Merge "Project import generated by Copybara." into main
diff --git a/v1.5.7/.copywrite.hcl b/v1.5.7/.copywrite.hcl
new file mode 100644
index 0000000..5f35653
--- /dev/null
+++ b/v1.5.7/.copywrite.hcl
@@ -0,0 +1,17 @@
+schema_version = 1
+
+project {
+  license        = "MPL-2.0"
+  copyright_year = 2014
+
+  # (OPTIONAL) A list of globs that should not have copyright/license headers.
+  # Supports doublestar glob patterns for more flexibility in defining which
+  # files or folders should be ignored
+  header_ignore = [
+    "**/*.tf",
+    "**/testdata/**",
+    "**/*.pb.go",
+    "**/*_string.go",
+    "**/mock*.go",
+  ]
+}
diff --git a/v1.5.7/.github/CODE_OF_CONDUCT.md b/v1.5.7/.github/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..0c8b092
--- /dev/null
+++ b/v1.5.7/.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/v1.5.7/.github/CONTRIBUTING.md b/v1.5.7/.github/CONTRIBUTING.md
new file mode 100644
index 0000000..ca460d6
--- /dev/null
+++ b/v1.5.7/.github/CONTRIBUTING.md
@@ -0,0 +1,234 @@
+# Contributing to Terraform
+
+This repository contains only Terraform core, which includes the command line interface and the main graph engine. Providers are implemented as plugins that each have their own repository linked from the [Terraform Registry index](https://registry.terraform.io/browse/providers). Instructions for developing each provider are usually in the associated README file. For more information, see [the provider development overview](https://www.terraform.io/docs/plugins/provider.html).
+
+**All communication on GitHub, the community forum, and other HashiCorp-provided communication channels is subject to [the HashiCorp community guidelines](https://www.hashicorp.com/community-guidelines).**
+
+This document provides guidance on Terraform contribution recommended practices. It covers what we're looking for in order to help set some expectations and help you get the most out of participation in this project. 
+
+To record a bug report, enhancement proposal, or give any other product feedback, please [open a GitHub issue](https://github.com/hashicorp/terraform/issues/new/choose) using the most appropriate issue template. Please do fill in all of the information the issue templates request, because we've seen from experience that this will maximize the chance that we'll be able to act on your feedback.
+
+---
+
+<!-- MarkdownTOC autolink="true" -->
+
+- [Contributing Fixes](#contributing-fixes)
+- [Proposing a Change](#proposing-a-change)
+	- [Caveats & areas of special concern](#caveats--areas-of-special-concern)
+		- [State Storage Backends](#state-storage-backends)
+		- [Provisioners](#provisioners)
+		- [Maintainers](#maintainers)
+	- [Pull Request Lifecycle](#pull-request-lifecycle)
+		- [Getting Your Pull Requests Merged Faster](#getting-your-pull-requests-merged-faster)
+	- [PR Checks](#pr-checks)
+- [Terraform CLI/Core Development Environment](#terraform-clicore-development-environment)
+- [Acceptance Tests: Testing interactions with external services](#acceptance-tests-testing-interactions-with-external-services)
+- [Generated Code](#generated-code)
+- [External Dependencies](#external-dependencies)
+
+<!-- /MarkdownTOC -->
+
+## Contributing Fixes
+
+It can be tempting to want to dive into an open source project and help _build the thing_ you believe you're missing. It's a wonderful and helpful intention. However, Terraform is a complex tool. Many seemingly simple changes can have serious effects on other areas of the code and it can take some time to become familiar with the effects of even basic changes. The Terraform team is not immune to unintended and sometimes undesirable changes. We do take our work seriously, and appreciate the globally diverse community that relies on Terraform for workflows of all sizes and criticality. 
+
+As a result of Terraform's complexity and high bar for stability, the most straightforward way to start helping with the Terraform project is to pick an existing bug and [get to work](#terraform-clicore-development-environment). 
+
+For new contributors we've labeled a few issues with `Good First Issue` as a nod to issues which will help get you familiar with Terraform development, while also providing an onramp to the codebase itself.
+
+Read the documentation, and don't be afraid to [ask questions](https://discuss.hashicorp.com/c/terraform-core/27). 
+
+## Proposing a Change
+
+In order to be respectful of the time of community contributors, we aim to discuss potential changes in GitHub issues prior to implementation. That will allow us to give design feedback up front and set expectations about the scope of the change, and, for larger changes, how best to approach the work such that the Terraform team can review it and merge it along with other concurrent work.
+
+If the bug you wish to fix or enhancement you wish to implement isn't already covered by a GitHub issue that contains feedback from the Terraform team, please do start a discussion (either in [a new GitHub issue](https://github.com/hashicorp/terraform/issues/new/choose) or an existing one, as appropriate) before you invest significant development time. If you mention your intent to implement the change described in your issue, the Terraform team can, as best as possible, prioritize including implementation-related feedback in the subsequent discussion.
+
+At this time, we do not have a formal process for reviewing outside proposals that significantly change Terraform's workflow, its primary usage patterns, and its language. Additionally, some seemingly simple proposals can have deep effects across Terraform, which is why we strongly suggest starting with an issue-based proposal. 
+
+For large proposals that could entail a significant design phase, we wish to be up front with potential contributors that, unfortunately, we are unlikely to be able to give prompt feedback. We are still interested to hear about your use-cases so that we can consider ways to meet them as part of other larger projects.
+
+Most changes will involve updates to the test suite, and changes to Terraform's documentation. The Terraform team can advise on different testing strategies for specific scenarios, and may ask you to revise the specific phrasing of your proposed documentation prose to match better with the standard "voice" of Terraform's documentation.
+
+This repository is primarily maintained by a small team at HashiCorp along with their other responsibilities, so unfortunately we cannot always respond promptly to pull requests, particularly if they do not relate to an existing GitHub issue where the Terraform team has already participated and indicated willingness to work on the issue or accept PRs for the proposal. We *are* grateful for all contributions however, and will give feedback on pull requests as soon as we're able.
+
+### Caveats & areas of special concern
+
+There are some areas of Terraform which are of special concern to the Terraform team. 
+
+#### State Storage Backends
+
+The Terraform team is not merging PRs for new state storage backends at the current time. Our priority regarding state storage backends is to find maintainers for existing backends and remove those backends without maintainers.
+
+Please see the [CODEOWNERS](https://github.com/hashicorp/terraform/blob/main/CODEOWNERS) file for the status of a given backend. Community members with an interest in a particular standard backend are welcome to help maintain it.
+
+Currently, merging state storage backends places a significant burden on the Terraform team. The team must set up an environment and cloud service provider account, or a new database/storage/key-value service, in order to build and test remote state storage backends. The time and complexity of doing so prevents us from moving Terraform forward in other ways.
+
+We are working to remove ourselves from the critical path of state storage backends by moving them towards a plugin model. In the meantime, we won't be accepting new remote state backends into Terraform.
+
+#### Provisioners
+
+Provisioners are an area of concern in Terraform for a number of reasons. Chiefly, they are often used in the place of configuration management tools or custom providers. 
+
+There are two main types of provisioners in Terraform, the generic provisioners (`file`,`local-exec`, and `remote-exec`) and the tool-specific provisioners (`chef`, `habbitat`, `puppet` & `salt-masterless`). **The tool-specific provisioners [are deprecated](https://discuss.hashicorp.com/t/notice-terraform-to-begin-deprecation-of-vendor-tool-specific-provisioners-starting-in-terraform-0-13-4/13997).** In practice this means we will not be accepting PRs for these areas of the codebase. 
+
+From our [documentation](https://www.terraform.io/docs/provisioners/index.html):
+
+> ... they [...] add a considerable amount of complexity and uncertainty to Terraform usage.[...] we still recommend attempting to solve it [your problem] using other techniques first, and use provisioners only if there is no other option.
+
+The Terraform team is in the process of building a way forward which continues to decrease reliance on provisioners. In the mean time however, as our documentation indicates, they are a tool of last resort. As such expect that PRs and issues for provisioners are not high in priority. 
+
+Please see the [CODEOWNERS](https://github.com/hashicorp/terraform/blob/main/CODEOWNERS) file for the status of a given provisioner. Community members with an interest in a particular provisioner are welcome to help maintain it.
+
+#### Maintainers
+
+Maintainers are key contributors to our Open Source project. They contribute their time and expertise and we ask that the community take extra special care to be mindful of this when interacting with them.
+
+For code that has a listed maintainer or maintainers in our [CODEOWNERS](https://github.com/hashicorp/terraform/blob/main/CODEOWNERS) file, the Terraform team will highlight them for participation in PRs which relate to the area of code they maintain. The expectation is that a maintainer will review the code and work with the PR contributor before the code is merged by the Terraform team.
+
+There is no expectation on response time for our maintainers; they may be indisposed for prolonged periods of time. Please be patient. Discussions on when code becomes "unmaintained" will be on a case-by-case basis. 
+
+If an an unmaintained area of code interests you and you'd like to become a maintainer, you may simply make a PR against our [CODEOWNERS](https://github.com/hashicorp/terraform/blob/main/CODEOWNERS) file with your github handle attached to the approriate area. If there is a maintainer or team of maintainers for that area, please coordinate with them as necessary. 
+
+### Pull Request Lifecycle
+
+1. You are welcome to submit a [draft pull request](https://github.blog/2019-02-14-introducing-draft-pull-requests/) for commentary or review before it is fully completed. It's also a good idea to include specific questions or items you'd like feedback on.
+2. Once you believe your pull request is ready to be merged you can create your pull request.
+3. When time permits Terraform's core team members will look over your contribution and either merge, or provide comments letting you know if there is anything left to do. It may take some time for us to respond. We may also have questions that we need answered about the code, either because something doesn't make sense to us or because we want to understand your thought process. We kindly ask that you do not target specific team members. 
+4. If we have requested changes, you can either make those changes or, if you disagree with the suggested changes, we can have a conversation about our reasoning and agree on a path forward. This may be a multi-step process. Our view is that pull requests are a chance to collaborate, and we welcome conversations about how to do things better. It is the contributor's responsibility to address any changes requested. While reviewers are happy to give guidance, it is unsustainable for us to perform the coding work necessary to get a PR into a mergeable state.
+5. Once all outstanding comments and checklist items have been addressed, your contribution will be merged! Merged PRs may or may not be included in the next release based on changes the Terraform teams deems as breaking or not. The core team takes care of updating the [CHANGELOG.md](https://github.com/hashicorp/terraform/blob/main/CHANGELOG.md) as they merge.
+6. In some cases, we might decide that a PR should be closed without merging. We'll make sure to provide clear reasoning when this happens. Following the recommended process above is one of the ways to ensure you don't spend time on a PR we can't or won't merge.
+
+#### Getting Your Pull Requests Merged Faster
+
+It is much easier to review pull requests that are:
+
+1. Well-documented: Try to explain in the pull request comments what your change does, why you have made the change, and provide instructions for how to produce the new behavior introduced in the pull request. If you can, provide screen captures or terminal output to show what the changes look like. This helps the reviewers understand and test the change.
+2. Small: Try to only make one change per pull request. If you found two bugs and want to fix them both, that's *awesome*, but it's still best to submit the fixes as separate pull requests. This makes it much easier for reviewers to keep in their heads all of the implications of individual code changes, and that means the PR takes less effort and energy to merge. In general, the smaller the pull request, the sooner reviewers will be able to make time to review it.
+3. Passing Tests: Based on how much time we have, we may not review pull requests which aren't passing our tests (look below for advice on how to run unit tests). If you need help figuring out why tests are failing, please feel free to ask, but while we're happy to give guidance it is generally your responsibility to make sure that tests are passing. If your pull request changes an interface or invalidates an assumption that causes a bunch of tests to fail, then you need to fix those tests before we can merge your PR.
+
+If we request changes, try to make those changes in a timely manner. Otherwise, PRs can go stale and be a lot more work for all of us to merge in the future.
+
+Even with everyone making their best effort to be responsive, it can be time-consuming to get a PR merged. It can be frustrating to deal with the back-and-forth as we make sure that we understand the changes fully. Please bear with us, and please know that we appreciate the time and energy you put into the project.
+
+### PR Checks
+
+The following checks run when a PR is opened:
+
+- Contributor License Agreement (CLA): If this is your first contribution to Terraform you will be asked to sign the CLA.
+- Tests: tests include unit tests and acceptance tests, and all tests must pass before a PR can be merged.
+
+----
+
+## Terraform CLI/Core Development Environment
+
+This repository contains the source code for Terraform CLI, which is the main component of Terraform that contains the core Terraform engine.
+
+Terraform providers are not maintained in this repository; you can find relevant
+repository and relevant issue tracker for each provider within the
+[Terraform Registry index](https://registry.terraform.io/browse/providers).
+
+This repository also does not include the source code for some other parts of the Terraform product including Terraform Cloud, Terraform Enterprise, and the Terraform Registry. Those components are not open source, though if you have feedback about them (including bug reports) please do feel free to [open a GitHub issue on this repository](https://github.com/hashicorp/terraform/issues/new/choose).
+
+---
+
+If you wish to work on the Terraform CLI source code, you'll first need to install the [Go](https://golang.org/) compiler and the version control system [Git](https://git-scm.com/).
+
+At this time the Terraform development environment is targeting only Linux and Mac OS X systems. While Terraform itself is compatible with Windows, unfortunately the unit test suite currently contains Unix-specific assumptions around maximum path lengths, path separators, etc.
+
+Refer to the file [`.go-version`](https://github.com/hashicorp/terraform/blob/main/.go-version) to see which version of Go Terraform is currently built with. Other versions will often work, but if you run into any build or testing problems please try with the specific Go version indicated. You can optionally simplify the installation of multiple specific versions of Go on your system by installing [`goenv`](https://github.com/syndbg/goenv), which reads `.go-version` and automatically selects the correct Go version.
+
+Use Git to clone this repository into a location of your choice. Terraform is using [Go Modules](https://blog.golang.org/using-go-modules), and so you should *not* clone it inside your `GOPATH`.
+
+Switch into the root directory of the cloned repository and build Terraform using the Go toolchain in the standard way:
+
+```
+cd terraform
+go install .
+```
+
+The first time you run the `go install` command, the Go toolchain will download any library dependencies that you don't already have in your Go modules cache. Subsequent builds will be faster because these dependencies will already be available on your local disk.
+
+Once the compilation process succeeds, you can find a `terraform` executable in the Go executable directory. If you haven't overridden it with the `GOBIN` environment variable, the executable directory is the `bin` directory inside the directory returned by the following command:
+
+```
+go env GOPATH
+```
+
+If you are planning to make changes to the Terraform source code, you should run the unit test suite before you start to make sure everything is initially passing:
+
+```
+go test ./...
+```
+
+As you make your changes, you can re-run the above command to ensure that the tests are *still* passing. If you are working only on a specific Go package, you can speed up your testing cycle by testing only that single package, or packages under a particular package prefix:
+
+```
+go test ./internal/command/...
+go test ./internal/addrs
+```
+
+## Acceptance Tests: Testing interactions with external services
+
+Terraform's unit test suite is self-contained, using mocks and local files to help ensure that it can run offline and is unlikely to be broken by changes to outside systems.
+
+However, several Terraform components interact with external services, such as the automatic provider installation mechanism, the Terraform Registry, Terraform Cloud, etc.
+
+There are some optional tests in the Terraform CLI codebase that *do* interact with external services, which we collectively refer to as "acceptance tests". You can enable these by setting the environment variable `TF_ACC=1` when running the tests. We recommend focusing only on the specific package you are working on when enabling acceptance tests, both because it can help the test run to complete faster and because you are less likely to encounter failures due to drift in systems unrelated to your current goal:
+
+```
+TF_ACC=1 go test ./internal/initwd
+```
+
+Because the acceptance tests depend on services outside of the Terraform codebase, and because the acceptance tests are usually used only when making changes to the systems they cover, it is common and expected that drift in those external systems will cause test failures. Because of this, prior to working on a system covered by acceptance tests it's important to run the existing tests for that system in an *unchanged* work tree first and respond to any test failures that preexist, to avoid misinterpreting such failures as bugs in your new changes.
+
+## Generated Code
+
+Some files in the Terraform CLI codebase are generated. In most cases, we update these using `go generate`, which is the standard way to encapsulate code generation steps in a Go codebase.
+
+```
+go generate ./...
+```
+
+Use `git diff` afterwards to inspect the changes and ensure that they are what you expected.
+
+Terraform includes generated Go stub code for the Terraform provider plugin protocol, which is defined using Protocol Buffers. Because the Protocol Buffers tools are not written in Go and thus cannot be automatically installed using `go get`, we follow a different process for generating these, which requires that you've already installed a suitable version of `protoc`:
+
+```
+make protobuf
+```
+
+## External Dependencies
+
+Terraform uses Go Modules for dependency management.
+
+Our dependency licensing policy for Terraform excludes proprietary licenses and "copyleft"-style licenses. We accept the common Mozilla Public License v2, MIT License, and BSD licenses. We will consider other open source licenses in similar spirit to those three, but if you plan to include such a dependency in a contribution we'd recommend opening a GitHub issue first to discuss what you intend to implement and what dependencies it will require so that the Terraform team can review the relevant licenses to for whether they meet our licensing needs.
+
+If you need to add a new dependency to Terraform or update the selected version for an existing one, use `go get` from the root of the Terraform repository as follows:
+
+```
+go get github.com/hashicorp/hcl/v2@2.0.0
+```
+
+This command will download the requested version (2.0.0 in the above example) and record that version selection in the `go.mod` file. It will also record checksums for the module in the `go.sum`.
+
+To complete the dependency change, clean up any redundancy in the module metadata files by running:
+
+```
+go mod tidy
+```
+
+To ensure that the upgrade has worked correctly, be sure to run the unit test suite at least once:
+
+```
+go test ./...
+```
+
+Because dependency changes affect a shared, top-level file, they are more likely than some other change types to become conflicted with other proposed changes during the code review process. For that reason, and to make dependency changes more visible in the change history, we prefer to record dependency changes as separate commits that include only the results of the above commands and the minimal set of changes to Terraform's own code for compatibility with the new version:
+
+```
+git add go.mod go.sum
+git commit -m "go get github.com/hashicorp/hcl/v2@2.0.0"
+```
+
+You can then make use of the new or updated dependency in new code added in subsequent commits.
diff --git a/v1.5.7/.github/ISSUE_TEMPLATE/bug_report.yml b/v1.5.7/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000..5b0b4ba
--- /dev/null
+++ b/v1.5.7/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,127 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+name: Bug Report
+description: Let us know about an unexpected error, a crash, or an incorrect behavior.
+labels: ["bug", "new"]
+body:
+  - type: markdown
+    attributes:
+      value: |
+        # Thank you for opening an issue.
+
+        The [hashicorp/terraform](https://github.com/hashicorp/terraform) issue tracker is reserved for bug reports relating to the core Terraform CLI application and configuration language.
+
+        For general usage questions, please see: https://www.terraform.io/community.html.
+
+        ## If your issue relates to:
+        * **Terraform Cloud/Enterprise**: please email tf-cloud@hashicorp.support or [open a new request](https://support.hashicorp.com/hc/en-us/requests/new).
+        * **AWS Terraform Provider**: Open an issue at [hashicorp/terraform-provider-aws](https://github.com/hashicorp/terraform-provider-aws/issues/new/choose).
+        * **Azure Terraform Provider**: Open an issue at [hashicorp/terraform-provider-azurerm](https://github.com/hashicorp/terraform-provider-azurerm/issues/new/choose).
+        * **Other Terraform Providers**: Please open an issue in the provider's own repository, which can be found by searching the [Terraform Registry](https://registry.terraform.io/browse/providers).
+
+        ## Filing a bug report
+
+        To fix problems, we need clear reproduction cases - we need to be able to see it happen locally. A reproduction case is ideally something a Terraform Core engineer can git-clone or copy-paste and run immediately, without inventing any details or context.
+
+        * A short example can be directly copy-pasteable; longer examples should be in separate git repositories, especially if multiple files are needed
+        * Please include all needed context. For example, if you figured out that an expression can cause a crash, put the expression in a variable definition or a resource
+        * Set defaults on (or omit) any variables. The person reproducing it should not need to invent variable settings
+        * If multiple steps are required, such as running terraform twice, consider scripting it in a simple shell script. Providing a script can be easier than explaining what changes to make to the config between runs.
+        * Omit any unneeded complexity: remove variables, conditional statements, functions, modules, providers, and resources that are not needed to trigger the bug
+        * When possible, use the [null resource](https://www.terraform.io/docs/providers/null/resource.html) provider rather than a real provider in order to minimize external dependencies. We know this isn't always feasible. The Terraform Core team doesn't have deep domain knowledge in every provider, or access to every cloud platform for reproduction cases.
+
+  - type: textarea
+    id: tf-version
+    attributes:
+      label: Terraform Version
+      description: Run `terraform version` to show the version, and paste the result below. If you are not running the latest version of Terraform, please try upgrading because your issue may have already been fixed.
+      render: shell
+      placeholder: ...output of `terraform version`...
+      value:
+    validations:
+      required: true
+
+  - type: textarea
+    id: tf-config
+    attributes:
+      label: Terraform Configuration Files
+      description: Paste the relevant parts of your Terraform configuration between the ``` marks below. For Terraform configs larger than a few resources, or that involve multiple files, please make a GitHub repository that we can clone, rather than copy-pasting multiple files in here.
+      placeholder:
+      value: |
+        ```terraform
+        ...terraform config...
+        ```
+    validations:
+      required: true
+
+  - type: textarea
+    id: tf-debug
+    attributes:
+      label: Debug Output
+      description: Full debug output can be obtained by running Terraform with the environment variable `TF_LOG=trace`. Please create a GitHub Gist containing the debug output. Please do _not_ paste the debug output in the issue, since debug output is long. Debug output may contain sensitive information. Please review it before posting publicly.
+      placeholder: ...link to gist...
+      value:
+    validations:
+      required: true
+  - type: textarea
+    id: tf-expected
+    attributes:
+      label: Expected Behavior
+      description: What should have happened?
+      placeholder: What should have happened?
+      value:
+    validations:
+      required: true
+  - type: textarea
+    id: tf-actual
+    attributes:
+      label: Actual Behavior
+      description: What actually happened?
+      placeholder: What actually happened?
+      value:
+    validations:
+      required: true
+  - type: textarea
+    id: tf-repro-steps
+    attributes:
+      label: Steps to Reproduce
+      description: |
+        Please list the full steps required to reproduce the issue, for example:
+          1. `terraform init`
+          2. `terraform apply`
+      placeholder: |
+        1. `terraform init`
+        2. `terraform apply`
+      value:
+    validations:
+      required: true
+  - type: textarea
+    id: tf-add-context
+    attributes:
+      label: Additional Context
+      description: |
+        Are there anything atypical about your situation that we should know?
+        For example: is Terraform running in a wrapper script or in a CI system? Are you passing any unusual command line options or environment variables to opt-in to non-default behavior?"
+      placeholder: Additional context...
+      value:
+    validations:
+      required: false
+  - type: textarea
+    id: tf-references
+    attributes:
+      label: References
+      description: |
+        Are there any other GitHub issues (open or closed) or Pull Requests that should be linked here? For example:
+        ```
+          - #6017
+        ```
+      placeholder:
+      value:
+    validations:
+      required: false
+
+  - type: markdown
+    attributes:
+      value: |
+        **Note:** If the submit button is disabled and you have filled out all required fields, please check that you did not forget a **Title** for the issue.
diff --git a/v1.5.7/.github/ISSUE_TEMPLATE/config.yml b/v1.5.7/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..04c1cdc
--- /dev/null
+++ b/v1.5.7/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,23 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+blank_issues_enabled: false
+contact_links:
+  - name: Terraform Cloud/Enterprise Troubleshooting and Feature Requests
+    url: https://support.hashicorp.com/hc/en-us/requests/new
+    about: For issues and feature requests related to the Terraform Cloud/Enterprise platform, please submit a HashiCorp support request or email tf-cloud@hashicorp.support
+  - name: AWS Terraform Provider Feedback and Questions
+    url: https://github.com/hashicorp/terraform-provider-aws
+    about: The AWS Terraform Provider has its own repository, any provider related issues or questions should be directed there.
+  - name: Azure Terraform Provider Feedback and Questions
+    url: https://github.com/hashicorp/terraform-provider-azurerm
+    about: The Azure Terraform Provider has its own repository, any provider related issues or questions should be directed there.
+  - name: Other Provider-related Feedback and Questions
+    url: https://registry.terraform.io/browse/providers
+    about: Each provider (e.g. GCP, Oracle, K8S, etc.) has its own repository, any provider related issues or questions should be directed to the appropriate issue tracker linked from the Registry.
+  - name: Provider Development Feedback and Questions
+    url: https://github.com/hashicorp/terraform-plugin-sdk/issues/new/choose
+    about: Plugin SDK has its own repository, any SDK and provider development related issues or questions should be directed there.
+  - name: Terraform Usage, 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 Community Forum.
\ No newline at end of file
diff --git a/v1.5.7/.github/ISSUE_TEMPLATE/documentation_issue.yml b/v1.5.7/.github/ISSUE_TEMPLATE/documentation_issue.yml
new file mode 100644
index 0000000..0d79888
--- /dev/null
+++ b/v1.5.7/.github/ISSUE_TEMPLATE/documentation_issue.yml
@@ -0,0 +1,76 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+name: Documentation Issue
+description: Report an issue or suggest a change in the documentation.
+labels: ["documentation", "new"]
+body:
+  - type: markdown
+    attributes:
+      value: |
+        # Thank you for opening a documentation change request.
+
+        Please only use the [hashicorp/terraform](https://github.com/hashicorp/terraform) `Documentation` issue type to report problems with the documentation on [https://www.terraform.io/docs](). Only technical writers (not engineers) monitor this issue type. Report Terraform bugs or feature requests with the `Bug report` or `Feature Request` issue types instead to get engineering attention.
+
+        For general usage questions, please see: https://www.terraform.io/community.html.
+
+  - type: textarea
+    id: tf-version
+    attributes:
+      label: Terraform Version
+      description: Run `terraform version` to show the version, and paste the result below. If you're not using the latest version, please check to see if something related to your request has already been implemented in a later version.
+      render: shell
+      placeholder: ...output of `terraform version`...
+      value:
+    validations:
+      required: true
+
+  - type: textarea
+    id: tf-affected-pages
+    attributes:
+      label: Affected Pages
+      description: |
+          Link to the pages relevant to your documentation change request.
+      placeholder:
+      value:
+    validations:
+      required: false
+
+  - type: textarea
+    id: tf-problem
+    attributes:
+      label: What is the docs issue?
+      description: What problems or suggestions do you have about the documentation?
+      placeholder:
+      value:
+    validations:
+      required: true
+
+  - type: textarea
+    id: tf-proposal
+    attributes:
+      label: Proposal
+      description: What documentation changes would fix this issue and where would you expect to find them? Are one or more page headings unclear? Do one or more pages need additional context, examples, or warnings? Do we need a new page or section dedicated to a specific topic?  Your ideas help us understand what you and other users need from our documentation and how we can improve the content.
+      placeholder:
+      value:
+    validations:
+      required: false
+
+  - type: textarea
+    id: tf-references
+    attributes:
+      label: References
+      description: |
+        Are there any other open or closed GitHub issues related to the problem or solution you described? If so, list them below. For example:
+        ```
+          - #6017
+        ```
+      placeholder:
+      value:
+    validations:
+      required: false
+
+  - type: markdown
+    attributes:
+      value: |
+        **Note:** If the submit button is disabled and you have filled out all required fields, please check that you did not forget a **Title** for the issue.
diff --git a/v1.5.7/.github/ISSUE_TEMPLATE/feature_request.yml b/v1.5.7/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 0000000..706da0d
--- /dev/null
+++ b/v1.5.7/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,90 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+name: Feature Request
+description: Suggest a new feature or other enhancement.
+labels: ["enhancement", "new"]
+body:
+  - type: markdown
+    attributes:
+      value: |
+        # Thank you for opening a feature request.
+
+        The [hashicorp/terraform](https://github.com/hashicorp/terraform) issue tracker is reserved for feature requests relating to the core Terraform CLI application and configuration language.
+
+        For general usage questions, please see: https://www.terraform.io/community.html.
+
+        ## If your feature request relates to:
+        * **Terraform Cloud/Enterprise**: please email tf-cloud@hashicorp.support or [open a new request](https://support.hashicorp.com/hc/en-us/requests/new).
+        * **AWS Terraform Provider**: Open an issue at [hashicorp/terraform-provider-aws](https://github.com/hashicorp/terraform-provider-aws/issues/new/choose).
+        * **Azure Terraform Provider**: Open an issue at [hashicorp/terraform-provider-azurerm](https://github.com/hashicorp/terraform-provider-azurerm/issues/new/choose).
+        * **Other Terraform Providers**: Please open an issue in the provider's own repository, which can be found by searching the [Terraform Registry](https://registry.terraform.io/browse/providers).
+
+  - type: textarea
+    id: tf-version
+    attributes:
+      label: Terraform Version
+      description: Run `terraform version` to show the version, and paste the result below. If you're not using the latest version, please check to see if something related to your request has already been implemented in a later version.
+      render: shell
+      placeholder: ...output of `terraform version`...
+      value:
+    validations:
+      required: true
+
+  - type: textarea
+    id: tf-use-case
+    attributes:
+      label: Use Cases
+      description: |
+        In order to properly evaluate a feature request, it is necessary to understand the use cases for it.
+        Please describe below the _end goal_ you are trying to achieve that has led you to request this feature.
+        Please keep this section focused on the problem and not on the suggested solution. We'll get to that in a moment, below!
+      placeholder:
+      value:
+    validations:
+      required: true
+
+  - type: textarea
+    id: tf-attempted-solution
+    attributes:
+      label: Attempted Solutions
+      description: |
+          If you've already tried to solve the problem within Terraform's existing features and found a limitation that prevented you from succeeding, please describe it below in as much detail as possible.
+          Ideally, this would include real configuration snippets that you tried, real Terraform command lines you ran, and what results you got in each case.
+          Please remove any sensitive information such as passwords before sharing configuration snippets and command lines.
+      placeholder:
+      value:
+    validations:
+      required: true
+
+  - type: textarea
+    id: tf-proposal
+    attributes:
+      label: Proposal
+      description: |
+          If you have an idea for a way to address the problem via a change to Terraform features, please describe it below.
+          In this section, it's helpful to include specific examples of how what you are suggesting might look in configuration files, or on the command line, since that allows us to understand the full picture of what you are proposing.
+          If you're not sure of some details, don't worry! When we evaluate the feature request we may suggest modifications as necessary to work within the design constraints of Terraform Core.
+      placeholder:
+      value:
+    validations:
+      required: false
+
+  - type: textarea
+    id: tf-references
+    attributes:
+      label: References
+      description: |
+        Are there any other GitHub issues, whether open or closed, that are related to the problem you've described above or to the suggested solution? If so, please create a list below that mentions each of them. For example:
+        ```
+          - #6017
+        ```
+      placeholder:
+      value:
+    validations:
+      required: false
+
+  - type: markdown
+    attributes:
+      value: |
+        **Note:** If the submit button is disabled and you have filled out all required fields, please check that you did not forget a **Title** for the issue.
diff --git a/v1.5.7/.github/SUPPORT.md b/v1.5.7/.github/SUPPORT.md
new file mode 100644
index 0000000..9ba846c
--- /dev/null
+++ b/v1.5.7/.github/SUPPORT.md
@@ -0,0 +1,4 @@
+# Support
+
+If you have questions about Terraform usage, please feel free to create a topic
+on [the official community forum](https://discuss.hashicorp.com/c/terraform-core).
diff --git a/v1.5.7/.github/actions/equivalence-test/action.yml b/v1.5.7/.github/actions/equivalence-test/action.yml
new file mode 100644
index 0000000..95b3010
--- /dev/null
+++ b/v1.5.7/.github/actions/equivalence-test/action.yml
@@ -0,0 +1,61 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+name: equivalence-test
+description: "Execute the suite of Terraform equivalence tests in testing/equivalence-tests"
+inputs:
+  target-terraform-version:
+    description: "The version of Terraform to use in execution."
+    required: true
+  target-terraform-branch:
+    description: "The branch within this repository to update and compare."
+    required: true
+  target-equivalence-test-version:
+    description: "The version of the Terraform equivalence tests to use."
+    default: "0.3.0"
+  target-os:
+    description: "Current operating system"
+    default: "linux"
+  target-arch:
+    description: "Current architecture"
+    default: "amd64"
+runs:
+  using: "composite"
+  steps:
+    - name: "download equivalence test binary"
+      shell: bash
+      run: |
+        ./.github/scripts/equivalence-test.sh download_equivalence_test_binary \
+          ${{ inputs.target-equivalence-test-version }} \
+          ./bin/equivalence-tests \
+          ${{ inputs.target-os }} \
+          ${{ inputs.target-arch }}
+    - name: "download terraform binary"
+      shell: bash
+      run: |
+        ./.github/scripts/equivalence-test.sh download_terraform_binary \
+          ${{ inputs.target-terraform-version }} \
+          ./bin/terraform \
+          ${{ inputs.target-os }} \
+          ${{ inputs.target-arch }}
+    - name: "run and update equivalence tests"
+      shell: bash
+      run: |
+        ./bin/equivalence-tests update \
+          --tests=testing/equivalence-tests/tests \
+          --goldens=testing/equivalence-tests/outputs \
+          --binary=$(pwd)/bin/terraform
+        
+        changed=$(git diff --quiet -- testing/equivalence-tests/outputs || echo true)
+        if [[ $changed == "true" ]]; then
+          echo "found changes, and pushing new golden files into branch ${{ inputs.target-terraform-branch }}."
+
+          git config user.email "52939924+teamterraform@users.noreply.github.com"
+          git config user.name "The Terraform Team"
+
+          git add ./testing/equivalence-tests/outputs
+          git commit -m "Automated equivalence test golden file update for release ${{ inputs.target-terraform-version }}."
+          git push
+        else
+          echo "found no changes, so not pushing any updates."
+        fi
diff --git a/v1.5.7/.github/actions/go-version/action.yml b/v1.5.7/.github/actions/go-version/action.yml
new file mode 100644
index 0000000..d1d5a29
--- /dev/null
+++ b/v1.5.7/.github/actions/go-version/action.yml
@@ -0,0 +1,26 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+name: 'Determine Go Toolchain Version'
+description: 'Uses the .go-version file to determine which Go toolchain to use for any Go-related actions downstream.'
+outputs:
+  version:
+    description: "Go toolchain version"
+    value: ${{ steps.go.outputs.version }}
+runs:
+  using: "composite"
+  steps:
+    # We use goenv to make sure we're always using the same Go version we'd
+    # use for releases, as recorded in the .go-version file.
+    - name: "Determine Go version"
+      id: go
+      shell: bash
+      # We use .go-version as our source of truth for current Go
+      # version, because "goenv" can react to it automatically.
+      # However, we don't actually use goenv for our automated
+      # steps in GitHub Actions, because it's primarily for
+      # interactive use in shells and makes things unnecessarily
+      # complex for automation.
+      run: |
+        echo "Building with Go $(cat .go-version)"
+        echo "version=$(cat .go-version)" >> "$GITHUB_OUTPUT"
diff --git a/v1.5.7/.github/pull_request_template.md b/v1.5.7/.github/pull_request_template.md
new file mode 100644
index 0000000..dfa6b82
--- /dev/null
+++ b/v1.5.7/.github/pull_request_template.md
@@ -0,0 +1,56 @@
+<!--
+
+Describe in detail the changes you are proposing, and the rationale.
+
+See the contributing guide:
+
+https://github.com/hashicorp/terraform/blob/main/.github/CONTRIBUTING.md
+
+-->
+
+<!--
+
+Link all GitHub issues fixed by this PR, and add references to prior
+related PRs.
+
+-->
+
+Fixes #
+
+## Target Release
+
+<!--
+
+In normal circumstances we only target changes at the upcoming minor
+release, or as a patch to the current minor version. If you need to
+port a security fix to an older release, highlight this here by listing
+all targeted releases.
+
+If targeting the next patch release, also add the relevant x.y-backport
+label to enable the backport bot.
+
+-->
+
+1.4.x
+
+## Draft CHANGELOG entry
+
+<!--
+
+Choose a category, delete the others:
+
+-->
+
+### NEW FEATURES | UPGRADE NOTES | ENHANCEMENTS | BUG FIXES | EXPERIMENTS
+
+<!--
+
+Write a short description of the user-facing change. Examples:
+
+- `terraform show -json`: Fixed crash with sensitive set values.
+- When rendering a diff, Terraform now quotes the name of any object attribute whose string representation is not a valid identifier.
+- The local token configuration in the cloud and remote backend now has higher priority than a token specified in a credentials block in the CLI configuration.
+
+--> 
+
+-  
diff --git a/v1.5.7/.github/scripts/e2e_test_linux_darwin.sh b/v1.5.7/.github/scripts/e2e_test_linux_darwin.sh
new file mode 100755
index 0000000..94cb27c
--- /dev/null
+++ b/v1.5.7/.github/scripts/e2e_test_linux_darwin.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+set -uo pipefail
+
+if [[ $arch == 'arm' || $arch == 'arm64' ]]
+then
+    export DIR=$(mktemp -d)
+    unzip -d $DIR "${e2e_cache_path}/terraform-e2etest_${os}_${arch}.zip"
+    unzip -d $DIR "./terraform_${version}_${os}_${arch}.zip"
+    sudo chmod +x $DIR/e2etest
+    docker run --platform=linux/arm64 -v $DIR:/src -w /src arm64v8/alpine ./e2etest -test.v
+else
+    unzip "${e2e_cache_path}/terraform-e2etest_${os}_${arch}.zip"
+    unzip "./terraform_${version}_${os}_${arch}.zip"
+    TF_ACC=1 ./e2etest -test.v
+fi
\ No newline at end of file
diff --git a/v1.5.7/.github/scripts/equivalence-test.sh b/v1.5.7/.github/scripts/equivalence-test.sh
new file mode 100755
index 0000000..e82ce32
--- /dev/null
+++ b/v1.5.7/.github/scripts/equivalence-test.sh
@@ -0,0 +1,165 @@
+#!/usr/bin/env bash
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+set -uo pipefail
+
+function usage {
+  cat <<-'EOF'
+Usage: ./equivalence-test.sh <command> [<args>] [<options>]
+
+Description:
+  This script will handle various commands related to the execution of the
+  Terraform equivalence tests.
+
+Commands:
+  get_target_branch <version>
+    get_target_branch returns the default target branch for a given Terraform
+    version.
+
+    target_branch=$(./equivalence-test.sh get_target_branch v1.4.3); target_branch=v1.4
+    target_branch=$(./equivalence-test.sh get_target_branch 1.4.3); target_branch=v1.4
+
+  download_equivalence_test_binary <version> <target> <os> <arch>
+    download_equivalence_test_binary downloads the equivalence testing binary
+    for a given version and places it at the target path.
+
+    ./equivalence-test.sh download_equivalence_test_binary 0.3.0 ./bin/terraform-equivalence-testing linux amd64
+
+  download_terraform_binary <version> <target> <os> <arch>
+    download_terraform_binary downloads the terraform release binary for a given
+    version and places it at the target path.
+
+    ./equivalence-test.sh download_terraform_binary 1.4.3 ./bin/terraform linux amd64
+EOF
+}
+
+function download_equivalence_test_binary {
+  VERSION="${1:-}"
+  TARGET="${2:-}"
+  OS="${3:-}"
+  ARCH="${4:-}"
+
+  if [[ -z "$VERSION" || -z "$TARGET" || -z "$OS" || -z "$ARCH" ]]; then
+    echo "missing at least one of [<version>, <target>, <os>, <arch>] arguments"
+    usage
+    exit 1
+  fi
+
+  curl \
+    -H "Accept: application/vnd.github+json" \
+    "https://api.github.com/repos/hashicorp/terraform-equivalence-testing/releases" > releases.json
+
+  ASSET="terraform-equivalence-testing_v${VERSION}_${OS}_${ARCH}.zip"
+  ASSET_ID=$(jq -r --arg VERSION "v$VERSION" --arg ASSET "$ASSET" '.[] | select(.name == $VERSION) | .assets[] | select(.name == $ASSET) | .id' releases.json)
+
+  mkdir -p zip
+  curl -L \
+    -H "Accept: application/octet-stream" \
+    "https://api.github.com/repos/hashicorp/terraform-equivalence-testing/releases/assets/$ASSET_ID" > "zip/$ASSET"
+
+  mkdir -p bin
+  unzip -p "zip/$ASSET" terraform-equivalence-testing > "$TARGET"
+  chmod u+x "$TARGET"
+  rm -r zip
+  rm releases.json
+}
+
+function download_terraform_binary {
+  VERSION="${1:-}"
+  TARGET="${2:-}"
+  OS="${3:-}"
+  ARCH="${4:-}"
+
+  if [[ -z "$VERSION" || -z "$TARGET" || -z "$OS" || -z "$ARCH" ]]; then
+    echo "missing at least one of [<version>, <target>, <os>, <arch>] arguments"
+    usage
+    exit 1
+  fi
+
+  mkdir -p zip
+  curl "https://releases.hashicorp.com/terraform/${VERSION}/terraform_${VERSION}_${OS}_${ARCH}.zip" > "zip/terraform.zip"
+
+  mkdir -p bin
+  unzip -p "zip/terraform.zip" terraform > "$TARGET"
+  chmod u+x "$TARGET"
+  rm -r zip
+}
+
+function get_target_branch {
+  VERSION="${1:-}"
+
+  if [ -z "$VERSION" ]; then
+    echo "missing <version> argument"
+    usage
+    exit 1
+  fi
+
+
+  # Split off the build metadata part, if any
+  # (we won't actually include it in our final version, and handle it only for
+  # completeness against semver syntax.)
+  IFS='+' read -ra VERSION BUILD_META <<< "$VERSION"
+
+  # Separate out the prerelease part, if any
+  IFS='-' read -r BASE_VERSION PRERELEASE <<< "$VERSION"
+
+  # Separate out major, minor and patch versions.
+  IFS='.' read -r MAJOR_VERSION MINOR_VERSION PATCH_VERSION <<< "$BASE_VERSION"
+
+  if [[ "$PRERELEASE" == *"alpha"* ]]; then
+    TARGET_BRANCH=main
+  else
+    if [[ $MAJOR_VERSION = v* ]]; then
+      TARGET_BRANCH=${MAJOR_VERSION}.${MINOR_VERSION}
+    else
+      TARGET_BRANCH=v${MAJOR_VERSION}.${MINOR_VERSION}
+    fi
+  fi
+
+  echo "$TARGET_BRANCH"
+}
+
+function main {
+  case "$1" in
+    get_target_branch)
+      if [ "${#@}" != 2 ]; then
+        echo "invalid number of arguments"
+        usage
+        exit 1
+      fi
+
+      get_target_branch "$2"
+
+      ;;
+    download_equivalence_test_binary)
+      if [ "${#@}" != 5 ]; then
+        echo "invalid number of arguments"
+        usage
+        exit 1
+      fi
+
+      download_equivalence_test_binary "$2" "$3" "$4" "$5"
+
+      ;;
+    download_terraform_binary)
+      if [ "${#@}" != 5 ]; then
+        echo "invalid number of arguments"
+        usage
+        exit 1
+      fi
+
+      download_terraform_binary "$2" "$3" "$4" "$5"
+
+      ;;
+    *)
+      echo "unrecognized command $*"
+      usage
+      exit 1
+
+      ;;
+  esac
+}
+
+main "$@"
+exit $?
diff --git a/v1.5.7/.github/scripts/get_product_version.sh b/v1.5.7/.github/scripts/get_product_version.sh
new file mode 100755
index 0000000..3de45ad
--- /dev/null
+++ b/v1.5.7/.github/scripts/get_product_version.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+set -uo pipefail
+
+# Trim the "v" prefix, if any.
+VERSION="${RAW_VERSION#v}"
+
+# Split off the build metadata part, if any
+# (we won't actually include it in our final version, and handle it only for
+# compleness against semver syntax.)
+IFS='+' read -ra VERSION BUILD_META <<< "$VERSION"
+
+# Separate out the prerelease part, if any
+# (version.go expects it to be in a separate variable)
+IFS='-' read -r BASE_VERSION PRERELEASE <<< "$VERSION"
+
+EXPERIMENTS_ENABLED=0
+if [[ "$PRERELEASE" == alpha* ]]; then
+EXPERIMENTS_ENABLED=1
+fi
+if [[ "$PRERELEASE" == dev* ]]; then
+EXPERIMENTS_ENABLED=1
+fi
+
+LDFLAGS="-w -s"
+if [[ "$EXPERIMENTS_ENABLED" == 1 ]]; then
+LDFLAGS="${LDFLAGS} -X 'main.experimentsAllowed=yes'"
+fi
+LDFLAGS="${LDFLAGS} -X 'github.com/hashicorp/terraform/version.Version=${BASE_VERSION}'"
+LDFLAGS="${LDFLAGS} -X 'github.com/hashicorp/terraform/version.Prerelease=${PRERELEASE}'"
+
+echo "Building Terraform CLI ${VERSION}"
+if [[ "$EXPERIMENTS_ENABLED" == 1 ]]; then
+echo "This build allows use of experimental features"
+fi
+echo "product-version=${VERSION}" | tee -a "${GITHUB_OUTPUT}"
+echo "product-version-base=${BASE_VERSION}" | tee -a "${GITHUB_OUTPUT}"
+echo "product-version-pre=${PRERELEASE}" | tee -a "${GITHUB_OUTPUT}"
+echo "experiments=${EXPERIMENTS_ENABLED}" | tee -a "${GITHUB_OUTPUT}"
+echo "go-ldflags=${LDFLAGS}" | tee -a "${GITHUB_OUTPUT}"
\ No newline at end of file
diff --git a/v1.5.7/.github/scripts/verify_docker b/v1.5.7/.github/scripts/verify_docker
new file mode 100755
index 0000000..6d016b2
--- /dev/null
+++ b/v1.5.7/.github/scripts/verify_docker
@@ -0,0 +1,47 @@
+#!/bin/bash
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+
+set -euo pipefail
+
+# verify_docker invokes the given Docker image with the argument `version` and inspects its output.
+# If its output doesn't match the version given, the script will exit 1 and report why it failed.
+# This is meant to be run as part of the build workflow to verify the built image meets some basic
+# criteria for validity.
+#
+# Because this is meant to be run as the `smoke_test` for the docker-build workflow, the script expects
+# the image name parameter to be provided by the `IMAGE_NAME` environment variable, rather than a
+# positional argument.
+
+function usage {
+  echo "IMAGE_NAME=<image uri> ./verify_docker <expect_version>"
+}
+
+function main {
+  local image_name="${IMAGE_NAME:-}"
+  local expect_version="${1:-}"
+  local got_version
+
+  if [[ -z "${image_name}" ]]; then
+    echo "ERROR: IMAGE_NAME is not set"
+    usage
+    exit 1
+  fi
+
+  if [[ -z "${expect_version}" ]]; then
+    echo "ERROR: expected version argument is required"
+    usage
+    exit 1
+  fi
+
+  got_version="$( awk '{print $2}' <(head -n1 <(docker run --rm "${image_name}" version)) )"
+  if [ "${got_version}" != "${expect_version}" ]; then
+    echo "Test FAILED"
+    echo "Got: ${got_version}, Want: ${expect_version}"
+    exit 1
+  fi
+  echo "Test PASSED"
+}
+
+main "$@"
diff --git a/v1.5.7/.github/workflows/build-Dockerfile b/v1.5.7/.github/workflows/build-Dockerfile
new file mode 100644
index 0000000..c0ea5b8
--- /dev/null
+++ b/v1.5.7/.github/workflows/build-Dockerfile
@@ -0,0 +1,41 @@
+# This Dockerfile is not intended for general use, but is rather used to
+# produce our "light" release packages as part of our official release
+# pipeline.
+#
+# If you want to test this locally you'll need to set the three arguments
+# to values realistic for what the hashicorp/actions-docker-build GitHub
+# action would set, and ensure that there's a suitable "terraform" executable
+# in the dist/linux/${TARGETARCH} directory.
+
+FROM docker.mirror.hashicorp.services/alpine:latest AS default
+
+# This is intended to be run from the hashicorp/actions-docker-build GitHub
+# action, which sets these appropriately based on context.
+ARG PRODUCT_VERSION=UNSPECIFIED
+ARG PRODUCT_REVISION=UNSPECIFIED
+ARG BIN_NAME=terraform
+
+# This argument is set by the Docker toolchain itself, to the name
+# of the CPU architecture we're building an image for.
+# Our caller should've extracted the corresponding "terraform" executable
+# into dist/linux/${TARGETARCH} for us to use.
+ARG TARGETARCH
+
+LABEL maintainer="HashiCorp Terraform Team <terraform@hashicorp.com>"
+
+# New standard version label.
+LABEL version=$PRODUCT_VERSION
+
+# Historical Terraform-specific label preserved for backward compatibility.
+LABEL "com.hashicorp.terraform.version"="${PRODUCT_VERSION}"
+
+RUN apk add --no-cache git openssh
+
+# The hashicorp/actions-docker-build GitHub Action extracts the appropriate
+# release package for our target architecture into the current working
+# directory before running "docker build", which we'll then copy into the
+# Docker image to make sure that we use an identical binary as all of the
+# other official release channels.
+COPY ["dist/linux/${TARGETARCH}/terraform", "/bin/terraform"]
+
+ENTRYPOINT ["/bin/terraform"]
diff --git a/v1.5.7/.github/workflows/build-terraform-oss.yml b/v1.5.7/.github/workflows/build-terraform-oss.yml
new file mode 100644
index 0000000..f7eed12
--- /dev/null
+++ b/v1.5.7/.github/workflows/build-terraform-oss.yml
@@ -0,0 +1,101 @@
+---
+name: build_terraform
+
+# This workflow is intended to be called by the build workflow. The crt make
+# targets that are utilized automatically determine build metadata and
+# handle building and packing Terraform.
+
+on:
+  workflow_call:
+    inputs:
+      cgo-enabled:
+        type: string
+        default: 0
+        required: true
+      goos:
+        required: true
+        type: string
+      goarch:
+        required: true
+        type: string
+      go-version:
+        type: string
+      package-name:
+        type: string
+        default: terraform
+      product-version:
+        type: string
+        required: true
+      ld-flags:
+        type: string
+        required: true
+      runson:
+        type: string
+        required: true
+
+jobs:
+  build:
+    runs-on: ${{ inputs.runson }}
+    name: Terraform ${{ inputs.goos }} ${{ inputs.goarch }} v${{ inputs.product-version }}
+    steps:
+      - uses: actions/checkout@v3
+      - uses: actions/setup-go@v3
+        with:
+          go-version: ${{ inputs.go-version }}
+      - name: Determine artifact basename
+        run: echo "ARTIFACT_BASENAME=${{ inputs.package-name }}_${{ inputs.product-version }}_${{ inputs.goos }}_${{ inputs.goarch }}.zip" >> $GITHUB_ENV
+      - name: Build Terraform
+        env:
+          GOOS: ${{ inputs.goos }}
+          GOARCH: ${{ inputs.goarch }}
+          GO_LDFLAGS: ${{ inputs.ld-flags }}
+          ACTIONSOS: ${{ inputs.runson }}
+          CGO_ENABLED: ${{ inputs.cgo-enabled }}
+        uses: hashicorp/actions-go-build@v0.1.7
+        with:
+          product_name: ${{ inputs.package-name }}
+          product_version: ${{ inputs.product-version }}
+          go_version: ${{ inputs.go-version }}
+          os: ${{ inputs.goos }}
+          arch: ${{ inputs.goarch }}
+          reproducible: nope
+          instructions: |-
+            mkdir dist out
+            set -x
+            go build -ldflags "${{ inputs.ld-flags }}" -o dist/ .
+            zip -r -j out/${{ env.ARTIFACT_BASENAME }} dist/
+      - uses: actions/upload-artifact@v3
+        with:
+          name: ${{ env.ARTIFACT_BASENAME }}
+          path: out/${{ env.ARTIFACT_BASENAME }}
+          if-no-files-found: error
+      - if: ${{ inputs.goos == 'linux' }}
+        uses: hashicorp/actions-packaging-linux@v1
+        with:
+          name: "terraform"
+          description: "Terraform enables you to safely and predictably create, change, and improve infrastructure. It is an open source tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned."
+          arch: ${{ inputs.goarch }}
+          version: ${{ inputs.product-version }}
+          maintainer: "HashiCorp"
+          homepage: "https://terraform.io/"
+          license: "MPL-2.0"
+          binary: "dist/terraform"
+          deb_depends: "git"
+          rpm_depends: "git"
+      - if: ${{ inputs.goos == 'linux' }}
+        name: Determine package file names
+        run: |
+          echo "RPM_PACKAGE=$(basename out/*.rpm)" >> $GITHUB_ENV
+          echo "DEB_PACKAGE=$(basename out/*.deb)" >> $GITHUB_ENV
+      - if: ${{ inputs.goos == 'linux' }}
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{ env.RPM_PACKAGE }}
+          path: out/${{ env.RPM_PACKAGE }}
+          if-no-files-found: error
+      - if: ${{ inputs.goos == 'linux' }}
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{ env.DEB_PACKAGE }}
+          path: out/${{ env.DEB_PACKAGE }}
+          if-no-files-found: error
diff --git a/v1.5.7/.github/workflows/build.yml b/v1.5.7/.github/workflows/build.yml
new file mode 100644
index 0000000..f8a3be1
--- /dev/null
+++ b/v1.5.7/.github/workflows/build.yml
@@ -0,0 +1,321 @@
+name: build
+
+# If you want to test changes to this file before merging to a main branch,
+# push them up to a branch whose name has the prefix "build-workflow-dev/",
+# which is a special prefix that triggers this workflow even though it's not
+# actually a release branch.
+
+on:
+  workflow_dispatch:
+  push:
+    branches:
+      - main
+      - 'v[0-9]+.[0-9]+'
+      - releng/**
+    tags:
+      - 'v[0-9]+.[0-9]+.[0-9]+*'
+
+env:
+  PKG_NAME: "terraform"
+
+permissions:
+  contents: read
+  statuses: write
+
+jobs:
+  get-product-version:
+    name: "Determine intended Terraform version"
+    runs-on: ubuntu-latest
+    outputs:
+      product-version: ${{ steps.get-product-version.outputs.product-version }}
+      product-version-base: ${{ steps.get-product-version.outputs.base-product-version }}
+      product-version-pre: ${{ steps.get-product-version.outputs.prerelease-product-version }}
+      experiments: ${{ steps.get-ldflags.outputs.experiments }}
+      go-ldflags: ${{ steps.get-ldflags.outputs.go-ldflags }}
+      pkg-name: ${{ steps.get-pkg-name.outputs.pkg-name }}
+
+    steps:
+      - uses: actions/checkout@v3
+      - name: Get Package Name
+        id: get-pkg-name
+        run: |
+          pkg_name=${{ env.PKG_NAME }}
+          echo "pkg-name=${pkg_name}" | tee -a "${GITHUB_OUTPUT}"
+      - name: Decide version number
+        id: get-product-version
+        uses: hashicorp/actions-set-product-version@v1
+      - name: Determine experiments
+        id: get-ldflags
+        env:
+          RAW_VERSION: ${{ steps.get-product-version.outputs.product-version }}
+        shell: bash
+        run: .github/scripts/get_product_version.sh
+      - name: Report chosen version number
+        run: |
+          [ -n "${{steps.get-product-version.outputs.product-version}}" ]
+          echo "::notice title=Terraform CLI Version::${{ steps.get-product-version.outputs.product-version }}"
+
+  get-go-version:
+    name: "Determine Go toolchain version"
+    runs-on: ubuntu-latest
+    outputs:
+      go-version: ${{ steps.get-go-version.outputs.version }}
+
+    steps:
+      - uses: actions/checkout@v3
+      - name: Determine Go version
+        id: get-go-version
+        uses: ./.github/actions/go-version
+
+  generate-metadata-file:
+    name: "Generate release metadata"
+    runs-on: ubuntu-latest
+    needs: get-product-version
+    outputs:
+      filepath: ${{ steps.generate-metadata-file.outputs.filepath }}
+
+    steps:
+      - uses: actions/checkout@v3
+      - name: Generate package metadata
+        id: generate-metadata-file
+        uses: hashicorp/actions-generate-metadata@v1
+        with:
+          version: ${{ needs.get-product-version.outputs.product-version }}
+          product: ${{ env.PKG_NAME }}
+
+      - uses: actions/upload-artifact@v2
+        with:
+          name: metadata.json
+          path: ${{ steps.generate-metadata-file.outputs.filepath }}
+
+  build:
+    name: Build for ${{ matrix.goos }}_${{ matrix.goarch }}
+    needs:
+      - get-product-version
+      - get-go-version
+    uses: ./.github/workflows/build-terraform-oss.yml
+    with:
+      goarch: ${{ matrix.goarch }}
+      goos: ${{ matrix.goos }}
+      go-version: ${{ needs.get-go-version.outputs.go-version }}
+      package-name: ${{ needs.get-product-version.outputs.pkg-name }}
+      product-version: ${{ needs.get-product-version.outputs.product-version }}
+      ld-flags: ${{ needs.get-product-version.outputs.go-ldflags }}
+      cgo-enabled: ${{ matrix.cgo-enabled }}
+      runson: ${{ matrix.runson }}
+    secrets: inherit
+    strategy:
+      matrix:
+        include:
+          - {goos: "freebsd", goarch: "386", runson: "ubuntu-latest", cgo-enabled: "0"}
+          - {goos: "freebsd", goarch: "amd64", runson: "ubuntu-latest", cgo-enabled: "0"}
+          - {goos: "freebsd", goarch: "arm", runson: "ubuntu-latest", cgo-enabled: "0"}
+          - {goos: "linux", goarch: "386", runson: "ubuntu-latest", cgo-enabled: "0"}
+          - {goos: "linux", goarch: "amd64", runson: "ubuntu-latest", cgo-enabled: "0"}
+          - {goos: "linux", goarch: "arm", runson: "ubuntu-latest", cgo-enabled: "0"}
+          - {goos: "linux", goarch: "arm64", runson: "ubuntu-latest", cgo-enabled: "0"}
+          - {goos: "openbsd", goarch: "386", runson: "ubuntu-latest", cgo-enabled: "0"}
+          - {goos: "openbsd", goarch: "amd64", runson: "ubuntu-latest", cgo-enabled: "0"}
+          - {goos: "solaris", goarch: "amd64", runson: "ubuntu-latest", cgo-enabled: "0"}
+          - {goos: "windows", goarch: "386", runson: "ubuntu-latest", cgo-enabled: "0"}
+          - {goos: "windows", goarch: "amd64", runson: "ubuntu-latest", cgo-enabled: "0"}
+          - {goos: "darwin", goarch: "amd64", runson: "macos-latest", cgo-enabled: "1"}
+          - {goos: "darwin", goarch: "arm64", runson: "macos-latest", cgo-enabled: "1"}
+      fail-fast: false
+
+  package-docker:
+    name: Build Docker image for linux_${{ matrix.arch }}
+    runs-on: ubuntu-latest
+    needs:
+      - get-product-version
+      - build
+    strategy:
+      matrix:
+        arch: ["amd64", "386", "arm", "arm64"]
+      fail-fast: false
+    env:
+      repo: "terraform"
+      version: ${{needs.get-product-version.outputs.product-version}}
+    steps:
+      - uses: actions/checkout@v3
+      - name: Build Docker images
+        uses: hashicorp/actions-docker-build@v1
+        with:
+          pkg_name: "terraform_${{env.version}}"
+          version: ${{env.version}}
+          bin_name: terraform
+          target: default
+          arch: ${{matrix.arch}}
+          dockerfile: .github/workflows/build-Dockerfile
+          smoke_test: .github/scripts/verify_docker v${{ env.version }}
+          tags: |
+            docker.io/hashicorp/${{env.repo}}:${{env.version}}
+            public.ecr.aws/hashicorp/${{env.repo}}:${{env.version}}
+
+  e2etest-build:
+    name: Build e2etest for ${{ matrix.goos }}_${{ matrix.goarch }}
+    runs-on: ubuntu-latest
+    outputs:
+      e2e-cache-key: ${{ steps.set-cache-values.outputs.e2e-cache-key }}
+      e2e-cache-path: ${{ steps.set-cache-values.outputs.e2e-cache-path }}
+    needs:
+      - get-product-version
+      - get-go-version
+    strategy:
+      matrix:
+        include:
+          - {goos: "darwin", goarch: "amd64"}
+          - {goos: "darwin", goarch: "arm64"}
+          - {goos: "windows", goarch: "amd64"}
+          - {goos: "windows", goarch: "386"}
+          - {goos: "linux", goarch: "386"}
+          - {goos: "linux", goarch: "amd64"}
+          - {goos: linux, goarch: "arm"}
+          - {goos: linux, goarch: "arm64"}
+      fail-fast: false
+
+    env:
+      build_script: ./internal/command/e2etest/make-archive.sh
+
+    steps:
+      - name: Set Cache Values
+        id: set-cache-values
+        run: |
+          cache_key=e2e-cache-${{ github.sha }}
+          cache_path=internal/command/e2etest/build
+          echo "e2e-cache-key=${cache_key}" | tee -a "${GITHUB_OUTPUT}"
+          echo "e2e-cache-path=${cache_path}" | tee -a "${GITHUB_OUTPUT}"
+      - uses: actions/checkout@v3
+
+      - name: Install Go toolchain
+        uses: actions/setup-go@v3
+        with:
+          go-version: ${{ needs.get-go-version.outputs.go-version }}
+
+      - name: Build test harness package
+        env:
+          GOOS: ${{ matrix.goos }}
+          GOARCH: ${{ matrix.goarch }}
+          GO_LDFLAGS: ${{ needs.get-product-version.outputs.go-ldflags }}
+        run: |
+          # NOTE: This script reacts to the GOOS, GOARCH, and GO_LDFLAGS
+          # environment variables defined above. The e2e test harness
+          # needs to know the version we're building for so it can verify
+          # that "terraform version" is returning that version number.
+          bash ./internal/command/e2etest/make-archive.sh
+
+      - name: Save test harness to cache
+        uses: actions/cache/save@v3
+        with:
+          path: ${{ steps.set-cache-values.outputs.e2e-cache-path }}
+          key: ${{ steps.set-cache-values.outputs.e2e-cache-key }}_${{ matrix.goos }}_${{ matrix.goarch }}
+
+  e2e-test:
+    name: Run e2e test for ${{ matrix.goos }}_${{ matrix.goarch }}
+    runs-on: ${{ matrix.runson }}
+    needs:
+      - get-product-version
+      - build
+      - e2etest-build
+    strategy:
+      matrix:
+        include:
+          - { runson: ubuntu-latest, goos: linux, goarch: "amd64" }
+          - { runson: ubuntu-latest, goos: linux, goarch: "386" }
+          - { runson: ubuntu-latest, goos: linux, goarch: "arm" }
+          - { runson: ubuntu-latest, goos: linux, goarch: "arm64" }
+          - { runson: macos-latest, goos: darwin, goarch: "amd64" }
+          - { runson: windows-latest, goos: windows, goarch: "amd64" }
+          - { runson: windows-latest, goos: windows, goarch: "386" }
+      fail-fast: false
+
+    env:
+      os: ${{ matrix.goos }}
+      arch: ${{ matrix.goarch }}
+      version: ${{needs.get-product-version.outputs.product-version}}
+
+    steps:
+      # NOTE: This intentionally _does not_ check out the source code
+      # for the commit/tag we're building, because by now we should
+      # have everything we need in the combination of CLI release package
+      # and e2etest package for this platform. (This helps ensure that we're
+      # really testing the release package and not inadvertently testing a
+      # fresh build from source.)
+      - name: Checkout repo
+        if: ${{ (matrix.goos == 'linux') || (matrix.goos == 'darwin') }}
+        uses: actions/checkout@v3
+      - name: "Restore cache"
+        uses: actions/cache/restore@v3
+        id: e2etestpkg
+        with:
+          path: ${{ needs.e2etest-build.outputs.e2e-cache-path }}
+          key: ${{ needs.e2etest-build.outputs.e2e-cache-key }}_${{ matrix.goos }}_${{ matrix.goarch }}
+          fail-on-cache-miss: true
+          enableCrossOsArchive: true
+      - name: "Download Terraform CLI package"
+        uses: actions/download-artifact@v2
+        id: clipkg
+        with:
+          name: terraform_${{env.version}}_${{ env.os }}_${{ env.arch }}.zip
+          path: .
+      - name: Extract packages
+        if: ${{ matrix.goos == 'windows' }}
+        run: |
+          unzip "${{ needs.e2etest-build.outputs.e2e-cache-path }}/terraform-e2etest_${{ env.os }}_${{ env.arch }}.zip"
+          unzip "./terraform_${{env.version}}_${{ env.os }}_${{ env.arch }}.zip"
+      - name: Set up QEMU
+        uses: docker/setup-qemu-action@v1
+        if: ${{ contains(matrix.goarch, 'arm') }}
+        with:
+          platforms: all
+      - name: Run E2E Tests (Darwin & Linux)
+        id: get-product-version
+        shell: bash
+        if: ${{ (matrix.goos == 'linux') || (matrix.goos == 'darwin') }}
+        env:
+          e2e_cache_path: ${{ needs.e2etest-build.outputs.e2e-cache-path }}
+        run: .github/scripts/e2e_test_linux_darwin.sh
+      - name: Run E2E Tests (Windows)
+        if: ${{ matrix.goos == 'windows' }}
+        env:
+          TF_ACC: 1
+        shell: cmd
+        run: e2etest.exe -test.v
+
+
+  e2e-test-exec:
+    name: Run terraform-exec test for linux amd64
+    runs-on: ubuntu-latest
+    needs:
+      - get-product-version
+      - get-go-version
+      - build
+
+    env:
+      os: ${{ matrix.goos }}
+      arch: ${{ matrix.goarch }}
+      version: ${{needs.get-product-version.outputs.product-version}}
+
+    steps:
+      - name: Install Go toolchain
+        uses: actions/setup-go@v3
+        with:
+          go-version: ${{ needs.get-go-version.outputs.go-version }}
+      - name: Download Terraform CLI package
+        uses: actions/download-artifact@v2
+        id: clipkg
+        with:
+          name: terraform_${{ env.version }}_linux_amd64.zip
+          path: .
+      - name: Checkout terraform-exec repo
+        uses: actions/checkout@v3
+        with:
+          repository: hashicorp/terraform-exec
+          path: terraform-exec
+      - name: Run terraform-exec end-to-end tests
+        run: |
+          FULL_RELEASE_VERSION="${{ env.version }}"
+          unzip terraform_${FULL_RELEASE_VERSION}_linux_amd64.zip
+          export TFEXEC_E2ETEST_TERRAFORM_PATH="$(pwd)/terraform"
+          cd terraform-exec
+          go test -race -timeout=30m -v ./tfexec/internal/e2etest
diff --git a/v1.5.7/.github/workflows/checks.yml b/v1.5.7/.github/workflows/checks.yml
new file mode 100644
index 0000000..c275445
--- /dev/null
+++ b/v1.5.7/.github/workflows/checks.yml
@@ -0,0 +1,190 @@
+# This workflow is a collection of "quick checks" that should be reasonable
+# to run for any new commit to this repository in principle.
+#
+# The main purpose of this workflow is to represent checks that we want to
+# run prior to reviewing and merging a pull request. We should therefore aim
+# for these checks to complete in no more than a few minutes in the common
+# case.
+#
+# The build.yml workflow includes some additional checks we run only for
+# already-merged changes to release branches and tags, as a compromise to
+# keep the PR feedback relatively fast. The intent is that checks.yml should
+# catch most problems but that build.yml might occasionally by the one to catch
+# more esoteric situations, such as architecture-specific or OS-specific
+# misbehavior.
+
+name: Quick Checks
+
+on:
+  pull_request:
+  push:
+    branches:
+      - main
+      - 'v[0-9]+.[0-9]+'
+      - checks-workflow-dev/*
+    tags:
+      - 'v[0-9]+.[0-9]+.[0-9]+*'
+
+# This workflow runs for not-yet-reviewed external contributions and so it
+# intentionally has no write access and only limited read access to the
+# repository.
+permissions:
+  contents: read
+
+jobs:
+  unit-tests:
+    name: "Unit Tests"
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: "Fetch source code"
+        uses: actions/checkout@v2
+
+      - name: Determine Go version
+        id: go
+        uses: ./.github/actions/go-version
+
+      - name: Install Go toolchain
+        uses: actions/setup-go@v2
+        with:
+          go-version: ${{ steps.go.outputs.version }}
+
+      # NOTE: This cache is shared so the following step must always be
+      # identical across the unit-tests, e2e-tests, and consistency-checks
+      # jobs, or else weird things could happen.
+      - name: Cache Go modules
+        uses: actions/cache@v3
+        with:
+          path: "~/go/pkg"
+          key: go-mod-${{ hashFiles('go.sum') }}
+          restore-keys: |
+            go-mod-
+
+      - name: "Unit tests"
+        run: |
+          go test ./...
+
+  race-tests:
+    name: "Race Tests"
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: "Fetch source code"
+        uses: actions/checkout@v2
+
+      - name: Determine Go version
+        id: go
+        uses: ./.github/actions/go-version
+
+      - name: Install Go toolchain
+        uses: actions/setup-go@v2
+        with:
+          go-version: ${{ steps.go.outputs.version }}
+
+      # NOTE: This cache is shared so the following step must always be
+      # identical across the unit-tests, e2e-tests, and consistency-checks
+      # jobs, or else weird things could happen.
+      - name: Cache Go modules
+        uses: actions/cache@v3
+        with:
+          path: "~/go/pkg"
+          key: go-mod-${{ hashFiles('go.sum') }}
+          restore-keys: |
+            go-mod-
+
+      # The race detector add significant time to the unit tests, so only run
+      # it for select packages.
+      - name: "Race detector"
+        run: |
+          go test -race ./internal/terraform ./internal/command ./internal/states
+
+  e2e-tests:
+    # This is an intentionally-limited form of our E2E test run which only
+    # covers Terraform running on Linux. The build.yml workflow runs these
+    # tests across various other platforms in order to catch the rare exception
+    # that might leak through this.
+    name: "End-to-end Tests"
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: "Fetch source code"
+        uses: actions/checkout@v2
+
+      - name: Determine Go version
+        id: go
+        uses: ./.github/actions/go-version
+
+      - name: Install Go toolchain
+        uses: actions/setup-go@v2
+        with:
+          go-version: ${{ steps.go.outputs.version }}
+
+      # NOTE: This cache is shared so the following step must always be
+      # identical across the unit-tests, e2e-tests, and consistency-checks
+      # jobs, or else weird things could happen.
+      - name: Cache Go modules
+        uses: actions/cache@v3
+        with:
+          path: "~/go/pkg"
+          key: go-mod-${{ hashFiles('go.sum') }}
+          restore-keys: |
+            go-mod-
+
+      - name: "End-to-end tests"
+        run: |
+          TF_ACC=1 go test -v ./internal/command/e2etest
+
+  consistency-checks:
+    name: "Code Consistency Checks"
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: "Fetch source code"
+        uses: actions/checkout@v2
+        with:
+          fetch-depth: 0 # We need to do comparisons against the main branch.
+
+      - name: Determine Go version
+        id: go
+        uses: ./.github/actions/go-version
+
+      - name: Install Go toolchain
+        uses: actions/setup-go@v2
+        with:
+          go-version: ${{ steps.go.outputs.version }}
+
+      # NOTE: This cache is shared so the following step must always be
+      # identical across the unit-tests, e2e-tests, and consistency-checks
+      # jobs, or else weird things could happen.
+      - name: Cache Go modules
+        uses: actions/cache@v3
+        with:
+          path: "~/go/pkg"
+          key: go-mod-${{ hashFiles('go.sum') }}
+          restore-keys: |
+            go-mod-
+
+      - name: "go.mod and go.sum consistency check"
+        run: |
+          go mod tidy
+          if [[ -n "$(git status --porcelain)" ]]; then
+            echo >&2 "ERROR: go.mod/go.sum are not up-to-date. Run 'go mod tidy' and then commit the updated files."
+            exit 1
+          fi
+
+      - name: Cache protobuf tools
+        uses: actions/cache@v3
+        with:
+          path: "tools/protobuf-compile/.workdir"
+          key: protobuf-tools-${{ hashFiles('tools/protobuf-compile/protobuf-compile.go') }}
+          restore-keys: |
+            protobuf-tools-
+
+      - name: "Code consistency checks"
+        run: |
+          make fmtcheck importscheck generate staticcheck exhaustive protobuf
+          if [[ -n "$(git status --porcelain)" ]]; then
+            echo >&2 "ERROR: Generated files are inconsistent. Run 'make generate' and 'make protobuf' locally and then commit the updated files."
+            git >&2 status --porcelain
+            exit 1
+          fi
diff --git a/v1.5.7/.github/workflows/crt-hook-equivalence-tests.yml b/v1.5.7/.github/workflows/crt-hook-equivalence-tests.yml
new file mode 100644
index 0000000..a4607cc
--- /dev/null
+++ b/v1.5.7/.github/workflows/crt-hook-equivalence-tests.yml
@@ -0,0 +1,45 @@
+name: crt-hook-equivalence-tests
+
+on:
+  repository_dispatch:
+    types:
+      - crt-hook-equivalence-tests::terraform::*
+
+permissions:
+  contents: write
+
+jobs:
+  parse-metadata:
+    name: "Parse metadata.json"
+    runs-on: ubuntu-latest
+    outputs:
+      version: ${{ steps.parse.outputs.version }}
+      target-branch: ${{ steps.parse.outputs.target-branch }}
+    steps:
+      - name: parse
+        id: parse
+        env:
+          METADATA_PAYLOAD: ${{ toJSON(github.event.client_payload.payload) }}
+        run: |
+          VERSION=$(echo ${METADATA_PAYLOAD} | jq -r '.version')
+          TARGET_BRANCH=$(./.github/scripts/equivalence-test.sh get-target-branch "$VERSION")
+          
+          echo "target-branch=$TARGET_BRANCH" >> "GITHUB_OUTPUT"
+          echo "version=$VERSION" >> "$GITHUB_OUTPUT"
+
+  run-equivalence-tests:
+    runs-on: ubuntu-latest
+    name: "Run equivalence tests"
+    needs:
+      - parse-metadata
+    steps:
+      - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
+        with:
+          ref: ${{ needs.parse-metadata.outputs.target-branch }}
+      - uses: ./.github/actions/equivalence-test
+        with:
+          target-terraform-version: ${{ needs.parse-metadata.outputs.version }}
+          target-terraform-branch: ${{ needs.parse-metadata.outputs.target-branch }}
+          target-equivalence-test-version: 0.3.0
+          target-os: linux
+          target-arch: amd64
diff --git a/v1.5.7/.github/workflows/issue-comment-created.yml b/v1.5.7/.github/workflows/issue-comment-created.yml
new file mode 100644
index 0000000..b8c4d6b
--- /dev/null
+++ b/v1.5.7/.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@v1
+        with:
+          labels: |
+            stale
+            waiting-reply
diff --git a/v1.5.7/.github/workflows/lock.yml b/v1.5.7/.github/workflows/lock.yml
new file mode 100644
index 0000000..ed67648
--- /dev/null
+++ b/v1.5.7/.github/workflows/lock.yml
@@ -0,0 +1,23 @@
+name: 'Lock Threads'
+
+on:
+  schedule:
+    - cron: '50 1 * * *'
+
+jobs:
+  lock:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: dessant/lock-threads@v2
+        with:
+          github-token: ${{ github.token }}
+          issue-lock-comment: >
+            I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues.
+
+            If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.
+          issue-lock-inactive-days: '30'
+          pr-lock-comment: >
+            I'm going to lock this pull request because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active contributions.
+
+            If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.
+          pr-lock-inactive-days: '30'
diff --git a/v1.5.7/.github/workflows/main.yml b/v1.5.7/.github/workflows/main.yml
new file mode 100644
index 0000000..08b438d
--- /dev/null
+++ b/v1.5.7/.github/workflows/main.yml
@@ -0,0 +1,21 @@
+---
+name: Backport Assistant Runner
+    
+on:
+  pull_request_target:
+    types:
+      - closed
+    
+jobs:
+  backport:
+    if: github.event.pull_request.merged
+    runs-on: ubuntu-latest
+    container: hashicorpdev/backport-assistant:0.2.1
+    steps:
+      - name: Run Backport Assistant
+        run: |
+          backport-assistant backport
+        env:
+          BACKPORT_LABEL_REGEXP: "(?P<target>\\d+\\.\\d+)-backport"
+          BACKPORT_TARGET_TEMPLATE: "v{{.target}}"
+          GITHUB_TOKEN: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
diff --git a/v1.5.7/.github/workflows/manual-equivalence-tests.yml b/v1.5.7/.github/workflows/manual-equivalence-tests.yml
new file mode 100644
index 0000000..fb6b0d5
--- /dev/null
+++ b/v1.5.7/.github/workflows/manual-equivalence-tests.yml
@@ -0,0 +1,37 @@
+name: manual-equivalence-tests
+
+on:
+  workflow_dispatch:
+    inputs:
+      target-branch:
+        type: string
+        description: "Which branch should be updated?"
+        required: true
+      terraform-version:
+        type: string
+        description: "Terraform version to run against (no v prefix, eg. 1.4.4)."
+        required: true
+      equivalence-test-version:
+        type: string
+        description: 'Equivalence testing framework version to use (no v prefix, eg. 0.3.0).'
+        default: "0.3.0"
+        required: true
+
+permissions:
+  contents: write # We push updates to the equivalence tests back into the repository.
+
+jobs:
+  run-equivalence-tests:
+    name: "Run equivalence tests"
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
+        with:
+          ref: ${{ inputs.target-branch }}
+      - uses: ./.github/actions/equivalence-test
+        with:
+          target-terraform-version: ${{ inputs.terraform-version }}
+          target-terraform-branch: ${{ inputs.target-branch }}
+          target-equivalence-test-version: ${{ inputs.equivalence-test-version }}
+          target-os: linux
+          target-arch: amd64
diff --git a/v1.5.7/.github/workflows/merged-pr.yml b/v1.5.7/.github/workflows/merged-pr.yml
new file mode 100644
index 0000000..df1249a
--- /dev/null
+++ b/v1.5.7/.github/workflows/merged-pr.yml
@@ -0,0 +1,24 @@
+name: Merged Pull Request
+permissions:
+  pull-requests: write
+
+# only trigger on pull request closed events
+on:
+  pull_request_target:
+    types: [ closed ]
+
+jobs:
+  merge_job:
+    # this job will only run if the PR has been merged
+    if: github.event.pull_request.merged == true
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/github-script@v5
+        with:
+          script: |
+            github.rest.issues.createComment({
+              issue_number: context.issue.number,
+              owner: context.repo.owner,
+              repo: context.repo.repo,
+              body: "Reminder for the merging maintainer: if this is a user-visible change, please update the changelog on the appropriate release branch."
+            })
diff --git a/v1.5.7/.gitignore b/v1.5.7/.gitignore
new file mode 100644
index 0000000..cc34a88
--- /dev/null
+++ b/v1.5.7/.gitignore
@@ -0,0 +1,27 @@
+*.dll
+*.exe
+.DS_Store
+bin/
+modules-dev/
+/pkg/
+website/.vagrant
+website/.bundle
+website/build
+website/node_modules
+.vagrant/
+*.backup
+*.bak
+*~
+.*.swp
+.idea
+*.iml
+*.test
+*.iml
+
+/terraform
+
+website/vendor
+vendor/
+
+# Coverage
+coverage.txt
diff --git a/v1.5.7/.go-version b/v1.5.7/.go-version
new file mode 100644
index 0000000..8909929
--- /dev/null
+++ b/v1.5.7/.go-version
@@ -0,0 +1 @@
+1.20.7
diff --git a/v1.5.7/.release/ci.hcl b/v1.5.7/.release/ci.hcl
new file mode 100644
index 0000000..0b4c1e9
--- /dev/null
+++ b/v1.5.7/.release/ci.hcl
@@ -0,0 +1,166 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+schema = "1"
+
+project "terraform" {
+  // the team key is not used by CRT currently
+  team = "terraform"
+  slack {
+    notification_channel = "C011WJ112MD"
+  }
+  github {
+    organization = "hashicorp"
+    repository = "terraform"
+
+    release_branches = [
+      "main",
+      "release/**",
+      "v**.**",
+    ]
+  }
+}
+
+event "build" {
+  depends = ["merge"]
+  action "build" {
+    organization = "hashicorp"
+    repository = "terraform"
+    workflow = "build"
+  }
+}
+
+// Read more about what the `prepare` workflow does here:
+// https://hashicorp.atlassian.net/wiki/spaces/RELENG/pages/2489712686/Dec+7th+2022+-+Introducing+the+new+Prepare+workflow
+event "prepare" {
+  depends = ["build"]
+
+  action "prepare" {
+    organization = "hashicorp"
+    repository   = "crt-workflows-common"
+    workflow     = "prepare"
+    depends      = ["build"]
+  }
+
+  notification {
+    on = "fail"
+  }
+}
+
+## These are promotion and post-publish events
+## they should be added to the end of the file after the verify event stanza.
+
+event "trigger-staging" {
+// This event is dispatched by the bob trigger-promotion command
+// and is required - do not delete.
+}
+
+event "promote-staging" {
+  depends = ["trigger-staging"]
+  action "promote-staging" {
+    organization = "hashicorp"
+    repository = "crt-workflows-common"
+    workflow = "promote-staging"
+    config = "release-metadata.hcl"
+  }
+
+  notification {
+    on = "always"
+  }
+}
+
+event "promote-staging-docker" {
+  depends = ["promote-staging"]
+  action "promote-staging-docker" {
+    organization = "hashicorp"
+    repository = "crt-workflows-common"
+    workflow = "promote-staging-docker"
+  }
+
+  notification {
+    on = "always"
+  }
+}
+
+event "promote-staging-packaging" {
+  depends = ["promote-staging-docker"]
+  action "promote-staging-packaging" {
+    organization = "hashicorp"
+    repository = "crt-workflows-common"
+    workflow = "promote-staging-packaging"
+  }
+
+  notification {
+    on = "always"
+  }
+}
+
+event "trigger-production" {
+// This event is dispatched by the bob trigger-promotion command
+// and is required - do not delete.
+}
+
+event "promote-production" {
+  depends = ["trigger-production"]
+  action "promote-production" {
+    organization = "hashicorp"
+    repository = "crt-workflows-common"
+    workflow = "promote-production"
+  }
+
+  notification {
+    on = "always"
+  }
+}
+
+event "promote-production-docker" {
+  depends = ["promote-production"]
+  action "promote-production-docker" {
+    organization = "hashicorp"
+    repository = "crt-workflows-common"
+    workflow = "promote-production-docker"
+  }
+
+  notification {
+    on = "always"
+  }
+}
+
+event "promote-production-packaging" {
+  depends = ["promote-production-docker"]
+  action "promote-production-packaging" {
+    organization = "hashicorp"
+    repository = "crt-workflows-common"
+    workflow = "promote-production-packaging"
+  }
+
+  notification {
+    on = "always"
+  }
+}
+
+event "crt-hook-tfc-upload" {
+  depends = ["promote-production-packaging"]
+  action "crt-hook-tfc-upload" {
+    organization = "hashicorp"
+    repository = "terraform-releases"
+    workflow = "crt-hook-tfc-upload"
+  }
+
+  notification {
+    on = "always"
+  }
+}
+
+event "update-ironbank" {
+  depends = ["crt-hook-tfc-upload"]
+  action "update-ironbank" {
+    organization = "hashicorp"
+    repository = "crt-workflows-common"
+    workflow = "update-ironbank"
+  }
+
+  notification {
+    on = "always"
+  }
+}
diff --git a/v1.5.7/.release/release-metadata.hcl b/v1.5.7/.release/release-metadata.hcl
new file mode 100644
index 0000000..06f7f89
--- /dev/null
+++ b/v1.5.7/.release/release-metadata.hcl
@@ -0,0 +1,8 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+url_docker_registry_dockerhub = "https://hub.docker.com/r/hashicorp/terraform"
+url_docker_registry_ecr = "https://gallery.ecr.aws/hashicorp/terraform"
+url_license = "https://github.com/hashicorp/terraform/blob/main/LICENSE"
+url_project_website = "https://www.terraform.io"
+url_source_repository = "https://github.com/hashicorp/terraform"
\ No newline at end of file
diff --git a/v1.5.7/.release/security-scan.hcl b/v1.5.7/.release/security-scan.hcl
new file mode 100644
index 0000000..bb86c5c
--- /dev/null
+++ b/v1.5.7/.release/security-scan.hcl
@@ -0,0 +1,16 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+container {
+  dependencies = false
+  alpine_secdb = true
+  secrets      = false
+}
+
+binary {
+  secrets      = true
+  go_modules   = true
+  osv          = false
+  oss_index    = true
+  nvd          = false
+}
\ No newline at end of file
diff --git a/v1.5.7/.tfdev b/v1.5.7/.tfdev
new file mode 100644
index 0000000..857b02d
--- /dev/null
+++ b/v1.5.7/.tfdev
@@ -0,0 +1,7 @@
+version_info {
+  version_var =    "github.com/hashicorp/terraform/version.Version"
+  prerelease_var = "github.com/hashicorp/terraform/version.Prerelease"
+}
+
+version_exec = false
+disable_provider_requirements = true
diff --git a/v1.5.7/BUGPROCESS.md b/v1.5.7/BUGPROCESS.md
new file mode 100644
index 0000000..faad74d
--- /dev/null
+++ b/v1.5.7/BUGPROCESS.md
@@ -0,0 +1,85 @@
+# Terraform Core GitHub Bug Triage & Labeling
+The Terraform Core team has adopted a more structured bug triage process than we previously used. Our goal is to respond to reports of issues quickly.
+
+When a bug report is filed, our goal is to either:
+1. Get it to a state where it is ready for engineering to fix it in an upcoming Terraform release, or 
+2. Close it and explain why, if we can't help
+
+## Process
+
+### 1. [Newly created issues](https://github.com/hashicorp/terraform/issues?q=is%3Aopen+label%3Anew+label%3Abug+-label%3Abackend%2Fk8s+-label%3Abackend%2Foss+-label%3Abackend%2Fazure+-label%3Abackend%2Fs3+-label%3Abackend%2Fgcs+-label%3Abackend%2Fconsul+-label%3Abackend%2Fartifactory+-label%3Aterraform-cloud+-label%3Abackend%2Fremote+-label%3Abackend%2Fswift+-label%3Abackend%2Fpg+-label%3Abackend%2Ftencent++-label%3Abackend%2Fmanta++-label%3Abackend%2Fatlas++-label%3Abackend%2Fetcdv3++-label%3Abackend%2Fetcdv2+-label%3Aconfirmed+-label%3A%22pending+project%22+-label%3A%22waiting+for+reproduction%22+-label%3A%22waiting-response%22+-label%3Aexplained+) require initial filtering. 
+
+These are raw reports that need categorization and support clarifying them. They need the following done:
+
+* label backends, provisioners, and providers so we can route work on codebases we don't support to the correct teams
+* point requests for help to the community forum and close the issue
+* close reports against old versions we no longer support
+* prompt users who have submitted obviously incomplete reproduction cases for additional information
+
+If an issue requires discussion with the user to get it out of this initial state, leave "new" on there and label it "waiting-response" until this phase of triage is done.
+
+Once this initial filtering has been done, remove the new label. If an issue subjectively looks very high-impact and likely to impact many users, assign it to the [appropriate milestone](https://github.com/hashicorp/terraform/milestones) to mark it as being urgent.
+
+### 2. Clarify [unreproduced issues](https://github.com/hashicorp/terraform/issues?q=is%3Aopen+label%3Abug+created%3A%3E2020-05-01+-label%3Abackend%2Fk8s+-label%3Aprovisioner%2Fsalt-masterless+-label%3Adocumentation+-label%3Aprovider%2Fazuredevops+-label%3Abackend%2Foss+-label%3Abackend%2Fazure+-label%3Abackend%2Fs3+-label%3Abackend%2Fgcs+-label%3Abackend%2Fconsul+-label%3Abackend%2Fartifactory+-label%3Aterraform-cloud+-label%3Abackend%2Fremote+-label%3Abackend%2Fswift+-label%3Abackend%2Fpg+-label%3Abackend%2Ftencent+-label%3Abackend%2Fmanta+-label%3Abackend%2Fatlas+-label%3Abackend%2Fetcdv3+-label%3Abackend%2Fetcdv2+-label%3Aconfirmed+-label%3A%22pending+project%22+-label%3Anew+-label%3A%22waiting+for+reproduction%22+-label%3Awaiting-response+-label%3Aexplained+sort%3Acreated-asc+)
+
+A core team member initially determines whether the issue is immediately reproducible. If they cannot readily reproduce it, they label it "waiting for reproduction" and correspond with the reporter to describe what is needed. When the issue is reproduced by a core team member, they label it "confirmed". 
+
+"confirmed" issues should have a clear reproduction case. Anyone who picks it up should be able to reproduce it readily without having to invent any details.
+
+Note that the link above excludes issues reported before May 2020; this is to avoid including issues that were reported prior to this new process being implemented. [Unreproduced issues reported before May 2020](https://github.com/hashicorp/terraform/issues?q=is%3Aopen+label%3Abug+created%3A%3C2020-05-01+-label%3Aprovisioner%2Fsalt-masterless+-label%3Adocumentation+-label%3Aprovider%2Fazuredevops+-label%3Abackend%2Foss+-label%3Abackend%2Fazure+-label%3Abackend%2Fs3+-label%3Abackend%2Fgcs+-label%3Abackend%2Fconsul+-label%3Abackend%2Fartifactory+-label%3Aterraform-cloud+-label%3Abackend%2Fremote+-label%3Abackend%2Fswift+-label%3Abackend%2Fpg+-label%3Abackend%2Ftencent+-label%3Abackend%2Fmanta+-label%3Abackend%2Fatlas+-label%3Abackend%2Fetcdv3+-label%3Abackend%2Fetcdv2+-label%3Aconfirmed+-label%3A%22pending+project%22+-label%3Anew+-label%3A%22waiting+for+reproduction%22+-label%3Awaiting-response+-label%3Aexplained+sort%3Areactions-%2B1-desc) will be triaged as capacity permits.
+
+
+### 3. Explain or fix [confirmed issues](https://github.com/hashicorp/terraform/issues?q=is%3Aopen+label%3Abug+-label%3Aexplained+-label%3Abackend%2Foss+-label%3Abackend%2Fk8s+-label%3Abackend%2Fazure+-label%3Abackend%2Fs3+-label%3Abackend%2Fgcs+-label%3Abackend%2Fconsul+-label%3Abackend%2Fartifactory+-label%3Aterraform-cloud+-label%3Abackend%2Fremote+-label%3Abackend%2Fswift+-label%3Abackend%2Fpg+-label%3Abackend%2Ftencent++-label%3Abackend%2Fmanta++-label%3Abackend%2Fatlas++-label%3Abackend%2Fetcdv3++-label%3Abackend%2Fetcdv2+label%3Aconfirmed+-label%3A%22pending+project%22+)
+The next step for confirmed issues is to either:
+
+* explain why the behavior is expected, label the issue as "working as designed", and close it, or
+* locate the cause of the defect in the codebase. When the defect is located, and that description is posted on the issue, the issue is labeled "explained". In many cases, this step will get skipped if the fix is obvious, and engineers will jump forward and make a PR. 
+
+ [Confirmed crashes](https://github.com/hashicorp/terraform/issues?q=is%3Aopen+label%3Acrash+label%3Abug+-label%3Abackend%2Fk8s+-label%3Aexplained+-label%3Abackend%2Foss+-label%3Abackend%2Fazure+-label%3Abackend%2Fs3+-label%3Abackend%2Fgcs+-label%3Abackend%2Fconsul+-label%3Abackend%2Fartifactory+-label%3Aterraform-cloud+-label%3Abackend%2Fremote+-label%3Abackend%2Fswift+-label%3Abackend%2Fpg+-label%3Abackend%2Ftencent++-label%3Abackend%2Fmanta++-label%3Abackend%2Fatlas++-label%3Abackend%2Fetcdv3++-label%3Abackend%2Fetcdv2+label%3Aconfirmed+-label%3A%22pending+project%22+) should generally be considered high impact
+
+### 4. The last step for [explained issues](https://github.com/hashicorp/terraform/issues?q=is%3Aopen+label%3Abug+label%3Aexplained+no%3Amilestone+-label%3Abackend%2Fk8s+-label%3Abackend%2Foss+-label%3Abackend%2Fazure+-label%3Abackend%2Fs3+-label%3Abackend%2Fgcs+-label%3Abackend%2Fconsul+-label%3Abackend%2Fartifactory+-label%3Aterraform-cloud+-label%3Abackend%2Fremote+-label%3Abackend%2Fswift+-label%3Abackend%2Fpg+-label%3Abackend%2Ftencent++-label%3Abackend%2Fmanta++-label%3Abackend%2Fatlas++-label%3Abackend%2Fetcdv3++-label%3Abackend%2Fetcdv2+label%3Aconfirmed+-label%3A%22pending+project%22+) is to make a PR to fix them. 
+
+Explained issues that are expected to be fixed in a future release should be assigned to a milestone
+
+## GitHub Issue Labels
+label                    | description
+------------------------ | -----------
+new                      | new issue not yet triaged
+explained                | a Terraform Core team member has described the root cause of this issue in code
+waiting for reproduction | unable to reproduce issue without further information 
+not reproducible         | closed because a reproduction case could not be generated
+duplicate                | issue closed because another issue already tracks this problem
+confirmed                | a Terraform Core team member has reproduced this issue
+working as designed      | confirmed as reported and closed because the behavior is intended
+pending project          | issue is confirmed but will require a significant project to fix
+
+## Lack of response and unreproducible issues
+When bugs that have been [labeled waiting response](https://github.com/hashicorp/terraform/issues?q=is%3Aopen+label%3Abug+-label%3Abackend%2Foss+-label%3Abackend%2Fk8s+-label%3Abackend%2Fazure+-label%3Abackend%2Fs3+-label%3Abackend%2Fgcs+-label%3Abackend%2Fconsul+-label%3Abackend%2Fartifactory+-label%3Aterraform-cloud+-label%3Abackend%2Fremote+-label%3Abackend%2Fswift+-label%3Abackend%2Fpg+-label%3Abackend%2Ftencent+-label%3Abackend%2Fmanta+-label%3Abackend%2Fatlas+-label%3Abackend%2Fetcdv3+-label%3Abackend%2Fetcdv2+-label%3Aconfirmed+-label%3A%22pending+project%22+-label%3A%22waiting+for+reproduction%22+label%3Awaiting-response+-label%3Aexplained+sort%3Aupdated-asc+) or [labeled "waiting for reproduction"](https://github.com/hashicorp/terraform/issues?q=is%3Aopen+label%3Abug+-label%3Abackend%2Foss+-label%3Abackend%2Fazure+-label%3Abackend%2Fs3+-label%3Abackend%2Fgcs+-label%3Abackend%2Fconsul+-label%3Abackend%2Fartifactory+-label%3Aterraform-cloud+-label%3Abackend%2Fremote+-label%3Abackend%2Fswift+-label%3Abackend%2Fpg+-label%3Abackend%2Ftencent+-label%3Abackend%2Fmanta+-label%3Abackend%2Fatlas+-label%3Abackend%2Fetcdv3+-label%3Abackend%2Fetcdv2+-label%3Aconfirmed+-label%3A%22pending+project%22+label%3A%22waiting+for+reproduction%22+-label%3Aexplained+sort%3Aupdated-asc+) for more than 30 days, we'll use our best judgement to determine whether it's more helpful to close it or prompt the reporter again. If they again go without a response for 30 days, they can be closed with a polite message explaining why and inviting the person to submit the needed information or reproduction case in the future.
+
+The intent of this process is to get fix the maximum number of bugs in Terraform as quickly as possible, and having un-actionable bug reports makes it harder for Terraform Core team members and community contributors to find bugs they can actually work on.
+
+## Helpful GitHub Filters
+
+### Triage Process
+1. [Newly created issues](https://github.com/hashicorp/terraform/issues?q=is%3Aopen+label%3Anew+label%3Abug+-label%3Abackend%2Foss+-label%3Abackend%2Fk8s+-label%3Abackend%2Fazure+-label%3Abackend%2Fs3+-label%3Abackend%2Fgcs+-label%3Abackend%2Fconsul+-label%3Abackend%2Fartifactory+-label%3Aterraform-cloud+-label%3Abackend%2Fremote+-label%3Abackend%2Fswift+-label%3Abackend%2Fpg+-label%3Abackend%2Ftencent++-label%3Abackend%2Fmanta++-label%3Abackend%2Fatlas++-label%3Abackend%2Fetcdv3++-label%3Abackend%2Fetcdv2+-label%3Aconfirmed+-label%3A%22pending+project%22+-label%3A%22waiting+for+reproduction%22+-label%3A%22waiting-response%22+-label%3Aexplained+) require initial filtering.
+2. Clarify [unreproduced issues](https://github.com/hashicorp/terraform/issues?q=is%3Aopen+label%3Abug+created%3A%3E2020-05-01+-label%3Abackend%2Fk8s+-label%3Aprovisioner%2Fsalt-masterless+-label%3Adocumentation+-label%3Aprovider%2Fazuredevops+-label%3Abackend%2Foss+-label%3Abackend%2Fazure+-label%3Abackend%2Fs3+-label%3Abackend%2Fgcs+-label%3Abackend%2Fconsul+-label%3Abackend%2Fartifactory+-label%3Aterraform-cloud+-label%3Abackend%2Fremote+-label%3Abackend%2Fswift+-label%3Abackend%2Fpg+-label%3Abackend%2Ftencent+-label%3Abackend%2Fmanta+-label%3Abackend%2Fatlas+-label%3Abackend%2Fetcdv3+-label%3Abackend%2Fetcdv2+-label%3Aconfirmed+-label%3A%22pending+project%22+-label%3Anew+-label%3A%22waiting+for+reproduction%22+-label%3Awaiting-response+-label%3Aexplained+sort%3Acreated-asc+)
+3. Explain or fix [confirmed issues](https://github.com/hashicorp/terraform/issues?q=is%3Aopen+label%3Abug+-label%3Aexplained+-label%3Abackend%2Fk8s+-label%3Abackend%2Foss+-label%3Abackend%2Fazure+-label%3Abackend%2Fs3+-label%3Abackend%2Fgcs+-label%3Abackend%2Fconsul+-label%3Abackend%2Fartifactory+-label%3Aterraform-cloud+-label%3Abackend%2Fremote+-label%3Abackend%2Fswift+-label%3Abackend%2Fpg+-label%3Abackend%2Ftencent++-label%3Abackend%2Fmanta++-label%3Abackend%2Fatlas++-label%3Abackend%2Fetcdv3++-label%3Abackend%2Fetcdv2+label%3Aconfirmed+-label%3A%22pending+project%22+). Prioritize [confirmed crashes](https://github.com/hashicorp/terraform/issues?q=is%3Aopen+label%3Acrash+label%3Abug+-label%3Aexplained+-label%3Abackend%2Fk8s+-label%3Abackend%2Foss+-label%3Abackend%2Fazure+-label%3Abackend%2Fs3+-label%3Abackend%2Fgcs+-label%3Abackend%2Fconsul+-label%3Abackend%2Fartifactory+-label%3Aterraform-cloud+-label%3Abackend%2Fremote+-label%3Abackend%2Fswift+-label%3Abackend%2Fpg+-label%3Abackend%2Ftencent++-label%3Abackend%2Fmanta++-label%3Abackend%2Fatlas++-label%3Abackend%2Fetcdv3++-label%3Abackend%2Fetcdv2+label%3Aconfirmed+-label%3A%22pending+project%22+).
+4. Fix [explained issues](https://github.com/hashicorp/terraform/issues?q=is%3Aopen+label%3Abug+label%3Aexplained+no%3Amilestone+-label%3Abackend%2Fk8s+-label%3Abackend%2Foss+-label%3Abackend%2Fazure+-label%3Abackend%2Fs3+-label%3Abackend%2Fgcs+-label%3Abackend%2Fconsul+-label%3Abackend%2Fartifactory+-label%3Aterraform-cloud+-label%3Abackend%2Fremote+-label%3Abackend%2Fswift+-label%3Abackend%2Fpg+-label%3Abackend%2Ftencent++-label%3Abackend%2Fmanta++-label%3Abackend%2Fatlas++-label%3Abackend%2Fetcdv3++-label%3Abackend%2Fetcdv2+label%3Aconfirmed+-label%3A%22pending+project%22+)
+
+### Other Backlog
+
+[Confirmed needs for documentation fixes](https://github.com/hashicorp/terraform/issues?q=is%3Aopen+label%3Abug+label%3Adocumentation++label%3Aconfirmed+-label%3Abackend%2Fk8s+-label%3Abackend%2Foss+-label%3Abackend%2Fazure+-label%3Abackend%2Fs3+-label%3Abackend%2Fgcs+-label%3Abackend%2Fconsul+-label%3Abackend%2Fartifactory+-label%3Aterraform-cloud+-label%3Abackend%2Fremote+-label%3Abackend%2Fswift+-label%3Abackend%2Fpg+-label%3Abackend%2Ftencent++-label%3Abackend%2Fmanta++-label%3Abackend%2Fatlas++-label%3Abackend%2Fetcdv3++-label%3Abackend%2Fetcdv2+)
+
+[Confirmed bugs that will require significant projects to fix](https://github.com/hashicorp/terraform/issues?q=is%3Aopen+label%3Abug+label%3Aconfirmed+label%3A%22pending+project%22+-label%3Abackend%2Fk8s+-label%3Abackend%2Foss+-label%3Abackend%2Fazure+-label%3Abackend%2Fs3+-label%3Abackend%2Fgcs+-label%3Abackend%2Fconsul+-label%3Abackend%2Fartifactory+-label%3Aterraform-cloud+-label%3Abackend%2Fremote+-label%3Abackend%2Fswift+-label%3Abackend%2Fpg+-label%3Abackend%2Ftencent++-label%3Abackend%2Fmanta++-label%3Abackend%2Fatlas++-label%3Abackend%2Fetcdv3++-label%3Abackend%2Fetcdv2+)
+
+### Milestone Use
+
+Milestones ending in .x indicate issues assigned to that milestone are intended to be fixed during that release lifecycle. Milestones ending in .0 indicate issues that will be fixed in that major release. For example:
+
+[0.13.x Milestone](https://github.com/hashicorp/terraform/milestone/17). Issues in this milestone should be considered high-priority but do not block a patch release. All issues in this milestone should be resolved in a 13.x release before the 0.14.0 RC1 ships.
+
+[0.14.0 Milestone](https://github.com/hashicorp/terraform/milestone/18). All issues in this milestone must be fixed before 0.14.0 RC1 ships, and should ideally be fixed before 0.14.0 beta 1 ships.
+
+[0.14.x Milestone](https://github.com/hashicorp/terraform/milestone/20). Issues in this milestone are expected to be addressed at some point in the 0.14.x lifecycle, before 0.15.0. All issues in this milestone should be resolved in a 14.x release before the 0.15.0 RC1 ships.
+
+[0.15.0 Milestone](https://github.com/hashicorp/terraform/milestone/19). All issues in this milestone must be fixed before 0.15.0 RC1 ships, and should ideally be fixed before 0.15.0 beta 1 ships.
diff --git a/v1.5.7/CHANGELOG.md b/v1.5.7/CHANGELOG.md
new file mode 100644
index 0000000..480d64d
--- /dev/null
+++ b/v1.5.7/CHANGELOG.md
@@ -0,0 +1,103 @@
+## 1.5.7 (September 7, 2023)
+
+BUG FIXES:
+
+* `terraform init`: Terraform will no longer allow downloading remote modules to invalid paths. ([#33745](https://github.com/hashicorp/terraform/issues/33745))
+* `terraform_remote_state`: prevent future possible incompatibility with states which include unknown `check` block result kinds. ([#33818](https://github.com/hashicorp/terraform/issues/33818))
+
+## 1.5.6 (August 23, 2023)
+
+BUG FIXES:
+
+* terraform_remote_state: Fixed a potential unsafe read panic when reading from multiple terraform_remote_state data sources ([#33333](https://github.com/hashicorp/terraform/issues/33333))
+
+## 1.5.5 (August 9, 2023)
+
+* `terraform init`: Fix crash when using invalid configuration in backend blocks. ([#33628](https://github.com/hashicorp/terraform/issues/33628))
+
+## 1.5.4 (July 26, 2023)
+
+BUG FIXES:
+
+* `check` blocks: Fixes crash when nested data sources are within configuration targeted by the terraform import command. ([#33578](https://github.com/hashicorp/terraform/issues/33578))
+* `check` blocks: Check blocks now operate in line with other checkable objects by also executing during import operations. ([#33578](https://github.com/hashicorp/terraform/issues/33578))
+
+## 1.5.3 (July 12, 2023)
+
+BUG FIXES:
+
+* core: Terraform could fail to evaluate module outputs when they are used in a provider configuration during a destroy operation ([#33462](https://github.com/hashicorp/terraform/pull/33462))
+* backend/consul: When failing to save state, `consul CAS failed with transaction errors` no longer shows an error instance memory address, but an actual error message. ([#33108](https://github.com/hashicorp/terraform/pull/33108))
+* plan renderer: Fixes crash when rendering the plan if a relevant attribute contains an integer index specified as a string. ([#33475](https://github.com/hashicorp/terraform/issues/33475))
+
+## 1.5.2 (June 28, 2023)
+
+BUG FIXES:
+
+* configs: Multiple `import` blocks with the same `id` string no longer result in a validation error ([#33434](https://github.com/hashicorp/terraform/issues/33434))
+
+## 1.5.1 (June 21, 2023)
+
+BUG FIXES:
+
+* core: plan validation would fail for providers using nested set attributes with computed object attribute ([#33377](https://github.com/hashicorp/terraform/issues/33377))
+
+## 1.5.0 (June 12, 2023)
+
+NEW FEATURES:
+
+* `check` blocks for validating infrastructure: Module and configuration authors can now write independent check blocks within their configuration to validate assertions about their infrastructure.
+
+    The new independent `check` blocks must specify at least one `assert` block, but possibly many, each one with a `condition` expression and an `error_message` expression matching the existing [Custom Condition Checks](https://developer.hashicorp.com/terraform/language/v1.4.x/expressions/custom-conditions).
+    Additionally, check blocks can optionally load a scoped [data source](https://developer.hashicorp.com/terraform/language/v1.4.x/data-sources). Scoped data sources match the existing data sources with the exception that they can only be referenced from within their check block.
+
+    Unlike the existing `precondition` and `postcondition` blocks, Terraform will not halt execution should the scoped data block fail or error or if any of the assertions fail.
+    This allows practitioners to continually validate the state of their infrastructure outside the usual lifecycle management cycle.
+
+* `import` blocks for importing infrastructure: Root module authors can now use the `import` block to declare their intent that Terraform adopt an existing resource.
+
+    Import is now a configuration-driven, plannable action, and is processed as part of a normal plan. Running `terraform plan` will show a summary of the resources that Terraform has planned to import, along with any other plan changes.
+
+    The existing `terraform import` CLI command has not been modified.
+
+    This is an early version of the `import` block feature, for which we are actively seeking user feedback to shape future development. The `import` block currently does not support interpolation in the `id` field, which must be a string.
+
+* Generating configuration for imported resources: in conjunction with the `import` block, this feature enables easy templating of configuration when importing existing resources into Terraform. A new flag `-generate-config-out=PATH` is added to `terraform plan`. When this flag is set, Terraform will generate HCL configuration for any resource included in an `import` block that does not already have associated configuration, and write it to a new file at `PATH`. Before applying, review the generated configuration and edit it as necessary.
+
+* Adds a new `plantimestamp` function that returns the timestamp at plan time. This is similar to the `timestamp` function which returns the timestamp at apply time ([#32980](https://github.com/hashicorp/terraform/pull/32980)).
+* Adds a new `strcontains` function that checks whether a given string contains a given substring. ([#33069](https://github.com/hashicorp/terraform/issues/33069))
+
+
+UPGRADE NOTES:
+
+* This is the last version of Terraform for which macOS 10.13 High Sierra or 10.14 Mojave are officially supported. Future Terraform versions may not function correctly on these older versions of macOS.
+* This is the last version of Terraform for which Windows 7, 8, Server 2008, and Server 2012 are supported by Terraform's main implementation language, Go. We already ended explicit support for versions earlier than Windows 10 in Terraform v0.15.0, but future Terraform versions may malfunction in more significant ways on these older Windows versions.
+* On Linux (and some other non-macOS Unix platforms we don't officially support), Terraform will now notice the `trust-ad` option in `/etc/resolv.conf` and, if set, will set the "authentic data" option in outgoing DNS requests in order to better match the behavior of the GNU libc resolver.
+
+    Terraform does not pay any attention to the corresponding option in responses, but some DNSSEC-aware recursive resolvers return different responses when the request option isn't set. This should therefore avoid some potential situations where a DNS request from Terraform might get a different response than a similar request from other software on your system.
+
+ENHANCEMENTS:
+
+* Terraform CLI's local operations mode will now attempt to persist state snapshots to the state storage backend periodically during the apply step, thereby reducing the window for lost data if the Terraform process is aborted unexpectedly. ([#32680](https://github.com/hashicorp/terraform/issues/32680))
+* If Terraform CLI receives SIGINT (or its equivalent on non-Unix platforms) during the apply step then it will immediately try to persist the latest state snapshot to the state storage backend, with the assumption that a graceful shutdown request often typically followed by a hard abort some time later if the graceful shutdown doesn't complete fast enough. ([#32680](https://github.com/hashicorp/terraform/issues/32680))
+* `pg` backend: Now supports the `PG_CONN_STR`, `PG_SCHEMA_NAME`, `PG_SKIP_SCHEMA_CREATION`, `PG_SKIP_TABLE_CREATION` and `PG_SKIP_INDEX_CREATION` environment variables. ([#33045](https://github.com/hashicorp/terraform/issues/33045))
+
+BUG FIXES:
+
+* `terraform init`: Fixed crash with invalid blank module name. ([#32781](https://github.com/hashicorp/terraform/issues/32781))
+* `moved` blocks: Fixed a typo in the error message that Terraform raises when you use `-target` to exclude an object that has been moved. ([#33149](https://github.com/hashicorp/terraform/issues/33149))
+
+## Previous Releases
+
+For information on prior major and minor releases, see their changelogs:
+
+* [v1.4](https://github.com/hashicorp/terraform/blob/v1.4/CHANGELOG.md)
+* [v1.3](https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md)
+* [v1.2](https://github.com/hashicorp/terraform/blob/v1.2/CHANGELOG.md)
+* [v1.1](https://github.com/hashicorp/terraform/blob/v1.1/CHANGELOG.md)
+* [v1.0](https://github.com/hashicorp/terraform/blob/v1.0/CHANGELOG.md)
+* [v0.15](https://github.com/hashicorp/terraform/blob/v0.15/CHANGELOG.md)
+* [v0.14](https://github.com/hashicorp/terraform/blob/v0.14/CHANGELOG.md)
+* [v0.13](https://github.com/hashicorp/terraform/blob/v0.13/CHANGELOG.md)
+* [v0.12](https://github.com/hashicorp/terraform/blob/v0.12/CHANGELOG.md)
+* [v0.11 and earlier](https://github.com/hashicorp/terraform/blob/v0.11/CHANGELOG.md)
diff --git a/v1.5.7/CODEOWNERS b/v1.5.7/CODEOWNERS
new file mode 100644
index 0000000..b02fd51
--- /dev/null
+++ b/v1.5.7/CODEOWNERS
@@ -0,0 +1,27 @@
+# Each line is a file pattern followed by one or more owners.
+# More on CODEOWNERS files: https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners
+
+# Remote-state backend                  # Maintainer
+/internal/backend/remote-state/artifactory       Unmaintained
+/internal/backend/remote-state/azure             @hashicorp/terraform-azure
+/internal/backend/remote-state/consul            @hashicorp/consul @remilapeyre
+/internal/backend/remote-state/cos               @likexian
+/internal/backend/remote-state/etcdv2            Unmaintained
+/internal/backend/remote-state/etcdv3            Unmaintained
+/internal/backend/remote-state/gcs               @hashicorp/terraform-google @hashicorp/terraform-ecosystem-strategic
+/internal/backend/remote-state/http              @hashicorp/terraform-core
+/internal/backend/remote-state/manta             Unmaintained
+/internal/backend/remote-state/oss               @xiaozhu36
+/internal/backend/remote-state/pg                @remilapeyre
+/internal/backend/remote-state/s3                @hashicorp/terraform-aws
+/internal/backend/remote-state/swift             Unmaintained
+/internal/backend/remote-state/kubernetes        @jrhouston @alexsomesan
+
+# Provisioners
+builtin/provisioners/chef               Deprecated
+builtin/provisioners/file               @hashicorp/terraform-core
+builtin/provisioners/habitat            Deprecated
+builtin/provisioners/local-exec         @hashicorp/terraform-core
+builtin/provisioners/puppet             Deprecated
+builtin/provisioners/remote-exec        @hashicorp/terraform-core
+builtin/provisioners/salt-masterless    Deprecated
diff --git a/v1.5.7/Dockerfile b/v1.5.7/Dockerfile
new file mode 100644
index 0000000..394dcfb
--- /dev/null
+++ b/v1.5.7/Dockerfile
@@ -0,0 +1,26 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+# This Dockerfile builds on golang:alpine by building Terraform from source
+# using the current working directory.
+#
+# This produces a docker image that contains a working Terraform binary along
+# with all of its source code. This is not what produces the official releases
+# in the "terraform" namespace on Dockerhub; those images include only
+# the officially-released binary from releases.hashicorp.com and are
+# built by the (closed-source) official release process.
+
+FROM docker.mirror.hashicorp.services/golang:alpine
+LABEL maintainer="HashiCorp Terraform Team <terraform@hashicorp.com>"
+
+RUN apk add --no-cache git bash openssh
+
+ENV TF_DEV=true
+ENV TF_RELEASE=1
+
+WORKDIR $GOPATH/src/github.com/hashicorp/terraform
+COPY . .
+RUN /bin/bash ./scripts/build.sh
+
+WORKDIR $GOPATH
+ENTRYPOINT ["terraform"]
diff --git a/v1.5.7/LICENSE b/v1.5.7/LICENSE
new file mode 100644
index 0000000..1409d6a
--- /dev/null
+++ b/v1.5.7/LICENSE
@@ -0,0 +1,356 @@
+Copyright (c) 2014 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/v1.5.7/Makefile b/v1.5.7/Makefile
new file mode 100644
index 0000000..84a5dfa
--- /dev/null
+++ b/v1.5.7/Makefile
@@ -0,0 +1,46 @@
+# generate runs `go generate` to build the dynamically generated
+# source files, except the protobuf stubs which are built instead with
+# "make protobuf".
+generate:
+	go generate ./...
+
+# We separate the protobuf generation because most development tasks on
+# Terraform do not involve changing protobuf files and protoc is not a
+# go-gettable dependency and so getting it installed can be inconvenient.
+#
+# If you are working on changes to protobuf interfaces, run this Makefile
+# target to be sure to regenerate all of the protobuf stubs using the expected
+# versions of protoc and the protoc Go plugins.
+protobuf:
+	go run ./tools/protobuf-compile .
+
+fmtcheck:
+	"$(CURDIR)/scripts/gofmtcheck.sh"
+
+importscheck:
+	"$(CURDIR)/scripts/goimportscheck.sh"
+
+staticcheck:
+	"$(CURDIR)/scripts/staticcheck.sh"
+
+exhaustive:
+	"$(CURDIR)/scripts/exhaustive.sh"
+
+# Run this if working on the website locally to run in watch mode.
+website:
+	$(MAKE) -C website website
+
+# Use this if you have run `website/build-local` to use the locally built image.
+website/local:
+	$(MAKE) -C website website/local
+
+# Run this to generate a new local Docker image.
+website/build-local:
+	$(MAKE) -C website website/build-local
+
+# disallow any parallelism (-j) for Make. This is necessary since some
+# commands during the build process create temporary files that collide
+# under parallel conditions.
+.NOTPARALLEL:
+
+.PHONY: fmtcheck importscheck generate protobuf staticcheck website website/local website/build-local
\ No newline at end of file
diff --git a/v1.5.7/README.md b/v1.5.7/README.md
new file mode 100644
index 0000000..e8509e3
--- /dev/null
+++ b/v1.5.7/README.md
@@ -0,0 +1,48 @@
+# Terraform
+
+- Website: https://www.terraform.io
+- Forums: [HashiCorp Discuss](https://discuss.hashicorp.com/c/terraform-core)
+- Documentation: [https://www.terraform.io/docs/](https://www.terraform.io/docs/)
+- Tutorials: [HashiCorp's Learn Platform](https://learn.hashicorp.com/terraform)
+- Certification Exam: [HashiCorp Certified: Terraform Associate](https://www.hashicorp.com/certification/#hashicorp-certified-terraform-associate)
+
+<img alt="Terraform" src="https://www.datocms-assets.com/2885/1629941242-logo-terraform-main.svg" width="600px">
+
+Terraform is a tool for building, changing, and versioning infrastructure safely and efficiently. Terraform can manage existing and popular service providers as well as custom in-house solutions.
+
+The key features of Terraform are:
+
+- **Infrastructure as Code**: Infrastructure is described using a high-level configuration syntax. This allows a blueprint of your datacenter to be versioned and treated as you would any other code. Additionally, infrastructure can be shared and re-used.
+
+- **Execution Plans**: Terraform has a "planning" step where it generates an execution plan. The execution plan shows what Terraform will do when you call apply. This lets you avoid any surprises when Terraform manipulates infrastructure.
+
+- **Resource Graph**: Terraform builds a graph of all your resources, and parallelizes the creation and modification of any non-dependent resources. Because of this, Terraform builds infrastructure as efficiently as possible, and operators get insight into dependencies in their infrastructure.
+
+- **Change Automation**: Complex changesets can be applied to your infrastructure with minimal human interaction. With the previously mentioned execution plan and resource graph, you know exactly what Terraform will change and in what order, avoiding many possible human errors.
+
+For more information, refer to the [What is Terraform?](https://www.terraform.io/intro) page on the Terraform website.
+
+## Getting Started & Documentation
+
+Documentation is available on the [Terraform website](https://www.terraform.io):
+
+- [Introduction](https://www.terraform.io/intro)
+- [Documentation](https://www.terraform.io/docs)
+
+If you're new to Terraform and want to get started creating infrastructure, please check out our [Getting Started guides](https://learn.hashicorp.com/terraform#getting-started) on HashiCorp's learning platform. There are also [additional guides](https://learn.hashicorp.com/terraform#operations-and-development) to continue your learning.
+
+Show off your Terraform knowledge by passing a certification exam. Visit the [certification page](https://www.hashicorp.com/certification/) for information about exams and find [study materials](https://learn.hashicorp.com/terraform/certification/terraform-associate) on HashiCorp's learning platform.
+
+## Developing Terraform
+
+This repository contains only Terraform core, which includes the command line interface and the main graph engine. Providers are implemented as plugins, and Terraform can automatically download providers that are published on [the Terraform Registry](https://registry.terraform.io). HashiCorp develops some providers, and others are developed by other organizations. For more information, see [Extending Terraform](https://www.terraform.io/docs/extend/index.html).
+
+- To learn more about compiling Terraform and contributing suggested changes, refer to [the contributing guide](.github/CONTRIBUTING.md).
+
+- To learn more about how we handle bug reports, refer to the [bug triage guide](./BUGPROCESS.md).
+
+- To learn how to contribute to the Terraform documentation in this repository, refer to the [Terraform Documentation README](/website/README.md).
+
+## License
+
+[Mozilla Public License v2.0](https://github.com/hashicorp/terraform/blob/main/LICENSE)
diff --git a/v1.5.7/checkpoint.go b/v1.5.7/checkpoint.go
new file mode 100644
index 0000000..54d52a1
--- /dev/null
+++ b/v1.5.7/checkpoint.go
@@ -0,0 +1,85 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"fmt"
+	"log"
+	"path/filepath"
+
+	"github.com/hashicorp/go-checkpoint"
+	"github.com/hashicorp/terraform/internal/command"
+	"github.com/hashicorp/terraform/internal/command/cliconfig"
+)
+
+func init() {
+	checkpointResult = make(chan *checkpoint.CheckResponse, 1)
+}
+
+var checkpointResult chan *checkpoint.CheckResponse
+
+// runCheckpoint runs a HashiCorp Checkpoint request. You can read about
+// Checkpoint here: https://github.com/hashicorp/go-checkpoint.
+func runCheckpoint(c *cliconfig.Config) {
+	// If the user doesn't want checkpoint at all, then return.
+	if c.DisableCheckpoint {
+		log.Printf("[INFO] Checkpoint disabled. Not running.")
+		checkpointResult <- nil
+		return
+	}
+
+	configDir, err := cliconfig.ConfigDir()
+	if err != nil {
+		log.Printf("[ERR] Checkpoint setup error: %s", err)
+		checkpointResult <- nil
+		return
+	}
+
+	version := Version
+	if VersionPrerelease != "" {
+		version += fmt.Sprintf("-%s", VersionPrerelease)
+	}
+
+	signaturePath := filepath.Join(configDir, "checkpoint_signature")
+	if c.DisableCheckpointSignature {
+		log.Printf("[INFO] Checkpoint signature disabled")
+		signaturePath = ""
+	}
+
+	resp, err := checkpoint.Check(&checkpoint.CheckParams{
+		Product:       "terraform",
+		Version:       version,
+		SignatureFile: signaturePath,
+		CacheFile:     filepath.Join(configDir, "checkpoint_cache"),
+	})
+	if err != nil {
+		log.Printf("[ERR] Checkpoint error: %s", err)
+		resp = nil
+	}
+
+	checkpointResult <- resp
+}
+
+// commandVersionCheck implements command.VersionCheckFunc and is used
+// as the version checker.
+func commandVersionCheck() (command.VersionCheckInfo, error) {
+	// Wait for the result to come through
+	info := <-checkpointResult
+	if info == nil {
+		var zero command.VersionCheckInfo
+		return zero, nil
+	}
+
+	// Build the alerts that we may have received about our version
+	alerts := make([]string, len(info.Alerts))
+	for i, a := range info.Alerts {
+		alerts[i] = a.Message
+	}
+
+	return command.VersionCheckInfo{
+		Outdated: info.Outdated,
+		Latest:   info.CurrentVersion,
+		Alerts:   alerts,
+	}, nil
+}
diff --git a/v1.5.7/codecov.yml b/v1.5.7/codecov.yml
new file mode 100644
index 0000000..605faed
--- /dev/null
+++ b/v1.5.7/codecov.yml
@@ -0,0 +1,27 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+comment:
+  layout: "flags, files"
+  behavior: default
+  require_changes: true   # only comment on changes in coverage
+  require_base: yes       # [yes :: must have a base report to post]
+  require_head: yes       # [yes :: must have a head report to post]
+  branches:               # branch names that can post comment
+    - "main"
+
+coverage:
+  status:
+    project:
+      default:
+        informational: true
+        target: auto
+        threshold: "0.5%"
+    patch:
+      default:
+        informational: true
+        target: auto
+        threshold: "0.5%"
+
+github_checks:
+    annotations: false
diff --git a/v1.5.7/commands.go b/v1.5.7/commands.go
new file mode 100644
index 0000000..4f06eef
--- /dev/null
+++ b/v1.5.7/commands.go
@@ -0,0 +1,451 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"os"
+	"os/signal"
+
+	"github.com/mitchellh/cli"
+
+	"github.com/hashicorp/go-plugin"
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform-svchost/auth"
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command"
+	"github.com/hashicorp/terraform/internal/command/cliconfig"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/command/webbrowser"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	pluginDiscovery "github.com/hashicorp/terraform/internal/plugin/discovery"
+	"github.com/hashicorp/terraform/internal/terminal"
+)
+
+// runningInAutomationEnvName gives the name of an environment variable that
+// can be set to any non-empty value in order to suppress certain messages
+// that assume that Terraform is being run from a command prompt.
+const runningInAutomationEnvName = "TF_IN_AUTOMATION"
+
+// Commands is the mapping of all the available Terraform commands.
+var Commands map[string]cli.CommandFactory
+
+// PrimaryCommands is an ordered sequence of the top-level commands (not
+// subcommands) that we emphasize at the top of our help output. This is
+// ordered so that we can show them in the typical workflow order, rather
+// than in alphabetical order. Anything not in this sequence or in the
+// HiddenCommands set appears under "all other commands".
+var PrimaryCommands []string
+
+// HiddenCommands is a set of top-level commands (not subcommands) that are
+// not advertised in the top-level help at all. This is typically because
+// they are either just stubs that return an error message about something
+// no longer being supported or backward-compatibility aliases for other
+// commands.
+//
+// No commands in the PrimaryCommands sequence should also appear in the
+// HiddenCommands set, because that would be rather silly.
+var HiddenCommands map[string]struct{}
+
+// Ui is the cli.Ui used for communicating to the outside world.
+var Ui cli.Ui
+
+func initCommands(
+	originalWorkingDir string,
+	streams *terminal.Streams,
+	config *cliconfig.Config,
+	services *disco.Disco,
+	providerSrc getproviders.Source,
+	providerDevOverrides map[addrs.Provider]getproviders.PackageLocalDir,
+	unmanagedProviders map[addrs.Provider]*plugin.ReattachConfig,
+) {
+	var inAutomation bool
+	if v := os.Getenv(runningInAutomationEnvName); v != "" {
+		inAutomation = true
+	}
+
+	for userHost, hostConfig := range config.Hosts {
+		host, err := svchost.ForComparison(userHost)
+		if err != nil {
+			// We expect the config was already validated by the time we get
+			// here, so we'll just ignore invalid hostnames.
+			continue
+		}
+		services.ForceHostServices(host, hostConfig.Services)
+	}
+
+	configDir, err := cliconfig.ConfigDir()
+	if err != nil {
+		configDir = "" // No config dir available (e.g. looking up a home directory failed)
+	}
+
+	wd := WorkingDir(originalWorkingDir, os.Getenv("TF_DATA_DIR"))
+
+	meta := command.Meta{
+		WorkingDir: wd,
+		Streams:    streams,
+		View:       views.NewView(streams).SetRunningInAutomation(inAutomation),
+
+		Color:            true,
+		GlobalPluginDirs: globalPluginDirs(),
+		Ui:               Ui,
+
+		Services:        services,
+		BrowserLauncher: webbrowser.NewNativeLauncher(),
+
+		RunningInAutomation: inAutomation,
+		CLIConfigDir:        configDir,
+		PluginCacheDir:      config.PluginCacheDir,
+
+		PluginCacheMayBreakDependencyLockFile: config.PluginCacheMayBreakDependencyLockFile,
+
+		ShutdownCh: makeShutdownCh(),
+
+		ProviderSource:       providerSrc,
+		ProviderDevOverrides: providerDevOverrides,
+		UnmanagedProviders:   unmanagedProviders,
+
+		AllowExperimentalFeatures: ExperimentsAllowed(),
+	}
+
+	// The command list is included in the terraform -help
+	// output, which is in turn included in the docs at
+	// website/docs/cli/commands/index.html.markdown; if you
+	// add, remove or reclassify commands then consider updating
+	// that to match.
+
+	Commands = map[string]cli.CommandFactory{
+		"apply": func() (cli.Command, error) {
+			return &command.ApplyCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"console": func() (cli.Command, error) {
+			return &command.ConsoleCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"destroy": func() (cli.Command, error) {
+			return &command.ApplyCommand{
+				Meta:    meta,
+				Destroy: true,
+			}, nil
+		},
+
+		"env": func() (cli.Command, error) {
+			return &command.WorkspaceCommand{
+				Meta:       meta,
+				LegacyName: true,
+			}, nil
+		},
+
+		"env list": func() (cli.Command, error) {
+			return &command.WorkspaceListCommand{
+				Meta:       meta,
+				LegacyName: true,
+			}, nil
+		},
+
+		"env select": func() (cli.Command, error) {
+			return &command.WorkspaceSelectCommand{
+				Meta:       meta,
+				LegacyName: true,
+			}, nil
+		},
+
+		"env new": func() (cli.Command, error) {
+			return &command.WorkspaceNewCommand{
+				Meta:       meta,
+				LegacyName: true,
+			}, nil
+		},
+
+		"env delete": func() (cli.Command, error) {
+			return &command.WorkspaceDeleteCommand{
+				Meta:       meta,
+				LegacyName: true,
+			}, nil
+		},
+
+		"fmt": func() (cli.Command, error) {
+			return &command.FmtCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"get": func() (cli.Command, error) {
+			return &command.GetCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"graph": func() (cli.Command, error) {
+			return &command.GraphCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"import": func() (cli.Command, error) {
+			return &command.ImportCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"init": func() (cli.Command, error) {
+			return &command.InitCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"login": func() (cli.Command, error) {
+			return &command.LoginCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"logout": func() (cli.Command, error) {
+			return &command.LogoutCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"metadata": func() (cli.Command, error) {
+			return &command.MetadataCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"metadata functions": func() (cli.Command, error) {
+			return &command.MetadataFunctionsCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"output": func() (cli.Command, error) {
+			return &command.OutputCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"plan": func() (cli.Command, error) {
+			return &command.PlanCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"providers": func() (cli.Command, error) {
+			return &command.ProvidersCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"providers lock": func() (cli.Command, error) {
+			return &command.ProvidersLockCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"providers mirror": func() (cli.Command, error) {
+			return &command.ProvidersMirrorCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"providers schema": func() (cli.Command, error) {
+			return &command.ProvidersSchemaCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"push": func() (cli.Command, error) {
+			return &command.PushCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"refresh": func() (cli.Command, error) {
+			return &command.RefreshCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"show": func() (cli.Command, error) {
+			return &command.ShowCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"taint": func() (cli.Command, error) {
+			return &command.TaintCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"test": func() (cli.Command, error) {
+			return &command.TestCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"validate": func() (cli.Command, error) {
+			return &command.ValidateCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"version": func() (cli.Command, error) {
+			return &command.VersionCommand{
+				Meta:              meta,
+				Version:           Version,
+				VersionPrerelease: VersionPrerelease,
+				Platform:          getproviders.CurrentPlatform,
+				CheckFunc:         commandVersionCheck,
+			}, nil
+		},
+
+		"untaint": func() (cli.Command, error) {
+			return &command.UntaintCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"workspace": func() (cli.Command, error) {
+			return &command.WorkspaceCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"workspace list": func() (cli.Command, error) {
+			return &command.WorkspaceListCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"workspace select": func() (cli.Command, error) {
+			return &command.WorkspaceSelectCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"workspace show": func() (cli.Command, error) {
+			return &command.WorkspaceShowCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"workspace new": func() (cli.Command, error) {
+			return &command.WorkspaceNewCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"workspace delete": func() (cli.Command, error) {
+			return &command.WorkspaceDeleteCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		//-----------------------------------------------------------
+		// Plumbing
+		//-----------------------------------------------------------
+
+		"force-unlock": func() (cli.Command, error) {
+			return &command.UnlockCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"state": func() (cli.Command, error) {
+			return &command.StateCommand{}, nil
+		},
+
+		"state list": func() (cli.Command, error) {
+			return &command.StateListCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"state rm": func() (cli.Command, error) {
+			return &command.StateRmCommand{
+				StateMeta: command.StateMeta{
+					Meta: meta,
+				},
+			}, nil
+		},
+
+		"state mv": func() (cli.Command, error) {
+			return &command.StateMvCommand{
+				StateMeta: command.StateMeta{
+					Meta: meta,
+				},
+			}, nil
+		},
+
+		"state pull": func() (cli.Command, error) {
+			return &command.StatePullCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"state push": func() (cli.Command, error) {
+			return &command.StatePushCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"state show": func() (cli.Command, error) {
+			return &command.StateShowCommand{
+				Meta: meta,
+			}, nil
+		},
+
+		"state replace-provider": func() (cli.Command, error) {
+			return &command.StateReplaceProviderCommand{
+				StateMeta: command.StateMeta{
+					Meta: meta,
+				},
+			}, nil
+		},
+	}
+
+	PrimaryCommands = []string{
+		"init",
+		"validate",
+		"plan",
+		"apply",
+		"destroy",
+	}
+
+	HiddenCommands = map[string]struct{}{
+		"env":             struct{}{},
+		"internal-plugin": struct{}{},
+		"push":            struct{}{},
+	}
+
+}
+
+// makeShutdownCh creates an interrupt listener and returns a channel.
+// A message will be sent on the channel for every interrupt received.
+func makeShutdownCh() <-chan struct{} {
+	resultCh := make(chan struct{})
+
+	signalCh := make(chan os.Signal, 4)
+	signal.Notify(signalCh, ignoreSignals...)
+	signal.Notify(signalCh, forwardSignals...)
+	go func() {
+		for {
+			<-signalCh
+			resultCh <- struct{}{}
+		}
+	}()
+
+	return resultCh
+}
+
+func credentialsSource(config *cliconfig.Config) (auth.CredentialsSource, error) {
+	helperPlugins := pluginDiscovery.FindPlugins("credentials", globalPluginDirs())
+	return config.CredentialsSource(helperPlugins)
+}
diff --git a/v1.5.7/docs/README.md b/v1.5.7/docs/README.md
new file mode 100644
index 0000000..715ce0c
--- /dev/null
+++ b/v1.5.7/docs/README.md
@@ -0,0 +1,40 @@
+# Terraform Core Codebase Documentation
+
+This directory contains some documentation about the Terraform Core codebase,
+aimed at readers who are interested in making code contributions.
+
+If you're looking for information on _using_ Terraform, please instead refer
+to [the main Terraform CLI documentation](https://www.terraform.io/docs/cli/index.html).
+
+## Terraform Core Architecture Documents
+
+* [Terraform Core Architecture Summary](./architecture.md): an overview of the
+  main components of Terraform Core and how they interact. This is the best
+  starting point if you are diving in to this codebase for the first time.
+
+* [Resource Instance Change Lifecycle](./resource-instance-change-lifecycle.md):
+  a description of the steps in validating, planning, and applying a change
+  to a resource instance, from the perspective of the provider plugin RPC
+  operations. This may be useful for understanding the various expectations
+  Terraform enforces about provider behavior, either if you intend to make
+  changes to those behaviors or if you are implementing a new Terraform plugin
+  SDK and so wish to conform to them.
+
+  (If you are planning to write a new provider using the _official_ SDK then
+  please refer to [the Extend documentation](https://www.terraform.io/docs/extend/index.html)
+  instead; it presents similar information from the perspective of the SDK
+  API, rather than the plugin wire protocol.)
+
+* [Plugin Protocol](./plugin-protocol/): gRPC/protobuf definitions for the
+  plugin wire protocol and information about its versioning strategy.
+
+  This documentation is for SDK developers, and is not necessary reading for
+  those implementing a provider using the official SDK.
+
+* [How Terraform Uses Unicode](./unicode.md): an overview of the various
+  features of Terraform that rely on Unicode and how to change those features
+  to adopt new versions of Unicode.
+
+## Contribution Guides
+
+* [Contributing to Terraform](../.github/CONTRIBUTING.md): a complete guideline for those who want to contribute to this project.
diff --git a/v1.5.7/docs/architecture.md b/v1.5.7/docs/architecture.md
new file mode 100644
index 0000000..0c93b16
--- /dev/null
+++ b/v1.5.7/docs/architecture.md
@@ -0,0 +1,375 @@
+# Terraform Core Architecture Summary
+
+This document is a summary of the main components of Terraform Core and how
+data and requests flow between these components. It's intended as a primer
+to help navigate the codebase to dig into more details.
+
+We assume some familiarity with user-facing Terraform concepts like
+configuration, state, CLI workflow, etc. The Terraform website has
+documentation on these ideas.
+
+## Terraform Request Flow
+
+The following diagram shows an approximation of how a user command is
+executed in Terraform:
+
+![Terraform Architecture Diagram, described in text below](./images/architecture-overview.png)
+
+Each of the different subsystems (solid boxes) in this diagram is described
+in more detail in a corresponding section below.
+
+## CLI (`command` package)
+
+Each time a user runs the `terraform` program, aside from some initial
+bootstrapping in the root package (not shown in the diagram) execution
+transfers immediately into one of the "command" implementations in
+[the `command` package](https://pkg.go.dev/github.com/hashicorp/terraform/internal/command).
+The mapping between the user-facing command names and
+their corresponding `command` package types can be found in the `commands.go`
+file in the root of the repository.
+
+The full flow illustrated above does not actually apply to _all_ commands,
+but it applies to the main Terraform workflow commands `terraform plan` and
+`terraform apply`, along with a few others.
+
+For these commands, the role of the command implementation is to read and parse
+any command line arguments, command line options, and environment variables
+that are needed for the given command and use them to produce a
+[`backend.Operation`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/backend#Operation)
+object that describes an action to be taken.
+
+An _operation_ consists of:
+
+* The action to be taken (e.g. "plan", "apply").
+* The name of the [workspace](https://www.terraform.io/docs/state/workspaces.html)
+  where the action will be taken.
+* Root module input variables to use for the action.
+* For the "plan" operation, a path to the directory containing the configuration's root module.
+* For the "apply" operation, the plan to apply.
+* Various other less-common options/settings such as `-target` addresses, the
+"force" flag, etc.
+
+The operation is then passed to the currently-selected
+[backend](https://www.terraform.io/docs/backends/index.html). Each backend name
+corresponds to an implementation of
+[`backend.Backend`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/backend#Backend), using a
+mapping table in
+[the `backend/init` package](https://pkg.go.dev/github.com/hashicorp/terraform/internal/backend/init).
+
+Backends that are able to execute operations additionally implement
+[`backend.Enhanced`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/backend#Enhanced);
+the command-handling code calls `Operation` with the operation it has
+constructed, and then the backend is responsible for executing that action.
+
+Backends that execute operations, however, do so as an architectural implementation detail and not a
+general feature of backends. That is, the term 'backend' as a Terraform feature is used to refer to
+a plugin that determines where Terraform stores its state snapshots - only the default `local`
+backend and Terraform Cloud's backends (`remote`, `cloud`) perform operations.
+
+Thus, most backends do _not_ implement this interface, and so the `command` package wraps these
+backends in an instance of
+[`local.Local`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/backend/local#Local),
+causing the operation to be executed locally within the `terraform` process itself.
+
+## Backends
+
+A _backend_ determines where Terraform should store its state snapshots.
+
+As described above, the `local` backend also executes operations on behalf of most other
+backends. It uses a _state manager_
+(either
+[`statemgr.Filesystem`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/states/statemgr#Filesystem) if the
+local backend is being used directly, or an implementation provided by whatever
+backend is being wrapped) to retrieve the current state for the workspace
+specified in the operation, then uses the _config loader_ to load and do
+initial processing/validation of the configuration specified in the
+operation. It then uses these, along with the other settings given in the
+operation, to construct a
+[`terraform.Context`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#Context),
+which is the main object that actually performs Terraform operations.
+
+The `local` backend finally calls an appropriate method on that context to
+begin execution of the relevant command, such as
+[`Plan`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#Context.Plan)
+or
+[`Apply`](), which in turn constructs a graph using a _graph builder_,
+described in a later section.
+
+## Configuration Loader
+
+The top-level configuration structure is represented by model types in
+[package `configs`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/configs).
+A whole configuration (the root module plus all of its descendent modules)
+is represented by
+[`configs.Config`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/configs#Config).
+
+The `configs` package contains some low-level functionality for constructing
+configuration objects, but the main entry point is in the sub-package
+[`configload`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/configs/configload]),
+via
+[`configload.Loader`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/configs/configload#Loader).
+A loader deals with all of the details of installing child modules
+(during `terraform init`) and then locating those modules again when a
+configuration is loaded by a backend. It takes the path to a root module
+and recursively loads all of the child modules to produce a single
+[`configs.Config`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/configs#Config)
+representing the entire configuration.
+
+Terraform expects configuration files written in the Terraform language, which
+is a DSL built on top of
+[HCL](https://github.com/hashicorp/hcl). Some parts of the configuration
+cannot be interpreted until we build and walk the graph, since they depend
+on the outcome of other parts of the configuration, and so these parts of
+the configuration remain represented as the low-level HCL types
+[`hcl.Body`](https://pkg.go.dev/github.com/hashicorp/hcl/v2/#Body)
+and
+[`hcl.Expression`](https://pkg.go.dev/github.com/hashicorp/hcl/v2/#Expression),
+allowing Terraform to interpret them at a more appropriate time.
+
+## State Manager
+
+A _state manager_ is responsible for storing and retrieving snapshots of the
+[Terraform state](https://www.terraform.io/docs/language/state/index.html)
+for a particular workspace. Each manager is an implementation of
+some combination of interfaces in
+[the `statemgr` package](https://pkg.go.dev/github.com/hashicorp/terraform/internal/states/statemgr),
+with most practical managers implementing the full set of operations
+described by
+[`statemgr.Full`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/states/statemgr#Full)
+provided by a _backend_. The smaller interfaces exist primarily for use in
+other function signatures to be explicit about what actions the function might
+take on the state manager; there is little reason to write a state manager
+that does not implement all of `statemgr.Full`.
+
+The implementation
+[`statemgr.Filesystem`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/states/statemgr#Filesystem) is used
+by default (by the `local` backend) and is responsible for the familiar
+`terraform.tfstate` local file that most Terraform users start with, before
+they switch to [remote state](https://www.terraform.io/docs/language/state/remote.html).
+Other implementations of `statemgr.Full` are used to implement remote state.
+Each of these saves and retrieves state via a remote network service
+appropriate to the backend that creates it.
+
+A state manager accepts and returns a state snapshot as a
+[`states.State`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/states#State)
+object. The state manager is responsible for exactly how that object is
+serialized and stored, but all state managers at the time of writing use
+the same JSON serialization format, storing the resulting JSON bytes in some
+kind of arbitrary blob store.
+
+## Graph Builder
+
+A _graph builder_ is called by a
+[`terraform.Context`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#Context)
+method (e.g. `Plan` or `Apply`) to produce the graph that will be used
+to represent the necessary steps for that operation and the dependency
+relationships between them.
+
+In most cases, the
+[vertices](https://en.wikipedia.org/wiki/Vertex_(graph_theory)) of Terraform's
+graphs each represent a specific object in the configuration, or something
+derived from those configuration objects. For example, each `resource` block
+in the configuration has one corresponding
+[`GraphNodeConfigResource`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#GraphNodeConfigResource)
+vertex representing it in the "plan" graph. (Terraform Core uses terminology
+inconsistently, describing graph _vertices_ also as graph _nodes_ in various
+places. These both describe the same concept.)
+
+The [edges](https://en.wikipedia.org/wiki/Glossary_of_graph_theory_terms#edge)
+in the graph represent "must happen after" relationships. These define the
+order in which the vertices are evaluated, ensuring that e.g. one resource is
+created before another resource that depends on it.
+
+Each operation has its own graph builder, because the graph building process
+is different for each. For example, a "plan" operation needs a graph built
+directly from the configuration, but an "apply" operation instead builds its
+graph from the set of changes described in the plan that is being applied.
+
+The graph builders all work in terms of a sequence of _transforms_, which
+are implementations of
+[`terraform.GraphTransformer`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#GraphTransformer).
+Implementations of this interface just take a graph and mutate it in any
+way needed, and so the set of available transforms is quite varied. Some
+important examples include:
+
+* [`ConfigTransformer`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#ConfigTransformer),
+  which creates a graph vertex for each `resource` block in the configuration.
+
+* [`StateTransformer`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#StateTransformer),
+  which creates a graph vertex for each resource instance currently tracked
+  in the state.
+
+* [`ReferenceTransformer`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#ReferenceTransformer),
+  which analyses the configuration to find dependencies between resources and
+  other objects and creates any necessary "happens after" edges for these.
+
+* [`ProviderTransformer`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#ProviderTransformer),
+  which associates each resource or resource instance with exactly one
+  provider configuration (implementing
+  [the inheritance rules](https://www.terraform.io/docs/language/modules/develop/providers.html))
+  and then creates "happens after" edges to ensure that the providers are
+  initialized before taking any actions with the resources that belong to
+  them.
+
+There are many more different graph transforms, which can be discovered
+by reading the source code for the different graph builders. Each graph
+builder uses a different subset of these depending on the needs of the
+operation that is being performed.
+
+The result of graph building is a
+[`terraform.Graph`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#Graph), which
+can then be processed using a _graph walker_.
+
+## Graph Walk
+
+The process of walking the graph visits each vertex of that graph in a way
+which respects the "happens after" edges in the graph. The walk algorithm
+itself is implemented in
+[the low-level `dag` package](https://pkg.go.dev/github.com/hashicorp/terraform/internal/dag#AcyclicGraph.Walk)
+(where "DAG" is short for [_Directed Acyclic Graph_](https://en.wikipedia.org/wiki/Directed_acyclic_graph)), in
+[`AcyclicGraph.Walk`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/dag#AcyclicGraph.Walk).
+However, the "interesting" Terraform walk functionality is implemented in
+[`terraform.ContextGraphWalker`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#ContextGraphWalker),
+which implements a small set of higher-level operations that are performed
+during the graph walk:
+
+* `EnterPath` is called once for each module in the configuration, taking a
+  module address and returning a
+  [`terraform.EvalContext`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#EvalContext)
+  that tracks objects within that module. `terraform.Context` is the _global_
+  context for the entire operation, while `terraform.EvalContext` is a
+  context for processing within a single module, and is the primary means
+  by which the namespaces in each module are kept separate.
+
+Each vertex in the graph is evaluated, in an order that guarantees that the
+"happens after" edges will be respected. If possible, the graph walk algorithm
+will evaluate multiple vertices concurrently. Vertex evaluation code must
+therefore make careful use of concurrency primitives such as mutexes in order
+to coordinate access to shared objects such as the `states.State` object.
+In most cases, we use the helper wrapper
+[`states.SyncState`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/states#SyncState)
+to safely implement concurrent reads and writes from the shared state.
+
+## Vertex Evaluation
+
+The action taken for each vertex during the graph walk is called
+_execution_. Execution runs a sequence of arbitrary actions that make sense
+for a particular vertex type.
+
+For example, evaluation of a vertex representing a resource instance during
+a plan operation would include the following high-level steps:
+
+* Retrieve the resource's associated provider from the `EvalContext`. This
+  should already be initialized earlier by the provider's own graph vertex,
+  due to the "happens after" edge between the resource node and the provider
+  node.
+
+* Retrieve from the state the portion relevant to the specific resource
+  instance being evaluated.
+
+* Evaluate the attribute expressions given for the resource in configuration.
+  This often involves retrieving the state of _other_ resource instances so
+  that their values can be copied or transformed into the current instance's
+  attributes, which is coordinated by the `EvalContext`.
+
+* Pass the current instance state and the resource configuration to the
+  provider, asking the provider to produce an _instance diff_ representing the
+  differences between the state and the configuration.
+
+* Save the instance diff as part of the plan that is being constructed by
+  this operation.
+
+Each execution step for a vertex is an implementation of
+[`terraform.Execute`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/erraform#Execute).
+As with graph transforms, the behavior of these implementations varies widely:
+whereas graph transforms can take any action against the graph, an `Execute`
+implementation can take any action against the `EvalContext`.
+
+The implementation of `terraform.EvalContext` used in real processing
+(as opposed to testing) is
+[`terraform.BuiltinEvalContext`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#BuiltinEvalContext).
+It provides coordinated access to plugins, the current state, and the current
+plan via the `EvalContext` interface methods.
+
+In order to be executed, a vertex must implement
+[`terraform.GraphNodeExecutable`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#GraphNodeExecutable),
+which has a single `Execute` method that handles. There are numerous `Execute`
+implementations with different behaviors, but some prominent examples are:
+
+* [NodePlannableResource.Execute](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#NodePlannableResourceInstance.Execute), which handles the `plan` operation.
+
+* [`NodeApplyableResourceInstance.Execute`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#NodeApplyableResourceInstance.Execute), which handles the main `apply` operation.
+
+* [`NodeDestroyResourceInstance.Execute`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#EvalWriteState), which handles the main `destroy` operation.
+
+A vertex must complete successfully before the graph walk will begin evaluation
+for other vertices that have "happens after" edges. Evaluation can fail with one
+or more errors, in which case the graph walk is halted and the errors are
+returned to the user.
+
+### Expression Evaluation
+
+An important part of vertex evaluation for most vertex types is evaluating
+any expressions in the configuration block associated with the vertex. This
+completes the processing of the portions of the configuration that were not
+processed by the configuration loader.
+
+The high-level process for expression evaluation is:
+
+1. Analyze the configuration expressions to see which other objects they refer
+  to. For example, the expression `aws_instance.example[1]` refers to one of
+  the instances created by a `resource "aws_instance" "example"` block in
+  configuration. This analysis is performed by
+  [`lang.References`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/lang#References),
+  or more often one of the helper wrappers around it:
+  [`lang.ReferencesInBlock`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/lang#ReferencesInBlock)
+  or
+  [`lang.ReferencesInExpr`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/lang#ReferencesInExpr)
+
+1. Retrieve from the state the data for the objects that are referred to and
+  create a lookup table of the values from these objects that the
+  HCL evaluation code can refer to.
+
+1. Prepare the table of built-in functions so that HCL evaluation can refer to
+  them.
+
+1. Ask HCL to evaluate each attribute's expression (a
+  [`hcl.Expression`](https://pkg.go.dev/github.com/hashicorp/hcl/v2/#Expression)
+  object) against the data and function lookup tables.
+
+In practice, steps 2 through 4 are usually run all together using one
+of the methods on [`lang.Scope`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/lang#Scope);
+most commonly,
+[`lang.EvalBlock`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/lang#Scope.EvalBlock)
+or
+[`lang.EvalExpr`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/lang#Scope.EvalExpr).
+
+Expression evaluation produces a dynamic value represented as a
+[`cty.Value`](https://pkg.go.dev/github.com/zclconf/go-cty/cty#Value).
+This Go type represents values from the Terraform language and such values
+are eventually passed to provider plugins.
+
+### Sub-graphs
+
+Some vertices have a special additional behavior that happens after their
+evaluation steps are complete, where the vertex implementation is given
+the opportunity to build another separate graph which will be walked as part
+of the evaluation of the vertex.
+
+The main example of this is when a `resource` block has the `count` argument
+set. In that case, the plan graph initially contains one vertex for each
+`resource` block, but that graph then _dynamically expands_ to have a sub-graph
+containing one vertex for each instance requested by the count. That is, the
+sub-graph of `aws_instance.example` might contain vertices for
+`aws_instance.example[0]`, `aws_instance.example[1]`, etc. This is necessary
+because the `count` argument may refer to other objects whose values are not
+known when the main graph is constructed, but become known while evaluating
+other vertices in the main graph.
+
+This special behavior applies to vertex objects that implement
+[`terraform.GraphNodeDynamicExpandable`](https://pkg.go.dev/github.com/hashicorp/terraform/internal/terraform#GraphNodeDynamicExpandable).
+Such vertices have their own nested _graph builder_, _graph walk_,
+and _vertex evaluation_ steps, with the same behaviors as described in these
+sections for the main graph. The difference is in which graph transforms
+are used to construct the graph and in which evaluation steps apply to the
+nodes in that sub-graph.
diff --git a/v1.5.7/docs/destroying.md b/v1.5.7/docs/destroying.md
new file mode 100644
index 0000000..9643e26
--- /dev/null
+++ b/v1.5.7/docs/destroying.md
@@ -0,0 +1,361 @@
+# Terraform Core Resource Destruction Notes
+
+This document intends to describe some of the details and complications
+involved in the destruction of resources. It covers the ordering defined for
+related create and destroy operations, as well as changes to the lifecycle
+ordering imposed by `create_before_destroy`. It is not intended to enumerate
+all possible combinations of dependency ordering, only to outline the basics
+and document some of the more complicated aspects of resource destruction.
+
+The graph diagrams here will continue to use the inverted graph structure used
+internally by Terraform, where edges represent dependencies rather than order
+of operations. 
+
+## Simple Resource Creation
+
+In order to describe resource destruction, we first need to create the
+resources and define their order. The order of creation is that which fulfills
+the dependencies for each resource. In this example, `A` has no dependencies,
+`B` depends on `A`, and `C` depends on `B`, and transitively depends on `A`.
+
+![Simple Resource Creation](./images/simple_create.png)
+<!--
+digraph create {
+    subgraph nodes {
+        rank=same;
+        a [label="A create"];
+        b [label="B create"];
+        c [label="C create"];
+        b -> c [dir=back];
+        a -> b [dir=back];
+    }
+}
+-->
+
+Order of operations:
+1. `A` is created
+1. `B` is created
+1. `C` is created
+
+## Resource Updates
+
+An existing resource may be updated with references to a newly created
+resource. The ordering here is exactly the same as one would expect for
+creation.
+
+![Simple Resource Updates](./images/simple_update.png)
+<!--
+digraph update {
+    subgraph nodes {
+        rank=same;
+        a [label="A create"];
+        b [label="B update"];
+        c [label="C update"];
+        b -> c [dir=back];
+        a -> b [dir=back];
+    }
+}
+-->
+
+Order of operations:
+1. `A` is created
+1. `B` is created
+1. `C` is created
+
+## Simple Resource Destruction
+
+The order for destroying resource is exactly the inverse used to create them.
+This example shows the graph for the destruction of the same nodes defined
+above. While destroy nodes will not contain attribute references, we will
+continue to use the inverted edges showing dependencies for destroy, so the
+operational ordering is still opposite the flow of the arrows.
+
+![Simple Resource Destruction](./images/simple_destroy.png)
+<!--
+digraph destroy {
+    subgraph nodes {
+        rank=same;
+        a [label="A destroy"];
+        b [label="B destroy"];
+        c [label="C destroy"];
+        a -> b;
+        b -> c;
+    }
+}
+-->
+
+Order of operations:
+1. `C` is destroyed
+1. `B` is destroyed
+1. `A` is Destroyed
+
+## Resource Replacement
+
+Resource replacement is the logical combination of the above scenarios. Here we
+will show the replacement steps involved when `B` depends on `A`.
+
+In this first example, we simultaneously replace both `A` and `B`. Here `B` is
+destroyed before `A`, then `A` is recreated before `B`.
+
+![Replace All](./images/replace_all.png)
+<!--
+digraph replacement {
+    subgraph create {
+        rank=same;
+        a [label="A create"];
+        b [label="B create"];
+        a -> b [dir=back];
+    }
+    subgraph destroy {
+        rank=same;
+        a_d [label="A destroy"];
+        b_d [label="B destroy"];
+        a_d -> b_d;
+    }
+
+    a -> a_d;
+    a -> b_d [style=dotted];
+    b -> a_d [style=dotted];
+    b -> b_d;
+}
+-->
+
+Order of operations:
+1. `B` is destroyed
+1. `A` is destroyed
+1. `A` is created
+1. `B` is created
+
+
+This second example replaces only `A`, while updating `B`. Resource `B` is only
+updated once `A` has been destroyed and recreated.
+
+![Replace Dependency](./images/replace_one.png)
+<!--
+digraph replacement {
+    subgraph create {
+        rank=same;
+        a [label="A create"];
+        b [label="B update"];
+        a -> b [dir=back];
+    }
+    subgraph destroy {
+        rank=same;
+        a_d [label="A destroy"];
+    }
+
+    a -> a_d;
+    b -> a_d [style=dotted];
+}
+-->
+
+Order of operations:
+1. `A` is destroyed
+1. `A` is created
+1. `B` is updated
+
+
+While the dependency edge from `B update` to `A destroy` isn't necessary in
+these examples, it is shown here as an implementation detail which will be
+mentioned later on.
+
+A final example based on the replacement graph; starting with the above
+configuration where `B` depends on `A`. The graph is reduced to an update of
+`A` while only destroying `B`. The interesting feature here is the remaining
+dependency of `A update` on `B destroy`. We can derive this ordering of
+operations from the full replacement example above, by replacing `A create`
+with `A update` and removing the unused nodes.
+
+![Replace All](./images/destroy_then_update.png)
+<!--
+digraph destroy_then_update {
+    subgraph update {
+        rank=same;
+        a [label="A update"];
+    }
+    subgraph destroy {
+        rank=same;
+        b_d [label="B destroy"];
+    }
+
+    a -> b_d;
+}
+-->
+## Create Before Destroy
+
+Currently, the only user-controllable method for changing the ordering of
+create and destroy operations is with the `create_before_destroy` resource
+`lifecycle` attribute. This has the obvious effect of causing a resource to be
+created before it is destroyed when replacement is required, but has a couple
+of other effects we will detail here.
+
+Taking the previous replacement examples, we can change the behavior of `A` to
+be that of `create_before_destroy`.
+
+![Replace all, dependency is create_before_destroy](./images/replace_all_cbd_dep.png)
+<!--
+digraph replacement {
+    subgraph create {
+        rank=same;
+        a [label="A create"];
+        b [label="B create"];
+        a -> b [dir=back];
+    }
+    subgraph destroy {
+        rank=same;
+        a_d [label="A destroy"];
+        b_d [label="B destroy"];
+        a_d -> b_d;
+    }
+
+    a -> a_d [dir=back];
+    a -> b_d;
+    b -> a_d [dir=back];
+    b -> b_d;
+}
+-->
+
+
+Order of operations:
+1. `B` is destroyed
+2. `A` is created
+1. `B` is created
+1. `A` is destroyed
+
+Note that in this first example, the creation of `B` is inserted in between the
+creation of `A` and the destruction of `A`. This becomes more important in the
+update example below.
+
+
+![Replace dependency, dependency is create_before_destroy](./images/replace_dep_cbd_dep.png)
+<!--
+digraph replacement {
+    subgraph create {
+        rank=same;
+        a [label="A create"];
+        b [label="B update"];
+        a -> b [dir=back];
+    }
+    subgraph destroy {
+        rank=same;
+        a_d [label="A destroy"];
+    }
+
+    a -> a_d [dir=back, style=dotted];
+    b -> a_d [dir=back];
+}
+-->
+
+Order of operations:
+1. `A` is created
+1. `B` is updated
+1. `A` is destroyed
+
+Here we can see clearly how `B` is updated after the creation of `A` and before
+the destruction of the _deposed_ resource `A`. (The prior resource `A` is
+sometimes referred to as "deposed" before it is destroyed, to disambiguate it
+from the newly created `A`.) This ordering is important for resource that
+"register" other resources, and require updating before the dependent resource
+can be destroyed.
+
+The transformation used to create these graphs is also where we use the extra
+edges mentioned above connecting `B` to `A destroy`. The algorithm to change a
+resource from the default ordering to `create_before_destroy` simply inverts
+any incoming edges from other resources, which automatically creates the
+necessary dependency ordering for dependent updates. This also ensures that
+reduced versions of this example still adhere to the same ordering rules, such
+as when the dependency is only being removed:
+
+![Update a destroyed create_before_destroy dependency](./images/update_destroy_cbd.png)
+<!--
+digraph update {
+    subgraph create {
+        rank=same;
+        b [label="B update"];
+    }
+    subgraph destroy {
+        rank=same;
+        a_d [label="A destroy"];
+    }
+
+    b -> a_d [dir=back];
+}
+-->
+
+Order of operations:
+1. `B` is updated
+1. `A` is destroyed
+
+### Forced Create Before Destroy
+
+In the previous examples, only resource `A` was being used as is it were
+`create_before_destroy`. The minimal graphs used show that it works in
+isolation, but that is only when the `create_before_destroy` resource has no
+dependencies of it own. When a `create_before_resource` depends on another
+resource, that dependency is "infected" by the `create_before_destroy`
+lifecycle attribute.
+
+This example demonstrates why forcing `create_before_destroy` is necessary. `B`
+has `create_before_destroy` while `A` does not. If we only invert the ordering
+for `B`, we can see that results in a cycle.
+
+![Incorrect create_before_destroy replacement](./images/replace_cbd_incorrect.png)
+<!--
+digraph replacement {
+    subgraph create {
+        rank=same;
+        a [label="A create"];
+        b [label="B create"];
+        a -> b [dir=back];
+    }
+    subgraph destroy {
+        rank=same;
+        a_d [label="A destroy"];
+        b_d [label="B destroy"];
+        a_d -> b_d;
+    }
+
+    a -> a_d;
+    a -> b_d [style=dotted];
+    b -> a_d [style=dotted];
+    b -> b_d [dir=back];
+}
+-->
+
+In order to resolve these cycles, all resources that precede a resource
+with `create_before_destroy` must in turn be handled in the same manner.
+Reversing the incoming edges to `A destroy` resolves the problem:
+
+![Correct create_before_destroy replacement](./images/replace_all_cbd.png)
+<!--
+digraph replacement {
+    subgraph create {
+        rank=same;
+        a [label="A create"];
+        b [label="B create"];
+        a -> b [dir=back];
+    }
+    subgraph destroy {
+        rank=same;
+        a_d [label="A destroy"];
+        b_d [label="B destroy"];
+        a_d -> b_d;
+    }
+
+    a -> a_d [dir=back];
+    a -> b_d [dir=back, style=dotted];
+    b -> a_d [dir=back, style=dotted];
+    b -> b_d [dir=back];
+}
+-->
+
+Order of operations:
+1. `A` is created
+1. `B` is created
+1. `B` is destroyed
+1. `A` is destroyed
+
+This also demonstrates why `create_before_destroy` cannot be overridden when
+it is inherited; changing the behavior here isn't possible without removing
+the initial reason for `create_before_destroy`; otherwise cycles are always
+introduced into the graph.
diff --git a/v1.5.7/docs/images/architecture-overview.png b/v1.5.7/docs/images/architecture-overview.png
new file mode 100644
index 0000000..40f2a04
--- /dev/null
+++ b/v1.5.7/docs/images/architecture-overview.png
Binary files differ
diff --git a/v1.5.7/docs/images/destroy_then_update.png b/v1.5.7/docs/images/destroy_then_update.png
new file mode 100644
index 0000000..f4f3d20
--- /dev/null
+++ b/v1.5.7/docs/images/destroy_then_update.png
Binary files differ
diff --git a/v1.5.7/docs/images/replace_all.png b/v1.5.7/docs/images/replace_all.png
new file mode 100644
index 0000000..54d5ad6
--- /dev/null
+++ b/v1.5.7/docs/images/replace_all.png
Binary files differ
diff --git a/v1.5.7/docs/images/replace_all_cbd.png b/v1.5.7/docs/images/replace_all_cbd.png
new file mode 100644
index 0000000..da72fe4
--- /dev/null
+++ b/v1.5.7/docs/images/replace_all_cbd.png
Binary files differ
diff --git a/v1.5.7/docs/images/replace_all_cbd_dep.png b/v1.5.7/docs/images/replace_all_cbd_dep.png
new file mode 100644
index 0000000..98bdbde
--- /dev/null
+++ b/v1.5.7/docs/images/replace_all_cbd_dep.png
Binary files differ
diff --git a/v1.5.7/docs/images/replace_cbd_incorrect.png b/v1.5.7/docs/images/replace_cbd_incorrect.png
new file mode 100644
index 0000000..72591d0
--- /dev/null
+++ b/v1.5.7/docs/images/replace_cbd_incorrect.png
Binary files differ
diff --git a/v1.5.7/docs/images/replace_dep_cbd_dep.png b/v1.5.7/docs/images/replace_dep_cbd_dep.png
new file mode 100644
index 0000000..35b7936
--- /dev/null
+++ b/v1.5.7/docs/images/replace_dep_cbd_dep.png
Binary files differ
diff --git a/v1.5.7/docs/images/replace_one.png b/v1.5.7/docs/images/replace_one.png
new file mode 100644
index 0000000..fe1aa1d
--- /dev/null
+++ b/v1.5.7/docs/images/replace_one.png
Binary files differ
diff --git a/v1.5.7/docs/images/resource-instance-change-lifecycle.png b/v1.5.7/docs/images/resource-instance-change-lifecycle.png
new file mode 100644
index 0000000..b6cf16e
--- /dev/null
+++ b/v1.5.7/docs/images/resource-instance-change-lifecycle.png
Binary files differ
diff --git a/v1.5.7/docs/images/simple_create.png b/v1.5.7/docs/images/simple_create.png
new file mode 100644
index 0000000..5c82954
--- /dev/null
+++ b/v1.5.7/docs/images/simple_create.png
Binary files differ
diff --git a/v1.5.7/docs/images/simple_destroy.png b/v1.5.7/docs/images/simple_destroy.png
new file mode 100644
index 0000000..be2e8fc
--- /dev/null
+++ b/v1.5.7/docs/images/simple_destroy.png
Binary files differ
diff --git a/v1.5.7/docs/images/simple_update.png b/v1.5.7/docs/images/simple_update.png
new file mode 100644
index 0000000..ada18b2
--- /dev/null
+++ b/v1.5.7/docs/images/simple_update.png
Binary files differ
diff --git a/v1.5.7/docs/images/update_destroy_cbd.png b/v1.5.7/docs/images/update_destroy_cbd.png
new file mode 100644
index 0000000..2ad04c9
--- /dev/null
+++ b/v1.5.7/docs/images/update_destroy_cbd.png
Binary files differ
diff --git a/v1.5.7/docs/planning-behaviors.md b/v1.5.7/docs/planning-behaviors.md
new file mode 100644
index 0000000..ecb6fb3
--- /dev/null
+++ b/v1.5.7/docs/planning-behaviors.md
@@ -0,0 +1,294 @@
+# Planning Behaviors
+
+A key design tenet for Terraform is that any actions with externally-visible
+side-effects should be carried out via the standard process of creating a
+plan and then applying it. Any new features should typically fit within this
+model.
+
+There are also some historical exceptions to this rule, which we hope to
+supplement with plan-and-apply-based equivalents over time.
+
+This document describes the default planning behavior of Terraform in the
+absence of any special instructions, and also describes the three main
+design approaches we can choose from when modelling non-default behaviors that
+require additional information from outside of Terraform Core.
+
+This document focuses primarily on actions relating to _resource instances_,
+because that is Terraform's main concern. However, these design principles can
+potentially generalize to other externally-visible objects, if we can describe
+their behaviors in a way comparable to the resource instance behaviors.
+
+This is developer-oriented documentation rather than user-oriented
+documentation. See
+[the main Terraform documentation](https://www.terraform.io/docs) for
+information on existing planning behaviors and other behaviors as viewed from
+an end-user perspective.
+
+## Default Planning Behavior
+
+When given no explicit information to the contrary, Terraform Core will
+automatically propose taking the following actions in the appropriate
+situations:
+
+- **Create**, if either of the following are true:
+  - There is a `resource` block in the configuration that has no corresponding
+    managed resource in the prior state.
+  - There is a `resource` block in the configuration that is recorded in the
+    prior state but whose `count` or `for_each` argument (or lack thereof)
+    describes an instance key that is not tracked in the prior state.
+- **Delete**, if either of the following are true:
+  - There is a managed resource tracked in the prior state which has no
+    corresponding `resource` block in the configuration.
+  - There is a managed resource tracked in the prior state which has a
+    corresponding `resource` block in the configuration _but_ its `count`
+    or `for_each` argument (or lack thereof) lacks an instance key that is
+    tracked in the prior state.
+- **Update**, if there is a corresponding resource instance both declared in the
+  configuration (in a `resource` block) and recorded in the prior state
+  (unless it's marked as "tainted") but there are differences between the prior
+  state and the configuration which the corresponding provider doesn't
+  explicitly classify as just being normalization.
+- **Replace**, if there is a corresponding resource instance both declared in
+  the configuration (in a `resource` block) and recorded in the prior state
+  _marked as "tainted"_. The special "tainted" status means that the process
+  of creating the object failed partway through and so the existing object does
+  not necessarily match the configuration, so Terraform plans to replace it
+  in order to ensure that the resulting object is complete.
+- **Read**, if there is a `data` block in the configuration.
+  - If possible, Terraform will eagerly perform this action during the planning
+    phase, rather than waiting until the apply phase.
+  - If the configuration contains at least one unknown value, or if the
+    data resource directly depends on a managed resource that has any change
+    proposed elsewhere in the plan, Terraform will instead delay this action
+    to the apply phase so that it can react to the completion of modification
+    actions on other objects.
+- **No-op**, to explicitly represent that Terraform considered a particular
+  resource instance but concluded that no action was required.
+
+The **Replace** action described above is really a sort of "meta-action", which
+Terraform expands into separate **Create** and **Delete** operations. There are
+two possible orderings, and the first one is the default planning behavior
+unless overridden by a special planning behavior as described later. The
+two possible lowerings of **Replace** are:
+1. **Delete** then **Create**: first delete the existing object bound to an
+  instance, and then create a new object at the same address based on the
+  current configuration.
+2. **Create** then **Delete**: mark the existing object bound to an instance as
+  "deposed" (still exists but not current), create a new current object at the
+  same address based on the current configuration, and then delete the deposed
+  object.
+
+## Special Planning Behaviors
+
+For the sake of this document, a "special" planning behavior is one where
+Terraform Core will select a different action than the defaults above,
+based on explicit instructions given either by a module author, an operator,
+or a provider.
+
+There are broadly three different design patterns for special planning
+behaviors, and so each "special" use-case will typically be met by one or more
+of the following depending on which stakeholder is activating the behavior:
+
+- [Configuration-driven Behaviors](#configuration-driven-behaviors) are
+  activated by additional annotations given in the source code of a module.
+
+    This design pattern is good for situations where the behavior relates to
+    a particular module and so should be activated for anyone using that
+    module. These behaviors are therefore specified by the module author, such
+    that any caller of the module will automatically benefit with no additional
+    work.
+- [Provider-driven Behaviors](#provider-driven-behaviors) are activated by
+  optional fields in a provider's response when asked to help plan one of the
+  default actions given above.
+
+    This design pattern is good for situations where the behavior relates to
+    the behavior of the remote system that a provider is wrapping, and so from
+    the perspective of a user of the provider the behavior should appear
+    "automatic".
+
+    Because these special behaviors are activated by values in the provider's
+    response to the planning request from Terraform Core, behaviors of this
+    sort will typically represent "tweaks" to or variants of the default
+    planning behaviors, rather than entirely different behaviors.
+- [Single-run Behaviors](#single-run-behaviors) are activated by explicitly
+  setting additional "plan options" when calling Terraform Core's plan
+  operation.
+
+    This design pattern is good for situations where the direct operator of
+    Terraform needs to do something exceptional or one-off, such as when the
+    configuration is correct but the real system has become degraded or damaged
+    in a way that Terraform cannot automatically understand.
+
+    However, this design pattern has the disadvantage that each new single-run
+    behavior type requires custom work in every wrapping UI or automaton around
+    Terraform Core, in order provide the user of that wrapper some way
+    to directly activate the special option, or to offer an "escape hatch" to
+    use Terraform CLI directly and bypass the wrapping automation for a
+    particular change.
+
+We've also encountered use-cases that seem to call for a hybrid between these
+different patterns. For example, a configuration construct might cause Terraform
+Core to _invite_ a provider to activate a special behavior, but let the
+provider make the final call about whether to do it. Or conversely, a provider
+might advertise the possibility of a special behavior but require the user to
+specify something in the configuration to activate it. The above are just
+broad categories to help us think through potential designs; some problems
+will require more creative combinations of these patterns than others.
+
+### Configuration-driven Behaviors
+
+Within the space of configuration-driven behaviors, we've encountered two
+main sub-categories:
+- Resource-specific behaviors, whose effect is scoped to a particular resource.
+  The configuration for these often lives inside the `resource` or `data`
+  block that declares the resource.
+- Global behaviors, whose effect can span across more than one resource and
+  sometimes between resources in different modules. The configuration for
+  these often lives in a separate location in a module, such as a separate
+  top-level block which refers to other resources using the typical address
+  syntax.
+
+The following is a non-exhaustive list of existing examples of
+configuration-driven behaviors, selected to illustrate some different variations
+that might be useful inspiration for new designs:
+
+- The `ignore_changes` argument inside `resource` block `lifecycle` blocks
+  tells Terraform that if there is an existing object bound to a particular
+  resource instance address then Terraform should ignore the configured value
+  for a particular argument and use the corresponding value from the prior
+  state instead.
+
+    This can therefore potentially cause what would've been an **Update** to be
+    a **No-op** instead.
+- The `replace_triggered_by` argument inside `resource` block `lifecycle`
+  blocks can use a proposed change elsewhere in a module to force Terraform
+  to propose one of the two **Replace** variants for a particular resource.
+- The `create_before_destroy` argument inside `resource` block `lifecycle`
+  blocks only takes effect if a particular resource instance has a proposed
+  **Replace** action. If not set or set to `false`, Terraform will decompose
+  it to **Destroy** then **Create**, but if set to `true` Terraform will use
+  the inverted ordering.
+
+    Because Terraform Core will never select a **Replace** action automatically
+    by itself, this is an example of a hybrid design where the config-driven
+    `create_before_destroy` combines with any other behavior (config-driven or
+    otherwise) that might cause **Replace** to customize exactly what that
+    **Replace** will mean.
+- Top-level `moved` blocks in a module activate a special behavior during the
+  planning phase, where Terraform will first try to change the bindings of
+  existing objects in the prior state to attach to new addresses before running
+  the normal planning process. This therefore allows a module author to
+  document certain kinds of refactoring so that Terraform can update the
+  state automatically once users upgrade to a new version of the module.
+
+    This special behavior is interesting because it doesn't _directly_ change
+    what actions Terraform will propose, but instead it adds an extra
+    preparation step before the typical planning process which changes the
+    addresses that the planning process will consider. It can therefore
+    _indirectly_ cause different proposed actions for affected resource
+    instances, such as transforming what by default might've been a **Delete**
+    of one instance and a **Create** of another into just a **No-op** or
+    **Update** of the second instance.
+
+    This one is an example of a "global behavior", because at minimum it
+    affects two resource instance addresses and, if working with whole resource
+    or whole module addresses, can potentially affect a large number of resource
+    instances all at once.
+
+### Provider-driven Behaviors
+
+Providers get an opportunity to activate some special behaviors for a particular
+resource instance when they respond to the `PlanResourceChange` function of
+the provider plugin protocol.
+
+When Terraform Core executes this RPC, it has already selected between
+**Create**, **Delete**, or **Update** actions for the particular resource
+instance, and so the special behaviors a provider may activate will typically
+serve as modifiers or tweaks to that base action, and will not allow
+the provider to select another base action altogether. The provider wire
+protocol does not talk about the action types explicitly, and instead only
+implies them via other content of the request and response, with Terraform Core
+making the final decision about how to react to that information.
+
+The following is a non-exhaustive list of existing examples of
+provider-driven behaviors, selected to illustrate some different variations
+that might be useful inspiration for new designs:
+
+- When the base action is **Update**, a provider may optionally return one or
+  more paths to attributes which have changes that the provider cannot
+  implement as an in-place update due to limitations of the remote system.
+
+    In that case, Terraform Core will replace the **Update** action with one of
+    the two **Replace** variants, which means that from the provider's
+    perspective the apply phase will really be two separate calls for the
+    decomposed **Create** and **Delete** actions (in either order), rather
+    than **Update** directly.
+- When the base action is **Update**, a provider may optionally return a
+  proposed new object where one or more of the arguments has its value set
+  to what was in the prior state rather than what was set in the configuration.
+  This represents any situation where a remote system supports multiple
+  different serializations of the same value that are all equivalent, and
+  so changing from one to another doesn't represent a real change in the
+  remote system.
+
+    If all of those taken together causes the new object to match the prior
+    state, Terraform Core will treat the update as a **No-op** instead.
+
+Of the three genres of special behaviors, provider-driven behaviors is the one
+we've made the least use of historically but one that seems to have a lot of
+opportunities for future exploration. Provider-driven behaviors can often be
+ideal because their effects appear as if they are built in to Terraform so
+that "it just works", with Terraform automatically deciding and explaining what
+needs to happen and why, without any special effort on the user's part.
+
+### Single-run Behaviors
+
+Terraform Core's "plan" operation takes a set of arguments that we collectively
+call "plan options", that can modify Terraform's planning behavior on a per-run
+basis without any configuration changes or special provider behaviors.
+
+As noted above, this particular genre of designs is the most burdensome to
+implement because any wrapping software that can ask Terraform Core to create
+a plan must ideally offer some way to set all of the available planning options,
+or else some part of Terraform's functionality won't be available to anyone
+using that wrapper.
+
+However, we've seen various situations where single-run behaviors really are the
+most appropriate way to handle a particular use-case, because the need for the
+behavior originates in some process happening outside of the scope of any
+particular Terraform module or provider.
+
+The following is a non-exhaustive list of existing examples of
+single-run behaviors, selected to illustrate some different variations
+that might be useful inspiration for new designs:
+
+- The "replace" planning option specifies zero or more resource instance
+  addresses.
+
+    For any resource instance specified, Terraform Core will transform any
+    **Update** or **No-op** action for that instance into one of the
+    **Replace** actions, thereby allowing an operator to respond to something
+    having become degraded in a way that Terraform and providers cannot
+    automatically detect and force Terraform to replace that object with
+    a new one that will hopefully function correctly.
+- The "refresh only" planning mode ("planning mode" is a single planning option
+  that selects between a few mutually-exclusive behaviors) forces Terraform
+  to treat every resource instance as **No-op**, regardless of what is bound
+  to that address in state or present in the configuration.
+
+## Legacy Operations
+
+Some of the legacy operations Terraform CLI offers that _aren't_ integrated
+with the plan and apply flow could be thought of as various degenerate kinds
+of single-run behaviors. Most don't offer any opportunity to preview an effect
+before applying it, but do meet a similar set of use-cases where an operator
+needs to take some action to respond to changes to the context Terraform is
+in rather than to the Terraform configuration itself.
+
+Most of these legacy operations could therefore most readily be translated to
+single-run behaviors, but before doing so it's worth researching whether people
+are using them as a workaround for missing configuration-driven and/or
+provider-driven behaviors. A particular legacy operation might be better
+replaced with a different sort of special behavior, or potentially by multiple
+different special behaviors of different genres if it's currently serving as
+a workaround for many different unmet needs.
diff --git a/v1.5.7/docs/plugin-protocol/README.md b/v1.5.7/docs/plugin-protocol/README.md
new file mode 100644
index 0000000..de92501
--- /dev/null
+++ b/v1.5.7/docs/plugin-protocol/README.md
@@ -0,0 +1,213 @@
+# Terraform Plugin Protocol
+
+This directory contains documentation about the physical wire protocol that
+Terraform Core uses to communicate with provider plugins.
+
+Most providers are not written directly against this protocol. Instead, prefer
+to use an SDK that implements this protocol and write the provider against
+the SDK's API.
+
+----
+
+**If you want to write a plugin for Terraform, please refer to
+[Extending Terraform](https://www.terraform.io/docs/extend/index.html) instead.**
+
+This documentation is for those who are developing _Terraform SDKs_, rather
+than those implementing plugins.
+
+----
+
+From Terraform v0.12.0 onwards, Terraform's plugin protocol is built on
+[gRPC](https://grpc.io/). This directory contains `.proto` definitions of
+different versions of Terraform's protocol.
+
+Only `.proto` files published as part of Terraform release tags are actually
+official protocol versions. If you are reading this directory on the `main`
+branch or any other development branch then it may contain protocol definitions
+that are not yet finalized and that may change before final release.
+
+## RPC Plugin Model
+
+Terraform plugins are normal executable programs that, when launched, expose
+gRPC services on a server accessed via the loopback interface. Terraform Core
+discovers and launches plugins, waits for a handshake to be printed on the
+plugin's `stdout`, and then connects to the indicated port number as a
+gRPC client.
+
+For this reason, we commonly refer to Terraform Core itself as the plugin
+"client" and the plugin program itself as the plugin "server". Both of these
+processes run locally, with the server process appearing as a child process
+of the client. Terraform Core controls the lifecycle of these server processes
+and will terminate them when they are no longer required.
+
+The startup and handshake protocol is not currently documented. We hope to
+document it here or to link to external documentation on it in future.
+
+## Versioning Strategy
+
+The Plugin Protocol uses a versioning strategy that aims to allow gradual
+enhancements to the protocol while retaining compatibility, but also to allow
+more significant breaking changes from time to time while allowing old and
+new plugins to be used together for some period.
+
+The versioning strategy described below was introduced with protocol version
+5.0 in Terraform v0.12. Prior versions of Terraform and prior protocol versions
+do not follow this strategy.
+
+The authoritative definition for each protocol version is in this directory
+as a Protocol Buffers (protobuf) service definition. The files follow the
+naming pattern `tfpluginX.Y.proto`, where X is the major version and Y
+is the minor version.
+
+### Major and minor versioning
+
+The minor version increases for each change introducing optional new
+functionality that can be ignored by implementations of prior versions. For
+example, if a new field were added to an response message, it could be a minor
+release as long as Terraform Core can provide some default behavior when that
+field is not populated.
+
+The major version increases for any significant change to the protocol where
+compatibility is broken. However, Terraform Core and an SDK may both choose
+to support multiple major versions at once: the plugin handshake includes a
+negotiation step where client and server can work together to select a
+mutually-supported major version.
+
+The major version number is encoded into the protobuf package name: major
+version 5 uses the package name `tfplugin5`, and one day major version 6
+will switch to `tfplugin6`. This change of name allows a plugin server to
+implement multiple major versions at once, by exporting multiple gRPC services.
+Minor version differences rely instead on feature-detection mechanisms, so they
+are not represented directly on the wire and exist primarily as a human
+communication tool to help us easily talk about which software supports which
+features.
+
+## Version compatibility for Core, SDK, and Providers
+
+A particular version of Terraform Core has both a minimum minor version it
+requires and a maximum major version that it supports. A particular version of
+Terraform Core may also be able to optionally use a newer minor version when
+available, but fall back on older behavior when that functionality is not
+available.
+
+Likewise, each provider plugin release is compatible with a set of versions.
+The compatible versions for a provider are a list of major and minor version
+pairs, such as "4.0", "5.2", which indicates that the provider supports the
+baseline features of major version 4 and supports major version 5 including
+the enhancements from both minor versions 1 and 2. This provider would
+therefore be compatible with a Terraform Core release that supports only
+protocol version 5.0, since major version 5 is supported and the optional
+5.1 and 5.2 enhancements will be ignored.
+
+If Terraform Core and the plugin do not have at least one mutually-supported
+major version, Terraform Core will return an error from `terraform init`
+during plugin installation:
+
+```
+Provider "aws" v1.0.0 is not compatible with Terraform v0.12.0.
+
+Provider version v2.0.0 is the earliest compatible version.
+Select it with the following version constraint:
+
+    version = "~> 2.0.0"
+```
+
+```
+Provider "aws" v3.0.0 is not compatible with Terraform v0.12.0.
+Provider version v2.34.0 is the latest compatible version. Select 
+it with the following constraint:
+
+    version = "~> 2.34.0"
+
+Alternatively, upgrade to the latest version of Terraform for compatibility with newer provider releases.
+```
+
+The above messages are for plugins installed via `terraform init` from a
+Terraform registry, where the registry API allows Terraform Core to recognize
+the protocol compatibility for each provider release. For plugins that are
+installed manually to a local plugin directory, Terraform Core has no way to
+suggest specific versions to upgrade or downgrade to, and so the error message
+is more generic:
+
+```
+The installed version of provider "example" is not compatible with Terraform v0.12.0.
+
+This provider was loaded from:
+     /usr/local/bin/terraform-provider-example_v0.1.0
+```
+
+## Adding/removing major version support in SDK and Providers
+
+The set of supported major versions is decided by the SDK used by the plugin.
+Over time, SDKs will add support for new major versions and phase out support
+for older major versions.
+
+In doing so, the SDK developer passes those capabilities and constraints on to
+any provider using their SDK, and that will in turn affect the compatibility
+of the plugin in ways that affect its semver-based version numbering:
+
+- If an SDK upgrade adds support for a new provider protocol, that will usually
+  be considered a new feature and thus warrant a new minor version.
+- If an SDK upgrade removes support for an old provider protocol, that is
+  always a breaking change and thus requires a major release of the provider.
+
+For this reason, SDK developers must be clear in their release notes about
+the addition and removal of support for major versions.
+
+Terraform Core also makes an assumption about major version support when
+it produces actionable error messages for users about incompatibilities:
+a particular protocol major version is supported for a single consecutive
+range of provider releases, with no "gaps".
+
+## Using the protobuf specifications in an SDK
+
+If you wish to build an SDK for Terraform plugins, an early step will be to
+copy one or more `.proto` files from this directory into your own repository
+(depending on which protocol versions you intend to support) and use the
+`protoc` protocol buffers compiler (with gRPC extensions) to generate suitable
+RPC stubs and types for your target language.
+
+For example, if you happen to be targeting Python, you might generate the
+stubs using a command like this:
+
+```
+protoc --python_out=. --grpc_python_out=. tfplugin5.1.proto
+```
+
+You can find out more about the tool usage for each target language in
+[the gRPC Quick Start guides](https://grpc.io/docs/quickstart/).
+
+The protobuf specification for a version is immutable after it has been
+included in at least one Terraform release. Any changes will be documented in
+a new `.proto` file establishing a new protocol version.
+
+The protocol buffer compiler will produce some sort of library object appropriate
+for the target language, which depending on the language might be called a
+module, or a package, or something else. We recommend to include the protocol
+major version in your module or package name so that you can potentially
+support multiple versions concurrently in future. For example, if you are
+targeting major version 5 you might call your package or module `tfplugin5`.
+
+To upgrade to a newer minor protocol version, copy the new `.proto` file
+from this directory into the same location as your previous version, delete
+the previous version, and then run the protocol buffers compiler again
+against the new `.proto` file. Because minor releases are backward-compatible,
+you can simply update your previous stubs in-place rather than creating a
+new set alongside.
+
+To support a new _major_ protocol version, create a new package or module
+and copy the relevant `.proto` file into it, creating a separate set of stubs
+that can in principle allow your SDK to support both major versions at the
+same time. We recommend supporting both the previous and current major versions
+together for a while across a major version upgrade so that users can avoid
+having to upgrade both Terraform Core and all of their providers at the same
+time, but you can delete the previous major version stubs once you remove
+support for that version.
+
+**Note:** Some of the `.proto` files contain statements about being updated
+in-place for minor versions. This reflects an earlier version management
+strategy which is no longer followed. The current process is to create a
+new file in this directory for each new minor version and consider all
+previously-tagged definitions as immutable. The outdated comments in those
+files are retained in order to keep the promise of immutability, even though
+it is now incorrect.
diff --git a/v1.5.7/docs/plugin-protocol/object-wire-format.md b/v1.5.7/docs/plugin-protocol/object-wire-format.md
new file mode 100644
index 0000000..5e1809c
--- /dev/null
+++ b/v1.5.7/docs/plugin-protocol/object-wire-format.md
@@ -0,0 +1,210 @@
+# Wire Format for Terraform Objects and Associated Values
+
+The provider wire protocol (as of major version 5) includes a protobuf message
+type `DynamicValue` which Terraform uses to represent values from the Terraform
+Language type system, which result from evaluating the content of `resource`,
+`data`, and `provider` blocks, based on a schema defined by the corresponding
+provider.
+
+Because the structure of these values is determined at runtime, `DynamicValue`
+uses one of two possible dynamic serialization formats for the values
+themselves: MessagePack or JSON. Terraform most commonly uses MessagePack,
+because it offers a compact binary representation of a value. However, a server
+implementation of the provider protocol should fall back to JSON if the
+MessagePack field is not populated, in order to support both formats.
+
+The remainder of this document describes how Terraform translates from its own
+type system into the type system of the two supported serialization formats.
+A server implementation of the Terraform provider protocol can use this
+information to decode `DynamicValue` values from incoming messages into
+whatever representation is convenient for the provider implementation.
+
+A server implementation must also be able to _produce_ `DynamicValue` messages
+as part of various response messages. When doing so, servers should always
+use MessagePack encoding, because Terraform does not consistently support
+JSON responses across all request types and all Terraform versions.
+
+Both the MessagePack and JSON serializations are driven by information the
+provider previously returned in a `Schema` message. Terraform will encode each
+value depending on the type constraint given for it in the corresponding schema,
+using the closest possible MessagePack or JSON type to the Terraform language
+type. Therefore a server implementation can decode a serialized value using a
+standard MessagePack or JSON library and assume it will conform to the
+serialization rules described below.
+
+## MessagePack Serialization Rules
+
+The MessagePack types referenced in this section are those defined in
+[The MessagePack type system specification](https://github.com/msgpack/msgpack/blob/master/spec.md#type-system).
+
+Note that MessagePack defines several possible serialization formats for each
+type, and Terraform may choose any of the formats of a specified type.
+The exact serialization chosen for a given value may vary between Terraform
+versions, but the types given here are contractual.
+
+Conversely, server implementations that are _producing_ MessagePack-encoded
+values are free to use any of the valid serialization formats for a particular
+type. However, we recommend choosing the most compact format that can represent
+the value without a loss of range.
+
+### `Schema.Block` Mapping Rules for MessagePack
+
+To represent the content of a block as MessagePack, Terraform constructs a
+MessagePack map that contains one key-value pair per attribute and one
+key-value pair per distinct nested block described in the `Schema.Block` message.
+
+The key-value pairs representing attributes have values based on
+[the `Schema.Attribute` mapping rules](#Schema.Attribute-mapping-rules-for-messagepack).
+The key-value pairs representing nested block types have values based on
+[the `Schema.NestedBlock` mapping rules](#Schema.NestedBlock-mapping-rules-for-messagepack).
+
+### `Schema.Attribute` Mapping Rules for MessagePack
+
+The MessagePack serialization of an attribute value depends on the value of the
+`type` field of the corresponding `Schema.Attribute` message. The `type` field is
+a compact JSON serialization of a
+[Terraform type constraint](https://www.terraform.io/docs/configuration/types.html),
+which consists either of a single
+string value (for primitive types) or a two-element array giving a type kind
+and a type argument.
+
+The following table describes the type-specific mapping rules. Along with those
+type-specific rules there are two special rules that override the mappings
+in the table below, regardless of type:
+
+* A null value is represented as a MessagePack nil value.
+* An unknown value (that is, a placeholder for a value that will be decided
+  only during the apply operation) is represented as a
+  [MessagePack extension](https://github.com/msgpack/msgpack/blob/master/spec.md#extension-types)
+  value whose type identifier is zero and whose value is unspecified and
+  meaningless.
+
+| `type` Pattern | MessagePack Representation |
+|---|---|
+| `"string"` | A MessagePack string containing the Unicode characters from the string value serialized as normalized UTF-8. |
+| `"number"` | Either MessagePack integer, MessagePack float, or MessagePack string representing the number. If a number is represented as a string then the string contains a decimal representation of the number which may have a larger mantissa than can be represented by a 64-bit float. |
+| `"bool"` | A MessagePack boolean value corresponding to the value. |
+| `["list",T]` | A MessagePack array with the same number of elements as the list value, each of which is represented by the result of applying these same mapping rules to the nested type `T`. |
+| `["set",T]` | Identical in representation to `["list",T]`, but the order of elements is undefined because Terraform sets are unordered. |
+| `["map",T]` | A MessagePack map with one key-value pair per element of the map value, where the element key is serialized as the map key (always a MessagePack string) and the element value is represented by a value constructed by applying these same mapping rules to the nested type `T`. |
+| `["object",ATTRS]` | A MessagePack map with one key-value pair per attribute defined in the `ATTRS` object. The attribute name is serialized as the map key (always a MessagePack string) and the attribute value is represented by a value constructed by applying these same mapping rules to each attribute's own type. |
+| `["tuple",TYPES]` | A MessagePack array with one element per element described by the `TYPES` array. The element values are constructed by applying these same mapping rules to the corresponding element of `TYPES`. |
+| `"dynamic"` | A MessagePack array with exactly two elements. The first element is a MessagePack binary value containing a JSON-serialized type constraint in the same format described in this table. The second element is the result of applying these same mapping rules to the value with the type given in the first element. This special type constraint represents values whose types will be decided only at runtime. |
+
+### `Schema.NestedBlock` Mapping Rules for MessagePack
+
+The MessagePack serialization of a collection of blocks of a particular type
+depends on the `nesting` field of the corresponding `Schema.NestedBlock` message.
+The `nesting` field is a value from the `Schema.NestingBlock.NestingMode`
+enumeration.
+
+All `nesting` values cause the individual blocks of a type to be represented
+by applying
+[the `Schema.Block` mapping rules](#Schema.Block-mapping-rules-for-messagepack)
+to the block's contents based on the `block` field, producing what we'll call
+a _block value_ in the table below.
+
+The `nesting` value then in turn defines how Terraform will collect all of the
+individual block values together to produce a single property value representing
+the nested block type. For all `nesting` values other than `MAP`, blocks may
+not have any labels. For the `nesting` value `MAP`, blocks must have exactly
+one label, which is a string we'll call a _block label_ in the table below.
+
+| `nesting` Value | MessagePack Representation |
+|---|---|
+| `SINGLE` | The block value of the single block of this type, or nil if there is no block of that type. |
+| `LIST` | A MessagePack array of all of the block values, preserving the order of definition of the blocks in the configuration. |
+| `SET` | A MessagePack array of all of the block values in no particular order. |
+| `MAP` | A MessagePack map with one key-value pair per block value, where the key is the block label and the value is the block value. |
+| `GROUP` | The same as with `SINGLE`, except that if there is no block of that type Terraform will synthesize a block value by pretending that all of the declared attributes are null and that there are zero blocks of each declared block type. |
+
+For the `LIST` and `SET` nesting modes, Terraform guarantees that the
+MessagePack array will have a number of elements between the `min_items` and
+`max_items` values given in the schema, _unless_ any of the block values contain
+nested unknown values. When unknown values are present, Terraform considers
+the value to be potentially incomplete and so Terraform defers validation of
+the number of blocks. For example, if the configuration includes a `dynamic`
+block whose `for_each` argument is unknown then the final number of blocks is
+not predictable until the apply phase.
+
+## JSON Serialization Rules
+
+The JSON serialization is a secondary representation for `DynamicValue`, with
+MessagePack preferred due to its ability to represent unknown values via an
+extension.
+
+The JSON encoding described in this section is also used for the `json` field
+of the `RawValue` message that forms part of an `UpgradeResourceState` request.
+However, in that case the data is serialized per the schema of the provider
+version that created it, which won't necessarily match the schema of the
+_current_ version of that provider.
+
+### `Schema.Block` Mapping Rules for JSON
+
+To represent the content of a block as JSON, Terraform constructs a
+JSON object that contains one property per attribute and one property per
+distinct nested block described in the `Schema.Block` message.
+
+The properties representing attributes have property values based on
+[the `Schema.Attribute` mapping rules](#Schema.Attribute-mapping-rules-for-json).
+The properties representing nested block types have property values based on
+[the `Schema.NestedBlock` mapping rules](#Schema.NestedBlock-mapping-rules-for-json).
+
+### `Schema.Attribute` Mapping Rules for JSON
+
+The JSON serialization of an attribute value depends on the value of the `type`
+field of the corresponding `Schema.Attribute` message. The `type` field is
+a compact JSON serialization of a
+[Terraform type constraint](https://www.terraform.io/docs/configuration/types.html),
+which consists either of a single
+string value (for primitive types) or a two-element array giving a type kind
+and a type argument.
+
+The following table describes the type-specific mapping rules. Along with those
+type-specific rules there is one special rule that overrides the rules in the
+table regardless of type:
+
+* A null value is always represented as JSON `null`.
+
+| `type` Pattern | JSON Representation |
+|---|---|
+| `"string"` | A JSON string containing the Unicode characters from the string value. |
+| `"number"` | A JSON number representing the number value. Terraform numbers are arbitrary-precision floating point, so the value may have a larger mantissa than can be represented by a 64-bit float. |
+| `"bool"` | Either JSON `true` or JSON `false`, depending on the boolean value. |
+| `["list",T]` | A JSON array with the same number of elements as the list value, each of which is represented by the result of applying these same mapping rules to the nested type `T`. |
+| `["set",T]` | Identical in representation to `["list",T]`, but the order of elements is undefined because Terraform sets are unordered. |
+| `["map",T]` | A JSON object with one property per element of the map value, where the element key is serialized as the property name string and the element value is represented by a property value constructed by applying these same mapping rules to the nested type `T`. |
+| `["object",ATTRS]` | A JSON object with one property per attribute defined in the `ATTRS` object. The attribute name is serialized as the property name string and the attribute value is represented by a property value constructed by applying these same mapping rules to each attribute's own type. |
+| `["tuple",TYPES]` | A JSON array with one element per element described by the `TYPES` array. The element values are constructed by applying these same mapping rules to the corresponding element of `TYPES`. |
+| `"dynamic"` | A JSON object with two properties: `"type"` specifying one of the `type` patterns described in this table in-band, giving the exact runtime type of the value, and `"value"` specifying the result of applying these same mapping rules to the table for the specified runtime type. This special type constraint represents values whose types will be decided only at runtime. |
+
+### `Schema.NestedBlock` Mapping Rules for JSON
+
+The JSON serialization of a collection of blocks of a particular type depends
+on the `nesting` field of the corresponding `Schema.NestedBlock` message.
+The `nesting` field is a value from the `Schema.NestingBlock.NestingMode`
+enumeration.
+
+All `nesting` values cause the individual blocks of a type to be represented
+by applying
+[the `Schema.Block` mapping rules](#Schema.Block-mapping-rules-for-json)
+to the block's contents based on the `block` field, producing what we'll call
+a _block value_ in the table below.
+
+The `nesting` value then in turn defines how Terraform will collect all of the
+individual block values together to produce a single property value representing
+the nested block type. For all `nesting` values other than `MAP`, blocks may
+not have any labels. For the `nesting` value `MAP`, blocks must have exactly
+one label, which is a string we'll call a _block label_ in the table below.
+
+| `nesting` Value | JSON Representation |
+|---|---|
+| `SINGLE` | The block value of the single block of this type, or `null` if there is no block of that type. |
+| `LIST` | A JSON array of all of the block values, preserving the order of definition of the blocks in the configuration. |
+| `SET` | A JSON array of all of the block values in no particular order. |
+| `MAP` | A JSON object with one property per block value, where the property name is the block label and the value is the block value. |
+| `GROUP` | The same as with `SINGLE`, except that if there is no block of that type Terraform will synthesize a block value by pretending that all of the declared attributes are null and that there are zero blocks of each declared block type. |
+
+For the `LIST` and `SET` nesting modes, Terraform guarantees that the JSON
+array will have a number of elements between the `min_items` and `max_items`
+values given in the schema.
diff --git a/v1.5.7/docs/plugin-protocol/releasing-new-version.md b/v1.5.7/docs/plugin-protocol/releasing-new-version.md
new file mode 100644
index 0000000..197a1a5
--- /dev/null
+++ b/v1.5.7/docs/plugin-protocol/releasing-new-version.md
@@ -0,0 +1,53 @@
+# Releasing a New Version of the Protocol
+
+Terraform's plugin protocol is the contract between Terraform's plugins and
+Terraform, and as such releasing a new version requires some coordination
+between those pieces. This document is intended to be a checklist to consult
+when adding a new major version of the protocol (X in X.Y) to ensure that
+everything that needs to be is aware of it.
+
+## New Protobuf File
+
+The protocol is defined in protobuf files that live in the hashicorp/terraform
+repository. Adding a new version of the protocol involves creating a new
+`.proto` file in that directory. It is recommended that you copy the latest
+protocol file, and modify it accordingly.
+
+## New terraform-plugin-go Package
+
+The
+[hashicorp/terraform-plugin-go](https://github.com/hashicorp/terraform-plugin-go)
+repository serves as the foundation for Terraform's plugin ecosystem. It needs
+to know about the new major protocol version. Either open an issue in that repo
+to have the Plugin SDK team add the new package, or if you would like to
+contribute it yourself, open a PR. It is recommended that you copy the package
+for the latest protocol version and modify it accordingly.
+
+## Update the Registry's List of Allowed Versions
+
+The Terraform Registry validates the protocol versions a provider advertises
+support for when ingesting providers. Providers will not be able to advertise
+support for the new protocol version until it is added to that list.
+
+## Update Terraform's Version Constraints
+
+Terraform only downloads providers that speak protocol versions it is
+compatible with from the Registry during `terraform init`. When adding support
+for a new protocol, you need to tell Terraform it knows that protocol version.
+Modify the `SupportedPluginProtocols` variable in hashicorp/terraform's
+`internal/getproviders/registry_client.go` file to include the new protocol.
+
+## Test Running a Provider With the Test Framework
+
+Use the provider test framework to test a provider written with the new
+protocol. This end-to-end test ensures that providers written with the new
+protocol work correctly with the test framework, especially in communicating
+the protocol version between the test framework and Terraform.
+
+## Test Retrieving and Running a Provider From the Registry
+
+Publish a provider, either to the public registry or to the staging registry,
+and test running `terraform init` and `terraform apply`, along with exercising
+any of the new functionality the protocol version introduces. This end-to-end
+test ensures that all the pieces needing to be updated before practitioners can
+use providers built with the new protocol have been updated.
diff --git a/v1.5.7/docs/plugin-protocol/tfplugin5.0.proto b/v1.5.7/docs/plugin-protocol/tfplugin5.0.proto
new file mode 100644
index 0000000..fc21ebf
--- /dev/null
+++ b/v1.5.7/docs/plugin-protocol/tfplugin5.0.proto
@@ -0,0 +1,356 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Terraform Plugin RPC protocol version 5.0
+//
+// This file defines version 5.0 of the RPC protocol. To implement a plugin
+// against this protocol, copy this definition into your own codebase and
+// use protoc to generate stubs for your target language.
+//
+// This file will be updated in-place in the source Terraform repository for
+// any minor versions of protocol 5, but later minor versions will always be
+// backwards compatible. Breaking changes, if any are required, will come
+// in a subsequent major version with its own separate proto definition.
+//
+// Note that only the proto files included in a release tag of Terraform are
+// official protocol releases. Proto files taken from other commits may include
+// incomplete changes or features that did not make it into a final release.
+// In all reasonable cases, plugin developers should take the proto file from
+// the tag of the most recent release of Terraform, and not from the main
+// branch or any other development branch.
+//
+syntax = "proto3";
+
+package tfplugin5;
+
+// DynamicValue is an opaque encoding of terraform data, with the field name
+// indicating the encoding scheme used.
+message DynamicValue {
+    bytes msgpack = 1;
+    bytes json = 2;
+}
+
+message Diagnostic {
+    enum Severity {
+        INVALID = 0;
+        ERROR = 1;
+        WARNING = 2;
+    }
+    Severity severity = 1;
+    string summary = 2;
+    string detail = 3;
+    AttributePath attribute = 4;
+}
+
+message AttributePath {
+    message Step {
+        oneof selector {
+            // Set "attribute_name" to represent looking up an attribute
+            // in the current object value.
+            string attribute_name = 1;
+            // Set "element_key_*" to represent looking up an element in
+            // an indexable collection type.
+            string element_key_string = 2;
+            int64 element_key_int = 3;
+        }
+    }
+    repeated Step steps = 1;
+}
+
+message Stop {
+    message Request {
+    }
+    message Response {
+		string Error = 1;
+    }
+}
+
+// RawState holds the stored state for a resource to be upgraded by the
+// provider. It can be in one of two formats, the current json encoded format
+// in bytes, or the legacy flatmap format as a map of strings.
+message RawState {
+    bytes json = 1;
+    map<string, string> flatmap = 2;
+}
+
+// Schema is the configuration schema for a Resource, Provider, or Provisioner.
+message Schema {
+    message Block {
+        int64 version = 1;
+        repeated Attribute attributes = 2;
+        repeated NestedBlock block_types = 3;
+    }
+
+    message Attribute {
+        string name = 1;
+        bytes type = 2;
+        string description = 3;
+        bool required = 4;
+        bool optional = 5;
+        bool computed = 6;
+        bool sensitive = 7;
+    }
+
+    message NestedBlock {
+        enum NestingMode {
+            INVALID = 0;
+            SINGLE = 1;
+            LIST = 2;
+            SET = 3;
+            MAP = 4;
+            GROUP = 5;
+        }
+
+        string type_name = 1;
+        Block block = 2;
+        NestingMode nesting = 3;
+        int64 min_items = 4;
+        int64 max_items = 5;
+    }
+
+    // The version of the schema.
+    // Schemas are versioned, so that providers can upgrade a saved resource
+    // state when the schema is changed. 
+    int64 version = 1;
+
+    // Block is the top level configuration block for this schema.
+    Block block = 2;
+}
+
+service Provider {
+    //////// Information about what a provider supports/expects
+    rpc GetSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
+    rpc PrepareProviderConfig(PrepareProviderConfig.Request) returns (PrepareProviderConfig.Response);
+    rpc ValidateResourceTypeConfig(ValidateResourceTypeConfig.Request) returns (ValidateResourceTypeConfig.Response);
+    rpc ValidateDataSourceConfig(ValidateDataSourceConfig.Request) returns (ValidateDataSourceConfig.Response);
+    rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
+
+    //////// One-time initialization, called before other functions below
+    rpc Configure(Configure.Request) returns (Configure.Response);
+
+    //////// Managed Resource Lifecycle
+    rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
+    rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
+    rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
+    rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
+
+    rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
+
+    //////// Graceful Shutdown
+    rpc Stop(Stop.Request) returns (Stop.Response);
+}
+
+message GetProviderSchema {
+    message Request {
+    }
+    message Response {
+        Schema provider = 1;
+        map<string, Schema> resource_schemas = 2;
+        map<string, Schema> data_source_schemas = 3;
+        repeated Diagnostic diagnostics = 4;
+    }
+}
+
+message PrepareProviderConfig {
+    message Request {
+        DynamicValue config = 1;
+    }
+    message Response {
+        DynamicValue prepared_config = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message UpgradeResourceState {
+    message Request {
+        string type_name = 1;
+
+        // version is the schema_version number recorded in the state file
+        int64 version = 2;
+
+        // raw_state is the raw states as stored for the resource.  Core does
+        // not have access to the schema of prior_version, so it's the
+        // provider's responsibility to interpret this value using the
+        // appropriate older schema. The raw_state will be the json encoded
+        // state, or a legacy flat-mapped format.
+        RawState raw_state = 3;
+    }
+    message Response {
+        // new_state is a msgpack-encoded data structure that, when interpreted with
+        // the _current_ schema for this resource type, is functionally equivalent to
+        // that which was given in prior_state_raw.
+        DynamicValue upgraded_state = 1;
+
+        // diagnostics describes any errors encountered during migration that could not
+        // be safely resolved, and warnings about any possibly-risky assumptions made
+        // in the upgrade process.
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ValidateResourceTypeConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ValidateDataSourceConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message Configure {
+    message Request {
+        string terraform_version = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ReadResource {
+    message Request {
+        string type_name = 1;
+        DynamicValue current_state = 2;
+        bytes private = 3;
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        repeated Diagnostic diagnostics = 2;
+        bytes private = 3;
+    }
+}
+
+message PlanResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue proposed_new_state = 3;
+        DynamicValue config = 4;
+        bytes prior_private = 5; 
+    }
+
+    message Response {
+        DynamicValue planned_state = 1;
+        repeated AttributePath requires_replace = 2;
+        bytes planned_private = 3; 
+        repeated Diagnostic diagnostics = 4;
+
+
+        // This may be set only by the helper/schema "SDK" in the main Terraform
+        // repository, to request that Terraform Core >=0.12 permit additional
+        // inconsistencies that can result from the legacy SDK type system
+        // and its imprecise mapping to the >=0.12 type system.
+        // The change in behavior implied by this flag makes sense only for the
+        // specific details of the legacy SDK type system, and are not a general
+        // mechanism to avoid proper type handling in providers.
+        //
+        //     ====              DO NOT USE THIS              ====
+        //     ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+        //     ====              DO NOT USE THIS              ====
+        bool legacy_type_system = 5;
+    }
+}
+
+message ApplyResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue planned_state = 3;
+        DynamicValue config = 4;
+        bytes planned_private = 5; 
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        bytes private = 2; 
+        repeated Diagnostic diagnostics = 3;
+
+        // This may be set only by the helper/schema "SDK" in the main Terraform
+        // repository, to request that Terraform Core >=0.12 permit additional
+        // inconsistencies that can result from the legacy SDK type system
+        // and its imprecise mapping to the >=0.12 type system.
+        // The change in behavior implied by this flag makes sense only for the
+        // specific details of the legacy SDK type system, and are not a general
+        // mechanism to avoid proper type handling in providers.
+        //
+        //     ====              DO NOT USE THIS              ====
+        //     ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+        //     ====              DO NOT USE THIS              ====
+        bool legacy_type_system = 4;
+    }
+}
+
+message ImportResourceState {
+    message Request {
+        string type_name = 1;
+        string id = 2;
+    }
+
+    message ImportedResource {
+        string type_name = 1;
+        DynamicValue state = 2;
+        bytes private = 3;
+    }
+
+    message Response {
+        repeated ImportedResource imported_resources = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ReadDataSource {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        DynamicValue state = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+service Provisioner {
+    rpc GetSchema(GetProvisionerSchema.Request) returns (GetProvisionerSchema.Response);
+    rpc ValidateProvisionerConfig(ValidateProvisionerConfig.Request) returns (ValidateProvisionerConfig.Response);
+    rpc ProvisionResource(ProvisionResource.Request) returns (stream ProvisionResource.Response);
+    rpc Stop(Stop.Request) returns (Stop.Response);
+}
+
+message GetProvisionerSchema {
+    message Request {
+    }
+    message Response {
+        Schema provisioner = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ValidateProvisionerConfig {
+    message Request {
+        DynamicValue config = 1;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ProvisionResource {
+    message Request {
+        DynamicValue config = 1;
+        DynamicValue connection = 2;
+    }
+    message Response {
+        string output  = 1;
+        repeated Diagnostic diagnostics = 2;
+    }   
+}
diff --git a/v1.5.7/docs/plugin-protocol/tfplugin5.1.proto b/v1.5.7/docs/plugin-protocol/tfplugin5.1.proto
new file mode 100644
index 0000000..a8c3b12
--- /dev/null
+++ b/v1.5.7/docs/plugin-protocol/tfplugin5.1.proto
@@ -0,0 +1,356 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Terraform Plugin RPC protocol version 5.1
+//
+// This file defines version 5.1 of the RPC protocol. To implement a plugin
+// against this protocol, copy this definition into your own codebase and
+// use protoc to generate stubs for your target language.
+//
+// This file will be updated in-place in the source Terraform repository for
+// any minor versions of protocol 5, but later minor versions will always be
+// backwards compatible. Breaking changes, if any are required, will come
+// in a subsequent major version with its own separate proto definition.
+//
+// Note that only the proto files included in a release tag of Terraform are
+// official protocol releases. Proto files taken from other commits may include
+// incomplete changes or features that did not make it into a final release.
+// In all reasonable cases, plugin developers should take the proto file from
+// the tag of the most recent release of Terraform, and not from the main
+// branch or any other development branch.
+//
+syntax = "proto3";
+
+package tfplugin5;
+
+// DynamicValue is an opaque encoding of terraform data, with the field name
+// indicating the encoding scheme used.
+message DynamicValue {
+    bytes msgpack = 1;
+    bytes json = 2;
+}
+
+message Diagnostic {
+    enum Severity {
+        INVALID = 0;
+        ERROR = 1;
+        WARNING = 2;
+    }
+    Severity severity = 1;
+    string summary = 2;
+    string detail = 3;
+    AttributePath attribute = 4;
+}
+
+message AttributePath {
+    message Step {
+        oneof selector {
+            // Set "attribute_name" to represent looking up an attribute
+            // in the current object value.
+            string attribute_name = 1;
+            // Set "element_key_*" to represent looking up an element in
+            // an indexable collection type.
+            string element_key_string = 2;
+            int64 element_key_int = 3;
+        }
+    }
+    repeated Step steps = 1;
+}
+
+message Stop {
+    message Request {
+    }
+    message Response {
+		string Error = 1;
+    }
+}
+
+// RawState holds the stored state for a resource to be upgraded by the
+// provider. It can be in one of two formats, the current json encoded format
+// in bytes, or the legacy flatmap format as a map of strings.
+message RawState {
+    bytes json = 1;
+    map<string, string> flatmap = 2;
+}
+
+// Schema is the configuration schema for a Resource, Provider, or Provisioner.
+message Schema {
+    message Block {
+        int64 version = 1;
+        repeated Attribute attributes = 2;
+        repeated NestedBlock block_types = 3;
+    }
+
+    message Attribute {
+        string name = 1;
+        bytes type = 2;
+        string description = 3;
+        bool required = 4;
+        bool optional = 5;
+        bool computed = 6;
+        bool sensitive = 7;
+    }
+
+    message NestedBlock {
+        enum NestingMode {
+            INVALID = 0;
+            SINGLE = 1;
+            LIST = 2;
+            SET = 3;
+            MAP = 4;
+            GROUP = 5;
+        }
+
+        string type_name = 1;
+        Block block = 2;
+        NestingMode nesting = 3;
+        int64 min_items = 4;
+        int64 max_items = 5;
+    }
+
+    // The version of the schema.
+    // Schemas are versioned, so that providers can upgrade a saved resource
+    // state when the schema is changed. 
+    int64 version = 1;
+
+    // Block is the top level configuration block for this schema.
+    Block block = 2;
+}
+
+service Provider {
+    //////// Information about what a provider supports/expects
+    rpc GetSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
+    rpc PrepareProviderConfig(PrepareProviderConfig.Request) returns (PrepareProviderConfig.Response);
+    rpc ValidateResourceTypeConfig(ValidateResourceTypeConfig.Request) returns (ValidateResourceTypeConfig.Response);
+    rpc ValidateDataSourceConfig(ValidateDataSourceConfig.Request) returns (ValidateDataSourceConfig.Response);
+    rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
+
+    //////// One-time initialization, called before other functions below
+    rpc Configure(Configure.Request) returns (Configure.Response);
+
+    //////// Managed Resource Lifecycle
+    rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
+    rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
+    rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
+    rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
+
+    rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
+
+    //////// Graceful Shutdown
+    rpc Stop(Stop.Request) returns (Stop.Response);
+}
+
+message GetProviderSchema {
+    message Request {
+    }
+    message Response {
+        Schema provider = 1;
+        map<string, Schema> resource_schemas = 2;
+        map<string, Schema> data_source_schemas = 3;
+        repeated Diagnostic diagnostics = 4;
+    }
+}
+
+message PrepareProviderConfig {
+    message Request {
+        DynamicValue config = 1;
+    }
+    message Response {
+        DynamicValue prepared_config = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message UpgradeResourceState {
+    message Request {
+        string type_name = 1;
+
+        // version is the schema_version number recorded in the state file
+        int64 version = 2;
+
+        // raw_state is the raw states as stored for the resource.  Core does
+        // not have access to the schema of prior_version, so it's the
+        // provider's responsibility to interpret this value using the
+        // appropriate older schema. The raw_state will be the json encoded
+        // state, or a legacy flat-mapped format.
+        RawState raw_state = 3;
+    }
+    message Response {
+        // new_state is a msgpack-encoded data structure that, when interpreted with
+        // the _current_ schema for this resource type, is functionally equivalent to
+        // that which was given in prior_state_raw.
+        DynamicValue upgraded_state = 1;
+
+        // diagnostics describes any errors encountered during migration that could not
+        // be safely resolved, and warnings about any possibly-risky assumptions made
+        // in the upgrade process.
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ValidateResourceTypeConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ValidateDataSourceConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message Configure {
+    message Request {
+        string terraform_version = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ReadResource {
+    message Request {
+        string type_name = 1;
+        DynamicValue current_state = 2;
+        bytes private = 3;
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        repeated Diagnostic diagnostics = 2;
+        bytes private = 3;
+    }
+}
+
+message PlanResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue proposed_new_state = 3;
+        DynamicValue config = 4;
+        bytes prior_private = 5; 
+    }
+
+    message Response {
+        DynamicValue planned_state = 1;
+        repeated AttributePath requires_replace = 2;
+        bytes planned_private = 3; 
+        repeated Diagnostic diagnostics = 4;
+
+
+        // This may be set only by the helper/schema "SDK" in the main Terraform
+        // repository, to request that Terraform Core >=0.12 permit additional
+        // inconsistencies that can result from the legacy SDK type system
+        // and its imprecise mapping to the >=0.12 type system.
+        // The change in behavior implied by this flag makes sense only for the
+        // specific details of the legacy SDK type system, and are not a general
+        // mechanism to avoid proper type handling in providers.
+        //
+        //     ====              DO NOT USE THIS              ====
+        //     ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+        //     ====              DO NOT USE THIS              ====
+        bool legacy_type_system = 5;
+    }
+}
+
+message ApplyResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue planned_state = 3;
+        DynamicValue config = 4;
+        bytes planned_private = 5; 
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        bytes private = 2; 
+        repeated Diagnostic diagnostics = 3;
+
+        // This may be set only by the helper/schema "SDK" in the main Terraform
+        // repository, to request that Terraform Core >=0.12 permit additional
+        // inconsistencies that can result from the legacy SDK type system
+        // and its imprecise mapping to the >=0.12 type system.
+        // The change in behavior implied by this flag makes sense only for the
+        // specific details of the legacy SDK type system, and are not a general
+        // mechanism to avoid proper type handling in providers.
+        //
+        //     ====              DO NOT USE THIS              ====
+        //     ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+        //     ====              DO NOT USE THIS              ====
+        bool legacy_type_system = 4;
+    }
+}
+
+message ImportResourceState {
+    message Request {
+        string type_name = 1;
+        string id = 2;
+    }
+
+    message ImportedResource {
+        string type_name = 1;
+        DynamicValue state = 2;
+        bytes private = 3;
+    }
+
+    message Response {
+        repeated ImportedResource imported_resources = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ReadDataSource {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        DynamicValue state = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+service Provisioner {
+    rpc GetSchema(GetProvisionerSchema.Request) returns (GetProvisionerSchema.Response);
+    rpc ValidateProvisionerConfig(ValidateProvisionerConfig.Request) returns (ValidateProvisionerConfig.Response);
+    rpc ProvisionResource(ProvisionResource.Request) returns (stream ProvisionResource.Response);
+    rpc Stop(Stop.Request) returns (Stop.Response);
+}
+
+message GetProvisionerSchema {
+    message Request {
+    }
+    message Response {
+        Schema provisioner = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ValidateProvisionerConfig {
+    message Request {
+        DynamicValue config = 1;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ProvisionResource {
+    message Request {
+        DynamicValue config = 1;
+        DynamicValue connection = 2;
+    }
+    message Response {
+        string output  = 1;
+        repeated Diagnostic diagnostics = 2;
+    }   
+}
diff --git a/v1.5.7/docs/plugin-protocol/tfplugin5.2.proto b/v1.5.7/docs/plugin-protocol/tfplugin5.2.proto
new file mode 100644
index 0000000..2960307
--- /dev/null
+++ b/v1.5.7/docs/plugin-protocol/tfplugin5.2.proto
@@ -0,0 +1,372 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Terraform Plugin RPC protocol version 5.2
+//
+// This file defines version 5.2 of the RPC protocol. To implement a plugin
+// against this protocol, copy this definition into your own codebase and
+// use protoc to generate stubs for your target language.
+//
+// This file will not be updated. Any minor versions of protocol 5 to follow
+// should copy this file and modify the copy while maintaing backwards
+// compatibility. Breaking changes, if any are required, will come
+// in a subsequent major version with its own separate proto definition.
+//
+// Note that only the proto files included in a release tag of Terraform are
+// official protocol releases. Proto files taken from other commits may include
+// incomplete changes or features that did not make it into a final release.
+// In all reasonable cases, plugin developers should take the proto file from
+// the tag of the most recent release of Terraform, and not from the main
+// branch or any other development branch.
+//
+syntax = "proto3";
+option go_package = "github.com/hashicorp/terraform/internal/tfplugin5";
+
+package tfplugin5;
+
+// DynamicValue is an opaque encoding of terraform data, with the field name
+// indicating the encoding scheme used.
+message DynamicValue {
+    bytes msgpack = 1;
+    bytes json = 2;
+}
+
+message Diagnostic {
+    enum Severity {
+        INVALID = 0;
+        ERROR = 1;
+        WARNING = 2;
+    }
+    Severity severity = 1;
+    string summary = 2;
+    string detail = 3;
+    AttributePath attribute = 4;
+}
+
+message AttributePath {
+    message Step {
+        oneof selector {
+            // Set "attribute_name" to represent looking up an attribute
+            // in the current object value.
+            string attribute_name = 1;
+            // Set "element_key_*" to represent looking up an element in
+            // an indexable collection type.
+            string element_key_string = 2;
+            int64 element_key_int = 3;
+        }
+    }
+    repeated Step steps = 1;
+}
+
+message Stop {
+    message Request {
+    }
+    message Response {
+                string Error = 1;
+    }
+}
+
+// RawState holds the stored state for a resource to be upgraded by the
+// provider. It can be in one of two formats, the current json encoded format
+// in bytes, or the legacy flatmap format as a map of strings.
+message RawState {
+    bytes json = 1;
+    map<string, string> flatmap = 2;
+}
+
+enum StringKind {
+    PLAIN = 0;
+    MARKDOWN = 1;
+}
+
+// Schema is the configuration schema for a Resource, Provider, or Provisioner.
+message Schema {
+    message Block {
+        int64 version = 1;
+        repeated Attribute attributes = 2;
+        repeated NestedBlock block_types = 3;
+        string description = 4;
+        StringKind description_kind = 5;
+        bool deprecated = 6;
+    }
+
+    message Attribute {
+        string name = 1;
+        bytes type = 2;
+        string description = 3;
+        bool required = 4;
+        bool optional = 5;
+        bool computed = 6;
+        bool sensitive = 7;
+        StringKind description_kind = 8;
+        bool deprecated = 9;
+    }
+
+    message NestedBlock {
+        enum NestingMode {
+            INVALID = 0;
+            SINGLE = 1;
+            LIST = 2;
+            SET = 3;
+            MAP = 4;
+            GROUP = 5;
+        }
+
+        string type_name = 1;
+        Block block = 2;
+        NestingMode nesting = 3;
+        int64 min_items = 4;
+        int64 max_items = 5;
+    }
+
+    // The version of the schema.
+    // Schemas are versioned, so that providers can upgrade a saved resource
+    // state when the schema is changed. 
+    int64 version = 1;
+
+    // Block is the top level configuration block for this schema.
+    Block block = 2;
+}
+
+service Provider {
+    //////// Information about what a provider supports/expects
+    rpc GetSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
+    rpc PrepareProviderConfig(PrepareProviderConfig.Request) returns (PrepareProviderConfig.Response);
+    rpc ValidateResourceTypeConfig(ValidateResourceTypeConfig.Request) returns (ValidateResourceTypeConfig.Response);
+    rpc ValidateDataSourceConfig(ValidateDataSourceConfig.Request) returns (ValidateDataSourceConfig.Response);
+    rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
+
+    //////// One-time initialization, called before other functions below
+    rpc Configure(Configure.Request) returns (Configure.Response);
+
+    //////// Managed Resource Lifecycle
+    rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
+    rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
+    rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
+    rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
+
+    rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
+
+    //////// Graceful Shutdown
+    rpc Stop(Stop.Request) returns (Stop.Response);
+}
+
+message GetProviderSchema {
+    message Request {
+    }
+    message Response {
+        Schema provider = 1;
+        map<string, Schema> resource_schemas = 2;
+        map<string, Schema> data_source_schemas = 3;
+        repeated Diagnostic diagnostics = 4;
+        Schema provider_meta = 5;
+    }
+}
+
+message PrepareProviderConfig {
+    message Request {
+        DynamicValue config = 1;
+    }
+    message Response {
+        DynamicValue prepared_config = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message UpgradeResourceState {
+    message Request {
+        string type_name = 1;
+
+        // version is the schema_version number recorded in the state file
+        int64 version = 2;
+
+        // raw_state is the raw states as stored for the resource.  Core does
+        // not have access to the schema of prior_version, so it's the
+        // provider's responsibility to interpret this value using the
+        // appropriate older schema. The raw_state will be the json encoded
+        // state, or a legacy flat-mapped format.
+        RawState raw_state = 3;
+    }
+    message Response {
+        // new_state is a msgpack-encoded data structure that, when interpreted with
+        // the _current_ schema for this resource type, is functionally equivalent to
+        // that which was given in prior_state_raw.
+        DynamicValue upgraded_state = 1;
+
+        // diagnostics describes any errors encountered during migration that could not
+        // be safely resolved, and warnings about any possibly-risky assumptions made
+        // in the upgrade process.
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ValidateResourceTypeConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ValidateDataSourceConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message Configure {
+    message Request {
+        string terraform_version = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ReadResource {
+    message Request {
+        string type_name = 1;
+        DynamicValue current_state = 2;
+        bytes private = 3;
+        DynamicValue provider_meta = 4;
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        repeated Diagnostic diagnostics = 2;
+        bytes private = 3;
+    }
+}
+
+message PlanResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue proposed_new_state = 3;
+        DynamicValue config = 4;
+        bytes prior_private = 5; 
+        DynamicValue provider_meta = 6;
+    }
+
+    message Response {
+        DynamicValue planned_state = 1;
+        repeated AttributePath requires_replace = 2;
+        bytes planned_private = 3; 
+        repeated Diagnostic diagnostics = 4;
+
+
+        // This may be set only by the helper/schema "SDK" in the main Terraform
+        // repository, to request that Terraform Core >=0.12 permit additional
+        // inconsistencies that can result from the legacy SDK type system
+        // and its imprecise mapping to the >=0.12 type system.
+        // The change in behavior implied by this flag makes sense only for the
+        // specific details of the legacy SDK type system, and are not a general
+        // mechanism to avoid proper type handling in providers.
+        //
+        //     ====              DO NOT USE THIS              ====
+        //     ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+        //     ====              DO NOT USE THIS              ====
+        bool legacy_type_system = 5;
+    }
+}
+
+message ApplyResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue planned_state = 3;
+        DynamicValue config = 4;
+        bytes planned_private = 5; 
+        DynamicValue provider_meta = 6;
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        bytes private = 2; 
+        repeated Diagnostic diagnostics = 3;
+
+        // This may be set only by the helper/schema "SDK" in the main Terraform
+        // repository, to request that Terraform Core >=0.12 permit additional
+        // inconsistencies that can result from the legacy SDK type system
+        // and its imprecise mapping to the >=0.12 type system.
+        // The change in behavior implied by this flag makes sense only for the
+        // specific details of the legacy SDK type system, and are not a general
+        // mechanism to avoid proper type handling in providers.
+        //
+        //     ====              DO NOT USE THIS              ====
+        //     ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+        //     ====              DO NOT USE THIS              ====
+        bool legacy_type_system = 4;
+    }
+}
+
+message ImportResourceState {
+    message Request {
+        string type_name = 1;
+        string id = 2;
+    }
+
+    message ImportedResource {
+        string type_name = 1;
+        DynamicValue state = 2;
+        bytes private = 3;
+    }
+
+    message Response {
+        repeated ImportedResource imported_resources = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ReadDataSource {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+        DynamicValue provider_meta = 3;
+    }
+    message Response {
+        DynamicValue state = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+service Provisioner {
+    rpc GetSchema(GetProvisionerSchema.Request) returns (GetProvisionerSchema.Response);
+    rpc ValidateProvisionerConfig(ValidateProvisionerConfig.Request) returns (ValidateProvisionerConfig.Response);
+    rpc ProvisionResource(ProvisionResource.Request) returns (stream ProvisionResource.Response);
+    rpc Stop(Stop.Request) returns (Stop.Response);
+}
+
+message GetProvisionerSchema {
+    message Request {
+    }
+    message Response {
+        Schema provisioner = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ValidateProvisionerConfig {
+    message Request {
+        DynamicValue config = 1;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ProvisionResource {
+    message Request {
+        DynamicValue config = 1;
+        DynamicValue connection = 2;
+    }
+    message Response {
+        string output  = 1;
+        repeated Diagnostic diagnostics = 2;
+    }   
+}
diff --git a/v1.5.7/docs/plugin-protocol/tfplugin5.3.proto b/v1.5.7/docs/plugin-protocol/tfplugin5.3.proto
new file mode 100644
index 0000000..dda153e
--- /dev/null
+++ b/v1.5.7/docs/plugin-protocol/tfplugin5.3.proto
@@ -0,0 +1,401 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Terraform Plugin RPC protocol version 5.3
+//
+// This file defines version 5.3 of the RPC protocol. To implement a plugin
+// against this protocol, copy this definition into your own codebase and
+// use protoc to generate stubs for your target language.
+//
+// This file will not be updated. Any minor versions of protocol 5 to follow
+// should copy this file and modify the copy while maintaing backwards
+// compatibility. Breaking changes, if any are required, will come
+// in a subsequent major version with its own separate proto definition.
+//
+// Note that only the proto files included in a release tag of Terraform are
+// official protocol releases. Proto files taken from other commits may include
+// incomplete changes or features that did not make it into a final release.
+// In all reasonable cases, plugin developers should take the proto file from
+// the tag of the most recent release of Terraform, and not from the main
+// branch or any other development branch.
+//
+syntax = "proto3";
+option go_package = "github.com/hashicorp/terraform/internal/tfplugin5";
+
+package tfplugin5;
+
+// DynamicValue is an opaque encoding of terraform data, with the field name
+// indicating the encoding scheme used.
+message DynamicValue {
+    bytes msgpack = 1;
+    bytes json = 2;
+}
+
+message Diagnostic {
+    enum Severity {
+        INVALID = 0;
+        ERROR = 1;
+        WARNING = 2;
+    }
+    Severity severity = 1;
+    string summary = 2;
+    string detail = 3;
+    AttributePath attribute = 4;
+}
+
+message AttributePath {
+    message Step {
+        oneof selector {
+            // Set "attribute_name" to represent looking up an attribute
+            // in the current object value.
+            string attribute_name = 1;
+            // Set "element_key_*" to represent looking up an element in
+            // an indexable collection type.
+            string element_key_string = 2;
+            int64 element_key_int = 3;
+        }
+    }
+    repeated Step steps = 1;
+}
+
+message Stop {
+    message Request {
+    }
+    message Response {
+                string Error = 1;
+    }
+}
+
+// RawState holds the stored state for a resource to be upgraded by the
+// provider. It can be in one of two formats, the current json encoded format
+// in bytes, or the legacy flatmap format as a map of strings.
+message RawState {
+    bytes json = 1;
+    map<string, string> flatmap = 2;
+}
+
+enum StringKind {
+    PLAIN = 0;
+    MARKDOWN = 1;
+}
+
+// Schema is the configuration schema for a Resource, Provider, or Provisioner.
+message Schema {
+    message Block {
+        int64 version = 1;
+        repeated Attribute attributes = 2;
+        repeated NestedBlock block_types = 3;
+        string description = 4;
+        StringKind description_kind = 5;
+        bool deprecated = 6;
+    }
+
+    message Attribute {
+        string name = 1;
+        bytes type = 2;
+        string description = 3;
+        bool required = 4;
+        bool optional = 5;
+        bool computed = 6;
+        bool sensitive = 7;
+        StringKind description_kind = 8;
+        bool deprecated = 9;
+    }
+
+    message NestedBlock {
+        enum NestingMode {
+            INVALID = 0;
+            SINGLE = 1;
+            LIST = 2;
+            SET = 3;
+            MAP = 4;
+            GROUP = 5;
+        }
+
+        string type_name = 1;
+        Block block = 2;
+        NestingMode nesting = 3;
+        int64 min_items = 4;
+        int64 max_items = 5;
+    }
+
+    // The version of the schema.
+    // Schemas are versioned, so that providers can upgrade a saved resource
+    // state when the schema is changed.
+    int64 version = 1;
+
+    // Block is the top level configuration block for this schema.
+    Block block = 2;
+}
+
+service Provider {
+    //////// Information about what a provider supports/expects
+    rpc GetSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
+    rpc PrepareProviderConfig(PrepareProviderConfig.Request) returns (PrepareProviderConfig.Response);
+    rpc ValidateResourceTypeConfig(ValidateResourceTypeConfig.Request) returns (ValidateResourceTypeConfig.Response);
+    rpc ValidateDataSourceConfig(ValidateDataSourceConfig.Request) returns (ValidateDataSourceConfig.Response);
+    rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
+
+    //////// One-time initialization, called before other functions below
+    rpc Configure(Configure.Request) returns (Configure.Response);
+
+    //////// Managed Resource Lifecycle
+    rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
+    rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
+    rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
+    rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
+
+    rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
+
+    //////// Graceful Shutdown
+    rpc Stop(Stop.Request) returns (Stop.Response);
+}
+
+message GetProviderSchema {
+    message Request {
+    }
+    message Response {
+        Schema provider = 1;
+        map<string, Schema> resource_schemas = 2;
+        map<string, Schema> data_source_schemas = 3;
+        repeated Diagnostic diagnostics = 4;
+        Schema provider_meta = 5;
+        ServerCapabilities server_capabilities = 6;
+    }
+
+
+    // ServerCapabilities allows providers to communicate extra information
+    // regarding supported protocol features. This is used to indicate
+    // availability of certain forward-compatible changes which may be optional
+    // in a major protocol version, but cannot be tested for directly.
+    message ServerCapabilities {
+        // The plan_destroy capability signals that a provider expects a call
+        // to PlanResourceChange when a resource is going to be destroyed.
+        bool plan_destroy = 1;
+    }
+}
+
+message PrepareProviderConfig {
+    message Request {
+        DynamicValue config = 1;
+    }
+    message Response {
+        DynamicValue prepared_config = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message UpgradeResourceState {
+    // Request is the message that is sent to the provider during the
+    // UpgradeResourceState RPC.
+    //
+    // This message intentionally does not include configuration data as any
+    // configuration-based or configuration-conditional changes should occur
+    // during the PlanResourceChange RPC. Additionally, the configuration is
+    // not guaranteed to exist (in the case of resource destruction), be wholly
+    // known, nor match the given prior state, which could lead to unexpected
+    // provider behaviors for practitioners.
+    message Request {
+        string type_name = 1;
+
+        // version is the schema_version number recorded in the state file
+        int64 version = 2;
+
+        // raw_state is the raw states as stored for the resource.  Core does
+        // not have access to the schema of prior_version, so it's the
+        // provider's responsibility to interpret this value using the
+        // appropriate older schema. The raw_state will be the json encoded
+        // state, or a legacy flat-mapped format.
+        RawState raw_state = 3;
+    }
+    message Response {
+        // new_state is a msgpack-encoded data structure that, when interpreted with
+        // the _current_ schema for this resource type, is functionally equivalent to
+        // that which was given in prior_state_raw.
+        DynamicValue upgraded_state = 1;
+
+        // diagnostics describes any errors encountered during migration that could not
+        // be safely resolved, and warnings about any possibly-risky assumptions made
+        // in the upgrade process.
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ValidateResourceTypeConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ValidateDataSourceConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message Configure {
+    message Request {
+        string terraform_version = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ReadResource {
+    // Request is the message that is sent to the provider during the
+    // ReadResource RPC.
+    //
+    // This message intentionally does not include configuration data as any
+    // configuration-based or configuration-conditional changes should occur
+    // during the PlanResourceChange RPC. Additionally, the configuration is
+    // not guaranteed to be wholly known nor match the given prior state, which
+    // could lead to unexpected provider behaviors for practitioners.
+    message Request {
+        string type_name = 1;
+        DynamicValue current_state = 2;
+        bytes private = 3;
+        DynamicValue provider_meta = 4;
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        repeated Diagnostic diagnostics = 2;
+        bytes private = 3;
+    }
+}
+
+message PlanResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue proposed_new_state = 3;
+        DynamicValue config = 4;
+        bytes prior_private = 5;
+        DynamicValue provider_meta = 6;
+    }
+
+    message Response {
+        DynamicValue planned_state = 1;
+        repeated AttributePath requires_replace = 2;
+        bytes planned_private = 3;
+        repeated Diagnostic diagnostics = 4;
+
+
+        // This may be set only by the helper/schema "SDK" in the main Terraform
+        // repository, to request that Terraform Core >=0.12 permit additional
+        // inconsistencies that can result from the legacy SDK type system
+        // and its imprecise mapping to the >=0.12 type system.
+        // The change in behavior implied by this flag makes sense only for the
+        // specific details of the legacy SDK type system, and are not a general
+        // mechanism to avoid proper type handling in providers.
+        //
+        //     ====              DO NOT USE THIS              ====
+        //     ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+        //     ====              DO NOT USE THIS              ====
+        bool legacy_type_system = 5;
+    }
+}
+
+message ApplyResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue planned_state = 3;
+        DynamicValue config = 4;
+        bytes planned_private = 5;
+        DynamicValue provider_meta = 6;
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        bytes private = 2;
+        repeated Diagnostic diagnostics = 3;
+
+        // This may be set only by the helper/schema "SDK" in the main Terraform
+        // repository, to request that Terraform Core >=0.12 permit additional
+        // inconsistencies that can result from the legacy SDK type system
+        // and its imprecise mapping to the >=0.12 type system.
+        // The change in behavior implied by this flag makes sense only for the
+        // specific details of the legacy SDK type system, and are not a general
+        // mechanism to avoid proper type handling in providers.
+        //
+        //     ====              DO NOT USE THIS              ====
+        //     ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+        //     ====              DO NOT USE THIS              ====
+        bool legacy_type_system = 4;
+    }
+}
+
+message ImportResourceState {
+    message Request {
+        string type_name = 1;
+        string id = 2;
+    }
+
+    message ImportedResource {
+        string type_name = 1;
+        DynamicValue state = 2;
+        bytes private = 3;
+    }
+
+    message Response {
+        repeated ImportedResource imported_resources = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ReadDataSource {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+        DynamicValue provider_meta = 3;
+    }
+    message Response {
+        DynamicValue state = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+service Provisioner {
+    rpc GetSchema(GetProvisionerSchema.Request) returns (GetProvisionerSchema.Response);
+    rpc ValidateProvisionerConfig(ValidateProvisionerConfig.Request) returns (ValidateProvisionerConfig.Response);
+    rpc ProvisionResource(ProvisionResource.Request) returns (stream ProvisionResource.Response);
+    rpc Stop(Stop.Request) returns (Stop.Response);
+}
+
+message GetProvisionerSchema {
+    message Request {
+    }
+    message Response {
+        Schema provisioner = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ValidateProvisionerConfig {
+    message Request {
+        DynamicValue config = 1;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ProvisionResource {
+    message Request {
+        DynamicValue config = 1;
+        DynamicValue connection = 2;
+    }
+    message Response {
+        string output  = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
diff --git a/v1.5.7/docs/plugin-protocol/tfplugin6.0.proto b/v1.5.7/docs/plugin-protocol/tfplugin6.0.proto
new file mode 100644
index 0000000..164edcc
--- /dev/null
+++ b/v1.5.7/docs/plugin-protocol/tfplugin6.0.proto
@@ -0,0 +1,324 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Terraform Plugin RPC protocol version 6.0
+//
+// This file defines version 6.0 of the RPC protocol. To implement a plugin
+// against this protocol, copy this definition into your own codebase and
+// use protoc to generate stubs for your target language.
+//
+// This file will not be updated. Any minor versions of protocol 6 to follow
+// should copy this file and modify the copy while maintaing backwards
+// compatibility. Breaking changes, if any are required, will come
+// in a subsequent major version with its own separate proto definition.
+//
+// Note that only the proto files included in a release tag of Terraform are
+// official protocol releases. Proto files taken from other commits may include
+// incomplete changes or features that did not make it into a final release.
+// In all reasonable cases, plugin developers should take the proto file from
+// the tag of the most recent release of Terraform, and not from the main
+// branch or any other development branch.
+//
+syntax = "proto3";
+option go_package = "github.com/hashicorp/terraform/internal/tfplugin6";
+
+package tfplugin6;
+
+// DynamicValue is an opaque encoding of terraform data, with the field name
+// indicating the encoding scheme used.
+message DynamicValue {
+    bytes msgpack = 1;
+    bytes json = 2;
+}
+
+message Diagnostic {
+    enum Severity {
+        INVALID = 0;
+        ERROR = 1;
+        WARNING = 2;
+    }
+    Severity severity = 1;
+    string summary = 2;
+    string detail = 3;
+    AttributePath attribute = 4;
+}
+
+message AttributePath {
+    message Step {
+        oneof selector {
+            // Set "attribute_name" to represent looking up an attribute
+            // in the current object value.
+            string attribute_name = 1;
+            // Set "element_key_*" to represent looking up an element in
+            // an indexable collection type.
+            string element_key_string = 2;
+            int64 element_key_int = 3;
+        }
+    }
+    repeated Step steps = 1;
+}
+
+message StopProvider {
+    message Request {
+    }
+    message Response {
+        string Error = 1;
+    }
+}
+
+// RawState holds the stored state for a resource to be upgraded by the
+// provider. It can be in one of two formats, the current json encoded format
+// in bytes, or the legacy flatmap format as a map of strings.
+message RawState {
+    bytes json = 1;
+    map<string, string> flatmap = 2;
+}
+
+enum StringKind {
+    PLAIN = 0;
+    MARKDOWN = 1;
+}
+
+// Schema is the configuration schema for a Resource or Provider.
+message Schema {
+    message Block {
+        int64 version = 1;
+        repeated Attribute attributes = 2;
+        repeated NestedBlock block_types = 3;
+        string description = 4;
+        StringKind description_kind = 5;
+        bool deprecated = 6;
+    }
+
+    message Attribute {
+        string name = 1;
+        bytes type = 2;
+        Object nested_type = 10;
+        string description = 3;
+        bool required = 4;
+        bool optional = 5;
+        bool computed = 6;
+        bool sensitive = 7;
+        StringKind description_kind = 8;
+        bool deprecated = 9;
+    }
+
+    message NestedBlock {
+        enum NestingMode {
+            INVALID = 0;
+            SINGLE = 1;
+            LIST = 2;
+            SET = 3;
+            MAP = 4;
+            GROUP = 5;
+        }
+
+        string type_name = 1;
+        Block block = 2;
+        NestingMode nesting = 3;
+        int64 min_items = 4;
+        int64 max_items = 5;
+    }
+
+    message Object {
+        enum NestingMode {
+            INVALID = 0;
+            SINGLE = 1;
+            LIST = 2;
+            SET = 3;
+            MAP = 4;
+        }
+
+        repeated Attribute attributes = 1;
+        NestingMode nesting = 3;
+        int64 min_items = 4;
+        int64 max_items = 5;
+    }
+
+    // The version of the schema.
+    // Schemas are versioned, so that providers can upgrade a saved resource
+    // state when the schema is changed. 
+    int64 version = 1;
+
+    // Block is the top level configuration block for this schema.
+    Block block = 2;
+}
+
+service Provider {
+    //////// Information about what a provider supports/expects
+    rpc GetProviderSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
+    rpc ValidateProviderConfig(ValidateProviderConfig.Request) returns (ValidateProviderConfig.Response);
+    rpc ValidateResourceConfig(ValidateResourceConfig.Request) returns (ValidateResourceConfig.Response);
+    rpc ValidateDataResourceConfig(ValidateDataResourceConfig.Request) returns (ValidateDataResourceConfig.Response);
+    rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
+
+    //////// One-time initialization, called before other functions below
+    rpc ConfigureProvider(ConfigureProvider.Request) returns (ConfigureProvider.Response);
+
+    //////// Managed Resource Lifecycle
+    rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
+    rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
+    rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
+    rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
+
+    rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
+
+    //////// Graceful Shutdown
+    rpc StopProvider(StopProvider.Request) returns (StopProvider.Response);
+}
+
+message GetProviderSchema {
+    message Request {
+    }
+    message Response {
+        Schema provider = 1;
+        map<string, Schema> resource_schemas = 2;
+        map<string, Schema> data_source_schemas = 3;
+        repeated Diagnostic diagnostics = 4;
+        Schema provider_meta = 5;
+    }
+}
+
+message ValidateProviderConfig {
+    message Request {
+        DynamicValue config = 1;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message UpgradeResourceState {
+    message Request {
+        string type_name = 1;
+
+        // version is the schema_version number recorded in the state file
+        int64 version = 2;
+
+        // raw_state is the raw states as stored for the resource.  Core does
+        // not have access to the schema of prior_version, so it's the
+        // provider's responsibility to interpret this value using the
+        // appropriate older schema. The raw_state will be the json encoded
+        // state, or a legacy flat-mapped format.
+        RawState raw_state = 3;
+    }
+    message Response {
+        // new_state is a msgpack-encoded data structure that, when interpreted with
+        // the _current_ schema for this resource type, is functionally equivalent to
+        // that which was given in prior_state_raw.
+        DynamicValue upgraded_state = 1;
+
+        // diagnostics describes any errors encountered during migration that could not
+        // be safely resolved, and warnings about any possibly-risky assumptions made
+        // in the upgrade process.
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ValidateResourceConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ValidateDataResourceConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ConfigureProvider {
+    message Request {
+        string terraform_version = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ReadResource {
+    message Request {
+        string type_name = 1;
+        DynamicValue current_state = 2;
+        bytes private = 3;
+        DynamicValue provider_meta = 4;
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        repeated Diagnostic diagnostics = 2;
+        bytes private = 3;
+    }
+}
+
+message PlanResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue proposed_new_state = 3;
+        DynamicValue config = 4;
+        bytes prior_private = 5; 
+        DynamicValue provider_meta = 6;
+    }
+
+    message Response {
+        DynamicValue planned_state = 1;
+        repeated AttributePath requires_replace = 2;
+        bytes planned_private = 3; 
+        repeated Diagnostic diagnostics = 4;
+    }
+}
+
+message ApplyResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue planned_state = 3;
+        DynamicValue config = 4;
+        bytes planned_private = 5; 
+        DynamicValue provider_meta = 6;
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        bytes private = 2; 
+        repeated Diagnostic diagnostics = 3;
+    }
+}
+
+message ImportResourceState {
+    message Request {
+        string type_name = 1;
+        string id = 2;
+    }
+
+    message ImportedResource {
+        string type_name = 1;
+        DynamicValue state = 2;
+        bytes private = 3;
+    }
+
+    message Response {
+        repeated ImportedResource imported_resources = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ReadDataSource {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+        DynamicValue provider_meta = 3;
+    }
+    message Response {
+        DynamicValue state = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
diff --git a/v1.5.7/docs/plugin-protocol/tfplugin6.1.proto b/v1.5.7/docs/plugin-protocol/tfplugin6.1.proto
new file mode 100644
index 0000000..72d309f
--- /dev/null
+++ b/v1.5.7/docs/plugin-protocol/tfplugin6.1.proto
@@ -0,0 +1,327 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Terraform Plugin RPC protocol version 6.1
+//
+// This file defines version 6.1 of the RPC protocol. To implement a plugin
+// against this protocol, copy this definition into your own codebase and
+// use protoc to generate stubs for your target language.
+//
+// This file will not be updated. Any minor versions of protocol 6 to follow
+// should copy this file and modify the copy while maintaing backwards
+// compatibility. Breaking changes, if any are required, will come
+// in a subsequent major version with its own separate proto definition.
+//
+// Note that only the proto files included in a release tag of Terraform are
+// official protocol releases. Proto files taken from other commits may include
+// incomplete changes or features that did not make it into a final release.
+// In all reasonable cases, plugin developers should take the proto file from
+// the tag of the most recent release of Terraform, and not from the main
+// branch or any other development branch.
+//
+syntax = "proto3";
+option go_package = "github.com/hashicorp/terraform/internal/tfplugin6";
+
+package tfplugin6;
+
+// DynamicValue is an opaque encoding of terraform data, with the field name
+// indicating the encoding scheme used.
+message DynamicValue {
+    bytes msgpack = 1;
+    bytes json = 2;
+}
+
+message Diagnostic {
+    enum Severity {
+        INVALID = 0;
+        ERROR = 1;
+        WARNING = 2;
+    }
+    Severity severity = 1;
+    string summary = 2;
+    string detail = 3;
+    AttributePath attribute = 4;
+}
+
+message AttributePath {
+    message Step {
+        oneof selector {
+            // Set "attribute_name" to represent looking up an attribute
+            // in the current object value.
+            string attribute_name = 1;
+            // Set "element_key_*" to represent looking up an element in
+            // an indexable collection type.
+            string element_key_string = 2;
+            int64 element_key_int = 3;
+        }
+    }
+    repeated Step steps = 1;
+}
+
+message StopProvider {
+    message Request {
+    }
+    message Response {
+        string Error = 1;
+    }
+}
+
+// RawState holds the stored state for a resource to be upgraded by the
+// provider. It can be in one of two formats, the current json encoded format
+// in bytes, or the legacy flatmap format as a map of strings.
+message RawState {
+    bytes json = 1;
+    map<string, string> flatmap = 2;
+}
+
+enum StringKind {
+    PLAIN = 0;
+    MARKDOWN = 1;
+}
+
+// Schema is the configuration schema for a Resource or Provider.
+message Schema {
+    message Block {
+        int64 version = 1;
+        repeated Attribute attributes = 2;
+        repeated NestedBlock block_types = 3;
+        string description = 4;
+        StringKind description_kind = 5;
+        bool deprecated = 6;
+    }
+
+    message Attribute {
+        string name = 1;
+        bytes type = 2;
+        Object nested_type = 10;
+        string description = 3;
+        bool required = 4;
+        bool optional = 5;
+        bool computed = 6;
+        bool sensitive = 7;
+        StringKind description_kind = 8;
+        bool deprecated = 9;
+    }
+
+    message NestedBlock {
+        enum NestingMode {
+            INVALID = 0;
+            SINGLE = 1;
+            LIST = 2;
+            SET = 3;
+            MAP = 4;
+            GROUP = 5;
+        }
+
+        string type_name = 1;
+        Block block = 2;
+        NestingMode nesting = 3;
+        int64 min_items = 4;
+        int64 max_items = 5;
+    }
+
+    message Object {
+        enum NestingMode {
+            INVALID = 0;
+            SINGLE = 1;
+            LIST = 2;
+            SET = 3;
+            MAP = 4;
+        }
+
+        repeated Attribute attributes = 1;
+        NestingMode nesting = 3;
+
+        // MinItems and MaxItems were never used in the protocol, and have no
+        // effect on validation.
+        int64 min_items = 4 [deprecated = true];
+        int64 max_items = 5 [deprecated = true];
+    }
+
+    // The version of the schema.
+    // Schemas are versioned, so that providers can upgrade a saved resource
+    // state when the schema is changed.
+    int64 version = 1;
+
+    // Block is the top level configuration block for this schema.
+    Block block = 2;
+}
+
+service Provider {
+    //////// Information about what a provider supports/expects
+    rpc GetProviderSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
+    rpc ValidateProviderConfig(ValidateProviderConfig.Request) returns (ValidateProviderConfig.Response);
+    rpc ValidateResourceConfig(ValidateResourceConfig.Request) returns (ValidateResourceConfig.Response);
+    rpc ValidateDataResourceConfig(ValidateDataResourceConfig.Request) returns (ValidateDataResourceConfig.Response);
+    rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
+
+    //////// One-time initialization, called before other functions below
+    rpc ConfigureProvider(ConfigureProvider.Request) returns (ConfigureProvider.Response);
+
+    //////// Managed Resource Lifecycle
+    rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
+    rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
+    rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
+    rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
+
+    rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
+
+    //////// Graceful Shutdown
+    rpc StopProvider(StopProvider.Request) returns (StopProvider.Response);
+}
+
+message GetProviderSchema {
+    message Request {
+    }
+    message Response {
+        Schema provider = 1;
+        map<string, Schema> resource_schemas = 2;
+        map<string, Schema> data_source_schemas = 3;
+        repeated Diagnostic diagnostics = 4;
+        Schema provider_meta = 5;
+    }
+}
+
+message ValidateProviderConfig {
+    message Request {
+        DynamicValue config = 1;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message UpgradeResourceState {
+    message Request {
+        string type_name = 1;
+
+        // version is the schema_version number recorded in the state file
+        int64 version = 2;
+
+        // raw_state is the raw states as stored for the resource.  Core does
+        // not have access to the schema of prior_version, so it's the
+        // provider's responsibility to interpret this value using the
+        // appropriate older schema. The raw_state will be the json encoded
+        // state, or a legacy flat-mapped format.
+        RawState raw_state = 3;
+    }
+    message Response {
+        // new_state is a msgpack-encoded data structure that, when interpreted with
+        // the _current_ schema for this resource type, is functionally equivalent to
+        // that which was given in prior_state_raw.
+        DynamicValue upgraded_state = 1;
+
+        // diagnostics describes any errors encountered during migration that could not
+        // be safely resolved, and warnings about any possibly-risky assumptions made
+        // in the upgrade process.
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ValidateResourceConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ValidateDataResourceConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ConfigureProvider {
+    message Request {
+        string terraform_version = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ReadResource {
+    message Request {
+        string type_name = 1;
+        DynamicValue current_state = 2;
+        bytes private = 3;
+        DynamicValue provider_meta = 4;
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        repeated Diagnostic diagnostics = 2;
+        bytes private = 3;
+    }
+}
+
+message PlanResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue proposed_new_state = 3;
+        DynamicValue config = 4;
+        bytes prior_private = 5;
+        DynamicValue provider_meta = 6;
+    }
+
+    message Response {
+        DynamicValue planned_state = 1;
+        repeated AttributePath requires_replace = 2;
+        bytes planned_private = 3;
+        repeated Diagnostic diagnostics = 4;
+    }
+}
+
+message ApplyResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue planned_state = 3;
+        DynamicValue config = 4;
+        bytes planned_private = 5;
+        DynamicValue provider_meta = 6;
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        bytes private = 2;
+        repeated Diagnostic diagnostics = 3;
+    }
+}
+
+message ImportResourceState {
+    message Request {
+        string type_name = 1;
+        string id = 2;
+    }
+
+    message ImportedResource {
+        string type_name = 1;
+        DynamicValue state = 2;
+        bytes private = 3;
+    }
+
+    message Response {
+        repeated ImportedResource imported_resources = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ReadDataSource {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+        DynamicValue provider_meta = 3;
+    }
+    message Response {
+        DynamicValue state = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
diff --git a/v1.5.7/docs/plugin-protocol/tfplugin6.2.proto b/v1.5.7/docs/plugin-protocol/tfplugin6.2.proto
new file mode 100644
index 0000000..8964305
--- /dev/null
+++ b/v1.5.7/docs/plugin-protocol/tfplugin6.2.proto
@@ -0,0 +1,353 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Terraform Plugin RPC protocol version 6.2
+//
+// This file defines version 6.2 of the RPC protocol. To implement a plugin
+// against this protocol, copy this definition into your own codebase and
+// use protoc to generate stubs for your target language.
+//
+// This file will not be updated. Any minor versions of protocol 6 to follow
+// should copy this file and modify the copy while maintaing backwards
+// compatibility. Breaking changes, if any are required, will come
+// in a subsequent major version with its own separate proto definition.
+//
+// Note that only the proto files included in a release tag of Terraform are
+// official protocol releases. Proto files taken from other commits may include
+// incomplete changes or features that did not make it into a final release.
+// In all reasonable cases, plugin developers should take the proto file from
+// the tag of the most recent release of Terraform, and not from the main
+// branch or any other development branch.
+//
+syntax = "proto3";
+option go_package = "github.com/hashicorp/terraform/internal/tfplugin6";
+
+package tfplugin6;
+
+// DynamicValue is an opaque encoding of terraform data, with the field name
+// indicating the encoding scheme used.
+message DynamicValue {
+    bytes msgpack = 1;
+    bytes json = 2;
+}
+
+message Diagnostic {
+    enum Severity {
+        INVALID = 0;
+        ERROR = 1;
+        WARNING = 2;
+    }
+    Severity severity = 1;
+    string summary = 2;
+    string detail = 3;
+    AttributePath attribute = 4;
+}
+
+message AttributePath {
+    message Step {
+        oneof selector {
+            // Set "attribute_name" to represent looking up an attribute
+            // in the current object value.
+            string attribute_name = 1;
+            // Set "element_key_*" to represent looking up an element in
+            // an indexable collection type.
+            string element_key_string = 2;
+            int64 element_key_int = 3;
+        }
+    }
+    repeated Step steps = 1;
+}
+
+message StopProvider {
+    message Request {
+    }
+    message Response {
+        string Error = 1;
+    }
+}
+
+// RawState holds the stored state for a resource to be upgraded by the
+// provider. It can be in one of two formats, the current json encoded format
+// in bytes, or the legacy flatmap format as a map of strings.
+message RawState {
+    bytes json = 1;
+    map<string, string> flatmap = 2;
+}
+
+enum StringKind {
+    PLAIN = 0;
+    MARKDOWN = 1;
+}
+
+// Schema is the configuration schema for a Resource or Provider.
+message Schema {
+    message Block {
+        int64 version = 1;
+        repeated Attribute attributes = 2;
+        repeated NestedBlock block_types = 3;
+        string description = 4;
+        StringKind description_kind = 5;
+        bool deprecated = 6;
+    }
+
+    message Attribute {
+        string name = 1;
+        bytes type = 2;
+        Object nested_type = 10;
+        string description = 3;
+        bool required = 4;
+        bool optional = 5;
+        bool computed = 6;
+        bool sensitive = 7;
+        StringKind description_kind = 8;
+        bool deprecated = 9;
+    }
+
+    message NestedBlock {
+        enum NestingMode {
+            INVALID = 0;
+            SINGLE = 1;
+            LIST = 2;
+            SET = 3;
+            MAP = 4;
+            GROUP = 5;
+        }
+
+        string type_name = 1;
+        Block block = 2;
+        NestingMode nesting = 3;
+        int64 min_items = 4;
+        int64 max_items = 5;
+    }
+
+    message Object {
+        enum NestingMode {
+            INVALID = 0;
+            SINGLE = 1;
+            LIST = 2;
+            SET = 3;
+            MAP = 4;
+        }
+
+        repeated Attribute attributes = 1;
+        NestingMode nesting = 3;
+
+        // MinItems and MaxItems were never used in the protocol, and have no
+        // effect on validation.
+        int64 min_items = 4 [deprecated = true];
+        int64 max_items = 5 [deprecated = true];
+    }
+
+    // The version of the schema.
+    // Schemas are versioned, so that providers can upgrade a saved resource
+    // state when the schema is changed.
+    int64 version = 1;
+
+    // Block is the top level configuration block for this schema.
+    Block block = 2;
+}
+
+service Provider {
+    //////// Information about what a provider supports/expects
+    rpc GetProviderSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
+    rpc ValidateProviderConfig(ValidateProviderConfig.Request) returns (ValidateProviderConfig.Response);
+    rpc ValidateResourceConfig(ValidateResourceConfig.Request) returns (ValidateResourceConfig.Response);
+    rpc ValidateDataResourceConfig(ValidateDataResourceConfig.Request) returns (ValidateDataResourceConfig.Response);
+    rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
+
+    //////// One-time initialization, called before other functions below
+    rpc ConfigureProvider(ConfigureProvider.Request) returns (ConfigureProvider.Response);
+
+    //////// Managed Resource Lifecycle
+    rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
+    rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
+    rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
+    rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
+
+    rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
+
+    //////// Graceful Shutdown
+    rpc StopProvider(StopProvider.Request) returns (StopProvider.Response);
+}
+
+message GetProviderSchema {
+    message Request {
+    }
+    message Response {
+        Schema provider = 1;
+        map<string, Schema> resource_schemas = 2;
+        map<string, Schema> data_source_schemas = 3;
+        repeated Diagnostic diagnostics = 4;
+        Schema provider_meta = 5;
+    }
+}
+
+message ValidateProviderConfig {
+    message Request {
+        DynamicValue config = 1;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message UpgradeResourceState {
+    message Request {
+        string type_name = 1;
+
+        // version is the schema_version number recorded in the state file
+        int64 version = 2;
+
+        // raw_state is the raw states as stored for the resource.  Core does
+        // not have access to the schema of prior_version, so it's the
+        // provider's responsibility to interpret this value using the
+        // appropriate older schema. The raw_state will be the json encoded
+        // state, or a legacy flat-mapped format.
+        RawState raw_state = 3;
+    }
+    message Response {
+        // new_state is a msgpack-encoded data structure that, when interpreted with
+        // the _current_ schema for this resource type, is functionally equivalent to
+        // that which was given in prior_state_raw.
+        DynamicValue upgraded_state = 1;
+
+        // diagnostics describes any errors encountered during migration that could not
+        // be safely resolved, and warnings about any possibly-risky assumptions made
+        // in the upgrade process.
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ValidateResourceConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ValidateDataResourceConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ConfigureProvider {
+    message Request {
+        string terraform_version = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ReadResource {
+    message Request {
+        string type_name = 1;
+        DynamicValue current_state = 2;
+        bytes private = 3;
+        DynamicValue provider_meta = 4;
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        repeated Diagnostic diagnostics = 2;
+        bytes private = 3;
+    }
+}
+
+message PlanResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue proposed_new_state = 3;
+        DynamicValue config = 4;
+        bytes prior_private = 5;
+        DynamicValue provider_meta = 6;
+    }
+
+    message Response {
+        DynamicValue planned_state = 1;
+        repeated AttributePath requires_replace = 2;
+        bytes planned_private = 3;
+        repeated Diagnostic diagnostics = 4;
+
+        // This may be set only by the helper/schema "SDK" in the main Terraform
+        // repository, to request that Terraform Core >=0.12 permit additional
+        // inconsistencies that can result from the legacy SDK type system
+        // and its imprecise mapping to the >=0.12 type system.
+        // The change in behavior implied by this flag makes sense only for the
+        // specific details of the legacy SDK type system, and are not a general
+        // mechanism to avoid proper type handling in providers.
+        //
+        //     ====              DO NOT USE THIS              ====
+        //     ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+        //     ====              DO NOT USE THIS              ====
+        bool legacy_type_system = 5;
+    }
+}
+
+message ApplyResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue planned_state = 3;
+        DynamicValue config = 4;
+        bytes planned_private = 5;
+        DynamicValue provider_meta = 6;
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        bytes private = 2;
+        repeated Diagnostic diagnostics = 3;
+
+        // This may be set only by the helper/schema "SDK" in the main Terraform
+        // repository, to request that Terraform Core >=0.12 permit additional
+        // inconsistencies that can result from the legacy SDK type system
+        // and its imprecise mapping to the >=0.12 type system.
+        // The change in behavior implied by this flag makes sense only for the
+        // specific details of the legacy SDK type system, and are not a general
+        // mechanism to avoid proper type handling in providers.
+        //
+        //     ====              DO NOT USE THIS              ====
+        //     ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+        //     ====              DO NOT USE THIS              ====
+        bool legacy_type_system = 4;
+    }
+}
+
+message ImportResourceState {
+    message Request {
+        string type_name = 1;
+        string id = 2;
+    }
+
+    message ImportedResource {
+        string type_name = 1;
+        DynamicValue state = 2;
+        bytes private = 3;
+    }
+
+    message Response {
+        repeated ImportedResource imported_resources = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ReadDataSource {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+        DynamicValue provider_meta = 3;
+    }
+    message Response {
+        DynamicValue state = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
diff --git a/v1.5.7/docs/plugin-protocol/tfplugin6.3.proto b/v1.5.7/docs/plugin-protocol/tfplugin6.3.proto
new file mode 100644
index 0000000..bd385bf
--- /dev/null
+++ b/v1.5.7/docs/plugin-protocol/tfplugin6.3.proto
@@ -0,0 +1,382 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Terraform Plugin RPC protocol version 6.3
+//
+// This file defines version 6.3 of the RPC protocol. To implement a plugin
+// against this protocol, copy this definition into your own codebase and
+// use protoc to generate stubs for your target language.
+//
+// This file will not be updated. Any minor versions of protocol 6 to follow
+// should copy this file and modify the copy while maintaing backwards
+// compatibility. Breaking changes, if any are required, will come
+// in a subsequent major version with its own separate proto definition.
+//
+// Note that only the proto files included in a release tag of Terraform are
+// official protocol releases. Proto files taken from other commits may include
+// incomplete changes or features that did not make it into a final release.
+// In all reasonable cases, plugin developers should take the proto file from
+// the tag of the most recent release of Terraform, and not from the main
+// branch or any other development branch.
+//
+syntax = "proto3";
+option go_package = "github.com/hashicorp/terraform/internal/tfplugin6";
+
+package tfplugin6;
+
+// DynamicValue is an opaque encoding of terraform data, with the field name
+// indicating the encoding scheme used.
+message DynamicValue {
+    bytes msgpack = 1;
+    bytes json = 2;
+}
+
+message Diagnostic {
+    enum Severity {
+        INVALID = 0;
+        ERROR = 1;
+        WARNING = 2;
+    }
+    Severity severity = 1;
+    string summary = 2;
+    string detail = 3;
+    AttributePath attribute = 4;
+}
+
+message AttributePath {
+    message Step {
+        oneof selector {
+            // Set "attribute_name" to represent looking up an attribute
+            // in the current object value.
+            string attribute_name = 1;
+            // Set "element_key_*" to represent looking up an element in
+            // an indexable collection type.
+            string element_key_string = 2;
+            int64 element_key_int = 3;
+        }
+    }
+    repeated Step steps = 1;
+}
+
+message StopProvider {
+    message Request {
+    }
+    message Response {
+        string Error = 1;
+    }
+}
+
+// RawState holds the stored state for a resource to be upgraded by the
+// provider. It can be in one of two formats, the current json encoded format
+// in bytes, or the legacy flatmap format as a map of strings.
+message RawState {
+    bytes json = 1;
+    map<string, string> flatmap = 2;
+}
+
+enum StringKind {
+    PLAIN = 0;
+    MARKDOWN = 1;
+}
+
+// Schema is the configuration schema for a Resource or Provider.
+message Schema {
+    message Block {
+        int64 version = 1;
+        repeated Attribute attributes = 2;
+        repeated NestedBlock block_types = 3;
+        string description = 4;
+        StringKind description_kind = 5;
+        bool deprecated = 6;
+    }
+
+    message Attribute {
+        string name = 1;
+        bytes type = 2;
+        Object nested_type = 10;
+        string description = 3;
+        bool required = 4;
+        bool optional = 5;
+        bool computed = 6;
+        bool sensitive = 7;
+        StringKind description_kind = 8;
+        bool deprecated = 9;
+    }
+
+    message NestedBlock {
+        enum NestingMode {
+            INVALID = 0;
+            SINGLE = 1;
+            LIST = 2;
+            SET = 3;
+            MAP = 4;
+            GROUP = 5;
+        }
+
+        string type_name = 1;
+        Block block = 2;
+        NestingMode nesting = 3;
+        int64 min_items = 4;
+        int64 max_items = 5;
+    }
+
+    message Object {
+        enum NestingMode {
+            INVALID = 0;
+            SINGLE = 1;
+            LIST = 2;
+            SET = 3;
+            MAP = 4;
+        }
+
+        repeated Attribute attributes = 1;
+        NestingMode nesting = 3;
+
+        // MinItems and MaxItems were never used in the protocol, and have no
+        // effect on validation.
+        int64 min_items = 4 [deprecated = true];
+        int64 max_items = 5 [deprecated = true];
+    }
+
+    // The version of the schema.
+    // Schemas are versioned, so that providers can upgrade a saved resource
+    // state when the schema is changed.
+    int64 version = 1;
+
+    // Block is the top level configuration block for this schema.
+    Block block = 2;
+}
+
+service Provider {
+    //////// Information about what a provider supports/expects
+    rpc GetProviderSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response);
+    rpc ValidateProviderConfig(ValidateProviderConfig.Request) returns (ValidateProviderConfig.Response);
+    rpc ValidateResourceConfig(ValidateResourceConfig.Request) returns (ValidateResourceConfig.Response);
+    rpc ValidateDataResourceConfig(ValidateDataResourceConfig.Request) returns (ValidateDataResourceConfig.Response);
+    rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response);
+
+    //////// One-time initialization, called before other functions below
+    rpc ConfigureProvider(ConfigureProvider.Request) returns (ConfigureProvider.Response);
+
+    //////// Managed Resource Lifecycle
+    rpc ReadResource(ReadResource.Request) returns (ReadResource.Response);
+    rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response);
+    rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response);
+    rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response);
+
+    rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response);
+
+    //////// Graceful Shutdown
+    rpc StopProvider(StopProvider.Request) returns (StopProvider.Response);
+}
+
+message GetProviderSchema {
+    message Request {
+    }
+    message Response {
+        Schema provider = 1;
+        map<string, Schema> resource_schemas = 2;
+        map<string, Schema> data_source_schemas = 3;
+        repeated Diagnostic diagnostics = 4;
+        Schema provider_meta = 5;
+        ServerCapabilities server_capabilities = 6;
+    }
+
+
+    // ServerCapabilities allows providers to communicate extra information
+    // regarding supported protocol features. This is used to indicate
+    // availability of certain forward-compatible changes which may be optional
+    // in a major protocol version, but cannot be tested for directly.
+    message ServerCapabilities {
+        // The plan_destroy capability signals that a provider expects a call
+        // to PlanResourceChange when a resource is going to be destroyed.
+        bool plan_destroy = 1;
+    }
+}
+
+message ValidateProviderConfig {
+    message Request {
+        DynamicValue config = 1;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message UpgradeResourceState {
+    // Request is the message that is sent to the provider during the
+    // UpgradeResourceState RPC.
+    //
+    // This message intentionally does not include configuration data as any
+    // configuration-based or configuration-conditional changes should occur
+    // during the PlanResourceChange RPC. Additionally, the configuration is
+    // not guaranteed to exist (in the case of resource destruction), be wholly
+    // known, nor match the given prior state, which could lead to unexpected
+    // provider behaviors for practitioners.
+    message Request {
+        string type_name = 1;
+
+        // version is the schema_version number recorded in the state file
+        int64 version = 2;
+
+        // raw_state is the raw states as stored for the resource.  Core does
+        // not have access to the schema of prior_version, so it's the
+        // provider's responsibility to interpret this value using the
+        // appropriate older schema. The raw_state will be the json encoded
+        // state, or a legacy flat-mapped format.
+        RawState raw_state = 3;
+    }
+    message Response {
+        // new_state is a msgpack-encoded data structure that, when interpreted with
+        // the _current_ schema for this resource type, is functionally equivalent to
+        // that which was given in prior_state_raw.
+        DynamicValue upgraded_state = 1;
+
+        // diagnostics describes any errors encountered during migration that could not
+        // be safely resolved, and warnings about any possibly-risky assumptions made
+        // in the upgrade process.
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ValidateResourceConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ValidateDataResourceConfig {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ConfigureProvider {
+    message Request {
+        string terraform_version = 1;
+        DynamicValue config = 2;
+    }
+    message Response {
+        repeated Diagnostic diagnostics = 1;
+    }
+}
+
+message ReadResource {
+    // Request is the message that is sent to the provider during the
+    // ReadResource RPC.
+    //
+    // This message intentionally does not include configuration data as any
+    // configuration-based or configuration-conditional changes should occur
+    // during the PlanResourceChange RPC. Additionally, the configuration is
+    // not guaranteed to be wholly known nor match the given prior state, which
+    // could lead to unexpected provider behaviors for practitioners.
+    message Request {
+        string type_name = 1;
+        DynamicValue current_state = 2;
+        bytes private = 3;
+        DynamicValue provider_meta = 4;
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        repeated Diagnostic diagnostics = 2;
+        bytes private = 3;
+    }
+}
+
+message PlanResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue proposed_new_state = 3;
+        DynamicValue config = 4;
+        bytes prior_private = 5;
+        DynamicValue provider_meta = 6;
+    }
+
+    message Response {
+        DynamicValue planned_state = 1;
+        repeated AttributePath requires_replace = 2;
+        bytes planned_private = 3;
+        repeated Diagnostic diagnostics = 4;
+
+        // This may be set only by the helper/schema "SDK" in the main Terraform
+        // repository, to request that Terraform Core >=0.12 permit additional
+        // inconsistencies that can result from the legacy SDK type system
+        // and its imprecise mapping to the >=0.12 type system.
+        // The change in behavior implied by this flag makes sense only for the
+        // specific details of the legacy SDK type system, and are not a general
+        // mechanism to avoid proper type handling in providers.
+        //
+        //     ====              DO NOT USE THIS              ====
+        //     ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+        //     ====              DO NOT USE THIS              ====
+        bool legacy_type_system = 5;
+    }
+}
+
+message ApplyResourceChange {
+    message Request {
+        string type_name = 1;
+        DynamicValue prior_state = 2;
+        DynamicValue planned_state = 3;
+        DynamicValue config = 4;
+        bytes planned_private = 5;
+        DynamicValue provider_meta = 6;
+    }
+    message Response {
+        DynamicValue new_state = 1;
+        bytes private = 2;
+        repeated Diagnostic diagnostics = 3;
+
+        // This may be set only by the helper/schema "SDK" in the main Terraform
+        // repository, to request that Terraform Core >=0.12 permit additional
+        // inconsistencies that can result from the legacy SDK type system
+        // and its imprecise mapping to the >=0.12 type system.
+        // The change in behavior implied by this flag makes sense only for the
+        // specific details of the legacy SDK type system, and are not a general
+        // mechanism to avoid proper type handling in providers.
+        //
+        //     ====              DO NOT USE THIS              ====
+        //     ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+        //     ====              DO NOT USE THIS              ====
+        bool legacy_type_system = 4;
+    }
+}
+
+message ImportResourceState {
+    message Request {
+        string type_name = 1;
+        string id = 2;
+    }
+
+    message ImportedResource {
+        string type_name = 1;
+        DynamicValue state = 2;
+        bytes private = 3;
+    }
+
+    message Response {
+        repeated ImportedResource imported_resources = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
+
+message ReadDataSource {
+    message Request {
+        string type_name = 1;
+        DynamicValue config = 2;
+        DynamicValue provider_meta = 3;
+    }
+    message Response {
+        DynamicValue state = 1;
+        repeated Diagnostic diagnostics = 2;
+    }
+}
diff --git a/v1.5.7/docs/resource-instance-change-lifecycle.md b/v1.5.7/docs/resource-instance-change-lifecycle.md
new file mode 100644
index 0000000..08e5ae3
--- /dev/null
+++ b/v1.5.7/docs/resource-instance-change-lifecycle.md
@@ -0,0 +1,372 @@
+# Terraform Resource Instance Change Lifecycle
+
+This document describes the relationships between the different operations
+called on a Terraform Provider to handle a change to a resource instance.
+
+![](https://user-images.githubusercontent.com/20180/172506401-777597dc-3e6e-411d-9580-b192fd34adba.png)
+
+The resource instance operations all both consume and produce objects that
+conform to the schema of the selected resource type.
+
+The overall goal of this process is to take a **Configuration** and a
+**Previous Run State**, merge them together using resource-type-specific
+planning logic to produce a **Planned State**, and then change the remote
+system to match that planned state before finally producing the **New State**
+that will be saved in order to become the **Previous Run State** for the next
+operation.
+
+The various object values used in different parts of this process are:
+
+* **Configuration**: Represents the values the user wrote in the configuration,
+  after any automatic type conversions to match the resource type schema.
+
+    Any attributes not defined by the user appear as null in the configuration
+    object. If an argument value is derived from an unknown result of another
+    resource instance, its value in the configuration object could also be
+    unknown.
+
+* **Prior State**: The provider's representation of the current state of the
+  remote object at the time of the most recent read.
+
+* **Proposed New State**: Terraform Core uses some built-in logic to perform
+  an initial basic merger of the **Configuration** and the **Prior State**
+  which a provider may use as a starting point for its planning operation.
+
+    The built-in logic primarily deals with the expected behavior for attributes
+    marked in the schema as "computed". If an attribute is only "computed",
+    Terraform expects the value to only be chosen by the provider and it will
+    preserve any Prior State. If an attribute is marked as "computed" and
+    "optional", this means that the user may either set it or may leave it
+    unset to allow the provider to choose a value.
+
+    Terraform Core therefore constructs the proposed new state by taking the
+    attribute value from Configuration if it is non-null, and then using the
+    Prior State as a fallback otherwise, thereby helping a provider to
+    preserve its previously-chosen value for the attribute where appropriate.
+
+* **Initial Planned State** and **Final Planned State** are both descriptions
+  of what the associated remote object ought to look like after completing
+  the planned action.
+
+    There will often be parts of the object that the provider isn't yet able to
+    predict, either because they will be decided by the remote system during
+    the apply step or because they are derived from configuration values from
+    other resource instances that are themselves not yet known. The provider
+    must mark these by including unknown values in the state objects.
+
+    The distinction between the _Initial_ and _Final_ planned states is that
+    the initial one is created during Terraform Core's planning phase based
+    on a possibly-incomplete configuration, whereas the final one is created
+    during the apply step once all of the dependencies have already been
+    updated and so the configuration should then be wholly known.
+
+* **New State** is a representation of the result of whatever modifications
+  were made to the remote system by the provider during the apply step.
+
+    The new state must always be wholly known, because it represents the
+    actual state of the system, rather than a hypothetical future state.
+
+* **Previous Run State** is the same object as the **New State** from
+  the previous run of Terraform. This is exactly what the provider most
+  recently returned, and so it will not take into account any changes that
+  may have been made outside of Terraform in the meantime, and it may conform
+  to an earlier version of the resource type schema and therefore be
+  incompatible with the _current_ schema.
+
+* **Upgraded State** is derived from **Previous Run State** by using some
+  provider-specified logic to upgrade the existing data to the latest schema.
+  However, it still represents the remote system as it was at the end of the
+  last run, and so still doesn't take into account any changes that may have
+  been made outside of Terraform.
+
+* The **Import ID** and **Import Stub State** are both details of the special
+  process of importing pre-existing objects into a Terraform state, and so
+  we'll wait to discuss those in a later section on importing.
+
+
+## Provider Protocol API Functions
+
+The following sections describe the three provider API functions that are
+called to plan and apply a change, including the expectations Terraform Core
+enforces for each.
+
+For historical reasons, the original Terraform SDK is exempt from error
+messages produced when certain assumptions are violated, but violating them
+will often cause downstream errors nonetheless, because Terraform's workflow
+depends on these contracts being met.
+
+The following section uses the word "attribute" to refer to the named
+attributes described in the resource type schema. A schema may also include
+nested blocks, which contain their _own_ set of attributes; the constraints
+apply recursively to these nested attributes too.
+
+The following are the function names used in provider protocol version 6.
+Protocol version 5 has the same set of operations but uses some
+marginally-different names for them, because we used protocol version 6 as an
+opportunity to tidy up some names that had been awkward before.
+
+### ValidateResourceConfig
+
+`ValidateResourceConfig` takes the **Configuration** object alone, and
+may return error or warning diagnostics in response to its attribute values.
+
+`ValidateResourceConfig` is the provider's opportunity to apply custom
+validation rules to the schema, allowing for constraints that could not be
+expressed via schema alone.
+
+In principle a provider can make any rule it wants here, although in practice
+providers should typically avoid reporting errors for values that are unknown.
+Terraform Core will call this function multiple times at different phases
+of evaluation, and guarantees to _eventually_ call with a wholly-known
+configuration so that the provider will have an opportunity to belatedly catch
+problems related to values that are initially unknown during planning.
+
+If a provider intends to choose a default value for a particular
+optional+computed attribute when left as null in the configuration, the
+provider _must_ tolerate that attribute being unknown in the configuration in
+order to get an opportunity to choose the default value during the later
+plan or apply phase.
+
+The validation step does not produce a new object itself and so it cannot
+modify the user's supplied configuration.
+
+### PlanResourceChange
+
+The purpose of `PlanResourceChange` is to predict the approximate effect of
+a subsequent apply operation, allowing Terraform to render the plan for the
+user and to propagate the predictable subset of results downstream through
+expressions in the configuration.
+
+This operation can base its decision on any combination of **Configuration**,
+**Prior State**, and **Proposed New State**, as long as its result fits the
+following constraints:
+
+* Any attribute that was non-null in the configuration must either preserve
+  the exact configuration value or return the corresponding attribute value
+  from the prior state. (Do the latter if you determine that the change is not
+  functionally significant, such as if the value is a JSON string that has
+  changed only in the positioning of whitespace.)
+
+* Any attribute that is marked as computed in the schema _and_ is null in the
+  configuration may be set by the provider to any arbitrary value of the
+  expected type.
+
+* If a computed attribute has any _known_ value in the planned new state, the
+  provider will be required to ensure that it is unchanged in the new state
+  returned by `ApplyResourceChange`, or return an error explaining why it
+  changed. Set an attribute to an unknown value to indicate that its final
+  result will be determined during `ApplyResourceChange`.
+
+`PlanResourceChange` is actually called twice per run for each resource type.
+
+The first call is during the planning phase, before Terraform prints out a
+diff to the user for confirmation. Because no changes at all have been applied
+at that point, the given **Configuration** may contain unknown values as
+placeholders for the results of expressions that derive from unknown values
+of other resource instances. The result of this initial call is the
+**Initial Planned State**.
+
+If the user accepts the plan, Terraform will call `PlanResourceChange` a
+second time during the apply step, and that call is guaranteed to have a
+wholly-known **Configuration** with any values from upstream dependencies
+taken into account already. The result of this second call is the
+**Final Planned State**.
+
+Terraform Core compares the final with the initial planned state, enforcing
+the following additional constraints along with those listed above:
+
+* Any attribute that had a known value in the **Initial Planned State** must
+  have an identical value in the **Final Planned State**.
+
+* Any attribute that had an unknown value in the **Initial Planned State** may
+  either remain unknown in the second _or_ take on any known value that
+  conforms to the unknown value's type constraint.
+
+The **Final Planned State** is what passes to `ApplyResourceChange`, as
+described in the following section.
+
+### ApplyResourceChange
+
+The `ApplyResourceChange` function is responsible for making calls into the
+remote system to make remote objects match the **Final Planned State**. During
+that operation, the provider should decide on final values for any attributes
+that were left unknown in the **Final Planned State**, and thus produce the
+**New State** object.
+
+`ApplyResourceChange` also receives the **Prior State** so that it can use it
+to potentially implement more "surgical" changes to particular parts of
+the remote objects by detecting portions that are unchanged, in cases where the
+remote API supports partial-update operations.
+
+The **New State** object returned from the provider must meet the following
+constraints:
+
+* Any attribute that had a known value in the **Final Planned State** must have
+  an identical value in the new state. In particular, if the remote API
+  returned a different serialization of the same value then the provider must
+  preserve the form the user wrote in the configuration, and _must not_ return
+  the normalized form produced by the provider.
+
+* Any attribute that had an unknown value in the **Final Planned State** must
+  take on a known value whose type conforms to the type constraint of the
+  unknown value. No unknown values are permitted in the **New State**.
+
+After calling `ApplyResourceChange` for each resource instance in the plan,
+and dealing with any other bookkeeping to return the results to the user,
+a single Terraform run is complete. Terraform Core saves the **New State**
+in a state snapshot for the entire configuration, so it'll be preserved for
+use on the next run.
+
+When the user subsequently runs Terraform again, the **New State** becomes
+the **Previous Run State** verbatim, and passes into `UpgradeResourceState`.
+
+### UpgradeResourceState
+
+Because the state values for a particular resource instance persist in a
+saved state snapshot from one run to the next, Terraform Core must deal with
+the possibility that the user has upgraded to a newer version of the provider
+since the last run, and that the new provider version has an incompatible
+schema for the relevant resource type.
+
+Terraform Core therefore begins by calling `UpgradeResourceState` and passing
+the **Previous Run State** in a _raw_ form, which in current protocol versions
+is the raw JSON data structure as was stored in the state snapshot. Terraform
+Core doesn't have access to the previous schema versions for a provider's
+resource types, so the provider itself must handle the data decoding in this
+upgrade function.
+
+The provider can then use whatever logic is appropriate to update the shape
+of the data to conform to the current schema for the resource type. Although
+Terraform Core has no way to enforce it, a provider should only change the
+shape of the data structure and should _not_ change the meaning of the data.
+In particular, it should not try to update the state data to capture any
+changes made to the corresponding remote object outside of Terraform.
+
+This function then returns the **Upgraded State**, which captures the same
+information as the **Previous Run State** but does so in a way that conforms
+to the current version of the resource type schema, which therefore allows
+Terraform Core to interact with the data fully for subsequent steps.
+
+### ReadResource
+
+Although Terraform typically expects to have exclusive control over any remote
+object that is bound to a resource instance, in practice users may make changes
+to those objects outside of Terraform, causing Terraform's records of the
+object to become stale.
+
+The `ReadResource` function asks the provider to make a best effort to detect
+any such external changes and describe them so that Terraform Core can use
+an up-to-date **Prior State** as the input to the next `PlanResourceChange`
+call.
+
+This is always a best effort operation because there are various reasons why
+a provider might not be able to detect certain changes. For example:
+* Some remote objects have write-only attributes, which means that there is
+  no way to determine what value is currently stored in the remote system.
+* There may be new features of the underlying API which the current provider
+  version doesn't know how to ask about.
+
+Terraform Core expects a provider to carefully distinguish between the
+following two situations for each attribute:
+* **Normalization**: the remote API has returned some data in a different form
+  than was recorded in the **Previous Run State**, but the meaning is unchanged.
+
+    In this case, the provider should return the exact value from the
+    **Previous Run State**, thereby preserving the value as it was written by
+    the user in the configuration and thus avoiding unwanted cascading changes to
+    elsewhere in the configuration.
+* **Drift**: the remote API returned data that is materially different from
+  what was recorded in the **Previous Run State**, meaning that the remote
+  system's behavior no longer matches what the configuration previously
+  requested.
+
+    In this case, the provider should return the value from the remote system,
+    thereby discarding the value from the **Previous Run State**. When a
+    provider does this, Terraform _may_ report it to the user as a change
+    made outside of Terraform, if Terraform Core determined that the detected
+    change was a possible cause of another planned action for a downstream
+    resource instance.
+
+This operation returns the **Prior State** to use for the next call to
+`PlanResourceChange`, thus completing the circle and beginning this process
+over again.
+
+## Handling of Nested Blocks in Configuration
+
+Nested blocks are a configuration-only construct and so the number of blocks
+cannot be changed on the fly during planning or during apply: each block
+represented in the configuration must have a corresponding nested object in
+the planned new state and new state, or Terraform Core will raise an error.
+
+If a provider wishes to report about new instances of the sub-object type
+represented by nested blocks that are created implicitly during the apply
+operation -- for example, if a compute instance gets a default network
+interface created when none are explicitly specified -- this must be done via
+separate "computed" attributes alongside the nested blocks. This could be list
+or map of objects that includes a mixture of the objects described by the
+nested blocks in the configuration and any additional objects created implicitly
+by the remote system.
+
+Provider protocol version 6 introduced the new idea of structural-typed
+attributes, which are a hybrid of attribute-style syntax but nested-block-style
+interpretation. For providers that use structural-typed attributes, they must
+follow the same rules as for a nested block type of the same nesting mode.
+
+## Import Behavior
+
+The main resource instance change lifecycle is concerned with objects whose
+entire lifecycle is driven through Terraform, including the initial creation
+of the object.
+
+As an aid to those who are adopting Terraform as a replacement for existing
+processes or software, Terraform also supports adopting pre-existing objects
+to bring them under Terraform's management without needing to recreate them
+first.
+
+When using this facility, the user provides the address of the resource
+instance they wish to bind the existing object to, and a string representation
+of the identifier of the existing object to be imported in a syntax defined
+by the provider on a per-resource-type basis, which we'll call the
+**Import ID**.
+
+The import process trades the user's **Import ID** for a special
+**Import Stub State**, which behaves as a placeholder for the
+**Previous Run State** pretending as if a previous Terraform run is what had
+created the object.
+
+### ImportResourceState
+
+The `ImportResourceState` operation takes the user's given **Import ID** and
+uses it to verify that the given object exists and, if so, to retrieve enough
+data about it to produce the **Import Stub State**.
+
+Terraform Core will always pass the returned **Import Stub State** to the
+normal `ReadResource` operation after `ImportResourceState` returns it, so
+in practice the provider may populate only the minimal subset of attributes
+that `ReadResource` will need to do its work, letting the normal function
+deal with populating the rest of the data to match what is currently set in
+the remote system.
+
+For the same reasons that `ReadResource` is only a _best effort_ at detecting
+changes outside of Terraform, a provider may not be able to fully support
+importing for all resource types. In that case, the provider developer must
+choose between the following options:
+
+* Perform only a partial import: the provider may choose to leave certain
+  attributes set to `null` in the **Prior State** after both
+  `ImportResourceState` and the subsequent `ReadResource` have completed.
+
+    In this case, the user can provide the missing value in the configuration
+    and thus cause the next `PlanResourceChange` to plan to update that value
+    to match the configuration. The provider's `PlanResourceChange` function
+    must be ready to deal with the attribute being `null` in the
+    **Prior State** and handle that appropriately.
+* Return an error explaining why importing isn't possible.
+
+    This is a last resort because of course it will then leave the user unable
+    to bring the existing object under Terraform's management. However, if a
+    particular object's design doesn't suit importing then it can be a better
+    user experience to be clear and honest that the user must replace the object
+    as part of adopting Terraform, rather than to perform an import that will
+    leave the object in a situation where Terraform cannot meaningfully manage
+    it.
diff --git a/v1.5.7/docs/unicode.md b/v1.5.7/docs/unicode.md
new file mode 100644
index 0000000..efcb442
--- /dev/null
+++ b/v1.5.7/docs/unicode.md
@@ -0,0 +1,142 @@
+# How Terraform Uses Unicode
+
+The Terraform language uses the Unicode standards as the basis of various
+different features. The Unicode Consortium publishes new versions of those
+standards periodically, and we aim to adopt those new versions in new
+minor releases of Terraform in order to support additional characters added
+in those new versions.
+
+Unfortunately due to those features being implemented by relying on a number
+of external libraries, adopting a new version of Unicode is not as simple as
+just updating a version number somewhere. This document aims to describe the
+various steps required to adopt a new version of Unicode in Terraform.
+
+We typically aim to be consistent across all of these dependencies as to which
+major version of Unicode we currently conform to. The usual initial driver
+for a Unicode upgrade is switching to new version of the Go runtime library
+which itself uses a new version of Unicode, because Go itself does not provide
+any way to select Unicode versions independently from Go versions. Therefore
+we typically upgrade to a new Unicode version only in conjunction with
+upgrading to a new Go version.
+
+## Unicode tables in the Go standard library
+
+Several Terraform language features are implemented in terms of functions in
+[the Go `strings` package](https://pkg.go.dev/strings),
+[the Go `unicode` package](https://pkg.go.dev/unicode), and other supporting
+packages in the Go standard library.
+
+The Go team maintains the Go standard library features to support a particular
+Unicode version for each Go version. The specific Unicode version for a
+particular Go version is available in
+[`unicode.Version`](https://pkg.go.dev/unicode#Version).
+
+We adopt a new version of Go by editing the `.go-version` file in the root
+of this repository. Although it's typically possible to build Terraform with
+other versions of Go, that file documents the version we intend to use for
+official releases and thus the primary version we use for development and
+testing. Adopting a new Go version typically also implies other behavior
+changes inherited from the Go standard library, so it's important to review the
+relevant version changelog(s) to note any behavior changes we'll need to pass
+on to our own users via the Terraform changelog.
+
+The other subsystems described below should always be set up to match
+`unicode.Version`. In some cases those libraries automatically try to align
+themselves with `unicode.Version` and generate an error if they cannot, but
+that isn't true of all of them.
+
+## Unicode Identifier Rules in HCL
+
+_Identifier and Pattern Syntax_ (TF31) is a Unicode standards annex which
+describe a set of rules for tokenizing "identifiers", such as variable names
+in a programming language.
+
+HCL uses a superset of that specification for its own identifier tokenization
+rules, and so it includes some code derived from the TF31 data tables that
+describe which characters belong to the "ID_Start" and "ID_Continue" classes.
+
+Since Terraform is the primary user of HCL, it's typically Terraform's adoption
+of a new Unicode version which drives HCL to adopt one. To update the Unicode
+tables to a new version:
+* Edit `hclsyntax/generate.go`'s line which runs `unicode2ragel.rb` to specify
+  the URL of the `DerivedCoreProperties.txt` data file for the intended Unicode
+  version.
+* Run `go generate ./hclsyntax` to run the generation code to update both
+  `unicode_derived.rl` and, indirectly, `scan_tokens.go`. (You will need both
+  a Ruby interpreter and the Ragel state machine compiler on your system in
+  order to complete this step.)
+* Run all the tests to check for regressions: `go test ./...`
+* If all looks good, commit all of the changes and open a PR to HCL.
+* Once that PR is merged and released, update Terraform to use the new version
+  of HCL.
+
+## Unicode Text Segmentation
+
+_Text Segmentation_ (TR29) is a Unicode standards annex which describes
+algorithms for breaking strings into smaller units such as sentences, words,
+and grapheme clusters.
+
+Several Terraform language features make use of the _grapheme cluster_
+algorithm in particular, because it provides a practical definition of
+individual visible characters, taking into account combining sequences such
+as Latin letters with separate diacritics or Emoji characters with gender
+presentation and skin tone modifiers.
+
+The text segmentation algorithms rely on supplementary data tables that are
+not part of the core set encoded in the Go standard library's `unicode`
+packages, and so instead we rely on the third-party module
+[`github.com/apparentlymart/go-textseg`](http://pkg.go.dev/github.com/apparentlymart/go-textseg)
+to provide those tables and a Go implementation of the grapheme cluster
+segmentation algorithm in terms of the tables.
+
+The `go-textseg` library is designed to allow calling programs to potentially
+support multiple Unicode versions at once, by offering a separate module major
+version for each Unicode major version. For example, the full module path for
+the Unicode 13 implementation is `github.com/apparentlymart/go-textseg/v13`.
+
+If that external library doesn't yet have support for the Unicode version we
+intend to adopt then we'll first need to open a pull request to contribute
+new language support. The details of how to do this will unfortunately vary
+depending on how significantly the Text Segmentation annex has changed since
+the most recently-supported Unicode version, but in many cases it can be
+just a matter of editing that library's `make_tables.go`, `make_test_tables.go`,
+and `generate.go` files to point to the URLs where the Unicode consortium
+published new tables and then run `go generate` to rebuild the files derived
+from those data sources. As long as the new Unicode version has only changed
+the data tables and not also changed the algorithm, often no further changes
+are needed.
+
+Once a new Unicode version is included, the maintainer of that library will
+typically publish a new major version that we can depend on. Two different
+codebases included in Terraform all depend directly on the `go-textseg` module
+for parts of their functionality:
+
+* [`hashicorp/hcl`](https://github.com/hashicorp/hcl) uses text
+  segmentation as part of producing visual column offsets in source ranges
+  returned by the tokenizer and parser. Terraform in turn uses that library
+  for the underlying syntax of the Terraform language, and so it passes on
+  those source ranges to the end-user as part of diagnostic messages.
+* The third-party module [`github.com/zclconf/go-cty`](https://github.com/zclconf/go-cty)
+  provides several of the Terraform language built in functions, including
+  functions like `substr` and `length` which need to count grapheme clusters
+  as part of their implementation.
+
+As part of upgrading Terraform's Unicode support we therefore typically also
+open pull requests against these other codebases, and then adopt the new
+versions that produces. Terraform work often drives the adoption of new Unicode
+versions in those codebases, with other dependencies following along when they
+next upgrade.
+
+At the time of writing Terraform itself doesn't _directly_ depend on
+`go-textseg`, and so there are no specific changes required in this Terraform
+codebase aside from the `go.sum` file update that always follows from
+changes to transitive dependencies.
+
+The `go-textseg` library does have a different "auto-version" mechanism which
+selects an appropriate module version based on the current Go language version,
+but neither HCL nor cty use that because the auto-version package will not
+compile for any Go version that doesn't have a corresponding Unicode version
+explicitly recorded in that repository, and so that would be too harsh a
+constraint for libraries like HCL which have many callers, many of which don't
+care strongly about Unicode support, that may wish to upgrade Go before the
+text segmentation library has been updated.
diff --git a/v1.5.7/experiments.go b/v1.5.7/experiments.go
new file mode 100644
index 0000000..603da77
--- /dev/null
+++ b/v1.5.7/experiments.go
@@ -0,0 +1,27 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+// experimentsAllowed can be set to any non-empty string using Go linker
+// arguments in order to enable the use of experimental features for a
+// particular Terraform build:
+//
+//	go install -ldflags="-X 'main.experimentsAllowed=yes'"
+//
+// By default this variable is initialized as empty, in which case
+// experimental features are not available.
+//
+// The Terraform release process should arrange for this variable to be
+// set for alpha releases and development snapshots, but _not_ for
+// betas, release candidates, or final releases.
+//
+// (NOTE: Some experimental features predate the rule that experiments
+// are available only for alpha/dev builds, and so intentionally do not
+// make use of this setting to avoid retracting a previously-documented
+// open experiment.)
+var experimentsAllowed string
+
+func ExperimentsAllowed() bool {
+	return experimentsAllowed != ""
+}
diff --git a/v1.5.7/go.mod b/v1.5.7/go.mod
new file mode 100644
index 0000000..a119eff
--- /dev/null
+++ b/v1.5.7/go.mod
@@ -0,0 +1,193 @@
+module github.com/hashicorp/terraform
+
+require (
+	cloud.google.com/go/kms v1.6.0
+	cloud.google.com/go/storage v1.28.0
+	github.com/Azure/azure-sdk-for-go v59.2.0+incompatible
+	github.com/Azure/go-autorest/autorest v0.11.24
+	github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2
+	github.com/agext/levenshtein v1.2.3
+	github.com/aliyun/alibaba-cloud-sdk-go v1.61.1501
+	github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190103054945-8205d1f41e70
+	github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible
+	github.com/apparentlymart/go-cidr v1.1.0
+	github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0
+	github.com/apparentlymart/go-shquot v0.0.1
+	github.com/apparentlymart/go-userdirs v0.0.0-20200915174352-b0c018a67c13
+	github.com/apparentlymart/go-versions v1.0.1
+	github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2
+	github.com/aws/aws-sdk-go v1.44.122
+	github.com/bgentry/speakeasy v0.1.0
+	github.com/bmatcuk/doublestar v1.1.5
+	github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
+	github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f
+	github.com/davecgh/go-spew v1.1.1
+	github.com/dylanmei/winrmtest v0.0.0-20210303004826-fbc9ae56efb6
+	github.com/go-test/deep v1.0.3
+	github.com/golang/mock v1.6.0
+	github.com/google/go-cmp v0.5.9
+	github.com/google/uuid v1.3.0
+	github.com/hashicorp/aws-sdk-go-base v0.7.1
+	github.com/hashicorp/consul/api v1.9.1
+	github.com/hashicorp/consul/sdk v0.8.0
+	github.com/hashicorp/errwrap v1.1.0
+	github.com/hashicorp/go-azure-helpers v0.43.0
+	github.com/hashicorp/go-checkpoint v0.5.0
+	github.com/hashicorp/go-cleanhttp v0.5.2
+	github.com/hashicorp/go-getter v1.7.0
+	github.com/hashicorp/go-hclog v0.15.0
+	github.com/hashicorp/go-multierror v1.1.1
+	github.com/hashicorp/go-plugin v1.4.3
+	github.com/hashicorp/go-retryablehttp v0.7.2
+	github.com/hashicorp/go-tfe v1.26.0
+	github.com/hashicorp/go-uuid v1.0.3
+	github.com/hashicorp/go-version v1.6.0
+	github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f
+	github.com/hashicorp/hcl/v2 v2.16.2
+	github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d
+	github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c
+	github.com/hashicorp/terraform-svchost v0.1.0
+	github.com/jmespath/go-jmespath v0.4.0
+	github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
+	github.com/lib/pq v1.10.3
+	github.com/manicminer/hamilton v0.44.0
+	github.com/masterzen/winrm v0.0.0-20200615185753-c42b5136ff88
+	github.com/mattn/go-isatty v0.0.16
+	github.com/mattn/go-shellwords v1.0.4
+	github.com/mitchellh/cli v1.1.5
+	github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db
+	github.com/mitchellh/copystructure v1.2.0
+	github.com/mitchellh/go-homedir v1.1.0
+	github.com/mitchellh/go-linereader v0.0.0-20190213213312-1b945b3263eb
+	github.com/mitchellh/go-wordwrap v1.0.1
+	github.com/mitchellh/gox v1.0.1
+	github.com/mitchellh/mapstructure v1.1.2
+	github.com/mitchellh/reflectwalk v1.0.2
+	github.com/nishanths/exhaustive v0.7.11
+	github.com/packer-community/winrmcp v0.0.0-20180921211025-c76d91c1e7db
+	github.com/pkg/browser v0.0.0-20201207095918-0426ae3fba23
+	github.com/pkg/errors v0.9.1
+	github.com/posener/complete v1.2.3
+	github.com/spf13/afero v1.2.2
+	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.588
+	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sts v1.0.588
+	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tag v1.0.233
+	github.com/tencentyun/cos-go-sdk-v5 v0.7.29
+	github.com/tombuildsstuff/giovanni v0.15.1
+	github.com/xanzy/ssh-agent v0.3.1
+	github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557
+	github.com/zclconf/go-cty v1.12.2
+	github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b
+	github.com/zclconf/go-cty-yaml v1.0.3
+	golang.org/x/crypto v0.1.0
+	golang.org/x/mod v0.8.0
+	golang.org/x/net v0.7.0
+	golang.org/x/oauth2 v0.4.0
+	golang.org/x/sys v0.5.0
+	golang.org/x/term v0.5.0
+	golang.org/x/text v0.8.0
+	golang.org/x/tools v0.6.0
+	golang.org/x/tools/cmd/cover v0.1.0-deprecated
+	google.golang.org/api v0.103.0
+	google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f
+	google.golang.org/grpc v1.53.0
+	google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0
+	google.golang.org/protobuf v1.28.1
+	honnef.co/go/tools v0.4.2
+	k8s.io/api v0.23.4
+	k8s.io/apimachinery v0.23.4
+	k8s.io/client-go v0.23.4
+	k8s.io/utils v0.0.0-20211116205334-6203023598ed
+)
+
+require (
+	cloud.google.com/go v0.107.0 // indirect
+	cloud.google.com/go/compute v1.15.1 // indirect
+	cloud.google.com/go/compute/metadata v0.2.3 // indirect
+	cloud.google.com/go/iam v0.8.0 // indirect
+	github.com/Azure/go-autorest v14.2.0+incompatible // indirect
+	github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
+	github.com/Azure/go-autorest/autorest/azure/cli v0.4.4 // indirect
+	github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
+	github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
+	github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
+	github.com/Azure/go-autorest/logger v0.2.1 // indirect
+	github.com/Azure/go-autorest/tracing v0.6.0 // indirect
+	github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect
+	github.com/BurntSushi/toml v1.2.1 // indirect
+	github.com/ChrisTrenkamp/goxpath v0.0.0-20190607011252-c5096ec8773d // 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/Microsoft/go-winio v0.5.0 // indirect
+	github.com/antchfx/xmlquery v1.3.5 // indirect
+	github.com/antchfx/xpath v1.1.10 // indirect
+	github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
+	github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect
+	github.com/armon/go-radix v1.0.0 // indirect
+	github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
+	github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
+	github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d // indirect
+	github.com/creack/pty v1.1.18 // indirect
+	github.com/dimchansky/utfbom v1.1.1 // indirect
+	github.com/dylanmei/iso8601 v0.1.0 // indirect
+	github.com/fatih/color v1.13.0 // indirect
+	github.com/go-logr/logr v1.2.0 // indirect
+	github.com/gofrs/uuid v4.0.0+incompatible // indirect
+	github.com/gogo/protobuf v1.3.2 // indirect
+	github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
+	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
+	github.com/golang/protobuf v1.5.2 // indirect
+	github.com/google/go-querystring v1.1.0 // indirect
+	github.com/google/gofuzz v1.1.0 // indirect
+	github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
+	github.com/googleapis/gax-go/v2 v2.7.0 // indirect
+	github.com/googleapis/gnostic v0.5.5 // indirect
+	github.com/hashicorp/go-immutable-radix v1.0.0 // indirect
+	github.com/hashicorp/go-msgpack v0.5.4 // indirect
+	github.com/hashicorp/go-rootcerts v1.0.2 // indirect
+	github.com/hashicorp/go-safetemp v1.0.0 // indirect
+	github.com/hashicorp/go-slug v0.11.1 // indirect
+	github.com/hashicorp/golang-lru v0.5.1 // indirect
+	github.com/hashicorp/serf v0.9.5 // indirect
+	github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect
+	github.com/huandu/xstrings v1.3.3 // indirect
+	github.com/imdario/mergo v0.3.13 // indirect
+	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/klauspost/compress v1.15.11 // indirect
+	github.com/manicminer/hamilton-autorest v0.2.0 // indirect
+	github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 // indirect
+	github.com/mattn/go-colorable v0.1.13 // indirect
+	github.com/mitchellh/go-testing-interface v1.14.1 // indirect
+	github.com/mitchellh/iochan v1.0.0 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/mozillazg/go-httpheader v0.3.0 // indirect
+	github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
+	github.com/oklog/run v1.0.0 // indirect
+	github.com/satori/go.uuid v1.2.0 // indirect
+	github.com/sergi/go-diff v1.2.0 // indirect
+	github.com/shopspring/decimal v1.3.1 // indirect
+	github.com/spf13/cast v1.5.0 // indirect
+	github.com/spf13/pflag v1.0.5 // indirect
+	github.com/ulikunitz/xz v0.5.10 // indirect
+	github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect
+	github.com/vmihailenco/tagparser v0.1.1 // indirect
+	go.opencensus.io v0.24.0 // indirect
+	golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a // indirect
+	golang.org/x/time v0.3.0 // indirect
+	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
+	google.golang.org/appengine v1.6.7 // indirect
+	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
+	gopkg.in/inf.v0 v0.9.1 // indirect
+	gopkg.in/ini.v1 v1.66.2 // indirect
+	gopkg.in/yaml.v2 v2.4.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+	k8s.io/klog/v2 v2.30.0 // indirect
+	k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
+	sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
+	sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
+	sigs.k8s.io/yaml v1.2.0 // indirect
+)
+
+go 1.18
diff --git a/v1.5.7/go.sum b/v1.5.7/go.sum
new file mode 100644
index 0000000..19b4b4b
--- /dev/null
+++ b/v1.5.7/go.sum
@@ -0,0 +1,1437 @@
+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 v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
+cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
+cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
+cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
+cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
+cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
+cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
+cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
+cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
+cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
+cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
+cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
+cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
+cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
+cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
+cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=
+cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=
+cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww=
+cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I=
+cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=
+cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY=
+cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=
+cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4=
+cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4=
+cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0=
+cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ=
+cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk=
+cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o=
+cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s=
+cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0=
+cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY=
+cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw=
+cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI=
+cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0=
+cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA=
+cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY=
+cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s=
+cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM=
+cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI=
+cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY=
+cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI=
+cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
+cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
+cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
+cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
+cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
+cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
+cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU=
+cloud.google.com/go/compute v1.15.1 h1:7UGq3QknM33pw5xATlpzeoomNxsacIVvTqTTvbfajmE=
+cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA=
+cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
+cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
+cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I=
+cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4=
+cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0=
+cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs=
+cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc=
+cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM=
+cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ=
+cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo=
+cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE=
+cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I=
+cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ=
+cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo=
+cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo=
+cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ=
+cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4=
+cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0=
+cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8=
+cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU=
+cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU=
+cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y=
+cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg=
+cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk=
+cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w=
+cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk=
+cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg=
+cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM=
+cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA=
+cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o=
+cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A=
+cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0=
+cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0=
+cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc=
+cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
+cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc=
+cloud.google.com/go/iam v0.8.0 h1:E2osAkZzxI/+8pZcxVLcDtAQx/u+hZXVryUaYQ5O0Kk=
+cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE=
+cloud.google.com/go/kms v1.6.0 h1:OWRZzrPmOZUzurjI2FBGtgY2mB1WaJkqhw6oIwSj0Yg=
+cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0=
+cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic=
+cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI=
+cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8=
+cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08=
+cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs=
+cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4=
+cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w=
+cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE=
+cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM=
+cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY=
+cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s=
+cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA=
+cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o=
+cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ=
+cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU=
+cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY=
+cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34=
+cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs=
+cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg=
+cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E=
+cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU=
+cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0=
+cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA=
+cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0=
+cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
+cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4=
+cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o=
+cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk=
+cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo=
+cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg=
+cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4=
+cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg=
+cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c=
+cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y=
+cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A=
+cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4=
+cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY=
+cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s=
+cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI=
+cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA=
+cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4=
+cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0=
+cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU=
+cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU=
+cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc=
+cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs=
+cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg=
+cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM=
+cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
+cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=
+cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s=
+cloud.google.com/go/storage v1.28.0 h1:DLrIZ6xkeZX6K70fU/boWx5INJumt6f+nwwWSHXzzGY=
+cloud.google.com/go/storage v1.28.0/go.mod h1:qlgZML35PXA3zoEnIkiPLY4/TOkUleufRlu6qmcf7sI=
+cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=
+cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g=
+cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU=
+cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4=
+cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0=
+cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo=
+cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo=
+cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE=
+cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=
+cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=
+cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/Azure/azure-sdk-for-go v45.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/azure-sdk-for-go v47.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/azure-sdk-for-go v59.2.0+incompatible h1:mbxiZy1K820hQ+dI+YIO/+a0wQDYqOu18BAGe4lXjVk=
+github.com/Azure/azure-sdk-for-go v59.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
+github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest v0.11.3/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
+github.com/Azure/go-autorest/autorest v0.11.10/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
+github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
+github.com/Azure/go-autorest/autorest v0.11.24 h1:1fIGgHKqVm54KIPT+q8Zmd1QlVsmHqeUGso5qm2BqqE=
+github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc=
+github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
+github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
+github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
+github.com/Azure/go-autorest/autorest/adal v0.9.14/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
+github.com/Azure/go-autorest/autorest/adal v0.9.18 h1:kLnPsRjzZZUF3K5REu/Kc+qMQrvuza2bwSnNdhmzLfQ=
+github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=
+github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s=
+github.com/Azure/go-autorest/autorest/azure/cli v0.4.2/go.mod h1:7qkJkT+j6b+hIpzMOwPChJhTqS8VbsqqgULzMNRugoM=
+github.com/Azure/go-autorest/autorest/azure/cli v0.4.4 h1:iuooz5cZL6VRcO7DVSFYxRcouqn6bFVE/e77Wts50Zk=
+github.com/Azure/go-autorest/autorest/azure/cli v0.4.4/go.mod h1:yAQ2b6eP/CmLPnmLvxtT1ALIY3OR1oFcCqVBi8vHiTc=
+github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
+github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
+github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk=
+github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=
+github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
+github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac=
+github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
+github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
+github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
+github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
+github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
+github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28=
+github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
+github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/ChrisTrenkamp/goxpath v0.0.0-20170922090931-c385f95c6022/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4=
+github.com/ChrisTrenkamp/goxpath v0.0.0-20190607011252-c5096ec8773d h1:W1diKnDQkXxNDhghdBSbQ4LI/E1aJNTwpqPp3KtlB8w=
+github.com/ChrisTrenkamp/goxpath v0.0.0-20190607011252-c5096ec8773d/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4=
+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.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU=
+github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+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/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM=
+github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
+github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
+github.com/aliyun/alibaba-cloud-sdk-go v1.61.1501 h1:Ij3S0pNUMgHlhx3Ew8g9RNrt59EKhHYdMODGtFXJfSc=
+github.com/aliyun/alibaba-cloud-sdk-go v1.61.1501/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
+github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190103054945-8205d1f41e70 h1:FrF4uxA24DF3ARNXVbUin3wa5fDLaB1Cy8mKks/LRz4=
+github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190103054945-8205d1f41e70/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
+github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible h1:ABQ7FF+IxSFHDMOTtjCfmMDMHiCq6EsAoCV/9sFinaM=
+github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible/go.mod h1:LDQHRZylxvcg8H7wBIDfvO5g/cy4/sz1iucBlc2l3Jw=
+github.com/antchfx/xmlquery v1.3.5 h1:I7TuBRqsnfFuL11ruavGm911Awx9IqSdiU6W/ztSmVw=
+github.com/antchfx/xmlquery v1.3.5/go.mod h1:64w0Xesg2sTaawIdNqMB+7qaW/bSqkQm+ssPaCMWNnc=
+github.com/antchfx/xpath v1.1.10 h1:cJ0pOvEdN/WvYXxvRrzQH9x5QWKpzHacYO8qzCcDYAg=
+github.com/antchfx/xpath v1.1.10/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU=
+github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc=
+github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I=
+github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
+github.com/apparentlymart/go-shquot v0.0.1 h1:MGV8lwxF4zw75lN7e0MGs7o6AFYn7L6AZaExUpLh0Mo=
+github.com/apparentlymart/go-shquot v0.0.1/go.mod h1:lw58XsE5IgUXZ9h0cxnypdx31p9mPFIVEQ9P3c7MlrU=
+github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
+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/apparentlymart/go-userdirs v0.0.0-20200915174352-b0c018a67c13 h1:JtuelWqyixKApmXm3qghhZ7O96P6NKpyrlSIe8Rwnhw=
+github.com/apparentlymart/go-userdirs v0.0.0-20200915174352-b0c018a67c13/go.mod h1:7kfpUbyCdGJ9fDRCp3fopPQi5+cKNHgTE4ZuNrO71Cw=
+github.com/apparentlymart/go-versions v1.0.1 h1:ECIpSn0adcYNsBfSRwdDdz9fWlL+S/6EUd9+irwkBgU=
+github.com/apparentlymart/go-versions v1.0.1/go.mod h1:YF5j7IQtrOAOnsGkniupEA5bfCjzd7i14yu0shZavyM=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 h1:7Ip0wMmLHLRJdrloDxZfhMm0xrLXZS8+COSu2bXmEQs=
+github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
+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-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
+github.com/aws/aws-sdk-go v1.44.122 h1:p6mw01WBaNpbdP2xrisz5tIkcNwzj/HysobNoaAHjgo=
+github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
+github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA=
+github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
+github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
+github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
+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 v1.1.5 h1:2bNwBOmhyFEFcoB3tGvTD5xanq+4kyOZlB8wFYbMjkk=
+github.com/bmatcuk/doublestar v1.1.5/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
+github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
+github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d h1:t5Wuyh53qYyg9eqn4BbnlIT+vmhyww0TatL+zT3uWgI=
+github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
+github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
+github.com/creack/pty v1.1.18/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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
+github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
+github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
+github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
+github.com/dylanmei/iso8601 v0.1.0 h1:812NGQDBcqquTfH5Yeo7lwR0nzx/cKdsmf3qMjPURUI=
+github.com/dylanmei/iso8601 v0.1.0/go.mod h1:w9KhXSgIyROl1DefbMYIE7UVSIvELTbMrCfx+QkYnoQ=
+github.com/dylanmei/winrmtest v0.0.0-20210303004826-fbc9ae56efb6 h1:zWydSUQBJApHwpQ4guHi+mGyQN/8yN6xbKWdDtL3ZNM=
+github.com/dylanmei/winrmtest v0.0.0-20210303004826-fbc9ae56efb6/go.mod h1:6BLLhzn1VEiJ4veuAGhINBTrBlV889Wd+aU4auxKOww=
+github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
+github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+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.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
+github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
+github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+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/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
+github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE=
+github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
+github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
+github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
+github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
+github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
+github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
+github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
+github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
+github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
+github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+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.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
+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.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
+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.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
+github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
+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.4.1/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.1/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.3/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-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+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/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
+github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ=
+github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+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/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
+github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
+github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbezB6QkpuE6jMD2/gfzk4AftXjs=
+github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
+github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
+github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
+github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
+github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
+github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=
+github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY=
+github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ=
+github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
+github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
+github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
+github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
+github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
+github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/hashicorp/aws-sdk-go-base v0.7.1 h1:7s/aR3hFn74tYPVihzDyZe7y/+BorN70rr9ZvpV3j3o=
+github.com/hashicorp/aws-sdk-go-base v0.7.1/go.mod h1:2fRjWDv3jJBeN6mVWFHV6hFTNeFBx2gpDLQaZNxUVAY=
+github.com/hashicorp/consul/api v1.9.1 h1:SngrdG2L62qqLsUz85qcPhFZ78rPf8tcD5qjMgs6MME=
+github.com/hashicorp/consul/api v1.9.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
+github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU=
+github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
+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-azure-helpers v0.12.0/go.mod h1:Zc3v4DNeX6PDdy7NljlYpnrdac1++qNW0I4U+ofGwpg=
+github.com/hashicorp/go-azure-helpers v0.43.0 h1:larj4ZgwO3hKzA9xIOTXRW4NBpI6F3K8wpig8eikNOw=
+github.com/hashicorp/go-azure-helpers v0.43.0/go.mod h1:ofh+59GPB8g/lWI08711STfrIPSPOlXQkuMc8rovpBk=
+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-getter v1.7.0 h1:bzrYP+qu/gMrL1au7/aDvkoOVGUJpeKBgbqRHACAFDY=
+github.com/hashicorp/go-getter v1.7.0/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
+github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
+github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-hclog v0.15.0 h1:qMuK0wxsoW4D0ddCCYwPSTm4KQv1X1ke3WmPWZ0Mvsk=
+github.com/hashicorp/go-hclog v0.15.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
+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-msgpack v0.5.4 h1:SFT72YqIkOcLdWJUYcriVX7hbrZpwc/f7h8aW2NUqrA=
+github.com/hashicorp/go-msgpack v0.5.4/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.4.3 h1:DXmvivbWD5qdiBts9TpBC7BYL1Aia5sxbRgQB+v6UZM=
+github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ=
+github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
+github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0=
+github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
+github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
+github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
+github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
+github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
+github.com/hashicorp/go-slug v0.11.1 h1:c6lLdQnlhUWbS5I7hw8SvfymoFuy6EmiFDedy6ir994=
+github.com/hashicorp/go-slug v0.11.1/go.mod h1:Ib+IWBYfEfJGI1ZyXMGNbu2BU+aa3Dzu41RKLH301v4=
+github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-tfe v1.26.0 h1:aacguqCENg6Z7ttfhAxdbbY2vm/jKrntl5sUUY0h6EM=
+github.com/hashicorp/go-tfe v1.26.0/go.mod h1:1Y6nsdMuJ14lYdc1VMLl/erlthvMzUsJn+WYWaAdSc4=
+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.2/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.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-version v1.3.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 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f h1:UdxlrJz4JOnY8W+DbLISwf2B8WXEolNRA8BGCwI9jws=
+github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
+github.com/hashicorp/hcl/v2 v2.16.2 h1:mpkHZh/Tv+xet3sy3F9Ld4FyI2tUpWe9x3XtPx9f1a0=
+github.com/hashicorp/hcl/v2 v2.16.2/go.mod h1:JRmR89jycNkrrqnMmvPDMd56n1rQJ2Q6KocSLCMCXng=
+github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d h1:9ARUJJ1VVynB176G1HCwleORqCaXm/Vx0uUi0dL26I0=
+github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d/go.mod h1:Yog5+CPEM3c99L1CL2CFCYoSzgWm5vTU58idbRUaLik=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
+github.com/hashicorp/memberlist v0.2.2 h1:5+RffWKwqJ71YPu9mWsF7ZOscZmwfasdA8kbdC7AO2g=
+github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
+github.com/hashicorp/serf v0.9.5 h1:EBWvyu9tcRszt3Bxp3KNssBMP1KuHWyO51lz9+786iM=
+github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
+github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c h1:D8aRO6+mTqHfLsK/BC3j5OAoogv1WLRWzY1AaTo3rBg=
+github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c/go.mod h1:Wn3Na71knbXc1G8Lh+yu/dQWWJeFQEpDeJMtWMtlmNI=
+github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg=
+github.com/hashicorp/terraform-svchost v0.1.0 h1:0+RcgZdZYNd81Vw7tu62g9JiLLvbOigp7QtyNh6CjXk=
+github.com/hashicorp/terraform-svchost v0.1.0/go.mod h1:ut8JaH0vumgdCfJaihdcZULqkAwHdQNwNH7taIDdsZM=
+github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
+github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
+github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
+github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+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/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
+github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
+github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
+github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
+github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
+github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
+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.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c=
+github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
+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.2.1/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/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
+github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
+github.com/lib/pq v1.10.3 h1:v9QZf2Sn6AmjXtQeFpdoq/eaNtYP6IN+7lcrygsIAtg=
+github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/manicminer/hamilton v0.43.0/go.mod h1:lbVyngC+/nCWuDp8UhC6Bw+bh7jcP/E+YwqzHTmzemk=
+github.com/manicminer/hamilton v0.44.0 h1:mLb4Vxbt2dsAvOpaB7xd/5D8LaTTX6ACwVP4TmW8qwE=
+github.com/manicminer/hamilton v0.44.0/go.mod h1:lbVyngC+/nCWuDp8UhC6Bw+bh7jcP/E+YwqzHTmzemk=
+github.com/manicminer/hamilton-autorest v0.2.0 h1:dDL+t2DrQza0EfNYINYCvXISeNwVqzgVAQh+CH/19ZU=
+github.com/manicminer/hamilton-autorest v0.2.0/go.mod h1:NselDpNTImEmOc/fa41kPg6YhDt/6S95ejWbTGZ6tlg=
+github.com/masterzen/simplexml v0.0.0-20160608183007-4572e39b1ab9/go.mod h1:kCEbxUJlNDEBNbdQMkPSp6yaKcRXVI6f4ddk8Riv4bc=
+github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 h1:2ZKn+w/BJeL43sCxI2jhPLRv73oVVOjEKZjKkflyqxg=
+github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786/go.mod h1:kCEbxUJlNDEBNbdQMkPSp6yaKcRXVI6f4ddk8Riv4bc=
+github.com/masterzen/winrm v0.0.0-20200615185753-c42b5136ff88 h1:cxuVcCvCLD9yYDbRCWw0jSgh1oT6P6mv3aJDKK5o7X4=
+github.com/masterzen/winrm v0.0.0-20200615185753-c42b5136ff88/go.mod h1:a2HXwefeat3evJHxFXSayvRHpYEPJYtErl4uIzfaUqY=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+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.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.4/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 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-shellwords v1.0.4 h1:xmZZyxuP+bYKAKkA9ABYXVNJ+G/Wf3R8d8vAP3LDJJk=
+github.com/mattn/go-shellwords v1.0.4/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/miekg/dns v1.1.26 h1:gPxPSwALAeHJSjarOs00QjVdV9QoBvc1D2ujQUr5BzU=
+github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
+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/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
+github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
+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-linereader v0.0.0-20190213213312-1b945b3263eb h1:GRiLv4rgyqjqzxbhJke65IYUf4NCOOvrPOJbV/sPxkM=
+github.com/mitchellh/go-linereader v0.0.0-20190213213312-1b945b3263eb/go.mod h1:OaY7UOoTkkrX3wRwjpYRKafIkkyeD0UtweSHAWWiqQM=
+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-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.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
+github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
+github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI=
+github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4=
+github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+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/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
+github.com/mozillazg/go-httpheader v0.3.0 h1:3brX5z8HTH+0RrNA1362Rc3HsaxyWEKtGY45YrhuINM=
+github.com/mozillazg/go-httpheader v0.3.0/go.mod h1:PuT8h0pw6efvp8ZeUec1Rs7dwjK08bt6gKSReGMqtdA=
+github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/nishanths/exhaustive v0.7.11 h1:xV/WU3Vdwh5BUH4N06JNUznb6d5zhRPOnlgCrpNYNKA=
+github.com/nishanths/exhaustive v0.7.11/go.mod h1:gX+MP7DWMKJmNa1HfMozK+u04hQd3na9i0hyqf3/dOI=
+github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
+github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
+github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
+github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
+github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/packer-community/winrmcp v0.0.0-20180921211025-c76d91c1e7db h1:9uViuKtx1jrlXLBW/pMnhOfzn3iSEdLase/But/IZRU=
+github.com/packer-community/winrmcp v0.0.0-20180921211025-c76d91c1e7db/go.mod h1:f6Izs6JvFTdnRbziASagjZ2vmf55NSIkC/weStxCHqk=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pkg/browser v0.0.0-20201207095918-0426ae3fba23 h1:dofHuld+js7eKSemxqTVIo8yRlpRw+H1SdpzZxWruBc=
+github.com/pkg/browser v0.0.0-20201207095918-0426ae3fba23/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+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_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
+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/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+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.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
+github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+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/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+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.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.194/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.588 h1:DYtBXB7sVc3EOW5horg8j55cLZynhsLYhHrvQ/jXKKM=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.588/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.194/go.mod h1:yrBKWhChnDqNz1xuXdSbWXG56XawEq0G5j1lg4VwBD4=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sts v1.0.588 h1:PlkFOALQZ9BLUyX8EalATUQD5xEn1Sz34C+Rw5VSpvk=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sts v1.0.588/go.mod h1:vPvXNb+zBZVJfZCIKWcYxLpGzgScKKgiPUArobWZ+nU=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tag v1.0.233 h1:5Tbi+jyZ2MojC6GK8V6hchwtnkP2IuENUTqSisbYOlA=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tag v1.0.233/go.mod h1:sX14+NSvMjOhNFaMtP2aDy6Bss8PyFXij21gpY6+DAs=
+github.com/tencentyun/cos-go-sdk-v5 v0.7.29 h1:uwRBzc70Wgtc5iQQCowqecfRT0OpCXUOZzodZHOOEDs=
+github.com/tencentyun/cos-go-sdk-v5 v0.7.29/go.mod h1:4E4+bQ2gBVJcgEC9Cufwylio4mXOct2iu05WjgEBx1o=
+github.com/tombuildsstuff/giovanni v0.15.1 h1:CVRaLOJ7C/eercCrKIsarfJ4SZoGMdBL9Q2deFDUXco=
+github.com/tombuildsstuff/giovanni v0.15.1/go.mod h1:0TZugJPEtqzPlMpuJHYfXY6Dq2uLPrXf98D2XQSxNbA=
+github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
+github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
+github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
+github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U=
+github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
+github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY=
+github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
+github.com/xanzy/ssh-agent v0.3.1 h1:AmzO1SSWxw73zxFZPRwaMN1MohDw8UyHnmuxyceTEGo=
+github.com/xanzy/ssh-agent v0.3.1/go.mod h1:QIE4lCeL7nkC25x+yA3LBIYfwCc1TFziCtG7cBAac6w=
+github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557 h1:Jpn2j6wHkC9wJv5iMfJhKqrZJx3TahFx+7sbZ7zQdxs=
+github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/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.0/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.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
+github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
+github.com/zclconf/go-cty v1.12.2 h1:h4VH6eKXHTw60DiEJEVjh6pqVPDcoe3DuAkH/Ejs+4g=
+github.com/zclconf/go-cty v1.12.2/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA=
+github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI=
+github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
+github.com/zclconf/go-cty-yaml v1.0.3 h1:og/eOQ7lvA/WWhHGFETVWNduJM7Rjsv2RRpx1sdFMLc=
+github.com/zclconf/go-cty-yaml v1.0.3/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
+go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f/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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+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-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
+golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a h1:Jw5wfR+h9mnIYH+OtGT2im5wV1YGGDora5vTv/aa5bE=
+golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/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.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.1/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 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180811021610-c39426892332/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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/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-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/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-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/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-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/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-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
+golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
+golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
+golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
+golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
+golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
+golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
+golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
+golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
+golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
+golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M=
+golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec=
+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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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-20220601150217-0de741cfad7f/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.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/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-20191001151750-bb3f8db39f24/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-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/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-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/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-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210603125802-9665404d3644/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-20210616094352-59db8d763f22/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-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/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-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/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-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/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-20220502124256-b6088ccd6cba/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-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220624220833-87e55d714810/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.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
+golang.org/x/sys v0.5.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-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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.4/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.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
+golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
+golang.org/x/time v0.3.0/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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/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-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
+golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
+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/tools/cmd/cover v0.1.0-deprecated h1:Rwy+mWYz6loAF+LnG1jHG/JWMHRMMC2/1XX3Ejkx9lA=
+golang.org/x/tools/cmd/cover v0.1.0-deprecated/go.mod h1:hMDiIvlpN1NoVgmjLjUJE9tMHyxHjFX7RuQ+rW12mSA=
+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=
+golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
+golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
+google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
+google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
+google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
+google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
+google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
+google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
+google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
+google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
+google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
+google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
+google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
+google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
+google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
+google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
+google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
+google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
+google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
+google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
+google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
+google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
+google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
+google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
+google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
+google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
+google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g=
+google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
+google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
+google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI=
+google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
+google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
+google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
+google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70=
+google.golang.org/api v0.103.0 h1:9yuVqlu2JCvcLg9p8S3fcFLZij8EPSyvODIY1rkMizQ=
+google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0=
+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.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+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-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
+google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
+google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
+google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
+google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
+google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
+google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
+google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
+google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
+google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
+google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
+google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
+google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
+google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
+google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
+google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
+google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
+google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
+google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
+google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
+google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
+google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
+google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
+google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE=
+google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=
+google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
+google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
+google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
+google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
+google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
+google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
+google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
+google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
+google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
+google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
+google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw=
+google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
+google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
+google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U=
+google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
+google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
+google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
+google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w=
+google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+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.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
+google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
+google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
+google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
+google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
+google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
+google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
+google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
+google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
+google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
+google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
+google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
+google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE=
+google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
+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.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
+google.golang.org/protobuf v1.28.1/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/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/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
+gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+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.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 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+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-20200615113413-eeeca48fe776/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-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.4.2 h1:6qXr+R5w+ktL5UkwEbPp+fEvfyoMPche6GkOpGHZcLc=
+honnef.co/go/tools v0.4.2/go.mod h1:36ZgoUOrqOk1GxwHhyryEkq8FQWkUO2xGuSMhUCcdvA=
+k8s.io/api v0.23.4 h1:85gnfXQOWbJa1SiWGpE9EEtHs0UVvDyIsSMpEtl2D4E=
+k8s.io/api v0.23.4/go.mod h1:i77F4JfyNNrhOjZF7OwwNJS5Y1S9dpwvb9iYRYRczfI=
+k8s.io/apimachinery v0.23.4 h1:fhnuMd/xUL3Cjfl64j5ULKZ1/J9n8NuQEgNL+WXWfdM=
+k8s.io/apimachinery v0.23.4/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
+k8s.io/client-go v0.23.4 h1:YVWvPeerA2gpUudLelvsolzH7c2sFoXXR5wM/sWqNFU=
+k8s.io/client-go v0.23.4/go.mod h1:PKnIL4pqLuvYUK1WU7RLTMYKPiIh7MYShLshtRY9cj0=
+k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
+k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
+k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
+k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw=
+k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4=
+k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
+k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE=
+k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s=
+sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
+sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
+sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
diff --git a/v1.5.7/help.go b/v1.5.7/help.go
new file mode 100644
index 0000000..8d87637
--- /dev/null
+++ b/v1.5.7/help.go
@@ -0,0 +1,97 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"log"
+	"sort"
+	"strings"
+
+	"github.com/mitchellh/cli"
+)
+
+// helpFunc is a cli.HelpFunc that can be used to output the help CLI instructions for Terraform.
+func helpFunc(commands map[string]cli.CommandFactory) string {
+	// Determine the maximum key length, and classify based on type
+	var otherCommands []string
+	maxKeyLen := 0
+
+	for key := range commands {
+		if _, ok := HiddenCommands[key]; ok {
+			// We don't consider hidden commands when deciding the
+			// maximum command length.
+			continue
+		}
+
+		if len(key) > maxKeyLen {
+			maxKeyLen = len(key)
+		}
+
+		isOther := true
+		for _, candidate := range PrimaryCommands {
+			if candidate == key {
+				isOther = false
+				break
+			}
+		}
+		if isOther {
+			otherCommands = append(otherCommands, key)
+		}
+	}
+	sort.Strings(otherCommands)
+
+	// The output produced by this is included in the docs at
+	// website/source/docs/cli/commands/index.html.markdown; if you
+	// change this then consider updating that to match.
+	helpText := fmt.Sprintf(`
+Usage: terraform [global options] <subcommand> [args]
+
+The available commands for execution are listed below.
+The primary workflow commands are given first, followed by
+less common or more advanced commands.
+
+Main commands:
+%s
+All other commands:
+%s
+Global options (use these before the subcommand, if any):
+  -chdir=DIR    Switch to a different working directory before executing the
+                given subcommand.
+  -help         Show this help output, or the help for a specified subcommand.
+  -version      An alias for the "version" subcommand.
+`, listCommands(commands, PrimaryCommands, maxKeyLen), listCommands(commands, otherCommands, maxKeyLen))
+
+	return strings.TrimSpace(helpText)
+}
+
+// listCommands just lists the commands in the map with the
+// given maximum key length.
+func listCommands(allCommands map[string]cli.CommandFactory, order []string, maxKeyLen int) string {
+	var buf bytes.Buffer
+
+	for _, key := range order {
+		commandFunc, ok := allCommands[key]
+		if !ok {
+			// This suggests an inconsistency in the command table definitions
+			// in commands.go .
+			panic("command not found: " + key)
+		}
+
+		command, err := commandFunc()
+		if err != nil {
+			// This would be really weird since there's no good reason for
+			// any of our command factories to fail.
+			log.Printf("[ERR] cli: Command '%s' failed to load: %s",
+				key, err)
+			continue
+		}
+
+		key = fmt.Sprintf("%s%s", key, strings.Repeat(" ", maxKeyLen-len(key)))
+		buf.WriteString(fmt.Sprintf("  %s  %s\n", key, command.Synopsis()))
+	}
+
+	return buf.String()
+}
diff --git a/v1.5.7/internal/addrs/check.go b/v1.5.7/internal/addrs/check.go
new file mode 100644
index 0000000..4f3d516
--- /dev/null
+++ b/v1.5.7/internal/addrs/check.go
@@ -0,0 +1,134 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import "fmt"
+
+// Check is the address of a check block within a module.
+//
+// For now, checks do not support meta arguments such as "count" or "for_each"
+// so this address uniquely describes a single check within a module.
+type Check struct {
+	referenceable
+	Name string
+}
+
+func (c Check) String() string {
+	return fmt.Sprintf("check.%s", c.Name)
+}
+
+// InModule returns a ConfigCheck from the receiver and the given module
+// address.
+func (c Check) InModule(modAddr Module) ConfigCheck {
+	return ConfigCheck{
+		Module: modAddr,
+		Check:  c,
+	}
+}
+
+// Absolute returns an AbsCheck from the receiver and the given module instance
+// address.
+func (c Check) Absolute(modAddr ModuleInstance) AbsCheck {
+	return AbsCheck{
+		Module: modAddr,
+		Check:  c,
+	}
+}
+
+func (c Check) Equal(o Check) bool {
+	return c.Name == o.Name
+}
+
+func (c Check) UniqueKey() UniqueKey {
+	return c // A Check is its own UniqueKey
+}
+
+func (c Check) uniqueKeySigil() {}
+
+// ConfigCheck is an address for a check block within a configuration.
+//
+// This contains a Check address and a Module address, meaning this describes
+// a check block within the entire configuration.
+type ConfigCheck struct {
+	Module Module
+	Check  Check
+}
+
+var _ ConfigCheckable = ConfigCheck{}
+
+func (c ConfigCheck) UniqueKey() UniqueKey {
+	return configCheckUniqueKey(c.String())
+}
+
+func (c ConfigCheck) configCheckableSigil() {}
+
+func (c ConfigCheck) CheckableKind() CheckableKind {
+	return CheckableCheck
+}
+
+func (c ConfigCheck) String() string {
+	if len(c.Module) == 0 {
+		return c.Check.String()
+	}
+	return fmt.Sprintf("%s.%s", c.Module, c.Check)
+}
+
+// AbsCheck is an absolute address for a check block under a given module path.
+//
+// This contains an actual ModuleInstance address (compared to the Module within
+// a ConfigCheck), meaning this uniquely describes a check block within the
+// entire configuration after any "count" or "foreach" meta arguments have been
+// evaluated on the containing module.
+type AbsCheck struct {
+	Module ModuleInstance
+	Check  Check
+}
+
+var _ Checkable = AbsCheck{}
+
+func (c AbsCheck) UniqueKey() UniqueKey {
+	return absCheckUniqueKey(c.String())
+}
+
+func (c AbsCheck) checkableSigil() {}
+
+// CheckRule returns an address for a given rule type within the check block.
+//
+// There will be at most one CheckDataResource rule within a check block (with
+// an index of 0). There will be at least one, but potentially many,
+// CheckAssertion rules within a check block.
+func (c AbsCheck) CheckRule(typ CheckRuleType, i int) CheckRule {
+	return CheckRule{
+		Container: c,
+		Type:      typ,
+		Index:     i,
+	}
+}
+
+// ConfigCheckable returns the ConfigCheck address for this absolute reference.
+func (c AbsCheck) ConfigCheckable() ConfigCheckable {
+	return ConfigCheck{
+		Module: c.Module.Module(),
+		Check:  c.Check,
+	}
+}
+
+func (c AbsCheck) CheckableKind() CheckableKind {
+	return CheckableCheck
+}
+
+func (c AbsCheck) String() string {
+	if len(c.Module) == 0 {
+		return c.Check.String()
+	}
+	return fmt.Sprintf("%s.%s", c.Module, c.Check)
+}
+
+type configCheckUniqueKey string
+
+func (k configCheckUniqueKey) uniqueKeySigil() {}
+
+type absCheckUniqueKey string
+
+func (k absCheckUniqueKey) uniqueKeySigil() {}
diff --git a/v1.5.7/internal/addrs/check_rule.go b/v1.5.7/internal/addrs/check_rule.go
new file mode 100644
index 0000000..6d4c1db
--- /dev/null
+++ b/v1.5.7/internal/addrs/check_rule.go
@@ -0,0 +1,108 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+)
+
+// CheckRule is the address of a check rule within a checkable object.
+//
+// This represents the check rule globally within a configuration, and is used
+// during graph evaluation to identify a condition result object to update with
+// the result of check rule evaluation.
+//
+// The check address is not distinct from resource traversals, and check rule
+// values are not intended to be available to the language, so the address is
+// not Referenceable.
+//
+// Note also that the check address is only relevant within the scope of a run,
+// as reordering check blocks between runs will result in their addresses
+// changing. CheckRule is therefore for internal use only and should not be
+// exposed in durable artifacts such as state snapshots.
+type CheckRule struct {
+	Container Checkable
+	Type      CheckRuleType
+	Index     int
+}
+
+func NewCheckRule(container Checkable, typ CheckRuleType, index int) CheckRule {
+	return CheckRule{
+		Container: container,
+		Type:      typ,
+		Index:     index,
+	}
+}
+
+func (c CheckRule) String() string {
+	container := c.Container.String()
+	switch c.Type {
+	case ResourcePrecondition:
+		return fmt.Sprintf("%s.precondition[%d]", container, c.Index)
+	case ResourcePostcondition:
+		return fmt.Sprintf("%s.postcondition[%d]", container, c.Index)
+	case OutputPrecondition:
+		return fmt.Sprintf("%s.precondition[%d]", container, c.Index)
+	default:
+		// This should not happen
+		return fmt.Sprintf("%s.condition[%d]", container, c.Index)
+	}
+}
+
+func (c CheckRule) UniqueKey() UniqueKey {
+	return checkRuleKey{
+		ContainerKey: c.Container.UniqueKey(),
+		Type:         c.Type,
+		Index:        c.Index,
+	}
+}
+
+type checkRuleKey struct {
+	ContainerKey UniqueKey
+	Type         CheckRuleType
+	Index        int
+}
+
+func (k checkRuleKey) uniqueKeySigil() {}
+
+// CheckRuleType describes a category of check. We use this only to establish
+// uniqueness for Check values, and do not expose this concept of "check types"
+// (which is subject to change in future) in any durable artifacts such as
+// state snapshots.
+//
+// (See [CheckableKind] for an enumeration that we _do_ use externally, to
+// describe the type of object being checked rather than the type of the check
+// itself.)
+type CheckRuleType int
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=CheckRuleType check_rule.go
+
+const (
+	InvalidCondition      CheckRuleType = 0
+	ResourcePrecondition  CheckRuleType = 1
+	ResourcePostcondition CheckRuleType = 2
+	OutputPrecondition    CheckRuleType = 3
+	CheckDataResource     CheckRuleType = 4
+	CheckAssertion        CheckRuleType = 5
+)
+
+// Description returns a human-readable description of the check type. This is
+// presented in the user interface through a diagnostic summary.
+func (c CheckRuleType) Description() string {
+	switch c {
+	case ResourcePrecondition:
+		return "Resource precondition"
+	case ResourcePostcondition:
+		return "Resource postcondition"
+	case OutputPrecondition:
+		return "Module output value precondition"
+	case CheckDataResource:
+		return "Check block data resource"
+	case CheckAssertion:
+		return "Check block assertion"
+	default:
+		// This should not happen
+		return "Condition"
+	}
+}
diff --git a/v1.5.7/internal/addrs/checkable.go b/v1.5.7/internal/addrs/checkable.go
new file mode 100644
index 0000000..55d4109
--- /dev/null
+++ b/v1.5.7/internal/addrs/checkable.go
@@ -0,0 +1,185 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+
+	"golang.org/x/text/cases"
+	"golang.org/x/text/language"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Checkable is an interface implemented by all address types that can contain
+// condition blocks.
+type Checkable interface {
+	UniqueKeyer
+
+	checkableSigil()
+
+	// CheckRule returns the address of an individual check rule of a specified
+	// type and index within this checkable container.
+	CheckRule(CheckRuleType, int) CheckRule
+
+	// ConfigCheckable returns the address of the configuration construct that
+	// this Checkable belongs to.
+	//
+	// Checkable objects can potentially be dynamically declared during a
+	// plan operation using constructs like resource for_each, and so
+	// ConfigCheckable gives us a way to talk about the static containers
+	// those dynamic objects belong to, in case we wish to group together
+	// dynamic checkable objects into their static checkable for reporting
+	// purposes.
+	ConfigCheckable() ConfigCheckable
+
+	CheckableKind() CheckableKind
+	String() string
+}
+
+var (
+	_ Checkable = AbsResourceInstance{}
+	_ Checkable = AbsOutputValue{}
+)
+
+// CheckableKind describes the different kinds of checkable objects.
+type CheckableKind rune
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=CheckableKind checkable.go
+
+const (
+	CheckableKindInvalid CheckableKind = 0
+	CheckableResource    CheckableKind = 'R'
+	CheckableOutputValue CheckableKind = 'O'
+	CheckableCheck       CheckableKind = 'C'
+)
+
+// ConfigCheckable is an interfaces implemented by address types that represent
+// configuration constructs that can have Checkable addresses associated with
+// them.
+//
+// This address type therefore in a sense represents a container for zero or
+// more checkable objects all declared by the same configuration construct,
+// so that we can talk about these groups of checkable objects before we're
+// ready to decide how many checkable objects belong to each one.
+type ConfigCheckable interface {
+	UniqueKeyer
+
+	configCheckableSigil()
+
+	CheckableKind() CheckableKind
+	String() string
+}
+
+var (
+	_ ConfigCheckable = ConfigResource{}
+	_ ConfigCheckable = ConfigOutputValue{}
+)
+
+// ParseCheckableStr attempts to parse the given string as a Checkable address
+// of the given kind.
+//
+// This should be the opposite of Checkable.String for any Checkable address
+// type, as long as "kind" is set to the value returned by the address's
+// CheckableKind method.
+//
+// We do not typically expect users to write out checkable addresses as input,
+// but we use them as part of some of our wire formats for persisting check
+// results between runs.
+func ParseCheckableStr(kind CheckableKind, src string) (Checkable, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(src), "", hcl.InitialPos)
+	diags = diags.Append(parseDiags)
+	if parseDiags.HasErrors() {
+		return nil, diags
+	}
+
+	path, remain, diags := parseModuleInstancePrefix(traversal)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	if remain.IsRelative() {
+		// (relative means that there's either nothing left or what's next isn't an identifier)
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid checkable address",
+			Detail:   "Module path must be followed by either a resource instance address or an output value address.",
+			Subject:  remain.SourceRange().Ptr(),
+		})
+		return nil, diags
+	}
+
+	getCheckableName := func(keyword string, descriptor string) (string, tfdiags.Diagnostics) {
+		var diags tfdiags.Diagnostics
+		var name string
+
+		if len(remain) != 2 {
+			diags = diags.Append(hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid checkable address",
+				Detail:   fmt.Sprintf("%s address must have only one attribute part after the keyword '%s', giving the name of the %s.", cases.Title(language.English, cases.NoLower).String(keyword), keyword, descriptor),
+				Subject:  remain.SourceRange().Ptr(),
+			})
+		}
+
+		if remain.RootName() != keyword {
+			diags = diags.Append(hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid checkable address",
+				Detail:   fmt.Sprintf("%s address must follow the module address with the keyword '%s'.", cases.Title(language.English, cases.NoLower).String(keyword), keyword),
+				Subject:  remain.SourceRange().Ptr(),
+			})
+		}
+		if step, ok := remain[1].(hcl.TraverseAttr); !ok {
+			diags = diags.Append(hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid checkable address",
+				Detail:   fmt.Sprintf("%s address must have only one attribute part after the keyword '%s', giving the name of the %s.", cases.Title(language.English, cases.NoLower).String(keyword), keyword, descriptor),
+				Subject:  remain.SourceRange().Ptr(),
+			})
+		} else {
+			name = step.Name
+		}
+
+		return name, diags
+	}
+
+	// We use "kind" to disambiguate here because unfortunately we've
+	// historically never reserved "output" as a possible resource type name
+	// and so it is in principle possible -- albeit unlikely -- that there
+	// might be a resource whose type is literally "output".
+	switch kind {
+	case CheckableResource:
+		riAddr, moreDiags := parseResourceInstanceUnderModule(path, remain)
+		diags = diags.Append(moreDiags)
+		if diags.HasErrors() {
+			return nil, diags
+		}
+		return riAddr, diags
+
+	case CheckableOutputValue:
+		name, nameDiags := getCheckableName("output", "output value")
+		diags = diags.Append(nameDiags)
+		if diags.HasErrors() {
+			return nil, diags
+		}
+		return OutputValue{Name: name}.Absolute(path), diags
+
+	case CheckableCheck:
+		name, nameDiags := getCheckableName("check", "check block")
+		diags = diags.Append(nameDiags)
+		if diags.HasErrors() {
+			return nil, diags
+		}
+		return Check{Name: name}.Absolute(path), diags
+
+	default:
+		panic(fmt.Sprintf("unsupported CheckableKind %s", kind))
+	}
+}
diff --git a/v1.5.7/internal/addrs/checkablekind_string.go b/v1.5.7/internal/addrs/checkablekind_string.go
new file mode 100644
index 0000000..e0657cb
--- /dev/null
+++ b/v1.5.7/internal/addrs/checkablekind_string.go
@@ -0,0 +1,37 @@
+// Code generated by "stringer -type=CheckableKind checkable.go"; DO NOT EDIT.
+
+package addrs
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[CheckableKindInvalid-0]
+	_ = x[CheckableResource-82]
+	_ = x[CheckableOutputValue-79]
+	_ = x[CheckableCheck-67]
+}
+
+const (
+	_CheckableKind_name_0 = "CheckableKindInvalid"
+	_CheckableKind_name_1 = "CheckableCheck"
+	_CheckableKind_name_2 = "CheckableOutputValue"
+	_CheckableKind_name_3 = "CheckableResource"
+)
+
+func (i CheckableKind) String() string {
+	switch {
+	case i == 0:
+		return _CheckableKind_name_0
+	case i == 67:
+		return _CheckableKind_name_1
+	case i == 79:
+		return _CheckableKind_name_2
+	case i == 82:
+		return _CheckableKind_name_3
+	default:
+		return "CheckableKind(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/v1.5.7/internal/addrs/checkruletype_string.go b/v1.5.7/internal/addrs/checkruletype_string.go
new file mode 100644
index 0000000..7865793
--- /dev/null
+++ b/v1.5.7/internal/addrs/checkruletype_string.go
@@ -0,0 +1,28 @@
+// Code generated by "stringer -type=CheckRuleType check_rule.go"; DO NOT EDIT.
+
+package addrs
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[InvalidCondition-0]
+	_ = x[ResourcePrecondition-1]
+	_ = x[ResourcePostcondition-2]
+	_ = x[OutputPrecondition-3]
+	_ = x[CheckDataResource-4]
+	_ = x[CheckAssertion-5]
+}
+
+const _CheckRuleType_name = "InvalidConditionResourcePreconditionResourcePostconditionOutputPreconditionCheckDataResourceCheckAssertion"
+
+var _CheckRuleType_index = [...]uint8{0, 16, 36, 57, 75, 92, 106}
+
+func (i CheckRuleType) String() string {
+	if i < 0 || i >= CheckRuleType(len(_CheckRuleType_index)-1) {
+		return "CheckRuleType(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _CheckRuleType_name[_CheckRuleType_index[i]:_CheckRuleType_index[i+1]]
+}
diff --git a/v1.5.7/internal/addrs/count_attr.go b/v1.5.7/internal/addrs/count_attr.go
new file mode 100644
index 0000000..ee56fc2
--- /dev/null
+++ b/v1.5.7/internal/addrs/count_attr.go
@@ -0,0 +1,21 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+// CountAttr is the address of an attribute of the "count" object in
+// the interpolation scope, like "count.index".
+type CountAttr struct {
+	referenceable
+	Name string
+}
+
+func (ca CountAttr) String() string {
+	return "count." + ca.Name
+}
+
+func (ca CountAttr) UniqueKey() UniqueKey {
+	return ca // A CountAttr is its own UniqueKey
+}
+
+func (ca CountAttr) uniqueKeySigil() {}
diff --git a/v1.5.7/internal/addrs/doc.go b/v1.5.7/internal/addrs/doc.go
new file mode 100644
index 0000000..0d29d9f
--- /dev/null
+++ b/v1.5.7/internal/addrs/doc.go
@@ -0,0 +1,20 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package addrs contains types that represent "addresses", which are
+// references to specific objects within a Terraform configuration or
+// state.
+//
+// All addresses have string representations based on HCL traversal syntax
+// which should be used in the user-interface, and also in-memory
+// representations that can be used internally.
+//
+// For object types that exist within Terraform modules a pair of types is
+// used. The "local" part of the address is represented by a type, and then
+// an absolute path to that object in the context of its module is represented
+// by a type of the same name with an "Abs" prefix added, for "absolute".
+//
+// All types within this package should be treated as immutable, even if this
+// is not enforced by the Go compiler. It is always an implementation error
+// to modify an address object in-place after it is initially constructed.
+package addrs
diff --git a/v1.5.7/internal/addrs/for_each_attr.go b/v1.5.7/internal/addrs/for_each_attr.go
new file mode 100644
index 0000000..48be27b
--- /dev/null
+++ b/v1.5.7/internal/addrs/for_each_attr.go
@@ -0,0 +1,21 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+// ForEachAttr is the address of an attribute referencing the current "for_each" object in
+// the interpolation scope, addressed using the "each" keyword, ex. "each.key" and "each.value"
+type ForEachAttr struct {
+	referenceable
+	Name string
+}
+
+func (f ForEachAttr) String() string {
+	return "each." + f.Name
+}
+
+func (f ForEachAttr) UniqueKey() UniqueKey {
+	return f // A ForEachAttr is its own UniqueKey
+}
+
+func (f ForEachAttr) uniqueKeySigil() {}
diff --git a/v1.5.7/internal/addrs/input_variable.go b/v1.5.7/internal/addrs/input_variable.go
new file mode 100644
index 0000000..c38d55e
--- /dev/null
+++ b/v1.5.7/internal/addrs/input_variable.go
@@ -0,0 +1,59 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+)
+
+// InputVariable is the address of an input variable.
+type InputVariable struct {
+	referenceable
+	Name string
+}
+
+func (v InputVariable) String() string {
+	return "var." + v.Name
+}
+
+func (v InputVariable) UniqueKey() UniqueKey {
+	return v // A InputVariable is its own UniqueKey
+}
+
+func (v InputVariable) uniqueKeySigil() {}
+
+// Absolute converts the receiver into an absolute address within the given
+// module instance.
+func (v InputVariable) Absolute(m ModuleInstance) AbsInputVariableInstance {
+	return AbsInputVariableInstance{
+		Module:   m,
+		Variable: v,
+	}
+}
+
+// AbsInputVariableInstance is the address of an input variable within a
+// particular module instance.
+type AbsInputVariableInstance struct {
+	Module   ModuleInstance
+	Variable InputVariable
+}
+
+// InputVariable returns the absolute address of the input variable of the
+// given name inside the receiving module instance.
+func (m ModuleInstance) InputVariable(name string) AbsInputVariableInstance {
+	return AbsInputVariableInstance{
+		Module: m,
+		Variable: InputVariable{
+			Name: name,
+		},
+	}
+}
+
+func (v AbsInputVariableInstance) String() string {
+	if len(v.Module) == 0 {
+		return v.Variable.String()
+	}
+
+	return fmt.Sprintf("%s.%s", v.Module.String(), v.Variable.String())
+}
diff --git a/v1.5.7/internal/addrs/instance_key.go b/v1.5.7/internal/addrs/instance_key.go
new file mode 100644
index 0000000..34c186c
--- /dev/null
+++ b/v1.5.7/internal/addrs/instance_key.go
@@ -0,0 +1,194 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"strings"
+	"unicode"
+
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/gocty"
+)
+
+// InstanceKey represents the key of an instance within an object that
+// contains multiple instances due to using "count" or "for_each" arguments
+// in configuration.
+//
+// IntKey and StringKey are the two implementations of this type. No other
+// implementations are allowed. The single instance of an object that _isn't_
+// using "count" or "for_each" is represented by NoKey, which is a nil
+// InstanceKey.
+type InstanceKey interface {
+	instanceKeySigil()
+	String() string
+
+	// Value returns the cty.Value of the appropriate type for the InstanceKey
+	// value.
+	Value() cty.Value
+}
+
+// ParseInstanceKey returns the instance key corresponding to the given value,
+// which must be known and non-null.
+//
+// If an unknown or null value is provided then this function will panic. This
+// function is intended to deal with the values that would naturally be found
+// in a hcl.TraverseIndex, which (when parsed from source, at least) can never
+// contain unknown or null values.
+func ParseInstanceKey(key cty.Value) (InstanceKey, error) {
+	switch key.Type() {
+	case cty.String:
+		return StringKey(key.AsString()), nil
+	case cty.Number:
+		var idx int
+		err := gocty.FromCtyValue(key, &idx)
+		return IntKey(idx), err
+	default:
+		return NoKey, fmt.Errorf("either a string or an integer is required")
+	}
+}
+
+// NoKey represents the absense of an InstanceKey, for the single instance
+// of a configuration object that does not use "count" or "for_each" at all.
+var NoKey InstanceKey
+
+// IntKey is the InstanceKey representation representing integer indices, as
+// used when the "count" argument is specified or if for_each is used with
+// a sequence type.
+type IntKey int
+
+func (k IntKey) instanceKeySigil() {
+}
+
+func (k IntKey) String() string {
+	return fmt.Sprintf("[%d]", int(k))
+}
+
+func (k IntKey) Value() cty.Value {
+	return cty.NumberIntVal(int64(k))
+}
+
+// StringKey is the InstanceKey representation representing string indices, as
+// used when the "for_each" argument is specified with a map or object type.
+type StringKey string
+
+func (k StringKey) instanceKeySigil() {
+}
+
+func (k StringKey) String() string {
+	// We use HCL's quoting syntax here so that we can in principle parse
+	// an address constructed by this package as if it were an HCL
+	// traversal, even if the string contains HCL's own metacharacters.
+	return fmt.Sprintf("[%s]", toHCLQuotedString(string(k)))
+}
+
+func (k StringKey) Value() cty.Value {
+	return cty.StringVal(string(k))
+}
+
+// InstanceKeyLess returns true if the first given instance key i should sort
+// before the second key j, and false otherwise.
+func InstanceKeyLess(i, j InstanceKey) bool {
+	iTy := instanceKeyType(i)
+	jTy := instanceKeyType(j)
+
+	switch {
+	case i == j:
+		return false
+	case i == NoKey:
+		return true
+	case j == NoKey:
+		return false
+	case iTy != jTy:
+		// The ordering here is arbitrary except that we want NoKeyType
+		// to sort before the others, so we'll just use the enum values
+		// of InstanceKeyType here (where NoKey is zero, sorting before
+		// any other).
+		return uint32(iTy) < uint32(jTy)
+	case iTy == IntKeyType:
+		return int(i.(IntKey)) < int(j.(IntKey))
+	case iTy == StringKeyType:
+		return string(i.(StringKey)) < string(j.(StringKey))
+	default:
+		// Shouldn't be possible to get down here in practice, since the
+		// above is exhaustive.
+		return false
+	}
+}
+
+func instanceKeyType(k InstanceKey) InstanceKeyType {
+	if _, ok := k.(StringKey); ok {
+		return StringKeyType
+	}
+	if _, ok := k.(IntKey); ok {
+		return IntKeyType
+	}
+	return NoKeyType
+}
+
+// InstanceKeyType represents the different types of instance key that are
+// supported. Usually it is sufficient to simply type-assert an InstanceKey
+// value to either IntKey or StringKey, but this type and its values can be
+// used to represent the types themselves, rather than specific values
+// of those types.
+type InstanceKeyType rune
+
+const (
+	NoKeyType     InstanceKeyType = 0
+	IntKeyType    InstanceKeyType = 'I'
+	StringKeyType InstanceKeyType = 'S'
+)
+
+// toHCLQuotedString is a helper which formats the given string in a way that
+// HCL's expression parser would treat as a quoted string template.
+//
+// This includes:
+//   - Adding quote marks at the start and the end.
+//   - Using backslash escapes as needed for characters that cannot be represented directly.
+//   - Escaping anything that would be treated as a template interpolation or control sequence.
+func toHCLQuotedString(s string) string {
+	// This is an adaptation of a similar function inside the hclwrite package,
+	// inlined here because hclwrite's version generates HCL tokens but we
+	// only need normal strings.
+	if len(s) == 0 {
+		return `""`
+	}
+	var buf strings.Builder
+	buf.WriteByte('"')
+	for i, r := range s {
+		switch r {
+		case '\n':
+			buf.WriteString(`\n`)
+		case '\r':
+			buf.WriteString(`\r`)
+		case '\t':
+			buf.WriteString(`\t`)
+		case '"':
+			buf.WriteString(`\"`)
+		case '\\':
+			buf.WriteString(`\\`)
+		case '$', '%':
+			buf.WriteRune(r)
+			remain := s[i+1:]
+			if len(remain) > 0 && remain[0] == '{' {
+				// Double up our template introducer symbol to escape it.
+				buf.WriteRune(r)
+			}
+		default:
+			if !unicode.IsPrint(r) {
+				var fmted string
+				if r < 65536 {
+					fmted = fmt.Sprintf("\\u%04x", r)
+				} else {
+					fmted = fmt.Sprintf("\\U%08x", r)
+				}
+				buf.WriteString(fmted)
+			} else {
+				buf.WriteRune(r)
+			}
+		}
+	}
+	buf.WriteByte('"')
+	return buf.String()
+}
diff --git a/v1.5.7/internal/addrs/instance_key_test.go b/v1.5.7/internal/addrs/instance_key_test.go
new file mode 100644
index 0000000..429457c
--- /dev/null
+++ b/v1.5.7/internal/addrs/instance_key_test.go
@@ -0,0 +1,78 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestInstanceKeyString(t *testing.T) {
+	tests := []struct {
+		Key  InstanceKey
+		Want string
+	}{
+		{
+			IntKey(0),
+			`[0]`,
+		},
+		{
+			IntKey(5),
+			`[5]`,
+		},
+		{
+			StringKey(""),
+			`[""]`,
+		},
+		{
+			StringKey("hi"),
+			`["hi"]`,
+		},
+		{
+			StringKey("0"),
+			`["0"]`, // intentionally distinct from IntKey(0)
+		},
+		{
+			// Quotes must be escaped
+			StringKey(`"`),
+			`["\""]`,
+		},
+		{
+			// Escape sequences must themselves be escaped
+			StringKey(`\r\n`),
+			`["\\r\\n"]`,
+		},
+		{
+			// Template interpolation sequences "${" must be escaped.
+			StringKey(`${hello}`),
+			`["$${hello}"]`,
+		},
+		{
+			// Template control sequences "%{" must be escaped.
+			StringKey(`%{ for something in something }%{ endfor }`),
+			`["%%{ for something in something }%%{ endfor }"]`,
+		},
+		{
+			// Dollar signs that aren't followed by { are not interpolation sequences
+			StringKey(`$hello`),
+			`["$hello"]`,
+		},
+		{
+			// Percent signs that aren't followed by { are not control sequences
+			StringKey(`%hello`),
+			`["%hello"]`,
+		},
+	}
+
+	for _, test := range tests {
+		testName := fmt.Sprintf("%#v", test.Key)
+		t.Run(testName, func(t *testing.T) {
+			got := test.Key.String()
+			want := test.Want
+			if got != want {
+				t.Errorf("wrong result\nreciever: %s\ngot:      %s\nwant:     %s", testName, got, want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/addrs/local_value.go b/v1.5.7/internal/addrs/local_value.go
new file mode 100644
index 0000000..0925843
--- /dev/null
+++ b/v1.5.7/internal/addrs/local_value.go
@@ -0,0 +1,57 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+)
+
+// LocalValue is the address of a local value.
+type LocalValue struct {
+	referenceable
+	Name string
+}
+
+func (v LocalValue) String() string {
+	return "local." + v.Name
+}
+
+func (v LocalValue) UniqueKey() UniqueKey {
+	return v // A LocalValue is its own UniqueKey
+}
+
+func (v LocalValue) uniqueKeySigil() {}
+
+// Absolute converts the receiver into an absolute address within the given
+// module instance.
+func (v LocalValue) Absolute(m ModuleInstance) AbsLocalValue {
+	return AbsLocalValue{
+		Module:     m,
+		LocalValue: v,
+	}
+}
+
+// AbsLocalValue is the absolute address of a local value within a module instance.
+type AbsLocalValue struct {
+	Module     ModuleInstance
+	LocalValue LocalValue
+}
+
+// LocalValue returns the absolute address of a local value of the given
+// name within the receiving module instance.
+func (m ModuleInstance) LocalValue(name string) AbsLocalValue {
+	return AbsLocalValue{
+		Module: m,
+		LocalValue: LocalValue{
+			Name: name,
+		},
+	}
+}
+
+func (v AbsLocalValue) String() string {
+	if len(v.Module) == 0 {
+		return v.LocalValue.String()
+	}
+	return fmt.Sprintf("%s.%s", v.Module.String(), v.LocalValue.String())
+}
diff --git a/v1.5.7/internal/addrs/map.go b/v1.5.7/internal/addrs/map.go
new file mode 100644
index 0000000..8e05c42
--- /dev/null
+++ b/v1.5.7/internal/addrs/map.go
@@ -0,0 +1,131 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+// Map represents a mapping whose keys are address types that implement
+// UniqueKeyer.
+//
+// Since not all address types are comparable in the Go language sense, this
+// type cannot work with the typical Go map access syntax, and so instead has
+// a method-based syntax. Use this type only for situations where the key
+// type isn't guaranteed to always be a valid key for a standard Go map.
+type Map[K UniqueKeyer, V any] struct {
+	// Elems is the internal data structure of the map.
+	//
+	// This is exported to allow for comparisons during tests and other similar
+	// careful read operations, but callers MUST NOT modify this map directly.
+	// Use only the methods of Map to modify the contents of this structure,
+	// to ensure that it remains correct and consistent.
+	Elems map[UniqueKey]MapElem[K, V]
+}
+
+type MapElem[K UniqueKeyer, V any] struct {
+	Key   K
+	Value V
+}
+
+func MakeMap[K UniqueKeyer, V any](initialElems ...MapElem[K, V]) Map[K, V] {
+	inner := make(map[UniqueKey]MapElem[K, V], len(initialElems))
+	ret := Map[K, V]{inner}
+	for _, elem := range initialElems {
+		ret.Put(elem.Key, elem.Value)
+	}
+	return ret
+}
+
+func MakeMapElem[K UniqueKeyer, V any](key K, value V) MapElem[K, V] {
+	return MapElem[K, V]{key, value}
+}
+
+// Put inserts a new element into the map, or replaces an existing element
+// which has an equivalent key.
+func (m Map[K, V]) Put(key K, value V) {
+	realKey := key.UniqueKey()
+	m.Elems[realKey] = MapElem[K, V]{key, value}
+}
+
+// PutElement is like Put but takes the key and value from the given MapElement
+// structure instead of as individual arguments.
+func (m Map[K, V]) PutElement(elem MapElem[K, V]) {
+	m.Put(elem.Key, elem.Value)
+}
+
+// Remove deletes the element with the given key from the map, or does nothing
+// if there is no such element.
+func (m Map[K, V]) Remove(key K) {
+	realKey := key.UniqueKey()
+	delete(m.Elems, realKey)
+}
+
+// Get returns the value of the element with the given key, or the zero value
+// of V if there is no such element.
+func (m Map[K, V]) Get(key K) V {
+	realKey := key.UniqueKey()
+	return m.Elems[realKey].Value
+}
+
+// GetOk is like Get but additionally returns a flag for whether there was an
+// element with the given key present in the map.
+func (m Map[K, V]) GetOk(key K) (V, bool) {
+	realKey := key.UniqueKey()
+	elem, ok := m.Elems[realKey]
+	return elem.Value, ok
+}
+
+// Has returns true if and only if there is an element in the map which has the
+// given key.
+func (m Map[K, V]) Has(key K) bool {
+	realKey := key.UniqueKey()
+	_, ok := m.Elems[realKey]
+	return ok
+}
+
+// Len returns the number of elements in the map.
+func (m Map[K, V]) Len() int {
+	return len(m.Elems)
+}
+
+// Elements returns a slice containing a snapshot of the current elements of
+// the map, in an unpredictable order.
+func (m Map[K, V]) Elements() []MapElem[K, V] {
+	if len(m.Elems) == 0 {
+		return nil
+	}
+	ret := make([]MapElem[K, V], 0, len(m.Elems))
+	for _, elem := range m.Elems {
+		ret = append(ret, elem)
+	}
+	return ret
+}
+
+// Keys returns a Set[K] containing a snapshot of the current keys of elements
+// of the map.
+func (m Map[K, V]) Keys() Set[K] {
+	if len(m.Elems) == 0 {
+		return nil
+	}
+	ret := make(Set[K], len(m.Elems))
+
+	// We mess with the internals of Set here, rather than going through its
+	// public interface, because that means we can avoid re-calling UniqueKey
+	// on all of the elements when we know that our own Put method would have
+	// already done the same thing.
+	for realKey, elem := range m.Elems {
+		ret[realKey] = elem.Key
+	}
+	return ret
+}
+
+// Values returns a slice containing a snapshot of the current values of
+// elements of the map, in an unpredictable order.
+func (m Map[K, V]) Values() []V {
+	if len(m.Elems) == 0 {
+		return nil
+	}
+	ret := make([]V, 0, len(m.Elems))
+	for _, elem := range m.Elems {
+		ret = append(ret, elem.Value)
+	}
+	return ret
+}
diff --git a/v1.5.7/internal/addrs/map_test.go b/v1.5.7/internal/addrs/map_test.go
new file mode 100644
index 0000000..648bebd
--- /dev/null
+++ b/v1.5.7/internal/addrs/map_test.go
@@ -0,0 +1,86 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"testing"
+)
+
+func TestMap(t *testing.T) {
+	variableName := InputVariable{Name: "name"}
+	localHello := LocalValue{Name: "hello"}
+	pathModule := PathAttr{Name: "module"}
+	moduleBeep := ModuleCall{Name: "beep"}
+	eachKey := ForEachAttr{Name: "key"} // intentionally not in the map
+
+	m := MakeMap(
+		MakeMapElem[Referenceable](variableName, "Aisling"),
+	)
+
+	m.Put(localHello, "hello")
+	m.Put(pathModule, "boop")
+	m.Put(moduleBeep, "unrealistic")
+
+	keySet := m.Keys()
+	if want := variableName; !m.Has(want) {
+		t.Errorf("map does not include %s", want)
+	}
+	if want := variableName; !keySet.Has(want) {
+		t.Errorf("key set does not include %s", want)
+	}
+	if want := localHello; !m.Has(want) {
+		t.Errorf("map does not include %s", want)
+	}
+	if want := localHello; !keySet.Has(want) {
+		t.Errorf("key set does not include %s", want)
+	}
+	if want := pathModule; !keySet.Has(want) {
+		t.Errorf("key set does not include %s", want)
+	}
+	if want := moduleBeep; !keySet.Has(want) {
+		t.Errorf("key set does not include %s", want)
+	}
+	if doNotWant := eachKey; m.Has(doNotWant) {
+		t.Errorf("map includes rogue element %s", doNotWant)
+	}
+	if doNotWant := eachKey; keySet.Has(doNotWant) {
+		t.Errorf("key set includes rogue element %s", doNotWant)
+	}
+
+	if got, want := m.Get(variableName), "Aisling"; got != want {
+		t.Errorf("unexpected value %q for %s; want %q", got, variableName, want)
+	}
+	if got, want := m.Get(localHello), "hello"; got != want {
+		t.Errorf("unexpected value %q for %s; want %q", got, localHello, want)
+	}
+	if got, want := m.Get(pathModule), "boop"; got != want {
+		t.Errorf("unexpected value %q for %s; want %q", got, pathModule, want)
+	}
+	if got, want := m.Get(moduleBeep), "unrealistic"; got != want {
+		t.Errorf("unexpected value %q for %s; want %q", got, moduleBeep, want)
+	}
+	if got, want := m.Get(eachKey), ""; got != want {
+		// eachKey isn't in the map, so Get returns the zero value of string
+		t.Errorf("unexpected value %q for %s; want %q", got, eachKey, want)
+	}
+
+	if v, ok := m.GetOk(variableName); v != "Aisling" || !ok {
+		t.Errorf("GetOk for %q returned incorrect result (%q, %#v)", variableName, v, ok)
+	}
+	if v, ok := m.GetOk(eachKey); v != "" || ok {
+		t.Errorf("GetOk for %q returned incorrect result (%q, %#v)", eachKey, v, ok)
+	}
+
+	m.Remove(moduleBeep)
+	if doNotWant := moduleBeep; m.Has(doNotWant) {
+		t.Errorf("map still includes %s after removing it", doNotWant)
+	}
+	if want := moduleBeep; !keySet.Has(want) {
+		t.Errorf("key set no longer includes %s after removing it from the map; key set is supposed to be a snapshot at the time of call", want)
+	}
+	keySet = m.Keys()
+	if doNotWant := moduleBeep; keySet.Has(doNotWant) {
+		t.Errorf("key set still includes %s after a second call after removing it from the map", doNotWant)
+	}
+}
diff --git a/v1.5.7/internal/addrs/module.go b/v1.5.7/internal/addrs/module.go
new file mode 100644
index 0000000..ff8fb65
--- /dev/null
+++ b/v1.5.7/internal/addrs/module.go
@@ -0,0 +1,170 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"strings"
+)
+
+// Module is an address for a module call within configuration. This is
+// the static counterpart of ModuleInstance, representing a traversal through
+// the static module call tree in configuration and does not take into account
+// the potentially-multiple instances of a module that might be created by
+// "count" and "for_each" arguments within those calls.
+//
+// This type should be used only in very specialized cases when working with
+// the static module call tree. Type ModuleInstance is appropriate in more cases.
+//
+// Although Module is a slice, it should be treated as immutable after creation.
+type Module []string
+
+// RootModule is the module address representing the root of the static module
+// call tree, which is also the zero value of Module.
+//
+// Note that this is not the root of the dynamic module tree, which is instead
+// represented by RootModuleInstance.
+var RootModule Module
+
+// IsRoot returns true if the receiver is the address of the root module,
+// or false otherwise.
+func (m Module) IsRoot() bool {
+	return len(m) == 0
+}
+
+func (m Module) String() string {
+	if len(m) == 0 {
+		return ""
+	}
+	// Calculate necessary space.
+	l := 0
+	for _, step := range m {
+		l += len(step)
+	}
+	buf := strings.Builder{}
+	// 8 is len(".module.") which separates entries.
+	buf.Grow(l + len(m)*8)
+	sep := ""
+	for _, step := range m {
+		buf.WriteString(sep)
+		buf.WriteString("module.")
+		buf.WriteString(step)
+		sep = "."
+	}
+	return buf.String()
+}
+
+func (m Module) Equal(other Module) bool {
+	if len(m) != len(other) {
+		return false
+	}
+	for i := range m {
+		if m[i] != other[i] {
+			return false
+		}
+	}
+	return true
+}
+
+func (m Module) targetableSigil() {
+	// Module is targetable
+}
+
+// TargetContains implements Targetable for Module by returning true if the given other
+// address either matches the receiver, is a sub-module-instance of the
+// receiver, or is a targetable absolute address within a module that
+// is contained within the receiver.
+func (m Module) TargetContains(other Targetable) bool {
+	switch to := other.(type) {
+
+	case Module:
+		if len(to) < len(m) {
+			// Can't be contained if the path is shorter
+			return false
+		}
+		// Other is contained if its steps match for the length of our own path.
+		for i, ourStep := range m {
+			otherStep := to[i]
+			if ourStep != otherStep {
+				return false
+			}
+		}
+		// If we fall out here then the prefixed matched, so it's contained.
+		return true
+
+	case ModuleInstance:
+		return m.TargetContains(to.Module())
+
+	case ConfigResource:
+		return m.TargetContains(to.Module)
+
+	case AbsResource:
+		return m.TargetContains(to.Module)
+
+	case AbsResourceInstance:
+		return m.TargetContains(to.Module)
+
+	default:
+		return false
+	}
+}
+
+func (m Module) AddrType() TargetableAddrType {
+	return ModuleAddrType
+}
+
+// Child returns the address of a child call in the receiver, identified by the
+// given name.
+func (m Module) Child(name string) Module {
+	ret := make(Module, 0, len(m)+1)
+	ret = append(ret, m...)
+	return append(ret, name)
+}
+
+// Parent returns the address of the parent module of the receiver, or the
+// receiver itself if there is no parent (if it's the root module address).
+func (m Module) Parent() Module {
+	if len(m) == 0 {
+		return m
+	}
+	return m[:len(m)-1]
+}
+
+// Call returns the module call address that corresponds to the given module
+// instance, along with the address of the module that contains it.
+//
+// There is no call for the root module, so this method will panic if called
+// on the root module address.
+//
+// In practice, this just turns the last element of the receiver into a
+// ModuleCall and then returns a slice of the receiever that excludes that
+// last part. This is just a convenience for situations where a call address
+// is required, such as when dealing with *Reference and Referencable values.
+func (m Module) Call() (Module, ModuleCall) {
+	if len(m) == 0 {
+		panic("cannot produce ModuleCall for root module")
+	}
+
+	caller, callName := m[:len(m)-1], m[len(m)-1]
+	return caller, ModuleCall{
+		Name: callName,
+	}
+}
+
+// Ancestors returns a slice containing the receiver and all of its ancestor
+// modules, all the way up to (and including) the root module.  The result is
+// ordered by depth, with the root module always first.
+//
+// Since the result always includes the root module, a caller may choose to
+// ignore it by slicing the result with [1:].
+func (m Module) Ancestors() []Module {
+	ret := make([]Module, 0, len(m)+1)
+	for i := 0; i <= len(m); i++ {
+		ret = append(ret, m[:i])
+	}
+	return ret
+}
+
+func (m Module) configMoveableSigil() {
+	// ModuleInstance is moveable
+}
diff --git a/v1.5.7/internal/addrs/module_call.go b/v1.5.7/internal/addrs/module_call.go
new file mode 100644
index 0000000..7d1af52
--- /dev/null
+++ b/v1.5.7/internal/addrs/module_call.go
@@ -0,0 +1,195 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+)
+
+// ModuleCall is the address of a call from the current module to a child
+// module.
+type ModuleCall struct {
+	referenceable
+	Name string
+}
+
+func (c ModuleCall) String() string {
+	return "module." + c.Name
+}
+
+func (c ModuleCall) UniqueKey() UniqueKey {
+	return c // A ModuleCall is its own UniqueKey
+}
+
+func (c ModuleCall) uniqueKeySigil() {}
+
+// Instance returns the address of an instance of the receiver identified by
+// the given key.
+func (c ModuleCall) Instance(key InstanceKey) ModuleCallInstance {
+	return ModuleCallInstance{
+		Call: c,
+		Key:  key,
+	}
+}
+
+func (c ModuleCall) Absolute(moduleAddr ModuleInstance) AbsModuleCall {
+	return AbsModuleCall{
+		Module: moduleAddr,
+		Call:   c,
+	}
+}
+
+func (c ModuleCall) Equal(other ModuleCall) bool {
+	return c.Name == other.Name
+}
+
+// AbsModuleCall is the address of a "module" block relative to the root
+// of the configuration.
+//
+// This is similar to ModuleInstance alone, but specifically represents
+// the module block itself rather than any one of the instances that
+// module block declares.
+type AbsModuleCall struct {
+	Module ModuleInstance
+	Call   ModuleCall
+}
+
+func (c AbsModuleCall) absMoveableSigil() {
+	// AbsModuleCall is "moveable".
+}
+
+func (c AbsModuleCall) String() string {
+	if len(c.Module) == 0 {
+		return "module." + c.Call.Name
+
+	}
+	return fmt.Sprintf("%s.module.%s", c.Module, c.Call.Name)
+}
+
+func (c AbsModuleCall) Instance(key InstanceKey) ModuleInstance {
+	ret := make(ModuleInstance, len(c.Module), len(c.Module)+1)
+	copy(ret, c.Module)
+	ret = append(ret, ModuleInstanceStep{
+		Name:        c.Call.Name,
+		InstanceKey: key,
+	})
+	return ret
+}
+
+func (c AbsModuleCall) Equal(other AbsModuleCall) bool {
+	return c.Module.Equal(other.Module) && c.Call.Equal(other.Call)
+}
+
+type absModuleCallInstanceKey string
+
+func (c AbsModuleCall) UniqueKey() UniqueKey {
+	return absModuleCallInstanceKey(c.String())
+}
+
+func (mk absModuleCallInstanceKey) uniqueKeySigil() {}
+
+// ModuleCallInstance is the address of one instance of a module created from
+// a module call, which might create multiple instances using "count" or
+// "for_each" arguments.
+//
+// There is no "Abs" version of ModuleCallInstance because an absolute module
+// path is represented by ModuleInstance.
+type ModuleCallInstance struct {
+	referenceable
+	Call ModuleCall
+	Key  InstanceKey
+}
+
+func (c ModuleCallInstance) String() string {
+	if c.Key == NoKey {
+		return c.Call.String()
+	}
+	return fmt.Sprintf("module.%s%s", c.Call.Name, c.Key)
+}
+
+func (c ModuleCallInstance) UniqueKey() UniqueKey {
+	return c // A ModuleCallInstance is its own UniqueKey
+}
+
+func (c ModuleCallInstance) uniqueKeySigil() {}
+
+func (c ModuleCallInstance) Absolute(moduleAddr ModuleInstance) ModuleInstance {
+	ret := make(ModuleInstance, len(moduleAddr), len(moduleAddr)+1)
+	copy(ret, moduleAddr)
+	ret = append(ret, ModuleInstanceStep{
+		Name:        c.Call.Name,
+		InstanceKey: c.Key,
+	})
+	return ret
+}
+
+// ModuleInstance returns the address of the module instance that corresponds
+// to the receiving call instance when resolved in the given calling module.
+// In other words, it returns the child module instance that the receving
+// call instance creates.
+func (c ModuleCallInstance) ModuleInstance(caller ModuleInstance) ModuleInstance {
+	return caller.Child(c.Call.Name, c.Key)
+}
+
+// Output returns the absolute address of an output of the receiver identified by its
+// name.
+func (c ModuleCallInstance) Output(name string) ModuleCallInstanceOutput {
+	return ModuleCallInstanceOutput{
+		Call: c,
+		Name: name,
+	}
+}
+
+// ModuleCallOutput is the address of a named output and its associated
+// ModuleCall, which may expand into multiple module instances
+type ModuleCallOutput struct {
+	referenceable
+	Call ModuleCall
+	Name string
+}
+
+func (m ModuleCallOutput) String() string {
+	return fmt.Sprintf("%s.%s", m.Call.String(), m.Name)
+}
+
+func (m ModuleCallOutput) UniqueKey() UniqueKey {
+	return m // A ModuleCallOutput is its own UniqueKey
+}
+
+func (m ModuleCallOutput) uniqueKeySigil() {}
+
+// ModuleCallInstanceOutput is the address of a particular named output produced by
+// an instance of a module call.
+type ModuleCallInstanceOutput struct {
+	referenceable
+	Call ModuleCallInstance
+	Name string
+}
+
+// ModuleCallOutput returns the referenceable ModuleCallOutput for this
+// particular instance.
+func (co ModuleCallInstanceOutput) ModuleCallOutput() ModuleCallOutput {
+	return ModuleCallOutput{
+		Call: co.Call.Call,
+		Name: co.Name,
+	}
+}
+
+func (co ModuleCallInstanceOutput) String() string {
+	return fmt.Sprintf("%s.%s", co.Call.String(), co.Name)
+}
+
+func (co ModuleCallInstanceOutput) UniqueKey() UniqueKey {
+	return co // A ModuleCallInstanceOutput is its own UniqueKey
+}
+
+func (co ModuleCallInstanceOutput) uniqueKeySigil() {}
+
+// AbsOutputValue returns the absolute output value address that corresponds
+// to the receving module call output address, once resolved in the given
+// calling module.
+func (co ModuleCallInstanceOutput) AbsOutputValue(caller ModuleInstance) AbsOutputValue {
+	moduleAddr := co.Call.ModuleInstance(caller)
+	return moduleAddr.OutputValue(co.Name)
+}
diff --git a/v1.5.7/internal/addrs/module_instance.go b/v1.5.7/internal/addrs/module_instance.go
new file mode 100644
index 0000000..b30b807
--- /dev/null
+++ b/v1.5.7/internal/addrs/module_instance.go
@@ -0,0 +1,546 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/gocty"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ModuleInstance is an address for a particular module instance within the
+// dynamic module tree. This is an extension of the static traversals
+// represented by type Module that deals with the possibility of a single
+// module call producing multiple instances via the "count" and "for_each"
+// arguments.
+//
+// Although ModuleInstance is a slice, it should be treated as immutable after
+// creation.
+type ModuleInstance []ModuleInstanceStep
+
+var (
+	_ Targetable = ModuleInstance(nil)
+)
+
+func ParseModuleInstance(traversal hcl.Traversal) (ModuleInstance, tfdiags.Diagnostics) {
+	mi, remain, diags := parseModuleInstancePrefix(traversal)
+	if len(remain) != 0 {
+		if len(remain) == len(traversal) {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid module instance address",
+				Detail:   "A module instance address must begin with \"module.\".",
+				Subject:  remain.SourceRange().Ptr(),
+			})
+		} else {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid module instance address",
+				Detail:   "The module instance address is followed by additional invalid content.",
+				Subject:  remain.SourceRange().Ptr(),
+			})
+		}
+	}
+	return mi, diags
+}
+
+// ParseModuleInstanceStr is a helper wrapper around ParseModuleInstance
+// that takes a string and parses it with the HCL native syntax traversal parser
+// before interpreting it.
+//
+// This should be used only in specialized situations since it will cause the
+// created references to not have any meaningful source location information.
+// If a reference string is coming from a source that should be identified in
+// error messages then the caller should instead parse it directly using a
+// suitable function from the HCL API and pass the traversal itself to
+// ParseModuleInstance.
+//
+// Error diagnostics are returned if either the parsing fails or the analysis
+// of the traversal fails. There is no way for the caller to distinguish the
+// two kinds of diagnostics programmatically. If error diagnostics are returned
+// then the returned address is invalid.
+func ParseModuleInstanceStr(str string) (ModuleInstance, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1})
+	diags = diags.Append(parseDiags)
+	if parseDiags.HasErrors() {
+		return nil, diags
+	}
+
+	addr, addrDiags := ParseModuleInstance(traversal)
+	diags = diags.Append(addrDiags)
+	return addr, diags
+}
+
+func parseModuleInstancePrefix(traversal hcl.Traversal) (ModuleInstance, hcl.Traversal, tfdiags.Diagnostics) {
+	remain := traversal
+	var mi ModuleInstance
+	var diags tfdiags.Diagnostics
+
+LOOP:
+	for len(remain) > 0 {
+		var next string
+		switch tt := remain[0].(type) {
+		case hcl.TraverseRoot:
+			next = tt.Name
+		case hcl.TraverseAttr:
+			next = tt.Name
+		default:
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid address operator",
+				Detail:   "Module address prefix must be followed by dot and then a name.",
+				Subject:  remain[0].SourceRange().Ptr(),
+			})
+			break LOOP
+		}
+
+		if next != "module" {
+			break
+		}
+
+		kwRange := remain[0].SourceRange()
+		remain = remain[1:]
+		// If we have the prefix "module" then we should be followed by an
+		// module call name, as an attribute, and then optionally an index step
+		// giving the instance key.
+		if len(remain) == 0 {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid address operator",
+				Detail:   "Prefix \"module.\" must be followed by a module name.",
+				Subject:  &kwRange,
+			})
+			break
+		}
+
+		var moduleName string
+		switch tt := remain[0].(type) {
+		case hcl.TraverseAttr:
+			moduleName = tt.Name
+		default:
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid address operator",
+				Detail:   "Prefix \"module.\" must be followed by a module name.",
+				Subject:  remain[0].SourceRange().Ptr(),
+			})
+			break LOOP
+		}
+		remain = remain[1:]
+		step := ModuleInstanceStep{
+			Name: moduleName,
+		}
+
+		if len(remain) > 0 {
+			if idx, ok := remain[0].(hcl.TraverseIndex); ok {
+				remain = remain[1:]
+
+				switch idx.Key.Type() {
+				case cty.String:
+					step.InstanceKey = StringKey(idx.Key.AsString())
+				case cty.Number:
+					var idxInt int
+					err := gocty.FromCtyValue(idx.Key, &idxInt)
+					if err == nil {
+						step.InstanceKey = IntKey(idxInt)
+					} else {
+						diags = diags.Append(&hcl.Diagnostic{
+							Severity: hcl.DiagError,
+							Summary:  "Invalid address operator",
+							Detail:   fmt.Sprintf("Invalid module index: %s.", err),
+							Subject:  idx.SourceRange().Ptr(),
+						})
+					}
+				default:
+					// Should never happen, because no other types are allowed in traversal indices.
+					diags = diags.Append(&hcl.Diagnostic{
+						Severity: hcl.DiagError,
+						Summary:  "Invalid address operator",
+						Detail:   "Invalid module key: must be either a string or an integer.",
+						Subject:  idx.SourceRange().Ptr(),
+					})
+				}
+			}
+		}
+
+		mi = append(mi, step)
+	}
+
+	var retRemain hcl.Traversal
+	if len(remain) > 0 {
+		retRemain = make(hcl.Traversal, len(remain))
+		copy(retRemain, remain)
+		// The first element here might be either a TraverseRoot or a
+		// TraverseAttr, depending on whether we had a module address on the
+		// front. To make life easier for callers, we'll normalize to always
+		// start with a TraverseRoot.
+		if tt, ok := retRemain[0].(hcl.TraverseAttr); ok {
+			retRemain[0] = hcl.TraverseRoot{
+				Name:     tt.Name,
+				SrcRange: tt.SrcRange,
+			}
+		}
+	}
+
+	return mi, retRemain, diags
+}
+
+// UnkeyedInstanceShim is a shim method for converting a Module address to the
+// equivalent ModuleInstance address that assumes that no modules have
+// keyed instances.
+//
+// This is a temporary allowance for the fact that Terraform does not presently
+// support "count" and "for_each" on modules, and thus graph building code that
+// derives graph nodes from configuration must just assume unkeyed modules
+// in order to construct the graph. At a later time when "count" and "for_each"
+// support is added for modules, all callers of this method will need to be
+// reworked to allow for keyed module instances.
+func (m Module) UnkeyedInstanceShim() ModuleInstance {
+	path := make(ModuleInstance, len(m))
+	for i, name := range m {
+		path[i] = ModuleInstanceStep{Name: name}
+	}
+	return path
+}
+
+// ModuleInstanceStep is a single traversal step through the dynamic module
+// tree. It is used only as part of ModuleInstance.
+type ModuleInstanceStep struct {
+	Name        string
+	InstanceKey InstanceKey
+}
+
+// RootModuleInstance is the module instance address representing the root
+// module, which is also the zero value of ModuleInstance.
+var RootModuleInstance ModuleInstance
+
+// IsRoot returns true if the receiver is the address of the root module instance,
+// or false otherwise.
+func (m ModuleInstance) IsRoot() bool {
+	return len(m) == 0
+}
+
+// Child returns the address of a child module instance of the receiver,
+// identified by the given name and key.
+func (m ModuleInstance) Child(name string, key InstanceKey) ModuleInstance {
+	ret := make(ModuleInstance, 0, len(m)+1)
+	ret = append(ret, m...)
+	return append(ret, ModuleInstanceStep{
+		Name:        name,
+		InstanceKey: key,
+	})
+}
+
+// ChildCall returns the address of a module call within the receiver,
+// identified by the given name.
+func (m ModuleInstance) ChildCall(name string) AbsModuleCall {
+	return AbsModuleCall{
+		Module: m,
+		Call:   ModuleCall{Name: name},
+	}
+}
+
+// Parent returns the address of the parent module instance of the receiver, or
+// the receiver itself if there is no parent (if it's the root module address).
+func (m ModuleInstance) Parent() ModuleInstance {
+	if len(m) == 0 {
+		return m
+	}
+	return m[:len(m)-1]
+}
+
+// String returns a string representation of the receiver, in the format used
+// within e.g. user-provided resource addresses.
+//
+// The address of the root module has the empty string as its representation.
+func (m ModuleInstance) String() string {
+	if len(m) == 0 {
+		return ""
+	}
+	// Calculate minimal necessary space (no instance keys).
+	l := 0
+	for _, step := range m {
+		l += len(step.Name)
+	}
+	buf := strings.Builder{}
+	// 8 is len(".module.") which separates entries.
+	buf.Grow(l + len(m)*8)
+	sep := ""
+	for _, step := range m {
+		buf.WriteString(sep)
+		buf.WriteString("module.")
+		buf.WriteString(step.Name)
+		if step.InstanceKey != NoKey {
+			buf.WriteString(step.InstanceKey.String())
+		}
+		sep = "."
+	}
+	return buf.String()
+}
+
+type moduleInstanceKey string
+
+func (m ModuleInstance) UniqueKey() UniqueKey {
+	return moduleInstanceKey(m.String())
+}
+
+func (mk moduleInstanceKey) uniqueKeySigil() {}
+
+// Equal returns true if the receiver and the given other value
+// contains the exact same parts.
+func (m ModuleInstance) Equal(o ModuleInstance) bool {
+	if len(m) != len(o) {
+		return false
+	}
+
+	for i := range m {
+		if m[i] != o[i] {
+			return false
+		}
+	}
+	return true
+}
+
+// Less returns true if the receiver should sort before the given other value
+// in a sorted list of addresses.
+func (m ModuleInstance) Less(o ModuleInstance) bool {
+	if len(m) != len(o) {
+		// Shorter path sorts first.
+		return len(m) < len(o)
+	}
+
+	for i := range m {
+		mS, oS := m[i], o[i]
+		switch {
+		case mS.Name != oS.Name:
+			return mS.Name < oS.Name
+		case mS.InstanceKey != oS.InstanceKey:
+			return InstanceKeyLess(mS.InstanceKey, oS.InstanceKey)
+		}
+	}
+
+	return false
+}
+
+// Ancestors returns a slice containing the receiver and all of its ancestor
+// module instances, all the way up to (and including) the root module.
+// The result is ordered by depth, with the root module always first.
+//
+// Since the result always includes the root module, a caller may choose to
+// ignore it by slicing the result with [1:].
+func (m ModuleInstance) Ancestors() []ModuleInstance {
+	ret := make([]ModuleInstance, 0, len(m)+1)
+	for i := 0; i <= len(m); i++ {
+		ret = append(ret, m[:i])
+	}
+	return ret
+}
+
+// IsAncestor returns true if the receiver is an ancestor of the given
+// other value.
+func (m ModuleInstance) IsAncestor(o ModuleInstance) bool {
+	// Longer or equal sized paths means the receiver cannot
+	// be an ancestor of the given module insatnce.
+	if len(m) >= len(o) {
+		return false
+	}
+
+	for i, ms := range m {
+		if ms.Name != o[i].Name {
+			return false
+		}
+		if ms.InstanceKey != NoKey && ms.InstanceKey != o[i].InstanceKey {
+			return false
+		}
+	}
+
+	return true
+}
+
+// Call returns the module call address that corresponds to the given module
+// instance, along with the address of the module instance that contains it.
+//
+// There is no call for the root module, so this method will panic if called
+// on the root module address.
+//
+// A single module call can produce potentially many module instances, so the
+// result discards any instance key that might be present on the last step
+// of the instance. To retain this, use CallInstance instead.
+//
+// In practice, this just turns the last element of the receiver into a
+// ModuleCall and then returns a slice of the receiever that excludes that
+// last part. This is just a convenience for situations where a call address
+// is required, such as when dealing with *Reference and Referencable values.
+func (m ModuleInstance) Call() (ModuleInstance, ModuleCall) {
+	if len(m) == 0 {
+		panic("cannot produce ModuleCall for root module")
+	}
+
+	inst, lastStep := m[:len(m)-1], m[len(m)-1]
+	return inst, ModuleCall{
+		Name: lastStep.Name,
+	}
+}
+
+// CallInstance returns the module call instance address that corresponds to
+// the given module instance, along with the address of the module instance
+// that contains it.
+//
+// There is no call for the root module, so this method will panic if called
+// on the root module address.
+//
+// In practice, this just turns the last element of the receiver into a
+// ModuleCallInstance and then returns a slice of the receiever that excludes
+// that last part. This is just a convenience for situations where a call\
+// address is required, such as when dealing with *Reference and Referencable
+// values.
+func (m ModuleInstance) CallInstance() (ModuleInstance, ModuleCallInstance) {
+	if len(m) == 0 {
+		panic("cannot produce ModuleCallInstance for root module")
+	}
+
+	inst, lastStep := m[:len(m)-1], m[len(m)-1]
+	return inst, ModuleCallInstance{
+		Call: ModuleCall{
+			Name: lastStep.Name,
+		},
+		Key: lastStep.InstanceKey,
+	}
+}
+
+// TargetContains implements Targetable by returning true if the given other
+// address either matches the receiver, is a sub-module-instance of the
+// receiver, or is a targetable absolute address within a module that
+// is contained within the reciever.
+func (m ModuleInstance) TargetContains(other Targetable) bool {
+	switch to := other.(type) {
+	case Module:
+		if len(to) < len(m) {
+			// Can't be contained if the path is shorter
+			return false
+		}
+		// Other is contained if its steps match for the length of our own path.
+		for i, ourStep := range m {
+			otherStep := to[i]
+
+			// We can't contain an entire module if we have a specific instance
+			// key. The case of NoKey is OK because this address is either
+			// meant to address an unexpanded module, or a single instance of
+			// that module, and both of those are a covered in-full by the
+			// Module address.
+			if ourStep.InstanceKey != NoKey {
+				return false
+			}
+
+			if ourStep.Name != otherStep {
+				return false
+			}
+		}
+		// If we fall out here then the prefixed matched, so it's contained.
+		return true
+
+	case ModuleInstance:
+		if len(to) < len(m) {
+			return false
+		}
+		for i, ourStep := range m {
+			otherStep := to[i]
+
+			if ourStep.Name != otherStep.Name {
+				return false
+			}
+
+			// if this is our last step, because all targets are parsed as
+			// instances, this may be a ModuleInstance intended to be used as a
+			// Module.
+			if i == len(m)-1 {
+				if ourStep.InstanceKey == NoKey {
+					// If the other step is a keyed instance, then we contain that
+					// step, and if it isn't it's a match, which is true either way
+					return true
+				}
+			}
+
+			if ourStep.InstanceKey != otherStep.InstanceKey {
+				return false
+			}
+
+		}
+		return true
+
+	case ConfigResource:
+		return m.TargetContains(to.Module)
+
+	case AbsResource:
+		return m.TargetContains(to.Module)
+
+	case AbsResourceInstance:
+		return m.TargetContains(to.Module)
+
+	default:
+		return false
+	}
+}
+
+// Module returns the address of the module that this instance is an instance
+// of.
+func (m ModuleInstance) Module() Module {
+	if len(m) == 0 {
+		return nil
+	}
+	ret := make(Module, len(m))
+	for i, step := range m {
+		ret[i] = step.Name
+	}
+	return ret
+}
+
+func (m ModuleInstance) AddrType() TargetableAddrType {
+	return ModuleInstanceAddrType
+}
+
+func (m ModuleInstance) targetableSigil() {
+	// ModuleInstance is targetable
+}
+
+func (m ModuleInstance) absMoveableSigil() {
+	// ModuleInstance is moveable
+}
+
+// IsDeclaredByCall returns true if the receiver is an instance of the given
+// AbsModuleCall.
+func (m ModuleInstance) IsDeclaredByCall(other AbsModuleCall) bool {
+	// Compare len(m) to len(other.Module+1) because the final module instance
+	// step in other is stored in the AbsModuleCall.Call
+	if len(m) > len(other.Module)+1 || len(m) == 0 && len(other.Module) == 0 {
+		return false
+	}
+
+	// Verify that the other's ModuleInstance matches the receiver.
+	inst, lastStep := other.Module, other.Call
+	for i := range inst {
+		if inst[i] != m[i] {
+			return false
+		}
+	}
+
+	// Now compare the final step of the received with the other Call, where
+	// only the name needs to match.
+	return lastStep.Name == m[len(m)-1].Name
+}
+
+func (s ModuleInstanceStep) String() string {
+	if s.InstanceKey != NoKey {
+		return s.Name + s.InstanceKey.String()
+	}
+	return s.Name
+}
diff --git a/v1.5.7/internal/addrs/module_instance_test.go b/v1.5.7/internal/addrs/module_instance_test.go
new file mode 100644
index 0000000..564c548
--- /dev/null
+++ b/v1.5.7/internal/addrs/module_instance_test.go
@@ -0,0 +1,173 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestModuleInstanceEqual_true(t *testing.T) {
+	addrs := []string{
+		"module.foo",
+		"module.foo.module.bar",
+		"module.foo[1].module.bar",
+		`module.foo["a"].module.bar["b"]`,
+		`module.foo["a"].module.bar.module.baz[3]`,
+	}
+	for _, m := range addrs {
+		t.Run(m, func(t *testing.T) {
+			addr, diags := ParseModuleInstanceStr(m)
+			if len(diags) > 0 {
+				t.Fatalf("unexpected diags: %s", diags.Err())
+			}
+			if !addr.Equal(addr) {
+				t.Fatalf("expected %#v to be equal to itself", addr)
+			}
+		})
+	}
+}
+
+func TestModuleInstanceEqual_false(t *testing.T) {
+	testCases := []struct {
+		left  string
+		right string
+	}{
+		{
+			"module.foo",
+			"module.bar",
+		},
+		{
+			"module.foo",
+			"module.foo.module.bar",
+		},
+		{
+			"module.foo[1]",
+			"module.bar[1]",
+		},
+		{
+			`module.foo[1]`,
+			`module.foo["1"]`,
+		},
+		{
+			"module.foo.module.bar",
+			"module.foo[1].module.bar",
+		},
+		{
+			`module.foo.module.bar`,
+			`module.foo["a"].module.bar`,
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(fmt.Sprintf("%s = %s", tc.left, tc.right), func(t *testing.T) {
+			left, diags := ParseModuleInstanceStr(tc.left)
+			if len(diags) > 0 {
+				t.Fatalf("unexpected diags parsing %s: %s", tc.left, diags.Err())
+			}
+			right, diags := ParseModuleInstanceStr(tc.right)
+			if len(diags) > 0 {
+				t.Fatalf("unexpected diags parsing %s: %s", tc.right, diags.Err())
+			}
+
+			if left.Equal(right) {
+				t.Fatalf("expected %#v not to be equal to %#v", left, right)
+			}
+
+			if right.Equal(left) {
+				t.Fatalf("expected %#v not to be equal to %#v", right, left)
+			}
+		})
+	}
+}
+
+func BenchmarkStringShort(b *testing.B) {
+	addr, _ := ParseModuleInstanceStr(`module.foo`)
+	for n := 0; n < b.N; n++ {
+		addr.String()
+	}
+}
+
+func BenchmarkStringLong(b *testing.B) {
+	addr, _ := ParseModuleInstanceStr(`module.southamerica-brazil-region.module.user-regional-desktops.module.user-name`)
+	for n := 0; n < b.N; n++ {
+		addr.String()
+	}
+}
+
+func TestModuleInstance_IsDeclaredByCall(t *testing.T) {
+	tests := []struct {
+		instance ModuleInstance
+		call     AbsModuleCall
+		want     bool
+	}{
+		{
+			ModuleInstance{},
+			AbsModuleCall{},
+			false,
+		},
+		{
+			mustParseModuleInstanceStr("module.child"),
+			AbsModuleCall{},
+			false,
+		},
+		{
+			ModuleInstance{},
+			AbsModuleCall{
+				RootModuleInstance,
+				ModuleCall{Name: "child"},
+			},
+			false,
+		},
+		{
+			mustParseModuleInstanceStr("module.child"),
+			AbsModuleCall{ // module.child
+				RootModuleInstance,
+				ModuleCall{Name: "child"},
+			},
+			true,
+		},
+		{
+			mustParseModuleInstanceStr(`module.child`),
+			AbsModuleCall{ // module.kinder.module.child
+				mustParseModuleInstanceStr("module.kinder"),
+				ModuleCall{Name: "child"},
+			},
+			false,
+		},
+		{
+			mustParseModuleInstanceStr("module.kinder"),
+			// module.kinder.module.child contains module.kinder, but is not itself an instance of module.kinder
+			AbsModuleCall{
+				mustParseModuleInstanceStr("module.kinder"),
+				ModuleCall{Name: "child"},
+			},
+			false,
+		},
+		{
+			mustParseModuleInstanceStr("module.child"),
+			AbsModuleCall{
+				mustParseModuleInstanceStr(`module.kinder["a"]`),
+				ModuleCall{Name: "kinder"},
+			},
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%q.IsCallInstance(%q)", test.instance, test.call.String()), func(t *testing.T) {
+			got := test.instance.IsDeclaredByCall(test.call)
+			if got != test.want {
+				t.Fatal("wrong result")
+			}
+		})
+	}
+}
+
+func mustParseModuleInstanceStr(str string) ModuleInstance {
+	mi, diags := ParseModuleInstanceStr(str)
+	if diags.HasErrors() {
+		panic(diags.ErrWithWarnings())
+	}
+	return mi
+}
diff --git a/v1.5.7/internal/addrs/module_package.go b/v1.5.7/internal/addrs/module_package.go
new file mode 100644
index 0000000..b38805b
--- /dev/null
+++ b/v1.5.7/internal/addrs/module_package.go
@@ -0,0 +1,49 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	tfaddr "github.com/hashicorp/terraform-registry-address"
+)
+
+// A ModulePackage represents a physical location where Terraform can retrieve
+// a module package, which is an archive, repository, or other similar
+// container which delivers the source code for one or more Terraform modules.
+//
+// A ModulePackage is a string in go-getter's address syntax. By convention,
+// we use ModulePackage-typed values only for the result of successfully
+// running the go-getter "detectors", which produces an address string which
+// includes an explicit installation method prefix along with an address
+// string in the format expected by that installation method.
+//
+// Note that although the "detector" phase of go-getter does do some simple
+// normalization in certain cases, it isn't generally possible to compare
+// two ModulePackage values to decide if they refer to the same package. Two
+// equal ModulePackage values represent the same package, but there might be
+// other non-equal ModulePackage values that also refer to that package, and
+// there is no reliable way to determine that.
+//
+// Don't convert a user-provided string directly to ModulePackage. Instead,
+// use ParseModuleSource with a remote module address and then access the
+// ModulePackage value from the result, making sure to also handle the
+// selected subdirectory if any. You should convert directly to ModulePackage
+// only for a string that is hard-coded into the program (e.g. in a unit test)
+// where you've ensured that it's already in the expected syntax.
+type ModulePackage string
+
+func (p ModulePackage) String() string {
+	return string(p)
+}
+
+// A ModuleRegistryPackage is an extra indirection over a ModulePackage where
+// we use a module registry to translate a more symbolic address (and
+// associated version constraint given out of band) into a physical source
+// location.
+//
+// ModuleRegistryPackage is distinct from ModulePackage because they have
+// disjoint use-cases: registry package addresses are only used to query a
+// registry in order to find a real module package address. These being
+// distinct is intended to help future maintainers more easily follow the
+// series of steps in the module installer, with the help of the type checker.
+type ModuleRegistryPackage = tfaddr.ModulePackage
diff --git a/v1.5.7/internal/addrs/module_source.go b/v1.5.7/internal/addrs/module_source.go
new file mode 100644
index 0000000..48987a0
--- /dev/null
+++ b/v1.5.7/internal/addrs/module_source.go
@@ -0,0 +1,368 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"path"
+	"strings"
+
+	tfaddr "github.com/hashicorp/terraform-registry-address"
+	"github.com/hashicorp/terraform/internal/getmodules"
+)
+
+// ModuleSource is the general type for all three of the possible module source
+// address types. The concrete implementations of this are ModuleSourceLocal,
+// ModuleSourceRegistry, and ModuleSourceRemote.
+type ModuleSource interface {
+	// String returns a full representation of the address, including any
+	// additional components that are typically implied by omission in
+	// user-written addresses.
+	//
+	// We typically use this longer representation in error message, in case
+	// the inclusion of normally-omitted components is helpful in debugging
+	// unexpected behavior.
+	String() string
+
+	// ForDisplay is similar to String but instead returns a representation of
+	// the idiomatic way to write the address in configuration, omitting
+	// components that are commonly just implied in addresses written by
+	// users.
+	//
+	// We typically use this shorter representation in informational messages,
+	// such as the note that we're about to start downloading a package.
+	ForDisplay() string
+
+	moduleSource()
+}
+
+var _ ModuleSource = ModuleSourceLocal("")
+var _ ModuleSource = ModuleSourceRegistry{}
+var _ ModuleSource = ModuleSourceRemote{}
+
+var moduleSourceLocalPrefixes = []string{
+	"./",
+	"../",
+	".\\",
+	"..\\",
+}
+
+// ParseModuleSource parses a module source address as given in the "source"
+// argument inside a "module" block in the configuration.
+//
+// For historical reasons this syntax is a bit overloaded, supporting three
+// different address types:
+//   - Local paths starting with either ./ or ../, which are special because
+//     Terraform considers them to belong to the same "package" as the caller.
+//   - Module registry addresses, given as either NAMESPACE/NAME/SYSTEM or
+//     HOST/NAMESPACE/NAME/SYSTEM, in which case the remote registry serves
+//     as an indirection over the third address type that follows.
+//   - Various URL-like and other heuristically-recognized strings which
+//     we currently delegate to the external library go-getter.
+//
+// There is some ambiguity between the module registry addresses and go-getter's
+// very liberal heuristics and so this particular function will typically treat
+// an invalid registry address as some other sort of remote source address
+// rather than returning an error. If you know that you're expecting a
+// registry address in particular, use ParseModuleSourceRegistry instead, which
+// can therefore expose more detailed error messages about registry address
+// parsing in particular.
+func ParseModuleSource(raw string) (ModuleSource, error) {
+	if isModuleSourceLocal(raw) {
+		localAddr, err := parseModuleSourceLocal(raw)
+		if err != nil {
+			// This is to make sure we really return a nil ModuleSource in
+			// this case, rather than an interface containing the zero
+			// value of ModuleSourceLocal.
+			return nil, err
+		}
+		return localAddr, nil
+	}
+
+	// For historical reasons, whether an address is a registry
+	// address is defined only by whether it can be successfully
+	// parsed as one, and anything else must fall through to be
+	// parsed as a direct remote source, where go-getter might
+	// then recognize it as a filesystem path. This is odd
+	// but matches behavior we've had since Terraform v0.10 which
+	// existing modules may be relying on.
+	// (Notice that this means that there's never any path where
+	// the registry source parse error gets returned to the caller,
+	// which is annoying but has been true for many releases
+	// without it posing a serious problem in practice.)
+	if ret, err := ParseModuleSourceRegistry(raw); err == nil {
+		return ret, nil
+	}
+
+	// If we get down here then we treat everything else as a
+	// remote address. In practice there's very little that
+	// go-getter doesn't consider invalid input, so even invalid
+	// nonsense will probably interpreted as _something_ here
+	// and then fail during installation instead. We can't
+	// really improve this situation for historical reasons.
+	remoteAddr, err := parseModuleSourceRemote(raw)
+	if err != nil {
+		// This is to make sure we really return a nil ModuleSource in
+		// this case, rather than an interface containing the zero
+		// value of ModuleSourceRemote.
+		return nil, err
+	}
+	return remoteAddr, nil
+}
+
+// ModuleSourceLocal is a ModuleSource representing a local path reference
+// from the caller's directory to the callee's directory within the same
+// module package.
+//
+// A "module package" here means a set of modules distributed together in
+// the same archive, repository, or similar. That's a significant distinction
+// because we always download and cache entire module packages at once,
+// and then create relative references within the same directory in order
+// to ensure all modules in the package are looking at a consistent filesystem
+// layout. We also assume that modules within a package are maintained together,
+// which means that cross-cutting maintenence across all of them would be
+// possible.
+//
+// The actual value of a ModuleSourceLocal is a normalized relative path using
+// forward slashes, even on operating systems that have other conventions,
+// because we're representing traversal within the logical filesystem
+// represented by the containing package, not actually within the physical
+// filesystem we unpacked the package into. We should typically not construct
+// ModuleSourceLocal values directly, except in tests where we can ensure
+// the value meets our assumptions. Use ParseModuleSource instead if the
+// input string is not hard-coded in the program.
+type ModuleSourceLocal string
+
+func parseModuleSourceLocal(raw string) (ModuleSourceLocal, error) {
+	// As long as we have a suitable prefix (detected by ParseModuleSource)
+	// there is no failure case for local paths: we just use the "path"
+	// package's cleaning logic to remove any redundant "./" and "../"
+	// sequences and any duplicate slashes and accept whatever that
+	// produces.
+
+	// Although using backslashes (Windows-style) is non-idiomatic, we do
+	// allow it and just normalize it away, so the rest of Terraform will
+	// only see the forward-slash form.
+	if strings.Contains(raw, `\`) {
+		// Note: We use string replacement rather than filepath.ToSlash
+		// here because the filepath package behavior varies by current
+		// platform, but we want to interpret configured paths the same
+		// across all platforms: these are virtual paths within a module
+		// package, not physical filesystem paths.
+		raw = strings.ReplaceAll(raw, `\`, "/")
+	}
+
+	// Note that we could've historically blocked using "//" in a path here
+	// in order to avoid confusion with the subdir syntax in remote addresses,
+	// but we historically just treated that as the same as a single slash
+	// and so we continue to do that now for compatibility. Clean strips those
+	// out and reduces them to just a single slash.
+	clean := path.Clean(raw)
+
+	// However, we do need to keep a single "./" on the front if it isn't
+	// a "../" path, or else it would be ambigous with the registry address
+	// syntax.
+	if !strings.HasPrefix(clean, "../") {
+		clean = "./" + clean
+	}
+
+	return ModuleSourceLocal(clean), nil
+}
+
+func isModuleSourceLocal(raw string) bool {
+	for _, prefix := range moduleSourceLocalPrefixes {
+		if strings.HasPrefix(raw, prefix) {
+			return true
+		}
+	}
+	return false
+}
+
+func (s ModuleSourceLocal) moduleSource() {}
+
+func (s ModuleSourceLocal) String() string {
+	// We assume that our underlying string was already normalized at
+	// construction, so we just return it verbatim.
+	return string(s)
+}
+
+func (s ModuleSourceLocal) ForDisplay() string {
+	return string(s)
+}
+
+// ModuleSourceRegistry is a ModuleSource representing a module listed in a
+// Terraform module registry.
+//
+// A registry source isn't a direct source location but rather an indirection
+// over a ModuleSourceRemote. The job of a registry is to translate the
+// combination of a ModuleSourceRegistry and a module version number into
+// a concrete ModuleSourceRemote that Terraform will then download and
+// install.
+type ModuleSourceRegistry tfaddr.Module
+
+// DefaultModuleRegistryHost is the hostname used for registry-based module
+// source addresses that do not have an explicit hostname.
+const DefaultModuleRegistryHost = tfaddr.DefaultModuleRegistryHost
+
+// ParseModuleSourceRegistry is a variant of ParseModuleSource which only
+// accepts module registry addresses, and will reject any other address type.
+//
+// Use this instead of ParseModuleSource if you know from some other surrounding
+// context that an address is intended to be a registry address rather than
+// some other address type, which will then allow for better error reporting
+// due to the additional information about user intent.
+func ParseModuleSourceRegistry(raw string) (ModuleSource, error) {
+	// Before we delegate to the "real" function we'll just make sure this
+	// doesn't look like a local source address, so we can return a better
+	// error message for that situation.
+	if isModuleSourceLocal(raw) {
+		return ModuleSourceRegistry{}, fmt.Errorf("can't use local directory %q as a module registry address", raw)
+	}
+
+	src, err := tfaddr.ParseModuleSource(raw)
+	if err != nil {
+		return nil, err
+	}
+	return ModuleSourceRegistry{
+		Package: src.Package,
+		Subdir:  src.Subdir,
+	}, nil
+}
+
+func (s ModuleSourceRegistry) moduleSource() {}
+
+func (s ModuleSourceRegistry) String() string {
+	if s.Subdir != "" {
+		return s.Package.String() + "//" + s.Subdir
+	}
+	return s.Package.String()
+}
+
+func (s ModuleSourceRegistry) ForDisplay() string {
+	if s.Subdir != "" {
+		return s.Package.ForDisplay() + "//" + s.Subdir
+	}
+	return s.Package.ForDisplay()
+}
+
+// ModuleSourceRemote is a ModuleSource representing a remote location from
+// which we can retrieve a module package.
+//
+// A ModuleSourceRemote can optionally include a "subdirectory" path, which
+// means that it's selecting a sub-directory of the given package to use as
+// the entry point into the package.
+type ModuleSourceRemote struct {
+	// Package is the address of the remote package that the requested
+	// module belongs to.
+	Package ModulePackage
+
+	// If Subdir is non-empty then it represents a sub-directory within the
+	// remote package which will serve as the entry-point for the package.
+	//
+	// Subdir uses a normalized forward-slash-based path syntax within the
+	// virtual filesystem represented by the final package. It will never
+	// include `../` or `./` sequences.
+	Subdir string
+}
+
+func parseModuleSourceRemote(raw string) (ModuleSourceRemote, error) {
+	var subDir string
+	raw, subDir = getmodules.SplitPackageSubdir(raw)
+	if strings.HasPrefix(subDir, "../") {
+		return ModuleSourceRemote{}, fmt.Errorf("subdirectory path %q leads outside of the module package", subDir)
+	}
+
+	// A remote source address is really just a go-getter address resulting
+	// from go-getter's "detect" phase, which adds on the prefix specifying
+	// which protocol it should use and possibly also adjusts the
+	// protocol-specific part into different syntax.
+	//
+	// Note that for historical reasons this can potentially do network
+	// requests in order to disambiguate certain address types, although
+	// that's a legacy thing that is only for some specific, less-commonly-used
+	// address types. Most just do local string manipulation. We should
+	// aim to remove the network requests over time, if possible.
+	norm, moreSubDir, err := getmodules.NormalizePackageAddress(raw)
+	if err != nil {
+		// We must pass through the returned error directly here because
+		// the getmodules package has some special error types it uses
+		// for certain cases where the UI layer might want to include a
+		// more helpful error message.
+		return ModuleSourceRemote{}, err
+	}
+
+	if moreSubDir != "" {
+		switch {
+		case subDir != "":
+			// The detector's own subdir goes first, because the
+			// subdir we were given is conceptually relative to
+			// the subdirectory that we just detected.
+			subDir = path.Join(moreSubDir, subDir)
+		default:
+			subDir = path.Clean(moreSubDir)
+		}
+		if strings.HasPrefix(subDir, "../") {
+			// This would suggest a bug in a go-getter detector, but
+			// we'll catch it anyway to avoid doing something confusing
+			// downstream.
+			return ModuleSourceRemote{}, fmt.Errorf("detected subdirectory path %q of %q leads outside of the module package", subDir, norm)
+		}
+	}
+
+	return ModuleSourceRemote{
+		Package: ModulePackage(norm),
+		Subdir:  subDir,
+	}, nil
+}
+
+func (s ModuleSourceRemote) moduleSource() {}
+
+func (s ModuleSourceRemote) String() string {
+	base := s.Package.String()
+
+	if s.Subdir != "" {
+		// Address contains query string
+		if strings.Contains(base, "?") {
+			parts := strings.SplitN(base, "?", 2)
+			return parts[0] + "//" + s.Subdir + "?" + parts[1]
+		}
+		return base + "//" + s.Subdir
+	}
+	return base
+}
+
+func (s ModuleSourceRemote) ForDisplay() string {
+	// The two string representations are identical for this address type.
+	// This isn't really entirely true to the idea of "ForDisplay" since
+	// it'll often include some additional components added in by the
+	// go-getter detectors, but we don't have any function to turn a
+	// "detected" string back into an idiomatic shorthand the user might've
+	// entered.
+	return s.String()
+}
+
+// FromRegistry can be called on a remote source address that was returned
+// from a module registry, passing in the original registry source address
+// that the registry was asked about, in order to get the effective final
+// remote source address.
+//
+// Specifically, this method handles the situations where one or both of
+// the two addresses contain subdirectory paths, combining both when necessary
+// in order to ensure that both the registry's given path and the user's
+// given path are both respected.
+//
+// This will return nonsense if given a registry address other than the one
+// that generated the reciever via a registry lookup.
+func (s ModuleSourceRemote) FromRegistry(given ModuleSourceRegistry) ModuleSourceRemote {
+	ret := s // not a pointer, so this is a shallow copy
+
+	switch {
+	case s.Subdir != "" && given.Subdir != "":
+		ret.Subdir = path.Join(s.Subdir, given.Subdir)
+	case given.Subdir != "":
+		ret.Subdir = given.Subdir
+	}
+
+	return ret
+}
diff --git a/v1.5.7/internal/addrs/module_source_test.go b/v1.5.7/internal/addrs/module_source_test.go
new file mode 100644
index 0000000..5d36621
--- /dev/null
+++ b/v1.5.7/internal/addrs/module_source_test.go
@@ -0,0 +1,633 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	svchost "github.com/hashicorp/terraform-svchost"
+)
+
+func TestParseModuleSource(t *testing.T) {
+	tests := map[string]struct {
+		input   string
+		want    ModuleSource
+		wantErr string
+	}{
+		// Local paths
+		"local in subdirectory": {
+			input: "./child",
+			want:  ModuleSourceLocal("./child"),
+		},
+		"local in subdirectory non-normalized": {
+			input: "./nope/../child",
+			want:  ModuleSourceLocal("./child"),
+		},
+		"local in sibling directory": {
+			input: "../sibling",
+			want:  ModuleSourceLocal("../sibling"),
+		},
+		"local in sibling directory non-normalized": {
+			input: "./nope/../../sibling",
+			want:  ModuleSourceLocal("../sibling"),
+		},
+		"Windows-style local in subdirectory": {
+			input: `.\child`,
+			want:  ModuleSourceLocal("./child"),
+		},
+		"Windows-style local in subdirectory non-normalized": {
+			input: `.\nope\..\child`,
+			want:  ModuleSourceLocal("./child"),
+		},
+		"Windows-style local in sibling directory": {
+			input: `..\sibling`,
+			want:  ModuleSourceLocal("../sibling"),
+		},
+		"Windows-style local in sibling directory non-normalized": {
+			input: `.\nope\..\..\sibling`,
+			want:  ModuleSourceLocal("../sibling"),
+		},
+		"an abominable mix of different slashes": {
+			input: `./nope\nope/why\./please\don't`,
+			want:  ModuleSourceLocal("./nope/nope/why/please/don't"),
+		},
+
+		// Registry addresses
+		// (NOTE: There is another test function TestParseModuleSourceRegistry
+		// which tests this situation more exhaustively, so this is just a
+		// token set of cases to see that we are indeed calling into the
+		// registry address parser when appropriate.)
+		"main registry implied": {
+			input: "hashicorp/subnets/cidr",
+			want: ModuleSourceRegistry{
+				Package: ModuleRegistryPackage{
+					Host:         svchost.Hostname("registry.terraform.io"),
+					Namespace:    "hashicorp",
+					Name:         "subnets",
+					TargetSystem: "cidr",
+				},
+				Subdir: "",
+			},
+		},
+		"main registry implied, subdir": {
+			input: "hashicorp/subnets/cidr//examples/foo",
+			want: ModuleSourceRegistry{
+				Package: ModuleRegistryPackage{
+					Host:         svchost.Hostname("registry.terraform.io"),
+					Namespace:    "hashicorp",
+					Name:         "subnets",
+					TargetSystem: "cidr",
+				},
+				Subdir: "examples/foo",
+			},
+		},
+		"main registry implied, escaping subdir": {
+			input: "hashicorp/subnets/cidr//../nope",
+			// NOTE: This error is actually being caught by the _remote package_
+			// address parser, because any registry parsing failure falls back
+			// to that but both of them have the same subdir validation. This
+			// case is here to make sure that stays true, so we keep reporting
+			// a suitable error when the user writes a registry-looking thing.
+			wantErr: `subdirectory path "../nope" leads outside of the module package`,
+		},
+		"custom registry": {
+			input: "example.com/awesomecorp/network/happycloud",
+			want: ModuleSourceRegistry{
+				Package: ModuleRegistryPackage{
+					Host:         svchost.Hostname("example.com"),
+					Namespace:    "awesomecorp",
+					Name:         "network",
+					TargetSystem: "happycloud",
+				},
+				Subdir: "",
+			},
+		},
+		"custom registry, subdir": {
+			input: "example.com/awesomecorp/network/happycloud//examples/foo",
+			want: ModuleSourceRegistry{
+				Package: ModuleRegistryPackage{
+					Host:         svchost.Hostname("example.com"),
+					Namespace:    "awesomecorp",
+					Name:         "network",
+					TargetSystem: "happycloud",
+				},
+				Subdir: "examples/foo",
+			},
+		},
+
+		// Remote package addresses
+		"github.com shorthand": {
+			input: "github.com/hashicorp/terraform-cidr-subnets",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("git::https://github.com/hashicorp/terraform-cidr-subnets.git"),
+			},
+		},
+		"github.com shorthand, subdir": {
+			input: "github.com/hashicorp/terraform-cidr-subnets//example/foo",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("git::https://github.com/hashicorp/terraform-cidr-subnets.git"),
+				Subdir:  "example/foo",
+			},
+		},
+		"git protocol, URL-style": {
+			input: "git://example.com/code/baz.git",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("git://example.com/code/baz.git"),
+			},
+		},
+		"git protocol, URL-style, subdir": {
+			input: "git://example.com/code/baz.git//bleep/bloop",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("git://example.com/code/baz.git"),
+				Subdir:  "bleep/bloop",
+			},
+		},
+		"git over HTTPS, URL-style": {
+			input: "git::https://example.com/code/baz.git",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("git::https://example.com/code/baz.git"),
+			},
+		},
+		"git over HTTPS, URL-style, subdir": {
+			input: "git::https://example.com/code/baz.git//bleep/bloop",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("git::https://example.com/code/baz.git"),
+				Subdir:  "bleep/bloop",
+			},
+		},
+		"git over HTTPS, URL-style, subdir, query parameters": {
+			input: "git::https://example.com/code/baz.git//bleep/bloop?otherthing=blah",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("git::https://example.com/code/baz.git?otherthing=blah"),
+				Subdir:  "bleep/bloop",
+			},
+		},
+		"git over SSH, URL-style": {
+			input: "git::ssh://git@example.com/code/baz.git",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("git::ssh://git@example.com/code/baz.git"),
+			},
+		},
+		"git over SSH, URL-style, subdir": {
+			input: "git::ssh://git@example.com/code/baz.git//bleep/bloop",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("git::ssh://git@example.com/code/baz.git"),
+				Subdir:  "bleep/bloop",
+			},
+		},
+		"git over SSH, scp-style": {
+			input: "git::git@example.com:code/baz.git",
+			want: ModuleSourceRemote{
+				// Normalized to URL-style
+				Package: ModulePackage("git::ssh://git@example.com/code/baz.git"),
+			},
+		},
+		"git over SSH, scp-style, subdir": {
+			input: "git::git@example.com:code/baz.git//bleep/bloop",
+			want: ModuleSourceRemote{
+				// Normalized to URL-style
+				Package: ModulePackage("git::ssh://git@example.com/code/baz.git"),
+				Subdir:  "bleep/bloop",
+			},
+		},
+
+		// NOTE: We intentionally don't test the bitbucket.org shorthands
+		// here, because that detector makes direct HTTP tequests to the
+		// Bitbucket API and thus isn't appropriate for unit testing.
+
+		"Google Cloud Storage bucket implied, path prefix": {
+			input: "www.googleapis.com/storage/v1/BUCKET_NAME/PATH_TO_MODULE",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("gcs::https://www.googleapis.com/storage/v1/BUCKET_NAME/PATH_TO_MODULE"),
+			},
+		},
+		"Google Cloud Storage bucket, path prefix": {
+			input: "gcs::https://www.googleapis.com/storage/v1/BUCKET_NAME/PATH_TO_MODULE",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("gcs::https://www.googleapis.com/storage/v1/BUCKET_NAME/PATH_TO_MODULE"),
+			},
+		},
+		"Google Cloud Storage bucket implied, archive object": {
+			input: "www.googleapis.com/storage/v1/BUCKET_NAME/PATH/TO/module.zip",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("gcs::https://www.googleapis.com/storage/v1/BUCKET_NAME/PATH/TO/module.zip"),
+			},
+		},
+		"Google Cloud Storage bucket, archive object": {
+			input: "gcs::https://www.googleapis.com/storage/v1/BUCKET_NAME/PATH/TO/module.zip",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("gcs::https://www.googleapis.com/storage/v1/BUCKET_NAME/PATH/TO/module.zip"),
+			},
+		},
+
+		"Amazon S3 bucket implied, archive object": {
+			input: "s3-eu-west-1.amazonaws.com/examplecorp-terraform-modules/vpc.zip",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("s3::https://s3-eu-west-1.amazonaws.com/examplecorp-terraform-modules/vpc.zip"),
+			},
+		},
+		"Amazon S3 bucket, archive object": {
+			input: "s3::https://s3-eu-west-1.amazonaws.com/examplecorp-terraform-modules/vpc.zip",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("s3::https://s3-eu-west-1.amazonaws.com/examplecorp-terraform-modules/vpc.zip"),
+			},
+		},
+
+		"HTTP URL": {
+			input: "http://example.com/module",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("http://example.com/module"),
+			},
+		},
+		"HTTPS URL": {
+			input: "https://example.com/module",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("https://example.com/module"),
+			},
+		},
+		"HTTPS URL, archive file": {
+			input: "https://example.com/module.zip",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("https://example.com/module.zip"),
+			},
+		},
+		"HTTPS URL, forced archive file": {
+			input: "https://example.com/module?archive=tar",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("https://example.com/module?archive=tar"),
+			},
+		},
+		"HTTPS URL, forced archive file and checksum": {
+			input: "https://example.com/module?archive=tar&checksum=blah",
+			want: ModuleSourceRemote{
+				// The query string only actually gets processed when we finally
+				// do the get, so "checksum=blah" is accepted as valid up
+				// at this parsing layer.
+				Package: ModulePackage("https://example.com/module?archive=tar&checksum=blah"),
+			},
+		},
+
+		"absolute filesystem path": {
+			// Although a local directory isn't really "remote", we do
+			// treat it as such because we still need to do all of the same
+			// high-level steps to work with these, even though "downloading"
+			// is replaced by a deep filesystem copy instead.
+			input: "/tmp/foo/example",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("file:///tmp/foo/example"),
+			},
+		},
+		"absolute filesystem path, subdir": {
+			// This is a funny situation where the user wants to use a
+			// directory elsewhere on their system as a package containing
+			// multiple modules, but the entry point is not at the root
+			// of that subtree, and so they can use the usual subdir
+			// syntax to move the package root higher in the real filesystem.
+			input: "/tmp/foo//example",
+			want: ModuleSourceRemote{
+				Package: ModulePackage("file:///tmp/foo"),
+				Subdir:  "example",
+			},
+		},
+
+		"subdir escaping out of package": {
+			// This is general logic for all subdir regardless of installation
+			// protocol, but we're using a filesystem path here just as an
+			// easy placeholder/
+			input:   "/tmp/foo//example/../../invalid",
+			wantErr: `subdirectory path "../invalid" leads outside of the module package`,
+		},
+
+		"relative path without the needed prefix": {
+			input: "boop/bloop",
+			// For this case we return a generic error message from the addrs
+			// layer, but using a specialized error type which our module
+			// installer checks for and produces an extra hint for users who
+			// were intending to write a local path which then got
+			// misinterpreted as a remote source due to the missing prefix.
+			// However, the main message is generic here because this is really
+			// just a general "this string doesn't match any of our source
+			// address patterns" situation, not _necessarily_ about relative
+			// local paths.
+			wantErr: `Terraform cannot detect a supported external module source type for boop/bloop`,
+		},
+
+		"go-getter will accept all sorts of garbage": {
+			input: "dfgdfgsd:dgfhdfghdfghdfg/dfghdfghdfg",
+			want: ModuleSourceRemote{
+				// Unfortunately go-getter doesn't actually reject a totally
+				// invalid address like this until getting time, as long as
+				// it looks somewhat like a URL.
+				Package: ModulePackage("dfgdfgsd:dgfhdfghdfghdfg/dfghdfghdfg"),
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			addr, err := ParseModuleSource(test.input)
+
+			if test.wantErr != "" {
+				switch {
+				case err == nil:
+					t.Errorf("unexpected success\nwant error: %s", test.wantErr)
+				case err.Error() != test.wantErr:
+					t.Errorf("wrong error messages\ngot:  %s\nwant: %s", err.Error(), test.wantErr)
+				}
+				return
+			}
+
+			if err != nil {
+				t.Fatalf("unexpected error: %s", err.Error())
+			}
+
+			if diff := cmp.Diff(addr, test.want); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+	}
+
+}
+
+func TestModuleSourceRemoteFromRegistry(t *testing.T) {
+	t.Run("both have subdir", func(t *testing.T) {
+		remote := ModuleSourceRemote{
+			Package: ModulePackage("boop"),
+			Subdir:  "foo",
+		}
+		registry := ModuleSourceRegistry{
+			Subdir: "bar",
+		}
+		gotAddr := remote.FromRegistry(registry)
+		if remote.Subdir != "foo" {
+			t.Errorf("FromRegistry modified the reciever; should be pure function")
+		}
+		if registry.Subdir != "bar" {
+			t.Errorf("FromRegistry modified the given address; should be pure function")
+		}
+		if got, want := gotAddr.Subdir, "foo/bar"; got != want {
+			t.Errorf("wrong resolved subdir\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run("only remote has subdir", func(t *testing.T) {
+		remote := ModuleSourceRemote{
+			Package: ModulePackage("boop"),
+			Subdir:  "foo",
+		}
+		registry := ModuleSourceRegistry{
+			Subdir: "",
+		}
+		gotAddr := remote.FromRegistry(registry)
+		if remote.Subdir != "foo" {
+			t.Errorf("FromRegistry modified the reciever; should be pure function")
+		}
+		if registry.Subdir != "" {
+			t.Errorf("FromRegistry modified the given address; should be pure function")
+		}
+		if got, want := gotAddr.Subdir, "foo"; got != want {
+			t.Errorf("wrong resolved subdir\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run("only registry has subdir", func(t *testing.T) {
+		remote := ModuleSourceRemote{
+			Package: ModulePackage("boop"),
+			Subdir:  "",
+		}
+		registry := ModuleSourceRegistry{
+			Subdir: "bar",
+		}
+		gotAddr := remote.FromRegistry(registry)
+		if remote.Subdir != "" {
+			t.Errorf("FromRegistry modified the reciever; should be pure function")
+		}
+		if registry.Subdir != "bar" {
+			t.Errorf("FromRegistry modified the given address; should be pure function")
+		}
+		if got, want := gotAddr.Subdir, "bar"; got != want {
+			t.Errorf("wrong resolved subdir\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+}
+
+func TestParseModuleSourceRemote(t *testing.T) {
+
+	tests := map[string]struct {
+		input          string
+		wantString     string
+		wantForDisplay string
+		wantErr        string
+	}{
+		"git over HTTPS, URL-style, query parameters": {
+			// Query parameters should be correctly appended after the Package
+			input:          `git::https://example.com/code/baz.git?otherthing=blah`,
+			wantString:     `git::https://example.com/code/baz.git?otherthing=blah`,
+			wantForDisplay: `git::https://example.com/code/baz.git?otherthing=blah`,
+		},
+		"git over HTTPS, URL-style, subdir, query parameters": {
+			// Query parameters should be correctly appended after the Package and Subdir
+			input:          `git::https://example.com/code/baz.git//bleep/bloop?otherthing=blah`,
+			wantString:     `git::https://example.com/code/baz.git//bleep/bloop?otherthing=blah`,
+			wantForDisplay: `git::https://example.com/code/baz.git//bleep/bloop?otherthing=blah`,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			remote, err := parseModuleSourceRemote(test.input)
+
+			if test.wantErr != "" {
+				switch {
+				case err == nil:
+					t.Errorf("unexpected success\nwant error: %s", test.wantErr)
+				case err.Error() != test.wantErr:
+					t.Errorf("wrong error messages\ngot:  %s\nwant: %s", err.Error(), test.wantErr)
+				}
+				return
+			}
+
+			if err != nil {
+				t.Fatalf("unexpected error: %s", err.Error())
+			}
+
+			if got, want := remote.String(), test.wantString; got != want {
+				t.Errorf("wrong String() result\ngot:  %s\nwant: %s", got, want)
+			}
+			if got, want := remote.ForDisplay(), test.wantForDisplay; got != want {
+				t.Errorf("wrong ForDisplay() result\ngot:  %s\nwant: %s", got, want)
+			}
+		})
+	}
+}
+
+func TestParseModuleSourceRegistry(t *testing.T) {
+	// We test parseModuleSourceRegistry alone here, in addition to testing
+	// it indirectly as part of TestParseModuleSource, because general
+	// module parsing unfortunately eats all of the error situations from
+	// registry passing by falling back to trying for a direct remote package
+	// address.
+
+	// Historical note: These test cases were originally derived from the
+	// ones in the old internal/registry/regsrc package that the
+	// ModuleSourceRegistry type is replacing. That package had the notion
+	// of "normalized" addresses as separate from the original user input,
+	// but this new implementation doesn't try to preserve the original
+	// user input at all, and so the main string output is always normalized.
+	//
+	// That package also had some behaviors to turn the namespace, name, and
+	// remote system portions into lowercase, but apparently we didn't
+	// actually make use of that in the end and were preserving the case
+	// the user provided in the input, and so for backward compatibility
+	// we're continuing to do that here, at the expense of now making the
+	// "ForDisplay" output case-preserving where its predecessor in the
+	// old package wasn't. The main Terraform Registry at registry.terraform.io
+	// is itself case-insensitive anyway, so our case-preserving here is
+	// entirely for the benefit of existing third-party registry
+	// implementations that might be case-sensitive, which we must remain
+	// compatible with now.
+
+	tests := map[string]struct {
+		input           string
+		wantString      string
+		wantForDisplay  string
+		wantForProtocol string
+		wantErr         string
+	}{
+		"public registry": {
+			input:           `hashicorp/consul/aws`,
+			wantString:      `registry.terraform.io/hashicorp/consul/aws`,
+			wantForDisplay:  `hashicorp/consul/aws`,
+			wantForProtocol: `hashicorp/consul/aws`,
+		},
+		"public registry with subdir": {
+			input:           `hashicorp/consul/aws//foo`,
+			wantString:      `registry.terraform.io/hashicorp/consul/aws//foo`,
+			wantForDisplay:  `hashicorp/consul/aws//foo`,
+			wantForProtocol: `hashicorp/consul/aws`,
+		},
+		"public registry using explicit hostname": {
+			input:           `registry.terraform.io/hashicorp/consul/aws`,
+			wantString:      `registry.terraform.io/hashicorp/consul/aws`,
+			wantForDisplay:  `hashicorp/consul/aws`,
+			wantForProtocol: `hashicorp/consul/aws`,
+		},
+		"public registry with mixed case names": {
+			input:           `HashiCorp/Consul/aws`,
+			wantString:      `registry.terraform.io/HashiCorp/Consul/aws`,
+			wantForDisplay:  `HashiCorp/Consul/aws`,
+			wantForProtocol: `HashiCorp/Consul/aws`,
+		},
+		"private registry with non-standard port": {
+			input:           `Example.com:1234/HashiCorp/Consul/aws`,
+			wantString:      `example.com:1234/HashiCorp/Consul/aws`,
+			wantForDisplay:  `example.com:1234/HashiCorp/Consul/aws`,
+			wantForProtocol: `HashiCorp/Consul/aws`,
+		},
+		"private registry with IDN hostname": {
+			input:           `Испытание.com/HashiCorp/Consul/aws`,
+			wantString:      `испытание.com/HashiCorp/Consul/aws`,
+			wantForDisplay:  `испытание.com/HashiCorp/Consul/aws`,
+			wantForProtocol: `HashiCorp/Consul/aws`,
+		},
+		"private registry with IDN hostname and non-standard port": {
+			input:           `Испытание.com:1234/HashiCorp/Consul/aws//Foo`,
+			wantString:      `испытание.com:1234/HashiCorp/Consul/aws//Foo`,
+			wantForDisplay:  `испытание.com:1234/HashiCorp/Consul/aws//Foo`,
+			wantForProtocol: `HashiCorp/Consul/aws`,
+		},
+		"invalid hostname": {
+			input:   `---.com/HashiCorp/Consul/aws`,
+			wantErr: `invalid module registry hostname "---.com"; internationalized domain names must be given as direct unicode characters, not in punycode`,
+		},
+		"hostname with only one label": {
+			// This was historically forbidden in our initial implementation,
+			// so we keep it forbidden to avoid newly interpreting such
+			// addresses as registry addresses rather than remote source
+			// addresses.
+			input:   `foo/var/baz/qux`,
+			wantErr: `invalid module registry hostname: must contain at least one dot`,
+		},
+		"invalid target system characters": {
+			input:   `foo/var/no-no-no`,
+			wantErr: `invalid target system "no-no-no": must be between one and 64 ASCII letters or digits`,
+		},
+		"invalid target system length": {
+			input:   `foo/var/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah`,
+			wantErr: `invalid target system "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah": must be between one and 64 ASCII letters or digits`,
+		},
+		"invalid namespace": {
+			input:   `boop!/var/baz`,
+			wantErr: `invalid namespace "boop!": must be between one and 64 characters, including ASCII letters, digits, dashes, and underscores, where dashes and underscores may not be the prefix or suffix`,
+		},
+		"missing part with explicit hostname": {
+			input:   `foo.com/var/baz`,
+			wantErr: `source address must have three more components after the hostname: the namespace, the name, and the target system`,
+		},
+		"errant query string": {
+			input:   `foo/var/baz?otherthing`,
+			wantErr: `module registry addresses may not include a query string portion`,
+		},
+		"github.com": {
+			// We don't allow using github.com like a module registry because
+			// that conflicts with the historically-supported shorthand for
+			// installing directly from GitHub-hosted git repositories.
+			input:   `github.com/HashiCorp/Consul/aws`,
+			wantErr: `can't use "github.com" as a module registry host, because it's reserved for installing directly from version control repositories`,
+		},
+		"bitbucket.org": {
+			// We don't allow using bitbucket.org like a module registry because
+			// that conflicts with the historically-supported shorthand for
+			// installing directly from BitBucket-hosted git repositories.
+			input:   `bitbucket.org/HashiCorp/Consul/aws`,
+			wantErr: `can't use "bitbucket.org" as a module registry host, because it's reserved for installing directly from version control repositories`,
+		},
+		"local path from current dir": {
+			// Can't use a local path when we're specifically trying to parse
+			// a _registry_ source address.
+			input:   `./boop`,
+			wantErr: `can't use local directory "./boop" as a module registry address`,
+		},
+		"local path from parent dir": {
+			// Can't use a local path when we're specifically trying to parse
+			// a _registry_ source address.
+			input:   `../boop`,
+			wantErr: `can't use local directory "../boop" as a module registry address`,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			addrI, err := ParseModuleSourceRegistry(test.input)
+
+			if test.wantErr != "" {
+				switch {
+				case err == nil:
+					t.Errorf("unexpected success\nwant error: %s", test.wantErr)
+				case err.Error() != test.wantErr:
+					t.Errorf("wrong error messages\ngot:  %s\nwant: %s", err.Error(), test.wantErr)
+				}
+				return
+			}
+
+			if err != nil {
+				t.Fatalf("unexpected error: %s", err.Error())
+			}
+
+			addr, ok := addrI.(ModuleSourceRegistry)
+			if !ok {
+				t.Fatalf("wrong address type %T; want %T", addrI, addr)
+			}
+
+			if got, want := addr.String(), test.wantString; got != want {
+				t.Errorf("wrong String() result\ngot:  %s\nwant: %s", got, want)
+			}
+			if got, want := addr.ForDisplay(), test.wantForDisplay; got != want {
+				t.Errorf("wrong ForDisplay() result\ngot:  %s\nwant: %s", got, want)
+			}
+			if got, want := addr.Package.ForRegistryProtocol(), test.wantForProtocol; got != want {
+				t.Errorf("wrong ForRegistryProtocol() result\ngot:  %s\nwant: %s", got, want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/addrs/module_test.go b/v1.5.7/internal/addrs/module_test.go
new file mode 100644
index 0000000..43bc1b2
--- /dev/null
+++ b/v1.5.7/internal/addrs/module_test.go
@@ -0,0 +1,99 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestModuleEqual_true(t *testing.T) {
+	modules := []Module{
+		RootModule,
+		{"a"},
+		{"a", "b"},
+		{"a", "b", "c"},
+	}
+	for _, m := range modules {
+		t.Run(m.String(), func(t *testing.T) {
+			if !m.Equal(m) {
+				t.Fatalf("expected %#v to be equal to itself", m)
+			}
+		})
+	}
+}
+
+func TestModuleEqual_false(t *testing.T) {
+	testCases := []struct {
+		left  Module
+		right Module
+	}{
+		{
+			RootModule,
+			Module{"a"},
+		},
+		{
+			Module{"a"},
+			Module{"b"},
+		},
+		{
+			Module{"a"},
+			Module{"a", "a"},
+		},
+		{
+			Module{"a", "b"},
+			Module{"a", "B"},
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(fmt.Sprintf("%s = %s", tc.left, tc.right), func(t *testing.T) {
+			if tc.left.Equal(tc.right) {
+				t.Fatalf("expected %#v not to be equal to %#v", tc.left, tc.right)
+			}
+
+			if tc.right.Equal(tc.left) {
+				t.Fatalf("expected %#v not to be equal to %#v", tc.right, tc.left)
+			}
+		})
+	}
+}
+
+func TestModuleString(t *testing.T) {
+	testCases := map[string]Module{
+		"": {},
+		"module.alpha": {
+			"alpha",
+		},
+		"module.alpha.module.beta": {
+			"alpha",
+			"beta",
+		},
+		"module.alpha.module.beta.module.charlie": {
+			"alpha",
+			"beta",
+			"charlie",
+		},
+	}
+	for str, module := range testCases {
+		t.Run(str, func(t *testing.T) {
+			if got, want := module.String(), str; got != want {
+				t.Errorf("wrong result: got %q, want %q", got, want)
+			}
+		})
+	}
+}
+
+func BenchmarkModuleStringShort(b *testing.B) {
+	module := Module{"a", "b"}
+	for n := 0; n < b.N; n++ {
+		module.String()
+	}
+}
+
+func BenchmarkModuleStringLong(b *testing.B) {
+	module := Module{"southamerica-brazil-region", "user-regional-desktop", "user-name"}
+	for n := 0; n < b.N; n++ {
+		module.String()
+	}
+}
diff --git a/v1.5.7/internal/addrs/move_endpoint.go b/v1.5.7/internal/addrs/move_endpoint.go
new file mode 100644
index 0000000..4d54c8e
--- /dev/null
+++ b/v1.5.7/internal/addrs/move_endpoint.go
@@ -0,0 +1,299 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// MoveEndpoint is to AbsMoveable and ConfigMoveable what Target is to
+// Targetable: a wrapping struct that captures the result of decoding an HCL
+// traversal representing a relative path from the current module to
+// a moveable object.
+//
+// Its name reflects that its primary purpose is for the "from" and "to"
+// addresses in a "moved" statement in the configuration, but it's also
+// valid to use MoveEndpoint for other similar mechanisms that give
+// Terraform hints about historical configuration changes that might
+// prompt creating a different plan than Terraform would by default.
+//
+// To obtain a full address from a MoveEndpoint you must use
+// either the package function UnifyMoveEndpoints (to get an AbsMoveable) or
+// the method ConfigMoveable (to get a ConfigMoveable).
+type MoveEndpoint struct {
+	// SourceRange is the location of the physical endpoint address
+	// in configuration, if this MoveEndpoint was decoded from a
+	// configuration expresson.
+	SourceRange tfdiags.SourceRange
+
+	// Internally we (ab)use AbsMoveable as the representation of our
+	// relative address, even though everywhere else in Terraform
+	// AbsMoveable always represents a fully-absolute address.
+	// In practice, due to the implementation of ParseMoveEndpoint,
+	// this is always either a ModuleInstance or an AbsResourceInstance,
+	// and we only consider the possibility of interpreting it as
+	// a AbsModuleCall or an AbsResource in UnifyMoveEndpoints.
+	// This is intentionally unexported to encapsulate this unusual
+	// meaning of AbsMoveable.
+	relSubject AbsMoveable
+}
+
+func (e *MoveEndpoint) ObjectKind() MoveEndpointKind {
+	return absMoveableEndpointKind(e.relSubject)
+}
+
+func (e *MoveEndpoint) String() string {
+	// Our internal pseudo-AbsMoveable representing the relative
+	// address (either ModuleInstance or AbsResourceInstance) is
+	// a good enough proxy for the relative move endpoint address
+	// serialization.
+	return e.relSubject.String()
+}
+
+func (e *MoveEndpoint) Equal(other *MoveEndpoint) bool {
+	switch {
+	case (e == nil) != (other == nil):
+		return false
+	case e == nil:
+		return true
+	default:
+		// Since we only use ModuleInstance and AbsResourceInstance in our
+		// string representation, we have no ambiguity between address types
+		// and can safely just compare the string representations to
+		// compare the relSubject values.
+		return e.String() == other.String() && e.SourceRange == other.SourceRange
+	}
+}
+
+// MightUnifyWith returns true if it is possible that a later call to
+// UnifyMoveEndpoints might succeed if given the reciever and the other
+// given endpoint.
+//
+// This is intended for early static validation of obviously-wrong situations,
+// although there are still various semantic errors that this cannot catch.
+func (e *MoveEndpoint) MightUnifyWith(other *MoveEndpoint) bool {
+	// For our purposes here we'll just do a unify without a base module
+	// address, because the rules for whether unify can succeed depend
+	// only on the relative part of the addresses, not on which module
+	// they were declared in.
+	from, to := UnifyMoveEndpoints(RootModule, e, other)
+	return from != nil && to != nil
+}
+
+// ConfigMovable transforms the reciever into a ConfigMovable by resolving it
+// relative to the given base module, which should be the module where
+// the MoveEndpoint expression was found.
+//
+// The result is useful for finding the target object in the configuration,
+// but it's not sufficient for fully interpreting a move statement because
+// it lacks the specific module and resource instance keys.
+func (e *MoveEndpoint) ConfigMoveable(baseModule Module) ConfigMoveable {
+	addr := e.relSubject
+	switch addr := addr.(type) {
+	case ModuleInstance:
+		ret := make(Module, 0, len(baseModule)+len(addr))
+		ret = append(ret, baseModule...)
+		ret = append(ret, addr.Module()...)
+		return ret
+	case AbsResourceInstance:
+		moduleAddr := make(Module, 0, len(baseModule)+len(addr.Module))
+		moduleAddr = append(moduleAddr, baseModule...)
+		moduleAddr = append(moduleAddr, addr.Module.Module()...)
+		return ConfigResource{
+			Module:   moduleAddr,
+			Resource: addr.Resource.Resource,
+		}
+	default:
+		// The above should be exhaustive for all of the types
+		// that ParseMoveEndpoint produces as our intermediate
+		// address representation.
+		panic(fmt.Sprintf("unsupported address type %T", addr))
+	}
+
+}
+
+// ParseMoveEndpoint attempts to interpret the given traversal as a
+// "move endpoint" address, which is a relative path from the module containing
+// the traversal to a movable object in either the same module or in some
+// child module.
+//
+// This deals only with the syntactic element of a move endpoint expression
+// in configuration. Before the result will be useful you'll need to combine
+// it with the address of the module where it was declared in order to get
+// an absolute address relative to the root module.
+func ParseMoveEndpoint(traversal hcl.Traversal) (*MoveEndpoint, tfdiags.Diagnostics) {
+	path, remain, diags := parseModuleInstancePrefix(traversal)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	rng := tfdiags.SourceRangeFromHCL(traversal.SourceRange())
+
+	if len(remain) == 0 {
+		return &MoveEndpoint{
+			relSubject:  path,
+			SourceRange: rng,
+		}, diags
+	}
+
+	riAddr, moreDiags := parseResourceInstanceUnderModule(path, remain)
+	diags = diags.Append(moreDiags)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	return &MoveEndpoint{
+		relSubject:  riAddr,
+		SourceRange: rng,
+	}, diags
+}
+
+// UnifyMoveEndpoints takes a pair of MoveEndpoint objects representing the
+// "from" and "to" addresses in a moved block, and returns a pair of
+// MoveEndpointInModule addresses guaranteed to be of the same dynamic type
+// that represent what the two MoveEndpoint addresses refer to.
+//
+// moduleAddr must be the address of the module where the move was declared.
+//
+// This function deals both with the conversion from relative to absolute
+// addresses and with resolving the ambiguity between no-key instance
+// addresses and whole-object addresses, returning the least specific
+// address type possible.
+//
+// Not all combinations of addresses are unifyable: the two addresses must
+// either both include resources or both just be modules. If the two
+// given addresses are incompatible then UnifyMoveEndpoints returns (nil, nil),
+// in which case the caller should typically report an error to the user
+// stating the unification constraints.
+func UnifyMoveEndpoints(moduleAddr Module, relFrom, relTo *MoveEndpoint) (modFrom, modTo *MoveEndpointInModule) {
+
+	// First we'll make a decision about which address type we're
+	// ultimately trying to unify to. For our internal purposes
+	// here we're going to borrow TargetableAddrType just as a
+	// convenient way to talk about our address types, even though
+	// targetable address types are not 100% aligned with moveable
+	// address types.
+	fromType := relFrom.internalAddrType()
+	toType := relTo.internalAddrType()
+	var wantType TargetableAddrType
+
+	// Our goal here is to choose the whole-resource or whole-module-call
+	// addresses if both agree on it, but to use specific instance addresses
+	// otherwise. This is a somewhat-arbitrary way to resolve syntactic
+	// ambiguity between the two situations which allows both for renaming
+	// whole resources and for switching from a single-instance object to
+	// a multi-instance object.
+	switch {
+	case fromType == AbsResourceInstanceAddrType || toType == AbsResourceInstanceAddrType:
+		wantType = AbsResourceInstanceAddrType
+	case fromType == AbsResourceAddrType || toType == AbsResourceAddrType:
+		wantType = AbsResourceAddrType
+	case fromType == ModuleInstanceAddrType || toType == ModuleInstanceAddrType:
+		wantType = ModuleInstanceAddrType
+	case fromType == ModuleAddrType || toType == ModuleAddrType:
+		// NOTE: We're fudging a little here and using
+		// ModuleAddrType to represent AbsModuleCall rather
+		// than Module.
+		wantType = ModuleAddrType
+	default:
+		panic("unhandled move address types")
+	}
+
+	modFrom = relFrom.prepareMoveEndpointInModule(moduleAddr, wantType)
+	modTo = relTo.prepareMoveEndpointInModule(moduleAddr, wantType)
+	if modFrom == nil || modTo == nil {
+		// if either of them failed then they both failed, to make the
+		// caller's life a little easier.
+		return nil, nil
+	}
+	return modFrom, modTo
+}
+
+func (e *MoveEndpoint) prepareMoveEndpointInModule(moduleAddr Module, wantType TargetableAddrType) *MoveEndpointInModule {
+	// relAddr can only be either AbsResourceInstance or ModuleInstance, the
+	// internal intermediate representation produced by ParseMoveEndpoint.
+	relAddr := e.relSubject
+
+	switch relAddr := relAddr.(type) {
+	case ModuleInstance:
+		switch wantType {
+		case ModuleInstanceAddrType:
+			// Since our internal representation is already a module instance,
+			// we can just rewrap this one.
+			return &MoveEndpointInModule{
+				SourceRange: e.SourceRange,
+				module:      moduleAddr,
+				relSubject:  relAddr,
+			}
+		case ModuleAddrType:
+			// NOTE: We're fudging a little here and using
+			// ModuleAddrType to represent AbsModuleCall rather
+			// than Module.
+			callerAddr, callAddr := relAddr.Call()
+			absCallAddr := AbsModuleCall{
+				Module: callerAddr,
+				Call:   callAddr,
+			}
+			return &MoveEndpointInModule{
+				SourceRange: e.SourceRange,
+				module:      moduleAddr,
+				relSubject:  absCallAddr,
+			}
+		default:
+			return nil // can't make any other types from a ModuleInstance
+		}
+	case AbsResourceInstance:
+		switch wantType {
+		case AbsResourceInstanceAddrType:
+			return &MoveEndpointInModule{
+				SourceRange: e.SourceRange,
+				module:      moduleAddr,
+				relSubject:  relAddr,
+			}
+		case AbsResourceAddrType:
+			return &MoveEndpointInModule{
+				SourceRange: e.SourceRange,
+				module:      moduleAddr,
+				relSubject:  relAddr.ContainingResource(),
+			}
+		default:
+			return nil // can't make any other types from an AbsResourceInstance
+		}
+	default:
+		panic(fmt.Sprintf("unhandled address type %T", relAddr))
+	}
+}
+
+// internalAddrType helps facilitate our slight abuse of TargetableAddrType
+// as a way to talk about our different possible result address types in
+// UnifyMoveEndpoints.
+//
+// It's not really correct to use TargetableAddrType in this way, because
+// it's for Targetable rather than for AbsMoveable, but as long as the two
+// remain aligned enough it saves introducing yet another enumeration with
+// similar members that would be for internal use only anyway.
+func (e *MoveEndpoint) internalAddrType() TargetableAddrType {
+	switch addr := e.relSubject.(type) {
+	case ModuleInstance:
+		if !addr.IsRoot() && addr[len(addr)-1].InstanceKey == NoKey {
+			// NOTE: We're fudging a little here and using
+			// ModuleAddrType to represent AbsModuleCall rather
+			// than Module.
+			return ModuleAddrType
+		}
+		return ModuleInstanceAddrType
+	case AbsResourceInstance:
+		if addr.Resource.Key == NoKey {
+			return AbsResourceAddrType
+		}
+		return AbsResourceInstanceAddrType
+	default:
+		// The above should cover all of the address types produced
+		// by ParseMoveEndpoint.
+		panic(fmt.Sprintf("unsupported address type %T", addr))
+	}
+}
diff --git a/v1.5.7/internal/addrs/move_endpoint_kind.go b/v1.5.7/internal/addrs/move_endpoint_kind.go
new file mode 100644
index 0000000..c09aa75
--- /dev/null
+++ b/v1.5.7/internal/addrs/move_endpoint_kind.go
@@ -0,0 +1,36 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import "fmt"
+
+// MoveEndpointKind represents the different kinds of object that a movable
+// address can refer to.
+type MoveEndpointKind rune
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type MoveEndpointKind
+
+const (
+	// MoveEndpointModule indicates that a move endpoint either refers to
+	// an individual module instance or to all instances of a particular
+	// module call.
+	MoveEndpointModule MoveEndpointKind = 'M'
+
+	// MoveEndpointResource indicates that a move endpoint either refers to
+	// an individual resource instance or to all instances of a particular
+	// resource.
+	MoveEndpointResource MoveEndpointKind = 'R'
+)
+
+func absMoveableEndpointKind(addr AbsMoveable) MoveEndpointKind {
+	switch addr := addr.(type) {
+	case ModuleInstance, AbsModuleCall:
+		return MoveEndpointModule
+	case AbsResourceInstance, AbsResource:
+		return MoveEndpointResource
+	default:
+		// The above should be exhaustive for all AbsMoveable types.
+		panic(fmt.Sprintf("unsupported address type %T", addr))
+	}
+}
diff --git a/v1.5.7/internal/addrs/move_endpoint_module.go b/v1.5.7/internal/addrs/move_endpoint_module.go
new file mode 100644
index 0000000..186b1ce
--- /dev/null
+++ b/v1.5.7/internal/addrs/move_endpoint_module.go
@@ -0,0 +1,743 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// anyKeyImpl is the InstanceKey representation indicating a wildcard, which
+// matches all possible keys. This is only used internally for matching
+// combinations of address types, where only portions of the path contain key
+// information.
+type anyKeyImpl rune
+
+func (k anyKeyImpl) instanceKeySigil() {
+}
+
+func (k anyKeyImpl) String() string {
+	return fmt.Sprintf("[%s]", string(k))
+}
+
+func (k anyKeyImpl) Value() cty.Value {
+	return cty.StringVal(string(k))
+}
+
+// anyKey is the only valid value of anyKeyImpl
+var anyKey = anyKeyImpl('*')
+
+// MoveEndpointInModule annotates a MoveEndpoint with the address of the
+// module where it was declared, which is the form we use for resolving
+// whether move statements chain from or are nested within other move
+// statements.
+type MoveEndpointInModule struct {
+	// SourceRange is the location of the physical endpoint address
+	// in configuration, if this MoveEndpoint was decoded from a
+	// configuration expresson.
+	SourceRange tfdiags.SourceRange
+
+	// The internals are unexported here because, as with MoveEndpoint,
+	// we're somewhat abusing AbsMoveable here to represent an address
+	// relative to the module, rather than as an absolute address.
+	// Conceptually, the following two fields represent a matching pattern
+	// for AbsMoveables where the elements of "module" behave as
+	// ModuleInstanceStep values with a wildcard instance key, because
+	// a moved block in a module affects all instances of that module.
+	// Unlike MoveEndpoint, relSubject in this case can be any of the
+	// address types that implement AbsMoveable.
+	module     Module
+	relSubject AbsMoveable
+}
+
+// ImpliedMoveStatementEndpoint is a special constructor for MoveEndpointInModule
+// which is suitable only for constructing "implied" move statements, which
+// means that we inferred the statement automatically rather than building it
+// from an explicit block in the configuration.
+//
+// Implied move endpoints, just as for the statements they are embedded in,
+// have somewhat-related-but-imprecise source ranges, typically referring to
+// some general configuration construct that implied the statement, because
+// by definition there is no explicit move endpoint expression in this case.
+func ImpliedMoveStatementEndpoint(addr AbsResourceInstance, rng tfdiags.SourceRange) *MoveEndpointInModule {
+	// implied move endpoints always belong to the root module, because each
+	// one refers to a single resource instance inside a specific module
+	// instance, rather than all instances of the module where the resource
+	// was declared.
+	return &MoveEndpointInModule{
+		SourceRange: rng,
+		module:      RootModule,
+		relSubject:  addr,
+	}
+}
+
+func (e *MoveEndpointInModule) ObjectKind() MoveEndpointKind {
+	return absMoveableEndpointKind(e.relSubject)
+}
+
+// String produces a string representation of the object matching pattern
+// represented by the reciever.
+//
+// Since there is no direct syntax for representing such an object matching
+// pattern, this function uses a splat-operator-like representation to stand
+// in for the wildcard instance keys.
+func (e *MoveEndpointInModule) String() string {
+	if e == nil {
+		return ""
+	}
+	var buf strings.Builder
+	for _, name := range e.module {
+		buf.WriteString("module.")
+		buf.WriteString(name)
+		buf.WriteString("[*].")
+	}
+	buf.WriteString(e.relSubject.String())
+
+	// For consistency we'll also use the splat-like wildcard syntax to
+	// represent the final step being either a resource or module call
+	// rather than an instance, so we can more easily distinguish the two
+	// in the string representation.
+	switch e.relSubject.(type) {
+	case AbsModuleCall, AbsResource:
+		buf.WriteString("[*]")
+	}
+
+	return buf.String()
+}
+
+// Equal returns true if the reciever represents the same matching pattern
+// as the other given endpoint, ignoring the source location information.
+//
+// This is not an optimized function and is here primarily to help with
+// writing concise assertions in test code.
+func (e *MoveEndpointInModule) Equal(other *MoveEndpointInModule) bool {
+	if (e == nil) != (other == nil) {
+		return false
+	}
+	if !e.module.Equal(other.module) {
+		return false
+	}
+	// This assumes that all of our possible "movables" are trivially
+	// comparable with reflect, which is true for all of them at the time
+	// of writing.
+	return reflect.DeepEqual(e.relSubject, other.relSubject)
+}
+
+// Module returns the address of the module where the receiving address was
+// declared.
+func (e *MoveEndpointInModule) Module() Module {
+	return e.module
+}
+
+// InModuleInstance returns an AbsMoveable address which concatenates the
+// given module instance address with the receiver's relative object selection
+// to produce one example of an instance that might be affected by this
+// move statement.
+//
+// The result is meaningful only if the given module instance is an instance
+// of the same module returned by the method Module. InModuleInstance doesn't
+// fully verify that (aside from some cheap/easy checks), but it will produce
+// meaningless garbage if not.
+func (e *MoveEndpointInModule) InModuleInstance(modInst ModuleInstance) AbsMoveable {
+	if len(modInst) != len(e.module) {
+		// We don't check all of the steps to make sure that their names match,
+		// because it would be expensive to do that repeatedly for every
+		// instance of a module, but if the lengths don't match then that's
+		// _obviously_ wrong.
+		panic("given instance address does not match module address")
+	}
+	switch relSubject := e.relSubject.(type) {
+	case ModuleInstance:
+		ret := make(ModuleInstance, 0, len(modInst)+len(relSubject))
+		ret = append(ret, modInst...)
+		ret = append(ret, relSubject...)
+		return ret
+	case AbsModuleCall:
+		retModAddr := make(ModuleInstance, 0, len(modInst)+len(relSubject.Module))
+		retModAddr = append(retModAddr, modInst...)
+		retModAddr = append(retModAddr, relSubject.Module...)
+		return relSubject.Call.Absolute(retModAddr)
+	case AbsResourceInstance:
+		retModAddr := make(ModuleInstance, 0, len(modInst)+len(relSubject.Module))
+		retModAddr = append(retModAddr, modInst...)
+		retModAddr = append(retModAddr, relSubject.Module...)
+		return relSubject.Resource.Absolute(retModAddr)
+	case AbsResource:
+		retModAddr := make(ModuleInstance, 0, len(modInst)+len(relSubject.Module))
+		retModAddr = append(retModAddr, modInst...)
+		retModAddr = append(retModAddr, relSubject.Module...)
+		return relSubject.Resource.Absolute(retModAddr)
+	default:
+		panic(fmt.Sprintf("unexpected move subject type %T", relSubject))
+	}
+}
+
+// ModuleCallTraversals returns both the address of the module where the
+// receiver was declared and any other module calls it traverses through
+// while selecting a particular object to move.
+//
+// This is a rather special-purpose function here mainly to support our
+// validation rule that a module can only traverse down into child modules.
+func (e *MoveEndpointInModule) ModuleCallTraversals() (Module, []ModuleCall) {
+	// We're returning []ModuleCall rather than Module here to make it clearer
+	// that this is a relative sequence of calls rather than an absolute
+	// module path.
+
+	var steps []ModuleInstanceStep
+	switch relSubject := e.relSubject.(type) {
+	case ModuleInstance:
+		// We want all of the steps except the last one here, because the
+		// last one is always selecting something declared in the same module
+		// even though our address structure doesn't capture that.
+		steps = []ModuleInstanceStep(relSubject[:len(relSubject)-1])
+	case AbsModuleCall:
+		steps = []ModuleInstanceStep(relSubject.Module)
+	case AbsResourceInstance:
+		steps = []ModuleInstanceStep(relSubject.Module)
+	case AbsResource:
+		steps = []ModuleInstanceStep(relSubject.Module)
+	default:
+		panic(fmt.Sprintf("unexpected move subject type %T", relSubject))
+	}
+
+	ret := make([]ModuleCall, len(steps))
+	for i, step := range steps {
+		ret[i] = ModuleCall{Name: step.Name}
+	}
+	return e.module, ret
+}
+
+// synthModuleInstance constructs a module instance out of the module path and
+// any module portion of the relSubject, substituting Module and Call segments
+// with ModuleInstanceStep using the anyKey value.
+// This is only used internally for comparison of these complete paths, but
+// does not represent how the individual parts are handled elsewhere in the
+// code.
+func (e *MoveEndpointInModule) synthModuleInstance() ModuleInstance {
+	var inst ModuleInstance
+
+	for _, mod := range e.module {
+		inst = append(inst, ModuleInstanceStep{Name: mod, InstanceKey: anyKey})
+	}
+
+	switch sub := e.relSubject.(type) {
+	case ModuleInstance:
+		inst = append(inst, sub...)
+	case AbsModuleCall:
+		inst = append(inst, sub.Module...)
+		inst = append(inst, ModuleInstanceStep{Name: sub.Call.Name, InstanceKey: anyKey})
+	case AbsResource:
+		inst = append(inst, sub.Module...)
+	case AbsResourceInstance:
+		inst = append(inst, sub.Module...)
+	default:
+		panic(fmt.Sprintf("unhandled relative address type %T", sub))
+	}
+
+	return inst
+}
+
+// SelectsModule returns true if the reciever directly selects either
+// the given module or a resource nested directly inside that module.
+//
+// This is a good function to use to decide which modules in a state
+// to consider when processing a particular move statement. For a
+// module move the given module itself is what will move, while a
+// resource move indicates that we should search each of the resources in
+// the given module to see if they match.
+func (e *MoveEndpointInModule) SelectsModule(addr ModuleInstance) bool {
+	synthInst := e.synthModuleInstance()
+
+	// In order to match the given module instance, our combined path must be
+	// equal in length.
+	if len(synthInst) != len(addr) {
+		return false
+	}
+
+	for i, step := range synthInst {
+		switch step.InstanceKey {
+		case anyKey:
+			// we can match any key as long as the name matches
+			if step.Name != addr[i].Name {
+				return false
+			}
+		default:
+			if step != addr[i] {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+// SelectsResource returns true if the receiver directly selects either
+// the given resource or one of its instances.
+func (e *MoveEndpointInModule) SelectsResource(addr AbsResource) bool {
+	// Only a subset of subject types can possibly select a resource, so
+	// we'll take care of those quickly before we do anything more expensive.
+	switch e.relSubject.(type) {
+	case AbsResource, AbsResourceInstance:
+		// okay
+	default:
+		return false // can't possibly match
+	}
+
+	if !e.SelectsModule(addr.Module) {
+		return false
+	}
+
+	// If we get here then we know the module part matches, so we only need
+	// to worry about the relative resource part.
+	switch relSubject := e.relSubject.(type) {
+	case AbsResource:
+		return addr.Resource.Equal(relSubject.Resource)
+	case AbsResourceInstance:
+		// We intentionally ignore the instance key, because we consider
+		// instances to be part of the resource they belong to.
+		return addr.Resource.Equal(relSubject.Resource.Resource)
+	default:
+		// We should've filtered out all other types above
+		panic(fmt.Sprintf("unsupported relSubject type %T", relSubject))
+	}
+}
+
+// moduleInstanceCanMatch indicates that modA can match modB taking into
+// account steps with an anyKey InstanceKey as wildcards. The comparison of
+// wildcard steps is done symmetrically, because varying portions of either
+// instance's path could have been derived from configuration vs evaluation.
+// The length of modA must be equal or shorter than the length of modB.
+func moduleInstanceCanMatch(modA, modB ModuleInstance) bool {
+	for i, step := range modA {
+		switch {
+		case step.InstanceKey == anyKey || modB[i].InstanceKey == anyKey:
+			// we can match any key as long as the names match
+			if step.Name != modB[i].Name {
+				return false
+			}
+		default:
+			if step != modB[i] {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+// CanChainFrom returns true if the reciever describes an address that could
+// potentially select an object that the other given address could select.
+//
+// In other words, this decides whether the move chaining rule applies, if
+// the reciever is the "to" from one statement and the other given address
+// is the "from" of another statement.
+func (e *MoveEndpointInModule) CanChainFrom(other *MoveEndpointInModule) bool {
+	eMod := e.synthModuleInstance()
+	oMod := other.synthModuleInstance()
+
+	// if the complete paths are different lengths, these cannot refer to the
+	// same value.
+	if len(eMod) != len(oMod) {
+		return false
+	}
+	if !moduleInstanceCanMatch(oMod, eMod) {
+		return false
+	}
+
+	eSub := e.relSubject
+	oSub := other.relSubject
+
+	switch oSub := oSub.(type) {
+	case AbsModuleCall, ModuleInstance:
+		switch eSub.(type) {
+		case AbsModuleCall, ModuleInstance:
+			// we already know the complete module path including any final
+			// module call name is equal.
+			return true
+		}
+
+	case AbsResource:
+		switch eSub := eSub.(type) {
+		case AbsResource:
+			return eSub.Resource.Equal(oSub.Resource)
+		}
+
+	case AbsResourceInstance:
+		switch eSub := eSub.(type) {
+		case AbsResourceInstance:
+			return eSub.Resource.Equal(oSub.Resource)
+		}
+	}
+
+	return false
+}
+
+// NestedWithin returns true if the receiver describes an address that is
+// contained within one of the objects that the given other address could
+// select.
+func (e *MoveEndpointInModule) NestedWithin(other *MoveEndpointInModule) bool {
+	eMod := e.synthModuleInstance()
+	oMod := other.synthModuleInstance()
+
+	// In order to be nested within the given endpoint, the module path must be
+	// shorter or equal.
+	if len(oMod) > len(eMod) {
+		return false
+	}
+
+	if !moduleInstanceCanMatch(oMod, eMod) {
+		return false
+	}
+
+	eSub := e.relSubject
+	oSub := other.relSubject
+
+	switch oSub := oSub.(type) {
+	case AbsModuleCall:
+		switch eSub.(type) {
+		case AbsModuleCall:
+			// we know the other endpoint selects our module, but if we are
+			// also a module call our path must be longer to be nested.
+			return len(eMod) > len(oMod)
+		}
+
+		return true
+
+	case ModuleInstance:
+		switch eSub.(type) {
+		case ModuleInstance, AbsModuleCall:
+			// a nested module must have a longer path
+			return len(eMod) > len(oMod)
+		}
+
+		return true
+
+	case AbsResource:
+		if len(eMod) != len(oMod) {
+			// these resources are from different modules
+			return false
+		}
+
+		// A resource can only contain a resource instance.
+		switch eSub := eSub.(type) {
+		case AbsResourceInstance:
+			return eSub.Resource.Resource.Equal(oSub.Resource)
+		}
+	}
+
+	return false
+}
+
+// matchModuleInstancePrefix is an internal helper to decide whether the given
+// module instance address refers to either the module where the move endpoint
+// was declared or some descendent of that module.
+//
+// If so, it will split the given address into two parts: the "prefix" part
+// which corresponds with the module where the statement was declared, and
+// the "relative" part which is the remainder that the relSubject of the
+// statement might match against.
+//
+// The second return value is another example of our light abuse of
+// ModuleInstance to represent _relative_ module references rather than
+// absolute: it's a module instance address relative to the same return value.
+// Because the exported idea of ModuleInstance represents only _absolute_
+// module instance addresses, we mustn't expose that value through any exported
+// API.
+func (e *MoveEndpointInModule) matchModuleInstancePrefix(instAddr ModuleInstance) (ModuleInstance, ModuleInstance, bool) {
+	if len(e.module) > len(instAddr) {
+		return nil, nil, false // to short to possibly match
+	}
+	for i := range e.module {
+		if e.module[i] != instAddr[i].Name {
+			return nil, nil, false
+		}
+	}
+	// If we get here then we have a match, so we'll slice up the input
+	// to produce the prefix and match segments.
+	return instAddr[:len(e.module)], instAddr[len(e.module):], true
+}
+
+// MoveDestination considers a an address representing a module
+// instance in the context of source and destination move endpoints and then,
+// if the module address matches the from endpoint, returns the corresponding
+// new module address that the object should move to.
+//
+// MoveDestination will return false in its second return value if the receiver
+// doesn't match fromMatch, indicating that the given move statement doesn't
+// apply to this object.
+//
+// Both of the given endpoints must be from the same move statement and thus
+// must have matching object types. If not, MoveDestination will panic.
+func (m ModuleInstance) MoveDestination(fromMatch, toMatch *MoveEndpointInModule) (ModuleInstance, bool) {
+	// NOTE: This implementation assumes the invariant that fromMatch and
+	// toMatch both belong to the same configuration statement, and thus they
+	// will both have the same address type and the same declaration module.
+
+	// The root module instance is not itself moveable.
+	if m.IsRoot() {
+		return nil, false
+	}
+
+	// The two endpoints must either be module call or module instance
+	// addresses, or else this statement can never match.
+	if fromMatch.ObjectKind() != MoveEndpointModule {
+		return nil, false
+	}
+
+	// The rest of our work will be against the part of the reciever that's
+	// relative to the declaration module. mRel is a weird abuse of
+	// ModuleInstance that represents a relative module address, similar to
+	// what we do for MoveEndpointInModule.relSubject.
+	mPrefix, mRel, match := fromMatch.matchModuleInstancePrefix(m)
+	if !match {
+		return nil, false
+	}
+
+	// Our next goal is to split mRel into two parts: the match (if any) and
+	// the suffix. Our result will then replace the match with the replacement
+	// in toMatch while preserving the prefix and suffix.
+	var mSuffix, mNewMatch ModuleInstance
+
+	switch relSubject := fromMatch.relSubject.(type) {
+	case ModuleInstance:
+		if len(relSubject) > len(mRel) {
+			return nil, false // too short to possibly match
+		}
+		for i := range relSubject {
+			if relSubject[i] != mRel[i] {
+				return nil, false // this step doesn't match
+			}
+		}
+		// If we get to here then we've found a match. Since the statement
+		// addresses are already themselves ModuleInstance fragments we can
+		// just slice out the relevant parts.
+		mNewMatch = toMatch.relSubject.(ModuleInstance)
+		mSuffix = mRel[len(relSubject):]
+	case AbsModuleCall:
+		// The module instance part of relSubject must be a prefix of
+		// mRel, and mRel must be at least one step longer to account for
+		// the call step itself.
+		if len(relSubject.Module) > len(mRel)-1 {
+			return nil, false
+		}
+		for i := range relSubject.Module {
+			if relSubject.Module[i] != mRel[i] {
+				return nil, false // this step doesn't match
+			}
+		}
+		// The call name must also match the next step of mRel, after
+		// the relSubject.Module prefix.
+		callStep := mRel[len(relSubject.Module)]
+		if callStep.Name != relSubject.Call.Name {
+			return nil, false
+		}
+		// If we get to here then we've found a match. We need to construct
+		// a new mNewMatch that's an instance of the "new" relSubject with
+		// the same key as our call.
+		mNewMatch = toMatch.relSubject.(AbsModuleCall).Instance(callStep.InstanceKey)
+		mSuffix = mRel[len(relSubject.Module)+1:]
+	default:
+		panic("invalid address type for module-kind move endpoint")
+	}
+
+	ret := make(ModuleInstance, 0, len(mPrefix)+len(mNewMatch)+len(mSuffix))
+	ret = append(ret, mPrefix...)
+	ret = append(ret, mNewMatch...)
+	ret = append(ret, mSuffix...)
+	return ret, true
+}
+
+// MoveDestination considers a an address representing a resource
+// in the context of source and destination move endpoints and then,
+// if the resource address matches the from endpoint, returns the corresponding
+// new resource address that the object should move to.
+//
+// MoveDestination will return false in its second return value if the receiver
+// doesn't match fromMatch, indicating that the given move statement doesn't
+// apply to this object.
+//
+// Both of the given endpoints must be from the same move statement and thus
+// must have matching object types. If not, MoveDestination will panic.
+func (r AbsResource) MoveDestination(fromMatch, toMatch *MoveEndpointInModule) (AbsResource, bool) {
+	switch fromMatch.ObjectKind() {
+	case MoveEndpointModule:
+		// If we've moving a module then any resource inside that module
+		// moves too.
+		fromMod := r.Module
+		toMod, match := fromMod.MoveDestination(fromMatch, toMatch)
+		if !match {
+			return AbsResource{}, false
+		}
+		return r.Resource.Absolute(toMod), true
+
+	case MoveEndpointResource:
+		fromRelSubject, ok := fromMatch.relSubject.(AbsResource)
+		if !ok {
+			// The only other possible type for a resource move is
+			// AbsResourceInstance, and that can never match an AbsResource.
+			return AbsResource{}, false
+		}
+
+		// fromMatch can only possibly match the reciever if the resource
+		// portions are identical, regardless of the module paths.
+		if fromRelSubject.Resource != r.Resource {
+			return AbsResource{}, false
+		}
+
+		// The module path portion of relSubject must have a prefix that
+		// matches the module where our endpoints were declared.
+		mPrefix, mRel, match := fromMatch.matchModuleInstancePrefix(r.Module)
+		if !match {
+			return AbsResource{}, false
+		}
+
+		// The remaining steps of the module path must _exactly_ match
+		// the relative module path in the "fromMatch" address.
+		if len(mRel) != len(fromRelSubject.Module) {
+			return AbsResource{}, false // can't match if lengths are different
+		}
+		for i := range mRel {
+			if mRel[i] != fromRelSubject.Module[i] {
+				return AbsResource{}, false // all of the steps must match
+			}
+		}
+
+		// If we got here then we have a match, and so our result is the
+		// module instance where the statement was declared (mPrefix) followed
+		// by the "to" relative address in toMatch.
+		toRelSubject := toMatch.relSubject.(AbsResource)
+		var mNew ModuleInstance
+		if len(mPrefix) > 0 || len(toRelSubject.Module) > 0 {
+			mNew = make(ModuleInstance, 0, len(mPrefix)+len(toRelSubject.Module))
+			mNew = append(mNew, mPrefix...)
+			mNew = append(mNew, toRelSubject.Module...)
+		}
+		ret := toRelSubject.Resource.Absolute(mNew)
+		return ret, true
+
+	default:
+		panic("unexpected object kind")
+	}
+}
+
+// MoveDestination considers a an address representing a resource
+// instance in the context of source and destination move endpoints and then,
+// if the instance address matches the from endpoint, returns the corresponding
+// new instance address that the object should move to.
+//
+// MoveDestination will return false in its second return value if the receiver
+// doesn't match fromMatch, indicating that the given move statement doesn't
+// apply to this object.
+//
+// Both of the given endpoints must be from the same move statement and thus
+// must have matching object types. If not, MoveDestination will panic.
+func (r AbsResourceInstance) MoveDestination(fromMatch, toMatch *MoveEndpointInModule) (AbsResourceInstance, bool) {
+	switch fromMatch.ObjectKind() {
+	case MoveEndpointModule:
+		// If we've moving a module then any resource inside that module
+		// moves too.
+		fromMod := r.Module
+		toMod, match := fromMod.MoveDestination(fromMatch, toMatch)
+		if !match {
+			return AbsResourceInstance{}, false
+		}
+		return r.Resource.Absolute(toMod), true
+
+	case MoveEndpointResource:
+		switch fromMatch.relSubject.(type) {
+		case AbsResource:
+			oldResource := r.ContainingResource()
+			newResource, match := oldResource.MoveDestination(fromMatch, toMatch)
+			if !match {
+				return AbsResourceInstance{}, false
+			}
+			return newResource.Instance(r.Resource.Key), true
+		case AbsResourceInstance:
+			fromRelSubject, ok := fromMatch.relSubject.(AbsResourceInstance)
+			if !ok {
+				// The only other possible type for a resource move is
+				// AbsResourceInstance, and that can never match an AbsResource.
+				return AbsResourceInstance{}, false
+			}
+
+			// fromMatch can only possibly match the reciever if the resource
+			// portions are identical, regardless of the module paths.
+			if fromRelSubject.Resource != r.Resource {
+				return AbsResourceInstance{}, false
+			}
+
+			// The module path portion of relSubject must have a prefix that
+			// matches the module where our endpoints were declared.
+			mPrefix, mRel, match := fromMatch.matchModuleInstancePrefix(r.Module)
+			if !match {
+				return AbsResourceInstance{}, false
+			}
+
+			// The remaining steps of the module path must _exactly_ match
+			// the relative module path in the "fromMatch" address.
+			if len(mRel) != len(fromRelSubject.Module) {
+				return AbsResourceInstance{}, false // can't match if lengths are different
+			}
+			for i := range mRel {
+				if mRel[i] != fromRelSubject.Module[i] {
+					return AbsResourceInstance{}, false // all of the steps must match
+				}
+			}
+
+			// If we got here then we have a match, and so our result is the
+			// module instance where the statement was declared (mPrefix) followed
+			// by the "to" relative address in toMatch.
+			toRelSubject := toMatch.relSubject.(AbsResourceInstance)
+			var mNew ModuleInstance
+			if len(mPrefix) > 0 || len(toRelSubject.Module) > 0 {
+				mNew = make(ModuleInstance, 0, len(mPrefix)+len(toRelSubject.Module))
+				mNew = append(mNew, mPrefix...)
+				mNew = append(mNew, toRelSubject.Module...)
+			}
+			ret := toRelSubject.Resource.Absolute(mNew)
+			return ret, true
+		default:
+			panic("invalid address type for resource-kind move endpoint")
+		}
+	default:
+		panic("unexpected object kind")
+	}
+}
+
+// IsModuleReIndex takes the From and To endpoints from a single move
+// statement, and returns true if the only changes are to module indexes, and
+// all non-absolute paths remain the same.
+func (from *MoveEndpointInModule) IsModuleReIndex(to *MoveEndpointInModule) bool {
+	// The statements must originate from the same module.
+	if !from.module.Equal(to.module) {
+		panic("cannot compare move expressions from different modules")
+	}
+
+	switch f := from.relSubject.(type) {
+	case AbsModuleCall:
+		switch t := to.relSubject.(type) {
+		case ModuleInstance:
+			// Generate a synthetic module to represent the full address of
+			// the module call. We're not actually comparing indexes, so the
+			// instance doesn't matter.
+			callAddr := f.Instance(NoKey).Module()
+			return callAddr.Equal(t.Module())
+		}
+
+	case ModuleInstance:
+		switch t := to.relSubject.(type) {
+		case AbsModuleCall:
+			callAddr := t.Instance(NoKey).Module()
+			return callAddr.Equal(f.Module())
+
+		case ModuleInstance:
+			return t.Module().Equal(f.Module())
+		}
+	}
+
+	return false
+}
diff --git a/v1.5.7/internal/addrs/move_endpoint_module_test.go b/v1.5.7/internal/addrs/move_endpoint_module_test.go
new file mode 100644
index 0000000..af02205
--- /dev/null
+++ b/v1.5.7/internal/addrs/move_endpoint_module_test.go
@@ -0,0 +1,1748 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestModuleInstanceMoveDestination(t *testing.T) {
+	tests := []struct {
+		DeclModule       string
+		StmtFrom, StmtTo string
+		Receiver         string
+		WantMatch        bool
+		WantResult       string
+	}{
+		{
+			``,
+			`module.foo`,
+			`module.bar`,
+			`module.foo`,
+			true,
+			`module.bar`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.bar`,
+			`module.foo[1]`,
+			true,
+			`module.bar[1]`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.bar`,
+			`module.foo["a"]`,
+			true,
+			`module.bar["a"]`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.bar.module.foo`,
+			`module.foo`,
+			true,
+			`module.bar.module.foo`,
+		},
+		{
+			``,
+			`module.foo.module.bar`,
+			`module.bar`,
+			`module.foo.module.bar`,
+			true,
+			`module.bar`,
+		},
+		{
+			``,
+			`module.foo[1]`,
+			`module.foo[2]`,
+			`module.foo[1]`,
+			true,
+			`module.foo[2]`,
+		},
+		{
+			``,
+			`module.foo[1]`,
+			`module.foo`,
+			`module.foo[1]`,
+			true,
+			`module.foo`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.foo[1]`,
+			`module.foo`,
+			true,
+			`module.foo[1]`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.foo[1]`,
+			`module.foo.module.bar`,
+			true,
+			`module.foo[1].module.bar`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.foo[1]`,
+			`module.foo.module.bar[0]`,
+			true,
+			`module.foo[1].module.bar[0]`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.bar.module.foo`,
+			`module.foo[0]`,
+			true,
+			`module.bar.module.foo[0]`,
+		},
+		{
+			``,
+			`module.foo.module.bar`,
+			`module.bar`,
+			`module.foo.module.bar[0]`,
+			true,
+			`module.bar[0]`,
+		},
+		{
+			`foo`,
+			`module.bar`,
+			`module.baz`,
+			`module.foo.module.bar`,
+			true,
+			`module.foo.module.baz`,
+		},
+		{
+			`foo`,
+			`module.bar`,
+			`module.baz`,
+			`module.foo[1].module.bar`,
+			true,
+			`module.foo[1].module.baz`,
+		},
+		{
+			`foo`,
+			`module.bar`,
+			`module.bar[1]`,
+			`module.foo[1].module.bar`,
+			true,
+			`module.foo[1].module.bar[1]`,
+		},
+		{
+			``,
+			`module.foo[1]`,
+			`module.foo[2]`,
+			`module.foo`,
+			false, // the receiver has a non-matching instance key (NoKey)
+			``,
+		},
+		{
+			``,
+			`module.foo[1]`,
+			`module.foo[2]`,
+			`module.foo[2]`,
+			false, // the receiver is already the "to" address
+			``,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.bar`,
+			``,
+			false, // the root module can never be moved
+			``,
+		},
+		{
+			`foo`,
+			`module.bar`,
+			`module.bar[1]`,
+			`module.boz`,
+			false, // the receiver is outside the declaration module
+			``,
+		},
+		{
+			`foo.bar`,
+			`module.bar`,
+			`module.bar[1]`,
+			`module.boz`,
+			false, // the receiver is outside the declaration module
+			``,
+		},
+		{
+			`foo.bar`,
+			`module.a`,
+			`module.b`,
+			`module.boz`,
+			false, // the receiver is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`module.a1.module.a2`,
+			`module.b1.module.b2`,
+			`module.c`,
+			false, // the receiver is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`module.a1.module.a2[0]`,
+			`module.b1.module.b2[1]`,
+			`module.c`,
+			false, // the receiver is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`module.a1.module.a2`,
+			`module.b1.module.b2`,
+			`module.a1.module.b2`,
+			false, // the receiver is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`module.a1.module.a2`,
+			`module.b1.module.b2`,
+			`module.b1.module.a2`,
+			false, // the receiver is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`module.a1.module.a2[0]`,
+			`module.b1.module.b2[1]`,
+			`module.a1.module.b2[0]`,
+			false, // the receiver is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`foo_instance.bar`,
+			`foo_instance.baz`,
+			`module.foo`,
+			false, // a resource address can never match a module instance
+			``,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(
+			fmt.Sprintf(
+				"%s: %s to %s with %s",
+				test.DeclModule,
+				test.StmtFrom, test.StmtTo,
+				test.Receiver,
+			),
+			func(t *testing.T) {
+
+				parseStmtEP := func(t *testing.T, input string) *MoveEndpoint {
+					t.Helper()
+
+					traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(input), "", hcl.InitialPos)
+					if hclDiags.HasErrors() {
+						// We're not trying to test the HCL parser here, so any
+						// failures at this point are likely to be bugs in the
+						// test case itself.
+						t.Fatalf("syntax error: %s", hclDiags.Error())
+					}
+
+					moveEp, diags := ParseMoveEndpoint(traversal)
+					if diags.HasErrors() {
+						t.Fatalf("unexpected error: %s", diags.Err().Error())
+					}
+					return moveEp
+				}
+
+				fromEPLocal := parseStmtEP(t, test.StmtFrom)
+				toEPLocal := parseStmtEP(t, test.StmtTo)
+
+				declModule := RootModule
+				if test.DeclModule != "" {
+					declModule = strings.Split(test.DeclModule, ".")
+				}
+				fromEP, toEP := UnifyMoveEndpoints(declModule, fromEPLocal, toEPLocal)
+				if fromEP == nil || toEP == nil {
+					t.Fatalf("invalid test case: non-unifyable endpoints\nfrom: %s\nto:   %s", fromEPLocal, toEPLocal)
+				}
+
+				receiverAddr := RootModuleInstance
+				if test.Receiver != "" {
+					var diags tfdiags.Diagnostics
+					receiverAddr, diags = ParseModuleInstanceStr(test.Receiver)
+					if diags.HasErrors() {
+						t.Fatalf("invalid reciever address: %s", diags.Err().Error())
+					}
+				}
+				gotAddr, gotMatch := receiverAddr.MoveDestination(fromEP, toEP)
+				if !test.WantMatch {
+					if gotMatch {
+						t.Errorf("unexpected match\nreceiver: %s\nfrom:     %s\nto:       %s\nresult:   %s", test.Receiver, fromEP, toEP, gotAddr)
+					}
+					return
+				}
+
+				if !gotMatch {
+					t.Errorf("unexpected non-match\nreceiver: %s\nfrom:     %s\nto:       %s", test.Receiver, fromEP, toEP)
+				}
+
+				if gotStr, wantStr := gotAddr.String(), test.WantResult; gotStr != wantStr {
+					t.Errorf("wrong result\ngot:  %s\nwant: %s", gotStr, wantStr)
+				}
+			},
+		)
+	}
+}
+
+func TestAbsResourceInstanceMoveDestination(t *testing.T) {
+	tests := []struct {
+		DeclModule       string
+		StmtFrom, StmtTo string
+		Receiver         string
+		WantMatch        bool
+		WantResult       string
+	}{
+		{
+			``,
+			`test_object.beep`,
+			`test_object.boop`,
+			`test_object.beep`,
+			true,
+			`test_object.boop`,
+		},
+		{
+			``,
+			`test_object.beep`,
+			`test_object.beep[2]`,
+			`test_object.beep`,
+			true,
+			`test_object.beep[2]`,
+		},
+		{
+			``,
+			`test_object.beep`,
+			`module.foo.test_object.beep`,
+			`test_object.beep`,
+			true,
+			`module.foo.test_object.beep`,
+		},
+		{
+			``,
+			`test_object.beep[2]`,
+			`module.foo.test_object.beep["a"]`,
+			`test_object.beep[2]`,
+			true,
+			`module.foo.test_object.beep["a"]`,
+		},
+		{
+			``,
+			`test_object.beep`,
+			`module.foo[0].test_object.beep`,
+			`test_object.beep`,
+			true,
+			`module.foo[0].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo.test_object.beep`,
+			`test_object.beep`,
+			`module.foo.test_object.beep`,
+			true,
+			`test_object.beep`,
+		},
+		{
+			``,
+			`module.foo[0].test_object.beep`,
+			`test_object.beep`,
+			`module.foo[0].test_object.beep`,
+			true,
+			`test_object.beep`,
+		},
+		{
+			`foo`,
+			`test_object.beep`,
+			`test_object.boop`,
+			`module.foo[0].test_object.beep`,
+			true,
+			`module.foo[0].test_object.boop`,
+		},
+		{
+			`foo`,
+			`test_object.beep`,
+			`test_object.beep[1]`,
+			`module.foo[0].test_object.beep`,
+			true,
+			`module.foo[0].test_object.beep[1]`,
+		},
+		{
+			``,
+			`test_object.beep`,
+			`test_object.boop`,
+			`test_object.boop`,
+			false, // the reciever is already the "to" address
+			``,
+		},
+		{
+			``,
+			`test_object.beep[1]`,
+			`test_object.beep[2]`,
+			`test_object.beep[5]`,
+			false, // the receiver has a non-matching instance key
+			``,
+		},
+		{
+			`foo`,
+			`test_object.beep`,
+			`test_object.boop`,
+			`test_object.beep`,
+			false, // the receiver is not inside an instance of module "foo"
+			``,
+		},
+		{
+			`foo.bar`,
+			`test_object.beep`,
+			`test_object.boop`,
+			`test_object.beep`,
+			false, // the receiver is not inside an instance of module "foo.bar"
+			``,
+		},
+		{
+			``,
+			`module.foo[0].test_object.beep`,
+			`test_object.beep`,
+			`module.foo[1].test_object.beep`,
+			false, // receiver is in a different instance of module.foo
+			``,
+		},
+
+		// Moving a module also moves all of the resources declared within it.
+		// The following tests all cover variations of that rule.
+		{
+			``,
+			`module.foo`,
+			`module.bar`,
+			`module.foo.test_object.beep`,
+			true,
+			`module.bar.test_object.beep`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.bar`,
+			`module.foo[1].test_object.beep`,
+			true,
+			`module.bar[1].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.bar`,
+			`module.foo["a"].test_object.beep`,
+			true,
+			`module.bar["a"].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.bar.module.foo`,
+			`module.foo.test_object.beep`,
+			true,
+			`module.bar.module.foo.test_object.beep`,
+		},
+		{
+			``,
+			`module.foo.module.bar`,
+			`module.bar`,
+			`module.foo.module.bar.test_object.beep`,
+			true,
+			`module.bar.test_object.beep`,
+		},
+		{
+			``,
+			`module.foo[1]`,
+			`module.foo[2]`,
+			`module.foo[1].test_object.beep`,
+			true,
+			`module.foo[2].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo[1]`,
+			`module.foo`,
+			`module.foo[1].test_object.beep`,
+			true,
+			`module.foo.test_object.beep`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.foo[1]`,
+			`module.foo.test_object.beep`,
+			true,
+			`module.foo[1].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.foo[1]`,
+			`module.foo.module.bar.test_object.beep`,
+			true,
+			`module.foo[1].module.bar.test_object.beep`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.foo[1]`,
+			`module.foo.module.bar[0].test_object.beep`,
+			true,
+			`module.foo[1].module.bar[0].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.bar.module.foo`,
+			`module.foo[0].test_object.beep`,
+			true,
+			`module.bar.module.foo[0].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo.module.bar`,
+			`module.bar`,
+			`module.foo.module.bar[0].test_object.beep`,
+			true,
+			`module.bar[0].test_object.beep`,
+		},
+		{
+			`foo`,
+			`module.bar`,
+			`module.baz`,
+			`module.foo.module.bar.test_object.beep`,
+			true,
+			`module.foo.module.baz.test_object.beep`,
+		},
+		{
+			`foo`,
+			`module.bar`,
+			`module.baz`,
+			`module.foo[1].module.bar.test_object.beep`,
+			true,
+			`module.foo[1].module.baz.test_object.beep`,
+		},
+		{
+			`foo`,
+			`module.bar`,
+			`module.bar[1]`,
+			`module.foo[1].module.bar.test_object.beep`,
+			true,
+			`module.foo[1].module.bar[1].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo[1]`,
+			`module.foo[2]`,
+			`module.foo.test_object.beep`,
+			false, // the receiver module has a non-matching instance key (NoKey)
+			``,
+		},
+		{
+			``,
+			`module.foo[1]`,
+			`module.foo[2]`,
+			`module.foo[2].test_object.beep`,
+			false, // the receiver is already at the "to" address
+			``,
+		},
+		{
+			`foo`,
+			`module.bar`,
+			`module.bar[1]`,
+			`module.boz.test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			`foo.bar`,
+			`module.bar`,
+			`module.bar[1]`,
+			`module.boz.test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			`foo.bar`,
+			`module.a`,
+			`module.b`,
+			`module.boz.test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`module.a1.module.a2`,
+			`module.b1.module.b2`,
+			`module.c.test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`module.a1.module.a2[0]`,
+			`module.b1.module.b2[1]`,
+			`module.c.test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`module.a1.module.a2`,
+			`module.b1.module.b2`,
+			`module.a1.module.b2.test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`module.a1.module.a2`,
+			`module.b1.module.b2`,
+			`module.b1.module.a2.test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`module.a1.module.a2[0]`,
+			`module.b1.module.b2[1]`,
+			`module.a1.module.b2[0].test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`foo_instance.bar`,
+			`foo_instance.baz`,
+			`module.foo.test_object.beep`,
+			false, // the resource address is unrelated to the move statements
+			``,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(
+			fmt.Sprintf(
+				"%s: %s to %s with %s",
+				test.DeclModule,
+				test.StmtFrom, test.StmtTo,
+				test.Receiver,
+			),
+			func(t *testing.T) {
+
+				parseStmtEP := func(t *testing.T, input string) *MoveEndpoint {
+					t.Helper()
+
+					traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(input), "", hcl.InitialPos)
+					if hclDiags.HasErrors() {
+						// We're not trying to test the HCL parser here, so any
+						// failures at this point are likely to be bugs in the
+						// test case itself.
+						t.Fatalf("syntax error: %s", hclDiags.Error())
+					}
+
+					moveEp, diags := ParseMoveEndpoint(traversal)
+					if diags.HasErrors() {
+						t.Fatalf("unexpected error: %s", diags.Err().Error())
+					}
+					return moveEp
+				}
+
+				fromEPLocal := parseStmtEP(t, test.StmtFrom)
+				toEPLocal := parseStmtEP(t, test.StmtTo)
+
+				declModule := RootModule
+				if test.DeclModule != "" {
+					declModule = strings.Split(test.DeclModule, ".")
+				}
+				fromEP, toEP := UnifyMoveEndpoints(declModule, fromEPLocal, toEPLocal)
+				if fromEP == nil || toEP == nil {
+					t.Fatalf("invalid test case: non-unifyable endpoints\nfrom: %s\nto:   %s", fromEPLocal, toEPLocal)
+				}
+
+				receiverAddr, diags := ParseAbsResourceInstanceStr(test.Receiver)
+				if diags.HasErrors() {
+					t.Fatalf("invalid reciever address: %s", diags.Err().Error())
+				}
+				gotAddr, gotMatch := receiverAddr.MoveDestination(fromEP, toEP)
+				if !test.WantMatch {
+					if gotMatch {
+						t.Errorf("unexpected match\nreceiver: %s\nfrom:     %s\nto:       %s\nresult:   %s", test.Receiver, fromEP, toEP, gotAddr)
+					}
+					return
+				}
+
+				if !gotMatch {
+					t.Fatalf("unexpected non-match\nreceiver: %s (%T)\nfrom:     %s\nto:       %s\ngot:      (no match)\nwant:     %s", test.Receiver, receiverAddr, fromEP, toEP, test.WantResult)
+				}
+
+				if gotStr, wantStr := gotAddr.String(), test.WantResult; gotStr != wantStr {
+					t.Errorf("wrong result\ngot:  %s\nwant: %s", gotStr, wantStr)
+				}
+			},
+		)
+	}
+}
+
+func TestAbsResourceMoveDestination(t *testing.T) {
+	tests := []struct {
+		DeclModule       string
+		StmtFrom, StmtTo string
+		Receiver         string
+		WantMatch        bool
+		WantResult       string
+	}{
+		{
+			``,
+			`test_object.beep`,
+			`test_object.boop`,
+			`test_object.beep`,
+			true,
+			`test_object.boop`,
+		},
+		{
+			``,
+			`test_object.beep`,
+			`module.foo.test_object.beep`,
+			`test_object.beep`,
+			true,
+			`module.foo.test_object.beep`,
+		},
+		{
+			``,
+			`test_object.beep`,
+			`module.foo[0].test_object.beep`,
+			`test_object.beep`,
+			true,
+			`module.foo[0].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo.test_object.beep`,
+			`test_object.beep`,
+			`module.foo.test_object.beep`,
+			true,
+			`test_object.beep`,
+		},
+		{
+			``,
+			`module.foo[0].test_object.beep`,
+			`test_object.beep`,
+			`module.foo[0].test_object.beep`,
+			true,
+			`test_object.beep`,
+		},
+		{
+			`foo`,
+			`test_object.beep`,
+			`test_object.boop`,
+			`module.foo[0].test_object.beep`,
+			true,
+			`module.foo[0].test_object.boop`,
+		},
+		{
+			``,
+			`test_object.beep`,
+			`test_object.boop`,
+			`test_object.boop`,
+			false, // the reciever is already the "to" address
+			``,
+		},
+		{
+			`foo`,
+			`test_object.beep`,
+			`test_object.boop`,
+			`test_object.beep`,
+			false, // the receiver is not inside an instance of module "foo"
+			``,
+		},
+		{
+			`foo.bar`,
+			`test_object.beep`,
+			`test_object.boop`,
+			`test_object.beep`,
+			false, // the receiver is not inside an instance of module "foo.bar"
+			``,
+		},
+		{
+			``,
+			`module.foo[0].test_object.beep`,
+			`test_object.beep`,
+			`module.foo[1].test_object.beep`,
+			false, // receiver is in a different instance of module.foo
+			``,
+		},
+
+		// Moving a module also moves all of the resources declared within it.
+		// The following tests all cover variations of that rule.
+		{
+			``,
+			`module.foo`,
+			`module.bar`,
+			`module.foo.test_object.beep`,
+			true,
+			`module.bar.test_object.beep`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.bar`,
+			`module.foo[1].test_object.beep`,
+			true,
+			`module.bar[1].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.bar`,
+			`module.foo["a"].test_object.beep`,
+			true,
+			`module.bar["a"].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.bar.module.foo`,
+			`module.foo.test_object.beep`,
+			true,
+			`module.bar.module.foo.test_object.beep`,
+		},
+		{
+			``,
+			`module.foo.module.bar`,
+			`module.bar`,
+			`module.foo.module.bar.test_object.beep`,
+			true,
+			`module.bar.test_object.beep`,
+		},
+		{
+			``,
+			`module.foo[1]`,
+			`module.foo[2]`,
+			`module.foo[1].test_object.beep`,
+			true,
+			`module.foo[2].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo[1]`,
+			`module.foo`,
+			`module.foo[1].test_object.beep`,
+			true,
+			`module.foo.test_object.beep`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.foo[1]`,
+			`module.foo.test_object.beep`,
+			true,
+			`module.foo[1].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.foo[1]`,
+			`module.foo.module.bar.test_object.beep`,
+			true,
+			`module.foo[1].module.bar.test_object.beep`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.foo[1]`,
+			`module.foo.module.bar[0].test_object.beep`,
+			true,
+			`module.foo[1].module.bar[0].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo`,
+			`module.bar.module.foo`,
+			`module.foo[0].test_object.beep`,
+			true,
+			`module.bar.module.foo[0].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo.module.bar`,
+			`module.bar`,
+			`module.foo.module.bar[0].test_object.beep`,
+			true,
+			`module.bar[0].test_object.beep`,
+		},
+		{
+			`foo`,
+			`module.bar`,
+			`module.baz`,
+			`module.foo.module.bar.test_object.beep`,
+			true,
+			`module.foo.module.baz.test_object.beep`,
+		},
+		{
+			`foo`,
+			`module.bar`,
+			`module.baz`,
+			`module.foo[1].module.bar.test_object.beep`,
+			true,
+			`module.foo[1].module.baz.test_object.beep`,
+		},
+		{
+			`foo`,
+			`module.bar`,
+			`module.bar[1]`,
+			`module.foo[1].module.bar.test_object.beep`,
+			true,
+			`module.foo[1].module.bar[1].test_object.beep`,
+		},
+		{
+			``,
+			`module.foo[1]`,
+			`module.foo[2]`,
+			`module.foo.test_object.beep`,
+			false, // the receiver module has a non-matching instance key (NoKey)
+			``,
+		},
+		{
+			``,
+			`module.foo[1]`,
+			`module.foo[2]`,
+			`module.foo[2].test_object.beep`,
+			false, // the receiver is already at the "to" address
+			``,
+		},
+		{
+			`foo`,
+			`module.bar`,
+			`module.bar[1]`,
+			`module.boz.test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			`foo.bar`,
+			`module.bar`,
+			`module.bar[1]`,
+			`module.boz.test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			`foo.bar`,
+			`module.a`,
+			`module.b`,
+			`module.boz.test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`module.a1.module.a2`,
+			`module.b1.module.b2`,
+			`module.c.test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`module.a1.module.a2[0]`,
+			`module.b1.module.b2[1]`,
+			`module.c.test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`module.a1.module.a2`,
+			`module.b1.module.b2`,
+			`module.a1.module.b2.test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`module.a1.module.a2`,
+			`module.b1.module.b2`,
+			`module.b1.module.a2.test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`module.a1.module.a2[0]`,
+			`module.b1.module.b2[1]`,
+			`module.a1.module.b2[0].test_object.beep`,
+			false, // the receiver module is outside the declaration module
+			``,
+		},
+		{
+			``,
+			`foo_instance.bar`,
+			`foo_instance.baz`,
+			`module.foo.test_object.beep`,
+			false, // the resource address is unrelated to the move statements
+			``,
+		},
+	}
+
+	for i, test := range tests {
+		t.Run(
+			fmt.Sprintf(
+				"[%02d] %s: %s to %s with %s",
+				i,
+				test.DeclModule,
+				test.StmtFrom, test.StmtTo,
+				test.Receiver,
+			),
+			func(t *testing.T) {
+
+				parseStmtEP := func(t *testing.T, input string) *MoveEndpoint {
+					t.Helper()
+
+					traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(input), "", hcl.InitialPos)
+					if hclDiags.HasErrors() {
+						// We're not trying to test the HCL parser here, so any
+						// failures at this point are likely to be bugs in the
+						// test case itself.
+						t.Fatalf("syntax error: %s", hclDiags.Error())
+					}
+
+					moveEp, diags := ParseMoveEndpoint(traversal)
+					if diags.HasErrors() {
+						t.Fatalf("unexpected error: %s", diags.Err().Error())
+					}
+					return moveEp
+				}
+
+				fromEPLocal := parseStmtEP(t, test.StmtFrom)
+				toEPLocal := parseStmtEP(t, test.StmtTo)
+
+				declModule := RootModule
+				if test.DeclModule != "" {
+					declModule = strings.Split(test.DeclModule, ".")
+				}
+				fromEP, toEP := UnifyMoveEndpoints(declModule, fromEPLocal, toEPLocal)
+				if fromEP == nil || toEP == nil {
+					t.Fatalf("invalid test case: non-unifyable endpoints\nfrom: %s\nto:   %s", fromEPLocal, toEPLocal)
+				}
+
+				// We only have an AbsResourceInstance parser, not an
+				// AbsResourceParser, and so we'll just cheat and parse this
+				// as a resource instance but fail if it includes an instance
+				// key.
+				receiverInstanceAddr, diags := ParseAbsResourceInstanceStr(test.Receiver)
+				if diags.HasErrors() {
+					t.Fatalf("invalid reciever address: %s", diags.Err().Error())
+				}
+				if receiverInstanceAddr.Resource.Key != NoKey {
+					t.Fatalf("invalid reciever address: must be a resource, not a resource instance")
+				}
+				receiverAddr := receiverInstanceAddr.ContainingResource()
+				gotAddr, gotMatch := receiverAddr.MoveDestination(fromEP, toEP)
+				if !test.WantMatch {
+					if gotMatch {
+						t.Errorf("unexpected match\nreceiver: %s (%T)\nfrom:     %s\nto:       %s\nresult:   %s", test.Receiver, receiverAddr, fromEP, toEP, gotAddr)
+					}
+					return
+				}
+
+				if !gotMatch {
+					t.Fatalf("unexpected non-match\nreceiver: %s (%T)\nfrom:     %s\nto:       %s\ngot:      no match\nwant:     %s", test.Receiver, receiverAddr, fromEP, toEP, test.WantResult)
+				}
+
+				if gotStr, wantStr := gotAddr.String(), test.WantResult; gotStr != wantStr {
+					t.Errorf("wrong result\ngot:  %s\nwant: %s", gotStr, wantStr)
+				}
+			},
+		)
+	}
+}
+
+func TestMoveEndpointChainAndNested(t *testing.T) {
+	tests := []struct {
+		Endpoint, Other            AbsMoveable
+		EndpointMod, OtherMod      Module
+		CanChainFrom, NestedWithin bool
+	}{
+		{
+			Endpoint: AbsModuleCall{
+				Module: mustParseModuleInstanceStr("module.foo[2]"),
+				Call:   ModuleCall{Name: "bar"},
+			},
+			Other: AbsModuleCall{
+				Module: mustParseModuleInstanceStr("module.foo[2]"),
+				Call:   ModuleCall{Name: "bar"},
+			},
+			CanChainFrom: true,
+			NestedWithin: false,
+		},
+
+		{
+			Endpoint: mustParseModuleInstanceStr("module.foo[2]"),
+			Other: AbsModuleCall{
+				Module: mustParseModuleInstanceStr("module.foo[2]"),
+				Call:   ModuleCall{Name: "bar"},
+			},
+			CanChainFrom: false,
+			NestedWithin: false,
+		},
+
+		{
+			Endpoint: mustParseModuleInstanceStr("module.foo[2].module.bar[2]"),
+			Other: AbsModuleCall{
+				Module: RootModuleInstance,
+				Call:   ModuleCall{Name: "foo"},
+			},
+			CanChainFrom: false,
+			NestedWithin: true,
+		},
+
+		{
+			Endpoint: mustParseAbsResourceInstanceStr("module.foo[2].module.bar.resource.baz").ContainingResource(),
+			Other: AbsModuleCall{
+				Module: mustParseModuleInstanceStr("module.foo[2]"),
+				Call:   ModuleCall{Name: "bar"},
+			},
+			CanChainFrom: false,
+			NestedWithin: true,
+		},
+
+		{
+			Endpoint: mustParseAbsResourceInstanceStr("module.foo[2].module.bar[3].resource.baz[2]"),
+			Other: AbsModuleCall{
+				Module: mustParseModuleInstanceStr("module.foo[2]"),
+				Call:   ModuleCall{Name: "bar"},
+			},
+			CanChainFrom: false,
+			NestedWithin: true,
+		},
+
+		{
+			Endpoint: AbsModuleCall{
+				Module: mustParseModuleInstanceStr("module.foo[2]"),
+				Call:   ModuleCall{Name: "bar"},
+			},
+			Other:        mustParseModuleInstanceStr("module.foo[2]"),
+			CanChainFrom: false,
+			NestedWithin: true,
+		},
+
+		{
+			Endpoint:     mustParseModuleInstanceStr("module.foo[2]"),
+			Other:        mustParseModuleInstanceStr("module.foo[2]"),
+			CanChainFrom: true,
+			NestedWithin: false,
+		},
+
+		{
+			Endpoint:     mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(),
+			Other:        mustParseModuleInstanceStr("module.foo[2]"),
+			CanChainFrom: false,
+			NestedWithin: true,
+		},
+
+		{
+			Endpoint:     mustParseAbsResourceInstanceStr("module.foo[2].module.bar.resource.baz"),
+			Other:        mustParseModuleInstanceStr("module.foo[2]"),
+			CanChainFrom: false,
+			NestedWithin: true,
+		},
+
+		{
+			Endpoint: AbsModuleCall{
+				Module: mustParseModuleInstanceStr("module.foo[2]"),
+				Call:   ModuleCall{Name: "bar"},
+			},
+			Other:        mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(),
+			CanChainFrom: false,
+			NestedWithin: false,
+		},
+
+		{
+			Endpoint:     mustParseModuleInstanceStr("module.foo[2]"),
+			Other:        mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(),
+			CanChainFrom: false,
+			NestedWithin: false,
+		},
+
+		{
+			Endpoint:     mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(),
+			Other:        mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(),
+			CanChainFrom: true,
+			NestedWithin: false,
+		},
+
+		{
+			Endpoint:     mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"),
+			Other:        mustParseAbsResourceInstanceStr("module.foo[2].resource.baz[2]").ContainingResource(),
+			CanChainFrom: false,
+			NestedWithin: true,
+		},
+
+		{
+			Endpoint: AbsModuleCall{
+				Module: mustParseModuleInstanceStr("module.foo[2]"),
+				Call:   ModuleCall{Name: "bar"},
+			},
+			Other:        mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"),
+			CanChainFrom: false,
+		},
+
+		{
+			Endpoint:     mustParseModuleInstanceStr("module.foo[2]"),
+			Other:        mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"),
+			CanChainFrom: false,
+		},
+		{
+			Endpoint:     mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(),
+			Other:        mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"),
+			CanChainFrom: false,
+		},
+
+		{
+			Endpoint:     mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"),
+			Other:        mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"),
+			CanChainFrom: true,
+		},
+
+		{
+			Endpoint:     mustParseAbsResourceInstanceStr("resource.baz"),
+			EndpointMod:  Module{"foo"},
+			Other:        mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"),
+			CanChainFrom: true,
+		},
+
+		{
+			Endpoint:     mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"),
+			Other:        mustParseAbsResourceInstanceStr("resource.baz"),
+			OtherMod:     Module{"foo"},
+			CanChainFrom: true,
+		},
+
+		{
+			Endpoint:     mustParseAbsResourceInstanceStr("resource.baz"),
+			EndpointMod:  Module{"foo"},
+			Other:        mustParseAbsResourceInstanceStr("resource.baz"),
+			OtherMod:     Module{"foo"},
+			CanChainFrom: true,
+		},
+
+		{
+			Endpoint:     mustParseAbsResourceInstanceStr("resource.baz").ContainingResource(),
+			EndpointMod:  Module{"foo"},
+			Other:        mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(),
+			CanChainFrom: true,
+		},
+
+		{
+			Endpoint:     mustParseModuleInstanceStr("module.foo[2].module.baz"),
+			Other:        mustParseModuleInstanceStr("module.baz"),
+			OtherMod:     Module{"foo"},
+			CanChainFrom: true,
+		},
+
+		{
+			Endpoint: AbsModuleCall{
+				Call: ModuleCall{Name: "bing"},
+			},
+			EndpointMod: Module{"foo", "baz"},
+			Other: AbsModuleCall{
+				Module: mustParseModuleInstanceStr("module.baz"),
+				Call:   ModuleCall{Name: "bing"},
+			},
+			OtherMod:     Module{"foo"},
+			CanChainFrom: true,
+		},
+
+		{
+			Endpoint:     mustParseAbsResourceInstanceStr("resource.baz"),
+			EndpointMod:  Module{"foo"},
+			Other:        mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(),
+			NestedWithin: true,
+		},
+
+		{
+			Endpoint:     mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"),
+			Other:        mustParseAbsResourceInstanceStr("resource.baz").ContainingResource(),
+			OtherMod:     Module{"foo"},
+			NestedWithin: true,
+		},
+
+		{
+			Endpoint:     mustParseAbsResourceInstanceStr("resource.baz"),
+			EndpointMod:  Module{"foo"},
+			Other:        mustParseAbsResourceInstanceStr("resource.baz").ContainingResource(),
+			OtherMod:     Module{"foo"},
+			NestedWithin: true,
+		},
+
+		{
+			Endpoint:     mustParseAbsResourceInstanceStr("ressurce.baz").ContainingResource(),
+			EndpointMod:  Module{"foo"},
+			Other:        mustParseModuleInstanceStr("module.foo[2]"),
+			NestedWithin: true,
+		},
+
+		{
+			Endpoint: AbsModuleCall{
+				Call: ModuleCall{Name: "bang"},
+			},
+			EndpointMod: Module{"foo", "baz", "bing"},
+			Other: AbsModuleCall{
+				Module: mustParseModuleInstanceStr("module.baz"),
+				Call:   ModuleCall{Name: "bing"},
+			},
+			OtherMod:     Module{"foo"},
+			NestedWithin: true,
+		},
+
+		{
+			Endpoint: AbsModuleCall{
+				Module: mustParseModuleInstanceStr("module.bing"),
+				Call:   ModuleCall{Name: "bang"},
+			},
+			EndpointMod: Module{"foo", "baz"},
+			Other: AbsModuleCall{
+				Module: mustParseModuleInstanceStr("module.foo.module.baz"),
+				Call:   ModuleCall{Name: "bing"},
+			},
+			NestedWithin: true,
+		},
+	}
+
+	for i, test := range tests {
+		t.Run(fmt.Sprintf("[%02d]%s.CanChainFrom(%s)", i, test.Endpoint, test.Other),
+			func(t *testing.T) {
+				endpoint := &MoveEndpointInModule{
+					relSubject: test.Endpoint,
+					module:     test.EndpointMod,
+				}
+
+				other := &MoveEndpointInModule{
+					relSubject: test.Other,
+					module:     test.OtherMod,
+				}
+
+				if endpoint.CanChainFrom(other) != test.CanChainFrom {
+					t.Errorf("expected %s CanChainFrom %s == %t", endpoint, other, test.CanChainFrom)
+				}
+
+				if endpoint.NestedWithin(other) != test.NestedWithin {
+					t.Errorf("expected %s NestedWithin %s == %t", endpoint, other, test.NestedWithin)
+				}
+			},
+		)
+	}
+}
+
+func TestSelectsModule(t *testing.T) {
+	tests := []struct {
+		Endpoint *MoveEndpointInModule
+		Addr     ModuleInstance
+		Selects  bool
+	}{
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: AbsModuleCall{
+					Module: mustParseModuleInstanceStr("module.foo[2]"),
+					Call:   ModuleCall{Name: "bar"},
+				},
+			},
+			Addr:    mustParseModuleInstanceStr("module.foo[2].module.bar[1]"),
+			Selects: true,
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				module: mustParseModuleInstanceStr("module.foo").Module(),
+				relSubject: AbsModuleCall{
+					Module: mustParseModuleInstanceStr("module.bar[2]"),
+					Call:   ModuleCall{Name: "baz"},
+				},
+			},
+			Addr:    mustParseModuleInstanceStr("module.foo[2].module.bar[2].module.baz"),
+			Selects: true,
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				module: mustParseModuleInstanceStr("module.foo").Module(),
+				relSubject: AbsModuleCall{
+					Module: mustParseModuleInstanceStr("module.bar[2]"),
+					Call:   ModuleCall{Name: "baz"},
+				},
+			},
+			Addr:    mustParseModuleInstanceStr("module.foo[2].module.bar[1].module.baz"),
+			Selects: false,
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: AbsModuleCall{
+					Module: mustParseModuleInstanceStr("module.bar"),
+					Call:   ModuleCall{Name: "baz"},
+				},
+			},
+			Addr:    mustParseModuleInstanceStr("module.bar[1].module.baz"),
+			Selects: false,
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				module:     mustParseModuleInstanceStr("module.foo").Module(),
+				relSubject: mustParseAbsResourceInstanceStr(`module.bar.resource.name["key"]`),
+			},
+			Addr:    mustParseModuleInstanceStr(`module.foo[1].module.bar`),
+			Selects: true,
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: mustParseModuleInstanceStr(`module.bar.module.baz["key"]`),
+			},
+			Addr:    mustParseModuleInstanceStr(`module.bar.module.baz["key"]`),
+			Selects: true,
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: mustParseAbsResourceInstanceStr(`module.bar.module.baz["key"].resource.name`).ContainingResource(),
+			},
+			Addr:    mustParseModuleInstanceStr(`module.bar.module.baz["key"]`),
+			Selects: true,
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				module:     mustParseModuleInstanceStr("module.nope").Module(),
+				relSubject: mustParseAbsResourceInstanceStr(`module.bar.resource.name["key"]`),
+			},
+			Addr:    mustParseModuleInstanceStr(`module.foo[1].module.bar`),
+			Selects: false,
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: mustParseModuleInstanceStr(`module.bar.module.baz["key"]`),
+			},
+			Addr:    mustParseModuleInstanceStr(`module.bar.module.baz["nope"]`),
+			Selects: false,
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: mustParseAbsResourceInstanceStr(`module.nope.module.baz["key"].resource.name`).ContainingResource(),
+			},
+			Addr:    mustParseModuleInstanceStr(`module.bar.module.baz["key"]`),
+			Selects: false,
+		},
+	}
+
+	for i, test := range tests {
+		t.Run(fmt.Sprintf("[%02d]%s.SelectsModule(%s)", i, test.Endpoint, test.Addr),
+			func(t *testing.T) {
+				if test.Endpoint.SelectsModule(test.Addr) != test.Selects {
+					t.Errorf("expected %s SelectsModule %s == %t", test.Endpoint, test.Addr, test.Selects)
+				}
+			},
+		)
+	}
+}
+
+func TestSelectsResource(t *testing.T) {
+	matchingResource := Resource{
+		Mode: ManagedResourceMode,
+		Type: "foo",
+		Name: "matching",
+	}
+	unmatchingResource := Resource{
+		Mode: ManagedResourceMode,
+		Type: "foo",
+		Name: "unmatching",
+	}
+	childMod := Module{
+		"child",
+	}
+	childModMatchingInst := ModuleInstance{
+		ModuleInstanceStep{Name: "child", InstanceKey: StringKey("matching")},
+	}
+	childModUnmatchingInst := ModuleInstance{
+		ModuleInstanceStep{Name: "child", InstanceKey: StringKey("unmatching")},
+	}
+
+	tests := []struct {
+		Endpoint *MoveEndpointInModule
+		Addr     AbsResource
+		Selects  bool
+	}{
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: matchingResource.Absolute(nil),
+			},
+			Addr:    matchingResource.Absolute(nil),
+			Selects: true, // exact match
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: unmatchingResource.Absolute(nil),
+			},
+			Addr:    matchingResource.Absolute(nil),
+			Selects: false, // wrong resource name
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: unmatchingResource.Instance(IntKey(1)).Absolute(nil),
+			},
+			Addr:    matchingResource.Absolute(nil),
+			Selects: false, // wrong resource name
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: matchingResource.Instance(NoKey).Absolute(nil),
+			},
+			Addr:    matchingResource.Absolute(nil),
+			Selects: true, // matches one instance
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: matchingResource.Instance(IntKey(0)).Absolute(nil),
+			},
+			Addr:    matchingResource.Absolute(nil),
+			Selects: true, // matches one instance
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: matchingResource.Instance(StringKey("a")).Absolute(nil),
+			},
+			Addr:    matchingResource.Absolute(nil),
+			Selects: true, // matches one instance
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				module:     childMod,
+				relSubject: matchingResource.Absolute(nil),
+			},
+			Addr:    matchingResource.Absolute(childModMatchingInst),
+			Selects: true, // in one of the instances of the module where the statement was written
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: matchingResource.Absolute(childModMatchingInst),
+			},
+			Addr:    matchingResource.Absolute(childModMatchingInst),
+			Selects: true, // exact match
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: matchingResource.Instance(IntKey(2)).Absolute(childModMatchingInst),
+			},
+			Addr:    matchingResource.Absolute(childModMatchingInst),
+			Selects: true, // matches one instance
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: matchingResource.Absolute(childModMatchingInst),
+			},
+			Addr:    matchingResource.Absolute(childModUnmatchingInst),
+			Selects: false, // the containing module instance doesn't match
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: AbsModuleCall{
+					Module: mustParseModuleInstanceStr("module.foo[2]"),
+					Call:   ModuleCall{Name: "bar"},
+				},
+			},
+			Addr:    matchingResource.Absolute(mustParseModuleInstanceStr("module.foo[2]")),
+			Selects: false, // a module call can't match a resource
+		},
+		{
+			Endpoint: &MoveEndpointInModule{
+				relSubject: mustParseModuleInstanceStr("module.foo[2]"),
+			},
+			Addr:    matchingResource.Absolute(mustParseModuleInstanceStr("module.foo[2]")),
+			Selects: false, // a module instance can't match a resource
+		},
+	}
+
+	for i, test := range tests {
+		t.Run(fmt.Sprintf("[%02d]%s SelectsResource(%s)", i, test.Endpoint, test.Addr),
+			func(t *testing.T) {
+				if got, want := test.Endpoint.SelectsResource(test.Addr), test.Selects; got != want {
+					t.Errorf("wrong result\nReceiver: %s\nArgument: %s\ngot:  %t\nwant: %t", test.Endpoint, test.Addr, got, want)
+				}
+			},
+		)
+	}
+}
+
+func TestIsModuleMoveReIndex(t *testing.T) {
+	tests := []struct {
+		from, to AbsMoveable
+		expect   bool
+	}{
+		{
+			from:   mustParseModuleInstanceStr(`module.bar`),
+			to:     mustParseModuleInstanceStr(`module.bar`),
+			expect: true,
+		},
+		{
+			from:   mustParseModuleInstanceStr(`module.bar`),
+			to:     mustParseModuleInstanceStr(`module.bar[0]`),
+			expect: true,
+		},
+		{
+			from: AbsModuleCall{
+				Call: ModuleCall{Name: "bar"},
+			},
+			to:     mustParseModuleInstanceStr(`module.bar[0]`),
+			expect: true,
+		},
+		{
+			from: mustParseModuleInstanceStr(`module.bar["a"]`),
+			to: AbsModuleCall{
+				Call: ModuleCall{Name: "bar"},
+			},
+			expect: true,
+		},
+		{
+			from:   mustParseModuleInstanceStr(`module.foo`),
+			to:     mustParseModuleInstanceStr(`module.bar`),
+			expect: false,
+		},
+		{
+			from:   mustParseModuleInstanceStr(`module.bar`),
+			to:     mustParseModuleInstanceStr(`module.foo[0]`),
+			expect: false,
+		},
+		{
+			from: AbsModuleCall{
+				Call: ModuleCall{Name: "bar"},
+			},
+			to:     mustParseModuleInstanceStr(`module.foo[0]`),
+			expect: false,
+		},
+		{
+			from: mustParseModuleInstanceStr(`module.bar["a"]`),
+			to: AbsModuleCall{
+				Call: ModuleCall{Name: "foo"},
+			},
+			expect: false,
+		},
+		{
+			from:   mustParseModuleInstanceStr(`module.bar.module.baz`),
+			to:     mustParseModuleInstanceStr(`module.bar.module.baz`),
+			expect: true,
+		},
+		{
+			from:   mustParseModuleInstanceStr(`module.bar.module.baz`),
+			to:     mustParseModuleInstanceStr(`module.bar.module.baz[0]`),
+			expect: true,
+		},
+		{
+			from:   mustParseModuleInstanceStr(`module.bar.module.baz`),
+			to:     mustParseModuleInstanceStr(`module.baz.module.baz`),
+			expect: false,
+		},
+		{
+			from:   mustParseModuleInstanceStr(`module.bar.module.baz`),
+			to:     mustParseModuleInstanceStr(`module.baz.module.baz[0]`),
+			expect: false,
+		},
+		{
+			from:   mustParseModuleInstanceStr(`module.bar.module.baz`),
+			to:     mustParseModuleInstanceStr(`module.bar[0].module.baz`),
+			expect: true,
+		},
+		{
+			from:   mustParseModuleInstanceStr(`module.bar[0].module.baz`),
+			to:     mustParseModuleInstanceStr(`module.bar.module.baz[0]`),
+			expect: true,
+		},
+		{
+			from:   mustParseModuleInstanceStr(`module.bar[0].module.baz`),
+			to:     mustParseModuleInstanceStr(`module.bar[1].module.baz[0]`),
+			expect: true,
+		},
+		{
+			from: AbsModuleCall{
+				Call: ModuleCall{Name: "baz"},
+			},
+			to:     mustParseModuleInstanceStr(`module.bar.module.baz[0]`),
+			expect: false,
+		},
+		{
+			from: mustParseModuleInstanceStr(`module.bar.module.baz[0]`),
+			to: AbsModuleCall{
+				Call: ModuleCall{Name: "baz"},
+			},
+			expect: false,
+		},
+
+		{
+			from: AbsModuleCall{
+				Module: mustParseModuleInstanceStr(`module.bar[0]`),
+				Call:   ModuleCall{Name: "baz"},
+			},
+			to:     mustParseModuleInstanceStr(`module.bar.module.baz[0]`),
+			expect: true,
+		},
+
+		{
+			from: mustParseModuleInstanceStr(`module.bar.module.baz[0]`),
+			to: AbsModuleCall{
+				Module: mustParseModuleInstanceStr(`module.bar[0]`),
+				Call:   ModuleCall{Name: "baz"},
+			},
+			expect: true,
+		},
+
+		{
+			from:   mustParseModuleInstanceStr(`module.baz`),
+			to:     mustParseModuleInstanceStr(`module.bar.module.baz[0]`),
+			expect: false,
+		},
+		{
+			from:   mustParseModuleInstanceStr(`module.bar.module.baz[0]`),
+			to:     mustParseModuleInstanceStr(`module.baz`),
+			expect: false,
+		},
+	}
+
+	for i, test := range tests {
+		t.Run(fmt.Sprintf("[%02d]IsModuleMoveReIndex(%s, %s)", i, test.from, test.to),
+			func(t *testing.T) {
+				from := &MoveEndpointInModule{
+					relSubject: test.from,
+				}
+
+				to := &MoveEndpointInModule{
+					relSubject: test.to,
+				}
+
+				if got := from.IsModuleReIndex(to); got != test.expect {
+					t.Errorf("expected %t, got %t", test.expect, got)
+				}
+			},
+		)
+	}
+}
+
+func mustParseAbsResourceInstanceStr(s string) AbsResourceInstance {
+	r, diags := ParseAbsResourceInstanceStr(s)
+	if diags.HasErrors() {
+		panic(diags.ErrWithWarnings().Error())
+	}
+	return r
+}
diff --git a/v1.5.7/internal/addrs/move_endpoint_test.go b/v1.5.7/internal/addrs/move_endpoint_test.go
new file mode 100644
index 0000000..83e1f3a
--- /dev/null
+++ b/v1.5.7/internal/addrs/move_endpoint_test.go
@@ -0,0 +1,635 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+)
+
+func TestParseMoveEndpoint(t *testing.T) {
+	tests := []struct {
+		Input   string
+		WantRel AbsMoveable // funny intermediate subset of AbsMoveable
+		WantErr string
+	}{
+		{
+			`foo.bar`,
+			AbsResourceInstance{
+				Module: RootModuleInstance,
+				Resource: ResourceInstance{
+					Resource: Resource{
+						Mode: ManagedResourceMode,
+						Type: "foo",
+						Name: "bar",
+					},
+					Key: NoKey,
+				},
+			},
+			``,
+		},
+		{
+			`foo.bar[0]`,
+			AbsResourceInstance{
+				Module: RootModuleInstance,
+				Resource: ResourceInstance{
+					Resource: Resource{
+						Mode: ManagedResourceMode,
+						Type: "foo",
+						Name: "bar",
+					},
+					Key: IntKey(0),
+				},
+			},
+			``,
+		},
+		{
+			`foo.bar["a"]`,
+			AbsResourceInstance{
+				Module: RootModuleInstance,
+				Resource: ResourceInstance{
+					Resource: Resource{
+						Mode: ManagedResourceMode,
+						Type: "foo",
+						Name: "bar",
+					},
+					Key: StringKey("a"),
+				},
+			},
+			``,
+		},
+		{
+			`module.boop.foo.bar`,
+			AbsResourceInstance{
+				Module: ModuleInstance{
+					ModuleInstanceStep{Name: "boop"},
+				},
+				Resource: ResourceInstance{
+					Resource: Resource{
+						Mode: ManagedResourceMode,
+						Type: "foo",
+						Name: "bar",
+					},
+					Key: NoKey,
+				},
+			},
+			``,
+		},
+		{
+			`module.boop.foo.bar[0]`,
+			AbsResourceInstance{
+				Module: ModuleInstance{
+					ModuleInstanceStep{Name: "boop"},
+				},
+				Resource: ResourceInstance{
+					Resource: Resource{
+						Mode: ManagedResourceMode,
+						Type: "foo",
+						Name: "bar",
+					},
+					Key: IntKey(0),
+				},
+			},
+			``,
+		},
+		{
+			`module.boop.foo.bar["a"]`,
+			AbsResourceInstance{
+				Module: ModuleInstance{
+					ModuleInstanceStep{Name: "boop"},
+				},
+				Resource: ResourceInstance{
+					Resource: Resource{
+						Mode: ManagedResourceMode,
+						Type: "foo",
+						Name: "bar",
+					},
+					Key: StringKey("a"),
+				},
+			},
+			``,
+		},
+		{
+			`data.foo.bar`,
+			AbsResourceInstance{
+				Module: RootModuleInstance,
+				Resource: ResourceInstance{
+					Resource: Resource{
+						Mode: DataResourceMode,
+						Type: "foo",
+						Name: "bar",
+					},
+					Key: NoKey,
+				},
+			},
+			``,
+		},
+		{
+			`data.foo.bar[0]`,
+			AbsResourceInstance{
+				Module: RootModuleInstance,
+				Resource: ResourceInstance{
+					Resource: Resource{
+						Mode: DataResourceMode,
+						Type: "foo",
+						Name: "bar",
+					},
+					Key: IntKey(0),
+				},
+			},
+			``,
+		},
+		{
+			`data.foo.bar["a"]`,
+			AbsResourceInstance{
+				Module: RootModuleInstance,
+				Resource: ResourceInstance{
+					Resource: Resource{
+						Mode: DataResourceMode,
+						Type: "foo",
+						Name: "bar",
+					},
+					Key: StringKey("a"),
+				},
+			},
+			``,
+		},
+		{
+			`module.boop.data.foo.bar`,
+			AbsResourceInstance{
+				Module: ModuleInstance{
+					ModuleInstanceStep{Name: "boop"},
+				},
+				Resource: ResourceInstance{
+					Resource: Resource{
+						Mode: DataResourceMode,
+						Type: "foo",
+						Name: "bar",
+					},
+					Key: NoKey,
+				},
+			},
+			``,
+		},
+		{
+			`module.boop.data.foo.bar[0]`,
+			AbsResourceInstance{
+				Module: ModuleInstance{
+					ModuleInstanceStep{Name: "boop"},
+				},
+				Resource: ResourceInstance{
+					Resource: Resource{
+						Mode: DataResourceMode,
+						Type: "foo",
+						Name: "bar",
+					},
+					Key: IntKey(0),
+				},
+			},
+			``,
+		},
+		{
+			`module.boop.data.foo.bar["a"]`,
+			AbsResourceInstance{
+				Module: ModuleInstance{
+					ModuleInstanceStep{Name: "boop"},
+				},
+				Resource: ResourceInstance{
+					Resource: Resource{
+						Mode: DataResourceMode,
+						Type: "foo",
+						Name: "bar",
+					},
+					Key: StringKey("a"),
+				},
+			},
+			``,
+		},
+		{
+			`module.foo`,
+			ModuleInstance{
+				ModuleInstanceStep{Name: "foo"},
+			},
+			``,
+		},
+		{
+			`module.foo[0]`,
+			ModuleInstance{
+				ModuleInstanceStep{Name: "foo", InstanceKey: IntKey(0)},
+			},
+			``,
+		},
+		{
+			`module.foo["a"]`,
+			ModuleInstance{
+				ModuleInstanceStep{Name: "foo", InstanceKey: StringKey("a")},
+			},
+			``,
+		},
+		{
+			`module.foo.module.bar`,
+			ModuleInstance{
+				ModuleInstanceStep{Name: "foo"},
+				ModuleInstanceStep{Name: "bar"},
+			},
+			``,
+		},
+		{
+			`module.foo[1].module.bar`,
+			ModuleInstance{
+				ModuleInstanceStep{Name: "foo", InstanceKey: IntKey(1)},
+				ModuleInstanceStep{Name: "bar"},
+			},
+			``,
+		},
+		{
+			`module.foo.module.bar[1]`,
+			ModuleInstance{
+				ModuleInstanceStep{Name: "foo"},
+				ModuleInstanceStep{Name: "bar", InstanceKey: IntKey(1)},
+			},
+			``,
+		},
+		{
+			`module.foo[0].module.bar[1]`,
+			ModuleInstance{
+				ModuleInstanceStep{Name: "foo", InstanceKey: IntKey(0)},
+				ModuleInstanceStep{Name: "bar", InstanceKey: IntKey(1)},
+			},
+			``,
+		},
+		{
+			`module`,
+			nil,
+			`Invalid address operator: Prefix "module." must be followed by a module name.`,
+		},
+		{
+			`module[0]`,
+			nil,
+			`Invalid address operator: Prefix "module." must be followed by a module name.`,
+		},
+		{
+			`module.foo.data`,
+			nil,
+			`Invalid address: Resource specification must include a resource type and name.`,
+		},
+		{
+			`module.foo.data.bar`,
+			nil,
+			`Invalid address: Resource specification must include a resource type and name.`,
+		},
+		{
+			`module.foo.data[0]`,
+			nil,
+			`Invalid address: Resource specification must include a resource type and name.`,
+		},
+		{
+			`module.foo.data.bar[0]`,
+			nil,
+			`Invalid address: A resource name is required.`,
+		},
+		{
+			`module.foo.bar`,
+			nil,
+			`Invalid address: Resource specification must include a resource type and name.`,
+		},
+		{
+			`module.foo.bar[0]`,
+			nil,
+			`Invalid address: A resource name is required.`,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Input, func(t *testing.T) {
+			traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(test.Input), "", hcl.InitialPos)
+			if hclDiags.HasErrors() {
+				// We're not trying to test the HCL parser here, so any
+				// failures at this point are likely to be bugs in the
+				// test case itself.
+				t.Fatalf("syntax error: %s", hclDiags.Error())
+			}
+
+			moveEp, diags := ParseMoveEndpoint(traversal)
+
+			switch {
+			case test.WantErr != "":
+				if !diags.HasErrors() {
+					t.Fatalf("unexpected success\nwant error: %s", test.WantErr)
+				}
+				gotErr := diags.Err().Error()
+				if gotErr != test.WantErr {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", gotErr, test.WantErr)
+				}
+			default:
+				if diags.HasErrors() {
+					t.Fatalf("unexpected error: %s", diags.Err().Error())
+				}
+				if diff := cmp.Diff(test.WantRel, moveEp.relSubject); diff != "" {
+					t.Errorf("wrong result\n%s", diff)
+				}
+			}
+		})
+	}
+}
+
+func TestUnifyMoveEndpoints(t *testing.T) {
+	tests := []struct {
+		InputFrom, InputTo string
+		Module             Module
+		WantFrom, WantTo   string
+	}{
+		{
+			InputFrom: `foo.bar`,
+			InputTo:   `foo.baz`,
+			Module:    RootModule,
+			WantFrom:  `foo.bar[*]`,
+			WantTo:    `foo.baz[*]`,
+		},
+		{
+			InputFrom: `foo.bar`,
+			InputTo:   `foo.baz`,
+			Module:    RootModule.Child("a"),
+			WantFrom:  `module.a[*].foo.bar[*]`,
+			WantTo:    `module.a[*].foo.baz[*]`,
+		},
+		{
+			InputFrom: `foo.bar`,
+			InputTo:   `module.b[0].foo.baz`,
+			Module:    RootModule.Child("a"),
+			WantFrom:  `module.a[*].foo.bar[*]`,
+			WantTo:    `module.a[*].module.b[0].foo.baz[*]`,
+		},
+		{
+			InputFrom: `foo.bar`,
+			InputTo:   `foo.bar["thing"]`,
+			Module:    RootModule,
+			WantFrom:  `foo.bar`,
+			WantTo:    `foo.bar["thing"]`,
+		},
+		{
+			InputFrom: `foo.bar["thing"]`,
+			InputTo:   `foo.bar`,
+			Module:    RootModule,
+			WantFrom:  `foo.bar["thing"]`,
+			WantTo:    `foo.bar`,
+		},
+		{
+			InputFrom: `foo.bar["a"]`,
+			InputTo:   `foo.bar["b"]`,
+			Module:    RootModule,
+			WantFrom:  `foo.bar["a"]`,
+			WantTo:    `foo.bar["b"]`,
+		},
+		{
+			InputFrom: `module.foo`,
+			InputTo:   `module.bar`,
+			Module:    RootModule,
+			WantFrom:  `module.foo[*]`,
+			WantTo:    `module.bar[*]`,
+		},
+		{
+			InputFrom: `module.foo`,
+			InputTo:   `module.bar.module.baz`,
+			Module:    RootModule,
+			WantFrom:  `module.foo[*]`,
+			WantTo:    `module.bar.module.baz[*]`,
+		},
+		{
+			InputFrom: `module.foo`,
+			InputTo:   `module.bar.module.baz`,
+			Module:    RootModule.Child("bloop"),
+			WantFrom:  `module.bloop[*].module.foo[*]`,
+			WantTo:    `module.bloop[*].module.bar.module.baz[*]`,
+		},
+		{
+			InputFrom: `module.foo[0]`,
+			InputTo:   `module.foo["a"]`,
+			Module:    RootModule,
+			WantFrom:  `module.foo[0]`,
+			WantTo:    `module.foo["a"]`,
+		},
+		{
+			InputFrom: `module.foo`,
+			InputTo:   `module.foo["a"]`,
+			Module:    RootModule,
+			WantFrom:  `module.foo`,
+			WantTo:    `module.foo["a"]`,
+		},
+		{
+			InputFrom: `module.foo[0]`,
+			InputTo:   `module.foo`,
+			Module:    RootModule,
+			WantFrom:  `module.foo[0]`,
+			WantTo:    `module.foo`,
+		},
+		{
+			InputFrom: `module.foo[0]`,
+			InputTo:   `module.foo`,
+			Module:    RootModule.Child("bloop"),
+			WantFrom:  `module.bloop[*].module.foo[0]`,
+			WantTo:    `module.bloop[*].module.foo`,
+		},
+		{
+			InputFrom: `module.foo`,
+			InputTo:   `foo.bar`,
+			Module:    RootModule,
+			WantFrom:  ``, // Can't unify module call with resource
+			WantTo:    ``,
+		},
+		{
+			InputFrom: `module.foo[0]`,
+			InputTo:   `foo.bar`,
+			Module:    RootModule,
+			WantFrom:  ``, // Can't unify module instance with resource
+			WantTo:    ``,
+		},
+		{
+			InputFrom: `module.foo`,
+			InputTo:   `foo.bar[0]`,
+			Module:    RootModule,
+			WantFrom:  ``, // Can't unify module call with resource instance
+			WantTo:    ``,
+		},
+		{
+			InputFrom: `module.foo[0]`,
+			InputTo:   `foo.bar[0]`,
+			Module:    RootModule,
+			WantFrom:  ``, // Can't unify module instance with resource instance
+			WantTo:    ``,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%s to %s in %s", test.InputFrom, test.InputTo, test.Module), func(t *testing.T) {
+			parseInput := func(input string) *MoveEndpoint {
+				t.Helper()
+
+				traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(input), "", hcl.InitialPos)
+				if hclDiags.HasErrors() {
+					// We're not trying to test the HCL parser here, so any
+					// failures at this point are likely to be bugs in the
+					// test case itself.
+					t.Fatalf("syntax error: %s", hclDiags.Error())
+				}
+
+				moveEp, diags := ParseMoveEndpoint(traversal)
+				if diags.HasErrors() {
+					t.Fatalf("unexpected error: %s", diags.Err().Error())
+				}
+				return moveEp
+			}
+
+			fromEp := parseInput(test.InputFrom)
+			toEp := parseInput(test.InputTo)
+
+			gotFrom, gotTo := UnifyMoveEndpoints(test.Module, fromEp, toEp)
+			if got, want := gotFrom.String(), test.WantFrom; got != want {
+				t.Errorf("wrong 'from' result\ngot:  %s\nwant: %s", got, want)
+			}
+			if got, want := gotTo.String(), test.WantTo; got != want {
+				t.Errorf("wrong 'to' result\ngot:  %s\nwant: %s", got, want)
+			}
+		})
+	}
+}
+
+func TestMoveEndpointConfigMoveable(t *testing.T) {
+	tests := []struct {
+		Input  string
+		Module Module
+		Want   ConfigMoveable
+	}{
+		{
+			`foo.bar`,
+			RootModule,
+			ConfigResource{
+				Module: RootModule,
+				Resource: Resource{
+					Mode: ManagedResourceMode,
+					Type: "foo",
+					Name: "bar",
+				},
+			},
+		},
+		{
+			`foo.bar[0]`,
+			RootModule,
+			ConfigResource{
+				Module: RootModule,
+				Resource: Resource{
+					Mode: ManagedResourceMode,
+					Type: "foo",
+					Name: "bar",
+				},
+			},
+		},
+		{
+			`module.foo.bar.baz`,
+			RootModule,
+			ConfigResource{
+				Module: Module{"foo"},
+				Resource: Resource{
+					Mode: ManagedResourceMode,
+					Type: "bar",
+					Name: "baz",
+				},
+			},
+		},
+		{
+			`module.foo[0].bar.baz`,
+			RootModule,
+			ConfigResource{
+				Module: Module{"foo"},
+				Resource: Resource{
+					Mode: ManagedResourceMode,
+					Type: "bar",
+					Name: "baz",
+				},
+			},
+		},
+		{
+			`foo.bar`,
+			Module{"boop"},
+			ConfigResource{
+				Module: Module{"boop"},
+				Resource: Resource{
+					Mode: ManagedResourceMode,
+					Type: "foo",
+					Name: "bar",
+				},
+			},
+		},
+		{
+			`module.bloop.foo.bar`,
+			Module{"bleep"},
+			ConfigResource{
+				Module: Module{"bleep", "bloop"},
+				Resource: Resource{
+					Mode: ManagedResourceMode,
+					Type: "foo",
+					Name: "bar",
+				},
+			},
+		},
+		{
+			`module.foo.bar.baz`,
+			RootModule,
+			ConfigResource{
+				Module: Module{"foo"},
+				Resource: Resource{
+					Mode: ManagedResourceMode,
+					Type: "bar",
+					Name: "baz",
+				},
+			},
+		},
+		{
+			`module.foo`,
+			RootModule,
+			Module{"foo"},
+		},
+		{
+			`module.foo[0]`,
+			RootModule,
+			Module{"foo"},
+		},
+		{
+			`module.bloop`,
+			Module{"bleep"},
+			Module{"bleep", "bloop"},
+		},
+		{
+			`module.bloop[0]`,
+			Module{"bleep"},
+			Module{"bleep", "bloop"},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%s in %s", test.Input, test.Module), func(t *testing.T) {
+			traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(test.Input), "", hcl.InitialPos)
+			if hclDiags.HasErrors() {
+				// We're not trying to test the HCL parser here, so any
+				// failures at this point are likely to be bugs in the
+				// test case itself.
+				t.Fatalf("syntax error: %s", hclDiags.Error())
+			}
+
+			moveEp, diags := ParseMoveEndpoint(traversal)
+			if diags.HasErrors() {
+				t.Fatalf("unexpected error: %s", diags.Err().Error())
+			}
+
+			got := moveEp.ConfigMoveable(test.Module)
+			if diff := cmp.Diff(test.Want, got); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/addrs/moveable.go b/v1.5.7/internal/addrs/moveable.go
new file mode 100644
index 0000000..6f7305c
--- /dev/null
+++ b/v1.5.7/internal/addrs/moveable.go
@@ -0,0 +1,60 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+// AbsMoveable is an interface implemented by address types that can be either
+// the source or destination of a "moved" statement in configuration, along
+// with any other similar cross-module state refactoring statements we might
+// allow.
+//
+// Note that AbsMoveable represents an absolute address relative to the root
+// of the configuration, which is different than the direct representation
+// of these in configuration where the author gives an address relative to
+// the current module where the address is defined. The type MoveEndpoint
+type AbsMoveable interface {
+	absMoveableSigil()
+	UniqueKeyer
+
+	String() string
+}
+
+// The following are all of the possible AbsMoveable address types:
+var (
+	_ AbsMoveable = AbsResource{}
+	_ AbsMoveable = AbsResourceInstance{}
+	_ AbsMoveable = ModuleInstance(nil)
+	_ AbsMoveable = AbsModuleCall{}
+)
+
+// AbsMoveableResource is an AbsMoveable that is either a resource or a resource
+// instance.
+type AbsMoveableResource interface {
+	AbsMoveable
+	AffectedAbsResource() AbsResource
+}
+
+// The following are all of the possible AbsMoveableResource types:
+var (
+	_ AbsMoveableResource = AbsResource{}
+	_ AbsMoveableResource = AbsResourceInstance{}
+)
+
+// ConfigMoveable is similar to AbsMoveable but represents a static object in
+// the configuration, rather than an instance of that object created by
+// module expansion.
+//
+// Note that ConfigMovable represents an absolute address relative to the root
+// of the configuration, which is different than the direct representation
+// of these in configuration where the author gives an address relative to
+// the current module where the address is defined. The type MoveEndpoint
+// represents the relative form given directly in configuration.
+type ConfigMoveable interface {
+	configMoveableSigil()
+}
+
+// The following are all of the possible ConfigMovable address types:
+var (
+	_ ConfigMoveable = ConfigResource{}
+	_ ConfigMoveable = Module(nil)
+)
diff --git a/v1.5.7/internal/addrs/moveendpointkind_string.go b/v1.5.7/internal/addrs/moveendpointkind_string.go
new file mode 100644
index 0000000..f706fb9
--- /dev/null
+++ b/v1.5.7/internal/addrs/moveendpointkind_string.go
@@ -0,0 +1,29 @@
+// Code generated by "stringer -type MoveEndpointKind"; DO NOT EDIT.
+
+package addrs
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[MoveEndpointModule-77]
+	_ = x[MoveEndpointResource-82]
+}
+
+const (
+	_MoveEndpointKind_name_0 = "MoveEndpointModule"
+	_MoveEndpointKind_name_1 = "MoveEndpointResource"
+)
+
+func (i MoveEndpointKind) String() string {
+	switch {
+	case i == 77:
+		return _MoveEndpointKind_name_0
+	case i == 82:
+		return _MoveEndpointKind_name_1
+	default:
+		return "MoveEndpointKind(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/v1.5.7/internal/addrs/output_value.go b/v1.5.7/internal/addrs/output_value.go
new file mode 100644
index 0000000..9b1da25
--- /dev/null
+++ b/v1.5.7/internal/addrs/output_value.go
@@ -0,0 +1,227 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// OutputValue is the address of an output value, in the context of the module
+// that is defining it.
+//
+// This is related to but separate from ModuleCallOutput, which represents
+// a module output from the perspective of its parent module. Since output
+// values cannot be represented from the module where they are defined,
+// OutputValue is not Referenceable, while ModuleCallOutput is.
+type OutputValue struct {
+	Name string
+}
+
+func (v OutputValue) String() string {
+	return "output." + v.Name
+}
+
+// Absolute converts the receiver into an absolute address within the given
+// module instance.
+func (v OutputValue) Absolute(m ModuleInstance) AbsOutputValue {
+	return AbsOutputValue{
+		Module:      m,
+		OutputValue: v,
+	}
+}
+
+// InModule converts the receiver into a config address within the given
+// module.
+func (v OutputValue) InModule(m Module) ConfigOutputValue {
+	return ConfigOutputValue{
+		Module:      m,
+		OutputValue: v,
+	}
+}
+
+// AbsOutputValue is the absolute address of an output value within a module instance.
+//
+// This represents an output globally within the namespace of a particular
+// configuration. It is related to but separate from ModuleCallOutput, which
+// represents a module output from the perspective of its parent module.
+type AbsOutputValue struct {
+	Module      ModuleInstance
+	OutputValue OutputValue
+}
+
+// OutputValue returns the absolute address of an output value of the given
+// name within the receiving module instance.
+func (m ModuleInstance) OutputValue(name string) AbsOutputValue {
+	return AbsOutputValue{
+		Module: m,
+		OutputValue: OutputValue{
+			Name: name,
+		},
+	}
+}
+
+func (v AbsOutputValue) CheckRule(t CheckRuleType, i int) CheckRule {
+	return CheckRule{
+		Container: v,
+		Type:      t,
+		Index:     i,
+	}
+}
+
+func (v AbsOutputValue) String() string {
+	if v.Module.IsRoot() {
+		return v.OutputValue.String()
+	}
+	return fmt.Sprintf("%s.%s", v.Module.String(), v.OutputValue.String())
+}
+
+func (v AbsOutputValue) Equal(o AbsOutputValue) bool {
+	return v.OutputValue == o.OutputValue && v.Module.Equal(o.Module)
+}
+
+func (v AbsOutputValue) ConfigOutputValue() ConfigOutputValue {
+	return ConfigOutputValue{
+		Module:      v.Module.Module(),
+		OutputValue: v.OutputValue,
+	}
+}
+
+func (v AbsOutputValue) checkableSigil() {
+	// Output values are checkable
+}
+
+func (v AbsOutputValue) ConfigCheckable() ConfigCheckable {
+	// Output values are declared by "output" blocks in the configuration,
+	// represented as ConfigOutputValue.
+	return v.ConfigOutputValue()
+}
+
+func (v AbsOutputValue) CheckableKind() CheckableKind {
+	return CheckableOutputValue
+}
+
+func (v AbsOutputValue) UniqueKey() UniqueKey {
+	return absOutputValueUniqueKey(v.String())
+}
+
+type absOutputValueUniqueKey string
+
+func (k absOutputValueUniqueKey) uniqueKeySigil() {}
+
+func ParseAbsOutputValue(traversal hcl.Traversal) (AbsOutputValue, tfdiags.Diagnostics) {
+	path, remain, diags := parseModuleInstancePrefix(traversal)
+	if diags.HasErrors() {
+		return AbsOutputValue{}, diags
+	}
+
+	if len(remain) != 2 {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid address",
+			Detail:   "An output name is required.",
+			Subject:  traversal.SourceRange().Ptr(),
+		})
+		return AbsOutputValue{}, diags
+	}
+
+	if remain.RootName() != "output" {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid address",
+			Detail:   "Output address must start with \"output.\".",
+			Subject:  remain[0].SourceRange().Ptr(),
+		})
+		return AbsOutputValue{}, diags
+	}
+
+	var name string
+	switch tt := remain[1].(type) {
+	case hcl.TraverseAttr:
+		name = tt.Name
+	default:
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid address",
+			Detail:   "An output name is required.",
+			Subject:  remain[1].SourceRange().Ptr(),
+		})
+		return AbsOutputValue{}, diags
+	}
+
+	return AbsOutputValue{
+		Module: path,
+		OutputValue: OutputValue{
+			Name: name,
+		},
+	}, diags
+}
+
+func ParseAbsOutputValueStr(str string) (AbsOutputValue, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1})
+	diags = diags.Append(parseDiags)
+	if parseDiags.HasErrors() {
+		return AbsOutputValue{}, diags
+	}
+
+	addr, addrDiags := ParseAbsOutputValue(traversal)
+	diags = diags.Append(addrDiags)
+	return addr, diags
+}
+
+// ModuleCallOutput converts an AbsModuleOutput into a ModuleCallOutput,
+// returning also the module instance that the ModuleCallOutput is relative
+// to.
+//
+// The root module does not have a call, and so this method cannot be used
+// with outputs in the root module, and will panic in that case.
+func (v AbsOutputValue) ModuleCallOutput() (ModuleInstance, ModuleCallInstanceOutput) {
+	if v.Module.IsRoot() {
+		panic("ReferenceFromCall used with root module output")
+	}
+
+	caller, call := v.Module.CallInstance()
+	return caller, ModuleCallInstanceOutput{
+		Call: call,
+		Name: v.OutputValue.Name,
+	}
+}
+
+// ConfigOutputValue represents a particular "output" block in the
+// configuration, which might have many AbsOutputValue addresses associated
+// with it at runtime if it belongs to a module that was called using
+// "count" or "for_each".
+type ConfigOutputValue struct {
+	Module      Module
+	OutputValue OutputValue
+}
+
+func (v ConfigOutputValue) String() string {
+	if v.Module.IsRoot() {
+		return v.OutputValue.String()
+	}
+	return fmt.Sprintf("%s.%s", v.Module.String(), v.OutputValue.String())
+}
+
+func (v ConfigOutputValue) configCheckableSigil() {
+	// ConfigOutputValue is the ConfigCheckable for AbsOutputValue.
+}
+
+func (v ConfigOutputValue) CheckableKind() CheckableKind {
+	return CheckableOutputValue
+}
+
+func (v ConfigOutputValue) UniqueKey() UniqueKey {
+	return configOutputValueUniqueKey(v.String())
+}
+
+type configOutputValueUniqueKey string
+
+func (k configOutputValueUniqueKey) uniqueKeySigil() {}
diff --git a/v1.5.7/internal/addrs/output_value_test.go b/v1.5.7/internal/addrs/output_value_test.go
new file mode 100644
index 0000000..ff48018
--- /dev/null
+++ b/v1.5.7/internal/addrs/output_value_test.go
@@ -0,0 +1,134 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/go-test/deep"
+)
+
+func TestAbsOutputValueInstanceEqual_true(t *testing.T) {
+	foo, diags := ParseModuleInstanceStr("module.foo")
+	if len(diags) > 0 {
+		t.Fatalf("unexpected diags: %s", diags.Err())
+	}
+	foobar, diags := ParseModuleInstanceStr("module.foo[1].module.bar")
+	if len(diags) > 0 {
+		t.Fatalf("unexpected diags: %s", diags.Err())
+	}
+
+	ovs := []AbsOutputValue{
+		foo.OutputValue("a"),
+		foobar.OutputValue("b"),
+	}
+	for _, r := range ovs {
+		t.Run(r.String(), func(t *testing.T) {
+			if !r.Equal(r) {
+				t.Fatalf("expected %#v to be equal to itself", r)
+			}
+		})
+	}
+}
+
+func TestAbsOutputValueInstanceEqual_false(t *testing.T) {
+	foo, diags := ParseModuleInstanceStr("module.foo")
+	if len(diags) > 0 {
+		t.Fatalf("unexpected diags: %s", diags.Err())
+	}
+	foobar, diags := ParseModuleInstanceStr("module.foo[1].module.bar")
+	if len(diags) > 0 {
+		t.Fatalf("unexpected diags: %s", diags.Err())
+	}
+
+	testCases := []struct {
+		left  AbsOutputValue
+		right AbsOutputValue
+	}{
+		{
+			foo.OutputValue("a"),
+			foo.OutputValue("b"),
+		},
+		{
+			foo.OutputValue("a"),
+			foobar.OutputValue("a"),
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(fmt.Sprintf("%s = %s", tc.left, tc.right), func(t *testing.T) {
+			if tc.left.Equal(tc.right) {
+				t.Fatalf("expected %#v not to be equal to %#v", tc.left, tc.right)
+			}
+
+			if tc.right.Equal(tc.left) {
+				t.Fatalf("expected %#v not to be equal to %#v", tc.right, tc.left)
+			}
+		})
+	}
+}
+
+func TestParseAbsOutputValueStr(t *testing.T) {
+	tests := map[string]struct {
+		want    AbsOutputValue
+		wantErr string
+	}{
+		"module.foo": {
+			wantErr: "An output name is required",
+		},
+		"module.foo.output": {
+			wantErr: "An output name is required",
+		},
+		"module.foo.boop.beep": {
+			wantErr: "Output address must start with \"output.\"",
+		},
+		"module.foo.output[0]": {
+			wantErr: "An output name is required",
+		},
+		"output": {
+			wantErr: "An output name is required",
+		},
+		"output[0]": {
+			wantErr: "An output name is required",
+		},
+		"output.boop": {
+			want: AbsOutputValue{
+				Module: RootModuleInstance,
+				OutputValue: OutputValue{
+					Name: "boop",
+				},
+			},
+		},
+		"module.foo.output.beep": {
+			want: AbsOutputValue{
+				Module: mustParseModuleInstanceStr("module.foo"),
+				OutputValue: OutputValue{
+					Name: "beep",
+				},
+			},
+		},
+	}
+
+	for input, tc := range tests {
+		t.Run(input, func(t *testing.T) {
+			got, diags := ParseAbsOutputValueStr(input)
+			for _, problem := range deep.Equal(got, tc.want) {
+				t.Errorf(problem)
+			}
+			if len(diags) > 0 {
+				gotErr := diags.Err().Error()
+				if tc.wantErr == "" {
+					t.Errorf("got error, expected success: %s", gotErr)
+				} else if !strings.Contains(gotErr, tc.wantErr) {
+					t.Errorf("unexpected error\n got: %s\nwant: %s", gotErr, tc.wantErr)
+				}
+			} else {
+				if tc.wantErr != "" {
+					t.Errorf("got success, expected error: %s", tc.wantErr)
+				}
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/addrs/parse_ref.go b/v1.5.7/internal/addrs/parse_ref.go
new file mode 100644
index 0000000..3c757bf
--- /dev/null
+++ b/v1.5.7/internal/addrs/parse_ref.go
@@ -0,0 +1,420 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Reference describes a reference to an address with source location
+// information.
+type Reference struct {
+	Subject     Referenceable
+	SourceRange tfdiags.SourceRange
+	Remaining   hcl.Traversal
+}
+
+// DisplayString returns a string that approximates the subject and remaining
+// traversal of the reciever in a way that resembles the Terraform language
+// syntax that could've produced it.
+//
+// It's not guaranteed to actually be a valid Terraform language expression,
+// since the intended use here is primarily for UI messages such as
+// diagnostics.
+func (r *Reference) DisplayString() string {
+	if len(r.Remaining) == 0 {
+		// Easy case: we can just return the subject's string.
+		return r.Subject.String()
+	}
+
+	var ret strings.Builder
+	ret.WriteString(r.Subject.String())
+	for _, step := range r.Remaining {
+		switch tStep := step.(type) {
+		case hcl.TraverseRoot:
+			ret.WriteString(tStep.Name)
+		case hcl.TraverseAttr:
+			ret.WriteByte('.')
+			ret.WriteString(tStep.Name)
+		case hcl.TraverseIndex:
+			ret.WriteByte('[')
+			switch tStep.Key.Type() {
+			case cty.String:
+				ret.WriteString(fmt.Sprintf("%q", tStep.Key.AsString()))
+			case cty.Number:
+				bf := tStep.Key.AsBigFloat()
+				ret.WriteString(bf.Text('g', 10))
+			}
+			ret.WriteByte(']')
+		}
+	}
+	return ret.String()
+}
+
+// ParseRef attempts to extract a referencable address from the prefix of the
+// given traversal, which must be an absolute traversal or this function
+// will panic.
+//
+// If no error diagnostics are returned, the returned reference includes the
+// address that was extracted, the source range it was extracted from, and any
+// remaining relative traversal that was not consumed as part of the
+// reference.
+//
+// If error diagnostics are returned then the Reference value is invalid and
+// must not be used.
+func ParseRef(traversal hcl.Traversal) (*Reference, tfdiags.Diagnostics) {
+	ref, diags := parseRef(traversal)
+
+	// Normalize a little to make life easier for callers.
+	if ref != nil {
+		if len(ref.Remaining) == 0 {
+			ref.Remaining = nil
+		}
+	}
+
+	return ref, diags
+}
+
+// ParseRefStr is a helper wrapper around ParseRef that takes a string
+// and parses it with the HCL native syntax traversal parser before
+// interpreting it.
+//
+// This should be used only in specialized situations since it will cause the
+// created references to not have any meaningful source location information.
+// If a reference string is coming from a source that should be identified in
+// error messages then the caller should instead parse it directly using a
+// suitable function from the HCL API and pass the traversal itself to
+// ParseRef.
+//
+// Error diagnostics are returned if either the parsing fails or the analysis
+// of the traversal fails. There is no way for the caller to distinguish the
+// two kinds of diagnostics programmatically. If error diagnostics are returned
+// the returned reference may be nil or incomplete.
+func ParseRefStr(str string) (*Reference, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1})
+	diags = diags.Append(parseDiags)
+	if parseDiags.HasErrors() {
+		return nil, diags
+	}
+
+	ref, targetDiags := ParseRef(traversal)
+	diags = diags.Append(targetDiags)
+	return ref, diags
+}
+
+func parseRef(traversal hcl.Traversal) (*Reference, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	root := traversal.RootName()
+	rootRange := traversal[0].SourceRange()
+
+	switch root {
+
+	case "count":
+		name, rng, remain, diags := parseSingleAttrRef(traversal)
+		return &Reference{
+			Subject:     CountAttr{Name: name},
+			SourceRange: tfdiags.SourceRangeFromHCL(rng),
+			Remaining:   remain,
+		}, diags
+
+	case "each":
+		name, rng, remain, diags := parseSingleAttrRef(traversal)
+		return &Reference{
+			Subject:     ForEachAttr{Name: name},
+			SourceRange: tfdiags.SourceRangeFromHCL(rng),
+			Remaining:   remain,
+		}, diags
+
+	case "data":
+		if len(traversal) < 3 {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid reference",
+				Detail:   `The "data" object must be followed by two attribute names: the data source type and the resource name.`,
+				Subject:  traversal.SourceRange().Ptr(),
+			})
+			return nil, diags
+		}
+		remain := traversal[1:] // trim off "data" so we can use our shared resource reference parser
+		return parseResourceRef(DataResourceMode, rootRange, remain)
+
+	case "resource":
+		// This is an alias for the normal case of just using a managed resource
+		// type as a top-level symbol, which will serve as an escape mechanism
+		// if a later edition of the Terraform language introduces a new
+		// reference prefix that conflicts with a resource type name in an
+		// existing provider. In that case, the edition upgrade tool can
+		// rewrite foo.bar into resource.foo.bar to ensure that "foo" remains
+		// interpreted as a resource type name rather than as the new reserved
+		// word.
+		if len(traversal) < 3 {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid reference",
+				Detail:   `The "resource" object must be followed by two attribute names: the resource type and the resource name.`,
+				Subject:  traversal.SourceRange().Ptr(),
+			})
+			return nil, diags
+		}
+		remain := traversal[1:] // trim off "resource" so we can use our shared resource reference parser
+		return parseResourceRef(ManagedResourceMode, rootRange, remain)
+
+	case "local":
+		name, rng, remain, diags := parseSingleAttrRef(traversal)
+		return &Reference{
+			Subject:     LocalValue{Name: name},
+			SourceRange: tfdiags.SourceRangeFromHCL(rng),
+			Remaining:   remain,
+		}, diags
+
+	case "module":
+		callName, callRange, remain, diags := parseSingleAttrRef(traversal)
+		if diags.HasErrors() {
+			return nil, diags
+		}
+
+		// A traversal starting with "module" can either be a reference to an
+		// entire module, or to a single output from a module instance,
+		// depending on what we find after this introducer.
+		callInstance := ModuleCallInstance{
+			Call: ModuleCall{
+				Name: callName,
+			},
+			Key: NoKey,
+		}
+
+		if len(remain) == 0 {
+			// Reference to an entire module. Might alternatively be a
+			// reference to a single instance of a particular module, but the
+			// caller will need to deal with that ambiguity since we don't have
+			// enough context here.
+			return &Reference{
+				Subject:     callInstance.Call,
+				SourceRange: tfdiags.SourceRangeFromHCL(callRange),
+				Remaining:   remain,
+			}, diags
+		}
+
+		if idxTrav, ok := remain[0].(hcl.TraverseIndex); ok {
+			var err error
+			callInstance.Key, err = ParseInstanceKey(idxTrav.Key)
+			if err != nil {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid index key",
+					Detail:   fmt.Sprintf("Invalid index for module instance: %s.", err),
+					Subject:  &idxTrav.SrcRange,
+				})
+				return nil, diags
+			}
+			remain = remain[1:]
+
+			if len(remain) == 0 {
+				// Also a reference to an entire module instance, but we have a key
+				// now.
+				return &Reference{
+					Subject:     callInstance,
+					SourceRange: tfdiags.SourceRangeFromHCL(hcl.RangeBetween(callRange, idxTrav.SrcRange)),
+					Remaining:   remain,
+				}, diags
+			}
+		}
+
+		if attrTrav, ok := remain[0].(hcl.TraverseAttr); ok {
+			remain = remain[1:]
+			return &Reference{
+				Subject: ModuleCallInstanceOutput{
+					Name: attrTrav.Name,
+					Call: callInstance,
+				},
+				SourceRange: tfdiags.SourceRangeFromHCL(hcl.RangeBetween(callRange, attrTrav.SrcRange)),
+				Remaining:   remain,
+			}, diags
+		}
+
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid reference",
+			Detail:   "Module instance objects do not support this operation.",
+			Subject:  remain[0].SourceRange().Ptr(),
+		})
+		return nil, diags
+
+	case "path":
+		name, rng, remain, diags := parseSingleAttrRef(traversal)
+		return &Reference{
+			Subject:     PathAttr{Name: name},
+			SourceRange: tfdiags.SourceRangeFromHCL(rng),
+			Remaining:   remain,
+		}, diags
+
+	case "self":
+		return &Reference{
+			Subject:     Self,
+			SourceRange: tfdiags.SourceRangeFromHCL(rootRange),
+			Remaining:   traversal[1:],
+		}, diags
+
+	case "terraform":
+		name, rng, remain, diags := parseSingleAttrRef(traversal)
+		return &Reference{
+			Subject:     TerraformAttr{Name: name},
+			SourceRange: tfdiags.SourceRangeFromHCL(rng),
+			Remaining:   remain,
+		}, diags
+
+	case "var":
+		name, rng, remain, diags := parseSingleAttrRef(traversal)
+		return &Reference{
+			Subject:     InputVariable{Name: name},
+			SourceRange: tfdiags.SourceRangeFromHCL(rng),
+			Remaining:   remain,
+		}, diags
+
+	case "template", "lazy", "arg":
+		// These names are all pre-emptively reserved in the hope of landing
+		// some version of "template values" or "lazy expressions" feature
+		// before the next opt-in language edition, but don't yet do anything.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Reserved symbol name",
+			Detail:   fmt.Sprintf("The symbol name %q is reserved for use in a future Terraform version. If you are using a provider that already uses this as a resource type name, add the prefix \"resource.\" to force interpretation as a resource type name.", root),
+			Subject:  rootRange.Ptr(),
+		})
+		return nil, diags
+
+	default:
+		return parseResourceRef(ManagedResourceMode, rootRange, traversal)
+	}
+}
+
+func parseResourceRef(mode ResourceMode, startRange hcl.Range, traversal hcl.Traversal) (*Reference, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	if len(traversal) < 2 {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid reference",
+			Detail:   `A reference to a resource type must be followed by at least one attribute access, specifying the resource name.`,
+			Subject:  hcl.RangeBetween(traversal[0].SourceRange(), traversal[len(traversal)-1].SourceRange()).Ptr(),
+		})
+		return nil, diags
+	}
+
+	var typeName, name string
+	switch tt := traversal[0].(type) { // Could be either root or attr, depending on our resource mode
+	case hcl.TraverseRoot:
+		typeName = tt.Name
+	case hcl.TraverseAttr:
+		typeName = tt.Name
+	default:
+		// If it isn't a TraverseRoot then it must be a "data" reference.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid reference",
+			Detail:   `The "data" object does not support this operation.`,
+			Subject:  traversal[0].SourceRange().Ptr(),
+		})
+		return nil, diags
+	}
+
+	attrTrav, ok := traversal[1].(hcl.TraverseAttr)
+	if !ok {
+		var what string
+		switch mode {
+		case DataResourceMode:
+			what = "data source"
+		default:
+			what = "resource type"
+		}
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid reference",
+			Detail:   fmt.Sprintf(`A reference to a %s must be followed by at least one attribute access, specifying the resource name.`, what),
+			Subject:  traversal[1].SourceRange().Ptr(),
+		})
+		return nil, diags
+	}
+	name = attrTrav.Name
+	rng := hcl.RangeBetween(startRange, attrTrav.SrcRange)
+	remain := traversal[2:]
+
+	resourceAddr := Resource{
+		Mode: mode,
+		Type: typeName,
+		Name: name,
+	}
+	resourceInstAddr := ResourceInstance{
+		Resource: resourceAddr,
+		Key:      NoKey,
+	}
+
+	if len(remain) == 0 {
+		// This might actually be a reference to the collection of all instances
+		// of the resource, but we don't have enough context here to decide
+		// so we'll let the caller resolve that ambiguity.
+		return &Reference{
+			Subject:     resourceAddr,
+			SourceRange: tfdiags.SourceRangeFromHCL(rng),
+		}, diags
+	}
+
+	if idxTrav, ok := remain[0].(hcl.TraverseIndex); ok {
+		var err error
+		resourceInstAddr.Key, err = ParseInstanceKey(idxTrav.Key)
+		if err != nil {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid index key",
+				Detail:   fmt.Sprintf("Invalid index for resource instance: %s.", err),
+				Subject:  &idxTrav.SrcRange,
+			})
+			return nil, diags
+		}
+		remain = remain[1:]
+		rng = hcl.RangeBetween(rng, idxTrav.SrcRange)
+	}
+
+	return &Reference{
+		Subject:     resourceInstAddr,
+		SourceRange: tfdiags.SourceRangeFromHCL(rng),
+		Remaining:   remain,
+	}, diags
+}
+
+func parseSingleAttrRef(traversal hcl.Traversal) (string, hcl.Range, hcl.Traversal, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	root := traversal.RootName()
+	rootRange := traversal[0].SourceRange()
+
+	if len(traversal) < 2 {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid reference",
+			Detail:   fmt.Sprintf("The %q object cannot be accessed directly. Instead, access one of its attributes.", root),
+			Subject:  &rootRange,
+		})
+		return "", hcl.Range{}, nil, diags
+	}
+	if attrTrav, ok := traversal[1].(hcl.TraverseAttr); ok {
+		return attrTrav.Name, hcl.RangeBetween(rootRange, attrTrav.SrcRange), traversal[2:], diags
+	}
+	diags = diags.Append(&hcl.Diagnostic{
+		Severity: hcl.DiagError,
+		Summary:  "Invalid reference",
+		Detail:   fmt.Sprintf("The %q object does not support this operation.", root),
+		Subject:  traversal[1].SourceRange().Ptr(),
+	})
+	return "", hcl.Range{}, nil, diags
+}
diff --git a/v1.5.7/internal/addrs/parse_ref_test.go b/v1.5.7/internal/addrs/parse_ref_test.go
new file mode 100644
index 0000000..91ad9e9
--- /dev/null
+++ b/v1.5.7/internal/addrs/parse_ref_test.go
@@ -0,0 +1,758 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"testing"
+
+	"github.com/go-test/deep"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestParseRef(t *testing.T) {
+	tests := []struct {
+		Input   string
+		Want    *Reference
+		WantErr string
+	}{
+
+		// count
+		{
+			`count.index`,
+			&Reference{
+				Subject: CountAttr{
+					Name: "index",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 12, Byte: 11},
+				},
+			},
+			``,
+		},
+		{
+			`count.index.blah`,
+			&Reference{
+				Subject: CountAttr{
+					Name: "index",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 12, Byte: 11},
+				},
+				Remaining: hcl.Traversal{
+					hcl.TraverseAttr{
+						Name: "blah",
+						SrcRange: hcl.Range{
+							Start: hcl.Pos{Line: 1, Column: 12, Byte: 11},
+							End:   hcl.Pos{Line: 1, Column: 17, Byte: 16},
+						},
+					},
+				},
+			},
+			``, // valid at this layer, but will fail during eval because "index" is a number
+		},
+		{
+			`count`,
+			nil,
+			`The "count" object cannot be accessed directly. Instead, access one of its attributes.`,
+		},
+		{
+			`count["hello"]`,
+			nil,
+			`The "count" object does not support this operation.`,
+		},
+
+		// each
+		{
+			`each.key`,
+			&Reference{
+				Subject: ForEachAttr{
+					Name: "key",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 9, Byte: 8},
+				},
+			},
+			``,
+		},
+		{
+			`each.value.blah`,
+			&Reference{
+				Subject: ForEachAttr{
+					Name: "value",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 11, Byte: 10},
+				},
+				Remaining: hcl.Traversal{
+					hcl.TraverseAttr{
+						Name: "blah",
+						SrcRange: hcl.Range{
+							Start: hcl.Pos{Line: 1, Column: 11, Byte: 10},
+							End:   hcl.Pos{Line: 1, Column: 16, Byte: 15},
+						},
+					},
+				},
+			},
+			``,
+		},
+		{
+			`each`,
+			nil,
+			`The "each" object cannot be accessed directly. Instead, access one of its attributes.`,
+		},
+		{
+			`each["hello"]`,
+			nil,
+			`The "each" object does not support this operation.`,
+		},
+		// data
+		{
+			`data.external.foo`,
+			&Reference{
+				Subject: Resource{
+					Mode: DataResourceMode,
+					Type: "external",
+					Name: "foo",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 18, Byte: 17},
+				},
+			},
+			``,
+		},
+		{
+			`data.external.foo.bar`,
+			&Reference{
+				Subject: ResourceInstance{
+					Resource: Resource{
+						Mode: DataResourceMode,
+						Type: "external",
+						Name: "foo",
+					},
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 18, Byte: 17},
+				},
+				Remaining: hcl.Traversal{
+					hcl.TraverseAttr{
+						Name: "bar",
+						SrcRange: hcl.Range{
+							Start: hcl.Pos{Line: 1, Column: 18, Byte: 17},
+							End:   hcl.Pos{Line: 1, Column: 22, Byte: 21},
+						},
+					},
+				},
+			},
+			``,
+		},
+		{
+			`data.external.foo["baz"].bar`,
+			&Reference{
+				Subject: ResourceInstance{
+					Resource: Resource{
+						Mode: DataResourceMode,
+						Type: "external",
+						Name: "foo",
+					},
+					Key: StringKey("baz"),
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 25, Byte: 24},
+				},
+				Remaining: hcl.Traversal{
+					hcl.TraverseAttr{
+						Name: "bar",
+						SrcRange: hcl.Range{
+							Start: hcl.Pos{Line: 1, Column: 25, Byte: 24},
+							End:   hcl.Pos{Line: 1, Column: 29, Byte: 28},
+						},
+					},
+				},
+			},
+			``,
+		},
+		{
+			`data.external.foo["baz"]`,
+			&Reference{
+				Subject: ResourceInstance{
+					Resource: Resource{
+						Mode: DataResourceMode,
+						Type: "external",
+						Name: "foo",
+					},
+					Key: StringKey("baz"),
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 25, Byte: 24},
+				},
+			},
+			``,
+		},
+		{
+			`data`,
+			nil,
+			`The "data" object must be followed by two attribute names: the data source type and the resource name.`,
+		},
+		{
+			`data.external`,
+			nil,
+			`The "data" object must be followed by two attribute names: the data source type and the resource name.`,
+		},
+
+		// local
+		{
+			`local.foo`,
+			&Reference{
+				Subject: LocalValue{
+					Name: "foo",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 10, Byte: 9},
+				},
+			},
+			``,
+		},
+		{
+			`local.foo.blah`,
+			&Reference{
+				Subject: LocalValue{
+					Name: "foo",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 10, Byte: 9},
+				},
+				Remaining: hcl.Traversal{
+					hcl.TraverseAttr{
+						Name: "blah",
+						SrcRange: hcl.Range{
+							Start: hcl.Pos{Line: 1, Column: 10, Byte: 9},
+							End:   hcl.Pos{Line: 1, Column: 15, Byte: 14},
+						},
+					},
+				},
+			},
+			``,
+		},
+		{
+			`local.foo["blah"]`,
+			&Reference{
+				Subject: LocalValue{
+					Name: "foo",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 10, Byte: 9},
+				},
+				Remaining: hcl.Traversal{
+					hcl.TraverseIndex{
+						Key: cty.StringVal("blah"),
+						SrcRange: hcl.Range{
+							Start: hcl.Pos{Line: 1, Column: 10, Byte: 9},
+							End:   hcl.Pos{Line: 1, Column: 18, Byte: 17},
+						},
+					},
+				},
+			},
+			``,
+		},
+		{
+			`local`,
+			nil,
+			`The "local" object cannot be accessed directly. Instead, access one of its attributes.`,
+		},
+		{
+			`local["foo"]`,
+			nil,
+			`The "local" object does not support this operation.`,
+		},
+
+		// module
+		{
+			`module.foo`,
+			&Reference{
+				Subject: ModuleCall{
+					Name: "foo",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 11, Byte: 10},
+				},
+			},
+			``,
+		},
+		{
+			`module.foo.bar`,
+			&Reference{
+				Subject: ModuleCallInstanceOutput{
+					Call: ModuleCallInstance{
+						Call: ModuleCall{
+							Name: "foo",
+						},
+					},
+					Name: "bar",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 15, Byte: 14},
+				},
+			},
+			``,
+		},
+		{
+			`module.foo.bar.baz`,
+			&Reference{
+				Subject: ModuleCallInstanceOutput{
+					Call: ModuleCallInstance{
+						Call: ModuleCall{
+							Name: "foo",
+						},
+					},
+					Name: "bar",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 15, Byte: 14},
+				},
+				Remaining: hcl.Traversal{
+					hcl.TraverseAttr{
+						Name: "baz",
+						SrcRange: hcl.Range{
+							Start: hcl.Pos{Line: 1, Column: 15, Byte: 14},
+							End:   hcl.Pos{Line: 1, Column: 19, Byte: 18},
+						},
+					},
+				},
+			},
+			``,
+		},
+		{
+			`module.foo["baz"]`,
+			&Reference{
+				Subject: ModuleCallInstance{
+					Call: ModuleCall{
+						Name: "foo",
+					},
+					Key: StringKey("baz"),
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 18, Byte: 17},
+				},
+			},
+			``,
+		},
+		{
+			`module.foo["baz"].bar`,
+			&Reference{
+				Subject: ModuleCallInstanceOutput{
+					Call: ModuleCallInstance{
+						Call: ModuleCall{
+							Name: "foo",
+						},
+						Key: StringKey("baz"),
+					},
+					Name: "bar",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 22, Byte: 21},
+				},
+			},
+			``,
+		},
+		{
+			`module.foo["baz"].bar.boop`,
+			&Reference{
+				Subject: ModuleCallInstanceOutput{
+					Call: ModuleCallInstance{
+						Call: ModuleCall{
+							Name: "foo",
+						},
+						Key: StringKey("baz"),
+					},
+					Name: "bar",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 22, Byte: 21},
+				},
+				Remaining: hcl.Traversal{
+					hcl.TraverseAttr{
+						Name: "boop",
+						SrcRange: hcl.Range{
+							Start: hcl.Pos{Line: 1, Column: 22, Byte: 21},
+							End:   hcl.Pos{Line: 1, Column: 27, Byte: 26},
+						},
+					},
+				},
+			},
+			``,
+		},
+		{
+			`module`,
+			nil,
+			`The "module" object cannot be accessed directly. Instead, access one of its attributes.`,
+		},
+		{
+			`module["foo"]`,
+			nil,
+			`The "module" object does not support this operation.`,
+		},
+
+		// path
+		{
+			`path.module`,
+			&Reference{
+				Subject: PathAttr{
+					Name: "module",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 12, Byte: 11},
+				},
+			},
+			``,
+		},
+		{
+			`path.module.blah`,
+			&Reference{
+				Subject: PathAttr{
+					Name: "module",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 12, Byte: 11},
+				},
+				Remaining: hcl.Traversal{
+					hcl.TraverseAttr{
+						Name: "blah",
+						SrcRange: hcl.Range{
+							Start: hcl.Pos{Line: 1, Column: 12, Byte: 11},
+							End:   hcl.Pos{Line: 1, Column: 17, Byte: 16},
+						},
+					},
+				},
+			},
+			``, // valid at this layer, but will fail during eval because "module" is a string
+		},
+		{
+			`path`,
+			nil,
+			`The "path" object cannot be accessed directly. Instead, access one of its attributes.`,
+		},
+		{
+			`path["module"]`,
+			nil,
+			`The "path" object does not support this operation.`,
+		},
+
+		// self
+		{
+			`self`,
+			&Reference{
+				Subject: Self,
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 5, Byte: 4},
+				},
+			},
+			``,
+		},
+		{
+			`self.blah`,
+			&Reference{
+				Subject: Self,
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 5, Byte: 4},
+				},
+				Remaining: hcl.Traversal{
+					hcl.TraverseAttr{
+						Name: "blah",
+						SrcRange: hcl.Range{
+							Start: hcl.Pos{Line: 1, Column: 5, Byte: 4},
+							End:   hcl.Pos{Line: 1, Column: 10, Byte: 9},
+						},
+					},
+				},
+			},
+			``,
+		},
+
+		// terraform
+		{
+			`terraform.workspace`,
+			&Reference{
+				Subject: TerraformAttr{
+					Name: "workspace",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 20, Byte: 19},
+				},
+			},
+			``,
+		},
+		{
+			`terraform.workspace.blah`,
+			&Reference{
+				Subject: TerraformAttr{
+					Name: "workspace",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 20, Byte: 19},
+				},
+				Remaining: hcl.Traversal{
+					hcl.TraverseAttr{
+						Name: "blah",
+						SrcRange: hcl.Range{
+							Start: hcl.Pos{Line: 1, Column: 20, Byte: 19},
+							End:   hcl.Pos{Line: 1, Column: 25, Byte: 24},
+						},
+					},
+				},
+			},
+			``, // valid at this layer, but will fail during eval because "workspace" is a string
+		},
+		{
+			`terraform`,
+			nil,
+			`The "terraform" object cannot be accessed directly. Instead, access one of its attributes.`,
+		},
+		{
+			`terraform["workspace"]`,
+			nil,
+			`The "terraform" object does not support this operation.`,
+		},
+
+		// var
+		{
+			`var.foo`,
+			&Reference{
+				Subject: InputVariable{
+					Name: "foo",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 8, Byte: 7},
+				},
+			},
+			``,
+		},
+		{
+			`var.foo.blah`,
+			&Reference{
+				Subject: InputVariable{
+					Name: "foo",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 8, Byte: 7},
+				},
+				Remaining: hcl.Traversal{
+					hcl.TraverseAttr{
+						Name: "blah",
+						SrcRange: hcl.Range{
+							Start: hcl.Pos{Line: 1, Column: 8, Byte: 7},
+							End:   hcl.Pos{Line: 1, Column: 13, Byte: 12},
+						},
+					},
+				},
+			},
+			``, // valid at this layer, but will fail during eval because "module" is a string
+		},
+		{
+			`var`,
+			nil,
+			`The "var" object cannot be accessed directly. Instead, access one of its attributes.`,
+		},
+		{
+			`var["foo"]`,
+			nil,
+			`The "var" object does not support this operation.`,
+		},
+
+		// the "resource" prefix forces interpreting the next name as a
+		// resource type name. This is an alias for just using a resource
+		// type name at the top level, to be used only if a later edition
+		// of the Terraform language introduces a new reserved word that
+		// overlaps with a resource type name.
+		{
+			`resource.boop_instance.foo`,
+			&Reference{
+				Subject: Resource{
+					Mode: ManagedResourceMode,
+					Type: "boop_instance",
+					Name: "foo",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 27, Byte: 26},
+				},
+			},
+			``,
+		},
+
+		// We have some names reserved which might be used by a
+		// still-under-discussion proposal for template values or lazy
+		// expressions.
+		{
+			`template.foo`,
+			nil,
+			`The symbol name "template" is reserved for use in a future Terraform version. If you are using a provider that already uses this as a resource type name, add the prefix "resource." to force interpretation as a resource type name.`,
+		},
+		{
+			`lazy.foo`,
+			nil,
+			`The symbol name "lazy" is reserved for use in a future Terraform version. If you are using a provider that already uses this as a resource type name, add the prefix "resource." to force interpretation as a resource type name.`,
+		},
+		{
+			`arg.foo`,
+			nil,
+			`The symbol name "arg" is reserved for use in a future Terraform version. If you are using a provider that already uses this as a resource type name, add the prefix "resource." to force interpretation as a resource type name.`,
+		},
+
+		// anything else, interpreted as a managed resource reference
+		{
+			`boop_instance.foo`,
+			&Reference{
+				Subject: Resource{
+					Mode: ManagedResourceMode,
+					Type: "boop_instance",
+					Name: "foo",
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 18, Byte: 17},
+				},
+			},
+			``,
+		},
+		{
+			`boop_instance.foo.bar`,
+			&Reference{
+				Subject: ResourceInstance{
+					Resource: Resource{
+						Mode: ManagedResourceMode,
+						Type: "boop_instance",
+						Name: "foo",
+					},
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 18, Byte: 17},
+				},
+				Remaining: hcl.Traversal{
+					hcl.TraverseAttr{
+						Name: "bar",
+						SrcRange: hcl.Range{
+							Start: hcl.Pos{Line: 1, Column: 18, Byte: 17},
+							End:   hcl.Pos{Line: 1, Column: 22, Byte: 21},
+						},
+					},
+				},
+			},
+			``,
+		},
+		{
+			`boop_instance.foo["baz"].bar`,
+			&Reference{
+				Subject: ResourceInstance{
+					Resource: Resource{
+						Mode: ManagedResourceMode,
+						Type: "boop_instance",
+						Name: "foo",
+					},
+					Key: StringKey("baz"),
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 25, Byte: 24},
+				},
+				Remaining: hcl.Traversal{
+					hcl.TraverseAttr{
+						Name: "bar",
+						SrcRange: hcl.Range{
+							Start: hcl.Pos{Line: 1, Column: 25, Byte: 24},
+							End:   hcl.Pos{Line: 1, Column: 29, Byte: 28},
+						},
+					},
+				},
+			},
+			``,
+		},
+		{
+			`boop_instance.foo["baz"]`,
+			&Reference{
+				Subject: ResourceInstance{
+					Resource: Resource{
+						Mode: ManagedResourceMode,
+						Type: "boop_instance",
+						Name: "foo",
+					},
+					Key: StringKey("baz"),
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 25, Byte: 24},
+				},
+			},
+			``,
+		},
+		{
+			`boop_instance`,
+			nil,
+			`A reference to a resource type must be followed by at least one attribute access, specifying the resource name.`,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Input, func(t *testing.T) {
+			traversal, travDiags := hclsyntax.ParseTraversalAbs([]byte(test.Input), "", hcl.Pos{Line: 1, Column: 1})
+			if travDiags.HasErrors() {
+				t.Fatal(travDiags.Error())
+			}
+
+			got, diags := ParseRef(traversal)
+
+			switch len(diags) {
+			case 0:
+				if test.WantErr != "" {
+					t.Fatalf("succeeded; want error: %s", test.WantErr)
+				}
+			case 1:
+				if test.WantErr == "" {
+					t.Fatalf("unexpected diagnostics: %s", diags.Err())
+				}
+				if got, want := diags[0].Description().Detail, test.WantErr; got != want {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+			default:
+				t.Fatalf("too many diagnostics: %s", diags.Err())
+			}
+
+			if diags.HasErrors() {
+				return
+			}
+
+			for _, problem := range deep.Equal(got, test.Want) {
+				t.Errorf(problem)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/addrs/parse_target.go b/v1.5.7/internal/addrs/parse_target.go
new file mode 100644
index 0000000..2740ace
--- /dev/null
+++ b/v1.5.7/internal/addrs/parse_target.go
@@ -0,0 +1,371 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Target describes a targeted address with source location information.
+type Target struct {
+	Subject     Targetable
+	SourceRange tfdiags.SourceRange
+}
+
+// ParseTarget attempts to interpret the given traversal as a targetable
+// address. The given traversal must be absolute, or this function will
+// panic.
+//
+// If no error diagnostics are returned, the returned target includes the
+// address that was extracted and the source range it was extracted from.
+//
+// If error diagnostics are returned then the Target value is invalid and
+// must not be used.
+func ParseTarget(traversal hcl.Traversal) (*Target, tfdiags.Diagnostics) {
+	path, remain, diags := parseModuleInstancePrefix(traversal)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	rng := tfdiags.SourceRangeFromHCL(traversal.SourceRange())
+
+	if len(remain) == 0 {
+		return &Target{
+			Subject:     path,
+			SourceRange: rng,
+		}, diags
+	}
+
+	riAddr, moreDiags := parseResourceInstanceUnderModule(path, remain)
+	diags = diags.Append(moreDiags)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	var subject Targetable
+	switch {
+	case riAddr.Resource.Key == NoKey:
+		// We always assume that a no-key instance is meant to
+		// be referring to the whole resource, because the distinction
+		// doesn't really matter for targets anyway.
+		subject = riAddr.ContainingResource()
+	default:
+		subject = riAddr
+	}
+
+	return &Target{
+		Subject:     subject,
+		SourceRange: rng,
+	}, diags
+}
+
+func parseResourceInstanceUnderModule(moduleAddr ModuleInstance, remain hcl.Traversal) (AbsResourceInstance, tfdiags.Diagnostics) {
+	// Note that this helper is used as part of both ParseTarget and
+	// ParseMoveEndpoint, so its error messages should be generic
+	// enough to suit both situations.
+
+	var diags tfdiags.Diagnostics
+
+	mode := ManagedResourceMode
+	if remain.RootName() == "data" {
+		mode = DataResourceMode
+		remain = remain[1:]
+	}
+
+	if len(remain) < 2 {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid address",
+			Detail:   "Resource specification must include a resource type and name.",
+			Subject:  remain.SourceRange().Ptr(),
+		})
+		return AbsResourceInstance{}, diags
+	}
+
+	var typeName, name string
+	switch tt := remain[0].(type) {
+	case hcl.TraverseRoot:
+		typeName = tt.Name
+	case hcl.TraverseAttr:
+		typeName = tt.Name
+	default:
+		switch mode {
+		case ManagedResourceMode:
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid address",
+				Detail:   "A resource type name is required.",
+				Subject:  remain[0].SourceRange().Ptr(),
+			})
+		case DataResourceMode:
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid address",
+				Detail:   "A data source name is required.",
+				Subject:  remain[0].SourceRange().Ptr(),
+			})
+		default:
+			panic("unknown mode")
+		}
+		return AbsResourceInstance{}, diags
+	}
+
+	switch tt := remain[1].(type) {
+	case hcl.TraverseAttr:
+		name = tt.Name
+	default:
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid address",
+			Detail:   "A resource name is required.",
+			Subject:  remain[1].SourceRange().Ptr(),
+		})
+		return AbsResourceInstance{}, diags
+	}
+
+	remain = remain[2:]
+	switch len(remain) {
+	case 0:
+		return moduleAddr.ResourceInstance(mode, typeName, name, NoKey), diags
+	case 1:
+		if tt, ok := remain[0].(hcl.TraverseIndex); ok {
+			key, err := ParseInstanceKey(tt.Key)
+			if err != nil {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid address",
+					Detail:   fmt.Sprintf("Invalid resource instance key: %s.", err),
+					Subject:  remain[0].SourceRange().Ptr(),
+				})
+				return AbsResourceInstance{}, diags
+			}
+
+			return moduleAddr.ResourceInstance(mode, typeName, name, key), diags
+		} else {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid address",
+				Detail:   "Resource instance key must be given in square brackets.",
+				Subject:  remain[0].SourceRange().Ptr(),
+			})
+			return AbsResourceInstance{}, diags
+		}
+	default:
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid address",
+			Detail:   "Unexpected extra operators after address.",
+			Subject:  remain[1].SourceRange().Ptr(),
+		})
+		return AbsResourceInstance{}, diags
+	}
+}
+
+// ParseTargetStr is a helper wrapper around ParseTarget that takes a string
+// and parses it with the HCL native syntax traversal parser before
+// interpreting it.
+//
+// This should be used only in specialized situations since it will cause the
+// created references to not have any meaningful source location information.
+// If a target string is coming from a source that should be identified in
+// error messages then the caller should instead parse it directly using a
+// suitable function from the HCL API and pass the traversal itself to
+// ParseTarget.
+//
+// Error diagnostics are returned if either the parsing fails or the analysis
+// of the traversal fails. There is no way for the caller to distinguish the
+// two kinds of diagnostics programmatically. If error diagnostics are returned
+// the returned target may be nil or incomplete.
+func ParseTargetStr(str string) (*Target, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1})
+	diags = diags.Append(parseDiags)
+	if parseDiags.HasErrors() {
+		return nil, diags
+	}
+
+	target, targetDiags := ParseTarget(traversal)
+	diags = diags.Append(targetDiags)
+	return target, diags
+}
+
+// ParseAbsResource attempts to interpret the given traversal as an absolute
+// resource address, using the same syntax as expected by ParseTarget.
+//
+// If no error diagnostics are returned, the returned target includes the
+// address that was extracted and the source range it was extracted from.
+//
+// If error diagnostics are returned then the AbsResource value is invalid and
+// must not be used.
+func ParseAbsResource(traversal hcl.Traversal) (AbsResource, tfdiags.Diagnostics) {
+	addr, diags := ParseTarget(traversal)
+	if diags.HasErrors() {
+		return AbsResource{}, diags
+	}
+
+	switch tt := addr.Subject.(type) {
+
+	case AbsResource:
+		return tt, diags
+
+	case AbsResourceInstance: // Catch likely user error with specialized message
+		// Assume that the last element of the traversal must be the index,
+		// since that's required for a valid resource instance address.
+		indexStep := traversal[len(traversal)-1]
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid address",
+			Detail:   "A resource address is required. This instance key identifies a specific resource instance, which is not expected here.",
+			Subject:  indexStep.SourceRange().Ptr(),
+		})
+		return AbsResource{}, diags
+
+	case ModuleInstance: // Catch likely user error with specialized message
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid address",
+			Detail:   "A resource address is required here. The module path must be followed by a resource specification.",
+			Subject:  traversal.SourceRange().Ptr(),
+		})
+		return AbsResource{}, diags
+
+	default: // Generic message for other address types
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid address",
+			Detail:   "A resource address is required here.",
+			Subject:  traversal.SourceRange().Ptr(),
+		})
+		return AbsResource{}, diags
+
+	}
+}
+
+// ParseAbsResourceStr is a helper wrapper around ParseAbsResource that takes a
+// string and parses it with the HCL native syntax traversal parser before
+// interpreting it.
+//
+// Error diagnostics are returned if either the parsing fails or the analysis
+// of the traversal fails. There is no way for the caller to distinguish the
+// two kinds of diagnostics programmatically. If error diagnostics are returned
+// the returned address may be incomplete.
+//
+// Since this function has no context about the source of the given string,
+// any returned diagnostics will not have meaningful source location
+// information.
+func ParseAbsResourceStr(str string) (AbsResource, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1})
+	diags = diags.Append(parseDiags)
+	if parseDiags.HasErrors() {
+		return AbsResource{}, diags
+	}
+
+	addr, addrDiags := ParseAbsResource(traversal)
+	diags = diags.Append(addrDiags)
+	return addr, diags
+}
+
+// ParseAbsResourceInstance attempts to interpret the given traversal as an
+// absolute resource instance address, using the same syntax as expected by
+// ParseTarget.
+//
+// If no error diagnostics are returned, the returned target includes the
+// address that was extracted and the source range it was extracted from.
+//
+// If error diagnostics are returned then the AbsResource value is invalid and
+// must not be used.
+func ParseAbsResourceInstance(traversal hcl.Traversal) (AbsResourceInstance, tfdiags.Diagnostics) {
+	addr, diags := ParseTarget(traversal)
+	if diags.HasErrors() {
+		return AbsResourceInstance{}, diags
+	}
+
+	switch tt := addr.Subject.(type) {
+
+	case AbsResource:
+		return tt.Instance(NoKey), diags
+
+	case AbsResourceInstance:
+		return tt, diags
+
+	case ModuleInstance: // Catch likely user error with specialized message
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid address",
+			Detail:   "A resource instance address is required here. The module path must be followed by a resource instance specification.",
+			Subject:  traversal.SourceRange().Ptr(),
+		})
+		return AbsResourceInstance{}, diags
+
+	default: // Generic message for other address types
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid address",
+			Detail:   "A resource address is required here.",
+			Subject:  traversal.SourceRange().Ptr(),
+		})
+		return AbsResourceInstance{}, diags
+
+	}
+}
+
+// ParseAbsResourceInstanceStr is a helper wrapper around
+// ParseAbsResourceInstance that takes a string and parses it with the HCL
+// native syntax traversal parser before interpreting it.
+//
+// Error diagnostics are returned if either the parsing fails or the analysis
+// of the traversal fails. There is no way for the caller to distinguish the
+// two kinds of diagnostics programmatically. If error diagnostics are returned
+// the returned address may be incomplete.
+//
+// Since this function has no context about the source of the given string,
+// any returned diagnostics will not have meaningful source location
+// information.
+func ParseAbsResourceInstanceStr(str string) (AbsResourceInstance, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1})
+	diags = diags.Append(parseDiags)
+	if parseDiags.HasErrors() {
+		return AbsResourceInstance{}, diags
+	}
+
+	addr, addrDiags := ParseAbsResourceInstance(traversal)
+	diags = diags.Append(addrDiags)
+	return addr, diags
+}
+
+// ModuleAddr returns the module address portion of the subject of
+// the recieving target.
+//
+// Regardless of specific address type, all targets always include
+// a module address. They might also include something in that
+// module, which this method always discards if so.
+func (t *Target) ModuleAddr() ModuleInstance {
+	switch addr := t.Subject.(type) {
+	case ModuleInstance:
+		return addr
+	case Module:
+		// We assume that a module address is really
+		// referring to a module path containing only
+		// single-instance modules.
+		return addr.UnkeyedInstanceShim()
+	case AbsResourceInstance:
+		return addr.Module
+	case AbsResource:
+		return addr.Module
+	default:
+		// The above cases should be exhaustive for all
+		// implementations of Targetable.
+		panic(fmt.Sprintf("unsupported target address type %T", addr))
+	}
+}
diff --git a/v1.5.7/internal/addrs/parse_target_test.go b/v1.5.7/internal/addrs/parse_target_test.go
new file mode 100644
index 0000000..e6e110b
--- /dev/null
+++ b/v1.5.7/internal/addrs/parse_target_test.go
@@ -0,0 +1,391 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"testing"
+
+	"github.com/go-test/deep"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestParseTarget(t *testing.T) {
+	tests := []struct {
+		Input   string
+		Want    *Target
+		WantErr string
+	}{
+		{
+			`module.foo`,
+			&Target{
+				Subject: ModuleInstance{
+					{
+						Name: "foo",
+					},
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 11, Byte: 10},
+				},
+			},
+			``,
+		},
+		{
+			`module.foo[2]`,
+			&Target{
+				Subject: ModuleInstance{
+					{
+						Name:        "foo",
+						InstanceKey: IntKey(2),
+					},
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 14, Byte: 13},
+				},
+			},
+			``,
+		},
+		{
+			`module.foo[2].module.bar`,
+			&Target{
+				Subject: ModuleInstance{
+					{
+						Name:        "foo",
+						InstanceKey: IntKey(2),
+					},
+					{
+						Name: "bar",
+					},
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 25, Byte: 24},
+				},
+			},
+			``,
+		},
+		{
+			`aws_instance.foo`,
+			&Target{
+				Subject: AbsResource{
+					Resource: Resource{
+						Mode: ManagedResourceMode,
+						Type: "aws_instance",
+						Name: "foo",
+					},
+					Module: RootModuleInstance,
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 17, Byte: 16},
+				},
+			},
+			``,
+		},
+		{
+			`aws_instance.foo[1]`,
+			&Target{
+				Subject: AbsResourceInstance{
+					Resource: ResourceInstance{
+						Resource: Resource{
+							Mode: ManagedResourceMode,
+							Type: "aws_instance",
+							Name: "foo",
+						},
+						Key: IntKey(1),
+					},
+					Module: RootModuleInstance,
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 20, Byte: 19},
+				},
+			},
+			``,
+		},
+		{
+			`data.aws_instance.foo`,
+			&Target{
+				Subject: AbsResource{
+					Resource: Resource{
+						Mode: DataResourceMode,
+						Type: "aws_instance",
+						Name: "foo",
+					},
+					Module: RootModuleInstance,
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 22, Byte: 21},
+				},
+			},
+			``,
+		},
+		{
+			`data.aws_instance.foo[1]`,
+			&Target{
+				Subject: AbsResourceInstance{
+					Resource: ResourceInstance{
+						Resource: Resource{
+							Mode: DataResourceMode,
+							Type: "aws_instance",
+							Name: "foo",
+						},
+						Key: IntKey(1),
+					},
+					Module: RootModuleInstance,
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 25, Byte: 24},
+				},
+			},
+			``,
+		},
+		{
+			`module.foo.aws_instance.bar`,
+			&Target{
+				Subject: AbsResource{
+					Resource: Resource{
+						Mode: ManagedResourceMode,
+						Type: "aws_instance",
+						Name: "bar",
+					},
+					Module: ModuleInstance{
+						{Name: "foo"},
+					},
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 28, Byte: 27},
+				},
+			},
+			``,
+		},
+		{
+			`module.foo.module.bar.aws_instance.baz`,
+			&Target{
+				Subject: AbsResource{
+					Resource: Resource{
+						Mode: ManagedResourceMode,
+						Type: "aws_instance",
+						Name: "baz",
+					},
+					Module: ModuleInstance{
+						{Name: "foo"},
+						{Name: "bar"},
+					},
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 39, Byte: 38},
+				},
+			},
+			``,
+		},
+		{
+			`module.foo.module.bar.aws_instance.baz["hello"]`,
+			&Target{
+				Subject: AbsResourceInstance{
+					Resource: ResourceInstance{
+						Resource: Resource{
+							Mode: ManagedResourceMode,
+							Type: "aws_instance",
+							Name: "baz",
+						},
+						Key: StringKey("hello"),
+					},
+					Module: ModuleInstance{
+						{Name: "foo"},
+						{Name: "bar"},
+					},
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 48, Byte: 47},
+				},
+			},
+			``,
+		},
+		{
+			`module.foo.data.aws_instance.bar`,
+			&Target{
+				Subject: AbsResource{
+					Resource: Resource{
+						Mode: DataResourceMode,
+						Type: "aws_instance",
+						Name: "bar",
+					},
+					Module: ModuleInstance{
+						{Name: "foo"},
+					},
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 33, Byte: 32},
+				},
+			},
+			``,
+		},
+		{
+			`module.foo.module.bar.data.aws_instance.baz`,
+			&Target{
+				Subject: AbsResource{
+					Resource: Resource{
+						Mode: DataResourceMode,
+						Type: "aws_instance",
+						Name: "baz",
+					},
+					Module: ModuleInstance{
+						{Name: "foo"},
+						{Name: "bar"},
+					},
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 44, Byte: 43},
+				},
+			},
+			``,
+		},
+		{
+			`module.foo.module.bar[0].data.aws_instance.baz`,
+			&Target{
+				Subject: AbsResource{
+					Resource: Resource{
+						Mode: DataResourceMode,
+						Type: "aws_instance",
+						Name: "baz",
+					},
+					Module: ModuleInstance{
+						{Name: "foo", InstanceKey: NoKey},
+						{Name: "bar", InstanceKey: IntKey(0)},
+					},
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 47, Byte: 46},
+				},
+			},
+			``,
+		},
+		{
+			`module.foo.module.bar["a"].data.aws_instance.baz["hello"]`,
+			&Target{
+				Subject: AbsResourceInstance{
+					Resource: ResourceInstance{
+						Resource: Resource{
+							Mode: DataResourceMode,
+							Type: "aws_instance",
+							Name: "baz",
+						},
+						Key: StringKey("hello"),
+					},
+					Module: ModuleInstance{
+						{Name: "foo", InstanceKey: NoKey},
+						{Name: "bar", InstanceKey: StringKey("a")},
+					},
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 58, Byte: 57},
+				},
+			},
+			``,
+		},
+		{
+			`module.foo.module.bar.data.aws_instance.baz["hello"]`,
+			&Target{
+				Subject: AbsResourceInstance{
+					Resource: ResourceInstance{
+						Resource: Resource{
+							Mode: DataResourceMode,
+							Type: "aws_instance",
+							Name: "baz",
+						},
+						Key: StringKey("hello"),
+					},
+					Module: ModuleInstance{
+						{Name: "foo"},
+						{Name: "bar"},
+					},
+				},
+				SourceRange: tfdiags.SourceRange{
+					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:   tfdiags.SourcePos{Line: 1, Column: 53, Byte: 52},
+				},
+			},
+			``,
+		},
+
+		{
+			`aws_instance`,
+			nil,
+			`Resource specification must include a resource type and name.`,
+		},
+		{
+			`module`,
+			nil,
+			`Prefix "module." must be followed by a module name.`,
+		},
+		{
+			`module["baz"]`,
+			nil,
+			`Prefix "module." must be followed by a module name.`,
+		},
+		{
+			`module.baz.bar`,
+			nil,
+			`Resource specification must include a resource type and name.`,
+		},
+		{
+			`aws_instance.foo.bar`,
+			nil,
+			`Resource instance key must be given in square brackets.`,
+		},
+		{
+			`aws_instance.foo[1].baz`,
+			nil,
+			`Unexpected extra operators after address.`,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Input, func(t *testing.T) {
+			traversal, travDiags := hclsyntax.ParseTraversalAbs([]byte(test.Input), "", hcl.Pos{Line: 1, Column: 1})
+			if travDiags.HasErrors() {
+				t.Fatal(travDiags.Error())
+			}
+
+			got, diags := ParseTarget(traversal)
+
+			switch len(diags) {
+			case 0:
+				if test.WantErr != "" {
+					t.Fatalf("succeeded; want error: %s", test.WantErr)
+				}
+			case 1:
+				if test.WantErr == "" {
+					t.Fatalf("unexpected diagnostics: %s", diags.Err())
+				}
+				if got, want := diags[0].Description().Detail, test.WantErr; got != want {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+			default:
+				t.Fatalf("too many diagnostics: %s", diags.Err())
+			}
+
+			if diags.HasErrors() {
+				return
+			}
+
+			for _, problem := range deep.Equal(got, test.Want) {
+				t.Errorf(problem)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/addrs/path_attr.go b/v1.5.7/internal/addrs/path_attr.go
new file mode 100644
index 0000000..e7ff33a
--- /dev/null
+++ b/v1.5.7/internal/addrs/path_attr.go
@@ -0,0 +1,21 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+// PathAttr is the address of an attribute of the "path" object in
+// the interpolation scope, like "path.module".
+type PathAttr struct {
+	referenceable
+	Name string
+}
+
+func (pa PathAttr) String() string {
+	return "path." + pa.Name
+}
+
+func (pa PathAttr) UniqueKey() UniqueKey {
+	return pa // A PathAttr is its own UniqueKey
+}
+
+func (pa PathAttr) uniqueKeySigil() {}
diff --git a/v1.5.7/internal/addrs/provider.go b/v1.5.7/internal/addrs/provider.go
new file mode 100644
index 0000000..80c1dff
--- /dev/null
+++ b/v1.5.7/internal/addrs/provider.go
@@ -0,0 +1,208 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"github.com/hashicorp/hcl/v2"
+	tfaddr "github.com/hashicorp/terraform-registry-address"
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Provider encapsulates a single provider type. In the future this will be
+// extended to include additional fields including Namespace and SourceHost
+type Provider = tfaddr.Provider
+
+// DefaultProviderRegistryHost is the hostname used for provider addresses that do
+// not have an explicit hostname.
+const DefaultProviderRegistryHost = tfaddr.DefaultProviderRegistryHost
+
+// BuiltInProviderHost is the pseudo-hostname used for the "built-in" provider
+// namespace. Built-in provider addresses must also have their namespace set
+// to BuiltInProviderNamespace in order to be considered as built-in.
+const BuiltInProviderHost = tfaddr.BuiltInProviderHost
+
+// BuiltInProviderNamespace is the provider namespace used for "built-in"
+// providers. Built-in provider addresses must also have their hostname
+// set to BuiltInProviderHost in order to be considered as built-in.
+//
+// The this namespace is literally named "builtin", in the hope that users
+// who see FQNs containing this will be able to infer the way in which they are
+// special, even if they haven't encountered the concept formally yet.
+const BuiltInProviderNamespace = tfaddr.BuiltInProviderNamespace
+
+// LegacyProviderNamespace is the special string used in the Namespace field
+// of type Provider to mark a legacy provider address. This special namespace
+// value would normally be invalid, and can be used only when the hostname is
+// DefaultRegistryHost because that host owns the mapping from legacy name to
+// FQN.
+const LegacyProviderNamespace = tfaddr.LegacyProviderNamespace
+
+func IsDefaultProvider(addr Provider) bool {
+	return addr.Hostname == DefaultProviderRegistryHost && addr.Namespace == "hashicorp"
+}
+
+// NewProvider constructs a provider address from its parts, and normalizes
+// the namespace and type parts to lowercase using unicode case folding rules
+// so that resulting addrs.Provider values can be compared using standard
+// Go equality rules (==).
+//
+// The hostname is given as a svchost.Hostname, which is required by the
+// contract of that type to have already been normalized for equality testing.
+//
+// This function will panic if the given namespace or type name are not valid.
+// When accepting namespace or type values from outside the program, use
+// ParseProviderPart first to check that the given value is valid.
+func NewProvider(hostname svchost.Hostname, namespace, typeName string) Provider {
+	return tfaddr.NewProvider(hostname, namespace, typeName)
+}
+
+// ImpliedProviderForUnqualifiedType represents the rules for inferring what
+// provider FQN a user intended when only a naked type name is available.
+//
+// For all except the type name "terraform" this returns a so-called "default"
+// provider, which is under the registry.terraform.io/hashicorp/ namespace.
+//
+// As a special case, the string "terraform" maps to
+// "terraform.io/builtin/terraform" because that is the more likely user
+// intent than the now-unmaintained "registry.terraform.io/hashicorp/terraform"
+// which remains only for compatibility with older Terraform versions.
+func ImpliedProviderForUnqualifiedType(typeName string) Provider {
+	switch typeName {
+	case "terraform":
+		// Note for future maintainers: any additional strings we add here
+		// as implied to be builtin must never also be use as provider names
+		// in the registry.terraform.io/hashicorp/... namespace, because
+		// otherwise older versions of Terraform could implicitly select
+		// the registry name instead of the internal one.
+		return NewBuiltInProvider(typeName)
+	default:
+		return NewDefaultProvider(typeName)
+	}
+}
+
+// NewDefaultProvider returns the default address of a HashiCorp-maintained,
+// Registry-hosted provider.
+func NewDefaultProvider(name string) Provider {
+	return tfaddr.Provider{
+		Type:      MustParseProviderPart(name),
+		Namespace: "hashicorp",
+		Hostname:  DefaultProviderRegistryHost,
+	}
+}
+
+// NewBuiltInProvider returns the address of a "built-in" provider. See
+// the docs for Provider.IsBuiltIn for more information.
+func NewBuiltInProvider(name string) Provider {
+	return tfaddr.Provider{
+		Type:      MustParseProviderPart(name),
+		Namespace: BuiltInProviderNamespace,
+		Hostname:  BuiltInProviderHost,
+	}
+}
+
+// NewLegacyProvider returns a mock address for a provider.
+// This will be removed when ProviderType is fully integrated.
+func NewLegacyProvider(name string) Provider {
+	return Provider{
+		// We intentionally don't normalize and validate the legacy names,
+		// because existing code expects legacy provider names to pass through
+		// verbatim, even if not compliant with our new naming rules.
+		Type:      name,
+		Namespace: LegacyProviderNamespace,
+		Hostname:  DefaultProviderRegistryHost,
+	}
+}
+
+// ParseProviderSourceString parses a value of the form expected in the "source"
+// argument of a required_providers entry and returns the corresponding
+// fully-qualified provider address. This is intended primarily to parse the
+// FQN-like strings returned by terraform-config-inspect.
+//
+// The following are valid source string formats:
+//
+//   - name
+//   - namespace/name
+//   - hostname/namespace/name
+func ParseProviderSourceString(str string) (tfaddr.Provider, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	ret, err := tfaddr.ParseProviderSource(str)
+	if pe, ok := err.(*tfaddr.ParserError); ok {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  pe.Summary,
+			Detail:   pe.Detail,
+		})
+		return ret, diags
+	}
+
+	if !ret.HasKnownNamespace() {
+		ret.Namespace = "hashicorp"
+	}
+
+	return ret, nil
+}
+
+// MustParseProviderSourceString is a wrapper around ParseProviderSourceString that panics if
+// it returns an error.
+func MustParseProviderSourceString(str string) Provider {
+	result, diags := ParseProviderSourceString(str)
+	if diags.HasErrors() {
+		panic(diags.Err().Error())
+	}
+	return result
+}
+
+// ParseProviderPart processes an addrs.Provider namespace or type string
+// provided by an end-user, producing a normalized version if possible or
+// an error if the string contains invalid characters.
+//
+// A provider part is processed in the same way as an individual label in a DNS
+// domain name: it is transformed to lowercase per the usual DNS case mapping
+// and normalization rules and may contain only letters, digits, and dashes.
+// Additionally, dashes may not appear at the start or end of the string.
+//
+// These restrictions are intended to allow these names to appear in fussy
+// contexts such as directory/file names on case-insensitive filesystems,
+// repository names on GitHub, etc. We're using the DNS rules in particular,
+// rather than some similar rules defined locally, because the hostname part
+// of an addrs.Provider is already a hostname and it's ideal to use exactly
+// the same case folding and normalization rules for all of the parts.
+//
+// In practice a provider type string conventionally does not contain dashes
+// either. Such names are permitted, but providers with such type names will be
+// hard to use because their resource type names will not be able to contain
+// the provider type name and thus each resource will need an explicit provider
+// address specified. (A real-world example of such a provider is the
+// "google-beta" variant of the GCP provider, which has resource types that
+// start with the "google_" prefix instead.)
+//
+// It's valid to pass the result of this function as the argument to a
+// subsequent call, in which case the result will be identical.
+func ParseProviderPart(given string) (string, error) {
+	return tfaddr.ParseProviderPart(given)
+}
+
+// MustParseProviderPart is a wrapper around ParseProviderPart that panics if
+// it returns an error.
+func MustParseProviderPart(given string) string {
+	result, err := ParseProviderPart(given)
+	if err != nil {
+		panic(err.Error())
+	}
+	return result
+}
+
+// IsProviderPartNormalized compares a given string to the result of ParseProviderPart(string)
+func IsProviderPartNormalized(str string) (bool, error) {
+	normalized, err := ParseProviderPart(str)
+	if err != nil {
+		return false, err
+	}
+	if str == normalized {
+		return true, nil
+	}
+	return false, nil
+}
diff --git a/v1.5.7/internal/addrs/provider_config.go b/v1.5.7/internal/addrs/provider_config.go
new file mode 100644
index 0000000..d6899b7
--- /dev/null
+++ b/v1.5.7/internal/addrs/provider_config.go
@@ -0,0 +1,413 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+)
+
+// ProviderConfig is an interface type whose dynamic type can be either
+// LocalProviderConfig or AbsProviderConfig, in order to represent situations
+// where a value might either be module-local or absolute but the decision
+// cannot be made until runtime.
+//
+// Where possible, use either LocalProviderConfig or AbsProviderConfig directly
+// instead, to make intent more clear. ProviderConfig can be used only in
+// situations where the recipient of the value has some out-of-band way to
+// determine a "current module" to use if the value turns out to be
+// a LocalProviderConfig.
+//
+// Recipients of non-nil ProviderConfig values that actually need
+// AbsProviderConfig values should call ResolveAbsProviderAddr on the
+// *configs.Config value representing the root module configuration, which
+// handles the translation from local to fully-qualified using mapping tables
+// defined in the configuration.
+//
+// Recipients of a ProviderConfig value can assume it can contain only a
+// LocalProviderConfig value, an AbsProviderConfigValue, or nil to represent
+// the absense of a provider config in situations where that is meaningful.
+type ProviderConfig interface {
+	providerConfig()
+}
+
+// LocalProviderConfig is the address of a provider configuration from the
+// perspective of references in a particular module.
+//
+// Finding the corresponding AbsProviderConfig will require looking up the
+// LocalName in the providers table in the module's configuration; there is
+// no syntax-only translation between these types.
+type LocalProviderConfig struct {
+	LocalName string
+
+	// If not empty, Alias identifies which non-default (aliased) provider
+	// configuration this address refers to.
+	Alias string
+}
+
+var _ ProviderConfig = LocalProviderConfig{}
+
+// NewDefaultLocalProviderConfig returns the address of the default (un-aliased)
+// configuration for the provider with the given local type name.
+func NewDefaultLocalProviderConfig(LocalNameName string) LocalProviderConfig {
+	return LocalProviderConfig{
+		LocalName: LocalNameName,
+	}
+}
+
+// providerConfig Implements addrs.ProviderConfig.
+func (pc LocalProviderConfig) providerConfig() {}
+
+func (pc LocalProviderConfig) String() string {
+	if pc.LocalName == "" {
+		// Should never happen; always indicates a bug
+		return "provider.<invalid>"
+	}
+
+	if pc.Alias != "" {
+		return fmt.Sprintf("provider.%s.%s", pc.LocalName, pc.Alias)
+	}
+
+	return "provider." + pc.LocalName
+}
+
+// StringCompact is an alternative to String that returns the form that can
+// be parsed by ParseProviderConfigCompact, without the "provider." prefix.
+func (pc LocalProviderConfig) StringCompact() string {
+	if pc.Alias != "" {
+		return fmt.Sprintf("%s.%s", pc.LocalName, pc.Alias)
+	}
+	return pc.LocalName
+}
+
+// AbsProviderConfig is the absolute address of a provider configuration
+// within a particular module instance.
+type AbsProviderConfig struct {
+	Module   Module
+	Provider Provider
+	Alias    string
+}
+
+var _ ProviderConfig = AbsProviderConfig{}
+
+// ParseAbsProviderConfig parses the given traversal as an absolute provider
+// configuration address. The following are examples of traversals that can be
+// successfully parsed as absolute provider configuration addresses:
+//
+//   - provider["registry.terraform.io/hashicorp/aws"]
+//   - provider["registry.terraform.io/hashicorp/aws"].foo
+//   - module.bar.provider["registry.terraform.io/hashicorp/aws"]
+//   - module.bar.module.baz.provider["registry.terraform.io/hashicorp/aws"].foo
+//
+// This type of address is used, for example, to record the relationships
+// between resources and provider configurations in the state structure.
+// This type of address is typically not used prominently in the UI, except in
+// error messages that refer to provider configurations.
+func ParseAbsProviderConfig(traversal hcl.Traversal) (AbsProviderConfig, tfdiags.Diagnostics) {
+	modInst, remain, diags := parseModuleInstancePrefix(traversal)
+	var ret AbsProviderConfig
+
+	// Providers cannot resolve within module instances, so verify that there
+	// are no instance keys in the module path before converting to a Module.
+	for _, step := range modInst {
+		if step.InstanceKey != NoKey {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid provider configuration address",
+				Detail:   "Provider address cannot contain module indexes",
+				Subject:  remain.SourceRange().Ptr(),
+			})
+			return ret, diags
+		}
+	}
+	ret.Module = modInst.Module()
+
+	if len(remain) < 2 || remain.RootName() != "provider" {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider configuration address",
+			Detail:   "Provider address must begin with \"provider.\", followed by a provider type name.",
+			Subject:  remain.SourceRange().Ptr(),
+		})
+		return ret, diags
+	}
+	if len(remain) > 3 {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider configuration address",
+			Detail:   "Extraneous operators after provider configuration alias.",
+			Subject:  hcl.Traversal(remain[3:]).SourceRange().Ptr(),
+		})
+		return ret, diags
+	}
+
+	if tt, ok := remain[1].(hcl.TraverseIndex); ok {
+		if !tt.Key.Type().Equals(cty.String) {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid provider configuration address",
+				Detail:   "The prefix \"provider.\" must be followed by a provider type name.",
+				Subject:  remain[1].SourceRange().Ptr(),
+			})
+			return ret, diags
+		}
+		p, sourceDiags := ParseProviderSourceString(tt.Key.AsString())
+		ret.Provider = p
+		if sourceDiags.HasErrors() {
+			diags = diags.Append(sourceDiags)
+			return ret, diags
+		}
+	} else {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider configuration address",
+			Detail:   "The prefix \"provider.\" must be followed by a provider type name.",
+			Subject:  remain[1].SourceRange().Ptr(),
+		})
+		return ret, diags
+	}
+
+	if len(remain) == 3 {
+		if tt, ok := remain[2].(hcl.TraverseAttr); ok {
+			ret.Alias = tt.Name
+		} else {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid provider configuration address",
+				Detail:   "Provider type name must be followed by a configuration alias name.",
+				Subject:  remain[2].SourceRange().Ptr(),
+			})
+			return ret, diags
+		}
+	}
+
+	return ret, diags
+}
+
+// ParseAbsProviderConfigStr is a helper wrapper around ParseAbsProviderConfig
+// that takes a string and parses it with the HCL native syntax traversal parser
+// before interpreting it.
+//
+// This should be used only in specialized situations since it will cause the
+// created references to not have any meaningful source location information.
+// If a reference string is coming from a source that should be identified in
+// error messages then the caller should instead parse it directly using a
+// suitable function from the HCL API and pass the traversal itself to
+// ParseAbsProviderConfig.
+//
+// Error diagnostics are returned if either the parsing fails or the analysis
+// of the traversal fails. There is no way for the caller to distinguish the
+// two kinds of diagnostics programmatically. If error diagnostics are returned
+// the returned address is invalid.
+func ParseAbsProviderConfigStr(str string) (AbsProviderConfig, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1})
+	diags = diags.Append(parseDiags)
+	if parseDiags.HasErrors() {
+		return AbsProviderConfig{}, diags
+	}
+	addr, addrDiags := ParseAbsProviderConfig(traversal)
+	diags = diags.Append(addrDiags)
+	return addr, diags
+}
+
+func ParseLegacyAbsProviderConfigStr(str string) (AbsProviderConfig, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1})
+	diags = diags.Append(parseDiags)
+	if parseDiags.HasErrors() {
+		return AbsProviderConfig{}, diags
+	}
+
+	addr, addrDiags := ParseLegacyAbsProviderConfig(traversal)
+	diags = diags.Append(addrDiags)
+	return addr, diags
+}
+
+// ParseLegacyAbsProviderConfig parses the given traversal as an absolute
+// provider address in the legacy form used by Terraform v0.12 and earlier.
+// The following are examples of traversals that can be successfully parsed as
+// legacy absolute provider configuration addresses:
+//
+//   - provider.aws
+//   - provider.aws.foo
+//   - module.bar.provider.aws
+//   - module.bar.module.baz.provider.aws.foo
+//
+// We can encounter this kind of address in a historical state snapshot that
+// hasn't yet been upgraded by refreshing or applying a plan with
+// Terraform v0.13. Later versions of Terraform reject state snapshots using
+// this format, and so users must follow the Terraform v0.13 upgrade guide
+// in that case.
+//
+// We will not use this address form for any new file formats.
+func ParseLegacyAbsProviderConfig(traversal hcl.Traversal) (AbsProviderConfig, tfdiags.Diagnostics) {
+	modInst, remain, diags := parseModuleInstancePrefix(traversal)
+	var ret AbsProviderConfig
+
+	// Providers cannot resolve within module instances, so verify that there
+	// are no instance keys in the module path before converting to a Module.
+	for _, step := range modInst {
+		if step.InstanceKey != NoKey {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid provider configuration address",
+				Detail:   "Provider address cannot contain module indexes",
+				Subject:  remain.SourceRange().Ptr(),
+			})
+			return ret, diags
+		}
+	}
+	ret.Module = modInst.Module()
+
+	if len(remain) < 2 || remain.RootName() != "provider" {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider configuration address",
+			Detail:   "Provider address must begin with \"provider.\", followed by a provider type name.",
+			Subject:  remain.SourceRange().Ptr(),
+		})
+		return ret, diags
+	}
+	if len(remain) > 3 {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider configuration address",
+			Detail:   "Extraneous operators after provider configuration alias.",
+			Subject:  hcl.Traversal(remain[3:]).SourceRange().Ptr(),
+		})
+		return ret, diags
+	}
+
+	// We always assume legacy-style providers in legacy state ...
+	if tt, ok := remain[1].(hcl.TraverseAttr); ok {
+		// ... unless it's the builtin "terraform" provider, a special case.
+		if tt.Name == "terraform" {
+			ret.Provider = NewBuiltInProvider(tt.Name)
+		} else {
+			ret.Provider = NewLegacyProvider(tt.Name)
+		}
+	} else {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider configuration address",
+			Detail:   "The prefix \"provider.\" must be followed by a provider type name.",
+			Subject:  remain[1].SourceRange().Ptr(),
+		})
+		return ret, diags
+	}
+
+	if len(remain) == 3 {
+		if tt, ok := remain[2].(hcl.TraverseAttr); ok {
+			ret.Alias = tt.Name
+		} else {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid provider configuration address",
+				Detail:   "Provider type name must be followed by a configuration alias name.",
+				Subject:  remain[2].SourceRange().Ptr(),
+			})
+			return ret, diags
+		}
+	}
+
+	return ret, diags
+}
+
+// ProviderConfigDefault returns the address of the default provider config of
+// the given type inside the recieving module instance.
+func (m ModuleInstance) ProviderConfigDefault(provider Provider) AbsProviderConfig {
+	return AbsProviderConfig{
+		Module:   m.Module(),
+		Provider: provider,
+	}
+}
+
+// ProviderConfigAliased returns the address of an aliased provider config of
+// the given type and alias inside the recieving module instance.
+func (m ModuleInstance) ProviderConfigAliased(provider Provider, alias string) AbsProviderConfig {
+	return AbsProviderConfig{
+		Module:   m.Module(),
+		Provider: provider,
+		Alias:    alias,
+	}
+}
+
+// providerConfig Implements addrs.ProviderConfig.
+func (pc AbsProviderConfig) providerConfig() {}
+
+// Inherited returns an address that the receiving configuration address might
+// inherit from in a parent module. The second bool return value indicates if
+// such inheritance is possible, and thus whether the returned address is valid.
+//
+// Inheritance is possible only for default (un-aliased) providers in modules
+// other than the root module. Even if a valid address is returned, inheritence
+// may not be performed for other reasons, such as if the calling module
+// provided explicit provider configurations within the call for this module.
+// The ProviderTransformer graph transform in the main terraform module has the
+// authoritative logic for provider inheritance, and this method is here mainly
+// just for its benefit.
+func (pc AbsProviderConfig) Inherited() (AbsProviderConfig, bool) {
+	// Can't inherit if we're already in the root.
+	if len(pc.Module) == 0 {
+		return AbsProviderConfig{}, false
+	}
+
+	// Can't inherit if we have an alias.
+	if pc.Alias != "" {
+		return AbsProviderConfig{}, false
+	}
+
+	// Otherwise, we might inherit from a configuration with the same
+	// provider type in the parent module instance.
+	parentMod := pc.Module.Parent()
+	return AbsProviderConfig{
+		Module:   parentMod,
+		Provider: pc.Provider,
+	}, true
+
+}
+
+// LegacyString() returns a legacy-style AbsProviderConfig string and should only be used for legacy state shimming.
+func (pc AbsProviderConfig) LegacyString() string {
+	if pc.Alias != "" {
+		if len(pc.Module) == 0 {
+			return fmt.Sprintf("%s.%s.%s", "provider", pc.Provider.LegacyString(), pc.Alias)
+		} else {
+			return fmt.Sprintf("%s.%s.%s.%s", pc.Module.String(), "provider", pc.Provider.LegacyString(), pc.Alias)
+		}
+	}
+	if len(pc.Module) == 0 {
+		return fmt.Sprintf("%s.%s", "provider", pc.Provider.LegacyString())
+	}
+	return fmt.Sprintf("%s.%s.%s", pc.Module.String(), "provider", pc.Provider.LegacyString())
+}
+
+// String() returns a string representation of an AbsProviderConfig in a format like the following examples:
+//
+//   - provider["example.com/namespace/name"]
+//   - provider["example.com/namespace/name"].alias
+//   - module.module-name.provider["example.com/namespace/name"]
+//   - module.module-name.provider["example.com/namespace/name"].alias
+func (pc AbsProviderConfig) String() string {
+	var parts []string
+	if len(pc.Module) > 0 {
+		parts = append(parts, pc.Module.String())
+	}
+
+	parts = append(parts, fmt.Sprintf("provider[%q]", pc.Provider))
+
+	if pc.Alias != "" {
+		parts = append(parts, pc.Alias)
+	}
+
+	return strings.Join(parts, ".")
+}
diff --git a/v1.5.7/internal/addrs/provider_config_test.go b/v1.5.7/internal/addrs/provider_config_test.go
new file mode 100644
index 0000000..e260407
--- /dev/null
+++ b/v1.5.7/internal/addrs/provider_config_test.go
@@ -0,0 +1,283 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/go-test/deep"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+)
+
+func TestParseAbsProviderConfig(t *testing.T) {
+	tests := []struct {
+		Input    string
+		Want     AbsProviderConfig
+		WantDiag string
+	}{
+		{
+			`provider["registry.terraform.io/hashicorp/aws"]`,
+			AbsProviderConfig{
+				Module: RootModule,
+				Provider: Provider{
+					Type:      "aws",
+					Namespace: "hashicorp",
+					Hostname:  "registry.terraform.io",
+				},
+			},
+			``,
+		},
+		{
+			`provider["registry.terraform.io/hashicorp/aws"].foo`,
+			AbsProviderConfig{
+				Module: RootModule,
+				Provider: Provider{
+					Type:      "aws",
+					Namespace: "hashicorp",
+					Hostname:  "registry.terraform.io",
+				},
+				Alias: "foo",
+			},
+			``,
+		},
+		{
+			`module.baz.provider["registry.terraform.io/hashicorp/aws"]`,
+			AbsProviderConfig{
+				Module: Module{"baz"},
+				Provider: Provider{
+					Type:      "aws",
+					Namespace: "hashicorp",
+					Hostname:  "registry.terraform.io",
+				},
+			},
+			``,
+		},
+		{
+			`module.baz.provider["registry.terraform.io/hashicorp/aws"].foo`,
+			AbsProviderConfig{
+				Module: Module{"baz"},
+				Provider: Provider{
+					Type:      "aws",
+					Namespace: "hashicorp",
+					Hostname:  "registry.terraform.io",
+				},
+				Alias: "foo",
+			},
+			``,
+		},
+		{
+			`module.baz["foo"].provider["registry.terraform.io/hashicorp/aws"]`,
+			AbsProviderConfig{},
+			`Provider address cannot contain module indexes`,
+		},
+		{
+			`module.baz[1].provider["registry.terraform.io/hashicorp/aws"]`,
+			AbsProviderConfig{},
+			`Provider address cannot contain module indexes`,
+		},
+		{
+			`module.baz[1].module.bar.provider["registry.terraform.io/hashicorp/aws"]`,
+			AbsProviderConfig{},
+			`Provider address cannot contain module indexes`,
+		},
+		{
+			`aws`,
+			AbsProviderConfig{},
+			`Provider address must begin with "provider.", followed by a provider type name.`,
+		},
+		{
+			`aws.foo`,
+			AbsProviderConfig{},
+			`Provider address must begin with "provider.", followed by a provider type name.`,
+		},
+		{
+			`provider`,
+			AbsProviderConfig{},
+			`Provider address must begin with "provider.", followed by a provider type name.`,
+		},
+		{
+			`provider.aws.foo.bar`,
+			AbsProviderConfig{},
+			`Extraneous operators after provider configuration alias.`,
+		},
+		{
+			`provider["aws"]["foo"]`,
+			AbsProviderConfig{},
+			`Provider type name must be followed by a configuration alias name.`,
+		},
+		{
+			`module.foo`,
+			AbsProviderConfig{},
+			`Provider address must begin with "provider.", followed by a provider type name.`,
+		},
+		{
+			`provider[0]`,
+			AbsProviderConfig{},
+			`The prefix "provider." must be followed by a provider type name.`,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Input, func(t *testing.T) {
+			traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(test.Input), "", hcl.Pos{})
+			if len(parseDiags) != 0 {
+				t.Errorf("unexpected diagnostics during parse")
+				for _, diag := range parseDiags {
+					t.Logf("- %s", diag)
+				}
+				return
+			}
+
+			got, diags := ParseAbsProviderConfig(traversal)
+
+			if test.WantDiag != "" {
+				if len(diags) != 1 {
+					t.Fatalf("got %d diagnostics; want 1", len(diags))
+				}
+				gotDetail := diags[0].Description().Detail
+				if gotDetail != test.WantDiag {
+					t.Fatalf("wrong diagnostic detail\ngot:  %s\nwant: %s", gotDetail, test.WantDiag)
+				}
+				return
+			} else {
+				if len(diags) != 0 {
+					t.Fatalf("got %d diagnostics; want 0", len(diags))
+				}
+			}
+
+			for _, problem := range deep.Equal(got, test.Want) {
+				t.Error(problem)
+			}
+		})
+	}
+}
+
+func TestAbsProviderConfigString(t *testing.T) {
+	tests := []struct {
+		Config AbsProviderConfig
+		Want   string
+	}{
+		{
+			AbsProviderConfig{
+				Module:   RootModule,
+				Provider: NewLegacyProvider("foo"),
+			},
+			`provider["registry.terraform.io/-/foo"]`,
+		},
+		{
+			AbsProviderConfig{
+				Module:   RootModule.Child("child_module"),
+				Provider: NewDefaultProvider("foo"),
+			},
+			`module.child_module.provider["registry.terraform.io/hashicorp/foo"]`,
+		},
+		{
+			AbsProviderConfig{
+				Module:   RootModule,
+				Alias:    "bar",
+				Provider: NewDefaultProvider("foo"),
+			},
+			`provider["registry.terraform.io/hashicorp/foo"].bar`,
+		},
+		{
+			AbsProviderConfig{
+				Module:   RootModule.Child("child_module"),
+				Alias:    "bar",
+				Provider: NewDefaultProvider("foo"),
+			},
+			`module.child_module.provider["registry.terraform.io/hashicorp/foo"].bar`,
+		},
+	}
+
+	for _, test := range tests {
+		got := test.Config.String()
+		if got != test.Want {
+			t.Errorf("wrong result. Got %s, want %s\n", got, test.Want)
+		}
+	}
+}
+
+func TestAbsProviderConfigLegacyString(t *testing.T) {
+	tests := []struct {
+		Config AbsProviderConfig
+		Want   string
+	}{
+		{
+			AbsProviderConfig{
+				Module:   RootModule,
+				Provider: NewLegacyProvider("foo"),
+			},
+			`provider.foo`,
+		},
+		{
+			AbsProviderConfig{
+				Module:   RootModule.Child("child_module"),
+				Provider: NewLegacyProvider("foo"),
+			},
+			`module.child_module.provider.foo`,
+		},
+		{
+			AbsProviderConfig{
+				Module:   RootModule,
+				Alias:    "bar",
+				Provider: NewLegacyProvider("foo"),
+			},
+			`provider.foo.bar`,
+		},
+		{
+			AbsProviderConfig{
+				Module:   RootModule.Child("child_module"),
+				Alias:    "bar",
+				Provider: NewLegacyProvider("foo"),
+			},
+			`module.child_module.provider.foo.bar`,
+		},
+	}
+
+	for _, test := range tests {
+		got := test.Config.LegacyString()
+		if got != test.Want {
+			t.Errorf("wrong result. Got %s, want %s\n", got, test.Want)
+		}
+	}
+}
+
+func TestParseLegacyAbsProviderConfigStr(t *testing.T) {
+	tests := []struct {
+		Config string
+		Want   AbsProviderConfig
+	}{
+		{
+			`provider.foo`,
+			AbsProviderConfig{
+				Module:   RootModule,
+				Provider: NewLegacyProvider("foo"),
+			},
+		},
+		{
+			`module.child_module.provider.foo`,
+			AbsProviderConfig{
+				Module:   RootModule.Child("child_module"),
+				Provider: NewLegacyProvider("foo"),
+			},
+		},
+		{
+			`provider.terraform`,
+			AbsProviderConfig{
+				Module:   RootModule,
+				Provider: NewBuiltInProvider("terraform"),
+			},
+		},
+	}
+
+	for _, test := range tests {
+		got, _ := ParseLegacyAbsProviderConfigStr(test.Config)
+		if !reflect.DeepEqual(got, test.Want) {
+			t.Errorf("wrong result. Got %s, want %s\n", got, test.Want)
+		}
+	}
+}
diff --git a/v1.5.7/internal/addrs/provider_test.go b/v1.5.7/internal/addrs/provider_test.go
new file mode 100644
index 0000000..9754a8c
--- /dev/null
+++ b/v1.5.7/internal/addrs/provider_test.go
@@ -0,0 +1,563 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"testing"
+
+	"github.com/go-test/deep"
+	svchost "github.com/hashicorp/terraform-svchost"
+)
+
+func TestProviderString(t *testing.T) {
+	tests := []struct {
+		Input Provider
+		Want  string
+	}{
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  DefaultProviderRegistryHost,
+				Namespace: "hashicorp",
+			},
+			NewDefaultProvider("test").String(),
+		},
+		{
+			Provider{
+				Type:      "test-beta",
+				Hostname:  DefaultProviderRegistryHost,
+				Namespace: "hashicorp",
+			},
+			NewDefaultProvider("test-beta").String(),
+		},
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  "registry.terraform.com",
+				Namespace: "hashicorp",
+			},
+			"registry.terraform.com/hashicorp/test",
+		},
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  DefaultProviderRegistryHost,
+				Namespace: "othercorp",
+			},
+			DefaultProviderRegistryHost.ForDisplay() + "/othercorp/test",
+		},
+	}
+
+	for _, test := range tests {
+		got := test.Input.String()
+		if got != test.Want {
+			t.Errorf("wrong result for %s\n", test.Input.String())
+		}
+	}
+}
+
+func TestProviderLegacyString(t *testing.T) {
+	tests := []struct {
+		Input Provider
+		Want  string
+	}{
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  DefaultProviderRegistryHost,
+				Namespace: LegacyProviderNamespace,
+			},
+			"test",
+		},
+		{
+			Provider{
+				Type:      "terraform",
+				Hostname:  BuiltInProviderHost,
+				Namespace: BuiltInProviderNamespace,
+			},
+			"terraform",
+		},
+	}
+
+	for _, test := range tests {
+		got := test.Input.LegacyString()
+		if got != test.Want {
+			t.Errorf("wrong result for %s\ngot:  %s\nwant: %s", test.Input.String(), got, test.Want)
+		}
+	}
+}
+
+func TestProviderDisplay(t *testing.T) {
+	tests := []struct {
+		Input Provider
+		Want  string
+	}{
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  DefaultProviderRegistryHost,
+				Namespace: "hashicorp",
+			},
+			"hashicorp/test",
+		},
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  "registry.terraform.com",
+				Namespace: "hashicorp",
+			},
+			"registry.terraform.com/hashicorp/test",
+		},
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  DefaultProviderRegistryHost,
+				Namespace: "othercorp",
+			},
+			"othercorp/test",
+		},
+	}
+
+	for _, test := range tests {
+		got := test.Input.ForDisplay()
+		if got != test.Want {
+			t.Errorf("wrong result for %s\n", test.Input.String())
+		}
+	}
+}
+
+func TestProviderIsDefaultProvider(t *testing.T) {
+	tests := []struct {
+		Input Provider
+		Want  bool
+	}{
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  DefaultProviderRegistryHost,
+				Namespace: "hashicorp",
+			},
+			true,
+		},
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  "registry.terraform.com",
+				Namespace: "hashicorp",
+			},
+			false,
+		},
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  DefaultProviderRegistryHost,
+				Namespace: "othercorp",
+			},
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		got := IsDefaultProvider(test.Input)
+		if got != test.Want {
+			t.Errorf("wrong result for %s\n", test.Input.String())
+		}
+	}
+}
+
+func TestProviderIsBuiltIn(t *testing.T) {
+	tests := []struct {
+		Input Provider
+		Want  bool
+	}{
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  BuiltInProviderHost,
+				Namespace: BuiltInProviderNamespace,
+			},
+			true,
+		},
+		{
+			Provider{
+				Type:      "terraform",
+				Hostname:  BuiltInProviderHost,
+				Namespace: BuiltInProviderNamespace,
+			},
+			true,
+		},
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  BuiltInProviderHost,
+				Namespace: "boop",
+			},
+			false,
+		},
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  DefaultProviderRegistryHost,
+				Namespace: BuiltInProviderNamespace,
+			},
+			false,
+		},
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  DefaultProviderRegistryHost,
+				Namespace: "hashicorp",
+			},
+			false,
+		},
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  "registry.terraform.com",
+				Namespace: "hashicorp",
+			},
+			false,
+		},
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  DefaultProviderRegistryHost,
+				Namespace: "othercorp",
+			},
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		got := test.Input.IsBuiltIn()
+		if got != test.Want {
+			t.Errorf("wrong result for %s\ngot:  %#v\nwant: %#v", test.Input.String(), got, test.Want)
+		}
+	}
+}
+
+func TestProviderIsLegacy(t *testing.T) {
+	tests := []struct {
+		Input Provider
+		Want  bool
+	}{
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  DefaultProviderRegistryHost,
+				Namespace: LegacyProviderNamespace,
+			},
+			true,
+		},
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  "registry.terraform.com",
+				Namespace: LegacyProviderNamespace,
+			},
+			false,
+		},
+		{
+			Provider{
+				Type:      "test",
+				Hostname:  DefaultProviderRegistryHost,
+				Namespace: "hashicorp",
+			},
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		got := test.Input.IsLegacy()
+		if got != test.Want {
+			t.Errorf("wrong result for %s\n", test.Input.String())
+		}
+	}
+}
+
+func TestParseProviderSourceStr(t *testing.T) {
+	tests := map[string]struct {
+		Want Provider
+		Err  bool
+	}{
+		"registry.terraform.io/hashicorp/aws": {
+			Provider{
+				Type:      "aws",
+				Namespace: "hashicorp",
+				Hostname:  DefaultProviderRegistryHost,
+			},
+			false,
+		},
+		"registry.Terraform.io/HashiCorp/AWS": {
+			Provider{
+				Type:      "aws",
+				Namespace: "hashicorp",
+				Hostname:  DefaultProviderRegistryHost,
+			},
+			false,
+		},
+		"hashicorp/aws": {
+			Provider{
+				Type:      "aws",
+				Namespace: "hashicorp",
+				Hostname:  DefaultProviderRegistryHost,
+			},
+			false,
+		},
+		"HashiCorp/AWS": {
+			Provider{
+				Type:      "aws",
+				Namespace: "hashicorp",
+				Hostname:  DefaultProviderRegistryHost,
+			},
+			false,
+		},
+		"aws": {
+			Provider{
+				Type:      "aws",
+				Namespace: "hashicorp",
+				Hostname:  DefaultProviderRegistryHost,
+			},
+			false,
+		},
+		"AWS": {
+			Provider{
+				Type:      "aws",
+				Namespace: "hashicorp",
+				Hostname:  DefaultProviderRegistryHost,
+			},
+			false,
+		},
+		"example.com/foo-bar/baz-boop": {
+			Provider{
+				Type:      "baz-boop",
+				Namespace: "foo-bar",
+				Hostname:  svchost.Hostname("example.com"),
+			},
+			false,
+		},
+		"foo-bar/baz-boop": {
+			Provider{
+				Type:      "baz-boop",
+				Namespace: "foo-bar",
+				Hostname:  DefaultProviderRegistryHost,
+			},
+			false,
+		},
+		"localhost:8080/foo/bar": {
+			Provider{
+				Type:      "bar",
+				Namespace: "foo",
+				Hostname:  svchost.Hostname("localhost:8080"),
+			},
+			false,
+		},
+		"example.com/too/many/parts/here": {
+			Provider{},
+			true,
+		},
+		"/too///many//slashes": {
+			Provider{},
+			true,
+		},
+		"///": {
+			Provider{},
+			true,
+		},
+		"/ / /": { // empty strings
+			Provider{},
+			true,
+		},
+		"badhost!/hashicorp/aws": {
+			Provider{},
+			true,
+		},
+		"example.com/badnamespace!/aws": {
+			Provider{},
+			true,
+		},
+		"example.com/bad--namespace/aws": {
+			Provider{},
+			true,
+		},
+		"example.com/-badnamespace/aws": {
+			Provider{},
+			true,
+		},
+		"example.com/badnamespace-/aws": {
+			Provider{},
+			true,
+		},
+		"example.com/bad.namespace/aws": {
+			Provider{},
+			true,
+		},
+		"example.com/hashicorp/badtype!": {
+			Provider{},
+			true,
+		},
+		"example.com/hashicorp/bad--type": {
+			Provider{},
+			true,
+		},
+		"example.com/hashicorp/-badtype": {
+			Provider{},
+			true,
+		},
+		"example.com/hashicorp/badtype-": {
+			Provider{},
+			true,
+		},
+		"example.com/hashicorp/bad.type": {
+			Provider{},
+			true,
+		},
+
+		// We forbid the terraform- prefix both because it's redundant to
+		// include "terraform" in a Terraform provider name and because we use
+		// the longer prefix terraform-provider- to hint for users who might be
+		// accidentally using the git repository name or executable file name
+		// instead of the provider type.
+		"example.com/hashicorp/terraform-provider-bad": {
+			Provider{},
+			true,
+		},
+		"example.com/hashicorp/terraform-bad": {
+			Provider{},
+			true,
+		},
+	}
+
+	for name, test := range tests {
+		got, diags := ParseProviderSourceString(name)
+		for _, problem := range deep.Equal(got, test.Want) {
+			t.Errorf(problem)
+		}
+		if len(diags) > 0 {
+			if test.Err == false {
+				t.Errorf("got error, expected success")
+			}
+		} else {
+			if test.Err {
+				t.Errorf("got success, expected error")
+			}
+		}
+	}
+}
+
+func TestParseProviderPart(t *testing.T) {
+	tests := map[string]struct {
+		Want  string
+		Error string
+	}{
+		`foo`: {
+			`foo`,
+			``,
+		},
+		`FOO`: {
+			`foo`,
+			``,
+		},
+		`Foo`: {
+			`foo`,
+			``,
+		},
+		`abc-123`: {
+			`abc-123`,
+			``,
+		},
+		`Испытание`: {
+			`испытание`,
+			``,
+		},
+		`münchen`: { // this is a precomposed u with diaeresis
+			`münchen`, // this is a precomposed u with diaeresis
+			``,
+		},
+		`münchen`: { // this is a separate u and combining diaeresis
+			`münchen`, // this is a precomposed u with diaeresis
+			``,
+		},
+		`abc--123`: {
+			``,
+			`cannot use multiple consecutive dashes`,
+		},
+		`xn--80akhbyknj4f`: { // this is the punycode form of "испытание", but we don't accept punycode here
+			``,
+			`cannot use multiple consecutive dashes`,
+		},
+		`abc.123`: {
+			``,
+			`dots are not allowed`,
+		},
+		`-abc123`: {
+			``,
+			`must contain only letters, digits, and dashes, and may not use leading or trailing dashes`,
+		},
+		`abc123-`: {
+			``,
+			`must contain only letters, digits, and dashes, and may not use leading or trailing dashes`,
+		},
+		``: {
+			``,
+			`must have at least one character`,
+		},
+	}
+
+	for given, test := range tests {
+		t.Run(given, func(t *testing.T) {
+			got, err := ParseProviderPart(given)
+			if test.Error != "" {
+				if err == nil {
+					t.Errorf("unexpected success\ngot:  %s\nwant: %s", err, test.Error)
+				} else if got := err.Error(); got != test.Error {
+					t.Errorf("wrong error\ngot:  %s\nwant: %s", got, test.Error)
+				}
+			} else {
+				if err != nil {
+					t.Errorf("unexpected error\ngot:  %s\nwant: <nil>", err)
+				} else if got != test.Want {
+					t.Errorf("wrong result\ngot:  %s\nwant: %s", got, test.Want)
+				}
+			}
+		})
+	}
+}
+
+func TestProviderEquals(t *testing.T) {
+	tests := []struct {
+		InputP Provider
+		OtherP Provider
+		Want   bool
+	}{
+		{
+			NewProvider(DefaultProviderRegistryHost, "foo", "test"),
+			NewProvider(DefaultProviderRegistryHost, "foo", "test"),
+			true,
+		},
+		{
+			NewProvider(DefaultProviderRegistryHost, "foo", "test"),
+			NewProvider(DefaultProviderRegistryHost, "bar", "test"),
+			false,
+		},
+		{
+			NewProvider(DefaultProviderRegistryHost, "foo", "test"),
+			NewProvider(DefaultProviderRegistryHost, "foo", "my-test"),
+			false,
+		},
+		{
+			NewProvider(DefaultProviderRegistryHost, "foo", "test"),
+			NewProvider("example.com", "foo", "test"),
+			false,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.InputP.String(), func(t *testing.T) {
+			got := test.InputP.Equals(test.OtherP)
+			if got != test.Want {
+				t.Errorf("wrong result\ngot:  %v\nwant: %v", got, test.Want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/addrs/referenceable.go b/v1.5.7/internal/addrs/referenceable.go
new file mode 100644
index 0000000..87ced61
--- /dev/null
+++ b/v1.5.7/internal/addrs/referenceable.go
@@ -0,0 +1,26 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+// Referenceable is an interface implemented by all address types that can
+// appear as references in configuration language expressions.
+type Referenceable interface {
+	// All implementations of this interface must be covered by the type switch
+	// in lang.Scope.buildEvalContext.
+	referenceableSigil()
+
+	// All Referenceable address types must have unique keys.
+	UniqueKeyer
+
+	// String produces a string representation of the address that could be
+	// parsed as a HCL traversal and passed to ParseRef to produce an identical
+	// result.
+	String() string
+}
+
+type referenceable struct {
+}
+
+func (r referenceable) referenceableSigil() {
+}
diff --git a/v1.5.7/internal/addrs/resource.go b/v1.5.7/internal/addrs/resource.go
new file mode 100644
index 0000000..e74b013
--- /dev/null
+++ b/v1.5.7/internal/addrs/resource.go
@@ -0,0 +1,482 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"strings"
+)
+
+// Resource is an address for a resource block within configuration, which
+// contains potentially-multiple resource instances if that configuration
+// block uses "count" or "for_each".
+type Resource struct {
+	referenceable
+	Mode ResourceMode
+	Type string
+	Name string
+}
+
+func (r Resource) String() string {
+	switch r.Mode {
+	case ManagedResourceMode:
+		return fmt.Sprintf("%s.%s", r.Type, r.Name)
+	case DataResourceMode:
+		return fmt.Sprintf("data.%s.%s", r.Type, r.Name)
+	default:
+		// Should never happen, but we'll return a string here rather than
+		// crashing just in case it does.
+		return fmt.Sprintf("<invalid>.%s.%s", r.Type, r.Name)
+	}
+}
+
+func (r Resource) Equal(o Resource) bool {
+	return r.Mode == o.Mode && r.Name == o.Name && r.Type == o.Type
+}
+
+func (r Resource) Less(o Resource) bool {
+	switch {
+	case r.Mode != o.Mode:
+		return r.Mode == DataResourceMode
+
+	case r.Type != o.Type:
+		return r.Type < o.Type
+
+	case r.Name != o.Name:
+		return r.Name < o.Name
+
+	default:
+		return false
+	}
+}
+
+func (r Resource) UniqueKey() UniqueKey {
+	return r // A Resource is its own UniqueKey
+}
+
+func (r Resource) uniqueKeySigil() {}
+
+// Instance produces the address for a specific instance of the receiver
+// that is idenfied by the given key.
+func (r Resource) Instance(key InstanceKey) ResourceInstance {
+	return ResourceInstance{
+		Resource: r,
+		Key:      key,
+	}
+}
+
+// Absolute returns an AbsResource from the receiver and the given module
+// instance address.
+func (r Resource) Absolute(module ModuleInstance) AbsResource {
+	return AbsResource{
+		Module:   module,
+		Resource: r,
+	}
+}
+
+// InModule returns a ConfigResource from the receiver and the given module
+// address.
+func (r Resource) InModule(module Module) ConfigResource {
+	return ConfigResource{
+		Module:   module,
+		Resource: r,
+	}
+}
+
+// ImpliedProvider returns the implied provider type name, for e.g. the "aws" in
+// "aws_instance"
+func (r Resource) ImpliedProvider() string {
+	typeName := r.Type
+	if under := strings.Index(typeName, "_"); under != -1 {
+		typeName = typeName[:under]
+	}
+
+	return typeName
+}
+
+// ResourceInstance is an address for a specific instance of a resource.
+// When a resource is defined in configuration with "count" or "for_each" it
+// produces zero or more instances, which can be addressed using this type.
+type ResourceInstance struct {
+	referenceable
+	Resource Resource
+	Key      InstanceKey
+}
+
+func (r ResourceInstance) ContainingResource() Resource {
+	return r.Resource
+}
+
+func (r ResourceInstance) String() string {
+	if r.Key == NoKey {
+		return r.Resource.String()
+	}
+	return r.Resource.String() + r.Key.String()
+}
+
+func (r ResourceInstance) Equal(o ResourceInstance) bool {
+	return r.Key == o.Key && r.Resource.Equal(o.Resource)
+}
+
+func (r ResourceInstance) Less(o ResourceInstance) bool {
+	if !r.Resource.Equal(o.Resource) {
+		return r.Resource.Less(o.Resource)
+	}
+
+	if r.Key != o.Key {
+		return InstanceKeyLess(r.Key, o.Key)
+	}
+
+	return false
+}
+
+func (r ResourceInstance) UniqueKey() UniqueKey {
+	return r // A ResourceInstance is its own UniqueKey
+}
+
+func (r ResourceInstance) uniqueKeySigil() {}
+
+// Absolute returns an AbsResourceInstance from the receiver and the given module
+// instance address.
+func (r ResourceInstance) Absolute(module ModuleInstance) AbsResourceInstance {
+	return AbsResourceInstance{
+		Module:   module,
+		Resource: r,
+	}
+}
+
+// AbsResource is an absolute address for a resource under a given module path.
+type AbsResource struct {
+	targetable
+	Module   ModuleInstance
+	Resource Resource
+}
+
+// Resource returns the address of a particular resource within the receiver.
+func (m ModuleInstance) Resource(mode ResourceMode, typeName string, name string) AbsResource {
+	return AbsResource{
+		Module: m,
+		Resource: Resource{
+			Mode: mode,
+			Type: typeName,
+			Name: name,
+		},
+	}
+}
+
+// Instance produces the address for a specific instance of the receiver
+// that is idenfied by the given key.
+func (r AbsResource) Instance(key InstanceKey) AbsResourceInstance {
+	return AbsResourceInstance{
+		Module:   r.Module,
+		Resource: r.Resource.Instance(key),
+	}
+}
+
+// Config returns the unexpanded ConfigResource for this AbsResource.
+func (r AbsResource) Config() ConfigResource {
+	return ConfigResource{
+		Module:   r.Module.Module(),
+		Resource: r.Resource,
+	}
+}
+
+// TargetContains implements Targetable by returning true if the given other
+// address is either equal to the receiver or is an instance of the
+// receiver.
+func (r AbsResource) TargetContains(other Targetable) bool {
+	switch to := other.(type) {
+
+	case AbsResource:
+		// We'll use our stringification as a cheat-ish way to test for equality.
+		return to.String() == r.String()
+
+	case ConfigResource:
+		// if an absolute resource from parsing a target address contains a
+		// ConfigResource, the string representation will match
+		return to.String() == r.String()
+
+	case AbsResourceInstance:
+		return r.TargetContains(to.ContainingResource())
+
+	default:
+		return false
+
+	}
+}
+
+func (r AbsResource) AddrType() TargetableAddrType {
+	return AbsResourceAddrType
+}
+
+func (r AbsResource) String() string {
+	if len(r.Module) == 0 {
+		return r.Resource.String()
+	}
+	return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String())
+}
+
+// AffectedAbsResource returns the AbsResource.
+func (r AbsResource) AffectedAbsResource() AbsResource {
+	return r
+}
+
+func (r AbsResource) Equal(o AbsResource) bool {
+	return r.Module.Equal(o.Module) && r.Resource.Equal(o.Resource)
+}
+
+func (r AbsResource) Less(o AbsResource) bool {
+	if !r.Module.Equal(o.Module) {
+		return r.Module.Less(o.Module)
+	}
+
+	if !r.Resource.Equal(o.Resource) {
+		return r.Resource.Less(o.Resource)
+	}
+
+	return false
+}
+
+func (r AbsResource) absMoveableSigil() {
+	// AbsResource is moveable
+}
+
+type absResourceKey string
+
+func (r absResourceKey) uniqueKeySigil() {}
+
+func (r AbsResource) UniqueKey() UniqueKey {
+	return absResourceKey(r.String())
+}
+
+// AbsResourceInstance is an absolute address for a resource instance under a
+// given module path.
+type AbsResourceInstance struct {
+	targetable
+	Module   ModuleInstance
+	Resource ResourceInstance
+}
+
+// ResourceInstance returns the address of a particular resource instance within the receiver.
+func (m ModuleInstance) ResourceInstance(mode ResourceMode, typeName string, name string, key InstanceKey) AbsResourceInstance {
+	return AbsResourceInstance{
+		Module: m,
+		Resource: ResourceInstance{
+			Resource: Resource{
+				Mode: mode,
+				Type: typeName,
+				Name: name,
+			},
+			Key: key,
+		},
+	}
+}
+
+// ContainingResource returns the address of the resource that contains the
+// receving resource instance. In other words, it discards the key portion
+// of the address to produce an AbsResource value.
+func (r AbsResourceInstance) ContainingResource() AbsResource {
+	return AbsResource{
+		Module:   r.Module,
+		Resource: r.Resource.ContainingResource(),
+	}
+}
+
+// ConfigResource returns the address of the configuration block that declared
+// this instance.
+func (r AbsResourceInstance) ConfigResource() ConfigResource {
+	return ConfigResource{
+		Module:   r.Module.Module(),
+		Resource: r.Resource.Resource,
+	}
+}
+
+// TargetContains implements Targetable by returning true if the given other
+// address is equal to the receiver.
+func (r AbsResourceInstance) TargetContains(other Targetable) bool {
+	switch to := other.(type) {
+
+	// while we currently don't start with an AbsResourceInstance as a target
+	// address, check all resource types for consistency.
+	case AbsResourceInstance:
+		// We'll use our stringification as a cheat-ish way to test for equality.
+		return to.String() == r.String()
+	case ConfigResource:
+		return to.String() == r.String()
+	case AbsResource:
+		return to.String() == r.String()
+
+	default:
+		return false
+
+	}
+}
+
+func (r AbsResourceInstance) AddrType() TargetableAddrType {
+	return AbsResourceInstanceAddrType
+}
+
+func (r AbsResourceInstance) String() string {
+	if len(r.Module) == 0 {
+		return r.Resource.String()
+	}
+	return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String())
+}
+
+// AffectedAbsResource returns the AbsResource for the instance.
+func (r AbsResourceInstance) AffectedAbsResource() AbsResource {
+	return AbsResource{
+		Module:   r.Module,
+		Resource: r.Resource.Resource,
+	}
+}
+
+func (r AbsResourceInstance) CheckRule(t CheckRuleType, i int) CheckRule {
+	return CheckRule{
+		Container: r,
+		Type:      t,
+		Index:     i,
+	}
+}
+
+func (v AbsResourceInstance) CheckableKind() CheckableKind {
+	return CheckableResource
+}
+
+func (r AbsResourceInstance) Equal(o AbsResourceInstance) bool {
+	return r.Module.Equal(o.Module) && r.Resource.Equal(o.Resource)
+}
+
+// Less returns true if the receiver should sort before the given other value
+// in a sorted list of addresses.
+func (r AbsResourceInstance) Less(o AbsResourceInstance) bool {
+	if !r.Module.Equal(o.Module) {
+		return r.Module.Less(o.Module)
+	}
+
+	if !r.Resource.Equal(o.Resource) {
+		return r.Resource.Less(o.Resource)
+	}
+
+	return false
+}
+
+// AbsResourceInstance is a Checkable
+func (r AbsResourceInstance) checkableSigil() {}
+
+func (r AbsResourceInstance) ConfigCheckable() ConfigCheckable {
+	// The ConfigCheckable for an AbsResourceInstance is its ConfigResource.
+	return r.ConfigResource()
+}
+
+type absResourceInstanceKey string
+
+func (r AbsResourceInstance) UniqueKey() UniqueKey {
+	return absResourceInstanceKey(r.String())
+}
+
+func (r absResourceInstanceKey) uniqueKeySigil() {}
+
+func (r AbsResourceInstance) absMoveableSigil() {
+	// AbsResourceInstance is moveable
+}
+
+// ConfigResource is an address for a resource within a configuration.
+type ConfigResource struct {
+	targetable
+	Module   Module
+	Resource Resource
+}
+
+// Resource returns the address of a particular resource within the module.
+func (m Module) Resource(mode ResourceMode, typeName string, name string) ConfigResource {
+	return ConfigResource{
+		Module: m,
+		Resource: Resource{
+			Mode: mode,
+			Type: typeName,
+			Name: name,
+		},
+	}
+}
+
+// Absolute produces the address for the receiver within a specific module instance.
+func (r ConfigResource) Absolute(module ModuleInstance) AbsResource {
+	return AbsResource{
+		Module:   module,
+		Resource: r.Resource,
+	}
+}
+
+// TargetContains implements Targetable by returning true if the given other
+// address is either equal to the receiver or is an instance of the
+// receiver.
+func (r ConfigResource) TargetContains(other Targetable) bool {
+	switch to := other.(type) {
+	case ConfigResource:
+		// We'll use our stringification as a cheat-ish way to test for equality.
+		return to.String() == r.String()
+	case AbsResource:
+		return r.TargetContains(to.Config())
+	case AbsResourceInstance:
+		return r.TargetContains(to.ContainingResource())
+	default:
+		return false
+	}
+}
+
+func (r ConfigResource) AddrType() TargetableAddrType {
+	return ConfigResourceAddrType
+}
+
+func (r ConfigResource) String() string {
+	if len(r.Module) == 0 {
+		return r.Resource.String()
+	}
+	return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String())
+}
+
+func (r ConfigResource) Equal(o ConfigResource) bool {
+	return r.Module.Equal(o.Module) && r.Resource.Equal(o.Resource)
+}
+
+func (r ConfigResource) UniqueKey() UniqueKey {
+	return configResourceKey(r.String())
+}
+
+func (r ConfigResource) configMoveableSigil() {
+	// ConfigResource is moveable
+}
+
+func (r ConfigResource) configCheckableSigil() {
+	// ConfigResource represents a configuration object that declares checkable objects
+}
+
+func (v ConfigResource) CheckableKind() CheckableKind {
+	return CheckableResource
+}
+
+type configResourceKey string
+
+func (k configResourceKey) uniqueKeySigil() {}
+
+// ResourceMode defines which lifecycle applies to a given resource. Each
+// resource lifecycle has a slightly different address format.
+type ResourceMode rune
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type ResourceMode
+
+const (
+	// InvalidResourceMode is the zero value of ResourceMode and is not
+	// a valid resource mode.
+	InvalidResourceMode ResourceMode = 0
+
+	// ManagedResourceMode indicates a managed resource, as defined by
+	// "resource" blocks in configuration.
+	ManagedResourceMode ResourceMode = 'M'
+
+	// DataResourceMode indicates a data resource, as defined by
+	// "data" blocks in configuration.
+	DataResourceMode ResourceMode = 'D'
+)
diff --git a/v1.5.7/internal/addrs/resource_phase.go b/v1.5.7/internal/addrs/resource_phase.go
new file mode 100644
index 0000000..3523b48
--- /dev/null
+++ b/v1.5.7/internal/addrs/resource_phase.go
@@ -0,0 +1,120 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import "fmt"
+
+// ResourceInstancePhase is a special kind of reference used only internally
+// during graph building to represent resource instances that are in a
+// non-primary state.
+//
+// Graph nodes can declare themselves referenceable via an instance phase
+// or can declare that they reference an instance phase in order to accomodate
+// secondary graph nodes dealing with, for example, destroy actions.
+//
+// This special reference type cannot be accessed directly by end-users, and
+// should never be shown in the UI.
+type ResourceInstancePhase struct {
+	referenceable
+	ResourceInstance ResourceInstance
+	Phase            ResourceInstancePhaseType
+}
+
+var _ Referenceable = ResourceInstancePhase{}
+
+// Phase returns a special "phase address" for the receving instance. See the
+// documentation of ResourceInstancePhase for the limited situations where this
+// is intended to be used.
+func (r ResourceInstance) Phase(rpt ResourceInstancePhaseType) ResourceInstancePhase {
+	return ResourceInstancePhase{
+		ResourceInstance: r,
+		Phase:            rpt,
+	}
+}
+
+// ContainingResource returns an address for the same phase of the resource
+// that this instance belongs to.
+func (rp ResourceInstancePhase) ContainingResource() ResourcePhase {
+	return rp.ResourceInstance.Resource.Phase(rp.Phase)
+}
+
+func (rp ResourceInstancePhase) String() string {
+	// We use a different separator here than usual to ensure that we'll
+	// never conflict with any non-phased resource instance string. This
+	// is intentionally something that would fail parsing with ParseRef,
+	// because this special address type should never be exposed in the UI.
+	return fmt.Sprintf("%s#%s", rp.ResourceInstance, rp.Phase)
+}
+
+func (rp ResourceInstancePhase) UniqueKey() UniqueKey {
+	return rp // A ResourceInstancePhase is its own UniqueKey
+}
+
+func (rp ResourceInstancePhase) uniqueKeySigil() {}
+
+// ResourceInstancePhaseType is an enumeration used with ResourceInstancePhase.
+type ResourceInstancePhaseType string
+
+const (
+	// ResourceInstancePhaseDestroy represents the "destroy" phase of a
+	// resource instance.
+	ResourceInstancePhaseDestroy ResourceInstancePhaseType = "destroy"
+
+	// ResourceInstancePhaseDestroyCBD is similar to ResourceInstancePhaseDestroy
+	// but is used for resources that have "create_before_destroy" set, thus
+	// requiring a different dependency ordering.
+	ResourceInstancePhaseDestroyCBD ResourceInstancePhaseType = "destroy-cbd"
+)
+
+func (rpt ResourceInstancePhaseType) String() string {
+	return string(rpt)
+}
+
+// ResourcePhase is a special kind of reference used only internally
+// during graph building to represent resources that are in a
+// non-primary state.
+//
+// Graph nodes can declare themselves referenceable via a resource phase
+// or can declare that they reference a resource phase in order to accomodate
+// secondary graph nodes dealing with, for example, destroy actions.
+//
+// Since resources (as opposed to instances) aren't actually phased, this
+// address type is used only as an approximation during initial construction
+// of the resource-oriented plan graph, under the assumption that resource
+// instances with ResourceInstancePhase addresses will be created in dynamic
+// subgraphs during the graph walk.
+//
+// This special reference type cannot be accessed directly by end-users, and
+// should never be shown in the UI.
+type ResourcePhase struct {
+	referenceable
+	Resource Resource
+	Phase    ResourceInstancePhaseType
+}
+
+var _ Referenceable = ResourcePhase{}
+
+// Phase returns a special "phase address" for the receving instance. See the
+// documentation of ResourceInstancePhase for the limited situations where this
+// is intended to be used.
+func (r Resource) Phase(rpt ResourceInstancePhaseType) ResourcePhase {
+	return ResourcePhase{
+		Resource: r,
+		Phase:    rpt,
+	}
+}
+
+func (rp ResourcePhase) String() string {
+	// We use a different separator here than usual to ensure that we'll
+	// never conflict with any non-phased resource instance string. This
+	// is intentionally something that would fail parsing with ParseRef,
+	// because this special address type should never be exposed in the UI.
+	return fmt.Sprintf("%s#%s", rp.Resource, rp.Phase)
+}
+
+func (rp ResourcePhase) UniqueKey() UniqueKey {
+	return rp // A ResourcePhase is its own UniqueKey
+}
+
+func (rp ResourcePhase) uniqueKeySigil() {}
diff --git a/v1.5.7/internal/addrs/resource_test.go b/v1.5.7/internal/addrs/resource_test.go
new file mode 100644
index 0000000..e48ad86
--- /dev/null
+++ b/v1.5.7/internal/addrs/resource_test.go
@@ -0,0 +1,350 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestResourceEqual_true(t *testing.T) {
+	resources := []Resource{
+		{
+			Mode: ManagedResourceMode,
+			Type: "a",
+			Name: "b",
+		},
+		{
+			Mode: DataResourceMode,
+			Type: "a",
+			Name: "b",
+		},
+	}
+	for _, r := range resources {
+		t.Run(r.String(), func(t *testing.T) {
+			if !r.Equal(r) {
+				t.Fatalf("expected %#v to be equal to itself", r)
+			}
+		})
+	}
+}
+
+func TestResourceEqual_false(t *testing.T) {
+	testCases := []struct {
+		left  Resource
+		right Resource
+	}{
+		{
+			Resource{Mode: DataResourceMode, Type: "a", Name: "b"},
+			Resource{Mode: ManagedResourceMode, Type: "a", Name: "b"},
+		},
+		{
+			Resource{Mode: ManagedResourceMode, Type: "a", Name: "b"},
+			Resource{Mode: ManagedResourceMode, Type: "b", Name: "b"},
+		},
+		{
+			Resource{Mode: ManagedResourceMode, Type: "a", Name: "b"},
+			Resource{Mode: ManagedResourceMode, Type: "a", Name: "c"},
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(fmt.Sprintf("%s = %s", tc.left, tc.right), func(t *testing.T) {
+			if tc.left.Equal(tc.right) {
+				t.Fatalf("expected %#v not to be equal to %#v", tc.left, tc.right)
+			}
+
+			if tc.right.Equal(tc.left) {
+				t.Fatalf("expected %#v not to be equal to %#v", tc.right, tc.left)
+			}
+		})
+	}
+}
+
+func TestResourceInstanceEqual_true(t *testing.T) {
+	resources := []ResourceInstance{
+		{
+			Resource: Resource{
+				Mode: ManagedResourceMode,
+				Type: "a",
+				Name: "b",
+			},
+			Key: IntKey(0),
+		},
+		{
+			Resource: Resource{
+				Mode: DataResourceMode,
+				Type: "a",
+				Name: "b",
+			},
+			Key: StringKey("x"),
+		},
+	}
+	for _, r := range resources {
+		t.Run(r.String(), func(t *testing.T) {
+			if !r.Equal(r) {
+				t.Fatalf("expected %#v to be equal to itself", r)
+			}
+		})
+	}
+}
+
+func TestResourceInstanceEqual_false(t *testing.T) {
+	testCases := []struct {
+		left  ResourceInstance
+		right ResourceInstance
+	}{
+		{
+			ResourceInstance{
+				Resource: Resource{Mode: DataResourceMode, Type: "a", Name: "b"},
+				Key:      IntKey(0),
+			},
+			ResourceInstance{
+				Resource: Resource{Mode: ManagedResourceMode, Type: "a", Name: "b"},
+				Key:      IntKey(0),
+			},
+		},
+		{
+			ResourceInstance{
+				Resource: Resource{Mode: ManagedResourceMode, Type: "a", Name: "b"},
+				Key:      IntKey(0),
+			},
+			ResourceInstance{
+				Resource: Resource{Mode: ManagedResourceMode, Type: "b", Name: "b"},
+				Key:      IntKey(0),
+			},
+		},
+		{
+			ResourceInstance{
+				Resource: Resource{Mode: ManagedResourceMode, Type: "a", Name: "b"},
+				Key:      IntKey(0),
+			},
+			ResourceInstance{
+				Resource: Resource{Mode: ManagedResourceMode, Type: "a", Name: "c"},
+				Key:      IntKey(0),
+			},
+		},
+		{
+			ResourceInstance{
+				Resource: Resource{Mode: DataResourceMode, Type: "a", Name: "b"},
+				Key:      IntKey(0),
+			},
+			ResourceInstance{
+				Resource: Resource{Mode: DataResourceMode, Type: "a", Name: "b"},
+				Key:      StringKey("0"),
+			},
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(fmt.Sprintf("%s = %s", tc.left, tc.right), func(t *testing.T) {
+			if tc.left.Equal(tc.right) {
+				t.Fatalf("expected %#v not to be equal to %#v", tc.left, tc.right)
+			}
+
+			if tc.right.Equal(tc.left) {
+				t.Fatalf("expected %#v not to be equal to %#v", tc.right, tc.left)
+			}
+		})
+	}
+}
+
+func TestAbsResourceInstanceEqual_true(t *testing.T) {
+	managed := Resource{Mode: ManagedResourceMode, Type: "a", Name: "b"}
+	data := Resource{Mode: DataResourceMode, Type: "a", Name: "b"}
+
+	foo, diags := ParseModuleInstanceStr("module.foo")
+	if len(diags) > 0 {
+		t.Fatalf("unexpected diags: %s", diags.Err())
+	}
+	foobar, diags := ParseModuleInstanceStr("module.foo[1].module.bar")
+	if len(diags) > 0 {
+		t.Fatalf("unexpected diags: %s", diags.Err())
+	}
+
+	instances := []AbsResourceInstance{
+		managed.Instance(IntKey(0)).Absolute(foo),
+		data.Instance(IntKey(0)).Absolute(foo),
+		managed.Instance(StringKey("a")).Absolute(foobar),
+	}
+	for _, r := range instances {
+		t.Run(r.String(), func(t *testing.T) {
+			if !r.Equal(r) {
+				t.Fatalf("expected %#v to be equal to itself", r)
+			}
+		})
+	}
+}
+
+func TestAbsResourceInstanceEqual_false(t *testing.T) {
+	managed := Resource{Mode: ManagedResourceMode, Type: "a", Name: "b"}
+	data := Resource{Mode: DataResourceMode, Type: "a", Name: "b"}
+
+	foo, diags := ParseModuleInstanceStr("module.foo")
+	if len(diags) > 0 {
+		t.Fatalf("unexpected diags: %s", diags.Err())
+	}
+	foobar, diags := ParseModuleInstanceStr("module.foo[1].module.bar")
+	if len(diags) > 0 {
+		t.Fatalf("unexpected diags: %s", diags.Err())
+	}
+
+	testCases := []struct {
+		left  AbsResourceInstance
+		right AbsResourceInstance
+	}{
+		{
+			managed.Instance(IntKey(0)).Absolute(foo),
+			data.Instance(IntKey(0)).Absolute(foo),
+		},
+		{
+			managed.Instance(IntKey(0)).Absolute(foo),
+			managed.Instance(IntKey(0)).Absolute(foobar),
+		},
+		{
+			managed.Instance(IntKey(0)).Absolute(foo),
+			managed.Instance(StringKey("0")).Absolute(foo),
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(fmt.Sprintf("%s = %s", tc.left, tc.right), func(t *testing.T) {
+			if tc.left.Equal(tc.right) {
+				t.Fatalf("expected %#v not to be equal to %#v", tc.left, tc.right)
+			}
+
+			if tc.right.Equal(tc.left) {
+				t.Fatalf("expected %#v not to be equal to %#v", tc.right, tc.left)
+			}
+		})
+	}
+}
+
+func TestAbsResourceUniqueKey(t *testing.T) {
+	resourceAddr1 := Resource{
+		Mode: ManagedResourceMode,
+		Type: "a",
+		Name: "b1",
+	}.Absolute(RootModuleInstance)
+	resourceAddr2 := Resource{
+		Mode: ManagedResourceMode,
+		Type: "a",
+		Name: "b2",
+	}.Absolute(RootModuleInstance)
+	resourceAddr3 := Resource{
+		Mode: ManagedResourceMode,
+		Type: "a",
+		Name: "in_module",
+	}.Absolute(RootModuleInstance.Child("boop", NoKey))
+
+	tests := []struct {
+		Reciever  AbsResource
+		Other     UniqueKeyer
+		WantEqual bool
+	}{
+		{
+			resourceAddr1,
+			resourceAddr1,
+			true,
+		},
+		{
+			resourceAddr1,
+			resourceAddr2,
+			false,
+		},
+		{
+			resourceAddr1,
+			resourceAddr3,
+			false,
+		},
+		{
+			resourceAddr3,
+			resourceAddr3,
+			true,
+		},
+		{
+			resourceAddr1,
+			resourceAddr1.Instance(NoKey),
+			false, // no-key instance key is distinct from its resource even though they have the same String result
+		},
+		{
+			resourceAddr1,
+			resourceAddr1.Instance(IntKey(1)),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%s matches %T %s?", test.Reciever, test.Other, test.Other), func(t *testing.T) {
+			rKey := test.Reciever.UniqueKey()
+			oKey := test.Other.UniqueKey()
+
+			gotEqual := rKey == oKey
+			if gotEqual != test.WantEqual {
+				t.Errorf(
+					"wrong result\nreceiver: %s\nother:    %s (%T)\ngot:  %t\nwant: %t",
+					test.Reciever, test.Other, test.Other,
+					gotEqual, test.WantEqual,
+				)
+			}
+		})
+	}
+}
+
+func TestConfigResourceEqual_true(t *testing.T) {
+	resources := []ConfigResource{
+		{
+			Resource: Resource{Mode: ManagedResourceMode, Type: "a", Name: "b"},
+			Module:   RootModule,
+		},
+		{
+			Resource: Resource{Mode: DataResourceMode, Type: "a", Name: "b"},
+			Module:   RootModule,
+		},
+		{
+			Resource: Resource{Mode: ManagedResourceMode, Type: "a", Name: "b"},
+			Module:   Module{"foo"},
+		},
+		{
+			Resource: Resource{Mode: DataResourceMode, Type: "a", Name: "b"},
+			Module:   Module{"foo"},
+		},
+	}
+	for _, r := range resources {
+		t.Run(r.String(), func(t *testing.T) {
+			if !r.Equal(r) {
+				t.Fatalf("expected %#v to be equal to itself", r)
+			}
+		})
+	}
+}
+
+func TestConfigResourceEqual_false(t *testing.T) {
+	managed := Resource{Mode: ManagedResourceMode, Type: "a", Name: "b"}
+	data := Resource{Mode: DataResourceMode, Type: "a", Name: "b"}
+
+	foo := Module{"foo"}
+	foobar := Module{"foobar"}
+	testCases := []struct {
+		left  ConfigResource
+		right ConfigResource
+	}{
+		{
+			ConfigResource{Resource: managed, Module: foo},
+			ConfigResource{Resource: data, Module: foo},
+		},
+		{
+			ConfigResource{Resource: managed, Module: foo},
+			ConfigResource{Resource: managed, Module: foobar},
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(fmt.Sprintf("%s = %s", tc.left, tc.right), func(t *testing.T) {
+			if tc.left.Equal(tc.right) {
+				t.Fatalf("expected %#v not to be equal to %#v", tc.left, tc.right)
+			}
+
+			if tc.right.Equal(tc.left) {
+				t.Fatalf("expected %#v not to be equal to %#v", tc.right, tc.left)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/addrs/resourcemode_string.go b/v1.5.7/internal/addrs/resourcemode_string.go
new file mode 100644
index 0000000..0b5c33f
--- /dev/null
+++ b/v1.5.7/internal/addrs/resourcemode_string.go
@@ -0,0 +1,33 @@
+// Code generated by "stringer -type ResourceMode"; DO NOT EDIT.
+
+package addrs
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[InvalidResourceMode-0]
+	_ = x[ManagedResourceMode-77]
+	_ = x[DataResourceMode-68]
+}
+
+const (
+	_ResourceMode_name_0 = "InvalidResourceMode"
+	_ResourceMode_name_1 = "DataResourceMode"
+	_ResourceMode_name_2 = "ManagedResourceMode"
+)
+
+func (i ResourceMode) String() string {
+	switch {
+	case i == 0:
+		return _ResourceMode_name_0
+	case i == 68:
+		return _ResourceMode_name_1
+	case i == 77:
+		return _ResourceMode_name_2
+	default:
+		return "ResourceMode(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/v1.5.7/internal/addrs/self.go b/v1.5.7/internal/addrs/self.go
new file mode 100644
index 0000000..1e103cd
--- /dev/null
+++ b/v1.5.7/internal/addrs/self.go
@@ -0,0 +1,23 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+// Self is the address of the special object "self" that behaves as an alias
+// for a containing object currently in scope.
+const Self selfT = 0
+
+type selfT int
+
+func (s selfT) referenceableSigil() {
+}
+
+func (s selfT) String() string {
+	return "self"
+}
+
+func (s selfT) UniqueKey() UniqueKey {
+	return Self // Self is its own UniqueKey
+}
+
+func (s selfT) uniqueKeySigil() {}
diff --git a/v1.5.7/internal/addrs/set.go b/v1.5.7/internal/addrs/set.go
new file mode 100644
index 0000000..0cce31f
--- /dev/null
+++ b/v1.5.7/internal/addrs/set.go
@@ -0,0 +1,70 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+// Set represents a set of addresses of types that implement UniqueKeyer.
+//
+// Modify the set only by the methods on this type. This type exposes its
+// internals for convenience during reading, such as iterating over set elements
+// by ranging over the map values, but making direct modifications could
+// potentially make the set data invalid or inconsistent, leading to undefined
+// behavior elsewhere.
+type Set[T UniqueKeyer] map[UniqueKey]T
+
+func MakeSet[T UniqueKeyer](elems ...T) Set[T] {
+	ret := Set[T](make(map[UniqueKey]T, len(elems)))
+	for _, elem := range elems {
+		ret.Add(elem)
+	}
+	return ret
+}
+
+// Has returns true if and only if the set includes the given address.
+func (s Set[T]) Has(addr T) bool {
+	_, exists := s[addr.UniqueKey()]
+	return exists
+}
+
+// Add inserts the given address into the set, if not already present. If
+// an equivalent address is already in the set, this replaces that address
+// with the new value.
+func (s Set[T]) Add(addr T) {
+	s[addr.UniqueKey()] = addr
+}
+
+// Remove deletes the given address from the set, if present. If not present,
+// this is a no-op.
+func (s Set[T]) Remove(addr T) {
+	delete(s, addr.UniqueKey())
+}
+
+// Union returns a new set which contains the union of all of the elements
+// of both the reciever and the given other set.
+func (s Set[T]) Union(other Set[T]) Set[T] {
+	ret := make(Set[T])
+	for k, addr := range s {
+		ret[k] = addr
+	}
+	for k, addr := range other {
+		ret[k] = addr
+	}
+	return ret
+}
+
+// Intersection returns a new set which contains the intersection of all of the
+// elements of both the reciever and the given other set.
+func (s Set[T]) Intersection(other Set[T]) Set[T] {
+	ret := make(Set[T])
+	for k, addr := range s {
+		if _, exists := other[k]; exists {
+			ret[k] = addr
+		}
+	}
+	for k, addr := range other {
+		if _, exists := s[k]; exists {
+			ret[k] = addr
+		}
+	}
+	return ret
+}
diff --git a/v1.5.7/internal/addrs/target_test.go b/v1.5.7/internal/addrs/target_test.go
new file mode 100644
index 0000000..e047e6a
--- /dev/null
+++ b/v1.5.7/internal/addrs/target_test.go
@@ -0,0 +1,234 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestTargetContains(t *testing.T) {
+	for _, test := range []struct {
+		addr, other Targetable
+		expect      bool
+	}{
+		{
+			mustParseTarget("module.foo"),
+			mustParseTarget("module.bar"),
+			false,
+		},
+		{
+			mustParseTarget("module.foo"),
+			mustParseTarget("module.foo"),
+			true,
+		},
+		{
+			RootModuleInstance,
+			mustParseTarget("module.foo"),
+			true,
+		},
+		{
+			mustParseTarget("module.foo"),
+			RootModuleInstance,
+			false,
+		},
+		{
+			mustParseTarget("module.foo"),
+			mustParseTarget("module.foo.module.bar[0]"),
+			true,
+		},
+		{
+			mustParseTarget("module.foo"),
+			mustParseTarget("module.foo.module.bar[0]"),
+			true,
+		},
+		{
+			mustParseTarget("module.foo[2]"),
+			mustParseTarget("module.foo[2].module.bar[0]"),
+			true,
+		},
+		{
+			mustParseTarget("module.foo"),
+			mustParseTarget("module.foo.test_resource.bar"),
+			true,
+		},
+		{
+			mustParseTarget("module.foo"),
+			mustParseTarget("module.foo.test_resource.bar[0]"),
+			true,
+		},
+
+		// Resources
+		{
+			mustParseTarget("test_resource.foo"),
+			mustParseTarget("test_resource.foo[\"bar\"]"),
+			true,
+		},
+		{
+			mustParseTarget(`test_resource.foo["bar"]`),
+			mustParseTarget(`test_resource.foo["bar"]`),
+			true,
+		},
+		{
+			mustParseTarget("test_resource.foo"),
+			mustParseTarget("test_resource.foo[2]"),
+			true,
+		},
+		{
+			mustParseTarget("test_resource.foo"),
+			mustParseTarget("module.bar.test_resource.foo[2]"),
+			false,
+		},
+		{
+			mustParseTarget("module.bar.test_resource.foo"),
+			mustParseTarget("module.bar.test_resource.foo[2]"),
+			true,
+		},
+		{
+			mustParseTarget("module.bar.test_resource.foo"),
+			mustParseTarget("module.bar[0].test_resource.foo[2]"),
+			false,
+		},
+		{
+			mustParseTarget("module.bar.test_resource.foo"),
+			mustParseTarget("module.bar.test_resource.foo[0]"),
+			true,
+		},
+		{
+			mustParseTarget("module.bax"),
+			mustParseTarget("module.bax[0].test_resource.foo[0]"),
+			true,
+		},
+
+		// Config paths, while never returned from parsing a target, must still
+		// be targetable
+		{
+			ConfigResource{
+				Module: []string{"bar"},
+				Resource: Resource{
+					Mode: ManagedResourceMode,
+					Type: "test_resource",
+					Name: "foo",
+				},
+			},
+			mustParseTarget("module.bar.test_resource.foo[2]"),
+			true,
+		},
+		{
+			mustParseTarget("module.bar"),
+			ConfigResource{
+				Module: []string{"bar"},
+				Resource: Resource{
+					Mode: ManagedResourceMode,
+					Type: "test_resource",
+					Name: "foo",
+				},
+			},
+			true,
+		},
+		{
+			mustParseTarget("module.bar.test_resource.foo"),
+			ConfigResource{
+				Module: []string{"bar"},
+				Resource: Resource{
+					Mode: ManagedResourceMode,
+					Type: "test_resource",
+					Name: "foo",
+				},
+			},
+			true,
+		},
+		{
+			ConfigResource{
+				Resource: Resource{
+					Mode: ManagedResourceMode,
+					Type: "test_resource",
+					Name: "foo",
+				},
+			},
+			mustParseTarget("module.bar.test_resource.foo[2]"),
+			false,
+		},
+		{
+			ConfigResource{
+				Module: []string{"bar"},
+				Resource: Resource{
+					Mode: ManagedResourceMode,
+					Type: "test_resource",
+					Name: "foo",
+				},
+			},
+			mustParseTarget("module.bar[0].test_resource.foo"),
+			true,
+		},
+
+		// Modules are also never the result of parsing a target, but also need
+		// to be targetable
+		{
+			Module{"bar"},
+			Module{"bar", "baz"},
+			true,
+		},
+		{
+			Module{"bar"},
+			mustParseTarget("module.bar[0]"),
+			true,
+		},
+		{
+			// Parsing an ambiguous module path needs to ensure the
+			// ModuleInstance could contain the Module. This is safe because if
+			// the module could be expanded, it must have an index, meaning no
+			// index indicates that the module instance and module are
+			// functionally equivalent.
+			mustParseTarget("module.bar"),
+			Module{"bar"},
+			true,
+		},
+		{
+			// A specific ModuleInstance cannot contain a module
+			mustParseTarget("module.bar[0]"),
+			Module{"bar"},
+			false,
+		},
+		{
+			Module{"bar", "baz"},
+			mustParseTarget("module.bar[0].module.baz.test_resource.foo[1]"),
+			true,
+		},
+		{
+			mustParseTarget("module.bar[0].module.baz"),
+			Module{"bar", "baz"},
+			false,
+		},
+	} {
+		t.Run(fmt.Sprintf("%s-in-%s", test.other, test.addr), func(t *testing.T) {
+			got := test.addr.TargetContains(test.other)
+			if got != test.expect {
+				t.Fatalf("expected %q.TargetContains(%q) == %t", test.addr, test.other, test.expect)
+			}
+		})
+	}
+}
+
+func TestResourceContains(t *testing.T) {
+	for _, test := range []struct {
+		in, other Targetable
+		expect    bool
+	}{} {
+		t.Run(fmt.Sprintf("%s-in-%s", test.other, test.in), func(t *testing.T) {
+			got := test.in.TargetContains(test.other)
+			if got != test.expect {
+				t.Fatalf("expected %q.TargetContains(%q) == %t", test.in, test.other, test.expect)
+			}
+		})
+	}
+}
+
+func mustParseTarget(str string) Targetable {
+	t, diags := ParseTargetStr(str)
+	if diags != nil {
+		panic(fmt.Sprintf("%s: %s", str, diags.ErrWithWarnings()))
+	}
+	return t.Subject
+}
diff --git a/v1.5.7/internal/addrs/targetable.go b/v1.5.7/internal/addrs/targetable.go
new file mode 100644
index 0000000..7e12684
--- /dev/null
+++ b/v1.5.7/internal/addrs/targetable.go
@@ -0,0 +1,43 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+// Targetable is an interface implemented by all address types that can be
+// used as "targets" for selecting sub-graphs of a graph.
+type Targetable interface {
+	targetableSigil()
+
+	// TargetContains returns true if the receiver is considered to contain
+	// the given other address. Containment, for the purpose of targeting,
+	// means that if a container address is targeted then all of the
+	// addresses within it are also implicitly targeted.
+	//
+	// A targetable address always contains at least itself.
+	TargetContains(other Targetable) bool
+
+	// AddrType returns the address type for comparison with other Targetable
+	// addresses.
+	AddrType() TargetableAddrType
+
+	// String produces a string representation of the address that could be
+	// parsed as a HCL traversal and passed to ParseTarget to produce an
+	// identical result.
+	String() string
+}
+
+type targetable struct {
+}
+
+func (r targetable) targetableSigil() {
+}
+
+type TargetableAddrType int
+
+const (
+	ConfigResourceAddrType TargetableAddrType = iota
+	AbsResourceInstanceAddrType
+	AbsResourceAddrType
+	ModuleAddrType
+	ModuleInstanceAddrType
+)
diff --git a/v1.5.7/internal/addrs/terraform_attr.go b/v1.5.7/internal/addrs/terraform_attr.go
new file mode 100644
index 0000000..c29379a
--- /dev/null
+++ b/v1.5.7/internal/addrs/terraform_attr.go
@@ -0,0 +1,21 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+// TerraformAttr is the address of an attribute of the "terraform" object in
+// the interpolation scope, like "terraform.workspace".
+type TerraformAttr struct {
+	referenceable
+	Name string
+}
+
+func (ta TerraformAttr) String() string {
+	return "terraform." + ta.Name
+}
+
+func (ta TerraformAttr) UniqueKey() UniqueKey {
+	return ta // A TerraformAttr is its own UniqueKey
+}
+
+func (ta TerraformAttr) uniqueKeySigil() {}
diff --git a/v1.5.7/internal/addrs/unique_key.go b/v1.5.7/internal/addrs/unique_key.go
new file mode 100644
index 0000000..e34a398
--- /dev/null
+++ b/v1.5.7/internal/addrs/unique_key.go
@@ -0,0 +1,30 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+// UniqueKey is an interface implemented by values that serve as unique map
+// keys for particular addresses.
+//
+// All implementations of UniqueKey are comparable and can thus be used as
+// map keys. Unique keys generated from different address types are always
+// distinct. All functionally-equivalent keys for the same address type
+// always compare equal, and likewise functionally-different values do not.
+type UniqueKey interface {
+	uniqueKeySigil()
+}
+
+// UniqueKeyer is an interface implemented by types that can be represented
+// by a unique key.
+//
+// Some address types naturally comply with the expectations of a UniqueKey
+// and may thus be their own unique key type. However, address types that
+// are not naturally comparable can implement this interface by returning
+// proxy values.
+type UniqueKeyer interface {
+	UniqueKey() UniqueKey
+}
+
+func Equivalent[T UniqueKeyer](a, b T) bool {
+	return a.UniqueKey() == b.UniqueKey()
+}
diff --git a/v1.5.7/internal/addrs/unique_key_test.go b/v1.5.7/internal/addrs/unique_key_test.go
new file mode 100644
index 0000000..2de1967
--- /dev/null
+++ b/v1.5.7/internal/addrs/unique_key_test.go
@@ -0,0 +1,75 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package addrs
+
+import (
+	"fmt"
+	"testing"
+)
+
+// TestUniqueKeyer aims to ensure that all of the types that have unique keys
+// will continue to meet the UniqueKeyer contract under future changes.
+//
+// If you add a new implementation of UniqueKey, consider adding a test case
+// for it here.
+func TestUniqueKeyer(t *testing.T) {
+	tests := []UniqueKeyer{
+		CountAttr{Name: "index"},
+		ForEachAttr{Name: "key"},
+		TerraformAttr{Name: "workspace"},
+		PathAttr{Name: "module"},
+		InputVariable{Name: "foo"},
+		ModuleCall{Name: "foo"},
+		ModuleCallInstance{
+			Call: ModuleCall{Name: "foo"},
+			Key:  StringKey("a"),
+		},
+		ModuleCallOutput{
+			Call: ModuleCall{Name: "foo"},
+			Name: "bar",
+		},
+		ModuleCallInstanceOutput{
+			Call: ModuleCallInstance{
+				Call: ModuleCall{Name: "foo"},
+				Key:  StringKey("a"),
+			},
+			Name: "bar",
+		},
+		Resource{
+			Mode: ManagedResourceMode,
+			Type: "foo",
+			Name: "bar",
+		},
+		ResourceInstance{
+			Resource: Resource{
+				Mode: ManagedResourceMode,
+				Type: "foo",
+				Name: "bar",
+			},
+			Key: IntKey(1),
+		},
+		RootModuleInstance,
+		RootModuleInstance.Child("foo", NoKey),
+		RootModuleInstance.ResourceInstance(
+			DataResourceMode,
+			"boop",
+			"beep",
+			NoKey,
+		),
+		Self,
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%s", test), func(t *testing.T) {
+			a := test.UniqueKey()
+			b := test.UniqueKey()
+
+			// The following comparison will panic if the unique key is not
+			// of a comparable type.
+			if a != b {
+				t.Fatalf("the two unique keys are not equal\na: %#v\b: %#v", a, b)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/backend/backend.go b/v1.5.7/internal/backend/backend.go
new file mode 100644
index 0000000..cee0f50
--- /dev/null
+++ b/v1.5.7/internal/backend/backend.go
@@ -0,0 +1,443 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package backend provides interfaces that the CLI uses to interact with
+// Terraform. A backend provides the abstraction that allows the same CLI
+// to simultaneously support both local and remote operations for seamlessly
+// using Terraform in a team environment.
+package backend
+
+import (
+	"context"
+	"errors"
+	"io/ioutil"
+	"log"
+	"os"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/mitchellh/go-homedir"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// DefaultStateName is the name of the default, initial state that every
+// backend must have. This state cannot be deleted.
+const DefaultStateName = "default"
+
+var (
+	// ErrDefaultWorkspaceNotSupported is returned when an operation does not
+	// support using the default workspace, but requires a named workspace to
+	// be selected.
+	ErrDefaultWorkspaceNotSupported = errors.New("default workspace not supported\n" +
+		"You can create a new workspace with the \"workspace new\" command.")
+
+	// ErrWorkspacesNotSupported is an error returned when a caller attempts
+	// to perform an operation on a workspace other than "default" for a
+	// backend that doesn't support multiple workspaces.
+	//
+	// The caller can detect this to do special fallback behavior or produce
+	// a specific, helpful error message.
+	ErrWorkspacesNotSupported = errors.New("workspaces not supported")
+)
+
+// InitFn is used to initialize a new backend.
+type InitFn func() Backend
+
+// Backend is the minimal interface that must be implemented to enable Terraform.
+type Backend interface {
+	// ConfigSchema returns a description of the expected configuration
+	// structure for the receiving backend.
+	//
+	// This method does not have any side-effects for the backend and can
+	// be safely used before configuring.
+	ConfigSchema() *configschema.Block
+
+	// PrepareConfig checks the validity of the values in the given
+	// configuration, and inserts any missing defaults, assuming that its
+	// structure has already been validated per the schema returned by
+	// ConfigSchema.
+	//
+	// This method does not have any side-effects for the backend and can
+	// be safely used before configuring. It also does not consult any
+	// external data such as environment variables, disk files, etc. Validation
+	// that requires such external data should be deferred until the
+	// Configure call.
+	//
+	// If error diagnostics are returned then the configuration is not valid
+	// and must not subsequently be passed to the Configure method.
+	//
+	// This method may return configuration-contextual diagnostics such
+	// as tfdiags.AttributeValue, and so the caller should provide the
+	// necessary context via the diags.InConfigBody method before returning
+	// diagnostics to the user.
+	PrepareConfig(cty.Value) (cty.Value, tfdiags.Diagnostics)
+
+	// Configure uses the provided configuration to set configuration fields
+	// within the backend.
+	//
+	// The given configuration is assumed to have already been validated
+	// against the schema returned by ConfigSchema and passed validation
+	// via PrepareConfig.
+	//
+	// This method may be called only once per backend instance, and must be
+	// called before all other methods except where otherwise stated.
+	//
+	// If error diagnostics are returned, the internal state of the instance
+	// is undefined and no other methods may be called.
+	Configure(cty.Value) tfdiags.Diagnostics
+
+	// StateMgr returns the state manager for the given workspace name.
+	//
+	// If the returned state manager also implements statemgr.Locker then
+	// it's the caller's responsibility to call Lock and Unlock as appropriate.
+	//
+	// If the named workspace doesn't exist, or if it has no state, it will
+	// be created either immediately on this call or the first time
+	// PersistState is called, depending on the state manager implementation.
+	StateMgr(workspace string) (statemgr.Full, error)
+
+	// DeleteWorkspace removes the workspace with the given name if it exists.
+	//
+	// DeleteWorkspace cannot prevent deleting a state that is in use. It is
+	// the responsibility of the caller to hold a Lock for the state manager
+	// belonging to this workspace before calling this method.
+	DeleteWorkspace(name string, force bool) error
+
+	// States returns a list of the names of all of the workspaces that exist
+	// in this backend.
+	Workspaces() ([]string, error)
+}
+
+// HostAlias describes a list of aliases that should be used when initializing an
+// Enhanced Backend
+type HostAlias struct {
+	From svchost.Hostname
+	To   svchost.Hostname
+}
+
+// Enhanced implements additional behavior on top of a normal backend.
+//
+// 'Enhanced' backends are an implementation detail only, and are no longer reflected as an external
+// 'feature' of backends. In other words, backends refer to plugins for remote state snapshot
+// storage only, and the Enhanced interface here is a necessary vestige of the 'local' and
+// remote/cloud backends only.
+type Enhanced interface {
+	Backend
+
+	// Operation performs a Terraform operation such as refresh, plan, apply.
+	// It is up to the implementation to determine what "performing" means.
+	// This DOES NOT BLOCK. The context returned as part of RunningOperation
+	// should be used to block for completion.
+	// If the state used in the operation can be locked, it is the
+	// responsibility of the Backend to lock the state for the duration of the
+	// running operation.
+	Operation(context.Context, *Operation) (*RunningOperation, error)
+
+	// ServiceDiscoveryAliases returns a mapping of Alias -> Target hosts to
+	// configure.
+	ServiceDiscoveryAliases() ([]HostAlias, error)
+}
+
+// Local implements additional behavior on a Backend that allows local
+// operations in addition to remote operations.
+//
+// This enables more behaviors of Terraform that require more data such
+// as `console`, `import`, `graph`. These require direct access to
+// configurations, variables, and more. Not all backends may support this
+// so we separate it out into its own optional interface.
+type Local interface {
+	// LocalRun uses information in the Operation to prepare a set of objects
+	// needed to start running that operation.
+	//
+	// The operation doesn't need a Type set, but it needs various other
+	// options set. This is a rather odd API that tries to treat all
+	// operations as the same when they really aren't; see the local and remote
+	// backend's implementations of this to understand what this actually
+	// does, because this operation has no well-defined contract aside from
+	// "whatever it already does".
+	LocalRun(*Operation) (*LocalRun, statemgr.Full, tfdiags.Diagnostics)
+}
+
+// LocalRun represents the assortment of objects that we can collect or
+// calculate from an Operation object, which we can then use for local
+// operations.
+//
+// The operation methods on terraform.Context (Plan, Apply, Import, etc) each
+// generate new artifacts which supersede parts of the LocalRun object that
+// started the operation, so callers should be careful to use those subsequent
+// artifacts instead of the fields of LocalRun where appropriate. The LocalRun
+// data intentionally doesn't update as a result of calling methods on Context,
+// in order to make data flow explicit.
+//
+// This type is a weird architectural wart resulting from the overly-general
+// way our backend API models operations, whereby we behave as if all
+// Terraform operations have the same inputs and outputs even though they
+// are actually all rather different. The exact meaning of the fields in
+// this type therefore vary depending on which OperationType was passed to
+// Local.Context in order to create an object of this type.
+type LocalRun struct {
+	// Core is an already-initialized Terraform Core context, ready to be
+	// used to run operations such as Plan and Apply.
+	Core *terraform.Context
+
+	// Config is the configuration we're working with, which typically comes
+	// from either config files directly on local disk (when we're creating
+	// a plan, or similar) or from a snapshot embedded in a plan file
+	// (when we're applying a saved plan).
+	Config *configs.Config
+
+	// InputState is the state that should be used for whatever is the first
+	// method call to a context created with CoreOpts. When creating a plan
+	// this will be the previous run state, but when applying a saved plan
+	// this will be the prior state recorded in that plan.
+	InputState *states.State
+
+	// PlanOpts are options to pass to a Plan or Plan-like operation.
+	//
+	// This is nil when we're applying a saved plan, because the plan itself
+	// contains enough information about its options to apply it.
+	PlanOpts *terraform.PlanOpts
+
+	// Plan is a plan loaded from a saved plan file, if our operation is to
+	// apply that saved plan.
+	//
+	// This is nil when we're not applying a saved plan.
+	Plan *plans.Plan
+}
+
+// An operation represents an operation for Terraform to execute.
+//
+// Note that not all fields are supported by all backends and can result
+// in an error if set. All backend implementations should show user-friendly
+// errors explaining any incorrectly set values. For example, the local
+// backend doesn't support a PlanId being set.
+//
+// The operation options are purposely designed to have maximal compatibility
+// between Terraform and Terraform Servers (a commercial product offered by
+// HashiCorp). Therefore, it isn't expected that other implementation support
+// every possible option. The struct here is generalized in order to allow
+// even partial implementations to exist in the open, without walling off
+// remote functionality 100% behind a commercial wall. Anyone can implement
+// against this interface and have Terraform interact with it just as it
+// would with HashiCorp-provided Terraform Servers.
+type Operation struct {
+	// Type is the operation to perform.
+	Type OperationType
+
+	// PlanId is an opaque value that backends can use to execute a specific
+	// plan for an apply operation.
+	//
+	// PlanOutBackend is the backend to store with the plan. This is the
+	// backend that will be used when applying the plan.
+	PlanId         string
+	PlanRefresh    bool   // PlanRefresh will do a refresh before a plan
+	PlanOutPath    string // PlanOutPath is the path to save the plan
+	PlanOutBackend *plans.Backend
+
+	// ConfigDir is the path to the directory containing the configuration's
+	// root module.
+	ConfigDir string
+
+	// ConfigLoader is a configuration loader that can be used to load
+	// configuration from ConfigDir.
+	ConfigLoader *configload.Loader
+
+	// DependencyLocks represents the locked dependencies associated with
+	// the configuration directory given in ConfigDir.
+	//
+	// Note that if field PlanFile is set then the plan file should contain
+	// its own dependency locks. The backend is responsible for correctly
+	// selecting between these two sets of locks depending on whether it
+	// will be using ConfigDir or PlanFile to get the configuration for
+	// this operation.
+	DependencyLocks *depsfile.Locks
+
+	// Hooks can be used to perform actions triggered by various events during
+	// the operation's lifecycle.
+	Hooks []terraform.Hook
+
+	// Plan is a plan that was passed as an argument. This is valid for
+	// plan and apply arguments but may not work for all backends.
+	PlanFile *planfile.Reader
+
+	// The options below are more self-explanatory and affect the runtime
+	// behavior of the operation.
+	PlanMode     plans.Mode
+	AutoApprove  bool
+	Targets      []addrs.Targetable
+	ForceReplace []addrs.AbsResourceInstance
+	Variables    map[string]UnparsedVariableValue
+
+	// Some operations use root module variables only opportunistically or
+	// don't need them at all. If this flag is set, the backend must treat
+	// all variables as optional and provide an unknown value for any required
+	// variables that aren't set in order to allow partial evaluation against
+	// the resulting incomplete context.
+	//
+	// This flag is honored only if PlanFile isn't set. If PlanFile is set then
+	// the variables set in the plan are used instead, and they must be valid.
+	AllowUnsetVariables bool
+
+	// View implements the logic for all UI interactions.
+	View views.Operation
+
+	// Input/output/control options.
+	UIIn  terraform.UIInput
+	UIOut terraform.UIOutput
+
+	// StateLocker is used to lock the state while providing UI feedback to the
+	// user. This will be replaced by the Backend to update the context.
+	//
+	// If state locking is not necessary, this should be set to a no-op
+	// implementation of clistate.Locker.
+	StateLocker clistate.Locker
+
+	// Workspace is the name of the workspace that this operation should run
+	// in, which controls which named state is used.
+	Workspace string
+
+	// GenerateConfigOut tells the operation both that it should generate config
+	// for unmatched import targets and where any generated config should be
+	// written to.
+	GenerateConfigOut string
+}
+
+// HasConfig returns true if and only if the operation has a ConfigDir value
+// that refers to a directory containing at least one Terraform configuration
+// file.
+func (o *Operation) HasConfig() bool {
+	return o.ConfigLoader.IsConfigDir(o.ConfigDir)
+}
+
+// Config loads the configuration that the operation applies to, using the
+// ConfigDir and ConfigLoader fields within the receiving operation.
+func (o *Operation) Config() (*configs.Config, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	config, hclDiags := o.ConfigLoader.LoadConfig(o.ConfigDir)
+	diags = diags.Append(hclDiags)
+	return config, diags
+}
+
+// ReportResult is a helper for the common chore of setting the status of
+// a running operation and showing any diagnostics produced during that
+// operation.
+//
+// If the given diagnostics contains errors then the operation's result
+// will be set to backend.OperationFailure. It will be set to
+// backend.OperationSuccess otherwise. It will then use o.View.Diagnostics
+// to show the given diagnostics before returning.
+//
+// Callers should feel free to do each of these operations separately in
+// more complex cases where e.g. diagnostics are interleaved with other
+// output, but terminating immediately after reporting error diagnostics is
+// common and can be expressed concisely via this method.
+func (o *Operation) ReportResult(op *RunningOperation, diags tfdiags.Diagnostics) {
+	if diags.HasErrors() {
+		op.Result = OperationFailure
+	} else {
+		op.Result = OperationSuccess
+	}
+	if o.View != nil {
+		o.View.Diagnostics(diags)
+	} else {
+		// Shouldn't generally happen, but if it does then we'll at least
+		// make some noise in the logs to help us spot it.
+		if len(diags) != 0 {
+			log.Printf(
+				"[ERROR] Backend needs to report diagnostics but View is not set:\n%s",
+				diags.ErrWithWarnings(),
+			)
+		}
+	}
+}
+
+// RunningOperation is the result of starting an operation.
+type RunningOperation struct {
+	// For implementers of a backend, this context should not wrap the
+	// passed in context. Otherwise, cancelling the parent context will
+	// immediately mark this context as "done" but those aren't the semantics
+	// we want: we want this context to be done only when the operation itself
+	// is fully done.
+	context.Context
+
+	// Stop requests the operation to complete early, by calling Stop on all
+	// the plugins. If the process needs to terminate immediately, call Cancel.
+	Stop context.CancelFunc
+
+	// Cancel is the context.CancelFunc associated with the embedded context,
+	// and can be called to terminate the operation early.
+	// Once Cancel is called, the operation should return as soon as possible
+	// to avoid running operations during process exit.
+	Cancel context.CancelFunc
+
+	// Result is the exit status of the operation, populated only after the
+	// operation has completed.
+	Result OperationResult
+
+	// PlanEmpty is populated after a Plan operation completes to note whether
+	// a plan is empty or has changes. This is only used in the CLI to determine
+	// the exit status because the plan value is not available at that point.
+	PlanEmpty bool
+
+	// State is the final state after the operation completed. Persisting
+	// this state is managed by the backend. This should only be read
+	// after the operation completes to avoid read/write races.
+	State *states.State
+}
+
+// OperationResult describes the result status of an operation.
+type OperationResult int
+
+const (
+	// OperationSuccess indicates that the operation completed as expected.
+	OperationSuccess OperationResult = 0
+
+	// OperationFailure indicates that the operation encountered some sort
+	// of error, and thus may have been only partially performed or not
+	// performed at all.
+	OperationFailure OperationResult = 1
+)
+
+func (r OperationResult) ExitStatus() int {
+	return int(r)
+}
+
+// If the argument is a path, Read loads it and returns the contents,
+// otherwise the argument is assumed to be the desired contents and is simply
+// returned.
+func ReadPathOrContents(poc string) (string, error) {
+	if len(poc) == 0 {
+		return poc, nil
+	}
+
+	path := poc
+	if path[0] == '~' {
+		var err error
+		path, err = homedir.Expand(path)
+		if err != nil {
+			return path, err
+		}
+	}
+
+	if _, err := os.Stat(path); err == nil {
+		contents, err := ioutil.ReadFile(path)
+		if err != nil {
+			return string(contents), err
+		}
+		return string(contents), nil
+	}
+
+	return poc, nil
+}
diff --git a/v1.5.7/internal/backend/backend_test.go b/v1.5.7/internal/backend/backend_test.go
new file mode 100644
index 0000000..d356226
--- /dev/null
+++ b/v1.5.7/internal/backend/backend_test.go
@@ -0,0 +1,132 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package backend
+
+import (
+	"io"
+	"io/ioutil"
+	"os"
+	"os/user"
+	"strings"
+	"testing"
+
+	"github.com/mitchellh/go-homedir"
+)
+
+func TestReadPathOrContents_Path(t *testing.T) {
+	f, cleanup := testTempFile(t)
+	defer cleanup()
+
+	if _, err := io.WriteString(f, "foobar"); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	f.Close()
+
+	contents, err := ReadPathOrContents(f.Name())
+
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if contents != "foobar" {
+		t.Fatalf("expected contents %s, got %s", "foobar", contents)
+	}
+}
+
+func TestReadPathOrContents_TildePath(t *testing.T) {
+	home, err := homedir.Dir()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	f, cleanup := testTempFile(t, home)
+	defer cleanup()
+
+	if _, err := io.WriteString(f, "foobar"); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	f.Close()
+
+	r := strings.NewReplacer(home, "~")
+	homePath := r.Replace(f.Name())
+	contents, err := ReadPathOrContents(homePath)
+
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if contents != "foobar" {
+		t.Fatalf("expected contents %s, got %s", "foobar", contents)
+	}
+}
+
+func TestRead_PathNoPermission(t *testing.T) {
+	// This skip condition is intended to get this test out of the way of users
+	// who are building and testing Terraform from within a Linux-based Docker
+	// container, where it is common for processes to be running as effectively
+	// root within the container.
+	if u, err := user.Current(); err == nil && u.Uid == "0" {
+		t.Skip("This test is invalid when running as root, since root can read every file")
+	}
+
+	f, cleanup := testTempFile(t)
+	defer cleanup()
+
+	if _, err := io.WriteString(f, "foobar"); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	f.Close()
+
+	if err := os.Chmod(f.Name(), 0); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	contents, err := ReadPathOrContents(f.Name())
+
+	if err == nil {
+		t.Fatal("Expected error, got none!")
+	}
+	if contents != "" {
+		t.Fatalf("expected contents %s, got %s", "", contents)
+	}
+}
+
+func TestReadPathOrContents_Contents(t *testing.T) {
+	input := "hello"
+
+	contents, err := ReadPathOrContents(input)
+
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if contents != input {
+		t.Fatalf("expected contents %s, got %s", input, contents)
+	}
+}
+
+func TestReadPathOrContents_TildeContents(t *testing.T) {
+	input := "~/hello/notafile"
+
+	contents, err := ReadPathOrContents(input)
+
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if contents != input {
+		t.Fatalf("expected contents %s, got %s", input, contents)
+	}
+}
+
+// Returns an open tempfile based at baseDir and a function to clean it up.
+func testTempFile(t *testing.T, baseDir ...string) (*os.File, func()) {
+	base := ""
+	if len(baseDir) == 1 {
+		base = baseDir[0]
+	}
+	f, err := ioutil.TempFile(base, "tf")
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	return f, func() {
+		os.Remove(f.Name())
+	}
+}
diff --git a/v1.5.7/internal/backend/cli.go b/v1.5.7/internal/backend/cli.go
new file mode 100644
index 0000000..1ae70ff
--- /dev/null
+++ b/v1.5.7/internal/backend/cli.go
@@ -0,0 +1,94 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package backend
+
+import (
+	"github.com/mitchellh/cli"
+	"github.com/mitchellh/colorstring"
+
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// CLI is an optional interface that can be implemented to be initialized
+// with information from the Terraform CLI. If this is implemented, this
+// initialization function will be called with data to help interact better
+// with a CLI.
+//
+// This interface was created to improve backend interaction with the
+// official Terraform CLI while making it optional for API users to have
+// to provide full CLI interaction to every backend.
+//
+// If you're implementing a Backend, it is acceptable to require CLI
+// initialization. In this case, your backend should be coded to error
+// on other methods (such as State, Operation) if CLI initialization was not
+// done with all required fields.
+type CLI interface {
+	Backend
+
+	// CLIInit is called once with options. The options passed to this
+	// function may not be modified after calling this since they can be
+	// read/written at any time by the Backend implementation.
+	//
+	// This may be called before or after Configure is called, so if settings
+	// here affect configurable settings, care should be taken to handle
+	// whether they should be overwritten or not.
+	CLIInit(*CLIOpts) error
+}
+
+// CLIOpts are the options passed into CLIInit for the CLI interface.
+//
+// These options represent the functionality the CLI exposes and often
+// maps to meta-flags available on every CLI (such as -input).
+//
+// When implementing a backend, it isn't expected that every option applies.
+// Your backend should be documented clearly to explain to end users what
+// options have an affect and what won't. In some cases, it may even make sense
+// to error in your backend when an option is set so that users don't make
+// a critically incorrect assumption about behavior.
+type CLIOpts struct {
+	// CLI and Colorize control the CLI output. If CLI is nil then no CLI
+	// output will be done. If CLIColor is nil then no coloring will be done.
+	CLI      cli.Ui
+	CLIColor *colorstring.Colorize
+
+	// Streams describes the low-level streams for Stdout, Stderr and Stdin,
+	// including some metadata about whether they are terminals. Most output
+	// should go via the object in field CLI above, but Streams can be useful
+	// for tailoring the output to fit the attached terminal, for example.
+	Streams *terminal.Streams
+
+	// StatePath is the local path where state is read from.
+	//
+	// StateOutPath is the local path where the state will be written.
+	// If this is empty, it will default to StatePath.
+	//
+	// StateBackupPath is the local path where a backup file will be written.
+	// If this is empty, no backup will be taken.
+	StatePath       string
+	StateOutPath    string
+	StateBackupPath string
+
+	// ContextOpts are the base context options to set when initializing a
+	// Terraform context. Many of these will be overridden or merged by
+	// Operation. See Operation for more details.
+	ContextOpts *terraform.ContextOpts
+
+	// Input will ask for necessary input prior to performing any operations.
+	//
+	// Validation will perform validation prior to running an operation. The
+	// variable naming doesn't match the style of others since we have a func
+	// Validate.
+	Input      bool
+	Validation bool
+
+	// RunningInAutomation indicates that commands are being run by an
+	// automated system rather than directly at a command prompt.
+	//
+	// This is a hint not to produce messages that expect that a user can
+	// run a follow-up command, perhaps because Terraform is running in
+	// some sort of workflow automation tool that abstracts away the
+	// exact commands that are being run.
+	RunningInAutomation bool
+}
diff --git a/v1.5.7/internal/backend/init/deprecate_test.go b/v1.5.7/internal/backend/init/deprecate_test.go
new file mode 100644
index 0000000..2a58cc1
--- /dev/null
+++ b/v1.5.7/internal/backend/init/deprecate_test.go
@@ -0,0 +1,33 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package init
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/backend/remote-state/inmem"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestDeprecateBackend(t *testing.T) {
+	deprecateMessage := "deprecated backend"
+	deprecatedBackend := deprecateBackend(
+		inmem.New(),
+		deprecateMessage,
+	)
+
+	_, diags := deprecatedBackend.PrepareConfig(cty.EmptyObjectVal)
+	if len(diags) != 1 {
+		t.Errorf("got %d diagnostics; want 1", len(diags))
+		for _, diag := range diags {
+			t.Errorf("- %s", diag)
+		}
+		return
+	}
+
+	desc := diags[0].Description()
+	if desc.Summary != deprecateMessage {
+		t.Fatalf("wrong message %q; want %q", desc.Summary, deprecateMessage)
+	}
+}
diff --git a/v1.5.7/internal/backend/init/init.go b/v1.5.7/internal/backend/init/init.go
new file mode 100644
index 0000000..ac95c55
--- /dev/null
+++ b/v1.5.7/internal/backend/init/init.go
@@ -0,0 +1,146 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package init contains the list of backends that can be initialized and
+// basic helper functions for initializing those backends.
+package init
+
+import (
+	"sync"
+
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+
+	backendLocal "github.com/hashicorp/terraform/internal/backend/local"
+	backendRemote "github.com/hashicorp/terraform/internal/backend/remote"
+	backendAzure "github.com/hashicorp/terraform/internal/backend/remote-state/azure"
+	backendConsul "github.com/hashicorp/terraform/internal/backend/remote-state/consul"
+	backendCos "github.com/hashicorp/terraform/internal/backend/remote-state/cos"
+	backendGCS "github.com/hashicorp/terraform/internal/backend/remote-state/gcs"
+	backendHTTP "github.com/hashicorp/terraform/internal/backend/remote-state/http"
+	backendInmem "github.com/hashicorp/terraform/internal/backend/remote-state/inmem"
+	backendKubernetes "github.com/hashicorp/terraform/internal/backend/remote-state/kubernetes"
+	backendOSS "github.com/hashicorp/terraform/internal/backend/remote-state/oss"
+	backendPg "github.com/hashicorp/terraform/internal/backend/remote-state/pg"
+	backendS3 "github.com/hashicorp/terraform/internal/backend/remote-state/s3"
+	backendCloud "github.com/hashicorp/terraform/internal/cloud"
+)
+
+// backends is the list of available backends. This is a global variable
+// because backends are currently hardcoded into Terraform and can't be
+// modified without recompilation.
+//
+// To read an available backend, use the Backend function. This ensures
+// safe concurrent read access to the list of built-in backends.
+//
+// Backends are hardcoded into Terraform because the API for backends uses
+// complex structures and supporting that over the plugin system is currently
+// prohibitively difficult. For those wanting to implement a custom backend,
+// they can do so with recompilation.
+var backends map[string]backend.InitFn
+var backendsLock sync.Mutex
+
+// RemovedBackends is a record of previously supported backends which have
+// since been deprecated and removed.
+var RemovedBackends map[string]string
+
+// Init initializes the backends map with all our hardcoded backends.
+func Init(services *disco.Disco) {
+	backendsLock.Lock()
+	defer backendsLock.Unlock()
+
+	backends = map[string]backend.InitFn{
+		"local":  func() backend.Backend { return backendLocal.New() },
+		"remote": func() backend.Backend { return backendRemote.New(services) },
+
+		// Remote State backends.
+		"azurerm":    func() backend.Backend { return backendAzure.New() },
+		"consul":     func() backend.Backend { return backendConsul.New() },
+		"cos":        func() backend.Backend { return backendCos.New() },
+		"gcs":        func() backend.Backend { return backendGCS.New() },
+		"http":       func() backend.Backend { return backendHTTP.New() },
+		"inmem":      func() backend.Backend { return backendInmem.New() },
+		"kubernetes": func() backend.Backend { return backendKubernetes.New() },
+		"oss":        func() backend.Backend { return backendOSS.New() },
+		"pg":         func() backend.Backend { return backendPg.New() },
+		"s3":         func() backend.Backend { return backendS3.New() },
+
+		// Terraform Cloud 'backend'
+		// This is an implementation detail only, used for the cloud package
+		"cloud": func() backend.Backend { return backendCloud.New(services) },
+	}
+
+	RemovedBackends = map[string]string{
+		"artifactory": `The "artifactory" backend is not supported in Terraform v1.3 or later.`,
+		"azure":       `The "azure" backend name has been removed, please use "azurerm".`,
+		"etcd":        `The "etcd" backend is not supported in Terraform v1.3 or later.`,
+		"etcdv3":      `The "etcdv3" backend is not supported in Terraform v1.3 or later.`,
+		"manta":       `The "manta" backend is not supported in Terraform v1.3 or later.`,
+		"swift":       `The "swift" backend is not supported in Terraform v1.3 or later.`,
+	}
+}
+
+// Backend returns the initialization factory for the given backend, or
+// nil if none exists.
+func Backend(name string) backend.InitFn {
+	backendsLock.Lock()
+	defer backendsLock.Unlock()
+	return backends[name]
+}
+
+// Set sets a new backend in the list of backends. If f is nil then the
+// backend will be removed from the map. If this backend already exists
+// then it will be overwritten.
+//
+// This method sets this backend globally and care should be taken to do
+// this only before Terraform is executing to prevent odd behavior of backends
+// changing mid-execution.
+func Set(name string, f backend.InitFn) {
+	backendsLock.Lock()
+	defer backendsLock.Unlock()
+
+	if f == nil {
+		delete(backends, name)
+		return
+	}
+
+	backends[name] = f
+}
+
+// deprecatedBackendShim is used to wrap a backend and inject a deprecation
+// warning into the Validate method.
+type deprecatedBackendShim struct {
+	backend.Backend
+	Message string
+}
+
+// PrepareConfig delegates to the wrapped backend to validate its config
+// and then appends shim's deprecation warning.
+func (b deprecatedBackendShim) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) {
+	newObj, diags := b.Backend.PrepareConfig(obj)
+	return newObj, diags.Append(tfdiags.SimpleWarning(b.Message))
+}
+
+// DeprecateBackend can be used to wrap a backend to retrun a deprecation
+// warning during validation.
+func deprecateBackend(b backend.Backend, message string) backend.Backend {
+	// Since a Backend wrapped by deprecatedBackendShim can no longer be
+	// asserted as an Enhanced or Local backend, disallow those types here
+	// entirely.  If something other than a basic backend.Backend needs to be
+	// deprecated, we can add that functionality to schema.Backend or the
+	// backend itself.
+	if _, ok := b.(backend.Enhanced); ok {
+		panic("cannot use DeprecateBackend on an Enhanced Backend")
+	}
+
+	if _, ok := b.(backend.Local); ok {
+		panic("cannot use DeprecateBackend on a Local Backend")
+	}
+
+	return deprecatedBackendShim{
+		Backend: b,
+		Message: message,
+	}
+}
diff --git a/v1.5.7/internal/backend/init/init_test.go b/v1.5.7/internal/backend/init/init_test.go
new file mode 100644
index 0000000..e05610e
--- /dev/null
+++ b/v1.5.7/internal/backend/init/init_test.go
@@ -0,0 +1,43 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package init
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestInit_backend(t *testing.T) {
+	// Initialize the backends map
+	Init(nil)
+
+	backends := []struct {
+		Name string
+		Type string
+	}{
+		{"local", "*local.Local"},
+		{"remote", "*remote.Remote"},
+		{"azurerm", "*azure.Backend"},
+		{"consul", "*consul.Backend"},
+		{"cos", "*cos.Backend"},
+		{"gcs", "*gcs.Backend"},
+		{"inmem", "*inmem.Backend"},
+		{"pg", "*pg.Backend"},
+		{"s3", "*s3.Backend"},
+	}
+
+	// Make sure we get the requested backend
+	for _, b := range backends {
+		t.Run(b.Name, func(t *testing.T) {
+			f := Backend(b.Name)
+			if f == nil {
+				t.Fatalf("backend %q is not present; should be", b.Name)
+			}
+			bType := reflect.TypeOf(f()).String()
+			if bType != b.Type {
+				t.Fatalf("expected backend %q to be %q, got: %q", b.Name, b.Type, bType)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/backend/local/backend.go b/v1.5.7/internal/backend/local/backend.go
new file mode 100644
index 0000000..592ffe0
--- /dev/null
+++ b/v1.5.7/internal/backend/local/backend.go
@@ -0,0 +1,496 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package local
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"sort"
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+const (
+	DefaultWorkspaceDir    = "terraform.tfstate.d"
+	DefaultWorkspaceFile   = "environment"
+	DefaultStateFilename   = "terraform.tfstate"
+	DefaultBackupExtension = ".backup"
+)
+
+// Local is an implementation of EnhancedBackend that performs all operations
+// locally. This is the "default" backend and implements normal Terraform
+// behavior as it is well known.
+type Local struct {
+	// The State* paths are set from the backend config, and may be left blank
+	// to use the defaults. If the actual paths for the local backend state are
+	// needed, use the StatePaths method.
+	//
+	// StatePath is the local path where state is read from.
+	//
+	// StateOutPath is the local path where the state will be written.
+	// If this is empty, it will default to StatePath.
+	//
+	// StateBackupPath is the local path where a backup file will be written.
+	// Set this to "-" to disable state backup.
+	//
+	// StateWorkspaceDir is the path to the folder containing data for
+	// non-default workspaces. This defaults to DefaultWorkspaceDir if not set.
+	StatePath         string
+	StateOutPath      string
+	StateBackupPath   string
+	StateWorkspaceDir string
+
+	// The OverrideState* paths are set based on per-operation CLI arguments
+	// and will override what'd be built from the State* fields if non-empty.
+	// While the interpretation of the State* fields depends on the active
+	// workspace, the OverrideState* fields are always used literally.
+	OverrideStatePath       string
+	OverrideStateOutPath    string
+	OverrideStateBackupPath string
+
+	// We only want to create a single instance of a local state, so store them
+	// here as they're loaded.
+	states map[string]statemgr.Full
+
+	// Terraform context. Many of these will be overridden or merged by
+	// Operation. See Operation for more details.
+	ContextOpts *terraform.ContextOpts
+
+	// OpInput will ask for necessary input prior to performing any operations.
+	//
+	// OpValidation will perform validation prior to running an operation. The
+	// variable naming doesn't match the style of others since we have a func
+	// Validate.
+	OpInput      bool
+	OpValidation bool
+
+	// Backend, if non-nil, will use this backend for non-enhanced behavior.
+	// This allows local behavior with remote state storage. It is a way to
+	// "upgrade" a non-enhanced backend to an enhanced backend with typical
+	// behavior.
+	//
+	// If this is nil, local performs normal state loading and storage.
+	Backend backend.Backend
+
+	// opLock locks operations
+	opLock sync.Mutex
+}
+
+var _ backend.Backend = (*Local)(nil)
+
+// New returns a new initialized local backend.
+func New() *Local {
+	return NewWithBackend(nil)
+}
+
+// NewWithBackend returns a new local backend initialized with a
+// dedicated backend for non-enhanced behavior.
+func NewWithBackend(backend backend.Backend) *Local {
+	return &Local{
+		Backend: backend,
+	}
+}
+
+func (b *Local) ConfigSchema() *configschema.Block {
+	if b.Backend != nil {
+		return b.Backend.ConfigSchema()
+	}
+	return &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"path": {
+				Type:     cty.String,
+				Optional: true,
+			},
+			"workspace_dir": {
+				Type:     cty.String,
+				Optional: true,
+			},
+		},
+	}
+}
+
+func (b *Local) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) {
+	if b.Backend != nil {
+		return b.Backend.PrepareConfig(obj)
+	}
+
+	var diags tfdiags.Diagnostics
+
+	if val := obj.GetAttr("path"); !val.IsNull() {
+		p := val.AsString()
+		if p == "" {
+			diags = diags.Append(tfdiags.AttributeValue(
+				tfdiags.Error,
+				"Invalid local state file path",
+				`The "path" attribute value must not be empty.`,
+				cty.Path{cty.GetAttrStep{Name: "path"}},
+			))
+		}
+	}
+
+	if val := obj.GetAttr("workspace_dir"); !val.IsNull() {
+		p := val.AsString()
+		if p == "" {
+			diags = diags.Append(tfdiags.AttributeValue(
+				tfdiags.Error,
+				"Invalid local workspace directory path",
+				`The "workspace_dir" attribute value must not be empty.`,
+				cty.Path{cty.GetAttrStep{Name: "workspace_dir"}},
+			))
+		}
+	}
+
+	return obj, diags
+}
+
+func (b *Local) Configure(obj cty.Value) tfdiags.Diagnostics {
+	if b.Backend != nil {
+		return b.Backend.Configure(obj)
+	}
+
+	var diags tfdiags.Diagnostics
+
+	if val := obj.GetAttr("path"); !val.IsNull() {
+		p := val.AsString()
+		b.StatePath = p
+		b.StateOutPath = p
+	} else {
+		b.StatePath = DefaultStateFilename
+		b.StateOutPath = DefaultStateFilename
+	}
+
+	if val := obj.GetAttr("workspace_dir"); !val.IsNull() {
+		p := val.AsString()
+		b.StateWorkspaceDir = p
+	} else {
+		b.StateWorkspaceDir = DefaultWorkspaceDir
+	}
+
+	return diags
+}
+
+func (b *Local) ServiceDiscoveryAliases() ([]backend.HostAlias, error) {
+	return []backend.HostAlias{}, nil
+}
+
+func (b *Local) Workspaces() ([]string, error) {
+	// If we have a backend handling state, defer to that.
+	if b.Backend != nil {
+		return b.Backend.Workspaces()
+	}
+
+	// the listing always start with "default"
+	envs := []string{backend.DefaultStateName}
+
+	entries, err := ioutil.ReadDir(b.stateWorkspaceDir())
+	// no error if there's no envs configured
+	if os.IsNotExist(err) {
+		return envs, nil
+	}
+	if err != nil {
+		return nil, err
+	}
+
+	var listed []string
+	for _, entry := range entries {
+		if entry.IsDir() {
+			listed = append(listed, filepath.Base(entry.Name()))
+		}
+	}
+
+	sort.Strings(listed)
+	envs = append(envs, listed...)
+
+	return envs, nil
+}
+
+// DeleteWorkspace removes a workspace.
+//
+// The "default" workspace cannot be removed.
+func (b *Local) DeleteWorkspace(name string, force bool) error {
+	// If we have a backend handling state, defer to that.
+	if b.Backend != nil {
+		return b.Backend.DeleteWorkspace(name, force)
+	}
+
+	if name == "" {
+		return errors.New("empty state name")
+	}
+
+	if name == backend.DefaultStateName {
+		return errors.New("cannot delete default state")
+	}
+
+	delete(b.states, name)
+	return os.RemoveAll(filepath.Join(b.stateWorkspaceDir(), name))
+}
+
+func (b *Local) StateMgr(name string) (statemgr.Full, error) {
+	// If we have a backend handling state, delegate to that.
+	if b.Backend != nil {
+		return b.Backend.StateMgr(name)
+	}
+
+	if s, ok := b.states[name]; ok {
+		return s, nil
+	}
+
+	if err := b.createState(name); err != nil {
+		return nil, err
+	}
+
+	statePath, stateOutPath, backupPath := b.StatePaths(name)
+	log.Printf("[TRACE] backend/local: state manager for workspace %q will:\n - read initial snapshot from %s\n - write new snapshots to %s\n - create any backup at %s", name, statePath, stateOutPath, backupPath)
+
+	s := statemgr.NewFilesystemBetweenPaths(statePath, stateOutPath)
+	if backupPath != "" {
+		s.SetBackupPath(backupPath)
+	}
+
+	if b.states == nil {
+		b.states = map[string]statemgr.Full{}
+	}
+	b.states[name] = s
+	return s, nil
+}
+
+// Operation implements backend.Enhanced
+//
+// This will initialize an in-memory terraform.Context to perform the
+// operation within this process.
+//
+// The given operation parameter will be merged with the ContextOpts on
+// the structure with the following rules. If a rule isn't specified and the
+// name conflicts, assume that the field is overwritten if set.
+func (b *Local) Operation(ctx context.Context, op *backend.Operation) (*backend.RunningOperation, error) {
+	if op.View == nil {
+		panic("Operation called with nil View")
+	}
+
+	// Determine the function to call for our operation
+	var f func(context.Context, context.Context, *backend.Operation, *backend.RunningOperation)
+	switch op.Type {
+	case backend.OperationTypeRefresh:
+		f = b.opRefresh
+	case backend.OperationTypePlan:
+		f = b.opPlan
+	case backend.OperationTypeApply:
+		f = b.opApply
+	default:
+		return nil, fmt.Errorf(
+			"unsupported operation type: %s\n\n"+
+				"This is a bug in Terraform and should be reported. The local backend\n"+
+				"is built-in to Terraform and should always support all operations.",
+			op.Type)
+	}
+
+	// Lock
+	b.opLock.Lock()
+
+	// Build our running operation
+	// the runninCtx is only used to block until the operation returns.
+	runningCtx, done := context.WithCancel(context.Background())
+	runningOp := &backend.RunningOperation{
+		Context: runningCtx,
+	}
+
+	// stopCtx wraps the context passed in, and is used to signal a graceful Stop.
+	stopCtx, stop := context.WithCancel(ctx)
+	runningOp.Stop = stop
+
+	// cancelCtx is used to cancel the operation immediately, usually
+	// indicating that the process is exiting.
+	cancelCtx, cancel := context.WithCancel(context.Background())
+	runningOp.Cancel = cancel
+
+	op.StateLocker = op.StateLocker.WithContext(stopCtx)
+
+	// Do it
+	go func() {
+		defer logging.PanicHandler()
+		defer done()
+		defer stop()
+		defer cancel()
+
+		defer b.opLock.Unlock()
+		f(stopCtx, cancelCtx, op, runningOp)
+	}()
+
+	// Return
+	return runningOp, nil
+}
+
+// opWait waits for the operation to complete, and a stop signal or a
+// cancelation signal.
+func (b *Local) opWait(
+	doneCh <-chan struct{},
+	stopCtx context.Context,
+	cancelCtx context.Context,
+	tfCtx *terraform.Context,
+	opStateMgr statemgr.Persister,
+	view views.Operation) (canceled bool) {
+	// Wait for the operation to finish or for us to be interrupted so
+	// we can handle it properly.
+	select {
+	case <-stopCtx.Done():
+		view.Stopping()
+
+		// try to force a PersistState just in case the process is terminated
+		// before we can complete.
+		if err := opStateMgr.PersistState(nil); err != nil {
+			// We can't error out from here, but warn the user if there was an error.
+			// If this isn't transient, we will catch it again below, and
+			// attempt to save the state another way.
+			var diags tfdiags.Diagnostics
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Error saving current state",
+				fmt.Sprintf(earlyStateWriteErrorFmt, err),
+			))
+			view.Diagnostics(diags)
+		}
+
+		// Stop execution
+		log.Println("[TRACE] backend/local: waiting for the running operation to stop")
+		go tfCtx.Stop()
+
+		select {
+		case <-cancelCtx.Done():
+			log.Println("[WARN] running operation was forcefully canceled")
+			// if the operation was canceled, we need to return immediately
+			canceled = true
+		case <-doneCh:
+			log.Println("[TRACE] backend/local: graceful stop has completed")
+		}
+	case <-cancelCtx.Done():
+		// this should not be called without first attempting to stop the
+		// operation
+		log.Println("[ERROR] running operation canceled without Stop")
+		canceled = true
+	case <-doneCh:
+	}
+	return
+}
+
+// StatePaths returns the StatePath, StateOutPath, and StateBackupPath as
+// configured from the CLI.
+func (b *Local) StatePaths(name string) (stateIn, stateOut, backupOut string) {
+	statePath := b.OverrideStatePath
+	stateOutPath := b.OverrideStateOutPath
+	backupPath := b.OverrideStateBackupPath
+
+	isDefault := name == backend.DefaultStateName || name == ""
+
+	baseDir := ""
+	if !isDefault {
+		baseDir = filepath.Join(b.stateWorkspaceDir(), name)
+	}
+
+	if statePath == "" {
+		if isDefault {
+			statePath = b.StatePath // s.StatePath applies only to the default workspace, since StateWorkspaceDir is used otherwise
+		}
+		if statePath == "" {
+			statePath = filepath.Join(baseDir, DefaultStateFilename)
+		}
+	}
+	if stateOutPath == "" {
+		stateOutPath = statePath
+	}
+	if backupPath == "" {
+		backupPath = b.StateBackupPath
+	}
+	switch backupPath {
+	case "-":
+		backupPath = ""
+	case "":
+		backupPath = stateOutPath + DefaultBackupExtension
+	}
+
+	return statePath, stateOutPath, backupPath
+}
+
+// PathsConflictWith returns true if any state path used by a workspace in
+// the receiver is the same as any state path used by the other given
+// local backend instance.
+//
+// This should be used when "migrating" from one local backend configuration to
+// another in order to avoid deleting the "old" state snapshots if they are
+// in the same files as the "new" state snapshots.
+func (b *Local) PathsConflictWith(other *Local) bool {
+	otherPaths := map[string]struct{}{}
+	otherWorkspaces, err := other.Workspaces()
+	if err != nil {
+		// If we can't enumerate the workspaces then we'll conservatively
+		// assume that paths _do_ overlap, since we can't be certain.
+		return true
+	}
+	for _, name := range otherWorkspaces {
+		p, _, _ := other.StatePaths(name)
+		otherPaths[p] = struct{}{}
+	}
+
+	ourWorkspaces, err := other.Workspaces()
+	if err != nil {
+		// If we can't enumerate the workspaces then we'll conservatively
+		// assume that paths _do_ overlap, since we can't be certain.
+		return true
+	}
+
+	for _, name := range ourWorkspaces {
+		p, _, _ := b.StatePaths(name)
+		if _, exists := otherPaths[p]; exists {
+			return true
+		}
+	}
+	return false
+}
+
+// this only ensures that the named directory exists
+func (b *Local) createState(name string) error {
+	if name == backend.DefaultStateName {
+		return nil
+	}
+
+	stateDir := filepath.Join(b.stateWorkspaceDir(), name)
+	s, err := os.Stat(stateDir)
+	if err == nil && s.IsDir() {
+		// no need to check for os.IsNotExist, since that is covered by os.MkdirAll
+		// which will catch the other possible errors as well.
+		return nil
+	}
+
+	err = os.MkdirAll(stateDir, 0755)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// stateWorkspaceDir returns the directory where state environments are stored.
+func (b *Local) stateWorkspaceDir() string {
+	if b.StateWorkspaceDir != "" {
+		return b.StateWorkspaceDir
+	}
+
+	return DefaultWorkspaceDir
+}
+
+const earlyStateWriteErrorFmt = `Error: %s
+
+Terraform encountered an error attempting to save the state before cancelling the current operation. Once the operation is complete another attempt will be made to save the final state.`
diff --git a/v1.5.7/internal/backend/local/backend_apply.go b/v1.5.7/internal/backend/local/backend_apply.go
new file mode 100644
index 0000000..2aabfab
--- /dev/null
+++ b/v1.5.7/internal/backend/local/backend_apply.go
@@ -0,0 +1,364 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package local
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"log"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// test hook called between plan+apply during opApply
+var testHookStopPlanApply func()
+
+func (b *Local) opApply(
+	stopCtx context.Context,
+	cancelCtx context.Context,
+	op *backend.Operation,
+	runningOp *backend.RunningOperation) {
+	log.Printf("[INFO] backend/local: starting Apply operation")
+
+	var diags, moreDiags tfdiags.Diagnostics
+
+	// If we have a nil module at this point, then set it to an empty tree
+	// to avoid any potential crashes.
+	if op.PlanFile == nil && op.PlanMode != plans.DestroyMode && !op.HasConfig() {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"No configuration files",
+			"Apply requires configuration to be present. Applying without a configuration "+
+				"would mark everything for destruction, which is normally not what is desired. "+
+				"If you would like to destroy everything, run 'terraform destroy' instead.",
+		))
+		op.ReportResult(runningOp, diags)
+		return
+	}
+
+	stateHook := new(StateHook)
+	op.Hooks = append(op.Hooks, stateHook)
+
+	// Get our context
+	lr, _, opState, contextDiags := b.localRun(op)
+	diags = diags.Append(contextDiags)
+	if contextDiags.HasErrors() {
+		op.ReportResult(runningOp, diags)
+		return
+	}
+	// the state was locked during successful context creation; unlock the state
+	// when the operation completes
+	defer func() {
+		diags := op.StateLocker.Unlock()
+		if diags.HasErrors() {
+			op.View.Diagnostics(diags)
+			runningOp.Result = backend.OperationFailure
+		}
+	}()
+
+	// We'll start off with our result being the input state, and replace it
+	// with the result state only if we eventually complete the apply
+	// operation.
+	runningOp.State = lr.InputState
+
+	schemas, moreDiags := lr.Core.Schemas(lr.Config, lr.InputState)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		op.ReportResult(runningOp, diags)
+		return
+	}
+	// stateHook uses schemas for when it periodically persists state to the
+	// persistent storage backend.
+	stateHook.Schemas = schemas
+	stateHook.PersistInterval = 20 * time.Second // arbitrary interval that's hopefully a sweet spot
+
+	var plan *plans.Plan
+	// If we weren't given a plan, then we refresh/plan
+	if op.PlanFile == nil {
+		// Perform the plan
+		log.Printf("[INFO] backend/local: apply calling Plan")
+		plan, moreDiags = lr.Core.Plan(lr.Config, lr.InputState, lr.PlanOpts)
+		diags = diags.Append(moreDiags)
+		if moreDiags.HasErrors() {
+			// If Terraform Core generated a partial plan despite the errors
+			// then we'll make a best effort to render it. Terraform Core
+			// promises that if it returns a non-nil plan along with errors
+			// then the plan won't necessarily contain all of the needed
+			// actions but that any it does include will be properly-formed.
+			// plan.Errored will be true in this case, which our plan
+			// renderer can rely on to tailor its messaging.
+			if plan != nil && (len(plan.Changes.Resources) != 0 || len(plan.Changes.Outputs) != 0) {
+				schemas, moreDiags := lr.Core.Schemas(lr.Config, lr.InputState)
+				// If schema loading returns errors then we'll just give up and
+				// ignore them to avoid distracting from the plan-time errors we're
+				// mainly trying to report here.
+				if !moreDiags.HasErrors() {
+					op.View.Plan(plan, schemas)
+				}
+			}
+			op.ReportResult(runningOp, diags)
+			return
+		}
+
+		trivialPlan := !plan.CanApply()
+		hasUI := op.UIOut != nil && op.UIIn != nil
+		mustConfirm := hasUI && !op.AutoApprove && !trivialPlan
+		op.View.Plan(plan, schemas)
+
+		if testHookStopPlanApply != nil {
+			testHookStopPlanApply()
+		}
+
+		// Check if we've been stopped before going through confirmation, or
+		// skipping confirmation in the case of -auto-approve.
+		// This can currently happen if a single stop request was received
+		// during the final batch of resource plan calls, so no operations were
+		// forced to abort, and no errors were returned from Plan.
+		if stopCtx.Err() != nil {
+			diags = diags.Append(errors.New("execution halted"))
+			runningOp.Result = backend.OperationFailure
+			op.ReportResult(runningOp, diags)
+			return
+		}
+
+		if mustConfirm {
+			var desc, query string
+			switch op.PlanMode {
+			case plans.DestroyMode:
+				if op.Workspace != "default" {
+					query = "Do you really want to destroy all resources in workspace \"" + op.Workspace + "\"?"
+				} else {
+					query = "Do you really want to destroy all resources?"
+				}
+				desc = "Terraform will destroy all your managed infrastructure, as shown above.\n" +
+					"There is no undo. Only 'yes' will be accepted to confirm."
+			case plans.RefreshOnlyMode:
+				if op.Workspace != "default" {
+					query = "Would you like to update the Terraform state for \"" + op.Workspace + "\" to reflect these detected changes?"
+				} else {
+					query = "Would you like to update the Terraform state to reflect these detected changes?"
+				}
+				desc = "Terraform will write these changes to the state without modifying any real infrastructure.\n" +
+					"There is no undo. Only 'yes' will be accepted to confirm."
+			default:
+				if op.Workspace != "default" {
+					query = "Do you want to perform these actions in workspace \"" + op.Workspace + "\"?"
+				} else {
+					query = "Do you want to perform these actions?"
+				}
+				desc = "Terraform will perform the actions described above.\n" +
+					"Only 'yes' will be accepted to approve."
+			}
+
+			// We'll show any accumulated warnings before we display the prompt,
+			// so the user can consider them when deciding how to answer.
+			if len(diags) > 0 {
+				op.View.Diagnostics(diags)
+				diags = nil // reset so we won't show the same diagnostics again later
+			}
+
+			v, err := op.UIIn.Input(stopCtx, &terraform.InputOpts{
+				Id:          "approve",
+				Query:       "\n" + query,
+				Description: desc,
+			})
+			if err != nil {
+				diags = diags.Append(fmt.Errorf("error asking for approval: %w", err))
+				op.ReportResult(runningOp, diags)
+				return
+			}
+			if v != "yes" {
+				op.View.Cancelled(op.PlanMode)
+				runningOp.Result = backend.OperationFailure
+				return
+			}
+		} else {
+			// If we didn't ask for confirmation from the user, and they have
+			// included any failing checks in their configuration, then they
+			// will see a very confusing output after the apply operation
+			// completes. This is because all the diagnostics from the plan
+			// operation will now be shown alongside the diagnostics from the
+			// apply operation. For check diagnostics, the plan output is
+			// irrelevant and simple noise after the same set of checks have
+			// been executed again during the apply stage. As such, we are going
+			// to remove all diagnostics marked as check diagnostics at this
+			// stage, so we will only show the user the check results from the
+			// apply operation.
+			//
+			// Note, if we did ask for approval then we would have displayed the
+			// plan check results at that point which is useful as the user can
+			// use them to make a decision about whether to apply the changes.
+			// It's just that if we didn't ask for approval then showing the
+			// user the checks from the plan alongside the checks from the apply
+			// is needlessly confusing.
+			var filteredDiags tfdiags.Diagnostics
+			for _, diag := range diags {
+				if !tfdiags.IsFromCheckBlock(diag) {
+					filteredDiags = filteredDiags.Append(diag)
+				}
+			}
+			diags = filteredDiags
+		}
+	} else {
+		plan = lr.Plan
+		if plan.Errored {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Cannot apply incomplete plan",
+				"Terraform encountered an error when generating this plan, so it cannot be applied.",
+			))
+			op.ReportResult(runningOp, diags)
+			return
+		}
+		for _, change := range plan.Changes.Resources {
+			if change.Action != plans.NoOp {
+				op.View.PlannedChange(change)
+			}
+		}
+	}
+
+	// Set up our hook for continuous state updates
+	stateHook.StateMgr = opState
+
+	// Start the apply in a goroutine so that we can be interrupted.
+	var applyState *states.State
+	var applyDiags tfdiags.Diagnostics
+	doneCh := make(chan struct{})
+	go func() {
+		defer logging.PanicHandler()
+		defer close(doneCh)
+		log.Printf("[INFO] backend/local: apply calling Apply")
+		applyState, applyDiags = lr.Core.Apply(plan, lr.Config)
+	}()
+
+	if b.opWait(doneCh, stopCtx, cancelCtx, lr.Core, opState, op.View) {
+		return
+	}
+	diags = diags.Append(applyDiags)
+
+	// Even on error with an empty state, the state value should not be nil.
+	// Return early here to prevent corrupting any existing state.
+	if diags.HasErrors() && applyState == nil {
+		log.Printf("[ERROR] backend/local: apply returned nil state")
+		op.ReportResult(runningOp, diags)
+		return
+	}
+
+	// Store the final state
+	runningOp.State = applyState
+	err := statemgr.WriteAndPersist(opState, applyState, schemas)
+	if err != nil {
+		// Export the state file from the state manager and assign the new
+		// state. This is needed to preserve the existing serial and lineage.
+		stateFile := statemgr.Export(opState)
+		if stateFile == nil {
+			stateFile = &statefile.File{}
+		}
+		stateFile.State = applyState
+
+		diags = diags.Append(b.backupStateForError(stateFile, err, op.View))
+		op.ReportResult(runningOp, diags)
+		return
+	}
+
+	if applyDiags.HasErrors() {
+		op.ReportResult(runningOp, diags)
+		return
+	}
+
+	// If we've accumulated any warnings along the way then we'll show them
+	// here just before we show the summary and next steps. If we encountered
+	// errors then we would've returned early at some other point above.
+	op.View.Diagnostics(diags)
+}
+
+// backupStateForError is called in a scenario where we're unable to persist the
+// state for some reason, and will attempt to save a backup copy of the state
+// to local disk to help the user recover. This is a "last ditch effort" sort
+// of thing, so we really don't want to end up in this codepath; we should do
+// everything we possibly can to get the state saved _somewhere_.
+func (b *Local) backupStateForError(stateFile *statefile.File, err error, view views.Operation) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	diags = diags.Append(tfdiags.Sourceless(
+		tfdiags.Error,
+		"Failed to save state",
+		fmt.Sprintf("Error saving state: %s", err),
+	))
+
+	local := statemgr.NewFilesystem("errored.tfstate")
+	writeErr := local.WriteStateForMigration(stateFile, true)
+	if writeErr != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to create local state file",
+			fmt.Sprintf("Error creating local state file for recovery: %s", writeErr),
+		))
+
+		// To avoid leaving the user with no state at all, our last resort
+		// is to print the JSON state out onto the terminal. This is an awful
+		// UX, so we should definitely avoid doing this if at all possible,
+		// but at least the user has _some_ path to recover if we end up
+		// here for some reason.
+		if dumpErr := view.EmergencyDumpState(stateFile); dumpErr != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to serialize state",
+				fmt.Sprintf(stateWriteFatalErrorFmt, dumpErr),
+			))
+		}
+
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to persist state to backend",
+			stateWriteConsoleFallbackError,
+		))
+		return diags
+	}
+
+	diags = diags.Append(tfdiags.Sourceless(
+		tfdiags.Error,
+		"Failed to persist state to backend",
+		stateWriteBackedUpError,
+	))
+
+	return diags
+}
+
+const stateWriteBackedUpError = `The error shown above has prevented Terraform from writing the updated state to the configured backend. To allow for recovery, the state has been written to the file "errored.tfstate" in the current working directory.
+
+Running "terraform apply" again at this point will create a forked state, making it harder to recover.
+
+To retry writing this state, use the following command:
+    terraform state push errored.tfstate
+`
+
+const stateWriteConsoleFallbackError = `The errors shown above prevented Terraform from writing the updated state to
+the configured backend and from creating a local backup file. As a fallback,
+the raw state data is printed above as a JSON object.
+
+To retry writing this state, copy the state data (from the first { to the last } inclusive) and save it into a local file called errored.tfstate, then run the following command:
+    terraform state push errored.tfstate
+`
+
+const stateWriteFatalErrorFmt = `Failed to save state after apply.
+
+Error serializing state: %s
+
+A catastrophic error has prevented Terraform from persisting the state file or creating a backup. Unfortunately this means that the record of any resources created during this apply has been lost, and such resources may exist outside of Terraform's management.
+
+For resources that support import, it is possible to recover by manually importing each resource using its id from the target system.
+
+This is a serious bug in Terraform and should be reported.
+`
diff --git a/v1.5.7/internal/backend/local/backend_apply_test.go b/v1.5.7/internal/backend/local/backend_apply_test.go
new file mode 100644
index 0000000..5ae4fd4
--- /dev/null
+++ b/v1.5.7/internal/backend/local/backend_apply_test.go
@@ -0,0 +1,433 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package local
+
+import (
+	"context"
+	"errors"
+	"os"
+	"path/filepath"
+	"strings"
+	"sync"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestLocal_applyBasic(t *testing.T) {
+	b := TestLocal(t)
+
+	p := TestLocalProvider(t, b, "test", applyFixtureSchema())
+	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{NewState: cty.ObjectVal(map[string]cty.Value{
+		"id":  cty.StringVal("yes"),
+		"ami": cty.StringVal("bar"),
+	})}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatal("operation failed")
+	}
+
+	if p.ReadResourceCalled {
+		t.Fatal("ReadResource should not be called")
+	}
+
+	if !p.PlanResourceChangeCalled {
+		t.Fatal("diff should be called")
+	}
+
+	if !p.ApplyResourceChangeCalled {
+		t.Fatal("apply should be called")
+	}
+
+	checkState(t, b.StateOutPath, `
+test_instance.foo:
+  ID = yes
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  ami = bar
+`)
+
+	if errOutput := done(t).Stderr(); errOutput != "" {
+		t.Fatalf("unexpected error output:\n%s", errOutput)
+	}
+}
+func TestLocal_applyCheck(t *testing.T) {
+	b := TestLocal(t)
+
+	p := TestLocalProvider(t, b, "test", applyFixtureSchema())
+	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{NewState: cty.ObjectVal(map[string]cty.Value{
+		"id":  cty.StringVal("yes"),
+		"ami": cty.StringVal("bar"),
+	})}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-check")
+	defer configCleanup()
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatal("operation failed")
+	}
+
+	if p.ReadResourceCalled {
+		t.Fatal("ReadResource should not be called")
+	}
+
+	if !p.PlanResourceChangeCalled {
+		t.Fatal("diff should be called")
+	}
+
+	if !p.ApplyResourceChangeCalled {
+		t.Fatal("apply should be called")
+	}
+
+	d := done(t)
+	if errOutput := d.Stderr(); errOutput != "" {
+		t.Fatalf("unexpected error output:\n%s", errOutput)
+	}
+
+	if stdOutput := d.Stdout(); strings.Contains(stdOutput, "Check block assertion known after apply") {
+		// As we are running an auto approved plan the warning that was
+		// generated during the plan should have been hidden.
+		t.Fatalf("std output contained unexpected check output:\n%s", stdOutput)
+	}
+}
+
+func TestLocal_applyEmptyDir(t *testing.T) {
+	b := TestLocal(t)
+
+	p := TestLocalProvider(t, b, "test", &terraform.ProviderSchema{})
+	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{NewState: cty.ObjectVal(map[string]cty.Value{"id": cty.StringVal("yes")})}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/empty")
+	defer configCleanup()
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("operation succeeded; want error")
+	}
+
+	if p.ApplyResourceChangeCalled {
+		t.Fatal("apply should not be called")
+	}
+
+	if _, err := os.Stat(b.StateOutPath); err == nil {
+		t.Fatal("should not exist")
+	}
+
+	// the backend should be unlocked after a run
+	assertBackendStateUnlocked(t, b)
+
+	if got, want := done(t).Stderr(), "Error: No configuration files"; !strings.Contains(got, want) {
+		t.Fatalf("unexpected error output:\n%s\nwant: %s", got, want)
+	}
+}
+
+func TestLocal_applyEmptyDirDestroy(t *testing.T) {
+	b := TestLocal(t)
+
+	p := TestLocalProvider(t, b, "test", &terraform.ProviderSchema{})
+	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/empty")
+	defer configCleanup()
+	op.PlanMode = plans.DestroyMode
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("apply operation failed")
+	}
+
+	if p.ApplyResourceChangeCalled {
+		t.Fatal("apply should not be called")
+	}
+
+	checkState(t, b.StateOutPath, `<no state>`)
+
+	if errOutput := done(t).Stderr(); errOutput != "" {
+		t.Fatalf("unexpected error output:\n%s", errOutput)
+	}
+}
+
+func TestLocal_applyError(t *testing.T) {
+	b := TestLocal(t)
+
+	schema := &terraform.ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"ami": {Type: cty.String, Optional: true},
+					"id":  {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	}
+	p := TestLocalProvider(t, b, "test", schema)
+
+	var lock sync.Mutex
+	errored := false
+	p.ApplyResourceChangeFn = func(
+		r providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+
+		lock.Lock()
+		defer lock.Unlock()
+		var diags tfdiags.Diagnostics
+
+		ami := r.Config.GetAttr("ami").AsString()
+		if !errored && ami == "error" {
+			errored = true
+			diags = diags.Append(errors.New("ami error"))
+			return providers.ApplyResourceChangeResponse{
+				Diagnostics: diags,
+			}
+		}
+		return providers.ApplyResourceChangeResponse{
+			Diagnostics: diags,
+			NewState: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("foo"),
+				"ami": cty.StringVal("bar"),
+			}),
+		}
+	}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-error")
+	defer configCleanup()
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("operation succeeded; want failure")
+	}
+
+	checkState(t, b.StateOutPath, `
+test_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  ami = bar
+	`)
+
+	// the backend should be unlocked after a run
+	assertBackendStateUnlocked(t, b)
+
+	if got, want := done(t).Stderr(), "Error: ami error"; !strings.Contains(got, want) {
+		t.Fatalf("unexpected error output:\n%s\nwant: %s", got, want)
+	}
+}
+
+func TestLocal_applyBackendFail(t *testing.T) {
+	b := TestLocal(t)
+
+	p := TestLocalProvider(t, b, "test", applyFixtureSchema())
+
+	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"id":  cty.StringVal("yes"),
+			"ami": cty.StringVal("bar"),
+		}),
+		Diagnostics: tfdiags.Diagnostics.Append(nil, errors.New("error before backend failure")),
+	}
+
+	wd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("failed to get current working directory")
+	}
+	err = os.Chdir(filepath.Dir(b.StatePath))
+	if err != nil {
+		t.Fatalf("failed to set temporary working directory")
+	}
+	defer os.Chdir(wd)
+
+	op, configCleanup, done := testOperationApply(t, wd+"/testdata/apply")
+	defer configCleanup()
+
+	b.Backend = &backendWithFailingState{}
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+
+	output := done(t)
+
+	if run.Result == backend.OperationSuccess {
+		t.Fatalf("apply succeeded; want error")
+	}
+
+	diagErr := output.Stderr()
+
+	if !strings.Contains(diagErr, "Error saving state: fake failure") {
+		t.Fatalf("missing \"fake failure\" message in diags:\n%s", diagErr)
+	}
+
+	if !strings.Contains(diagErr, "error before backend failure") {
+		t.Fatalf("missing 'error before backend failure' diagnostic from apply")
+	}
+
+	// The fallback behavior should've created a file errored.tfstate in the
+	// current working directory.
+	checkState(t, "errored.tfstate", `
+test_instance.foo: (tainted)
+  ID = yes
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  ami = bar
+	`)
+
+	// the backend should be unlocked after a run
+	assertBackendStateUnlocked(t, b)
+}
+
+func TestLocal_applyRefreshFalse(t *testing.T) {
+	b := TestLocal(t)
+
+	p := TestLocalProvider(t, b, "test", planFixtureSchema())
+	testStateFile(t, b.StatePath, testPlanState())
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/plan")
+	defer configCleanup()
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("plan operation failed")
+	}
+
+	if p.ReadResourceCalled {
+		t.Fatal("ReadResource should not be called")
+	}
+
+	if errOutput := done(t).Stderr(); errOutput != "" {
+		t.Fatalf("unexpected error output:\n%s", errOutput)
+	}
+}
+
+type backendWithFailingState struct {
+	Local
+}
+
+func (b *backendWithFailingState) StateMgr(name string) (statemgr.Full, error) {
+	return &failingState{
+		statemgr.NewFilesystem("failing-state.tfstate"),
+	}, nil
+}
+
+type failingState struct {
+	*statemgr.Filesystem
+}
+
+func (s failingState) WriteState(state *states.State) error {
+	return errors.New("fake failure")
+}
+
+func testOperationApply(t *testing.T, configDir string) (*backend.Operation, func(), func(*testing.T) *terminal.TestOutput) {
+	t.Helper()
+
+	_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams))
+
+	// Many of our tests use an overridden "test" provider that's just in-memory
+	// inside the test process, not a separate plugin on disk.
+	depLocks := depsfile.NewLocks()
+	depLocks.SetProviderOverridden(addrs.MustParseProviderSourceString("registry.terraform.io/hashicorp/test"))
+
+	return &backend.Operation{
+		Type:            backend.OperationTypeApply,
+		ConfigDir:       configDir,
+		ConfigLoader:    configLoader,
+		StateLocker:     clistate.NewNoopLocker(),
+		View:            view,
+		DependencyLocks: depLocks,
+	}, configCleanup, done
+}
+
+// applyFixtureSchema returns a schema suitable for processing the
+// configuration in testdata/apply . This schema should be
+// assigned to a mock provider named "test".
+func applyFixtureSchema() *terraform.ProviderSchema {
+	return &terraform.ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"ami": {Type: cty.String, Optional: true},
+					"id":  {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	}
+}
+
+func TestApply_applyCanceledAutoApprove(t *testing.T) {
+	b := TestLocal(t)
+
+	TestLocalProvider(t, b, "test", applyFixtureSchema())
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	op.AutoApprove = true
+	defer configCleanup()
+	defer func() {
+		output := done(t)
+		if !strings.Contains(output.Stderr(), "execution halted") {
+			t.Fatal("expected 'execution halted', got:\n", output.All())
+		}
+	}()
+
+	ctx, cancel := context.WithCancel(context.Background())
+	testHookStopPlanApply = cancel
+	defer func() {
+		testHookStopPlanApply = nil
+	}()
+
+	run, err := b.Operation(ctx, op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+
+}
diff --git a/v1.5.7/internal/backend/local/backend_local.go b/v1.5.7/internal/backend/local/backend_local.go
new file mode 100644
index 0000000..9bfad4e
--- /dev/null
+++ b/v1.5.7/internal/backend/local/backend_local.go
@@ -0,0 +1,501 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package local
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// backend.Local implementation.
+func (b *Local) LocalRun(op *backend.Operation) (*backend.LocalRun, statemgr.Full, tfdiags.Diagnostics) {
+	// Make sure the type is invalid. We use this as a way to know not
+	// to ask for input/validate. We're modifying this through a pointer,
+	// so we're mutating an object that belongs to the caller here, which
+	// seems bad but we're preserving it for now until we have time to
+	// properly design this API, vs. just preserving whatever it currently
+	// happens to do.
+	op.Type = backend.OperationTypeInvalid
+
+	op.StateLocker = op.StateLocker.WithContext(context.Background())
+
+	lr, _, stateMgr, diags := b.localRun(op)
+	return lr, stateMgr, diags
+}
+
+func (b *Local) localRun(op *backend.Operation) (*backend.LocalRun, *configload.Snapshot, statemgr.Full, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// Get the latest state.
+	log.Printf("[TRACE] backend/local: requesting state manager for workspace %q", op.Workspace)
+	s, err := b.StateMgr(op.Workspace)
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("error loading state: %w", err))
+		return nil, nil, nil, diags
+	}
+	log.Printf("[TRACE] backend/local: requesting state lock for workspace %q", op.Workspace)
+	if diags := op.StateLocker.Lock(s, op.Type.String()); diags.HasErrors() {
+		return nil, nil, nil, diags
+	}
+
+	defer func() {
+		// If we're returning with errors, and thus not producing a valid
+		// context, we'll want to avoid leaving the workspace locked.
+		if diags.HasErrors() {
+			diags = diags.Append(op.StateLocker.Unlock())
+		}
+	}()
+
+	log.Printf("[TRACE] backend/local: reading remote state for workspace %q", op.Workspace)
+	if err := s.RefreshState(); err != nil {
+		diags = diags.Append(fmt.Errorf("error loading state: %w", err))
+		return nil, nil, nil, diags
+	}
+
+	ret := &backend.LocalRun{}
+
+	// Initialize our context options
+	var coreOpts terraform.ContextOpts
+	if v := b.ContextOpts; v != nil {
+		coreOpts = *v
+	}
+	coreOpts.UIInput = op.UIIn
+	coreOpts.Hooks = op.Hooks
+
+	var ctxDiags tfdiags.Diagnostics
+	var configSnap *configload.Snapshot
+	if op.PlanFile != nil {
+		var stateMeta *statemgr.SnapshotMeta
+		// If the statemgr implements our optional PersistentMeta interface then we'll
+		// additionally verify that the state snapshot in the plan file has
+		// consistent metadata, as an additional safety check.
+		if sm, ok := s.(statemgr.PersistentMeta); ok {
+			m := sm.StateSnapshotMeta()
+			stateMeta = &m
+		}
+		log.Printf("[TRACE] backend/local: populating backend.LocalRun from plan file")
+		ret, configSnap, ctxDiags = b.localRunForPlanFile(op, op.PlanFile, ret, &coreOpts, stateMeta)
+		if ctxDiags.HasErrors() {
+			diags = diags.Append(ctxDiags)
+			return nil, nil, nil, diags
+		}
+
+		// Write sources into the cache of the main loader so that they are
+		// available if we need to generate diagnostic message snippets.
+		op.ConfigLoader.ImportSourcesFromSnapshot(configSnap)
+	} else {
+		log.Printf("[TRACE] backend/local: populating backend.LocalRun for current working directory")
+		ret, configSnap, ctxDiags = b.localRunDirect(op, ret, &coreOpts, s)
+	}
+	diags = diags.Append(ctxDiags)
+	if diags.HasErrors() {
+		return nil, nil, nil, diags
+	}
+
+	// If we have an operation, then we automatically do the input/validate
+	// here since every option requires this.
+	if op.Type != backend.OperationTypeInvalid {
+		// If input asking is enabled, then do that
+		if op.PlanFile == nil && b.OpInput {
+			mode := terraform.InputModeProvider
+
+			log.Printf("[TRACE] backend/local: requesting interactive input, if necessary")
+			inputDiags := ret.Core.Input(ret.Config, mode)
+			diags = diags.Append(inputDiags)
+			if inputDiags.HasErrors() {
+				return nil, nil, nil, diags
+			}
+		}
+
+		// If validation is enabled, validate
+		if b.OpValidation {
+			log.Printf("[TRACE] backend/local: running validation operation")
+			validateDiags := ret.Core.Validate(ret.Config)
+			diags = diags.Append(validateDiags)
+		}
+	}
+
+	return ret, configSnap, s, diags
+}
+
+func (b *Local) localRunDirect(op *backend.Operation, run *backend.LocalRun, coreOpts *terraform.ContextOpts, s statemgr.Full) (*backend.LocalRun, *configload.Snapshot, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// Load the configuration using the caller-provided configuration loader.
+	config, configSnap, configDiags := op.ConfigLoader.LoadConfigWithSnapshot(op.ConfigDir)
+	diags = diags.Append(configDiags)
+	if configDiags.HasErrors() {
+		return nil, nil, diags
+	}
+	run.Config = config
+
+	if errs := config.VerifyDependencySelections(op.DependencyLocks); len(errs) > 0 {
+		var buf strings.Builder
+		for _, err := range errs {
+			fmt.Fprintf(&buf, "\n  - %s", err.Error())
+		}
+		var suggestion string
+		switch {
+		case op.DependencyLocks == nil:
+			// If we get here then it suggests that there's a caller that we
+			// didn't yet update to populate DependencyLocks, which is a bug.
+			suggestion = "This run has no dependency lock information provided at all, which is a bug in Terraform; please report it!"
+		case op.DependencyLocks.Empty():
+			suggestion = "To make the initial dependency selections that will initialize the dependency lock file, run:\n  terraform init"
+		default:
+			suggestion = "To update the locked dependency selections to match a changed configuration, run:\n  terraform init -upgrade"
+		}
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Inconsistent dependency lock file",
+			fmt.Sprintf(
+				"The following dependency selections recorded in the lock file are inconsistent with the current configuration:%s\n\n%s",
+				buf.String(), suggestion,
+			),
+		))
+	}
+
+	var rawVariables map[string]backend.UnparsedVariableValue
+	if op.AllowUnsetVariables {
+		// Rather than prompting for input, we'll just stub out the required
+		// but unset variables with unknown values to represent that they are
+		// placeholders for values the user would need to provide for other
+		// operations.
+		rawVariables = b.stubUnsetRequiredVariables(op.Variables, config.Module.Variables)
+	} else {
+		// If interactive input is enabled, we might gather some more variable
+		// values through interactive prompts.
+		// TODO: Need to route the operation context through into here, so that
+		// the interactive prompts can be sensitive to its timeouts/etc.
+		rawVariables = b.interactiveCollectVariables(context.TODO(), op.Variables, config.Module.Variables, op.UIIn)
+	}
+
+	variables, varDiags := backend.ParseVariableValues(rawVariables, config.Module.Variables)
+	diags = diags.Append(varDiags)
+	if diags.HasErrors() {
+		return nil, nil, diags
+	}
+
+	planOpts := &terraform.PlanOpts{
+		Mode:               op.PlanMode,
+		Targets:            op.Targets,
+		ForceReplace:       op.ForceReplace,
+		SetVariables:       variables,
+		SkipRefresh:        op.Type != backend.OperationTypeRefresh && !op.PlanRefresh,
+		GenerateConfigPath: op.GenerateConfigOut,
+	}
+	run.PlanOpts = planOpts
+
+	// For a "direct" local run, the input state is the most recently stored
+	// snapshot, from the previous run.
+	run.InputState = s.State()
+
+	tfCtx, moreDiags := terraform.NewContext(coreOpts)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		return nil, nil, diags
+	}
+	run.Core = tfCtx
+	return run, configSnap, diags
+}
+
+func (b *Local) localRunForPlanFile(op *backend.Operation, pf *planfile.Reader, run *backend.LocalRun, coreOpts *terraform.ContextOpts, currentStateMeta *statemgr.SnapshotMeta) (*backend.LocalRun, *configload.Snapshot, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	const errSummary = "Invalid plan file"
+
+	// A plan file has a snapshot of configuration embedded inside it, which
+	// is used instead of whatever configuration might be already present
+	// in the filesystem.
+	snap, err := pf.ReadConfigSnapshot()
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			errSummary,
+			fmt.Sprintf("Failed to read configuration snapshot from plan file: %s.", err),
+		))
+		return nil, snap, diags
+	}
+	loader := configload.NewLoaderFromSnapshot(snap)
+	config, configDiags := loader.LoadConfig(snap.Modules[""].Dir)
+	diags = diags.Append(configDiags)
+	if configDiags.HasErrors() {
+		return nil, snap, diags
+	}
+	run.Config = config
+
+	// NOTE: We're intentionally comparing the current locks with the
+	// configuration snapshot, rather than the lock snapshot in the plan file,
+	// because it's the current locks which dictate our plugin selections
+	// in coreOpts below. However, we'll also separately check that the
+	// plan file has identical locked plugins below, and thus we're effectively
+	// checking consistency with both here.
+	if errs := config.VerifyDependencySelections(op.DependencyLocks); len(errs) > 0 {
+		var buf strings.Builder
+		for _, err := range errs {
+			fmt.Fprintf(&buf, "\n  - %s", err.Error())
+		}
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Inconsistent dependency lock file",
+			fmt.Sprintf(
+				"The following dependency selections recorded in the lock file are inconsistent with the configuration in the saved plan:%s\n\nA saved plan can be applied only to the same configuration it was created from. Create a new plan from the updated configuration.",
+				buf.String(),
+			),
+		))
+	}
+
+	// This check is an important complement to the check above: the locked
+	// dependencies in the configuration must match the configuration, and
+	// the locked dependencies in the plan must match the locked dependencies
+	// in the configuration, and so transitively we ensure that the locked
+	// dependencies in the plan match the configuration too. However, this
+	// additionally catches any inconsistency between the two sets of locks
+	// even if they both happen to be valid per the current configuration,
+	// which is one of several ways we try to catch the mistake of applying
+	// a saved plan file in a different place than where we created it.
+	depLocksFromPlan, moreDiags := pf.ReadDependencyLocks()
+	diags = diags.Append(moreDiags)
+	if depLocksFromPlan != nil && !op.DependencyLocks.Equal(depLocksFromPlan) {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Inconsistent dependency lock file",
+			"The given plan file was created with a different set of external dependency selections than the current configuration. A saved plan can be applied only to the same configuration it was created from.\n\nCreate a new plan from the updated configuration.",
+		))
+	}
+
+	// A plan file also contains a snapshot of the prior state the changes
+	// are intended to apply to.
+	priorStateFile, err := pf.ReadStateFile()
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			errSummary,
+			fmt.Sprintf("Failed to read prior state snapshot from plan file: %s.", err),
+		))
+		return nil, snap, diags
+	}
+
+	if currentStateMeta != nil {
+		// If the caller sets this, we require that the stored prior state
+		// has the same metadata, which is an extra safety check that nothing
+		// has changed since the plan was created. (All of the "real-world"
+		// state manager implementations support this, but simpler test backends
+		// may not.)
+
+		// Because the plan always contains a state, even if it is empty, the
+		// first plan to be applied will have empty snapshot metadata. In this
+		// case we compare only the serial in order to provide a more correct
+		// error.
+		firstPlan := priorStateFile.Lineage == "" && priorStateFile.Serial == 0
+
+		switch {
+		case !firstPlan && priorStateFile.Lineage != currentStateMeta.Lineage:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Saved plan does not match the given state",
+				"The given plan file can not be applied because it was created from a different state lineage.",
+			))
+
+		case priorStateFile.Serial != currentStateMeta.Serial:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Saved plan is stale",
+				"The given plan file can no longer be applied because the state was changed by another operation after the plan was created.",
+			))
+		}
+	}
+	// When we're applying a saved plan, the input state is the "prior state"
+	// recorded in the plan, which incorporates the result of all of the
+	// refreshing we did while building the plan.
+	run.InputState = priorStateFile.State
+
+	plan, err := pf.ReadPlan()
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			errSummary,
+			fmt.Sprintf("Failed to read plan from plan file: %s.", err),
+		))
+		return nil, snap, diags
+	}
+	// When we're applying a saved plan, we populate Plan instead of PlanOpts,
+	// because a plan object incorporates the subset of data from PlanOps that
+	// we need to apply the plan.
+	run.Plan = plan
+
+	tfCtx, moreDiags := terraform.NewContext(coreOpts)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		return nil, nil, diags
+	}
+	run.Core = tfCtx
+	return run, snap, diags
+}
+
+// interactiveCollectVariables attempts to complete the given existing
+// map of variables by interactively prompting for any variables that are
+// declared as required but not yet present.
+//
+// If interactive input is disabled for this backend instance then this is
+// a no-op. If input is enabled but fails for some reason, the resulting
+// map will be incomplete. For these reasons, the caller must still validate
+// that the result is complete and valid.
+//
+// This function does not modify the map given in "existing", but may return
+// it unchanged if no modifications are required. If modifications are required,
+// the result is a new map with all of the elements from "existing" plus
+// additional elements as appropriate.
+//
+// Interactive prompting is a "best effort" thing for first-time user UX and
+// not something we expect folks to be relying on for routine use. Terraform
+// is primarily a non-interactive tool and so we prefer to report in error
+// messages that variables are not set rather than reporting that input failed:
+// the primary resolution to missing variables is to provide them by some other
+// means.
+func (b *Local) interactiveCollectVariables(ctx context.Context, existing map[string]backend.UnparsedVariableValue, vcs map[string]*configs.Variable, uiInput terraform.UIInput) map[string]backend.UnparsedVariableValue {
+	var needed []string
+	if b.OpInput && uiInput != nil {
+		for name, vc := range vcs {
+			if !vc.Required() {
+				continue // We only prompt for required variables
+			}
+			if _, exists := existing[name]; !exists {
+				needed = append(needed, name)
+			}
+		}
+	} else {
+		log.Print("[DEBUG] backend/local: Skipping interactive prompts for variables because input is disabled")
+	}
+	if len(needed) == 0 {
+		return existing
+	}
+
+	log.Printf("[DEBUG] backend/local: will prompt for input of unset required variables %s", needed)
+
+	// If we get here then we're planning to prompt for at least one additional
+	// variable's value.
+	sort.Strings(needed) // prompt in lexical order
+	ret := make(map[string]backend.UnparsedVariableValue, len(vcs))
+	for k, v := range existing {
+		ret[k] = v
+	}
+	for _, name := range needed {
+		vc := vcs[name]
+		rawValue, err := uiInput.Input(ctx, &terraform.InputOpts{
+			Id:          fmt.Sprintf("var.%s", name),
+			Query:       fmt.Sprintf("var.%s", name),
+			Description: vc.Description,
+			Secret:      vc.Sensitive,
+		})
+		if err != nil {
+			// Since interactive prompts are best-effort, we'll just continue
+			// here and let subsequent validation report this as a variable
+			// not specified.
+			log.Printf("[WARN] backend/local: Failed to request user input for variable %q: %s", name, err)
+			continue
+		}
+		ret[name] = unparsedInteractiveVariableValue{Name: name, RawValue: rawValue}
+	}
+	return ret
+}
+
+// stubUnsetVariables ensures that all required variables defined in the
+// configuration exist in the resulting map, by adding new elements as necessary.
+//
+// The stubbed value of any additions will be an unknown variable conforming
+// to the variable's configured type constraint, meaning that no particular
+// value is known and that one must be provided by the user in order to get
+// a complete result.
+//
+// Unset optional attributes (those with default values) will not be populated
+// by this function, under the assumption that a later step will handle those.
+// In this sense, stubUnsetRequiredVariables is essentially a non-interactive,
+// non-error-producing variant of interactiveCollectVariables that creates
+// placeholders for values the user would be prompted for interactively on
+// other operations.
+//
+// This function should be used only in situations where variables values
+// will not be directly used and the variables map is being constructed only
+// to produce a complete Terraform context for some ancillary functionality
+// like "terraform console", "terraform state ...", etc.
+//
+// This function is guaranteed not to modify the given map, but it may return
+// the given map unchanged if no additions are required. If additions are
+// required then the result will be a new map containing everything in the
+// given map plus additional elements.
+func (b *Local) stubUnsetRequiredVariables(existing map[string]backend.UnparsedVariableValue, vcs map[string]*configs.Variable) map[string]backend.UnparsedVariableValue {
+	var missing bool // Do we need to add anything?
+	for name, vc := range vcs {
+		if !vc.Required() {
+			continue // We only stub required variables
+		}
+		if _, exists := existing[name]; !exists {
+			missing = true
+		}
+	}
+	if !missing {
+		return existing
+	}
+
+	// If we get down here then there's at least one variable value to add.
+	ret := make(map[string]backend.UnparsedVariableValue, len(vcs))
+	for k, v := range existing {
+		ret[k] = v
+	}
+	for name, vc := range vcs {
+		if !vc.Required() {
+			continue
+		}
+		if _, exists := existing[name]; !exists {
+			ret[name] = unparsedUnknownVariableValue{Name: name, WantType: vc.Type}
+		}
+	}
+	return ret
+}
+
+type unparsedInteractiveVariableValue struct {
+	Name, RawValue string
+}
+
+var _ backend.UnparsedVariableValue = unparsedInteractiveVariableValue{}
+
+func (v unparsedInteractiveVariableValue) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	val, valDiags := mode.Parse(v.Name, v.RawValue)
+	diags = diags.Append(valDiags)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+	return &terraform.InputValue{
+		Value:      val,
+		SourceType: terraform.ValueFromInput,
+	}, diags
+}
+
+type unparsedUnknownVariableValue struct {
+	Name     string
+	WantType cty.Type
+}
+
+var _ backend.UnparsedVariableValue = unparsedUnknownVariableValue{}
+
+func (v unparsedUnknownVariableValue) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) {
+	return &terraform.InputValue{
+		Value:      cty.UnknownVal(v.WantType),
+		SourceType: terraform.ValueFromInput,
+	}, nil
+}
diff --git a/v1.5.7/internal/backend/local/backend_local_test.go b/v1.5.7/internal/backend/local/backend_local_test.go
new file mode 100644
index 0000000..e362cb9
--- /dev/null
+++ b/v1.5.7/internal/backend/local/backend_local_test.go
@@ -0,0 +1,242 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package local
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestLocalRun(t *testing.T) {
+	configDir := "./testdata/empty"
+	b := TestLocal(t)
+
+	_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
+	defer configCleanup()
+
+	streams, _ := terminal.StreamsForTesting(t)
+	view := views.NewView(streams)
+	stateLocker := clistate.NewLocker(0, views.NewStateLocker(arguments.ViewHuman, view))
+
+	op := &backend.Operation{
+		ConfigDir:    configDir,
+		ConfigLoader: configLoader,
+		Workspace:    backend.DefaultStateName,
+		StateLocker:  stateLocker,
+	}
+
+	_, _, diags := b.LocalRun(op)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err().Error())
+	}
+
+	// LocalRun() retains a lock on success
+	assertBackendStateLocked(t, b)
+}
+
+func TestLocalRun_error(t *testing.T) {
+	configDir := "./testdata/invalid"
+	b := TestLocal(t)
+
+	// This backend will return an error when asked to RefreshState, which
+	// should then cause LocalRun to return with the state unlocked.
+	b.Backend = backendWithStateStorageThatFailsRefresh{}
+
+	_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
+	defer configCleanup()
+
+	streams, _ := terminal.StreamsForTesting(t)
+	view := views.NewView(streams)
+	stateLocker := clistate.NewLocker(0, views.NewStateLocker(arguments.ViewHuman, view))
+
+	op := &backend.Operation{
+		ConfigDir:    configDir,
+		ConfigLoader: configLoader,
+		Workspace:    backend.DefaultStateName,
+		StateLocker:  stateLocker,
+	}
+
+	_, _, diags := b.LocalRun(op)
+	if !diags.HasErrors() {
+		t.Fatal("unexpected success")
+	}
+
+	// LocalRun() unlocks the state on failure
+	assertBackendStateUnlocked(t, b)
+}
+
+func TestLocalRun_stalePlan(t *testing.T) {
+	configDir := "./testdata/apply"
+	b := TestLocal(t)
+
+	_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
+	defer configCleanup()
+
+	// Write an empty state file with serial 3
+	sf, err := os.Create(b.StatePath)
+	if err != nil {
+		t.Fatalf("unexpected error creating state file %s: %s", b.StatePath, err)
+	}
+	if err := statefile.Write(statefile.New(states.NewState(), "boop", 3), sf); err != nil {
+		t.Fatalf("unexpected error writing state file: %s", err)
+	}
+
+	// Refresh the state
+	sm, err := b.StateMgr("")
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := sm.RefreshState(); err != nil {
+		t.Fatalf("unexpected error refreshing state: %s", err)
+	}
+
+	// Create a minimal plan which also has state file serial 2, so is stale
+	backendConfig := cty.ObjectVal(map[string]cty.Value{
+		"path":          cty.NullVal(cty.String),
+		"workspace_dir": cty.NullVal(cty.String),
+	})
+	backendConfigRaw, err := plans.NewDynamicValue(backendConfig, backendConfig.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	plan := &plans.Plan{
+		UIMode:  plans.NormalMode,
+		Changes: plans.NewChanges(),
+		Backend: plans.Backend{
+			Type:   "local",
+			Config: backendConfigRaw,
+		},
+		PrevRunState: states.NewState(),
+		PriorState:   states.NewState(),
+	}
+	prevStateFile := statefile.New(plan.PrevRunState, "boop", 1)
+	stateFile := statefile.New(plan.PriorState, "boop", 2)
+
+	// Roundtrip through serialization as expected by the operation
+	outDir := t.TempDir()
+	defer os.RemoveAll(outDir)
+	planPath := filepath.Join(outDir, "plan.tfplan")
+	planfileArgs := planfile.CreateArgs{
+		ConfigSnapshot:       configload.NewEmptySnapshot(),
+		PreviousRunStateFile: prevStateFile,
+		StateFile:            stateFile,
+		Plan:                 plan,
+	}
+	if err := planfile.Create(planPath, planfileArgs); err != nil {
+		t.Fatalf("unexpected error writing planfile: %s", err)
+	}
+	planFile, err := planfile.Open(planPath)
+	if err != nil {
+		t.Fatalf("unexpected error reading planfile: %s", err)
+	}
+
+	streams, _ := terminal.StreamsForTesting(t)
+	view := views.NewView(streams)
+	stateLocker := clistate.NewLocker(0, views.NewStateLocker(arguments.ViewHuman, view))
+
+	op := &backend.Operation{
+		ConfigDir:    configDir,
+		ConfigLoader: configLoader,
+		PlanFile:     planFile,
+		Workspace:    backend.DefaultStateName,
+		StateLocker:  stateLocker,
+	}
+
+	_, _, diags := b.LocalRun(op)
+	if !diags.HasErrors() {
+		t.Fatal("unexpected success")
+	}
+
+	// LocalRun() unlocks the state on failure
+	assertBackendStateUnlocked(t, b)
+}
+
+type backendWithStateStorageThatFailsRefresh struct {
+}
+
+var _ backend.Backend = backendWithStateStorageThatFailsRefresh{}
+
+func (b backendWithStateStorageThatFailsRefresh) StateMgr(workspace string) (statemgr.Full, error) {
+	return &stateStorageThatFailsRefresh{}, nil
+}
+
+func (b backendWithStateStorageThatFailsRefresh) ConfigSchema() *configschema.Block {
+	return &configschema.Block{}
+}
+
+func (b backendWithStateStorageThatFailsRefresh) PrepareConfig(in cty.Value) (cty.Value, tfdiags.Diagnostics) {
+	return in, nil
+}
+
+func (b backendWithStateStorageThatFailsRefresh) Configure(cty.Value) tfdiags.Diagnostics {
+	return nil
+}
+
+func (b backendWithStateStorageThatFailsRefresh) DeleteWorkspace(name string, force bool) error {
+	return fmt.Errorf("unimplemented")
+}
+
+func (b backendWithStateStorageThatFailsRefresh) Workspaces() ([]string, error) {
+	return []string{"default"}, nil
+}
+
+type stateStorageThatFailsRefresh struct {
+	locked bool
+}
+
+func (s *stateStorageThatFailsRefresh) Lock(info *statemgr.LockInfo) (string, error) {
+	if s.locked {
+		return "", fmt.Errorf("already locked")
+	}
+	s.locked = true
+	return "locked", nil
+}
+
+func (s *stateStorageThatFailsRefresh) Unlock(id string) error {
+	if !s.locked {
+		return fmt.Errorf("not locked")
+	}
+	s.locked = false
+	return nil
+}
+
+func (s *stateStorageThatFailsRefresh) State() *states.State {
+	return nil
+}
+
+func (s *stateStorageThatFailsRefresh) GetRootOutputValues() (map[string]*states.OutputValue, error) {
+	return nil, fmt.Errorf("unimplemented")
+}
+
+func (s *stateStorageThatFailsRefresh) WriteState(*states.State) error {
+	return fmt.Errorf("unimplemented")
+}
+
+func (s *stateStorageThatFailsRefresh) RefreshState() error {
+	return fmt.Errorf("intentionally failing for testing purposes")
+}
+
+func (s *stateStorageThatFailsRefresh) PersistState(schemas *terraform.Schemas) error {
+	return fmt.Errorf("unimplemented")
+}
diff --git a/v1.5.7/internal/backend/local/backend_plan.go b/v1.5.7/internal/backend/local/backend_plan.go
new file mode 100644
index 0000000..79ff402
--- /dev/null
+++ b/v1.5.7/internal/backend/local/backend_plan.go
@@ -0,0 +1,253 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package local
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/genconfig"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func (b *Local) opPlan(
+	stopCtx context.Context,
+	cancelCtx context.Context,
+	op *backend.Operation,
+	runningOp *backend.RunningOperation) {
+
+	log.Printf("[INFO] backend/local: starting Plan operation")
+
+	var diags tfdiags.Diagnostics
+
+	if op.PlanFile != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Can't re-plan a saved plan",
+			"The plan command was given a saved plan file as its input. This command generates "+
+				"a new plan, and so it requires a configuration directory as its argument.",
+		))
+		op.ReportResult(runningOp, diags)
+		return
+	}
+
+	// Local planning requires a config, unless we're planning to destroy.
+	if op.PlanMode != plans.DestroyMode && !op.HasConfig() {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"No configuration files",
+			"Plan requires configuration to be present. Planning without a configuration would "+
+				"mark everything for destruction, which is normally not what is desired. If you "+
+				"would like to destroy everything, run plan with the -destroy option. Otherwise, "+
+				"create a Terraform configuration file (.tf file) and try again.",
+		))
+		op.ReportResult(runningOp, diags)
+		return
+	}
+
+	if len(op.GenerateConfigOut) > 0 {
+		if op.PlanMode != plans.NormalMode {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid generate-config-out flag",
+				"Config can only be generated during a normal plan operation, and not during a refresh-only or destroy plan."))
+			op.ReportResult(runningOp, diags)
+			return
+		}
+
+		diags = diags.Append(genconfig.ValidateTargetFile(op.GenerateConfigOut))
+		if diags.HasErrors() {
+			op.ReportResult(runningOp, diags)
+			return
+		}
+	}
+
+	if b.ContextOpts == nil {
+		b.ContextOpts = new(terraform.ContextOpts)
+	}
+
+	// Get our context
+	lr, configSnap, opState, ctxDiags := b.localRun(op)
+	diags = diags.Append(ctxDiags)
+	if ctxDiags.HasErrors() {
+		op.ReportResult(runningOp, diags)
+		return
+	}
+	// the state was locked during succesfull context creation; unlock the state
+	// when the operation completes
+	defer func() {
+		diags := op.StateLocker.Unlock()
+		if diags.HasErrors() {
+			op.View.Diagnostics(diags)
+			runningOp.Result = backend.OperationFailure
+		}
+	}()
+
+	// Since planning doesn't immediately change the persisted state, the
+	// resulting state is always just the input state.
+	runningOp.State = lr.InputState
+
+	// Perform the plan in a goroutine so we can be interrupted
+	var plan *plans.Plan
+	var planDiags tfdiags.Diagnostics
+	doneCh := make(chan struct{})
+	go func() {
+		defer logging.PanicHandler()
+		defer close(doneCh)
+		log.Printf("[INFO] backend/local: plan calling Plan")
+		plan, planDiags = lr.Core.Plan(lr.Config, lr.InputState, lr.PlanOpts)
+	}()
+
+	if b.opWait(doneCh, stopCtx, cancelCtx, lr.Core, opState, op.View) {
+		// If we get in here then the operation was cancelled, which is always
+		// considered to be a failure.
+		log.Printf("[INFO] backend/local: plan operation was force-cancelled by interrupt")
+		runningOp.Result = backend.OperationFailure
+		return
+	}
+	log.Printf("[INFO] backend/local: plan operation completed")
+
+	// NOTE: We intentionally don't stop here on errors because we always want
+	// to try to present a partial plan report and, if the user chose to,
+	// generate a partial saved plan file for external analysis.
+	diags = diags.Append(planDiags)
+
+	// Even if there are errors we need to handle anything that may be
+	// contained within the plan, so only exit if there is no data at all.
+	if plan == nil {
+		runningOp.PlanEmpty = true
+		op.ReportResult(runningOp, diags)
+		return
+	}
+
+	// Record whether this plan includes any side-effects that could be applied.
+	runningOp.PlanEmpty = !plan.CanApply()
+
+	// Save the plan to disk
+	if path := op.PlanOutPath; path != "" {
+		if op.PlanOutBackend == nil {
+			// This is always a bug in the operation caller; it's not valid
+			// to set PlanOutPath without also setting PlanOutBackend.
+			diags = diags.Append(fmt.Errorf(
+				"PlanOutPath set without also setting PlanOutBackend (this is a bug in Terraform)"),
+			)
+			op.ReportResult(runningOp, diags)
+			return
+		}
+		plan.Backend = *op.PlanOutBackend
+
+		// We may have updated the state in the refresh step above, but we
+		// will freeze that updated state in the plan file for now and
+		// only write it if this plan is subsequently applied.
+		plannedStateFile := statemgr.PlannedStateUpdate(opState, plan.PriorState)
+
+		// We also include a file containing the state as it existed before
+		// we took any action at all, but this one isn't intended to ever
+		// be saved to the backend (an equivalent snapshot should already be
+		// there) and so we just use a stub state file header in this case.
+		// NOTE: This won't be exactly identical to the latest state snapshot
+		// in the backend because it's still been subject to state upgrading
+		// to make it consumable by the current Terraform version, and
+		// intentionally doesn't preserve the header info.
+		prevStateFile := &statefile.File{
+			State: plan.PrevRunState,
+		}
+
+		log.Printf("[INFO] backend/local: writing plan output to: %s", path)
+		err := planfile.Create(path, planfile.CreateArgs{
+			ConfigSnapshot:       configSnap,
+			PreviousRunStateFile: prevStateFile,
+			StateFile:            plannedStateFile,
+			Plan:                 plan,
+			DependencyLocks:      op.DependencyLocks,
+		})
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to write plan file",
+				fmt.Sprintf("The plan file could not be written: %s.", err),
+			))
+			op.ReportResult(runningOp, diags)
+			return
+		}
+	}
+
+	// Render the plan, if we produced one.
+	// (This might potentially be a partial plan with Errored set to true)
+	schemas, moreDiags := lr.Core.Schemas(lr.Config, lr.InputState)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		op.ReportResult(runningOp, diags)
+		return
+	}
+
+	// Write out any generated config, before we render the plan.
+	wroteConfig, moreDiags := maybeWriteGeneratedConfig(plan, op.GenerateConfigOut)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		op.ReportResult(runningOp, diags)
+		return
+	}
+
+	op.View.Plan(plan, schemas)
+
+	// If we've accumulated any diagnostics along the way then we'll show them
+	// here just before we show the summary and next steps. This can potentially
+	// include errors, because we intentionally try to show a partial plan
+	// above even if Terraform Core encountered an error partway through
+	// creating it.
+	op.ReportResult(runningOp, diags)
+
+	if !runningOp.PlanEmpty {
+		if wroteConfig {
+			op.View.PlanNextStep(op.PlanOutPath, op.GenerateConfigOut)
+		} else {
+			op.View.PlanNextStep(op.PlanOutPath, "")
+		}
+	}
+}
+
+func maybeWriteGeneratedConfig(plan *plans.Plan, out string) (wroteConfig bool, diags tfdiags.Diagnostics) {
+	if genconfig.ShouldWriteConfig(out) {
+		diags := genconfig.ValidateTargetFile(out)
+		if diags.HasErrors() {
+			return false, diags
+		}
+
+		var writer io.Writer
+		for _, c := range plan.Changes.Resources {
+			change := genconfig.Change{
+				Addr:            c.Addr.String(),
+				GeneratedConfig: c.GeneratedConfig,
+			}
+			if c.Importing != nil {
+				change.ImportID = c.Importing.ID
+			}
+
+			var moreDiags tfdiags.Diagnostics
+			writer, wroteConfig, moreDiags = change.MaybeWriteConfig(writer, out)
+			if moreDiags.HasErrors() {
+				return false, diags.Append(moreDiags)
+			}
+		}
+	}
+
+	if wroteConfig {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Warning,
+			"Config generation is experimental",
+			"Generating configuration during import is currently experimental, and the generated configuration format may change in future versions."))
+	}
+
+	return wroteConfig, diags
+}
diff --git a/v1.5.7/internal/backend/local/backend_plan_test.go b/v1.5.7/internal/backend/local/backend_plan_test.go
new file mode 100644
index 0000000..ee213df
--- /dev/null
+++ b/v1.5.7/internal/backend/local/backend_plan_test.go
@@ -0,0 +1,909 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package local
+
+import (
+	"context"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestLocal_planBasic(t *testing.T) {
+	b := TestLocal(t)
+	p := TestLocalProvider(t, b, "test", planFixtureSchema())
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	op.PlanRefresh = true
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("plan operation failed")
+	}
+
+	if !p.PlanResourceChangeCalled {
+		t.Fatal("PlanResourceChange should be called")
+	}
+
+	// the backend should be unlocked after a run
+	assertBackendStateUnlocked(t, b)
+
+	if errOutput := done(t).Stderr(); errOutput != "" {
+		t.Fatalf("unexpected error output:\n%s", errOutput)
+	}
+}
+
+func TestLocal_planInAutomation(t *testing.T) {
+	b := TestLocal(t)
+	TestLocalProvider(t, b, "test", planFixtureSchema())
+
+	const msg = `You didn't use the -out option`
+
+	// When we're "in automation" we omit certain text from the plan output.
+	// However, the responsibility for this omission is in the view, so here we
+	// test for its presence while the "in automation" setting is false, to
+	// validate that we are calling the correct view method.
+	//
+	// Ideally this test would be replaced by a call-logging mock view, but
+	// that's future work.
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	op.PlanRefresh = true
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("plan operation failed")
+	}
+
+	if output := done(t).Stdout(); !strings.Contains(output, msg) {
+		t.Fatalf("missing next-steps message when not in automation\nwant: %s\noutput:\n%s", msg, output)
+	}
+}
+
+func TestLocal_planNoConfig(t *testing.T) {
+	b := TestLocal(t)
+	TestLocalProvider(t, b, "test", &terraform.ProviderSchema{})
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/empty")
+	defer configCleanup()
+	op.PlanRefresh = true
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+
+	output := done(t)
+
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("plan operation succeeded; want failure")
+	}
+
+	if stderr := output.Stderr(); !strings.Contains(stderr, "No configuration files") {
+		t.Fatalf("bad: %s", stderr)
+	}
+
+	// the backend should be unlocked after a run
+	assertBackendStateUnlocked(t, b)
+}
+
+// This test validates the state lacking behavior when the inner call to
+// Context() fails
+func TestLocal_plan_context_error(t *testing.T) {
+	b := TestLocal(t)
+
+	// This is an intentionally-invalid value to make terraform.NewContext fail
+	// when b.Operation calls it.
+	// NOTE: This test was originally using a provider initialization failure
+	// as its forced error condition, but terraform.NewContext is no longer
+	// responsible for checking that. Invalid parallelism is the last situation
+	// where terraform.NewContext can return error diagnostics, and arguably
+	// we should be validating this argument at the UI layer anyway, so perhaps
+	// in future we'll make terraform.NewContext never return errors and then
+	// this test will become redundant, because its purpose is specifically
+	// to test that we properly unlock the state if terraform.NewContext
+	// returns an error.
+	if b.ContextOpts == nil {
+		b.ContextOpts = &terraform.ContextOpts{}
+	}
+	b.ContextOpts.Parallelism = -1
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+
+	// we coerce a failure in Context() by omitting the provider schema
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationFailure {
+		t.Fatalf("plan operation succeeded")
+	}
+
+	// the backend should be unlocked after a run
+	assertBackendStateUnlocked(t, b)
+
+	if got, want := done(t).Stderr(), "Error: Invalid parallelism value"; !strings.Contains(got, want) {
+		t.Fatalf("unexpected error output:\n%s\nwant: %s", got, want)
+	}
+}
+
+func TestLocal_planOutputsChanged(t *testing.T) {
+	b := TestLocal(t)
+	testStateFile(t, b.StatePath, states.BuildState(func(ss *states.SyncState) {
+		ss.SetOutputValue(addrs.AbsOutputValue{
+			Module:      addrs.RootModuleInstance,
+			OutputValue: addrs.OutputValue{Name: "changed"},
+		}, cty.StringVal("before"), false)
+		ss.SetOutputValue(addrs.AbsOutputValue{
+			Module:      addrs.RootModuleInstance,
+			OutputValue: addrs.OutputValue{Name: "sensitive_before"},
+		}, cty.StringVal("before"), true)
+		ss.SetOutputValue(addrs.AbsOutputValue{
+			Module:      addrs.RootModuleInstance,
+			OutputValue: addrs.OutputValue{Name: "sensitive_after"},
+		}, cty.StringVal("before"), false)
+		ss.SetOutputValue(addrs.AbsOutputValue{
+			Module:      addrs.RootModuleInstance,
+			OutputValue: addrs.OutputValue{Name: "removed"}, // not present in the config fixture
+		}, cty.StringVal("before"), false)
+		ss.SetOutputValue(addrs.AbsOutputValue{
+			Module:      addrs.RootModuleInstance,
+			OutputValue: addrs.OutputValue{Name: "unchanged"},
+		}, cty.StringVal("before"), false)
+		// NOTE: This isn't currently testing the situation where the new
+		// value of an output is unknown, because to do that requires there to
+		// be at least one managed resource Create action in the plan and that
+		// would defeat the point of this test, which is to ensure that a
+		// plan containing only output changes is considered "non-empty".
+		// For now we're not too worried about testing the "new value is
+		// unknown" situation because that's already common for printing out
+		// resource changes and we already have many tests for that.
+	}))
+	outDir := t.TempDir()
+	defer os.RemoveAll(outDir)
+	planPath := filepath.Join(outDir, "plan.tfplan")
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-outputs-changed")
+	defer configCleanup()
+	op.PlanRefresh = true
+	op.PlanOutPath = planPath
+	cfg := cty.ObjectVal(map[string]cty.Value{
+		"path": cty.StringVal(b.StatePath),
+	})
+	cfgRaw, err := plans.NewDynamicValue(cfg, cfg.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	op.PlanOutBackend = &plans.Backend{
+		// Just a placeholder so that we can generate a valid plan file.
+		Type:   "local",
+		Config: cfgRaw,
+	}
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("plan operation failed")
+	}
+	if run.PlanEmpty {
+		t.Error("plan should not be empty")
+	}
+
+	expectedOutput := strings.TrimSpace(`
+Changes to Outputs:
+  + added            = "after"
+  ~ changed          = "before" -> "after"
+  - removed          = "before" -> null
+  ~ sensitive_after  = (sensitive value)
+  ~ sensitive_before = (sensitive value)
+
+You can apply this plan to save these new output values to the Terraform
+state, without changing any real infrastructure.
+`)
+
+	if output := done(t).Stdout(); !strings.Contains(output, expectedOutput) {
+		t.Errorf("Unexpected output:\n%s\n\nwant output containing:\n%s", output, expectedOutput)
+	}
+}
+
+// Module outputs should not cause the plan to be rendered
+func TestLocal_planModuleOutputsChanged(t *testing.T) {
+	b := TestLocal(t)
+	testStateFile(t, b.StatePath, states.BuildState(func(ss *states.SyncState) {
+		ss.SetOutputValue(addrs.AbsOutputValue{
+			Module:      addrs.RootModuleInstance.Child("mod", addrs.NoKey),
+			OutputValue: addrs.OutputValue{Name: "changed"},
+		}, cty.StringVal("before"), false)
+	}))
+	outDir := t.TempDir()
+	defer os.RemoveAll(outDir)
+	planPath := filepath.Join(outDir, "plan.tfplan")
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-module-outputs-changed")
+	defer configCleanup()
+	op.PlanRefresh = true
+	op.PlanOutPath = planPath
+	cfg := cty.ObjectVal(map[string]cty.Value{
+		"path": cty.StringVal(b.StatePath),
+	})
+	cfgRaw, err := plans.NewDynamicValue(cfg, cfg.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	op.PlanOutBackend = &plans.Backend{
+		Type:   "local",
+		Config: cfgRaw,
+	}
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("plan operation failed")
+	}
+	if !run.PlanEmpty {
+		t.Fatal("plan should be empty")
+	}
+
+	expectedOutput := strings.TrimSpace(`
+No changes. Your infrastructure matches the configuration.
+`)
+	if output := done(t).Stdout(); !strings.Contains(output, expectedOutput) {
+		t.Fatalf("Unexpected output:\n%s\n\nwant output containing:\n%s", output, expectedOutput)
+	}
+}
+
+func TestLocal_planTainted(t *testing.T) {
+	b := TestLocal(t)
+	p := TestLocalProvider(t, b, "test", planFixtureSchema())
+	testStateFile(t, b.StatePath, testPlanState_tainted())
+	outDir := t.TempDir()
+	planPath := filepath.Join(outDir, "plan.tfplan")
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	op.PlanRefresh = true
+	op.PlanOutPath = planPath
+	cfg := cty.ObjectVal(map[string]cty.Value{
+		"path": cty.StringVal(b.StatePath),
+	})
+	cfgRaw, err := plans.NewDynamicValue(cfg, cfg.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	op.PlanOutBackend = &plans.Backend{
+		// Just a placeholder so that we can generate a valid plan file.
+		Type:   "local",
+		Config: cfgRaw,
+	}
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("plan operation failed")
+	}
+	if !p.ReadResourceCalled {
+		t.Fatal("ReadResource should be called")
+	}
+	if run.PlanEmpty {
+		t.Fatal("plan should not be empty")
+	}
+
+	expectedOutput := `Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+-/+ destroy and then create replacement
+
+Terraform will perform the following actions:
+
+  # test_instance.foo is tainted, so must be replaced
+-/+ resource "test_instance" "foo" {
+        # (1 unchanged attribute hidden)
+
+        # (1 unchanged block hidden)
+    }
+
+Plan: 1 to add, 0 to change, 1 to destroy.`
+	if output := done(t).Stdout(); !strings.Contains(output, expectedOutput) {
+		t.Fatalf("Unexpected output\ngot\n%s\n\nwant:\n%s", output, expectedOutput)
+	}
+}
+
+func TestLocal_planDeposedOnly(t *testing.T) {
+	b := TestLocal(t)
+	p := TestLocalProvider(t, b, "test", planFixtureSchema())
+	testStateFile(t, b.StatePath, states.BuildState(func(ss *states.SyncState) {
+		ss.SetResourceInstanceDeposed(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			states.DeposedKey("00000000"),
+			&states.ResourceInstanceObjectSrc{
+				Status: states.ObjectReady,
+				AttrsJSON: []byte(`{
+				"ami": "bar",
+				"network_interface": [{
+					"device_index": 0,
+					"description": "Main network interface"
+				}]
+			}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	}))
+	outDir := t.TempDir()
+	planPath := filepath.Join(outDir, "plan.tfplan")
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	op.PlanRefresh = true
+	op.PlanOutPath = planPath
+	cfg := cty.ObjectVal(map[string]cty.Value{
+		"path": cty.StringVal(b.StatePath),
+	})
+	cfgRaw, err := plans.NewDynamicValue(cfg, cfg.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	op.PlanOutBackend = &plans.Backend{
+		// Just a placeholder so that we can generate a valid plan file.
+		Type:   "local",
+		Config: cfgRaw,
+	}
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("plan operation failed")
+	}
+	if !p.ReadResourceCalled {
+		t.Fatal("ReadResource should've been called to refresh the deposed object")
+	}
+	if run.PlanEmpty {
+		t.Fatal("plan should not be empty")
+	}
+
+	// The deposed object and the current object are distinct, so our
+	// plan includes separate actions for each of them. This strange situation
+	// is not common: it should arise only if Terraform fails during
+	// a create-before-destroy when the create hasn't completed yet but
+	// in a severe way that prevents the previous object from being restored
+	// as "current".
+	//
+	// However, that situation was more common in some earlier Terraform
+	// versions where deposed objects were not managed properly, so this
+	// can arise when upgrading from an older version with deposed objects
+	// already in the state.
+	//
+	// This is one of the few cases where we expose the idea of "deposed" in
+	// the UI, including the user-unfriendly "deposed key" (00000000 in this
+	// case) just so that users can correlate this with what they might
+	// see in `terraform show` and in the subsequent apply output, because
+	// it's also possible for there to be _multiple_ deposed objects, in the
+	// unlikely event that create_before_destroy _keeps_ crashing across
+	// subsequent runs.
+	expectedOutput := `Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+  - destroy
+
+Terraform will perform the following actions:
+
+  # test_instance.foo will be created
+  + resource "test_instance" "foo" {
+      + ami = "bar"
+
+      + network_interface {
+          + description  = "Main network interface"
+          + device_index = 0
+        }
+    }
+
+  # test_instance.foo (deposed object 00000000) will be destroyed
+  # (left over from a partially-failed replacement of this instance)
+  - resource "test_instance" "foo" {
+      - ami = "bar" -> null
+
+      - network_interface {
+          - description  = "Main network interface" -> null
+          - device_index = 0 -> null
+        }
+    }
+
+Plan: 1 to add, 0 to change, 1 to destroy.`
+	if output := done(t).Stdout(); !strings.Contains(output, expectedOutput) {
+		t.Fatalf("Unexpected output:\n%s", output)
+	}
+}
+
+func TestLocal_planTainted_createBeforeDestroy(t *testing.T) {
+	b := TestLocal(t)
+
+	p := TestLocalProvider(t, b, "test", planFixtureSchema())
+	testStateFile(t, b.StatePath, testPlanState_tainted())
+	outDir := t.TempDir()
+	planPath := filepath.Join(outDir, "plan.tfplan")
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-cbd")
+	defer configCleanup()
+	op.PlanRefresh = true
+	op.PlanOutPath = planPath
+	cfg := cty.ObjectVal(map[string]cty.Value{
+		"path": cty.StringVal(b.StatePath),
+	})
+	cfgRaw, err := plans.NewDynamicValue(cfg, cfg.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	op.PlanOutBackend = &plans.Backend{
+		// Just a placeholder so that we can generate a valid plan file.
+		Type:   "local",
+		Config: cfgRaw,
+	}
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("plan operation failed")
+	}
+	if !p.ReadResourceCalled {
+		t.Fatal("ReadResource should be called")
+	}
+	if run.PlanEmpty {
+		t.Fatal("plan should not be empty")
+	}
+
+	expectedOutput := `Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
++/- create replacement and then destroy
+
+Terraform will perform the following actions:
+
+  # test_instance.foo is tainted, so must be replaced
++/- resource "test_instance" "foo" {
+        # (1 unchanged attribute hidden)
+
+        # (1 unchanged block hidden)
+    }
+
+Plan: 1 to add, 0 to change, 1 to destroy.`
+	if output := done(t).Stdout(); !strings.Contains(output, expectedOutput) {
+		t.Fatalf("Unexpected output:\n%s", output)
+	}
+}
+
+func TestLocal_planRefreshFalse(t *testing.T) {
+	b := TestLocal(t)
+
+	p := TestLocalProvider(t, b, "test", planFixtureSchema())
+	testStateFile(t, b.StatePath, testPlanState())
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("plan operation failed")
+	}
+
+	if p.ReadResourceCalled {
+		t.Fatal("ReadResource should not be called")
+	}
+
+	if !run.PlanEmpty {
+		t.Fatal("plan should be empty")
+	}
+
+	if errOutput := done(t).Stderr(); errOutput != "" {
+		t.Fatalf("unexpected error output:\n%s", errOutput)
+	}
+}
+
+func TestLocal_planDestroy(t *testing.T) {
+	b := TestLocal(t)
+
+	TestLocalProvider(t, b, "test", planFixtureSchema())
+	testStateFile(t, b.StatePath, testPlanState())
+
+	outDir := t.TempDir()
+	planPath := filepath.Join(outDir, "plan.tfplan")
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	op.PlanMode = plans.DestroyMode
+	op.PlanRefresh = true
+	op.PlanOutPath = planPath
+	cfg := cty.ObjectVal(map[string]cty.Value{
+		"path": cty.StringVal(b.StatePath),
+	})
+	cfgRaw, err := plans.NewDynamicValue(cfg, cfg.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	op.PlanOutBackend = &plans.Backend{
+		// Just a placeholder so that we can generate a valid plan file.
+		Type:   "local",
+		Config: cfgRaw,
+	}
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("plan operation failed")
+	}
+
+	if run.PlanEmpty {
+		t.Fatal("plan should not be empty")
+	}
+
+	plan := testReadPlan(t, planPath)
+	for _, r := range plan.Changes.Resources {
+		if r.Action.String() != "Delete" {
+			t.Fatalf("bad: %#v", r.Action.String())
+		}
+	}
+
+	if errOutput := done(t).Stderr(); errOutput != "" {
+		t.Fatalf("unexpected error output:\n%s", errOutput)
+	}
+}
+
+func TestLocal_planDestroy_withDataSources(t *testing.T) {
+	b := TestLocal(t)
+
+	TestLocalProvider(t, b, "test", planFixtureSchema())
+	testStateFile(t, b.StatePath, testPlanState_withDataSource())
+
+	outDir := t.TempDir()
+	planPath := filepath.Join(outDir, "plan.tfplan")
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/destroy-with-ds")
+	defer configCleanup()
+	op.PlanMode = plans.DestroyMode
+	op.PlanRefresh = true
+	op.PlanOutPath = planPath
+	cfg := cty.ObjectVal(map[string]cty.Value{
+		"path": cty.StringVal(b.StatePath),
+	})
+	cfgRaw, err := plans.NewDynamicValue(cfg, cfg.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	op.PlanOutBackend = &plans.Backend{
+		// Just a placeholder so that we can generate a valid plan file.
+		Type:   "local",
+		Config: cfgRaw,
+	}
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("plan operation failed")
+	}
+
+	if run.PlanEmpty {
+		t.Fatal("plan should not be empty")
+	}
+
+	// Data source should still exist in the the plan file
+	plan := testReadPlan(t, planPath)
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatalf("Expected exactly 1 resource for destruction, %d given: %q",
+			len(plan.Changes.Resources), getAddrs(plan.Changes.Resources))
+	}
+
+	// Data source should not be rendered in the output
+	expectedOutput := `Terraform will perform the following actions:
+
+  # test_instance.foo[0] will be destroyed
+  - resource "test_instance" "foo" {
+      - ami = "bar" -> null
+
+      - network_interface {
+          - description  = "Main network interface" -> null
+          - device_index = 0 -> null
+        }
+    }
+
+Plan: 0 to add, 0 to change, 1 to destroy.`
+
+	if output := done(t).Stdout(); !strings.Contains(output, expectedOutput) {
+		t.Fatalf("Unexpected output:\n%s", output)
+	}
+}
+
+func getAddrs(resources []*plans.ResourceInstanceChangeSrc) []string {
+	addrs := make([]string, len(resources))
+	for i, r := range resources {
+		addrs[i] = r.Addr.String()
+	}
+	return addrs
+}
+
+func TestLocal_planOutPathNoChange(t *testing.T) {
+	b := TestLocal(t)
+	TestLocalProvider(t, b, "test", planFixtureSchema())
+	testStateFile(t, b.StatePath, testPlanState())
+
+	outDir := t.TempDir()
+	planPath := filepath.Join(outDir, "plan.tfplan")
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	op.PlanOutPath = planPath
+	cfg := cty.ObjectVal(map[string]cty.Value{
+		"path": cty.StringVal(b.StatePath),
+	})
+	cfgRaw, err := plans.NewDynamicValue(cfg, cfg.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	op.PlanOutBackend = &plans.Backend{
+		// Just a placeholder so that we can generate a valid plan file.
+		Type:   "local",
+		Config: cfgRaw,
+	}
+	op.PlanRefresh = true
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("plan operation failed")
+	}
+
+	plan := testReadPlan(t, planPath)
+
+	if !plan.Changes.Empty() {
+		t.Fatalf("expected empty plan to be written")
+	}
+
+	if errOutput := done(t).Stderr(); errOutput != "" {
+		t.Fatalf("unexpected error output:\n%s", errOutput)
+	}
+}
+
+func testOperationPlan(t *testing.T, configDir string) (*backend.Operation, func(), func(*testing.T) *terminal.TestOutput) {
+	t.Helper()
+
+	_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams))
+
+	// Many of our tests use an overridden "test" provider that's just in-memory
+	// inside the test process, not a separate plugin on disk.
+	depLocks := depsfile.NewLocks()
+	depLocks.SetProviderOverridden(addrs.MustParseProviderSourceString("registry.terraform.io/hashicorp/test"))
+
+	return &backend.Operation{
+		Type:            backend.OperationTypePlan,
+		ConfigDir:       configDir,
+		ConfigLoader:    configLoader,
+		StateLocker:     clistate.NewNoopLocker(),
+		View:            view,
+		DependencyLocks: depLocks,
+	}, configCleanup, done
+}
+
+// testPlanState is just a common state that we use for testing plan.
+func testPlanState() *states.State {
+	state := states.NewState()
+	rootModule := state.RootModule()
+	rootModule.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: "foo",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status: states.ObjectReady,
+			AttrsJSON: []byte(`{
+				"ami": "bar",
+				"network_interface": [{
+					"device_index": 0,
+					"description": "Main network interface"
+				}]
+			}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	return state
+}
+
+func testPlanState_withDataSource() *states.State {
+	state := states.NewState()
+	rootModule := state.RootModule()
+	rootModule.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: "foo",
+		}.Instance(addrs.IntKey(0)),
+		&states.ResourceInstanceObjectSrc{
+			Status: states.ObjectReady,
+			AttrsJSON: []byte(`{
+				"ami": "bar",
+				"network_interface": [{
+					"device_index": 0,
+					"description": "Main network interface"
+				}]
+			}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	rootModule.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.DataResourceMode,
+			Type: "test_ds",
+			Name: "bar",
+		}.Instance(addrs.IntKey(0)),
+		&states.ResourceInstanceObjectSrc{
+			Status: states.ObjectReady,
+			AttrsJSON: []byte(`{
+				"filter": "foo"
+			}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	return state
+}
+
+func testPlanState_tainted() *states.State {
+	state := states.NewState()
+	rootModule := state.RootModule()
+	rootModule.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: "foo",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status: states.ObjectTainted,
+			AttrsJSON: []byte(`{
+				"ami": "bar",
+				"network_interface": [{
+					"device_index": 0,
+					"description": "Main network interface"
+				}]
+			}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	return state
+}
+
+func testReadPlan(t *testing.T, path string) *plans.Plan {
+	t.Helper()
+
+	p, err := planfile.Open(path)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer p.Close()
+
+	plan, err := p.ReadPlan()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	return plan
+}
+
+// planFixtureSchema returns a schema suitable for processing the
+// configuration in testdata/plan . This schema should be
+// assigned to a mock provider named "test".
+func planFixtureSchema() *terraform.ProviderSchema {
+	return &terraform.ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"ami": {Type: cty.String, Optional: true},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"network_interface": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"device_index": {Type: cty.Number, Optional: true},
+								"description":  {Type: cty.String, Optional: true},
+							},
+						},
+					},
+				},
+			},
+		},
+		DataSources: map[string]*configschema.Block{
+			"test_ds": {
+				Attributes: map[string]*configschema.Attribute{
+					"filter": {Type: cty.String, Required: true},
+				},
+			},
+		},
+	}
+}
+
+func TestLocal_invalidOptions(t *testing.T) {
+	b := TestLocal(t)
+	TestLocalProvider(t, b, "test", planFixtureSchema())
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	op.PlanRefresh = true
+	op.PlanMode = plans.RefreshOnlyMode
+	op.ForceReplace = []addrs.AbsResourceInstance{mustResourceInstanceAddr("test_instance.foo")}
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatalf("plan operation failed")
+	}
+
+	if errOutput := done(t).Stderr(); errOutput == "" {
+		t.Fatal("expected error output")
+	}
+}
diff --git a/v1.5.7/internal/backend/local/backend_refresh.go b/v1.5.7/internal/backend/local/backend_refresh.go
new file mode 100644
index 0000000..fa4fd16
--- /dev/null
+++ b/v1.5.7/internal/backend/local/backend_refresh.go
@@ -0,0 +1,119 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package local
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"os"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func (b *Local) opRefresh(
+	stopCtx context.Context,
+	cancelCtx context.Context,
+	op *backend.Operation,
+	runningOp *backend.RunningOperation) {
+
+	var diags tfdiags.Diagnostics
+
+	// Check if our state exists if we're performing a refresh operation. We
+	// only do this if we're managing state with this backend.
+	if b.Backend == nil {
+		if _, err := os.Stat(b.StatePath); err != nil {
+			if os.IsNotExist(err) {
+				err = nil
+			}
+
+			if err != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Cannot read state file",
+					fmt.Sprintf("Failed to read %s: %s", b.StatePath, err),
+				))
+				op.ReportResult(runningOp, diags)
+				return
+			}
+		}
+	}
+
+	// Refresh now happens via a plan, so we need to ensure this is enabled
+	op.PlanRefresh = true
+
+	// Get our context
+	lr, _, opState, contextDiags := b.localRun(op)
+	diags = diags.Append(contextDiags)
+	if contextDiags.HasErrors() {
+		op.ReportResult(runningOp, diags)
+		return
+	}
+
+	// the state was locked during successful context creation; unlock the state
+	// when the operation completes
+	defer func() {
+		diags := op.StateLocker.Unlock()
+		if diags.HasErrors() {
+			op.View.Diagnostics(diags)
+			runningOp.Result = backend.OperationFailure
+		}
+	}()
+
+	// If we succeed then we'll overwrite this with the resulting state below,
+	// but otherwise the resulting state is just the input state.
+	runningOp.State = lr.InputState
+	if !runningOp.State.HasManagedResourceInstanceObjects() {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Warning,
+			"Empty or non-existent state",
+			"There are currently no remote objects tracked in the state, so there is nothing to refresh.",
+		))
+	}
+
+	// get schemas before writing state
+	schemas, moreDiags := lr.Core.Schemas(lr.Config, lr.InputState)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		op.ReportResult(runningOp, diags)
+		return
+	}
+
+	// Perform the refresh in a goroutine so we can be interrupted
+	var newState *states.State
+	var refreshDiags tfdiags.Diagnostics
+	doneCh := make(chan struct{})
+	go func() {
+		defer logging.PanicHandler()
+		defer close(doneCh)
+		newState, refreshDiags = lr.Core.Refresh(lr.Config, lr.InputState, lr.PlanOpts)
+		log.Printf("[INFO] backend/local: refresh calling Refresh")
+	}()
+
+	if b.opWait(doneCh, stopCtx, cancelCtx, lr.Core, opState, op.View) {
+		return
+	}
+
+	// Write the resulting state to the running op
+	runningOp.State = newState
+	diags = diags.Append(refreshDiags)
+	if refreshDiags.HasErrors() {
+		op.ReportResult(runningOp, diags)
+		return
+	}
+
+	err := statemgr.WriteAndPersist(opState, newState, schemas)
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("failed to write state: %w", err))
+		op.ReportResult(runningOp, diags)
+		return
+	}
+
+	// Show any remaining warnings before exiting
+	op.ReportResult(runningOp, diags)
+}
diff --git a/v1.5.7/internal/backend/local/backend_refresh_test.go b/v1.5.7/internal/backend/local/backend_refresh_test.go
new file mode 100644
index 0000000..eaf7e7d
--- /dev/null
+++ b/v1.5.7/internal/backend/local/backend_refresh_test.go
@@ -0,0 +1,311 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package local
+
+import (
+	"context"
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestLocal_refresh(t *testing.T) {
+	b := TestLocal(t)
+
+	p := TestLocalProvider(t, b, "test", refreshFixtureSchema())
+	testStateFile(t, b.StatePath, testRefreshState())
+
+	p.ReadResourceFn = nil
+	p.ReadResourceResponse = &providers.ReadResourceResponse{NewState: cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("yes"),
+	})}
+
+	op, configCleanup, done := testOperationRefresh(t, "./testdata/refresh")
+	defer configCleanup()
+	defer done(t)
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+
+	if !p.ReadResourceCalled {
+		t.Fatal("ReadResource should be called")
+	}
+
+	checkState(t, b.StateOutPath, `
+test_instance.foo:
+  ID = yes
+  provider = provider["registry.terraform.io/hashicorp/test"]
+	`)
+
+	// the backend should be unlocked after a run
+	assertBackendStateUnlocked(t, b)
+}
+
+func TestLocal_refreshInput(t *testing.T) {
+	b := TestLocal(t)
+
+	schema := &terraform.ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"value": {Type: cty.String, Optional: true},
+			},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Computed: true},
+					"foo": {Type: cty.String, Optional: true},
+					"ami": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	}
+
+	p := TestLocalProvider(t, b, "test", schema)
+	testStateFile(t, b.StatePath, testRefreshState())
+
+	p.ReadResourceFn = nil
+	p.ReadResourceResponse = &providers.ReadResourceResponse{NewState: cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("yes"),
+	})}
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		val := req.Config.GetAttr("value")
+		if val.IsNull() || val.AsString() != "bar" {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("incorrect value %#v", val))
+		}
+
+		return
+	}
+
+	// Enable input asking since it is normally disabled by default
+	b.OpInput = true
+	b.ContextOpts.UIInput = &terraform.MockUIInput{InputReturnString: "bar"}
+
+	op, configCleanup, done := testOperationRefresh(t, "./testdata/refresh-var-unset")
+	defer configCleanup()
+	defer done(t)
+	op.UIIn = b.ContextOpts.UIInput
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+
+	if !p.ReadResourceCalled {
+		t.Fatal("ReadResource should be called")
+	}
+
+	checkState(t, b.StateOutPath, `
+test_instance.foo:
+  ID = yes
+  provider = provider["registry.terraform.io/hashicorp/test"]
+	`)
+}
+
+func TestLocal_refreshValidate(t *testing.T) {
+	b := TestLocal(t)
+	p := TestLocalProvider(t, b, "test", refreshFixtureSchema())
+	testStateFile(t, b.StatePath, testRefreshState())
+	p.ReadResourceFn = nil
+	p.ReadResourceResponse = &providers.ReadResourceResponse{NewState: cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("yes"),
+	})}
+
+	// Enable validation
+	b.OpValidation = true
+
+	op, configCleanup, done := testOperationRefresh(t, "./testdata/refresh")
+	defer configCleanup()
+	defer done(t)
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+
+	checkState(t, b.StateOutPath, `
+test_instance.foo:
+  ID = yes
+  provider = provider["registry.terraform.io/hashicorp/test"]
+	`)
+}
+
+func TestLocal_refreshValidateProviderConfigured(t *testing.T) {
+	b := TestLocal(t)
+
+	schema := &terraform.ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"value": {Type: cty.String, Optional: true},
+			},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Computed: true},
+					"ami": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	}
+
+	p := TestLocalProvider(t, b, "test", schema)
+	testStateFile(t, b.StatePath, testRefreshState())
+	p.ReadResourceFn = nil
+	p.ReadResourceResponse = &providers.ReadResourceResponse{NewState: cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("yes"),
+	})}
+
+	// Enable validation
+	b.OpValidation = true
+
+	op, configCleanup, done := testOperationRefresh(t, "./testdata/refresh-provider-config")
+	defer configCleanup()
+	defer done(t)
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+
+	if !p.ValidateProviderConfigCalled {
+		t.Fatal("Validate provider config should be called")
+	}
+
+	checkState(t, b.StateOutPath, `
+test_instance.foo:
+  ID = yes
+  provider = provider["registry.terraform.io/hashicorp/test"]
+	`)
+}
+
+// This test validates the state lacking behavior when the inner call to
+// Context() fails
+func TestLocal_refresh_context_error(t *testing.T) {
+	b := TestLocal(t)
+	testStateFile(t, b.StatePath, testRefreshState())
+	op, configCleanup, done := testOperationRefresh(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	// we coerce a failure in Context() by omitting the provider schema
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("operation succeeded; want failure")
+	}
+	assertBackendStateUnlocked(t, b)
+}
+
+func TestLocal_refreshEmptyState(t *testing.T) {
+	b := TestLocal(t)
+
+	p := TestLocalProvider(t, b, "test", refreshFixtureSchema())
+	testStateFile(t, b.StatePath, states.NewState())
+
+	p.ReadResourceFn = nil
+	p.ReadResourceResponse = &providers.ReadResourceResponse{NewState: cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("yes"),
+	})}
+
+	op, configCleanup, done := testOperationRefresh(t, "./testdata/refresh")
+	defer configCleanup()
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	<-run.Done()
+
+	output := done(t)
+
+	if stderr := output.Stderr(); stderr != "" {
+		t.Fatalf("expected only warning diags, got errors: %s", stderr)
+	}
+	if got, want := output.Stdout(), "Warning: Empty or non-existent state"; !strings.Contains(got, want) {
+		t.Errorf("wrong diags\n got: %s\nwant: %s", got, want)
+	}
+
+	// the backend should be unlocked after a run
+	assertBackendStateUnlocked(t, b)
+}
+
+func testOperationRefresh(t *testing.T, configDir string) (*backend.Operation, func(), func(*testing.T) *terminal.TestOutput) {
+	t.Helper()
+
+	_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams))
+
+	// Many of our tests use an overridden "test" provider that's just in-memory
+	// inside the test process, not a separate plugin on disk.
+	depLocks := depsfile.NewLocks()
+	depLocks.SetProviderOverridden(addrs.MustParseProviderSourceString("registry.terraform.io/hashicorp/test"))
+
+	return &backend.Operation{
+		Type:            backend.OperationTypeRefresh,
+		ConfigDir:       configDir,
+		ConfigLoader:    configLoader,
+		StateLocker:     clistate.NewNoopLocker(),
+		View:            view,
+		DependencyLocks: depLocks,
+	}, configCleanup, done
+}
+
+// testRefreshState is just a common state that we use for testing refresh.
+func testRefreshState() *states.State {
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	return state
+}
+
+// refreshFixtureSchema returns a schema suitable for processing the
+// configuration in testdata/refresh . This schema should be
+// assigned to a mock provider named "test".
+func refreshFixtureSchema() *terraform.ProviderSchema {
+	return &terraform.ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"ami": {Type: cty.String, Optional: true},
+					"id":  {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	}
+}
diff --git a/v1.5.7/internal/backend/local/backend_test.go b/v1.5.7/internal/backend/local/backend_test.go
new file mode 100644
index 0000000..b181625
--- /dev/null
+++ b/v1.5.7/internal/backend/local/backend_test.go
@@ -0,0 +1,249 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package local
+
+import (
+	"errors"
+	"os"
+	"path/filepath"
+	"reflect"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+func TestLocal_impl(t *testing.T) {
+	var _ backend.Enhanced = New()
+	var _ backend.Local = New()
+	var _ backend.CLI = New()
+}
+
+func TestLocal_backend(t *testing.T) {
+	testTmpDir(t)
+	b := New()
+	backend.TestBackendStates(t, b)
+	backend.TestBackendStateLocks(t, b, b)
+}
+
+func checkState(t *testing.T, path, expected string) {
+	t.Helper()
+	// Read the state
+	f, err := os.Open(path)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	state, err := statefile.Read(f)
+	f.Close()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := state.State.String()
+	expected = strings.TrimSpace(expected)
+	if actual != expected {
+		t.Fatalf("state does not match! actual:\n%s\n\nexpected:\n%s", actual, expected)
+	}
+}
+
+func TestLocal_StatePaths(t *testing.T) {
+	b := New()
+
+	// Test the defaults
+	path, out, back := b.StatePaths("")
+
+	if path != DefaultStateFilename {
+		t.Fatalf("expected %q, got %q", DefaultStateFilename, path)
+	}
+
+	if out != DefaultStateFilename {
+		t.Fatalf("expected %q, got %q", DefaultStateFilename, out)
+	}
+
+	dfltBackup := DefaultStateFilename + DefaultBackupExtension
+	if back != dfltBackup {
+		t.Fatalf("expected %q, got %q", dfltBackup, back)
+	}
+
+	// check with env
+	testEnv := "test_env"
+	path, out, back = b.StatePaths(testEnv)
+
+	expectedPath := filepath.Join(DefaultWorkspaceDir, testEnv, DefaultStateFilename)
+	expectedOut := expectedPath
+	expectedBackup := expectedPath + DefaultBackupExtension
+
+	if path != expectedPath {
+		t.Fatalf("expected %q, got %q", expectedPath, path)
+	}
+
+	if out != expectedOut {
+		t.Fatalf("expected %q, got %q", expectedOut, out)
+	}
+
+	if back != expectedBackup {
+		t.Fatalf("expected %q, got %q", expectedBackup, back)
+	}
+
+}
+
+func TestLocal_addAndRemoveStates(t *testing.T) {
+	testTmpDir(t)
+	dflt := backend.DefaultStateName
+	expectedStates := []string{dflt}
+
+	b := New()
+	states, err := b.Workspaces()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !reflect.DeepEqual(states, expectedStates) {
+		t.Fatalf("expected []string{%q}, got %q", dflt, states)
+	}
+
+	expectedA := "test_A"
+	if _, err := b.StateMgr(expectedA); err != nil {
+		t.Fatal(err)
+	}
+
+	states, err = b.Workspaces()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expectedStates = append(expectedStates, expectedA)
+	if !reflect.DeepEqual(states, expectedStates) {
+		t.Fatalf("expected %q, got %q", expectedStates, states)
+	}
+
+	expectedB := "test_B"
+	if _, err := b.StateMgr(expectedB); err != nil {
+		t.Fatal(err)
+	}
+
+	states, err = b.Workspaces()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expectedStates = append(expectedStates, expectedB)
+	if !reflect.DeepEqual(states, expectedStates) {
+		t.Fatalf("expected %q, got %q", expectedStates, states)
+	}
+
+	if err := b.DeleteWorkspace(expectedA, true); err != nil {
+		t.Fatal(err)
+	}
+
+	states, err = b.Workspaces()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expectedStates = []string{dflt, expectedB}
+	if !reflect.DeepEqual(states, expectedStates) {
+		t.Fatalf("expected %q, got %q", expectedStates, states)
+	}
+
+	if err := b.DeleteWorkspace(expectedB, true); err != nil {
+		t.Fatal(err)
+	}
+
+	states, err = b.Workspaces()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expectedStates = []string{dflt}
+	if !reflect.DeepEqual(states, expectedStates) {
+		t.Fatalf("expected %q, got %q", expectedStates, states)
+	}
+
+	if err := b.DeleteWorkspace(dflt, true); err == nil {
+		t.Fatal("expected error deleting default state")
+	}
+}
+
+// a local backend which returns sentinel errors for NamedState methods to
+// verify it's being called.
+type testDelegateBackend struct {
+	*Local
+
+	// return a sentinel error on these calls
+	stateErr  bool
+	statesErr bool
+	deleteErr bool
+}
+
+var errTestDelegateState = errors.New("state called")
+var errTestDelegateStates = errors.New("states called")
+var errTestDelegateDeleteState = errors.New("delete called")
+
+func (b *testDelegateBackend) StateMgr(name string) (statemgr.Full, error) {
+	if b.stateErr {
+		return nil, errTestDelegateState
+	}
+	s := statemgr.NewFilesystem("terraform.tfstate")
+	return s, nil
+}
+
+func (b *testDelegateBackend) Workspaces() ([]string, error) {
+	if b.statesErr {
+		return nil, errTestDelegateStates
+	}
+	return []string{"default"}, nil
+}
+
+func (b *testDelegateBackend) DeleteWorkspace(name string, force bool) error {
+	if b.deleteErr {
+		return errTestDelegateDeleteState
+	}
+	return nil
+}
+
+// verify that the MultiState methods are dispatched to the correct Backend.
+func TestLocal_multiStateBackend(t *testing.T) {
+	// assign a separate backend where we can read the state
+	b := NewWithBackend(&testDelegateBackend{
+		stateErr:  true,
+		statesErr: true,
+		deleteErr: true,
+	})
+
+	if _, err := b.StateMgr("test"); err != errTestDelegateState {
+		t.Fatal("expected errTestDelegateState, got:", err)
+	}
+
+	if _, err := b.Workspaces(); err != errTestDelegateStates {
+		t.Fatal("expected errTestDelegateStates, got:", err)
+	}
+
+	if err := b.DeleteWorkspace("test", true); err != errTestDelegateDeleteState {
+		t.Fatal("expected errTestDelegateDeleteState, got:", err)
+	}
+}
+
+// testTmpDir changes into a tmp dir and change back automatically when the test
+// and all its subtests complete.
+func testTmpDir(t *testing.T) {
+	tmp := t.TempDir()
+
+	old, err := os.Getwd()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := os.Chdir(tmp); err != nil {
+		t.Fatal(err)
+	}
+
+	t.Cleanup(func() {
+		// ignore errors and try to clean up
+		os.Chdir(old)
+	})
+}
diff --git a/v1.5.7/internal/backend/local/cli.go b/v1.5.7/internal/backend/local/cli.go
new file mode 100644
index 0000000..0704071
--- /dev/null
+++ b/v1.5.7/internal/backend/local/cli.go
@@ -0,0 +1,35 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package local
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/backend"
+)
+
+// backend.CLI impl.
+func (b *Local) CLIInit(opts *backend.CLIOpts) error {
+	b.ContextOpts = opts.ContextOpts
+	b.OpInput = opts.Input
+	b.OpValidation = opts.Validation
+
+	// configure any new cli options
+	if opts.StatePath != "" {
+		log.Printf("[TRACE] backend/local: CLI option -state is overriding state path to %s", opts.StatePath)
+		b.OverrideStatePath = opts.StatePath
+	}
+
+	if opts.StateOutPath != "" {
+		log.Printf("[TRACE] backend/local: CLI option -state-out is overriding state output path to %s", opts.StateOutPath)
+		b.OverrideStateOutPath = opts.StateOutPath
+	}
+
+	if opts.StateBackupPath != "" {
+		log.Printf("[TRACE] backend/local: CLI option -backup is overriding state backup path to %s", opts.StateBackupPath)
+		b.OverrideStateBackupPath = opts.StateBackupPath
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/backend/local/hook_state.go b/v1.5.7/internal/backend/local/hook_state.go
new file mode 100644
index 0000000..d591d36
--- /dev/null
+++ b/v1.5.7/internal/backend/local/hook_state.go
@@ -0,0 +1,175 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package local
+
+import (
+	"log"
+	"sync"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// StateHook is a hook that continuously updates the state by calling
+// WriteState on a statemgr.Full.
+type StateHook struct {
+	terraform.NilHook
+	sync.Mutex
+
+	StateMgr statemgr.Writer
+
+	// If PersistInterval is nonzero then for any new state update after
+	// the duration has elapsed we'll try to persist a state snapshot
+	// to the persistent backend too.
+	// That's only possible if field Schemas is valid, because the
+	// StateMgr.PersistState function for some backends needs schemas.
+	PersistInterval time.Duration
+
+	// Schemas are the schemas to use when persisting state due to
+	// PersistInterval. This is ignored if PersistInterval is zero,
+	// and PersistInterval is ignored if this is nil.
+	Schemas *terraform.Schemas
+
+	intermediatePersist IntermediateStatePersistInfo
+}
+
+type IntermediateStatePersistInfo struct {
+	// RequestedPersistInterval is the persist interval requested by whatever
+	// instantiated the StateHook.
+	//
+	// Implementations of [IntermediateStateConditionalPersister] should ideally
+	// respect this, but may ignore it if they use something other than the
+	// passage of time to make their decision.
+	RequestedPersistInterval time.Duration
+
+	// LastPersist is the time when the last intermediate state snapshot was
+	// persisted, or the time of the first report for Terraform Core if there
+	// hasn't yet been a persisted snapshot.
+	LastPersist time.Time
+
+	// ForcePersist is true when Terraform CLI has receieved an interrupt
+	// signal and is therefore trying to create snapshots more aggressively
+	// in anticipation of possibly being terminated ungracefully.
+	// [IntermediateStateConditionalPersister] implementations should ideally
+	// persist every snapshot they get when this flag is set, unless they have
+	// some external information that implies this shouldn't be necessary.
+	ForcePersist bool
+}
+
+var _ terraform.Hook = (*StateHook)(nil)
+
+func (h *StateHook) PostStateUpdate(new *states.State) (terraform.HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.intermediatePersist.RequestedPersistInterval = h.PersistInterval
+
+	if h.intermediatePersist.LastPersist.IsZero() {
+		// The first PostStateUpdate starts the clock for intermediate
+		// calls to PersistState.
+		h.intermediatePersist.LastPersist = time.Now()
+	}
+
+	if h.StateMgr != nil {
+		if err := h.StateMgr.WriteState(new); err != nil {
+			return terraform.HookActionHalt, err
+		}
+		if mgrPersist, ok := h.StateMgr.(statemgr.Persister); ok && h.PersistInterval != 0 && h.Schemas != nil {
+			if h.shouldPersist() {
+				err := mgrPersist.PersistState(h.Schemas)
+				if err != nil {
+					return terraform.HookActionHalt, err
+				}
+				h.intermediatePersist.LastPersist = time.Now()
+			} else {
+				log.Printf("[DEBUG] State storage %T declined to persist a state snapshot", h.StateMgr)
+			}
+		}
+	}
+
+	return terraform.HookActionContinue, nil
+}
+
+func (h *StateHook) Stopping() {
+	h.Lock()
+	defer h.Unlock()
+
+	// If Terraform has been asked to stop then that might mean that a hard
+	// kill signal will follow shortly in case Terraform doesn't stop
+	// quickly enough, and so we'll try to persist the latest state
+	// snapshot in the hope that it'll give the user less recovery work to
+	// do if they _do_ subsequently hard-kill Terraform during an apply.
+
+	if mgrPersist, ok := h.StateMgr.(statemgr.Persister); ok && h.Schemas != nil {
+		// While we're in the stopping phase we'll try to persist every
+		// new state update to maximize every opportunity we get to avoid
+		// losing track of objects that have been created or updated.
+		// Terraform Core won't start any new operations after it's been
+		// stopped, so at most we should see one more PostStateUpdate
+		// call per already-active request.
+		h.intermediatePersist.ForcePersist = true
+
+		if h.shouldPersist() {
+			err := mgrPersist.PersistState(h.Schemas)
+			if err != nil {
+				// This hook can't affect Terraform Core's ongoing behavior,
+				// but it's a best effort thing anyway so we'll just emit a
+				// log to aid with debugging.
+				log.Printf("[ERROR] Failed to persist state after interruption: %s", err)
+			}
+		} else {
+			log.Printf("[DEBUG] State storage %T declined to persist a state snapshot", h.StateMgr)
+		}
+	}
+
+}
+
+func (h *StateHook) shouldPersist() bool {
+	if m, ok := h.StateMgr.(IntermediateStateConditionalPersister); ok {
+		return m.ShouldPersistIntermediateState(&h.intermediatePersist)
+	}
+	return DefaultIntermediateStatePersistRule(&h.intermediatePersist)
+}
+
+// DefaultIntermediateStatePersistRule is the default implementation of
+// [IntermediateStateConditionalPersister.ShouldPersistIntermediateState] used
+// when the selected state manager doesn't implement that interface.
+//
+// Implementers of that interface can optionally wrap a call to this function
+// if they want to combine the default behavior with some logic of their own.
+func DefaultIntermediateStatePersistRule(info *IntermediateStatePersistInfo) bool {
+	return info.ForcePersist || time.Since(info.LastPersist) >= info.RequestedPersistInterval
+}
+
+// IntermediateStateConditionalPersister is an optional extension of
+// [statemgr.Persister] that allows an implementation to tailor the rules for
+// whether to create intermediate state snapshots when Terraform Core emits
+// events reporting that the state might have changed.
+//
+// For state managers that don't implement this interface, [StateHook] uses
+// a default set of rules that aim to be a good compromise between how long
+// a state change can be active before it gets committed as a snapshot vs.
+// how many intermediate snapshots will get created. That compromise is subject
+// to change over time, but a state manager can implement this interface to
+// exert full control over those rules.
+type IntermediateStateConditionalPersister interface {
+	// ShouldPersistIntermediateState will be called each time Terraform Core
+	// emits an intermediate state event that is potentially eligible to be
+	// persisted.
+	//
+	// The implemention should return true to signal that the state snapshot
+	// most recently provided to the object's WriteState should be persisted,
+	// or false if it should not be persisted. If this function returns true
+	// then the receiver will see a subsequent call to
+	// [statemgr.Persister.PersistState] to request persistence.
+	//
+	// The implementation must not modify anything reachable through the
+	// arguments, and must not retain pointers to anything reachable through
+	// them after the function returns. However, implementers can assume that
+	// nothing will write to anything reachable through the arguments while
+	// this function is active.
+	ShouldPersistIntermediateState(info *IntermediateStatePersistInfo) bool
+}
diff --git a/v1.5.7/internal/backend/local/hook_state_test.go b/v1.5.7/internal/backend/local/hook_state_test.go
new file mode 100644
index 0000000..3c850b8
--- /dev/null
+++ b/v1.5.7/internal/backend/local/hook_state_test.go
@@ -0,0 +1,297 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package local
+
+import (
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+func TestStateHook_impl(t *testing.T) {
+	var _ terraform.Hook = new(StateHook)
+}
+
+func TestStateHook(t *testing.T) {
+	is := statemgr.NewTransientInMemory(nil)
+	var hook terraform.Hook = &StateHook{StateMgr: is}
+
+	s := statemgr.TestFullInitialState()
+	action, err := hook.PostStateUpdate(s)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if action != terraform.HookActionContinue {
+		t.Fatalf("bad: %v", action)
+	}
+	if !is.State().Equal(s) {
+		t.Fatalf("bad state: %#v", is.State())
+	}
+}
+
+func TestStateHookStopping(t *testing.T) {
+	is := &testPersistentState{}
+	hook := &StateHook{
+		StateMgr:        is,
+		Schemas:         &terraform.Schemas{},
+		PersistInterval: 4 * time.Hour,
+		intermediatePersist: IntermediateStatePersistInfo{
+			LastPersist: time.Now(),
+		},
+	}
+
+	s := statemgr.TestFullInitialState()
+	action, err := hook.PostStateUpdate(s)
+	if err != nil {
+		t.Fatalf("unexpected error from PostStateUpdate: %s", err)
+	}
+	if got, want := action, terraform.HookActionContinue; got != want {
+		t.Fatalf("wrong hookaction %#v; want %#v", got, want)
+	}
+	if is.Written == nil || !is.Written.Equal(s) {
+		t.Fatalf("mismatching state written")
+	}
+	if is.Persisted != nil {
+		t.Fatalf("persisted too soon")
+	}
+
+	// We'll now force lastPersist to be long enough ago that persisting
+	// should be due on the next call.
+	hook.intermediatePersist.LastPersist = time.Now().Add(-5 * time.Hour)
+	hook.PostStateUpdate(s)
+	if is.Written == nil || !is.Written.Equal(s) {
+		t.Fatalf("mismatching state written")
+	}
+	if is.Persisted == nil || !is.Persisted.Equal(s) {
+		t.Fatalf("mismatching state persisted")
+	}
+	hook.PostStateUpdate(s)
+	if is.Written == nil || !is.Written.Equal(s) {
+		t.Fatalf("mismatching state written")
+	}
+	if is.Persisted == nil || !is.Persisted.Equal(s) {
+		t.Fatalf("mismatching state persisted")
+	}
+
+	gotLog := is.CallLog
+	wantLog := []string{
+		// Initial call before we reset lastPersist
+		"WriteState",
+
+		// Write and then persist after we reset lastPersist
+		"WriteState",
+		"PersistState",
+
+		// Final call when persisting wasn't due yet.
+		"WriteState",
+	}
+	if diff := cmp.Diff(wantLog, gotLog); diff != "" {
+		t.Fatalf("wrong call log so far\n%s", diff)
+	}
+
+	// We'll reset the log now before we try seeing what happens after
+	// we use "Stopped".
+	is.CallLog = is.CallLog[:0]
+	is.Persisted = nil
+
+	hook.Stopping()
+	if is.Persisted == nil || !is.Persisted.Equal(s) {
+		t.Fatalf("mismatching state persisted")
+	}
+
+	is.Persisted = nil
+	hook.PostStateUpdate(s)
+	if is.Persisted == nil || !is.Persisted.Equal(s) {
+		t.Fatalf("mismatching state persisted")
+	}
+	is.Persisted = nil
+	hook.PostStateUpdate(s)
+	if is.Persisted == nil || !is.Persisted.Equal(s) {
+		t.Fatalf("mismatching state persisted")
+	}
+
+	gotLog = is.CallLog
+	wantLog = []string{
+		// "Stopping" immediately persisted
+		"PersistState",
+
+		// PostStateUpdate then writes and persists on every call,
+		// on the assumption that we're now bailing out after
+		// being cancelled and trying to save as much state as we can.
+		"WriteState",
+		"PersistState",
+		"WriteState",
+		"PersistState",
+	}
+	if diff := cmp.Diff(wantLog, gotLog); diff != "" {
+		t.Fatalf("wrong call log once in stopping mode\n%s", diff)
+	}
+}
+
+func TestStateHookCustomPersistRule(t *testing.T) {
+	is := &testPersistentStateThatRefusesToPersist{}
+	hook := &StateHook{
+		StateMgr:        is,
+		Schemas:         &terraform.Schemas{},
+		PersistInterval: 4 * time.Hour,
+		intermediatePersist: IntermediateStatePersistInfo{
+			LastPersist: time.Now(),
+		},
+	}
+
+	s := statemgr.TestFullInitialState()
+	action, err := hook.PostStateUpdate(s)
+	if err != nil {
+		t.Fatalf("unexpected error from PostStateUpdate: %s", err)
+	}
+	if got, want := action, terraform.HookActionContinue; got != want {
+		t.Fatalf("wrong hookaction %#v; want %#v", got, want)
+	}
+	if is.Written == nil || !is.Written.Equal(s) {
+		t.Fatalf("mismatching state written")
+	}
+	if is.Persisted != nil {
+		t.Fatalf("persisted too soon")
+	}
+
+	// We'll now force lastPersist to be long enough ago that persisting
+	// should be due on the next call.
+	hook.intermediatePersist.LastPersist = time.Now().Add(-5 * time.Hour)
+	hook.PostStateUpdate(s)
+	if is.Written == nil || !is.Written.Equal(s) {
+		t.Fatalf("mismatching state written")
+	}
+	if is.Persisted != nil {
+		t.Fatalf("has a persisted state, but shouldn't")
+	}
+	hook.PostStateUpdate(s)
+	if is.Written == nil || !is.Written.Equal(s) {
+		t.Fatalf("mismatching state written")
+	}
+	if is.Persisted != nil {
+		t.Fatalf("has a persisted state, but shouldn't")
+	}
+
+	gotLog := is.CallLog
+	wantLog := []string{
+		// Initial call before we reset lastPersist
+		"WriteState",
+		"ShouldPersistIntermediateState",
+		// Previous call should return false, preventing a "PersistState" call
+
+		// Write and then decline to persist
+		"WriteState",
+		"ShouldPersistIntermediateState",
+		// Previous call should return false, preventing a "PersistState" call
+
+		// Final call before we start "stopping".
+		"WriteState",
+		"ShouldPersistIntermediateState",
+		// Previous call should return false, preventing a "PersistState" call
+	}
+	if diff := cmp.Diff(wantLog, gotLog); diff != "" {
+		t.Fatalf("wrong call log so far\n%s", diff)
+	}
+
+	// We'll reset the log now before we try seeing what happens after
+	// we use "Stopped".
+	is.CallLog = is.CallLog[:0]
+	is.Persisted = nil
+
+	hook.Stopping()
+	if is.Persisted == nil || !is.Persisted.Equal(s) {
+		t.Fatalf("mismatching state persisted")
+	}
+
+	is.Persisted = nil
+	hook.PostStateUpdate(s)
+	if is.Persisted == nil || !is.Persisted.Equal(s) {
+		t.Fatalf("mismatching state persisted")
+	}
+	is.Persisted = nil
+	hook.PostStateUpdate(s)
+	if is.Persisted == nil || !is.Persisted.Equal(s) {
+		t.Fatalf("mismatching state persisted")
+	}
+
+	gotLog = is.CallLog
+	wantLog = []string{
+		"ShouldPersistIntermediateState",
+		// Previous call should return true, allowing the following "PersistState" call
+		"PersistState",
+		"WriteState",
+		"ShouldPersistIntermediateState",
+		// Previous call should return true, allowing the following "PersistState" call
+		"PersistState",
+		"WriteState",
+		"ShouldPersistIntermediateState",
+		// Previous call should return true, allowing the following "PersistState" call
+		"PersistState",
+	}
+	if diff := cmp.Diff(wantLog, gotLog); diff != "" {
+		t.Fatalf("wrong call log once in stopping mode\n%s", diff)
+	}
+}
+
+type testPersistentState struct {
+	CallLog []string
+
+	Written   *states.State
+	Persisted *states.State
+}
+
+var _ statemgr.Writer = (*testPersistentState)(nil)
+var _ statemgr.Persister = (*testPersistentState)(nil)
+
+func (sm *testPersistentState) WriteState(state *states.State) error {
+	sm.CallLog = append(sm.CallLog, "WriteState")
+	sm.Written = state
+	return nil
+}
+
+func (sm *testPersistentState) PersistState(schemas *terraform.Schemas) error {
+	if schemas == nil {
+		return fmt.Errorf("no schemas")
+	}
+	sm.CallLog = append(sm.CallLog, "PersistState")
+	sm.Persisted = sm.Written
+	return nil
+}
+
+type testPersistentStateThatRefusesToPersist struct {
+	CallLog []string
+
+	Written   *states.State
+	Persisted *states.State
+}
+
+var _ statemgr.Writer = (*testPersistentStateThatRefusesToPersist)(nil)
+var _ statemgr.Persister = (*testPersistentStateThatRefusesToPersist)(nil)
+var _ IntermediateStateConditionalPersister = (*testPersistentStateThatRefusesToPersist)(nil)
+
+func (sm *testPersistentStateThatRefusesToPersist) WriteState(state *states.State) error {
+	sm.CallLog = append(sm.CallLog, "WriteState")
+	sm.Written = state
+	return nil
+}
+
+func (sm *testPersistentStateThatRefusesToPersist) PersistState(schemas *terraform.Schemas) error {
+	if schemas == nil {
+		return fmt.Errorf("no schemas")
+	}
+	sm.CallLog = append(sm.CallLog, "PersistState")
+	sm.Persisted = sm.Written
+	return nil
+}
+
+// ShouldPersistIntermediateState implements IntermediateStateConditionalPersister
+func (sm *testPersistentStateThatRefusesToPersist) ShouldPersistIntermediateState(info *IntermediateStatePersistInfo) bool {
+	sm.CallLog = append(sm.CallLog, "ShouldPersistIntermediateState")
+	return info.ForcePersist
+}
diff --git a/v1.5.7/internal/backend/local/local_test.go b/v1.5.7/internal/backend/local/local_test.go
new file mode 100644
index 0000000..00f7106
--- /dev/null
+++ b/v1.5.7/internal/backend/local/local_test.go
@@ -0,0 +1,17 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package local
+
+import (
+	"flag"
+	"os"
+	"testing"
+
+	_ "github.com/hashicorp/terraform/internal/logging"
+)
+
+func TestMain(m *testing.M) {
+	flag.Parse()
+	os.Exit(m.Run())
+}
diff --git a/v1.5.7/internal/backend/local/testdata/apply-check/main.tf b/v1.5.7/internal/backend/local/testdata/apply-check/main.tf
new file mode 100644
index 0000000..5782be8
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/apply-check/main.tf
@@ -0,0 +1,10 @@
+resource "test_instance" "foo" {
+  ami = "bar"
+}
+
+check "test_instance_exists" {
+  assert {
+    condition = test_instance.foo.id != null
+    error_message = "value should have been computed"
+  }
+}
diff --git a/v1.5.7/internal/backend/local/testdata/apply-empty/hello.txt b/v1.5.7/internal/backend/local/testdata/apply-empty/hello.txt
new file mode 100644
index 0000000..7dcfcbb
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/apply-empty/hello.txt
@@ -0,0 +1 @@
+This is an empty dir
diff --git a/v1.5.7/internal/backend/local/testdata/apply-error/main.tf b/v1.5.7/internal/backend/local/testdata/apply-error/main.tf
new file mode 100644
index 0000000..532c52f
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/apply-error/main.tf
@@ -0,0 +1,7 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+}
+
+resource "test_instance" "bar" {
+    ami = "error"
+}
diff --git a/v1.5.7/internal/backend/local/testdata/apply/main.tf b/v1.5.7/internal/backend/local/testdata/apply/main.tf
new file mode 100644
index 0000000..1b10129
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/apply/main.tf
@@ -0,0 +1,3 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+}
diff --git a/v1.5.7/internal/backend/local/testdata/destroy-with-ds/main.tf b/v1.5.7/internal/backend/local/testdata/destroy-with-ds/main.tf
new file mode 100644
index 0000000..7062d89
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/destroy-with-ds/main.tf
@@ -0,0 +1,8 @@
+resource "test_instance" "foo" {
+  count = 1
+  ami = "bar"
+}
+
+data "test_ds" "bar" {
+  filter = "foo"
+}
diff --git a/v1.5.7/internal/backend/local/testdata/empty/.gitignore b/v1.5.7/internal/backend/local/testdata/empty/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/empty/.gitignore
diff --git a/v1.5.7/internal/backend/local/testdata/invalid/invalid.tf b/v1.5.7/internal/backend/local/testdata/invalid/invalid.tf
new file mode 100644
index 0000000..7f2d072
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/invalid/invalid.tf
@@ -0,0 +1,6 @@
+# This configuration is intended to be loadable (valid syntax, etc) but to
+# fail terraform.Context.Validate.
+
+locals {
+  a = local.nonexist
+}
diff --git a/v1.5.7/internal/backend/local/testdata/plan-cbd/main.tf b/v1.5.7/internal/backend/local/testdata/plan-cbd/main.tf
new file mode 100644
index 0000000..1a7ae84
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/plan-cbd/main.tf
@@ -0,0 +1,13 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+
+    # This is here because at some point it caused a test failure
+    network_interface {
+      device_index = 0
+      description = "Main network interface"
+    }
+
+    lifecycle {
+      create_before_destroy = true
+    }
+}
diff --git a/v1.5.7/internal/backend/local/testdata/plan-module-outputs-changed/main.tf b/v1.5.7/internal/backend/local/testdata/plan-module-outputs-changed/main.tf
new file mode 100644
index 0000000..ba84684
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/plan-module-outputs-changed/main.tf
@@ -0,0 +1,3 @@
+module "mod" {
+  source = "./mod"
+}
diff --git a/v1.5.7/internal/backend/local/testdata/plan-module-outputs-changed/mod/main.tf b/v1.5.7/internal/backend/local/testdata/plan-module-outputs-changed/mod/main.tf
new file mode 100644
index 0000000..cee14bd
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/plan-module-outputs-changed/mod/main.tf
@@ -0,0 +1,3 @@
+output "changed" {
+  value = "after"
+}
diff --git a/v1.5.7/internal/backend/local/testdata/plan-outputs-changed/main.tf b/v1.5.7/internal/backend/local/testdata/plan-outputs-changed/main.tf
new file mode 100644
index 0000000..1df236f
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/plan-outputs-changed/main.tf
@@ -0,0 +1,28 @@
+module "submodule" {
+  source = "./submodule"
+}
+
+output "changed" {
+  value = "after"
+}
+
+output "sensitive_before" {
+  value = "after"
+  # no sensitive = true here, but the prior state is marked as sensitive in the test code
+}
+
+output "sensitive_after" {
+  value = "after"
+
+  # This one is _not_ sensitive in the prior state, but is transitioning to
+  # being sensitive in our new plan.
+  sensitive = true
+}
+
+output "added" { // not present in the prior state
+  value = "after"
+}
+
+output "unchanged" {
+  value = "before"
+}
diff --git a/v1.5.7/internal/backend/local/testdata/plan-outputs-changed/submodule/main.tf b/v1.5.7/internal/backend/local/testdata/plan-outputs-changed/submodule/main.tf
new file mode 100644
index 0000000..ae32f8a
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/plan-outputs-changed/submodule/main.tf
@@ -0,0 +1,3 @@
+output "foo" {
+  value = "bar"
+}
diff --git a/v1.5.7/internal/backend/local/testdata/plan/main.tf b/v1.5.7/internal/backend/local/testdata/plan/main.tf
new file mode 100644
index 0000000..fd9da13
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/plan/main.tf
@@ -0,0 +1,9 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+
+    # This is here because at some point it caused a test failure
+    network_interface {
+      device_index = 0
+      description = "Main network interface"
+    }
+}
diff --git a/v1.5.7/internal/backend/local/testdata/refresh-provider-config/main.tf b/v1.5.7/internal/backend/local/testdata/refresh-provider-config/main.tf
new file mode 100644
index 0000000..f3a3ebb
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/refresh-provider-config/main.tf
@@ -0,0 +1,7 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+}
+
+provider "test" {
+    value = "foo"
+}
diff --git a/v1.5.7/internal/backend/local/testdata/refresh-var-unset/main.tf b/v1.5.7/internal/backend/local/testdata/refresh-var-unset/main.tf
new file mode 100644
index 0000000..8e6b73d
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/refresh-var-unset/main.tf
@@ -0,0 +1,9 @@
+variable "should_ask" {}
+
+provider "test" {
+  value = var.should_ask
+}
+
+resource "test_instance" "foo" {
+  foo = "bar"
+}
diff --git a/v1.5.7/internal/backend/local/testdata/refresh/main.tf b/v1.5.7/internal/backend/local/testdata/refresh/main.tf
new file mode 100644
index 0000000..1b10129
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testdata/refresh/main.tf
@@ -0,0 +1,3 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+}
diff --git a/v1.5.7/internal/backend/local/testing.go b/v1.5.7/internal/backend/local/testing.go
new file mode 100644
index 0000000..1900a8f
--- /dev/null
+++ b/v1.5.7/internal/backend/local/testing.go
@@ -0,0 +1,242 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package local
+
+import (
+	"path/filepath"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// TestLocal returns a configured Local struct with temporary paths and
+// in-memory ContextOpts.
+//
+// No operations will be called on the returned value, so you can still set
+// public fields without any locks.
+func TestLocal(t *testing.T) *Local {
+	t.Helper()
+	tempDir, err := filepath.EvalSymlinks(t.TempDir())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	local := New()
+	local.StatePath = filepath.Join(tempDir, "state.tfstate")
+	local.StateOutPath = filepath.Join(tempDir, "state.tfstate")
+	local.StateBackupPath = filepath.Join(tempDir, "state.tfstate.bak")
+	local.StateWorkspaceDir = filepath.Join(tempDir, "state.tfstate.d")
+	local.ContextOpts = &terraform.ContextOpts{}
+
+	return local
+}
+
+// TestLocalProvider modifies the ContextOpts of the *Local parameter to
+// have a provider with the given name.
+func TestLocalProvider(t *testing.T, b *Local, name string, schema *terraform.ProviderSchema) *terraform.MockProvider {
+	// Build a mock resource provider for in-memory operations
+	p := new(terraform.MockProvider)
+
+	if schema == nil {
+		schema = &terraform.ProviderSchema{} // default schema is empty
+	}
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider:      providers.Schema{Block: schema.Provider},
+		ProviderMeta:  providers.Schema{Block: schema.ProviderMeta},
+		ResourceTypes: map[string]providers.Schema{},
+		DataSources:   map[string]providers.Schema{},
+	}
+	for name, res := range schema.ResourceTypes {
+		p.GetProviderSchemaResponse.ResourceTypes[name] = providers.Schema{
+			Block:   res,
+			Version: int64(schema.ResourceTypeSchemaVersions[name]),
+		}
+	}
+	for name, dat := range schema.DataSources {
+		p.GetProviderSchemaResponse.DataSources[name] = providers.Schema{Block: dat}
+	}
+
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		// this is a destroy plan,
+		if req.ProposedNewState.IsNull() {
+			resp.PlannedState = req.ProposedNewState
+			resp.PlannedPrivate = req.PriorPrivate
+			return resp
+		}
+
+		rSchema, _ := schema.SchemaForResourceType(addrs.ManagedResourceMode, req.TypeName)
+		if rSchema == nil {
+			rSchema = &configschema.Block{} // default schema is empty
+		}
+		plannedVals := map[string]cty.Value{}
+		for name, attrS := range rSchema.Attributes {
+			val := req.ProposedNewState.GetAttr(name)
+			if attrS.Computed && val.IsNull() {
+				val = cty.UnknownVal(attrS.Type)
+			}
+			plannedVals[name] = val
+		}
+		for name := range rSchema.BlockTypes {
+			// For simplicity's sake we just copy the block attributes over
+			// verbatim, since this package's mock providers are all relatively
+			// simple -- we're testing the backend, not esoteric provider features.
+			plannedVals[name] = req.ProposedNewState.GetAttr(name)
+		}
+
+		return providers.PlanResourceChangeResponse{
+			PlannedState:   cty.ObjectVal(plannedVals),
+			PlannedPrivate: req.PriorPrivate,
+		}
+	}
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		return providers.ReadResourceResponse{NewState: req.PriorState}
+	}
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		return providers.ReadDataSourceResponse{State: req.Config}
+	}
+
+	// Initialize the opts
+	if b.ContextOpts == nil {
+		b.ContextOpts = &terraform.ContextOpts{}
+	}
+
+	// Set up our provider
+	b.ContextOpts.Providers = map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider(name): providers.FactoryFixed(p),
+	}
+
+	return p
+
+}
+
+// TestLocalSingleState is a backend implementation that wraps Local
+// and modifies it to only support single states (returns
+// ErrWorkspacesNotSupported for multi-state operations).
+//
+// This isn't an actual use case, this is exported just to provide a
+// easy way to test that behavior.
+type TestLocalSingleState struct {
+	*Local
+}
+
+// TestNewLocalSingle is a factory for creating a TestLocalSingleState.
+// This function matches the signature required for backend/init.
+func TestNewLocalSingle() backend.Backend {
+	return &TestLocalSingleState{Local: New()}
+}
+
+func (b *TestLocalSingleState) Workspaces() ([]string, error) {
+	return nil, backend.ErrWorkspacesNotSupported
+}
+
+func (b *TestLocalSingleState) DeleteWorkspace(string, bool) error {
+	return backend.ErrWorkspacesNotSupported
+}
+
+func (b *TestLocalSingleState) StateMgr(name string) (statemgr.Full, error) {
+	if name != backend.DefaultStateName {
+		return nil, backend.ErrWorkspacesNotSupported
+	}
+
+	return b.Local.StateMgr(name)
+}
+
+// TestLocalNoDefaultState is a backend implementation that wraps
+// Local and modifies it to support named states, but not the
+// default state. It returns ErrDefaultWorkspaceNotSupported when
+// the DefaultStateName is used.
+type TestLocalNoDefaultState struct {
+	*Local
+}
+
+// TestNewLocalNoDefault is a factory for creating a TestLocalNoDefaultState.
+// This function matches the signature required for backend/init.
+func TestNewLocalNoDefault() backend.Backend {
+	return &TestLocalNoDefaultState{Local: New()}
+}
+
+func (b *TestLocalNoDefaultState) Workspaces() ([]string, error) {
+	workspaces, err := b.Local.Workspaces()
+	if err != nil {
+		return nil, err
+	}
+
+	filtered := workspaces[:0]
+	for _, name := range workspaces {
+		if name != backend.DefaultStateName {
+			filtered = append(filtered, name)
+		}
+	}
+
+	return filtered, nil
+}
+
+func (b *TestLocalNoDefaultState) DeleteWorkspace(name string, force bool) error {
+	if name == backend.DefaultStateName {
+		return backend.ErrDefaultWorkspaceNotSupported
+	}
+	return b.Local.DeleteWorkspace(name, force)
+}
+
+func (b *TestLocalNoDefaultState) StateMgr(name string) (statemgr.Full, error) {
+	if name == backend.DefaultStateName {
+		return nil, backend.ErrDefaultWorkspaceNotSupported
+	}
+	return b.Local.StateMgr(name)
+}
+
+func testStateFile(t *testing.T, path string, s *states.State) {
+	stateFile := statemgr.NewFilesystem(path)
+	stateFile.WriteState(s)
+}
+
+func mustProviderConfig(s string) addrs.AbsProviderConfig {
+	p, diags := addrs.ParseAbsProviderConfigStr(s)
+	if diags.HasErrors() {
+		panic(diags.Err())
+	}
+	return p
+}
+
+func mustResourceInstanceAddr(s string) addrs.AbsResourceInstance {
+	addr, diags := addrs.ParseAbsResourceInstanceStr(s)
+	if diags.HasErrors() {
+		panic(diags.Err())
+	}
+	return addr
+}
+
+// assertBackendStateUnlocked attempts to lock the backend state. Failure
+// indicates that the state was indeed locked and therefore this function will
+// return true.
+func assertBackendStateUnlocked(t *testing.T, b *Local) bool {
+	t.Helper()
+	stateMgr, _ := b.StateMgr(backend.DefaultStateName)
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Errorf("state is already locked: %s", err.Error())
+		return false
+	}
+	return true
+}
+
+// assertBackendStateLocked attempts to lock the backend state. Failure
+// indicates that the state was already locked and therefore this function will
+// return false.
+func assertBackendStateLocked(t *testing.T, b *Local) bool {
+	t.Helper()
+	stateMgr, _ := b.StateMgr(backend.DefaultStateName)
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		return true
+	}
+	t.Error("unexpected success locking state")
+	return true
+}
diff --git a/v1.5.7/internal/backend/operation_type.go b/v1.5.7/internal/backend/operation_type.go
new file mode 100644
index 0000000..03f11ba
--- /dev/null
+++ b/v1.5.7/internal/backend/operation_type.go
@@ -0,0 +1,17 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package backend
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=OperationType operation_type.go
+
+// OperationType is an enum used with Operation to specify the operation
+// type to perform for Terraform.
+type OperationType uint
+
+const (
+	OperationTypeInvalid OperationType = iota
+	OperationTypeRefresh
+	OperationTypePlan
+	OperationTypeApply
+)
diff --git a/v1.5.7/internal/backend/operationtype_string.go b/v1.5.7/internal/backend/operationtype_string.go
new file mode 100644
index 0000000..fe84d84
--- /dev/null
+++ b/v1.5.7/internal/backend/operationtype_string.go
@@ -0,0 +1,26 @@
+// Code generated by "stringer -type=OperationType operation_type.go"; DO NOT EDIT.
+
+package backend
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[OperationTypeInvalid-0]
+	_ = x[OperationTypeRefresh-1]
+	_ = x[OperationTypePlan-2]
+	_ = x[OperationTypeApply-3]
+}
+
+const _OperationType_name = "OperationTypeInvalidOperationTypeRefreshOperationTypePlanOperationTypeApply"
+
+var _OperationType_index = [...]uint8{0, 20, 40, 57, 75}
+
+func (i OperationType) String() string {
+	if i >= OperationType(len(_OperationType_index)-1) {
+		return "OperationType(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _OperationType_name[_OperationType_index[i]:_OperationType_index[i+1]]
+}
diff --git a/v1.5.7/internal/backend/remote-state/azure/arm_client.go b/v1.5.7/internal/backend/remote-state/azure/arm_client.go
new file mode 100644
index 0000000..8ca63e9
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/azure/arm_client.go
@@ -0,0 +1,249 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package azure
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"os"
+	"time"
+
+	"github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources"
+	armStorage "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-01-01/storage"
+	"github.com/Azure/go-autorest/autorest"
+	"github.com/Azure/go-autorest/autorest/azure"
+	"github.com/hashicorp/go-azure-helpers/authentication"
+	"github.com/hashicorp/go-azure-helpers/sender"
+	"github.com/hashicorp/terraform/internal/httpclient"
+	"github.com/hashicorp/terraform/version"
+	"github.com/manicminer/hamilton/environments"
+	"github.com/tombuildsstuff/giovanni/storage/2018-11-09/blob/blobs"
+	"github.com/tombuildsstuff/giovanni/storage/2018-11-09/blob/containers"
+)
+
+type ArmClient struct {
+	// These Clients are only initialized if an Access Key isn't provided
+	groupsClient          *resources.GroupsClient
+	storageAccountsClient *armStorage.AccountsClient
+	containersClient      *containers.Client
+	blobsClient           *blobs.Client
+
+	// azureAdStorageAuth is only here if we're using AzureAD Authentication but is an Authorizer for Storage
+	azureAdStorageAuth *autorest.Authorizer
+
+	accessKey          string
+	environment        azure.Environment
+	resourceGroupName  string
+	storageAccountName string
+	sasToken           string
+}
+
+func buildArmClient(ctx context.Context, config BackendConfig) (*ArmClient, error) {
+	env, err := authentication.AzureEnvironmentByNameFromEndpoint(ctx, config.MetadataHost, config.Environment)
+	if err != nil {
+		return nil, err
+	}
+
+	client := ArmClient{
+		environment:        *env,
+		resourceGroupName:  config.ResourceGroupName,
+		storageAccountName: config.StorageAccountName,
+	}
+
+	// if we have an Access Key - we don't need the other clients
+	if config.AccessKey != "" {
+		client.accessKey = config.AccessKey
+		return &client, nil
+	}
+
+	// likewise with a SAS token
+	if config.SasToken != "" {
+		client.sasToken = config.SasToken
+		return &client, nil
+	}
+
+	builder := authentication.Builder{
+		ClientID:                      config.ClientID,
+		SubscriptionID:                config.SubscriptionID,
+		TenantID:                      config.TenantID,
+		CustomResourceManagerEndpoint: config.CustomResourceManagerEndpoint,
+		MetadataHost:                  config.MetadataHost,
+		Environment:                   config.Environment,
+		ClientSecretDocsLink:          "https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_client_secret",
+
+		// Service Principal (Client Certificate)
+		ClientCertPassword: config.ClientCertificatePassword,
+		ClientCertPath:     config.ClientCertificatePath,
+
+		// Service Principal (Client Secret)
+		ClientSecret: config.ClientSecret,
+
+		// Managed Service Identity
+		MsiEndpoint: config.MsiEndpoint,
+
+		// OIDC
+		IDToken:             config.OIDCToken,
+		IDTokenFilePath:     config.OIDCTokenFilePath,
+		IDTokenRequestURL:   config.OIDCRequestURL,
+		IDTokenRequestToken: config.OIDCRequestToken,
+
+		// Feature Toggles
+		SupportsAzureCliToken:          true,
+		SupportsClientCertAuth:         true,
+		SupportsClientSecretAuth:       true,
+		SupportsManagedServiceIdentity: config.UseMsi,
+		SupportsOIDCAuth:               config.UseOIDC,
+		UseMicrosoftGraph:              true,
+	}
+	armConfig, err := builder.Build()
+	if err != nil {
+		return nil, fmt.Errorf("Error building ARM Config: %+v", err)
+	}
+
+	oauthConfig, err := armConfig.BuildOAuthConfig(env.ActiveDirectoryEndpoint)
+	if err != nil {
+		return nil, err
+	}
+
+	hamiltonEnv, err := environments.EnvironmentFromString(config.Environment)
+	if err != nil {
+		return nil, err
+	}
+
+	sender := sender.BuildSender("backend/remote-state/azure")
+	log.Printf("[DEBUG] Obtaining an MSAL / Microsoft Graph token for Resource Manager..")
+	auth, err := armConfig.GetMSALToken(ctx, hamiltonEnv.ResourceManager, sender, oauthConfig, env.TokenAudience)
+	if err != nil {
+		return nil, err
+	}
+
+	if config.UseAzureADAuthentication {
+		log.Printf("[DEBUG] Obtaining an MSAL / Microsoft Graph token for Storage..")
+		storageAuth, err := armConfig.GetMSALToken(ctx, hamiltonEnv.Storage, sender, oauthConfig, env.ResourceIdentifiers.Storage)
+		if err != nil {
+			return nil, err
+		}
+		client.azureAdStorageAuth = &storageAuth
+	}
+
+	accountsClient := armStorage.NewAccountsClientWithBaseURI(env.ResourceManagerEndpoint, armConfig.SubscriptionID)
+	client.configureClient(&accountsClient.Client, auth)
+	client.storageAccountsClient = &accountsClient
+
+	groupsClient := resources.NewGroupsClientWithBaseURI(env.ResourceManagerEndpoint, armConfig.SubscriptionID)
+	client.configureClient(&groupsClient.Client, auth)
+	client.groupsClient = &groupsClient
+
+	return &client, nil
+}
+
+func (c ArmClient) getBlobClient(ctx context.Context) (*blobs.Client, error) {
+	if c.sasToken != "" {
+		log.Printf("[DEBUG] Building the Blob Client from a SAS Token")
+		storageAuth, err := autorest.NewSASTokenAuthorizer(c.sasToken)
+		if err != nil {
+			return nil, fmt.Errorf("Error building Authorizer: %+v", err)
+		}
+
+		blobsClient := blobs.NewWithEnvironment(c.environment)
+		c.configureClient(&blobsClient.Client, storageAuth)
+		return &blobsClient, nil
+	}
+
+	if c.azureAdStorageAuth != nil {
+		blobsClient := blobs.NewWithEnvironment(c.environment)
+		c.configureClient(&blobsClient.Client, *c.azureAdStorageAuth)
+		return &blobsClient, nil
+	}
+
+	accessKey := c.accessKey
+	if accessKey == "" {
+		log.Printf("[DEBUG] Building the Blob Client from an Access Token (using user credentials)")
+		keys, err := c.storageAccountsClient.ListKeys(ctx, c.resourceGroupName, c.storageAccountName, "")
+		if err != nil {
+			return nil, fmt.Errorf("Error retrieving keys for Storage Account %q: %s", c.storageAccountName, err)
+		}
+
+		if keys.Keys == nil {
+			return nil, fmt.Errorf("Nil key returned for storage account %q", c.storageAccountName)
+		}
+
+		accessKeys := *keys.Keys
+		accessKey = *accessKeys[0].Value
+	}
+
+	storageAuth, err := autorest.NewSharedKeyAuthorizer(c.storageAccountName, accessKey, autorest.SharedKey)
+	if err != nil {
+		return nil, fmt.Errorf("Error building Authorizer: %+v", err)
+	}
+
+	blobsClient := blobs.NewWithEnvironment(c.environment)
+	c.configureClient(&blobsClient.Client, storageAuth)
+	return &blobsClient, nil
+}
+
+func (c ArmClient) getContainersClient(ctx context.Context) (*containers.Client, error) {
+	if c.sasToken != "" {
+		log.Printf("[DEBUG] Building the Container Client from a SAS Token")
+		storageAuth, err := autorest.NewSASTokenAuthorizer(c.sasToken)
+		if err != nil {
+			return nil, fmt.Errorf("Error building Authorizer: %+v", err)
+		}
+
+		containersClient := containers.NewWithEnvironment(c.environment)
+		c.configureClient(&containersClient.Client, storageAuth)
+		return &containersClient, nil
+	}
+
+	if c.azureAdStorageAuth != nil {
+		containersClient := containers.NewWithEnvironment(c.environment)
+		c.configureClient(&containersClient.Client, *c.azureAdStorageAuth)
+		return &containersClient, nil
+	}
+
+	accessKey := c.accessKey
+	if accessKey == "" {
+		log.Printf("[DEBUG] Building the Container Client from an Access Token (using user credentials)")
+		keys, err := c.storageAccountsClient.ListKeys(ctx, c.resourceGroupName, c.storageAccountName, "")
+		if err != nil {
+			return nil, fmt.Errorf("Error retrieving keys for Storage Account %q: %s", c.storageAccountName, err)
+		}
+
+		if keys.Keys == nil {
+			return nil, fmt.Errorf("Nil key returned for storage account %q", c.storageAccountName)
+		}
+
+		accessKeys := *keys.Keys
+		accessKey = *accessKeys[0].Value
+	}
+
+	storageAuth, err := autorest.NewSharedKeyAuthorizer(c.storageAccountName, accessKey, autorest.SharedKey)
+	if err != nil {
+		return nil, fmt.Errorf("Error building Authorizer: %+v", err)
+	}
+
+	containersClient := containers.NewWithEnvironment(c.environment)
+	c.configureClient(&containersClient.Client, storageAuth)
+	return &containersClient, nil
+}
+
+func (c *ArmClient) configureClient(client *autorest.Client, auth autorest.Authorizer) {
+	client.UserAgent = buildUserAgent()
+	client.Authorizer = auth
+	client.Sender = buildSender()
+	client.SkipResourceProviderRegistration = false
+	client.PollingDuration = 60 * time.Minute
+}
+
+func buildUserAgent() string {
+	userAgent := httpclient.TerraformUserAgent(version.Version)
+
+	// append the CloudShell version to the user agent if it exists
+	if azureAgent := os.Getenv("AZURE_HTTP_USER_AGENT"); azureAgent != "" {
+		userAgent = fmt.Sprintf("%s %s", userAgent, azureAgent)
+	}
+
+	return userAgent
+}
diff --git a/v1.5.7/internal/backend/remote-state/azure/backend.go b/v1.5.7/internal/backend/remote-state/azure/backend.go
new file mode 100644
index 0000000..89cec85
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/azure/backend.go
@@ -0,0 +1,274 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package azure
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/legacy/helper/schema"
+)
+
+// New creates a new backend for Azure remote state.
+func New() backend.Backend {
+	s := &schema.Backend{
+		Schema: map[string]*schema.Schema{
+			"storage_account_name": {
+				Type:        schema.TypeString,
+				Required:    true,
+				Description: "The name of the storage account.",
+			},
+
+			"container_name": {
+				Type:        schema.TypeString,
+				Required:    true,
+				Description: "The container name.",
+			},
+
+			"key": {
+				Type:        schema.TypeString,
+				Required:    true,
+				Description: "The blob key.",
+			},
+
+			"metadata_host": {
+				Type:        schema.TypeString,
+				Required:    true,
+				DefaultFunc: schema.EnvDefaultFunc("ARM_METADATA_HOST", ""),
+				Description: "The Metadata URL which will be used to obtain the Cloud Environment.",
+			},
+
+			"environment": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The Azure cloud environment.",
+				DefaultFunc: schema.EnvDefaultFunc("ARM_ENVIRONMENT", "public"),
+			},
+
+			"access_key": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The access key.",
+				DefaultFunc: schema.EnvDefaultFunc("ARM_ACCESS_KEY", ""),
+			},
+
+			"sas_token": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "A SAS Token used to interact with the Blob Storage Account.",
+				DefaultFunc: schema.EnvDefaultFunc("ARM_SAS_TOKEN", ""),
+			},
+
+			"snapshot": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "Enable/Disable automatic blob snapshotting",
+				DefaultFunc: schema.EnvDefaultFunc("ARM_SNAPSHOT", false),
+			},
+
+			"resource_group_name": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The resource group name.",
+			},
+
+			"client_id": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The Client ID.",
+				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_ID", ""),
+			},
+
+			"endpoint": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "A custom Endpoint used to access the Azure Resource Manager API's.",
+				DefaultFunc: schema.EnvDefaultFunc("ARM_ENDPOINT", ""),
+			},
+
+			"subscription_id": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The Subscription ID.",
+				DefaultFunc: schema.EnvDefaultFunc("ARM_SUBSCRIPTION_ID", ""),
+			},
+
+			"tenant_id": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The Tenant ID.",
+				DefaultFunc: schema.EnvDefaultFunc("ARM_TENANT_ID", ""),
+			},
+
+			// Service Principal (Client Certificate) specific
+			"client_certificate_password": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The password associated with the Client Certificate specified in `client_certificate_path`",
+				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_CERTIFICATE_PASSWORD", ""),
+			},
+			"client_certificate_path": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The path to the PFX file used as the Client Certificate when authenticating as a Service Principal",
+				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_CERTIFICATE_PATH", ""),
+			},
+
+			// Service Principal (Client Secret) specific
+			"client_secret": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The Client Secret.",
+				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_SECRET", ""),
+			},
+
+			// Managed Service Identity specific
+			"use_msi": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "Should Managed Service Identity be used?",
+				DefaultFunc: schema.EnvDefaultFunc("ARM_USE_MSI", false),
+			},
+			"msi_endpoint": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The Managed Service Identity Endpoint.",
+				DefaultFunc: schema.EnvDefaultFunc("ARM_MSI_ENDPOINT", ""),
+			},
+
+			// OIDC auth specific fields
+			"use_oidc": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("ARM_USE_OIDC", false),
+				Description: "Allow OIDC to be used for authentication",
+			},
+			"oidc_token": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("ARM_OIDC_TOKEN", ""),
+				Description: "A generic JWT token that can be used for OIDC authentication. Should not be used in conjunction with `oidc_request_token`.",
+			},
+			"oidc_token_file_path": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("ARM_OIDC_TOKEN_FILE_PATH", ""),
+				Description: "Path to file containing a generic JWT token that can be used for OIDC authentication. Should not be used in conjunction with `oidc_request_token`.",
+			},
+			"oidc_request_url": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.MultiEnvDefaultFunc([]string{"ARM_OIDC_REQUEST_URL", "ACTIONS_ID_TOKEN_REQUEST_URL"}, ""),
+				Description: "The URL of the OIDC provider from which to request an ID token. Needs to be used in conjunction with `oidc_request_token`. This is meant to be used for Github Actions.",
+			},
+			"oidc_request_token": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.MultiEnvDefaultFunc([]string{"ARM_OIDC_REQUEST_TOKEN", "ACTIONS_ID_TOKEN_REQUEST_TOKEN"}, ""),
+				Description: "The bearer token to use for the request to the OIDC providers `oidc_request_url` URL to fetch an ID token. Needs to be used in conjunction with `oidc_request_url`. This is meant to be used for Github Actions.",
+			},
+
+			// Feature Flags
+			"use_azuread_auth": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "Should Terraform use AzureAD Authentication to access the Blob?",
+				DefaultFunc: schema.EnvDefaultFunc("ARM_USE_AZUREAD", false),
+			},
+		},
+	}
+
+	result := &Backend{Backend: s}
+	result.Backend.ConfigureFunc = result.configure
+	return result
+}
+
+type Backend struct {
+	*schema.Backend
+
+	// The fields below are set from configure
+	armClient     *ArmClient
+	containerName string
+	keyName       string
+	accountName   string
+	snapshot      bool
+}
+
+type BackendConfig struct {
+	// Required
+	StorageAccountName string
+
+	// Optional
+	AccessKey                     string
+	ClientID                      string
+	ClientCertificatePassword     string
+	ClientCertificatePath         string
+	ClientSecret                  string
+	CustomResourceManagerEndpoint string
+	MetadataHost                  string
+	Environment                   string
+	MsiEndpoint                   string
+	OIDCToken                     string
+	OIDCTokenFilePath             string
+	OIDCRequestURL                string
+	OIDCRequestToken              string
+	ResourceGroupName             string
+	SasToken                      string
+	SubscriptionID                string
+	TenantID                      string
+	UseMsi                        bool
+	UseOIDC                       bool
+	UseAzureADAuthentication      bool
+}
+
+func (b *Backend) configure(ctx context.Context) error {
+	if b.containerName != "" {
+		return nil
+	}
+
+	// Grab the resource data
+	data := schema.FromContextBackendConfig(ctx)
+	b.containerName = data.Get("container_name").(string)
+	b.accountName = data.Get("storage_account_name").(string)
+	b.keyName = data.Get("key").(string)
+	b.snapshot = data.Get("snapshot").(bool)
+
+	config := BackendConfig{
+		AccessKey:                     data.Get("access_key").(string),
+		ClientID:                      data.Get("client_id").(string),
+		ClientCertificatePassword:     data.Get("client_certificate_password").(string),
+		ClientCertificatePath:         data.Get("client_certificate_path").(string),
+		ClientSecret:                  data.Get("client_secret").(string),
+		CustomResourceManagerEndpoint: data.Get("endpoint").(string),
+		MetadataHost:                  data.Get("metadata_host").(string),
+		Environment:                   data.Get("environment").(string),
+		MsiEndpoint:                   data.Get("msi_endpoint").(string),
+		OIDCToken:                     data.Get("oidc_token").(string),
+		OIDCTokenFilePath:             data.Get("oidc_token_file_path").(string),
+		OIDCRequestURL:                data.Get("oidc_request_url").(string),
+		OIDCRequestToken:              data.Get("oidc_request_token").(string),
+		ResourceGroupName:             data.Get("resource_group_name").(string),
+		SasToken:                      data.Get("sas_token").(string),
+		StorageAccountName:            data.Get("storage_account_name").(string),
+		SubscriptionID:                data.Get("subscription_id").(string),
+		TenantID:                      data.Get("tenant_id").(string),
+		UseMsi:                        data.Get("use_msi").(bool),
+		UseOIDC:                       data.Get("use_oidc").(bool),
+		UseAzureADAuthentication:      data.Get("use_azuread_auth").(bool),
+	}
+
+	armClient, err := buildArmClient(context.TODO(), config)
+	if err != nil {
+		return err
+	}
+
+	thingsNeededToLookupAccessKeySpecified := config.AccessKey == "" && config.SasToken == "" && config.ResourceGroupName == ""
+	if thingsNeededToLookupAccessKeySpecified && !config.UseAzureADAuthentication {
+		return fmt.Errorf("Either an Access Key / SAS Token or the Resource Group for the Storage Account must be specified - or Azure AD Authentication must be enabled")
+	}
+
+	b.armClient = armClient
+	return nil
+}
diff --git a/v1.5.7/internal/backend/remote-state/azure/backend_state.go b/v1.5.7/internal/backend/remote-state/azure/backend_state.go
new file mode 100644
index 0000000..1806cd8
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/azure/backend_state.go
@@ -0,0 +1,170 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package azure
+
+import (
+	"context"
+	"fmt"
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/tombuildsstuff/giovanni/storage/2018-11-09/blob/blobs"
+	"github.com/tombuildsstuff/giovanni/storage/2018-11-09/blob/containers"
+)
+
+const (
+	// This will be used as directory name, the odd looking colon is simply to
+	// reduce the chance of name conflicts with existing objects.
+	keyEnvPrefix = "env:"
+)
+
+func (b *Backend) Workspaces() ([]string, error) {
+	prefix := b.keyName + keyEnvPrefix
+	params := containers.ListBlobsInput{
+		Prefix: &prefix,
+	}
+
+	ctx := context.TODO()
+	client, err := b.armClient.getContainersClient(ctx)
+	if err != nil {
+		return nil, err
+	}
+	resp, err := client.ListBlobs(ctx, b.armClient.storageAccountName, b.containerName, params)
+	if err != nil {
+		return nil, err
+	}
+
+	envs := map[string]struct{}{}
+	for _, obj := range resp.Blobs.Blobs {
+		key := obj.Name
+		if strings.HasPrefix(key, prefix) {
+			name := strings.TrimPrefix(key, prefix)
+			// we store the state in a key, not a directory
+			if strings.Contains(name, "/") {
+				continue
+			}
+
+			envs[name] = struct{}{}
+		}
+	}
+
+	result := []string{backend.DefaultStateName}
+	for name := range envs {
+		result = append(result, name)
+	}
+	sort.Strings(result[1:])
+	return result, nil
+}
+
+func (b *Backend) DeleteWorkspace(name string, _ bool) error {
+	if name == backend.DefaultStateName || name == "" {
+		return fmt.Errorf("can't delete default state")
+	}
+
+	ctx := context.TODO()
+	client, err := b.armClient.getBlobClient(ctx)
+	if err != nil {
+		return err
+	}
+
+	if resp, err := client.Delete(ctx, b.armClient.storageAccountName, b.containerName, b.path(name), blobs.DeleteInput{}); err != nil {
+		if resp.Response.StatusCode != 404 {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
+	ctx := context.TODO()
+	blobClient, err := b.armClient.getBlobClient(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	client := &RemoteClient{
+		giovanniBlobClient: *blobClient,
+		containerName:      b.containerName,
+		keyName:            b.path(name),
+		accountName:        b.accountName,
+		snapshot:           b.snapshot,
+	}
+
+	stateMgr := &remote.State{Client: client}
+
+	// Grab the value
+	if err := stateMgr.RefreshState(); err != nil {
+		return nil, err
+	}
+	//if this isn't the default state name, we need to create the object so
+	//it's listed by States.
+	if v := stateMgr.State(); v == nil {
+		// take a lock on this state while we write it
+		lockInfo := statemgr.NewLockInfo()
+		lockInfo.Operation = "init"
+		lockId, err := client.Lock(lockInfo)
+		if err != nil {
+			return nil, fmt.Errorf("failed to lock azure state: %s", err)
+		}
+
+		// Local helper function so we can call it multiple places
+		lockUnlock := func(parent error) error {
+			if err := stateMgr.Unlock(lockId); err != nil {
+				return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err)
+			}
+			return parent
+		}
+
+		// Grab the value
+		if err := stateMgr.RefreshState(); err != nil {
+			err = lockUnlock(err)
+			return nil, err
+		}
+		//if this isn't the default state name, we need to create the object so
+		//it's listed by States.
+		if v := stateMgr.State(); v == nil {
+			// If we have no state, we have to create an empty state
+			if err := stateMgr.WriteState(states.NewState()); err != nil {
+				err = lockUnlock(err)
+				return nil, err
+			}
+			if err := stateMgr.PersistState(nil); err != nil {
+				err = lockUnlock(err)
+				return nil, err
+			}
+
+			// Unlock, the state should now be initialized
+			if err := lockUnlock(nil); err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	return stateMgr, nil
+}
+
+func (b *Backend) client() *RemoteClient {
+	return &RemoteClient{}
+}
+
+func (b *Backend) path(name string) string {
+	if name == backend.DefaultStateName {
+		return b.keyName
+	}
+
+	return b.keyName + keyEnvPrefix + name
+}
+
+const errStateUnlock = `
+Error unlocking Azure state. Lock ID: %s
+
+Error: %s
+
+You may have to force-unlock this state in order to use it again.
+`
diff --git a/v1.5.7/internal/backend/remote-state/azure/backend_test.go b/v1.5.7/internal/backend/remote-state/azure/backend_test.go
new file mode 100644
index 0000000..d26a193
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/azure/backend_test.go
@@ -0,0 +1,369 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package azure
+
+import (
+	"context"
+	"os"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/legacy/helper/acctest"
+)
+
+func TestBackend_impl(t *testing.T) {
+	var _ backend.Backend = new(Backend)
+}
+
+func TestBackendConfig(t *testing.T) {
+	// This test just instantiates the client. Shouldn't make any actual
+	// requests nor incur any costs.
+
+	config := map[string]interface{}{
+		"storage_account_name": "tfaccount",
+		"container_name":       "tfcontainer",
+		"key":                  "state",
+		"snapshot":             false,
+		// Access Key must be Base64
+		"access_key": "QUNDRVNTX0tFWQ0K",
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(config)).(*Backend)
+
+	if b.containerName != "tfcontainer" {
+		t.Fatalf("Incorrect bucketName was populated")
+	}
+	if b.keyName != "state" {
+		t.Fatalf("Incorrect keyName was populated")
+	}
+	if b.snapshot != false {
+		t.Fatalf("Incorrect snapshot was populated")
+	}
+}
+
+func TestAccBackendAccessKeyBasic(t *testing.T) {
+	testAccAzureBackend(t)
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		armClient.destroyTestResources(ctx, res)
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"access_key":           res.storageAccountAccessKey,
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	backend.TestBackendStates(t, b)
+}
+
+func TestAccBackendSASTokenBasic(t *testing.T) {
+	testAccAzureBackend(t)
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	sasToken, err := buildSasToken(res.storageAccountName, res.storageAccountAccessKey)
+	if err != nil {
+		t.Fatalf("Error building SAS Token: %+v", err)
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"sas_token":            *sasToken,
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	backend.TestBackendStates(t, b)
+}
+
+func TestAccBackendOIDCBasic(t *testing.T) {
+	testAccAzureBackend(t)
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"resource_group_name":  res.resourceGroup,
+		"use_oidc":             true,
+		"subscription_id":      os.Getenv("ARM_SUBSCRIPTION_ID"),
+		"tenant_id":            os.Getenv("ARM_TENANT_ID"),
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	backend.TestBackendStates(t, b)
+}
+
+func TestAccBackendAzureADAuthBasic(t *testing.T) {
+	testAccAzureBackend(t)
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	res.useAzureADAuth = true
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		armClient.destroyTestResources(ctx, res)
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"access_key":           res.storageAccountAccessKey,
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+		"use_azuread_auth":     true,
+	})).(*Backend)
+
+	backend.TestBackendStates(t, b)
+}
+
+func TestAccBackendManagedServiceIdentityBasic(t *testing.T) {
+	testAccAzureBackendRunningInAzure(t)
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"resource_group_name":  res.resourceGroup,
+		"use_msi":              true,
+		"subscription_id":      os.Getenv("ARM_SUBSCRIPTION_ID"),
+		"tenant_id":            os.Getenv("ARM_TENANT_ID"),
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	backend.TestBackendStates(t, b)
+}
+
+func TestAccBackendServicePrincipalClientCertificateBasic(t *testing.T) {
+	testAccAzureBackend(t)
+
+	clientCertPassword := os.Getenv("ARM_CLIENT_CERTIFICATE_PASSWORD")
+	clientCertPath := os.Getenv("ARM_CLIENT_CERTIFICATE_PATH")
+	if clientCertPath == "" {
+		t.Skip("Skipping since `ARM_CLIENT_CERTIFICATE_PATH` is not specified!")
+	}
+
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name":        res.storageAccountName,
+		"container_name":              res.storageContainerName,
+		"key":                         res.storageKeyName,
+		"resource_group_name":         res.resourceGroup,
+		"subscription_id":             os.Getenv("ARM_SUBSCRIPTION_ID"),
+		"tenant_id":                   os.Getenv("ARM_TENANT_ID"),
+		"client_id":                   os.Getenv("ARM_CLIENT_ID"),
+		"client_certificate_password": clientCertPassword,
+		"client_certificate_path":     clientCertPath,
+		"environment":                 os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":                    os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	backend.TestBackendStates(t, b)
+}
+
+func TestAccBackendServicePrincipalClientSecretBasic(t *testing.T) {
+	testAccAzureBackend(t)
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"resource_group_name":  res.resourceGroup,
+		"subscription_id":      os.Getenv("ARM_SUBSCRIPTION_ID"),
+		"tenant_id":            os.Getenv("ARM_TENANT_ID"),
+		"client_id":            os.Getenv("ARM_CLIENT_ID"),
+		"client_secret":        os.Getenv("ARM_CLIENT_SECRET"),
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	backend.TestBackendStates(t, b)
+}
+
+func TestAccBackendServicePrincipalClientSecretCustomEndpoint(t *testing.T) {
+	testAccAzureBackend(t)
+
+	// this is only applicable for Azure Stack.
+	endpoint := os.Getenv("ARM_ENDPOINT")
+	if endpoint == "" {
+		t.Skip("Skipping as ARM_ENDPOINT isn't configured")
+	}
+
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"resource_group_name":  res.resourceGroup,
+		"subscription_id":      os.Getenv("ARM_SUBSCRIPTION_ID"),
+		"tenant_id":            os.Getenv("ARM_TENANT_ID"),
+		"client_id":            os.Getenv("ARM_CLIENT_ID"),
+		"client_secret":        os.Getenv("ARM_CLIENT_SECRET"),
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             endpoint,
+	})).(*Backend)
+
+	backend.TestBackendStates(t, b)
+}
+
+func TestAccBackendAccessKeyLocked(t *testing.T) {
+	testAccAzureBackend(t)
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"access_key":           res.storageAccountAccessKey,
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"access_key":           res.storageAccountAccessKey,
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	backend.TestBackendStateLocks(t, b1, b2)
+	backend.TestBackendStateForceUnlock(t, b1, b2)
+
+	backend.TestBackendStateLocksInWS(t, b1, b2, "foo")
+	backend.TestBackendStateForceUnlockInWS(t, b1, b2, "foo")
+}
+
+func TestAccBackendServicePrincipalLocked(t *testing.T) {
+	testAccAzureBackend(t)
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"access_key":           res.storageAccountAccessKey,
+		"subscription_id":      os.Getenv("ARM_SUBSCRIPTION_ID"),
+		"tenant_id":            os.Getenv("ARM_TENANT_ID"),
+		"client_id":            os.Getenv("ARM_CLIENT_ID"),
+		"client_secret":        os.Getenv("ARM_CLIENT_SECRET"),
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"access_key":           res.storageAccountAccessKey,
+		"subscription_id":      os.Getenv("ARM_SUBSCRIPTION_ID"),
+		"tenant_id":            os.Getenv("ARM_TENANT_ID"),
+		"client_id":            os.Getenv("ARM_CLIENT_ID"),
+		"client_secret":        os.Getenv("ARM_CLIENT_SECRET"),
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	backend.TestBackendStateLocks(t, b1, b2)
+	backend.TestBackendStateForceUnlock(t, b1, b2)
+
+	backend.TestBackendStateLocksInWS(t, b1, b2, "foo")
+	backend.TestBackendStateForceUnlockInWS(t, b1, b2, "foo")
+}
diff --git a/v1.5.7/internal/backend/remote-state/azure/client.go b/v1.5.7/internal/backend/remote-state/azure/client.go
new file mode 100644
index 0000000..a5126ac
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/azure/client.go
@@ -0,0 +1,282 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package azure
+
+import (
+	"context"
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"log"
+	"net/http"
+
+	"github.com/hashicorp/go-multierror"
+	"github.com/hashicorp/go-uuid"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/tombuildsstuff/giovanni/storage/2018-11-09/blob/blobs"
+)
+
+const (
+	leaseHeader = "x-ms-lease-id"
+	// Must be lower case
+	lockInfoMetaKey = "terraformlockid"
+)
+
+type RemoteClient struct {
+	giovanniBlobClient blobs.Client
+	accountName        string
+	containerName      string
+	keyName            string
+	leaseID            string
+	snapshot           bool
+}
+
+func (c *RemoteClient) Get() (*remote.Payload, error) {
+	options := blobs.GetInput{}
+	if c.leaseID != "" {
+		options.LeaseID = &c.leaseID
+	}
+
+	ctx := context.TODO()
+	blob, err := c.giovanniBlobClient.Get(ctx, c.accountName, c.containerName, c.keyName, options)
+	if err != nil {
+		if blob.Response.IsHTTPStatus(http.StatusNotFound) {
+			return nil, nil
+		}
+		return nil, err
+	}
+
+	payload := &remote.Payload{
+		Data: blob.Contents,
+	}
+
+	// If there was no data, then return nil
+	if len(payload.Data) == 0 {
+		return nil, nil
+	}
+
+	return payload, nil
+}
+
+func (c *RemoteClient) Put(data []byte) error {
+	getOptions := blobs.GetPropertiesInput{}
+	setOptions := blobs.SetPropertiesInput{}
+	putOptions := blobs.PutBlockBlobInput{}
+
+	options := blobs.GetInput{}
+	if c.leaseID != "" {
+		options.LeaseID = &c.leaseID
+		getOptions.LeaseID = &c.leaseID
+		setOptions.LeaseID = &c.leaseID
+		putOptions.LeaseID = &c.leaseID
+	}
+
+	ctx := context.TODO()
+
+	if c.snapshot {
+		snapshotInput := blobs.SnapshotInput{LeaseID: options.LeaseID}
+
+		log.Printf("[DEBUG] Snapshotting existing Blob %q (Container %q / Account %q)", c.keyName, c.containerName, c.accountName)
+		if _, err := c.giovanniBlobClient.Snapshot(ctx, c.accountName, c.containerName, c.keyName, snapshotInput); err != nil {
+			return fmt.Errorf("error snapshotting Blob %q (Container %q / Account %q): %+v", c.keyName, c.containerName, c.accountName, err)
+		}
+
+		log.Print("[DEBUG] Created blob snapshot")
+	}
+
+	blob, err := c.giovanniBlobClient.GetProperties(ctx, c.accountName, c.containerName, c.keyName, getOptions)
+	if err != nil {
+		if blob.StatusCode != 404 {
+			return err
+		}
+	}
+
+	contentType := "application/json"
+	putOptions.Content = &data
+	putOptions.ContentType = &contentType
+	putOptions.MetaData = blob.MetaData
+	_, err = c.giovanniBlobClient.PutBlockBlob(ctx, c.accountName, c.containerName, c.keyName, putOptions)
+
+	return err
+}
+
+func (c *RemoteClient) Delete() error {
+	options := blobs.DeleteInput{}
+
+	if c.leaseID != "" {
+		options.LeaseID = &c.leaseID
+	}
+
+	ctx := context.TODO()
+	resp, err := c.giovanniBlobClient.Delete(ctx, c.accountName, c.containerName, c.keyName, options)
+	if err != nil {
+		if !resp.IsHTTPStatus(http.StatusNotFound) {
+			return err
+		}
+	}
+	return nil
+}
+
+func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
+	stateName := fmt.Sprintf("%s/%s", c.containerName, c.keyName)
+	info.Path = stateName
+
+	if info.ID == "" {
+		lockID, err := uuid.GenerateUUID()
+		if err != nil {
+			return "", err
+		}
+
+		info.ID = lockID
+	}
+
+	getLockInfoErr := func(err error) error {
+		lockInfo, infoErr := c.getLockInfo()
+		if infoErr != nil {
+			err = multierror.Append(err, infoErr)
+		}
+
+		return &statemgr.LockError{
+			Err:  err,
+			Info: lockInfo,
+		}
+	}
+
+	leaseOptions := blobs.AcquireLeaseInput{
+		ProposedLeaseID: &info.ID,
+		LeaseDuration:   -1,
+	}
+	ctx := context.TODO()
+
+	// obtain properties to see if the blob lease is already in use. If the blob doesn't exist, create it
+	properties, err := c.giovanniBlobClient.GetProperties(ctx, c.accountName, c.containerName, c.keyName, blobs.GetPropertiesInput{})
+	if err != nil {
+		// error if we had issues getting the blob
+		if !properties.Response.IsHTTPStatus(http.StatusNotFound) {
+			return "", getLockInfoErr(err)
+		}
+		// if we don't find the blob, we need to build it
+
+		contentType := "application/json"
+		putGOptions := blobs.PutBlockBlobInput{
+			ContentType: &contentType,
+		}
+
+		_, err = c.giovanniBlobClient.PutBlockBlob(ctx, c.accountName, c.containerName, c.keyName, putGOptions)
+		if err != nil {
+			return "", getLockInfoErr(err)
+		}
+	}
+
+	// if the blob is already locked then error
+	if properties.LeaseStatus == blobs.Locked {
+		return "", getLockInfoErr(fmt.Errorf("state blob is already locked"))
+	}
+
+	leaseID, err := c.giovanniBlobClient.AcquireLease(ctx, c.accountName, c.containerName, c.keyName, leaseOptions)
+	if err != nil {
+		return "", getLockInfoErr(err)
+	}
+
+	info.ID = leaseID.LeaseID
+	c.leaseID = leaseID.LeaseID
+
+	if err := c.writeLockInfo(info); err != nil {
+		return "", err
+	}
+
+	return info.ID, nil
+}
+
+func (c *RemoteClient) getLockInfo() (*statemgr.LockInfo, error) {
+	options := blobs.GetPropertiesInput{}
+	if c.leaseID != "" {
+		options.LeaseID = &c.leaseID
+	}
+
+	ctx := context.TODO()
+	blob, err := c.giovanniBlobClient.GetProperties(ctx, c.accountName, c.containerName, c.keyName, options)
+	if err != nil {
+		return nil, err
+	}
+
+	raw := blob.MetaData[lockInfoMetaKey]
+	if raw == "" {
+		return nil, fmt.Errorf("blob metadata %q was empty", lockInfoMetaKey)
+	}
+
+	data, err := base64.StdEncoding.DecodeString(raw)
+	if err != nil {
+		return nil, err
+	}
+
+	lockInfo := &statemgr.LockInfo{}
+	err = json.Unmarshal(data, lockInfo)
+	if err != nil {
+		return nil, err
+	}
+
+	return lockInfo, nil
+}
+
+// writes info to blob meta data, deletes metadata entry if info is nil
+func (c *RemoteClient) writeLockInfo(info *statemgr.LockInfo) error {
+	ctx := context.TODO()
+	blob, err := c.giovanniBlobClient.GetProperties(ctx, c.accountName, c.containerName, c.keyName, blobs.GetPropertiesInput{LeaseID: &c.leaseID})
+	if err != nil {
+		return err
+	}
+	if err != nil {
+		return err
+	}
+
+	if info == nil {
+		delete(blob.MetaData, lockInfoMetaKey)
+	} else {
+		value := base64.StdEncoding.EncodeToString(info.Marshal())
+		blob.MetaData[lockInfoMetaKey] = value
+	}
+
+	opts := blobs.SetMetaDataInput{
+		LeaseID:  &c.leaseID,
+		MetaData: blob.MetaData,
+	}
+
+	_, err = c.giovanniBlobClient.SetMetaData(ctx, c.accountName, c.containerName, c.keyName, opts)
+	return err
+}
+
+func (c *RemoteClient) Unlock(id string) error {
+	lockErr := &statemgr.LockError{}
+
+	lockInfo, err := c.getLockInfo()
+	if err != nil {
+		lockErr.Err = fmt.Errorf("failed to retrieve lock info: %s", err)
+		return lockErr
+	}
+	lockErr.Info = lockInfo
+
+	if lockInfo.ID != id {
+		lockErr.Err = fmt.Errorf("lock id %q does not match existing lock", id)
+		return lockErr
+	}
+
+	c.leaseID = lockInfo.ID
+	if err := c.writeLockInfo(nil); err != nil {
+		lockErr.Err = fmt.Errorf("failed to delete lock info from metadata: %s", err)
+		return lockErr
+	}
+
+	ctx := context.TODO()
+	_, err = c.giovanniBlobClient.ReleaseLease(ctx, c.accountName, c.containerName, c.keyName, id)
+	if err != nil {
+		lockErr.Err = err
+		return lockErr
+	}
+
+	c.leaseID = ""
+
+	return nil
+}
diff --git a/v1.5.7/internal/backend/remote-state/azure/client_test.go b/v1.5.7/internal/backend/remote-state/azure/client_test.go
new file mode 100644
index 0000000..c3cb694
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/azure/client_test.go
@@ -0,0 +1,314 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package azure
+
+import (
+	"context"
+	"os"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/legacy/helper/acctest"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/tombuildsstuff/giovanni/storage/2018-11-09/blob/blobs"
+)
+
+func TestRemoteClient_impl(t *testing.T) {
+	var _ remote.Client = new(RemoteClient)
+	var _ remote.ClientLocker = new(RemoteClient)
+}
+
+func TestRemoteClientAccessKeyBasic(t *testing.T) {
+	testAccAzureBackend(t)
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"access_key":           res.storageAccountAccessKey,
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	state, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestClient(t, state.(*remote.State).Client)
+}
+
+func TestRemoteClientManagedServiceIdentityBasic(t *testing.T) {
+	testAccAzureBackendRunningInAzure(t)
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"resource_group_name":  res.resourceGroup,
+		"use_msi":              true,
+		"subscription_id":      os.Getenv("ARM_SUBSCRIPTION_ID"),
+		"tenant_id":            os.Getenv("ARM_TENANT_ID"),
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	state, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestClient(t, state.(*remote.State).Client)
+}
+
+func TestRemoteClientSasTokenBasic(t *testing.T) {
+	testAccAzureBackend(t)
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	sasToken, err := buildSasToken(res.storageAccountName, res.storageAccountAccessKey)
+	if err != nil {
+		t.Fatalf("Error building SAS Token: %+v", err)
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"sas_token":            *sasToken,
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	state, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestClient(t, state.(*remote.State).Client)
+}
+
+func TestRemoteClientServicePrincipalBasic(t *testing.T) {
+	testAccAzureBackend(t)
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"resource_group_name":  res.resourceGroup,
+		"subscription_id":      os.Getenv("ARM_SUBSCRIPTION_ID"),
+		"tenant_id":            os.Getenv("ARM_TENANT_ID"),
+		"client_id":            os.Getenv("ARM_CLIENT_ID"),
+		"client_secret":        os.Getenv("ARM_CLIENT_SECRET"),
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	state, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestClient(t, state.(*remote.State).Client)
+}
+
+func TestRemoteClientAccessKeyLocks(t *testing.T) {
+	testAccAzureBackend(t)
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"access_key":           res.storageAccountAccessKey,
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"access_key":           res.storageAccountAccessKey,
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	s1, err := b1.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	s2, err := b2.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestRemoteLocks(t, s1.(*remote.State).Client, s2.(*remote.State).Client)
+}
+
+func TestRemoteClientServicePrincipalLocks(t *testing.T) {
+	testAccAzureBackend(t)
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"resource_group_name":  res.resourceGroup,
+		"subscription_id":      os.Getenv("ARM_SUBSCRIPTION_ID"),
+		"tenant_id":            os.Getenv("ARM_TENANT_ID"),
+		"client_id":            os.Getenv("ARM_CLIENT_ID"),
+		"client_secret":        os.Getenv("ARM_CLIENT_SECRET"),
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"storage_account_name": res.storageAccountName,
+		"container_name":       res.storageContainerName,
+		"key":                  res.storageKeyName,
+		"resource_group_name":  res.resourceGroup,
+		"subscription_id":      os.Getenv("ARM_SUBSCRIPTION_ID"),
+		"tenant_id":            os.Getenv("ARM_TENANT_ID"),
+		"client_id":            os.Getenv("ARM_CLIENT_ID"),
+		"client_secret":        os.Getenv("ARM_CLIENT_SECRET"),
+		"environment":          os.Getenv("ARM_ENVIRONMENT"),
+		"endpoint":             os.Getenv("ARM_ENDPOINT"),
+	})).(*Backend)
+
+	s1, err := b1.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	s2, err := b2.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestRemoteLocks(t, s1.(*remote.State).Client, s2.(*remote.State).Client)
+}
+
+func TestPutMaintainsMetaData(t *testing.T) {
+	testAccAzureBackend(t)
+	rs := acctest.RandString(4)
+	res := testResourceNames(rs, "testState")
+	armClient := buildTestClient(t, res)
+
+	ctx := context.TODO()
+	err := armClient.buildTestResources(ctx, &res)
+	defer armClient.destroyTestResources(ctx, res)
+	if err != nil {
+		t.Fatalf("Error creating Test Resources: %q", err)
+	}
+
+	headerName := "acceptancetest"
+	expectedValue := "f3b56bad-33ad-4b93-a600-7a66e9cbd1eb"
+
+	client, err := armClient.getBlobClient(ctx)
+	if err != nil {
+		t.Fatalf("Error building Blob Client: %+v", err)
+	}
+
+	_, err = client.PutBlockBlob(ctx, res.storageAccountName, res.storageContainerName, res.storageKeyName, blobs.PutBlockBlobInput{})
+	if err != nil {
+		t.Fatalf("Error Creating Block Blob: %+v", err)
+	}
+
+	blobReference, err := client.GetProperties(ctx, res.storageAccountName, res.storageContainerName, res.storageKeyName, blobs.GetPropertiesInput{})
+	if err != nil {
+		t.Fatalf("Error loading MetaData: %+v", err)
+	}
+
+	blobReference.MetaData[headerName] = expectedValue
+	opts := blobs.SetMetaDataInput{
+		MetaData: blobReference.MetaData,
+	}
+	_, err = client.SetMetaData(ctx, res.storageAccountName, res.storageContainerName, res.storageKeyName, opts)
+	if err != nil {
+		t.Fatalf("Error setting MetaData: %+v", err)
+	}
+
+	// update the metadata using the Backend
+	remoteClient := RemoteClient{
+		keyName:       res.storageKeyName,
+		containerName: res.storageContainerName,
+		accountName:   res.storageAccountName,
+
+		giovanniBlobClient: *client,
+	}
+
+	bytes := []byte(acctest.RandString(20))
+	err = remoteClient.Put(bytes)
+	if err != nil {
+		t.Fatalf("Error putting data: %+v", err)
+	}
+
+	// Verify it still exists
+	blobReference, err = client.GetProperties(ctx, res.storageAccountName, res.storageContainerName, res.storageKeyName, blobs.GetPropertiesInput{})
+	if err != nil {
+		t.Fatalf("Error loading MetaData: %+v", err)
+	}
+
+	if blobReference.MetaData[headerName] != expectedValue {
+		t.Fatalf("%q was not set to %q in the MetaData: %+v", headerName, expectedValue, blobReference.MetaData)
+	}
+}
diff --git a/v1.5.7/internal/backend/remote-state/azure/helpers_test.go b/v1.5.7/internal/backend/remote-state/azure/helpers_test.go
new file mode 100644
index 0000000..03012ac
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/azure/helpers_test.go
@@ -0,0 +1,231 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package azure
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"os"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources"
+	armStorage "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-01-01/storage"
+	"github.com/Azure/go-autorest/autorest"
+	sasStorage "github.com/hashicorp/go-azure-helpers/storage"
+	"github.com/tombuildsstuff/giovanni/storage/2018-11-09/blob/containers"
+)
+
+const (
+	// required for Azure Stack
+	sasSignedVersion = "2015-04-05"
+)
+
+// verify that we are doing ACC tests or the Azure tests specifically
+func testAccAzureBackend(t *testing.T) {
+	skip := os.Getenv("TF_ACC") == "" && os.Getenv("TF_AZURE_TEST") == ""
+	if skip {
+		t.Log("azure backend tests require setting TF_ACC or TF_AZURE_TEST")
+		t.Skip()
+	}
+}
+
+// these kind of tests can only run when within Azure (e.g. MSI)
+func testAccAzureBackendRunningInAzure(t *testing.T) {
+	testAccAzureBackend(t)
+
+	if os.Getenv("TF_RUNNING_IN_AZURE") == "" {
+		t.Skip("Skipping test since not running in Azure")
+	}
+}
+
+// these kind of tests can only run when within GitHub Actions (e.g. OIDC)
+func testAccAzureBackendRunningInGitHubActions(t *testing.T) {
+	testAccAzureBackend(t)
+
+	if os.Getenv("TF_RUNNING_IN_GITHUB_ACTIONS") == "" {
+		t.Skip("Skipping test since not running in GitHub Actions")
+	}
+}
+
+func buildTestClient(t *testing.T, res resourceNames) *ArmClient {
+	subscriptionID := os.Getenv("ARM_SUBSCRIPTION_ID")
+	tenantID := os.Getenv("ARM_TENANT_ID")
+	clientID := os.Getenv("ARM_CLIENT_ID")
+	clientSecret := os.Getenv("ARM_CLIENT_SECRET")
+	msiEnabled := strings.EqualFold(os.Getenv("ARM_USE_MSI"), "true")
+	environment := os.Getenv("ARM_ENVIRONMENT")
+
+	hasCredentials := (clientID != "" && clientSecret != "") || msiEnabled
+	if !hasCredentials {
+		t.Fatal("Azure credentials missing or incomplete")
+	}
+
+	if subscriptionID == "" {
+		t.Fatalf("Missing ARM_SUBSCRIPTION_ID")
+	}
+
+	if tenantID == "" {
+		t.Fatalf("Missing ARM_TENANT_ID")
+	}
+
+	if environment == "" {
+		t.Fatalf("Missing ARM_ENVIRONMENT")
+	}
+
+	// location isn't used in this method, but is in the other test methods
+	location := os.Getenv("ARM_LOCATION")
+	if location == "" {
+		t.Fatalf("Missing ARM_LOCATION")
+	}
+
+	// Endpoint is optional (only for Stack)
+	endpoint := os.Getenv("ARM_ENDPOINT")
+
+	armClient, err := buildArmClient(context.TODO(), BackendConfig{
+		SubscriptionID:                subscriptionID,
+		TenantID:                      tenantID,
+		ClientID:                      clientID,
+		ClientSecret:                  clientSecret,
+		CustomResourceManagerEndpoint: endpoint,
+		Environment:                   environment,
+		ResourceGroupName:             res.resourceGroup,
+		StorageAccountName:            res.storageAccountName,
+		UseMsi:                        msiEnabled,
+		UseAzureADAuthentication:      res.useAzureADAuth,
+	})
+	if err != nil {
+		t.Fatalf("Failed to build ArmClient: %+v", err)
+	}
+
+	return armClient
+}
+
+func buildSasToken(accountName, accessKey string) (*string, error) {
+	// grant full access to Objects in the Blob Storage Account
+	permissions := "rwdlacup" // full control
+	resourceTypes := "sco"    // service, container, object
+	services := "b"           // blob
+
+	// Details on how to do this are here:
+	// https://docs.microsoft.com/en-us/rest/api/storageservices/Constructing-an-Account-SAS
+	signedProtocol := "https,http"
+	signedIp := ""
+	signedVersion := sasSignedVersion
+
+	utcNow := time.Now().UTC()
+
+	// account for servers being up to 5 minutes out
+	startDate := utcNow.Add(time.Minute * -5).Format(time.RFC3339)
+	endDate := utcNow.Add(time.Hour * 24).Format(time.RFC3339)
+
+	sasToken, err := sasStorage.ComputeAccountSASToken(accountName, accessKey, permissions, services, resourceTypes,
+		startDate, endDate, signedProtocol, signedIp, signedVersion)
+	if err != nil {
+		return nil, fmt.Errorf("Error computing SAS Token: %+v", err)
+	}
+	log.Printf("SAS Token should be %q", sasToken)
+	return &sasToken, nil
+}
+
+type resourceNames struct {
+	resourceGroup           string
+	location                string
+	storageAccountName      string
+	storageContainerName    string
+	storageKeyName          string
+	storageAccountAccessKey string
+	useAzureADAuth          bool
+}
+
+func testResourceNames(rString string, keyName string) resourceNames {
+	return resourceNames{
+		resourceGroup:        fmt.Sprintf("acctestRG-backend-%s-%s", strings.Replace(time.Now().Local().Format("060102150405.00"), ".", "", 1), rString),
+		location:             os.Getenv("ARM_LOCATION"),
+		storageAccountName:   fmt.Sprintf("acctestsa%s", rString),
+		storageContainerName: "acctestcont",
+		storageKeyName:       keyName,
+		useAzureADAuth:       false,
+	}
+}
+
+func (c *ArmClient) buildTestResources(ctx context.Context, names *resourceNames) error {
+	log.Printf("Creating Resource Group %q", names.resourceGroup)
+	_, err := c.groupsClient.CreateOrUpdate(ctx, names.resourceGroup, resources.Group{Location: &names.location})
+	if err != nil {
+		return fmt.Errorf("failed to create test resource group: %s", err)
+	}
+
+	log.Printf("Creating Storage Account %q in Resource Group %q", names.storageAccountName, names.resourceGroup)
+	storageProps := armStorage.AccountCreateParameters{
+		Sku: &armStorage.Sku{
+			Name: armStorage.StandardLRS,
+			Tier: armStorage.Standard,
+		},
+		Location: &names.location,
+	}
+	if names.useAzureADAuth {
+		allowSharedKeyAccess := false
+		storageProps.AccountPropertiesCreateParameters = &armStorage.AccountPropertiesCreateParameters{
+			AllowSharedKeyAccess: &allowSharedKeyAccess,
+		}
+	}
+	future, err := c.storageAccountsClient.Create(ctx, names.resourceGroup, names.storageAccountName, storageProps)
+	if err != nil {
+		return fmt.Errorf("failed to create test storage account: %s", err)
+	}
+
+	err = future.WaitForCompletionRef(ctx, c.storageAccountsClient.Client)
+	if err != nil {
+		return fmt.Errorf("failed waiting for the creation of storage account: %s", err)
+	}
+
+	containersClient := containers.NewWithEnvironment(c.environment)
+	if names.useAzureADAuth {
+		containersClient.Client.Authorizer = *c.azureAdStorageAuth
+	} else {
+		log.Printf("fetching access key for storage account")
+		resp, err := c.storageAccountsClient.ListKeys(ctx, names.resourceGroup, names.storageAccountName, "")
+		if err != nil {
+			return fmt.Errorf("failed to list storage account keys %s:", err)
+		}
+
+		keys := *resp.Keys
+		accessKey := *keys[0].Value
+		names.storageAccountAccessKey = accessKey
+
+		storageAuth, err := autorest.NewSharedKeyAuthorizer(names.storageAccountName, accessKey, autorest.SharedKey)
+		if err != nil {
+			return fmt.Errorf("Error building Authorizer: %+v", err)
+		}
+
+		containersClient.Client.Authorizer = storageAuth
+	}
+
+	log.Printf("Creating Container %q in Storage Account %q (Resource Group %q)", names.storageContainerName, names.storageAccountName, names.resourceGroup)
+	_, err = containersClient.Create(ctx, names.storageAccountName, names.storageContainerName, containers.CreateInput{})
+	if err != nil {
+		return fmt.Errorf("failed to create storage container: %s", err)
+	}
+
+	return nil
+}
+
+func (c ArmClient) destroyTestResources(ctx context.Context, resources resourceNames) error {
+	log.Printf("[DEBUG] Deleting Resource Group %q..", resources.resourceGroup)
+	future, err := c.groupsClient.Delete(ctx, resources.resourceGroup)
+	if err != nil {
+		return fmt.Errorf("Error deleting Resource Group: %+v", err)
+	}
+
+	log.Printf("[DEBUG] Waiting for deletion of Resource Group %q..", resources.resourceGroup)
+	err = future.WaitForCompletionRef(ctx, c.groupsClient.Client)
+	if err != nil {
+		return fmt.Errorf("Error waiting for the deletion of Resource Group: %+v", err)
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/backend/remote-state/azure/sender.go b/v1.5.7/internal/backend/remote-state/azure/sender.go
new file mode 100644
index 0000000..fc2f94f
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/azure/sender.go
@@ -0,0 +1,67 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package azure
+
+import (
+	"log"
+	"net/http"
+	"net/http/httputil"
+
+	"github.com/Azure/go-autorest/autorest"
+	"github.com/hashicorp/terraform/internal/logging"
+)
+
+func buildSender() autorest.Sender {
+	return autorest.DecorateSender(&http.Client{
+		Transport: &http.Transport{
+			Proxy: http.ProxyFromEnvironment,
+		},
+	}, withRequestLogging())
+}
+
+func withRequestLogging() autorest.SendDecorator {
+	return func(s autorest.Sender) autorest.Sender {
+		return autorest.SenderFunc(func(r *http.Request) (*http.Response, error) {
+			// only log if logging's enabled
+			logLevel := logging.CurrentLogLevel()
+			if logLevel == "" {
+				return s.Do(r)
+			}
+
+			// strip the authorization header prior to printing
+			authHeaderName := "Authorization"
+			auth := r.Header.Get(authHeaderName)
+			if auth != "" {
+				r.Header.Del(authHeaderName)
+			}
+
+			// dump request to wire format
+			if dump, err := httputil.DumpRequestOut(r, true); err == nil {
+				log.Printf("[DEBUG] Azure Backend Request: \n%s\n", dump)
+			} else {
+				// fallback to basic message
+				log.Printf("[DEBUG] Azure Backend Request: %s to %s\n", r.Method, r.URL)
+			}
+
+			// add the auth header back
+			if auth != "" {
+				r.Header.Add(authHeaderName, auth)
+			}
+
+			resp, err := s.Do(r)
+			if resp != nil {
+				// dump response to wire format
+				if dump, err2 := httputil.DumpResponse(resp, true); err2 == nil {
+					log.Printf("[DEBUG] Azure Backend Response for %s: \n%s\n", r.URL, dump)
+				} else {
+					// fallback to basic message
+					log.Printf("[DEBUG] Azure Backend Response: %s for %s\n", resp.Status, r.URL)
+				}
+			} else {
+				log.Printf("[DEBUG] Request to %s completed with no response", r.URL)
+			}
+			return resp, err
+		})
+	}
+}
diff --git a/v1.5.7/internal/backend/remote-state/consul/backend.go b/v1.5.7/internal/backend/remote-state/consul/backend.go
new file mode 100644
index 0000000..cf233b9
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/consul/backend.go
@@ -0,0 +1,183 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package consul
+
+import (
+	"context"
+	"net"
+	"strings"
+	"time"
+
+	consulapi "github.com/hashicorp/consul/api"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/legacy/helper/schema"
+)
+
+// New creates a new backend for Consul remote state.
+func New() backend.Backend {
+	s := &schema.Backend{
+		Schema: map[string]*schema.Schema{
+			"path": &schema.Schema{
+				Type:        schema.TypeString,
+				Required:    true,
+				Description: "Path to store state in Consul",
+			},
+
+			"access_token": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "Access token for a Consul ACL",
+				Default:     "", // To prevent input
+			},
+
+			"address": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "Address to the Consul Cluster",
+				Default:     "", // To prevent input
+			},
+
+			"scheme": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "Scheme to communicate to Consul with",
+				Default:     "", // To prevent input
+			},
+
+			"datacenter": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "Datacenter to communicate with",
+				Default:     "", // To prevent input
+			},
+
+			"http_auth": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "HTTP Auth in the format of 'username:password'",
+				Default:     "", // To prevent input
+			},
+
+			"gzip": &schema.Schema{
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "Compress the state data using gzip",
+				Default:     false,
+			},
+
+			"lock": &schema.Schema{
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "Lock state access",
+				Default:     true,
+			},
+
+			"ca_file": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "A path to a PEM-encoded certificate authority used to verify the remote agent's certificate.",
+				DefaultFunc: schema.EnvDefaultFunc("CONSUL_CACERT", ""),
+			},
+
+			"cert_file": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "A path to a PEM-encoded certificate provided to the remote agent; requires use of key_file.",
+				DefaultFunc: schema.EnvDefaultFunc("CONSUL_CLIENT_CERT", ""),
+			},
+
+			"key_file": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "A path to a PEM-encoded private key, required if cert_file is specified.",
+				DefaultFunc: schema.EnvDefaultFunc("CONSUL_CLIENT_KEY", ""),
+			},
+		},
+	}
+
+	result := &Backend{Backend: s}
+	result.Backend.ConfigureFunc = result.configure
+	return result
+}
+
+type Backend struct {
+	*schema.Backend
+
+	// The fields below are set from configure
+	client     *consulapi.Client
+	configData *schema.ResourceData
+	lock       bool
+}
+
+func (b *Backend) configure(ctx context.Context) error {
+	// Grab the resource data
+	b.configData = schema.FromContextBackendConfig(ctx)
+
+	// Store the lock information
+	b.lock = b.configData.Get("lock").(bool)
+
+	data := b.configData
+
+	// Configure the client
+	config := consulapi.DefaultConfig()
+
+	// replace the default Transport Dialer to reduce the KeepAlive
+	config.Transport.DialContext = dialContext
+
+	if v, ok := data.GetOk("access_token"); ok && v.(string) != "" {
+		config.Token = v.(string)
+	}
+	if v, ok := data.GetOk("address"); ok && v.(string) != "" {
+		config.Address = v.(string)
+	}
+	if v, ok := data.GetOk("scheme"); ok && v.(string) != "" {
+		config.Scheme = v.(string)
+	}
+	if v, ok := data.GetOk("datacenter"); ok && v.(string) != "" {
+		config.Datacenter = v.(string)
+	}
+
+	if v, ok := data.GetOk("ca_file"); ok && v.(string) != "" {
+		config.TLSConfig.CAFile = v.(string)
+	}
+	if v, ok := data.GetOk("cert_file"); ok && v.(string) != "" {
+		config.TLSConfig.CertFile = v.(string)
+	}
+	if v, ok := data.GetOk("key_file"); ok && v.(string) != "" {
+		config.TLSConfig.KeyFile = v.(string)
+	}
+
+	if v, ok := data.GetOk("http_auth"); ok && v.(string) != "" {
+		auth := v.(string)
+
+		var username, password string
+		if strings.Contains(auth, ":") {
+			split := strings.SplitN(auth, ":", 2)
+			username = split[0]
+			password = split[1]
+		} else {
+			username = auth
+		}
+
+		config.HttpAuth = &consulapi.HttpBasicAuth{
+			Username: username,
+			Password: password,
+		}
+	}
+
+	client, err := consulapi.NewClient(config)
+	if err != nil {
+		return err
+	}
+
+	b.client = client
+	return nil
+}
+
+// dialContext is the DialContext function for the consul client transport.
+// This is stored in a package var to inject a different dialer for tests.
+var dialContext = (&net.Dialer{
+	Timeout:   30 * time.Second,
+	KeepAlive: 17 * time.Second,
+}).DialContext
diff --git a/v1.5.7/internal/backend/remote-state/consul/backend_state.go b/v1.5.7/internal/backend/remote-state/consul/backend_state.go
new file mode 100644
index 0000000..7b8ca28
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/consul/backend_state.go
@@ -0,0 +1,157 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package consul
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+const (
+	keyEnvPrefix = "-env:"
+)
+
+func (b *Backend) Workspaces() ([]string, error) {
+	// List our raw path
+	prefix := b.configData.Get("path").(string) + keyEnvPrefix
+	keys, _, err := b.client.KV().Keys(prefix, "/", nil)
+	if err != nil {
+		return nil, err
+	}
+
+	// Find the envs, we use a map since we can get duplicates with
+	// path suffixes.
+	envs := map[string]struct{}{}
+	for _, key := range keys {
+		// Consul should ensure this but it doesn't hurt to check again
+		if strings.HasPrefix(key, prefix) {
+			key = strings.TrimPrefix(key, prefix)
+
+			// Ignore anything with a "/" in it since we store the state
+			// directly in a key not a directory.
+			if idx := strings.IndexRune(key, '/'); idx >= 0 {
+				continue
+			}
+
+			envs[key] = struct{}{}
+		}
+	}
+
+	result := make([]string, 1, len(envs)+1)
+	result[0] = backend.DefaultStateName
+	for k, _ := range envs {
+		result = append(result, k)
+	}
+
+	return result, nil
+}
+
+func (b *Backend) DeleteWorkspace(name string, _ bool) error {
+	if name == backend.DefaultStateName || name == "" {
+		return fmt.Errorf("can't delete default state")
+	}
+
+	// Determine the path of the data
+	path := b.path(name)
+
+	// Delete it. We just delete it without any locking since
+	// the DeleteState API is documented as such.
+	_, err := b.client.KV().Delete(path, nil)
+	return err
+}
+
+func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
+	// Determine the path of the data
+	path := b.path(name)
+
+	// Determine whether to gzip or not
+	gzip := b.configData.Get("gzip").(bool)
+
+	// Build the state client
+	var stateMgr = &remote.State{
+		Client: &RemoteClient{
+			Client:    b.client,
+			Path:      path,
+			GZip:      gzip,
+			lockState: b.lock,
+		},
+	}
+
+	if !b.lock {
+		stateMgr.DisableLocks()
+	}
+
+	// the default state always exists
+	if name == backend.DefaultStateName {
+		return stateMgr, nil
+	}
+
+	// Grab a lock, we use this to write an empty state if one doesn't
+	// exist already. We have to write an empty state as a sentinel value
+	// so States() knows it exists.
+	lockInfo := statemgr.NewLockInfo()
+	lockInfo.Operation = "init"
+	lockId, err := stateMgr.Lock(lockInfo)
+	if err != nil {
+		return nil, fmt.Errorf("failed to lock state in Consul: %s", err)
+	}
+
+	// Local helper function so we can call it multiple places
+	lockUnlock := func(parent error) error {
+		if err := stateMgr.Unlock(lockId); err != nil {
+			return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err)
+		}
+
+		return parent
+	}
+
+	// Grab the value
+	if err := stateMgr.RefreshState(); err != nil {
+		err = lockUnlock(err)
+		return nil, err
+	}
+
+	// If we have no state, we have to create an empty state
+	if v := stateMgr.State(); v == nil {
+		if err := stateMgr.WriteState(states.NewState()); err != nil {
+			err = lockUnlock(err)
+			return nil, err
+		}
+		if err := stateMgr.PersistState(nil); err != nil {
+			err = lockUnlock(err)
+			return nil, err
+		}
+	}
+
+	// Unlock, the state should now be initialized
+	if err := lockUnlock(nil); err != nil {
+		return nil, err
+	}
+
+	return stateMgr, nil
+}
+
+func (b *Backend) path(name string) string {
+	path := b.configData.Get("path").(string)
+	if name != backend.DefaultStateName {
+		path += fmt.Sprintf("%s%s", keyEnvPrefix, name)
+	}
+
+	return path
+}
+
+const errStateUnlock = `
+Error unlocking Consul state. Lock ID: %s
+
+Error: %s
+
+You may have to force-unlock this state in order to use it again.
+The Consul backend acquires a lock during initialization to ensure
+the minimum required key/values are prepared.
+`
diff --git a/v1.5.7/internal/backend/remote-state/consul/backend_test.go b/v1.5.7/internal/backend/remote-state/consul/backend_test.go
new file mode 100644
index 0000000..284b00f
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/consul/backend_test.go
@@ -0,0 +1,106 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package consul
+
+import (
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/consul/sdk/testutil"
+	"github.com/hashicorp/terraform/internal/backend"
+)
+
+func TestBackend_impl(t *testing.T) {
+	var _ backend.Backend = new(Backend)
+}
+
+func newConsulTestServer(t *testing.T) *testutil.TestServer {
+	if os.Getenv("TF_ACC") == "" && os.Getenv("TF_CONSUL_TEST") == "" {
+		t.Skipf("consul server tests require setting TF_ACC or TF_CONSUL_TEST")
+	}
+
+	srv, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) {
+		c.LogLevel = "warn"
+
+		if !flag.Parsed() {
+			flag.Parse()
+		}
+
+		if !testing.Verbose() {
+			c.Stdout = ioutil.Discard
+			c.Stderr = ioutil.Discard
+		}
+	})
+
+	if err != nil {
+		t.Fatalf("failed to create consul test server: %s", err)
+	}
+
+	srv.WaitForSerfCheck(t)
+	srv.WaitForLeader(t)
+
+	return srv
+}
+
+func TestBackend(t *testing.T) {
+	srv := newConsulTestServer(t)
+
+	path := fmt.Sprintf("tf-unit/%s", time.Now().String())
+
+	// Get the backend. We need two to test locking.
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"address": srv.HTTPAddr,
+		"path":    path,
+	}))
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"address": srv.HTTPAddr,
+		"path":    path,
+	}))
+
+	// Test
+	backend.TestBackendStates(t, b1)
+	backend.TestBackendStateLocks(t, b1, b2)
+}
+
+func TestBackend_lockDisabled(t *testing.T) {
+	srv := newConsulTestServer(t)
+
+	path := fmt.Sprintf("tf-unit/%s", time.Now().String())
+
+	// Get the backend. We need two to test locking.
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"address": srv.HTTPAddr,
+		"path":    path,
+		"lock":    false,
+	}))
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"address": srv.HTTPAddr,
+		"path":    path + "different", // Diff so locking test would fail if it was locking
+		"lock":    false,
+	}))
+
+	// Test
+	backend.TestBackendStates(t, b1)
+	backend.TestBackendStateLocks(t, b1, b2)
+}
+
+func TestBackend_gzip(t *testing.T) {
+	srv := newConsulTestServer(t)
+
+	// Get the backend
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"address": srv.HTTPAddr,
+		"path":    fmt.Sprintf("tf-unit/%s", time.Now().String()),
+		"gzip":    true,
+	}))
+
+	// Test
+	backend.TestBackendStates(t, b)
+}
diff --git a/v1.5.7/internal/backend/remote-state/consul/client.go b/v1.5.7/internal/backend/remote-state/consul/client.go
new file mode 100644
index 0000000..70cf6e4
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/consul/client.go
@@ -0,0 +1,689 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package consul
+
+import (
+	"bytes"
+	"compress/gzip"
+	"context"
+	"crypto/md5"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"log"
+	"strings"
+	"sync"
+	"time"
+
+	consulapi "github.com/hashicorp/consul/api"
+	multierror "github.com/hashicorp/go-multierror"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+const (
+	lockSuffix     = "/.lock"
+	lockInfoSuffix = "/.lockinfo"
+
+	// The Session TTL associated with this lock.
+	lockSessionTTL = "15s"
+
+	// the delay time from when a session is lost to when the
+	// lock is released by the server
+	lockDelay = 5 * time.Second
+	// interval between attempts to reacquire a lost lock
+	lockReacquireInterval = 2 * time.Second
+)
+
+var lostLockErr = errors.New("consul lock was lost")
+
+// RemoteClient is a remote client that stores data in Consul.
+type RemoteClient struct {
+	Client *consulapi.Client
+	Path   string
+	GZip   bool
+
+	mu sync.Mutex
+	// lockState is true if we're using locks
+	lockState bool
+
+	// The index of the last state we wrote.
+	// If this is > 0, Put will perform a CAS to ensure that the state wasn't
+	// changed during the operation. This is important even with locks, because
+	// if the client loses the lock for some reason, then reacquires it, we
+	// need to make sure that the state was not modified.
+	modifyIndex uint64
+
+	consulLock *consulapi.Lock
+	lockCh     <-chan struct{}
+
+	info *statemgr.LockInfo
+
+	// cancel our goroutine which is monitoring the lock to automatically
+	// reacquire it when possible.
+	monitorCancel context.CancelFunc
+	monitorWG     sync.WaitGroup
+
+	// sessionCancel cancels the Context use for session.RenewPeriodic, and is
+	// called when unlocking, or before creating a new lock if the lock is
+	// lost.
+	sessionCancel context.CancelFunc
+}
+
+func (c *RemoteClient) Get() (*remote.Payload, error) {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	kv := c.Client.KV()
+
+	chunked, hash, chunks, pair, err := c.chunkedMode()
+	if err != nil {
+		return nil, err
+	}
+	if pair == nil {
+		return nil, nil
+	}
+
+	c.modifyIndex = pair.ModifyIndex
+
+	var payload []byte
+	if chunked {
+		for _, c := range chunks {
+			pair, _, err := kv.Get(c, nil)
+			if err != nil {
+				return nil, err
+			}
+			if pair == nil {
+				return nil, fmt.Errorf("Key %q could not be found", c)
+			}
+			payload = append(payload, pair.Value[:]...)
+		}
+	} else {
+		payload = pair.Value
+	}
+
+	// If the payload starts with 0x1f, it's gzip, not json
+	if len(payload) >= 1 && payload[0] == '\x1f' {
+		payload, err = uncompressState(payload)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	md5 := md5.Sum(payload)
+
+	if hash != "" && fmt.Sprintf("%x", md5) != hash {
+		return nil, fmt.Errorf("The remote state does not match the expected hash")
+	}
+
+	return &remote.Payload{
+		Data: payload,
+		MD5:  md5[:],
+	}, nil
+}
+
+func (c *RemoteClient) Put(data []byte) error {
+	// The state can be stored in 4 different ways, based on the payload size
+	// and whether the user enabled gzip:
+	//  - single entry mode with plain JSON: a single JSON is stored at
+	//	  "tfstate/my_project"
+	//  - single entry mode gzip: the JSON payload is first gziped and stored at
+	//    "tfstate/my_project"
+	//  - chunked mode with plain JSON: the JSON payload is split in pieces and
+	//    stored like so:
+	//       - "tfstate/my_project" -> a JSON payload that contains the path of
+	//         the chunks and an MD5 sum like so:
+	//              {
+	//              	"current-hash": "abcdef1234",
+	//              	"chunks": [
+	//              		"tfstate/my_project/tfstate.abcdef1234/0",
+	//              		"tfstate/my_project/tfstate.abcdef1234/1",
+	//              		"tfstate/my_project/tfstate.abcdef1234/2",
+	//              	]
+	//              }
+	//       - "tfstate/my_project/tfstate.abcdef1234/0" -> The first chunk
+	//       - "tfstate/my_project/tfstate.abcdef1234/1" -> The next one
+	//       - ...
+	//  - chunked mode with gzip: the same system but we gziped the JSON payload
+	//    before splitting it in chunks
+	//
+	// When overwritting the current state, we need to clean the old chunks if
+	// we were in chunked mode (no matter whether we need to use chunks for the
+	// new one). To do so based on the 4 possibilities above we look at the
+	// value at "tfstate/my_project" and if it is:
+	//  - absent then it's a new state and there will be nothing to cleanup,
+	//  - not a JSON payload we were in single entry mode with gzip so there will
+	// 	  be nothing to cleanup
+	//  - a JSON payload, then we were either single entry mode with plain JSON
+	//    or in chunked mode. To differentiate between the two we look whether a
+	//    "current-hash" key is present in the payload. If we find one we were
+	//    in chunked mode and we will need to remove the old chunks (whether or
+	//    not we were using gzip does not matter in that case).
+
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	kv := c.Client.KV()
+
+	// First we determine what mode we were using and to prepare the cleanup
+	chunked, hash, _, _, err := c.chunkedMode()
+	if err != nil {
+		return err
+	}
+	cleanupOldChunks := func() {}
+	if chunked {
+		cleanupOldChunks = func() {
+			// We ignore all errors that can happen here because we already
+			// saved the new state and there is no way to return a warning to
+			// the user. We may end up with dangling chunks but there is no way
+			// to be sure we won't.
+			path := strings.TrimRight(c.Path, "/") + fmt.Sprintf("/tfstate.%s/", hash)
+			kv.DeleteTree(path, nil)
+		}
+	}
+
+	payload := data
+	if c.GZip {
+		if compressedState, err := compressState(data); err == nil {
+			payload = compressedState
+		} else {
+			return err
+		}
+	}
+
+	// default to doing a CAS
+	verb := consulapi.KVCAS
+
+	// Assume a 0 index doesn't need a CAS for now, since we are either
+	// creating a new state or purposely overwriting one.
+	if c.modifyIndex == 0 {
+		verb = consulapi.KVSet
+	}
+
+	// The payload may be too large to store in a single KV entry in Consul. We
+	// could try to determine whether it will fit or not before sending the
+	// request but since we are using the Transaction API and not the KV API,
+	// it grows by about a 1/3 when it is base64 encoded plus the overhead of
+	// the fields specific to the Transaction API.
+	// Rather than trying to calculate the overhead (which could change from
+	// one version of Consul to another, and between Consul Community Edition
+	// and Consul Enterprise), we try to send the whole state in one request, if
+	// it fails because it is too big we then split it in chunks and send each
+	// chunk separately.
+	// When splitting in chunks, we make each chunk 524288 bits, which is the
+	// default max size for raft. If the user changed it, we still may send
+	// chunks too big and fail but this is not a setting that should be fiddled
+	// with anyway.
+
+	store := func(payload []byte) error {
+		// KV.Put doesn't return the new index, so we use a single operation
+		// transaction to get the new index with a single request.
+		txOps := consulapi.KVTxnOps{
+			&consulapi.KVTxnOp{
+				Verb:  verb,
+				Key:   c.Path,
+				Value: payload,
+				Index: c.modifyIndex,
+			},
+		}
+
+		ok, resp, _, err := kv.Txn(txOps, nil)
+		if err != nil {
+			return err
+		}
+		// transaction was rolled back
+		if !ok {
+			var resultErr error
+			for _, respError := range resp.Errors {
+				resultErr = multierror.Append(resultErr, errors.New(respError.What))
+			}
+			return fmt.Errorf("consul CAS failed with transaction errors: %w", resultErr)
+		}
+
+		if len(resp.Results) != 1 {
+			// this probably shouldn't happen
+			return fmt.Errorf("expected on 1 response value, got: %d", len(resp.Results))
+		}
+
+		c.modifyIndex = resp.Results[0].ModifyIndex
+
+		// We remove all the old chunks
+		cleanupOldChunks()
+
+		return nil
+	}
+
+	if err = store(payload); err == nil {
+		// The payload was small enough to be stored
+		return nil
+	} else if !strings.Contains(err.Error(), "too large") {
+		// We failed for some other reason, report this to the user
+		return err
+	}
+
+	// The payload was too large so we split it in multiple chunks
+
+	md5 := md5.Sum(data)
+	chunks := split(payload, 524288)
+	chunkPaths := make([]string, 0)
+
+	// First we write the new chunks
+	for i, p := range chunks {
+		path := strings.TrimRight(c.Path, "/") + fmt.Sprintf("/tfstate.%x/%d", md5, i)
+		chunkPaths = append(chunkPaths, path)
+		_, err := kv.Put(&consulapi.KVPair{
+			Key:   path,
+			Value: p,
+		}, nil)
+
+		if err != nil {
+			return err
+		}
+	}
+
+	// Then we update the link to point to the new chunks
+	payload, err = json.Marshal(map[string]interface{}{
+		"current-hash": fmt.Sprintf("%x", md5),
+		"chunks":       chunkPaths,
+	})
+	if err != nil {
+		return err
+	}
+	return store(payload)
+}
+
+func (c *RemoteClient) Delete() error {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	kv := c.Client.KV()
+
+	chunked, hash, _, _, err := c.chunkedMode()
+	if err != nil {
+		return err
+	}
+
+	_, err = kv.Delete(c.Path, nil)
+
+	// If there were chunks we need to remove them
+	if chunked {
+		path := strings.TrimRight(c.Path, "/") + fmt.Sprintf("/tfstate.%s/", hash)
+		kv.DeleteTree(path, nil)
+	}
+
+	return err
+}
+
+func (c *RemoteClient) lockPath() string {
+	// we sanitize the path for the lock as Consul does not like having
+	// two consecutive slashes for the lock path
+	return strings.TrimRight(c.Path, "/")
+}
+
+func (c *RemoteClient) putLockInfo(info *statemgr.LockInfo) error {
+	info.Path = c.Path
+	info.Created = time.Now().UTC()
+
+	kv := c.Client.KV()
+	_, err := kv.Put(&consulapi.KVPair{
+		Key:   c.lockPath() + lockInfoSuffix,
+		Value: info.Marshal(),
+	}, nil)
+
+	return err
+}
+
+func (c *RemoteClient) getLockInfo() (*statemgr.LockInfo, error) {
+	path := c.lockPath() + lockInfoSuffix
+	pair, _, err := c.Client.KV().Get(path, nil)
+	if err != nil {
+		return nil, err
+	}
+	if pair == nil {
+		return nil, nil
+	}
+
+	li := &statemgr.LockInfo{}
+	err = json.Unmarshal(pair.Value, li)
+	if err != nil {
+		return nil, fmt.Errorf("error unmarshaling lock info: %s", err)
+	}
+
+	return li, nil
+}
+
+func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	if !c.lockState {
+		return "", nil
+	}
+
+	c.info = info
+
+	// These checks only are to ensure we strictly follow the specification.
+	// Terraform shouldn't ever re-lock, so provide errors for the 2 possible
+	// states if this is called.
+	select {
+	case <-c.lockCh:
+		// We had a lock, but lost it.
+		return "", errors.New("lost consul lock, cannot re-lock")
+	default:
+		if c.lockCh != nil {
+			// we have an active lock already
+			return "", fmt.Errorf("state %q already locked", c.Path)
+		}
+	}
+
+	return c.lock()
+}
+
+// the lock implementation.
+// Only to be called while holding Client.mu
+func (c *RemoteClient) lock() (string, error) {
+	// We create a new session here, so it can be canceled when the lock is
+	// lost or unlocked.
+	lockSession, err := c.createSession()
+	if err != nil {
+		return "", err
+	}
+
+	// store the session ID for correlation with consul logs
+	c.info.Info = "consul session: " + lockSession
+
+	// A random lock ID has been generated but we override it with the session
+	// ID as this will make it easier to manually invalidate the session
+	// if needed.
+	c.info.ID = lockSession
+
+	opts := &consulapi.LockOptions{
+		Key:     c.lockPath() + lockSuffix,
+		Session: lockSession,
+
+		// only wait briefly, so terraform has the choice to fail fast or
+		// retry as needed.
+		LockWaitTime: time.Second,
+		LockTryOnce:  true,
+
+		// Don't let the lock monitor give up right away, as it's possible the
+		// session is still OK. While the session is refreshed at a rate of
+		// TTL/2, the lock monitor is an idle blocking request and is more
+		// susceptible to being closed by a lower network layer.
+		MonitorRetries: 5,
+		//
+		// The delay between lock monitor retries.
+		// While the session has a 15s TTL plus a 5s wait period on a lost
+		// lock, if we can't get our lock back in 10+ seconds something is
+		// wrong so we're going to drop the session and start over.
+		MonitorRetryTime: 2 * time.Second,
+	}
+
+	c.consulLock, err = c.Client.LockOpts(opts)
+	if err != nil {
+		return "", err
+	}
+
+	lockErr := &statemgr.LockError{}
+
+	lockCh, err := c.consulLock.Lock(make(chan struct{}))
+	if err != nil {
+		lockErr.Err = err
+		return "", lockErr
+	}
+
+	if lockCh == nil {
+		lockInfo, e := c.getLockInfo()
+		if e != nil {
+			lockErr.Err = e
+			return "", lockErr
+		}
+
+		lockErr.Info = lockInfo
+
+		return "", lockErr
+	}
+
+	c.lockCh = lockCh
+
+	err = c.putLockInfo(c.info)
+	if err != nil {
+		if unlockErr := c.unlock(c.info.ID); unlockErr != nil {
+			err = multierror.Append(err, unlockErr)
+		}
+
+		return "", err
+	}
+
+	// Start a goroutine to monitor the lock state.
+	// If we lose the lock to due communication issues with the consul agent,
+	// attempt to immediately reacquire the lock. Put will verify the integrity
+	// of the state by using a CAS operation.
+	ctx, cancel := context.WithCancel(context.Background())
+	c.monitorCancel = cancel
+	c.monitorWG.Add(1)
+	go func() {
+		defer c.monitorWG.Done()
+		select {
+		case <-c.lockCh:
+			log.Println("[ERROR] lost consul lock")
+			for {
+				c.mu.Lock()
+				// We lost our lock, so we need to cancel the session too.
+				// The CancelFunc is only replaced while holding Client.mu, so
+				// this is safe to call here. This will be replaced by the
+				// lock() call below.
+				c.sessionCancel()
+
+				c.consulLock = nil
+				_, err := c.lock()
+				c.mu.Unlock()
+
+				if err != nil {
+					// We failed to get the lock, keep trying as long as
+					// terraform is running. There may be changes in progress,
+					// so there's no use in aborting. Either we eventually
+					// reacquire the lock, or a Put will fail on a CAS.
+					log.Printf("[ERROR] could not reacquire lock: %s", err)
+					time.Sleep(lockReacquireInterval)
+
+					select {
+					case <-ctx.Done():
+						return
+					default:
+					}
+					continue
+				}
+
+				// if the error was nil, the new lock started a new copy of
+				// this goroutine.
+				return
+			}
+
+		case <-ctx.Done():
+			return
+		}
+	}()
+
+	if testLockHook != nil {
+		testLockHook()
+	}
+
+	return c.info.ID, nil
+}
+
+// called after a lock is acquired
+var testLockHook func()
+
+func (c *RemoteClient) createSession() (string, error) {
+	// create the context first. Even if the session creation fails, we assume
+	// that the CancelFunc is always callable.
+	ctx, cancel := context.WithCancel(context.Background())
+	c.sessionCancel = cancel
+
+	session := c.Client.Session()
+	se := &consulapi.SessionEntry{
+		Name:      consulapi.DefaultLockSessionName,
+		TTL:       lockSessionTTL,
+		LockDelay: lockDelay,
+	}
+
+	id, _, err := session.Create(se, nil)
+	if err != nil {
+		return "", err
+	}
+
+	log.Println("[INFO] created consul lock session", id)
+
+	// keep the session renewed
+	go session.RenewPeriodic(lockSessionTTL, id, nil, ctx.Done())
+
+	return id, nil
+}
+
+func (c *RemoteClient) Unlock(id string) error {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	if !c.lockState {
+		return nil
+	}
+
+	return c.unlock(id)
+}
+
+// the unlock implementation.
+// Only to be called while holding Client.mu
+func (c *RemoteClient) unlock(id string) error {
+	// This method can be called in two circumstances:
+	// - when the plan apply or destroy operation finishes and the lock needs to be released,
+	// the watchdog stopped and the session closed
+	// - when the user calls `terraform force-unlock <lock_id>` in which case
+	// we only need to release the lock.
+
+	if c.consulLock == nil || c.lockCh == nil {
+		// The user called `terraform force-unlock <lock_id>`, we just destroy
+		// the session which will release the lock, clean the KV store and quit.
+
+		_, err := c.Client.Session().Destroy(id, nil)
+		if err != nil {
+			return err
+		}
+		// We ignore the errors that may happen during cleanup
+		kv := c.Client.KV()
+		kv.Delete(c.lockPath()+lockSuffix, nil)
+		kv.Delete(c.lockPath()+lockInfoSuffix, nil)
+
+		return nil
+	}
+
+	// cancel our monitoring goroutine
+	c.monitorCancel()
+
+	defer func() {
+		c.consulLock = nil
+
+		// The consul session is only used for this single lock, so cancel it
+		// after we unlock.
+		// The session is only created and replaced holding Client.mu, so the
+		// CancelFunc must be non-nil.
+		c.sessionCancel()
+	}()
+
+	select {
+	case <-c.lockCh:
+		return lostLockErr
+	default:
+	}
+
+	kv := c.Client.KV()
+
+	var errs error
+
+	if _, err := kv.Delete(c.lockPath()+lockInfoSuffix, nil); err != nil {
+		errs = multierror.Append(errs, err)
+	}
+
+	if err := c.consulLock.Unlock(); err != nil {
+		errs = multierror.Append(errs, err)
+	}
+
+	// the monitoring goroutine may be in a select on the lockCh, so we need to
+	// wait for it to return before changing the value.
+	c.monitorWG.Wait()
+	c.lockCh = nil
+
+	// This is only cleanup, and will fail if the lock was immediately taken by
+	// another client, so we don't report an error to the user here.
+	c.consulLock.Destroy()
+
+	return errs
+}
+
+func compressState(data []byte) ([]byte, error) {
+	b := new(bytes.Buffer)
+	gz := gzip.NewWriter(b)
+	if _, err := gz.Write(data); err != nil {
+		return nil, err
+	}
+	if err := gz.Flush(); err != nil {
+		return nil, err
+	}
+	if err := gz.Close(); err != nil {
+		return nil, err
+	}
+	return b.Bytes(), nil
+}
+
+func uncompressState(data []byte) ([]byte, error) {
+	b := new(bytes.Buffer)
+	gz, err := gzip.NewReader(bytes.NewReader(data))
+	if err != nil {
+		return nil, err
+	}
+	b.ReadFrom(gz)
+	if err := gz.Close(); err != nil {
+		return nil, err
+	}
+	return b.Bytes(), nil
+}
+
+func split(payload []byte, limit int) [][]byte {
+	var chunk []byte
+	chunks := make([][]byte, 0, len(payload)/limit+1)
+	for len(payload) >= limit {
+		chunk, payload = payload[:limit], payload[limit:]
+		chunks = append(chunks, chunk)
+	}
+	if len(payload) > 0 {
+		chunks = append(chunks, payload[:])
+	}
+	return chunks
+}
+
+func (c *RemoteClient) chunkedMode() (bool, string, []string, *consulapi.KVPair, error) {
+	kv := c.Client.KV()
+	pair, _, err := kv.Get(c.Path, nil)
+	if err != nil {
+		return false, "", nil, pair, err
+	}
+	if pair != nil {
+		var d map[string]interface{}
+		err = json.Unmarshal(pair.Value, &d)
+		// If there is an error when unmarshaling the payload, the state has
+		// probably been gziped in single entry mode.
+		if err == nil {
+			// If we find the "current-hash" key we were in chunked mode
+			hash, ok := d["current-hash"]
+			if ok {
+				chunks := make([]string, 0)
+				for _, c := range d["chunks"].([]interface{}) {
+					chunks = append(chunks, c.(string))
+				}
+				return true, hash.(string), chunks, pair, nil
+			}
+		}
+	}
+	return false, "", nil, pair, nil
+}
diff --git a/v1.5.7/internal/backend/remote-state/consul/client_test.go b/v1.5.7/internal/backend/remote-state/consul/client_test.go
new file mode 100644
index 0000000..6b156a1
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/consul/client_test.go
@@ -0,0 +1,494 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package consul
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"fmt"
+	"math/rand"
+	"net"
+	"reflect"
+	"strings"
+	"sync"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+func TestRemoteClient_impl(t *testing.T) {
+	var _ remote.Client = new(RemoteClient)
+	var _ remote.ClientLocker = new(RemoteClient)
+}
+
+func TestRemoteClient(t *testing.T) {
+	srv := newConsulTestServer(t)
+
+	testCases := []string{
+		fmt.Sprintf("tf-unit/%s", time.Now().String()),
+		fmt.Sprintf("tf-unit/%s/", time.Now().String()),
+	}
+
+	for _, path := range testCases {
+		t.Run(path, func(*testing.T) {
+			// Get the backend
+			b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+				"address": srv.HTTPAddr,
+				"path":    path,
+			}))
+
+			// Grab the client
+			state, err := b.StateMgr(backend.DefaultStateName)
+			if err != nil {
+				t.Fatalf("err: %s", err)
+			}
+
+			// Test
+			remote.TestClient(t, state.(*remote.State).Client)
+		})
+	}
+}
+
+// test the gzip functionality of the client
+func TestRemoteClient_gzipUpgrade(t *testing.T) {
+	srv := newConsulTestServer(t)
+
+	statePath := fmt.Sprintf("tf-unit/%s", time.Now().String())
+
+	// Get the backend
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"address": srv.HTTPAddr,
+		"path":    statePath,
+	}))
+
+	// Grab the client
+	state, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Test
+	remote.TestClient(t, state.(*remote.State).Client)
+
+	// create a new backend with gzip
+	b = backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"address": srv.HTTPAddr,
+		"path":    statePath,
+		"gzip":    true,
+	}))
+
+	// Grab the client
+	state, err = b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Test
+	remote.TestClient(t, state.(*remote.State).Client)
+}
+
+// TestConsul_largeState tries to write a large payload using the Consul state
+// manager, as there is a limit to the size of the values in the KV store it
+// will need to be split up before being saved and put back together when read.
+func TestConsul_largeState(t *testing.T) {
+	srv := newConsulTestServer(t)
+
+	path := "tf-unit/test-large-state"
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"address": srv.HTTPAddr,
+		"path":    path,
+	}))
+
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	c := s.(*remote.State).Client.(*RemoteClient)
+	c.Path = path
+
+	// testPaths fails the test if the keys found at the prefix don't match
+	// what is expected
+	testPaths := func(t *testing.T, expected []string) {
+		kv := c.Client.KV()
+		pairs, _, err := kv.List(c.Path, nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+		res := make([]string, 0)
+		for _, p := range pairs {
+			res = append(res, p.Key)
+		}
+		if !reflect.DeepEqual(res, expected) {
+			t.Fatalf("Wrong keys: %#v", res)
+		}
+	}
+
+	testPayload := func(t *testing.T, data map[string]string, keys []string) {
+		payload, err := json.Marshal(data)
+		if err != nil {
+			t.Fatal(err)
+		}
+		err = c.Put(payload)
+		if err != nil {
+			t.Fatal("could not put payload", err)
+		}
+
+		remote, err := c.Get()
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if !bytes.Equal(payload, remote.Data) {
+			t.Fatal("the data do not match")
+		}
+
+		testPaths(t, keys)
+	}
+
+	// The default limit for the size of the value in Consul is 524288 bytes
+	testPayload(
+		t,
+		map[string]string{
+			"foo": strings.Repeat("a", 524288+2),
+		},
+		[]string{
+			"tf-unit/test-large-state",
+			"tf-unit/test-large-state/tfstate.2cb96f52c9fff8e0b56cb786ec4d2bed/0",
+			"tf-unit/test-large-state/tfstate.2cb96f52c9fff8e0b56cb786ec4d2bed/1",
+		},
+	)
+
+	// This payload is just short enough to be stored but will be bigger when
+	// going through the Transaction API as it will be base64 encoded
+	testPayload(
+		t,
+		map[string]string{
+			"foo": strings.Repeat("a", 524288-10),
+		},
+		[]string{
+			"tf-unit/test-large-state",
+			"tf-unit/test-large-state/tfstate.4f407ace136a86521fd0d366972fe5c7/0",
+		},
+	)
+
+	// We try to replace the payload with a small one, the old chunks should be removed
+	testPayload(
+		t,
+		map[string]string{"var": "a"},
+		[]string{"tf-unit/test-large-state"},
+	)
+
+	// Test with gzip and chunks
+	b = backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"address": srv.HTTPAddr,
+		"path":    path,
+		"gzip":    true,
+	}))
+
+	s, err = b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	c = s.(*remote.State).Client.(*RemoteClient)
+	c.Path = path
+
+	// We need a long random string so it results in multiple chunks even after
+	// being gziped
+
+	// We use a fixed seed so the test can be reproductible
+	rand.Seed(1234)
+	RandStringRunes := func(n int) string {
+		var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
+		b := make([]rune, n)
+		for i := range b {
+			b[i] = letterRunes[rand.Intn(len(letterRunes))]
+		}
+		return string(b)
+	}
+
+	testPayload(
+		t,
+		map[string]string{
+			"bar": RandStringRunes(5 * (524288 + 2)),
+		},
+		[]string{
+			"tf-unit/test-large-state",
+			"tf-unit/test-large-state/tfstate.58e8160335864b520b1cc7f2222a4019/0",
+			"tf-unit/test-large-state/tfstate.58e8160335864b520b1cc7f2222a4019/1",
+			"tf-unit/test-large-state/tfstate.58e8160335864b520b1cc7f2222a4019/2",
+			"tf-unit/test-large-state/tfstate.58e8160335864b520b1cc7f2222a4019/3",
+		},
+	)
+
+	// Deleting the state should remove all chunks
+	err = c.Delete()
+	if err != nil {
+		t.Fatal(err)
+	}
+	testPaths(t, []string{})
+}
+
+func TestConsul_stateLock(t *testing.T) {
+	srv := newConsulTestServer(t)
+
+	testCases := []string{
+		fmt.Sprintf("tf-unit/%s", time.Now().String()),
+		fmt.Sprintf("tf-unit/%s/", time.Now().String()),
+	}
+
+	for _, path := range testCases {
+		t.Run(path, func(*testing.T) {
+			// create 2 instances to get 2 remote.Clients
+			sA, err := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+				"address": srv.HTTPAddr,
+				"path":    path,
+			})).StateMgr(backend.DefaultStateName)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			sB, err := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+				"address": srv.HTTPAddr,
+				"path":    path,
+			})).StateMgr(backend.DefaultStateName)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			remote.TestRemoteLocks(t, sA.(*remote.State).Client, sB.(*remote.State).Client)
+		})
+	}
+}
+
+func TestConsul_destroyLock(t *testing.T) {
+	srv := newConsulTestServer(t)
+
+	testCases := []string{
+		fmt.Sprintf("tf-unit/%s", time.Now().String()),
+		fmt.Sprintf("tf-unit/%s/", time.Now().String()),
+	}
+
+	testLock := func(client *RemoteClient, lockPath string) {
+		// get the lock val
+		pair, _, err := client.Client.KV().Get(lockPath, nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if pair != nil {
+			t.Fatalf("lock key not cleaned up at: %s", pair.Key)
+		}
+	}
+
+	for _, path := range testCases {
+		t.Run(path, func(*testing.T) {
+			// Get the backend
+			b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+				"address": srv.HTTPAddr,
+				"path":    path,
+			}))
+
+			// Grab the client
+			s, err := b.StateMgr(backend.DefaultStateName)
+			if err != nil {
+				t.Fatalf("err: %s", err)
+			}
+
+			clientA := s.(*remote.State).Client.(*RemoteClient)
+
+			info := statemgr.NewLockInfo()
+			id, err := clientA.Lock(info)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			lockPath := clientA.Path + lockSuffix
+
+			if err := clientA.Unlock(id); err != nil {
+				t.Fatal(err)
+			}
+
+			testLock(clientA, lockPath)
+
+			// The release the lock from a second client to test the
+			// `terraform force-unlock <lock_id>` functionnality
+			s, err = b.StateMgr(backend.DefaultStateName)
+			if err != nil {
+				t.Fatalf("err: %s", err)
+			}
+
+			clientB := s.(*remote.State).Client.(*RemoteClient)
+
+			info = statemgr.NewLockInfo()
+			id, err = clientA.Lock(info)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			if err := clientB.Unlock(id); err != nil {
+				t.Fatal(err)
+			}
+
+			testLock(clientA, lockPath)
+
+			err = clientA.Unlock(id)
+
+			if err == nil {
+				t.Fatal("consul lock should have been lost")
+			}
+			if err.Error() != "consul lock was lost" {
+				t.Fatal("got wrong error", err)
+			}
+		})
+	}
+}
+
+func TestConsul_lostLock(t *testing.T) {
+	srv := newConsulTestServer(t)
+
+	path := fmt.Sprintf("tf-unit/%s", time.Now().String())
+
+	// create 2 instances to get 2 remote.Clients
+	sA, err := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"address": srv.HTTPAddr,
+		"path":    path,
+	})).StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	sB, err := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"address": srv.HTTPAddr,
+		"path":    path + "-not-used",
+	})).StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	info := statemgr.NewLockInfo()
+	info.Operation = "test-lost-lock"
+	id, err := sA.Lock(info)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	reLocked := make(chan struct{})
+	testLockHook = func() {
+		close(reLocked)
+		testLockHook = nil
+	}
+
+	// now we use the second client to break the lock
+	kv := sB.(*remote.State).Client.(*RemoteClient).Client.KV()
+	_, err = kv.Delete(path+lockSuffix, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	<-reLocked
+
+	if err := sA.Unlock(id); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestConsul_lostLockConnection(t *testing.T) {
+	srv := newConsulTestServer(t)
+
+	// create an "unreliable" network by closing all the consul client's
+	// network connections
+	conns := &unreliableConns{}
+	origDialFn := dialContext
+	defer func() {
+		dialContext = origDialFn
+	}()
+	dialContext = conns.DialContext
+
+	path := fmt.Sprintf("tf-unit/%s", time.Now().String())
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"address": srv.HTTPAddr,
+		"path":    path,
+	}))
+
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	info := statemgr.NewLockInfo()
+	info.Operation = "test-lost-lock-connection"
+	id, err := s.Lock(info)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// kill the connection a few times
+	for i := 0; i < 3; i++ {
+		dialed := conns.dialedDone()
+		// kill any open connections
+		conns.Kill()
+		// wait for a new connection to be dialed, and kill it again
+		<-dialed
+	}
+
+	if err := s.Unlock(id); err != nil {
+		t.Fatal("unlock error:", err)
+	}
+}
+
+type unreliableConns struct {
+	sync.Mutex
+	conns        []net.Conn
+	dialCallback func()
+}
+
+func (u *unreliableConns) DialContext(ctx context.Context, netw, addr string) (net.Conn, error) {
+	u.Lock()
+	defer u.Unlock()
+
+	dialer := &net.Dialer{}
+	conn, err := dialer.DialContext(ctx, netw, addr)
+	if err != nil {
+		return nil, err
+	}
+
+	u.conns = append(u.conns, conn)
+
+	if u.dialCallback != nil {
+		u.dialCallback()
+	}
+
+	return conn, nil
+}
+
+func (u *unreliableConns) dialedDone() chan struct{} {
+	u.Lock()
+	defer u.Unlock()
+	dialed := make(chan struct{})
+	u.dialCallback = func() {
+		defer close(dialed)
+		u.dialCallback = nil
+	}
+
+	return dialed
+}
+
+// Kill these with a deadline, just to make sure we don't end up with any EOFs
+// that get ignored.
+func (u *unreliableConns) Kill() {
+	u.Lock()
+	defer u.Unlock()
+
+	for _, conn := range u.conns {
+		conn.(*net.TCPConn).SetDeadline(time.Now())
+	}
+	u.conns = nil
+}
diff --git a/v1.5.7/internal/backend/remote-state/cos/backend.go b/v1.5.7/internal/backend/remote-state/cos/backend.go
new file mode 100644
index 0000000..d4d8d3c
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/cos/backend.go
@@ -0,0 +1,338 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cos
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"net/url"
+	"os"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/legacy/helper/schema"
+	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
+	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
+	sts "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sts/v20180813"
+	tag "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tag/v20180813"
+	"github.com/tencentyun/cos-go-sdk-v5"
+)
+
+// Default value from environment variable
+const (
+	PROVIDER_SECRET_ID                    = "TENCENTCLOUD_SECRET_ID"
+	PROVIDER_SECRET_KEY                   = "TENCENTCLOUD_SECRET_KEY"
+	PROVIDER_SECURITY_TOKEN               = "TENCENTCLOUD_SECURITY_TOKEN"
+	PROVIDER_REGION                       = "TENCENTCLOUD_REGION"
+	PROVIDER_ASSUME_ROLE_ARN              = "TENCENTCLOUD_ASSUME_ROLE_ARN"
+	PROVIDER_ASSUME_ROLE_SESSION_NAME     = "TENCENTCLOUD_ASSUME_ROLE_SESSION_NAME"
+	PROVIDER_ASSUME_ROLE_SESSION_DURATION = "TENCENTCLOUD_ASSUME_ROLE_SESSION_DURATION"
+)
+
+// Backend implements "backend".Backend for tencentCloud cos
+type Backend struct {
+	*schema.Backend
+	credential *common.Credential
+
+	cosContext context.Context
+	cosClient  *cos.Client
+	tagClient  *tag.Client
+	stsClient  *sts.Client
+
+	region  string
+	bucket  string
+	prefix  string
+	key     string
+	encrypt bool
+	acl     string
+}
+
+// New creates a new backend for TencentCloud cos remote state.
+func New() backend.Backend {
+	s := &schema.Backend{
+		Schema: map[string]*schema.Schema{
+			"secret_id": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc(PROVIDER_SECRET_ID, nil),
+				Description: "Secret id of Tencent Cloud",
+			},
+			"secret_key": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc(PROVIDER_SECRET_KEY, nil),
+				Description: "Secret key of Tencent Cloud",
+				Sensitive:   true,
+			},
+			"security_token": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc(PROVIDER_SECURITY_TOKEN, nil),
+				Description: "TencentCloud Security Token of temporary access credentials. It can be sourced from the `TENCENTCLOUD_SECURITY_TOKEN` environment variable. Notice: for supported products, please refer to: [temporary key supported products](https://intl.cloud.tencent.com/document/product/598/10588).",
+				Sensitive:   true,
+			},
+			"region": {
+				Type:         schema.TypeString,
+				Required:     true,
+				DefaultFunc:  schema.EnvDefaultFunc(PROVIDER_REGION, nil),
+				Description:  "The region of the COS bucket",
+				InputDefault: "ap-guangzhou",
+			},
+			"bucket": {
+				Type:        schema.TypeString,
+				Required:    true,
+				Description: "The name of the COS bucket",
+			},
+			"prefix": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The directory for saving the state file in bucket",
+				ValidateFunc: func(v interface{}, s string) ([]string, []error) {
+					prefix := v.(string)
+					if strings.HasPrefix(prefix, "/") || strings.HasPrefix(prefix, "./") {
+						return nil, []error{fmt.Errorf("prefix must not start with '/' or './'")}
+					}
+					return nil, nil
+				},
+			},
+			"key": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The path for saving the state file in bucket",
+				Default:     "terraform.tfstate",
+				ValidateFunc: func(v interface{}, s string) ([]string, []error) {
+					if strings.HasPrefix(v.(string), "/") || strings.HasSuffix(v.(string), "/") {
+						return nil, []error{fmt.Errorf("key can not start and end with '/'")}
+					}
+					return nil, nil
+				},
+			},
+			"encrypt": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "Whether to enable server side encryption of the state file",
+				Default:     true,
+			},
+			"acl": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "Object ACL to be applied to the state file",
+				Default:     "private",
+				ValidateFunc: func(v interface{}, s string) ([]string, []error) {
+					value := v.(string)
+					if value != "private" && value != "public-read" {
+						return nil, []error{fmt.Errorf(
+							"acl value invalid, expected %s or %s, got %s",
+							"private", "public-read", value)}
+					}
+					return nil, nil
+				},
+			},
+			"accelerate": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "Whether to enable global Acceleration",
+				Default:     false,
+			},
+			"assume_role": {
+				Type:        schema.TypeSet,
+				Optional:    true,
+				MaxItems:    1,
+				Description: "The `assume_role` block. If provided, terraform will attempt to assume this role using the supplied credentials.",
+				Elem: &schema.Resource{
+					Schema: map[string]*schema.Schema{
+						"role_arn": {
+							Type:        schema.TypeString,
+							Required:    true,
+							DefaultFunc: schema.EnvDefaultFunc(PROVIDER_ASSUME_ROLE_ARN, nil),
+							Description: "The ARN of the role to assume. It can be sourced from the `TENCENTCLOUD_ASSUME_ROLE_ARN`.",
+						},
+						"session_name": {
+							Type:        schema.TypeString,
+							Required:    true,
+							DefaultFunc: schema.EnvDefaultFunc(PROVIDER_ASSUME_ROLE_SESSION_NAME, nil),
+							Description: "The session name to use when making the AssumeRole call. It can be sourced from the `TENCENTCLOUD_ASSUME_ROLE_SESSION_NAME`.",
+						},
+						"session_duration": {
+							Type:     schema.TypeInt,
+							Required: true,
+							DefaultFunc: func() (interface{}, error) {
+								if v := os.Getenv(PROVIDER_ASSUME_ROLE_SESSION_DURATION); v != "" {
+									return strconv.Atoi(v)
+								}
+								return 7200, nil
+							},
+							ValidateFunc: validateIntegerInRange(0, 43200),
+							Description:  "The duration of the session when making the AssumeRole call. Its value ranges from 0 to 43200(seconds), and default is 7200 seconds. It can be sourced from the `TENCENTCLOUD_ASSUME_ROLE_SESSION_DURATION`.",
+						},
+						"policy": {
+							Type:        schema.TypeString,
+							Optional:    true,
+							Description: "A more restrictive policy when making the AssumeRole call. Its content must not contains `principal` elements. Notice: more syntax references, please refer to: [policies syntax logic](https://intl.cloud.tencent.com/document/product/598/10603).",
+						},
+					},
+				},
+			},
+		},
+	}
+
+	result := &Backend{Backend: s}
+	result.Backend.ConfigureFunc = result.configure
+
+	return result
+}
+
+func validateIntegerInRange(min, max int64) schema.SchemaValidateFunc {
+	return func(v interface{}, k string) (ws []string, errors []error) {
+		value := int64(v.(int))
+		if value < min {
+			errors = append(errors, fmt.Errorf(
+				"%q cannot be lower than %d: %d", k, min, value))
+		}
+		if value > max {
+			errors = append(errors, fmt.Errorf(
+				"%q cannot be higher than %d: %d", k, max, value))
+		}
+		return
+	}
+}
+
+// configure init cos client
+func (b *Backend) configure(ctx context.Context) error {
+	if b.cosClient != nil {
+		return nil
+	}
+
+	b.cosContext = ctx
+	data := schema.FromContextBackendConfig(b.cosContext)
+
+	b.region = data.Get("region").(string)
+	b.bucket = data.Get("bucket").(string)
+	b.prefix = data.Get("prefix").(string)
+	b.key = data.Get("key").(string)
+	b.encrypt = data.Get("encrypt").(bool)
+	b.acl = data.Get("acl").(string)
+
+	var (
+		u   *url.URL
+		err error
+	)
+	accelerate := data.Get("accelerate").(bool)
+	if accelerate {
+		u, err = url.Parse(fmt.Sprintf("https://%s.cos.accelerate.myqcloud.com", b.bucket))
+	} else {
+		u, err = url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com", b.bucket, b.region))
+	}
+	if err != nil {
+		return err
+	}
+
+	secretId := data.Get("secret_id").(string)
+	secretKey := data.Get("secret_key").(string)
+	securityToken := data.Get("security_token").(string)
+
+	// init credential by AKSK & TOKEN
+	b.credential = common.NewTokenCredential(secretId, secretKey, securityToken)
+	// update credential if assume role exist
+	err = handleAssumeRole(data, b)
+	if err != nil {
+		return err
+	}
+
+	b.cosClient = cos.NewClient(
+		&cos.BaseURL{BucketURL: u},
+		&http.Client{
+			Timeout: 60 * time.Second,
+			Transport: &cos.AuthorizationTransport{
+				SecretID:     b.credential.SecretId,
+				SecretKey:    b.credential.SecretKey,
+				SessionToken: b.credential.Token,
+			},
+		},
+	)
+
+	b.tagClient = b.UseTagClient()
+	return err
+}
+
+func handleAssumeRole(data *schema.ResourceData, b *Backend) error {
+	assumeRoleList := data.Get("assume_role").(*schema.Set).List()
+	if len(assumeRoleList) == 1 {
+		assumeRole := assumeRoleList[0].(map[string]interface{})
+		assumeRoleArn := assumeRole["role_arn"].(string)
+		assumeRoleSessionName := assumeRole["session_name"].(string)
+		assumeRoleSessionDuration := assumeRole["session_duration"].(int)
+		assumeRolePolicy := assumeRole["policy"].(string)
+
+		err := b.updateCredentialWithSTS(assumeRoleArn, assumeRoleSessionName, assumeRoleSessionDuration, assumeRolePolicy)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (b *Backend) updateCredentialWithSTS(assumeRoleArn, assumeRoleSessionName string, assumeRoleSessionDuration int, assumeRolePolicy string) error {
+	// assume role by STS
+	request := sts.NewAssumeRoleRequest()
+	request.RoleArn = &assumeRoleArn
+	request.RoleSessionName = &assumeRoleSessionName
+	duration := uint64(assumeRoleSessionDuration)
+	request.DurationSeconds = &duration
+	if assumeRolePolicy != "" {
+		policy := url.QueryEscape(assumeRolePolicy)
+		request.Policy = &policy
+	}
+
+	response, err := b.UseStsClient().AssumeRole(request)
+	if err != nil {
+		return err
+	}
+	// update credentials by result of assume role
+	b.credential = common.NewTokenCredential(
+		*response.Response.Credentials.TmpSecretId,
+		*response.Response.Credentials.TmpSecretKey,
+		*response.Response.Credentials.Token,
+	)
+
+	return nil
+}
+
+// UseStsClient returns sts client for service
+func (b *Backend) UseStsClient() *sts.Client {
+	if b.stsClient != nil {
+		return b.stsClient
+	}
+	cpf := b.NewClientProfile(300)
+	b.stsClient, _ = sts.NewClient(b.credential, b.region, cpf)
+	b.stsClient.WithHttpTransport(&LogRoundTripper{})
+
+	return b.stsClient
+}
+
+// UseTagClient returns tag client for service
+func (b *Backend) UseTagClient() *tag.Client {
+	if b.tagClient != nil {
+		return b.tagClient
+	}
+	cpf := b.NewClientProfile(300)
+	cpf.Language = "en-US"
+	b.tagClient, _ = tag.NewClient(b.credential, b.region, cpf)
+	return b.tagClient
+}
+
+// NewClientProfile returns a new ClientProfile
+func (b *Backend) NewClientProfile(timeout int) *profile.ClientProfile {
+	cpf := profile.NewClientProfile()
+
+	// all request use method POST
+	cpf.HttpProfile.ReqMethod = "POST"
+	// request timeout
+	cpf.HttpProfile.ReqTimeout = timeout
+
+	return cpf
+}
diff --git a/v1.5.7/internal/backend/remote-state/cos/backend_state.go b/v1.5.7/internal/backend/remote-state/cos/backend_state.go
new file mode 100644
index 0000000..24d6517
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/cos/backend_state.go
@@ -0,0 +1,188 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cos
+
+import (
+	"fmt"
+	"log"
+	"path"
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+// Define file suffix
+const (
+	stateFileSuffix = ".tfstate"
+	lockFileSuffix  = ".tflock"
+)
+
+// Workspaces returns a list of names for the workspaces
+func (b *Backend) Workspaces() ([]string, error) {
+	c, err := b.client("tencentcloud")
+	if err != nil {
+		return nil, err
+	}
+
+	obs, err := c.getBucket(b.prefix)
+	log.Printf("[DEBUG] list all workspaces, objects: %v, error: %v", obs, err)
+	if err != nil {
+		return nil, err
+	}
+
+	ws := []string{backend.DefaultStateName}
+	for _, vv := range obs {
+		// <name>.tfstate
+		if !strings.HasSuffix(vv.Key, stateFileSuffix) {
+			continue
+		}
+		// default worksapce
+		if path.Join(b.prefix, b.key) == vv.Key {
+			continue
+		}
+		// <prefix>/<worksapce>/<key>
+		prefix := strings.TrimRight(b.prefix, "/") + "/"
+		parts := strings.Split(strings.TrimPrefix(vv.Key, prefix), "/")
+		if len(parts) > 0 && parts[0] != "" {
+			ws = append(ws, parts[0])
+		}
+	}
+
+	sort.Strings(ws[1:])
+	log.Printf("[DEBUG] list all workspaces, workspaces: %v", ws)
+
+	return ws, nil
+}
+
+// DeleteWorkspace deletes the named workspaces. The "default" state cannot be deleted.
+func (b *Backend) DeleteWorkspace(name string, _ bool) error {
+	log.Printf("[DEBUG] delete workspace, workspace: %v", name)
+
+	if name == backend.DefaultStateName || name == "" {
+		return fmt.Errorf("default state is not allow to delete")
+	}
+
+	c, err := b.client(name)
+	if err != nil {
+		return err
+	}
+
+	return c.Delete()
+}
+
+// StateMgr manage the state, if the named state not exists, a new file will created
+func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
+	log.Printf("[DEBUG] state manager, current workspace: %v", name)
+
+	c, err := b.client(name)
+	if err != nil {
+		return nil, err
+	}
+	stateMgr := &remote.State{Client: c}
+
+	ws, err := b.Workspaces()
+	if err != nil {
+		return nil, err
+	}
+
+	exists := false
+	for _, candidate := range ws {
+		if candidate == name {
+			exists = true
+			break
+		}
+	}
+
+	if !exists {
+		log.Printf("[DEBUG] workspace %v not exists", name)
+
+		// take a lock on this state while we write it
+		lockInfo := statemgr.NewLockInfo()
+		lockInfo.Operation = "init"
+		lockId, err := c.Lock(lockInfo)
+		if err != nil {
+			return nil, fmt.Errorf("Failed to lock cos state: %s", err)
+		}
+
+		// Local helper function so we can call it multiple places
+		lockUnlock := func(e error) error {
+			if err := stateMgr.Unlock(lockId); err != nil {
+				return fmt.Errorf(unlockErrMsg, err, lockId)
+			}
+			return e
+		}
+
+		// Grab the value
+		if err := stateMgr.RefreshState(); err != nil {
+			err = lockUnlock(err)
+			return nil, err
+		}
+
+		// If we have no state, we have to create an empty state
+		if v := stateMgr.State(); v == nil {
+			if err := stateMgr.WriteState(states.NewState()); err != nil {
+				err = lockUnlock(err)
+				return nil, err
+			}
+			if err := stateMgr.PersistState(nil); err != nil {
+				err = lockUnlock(err)
+				return nil, err
+			}
+		}
+
+		// Unlock, the state should now be initialized
+		if err := lockUnlock(nil); err != nil {
+			return nil, err
+		}
+	}
+
+	return stateMgr, nil
+}
+
+// client returns a remoteClient for the named state.
+func (b *Backend) client(name string) (*remoteClient, error) {
+	if strings.TrimSpace(name) == "" {
+		return nil, fmt.Errorf("state name not allow to be empty")
+	}
+
+	return &remoteClient{
+		cosContext: b.cosContext,
+		cosClient:  b.cosClient,
+		tagClient:  b.tagClient,
+		bucket:     b.bucket,
+		stateFile:  b.stateFile(name),
+		lockFile:   b.lockFile(name),
+		encrypt:    b.encrypt,
+		acl:        b.acl,
+	}, nil
+}
+
+// stateFile returns state file path by name
+func (b *Backend) stateFile(name string) string {
+	if name == backend.DefaultStateName {
+		return path.Join(b.prefix, b.key)
+	}
+	return path.Join(b.prefix, name, b.key)
+}
+
+// lockFile returns lock file path by name
+func (b *Backend) lockFile(name string) string {
+	return b.stateFile(name) + lockFileSuffix
+}
+
+// unlockErrMsg is error msg for unlock failed
+const unlockErrMsg = `
+Unlocking the state file on TencentCloud cos backend failed:
+
+Error message: %v
+Lock ID (gen): %s
+
+You may have to force-unlock this state in order to use it again.
+The TencentCloud backend acquires a lock during initialization
+to ensure the initial state file is created.
+`
diff --git a/v1.5.7/internal/backend/remote-state/cos/backend_test.go b/v1.5.7/internal/backend/remote-state/cos/backend_test.go
new file mode 100644
index 0000000..c5f803c
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/cos/backend_test.go
@@ -0,0 +1,259 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cos
+
+import (
+	"crypto/md5"
+	"fmt"
+	"os"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states/remote"
+)
+
+const (
+	defaultPrefix = ""
+	defaultKey    = "terraform.tfstate"
+)
+
+// Testing Thanks to GCS
+
+func TestStateFile(t *testing.T) {
+	t.Parallel()
+
+	cases := []struct {
+		prefix        string
+		stateName     string
+		key           string
+		wantStateFile string
+		wantLockFile  string
+	}{
+		{"", "default", "default.tfstate", "default.tfstate", "default.tfstate.tflock"},
+		{"", "default", "test.tfstate", "test.tfstate", "test.tfstate.tflock"},
+		{"", "dev", "test.tfstate", "dev/test.tfstate", "dev/test.tfstate.tflock"},
+		{"terraform/test", "default", "default.tfstate", "terraform/test/default.tfstate", "terraform/test/default.tfstate.tflock"},
+		{"terraform/test", "default", "test.tfstate", "terraform/test/test.tfstate", "terraform/test/test.tfstate.tflock"},
+		{"terraform/test", "dev", "test.tfstate", "terraform/test/dev/test.tfstate", "terraform/test/dev/test.tfstate.tflock"},
+	}
+
+	for _, c := range cases {
+		t.Run(fmt.Sprintf("%s %s %s", c.prefix, c.key, c.stateName), func(t *testing.T) {
+			b := &Backend{
+				prefix: c.prefix,
+				key:    c.key,
+			}
+			if got, want := b.stateFile(c.stateName), c.wantStateFile; got != want {
+				t.Errorf("wrong state file name\ngot:  %s\nwant: %s", got, want)
+			}
+			if got, want := b.lockFile(c.stateName), c.wantLockFile; got != want {
+				t.Errorf("wrong lock file name\ngot:  %s\nwant: %s", got, want)
+			}
+		})
+	}
+}
+
+func TestRemoteClient(t *testing.T) {
+	t.Parallel()
+
+	bucket := bucketName(t)
+
+	be := setupBackend(t, bucket, defaultPrefix, defaultKey, false)
+	defer teardownBackend(t, be)
+
+	ss, err := be.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	rs, ok := ss.(*remote.State)
+	if !ok {
+		t.Fatalf("wrong state manager type\ngot:  %T\nwant: %T", ss, rs)
+	}
+
+	remote.TestClient(t, rs.Client)
+}
+
+func TestRemoteClientWithPrefix(t *testing.T) {
+	t.Parallel()
+
+	prefix := "prefix/test"
+	bucket := bucketName(t)
+
+	be := setupBackend(t, bucket, prefix, defaultKey, false)
+	defer teardownBackend(t, be)
+
+	ss, err := be.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	rs, ok := ss.(*remote.State)
+	if !ok {
+		t.Fatalf("wrong state manager type\ngot:  %T\nwant: %T", ss, rs)
+	}
+
+	remote.TestClient(t, rs.Client)
+}
+
+func TestRemoteClientWithEncryption(t *testing.T) {
+	t.Parallel()
+
+	bucket := bucketName(t)
+
+	be := setupBackend(t, bucket, defaultPrefix, defaultKey, true)
+	defer teardownBackend(t, be)
+
+	ss, err := be.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	rs, ok := ss.(*remote.State)
+	if !ok {
+		t.Fatalf("wrong state manager type\ngot:  %T\nwant: %T", ss, rs)
+	}
+
+	remote.TestClient(t, rs.Client)
+}
+
+func TestRemoteLocks(t *testing.T) {
+	t.Parallel()
+
+	bucket := bucketName(t)
+
+	be := setupBackend(t, bucket, defaultPrefix, defaultKey, false)
+	defer teardownBackend(t, be)
+
+	remoteClient := func() (remote.Client, error) {
+		ss, err := be.StateMgr(backend.DefaultStateName)
+		if err != nil {
+			return nil, err
+		}
+
+		rs, ok := ss.(*remote.State)
+		if !ok {
+			return nil, fmt.Errorf("be.StateMgr(): got a %T, want a *remote.State", ss)
+		}
+
+		return rs.Client, nil
+	}
+
+	c0, err := remoteClient()
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	c1, err := remoteClient()
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	remote.TestRemoteLocks(t, c0, c1)
+}
+
+func TestBackend(t *testing.T) {
+	t.Parallel()
+
+	bucket := bucketName(t)
+
+	be0 := setupBackend(t, bucket, defaultPrefix, defaultKey, false)
+	defer teardownBackend(t, be0)
+
+	be1 := setupBackend(t, bucket, defaultPrefix, defaultKey, false)
+	defer teardownBackend(t, be1)
+
+	backend.TestBackendStates(t, be0)
+	backend.TestBackendStateLocks(t, be0, be1)
+	backend.TestBackendStateForceUnlock(t, be0, be1)
+}
+
+func TestBackendWithPrefix(t *testing.T) {
+	t.Parallel()
+
+	prefix := "prefix/test"
+	bucket := bucketName(t)
+
+	be0 := setupBackend(t, bucket, prefix, defaultKey, false)
+	defer teardownBackend(t, be0)
+
+	be1 := setupBackend(t, bucket, prefix+"/", defaultKey, false)
+	defer teardownBackend(t, be1)
+
+	backend.TestBackendStates(t, be0)
+	backend.TestBackendStateLocks(t, be0, be1)
+}
+
+func TestBackendWithEncryption(t *testing.T) {
+	t.Parallel()
+
+	bucket := bucketName(t)
+
+	be0 := setupBackend(t, bucket, defaultPrefix, defaultKey, true)
+	defer teardownBackend(t, be0)
+
+	be1 := setupBackend(t, bucket, defaultPrefix, defaultKey, true)
+	defer teardownBackend(t, be1)
+
+	backend.TestBackendStates(t, be0)
+	backend.TestBackendStateLocks(t, be0, be1)
+}
+
+func setupBackend(t *testing.T, bucket, prefix, key string, encrypt bool) backend.Backend {
+	t.Helper()
+
+	skip := os.Getenv("TF_COS_APPID") == ""
+	if skip {
+		t.Skip("This test require setting TF_COS_APPID environment variables")
+	}
+
+	if os.Getenv(PROVIDER_REGION) == "" {
+		os.Setenv(PROVIDER_REGION, "ap-guangzhou")
+	}
+
+	appId := os.Getenv("TF_COS_APPID")
+	region := os.Getenv(PROVIDER_REGION)
+
+	config := map[string]interface{}{
+		"region": region,
+		"bucket": bucket + appId,
+		"prefix": prefix,
+		"key":    key,
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(config))
+	be := b.(*Backend)
+
+	c, err := be.client("tencentcloud")
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	err = c.putBucket()
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	return b
+}
+
+func teardownBackend(t *testing.T, b backend.Backend) {
+	t.Helper()
+
+	c, err := b.(*Backend).client("tencentcloud")
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	err = c.deleteBucket(true)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+}
+
+func bucketName(t *testing.T) string {
+	unique := fmt.Sprintf("%s-%x", t.Name(), time.Now().UnixNano())
+	return fmt.Sprintf("terraform-test-%s-%s", fmt.Sprintf("%x", md5.Sum([]byte(unique)))[:10], "")
+}
diff --git a/v1.5.7/internal/backend/remote-state/cos/client.go b/v1.5.7/internal/backend/remote-state/cos/client.go
new file mode 100644
index 0000000..ad80ab7
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/cos/client.go
@@ -0,0 +1,445 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cos
+
+import (
+	"bytes"
+	"context"
+	"crypto/md5"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"strings"
+	"time"
+
+	multierror "github.com/hashicorp/go-multierror"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	tag "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tag/v20180813"
+	"github.com/tencentyun/cos-go-sdk-v5"
+)
+
+const (
+	lockTagKey = "tencentcloud-terraform-lock"
+)
+
+// RemoteClient implements the client of remote state
+type remoteClient struct {
+	cosContext context.Context
+	cosClient  *cos.Client
+	tagClient  *tag.Client
+
+	bucket    string
+	stateFile string
+	lockFile  string
+	encrypt   bool
+	acl       string
+}
+
+// Get returns remote state file
+func (c *remoteClient) Get() (*remote.Payload, error) {
+	log.Printf("[DEBUG] get remote state file %s", c.stateFile)
+
+	exists, data, checksum, err := c.getObject(c.stateFile)
+	if err != nil {
+		return nil, err
+	}
+
+	if !exists {
+		return nil, nil
+	}
+
+	payload := &remote.Payload{
+		Data: data,
+		MD5:  []byte(checksum),
+	}
+
+	return payload, nil
+}
+
+// Put put state file to remote
+func (c *remoteClient) Put(data []byte) error {
+	log.Printf("[DEBUG] put remote state file %s", c.stateFile)
+
+	return c.putObject(c.stateFile, data)
+}
+
+// Delete delete remote state file
+func (c *remoteClient) Delete() error {
+	log.Printf("[DEBUG] delete remote state file %s", c.stateFile)
+
+	return c.deleteObject(c.stateFile)
+}
+
+// Lock lock remote state file for writing
+func (c *remoteClient) Lock(info *statemgr.LockInfo) (string, error) {
+	log.Printf("[DEBUG] lock remote state file %s", c.lockFile)
+
+	err := c.cosLock(c.bucket, c.lockFile)
+	if err != nil {
+		return "", c.lockError(err)
+	}
+	defer c.cosUnlock(c.bucket, c.lockFile)
+
+	exists, _, _, err := c.getObject(c.lockFile)
+	if err != nil {
+		return "", c.lockError(err)
+	}
+
+	if exists {
+		return "", c.lockError(fmt.Errorf("lock file %s exists", c.lockFile))
+	}
+
+	info.Path = c.lockFile
+	data, err := json.Marshal(info)
+	if err != nil {
+		return "", c.lockError(err)
+	}
+
+	check := fmt.Sprintf("%x", md5.Sum(data))
+	err = c.putObject(c.lockFile, data)
+	if err != nil {
+		return "", c.lockError(err)
+	}
+
+	return check, nil
+}
+
+// Unlock unlock remote state file
+func (c *remoteClient) Unlock(check string) error {
+	log.Printf("[DEBUG] unlock remote state file %s", c.lockFile)
+
+	info, err := c.lockInfo()
+	if err != nil {
+		return c.lockError(err)
+	}
+
+	if info.ID != check {
+		return c.lockError(fmt.Errorf("lock id mismatch, %v != %v", info.ID, check))
+	}
+
+	err = c.deleteObject(c.lockFile)
+	if err != nil {
+		return c.lockError(err)
+	}
+
+	err = c.cosUnlock(c.bucket, c.lockFile)
+	if err != nil {
+		return c.lockError(err)
+	}
+
+	return nil
+}
+
+// lockError returns statemgr.LockError
+func (c *remoteClient) lockError(err error) *statemgr.LockError {
+	log.Printf("[DEBUG] failed to lock or unlock %s: %v", c.lockFile, err)
+
+	lockErr := &statemgr.LockError{
+		Err: err,
+	}
+
+	info, infoErr := c.lockInfo()
+	if infoErr != nil {
+		lockErr.Err = multierror.Append(lockErr.Err, infoErr)
+	} else {
+		lockErr.Info = info
+	}
+
+	return lockErr
+}
+
+// lockInfo returns LockInfo from lock file
+func (c *remoteClient) lockInfo() (*statemgr.LockInfo, error) {
+	exists, data, checksum, err := c.getObject(c.lockFile)
+	if err != nil {
+		return nil, err
+	}
+
+	if !exists {
+		return nil, fmt.Errorf("lock file %s not exists", c.lockFile)
+	}
+
+	info := &statemgr.LockInfo{}
+	if err := json.Unmarshal(data, info); err != nil {
+		return nil, err
+	}
+
+	info.ID = checksum
+
+	return info, nil
+}
+
+// getObject get remote object
+func (c *remoteClient) getObject(cosFile string) (exists bool, data []byte, checksum string, err error) {
+	rsp, err := c.cosClient.Object.Get(c.cosContext, cosFile, nil)
+	if rsp == nil {
+		log.Printf("[DEBUG] getObject %s: error: %v", cosFile, err)
+		err = fmt.Errorf("failed to open file at %v: %v", cosFile, err)
+		return
+	}
+	defer rsp.Body.Close()
+
+	log.Printf("[DEBUG] getObject %s: code: %d, error: %v", cosFile, rsp.StatusCode, err)
+	if err != nil {
+		if rsp.StatusCode == 404 {
+			err = nil
+		} else {
+			err = fmt.Errorf("failed to open file at %v: %v", cosFile, err)
+		}
+		return
+	}
+
+	checksum = rsp.Header.Get("X-Cos-Meta-Md5")
+	log.Printf("[DEBUG] getObject %s: checksum: %s", cosFile, checksum)
+	if len(checksum) != 32 {
+		err = fmt.Errorf("failed to open file at %v: checksum %s invalid", cosFile, checksum)
+		return
+	}
+
+	exists = true
+	data, err = ioutil.ReadAll(rsp.Body)
+	log.Printf("[DEBUG] getObject %s: data length: %d", cosFile, len(data))
+	if err != nil {
+		err = fmt.Errorf("failed to open file at %v: %v", cosFile, err)
+		return
+	}
+
+	check := fmt.Sprintf("%x", md5.Sum(data))
+	log.Printf("[DEBUG] getObject %s: check: %s", cosFile, check)
+	if check != checksum {
+		err = fmt.Errorf("failed to open file at %v: checksum mismatch, %s != %s", cosFile, check, checksum)
+		return
+	}
+
+	return
+}
+
+// putObject put object to remote
+func (c *remoteClient) putObject(cosFile string, data []byte) error {
+	opt := &cos.ObjectPutOptions{
+		ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{
+			XCosMetaXXX: &http.Header{
+				"X-Cos-Meta-Md5": []string{fmt.Sprintf("%x", md5.Sum(data))},
+			},
+		},
+		ACLHeaderOptions: &cos.ACLHeaderOptions{
+			XCosACL: c.acl,
+		},
+	}
+
+	if c.encrypt {
+		opt.ObjectPutHeaderOptions.XCosServerSideEncryption = "AES256"
+	}
+
+	r := bytes.NewReader(data)
+	rsp, err := c.cosClient.Object.Put(c.cosContext, cosFile, r, opt)
+	if rsp == nil {
+		log.Printf("[DEBUG] putObject %s: error: %v", cosFile, err)
+		return fmt.Errorf("failed to save file to %v: %v", cosFile, err)
+	}
+	defer rsp.Body.Close()
+
+	log.Printf("[DEBUG] putObject %s: code: %d, error: %v", cosFile, rsp.StatusCode, err)
+	if err != nil {
+		return fmt.Errorf("failed to save file to %v: %v", cosFile, err)
+	}
+
+	return nil
+}
+
+// deleteObject delete remote object
+func (c *remoteClient) deleteObject(cosFile string) error {
+	rsp, err := c.cosClient.Object.Delete(c.cosContext, cosFile)
+	if rsp == nil {
+		log.Printf("[DEBUG] deleteObject %s: error: %v", cosFile, err)
+		return fmt.Errorf("failed to delete file %v: %v", cosFile, err)
+	}
+	defer rsp.Body.Close()
+
+	log.Printf("[DEBUG] deleteObject %s: code: %d, error: %v", cosFile, rsp.StatusCode, err)
+	if rsp.StatusCode == 404 {
+		return nil
+	}
+
+	if err != nil {
+		return fmt.Errorf("failed to delete file %v: %v", cosFile, err)
+	}
+
+	return nil
+}
+
+// getBucket list bucket by prefix
+func (c *remoteClient) getBucket(prefix string) (obs []cos.Object, err error) {
+	fs, rsp, err := c.cosClient.Bucket.Get(c.cosContext, &cos.BucketGetOptions{Prefix: prefix})
+	if rsp == nil {
+		log.Printf("[DEBUG] getBucket %s/%s: error: %v", c.bucket, prefix, err)
+		err = fmt.Errorf("bucket %s not exists", c.bucket)
+		return
+	}
+	defer rsp.Body.Close()
+
+	log.Printf("[DEBUG] getBucket %s/%s: code: %d, error: %v", c.bucket, prefix, rsp.StatusCode, err)
+	if rsp.StatusCode == 404 {
+		err = fmt.Errorf("bucket %s not exists", c.bucket)
+		return
+	}
+
+	if err != nil {
+		return
+	}
+
+	return fs.Contents, nil
+}
+
+// putBucket create cos bucket
+func (c *remoteClient) putBucket() error {
+	rsp, err := c.cosClient.Bucket.Put(c.cosContext, nil)
+	if rsp == nil {
+		log.Printf("[DEBUG] putBucket %s: error: %v", c.bucket, err)
+		return fmt.Errorf("failed to create bucket %v: %v", c.bucket, err)
+	}
+	defer rsp.Body.Close()
+
+	log.Printf("[DEBUG] putBucket %s: code: %d, error: %v", c.bucket, rsp.StatusCode, err)
+	if rsp.StatusCode == 409 {
+		return nil
+	}
+
+	if err != nil {
+		return fmt.Errorf("failed to create bucket %v: %v", c.bucket, err)
+	}
+
+	return nil
+}
+
+// deleteBucket delete cos bucket
+func (c *remoteClient) deleteBucket(recursive bool) error {
+	if recursive {
+		obs, err := c.getBucket("")
+		if err != nil {
+			if strings.Contains(err.Error(), "not exists") {
+				return nil
+			}
+			log.Printf("[DEBUG] deleteBucket %s: empty bucket error: %v", c.bucket, err)
+			return fmt.Errorf("failed to empty bucket %v: %v", c.bucket, err)
+		}
+		for _, v := range obs {
+			c.deleteObject(v.Key)
+		}
+	}
+
+	rsp, err := c.cosClient.Bucket.Delete(c.cosContext)
+	if rsp == nil {
+		log.Printf("[DEBUG] deleteBucket %s: error: %v", c.bucket, err)
+		return fmt.Errorf("failed to delete bucket %v: %v", c.bucket, err)
+	}
+	defer rsp.Body.Close()
+
+	log.Printf("[DEBUG] deleteBucket %s: code: %d, error: %v", c.bucket, rsp.StatusCode, err)
+	if rsp.StatusCode == 404 {
+		return nil
+	}
+
+	if err != nil {
+		return fmt.Errorf("failed to delete bucket %v: %v", c.bucket, err)
+	}
+
+	return nil
+}
+
+// cosLock lock cos for writing
+func (c *remoteClient) cosLock(bucket, cosFile string) error {
+	log.Printf("[DEBUG] lock cos file %s:%s", bucket, cosFile)
+
+	cosPath := fmt.Sprintf("%s:%s", bucket, cosFile)
+	lockTagValue := fmt.Sprintf("%x", md5.Sum([]byte(cosPath)))
+
+	return c.CreateTag(lockTagKey, lockTagValue)
+}
+
+// cosUnlock unlock cos writing
+func (c *remoteClient) cosUnlock(bucket, cosFile string) error {
+	log.Printf("[DEBUG] unlock cos file %s:%s", bucket, cosFile)
+
+	cosPath := fmt.Sprintf("%s:%s", bucket, cosFile)
+	lockTagValue := fmt.Sprintf("%x", md5.Sum([]byte(cosPath)))
+
+	var err error
+	for i := 0; i < 30; i++ {
+		tagExists, err := c.CheckTag(lockTagKey, lockTagValue)
+
+		if err != nil {
+			return err
+		}
+
+		if !tagExists {
+			return nil
+		}
+
+		err = c.DeleteTag(lockTagKey, lockTagValue)
+		if err == nil {
+			return nil
+		}
+		time.Sleep(1 * time.Second)
+	}
+
+	return err
+}
+
+// CheckTag checks if tag key:value exists
+func (c *remoteClient) CheckTag(key, value string) (exists bool, err error) {
+	request := tag.NewDescribeTagsRequest()
+	request.TagKey = &key
+	request.TagValue = &value
+
+	response, err := c.tagClient.DescribeTags(request)
+	log.Printf("[DEBUG] create tag %s:%s: error: %v", key, value, err)
+	if err != nil {
+		return
+	}
+
+	if len(response.Response.Tags) == 0 {
+		return
+	}
+
+	tagKey := response.Response.Tags[0].TagKey
+	tagValue := response.Response.Tags[0].TagValue
+
+	exists = key == *tagKey && value == *tagValue
+
+	return
+}
+
+// CreateTag create tag by key and value
+func (c *remoteClient) CreateTag(key, value string) error {
+	request := tag.NewCreateTagRequest()
+	request.TagKey = &key
+	request.TagValue = &value
+
+	_, err := c.tagClient.CreateTag(request)
+	log.Printf("[DEBUG] create tag %s:%s: error: %v", key, value, err)
+	if err != nil {
+		return fmt.Errorf("failed to create tag: %s -> %s: %s", key, value, err)
+	}
+
+	return nil
+}
+
+// DeleteTag create tag by key and value
+func (c *remoteClient) DeleteTag(key, value string) error {
+	request := tag.NewDeleteTagRequest()
+	request.TagKey = &key
+	request.TagValue = &value
+
+	_, err := c.tagClient.DeleteTag(request)
+	log.Printf("[DEBUG] delete tag %s:%s: error: %v", key, value, err)
+	if err != nil {
+		return fmt.Errorf("failed to delete tag: %s -> %s: %s", key, value, err)
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/backend/remote-state/cos/transport.go b/v1.5.7/internal/backend/remote-state/cos/transport.go
new file mode 100644
index 0000000..9cd5506
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/cos/transport.go
@@ -0,0 +1,115 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cos
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"os"
+	"time"
+)
+
+const REQUEST_CLIENT = "TENCENTCLOUD_API_REQUEST_CLIENT"
+
+var ReqClient = "Terraform-latest"
+
+func SetReqClient(name string) {
+	if name == "" {
+		return
+	}
+	ReqClient = name
+}
+
+type LogRoundTripper struct {
+}
+
+func (me *LogRoundTripper) RoundTrip(request *http.Request) (response *http.Response, errRet error) {
+
+	var inBytes, outBytes []byte
+
+	var start = time.Now()
+
+	defer func() { me.log(inBytes, outBytes, errRet, start) }()
+
+	bodyReader, errRet := request.GetBody()
+	if errRet != nil {
+		return
+	}
+	var headName = "X-TC-Action"
+
+	if envReqClient := os.Getenv(REQUEST_CLIENT); envReqClient != "" {
+		ReqClient = envReqClient
+	}
+
+	request.Header.Set("X-TC-RequestClient", ReqClient)
+	inBytes = []byte(fmt.Sprintf("%s, request: ", request.Header[headName]))
+	requestBody, errRet := ioutil.ReadAll(bodyReader)
+	if errRet != nil {
+		return
+	}
+	inBytes = append(inBytes, requestBody...)
+
+	headName = "X-TC-Region"
+	appendMessage := []byte(fmt.Sprintf(
+		", (host %+v, region:%+v)",
+		request.Header["Host"],
+		request.Header[headName],
+	))
+
+	inBytes = append(inBytes, appendMessage...)
+
+	response, errRet = http.DefaultTransport.RoundTrip(request)
+	if errRet != nil {
+		return
+	}
+	outBytes, errRet = ioutil.ReadAll(response.Body)
+	if errRet != nil {
+		return
+	}
+	response.Body = ioutil.NopCloser(bytes.NewBuffer(outBytes))
+	return
+}
+
+func (me *LogRoundTripper) log(in []byte, out []byte, err error, start time.Time) {
+	var buf bytes.Buffer
+	buf.WriteString("######")
+	tag := "[DEBUG]"
+	if err != nil {
+		tag = "[CRITICAL]"
+	}
+	buf.WriteString(tag)
+	if len(in) > 0 {
+		buf.WriteString("tencentcloud-sdk-go: ")
+		buf.Write(in)
+	}
+	if len(out) > 0 {
+		buf.WriteString("; response:")
+		err := json.Compact(&buf, out)
+		if err != nil {
+			out := bytes.Replace(out,
+				[]byte("\n"),
+				[]byte(""),
+				-1)
+			out = bytes.Replace(out,
+				[]byte(" "),
+				[]byte(""),
+				-1)
+			buf.Write(out)
+		}
+	}
+
+	if err != nil {
+		buf.WriteString("; error:")
+		buf.WriteString(err.Error())
+	}
+
+	costFormat := fmt.Sprintf(",cost %s", time.Since(start).String())
+	buf.WriteString(costFormat)
+
+	log.Println(buf.String())
+}
diff --git a/v1.5.7/internal/backend/remote-state/gcs/backend.go b/v1.5.7/internal/backend/remote-state/gcs/backend.go
new file mode 100644
index 0000000..51375ed
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/gcs/backend.go
@@ -0,0 +1,252 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package gcs implements remote storage of state on Google Cloud Storage (GCS).
+package gcs
+
+import (
+	"context"
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"os"
+	"strings"
+
+	"cloud.google.com/go/storage"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/httpclient"
+	"github.com/hashicorp/terraform/internal/legacy/helper/schema"
+	"golang.org/x/oauth2"
+	"google.golang.org/api/impersonate"
+	"google.golang.org/api/option"
+)
+
+// Backend implements "backend".Backend for GCS.
+// Input(), Validate() and Configure() are implemented by embedding *schema.Backend.
+// State(), DeleteState() and States() are implemented explicitly.
+type Backend struct {
+	*schema.Backend
+
+	storageClient  *storage.Client
+	storageContext context.Context
+
+	bucketName string
+	prefix     string
+
+	encryptionKey []byte
+	kmsKeyName    string
+}
+
+func New() backend.Backend {
+	b := &Backend{}
+	b.Backend = &schema.Backend{
+		ConfigureFunc: b.configure,
+		Schema: map[string]*schema.Schema{
+			"bucket": {
+				Type:        schema.TypeString,
+				Required:    true,
+				Description: "The name of the Google Cloud Storage bucket",
+			},
+
+			"prefix": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The directory where state files will be saved inside the bucket",
+			},
+
+			"credentials": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "Google Cloud JSON Account Key",
+				Default:     "",
+			},
+
+			"access_token": {
+				Type:     schema.TypeString,
+				Optional: true,
+				DefaultFunc: schema.MultiEnvDefaultFunc([]string{
+					"GOOGLE_OAUTH_ACCESS_TOKEN",
+				}, nil),
+				Description: "An OAuth2 token used for GCP authentication",
+			},
+
+			"impersonate_service_account": {
+				Type:     schema.TypeString,
+				Optional: true,
+				DefaultFunc: schema.MultiEnvDefaultFunc([]string{
+					"GOOGLE_BACKEND_IMPERSONATE_SERVICE_ACCOUNT",
+					"GOOGLE_IMPERSONATE_SERVICE_ACCOUNT",
+				}, nil),
+				Description: "The service account to impersonate for all Google API Calls",
+			},
+
+			"impersonate_service_account_delegates": {
+				Type:        schema.TypeList,
+				Optional:    true,
+				Description: "The delegation chain for the impersonated service account",
+				Elem:        &schema.Schema{Type: schema.TypeString},
+			},
+
+			"encryption_key": {
+				Type:     schema.TypeString,
+				Optional: true,
+				DefaultFunc: schema.MultiEnvDefaultFunc([]string{
+					"GOOGLE_ENCRYPTION_KEY",
+				}, nil),
+				Description:   "A 32 byte base64 encoded 'customer supplied encryption key' used when reading and writing state files in the bucket.",
+				ConflictsWith: []string{"kms_encryption_key"},
+			},
+
+			"kms_encryption_key": {
+				Type:     schema.TypeString,
+				Optional: true,
+				DefaultFunc: schema.MultiEnvDefaultFunc([]string{
+					"GOOGLE_KMS_ENCRYPTION_KEY",
+				}, nil),
+				Description:   "A Cloud KMS key ('customer managed encryption key') used when reading and writing state files in the bucket. Format should be 'projects/{{project}}/locations/{{location}}/keyRings/{{keyRing}}/cryptoKeys/{{name}}'.",
+				ConflictsWith: []string{"encryption_key"},
+			},
+
+			"storage_custom_endpoint": {
+				Type:     schema.TypeString,
+				Optional: true,
+				DefaultFunc: schema.MultiEnvDefaultFunc([]string{
+					"GOOGLE_BACKEND_STORAGE_CUSTOM_ENDPOINT",
+					"GOOGLE_STORAGE_CUSTOM_ENDPOINT",
+				}, nil),
+			},
+		},
+	}
+
+	return b
+}
+
+func (b *Backend) configure(ctx context.Context) error {
+	if b.storageClient != nil {
+		return nil
+	}
+
+	// ctx is a background context with the backend config added.
+	// Since no context is passed to remoteClient.Get(), .Lock(), etc. but
+	// one is required for calling the GCP API, we're holding on to this
+	// context here and re-use it later.
+	b.storageContext = ctx
+
+	data := schema.FromContextBackendConfig(b.storageContext)
+
+	b.bucketName = data.Get("bucket").(string)
+	b.prefix = strings.TrimLeft(data.Get("prefix").(string), "/")
+	if b.prefix != "" && !strings.HasSuffix(b.prefix, "/") {
+		b.prefix = b.prefix + "/"
+	}
+
+	var opts []option.ClientOption
+	var credOptions []option.ClientOption
+
+	// Add credential source
+	var creds string
+	var tokenSource oauth2.TokenSource
+
+	if v, ok := data.GetOk("access_token"); ok {
+		tokenSource = oauth2.StaticTokenSource(&oauth2.Token{
+			AccessToken: v.(string),
+		})
+	} else if v, ok := data.GetOk("credentials"); ok {
+		creds = v.(string)
+	} else if v := os.Getenv("GOOGLE_BACKEND_CREDENTIALS"); v != "" {
+		creds = v
+	} else {
+		creds = os.Getenv("GOOGLE_CREDENTIALS")
+	}
+
+	if tokenSource != nil {
+		credOptions = append(credOptions, option.WithTokenSource(tokenSource))
+	} else if creds != "" {
+
+		// to mirror how the provider works, we accept the file path or the contents
+		contents, err := backend.ReadPathOrContents(creds)
+		if err != nil {
+			return fmt.Errorf("Error loading credentials: %s", err)
+		}
+
+		if !json.Valid([]byte(contents)) {
+			return fmt.Errorf("the string provided in credentials is neither valid json nor a valid file path")
+		}
+
+		credOptions = append(credOptions, option.WithCredentialsJSON([]byte(contents)))
+	}
+
+	// Service Account Impersonation
+	if v, ok := data.GetOk("impersonate_service_account"); ok {
+		ServiceAccount := v.(string)
+		var delegates []string
+
+		if v, ok := data.GetOk("impersonate_service_account_delegates"); ok {
+			d := v.([]interface{})
+			if len(delegates) > 0 {
+				delegates = make([]string, 0, len(d))
+			}
+			for _, delegate := range d {
+				delegates = append(delegates, delegate.(string))
+			}
+		}
+
+		ts, err := impersonate.CredentialsTokenSource(ctx, impersonate.CredentialsConfig{
+			TargetPrincipal: ServiceAccount,
+			Scopes:          []string{storage.ScopeReadWrite},
+			Delegates:       delegates,
+		}, credOptions...)
+
+		if err != nil {
+			return err
+		}
+
+		opts = append(opts, option.WithTokenSource(ts))
+
+	} else {
+		opts = append(opts, credOptions...)
+	}
+
+	opts = append(opts, option.WithUserAgent(httpclient.UserAgentString()))
+
+	// Custom endpoint for storage API
+	if storageEndpoint, ok := data.GetOk("storage_custom_endpoint"); ok {
+		endpoint := option.WithEndpoint(storageEndpoint.(string))
+		opts = append(opts, endpoint)
+	}
+	client, err := storage.NewClient(b.storageContext, opts...)
+	if err != nil {
+		return fmt.Errorf("storage.NewClient() failed: %v", err)
+	}
+
+	b.storageClient = client
+
+	// Customer-supplied encryption
+	key := data.Get("encryption_key").(string)
+	if key != "" {
+		kc, err := backend.ReadPathOrContents(key)
+		if err != nil {
+			return fmt.Errorf("Error loading encryption key: %s", err)
+		}
+
+		// The GCS client expects a customer supplied encryption key to be
+		// passed in as a 32 byte long byte slice. The byte slice is base64
+		// encoded before being passed to the API. We take a base64 encoded key
+		// to remain consistent with the GCS docs.
+		// https://cloud.google.com/storage/docs/encryption#customer-supplied
+		// https://github.com/GoogleCloudPlatform/google-cloud-go/blob/def681/storage/storage.go#L1181
+		k, err := base64.StdEncoding.DecodeString(kc)
+		if err != nil {
+			return fmt.Errorf("Error decoding encryption key: %s", err)
+		}
+		b.encryptionKey = k
+	}
+
+	// Customer-managed encryption
+	kmsName := data.Get("kms_encryption_key").(string)
+	if kmsName != "" {
+		b.kmsKeyName = kmsName
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/backend/remote-state/gcs/backend_state.go b/v1.5.7/internal/backend/remote-state/gcs/backend_state.go
new file mode 100644
index 0000000..b36dc7c
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/gcs/backend_state.go
@@ -0,0 +1,158 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package gcs
+
+import (
+	"fmt"
+	"path"
+	"sort"
+	"strings"
+
+	"cloud.google.com/go/storage"
+	"google.golang.org/api/iterator"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+const (
+	stateFileSuffix = ".tfstate"
+	lockFileSuffix  = ".tflock"
+)
+
+// Workspaces returns a list of names for the workspaces found on GCS. The default
+// state is always returned as the first element in the slice.
+func (b *Backend) Workspaces() ([]string, error) {
+	states := []string{backend.DefaultStateName}
+
+	bucket := b.storageClient.Bucket(b.bucketName)
+	objs := bucket.Objects(b.storageContext, &storage.Query{
+		Delimiter: "/",
+		Prefix:    b.prefix,
+	})
+	for {
+		attrs, err := objs.Next()
+		if err == iterator.Done {
+			break
+		}
+		if err != nil {
+			return nil, fmt.Errorf("querying Cloud Storage failed: %v", err)
+		}
+
+		name := path.Base(attrs.Name)
+		if !strings.HasSuffix(name, stateFileSuffix) {
+			continue
+		}
+		st := strings.TrimSuffix(name, stateFileSuffix)
+
+		if st != backend.DefaultStateName {
+			states = append(states, st)
+		}
+	}
+
+	sort.Strings(states[1:])
+	return states, nil
+}
+
+// DeleteWorkspace deletes the named workspaces. The "default" state cannot be deleted.
+func (b *Backend) DeleteWorkspace(name string, _ bool) error {
+	if name == backend.DefaultStateName {
+		return fmt.Errorf("cowardly refusing to delete the %q state", name)
+	}
+
+	c, err := b.client(name)
+	if err != nil {
+		return err
+	}
+
+	return c.Delete()
+}
+
+// client returns a remoteClient for the named state.
+func (b *Backend) client(name string) (*remoteClient, error) {
+	if name == "" {
+		return nil, fmt.Errorf("%q is not a valid state name", name)
+	}
+
+	return &remoteClient{
+		storageContext: b.storageContext,
+		storageClient:  b.storageClient,
+		bucketName:     b.bucketName,
+		stateFilePath:  b.stateFile(name),
+		lockFilePath:   b.lockFile(name),
+		encryptionKey:  b.encryptionKey,
+		kmsKeyName:     b.kmsKeyName,
+	}, nil
+}
+
+// StateMgr reads and returns the named state from GCS. If the named state does
+// not yet exist, a new state file is created.
+func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
+	c, err := b.client(name)
+	if err != nil {
+		return nil, err
+	}
+
+	st := &remote.State{Client: c}
+
+	// Grab the value
+	if err := st.RefreshState(); err != nil {
+		return nil, err
+	}
+
+	// If we have no state, we have to create an empty state
+	if v := st.State(); v == nil {
+
+		lockInfo := statemgr.NewLockInfo()
+		lockInfo.Operation = "init"
+		lockID, err := st.Lock(lockInfo)
+		if err != nil {
+			return nil, err
+		}
+
+		// Local helper function so we can call it multiple places
+		unlock := func(baseErr error) error {
+			if err := st.Unlock(lockID); err != nil {
+				const unlockErrMsg = `%v
+				Additionally, unlocking the state file on Google Cloud Storage failed:
+
+				Error message: %q
+				Lock ID (gen): %v
+				Lock file URL: %v
+
+				You may have to force-unlock this state in order to use it again.
+				The GCloud backend acquires a lock during initialization to ensure
+				the initial state file is created.`
+				return fmt.Errorf(unlockErrMsg, baseErr, err.Error(), lockID, c.lockFileURL())
+			}
+
+			return baseErr
+		}
+
+		if err := st.WriteState(states.NewState()); err != nil {
+			return nil, unlock(err)
+		}
+		if err := st.PersistState(nil); err != nil {
+			return nil, unlock(err)
+		}
+
+		// Unlock, the state should now be initialized
+		if err := unlock(nil); err != nil {
+			return nil, err
+		}
+
+	}
+
+	return st, nil
+}
+
+func (b *Backend) stateFile(name string) string {
+	return path.Join(b.prefix, name+stateFileSuffix)
+}
+
+func (b *Backend) lockFile(name string) string {
+	return path.Join(b.prefix, name+lockFileSuffix)
+}
diff --git a/v1.5.7/internal/backend/remote-state/gcs/backend_test.go b/v1.5.7/internal/backend/remote-state/gcs/backend_test.go
new file mode 100644
index 0000000..40d0fd1
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/gcs/backend_test.go
@@ -0,0 +1,444 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package gcs
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"log"
+	"os"
+	"strings"
+	"testing"
+	"time"
+
+	kms "cloud.google.com/go/kms/apiv1"
+	"cloud.google.com/go/storage"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/httpclient"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"google.golang.org/api/option"
+	kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
+)
+
+const (
+	noPrefix        = ""
+	noEncryptionKey = ""
+	noKmsKeyName    = ""
+)
+
+// See https://cloud.google.com/storage/docs/using-encryption-keys#generating_your_own_encryption_key
+const encryptionKey = "yRyCOikXi1ZDNE0xN3yiFsJjg7LGimoLrGFcLZgQoVk="
+
+// KMS key ring name and key name are hardcoded here and re-used because key rings (and keys) cannot be deleted
+// Test code asserts their presence and creates them if they're absent. They're not deleted at the end of tests.
+// See: https://cloud.google.com/kms/docs/faq#cannot_delete
+const (
+	keyRingName = "tf-gcs-backend-acc-tests"
+	keyName     = "tf-test-key-1"
+	kmsRole     = "roles/cloudkms.cryptoKeyEncrypterDecrypter" // GCS service account needs this binding on the created key
+)
+
+var keyRingLocation = os.Getenv("GOOGLE_REGION")
+
+func TestStateFile(t *testing.T) {
+	t.Parallel()
+
+	cases := []struct {
+		prefix        string
+		name          string
+		wantStateFile string
+		wantLockFile  string
+	}{
+		{"state", "default", "state/default.tfstate", "state/default.tflock"},
+		{"state", "test", "state/test.tfstate", "state/test.tflock"},
+		{"state", "test", "state/test.tfstate", "state/test.tflock"},
+		{"state", "test", "state/test.tfstate", "state/test.tflock"},
+	}
+	for _, c := range cases {
+		b := &Backend{
+			prefix: c.prefix,
+		}
+
+		if got := b.stateFile(c.name); got != c.wantStateFile {
+			t.Errorf("stateFile(%q) = %q, want %q", c.name, got, c.wantStateFile)
+		}
+
+		if got := b.lockFile(c.name); got != c.wantLockFile {
+			t.Errorf("lockFile(%q) = %q, want %q", c.name, got, c.wantLockFile)
+		}
+	}
+}
+
+func TestRemoteClient(t *testing.T) {
+	t.Parallel()
+
+	bucket := bucketName(t)
+	be := setupBackend(t, bucket, noPrefix, noEncryptionKey, noKmsKeyName)
+	defer teardownBackend(t, be, noPrefix)
+
+	ss, err := be.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("be.StateMgr(%q) = %v", backend.DefaultStateName, err)
+	}
+
+	rs, ok := ss.(*remote.State)
+	if !ok {
+		t.Fatalf("be.StateMgr(): got a %T, want a *remote.State", ss)
+	}
+
+	remote.TestClient(t, rs.Client)
+}
+func TestRemoteClientWithEncryption(t *testing.T) {
+	t.Parallel()
+
+	bucket := bucketName(t)
+	be := setupBackend(t, bucket, noPrefix, encryptionKey, noKmsKeyName)
+	defer teardownBackend(t, be, noPrefix)
+
+	ss, err := be.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("be.StateMgr(%q) = %v", backend.DefaultStateName, err)
+	}
+
+	rs, ok := ss.(*remote.State)
+	if !ok {
+		t.Fatalf("be.StateMgr(): got a %T, want a *remote.State", ss)
+	}
+
+	remote.TestClient(t, rs.Client)
+}
+
+func TestRemoteLocks(t *testing.T) {
+	t.Parallel()
+
+	bucket := bucketName(t)
+	be := setupBackend(t, bucket, noPrefix, noEncryptionKey, noKmsKeyName)
+	defer teardownBackend(t, be, noPrefix)
+
+	remoteClient := func() (remote.Client, error) {
+		ss, err := be.StateMgr(backend.DefaultStateName)
+		if err != nil {
+			return nil, err
+		}
+
+		rs, ok := ss.(*remote.State)
+		if !ok {
+			return nil, fmt.Errorf("be.StateMgr(): got a %T, want a *remote.State", ss)
+		}
+
+		return rs.Client, nil
+	}
+
+	c0, err := remoteClient()
+	if err != nil {
+		t.Fatalf("remoteClient(0) = %v", err)
+	}
+	c1, err := remoteClient()
+	if err != nil {
+		t.Fatalf("remoteClient(1) = %v", err)
+	}
+
+	remote.TestRemoteLocks(t, c0, c1)
+}
+
+func TestBackend(t *testing.T) {
+	t.Parallel()
+
+	bucket := bucketName(t)
+
+	be0 := setupBackend(t, bucket, noPrefix, noEncryptionKey, noKmsKeyName)
+	defer teardownBackend(t, be0, noPrefix)
+
+	be1 := setupBackend(t, bucket, noPrefix, noEncryptionKey, noKmsKeyName)
+
+	backend.TestBackendStates(t, be0)
+	backend.TestBackendStateLocks(t, be0, be1)
+	backend.TestBackendStateForceUnlock(t, be0, be1)
+}
+
+func TestBackendWithPrefix(t *testing.T) {
+	t.Parallel()
+
+	prefix := "test/prefix"
+	bucket := bucketName(t)
+
+	be0 := setupBackend(t, bucket, prefix, noEncryptionKey, noKmsKeyName)
+	defer teardownBackend(t, be0, prefix)
+
+	be1 := setupBackend(t, bucket, prefix+"/", noEncryptionKey, noKmsKeyName)
+
+	backend.TestBackendStates(t, be0)
+	backend.TestBackendStateLocks(t, be0, be1)
+}
+func TestBackendWithCustomerSuppliedEncryption(t *testing.T) {
+	t.Parallel()
+
+	bucket := bucketName(t)
+
+	be0 := setupBackend(t, bucket, noPrefix, encryptionKey, noKmsKeyName)
+	defer teardownBackend(t, be0, noPrefix)
+
+	be1 := setupBackend(t, bucket, noPrefix, encryptionKey, noKmsKeyName)
+
+	backend.TestBackendStates(t, be0)
+	backend.TestBackendStateLocks(t, be0, be1)
+}
+
+func TestBackendWithCustomerManagedKMSEncryption(t *testing.T) {
+	t.Parallel()
+
+	projectID := os.Getenv("GOOGLE_PROJECT")
+	bucket := bucketName(t)
+
+	// Taken from global variables in test file
+	kmsDetails := map[string]string{
+		"project":  projectID,
+		"location": keyRingLocation,
+		"ringName": keyRingName,
+		"keyName":  keyName,
+	}
+
+	kmsName := setupKmsKey(t, kmsDetails)
+
+	be0 := setupBackend(t, bucket, noPrefix, noEncryptionKey, kmsName)
+	defer teardownBackend(t, be0, noPrefix)
+
+	be1 := setupBackend(t, bucket, noPrefix, noEncryptionKey, kmsName)
+
+	backend.TestBackendStates(t, be0)
+	backend.TestBackendStateLocks(t, be0, be1)
+}
+
+// setupBackend returns a new GCS backend.
+func setupBackend(t *testing.T, bucket, prefix, key, kmsName string) backend.Backend {
+	t.Helper()
+
+	projectID := os.Getenv("GOOGLE_PROJECT")
+	if projectID == "" || os.Getenv("TF_ACC") == "" {
+		t.Skip("This test creates a bucket in GCS and populates it. " +
+			"Since this may incur costs, it will only run if " +
+			"the TF_ACC and GOOGLE_PROJECT environment variables are set.")
+	}
+
+	config := map[string]interface{}{
+		"bucket": bucket,
+		"prefix": prefix,
+	}
+	// Only add encryption keys to config if non-zero value set
+	// If not set here, default values are supplied in `TestBackendConfig` by `PrepareConfig` function call
+	if len(key) > 0 {
+		config["encryption_key"] = key
+	}
+	if len(kmsName) > 0 {
+		config["kms_encryption_key"] = kmsName
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(config))
+	be := b.(*Backend)
+
+	// create the bucket if it doesn't exist
+	bkt := be.storageClient.Bucket(bucket)
+	_, err := bkt.Attrs(be.storageContext)
+	if err != nil {
+		if err != storage.ErrBucketNotExist {
+			t.Fatal(err)
+		}
+
+		attrs := &storage.BucketAttrs{
+			Location: os.Getenv("GOOGLE_REGION"),
+		}
+		err := bkt.Create(be.storageContext, projectID, attrs)
+		if err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	return b
+}
+
+// setupKmsKey asserts that a KMS key chain and key exist and necessary IAM bindings are in place
+// If the key ring or key do not exist they are created and permissions are given to the GCS Service account
+func setupKmsKey(t *testing.T, keyDetails map[string]string) string {
+	t.Helper()
+
+	projectID := os.Getenv("GOOGLE_PROJECT")
+	if projectID == "" || os.Getenv("TF_ACC") == "" {
+		t.Skip("This test creates a KMS key ring and key in Cloud KMS. " +
+			"Since this may incur costs, it will only run if " +
+			"the TF_ACC and GOOGLE_PROJECT environment variables are set.")
+	}
+
+	// KMS Client
+	ctx := context.Background()
+	opts, err := testGetClientOptions(t)
+	if err != nil {
+		e := fmt.Errorf("testGetClientOptions() failed: %s", err)
+		t.Fatal(e)
+	}
+	c, err := kms.NewKeyManagementClient(ctx, opts...)
+	if err != nil {
+		e := fmt.Errorf("kms.NewKeyManagementClient() failed: %v", err)
+		t.Fatal(e)
+	}
+	defer c.Close()
+
+	// Get KMS key ring, create if doesn't exist
+	reqGetKeyRing := &kmspb.GetKeyRingRequest{
+		Name: fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", keyDetails["project"], keyDetails["location"], keyDetails["ringName"]),
+	}
+	var keyRing *kmspb.KeyRing
+	keyRing, err = c.GetKeyRing(ctx, reqGetKeyRing)
+	if err != nil {
+		if !strings.Contains(err.Error(), "NotFound") {
+			// Handle unexpected error that isn't related to the key ring not being made yet
+			t.Fatal(err)
+		}
+		// Create key ring that doesn't exist
+		t.Logf("Cloud KMS key ring `%s` not found: creating key ring",
+			fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", keyDetails["project"], keyDetails["location"], keyDetails["ringName"]),
+		)
+		reqCreateKeyRing := &kmspb.CreateKeyRingRequest{
+			Parent:    fmt.Sprintf("projects/%s/locations/%s", keyDetails["project"], keyDetails["location"]),
+			KeyRingId: keyDetails["ringName"],
+		}
+		keyRing, err = c.CreateKeyRing(ctx, reqCreateKeyRing)
+		if err != nil {
+			t.Fatal(err)
+		}
+		t.Logf("Cloud KMS key ring `%s` created successfully", keyRing.Name)
+	}
+
+	// Get KMS key, create if doesn't exist (and give GCS service account permission to use)
+	reqGetKey := &kmspb.GetCryptoKeyRequest{
+		Name: fmt.Sprintf("%s/cryptoKeys/%s", keyRing.Name, keyDetails["keyName"]),
+	}
+	var key *kmspb.CryptoKey
+	key, err = c.GetCryptoKey(ctx, reqGetKey)
+	if err != nil {
+		if !strings.Contains(err.Error(), "NotFound") {
+			// Handle unexpected error that isn't related to the key not being made yet
+			t.Fatal(err)
+		}
+		// Create key that doesn't exist
+		t.Logf("Cloud KMS key `%s` not found: creating key",
+			fmt.Sprintf("%s/cryptoKeys/%s", keyRing.Name, keyDetails["keyName"]),
+		)
+		reqCreateKey := &kmspb.CreateCryptoKeyRequest{
+			Parent:      keyRing.Name,
+			CryptoKeyId: keyDetails["keyName"],
+			CryptoKey: &kmspb.CryptoKey{
+				Purpose: kmspb.CryptoKey_ENCRYPT_DECRYPT,
+			},
+		}
+		key, err = c.CreateCryptoKey(ctx, reqCreateKey)
+		if err != nil {
+			t.Fatal(err)
+		}
+		t.Logf("Cloud KMS key `%s` created successfully", key.Name)
+	}
+
+	// Get GCS Service account email, check has necessary permission on key
+	// Note: we cannot reuse the backend's storage client (like in the setupBackend function)
+	// because the KMS key needs to exist before the backend buckets are made in the test.
+	sc, err := storage.NewClient(ctx, opts...) //reuse opts from KMS client
+	if err != nil {
+		e := fmt.Errorf("storage.NewClient() failed: %v", err)
+		t.Fatal(e)
+	}
+	defer sc.Close()
+	gcsServiceAccount, err := sc.ServiceAccount(ctx, keyDetails["project"])
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Assert Cloud Storage service account has permission to use this key.
+	member := fmt.Sprintf("serviceAccount:%s", gcsServiceAccount)
+	iamHandle := c.ResourceIAM(key.Name)
+	policy, err := iamHandle.Policy(ctx)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if ok := policy.HasRole(member, kmsRole); !ok {
+		// Add the missing permissions
+		t.Logf("Granting GCS service account %s %s role on key %s", gcsServiceAccount, kmsRole, key.Name)
+		policy.Add(member, kmsRole)
+		err = iamHandle.SetPolicy(ctx, policy)
+		if err != nil {
+			t.Fatal(err)
+		}
+	}
+	return key.Name
+}
+
+// teardownBackend deletes all states from be except the default state.
+func teardownBackend(t *testing.T, be backend.Backend, prefix string) {
+	t.Helper()
+	gcsBE, ok := be.(*Backend)
+	if !ok {
+		t.Fatalf("be is a %T, want a *gcsBackend", be)
+	}
+	ctx := gcsBE.storageContext
+
+	bucket := gcsBE.storageClient.Bucket(gcsBE.bucketName)
+	objs := bucket.Objects(ctx, nil)
+
+	for o, err := objs.Next(); err == nil; o, err = objs.Next() {
+		if err := bucket.Object(o.Name).Delete(ctx); err != nil {
+			log.Printf("Error trying to delete object: %s %s\n\n", o.Name, err)
+		} else {
+			log.Printf("Object deleted: %s", o.Name)
+		}
+	}
+
+	// Delete the bucket itself.
+	if err := bucket.Delete(ctx); err != nil {
+		t.Errorf("deleting bucket %q failed, manual cleanup may be required: %v", gcsBE.bucketName, err)
+	}
+}
+
+// bucketName returns a valid bucket name for this test.
+func bucketName(t *testing.T) string {
+	name := fmt.Sprintf("tf-%x-%s", time.Now().UnixNano(), t.Name())
+
+	// Bucket names must contain 3 to 63 characters.
+	if len(name) > 63 {
+		name = name[:63]
+	}
+
+	return strings.ToLower(name)
+}
+
+// getClientOptions returns the []option.ClientOption needed to configure Google API clients
+// that are required in acceptance tests but are not part of the gcs backend itself
+func testGetClientOptions(t *testing.T) ([]option.ClientOption, error) {
+	t.Helper()
+
+	var creds string
+	if v := os.Getenv("GOOGLE_BACKEND_CREDENTIALS"); v != "" {
+		creds = v
+	} else {
+		creds = os.Getenv("GOOGLE_CREDENTIALS")
+	}
+	if creds == "" {
+		t.Skip("This test required credentials to be supplied via" +
+			"the GOOGLE_CREDENTIALS or GOOGLE_BACKEND_CREDENTIALS environment variables.")
+	}
+
+	var opts []option.ClientOption
+	var credOptions []option.ClientOption
+
+	contents, err := backend.ReadPathOrContents(creds)
+	if err != nil {
+		return nil, fmt.Errorf("error loading credentials: %s", err)
+	}
+	if !json.Valid([]byte(contents)) {
+		return nil, fmt.Errorf("the string provided in credentials is neither valid json nor a valid file path")
+	}
+	credOptions = append(credOptions, option.WithCredentialsJSON([]byte(contents)))
+	opts = append(opts, credOptions...)
+	opts = append(opts, option.WithUserAgent(httpclient.UserAgentString()))
+
+	return opts, nil
+}
diff --git a/v1.5.7/internal/backend/remote-state/gcs/client.go b/v1.5.7/internal/backend/remote-state/gcs/client.go
new file mode 100644
index 0000000..e0884c3
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/gcs/client.go
@@ -0,0 +1,193 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package gcs
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"strconv"
+
+	"cloud.google.com/go/storage"
+	multierror "github.com/hashicorp/go-multierror"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"golang.org/x/net/context"
+)
+
+// remoteClient is used by "state/remote".State to read and write
+// blobs representing state.
+// Implements "state/remote".ClientLocker
+type remoteClient struct {
+	storageContext context.Context
+	storageClient  *storage.Client
+	bucketName     string
+	stateFilePath  string
+	lockFilePath   string
+	encryptionKey  []byte
+	kmsKeyName     string
+}
+
+func (c *remoteClient) Get() (payload *remote.Payload, err error) {
+	stateFileReader, err := c.stateFile().NewReader(c.storageContext)
+	if err != nil {
+		if err == storage.ErrObjectNotExist {
+			return nil, nil
+		} else {
+			return nil, fmt.Errorf("Failed to open state file at %v: %v", c.stateFileURL(), err)
+		}
+	}
+	defer stateFileReader.Close()
+
+	stateFileContents, err := ioutil.ReadAll(stateFileReader)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to read state file from %v: %v", c.stateFileURL(), err)
+	}
+
+	stateFileAttrs, err := c.stateFile().Attrs(c.storageContext)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to read state file attrs from %v: %v", c.stateFileURL(), err)
+	}
+
+	result := &remote.Payload{
+		Data: stateFileContents,
+		MD5:  stateFileAttrs.MD5,
+	}
+
+	return result, nil
+}
+
+func (c *remoteClient) Put(data []byte) error {
+	err := func() error {
+		stateFileWriter := c.stateFile().NewWriter(c.storageContext)
+		if len(c.kmsKeyName) > 0 {
+			stateFileWriter.KMSKeyName = c.kmsKeyName
+		}
+		if _, err := stateFileWriter.Write(data); err != nil {
+			return err
+		}
+		return stateFileWriter.Close()
+	}()
+	if err != nil {
+		return fmt.Errorf("Failed to upload state to %v: %v", c.stateFileURL(), err)
+	}
+
+	return nil
+}
+
+func (c *remoteClient) Delete() error {
+	if err := c.stateFile().Delete(c.storageContext); err != nil {
+		return fmt.Errorf("Failed to delete state file %v: %v", c.stateFileURL(), err)
+	}
+
+	return nil
+}
+
+// Lock writes to a lock file, ensuring file creation. Returns the generation
+// number, which must be passed to Unlock().
+func (c *remoteClient) Lock(info *statemgr.LockInfo) (string, error) {
+	// update the path we're using
+	// we can't set the ID until the info is written
+	info.Path = c.lockFileURL()
+
+	infoJson, err := json.Marshal(info)
+	if err != nil {
+		return "", err
+	}
+
+	lockFile := c.lockFile()
+	w := lockFile.If(storage.Conditions{DoesNotExist: true}).NewWriter(c.storageContext)
+	err = func() error {
+		if _, err := w.Write(infoJson); err != nil {
+			return err
+		}
+		return w.Close()
+	}()
+
+	if err != nil {
+		return "", c.lockError(fmt.Errorf("writing %q failed: %v", c.lockFileURL(), err))
+	}
+
+	info.ID = strconv.FormatInt(w.Attrs().Generation, 10)
+
+	return info.ID, nil
+}
+
+func (c *remoteClient) Unlock(id string) error {
+	gen, err := strconv.ParseInt(id, 10, 64)
+	if err != nil {
+		return fmt.Errorf("Lock ID should be numerical value, got '%s'", id)
+	}
+
+	if err := c.lockFile().If(storage.Conditions{GenerationMatch: gen}).Delete(c.storageContext); err != nil {
+		return c.lockError(err)
+	}
+
+	return nil
+}
+
+func (c *remoteClient) lockError(err error) *statemgr.LockError {
+	lockErr := &statemgr.LockError{
+		Err: err,
+	}
+
+	info, infoErr := c.lockInfo()
+	if infoErr != nil {
+		lockErr.Err = multierror.Append(lockErr.Err, infoErr)
+	} else {
+		lockErr.Info = info
+	}
+	return lockErr
+}
+
+// lockInfo reads the lock file, parses its contents and returns the parsed
+// LockInfo struct.
+func (c *remoteClient) lockInfo() (*statemgr.LockInfo, error) {
+	r, err := c.lockFile().NewReader(c.storageContext)
+	if err != nil {
+		return nil, err
+	}
+	defer r.Close()
+
+	rawData, err := ioutil.ReadAll(r)
+	if err != nil {
+		return nil, err
+	}
+
+	info := &statemgr.LockInfo{}
+	if err := json.Unmarshal(rawData, info); err != nil {
+		return nil, err
+	}
+
+	// We use the Generation as the ID, so overwrite the ID in the json.
+	// This can't be written into the Info, since the generation isn't known
+	// until it's written.
+	attrs, err := c.lockFile().Attrs(c.storageContext)
+	if err != nil {
+		return nil, err
+	}
+	info.ID = strconv.FormatInt(attrs.Generation, 10)
+
+	return info, nil
+}
+
+func (c *remoteClient) stateFile() *storage.ObjectHandle {
+	h := c.storageClient.Bucket(c.bucketName).Object(c.stateFilePath)
+	if len(c.encryptionKey) > 0 {
+		return h.Key(c.encryptionKey)
+	}
+	return h
+}
+
+func (c *remoteClient) stateFileURL() string {
+	return fmt.Sprintf("gs://%v/%v", c.bucketName, c.stateFilePath)
+}
+
+func (c *remoteClient) lockFile() *storage.ObjectHandle {
+	return c.storageClient.Bucket(c.bucketName).Object(c.lockFilePath)
+}
+
+func (c *remoteClient) lockFileURL() string {
+	return fmt.Sprintf("gs://%v/%v", c.bucketName, c.lockFilePath)
+}
diff --git a/v1.5.7/internal/backend/remote-state/http/backend.go b/v1.5.7/internal/backend/remote-state/http/backend.go
new file mode 100644
index 0000000..d21a7b5
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/http/backend.go
@@ -0,0 +1,260 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package http
+
+import (
+	"context"
+	"crypto/tls"
+	"crypto/x509"
+	"errors"
+	"fmt"
+	"log"
+	"net/http"
+	"net/url"
+	"time"
+
+	"github.com/hashicorp/go-retryablehttp"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/legacy/helper/schema"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+func New() backend.Backend {
+	s := &schema.Backend{
+		Schema: map[string]*schema.Schema{
+			"address": &schema.Schema{
+				Type:        schema.TypeString,
+				Required:    true,
+				DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_ADDRESS", nil),
+				Description: "The address of the REST endpoint",
+			},
+			"update_method": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_UPDATE_METHOD", "POST"),
+				Description: "HTTP method to use when updating state",
+			},
+			"lock_address": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_LOCK_ADDRESS", nil),
+				Description: "The address of the lock REST endpoint",
+			},
+			"unlock_address": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_UNLOCK_ADDRESS", nil),
+				Description: "The address of the unlock REST endpoint",
+			},
+			"lock_method": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_LOCK_METHOD", "LOCK"),
+				Description: "The HTTP method to use when locking",
+			},
+			"unlock_method": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_UNLOCK_METHOD", "UNLOCK"),
+				Description: "The HTTP method to use when unlocking",
+			},
+			"username": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_USERNAME", nil),
+				Description: "The username for HTTP basic authentication",
+			},
+			"password": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_PASSWORD", nil),
+				Description: "The password for HTTP basic authentication",
+			},
+			"skip_cert_verification": &schema.Schema{
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Default:     false,
+				Description: "Whether to skip TLS verification.",
+			},
+			"retry_max": &schema.Schema{
+				Type:        schema.TypeInt,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_RETRY_MAX", 2),
+				Description: "The number of HTTP request retries.",
+			},
+			"retry_wait_min": &schema.Schema{
+				Type:        schema.TypeInt,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_RETRY_WAIT_MIN", 1),
+				Description: "The minimum time in seconds to wait between HTTP request attempts.",
+			},
+			"retry_wait_max": &schema.Schema{
+				Type:        schema.TypeInt,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_RETRY_WAIT_MAX", 30),
+				Description: "The maximum time in seconds to wait between HTTP request attempts.",
+			},
+			"client_ca_certificate_pem": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_CLIENT_CA_CERTIFICATE_PEM", ""),
+				Description: "A PEM-encoded CA certificate chain used by the client to verify server certificates during TLS authentication.",
+			},
+			"client_certificate_pem": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_CLIENT_CERTIFICATE_PEM", ""),
+				Description: "A PEM-encoded certificate used by the server to verify the client during mutual TLS (mTLS) authentication.",
+			},
+			"client_private_key_pem": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_CLIENT_PRIVATE_KEY_PEM", ""),
+				Description: "A PEM-encoded private key, required if client_certificate_pem is specified.",
+			},
+		},
+	}
+
+	b := &Backend{Backend: s}
+	b.Backend.ConfigureFunc = b.configure
+	return b
+}
+
+type Backend struct {
+	*schema.Backend
+
+	client *httpClient
+}
+
+// configureTLS configures TLS when needed; if there are no conditions requiring TLS, no change is made.
+func (b *Backend) configureTLS(client *retryablehttp.Client, data *schema.ResourceData) error {
+	// If there are no conditions needing to configure TLS, leave the client untouched
+	skipCertVerification := data.Get("skip_cert_verification").(bool)
+	clientCACertificatePem := data.Get("client_ca_certificate_pem").(string)
+	clientCertificatePem := data.Get("client_certificate_pem").(string)
+	clientPrivateKeyPem := data.Get("client_private_key_pem").(string)
+	if !skipCertVerification && clientCACertificatePem == "" && clientCertificatePem == "" && clientPrivateKeyPem == "" {
+		return nil
+	}
+	if clientCertificatePem != "" && clientPrivateKeyPem == "" {
+		return fmt.Errorf("client_certificate_pem is set but client_private_key_pem is not")
+	}
+	if clientPrivateKeyPem != "" && clientCertificatePem == "" {
+		return fmt.Errorf("client_private_key_pem is set but client_certificate_pem is not")
+	}
+
+	// TLS configuration is needed; create an object and configure it
+	var tlsConfig tls.Config
+	client.HTTPClient.Transport.(*http.Transport).TLSClientConfig = &tlsConfig
+
+	if skipCertVerification {
+		// ignores TLS verification
+		tlsConfig.InsecureSkipVerify = true
+	}
+	if clientCACertificatePem != "" {
+		// trust servers based on a CA
+		tlsConfig.RootCAs = x509.NewCertPool()
+		if !tlsConfig.RootCAs.AppendCertsFromPEM([]byte(clientCACertificatePem)) {
+			return errors.New("failed to append certs")
+		}
+	}
+	if clientCertificatePem != "" && clientPrivateKeyPem != "" {
+		// attach a client certificate to the TLS handshake (aka mTLS)
+		certificate, err := tls.X509KeyPair([]byte(clientCertificatePem), []byte(clientPrivateKeyPem))
+		if err != nil {
+			return fmt.Errorf("cannot load client certificate: %w", err)
+		}
+		tlsConfig.Certificates = []tls.Certificate{certificate}
+	}
+
+	return nil
+}
+
+func (b *Backend) configure(ctx context.Context) error {
+	data := schema.FromContextBackendConfig(ctx)
+
+	address := data.Get("address").(string)
+	updateURL, err := url.Parse(address)
+	if err != nil {
+		return fmt.Errorf("failed to parse address URL: %s", err)
+	}
+	if updateURL.Scheme != "http" && updateURL.Scheme != "https" {
+		return fmt.Errorf("address must be HTTP or HTTPS")
+	}
+
+	updateMethod := data.Get("update_method").(string)
+
+	var lockURL *url.URL
+	if v, ok := data.GetOk("lock_address"); ok && v.(string) != "" {
+		var err error
+		lockURL, err = url.Parse(v.(string))
+		if err != nil {
+			return fmt.Errorf("failed to parse lockAddress URL: %s", err)
+		}
+		if lockURL.Scheme != "http" && lockURL.Scheme != "https" {
+			return fmt.Errorf("lockAddress must be HTTP or HTTPS")
+		}
+	}
+
+	lockMethod := data.Get("lock_method").(string)
+
+	var unlockURL *url.URL
+	if v, ok := data.GetOk("unlock_address"); ok && v.(string) != "" {
+		var err error
+		unlockURL, err = url.Parse(v.(string))
+		if err != nil {
+			return fmt.Errorf("failed to parse unlockAddress URL: %s", err)
+		}
+		if unlockURL.Scheme != "http" && unlockURL.Scheme != "https" {
+			return fmt.Errorf("unlockAddress must be HTTP or HTTPS")
+		}
+	}
+
+	unlockMethod := data.Get("unlock_method").(string)
+
+	rClient := retryablehttp.NewClient()
+	rClient.RetryMax = data.Get("retry_max").(int)
+	rClient.RetryWaitMin = time.Duration(data.Get("retry_wait_min").(int)) * time.Second
+	rClient.RetryWaitMax = time.Duration(data.Get("retry_wait_max").(int)) * time.Second
+	rClient.Logger = log.New(logging.LogOutput(), "", log.Flags())
+	if err = b.configureTLS(rClient, data); err != nil {
+		return err
+	}
+
+	b.client = &httpClient{
+		URL:          updateURL,
+		UpdateMethod: updateMethod,
+
+		LockURL:      lockURL,
+		LockMethod:   lockMethod,
+		UnlockURL:    unlockURL,
+		UnlockMethod: unlockMethod,
+
+		Username: data.Get("username").(string),
+		Password: data.Get("password").(string),
+
+		// accessible only for testing use
+		Client: rClient,
+	}
+	return nil
+}
+
+func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
+	if name != backend.DefaultStateName {
+		return nil, backend.ErrWorkspacesNotSupported
+	}
+
+	return &remote.State{Client: b.client}, nil
+}
+
+func (b *Backend) Workspaces() ([]string, error) {
+	return nil, backend.ErrWorkspacesNotSupported
+}
+
+func (b *Backend) DeleteWorkspace(string, bool) error {
+	return backend.ErrWorkspacesNotSupported
+}
diff --git a/v1.5.7/internal/backend/remote-state/http/backend_test.go b/v1.5.7/internal/backend/remote-state/http/backend_test.go
new file mode 100644
index 0000000..6a38b0f
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/http/backend_test.go
@@ -0,0 +1,167 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package http
+
+import (
+	"os"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/backend"
+)
+
+func TestBackend_impl(t *testing.T) {
+	var _ backend.Backend = new(Backend)
+}
+
+func TestHTTPClientFactory(t *testing.T) {
+	// defaults
+
+	conf := map[string]cty.Value{
+		"address": cty.StringVal("http://127.0.0.1:8888/foo"),
+	}
+	b := backend.TestBackendConfig(t, New(), configs.SynthBody("synth", conf)).(*Backend)
+	client := b.client
+
+	if client == nil {
+		t.Fatal("Unexpected failure, address")
+	}
+	if client.URL.String() != "http://127.0.0.1:8888/foo" {
+		t.Fatalf("Expected address \"%s\", got \"%s\"", conf["address"], client.URL.String())
+	}
+	if client.UpdateMethod != "POST" {
+		t.Fatalf("Expected update_method \"%s\", got \"%s\"", "POST", client.UpdateMethod)
+	}
+	if client.LockURL != nil || client.LockMethod != "LOCK" {
+		t.Fatal("Unexpected lock_address or lock_method")
+	}
+	if client.UnlockURL != nil || client.UnlockMethod != "UNLOCK" {
+		t.Fatal("Unexpected unlock_address or unlock_method")
+	}
+	if client.Username != "" || client.Password != "" {
+		t.Fatal("Unexpected username or password")
+	}
+
+	// custom
+	conf = map[string]cty.Value{
+		"address":        cty.StringVal("http://127.0.0.1:8888/foo"),
+		"update_method":  cty.StringVal("BLAH"),
+		"lock_address":   cty.StringVal("http://127.0.0.1:8888/bar"),
+		"lock_method":    cty.StringVal("BLIP"),
+		"unlock_address": cty.StringVal("http://127.0.0.1:8888/baz"),
+		"unlock_method":  cty.StringVal("BLOOP"),
+		"username":       cty.StringVal("user"),
+		"password":       cty.StringVal("pass"),
+		"retry_max":      cty.StringVal("999"),
+		"retry_wait_min": cty.StringVal("15"),
+		"retry_wait_max": cty.StringVal("150"),
+	}
+
+	b = backend.TestBackendConfig(t, New(), configs.SynthBody("synth", conf)).(*Backend)
+	client = b.client
+
+	if client == nil {
+		t.Fatal("Unexpected failure, update_method")
+	}
+	if client.UpdateMethod != "BLAH" {
+		t.Fatalf("Expected update_method \"%s\", got \"%s\"", "BLAH", client.UpdateMethod)
+	}
+	if client.LockURL.String() != conf["lock_address"].AsString() || client.LockMethod != "BLIP" {
+		t.Fatalf("Unexpected lock_address \"%s\" vs \"%s\" or lock_method \"%s\" vs \"%s\"", client.LockURL.String(),
+			conf["lock_address"].AsString(), client.LockMethod, conf["lock_method"])
+	}
+	if client.UnlockURL.String() != conf["unlock_address"].AsString() || client.UnlockMethod != "BLOOP" {
+		t.Fatalf("Unexpected unlock_address \"%s\" vs \"%s\" or unlock_method \"%s\" vs \"%s\"", client.UnlockURL.String(),
+			conf["unlock_address"].AsString(), client.UnlockMethod, conf["unlock_method"])
+	}
+	if client.Username != "user" || client.Password != "pass" {
+		t.Fatalf("Unexpected username \"%s\" vs \"%s\" or password \"%s\" vs \"%s\"", client.Username, conf["username"],
+			client.Password, conf["password"])
+	}
+	if client.Client.RetryMax != 999 {
+		t.Fatalf("Expected retry_max \"%d\", got \"%d\"", 999, client.Client.RetryMax)
+	}
+	if client.Client.RetryWaitMin != 15*time.Second {
+		t.Fatalf("Expected retry_wait_min \"%s\", got \"%s\"", 15*time.Second, client.Client.RetryWaitMin)
+	}
+	if client.Client.RetryWaitMax != 150*time.Second {
+		t.Fatalf("Expected retry_wait_max \"%s\", got \"%s\"", 150*time.Second, client.Client.RetryWaitMax)
+	}
+}
+
+func TestHTTPClientFactoryWithEnv(t *testing.T) {
+	// env
+	conf := map[string]string{
+		"address":        "http://127.0.0.1:8888/foo",
+		"update_method":  "BLAH",
+		"lock_address":   "http://127.0.0.1:8888/bar",
+		"lock_method":    "BLIP",
+		"unlock_address": "http://127.0.0.1:8888/baz",
+		"unlock_method":  "BLOOP",
+		"username":       "user",
+		"password":       "pass",
+		"retry_max":      "999",
+		"retry_wait_min": "15",
+		"retry_wait_max": "150",
+	}
+
+	defer testWithEnv(t, "TF_HTTP_ADDRESS", conf["address"])()
+	defer testWithEnv(t, "TF_HTTP_UPDATE_METHOD", conf["update_method"])()
+	defer testWithEnv(t, "TF_HTTP_LOCK_ADDRESS", conf["lock_address"])()
+	defer testWithEnv(t, "TF_HTTP_UNLOCK_ADDRESS", conf["unlock_address"])()
+	defer testWithEnv(t, "TF_HTTP_LOCK_METHOD", conf["lock_method"])()
+	defer testWithEnv(t, "TF_HTTP_UNLOCK_METHOD", conf["unlock_method"])()
+	defer testWithEnv(t, "TF_HTTP_USERNAME", conf["username"])()
+	defer testWithEnv(t, "TF_HTTP_PASSWORD", conf["password"])()
+	defer testWithEnv(t, "TF_HTTP_RETRY_MAX", conf["retry_max"])()
+	defer testWithEnv(t, "TF_HTTP_RETRY_WAIT_MIN", conf["retry_wait_min"])()
+	defer testWithEnv(t, "TF_HTTP_RETRY_WAIT_MAX", conf["retry_wait_max"])()
+
+	b := backend.TestBackendConfig(t, New(), nil).(*Backend)
+	client := b.client
+
+	if client == nil {
+		t.Fatal("Unexpected failure, EnvDefaultFunc")
+	}
+	if client.UpdateMethod != "BLAH" {
+		t.Fatalf("Expected update_method \"%s\", got \"%s\"", "BLAH", client.UpdateMethod)
+	}
+	if client.LockURL.String() != conf["lock_address"] || client.LockMethod != "BLIP" {
+		t.Fatalf("Unexpected lock_address \"%s\" vs \"%s\" or lock_method \"%s\" vs \"%s\"", client.LockURL.String(),
+			conf["lock_address"], client.LockMethod, conf["lock_method"])
+	}
+	if client.UnlockURL.String() != conf["unlock_address"] || client.UnlockMethod != "BLOOP" {
+		t.Fatalf("Unexpected unlock_address \"%s\" vs \"%s\" or unlock_method \"%s\" vs \"%s\"", client.UnlockURL.String(),
+			conf["unlock_address"], client.UnlockMethod, conf["unlock_method"])
+	}
+	if client.Username != "user" || client.Password != "pass" {
+		t.Fatalf("Unexpected username \"%s\" vs \"%s\" or password \"%s\" vs \"%s\"", client.Username, conf["username"],
+			client.Password, conf["password"])
+	}
+	if client.Client.RetryMax != 999 {
+		t.Fatalf("Expected retry_max \"%d\", got \"%d\"", 999, client.Client.RetryMax)
+	}
+	if client.Client.RetryWaitMin != 15*time.Second {
+		t.Fatalf("Expected retry_wait_min \"%s\", got \"%s\"", 15*time.Second, client.Client.RetryWaitMin)
+	}
+	if client.Client.RetryWaitMax != 150*time.Second {
+		t.Fatalf("Expected retry_wait_max \"%s\", got \"%s\"", 150*time.Second, client.Client.RetryWaitMax)
+	}
+}
+
+// testWithEnv sets an environment variable and returns a deferable func to clean up
+func testWithEnv(t *testing.T, key string, value string) func() {
+	if err := os.Setenv(key, value); err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	return func() {
+		if err := os.Unsetenv(key); err != nil {
+			t.Fatalf("err: %v", err)
+		}
+	}
+}
diff --git a/v1.5.7/internal/backend/remote-state/http/client.go b/v1.5.7/internal/backend/remote-state/http/client.go
new file mode 100644
index 0000000..37f6268
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/http/client.go
@@ -0,0 +1,259 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package http
+
+import (
+	"bytes"
+	"crypto/md5"
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+
+	"github.com/hashicorp/go-retryablehttp"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+// httpClient is a remote client that stores data in Consul or HTTP REST.
+type httpClient struct {
+	// Update & Retrieve
+	URL          *url.URL
+	UpdateMethod string
+
+	// Locking
+	LockURL      *url.URL
+	LockMethod   string
+	UnlockURL    *url.URL
+	UnlockMethod string
+
+	// HTTP
+	Client   *retryablehttp.Client
+	Username string
+	Password string
+
+	lockID       string
+	jsonLockInfo []byte
+}
+
+func (c *httpClient) httpRequest(method string, url *url.URL, data *[]byte, what string) (*http.Response, error) {
+	// If we have data we need a reader
+	var reader io.Reader = nil
+	if data != nil {
+		reader = bytes.NewReader(*data)
+	}
+
+	// Create the request
+	req, err := retryablehttp.NewRequest(method, url.String(), reader)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to make %s HTTP request: %s", what, err)
+	}
+	// Set up basic auth
+	if c.Username != "" {
+		req.SetBasicAuth(c.Username, c.Password)
+	}
+
+	// Work with data/body
+	if data != nil {
+		req.Header.Set("Content-Type", "application/json")
+		req.ContentLength = int64(len(*data))
+
+		// Generate the MD5
+		hash := md5.Sum(*data)
+		b64 := base64.StdEncoding.EncodeToString(hash[:])
+		req.Header.Set("Content-MD5", b64)
+	}
+
+	// Make the request
+	resp, err := c.Client.Do(req)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to %s: %v", what, err)
+	}
+
+	return resp, nil
+}
+
+func (c *httpClient) Lock(info *statemgr.LockInfo) (string, error) {
+	if c.LockURL == nil {
+		return "", nil
+	}
+	c.lockID = ""
+
+	jsonLockInfo := info.Marshal()
+	resp, err := c.httpRequest(c.LockMethod, c.LockURL, &jsonLockInfo, "lock")
+	if err != nil {
+		return "", err
+	}
+	defer resp.Body.Close()
+
+	switch resp.StatusCode {
+	case http.StatusOK:
+		c.lockID = info.ID
+		c.jsonLockInfo = jsonLockInfo
+		return info.ID, nil
+	case http.StatusUnauthorized:
+		return "", fmt.Errorf("HTTP remote state endpoint requires auth")
+	case http.StatusForbidden:
+		return "", fmt.Errorf("HTTP remote state endpoint invalid auth")
+	case http.StatusConflict, http.StatusLocked:
+		defer resp.Body.Close()
+		body, err := ioutil.ReadAll(resp.Body)
+		if err != nil {
+			return "", &statemgr.LockError{
+				Info: info,
+				Err:  fmt.Errorf("HTTP remote state already locked, failed to read body"),
+			}
+		}
+		existing := statemgr.LockInfo{}
+		err = json.Unmarshal(body, &existing)
+		if err != nil {
+			return "", &statemgr.LockError{
+				Info: info,
+				Err:  fmt.Errorf("HTTP remote state already locked, failed to unmarshal body"),
+			}
+		}
+		return "", &statemgr.LockError{
+			Info: info,
+			Err:  fmt.Errorf("HTTP remote state already locked: ID=%s", existing.ID),
+		}
+	default:
+		return "", fmt.Errorf("Unexpected HTTP response code %d", resp.StatusCode)
+	}
+}
+
+func (c *httpClient) Unlock(id string) error {
+	if c.UnlockURL == nil {
+		return nil
+	}
+
+	resp, err := c.httpRequest(c.UnlockMethod, c.UnlockURL, &c.jsonLockInfo, "unlock")
+	if err != nil {
+		return err
+	}
+	defer resp.Body.Close()
+
+	switch resp.StatusCode {
+	case http.StatusOK:
+		return nil
+	default:
+		return fmt.Errorf("Unexpected HTTP response code %d", resp.StatusCode)
+	}
+}
+
+func (c *httpClient) Get() (*remote.Payload, error) {
+	resp, err := c.httpRequest("GET", c.URL, nil, "get state")
+	if err != nil {
+		return nil, err
+	}
+	defer resp.Body.Close()
+
+	// Handle the common status codes
+	switch resp.StatusCode {
+	case http.StatusOK:
+		// Handled after
+	case http.StatusNoContent:
+		return nil, nil
+	case http.StatusNotFound:
+		return nil, nil
+	case http.StatusUnauthorized:
+		return nil, fmt.Errorf("HTTP remote state endpoint requires auth")
+	case http.StatusForbidden:
+		return nil, fmt.Errorf("HTTP remote state endpoint invalid auth")
+	case http.StatusInternalServerError:
+		return nil, fmt.Errorf("HTTP remote state internal server error")
+	default:
+		return nil, fmt.Errorf("Unexpected HTTP response code %d", resp.StatusCode)
+	}
+
+	// Read in the body
+	buf := bytes.NewBuffer(nil)
+	if _, err := io.Copy(buf, resp.Body); err != nil {
+		return nil, fmt.Errorf("Failed to read remote state: %s", err)
+	}
+
+	// Create the payload
+	payload := &remote.Payload{
+		Data: buf.Bytes(),
+	}
+
+	// If there was no data, then return nil
+	if len(payload.Data) == 0 {
+		return nil, nil
+	}
+
+	// Check for the MD5
+	if raw := resp.Header.Get("Content-MD5"); raw != "" {
+		md5, err := base64.StdEncoding.DecodeString(raw)
+		if err != nil {
+			return nil, fmt.Errorf(
+				"Failed to decode Content-MD5 '%s': %s", raw, err)
+		}
+
+		payload.MD5 = md5
+	} else {
+		// Generate the MD5
+		hash := md5.Sum(payload.Data)
+		payload.MD5 = hash[:]
+	}
+
+	return payload, nil
+}
+
+func (c *httpClient) Put(data []byte) error {
+	// Copy the target URL
+	base := *c.URL
+
+	if c.lockID != "" {
+		query := base.Query()
+		query.Set("ID", c.lockID)
+		base.RawQuery = query.Encode()
+	}
+
+	/*
+		// Set the force query parameter if needed
+		if force {
+			values := base.Query()
+			values.Set("force", "true")
+			base.RawQuery = values.Encode()
+		}
+	*/
+
+	var method string = "POST"
+	if c.UpdateMethod != "" {
+		method = c.UpdateMethod
+	}
+	resp, err := c.httpRequest(method, &base, &data, "upload state")
+	if err != nil {
+		return err
+	}
+	defer resp.Body.Close()
+
+	// Handle the error codes
+	switch resp.StatusCode {
+	case http.StatusOK, http.StatusCreated, http.StatusNoContent:
+		return nil
+	default:
+		return fmt.Errorf("HTTP error: %d", resp.StatusCode)
+	}
+}
+
+func (c *httpClient) Delete() error {
+	// Make the request
+	resp, err := c.httpRequest("DELETE", c.URL, nil, "delete state")
+	if err != nil {
+		return err
+	}
+	defer resp.Body.Close()
+
+	// Handle the error codes
+	switch resp.StatusCode {
+	case http.StatusOK:
+		return nil
+	default:
+		return fmt.Errorf("HTTP error: %d", resp.StatusCode)
+	}
+}
diff --git a/v1.5.7/internal/backend/remote-state/http/client_test.go b/v1.5.7/internal/backend/remote-state/http/client_test.go
new file mode 100644
index 0000000..7cc41f9
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/http/client_test.go
@@ -0,0 +1,178 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package http
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"reflect"
+	"testing"
+
+	"github.com/hashicorp/go-retryablehttp"
+	"github.com/hashicorp/terraform/internal/states/remote"
+)
+
+func TestHTTPClient_impl(t *testing.T) {
+	var _ remote.Client = new(httpClient)
+	var _ remote.ClientLocker = new(httpClient)
+}
+
+func TestHTTPClient(t *testing.T) {
+	handler := new(testHTTPHandler)
+	ts := httptest.NewServer(http.HandlerFunc(handler.Handle))
+	defer ts.Close()
+
+	url, err := url.Parse(ts.URL)
+	if err != nil {
+		t.Fatalf("Parse: %s", err)
+	}
+
+	// Test basic get/update
+	client := &httpClient{URL: url, Client: retryablehttp.NewClient()}
+	remote.TestClient(t, client)
+
+	// test just a single PUT
+	p := &httpClient{
+		URL:          url,
+		UpdateMethod: "PUT",
+		Client:       retryablehttp.NewClient(),
+	}
+	remote.TestClient(t, p)
+
+	// Test locking and alternative UpdateMethod
+	a := &httpClient{
+		URL:          url,
+		UpdateMethod: "PUT",
+		LockURL:      url,
+		LockMethod:   "LOCK",
+		UnlockURL:    url,
+		UnlockMethod: "UNLOCK",
+		Client:       retryablehttp.NewClient(),
+	}
+	b := &httpClient{
+		URL:          url,
+		UpdateMethod: "PUT",
+		LockURL:      url,
+		LockMethod:   "LOCK",
+		UnlockURL:    url,
+		UnlockMethod: "UNLOCK",
+		Client:       retryablehttp.NewClient(),
+	}
+	remote.TestRemoteLocks(t, a, b)
+
+	// test a WebDAV-ish backend
+	davhandler := new(testHTTPHandler)
+	ts = httptest.NewServer(http.HandlerFunc(davhandler.HandleWebDAV))
+	defer ts.Close()
+
+	url, err = url.Parse(ts.URL)
+	client = &httpClient{
+		URL:          url,
+		UpdateMethod: "PUT",
+		Client:       retryablehttp.NewClient(),
+	}
+	if err != nil {
+		t.Fatalf("Parse: %s", err)
+	}
+
+	remote.TestClient(t, client) // first time through: 201
+	remote.TestClient(t, client) // second time, with identical data: 204
+
+	// test a broken backend
+	brokenHandler := new(testBrokenHTTPHandler)
+	brokenHandler.handler = new(testHTTPHandler)
+	ts = httptest.NewServer(http.HandlerFunc(brokenHandler.Handle))
+	defer ts.Close()
+
+	url, err = url.Parse(ts.URL)
+	if err != nil {
+		t.Fatalf("Parse: %s", err)
+	}
+	client = &httpClient{URL: url, Client: retryablehttp.NewClient()}
+	remote.TestClient(t, client)
+}
+
+type testHTTPHandler struct {
+	Data   []byte
+	Locked bool
+}
+
+func (h *testHTTPHandler) Handle(w http.ResponseWriter, r *http.Request) {
+	switch r.Method {
+	case "GET":
+		w.Write(h.Data)
+	case "PUT":
+		buf := new(bytes.Buffer)
+		if _, err := io.Copy(buf, r.Body); err != nil {
+			w.WriteHeader(500)
+		}
+		w.WriteHeader(201)
+		h.Data = buf.Bytes()
+	case "POST":
+		buf := new(bytes.Buffer)
+		if _, err := io.Copy(buf, r.Body); err != nil {
+			w.WriteHeader(500)
+		}
+		h.Data = buf.Bytes()
+	case "LOCK":
+		if h.Locked {
+			w.WriteHeader(423)
+		} else {
+			h.Locked = true
+		}
+	case "UNLOCK":
+		h.Locked = false
+	case "DELETE":
+		h.Data = nil
+		w.WriteHeader(200)
+	default:
+		w.WriteHeader(500)
+		w.Write([]byte(fmt.Sprintf("Unknown method: %s", r.Method)))
+	}
+}
+
+// mod_dav-ish behavior
+func (h *testHTTPHandler) HandleWebDAV(w http.ResponseWriter, r *http.Request) {
+	switch r.Method {
+	case "GET":
+		w.Write(h.Data)
+	case "PUT":
+		buf := new(bytes.Buffer)
+		if _, err := io.Copy(buf, r.Body); err != nil {
+			w.WriteHeader(500)
+		}
+		if reflect.DeepEqual(h.Data, buf.Bytes()) {
+			h.Data = buf.Bytes()
+			w.WriteHeader(204)
+		} else {
+			h.Data = buf.Bytes()
+			w.WriteHeader(201)
+		}
+	case "DELETE":
+		h.Data = nil
+		w.WriteHeader(200)
+	default:
+		w.WriteHeader(500)
+		w.Write([]byte(fmt.Sprintf("Unknown method: %s", r.Method)))
+	}
+}
+
+type testBrokenHTTPHandler struct {
+	lastRequestWasBroken bool
+	handler              *testHTTPHandler
+}
+
+func (h *testBrokenHTTPHandler) Handle(w http.ResponseWriter, r *http.Request) {
+	if h.lastRequestWasBroken {
+		h.lastRequestWasBroken = false
+		h.handler.Handle(w, r)
+	} else {
+		h.lastRequestWasBroken = true
+		w.WriteHeader(500)
+	}
+}
diff --git a/v1.5.7/internal/backend/remote-state/http/mock_server_test.go b/v1.5.7/internal/backend/remote-state/http/mock_server_test.go
new file mode 100644
index 0000000..ac6a3e3
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/http/mock_server_test.go
@@ -0,0 +1,95 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: server_test.go
+
+// Package http is a generated GoMock package.
+package http
+
+import (
+	http "net/http"
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockHttpServerCallback is a mock of HttpServerCallback interface.
+type MockHttpServerCallback struct {
+	ctrl     *gomock.Controller
+	recorder *MockHttpServerCallbackMockRecorder
+}
+
+// MockHttpServerCallbackMockRecorder is the mock recorder for MockHttpServerCallback.
+type MockHttpServerCallbackMockRecorder struct {
+	mock *MockHttpServerCallback
+}
+
+// NewMockHttpServerCallback creates a new mock instance.
+func NewMockHttpServerCallback(ctrl *gomock.Controller) *MockHttpServerCallback {
+	mock := &MockHttpServerCallback{ctrl: ctrl}
+	mock.recorder = &MockHttpServerCallbackMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockHttpServerCallback) EXPECT() *MockHttpServerCallbackMockRecorder {
+	return m.recorder
+}
+
+// StateDELETE mocks base method.
+func (m *MockHttpServerCallback) StateDELETE(req *http.Request) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "StateDELETE", req)
+}
+
+// StateDELETE indicates an expected call of StateDELETE.
+func (mr *MockHttpServerCallbackMockRecorder) StateDELETE(req interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateDELETE", reflect.TypeOf((*MockHttpServerCallback)(nil).StateDELETE), req)
+}
+
+// StateGET mocks base method.
+func (m *MockHttpServerCallback) StateGET(req *http.Request) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "StateGET", req)
+}
+
+// StateGET indicates an expected call of StateGET.
+func (mr *MockHttpServerCallbackMockRecorder) StateGET(req interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateGET", reflect.TypeOf((*MockHttpServerCallback)(nil).StateGET), req)
+}
+
+// StateLOCK mocks base method.
+func (m *MockHttpServerCallback) StateLOCK(req *http.Request) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "StateLOCK", req)
+}
+
+// StateLOCK indicates an expected call of StateLOCK.
+func (mr *MockHttpServerCallbackMockRecorder) StateLOCK(req interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateLOCK", reflect.TypeOf((*MockHttpServerCallback)(nil).StateLOCK), req)
+}
+
+// StatePOST mocks base method.
+func (m *MockHttpServerCallback) StatePOST(req *http.Request) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "StatePOST", req)
+}
+
+// StatePOST indicates an expected call of StatePOST.
+func (mr *MockHttpServerCallbackMockRecorder) StatePOST(req interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StatePOST", reflect.TypeOf((*MockHttpServerCallback)(nil).StatePOST), req)
+}
+
+// StateUNLOCK mocks base method.
+func (m *MockHttpServerCallback) StateUNLOCK(req *http.Request) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "StateUNLOCK", req)
+}
+
+// StateUNLOCK indicates an expected call of StateUNLOCK.
+func (mr *MockHttpServerCallbackMockRecorder) StateUNLOCK(req interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateUNLOCK", reflect.TypeOf((*MockHttpServerCallback)(nil).StateUNLOCK), req)
+}
diff --git a/v1.5.7/internal/backend/remote-state/http/server_test.go b/v1.5.7/internal/backend/remote-state/http/server_test.go
new file mode 100644
index 0000000..58c084f
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/http/server_test.go
@@ -0,0 +1,425 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package http
+
+//go:generate go run github.com/golang/mock/mockgen -package $GOPACKAGE -source $GOFILE -destination mock_$GOFILE
+
+import (
+	"context"
+	"crypto/tls"
+	"crypto/x509"
+	"encoding/json"
+	"io"
+	"net/http"
+	"net/http/httptest"
+	"os"
+	"os/signal"
+	"path/filepath"
+	"reflect"
+	"strings"
+	"sync"
+	"syscall"
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/zclconf/go-cty/cty"
+)
+
+const sampleState = `
+{
+    "version": 4,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "remote": {
+        "type": "http",
+        "config": {
+            "path": "local-state.tfstate"
+        }
+    }
+}
+`
+
+type (
+	HttpServerCallback interface {
+		StateGET(req *http.Request)
+		StatePOST(req *http.Request)
+		StateDELETE(req *http.Request)
+		StateLOCK(req *http.Request)
+		StateUNLOCK(req *http.Request)
+	}
+	httpServer struct {
+		r     *http.ServeMux
+		data  map[string]string
+		locks map[string]string
+		lock  sync.RWMutex
+
+		httpServerCallback HttpServerCallback
+	}
+	httpServerOpt func(*httpServer)
+)
+
+func withHttpServerCallback(callback HttpServerCallback) httpServerOpt {
+	return func(s *httpServer) {
+		s.httpServerCallback = callback
+	}
+}
+
+func newHttpServer(opts ...httpServerOpt) *httpServer {
+	r := http.NewServeMux()
+	s := &httpServer{
+		r:     r,
+		data:  make(map[string]string),
+		locks: make(map[string]string),
+	}
+	for _, opt := range opts {
+		opt(s)
+	}
+	s.data["sample"] = sampleState
+	r.HandleFunc("/state/", s.handleState)
+	return s
+}
+
+func (h *httpServer) getResource(req *http.Request) string {
+	switch pathParts := strings.SplitN(req.URL.Path, string(filepath.Separator), 3); len(pathParts) {
+	case 3:
+		return pathParts[2]
+	default:
+		return ""
+	}
+}
+
+func (h *httpServer) handleState(writer http.ResponseWriter, req *http.Request) {
+	switch req.Method {
+	case "GET":
+		h.handleStateGET(writer, req)
+	case "POST":
+		h.handleStatePOST(writer, req)
+	case "DELETE":
+		h.handleStateDELETE(writer, req)
+	case "LOCK":
+		h.handleStateLOCK(writer, req)
+	case "UNLOCK":
+		h.handleStateUNLOCK(writer, req)
+	}
+}
+
+func (h *httpServer) handleStateGET(writer http.ResponseWriter, req *http.Request) {
+	if h.httpServerCallback != nil {
+		defer h.httpServerCallback.StateGET(req)
+	}
+	resource := h.getResource(req)
+
+	h.lock.RLock()
+	defer h.lock.RUnlock()
+
+	if state, ok := h.data[resource]; ok {
+		_, _ = io.WriteString(writer, state)
+	} else {
+		writer.WriteHeader(http.StatusNotFound)
+	}
+}
+
+func (h *httpServer) handleStatePOST(writer http.ResponseWriter, req *http.Request) {
+	if h.httpServerCallback != nil {
+		defer h.httpServerCallback.StatePOST(req)
+	}
+	defer req.Body.Close()
+	resource := h.getResource(req)
+
+	data, err := io.ReadAll(req.Body)
+	if err != nil {
+		writer.WriteHeader(http.StatusBadRequest)
+		return
+	}
+
+	h.lock.Lock()
+	defer h.lock.Unlock()
+
+	h.data[resource] = string(data)
+	writer.WriteHeader(http.StatusOK)
+}
+
+func (h *httpServer) handleStateDELETE(writer http.ResponseWriter, req *http.Request) {
+	if h.httpServerCallback != nil {
+		defer h.httpServerCallback.StateDELETE(req)
+	}
+	resource := h.getResource(req)
+
+	h.lock.Lock()
+	defer h.lock.Unlock()
+
+	delete(h.data, resource)
+	writer.WriteHeader(http.StatusOK)
+}
+
+func (h *httpServer) handleStateLOCK(writer http.ResponseWriter, req *http.Request) {
+	if h.httpServerCallback != nil {
+		defer h.httpServerCallback.StateLOCK(req)
+	}
+	defer req.Body.Close()
+	resource := h.getResource(req)
+
+	data, err := io.ReadAll(req.Body)
+	if err != nil {
+		writer.WriteHeader(http.StatusBadRequest)
+		return
+	}
+
+	h.lock.Lock()
+	defer h.lock.Unlock()
+
+	if existingLock, ok := h.locks[resource]; ok {
+		writer.WriteHeader(http.StatusLocked)
+		_, _ = io.WriteString(writer, existingLock)
+	} else {
+		h.locks[resource] = string(data)
+		_, _ = io.WriteString(writer, existingLock)
+	}
+}
+
+func (h *httpServer) handleStateUNLOCK(writer http.ResponseWriter, req *http.Request) {
+	if h.httpServerCallback != nil {
+		defer h.httpServerCallback.StateUNLOCK(req)
+	}
+	defer req.Body.Close()
+	resource := h.getResource(req)
+
+	data, err := io.ReadAll(req.Body)
+	if err != nil {
+		writer.WriteHeader(http.StatusBadRequest)
+		return
+	}
+	var lockInfo map[string]interface{}
+	if err = json.Unmarshal(data, &lockInfo); err != nil {
+		writer.WriteHeader(http.StatusInternalServerError)
+		return
+	}
+
+	h.lock.Lock()
+	defer h.lock.Unlock()
+
+	if existingLock, ok := h.locks[resource]; ok {
+		var existingLockInfo map[string]interface{}
+		if err = json.Unmarshal([]byte(existingLock), &existingLockInfo); err != nil {
+			writer.WriteHeader(http.StatusInternalServerError)
+			return
+		}
+		lockID := lockInfo["ID"].(string)
+		existingID := existingLockInfo["ID"].(string)
+		if lockID != existingID {
+			writer.WriteHeader(http.StatusConflict)
+			_, _ = io.WriteString(writer, existingLock)
+		} else {
+			delete(h.locks, resource)
+			_, _ = io.WriteString(writer, existingLock)
+		}
+	} else {
+		writer.WriteHeader(http.StatusConflict)
+	}
+}
+
+func (h *httpServer) handler() http.Handler {
+	return h.r
+}
+
+func NewHttpTestServer(opts ...httpServerOpt) (*httptest.Server, error) {
+	clientCAData, err := os.ReadFile("testdata/certs/ca.cert.pem")
+	if err != nil {
+		return nil, err
+	}
+	clientCAs := x509.NewCertPool()
+	clientCAs.AppendCertsFromPEM(clientCAData)
+
+	cert, err := tls.LoadX509KeyPair("testdata/certs/server.crt", "testdata/certs/server.key")
+	if err != nil {
+		return nil, err
+	}
+
+	h := newHttpServer(opts...)
+	s := httptest.NewUnstartedServer(h.handler())
+	s.TLS = &tls.Config{
+		ClientAuth:   tls.RequireAndVerifyClientCert,
+		ClientCAs:    clientCAs,
+		Certificates: []tls.Certificate{cert},
+	}
+
+	s.StartTLS()
+	return s, nil
+}
+
+func TestMTLSServer_NoCertFails(t *testing.T) {
+	// Ensure that no calls are made to the server - everything is blocked by the tls.RequireAndVerifyClientCert
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+	mockCallback := NewMockHttpServerCallback(ctrl)
+
+	// Fire up a test server
+	ts, err := NewHttpTestServer(withHttpServerCallback(mockCallback))
+	if err != nil {
+		t.Fatalf("unexpected error creating test server: %v", err)
+	}
+	defer ts.Close()
+
+	// Configure the backend to the pre-populated sample state
+	url := ts.URL + "/state/sample"
+	conf := map[string]cty.Value{
+		"address":                cty.StringVal(url),
+		"skip_cert_verification": cty.BoolVal(true),
+	}
+	b := backend.TestBackendConfig(t, New(), configs.SynthBody("synth", conf)).(*Backend)
+	if nil == b {
+		t.Fatal("nil backend")
+	}
+
+	// Now get a state manager and check that it fails to refresh the state
+	sm, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error fetching StateMgr with %s: %v", backend.DefaultStateName, err)
+	}
+	err = sm.RefreshState()
+	if nil == err {
+		t.Error("expected error when refreshing state without a client cert")
+	} else if !strings.Contains(err.Error(), "remote error: tls: bad certificate") {
+		t.Errorf("expected the error to report missing tls credentials: %v", err)
+	}
+}
+
+func TestMTLSServer_WithCertPasses(t *testing.T) {
+	// Ensure that the expected amount of calls is made to the server
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+	mockCallback := NewMockHttpServerCallback(ctrl)
+
+	// Two or three (not testing the caching here) calls to GET
+	mockCallback.EXPECT().
+		StateGET(gomock.Any()).
+		MinTimes(2).
+		MaxTimes(3)
+	// One call to the POST to write the data
+	mockCallback.EXPECT().
+		StatePOST(gomock.Any())
+
+	// Fire up a test server
+	ts, err := NewHttpTestServer(withHttpServerCallback(mockCallback))
+	if err != nil {
+		t.Fatalf("unexpected error creating test server: %v", err)
+	}
+	defer ts.Close()
+
+	// Configure the backend to the pre-populated sample state, and with all the test certs lined up
+	url := ts.URL + "/state/sample"
+	caData, err := os.ReadFile("testdata/certs/ca.cert.pem")
+	if err != nil {
+		t.Fatalf("error reading ca certs: %v", err)
+	}
+	clientCertData, err := os.ReadFile("testdata/certs/client.crt")
+	if err != nil {
+		t.Fatalf("error reading client cert: %v", err)
+	}
+	clientKeyData, err := os.ReadFile("testdata/certs/client.key")
+	if err != nil {
+		t.Fatalf("error reading client key: %v", err)
+	}
+	conf := map[string]cty.Value{
+		"address":                   cty.StringVal(url),
+		"lock_address":              cty.StringVal(url),
+		"unlock_address":            cty.StringVal(url),
+		"client_ca_certificate_pem": cty.StringVal(string(caData)),
+		"client_certificate_pem":    cty.StringVal(string(clientCertData)),
+		"client_private_key_pem":    cty.StringVal(string(clientKeyData)),
+	}
+	b := backend.TestBackendConfig(t, New(), configs.SynthBody("synth", conf)).(*Backend)
+	if nil == b {
+		t.Fatal("nil backend")
+	}
+
+	// Now get a state manager, fetch the state, and ensure that the "foo" output is not set
+	sm, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error fetching StateMgr with %s: %v", backend.DefaultStateName, err)
+	}
+	if err = sm.RefreshState(); err != nil {
+		t.Fatalf("unexpected error calling RefreshState: %v", err)
+	}
+	state := sm.State()
+	if nil == state {
+		t.Fatal("nil state")
+	}
+	stateFoo := state.OutputValue(addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance))
+	if stateFoo != nil {
+		t.Errorf("expected nil foo from state; got %v", stateFoo)
+	}
+
+	// Create a new state that has "foo" set to "bar" and ensure that state is as expected
+	state = states.BuildState(func(ss *states.SyncState) {
+		ss.SetOutputValue(
+			addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance),
+			cty.StringVal("bar"),
+			false)
+	})
+	stateFoo = state.OutputValue(addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance))
+	if nil == stateFoo {
+		t.Fatal("nil foo after building state with foo populated")
+	}
+	if foo := stateFoo.Value.AsString(); foo != "bar" {
+		t.Errorf("Expected built state foo value to be bar; got %s", foo)
+	}
+
+	// Ensure the change hasn't altered the current state manager state by checking "foo" and comparing states
+	curState := sm.State()
+	curStateFoo := curState.OutputValue(addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance))
+	if curStateFoo != nil {
+		t.Errorf("expected session manager state to be unaltered and still nil, but got: %v", curStateFoo)
+	}
+	if reflect.DeepEqual(state, curState) {
+		t.Errorf("expected %v != %v; but they were equal", state, curState)
+	}
+
+	// Write the new state, persist, and refresh
+	if err = sm.WriteState(state); err != nil {
+		t.Errorf("error writing state: %v", err)
+	}
+	if err = sm.PersistState(nil); err != nil {
+		t.Errorf("error persisting state: %v", err)
+	}
+	if err = sm.RefreshState(); err != nil {
+		t.Errorf("error refreshing state: %v", err)
+	}
+
+	// Get the state again and verify that is now the same as state and has the "foo" value set to "bar"
+	curState = sm.State()
+	if !reflect.DeepEqual(state, curState) {
+		t.Errorf("expected %v == %v; but they were unequal", state, curState)
+	}
+	curStateFoo = curState.OutputValue(addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance))
+	if nil == curStateFoo {
+		t.Fatal("nil foo")
+	}
+	if foo := curStateFoo.Value.AsString(); foo != "bar" {
+		t.Errorf("expected foo to be bar, but got: %s", foo)
+	}
+}
+
+// TestRunServer allows running the server for local debugging; it runs until ctl-c is received
+func TestRunServer(t *testing.T) {
+	if _, ok := os.LookupEnv("TEST_RUN_SERVER"); !ok {
+		t.Skip("TEST_RUN_SERVER not set")
+	}
+	s, err := NewHttpTestServer()
+	if err != nil {
+		t.Fatalf("unexpected error creating test server: %v", err)
+	}
+	defer s.Close()
+
+	t.Log(s.URL)
+
+	ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
+	defer cancel()
+	// wait until signal
+	<-ctx.Done()
+}
diff --git a/v1.5.7/internal/backend/remote-state/http/testdata/certs/ca.cert.pem b/v1.5.7/internal/backend/remote-state/http/testdata/certs/ca.cert.pem
new file mode 100644
index 0000000..81e6201
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/http/testdata/certs/ca.cert.pem
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIFBzCCAu+gAwIBAgIUFPfAxSWlzjWAdQAW+uDbciQm3SowDQYJKoZIhvcNAQEL
+BQAwEjEQMA4GA1UEAwwHdGVzdC5jYTAgFw0yMjEwMTMyMTE4MTlaGA8zMDIyMDIx
+MzIxMTgxOVowEjEQMA4GA1UEAwwHdGVzdC5jYTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAJUdKvIM9q7H8TLqj0O6qHUnbE0N3dnNNGVtyO7Nkn4t7urx
+X4qmQ6nMzKlC5YhGIlOKO4X0kPXf623+bP+jUf9qAFLkx5SK9TDerhh3e9y9+0YY
+C+CM8bQdJD7jFN1oOcKTJipNbjVXCqWqrBXJg91v3p4kyUvGUv05d3pU9nQvKd7R
+BGdWh68hjPFqdFso+A1ggxwJ4pEQCllxLu60RpRFwPoup/BeblPz9f3voeqhxT1J
+RLviG6HhpMxh44qNh8UrWGyaAk2C5c0rghBUHdfx/RgP2cYuUo5fhPYOHhO0lX80
+0LebXA6nwOhVeHNvrRfjEJS3tTWaFXyaOUiJT2QX2nG0i6cx6pS8dLMMSFLjMSX6
+bTH3KtTR+UrOfC3B47FOO5U++EnBg3WiZCKp+i8+5Sc3MjTw4B8cmydYr59hNWrk
+8zrfG1uE6WvxKg1bRc1FcixERcLnIbRH6LE3hHXzYlLoJ8+q9zP0EGqGHycSlv+C
+E+6QMMKU0u2tHnixqhlt79ad6bpC52VS3lFt3Fh/TEKWjS1rn2hYZKGSymJpbPFn
+q1RQZcxZWjKjqi5UEuAVGfBc4+HLZHq2Vq9umjLn0nuVixjBeBsCBaFC/amksFEJ
+fAmMXDERO7Hb4vePq1t9iusWrRPhkvZt6R1Pozg1Ls+xSJQE09n3jWd0/fMhAgMB
+AAGjUzBRMB0GA1UdDgQWBBSe+CLJRDjlHurYVRcXvhXyohcVdDAfBgNVHSMEGDAW
+gBSe+CLJRDjlHurYVRcXvhXyohcVdDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
+DQEBCwUAA4ICAQBluWhlAuG7CfMP31aJzl9AucHHLwfAECKg35XTPiF+YrL7rcbQ
+0dQyErCXyx7lLGEMqfNxVW48JtLCAATAZk3PwaQdU5OTcKA6Q/mQJwagfgmCVC5+
+Y4fdc7HhfOkGCOQ7aqyJ/EmygafgShreNimRDgIFomEs2hEEKAfvq2YBKcfcDyS7
+vCJZgzKoDmFe4DJjnYN/Gmj/4ak1kwtkoTkwdBlK+zWfbWHSUweXjCvbPPhKCPfy
+3Vu++BIW7402aLsP4xyQY/HPGErV3l1TpY3FdCENGQXANF/gPDWj/Q92OdTMRL0U
+XXSshNT3YjCxUH3M4A07A11TQwXZRFs2AkZyjJ6M5XNd36FswHh7fSjNLThU6h2V
+dI0y/rU4y24KG7KeUayTE1HLGGDskZdXSOL2vH/MTvpheKnLE8fQrKb/SgY+l9RA
+fIKwjDfMSL11luuSUIdevt5CEGFms8hpLU1RG2z/qSYz3If/dhN6YdiFJ54Qhjw9
+J5UO4eucsCm3MmsX2jUsDUIjHu92Rt7a3N21lVwzAifwwUzlDrY5xFrtpdhiSEAd
+HFmIQOEr3C9xqD3v3b/4N9SoOjZS2j4xk+GQ8XZeTDYf8ZlkXvXHWwEHbVqj0toe
+WDooC6oivNJAEs2GxJpyLmmfxIbRjE1sdmVZtmlSb3hY0Rme1SF9FoyZDw==
+-----END CERTIFICATE-----
diff --git a/v1.5.7/internal/backend/remote-state/http/testdata/certs/ca.key b/v1.5.7/internal/backend/remote-state/http/testdata/certs/ca.key
new file mode 100644
index 0000000..e297d3a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/http/testdata/certs/ca.key
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCVHSryDPaux/Ey
+6o9Duqh1J2xNDd3ZzTRlbcjuzZJ+Le7q8V+KpkOpzMypQuWIRiJTijuF9JD13+tt
+/mz/o1H/agBS5MeUivUw3q4Yd3vcvftGGAvgjPG0HSQ+4xTdaDnCkyYqTW41Vwql
+qqwVyYPdb96eJMlLxlL9OXd6VPZ0Lyne0QRnVoevIYzxanRbKPgNYIMcCeKREApZ
+cS7utEaURcD6LqfwXm5T8/X976HqocU9SUS74huh4aTMYeOKjYfFK1hsmgJNguXN
+K4IQVB3X8f0YD9nGLlKOX4T2Dh4TtJV/NNC3m1wOp8DoVXhzb60X4xCUt7U1mhV8
+mjlIiU9kF9pxtIunMeqUvHSzDEhS4zEl+m0x9yrU0flKznwtweOxTjuVPvhJwYN1
+omQiqfovPuUnNzI08OAfHJsnWK+fYTVq5PM63xtbhOlr8SoNW0XNRXIsREXC5yG0
+R+ixN4R182JS6CfPqvcz9BBqhh8nEpb/ghPukDDClNLtrR54saoZbe/Wnem6Qudl
+Ut5RbdxYf0xClo0ta59oWGShkspiaWzxZ6tUUGXMWVoyo6ouVBLgFRnwXOPhy2R6
+tlavbpoy59J7lYsYwXgbAgWhQv2ppLBRCXwJjFwxETux2+L3j6tbfYrrFq0T4ZL2
+bekdT6M4NS7PsUiUBNPZ941ndP3zIQIDAQABAoICACEM6/3mfa7TxlRgxQxgDQKa
+kFir4CZsY1av9L9pdTTefXw5r9GNdKXoLNy/ZRzFXsphczwHrzGwRgCFSieHTZ9t
+IVE+QDZebmY8lR37LcsJmO46WjeVReWEKAqATpmchmDoOKdbrjfIaSW7JJVXqxCj
+wRYQVUWkWbSiziahOlcaNQ+cCHvXJA/fQdwomk2yUPi2EZlfX4aDpaeZfKuP7azj
+oRhSywpuA8o74qQ8PwlAffVNjhyOy00gNGTQtZx6LkO3jcvUfvorL0BAin2QB2Vb
+z5tLuBtDHS1NYq0fB++aMSCW1kQ7/TWKXSmh+Cat9BG9VGmCJnoRAv4xOM0pEh1o
+vui18+UT2tJ4OZLP8tOH1A0OMTF98EojmKwUlStnkm+vNgdU0IWPFZng77qL+rJd
+9sR9BkT9gfW+0EMUMG25ocNV4/t01O0q95oH3F3LQ7iIKGzzErX//2qGteaHEu9u
+Cbd1QniQDKzMEJV0hHpWxAcZcJx4Wje7dPgDCRTv2juU8sWM7d43KAAQ+tQpLkem
+yzK0UAQzSnWS2QjrR44hujYmf4zPcMsQFBSvztP7dbtwKuTQbiQRYn4ZCqcCv/DQ
+RpI69NoulWO7kHhbZqqtiWxcmtdLSwN+9Gx/x6sgYSemx5h8rti0lIBi/Pzfq39U
+WuiGg9yjUSU1zqdtDdihAoIBAQDI6XRf/umV3gdba1krxW4q+g5ly3eJlYd/BKTC
+xYNx9ixjOJ+J1ov1gF2P+60HDhYQ9bsoPMhHfJU6qXR5Hu0xZSKK7TPkcJHH6WHm
+ErcqtgJiADtl7sfo/GTn45MaF71fTXSgrjCMLGA99IYPooMVWE+TrFEYNOcPgO4x
+hNq0n0C29ORSr+9oqStCuJ5a+iDvL7KGnmsyun1HuWUKVdxbt4CPpMwsQWcBLfVg
+Ispd5q5fG/DPDZFnha5XLbAPWeLn+1mweK4Y4Jugr593o6S9q04jlLa5wLDMCXUN
+fPXJFJcg+vcvcZ0IlfvFsfZ8IrO/UMHqOeMUhTt8s4KoMYAFAoIBAQC9/9+aC+Tq
+H4t1Dl+GZAavsVlP7kFekmAK02GJ103qmFcITpcx8cx3eA/0oZGpvQCHsJGHoa1P
+EaMtKVITokkvOTJB/zxvSw6K5oCx1qEGoEqyXTs2rNLVchGwunpE4C6Ikhw5+gew
+e299nmLE6bckStCLVINDWQOjRJ0Jl26rmdGk/3wLgliZNVKu/Yhsr4RY+FZoErOk
+YulZp648GfvuwXZUdAWIdmg4JfOrcizmhya3L0qteOZ7FpqKXCPmDgXD3E4IVdMJ
+CRfywxkqXCHxRlN49/9I2y3B3eaWkGStqgvzHbrMR6uobn4+YRkjgam4ILnUO6Vt
+Zy1R3HHvSH1tAoIBAQC9WGc44UC64RkF61GKkvKUxj0zamIp5CZiarnsZcDPcjW6
+/O4+NViJ8oQ64fHbqEbbjPrpnP8TgDITqwf97kuUNcAsNgilzgFV6nk9H35IXmg4
+fAd+tV7qEJP4ht1nxd/PJWw40nEmadv6B60gpwPq5eN5RPjYW2M3lUbmnFKRz1Rq
+GLnlw7FZbbU7mEqFax4GzWjuvfZBRMg1BGBZMToPpg0fUyyouKqezfVmuOMHRBQp
+xmdYe20Bp1b7Ci/XB9t0zcllKxbIk0WYVmtvkWX86qkll03uGc+FO5R5Nb9d1m3n
+wx2aNPTN1qwFUQb/TqUgNLfMSunbuQSrLXKBmMURAoIBAQC9wkXiJqr0IZk4yagi
+ItiCtI/MwtpKx8pgRYmPD5fkC04xH7zlxuc9Eo5s9sjyS6+x1WkjmxfqdmUQf8pX
+jaemIGvPekkzpjTaCSjTdNbSNVklFvRCwQy43PpKFZR0IaqX/8VtKghv/Hf3cC6Z
+GAsvlgD+huOqaca2U5q7r6B6hl/ZeMi8/eva6GSyHMkaM5ns+enie3srXRZN0qiz
+ogf6BwJViqLUDd485bqdqqSpgKXsIrFk2/DlUkf6k9fOtoaPfQH6VS02QvzGGpCR
+u/6yaFiJ4rX2X+EtVKAuE/xZbhINN84OpC4PRHuVdYiT67ZEDXtLOl8YCwo6Tf8E
+ytNpAoIBADWxq0izh7P7pGW58JhA7wl3vCUFUJ77JC4pjYzKlBsMi7OcZrlzNi2J
+4rtO8JO5S8eG5erEA1FuPb6LCPqzetKTD+xKKxgEcICkWuH6RWdRq82bkVqL2gQ7
+tp7qdfwNl0K6XNnB+VaCPAzsrFJJZnoRIz3BQBocT3Fwxe/XwS1KDjLere//bgHR
+9jxYZRHKr72Y9lTMWMW2ygxmdlWk37pv4rsQK31HOGo8JtRVOISZnHLSQwMVNQ25
+5IincDO5FGjOQxFxrGjw+YQkAcQC8PkpiKU7hY396FHEvrr8xqTl/TPuJaAuSbvW
+g3yddc0Zj29o1jw56J043a37q1CmmsI=
+-----END PRIVATE KEY-----
diff --git a/v1.5.7/internal/backend/remote-state/http/testdata/certs/client.crt b/v1.5.7/internal/backend/remote-state/http/testdata/certs/client.crt
new file mode 100644
index 0000000..1d5a744
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/http/testdata/certs/client.crt
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIFCzCCAvOgAwIBAgIUJsntRGo85J+ZJAb73snhKsM1oVowDQYJKoZIhvcNAQEL
+BQAwEjEQMA4GA1UEAwwHdGVzdC5jYTAgFw0yMjEwMTMyMTE4NDBaGA8zMDIyMDIx
+MzIxMTg0MFowFjEUMBIGA1UEAwwLdGVzdC5jbGllbnQwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQCUQebHvDL2ksHcNh6hw0xMCbPxwrBd+qQVFGf/2wL3
+Dk8Ls/NgKQqkoG4WPi4vIuu277+7ngqUZcFbDL/MO7uAWlzthFkhI8IyXeB8t+cj
+liqwdgfRFLvoae1PG6ZoFrTXgOsW3tW8SRC8Kax7RdJjEMU1yWEC6OwiH/gabqZM
++i2qSwOgPnxAalljbWDJU0kj+zRfw35W4L/Q9quMid8KQYE71wQoiiBFYFcx552c
+kL30xEpKat5ffB42sBpDzO3S/dM0k36im3wEFJHaEW2q4+0Ns9/PQ2OxIfoRC+lD
+qYVPeljNSK2n+PSZDjswpZtqK68RD0AM0PmuPqV7Q2DPGoCXpwcq3lczlFH69T7z
+s7izG8cnmyi9eWiXgPFWG5JzyeQi2P5fMumF1UVpG2NHyDyEGfXME8dh4S6BpAUJ
+9BAXjatjzA5bq4CGS1w/pFrUvhiVQY7byGDqrtTiDa1f48T2CkvVmRUIiKlrvnDe
+ezCnJ6P28D0yISyJLN45sQhuyw5idaXHl2AsvDRDFj2iZ/WhY7tCf0O/DSCuI1uZ
+WcFXHdRFn9RoGuUqy97+6rPZaB+xNnx83O9pG+Hrx2iz2pSD/pb0b9xKH5VvN1pN
+JjtaoMXod1+2z8XdTUzPvkeZyDXIasaZwmSEOOZmGgoRe+KE4ZBlk4XBlm5p2Q6U
+RwIDAQABo1MwUTAPBgNVHREECDAGhwR/AAABMB0GA1UdDgQWBBQ/5KcOS58ZKYth
+wRpJ+VKCcwJdpTAfBgNVHSMEGDAWgBSe+CLJRDjlHurYVRcXvhXyohcVdDANBgkq
+hkiG9w0BAQsFAAOCAgEABiy0c+7T7dam8IjejbDlamAMvDCWFoVW+mLjsGwaS7vx
+jmtGig5E08q7axf32iAkfwzi/vEwt66uWGVctUm6/EqH2XvlqZXcsMGiAuWYwJ2Q
+DXowHlcIoIRC958qA+6cCAdxoUnTpYSdWWMR+QZ9XDB9MaAZJ+zKhb8nEETl9jGR
+Z9iaSEnupposxt5NMvNUU8dTjjjv430WvZnvZaTvegLIQ5QaHeECUQ61Nm18tEey
+cPiMu2TN8uO4m67lj4kyXaS3wD7zNuZph55g4vNbQrffTEHUZSFqrr1fyG+7Y+fb
+F9hzbhqBgCnYQ5JaxtVbqFAvwDFWRoq2G9gARi/Yuf34djoP09IZvbRymZWJ5857
+KRCT6mBestfOzu2oIz6lDO44fFiejOTDCSDHZ2Try3xAsqS4LAZjWNSqfBIJwABi
+bNTWV2yxtlnqEkaPtGYSwQLdF8MTBRbxzsiELktgdgt7XcfarhEKj9iHWirEt0Cw
+POnl8S8GzwpsSAomijlLhfyU0J1+p6UP0zJE4YOjKZFv5ddmBCeSTwj0gwVSsSNg
+ff7T7IvkTcIMZUlrskeMY4svXpI5FeG+sXXNp2J/iz4XIQdcdpB3t+fDCUcic9Fq
+ILJKT1sQpjv4gyAO2BJd4D7clUJwDC059+dh3dDC9d51uHvCra2F/+FGeodQRuU=
+-----END CERTIFICATE-----
diff --git a/v1.5.7/internal/backend/remote-state/http/testdata/certs/client.csr b/v1.5.7/internal/backend/remote-state/http/testdata/certs/client.csr
new file mode 100644
index 0000000..ec0f313
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/http/testdata/certs/client.csr
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIEfTCCAmUCAQAwFjEUMBIGA1UEAwwLdGVzdC5jbGllbnQwggIiMA0GCSqGSIb3
+DQEBAQUAA4ICDwAwggIKAoICAQCUQebHvDL2ksHcNh6hw0xMCbPxwrBd+qQVFGf/
+2wL3Dk8Ls/NgKQqkoG4WPi4vIuu277+7ngqUZcFbDL/MO7uAWlzthFkhI8IyXeB8
+t+cjliqwdgfRFLvoae1PG6ZoFrTXgOsW3tW8SRC8Kax7RdJjEMU1yWEC6OwiH/ga
+bqZM+i2qSwOgPnxAalljbWDJU0kj+zRfw35W4L/Q9quMid8KQYE71wQoiiBFYFcx
+552ckL30xEpKat5ffB42sBpDzO3S/dM0k36im3wEFJHaEW2q4+0Ns9/PQ2OxIfoR
+C+lDqYVPeljNSK2n+PSZDjswpZtqK68RD0AM0PmuPqV7Q2DPGoCXpwcq3lczlFH6
+9T7zs7izG8cnmyi9eWiXgPFWG5JzyeQi2P5fMumF1UVpG2NHyDyEGfXME8dh4S6B
+pAUJ9BAXjatjzA5bq4CGS1w/pFrUvhiVQY7byGDqrtTiDa1f48T2CkvVmRUIiKlr
+vnDeezCnJ6P28D0yISyJLN45sQhuyw5idaXHl2AsvDRDFj2iZ/WhY7tCf0O/DSCu
+I1uZWcFXHdRFn9RoGuUqy97+6rPZaB+xNnx83O9pG+Hrx2iz2pSD/pb0b9xKH5Vv
+N1pNJjtaoMXod1+2z8XdTUzPvkeZyDXIasaZwmSEOOZmGgoRe+KE4ZBlk4XBlm5p
+2Q6URwIDAQABoCIwIAYJKoZIhvcNAQkOMRMwETAPBgNVHREECDAGhwR/AAABMA0G
+CSqGSIb3DQEBCwUAA4ICAQAFUKmXAcULGC1idSXVWRnhzzr6qnl4K2QZVse8kNsk
+BD+ePZp7/jc9URP+ykFhVHc1gOy0VgvNm6qePS9ccPTQrRxmXUmMrV2ead9z4h4O
+OnnIyfxLxO+Kd1lJ/1UU8CNs3tDQnxEvtx1hYBIDNsyB4bAsfGVBGzBrsoHEjZOg
+zTvvPEnH/GpnEITTwK9J6tZ2zanE0K5z2NcSHPjzO0z92sAkcfTIZovcsVCGR3j4
+UDBMWAgK9vybG5G6taQyducU7/kMLcEP5ayG0qIeIrS2GRmOqSixAQQ+Qk6Ucs4w
+HD3/9oue5vWJEG0j86jEchdg3OCbHbQEje8Bf39xhpICel45EdGsxc61kiB/c5Lu
+8kYQTXDr9P1wtAag5XLmv/nf6pzlQ+LthU/2/EH0r948Rj2Yz4HOOHsfPuB/izF8
+NTAH/VBgp2c/VRjEYd0YQ4X3AS+Q8BwBeR8+OUJu97AIWnM8kjTcRa1ybCGMkQ3L
+IjGWgIYnICEmiEJhLo/y7jMSdRwUT9g5zz3koqChzeFSU1LuH/yE2B6GfneblDK+
+B7WDOkUEbHfJ5q0TZwWEgQdpcY5OH+o78NfJpTvgNtPV3B83+g+DdAW2jtgMZ6do
+Rb7V+uPvbU9VC2Ng7jacewMtfM3PKugIZ034UUjebQ7/N5ZD01xuJKOG/w2LuUGh
+GQ==
+-----END CERTIFICATE REQUEST-----
diff --git a/v1.5.7/internal/backend/remote-state/http/testdata/certs/client.key b/v1.5.7/internal/backend/remote-state/http/testdata/certs/client.key
new file mode 100644
index 0000000..392a800
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/http/testdata/certs/client.key
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCUQebHvDL2ksHc
+Nh6hw0xMCbPxwrBd+qQVFGf/2wL3Dk8Ls/NgKQqkoG4WPi4vIuu277+7ngqUZcFb
+DL/MO7uAWlzthFkhI8IyXeB8t+cjliqwdgfRFLvoae1PG6ZoFrTXgOsW3tW8SRC8
+Kax7RdJjEMU1yWEC6OwiH/gabqZM+i2qSwOgPnxAalljbWDJU0kj+zRfw35W4L/Q
+9quMid8KQYE71wQoiiBFYFcx552ckL30xEpKat5ffB42sBpDzO3S/dM0k36im3wE
+FJHaEW2q4+0Ns9/PQ2OxIfoRC+lDqYVPeljNSK2n+PSZDjswpZtqK68RD0AM0Pmu
+PqV7Q2DPGoCXpwcq3lczlFH69T7zs7izG8cnmyi9eWiXgPFWG5JzyeQi2P5fMumF
+1UVpG2NHyDyEGfXME8dh4S6BpAUJ9BAXjatjzA5bq4CGS1w/pFrUvhiVQY7byGDq
+rtTiDa1f48T2CkvVmRUIiKlrvnDeezCnJ6P28D0yISyJLN45sQhuyw5idaXHl2As
+vDRDFj2iZ/WhY7tCf0O/DSCuI1uZWcFXHdRFn9RoGuUqy97+6rPZaB+xNnx83O9p
+G+Hrx2iz2pSD/pb0b9xKH5VvN1pNJjtaoMXod1+2z8XdTUzPvkeZyDXIasaZwmSE
+OOZmGgoRe+KE4ZBlk4XBlm5p2Q6URwIDAQABAoICAC6TP3l6/bWpqB5SoC/oZzUy
+DSZDp912SorWxM9DkfxkMd/20dvhONc8ESmKsj6bpVpsmhrKTP+Osf41FKIIF+D8
+QlpZrBh1n+HrzQTRT1tGJzYVdmIwNdIPSP6DrLThgUF8Xh5qtdG3UHsUSnvVlQEL
+OTErCP99hgU4btx662Kea68mbsauKqGf52INcAz/Tahwl+UHyM5pP8lZXM5DV97k
+ckGGzGch8X5qBCqI3WJctFhLPB2B0kdD+kfq7e1j2Ujh9bJ8LZnO59huT92mgQHh
+Jc0at5Jo1M5GYsVtLQRVIqyzvmcLUIbG9qyIpH6lYBwsCgz9cf00v2OGib0eDzC2
+ZqeiotDiul5f6vtNw1YqDdrZWSxRfwqoqzeZX0/bypw6+UTGri+lU7RSRsA845gd
+gMjcAd2WocqSNhPBTVPivIDmzHfSMomfnJHCw+aKcm/o6fxcSp4g8pPzpx52h0Eb
+tO7rTKTlmglZ8Cc59CPmRqLq+Pk+lHgxTDOUOxZANCuBih4MrDJ2NFnnZxervjPM
+te3VlJu8nE5mNuHhT1czekU01lPHQa2E4f5Q74bWpYg71KntN2Po8oUaQQjcX72N
+b9N0TzeBrR2TQD/j2S1Mz4ZoStOwOovHdtPZOmfYN30OMX8JzqZLhF4Dfyx8T1JC
+Pd1089N0HbX7XIXuEKJtAoIBAQC8xIVQMqg7A9O3u4i2Afq6nASHDM1tnH1l8Ua+
+T2Z6kmPBgjPb+tBrX6YeD13yDxKvfsEr9GnyuQQJdvqNwjVkGNg3Z6HX/HyHIUij
+bub3LvpyQzYNkpb2qcoka+AIWDvbpmstetobQ6OK9F914ur29L9XXSp0diZn+1Ff
+JqZFfZwgkhsz0Q8HZxT4FfbV+2k6PWk3RPriyKLgZAd3OXswbx/6K7owdUgrOhYA
+vUXRae0UrNi0Y2kanzzoBdBLDS3ChML5VBMPIrHac4A97FJS88aewEgMC0E1wlin
+J7nwVAubAG7YzEpQeP/4Wp2j9hfwqtO8JlaJL1vygAgQG42NAoIBAQDJD7v0qDal
+cuGaHEQLhEVOu7JtQwHn7LmJQyamqCmlL0mDwQOixhEh58sQFUeNYEGKwEGWF+Tk
+hA8sAYk4jagUF5sCkOQoWdFWna4uPqlpwozFc/Wj3jKoiYOGn4SFeEJdgQG3rMDM
+oepVvaNOljJnNlntKZHUwOM0F6xxV4dXyqnPn+nXmM/Iywd+LSsMN5w8c4IFE+Da
+WKrbKMobdaARtx9Lpv7ESObLX3eCRqL1KbuRN2a000Ojfv4kprH1XxMdCWUxXoLk
+ac1I29cvx0FFYJfIr3CScdwaKiwGKguk8IMIih3dLulgnaqJ2vUjI3qyQMEFRMBW
+3HxFAk3VU6IjAoIBAFRmMYz3+UvZnDHMAYYPQIFq/IM9cCQQEekghZbVfWZUSZHd
+mz5B2CoJ7AYIrOJrZtlcfRYgA7bojiuFLOVw7dpBWXr8NNqTI0Jv2UBpd48RTB0G
+fAZ5glHq/FxodxSEDs9YixcclKQYC+k29e+Jc7DTITH4j+DearGXJny6lSEA1muh
+p9P1JxkSN8fsWh62eAf4KTDzAJGhT2Gwl73wz2mKZeu+3VKJPalGIUxXU/4btErI
+NWQCBp5GkD7VSpoj3E/aeCpuMs9Tnd2kQrRtEynPoQCdzBjGd3OH34dtNa+EhGPb
+P7RjMt7kGt559X23rGCIoH7BTXOs3xl/sRsylokCggEBAILXEmEr9iPElrtLGZzE
+/rU1v+8KY/shObvxTv21ASTVmOl8eXk7m3qM9MAKmP2PXheE9SlPc0yiA52Hglyj
+EnXAxsbsswzvJiNPiUHe1TBVwnXb+EYjGqRCmKzKsdqJX+apRQzaBr0jwPL67YL+
+it5PqEWFf7kLrM8BeN5pL1IaOFc8oVgDwXPRa5bYneLdbXaJVFspjHGKseTcrmkg
+KoJcwKjii3gAWPCPt523ieQwvDbL7rJNqP6Eba48LCKZND75FjkCX/t0PnrjVS1q
+ZTdYnG2kfYVPQwRj3TJFuj4jpaGw/64oEQcmkwwSyOOM+xN0wCdFjkT4RoZB8ZSZ
+UDECggEAQ7nnkDKqL2SGsC2tuXpOO1rn2Ifp71hK9TiSUh6QIEk3parO5ualayH+
+UUsav++GIexHIxH5sxbeO6wCurRbrA/64tTXRYh/T9tIkfI4wstgRoFCMPN5CdIs
+Q1s48wH1KfQWz1UiNM0rwJKs2kDIWOj9bZotq9Ir3dXYoKgr4sotQFZUVyq2n5Z7
+jE0/bYPHI8+3WXaZsLEzBA167/6IUzIoM5QEgKYP3999CEu2ZKewjnElPMflDJWm
+OGT5JYz9SjwKH/9ngGcpIo8i35LSj5R9cK9Sf6dTKo2YZAU1U8yjfaRXIVAmSBFS
+SXbUSo1aOU/ZWOnVKdyjhPBcPZMEqQ==
+-----END PRIVATE KEY-----
diff --git a/v1.5.7/internal/backend/remote-state/http/testdata/certs/server.crt b/v1.5.7/internal/backend/remote-state/http/testdata/certs/server.crt
new file mode 100644
index 0000000..d16cc62
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/http/testdata/certs/server.crt
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIFCzCCAvOgAwIBAgIUEJ4OCw9X1j5TegymXZENMgfdBZcwDQYJKoZIhvcNAQEL
+BQAwEjEQMA4GA1UEAwwHdGVzdC5jYTAgFw0yMjEwMTMyMTE4MzBaGA8zMDIyMDIx
+MzIxMTgzMFowFjEUMBIGA1UEAwwLdGVzdC5zZXJ2ZXIwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQDBTTBoca0tn2EAxbQLXw1diEH5+YltZUFz5gH3aSDf
+H+uKame4iFsPybsUstmUqy3D9ZTzjNcauAhB75+RgePn4D0/qePPjdsFz11jxacA
+AMkg/mPLPtrkEAiRzvSXXoYN1Gq6uNdGricyKGtSKzqQh158W2ZfLKUKvgGlQ8RD
+3RFsFanQS6aiNwPgFK1SeFFt4wTJbtpvKNpJSe/XDDmkyMIN6/pVRo56v2PvsERA
+mUQJ+blyhOy7Egt0/uF7JUklzLIi5eKjv2JpcVwH83OAovKl1vy2mfiCZSjCwQeB
+ahnWgAaAaJir7uOVNDNXI4qM/KySKN7Nfyo+9sRuNBjMb5b0N8s70YIAyzoylJ0U
+E8x+a7XyMJlPvpARGXuNSDwR9rRytpGZIeMPcO1YQh9+V5k7il6/70thNYW5/Cb0
+PsHU5XOSlmOsOLcr1JaD2YTJJflVyhrPwMSAphRuUCFuyQinnHi59Rk2rNuTj/R3
+dFrSqtcfnvjbc+1KbyDFpnyf40W/EPmS4mF3UPRD4oRsvXpy85E25uh5Q+R4MMdd
+g3KHsZ+SiObUBa33kd9rG6peJz0cvkJIhBzbJcXPzN2EMgow2C5MYKjmNXclYWIH
+ypkFSo6OxFHhIQdeh3Ga7pZqJaOVUA8wm2olIjRQgQFJjRRc6KU2w95lJlFvHXlW
+0QIDAQABo1MwUTAPBgNVHREECDAGhwR/AAABMB0GA1UdDgQWBBQpv1S2rSSjgJ7a
+xONcLKxYRE3qJzAfBgNVHSMEGDAWgBSe+CLJRDjlHurYVRcXvhXyohcVdDANBgkq
+hkiG9w0BAQsFAAOCAgEASpVE6Pj/sPf5heCDI8miF3Xw65BkLMCCL4ZUOugtK0Hg
+dbcnaMd6Hwf+mEs/2jaD+2xah489fX4KynJnQ68VpnTMT4yYcsEfvwmZA7Bqo/Ef
+MwyFJe/E+Y1mAu7KQodLZ1E13cGVQKDQVwQ5ueyRD3C0bY3glMKfnXvnIIEMiSCg
+UTAstj4Z0h9KYrVSRRVfCGOtlvFPo8jg+yPVPsDqGHn2hOH+FYoHv8V1/gGrXJTe
+HcTHFIAIkBefHAXCaCYYq3Qfp/ZBpuT5N4bwQtHKmgv5hhyy0kaZRFfE98WkGdSk
+Yg5wZRIX6UbjPdyiEnhQdOrnGDehKf9iwv1q98B9hgXzEzdK0e3bR8UY2MRvs/Vz
+L2BBDkJHsTo9P1q6zAsmfVNhQPGrEH2pDir8yYpXPz/ocZa7GghJ/RPrYirVTHZp
+fNxoMkNfgfVQpSsFvvI/fMGfhG65TQJdq82rAJ5tRRRs69uA00NCggKRWmEdVYpV
+jWuMiLrE5U2tHruMytM/ek6kjhzmNpJgPG2alsJHgVb5G8elcCuC0Dx5HjnwbR60
+8V1v2z5kgU9dkT05vZ5RPmNyuv+VP+8Qx/NPCMrf1SaQffW4PaP3YUaRwzJYzEP/
+ZDUOmPsgUMLwj/jT3sEkSc1qUByui2A0QJk2dQzcbNfvpWoBQ+q7m2OHkmzXZCc=
+-----END CERTIFICATE-----
diff --git a/v1.5.7/internal/backend/remote-state/http/testdata/certs/server.csr b/v1.5.7/internal/backend/remote-state/http/testdata/certs/server.csr
new file mode 100644
index 0000000..92d06b7
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/http/testdata/certs/server.csr
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIEfTCCAmUCAQAwFjEUMBIGA1UEAwwLdGVzdC5zZXJ2ZXIwggIiMA0GCSqGSIb3
+DQEBAQUAA4ICDwAwggIKAoICAQDBTTBoca0tn2EAxbQLXw1diEH5+YltZUFz5gH3
+aSDfH+uKame4iFsPybsUstmUqy3D9ZTzjNcauAhB75+RgePn4D0/qePPjdsFz11j
+xacAAMkg/mPLPtrkEAiRzvSXXoYN1Gq6uNdGricyKGtSKzqQh158W2ZfLKUKvgGl
+Q8RD3RFsFanQS6aiNwPgFK1SeFFt4wTJbtpvKNpJSe/XDDmkyMIN6/pVRo56v2Pv
+sERAmUQJ+blyhOy7Egt0/uF7JUklzLIi5eKjv2JpcVwH83OAovKl1vy2mfiCZSjC
+wQeBahnWgAaAaJir7uOVNDNXI4qM/KySKN7Nfyo+9sRuNBjMb5b0N8s70YIAyzoy
+lJ0UE8x+a7XyMJlPvpARGXuNSDwR9rRytpGZIeMPcO1YQh9+V5k7il6/70thNYW5
+/Cb0PsHU5XOSlmOsOLcr1JaD2YTJJflVyhrPwMSAphRuUCFuyQinnHi59Rk2rNuT
+j/R3dFrSqtcfnvjbc+1KbyDFpnyf40W/EPmS4mF3UPRD4oRsvXpy85E25uh5Q+R4
+MMddg3KHsZ+SiObUBa33kd9rG6peJz0cvkJIhBzbJcXPzN2EMgow2C5MYKjmNXcl
+YWIHypkFSo6OxFHhIQdeh3Ga7pZqJaOVUA8wm2olIjRQgQFJjRRc6KU2w95lJlFv
+HXlW0QIDAQABoCIwIAYJKoZIhvcNAQkOMRMwETAPBgNVHREECDAGhwR/AAABMA0G
+CSqGSIb3DQEBCwUAA4ICAQA5BmbXy/UXXNXe0WHR1gxx5nwmJ1CyNy+efVq4cl8Z
+ltxaTWy8IZOGN3YHY2ZhmKccm7ecNq1Kv9FUctPe6+97HXb2rL0rB0gO1AyxWJKU
+edzls63/0n+AnQqwnPQdgL9N5vIw/0avLo3U8F+kI5hbYfG7fvw3zHdJIMiLTRsn
+qKvkF2TMBxr06nrlJsQqG90k9xS3iX7DqssDq3niVgAwP2NbS2wDXk7/6R40LNx9
+RzFHDyHplF/3ySjctkx7kkAPdamGr8NNs7kQkVZGKmD25V7i5ggoGx9lo3AiBbmT
+9Keac43vhlC4Bj9zW2O6Ih9TP9sDhp6iA4NtdNnK9tfn59Av6J4pB6EhMzaLtu4J
+jqc5b3+Wvq1xv0Sm2Y+JjuawT7jgrT4vnSEqqkFTTV6igzctatOCxz4ejl3Q2sD0
+OjlArZWX9kY2yyuFt6LhlM3We0IDUQjEf0JtA9EFixbm+ieHbPEFHFiD0w9uN/VI
+cYzxnubGgvv2wN1N+YHNRFFOWyT+Ty7Hp0Kz3dh8g+DY4vxvsfG6XfnvPT5StSKd
+ACEfl8HoSET/qJZIkuIhErzzUNNK4+4QzQav7auZUQUrdK6P+rryE3lZauZ3rV+9
+ZXWT3PG1qHuWNNriTrC6n4tpa8m5UkZMdeoK2pS3y3SLDCJJV7Q3WHCZEVddIPdV
+Ew==
+-----END CERTIFICATE REQUEST-----
diff --git a/v1.5.7/internal/backend/remote-state/http/testdata/certs/server.key b/v1.5.7/internal/backend/remote-state/http/testdata/certs/server.key
new file mode 100644
index 0000000..881229b
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/http/testdata/certs/server.key
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDBTTBoca0tn2EA
+xbQLXw1diEH5+YltZUFz5gH3aSDfH+uKame4iFsPybsUstmUqy3D9ZTzjNcauAhB
+75+RgePn4D0/qePPjdsFz11jxacAAMkg/mPLPtrkEAiRzvSXXoYN1Gq6uNdGricy
+KGtSKzqQh158W2ZfLKUKvgGlQ8RD3RFsFanQS6aiNwPgFK1SeFFt4wTJbtpvKNpJ
+Se/XDDmkyMIN6/pVRo56v2PvsERAmUQJ+blyhOy7Egt0/uF7JUklzLIi5eKjv2Jp
+cVwH83OAovKl1vy2mfiCZSjCwQeBahnWgAaAaJir7uOVNDNXI4qM/KySKN7Nfyo+
+9sRuNBjMb5b0N8s70YIAyzoylJ0UE8x+a7XyMJlPvpARGXuNSDwR9rRytpGZIeMP
+cO1YQh9+V5k7il6/70thNYW5/Cb0PsHU5XOSlmOsOLcr1JaD2YTJJflVyhrPwMSA
+phRuUCFuyQinnHi59Rk2rNuTj/R3dFrSqtcfnvjbc+1KbyDFpnyf40W/EPmS4mF3
+UPRD4oRsvXpy85E25uh5Q+R4MMddg3KHsZ+SiObUBa33kd9rG6peJz0cvkJIhBzb
+JcXPzN2EMgow2C5MYKjmNXclYWIHypkFSo6OxFHhIQdeh3Ga7pZqJaOVUA8wm2ol
+IjRQgQFJjRRc6KU2w95lJlFvHXlW0QIDAQABAoICAAnye228f9FrtLWx9tBo/UqV
+YvPGrBRFlCcvLGW7crYYsenHDPxZg/odgvOPOpQkdO/zGM2prz4QP1iJSLhXq084
+4l3+05rQLXewkpk6SBw/bho1DRSd8OywiIhcUojhk9ttVWqzbVyVRK4Xl2I8mEBs
+vud+WpfGN94EJhiHkrd9TlK2EK2H3xTU6O2kksC+MU6K0qm8+x+iRg1kcSOrXOIG
+dLn7rT+rKFTXuYBRnUmHuZEb2Tez8Gy2AoHsRdUs94Uq8fXKx61ugVV0wGwmUojJ
+mdv/4rRQ2xF2vDC9dzHpMFgx8WO1PjoGyo5Yh9XRneUgcY757HE9vIJN95DGPIpd
+vCYaGrGA/JipOmTrmMoFurhdwdiyzAzUsXV5AKKo+PNEsSz+36y/xa2z7PlvnBR2
+rpKw/ocsRoaKiI9pG7b9ty0QyiY/teVTpt0sQDIvpZwx60wYhkziFl8sn6CGQWQm
+a1bFzb+5ZrEMj7gCeffOJmQSvpn2fGzlyp3RrkyaRGK4YhWU9SJsPUAnxRF5yoOm
+EzwYFYC0AScPdywS3nA4IWIeKnuydGH+6M/Cqk9qkiGrflKFpCn2eBvFWMTuoUYd
+/jyE2t4th/T1qsqKbJqKiRAz4dQlrqWdN6SnBk8MRhDbqtbbSREIdU1z58qD3kuf
+0thbm9SrDRV4UgYiUckLAoIBAQDqt3NLq5OgOsEOuoYYqQYWDWNiTusrvsutood+
++AXPcxZKR8O3g/gUGuhyKE3a9DMYnFoLCaTqX1iDqg/KUemoqc2+A9pZ+QAXRXnE
+R/4PFh1Sgyhyrwz30svUVs9FYpiP65ZiY6LhDmSL6bl1u4DYJUhgXiHkF6q+KryN
+M1uLpSmUOTOwJf6tltYgMPMegDXQE2VZ7VnQMN1m2rhDRmycM14CyJSSWZAyCzbJ
+ylDeKWs4wxATLrWIGUPLzqua4/uILsUeAzvyOCrCgJHSEDdITGdQJClF17bZH9xG
+H6pIA0VPoWq480lE+gw9Mwu1m4QjOOM0RHF5nm6YKFJLIdCjAoIBAQDS1FuEtuVI
+6oQa2Sh7EILZq/gyVrXmeLLYUQChYBFZxK0PVkbFT+ztkHnD2gBz4exXUEaGpBNA
+6Yr8iz6VCNdQ0KcrvzFINZwcRJTeSxLXArQ2LkDJmDZJoIC1cSurrU8ot94EHC94
+qjGQW4K3qFZIiyXHQJNgSrYaHADmDi9sQQNmyP0pSIY/q9Gn/2DLADItIt/0iFz0
+kc07kF6l/1JADSiUHMzHhUxh04LXo2LRQVHYWaK0DrVI50wXivOCARFkQrFdrszX
+ymFf7d6AskIiAIBNYXmb3of2NSwzWx6RnZI9YVpw2277xzVh2vDxI2Pc0ordAzFk
+YY0DLGFNeI37AoIBAHnHkt949xBUS6RrrHWRBOJeMelozuWUibLeN/TtlH4s1SzX
+DTnjE8zCpUXNmY930ib7wFAnwdQEgjVV//lWBKiI6YGkGB9EbQKl/maTf8KuE6qi
++FKAdncCfNT/8WyrmkJZ1l3YGkMwp4RcUOg/z7rVpTaywFzK1sDyBYAxXFcY63jH
+MQU8wWWpdBGhtBJoLQN3fMdquYWmRMk/xAjLukBU+nrxPPyt0X3Viaiq+sg5rzL1
+Khr5yiACE8Xjxe+ISBJBSe6neOvUroLaGE5oMXamhZf0GyHsqScAO9Z6SWwxnj2R
+n4C0YZiTL9R07qdcN/PaaS/OLx4N0I3Lpd7rfYcCggEAdgBHrPNVR8eC4ygSYTbv
+lfeLtlkT/Ignya0kxi3n6C+NkVz/xWYjvR+1F2qIAFQ+HOygXLGu2REeKpWhFHdb
+VC9EsdaUNc9Trfqwu+6W/+LSjNS8jFj2YaVFBMjv4WniOW8YA4LnCwlvLlYZxsOg
+b3/6SBibpDSM0fZEhn8ACf4lcj0ifR3Ljg2UDgyA134nl13CrbI5HOYSUblPUGek
+WJdE1Al+kFnKU6K3xAv9vhNqRMZ+q3rj+ocC7tZlzqjcXBp7/Wxd2JW8hJ21gKDF
+JRTUuvrIvvYBcUt3jtL8PBJOjK5VmX8oEiIAfeG2I7FkLm9lK6ii14VGELWhTGQi
+SwKCAQEAkZTSBq7tJ5CwiwKW3ubTEyDWugO3IplXAn8NMzGwSG5NF6qLqTpRAlDk
+IJ7JEuMY0KKNDj4qCy+EEyR7a3+P1QcYquBAAFcwsaq+49ix+MxApVUjj2RT7yzt
+IT3J1NP782AAVMUVK2n/tBvhRnDPmofhwCXKxP8t1SGbUCX+2I5IcAL3aQgSrDsF
+uyUPCSL08f6SJWDQa7k9RFg2vnJgJjPJnvf+xuI6jJrbOJUcmUfBmTcYzjWKZvRB
+RctFOLbbrfsY3D2jgW/CUw/jbrwUokwm4VatzMCgHlZi6WJIGJftDP4b1MJACe02
++AXVqLYxuaMTIdm5Ahyl1sCNrOl8nQ==
+-----END PRIVATE KEY-----
diff --git a/v1.5.7/internal/backend/remote-state/http/testdata/gencerts.sh b/v1.5.7/internal/backend/remote-state/http/testdata/gencerts.sh
new file mode 100755
index 0000000..ebb987d
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/http/testdata/gencerts.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+#
+# Generates certs required for mTLS testing:
+# - ca.key and ca.cert.pem are self-signed, used as the source of truth for client and server to verify each other.
+# - client.key and client.crt are the client's key and cert (signed by the ca key and cert)
+# - server.key and server.crt are the server's key and cert (signed by the ca key and cert)
+
+set -ex
+
+# I was doing this on M1 mac and needed newer openssl to add the SAN IP; please export OPENSSL when invoking as needed
+OPENSSL="${OPENSSL:-openssl}"
+
+# Nuke and recreate the certs dir
+rm -rf certs
+mkdir certs
+cd certs || exit 1
+
+# CA
+"$OPENSSL" genrsa -out ca.key 4096
+"$OPENSSL" req -new -x509 -days 365000 -key ca.key -out ca.cert.pem
+
+# Server
+"$OPENSSL" genrsa -out server.key 4096
+"$OPENSSL" req -new -key server.key -out server.csr -addext 'subjectAltName = IP:127.0.0.1'
+"$OPENSSL" x509 -req -days 365000 -in server.csr -CA ca.cert.pem -CAkey ca.key -CAcreateserial -out server.crt -copy_extensions copy
+
+# Client
+"$OPENSSL" genrsa -out client.key 4096
+"$OPENSSL" req -new -key client.key -out client.csr -addext 'subjectAltName = IP:127.0.0.1'
+"$OPENSSL" x509 -req -days 365000 -in client.csr -CA ca.cert.pem -CAkey ca.key -CAcreateserial -out client.crt -copy_extensions copy
diff --git a/v1.5.7/internal/backend/remote-state/inmem/backend.go b/v1.5.7/internal/backend/remote-state/inmem/backend.go
new file mode 100644
index 0000000..bcd803b
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/inmem/backend.go
@@ -0,0 +1,211 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package inmem
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"sort"
+	"sync"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/legacy/helper/schema"
+	statespkg "github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+// we keep the states and locks in package-level variables, so that they can be
+// accessed from multiple instances of the backend. This better emulates
+// backend instances accessing a single remote data store.
+var (
+	states stateMap
+	locks  lockMap
+)
+
+func init() {
+	Reset()
+}
+
+// Reset clears out all existing state and lock data.
+// This is used to initialize the package during init, as well as between
+// tests.
+func Reset() {
+	states = stateMap{
+		m: map[string]*remote.State{},
+	}
+
+	locks = lockMap{
+		m: map[string]*statemgr.LockInfo{},
+	}
+}
+
+// New creates a new backend for Inmem remote state.
+func New() backend.Backend {
+	// Set the schema
+	s := &schema.Backend{
+		Schema: map[string]*schema.Schema{
+			"lock_id": &schema.Schema{
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "initializes the state in a locked configuration",
+			},
+		},
+	}
+	backend := &Backend{Backend: s}
+	backend.Backend.ConfigureFunc = backend.configure
+	return backend
+}
+
+type Backend struct {
+	*schema.Backend
+}
+
+func (b *Backend) configure(ctx context.Context) error {
+	states.Lock()
+	defer states.Unlock()
+
+	defaultClient := &RemoteClient{
+		Name: backend.DefaultStateName,
+	}
+
+	states.m[backend.DefaultStateName] = &remote.State{
+		Client: defaultClient,
+	}
+
+	// set the default client lock info per the test config
+	data := schema.FromContextBackendConfig(ctx)
+	if v, ok := data.GetOk("lock_id"); ok && v.(string) != "" {
+		info := statemgr.NewLockInfo()
+		info.ID = v.(string)
+		info.Operation = "test"
+		info.Info = "test config"
+
+		locks.lock(backend.DefaultStateName, info)
+	}
+
+	return nil
+}
+
+func (b *Backend) Workspaces() ([]string, error) {
+	states.Lock()
+	defer states.Unlock()
+
+	var workspaces []string
+
+	for s := range states.m {
+		workspaces = append(workspaces, s)
+	}
+
+	sort.Strings(workspaces)
+	return workspaces, nil
+}
+
+func (b *Backend) DeleteWorkspace(name string, _ bool) error {
+	states.Lock()
+	defer states.Unlock()
+
+	if name == backend.DefaultStateName || name == "" {
+		return fmt.Errorf("can't delete default state")
+	}
+
+	delete(states.m, name)
+	return nil
+}
+
+func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
+	states.Lock()
+	defer states.Unlock()
+
+	s := states.m[name]
+	if s == nil {
+		s = &remote.State{
+			Client: &RemoteClient{
+				Name: name,
+			},
+		}
+		states.m[name] = s
+
+		// to most closely replicate other implementations, we are going to
+		// take a lock and create a new state if it doesn't exist.
+		lockInfo := statemgr.NewLockInfo()
+		lockInfo.Operation = "init"
+		lockID, err := s.Lock(lockInfo)
+		if err != nil {
+			return nil, fmt.Errorf("failed to lock inmem state: %s", err)
+		}
+		defer s.Unlock(lockID)
+
+		// If we have no state, we have to create an empty state
+		if v := s.State(); v == nil {
+			if err := s.WriteState(statespkg.NewState()); err != nil {
+				return nil, err
+			}
+			if err := s.PersistState(nil); err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	return s, nil
+}
+
+type stateMap struct {
+	sync.Mutex
+	m map[string]*remote.State
+}
+
+// Global level locks for inmem backends.
+type lockMap struct {
+	sync.Mutex
+	m map[string]*statemgr.LockInfo
+}
+
+func (l *lockMap) lock(name string, info *statemgr.LockInfo) (string, error) {
+	l.Lock()
+	defer l.Unlock()
+
+	lockInfo := l.m[name]
+	if lockInfo != nil {
+		lockErr := &statemgr.LockError{
+			Info: lockInfo,
+		}
+
+		lockErr.Err = errors.New("state locked")
+		// make a copy of the lock info to avoid any testing shenanigans
+		*lockErr.Info = *lockInfo
+		return "", lockErr
+	}
+
+	info.Created = time.Now().UTC()
+	l.m[name] = info
+
+	return info.ID, nil
+}
+
+func (l *lockMap) unlock(name, id string) error {
+	l.Lock()
+	defer l.Unlock()
+
+	lockInfo := l.m[name]
+
+	if lockInfo == nil {
+		return errors.New("state not locked")
+	}
+
+	lockErr := &statemgr.LockError{
+		Info: &statemgr.LockInfo{},
+	}
+
+	if id != lockInfo.ID {
+		lockErr.Err = errors.New("invalid lock id")
+		*lockErr.Info = *lockInfo
+		return lockErr
+	}
+
+	delete(l.m, name)
+	return nil
+}
diff --git a/v1.5.7/internal/backend/remote-state/inmem/backend_test.go b/v1.5.7/internal/backend/remote-state/inmem/backend_test.go
new file mode 100644
index 0000000..032615a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/inmem/backend_test.go
@@ -0,0 +1,95 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package inmem
+
+import (
+	"flag"
+	"os"
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	statespkg "github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/remote"
+
+	_ "github.com/hashicorp/terraform/internal/logging"
+)
+
+func TestMain(m *testing.M) {
+	flag.Parse()
+	os.Exit(m.Run())
+}
+
+func TestBackend_impl(t *testing.T) {
+	var _ backend.Backend = new(Backend)
+}
+
+func TestBackendConfig(t *testing.T) {
+	defer Reset()
+	testID := "test_lock_id"
+
+	config := map[string]interface{}{
+		"lock_id": testID,
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(config)).(*Backend)
+
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	c := s.(*remote.State).Client.(*RemoteClient)
+	if c.Name != backend.DefaultStateName {
+		t.Fatal("client name is not configured")
+	}
+
+	if err := locks.unlock(backend.DefaultStateName, testID); err != nil {
+		t.Fatalf("default state should have been locked: %s", err)
+	}
+}
+
+func TestBackend(t *testing.T) {
+	defer Reset()
+	b := backend.TestBackendConfig(t, New(), hcl.EmptyBody()).(*Backend)
+	backend.TestBackendStates(t, b)
+}
+
+func TestBackendLocked(t *testing.T) {
+	defer Reset()
+	b1 := backend.TestBackendConfig(t, New(), hcl.EmptyBody()).(*Backend)
+	b2 := backend.TestBackendConfig(t, New(), hcl.EmptyBody()).(*Backend)
+
+	backend.TestBackendStateLocks(t, b1, b2)
+}
+
+// use the this backen to test the remote.State implementation
+func TestRemoteState(t *testing.T) {
+	defer Reset()
+	b := backend.TestBackendConfig(t, New(), hcl.EmptyBody())
+
+	workspace := "workspace"
+
+	// create a new workspace in this backend
+	s, err := b.StateMgr(workspace)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// force overwriting the remote state
+	newState := statespkg.NewState()
+
+	if err := s.WriteState(newState); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := s.PersistState(nil); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := s.RefreshState(); err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/v1.5.7/internal/backend/remote-state/inmem/client.go b/v1.5.7/internal/backend/remote-state/inmem/client.go
new file mode 100644
index 0000000..2e845ba
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/inmem/client.go
@@ -0,0 +1,50 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package inmem
+
+import (
+	"crypto/md5"
+
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+// RemoteClient is a remote client that stores data in memory for testing.
+type RemoteClient struct {
+	Data []byte
+	MD5  []byte
+	Name string
+}
+
+func (c *RemoteClient) Get() (*remote.Payload, error) {
+	if c.Data == nil {
+		return nil, nil
+	}
+
+	return &remote.Payload{
+		Data: c.Data,
+		MD5:  c.MD5,
+	}, nil
+}
+
+func (c *RemoteClient) Put(data []byte) error {
+	md5 := md5.Sum(data)
+
+	c.Data = data
+	c.MD5 = md5[:]
+	return nil
+}
+
+func (c *RemoteClient) Delete() error {
+	c.Data = nil
+	c.MD5 = nil
+	return nil
+}
+
+func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
+	return locks.lock(c.Name, info)
+}
+func (c *RemoteClient) Unlock(id string) error {
+	return locks.unlock(c.Name, id)
+}
diff --git a/v1.5.7/internal/backend/remote-state/inmem/client_test.go b/v1.5.7/internal/backend/remote-state/inmem/client_test.go
new file mode 100644
index 0000000..0361fef
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/inmem/client_test.go
@@ -0,0 +1,39 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package inmem
+
+import (
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states/remote"
+)
+
+func TestRemoteClient_impl(t *testing.T) {
+	var _ remote.Client = new(RemoteClient)
+	var _ remote.ClientLocker = new(RemoteClient)
+}
+
+func TestRemoteClient(t *testing.T) {
+	defer Reset()
+	b := backend.TestBackendConfig(t, New(), hcl.EmptyBody())
+
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestClient(t, s.(*remote.State).Client)
+}
+
+func TestInmemLocks(t *testing.T) {
+	defer Reset()
+	s, err := backend.TestBackendConfig(t, New(), hcl.EmptyBody()).StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestRemoteLocks(t, s.(*remote.State).Client, s.(*remote.State).Client)
+}
diff --git a/v1.5.7/internal/backend/remote-state/kubernetes/backend.go b/v1.5.7/internal/backend/remote-state/kubernetes/backend.go
new file mode 100644
index 0000000..a5ad1b5
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/kubernetes/backend.go
@@ -0,0 +1,408 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package kubernetes
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"log"
+	"os"
+	"path/filepath"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/legacy/helper/schema"
+	"github.com/hashicorp/terraform/version"
+	"github.com/mitchellh/go-homedir"
+	k8sSchema "k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/client-go/dynamic"
+	"k8s.io/client-go/kubernetes"
+	coordinationv1 "k8s.io/client-go/kubernetes/typed/coordination/v1"
+	restclient "k8s.io/client-go/rest"
+	"k8s.io/client-go/tools/clientcmd"
+	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
+)
+
+// Modified from github.com/terraform-providers/terraform-provider-kubernetes
+
+const (
+	noConfigError = `
+
+[Kubernetes backend] Neither service_account nor load_config_file were set to true, 
+this could cause issues connecting to your Kubernetes cluster.
+`
+)
+
+var (
+	secretResource = k8sSchema.GroupVersionResource{
+		Group:    "",
+		Version:  "v1",
+		Resource: "secrets",
+	}
+)
+
+// New creates a new backend for kubernetes remote state.
+func New() backend.Backend {
+	s := &schema.Backend{
+		Schema: map[string]*schema.Schema{
+			"secret_suffix": {
+				Type:        schema.TypeString,
+				Required:    true,
+				Description: "Suffix used when creating the secret. The secret will be named in the format: `tfstate-{workspace}-{secret_suffix}`.",
+			},
+			"labels": {
+				Type:        schema.TypeMap,
+				Optional:    true,
+				Description: "Map of additional labels to be applied to the secret.",
+				Elem:        &schema.Schema{Type: schema.TypeString},
+			},
+			"namespace": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("KUBE_NAMESPACE", "default"),
+				Description: "Namespace to store the secret in.",
+			},
+			"in_cluster_config": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("KUBE_IN_CLUSTER_CONFIG", false),
+				Description: "Used to authenticate to the cluster from inside a pod.",
+			},
+			"load_config_file": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("KUBE_LOAD_CONFIG_FILE", true),
+				Description: "Load local kubeconfig.",
+			},
+			"host": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("KUBE_HOST", ""),
+				Description: "The hostname (in form of URI) of Kubernetes master.",
+			},
+			"username": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("KUBE_USER", ""),
+				Description: "The username to use for HTTP basic authentication when accessing the Kubernetes master endpoint.",
+			},
+			"password": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("KUBE_PASSWORD", ""),
+				Description: "The password to use for HTTP basic authentication when accessing the Kubernetes master endpoint.",
+			},
+			"insecure": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("KUBE_INSECURE", false),
+				Description: "Whether server should be accessed without verifying the TLS certificate.",
+			},
+			"client_certificate": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("KUBE_CLIENT_CERT_DATA", ""),
+				Description: "PEM-encoded client certificate for TLS authentication.",
+			},
+			"client_key": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("KUBE_CLIENT_KEY_DATA", ""),
+				Description: "PEM-encoded client certificate key for TLS authentication.",
+			},
+			"cluster_ca_certificate": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("KUBE_CLUSTER_CA_CERT_DATA", ""),
+				Description: "PEM-encoded root certificates bundle for TLS authentication.",
+			},
+			"config_paths": {
+				Type:        schema.TypeList,
+				Elem:        &schema.Schema{Type: schema.TypeString},
+				Optional:    true,
+				Description: "A list of paths to kube config files. Can be set with KUBE_CONFIG_PATHS environment variable.",
+			},
+			"config_path": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("KUBE_CONFIG_PATH", ""),
+				Description: "Path to the kube config file. Can be set with KUBE_CONFIG_PATH environment variable.",
+			},
+			"config_context": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("KUBE_CTX", ""),
+			},
+			"config_context_auth_info": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("KUBE_CTX_AUTH_INFO", ""),
+				Description: "",
+			},
+			"config_context_cluster": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("KUBE_CTX_CLUSTER", ""),
+				Description: "",
+			},
+			"token": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("KUBE_TOKEN", ""),
+				Description: "Token to authentifcate a service account.",
+			},
+			"exec": {
+				Type:     schema.TypeList,
+				Optional: true,
+				MaxItems: 1,
+				Elem: &schema.Resource{
+					Schema: map[string]*schema.Schema{
+						"api_version": {
+							Type:     schema.TypeString,
+							Required: true,
+						},
+						"command": {
+							Type:     schema.TypeString,
+							Required: true,
+						},
+						"env": {
+							Type:     schema.TypeMap,
+							Optional: true,
+							Elem:     &schema.Schema{Type: schema.TypeString},
+						},
+						"args": {
+							Type:     schema.TypeList,
+							Optional: true,
+							Elem:     &schema.Schema{Type: schema.TypeString},
+						},
+					},
+				},
+				Description: "Use a credential plugin to authenticate.",
+			},
+		},
+	}
+
+	result := &Backend{Backend: s}
+	result.Backend.ConfigureFunc = result.configure
+	return result
+}
+
+type Backend struct {
+	*schema.Backend
+
+	// The fields below are set from configure
+	kubernetesSecretClient dynamic.ResourceInterface
+	kubernetesLeaseClient  coordinationv1.LeaseInterface
+	config                 *restclient.Config
+	namespace              string
+	labels                 map[string]string
+	nameSuffix             string
+}
+
+func (b Backend) KubernetesSecretClient() (dynamic.ResourceInterface, error) {
+	if b.kubernetesSecretClient != nil {
+		return b.kubernetesSecretClient, nil
+	}
+
+	client, err := dynamic.NewForConfig(b.config)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to configure: %s", err)
+	}
+
+	b.kubernetesSecretClient = client.Resource(secretResource).Namespace(b.namespace)
+	return b.kubernetesSecretClient, nil
+}
+
+func (b Backend) KubernetesLeaseClient() (coordinationv1.LeaseInterface, error) {
+	if b.kubernetesLeaseClient != nil {
+		return b.kubernetesLeaseClient, nil
+	}
+
+	client, err := kubernetes.NewForConfig(b.config)
+	if err != nil {
+		return nil, err
+	}
+
+	b.kubernetesLeaseClient = client.CoordinationV1().Leases(b.namespace)
+	return b.kubernetesLeaseClient, nil
+}
+
+func (b *Backend) configure(ctx context.Context) error {
+	if b.config != nil {
+		return nil
+	}
+
+	// Grab the resource data
+	data := schema.FromContextBackendConfig(ctx)
+
+	cfg, err := getInitialConfig(data)
+	if err != nil {
+		return err
+	}
+
+	// Overriding with static configuration
+	cfg.UserAgent = fmt.Sprintf("HashiCorp/1.0 Terraform/%s", version.String())
+
+	if v, ok := data.GetOk("host"); ok {
+		cfg.Host = v.(string)
+	}
+	if v, ok := data.GetOk("username"); ok {
+		cfg.Username = v.(string)
+	}
+	if v, ok := data.GetOk("password"); ok {
+		cfg.Password = v.(string)
+	}
+	if v, ok := data.GetOk("insecure"); ok {
+		cfg.Insecure = v.(bool)
+	}
+	if v, ok := data.GetOk("cluster_ca_certificate"); ok {
+		cfg.CAData = bytes.NewBufferString(v.(string)).Bytes()
+	}
+	if v, ok := data.GetOk("client_certificate"); ok {
+		cfg.CertData = bytes.NewBufferString(v.(string)).Bytes()
+	}
+	if v, ok := data.GetOk("client_key"); ok {
+		cfg.KeyData = bytes.NewBufferString(v.(string)).Bytes()
+	}
+	if v, ok := data.GetOk("token"); ok {
+		cfg.BearerToken = v.(string)
+	}
+
+	if v, ok := data.GetOk("labels"); ok {
+		labels := map[string]string{}
+		for k, vv := range v.(map[string]interface{}) {
+			labels[k] = vv.(string)
+		}
+		b.labels = labels
+	}
+
+	ns := data.Get("namespace").(string)
+	b.namespace = ns
+	b.nameSuffix = data.Get("secret_suffix").(string)
+	b.config = cfg
+
+	return nil
+}
+
+func getInitialConfig(data *schema.ResourceData) (*restclient.Config, error) {
+	var cfg *restclient.Config
+	var err error
+
+	inCluster := data.Get("in_cluster_config").(bool)
+	if inCluster {
+		cfg, err = restclient.InClusterConfig()
+		if err != nil {
+			return nil, err
+		}
+	} else {
+		cfg, err = tryLoadingConfigFile(data)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	if cfg == nil {
+		cfg = &restclient.Config{}
+	}
+	return cfg, err
+}
+
+func tryLoadingConfigFile(d *schema.ResourceData) (*restclient.Config, error) {
+	loader := &clientcmd.ClientConfigLoadingRules{}
+
+	configPaths := []string{}
+	if v, ok := d.Get("config_path").(string); ok && v != "" {
+		configPaths = []string{v}
+	} else if v, ok := d.Get("config_paths").([]interface{}); ok && len(v) > 0 {
+		for _, p := range v {
+			configPaths = append(configPaths, p.(string))
+		}
+	} else if v := os.Getenv("KUBE_CONFIG_PATHS"); v != "" {
+		configPaths = filepath.SplitList(v)
+	}
+
+	expandedPaths := []string{}
+	for _, p := range configPaths {
+		path, err := homedir.Expand(p)
+		if err != nil {
+			log.Printf("[DEBUG] Could not expand path: %s", err)
+			return nil, err
+		}
+		log.Printf("[DEBUG] Using kubeconfig: %s", path)
+		expandedPaths = append(expandedPaths, path)
+	}
+
+	if len(expandedPaths) == 1 {
+		loader.ExplicitPath = expandedPaths[0]
+	} else {
+		loader.Precedence = expandedPaths
+	}
+
+	overrides := &clientcmd.ConfigOverrides{}
+	ctxSuffix := "; default context"
+
+	ctx, ctxOk := d.GetOk("config_context")
+	authInfo, authInfoOk := d.GetOk("config_context_auth_info")
+	cluster, clusterOk := d.GetOk("config_context_cluster")
+	if ctxOk || authInfoOk || clusterOk {
+		ctxSuffix = "; overriden context"
+		if ctxOk {
+			overrides.CurrentContext = ctx.(string)
+			ctxSuffix += fmt.Sprintf("; config ctx: %s", overrides.CurrentContext)
+			log.Printf("[DEBUG] Using custom current context: %q", overrides.CurrentContext)
+		}
+
+		overrides.Context = clientcmdapi.Context{}
+		if authInfoOk {
+			overrides.Context.AuthInfo = authInfo.(string)
+			ctxSuffix += fmt.Sprintf("; auth_info: %s", overrides.Context.AuthInfo)
+		}
+		if clusterOk {
+			overrides.Context.Cluster = cluster.(string)
+			ctxSuffix += fmt.Sprintf("; cluster: %s", overrides.Context.Cluster)
+		}
+		log.Printf("[DEBUG] Using overidden context: %#v", overrides.Context)
+	}
+
+	if v, ok := d.GetOk("exec"); ok {
+		exec := &clientcmdapi.ExecConfig{}
+		if spec, ok := v.([]interface{})[0].(map[string]interface{}); ok {
+			exec.APIVersion = spec["api_version"].(string)
+			exec.Command = spec["command"].(string)
+			exec.Args = expandStringSlice(spec["args"].([]interface{}))
+			for kk, vv := range spec["env"].(map[string]interface{}) {
+				exec.Env = append(exec.Env, clientcmdapi.ExecEnvVar{Name: kk, Value: vv.(string)})
+			}
+		} else {
+			return nil, fmt.Errorf("Failed to parse exec")
+		}
+		overrides.AuthInfo.Exec = exec
+	}
+
+	cc := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loader, overrides)
+	cfg, err := cc.ClientConfig()
+	if err != nil {
+		if pathErr, ok := err.(*os.PathError); ok && os.IsNotExist(pathErr.Err) {
+			log.Printf("[INFO] Unable to load config file as it doesn't exist at %q", pathErr.Path)
+			return nil, nil
+		}
+		return nil, fmt.Errorf("Failed to initialize kubernetes configuration: %s", err)
+	}
+
+	log.Printf("[INFO] Successfully initialized config")
+	return cfg, nil
+}
+
+func expandStringSlice(s []interface{}) []string {
+	result := make([]string, len(s), len(s))
+	for k, v := range s {
+		// Handle the Terraform parser bug which turns empty strings in lists to nil.
+		if v == nil {
+			result[k] = ""
+		} else {
+			result[k] = v.(string)
+		}
+	}
+	return result
+}
diff --git a/v1.5.7/internal/backend/remote-state/kubernetes/backend_state.go b/v1.5.7/internal/backend/remote-state/kubernetes/backend_state.go
new file mode 100644
index 0000000..319c2d3
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/kubernetes/backend_state.go
@@ -0,0 +1,173 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package kubernetes
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"sort"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// Workspaces returns a list of names for the workspaces found in k8s. The default
+// workspace is always returned as the first element in the slice.
+func (b *Backend) Workspaces() ([]string, error) {
+	secretClient, err := b.KubernetesSecretClient()
+	if err != nil {
+		return nil, err
+	}
+
+	secrets, err := secretClient.List(
+		context.Background(),
+		metav1.ListOptions{
+			LabelSelector: tfstateKey + "=true",
+		},
+	)
+	if err != nil {
+		return nil, err
+	}
+
+	// Use a map so there aren't duplicate workspaces
+	m := make(map[string]struct{})
+	for _, secret := range secrets.Items {
+		sl := secret.GetLabels()
+		ws, ok := sl[tfstateWorkspaceKey]
+		if !ok {
+			continue
+		}
+
+		key, ok := sl[tfstateSecretSuffixKey]
+		if !ok {
+			continue
+		}
+
+		// Make sure it isn't default and the key matches
+		if ws != backend.DefaultStateName && key == b.nameSuffix {
+			m[ws] = struct{}{}
+		}
+	}
+
+	states := []string{backend.DefaultStateName}
+	for k := range m {
+		states = append(states, k)
+	}
+
+	sort.Strings(states[1:])
+	return states, nil
+}
+
+func (b *Backend) DeleteWorkspace(name string, _ bool) error {
+	if name == backend.DefaultStateName || name == "" {
+		return fmt.Errorf("can't delete default state")
+	}
+
+	client, err := b.remoteClient(name)
+	if err != nil {
+		return err
+	}
+
+	return client.Delete()
+}
+
+func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
+	c, err := b.remoteClient(name)
+	if err != nil {
+		return nil, err
+	}
+
+	stateMgr := &remote.State{Client: c}
+
+	// Grab the value
+	if err := stateMgr.RefreshState(); err != nil {
+		return nil, err
+	}
+
+	// If we have no state, we have to create an empty state
+	if v := stateMgr.State(); v == nil {
+
+		lockInfo := statemgr.NewLockInfo()
+		lockInfo.Operation = "init"
+		lockID, err := stateMgr.Lock(lockInfo)
+		if err != nil {
+			return nil, err
+		}
+
+		secretName, err := c.createSecretName()
+		if err != nil {
+			return nil, err
+		}
+
+		// Local helper function so we can call it multiple places
+		unlock := func(baseErr error) error {
+			if err := stateMgr.Unlock(lockID); err != nil {
+				const unlockErrMsg = `%v
+				Additionally, unlocking the state in Kubernetes failed:
+
+				Error message: %q
+				Lock ID (gen): %v
+				Secret Name: %v
+
+				You may have to force-unlock this state in order to use it again.
+				The Kubernetes backend acquires a lock during initialization to ensure
+				the initial state file is created.`
+				return fmt.Errorf(unlockErrMsg, baseErr, err.Error(), lockID, secretName)
+			}
+
+			return baseErr
+		}
+
+		if err := stateMgr.WriteState(states.NewState()); err != nil {
+			return nil, unlock(err)
+		}
+		if err := stateMgr.PersistState(nil); err != nil {
+			return nil, unlock(err)
+		}
+
+		// Unlock, the state should now be initialized
+		if err := unlock(nil); err != nil {
+			return nil, err
+		}
+
+	}
+
+	return stateMgr, nil
+}
+
+// get a remote client configured for this state
+func (b *Backend) remoteClient(name string) (*RemoteClient, error) {
+	if name == "" {
+		return nil, errors.New("missing state name")
+	}
+
+	secretClient, err := b.KubernetesSecretClient()
+	if err != nil {
+		return nil, err
+	}
+
+	leaseClient, err := b.KubernetesLeaseClient()
+	if err != nil {
+		return nil, err
+	}
+
+	client := &RemoteClient{
+		kubernetesSecretClient: secretClient,
+		kubernetesLeaseClient:  leaseClient,
+		namespace:              b.namespace,
+		labels:                 b.labels,
+		nameSuffix:             b.nameSuffix,
+		workspace:              name,
+	}
+
+	return client, nil
+}
+
+func (b *Backend) client() *RemoteClient {
+	return &RemoteClient{}
+}
diff --git a/v1.5.7/internal/backend/remote-state/kubernetes/backend_test.go b/v1.5.7/internal/backend/remote-state/kubernetes/backend_test.go
new file mode 100644
index 0000000..0eb0f78
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/kubernetes/backend_test.go
@@ -0,0 +1,199 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package kubernetes
+
+import (
+	"context"
+	"fmt"
+	"math/rand"
+	"os"
+	"sync"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+const (
+	secretSuffix = "test-state"
+)
+
+var namespace string
+
+// verify that we are doing ACC tests or the k8s tests specifically
+func testACC(t *testing.T) {
+	skip := os.Getenv("TF_ACC") == "" && os.Getenv("TF_K8S_TEST") == ""
+	if skip {
+		t.Log("k8s backend tests require setting TF_ACC or TF_K8S_TEST")
+		t.Skip()
+	}
+
+	ns := os.Getenv("KUBE_NAMESPACE")
+
+	if ns != "" {
+		namespace = ns
+	} else {
+		namespace = "default"
+	}
+
+	cleanupK8sResources(t)
+}
+
+func TestBackend_impl(t *testing.T) {
+	var _ backend.Backend = new(Backend)
+}
+
+func TestBackend(t *testing.T) {
+	testACC(t)
+	defer cleanupK8sResources(t)
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"secret_suffix": secretSuffix,
+	}))
+
+	// Test
+	backend.TestBackendStates(t, b1)
+}
+
+func TestBackendLocks(t *testing.T) {
+	testACC(t)
+	defer cleanupK8sResources(t)
+
+	// Get the backend. We need two to test locking.
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"secret_suffix": secretSuffix,
+	}))
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"secret_suffix": secretSuffix,
+	}))
+
+	// Test
+	backend.TestBackendStateLocks(t, b1, b2)
+	backend.TestBackendStateForceUnlock(t, b1, b2)
+}
+
+func TestBackendLocksSoak(t *testing.T) {
+	testACC(t)
+	defer cleanupK8sResources(t)
+
+	clientCount := 100
+	lockAttempts := 100
+
+	lockers := []statemgr.Locker{}
+	for i := 0; i < clientCount; i++ {
+		b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+			"secret_suffix": secretSuffix,
+		}))
+
+		s, err := b.StateMgr(backend.DefaultStateName)
+		if err != nil {
+			t.Fatalf("Error creating state manager: %v", err)
+		}
+
+		lockers = append(lockers, s.(statemgr.Locker))
+	}
+
+	wg := sync.WaitGroup{}
+	for i, l := range lockers {
+		wg.Add(1)
+		go func(locker statemgr.Locker, n int) {
+			defer wg.Done()
+
+			li := statemgr.NewLockInfo()
+			li.Operation = "test"
+			li.Who = fmt.Sprintf("client-%v", n)
+
+			for i := 0; i < lockAttempts; i++ {
+				id, err := locker.Lock(li)
+				if err != nil {
+					continue
+				}
+
+				// hold onto the lock for a little bit
+				time.Sleep(time.Duration(rand.Intn(10)) * time.Microsecond)
+
+				err = locker.Unlock(id)
+				if err != nil {
+					t.Errorf("failed to unlock: %v", err)
+				}
+			}
+		}(l, i)
+	}
+
+	wg.Wait()
+}
+
+func cleanupK8sResources(t *testing.T) {
+	ctx := context.Background()
+	// Get a backend to use the k8s client
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"secret_suffix": secretSuffix,
+	}))
+
+	b := b1.(*Backend)
+
+	sClient, err := b.KubernetesSecretClient()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Delete secrets
+	opts := metav1.ListOptions{LabelSelector: tfstateKey + "=true"}
+	secrets, err := sClient.List(ctx, opts)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	delProp := metav1.DeletePropagationBackground
+	delOps := metav1.DeleteOptions{PropagationPolicy: &delProp}
+	var errs []error
+
+	for _, secret := range secrets.Items {
+		labels := secret.GetLabels()
+		key, ok := labels[tfstateSecretSuffixKey]
+		if !ok {
+			continue
+		}
+
+		if key == secretSuffix {
+			err = sClient.Delete(ctx, secret.GetName(), delOps)
+			if err != nil {
+				errs = append(errs, err)
+			}
+		}
+	}
+
+	leaseClient, err := b.KubernetesLeaseClient()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Delete leases
+	leases, err := leaseClient.List(ctx, opts)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, lease := range leases.Items {
+		labels := lease.GetLabels()
+		key, ok := labels[tfstateSecretSuffixKey]
+		if !ok {
+			continue
+		}
+
+		if key == secretSuffix {
+			err = leaseClient.Delete(ctx, lease.GetName(), delOps)
+			if err != nil {
+				errs = append(errs, err)
+			}
+		}
+	}
+
+	if len(errs) > 0 {
+		t.Fatal(errs)
+	}
+}
diff --git a/v1.5.7/internal/backend/remote-state/kubernetes/client.go b/v1.5.7/internal/backend/remote-state/kubernetes/client.go
new file mode 100644
index 0000000..5329df9
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/kubernetes/client.go
@@ -0,0 +1,416 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package kubernetes
+
+import (
+	"bytes"
+	"compress/gzip"
+	"context"
+	"crypto/md5"
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	k8serrors "k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/util/validation"
+	"k8s.io/client-go/dynamic"
+	_ "k8s.io/client-go/plugin/pkg/client/auth" // Import to initialize client auth plugins.
+	"k8s.io/utils/pointer"
+
+	coordinationv1 "k8s.io/api/coordination/v1"
+	coordinationclientv1 "k8s.io/client-go/kubernetes/typed/coordination/v1"
+)
+
+const (
+	tfstateKey                = "tfstate"
+	tfstateSecretSuffixKey    = "tfstateSecretSuffix"
+	tfstateWorkspaceKey       = "tfstateWorkspace"
+	tfstateLockInfoAnnotation = "app.terraform.io/lock-info"
+	managedByKey              = "app.kubernetes.io/managed-by"
+)
+
+type RemoteClient struct {
+	kubernetesSecretClient dynamic.ResourceInterface
+	kubernetesLeaseClient  coordinationclientv1.LeaseInterface
+	namespace              string
+	labels                 map[string]string
+	nameSuffix             string
+	workspace              string
+}
+
+func (c *RemoteClient) Get() (payload *remote.Payload, err error) {
+	secretName, err := c.createSecretName()
+	if err != nil {
+		return nil, err
+	}
+	secret, err := c.kubernetesSecretClient.Get(context.Background(), secretName, metav1.GetOptions{})
+	if err != nil {
+		if k8serrors.IsNotFound(err) {
+			return nil, nil
+		}
+		return nil, err
+	}
+
+	secretData := getSecretData(secret)
+	stateRaw, ok := secretData[tfstateKey]
+	if !ok {
+		// The secret exists but there is no state in it
+		return nil, nil
+	}
+
+	stateRawString := stateRaw.(string)
+
+	state, err := uncompressState(stateRawString)
+	if err != nil {
+		return nil, err
+	}
+
+	md5 := md5.Sum(state)
+
+	p := &remote.Payload{
+		Data: state,
+		MD5:  md5[:],
+	}
+	return p, nil
+}
+
+func (c *RemoteClient) Put(data []byte) error {
+	ctx := context.Background()
+	secretName, err := c.createSecretName()
+	if err != nil {
+		return err
+	}
+
+	payload, err := compressState(data)
+	if err != nil {
+		return err
+	}
+
+	secret, err := c.getSecret(secretName)
+	if err != nil {
+		if !k8serrors.IsNotFound(err) {
+			return err
+		}
+
+		secret = &unstructured.Unstructured{
+			Object: map[string]interface{}{
+				"metadata": metav1.ObjectMeta{
+					Name:        secretName,
+					Namespace:   c.namespace,
+					Labels:      c.getLabels(),
+					Annotations: map[string]string{"encoding": "gzip"},
+				},
+			},
+		}
+
+		secret, err = c.kubernetesSecretClient.Create(ctx, secret, metav1.CreateOptions{})
+		if err != nil {
+			return err
+		}
+	}
+
+	setState(secret, payload)
+	_, err = c.kubernetesSecretClient.Update(ctx, secret, metav1.UpdateOptions{})
+	return err
+}
+
+// Delete the state secret
+func (c *RemoteClient) Delete() error {
+	secretName, err := c.createSecretName()
+	if err != nil {
+		return err
+	}
+
+	err = c.deleteSecret(secretName)
+	if err != nil {
+		if !k8serrors.IsNotFound(err) {
+			return err
+		}
+	}
+
+	leaseName, err := c.createLeaseName()
+	if err != nil {
+		return err
+	}
+
+	err = c.deleteLease(leaseName)
+	if err != nil {
+		if !k8serrors.IsNotFound(err) {
+			return err
+		}
+	}
+	return nil
+}
+
+func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
+	ctx := context.Background()
+	leaseName, err := c.createLeaseName()
+	if err != nil {
+		return "", err
+	}
+
+	lease, err := c.getLease(leaseName)
+	if err != nil {
+		if !k8serrors.IsNotFound(err) {
+			return "", err
+		}
+
+		labels := c.getLabels()
+		lease = &coordinationv1.Lease{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:   leaseName,
+				Labels: labels,
+				Annotations: map[string]string{
+					tfstateLockInfoAnnotation: string(info.Marshal()),
+				},
+			},
+			Spec: coordinationv1.LeaseSpec{
+				HolderIdentity: pointer.StringPtr(info.ID),
+			},
+		}
+
+		_, err = c.kubernetesLeaseClient.Create(ctx, lease, metav1.CreateOptions{})
+		if err != nil {
+			return "", err
+		} else {
+			return info.ID, nil
+		}
+	}
+
+	if lease.Spec.HolderIdentity != nil {
+		if *lease.Spec.HolderIdentity == info.ID {
+			return info.ID, nil
+		}
+
+		currentLockInfo, err := c.getLockInfo(lease)
+		if err != nil {
+			return "", err
+		}
+
+		lockErr := &statemgr.LockError{
+			Info: currentLockInfo,
+			Err:  errors.New("the state is already locked by another terraform client"),
+		}
+		return "", lockErr
+	}
+
+	lease.Spec.HolderIdentity = pointer.StringPtr(info.ID)
+	setLockInfo(lease, info.Marshal())
+	_, err = c.kubernetesLeaseClient.Update(ctx, lease, metav1.UpdateOptions{})
+	if err != nil {
+		return "", err
+	}
+
+	return info.ID, err
+}
+
+func (c *RemoteClient) Unlock(id string) error {
+	leaseName, err := c.createLeaseName()
+	if err != nil {
+		return err
+	}
+
+	lease, err := c.getLease(leaseName)
+	if err != nil {
+		return err
+	}
+
+	if lease.Spec.HolderIdentity == nil {
+		return fmt.Errorf("state is already unlocked")
+	}
+
+	lockInfo, err := c.getLockInfo(lease)
+	if err != nil {
+		return err
+	}
+
+	lockErr := &statemgr.LockError{Info: lockInfo}
+	if *lease.Spec.HolderIdentity != id {
+		lockErr.Err = fmt.Errorf("lock id %q does not match existing lock", id)
+		return lockErr
+	}
+
+	lease.Spec.HolderIdentity = nil
+	removeLockInfo(lease)
+
+	_, err = c.kubernetesLeaseClient.Update(context.Background(), lease, metav1.UpdateOptions{})
+	if err != nil {
+		lockErr.Err = err
+		return lockErr
+	}
+
+	return nil
+}
+
+func (c *RemoteClient) getLockInfo(lease *coordinationv1.Lease) (*statemgr.LockInfo, error) {
+	lockData, ok := getLockInfo(lease)
+	if len(lockData) == 0 || !ok {
+		return nil, nil
+	}
+
+	lockInfo := &statemgr.LockInfo{}
+	err := json.Unmarshal(lockData, lockInfo)
+	if err != nil {
+		return nil, err
+	}
+
+	return lockInfo, nil
+}
+
+func (c *RemoteClient) getLabels() map[string]string {
+	l := map[string]string{
+		tfstateKey:             "true",
+		tfstateSecretSuffixKey: c.nameSuffix,
+		tfstateWorkspaceKey:    c.workspace,
+		managedByKey:           "terraform",
+	}
+
+	if len(c.labels) != 0 {
+		for k, v := range c.labels {
+			l[k] = v
+		}
+	}
+
+	return l
+}
+
+func (c *RemoteClient) getSecret(name string) (*unstructured.Unstructured, error) {
+	return c.kubernetesSecretClient.Get(context.Background(), name, metav1.GetOptions{})
+}
+
+func (c *RemoteClient) getLease(name string) (*coordinationv1.Lease, error) {
+	return c.kubernetesLeaseClient.Get(context.Background(), name, metav1.GetOptions{})
+}
+
+func (c *RemoteClient) deleteSecret(name string) error {
+	secret, err := c.getSecret(name)
+	if err != nil {
+		return err
+	}
+
+	labels := secret.GetLabels()
+	v, ok := labels[tfstateKey]
+	if !ok || v != "true" {
+		return fmt.Errorf("Secret does does not have %q label", tfstateKey)
+	}
+
+	delProp := metav1.DeletePropagationBackground
+	delOps := metav1.DeleteOptions{PropagationPolicy: &delProp}
+	return c.kubernetesSecretClient.Delete(context.Background(), name, delOps)
+}
+
+func (c *RemoteClient) deleteLease(name string) error {
+	secret, err := c.getLease(name)
+	if err != nil {
+		return err
+	}
+
+	labels := secret.GetLabels()
+	v, ok := labels[tfstateKey]
+	if !ok || v != "true" {
+		return fmt.Errorf("Lease does does not have %q label", tfstateKey)
+	}
+
+	delProp := metav1.DeletePropagationBackground
+	delOps := metav1.DeleteOptions{PropagationPolicy: &delProp}
+	return c.kubernetesLeaseClient.Delete(context.Background(), name, delOps)
+}
+
+func (c *RemoteClient) createSecretName() (string, error) {
+	secretName := strings.Join([]string{tfstateKey, c.workspace, c.nameSuffix}, "-")
+
+	errs := validation.IsDNS1123Subdomain(secretName)
+	if len(errs) > 0 {
+		k8sInfo := `
+This is a requirement for Kubernetes secret names. 
+The workspace name and key must adhere to Kubernetes naming conventions.`
+		msg := fmt.Sprintf("the secret name %v is invalid, ", secretName)
+		return "", errors.New(msg + strings.Join(errs, ",") + k8sInfo)
+	}
+
+	return secretName, nil
+}
+
+func (c *RemoteClient) createLeaseName() (string, error) {
+	n, err := c.createSecretName()
+	if err != nil {
+		return "", err
+	}
+	return "lock-" + n, nil
+}
+
+func compressState(data []byte) ([]byte, error) {
+	b := new(bytes.Buffer)
+	gz := gzip.NewWriter(b)
+	if _, err := gz.Write(data); err != nil {
+		return nil, err
+	}
+	if err := gz.Close(); err != nil {
+		return nil, err
+	}
+	return b.Bytes(), nil
+}
+
+func uncompressState(data string) ([]byte, error) {
+	decode, err := base64.StdEncoding.DecodeString(data)
+	if err != nil {
+		return nil, err
+	}
+
+	b := new(bytes.Buffer)
+	gz, err := gzip.NewReader(bytes.NewReader(decode))
+	if err != nil {
+		return nil, err
+	}
+	b.ReadFrom(gz)
+	if err := gz.Close(); err != nil {
+		return nil, err
+	}
+	return b.Bytes(), nil
+}
+
+func getSecretData(secret *unstructured.Unstructured) map[string]interface{} {
+	if m, ok := secret.Object["data"].(map[string]interface{}); ok {
+		return m
+	}
+	return map[string]interface{}{}
+}
+
+func getLockInfo(lease *coordinationv1.Lease) ([]byte, bool) {
+	info, ok := lease.ObjectMeta.GetAnnotations()[tfstateLockInfoAnnotation]
+	if !ok {
+		return nil, false
+	}
+	return []byte(info), true
+}
+
+func setLockInfo(lease *coordinationv1.Lease, l []byte) {
+	annotations := lease.ObjectMeta.GetAnnotations()
+	if annotations != nil {
+		annotations[tfstateLockInfoAnnotation] = string(l)
+	} else {
+		annotations = map[string]string{
+			tfstateLockInfoAnnotation: string(l),
+		}
+	}
+	lease.ObjectMeta.SetAnnotations(annotations)
+}
+
+func removeLockInfo(lease *coordinationv1.Lease) {
+	annotations := lease.ObjectMeta.GetAnnotations()
+	delete(annotations, tfstateLockInfoAnnotation)
+	lease.ObjectMeta.SetAnnotations(annotations)
+}
+
+func setState(secret *unstructured.Unstructured, t []byte) {
+	secretData := getSecretData(secret)
+	secretData[tfstateKey] = t
+	secret.Object["data"] = secretData
+}
diff --git a/v1.5.7/internal/backend/remote-state/kubernetes/client_test.go b/v1.5.7/internal/backend/remote-state/kubernetes/client_test.go
new file mode 100644
index 0000000..523df39
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/kubernetes/client_test.go
@@ -0,0 +1,122 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package kubernetes
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+func TestRemoteClient_impl(t *testing.T) {
+	var _ remote.Client = new(RemoteClient)
+	var _ remote.ClientLocker = new(RemoteClient)
+}
+
+func TestRemoteClient(t *testing.T) {
+	testACC(t)
+	defer cleanupK8sResources(t)
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"secret_suffix": secretSuffix,
+	}))
+
+	state, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestClient(t, state.(*remote.State).Client)
+}
+
+func TestRemoteClientLocks(t *testing.T) {
+	testACC(t)
+	defer cleanupK8sResources(t)
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"secret_suffix": secretSuffix,
+	}))
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"secret_suffix": secretSuffix,
+	}))
+
+	s1, err := b1.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	s2, err := b2.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestRemoteLocks(t, s1.(*remote.State).Client, s2.(*remote.State).Client)
+}
+
+func TestForceUnlock(t *testing.T) {
+	testACC(t)
+	defer cleanupK8sResources(t)
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"secret_suffix": secretSuffix,
+	}))
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"secret_suffix": secretSuffix,
+	}))
+
+	// first test with default
+	s1, err := b1.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	info := statemgr.NewLockInfo()
+	info.Operation = "test"
+	info.Who = "clientA"
+
+	lockID, err := s1.Lock(info)
+	if err != nil {
+		t.Fatal("unable to get initial lock:", err)
+	}
+
+	// s1 is now locked, get the same state through s2 and unlock it
+	s2, err := b2.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal("failed to get default state to force unlock:", err)
+	}
+
+	if err := s2.Unlock(lockID); err != nil {
+		t.Fatal("failed to force-unlock default state")
+	}
+
+	// now try the same thing with a named state
+	// first test with default
+	s1, err = b1.StateMgr("test")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	info = statemgr.NewLockInfo()
+	info.Operation = "test"
+	info.Who = "clientA"
+
+	lockID, err = s1.Lock(info)
+	if err != nil {
+		t.Fatal("unable to get initial lock:", err)
+	}
+
+	// s1 is now locked, get the same state through s2 and unlock it
+	s2, err = b2.StateMgr("test")
+	if err != nil {
+		t.Fatal("failed to get named state to force unlock:", err)
+	}
+
+	if err = s2.Unlock(lockID); err != nil {
+		t.Fatal("failed to force-unlock named state")
+	}
+}
diff --git a/v1.5.7/internal/backend/remote-state/oss/backend.go b/v1.5.7/internal/backend/remote-state/oss/backend.go
new file mode 100644
index 0000000..e6a546a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/oss/backend.go
@@ -0,0 +1,709 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package oss
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"net/url"
+	"os"
+	"regexp"
+	"runtime"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/endpoints"
+
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
+	"github.com/aliyun/alibaba-cloud-sdk-go/services/location"
+	"github.com/aliyun/alibaba-cloud-sdk-go/services/sts"
+	"github.com/aliyun/aliyun-oss-go-sdk/oss"
+	"github.com/aliyun/aliyun-tablestore-go-sdk/tablestore"
+	"github.com/hashicorp/go-cleanhttp"
+	"github.com/jmespath/go-jmespath"
+	"github.com/mitchellh/go-homedir"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/legacy/helper/schema"
+	"github.com/hashicorp/terraform/version"
+)
+
+// Deprecated in favor of flattening assume_role_* options
+func deprecatedAssumeRoleSchema() *schema.Schema {
+	return &schema.Schema{
+		Type:     schema.TypeSet,
+		Optional: true,
+		MaxItems: 1,
+		//Deprecated: "use assume_role_* options instead",
+		Elem: &schema.Resource{
+			Schema: map[string]*schema.Schema{
+				"role_arn": {
+					Type:        schema.TypeString,
+					Required:    true,
+					Description: "The ARN of a RAM role to assume prior to making API calls.",
+					DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ASSUME_ROLE_ARN", ""),
+				},
+				"session_name": {
+					Type:        schema.TypeString,
+					Optional:    true,
+					Description: "The session name to use when assuming the role.",
+					DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ASSUME_ROLE_SESSION_NAME", ""),
+				},
+				"policy": {
+					Type:        schema.TypeString,
+					Optional:    true,
+					Description: "The permissions applied when assuming a role. You cannot use this policy to grant permissions which exceed those of the role that is being assumed.",
+				},
+				"session_expiration": {
+					Type:        schema.TypeInt,
+					Optional:    true,
+					Description: "The time after which the established session for assuming role expires.",
+					ValidateFunc: func(v interface{}, k string) ([]string, []error) {
+						min := 900
+						max := 3600
+						value, ok := v.(int)
+						if !ok {
+							return nil, []error{fmt.Errorf("expected type of %s to be int", k)}
+						}
+
+						if value < min || value > max {
+							return nil, []error{fmt.Errorf("expected %s to be in the range (%d - %d), got %d", k, min, max, v)}
+						}
+
+						return nil, nil
+					},
+				},
+			},
+		},
+	}
+}
+
+// New creates a new backend for OSS remote state.
+func New() backend.Backend {
+	s := &schema.Backend{
+		Schema: map[string]*schema.Schema{
+			"access_key": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "Alibaba Cloud Access Key ID",
+				DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ACCESS_KEY", os.Getenv("ALICLOUD_ACCESS_KEY_ID")),
+			},
+
+			"secret_key": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "Alibaba Cloud Access Secret Key",
+				DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_SECRET_KEY", os.Getenv("ALICLOUD_ACCESS_KEY_SECRET")),
+			},
+
+			"security_token": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "Alibaba Cloud Security Token",
+				DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_SECURITY_TOKEN", ""),
+			},
+
+			"ecs_role_name": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ECS_ROLE_NAME", os.Getenv("ALICLOUD_ECS_ROLE_NAME")),
+				Description: "The RAM Role Name attached on a ECS instance for API operations. You can retrieve this from the 'Access Control' section of the Alibaba Cloud console.",
+			},
+
+			"region": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The region of the OSS bucket.",
+				DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_REGION", os.Getenv("ALICLOUD_DEFAULT_REGION")),
+			},
+			"sts_endpoint": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "A custom endpoint for the STS API",
+				DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_STS_ENDPOINT", ""),
+			},
+			"tablestore_endpoint": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "A custom endpoint for the TableStore API",
+				DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_TABLESTORE_ENDPOINT", ""),
+			},
+			"endpoint": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "A custom endpoint for the OSS API",
+				DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_OSS_ENDPOINT", os.Getenv("OSS_ENDPOINT")),
+			},
+
+			"bucket": {
+				Type:        schema.TypeString,
+				Required:    true,
+				Description: "The name of the OSS bucket",
+			},
+
+			"prefix": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The directory where state files will be saved inside the bucket",
+				Default:     "env:",
+				ValidateFunc: func(v interface{}, s string) ([]string, []error) {
+					prefix := v.(string)
+					if strings.HasPrefix(prefix, "/") || strings.HasPrefix(prefix, "./") {
+						return nil, []error{fmt.Errorf("workspace_key_prefix must not start with '/' or './'")}
+					}
+					return nil, nil
+				},
+			},
+
+			"key": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The path of the state file inside the bucket",
+				ValidateFunc: func(v interface{}, s string) ([]string, []error) {
+					if strings.HasPrefix(v.(string), "/") || strings.HasSuffix(v.(string), "/") {
+						return nil, []error{fmt.Errorf("key can not start and end with '/'")}
+					}
+					return nil, nil
+				},
+				Default: "terraform.tfstate",
+			},
+
+			"tablestore_table": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "TableStore table for state locking and consistency",
+				Default:     "",
+			},
+
+			"encrypt": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "Whether to enable server side encryption of the state file",
+				Default:     false,
+			},
+
+			"acl": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "Object ACL to be applied to the state file",
+				Default:     "",
+				ValidateFunc: func(v interface{}, k string) ([]string, []error) {
+					if value := v.(string); value != "" {
+						acls := oss.ACLType(value)
+						if acls != oss.ACLPrivate && acls != oss.ACLPublicRead && acls != oss.ACLPublicReadWrite {
+							return nil, []error{fmt.Errorf(
+								"%q must be a valid ACL value , expected %s, %s or %s, got %q",
+								k, oss.ACLPrivate, oss.ACLPublicRead, oss.ACLPublicReadWrite, acls)}
+						}
+					}
+					return nil, nil
+				},
+			},
+			"shared_credentials_file": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_SHARED_CREDENTIALS_FILE", ""),
+				Description: "This is the path to the shared credentials file. If this is not set and a profile is specified, `~/.aliyun/config.json` will be used.",
+			},
+			"profile": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "This is the Alibaba Cloud profile name as set in the shared credentials file. It can also be sourced from the `ALICLOUD_PROFILE` environment variable.",
+				DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_PROFILE", ""),
+			},
+			"assume_role": deprecatedAssumeRoleSchema(),
+			"assume_role_role_arn": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The ARN of a RAM role to assume prior to making API calls.",
+				DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ASSUME_ROLE_ARN", ""),
+			},
+			"assume_role_session_name": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The session name to use when assuming the role.",
+				DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ASSUME_ROLE_SESSION_NAME", ""),
+			},
+			"assume_role_policy": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The permissions applied when assuming a role. You cannot use this policy to grant permissions which exceed those of the role that is being assumed.",
+			},
+			"assume_role_session_expiration": {
+				Type:        schema.TypeInt,
+				Optional:    true,
+				Description: "The time after which the established session for assuming role expires.",
+				ValidateFunc: func(v interface{}, k string) ([]string, []error) {
+					min := 900
+					max := 3600
+					value, ok := v.(int)
+					if !ok {
+						return nil, []error{fmt.Errorf("expected type of %s to be int", k)}
+					}
+
+					if value < min || value > max {
+						return nil, []error{fmt.Errorf("expected %s to be in the range (%d - %d), got %d", k, min, max, v)}
+					}
+
+					return nil, nil
+				},
+			},
+		},
+	}
+
+	result := &Backend{Backend: s}
+	result.Backend.ConfigureFunc = result.configure
+	return result
+}
+
+type Backend struct {
+	*schema.Backend
+
+	// The fields below are set from configure
+	ossClient *oss.Client
+	otsClient *tablestore.TableStoreClient
+
+	bucketName           string
+	statePrefix          string
+	stateKey             string
+	serverSideEncryption bool
+	acl                  string
+	otsEndpoint          string
+	otsTable             string
+}
+
+func (b *Backend) configure(ctx context.Context) error {
+	if b.ossClient != nil {
+		return nil
+	}
+
+	// Grab the resource data
+	d := schema.FromContextBackendConfig(ctx)
+
+	b.bucketName = d.Get("bucket").(string)
+	b.statePrefix = strings.TrimPrefix(strings.Trim(d.Get("prefix").(string), "/"), "./")
+	b.stateKey = d.Get("key").(string)
+	b.serverSideEncryption = d.Get("encrypt").(bool)
+	b.acl = d.Get("acl").(string)
+
+	var getBackendConfig = func(str string, key string) string {
+		if str == "" {
+			value, err := getConfigFromProfile(d, key)
+			if err == nil && value != nil {
+				str = value.(string)
+			}
+		}
+		return str
+	}
+
+	accessKey := getBackendConfig(d.Get("access_key").(string), "access_key_id")
+	secretKey := getBackendConfig(d.Get("secret_key").(string), "access_key_secret")
+	securityToken := getBackendConfig(d.Get("security_token").(string), "sts_token")
+	region := getBackendConfig(d.Get("region").(string), "region_id")
+
+	stsEndpoint := d.Get("sts_endpoint").(string)
+	endpoint := d.Get("endpoint").(string)
+	schma := "https"
+
+	roleArn := getBackendConfig("", "ram_role_arn")
+	sessionName := getBackendConfig("", "ram_session_name")
+	var policy string
+	var sessionExpiration int
+	expiredSeconds, err := getConfigFromProfile(d, "expired_seconds")
+	if err == nil && expiredSeconds != nil {
+		sessionExpiration = (int)(expiredSeconds.(float64))
+	}
+
+	if v, ok := d.GetOk("assume_role_role_arn"); ok && v.(string) != "" {
+		roleArn = v.(string)
+		if v, ok := d.GetOk("assume_role_session_name"); ok {
+			sessionName = v.(string)
+		}
+		if v, ok := d.GetOk("assume_role_policy"); ok {
+			policy = v.(string)
+		}
+		if v, ok := d.GetOk("assume_role_session_expiration"); ok {
+			sessionExpiration = v.(int)
+		}
+	} else if v, ok := d.GetOk("assume_role"); ok {
+		// deprecated assume_role block
+		for _, v := range v.(*schema.Set).List() {
+			assumeRole := v.(map[string]interface{})
+			if assumeRole["role_arn"].(string) != "" {
+				roleArn = assumeRole["role_arn"].(string)
+			}
+			if assumeRole["session_name"].(string) != "" {
+				sessionName = assumeRole["session_name"].(string)
+			}
+			policy = assumeRole["policy"].(string)
+			sessionExpiration = assumeRole["session_expiration"].(int)
+		}
+	}
+
+	if sessionName == "" {
+		sessionName = "terraform"
+	}
+	if sessionExpiration == 0 {
+		if v := os.Getenv("ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION"); v != "" {
+			if expiredSeconds, err := strconv.Atoi(v); err == nil {
+				sessionExpiration = expiredSeconds
+			}
+		}
+		if sessionExpiration == 0 {
+			sessionExpiration = 3600
+		}
+	}
+
+	if accessKey == "" {
+		ecsRoleName := getBackendConfig(d.Get("ecs_role_name").(string), "ram_role_name")
+		subAccessKeyId, subAccessKeySecret, subSecurityToken, err := getAuthCredentialByEcsRoleName(ecsRoleName)
+		if err != nil {
+			return err
+		}
+		accessKey, secretKey, securityToken = subAccessKeyId, subAccessKeySecret, subSecurityToken
+	}
+
+	if roleArn != "" {
+		subAccessKeyId, subAccessKeySecret, subSecurityToken, err := getAssumeRoleAK(accessKey, secretKey, securityToken, region, roleArn, sessionName, policy, stsEndpoint, sessionExpiration)
+		if err != nil {
+			return err
+		}
+		accessKey, secretKey, securityToken = subAccessKeyId, subAccessKeySecret, subSecurityToken
+	}
+
+	if endpoint == "" {
+		endpointsResponse, err := b.getOSSEndpointByRegion(accessKey, secretKey, securityToken, region)
+		if err != nil {
+			log.Printf("[WARN] getting oss endpoint failed and using oss-%s.aliyuncs.com instead. Error: %#v.", region, err)
+		} else {
+			for _, endpointItem := range endpointsResponse.Endpoints.Endpoint {
+				if endpointItem.Type == "openAPI" {
+					endpoint = endpointItem.Endpoint
+					break
+				}
+			}
+		}
+		if endpoint == "" {
+			endpoint = fmt.Sprintf("oss-%s.aliyuncs.com", region)
+		}
+	}
+	if !strings.HasPrefix(endpoint, "http") {
+		endpoint = fmt.Sprintf("%s://%s", schma, endpoint)
+	}
+	log.Printf("[DEBUG] Instantiate OSS client using endpoint: %#v", endpoint)
+	var options []oss.ClientOption
+	if securityToken != "" {
+		options = append(options, oss.SecurityToken(securityToken))
+	}
+	options = append(options, oss.UserAgent(fmt.Sprintf("%s/%s", TerraformUA, TerraformVersion)))
+
+	proxyUrl := getHttpProxyUrl()
+	if proxyUrl != nil {
+		options = append(options, oss.Proxy(proxyUrl.String()))
+	}
+
+	client, err := oss.New(endpoint, accessKey, secretKey, options...)
+	b.ossClient = client
+	otsEndpoint := d.Get("tablestore_endpoint").(string)
+	if otsEndpoint != "" {
+		if !strings.HasPrefix(otsEndpoint, "http") {
+			otsEndpoint = fmt.Sprintf("%s://%s", schma, otsEndpoint)
+		}
+		b.otsEndpoint = otsEndpoint
+		parts := strings.Split(strings.TrimPrefix(strings.TrimPrefix(otsEndpoint, "https://"), "http://"), ".")
+		b.otsClient = tablestore.NewClientWithConfig(otsEndpoint, parts[0], accessKey, secretKey, securityToken, tablestore.NewDefaultTableStoreConfig())
+	}
+	b.otsTable = d.Get("tablestore_table").(string)
+
+	return err
+}
+
+func (b *Backend) getOSSEndpointByRegion(access_key, secret_key, security_token, region string) (*location.DescribeEndpointsResponse, error) {
+	args := location.CreateDescribeEndpointsRequest()
+	args.ServiceCode = "oss"
+	args.Id = region
+	args.Domain = "location-readonly.aliyuncs.com"
+
+	locationClient, err := location.NewClientWithOptions(region, getSdkConfig(), credentials.NewStsTokenCredential(access_key, secret_key, security_token))
+	if err != nil {
+		return nil, fmt.Errorf("unable to initialize the location client: %#v", err)
+
+	}
+	locationClient.AppendUserAgent(TerraformUA, TerraformVersion)
+	endpointsResponse, err := locationClient.DescribeEndpoints(args)
+	if err != nil {
+		return nil, fmt.Errorf("describe oss endpoint using region: %#v got an error: %#v", region, err)
+	}
+	return endpointsResponse, nil
+}
+
+func getAssumeRoleAK(accessKey, secretKey, stsToken, region, roleArn, sessionName, policy, stsEndpoint string, sessionExpiration int) (string, string, string, error) {
+	request := sts.CreateAssumeRoleRequest()
+	request.RoleArn = roleArn
+	request.RoleSessionName = sessionName
+	request.DurationSeconds = requests.NewInteger(sessionExpiration)
+	request.Policy = policy
+	request.Scheme = "https"
+
+	var client *sts.Client
+	var err error
+	if stsToken == "" {
+		client, err = sts.NewClientWithAccessKey(region, accessKey, secretKey)
+	} else {
+		client, err = sts.NewClientWithStsToken(region, accessKey, secretKey, stsToken)
+	}
+	if err != nil {
+		return "", "", "", err
+	}
+	if stsEndpoint != "" {
+		endpoints.AddEndpointMapping(region, "STS", stsEndpoint)
+	}
+	response, err := client.AssumeRole(request)
+	if err != nil {
+		return "", "", "", err
+	}
+	return response.Credentials.AccessKeyId, response.Credentials.AccessKeySecret, response.Credentials.SecurityToken, nil
+}
+
+func getSdkConfig() *sdk.Config {
+	return sdk.NewConfig().
+		WithMaxRetryTime(5).
+		WithTimeout(time.Duration(30) * time.Second).
+		WithGoRoutinePoolSize(10).
+		WithDebug(false).
+		WithHttpTransport(getTransport()).
+		WithScheme("HTTPS")
+}
+
+func getTransport() *http.Transport {
+	handshakeTimeout, err := strconv.Atoi(os.Getenv("TLSHandshakeTimeout"))
+	if err != nil {
+		handshakeTimeout = 120
+	}
+	transport := cleanhttp.DefaultTransport()
+	transport.TLSHandshakeTimeout = time.Duration(handshakeTimeout) * time.Second
+	transport.Proxy = http.ProxyFromEnvironment
+	return transport
+}
+
+type Invoker struct {
+	catchers []*Catcher
+}
+
+type Catcher struct {
+	Reason           string
+	RetryCount       int
+	RetryWaitSeconds int
+}
+
+const TerraformUA = "HashiCorp-Terraform"
+
+var TerraformVersion = strings.TrimSuffix(version.String(), "-dev")
+var ClientErrorCatcher = Catcher{"AliyunGoClientFailure", 10, 3}
+var ServiceBusyCatcher = Catcher{"ServiceUnavailable", 10, 3}
+
+func NewInvoker() Invoker {
+	i := Invoker{}
+	i.AddCatcher(ClientErrorCatcher)
+	i.AddCatcher(ServiceBusyCatcher)
+	return i
+}
+
+func (a *Invoker) AddCatcher(catcher Catcher) {
+	a.catchers = append(a.catchers, &catcher)
+}
+
+func (a *Invoker) Run(f func() error) error {
+	err := f()
+
+	if err == nil {
+		return nil
+	}
+
+	for _, catcher := range a.catchers {
+		if strings.Contains(err.Error(), catcher.Reason) {
+			catcher.RetryCount--
+
+			if catcher.RetryCount <= 0 {
+				return fmt.Errorf("retry timeout and got an error: %#v", err)
+			} else {
+				time.Sleep(time.Duration(catcher.RetryWaitSeconds) * time.Second)
+				return a.Run(f)
+			}
+		}
+	}
+	return err
+}
+
+var providerConfig map[string]interface{}
+
+func getConfigFromProfile(d *schema.ResourceData, ProfileKey string) (interface{}, error) {
+
+	if providerConfig == nil {
+		if v, ok := d.GetOk("profile"); !ok || v.(string) == "" {
+			return nil, nil
+		}
+		current := d.Get("profile").(string)
+		// Set CredsFilename, expanding home directory
+		profilePath, err := homedir.Expand(d.Get("shared_credentials_file").(string))
+		if err != nil {
+			return nil, err
+		}
+		if profilePath == "" {
+			profilePath = fmt.Sprintf("%s/.aliyun/config.json", os.Getenv("HOME"))
+			if runtime.GOOS == "windows" {
+				profilePath = fmt.Sprintf("%s/.aliyun/config.json", os.Getenv("USERPROFILE"))
+			}
+		}
+		providerConfig = make(map[string]interface{})
+		_, err = os.Stat(profilePath)
+		if !os.IsNotExist(err) {
+			data, err := ioutil.ReadFile(profilePath)
+			if err != nil {
+				return nil, err
+			}
+			config := map[string]interface{}{}
+			err = json.Unmarshal(data, &config)
+			if err != nil {
+				return nil, err
+			}
+			for _, v := range config["profiles"].([]interface{}) {
+				if current == v.(map[string]interface{})["name"] {
+					providerConfig = v.(map[string]interface{})
+				}
+			}
+		}
+	}
+
+	mode := ""
+	if v, ok := providerConfig["mode"]; ok {
+		mode = v.(string)
+	} else {
+		return v, nil
+	}
+	switch ProfileKey {
+	case "access_key_id", "access_key_secret":
+		if mode == "EcsRamRole" {
+			return "", nil
+		}
+	case "ram_role_name":
+		if mode != "EcsRamRole" {
+			return "", nil
+		}
+	case "sts_token":
+		if mode != "StsToken" {
+			return "", nil
+		}
+	case "ram_role_arn", "ram_session_name":
+		if mode != "RamRoleArn" {
+			return "", nil
+		}
+	case "expired_seconds":
+		if mode != "RamRoleArn" {
+			return float64(0), nil
+		}
+	}
+
+	return providerConfig[ProfileKey], nil
+}
+
+var securityCredURL = "http://100.100.100.200/latest/meta-data/ram/security-credentials/"
+
+// getAuthCredentialByEcsRoleName aims to access meta to get sts credential
+// Actually, the job should be done by sdk, but currently not all resources and products support alibaba-cloud-sdk-go,
+// and their go sdk does support ecs role name.
+// This method is a temporary solution and it should be removed after all go sdk support ecs role name
+// The related PR: https://github.com/terraform-providers/terraform-provider-alicloud/pull/731
+func getAuthCredentialByEcsRoleName(ecsRoleName string) (accessKey, secretKey, token string, err error) {
+
+	if ecsRoleName == "" {
+		return
+	}
+	requestUrl := securityCredURL + ecsRoleName
+	httpRequest, err := http.NewRequest(requests.GET, requestUrl, strings.NewReader(""))
+	if err != nil {
+		err = fmt.Errorf("build sts requests err: %s", err.Error())
+		return
+	}
+	httpClient := &http.Client{}
+	httpResponse, err := httpClient.Do(httpRequest)
+	if err != nil {
+		err = fmt.Errorf("get Ecs sts token err : %s", err.Error())
+		return
+	}
+
+	response := responses.NewCommonResponse()
+	err = responses.Unmarshal(response, httpResponse, "")
+	if err != nil {
+		err = fmt.Errorf("unmarshal Ecs sts token response err : %s", err.Error())
+		return
+	}
+
+	if response.GetHttpStatus() != http.StatusOK {
+		err = fmt.Errorf("get Ecs sts token err, httpStatus: %d, message = %s", response.GetHttpStatus(), response.GetHttpContentString())
+		return
+	}
+	var data interface{}
+	err = json.Unmarshal(response.GetHttpContentBytes(), &data)
+	if err != nil {
+		err = fmt.Errorf("refresh Ecs sts token err, json.Unmarshal fail: %s", err.Error())
+		return
+	}
+	code, err := jmespath.Search("Code", data)
+	if err != nil {
+		err = fmt.Errorf("refresh Ecs sts token err, fail to get Code: %s", err.Error())
+		return
+	}
+	if code.(string) != "Success" {
+		err = fmt.Errorf("refresh Ecs sts token err, Code is not Success")
+		return
+	}
+	accessKeyId, err := jmespath.Search("AccessKeyId", data)
+	if err != nil {
+		err = fmt.Errorf("refresh Ecs sts token err, fail to get AccessKeyId: %s", err.Error())
+		return
+	}
+	accessKeySecret, err := jmespath.Search("AccessKeySecret", data)
+	if err != nil {
+		err = fmt.Errorf("refresh Ecs sts token err, fail to get AccessKeySecret: %s", err.Error())
+		return
+	}
+	securityToken, err := jmespath.Search("SecurityToken", data)
+	if err != nil {
+		err = fmt.Errorf("refresh Ecs sts token err, fail to get SecurityToken: %s", err.Error())
+		return
+	}
+
+	if accessKeyId == nil || accessKeySecret == nil || securityToken == nil {
+		err = fmt.Errorf("there is no any available accesskey, secret and security token for Ecs role %s", ecsRoleName)
+		return
+	}
+
+	return accessKeyId.(string), accessKeySecret.(string), securityToken.(string), nil
+}
+
+func getHttpProxyUrl() *url.URL {
+	for _, v := range []string{"HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy"} {
+		value := strings.Trim(os.Getenv(v), " ")
+		if value != "" {
+			if !regexp.MustCompile(`^http(s)?://`).MatchString(value) {
+				value = fmt.Sprintf("https://%s", value)
+			}
+			proxyUrl, err := url.Parse(value)
+			if err == nil {
+				return proxyUrl
+			}
+			break
+		}
+	}
+	return nil
+}
diff --git a/v1.5.7/internal/backend/remote-state/oss/backend_state.go b/v1.5.7/internal/backend/remote-state/oss/backend_state.go
new file mode 100644
index 0000000..fc32a7b
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/oss/backend_state.go
@@ -0,0 +1,200 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package oss
+
+import (
+	"errors"
+	"fmt"
+	"log"
+	"path"
+	"sort"
+	"strings"
+
+	"github.com/aliyun/aliyun-oss-go-sdk/oss"
+	"github.com/aliyun/aliyun-tablestore-go-sdk/tablestore"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+const (
+	lockFileSuffix = ".tflock"
+)
+
+// get a remote client configured for this state
+func (b *Backend) remoteClient(name string) (*RemoteClient, error) {
+	if name == "" {
+		return nil, errors.New("missing state name")
+	}
+
+	client := &RemoteClient{
+		ossClient:            b.ossClient,
+		bucketName:           b.bucketName,
+		stateFile:            b.stateFile(name),
+		lockFile:             b.lockFile(name),
+		serverSideEncryption: b.serverSideEncryption,
+		acl:                  b.acl,
+		otsTable:             b.otsTable,
+		otsClient:            b.otsClient,
+	}
+	if b.otsEndpoint != "" && b.otsTable != "" {
+		_, err := b.otsClient.DescribeTable(&tablestore.DescribeTableRequest{
+			TableName: b.otsTable,
+		})
+		if err != nil {
+			return client, fmt.Errorf("error describing table store %s: %#v", b.otsTable, err)
+		}
+	}
+
+	return client, nil
+}
+
+func (b *Backend) Workspaces() ([]string, error) {
+	bucket, err := b.ossClient.Bucket(b.bucketName)
+	if err != nil {
+		return []string{""}, fmt.Errorf("error getting bucket: %#v", err)
+	}
+
+	var options []oss.Option
+	options = append(options, oss.Prefix(b.statePrefix+"/"), oss.MaxKeys(1000))
+	resp, err := bucket.ListObjects(options...)
+	if err != nil {
+		return nil, err
+	}
+
+	result := []string{backend.DefaultStateName}
+	prefix := b.statePrefix
+	lastObj := ""
+	for {
+		for _, obj := range resp.Objects {
+			// we have 3 parts, the state prefix, the workspace name, and the state file: <prefix>/<worksapce-name>/<key>
+			if path.Join(b.statePrefix, b.stateKey) == obj.Key {
+				// filter the default workspace
+				continue
+			}
+			lastObj = obj.Key
+			parts := strings.Split(strings.TrimPrefix(obj.Key, prefix+"/"), "/")
+			if len(parts) > 0 && parts[0] != "" {
+				result = append(result, parts[0])
+			}
+		}
+		if resp.IsTruncated {
+			if len(options) == 3 {
+				options[2] = oss.Marker(lastObj)
+			} else {
+				options = append(options, oss.Marker(lastObj))
+			}
+			resp, err = bucket.ListObjects(options...)
+			if err != nil {
+				return nil, err
+			}
+		} else {
+			break
+		}
+	}
+	sort.Strings(result[1:])
+	return result, nil
+}
+
+func (b *Backend) DeleteWorkspace(name string, _ bool) error {
+	if name == backend.DefaultStateName || name == "" {
+		return fmt.Errorf("can't delete default state")
+	}
+
+	client, err := b.remoteClient(name)
+	if err != nil {
+		return err
+	}
+	return client.Delete()
+}
+
+func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
+	client, err := b.remoteClient(name)
+	if err != nil {
+		return nil, err
+	}
+	stateMgr := &remote.State{Client: client}
+
+	// Check to see if this state already exists.
+	existing, err := b.Workspaces()
+	if err != nil {
+		return nil, err
+	}
+
+	log.Printf("[DEBUG] Current workspace name: %s. All workspaces:%#v", name, existing)
+
+	exists := false
+	for _, s := range existing {
+		if s == name {
+			exists = true
+			break
+		}
+	}
+	// We need to create the object so it's listed by States.
+	if !exists {
+		// take a lock on this state while we write it
+		lockInfo := statemgr.NewLockInfo()
+		lockInfo.Operation = "init"
+		lockId, err := client.Lock(lockInfo)
+		if err != nil {
+			return nil, fmt.Errorf("failed to lock OSS state: %s", err)
+		}
+
+		// Local helper function so we can call it multiple places
+		lockUnlock := func(e error) error {
+			if err := stateMgr.Unlock(lockId); err != nil {
+				return fmt.Errorf(strings.TrimSpace(stateUnlockError), lockId, err)
+			}
+			return e
+		}
+
+		// Grab the value
+		if err := stateMgr.RefreshState(); err != nil {
+			err = lockUnlock(err)
+			return nil, err
+		}
+
+		// If we have no state, we have to create an empty state
+		if v := stateMgr.State(); v == nil {
+			if err := stateMgr.WriteState(states.NewState()); err != nil {
+				err = lockUnlock(err)
+				return nil, err
+			}
+			if err := stateMgr.PersistState(nil); err != nil {
+				err = lockUnlock(err)
+				return nil, err
+			}
+		}
+
+		// Unlock, the state should now be initialized
+		if err := lockUnlock(nil); err != nil {
+			return nil, err
+		}
+
+	}
+	return stateMgr, nil
+}
+
+func (b *Backend) stateFile(name string) string {
+	if name == backend.DefaultStateName {
+		return path.Join(b.statePrefix, b.stateKey)
+	}
+	return path.Join(b.statePrefix, name, b.stateKey)
+}
+
+func (b *Backend) lockFile(name string) string {
+	return b.stateFile(name) + lockFileSuffix
+}
+
+const stateUnlockError = `
+Error unlocking Alibaba Cloud OSS state file:
+
+Lock ID: %s
+Error message: %#v
+
+You may have to force-unlock this state in order to use it again.
+The Alibaba Cloud backend acquires a lock during initialization to ensure the initial state file is created.
+`
diff --git a/v1.5.7/internal/backend/remote-state/oss/backend_test.go b/v1.5.7/internal/backend/remote-state/oss/backend_test.go
new file mode 100644
index 0000000..3018af3
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/oss/backend_test.go
@@ -0,0 +1,253 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package oss
+
+import (
+	"fmt"
+	"math/rand"
+	"os"
+	"testing"
+	"time"
+
+	"strings"
+
+	"github.com/aliyun/aliyun-oss-go-sdk/oss"
+	"github.com/aliyun/aliyun-tablestore-go-sdk/tablestore"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+)
+
+// verify that we are doing ACC tests or the OSS tests specifically
+func testACC(t *testing.T) {
+	skip := os.Getenv("TF_ACC") == "" && os.Getenv("TF_OSS_TEST") == ""
+	if skip {
+		t.Log("oss backend tests require setting TF_ACC or TF_OSS_TEST")
+		t.Skip()
+	}
+	if skip {
+		t.Fatal("oss backend tests require setting ALICLOUD_ACCESS_KEY or ALICLOUD_ACCESS_KEY_ID")
+	}
+	if os.Getenv("ALICLOUD_REGION") == "" {
+		os.Setenv("ALICLOUD_REGION", "cn-beijing")
+	}
+}
+
+func TestBackend_impl(t *testing.T) {
+	var _ backend.Backend = new(Backend)
+}
+
+func TestBackendConfig(t *testing.T) {
+	testACC(t)
+	config := map[string]interface{}{
+		"region":              "cn-beijing",
+		"bucket":              "terraform-backend-oss-test",
+		"prefix":              "mystate",
+		"key":                 "first.tfstate",
+		"tablestore_endpoint": "https://terraformstate.cn-beijing.ots.aliyuncs.com",
+		"tablestore_table":    "TableStore",
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(config)).(*Backend)
+
+	if !strings.HasPrefix(b.ossClient.Config.Endpoint, "https://oss-cn-beijing") {
+		t.Fatalf("Incorrect region was provided")
+	}
+	if b.bucketName != "terraform-backend-oss-test" {
+		t.Fatalf("Incorrect bucketName was provided")
+	}
+	if b.statePrefix != "mystate" {
+		t.Fatalf("Incorrect state file path was provided")
+	}
+	if b.stateKey != "first.tfstate" {
+		t.Fatalf("Incorrect keyName was provided")
+	}
+
+	if b.ossClient.Config.AccessKeyID == "" {
+		t.Fatalf("No Access Key Id was provided")
+	}
+	if b.ossClient.Config.AccessKeySecret == "" {
+		t.Fatalf("No Secret Access Key was provided")
+	}
+}
+
+func TestBackendConfigWorkSpace(t *testing.T) {
+	testACC(t)
+	bucketName := fmt.Sprintf("terraform-backend-oss-test-%d", rand.Intn(1000))
+	config := map[string]interface{}{
+		"region":              "cn-beijing",
+		"bucket":              bucketName,
+		"prefix":              "mystate",
+		"key":                 "first.tfstate",
+		"tablestore_endpoint": "https://terraformstate.cn-beijing.ots.aliyuncs.com",
+		"tablestore_table":    "TableStore",
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(config)).(*Backend)
+	createOSSBucket(t, b.ossClient, bucketName)
+	defer deleteOSSBucket(t, b.ossClient, bucketName)
+	if _, err := b.Workspaces(); err != nil {
+		t.Fatal(err.Error())
+	}
+	if !strings.HasPrefix(b.ossClient.Config.Endpoint, "https://oss-cn-beijing") {
+		t.Fatalf("Incorrect region was provided")
+	}
+	if b.bucketName != bucketName {
+		t.Fatalf("Incorrect bucketName was provided")
+	}
+	if b.statePrefix != "mystate" {
+		t.Fatalf("Incorrect state file path was provided")
+	}
+	if b.stateKey != "first.tfstate" {
+		t.Fatalf("Incorrect keyName was provided")
+	}
+
+	if b.ossClient.Config.AccessKeyID == "" {
+		t.Fatalf("No Access Key Id was provided")
+	}
+	if b.ossClient.Config.AccessKeySecret == "" {
+		t.Fatalf("No Secret Access Key was provided")
+	}
+}
+
+func TestBackendConfigProfile(t *testing.T) {
+	testACC(t)
+	config := map[string]interface{}{
+		"region":              "cn-beijing",
+		"bucket":              "terraform-backend-oss-test",
+		"prefix":              "mystate",
+		"key":                 "first.tfstate",
+		"tablestore_endpoint": "https://terraformstate.cn-beijing.ots.aliyuncs.com",
+		"tablestore_table":    "TableStore",
+		"profile":             "default",
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(config)).(*Backend)
+
+	if !strings.HasPrefix(b.ossClient.Config.Endpoint, "https://oss-cn-beijing") {
+		t.Fatalf("Incorrect region was provided")
+	}
+	if b.bucketName != "terraform-backend-oss-test" {
+		t.Fatalf("Incorrect bucketName was provided")
+	}
+	if b.statePrefix != "mystate" {
+		t.Fatalf("Incorrect state file path was provided")
+	}
+	if b.stateKey != "first.tfstate" {
+		t.Fatalf("Incorrect keyName was provided")
+	}
+
+	if b.ossClient.Config.AccessKeyID == "" {
+		t.Fatalf("No Access Key Id was provided")
+	}
+	if b.ossClient.Config.AccessKeySecret == "" {
+		t.Fatalf("No Secret Access Key was provided")
+	}
+}
+
+func TestBackendConfig_invalidKey(t *testing.T) {
+	testACC(t)
+	cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{
+		"region":              "cn-beijing",
+		"bucket":              "terraform-backend-oss-test",
+		"prefix":              "/leading-slash",
+		"name":                "/test.tfstate",
+		"tablestore_endpoint": "https://terraformstate.cn-beijing.ots.aliyuncs.com",
+		"tablestore_table":    "TableStore",
+	})
+
+	_, results := New().PrepareConfig(cfg)
+	if !results.HasErrors() {
+		t.Fatal("expected config validation error")
+	}
+}
+
+func TestBackend(t *testing.T) {
+	testACC(t)
+
+	bucketName := fmt.Sprintf("terraform-remote-oss-test-%x", time.Now().Unix())
+	statePrefix := "multi/level/path/"
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket": bucketName,
+		"prefix": statePrefix,
+	})).(*Backend)
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket": bucketName,
+		"prefix": statePrefix,
+	})).(*Backend)
+
+	createOSSBucket(t, b1.ossClient, bucketName)
+	defer deleteOSSBucket(t, b1.ossClient, bucketName)
+
+	backend.TestBackendStates(t, b1)
+	backend.TestBackendStateLocks(t, b1, b2)
+	backend.TestBackendStateForceUnlock(t, b1, b2)
+}
+
+func createOSSBucket(t *testing.T, ossClient *oss.Client, bucketName string) {
+	// Be clear about what we're doing in case the user needs to clean this up later.
+	if err := ossClient.CreateBucket(bucketName); err != nil {
+		t.Fatal("failed to create test OSS bucket:", err)
+	}
+}
+
+func deleteOSSBucket(t *testing.T, ossClient *oss.Client, bucketName string) {
+	warning := "WARNING: Failed to delete the test OSS bucket. It may have been left in your Alibaba Cloud account and may incur storage charges. (error was %s)"
+
+	// first we have to get rid of the env objects, or we can't delete the bucket
+	bucket, err := ossClient.Bucket(bucketName)
+	if err != nil {
+		t.Fatal("Error getting bucket:", err)
+		return
+	}
+	objects, err := bucket.ListObjects()
+	if err != nil {
+		t.Logf(warning, err)
+		return
+	}
+	for _, obj := range objects.Objects {
+		if err := bucket.DeleteObject(obj.Key); err != nil {
+			// this will need cleanup no matter what, so just warn and exit
+			t.Logf(warning, err)
+			return
+		}
+	}
+
+	if err := ossClient.DeleteBucket(bucketName); err != nil {
+		t.Logf(warning, err)
+	}
+}
+
+// create the tablestore table, and wait until we can query it.
+func createTablestoreTable(t *testing.T, otsClient *tablestore.TableStoreClient, tableName string) {
+	tableMeta := new(tablestore.TableMeta)
+	tableMeta.TableName = tableName
+	tableMeta.AddPrimaryKeyColumn(pkName, tablestore.PrimaryKeyType_STRING)
+
+	tableOption := new(tablestore.TableOption)
+	tableOption.TimeToAlive = -1
+	tableOption.MaxVersion = 1
+
+	reservedThroughput := new(tablestore.ReservedThroughput)
+
+	_, err := otsClient.CreateTable(&tablestore.CreateTableRequest{
+		TableMeta:          tableMeta,
+		TableOption:        tableOption,
+		ReservedThroughput: reservedThroughput,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func deleteTablestoreTable(t *testing.T, otsClient *tablestore.TableStoreClient, tableName string) {
+	params := &tablestore.DeleteTableRequest{
+		TableName: tableName,
+	}
+	_, err := otsClient.DeleteTable(params)
+	if err != nil {
+		t.Logf("WARNING: Failed to delete the test TableStore table %q. It has been left in your Alibaba Cloud account and may incur charges. (error was %s)", tableName, err)
+	}
+}
diff --git a/v1.5.7/internal/backend/remote-state/oss/client.go b/v1.5.7/internal/backend/remote-state/oss/client.go
new file mode 100644
index 0000000..61bcac2
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/oss/client.go
@@ -0,0 +1,452 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package oss
+
+import (
+	"bytes"
+	"crypto/md5"
+	"encoding/hex"
+	"encoding/json"
+	"fmt"
+	"io"
+	"log"
+	"time"
+
+	"github.com/aliyun/aliyun-oss-go-sdk/oss"
+	"github.com/aliyun/aliyun-tablestore-go-sdk/tablestore"
+	"github.com/hashicorp/go-multierror"
+	uuid "github.com/hashicorp/go-uuid"
+	"github.com/pkg/errors"
+
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+const (
+	// Store the last saved serial in tablestore with this suffix for consistency checks.
+	stateIDSuffix = "-md5"
+
+	pkName = "LockID"
+)
+
+var (
+	// The amount of time we will retry a state waiting for it to match the
+	// expected checksum.
+	consistencyRetryTimeout = 10 * time.Second
+
+	// delay when polling the state
+	consistencyRetryPollInterval = 2 * time.Second
+)
+
+// test hook called when checksums don't match
+var testChecksumHook func()
+
+type RemoteClient struct {
+	ossClient            *oss.Client
+	otsClient            *tablestore.TableStoreClient
+	bucketName           string
+	stateFile            string
+	lockFile             string
+	serverSideEncryption bool
+	acl                  string
+	otsTable             string
+}
+
+func (c *RemoteClient) Get() (payload *remote.Payload, err error) {
+	deadline := time.Now().Add(consistencyRetryTimeout)
+
+	// If we have a checksum, and the returned payload doesn't match, we retry
+	// up until deadline.
+	for {
+		payload, err = c.getObj()
+		if err != nil {
+			return nil, err
+		}
+
+		// If the remote state was manually removed the payload will be nil,
+		// but if there's still a digest entry for that state we will still try
+		// to compare the MD5 below.
+		var digest []byte
+		if payload != nil {
+			digest = payload.MD5
+		}
+
+		// verify that this state is what we expect
+		if expected, err := c.getMD5(); err != nil {
+			log.Printf("[WARN] failed to fetch state md5: %s", err)
+		} else if len(expected) > 0 && !bytes.Equal(expected, digest) {
+			log.Printf("[WARN] state md5 mismatch: expected '%x', got '%x'", expected, digest)
+
+			if testChecksumHook != nil {
+				testChecksumHook()
+			}
+
+			if time.Now().Before(deadline) {
+				time.Sleep(consistencyRetryPollInterval)
+				log.Println("[INFO] retrying OSS RemoteClient.Get...")
+				continue
+			}
+
+			return nil, fmt.Errorf(errBadChecksumFmt, digest)
+		}
+
+		break
+	}
+	return payload, nil
+}
+
+func (c *RemoteClient) Put(data []byte) error {
+	bucket, err := c.ossClient.Bucket(c.bucketName)
+	if err != nil {
+		return fmt.Errorf("error getting bucket: %#v", err)
+	}
+
+	body := bytes.NewReader(data)
+
+	var options []oss.Option
+	if c.acl != "" {
+		options = append(options, oss.ACL(oss.ACLType(c.acl)))
+	}
+	options = append(options, oss.ContentType("application/json"))
+	if c.serverSideEncryption {
+		options = append(options, oss.ServerSideEncryption("AES256"))
+	}
+	options = append(options, oss.ContentLength(int64(len(data))))
+
+	if body != nil {
+		if err := bucket.PutObject(c.stateFile, body, options...); err != nil {
+			return fmt.Errorf("failed to upload state %s: %#v", c.stateFile, err)
+		}
+	}
+
+	sum := md5.Sum(data)
+	if err := c.putMD5(sum[:]); err != nil {
+		// if this errors out, we unfortunately have to error out altogether,
+		// since the next Get will inevitably fail.
+		return fmt.Errorf("failed to store state MD5: %s", err)
+	}
+	return nil
+}
+
+func (c *RemoteClient) Delete() error {
+	bucket, err := c.ossClient.Bucket(c.bucketName)
+	if err != nil {
+		return fmt.Errorf("error getting bucket %s: %#v", c.bucketName, err)
+	}
+
+	log.Printf("[DEBUG] Deleting remote state from OSS: %#v", c.stateFile)
+
+	if err := bucket.DeleteObject(c.stateFile); err != nil {
+		return fmt.Errorf("error deleting state %s: %#v", c.stateFile, err)
+	}
+
+	if err := c.deleteMD5(); err != nil {
+		log.Printf("[WARN] Error deleting state MD5: %s", err)
+	}
+	return nil
+}
+
+func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
+	if c.otsTable == "" {
+		return "", nil
+	}
+
+	info.Path = c.lockPath()
+
+	if info.ID == "" {
+		lockID, err := uuid.GenerateUUID()
+		if err != nil {
+			return "", err
+		}
+		info.ID = lockID
+	}
+
+	putParams := &tablestore.PutRowChange{
+		TableName: c.otsTable,
+		PrimaryKey: &tablestore.PrimaryKey{
+			PrimaryKeys: []*tablestore.PrimaryKeyColumn{
+				{
+					ColumnName: pkName,
+					Value:      c.lockPath(),
+				},
+			},
+		},
+		Columns: []tablestore.AttributeColumn{
+			{
+				ColumnName: "Info",
+				Value:      string(info.Marshal()),
+			},
+		},
+		Condition: &tablestore.RowCondition{
+			RowExistenceExpectation: tablestore.RowExistenceExpectation_EXPECT_NOT_EXIST,
+		},
+	}
+
+	log.Printf("[DEBUG] Recording state lock in tablestore: %#v; LOCKID:%s", putParams, c.lockPath())
+
+	_, err := c.otsClient.PutRow(&tablestore.PutRowRequest{
+		PutRowChange: putParams,
+	})
+	if err != nil {
+		err = fmt.Errorf("invoking PutRow got an error: %#v", err)
+		lockInfo, infoErr := c.getLockInfo()
+		if infoErr != nil {
+			err = multierror.Append(err, fmt.Errorf("\ngetting lock info got an error: %#v", infoErr))
+		}
+		lockErr := &statemgr.LockError{
+			Err:  err,
+			Info: lockInfo,
+		}
+		log.Printf("[ERROR] state lock error: %s", lockErr.Error())
+		return "", lockErr
+	}
+
+	return info.ID, nil
+}
+
+func (c *RemoteClient) getMD5() ([]byte, error) {
+	if c.otsTable == "" {
+		return nil, nil
+	}
+
+	getParams := &tablestore.SingleRowQueryCriteria{
+		TableName: c.otsTable,
+		PrimaryKey: &tablestore.PrimaryKey{
+			PrimaryKeys: []*tablestore.PrimaryKeyColumn{
+				{
+					ColumnName: pkName,
+					Value:      c.lockPath() + stateIDSuffix,
+				},
+			},
+		},
+		ColumnsToGet: []string{pkName, "Digest"},
+		MaxVersion:   1,
+	}
+
+	log.Printf("[DEBUG] Retrieving state serial in tablestore: %#v", getParams)
+
+	object, err := c.otsClient.GetRow(&tablestore.GetRowRequest{
+		SingleRowQueryCriteria: getParams,
+	})
+
+	if err != nil {
+		return nil, err
+	}
+
+	var val string
+	if v, ok := object.GetColumnMap().Columns["Digest"]; ok && len(v) > 0 {
+		val = v[0].Value.(string)
+	}
+
+	sum, err := hex.DecodeString(val)
+	if err != nil || len(sum) != md5.Size {
+		return nil, errors.New("invalid md5")
+	}
+
+	return sum, nil
+}
+
+// store the hash of the state to that clients can check for stale state files.
+func (c *RemoteClient) putMD5(sum []byte) error {
+	if c.otsTable == "" {
+		return nil
+	}
+
+	if len(sum) != md5.Size {
+		return errors.New("invalid payload md5")
+	}
+
+	putParams := &tablestore.PutRowChange{
+		TableName: c.otsTable,
+		PrimaryKey: &tablestore.PrimaryKey{
+			PrimaryKeys: []*tablestore.PrimaryKeyColumn{
+				{
+					ColumnName: pkName,
+					Value:      c.lockPath() + stateIDSuffix,
+				},
+			},
+		},
+		Columns: []tablestore.AttributeColumn{
+			{
+				ColumnName: "Digest",
+				Value:      hex.EncodeToString(sum),
+			},
+		},
+		Condition: &tablestore.RowCondition{
+			RowExistenceExpectation: tablestore.RowExistenceExpectation_IGNORE,
+		},
+	}
+
+	log.Printf("[DEBUG] Recoring state serial in tablestore: %#v", putParams)
+
+	_, err := c.otsClient.PutRow(&tablestore.PutRowRequest{
+		PutRowChange: putParams,
+	})
+
+	if err != nil {
+		log.Printf("[WARN] failed to record state serial in tablestore: %s", err)
+	}
+
+	return nil
+}
+
+// remove the hash value for a deleted state
+func (c *RemoteClient) deleteMD5() error {
+	if c.otsTable == "" {
+		return nil
+	}
+
+	params := &tablestore.DeleteRowRequest{
+		DeleteRowChange: &tablestore.DeleteRowChange{
+			TableName: c.otsTable,
+			PrimaryKey: &tablestore.PrimaryKey{
+				PrimaryKeys: []*tablestore.PrimaryKeyColumn{
+					{
+						ColumnName: pkName,
+						Value:      c.lockPath() + stateIDSuffix,
+					},
+				},
+			},
+			Condition: &tablestore.RowCondition{
+				RowExistenceExpectation: tablestore.RowExistenceExpectation_EXPECT_EXIST,
+			},
+		},
+	}
+
+	log.Printf("[DEBUG] Deleting state serial in tablestore: %#v", params)
+
+	if _, err := c.otsClient.DeleteRow(params); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c *RemoteClient) getLockInfo() (*statemgr.LockInfo, error) {
+	getParams := &tablestore.SingleRowQueryCriteria{
+		TableName: c.otsTable,
+		PrimaryKey: &tablestore.PrimaryKey{
+			PrimaryKeys: []*tablestore.PrimaryKeyColumn{
+				{
+					ColumnName: pkName,
+					Value:      c.lockPath(),
+				},
+			},
+		},
+		ColumnsToGet: []string{pkName, "Info"},
+		MaxVersion:   1,
+	}
+
+	log.Printf("[DEBUG] Retrieving state lock info from tablestore: %#v", getParams)
+
+	object, err := c.otsClient.GetRow(&tablestore.GetRowRequest{
+		SingleRowQueryCriteria: getParams,
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	var infoData string
+	if v, ok := object.GetColumnMap().Columns["Info"]; ok && len(v) > 0 {
+		infoData = v[0].Value.(string)
+	}
+	lockInfo := &statemgr.LockInfo{}
+	err = json.Unmarshal([]byte(infoData), lockInfo)
+	if err != nil {
+		return nil, err
+	}
+	return lockInfo, nil
+}
+func (c *RemoteClient) Unlock(id string) error {
+	if c.otsTable == "" {
+		return nil
+	}
+
+	lockErr := &statemgr.LockError{}
+
+	lockInfo, err := c.getLockInfo()
+	if err != nil {
+		lockErr.Err = fmt.Errorf("failed to retrieve lock info: %s", err)
+		return lockErr
+	}
+	lockErr.Info = lockInfo
+
+	if lockInfo.ID != id {
+		lockErr.Err = fmt.Errorf("lock id %q does not match existing lock", id)
+		return lockErr
+	}
+	params := &tablestore.DeleteRowRequest{
+		DeleteRowChange: &tablestore.DeleteRowChange{
+			TableName: c.otsTable,
+			PrimaryKey: &tablestore.PrimaryKey{
+				PrimaryKeys: []*tablestore.PrimaryKeyColumn{
+					{
+						ColumnName: pkName,
+						Value:      c.lockPath(),
+					},
+				},
+			},
+			Condition: &tablestore.RowCondition{
+				RowExistenceExpectation: tablestore.RowExistenceExpectation_IGNORE,
+			},
+		},
+	}
+
+	_, err = c.otsClient.DeleteRow(params)
+
+	if err != nil {
+		lockErr.Err = err
+		return lockErr
+	}
+
+	return nil
+}
+
+func (c *RemoteClient) lockPath() string {
+	return fmt.Sprintf("%s/%s", c.bucketName, c.stateFile)
+}
+
+func (c *RemoteClient) getObj() (*remote.Payload, error) {
+	bucket, err := c.ossClient.Bucket(c.bucketName)
+	if err != nil {
+		return nil, fmt.Errorf("error getting bucket %s: %#v", c.bucketName, err)
+	}
+
+	if exist, err := bucket.IsObjectExist(c.stateFile); err != nil {
+		return nil, fmt.Errorf("estimating object %s is exist got an error: %#v", c.stateFile, err)
+	} else if !exist {
+		return nil, nil
+	}
+
+	var options []oss.Option
+	output, err := bucket.GetObject(c.stateFile, options...)
+	if err != nil {
+		return nil, fmt.Errorf("error getting object: %#v", err)
+	}
+
+	buf := bytes.NewBuffer(nil)
+	if _, err := io.Copy(buf, output); err != nil {
+		return nil, fmt.Errorf("failed to read remote state: %s", err)
+	}
+	sum := md5.Sum(buf.Bytes())
+	payload := &remote.Payload{
+		Data: buf.Bytes(),
+		MD5:  sum[:],
+	}
+
+	// If there was no data, then return nil
+	if len(payload.Data) == 0 {
+		return nil, nil
+	}
+
+	return payload, nil
+}
+
+const errBadChecksumFmt = `state data in OSS does not have the expected content.
+
+This may be caused by unusually long delays in OSS processing a previous state
+update.  Please wait for a minute or two and try again. If this problem
+persists, and neither OSS nor TableStore are experiencing an outage, you may need
+to manually verify the remote state and update the Digest value stored in the
+TableStore table to the following value: %x`
diff --git a/v1.5.7/internal/backend/remote-state/oss/client_test.go b/v1.5.7/internal/backend/remote-state/oss/client_test.go
new file mode 100644
index 0000000..83957f5
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/oss/client_test.go
@@ -0,0 +1,380 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package oss
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+	"time"
+
+	"bytes"
+	"crypto/md5"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+// NOTE: Before running this testcase, please create a OTS instance called 'tf-oss-remote'
+var RemoteTestUsedOTSEndpoint = "https://tf-oss-remote.cn-hangzhou.ots.aliyuncs.com"
+
+func TestRemoteClient_impl(t *testing.T) {
+	var _ remote.Client = new(RemoteClient)
+	var _ remote.ClientLocker = new(RemoteClient)
+}
+
+func TestRemoteClient(t *testing.T) {
+	testACC(t)
+	bucketName := fmt.Sprintf("tf-remote-oss-test-%x", time.Now().Unix())
+	path := "testState"
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":  bucketName,
+		"prefix":  path,
+		"encrypt": true,
+	})).(*Backend)
+
+	createOSSBucket(t, b.ossClient, bucketName)
+	defer deleteOSSBucket(t, b.ossClient, bucketName)
+
+	state, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestClient(t, state.(*remote.State).Client)
+}
+
+func TestRemoteClientLocks(t *testing.T) {
+	testACC(t)
+	bucketName := fmt.Sprintf("tf-remote-oss-test-%x", time.Now().Unix())
+	tableName := fmt.Sprintf("tfRemoteTestForce%x", time.Now().Unix())
+	path := "testState"
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":              bucketName,
+		"prefix":              path,
+		"encrypt":             true,
+		"tablestore_table":    tableName,
+		"tablestore_endpoint": RemoteTestUsedOTSEndpoint,
+	})).(*Backend)
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":              bucketName,
+		"prefix":              path,
+		"encrypt":             true,
+		"tablestore_table":    tableName,
+		"tablestore_endpoint": RemoteTestUsedOTSEndpoint,
+	})).(*Backend)
+
+	createOSSBucket(t, b1.ossClient, bucketName)
+	defer deleteOSSBucket(t, b1.ossClient, bucketName)
+	createTablestoreTable(t, b1.otsClient, tableName)
+	defer deleteTablestoreTable(t, b1.otsClient, tableName)
+
+	s1, err := b1.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	s2, err := b2.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestRemoteLocks(t, s1.(*remote.State).Client, s2.(*remote.State).Client)
+}
+
+// verify that the backend can handle more than one state in the same table
+func TestRemoteClientLocks_multipleStates(t *testing.T) {
+	testACC(t)
+	bucketName := fmt.Sprintf("tf-remote-oss-test-force-%x", time.Now().Unix())
+	tableName := fmt.Sprintf("tfRemoteTestForce%x", time.Now().Unix())
+	path := "testState"
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":              bucketName,
+		"prefix":              path,
+		"encrypt":             true,
+		"tablestore_table":    tableName,
+		"tablestore_endpoint": RemoteTestUsedOTSEndpoint,
+	})).(*Backend)
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":              bucketName,
+		"prefix":              path,
+		"encrypt":             true,
+		"tablestore_table":    tableName,
+		"tablestore_endpoint": RemoteTestUsedOTSEndpoint,
+	})).(*Backend)
+
+	createOSSBucket(t, b1.ossClient, bucketName)
+	defer deleteOSSBucket(t, b1.ossClient, bucketName)
+	createTablestoreTable(t, b1.otsClient, tableName)
+	defer deleteTablestoreTable(t, b1.otsClient, tableName)
+
+	s1, err := b1.StateMgr("s1")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if _, err := s1.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatal("failed to get lock for s1:", err)
+	}
+
+	// s1 is now locked, s2 should not be locked as it's a different state file
+	s2, err := b2.StateMgr("s2")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if _, err := s2.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatal("failed to get lock for s2:", err)
+	}
+}
+
+// verify that we can unlock a state with an existing lock
+func TestRemoteForceUnlock(t *testing.T) {
+	testACC(t)
+	bucketName := fmt.Sprintf("tf-remote-oss-test-force-%x", time.Now().Unix())
+	tableName := fmt.Sprintf("tfRemoteTestForce%x", time.Now().Unix())
+	path := "testState"
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":              bucketName,
+		"prefix":              path,
+		"encrypt":             true,
+		"tablestore_table":    tableName,
+		"tablestore_endpoint": RemoteTestUsedOTSEndpoint,
+	})).(*Backend)
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":              bucketName,
+		"prefix":              path,
+		"encrypt":             true,
+		"tablestore_table":    tableName,
+		"tablestore_endpoint": RemoteTestUsedOTSEndpoint,
+	})).(*Backend)
+
+	createOSSBucket(t, b1.ossClient, bucketName)
+	defer deleteOSSBucket(t, b1.ossClient, bucketName)
+	createTablestoreTable(t, b1.otsClient, tableName)
+	defer deleteTablestoreTable(t, b1.otsClient, tableName)
+
+	// first test with default
+	s1, err := b1.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	info := statemgr.NewLockInfo()
+	info.Operation = "test"
+	info.Who = "clientA"
+
+	lockID, err := s1.Lock(info)
+	if err != nil {
+		t.Fatal("unable to get initial lock:", err)
+	}
+
+	// s1 is now locked, get the same state through s2 and unlock it
+	s2, err := b2.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal("failed to get default state to force unlock:", err)
+	}
+
+	if err := s2.Unlock(lockID); err != nil {
+		t.Fatal("failed to force-unlock default state")
+	}
+
+	// now try the same thing with a named state
+	// first test with default
+	s1, err = b1.StateMgr("test")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	info = statemgr.NewLockInfo()
+	info.Operation = "test"
+	info.Who = "clientA"
+
+	lockID, err = s1.Lock(info)
+	if err != nil {
+		t.Fatal("unable to get initial lock:", err)
+	}
+
+	// s1 is now locked, get the same state through s2 and unlock it
+	s2, err = b2.StateMgr("test")
+	if err != nil {
+		t.Fatal("failed to get named state to force unlock:", err)
+	}
+
+	if err = s2.Unlock(lockID); err != nil {
+		t.Fatal("failed to force-unlock named state")
+	}
+}
+
+func TestRemoteClient_clientMD5(t *testing.T) {
+	testACC(t)
+
+	bucketName := fmt.Sprintf("tf-remote-oss-test-%x", time.Now().Unix())
+	tableName := fmt.Sprintf("tfRemoteTestForce%x", time.Now().Unix())
+	path := "testState"
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":              bucketName,
+		"prefix":              path,
+		"tablestore_table":    tableName,
+		"tablestore_endpoint": RemoteTestUsedOTSEndpoint,
+	})).(*Backend)
+
+	createOSSBucket(t, b.ossClient, bucketName)
+	defer deleteOSSBucket(t, b.ossClient, bucketName)
+	createTablestoreTable(t, b.otsClient, tableName)
+	defer deleteTablestoreTable(t, b.otsClient, tableName)
+
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+	client := s.(*remote.State).Client.(*RemoteClient)
+
+	sum := md5.Sum([]byte("test"))
+
+	if err := client.putMD5(sum[:]); err != nil {
+		t.Fatal(err)
+	}
+
+	getSum, err := client.getMD5()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !bytes.Equal(getSum, sum[:]) {
+		t.Fatalf("getMD5 returned the wrong checksum: expected %x, got %x", sum[:], getSum)
+	}
+
+	if err := client.deleteMD5(); err != nil {
+		t.Fatal(err)
+	}
+
+	if getSum, err := client.getMD5(); err == nil {
+		t.Fatalf("expected getMD5 error, got none. checksum: %x", getSum)
+	}
+}
+
+// verify that a client won't return a state with an incorrect checksum.
+func TestRemoteClient_stateChecksum(t *testing.T) {
+	testACC(t)
+
+	bucketName := fmt.Sprintf("tf-remote-oss-test-%x", time.Now().Unix())
+	tableName := fmt.Sprintf("tfRemoteTestForce%x", time.Now().Unix())
+	path := "testState"
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":              bucketName,
+		"prefix":              path,
+		"tablestore_table":    tableName,
+		"tablestore_endpoint": RemoteTestUsedOTSEndpoint,
+	})).(*Backend)
+
+	createOSSBucket(t, b1.ossClient, bucketName)
+	defer deleteOSSBucket(t, b1.ossClient, bucketName)
+	createTablestoreTable(t, b1.otsClient, tableName)
+	defer deleteTablestoreTable(t, b1.otsClient, tableName)
+
+	s1, err := b1.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+	client1 := s1.(*remote.State).Client
+
+	// create an old and new state version to persist
+	s := statemgr.TestFullInitialState()
+	sf := &statefile.File{State: s}
+	var oldState bytes.Buffer
+	if err := statefile.Write(sf, &oldState); err != nil {
+		t.Fatal(err)
+	}
+	sf.Serial++
+	var newState bytes.Buffer
+	if err := statefile.Write(sf, &newState); err != nil {
+		t.Fatal(err)
+	}
+
+	// Use b2 without a tablestore_table to bypass the lock table to write the state directly.
+	// client2 will write the "incorrect" state, simulating oss eventually consistency delays
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket": bucketName,
+		"prefix": path,
+	})).(*Backend)
+	s2, err := b2.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+	client2 := s2.(*remote.State).Client
+
+	// write the new state through client2 so that there is no checksum yet
+	if err := client2.Put(newState.Bytes()); err != nil {
+		t.Fatal(err)
+	}
+
+	// verify that we can pull a state without a checksum
+	if _, err := client1.Get(); err != nil {
+		t.Fatal(err)
+	}
+
+	// write the new state back with its checksum
+	if err := client1.Put(newState.Bytes()); err != nil {
+		t.Fatal(err)
+	}
+
+	// put an empty state in place to check for panics during get
+	if err := client2.Put([]byte{}); err != nil {
+		t.Fatal(err)
+	}
+
+	// remove the timeouts so we can fail immediately
+	origTimeout := consistencyRetryTimeout
+	origInterval := consistencyRetryPollInterval
+	defer func() {
+		consistencyRetryTimeout = origTimeout
+		consistencyRetryPollInterval = origInterval
+	}()
+	consistencyRetryTimeout = 0
+	consistencyRetryPollInterval = 0
+
+	// fetching an empty state through client1 should now error out due to a
+	// mismatched checksum.
+	if _, err := client1.Get(); !strings.HasPrefix(err.Error(), errBadChecksumFmt[:80]) {
+		t.Fatalf("expected state checksum error: got %s", err)
+	}
+
+	// put the old state in place of the new, without updating the checksum
+	if err := client2.Put(oldState.Bytes()); err != nil {
+		t.Fatal(err)
+	}
+
+	// fetching the wrong state through client1 should now error out due to a
+	// mismatched checksum.
+	if _, err := client1.Get(); !strings.HasPrefix(err.Error(), errBadChecksumFmt[:80]) {
+		t.Fatalf("expected state checksum error: got %s", err)
+	}
+
+	// update the state with the correct one after we Get again
+	testChecksumHook = func() {
+		if err := client2.Put(newState.Bytes()); err != nil {
+			t.Fatal(err)
+		}
+		testChecksumHook = nil
+	}
+
+	consistencyRetryTimeout = origTimeout
+
+	// this final Get will fail to fail the checksum verification, the above
+	// callback will update the state with the correct version, and Get should
+	// retry automatically.
+	if _, err := client1.Get(); err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/v1.5.7/internal/backend/remote-state/pg/backend.go b/v1.5.7/internal/backend/remote-state/pg/backend.go
new file mode 100644
index 0000000..083cb99
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/pg/backend.go
@@ -0,0 +1,151 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package pg
+
+import (
+	"context"
+	"database/sql"
+	"fmt"
+	"os"
+	"strconv"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/legacy/helper/schema"
+	"github.com/lib/pq"
+)
+
+const (
+	statesTableName = "states"
+	statesIndexName = "states_by_name"
+)
+
+func defaultBoolFunc(k string, dv bool) schema.SchemaDefaultFunc {
+	return func() (interface{}, error) {
+		if v := os.Getenv(k); v != "" {
+			return strconv.ParseBool(v)
+		}
+
+		return dv, nil
+	}
+}
+
+// New creates a new backend for Postgres remote state.
+func New() backend.Backend {
+	s := &schema.Backend{
+		Schema: map[string]*schema.Schema{
+			"conn_str": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "Postgres connection string; a `postgres://` URL",
+				DefaultFunc: schema.EnvDefaultFunc("PG_CONN_STR", nil),
+			},
+
+			"schema_name": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "Name of the automatically managed Postgres schema to store state",
+				DefaultFunc: schema.EnvDefaultFunc("PG_SCHEMA_NAME", "terraform_remote_state"),
+			},
+
+			"skip_schema_creation": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "If set to `true`, Terraform won't try to create the Postgres schema",
+				DefaultFunc: defaultBoolFunc("PG_SKIP_SCHEMA_CREATION", false),
+			},
+
+			"skip_table_creation": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "If set to `true`, Terraform won't try to create the Postgres table",
+				DefaultFunc: defaultBoolFunc("PG_SKIP_TABLE_CREATION", false),
+			},
+
+			"skip_index_creation": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "If set to `true`, Terraform won't try to create the Postgres index",
+				DefaultFunc: defaultBoolFunc("PG_SKIP_INDEX_CREATION", false),
+			},
+		},
+	}
+
+	result := &Backend{Backend: s}
+	result.Backend.ConfigureFunc = result.configure
+	return result
+}
+
+type Backend struct {
+	*schema.Backend
+
+	// The fields below are set from configure
+	db         *sql.DB
+	configData *schema.ResourceData
+	connStr    string
+	schemaName string
+}
+
+func (b *Backend) configure(ctx context.Context) error {
+	// Grab the resource data
+	b.configData = schema.FromContextBackendConfig(ctx)
+	data := b.configData
+
+	b.connStr = data.Get("conn_str").(string)
+	b.schemaName = pq.QuoteIdentifier(data.Get("schema_name").(string))
+
+	db, err := sql.Open("postgres", b.connStr)
+	if err != nil {
+		return err
+	}
+
+	// Prepare database schema, tables, & indexes.
+	var query string
+
+	if !data.Get("skip_schema_creation").(bool) {
+		// list all schemas to see if it exists
+		var count int
+		query = `select count(1) from information_schema.schemata where schema_name = $1`
+		if err := db.QueryRow(query, data.Get("schema_name").(string)).Scan(&count); err != nil {
+			return err
+		}
+
+		// skip schema creation if schema already exists
+		// `CREATE SCHEMA IF NOT EXISTS` is to be avoided if ever
+		// a user hasn't been granted the `CREATE SCHEMA` privilege
+		if count < 1 {
+			// tries to create the schema
+			query = `CREATE SCHEMA IF NOT EXISTS %s`
+			if _, err := db.Exec(fmt.Sprintf(query, b.schemaName)); err != nil {
+				return err
+			}
+		}
+	}
+
+	if !data.Get("skip_table_creation").(bool) {
+		if _, err := db.Exec("CREATE SEQUENCE IF NOT EXISTS public.global_states_id_seq AS bigint"); err != nil {
+			return err
+		}
+
+		query = `CREATE TABLE IF NOT EXISTS %s.%s (
+			id bigint NOT NULL DEFAULT nextval('public.global_states_id_seq') PRIMARY KEY,
+			name text UNIQUE,
+			data text
+			)`
+		if _, err := db.Exec(fmt.Sprintf(query, b.schemaName, statesTableName)); err != nil {
+			return err
+		}
+	}
+
+	if !data.Get("skip_index_creation").(bool) {
+		query = `CREATE UNIQUE INDEX IF NOT EXISTS %s ON %s.%s (name)`
+		if _, err := db.Exec(fmt.Sprintf(query, statesIndexName, b.schemaName, statesTableName)); err != nil {
+			return err
+		}
+	}
+
+	// Assign db after its schema is prepared.
+	b.db = db
+
+	return nil
+}
diff --git a/v1.5.7/internal/backend/remote-state/pg/backend_state.go b/v1.5.7/internal/backend/remote-state/pg/backend_state.go
new file mode 100644
index 0000000..ab314a4
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/pg/backend_state.go
@@ -0,0 +1,118 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package pg
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+func (b *Backend) Workspaces() ([]string, error) {
+	query := `SELECT name FROM %s.%s WHERE name != 'default' ORDER BY name`
+	rows, err := b.db.Query(fmt.Sprintf(query, b.schemaName, statesTableName))
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	result := []string{
+		backend.DefaultStateName,
+	}
+
+	for rows.Next() {
+		var name string
+		if err := rows.Scan(&name); err != nil {
+			return nil, err
+		}
+		result = append(result, name)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+
+	return result, nil
+}
+
+func (b *Backend) DeleteWorkspace(name string, _ bool) error {
+	if name == backend.DefaultStateName || name == "" {
+		return fmt.Errorf("can't delete default state")
+	}
+
+	query := `DELETE FROM %s.%s WHERE name = $1`
+	_, err := b.db.Exec(fmt.Sprintf(query, b.schemaName, statesTableName), name)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
+	// Build the state client
+	var stateMgr statemgr.Full = &remote.State{
+		Client: &RemoteClient{
+			Client:     b.db,
+			Name:       name,
+			SchemaName: b.schemaName,
+		},
+	}
+
+	// Check to see if this state already exists.
+	// If the state doesn't exist, we have to assume this
+	// is a normal create operation, and take the lock at that point.
+	existing, err := b.Workspaces()
+	if err != nil {
+		return nil, err
+	}
+
+	exists := false
+	for _, s := range existing {
+		if s == name {
+			exists = true
+			break
+		}
+	}
+
+	// Grab a lock, we use this to write an empty state if one doesn't
+	// exist already. We have to write an empty state as a sentinel value
+	// so Workspaces() knows it exists.
+	if !exists {
+		lockInfo := statemgr.NewLockInfo()
+		lockInfo.Operation = "init"
+		lockId, err := stateMgr.Lock(lockInfo)
+		if err != nil {
+			return nil, fmt.Errorf("failed to lock state in Postgres: %s", err)
+		}
+
+		// Local helper function so we can call it multiple places
+		lockUnlock := func(parent error) error {
+			if err := stateMgr.Unlock(lockId); err != nil {
+				return fmt.Errorf(`error unlocking Postgres state: %s`, err)
+			}
+			return parent
+		}
+
+		if v := stateMgr.State(); v == nil {
+			if err := stateMgr.WriteState(states.NewState()); err != nil {
+				err = lockUnlock(err)
+				return nil, err
+			}
+			if err := stateMgr.PersistState(nil); err != nil {
+				err = lockUnlock(err)
+				return nil, err
+			}
+		}
+
+		// Unlock, the state should now be initialized
+		if err := lockUnlock(nil); err != nil {
+			return nil, err
+		}
+	}
+
+	return stateMgr, nil
+}
diff --git a/v1.5.7/internal/backend/remote-state/pg/backend_test.go b/v1.5.7/internal/backend/remote-state/pg/backend_test.go
new file mode 100644
index 0000000..80eba7b
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/pg/backend_test.go
@@ -0,0 +1,513 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package pg
+
+// Create the test database: createdb terraform_backend_pg_test
+// TF_ACC=1 GO111MODULE=on go test -v -mod=vendor -timeout=2m -parallel=4 github.com/hashicorp/terraform/backend/remote-state/pg
+
+import (
+	"database/sql"
+	"fmt"
+	"net/url"
+	"os"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/hcl/v2/hcldec"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/lib/pq"
+)
+
+// Function to skip a test unless in ACCeptance test mode.
+//
+// A running Postgres server identified by env variable
+// DATABASE_URL is required for acceptance tests.
+func testACC(t *testing.T) string {
+	skip := os.Getenv("TF_ACC") == ""
+	if skip {
+		t.Log("pg backend tests require setting TF_ACC")
+		t.Skip()
+	}
+	databaseUrl, found := os.LookupEnv("DATABASE_URL")
+	if !found {
+		databaseUrl = "postgres://localhost/terraform_backend_pg_test?sslmode=disable"
+		os.Setenv("DATABASE_URL", databaseUrl)
+	}
+	u, err := url.Parse(databaseUrl)
+	if err != nil {
+		t.Fatal(err)
+	}
+	return u.Path[1:]
+}
+
+func TestBackend_impl(t *testing.T) {
+	var _ backend.Backend = new(Backend)
+}
+
+func TestBackendConfig(t *testing.T) {
+	databaseName := testACC(t)
+	connStr := getDatabaseUrl()
+
+	testCases := []struct {
+		Name                     string
+		EnvVars                  map[string]string
+		Config                   map[string]interface{}
+		ExpectConfigurationError string
+		ExpectConnectionError    string
+	}{
+		{
+			Name: "valid-config",
+			Config: map[string]interface{}{
+				"conn_str":    connStr,
+				"schema_name": fmt.Sprintf("terraform_%s", t.Name()),
+			},
+		},
+		{
+			Name: "missing-conn_str-defaults-to-localhost",
+			EnvVars: map[string]string{
+				"PGSSLMODE":  "disable",
+				"PGDATABASE": databaseName,
+			},
+			Config: map[string]interface{}{
+				"schema_name": fmt.Sprintf("terraform_%s", t.Name()),
+			},
+		},
+		{
+			Name: "conn-str-env-var",
+			EnvVars: map[string]string{
+				"PG_CONN_STR": connStr,
+			},
+			Config: map[string]interface{}{
+				"schema_name": fmt.Sprintf("terraform_%s", t.Name()),
+			},
+		},
+		{
+			Name: "setting-credentials-using-env-vars",
+			EnvVars: map[string]string{
+				"PGUSER":     "baduser",
+				"PGPASSWORD": "badpassword",
+			},
+			Config: map[string]interface{}{
+				"conn_str":    connStr,
+				"schema_name": fmt.Sprintf("terraform_%s", t.Name()),
+			},
+			ExpectConnectionError: `role "baduser" does not exist`,
+		},
+		{
+			Name: "host-in-env-vars",
+			EnvVars: map[string]string{
+				"PGHOST": "hostthatdoesnotexist",
+			},
+			Config: map[string]interface{}{
+				"schema_name": fmt.Sprintf("terraform_%s", t.Name()),
+			},
+			ExpectConnectionError: `no such host`,
+		},
+		{
+			Name: "boolean-env-vars",
+			EnvVars: map[string]string{
+				"PGSSLMODE":               "disable",
+				"PG_SKIP_SCHEMA_CREATION": "f",
+				"PG_SKIP_TABLE_CREATION":  "f",
+				"PG_SKIP_INDEX_CREATION":  "f",
+				"PGDATABASE":              databaseName,
+			},
+			Config: map[string]interface{}{
+				"schema_name": fmt.Sprintf("terraform_%s", t.Name()),
+			},
+		},
+		{
+			Name: "wrong-boolean-env-vars",
+			EnvVars: map[string]string{
+				"PGSSLMODE":               "disable",
+				"PG_SKIP_SCHEMA_CREATION": "foo",
+				"PGDATABASE":              databaseName,
+			},
+			Config: map[string]interface{}{
+				"schema_name": fmt.Sprintf("terraform_%s", t.Name()),
+			},
+			ExpectConfigurationError: `error getting default for "skip_schema_creation"`,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.Name, func(t *testing.T) {
+			for k, v := range tc.EnvVars {
+				t.Setenv(k, v)
+			}
+
+			config := backend.TestWrapConfig(tc.Config)
+			schemaName := pq.QuoteIdentifier(tc.Config["schema_name"].(string))
+
+			dbCleaner, err := sql.Open("postgres", connStr)
+			if err != nil {
+				t.Fatal(err)
+			}
+			defer dbCleaner.Query(fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", schemaName))
+
+			var diags tfdiags.Diagnostics
+			b := New().(*Backend)
+			schema := b.ConfigSchema()
+			spec := schema.DecoderSpec()
+			obj, decDiags := hcldec.Decode(config, spec, nil)
+			diags = diags.Append(decDiags)
+
+			newObj, valDiags := b.PrepareConfig(obj)
+			diags = diags.Append(valDiags.InConfigBody(config, ""))
+
+			if tc.ExpectConfigurationError != "" {
+				if !diags.HasErrors() {
+					t.Fatal("error expected but got none")
+				}
+				if !strings.Contains(diags.ErrWithWarnings().Error(), tc.ExpectConfigurationError) {
+					t.Fatalf("failed to find %q in %s", tc.ExpectConfigurationError, diags.ErrWithWarnings())
+				}
+				return
+			} else if diags.HasErrors() {
+				t.Fatal(diags.ErrWithWarnings())
+			}
+
+			obj = newObj
+
+			confDiags := b.Configure(obj)
+			if tc.ExpectConnectionError != "" {
+				err := confDiags.InConfigBody(config, "").ErrWithWarnings()
+				if err == nil {
+					t.Fatal("error expected but got none")
+				}
+				if !strings.Contains(err.Error(), tc.ExpectConnectionError) {
+					t.Fatalf("failed to find %q in %s", tc.ExpectConnectionError, err)
+				}
+				return
+			} else if len(confDiags) != 0 {
+				confDiags = confDiags.InConfigBody(config, "")
+				t.Fatal(confDiags.ErrWithWarnings())
+			}
+
+			if b == nil {
+				t.Fatal("Backend could not be configured")
+			}
+
+			_, err = b.db.Query(fmt.Sprintf("SELECT name, data FROM %s.%s LIMIT 1", schemaName, statesTableName))
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			_, err = b.StateMgr(backend.DefaultStateName)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			s, err := b.StateMgr(backend.DefaultStateName)
+			if err != nil {
+				t.Fatal(err)
+			}
+			c := s.(*remote.State).Client.(*RemoteClient)
+			if c.Name != backend.DefaultStateName {
+				t.Fatal("RemoteClient name is not configured")
+			}
+
+			backend.TestBackendStates(t, b)
+		})
+	}
+
+}
+
+func TestBackendConfigSkipOptions(t *testing.T) {
+	testACC(t)
+	connStr := getDatabaseUrl()
+
+	testCases := []struct {
+		Name               string
+		SkipSchemaCreation bool
+		SkipTableCreation  bool
+		SkipIndexCreation  bool
+		TestIndexIsPresent bool
+		Setup              func(t *testing.T, db *sql.DB, schemaName string)
+	}{
+		{
+			Name:               "skip_schema_creation",
+			SkipSchemaCreation: true,
+			TestIndexIsPresent: true,
+			Setup: func(t *testing.T, db *sql.DB, schemaName string) {
+				// create the schema as a prerequisites
+				_, err := db.Query(fmt.Sprintf(`CREATE SCHEMA IF NOT EXISTS %s`, schemaName))
+				if err != nil {
+					t.Fatal(err)
+				}
+			},
+		},
+		{
+			Name:               "skip_table_creation",
+			SkipTableCreation:  true,
+			TestIndexIsPresent: true,
+			Setup: func(t *testing.T, db *sql.DB, schemaName string) {
+				// since the table needs to be already created the schema must be too
+				_, err := db.Query(fmt.Sprintf(`CREATE SCHEMA %s`, schemaName))
+				if err != nil {
+					t.Fatal(err)
+				}
+				_, err = db.Query(fmt.Sprintf(`CREATE TABLE %s.%s (
+					id SERIAL PRIMARY KEY,
+					name TEXT,
+					data TEXT
+					)`, schemaName, statesTableName))
+				if err != nil {
+					t.Fatal(err)
+				}
+			},
+		},
+		{
+			Name:               "skip_index_creation",
+			SkipIndexCreation:  true,
+			TestIndexIsPresent: true,
+			Setup: func(t *testing.T, db *sql.DB, schemaName string) {
+				// Everything need to exists for the index to be created
+				_, err := db.Query(fmt.Sprintf(`CREATE SCHEMA %s`, schemaName))
+				if err != nil {
+					t.Fatal(err)
+				}
+				_, err = db.Query(fmt.Sprintf(`CREATE TABLE %s.%s (
+					id SERIAL PRIMARY KEY,
+					name TEXT,
+					data TEXT
+					)`, schemaName, statesTableName))
+				if err != nil {
+					t.Fatal(err)
+				}
+				_, err = db.Exec(fmt.Sprintf(`CREATE UNIQUE INDEX IF NOT EXISTS %s ON %s.%s (name)`, statesIndexName, schemaName, statesTableName))
+				if err != nil {
+					t.Fatal(err)
+				}
+			},
+		},
+		{
+			Name:              "missing_index",
+			SkipIndexCreation: true,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.Name, func(t *testing.T) {
+			schemaName := tc.Name
+
+			config := backend.TestWrapConfig(map[string]interface{}{
+				"conn_str":             connStr,
+				"schema_name":          schemaName,
+				"skip_schema_creation": tc.SkipSchemaCreation,
+				"skip_table_creation":  tc.SkipTableCreation,
+				"skip_index_creation":  tc.SkipIndexCreation,
+			})
+			schemaName = pq.QuoteIdentifier(schemaName)
+			db, err := sql.Open("postgres", connStr)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			if tc.Setup != nil {
+				tc.Setup(t, db, schemaName)
+			}
+			defer db.Query(fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", schemaName))
+
+			b := backend.TestBackendConfig(t, New(), config).(*Backend)
+
+			if b == nil {
+				t.Fatal("Backend could not be configured")
+			}
+
+			// Make sure everything has been created
+
+			// This tests that both the schema and the table have been created
+			_, err = b.db.Query(fmt.Sprintf("SELECT name, data FROM %s.%s LIMIT 1", schemaName, statesTableName))
+			if err != nil {
+				t.Fatal(err)
+			}
+			if tc.TestIndexIsPresent {
+				// Make sure that the index exists
+				query := `select count(*) from pg_indexes where schemaname=$1 and tablename=$2 and indexname=$3;`
+				var count int
+				if err := b.db.QueryRow(query, tc.Name, statesTableName, statesIndexName).Scan(&count); err != nil {
+					t.Fatal(err)
+				}
+				if count != 1 {
+					t.Fatalf("The index has not been created (%d)", count)
+				}
+			}
+
+			_, err = b.StateMgr(backend.DefaultStateName)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			s, err := b.StateMgr(backend.DefaultStateName)
+			if err != nil {
+				t.Fatal(err)
+			}
+			c := s.(*remote.State).Client.(*RemoteClient)
+			if c.Name != backend.DefaultStateName {
+				t.Fatal("RemoteClient name is not configured")
+			}
+
+			// Make sure that all workspace must have a unique name
+			_, err = db.Exec(fmt.Sprintf(`INSERT INTO %s.%s VALUES (100, 'unique_name_test', '')`, schemaName, statesTableName))
+			if err != nil {
+				t.Fatal(err)
+			}
+			_, err = db.Exec(fmt.Sprintf(`INSERT INTO %s.%s VALUES (101, 'unique_name_test', '')`, schemaName, statesTableName))
+			if err == nil {
+				t.Fatal("Creating two workspaces with the same name did not raise an error")
+			}
+		})
+	}
+
+}
+
+func TestBackendStates(t *testing.T) {
+	testACC(t)
+	connStr := getDatabaseUrl()
+
+	testCases := []string{
+		fmt.Sprintf("terraform_%s", t.Name()),
+		fmt.Sprintf("test with spaces: %s", t.Name()),
+	}
+	for _, schemaName := range testCases {
+		t.Run(schemaName, func(t *testing.T) {
+			dbCleaner, err := sql.Open("postgres", connStr)
+			if err != nil {
+				t.Fatal(err)
+			}
+			defer dbCleaner.Query(fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", pq.QuoteIdentifier(schemaName)))
+
+			config := backend.TestWrapConfig(map[string]interface{}{
+				"conn_str":    connStr,
+				"schema_name": schemaName,
+			})
+			b := backend.TestBackendConfig(t, New(), config).(*Backend)
+
+			if b == nil {
+				t.Fatal("Backend could not be configured")
+			}
+
+			backend.TestBackendStates(t, b)
+		})
+	}
+}
+
+func TestBackendStateLocks(t *testing.T) {
+	testACC(t)
+	connStr := getDatabaseUrl()
+	schemaName := fmt.Sprintf("terraform_%s", t.Name())
+	dbCleaner, err := sql.Open("postgres", connStr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer dbCleaner.Query(fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", schemaName))
+
+	config := backend.TestWrapConfig(map[string]interface{}{
+		"conn_str":    connStr,
+		"schema_name": schemaName,
+	})
+	b := backend.TestBackendConfig(t, New(), config).(*Backend)
+
+	if b == nil {
+		t.Fatal("Backend could not be configured")
+	}
+
+	bb := backend.TestBackendConfig(t, New(), config).(*Backend)
+
+	if bb == nil {
+		t.Fatal("Backend could not be configured")
+	}
+
+	backend.TestBackendStateLocks(t, b, bb)
+}
+
+func TestBackendConcurrentLock(t *testing.T) {
+	testACC(t)
+	connStr := getDatabaseUrl()
+	dbCleaner, err := sql.Open("postgres", connStr)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	getStateMgr := func(schemaName string) (statemgr.Full, *statemgr.LockInfo) {
+		defer dbCleaner.Query(fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", schemaName))
+		config := backend.TestWrapConfig(map[string]interface{}{
+			"conn_str":    connStr,
+			"schema_name": schemaName,
+		})
+		b := backend.TestBackendConfig(t, New(), config).(*Backend)
+
+		if b == nil {
+			t.Fatal("Backend could not be configured")
+		}
+		stateMgr, err := b.StateMgr(backend.DefaultStateName)
+		if err != nil {
+			t.Fatalf("Failed to get the state manager: %v", err)
+		}
+
+		info := statemgr.NewLockInfo()
+		info.Operation = "test"
+		info.Who = schemaName
+
+		return stateMgr, info
+	}
+
+	s1, i1 := getStateMgr(fmt.Sprintf("terraform_%s_1", t.Name()))
+	s2, i2 := getStateMgr(fmt.Sprintf("terraform_%s_2", t.Name()))
+
+	// First we need to create the workspace as the lock for creating them is
+	// global
+	lockID1, err := s1.Lock(i1)
+	if err != nil {
+		t.Fatalf("failed to lock first state: %v", err)
+	}
+
+	if err = s1.PersistState(nil); err != nil {
+		t.Fatalf("failed to persist state: %v", err)
+	}
+
+	if err := s1.Unlock(lockID1); err != nil {
+		t.Fatalf("failed to unlock first state: %v", err)
+	}
+
+	lockID2, err := s2.Lock(i2)
+	if err != nil {
+		t.Fatalf("failed to lock second state: %v", err)
+	}
+
+	if err = s2.PersistState(nil); err != nil {
+		t.Fatalf("failed to persist state: %v", err)
+	}
+
+	if err := s2.Unlock(lockID2); err != nil {
+		t.Fatalf("failed to unlock first state: %v", err)
+	}
+
+	// Now we can test concurrent lock
+	lockID1, err = s1.Lock(i1)
+	if err != nil {
+		t.Fatalf("failed to lock first state: %v", err)
+	}
+
+	lockID2, err = s2.Lock(i2)
+	if err != nil {
+		t.Fatalf("failed to lock second state: %v", err)
+	}
+
+	if err := s1.Unlock(lockID1); err != nil {
+		t.Fatalf("failed to unlock first state: %v", err)
+	}
+
+	if err := s2.Unlock(lockID2); err != nil {
+		t.Fatalf("failed to unlock first state: %v", err)
+	}
+}
+
+func getDatabaseUrl() string {
+	return os.Getenv("DATABASE_URL")
+}
diff --git a/v1.5.7/internal/backend/remote-state/pg/client.go b/v1.5.7/internal/backend/remote-state/pg/client.go
new file mode 100644
index 0000000..cd5d330
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/pg/client.go
@@ -0,0 +1,145 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package pg
+
+import (
+	"crypto/md5"
+	"database/sql"
+	"fmt"
+
+	uuid "github.com/hashicorp/go-uuid"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	_ "github.com/lib/pq"
+)
+
+// RemoteClient is a remote client that stores data in a Postgres database
+type RemoteClient struct {
+	Client     *sql.DB
+	Name       string
+	SchemaName string
+
+	info *statemgr.LockInfo
+}
+
+func (c *RemoteClient) Get() (*remote.Payload, error) {
+	query := `SELECT data FROM %s.%s WHERE name = $1`
+	row := c.Client.QueryRow(fmt.Sprintf(query, c.SchemaName, statesTableName), c.Name)
+	var data []byte
+	err := row.Scan(&data)
+	switch {
+	case err == sql.ErrNoRows:
+		// No existing state returns empty.
+		return nil, nil
+	case err != nil:
+		return nil, err
+	default:
+		md5 := md5.Sum(data)
+		return &remote.Payload{
+			Data: data,
+			MD5:  md5[:],
+		}, nil
+	}
+}
+
+func (c *RemoteClient) Put(data []byte) error {
+	query := `INSERT INTO %s.%s (name, data) VALUES ($1, $2)
+		ON CONFLICT (name) DO UPDATE
+		SET data = $2 WHERE %s.name = $1`
+	_, err := c.Client.Exec(fmt.Sprintf(query, c.SchemaName, statesTableName, statesTableName), c.Name, data)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (c *RemoteClient) Delete() error {
+	query := `DELETE FROM %s.%s WHERE name = $1`
+	_, err := c.Client.Exec(fmt.Sprintf(query, c.SchemaName, statesTableName), c.Name)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
+	var err error
+	var lockID string
+
+	if info.ID == "" {
+		lockID, err = uuid.GenerateUUID()
+		if err != nil {
+			return "", err
+		}
+		info.ID = lockID
+	}
+
+	// Local helper function so we can call it multiple places
+	//
+	lockUnlock := func(pgLockId string) error {
+		query := `SELECT pg_advisory_unlock(%s)`
+		row := c.Client.QueryRow(fmt.Sprintf(query, pgLockId))
+		var didUnlock []byte
+		err := row.Scan(&didUnlock)
+		if err != nil {
+			return &statemgr.LockError{Info: info, Err: err}
+		}
+		return nil
+	}
+
+	// Try to acquire locks for the existing row `id` and the creation lock `-1`.
+	query := `SELECT %s.id, pg_try_advisory_lock(%s.id), pg_try_advisory_lock(-1) FROM %s.%s WHERE %s.name = $1`
+	row := c.Client.QueryRow(fmt.Sprintf(query, statesTableName, statesTableName, c.SchemaName, statesTableName, statesTableName), c.Name)
+	var pgLockId, didLock, didLockForCreate []byte
+	err = row.Scan(&pgLockId, &didLock, &didLockForCreate)
+	switch {
+	case err == sql.ErrNoRows:
+		// No rows means we're creating the workspace. Take the creation lock.
+		innerRow := c.Client.QueryRow(`SELECT pg_try_advisory_lock(-1)`)
+		var innerDidLock []byte
+		err := innerRow.Scan(&innerDidLock)
+		if err != nil {
+			return "", &statemgr.LockError{Info: info, Err: err}
+		}
+		if string(innerDidLock) == "false" {
+			return "", &statemgr.LockError{Info: info, Err: fmt.Errorf("Already locked for workspace creation: %s", c.Name)}
+		}
+		info.Path = "-1"
+	case err != nil:
+		return "", &statemgr.LockError{Info: info, Err: err}
+	case string(didLock) == "false":
+		// Existing workspace is already locked. Release the attempted creation lock.
+		lockUnlock("-1")
+		return "", &statemgr.LockError{Info: info, Err: fmt.Errorf("Workspace is already locked: %s", c.Name)}
+	case string(didLockForCreate) == "false":
+		// Someone has the creation lock already. Release the existing workspace because it might not be safe to touch.
+		lockUnlock(string(pgLockId))
+		return "", &statemgr.LockError{Info: info, Err: fmt.Errorf("Cannot lock workspace; already locked for workspace creation: %s", c.Name)}
+	default:
+		// Existing workspace is now locked. Release the attempted creation lock.
+		lockUnlock("-1")
+		info.Path = string(pgLockId)
+	}
+	c.info = info
+
+	return info.ID, nil
+}
+
+func (c *RemoteClient) getLockInfo() (*statemgr.LockInfo, error) {
+	return c.info, nil
+}
+
+func (c *RemoteClient) Unlock(id string) error {
+	if c.info != nil && c.info.Path != "" {
+		query := `SELECT pg_advisory_unlock(%s)`
+		row := c.Client.QueryRow(fmt.Sprintf(query, c.info.Path))
+		var didUnlock []byte
+		err := row.Scan(&didUnlock)
+		if err != nil {
+			return &statemgr.LockError{Info: c.info, Err: err}
+		}
+		c.info = nil
+	}
+	return nil
+}
diff --git a/v1.5.7/internal/backend/remote-state/pg/client_test.go b/v1.5.7/internal/backend/remote-state/pg/client_test.go
new file mode 100644
index 0000000..5b7eee5
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/pg/client_test.go
@@ -0,0 +1,79 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package pg
+
+// Create the test database: createdb terraform_backend_pg_test
+// TF_ACC=1 GO111MODULE=on go test -v -mod=vendor -timeout=2m -parallel=4 github.com/hashicorp/terraform/backend/remote-state/pg
+
+import (
+	"database/sql"
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states/remote"
+)
+
+func TestRemoteClient_impl(t *testing.T) {
+	var _ remote.Client = new(RemoteClient)
+	var _ remote.ClientLocker = new(RemoteClient)
+}
+
+func TestRemoteClient(t *testing.T) {
+	testACC(t)
+	connStr := getDatabaseUrl()
+	schemaName := fmt.Sprintf("terraform_%s", t.Name())
+	dbCleaner, err := sql.Open("postgres", connStr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer dbCleaner.Query(fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", schemaName))
+
+	config := backend.TestWrapConfig(map[string]interface{}{
+		"conn_str":    connStr,
+		"schema_name": schemaName,
+	})
+	b := backend.TestBackendConfig(t, New(), config).(*Backend)
+
+	if b == nil {
+		t.Fatal("Backend could not be configured")
+	}
+
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestClient(t, s.(*remote.State).Client)
+}
+
+func TestRemoteLocks(t *testing.T) {
+	testACC(t)
+	connStr := getDatabaseUrl()
+	schemaName := fmt.Sprintf("terraform_%s", t.Name())
+	dbCleaner, err := sql.Open("postgres", connStr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer dbCleaner.Query(fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", schemaName))
+
+	config := backend.TestWrapConfig(map[string]interface{}{
+		"conn_str":    connStr,
+		"schema_name": schemaName,
+	})
+
+	b1 := backend.TestBackendConfig(t, New(), config).(*Backend)
+	s1, err := b1.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	b2 := backend.TestBackendConfig(t, New(), config).(*Backend)
+	s2, err := b2.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestRemoteLocks(t, s1.(*remote.State).Client, s2.(*remote.State).Client)
+}
diff --git a/v1.5.7/internal/backend/remote-state/s3/backend.go b/v1.5.7/internal/backend/remote-state/s3/backend.go
new file mode 100644
index 0000000..aa64869
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/s3/backend.go
@@ -0,0 +1,416 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package s3
+
+import (
+	"context"
+	"encoding/base64"
+	"errors"
+	"fmt"
+	"strings"
+
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/service/dynamodb"
+	"github.com/aws/aws-sdk-go/service/s3"
+	awsbase "github.com/hashicorp/aws-sdk-go-base"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/legacy/helper/schema"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/version"
+)
+
+// New creates a new backend for S3 remote state.
+func New() backend.Backend {
+	s := &schema.Backend{
+		Schema: map[string]*schema.Schema{
+			"bucket": {
+				Type:        schema.TypeString,
+				Required:    true,
+				Description: "The name of the S3 bucket",
+			},
+
+			"key": {
+				Type:        schema.TypeString,
+				Required:    true,
+				Description: "The path to the state file inside the bucket",
+				ValidateFunc: func(v interface{}, s string) ([]string, []error) {
+					// s3 will strip leading slashes from an object, so while this will
+					// technically be accepted by s3, it will break our workspace hierarchy.
+					if strings.HasPrefix(v.(string), "/") {
+						return nil, []error{errors.New("key must not start with '/'")}
+					}
+					// s3 will recognize objects with a trailing slash as a directory
+					// so they should not be valid keys
+					if strings.HasSuffix(v.(string), "/") {
+						return nil, []error{errors.New("key must not end with '/'")}
+					}
+					return nil, nil
+				},
+			},
+
+			"region": {
+				Type:        schema.TypeString,
+				Required:    true,
+				Description: "AWS region of the S3 Bucket and DynamoDB Table (if used).",
+				DefaultFunc: schema.MultiEnvDefaultFunc([]string{
+					"AWS_REGION",
+					"AWS_DEFAULT_REGION",
+				}, nil),
+			},
+
+			"dynamodb_endpoint": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "A custom endpoint for the DynamoDB API",
+				DefaultFunc: schema.EnvDefaultFunc("AWS_DYNAMODB_ENDPOINT", ""),
+			},
+
+			"endpoint": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "A custom endpoint for the S3 API",
+				DefaultFunc: schema.EnvDefaultFunc("AWS_S3_ENDPOINT", ""),
+			},
+
+			"iam_endpoint": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "A custom endpoint for the IAM API",
+				DefaultFunc: schema.EnvDefaultFunc("AWS_IAM_ENDPOINT", ""),
+			},
+
+			"sts_endpoint": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "A custom endpoint for the STS API",
+				DefaultFunc: schema.EnvDefaultFunc("AWS_STS_ENDPOINT", ""),
+			},
+
+			"encrypt": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "Whether to enable server side encryption of the state file",
+				Default:     false,
+			},
+
+			"acl": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "Canned ACL to be applied to the state file",
+				Default:     "",
+			},
+
+			"access_key": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "AWS access key",
+				Default:     "",
+			},
+
+			"secret_key": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "AWS secret key",
+				Default:     "",
+			},
+
+			"kms_key_id": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The ARN of a KMS Key to use for encrypting the state",
+				Default:     "",
+			},
+
+			"dynamodb_table": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "DynamoDB table for state locking and consistency",
+				Default:     "",
+			},
+
+			"profile": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "AWS profile name",
+				Default:     "",
+			},
+
+			"shared_credentials_file": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "Path to a shared credentials file",
+				Default:     "",
+			},
+
+			"token": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "MFA token",
+				Default:     "",
+			},
+
+			"skip_credentials_validation": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "Skip the credentials validation via STS API.",
+				Default:     false,
+			},
+
+			"skip_region_validation": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "Skip static validation of region name.",
+				Default:     false,
+			},
+
+			"skip_metadata_api_check": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "Skip the AWS Metadata API check.",
+				Default:     false,
+			},
+
+			"sse_customer_key": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The base64-encoded encryption key to use for server-side encryption with customer-provided keys (SSE-C).",
+				DefaultFunc: schema.EnvDefaultFunc("AWS_SSE_CUSTOMER_KEY", ""),
+				Sensitive:   true,
+				ValidateFunc: func(v interface{}, s string) ([]string, []error) {
+					key := v.(string)
+					if key != "" && len(key) != 44 {
+						return nil, []error{errors.New("sse_customer_key must be 44 characters in length (256 bits, base64 encoded)")}
+					}
+					return nil, nil
+				},
+			},
+
+			"role_arn": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The role to be assumed",
+				Default:     "",
+			},
+
+			"session_name": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The session name to use when assuming the role.",
+				Default:     "",
+			},
+
+			"external_id": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The external ID to use when assuming the role",
+				Default:     "",
+			},
+
+			"assume_role_duration_seconds": {
+				Type:        schema.TypeInt,
+				Optional:    true,
+				Description: "Seconds to restrict the assume role session duration.",
+			},
+
+			"assume_role_policy": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "IAM Policy JSON describing further restricting permissions for the IAM Role being assumed.",
+				Default:     "",
+			},
+
+			"assume_role_policy_arns": {
+				Type:        schema.TypeSet,
+				Optional:    true,
+				Description: "Amazon Resource Names (ARNs) of IAM Policies describing further restricting permissions for the IAM Role being assumed.",
+				Elem:        &schema.Schema{Type: schema.TypeString},
+			},
+
+			"assume_role_tags": {
+				Type:        schema.TypeMap,
+				Optional:    true,
+				Description: "Assume role session tags.",
+				Elem:        &schema.Schema{Type: schema.TypeString},
+			},
+
+			"assume_role_transitive_tag_keys": {
+				Type:        schema.TypeSet,
+				Optional:    true,
+				Description: "Assume role session tag keys to pass to any subsequent sessions.",
+				Elem:        &schema.Schema{Type: schema.TypeString},
+			},
+
+			"workspace_key_prefix": {
+				Type:        schema.TypeString,
+				Optional:    true,
+				Description: "The prefix applied to the non-default state path inside the bucket.",
+				Default:     "env:",
+				ValidateFunc: func(v interface{}, s string) ([]string, []error) {
+					prefix := v.(string)
+					if strings.HasPrefix(prefix, "/") || strings.HasSuffix(prefix, "/") {
+						return nil, []error{errors.New("workspace_key_prefix must not start or end with '/'")}
+					}
+					return nil, nil
+				},
+			},
+
+			"force_path_style": {
+				Type:        schema.TypeBool,
+				Optional:    true,
+				Description: "Force s3 to use path style api.",
+				Default:     false,
+			},
+
+			"max_retries": {
+				Type:        schema.TypeInt,
+				Optional:    true,
+				Description: "The maximum number of times an AWS API request is retried on retryable failure.",
+				Default:     5,
+			},
+		},
+	}
+
+	result := &Backend{Backend: s}
+	result.Backend.ConfigureFunc = result.configure
+	return result
+}
+
+type Backend struct {
+	*schema.Backend
+
+	// The fields below are set from configure
+	s3Client  *s3.S3
+	dynClient *dynamodb.DynamoDB
+
+	bucketName            string
+	keyName               string
+	serverSideEncryption  bool
+	customerEncryptionKey []byte
+	acl                   string
+	kmsKeyID              string
+	ddbTable              string
+	workspaceKeyPrefix    string
+}
+
+func (b *Backend) configure(ctx context.Context) error {
+	if b.s3Client != nil {
+		return nil
+	}
+
+	// Grab the resource data
+	data := schema.FromContextBackendConfig(ctx)
+
+	if !data.Get("skip_region_validation").(bool) {
+		if err := awsbase.ValidateRegion(data.Get("region").(string)); err != nil {
+			return err
+		}
+	}
+
+	b.bucketName = data.Get("bucket").(string)
+	b.keyName = data.Get("key").(string)
+	b.acl = data.Get("acl").(string)
+	b.workspaceKeyPrefix = data.Get("workspace_key_prefix").(string)
+	b.serverSideEncryption = data.Get("encrypt").(bool)
+	b.kmsKeyID = data.Get("kms_key_id").(string)
+	b.ddbTable = data.Get("dynamodb_table").(string)
+
+	customerKeyString := data.Get("sse_customer_key").(string)
+	if customerKeyString != "" {
+		if b.kmsKeyID != "" {
+			return errors.New(encryptionKeyConflictError)
+		}
+
+		var err error
+		b.customerEncryptionKey, err = base64.StdEncoding.DecodeString(customerKeyString)
+		if err != nil {
+			return fmt.Errorf("Failed to decode sse_customer_key: %s", err.Error())
+		}
+	}
+
+	cfg := &awsbase.Config{
+		AccessKey:                 data.Get("access_key").(string),
+		AssumeRoleARN:             data.Get("role_arn").(string),
+		AssumeRoleDurationSeconds: data.Get("assume_role_duration_seconds").(int),
+		AssumeRoleExternalID:      data.Get("external_id").(string),
+		AssumeRolePolicy:          data.Get("assume_role_policy").(string),
+		AssumeRoleSessionName:     data.Get("session_name").(string),
+		CallerDocumentationURL:    "https://www.terraform.io/docs/language/settings/backends/s3.html",
+		CallerName:                "S3 Backend",
+		CredsFilename:             data.Get("shared_credentials_file").(string),
+		DebugLogging:              logging.IsDebugOrHigher(),
+		IamEndpoint:               data.Get("iam_endpoint").(string),
+		MaxRetries:                data.Get("max_retries").(int),
+		Profile:                   data.Get("profile").(string),
+		Region:                    data.Get("region").(string),
+		SecretKey:                 data.Get("secret_key").(string),
+		SkipCredsValidation:       data.Get("skip_credentials_validation").(bool),
+		SkipMetadataApiCheck:      data.Get("skip_metadata_api_check").(bool),
+		StsEndpoint:               data.Get("sts_endpoint").(string),
+		Token:                     data.Get("token").(string),
+		UserAgentProducts: []*awsbase.UserAgentProduct{
+			{Name: "APN", Version: "1.0"},
+			{Name: "HashiCorp", Version: "1.0"},
+			{Name: "Terraform", Version: version.String()},
+		},
+	}
+
+	if policyARNSet := data.Get("assume_role_policy_arns").(*schema.Set); policyARNSet.Len() > 0 {
+		for _, policyARNRaw := range policyARNSet.List() {
+			policyARN, ok := policyARNRaw.(string)
+
+			if !ok {
+				continue
+			}
+
+			cfg.AssumeRolePolicyARNs = append(cfg.AssumeRolePolicyARNs, policyARN)
+		}
+	}
+
+	if tagMap := data.Get("assume_role_tags").(map[string]interface{}); len(tagMap) > 0 {
+		cfg.AssumeRoleTags = make(map[string]string)
+
+		for k, vRaw := range tagMap {
+			v, ok := vRaw.(string)
+
+			if !ok {
+				continue
+			}
+
+			cfg.AssumeRoleTags[k] = v
+		}
+	}
+
+	if transitiveTagKeySet := data.Get("assume_role_transitive_tag_keys").(*schema.Set); transitiveTagKeySet.Len() > 0 {
+		for _, transitiveTagKeyRaw := range transitiveTagKeySet.List() {
+			transitiveTagKey, ok := transitiveTagKeyRaw.(string)
+
+			if !ok {
+				continue
+			}
+
+			cfg.AssumeRoleTransitiveTagKeys = append(cfg.AssumeRoleTransitiveTagKeys, transitiveTagKey)
+		}
+	}
+
+	sess, err := awsbase.GetSession(cfg)
+	if err != nil {
+		return fmt.Errorf("error configuring S3 Backend: %w", err)
+	}
+
+	b.dynClient = dynamodb.New(sess.Copy(&aws.Config{
+		Endpoint: aws.String(data.Get("dynamodb_endpoint").(string)),
+	}))
+	b.s3Client = s3.New(sess.Copy(&aws.Config{
+		Endpoint:         aws.String(data.Get("endpoint").(string)),
+		S3ForcePathStyle: aws.Bool(data.Get("force_path_style").(bool)),
+	}))
+
+	return nil
+}
+
+const encryptionKeyConflictError = `Cannot have both kms_key_id and sse_customer_key set.
+
+The kms_key_id is used for encryption with KMS-Managed Keys (SSE-KMS)
+while sse_customer_key is used for encryption with customer-managed keys (SSE-C).
+Please choose one or the other.`
diff --git a/v1.5.7/internal/backend/remote-state/s3/backend_state.go b/v1.5.7/internal/backend/remote-state/s3/backend_state.go
new file mode 100644
index 0000000..add7d39
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/s3/backend_state.go
@@ -0,0 +1,224 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package s3
+
+import (
+	"errors"
+	"fmt"
+	"path"
+	"sort"
+	"strings"
+
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/awserr"
+	"github.com/aws/aws-sdk-go/service/s3"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+func (b *Backend) Workspaces() ([]string, error) {
+	const maxKeys = 1000
+
+	prefix := ""
+
+	if b.workspaceKeyPrefix != "" {
+		prefix = b.workspaceKeyPrefix + "/"
+	}
+
+	params := &s3.ListObjectsInput{
+		Bucket:  &b.bucketName,
+		Prefix:  aws.String(prefix),
+		MaxKeys: aws.Int64(maxKeys),
+	}
+
+	wss := []string{backend.DefaultStateName}
+	err := b.s3Client.ListObjectsPages(params, func(page *s3.ListObjectsOutput, lastPage bool) bool {
+		for _, obj := range page.Contents {
+			ws := b.keyEnv(*obj.Key)
+			if ws != "" {
+				wss = append(wss, ws)
+			}
+		}
+		return !lastPage
+	})
+
+	if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == s3.ErrCodeNoSuchBucket {
+		return nil, fmt.Errorf(errS3NoSuchBucket, err)
+	}
+
+	sort.Strings(wss[1:])
+	return wss, nil
+}
+
+func (b *Backend) keyEnv(key string) string {
+	prefix := b.workspaceKeyPrefix
+
+	if prefix == "" {
+		parts := strings.SplitN(key, "/", 2)
+		if len(parts) > 1 && parts[1] == b.keyName {
+			return parts[0]
+		} else {
+			return ""
+		}
+	}
+
+	// add a slash to treat this as a directory
+	prefix += "/"
+
+	parts := strings.SplitAfterN(key, prefix, 2)
+	if len(parts) < 2 {
+		return ""
+	}
+
+	// shouldn't happen since we listed by prefix
+	if parts[0] != prefix {
+		return ""
+	}
+
+	parts = strings.SplitN(parts[1], "/", 2)
+
+	if len(parts) < 2 {
+		return ""
+	}
+
+	// not our key, so don't include it in our listing
+	if parts[1] != b.keyName {
+		return ""
+	}
+
+	return parts[0]
+}
+
+func (b *Backend) DeleteWorkspace(name string, _ bool) error {
+	if name == backend.DefaultStateName || name == "" {
+		return fmt.Errorf("can't delete default state")
+	}
+
+	client, err := b.remoteClient(name)
+	if err != nil {
+		return err
+	}
+
+	return client.Delete()
+}
+
+// get a remote client configured for this state
+func (b *Backend) remoteClient(name string) (*RemoteClient, error) {
+	if name == "" {
+		return nil, errors.New("missing state name")
+	}
+
+	client := &RemoteClient{
+		s3Client:              b.s3Client,
+		dynClient:             b.dynClient,
+		bucketName:            b.bucketName,
+		path:                  b.path(name),
+		serverSideEncryption:  b.serverSideEncryption,
+		customerEncryptionKey: b.customerEncryptionKey,
+		acl:                   b.acl,
+		kmsKeyID:              b.kmsKeyID,
+		ddbTable:              b.ddbTable,
+	}
+
+	return client, nil
+}
+
+func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
+	client, err := b.remoteClient(name)
+	if err != nil {
+		return nil, err
+	}
+
+	stateMgr := &remote.State{Client: client}
+	// Check to see if this state already exists.
+	// If we're trying to force-unlock a state, we can't take the lock before
+	// fetching the state. If the state doesn't exist, we have to assume this
+	// is a normal create operation, and take the lock at that point.
+	//
+	// If we need to force-unlock, but for some reason the state no longer
+	// exists, the user will have to use aws tools to manually fix the
+	// situation.
+	existing, err := b.Workspaces()
+	if err != nil {
+		return nil, err
+	}
+
+	exists := false
+	for _, s := range existing {
+		if s == name {
+			exists = true
+			break
+		}
+	}
+
+	// We need to create the object so it's listed by States.
+	if !exists {
+		// take a lock on this state while we write it
+		lockInfo := statemgr.NewLockInfo()
+		lockInfo.Operation = "init"
+		lockId, err := client.Lock(lockInfo)
+		if err != nil {
+			return nil, fmt.Errorf("failed to lock s3 state: %s", err)
+		}
+
+		// Local helper function so we can call it multiple places
+		lockUnlock := func(parent error) error {
+			if err := stateMgr.Unlock(lockId); err != nil {
+				return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err)
+			}
+			return parent
+		}
+
+		// Grab the value
+		// This is to ensure that no one beat us to writing a state between
+		// the `exists` check and taking the lock.
+		if err := stateMgr.RefreshState(); err != nil {
+			err = lockUnlock(err)
+			return nil, err
+		}
+
+		// If we have no state, we have to create an empty state
+		if v := stateMgr.State(); v == nil {
+			if err := stateMgr.WriteState(states.NewState()); err != nil {
+				err = lockUnlock(err)
+				return nil, err
+			}
+			if err := stateMgr.PersistState(nil); err != nil {
+				err = lockUnlock(err)
+				return nil, err
+			}
+		}
+
+		// Unlock, the state should now be initialized
+		if err := lockUnlock(nil); err != nil {
+			return nil, err
+		}
+
+	}
+
+	return stateMgr, nil
+}
+
+func (b *Backend) client() *RemoteClient {
+	return &RemoteClient{}
+}
+
+func (b *Backend) path(name string) string {
+	if name == backend.DefaultStateName {
+		return b.keyName
+	}
+
+	return path.Join(b.workspaceKeyPrefix, name, b.keyName)
+}
+
+const errStateUnlock = `
+Error unlocking S3 state. Lock ID: %s
+
+Error: %s
+
+You may have to force-unlock this state in order to use it again.
+`
diff --git a/v1.5.7/internal/backend/remote-state/s3/backend_test.go b/v1.5.7/internal/backend/remote-state/s3/backend_test.go
new file mode 100644
index 0000000..92fe40b
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/s3/backend_test.go
@@ -0,0 +1,798 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package s3
+
+import (
+	"fmt"
+	"net/url"
+	"os"
+	"reflect"
+	"testing"
+	"time"
+
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/service/dynamodb"
+	"github.com/aws/aws-sdk-go/service/s3"
+	awsbase "github.com/hashicorp/aws-sdk-go-base"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/remote"
+)
+
+var (
+	mockStsGetCallerIdentityRequestBody = url.Values{
+		"Action":  []string{"GetCallerIdentity"},
+		"Version": []string{"2011-06-15"},
+	}.Encode()
+)
+
+// verify that we are doing ACC tests or the S3 tests specifically
+func testACC(t *testing.T) {
+	skip := os.Getenv("TF_ACC") == "" && os.Getenv("TF_S3_TEST") == ""
+	if skip {
+		t.Log("s3 backend tests require setting TF_ACC or TF_S3_TEST")
+		t.Skip()
+	}
+	if os.Getenv("AWS_DEFAULT_REGION") == "" {
+		os.Setenv("AWS_DEFAULT_REGION", "us-west-2")
+	}
+}
+
+func TestBackend_impl(t *testing.T) {
+	var _ backend.Backend = new(Backend)
+}
+
+func TestBackendConfig(t *testing.T) {
+	testACC(t)
+	config := map[string]interface{}{
+		"region":         "us-west-1",
+		"bucket":         "tf-test",
+		"key":            "state",
+		"encrypt":        true,
+		"dynamodb_table": "dynamoTable",
+	}
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(config)).(*Backend)
+
+	if *b.s3Client.Config.Region != "us-west-1" {
+		t.Fatalf("Incorrect region was populated")
+	}
+	if b.bucketName != "tf-test" {
+		t.Fatalf("Incorrect bucketName was populated")
+	}
+	if b.keyName != "state" {
+		t.Fatalf("Incorrect keyName was populated")
+	}
+
+	credentials, err := b.s3Client.Config.Credentials.Get()
+	if err != nil {
+		t.Fatalf("Error when requesting credentials")
+	}
+	if credentials.AccessKeyID == "" {
+		t.Fatalf("No Access Key Id was populated")
+	}
+	if credentials.SecretAccessKey == "" {
+		t.Fatalf("No Secret Access Key was populated")
+	}
+}
+
+func TestBackendConfig_AssumeRole(t *testing.T) {
+	testACC(t)
+
+	testCases := []struct {
+		Config           map[string]interface{}
+		Description      string
+		MockStsEndpoints []*awsbase.MockEndpoint
+	}{
+		{
+			Config: map[string]interface{}{
+				"bucket":       "tf-test",
+				"key":          "state",
+				"region":       "us-west-1",
+				"role_arn":     awsbase.MockStsAssumeRoleArn,
+				"session_name": awsbase.MockStsAssumeRoleSessionName,
+			},
+			Description: "role_arn",
+			MockStsEndpoints: []*awsbase.MockEndpoint{
+				{
+					Request: &awsbase.MockRequest{Method: "POST", Uri: "/", Body: url.Values{
+						"Action":          []string{"AssumeRole"},
+						"DurationSeconds": []string{"900"},
+						"RoleArn":         []string{awsbase.MockStsAssumeRoleArn},
+						"RoleSessionName": []string{awsbase.MockStsAssumeRoleSessionName},
+						"Version":         []string{"2011-06-15"},
+					}.Encode()},
+					Response: &awsbase.MockResponse{StatusCode: 200, Body: awsbase.MockStsAssumeRoleValidResponseBody, ContentType: "text/xml"},
+				},
+				{
+					Request:  &awsbase.MockRequest{Method: "POST", Uri: "/", Body: mockStsGetCallerIdentityRequestBody},
+					Response: &awsbase.MockResponse{StatusCode: 200, Body: awsbase.MockStsGetCallerIdentityValidResponseBody, ContentType: "text/xml"},
+				},
+			},
+		},
+		{
+			Config: map[string]interface{}{
+				"assume_role_duration_seconds": 3600,
+				"bucket":                       "tf-test",
+				"key":                          "state",
+				"region":                       "us-west-1",
+				"role_arn":                     awsbase.MockStsAssumeRoleArn,
+				"session_name":                 awsbase.MockStsAssumeRoleSessionName,
+			},
+			Description: "assume_role_duration_seconds",
+			MockStsEndpoints: []*awsbase.MockEndpoint{
+				{
+					Request: &awsbase.MockRequest{Method: "POST", Uri: "/", Body: url.Values{
+						"Action":          []string{"AssumeRole"},
+						"DurationSeconds": []string{"3600"},
+						"RoleArn":         []string{awsbase.MockStsAssumeRoleArn},
+						"RoleSessionName": []string{awsbase.MockStsAssumeRoleSessionName},
+						"Version":         []string{"2011-06-15"},
+					}.Encode()},
+					Response: &awsbase.MockResponse{StatusCode: 200, Body: awsbase.MockStsAssumeRoleValidResponseBody, ContentType: "text/xml"},
+				},
+				{
+					Request:  &awsbase.MockRequest{Method: "POST", Uri: "/", Body: mockStsGetCallerIdentityRequestBody},
+					Response: &awsbase.MockResponse{StatusCode: 200, Body: awsbase.MockStsGetCallerIdentityValidResponseBody, ContentType: "text/xml"},
+				},
+			},
+		},
+		{
+			Config: map[string]interface{}{
+				"bucket":       "tf-test",
+				"external_id":  awsbase.MockStsAssumeRoleExternalId,
+				"key":          "state",
+				"region":       "us-west-1",
+				"role_arn":     awsbase.MockStsAssumeRoleArn,
+				"session_name": awsbase.MockStsAssumeRoleSessionName,
+			},
+			Description: "external_id",
+			MockStsEndpoints: []*awsbase.MockEndpoint{
+				{
+					Request: &awsbase.MockRequest{Method: "POST", Uri: "/", Body: url.Values{
+						"Action":          []string{"AssumeRole"},
+						"DurationSeconds": []string{"900"},
+						"ExternalId":      []string{awsbase.MockStsAssumeRoleExternalId},
+						"RoleArn":         []string{awsbase.MockStsAssumeRoleArn},
+						"RoleSessionName": []string{awsbase.MockStsAssumeRoleSessionName},
+						"Version":         []string{"2011-06-15"},
+					}.Encode()},
+					Response: &awsbase.MockResponse{StatusCode: 200, Body: awsbase.MockStsAssumeRoleValidResponseBody, ContentType: "text/xml"},
+				},
+				{
+					Request:  &awsbase.MockRequest{Method: "POST", Uri: "/", Body: mockStsGetCallerIdentityRequestBody},
+					Response: &awsbase.MockResponse{StatusCode: 200, Body: awsbase.MockStsGetCallerIdentityValidResponseBody, ContentType: "text/xml"},
+				},
+			},
+		},
+		{
+			Config: map[string]interface{}{
+				"assume_role_policy": awsbase.MockStsAssumeRolePolicy,
+				"bucket":             "tf-test",
+				"key":                "state",
+				"region":             "us-west-1",
+				"role_arn":           awsbase.MockStsAssumeRoleArn,
+				"session_name":       awsbase.MockStsAssumeRoleSessionName,
+			},
+			Description: "assume_role_policy",
+			MockStsEndpoints: []*awsbase.MockEndpoint{
+				{
+					Request: &awsbase.MockRequest{Method: "POST", Uri: "/", Body: url.Values{
+						"Action":          []string{"AssumeRole"},
+						"DurationSeconds": []string{"900"},
+						"Policy":          []string{awsbase.MockStsAssumeRolePolicy},
+						"RoleArn":         []string{awsbase.MockStsAssumeRoleArn},
+						"RoleSessionName": []string{awsbase.MockStsAssumeRoleSessionName},
+						"Version":         []string{"2011-06-15"},
+					}.Encode()},
+					Response: &awsbase.MockResponse{StatusCode: 200, Body: awsbase.MockStsAssumeRoleValidResponseBody, ContentType: "text/xml"},
+				},
+				{
+					Request:  &awsbase.MockRequest{Method: "POST", Uri: "/", Body: mockStsGetCallerIdentityRequestBody},
+					Response: &awsbase.MockResponse{StatusCode: 200, Body: awsbase.MockStsGetCallerIdentityValidResponseBody, ContentType: "text/xml"},
+				},
+			},
+		},
+		{
+			Config: map[string]interface{}{
+				"assume_role_policy_arns": []interface{}{awsbase.MockStsAssumeRolePolicyArn},
+				"bucket":                  "tf-test",
+				"key":                     "state",
+				"region":                  "us-west-1",
+				"role_arn":                awsbase.MockStsAssumeRoleArn,
+				"session_name":            awsbase.MockStsAssumeRoleSessionName,
+			},
+			Description: "assume_role_policy_arns",
+			MockStsEndpoints: []*awsbase.MockEndpoint{
+				{
+					Request: &awsbase.MockRequest{Method: "POST", Uri: "/", Body: url.Values{
+						"Action":                  []string{"AssumeRole"},
+						"DurationSeconds":         []string{"900"},
+						"PolicyArns.member.1.arn": []string{awsbase.MockStsAssumeRolePolicyArn},
+						"RoleArn":                 []string{awsbase.MockStsAssumeRoleArn},
+						"RoleSessionName":         []string{awsbase.MockStsAssumeRoleSessionName},
+						"Version":                 []string{"2011-06-15"},
+					}.Encode()},
+					Response: &awsbase.MockResponse{StatusCode: 200, Body: awsbase.MockStsAssumeRoleValidResponseBody, ContentType: "text/xml"},
+				},
+				{
+					Request:  &awsbase.MockRequest{Method: "POST", Uri: "/", Body: mockStsGetCallerIdentityRequestBody},
+					Response: &awsbase.MockResponse{StatusCode: 200, Body: awsbase.MockStsGetCallerIdentityValidResponseBody, ContentType: "text/xml"},
+				},
+			},
+		},
+		{
+			Config: map[string]interface{}{
+				"assume_role_tags": map[string]interface{}{
+					awsbase.MockStsAssumeRoleTagKey: awsbase.MockStsAssumeRoleTagValue,
+				},
+				"bucket":       "tf-test",
+				"key":          "state",
+				"region":       "us-west-1",
+				"role_arn":     awsbase.MockStsAssumeRoleArn,
+				"session_name": awsbase.MockStsAssumeRoleSessionName,
+			},
+			Description: "assume_role_tags",
+			MockStsEndpoints: []*awsbase.MockEndpoint{
+				{
+					Request: &awsbase.MockRequest{Method: "POST", Uri: "/", Body: url.Values{
+						"Action":              []string{"AssumeRole"},
+						"DurationSeconds":     []string{"900"},
+						"RoleArn":             []string{awsbase.MockStsAssumeRoleArn},
+						"RoleSessionName":     []string{awsbase.MockStsAssumeRoleSessionName},
+						"Tags.member.1.Key":   []string{awsbase.MockStsAssumeRoleTagKey},
+						"Tags.member.1.Value": []string{awsbase.MockStsAssumeRoleTagValue},
+						"Version":             []string{"2011-06-15"},
+					}.Encode()},
+					Response: &awsbase.MockResponse{StatusCode: 200, Body: awsbase.MockStsAssumeRoleValidResponseBody, ContentType: "text/xml"},
+				},
+				{
+					Request:  &awsbase.MockRequest{Method: "POST", Uri: "/", Body: mockStsGetCallerIdentityRequestBody},
+					Response: &awsbase.MockResponse{StatusCode: 200, Body: awsbase.MockStsGetCallerIdentityValidResponseBody, ContentType: "text/xml"},
+				},
+			},
+		},
+		{
+			Config: map[string]interface{}{
+				"assume_role_tags": map[string]interface{}{
+					awsbase.MockStsAssumeRoleTagKey: awsbase.MockStsAssumeRoleTagValue,
+				},
+				"assume_role_transitive_tag_keys": []interface{}{awsbase.MockStsAssumeRoleTagKey},
+				"bucket":                          "tf-test",
+				"key":                             "state",
+				"region":                          "us-west-1",
+				"role_arn":                        awsbase.MockStsAssumeRoleArn,
+				"session_name":                    awsbase.MockStsAssumeRoleSessionName,
+			},
+			Description: "assume_role_transitive_tag_keys",
+			MockStsEndpoints: []*awsbase.MockEndpoint{
+				{
+					Request: &awsbase.MockRequest{Method: "POST", Uri: "/", Body: url.Values{
+						"Action":                     []string{"AssumeRole"},
+						"DurationSeconds":            []string{"900"},
+						"RoleArn":                    []string{awsbase.MockStsAssumeRoleArn},
+						"RoleSessionName":            []string{awsbase.MockStsAssumeRoleSessionName},
+						"Tags.member.1.Key":          []string{awsbase.MockStsAssumeRoleTagKey},
+						"Tags.member.1.Value":        []string{awsbase.MockStsAssumeRoleTagValue},
+						"TransitiveTagKeys.member.1": []string{awsbase.MockStsAssumeRoleTagKey},
+						"Version":                    []string{"2011-06-15"},
+					}.Encode()},
+					Response: &awsbase.MockResponse{StatusCode: 200, Body: awsbase.MockStsAssumeRoleValidResponseBody, ContentType: "text/xml"},
+				},
+				{
+					Request:  &awsbase.MockRequest{Method: "POST", Uri: "/", Body: mockStsGetCallerIdentityRequestBody},
+					Response: &awsbase.MockResponse{StatusCode: 200, Body: awsbase.MockStsGetCallerIdentityValidResponseBody, ContentType: "text/xml"},
+				},
+			},
+		},
+	}
+
+	for _, testCase := range testCases {
+		testCase := testCase
+
+		t.Run(testCase.Description, func(t *testing.T) {
+			closeSts, mockStsSession, err := awsbase.GetMockedAwsApiSession("STS", testCase.MockStsEndpoints)
+			defer closeSts()
+
+			if err != nil {
+				t.Fatalf("unexpected error creating mock STS server: %s", err)
+			}
+
+			if mockStsSession != nil && mockStsSession.Config != nil {
+				testCase.Config["sts_endpoint"] = aws.StringValue(mockStsSession.Config.Endpoint)
+			}
+
+			diags := New().Configure(hcl2shim.HCL2ValueFromConfigValue(testCase.Config))
+
+			if diags.HasErrors() {
+				for _, diag := range diags {
+					t.Errorf("unexpected error: %s", diag.Description().Summary)
+				}
+			}
+		})
+	}
+}
+
+func TestBackendConfig_invalidKey(t *testing.T) {
+	testACC(t)
+	cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{
+		"region":         "us-west-1",
+		"bucket":         "tf-test",
+		"key":            "/leading-slash",
+		"encrypt":        true,
+		"dynamodb_table": "dynamoTable",
+	})
+
+	_, diags := New().PrepareConfig(cfg)
+	if !diags.HasErrors() {
+		t.Fatal("expected config validation error")
+	}
+
+	cfg = hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{
+		"region":         "us-west-1",
+		"bucket":         "tf-test",
+		"key":            "trailing-slash/",
+		"encrypt":        true,
+		"dynamodb_table": "dynamoTable",
+	})
+
+	_, diags = New().PrepareConfig(cfg)
+	if !diags.HasErrors() {
+		t.Fatal("expected config validation error")
+	}
+}
+
+func TestBackendConfig_invalidSSECustomerKeyLength(t *testing.T) {
+	testACC(t)
+	cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{
+		"region":           "us-west-1",
+		"bucket":           "tf-test",
+		"encrypt":          true,
+		"key":              "state",
+		"dynamodb_table":   "dynamoTable",
+		"sse_customer_key": "key",
+	})
+
+	_, diags := New().PrepareConfig(cfg)
+	if !diags.HasErrors() {
+		t.Fatal("expected error for invalid sse_customer_key length")
+	}
+}
+
+func TestBackendConfig_invalidSSECustomerKeyEncoding(t *testing.T) {
+	testACC(t)
+	cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{
+		"region":           "us-west-1",
+		"bucket":           "tf-test",
+		"encrypt":          true,
+		"key":              "state",
+		"dynamodb_table":   "dynamoTable",
+		"sse_customer_key": "====CT70aTYB2JGff7AjQtwbiLkwH4npICay1PWtmdka",
+	})
+
+	diags := New().Configure(cfg)
+	if !diags.HasErrors() {
+		t.Fatal("expected error for failing to decode sse_customer_key")
+	}
+}
+
+func TestBackendConfig_conflictingEncryptionSchema(t *testing.T) {
+	testACC(t)
+	cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{
+		"region":           "us-west-1",
+		"bucket":           "tf-test",
+		"key":              "state",
+		"encrypt":          true,
+		"dynamodb_table":   "dynamoTable",
+		"sse_customer_key": "1hwbcNPGWL+AwDiyGmRidTWAEVmCWMKbEHA+Es8w75o=",
+		"kms_key_id":       "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab",
+	})
+
+	diags := New().Configure(cfg)
+	if !diags.HasErrors() {
+		t.Fatal("expected error for simultaneous usage of kms_key_id and sse_customer_key")
+	}
+}
+
+func TestBackend(t *testing.T) {
+	testACC(t)
+
+	bucketName := fmt.Sprintf("terraform-remote-s3-test-%x", time.Now().Unix())
+	keyName := "testState"
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":  bucketName,
+		"key":     keyName,
+		"encrypt": true,
+	})).(*Backend)
+
+	createS3Bucket(t, b.s3Client, bucketName)
+	defer deleteS3Bucket(t, b.s3Client, bucketName)
+
+	backend.TestBackendStates(t, b)
+}
+
+func TestBackendLocked(t *testing.T) {
+	testACC(t)
+
+	bucketName := fmt.Sprintf("terraform-remote-s3-test-%x", time.Now().Unix())
+	keyName := "test/state"
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":         bucketName,
+		"key":            keyName,
+		"encrypt":        true,
+		"dynamodb_table": bucketName,
+	})).(*Backend)
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":         bucketName,
+		"key":            keyName,
+		"encrypt":        true,
+		"dynamodb_table": bucketName,
+	})).(*Backend)
+
+	createS3Bucket(t, b1.s3Client, bucketName)
+	defer deleteS3Bucket(t, b1.s3Client, bucketName)
+	createDynamoDBTable(t, b1.dynClient, bucketName)
+	defer deleteDynamoDBTable(t, b1.dynClient, bucketName)
+
+	backend.TestBackendStateLocks(t, b1, b2)
+	backend.TestBackendStateForceUnlock(t, b1, b2)
+}
+
+func TestBackendSSECustomerKey(t *testing.T) {
+	testACC(t)
+	bucketName := fmt.Sprintf("terraform-remote-s3-test-%x", time.Now().Unix())
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":           bucketName,
+		"encrypt":          true,
+		"key":              "test-SSE-C",
+		"sse_customer_key": "4Dm1n4rphuFgawxuzY/bEfvLf6rYK0gIjfaDSLlfXNk=",
+	})).(*Backend)
+
+	createS3Bucket(t, b.s3Client, bucketName)
+	defer deleteS3Bucket(t, b.s3Client, bucketName)
+
+	backend.TestBackendStates(t, b)
+}
+
+// add some extra junk in S3 to try and confuse the env listing.
+func TestBackendExtraPaths(t *testing.T) {
+	testACC(t)
+	bucketName := fmt.Sprintf("terraform-remote-s3-test-%x", time.Now().Unix())
+	keyName := "test/state/tfstate"
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":  bucketName,
+		"key":     keyName,
+		"encrypt": true,
+	})).(*Backend)
+
+	createS3Bucket(t, b.s3Client, bucketName)
+	defer deleteS3Bucket(t, b.s3Client, bucketName)
+
+	// put multiple states in old env paths.
+	s1 := states.NewState()
+	s2 := states.NewState()
+
+	// RemoteClient to Put things in various paths
+	client := &RemoteClient{
+		s3Client:             b.s3Client,
+		dynClient:            b.dynClient,
+		bucketName:           b.bucketName,
+		path:                 b.path("s1"),
+		serverSideEncryption: b.serverSideEncryption,
+		acl:                  b.acl,
+		kmsKeyID:             b.kmsKeyID,
+		ddbTable:             b.ddbTable,
+	}
+
+	// Write the first state
+	stateMgr := &remote.State{Client: client}
+	stateMgr.WriteState(s1)
+	if err := stateMgr.PersistState(nil); err != nil {
+		t.Fatal(err)
+	}
+
+	// Write the second state
+	// Note a new state manager - otherwise, because these
+	// states are equal, the state will not Put to the remote
+	client.path = b.path("s2")
+	stateMgr2 := &remote.State{Client: client}
+	stateMgr2.WriteState(s2)
+	if err := stateMgr2.PersistState(nil); err != nil {
+		t.Fatal(err)
+	}
+
+	s2Lineage := stateMgr2.StateSnapshotMeta().Lineage
+
+	if err := checkStateList(b, []string{"default", "s1", "s2"}); err != nil {
+		t.Fatal(err)
+	}
+
+	// put a state in an env directory name
+	client.path = b.workspaceKeyPrefix + "/error"
+	stateMgr.WriteState(states.NewState())
+	if err := stateMgr.PersistState(nil); err != nil {
+		t.Fatal(err)
+	}
+	if err := checkStateList(b, []string{"default", "s1", "s2"}); err != nil {
+		t.Fatal(err)
+	}
+
+	// add state with the wrong key for an existing env
+	client.path = b.workspaceKeyPrefix + "/s2/notTestState"
+	stateMgr.WriteState(states.NewState())
+	if err := stateMgr.PersistState(nil); err != nil {
+		t.Fatal(err)
+	}
+	if err := checkStateList(b, []string{"default", "s1", "s2"}); err != nil {
+		t.Fatal(err)
+	}
+
+	// remove the state with extra subkey
+	if err := client.Delete(); err != nil {
+		t.Fatal(err)
+	}
+
+	// delete the real workspace
+	if err := b.DeleteWorkspace("s2", true); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := checkStateList(b, []string{"default", "s1"}); err != nil {
+		t.Fatal(err)
+	}
+
+	// fetch that state again, which should produce a new lineage
+	s2Mgr, err := b.StateMgr("s2")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := s2Mgr.RefreshState(); err != nil {
+		t.Fatal(err)
+	}
+
+	if s2Mgr.(*remote.State).StateSnapshotMeta().Lineage == s2Lineage {
+		t.Fatal("state s2 was not deleted")
+	}
+	s2 = s2Mgr.State()
+	s2Lineage = stateMgr.StateSnapshotMeta().Lineage
+
+	// add a state with a key that matches an existing environment dir name
+	client.path = b.workspaceKeyPrefix + "/s2/"
+	stateMgr.WriteState(states.NewState())
+	if err := stateMgr.PersistState(nil); err != nil {
+		t.Fatal(err)
+	}
+
+	// make sure s2 is OK
+	s2Mgr, err = b.StateMgr("s2")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := s2Mgr.RefreshState(); err != nil {
+		t.Fatal(err)
+	}
+
+	if stateMgr.StateSnapshotMeta().Lineage != s2Lineage {
+		t.Fatal("we got the wrong state for s2")
+	}
+
+	if err := checkStateList(b, []string{"default", "s1", "s2"}); err != nil {
+		t.Fatal(err)
+	}
+}
+
+// ensure we can separate the workspace prefix when it also matches the prefix
+// of the workspace name itself.
+func TestBackendPrefixInWorkspace(t *testing.T) {
+	testACC(t)
+	bucketName := fmt.Sprintf("terraform-remote-s3-test-%x", time.Now().Unix())
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":               bucketName,
+		"key":                  "test-env.tfstate",
+		"workspace_key_prefix": "env",
+	})).(*Backend)
+
+	createS3Bucket(t, b.s3Client, bucketName)
+	defer deleteS3Bucket(t, b.s3Client, bucketName)
+
+	// get a state that contains the prefix as a substring
+	sMgr, err := b.StateMgr("env-1")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := sMgr.RefreshState(); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := checkStateList(b, []string{"default", "env-1"}); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestKeyEnv(t *testing.T) {
+	testACC(t)
+	keyName := "some/paths/tfstate"
+
+	bucket0Name := fmt.Sprintf("terraform-remote-s3-test-%x-0", time.Now().Unix())
+	b0 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":               bucket0Name,
+		"key":                  keyName,
+		"encrypt":              true,
+		"workspace_key_prefix": "",
+	})).(*Backend)
+
+	createS3Bucket(t, b0.s3Client, bucket0Name)
+	defer deleteS3Bucket(t, b0.s3Client, bucket0Name)
+
+	bucket1Name := fmt.Sprintf("terraform-remote-s3-test-%x-1", time.Now().Unix())
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":               bucket1Name,
+		"key":                  keyName,
+		"encrypt":              true,
+		"workspace_key_prefix": "project/env:",
+	})).(*Backend)
+
+	createS3Bucket(t, b1.s3Client, bucket1Name)
+	defer deleteS3Bucket(t, b1.s3Client, bucket1Name)
+
+	bucket2Name := fmt.Sprintf("terraform-remote-s3-test-%x-2", time.Now().Unix())
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":  bucket2Name,
+		"key":     keyName,
+		"encrypt": true,
+	})).(*Backend)
+
+	createS3Bucket(t, b2.s3Client, bucket2Name)
+	defer deleteS3Bucket(t, b2.s3Client, bucket2Name)
+
+	if err := testGetWorkspaceForKey(b0, "some/paths/tfstate", ""); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := testGetWorkspaceForKey(b0, "ws1/some/paths/tfstate", "ws1"); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := testGetWorkspaceForKey(b1, "project/env:/ws1/some/paths/tfstate", "ws1"); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := testGetWorkspaceForKey(b1, "project/env:/ws2/some/paths/tfstate", "ws2"); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := testGetWorkspaceForKey(b2, "env:/ws3/some/paths/tfstate", "ws3"); err != nil {
+		t.Fatal(err)
+	}
+
+	backend.TestBackendStates(t, b0)
+	backend.TestBackendStates(t, b1)
+	backend.TestBackendStates(t, b2)
+}
+
+func testGetWorkspaceForKey(b *Backend, key string, expected string) error {
+	if actual := b.keyEnv(key); actual != expected {
+		return fmt.Errorf("incorrect workspace for key[%q]. Expected[%q]: Actual[%q]", key, expected, actual)
+	}
+	return nil
+}
+
+func checkStateList(b backend.Backend, expected []string) error {
+	states, err := b.Workspaces()
+	if err != nil {
+		return err
+	}
+
+	if !reflect.DeepEqual(states, expected) {
+		return fmt.Errorf("incorrect states listed: %q", states)
+	}
+	return nil
+}
+
+func createS3Bucket(t *testing.T, s3Client *s3.S3, bucketName string) {
+	createBucketReq := &s3.CreateBucketInput{
+		Bucket: &bucketName,
+	}
+
+	// Be clear about what we're doing in case the user needs to clean
+	// this up later.
+	t.Logf("creating S3 bucket %s in %s", bucketName, *s3Client.Config.Region)
+	_, err := s3Client.CreateBucket(createBucketReq)
+	if err != nil {
+		t.Fatal("failed to create test S3 bucket:", err)
+	}
+}
+
+func deleteS3Bucket(t *testing.T, s3Client *s3.S3, bucketName string) {
+	warning := "WARNING: Failed to delete the test S3 bucket. It may have been left in your AWS account and may incur storage charges. (error was %s)"
+
+	// first we have to get rid of the env objects, or we can't delete the bucket
+	resp, err := s3Client.ListObjects(&s3.ListObjectsInput{Bucket: &bucketName})
+	if err != nil {
+		t.Logf(warning, err)
+		return
+	}
+	for _, obj := range resp.Contents {
+		if _, err := s3Client.DeleteObject(&s3.DeleteObjectInput{Bucket: &bucketName, Key: obj.Key}); err != nil {
+			// this will need cleanup no matter what, so just warn and exit
+			t.Logf(warning, err)
+			return
+		}
+	}
+
+	if _, err := s3Client.DeleteBucket(&s3.DeleteBucketInput{Bucket: &bucketName}); err != nil {
+		t.Logf(warning, err)
+	}
+}
+
+// create the dynamoDB table, and wait until we can query it.
+func createDynamoDBTable(t *testing.T, dynClient *dynamodb.DynamoDB, tableName string) {
+	createInput := &dynamodb.CreateTableInput{
+		AttributeDefinitions: []*dynamodb.AttributeDefinition{
+			{
+				AttributeName: aws.String("LockID"),
+				AttributeType: aws.String("S"),
+			},
+		},
+		KeySchema: []*dynamodb.KeySchemaElement{
+			{
+				AttributeName: aws.String("LockID"),
+				KeyType:       aws.String("HASH"),
+			},
+		},
+		ProvisionedThroughput: &dynamodb.ProvisionedThroughput{
+			ReadCapacityUnits:  aws.Int64(5),
+			WriteCapacityUnits: aws.Int64(5),
+		},
+		TableName: aws.String(tableName),
+	}
+
+	_, err := dynClient.CreateTable(createInput)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// now wait until it's ACTIVE
+	start := time.Now()
+	time.Sleep(time.Second)
+
+	describeInput := &dynamodb.DescribeTableInput{
+		TableName: aws.String(tableName),
+	}
+
+	for {
+		resp, err := dynClient.DescribeTable(describeInput)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if *resp.Table.TableStatus == "ACTIVE" {
+			return
+		}
+
+		if time.Since(start) > time.Minute {
+			t.Fatalf("timed out creating DynamoDB table %s", tableName)
+		}
+
+		time.Sleep(3 * time.Second)
+	}
+
+}
+
+func deleteDynamoDBTable(t *testing.T, dynClient *dynamodb.DynamoDB, tableName string) {
+	params := &dynamodb.DeleteTableInput{
+		TableName: aws.String(tableName),
+	}
+	_, err := dynClient.DeleteTable(params)
+	if err != nil {
+		t.Logf("WARNING: Failed to delete the test DynamoDB table %q. It has been left in your AWS account and may incur charges. (error was %s)", tableName, err)
+	}
+}
diff --git a/v1.5.7/internal/backend/remote-state/s3/client.go b/v1.5.7/internal/backend/remote-state/s3/client.go
new file mode 100644
index 0000000..5df548c
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/s3/client.go
@@ -0,0 +1,425 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package s3
+
+import (
+	"bytes"
+	"crypto/md5"
+	"encoding/base64"
+	"encoding/hex"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"log"
+	"time"
+
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/awserr"
+	"github.com/aws/aws-sdk-go/service/dynamodb"
+	"github.com/aws/aws-sdk-go/service/s3"
+	multierror "github.com/hashicorp/go-multierror"
+	uuid "github.com/hashicorp/go-uuid"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+// Store the last saved serial in dynamo with this suffix for consistency checks.
+const (
+	s3EncryptionAlgorithm  = "AES256"
+	stateIDSuffix          = "-md5"
+	s3ErrCodeInternalError = "InternalError"
+)
+
+type RemoteClient struct {
+	s3Client              *s3.S3
+	dynClient             *dynamodb.DynamoDB
+	bucketName            string
+	path                  string
+	serverSideEncryption  bool
+	customerEncryptionKey []byte
+	acl                   string
+	kmsKeyID              string
+	ddbTable              string
+}
+
+var (
+	// The amount of time we will retry a state waiting for it to match the
+	// expected checksum.
+	consistencyRetryTimeout = 10 * time.Second
+
+	// delay when polling the state
+	consistencyRetryPollInterval = 2 * time.Second
+)
+
+// test hook called when checksums don't match
+var testChecksumHook func()
+
+func (c *RemoteClient) Get() (payload *remote.Payload, err error) {
+	deadline := time.Now().Add(consistencyRetryTimeout)
+
+	// If we have a checksum, and the returned payload doesn't match, we retry
+	// up until deadline.
+	for {
+		payload, err = c.get()
+		if err != nil {
+			return nil, err
+		}
+
+		// If the remote state was manually removed the payload will be nil,
+		// but if there's still a digest entry for that state we will still try
+		// to compare the MD5 below.
+		var digest []byte
+		if payload != nil {
+			digest = payload.MD5
+		}
+
+		// verify that this state is what we expect
+		if expected, err := c.getMD5(); err != nil {
+			log.Printf("[WARN] failed to fetch state md5: %s", err)
+		} else if len(expected) > 0 && !bytes.Equal(expected, digest) {
+			log.Printf("[WARN] state md5 mismatch: expected '%x', got '%x'", expected, digest)
+
+			if testChecksumHook != nil {
+				testChecksumHook()
+			}
+
+			if time.Now().Before(deadline) {
+				time.Sleep(consistencyRetryPollInterval)
+				log.Println("[INFO] retrying S3 RemoteClient.Get...")
+				continue
+			}
+
+			return nil, fmt.Errorf(errBadChecksumFmt, digest)
+		}
+
+		break
+	}
+
+	return payload, err
+}
+
+func (c *RemoteClient) get() (*remote.Payload, error) {
+	var output *s3.GetObjectOutput
+	var err error
+
+	input := &s3.GetObjectInput{
+		Bucket: &c.bucketName,
+		Key:    &c.path,
+	}
+
+	if c.serverSideEncryption && c.customerEncryptionKey != nil {
+		input.SetSSECustomerKey(string(c.customerEncryptionKey))
+		input.SetSSECustomerAlgorithm(s3EncryptionAlgorithm)
+		input.SetSSECustomerKeyMD5(c.getSSECustomerKeyMD5())
+	}
+
+	output, err = c.s3Client.GetObject(input)
+
+	if err != nil {
+		if awserr, ok := err.(awserr.Error); ok {
+			switch awserr.Code() {
+			case s3.ErrCodeNoSuchBucket:
+				return nil, fmt.Errorf(errS3NoSuchBucket, err)
+			case s3.ErrCodeNoSuchKey:
+				return nil, nil
+			}
+		}
+		return nil, err
+	}
+
+	defer output.Body.Close()
+
+	buf := bytes.NewBuffer(nil)
+	if _, err := io.Copy(buf, output.Body); err != nil {
+		return nil, fmt.Errorf("Failed to read remote state: %s", err)
+	}
+
+	sum := md5.Sum(buf.Bytes())
+	payload := &remote.Payload{
+		Data: buf.Bytes(),
+		MD5:  sum[:],
+	}
+
+	// If there was no data, then return nil
+	if len(payload.Data) == 0 {
+		return nil, nil
+	}
+
+	return payload, nil
+}
+
+func (c *RemoteClient) Put(data []byte) error {
+	contentType := "application/json"
+	contentLength := int64(len(data))
+
+	i := &s3.PutObjectInput{
+		ContentType:   &contentType,
+		ContentLength: &contentLength,
+		Body:          bytes.NewReader(data),
+		Bucket:        &c.bucketName,
+		Key:           &c.path,
+	}
+
+	if c.serverSideEncryption {
+		if c.kmsKeyID != "" {
+			i.SSEKMSKeyId = &c.kmsKeyID
+			i.ServerSideEncryption = aws.String("aws:kms")
+		} else if c.customerEncryptionKey != nil {
+			i.SetSSECustomerKey(string(c.customerEncryptionKey))
+			i.SetSSECustomerAlgorithm(s3EncryptionAlgorithm)
+			i.SetSSECustomerKeyMD5(c.getSSECustomerKeyMD5())
+		} else {
+			i.ServerSideEncryption = aws.String(s3EncryptionAlgorithm)
+		}
+	}
+
+	if c.acl != "" {
+		i.ACL = aws.String(c.acl)
+	}
+
+	log.Printf("[DEBUG] Uploading remote state to S3: %#v", i)
+
+	_, err := c.s3Client.PutObject(i)
+	if err != nil {
+		return fmt.Errorf("failed to upload state: %s", err)
+	}
+
+	sum := md5.Sum(data)
+	if err := c.putMD5(sum[:]); err != nil {
+		// if this errors out, we unfortunately have to error out altogether,
+		// since the next Get will inevitably fail.
+		return fmt.Errorf("failed to store state MD5: %s", err)
+
+	}
+
+	return nil
+}
+
+func (c *RemoteClient) Delete() error {
+	_, err := c.s3Client.DeleteObject(&s3.DeleteObjectInput{
+		Bucket: &c.bucketName,
+		Key:    &c.path,
+	})
+
+	if err != nil {
+		return err
+	}
+
+	if err := c.deleteMD5(); err != nil {
+		log.Printf("error deleting state md5: %s", err)
+	}
+
+	return nil
+}
+
+func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {
+	if c.ddbTable == "" {
+		return "", nil
+	}
+
+	info.Path = c.lockPath()
+
+	if info.ID == "" {
+		lockID, err := uuid.GenerateUUID()
+		if err != nil {
+			return "", err
+		}
+
+		info.ID = lockID
+	}
+
+	putParams := &dynamodb.PutItemInput{
+		Item: map[string]*dynamodb.AttributeValue{
+			"LockID": {S: aws.String(c.lockPath())},
+			"Info":   {S: aws.String(string(info.Marshal()))},
+		},
+		TableName:           aws.String(c.ddbTable),
+		ConditionExpression: aws.String("attribute_not_exists(LockID)"),
+	}
+	_, err := c.dynClient.PutItem(putParams)
+
+	if err != nil {
+		lockInfo, infoErr := c.getLockInfo()
+		if infoErr != nil {
+			err = multierror.Append(err, infoErr)
+		}
+
+		lockErr := &statemgr.LockError{
+			Err:  err,
+			Info: lockInfo,
+		}
+		return "", lockErr
+	}
+
+	return info.ID, nil
+}
+
+func (c *RemoteClient) getMD5() ([]byte, error) {
+	if c.ddbTable == "" {
+		return nil, nil
+	}
+
+	getParams := &dynamodb.GetItemInput{
+		Key: map[string]*dynamodb.AttributeValue{
+			"LockID": {S: aws.String(c.lockPath() + stateIDSuffix)},
+		},
+		ProjectionExpression: aws.String("LockID, Digest"),
+		TableName:            aws.String(c.ddbTable),
+		ConsistentRead:       aws.Bool(true),
+	}
+
+	resp, err := c.dynClient.GetItem(getParams)
+	if err != nil {
+		return nil, err
+	}
+
+	var val string
+	if v, ok := resp.Item["Digest"]; ok && v.S != nil {
+		val = *v.S
+	}
+
+	sum, err := hex.DecodeString(val)
+	if err != nil || len(sum) != md5.Size {
+		return nil, errors.New("invalid md5")
+	}
+
+	return sum, nil
+}
+
+// store the hash of the state so that clients can check for stale state files.
+func (c *RemoteClient) putMD5(sum []byte) error {
+	if c.ddbTable == "" {
+		return nil
+	}
+
+	if len(sum) != md5.Size {
+		return errors.New("invalid payload md5")
+	}
+
+	putParams := &dynamodb.PutItemInput{
+		Item: map[string]*dynamodb.AttributeValue{
+			"LockID": {S: aws.String(c.lockPath() + stateIDSuffix)},
+			"Digest": {S: aws.String(hex.EncodeToString(sum))},
+		},
+		TableName: aws.String(c.ddbTable),
+	}
+	_, err := c.dynClient.PutItem(putParams)
+	if err != nil {
+		log.Printf("[WARN] failed to record state serial in dynamodb: %s", err)
+	}
+
+	return nil
+}
+
+// remove the hash value for a deleted state
+func (c *RemoteClient) deleteMD5() error {
+	if c.ddbTable == "" {
+		return nil
+	}
+
+	params := &dynamodb.DeleteItemInput{
+		Key: map[string]*dynamodb.AttributeValue{
+			"LockID": {S: aws.String(c.lockPath() + stateIDSuffix)},
+		},
+		TableName: aws.String(c.ddbTable),
+	}
+	if _, err := c.dynClient.DeleteItem(params); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (c *RemoteClient) getLockInfo() (*statemgr.LockInfo, error) {
+	getParams := &dynamodb.GetItemInput{
+		Key: map[string]*dynamodb.AttributeValue{
+			"LockID": {S: aws.String(c.lockPath())},
+		},
+		ProjectionExpression: aws.String("LockID, Info"),
+		TableName:            aws.String(c.ddbTable),
+		ConsistentRead:       aws.Bool(true),
+	}
+
+	resp, err := c.dynClient.GetItem(getParams)
+	if err != nil {
+		return nil, err
+	}
+
+	var infoData string
+	if v, ok := resp.Item["Info"]; ok && v.S != nil {
+		infoData = *v.S
+	}
+
+	lockInfo := &statemgr.LockInfo{}
+	err = json.Unmarshal([]byte(infoData), lockInfo)
+	if err != nil {
+		return nil, err
+	}
+
+	return lockInfo, nil
+}
+
+func (c *RemoteClient) Unlock(id string) error {
+	if c.ddbTable == "" {
+		return nil
+	}
+
+	lockErr := &statemgr.LockError{}
+
+	// TODO: store the path and lock ID in separate fields, and have proper
+	// projection expression only delete the lock if both match, rather than
+	// checking the ID from the info field first.
+	lockInfo, err := c.getLockInfo()
+	if err != nil {
+		lockErr.Err = fmt.Errorf("failed to retrieve lock info: %s", err)
+		return lockErr
+	}
+	lockErr.Info = lockInfo
+
+	if lockInfo.ID != id {
+		lockErr.Err = fmt.Errorf("lock id %q does not match existing lock", id)
+		return lockErr
+	}
+
+	params := &dynamodb.DeleteItemInput{
+		Key: map[string]*dynamodb.AttributeValue{
+			"LockID": {S: aws.String(c.lockPath())},
+		},
+		TableName: aws.String(c.ddbTable),
+	}
+	_, err = c.dynClient.DeleteItem(params)
+
+	if err != nil {
+		lockErr.Err = err
+		return lockErr
+	}
+	return nil
+}
+
+func (c *RemoteClient) lockPath() string {
+	return fmt.Sprintf("%s/%s", c.bucketName, c.path)
+}
+
+func (c *RemoteClient) getSSECustomerKeyMD5() string {
+	b := md5.Sum(c.customerEncryptionKey)
+	return base64.StdEncoding.EncodeToString(b[:])
+}
+
+const errBadChecksumFmt = `state data in S3 does not have the expected content.
+
+This may be caused by unusually long delays in S3 processing a previous state
+update.  Please wait for a minute or two and try again. If this problem
+persists, and neither S3 nor DynamoDB are experiencing an outage, you may need
+to manually verify the remote state and update the Digest value stored in the
+DynamoDB table to the following value: %x
+`
+
+const errS3NoSuchBucket = `S3 bucket does not exist.
+
+The referenced S3 bucket must have been previously created. If the S3 bucket
+was created within the last minute, please wait for a minute or two and try
+again.
+
+Error: %s
+`
diff --git a/v1.5.7/internal/backend/remote-state/s3/client_test.go b/v1.5.7/internal/backend/remote-state/s3/client_test.go
new file mode 100644
index 0000000..52488ec
--- /dev/null
+++ b/v1.5.7/internal/backend/remote-state/s3/client_test.go
@@ -0,0 +1,320 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package s3
+
+import (
+	"bytes"
+	"crypto/md5"
+	"fmt"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+func TestRemoteClient_impl(t *testing.T) {
+	var _ remote.Client = new(RemoteClient)
+	var _ remote.ClientLocker = new(RemoteClient)
+}
+
+func TestRemoteClient(t *testing.T) {
+	testACC(t)
+	bucketName := fmt.Sprintf("terraform-remote-s3-test-%x", time.Now().Unix())
+	keyName := "testState"
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":  bucketName,
+		"key":     keyName,
+		"encrypt": true,
+	})).(*Backend)
+
+	createS3Bucket(t, b.s3Client, bucketName)
+	defer deleteS3Bucket(t, b.s3Client, bucketName)
+
+	state, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestClient(t, state.(*remote.State).Client)
+}
+
+func TestRemoteClientLocks(t *testing.T) {
+	testACC(t)
+	bucketName := fmt.Sprintf("terraform-remote-s3-test-%x", time.Now().Unix())
+	keyName := "testState"
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":         bucketName,
+		"key":            keyName,
+		"encrypt":        true,
+		"dynamodb_table": bucketName,
+	})).(*Backend)
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":         bucketName,
+		"key":            keyName,
+		"encrypt":        true,
+		"dynamodb_table": bucketName,
+	})).(*Backend)
+
+	createS3Bucket(t, b1.s3Client, bucketName)
+	defer deleteS3Bucket(t, b1.s3Client, bucketName)
+	createDynamoDBTable(t, b1.dynClient, bucketName)
+	defer deleteDynamoDBTable(t, b1.dynClient, bucketName)
+
+	s1, err := b1.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	s2, err := b2.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	remote.TestRemoteLocks(t, s1.(*remote.State).Client, s2.(*remote.State).Client)
+}
+
+// verify that we can unlock a state with an existing lock
+func TestForceUnlock(t *testing.T) {
+	testACC(t)
+	bucketName := fmt.Sprintf("terraform-remote-s3-test-force-%x", time.Now().Unix())
+	keyName := "testState"
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":         bucketName,
+		"key":            keyName,
+		"encrypt":        true,
+		"dynamodb_table": bucketName,
+	})).(*Backend)
+
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":         bucketName,
+		"key":            keyName,
+		"encrypt":        true,
+		"dynamodb_table": bucketName,
+	})).(*Backend)
+
+	createS3Bucket(t, b1.s3Client, bucketName)
+	defer deleteS3Bucket(t, b1.s3Client, bucketName)
+	createDynamoDBTable(t, b1.dynClient, bucketName)
+	defer deleteDynamoDBTable(t, b1.dynClient, bucketName)
+
+	// first test with default
+	s1, err := b1.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	info := statemgr.NewLockInfo()
+	info.Operation = "test"
+	info.Who = "clientA"
+
+	lockID, err := s1.Lock(info)
+	if err != nil {
+		t.Fatal("unable to get initial lock:", err)
+	}
+
+	// s1 is now locked, get the same state through s2 and unlock it
+	s2, err := b2.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal("failed to get default state to force unlock:", err)
+	}
+
+	if err := s2.Unlock(lockID); err != nil {
+		t.Fatal("failed to force-unlock default state")
+	}
+
+	// now try the same thing with a named state
+	// first test with default
+	s1, err = b1.StateMgr("test")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	info = statemgr.NewLockInfo()
+	info.Operation = "test"
+	info.Who = "clientA"
+
+	lockID, err = s1.Lock(info)
+	if err != nil {
+		t.Fatal("unable to get initial lock:", err)
+	}
+
+	// s1 is now locked, get the same state through s2 and unlock it
+	s2, err = b2.StateMgr("test")
+	if err != nil {
+		t.Fatal("failed to get named state to force unlock:", err)
+	}
+
+	if err = s2.Unlock(lockID); err != nil {
+		t.Fatal("failed to force-unlock named state")
+	}
+}
+
+func TestRemoteClient_clientMD5(t *testing.T) {
+	testACC(t)
+
+	bucketName := fmt.Sprintf("terraform-remote-s3-test-%x", time.Now().Unix())
+	keyName := "testState"
+
+	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":         bucketName,
+		"key":            keyName,
+		"dynamodb_table": bucketName,
+	})).(*Backend)
+
+	createS3Bucket(t, b.s3Client, bucketName)
+	defer deleteS3Bucket(t, b.s3Client, bucketName)
+	createDynamoDBTable(t, b.dynClient, bucketName)
+	defer deleteDynamoDBTable(t, b.dynClient, bucketName)
+
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+	client := s.(*remote.State).Client.(*RemoteClient)
+
+	sum := md5.Sum([]byte("test"))
+
+	if err := client.putMD5(sum[:]); err != nil {
+		t.Fatal(err)
+	}
+
+	getSum, err := client.getMD5()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !bytes.Equal(getSum, sum[:]) {
+		t.Fatalf("getMD5 returned the wrong checksum: expected %x, got %x", sum[:], getSum)
+	}
+
+	if err := client.deleteMD5(); err != nil {
+		t.Fatal(err)
+	}
+
+	if getSum, err := client.getMD5(); err == nil {
+		t.Fatalf("expected getMD5 error, got none. checksum: %x", getSum)
+	}
+}
+
+// verify that a client won't return a state with an incorrect checksum.
+func TestRemoteClient_stateChecksum(t *testing.T) {
+	testACC(t)
+
+	bucketName := fmt.Sprintf("terraform-remote-s3-test-%x", time.Now().Unix())
+	keyName := "testState"
+
+	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket":         bucketName,
+		"key":            keyName,
+		"dynamodb_table": bucketName,
+	})).(*Backend)
+
+	createS3Bucket(t, b1.s3Client, bucketName)
+	defer deleteS3Bucket(t, b1.s3Client, bucketName)
+	createDynamoDBTable(t, b1.dynClient, bucketName)
+	defer deleteDynamoDBTable(t, b1.dynClient, bucketName)
+
+	s1, err := b1.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+	client1 := s1.(*remote.State).Client
+
+	// create an old and new state version to persist
+	s := statemgr.TestFullInitialState()
+	sf := &statefile.File{State: s}
+	var oldState bytes.Buffer
+	if err := statefile.Write(sf, &oldState); err != nil {
+		t.Fatal(err)
+	}
+	sf.Serial++
+	var newState bytes.Buffer
+	if err := statefile.Write(sf, &newState); err != nil {
+		t.Fatal(err)
+	}
+
+	// Use b2 without a dynamodb_table to bypass the lock table to write the state directly.
+	// client2 will write the "incorrect" state, simulating s3 eventually consistency delays
+	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
+		"bucket": bucketName,
+		"key":    keyName,
+	})).(*Backend)
+	s2, err := b2.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatal(err)
+	}
+	client2 := s2.(*remote.State).Client
+
+	// write the new state through client2 so that there is no checksum yet
+	if err := client2.Put(newState.Bytes()); err != nil {
+		t.Fatal(err)
+	}
+
+	// verify that we can pull a state without a checksum
+	if _, err := client1.Get(); err != nil {
+		t.Fatal(err)
+	}
+
+	// write the new state back with its checksum
+	if err := client1.Put(newState.Bytes()); err != nil {
+		t.Fatal(err)
+	}
+
+	// put an empty state in place to check for panics during get
+	if err := client2.Put([]byte{}); err != nil {
+		t.Fatal(err)
+	}
+
+	// remove the timeouts so we can fail immediately
+	origTimeout := consistencyRetryTimeout
+	origInterval := consistencyRetryPollInterval
+	defer func() {
+		consistencyRetryTimeout = origTimeout
+		consistencyRetryPollInterval = origInterval
+	}()
+	consistencyRetryTimeout = 0
+	consistencyRetryPollInterval = 0
+
+	// fetching an empty state through client1 should now error out due to a
+	// mismatched checksum.
+	if _, err := client1.Get(); !strings.HasPrefix(err.Error(), errBadChecksumFmt[:80]) {
+		t.Fatalf("expected state checksum error: got %s", err)
+	}
+
+	// put the old state in place of the new, without updating the checksum
+	if err := client2.Put(oldState.Bytes()); err != nil {
+		t.Fatal(err)
+	}
+
+	// fetching the wrong state through client1 should now error out due to a
+	// mismatched checksum.
+	if _, err := client1.Get(); !strings.HasPrefix(err.Error(), errBadChecksumFmt[:80]) {
+		t.Fatalf("expected state checksum error: got %s", err)
+	}
+
+	// update the state with the correct one after we Get again
+	testChecksumHook = func() {
+		if err := client2.Put(newState.Bytes()); err != nil {
+			t.Fatal(err)
+		}
+		testChecksumHook = nil
+	}
+
+	consistencyRetryTimeout = origTimeout
+
+	// this final Get will fail to fail the checksum verification, the above
+	// callback will update the state with the correct version, and Get should
+	// retry automatically.
+	if _, err := client1.Get(); err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/v1.5.7/internal/backend/remote/backend.go b/v1.5.7/internal/backend/remote/backend.go
new file mode 100644
index 0000000..a6bbe09
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/backend.go
@@ -0,0 +1,1096 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"net/http"
+	"net/url"
+	"os"
+	"sort"
+	"strings"
+	"sync"
+	"time"
+
+	tfe "github.com/hashicorp/go-tfe"
+	version "github.com/hashicorp/go-version"
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	tfversion "github.com/hashicorp/terraform/version"
+	"github.com/mitchellh/cli"
+	"github.com/mitchellh/colorstring"
+	"github.com/zclconf/go-cty/cty"
+
+	backendLocal "github.com/hashicorp/terraform/internal/backend/local"
+)
+
+const (
+	defaultHostname    = "app.terraform.io"
+	defaultParallelism = 10
+	stateServiceID     = "state.v2"
+	tfeServiceID       = "tfe.v2.1"
+	genericHostname    = "localterraform.com"
+)
+
+// Remote is an implementation of EnhancedBackend that performs all
+// operations in a remote backend.
+type Remote struct {
+	// CLI and Colorize control the CLI output. If CLI is nil then no CLI
+	// output will be done. If CLIColor is nil then no coloring will be done.
+	CLI      cli.Ui
+	CLIColor *colorstring.Colorize
+
+	// ContextOpts are the base context options to set when initializing a
+	// new Terraform context. Many of these will be overridden or merged by
+	// Operation. See Operation for more details.
+	ContextOpts *terraform.ContextOpts
+
+	// client is the remote backend API client.
+	client *tfe.Client
+
+	// lastRetry is set to the last time a request was retried.
+	lastRetry time.Time
+
+	// hostname of the remote backend server.
+	hostname string
+
+	// organization is the organization that contains the target workspaces.
+	organization string
+
+	// workspace is used to map the default workspace to a remote workspace.
+	workspace string
+
+	// prefix is used to filter down a set of workspaces that use a single
+	// configuration.
+	prefix string
+
+	// services is used for service discovery
+	services *disco.Disco
+
+	// local, if non-nil, will be used for all enhanced behavior. This
+	// allows local behavior with the remote backend functioning as remote
+	// state storage backend.
+	local backend.Enhanced
+
+	// forceLocal, if true, will force the use of the local backend.
+	forceLocal bool
+
+	// opLock locks operations
+	opLock sync.Mutex
+
+	// ignoreVersionConflict, if true, will disable the requirement that the
+	// local Terraform version matches the remote workspace's configured
+	// version. This will also cause VerifyWorkspaceTerraformVersion to return
+	// a warning diagnostic instead of an error.
+	ignoreVersionConflict bool
+}
+
+var _ backend.Backend = (*Remote)(nil)
+var _ backend.Enhanced = (*Remote)(nil)
+var _ backend.Local = (*Remote)(nil)
+
+// New creates a new initialized remote backend.
+func New(services *disco.Disco) *Remote {
+	return &Remote{
+		services: services,
+	}
+}
+
+// ConfigSchema implements backend.Enhanced.
+func (b *Remote) ConfigSchema() *configschema.Block {
+	return &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"hostname": {
+				Type:        cty.String,
+				Optional:    true,
+				Description: schemaDescriptions["hostname"],
+			},
+			"organization": {
+				Type:        cty.String,
+				Required:    true,
+				Description: schemaDescriptions["organization"],
+			},
+			"token": {
+				Type:        cty.String,
+				Optional:    true,
+				Description: schemaDescriptions["token"],
+			},
+		},
+
+		BlockTypes: map[string]*configschema.NestedBlock{
+			"workspaces": {
+				Block: configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"name": {
+							Type:        cty.String,
+							Optional:    true,
+							Description: schemaDescriptions["name"],
+						},
+						"prefix": {
+							Type:        cty.String,
+							Optional:    true,
+							Description: schemaDescriptions["prefix"],
+						},
+					},
+				},
+				Nesting: configschema.NestingSingle,
+			},
+		},
+	}
+}
+
+// PrepareConfig implements backend.Backend.
+func (b *Remote) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	if obj.IsNull() {
+		return obj, diags
+	}
+
+	if val := obj.GetAttr("organization"); val.IsNull() || val.AsString() == "" {
+		diags = diags.Append(tfdiags.AttributeValue(
+			tfdiags.Error,
+			"Invalid organization value",
+			`The "organization" attribute value must not be empty.`,
+			cty.Path{cty.GetAttrStep{Name: "organization"}},
+		))
+	}
+
+	var name, prefix string
+	if workspaces := obj.GetAttr("workspaces"); !workspaces.IsNull() {
+		if val := workspaces.GetAttr("name"); !val.IsNull() {
+			name = val.AsString()
+		}
+		if val := workspaces.GetAttr("prefix"); !val.IsNull() {
+			prefix = val.AsString()
+		}
+	}
+
+	// Make sure that we have either a workspace name or a prefix.
+	if name == "" && prefix == "" {
+		diags = diags.Append(tfdiags.AttributeValue(
+			tfdiags.Error,
+			"Invalid workspaces configuration",
+			`Either workspace "name" or "prefix" is required.`,
+			cty.Path{cty.GetAttrStep{Name: "workspaces"}},
+		))
+	}
+
+	// Make sure that only one of workspace name or a prefix is configured.
+	if name != "" && prefix != "" {
+		diags = diags.Append(tfdiags.AttributeValue(
+			tfdiags.Error,
+			"Invalid workspaces configuration",
+			`Only one of workspace "name" or "prefix" is allowed.`,
+			cty.Path{cty.GetAttrStep{Name: "workspaces"}},
+		))
+	}
+
+	return obj, diags
+}
+
+func (b *Remote) ServiceDiscoveryAliases() ([]backend.HostAlias, error) {
+	aliasHostname, err := svchost.ForComparison(genericHostname)
+	if err != nil {
+		// This should never happen because the hostname is statically defined.
+		return nil, fmt.Errorf("failed to create backend alias from alias %q. The hostname is not in the correct format. This is a bug in the backend", genericHostname)
+	}
+
+	targetHostname, err := svchost.ForComparison(b.hostname)
+	if err != nil {
+		// This should never happen because the 'to' alias is the backend host, which has likely
+		// already been evaluated as a svchost.Hostname by now
+		return nil, fmt.Errorf("failed to create backend alias to target %q. The hostname is not in the correct format", b.hostname)
+	}
+
+	return []backend.HostAlias{
+		{
+			From: aliasHostname,
+			To:   targetHostname,
+		},
+	}, nil
+}
+
+// Configure implements backend.Enhanced.
+func (b *Remote) Configure(obj cty.Value) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+	if obj.IsNull() {
+		return diags
+	}
+
+	// Get the hostname.
+	if val := obj.GetAttr("hostname"); !val.IsNull() && val.AsString() != "" {
+		b.hostname = val.AsString()
+	} else {
+		b.hostname = defaultHostname
+	}
+
+	// Get the organization.
+	if val := obj.GetAttr("organization"); !val.IsNull() {
+		b.organization = val.AsString()
+	}
+
+	// Get the workspaces configuration block and retrieve the
+	// default workspace name and prefix.
+	if workspaces := obj.GetAttr("workspaces"); !workspaces.IsNull() {
+		if val := workspaces.GetAttr("name"); !val.IsNull() {
+			b.workspace = val.AsString()
+		}
+		if val := workspaces.GetAttr("prefix"); !val.IsNull() {
+			b.prefix = val.AsString()
+		}
+	}
+
+	// Determine if we are forced to use the local backend.
+	b.forceLocal = os.Getenv("TF_FORCE_LOCAL_BACKEND") != ""
+
+	serviceID := tfeServiceID
+	if b.forceLocal {
+		serviceID = stateServiceID
+	}
+
+	// Discover the service URL for this host to confirm that it provides
+	// a remote backend API and to get the version constraints.
+	service, constraints, err := b.discover(serviceID)
+
+	// First check any contraints we might have received.
+	if constraints != nil {
+		diags = diags.Append(b.checkConstraints(constraints))
+		if diags.HasErrors() {
+			return diags
+		}
+	}
+
+	// When we don't have any constraints errors, also check for discovery
+	// errors before we continue.
+	if err != nil {
+		diags = diags.Append(tfdiags.AttributeValue(
+			tfdiags.Error,
+			strings.ToUpper(err.Error()[:1])+err.Error()[1:],
+			"", // no description is needed here, the error is clear
+			cty.Path{cty.GetAttrStep{Name: "hostname"}},
+		))
+		return diags
+	}
+
+	// Get the token from the config.
+	var token string
+	if val := obj.GetAttr("token"); !val.IsNull() {
+		token = val.AsString()
+	}
+
+	// Retrieve the token for this host as configured in the credentials
+	// section of the CLI Config File if no token was configured for this
+	// host in the config.
+	if token == "" {
+		token, err = b.token()
+		if err != nil {
+			diags = diags.Append(tfdiags.AttributeValue(
+				tfdiags.Error,
+				strings.ToUpper(err.Error()[:1])+err.Error()[1:],
+				"", // no description is needed here, the error is clear
+				cty.Path{cty.GetAttrStep{Name: "hostname"}},
+			))
+			return diags
+		}
+	}
+
+	// Return an error if we still don't have a token at this point.
+	if token == "" {
+		loginCommand := "terraform login"
+		if b.hostname != defaultHostname {
+			loginCommand = loginCommand + " " + b.hostname
+		}
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Required token could not be found",
+			fmt.Sprintf(
+				"Run the following command to generate a token for %s:\n    %s",
+				b.hostname,
+				loginCommand,
+			),
+		))
+		return diags
+	}
+
+	cfg := &tfe.Config{
+		Address:      service.String(),
+		BasePath:     service.Path,
+		Token:        token,
+		Headers:      make(http.Header),
+		RetryLogHook: b.retryLogHook,
+	}
+
+	// Set the version header to the current version.
+	cfg.Headers.Set(tfversion.Header, tfversion.Version)
+
+	// Create the remote backend API client.
+	b.client, err = tfe.NewClient(cfg)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to create the Terraform Enterprise client",
+			fmt.Sprintf(
+				`The "remote" backend encountered an unexpected error while creating the `+
+					`Terraform Enterprise client: %s.`, err,
+			),
+		))
+		return diags
+	}
+
+	// Check if the organization exists by reading its entitlements.
+	entitlements, err := b.client.Organizations.ReadEntitlements(context.Background(), b.organization)
+	if err != nil {
+		if err == tfe.ErrResourceNotFound {
+			err = fmt.Errorf("organization %q at host %s not found.\n\n"+
+				"Please ensure that the organization and hostname are correct "+
+				"and that your API token for %s is valid.",
+				b.organization, b.hostname, b.hostname)
+		}
+		diags = diags.Append(tfdiags.AttributeValue(
+			tfdiags.Error,
+			fmt.Sprintf("Failed to read organization %q at host %s", b.organization, b.hostname),
+			fmt.Sprintf("The \"remote\" backend encountered an unexpected error while reading the "+
+				"organization settings: %s", err),
+			cty.Path{cty.GetAttrStep{Name: "organization"}},
+		))
+		return diags
+	}
+
+	// Configure a local backend for when we need to run operations locally.
+	b.local = backendLocal.NewWithBackend(b)
+	b.forceLocal = b.forceLocal || !entitlements.Operations
+
+	// Enable retries for server errors as the backend is now fully configured.
+	b.client.RetryServerErrors(true)
+
+	return diags
+}
+
+// discover the remote backend API service URL and version constraints.
+func (b *Remote) discover(serviceID string) (*url.URL, *disco.Constraints, error) {
+	hostname, err := svchost.ForComparison(b.hostname)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	host, err := b.services.Discover(hostname)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	service, err := host.ServiceURL(serviceID)
+	// Return the error, unless its a disco.ErrVersionNotSupported error.
+	if _, ok := err.(*disco.ErrVersionNotSupported); !ok && err != nil {
+		return nil, nil, err
+	}
+
+	// We purposefully ignore the error and return the previous error, as
+	// checking for version constraints is considered optional.
+	constraints, _ := host.VersionConstraints(serviceID, "terraform")
+
+	return service, constraints, err
+}
+
+// checkConstraints checks service version constrains against our own
+// version and returns rich and informational diagnostics in case any
+// incompatibilities are detected.
+func (b *Remote) checkConstraints(c *disco.Constraints) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	if c == nil || c.Minimum == "" || c.Maximum == "" {
+		return diags
+	}
+
+	// Generate a parsable constraints string.
+	excluding := ""
+	if len(c.Excluding) > 0 {
+		excluding = fmt.Sprintf(", != %s", strings.Join(c.Excluding, ", != "))
+	}
+	constStr := fmt.Sprintf(">= %s%s, <= %s", c.Minimum, excluding, c.Maximum)
+
+	// Create the constraints to check against.
+	constraints, err := version.NewConstraint(constStr)
+	if err != nil {
+		return diags.Append(checkConstraintsWarning(err))
+	}
+
+	// Create the version to check.
+	v, err := version.NewVersion(tfversion.Version)
+	if err != nil {
+		return diags.Append(checkConstraintsWarning(err))
+	}
+
+	// Return if we satisfy all constraints.
+	if constraints.Check(v) {
+		return diags
+	}
+
+	// Find out what action (upgrade/downgrade) we should advice.
+	minimum, err := version.NewVersion(c.Minimum)
+	if err != nil {
+		return diags.Append(checkConstraintsWarning(err))
+	}
+
+	maximum, err := version.NewVersion(c.Maximum)
+	if err != nil {
+		return diags.Append(checkConstraintsWarning(err))
+	}
+
+	var excludes []*version.Version
+	for _, exclude := range c.Excluding {
+		v, err := version.NewVersion(exclude)
+		if err != nil {
+			return diags.Append(checkConstraintsWarning(err))
+		}
+		excludes = append(excludes, v)
+	}
+
+	// Sort all the excludes.
+	sort.Sort(version.Collection(excludes))
+
+	var action, toVersion string
+	switch {
+	case minimum.GreaterThan(v):
+		action = "upgrade"
+		toVersion = ">= " + minimum.String()
+	case maximum.LessThan(v):
+		action = "downgrade"
+		toVersion = "<= " + maximum.String()
+	case len(excludes) > 0:
+		// Get the latest excluded version.
+		action = "upgrade"
+		toVersion = "> " + excludes[len(excludes)-1].String()
+	}
+
+	switch {
+	case len(excludes) == 1:
+		excluding = fmt.Sprintf(", excluding version %s", excludes[0].String())
+	case len(excludes) > 1:
+		var vs []string
+		for _, v := range excludes {
+			vs = append(vs, v.String())
+		}
+		excluding = fmt.Sprintf(", excluding versions %s", strings.Join(vs, ", "))
+	default:
+		excluding = ""
+	}
+
+	summary := fmt.Sprintf("Incompatible Terraform version v%s", v.String())
+	details := fmt.Sprintf(
+		"The configured Terraform Enterprise backend is compatible with Terraform "+
+			"versions >= %s, <= %s%s.", c.Minimum, c.Maximum, excluding,
+	)
+
+	if action != "" && toVersion != "" {
+		summary = fmt.Sprintf("Please %s Terraform to %s", action, toVersion)
+		details += fmt.Sprintf(" Please %s to a supported version and try again.", action)
+	}
+
+	// Return the customized and informational error message.
+	return diags.Append(tfdiags.Sourceless(tfdiags.Error, summary, details))
+}
+
+// token returns the token for this host as configured in the credentials
+// section of the CLI Config File. If no token was configured, an empty
+// string will be returned instead.
+func (b *Remote) token() (string, error) {
+	hostname, err := svchost.ForComparison(b.hostname)
+	if err != nil {
+		return "", err
+	}
+	creds, err := b.services.CredentialsForHost(hostname)
+	if err != nil {
+		log.Printf("[WARN] Failed to get credentials for %s: %s (ignoring)", b.hostname, err)
+		return "", nil
+	}
+	if creds != nil {
+		return creds.Token(), nil
+	}
+	return "", nil
+}
+
+// retryLogHook is invoked each time a request is retried allowing the
+// backend to log any connection issues to prevent data loss.
+func (b *Remote) retryLogHook(attemptNum int, resp *http.Response) {
+	if b.CLI != nil {
+		// Ignore the first retry to make sure any delayed output will
+		// be written to the console before we start logging retries.
+		//
+		// The retry logic in the TFE client will retry both rate limited
+		// requests and server errors, but in the remote backend we only
+		// care about server errors so we ignore rate limit (429) errors.
+		if attemptNum == 0 || (resp != nil && resp.StatusCode == 429) {
+			// Reset the last retry time.
+			b.lastRetry = time.Now()
+			return
+		}
+
+		if attemptNum == 1 {
+			b.CLI.Output(b.Colorize().Color(strings.TrimSpace(initialRetryError)))
+		} else {
+			b.CLI.Output(b.Colorize().Color(strings.TrimSpace(
+				fmt.Sprintf(repeatedRetryError, time.Since(b.lastRetry).Round(time.Second)))))
+		}
+	}
+}
+
+// Workspaces implements backend.Enhanced.
+func (b *Remote) Workspaces() ([]string, error) {
+	if b.prefix == "" {
+		return nil, backend.ErrWorkspacesNotSupported
+	}
+	return b.workspaces()
+}
+
+// workspaces returns a filtered list of remote workspace names.
+func (b *Remote) workspaces() ([]string, error) {
+	options := &tfe.WorkspaceListOptions{}
+	switch {
+	case b.workspace != "":
+		options.Search = b.workspace
+	case b.prefix != "":
+		options.Search = b.prefix
+	}
+
+	// Create a slice to contain all the names.
+	var names []string
+
+	for {
+		wl, err := b.client.Workspaces.List(context.Background(), b.organization, options)
+		if err != nil {
+			return nil, err
+		}
+
+		for _, w := range wl.Items {
+			if b.workspace != "" && w.Name == b.workspace {
+				names = append(names, backend.DefaultStateName)
+				continue
+			}
+			if b.prefix != "" && strings.HasPrefix(w.Name, b.prefix) {
+				names = append(names, strings.TrimPrefix(w.Name, b.prefix))
+			}
+		}
+
+		// Exit the loop when we've seen all pages.
+		if wl.CurrentPage >= wl.TotalPages {
+			break
+		}
+
+		// Update the page number to get the next page.
+		options.PageNumber = wl.NextPage
+	}
+
+	// Sort the result so we have consistent output.
+	sort.StringSlice(names).Sort()
+
+	return names, nil
+}
+
+// WorkspaceNamePattern provides an appropriate workspace renaming pattern for backend migration
+// purposes (handled outside of this package), based on previous usage of this backend with the
+// 'prefix' workspace functionality. As of this writing, see meta_backend.migrate.go
+func (b *Remote) WorkspaceNamePattern() string {
+	if b.prefix != "" {
+		return b.prefix + "*"
+	}
+
+	return ""
+}
+
+// DeleteWorkspace implements backend.Enhanced.
+func (b *Remote) DeleteWorkspace(name string, _ bool) error {
+	if b.workspace == "" && name == backend.DefaultStateName {
+		return backend.ErrDefaultWorkspaceNotSupported
+	}
+	if b.prefix == "" && name != backend.DefaultStateName {
+		return backend.ErrWorkspacesNotSupported
+	}
+
+	// Configure the remote workspace name.
+	switch {
+	case name == backend.DefaultStateName:
+		name = b.workspace
+	case b.prefix != "" && !strings.HasPrefix(name, b.prefix):
+		name = b.prefix + name
+	}
+
+	client := &remoteClient{
+		client:       b.client,
+		organization: b.organization,
+		workspace: &tfe.Workspace{
+			Name: name,
+		},
+	}
+
+	return client.Delete()
+}
+
+// StateMgr implements backend.Enhanced.
+func (b *Remote) StateMgr(name string) (statemgr.Full, error) {
+	if b.workspace == "" && name == backend.DefaultStateName {
+		return nil, backend.ErrDefaultWorkspaceNotSupported
+	}
+	if b.prefix == "" && name != backend.DefaultStateName {
+		return nil, backend.ErrWorkspacesNotSupported
+	}
+
+	// Configure the remote workspace name.
+	switch {
+	case name == backend.DefaultStateName:
+		name = b.workspace
+	case b.prefix != "" && !strings.HasPrefix(name, b.prefix):
+		name = b.prefix + name
+	}
+
+	workspace, err := b.client.Workspaces.Read(context.Background(), b.organization, name)
+	if err != nil && err != tfe.ErrResourceNotFound {
+		return nil, fmt.Errorf("Failed to retrieve workspace %s: %v", name, err)
+	}
+
+	if err == tfe.ErrResourceNotFound {
+		options := tfe.WorkspaceCreateOptions{
+			Name: tfe.String(name),
+		}
+
+		// We only set the Terraform Version for the new workspace if this is
+		// a release candidate or a final release.
+		if tfversion.Prerelease == "" || strings.HasPrefix(tfversion.Prerelease, "rc") {
+			options.TerraformVersion = tfe.String(tfversion.String())
+		}
+
+		workspace, err = b.client.Workspaces.Create(context.Background(), b.organization, options)
+		if err != nil {
+			return nil, fmt.Errorf("Error creating workspace %s: %v", name, err)
+		}
+	}
+
+	// This is a fallback error check. Most code paths should use other
+	// mechanisms to check the version, then set the ignoreVersionConflict
+	// field to true. This check is only in place to ensure that we don't
+	// accidentally upgrade state with a new code path, and the version check
+	// logic is coarser and simpler.
+	if !b.ignoreVersionConflict {
+		wsv := workspace.TerraformVersion
+		// Explicitly ignore the pseudo-version "latest" here, as it will cause
+		// plan and apply to always fail.
+		if wsv != tfversion.String() && wsv != "latest" {
+			return nil, fmt.Errorf("Remote workspace Terraform version %q does not match local Terraform version %q", workspace.TerraformVersion, tfversion.String())
+		}
+	}
+
+	client := &remoteClient{
+		client:       b.client,
+		organization: b.organization,
+		workspace:    workspace,
+
+		// This is optionally set during Terraform Enterprise runs.
+		runID: os.Getenv("TFE_RUN_ID"),
+	}
+
+	return &remote.State{
+		Client: client,
+
+		// client.runID will be set if we're running a the Terraform Cloud
+		// or Terraform Enterprise remote execution environment, in which
+		// case we'll disable intermediate snapshots to avoid extra storage
+		// costs for Terraform Enterprise customers.
+		// Other implementations of the remote state protocol should not run
+		// in contexts where there's a "TFE Run ID" and so are not affected
+		// by this special case.
+		DisableIntermediateSnapshots: client.runID != "",
+	}, nil
+}
+
+func isLocalExecutionMode(execMode string) bool {
+	return execMode == "local"
+}
+
+func (b *Remote) fetchWorkspace(ctx context.Context, organization string, name string) (*tfe.Workspace, error) {
+	remoteWorkspaceName := b.getRemoteWorkspaceName(name)
+	// Retrieve the workspace for this operation.
+	w, err := b.client.Workspaces.Read(ctx, b.organization, remoteWorkspaceName)
+	if err != nil {
+		switch err {
+		case context.Canceled:
+			return nil, err
+		case tfe.ErrResourceNotFound:
+			return nil, fmt.Errorf(
+				"workspace %s not found\n\n"+
+					"The configured \"remote\" backend returns '404 Not Found' errors for resources\n"+
+					"that do not exist, as well as for resources that a user doesn't have access\n"+
+					"to. If the resource does exist, please check the rights for the used token",
+				name,
+			)
+		default:
+			err := fmt.Errorf(
+				"the configured \"remote\" backend encountered an unexpected error:\n\n%s",
+				err,
+			)
+			return nil, err
+		}
+	}
+
+	return w, nil
+}
+
+// Operation implements backend.Enhanced.
+func (b *Remote) Operation(ctx context.Context, op *backend.Operation) (*backend.RunningOperation, error) {
+	w, err := b.fetchWorkspace(ctx, b.organization, op.Workspace)
+
+	if err != nil {
+		return nil, err
+	}
+
+	// Terraform remote version conflicts are not a concern for operations. We
+	// are in one of three states:
+	//
+	// - Running remotely, in which case the local version is irrelevant;
+	// - Workspace configured for local operations, in which case the remote
+	//   version is meaningless;
+	// - Forcing local operations with a remote backend, which should only
+	//   happen in the Terraform Cloud worker, in which case the Terraform
+	//   versions by definition match.
+	b.IgnoreVersionConflict()
+
+	// Check if we need to use the local backend to run the operation.
+	if b.forceLocal || isLocalExecutionMode(w.ExecutionMode) {
+		// Record that we're forced to run operations locally to allow the
+		// command package UI to operate correctly
+		b.forceLocal = true
+		log.Printf("[DEBUG] Remote backend is delegating %s to the local backend", op.Type)
+		return b.local.Operation(ctx, op)
+	}
+
+	// Set the remote workspace name.
+	op.Workspace = w.Name
+
+	// Determine the function to call for our operation
+	var f func(context.Context, context.Context, *backend.Operation, *tfe.Workspace) (*tfe.Run, error)
+	switch op.Type {
+	case backend.OperationTypePlan:
+		f = b.opPlan
+	case backend.OperationTypeApply:
+		f = b.opApply
+	case backend.OperationTypeRefresh:
+		return nil, fmt.Errorf(
+			"\n\nThe \"refresh\" operation is not supported when using the \"remote\" backend. " +
+				"Use \"terraform apply -refresh-only\" instead.")
+	default:
+		return nil, fmt.Errorf(
+			"\n\nThe \"remote\" backend does not support the %q operation.", op.Type)
+	}
+
+	// Lock
+	b.opLock.Lock()
+
+	// Build our running operation
+	// the runninCtx is only used to block until the operation returns.
+	runningCtx, done := context.WithCancel(context.Background())
+	runningOp := &backend.RunningOperation{
+		Context:   runningCtx,
+		PlanEmpty: true,
+	}
+
+	// stopCtx wraps the context passed in, and is used to signal a graceful Stop.
+	stopCtx, stop := context.WithCancel(ctx)
+	runningOp.Stop = stop
+
+	// cancelCtx is used to cancel the operation immediately, usually
+	// indicating that the process is exiting.
+	cancelCtx, cancel := context.WithCancel(context.Background())
+	runningOp.Cancel = cancel
+
+	// Do it.
+	go func() {
+		defer logging.PanicHandler()
+		defer done()
+		defer stop()
+		defer cancel()
+
+		defer b.opLock.Unlock()
+
+		r, opErr := f(stopCtx, cancelCtx, op, w)
+		if opErr != nil && opErr != context.Canceled {
+			var diags tfdiags.Diagnostics
+			diags = diags.Append(opErr)
+			op.ReportResult(runningOp, diags)
+			return
+		}
+
+		if r == nil && opErr == context.Canceled {
+			runningOp.Result = backend.OperationFailure
+			return
+		}
+
+		if r != nil {
+			// Retrieve the run to get its current status.
+			r, err := b.client.Runs.Read(cancelCtx, r.ID)
+			if err != nil {
+				var diags tfdiags.Diagnostics
+				diags = diags.Append(generalError("Failed to retrieve run", err))
+				op.ReportResult(runningOp, diags)
+				return
+			}
+
+			// Record if there are any changes.
+			runningOp.PlanEmpty = !r.HasChanges
+
+			if opErr == context.Canceled {
+				if err := b.cancel(cancelCtx, op, r); err != nil {
+					var diags tfdiags.Diagnostics
+					diags = diags.Append(generalError("Failed to retrieve run", err))
+					op.ReportResult(runningOp, diags)
+					return
+				}
+			}
+
+			if r.Status == tfe.RunCanceled || r.Status == tfe.RunErrored {
+				runningOp.Result = backend.OperationFailure
+			}
+		}
+	}()
+
+	// Return the running operation.
+	return runningOp, nil
+}
+
+func (b *Remote) cancel(cancelCtx context.Context, op *backend.Operation, r *tfe.Run) error {
+	if r.Actions.IsCancelable {
+		// Only ask if the remote operation should be canceled
+		// if the auto approve flag is not set.
+		if !op.AutoApprove {
+			v, err := op.UIIn.Input(cancelCtx, &terraform.InputOpts{
+				Id:          "cancel",
+				Query:       "\nDo you want to cancel the remote operation?",
+				Description: "Only 'yes' will be accepted to cancel.",
+			})
+			if err != nil {
+				return generalError("Failed asking to cancel", err)
+			}
+			if v != "yes" {
+				if b.CLI != nil {
+					b.CLI.Output(b.Colorize().Color(strings.TrimSpace(operationNotCanceled)))
+				}
+				return nil
+			}
+		} else {
+			if b.CLI != nil {
+				// Insert a blank line to separate the ouputs.
+				b.CLI.Output("")
+			}
+		}
+
+		// Try to cancel the remote operation.
+		err := b.client.Runs.Cancel(cancelCtx, r.ID, tfe.RunCancelOptions{})
+		if err != nil {
+			return generalError("Failed to cancel run", err)
+		}
+		if b.CLI != nil {
+			b.CLI.Output(b.Colorize().Color(strings.TrimSpace(operationCanceled)))
+		}
+	}
+
+	return nil
+}
+
+// IgnoreVersionConflict allows commands to disable the fall-back check that
+// the local Terraform version matches the remote workspace's configured
+// Terraform version. This should be called by commands where this check is
+// unnecessary, such as those performing remote operations, or read-only
+// operations. It will also be called if the user uses a command-line flag to
+// override this check.
+func (b *Remote) IgnoreVersionConflict() {
+	b.ignoreVersionConflict = true
+}
+
+// VerifyWorkspaceTerraformVersion compares the local Terraform version against
+// the workspace's configured Terraform version. If they are equal, this means
+// that there are no compatibility concerns, so it returns no diagnostics.
+//
+// If the versions differ,
+func (b *Remote) VerifyWorkspaceTerraformVersion(workspaceName string) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	workspace, err := b.getRemoteWorkspace(context.Background(), workspaceName)
+	if err != nil {
+		// If the workspace doesn't exist, there can be no compatibility
+		// problem, so we can return. This is most likely to happen when
+		// migrating state from a local backend to a new workspace.
+		if err == tfe.ErrResourceNotFound {
+			return nil
+		}
+
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Error looking up workspace",
+			fmt.Sprintf("Workspace read failed: %s", err),
+		))
+		return diags
+	}
+
+	// If the workspace has the pseudo-version "latest", all bets are off. We
+	// cannot reasonably determine what the intended Terraform version is, so
+	// we'll skip version verification.
+	if workspace.TerraformVersion == "latest" {
+		return nil
+	}
+
+	// If the workspace has remote operations disabled, the remote Terraform
+	// version is effectively meaningless, so we'll skip version verification.
+	if isLocalExecutionMode(workspace.ExecutionMode) {
+		return nil
+	}
+
+	remoteVersion, err := version.NewSemver(workspace.TerraformVersion)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Error looking up workspace",
+			fmt.Sprintf("Invalid Terraform version: %s", err),
+		))
+		return diags
+	}
+
+	v014 := version.Must(version.NewSemver("0.14.0"))
+	if tfversion.SemVer.LessThan(v014) || remoteVersion.LessThan(v014) {
+		// Versions of Terraform prior to 0.14.0 will refuse to load state files
+		// written by a newer version of Terraform, even if it is only a patch
+		// level difference. As a result we require an exact match.
+		if tfversion.SemVer.Equal(remoteVersion) {
+			return diags
+		}
+	}
+	if tfversion.SemVer.GreaterThanOrEqual(v014) && remoteVersion.GreaterThanOrEqual(v014) {
+		// Versions of Terraform after 0.14.0 should be compatible with each
+		// other.  At the time this code was written, the only constraints we
+		// are aware of are:
+		//
+		// - 0.14.0 is guaranteed to be compatible with versions up to but not
+		//   including 1.3.0
+		v130 := version.Must(version.NewSemver("1.3.0"))
+		if tfversion.SemVer.LessThan(v130) && remoteVersion.LessThan(v130) {
+			return diags
+		}
+		// - Any new Terraform state version will require at least minor patch
+		//   increment, so x.y.* will always be compatible with each other
+		tfvs := tfversion.SemVer.Segments64()
+		rwvs := remoteVersion.Segments64()
+		if len(tfvs) == 3 && len(rwvs) == 3 && tfvs[0] == rwvs[0] && tfvs[1] == rwvs[1] {
+			return diags
+		}
+	}
+
+	// Even if ignoring version conflicts, it may still be useful to call this
+	// method and warn the user about a mismatch between the local and remote
+	// Terraform versions.
+	severity := tfdiags.Error
+	if b.ignoreVersionConflict {
+		severity = tfdiags.Warning
+	}
+
+	suggestion := " If you're sure you want to upgrade the state, you can force Terraform to continue using the -ignore-remote-version flag. This may result in an unusable workspace."
+	if b.ignoreVersionConflict {
+		suggestion = ""
+	}
+	diags = diags.Append(tfdiags.Sourceless(
+		severity,
+		"Terraform version mismatch",
+		fmt.Sprintf(
+			"The local Terraform version (%s) does not match the configured version for remote workspace %s/%s (%s).%s",
+			tfversion.String(),
+			b.organization,
+			workspace.Name,
+			workspace.TerraformVersion,
+			suggestion,
+		),
+	))
+
+	return diags
+}
+
+func (b *Remote) IsLocalOperations() bool {
+	return b.forceLocal
+}
+
+func generalError(msg string, err error) error {
+	var diags tfdiags.Diagnostics
+
+	if urlErr, ok := err.(*url.Error); ok {
+		err = urlErr.Err
+	}
+
+	switch err {
+	case context.Canceled:
+		return err
+	case tfe.ErrResourceNotFound:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			fmt.Sprintf("%s: %v", msg, err),
+			`The configured "remote" backend returns '404 Not Found' errors for resources `+
+				`that do not exist, as well as for resources that a user doesn't have access `+
+				`to. If the resource does exist, please check the rights for the used token.`,
+		))
+		return diags.Err()
+	default:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			fmt.Sprintf("%s: %v", msg, err),
+			`The configured "remote" backend encountered an unexpected error. Sometimes `+
+				`this is caused by network connection problems, in which case you could retry `+
+				`the command. If the issue persists please open a support ticket to get help `+
+				`resolving the problem.`,
+		))
+		return diags.Err()
+	}
+}
+
+func checkConstraintsWarning(err error) tfdiags.Diagnostic {
+	return tfdiags.Sourceless(
+		tfdiags.Warning,
+		fmt.Sprintf("Failed to check version constraints: %v", err),
+		"Checking version constraints is considered optional, but this is an"+
+			"unexpected error which should be reported.",
+	)
+}
+
+// The newline in this error is to make it look good in the CLI!
+const initialRetryError = `
+[reset][yellow]There was an error connecting to the remote backend. Please do not exit
+Terraform to prevent data loss! Trying to restore the connection...
+[reset]
+`
+
+const repeatedRetryError = `
+[reset][yellow]Still trying to restore the connection... (%s elapsed)[reset]
+`
+
+const operationCanceled = `
+[reset][red]The remote operation was successfully cancelled.[reset]
+`
+
+const operationNotCanceled = `
+[reset][red]The remote operation was not cancelled.[reset]
+`
+
+var schemaDescriptions = map[string]string{
+	"hostname":     "The remote backend hostname to connect to (defaults to app.terraform.io).",
+	"organization": "The name of the organization containing the targeted workspace(s).",
+	"token": "The token used to authenticate with the remote backend. If credentials for the\n" +
+		"host are configured in the CLI Config File, then those will be used instead.",
+	"name": "A workspace name used to map the default workspace to a named remote workspace.\n" +
+		"When configured only the default workspace can be used. This option conflicts\n" +
+		"with \"prefix\"",
+	"prefix": "A prefix used to filter workspaces using a single configuration. New workspaces\n" +
+		"will automatically be prefixed with this prefix. If omitted only the default\n" +
+		"workspace can be used. This option conflicts with \"name\"",
+}
diff --git a/v1.5.7/internal/backend/remote/backend_apply.go b/v1.5.7/internal/backend/remote/backend_apply.go
new file mode 100644
index 0000000..f00119f
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/backend_apply.go
@@ -0,0 +1,304 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"bufio"
+	"context"
+	"fmt"
+	"io"
+	"log"
+
+	tfe "github.com/hashicorp/go-tfe"
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func (b *Remote) opApply(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
+	log.Printf("[INFO] backend/remote: starting Apply operation")
+
+	var diags tfdiags.Diagnostics
+
+	// We should remove the `CanUpdate` part of this test, but for now
+	// (to remain compatible with tfe.v2.1) we'll leave it in here.
+	if !w.Permissions.CanUpdate && !w.Permissions.CanQueueApply {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Insufficient rights to apply changes",
+			"The provided credentials have insufficient rights to apply changes. In order "+
+				"to apply changes at least write permissions on the workspace are required.",
+		))
+		return nil, diags.Err()
+	}
+
+	if w.VCSRepo != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Apply not allowed for workspaces with a VCS connection",
+			"A workspace that is connected to a VCS requires the VCS-driven workflow "+
+				"to ensure that the VCS remains the single source of truth.",
+		))
+		return nil, diags.Err()
+	}
+
+	if b.ContextOpts != nil && b.ContextOpts.Parallelism != defaultParallelism {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Custom parallelism values are currently not supported",
+			`The "remote" backend does not support setting a custom parallelism `+
+				`value at this time.`,
+		))
+	}
+
+	if op.PlanFile != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Applying a saved plan is currently not supported",
+			`The "remote" backend currently requires configuration to be present and `+
+				`does not accept an existing saved plan as an argument at this time.`,
+		))
+	}
+
+	if b.hasExplicitVariableValues(op) {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Run variables are currently not supported",
+			fmt.Sprintf(
+				"The \"remote\" backend does not support setting run variables at this time. "+
+					"Currently the only to way to pass variables to the remote backend is by "+
+					"creating a '*.auto.tfvars' variables file. This file will automatically "+
+					"be loaded by the \"remote\" backend when the workspace is configured to use "+
+					"Terraform v0.10.0 or later.\n\nAdditionally you can also set variables on "+
+					"the workspace in the web UI:\nhttps://%s/app/%s/%s/variables",
+				b.hostname, b.organization, op.Workspace,
+			),
+		))
+	}
+
+	if !op.HasConfig() && op.PlanMode != plans.DestroyMode {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"No configuration files found",
+			`Apply requires configuration to be present. Applying without a configuration `+
+				`would mark everything for destruction, which is normally not what is desired. `+
+				`If you would like to destroy everything, please run 'terraform destroy' which `+
+				`does not require any configuration files.`,
+		))
+	}
+
+	// For API versions prior to 2.3, RemoteAPIVersion will return an empty string,
+	// so if there's an error when parsing the RemoteAPIVersion, it's handled as
+	// equivalent to an API version < 2.3.
+	currentAPIVersion, parseErr := version.NewVersion(b.client.RemoteAPIVersion())
+
+	if !op.PlanRefresh {
+		desiredAPIVersion, _ := version.NewVersion("2.4")
+
+		if parseErr != nil || currentAPIVersion.LessThan(desiredAPIVersion) {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Planning without refresh is not supported",
+				fmt.Sprintf(
+					`The host %s does not support the -refresh=false option for `+
+						`remote plans.`,
+					b.hostname,
+				),
+			))
+		}
+	}
+
+	if op.PlanMode == plans.RefreshOnlyMode {
+		desiredAPIVersion, _ := version.NewVersion("2.4")
+
+		if parseErr != nil || currentAPIVersion.LessThan(desiredAPIVersion) {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Refresh-only mode is not supported",
+				fmt.Sprintf(
+					`The host %s does not support -refresh-only mode for `+
+						`remote plans.`,
+					b.hostname,
+				),
+			))
+		}
+	}
+
+	if len(op.ForceReplace) != 0 {
+		desiredAPIVersion, _ := version.NewVersion("2.4")
+
+		if parseErr != nil || currentAPIVersion.LessThan(desiredAPIVersion) {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Planning resource replacements is not supported",
+				fmt.Sprintf(
+					`The host %s does not support the -replace option for `+
+						`remote plans.`,
+					b.hostname,
+				),
+			))
+		}
+	}
+
+	if len(op.Targets) != 0 {
+		desiredAPIVersion, _ := version.NewVersion("2.3")
+
+		if parseErr != nil || currentAPIVersion.LessThan(desiredAPIVersion) {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Resource targeting is not supported",
+				fmt.Sprintf(
+					`The host %s does not support the -target option for `+
+						`remote plans.`,
+					b.hostname,
+				),
+			))
+		}
+	}
+
+	// Return if there are any errors.
+	if diags.HasErrors() {
+		return nil, diags.Err()
+	}
+
+	// Run the plan phase.
+	r, err := b.plan(stopCtx, cancelCtx, op, w)
+	if err != nil {
+		return r, err
+	}
+
+	// This check is also performed in the plan method to determine if
+	// the policies should be checked, but we need to check the values
+	// here again to determine if we are done and should return.
+	if !r.HasChanges || r.Status == tfe.RunCanceled || r.Status == tfe.RunErrored {
+		return r, nil
+	}
+
+	// Retrieve the run to get its current status.
+	r, err = b.client.Runs.Read(stopCtx, r.ID)
+	if err != nil {
+		return r, generalError("Failed to retrieve run", err)
+	}
+
+	// Return if the run cannot be confirmed.
+	if !w.AutoApply && !r.Actions.IsConfirmable {
+		return r, nil
+	}
+
+	// Since we already checked the permissions before creating the run
+	// this should never happen. But it doesn't hurt to keep this in as
+	// a safeguard for any unexpected situations.
+	if !w.AutoApply && !r.Permissions.CanApply {
+		// Make sure we discard the run if possible.
+		if r.Actions.IsDiscardable {
+			err = b.client.Runs.Discard(stopCtx, r.ID, tfe.RunDiscardOptions{})
+			if err != nil {
+				switch op.PlanMode {
+				case plans.DestroyMode:
+					return r, generalError("Failed to discard destroy", err)
+				default:
+					return r, generalError("Failed to discard apply", err)
+				}
+			}
+		}
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Insufficient rights to approve the pending changes",
+			fmt.Sprintf("There are pending changes, but the provided credentials have "+
+				"insufficient rights to approve them. The run will be discarded to prevent "+
+				"it from blocking the queue waiting for external approval. To queue a run "+
+				"that can be approved by someone else, please use the 'Queue Plan' button in "+
+				"the web UI:\nhttps://%s/app/%s/%s/runs", b.hostname, b.organization, op.Workspace),
+		))
+		return r, diags.Err()
+	}
+
+	mustConfirm := (op.UIIn != nil && op.UIOut != nil) && !op.AutoApprove
+
+	if !w.AutoApply {
+		if mustConfirm {
+			opts := &terraform.InputOpts{Id: "approve"}
+
+			if op.PlanMode == plans.DestroyMode {
+				opts.Query = "\nDo you really want to destroy all resources in workspace \"" + op.Workspace + "\"?"
+				opts.Description = "Terraform will destroy all your managed infrastructure, as shown above.\n" +
+					"There is no undo. Only 'yes' will be accepted to confirm."
+			} else {
+				opts.Query = "\nDo you want to perform these actions in workspace \"" + op.Workspace + "\"?"
+				opts.Description = "Terraform will perform the actions described above.\n" +
+					"Only 'yes' will be accepted to approve."
+			}
+
+			err = b.confirm(stopCtx, op, opts, r, "yes")
+			if err != nil && err != errRunApproved {
+				return r, err
+			}
+		}
+
+		if err != errRunApproved {
+			if err = b.client.Runs.Apply(stopCtx, r.ID, tfe.RunApplyOptions{}); err != nil {
+				return r, generalError("Failed to approve the apply command", err)
+			}
+		}
+	}
+
+	// If we don't need to ask for confirmation, insert a blank
+	// line to separate the ouputs.
+	if w.AutoApply || !mustConfirm {
+		if b.CLI != nil {
+			b.CLI.Output("")
+		}
+	}
+
+	r, err = b.waitForRun(stopCtx, cancelCtx, op, "apply", r, w)
+	if err != nil {
+		return r, err
+	}
+
+	logs, err := b.client.Applies.Logs(stopCtx, r.Apply.ID)
+	if err != nil {
+		return r, generalError("Failed to retrieve logs", err)
+	}
+	reader := bufio.NewReaderSize(logs, 64*1024)
+
+	if b.CLI != nil {
+		skip := 0
+		for next := true; next; {
+			var l, line []byte
+
+			for isPrefix := true; isPrefix; {
+				l, isPrefix, err = reader.ReadLine()
+				if err != nil {
+					if err != io.EOF {
+						return r, generalError("Failed to read logs", err)
+					}
+					next = false
+				}
+				line = append(line, l...)
+			}
+
+			// Skip the first 3 lines to prevent duplicate output.
+			if skip < 3 {
+				skip++
+				continue
+			}
+
+			if next || len(line) > 0 {
+				b.CLI.Output(b.Colorize().Color(string(line)))
+			}
+		}
+	}
+
+	return r, nil
+}
+
+const applyDefaultHeader = `
+[reset][yellow]Running apply in the remote backend. Output will stream here. Pressing Ctrl-C
+will cancel the remote apply if it's still pending. If the apply started it
+will stop streaming the logs, but will not stop the apply running remotely.[reset]
+
+Preparing the remote apply...
+`
diff --git a/v1.5.7/internal/backend/remote/backend_apply_test.go b/v1.5.7/internal/backend/remote/backend_apply_test.go
new file mode 100644
index 0000000..acabebb
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/backend_apply_test.go
@@ -0,0 +1,1668 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"context"
+	"os"
+	"os/signal"
+	"strings"
+	"syscall"
+	"testing"
+	"time"
+
+	"github.com/google/go-cmp/cmp"
+	tfe "github.com/hashicorp/go-tfe"
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/cloud"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+	tfversion "github.com/hashicorp/terraform/version"
+	"github.com/mitchellh/cli"
+)
+
+func testOperationApply(t *testing.T, configDir string) (*backend.Operation, func(), func(*testing.T) *terminal.TestOutput) {
+	t.Helper()
+
+	return testOperationApplyWithTimeout(t, configDir, 0)
+}
+
+func testOperationApplyWithTimeout(t *testing.T, configDir string, timeout time.Duration) (*backend.Operation, func(), func(*testing.T) *terminal.TestOutput) {
+	t.Helper()
+
+	_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewView(streams)
+	stateLockerView := views.NewStateLocker(arguments.ViewHuman, view)
+	operationView := views.NewOperation(arguments.ViewHuman, false, view)
+
+	// Many of our tests use an overridden "null" provider that's just in-memory
+	// inside the test process, not a separate plugin on disk.
+	depLocks := depsfile.NewLocks()
+	depLocks.SetProviderOverridden(addrs.MustParseProviderSourceString("registry.terraform.io/hashicorp/null"))
+
+	return &backend.Operation{
+		ConfigDir:       configDir,
+		ConfigLoader:    configLoader,
+		PlanRefresh:     true,
+		StateLocker:     clistate.NewLocker(timeout, stateLockerView),
+		Type:            backend.OperationTypeApply,
+		View:            operationView,
+		DependencyLocks: depLocks,
+	}, configCleanup, done
+}
+
+func TestRemote_applyBasic(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+
+	stateMgr, _ := b.StateMgr(backend.DefaultStateName)
+	// An error suggests that the state was not unlocked after apply
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after apply: %s", err.Error())
+	}
+}
+
+func TestRemote_applyCanceled(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	// Stop the run to simulate a Ctrl-C.
+	run.Stop()
+
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+
+	stateMgr, _ := b.StateMgr(backend.DefaultStateName)
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after cancelling apply: %s", err.Error())
+	}
+}
+
+func TestRemote_applyWithoutPermissions(t *testing.T) {
+	b, bCleanup := testBackendNoDefault(t)
+	defer bCleanup()
+
+	// Create a named workspace without permissions.
+	w, err := b.client.Workspaces.Create(
+		context.Background(),
+		b.organization,
+		tfe.WorkspaceCreateOptions{
+			Name: tfe.String(b.prefix + "prod"),
+		},
+	)
+	if err != nil {
+		t.Fatalf("error creating named workspace: %v", err)
+	}
+	w.Permissions.CanQueueApply = false
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+
+	op.UIOut = b.CLI
+	op.Workspace = "prod"
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "Insufficient rights to apply changes") {
+		t.Fatalf("expected a permissions error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_applyWithVCS(t *testing.T) {
+	b, bCleanup := testBackendNoDefault(t)
+	defer bCleanup()
+
+	// Create a named workspace with a VCS.
+	_, err := b.client.Workspaces.Create(
+		context.Background(),
+		b.organization,
+		tfe.WorkspaceCreateOptions{
+			Name:    tfe.String(b.prefix + "prod"),
+			VCSRepo: &tfe.VCSRepoOptions{},
+		},
+	)
+	if err != nil {
+		t.Fatalf("error creating named workspace: %v", err)
+	}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+
+	op.Workspace = "prod"
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "not allowed for workspaces with a VCS") {
+		t.Fatalf("expected a VCS error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_applyWithParallelism(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+
+	if b.ContextOpts == nil {
+		b.ContextOpts = &terraform.ContextOpts{}
+	}
+	b.ContextOpts.Parallelism = 3
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "parallelism values are currently not supported") {
+		t.Fatalf("expected a parallelism error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_applyWithPlan(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+
+	op.PlanFile = &planfile.Reader{}
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "saved plan is currently not supported") {
+		t.Fatalf("expected a saved plan error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_applyWithoutRefresh(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	op.PlanRefresh = false
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected plan to be non-empty")
+	}
+
+	// We should find a run inside the mock client that has refresh set
+	// to false.
+	runsAPI := b.client.Runs.(*cloud.MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff(false, run.Refresh); diff != "" {
+			t.Errorf("wrong Refresh setting in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestRemote_applyWithoutRefreshIncompatibleAPIVersion(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+
+	b.client.SetFakeRemoteAPIVersion("2.3")
+
+	op.PlanRefresh = false
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "Planning without refresh is not supported") {
+		t.Fatalf("expected a not supported error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_applyWithRefreshOnly(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	op.PlanMode = plans.RefreshOnlyMode
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected plan to be non-empty")
+	}
+
+	// We should find a run inside the mock client that has refresh-only set
+	// to true.
+	runsAPI := b.client.Runs.(*cloud.MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff(true, run.RefreshOnly); diff != "" {
+			t.Errorf("wrong RefreshOnly setting in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestRemote_applyWithRefreshOnlyIncompatibleAPIVersion(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+
+	b.client.SetFakeRemoteAPIVersion("2.3")
+
+	op.PlanMode = plans.RefreshOnlyMode
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "Refresh-only mode is not supported") {
+		t.Fatalf("expected a not supported error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_applyWithTarget(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	addr, _ := addrs.ParseAbsResourceStr("null_resource.foo")
+
+	op.Targets = []addrs.Targetable{addr}
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatal("expected apply operation to succeed")
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected plan to be non-empty")
+	}
+
+	// We should find a run inside the mock client that has the same
+	// target address we requested above.
+	runsAPI := b.client.Runs.(*cloud.MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff([]string{"null_resource.foo"}, run.TargetAddrs); diff != "" {
+			t.Errorf("wrong TargetAddrs in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestRemote_applyWithTargetIncompatibleAPIVersion(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+
+	// Set the tfe client's RemoteAPIVersion to an empty string, to mimic
+	// API versions prior to 2.3.
+	b.client.SetFakeRemoteAPIVersion("")
+
+	addr, _ := addrs.ParseAbsResourceStr("null_resource.foo")
+
+	op.Targets = []addrs.Targetable{addr}
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "Resource targeting is not supported") {
+		t.Fatalf("expected a targeting error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_applyWithReplace(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	addr, _ := addrs.ParseAbsResourceInstanceStr("null_resource.foo")
+
+	op.ForceReplace = []addrs.AbsResourceInstance{addr}
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatal("expected plan operation to succeed")
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected plan to be non-empty")
+	}
+
+	// We should find a run inside the mock client that has the same
+	// refresh address we requested above.
+	runsAPI := b.client.Runs.(*cloud.MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff([]string{"null_resource.foo"}, run.ReplaceAddrs); diff != "" {
+			t.Errorf("wrong ReplaceAddrs in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestRemote_applyWithReplaceIncompatibleAPIVersion(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+
+	b.client.SetFakeRemoteAPIVersion("2.3")
+
+	addr, _ := addrs.ParseAbsResourceInstanceStr("null_resource.foo")
+
+	op.ForceReplace = []addrs.AbsResourceInstance{addr}
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "Planning resource replacements is not supported") {
+		t.Fatalf("expected a not supported error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_applyWithVariables(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-variables")
+	defer configCleanup()
+
+	op.Variables = testVariables(terraform.ValueFromNamedFile, "foo", "bar")
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "variables are currently not supported") {
+		t.Fatalf("expected a variables error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_applyNoConfig(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/empty")
+	defer configCleanup()
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "configuration files found") {
+		t.Fatalf("expected configuration files error, got: %v", errOutput)
+	}
+
+	stateMgr, _ := b.StateMgr(backend.DefaultStateName)
+	// An error suggests that the state was not unlocked after apply
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after failed apply: %s", err.Error())
+	}
+}
+
+func TestRemote_applyNoChanges(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-no-changes")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "No changes. Infrastructure is up-to-date.") {
+		t.Fatalf("expected no changes in plan summery: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: true") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+}
+
+func TestRemote_applyNoApprove(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+
+	input := testInput(t, map[string]string{
+		"approve": "no",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "Apply discarded") {
+		t.Fatalf("expected an apply discarded error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_applyAutoApprove(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "no",
+	})
+
+	op.AutoApprove = true
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) != 1 {
+		t.Fatalf("expected an unused answer, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+}
+
+func TestRemote_applyApprovedExternally(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "wait-for-external-update",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = backend.DefaultStateName
+
+	ctx := context.Background()
+
+	run, err := b.Operation(ctx, op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	// Wait 50 milliseconds to make sure the run started.
+	time.Sleep(50 * time.Millisecond)
+
+	wl, err := b.client.Workspaces.List(
+		ctx,
+		b.organization,
+		nil,
+	)
+	if err != nil {
+		t.Fatalf("unexpected error listing workspaces: %v", err)
+	}
+	if len(wl.Items) != 1 {
+		t.Fatalf("expected 1 workspace, got %d workspaces", len(wl.Items))
+	}
+
+	rl, err := b.client.Runs.List(ctx, wl.Items[0].ID, nil)
+	if err != nil {
+		t.Fatalf("unexpected error listing runs: %v", err)
+	}
+	if len(rl.Items) != 1 {
+		t.Fatalf("expected 1 run, got %d runs", len(rl.Items))
+	}
+
+	err = b.client.Runs.Apply(context.Background(), rl.Items[0].ID, tfe.RunApplyOptions{})
+	if err != nil {
+		t.Fatalf("unexpected error approving run: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "approved using the UI or API") {
+		t.Fatalf("expected external approval in output: %s", output)
+	}
+	if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+}
+
+func TestRemote_applyDiscardedExternally(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "wait-for-external-update",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = backend.DefaultStateName
+
+	ctx := context.Background()
+
+	run, err := b.Operation(ctx, op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	// Wait 50 milliseconds to make sure the run started.
+	time.Sleep(50 * time.Millisecond)
+
+	wl, err := b.client.Workspaces.List(
+		ctx,
+		b.organization,
+		nil,
+	)
+	if err != nil {
+		t.Fatalf("unexpected error listing workspaces: %v", err)
+	}
+	if len(wl.Items) != 1 {
+		t.Fatalf("expected 1 workspace, got %d workspaces", len(wl.Items))
+	}
+
+	rl, err := b.client.Runs.List(ctx, wl.Items[0].ID, nil)
+	if err != nil {
+		t.Fatalf("unexpected error listing runs: %v", err)
+	}
+	if len(rl.Items) != 1 {
+		t.Fatalf("expected 1 run, got %d runs", len(rl.Items))
+	}
+
+	err = b.client.Runs.Discard(context.Background(), rl.Items[0].ID, tfe.RunDiscardOptions{})
+	if err != nil {
+		t.Fatalf("unexpected error discarding run: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "discarded using the UI or API") {
+		t.Fatalf("expected external discard output: %s", output)
+	}
+	if strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("unexpected apply summery in output: %s", output)
+	}
+}
+
+func TestRemote_applyWithAutoApply(t *testing.T) {
+	b, bCleanup := testBackendNoDefault(t)
+	defer bCleanup()
+
+	// Create a named workspace that auto applies.
+	_, err := b.client.Workspaces.Create(
+		context.Background(),
+		b.organization,
+		tfe.WorkspaceCreateOptions{
+			AutoApply: tfe.Bool(true),
+			Name:      tfe.String(b.prefix + "prod"),
+		},
+	)
+	if err != nil {
+		t.Fatalf("error creating named workspace: %v", err)
+	}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = "prod"
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) != 1 {
+		t.Fatalf("expected an unused answer, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+}
+
+func TestRemote_applyForceLocal(t *testing.T) {
+	// Set TF_FORCE_LOCAL_BACKEND so the remote backend will use
+	// the local backend with itself as embedded backend.
+	if err := os.Setenv("TF_FORCE_LOCAL_BACKEND", "1"); err != nil {
+		t.Fatalf("error setting environment variable TF_FORCE_LOCAL_BACKEND: %v", err)
+	}
+	defer os.Unsetenv("TF_FORCE_LOCAL_BACKEND")
+
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = backend.DefaultStateName
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams))
+	op.View = view
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if strings.Contains(output, "Running apply in the remote backend") {
+		t.Fatalf("unexpected remote backend header in output: %s", output)
+	}
+	if output := done(t).Stdout(); !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+	if !run.State.HasManagedResourceInstanceObjects() {
+		t.Fatalf("expected resources in state")
+	}
+}
+
+func TestRemote_applyWorkspaceWithoutOperations(t *testing.T) {
+	b, bCleanup := testBackendNoDefault(t)
+	defer bCleanup()
+
+	ctx := context.Background()
+
+	// Create a named workspace that doesn't allow operations.
+	_, err := b.client.Workspaces.Create(
+		ctx,
+		b.organization,
+		tfe.WorkspaceCreateOptions{
+			Name: tfe.String(b.prefix + "no-operations"),
+		},
+	)
+	if err != nil {
+		t.Fatalf("error creating named workspace: %v", err)
+	}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = "no-operations"
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams))
+	op.View = view
+
+	run, err := b.Operation(ctx, op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if strings.Contains(output, "Running apply in the remote backend") {
+		t.Fatalf("unexpected remote backend header in output: %s", output)
+	}
+	if output := done(t).Stdout(); !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+	if !run.State.HasManagedResourceInstanceObjects() {
+		t.Fatalf("expected resources in state")
+	}
+}
+
+func TestRemote_applyLockTimeout(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	ctx := context.Background()
+
+	// Retrieve the workspace used to run this operation in.
+	w, err := b.client.Workspaces.Read(ctx, b.organization, b.workspace)
+	if err != nil {
+		t.Fatalf("error retrieving workspace: %v", err)
+	}
+
+	// Create a new configuration version.
+	c, err := b.client.ConfigurationVersions.Create(ctx, w.ID, tfe.ConfigurationVersionCreateOptions{})
+	if err != nil {
+		t.Fatalf("error creating configuration version: %v", err)
+	}
+
+	// Create a pending run to block this run.
+	_, err = b.client.Runs.Create(ctx, tfe.RunCreateOptions{
+		ConfigurationVersion: c,
+		Workspace:            w,
+	})
+	if err != nil {
+		t.Fatalf("error creating pending run: %v", err)
+	}
+
+	op, configCleanup, done := testOperationApplyWithTimeout(t, "./testdata/apply", 50*time.Millisecond)
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"cancel":  "yes",
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = backend.DefaultStateName
+
+	_, err = b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	sigint := make(chan os.Signal, 1)
+	signal.Notify(sigint, syscall.SIGINT)
+	select {
+	case <-sigint:
+		// Stop redirecting SIGINT signals.
+		signal.Stop(sigint)
+	case <-time.After(200 * time.Millisecond):
+		t.Fatalf("expected lock timeout after 50 milliseconds, waited 200 milliseconds")
+	}
+
+	if len(input.answers) != 2 {
+		t.Fatalf("expected unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "Lock timeout exceeded") {
+		t.Fatalf("expected lock timout error in output: %s", output)
+	}
+	if strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("unexpected plan summery in output: %s", output)
+	}
+	if strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("unexpected apply summery in output: %s", output)
+	}
+}
+
+func TestRemote_applyDestroy(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-destroy")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.PlanMode = plans.DestroyMode
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "0 to add, 0 to change, 1 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "0 added, 0 changed, 1 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+}
+
+func TestRemote_applyDestroyNoConfig(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/empty")
+	defer configCleanup()
+	defer done(t)
+
+	op.PlanMode = plans.DestroyMode
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+}
+
+func TestRemote_applyPolicyPass(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-policy-passed")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: true") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+	if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+}
+
+func TestRemote_applyPolicyHardFail(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-policy-hard-failed")
+	defer configCleanup()
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	viewOutput := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	if len(input.answers) != 1 {
+		t.Fatalf("expected an unused answers, got: %v", input.answers)
+	}
+
+	errOutput := viewOutput.Stderr()
+	if !strings.Contains(errOutput, "hard failed") {
+		t.Fatalf("expected a policy check error, got: %v", errOutput)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: false") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+	if strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("unexpected apply summery in output: %s", output)
+	}
+}
+
+func TestRemote_applyPolicySoftFail(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-policy-soft-failed")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"override": "override",
+		"approve":  "yes",
+	})
+
+	op.AutoApprove = false
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: false") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+	if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+}
+
+func TestRemote_applyPolicySoftFailAutoApproveSuccess(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-policy-soft-failed")
+	defer configCleanup()
+
+	input := testInput(t, map[string]string{})
+
+	op.AutoApprove = true
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	viewOutput := done(t)
+	if run.Result != backend.OperationSuccess {
+		t.Fatal("expected apply operation to success due to auto-approve")
+	}
+
+	if run.PlanEmpty {
+		t.Fatalf("expected plan to not be empty, plan opertion completed without error")
+	}
+
+	if len(input.answers) != 0 {
+		t.Fatalf("expected no answers, got: %v", input.answers)
+	}
+
+	errOutput := viewOutput.Stderr()
+	if strings.Contains(errOutput, "soft failed") {
+		t.Fatalf("expected no policy check errors, instead got: %v", errOutput)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Sentinel Result: false") {
+		t.Fatalf("expected policy check to be false, insead got: %s", output)
+	}
+	if !strings.Contains(output, "Apply complete!") {
+		t.Fatalf("expected apply to be complete, instead got: %s", output)
+	}
+
+	if !strings.Contains(output, "Resources: 1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected resources, instead got: %s", output)
+	}
+}
+
+func TestRemote_applyPolicySoftFailAutoApply(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	// Create a named workspace that auto applies.
+	_, err := b.client.Workspaces.Create(
+		context.Background(),
+		b.organization,
+		tfe.WorkspaceCreateOptions{
+			AutoApply: tfe.Bool(true),
+			Name:      tfe.String(b.prefix + "prod"),
+		},
+	)
+	if err != nil {
+		t.Fatalf("error creating named workspace: %v", err)
+	}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-policy-soft-failed")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"override": "override",
+		"approve":  "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = "prod"
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) != 1 {
+		t.Fatalf("expected an unused answer, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: false") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+	if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+}
+
+func TestRemote_applyWithRemoteError(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-with-error")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if run.Result.ExitStatus() != 1 {
+		t.Fatalf("expected exit code 1, got %d", run.Result.ExitStatus())
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "null_resource.foo: 1 error") {
+		t.Fatalf("expected apply error in output: %s", output)
+	}
+}
+
+func TestRemote_applyVersionCheck(t *testing.T) {
+	testCases := map[string]struct {
+		localVersion  string
+		remoteVersion string
+		forceLocal    bool
+		executionMode string
+		wantErr       string
+	}{
+		"versions can be different for remote apply": {
+			localVersion:  "0.14.0",
+			remoteVersion: "0.13.5",
+			executionMode: "remote",
+		},
+		"versions can be different for local apply": {
+			localVersion:  "0.14.0",
+			remoteVersion: "0.13.5",
+			executionMode: "local",
+		},
+		"force local with remote operations and different versions is acceptable": {
+			localVersion:  "0.14.0",
+			remoteVersion: "0.14.0-acme-provider-bundle",
+			forceLocal:    true,
+			executionMode: "remote",
+		},
+		"no error if versions are identical": {
+			localVersion:  "0.14.0",
+			remoteVersion: "0.14.0",
+			forceLocal:    true,
+			executionMode: "remote",
+		},
+		"no error if force local but workspace has remote operations disabled": {
+			localVersion:  "0.14.0",
+			remoteVersion: "0.13.5",
+			forceLocal:    true,
+			executionMode: "local",
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			b, bCleanup := testBackendDefault(t)
+			defer bCleanup()
+
+			// SETUP: Save original local version state and restore afterwards
+			p := tfversion.Prerelease
+			v := tfversion.Version
+			s := tfversion.SemVer
+			defer func() {
+				tfversion.Prerelease = p
+				tfversion.Version = v
+				tfversion.SemVer = s
+			}()
+
+			// SETUP: Set local version for the test case
+			tfversion.Prerelease = ""
+			tfversion.Version = tc.localVersion
+			tfversion.SemVer = version.Must(version.NewSemver(tc.localVersion))
+
+			// SETUP: Set force local for the test case
+			b.forceLocal = tc.forceLocal
+
+			ctx := context.Background()
+
+			// SETUP: set the operations and Terraform Version fields on the
+			// remote workspace
+			_, err := b.client.Workspaces.Update(
+				ctx,
+				b.organization,
+				b.workspace,
+				tfe.WorkspaceUpdateOptions{
+					ExecutionMode:    tfe.String(tc.executionMode),
+					TerraformVersion: tfe.String(tc.remoteVersion),
+				},
+			)
+			if err != nil {
+				t.Fatalf("error creating named workspace: %v", err)
+			}
+
+			// RUN: prepare the apply operation and run it
+			op, configCleanup, _ := testOperationApply(t, "./testdata/apply")
+			defer configCleanup()
+
+			streams, done := terminal.StreamsForTesting(t)
+			view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams))
+			op.View = view
+
+			input := testInput(t, map[string]string{
+				"approve": "yes",
+			})
+
+			op.UIIn = input
+			op.UIOut = b.CLI
+			op.Workspace = backend.DefaultStateName
+
+			run, err := b.Operation(ctx, op)
+			if err != nil {
+				t.Fatalf("error starting operation: %v", err)
+			}
+
+			// RUN: wait for completion
+			<-run.Done()
+			output := done(t)
+
+			if tc.wantErr != "" {
+				// ASSERT: if the test case wants an error, check for failure
+				// and the error message
+				if run.Result != backend.OperationFailure {
+					t.Fatalf("expected run to fail, but result was %#v", run.Result)
+				}
+				errOutput := output.Stderr()
+				if !strings.Contains(errOutput, tc.wantErr) {
+					t.Fatalf("missing error %q\noutput: %s", tc.wantErr, errOutput)
+				}
+			} else {
+				// ASSERT: otherwise, check for success and appropriate output
+				// based on whether the run should be local or remote
+				if run.Result != backend.OperationSuccess {
+					t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+				}
+				output := b.CLI.(*cli.MockUi).OutputWriter.String()
+				hasRemote := strings.Contains(output, "Running apply in the remote backend")
+				hasSummary := strings.Contains(output, "1 added, 0 changed, 0 destroyed")
+				hasResources := run.State.HasManagedResourceInstanceObjects()
+				if !tc.forceLocal && !isLocalExecutionMode(tc.executionMode) {
+					if !hasRemote {
+						t.Errorf("missing remote backend header in output: %s", output)
+					}
+					if !hasSummary {
+						t.Errorf("expected apply summary in output: %s", output)
+					}
+				} else {
+					if hasRemote {
+						t.Errorf("unexpected remote backend header in output: %s", output)
+					}
+					if !hasResources {
+						t.Errorf("expected resources in state")
+					}
+				}
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/backend/remote/backend_common.go b/v1.5.7/internal/backend/remote/backend_common.go
new file mode 100644
index 0000000..78928f8
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/backend_common.go
@@ -0,0 +1,580 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"bufio"
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"math"
+	"strconv"
+	"strings"
+	"time"
+
+	tfe "github.com/hashicorp/go-tfe"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+var (
+	errApplyDiscarded   = errors.New("Apply discarded.")
+	errDestroyDiscarded = errors.New("Destroy discarded.")
+	errRunApproved      = errors.New("approved using the UI or API")
+	errRunDiscarded     = errors.New("discarded using the UI or API")
+	errRunOverridden    = errors.New("overridden using the UI or API")
+)
+
+var (
+	backoffMin = 1000.0
+	backoffMax = 3000.0
+
+	runPollInterval = 3 * time.Second
+)
+
+// backoff will perform exponential backoff based on the iteration and
+// limited by the provided min and max (in milliseconds) durations.
+func backoff(min, max float64, iter int) time.Duration {
+	backoff := math.Pow(2, float64(iter)/5) * min
+	if backoff > max {
+		backoff = max
+	}
+	return time.Duration(backoff) * time.Millisecond
+}
+
+func (b *Remote) waitForRun(stopCtx, cancelCtx context.Context, op *backend.Operation, opType string, r *tfe.Run, w *tfe.Workspace) (*tfe.Run, error) {
+	started := time.Now()
+	updated := started
+	for i := 0; ; i++ {
+		select {
+		case <-stopCtx.Done():
+			return r, stopCtx.Err()
+		case <-cancelCtx.Done():
+			return r, cancelCtx.Err()
+		case <-time.After(backoff(backoffMin, backoffMax, i)):
+			// Timer up, show status
+		}
+
+		// Retrieve the run to get its current status.
+		r, err := b.client.Runs.Read(stopCtx, r.ID)
+		if err != nil {
+			return r, generalError("Failed to retrieve run", err)
+		}
+
+		// Return if the run is no longer pending.
+		if r.Status != tfe.RunPending && r.Status != tfe.RunConfirmed {
+			if i == 0 && opType == "plan" && b.CLI != nil {
+				b.CLI.Output(b.Colorize().Color(fmt.Sprintf("Waiting for the %s to start...\n", opType)))
+			}
+			if i > 0 && b.CLI != nil {
+				// Insert a blank line to separate the ouputs.
+				b.CLI.Output("")
+			}
+			return r, nil
+		}
+
+		// Check if 30 seconds have passed since the last update.
+		current := time.Now()
+		if b.CLI != nil && (i == 0 || current.Sub(updated).Seconds() > 30) {
+			updated = current
+			position := 0
+			elapsed := ""
+
+			// Calculate and set the elapsed time.
+			if i > 0 {
+				elapsed = fmt.Sprintf(
+					" (%s elapsed)", current.Sub(started).Truncate(30*time.Second))
+			}
+
+			// Retrieve the workspace used to run this operation in.
+			w, err = b.client.Workspaces.Read(stopCtx, b.organization, w.Name)
+			if err != nil {
+				return nil, generalError("Failed to retrieve workspace", err)
+			}
+
+			// If the workspace is locked the run will not be queued and we can
+			// update the status without making any expensive calls.
+			if w.Locked && w.CurrentRun != nil {
+				cr, err := b.client.Runs.Read(stopCtx, w.CurrentRun.ID)
+				if err != nil {
+					return r, generalError("Failed to retrieve current run", err)
+				}
+				if cr.Status == tfe.RunPending {
+					b.CLI.Output(b.Colorize().Color(
+						"Waiting for the manually locked workspace to be unlocked..." + elapsed))
+					continue
+				}
+			}
+
+			// Skip checking the workspace queue when we are the current run.
+			if w.CurrentRun == nil || w.CurrentRun.ID != r.ID {
+				found := false
+				options := &tfe.RunListOptions{}
+			runlist:
+				for {
+					rl, err := b.client.Runs.List(stopCtx, w.ID, options)
+					if err != nil {
+						return r, generalError("Failed to retrieve run list", err)
+					}
+
+					// Loop through all runs to calculate the workspace queue position.
+					for _, item := range rl.Items {
+						if !found {
+							if r.ID == item.ID {
+								found = true
+							}
+							continue
+						}
+
+						// If the run is in a final state, ignore it and continue.
+						switch item.Status {
+						case tfe.RunApplied, tfe.RunCanceled, tfe.RunDiscarded, tfe.RunErrored:
+							continue
+						case tfe.RunPlanned:
+							if op.Type == backend.OperationTypePlan {
+								continue
+							}
+						}
+
+						// Increase the workspace queue position.
+						position++
+
+						// Stop searching when we reached the current run.
+						if w.CurrentRun != nil && w.CurrentRun.ID == item.ID {
+							break runlist
+						}
+					}
+
+					// Exit the loop when we've seen all pages.
+					if rl.CurrentPage >= rl.TotalPages {
+						break
+					}
+
+					// Update the page number to get the next page.
+					options.PageNumber = rl.NextPage
+				}
+
+				if position > 0 {
+					b.CLI.Output(b.Colorize().Color(fmt.Sprintf(
+						"Waiting for %d run(s) to finish before being queued...%s",
+						position,
+						elapsed,
+					)))
+					continue
+				}
+			}
+
+			options := tfe.ReadRunQueueOptions{}
+		search:
+			for {
+				rq, err := b.client.Organizations.ReadRunQueue(stopCtx, b.organization, options)
+				if err != nil {
+					return r, generalError("Failed to retrieve queue", err)
+				}
+
+				// Search through all queued items to find our run.
+				for _, item := range rq.Items {
+					if r.ID == item.ID {
+						position = item.PositionInQueue
+						break search
+					}
+				}
+
+				// Exit the loop when we've seen all pages.
+				if rq.CurrentPage >= rq.TotalPages {
+					break
+				}
+
+				// Update the page number to get the next page.
+				options.PageNumber = rq.NextPage
+			}
+
+			if position > 0 {
+				c, err := b.client.Organizations.ReadCapacity(stopCtx, b.organization)
+				if err != nil {
+					return r, generalError("Failed to retrieve capacity", err)
+				}
+				b.CLI.Output(b.Colorize().Color(fmt.Sprintf(
+					"Waiting for %d queued run(s) to finish before starting...%s",
+					position-c.Running,
+					elapsed,
+				)))
+				continue
+			}
+
+			b.CLI.Output(b.Colorize().Color(fmt.Sprintf(
+				"Waiting for the %s to start...%s", opType, elapsed)))
+		}
+	}
+}
+
+// hasExplicitVariableValues is a best-effort check to determine whether the
+// user has provided -var or -var-file arguments to a remote operation.
+//
+// The results may be inaccurate if the configuration is invalid or if
+// individual variable values are invalid. That's okay because we only use this
+// result to hint the user to set variables a different way. It's always the
+// remote system's responsibility to do final validation of the input.
+func (b *Remote) hasExplicitVariableValues(op *backend.Operation) bool {
+	// Load the configuration using the caller-provided configuration loader.
+	config, _, configDiags := op.ConfigLoader.LoadConfigWithSnapshot(op.ConfigDir)
+	if configDiags.HasErrors() {
+		// If we can't load the configuration then we'll assume no explicit
+		// variable values just to let the remote operation start and let
+		// the remote system return the same set of configuration errors.
+		return false
+	}
+
+	// We're intentionally ignoring the diagnostics here because validation
+	// of the variable values is the responsibilty of the remote system. Our
+	// goal here is just to make a best effort count of how many variable
+	// values are coming from -var or -var-file CLI arguments so that we can
+	// hint the user that those are not supported for remote operations.
+	variables, _ := backend.ParseVariableValues(op.Variables, config.Module.Variables)
+
+	// Check for explicitly-defined (-var and -var-file) variables, which the
+	// remote backend does not support. All other source types are okay,
+	// because they are implicit from the execution context anyway and so
+	// their final values will come from the _remote_ execution context.
+	for _, v := range variables {
+		switch v.SourceType {
+		case terraform.ValueFromCLIArg, terraform.ValueFromNamedFile:
+			return true
+		}
+	}
+
+	return false
+}
+
+func (b *Remote) costEstimate(stopCtx, cancelCtx context.Context, op *backend.Operation, r *tfe.Run) error {
+	if r.CostEstimate == nil {
+		return nil
+	}
+
+	msgPrefix := "Cost estimation"
+	started := time.Now()
+	updated := started
+	for i := 0; ; i++ {
+		select {
+		case <-stopCtx.Done():
+			return stopCtx.Err()
+		case <-cancelCtx.Done():
+			return cancelCtx.Err()
+		case <-time.After(backoff(backoffMin, backoffMax, i)):
+		}
+
+		// Retrieve the cost estimate to get its current status.
+		ce, err := b.client.CostEstimates.Read(stopCtx, r.CostEstimate.ID)
+		if err != nil {
+			return generalError("Failed to retrieve cost estimate", err)
+		}
+
+		// If the run is canceled or errored, but the cost-estimate still has
+		// no result, there is nothing further to render.
+		if ce.Status != tfe.CostEstimateFinished {
+			if r.Status == tfe.RunCanceled || r.Status == tfe.RunErrored {
+				return nil
+			}
+		}
+
+		// checking if i == 0 so as to avoid printing this starting horizontal-rule
+		// every retry, and that it only prints it on the first (i=0) attempt.
+		if b.CLI != nil && i == 0 {
+			b.CLI.Output("\n------------------------------------------------------------------------\n")
+		}
+
+		switch ce.Status {
+		case tfe.CostEstimateFinished:
+			delta, err := strconv.ParseFloat(ce.DeltaMonthlyCost, 64)
+			if err != nil {
+				return generalError("Unexpected error", err)
+			}
+
+			sign := "+"
+			if delta < 0 {
+				sign = "-"
+			}
+
+			deltaRepr := strings.Replace(ce.DeltaMonthlyCost, "-", "", 1)
+
+			if b.CLI != nil {
+				b.CLI.Output(b.Colorize().Color(msgPrefix + ":\n"))
+				b.CLI.Output(b.Colorize().Color(fmt.Sprintf("Resources: %d of %d estimated", ce.MatchedResourcesCount, ce.ResourcesCount)))
+				b.CLI.Output(b.Colorize().Color(fmt.Sprintf("           $%s/mo %s$%s", ce.ProposedMonthlyCost, sign, deltaRepr)))
+
+				if len(r.PolicyChecks) == 0 && r.HasChanges && op.Type == backend.OperationTypeApply {
+					b.CLI.Output("\n------------------------------------------------------------------------")
+				}
+			}
+
+			return nil
+		case tfe.CostEstimatePending, tfe.CostEstimateQueued:
+			// Check if 30 seconds have passed since the last update.
+			current := time.Now()
+			if b.CLI != nil && (i == 0 || current.Sub(updated).Seconds() > 30) {
+				updated = current
+				elapsed := ""
+
+				// Calculate and set the elapsed time.
+				if i > 0 {
+					elapsed = fmt.Sprintf(
+						" (%s elapsed)", current.Sub(started).Truncate(30*time.Second))
+				}
+				b.CLI.Output(b.Colorize().Color(msgPrefix + ":\n"))
+				b.CLI.Output(b.Colorize().Color("Waiting for cost estimate to complete..." + elapsed + "\n"))
+			}
+			continue
+		case tfe.CostEstimateSkippedDueToTargeting:
+			b.CLI.Output(b.Colorize().Color(msgPrefix + ":\n"))
+			b.CLI.Output("Not available for this plan, because it was created with the -target option.")
+			b.CLI.Output("\n------------------------------------------------------------------------")
+			return nil
+		case tfe.CostEstimateErrored:
+			b.CLI.Output(msgPrefix + " errored.\n")
+			b.CLI.Output("\n------------------------------------------------------------------------")
+			return nil
+		case tfe.CostEstimateCanceled:
+			return fmt.Errorf(msgPrefix + " canceled.")
+		default:
+			return fmt.Errorf("Unknown or unexpected cost estimate state: %s", ce.Status)
+		}
+	}
+}
+
+func (b *Remote) checkPolicy(stopCtx, cancelCtx context.Context, op *backend.Operation, r *tfe.Run) error {
+	if b.CLI != nil {
+		b.CLI.Output("\n------------------------------------------------------------------------\n")
+	}
+	for i, pc := range r.PolicyChecks {
+		// Read the policy check logs. This is a blocking call that will only
+		// return once the policy check is complete.
+		logs, err := b.client.PolicyChecks.Logs(stopCtx, pc.ID)
+		if err != nil {
+			return generalError("Failed to retrieve policy check logs", err)
+		}
+		reader := bufio.NewReaderSize(logs, 64*1024)
+
+		// Retrieve the policy check to get its current status.
+		pc, err := b.client.PolicyChecks.Read(stopCtx, pc.ID)
+		if err != nil {
+			return generalError("Failed to retrieve policy check", err)
+		}
+
+		// If the run is canceled or errored, but the policy check still has
+		// no result, there is nothing further to render.
+		if r.Status == tfe.RunCanceled || r.Status == tfe.RunErrored {
+			switch pc.Status {
+			case tfe.PolicyPending, tfe.PolicyQueued, tfe.PolicyUnreachable:
+				continue
+			}
+		}
+
+		var msgPrefix string
+		switch pc.Scope {
+		case tfe.PolicyScopeOrganization:
+			msgPrefix = "Organization policy check"
+		case tfe.PolicyScopeWorkspace:
+			msgPrefix = "Workspace policy check"
+		default:
+			msgPrefix = fmt.Sprintf("Unknown policy check (%s)", pc.Scope)
+		}
+
+		if b.CLI != nil {
+			b.CLI.Output(b.Colorize().Color(msgPrefix + ":\n"))
+		}
+
+		if b.CLI != nil {
+			for next := true; next; {
+				var l, line []byte
+
+				for isPrefix := true; isPrefix; {
+					l, isPrefix, err = reader.ReadLine()
+					if err != nil {
+						if err != io.EOF {
+							return generalError("Failed to read logs", err)
+						}
+						next = false
+					}
+					line = append(line, l...)
+				}
+
+				if next || len(line) > 0 {
+					b.CLI.Output(b.Colorize().Color(string(line)))
+				}
+			}
+		}
+
+		switch pc.Status {
+		case tfe.PolicyPasses:
+			if (r.HasChanges && op.Type == backend.OperationTypeApply || i < len(r.PolicyChecks)-1) && b.CLI != nil {
+				b.CLI.Output("\n------------------------------------------------------------------------")
+			}
+			continue
+		case tfe.PolicyErrored:
+			return fmt.Errorf(msgPrefix + " errored.")
+		case tfe.PolicyHardFailed:
+			return fmt.Errorf(msgPrefix + " hard failed.")
+		case tfe.PolicySoftFailed:
+			runUrl := fmt.Sprintf(runHeader, b.hostname, b.organization, op.Workspace, r.ID)
+
+			if op.Type == backend.OperationTypePlan || op.UIOut == nil || op.UIIn == nil ||
+				!pc.Actions.IsOverridable || !pc.Permissions.CanOverride {
+				return fmt.Errorf(msgPrefix + " soft failed.\n" + runUrl)
+			}
+
+			if op.AutoApprove {
+				if _, err = b.client.PolicyChecks.Override(stopCtx, pc.ID); err != nil {
+					return generalError(fmt.Sprintf("Failed to override policy check.\n%s", runUrl), err)
+				}
+			} else {
+				opts := &terraform.InputOpts{
+					Id:          "override",
+					Query:       "\nDo you want to override the soft failed policy check?",
+					Description: "Only 'override' will be accepted to override.",
+				}
+				err = b.confirm(stopCtx, op, opts, r, "override")
+				if err != nil && err != errRunOverridden {
+					return fmt.Errorf(
+						fmt.Sprintf("Failed to override: %s\n%s\n", err.Error(), runUrl),
+					)
+				}
+
+				if err != errRunOverridden {
+					if _, err = b.client.PolicyChecks.Override(stopCtx, pc.ID); err != nil {
+						return generalError(fmt.Sprintf("Failed to override policy check.\n%s", runUrl), err)
+					}
+				} else {
+					b.CLI.Output(fmt.Sprintf("The run needs to be manually overridden or discarded.\n%s\n", runUrl))
+				}
+			}
+
+			if b.CLI != nil {
+				b.CLI.Output("------------------------------------------------------------------------")
+			}
+		default:
+			return fmt.Errorf("Unknown or unexpected policy state: %s", pc.Status)
+		}
+	}
+
+	return nil
+}
+
+func (b *Remote) confirm(stopCtx context.Context, op *backend.Operation, opts *terraform.InputOpts, r *tfe.Run, keyword string) error {
+	doneCtx, cancel := context.WithCancel(stopCtx)
+	result := make(chan error, 2)
+
+	go func() {
+		defer logging.PanicHandler()
+
+		// Make sure we cancel doneCtx before we return
+		// so the input command is also canceled.
+		defer cancel()
+
+		for {
+			select {
+			case <-doneCtx.Done():
+				return
+			case <-stopCtx.Done():
+				return
+			case <-time.After(runPollInterval):
+				// Retrieve the run again to get its current status.
+				r, err := b.client.Runs.Read(stopCtx, r.ID)
+				if err != nil {
+					result <- generalError("Failed to retrieve run", err)
+					return
+				}
+
+				switch keyword {
+				case "override":
+					if r.Status != tfe.RunPolicyOverride {
+						if r.Status == tfe.RunDiscarded {
+							err = errRunDiscarded
+						} else {
+							err = errRunOverridden
+						}
+					}
+				case "yes":
+					if !r.Actions.IsConfirmable {
+						if r.Status == tfe.RunDiscarded {
+							err = errRunDiscarded
+						} else {
+							err = errRunApproved
+						}
+					}
+				}
+
+				if err != nil {
+					if b.CLI != nil {
+						b.CLI.Output(b.Colorize().Color(
+							fmt.Sprintf("[reset][yellow]%s[reset]", err.Error())))
+					}
+
+					if err == errRunDiscarded {
+						err = errApplyDiscarded
+						if op.PlanMode == plans.DestroyMode {
+							err = errDestroyDiscarded
+						}
+					}
+
+					result <- err
+					return
+				}
+			}
+		}
+	}()
+
+	result <- func() error {
+		v, err := op.UIIn.Input(doneCtx, opts)
+		if err != nil && err != context.Canceled && stopCtx.Err() != context.Canceled {
+			return fmt.Errorf("Error asking %s: %v", opts.Id, err)
+		}
+
+		// We return the error of our parent channel as we don't
+		// care about the error of the doneCtx which is only used
+		// within this function. So if the doneCtx was canceled
+		// because stopCtx was canceled, this will properly return
+		// a context.Canceled error and otherwise it returns nil.
+		if doneCtx.Err() == context.Canceled || stopCtx.Err() == context.Canceled {
+			return stopCtx.Err()
+		}
+
+		// Make sure we cancel the context here so the loop that
+		// checks for external changes to the run is ended before
+		// we start to make changes ourselves.
+		cancel()
+
+		if v != keyword {
+			// Retrieve the run again to get its current status.
+			r, err = b.client.Runs.Read(stopCtx, r.ID)
+			if err != nil {
+				return generalError("Failed to retrieve run", err)
+			}
+
+			// Make sure we discard the run if possible.
+			if r.Actions.IsDiscardable {
+				err = b.client.Runs.Discard(stopCtx, r.ID, tfe.RunDiscardOptions{})
+				if err != nil {
+					if op.PlanMode == plans.DestroyMode {
+						return generalError("Failed to discard destroy", err)
+					}
+					return generalError("Failed to discard apply", err)
+				}
+			}
+
+			// Even if the run was discarded successfully, we still
+			// return an error as the apply command was canceled.
+			if op.PlanMode == plans.DestroyMode {
+				return errDestroyDiscarded
+			}
+			return errApplyDiscarded
+		}
+
+		return nil
+	}()
+
+	return <-result
+}
diff --git a/v1.5.7/internal/backend/remote/backend_context.go b/v1.5.7/internal/backend/remote/backend_context.go
new file mode 100644
index 0000000..2febe27
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/backend_context.go
@@ -0,0 +1,298 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"strings"
+
+	tfe "github.com/hashicorp/go-tfe"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Context implements backend.Local.
+func (b *Remote) LocalRun(op *backend.Operation) (*backend.LocalRun, statemgr.Full, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	ret := &backend.LocalRun{
+		PlanOpts: &terraform.PlanOpts{
+			Mode:    op.PlanMode,
+			Targets: op.Targets,
+		},
+	}
+
+	op.StateLocker = op.StateLocker.WithContext(context.Background())
+
+	// Get the remote workspace name.
+	remoteWorkspaceName := b.getRemoteWorkspaceName(op.Workspace)
+
+	// Get the latest state.
+	log.Printf("[TRACE] backend/remote: requesting state manager for workspace %q", remoteWorkspaceName)
+	stateMgr, err := b.StateMgr(op.Workspace)
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("error loading state: %w", err))
+		return nil, nil, diags
+	}
+
+	log.Printf("[TRACE] backend/remote: requesting state lock for workspace %q", remoteWorkspaceName)
+	if diags := op.StateLocker.Lock(stateMgr, op.Type.String()); diags.HasErrors() {
+		return nil, nil, diags
+	}
+
+	defer func() {
+		// If we're returning with errors, and thus not producing a valid
+		// context, we'll want to avoid leaving the remote workspace locked.
+		if diags.HasErrors() {
+			diags = diags.Append(op.StateLocker.Unlock())
+		}
+	}()
+
+	log.Printf("[TRACE] backend/remote: reading remote state for workspace %q", remoteWorkspaceName)
+	if err := stateMgr.RefreshState(); err != nil {
+		diags = diags.Append(fmt.Errorf("error loading state: %w", err))
+		return nil, nil, diags
+	}
+
+	// Initialize our context options
+	var opts terraform.ContextOpts
+	if v := b.ContextOpts; v != nil {
+		opts = *v
+	}
+
+	// Copy set options from the operation
+	opts.UIInput = op.UIIn
+
+	// Load the latest state. If we enter contextFromPlanFile below then the
+	// state snapshot in the plan file must match this, or else it'll return
+	// error diagnostics.
+	log.Printf("[TRACE] backend/remote: retrieving remote state snapshot for workspace %q", remoteWorkspaceName)
+	ret.InputState = stateMgr.State()
+
+	log.Printf("[TRACE] backend/remote: loading configuration for the current working directory")
+	config, configDiags := op.ConfigLoader.LoadConfig(op.ConfigDir)
+	diags = diags.Append(configDiags)
+	if configDiags.HasErrors() {
+		return nil, nil, diags
+	}
+	ret.Config = config
+
+	if op.AllowUnsetVariables {
+		// If we're not going to use the variables in an operation we'll be
+		// more lax about them, stubbing out any unset ones as unknown.
+		// This gives us enough information to produce a consistent context,
+		// but not enough information to run a real operation (plan, apply, etc)
+		ret.PlanOpts.SetVariables = stubAllVariables(op.Variables, config.Module.Variables)
+	} else {
+		// The underlying API expects us to use the opaque workspace id to request
+		// variables, so we'll need to look that up using our organization name
+		// and workspace name.
+		remoteWorkspaceID, err := b.getRemoteWorkspaceID(context.Background(), op.Workspace)
+		if err != nil {
+			diags = diags.Append(fmt.Errorf("error finding remote workspace: %w", err))
+			return nil, nil, diags
+		}
+
+		w, err := b.fetchWorkspace(context.Background(), b.organization, op.Workspace)
+		if err != nil {
+			diags = diags.Append(fmt.Errorf("error loading workspace: %w", err))
+			return nil, nil, diags
+		}
+
+		if isLocalExecutionMode(w.ExecutionMode) {
+			log.Printf("[TRACE] skipping retrieving variables from workspace %s/%s (%s), workspace is in Local Execution mode", remoteWorkspaceName, b.organization, remoteWorkspaceID)
+		} else {
+			log.Printf("[TRACE] backend/remote: retrieving variables from workspace %s/%s (%s)", remoteWorkspaceName, b.organization, remoteWorkspaceID)
+			tfeVariables, err := b.client.Variables.List(context.Background(), remoteWorkspaceID, nil)
+			if err != nil && err != tfe.ErrResourceNotFound {
+				diags = diags.Append(fmt.Errorf("error loading variables: %w", err))
+				return nil, nil, diags
+			}
+			if tfeVariables != nil {
+				if op.Variables == nil {
+					op.Variables = make(map[string]backend.UnparsedVariableValue)
+				}
+				for _, v := range tfeVariables.Items {
+					if v.Category == tfe.CategoryTerraform {
+						if _, ok := op.Variables[v.Key]; !ok {
+							op.Variables[v.Key] = &remoteStoredVariableValue{
+								definition: v,
+							}
+						}
+					}
+				}
+			}
+		}
+
+		if op.Variables != nil {
+			variables, varDiags := backend.ParseVariableValues(op.Variables, config.Module.Variables)
+			diags = diags.Append(varDiags)
+			if diags.HasErrors() {
+				return nil, nil, diags
+			}
+			ret.PlanOpts.SetVariables = variables
+		}
+	}
+
+	tfCtx, ctxDiags := terraform.NewContext(&opts)
+	diags = diags.Append(ctxDiags)
+	ret.Core = tfCtx
+
+	log.Printf("[TRACE] backend/remote: finished building terraform.Context")
+
+	return ret, stateMgr, diags
+}
+
+func (b *Remote) getRemoteWorkspaceName(localWorkspaceName string) string {
+	switch {
+	case localWorkspaceName == backend.DefaultStateName:
+		// The default workspace name is a special case, for when the backend
+		// is configured to with to an exact remote workspace rather than with
+		// a remote workspace _prefix_.
+		return b.workspace
+	case b.prefix != "" && !strings.HasPrefix(localWorkspaceName, b.prefix):
+		return b.prefix + localWorkspaceName
+	default:
+		return localWorkspaceName
+	}
+}
+
+func (b *Remote) getRemoteWorkspace(ctx context.Context, localWorkspaceName string) (*tfe.Workspace, error) {
+	remoteWorkspaceName := b.getRemoteWorkspaceName(localWorkspaceName)
+
+	log.Printf("[TRACE] backend/remote: looking up workspace for %s/%s", b.organization, remoteWorkspaceName)
+	remoteWorkspace, err := b.client.Workspaces.Read(ctx, b.organization, remoteWorkspaceName)
+	if err != nil {
+		return nil, err
+	}
+
+	return remoteWorkspace, nil
+}
+
+func (b *Remote) getRemoteWorkspaceID(ctx context.Context, localWorkspaceName string) (string, error) {
+	remoteWorkspace, err := b.getRemoteWorkspace(ctx, localWorkspaceName)
+	if err != nil {
+		return "", err
+	}
+
+	return remoteWorkspace.ID, nil
+}
+
+func stubAllVariables(vv map[string]backend.UnparsedVariableValue, decls map[string]*configs.Variable) terraform.InputValues {
+	ret := make(terraform.InputValues, len(decls))
+
+	for name, cfg := range decls {
+		raw, exists := vv[name]
+		if !exists {
+			ret[name] = &terraform.InputValue{
+				Value:      cty.UnknownVal(cfg.Type),
+				SourceType: terraform.ValueFromConfig,
+			}
+			continue
+		}
+
+		val, diags := raw.ParseVariableValue(cfg.ParsingMode)
+		if diags.HasErrors() {
+			ret[name] = &terraform.InputValue{
+				Value:      cty.UnknownVal(cfg.Type),
+				SourceType: terraform.ValueFromConfig,
+			}
+			continue
+		}
+		ret[name] = val
+	}
+
+	return ret
+}
+
+// remoteStoredVariableValue is a backend.UnparsedVariableValue implementation
+// that translates from the go-tfe representation of stored variables into
+// the Terraform Core backend representation of variables.
+type remoteStoredVariableValue struct {
+	definition *tfe.Variable
+}
+
+var _ backend.UnparsedVariableValue = (*remoteStoredVariableValue)(nil)
+
+func (v *remoteStoredVariableValue) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	var val cty.Value
+
+	switch {
+	case v.definition.Sensitive:
+		// If it's marked as sensitive then it's not available for use in
+		// local operations. We'll use an unknown value as a placeholder for
+		// it so that operations that don't need it might still work, but
+		// we'll also produce a warning about it to add context for any
+		// errors that might result here.
+		val = cty.DynamicVal
+		if !v.definition.HCL {
+			// If it's not marked as HCL then we at least know that the
+			// value must be a string, so we'll set that in case it allows
+			// us to do some more precise type checking.
+			val = cty.UnknownVal(cty.String)
+		}
+
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Warning,
+			fmt.Sprintf("Value for var.%s unavailable", v.definition.Key),
+			fmt.Sprintf("The value of variable %q is marked as sensitive in the remote workspace. This operation always runs locally, so the value for that variable is not available.", v.definition.Key),
+		))
+
+	case v.definition.HCL:
+		// If the variable value is marked as being in HCL syntax, we need to
+		// parse it the same way as it would be interpreted in a .tfvars
+		// file because that is how it would get passed to Terraform CLI for
+		// a remote operation and we want to mimic that result as closely as
+		// possible.
+		var exprDiags hcl.Diagnostics
+		expr, exprDiags := hclsyntax.ParseExpression([]byte(v.definition.Value), "<remote workspace>", hcl.Pos{Line: 1, Column: 1})
+		if expr != nil {
+			var moreDiags hcl.Diagnostics
+			val, moreDiags = expr.Value(nil)
+			exprDiags = append(exprDiags, moreDiags...)
+		} else {
+			// We'll have already put some errors in exprDiags above, so we'll
+			// just stub out the value here.
+			val = cty.DynamicVal
+		}
+
+		// We don't have sufficient context to return decent error messages
+		// for syntax errors in the remote values, so we'll just return a
+		// generic message instead for now.
+		// (More complete error messages will still result from true remote
+		// operations, because they'll run on the remote system where we've
+		// materialized the values into a tfvars file we can report from.)
+		if exprDiags.HasErrors() {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				fmt.Sprintf("Invalid expression for var.%s", v.definition.Key),
+				fmt.Sprintf("The value of variable %q is marked in the remote workspace as being specified in HCL syntax, but the given value is not valid HCL. Stored variable values must be valid literal expressions and may not contain references to other variables or calls to functions.", v.definition.Key),
+			))
+		}
+
+	default:
+		// A variable value _not_ marked as HCL is always be a string, given
+		// literally.
+		val = cty.StringVal(v.definition.Value)
+	}
+
+	return &terraform.InputValue{
+		Value: val,
+
+		// We mark these as "from input" with the rationale that entering
+		// variable values into the Terraform Cloud or Enterprise UI is,
+		// roughly speaking, a similar idea to entering variable values at
+		// the interactive CLI prompts. It's not a perfect correspondance,
+		// but it's closer than the other options.
+		SourceType: terraform.ValueFromInput,
+	}, diags
+}
diff --git a/v1.5.7/internal/backend/remote/backend_context_test.go b/v1.5.7/internal/backend/remote/backend_context_test.go
new file mode 100644
index 0000000..8b875f7
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/backend_context_test.go
@@ -0,0 +1,473 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"context"
+	"reflect"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+
+	tfe "github.com/hashicorp/go-tfe"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestRemoteStoredVariableValue(t *testing.T) {
+	tests := map[string]struct {
+		Def       *tfe.Variable
+		Want      cty.Value
+		WantError string
+	}{
+		"string literal": {
+			&tfe.Variable{
+				Key:       "test",
+				Value:     "foo",
+				HCL:       false,
+				Sensitive: false,
+			},
+			cty.StringVal("foo"),
+			``,
+		},
+		"string HCL": {
+			&tfe.Variable{
+				Key:       "test",
+				Value:     `"foo"`,
+				HCL:       true,
+				Sensitive: false,
+			},
+			cty.StringVal("foo"),
+			``,
+		},
+		"list HCL": {
+			&tfe.Variable{
+				Key:       "test",
+				Value:     `[]`,
+				HCL:       true,
+				Sensitive: false,
+			},
+			cty.EmptyTupleVal,
+			``,
+		},
+		"null HCL": {
+			&tfe.Variable{
+				Key:       "test",
+				Value:     `null`,
+				HCL:       true,
+				Sensitive: false,
+			},
+			cty.NullVal(cty.DynamicPseudoType),
+			``,
+		},
+		"literal sensitive": {
+			&tfe.Variable{
+				Key:       "test",
+				HCL:       false,
+				Sensitive: true,
+			},
+			cty.UnknownVal(cty.String),
+			``,
+		},
+		"HCL sensitive": {
+			&tfe.Variable{
+				Key:       "test",
+				HCL:       true,
+				Sensitive: true,
+			},
+			cty.DynamicVal,
+			``,
+		},
+		"HCL computation": {
+			// This (stored expressions containing computation) is not a case
+			// we intentionally supported, but it became possible for remote
+			// operations in Terraform 0.12 (due to Terraform Cloud/Enterprise
+			// just writing the HCL verbatim into generated `.tfvars` files).
+			// We support it here for consistency, and we continue to support
+			// it in both places for backward-compatibility. In practice,
+			// there's little reason to do computation in a stored variable
+			// value because references are not supported.
+			&tfe.Variable{
+				Key:       "test",
+				Value:     `[for v in ["a"] : v]`,
+				HCL:       true,
+				Sensitive: false,
+			},
+			cty.TupleVal([]cty.Value{cty.StringVal("a")}),
+			``,
+		},
+		"HCL syntax error": {
+			&tfe.Variable{
+				Key:       "test",
+				Value:     `[`,
+				HCL:       true,
+				Sensitive: false,
+			},
+			cty.DynamicVal,
+			`Invalid expression for var.test: The value of variable "test" is marked in the remote workspace as being specified in HCL syntax, but the given value is not valid HCL. Stored variable values must be valid literal expressions and may not contain references to other variables or calls to functions.`,
+		},
+		"HCL with references": {
+			&tfe.Variable{
+				Key:       "test",
+				Value:     `foo.bar`,
+				HCL:       true,
+				Sensitive: false,
+			},
+			cty.DynamicVal,
+			`Invalid expression for var.test: The value of variable "test" is marked in the remote workspace as being specified in HCL syntax, but the given value is not valid HCL. Stored variable values must be valid literal expressions and may not contain references to other variables or calls to functions.`,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			v := &remoteStoredVariableValue{
+				definition: test.Def,
+			}
+			// This ParseVariableValue implementation ignores the parsing mode,
+			// so we'll just always parse literal here. (The parsing mode is
+			// selected by the remote server, not by our local configuration.)
+			gotIV, diags := v.ParseVariableValue(configs.VariableParseLiteral)
+			if test.WantError != "" {
+				if !diags.HasErrors() {
+					t.Fatalf("missing expected error\ngot:  <no error>\nwant: %s", test.WantError)
+				}
+				errStr := diags.Err().Error()
+				if errStr != test.WantError {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", errStr, test.WantError)
+				}
+			} else {
+				if diags.HasErrors() {
+					t.Fatalf("unexpected error\ngot:  %s\nwant: <no error>", diags.Err().Error())
+				}
+				got := gotIV.Value
+				if !test.Want.RawEquals(got) {
+					t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+				}
+			}
+		})
+	}
+}
+
+func TestRemoteContextWithVars(t *testing.T) {
+	catTerraform := tfe.CategoryTerraform
+	catEnv := tfe.CategoryEnv
+
+	tests := map[string]struct {
+		Opts      *tfe.VariableCreateOptions
+		WantError string
+	}{
+		"Terraform variable": {
+			&tfe.VariableCreateOptions{
+				Category: &catTerraform,
+			},
+			`Value for undeclared variable: A variable named "key" was assigned a value, but the root module does not declare a variable of that name. To use this value, add a "variable" block to the configuration.`,
+		},
+		"environment variable": {
+			&tfe.VariableCreateOptions{
+				Category: &catEnv,
+			},
+			``,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			configDir := "./testdata/empty"
+
+			b, bCleanup := testBackendDefault(t)
+			defer bCleanup()
+
+			_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
+			defer configCleanup()
+
+			workspaceID, err := b.getRemoteWorkspaceID(context.Background(), backend.DefaultStateName)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			streams, _ := terminal.StreamsForTesting(t)
+			view := views.NewStateLocker(arguments.ViewHuman, views.NewView(streams))
+
+			op := &backend.Operation{
+				ConfigDir:    configDir,
+				ConfigLoader: configLoader,
+				StateLocker:  clistate.NewLocker(0, view),
+				Workspace:    backend.DefaultStateName,
+			}
+
+			v := test.Opts
+			if v.Key == nil {
+				key := "key"
+				v.Key = &key
+			}
+			b.client.Variables.Create(context.TODO(), workspaceID, *v)
+
+			_, _, diags := b.LocalRun(op)
+
+			if test.WantError != "" {
+				if !diags.HasErrors() {
+					t.Fatalf("missing expected error\ngot:  <no error>\nwant: %s", test.WantError)
+				}
+				errStr := diags.Err().Error()
+				if errStr != test.WantError {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", errStr, test.WantError)
+				}
+				// When Context() returns an error, it should unlock the state,
+				// so re-locking it is expected to succeed.
+				stateMgr, _ := b.StateMgr(backend.DefaultStateName)
+				if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+					t.Fatalf("unexpected error locking state: %s", err.Error())
+				}
+			} else {
+				if diags.HasErrors() {
+					t.Fatalf("unexpected error\ngot:  %s\nwant: <no error>", diags.Err().Error())
+				}
+				// When Context() succeeds, this should fail w/ "workspace already locked"
+				stateMgr, _ := b.StateMgr(backend.DefaultStateName)
+				if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err == nil {
+					t.Fatal("unexpected success locking state after Context")
+				}
+			}
+		})
+	}
+}
+
+func TestRemoteVariablesDoNotOverride(t *testing.T) {
+	catTerraform := tfe.CategoryTerraform
+
+	varName1 := "key1"
+	varName2 := "key2"
+	varName3 := "key3"
+
+	varValue1 := "value1"
+	varValue2 := "value2"
+	varValue3 := "value3"
+
+	tests := map[string]struct {
+		localVariables    map[string]backend.UnparsedVariableValue
+		remoteVariables   []*tfe.VariableCreateOptions
+		expectedVariables terraform.InputValues
+	}{
+		"no local variables": {
+			map[string]backend.UnparsedVariableValue{},
+			[]*tfe.VariableCreateOptions{
+				{
+					Key:      &varName1,
+					Value:    &varValue1,
+					Category: &catTerraform,
+				},
+				{
+					Key:      &varName2,
+					Value:    &varValue2,
+					Category: &catTerraform,
+				},
+				{
+					Key:      &varName3,
+					Value:    &varValue3,
+					Category: &catTerraform,
+				},
+			},
+			terraform.InputValues{
+				varName1: &terraform.InputValue{
+					Value:      cty.StringVal(varValue1),
+					SourceType: terraform.ValueFromInput,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "",
+						Start:    tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+					},
+				},
+				varName2: &terraform.InputValue{
+					Value:      cty.StringVal(varValue2),
+					SourceType: terraform.ValueFromInput,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "",
+						Start:    tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+					},
+				},
+				varName3: &terraform.InputValue{
+					Value:      cty.StringVal(varValue3),
+					SourceType: terraform.ValueFromInput,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "",
+						Start:    tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+					},
+				},
+			},
+		},
+		"single conflicting local variable": {
+			map[string]backend.UnparsedVariableValue{
+				varName3: testUnparsedVariableValue(varValue3),
+			},
+			[]*tfe.VariableCreateOptions{
+				{
+					Key:      &varName1,
+					Value:    &varValue1,
+					Category: &catTerraform,
+				}, {
+					Key:      &varName2,
+					Value:    &varValue2,
+					Category: &catTerraform,
+				}, {
+					Key:      &varName3,
+					Value:    &varValue3,
+					Category: &catTerraform,
+				},
+			},
+			terraform.InputValues{
+				varName1: &terraform.InputValue{
+					Value:      cty.StringVal(varValue1),
+					SourceType: terraform.ValueFromInput,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "",
+						Start:    tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+					},
+				},
+				varName2: &terraform.InputValue{
+					Value:      cty.StringVal(varValue2),
+					SourceType: terraform.ValueFromInput,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "",
+						Start:    tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+					},
+				},
+				varName3: &terraform.InputValue{
+					Value:      cty.StringVal(varValue3),
+					SourceType: terraform.ValueFromNamedFile,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "fake.tfvars",
+						Start:    tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					},
+				},
+			},
+		},
+		"no conflicting local variable": {
+			map[string]backend.UnparsedVariableValue{
+				varName3: testUnparsedVariableValue(varValue3),
+			},
+			[]*tfe.VariableCreateOptions{
+				{
+					Key:      &varName1,
+					Value:    &varValue1,
+					Category: &catTerraform,
+				}, {
+					Key:      &varName2,
+					Value:    &varValue2,
+					Category: &catTerraform,
+				},
+			},
+			terraform.InputValues{
+				varName1: &terraform.InputValue{
+					Value:      cty.StringVal(varValue1),
+					SourceType: terraform.ValueFromInput,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "",
+						Start:    tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+					},
+				},
+				varName2: &terraform.InputValue{
+					Value:      cty.StringVal(varValue2),
+					SourceType: terraform.ValueFromInput,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "",
+						Start:    tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+					},
+				},
+				varName3: &terraform.InputValue{
+					Value:      cty.StringVal(varValue3),
+					SourceType: terraform.ValueFromNamedFile,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "fake.tfvars",
+						Start:    tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					},
+				},
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			configDir := "./testdata/variables"
+
+			b, bCleanup := testBackendDefault(t)
+			defer bCleanup()
+
+			_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
+			defer configCleanup()
+
+			workspaceID, err := b.getRemoteWorkspaceID(context.Background(), backend.DefaultStateName)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			streams, _ := terminal.StreamsForTesting(t)
+			view := views.NewStateLocker(arguments.ViewHuman, views.NewView(streams))
+
+			op := &backend.Operation{
+				ConfigDir:    configDir,
+				ConfigLoader: configLoader,
+				StateLocker:  clistate.NewLocker(0, view),
+				Workspace:    backend.DefaultStateName,
+				Variables:    test.localVariables,
+			}
+
+			for _, v := range test.remoteVariables {
+				b.client.Variables.Create(context.TODO(), workspaceID, *v)
+			}
+
+			lr, _, diags := b.LocalRun(op)
+
+			if diags.HasErrors() {
+				t.Fatalf("unexpected error\ngot:  %s\nwant: <no error>", diags.Err().Error())
+			}
+			// When Context() succeeds, this should fail w/ "workspace already locked"
+			stateMgr, _ := b.StateMgr(backend.DefaultStateName)
+			if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err == nil {
+				t.Fatal("unexpected success locking state after Context")
+			}
+
+			actual := lr.PlanOpts.SetVariables
+			expected := test.expectedVariables
+
+			for expectedKey := range expected {
+				actualValue := actual[expectedKey]
+				expectedValue := expected[expectedKey]
+
+				if !reflect.DeepEqual(*actualValue, *expectedValue) {
+					t.Fatalf("unexpected variable '%s'\ngot:  %v\nwant: %v", expectedKey, actualValue, expectedValue)
+				}
+			}
+		})
+	}
+}
+
+type testUnparsedVariableValue string
+
+func (v testUnparsedVariableValue) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) {
+	return &terraform.InputValue{
+		Value:      cty.StringVal(string(v)),
+		SourceType: terraform.ValueFromNamedFile,
+		SourceRange: tfdiags.SourceRange{
+			Filename: "fake.tfvars",
+			Start:    tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+			End:      tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+		},
+	}, nil
+}
diff --git a/v1.5.7/internal/backend/remote/backend_plan.go b/v1.5.7/internal/backend/remote/backend_plan.go
new file mode 100644
index 0000000..40c5c08
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/backend_plan.go
@@ -0,0 +1,454 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"bufio"
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+	"syscall"
+	"time"
+
+	tfe "github.com/hashicorp/go-tfe"
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+var planConfigurationVersionsPollInterval = 500 * time.Millisecond
+
+func (b *Remote) opPlan(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
+	log.Printf("[INFO] backend/remote: starting Plan operation")
+
+	var diags tfdiags.Diagnostics
+
+	if !w.Permissions.CanQueueRun {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Insufficient rights to generate a plan",
+			"The provided credentials have insufficient rights to generate a plan. In order "+
+				"to generate plans, at least plan permissions on the workspace are required.",
+		))
+		return nil, diags.Err()
+	}
+
+	if b.ContextOpts != nil && b.ContextOpts.Parallelism != defaultParallelism {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Custom parallelism values are currently not supported",
+			`The "remote" backend does not support setting a custom parallelism `+
+				`value at this time.`,
+		))
+	}
+
+	if op.PlanFile != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Displaying a saved plan is currently not supported",
+			`The "remote" backend currently requires configuration to be present and `+
+				`does not accept an existing saved plan as an argument at this time.`,
+		))
+	}
+
+	if op.PlanOutPath != "" {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Saving a generated plan is currently not supported",
+			`The "remote" backend does not support saving the generated execution `+
+				`plan locally at this time.`,
+		))
+	}
+
+	if op.GenerateConfigOut != "" {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Generating configuration is not currently supported",
+			`The "remote" backend does not currently support generating resource configuration `+
+				`as part of a plan.`,
+		))
+	}
+
+	if b.hasExplicitVariableValues(op) {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Run variables are currently not supported",
+			fmt.Sprintf(
+				"The \"remote\" backend does not support setting run variables at this time. "+
+					"Currently the only to way to pass variables to the remote backend is by "+
+					"creating a '*.auto.tfvars' variables file. This file will automatically "+
+					"be loaded by the \"remote\" backend when the workspace is configured to use "+
+					"Terraform v0.10.0 or later.\n\nAdditionally you can also set variables on "+
+					"the workspace in the web UI:\nhttps://%s/app/%s/%s/variables",
+				b.hostname, b.organization, op.Workspace,
+			),
+		))
+	}
+
+	if !op.HasConfig() && op.PlanMode != plans.DestroyMode {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"No configuration files found",
+			`Plan requires configuration to be present. Planning without a configuration `+
+				`would mark everything for destruction, which is normally not what is desired. `+
+				`If you would like to destroy everything, please run plan with the "-destroy" `+
+				`flag or create a single empty configuration file. Otherwise, please create `+
+				`a Terraform configuration file in the path being executed and try again.`,
+		))
+	}
+
+	// For API versions prior to 2.3, RemoteAPIVersion will return an empty string,
+	// so if there's an error when parsing the RemoteAPIVersion, it's handled as
+	// equivalent to an API version < 2.3.
+	currentAPIVersion, parseErr := version.NewVersion(b.client.RemoteAPIVersion())
+
+	if len(op.Targets) != 0 {
+		desiredAPIVersion, _ := version.NewVersion("2.3")
+
+		if parseErr != nil || currentAPIVersion.LessThan(desiredAPIVersion) {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Resource targeting is not supported",
+				fmt.Sprintf(
+					`The host %s does not support the -target option for `+
+						`remote plans.`,
+					b.hostname,
+				),
+			))
+		}
+	}
+
+	if !op.PlanRefresh {
+		desiredAPIVersion, _ := version.NewVersion("2.4")
+
+		if parseErr != nil || currentAPIVersion.LessThan(desiredAPIVersion) {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Planning without refresh is not supported",
+				fmt.Sprintf(
+					`The host %s does not support the -refresh=false option for `+
+						`remote plans.`,
+					b.hostname,
+				),
+			))
+		}
+	}
+
+	if len(op.ForceReplace) != 0 {
+		desiredAPIVersion, _ := version.NewVersion("2.4")
+
+		if parseErr != nil || currentAPIVersion.LessThan(desiredAPIVersion) {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Planning resource replacements is not supported",
+				fmt.Sprintf(
+					`The host %s does not support the -replace option for `+
+						`remote plans.`,
+					b.hostname,
+				),
+			))
+		}
+	}
+
+	if op.PlanMode == plans.RefreshOnlyMode {
+		desiredAPIVersion, _ := version.NewVersion("2.4")
+
+		if parseErr != nil || currentAPIVersion.LessThan(desiredAPIVersion) {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Refresh-only mode is not supported",
+				fmt.Sprintf(
+					`The host %s does not support -refresh-only mode for `+
+						`remote plans.`,
+					b.hostname,
+				),
+			))
+		}
+	}
+
+	// Return if there are any errors.
+	if diags.HasErrors() {
+		return nil, diags.Err()
+	}
+
+	return b.plan(stopCtx, cancelCtx, op, w)
+}
+
+func (b *Remote) plan(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
+	if b.CLI != nil {
+		header := planDefaultHeader
+		if op.Type == backend.OperationTypeApply {
+			header = applyDefaultHeader
+		}
+		b.CLI.Output(b.Colorize().Color(strings.TrimSpace(header) + "\n"))
+	}
+
+	configOptions := tfe.ConfigurationVersionCreateOptions{
+		AutoQueueRuns: tfe.Bool(false),
+		Speculative:   tfe.Bool(op.Type == backend.OperationTypePlan),
+	}
+
+	cv, err := b.client.ConfigurationVersions.Create(stopCtx, w.ID, configOptions)
+	if err != nil {
+		return nil, generalError("Failed to create configuration version", err)
+	}
+
+	var configDir string
+	if op.ConfigDir != "" {
+		// De-normalize the configuration directory path.
+		configDir, err = filepath.Abs(op.ConfigDir)
+		if err != nil {
+			return nil, generalError(
+				"Failed to get absolute path of the configuration directory: %v", err)
+		}
+
+		// Make sure to take the working directory into account by removing
+		// the working directory from the current path. This will result in
+		// a path that points to the expected root of the workspace.
+		configDir = filepath.Clean(strings.TrimSuffix(
+			filepath.Clean(configDir),
+			filepath.Clean(w.WorkingDirectory),
+		))
+
+		// If the workspace has a subdirectory as its working directory then
+		// our configDir will be some parent directory of the current working
+		// directory. Users are likely to find that surprising, so we'll
+		// produce an explicit message about it to be transparent about what
+		// we are doing and why.
+		if w.WorkingDirectory != "" && filepath.Base(configDir) != w.WorkingDirectory {
+			if b.CLI != nil {
+				b.CLI.Output(fmt.Sprintf(strings.TrimSpace(`
+The remote workspace is configured to work with configuration at
+%s relative to the target repository.
+
+Terraform will upload the contents of the following directory,
+excluding files or directories as defined by a .terraformignore file
+at %s/.terraformignore (if it is present),
+in order to capture the filesystem context the remote workspace expects:
+    %s
+`), w.WorkingDirectory, configDir, configDir) + "\n")
+			}
+		}
+
+	} else {
+		// We did a check earlier to make sure we either have a config dir,
+		// or the plan is run with -destroy. So this else clause will only
+		// be executed when we are destroying and doesn't need the config.
+		configDir, err = ioutil.TempDir("", "tf")
+		if err != nil {
+			return nil, generalError("Failed to create temporary directory", err)
+		}
+		defer os.RemoveAll(configDir)
+
+		// Make sure the configured working directory exists.
+		err = os.MkdirAll(filepath.Join(configDir, w.WorkingDirectory), 0700)
+		if err != nil {
+			return nil, generalError(
+				"Failed to create temporary working directory", err)
+		}
+	}
+
+	err = b.client.ConfigurationVersions.Upload(stopCtx, cv.UploadURL, configDir)
+	if err != nil {
+		return nil, generalError("Failed to upload configuration files", err)
+	}
+
+	uploaded := false
+	for i := 0; i < 60 && !uploaded; i++ {
+		select {
+		case <-stopCtx.Done():
+			return nil, context.Canceled
+		case <-cancelCtx.Done():
+			return nil, context.Canceled
+		case <-time.After(planConfigurationVersionsPollInterval):
+			cv, err = b.client.ConfigurationVersions.Read(stopCtx, cv.ID)
+			if err != nil {
+				return nil, generalError("Failed to retrieve configuration version", err)
+			}
+
+			if cv.Status == tfe.ConfigurationUploaded {
+				uploaded = true
+			}
+		}
+	}
+
+	if !uploaded {
+		return nil, generalError(
+			"Failed to upload configuration files", errors.New("operation timed out"))
+	}
+
+	runOptions := tfe.RunCreateOptions{
+		ConfigurationVersion: cv,
+		Refresh:              tfe.Bool(op.PlanRefresh),
+		Workspace:            w,
+	}
+
+	switch op.PlanMode {
+	case plans.NormalMode:
+		// okay, but we don't need to do anything special for this
+	case plans.RefreshOnlyMode:
+		runOptions.RefreshOnly = tfe.Bool(true)
+	case plans.DestroyMode:
+		runOptions.IsDestroy = tfe.Bool(true)
+	default:
+		// Shouldn't get here because we should update this for each new
+		// plan mode we add, mapping it to the corresponding RunCreateOptions
+		// field.
+		return nil, generalError(
+			"Invalid plan mode",
+			fmt.Errorf("remote backend doesn't support %s", op.PlanMode),
+		)
+	}
+
+	if len(op.Targets) != 0 {
+		runOptions.TargetAddrs = make([]string, 0, len(op.Targets))
+		for _, addr := range op.Targets {
+			runOptions.TargetAddrs = append(runOptions.TargetAddrs, addr.String())
+		}
+	}
+
+	if len(op.ForceReplace) != 0 {
+		runOptions.ReplaceAddrs = make([]string, 0, len(op.ForceReplace))
+		for _, addr := range op.ForceReplace {
+			runOptions.ReplaceAddrs = append(runOptions.ReplaceAddrs, addr.String())
+		}
+	}
+
+	r, err := b.client.Runs.Create(stopCtx, runOptions)
+	if err != nil {
+		return r, generalError("Failed to create run", err)
+	}
+
+	// When the lock timeout is set, if the run is still pending and
+	// cancellable after that period, we attempt to cancel it.
+	if lockTimeout := op.StateLocker.Timeout(); lockTimeout > 0 {
+		go func() {
+			defer logging.PanicHandler()
+
+			select {
+			case <-stopCtx.Done():
+				return
+			case <-cancelCtx.Done():
+				return
+			case <-time.After(lockTimeout):
+				// Retrieve the run to get its current status.
+				r, err := b.client.Runs.Read(cancelCtx, r.ID)
+				if err != nil {
+					log.Printf("[ERROR] error reading run: %v", err)
+					return
+				}
+
+				if r.Status == tfe.RunPending && r.Actions.IsCancelable {
+					if b.CLI != nil {
+						b.CLI.Output(b.Colorize().Color(strings.TrimSpace(lockTimeoutErr)))
+					}
+
+					// We abuse the auto aprove flag to indicate that we do not
+					// want to ask if the remote operation should be canceled.
+					op.AutoApprove = true
+
+					p, err := os.FindProcess(os.Getpid())
+					if err != nil {
+						log.Printf("[ERROR] error searching process ID: %v", err)
+						return
+					}
+					p.Signal(syscall.SIGINT)
+				}
+			}
+		}()
+	}
+
+	if b.CLI != nil {
+		b.CLI.Output(b.Colorize().Color(strings.TrimSpace(fmt.Sprintf(
+			runHeader, b.hostname, b.organization, op.Workspace, r.ID)) + "\n"))
+	}
+
+	r, err = b.waitForRun(stopCtx, cancelCtx, op, "plan", r, w)
+	if err != nil {
+		return r, err
+	}
+
+	logs, err := b.client.Plans.Logs(stopCtx, r.Plan.ID)
+	if err != nil {
+		return r, generalError("Failed to retrieve logs", err)
+	}
+	reader := bufio.NewReaderSize(logs, 64*1024)
+
+	if b.CLI != nil {
+		for next := true; next; {
+			var l, line []byte
+
+			for isPrefix := true; isPrefix; {
+				l, isPrefix, err = reader.ReadLine()
+				if err != nil {
+					if err != io.EOF {
+						return r, generalError("Failed to read logs", err)
+					}
+					next = false
+				}
+				line = append(line, l...)
+			}
+
+			if next || len(line) > 0 {
+				b.CLI.Output(b.Colorize().Color(string(line)))
+			}
+		}
+	}
+
+	// Retrieve the run to get its current status.
+	r, err = b.client.Runs.Read(stopCtx, r.ID)
+	if err != nil {
+		return r, generalError("Failed to retrieve run", err)
+	}
+
+	// If the run is canceled or errored, we still continue to the
+	// cost-estimation and policy check phases to ensure we render any
+	// results available. In the case of a hard-failed policy check, the
+	// status of the run will be "errored", but there is still policy
+	// information which should be shown.
+
+	// Show any cost estimation output.
+	if r.CostEstimate != nil {
+		err = b.costEstimate(stopCtx, cancelCtx, op, r)
+		if err != nil {
+			return r, err
+		}
+	}
+
+	// Check any configured sentinel policies.
+	if len(r.PolicyChecks) > 0 {
+		err = b.checkPolicy(stopCtx, cancelCtx, op, r)
+		if err != nil {
+			return r, err
+		}
+	}
+
+	return r, nil
+}
+
+const planDefaultHeader = `
+[reset][yellow]Running plan in the remote backend. Output will stream here. Pressing Ctrl-C
+will stop streaming the logs, but will not stop the plan running remotely.[reset]
+
+Preparing the remote plan...
+`
+
+const runHeader = `
+[reset][yellow]To view this run in a browser, visit:
+https://%s/app/%s/%s/runs/%s[reset]
+`
+
+// The newline in this error is to make it look good in the CLI!
+const lockTimeoutErr = `
+[reset][red]Lock timeout exceeded, sending interrupt to cancel the remote operation.
+[reset]
+`
diff --git a/v1.5.7/internal/backend/remote/backend_plan_test.go b/v1.5.7/internal/backend/remote/backend_plan_test.go
new file mode 100644
index 0000000..9068492
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/backend_plan_test.go
@@ -0,0 +1,1280 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"context"
+	"os"
+	"os/signal"
+	"strings"
+	"syscall"
+	"testing"
+	"time"
+
+	"github.com/google/go-cmp/cmp"
+	tfe "github.com/hashicorp/go-tfe"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/cloud"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/mitchellh/cli"
+)
+
+func testOperationPlan(t *testing.T, configDir string) (*backend.Operation, func(), func(*testing.T) *terminal.TestOutput) {
+	t.Helper()
+
+	return testOperationPlanWithTimeout(t, configDir, 0)
+}
+
+func testOperationPlanWithTimeout(t *testing.T, configDir string, timeout time.Duration) (*backend.Operation, func(), func(*testing.T) *terminal.TestOutput) {
+	t.Helper()
+
+	_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewView(streams)
+	stateLockerView := views.NewStateLocker(arguments.ViewHuman, view)
+	operationView := views.NewOperation(arguments.ViewHuman, false, view)
+
+	// Many of our tests use an overridden "null" provider that's just in-memory
+	// inside the test process, not a separate plugin on disk.
+	depLocks := depsfile.NewLocks()
+	depLocks.SetProviderOverridden(addrs.MustParseProviderSourceString("registry.terraform.io/hashicorp/null"))
+
+	return &backend.Operation{
+		ConfigDir:       configDir,
+		ConfigLoader:    configLoader,
+		PlanRefresh:     true,
+		StateLocker:     clistate.NewLocker(timeout, stateLockerView),
+		Type:            backend.OperationTypePlan,
+		View:            operationView,
+		DependencyLocks: depLocks,
+	}, configCleanup, done
+}
+
+func TestRemote_planBasic(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatal("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+
+	stateMgr, _ := b.StateMgr(backend.DefaultStateName)
+	// An error suggests that the state was not unlocked after the operation finished
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after successful plan: %s", err.Error())
+	}
+}
+
+func TestRemote_planCanceled(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	// Stop the run to simulate a Ctrl-C.
+	run.Stop()
+
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+
+	stateMgr, _ := b.StateMgr(backend.DefaultStateName)
+	// An error suggests that the state was not unlocked after the operation finished
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after cancelled plan: %s", err.Error())
+	}
+}
+
+func TestRemote_planLongLine(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-long-line")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatal("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestRemote_planWithoutPermissions(t *testing.T) {
+	b, bCleanup := testBackendNoDefault(t)
+	defer bCleanup()
+
+	// Create a named workspace without permissions.
+	w, err := b.client.Workspaces.Create(
+		context.Background(),
+		b.organization,
+		tfe.WorkspaceCreateOptions{
+			Name: tfe.String(b.prefix + "prod"),
+		},
+	)
+	if err != nil {
+		t.Fatalf("error creating named workspace: %v", err)
+	}
+	w.Permissions.CanQueueRun = false
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+
+	op.Workspace = "prod"
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "Insufficient rights to generate a plan") {
+		t.Fatalf("expected a permissions error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_planWithParallelism(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+
+	if b.ContextOpts == nil {
+		b.ContextOpts = &terraform.ContextOpts{}
+	}
+	b.ContextOpts.Parallelism = 3
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "parallelism values are currently not supported") {
+		t.Fatalf("expected a parallelism error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_planWithPlan(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+
+	op.PlanFile = &planfile.Reader{}
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "saved plan is currently not supported") {
+		t.Fatalf("expected a saved plan error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_planWithPath(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+
+	op.PlanOutPath = "./testdata/plan"
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "generated plan is currently not supported") {
+		t.Fatalf("expected a generated plan error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_planWithoutRefresh(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.PlanRefresh = false
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatal("expected a non-empty plan")
+	}
+
+	// We should find a run inside the mock client that has refresh set
+	// to false.
+	runsAPI := b.client.Runs.(*cloud.MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff(false, run.Refresh); diff != "" {
+			t.Errorf("wrong Refresh setting in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestRemote_planWithoutRefreshIncompatibleAPIVersion(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+
+	b.client.SetFakeRemoteAPIVersion("2.3")
+
+	op.PlanRefresh = false
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "Planning without refresh is not supported") {
+		t.Fatalf("expected not supported error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_planWithRefreshOnly(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.PlanMode = plans.RefreshOnlyMode
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatal("expected a non-empty plan")
+	}
+
+	// We should find a run inside the mock client that has refresh-only set
+	// to true.
+	runsAPI := b.client.Runs.(*cloud.MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff(true, run.RefreshOnly); diff != "" {
+			t.Errorf("wrong RefreshOnly setting in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestRemote_planWithRefreshOnlyIncompatibleAPIVersion(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+
+	b.client.SetFakeRemoteAPIVersion("2.3")
+
+	op.PlanMode = plans.RefreshOnlyMode
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "Refresh-only mode is not supported") {
+		t.Fatalf("expected not supported error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_planWithTarget(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	// When the backend code creates a new run, we'll tweak it so that it
+	// has a cost estimation object with the "skipped_due_to_targeting" status,
+	// emulating how a real server is expected to behave in that case.
+	b.client.Runs.(*cloud.MockRuns).ModifyNewRun = func(client *cloud.MockClient, options tfe.RunCreateOptions, run *tfe.Run) {
+		const fakeID = "fake"
+		// This is the cost estimate object embedded in the run itself which
+		// the backend will use to learn the ID to request from the cost
+		// estimates endpoint. It's pending to simulate what a freshly-created
+		// run is likely to look like.
+		run.CostEstimate = &tfe.CostEstimate{
+			ID:     fakeID,
+			Status: "pending",
+		}
+		// The backend will then use the main cost estimation API to retrieve
+		// the same ID indicated in the object above, where we'll then return
+		// the status "skipped_due_to_targeting" to trigger the special skip
+		// message in the backend output.
+		client.CostEstimates.Estimations[fakeID] = &tfe.CostEstimate{
+			ID:     fakeID,
+			Status: "skipped_due_to_targeting",
+		}
+	}
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	addr, _ := addrs.ParseAbsResourceStr("null_resource.foo")
+
+	op.Targets = []addrs.Targetable{addr}
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatal("expected plan operation to succeed")
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected plan to be non-empty")
+	}
+
+	// testBackendDefault above attached a "mock UI" to our backend, so we
+	// can retrieve its non-error output via the OutputWriter in-memory buffer.
+	gotOutput := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if wantOutput := "Not available for this plan, because it was created with the -target option."; !strings.Contains(gotOutput, wantOutput) {
+		t.Errorf("missing message about skipped cost estimation\ngot:\n%s\nwant substring: %s", gotOutput, wantOutput)
+	}
+
+	// We should find a run inside the mock client that has the same
+	// target address we requested above.
+	runsAPI := b.client.Runs.(*cloud.MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff([]string{"null_resource.foo"}, run.TargetAddrs); diff != "" {
+			t.Errorf("wrong TargetAddrs in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestRemote_planWithTargetIncompatibleAPIVersion(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+
+	// Set the tfe client's RemoteAPIVersion to an empty string, to mimic
+	// API versions prior to 2.3.
+	b.client.SetFakeRemoteAPIVersion("")
+
+	addr, _ := addrs.ParseAbsResourceStr("null_resource.foo")
+
+	op.Targets = []addrs.Targetable{addr}
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "Resource targeting is not supported") {
+		t.Fatalf("expected a targeting error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_planWithReplace(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	addr, _ := addrs.ParseAbsResourceInstanceStr("null_resource.foo")
+
+	op.ForceReplace = []addrs.AbsResourceInstance{addr}
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatal("expected plan operation to succeed")
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected plan to be non-empty")
+	}
+
+	// We should find a run inside the mock client that has the same
+	// refresh address we requested above.
+	runsAPI := b.client.Runs.(*cloud.MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff([]string{"null_resource.foo"}, run.ReplaceAddrs); diff != "" {
+			t.Errorf("wrong ReplaceAddrs in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestRemote_planWithReplaceIncompatibleAPIVersion(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+
+	b.client.SetFakeRemoteAPIVersion("2.3")
+
+	addr, _ := addrs.ParseAbsResourceInstanceStr("null_resource.foo")
+
+	op.ForceReplace = []addrs.AbsResourceInstance{addr}
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "Planning resource replacements is not supported") {
+		t.Fatalf("expected not supported error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_planWithVariables(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-variables")
+	defer configCleanup()
+
+	op.Variables = testVariables(terraform.ValueFromCLIArg, "foo", "bar")
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "variables are currently not supported") {
+		t.Fatalf("expected a variables error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_planNoConfig(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/empty")
+	defer configCleanup()
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "configuration files found") {
+		t.Fatalf("expected configuration files error, got: %v", errOutput)
+	}
+}
+
+func TestRemote_planNoChanges(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-no-changes")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "No changes. Infrastructure is up-to-date.") {
+		t.Fatalf("expected no changes in plan summary: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: true") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+}
+
+func TestRemote_planForceLocal(t *testing.T) {
+	// Set TF_FORCE_LOCAL_BACKEND so the remote backend will use
+	// the local backend with itself as embedded backend.
+	if err := os.Setenv("TF_FORCE_LOCAL_BACKEND", "1"); err != nil {
+		t.Fatalf("error setting environment variable TF_FORCE_LOCAL_BACKEND: %v", err)
+	}
+	defer os.Unsetenv("TF_FORCE_LOCAL_BACKEND")
+
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = backend.DefaultStateName
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams))
+	op.View = view
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if strings.Contains(output, "Running plan in the remote backend") {
+		t.Fatalf("unexpected remote backend header in output: %s", output)
+	}
+	if output := done(t).Stdout(); !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestRemote_planWithoutOperationsEntitlement(t *testing.T) {
+	b, bCleanup := testBackendNoOperations(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = backend.DefaultStateName
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams))
+	op.View = view
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if strings.Contains(output, "Running plan in the remote backend") {
+		t.Fatalf("unexpected remote backend header in output: %s", output)
+	}
+	if output := done(t).Stdout(); !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestRemote_planWorkspaceWithoutOperations(t *testing.T) {
+	b, bCleanup := testBackendNoDefault(t)
+	defer bCleanup()
+
+	ctx := context.Background()
+
+	// Create a named workspace that doesn't allow operations.
+	_, err := b.client.Workspaces.Create(
+		ctx,
+		b.organization,
+		tfe.WorkspaceCreateOptions{
+			Name: tfe.String(b.prefix + "no-operations"),
+		},
+	)
+	if err != nil {
+		t.Fatalf("error creating named workspace: %v", err)
+	}
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = "no-operations"
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams))
+	op.View = view
+
+	run, err := b.Operation(ctx, op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if strings.Contains(output, "Running plan in the remote backend") {
+		t.Fatalf("unexpected remote backend header in output: %s", output)
+	}
+	if output := done(t).Stdout(); !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestRemote_planLockTimeout(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	ctx := context.Background()
+
+	// Retrieve the workspace used to run this operation in.
+	w, err := b.client.Workspaces.Read(ctx, b.organization, b.workspace)
+	if err != nil {
+		t.Fatalf("error retrieving workspace: %v", err)
+	}
+
+	// Create a new configuration version.
+	c, err := b.client.ConfigurationVersions.Create(ctx, w.ID, tfe.ConfigurationVersionCreateOptions{})
+	if err != nil {
+		t.Fatalf("error creating configuration version: %v", err)
+	}
+
+	// Create a pending run to block this run.
+	_, err = b.client.Runs.Create(ctx, tfe.RunCreateOptions{
+		ConfigurationVersion: c,
+		Workspace:            w,
+	})
+	if err != nil {
+		t.Fatalf("error creating pending run: %v", err)
+	}
+
+	op, configCleanup, done := testOperationPlanWithTimeout(t, "./testdata/plan", 50)
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"cancel":  "yes",
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = backend.DefaultStateName
+
+	_, err = b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	sigint := make(chan os.Signal, 1)
+	signal.Notify(sigint, syscall.SIGINT)
+	select {
+	case <-sigint:
+		// Stop redirecting SIGINT signals.
+		signal.Stop(sigint)
+	case <-time.After(200 * time.Millisecond):
+		t.Fatalf("expected lock timeout after 50 milliseconds, waited 200 milliseconds")
+	}
+
+	if len(input.answers) != 2 {
+		t.Fatalf("expected unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "Lock timeout exceeded") {
+		t.Fatalf("expected lock timout error in output: %s", output)
+	}
+	if strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("unexpected plan summary in output: %s", output)
+	}
+}
+
+func TestRemote_planDestroy(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.PlanMode = plans.DestroyMode
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+}
+
+func TestRemote_planDestroyNoConfig(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/empty")
+	defer configCleanup()
+	defer done(t)
+
+	op.PlanMode = plans.DestroyMode
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+}
+
+func TestRemote_planWithWorkingDirectory(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	options := tfe.WorkspaceUpdateOptions{
+		WorkingDirectory: tfe.String("terraform"),
+	}
+
+	// Configure the workspace to use a custom working directory.
+	_, err := b.client.Workspaces.Update(context.Background(), b.organization, b.workspace, options)
+	if err != nil {
+		t.Fatalf("error configuring working directory: %v", err)
+	}
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-with-working-directory/terraform")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "The remote workspace is configured to work with configuration") {
+		t.Fatalf("expected working directory warning: %s", output)
+	}
+	if !strings.Contains(output, "Running plan in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestRemote_planWithWorkingDirectoryFromCurrentPath(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	options := tfe.WorkspaceUpdateOptions{
+		WorkingDirectory: tfe.String("terraform"),
+	}
+
+	// Configure the workspace to use a custom working directory.
+	_, err := b.client.Workspaces.Update(context.Background(), b.organization, b.workspace, options)
+	if err != nil {
+		t.Fatalf("error configuring working directory: %v", err)
+	}
+
+	wd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("error getting current working directory: %v", err)
+	}
+
+	// We need to change into the configuration directory to make sure
+	// the logic to upload the correct slug is working as expected.
+	if err := os.Chdir("./testdata/plan-with-working-directory/terraform"); err != nil {
+		t.Fatalf("error changing directory: %v", err)
+	}
+	defer os.Chdir(wd) // Make sure we change back again when were done.
+
+	// For this test we need to give our current directory instead of the
+	// full path to the configuration as we already changed directories.
+	op, configCleanup, done := testOperationPlan(t, ".")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestRemote_planCostEstimation(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-cost-estimation")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "Resources: 1 of 1 estimated") {
+		t.Fatalf("expected cost estimate result in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestRemote_planPolicyPass(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-policy-passed")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: true") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestRemote_planPolicyHardFail(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-policy-hard-failed")
+	defer configCleanup()
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	viewOutput := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := viewOutput.Stderr()
+	if !strings.Contains(errOutput, "hard failed") {
+		t.Fatalf("expected a policy check error, got: %v", errOutput)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: false") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestRemote_planPolicySoftFail(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-policy-soft-failed")
+	defer configCleanup()
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	viewOutput := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := viewOutput.Stderr()
+	if !strings.Contains(errOutput, "soft failed") {
+		t.Fatalf("expected a policy check error, got: %v", errOutput)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: false") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestRemote_planWithRemoteError(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-with-error")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if run.Result.ExitStatus() != 1 {
+		t.Fatalf("expected exit code 1, got %d", run.Result.ExitStatus())
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in the remote backend") {
+		t.Fatalf("expected remote backend header in output: %s", output)
+	}
+	if !strings.Contains(output, "null_resource.foo: 1 error") {
+		t.Fatalf("expected plan error in output: %s", output)
+	}
+}
+
+func TestRemote_planOtherError(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = "network-error" // custom error response in backend_mock.go
+
+	_, err := b.Operation(context.Background(), op)
+	if err == nil {
+		t.Errorf("expected error, got success")
+	}
+
+	if !strings.Contains(err.Error(),
+		"the configured \"remote\" backend encountered an unexpected error:\n\nI'm a little teacup") {
+		t.Fatalf("expected error message, got: %s", err.Error())
+	}
+}
+
+func TestRemote_planWithGenConfigOut(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+
+	op.GenerateConfigOut = "generated.tf"
+	op.Workspace = backend.DefaultStateName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "Generating configuration is not currently supported") {
+		t.Fatalf("expected error about config generation, got: %v", errOutput)
+	}
+}
diff --git a/v1.5.7/internal/backend/remote/backend_state.go b/v1.5.7/internal/backend/remote/backend_state.go
new file mode 100644
index 0000000..f65343e
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/backend_state.go
@@ -0,0 +1,198 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"bytes"
+	"context"
+	"crypto/md5"
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+
+	tfe "github.com/hashicorp/go-tfe"
+
+	"github.com/hashicorp/terraform/internal/command/jsonstate"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+type remoteClient struct {
+	client         *tfe.Client
+	lockInfo       *statemgr.LockInfo
+	organization   string
+	runID          string
+	stateUploadErr bool
+	workspace      *tfe.Workspace
+	forcePush      bool
+}
+
+// Get the remote state.
+func (r *remoteClient) Get() (*remote.Payload, error) {
+	ctx := context.Background()
+
+	sv, err := r.client.StateVersions.ReadCurrent(ctx, r.workspace.ID)
+	if err != nil {
+		if err == tfe.ErrResourceNotFound {
+			// If no state exists, then return nil.
+			return nil, nil
+		}
+		return nil, fmt.Errorf("Error retrieving state: %v", err)
+	}
+
+	state, err := r.client.StateVersions.Download(ctx, sv.DownloadURL)
+	if err != nil {
+		return nil, fmt.Errorf("Error downloading state: %v", err)
+	}
+
+	// If the state is empty, then return nil.
+	if len(state) == 0 {
+		return nil, nil
+	}
+
+	// Get the MD5 checksum of the state.
+	sum := md5.Sum(state)
+
+	return &remote.Payload{
+		Data: state,
+		MD5:  sum[:],
+	}, nil
+}
+
+// Put the remote state.
+func (r *remoteClient) Put(state []byte) error {
+	ctx := context.Background()
+
+	// Read the raw state into a Terraform state.
+	stateFile, err := statefile.Read(bytes.NewReader(state))
+	if err != nil {
+		return fmt.Errorf("Error reading state: %s", err)
+	}
+
+	ov, err := jsonstate.MarshalOutputs(stateFile.State.RootModule().OutputValues)
+	if err != nil {
+		return fmt.Errorf("Error reading output values: %s", err)
+	}
+	o, err := json.Marshal(ov)
+	if err != nil {
+		return fmt.Errorf("Error converting output values to json: %s", err)
+	}
+
+	options := tfe.StateVersionCreateOptions{
+		Lineage:          tfe.String(stateFile.Lineage),
+		Serial:           tfe.Int64(int64(stateFile.Serial)),
+		MD5:              tfe.String(fmt.Sprintf("%x", md5.Sum(state))),
+		State:            tfe.String(base64.StdEncoding.EncodeToString(state)),
+		Force:            tfe.Bool(r.forcePush),
+		JSONStateOutputs: tfe.String(base64.StdEncoding.EncodeToString(o)),
+	}
+
+	// If we have a run ID, make sure to add it to the options
+	// so the state will be properly associated with the run.
+	if r.runID != "" {
+		options.Run = &tfe.Run{ID: r.runID}
+	}
+
+	// Create the new state.
+	_, err = r.client.StateVersions.Create(ctx, r.workspace.ID, options)
+	if err != nil {
+		r.stateUploadErr = true
+		return fmt.Errorf("Error uploading state: %v", err)
+	}
+
+	return nil
+}
+
+// Delete the remote state.
+func (r *remoteClient) Delete() error {
+	err := r.client.Workspaces.Delete(context.Background(), r.organization, r.workspace.Name)
+	if err != nil && err != tfe.ErrResourceNotFound {
+		return fmt.Errorf("Error deleting workspace %s: %v", r.workspace.Name, err)
+	}
+
+	return nil
+}
+
+// EnableForcePush to allow the remote client to overwrite state
+// by implementing remote.ClientForcePusher
+func (r *remoteClient) EnableForcePush() {
+	r.forcePush = true
+}
+
+// Lock the remote state.
+func (r *remoteClient) Lock(info *statemgr.LockInfo) (string, error) {
+	ctx := context.Background()
+
+	lockErr := &statemgr.LockError{Info: r.lockInfo}
+
+	// Lock the workspace.
+	_, err := r.client.Workspaces.Lock(ctx, r.workspace.ID, tfe.WorkspaceLockOptions{
+		Reason: tfe.String("Locked by Terraform"),
+	})
+	if err != nil {
+		if err == tfe.ErrWorkspaceLocked {
+			lockErr.Info = info
+			err = fmt.Errorf("%s (lock ID: \"%s/%s\")", err, r.organization, r.workspace.Name)
+		}
+		lockErr.Err = err
+		return "", lockErr
+	}
+
+	r.lockInfo = info
+
+	return r.lockInfo.ID, nil
+}
+
+// Unlock the remote state.
+func (r *remoteClient) Unlock(id string) error {
+	ctx := context.Background()
+
+	// We first check if there was an error while uploading the latest
+	// state. If so, we will not unlock the workspace to prevent any
+	// changes from being applied until the correct state is uploaded.
+	if r.stateUploadErr {
+		return nil
+	}
+
+	lockErr := &statemgr.LockError{Info: r.lockInfo}
+
+	// With lock info this should be treated as a normal unlock.
+	if r.lockInfo != nil {
+		// Verify the expected lock ID.
+		if r.lockInfo.ID != id {
+			lockErr.Err = fmt.Errorf("lock ID does not match existing lock")
+			return lockErr
+		}
+
+		// Unlock the workspace.
+		_, err := r.client.Workspaces.Unlock(ctx, r.workspace.ID)
+		if err != nil {
+			lockErr.Err = err
+			return lockErr
+		}
+
+		return nil
+	}
+
+	// Verify the optional force-unlock lock ID.
+	if r.organization+"/"+r.workspace.Name != id {
+		lockErr.Err = fmt.Errorf(
+			"lock ID %q does not match existing lock ID \"%s/%s\"",
+			id,
+			r.organization,
+			r.workspace.Name,
+		)
+		return lockErr
+	}
+
+	// Force unlock the workspace.
+	_, err := r.client.Workspaces.ForceUnlock(ctx, r.workspace.ID)
+	if err != nil {
+		lockErr.Err = err
+		return lockErr
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/backend/remote/backend_state_test.go b/v1.5.7/internal/backend/remote/backend_state_test.go
new file mode 100644
index 0000000..f89a4b7
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/backend_state_test.go
@@ -0,0 +1,63 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"bytes"
+	"os"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/cloud"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+)
+
+func TestRemoteClient_impl(t *testing.T) {
+	var _ remote.Client = new(remoteClient)
+}
+
+func TestRemoteClient(t *testing.T) {
+	client := testRemoteClient(t)
+	remote.TestClient(t, client)
+}
+
+func TestRemoteClient_stateLock(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	s1, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("expected no error, got %v", err)
+	}
+
+	s2, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("expected no error, got %v", err)
+	}
+
+	remote.TestRemoteLocks(t, s1.(*remote.State).Client, s2.(*remote.State).Client)
+}
+
+func TestRemoteClient_withRunID(t *testing.T) {
+	// Set the TFE_RUN_ID environment variable before creating the client!
+	if err := os.Setenv("TFE_RUN_ID", cloud.GenerateID("run-")); err != nil {
+		t.Fatalf("error setting env var TFE_RUN_ID: %v", err)
+	}
+
+	// Create a new test client.
+	client := testRemoteClient(t)
+
+	// Create a new empty state.
+	sf := statefile.New(states.NewState(), "", 0)
+	var buf bytes.Buffer
+	statefile.Write(sf, &buf)
+
+	// Store the new state to verify (this will be done
+	// by the mock that is used) that the run ID is set.
+	if err := client.Put(buf.Bytes()); err != nil {
+		t.Fatalf("expected no error, got %v", err)
+	}
+}
diff --git a/v1.5.7/internal/backend/remote/backend_test.go b/v1.5.7/internal/backend/remote/backend_test.go
new file mode 100644
index 0000000..743a347
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/backend_test.go
@@ -0,0 +1,753 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"context"
+	"fmt"
+	"reflect"
+	"strings"
+	"testing"
+
+	tfe "github.com/hashicorp/go-tfe"
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	tfversion "github.com/hashicorp/terraform/version"
+	"github.com/zclconf/go-cty/cty"
+
+	backendLocal "github.com/hashicorp/terraform/internal/backend/local"
+)
+
+func TestRemote(t *testing.T) {
+	var _ backend.Enhanced = New(nil)
+	var _ backend.CLI = New(nil)
+}
+
+func TestRemote_backendDefault(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	backend.TestBackendStates(t, b)
+	backend.TestBackendStateLocks(t, b, b)
+	backend.TestBackendStateForceUnlock(t, b, b)
+}
+
+func TestRemote_backendNoDefault(t *testing.T) {
+	b, bCleanup := testBackendNoDefault(t)
+	defer bCleanup()
+
+	backend.TestBackendStates(t, b)
+}
+
+func TestRemote_config(t *testing.T) {
+	cases := map[string]struct {
+		config  cty.Value
+		confErr string
+		valErr  string
+	}{
+		"with_a_nonexisting_organization": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"organization": cty.StringVal("nonexisting"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name":   cty.StringVal("prod"),
+					"prefix": cty.NullVal(cty.String),
+				}),
+			}),
+			confErr: "organization \"nonexisting\" at host app.terraform.io not found",
+		},
+		"with_an_unknown_host": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.StringVal("nonexisting.local"),
+				"organization": cty.StringVal("hashicorp"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name":   cty.StringVal("prod"),
+					"prefix": cty.NullVal(cty.String),
+				}),
+			}),
+			confErr: "Failed to request discovery document",
+		},
+		// localhost advertises TFE services, but has no token in the credentials
+		"without_a_token": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.StringVal("localhost"),
+				"organization": cty.StringVal("hashicorp"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name":   cty.StringVal("prod"),
+					"prefix": cty.NullVal(cty.String),
+				}),
+			}),
+			confErr: "terraform login localhost",
+		},
+		"with_a_name": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"organization": cty.StringVal("hashicorp"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name":   cty.StringVal("prod"),
+					"prefix": cty.NullVal(cty.String),
+				}),
+			}),
+		},
+		"with_a_prefix": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"organization": cty.StringVal("hashicorp"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name":   cty.NullVal(cty.String),
+					"prefix": cty.StringVal("my-app-"),
+				}),
+			}),
+		},
+		"without_either_a_name_and_a_prefix": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"organization": cty.StringVal("hashicorp"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name":   cty.NullVal(cty.String),
+					"prefix": cty.NullVal(cty.String),
+				}),
+			}),
+			valErr: `Either workspace "name" or "prefix" is required`,
+		},
+		"with_both_a_name_and_a_prefix": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"organization": cty.StringVal("hashicorp"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name":   cty.StringVal("prod"),
+					"prefix": cty.StringVal("my-app-"),
+				}),
+			}),
+			valErr: `Only one of workspace "name" or "prefix" is allowed`,
+		},
+		"null config": {
+			config: cty.NullVal(cty.EmptyObject),
+		},
+	}
+
+	for name, tc := range cases {
+		s := testServer(t)
+		b := New(testDisco(s))
+
+		// Validate
+		_, valDiags := b.PrepareConfig(tc.config)
+		if (valDiags.Err() != nil || tc.valErr != "") &&
+			(valDiags.Err() == nil || !strings.Contains(valDiags.Err().Error(), tc.valErr)) {
+			t.Fatalf("%s: unexpected validation result: %v", name, valDiags.Err())
+		}
+
+		// Configure
+		confDiags := b.Configure(tc.config)
+		if (confDiags.Err() != nil || tc.confErr != "") &&
+			(confDiags.Err() == nil || !strings.Contains(confDiags.Err().Error(), tc.confErr)) {
+			t.Fatalf("%s: unexpected configure result: %v", name, confDiags.Err())
+		}
+	}
+}
+
+func TestRemote_versionConstraints(t *testing.T) {
+	cases := map[string]struct {
+		config     cty.Value
+		prerelease string
+		version    string
+		result     string
+	}{
+		"compatible version": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"organization": cty.StringVal("hashicorp"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name":   cty.StringVal("prod"),
+					"prefix": cty.NullVal(cty.String),
+				}),
+			}),
+			version: "0.11.1",
+		},
+		"version too old": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"organization": cty.StringVal("hashicorp"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name":   cty.StringVal("prod"),
+					"prefix": cty.NullVal(cty.String),
+				}),
+			}),
+			version: "0.0.1",
+			result:  "upgrade Terraform to >= 0.1.0",
+		},
+		"version too new": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"organization": cty.StringVal("hashicorp"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name":   cty.StringVal("prod"),
+					"prefix": cty.NullVal(cty.String),
+				}),
+			}),
+			version: "10.0.1",
+			result:  "downgrade Terraform to <= 10.0.0",
+		},
+	}
+
+	// Save and restore the actual version.
+	p := tfversion.Prerelease
+	v := tfversion.Version
+	defer func() {
+		tfversion.Prerelease = p
+		tfversion.Version = v
+	}()
+
+	for name, tc := range cases {
+		s := testServer(t)
+		b := New(testDisco(s))
+
+		// Set the version for this test.
+		tfversion.Prerelease = tc.prerelease
+		tfversion.Version = tc.version
+
+		// Validate
+		_, valDiags := b.PrepareConfig(tc.config)
+		if valDiags.HasErrors() {
+			t.Fatalf("%s: unexpected validation result: %v", name, valDiags.Err())
+		}
+
+		// Configure
+		confDiags := b.Configure(tc.config)
+		if (confDiags.Err() != nil || tc.result != "") &&
+			(confDiags.Err() == nil || !strings.Contains(confDiags.Err().Error(), tc.result)) {
+			t.Fatalf("%s: unexpected configure result: %v", name, confDiags.Err())
+		}
+	}
+}
+
+func TestRemote_localBackend(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	local, ok := b.local.(*backendLocal.Local)
+	if !ok {
+		t.Fatalf("expected b.local to be \"*local.Local\", got: %T", b.local)
+	}
+
+	remote, ok := local.Backend.(*Remote)
+	if !ok {
+		t.Fatalf("expected local.Backend to be *remote.Remote, got: %T", remote)
+	}
+}
+
+func TestRemote_addAndRemoveWorkspacesDefault(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	if _, err := b.Workspaces(); err != backend.ErrWorkspacesNotSupported {
+		t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err)
+	}
+
+	if _, err := b.StateMgr(backend.DefaultStateName); err != nil {
+		t.Fatalf("expected no error, got %v", err)
+	}
+
+	if _, err := b.StateMgr("prod"); err != backend.ErrWorkspacesNotSupported {
+		t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err)
+	}
+
+	if err := b.DeleteWorkspace(backend.DefaultStateName, true); err != nil {
+		t.Fatalf("expected no error, got %v", err)
+	}
+
+	if err := b.DeleteWorkspace("prod", true); err != backend.ErrWorkspacesNotSupported {
+		t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err)
+	}
+}
+
+func TestRemote_addAndRemoveWorkspacesNoDefault(t *testing.T) {
+	b, bCleanup := testBackendNoDefault(t)
+	defer bCleanup()
+
+	states, err := b.Workspaces()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expectedWorkspaces := []string(nil)
+	if !reflect.DeepEqual(states, expectedWorkspaces) {
+		t.Fatalf("expected states %#+v, got %#+v", expectedWorkspaces, states)
+	}
+
+	if _, err := b.StateMgr(backend.DefaultStateName); err != backend.ErrDefaultWorkspaceNotSupported {
+		t.Fatalf("expected error %v, got %v", backend.ErrDefaultWorkspaceNotSupported, err)
+	}
+
+	expectedA := "test_A"
+	if _, err := b.StateMgr(expectedA); err != nil {
+		t.Fatal(err)
+	}
+
+	states, err = b.Workspaces()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expectedWorkspaces = append(expectedWorkspaces, expectedA)
+	if !reflect.DeepEqual(states, expectedWorkspaces) {
+		t.Fatalf("expected %#+v, got %#+v", expectedWorkspaces, states)
+	}
+
+	expectedB := "test_B"
+	if _, err := b.StateMgr(expectedB); err != nil {
+		t.Fatal(err)
+	}
+
+	states, err = b.Workspaces()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expectedWorkspaces = append(expectedWorkspaces, expectedB)
+	if !reflect.DeepEqual(states, expectedWorkspaces) {
+		t.Fatalf("expected %#+v, got %#+v", expectedWorkspaces, states)
+	}
+
+	if err := b.DeleteWorkspace(backend.DefaultStateName, true); err != backend.ErrDefaultWorkspaceNotSupported {
+		t.Fatalf("expected error %v, got %v", backend.ErrDefaultWorkspaceNotSupported, err)
+	}
+
+	if err := b.DeleteWorkspace(expectedA, true); err != nil {
+		t.Fatal(err)
+	}
+
+	states, err = b.Workspaces()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expectedWorkspaces = []string{expectedB}
+	if !reflect.DeepEqual(states, expectedWorkspaces) {
+		t.Fatalf("expected %#+v got %#+v", expectedWorkspaces, states)
+	}
+
+	if err := b.DeleteWorkspace(expectedB, true); err != nil {
+		t.Fatal(err)
+	}
+
+	states, err = b.Workspaces()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expectedWorkspaces = []string(nil)
+	if !reflect.DeepEqual(states, expectedWorkspaces) {
+		t.Fatalf("expected %#+v, got %#+v", expectedWorkspaces, states)
+	}
+}
+
+func TestRemote_checkConstraints(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	cases := map[string]struct {
+		constraints *disco.Constraints
+		prerelease  string
+		version     string
+		result      string
+	}{
+		"compatible version": {
+			constraints: &disco.Constraints{
+				Minimum: "0.11.0",
+				Maximum: "0.11.11",
+			},
+			version: "0.11.1",
+			result:  "",
+		},
+		"version too old": {
+			constraints: &disco.Constraints{
+				Minimum: "0.11.0",
+				Maximum: "0.11.11",
+			},
+			version: "0.10.1",
+			result:  "upgrade Terraform to >= 0.11.0",
+		},
+		"version too new": {
+			constraints: &disco.Constraints{
+				Minimum: "0.11.0",
+				Maximum: "0.11.11",
+			},
+			version: "0.12.0",
+			result:  "downgrade Terraform to <= 0.11.11",
+		},
+		"version excluded - ordered": {
+			constraints: &disco.Constraints{
+				Minimum:   "0.11.0",
+				Excluding: []string{"0.11.7", "0.11.8"},
+				Maximum:   "0.11.11",
+			},
+			version: "0.11.7",
+			result:  "upgrade Terraform to > 0.11.8",
+		},
+		"version excluded - unordered": {
+			constraints: &disco.Constraints{
+				Minimum:   "0.11.0",
+				Excluding: []string{"0.11.8", "0.11.6"},
+				Maximum:   "0.11.11",
+			},
+			version: "0.11.6",
+			result:  "upgrade Terraform to > 0.11.8",
+		},
+		"list versions": {
+			constraints: &disco.Constraints{
+				Minimum: "0.11.0",
+				Maximum: "0.11.11",
+			},
+			version: "0.10.1",
+			result:  "versions >= 0.11.0, <= 0.11.11.",
+		},
+		"list exclusion": {
+			constraints: &disco.Constraints{
+				Minimum:   "0.11.0",
+				Excluding: []string{"0.11.6"},
+				Maximum:   "0.11.11",
+			},
+			version: "0.11.6",
+			result:  "excluding version 0.11.6.",
+		},
+		"list exclusions": {
+			constraints: &disco.Constraints{
+				Minimum:   "0.11.0",
+				Excluding: []string{"0.11.8", "0.11.6"},
+				Maximum:   "0.11.11",
+			},
+			version: "0.11.6",
+			result:  "excluding versions 0.11.6, 0.11.8.",
+		},
+	}
+
+	// Save and restore the actual version.
+	p := tfversion.Prerelease
+	v := tfversion.Version
+	defer func() {
+		tfversion.Prerelease = p
+		tfversion.Version = v
+	}()
+
+	for name, tc := range cases {
+		// Set the version for this test.
+		tfversion.Prerelease = tc.prerelease
+		tfversion.Version = tc.version
+
+		// Check the constraints.
+		diags := b.checkConstraints(tc.constraints)
+		if (diags.Err() != nil || tc.result != "") &&
+			(diags.Err() == nil || !strings.Contains(diags.Err().Error(), tc.result)) {
+			t.Fatalf("%s: unexpected constraints result: %v", name, diags.Err())
+		}
+	}
+}
+
+func TestRemote_StateMgr_versionCheck(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	// Some fixed versions for testing with. This logic is a simple string
+	// comparison, so we don't need many test cases.
+	v0135 := version.Must(version.NewSemver("0.13.5"))
+	v0140 := version.Must(version.NewSemver("0.14.0"))
+
+	// Save original local version state and restore afterwards
+	p := tfversion.Prerelease
+	v := tfversion.Version
+	s := tfversion.SemVer
+	defer func() {
+		tfversion.Prerelease = p
+		tfversion.Version = v
+		tfversion.SemVer = s
+	}()
+
+	// For this test, the local Terraform version is set to 0.14.0
+	tfversion.Prerelease = ""
+	tfversion.Version = v0140.String()
+	tfversion.SemVer = v0140
+
+	// Update the mock remote workspace Terraform version to match the local
+	// Terraform version
+	if _, err := b.client.Workspaces.Update(
+		context.Background(),
+		b.organization,
+		b.workspace,
+		tfe.WorkspaceUpdateOptions{
+			TerraformVersion: tfe.String(v0140.String()),
+		},
+	); err != nil {
+		t.Fatalf("error: %v", err)
+	}
+
+	// This should succeed
+	if _, err := b.StateMgr(backend.DefaultStateName); err != nil {
+		t.Fatalf("expected no error, got %v", err)
+	}
+
+	// Now change the remote workspace to a different Terraform version
+	if _, err := b.client.Workspaces.Update(
+		context.Background(),
+		b.organization,
+		b.workspace,
+		tfe.WorkspaceUpdateOptions{
+			TerraformVersion: tfe.String(v0135.String()),
+		},
+	); err != nil {
+		t.Fatalf("error: %v", err)
+	}
+
+	// This should fail
+	want := `Remote workspace Terraform version "0.13.5" does not match local Terraform version "0.14.0"`
+	if _, err := b.StateMgr(backend.DefaultStateName); err.Error() != want {
+		t.Fatalf("wrong error\n got: %v\nwant: %v", err.Error(), want)
+	}
+}
+
+func TestRemote_StateMgr_versionCheckLatest(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	v0140 := version.Must(version.NewSemver("0.14.0"))
+
+	// Save original local version state and restore afterwards
+	p := tfversion.Prerelease
+	v := tfversion.Version
+	s := tfversion.SemVer
+	defer func() {
+		tfversion.Prerelease = p
+		tfversion.Version = v
+		tfversion.SemVer = s
+	}()
+
+	// For this test, the local Terraform version is set to 0.14.0
+	tfversion.Prerelease = ""
+	tfversion.Version = v0140.String()
+	tfversion.SemVer = v0140
+
+	// Update the remote workspace to the pseudo-version "latest"
+	if _, err := b.client.Workspaces.Update(
+		context.Background(),
+		b.organization,
+		b.workspace,
+		tfe.WorkspaceUpdateOptions{
+			TerraformVersion: tfe.String("latest"),
+		},
+	); err != nil {
+		t.Fatalf("error: %v", err)
+	}
+
+	// This should succeed despite not being a string match
+	if _, err := b.StateMgr(backend.DefaultStateName); err != nil {
+		t.Fatalf("expected no error, got %v", err)
+	}
+}
+
+func TestRemote_VerifyWorkspaceTerraformVersion(t *testing.T) {
+	testCases := []struct {
+		local         string
+		remote        string
+		executionMode string
+		wantErr       bool
+	}{
+		{"0.13.5", "0.13.5", "remote", false},
+		{"0.14.0", "0.13.5", "remote", true},
+		{"0.14.0", "0.13.5", "local", false},
+		{"0.14.0", "0.14.1", "remote", false},
+		{"0.14.0", "1.0.99", "remote", false},
+		{"0.14.0", "1.1.0", "remote", false},
+		{"0.14.0", "1.3.0", "remote", true},
+		{"1.2.0", "1.2.99", "remote", false},
+		{"1.2.0", "1.3.0", "remote", true},
+		{"0.15.0", "latest", "remote", false},
+	}
+	for _, tc := range testCases {
+		t.Run(fmt.Sprintf("local %s, remote %s", tc.local, tc.remote), func(t *testing.T) {
+			b, bCleanup := testBackendDefault(t)
+			defer bCleanup()
+
+			local := version.Must(version.NewSemver(tc.local))
+
+			// Save original local version state and restore afterwards
+			p := tfversion.Prerelease
+			v := tfversion.Version
+			s := tfversion.SemVer
+			defer func() {
+				tfversion.Prerelease = p
+				tfversion.Version = v
+				tfversion.SemVer = s
+			}()
+
+			// Override local version as specified
+			tfversion.Prerelease = ""
+			tfversion.Version = local.String()
+			tfversion.SemVer = local
+
+			// Update the mock remote workspace Terraform version to the
+			// specified remote version
+			if _, err := b.client.Workspaces.Update(
+				context.Background(),
+				b.organization,
+				b.workspace,
+				tfe.WorkspaceUpdateOptions{
+					ExecutionMode:    &tc.executionMode,
+					TerraformVersion: tfe.String(tc.remote),
+				},
+			); err != nil {
+				t.Fatalf("error: %v", err)
+			}
+
+			diags := b.VerifyWorkspaceTerraformVersion(backend.DefaultStateName)
+			if tc.wantErr {
+				if len(diags) != 1 {
+					t.Fatal("expected diag, but none returned")
+				}
+				if got := diags.Err().Error(); !strings.Contains(got, "Terraform version mismatch") {
+					t.Fatalf("unexpected error: %s", got)
+				}
+			} else {
+				if len(diags) != 0 {
+					t.Fatalf("unexpected diags: %s", diags.Err())
+				}
+			}
+		})
+	}
+}
+
+func TestRemote_VerifyWorkspaceTerraformVersion_workspaceErrors(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	// Attempting to check the version against a workspace which doesn't exist
+	// should result in no errors
+	diags := b.VerifyWorkspaceTerraformVersion("invalid-workspace")
+	if len(diags) != 0 {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+
+	// Use a special workspace ID to trigger a 500 error, which should result
+	// in a failed check
+	diags = b.VerifyWorkspaceTerraformVersion("network-error")
+	if len(diags) != 1 {
+		t.Fatal("expected diag, but none returned")
+	}
+	if got := diags.Err().Error(); !strings.Contains(got, "Error looking up workspace: Workspace read failed") {
+		t.Fatalf("unexpected error: %s", got)
+	}
+
+	// Update the mock remote workspace Terraform version to an invalid version
+	if _, err := b.client.Workspaces.Update(
+		context.Background(),
+		b.organization,
+		b.workspace,
+		tfe.WorkspaceUpdateOptions{
+			TerraformVersion: tfe.String("1.0.cheetarah"),
+		},
+	); err != nil {
+		t.Fatalf("error: %v", err)
+	}
+	diags = b.VerifyWorkspaceTerraformVersion(backend.DefaultStateName)
+
+	if len(diags) != 1 {
+		t.Fatal("expected diag, but none returned")
+	}
+	if got := diags.Err().Error(); !strings.Contains(got, "Error looking up workspace: Invalid Terraform version") {
+		t.Fatalf("unexpected error: %s", got)
+	}
+}
+
+func TestRemote_VerifyWorkspaceTerraformVersion_ignoreFlagSet(t *testing.T) {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	// If the ignore flag is set, the behaviour changes
+	b.IgnoreVersionConflict()
+
+	// Different local & remote versions to cause an error
+	local := version.Must(version.NewSemver("0.14.0"))
+	remote := version.Must(version.NewSemver("0.13.5"))
+
+	// Save original local version state and restore afterwards
+	p := tfversion.Prerelease
+	v := tfversion.Version
+	s := tfversion.SemVer
+	defer func() {
+		tfversion.Prerelease = p
+		tfversion.Version = v
+		tfversion.SemVer = s
+	}()
+
+	// Override local version as specified
+	tfversion.Prerelease = ""
+	tfversion.Version = local.String()
+	tfversion.SemVer = local
+
+	// Update the mock remote workspace Terraform version to the
+	// specified remote version
+	if _, err := b.client.Workspaces.Update(
+		context.Background(),
+		b.organization,
+		b.workspace,
+		tfe.WorkspaceUpdateOptions{
+			TerraformVersion: tfe.String(remote.String()),
+		},
+	); err != nil {
+		t.Fatalf("error: %v", err)
+	}
+
+	diags := b.VerifyWorkspaceTerraformVersion(backend.DefaultStateName)
+	if len(diags) != 1 {
+		t.Fatal("expected diag, but none returned")
+	}
+
+	if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
+		t.Errorf("wrong severity: got %#v, want %#v", got, want)
+	}
+	if got, want := diags[0].Description().Summary, "Terraform version mismatch"; got != want {
+		t.Errorf("wrong summary: got %s, want %s", got, want)
+	}
+	wantDetail := "The local Terraform version (0.14.0) does not match the configured version for remote workspace hashicorp/prod (0.13.5)."
+	if got := diags[0].Description().Detail; got != wantDetail {
+		t.Errorf("wrong summary: got %s, want %s", got, wantDetail)
+	}
+}
+
+func TestRemote_ServiceDiscoveryAliases(t *testing.T) {
+	s := testServer(t)
+	b := New(testDisco(s))
+
+	diag := b.Configure(cty.ObjectVal(map[string]cty.Value{
+		"hostname":     cty.NullVal(cty.String), // Forces aliasing to test server
+		"organization": cty.StringVal("hashicorp"),
+		"token":        cty.NullVal(cty.String),
+		"workspaces": cty.ObjectVal(map[string]cty.Value{
+			"name":   cty.StringVal("prod"),
+			"prefix": cty.NullVal(cty.String),
+		}),
+	}))
+	if diag.HasErrors() {
+		t.Fatalf("expected no diagnostic errors, got %s", diag.Err())
+	}
+
+	aliases, err := b.ServiceDiscoveryAliases()
+	if err != nil {
+		t.Fatalf("expected no errors, got %s", err)
+	}
+	if len(aliases) != 1 {
+		t.Fatalf("expected 1 alias but got %d", len(aliases))
+	}
+}
diff --git a/v1.5.7/internal/backend/remote/cli.go b/v1.5.7/internal/backend/remote/cli.go
new file mode 100644
index 0000000..0834f6c
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/cli.go
@@ -0,0 +1,23 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"github.com/hashicorp/terraform/internal/backend"
+)
+
+// CLIInit implements backend.CLI
+func (b *Remote) CLIInit(opts *backend.CLIOpts) error {
+	if cli, ok := b.local.(backend.CLI); ok {
+		if err := cli.CLIInit(opts); err != nil {
+			return err
+		}
+	}
+
+	b.CLI = opts.CLI
+	b.CLIColor = opts.CLIColor
+	b.ContextOpts = opts.ContextOpts
+
+	return nil
+}
diff --git a/v1.5.7/internal/backend/remote/colorize.go b/v1.5.7/internal/backend/remote/colorize.go
new file mode 100644
index 0000000..97e769d
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/colorize.go
@@ -0,0 +1,53 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"regexp"
+
+	"github.com/mitchellh/colorstring"
+)
+
+// TODO SvH: This file should be deleted and the type cliColorize should be
+// renamed back to Colorize as soon as we can pass -no-color to the backend.
+
+// colorsRe is used to find ANSI escaped color codes.
+var colorsRe = regexp.MustCompile("\033\\[\\d{1,3}m")
+
+// Colorer is the interface that must be implemented to colorize strings.
+type Colorer interface {
+	Color(v string) string
+}
+
+// Colorize is used to print output when the -no-color flag is used. It will
+// strip all ANSI escaped color codes which are set while the operation was
+// executed in Terraform Enterprise.
+//
+// When Terraform Enterprise supports run specific variables, this code can be
+// removed as we can then pass the CLI flag to the backend and prevent the color
+// codes from being written to the output.
+type Colorize struct {
+	cliColor *colorstring.Colorize
+}
+
+// Color will strip all ANSI escaped color codes and return a uncolored string.
+func (c *Colorize) Color(v string) string {
+	return colorsRe.ReplaceAllString(c.cliColor.Color(v), "")
+}
+
+// Colorize returns the Colorize structure that can be used for colorizing
+// output. This is guaranteed to always return a non-nil value and so is useful
+// as a helper to wrap any potentially colored strings.
+func (b *Remote) Colorize() Colorer {
+	if b.CLIColor != nil && !b.CLIColor.Disable {
+		return b.CLIColor
+	}
+	if b.CLIColor != nil {
+		return &Colorize{cliColor: b.CLIColor}
+	}
+	return &Colorize{cliColor: &colorstring.Colorize{
+		Colors:  colorstring.DefaultColors,
+		Disable: true,
+	}}
+}
diff --git a/v1.5.7/internal/backend/remote/remote_test.go b/v1.5.7/internal/backend/remote/remote_test.go
new file mode 100644
index 0000000..77ab784
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/remote_test.go
@@ -0,0 +1,28 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"flag"
+	"os"
+	"testing"
+	"time"
+
+	_ "github.com/hashicorp/terraform/internal/logging"
+)
+
+func TestMain(m *testing.M) {
+	flag.Parse()
+
+	// Make sure TF_FORCE_LOCAL_BACKEND is unset
+	os.Unsetenv("TF_FORCE_LOCAL_BACKEND")
+
+	// Reduce delays to make tests run faster
+	backoffMin = 1.0
+	backoffMax = 1.0
+	planConfigurationVersionsPollInterval = 1 * time.Millisecond
+	runPollInterval = 1 * time.Millisecond
+
+	os.Exit(m.Run())
+}
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-destroy/apply.log b/v1.5.7/internal/backend/remote/testdata/apply-destroy/apply.log
new file mode 100644
index 0000000..d126547
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-destroy/apply.log
@@ -0,0 +1,7 @@
+Terraform v0.11.10
+
+Initializing plugins and modules...
+null_resource.hello: Destroying... (ID: 8657651096157629581)
+null_resource.hello: Destruction complete after 0s
+
+Apply complete! Resources: 0 added, 0 changed, 1 destroyed.
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-destroy/main.tf b/v1.5.7/internal/backend/remote/testdata/apply-destroy/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-destroy/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-destroy/plan.log b/v1.5.7/internal/backend/remote/testdata/apply-destroy/plan.log
new file mode 100644
index 0000000..1d38d41
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-destroy/plan.log
@@ -0,0 +1,22 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+null_resource.hello: Refreshing state... (ID: 8657651096157629581)
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  - destroy
+
+Terraform will perform the following actions:
+
+  - null_resource.hello
+
+
+Plan: 0 to add, 0 to change, 1 to destroy.
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-no-changes/main.tf b/v1.5.7/internal/backend/remote/testdata/apply-no-changes/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-no-changes/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-no-changes/plan.log b/v1.5.7/internal/backend/remote/testdata/apply-no-changes/plan.log
new file mode 100644
index 0000000..7041681
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-no-changes/plan.log
@@ -0,0 +1,17 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+null_resource.hello: Refreshing state... (ID: 8657651096157629581)
+
+------------------------------------------------------------------------
+
+No changes. Infrastructure is up-to-date.
+
+This means that Terraform did not detect any differences between your
+configuration and real physical resources that exist. As a result, no
+actions need to be performed.
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-no-changes/policy.log b/v1.5.7/internal/backend/remote/testdata/apply-no-changes/policy.log
new file mode 100644
index 0000000..b0cb1e5
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-no-changes/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: true
+
+This result means that Sentinel policies returned true and the protected
+behavior is allowed by Sentinel policies.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (soft-mandatory)
+
+Result: true
+
+TRUE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-policy-hard-failed/main.tf b/v1.5.7/internal/backend/remote/testdata/apply-policy-hard-failed/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-policy-hard-failed/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-policy-hard-failed/plan.log b/v1.5.7/internal/backend/remote/testdata/apply-policy-hard-failed/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-policy-hard-failed/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-policy-hard-failed/policy.log b/v1.5.7/internal/backend/remote/testdata/apply-policy-hard-failed/policy.log
new file mode 100644
index 0000000..5d6e693
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-policy-hard-failed/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: false
+
+Sentinel evaluated to false because one or more Sentinel policies evaluated
+to false. This false was not due to an undefined value or runtime error.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (hard-mandatory)
+
+Result: false
+
+FALSE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-policy-passed/apply.log b/v1.5.7/internal/backend/remote/testdata/apply-policy-passed/apply.log
new file mode 100644
index 0000000..9019948
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-policy-passed/apply.log
@@ -0,0 +1,7 @@
+Terraform v0.11.10
+
+Initializing plugins and modules...
+null_resource.hello: Creating...
+null_resource.hello: Creation complete after 0s (ID: 8657651096157629581)
+
+Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-policy-passed/main.tf b/v1.5.7/internal/backend/remote/testdata/apply-policy-passed/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-policy-passed/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-policy-passed/plan.log b/v1.5.7/internal/backend/remote/testdata/apply-policy-passed/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-policy-passed/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-policy-passed/policy.log b/v1.5.7/internal/backend/remote/testdata/apply-policy-passed/policy.log
new file mode 100644
index 0000000..b0cb1e5
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-policy-passed/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: true
+
+This result means that Sentinel policies returned true and the protected
+behavior is allowed by Sentinel policies.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (soft-mandatory)
+
+Result: true
+
+TRUE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-policy-soft-failed/apply.log b/v1.5.7/internal/backend/remote/testdata/apply-policy-soft-failed/apply.log
new file mode 100644
index 0000000..9019948
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-policy-soft-failed/apply.log
@@ -0,0 +1,7 @@
+Terraform v0.11.10
+
+Initializing plugins and modules...
+null_resource.hello: Creating...
+null_resource.hello: Creation complete after 0s (ID: 8657651096157629581)
+
+Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-policy-soft-failed/main.tf b/v1.5.7/internal/backend/remote/testdata/apply-policy-soft-failed/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-policy-soft-failed/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-policy-soft-failed/plan.log b/v1.5.7/internal/backend/remote/testdata/apply-policy-soft-failed/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-policy-soft-failed/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-policy-soft-failed/policy.log b/v1.5.7/internal/backend/remote/testdata/apply-policy-soft-failed/policy.log
new file mode 100644
index 0000000..3e4ebed
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-policy-soft-failed/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: false
+
+Sentinel evaluated to false because one or more Sentinel policies evaluated
+to false. This false was not due to an undefined value or runtime error.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (soft-mandatory)
+
+Result: false
+
+FALSE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-variables/apply.log b/v1.5.7/internal/backend/remote/testdata/apply-variables/apply.log
new file mode 100644
index 0000000..9019948
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-variables/apply.log
@@ -0,0 +1,7 @@
+Terraform v0.11.10
+
+Initializing plugins and modules...
+null_resource.hello: Creating...
+null_resource.hello: Creation complete after 0s (ID: 8657651096157629581)
+
+Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-variables/main.tf b/v1.5.7/internal/backend/remote/testdata/apply-variables/main.tf
new file mode 100644
index 0000000..955e8b4
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-variables/main.tf
@@ -0,0 +1,4 @@
+variable "foo" {}
+variable "bar" {}
+
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-variables/plan.log b/v1.5.7/internal/backend/remote/testdata/apply-variables/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-variables/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-with-error/main.tf b/v1.5.7/internal/backend/remote/testdata/apply-with-error/main.tf
new file mode 100644
index 0000000..bc45f28
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-with-error/main.tf
@@ -0,0 +1,5 @@
+resource "null_resource" "foo" {
+  triggers {
+    random = "${guid()}"
+  }
+}
diff --git a/v1.5.7/internal/backend/remote/testdata/apply-with-error/plan.log b/v1.5.7/internal/backend/remote/testdata/apply-with-error/plan.log
new file mode 100644
index 0000000..4344a37
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply-with-error/plan.log
@@ -0,0 +1,10 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+
+Error: null_resource.foo: 1 error(s) occurred:
+
+* null_resource.foo: 1:3: unknown function called: guid in:
+
+${guid()}
diff --git a/v1.5.7/internal/backend/remote/testdata/apply/apply.log b/v1.5.7/internal/backend/remote/testdata/apply/apply.log
new file mode 100644
index 0000000..9019948
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply/apply.log
@@ -0,0 +1,7 @@
+Terraform v0.11.10
+
+Initializing plugins and modules...
+null_resource.hello: Creating...
+null_resource.hello: Creation complete after 0s (ID: 8657651096157629581)
+
+Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
diff --git a/v1.5.7/internal/backend/remote/testdata/apply/main.tf b/v1.5.7/internal/backend/remote/testdata/apply/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/backend/remote/testdata/apply/plan.log b/v1.5.7/internal/backend/remote/testdata/apply/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/apply/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/backend/remote/testdata/empty/.gitignore b/v1.5.7/internal/backend/remote/testdata/empty/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/empty/.gitignore
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-cost-estimation/ce.log b/v1.5.7/internal/backend/remote/testdata/plan-cost-estimation/ce.log
new file mode 100644
index 0000000..e51fef1
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-cost-estimation/ce.log
@@ -0,0 +1,6 @@
++---------+------+-----+-------------+----------------------+
+| PRODUCT | NAME | SKU | DESCRIPTION |        DELTA         |
++---------+------+-----+-------------+----------------------+
++---------+------+-----+-------------+----------------------+
+|                           TOTAL    | $0.000 USD / 720 HRS |
++---------+------+-----+-------------+----------------------+
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-cost-estimation/cost-estimate.log b/v1.5.7/internal/backend/remote/testdata/plan-cost-estimation/cost-estimate.log
new file mode 100644
index 0000000..67a5092
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-cost-estimation/cost-estimate.log
@@ -0,0 +1,5 @@
+Cost estimation:
+
+Waiting for cost estimation to complete...
+Resources: 1 of 1 estimated
+           $25.488/mo +$25.488
\ No newline at end of file
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-cost-estimation/main.tf b/v1.5.7/internal/backend/remote/testdata/plan-cost-estimation/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-cost-estimation/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-cost-estimation/plan.log b/v1.5.7/internal/backend/remote/testdata/plan-cost-estimation/plan.log
new file mode 100644
index 0000000..fae287f
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-cost-estimation/plan.log
@@ -0,0 +1,20 @@
+Terraform v0.12.9
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-long-line/main.tf b/v1.5.7/internal/backend/remote/testdata/plan-long-line/main.tf
new file mode 100644
index 0000000..0a8d623
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-long-line/main.tf
@@ -0,0 +1,5 @@
+resource "null_resource" "foo" {
+  triggers {
+    long_line = "[{'_id':'5c5ab0ed7de45e993ffb9eeb','index':0,'guid':'e734d772-6b5a-4cb0-805c-91cd5e560e20','isActive':false,'balance':'$1,472.03','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Darlene','last':'Garza'},'company':'GEEKOSIS','email':'darlene.garza@geekosis.io','phone':'+1 (850) 506-3347','address':'165 Kiely Place, Como, New Mexico, 4335','about':'Officia ullamco et sunt magna voluptate culpa cupidatat ea tempor laboris cupidatat ea anim laboris. Minim enim quis enim esse laborum est veniam. Lorem excepteur elit Lorem cupidatat elit ea anim irure fugiat fugiat sunt mollit. Consectetur ad nulla dolor amet esse occaecat aliquip sit. Magna sit elit adipisicing ut reprehenderit anim exercitation sit quis ea pariatur Lorem magna dolore.','registered':'Wednesday, March 11, 2015 12:58 PM','latitude':'20.729127','longitude':'-127.343593','tags':['minim','in','deserunt','occaecat','fugiat'],'greeting':'Hello, Darlene! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eda9117d15f1c1f112','index':1,'guid':'f0d1eed2-c6a9-4535-8800-d4bd53fe7eee','isActive':true,'balance':'$2,901.90','picture':'http://placehold.it/32x32','age':28,'eyeColor':'brown','name':{'first':'Flora','last':'Short'},'company':'SIGNITY','email':'flora.short@signity.me','phone':'+1 (840) 520-2666','address':'636 Johnson Avenue, Gerber, Wisconsin, 9139','about':'Veniam dolore deserunt Lorem aliqua qui eiusmod. Amet tempor fugiat duis incididunt amet adipisicing. Id ea nisi veniam eiusmod.','registered':'Wednesday, May 2, 2018 5:59 AM','latitude':'-63.267612','longitude':'4.224102','tags':['veniam','incididunt','id','aliqua','reprehenderit'],'greeting':'Hello, Flora! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed83fd574d8041fa16','index':2,'guid':'29499a07-414a-436f-ba62-6634ca16bdcc','isActive':true,'balance':'$2,781.28','picture':'http://placehold.it/32x32','age':22,'eyeColor':'green','name':{'first':'Trevino','last':'Marks'},'company':'KEGULAR','email':'trevino.marks@kegular.com','phone':'+1 (843) 571-2269','address':'200 Alabama Avenue, Grenelefe, Florida, 7963','about':'Occaecat nisi exercitation Lorem mollit laborum magna adipisicing culpa dolor proident dolore. Non consequat ea amet et id mollit incididunt minim anim amet nostrud labore tempor. Proident eu sint commodo nisi consequat voluptate do fugiat proident. Laboris eiusmod veniam non et elit nulla nisi labore incididunt Lorem consequat consectetur voluptate.','registered':'Saturday, January 25, 2014 5:56 AM','latitude':'65.044005','longitude':'-127.454864','tags':['anim','duis','velit','pariatur','enim'],'greeting':'Hello, Trevino! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed784eb6e350ff0a07','index':3,'guid':'40ed47e2-1747-4665-ab59-cdb3630a7642','isActive':true,'balance':'$2,000.78','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Solis','last':'Mckinney'},'company':'QABOOS','email':'solis.mckinney@qaboos.org','phone':'+1 (924) 405-2560','address':'712 Herkimer Court, Klondike, Ohio, 8133','about':'Minim ad anim minim tempor mollit magna tempor et non commodo amet. Nisi cupidatat labore culpa consectetur exercitation laborum adipisicing fugiat officia adipisicing consequat non. Qui voluptate tempor laboris exercitation qui non adipisicing occaecat voluptate sunt do nostrud velit. Consequat tempor officia laboris tempor irure cupidatat aliquip voluptate nostrud velit ex nulla tempor laboris. Qui pariatur pariatur enim aliquip velit. Officia mollit ullamco laboris velit velit eiusmod enim amet incididunt consectetur sunt.','registered':'Wednesday, April 12, 2017 6:59 AM','latitude':'-25.055596','longitude':'-140.126525','tags':['ipsum','adipisicing','amet','nulla','dolore'],'greeting':'Hello, Solis! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed02ce1ea9a2155d51','index':4,'guid':'1b5fb7d3-3b9a-4382-81b5-9ab01a27e74b','isActive':true,'balance':'$1,373.67','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Janell','last':'Battle'},'company':'GEEKMOSIS','email':'janell.battle@geekmosis.net','phone':'+1 (810) 591-3014','address':'517 Onderdonk Avenue, Shrewsbury, District Of Columbia, 2335','about':'Reprehenderit ad proident do anim qui officia magna magna duis cillum esse minim est. Excepteur ipsum anim ad laboris. In occaecat dolore nulla ea Lorem tempor et culpa in sint. Officia eu eu incididunt sit amet. Culpa duis id reprehenderit ut anim sit sunt. Duis dolore proident velit incididunt adipisicing pariatur fugiat incididunt eiusmod eu veniam irure.','registered':'Thursday, February 8, 2018 1:44 AM','latitude':'-33.254864','longitude':'-154.145885','tags':['aute','deserunt','ipsum','eiusmod','laborum'],'greeting':'Hello, Janell! You have 5 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edab58604bd7d3dd1c','index':5,'guid':'6354c035-af22-44c9-8be9-b2ea9decc24d','isActive':true,'balance':'$3,535.68','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Combs','last':'Kirby'},'company':'LUXURIA','email':'combs.kirby@luxuria.name','phone':'+1 (900) 498-3266','address':'377 Kingsland Avenue, Ruckersville, Maine, 9916','about':'Lorem duis ipsum pariatur aliquip sunt. Commodo esse laborum incididunt mollit quis est laboris ea ea quis fugiat. Enim elit ullamco velit et fugiat veniam irure deserunt aliqua ad irure veniam.','registered':'Tuesday, February 21, 2017 4:04 PM','latitude':'-70.20591','longitude':'162.546871','tags':['reprehenderit','est','enim','aute','ad'],'greeting':'Hello, Combs! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edf7fafeffc6357c51','index':6,'guid':'02523e0b-cc90-4309-b6b2-f493dc6076f6','isActive':false,'balance':'$3,754.30','picture':'http://placehold.it/32x32','age':29,'eyeColor':'green','name':{'first':'Macias','last':'Calderon'},'company':'AMTAP','email':'macias.calderon@amtap.us','phone':'+1 (996) 569-3667','address':'305 Royce Street, Glidden, Iowa, 9248','about':'Exercitation nulla deserunt pariatur adipisicing. In commodo deserunt incididunt ut velit minim qui ut quis. Labore elit ullamco eiusmod voluptate in eu do est fugiat aute mollit deserunt. Eu duis proident velit fugiat velit ut. Ut non esse amet laborum nisi tempor in nulla.','registered':'Thursday, October 23, 2014 10:28 PM','latitude':'32.371629','longitude':'60.155135','tags':['commodo','elit','velit','excepteur','aliqua'],'greeting':'Hello, Macias! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed0e8a6109e7fabf17','index':7,'guid':'675ff6b6-197b-4154-9775-813d661df822','isActive':false,'balance':'$2,850.62','picture':'http://placehold.it/32x32','age':37,'eyeColor':'green','name':{'first':'Stefanie','last':'Rivers'},'company':'RECRITUBE','email':'stefanie.rivers@recritube.biz','phone':'+1 (994) 591-3551','address':'995 Campus Road, Abrams, Virginia, 3251','about':'Esse aute non laborum Lorem nulla irure. Veniam elit aute ut et dolor non deserunt laboris tempor. Ipsum quis cupidatat laborum laboris voluptate esse duis eiusmod excepteur consectetur commodo ullamco qui occaecat. Culpa velit cillum occaecat minim nisi.','registered':'Thursday, June 9, 2016 3:40 PM','latitude':'-18.526825','longitude':'149.670782','tags':['occaecat','sunt','reprehenderit','ipsum','magna'],'greeting':'Hello, Stefanie! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edf7d9bc2db4e476e3','index':8,'guid':'adaefc55-f6ea-4bd1-a147-0e31c3ce7a21','isActive':true,'balance':'$2,555.13','picture':'http://placehold.it/32x32','age':20,'eyeColor':'blue','name':{'first':'Hillary','last':'Lancaster'},'company':'OLUCORE','email':'hillary.lancaster@olucore.ca','phone':'+1 (964) 474-3018','address':'232 Berriman Street, Kaka, Massachusetts, 6792','about':'Veniam ad laboris quis reprehenderit aliquip nisi sunt excepteur ea aute laborum excepteur incididunt. Nisi exercitation aliquip do culpa commodo ex officia ut enim mollit in deserunt in amet. Anim eu deserunt dolore non cupidatat ut enim incididunt aute dolore voluptate. Do cillum mollit laborum non incididunt occaecat aute voluptate nisi irure.','registered':'Thursday, June 4, 2015 9:45 PM','latitude':'88.075919','longitude':'-148.951368','tags':['reprehenderit','veniam','ad','aute','anim'],'greeting':'Hello, Hillary! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed7b7192ad6a0f267c','index':9,'guid':'0ca9b8ea-f671-474e-be26-4a49cae4838a','isActive':true,'balance':'$3,684.51','picture':'http://placehold.it/32x32','age':40,'eyeColor':'brown','name':{'first':'Jill','last':'Conner'},'company':'EXOZENT','email':'jill.conner@exozent.info','phone':'+1 (887) 467-2168','address':'751 Thames Street, Juarez, American Samoa, 8386','about':'Enim voluptate et non est in magna laborum aliqua enim aliqua est non nostrud. Tempor est nulla ipsum consectetur esse nostrud est id. Consequat do voluptate cupidatat eu fugiat et fugiat velit id. Sint dolore ad qui tempor anim eu amet consectetur do elit aute adipisicing consequat ex.','registered':'Sunday, October 22, 2017 7:35 AM','latitude':'84.384911','longitude':'40.305648','tags':['tempor','sint','irure','et','ex'],'greeting':'Hello, Jill! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed713fe676575aa72b','index':10,'guid':'c28023cf-cc57-4c2e-8d91-dfbe6bafadcd','isActive':false,'balance':'$2,792.45','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Hurley','last':'George'},'company':'ZAJ','email':'hurley.george@zaj.tv','phone':'+1 (984) 547-3284','address':'727 Minna Street, Lacomb, Colorado, 2557','about':'Ex velit cupidatat veniam culpa. Eiusmod ut fugiat adipisicing incididunt consectetur exercitation Lorem exercitation ex. Incididunt anim aute incididunt fugiat cupidatat qui eu non reprehenderit. Eiusmod dolor nisi culpa excepteur ut velit minim dolor voluptate amet commodo culpa in.','registered':'Thursday, February 16, 2017 6:41 AM','latitude':'25.989949','longitude':'10.200053','tags':['minim','ut','sunt','consequat','ullamco'],'greeting':'Hello, Hurley! You have 8 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1e56732746c70d8b','index':11,'guid':'e9766f13-766c-4450-b4d2-8b04580f60b7','isActive':true,'balance':'$3,874.26','picture':'http://placehold.it/32x32','age':35,'eyeColor':'green','name':{'first':'Leticia','last':'Pace'},'company':'HONOTRON','email':'leticia.pace@honotron.co.uk','phone':'+1 (974) 536-3322','address':'365 Goodwin Place, Savage, Nevada, 9191','about':'Nisi Lorem aliqua esse eiusmod magna. Ad minim incididunt proident ut Lorem cupidatat qui velit aliqua ullamco et ipsum in. Aliquip elit consectetur pariatur esse exercitation et officia quis. Occaecat tempor proident cillum anim ad commodo velit ut voluptate. Tempor et occaecat sit sint aliquip tempor nulla velit magna nisi proident exercitation Lorem id.','registered':'Saturday, August 4, 2018 5:05 AM','latitude':'70.620386','longitude':'-86.335813','tags':['occaecat','velit','labore','laboris','esse'],'greeting':'Hello, Leticia! You have 8 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed941337fe42f47426','index':12,'guid':'6d390762-17ea-4b58-9a36-b0c9a8748a42','isActive':true,'balance':'$1,049.61','picture':'http://placehold.it/32x32','age':38,'eyeColor':'green','name':{'first':'Rose','last':'Humphrey'},'company':'MYOPIUM','email':'rose.humphrey@myopium.io','phone':'+1 (828) 426-3086','address':'389 Sapphire Street, Saticoy, Marshall Islands, 1423','about':'Aliquip enim excepteur adipisicing ex. Consequat aliqua consequat nostrud do occaecat deserunt excepteur sit et ipsum sunt dolor eu. Dolore laborum commodo excepteur tempor ad adipisicing proident excepteur magna non Lorem proident consequat aute. Fugiat minim consequat occaecat voluptate esse velit officia laboris nostrud nisi ut voluptate.','registered':'Monday, April 16, 2018 12:38 PM','latitude':'-47.083742','longitude':'109.022423','tags':['aute','non','sit','adipisicing','mollit'],'greeting':'Hello, Rose! You have 9 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd0c02fc3fdc01a40','index':13,'guid':'07755618-6fdf-4b33-af50-364c18909227','isActive':true,'balance':'$1,823.61','picture':'http://placehold.it/32x32','age':36,'eyeColor':'green','name':{'first':'Judith','last':'Hale'},'company':'COLLAIRE','email':'judith.hale@collaire.me','phone':'+1 (922) 508-2843','address':'193 Coffey Street, Castleton, North Dakota, 3638','about':'Minim non ullamco ad anim nostrud dolore nostrud veniam consequat id eiusmod veniam laboris. Lorem irure esse mollit non velit aute id cupidatat est mollit occaecat magna excepteur. Adipisicing tempor nisi sit aliquip tempor pariatur tempor eu consectetur nulla amet nulla. Quis nisi nisi ea incididunt culpa et do. Esse officia eu pariatur velit sunt quis proident amet consectetur consequat. Nisi excepteur culpa nulla sit dolor deserunt excepteur dolor consequat elit cillum tempor Lorem.','registered':'Wednesday, August 24, 2016 12:29 AM','latitude':'-80.15514','longitude':'39.91007','tags':['consectetur','incididunt','aliquip','dolor','consequat'],'greeting':'Hello, Judith! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edb3e1e29caa4f728b','index':14,'guid':'2c6617a2-e7a9-4ff7-a8b9-e99554fe70fe','isActive':true,'balance':'$1,971.00','picture':'http://placehold.it/32x32','age':39,'eyeColor':'blue','name':{'first':'Estes','last':'Sweet'},'company':'GEEKKO','email':'estes.sweet@geekko.com','phone':'+1 (866) 448-3032','address':'847 Cove Lane, Kula, Mississippi, 9178','about':'Veniam consectetur occaecat est excepteur consequat ipsum cillum sit consectetur. Ut cupidatat et reprehenderit dolore enim do cillum qui pariatur ad laborum incididunt esse. Fugiat sunt dolor veniam laboris ipsum deserunt proident reprehenderit laboris non nostrud. Magna excepteur sint magna laborum tempor sit exercitation ipsum labore est ullamco ullamco. Cillum voluptate cillum ea laborum Lorem. Excepteur sint ut nisi est esse non. Minim excepteur ullamco velit nisi ut in elit exercitation ut dolore.','registered':'Sunday, August 12, 2018 5:06 PM','latitude':'-9.57771','longitude':'-159.94577','tags':['culpa','dolor','velit','anim','pariatur'],'greeting':'Hello, Estes! You have 7 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edbcf088c6fd593091','index':15,'guid':'2cc79958-1b40-4e2c-907a-433903fd3da9','isActive':false,'balance':'$3,751.53','picture':'http://placehold.it/32x32','age':34,'eyeColor':'brown','name':{'first':'Kemp','last':'Spence'},'company':'EXOBLUE','email':'kemp.spence@exoblue.org','phone':'+1 (864) 487-2992','address':'217 Clay Street, Monument, North Carolina, 1460','about':'Nostrud duis cillum sint non commodo dolor aute aliqua adipisicing ad nulla non excepteur proident. Fugiat labore elit tempor cillum veniam reprehenderit laboris consectetur dolore amet qui cupidatat. Amet aliqua elit anim et consequat commodo excepteur officia anim aliqua ea eu labore cillum. Et ex dolor duis dolore commodo veniam et nisi.','registered':'Monday, October 29, 2018 5:23 AM','latitude':'-70.304222','longitude':'83.582371','tags':['velit','duis','consequat','incididunt','duis'],'greeting':'Hello, Kemp! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed6400479feb3de505','index':16,'guid':'91ccae6d-a3ea-43cf-bb00-3f2729256cc9','isActive':false,'balance':'$2,477.79','picture':'http://placehold.it/32x32','age':40,'eyeColor':'blue','name':{'first':'Ronda','last':'Burris'},'company':'EQUITOX','email':'ronda.burris@equitox.net','phone':'+1 (817) 553-3228','address':'708 Lawton Street, Deputy, Wyoming, 8598','about':'Excepteur voluptate aliquip consequat cillum est duis sit cillum eu eiusmod et laborum ullamco. Et minim reprehenderit aute voluptate amet ullamco. Amet sit enim ad irure deserunt nostrud anim veniam consequat dolor commodo. Consequat do occaecat do exercitation ullamco dolor ut. Id laboris consequat est dolor dolore tempor ullamco anim do ut nulla deserunt labore. Mollit ex Lorem ullamco mollit.','registered':'Monday, April 23, 2018 5:27 PM','latitude':'-31.227208','longitude':'0.63785','tags':['ipsum','magna','consectetur','sit','irure'],'greeting':'Hello, Ronda! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eddbeab2e53e04d563','index':17,'guid':'a86d4eb6-6bd8-48c2-a8fc-1c933c835852','isActive':false,'balance':'$3,709.03','picture':'http://placehold.it/32x32','age':37,'eyeColor':'blue','name':{'first':'Rosario','last':'Dillard'},'company':'BARKARAMA','email':'rosario.dillard@barkarama.name','phone':'+1 (933) 525-3898','address':'730 Chauncey Street, Forbestown, South Carolina, 6894','about':'Est eu fugiat aliquip ea ad qui ad mollit ad tempor voluptate et incididunt reprehenderit. Incididunt fugiat commodo minim adipisicing culpa consectetur duis eu ut commodo consequat voluptate labore. Nostrud irure labore adipisicing irure quis magna consequat dolor Lorem sint enim. Sint excepteur eu dolore elit ut do mollit sunt enim est. Labore id nostrud sint Lorem esse nostrud.','registered':'Friday, December 25, 2015 8:59 PM','latitude':'37.440827','longitude':'44.580474','tags':['Lorem','sit','ipsum','ea','ut'],'greeting':'Hello, Rosario! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eddf8e9b9c031d04e8','index':18,'guid':'a96f997c-daf8-40d4-92e1-be07e2cf0f60','isActive':false,'balance':'$1,878.37','picture':'http://placehold.it/32x32','age':37,'eyeColor':'brown','name':{'first':'Sondra','last':'Gonzales'},'company':'XUMONK','email':'sondra.gonzales@xumonk.us','phone':'+1 (838) 560-2255','address':'230 Cox Place, Geyserville, Georgia, 6805','about':'Laborum sunt voluptate ea laboris nostrud. Amet deserunt aliqua Lorem voluptate velit deserunt occaecat minim ullamco. Lorem occaecat sit labore adipisicing ad magna mollit labore ullamco proident. Ea velit do proident fugiat esse commodo ex nostrud eu mollit pariatur. Labore laborum qui voluptate quis proident reprehenderit tempor dolore duis deserunt esse aliqua aliquip. Non veniam enim pariatur cupidatat ipsum dolore est reprehenderit. Non exercitation adipisicing proident magna elit occaecat non magna.','registered':'Sunday, June 26, 2016 4:02 AM','latitude':'62.247742','longitude':'-44.90666','tags':['ea','aute','in','voluptate','magna'],'greeting':'Hello, Sondra! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed2c1bcd06781f677e','index':19,'guid':'6ac47a16-eed4-4460-92ee-e0dd33c1fbb5','isActive':false,'balance':'$3,730.64','picture':'http://placehold.it/32x32','age':20,'eyeColor':'brown','name':{'first':'Anastasia','last':'Vega'},'company':'FIREWAX','email':'anastasia.vega@firewax.biz','phone':'+1 (867) 493-3698','address':'803 Arlington Avenue, Rosburg, Northern Mariana Islands, 8769','about':'Sint ex nisi tempor sunt voluptate non et eiusmod irure. Aute reprehenderit dolor mollit aliqua Lorem voluptate occaecat. Sint laboris deserunt Lorem incididunt nulla cupidatat do.','registered':'Friday, March 18, 2016 12:02 PM','latitude':'-32.010216','longitude':'-87.874753','tags':['aliquip','mollit','mollit','ad','laborum'],'greeting':'Hello, Anastasia! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed727fd645854bbf43','index':20,'guid':'67bd8cdb-ce6b-455c-944c-a80e17c6fa75','isActive':true,'balance':'$2,868.06','picture':'http://placehold.it/32x32','age':29,'eyeColor':'green','name':{'first':'Lucinda','last':'Cox'},'company':'ENDIPINE','email':'lucinda.cox@endipine.ca','phone':'+1 (990) 428-3002','address':'412 Thatford Avenue, Lafferty, New Jersey, 5271','about':'Esse nulla sunt ut consequat aute mollit. Est occaecat sunt nisi irure id anim est commodo. Elit mollit amet dolore sunt adipisicing ea laborum quis ea reprehenderit non consequat dolore. Minim sunt occaecat quis aute commodo dolore quis commodo proident. Sunt sint duis ullamco sit ea esse Lorem. Consequat pariatur eiusmod laboris adipisicing labore in laboris adipisicing adipisicing consequat aute ea et.','registered':'Friday, May 1, 2015 10:16 PM','latitude':'-14.200957','longitude':'-82.211386','tags':['do','sit','qui','officia','aliquip'],'greeting':'Hello, Lucinda! You have 9 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed5a97284eb2cbd3a8','index':21,'guid':'f9fc999d-515c-4fc4-b339-76300e1b4bf2','isActive':true,'balance':'$1,172.57','picture':'http://placehold.it/32x32','age':35,'eyeColor':'brown','name':{'first':'Conrad','last':'Bradley'},'company':'FUELWORKS','email':'conrad.bradley@fuelworks.info','phone':'+1 (956) 561-3226','address':'685 Fenimore Street, Esmont, Maryland, 7523','about':'Labore reprehenderit anim nisi sunt do nisi in. Est anim cillum id minim exercitation ullamco voluptate ipsum eu. Elit culpa consequat reprehenderit laborum in eu. Laboris amet voluptate laboris qui voluptate duis minim reprehenderit. Commodo sunt irure dolore sunt occaecat velit nisi eu minim minim.','registered':'Wednesday, January 18, 2017 11:13 PM','latitude':'31.665993','longitude':'38.868968','tags':['excepteur','exercitation','est','nisi','mollit'],'greeting':'Hello, Conrad! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edc4eaf6f760c38218','index':22,'guid':'8794ef5f-da2f-46f0-a755-c18a16409fd5','isActive':false,'balance':'$3,594.73','picture':'http://placehold.it/32x32','age':27,'eyeColor':'blue','name':{'first':'Marquez','last':'Vargas'},'company':'MALATHION','email':'marquez.vargas@malathion.tv','phone':'+1 (976) 438-3126','address':'296 Hall Street, National, Texas, 2067','about':'Proident cillum aute minim fugiat sunt aliqua non occaecat est duis id id tempor. Qui deserunt nisi amet pariatur proident eu laboris esse adipisicing magna. Anim anim mollit aute non magna nisi aute magna labore ullamco reprehenderit voluptate et ad. Proident adipisicing aute eiusmod nostrud nostrud deserunt culpa. Elit eu ullamco nisi aliqua dolor sint pariatur excepteur sit consectetur tempor. Consequat Lorem ullamco commodo veniam qui sint magna. Sit mollit ad aliquip est id eu officia id adipisicing duis ad.','registered':'Tuesday, November 17, 2015 6:16 PM','latitude':'-36.443667','longitude':'22.336776','tags':['aliquip','veniam','ipsum','Lorem','ex'],'greeting':'Hello, Marquez! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edd7c718518ee0466a','index':23,'guid':'ad8781a2-059e-4288-9879-309d53a99bf5','isActive':true,'balance':'$3,570.68','picture':'http://placehold.it/32x32','age':21,'eyeColor':'brown','name':{'first':'Snider','last':'Frost'},'company':'ZILODYNE','email':'snider.frost@zilodyne.co.uk','phone':'+1 (913) 485-3275','address':'721 Lincoln Road, Richmond, Utah, 672','about':'Minim enim Lorem esse incididunt do reprehenderit velit laborum ullamco. In aute eiusmod esse aliqua et labore tempor sunt ex mollit veniam tempor. Nulla elit cillum qui ullamco dolore amet deserunt magna amet laborum.','registered':'Saturday, August 23, 2014 12:58 AM','latitude':'-88.682554','longitude':'74.063179','tags':['nulla','ea','sint','aliquip','duis'],'greeting':'Hello, Snider! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edf026fece8e2c0970','index':24,'guid':'1b7d81e1-1dba-4322-bb1a-eaa6a24cccea','isActive':false,'balance':'$2,037.91','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Snyder','last':'Fletcher'},'company':'COMTEST','email':'snyder.fletcher@comtest.io','phone':'+1 (830) 538-3860','address':'221 Lewis Place, Zortman, Idaho, 572','about':'Elit anim enim esse dolore exercitation. Laboris esse sint adipisicing fugiat sint do occaecat ut voluptate sint nulla. Ad sint ut reprehenderit nostrud irure id consectetur officia velit consequat.','registered':'Sunday, January 1, 2017 1:13 AM','latitude':'-54.742604','longitude':'69.534932','tags':['exercitation','commodo','in','id','aliqua'],'greeting':'Hello, Snyder! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed4b9a7f83da6d2dfd','index':25,'guid':'0b2cc6b6-0044-4b1c-aa31-bd72963457a0','isActive':false,'balance':'$1,152.76','picture':'http://placehold.it/32x32','age':27,'eyeColor':'blue','name':{'first':'Regina','last':'James'},'company':'TELPOD','email':'regina.james@telpod.me','phone':'+1 (989) 455-3228','address':'688 Essex Street, Clayville, Alabama, 2772','about':'Eiusmod elit culpa reprehenderit ea veniam. Officia irure culpa duis aute ut. Irure duis cillum officia ea pariatur velit ut dolor incididunt reprehenderit ex elit laborum. Est pariatur veniam ad irure. Labore velit sunt esse laboris aliqua velit deserunt deserunt sit. Elit eiusmod ad laboris aliquip minim irure excepteur enim quis. Quis incididunt adipisicing ut magna cupidatat sit amet culpa.','registered':'Tuesday, April 25, 2017 10:16 PM','latitude':'-75.088027','longitude':'47.209828','tags':['elit','nisi','est','voluptate','proident'],'greeting':'Hello, Regina! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed10884f32f779f2bf','index':26,'guid':'1f6fb522-0002-46ff-8dac-451247f28168','isActive':true,'balance':'$1,948.79','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Collins','last':'Mcpherson'},'company':'DIGIGEN','email':'collins.mcpherson@digigen.com','phone':'+1 (991) 519-2334','address':'317 Merit Court, Sanford, Michigan, 6468','about':'Magna qui culpa dolor officia labore mollit ex excepteur duis eiusmod. Ea cupidatat ex ipsum mollit do minim duis. Nisi eiusmod minim tempor id esse commodo sunt sunt ullamco ut do laborum ullamco magna. Aliquip laborum dolor officia officia eu nostrud velit minim est anim. Ex elit laborum sunt magna exercitation nisi cillum sunt aute qui ea ullamco. Cupidatat ea sunt aute dolor duis nisi Lorem ullamco eiusmod. Sit ea velit ad veniam aliqua ad elit cupidatat ut magna in.','registered':'Friday, June 10, 2016 4:38 PM','latitude':'25.513996','longitude':'14.911124','tags':['exercitation','non','sit','velit','officia'],'greeting':'Hello, Collins! You have 5 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed8a575110efb15c6c','index':27,'guid':'2a904c82-068b-4ded-9ae6-cfeb6d7e62c9','isActive':true,'balance':'$3,427.91','picture':'http://placehold.it/32x32','age':24,'eyeColor':'green','name':{'first':'Mckay','last':'Barrera'},'company':'COMVEYER','email':'mckay.barrera@comveyer.org','phone':'+1 (853) 470-2560','address':'907 Glenwood Road, Churchill, Oregon, 8583','about':'In voluptate esse dolore enim sint quis dolor do exercitation sint et labore nisi. Eiusmod tempor exercitation dolore elit sit velit sint et. Sit magna adipisicing eiusmod do anim velit deserunt laboris ad ea pariatur. Irure nisi anim mollit elit commodo nulla. Aute eiusmod sit nulla eiusmod. Eiusmod est officia commodo mollit laboris do deserunt eu do nisi amet. Proident ad duis eiusmod laboris Lorem ut culpa pariatur Lorem reprehenderit minim aliquip irure sunt.','registered':'Saturday, December 19, 2015 2:49 PM','latitude':'-55.243287','longitude':'138.035406','tags':['non','quis','laboris','enim','nisi'],'greeting':'Hello, Mckay! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edcd49ab6a73ff7f32','index':28,'guid':'5d3e0dae-3f58-437f-b12d-de24667a904d','isActive':true,'balance':'$3,270.52','picture':'http://placehold.it/32x32','age':35,'eyeColor':'blue','name':{'first':'Mabel','last':'Leonard'},'company':'QUADEEBO','email':'mabel.leonard@quadeebo.net','phone':'+1 (805) 432-2356','address':'965 Underhill Avenue, Falconaire, Minnesota, 4450','about':'Cupidatat amet sunt est ipsum occaecat sit fugiat excepteur Lorem Lorem ex ea ipsum. Ad incididunt est irure magna excepteur occaecat nostrud. Minim dolor id anim ipsum qui nostrud ullamco aute ex Lorem magna deserunt excepteur Lorem.','registered':'Saturday, March 28, 2015 5:55 AM','latitude':'27.388359','longitude':'156.408728','tags':['quis','velit','deserunt','dolore','sit'],'greeting':'Hello, Mabel! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edde16ac2dc2fbb6c1','index':29,'guid':'d50c2233-70fc-4748-8ebf-02d45ac2a446','isActive':false,'balance':'$3,100.70','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Pace','last':'Duke'},'company':'SEQUITUR','email':'pace.duke@sequitur.name','phone':'+1 (983) 568-3119','address':'895 Melrose Street, Reno, Connecticut, 6259','about':'Ex veniam aliquip exercitation mollit elit est minim veniam aliqua labore deserunt. Dolor sunt sint cillum Lorem nisi ea irure cupidatat. Velit ut culpa cupidatat consequat cillum. Sint voluptate quis laboris qui incididunt do elit Lorem qui ullamco ut eu pariatur occaecat.','registered':'Saturday, August 18, 2018 2:18 PM','latitude':'31.930443','longitude':'-129.494784','tags':['culpa','est','nostrud','quis','aliquip'],'greeting':'Hello, Pace! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edb908d85642ba77e8','index':30,'guid':'3edb6e42-367a-403d-a511-eb78bcc11f60','isActive':true,'balance':'$1,912.07','picture':'http://placehold.it/32x32','age':24,'eyeColor':'green','name':{'first':'Cohen','last':'Morrison'},'company':'POWERNET','email':'cohen.morrison@powernet.us','phone':'+1 (888) 597-2141','address':'565 Troutman Street, Idledale, West Virginia, 3196','about':'Ullamco voluptate duis commodo amet occaecat consequat et occaecat dolore nulla eu. Do aliqua sunt deserunt occaecat laboris labore voluptate cupidatat ullamco exercitation aliquip elit voluptate anim. Occaecat deserunt in labore cillum aute deserunt ea excepteur laboris sunt. Officia irure sint incididunt labore sint ipsum ullamco ea elit. Fugiat nostrud sunt ut officia mollit proident sunt dolor fugiat esse tempor do.','registered':'Friday, January 1, 2016 5:42 AM','latitude':'-20.01215','longitude':'26.361552','tags':['consectetur','sunt','nulla','reprehenderit','dolore'],'greeting':'Hello, Cohen! You have 10 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed91c77aa25a64a757','index':31,'guid':'8999a97b-0035-4f19-b555-91dd69aaa9b8','isActive':false,'balance':'$3,097.67','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Stout','last':'Valdez'},'company':'UPLINX','email':'stout.valdez@uplinx.biz','phone':'+1 (854) 480-3633','address':'880 Chestnut Avenue, Lowgap, Hawaii, 1537','about':'Cupidatat enim dolore non voluptate. Aliqua ut non Lorem in exercitation reprehenderit voluptate. Excepteur deserunt tempor laboris quis.','registered':'Wednesday, March 16, 2016 6:53 AM','latitude':'50.328393','longitude':'-25.990308','tags':['ea','fugiat','duis','consectetur','enim'],'greeting':'Hello, Stout! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed0f52176c8c3e1bed','index':32,'guid':'743abcbd-1fab-4aed-8cb7-3c935eb64c74','isActive':false,'balance':'$1,118.54','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Ortega','last':'Joseph'},'company':'APEXIA','email':'ortega.joseph@apexia.ca','phone':'+1 (872) 596-3024','address':'304 Canda Avenue, Mulino, New York, 8721','about':'Ipsum elit id cupidatat minim nisi minim. Ea ex amet ea ipsum Lorem deserunt. Occaecat cupidatat magna cillum aliquip sint id quis amet nostrud officia enim laborum. Aliqua deserunt amet commodo laboris labore mollit est. Officia voluptate Lorem esse mollit aliquip laboris cupidatat minim et. Labore esse incididunt officia nostrud pariatur reprehenderit.','registered':'Tuesday, January 31, 2017 6:06 AM','latitude':'43.861714','longitude':'33.771783','tags':['ut','Lorem','esse','quis','fugiat'],'greeting':'Hello, Ortega! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed2c00cdd101b6cd52','index':33,'guid':'4f6f99cf-f692-4d03-b23a-26f2b27273bd','isActive':true,'balance':'$1,682.91','picture':'http://placehold.it/32x32','age':20,'eyeColor':'blue','name':{'first':'Sampson','last':'Taylor'},'company':'GEOFORMA','email':'sampson.taylor@geoforma.info','phone':'+1 (911) 482-2993','address':'582 Kent Street, Umapine, Virgin Islands, 5300','about':'Voluptate laboris occaecat laboris tempor cillum quis cupidatat qui pariatur. Lorem minim commodo mollit adipisicing Lorem ut dolor consectetur ipsum. Sint sit voluptate labore aliqua ex labore velit. Ullamco tempor consectetur voluptate deserunt voluptate minim enim. Cillum commodo duis reprehenderit eu duis.','registered':'Thursday, November 9, 2017 11:24 PM','latitude':'24.949379','longitude':'155.034468','tags':['Lorem','cupidatat','elit','reprehenderit','commodo'],'greeting':'Hello, Sampson! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed4b7210ba0bc0d508','index':34,'guid':'73fd415f-f8cf-43e0-a86c-e725d000abd4','isActive':false,'balance':'$1,289.37','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Shari','last':'Melendez'},'company':'DIGIPRINT','email':'shari.melendez@digiprint.tv','phone':'+1 (914) 475-3995','address':'950 Wolf Place, Enetai, Alaska, 693','about':'Dolor incididunt et est commodo aliquip labore ad ullamco. Velit ex cillum nulla elit ex esse. Consectetur mollit fugiat cillum proident elit sunt non officia cillum ex laboris sint eu. Esse nulla eu officia in Lorem sint minim esse velit. Est Lorem ipsum enim aute. Elit minim eiusmod officia reprehenderit officia ut irure Lorem.','registered':'Wednesday, August 23, 2017 11:12 PM','latitude':'-70.347863','longitude':'94.812072','tags':['ea','ex','fugiat','duis','eu'],'greeting':'Hello, Shari! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed85ac364619d892ef','index':35,'guid':'c1905f34-14ff-4bd8-b683-02cac4d52623','isActive':false,'balance':'$2,538.50','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Santiago','last':'Joyner'},'company':'BRAINCLIP','email':'santiago.joyner@brainclip.co.uk','phone':'+1 (835) 405-2676','address':'554 Rose Street, Muir, Kentucky, 7752','about':'Quis culpa dolore fugiat magna culpa non deserunt consectetur elit. Id cupidatat occaecat duis irure ullamco elit in labore magna pariatur cillum est. Mollit dolore velit ipsum anim aliqua culpa sint. Occaecat aute anim ut sunt eu.','registered':'Thursday, January 18, 2018 4:49 PM','latitude':'57.057918','longitude':'-50.472596','tags':['ullamco','ullamco','sunt','voluptate','irure'],'greeting':'Hello, Santiago! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1763f56b1121fa88','index':36,'guid':'a7f50659-4ae3-4f3e-a9d8-087e05334b51','isActive':false,'balance':'$1,435.16','picture':'http://placehold.it/32x32','age':37,'eyeColor':'blue','name':{'first':'Adeline','last':'Hoffman'},'company':'BITREX','email':'adeline.hoffman@bitrex.io','phone':'+1 (823) 488-3201','address':'221 Corbin Place, Edmund, Palau, 193','about':'Magna ullamco consectetur velit adipisicing cillum ea. Est qui incididunt est ullamco ex aute exercitation irure. Cupidatat consectetur proident qui fugiat do. Labore magna aliqua consectetur fugiat. Excepteur deserunt sit qui dolor fugiat aute sunt anim ipsum magna ea commodo qui. Minim eu adipisicing ut irure excepteur eiusmod aliqua. Voluptate nisi ad consequat qui.','registered':'Tuesday, June 14, 2016 9:26 AM','latitude':'-53.123355','longitude':'88.180776','tags':['non','est','commodo','ut','aliquip'],'greeting':'Hello, Adeline! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed945d079f63e3185e','index':37,'guid':'1f4619e0-9289-4bea-a9db-a75f4cba1138','isActive':true,'balance':'$2,019.54','picture':'http://placehold.it/32x32','age':36,'eyeColor':'blue','name':{'first':'Porter','last':'Morse'},'company':'COMVOY','email':'porter.morse@comvoy.me','phone':'+1 (933) 562-3220','address':'416 India Street, Bourg, Rhode Island, 2266','about':'Et sint anim et sunt. Non mollit sunt cillum veniam sunt sint amet non mollit. Fugiat ea ullamco pariatur deserunt ex do minim irure irure.','registered':'Saturday, July 16, 2016 10:03 PM','latitude':'-81.782545','longitude':'69.783509','tags':['irure','consequat','veniam','nulla','velit'],'greeting':'Hello, Porter! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed411dd0f06c66bba6','index':38,'guid':'93c900f0-54c0-4c4c-b21d-d59d8d7c6177','isActive':true,'balance':'$3,764.84','picture':'http://placehold.it/32x32','age':26,'eyeColor':'green','name':{'first':'Fitzgerald','last':'Logan'},'company':'UTARIAN','email':'fitzgerald.logan@utarian.com','phone':'+1 (815) 461-2709','address':'498 Logan Street, Tonopah, Arkansas, 6652','about':'Quis Lorem sit est et dolor est esse in veniam. Mollit anim nostrud laboris consequat voluptate qui ad ipsum sint laborum exercitation quis ipsum. Incididunt cupidatat esse ea amet deserunt consequat eu proident duis adipisicing pariatur. Amet deserunt mollit aliquip mollit consequat sunt quis labore laboris quis. Magna cillum fugiat anim velit Lorem duis. Lorem duis amet veniam occaecat est excepteur ut ea velit esse non pariatur. Do veniam quis eu consequat ad duis incididunt minim dolore sit non minim adipisicing et.','registered':'Wednesday, August 9, 2017 9:20 PM','latitude':'24.480657','longitude':'-108.693421','tags':['dolore','ad','occaecat','quis','labore'],'greeting':'Hello, Fitzgerald! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edbb6f14559d8a7b28','index':39,'guid':'9434f48b-70a0-4161-8d06-c53bf8b9df94','isActive':true,'balance':'$3,713.47','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Mcconnell','last':'Nash'},'company':'TETAK','email':'mcconnell.nash@tetak.org','phone':'+1 (956) 477-3586','address':'853 Turnbull Avenue, Clarence, Missouri, 1599','about':'Culpa excepteur minim anim magna dolor dolore ad ex eu. In cupidatat cillum elit dolore in est minim dolore consectetur reprehenderit voluptate laborum. Deserunt id velit ad dolor mollit.','registered':'Saturday, November 10, 2018 9:27 AM','latitude':'1.691589','longitude':'143.704377','tags':['ut','deserunt','sit','cupidatat','ea'],'greeting':'Hello, Mcconnell! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed1a87ea0390733ffa','index':40,'guid':'ec8a55f7-7114-4787-b1ff-4e631731bc2c','isActive':true,'balance':'$2,200.71','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Kitty','last':'Meyers'},'company':'FIBEROX','email':'kitty.meyers@fiberox.net','phone':'+1 (864) 458-3826','address':'537 Georgia Avenue, Thermal, Illinois, 7930','about':'Non excepteur laboris Lorem magna adipisicing exercitation. Anim esse in pariatur minim ipsum qui voluptate irure. Pariatur Lorem pariatur esse commodo aute adipisicing anim commodo. Exercitation nostrud aliqua duis et amet amet tempor.','registered':'Tuesday, September 13, 2016 8:16 PM','latitude':'19.59506','longitude':'-57.814297','tags':['duis','ullamco','velit','sint','consequat'],'greeting':'Hello, Kitty! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed4dc76717bf1217b3','index':41,'guid':'40521cde-f835-4620-902b-af7abf185d8d','isActive':false,'balance':'$2,907.02','picture':'http://placehold.it/32x32','age':26,'eyeColor':'green','name':{'first':'Klein','last':'Goodwin'},'company':'PLASTO','email':'klein.goodwin@plasto.name','phone':'+1 (950) 563-3104','address':'764 Devoe Street, Lindcove, Oklahoma, 458','about':'Amet aliqua magna ea veniam non aliquip irure esse id ipsum cillum sint tempor dolor. Ullamco deserunt fugiat amet pariatur culpa nostrud commodo commodo. Ad occaecat magna adipisicing voluptate. Minim ad adipisicing cupidatat elit nostrud eu irure. Cupidatat occaecat aute magna consectetur dolore anim et. Ex voluptate velit exercitation laborum ad ullamco ad. Aliquip nulla ipsum dolore cillum qui nostrud eu adipisicing amet tempor do.','registered':'Tuesday, February 13, 2018 3:56 PM','latitude':'-27.168725','longitude':'-29.499285','tags':['minim','labore','do','deserunt','dolor'],'greeting':'Hello, Klein! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1ac77396b29aee9e','index':42,'guid':'7cfc03e3-30e9-4ae1-a1f5-f6c3223ca770','isActive':true,'balance':'$2,986.47','picture':'http://placehold.it/32x32','age':22,'eyeColor':'brown','name':{'first':'Isabelle','last':'Bishop'},'company':'GEEKNET','email':'isabelle.bishop@geeknet.us','phone':'+1 (908) 418-2642','address':'729 Willmohr Street, Aguila, Montana, 7510','about':'In nulla commodo nostrud sint. Elit et occaecat et aliqua aliquip magna esse commodo duis Lorem dolor magna enim deserunt. Ipsum pariatur reprehenderit ipsum adipisicing mollit incididunt ut. Sunt in consequat ex ut minim non qui anim labore. Deserunt minim voluptate in nulla occaecat.','registered':'Monday, September 15, 2014 6:22 AM','latitude':'-81.686947','longitude':'38.409291','tags':['proident','est','aliqua','veniam','anim'],'greeting':'Hello, Isabelle! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edb3a070c9469a4893','index':43,'guid':'3dec76b4-0b55-4765-a2fd-b8dbd9c82f8f','isActive':true,'balance':'$2,501.24','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Josefina','last':'Turner'},'company':'COMSTAR','email':'josefina.turner@comstar.biz','phone':'+1 (908) 566-3029','address':'606 Schenck Place, Brutus, Vermont, 8681','about':'Enim consectetur pariatur sint dolor nostrud est deserunt nulla quis pariatur sit. Ad aute incididunt nisi excepteur duis est velit voluptate ullamco occaecat magna reprehenderit aliquip. Proident deserunt consectetur non et exercitation elit dolore enim aliqua incididunt anim amet. Ex esse sint commodo minim aliqua ut irure. Proident ex culpa voluptate fugiat nisi. Sint commodo laboris excepteur minim ipsum labore tempor quis magna.','registered':'Saturday, December 31, 2016 6:38 AM','latitude':'35.275088','longitude':'24.30485','tags':['minim','ut','irure','Lorem','veniam'],'greeting':'Hello, Josefina! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1aa7d74128ee3d0f','index':44,'guid':'10599279-c367-46c4-9f7a-744c2e4bf6c9','isActive':true,'balance':'$1,753.06','picture':'http://placehold.it/32x32','age':27,'eyeColor':'blue','name':{'first':'Lily','last':'Haynes'},'company':'KIOSK','email':'lily.haynes@kiosk.ca','phone':'+1 (872) 451-2301','address':'509 Balfour Place, Grazierville, New Hampshire, 2750','about':'Nisi aliquip occaecat nostrud do sint qui nisi officia Lorem. Ad et et laboris nisi dolore aliqua eu. Aliqua veniam quis eu pariatur incididunt mollit id deserunt officia eiusmod. Consequat adipisicing do nisi voluptate eiusmod minim pariatur minim nisi nostrud culpa cupidatat. Irure consectetur id consequat adipisicing ullamco occaecat do. Ex proident ea quis nulla incididunt sunt excepteur incididunt. Aliquip minim nostrud non anim Lorem.','registered':'Tuesday, November 20, 2018 9:28 AM','latitude':'-12.677798','longitude':'114.506787','tags':['culpa','amet','elit','officia','irure'],'greeting':'Hello, Lily! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed74c76f2e84e201ce','index':45,'guid':'ec0a68d4-629e-46c9-9af7-f6ea867f02ba','isActive':true,'balance':'$1,477.93','picture':'http://placehold.it/32x32','age':23,'eyeColor':'green','name':{'first':'Shauna','last':'Pitts'},'company':'SPACEWAX','email':'shauna.pitts@spacewax.info','phone':'+1 (841) 406-2360','address':'348 Tabor Court, Westwood, Puerto Rico, 8297','about':'Aliquip irure officia magna ea magna mollit ea non amet deserunt. Veniam mollit labore culpa magna aliqua quis consequat est consectetur ea reprehenderit nostrud consequat aliqua. Mollit do ipsum mollit eiusmod.','registered':'Thursday, October 2, 2014 2:48 AM','latitude':'-55.17388','longitude':'-13.370494','tags':['anim','consectetur','cillum','veniam','duis'],'greeting':'Hello, Shauna! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed419e718484b16722','index':46,'guid':'b2d6101d-5646-43f4-8207-284494e5a990','isActive':false,'balance':'$2,006.96','picture':'http://placehold.it/32x32','age':27,'eyeColor':'brown','name':{'first':'Lawrence','last':'Boyer'},'company':'SKYPLEX','email':'lawrence.boyer@skyplex.tv','phone':'+1 (953) 548-2618','address':'464 Pilling Street, Blandburg, Arizona, 5531','about':'Culpa sit minim pariatur mollit cupidatat sunt duis. Nisi ea proident veniam exercitation adipisicing Lorem aliquip amet dolor voluptate in nisi. Non commodo anim sunt est fugiat laborum nisi aliqua non Lorem exercitation dolor. Laboris dolore do minim ut eiusmod enim magna cillum laborum consectetur aliquip minim enim Lorem. Veniam ex veniam occaecat aliquip elit aliquip est eiusmod minim minim adipisicing.','registered':'Wednesday, July 30, 2014 2:17 AM','latitude':'-78.681255','longitude':'139.960626','tags':['consequat','Lorem','incididunt','dolor','esse'],'greeting':'Hello, Lawrence! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed08a9024998292c70','index':47,'guid':'277de142-ebeb-4828-906a-7fd8bc0a738a','isActive':true,'balance':'$1,273.19','picture':'http://placehold.it/32x32','age':27,'eyeColor':'brown','name':{'first':'Sonya','last':'Stafford'},'company':'AQUACINE','email':'sonya.stafford@aquacine.co.uk','phone':'+1 (824) 581-3927','address':'641 Bowery Street, Hillsboro, Delaware, 7893','about':'Culpa labore ex reprehenderit mollit cupidatat dolore et ut quis in. Sint esse culpa enim culpa tempor exercitation veniam minim consectetur. Sunt est laboris minim quis incididunt exercitation laboris cupidatat fugiat ad. Deserunt ipsum do dolor cillum excepteur incididunt.','registered':'Thursday, March 26, 2015 1:10 PM','latitude':'-84.750592','longitude':'165.493533','tags':['minim','officia','dolore','ipsum','est'],'greeting':'Hello, Sonya! You have 8 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd5037f2c79ecde68','index':48,'guid':'2dc6532f-9a26-49aa-b444-8923896db89c','isActive':false,'balance':'$3,168.93','picture':'http://placehold.it/32x32','age':36,'eyeColor':'brown','name':{'first':'Marguerite','last':'Stuart'},'company':'ACCUFARM','email':'marguerite.stuart@accufarm.io','phone':'+1 (848) 535-2253','address':'301 Menahan Street, Sunnyside, Nebraska, 4809','about':'Deserunt sint labore voluptate amet anim culpa nostrud adipisicing enim cupidatat ullamco exercitation fugiat est. Magna dolor aute incididunt ea ad adipisicing. Do cupidatat ut officia officia culpa sit do.','registered':'Thursday, May 8, 2014 1:25 PM','latitude':'21.82277','longitude':'-7.368347','tags':['labore','nulla','ullamco','irure','adipisicing'],'greeting':'Hello, Marguerite! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edb26d315635818dae','index':49,'guid':'083a5eda-0a70-4f89-87f7-2cd386c0f22a','isActive':false,'balance':'$2,576.25','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Louella','last':'Holloway'},'company':'BEDDER','email':'louella.holloway@bedder.me','phone':'+1 (801) 425-3761','address':'545 Lafayette Avenue, Caledonia, Louisiana, 2816','about':'Qui exercitation occaecat dolore mollit. Fugiat cupidatat proident culpa fugiat quis. In cupidatat commodo elit ea enim occaecat esse exercitation nostrud occaecat veniam laboris fugiat. Nisi sunt reprehenderit aliqua reprehenderit tempor id dolore ullamco pariatur reprehenderit et eu ex pariatur.','registered':'Wednesday, November 5, 2014 1:10 AM','latitude':'36.385637','longitude':'77.949423','tags':['eu','irure','velit','non','aliquip'],'greeting':'Hello, Louella! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed77cd60a1abc1ecce','index':50,'guid':'2887c3c1-3eba-4237-a0db-1977eed94554','isActive':true,'balance':'$1,633.51','picture':'http://placehold.it/32x32','age':22,'eyeColor':'green','name':{'first':'Bates','last':'Carrillo'},'company':'ZOMBOID','email':'bates.carrillo@zomboid.com','phone':'+1 (934) 405-2006','address':'330 Howard Alley, Troy, Kansas, 4881','about':'Voluptate esse est ullamco anim tempor ea reprehenderit. Occaecat pariatur deserunt cillum laboris labore id exercitation esse ipsum ipsum ex aliquip. Sunt non elit est ea occaecat. Magna deserunt commodo aliqua ipsum est cillum dolor nisi. Ex duis est tempor tempor laboris do do quis id magna. Dolor do est elit eu laborum ullamco culpa consequat velit eiusmod tempor.','registered':'Saturday, May 28, 2016 3:56 AM','latitude':'83.310134','longitude':'-105.862836','tags':['est','commodo','ea','commodo','sunt'],'greeting':'Hello, Bates! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed5ec0ec299b471fb5','index':51,'guid':'512b5e67-f785-492e-9d94-e43ef8b399b8','isActive':false,'balance':'$3,032.22','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Floyd','last':'Yang'},'company':'FRENEX','email':'floyd.yang@frenex.org','phone':'+1 (924) 566-3304','address':'418 Quay Street, Chumuckla, Guam, 7743','about':'Irure sit velit exercitation dolore est nisi incididunt ut quis consectetur incididunt est dolor. Aute nisi enim esse aliquip enim culpa commodo consectetur. Duis laborum magna ad duis ipsum aliqua eiusmod cillum. Consectetur et duis eiusmod irure ad est nisi incididunt eiusmod labore. Pariatur proident in Lorem adipisicing mollit proident excepteur nulla do nostrud mollit eiusmod. Duis ad dolore irure fugiat anim laboris ipsum et sit duis ipsum voluptate. Lorem non aute exercitation qui ullamco officia minim sint pariatur ut dolor.','registered':'Wednesday, January 18, 2017 2:01 AM','latitude':'45.888721','longitude':'-41.232793','tags':['elit','in','esse','ea','officia'],'greeting':'Hello, Floyd! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed51e26ca89e5caf49','index':52,'guid':'4e0907f6-facc-46df-8952-73561a53fe33','isActive':true,'balance':'$3,767.41','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Gardner','last':'Carey'},'company':'KLUGGER','email':'gardner.carey@klugger.net','phone':'+1 (876) 481-3502','address':'131 Utica Avenue, Cannondale, Federated States Of Micronesia, 610','about':'Amet ad pariatur excepteur anim ex officia commodo proident aliqua occaecat consequat Lorem officia sit. Id minim velit nisi laboris nisi nulla incididunt eiusmod velit. Deserunt labore quis et tempor. Et labore exercitation laborum officia ullamco nostrud adipisicing laboris esse laborum aute anim elit. Sunt ad officia tempor esse et quis aliquip irure pariatur laborum id quis ex. Eu consequat nisi deserunt id eu proident ex minim aute nulla tempor ex.','registered':'Friday, February 21, 2014 6:42 AM','latitude':'-54.740231','longitude':'15.01484','tags':['commodo','laboris','occaecat','aliquip','adipisicing'],'greeting':'Hello, Gardner! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed52e3c9407105093a','index':53,'guid':'1d3b9e7a-1bc3-40ea-b808-1c33f0d48c70','isActive':true,'balance':'$1,113.30','picture':'http://placehold.it/32x32','age':26,'eyeColor':'blue','name':{'first':'Herman','last':'Rogers'},'company':'TALENDULA','email':'herman.rogers@talendula.name','phone':'+1 (818) 521-2005','address':'541 Norman Avenue, Winfred, Tennessee, 447','about':'Culpa ex laborum non ad ullamco officia. Nisi mollit mollit voluptate sit sint ullamco. Lorem exercitation nulla anim eiusmod deserunt magna sint. Officia sunt eiusmod aliqua reprehenderit sunt mollit sit cupidatat sint.','registered':'Wednesday, July 11, 2018 1:05 AM','latitude':'-20.708105','longitude':'-151.294563','tags':['exercitation','minim','officia','qui','enim'],'greeting':'Hello, Herman! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edfcb123d545b6edb4','index':54,'guid':'c0e0c669-4eed-43ee-bdd0-78fe6e9ca4d5','isActive':true,'balance':'$3,309.64','picture':'http://placehold.it/32x32','age':22,'eyeColor':'green','name':{'first':'Whitley','last':'Stark'},'company':'MUSAPHICS','email':'whitley.stark@musaphics.us','phone':'+1 (803) 476-2151','address':'548 Cobek Court, Chamizal, Indiana, 204','about':'Adipisicing veniam dolor ex sint sit id eu voluptate. Excepteur veniam proident exercitation id eu et sunt pariatur. Qui occaecat culpa aliqua nisi excepteur minim veniam. Est duis nulla laborum excepteur cillum pariatur sint incididunt. Velit commodo eu incididunt voluptate. Amet laboris laboris id adipisicing labore eiusmod consequat minim cillum et.','registered':'Thursday, March 27, 2014 9:10 AM','latitude':'71.219596','longitude':'51.012855','tags':['reprehenderit','mollit','laborum','voluptate','aliquip'],'greeting':'Hello, Whitley! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed81510dfc61602fcf','index':55,'guid':'7ec5c24d-f169-4399-a2a3-300c0f45e52e','isActive':false,'balance':'$3,721.04','picture':'http://placehold.it/32x32','age':23,'eyeColor':'green','name':{'first':'Gretchen','last':'Wade'},'company':'EWEVILLE','email':'gretchen.wade@eweville.biz','phone':'+1 (977) 598-3700','address':'721 Colonial Road, Brookfield, South Dakota, 3888','about':'Fugiat consequat sint ut ut et ullamco eiusmod deserunt pariatur. Veniam eiusmod esse fugiat mollit. Proident laboris minim qui do ipsum excepteur exercitation irure anim. Aliqua labore quis eu fugiat dolore ullamco velit Lorem voluptate ipsum nostrud eiusmod laborum proident.','registered':'Friday, October 12, 2018 10:59 AM','latitude':'41.937653','longitude':'63.378531','tags':['aute','cillum','ea','ex','aute'],'greeting':'Hello, Gretchen! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edf78f77d4a7d557bb','index':56,'guid':'8718ada7-6fd0-49ef-a405-29850503948b','isActive':false,'balance':'$3,341.33','picture':'http://placehold.it/32x32','age':32,'eyeColor':'blue','name':{'first':'Naomi','last':'Frye'},'company':'MAZUDA','email':'naomi.frye@mazuda.ca','phone':'+1 (825) 427-2255','address':'741 Coyle Street, Comptche, Pennsylvania, 8441','about':'Aliqua fugiat laborum quis ullamco cupidatat sit dolor nulla dolore. Do Lorem et ipsum culpa irure sit do dolor qui sit laboris aliqua. Ex consectetur irure in veniam reprehenderit amet do elit eiusmod est magna.','registered':'Thursday, January 9, 2014 7:18 AM','latitude':'41.078645','longitude':'-50.241966','tags':['do','aliquip','eiusmod','velit','id'],'greeting':'Hello, Naomi! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edbf45db2e072a48b4','index':57,'guid':'c158ebf7-fb8b-4ea8-adbf-8c51c6486715','isActive':true,'balance':'$2,811.55','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Lamb','last':'Johns'},'company':'DOGTOWN','email':'lamb.johns@dogtown.info','phone':'+1 (946) 530-3057','address':'559 Malbone Street, Kennedyville, California, 2052','about':'Eiusmod dolor labore cillum ad veniam elit voluptate voluptate pariatur est cupidatat. Laboris ut qui in cillum sunt dolore ut enim. Minim nostrud ex qui quis reprehenderit magna ipsum cupidatat irure minim laboris veniam irure. Fugiat velit deserunt aliquip in esse proident excepteur labore reprehenderit excepteur sunt in cupidatat exercitation. Ex pariatur irure mollit tempor non magna ex.','registered':'Friday, April 21, 2017 1:51 AM','latitude':'-61.403599','longitude':'-93.447102','tags':['aliquip','tempor','sint','enim','ipsum'],'greeting':'Hello, Lamb! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edbb9c88190cb59cf2','index':58,'guid':'f0de5ac5-eb28-491b-81c5-76d447c9055e','isActive':true,'balance':'$1,611.99','picture':'http://placehold.it/32x32','age':37,'eyeColor':'brown','name':{'first':'Lynette','last':'Cleveland'},'company':'ARTWORLDS','email':'lynette.cleveland@artworlds.tv','phone':'+1 (889) 596-3723','address':'439 Montauk Avenue, Felt, New Mexico, 9681','about':'Incididunt aliquip est aliquip est ullamco do consectetur dolor. Lorem mollit mollit dolor et ipsum ut qui veniam aute ea. Adipisicing reprehenderit culpa velit laborum adipisicing amet consectetur velit nisi. Ut qui proident ad cillum excepteur adipisicing quis labore. Duis velit culpa et excepteur eiusmod ex labore in nisi nostrud. Et ullamco minim excepteur ut enim reprehenderit consequat eiusmod laboris Lorem commodo exercitation qui laborum.','registered':'Wednesday, August 26, 2015 12:53 PM','latitude':'49.861336','longitude':'86.865926','tags':['reprehenderit','minim','in','minim','nostrud'],'greeting':'Hello, Lynette! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed5b760ddde7295fa8','index':59,'guid':'f8180d3f-c5c0-48b2-966e-a0b2a80f8e84','isActive':true,'balance':'$3,376.75','picture':'http://placehold.it/32x32','age':32,'eyeColor':'green','name':{'first':'Obrien','last':'Page'},'company':'GLASSTEP','email':'obrien.page@glasstep.co.uk','phone':'+1 (902) 583-3086','address':'183 Ridgewood Avenue, Vicksburg, Wisconsin, 7430','about':'Aute excepteur cillum exercitation duis Lorem irure labore elit. Labore magna cupidatat velit consectetur minim do Lorem in excepteur commodo ea consequat ullamco laborum. Ut in id occaecat eu quis duis id ea deserunt veniam.','registered':'Wednesday, March 29, 2017 12:13 AM','latitude':'-40.156154','longitude':'72.76301','tags':['excepteur','non','anim','nulla','anim'],'greeting':'Hello, Obrien! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed52985d3d8901d653','index':60,'guid':'d2e14fa1-8c54-4bcb-8a58-eb2e6f8d0e45','isActive':true,'balance':'$1,659.47','picture':'http://placehold.it/32x32','age':33,'eyeColor':'brown','name':{'first':'Knowles','last':'Goodman'},'company':'CENTREE','email':'knowles.goodman@centree.io','phone':'+1 (862) 563-3692','address':'504 Lott Street, Allensworth, Florida, 7148','about':'Do aliquip voluptate aliqua nostrud. Eu dolore ex occaecat pariatur aute laborum aute nulla aute amet. Excepteur sit laboris ad non anim ut officia ut ad exercitation officia dolore laboris. Esse voluptate minim deserunt nostrud exercitation laborum voluptate exercitation id laborum fugiat proident cupidatat proident. Nulla nostrud est sint adipisicing incididunt exercitation dolor sit et elit tempor occaecat sint culpa. Pariatur occaecat laboris pariatur laboris ad pariatur in cillum fugiat est fugiat. Proident eu id irure excepteur esse aute cillum adipisicing.','registered':'Wednesday, October 15, 2014 6:17 PM','latitude':'-15.73863','longitude':'87.422009','tags':['consequat','sint','tempor','veniam','culpa'],'greeting':'Hello, Knowles! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0eda00b73bdb7ea54e9','index':61,'guid':'c8a064db-0ec6-4832-9820-7280a0333709','isActive':true,'balance':'$3,701.14','picture':'http://placehold.it/32x32','age':35,'eyeColor':'brown','name':{'first':'Shepherd','last':'Todd'},'company':'ECRATIC','email':'shepherd.todd@ecratic.me','phone':'+1 (881) 444-3389','address':'450 Frank Court, Temperanceville, Ohio, 7006','about':'Voluptate cillum ad fugiat velit adipisicing sint consequat veniam Lorem reprehenderit. Cillum sit non deserunt consequat. Amet sunt pariatur non mollit ullamco proident sint dolore anim elit cupidatat anim do ullamco. Lorem Lorem incididunt ea elit consequat laboris enim duis quis Lorem id aute veniam consequat. Cillum veniam cillum sint qui Lorem fugiat culpa consequat. Est sint duis ut qui fugiat. Laborum pariatur velit et sunt mollit eiusmod excepteur culpa ex et officia.','registered':'Tuesday, October 10, 2017 2:01 AM','latitude':'82.951563','longitude':'-4.866954','tags':['eu','qui','proident','esse','ex'],'greeting':'Hello, Shepherd! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed0e51d1a7e2d9e559','index':62,'guid':'739c3d38-200d-4531-84d8-4e7c39ae5b8c','isActive':true,'balance':'$3,679.01','picture':'http://placehold.it/32x32','age':31,'eyeColor':'brown','name':{'first':'Rosalyn','last':'Heath'},'company':'ZAYA','email':'rosalyn.heath@zaya.com','phone':'+1 (865) 403-3520','address':'303 Henderson Walk, Hoehne, District Of Columbia, 4306','about':'Sint occaecat nulla mollit sint fugiat eu proident dolor labore consequat. Occaecat tempor excepteur do fugiat incididunt Lorem in ullamco dolore laborum. Cillum mollit aliquip excepteur aliquip sint sunt minim non irure irure. Cillum fugiat aliqua enim dolore. Nulla culpa culpa nostrud ad. Eiusmod culpa proident proident non est cupidatat eu sunt sit incididunt id nisi.','registered':'Wednesday, April 22, 2015 12:35 PM','latitude':'33.628504','longitude':'110.772802','tags':['consequat','ut','ex','labore','consectetur'],'greeting':'Hello, Rosalyn! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd5274c01d353d0c5','index':63,'guid':'8815fe55-8af1-4708-a62a-d554dbd74a4a','isActive':true,'balance':'$2,126.01','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Queen','last':'Harper'},'company':'TRI@TRIBALOG','email':'queen.harper@tri@tribalog.org','phone':'+1 (903) 592-3145','address':'926 Heath Place, Wawona, Maine, 7340','about':'Laborum cupidatat commodo aliquip reprehenderit. Excepteur eu labore duis minim minim voluptate aute nostrud deserunt ut velit ullamco. Adipisicing nisi occaecat laborum proident. Id reprehenderit eiusmod cupidatat qui aute consequat amet enim commodo duis non ipsum. Amet ut aliqua magna qui proident mollit aute.','registered':'Saturday, April 9, 2016 5:12 AM','latitude':'51.814216','longitude':'177.348115','tags':['cillum','ut','dolor','do','nisi'],'greeting':'Hello, Queen! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed126298b6ce62ed56','index':64,'guid':'001c87fe-182f-450f-903b-2e29a9bb0322','isActive':true,'balance':'$3,578.29','picture':'http://placehold.it/32x32','age':20,'eyeColor':'green','name':{'first':'Pauline','last':'Mills'},'company':'CRUSTATIA','email':'pauline.mills@crustatia.net','phone':'+1 (984) 582-3899','address':'899 Revere Place, Welch, Iowa, 216','about':'Tempor eu exercitation ut id. Deserunt ex reprehenderit veniam nisi. Aute laborum veniam velit dolore ut deserunt Lorem sit esse quis dolor ex do nisi. In dolor tempor officia id. Velit nisi culpa nostrud laborum officia incididunt laborum velit non quis id exercitation exercitation. Anim elit ullamco in enim Lorem culpa aliqua Lorem.','registered':'Monday, June 2, 2014 2:03 PM','latitude':'56.427576','longitude':'172.183669','tags':['pariatur','pariatur','pariatur','fugiat','Lorem'],'greeting':'Hello, Pauline! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed3e332ad9e8a178d8','index':65,'guid':'5ad7292b-feef-4a7e-b485-142cadfbe8ea','isActive':false,'balance':'$3,916.54','picture':'http://placehold.it/32x32','age':22,'eyeColor':'brown','name':{'first':'Garrett','last':'Richmond'},'company':'XYQAG','email':'garrett.richmond@xyqag.name','phone':'+1 (952) 584-3794','address':'233 Grove Street, Summerfield, Virginia, 4735','about':'Nostrud quis pariatur occaecat laborum laboris aliqua ut fugiat dolor. Commodo tempor excepteur enim nostrud Lorem. Aute elit nulla labore ad pariatur cupidatat Lorem qui cupidatat velit deserunt excepteur esse. Excepteur nulla et nostrud quis labore est veniam enim nisi laboris ut enim. Ea esse nulla anim excepteur reprehenderit deserunt voluptate minim qui labore adipisicing amet eu enim.','registered':'Wednesday, March 5, 2014 4:35 PM','latitude':'68.665041','longitude':'148.799524','tags':['irure','reprehenderit','minim','ea','do'],'greeting':'Hello, Garrett! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed541aa2ec47466ace','index':66,'guid':'9cda6f3c-c9ab-451c-bb19-2e4c8463d011','isActive':true,'balance':'$3,352.52','picture':'http://placehold.it/32x32','age':30,'eyeColor':'brown','name':{'first':'Cobb','last':'Whitley'},'company':'UNIA','email':'cobb.whitley@unia.us','phone':'+1 (888) 490-3342','address':'864 Belmont Avenue, Needmore, Massachusetts, 8286','about':'Nisi aliquip fugiat ipsum nisi ullamco minim pariatur labore. Sint labore anim do ad ad esse eu nostrud nulla commodo anim. Cillum anim enim duis cillum non do nisi aliquip veniam voluptate commodo aliqua laborum. Exercitation in do eu qui sint aliquip. Esse adipisicing deserunt deserunt qui anim aliqua occaecat et nostrud elit ea in anim cillum. Tempor mollit proident tempor sunt est sint laborum ullamco incididunt non. Velit aliqua sunt excepteur nisi qui eiusmod ipsum dolore aliquip velit ullamco ullamco.','registered':'Friday, May 23, 2014 7:11 PM','latitude':'-32.950581','longitude':'147.772494','tags':['mollit','adipisicing','irure','ad','minim'],'greeting':'Hello, Cobb! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed8186c3d6f34c2be3','index':67,'guid':'fee98f6d-d68a-4189-8180-b6cb337e537e','isActive':false,'balance':'$1,698.42','picture':'http://placehold.it/32x32','age':20,'eyeColor':'blue','name':{'first':'Brennan','last':'Tyler'},'company':'PODUNK','email':'brennan.tyler@podunk.biz','phone':'+1 (867) 498-2727','address':'599 Harkness Avenue, Gorst, American Samoa, 322','about':'Reprehenderit id sit qui id qui aute ea sit magna in qui proident. Excepteur ad nostrud do nostrud in incididunt voluptate adipisicing sint anim. Ullamco consequat minim nulla irure ex est irure reprehenderit deserunt voluptate dolore anim sunt. Occaecat dolore voluptate voluptate elit commodo nulla laborum ad do irure.','registered':'Friday, February 9, 2018 5:40 PM','latitude':'11.150893','longitude':'-85.298004','tags':['quis','minim','deserunt','cillum','laboris'],'greeting':'Hello, Brennan! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed075c9c4f7439818d','index':68,'guid':'1ef76b18-6b8d-4c3c-aca3-9fa2b43f0242','isActive':false,'balance':'$2,091.17','picture':'http://placehold.it/32x32','age':26,'eyeColor':'brown','name':{'first':'Neal','last':'Stephenson'},'company':'OTHERSIDE','email':'neal.stephenson@otherside.ca','phone':'+1 (820) 496-3344','address':'867 Wilson Street, Kidder, Colorado, 4599','about':'Do laboris enim proident in qui velit adipisicing magna anim. Amet proident non exercitation ipsum aliqua excepteur nostrud. Enim esse non sit in nostrud deserunt id laborum cillum deserunt consequat. Anim velit exercitation qui sit voluptate. Irure duis non veniam velit mollit exercitation id exercitation.','registered':'Thursday, November 13, 2014 11:00 PM','latitude':'54.809693','longitude':'1.877241','tags':['anim','duis','in','officia','sint'],'greeting':'Hello, Neal! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0eda0a2dc24db64b638','index':69,'guid':'194744fd-089b-40b6-a290-98a6ec30a415','isActive':false,'balance':'$3,191.67','picture':'http://placehold.it/32x32','age':24,'eyeColor':'brown','name':{'first':'Shields','last':'Hubbard'},'company':'MIRACULA','email':'shields.hubbard@miracula.info','phone':'+1 (885) 582-2001','address':'529 Eagle Street, Guilford, Nevada, 1460','about':'Eiusmod exercitation ut incididunt veniam commodo culpa ullamco mollit id adipisicing exercitation ad sint. Nostrud excepteur amet aliqua mollit incididunt laborum voluptate id anim. Nulla sint laboris dolor esse cupidatat laborum ex sint. Ex non sunt sit nulla.','registered':'Monday, February 13, 2017 6:22 AM','latitude':'-69.145209','longitude':'-40.69755','tags':['tempor','enim','qui','velit','elit'],'greeting':'Hello, Shields! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edf939c130177e074d','index':70,'guid':'303b176c-7803-4ed2-a35f-3e3c831793ef','isActive':false,'balance':'$2,359.09','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Coleen','last':'Knight'},'company':'BLEEKO','email':'coleen.knight@bleeko.tv','phone':'+1 (867) 423-3146','address':'527 Broadway , Bonanza, Marshall Islands, 4988','about':'Laboris nulla pariatur laborum ad aute excepteur sunt pariatur exercitation. Do nostrud qui ipsum ullamco et sint do Lorem cillum ullamco do. Exercitation labore excepteur commodo incididunt eiusmod proident consectetur adipisicing nostrud aute voluptate laboris. Commodo anim proident eiusmod pariatur est ea laborum incididunt qui tempor reprehenderit ullamco id. Eiusmod commodo nisi consectetur ut qui quis aliqua sit minim nostrud sunt laborum eiusmod adipisicing.','registered':'Sunday, May 6, 2018 8:03 AM','latitude':'70.729041','longitude':'113.052761','tags':['Lorem','ullamco','nulla','ullamco','commodo'],'greeting':'Hello, Coleen! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edae8b1ce688b61223','index':71,'guid':'7d6f3b1a-c367-4068-9e8e-1717d513ece3','isActive':false,'balance':'$2,911.07','picture':'http://placehold.it/32x32','age':21,'eyeColor':'brown','name':{'first':'Clark','last':'Ryan'},'company':'ECLIPSENT','email':'clark.ryan@eclipsent.co.uk','phone':'+1 (938) 562-2740','address':'500 Lewis Avenue, Rockbridge, North Dakota, 5133','about':'Adipisicing exercitation officia sit excepteur excepteur sunt sint amet. Aliqua ipsum sint laboris eiusmod esse culpa elit sunt. Dolore est consectetur est quis quis magna. Aliquip nostrud dolore ex pariatur. Anim nostrud duis exercitation ut magna magna culpa. Nisi irure id mollit labore non sit mollit occaecat Lorem est ipsum. Nulla est fugiat cillum nisi aliqua consectetur amet nulla nostrud esse.','registered':'Friday, July 24, 2015 9:28 AM','latitude':'-68.055815','longitude':'-50.926966','tags':['deserunt','ad','ad','ut','id'],'greeting':'Hello, Clark! You have 7 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed5d1e8df45d8ab4db','index':72,'guid':'ce85db37-7d04-4f4c-a4b0-78003533e5c6','isActive':false,'balance':'$1,127.43','picture':'http://placehold.it/32x32','age':21,'eyeColor':'green','name':{'first':'Dillon','last':'Hooper'},'company':'MEDESIGN','email':'dillon.hooper@medesign.io','phone':'+1 (929) 600-3797','address':'652 Mill Avenue, Elliston, Mississippi, 2958','about':'Dolore culpa qui exercitation nostrud do. Irure duis in ad ipsum aliqua aliquip nulla sit veniam officia quis occaecat est. Magna qui eiusmod pariatur aliquip minim commodo. Qui ex dolor excepteur consequat eiusmod occaecat. In officia ipsum do Lorem excepteur proident pariatur labore.','registered':'Monday, May 26, 2014 2:38 AM','latitude':'-36.032189','longitude':'86.865529','tags':['non','ut','ex','Lorem','quis'],'greeting':'Hello, Dillon! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edb84814579c3121b3','index':73,'guid':'d7303901-5186-4595-a759-22306f67d0a3','isActive':true,'balance':'$2,326.59','picture':'http://placehold.it/32x32','age':33,'eyeColor':'green','name':{'first':'Moreno','last':'Hull'},'company':'ZEAM','email':'moreno.hull@zeam.me','phone':'+1 (984) 586-3738','address':'265 Pine Street, Talpa, North Carolina, 6041','about':'Fugiat exercitation est ullamco anim. Exercitation proident id sunt culpa Lorem amet. Consectetur anim consectetur pariatur consequat consectetur amet excepteur voluptate ea velit duis eiusmod proident. In sint laborum cupidatat ea amet ex. Reprehenderit amet sunt dolor ullamco est ex deserunt.','registered':'Wednesday, January 24, 2018 8:52 PM','latitude':'84.956857','longitude':'113.210051','tags':['est','excepteur','anim','Lorem','dolor'],'greeting':'Hello, Moreno! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eda4eb9dcb92c82d06','index':74,'guid':'8ee28651-802e-4523-b676-c713f6e874b8','isActive':true,'balance':'$3,783.97','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Tracie','last':'Price'},'company':'ICOLOGY','email':'tracie.price@icology.com','phone':'+1 (897) 403-3768','address':'487 Sheffield Avenue, Vallonia, Wyoming, 276','about':'Voluptate laboris laborum aute ex sint voluptate officia proident. Sit esse nostrud cupidatat in veniam sit duis est. Do mollit elit exercitation aliqua id irure ex. Lorem reprehenderit do ullamco sint ea ad nisi ad ut.','registered':'Saturday, December 10, 2016 9:44 AM','latitude':'77.770464','longitude':'151.392903','tags':['incididunt','labore','aliquip','anim','minim'],'greeting':'Hello, Tracie! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed68ab1a55d1c35e6c','index':75,'guid':'deedd26a-8928-4064-9666-5c59ea8144b4','isActive':true,'balance':'$2,848.08','picture':'http://placehold.it/32x32','age':32,'eyeColor':'brown','name':{'first':'Montgomery','last':'Bruce'},'company':'CYTREK','email':'montgomery.bruce@cytrek.org','phone':'+1 (824) 414-2731','address':'397 Beach Place, Ellerslie, South Carolina, 967','about':'Mollit minim excepteur magna velit cillum excepteur exercitation anim id labore deserunt do. Fugiat ex et id ad. Duis excepteur laboris est nulla do id irure quis eiusmod do esse ut culpa in.','registered':'Tuesday, August 25, 2015 6:42 AM','latitude':'79.722631','longitude':'-7.516885','tags':['Lorem','sint','voluptate','proident','incididunt'],'greeting':'Hello, Montgomery! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd90e0abb1cc2b0aa','index':76,'guid':'a072159d-12db-4747-9c2a-e2486a53d043','isActive':false,'balance':'$2,723.54','picture':'http://placehold.it/32x32','age':40,'eyeColor':'green','name':{'first':'Zelma','last':'Salinas'},'company':'IMAGEFLOW','email':'zelma.salinas@imageflow.net','phone':'+1 (964) 555-3856','address':'584 Reeve Place, Nord, Georgia, 7473','about':'Aliqua proident excepteur duis cupidatat cillum amet esse esse consectetur ea. Officia sunt consequat nostrud minim enim dolore dolor duis cillum. Esse labore veniam sint laborum excepteur sint tempor do ad cupidatat aliquip laboris elit id. Velit reprehenderit ullamco velit ullamco adipisicing velit esse irure velit et.','registered':'Thursday, February 25, 2016 8:18 PM','latitude':'-32.880524','longitude':'115.180489','tags':['id','nulla','reprehenderit','consequat','reprehenderit'],'greeting':'Hello, Zelma! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed98d836c8da283bb2','index':77,'guid':'838bebad-cc20-44e9-9eb7-902a8ca25efb','isActive':false,'balance':'$3,488.91','picture':'http://placehold.it/32x32','age':20,'eyeColor':'green','name':{'first':'Shaw','last':'Parsons'},'company':'PEARLESEX','email':'shaw.parsons@pearlesex.name','phone':'+1 (912) 567-3580','address':'606 Ocean Avenue, Tyro, Northern Mariana Islands, 3367','about':'Laborum labore occaecat culpa pariatur nisi non adipisicing esse consectetur officia officia. Deserunt velit eu enim consectetur ut cillum aliqua occaecat dolor qui esse. Incididunt ad est ex eu culpa anim aliquip laborum. Aliqua consectetur velit exercitation magna minim nulla do ut excepteur enim aliquip et. Nostrud enim sunt amet amet proident aliqua velit dolore. Consectetur ipsum fugiat proident id est reprehenderit tempor irure commodo. Sit excepteur fugiat occaecat nulla Lorem et cillum.','registered':'Thursday, April 19, 2018 1:41 AM','latitude':'69.715573','longitude':'-118.481237','tags':['laboris','adipisicing','magna','voluptate','id'],'greeting':'Hello, Shaw! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed1101734633c6ebba','index':78,'guid':'8fd0c52a-9d74-4984-a608-d612ecd8ddf0','isActive':true,'balance':'$3,820.02','picture':'http://placehold.it/32x32','age':39,'eyeColor':'brown','name':{'first':'Jaime','last':'Beard'},'company':'IZZBY','email':'jaime.beard@izzby.us','phone':'+1 (820) 412-3806','address':'362 Hudson Avenue, Delco, New Jersey, 5684','about':'Ut cupidatat veniam nulla magna commodo sit duis veniam consectetur cupidatat elit quis tempor. Duis officia ullamco proident sunt non mollit excepteur. Nisi ex amet laboris proident duis reprehenderit et est aliqua mollit amet ad. Enim eu elit excepteur eu exercitation duis consequat culpa. Adipisicing reprehenderit duis Lorem reprehenderit dolor aliqua incididunt eiusmod consequat ad occaecat fugiat do laborum. Qui ad aliquip ex do sunt. Fugiat non ut fugiat eu.','registered':'Sunday, March 9, 2014 3:41 PM','latitude':'17.926318','longitude':'108.985996','tags':['ut','voluptate','veniam','non','commodo'],'greeting':'Hello, Jaime! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edcd125a89dcf18e0d','index':79,'guid':'eccaa4ca-0fa7-4b00-a1e3-fe7953403894','isActive':true,'balance':'$1,521.33','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Terra','last':'Sullivan'},'company':'ZANITY','email':'terra.sullivan@zanity.biz','phone':'+1 (995) 498-2714','address':'346 Congress Street, Tuttle, Maryland, 3152','about':'Incididunt enim veniam ut veniam quis dolore pariatur culpa ex. Cillum laboris dolor exercitation officia. Officia irure magna aliqua veniam officia ullamco culpa. Cillum enim velit ea sint sint officia labore ea adipisicing culpa laboris. Anim aute sint commodo culpa ex quis minim ut laborum.','registered':'Sunday, June 1, 2014 5:38 AM','latitude':'-4.655435','longitude':'5.851803','tags':['anim','non','anim','laborum','pariatur'],'greeting':'Hello, Terra! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed9b9fc3041a674c87','index':80,'guid':'9f95fa36-4e45-4c3f-9362-3d4d809bf57f','isActive':true,'balance':'$3,403.16','picture':'http://placehold.it/32x32','age':39,'eyeColor':'brown','name':{'first':'Sharpe','last':'Berger'},'company':'ZILLAN','email':'sharpe.berger@zillan.ca','phone':'+1 (913) 498-3005','address':'277 Bragg Street, Faywood, Texas, 6487','about':'Dolor duis id aute ea veniam amet ullamco id. Culpa deserunt irure mollit tempor dolore veniam culpa officia culpa laborum eiusmod. Ullamco tempor qui aliqua cupidatat veniam cillum eu ut ex minim eu in. Quis exercitation anim eiusmod tempor esse mollit exercitation cillum ipsum reprehenderit. Sint voluptate ipsum officia sint magna nulla tempor eiusmod eiusmod veniam. Consectetur non ad veniam exercitation voluptate non nostrud.','registered':'Tuesday, June 27, 2017 12:58 AM','latitude':'-0.54085','longitude':'106.258693','tags':['proident','eiusmod','commodo','excepteur','pariatur'],'greeting':'Hello, Sharpe! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed1a1866757bf675e0','index':81,'guid':'1b944a01-01d3-4846-94e3-630f4d0e51a3','isActive':true,'balance':'$2,038.61','picture':'http://placehold.it/32x32','age':28,'eyeColor':'brown','name':{'first':'Blanchard','last':'Ewing'},'company':'CONJURICA','email':'blanchard.ewing@conjurica.info','phone':'+1 (859) 593-3212','address':'252 Beaver Street, Kiskimere, Utah, 3255','about':'Labore magna aute adipisicing ut dolor sit ea. Officia culpa aute occaecat sit ex ullamco aliquip ad sit culpa. Ex in enim dolore ex est sit. Do irure nulla magna sint aliquip in duis aute. Magna ullamco sit labore ea tempor voluptate.','registered':'Monday, May 4, 2015 10:50 AM','latitude':'76.207595','longitude':'0.672563','tags':['proident','pariatur','officia','in','culpa'],'greeting':'Hello, Blanchard! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed987d82f4e22d939c','index':82,'guid':'97a90aee-3cee-4678-819e-24fb94279dc1','isActive':false,'balance':'$1,201.55','picture':'http://placehold.it/32x32','age':28,'eyeColor':'blue','name':{'first':'Wells','last':'Solomon'},'company':'CORPULSE','email':'wells.solomon@corpulse.tv','phone':'+1 (840) 539-3349','address':'159 Radde Place, Linganore, Idaho, 230','about':'Consequat dolore mollit sit irure cupidatat commodo. Incididunt cillum reprehenderit ullamco sit proident cupidatat occaecat reprehenderit officia. Ad anim Lorem elit in officia minim proident nisi commodo eiusmod ea Lorem dolore voluptate. Dolor aliquip est commodo Lorem dolor ut aliquip ut. Sit anim officia dolore excepteur aute enim cillum.','registered':'Friday, January 6, 2017 1:59 PM','latitude':'70.020883','longitude':'14.503588','tags':['mollit','aute','officia','nostrud','laboris'],'greeting':'Hello, Wells! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eddf7a904ea0d0bc2a','index':83,'guid':'fe639a0c-7517-43e6-b0da-cd9ca5b9e267','isActive':false,'balance':'$3,664.47','picture':'http://placehold.it/32x32','age':33,'eyeColor':'blue','name':{'first':'Natalia','last':'Brown'},'company':'SYNTAC','email':'natalia.brown@syntac.co.uk','phone':'+1 (952) 595-3513','address':'332 Lenox Road, Springville, Alabama, 8406','about':'Nulla consequat officia commodo ea sunt irure anim velit aliquip aliquip. Labore ullamco occaecat proident voluptate cillum labore minim nostrud excepteur. Qui fugiat nostrud cillum fugiat ullamco id commodo aliqua voluptate mollit id id laboris. Cillum qui duis duis sit adipisicing elit ut aliqua eu. Anim nisi aliqua sit mollit.','registered':'Sunday, July 30, 2017 1:02 PM','latitude':'31.937613','longitude':'-9.957927','tags':['magna','adipisicing','exercitation','tempor','consectetur'],'greeting':'Hello, Natalia! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed8823fa385cad4aa3','index':84,'guid':'5cf280da-f5f0-4cc6-9063-e9d5863c8c89','isActive':false,'balance':'$1,624.17','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Greene','last':'Waller'},'company':'ISOTRACK','email':'greene.waller@isotrack.io','phone':'+1 (838) 406-3608','address':'362 Albemarle Road, Gardiner, Michigan, 2764','about':'Ut nisi sit sint nulla dolor magna. Culpa occaecat adipisicing veniam proident excepteur tempor quis ex. Fugiat tempor laborum dolor adipisicing irure anim cupidatat ut exercitation ex sit. Cupidatat exercitation commodo sunt ex irure fugiat eu esse do ullamco mollit dolore cupidatat. Cupidatat magna incididunt officia dolore esse voluptate deserunt in laborum dolor. Sit fugiat Lorem eu ullamco. Laboris veniam quis cillum tempor ex fugiat cillum cupidatat.','registered':'Sunday, June 10, 2018 10:32 PM','latitude':'0.256921','longitude':'-96.141941','tags':['magna','dolore','deserunt','aliquip','cillum'],'greeting':'Hello, Greene! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eda7c905c2d24c7d31','index':85,'guid':'aa30a9fb-8a16-48eb-8bb7-1307d1e1f191','isActive':false,'balance':'$1,974.04','picture':'http://placehold.it/32x32','age':36,'eyeColor':'green','name':{'first':'Carlene','last':'Hanson'},'company':'DIGIRANG','email':'carlene.hanson@digirang.me','phone':'+1 (981) 417-3209','address':'435 Clark Street, Choctaw, Oregon, 9888','about':'Amet labore esse cillum irure laborum consectetur occaecat non aliquip aliquip proident. Nisi magna nulla officia duis labore aute nulla laborum duis tempor minim. Velit elit reprehenderit nisi exercitation officia incididunt amet cupidatat excepteur proident consectetur.','registered':'Thursday, April 20, 2017 6:13 AM','latitude':'68.529086','longitude':'68.802409','tags':['pariatur','nulla','qui','amet','labore'],'greeting':'Hello, Carlene! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed6fbee12ce9e55dbf','index':86,'guid':'0fce89aa-3310-48df-862a-68bd3d776644','isActive':false,'balance':'$3,909.64','picture':'http://placehold.it/32x32','age':40,'eyeColor':'brown','name':{'first':'Doris','last':'Collins'},'company':'ZIORE','email':'doris.collins@ziore.com','phone':'+1 (914) 405-2360','address':'301 Lorraine Street, Stouchsburg, Minnesota, 7476','about':'Nisi deserunt aliquip et deserunt ipsum ad consectetur est non ullamco. Dolore do ut voluptate do eiusmod. Culpa ad in eiusmod nisi cillum do. Officia magna cillum sint aliqua reprehenderit amet est ipsum. Eiusmod deserunt commodo proident consequat. Amet minim dolor consequat aliquip aliquip culpa non exercitation non.','registered':'Wednesday, February 25, 2015 9:15 PM','latitude':'-57.364906','longitude':'130.766587','tags':['nulla','deserunt','cillum','eiusmod','adipisicing'],'greeting':'Hello, Doris! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edede9402476c398c0','index':87,'guid':'60cf0aa6-bc6d-4305-8842-d27e6af1306f','isActive':false,'balance':'$2,817.53','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Cline','last':'Hayden'},'company':'ECRAZE','email':'cline.hayden@ecraze.org','phone':'+1 (965) 507-2138','address':'352 Rutland Road, Ebro, Connecticut, 1196','about':'Dolor eiusmod enim anim sit enim ea tempor. Tempor amet consectetur aliquip culpa do ex excepteur deserunt. Dolor commodo veniam culpa sint. Commodo consectetur pariatur irure nisi deserunt cillum est dolor ipsum ea.','registered':'Thursday, September 29, 2016 5:58 AM','latitude':'62.50713','longitude':'86.247286','tags':['enim','tempor','anim','veniam','proident'],'greeting':'Hello, Cline! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edeb72f151994a551b','index':88,'guid':'dbb49c62-86b1-409f-b8b8-f609c709d2a8','isActive':false,'balance':'$3,122.56','picture':'http://placehold.it/32x32','age':39,'eyeColor':'green','name':{'first':'Janelle','last':'Rutledge'},'company':'TERRAGEN','email':'janelle.rutledge@terragen.net','phone':'+1 (914) 581-3749','address':'170 Falmouth Street, Alderpoint, West Virginia, 642','about':'Laboris proident cillum sunt qui ea sunt. Officia adipisicing exercitation dolore magna reprehenderit amet anim id. Laboris commodo sit irure irure. Excepteur est mollit fugiat incididunt consectetur veniam irure ea mollit. Cillum enim consequat sunt sunt nisi incididunt tempor enim.','registered':'Monday, February 16, 2015 5:46 AM','latitude':'-46.392023','longitude':'32.054562','tags':['eu','eu','nisi','labore','deserunt'],'greeting':'Hello, Janelle! You have 9 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edc9c2604846ff9a0d','index':89,'guid':'c4d7a365-f1d3-4584-b78e-008394c219f7','isActive':true,'balance':'$1,807.19','picture':'http://placehold.it/32x32','age':24,'eyeColor':'green','name':{'first':'Abby','last':'Lopez'},'company':'GRAINSPOT','email':'abby.lopez@grainspot.name','phone':'+1 (917) 442-3955','address':'488 Kensington Walk, Winston, Hawaii, 9109','about':'Incididunt deserunt Lorem proident magna tempor enim quis duis eu ut adipisicing in. Ex mollit non irure aliqua officia. Fugiat id ipsum consequat irure id ullamco culpa quis nulla enim aliquip consequat et. Dolor ut anim velit irure consequat cillum eu. Aute occaecat laborum est aliqua.','registered':'Sunday, April 1, 2018 11:28 PM','latitude':'-10.177041','longitude':'-165.756718','tags':['est','laborum','culpa','non','quis'],'greeting':'Hello, Abby! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed03237438b158af9e','index':90,'guid':'36c4a19f-2d00-4e40-bd49-155fd2ce0a6c','isActive':false,'balance':'$2,757.86','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Whitney','last':'Sheppard'},'company':'ANACHO','email':'whitney.sheppard@anacho.us','phone':'+1 (922) 437-2383','address':'951 Beekman Place, Homeworth, New York, 6088','about':'Sint minim nisi minim non minim aliqua pariatur ullamco do sint qui labore. Aute elit reprehenderit ad do fugiat est amet. In incididunt tempor commodo cillum tempor est labore anim.','registered':'Tuesday, September 13, 2016 6:43 PM','latitude':'-49.732527','longitude':'-171.846715','tags':['exercitation','veniam','sunt','est','proident'],'greeting':'Hello, Whitney! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edb99dd3aa53d2cb7f','index':91,'guid':'17afd430-f37f-4d55-958c-72f35cdb5997','isActive':false,'balance':'$3,683.86','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Ilene','last':'Blackwell'},'company':'ENQUILITY','email':'ilene.blackwell@enquility.biz','phone':'+1 (817) 555-2616','address':'950 Varanda Place, Belgreen, Virgin Islands, 1765','about':'Id eiusmod deserunt eiusmod adipisicing adipisicing est enim pariatur esse duis. Qui velit duis irure magna consectetur dolore reprehenderit. Cillum dolore minim consectetur irure non qui velit cillum veniam adipisicing incididunt. Deserunt veniam excepteur veniam velit aliquip labore quis exercitation magna do non dolor. Aliquip occaecat minim adipisicing deserunt fugiat nulla occaecat proident irure consectetur eiusmod irure. Enim Lorem deserunt amet Lorem commodo eiusmod reprehenderit occaecat adipisicing dolor voluptate cillum.','registered':'Thursday, February 1, 2018 8:39 AM','latitude':'57.393644','longitude':'-3.704258','tags':['adipisicing','dolor','commodo','Lorem','Lorem'],'greeting':'Hello, Ilene! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed353f4deb62c3342a','index':92,'guid':'9953e285-2095-4f1c-978b-9ece2a867e9d','isActive':false,'balance':'$1,202.44','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Dawson','last':'Herman'},'company':'BITENDREX','email':'dawson.herman@bitendrex.ca','phone':'+1 (843) 522-2655','address':'471 Channel Avenue, Denio, Alaska, 5040','about':'Nisi occaecat mollit reprehenderit nisi minim Lorem mollit. Ea proident irure cillum quis. Deserunt consectetur consectetur consequat quis enim minim ea ipsum proident nisi ad non aliquip. Veniam aute minim consequat irure voluptate aute amet excepteur exercitation cillum duis quis adipisicing nostrud.','registered':'Tuesday, December 8, 2015 5:40 PM','latitude':'-55.602721','longitude':'-26.683234','tags':['qui','dolor','deserunt','eiusmod','labore'],'greeting':'Hello, Dawson! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd5464bc50a5310ad','index':93,'guid':'724b2434-4dbd-417d-aa07-6065715f434f','isActive':false,'balance':'$1,595.98','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Alice','last':'Christian'},'company':'ZENOLUX','email':'alice.christian@zenolux.info','phone':'+1 (954) 466-2650','address':'875 Gerritsen Avenue, Townsend, Kentucky, 6568','about':'Nulla labore occaecat ex culpa magna. Commodo occaecat et in consequat cillum laborum magna adipisicing excepteur. Do ut Lorem esse voluptate officia ea aliquip proident amet veniam minim nulla adipisicing. Enim consectetur incididunt laborum voluptate tempor deserunt non laboris. Aliquip deserunt aute irure dolore magna anim aliquip sint magna Lorem. Officia laboris nulla officia sint labore nisi. Do Lorem id in est esse adipisicing id fugiat enim esse laborum.','registered':'Wednesday, October 3, 2018 9:26 PM','latitude':'-88.790637','longitude':'138.817328','tags':['duis','ea','magna','ea','incididunt'],'greeting':'Hello, Alice! You have 8 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0eda01886247b6a4f3d','index':94,'guid':'17c9f4d3-7d72-44e3-8f7c-08d7de920f46','isActive':false,'balance':'$3,173.29','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Schwartz','last':'Mccormick'},'company':'EVIDENDS','email':'schwartz.mccormick@evidends.tv','phone':'+1 (924) 531-2802','address':'160 Midwood Street, Indio, Palau, 4241','about':'Anim reprehenderit et et adipisicing voluptate consequat elit. Sint Lorem laboris Lorem minim nostrud aute reprehenderit elit aute quis nulla. Officia aute eiusmod mollit cillum eu aliquip non enim ea occaecat quis fugiat occaecat officia. Eiusmod culpa exercitation dolor aliqua enim occaecat nisi cupidatat duis ex dolore id. Id consequat aliqua cupidatat ut. Sit nisi est sunt culpa ullamco excepteur sunt pariatur incididunt amet. Ut tempor duis velit eu ut id culpa aute anim occaecat labore.','registered':'Thursday, March 2, 2017 5:57 PM','latitude':'38.618587','longitude':'-165.142529','tags':['ad','reprehenderit','magna','elit','mollit'],'greeting':'Hello, Schwartz! You have 10 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed51be4df456ec2bc9','index':95,'guid':'44f68f65-959b-4ec2-bd2a-1f30035f76fc','isActive':false,'balance':'$3,242.24','picture':'http://placehold.it/32x32','age':39,'eyeColor':'blue','name':{'first':'Bonita','last':'Stevens'},'company':'SLOFAST','email':'bonita.stevens@slofast.co.uk','phone':'+1 (886) 473-2105','address':'459 Bushwick Court, Kilbourne, Rhode Island, 9450','about':'Consequat reprehenderit qui reprehenderit nisi sit est in qui aliquip amet. Ex deserunt cupidatat amet cillum eiusmod irure anim in amet proident voluptate. Ad officia culpa in non incididunt do.','registered':'Saturday, August 22, 2015 5:23 AM','latitude':'60.013542','longitude':'58.242132','tags':['aute','adipisicing','in','cillum','officia'],'greeting':'Hello, Bonita! You have 5 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed50a55e3587993f68','index':96,'guid':'652e434f-221e-4899-af12-38dca5c9621d','isActive':false,'balance':'$2,720.06','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Charmaine','last':'Jackson'},'company':'FLUM','email':'charmaine.jackson@flum.io','phone':'+1 (947) 573-2692','address':'788 Windsor Place, Highland, Arkansas, 8869','about':'Dolore reprehenderit irure excepteur eu reprehenderit sint Lorem ut amet in. Consequat anim elit sunt aliquip incididunt. Culpa consequat do exercitation dolor enim dolor sunt sit excepteur ad anim. Dolor aute elit velit mollit minim eu.','registered':'Wednesday, April 6, 2016 7:54 PM','latitude':'25.756553','longitude':'-5.482531','tags':['amet','sint','consequat','est','ex'],'greeting':'Hello, Charmaine! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed213621949bbdd5d3','index':97,'guid':'7d7d93d8-3e37-4b4a-9fa2-591fb7d153ce','isActive':true,'balance':'$1,370.63','picture':'http://placehold.it/32x32','age':36,'eyeColor':'brown','name':{'first':'Petersen','last':'Cooley'},'company':'ROTODYNE','email':'petersen.cooley@rotodyne.me','phone':'+1 (929) 563-3339','address':'338 Pioneer Street, Carbonville, Missouri, 3030','about':'Cillum elit dolore labore aute. Cillum ea incididunt cupidatat consequat sint eu mollit. Excepteur commodo eiusmod ex Lorem enim velit minim.','registered':'Friday, December 8, 2017 5:53 AM','latitude':'-10.576254','longitude':'-111.176861','tags':['veniam','eu','eiusmod','dolore','voluptate'],'greeting':'Hello, Petersen! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed3e938138d58ed453','index':98,'guid':'d6fea4a3-03f6-46ee-90b9-8ec51a585e29','isActive':true,'balance':'$1,216.54','picture':'http://placehold.it/32x32','age':39,'eyeColor':'blue','name':{'first':'Rosanne','last':'Terry'},'company':'EXTREMO','email':'rosanne.terry@extremo.com','phone':'+1 (812) 496-2691','address':'368 Rockaway Avenue, Gloucester, Illinois, 7913','about':'Duis et nostrud duis quis minim eiusmod culpa do ea ad pariatur tempor. Velit veniam aliqua aliquip est enim ex et culpa dolor ullamco culpa officia. Eu id occaecat aute cillum aute sit aute laboris ipsum voluptate ex. Amet tempor minim tempor Lorem quis dolore. Pariatur consequat dolore nulla veniam dolor exercitation consequat nulla laboris incididunt do. Dolore do tempor deserunt exercitation incididunt officia incididunt ut do reprehenderit do eiusmod nulla.','registered':'Sunday, August 6, 2017 12:46 PM','latitude':'-43.257964','longitude':'-45.147686','tags':['et','incididunt','esse','commodo','ipsum'],'greeting':'Hello, Rosanne! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed632b1a1d65501d6b','index':99,'guid':'bf8c6ac1-ee18-48ee-ae94-ea515a53c951','isActive':true,'balance':'$2,905.58','picture':'http://placehold.it/32x32','age':21,'eyeColor':'blue','name':{'first':'Irene','last':'Castro'},'company':'POLARIA','email':'irene.castro@polaria.org','phone':'+1 (818) 417-3761','address':'901 Dupont Street, Sperryville, Oklahoma, 953','about':'Pariatur minim laboris aliqua dolor aliquip consequat ea do duis voluptate id Lorem. In reprehenderit et adipisicing anim elit incididunt velit in laborum laborum. Qui minim magna et amet sit do voluptate reprehenderit ea sit sint velit.','registered':'Tuesday, August 18, 2015 10:48 AM','latitude':'-7.004055','longitude':'116.052433','tags':['sit','proident','enim','ullamco','non'],'greeting':'Hello, Irene! You have 10 unread messages.','favoriteFruit':'apple'}]"
+  }
+}
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-long-line/plan.log b/v1.5.7/internal/backend/remote/testdata/plan-long-line/plan.log
new file mode 100644
index 0000000..f34ed17
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-long-line/plan.log
@@ -0,0 +1,23 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id:                 <computed>
+      triggers.%:         "1"
+      triggers.long_line: "[{'_id':'5c5ab0ed7de45e993ffb9eeb','index':0,'guid':'e734d772-6b5a-4cb0-805c-91cd5e560e20','isActive':false,'balance':'$1,472.03','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Darlene','last':'Garza'},'company':'GEEKOSIS','email':'darlene.garza@geekosis.io','phone':'+1 (850) 506-3347','address':'165 Kiely Place, Como, New Mexico, 4335','about':'Officia ullamco et sunt magna voluptate culpa cupidatat ea tempor laboris cupidatat ea anim laboris. Minim enim quis enim esse laborum est veniam. Lorem excepteur elit Lorem cupidatat elit ea anim irure fugiat fugiat sunt mollit. Consectetur ad nulla dolor amet esse occaecat aliquip sit. Magna sit elit adipisicing ut reprehenderit anim exercitation sit quis ea pariatur Lorem magna dolore.','registered':'Wednesday, March 11, 2015 12:58 PM','latitude':'20.729127','longitude':'-127.343593','tags':['minim','in','deserunt','occaecat','fugiat'],'greeting':'Hello, Darlene! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eda9117d15f1c1f112','index':1,'guid':'f0d1eed2-c6a9-4535-8800-d4bd53fe7eee','isActive':true,'balance':'$2,901.90','picture':'http://placehold.it/32x32','age':28,'eyeColor':'brown','name':{'first':'Flora','last':'Short'},'company':'SIGNITY','email':'flora.short@signity.me','phone':'+1 (840) 520-2666','address':'636 Johnson Avenue, Gerber, Wisconsin, 9139','about':'Veniam dolore deserunt Lorem aliqua qui eiusmod. Amet tempor fugiat duis incididunt amet adipisicing. Id ea nisi veniam eiusmod.','registered':'Wednesday, May 2, 2018 5:59 AM','latitude':'-63.267612','longitude':'4.224102','tags':['veniam','incididunt','id','aliqua','reprehenderit'],'greeting':'Hello, Flora! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed83fd574d8041fa16','index':2,'guid':'29499a07-414a-436f-ba62-6634ca16bdcc','isActive':true,'balance':'$2,781.28','picture':'http://placehold.it/32x32','age':22,'eyeColor':'green','name':{'first':'Trevino','last':'Marks'},'company':'KEGULAR','email':'trevino.marks@kegular.com','phone':'+1 (843) 571-2269','address':'200 Alabama Avenue, Grenelefe, Florida, 7963','about':'Occaecat nisi exercitation Lorem mollit laborum magna adipisicing culpa dolor proident dolore. Non consequat ea amet et id mollit incididunt minim anim amet nostrud labore tempor. Proident eu sint commodo nisi consequat voluptate do fugiat proident. Laboris eiusmod veniam non et elit nulla nisi labore incididunt Lorem consequat consectetur voluptate.','registered':'Saturday, January 25, 2014 5:56 AM','latitude':'65.044005','longitude':'-127.454864','tags':['anim','duis','velit','pariatur','enim'],'greeting':'Hello, Trevino! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed784eb6e350ff0a07','index':3,'guid':'40ed47e2-1747-4665-ab59-cdb3630a7642','isActive':true,'balance':'$2,000.78','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Solis','last':'Mckinney'},'company':'QABOOS','email':'solis.mckinney@qaboos.org','phone':'+1 (924) 405-2560','address':'712 Herkimer Court, Klondike, Ohio, 8133','about':'Minim ad anim minim tempor mollit magna tempor et non commodo amet. Nisi cupidatat labore culpa consectetur exercitation laborum adipisicing fugiat officia adipisicing consequat non. Qui voluptate tempor laboris exercitation qui non adipisicing occaecat voluptate sunt do nostrud velit. Consequat tempor officia laboris tempor irure cupidatat aliquip voluptate nostrud velit ex nulla tempor laboris. Qui pariatur pariatur enim aliquip velit. Officia mollit ullamco laboris velit velit eiusmod enim amet incididunt consectetur sunt.','registered':'Wednesday, April 12, 2017 6:59 AM','latitude':'-25.055596','longitude':'-140.126525','tags':['ipsum','adipisicing','amet','nulla','dolore'],'greeting':'Hello, Solis! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed02ce1ea9a2155d51','index':4,'guid':'1b5fb7d3-3b9a-4382-81b5-9ab01a27e74b','isActive':true,'balance':'$1,373.67','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Janell','last':'Battle'},'company':'GEEKMOSIS','email':'janell.battle@geekmosis.net','phone':'+1 (810) 591-3014','address':'517 Onderdonk Avenue, Shrewsbury, District Of Columbia, 2335','about':'Reprehenderit ad proident do anim qui officia magna magna duis cillum esse minim est. Excepteur ipsum anim ad laboris. In occaecat dolore nulla ea Lorem tempor et culpa in sint. Officia eu eu incididunt sit amet. Culpa duis id reprehenderit ut anim sit sunt. Duis dolore proident velit incididunt adipisicing pariatur fugiat incididunt eiusmod eu veniam irure.','registered':'Thursday, February 8, 2018 1:44 AM','latitude':'-33.254864','longitude':'-154.145885','tags':['aute','deserunt','ipsum','eiusmod','laborum'],'greeting':'Hello, Janell! You have 5 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edab58604bd7d3dd1c','index':5,'guid':'6354c035-af22-44c9-8be9-b2ea9decc24d','isActive':true,'balance':'$3,535.68','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Combs','last':'Kirby'},'company':'LUXURIA','email':'combs.kirby@luxuria.name','phone':'+1 (900) 498-3266','address':'377 Kingsland Avenue, Ruckersville, Maine, 9916','about':'Lorem duis ipsum pariatur aliquip sunt. Commodo esse laborum incididunt mollit quis est laboris ea ea quis fugiat. Enim elit ullamco velit et fugiat veniam irure deserunt aliqua ad irure veniam.','registered':'Tuesday, February 21, 2017 4:04 PM','latitude':'-70.20591','longitude':'162.546871','tags':['reprehenderit','est','enim','aute','ad'],'greeting':'Hello, Combs! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edf7fafeffc6357c51','index':6,'guid':'02523e0b-cc90-4309-b6b2-f493dc6076f6','isActive':false,'balance':'$3,754.30','picture':'http://placehold.it/32x32','age':29,'eyeColor':'green','name':{'first':'Macias','last':'Calderon'},'company':'AMTAP','email':'macias.calderon@amtap.us','phone':'+1 (996) 569-3667','address':'305 Royce Street, Glidden, Iowa, 9248','about':'Exercitation nulla deserunt pariatur adipisicing. In commodo deserunt incididunt ut velit minim qui ut quis. Labore elit ullamco eiusmod voluptate in eu do est fugiat aute mollit deserunt. Eu duis proident velit fugiat velit ut. Ut non esse amet laborum nisi tempor in nulla.','registered':'Thursday, October 23, 2014 10:28 PM','latitude':'32.371629','longitude':'60.155135','tags':['commodo','elit','velit','excepteur','aliqua'],'greeting':'Hello, Macias! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed0e8a6109e7fabf17','index':7,'guid':'675ff6b6-197b-4154-9775-813d661df822','isActive':false,'balance':'$2,850.62','picture':'http://placehold.it/32x32','age':37,'eyeColor':'green','name':{'first':'Stefanie','last':'Rivers'},'company':'RECRITUBE','email':'stefanie.rivers@recritube.biz','phone':'+1 (994) 591-3551','address':'995 Campus Road, Abrams, Virginia, 3251','about':'Esse aute non laborum Lorem nulla irure. Veniam elit aute ut et dolor non deserunt laboris tempor. Ipsum quis cupidatat laborum laboris voluptate esse duis eiusmod excepteur consectetur commodo ullamco qui occaecat. Culpa velit cillum occaecat minim nisi.','registered':'Thursday, June 9, 2016 3:40 PM','latitude':'-18.526825','longitude':'149.670782','tags':['occaecat','sunt','reprehenderit','ipsum','magna'],'greeting':'Hello, Stefanie! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edf7d9bc2db4e476e3','index':8,'guid':'adaefc55-f6ea-4bd1-a147-0e31c3ce7a21','isActive':true,'balance':'$2,555.13','picture':'http://placehold.it/32x32','age':20,'eyeColor':'blue','name':{'first':'Hillary','last':'Lancaster'},'company':'OLUCORE','email':'hillary.lancaster@olucore.ca','phone':'+1 (964) 474-3018','address':'232 Berriman Street, Kaka, Massachusetts, 6792','about':'Veniam ad laboris quis reprehenderit aliquip nisi sunt excepteur ea aute laborum excepteur incididunt. Nisi exercitation aliquip do culpa commodo ex officia ut enim mollit in deserunt in amet. Anim eu deserunt dolore non cupidatat ut enim incididunt aute dolore voluptate. Do cillum mollit laborum non incididunt occaecat aute voluptate nisi irure.','registered':'Thursday, June 4, 2015 9:45 PM','latitude':'88.075919','longitude':'-148.951368','tags':['reprehenderit','veniam','ad','aute','anim'],'greeting':'Hello, Hillary! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed7b7192ad6a0f267c','index':9,'guid':'0ca9b8ea-f671-474e-be26-4a49cae4838a','isActive':true,'balance':'$3,684.51','picture':'http://placehold.it/32x32','age':40,'eyeColor':'brown','name':{'first':'Jill','last':'Conner'},'company':'EXOZENT','email':'jill.conner@exozent.info','phone':'+1 (887) 467-2168','address':'751 Thames Street, Juarez, American Samoa, 8386','about':'Enim voluptate et non est in magna laborum aliqua enim aliqua est non nostrud. Tempor est nulla ipsum consectetur esse nostrud est id. Consequat do voluptate cupidatat eu fugiat et fugiat velit id. Sint dolore ad qui tempor anim eu amet consectetur do elit aute adipisicing consequat ex.','registered':'Sunday, October 22, 2017 7:35 AM','latitude':'84.384911','longitude':'40.305648','tags':['tempor','sint','irure','et','ex'],'greeting':'Hello, Jill! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed713fe676575aa72b','index':10,'guid':'c28023cf-cc57-4c2e-8d91-dfbe6bafadcd','isActive':false,'balance':'$2,792.45','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Hurley','last':'George'},'company':'ZAJ','email':'hurley.george@zaj.tv','phone':'+1 (984) 547-3284','address':'727 Minna Street, Lacomb, Colorado, 2557','about':'Ex velit cupidatat veniam culpa. Eiusmod ut fugiat adipisicing incididunt consectetur exercitation Lorem exercitation ex. Incididunt anim aute incididunt fugiat cupidatat qui eu non reprehenderit. Eiusmod dolor nisi culpa excepteur ut velit minim dolor voluptate amet commodo culpa in.','registered':'Thursday, February 16, 2017 6:41 AM','latitude':'25.989949','longitude':'10.200053','tags':['minim','ut','sunt','consequat','ullamco'],'greeting':'Hello, Hurley! You have 8 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1e56732746c70d8b','index':11,'guid':'e9766f13-766c-4450-b4d2-8b04580f60b7','isActive':true,'balance':'$3,874.26','picture':'http://placehold.it/32x32','age':35,'eyeColor':'green','name':{'first':'Leticia','last':'Pace'},'company':'HONOTRON','email':'leticia.pace@honotron.co.uk','phone':'+1 (974) 536-3322','address':'365 Goodwin Place, Savage, Nevada, 9191','about':'Nisi Lorem aliqua esse eiusmod magna. Ad minim incididunt proident ut Lorem cupidatat qui velit aliqua ullamco et ipsum in. Aliquip elit consectetur pariatur esse exercitation et officia quis. Occaecat tempor proident cillum anim ad commodo velit ut voluptate. Tempor et occaecat sit sint aliquip tempor nulla velit magna nisi proident exercitation Lorem id.','registered':'Saturday, August 4, 2018 5:05 AM','latitude':'70.620386','longitude':'-86.335813','tags':['occaecat','velit','labore','laboris','esse'],'greeting':'Hello, Leticia! You have 8 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed941337fe42f47426','index':12,'guid':'6d390762-17ea-4b58-9a36-b0c9a8748a42','isActive':true,'balance':'$1,049.61','picture':'http://placehold.it/32x32','age':38,'eyeColor':'green','name':{'first':'Rose','last':'Humphrey'},'company':'MYOPIUM','email':'rose.humphrey@myopium.io','phone':'+1 (828) 426-3086','address':'389 Sapphire Street, Saticoy, Marshall Islands, 1423','about':'Aliquip enim excepteur adipisicing ex. Consequat aliqua consequat nostrud do occaecat deserunt excepteur sit et ipsum sunt dolor eu. Dolore laborum commodo excepteur tempor ad adipisicing proident excepteur magna non Lorem proident consequat aute. Fugiat minim consequat occaecat voluptate esse velit officia laboris nostrud nisi ut voluptate.','registered':'Monday, April 16, 2018 12:38 PM','latitude':'-47.083742','longitude':'109.022423','tags':['aute','non','sit','adipisicing','mollit'],'greeting':'Hello, Rose! You have 9 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd0c02fc3fdc01a40','index':13,'guid':'07755618-6fdf-4b33-af50-364c18909227','isActive':true,'balance':'$1,823.61','picture':'http://placehold.it/32x32','age':36,'eyeColor':'green','name':{'first':'Judith','last':'Hale'},'company':'COLLAIRE','email':'judith.hale@collaire.me','phone':'+1 (922) 508-2843','address':'193 Coffey Street, Castleton, North Dakota, 3638','about':'Minim non ullamco ad anim nostrud dolore nostrud veniam consequat id eiusmod veniam laboris. Lorem irure esse mollit non velit aute id cupidatat est mollit occaecat magna excepteur. Adipisicing tempor nisi sit aliquip tempor pariatur tempor eu consectetur nulla amet nulla. Quis nisi nisi ea incididunt culpa et do. Esse officia eu pariatur velit sunt quis proident amet consectetur consequat. Nisi excepteur culpa nulla sit dolor deserunt excepteur dolor consequat elit cillum tempor Lorem.','registered':'Wednesday, August 24, 2016 12:29 AM','latitude':'-80.15514','longitude':'39.91007','tags':['consectetur','incididunt','aliquip','dolor','consequat'],'greeting':'Hello, Judith! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edb3e1e29caa4f728b','index':14,'guid':'2c6617a2-e7a9-4ff7-a8b9-e99554fe70fe','isActive':true,'balance':'$1,971.00','picture':'http://placehold.it/32x32','age':39,'eyeColor':'blue','name':{'first':'Estes','last':'Sweet'},'company':'GEEKKO','email':'estes.sweet@geekko.com','phone':'+1 (866) 448-3032','address':'847 Cove Lane, Kula, Mississippi, 9178','about':'Veniam consectetur occaecat est excepteur consequat ipsum cillum sit consectetur. Ut cupidatat et reprehenderit dolore enim do cillum qui pariatur ad laborum incididunt esse. Fugiat sunt dolor veniam laboris ipsum deserunt proident reprehenderit laboris non nostrud. Magna excepteur sint magna laborum tempor sit exercitation ipsum labore est ullamco ullamco. Cillum voluptate cillum ea laborum Lorem. Excepteur sint ut nisi est esse non. Minim excepteur ullamco velit nisi ut in elit exercitation ut dolore.','registered':'Sunday, August 12, 2018 5:06 PM','latitude':'-9.57771','longitude':'-159.94577','tags':['culpa','dolor','velit','anim','pariatur'],'greeting':'Hello, Estes! You have 7 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edbcf088c6fd593091','index':15,'guid':'2cc79958-1b40-4e2c-907a-433903fd3da9','isActive':false,'balance':'$3,751.53','picture':'http://placehold.it/32x32','age':34,'eyeColor':'brown','name':{'first':'Kemp','last':'Spence'},'company':'EXOBLUE','email':'kemp.spence@exoblue.org','phone':'+1 (864) 487-2992','address':'217 Clay Street, Monument, North Carolina, 1460','about':'Nostrud duis cillum sint non commodo dolor aute aliqua adipisicing ad nulla non excepteur proident. Fugiat labore elit tempor cillum veniam reprehenderit laboris consectetur dolore amet qui cupidatat. Amet aliqua elit anim et consequat commodo excepteur officia anim aliqua ea eu labore cillum. Et ex dolor duis dolore commodo veniam et nisi.','registered':'Monday, October 29, 2018 5:23 AM','latitude':'-70.304222','longitude':'83.582371','tags':['velit','duis','consequat','incididunt','duis'],'greeting':'Hello, Kemp! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed6400479feb3de505','index':16,'guid':'91ccae6d-a3ea-43cf-bb00-3f2729256cc9','isActive':false,'balance':'$2,477.79','picture':'http://placehold.it/32x32','age':40,'eyeColor':'blue','name':{'first':'Ronda','last':'Burris'},'company':'EQUITOX','email':'ronda.burris@equitox.net','phone':'+1 (817) 553-3228','address':'708 Lawton Street, Deputy, Wyoming, 8598','about':'Excepteur voluptate aliquip consequat cillum est duis sit cillum eu eiusmod et laborum ullamco. Et minim reprehenderit aute voluptate amet ullamco. Amet sit enim ad irure deserunt nostrud anim veniam consequat dolor commodo. Consequat do occaecat do exercitation ullamco dolor ut. Id laboris consequat est dolor dolore tempor ullamco anim do ut nulla deserunt labore. Mollit ex Lorem ullamco mollit.','registered':'Monday, April 23, 2018 5:27 PM','latitude':'-31.227208','longitude':'0.63785','tags':['ipsum','magna','consectetur','sit','irure'],'greeting':'Hello, Ronda! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eddbeab2e53e04d563','index':17,'guid':'a86d4eb6-6bd8-48c2-a8fc-1c933c835852','isActive':false,'balance':'$3,709.03','picture':'http://placehold.it/32x32','age':37,'eyeColor':'blue','name':{'first':'Rosario','last':'Dillard'},'company':'BARKARAMA','email':'rosario.dillard@barkarama.name','phone':'+1 (933) 525-3898','address':'730 Chauncey Street, Forbestown, South Carolina, 6894','about':'Est eu fugiat aliquip ea ad qui ad mollit ad tempor voluptate et incididunt reprehenderit. Incididunt fugiat commodo minim adipisicing culpa consectetur duis eu ut commodo consequat voluptate labore. Nostrud irure labore adipisicing irure quis magna consequat dolor Lorem sint enim. Sint excepteur eu dolore elit ut do mollit sunt enim est. Labore id nostrud sint Lorem esse nostrud.','registered':'Friday, December 25, 2015 8:59 PM','latitude':'37.440827','longitude':'44.580474','tags':['Lorem','sit','ipsum','ea','ut'],'greeting':'Hello, Rosario! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eddf8e9b9c031d04e8','index':18,'guid':'a96f997c-daf8-40d4-92e1-be07e2cf0f60','isActive':false,'balance':'$1,878.37','picture':'http://placehold.it/32x32','age':37,'eyeColor':'brown','name':{'first':'Sondra','last':'Gonzales'},'company':'XUMONK','email':'sondra.gonzales@xumonk.us','phone':'+1 (838) 560-2255','address':'230 Cox Place, Geyserville, Georgia, 6805','about':'Laborum sunt voluptate ea laboris nostrud. Amet deserunt aliqua Lorem voluptate velit deserunt occaecat minim ullamco. Lorem occaecat sit labore adipisicing ad magna mollit labore ullamco proident. Ea velit do proident fugiat esse commodo ex nostrud eu mollit pariatur. Labore laborum qui voluptate quis proident reprehenderit tempor dolore duis deserunt esse aliqua aliquip. Non veniam enim pariatur cupidatat ipsum dolore est reprehenderit. Non exercitation adipisicing proident magna elit occaecat non magna.','registered':'Sunday, June 26, 2016 4:02 AM','latitude':'62.247742','longitude':'-44.90666','tags':['ea','aute','in','voluptate','magna'],'greeting':'Hello, Sondra! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed2c1bcd06781f677e','index':19,'guid':'6ac47a16-eed4-4460-92ee-e0dd33c1fbb5','isActive':false,'balance':'$3,730.64','picture':'http://placehold.it/32x32','age':20,'eyeColor':'brown','name':{'first':'Anastasia','last':'Vega'},'company':'FIREWAX','email':'anastasia.vega@firewax.biz','phone':'+1 (867) 493-3698','address':'803 Arlington Avenue, Rosburg, Northern Mariana Islands, 8769','about':'Sint ex nisi tempor sunt voluptate non et eiusmod irure. Aute reprehenderit dolor mollit aliqua Lorem voluptate occaecat. Sint laboris deserunt Lorem incididunt nulla cupidatat do.','registered':'Friday, March 18, 2016 12:02 PM','latitude':'-32.010216','longitude':'-87.874753','tags':['aliquip','mollit','mollit','ad','laborum'],'greeting':'Hello, Anastasia! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed727fd645854bbf43','index':20,'guid':'67bd8cdb-ce6b-455c-944c-a80e17c6fa75','isActive':true,'balance':'$2,868.06','picture':'http://placehold.it/32x32','age':29,'eyeColor':'green','name':{'first':'Lucinda','last':'Cox'},'company':'ENDIPINE','email':'lucinda.cox@endipine.ca','phone':'+1 (990) 428-3002','address':'412 Thatford Avenue, Lafferty, New Jersey, 5271','about':'Esse nulla sunt ut consequat aute mollit. Est occaecat sunt nisi irure id anim est commodo. Elit mollit amet dolore sunt adipisicing ea laborum quis ea reprehenderit non consequat dolore. Minim sunt occaecat quis aute commodo dolore quis commodo proident. Sunt sint duis ullamco sit ea esse Lorem. Consequat pariatur eiusmod laboris adipisicing labore in laboris adipisicing adipisicing consequat aute ea et.','registered':'Friday, May 1, 2015 10:16 PM','latitude':'-14.200957','longitude':'-82.211386','tags':['do','sit','qui','officia','aliquip'],'greeting':'Hello, Lucinda! You have 9 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed5a97284eb2cbd3a8','index':21,'guid':'f9fc999d-515c-4fc4-b339-76300e1b4bf2','isActive':true,'balance':'$1,172.57','picture':'http://placehold.it/32x32','age':35,'eyeColor':'brown','name':{'first':'Conrad','last':'Bradley'},'company':'FUELWORKS','email':'conrad.bradley@fuelworks.info','phone':'+1 (956) 561-3226','address':'685 Fenimore Street, Esmont, Maryland, 7523','about':'Labore reprehenderit anim nisi sunt do nisi in. Est anim cillum id minim exercitation ullamco voluptate ipsum eu. Elit culpa consequat reprehenderit laborum in eu. Laboris amet voluptate laboris qui voluptate duis minim reprehenderit. Commodo sunt irure dolore sunt occaecat velit nisi eu minim minim.','registered':'Wednesday, January 18, 2017 11:13 PM','latitude':'31.665993','longitude':'38.868968','tags':['excepteur','exercitation','est','nisi','mollit'],'greeting':'Hello, Conrad! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edc4eaf6f760c38218','index':22,'guid':'8794ef5f-da2f-46f0-a755-c18a16409fd5','isActive':false,'balance':'$3,594.73','picture':'http://placehold.it/32x32','age':27,'eyeColor':'blue','name':{'first':'Marquez','last':'Vargas'},'company':'MALATHION','email':'marquez.vargas@malathion.tv','phone':'+1 (976) 438-3126','address':'296 Hall Street, National, Texas, 2067','about':'Proident cillum aute minim fugiat sunt aliqua non occaecat est duis id id tempor. Qui deserunt nisi amet pariatur proident eu laboris esse adipisicing magna. Anim anim mollit aute non magna nisi aute magna labore ullamco reprehenderit voluptate et ad. Proident adipisicing aute eiusmod nostrud nostrud deserunt culpa. Elit eu ullamco nisi aliqua dolor sint pariatur excepteur sit consectetur tempor. Consequat Lorem ullamco commodo veniam qui sint magna. Sit mollit ad aliquip est id eu officia id adipisicing duis ad.','registered':'Tuesday, November 17, 2015 6:16 PM','latitude':'-36.443667','longitude':'22.336776','tags':['aliquip','veniam','ipsum','Lorem','ex'],'greeting':'Hello, Marquez! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edd7c718518ee0466a','index':23,'guid':'ad8781a2-059e-4288-9879-309d53a99bf5','isActive':true,'balance':'$3,570.68','picture':'http://placehold.it/32x32','age':21,'eyeColor':'brown','name':{'first':'Snider','last':'Frost'},'company':'ZILODYNE','email':'snider.frost@zilodyne.co.uk','phone':'+1 (913) 485-3275','address':'721 Lincoln Road, Richmond, Utah, 672','about':'Minim enim Lorem esse incididunt do reprehenderit velit laborum ullamco. In aute eiusmod esse aliqua et labore tempor sunt ex mollit veniam tempor. Nulla elit cillum qui ullamco dolore amet deserunt magna amet laborum.','registered':'Saturday, August 23, 2014 12:58 AM','latitude':'-88.682554','longitude':'74.063179','tags':['nulla','ea','sint','aliquip','duis'],'greeting':'Hello, Snider! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edf026fece8e2c0970','index':24,'guid':'1b7d81e1-1dba-4322-bb1a-eaa6a24cccea','isActive':false,'balance':'$2,037.91','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Snyder','last':'Fletcher'},'company':'COMTEST','email':'snyder.fletcher@comtest.io','phone':'+1 (830) 538-3860','address':'221 Lewis Place, Zortman, Idaho, 572','about':'Elit anim enim esse dolore exercitation. Laboris esse sint adipisicing fugiat sint do occaecat ut voluptate sint nulla. Ad sint ut reprehenderit nostrud irure id consectetur officia velit consequat.','registered':'Sunday, January 1, 2017 1:13 AM','latitude':'-54.742604','longitude':'69.534932','tags':['exercitation','commodo','in','id','aliqua'],'greeting':'Hello, Snyder! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed4b9a7f83da6d2dfd','index':25,'guid':'0b2cc6b6-0044-4b1c-aa31-bd72963457a0','isActive':false,'balance':'$1,152.76','picture':'http://placehold.it/32x32','age':27,'eyeColor':'blue','name':{'first':'Regina','last':'James'},'company':'TELPOD','email':'regina.james@telpod.me','phone':'+1 (989) 455-3228','address':'688 Essex Street, Clayville, Alabama, 2772','about':'Eiusmod elit culpa reprehenderit ea veniam. Officia irure culpa duis aute ut. Irure duis cillum officia ea pariatur velit ut dolor incididunt reprehenderit ex elit laborum. Est pariatur veniam ad irure. Labore velit sunt esse laboris aliqua velit deserunt deserunt sit. Elit eiusmod ad laboris aliquip minim irure excepteur enim quis. Quis incididunt adipisicing ut magna cupidatat sit amet culpa.','registered':'Tuesday, April 25, 2017 10:16 PM','latitude':'-75.088027','longitude':'47.209828','tags':['elit','nisi','est','voluptate','proident'],'greeting':'Hello, Regina! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed10884f32f779f2bf','index':26,'guid':'1f6fb522-0002-46ff-8dac-451247f28168','isActive':true,'balance':'$1,948.79','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Collins','last':'Mcpherson'},'company':'DIGIGEN','email':'collins.mcpherson@digigen.com','phone':'+1 (991) 519-2334','address':'317 Merit Court, Sanford, Michigan, 6468','about':'Magna qui culpa dolor officia labore mollit ex excepteur duis eiusmod. Ea cupidatat ex ipsum mollit do minim duis. Nisi eiusmod minim tempor id esse commodo sunt sunt ullamco ut do laborum ullamco magna. Aliquip laborum dolor officia officia eu nostrud velit minim est anim. Ex elit laborum sunt magna exercitation nisi cillum sunt aute qui ea ullamco. Cupidatat ea sunt aute dolor duis nisi Lorem ullamco eiusmod. Sit ea velit ad veniam aliqua ad elit cupidatat ut magna in.','registered':'Friday, June 10, 2016 4:38 PM','latitude':'25.513996','longitude':'14.911124','tags':['exercitation','non','sit','velit','officia'],'greeting':'Hello, Collins! You have 5 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed8a575110efb15c6c','index':27,'guid':'2a904c82-068b-4ded-9ae6-cfeb6d7e62c9','isActive':true,'balance':'$3,427.91','picture':'http://placehold.it/32x32','age':24,'eyeColor':'green','name':{'first':'Mckay','last':'Barrera'},'company':'COMVEYER','email':'mckay.barrera@comveyer.org','phone':'+1 (853) 470-2560','address':'907 Glenwood Road, Churchill, Oregon, 8583','about':'In voluptate esse dolore enim sint quis dolor do exercitation sint et labore nisi. Eiusmod tempor exercitation dolore elit sit velit sint et. Sit magna adipisicing eiusmod do anim velit deserunt laboris ad ea pariatur. Irure nisi anim mollit elit commodo nulla. Aute eiusmod sit nulla eiusmod. Eiusmod est officia commodo mollit laboris do deserunt eu do nisi amet. Proident ad duis eiusmod laboris Lorem ut culpa pariatur Lorem reprehenderit minim aliquip irure sunt.','registered':'Saturday, December 19, 2015 2:49 PM','latitude':'-55.243287','longitude':'138.035406','tags':['non','quis','laboris','enim','nisi'],'greeting':'Hello, Mckay! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edcd49ab6a73ff7f32','index':28,'guid':'5d3e0dae-3f58-437f-b12d-de24667a904d','isActive':true,'balance':'$3,270.52','picture':'http://placehold.it/32x32','age':35,'eyeColor':'blue','name':{'first':'Mabel','last':'Leonard'},'company':'QUADEEBO','email':'mabel.leonard@quadeebo.net','phone':'+1 (805) 432-2356','address':'965 Underhill Avenue, Falconaire, Minnesota, 4450','about':'Cupidatat amet sunt est ipsum occaecat sit fugiat excepteur Lorem Lorem ex ea ipsum. Ad incididunt est irure magna excepteur occaecat nostrud. Minim dolor id anim ipsum qui nostrud ullamco aute ex Lorem magna deserunt excepteur Lorem.','registered':'Saturday, March 28, 2015 5:55 AM','latitude':'27.388359','longitude':'156.408728','tags':['quis','velit','deserunt','dolore','sit'],'greeting':'Hello, Mabel! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edde16ac2dc2fbb6c1','index':29,'guid':'d50c2233-70fc-4748-8ebf-02d45ac2a446','isActive':false,'balance':'$3,100.70','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Pace','last':'Duke'},'company':'SEQUITUR','email':'pace.duke@sequitur.name','phone':'+1 (983) 568-3119','address':'895 Melrose Street, Reno, Connecticut, 6259','about':'Ex veniam aliquip exercitation mollit elit est minim veniam aliqua labore deserunt. Dolor sunt sint cillum Lorem nisi ea irure cupidatat. Velit ut culpa cupidatat consequat cillum. Sint voluptate quis laboris qui incididunt do elit Lorem qui ullamco ut eu pariatur occaecat.','registered':'Saturday, August 18, 2018 2:18 PM','latitude':'31.930443','longitude':'-129.494784','tags':['culpa','est','nostrud','quis','aliquip'],'greeting':'Hello, Pace! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edb908d85642ba77e8','index':30,'guid':'3edb6e42-367a-403d-a511-eb78bcc11f60','isActive':true,'balance':'$1,912.07','picture':'http://placehold.it/32x32','age':24,'eyeColor':'green','name':{'first':'Cohen','last':'Morrison'},'company':'POWERNET','email':'cohen.morrison@powernet.us','phone':'+1 (888) 597-2141','address':'565 Troutman Street, Idledale, West Virginia, 3196','about':'Ullamco voluptate duis commodo amet occaecat consequat et occaecat dolore nulla eu. Do aliqua sunt deserunt occaecat laboris labore voluptate cupidatat ullamco exercitation aliquip elit voluptate anim. Occaecat deserunt in labore cillum aute deserunt ea excepteur laboris sunt. Officia irure sint incididunt labore sint ipsum ullamco ea elit. Fugiat nostrud sunt ut officia mollit proident sunt dolor fugiat esse tempor do.','registered':'Friday, January 1, 2016 5:42 AM','latitude':'-20.01215','longitude':'26.361552','tags':['consectetur','sunt','nulla','reprehenderit','dolore'],'greeting':'Hello, Cohen! You have 10 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed91c77aa25a64a757','index':31,'guid':'8999a97b-0035-4f19-b555-91dd69aaa9b8','isActive':false,'balance':'$3,097.67','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Stout','last':'Valdez'},'company':'UPLINX','email':'stout.valdez@uplinx.biz','phone':'+1 (854) 480-3633','address':'880 Chestnut Avenue, Lowgap, Hawaii, 1537','about':'Cupidatat enim dolore non voluptate. Aliqua ut non Lorem in exercitation reprehenderit voluptate. Excepteur deserunt tempor laboris quis.','registered':'Wednesday, March 16, 2016 6:53 AM','latitude':'50.328393','longitude':'-25.990308','tags':['ea','fugiat','duis','consectetur','enim'],'greeting':'Hello, Stout! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed0f52176c8c3e1bed','index':32,'guid':'743abcbd-1fab-4aed-8cb7-3c935eb64c74','isActive':false,'balance':'$1,118.54','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Ortega','last':'Joseph'},'company':'APEXIA','email':'ortega.joseph@apexia.ca','phone':'+1 (872) 596-3024','address':'304 Canda Avenue, Mulino, New York, 8721','about':'Ipsum elit id cupidatat minim nisi minim. Ea ex amet ea ipsum Lorem deserunt. Occaecat cupidatat magna cillum aliquip sint id quis amet nostrud officia enim laborum. Aliqua deserunt amet commodo laboris labore mollit est. Officia voluptate Lorem esse mollit aliquip laboris cupidatat minim et. Labore esse incididunt officia nostrud pariatur reprehenderit.','registered':'Tuesday, January 31, 2017 6:06 AM','latitude':'43.861714','longitude':'33.771783','tags':['ut','Lorem','esse','quis','fugiat'],'greeting':'Hello, Ortega! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed2c00cdd101b6cd52','index':33,'guid':'4f6f99cf-f692-4d03-b23a-26f2b27273bd','isActive':true,'balance':'$1,682.91','picture':'http://placehold.it/32x32','age':20,'eyeColor':'blue','name':{'first':'Sampson','last':'Taylor'},'company':'GEOFORMA','email':'sampson.taylor@geoforma.info','phone':'+1 (911) 482-2993','address':'582 Kent Street, Umapine, Virgin Islands, 5300','about':'Voluptate laboris occaecat laboris tempor cillum quis cupidatat qui pariatur. Lorem minim commodo mollit adipisicing Lorem ut dolor consectetur ipsum. Sint sit voluptate labore aliqua ex labore velit. Ullamco tempor consectetur voluptate deserunt voluptate minim enim. Cillum commodo duis reprehenderit eu duis.','registered':'Thursday, November 9, 2017 11:24 PM','latitude':'24.949379','longitude':'155.034468','tags':['Lorem','cupidatat','elit','reprehenderit','commodo'],'greeting':'Hello, Sampson! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed4b7210ba0bc0d508','index':34,'guid':'73fd415f-f8cf-43e0-a86c-e725d000abd4','isActive':false,'balance':'$1,289.37','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Shari','last':'Melendez'},'company':'DIGIPRINT','email':'shari.melendez@digiprint.tv','phone':'+1 (914) 475-3995','address':'950 Wolf Place, Enetai, Alaska, 693','about':'Dolor incididunt et est commodo aliquip labore ad ullamco. Velit ex cillum nulla elit ex esse. Consectetur mollit fugiat cillum proident elit sunt non officia cillum ex laboris sint eu. Esse nulla eu officia in Lorem sint minim esse velit. Est Lorem ipsum enim aute. Elit minim eiusmod officia reprehenderit officia ut irure Lorem.','registered':'Wednesday, August 23, 2017 11:12 PM','latitude':'-70.347863','longitude':'94.812072','tags':['ea','ex','fugiat','duis','eu'],'greeting':'Hello, Shari! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed85ac364619d892ef','index':35,'guid':'c1905f34-14ff-4bd8-b683-02cac4d52623','isActive':false,'balance':'$2,538.50','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Santiago','last':'Joyner'},'company':'BRAINCLIP','email':'santiago.joyner@brainclip.co.uk','phone':'+1 (835) 405-2676','address':'554 Rose Street, Muir, Kentucky, 7752','about':'Quis culpa dolore fugiat magna culpa non deserunt consectetur elit. Id cupidatat occaecat duis irure ullamco elit in labore magna pariatur cillum est. Mollit dolore velit ipsum anim aliqua culpa sint. Occaecat aute anim ut sunt eu.','registered':'Thursday, January 18, 2018 4:49 PM','latitude':'57.057918','longitude':'-50.472596','tags':['ullamco','ullamco','sunt','voluptate','irure'],'greeting':'Hello, Santiago! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1763f56b1121fa88','index':36,'guid':'a7f50659-4ae3-4f3e-a9d8-087e05334b51','isActive':false,'balance':'$1,435.16','picture':'http://placehold.it/32x32','age':37,'eyeColor':'blue','name':{'first':'Adeline','last':'Hoffman'},'company':'BITREX','email':'adeline.hoffman@bitrex.io','phone':'+1 (823) 488-3201','address':'221 Corbin Place, Edmund, Palau, 193','about':'Magna ullamco consectetur velit adipisicing cillum ea. Est qui incididunt est ullamco ex aute exercitation irure. Cupidatat consectetur proident qui fugiat do. Labore magna aliqua consectetur fugiat. Excepteur deserunt sit qui dolor fugiat aute sunt anim ipsum magna ea commodo qui. Minim eu adipisicing ut irure excepteur eiusmod aliqua. Voluptate nisi ad consequat qui.','registered':'Tuesday, June 14, 2016 9:26 AM','latitude':'-53.123355','longitude':'88.180776','tags':['non','est','commodo','ut','aliquip'],'greeting':'Hello, Adeline! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed945d079f63e3185e','index':37,'guid':'1f4619e0-9289-4bea-a9db-a75f4cba1138','isActive':true,'balance':'$2,019.54','picture':'http://placehold.it/32x32','age':36,'eyeColor':'blue','name':{'first':'Porter','last':'Morse'},'company':'COMVOY','email':'porter.morse@comvoy.me','phone':'+1 (933) 562-3220','address':'416 India Street, Bourg, Rhode Island, 2266','about':'Et sint anim et sunt. Non mollit sunt cillum veniam sunt sint amet non mollit. Fugiat ea ullamco pariatur deserunt ex do minim irure irure.','registered':'Saturday, July 16, 2016 10:03 PM','latitude':'-81.782545','longitude':'69.783509','tags':['irure','consequat','veniam','nulla','velit'],'greeting':'Hello, Porter! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed411dd0f06c66bba6','index':38,'guid':'93c900f0-54c0-4c4c-b21d-d59d8d7c6177','isActive':true,'balance':'$3,764.84','picture':'http://placehold.it/32x32','age':26,'eyeColor':'green','name':{'first':'Fitzgerald','last':'Logan'},'company':'UTARIAN','email':'fitzgerald.logan@utarian.com','phone':'+1 (815) 461-2709','address':'498 Logan Street, Tonopah, Arkansas, 6652','about':'Quis Lorem sit est et dolor est esse in veniam. Mollit anim nostrud laboris consequat voluptate qui ad ipsum sint laborum exercitation quis ipsum. Incididunt cupidatat esse ea amet deserunt consequat eu proident duis adipisicing pariatur. Amet deserunt mollit aliquip mollit consequat sunt quis labore laboris quis. Magna cillum fugiat anim velit Lorem duis. Lorem duis amet veniam occaecat est excepteur ut ea velit esse non pariatur. Do veniam quis eu consequat ad duis incididunt minim dolore sit non minim adipisicing et.','registered':'Wednesday, August 9, 2017 9:20 PM','latitude':'24.480657','longitude':'-108.693421','tags':['dolore','ad','occaecat','quis','labore'],'greeting':'Hello, Fitzgerald! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edbb6f14559d8a7b28','index':39,'guid':'9434f48b-70a0-4161-8d06-c53bf8b9df94','isActive':true,'balance':'$3,713.47','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Mcconnell','last':'Nash'},'company':'TETAK','email':'mcconnell.nash@tetak.org','phone':'+1 (956) 477-3586','address':'853 Turnbull Avenue, Clarence, Missouri, 1599','about':'Culpa excepteur minim anim magna dolor dolore ad ex eu. In cupidatat cillum elit dolore in est minim dolore consectetur reprehenderit voluptate laborum. Deserunt id velit ad dolor mollit.','registered':'Saturday, November 10, 2018 9:27 AM','latitude':'1.691589','longitude':'143.704377','tags':['ut','deserunt','sit','cupidatat','ea'],'greeting':'Hello, Mcconnell! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed1a87ea0390733ffa','index':40,'guid':'ec8a55f7-7114-4787-b1ff-4e631731bc2c','isActive':true,'balance':'$2,200.71','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Kitty','last':'Meyers'},'company':'FIBEROX','email':'kitty.meyers@fiberox.net','phone':'+1 (864) 458-3826','address':'537 Georgia Avenue, Thermal, Illinois, 7930','about':'Non excepteur laboris Lorem magna adipisicing exercitation. Anim esse in pariatur minim ipsum qui voluptate irure. Pariatur Lorem pariatur esse commodo aute adipisicing anim commodo. Exercitation nostrud aliqua duis et amet amet tempor.','registered':'Tuesday, September 13, 2016 8:16 PM','latitude':'19.59506','longitude':'-57.814297','tags':['duis','ullamco','velit','sint','consequat'],'greeting':'Hello, Kitty! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed4dc76717bf1217b3','index':41,'guid':'40521cde-f835-4620-902b-af7abf185d8d','isActive':false,'balance':'$2,907.02','picture':'http://placehold.it/32x32','age':26,'eyeColor':'green','name':{'first':'Klein','last':'Goodwin'},'company':'PLASTO','email':'klein.goodwin@plasto.name','phone':'+1 (950) 563-3104','address':'764 Devoe Street, Lindcove, Oklahoma, 458','about':'Amet aliqua magna ea veniam non aliquip irure esse id ipsum cillum sint tempor dolor. Ullamco deserunt fugiat amet pariatur culpa nostrud commodo commodo. Ad occaecat magna adipisicing voluptate. Minim ad adipisicing cupidatat elit nostrud eu irure. Cupidatat occaecat aute magna consectetur dolore anim et. Ex voluptate velit exercitation laborum ad ullamco ad. Aliquip nulla ipsum dolore cillum qui nostrud eu adipisicing amet tempor do.','registered':'Tuesday, February 13, 2018 3:56 PM','latitude':'-27.168725','longitude':'-29.499285','tags':['minim','labore','do','deserunt','dolor'],'greeting':'Hello, Klein! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1ac77396b29aee9e','index':42,'guid':'7cfc03e3-30e9-4ae1-a1f5-f6c3223ca770','isActive':true,'balance':'$2,986.47','picture':'http://placehold.it/32x32','age':22,'eyeColor':'brown','name':{'first':'Isabelle','last':'Bishop'},'company':'GEEKNET','email':'isabelle.bishop@geeknet.us','phone':'+1 (908) 418-2642','address':'729 Willmohr Street, Aguila, Montana, 7510','about':'In nulla commodo nostrud sint. Elit et occaecat et aliqua aliquip magna esse commodo duis Lorem dolor magna enim deserunt. Ipsum pariatur reprehenderit ipsum adipisicing mollit incididunt ut. Sunt in consequat ex ut minim non qui anim labore. Deserunt minim voluptate in nulla occaecat.','registered':'Monday, September 15, 2014 6:22 AM','latitude':'-81.686947','longitude':'38.409291','tags':['proident','est','aliqua','veniam','anim'],'greeting':'Hello, Isabelle! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edb3a070c9469a4893','index':43,'guid':'3dec76b4-0b55-4765-a2fd-b8dbd9c82f8f','isActive':true,'balance':'$2,501.24','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Josefina','last':'Turner'},'company':'COMSTAR','email':'josefina.turner@comstar.biz','phone':'+1 (908) 566-3029','address':'606 Schenck Place, Brutus, Vermont, 8681','about':'Enim consectetur pariatur sint dolor nostrud est deserunt nulla quis pariatur sit. Ad aute incididunt nisi excepteur duis est velit voluptate ullamco occaecat magna reprehenderit aliquip. Proident deserunt consectetur non et exercitation elit dolore enim aliqua incididunt anim amet. Ex esse sint commodo minim aliqua ut irure. Proident ex culpa voluptate fugiat nisi. Sint commodo laboris excepteur minim ipsum labore tempor quis magna.','registered':'Saturday, December 31, 2016 6:38 AM','latitude':'35.275088','longitude':'24.30485','tags':['minim','ut','irure','Lorem','veniam'],'greeting':'Hello, Josefina! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1aa7d74128ee3d0f','index':44,'guid':'10599279-c367-46c4-9f7a-744c2e4bf6c9','isActive':true,'balance':'$1,753.06','picture':'http://placehold.it/32x32','age':27,'eyeColor':'blue','name':{'first':'Lily','last':'Haynes'},'company':'KIOSK','email':'lily.haynes@kiosk.ca','phone':'+1 (872) 451-2301','address':'509 Balfour Place, Grazierville, New Hampshire, 2750','about':'Nisi aliquip occaecat nostrud do sint qui nisi officia Lorem. Ad et et laboris nisi dolore aliqua eu. Aliqua veniam quis eu pariatur incididunt mollit id deserunt officia eiusmod. Consequat adipisicing do nisi voluptate eiusmod minim pariatur minim nisi nostrud culpa cupidatat. Irure consectetur id consequat adipisicing ullamco occaecat do. Ex proident ea quis nulla incididunt sunt excepteur incididunt. Aliquip minim nostrud non anim Lorem.','registered':'Tuesday, November 20, 2018 9:28 AM','latitude':'-12.677798','longitude':'114.506787','tags':['culpa','amet','elit','officia','irure'],'greeting':'Hello, Lily! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed74c76f2e84e201ce','index':45,'guid':'ec0a68d4-629e-46c9-9af7-f6ea867f02ba','isActive':true,'balance':'$1,477.93','picture':'http://placehold.it/32x32','age':23,'eyeColor':'green','name':{'first':'Shauna','last':'Pitts'},'company':'SPACEWAX','email':'shauna.pitts@spacewax.info','phone':'+1 (841) 406-2360','address':'348 Tabor Court, Westwood, Puerto Rico, 8297','about':'Aliquip irure officia magna ea magna mollit ea non amet deserunt. Veniam mollit labore culpa magna aliqua quis consequat est consectetur ea reprehenderit nostrud consequat aliqua. Mollit do ipsum mollit eiusmod.','registered':'Thursday, October 2, 2014 2:48 AM','latitude':'-55.17388','longitude':'-13.370494','tags':['anim','consectetur','cillum','veniam','duis'],'greeting':'Hello, Shauna! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed419e718484b16722','index':46,'guid':'b2d6101d-5646-43f4-8207-284494e5a990','isActive':false,'balance':'$2,006.96','picture':'http://placehold.it/32x32','age':27,'eyeColor':'brown','name':{'first':'Lawrence','last':'Boyer'},'company':'SKYPLEX','email':'lawrence.boyer@skyplex.tv','phone':'+1 (953) 548-2618','address':'464 Pilling Street, Blandburg, Arizona, 5531','about':'Culpa sit minim pariatur mollit cupidatat sunt duis. Nisi ea proident veniam exercitation adipisicing Lorem aliquip amet dolor voluptate in nisi. Non commodo anim sunt est fugiat laborum nisi aliqua non Lorem exercitation dolor. Laboris dolore do minim ut eiusmod enim magna cillum laborum consectetur aliquip minim enim Lorem. Veniam ex veniam occaecat aliquip elit aliquip est eiusmod minim minim adipisicing.','registered':'Wednesday, July 30, 2014 2:17 AM','latitude':'-78.681255','longitude':'139.960626','tags':['consequat','Lorem','incididunt','dolor','esse'],'greeting':'Hello, Lawrence! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed08a9024998292c70','index':47,'guid':'277de142-ebeb-4828-906a-7fd8bc0a738a','isActive':true,'balance':'$1,273.19','picture':'http://placehold.it/32x32','age':27,'eyeColor':'brown','name':{'first':'Sonya','last':'Stafford'},'company':'AQUACINE','email':'sonya.stafford@aquacine.co.uk','phone':'+1 (824) 581-3927','address':'641 Bowery Street, Hillsboro, Delaware, 7893','about':'Culpa labore ex reprehenderit mollit cupidatat dolore et ut quis in. Sint esse culpa enim culpa tempor exercitation veniam minim consectetur. Sunt est laboris minim quis incididunt exercitation laboris cupidatat fugiat ad. Deserunt ipsum do dolor cillum excepteur incididunt.','registered':'Thursday, March 26, 2015 1:10 PM','latitude':'-84.750592','longitude':'165.493533','tags':['minim','officia','dolore','ipsum','est'],'greeting':'Hello, Sonya! You have 8 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd5037f2c79ecde68','index':48,'guid':'2dc6532f-9a26-49aa-b444-8923896db89c','isActive':false,'balance':'$3,168.93','picture':'http://placehold.it/32x32','age':36,'eyeColor':'brown','name':{'first':'Marguerite','last':'Stuart'},'company':'ACCUFARM','email':'marguerite.stuart@accufarm.io','phone':'+1 (848) 535-2253','address':'301 Menahan Street, Sunnyside, Nebraska, 4809','about':'Deserunt sint labore voluptate amet anim culpa nostrud adipisicing enim cupidatat ullamco exercitation fugiat est. Magna dolor aute incididunt ea ad adipisicing. Do cupidatat ut officia officia culpa sit do.','registered':'Thursday, May 8, 2014 1:25 PM','latitude':'21.82277','longitude':'-7.368347','tags':['labore','nulla','ullamco','irure','adipisicing'],'greeting':'Hello, Marguerite! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edb26d315635818dae','index':49,'guid':'083a5eda-0a70-4f89-87f7-2cd386c0f22a','isActive':false,'balance':'$2,576.25','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Louella','last':'Holloway'},'company':'BEDDER','email':'louella.holloway@bedder.me','phone':'+1 (801) 425-3761','address':'545 Lafayette Avenue, Caledonia, Louisiana, 2816','about':'Qui exercitation occaecat dolore mollit. Fugiat cupidatat proident culpa fugiat quis. In cupidatat commodo elit ea enim occaecat esse exercitation nostrud occaecat veniam laboris fugiat. Nisi sunt reprehenderit aliqua reprehenderit tempor id dolore ullamco pariatur reprehenderit et eu ex pariatur.','registered':'Wednesday, November 5, 2014 1:10 AM','latitude':'36.385637','longitude':'77.949423','tags':['eu','irure','velit','non','aliquip'],'greeting':'Hello, Louella! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed77cd60a1abc1ecce','index':50,'guid':'2887c3c1-3eba-4237-a0db-1977eed94554','isActive':true,'balance':'$1,633.51','picture':'http://placehold.it/32x32','age':22,'eyeColor':'green','name':{'first':'Bates','last':'Carrillo'},'company':'ZOMBOID','email':'bates.carrillo@zomboid.com','phone':'+1 (934) 405-2006','address':'330 Howard Alley, Troy, Kansas, 4881','about':'Voluptate esse est ullamco anim tempor ea reprehenderit. Occaecat pariatur deserunt cillum laboris labore id exercitation esse ipsum ipsum ex aliquip. Sunt non elit est ea occaecat. Magna deserunt commodo aliqua ipsum est cillum dolor nisi. Ex duis est tempor tempor laboris do do quis id magna. Dolor do est elit eu laborum ullamco culpa consequat velit eiusmod tempor.','registered':'Saturday, May 28, 2016 3:56 AM','latitude':'83.310134','longitude':'-105.862836','tags':['est','commodo','ea','commodo','sunt'],'greeting':'Hello, Bates! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed5ec0ec299b471fb5','index':51,'guid':'512b5e67-f785-492e-9d94-e43ef8b399b8','isActive':false,'balance':'$3,032.22','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Floyd','last':'Yang'},'company':'FRENEX','email':'floyd.yang@frenex.org','phone':'+1 (924) 566-3304','address':'418 Quay Street, Chumuckla, Guam, 7743','about':'Irure sit velit exercitation dolore est nisi incididunt ut quis consectetur incididunt est dolor. Aute nisi enim esse aliquip enim culpa commodo consectetur. Duis laborum magna ad duis ipsum aliqua eiusmod cillum. Consectetur et duis eiusmod irure ad est nisi incididunt eiusmod labore. Pariatur proident in Lorem adipisicing mollit proident excepteur nulla do nostrud mollit eiusmod. Duis ad dolore irure fugiat anim laboris ipsum et sit duis ipsum voluptate. Lorem non aute exercitation qui ullamco officia minim sint pariatur ut dolor.','registered':'Wednesday, January 18, 2017 2:01 AM','latitude':'45.888721','longitude':'-41.232793','tags':['elit','in','esse','ea','officia'],'greeting':'Hello, Floyd! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed51e26ca89e5caf49','index':52,'guid':'4e0907f6-facc-46df-8952-73561a53fe33','isActive':true,'balance':'$3,767.41','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Gardner','last':'Carey'},'company':'KLUGGER','email':'gardner.carey@klugger.net','phone':'+1 (876) 481-3502','address':'131 Utica Avenue, Cannondale, Federated States Of Micronesia, 610','about':'Amet ad pariatur excepteur anim ex officia commodo proident aliqua occaecat consequat Lorem officia sit. Id minim velit nisi laboris nisi nulla incididunt eiusmod velit. Deserunt labore quis et tempor. Et labore exercitation laborum officia ullamco nostrud adipisicing laboris esse laborum aute anim elit. Sunt ad officia tempor esse et quis aliquip irure pariatur laborum id quis ex. Eu consequat nisi deserunt id eu proident ex minim aute nulla tempor ex.','registered':'Friday, February 21, 2014 6:42 AM','latitude':'-54.740231','longitude':'15.01484','tags':['commodo','laboris','occaecat','aliquip','adipisicing'],'greeting':'Hello, Gardner! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed52e3c9407105093a','index':53,'guid':'1d3b9e7a-1bc3-40ea-b808-1c33f0d48c70','isActive':true,'balance':'$1,113.30','picture':'http://placehold.it/32x32','age':26,'eyeColor':'blue','name':{'first':'Herman','last':'Rogers'},'company':'TALENDULA','email':'herman.rogers@talendula.name','phone':'+1 (818) 521-2005','address':'541 Norman Avenue, Winfred, Tennessee, 447','about':'Culpa ex laborum non ad ullamco officia. Nisi mollit mollit voluptate sit sint ullamco. Lorem exercitation nulla anim eiusmod deserunt magna sint. Officia sunt eiusmod aliqua reprehenderit sunt mollit sit cupidatat sint.','registered':'Wednesday, July 11, 2018 1:05 AM','latitude':'-20.708105','longitude':'-151.294563','tags':['exercitation','minim','officia','qui','enim'],'greeting':'Hello, Herman! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edfcb123d545b6edb4','index':54,'guid':'c0e0c669-4eed-43ee-bdd0-78fe6e9ca4d5','isActive':true,'balance':'$3,309.64','picture':'http://placehold.it/32x32','age':22,'eyeColor':'green','name':{'first':'Whitley','last':'Stark'},'company':'MUSAPHICS','email':'whitley.stark@musaphics.us','phone':'+1 (803) 476-2151','address':'548 Cobek Court, Chamizal, Indiana, 204','about':'Adipisicing veniam dolor ex sint sit id eu voluptate. Excepteur veniam proident exercitation id eu et sunt pariatur. Qui occaecat culpa aliqua nisi excepteur minim veniam. Est duis nulla laborum excepteur cillum pariatur sint incididunt. Velit commodo eu incididunt voluptate. Amet laboris laboris id adipisicing labore eiusmod consequat minim cillum et.','registered':'Thursday, March 27, 2014 9:10 AM','latitude':'71.219596','longitude':'51.012855','tags':['reprehenderit','mollit','laborum','voluptate','aliquip'],'greeting':'Hello, Whitley! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed81510dfc61602fcf','index':55,'guid':'7ec5c24d-f169-4399-a2a3-300c0f45e52e','isActive':false,'balance':'$3,721.04','picture':'http://placehold.it/32x32','age':23,'eyeColor':'green','name':{'first':'Gretchen','last':'Wade'},'company':'EWEVILLE','email':'gretchen.wade@eweville.biz','phone':'+1 (977) 598-3700','address':'721 Colonial Road, Brookfield, South Dakota, 3888','about':'Fugiat consequat sint ut ut et ullamco eiusmod deserunt pariatur. Veniam eiusmod esse fugiat mollit. Proident laboris minim qui do ipsum excepteur exercitation irure anim. Aliqua labore quis eu fugiat dolore ullamco velit Lorem voluptate ipsum nostrud eiusmod laborum proident.','registered':'Friday, October 12, 2018 10:59 AM','latitude':'41.937653','longitude':'63.378531','tags':['aute','cillum','ea','ex','aute'],'greeting':'Hello, Gretchen! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edf78f77d4a7d557bb','index':56,'guid':'8718ada7-6fd0-49ef-a405-29850503948b','isActive':false,'balance':'$3,341.33','picture':'http://placehold.it/32x32','age':32,'eyeColor':'blue','name':{'first':'Naomi','last':'Frye'},'company':'MAZUDA','email':'naomi.frye@mazuda.ca','phone':'+1 (825) 427-2255','address':'741 Coyle Street, Comptche, Pennsylvania, 8441','about':'Aliqua fugiat laborum quis ullamco cupidatat sit dolor nulla dolore. Do Lorem et ipsum culpa irure sit do dolor qui sit laboris aliqua. Ex consectetur irure in veniam reprehenderit amet do elit eiusmod est magna.','registered':'Thursday, January 9, 2014 7:18 AM','latitude':'41.078645','longitude':'-50.241966','tags':['do','aliquip','eiusmod','velit','id'],'greeting':'Hello, Naomi! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edbf45db2e072a48b4','index':57,'guid':'c158ebf7-fb8b-4ea8-adbf-8c51c6486715','isActive':true,'balance':'$2,811.55','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Lamb','last':'Johns'},'company':'DOGTOWN','email':'lamb.johns@dogtown.info','phone':'+1 (946) 530-3057','address':'559 Malbone Street, Kennedyville, California, 2052','about':'Eiusmod dolor labore cillum ad veniam elit voluptate voluptate pariatur est cupidatat. Laboris ut qui in cillum sunt dolore ut enim. Minim nostrud ex qui quis reprehenderit magna ipsum cupidatat irure minim laboris veniam irure. Fugiat velit deserunt aliquip in esse proident excepteur labore reprehenderit excepteur sunt in cupidatat exercitation. Ex pariatur irure mollit tempor non magna ex.','registered':'Friday, April 21, 2017 1:51 AM','latitude':'-61.403599','longitude':'-93.447102','tags':['aliquip','tempor','sint','enim','ipsum'],'greeting':'Hello, Lamb! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edbb9c88190cb59cf2','index':58,'guid':'f0de5ac5-eb28-491b-81c5-76d447c9055e','isActive':true,'balance':'$1,611.99','picture':'http://placehold.it/32x32','age':37,'eyeColor':'brown','name':{'first':'Lynette','last':'Cleveland'},'company':'ARTWORLDS','email':'lynette.cleveland@artworlds.tv','phone':'+1 (889) 596-3723','address':'439 Montauk Avenue, Felt, New Mexico, 9681','about':'Incididunt aliquip est aliquip est ullamco do consectetur dolor. Lorem mollit mollit dolor et ipsum ut qui veniam aute ea. Adipisicing reprehenderit culpa velit laborum adipisicing amet consectetur velit nisi. Ut qui proident ad cillum excepteur adipisicing quis labore. Duis velit culpa et excepteur eiusmod ex labore in nisi nostrud. Et ullamco minim excepteur ut enim reprehenderit consequat eiusmod laboris Lorem commodo exercitation qui laborum.','registered':'Wednesday, August 26, 2015 12:53 PM','latitude':'49.861336','longitude':'86.865926','tags':['reprehenderit','minim','in','minim','nostrud'],'greeting':'Hello, Lynette! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed5b760ddde7295fa8','index':59,'guid':'f8180d3f-c5c0-48b2-966e-a0b2a80f8e84','isActive':true,'balance':'$3,376.75','picture':'http://placehold.it/32x32','age':32,'eyeColor':'green','name':{'first':'Obrien','last':'Page'},'company':'GLASSTEP','email':'obrien.page@glasstep.co.uk','phone':'+1 (902) 583-3086','address':'183 Ridgewood Avenue, Vicksburg, Wisconsin, 7430','about':'Aute excepteur cillum exercitation duis Lorem irure labore elit. Labore magna cupidatat velit consectetur minim do Lorem in excepteur commodo ea consequat ullamco laborum. Ut in id occaecat eu quis duis id ea deserunt veniam.','registered':'Wednesday, March 29, 2017 12:13 AM','latitude':'-40.156154','longitude':'72.76301','tags':['excepteur','non','anim','nulla','anim'],'greeting':'Hello, Obrien! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed52985d3d8901d653','index':60,'guid':'d2e14fa1-8c54-4bcb-8a58-eb2e6f8d0e45','isActive':true,'balance':'$1,659.47','picture':'http://placehold.it/32x32','age':33,'eyeColor':'brown','name':{'first':'Knowles','last':'Goodman'},'company':'CENTREE','email':'knowles.goodman@centree.io','phone':'+1 (862) 563-3692','address':'504 Lott Street, Allensworth, Florida, 7148','about':'Do aliquip voluptate aliqua nostrud. Eu dolore ex occaecat pariatur aute laborum aute nulla aute amet. Excepteur sit laboris ad non anim ut officia ut ad exercitation officia dolore laboris. Esse voluptate minim deserunt nostrud exercitation laborum voluptate exercitation id laborum fugiat proident cupidatat proident. Nulla nostrud est sint adipisicing incididunt exercitation dolor sit et elit tempor occaecat sint culpa. Pariatur occaecat laboris pariatur laboris ad pariatur in cillum fugiat est fugiat. Proident eu id irure excepteur esse aute cillum adipisicing.','registered':'Wednesday, October 15, 2014 6:17 PM','latitude':'-15.73863','longitude':'87.422009','tags':['consequat','sint','tempor','veniam','culpa'],'greeting':'Hello, Knowles! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0eda00b73bdb7ea54e9','index':61,'guid':'c8a064db-0ec6-4832-9820-7280a0333709','isActive':true,'balance':'$3,701.14','picture':'http://placehold.it/32x32','age':35,'eyeColor':'brown','name':{'first':'Shepherd','last':'Todd'},'company':'ECRATIC','email':'shepherd.todd@ecratic.me','phone':'+1 (881) 444-3389','address':'450 Frank Court, Temperanceville, Ohio, 7006','about':'Voluptate cillum ad fugiat velit adipisicing sint consequat veniam Lorem reprehenderit. Cillum sit non deserunt consequat. Amet sunt pariatur non mollit ullamco proident sint dolore anim elit cupidatat anim do ullamco. Lorem Lorem incididunt ea elit consequat laboris enim duis quis Lorem id aute veniam consequat. Cillum veniam cillum sint qui Lorem fugiat culpa consequat. Est sint duis ut qui fugiat. Laborum pariatur velit et sunt mollit eiusmod excepteur culpa ex et officia.','registered':'Tuesday, October 10, 2017 2:01 AM','latitude':'82.951563','longitude':'-4.866954','tags':['eu','qui','proident','esse','ex'],'greeting':'Hello, Shepherd! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed0e51d1a7e2d9e559','index':62,'guid':'739c3d38-200d-4531-84d8-4e7c39ae5b8c','isActive':true,'balance':'$3,679.01','picture':'http://placehold.it/32x32','age':31,'eyeColor':'brown','name':{'first':'Rosalyn','last':'Heath'},'company':'ZAYA','email':'rosalyn.heath@zaya.com','phone':'+1 (865) 403-3520','address':'303 Henderson Walk, Hoehne, District Of Columbia, 4306','about':'Sint occaecat nulla mollit sint fugiat eu proident dolor labore consequat. Occaecat tempor excepteur do fugiat incididunt Lorem in ullamco dolore laborum. Cillum mollit aliquip excepteur aliquip sint sunt minim non irure irure. Cillum fugiat aliqua enim dolore. Nulla culpa culpa nostrud ad. Eiusmod culpa proident proident non est cupidatat eu sunt sit incididunt id nisi.','registered':'Wednesday, April 22, 2015 12:35 PM','latitude':'33.628504','longitude':'110.772802','tags':['consequat','ut','ex','labore','consectetur'],'greeting':'Hello, Rosalyn! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd5274c01d353d0c5','index':63,'guid':'8815fe55-8af1-4708-a62a-d554dbd74a4a','isActive':true,'balance':'$2,126.01','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Queen','last':'Harper'},'company':'TRI@TRIBALOG','email':'queen.harper@tri@tribalog.org','phone':'+1 (903) 592-3145','address':'926 Heath Place, Wawona, Maine, 7340','about':'Laborum cupidatat commodo aliquip reprehenderit. Excepteur eu labore duis minim minim voluptate aute nostrud deserunt ut velit ullamco. Adipisicing nisi occaecat laborum proident. Id reprehenderit eiusmod cupidatat qui aute consequat amet enim commodo duis non ipsum. Amet ut aliqua magna qui proident mollit aute.','registered':'Saturday, April 9, 2016 5:12 AM','latitude':'51.814216','longitude':'177.348115','tags':['cillum','ut','dolor','do','nisi'],'greeting':'Hello, Queen! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed126298b6ce62ed56','index':64,'guid':'001c87fe-182f-450f-903b-2e29a9bb0322','isActive':true,'balance':'$3,578.29','picture':'http://placehold.it/32x32','age':20,'eyeColor':'green','name':{'first':'Pauline','last':'Mills'},'company':'CRUSTATIA','email':'pauline.mills@crustatia.net','phone':'+1 (984) 582-3899','address':'899 Revere Place, Welch, Iowa, 216','about':'Tempor eu exercitation ut id. Deserunt ex reprehenderit veniam nisi. Aute laborum veniam velit dolore ut deserunt Lorem sit esse quis dolor ex do nisi. In dolor tempor officia id. Velit nisi culpa nostrud laborum officia incididunt laborum velit non quis id exercitation exercitation. Anim elit ullamco in enim Lorem culpa aliqua Lorem.','registered':'Monday, June 2, 2014 2:03 PM','latitude':'56.427576','longitude':'172.183669','tags':['pariatur','pariatur','pariatur','fugiat','Lorem'],'greeting':'Hello, Pauline! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed3e332ad9e8a178d8','index':65,'guid':'5ad7292b-feef-4a7e-b485-142cadfbe8ea','isActive':false,'balance':'$3,916.54','picture':'http://placehold.it/32x32','age':22,'eyeColor':'brown','name':{'first':'Garrett','last':'Richmond'},'company':'XYQAG','email':'garrett.richmond@xyqag.name','phone':'+1 (952) 584-3794','address':'233 Grove Street, Summerfield, Virginia, 4735','about':'Nostrud quis pariatur occaecat laborum laboris aliqua ut fugiat dolor. Commodo tempor excepteur enim nostrud Lorem. Aute elit nulla labore ad pariatur cupidatat Lorem qui cupidatat velit deserunt excepteur esse. Excepteur nulla et nostrud quis labore est veniam enim nisi laboris ut enim. Ea esse nulla anim excepteur reprehenderit deserunt voluptate minim qui labore adipisicing amet eu enim.','registered':'Wednesday, March 5, 2014 4:35 PM','latitude':'68.665041','longitude':'148.799524','tags':['irure','reprehenderit','minim','ea','do'],'greeting':'Hello, Garrett! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed541aa2ec47466ace','index':66,'guid':'9cda6f3c-c9ab-451c-bb19-2e4c8463d011','isActive':true,'balance':'$3,352.52','picture':'http://placehold.it/32x32','age':30,'eyeColor':'brown','name':{'first':'Cobb','last':'Whitley'},'company':'UNIA','email':'cobb.whitley@unia.us','phone':'+1 (888) 490-3342','address':'864 Belmont Avenue, Needmore, Massachusetts, 8286','about':'Nisi aliquip fugiat ipsum nisi ullamco minim pariatur labore. Sint labore anim do ad ad esse eu nostrud nulla commodo anim. Cillum anim enim duis cillum non do nisi aliquip veniam voluptate commodo aliqua laborum. Exercitation in do eu qui sint aliquip. Esse adipisicing deserunt deserunt qui anim aliqua occaecat et nostrud elit ea in anim cillum. Tempor mollit proident tempor sunt est sint laborum ullamco incididunt non. Velit aliqua sunt excepteur nisi qui eiusmod ipsum dolore aliquip velit ullamco ullamco.','registered':'Friday, May 23, 2014 7:11 PM','latitude':'-32.950581','longitude':'147.772494','tags':['mollit','adipisicing','irure','ad','minim'],'greeting':'Hello, Cobb! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed8186c3d6f34c2be3','index':67,'guid':'fee98f6d-d68a-4189-8180-b6cb337e537e','isActive':false,'balance':'$1,698.42','picture':'http://placehold.it/32x32','age':20,'eyeColor':'blue','name':{'first':'Brennan','last':'Tyler'},'company':'PODUNK','email':'brennan.tyler@podunk.biz','phone':'+1 (867) 498-2727','address':'599 Harkness Avenue, Gorst, American Samoa, 322','about':'Reprehenderit id sit qui id qui aute ea sit magna in qui proident. Excepteur ad nostrud do nostrud in incididunt voluptate adipisicing sint anim. Ullamco consequat minim nulla irure ex est irure reprehenderit deserunt voluptate dolore anim sunt. Occaecat dolore voluptate voluptate elit commodo nulla laborum ad do irure.','registered':'Friday, February 9, 2018 5:40 PM','latitude':'11.150893','longitude':'-85.298004','tags':['quis','minim','deserunt','cillum','laboris'],'greeting':'Hello, Brennan! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed075c9c4f7439818d','index':68,'guid':'1ef76b18-6b8d-4c3c-aca3-9fa2b43f0242','isActive':false,'balance':'$2,091.17','picture':'http://placehold.it/32x32','age':26,'eyeColor':'brown','name':{'first':'Neal','last':'Stephenson'},'company':'OTHERSIDE','email':'neal.stephenson@otherside.ca','phone':'+1 (820) 496-3344','address':'867 Wilson Street, Kidder, Colorado, 4599','about':'Do laboris enim proident in qui velit adipisicing magna anim. Amet proident non exercitation ipsum aliqua excepteur nostrud. Enim esse non sit in nostrud deserunt id laborum cillum deserunt consequat. Anim velit exercitation qui sit voluptate. Irure duis non veniam velit mollit exercitation id exercitation.','registered':'Thursday, November 13, 2014 11:00 PM','latitude':'54.809693','longitude':'1.877241','tags':['anim','duis','in','officia','sint'],'greeting':'Hello, Neal! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0eda0a2dc24db64b638','index':69,'guid':'194744fd-089b-40b6-a290-98a6ec30a415','isActive':false,'balance':'$3,191.67','picture':'http://placehold.it/32x32','age':24,'eyeColor':'brown','name':{'first':'Shields','last':'Hubbard'},'company':'MIRACULA','email':'shields.hubbard@miracula.info','phone':'+1 (885) 582-2001','address':'529 Eagle Street, Guilford, Nevada, 1460','about':'Eiusmod exercitation ut incididunt veniam commodo culpa ullamco mollit id adipisicing exercitation ad sint. Nostrud excepteur amet aliqua mollit incididunt laborum voluptate id anim. Nulla sint laboris dolor esse cupidatat laborum ex sint. Ex non sunt sit nulla.','registered':'Monday, February 13, 2017 6:22 AM','latitude':'-69.145209','longitude':'-40.69755','tags':['tempor','enim','qui','velit','elit'],'greeting':'Hello, Shields! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edf939c130177e074d','index':70,'guid':'303b176c-7803-4ed2-a35f-3e3c831793ef','isActive':false,'balance':'$2,359.09','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Coleen','last':'Knight'},'company':'BLEEKO','email':'coleen.knight@bleeko.tv','phone':'+1 (867) 423-3146','address':'527 Broadway , Bonanza, Marshall Islands, 4988','about':'Laboris nulla pariatur laborum ad aute excepteur sunt pariatur exercitation. Do nostrud qui ipsum ullamco et sint do Lorem cillum ullamco do. Exercitation labore excepteur commodo incididunt eiusmod proident consectetur adipisicing nostrud aute voluptate laboris. Commodo anim proident eiusmod pariatur est ea laborum incididunt qui tempor reprehenderit ullamco id. Eiusmod commodo nisi consectetur ut qui quis aliqua sit minim nostrud sunt laborum eiusmod adipisicing.','registered':'Sunday, May 6, 2018 8:03 AM','latitude':'70.729041','longitude':'113.052761','tags':['Lorem','ullamco','nulla','ullamco','commodo'],'greeting':'Hello, Coleen! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edae8b1ce688b61223','index':71,'guid':'7d6f3b1a-c367-4068-9e8e-1717d513ece3','isActive':false,'balance':'$2,911.07','picture':'http://placehold.it/32x32','age':21,'eyeColor':'brown','name':{'first':'Clark','last':'Ryan'},'company':'ECLIPSENT','email':'clark.ryan@eclipsent.co.uk','phone':'+1 (938) 562-2740','address':'500 Lewis Avenue, Rockbridge, North Dakota, 5133','about':'Adipisicing exercitation officia sit excepteur excepteur sunt sint amet. Aliqua ipsum sint laboris eiusmod esse culpa elit sunt. Dolore est consectetur est quis quis magna. Aliquip nostrud dolore ex pariatur. Anim nostrud duis exercitation ut magna magna culpa. Nisi irure id mollit labore non sit mollit occaecat Lorem est ipsum. Nulla est fugiat cillum nisi aliqua consectetur amet nulla nostrud esse.','registered':'Friday, July 24, 2015 9:28 AM','latitude':'-68.055815','longitude':'-50.926966','tags':['deserunt','ad','ad','ut','id'],'greeting':'Hello, Clark! You have 7 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed5d1e8df45d8ab4db','index':72,'guid':'ce85db37-7d04-4f4c-a4b0-78003533e5c6','isActive':false,'balance':'$1,127.43','picture':'http://placehold.it/32x32','age':21,'eyeColor':'green','name':{'first':'Dillon','last':'Hooper'},'company':'MEDESIGN','email':'dillon.hooper@medesign.io','phone':'+1 (929) 600-3797','address':'652 Mill Avenue, Elliston, Mississippi, 2958','about':'Dolore culpa qui exercitation nostrud do. Irure duis in ad ipsum aliqua aliquip nulla sit veniam officia quis occaecat est. Magna qui eiusmod pariatur aliquip minim commodo. Qui ex dolor excepteur consequat eiusmod occaecat. In officia ipsum do Lorem excepteur proident pariatur labore.','registered':'Monday, May 26, 2014 2:38 AM','latitude':'-36.032189','longitude':'86.865529','tags':['non','ut','ex','Lorem','quis'],'greeting':'Hello, Dillon! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edb84814579c3121b3','index':73,'guid':'d7303901-5186-4595-a759-22306f67d0a3','isActive':true,'balance':'$2,326.59','picture':'http://placehold.it/32x32','age':33,'eyeColor':'green','name':{'first':'Moreno','last':'Hull'},'company':'ZEAM','email':'moreno.hull@zeam.me','phone':'+1 (984) 586-3738','address':'265 Pine Street, Talpa, North Carolina, 6041','about':'Fugiat exercitation est ullamco anim. Exercitation proident id sunt culpa Lorem amet. Consectetur anim consectetur pariatur consequat consectetur amet excepteur voluptate ea velit duis eiusmod proident. In sint laborum cupidatat ea amet ex. Reprehenderit amet sunt dolor ullamco est ex deserunt.','registered':'Wednesday, January 24, 2018 8:52 PM','latitude':'84.956857','longitude':'113.210051','tags':['est','excepteur','anim','Lorem','dolor'],'greeting':'Hello, Moreno! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eda4eb9dcb92c82d06','index':74,'guid':'8ee28651-802e-4523-b676-c713f6e874b8','isActive':true,'balance':'$3,783.97','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Tracie','last':'Price'},'company':'ICOLOGY','email':'tracie.price@icology.com','phone':'+1 (897) 403-3768','address':'487 Sheffield Avenue, Vallonia, Wyoming, 276','about':'Voluptate laboris laborum aute ex sint voluptate officia proident. Sit esse nostrud cupidatat in veniam sit duis est. Do mollit elit exercitation aliqua id irure ex. Lorem reprehenderit do ullamco sint ea ad nisi ad ut.','registered':'Saturday, December 10, 2016 9:44 AM','latitude':'77.770464','longitude':'151.392903','tags':['incididunt','labore','aliquip','anim','minim'],'greeting':'Hello, Tracie! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed68ab1a55d1c35e6c','index':75,'guid':'deedd26a-8928-4064-9666-5c59ea8144b4','isActive':true,'balance':'$2,848.08','picture':'http://placehold.it/32x32','age':32,'eyeColor':'brown','name':{'first':'Montgomery','last':'Bruce'},'company':'CYTREK','email':'montgomery.bruce@cytrek.org','phone':'+1 (824) 414-2731','address':'397 Beach Place, Ellerslie, South Carolina, 967','about':'Mollit minim excepteur magna velit cillum excepteur exercitation anim id labore deserunt do. Fugiat ex et id ad. Duis excepteur laboris est nulla do id irure quis eiusmod do esse ut culpa in.','registered':'Tuesday, August 25, 2015 6:42 AM','latitude':'79.722631','longitude':'-7.516885','tags':['Lorem','sint','voluptate','proident','incididunt'],'greeting':'Hello, Montgomery! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd90e0abb1cc2b0aa','index':76,'guid':'a072159d-12db-4747-9c2a-e2486a53d043','isActive':false,'balance':'$2,723.54','picture':'http://placehold.it/32x32','age':40,'eyeColor':'green','name':{'first':'Zelma','last':'Salinas'},'company':'IMAGEFLOW','email':'zelma.salinas@imageflow.net','phone':'+1 (964) 555-3856','address':'584 Reeve Place, Nord, Georgia, 7473','about':'Aliqua proident excepteur duis cupidatat cillum amet esse esse consectetur ea. Officia sunt consequat nostrud minim enim dolore dolor duis cillum. Esse labore veniam sint laborum excepteur sint tempor do ad cupidatat aliquip laboris elit id. Velit reprehenderit ullamco velit ullamco adipisicing velit esse irure velit et.','registered':'Thursday, February 25, 2016 8:18 PM','latitude':'-32.880524','longitude':'115.180489','tags':['id','nulla','reprehenderit','consequat','reprehenderit'],'greeting':'Hello, Zelma! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed98d836c8da283bb2','index':77,'guid':'838bebad-cc20-44e9-9eb7-902a8ca25efb','isActive':false,'balance':'$3,488.91','picture':'http://placehold.it/32x32','age':20,'eyeColor':'green','name':{'first':'Shaw','last':'Parsons'},'company':'PEARLESEX','email':'shaw.parsons@pearlesex.name','phone':'+1 (912) 567-3580','address':'606 Ocean Avenue, Tyro, Northern Mariana Islands, 3367','about':'Laborum labore occaecat culpa pariatur nisi non adipisicing esse consectetur officia officia. Deserunt velit eu enim consectetur ut cillum aliqua occaecat dolor qui esse. Incididunt ad est ex eu culpa anim aliquip laborum. Aliqua consectetur velit exercitation magna minim nulla do ut excepteur enim aliquip et. Nostrud enim sunt amet amet proident aliqua velit dolore. Consectetur ipsum fugiat proident id est reprehenderit tempor irure commodo. Sit excepteur fugiat occaecat nulla Lorem et cillum.','registered':'Thursday, April 19, 2018 1:41 AM','latitude':'69.715573','longitude':'-118.481237','tags':['laboris','adipisicing','magna','voluptate','id'],'greeting':'Hello, Shaw! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed1101734633c6ebba','index':78,'guid':'8fd0c52a-9d74-4984-a608-d612ecd8ddf0','isActive':true,'balance':'$3,820.02','picture':'http://placehold.it/32x32','age':39,'eyeColor':'brown','name':{'first':'Jaime','last':'Beard'},'company':'IZZBY','email':'jaime.beard@izzby.us','phone':'+1 (820) 412-3806','address':'362 Hudson Avenue, Delco, New Jersey, 5684','about':'Ut cupidatat veniam nulla magna commodo sit duis veniam consectetur cupidatat elit quis tempor. Duis officia ullamco proident sunt non mollit excepteur. Nisi ex amet laboris proident duis reprehenderit et est aliqua mollit amet ad. Enim eu elit excepteur eu exercitation duis consequat culpa. Adipisicing reprehenderit duis Lorem reprehenderit dolor aliqua incididunt eiusmod consequat ad occaecat fugiat do laborum. Qui ad aliquip ex do sunt. Fugiat non ut fugiat eu.','registered':'Sunday, March 9, 2014 3:41 PM','latitude':'17.926318','longitude':'108.985996','tags':['ut','voluptate','veniam','non','commodo'],'greeting':'Hello, Jaime! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edcd125a89dcf18e0d','index':79,'guid':'eccaa4ca-0fa7-4b00-a1e3-fe7953403894','isActive':true,'balance':'$1,521.33','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Terra','last':'Sullivan'},'company':'ZANITY','email':'terra.sullivan@zanity.biz','phone':'+1 (995) 498-2714','address':'346 Congress Street, Tuttle, Maryland, 3152','about':'Incididunt enim veniam ut veniam quis dolore pariatur culpa ex. Cillum laboris dolor exercitation officia. Officia irure magna aliqua veniam officia ullamco culpa. Cillum enim velit ea sint sint officia labore ea adipisicing culpa laboris. Anim aute sint commodo culpa ex quis minim ut laborum.','registered':'Sunday, June 1, 2014 5:38 AM','latitude':'-4.655435','longitude':'5.851803','tags':['anim','non','anim','laborum','pariatur'],'greeting':'Hello, Terra! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed9b9fc3041a674c87','index':80,'guid':'9f95fa36-4e45-4c3f-9362-3d4d809bf57f','isActive':true,'balance':'$3,403.16','picture':'http://placehold.it/32x32','age':39,'eyeColor':'brown','name':{'first':'Sharpe','last':'Berger'},'company':'ZILLAN','email':'sharpe.berger@zillan.ca','phone':'+1 (913) 498-3005','address':'277 Bragg Street, Faywood, Texas, 6487','about':'Dolor duis id aute ea veniam amet ullamco id. Culpa deserunt irure mollit tempor dolore veniam culpa officia culpa laborum eiusmod. Ullamco tempor qui aliqua cupidatat veniam cillum eu ut ex minim eu in. Quis exercitation anim eiusmod tempor esse mollit exercitation cillum ipsum reprehenderit. Sint voluptate ipsum officia sint magna nulla tempor eiusmod eiusmod veniam. Consectetur non ad veniam exercitation voluptate non nostrud.','registered':'Tuesday, June 27, 2017 12:58 AM','latitude':'-0.54085','longitude':'106.258693','tags':['proident','eiusmod','commodo','excepteur','pariatur'],'greeting':'Hello, Sharpe! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed1a1866757bf675e0','index':81,'guid':'1b944a01-01d3-4846-94e3-630f4d0e51a3','isActive':true,'balance':'$2,038.61','picture':'http://placehold.it/32x32','age':28,'eyeColor':'brown','name':{'first':'Blanchard','last':'Ewing'},'company':'CONJURICA','email':'blanchard.ewing@conjurica.info','phone':'+1 (859) 593-3212','address':'252 Beaver Street, Kiskimere, Utah, 3255','about':'Labore magna aute adipisicing ut dolor sit ea. Officia culpa aute occaecat sit ex ullamco aliquip ad sit culpa. Ex in enim dolore ex est sit. Do irure nulla magna sint aliquip in duis aute. Magna ullamco sit labore ea tempor voluptate.','registered':'Monday, May 4, 2015 10:50 AM','latitude':'76.207595','longitude':'0.672563','tags':['proident','pariatur','officia','in','culpa'],'greeting':'Hello, Blanchard! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed987d82f4e22d939c','index':82,'guid':'97a90aee-3cee-4678-819e-24fb94279dc1','isActive':false,'balance':'$1,201.55','picture':'http://placehold.it/32x32','age':28,'eyeColor':'blue','name':{'first':'Wells','last':'Solomon'},'company':'CORPULSE','email':'wells.solomon@corpulse.tv','phone':'+1 (840) 539-3349','address':'159 Radde Place, Linganore, Idaho, 230','about':'Consequat dolore mollit sit irure cupidatat commodo. Incididunt cillum reprehenderit ullamco sit proident cupidatat occaecat reprehenderit officia. Ad anim Lorem elit in officia minim proident nisi commodo eiusmod ea Lorem dolore voluptate. Dolor aliquip est commodo Lorem dolor ut aliquip ut. Sit anim officia dolore excepteur aute enim cillum.','registered':'Friday, January 6, 2017 1:59 PM','latitude':'70.020883','longitude':'14.503588','tags':['mollit','aute','officia','nostrud','laboris'],'greeting':'Hello, Wells! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eddf7a904ea0d0bc2a','index':83,'guid':'fe639a0c-7517-43e6-b0da-cd9ca5b9e267','isActive':false,'balance':'$3,664.47','picture':'http://placehold.it/32x32','age':33,'eyeColor':'blue','name':{'first':'Natalia','last':'Brown'},'company':'SYNTAC','email':'natalia.brown@syntac.co.uk','phone':'+1 (952) 595-3513','address':'332 Lenox Road, Springville, Alabama, 8406','about':'Nulla consequat officia commodo ea sunt irure anim velit aliquip aliquip. Labore ullamco occaecat proident voluptate cillum labore minim nostrud excepteur. Qui fugiat nostrud cillum fugiat ullamco id commodo aliqua voluptate mollit id id laboris. Cillum qui duis duis sit adipisicing elit ut aliqua eu. Anim nisi aliqua sit mollit.','registered':'Sunday, July 30, 2017 1:02 PM','latitude':'31.937613','longitude':'-9.957927','tags':['magna','adipisicing','exercitation','tempor','consectetur'],'greeting':'Hello, Natalia! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed8823fa385cad4aa3','index':84,'guid':'5cf280da-f5f0-4cc6-9063-e9d5863c8c89','isActive':false,'balance':'$1,624.17','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Greene','last':'Waller'},'company':'ISOTRACK','email':'greene.waller@isotrack.io','phone':'+1 (838) 406-3608','address':'362 Albemarle Road, Gardiner, Michigan, 2764','about':'Ut nisi sit sint nulla dolor magna. Culpa occaecat adipisicing veniam proident excepteur tempor quis ex. Fugiat tempor laborum dolor adipisicing irure anim cupidatat ut exercitation ex sit. Cupidatat exercitation commodo sunt ex irure fugiat eu esse do ullamco mollit dolore cupidatat. Cupidatat magna incididunt officia dolore esse voluptate deserunt in laborum dolor. Sit fugiat Lorem eu ullamco. Laboris veniam quis cillum tempor ex fugiat cillum cupidatat.','registered':'Sunday, June 10, 2018 10:32 PM','latitude':'0.256921','longitude':'-96.141941','tags':['magna','dolore','deserunt','aliquip','cillum'],'greeting':'Hello, Greene! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eda7c905c2d24c7d31','index':85,'guid':'aa30a9fb-8a16-48eb-8bb7-1307d1e1f191','isActive':false,'balance':'$1,974.04','picture':'http://placehold.it/32x32','age':36,'eyeColor':'green','name':{'first':'Carlene','last':'Hanson'},'company':'DIGIRANG','email':'carlene.hanson@digirang.me','phone':'+1 (981) 417-3209','address':'435 Clark Street, Choctaw, Oregon, 9888','about':'Amet labore esse cillum irure laborum consectetur occaecat non aliquip aliquip proident. Nisi magna nulla officia duis labore aute nulla laborum duis tempor minim. Velit elit reprehenderit nisi exercitation officia incididunt amet cupidatat excepteur proident consectetur.','registered':'Thursday, April 20, 2017 6:13 AM','latitude':'68.529086','longitude':'68.802409','tags':['pariatur','nulla','qui','amet','labore'],'greeting':'Hello, Carlene! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed6fbee12ce9e55dbf','index':86,'guid':'0fce89aa-3310-48df-862a-68bd3d776644','isActive':false,'balance':'$3,909.64','picture':'http://placehold.it/32x32','age':40,'eyeColor':'brown','name':{'first':'Doris','last':'Collins'},'company':'ZIORE','email':'doris.collins@ziore.com','phone':'+1 (914) 405-2360','address':'301 Lorraine Street, Stouchsburg, Minnesota, 7476','about':'Nisi deserunt aliquip et deserunt ipsum ad consectetur est non ullamco. Dolore do ut voluptate do eiusmod. Culpa ad in eiusmod nisi cillum do. Officia magna cillum sint aliqua reprehenderit amet est ipsum. Eiusmod deserunt commodo proident consequat. Amet minim dolor consequat aliquip aliquip culpa non exercitation non.','registered':'Wednesday, February 25, 2015 9:15 PM','latitude':'-57.364906','longitude':'130.766587','tags':['nulla','deserunt','cillum','eiusmod','adipisicing'],'greeting':'Hello, Doris! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edede9402476c398c0','index':87,'guid':'60cf0aa6-bc6d-4305-8842-d27e6af1306f','isActive':false,'balance':'$2,817.53','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Cline','last':'Hayden'},'company':'ECRAZE','email':'cline.hayden@ecraze.org','phone':'+1 (965) 507-2138','address':'352 Rutland Road, Ebro, Connecticut, 1196','about':'Dolor eiusmod enim anim sit enim ea tempor. Tempor amet consectetur aliquip culpa do ex excepteur deserunt. Dolor commodo veniam culpa sint. Commodo consectetur pariatur irure nisi deserunt cillum est dolor ipsum ea.','registered':'Thursday, September 29, 2016 5:58 AM','latitude':'62.50713','longitude':'86.247286','tags':['enim','tempor','anim','veniam','proident'],'greeting':'Hello, Cline! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edeb72f151994a551b','index':88,'guid':'dbb49c62-86b1-409f-b8b8-f609c709d2a8','isActive':false,'balance':'$3,122.56','picture':'http://placehold.it/32x32','age':39,'eyeColor':'green','name':{'first':'Janelle','last':'Rutledge'},'company':'TERRAGEN','email':'janelle.rutledge@terragen.net','phone':'+1 (914) 581-3749','address':'170 Falmouth Street, Alderpoint, West Virginia, 642','about':'Laboris proident cillum sunt qui ea sunt. Officia adipisicing exercitation dolore magna reprehenderit amet anim id. Laboris commodo sit irure irure. Excepteur est mollit fugiat incididunt consectetur veniam irure ea mollit. Cillum enim consequat sunt sunt nisi incididunt tempor enim.','registered':'Monday, February 16, 2015 5:46 AM','latitude':'-46.392023','longitude':'32.054562','tags':['eu','eu','nisi','labore','deserunt'],'greeting':'Hello, Janelle! You have 9 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edc9c2604846ff9a0d','index':89,'guid':'c4d7a365-f1d3-4584-b78e-008394c219f7','isActive':true,'balance':'$1,807.19','picture':'http://placehold.it/32x32','age':24,'eyeColor':'green','name':{'first':'Abby','last':'Lopez'},'company':'GRAINSPOT','email':'abby.lopez@grainspot.name','phone':'+1 (917) 442-3955','address':'488 Kensington Walk, Winston, Hawaii, 9109','about':'Incididunt deserunt Lorem proident magna tempor enim quis duis eu ut adipisicing in. Ex mollit non irure aliqua officia. Fugiat id ipsum consequat irure id ullamco culpa quis nulla enim aliquip consequat et. Dolor ut anim velit irure consequat cillum eu. Aute occaecat laborum est aliqua.','registered':'Sunday, April 1, 2018 11:28 PM','latitude':'-10.177041','longitude':'-165.756718','tags':['est','laborum','culpa','non','quis'],'greeting':'Hello, Abby! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed03237438b158af9e','index':90,'guid':'36c4a19f-2d00-4e40-bd49-155fd2ce0a6c','isActive':false,'balance':'$2,757.86','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Whitney','last':'Sheppard'},'company':'ANACHO','email':'whitney.sheppard@anacho.us','phone':'+1 (922) 437-2383','address':'951 Beekman Place, Homeworth, New York, 6088','about':'Sint minim nisi minim non minim aliqua pariatur ullamco do sint qui labore. Aute elit reprehenderit ad do fugiat est amet. In incididunt tempor commodo cillum tempor est labore anim.','registered':'Tuesday, September 13, 2016 6:43 PM','latitude':'-49.732527','longitude':'-171.846715','tags':['exercitation','veniam','sunt','est','proident'],'greeting':'Hello, Whitney! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edb99dd3aa53d2cb7f','index':91,'guid':'17afd430-f37f-4d55-958c-72f35cdb5997','isActive':false,'balance':'$3,683.86','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Ilene','last':'Blackwell'},'company':'ENQUILITY','email':'ilene.blackwell@enquility.biz','phone':'+1 (817) 555-2616','address':'950 Varanda Place, Belgreen, Virgin Islands, 1765','about':'Id eiusmod deserunt eiusmod adipisicing adipisicing est enim pariatur esse duis. Qui velit duis irure magna consectetur dolore reprehenderit. Cillum dolore minim consectetur irure non qui velit cillum veniam adipisicing incididunt. Deserunt veniam excepteur veniam velit aliquip labore quis exercitation magna do non dolor. Aliquip occaecat minim adipisicing deserunt fugiat nulla occaecat proident irure consectetur eiusmod irure. Enim Lorem deserunt amet Lorem commodo eiusmod reprehenderit occaecat adipisicing dolor voluptate cillum.','registered':'Thursday, February 1, 2018 8:39 AM','latitude':'57.393644','longitude':'-3.704258','tags':['adipisicing','dolor','commodo','Lorem','Lorem'],'greeting':'Hello, Ilene! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed353f4deb62c3342a','index':92,'guid':'9953e285-2095-4f1c-978b-9ece2a867e9d','isActive':false,'balance':'$1,202.44','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Dawson','last':'Herman'},'company':'BITENDREX','email':'dawson.herman@bitendrex.ca','phone':'+1 (843) 522-2655','address':'471 Channel Avenue, Denio, Alaska, 5040','about':'Nisi occaecat mollit reprehenderit nisi minim Lorem mollit. Ea proident irure cillum quis. Deserunt consectetur consectetur consequat quis enim minim ea ipsum proident nisi ad non aliquip. Veniam aute minim consequat irure voluptate aute amet excepteur exercitation cillum duis quis adipisicing nostrud.','registered':'Tuesday, December 8, 2015 5:40 PM','latitude':'-55.602721','longitude':'-26.683234','tags':['qui','dolor','deserunt','eiusmod','labore'],'greeting':'Hello, Dawson! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd5464bc50a5310ad','index':93,'guid':'724b2434-4dbd-417d-aa07-6065715f434f','isActive':false,'balance':'$1,595.98','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Alice','last':'Christian'},'company':'ZENOLUX','email':'alice.christian@zenolux.info','phone':'+1 (954) 466-2650','address':'875 Gerritsen Avenue, Townsend, Kentucky, 6568','about':'Nulla labore occaecat ex culpa magna. Commodo occaecat et in consequat cillum laborum magna adipisicing excepteur. Do ut Lorem esse voluptate officia ea aliquip proident amet veniam minim nulla adipisicing. Enim consectetur incididunt laborum voluptate tempor deserunt non laboris. Aliquip deserunt aute irure dolore magna anim aliquip sint magna Lorem. Officia laboris nulla officia sint labore nisi. Do Lorem id in est esse adipisicing id fugiat enim esse laborum.','registered':'Wednesday, October 3, 2018 9:26 PM','latitude':'-88.790637','longitude':'138.817328','tags':['duis','ea','magna','ea','incididunt'],'greeting':'Hello, Alice! You have 8 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0eda01886247b6a4f3d','index':94,'guid':'17c9f4d3-7d72-44e3-8f7c-08d7de920f46','isActive':false,'balance':'$3,173.29','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Schwartz','last':'Mccormick'},'company':'EVIDENDS','email':'schwartz.mccormick@evidends.tv','phone':'+1 (924) 531-2802','address':'160 Midwood Street, Indio, Palau, 4241','about':'Anim reprehenderit et et adipisicing voluptate consequat elit. Sint Lorem laboris Lorem minim nostrud aute reprehenderit elit aute quis nulla. Officia aute eiusmod mollit cillum eu aliquip non enim ea occaecat quis fugiat occaecat officia. Eiusmod culpa exercitation dolor aliqua enim occaecat nisi cupidatat duis ex dolore id. Id consequat aliqua cupidatat ut. Sit nisi est sunt culpa ullamco excepteur sunt pariatur incididunt amet. Ut tempor duis velit eu ut id culpa aute anim occaecat labore.','registered':'Thursday, March 2, 2017 5:57 PM','latitude':'38.618587','longitude':'-165.142529','tags':['ad','reprehenderit','magna','elit','mollit'],'greeting':'Hello, Schwartz! You have 10 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed51be4df456ec2bc9','index':95,'guid':'44f68f65-959b-4ec2-bd2a-1f30035f76fc','isActive':false,'balance':'$3,242.24','picture':'http://placehold.it/32x32','age':39,'eyeColor':'blue','name':{'first':'Bonita','last':'Stevens'},'company':'SLOFAST','email':'bonita.stevens@slofast.co.uk','phone':'+1 (886) 473-2105','address':'459 Bushwick Court, Kilbourne, Rhode Island, 9450','about':'Consequat reprehenderit qui reprehenderit nisi sit est in qui aliquip amet. Ex deserunt cupidatat amet cillum eiusmod irure anim in amet proident voluptate. Ad officia culpa in non incididunt do.','registered':'Saturday, August 22, 2015 5:23 AM','latitude':'60.013542','longitude':'58.242132','tags':['aute','adipisicing','in','cillum','officia'],'greeting':'Hello, Bonita! You have 5 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed50a55e3587993f68','index':96,'guid':'652e434f-221e-4899-af12-38dca5c9621d','isActive':false,'balance':'$2,720.06','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Charmaine','last':'Jackson'},'company':'FLUM','email':'charmaine.jackson@flum.io','phone':'+1 (947) 573-2692','address':'788 Windsor Place, Highland, Arkansas, 8869','about':'Dolore reprehenderit irure excepteur eu reprehenderit sint Lorem ut amet in. Consequat anim elit sunt aliquip incididunt. Culpa consequat do exercitation dolor enim dolor sunt sit excepteur ad anim. Dolor aute elit velit mollit minim eu.','registered':'Wednesday, April 6, 2016 7:54 PM','latitude':'25.756553','longitude':'-5.482531','tags':['amet','sint','consequat','est','ex'],'greeting':'Hello, Charmaine! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed213621949bbdd5d3','index':97,'guid':'7d7d93d8-3e37-4b4a-9fa2-591fb7d153ce','isActive':true,'balance':'$1,370.63','picture':'http://placehold.it/32x32','age':36,'eyeColor':'brown','name':{'first':'Petersen','last':'Cooley'},'company':'ROTODYNE','email':'petersen.cooley@rotodyne.me','phone':'+1 (929) 563-3339','address':'338 Pioneer Street, Carbonville, Missouri, 3030','about':'Cillum elit dolore labore aute. Cillum ea incididunt cupidatat consequat sint eu mollit. Excepteur commodo eiusmod ex Lorem enim velit minim.','registered':'Friday, December 8, 2017 5:53 AM','latitude':'-10.576254','longitude':'-111.176861','tags':['veniam','eu','eiusmod','dolore','voluptate'],'greeting':'Hello, Petersen! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed3e938138d58ed453','index':98,'guid':'d6fea4a3-03f6-46ee-90b9-8ec51a585e29','isActive':true,'balance':'$1,216.54','picture':'http://placehold.it/32x32','age':39,'eyeColor':'blue','name':{'first':'Rosanne','last':'Terry'},'company':'EXTREMO','email':'rosanne.terry@extremo.com','phone':'+1 (812) 496-2691','address':'368 Rockaway Avenue, Gloucester, Illinois, 7913','about':'Duis et nostrud duis quis minim eiusmod culpa do ea ad pariatur tempor. Velit veniam aliqua aliquip est enim ex et culpa dolor ullamco culpa officia. Eu id occaecat aute cillum aute sit aute laboris ipsum voluptate ex. Amet tempor minim tempor Lorem quis dolore. Pariatur consequat dolore nulla veniam dolor exercitation consequat nulla laboris incididunt do. Dolore do tempor deserunt exercitation incididunt officia incididunt ut do reprehenderit do eiusmod nulla.','registered':'Sunday, August 6, 2017 12:46 PM','latitude':'-43.257964','longitude':'-45.147686','tags':['et','incididunt','esse','commodo','ipsum'],'greeting':'Hello, Rosanne! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed632b1a1d65501d6b','index':99,'guid':'bf8c6ac1-ee18-48ee-ae94-ea515a53c951','isActive':true,'balance':'$2,905.58','picture':'http://placehold.it/32x32','age':21,'eyeColor':'blue','name':{'first':'Irene','last':'Castro'},'company':'POLARIA','email':'irene.castro@polaria.org','phone':'+1 (818) 417-3761','address':'901 Dupont Street, Sperryville, Oklahoma, 953','about':'Pariatur minim laboris aliqua dolor aliquip consequat ea do duis voluptate id Lorem. In reprehenderit et adipisicing anim elit incididunt velit in laborum laborum. Qui minim magna et amet sit do voluptate reprehenderit ea sit sint velit.','registered':'Tuesday, August 18, 2015 10:48 AM','latitude':'-7.004055','longitude':'116.052433','tags':['sit','proident','enim','ullamco','non'],'greeting':'Hello, Irene! You have 10 unread messages.','favoriteFruit':'apple'}]"
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-no-changes/main.tf b/v1.5.7/internal/backend/remote/testdata/plan-no-changes/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-no-changes/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-no-changes/plan.log b/v1.5.7/internal/backend/remote/testdata/plan-no-changes/plan.log
new file mode 100644
index 0000000..7041681
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-no-changes/plan.log
@@ -0,0 +1,17 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+null_resource.hello: Refreshing state... (ID: 8657651096157629581)
+
+------------------------------------------------------------------------
+
+No changes. Infrastructure is up-to-date.
+
+This means that Terraform did not detect any differences between your
+configuration and real physical resources that exist. As a result, no
+actions need to be performed.
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-no-changes/policy.log b/v1.5.7/internal/backend/remote/testdata/plan-no-changes/policy.log
new file mode 100644
index 0000000..b0cb1e5
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-no-changes/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: true
+
+This result means that Sentinel policies returned true and the protected
+behavior is allowed by Sentinel policies.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (soft-mandatory)
+
+Result: true
+
+TRUE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-policy-hard-failed/main.tf b/v1.5.7/internal/backend/remote/testdata/plan-policy-hard-failed/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-policy-hard-failed/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-policy-hard-failed/plan.log b/v1.5.7/internal/backend/remote/testdata/plan-policy-hard-failed/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-policy-hard-failed/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-policy-hard-failed/policy.log b/v1.5.7/internal/backend/remote/testdata/plan-policy-hard-failed/policy.log
new file mode 100644
index 0000000..5d6e693
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-policy-hard-failed/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: false
+
+Sentinel evaluated to false because one or more Sentinel policies evaluated
+to false. This false was not due to an undefined value or runtime error.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (hard-mandatory)
+
+Result: false
+
+FALSE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-policy-passed/main.tf b/v1.5.7/internal/backend/remote/testdata/plan-policy-passed/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-policy-passed/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-policy-passed/plan.log b/v1.5.7/internal/backend/remote/testdata/plan-policy-passed/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-policy-passed/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-policy-passed/policy.log b/v1.5.7/internal/backend/remote/testdata/plan-policy-passed/policy.log
new file mode 100644
index 0000000..b0cb1e5
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-policy-passed/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: true
+
+This result means that Sentinel policies returned true and the protected
+behavior is allowed by Sentinel policies.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (soft-mandatory)
+
+Result: true
+
+TRUE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-policy-soft-failed/main.tf b/v1.5.7/internal/backend/remote/testdata/plan-policy-soft-failed/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-policy-soft-failed/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-policy-soft-failed/plan.log b/v1.5.7/internal/backend/remote/testdata/plan-policy-soft-failed/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-policy-soft-failed/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-policy-soft-failed/policy.log b/v1.5.7/internal/backend/remote/testdata/plan-policy-soft-failed/policy.log
new file mode 100644
index 0000000..3e4ebed
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-policy-soft-failed/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: false
+
+Sentinel evaluated to false because one or more Sentinel policies evaluated
+to false. This false was not due to an undefined value or runtime error.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (soft-mandatory)
+
+Result: false
+
+FALSE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-variables/main.tf b/v1.5.7/internal/backend/remote/testdata/plan-variables/main.tf
new file mode 100644
index 0000000..955e8b4
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-variables/main.tf
@@ -0,0 +1,4 @@
+variable "foo" {}
+variable "bar" {}
+
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-variables/plan.log b/v1.5.7/internal/backend/remote/testdata/plan-variables/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-variables/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-with-error/main.tf b/v1.5.7/internal/backend/remote/testdata/plan-with-error/main.tf
new file mode 100644
index 0000000..bc45f28
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-with-error/main.tf
@@ -0,0 +1,5 @@
+resource "null_resource" "foo" {
+  triggers {
+    random = "${guid()}"
+  }
+}
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-with-error/plan.log b/v1.5.7/internal/backend/remote/testdata/plan-with-error/plan.log
new file mode 100644
index 0000000..4344a37
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-with-error/plan.log
@@ -0,0 +1,10 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+
+Error: null_resource.foo: 1 error(s) occurred:
+
+* null_resource.foo: 1:3: unknown function called: guid in:
+
+${guid()}
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-with-working-directory/terraform/main.tf b/v1.5.7/internal/backend/remote/testdata/plan-with-working-directory/terraform/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-with-working-directory/terraform/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/backend/remote/testdata/plan-with-working-directory/terraform/plan.log b/v1.5.7/internal/backend/remote/testdata/plan-with-working-directory/terraform/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan-with-working-directory/terraform/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/backend/remote/testdata/plan/main.tf b/v1.5.7/internal/backend/remote/testdata/plan/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/backend/remote/testdata/plan/plan.log b/v1.5.7/internal/backend/remote/testdata/plan/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/plan/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/backend/remote/testdata/variables/main.tf b/v1.5.7/internal/backend/remote/testdata/variables/main.tf
new file mode 100644
index 0000000..9e1a0a4
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testdata/variables/main.tf
@@ -0,0 +1,8 @@
+variable "key1" {
+}
+
+variable "key2" {
+}
+
+variable "key3" {
+}
diff --git a/v1.5.7/internal/backend/remote/testing.go b/v1.5.7/internal/backend/remote/testing.go
new file mode 100644
index 0000000..0721087
--- /dev/null
+++ b/v1.5.7/internal/backend/remote/testing.go
@@ -0,0 +1,325 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"net/http"
+	"net/http/httptest"
+	"path"
+	"testing"
+	"time"
+
+	tfe "github.com/hashicorp/go-tfe"
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform-svchost/auth"
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/cloud"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/httpclient"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/hashicorp/terraform/version"
+	"github.com/mitchellh/cli"
+	"github.com/zclconf/go-cty/cty"
+
+	backendLocal "github.com/hashicorp/terraform/internal/backend/local"
+)
+
+const (
+	testCred = "test-auth-token"
+)
+
+var (
+	tfeHost  = svchost.Hostname(defaultHostname)
+	credsSrc = auth.StaticCredentialsSource(map[svchost.Hostname]map[string]interface{}{
+		tfeHost: {"token": testCred},
+	})
+)
+
+// mockInput is a mock implementation of terraform.UIInput.
+type mockInput struct {
+	answers map[string]string
+}
+
+func (m *mockInput) Input(ctx context.Context, opts *terraform.InputOpts) (string, error) {
+	v, ok := m.answers[opts.Id]
+	if !ok {
+		return "", fmt.Errorf("unexpected input request in test: %s", opts.Id)
+	}
+	if v == "wait-for-external-update" {
+		select {
+		case <-ctx.Done():
+		case <-time.After(time.Minute):
+		}
+	}
+	delete(m.answers, opts.Id)
+	return v, nil
+}
+
+func testInput(t *testing.T, answers map[string]string) *mockInput {
+	return &mockInput{answers: answers}
+}
+
+func testBackendDefault(t *testing.T) (*Remote, func()) {
+	obj := cty.ObjectVal(map[string]cty.Value{
+		"hostname":     cty.NullVal(cty.String),
+		"organization": cty.StringVal("hashicorp"),
+		"token":        cty.NullVal(cty.String),
+		"workspaces": cty.ObjectVal(map[string]cty.Value{
+			"name":   cty.StringVal("prod"),
+			"prefix": cty.NullVal(cty.String),
+		}),
+	})
+	return testBackend(t, obj)
+}
+
+func testBackendNoDefault(t *testing.T) (*Remote, func()) {
+	obj := cty.ObjectVal(map[string]cty.Value{
+		"hostname":     cty.NullVal(cty.String),
+		"organization": cty.StringVal("hashicorp"),
+		"token":        cty.NullVal(cty.String),
+		"workspaces": cty.ObjectVal(map[string]cty.Value{
+			"name":   cty.NullVal(cty.String),
+			"prefix": cty.StringVal("my-app-"),
+		}),
+	})
+	return testBackend(t, obj)
+}
+
+func testBackendNoOperations(t *testing.T) (*Remote, func()) {
+	obj := cty.ObjectVal(map[string]cty.Value{
+		"hostname":     cty.NullVal(cty.String),
+		"organization": cty.StringVal("no-operations"),
+		"token":        cty.NullVal(cty.String),
+		"workspaces": cty.ObjectVal(map[string]cty.Value{
+			"name":   cty.StringVal("prod"),
+			"prefix": cty.NullVal(cty.String),
+		}),
+	})
+	return testBackend(t, obj)
+}
+
+func testRemoteClient(t *testing.T) remote.Client {
+	b, bCleanup := testBackendDefault(t)
+	defer bCleanup()
+
+	raw, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("error: %v", err)
+	}
+
+	return raw.(*remote.State).Client
+}
+
+func testBackend(t *testing.T, obj cty.Value) (*Remote, func()) {
+	s := testServer(t)
+	b := New(testDisco(s))
+
+	// Configure the backend so the client is created.
+	newObj, valDiags := b.PrepareConfig(obj)
+	if len(valDiags) != 0 {
+		t.Fatal(valDiags.ErrWithWarnings())
+	}
+	obj = newObj
+
+	confDiags := b.Configure(obj)
+	if len(confDiags) != 0 {
+		t.Fatal(confDiags.ErrWithWarnings())
+	}
+
+	// Get a new mock client.
+	mc := cloud.NewMockClient()
+
+	// Replace the services we use with our mock services.
+	b.CLI = cli.NewMockUi()
+	b.client.Applies = mc.Applies
+	b.client.ConfigurationVersions = mc.ConfigurationVersions
+	b.client.CostEstimates = mc.CostEstimates
+	b.client.Organizations = mc.Organizations
+	b.client.Plans = mc.Plans
+	b.client.PolicyChecks = mc.PolicyChecks
+	b.client.Runs = mc.Runs
+	b.client.RunEvents = mc.RunEvents
+	b.client.StateVersions = mc.StateVersions
+	b.client.Variables = mc.Variables
+	b.client.Workspaces = mc.Workspaces
+
+	// Set local to a local test backend.
+	b.local = testLocalBackend(t, b)
+
+	ctx := context.Background()
+
+	// Create the organization.
+	_, err := b.client.Organizations.Create(ctx, tfe.OrganizationCreateOptions{
+		Name: tfe.String(b.organization),
+	})
+	if err != nil {
+		t.Fatalf("error: %v", err)
+	}
+
+	// Create the default workspace if required.
+	if b.workspace != "" {
+		_, err = b.client.Workspaces.Create(ctx, b.organization, tfe.WorkspaceCreateOptions{
+			Name: tfe.String(b.workspace),
+		})
+		if err != nil {
+			t.Fatalf("error: %v", err)
+		}
+	}
+
+	return b, s.Close
+}
+
+func testLocalBackend(t *testing.T, remote *Remote) backend.Enhanced {
+	b := backendLocal.NewWithBackend(remote)
+
+	// Add a test provider to the local backend.
+	p := backendLocal.TestLocalProvider(t, b, "null", &terraform.ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"null_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{NewState: cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("yes"),
+	})}
+
+	return b
+}
+
+// testServer returns a *httptest.Server used for local testing.
+func testServer(t *testing.T) *httptest.Server {
+	mux := http.NewServeMux()
+
+	// Respond to service discovery calls.
+	mux.HandleFunc("/well-known/terraform.json", func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/json")
+		io.WriteString(w, `{
+  "state.v2": "/api/v2/",
+  "tfe.v2.1": "/api/v2/",
+  "versions.v1": "/v1/versions/"
+}`)
+	})
+
+	// Respond to service version constraints calls.
+	mux.HandleFunc("/v1/versions/", func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/json")
+		io.WriteString(w, fmt.Sprintf(`{
+  "service": "%s",
+  "product": "terraform",
+  "minimum": "0.1.0",
+  "maximum": "10.0.0"
+}`, path.Base(r.URL.Path)))
+	})
+
+	// Respond to pings to get the API version header.
+	mux.HandleFunc("/api/v2/ping", func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/json")
+		w.Header().Set("TFP-API-Version", "2.4")
+	})
+
+	// Respond to the initial query to read the hashicorp org entitlements.
+	mux.HandleFunc("/api/v2/organizations/hashicorp/entitlement-set", func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/vnd.api+json")
+		io.WriteString(w, `{
+  "data": {
+    "id": "org-GExadygjSbKP8hsY",
+    "type": "entitlement-sets",
+    "attributes": {
+      "operations": true,
+      "private-module-registry": true,
+      "sentinel": true,
+      "state-storage": true,
+      "teams": true,
+      "vcs-integrations": true
+    }
+  }
+}`)
+	})
+
+	// Respond to the initial query to read the no-operations org entitlements.
+	mux.HandleFunc("/api/v2/organizations/no-operations/entitlement-set", func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/vnd.api+json")
+		io.WriteString(w, `{
+  "data": {
+    "id": "org-ufxa3y8jSbKP8hsT",
+    "type": "entitlement-sets",
+    "attributes": {
+      "operations": false,
+      "private-module-registry": true,
+      "sentinel": true,
+      "state-storage": true,
+      "teams": true,
+      "vcs-integrations": true
+    }
+  }
+}`)
+	})
+
+	// All tests that are assumed to pass will use the hashicorp organization,
+	// so for all other organization requests we will return a 404.
+	mux.HandleFunc("/api/v2/organizations/", func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(404)
+		io.WriteString(w, `{
+  "errors": [
+    {
+      "status": "404",
+      "title": "not found"
+    }
+  ]
+}`)
+	})
+
+	return httptest.NewServer(mux)
+}
+
+// testDisco returns a *disco.Disco mapping app.terraform.io and
+// localhost to a local test server.
+func testDisco(s *httptest.Server) *disco.Disco {
+	services := map[string]interface{}{
+		"state.v2":    fmt.Sprintf("%s/api/v2/", s.URL),
+		"tfe.v2.1":    fmt.Sprintf("%s/api/v2/", s.URL),
+		"versions.v1": fmt.Sprintf("%s/v1/versions/", s.URL),
+	}
+	d := disco.NewWithCredentialsSource(credsSrc)
+	d.SetUserAgent(httpclient.TerraformUserAgent(version.String()))
+
+	d.ForceHostServices(svchost.Hostname(defaultHostname), services)
+	d.ForceHostServices(svchost.Hostname("localhost"), services)
+	return d
+}
+
+type unparsedVariableValue struct {
+	value  string
+	source terraform.ValueSourceType
+}
+
+func (v *unparsedVariableValue) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) {
+	return &terraform.InputValue{
+		Value:      cty.StringVal(v.value),
+		SourceType: v.source,
+	}, tfdiags.Diagnostics{}
+}
+
+// testVariable returns a backend.UnparsedVariableValue used for testing.
+func testVariables(s terraform.ValueSourceType, vs ...string) map[string]backend.UnparsedVariableValue {
+	vars := make(map[string]backend.UnparsedVariableValue, len(vs))
+	for _, v := range vs {
+		vars[v] = &unparsedVariableValue{
+			value:  v,
+			source: s,
+		}
+	}
+	return vars
+}
diff --git a/v1.5.7/internal/backend/testing.go b/v1.5.7/internal/backend/testing.go
new file mode 100644
index 0000000..5c8eac3
--- /dev/null
+++ b/v1.5.7/internal/backend/testing.go
@@ -0,0 +1,428 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package backend
+
+import (
+	"reflect"
+	"sort"
+	"testing"
+
+	uuid "github.com/hashicorp/go-uuid"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcldec"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// TestBackendConfig validates and configures the backend with the
+// given configuration.
+func TestBackendConfig(t *testing.T, b Backend, c hcl.Body) Backend {
+	t.Helper()
+
+	t.Logf("TestBackendConfig on %T with %#v", b, c)
+
+	var diags tfdiags.Diagnostics
+
+	// To make things easier for test authors, we'll allow a nil body here
+	// (even though that's not normally valid) and just treat it as an empty
+	// body.
+	if c == nil {
+		c = hcl.EmptyBody()
+	}
+
+	schema := b.ConfigSchema()
+	spec := schema.DecoderSpec()
+	obj, decDiags := hcldec.Decode(c, spec, nil)
+	diags = diags.Append(decDiags)
+
+	newObj, valDiags := b.PrepareConfig(obj)
+	diags = diags.Append(valDiags.InConfigBody(c, ""))
+
+	// it's valid for a Backend to have warnings (e.g. a Deprecation) as such we should only raise on errors
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	obj = newObj
+
+	confDiags := b.Configure(obj)
+	if len(confDiags) != 0 {
+		confDiags = confDiags.InConfigBody(c, "")
+		t.Fatal(confDiags.ErrWithWarnings())
+	}
+
+	return b
+}
+
+// TestWrapConfig takes a raw data structure and converts it into a
+// synthetic hcl.Body to use for testing.
+//
+// The given structure should only include values that can be accepted by
+// hcl2shim.HCL2ValueFromConfigValue. If incompatible values are given,
+// this function will panic.
+func TestWrapConfig(raw map[string]interface{}) hcl.Body {
+	obj := hcl2shim.HCL2ValueFromConfigValue(raw)
+	return configs.SynthBody("<TestWrapConfig>", obj.AsValueMap())
+}
+
+// TestBackend will test the functionality of a Backend. The backend is
+// assumed to already be configured. This will test state functionality.
+// If the backend reports it doesn't support multi-state by returning the
+// error ErrWorkspacesNotSupported, then it will not test that.
+func TestBackendStates(t *testing.T, b Backend) {
+	t.Helper()
+
+	noDefault := false
+	if _, err := b.StateMgr(DefaultStateName); err != nil {
+		if err == ErrDefaultWorkspaceNotSupported {
+			noDefault = true
+		} else {
+			t.Fatalf("error: %v", err)
+		}
+	}
+
+	workspaces, err := b.Workspaces()
+	if err != nil {
+		if err == ErrWorkspacesNotSupported {
+			t.Logf("TestBackend: workspaces not supported in %T, skipping", b)
+			return
+		}
+		t.Fatalf("error: %v", err)
+	}
+
+	// Test it starts with only the default
+	if !noDefault && (len(workspaces) != 1 || workspaces[0] != DefaultStateName) {
+		t.Fatalf("should only have the default workspace to start: %#v", workspaces)
+	}
+
+	// Create a couple states
+	foo, err := b.StateMgr("foo")
+	if err != nil {
+		t.Fatalf("error: %s", err)
+	}
+	if err := foo.RefreshState(); err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	if v := foo.State(); v.HasManagedResourceInstanceObjects() {
+		t.Fatalf("should be empty: %s", v)
+	}
+
+	bar, err := b.StateMgr("bar")
+	if err != nil {
+		t.Fatalf("error: %s", err)
+	}
+	if err := bar.RefreshState(); err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	if v := bar.State(); v.HasManagedResourceInstanceObjects() {
+		t.Fatalf("should be empty: %s", v)
+	}
+
+	// Verify they are distinct states that can be read back from storage
+	{
+		// We'll use two distinct states here and verify that changing one
+		// does not also change the other.
+		fooState := states.NewState()
+		barState := states.NewState()
+
+		// write a known state to foo
+		if err := foo.WriteState(fooState); err != nil {
+			t.Fatal("error writing foo state:", err)
+		}
+		if err := foo.PersistState(nil); err != nil {
+			t.Fatal("error persisting foo state:", err)
+		}
+
+		// We'll make "bar" different by adding a fake resource state to it.
+		barState.SyncWrapper().SetResourceInstanceCurrent(
+			addrs.ResourceInstance{
+				Resource: addrs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "test_thing",
+					Name: "foo",
+				},
+			}.Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON:     []byte("{}"),
+				Status:        states.ObjectReady,
+				SchemaVersion: 0,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+
+		// write a distinct known state to bar
+		if err := bar.WriteState(barState); err != nil {
+			t.Fatalf("bad: %s", err)
+		}
+		if err := bar.PersistState(nil); err != nil {
+			t.Fatalf("bad: %s", err)
+		}
+
+		// verify that foo is unchanged with the existing state manager
+		if err := foo.RefreshState(); err != nil {
+			t.Fatal("error refreshing foo:", err)
+		}
+		fooState = foo.State()
+		if fooState.HasManagedResourceInstanceObjects() {
+			t.Fatal("after writing a resource to bar, foo now has resources too")
+		}
+
+		// fetch foo again from the backend
+		foo, err = b.StateMgr("foo")
+		if err != nil {
+			t.Fatal("error re-fetching state:", err)
+		}
+		if err := foo.RefreshState(); err != nil {
+			t.Fatal("error refreshing foo:", err)
+		}
+		fooState = foo.State()
+		if fooState.HasManagedResourceInstanceObjects() {
+			t.Fatal("after writing a resource to bar and re-reading foo, foo now has resources too")
+		}
+
+		// fetch the bar again from the backend
+		bar, err = b.StateMgr("bar")
+		if err != nil {
+			t.Fatal("error re-fetching state:", err)
+		}
+		if err := bar.RefreshState(); err != nil {
+			t.Fatal("error refreshing bar:", err)
+		}
+		barState = bar.State()
+		if !barState.HasManagedResourceInstanceObjects() {
+			t.Fatal("after writing a resource instance object to bar and re-reading it, the object has vanished")
+		}
+	}
+
+	// Verify we can now list them
+	{
+		// we determined that named stated are supported earlier
+		workspaces, err := b.Workspaces()
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		sort.Strings(workspaces)
+		expected := []string{"bar", "default", "foo"}
+		if noDefault {
+			expected = []string{"bar", "foo"}
+		}
+		if !reflect.DeepEqual(workspaces, expected) {
+			t.Fatalf("wrong workspaces list\ngot:  %#v\nwant: %#v", workspaces, expected)
+		}
+	}
+
+	// Delete some workspaces
+	if err := b.DeleteWorkspace("foo", true); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Verify the default state can't be deleted
+	if err := b.DeleteWorkspace(DefaultStateName, true); err == nil {
+		t.Fatal("expected error")
+	}
+
+	// Create and delete the foo workspace again.
+	// Make sure that there are no leftover artifacts from a deleted state
+	// preventing re-creation.
+	foo, err = b.StateMgr("foo")
+	if err != nil {
+		t.Fatalf("error: %s", err)
+	}
+	if err := foo.RefreshState(); err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+	if v := foo.State(); v.HasManagedResourceInstanceObjects() {
+		t.Fatalf("should be empty: %s", v)
+	}
+	// and delete it again
+	if err := b.DeleteWorkspace("foo", true); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Verify deletion
+	{
+		workspaces, err := b.Workspaces()
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		sort.Strings(workspaces)
+		expected := []string{"bar", "default"}
+		if noDefault {
+			expected = []string{"bar"}
+		}
+		if !reflect.DeepEqual(workspaces, expected) {
+			t.Fatalf("wrong workspaces list\ngot:  %#v\nwant: %#v", workspaces, expected)
+		}
+	}
+}
+
+// TestBackendStateLocks will test the locking functionality of the remote
+// state backend.
+func TestBackendStateLocks(t *testing.T, b1, b2 Backend) {
+	t.Helper()
+	testLocks(t, b1, b2, false)
+}
+
+// TestBackendStateForceUnlock verifies that the lock error is the expected
+// type, and the lock can be unlocked using the ID reported in the error.
+// Remote state backends that support -force-unlock should call this in at
+// least one of the acceptance tests.
+func TestBackendStateForceUnlock(t *testing.T, b1, b2 Backend) {
+	t.Helper()
+	testLocks(t, b1, b2, true)
+}
+
+// TestBackendStateLocksInWS will test the locking functionality of the remote
+// state backend.
+func TestBackendStateLocksInWS(t *testing.T, b1, b2 Backend, ws string) {
+	t.Helper()
+	testLocksInWorkspace(t, b1, b2, false, ws)
+}
+
+// TestBackendStateForceUnlockInWS verifies that the lock error is the expected
+// type, and the lock can be unlocked using the ID reported in the error.
+// Remote state backends that support -force-unlock should call this in at
+// least one of the acceptance tests.
+func TestBackendStateForceUnlockInWS(t *testing.T, b1, b2 Backend, ws string) {
+	t.Helper()
+	testLocksInWorkspace(t, b1, b2, true, ws)
+}
+
+func testLocks(t *testing.T, b1, b2 Backend, testForceUnlock bool) {
+	testLocksInWorkspace(t, b1, b2, testForceUnlock, DefaultStateName)
+}
+
+func testLocksInWorkspace(t *testing.T, b1, b2 Backend, testForceUnlock bool, workspace string) {
+	t.Helper()
+
+	// Get the default state for each
+	b1StateMgr, err := b1.StateMgr(DefaultStateName)
+	if err != nil {
+		t.Fatalf("error: %s", err)
+	}
+	if err := b1StateMgr.RefreshState(); err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+
+	// Fast exit if this doesn't support locking at all
+	if _, ok := b1StateMgr.(statemgr.Locker); !ok {
+		t.Logf("TestBackend: backend %T doesn't support state locking, not testing", b1)
+		return
+	}
+
+	t.Logf("TestBackend: testing state locking for %T", b1)
+
+	b2StateMgr, err := b2.StateMgr(DefaultStateName)
+	if err != nil {
+		t.Fatalf("error: %s", err)
+	}
+	if err := b2StateMgr.RefreshState(); err != nil {
+		t.Fatalf("bad: %s", err)
+	}
+
+	// Reassign so its obvious whats happening
+	lockerA := b1StateMgr.(statemgr.Locker)
+	lockerB := b2StateMgr.(statemgr.Locker)
+
+	infoA := statemgr.NewLockInfo()
+	infoA.Operation = "test"
+	infoA.Who = "clientA"
+
+	infoB := statemgr.NewLockInfo()
+	infoB.Operation = "test"
+	infoB.Who = "clientB"
+
+	lockIDA, err := lockerA.Lock(infoA)
+	if err != nil {
+		t.Fatal("unable to get initial lock:", err)
+	}
+
+	// Make sure we can still get the statemgr.Full from another instance even
+	// when locked.  This should only happen when a state is loaded via the
+	// backend, and as a remote state.
+	_, err = b2.StateMgr(DefaultStateName)
+	if err != nil {
+		t.Errorf("failed to read locked state from another backend instance: %s", err)
+	}
+
+	// If the lock ID is blank, assume locking is disabled
+	if lockIDA == "" {
+		t.Logf("TestBackend: %T: empty string returned for lock, assuming disabled", b1)
+		return
+	}
+
+	_, err = lockerB.Lock(infoB)
+	if err == nil {
+		lockerA.Unlock(lockIDA)
+		t.Fatal("client B obtained lock while held by client A")
+	}
+
+	if err := lockerA.Unlock(lockIDA); err != nil {
+		t.Fatal("error unlocking client A", err)
+	}
+
+	lockIDB, err := lockerB.Lock(infoB)
+	if err != nil {
+		t.Fatal("unable to obtain lock from client B")
+	}
+
+	if lockIDB == lockIDA {
+		t.Errorf("duplicate lock IDs: %q", lockIDB)
+	}
+
+	if err = lockerB.Unlock(lockIDB); err != nil {
+		t.Fatal("error unlocking client B:", err)
+	}
+
+	// test the equivalent of -force-unlock, by using the id from the error
+	// output.
+	if !testForceUnlock {
+		return
+	}
+
+	// get a new ID
+	infoA.ID, err = uuid.GenerateUUID()
+	if err != nil {
+		panic(err)
+	}
+
+	lockIDA, err = lockerA.Lock(infoA)
+	if err != nil {
+		t.Fatal("unable to get re lock A:", err)
+	}
+	unlock := func() {
+		err := lockerA.Unlock(lockIDA)
+		if err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	_, err = lockerB.Lock(infoB)
+	if err == nil {
+		unlock()
+		t.Fatal("client B obtained lock while held by client A")
+	}
+
+	infoErr, ok := err.(*statemgr.LockError)
+	if !ok {
+		unlock()
+		t.Fatalf("expected type *statemgr.LockError, got : %#v", err)
+	}
+
+	// try to unlock with the second unlocker, using the ID from the error
+	if err := lockerB.Unlock(infoErr.Info.ID); err != nil {
+		unlock()
+		t.Fatalf("could not unlock with the reported ID %q: %s", infoErr.Info.ID, err)
+	}
+}
diff --git a/v1.5.7/internal/backend/unparsed_value.go b/v1.5.7/internal/backend/unparsed_value.go
new file mode 100644
index 0000000..15b43e7
--- /dev/null
+++ b/v1.5.7/internal/backend/unparsed_value.go
@@ -0,0 +1,215 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package backend
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// UnparsedVariableValue represents a variable value provided by the caller
+// whose parsing must be deferred until configuration is available.
+//
+// This exists to allow processing of variable-setting arguments (e.g. in the
+// command package) to be separated from parsing (in the backend package).
+type UnparsedVariableValue interface {
+	// ParseVariableValue information in the provided variable configuration
+	// to parse (if necessary) and return the variable value encapsulated in
+	// the receiver.
+	//
+	// If error diagnostics are returned, the resulting value may be invalid
+	// or incomplete.
+	ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics)
+}
+
+// ParseUndeclaredVariableValues processes a map of unparsed variable values
+// and returns an input values map of the ones not declared in the specified
+// declaration map along with detailed diagnostics about values of undeclared
+// variables being present, depending on the source of these values. If more
+// than two undeclared values are present in file form (config, auto, -var-file)
+// the remaining errors are summarized to avoid a massive list of errors.
+func ParseUndeclaredVariableValues(vv map[string]UnparsedVariableValue, decls map[string]*configs.Variable) (terraform.InputValues, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	ret := make(terraform.InputValues, len(vv))
+	seenUndeclaredInFile := 0
+
+	for name, rv := range vv {
+		if _, declared := decls[name]; declared {
+			// Only interested in parsing undeclared variables
+			continue
+		}
+
+		val, valDiags := rv.ParseVariableValue(configs.VariableParseLiteral)
+		if valDiags.HasErrors() {
+			continue
+		}
+
+		ret[name] = val
+
+		switch val.SourceType {
+		case terraform.ValueFromConfig, terraform.ValueFromAutoFile, terraform.ValueFromNamedFile:
+			// We allow undeclared names for variable values from files and warn in case
+			// users have forgotten a variable {} declaration or have a typo in their var name.
+			// Some users will actively ignore this warning because they use a .tfvars file
+			// across multiple configurations.
+			if seenUndeclaredInFile < 2 {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Warning,
+					"Value for undeclared variable",
+					fmt.Sprintf("The root module does not declare a variable named %q but a value was found in file %q. If you meant to use this value, add a \"variable\" block to the configuration.\n\nTo silence these warnings, use TF_VAR_... environment variables to provide certain \"global\" settings to all configurations in your organization. To reduce the verbosity of these warnings, use the -compact-warnings option.", name, val.SourceRange.Filename),
+				))
+			}
+			seenUndeclaredInFile++
+
+		case terraform.ValueFromEnvVar:
+			// We allow and ignore undeclared names for environment
+			// variables, because users will often set these globally
+			// when they are used across many (but not necessarily all)
+			// configurations.
+		case terraform.ValueFromCLIArg:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Value for undeclared variable",
+				fmt.Sprintf("A variable named %q was assigned on the command line, but the root module does not declare a variable of that name. To use this value, add a \"variable\" block to the configuration.", name),
+			))
+		default:
+			// For all other source types we are more vague, but other situations
+			// don't generally crop up at this layer in practice.
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Value for undeclared variable",
+				fmt.Sprintf("A variable named %q was assigned a value, but the root module does not declare a variable of that name. To use this value, add a \"variable\" block to the configuration.", name),
+			))
+		}
+	}
+
+	if seenUndeclaredInFile > 2 {
+		extras := seenUndeclaredInFile - 2
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagWarning,
+			Summary:  "Values for undeclared variables",
+			Detail:   fmt.Sprintf("In addition to the other similar warnings shown, %d other variable(s) defined without being declared.", extras),
+		})
+	}
+
+	return ret, diags
+}
+
+// ParseDeclaredVariableValues processes a map of unparsed variable values
+// and returns an input values map of the ones declared in the specified
+// variable declaration mapping. Diagnostics will be populating with
+// any variable parsing errors encountered within this collection.
+func ParseDeclaredVariableValues(vv map[string]UnparsedVariableValue, decls map[string]*configs.Variable) (terraform.InputValues, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	ret := make(terraform.InputValues, len(vv))
+
+	for name, rv := range vv {
+		var mode configs.VariableParsingMode
+		config, declared := decls[name]
+
+		if declared {
+			mode = config.ParsingMode
+		} else {
+			// Only interested in parsing declared variables
+			continue
+		}
+
+		val, valDiags := rv.ParseVariableValue(mode)
+		diags = diags.Append(valDiags)
+		if valDiags.HasErrors() {
+			continue
+		}
+
+		ret[name] = val
+	}
+
+	return ret, diags
+}
+
+// Checks all given terraform.InputValues variable maps for the existance of
+// a named variable
+func isDefinedAny(name string, maps ...terraform.InputValues) bool {
+	for _, m := range maps {
+		if _, defined := m[name]; defined {
+			return true
+		}
+	}
+	return false
+}
+
+// ParseVariableValues processes a map of unparsed variable values by
+// correlating each one with the given variable declarations which should
+// be from a root module.
+//
+// The map of unparsed variable values should include variables from all
+// possible root module declarations sources such that it is as complete as
+// it can possibly be for the current operation. If any declared variables
+// are not included in the map, ParseVariableValues will either substitute
+// a configured default value or produce an error.
+//
+// If this function returns without any errors in the diagnostics, the
+// resulting input values map is guaranteed to be valid and ready to pass
+// to terraform.NewContext. If the diagnostics contains errors, the returned
+// InputValues may be incomplete but will include the subset of variables
+// that were successfully processed, allowing for careful analysis of the
+// partial result.
+func ParseVariableValues(vv map[string]UnparsedVariableValue, decls map[string]*configs.Variable) (terraform.InputValues, tfdiags.Diagnostics) {
+	ret, diags := ParseDeclaredVariableValues(vv, decls)
+	undeclared, diagsUndeclared := ParseUndeclaredVariableValues(vv, decls)
+
+	diags = diags.Append(diagsUndeclared)
+
+	// By this point we should've gathered all of the required root module
+	// variables from one of the many possible sources. We'll now populate
+	// any we haven't gathered as unset placeholders which Terraform Core
+	// can then react to.
+	for name, vc := range decls {
+		if isDefinedAny(name, ret, undeclared) {
+			continue
+		}
+
+		// This check is redundant with a check made in Terraform Core when
+		// processing undeclared variables, but allows us to generate a more
+		// specific error message which mentions -var and -var-file command
+		// line options, whereas the one in Terraform Core is more general
+		// due to supporting both root and child module variables.
+		if vc.Required() {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "No value for required variable",
+				Detail:   fmt.Sprintf("The root module input variable %q is not set, and has no default value. Use a -var or -var-file command line argument to provide a value for this variable.", name),
+				Subject:  vc.DeclRange.Ptr(),
+			})
+
+			// We'll include a placeholder value anyway, just so that our
+			// result is complete for any calling code that wants to cautiously
+			// analyze it for diagnostic purposes. Since our diagnostics now
+			// includes an error, normal processing will ignore this result.
+			ret[name] = &terraform.InputValue{
+				Value:       cty.DynamicVal,
+				SourceType:  terraform.ValueFromConfig,
+				SourceRange: tfdiags.SourceRangeFromHCL(vc.DeclRange),
+			}
+		} else {
+			// We're still required to put an entry for this variable
+			// in the mapping to be explicit to Terraform Core that we
+			// visited it, but its value will be cty.NilVal to represent
+			// that it wasn't set at all at this layer, and so Terraform Core
+			// should substitute a default if available, or generate an error
+			// if not.
+			ret[name] = &terraform.InputValue{
+				Value:       cty.NilVal,
+				SourceType:  terraform.ValueFromConfig,
+				SourceRange: tfdiags.SourceRangeFromHCL(vc.DeclRange),
+			}
+		}
+	}
+
+	return ret, diags
+}
diff --git a/v1.5.7/internal/backend/unparsed_value_test.go b/v1.5.7/internal/backend/unparsed_value_test.go
new file mode 100644
index 0000000..0ae925e
--- /dev/null
+++ b/v1.5.7/internal/backend/unparsed_value_test.go
@@ -0,0 +1,237 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package backend
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestUnparsedValue(t *testing.T) {
+	vv := map[string]UnparsedVariableValue{
+		"undeclared0": testUnparsedVariableValue("0"),
+		"undeclared1": testUnparsedVariableValue("1"),
+		"undeclared2": testUnparsedVariableValue("2"),
+		"undeclared3": testUnparsedVariableValue("3"),
+		"undeclared4": testUnparsedVariableValue("4"),
+		"declared1":   testUnparsedVariableValue("5"),
+	}
+	decls := map[string]*configs.Variable{
+		"declared1": {
+			Name:           "declared1",
+			Type:           cty.String,
+			ConstraintType: cty.String,
+			ParsingMode:    configs.VariableParseLiteral,
+			DeclRange: hcl.Range{
+				Filename: "fake.tf",
+				Start:    hcl.Pos{Line: 2, Column: 1, Byte: 0},
+				End:      hcl.Pos{Line: 2, Column: 1, Byte: 0},
+			},
+		},
+		"missing1": {
+			Name:           "missing1",
+			Type:           cty.String,
+			ConstraintType: cty.String,
+			ParsingMode:    configs.VariableParseLiteral,
+			DeclRange: hcl.Range{
+				Filename: "fake.tf",
+				Start:    hcl.Pos{Line: 3, Column: 1, Byte: 0},
+				End:      hcl.Pos{Line: 3, Column: 1, Byte: 0},
+			},
+		},
+		"missing2": {
+			Name:           "missing1",
+			Type:           cty.String,
+			ConstraintType: cty.String,
+			ParsingMode:    configs.VariableParseLiteral,
+			Default:        cty.StringVal("default for missing2"),
+			DeclRange: hcl.Range{
+				Filename: "fake.tf",
+				Start:    hcl.Pos{Line: 4, Column: 1, Byte: 0},
+				End:      hcl.Pos{Line: 4, Column: 1, Byte: 0},
+			},
+		},
+	}
+
+	const undeclSingular = `Value for undeclared variable`
+	const undeclPlural = `Values for undeclared variables`
+
+	t.Run("ParseDeclaredVariableValues", func(t *testing.T) {
+		gotVals, diags := ParseDeclaredVariableValues(vv, decls)
+
+		if got, want := len(diags), 0; got != want {
+			t.Fatalf("wrong number of diagnostics %d; want %d", got, want)
+		}
+
+		wantVals := terraform.InputValues{
+			"declared1": {
+				Value:      cty.StringVal("5"),
+				SourceType: terraform.ValueFromNamedFile,
+				SourceRange: tfdiags.SourceRange{
+					Filename: "fake.tfvars",
+					Start:    tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:      tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+				},
+			},
+		}
+
+		if diff := cmp.Diff(wantVals, gotVals, cmp.Comparer(cty.Value.RawEquals)); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+
+	t.Run("ParseUndeclaredVariableValues", func(t *testing.T) {
+		gotVals, diags := ParseUndeclaredVariableValues(vv, decls)
+
+		if got, want := len(diags), 3; got != want {
+			t.Fatalf("wrong number of diagnostics %d; want %d", got, want)
+		}
+
+		if got, want := diags[0].Description().Summary, undeclSingular; got != want {
+			t.Errorf("wrong summary for diagnostic 0\ngot:  %s\nwant: %s", got, want)
+		}
+
+		if got, want := diags[1].Description().Summary, undeclSingular; got != want {
+			t.Errorf("wrong summary for diagnostic 1\ngot:  %s\nwant: %s", got, want)
+		}
+
+		if got, want := diags[2].Description().Summary, undeclPlural; got != want {
+			t.Errorf("wrong summary for diagnostic 2\ngot:  %s\nwant: %s", got, want)
+		}
+
+		wantVals := terraform.InputValues{
+			"undeclared0": {
+				Value:      cty.StringVal("0"),
+				SourceType: terraform.ValueFromNamedFile,
+				SourceRange: tfdiags.SourceRange{
+					Filename: "fake.tfvars",
+					Start:    tfdiags.SourcePos{Line: 1, Column: 1},
+					End:      tfdiags.SourcePos{Line: 1, Column: 1},
+				},
+			},
+			"undeclared1": {
+				Value:      cty.StringVal("1"),
+				SourceType: terraform.ValueFromNamedFile,
+				SourceRange: tfdiags.SourceRange{
+					Filename: "fake.tfvars",
+					Start:    tfdiags.SourcePos{Line: 1, Column: 1},
+					End:      tfdiags.SourcePos{Line: 1, Column: 1},
+				},
+			},
+			"undeclared2": {
+				Value:      cty.StringVal("2"),
+				SourceType: terraform.ValueFromNamedFile,
+				SourceRange: tfdiags.SourceRange{
+					Filename: "fake.tfvars",
+					Start:    tfdiags.SourcePos{Line: 1, Column: 1},
+					End:      tfdiags.SourcePos{Line: 1, Column: 1},
+				},
+			},
+			"undeclared3": {
+				Value:      cty.StringVal("3"),
+				SourceType: terraform.ValueFromNamedFile,
+				SourceRange: tfdiags.SourceRange{
+					Filename: "fake.tfvars",
+					Start:    tfdiags.SourcePos{Line: 1, Column: 1},
+					End:      tfdiags.SourcePos{Line: 1, Column: 1},
+				},
+			},
+			"undeclared4": {
+				Value:      cty.StringVal("4"),
+				SourceType: terraform.ValueFromNamedFile,
+				SourceRange: tfdiags.SourceRange{
+					Filename: "fake.tfvars",
+					Start:    tfdiags.SourcePos{Line: 1, Column: 1},
+					End:      tfdiags.SourcePos{Line: 1, Column: 1},
+				},
+			},
+		}
+		if diff := cmp.Diff(wantVals, gotVals, cmp.Comparer(cty.Value.RawEquals)); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+
+	t.Run("ParseVariableValues", func(t *testing.T) {
+		gotVals, diags := ParseVariableValues(vv, decls)
+		for _, diag := range diags {
+			t.Logf("%s: %s", diag.Description().Summary, diag.Description().Detail)
+		}
+		if got, want := len(diags), 4; got != want {
+			t.Fatalf("wrong number of diagnostics %d; want %d", got, want)
+		}
+
+		const missingRequired = `No value for required variable`
+
+		if got, want := diags[0].Description().Summary, undeclSingular; got != want {
+			t.Errorf("wrong summary for diagnostic 0\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := diags[1].Description().Summary, undeclSingular; got != want {
+			t.Errorf("wrong summary for diagnostic 1\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := diags[2].Description().Summary, undeclPlural; got != want {
+			t.Errorf("wrong summary for diagnostic 2\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := diags[2].Description().Detail, "3 other variable(s)"; !strings.Contains(got, want) {
+			t.Errorf("wrong detail for diagnostic 2\ngot:  %s\nmust contain: %s", got, want)
+		}
+		if got, want := diags[3].Description().Summary, missingRequired; got != want {
+			t.Errorf("wrong summary for diagnostic 3\ngot:  %s\nwant: %s", got, want)
+		}
+
+		wantVals := terraform.InputValues{
+			"declared1": {
+				Value:      cty.StringVal("5"),
+				SourceType: terraform.ValueFromNamedFile,
+				SourceRange: tfdiags.SourceRange{
+					Filename: "fake.tfvars",
+					Start:    tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					End:      tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+				},
+			},
+			"missing1": {
+				Value:      cty.DynamicVal,
+				SourceType: terraform.ValueFromConfig,
+				SourceRange: tfdiags.SourceRange{
+					Filename: "fake.tf",
+					Start:    tfdiags.SourcePos{Line: 3, Column: 1, Byte: 0},
+					End:      tfdiags.SourcePos{Line: 3, Column: 1, Byte: 0},
+				},
+			},
+			"missing2": {
+				Value:      cty.NilVal, // Terraform Core handles substituting the default
+				SourceType: terraform.ValueFromConfig,
+				SourceRange: tfdiags.SourceRange{
+					Filename: "fake.tf",
+					Start:    tfdiags.SourcePos{Line: 4, Column: 1, Byte: 0},
+					End:      tfdiags.SourcePos{Line: 4, Column: 1, Byte: 0},
+				},
+			},
+		}
+		if diff := cmp.Diff(wantVals, gotVals, cmp.Comparer(cty.Value.RawEquals)); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+}
+
+type testUnparsedVariableValue string
+
+func (v testUnparsedVariableValue) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) {
+	return &terraform.InputValue{
+		Value:      cty.StringVal(string(v)),
+		SourceType: terraform.ValueFromNamedFile,
+		SourceRange: tfdiags.SourceRange{
+			Filename: "fake.tfvars",
+			Start:    tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+			End:      tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+		},
+	}, nil
+}
diff --git a/v1.5.7/internal/builtin/providers/README b/v1.5.7/internal/builtin/providers/README
new file mode 100644
index 0000000..00ffa71
--- /dev/null
+++ b/v1.5.7/internal/builtin/providers/README
@@ -0,0 +1 @@
+providers moved to github.com/terraform-providers
diff --git a/v1.5.7/internal/builtin/providers/terraform/data_source_state.go b/v1.5.7/internal/builtin/providers/terraform/data_source_state.go
new file mode 100644
index 0000000..28e4c9e
--- /dev/null
+++ b/v1.5.7/internal/builtin/providers/terraform/data_source_state.go
@@ -0,0 +1,266 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/backend/remote"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+
+	backendInit "github.com/hashicorp/terraform/internal/backend/init"
+)
+
+func dataSourceRemoteStateGetSchema() providers.Schema {
+	return providers.Schema{
+		Block: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"backend": {
+					Type:            cty.String,
+					Description:     "The remote backend to use, e.g. `remote` or `http`.",
+					DescriptionKind: configschema.StringMarkdown,
+					Required:        true,
+				},
+				"config": {
+					Type: cty.DynamicPseudoType,
+					Description: "The configuration of the remote backend. " +
+						"Although this is optional, most backends require " +
+						"some configuration.\n\n" +
+						"The object can use any arguments that would be valid " +
+						"in the equivalent `terraform { backend \"<TYPE>\" { ... } }` " +
+						"block.",
+					DescriptionKind: configschema.StringMarkdown,
+					Optional:        true,
+				},
+				"defaults": {
+					Type: cty.DynamicPseudoType,
+					Description: "Default values for outputs, in case " +
+						"the state file is empty or lacks a required output.",
+					DescriptionKind: configschema.StringMarkdown,
+					Optional:        true,
+				},
+				"outputs": {
+					Type: cty.DynamicPseudoType,
+					Description: "An object containing every root-level " +
+						"output in the remote state.",
+					DescriptionKind: configschema.StringMarkdown,
+					Computed:        true,
+				},
+				"workspace": {
+					Type: cty.String,
+					Description: "The Terraform workspace to use, if " +
+						"the backend supports workspaces.",
+					DescriptionKind: configschema.StringMarkdown,
+					Optional:        true,
+				},
+			},
+		},
+	}
+}
+
+func dataSourceRemoteStateValidate(cfg cty.Value) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	// Getting the backend implicitly validates the configuration for it,
+	// but we can only do that if it's all known already.
+	if cfg.GetAttr("config").IsWhollyKnown() && cfg.GetAttr("backend").IsKnown() {
+		_, _, moreDiags := getBackend(cfg)
+		diags = diags.Append(moreDiags)
+	} else {
+		// Otherwise we'll just type-check the config object itself.
+		configTy := cfg.GetAttr("config").Type()
+		if configTy != cty.DynamicPseudoType && !(configTy.IsObjectType() || configTy.IsMapType()) {
+			diags = diags.Append(tfdiags.AttributeValue(
+				tfdiags.Error,
+				"Invalid backend configuration",
+				"The configuration must be an object value.",
+				cty.GetAttrPath("config"),
+			))
+		}
+	}
+
+	{
+		defaultsTy := cfg.GetAttr("defaults").Type()
+		if defaultsTy != cty.DynamicPseudoType && !(defaultsTy.IsObjectType() || defaultsTy.IsMapType()) {
+			diags = diags.Append(tfdiags.AttributeValue(
+				tfdiags.Error,
+				"Invalid default values",
+				"Defaults must be given in an object value.",
+				cty.GetAttrPath("defaults"),
+			))
+		}
+	}
+
+	return diags
+}
+
+func dataSourceRemoteStateRead(d cty.Value) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	b, cfg, moreDiags := getBackend(d)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		return cty.NilVal, diags
+	}
+
+	configureDiags := b.Configure(cfg)
+	if configureDiags.HasErrors() {
+		diags = diags.Append(configureDiags.Err())
+		return cty.NilVal, diags
+	}
+
+	newState := make(map[string]cty.Value)
+	newState["backend"] = d.GetAttr("backend")
+	newState["config"] = d.GetAttr("config")
+
+	workspaceVal := d.GetAttr("workspace")
+	// This attribute is not computed, so we always have to store the state
+	// value, even if we implicitly use a default.
+	newState["workspace"] = workspaceVal
+
+	workspaceName := backend.DefaultStateName
+	if !workspaceVal.IsNull() {
+		workspaceName = workspaceVal.AsString()
+	}
+
+	state, err := b.StateMgr(workspaceName)
+	if err != nil {
+		diags = diags.Append(tfdiags.AttributeValue(
+			tfdiags.Error,
+			"Error loading state error",
+			fmt.Sprintf("error loading the remote state: %s", err),
+			cty.Path(nil).GetAttr("backend"),
+		))
+		return cty.NilVal, diags
+	}
+
+	if err := state.RefreshState(); err != nil {
+		diags = diags.Append(err)
+		return cty.NilVal, diags
+	}
+
+	outputs := make(map[string]cty.Value)
+
+	if defaultsVal := d.GetAttr("defaults"); !defaultsVal.IsNull() {
+		newState["defaults"] = defaultsVal
+		it := defaultsVal.ElementIterator()
+		for it.Next() {
+			k, v := it.Element()
+			outputs[k.AsString()] = v
+		}
+	} else {
+		newState["defaults"] = cty.NullVal(cty.DynamicPseudoType)
+	}
+
+	remoteState := state.State()
+	if remoteState == nil {
+		diags = diags.Append(tfdiags.AttributeValue(
+			tfdiags.Error,
+			"Unable to find remote state",
+			"No stored state was found for the given workspace in the given backend.",
+			cty.Path(nil).GetAttr("workspace"),
+		))
+		newState["outputs"] = cty.EmptyObjectVal
+		return cty.ObjectVal(newState), diags
+	}
+	mod := remoteState.RootModule()
+	if mod != nil { // should always have a root module in any valid state
+		for k, os := range mod.OutputValues {
+			outputs[k] = os.Value
+		}
+	}
+
+	newState["outputs"] = cty.ObjectVal(outputs)
+
+	return cty.ObjectVal(newState), diags
+}
+
+func getBackend(cfg cty.Value) (backend.Backend, cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	backendType := cfg.GetAttr("backend").AsString()
+
+	// Don't break people using the old _local syntax - but note warning above
+	if backendType == "_local" {
+		log.Println(`[INFO] Switching old (unsupported) backend "_local" to "local"`)
+		backendType = "local"
+	}
+
+	// Create the client to access our remote state
+	log.Printf("[DEBUG] Initializing remote state backend: %s", backendType)
+	f := getBackendFactory(backendType)
+	if f == nil {
+		detail := fmt.Sprintf("There is no backend type named %q.", backendType)
+		if msg, removed := backendInit.RemovedBackends[backendType]; removed {
+			detail = msg
+		}
+
+		diags = diags.Append(tfdiags.AttributeValue(
+			tfdiags.Error,
+			"Invalid backend configuration",
+			detail,
+			cty.Path(nil).GetAttr("backend"),
+		))
+		return nil, cty.NilVal, diags
+	}
+	b := f()
+
+	config := cfg.GetAttr("config")
+	if config.IsNull() {
+		// We'll treat this as an empty configuration and see if the backend's
+		// schema and validation code will accept it.
+		config = cty.EmptyObjectVal
+	}
+
+	if config.Type().IsMapType() { // The code below expects an object type, so we'll convert
+		config = cty.ObjectVal(config.AsValueMap())
+	}
+
+	schema := b.ConfigSchema()
+	// Try to coerce the provided value into the desired configuration type.
+	configVal, err := schema.CoerceValue(config)
+	if err != nil {
+		diags = diags.Append(tfdiags.AttributeValue(
+			tfdiags.Error,
+			"Invalid backend configuration",
+			fmt.Sprintf("The given configuration is not valid for backend %q: %s.", backendType,
+				tfdiags.FormatError(err)),
+			cty.Path(nil).GetAttr("config"),
+		))
+		return nil, cty.NilVal, diags
+	}
+
+	newVal, validateDiags := b.PrepareConfig(configVal)
+	diags = diags.Append(validateDiags)
+	if validateDiags.HasErrors() {
+		return nil, cty.NilVal, diags
+	}
+
+	// If this is the enhanced remote backend, we want to disable the version
+	// check, because this is a read-only operation
+	if rb, ok := b.(*remote.Remote); ok {
+		rb.IgnoreVersionConflict()
+	}
+
+	return b, newVal, diags
+}
+
+// overrideBackendFactories allows test cases to control the set of available
+// backends to allow for more self-contained tests. This should never be set
+// in non-test code.
+var overrideBackendFactories map[string]backend.InitFn
+
+func getBackendFactory(backendType string) backend.InitFn {
+	if len(overrideBackendFactories) > 0 {
+		// Tests may override the set of backend factories.
+		return overrideBackendFactories[backendType]
+	}
+
+	return backendInit.Backend(backendType)
+}
diff --git a/v1.5.7/internal/builtin/providers/terraform/data_source_state_test.go b/v1.5.7/internal/builtin/providers/terraform/data_source_state_test.go
new file mode 100644
index 0000000..9812400
--- /dev/null
+++ b/v1.5.7/internal/builtin/providers/terraform/data_source_state_test.go
@@ -0,0 +1,374 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+	"testing"
+
+	"github.com/apparentlymart/go-dump/dump"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestResource(t *testing.T) {
+	if err := dataSourceRemoteStateGetSchema().Block.InternalValidate(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+}
+
+func TestState_basic(t *testing.T) {
+	var tests = map[string]struct {
+		Config cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		"basic": {
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/basic.tfstate"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/basic.tfstate"),
+				}),
+				"outputs": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("bar"),
+				}),
+				"defaults":  cty.NullVal(cty.DynamicPseudoType),
+				"workspace": cty.NullVal(cty.String),
+			}),
+			false,
+		},
+		"workspace": {
+			cty.ObjectVal(map[string]cty.Value{
+				"backend":   cty.StringVal("local"),
+				"workspace": cty.StringVal(backend.DefaultStateName),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/basic.tfstate"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"backend":   cty.StringVal("local"),
+				"workspace": cty.StringVal(backend.DefaultStateName),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/basic.tfstate"),
+				}),
+				"outputs": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("bar"),
+				}),
+				"defaults": cty.NullVal(cty.DynamicPseudoType),
+			}),
+			false,
+		},
+		"_local": {
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("_local"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/basic.tfstate"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("_local"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/basic.tfstate"),
+				}),
+				"outputs": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("bar"),
+				}),
+				"defaults":  cty.NullVal(cty.DynamicPseudoType),
+				"workspace": cty.NullVal(cty.String),
+			}),
+			false,
+		},
+		"complex outputs": {
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/complex_outputs.tfstate"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/complex_outputs.tfstate"),
+				}),
+				"outputs": cty.ObjectVal(map[string]cty.Value{
+					"computed_map": cty.MapVal(map[string]cty.Value{
+						"key1": cty.StringVal("value1"),
+					}),
+					"computed_set": cty.ListVal([]cty.Value{
+						cty.StringVal("setval1"),
+						cty.StringVal("setval2"),
+					}),
+					"map": cty.MapVal(map[string]cty.Value{
+						"key":  cty.StringVal("test"),
+						"test": cty.StringVal("test"),
+					}),
+					"set": cty.ListVal([]cty.Value{
+						cty.StringVal("test1"),
+						cty.StringVal("test2"),
+					}),
+				}),
+				"defaults":  cty.NullVal(cty.DynamicPseudoType),
+				"workspace": cty.NullVal(cty.String),
+			}),
+			false,
+		},
+		"null outputs": {
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/null_outputs.tfstate"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/null_outputs.tfstate"),
+				}),
+				"outputs": cty.ObjectVal(map[string]cty.Value{
+					"map":  cty.NullVal(cty.Map(cty.String)),
+					"list": cty.NullVal(cty.List(cty.String)),
+				}),
+				"defaults":  cty.NullVal(cty.DynamicPseudoType),
+				"workspace": cty.NullVal(cty.String),
+			}),
+			false,
+		},
+		"defaults": {
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/empty.tfstate"),
+				}),
+				"defaults": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("bar"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/empty.tfstate"),
+				}),
+				"defaults": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("bar"),
+				}),
+				"outputs": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("bar"),
+				}),
+				"workspace": cty.NullVal(cty.String),
+			}),
+			false,
+		},
+		"missing": {
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/missing.tfstate"), // intentionally not present on disk
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/missing.tfstate"),
+				}),
+				"defaults":  cty.NullVal(cty.DynamicPseudoType),
+				"outputs":   cty.EmptyObjectVal,
+				"workspace": cty.NullVal(cty.String),
+			}),
+			true,
+		},
+		"wrong type for config": {
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config":  cty.StringVal("nope"),
+			}),
+			cty.NilVal,
+			true,
+		},
+		"wrong type for config with unknown backend": {
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.UnknownVal(cty.String),
+				"config":  cty.StringVal("nope"),
+			}),
+			cty.NilVal,
+			true,
+		},
+		"wrong type for config with unknown config": {
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config":  cty.UnknownVal(cty.String),
+			}),
+			cty.NilVal,
+			true,
+		},
+		"wrong type for defaults": {
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/basic.tfstate"),
+				}),
+				"defaults": cty.StringVal("nope"),
+			}),
+			cty.NilVal,
+			true,
+		},
+		"config as map": {
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config": cty.MapVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/empty.tfstate"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config": cty.MapVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/empty.tfstate"),
+				}),
+				"defaults":  cty.NullVal(cty.DynamicPseudoType),
+				"outputs":   cty.EmptyObjectVal,
+				"workspace": cty.NullVal(cty.String),
+			}),
+			false,
+		},
+		"defaults as map": {
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/basic.tfstate"),
+				}),
+				"defaults": cty.MapValEmpty(cty.String),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/basic.tfstate"),
+				}),
+				"defaults": cty.MapValEmpty(cty.String),
+				"outputs": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("bar"),
+				}),
+				"workspace": cty.NullVal(cty.String),
+			}),
+			false,
+		},
+		"nonexistent backend": {
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("nonexistent"),
+				"config": cty.ObjectVal(map[string]cty.Value{
+					"path": cty.StringVal("./testdata/basic.tfstate"),
+				}),
+			}),
+			cty.NilVal,
+			true,
+		},
+		"null config": {
+			cty.ObjectVal(map[string]cty.Value{
+				"backend": cty.StringVal("local"),
+				"config":  cty.NullVal(cty.DynamicPseudoType),
+			}),
+			cty.NilVal,
+			true,
+		},
+	}
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			schema := dataSourceRemoteStateGetSchema().Block
+			config, err := schema.CoerceValue(test.Config)
+			if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			diags := dataSourceRemoteStateValidate(config)
+
+			var got cty.Value
+			if !diags.HasErrors() && config.IsWhollyKnown() {
+				var moreDiags tfdiags.Diagnostics
+				got, moreDiags = dataSourceRemoteStateRead(config)
+				diags = diags.Append(moreDiags)
+			}
+
+			if test.Err {
+				if !diags.HasErrors() {
+					t.Fatal("succeeded; want error")
+				}
+			} else if diags.HasErrors() {
+				t.Fatalf("unexpected errors: %s", diags.Err())
+			}
+
+			if test.Want != cty.NilVal && !test.Want.RawEquals(got) {
+				t.Errorf("wrong result\nconfig: %sgot:    %swant:   %s", dump.Value(config), dump.Value(got), dump.Value(test.Want))
+			}
+		})
+	}
+}
+
+func TestState_validation(t *testing.T) {
+	// The main test TestState_basic covers both validation and reading of
+	// state snapshots, so this additional test is here only to verify that
+	// the validation step in isolation does not attempt to configure
+	// the backend.
+	overrideBackendFactories = map[string]backend.InitFn{
+		"failsconfigure": func() backend.Backend {
+			return backendFailsConfigure{}
+		},
+	}
+	defer func() {
+		// undo our overrides so we won't affect other tests
+		overrideBackendFactories = nil
+	}()
+
+	schema := dataSourceRemoteStateGetSchema().Block
+	config, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
+		"backend": cty.StringVal("failsconfigure"),
+		"config":  cty.EmptyObjectVal,
+	}))
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	diags := dataSourceRemoteStateValidate(config)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+}
+
+type backendFailsConfigure struct{}
+
+func (b backendFailsConfigure) ConfigSchema() *configschema.Block {
+	log.Printf("[TRACE] backendFailsConfigure.ConfigSchema")
+	return &configschema.Block{} // intentionally empty configuration schema
+}
+
+func (b backendFailsConfigure) PrepareConfig(given cty.Value) (cty.Value, tfdiags.Diagnostics) {
+	// No special actions to take here
+	return given, nil
+}
+
+func (b backendFailsConfigure) Configure(config cty.Value) tfdiags.Diagnostics {
+	log.Printf("[TRACE] backendFailsConfigure.Configure(%#v)", config)
+	var diags tfdiags.Diagnostics
+	diags = diags.Append(fmt.Errorf("Configure should never be called"))
+	return diags
+}
+
+func (b backendFailsConfigure) StateMgr(workspace string) (statemgr.Full, error) {
+	return nil, fmt.Errorf("StateMgr not implemented")
+}
+
+func (b backendFailsConfigure) DeleteWorkspace(name string, _ bool) error {
+	return fmt.Errorf("DeleteWorkspace not implemented")
+}
+
+func (b backendFailsConfigure) Workspaces() ([]string, error) {
+	return nil, fmt.Errorf("Workspaces not implemented")
+}
diff --git a/v1.5.7/internal/builtin/providers/terraform/provider.go b/v1.5.7/internal/builtin/providers/terraform/provider.go
new file mode 100644
index 0000000..2c91210
--- /dev/null
+++ b/v1.5.7/internal/builtin/providers/terraform/provider.go
@@ -0,0 +1,141 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/providers"
+)
+
+// Provider is an implementation of providers.Interface
+type Provider struct{}
+
+// NewProvider returns a new terraform provider
+func NewProvider() providers.Interface {
+	return &Provider{}
+}
+
+// GetSchema returns the complete schema for the provider.
+func (p *Provider) GetProviderSchema() providers.GetProviderSchemaResponse {
+	return providers.GetProviderSchemaResponse{
+		DataSources: map[string]providers.Schema{
+			"terraform_remote_state": dataSourceRemoteStateGetSchema(),
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"terraform_data": dataStoreResourceSchema(),
+		},
+	}
+}
+
+// ValidateProviderConfig is used to validate the configuration values.
+func (p *Provider) ValidateProviderConfig(req providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse {
+	// At this moment there is nothing to configure for the terraform provider,
+	// so we will happily return without taking any action
+	var res providers.ValidateProviderConfigResponse
+	res.PreparedConfig = req.Config
+	return res
+}
+
+// ValidateDataResourceConfig is used to validate the data source configuration values.
+func (p *Provider) ValidateDataResourceConfig(req providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse {
+	// FIXME: move the backend configuration validate call that's currently
+	// inside the read method  into here so that we can catch provider configuration
+	// errors in terraform validate as well as during terraform plan.
+	var res providers.ValidateDataResourceConfigResponse
+
+	// This should not happen
+	if req.TypeName != "terraform_remote_state" {
+		res.Diagnostics.Append(fmt.Errorf("Error: unsupported data source %s", req.TypeName))
+		return res
+	}
+
+	diags := dataSourceRemoteStateValidate(req.Config)
+	res.Diagnostics = diags
+
+	return res
+}
+
+// Configure configures and initializes the provider.
+func (p *Provider) ConfigureProvider(providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
+	// At this moment there is nothing to configure for the terraform provider,
+	// so we will happily return without taking any action
+	var res providers.ConfigureProviderResponse
+	return res
+}
+
+// ReadDataSource returns the data source's current state.
+func (p *Provider) ReadDataSource(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+	// call function
+	var res providers.ReadDataSourceResponse
+
+	// This should not happen
+	if req.TypeName != "terraform_remote_state" {
+		res.Diagnostics.Append(fmt.Errorf("Error: unsupported data source %s", req.TypeName))
+		return res
+	}
+
+	newState, diags := dataSourceRemoteStateRead(req.Config)
+
+	res.State = newState
+	res.Diagnostics = diags
+
+	return res
+}
+
+// Stop is called when the provider should halt any in-flight actions.
+func (p *Provider) Stop() error {
+	log.Println("[DEBUG] terraform provider cannot Stop")
+	return nil
+}
+
+// All the Resource-specific functions are below.
+// The terraform provider supplies a single data source, `terraform_remote_state`
+// and no resources.
+
+// UpgradeResourceState is called when the state loader encounters an
+// instance state whose schema version is less than the one reported by the
+// currently-used version of the corresponding provider, and the upgraded
+// result is used for any further processing.
+func (p *Provider) UpgradeResourceState(req providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse {
+	return upgradeDataStoreResourceState(req)
+}
+
+// ReadResource refreshes a resource and returns its current state.
+func (p *Provider) ReadResource(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+	return readDataStoreResourceState(req)
+}
+
+// PlanResourceChange takes the current state and proposed state of a
+// resource, and returns the planned final state.
+func (p *Provider) PlanResourceChange(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+	return planDataStoreResourceChange(req)
+}
+
+// ApplyResourceChange takes the planned state for a resource, which may
+// yet contain unknown computed values, and applies the changes returning
+// the final state.
+func (p *Provider) ApplyResourceChange(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+	return applyDataStoreResourceChange(req)
+}
+
+// ImportResourceState requests that the given resource be imported.
+func (p *Provider) ImportResourceState(req providers.ImportResourceStateRequest) providers.ImportResourceStateResponse {
+	if req.TypeName == "terraform_data" {
+		return importDataStore(req)
+	}
+
+	panic("unimplemented - terraform_remote_state has no resources")
+}
+
+// ValidateResourceConfig is used to to validate the resource configuration values.
+func (p *Provider) ValidateResourceConfig(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+	return validateDataStoreResourceConfig(req)
+}
+
+// Close is a noop for this provider, since it's run in-process.
+func (p *Provider) Close() error {
+	return nil
+}
diff --git a/v1.5.7/internal/builtin/providers/terraform/provider_test.go b/v1.5.7/internal/builtin/providers/terraform/provider_test.go
new file mode 100644
index 0000000..49efb09
--- /dev/null
+++ b/v1.5.7/internal/builtin/providers/terraform/provider_test.go
@@ -0,0 +1,13 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	backendInit "github.com/hashicorp/terraform/internal/backend/init"
+)
+
+func init() {
+	// Initialize the backends
+	backendInit.Init(nil)
+}
diff --git a/v1.5.7/internal/builtin/providers/terraform/resource_data.go b/v1.5.7/internal/builtin/providers/terraform/resource_data.go
new file mode 100644
index 0000000..6fdba7e
--- /dev/null
+++ b/v1.5.7/internal/builtin/providers/terraform/resource_data.go
@@ -0,0 +1,172 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/go-uuid"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+)
+
+func dataStoreResourceSchema() providers.Schema {
+	return providers.Schema{
+		Block: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"input":            {Type: cty.DynamicPseudoType, Optional: true},
+				"output":           {Type: cty.DynamicPseudoType, Computed: true},
+				"triggers_replace": {Type: cty.DynamicPseudoType, Optional: true},
+				"id":               {Type: cty.String, Computed: true},
+			},
+		},
+	}
+}
+
+func validateDataStoreResourceConfig(req providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
+	if req.Config.IsNull() {
+		return resp
+	}
+
+	// Core does not currently validate computed values are not set in the
+	// configuration.
+	for _, attr := range []string{"id", "output"} {
+		if !req.Config.GetAttr(attr).IsNull() {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf(`%q attribute is read-only`, attr))
+		}
+	}
+	return resp
+}
+
+func upgradeDataStoreResourceState(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
+	ty := dataStoreResourceSchema().Block.ImpliedType()
+	val, err := ctyjson.Unmarshal(req.RawStateJSON, ty)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	resp.UpgradedState = val
+	return resp
+}
+
+func readDataStoreResourceState(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+	resp.NewState = req.PriorState
+	return resp
+}
+
+func planDataStoreResourceChange(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+	if req.ProposedNewState.IsNull() {
+		// destroy op
+		resp.PlannedState = req.ProposedNewState
+		return resp
+	}
+
+	planned := req.ProposedNewState.AsValueMap()
+
+	input := req.ProposedNewState.GetAttr("input")
+	trigger := req.ProposedNewState.GetAttr("triggers_replace")
+
+	switch {
+	case req.PriorState.IsNull():
+		// Create
+		// Set the id value to unknown.
+		planned["id"] = cty.UnknownVal(cty.String)
+
+		// Output type must always match the input, even when it's null.
+		if input.IsNull() {
+			planned["output"] = input
+		} else {
+			planned["output"] = cty.UnknownVal(input.Type())
+		}
+
+		resp.PlannedState = cty.ObjectVal(planned)
+		return resp
+
+	case !req.PriorState.GetAttr("triggers_replace").RawEquals(trigger):
+		// trigger changed, so we need to replace the entire instance
+		resp.RequiresReplace = append(resp.RequiresReplace, cty.GetAttrPath("triggers_replace"))
+		planned["id"] = cty.UnknownVal(cty.String)
+
+		// We need to check the input for the replacement instance to compute a
+		// new output.
+		if input.IsNull() {
+			planned["output"] = input
+		} else {
+			planned["output"] = cty.UnknownVal(input.Type())
+		}
+
+	case !req.PriorState.GetAttr("input").RawEquals(input):
+		// only input changed, so we only need to re-compute output
+		planned["output"] = cty.UnknownVal(input.Type())
+	}
+
+	resp.PlannedState = cty.ObjectVal(planned)
+	return resp
+}
+
+var testUUIDHook func() string
+
+func applyDataStoreResourceChange(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+	if req.PlannedState.IsNull() {
+		resp.NewState = req.PlannedState
+		return resp
+	}
+
+	newState := req.PlannedState.AsValueMap()
+
+	if !req.PlannedState.GetAttr("output").IsKnown() {
+		newState["output"] = req.PlannedState.GetAttr("input")
+	}
+
+	if !req.PlannedState.GetAttr("id").IsKnown() {
+		idString, err := uuid.GenerateUUID()
+		// Terraform would probably never get this far without a good random
+		// source, but catch the error anyway.
+		if err != nil {
+			diag := tfdiags.AttributeValue(
+				tfdiags.Error,
+				"Error generating id",
+				err.Error(),
+				cty.GetAttrPath("id"),
+			)
+
+			resp.Diagnostics = resp.Diagnostics.Append(diag)
+		}
+
+		if testUUIDHook != nil {
+			idString = testUUIDHook()
+		}
+
+		newState["id"] = cty.StringVal(idString)
+	}
+
+	resp.NewState = cty.ObjectVal(newState)
+
+	return resp
+}
+
+// TODO: This isn't very useful even for examples, because terraform_data has
+// no way to refresh the full resource value from only the import ID. This
+// minimal implementation allows the import to succeed, and can be extended
+// once the configuration is available during import.
+func importDataStore(req providers.ImportResourceStateRequest) (resp providers.ImportResourceStateResponse) {
+	schema := dataStoreResourceSchema()
+	v := cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal(req.ID),
+	})
+	state, err := schema.Block.CoerceValue(v)
+	resp.Diagnostics = resp.Diagnostics.Append(err)
+
+	resp.ImportedResources = []providers.ImportedResource{
+		{
+			TypeName: req.TypeName,
+			State:    state,
+		},
+	}
+	return resp
+}
diff --git a/v1.5.7/internal/builtin/providers/terraform/resource_data_test.go b/v1.5.7/internal/builtin/providers/terraform/resource_data_test.go
new file mode 100644
index 0000000..28a0383
--- /dev/null
+++ b/v1.5.7/internal/builtin/providers/terraform/resource_data_test.go
@@ -0,0 +1,385 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+)
+
+func TestManagedDataValidate(t *testing.T) {
+	cfg := map[string]cty.Value{
+		"input":            cty.NullVal(cty.DynamicPseudoType),
+		"output":           cty.NullVal(cty.DynamicPseudoType),
+		"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+		"id":               cty.NullVal(cty.String),
+	}
+
+	// empty
+	req := providers.ValidateResourceConfigRequest{
+		TypeName: "terraform_data",
+		Config:   cty.ObjectVal(cfg),
+	}
+
+	resp := validateDataStoreResourceConfig(req)
+	if resp.Diagnostics.HasErrors() {
+		t.Error("empty config error:", resp.Diagnostics.ErrWithWarnings())
+	}
+
+	// invalid computed values
+	cfg["output"] = cty.StringVal("oops")
+	req.Config = cty.ObjectVal(cfg)
+
+	resp = validateDataStoreResourceConfig(req)
+	if !resp.Diagnostics.HasErrors() {
+		t.Error("expected error")
+	}
+
+	msg := resp.Diagnostics.Err().Error()
+	if !strings.Contains(msg, "attribute is read-only") {
+		t.Error("unexpected error", msg)
+	}
+}
+
+func TestManagedDataUpgradeState(t *testing.T) {
+	schema := dataStoreResourceSchema()
+	ty := schema.Block.ImpliedType()
+
+	state := cty.ObjectVal(map[string]cty.Value{
+		"input":  cty.StringVal("input"),
+		"output": cty.StringVal("input"),
+		"triggers_replace": cty.ListVal([]cty.Value{
+			cty.StringVal("a"), cty.StringVal("b"),
+		}),
+		"id": cty.StringVal("not-quite-unique"),
+	})
+
+	jsState, err := ctyjson.Marshal(state, ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// empty
+	req := providers.UpgradeResourceStateRequest{
+		TypeName:     "terraform_data",
+		RawStateJSON: jsState,
+	}
+
+	resp := upgradeDataStoreResourceState(req)
+	if resp.Diagnostics.HasErrors() {
+		t.Error("upgrade state error:", resp.Diagnostics.ErrWithWarnings())
+	}
+
+	if !resp.UpgradedState.RawEquals(state) {
+		t.Errorf("prior state was:\n%#v\nupgraded state is:\n%#v\n", state, resp.UpgradedState)
+	}
+}
+
+func TestManagedDataRead(t *testing.T) {
+	req := providers.ReadResourceRequest{
+		TypeName: "terraform_data",
+		PriorState: cty.ObjectVal(map[string]cty.Value{
+			"input":  cty.StringVal("input"),
+			"output": cty.StringVal("input"),
+			"triggers_replace": cty.ListVal([]cty.Value{
+				cty.StringVal("a"), cty.StringVal("b"),
+			}),
+			"id": cty.StringVal("not-quite-unique"),
+		}),
+	}
+
+	resp := readDataStoreResourceState(req)
+	if resp.Diagnostics.HasErrors() {
+		t.Fatal("unexpected error", resp.Diagnostics.ErrWithWarnings())
+	}
+
+	if !resp.NewState.RawEquals(req.PriorState) {
+		t.Errorf("prior state was:\n%#v\nnew state is:\n%#v\n", req.PriorState, resp.NewState)
+	}
+}
+
+func TestManagedDataPlan(t *testing.T) {
+	schema := dataStoreResourceSchema().Block
+	ty := schema.ImpliedType()
+
+	for name, tc := range map[string]struct {
+		prior    cty.Value
+		proposed cty.Value
+		planned  cty.Value
+	}{
+		"create": {
+			prior: cty.NullVal(ty),
+			proposed: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.NullVal(cty.DynamicPseudoType),
+				"output":           cty.NullVal(cty.DynamicPseudoType),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.NullVal(cty.String),
+			}),
+			planned: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.NullVal(cty.DynamicPseudoType),
+				"output":           cty.NullVal(cty.DynamicPseudoType),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.UnknownVal(cty.String),
+			}),
+		},
+
+		"create-typed-null-input": {
+			prior: cty.NullVal(ty),
+			proposed: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.NullVal(cty.String),
+				"output":           cty.NullVal(cty.DynamicPseudoType),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.NullVal(cty.String),
+			}),
+			planned: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.NullVal(cty.String),
+				"output":           cty.NullVal(cty.String),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.UnknownVal(cty.String),
+			}),
+		},
+
+		"create-output": {
+			prior: cty.NullVal(ty),
+			proposed: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.StringVal("input"),
+				"output":           cty.NullVal(cty.DynamicPseudoType),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.NullVal(cty.String),
+			}),
+			planned: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.StringVal("input"),
+				"output":           cty.UnknownVal(cty.String),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.UnknownVal(cty.String),
+			}),
+		},
+
+		"update-input": {
+			prior: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.StringVal("input"),
+				"output":           cty.StringVal("input"),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.StringVal("not-quite-unique"),
+			}),
+			proposed: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.UnknownVal(cty.List(cty.String)),
+				"output":           cty.StringVal("input"),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.StringVal("not-quite-unique"),
+			}),
+			planned: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.UnknownVal(cty.List(cty.String)),
+				"output":           cty.UnknownVal(cty.List(cty.String)),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.StringVal("not-quite-unique"),
+			}),
+		},
+
+		"update-trigger": {
+			prior: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.StringVal("input"),
+				"output":           cty.StringVal("input"),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.StringVal("not-quite-unique"),
+			}),
+			proposed: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.StringVal("input"),
+				"output":           cty.StringVal("input"),
+				"triggers_replace": cty.StringVal("new-value"),
+				"id":               cty.StringVal("not-quite-unique"),
+			}),
+			planned: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.StringVal("input"),
+				"output":           cty.UnknownVal(cty.String),
+				"triggers_replace": cty.StringVal("new-value"),
+				"id":               cty.UnknownVal(cty.String),
+			}),
+		},
+
+		"update-input-trigger": {
+			prior: cty.ObjectVal(map[string]cty.Value{
+				"input":  cty.StringVal("input"),
+				"output": cty.StringVal("input"),
+				"triggers_replace": cty.MapVal(map[string]cty.Value{
+					"key": cty.StringVal("value"),
+				}),
+				"id": cty.StringVal("not-quite-unique"),
+			}),
+			proposed: cty.ObjectVal(map[string]cty.Value{
+				"input":  cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
+				"output": cty.StringVal("input"),
+				"triggers_replace": cty.MapVal(map[string]cty.Value{
+					"key": cty.StringVal("new value"),
+				}),
+				"id": cty.StringVal("not-quite-unique"),
+			}),
+			planned: cty.ObjectVal(map[string]cty.Value{
+				"input":  cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
+				"output": cty.UnknownVal(cty.List(cty.String)),
+				"triggers_replace": cty.MapVal(map[string]cty.Value{
+					"key": cty.StringVal("new value"),
+				}),
+				"id": cty.UnknownVal(cty.String),
+			}),
+		},
+	} {
+		t.Run("plan-"+name, func(t *testing.T) {
+			req := providers.PlanResourceChangeRequest{
+				TypeName:         "terraform_data",
+				PriorState:       tc.prior,
+				ProposedNewState: tc.proposed,
+			}
+
+			resp := planDataStoreResourceChange(req)
+			if resp.Diagnostics.HasErrors() {
+				t.Fatal(resp.Diagnostics.ErrWithWarnings())
+			}
+
+			if !resp.PlannedState.RawEquals(tc.planned) {
+				t.Errorf("expected:\n%#v\ngot:\n%#v\n", tc.planned, resp.PlannedState)
+			}
+		})
+	}
+}
+
+func TestManagedDataApply(t *testing.T) {
+	testUUIDHook = func() string {
+		return "not-quite-unique"
+	}
+	defer func() {
+		testUUIDHook = nil
+	}()
+
+	schema := dataStoreResourceSchema().Block
+	ty := schema.ImpliedType()
+
+	for name, tc := range map[string]struct {
+		prior   cty.Value
+		planned cty.Value
+		state   cty.Value
+	}{
+		"create": {
+			prior: cty.NullVal(ty),
+			planned: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.NullVal(cty.DynamicPseudoType),
+				"output":           cty.NullVal(cty.DynamicPseudoType),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.UnknownVal(cty.String),
+			}),
+			state: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.NullVal(cty.DynamicPseudoType),
+				"output":           cty.NullVal(cty.DynamicPseudoType),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.StringVal("not-quite-unique"),
+			}),
+		},
+
+		"create-output": {
+			prior: cty.NullVal(ty),
+			planned: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.StringVal("input"),
+				"output":           cty.UnknownVal(cty.String),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.UnknownVal(cty.String),
+			}),
+			state: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.StringVal("input"),
+				"output":           cty.StringVal("input"),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.StringVal("not-quite-unique"),
+			}),
+		},
+
+		"update-input": {
+			prior: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.StringVal("input"),
+				"output":           cty.StringVal("input"),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.StringVal("not-quite-unique"),
+			}),
+			planned: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
+				"output":           cty.UnknownVal(cty.List(cty.String)),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.StringVal("not-quite-unique"),
+			}),
+			state: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
+				"output":           cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.StringVal("not-quite-unique"),
+			}),
+		},
+
+		"update-trigger": {
+			prior: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.StringVal("input"),
+				"output":           cty.StringVal("input"),
+				"triggers_replace": cty.NullVal(cty.DynamicPseudoType),
+				"id":               cty.StringVal("not-quite-unique"),
+			}),
+			planned: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.StringVal("input"),
+				"output":           cty.UnknownVal(cty.String),
+				"triggers_replace": cty.StringVal("new-value"),
+				"id":               cty.UnknownVal(cty.String),
+			}),
+			state: cty.ObjectVal(map[string]cty.Value{
+				"input":            cty.StringVal("input"),
+				"output":           cty.StringVal("input"),
+				"triggers_replace": cty.StringVal("new-value"),
+				"id":               cty.StringVal("not-quite-unique"),
+			}),
+		},
+
+		"update-input-trigger": {
+			prior: cty.ObjectVal(map[string]cty.Value{
+				"input":  cty.StringVal("input"),
+				"output": cty.StringVal("input"),
+				"triggers_replace": cty.MapVal(map[string]cty.Value{
+					"key": cty.StringVal("value"),
+				}),
+				"id": cty.StringVal("not-quite-unique"),
+			}),
+			planned: cty.ObjectVal(map[string]cty.Value{
+				"input":  cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
+				"output": cty.UnknownVal(cty.List(cty.String)),
+				"triggers_replace": cty.MapVal(map[string]cty.Value{
+					"key": cty.StringVal("new value"),
+				}),
+				"id": cty.UnknownVal(cty.String),
+			}),
+			state: cty.ObjectVal(map[string]cty.Value{
+				"input":  cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
+				"output": cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
+				"triggers_replace": cty.MapVal(map[string]cty.Value{
+					"key": cty.StringVal("new value"),
+				}),
+				"id": cty.StringVal("not-quite-unique"),
+			}),
+		},
+	} {
+		t.Run("apply-"+name, func(t *testing.T) {
+			req := providers.ApplyResourceChangeRequest{
+				TypeName:     "terraform_data",
+				PriorState:   tc.prior,
+				PlannedState: tc.planned,
+			}
+
+			resp := applyDataStoreResourceChange(req)
+			if resp.Diagnostics.HasErrors() {
+				t.Fatal(resp.Diagnostics.ErrWithWarnings())
+			}
+
+			if !resp.NewState.RawEquals(tc.state) {
+				t.Errorf("expected:\n%#v\ngot:\n%#v\n", tc.state, resp.NewState)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/builtin/providers/terraform/testdata/basic.tfstate b/v1.5.7/internal/builtin/providers/terraform/testdata/basic.tfstate
new file mode 100644
index 0000000..d41a2d1
--- /dev/null
+++ b/v1.5.7/internal/builtin/providers/terraform/testdata/basic.tfstate
@@ -0,0 +1,12 @@
+{
+    "version": 4,
+    "terraform_version": "0.13.0",
+    "serial": 0,
+    "lineage": "",
+    "outputs": {
+        "foo": {
+            "value": "bar",
+            "type": "string"
+        }
+    }
+}
diff --git a/v1.5.7/internal/builtin/providers/terraform/testdata/complex_outputs.tfstate b/v1.5.7/internal/builtin/providers/terraform/testdata/complex_outputs.tfstate
new file mode 100644
index 0000000..4f57253
--- /dev/null
+++ b/v1.5.7/internal/builtin/providers/terraform/testdata/complex_outputs.tfstate
@@ -0,0 +1,70 @@
+{
+    "version": 4,
+    "terraform_version": "0.13.0",
+    "serial": 0,
+    "lineage": "",
+    "outputs": {
+        "computed_map": {
+            "sensitive": false,
+            "type": [
+                "map",
+                "string"
+            ],
+            "value": {
+                "key1": "value1"
+            }
+        },
+        "computed_set": {
+            "sensitive": false,
+            "type": [
+                "list",
+                "string"
+            ],
+            "value": [
+                "setval1",
+                "setval2"
+            ]
+        },
+        "map": {
+            "sensitive": false,
+            "type": [
+                "map",
+                "string"
+            ],
+            "value": {
+                "key": "test",
+                "test": "test"
+            }
+        },
+        "set": {
+            "sensitive": false,
+            "type": [
+                "list",
+                "string"
+            ],
+            "value": [
+                "test1",
+                "test2"
+            ]
+        }
+    },
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "test_resource",
+            "name": "main",
+            "each": "list",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "index_key": 0,
+                    "schema_version": 0,
+                    "attributes": {
+                        "id": "testId"
+                    },
+                    "private": "bnVsbA=="
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/builtin/providers/terraform/testdata/empty.tfstate b/v1.5.7/internal/builtin/providers/terraform/testdata/empty.tfstate
new file mode 100644
index 0000000..14610e8
--- /dev/null
+++ b/v1.5.7/internal/builtin/providers/terraform/testdata/empty.tfstate
@@ -0,0 +1,6 @@
+{
+    "version": 4,
+    "terraform_version": "0.13.0",
+    "serial": 0,
+    "lineage": ""
+}
diff --git a/v1.5.7/internal/builtin/providers/terraform/testdata/null_outputs.tfstate b/v1.5.7/internal/builtin/providers/terraform/testdata/null_outputs.tfstate
new file mode 100644
index 0000000..8b0cfdf
--- /dev/null
+++ b/v1.5.7/internal/builtin/providers/terraform/testdata/null_outputs.tfstate
@@ -0,0 +1,22 @@
+{
+    "version": 4,
+    "terraform_version": "0.13.0",
+    "serial": 0,
+    "lineage": "",
+    "outputs": {
+        "map": {
+            "value": null,
+            "type": [
+                "map",
+                "string"
+            ]
+        },
+        "list": {
+            "value": null,
+            "type": [
+                "list",
+                "string"
+            ]
+        }
+    }
+}
diff --git a/v1.5.7/internal/builtin/provisioners/file/resource_provisioner.go b/v1.5.7/internal/builtin/provisioners/file/resource_provisioner.go
new file mode 100644
index 0000000..8216e81
--- /dev/null
+++ b/v1.5.7/internal/builtin/provisioners/file/resource_provisioner.go
@@ -0,0 +1,210 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package file
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"os"
+
+	"github.com/hashicorp/terraform/internal/communicator"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/mitchellh/go-homedir"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func New() provisioners.Interface {
+	ctx, cancel := context.WithCancel(context.Background())
+	return &provisioner{
+		ctx:    ctx,
+		cancel: cancel,
+	}
+}
+
+type provisioner struct {
+	// We store a context here tied to the lifetime of the provisioner.
+	// This allows the Stop method to cancel any in-flight requests.
+	ctx    context.Context
+	cancel context.CancelFunc
+}
+
+func (p *provisioner) GetSchema() (resp provisioners.GetSchemaResponse) {
+	schema := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"source": {
+				Type:     cty.String,
+				Optional: true,
+			},
+
+			"content": {
+				Type:     cty.String,
+				Optional: true,
+			},
+
+			"destination": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	}
+	resp.Provisioner = schema
+	return resp
+}
+
+func (p *provisioner) ValidateProvisionerConfig(req provisioners.ValidateProvisionerConfigRequest) (resp provisioners.ValidateProvisionerConfigResponse) {
+	cfg, err := p.GetSchema().Provisioner.CoerceValue(req.Config)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+	}
+
+	source := cfg.GetAttr("source")
+	content := cfg.GetAttr("content")
+
+	switch {
+	case !source.IsNull() && !content.IsNull():
+		resp.Diagnostics = resp.Diagnostics.Append(errors.New("Cannot set both 'source' and 'content'"))
+		return resp
+	case source.IsNull() && content.IsNull():
+		resp.Diagnostics = resp.Diagnostics.Append(errors.New("Must provide one of 'source' or 'content'"))
+		return resp
+	}
+
+	return resp
+}
+
+func (p *provisioner) ProvisionResource(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+	if req.Connection.IsNull() {
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"file provisioner error",
+			"Missing connection configuration for provisioner.",
+		))
+		return resp
+	}
+
+	comm, err := communicator.New(req.Connection)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"file provisioner error",
+			err.Error(),
+		))
+		return resp
+	}
+
+	// Get the source
+	src, deleteSource, err := getSrc(req.Config)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"file provisioner error",
+			err.Error(),
+		))
+		return resp
+	}
+	if deleteSource {
+		defer os.Remove(src)
+	}
+
+	// Begin the file copy
+	dst := req.Config.GetAttr("destination").AsString()
+	if err := copyFiles(p.ctx, comm, src, dst); err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"file provisioner error",
+			err.Error(),
+		))
+		return resp
+	}
+
+	return resp
+}
+
+// getSrc returns the file to use as source
+func getSrc(v cty.Value) (string, bool, error) {
+	content := v.GetAttr("content")
+	src := v.GetAttr("source")
+
+	switch {
+	case !content.IsNull():
+		file, err := ioutil.TempFile("", "tf-file-content")
+		if err != nil {
+			return "", true, err
+		}
+
+		if _, err = file.WriteString(content.AsString()); err != nil {
+			return "", true, err
+		}
+
+		return file.Name(), true, nil
+
+	case !src.IsNull():
+		expansion, err := homedir.Expand(src.AsString())
+		return expansion, false, err
+
+	default:
+		panic("source and content cannot both be null")
+	}
+}
+
+// copyFiles is used to copy the files from a source to a destination
+func copyFiles(ctx context.Context, comm communicator.Communicator, src, dst string) error {
+	retryCtx, cancel := context.WithTimeout(ctx, comm.Timeout())
+	defer cancel()
+
+	// Wait and retry until we establish the connection
+	err := communicator.Retry(retryCtx, func() error {
+		return comm.Connect(nil)
+	})
+	if err != nil {
+		return err
+	}
+
+	// disconnect when the context is canceled, which will close this after
+	// Apply as well.
+	go func() {
+		<-ctx.Done()
+		comm.Disconnect()
+	}()
+
+	info, err := os.Stat(src)
+	if err != nil {
+		return err
+	}
+
+	// If we're uploading a directory, short circuit and do that
+	if info.IsDir() {
+		if err := comm.UploadDir(dst, src); err != nil {
+			return fmt.Errorf("Upload failed: %v", err)
+		}
+		return nil
+	}
+
+	// We're uploading a file...
+	f, err := os.Open(src)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	err = comm.Upload(dst, f)
+	if err != nil {
+		return fmt.Errorf("Upload failed: %v", err)
+	}
+
+	return err
+}
+
+func (p *provisioner) Stop() error {
+	p.cancel()
+	return nil
+}
+
+func (p *provisioner) Close() error {
+	return nil
+}
diff --git a/v1.5.7/internal/builtin/provisioners/file/resource_provisioner_test.go b/v1.5.7/internal/builtin/provisioners/file/resource_provisioner_test.go
new file mode 100644
index 0000000..9ef88f5
--- /dev/null
+++ b/v1.5.7/internal/builtin/provisioners/file/resource_provisioner_test.go
@@ -0,0 +1,121 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package file
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestResourceProvider_Validate_good_source(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"source":      cty.StringVal("/tmp/foo"),
+		"destination": cty.StringVal("/tmp/bar"),
+	})
+
+	resp := New().ValidateProvisionerConfig(provisioners.ValidateProvisionerConfigRequest{
+		Config: v,
+	})
+
+	if len(resp.Diagnostics) > 0 {
+		t.Fatal(resp.Diagnostics.ErrWithWarnings())
+	}
+}
+
+func TestResourceProvider_Validate_good_content(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"content":     cty.StringVal("value to copy"),
+		"destination": cty.StringVal("/tmp/bar"),
+	})
+
+	resp := New().ValidateProvisionerConfig(provisioners.ValidateProvisionerConfigRequest{
+		Config: v,
+	})
+
+	if len(resp.Diagnostics) > 0 {
+		t.Fatal(resp.Diagnostics.ErrWithWarnings())
+	}
+}
+
+func TestResourceProvider_Validate_good_unknown_variable_value(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"content":     cty.UnknownVal(cty.String),
+		"destination": cty.StringVal("/tmp/bar"),
+	})
+
+	resp := New().ValidateProvisionerConfig(provisioners.ValidateProvisionerConfigRequest{
+		Config: v,
+	})
+
+	if len(resp.Diagnostics) > 0 {
+		t.Fatal(resp.Diagnostics.ErrWithWarnings())
+	}
+}
+
+func TestResourceProvider_Validate_bad_not_destination(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"source": cty.StringVal("nope"),
+	})
+
+	resp := New().ValidateProvisionerConfig(provisioners.ValidateProvisionerConfigRequest{
+		Config: v,
+	})
+
+	if !resp.Diagnostics.HasErrors() {
+		t.Fatal("Should have errors")
+	}
+}
+
+func TestResourceProvider_Validate_bad_no_source(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"destination": cty.StringVal("/tmp/bar"),
+	})
+
+	resp := New().ValidateProvisionerConfig(provisioners.ValidateProvisionerConfigRequest{
+		Config: v,
+	})
+
+	if !resp.Diagnostics.HasErrors() {
+		t.Fatal("Should have errors")
+	}
+}
+
+func TestResourceProvider_Validate_bad_to_many_src(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"source":      cty.StringVal("nope"),
+		"content":     cty.StringVal("vlue to copy"),
+		"destination": cty.StringVal("/tmp/bar"),
+	})
+
+	resp := New().ValidateProvisionerConfig(provisioners.ValidateProvisionerConfigRequest{
+		Config: v,
+	})
+
+	if !resp.Diagnostics.HasErrors() {
+		t.Fatal("Should have errors")
+	}
+}
+
+// Validate that Stop can Close can be called even when not provisioning.
+func TestResourceProvisioner_StopClose(t *testing.T) {
+	p := New()
+	p.Stop()
+	p.Close()
+}
+
+func TestResourceProvisioner_connectionRequired(t *testing.T) {
+	p := New()
+	resp := p.ProvisionResource(provisioners.ProvisionResourceRequest{})
+	if !resp.Diagnostics.HasErrors() {
+		t.Fatal("expected error")
+	}
+
+	got := resp.Diagnostics.Err().Error()
+	if !strings.Contains(got, "Missing connection") {
+		t.Fatalf("expected 'Missing connection' error: got %q", got)
+	}
+}
diff --git a/v1.5.7/internal/builtin/provisioners/local-exec/resource_provisioner.go b/v1.5.7/internal/builtin/provisioners/local-exec/resource_provisioner.go
new file mode 100644
index 0000000..edac8cc
--- /dev/null
+++ b/v1.5.7/internal/builtin/provisioners/local-exec/resource_provisioner.go
@@ -0,0 +1,224 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package localexec
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"os"
+	"os/exec"
+	"runtime"
+
+	"github.com/armon/circbuf"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/mitchellh/go-linereader"
+	"github.com/zclconf/go-cty/cty"
+)
+
+const (
+	// maxBufSize limits how much output we collect from a local
+	// invocation. This is to prevent TF memory usage from growing
+	// to an enormous amount due to a faulty process.
+	maxBufSize = 8 * 1024
+)
+
+func New() provisioners.Interface {
+	ctx, cancel := context.WithCancel(context.Background())
+	return &provisioner{
+		ctx:    ctx,
+		cancel: cancel,
+	}
+}
+
+type provisioner struct {
+	// We store a context here tied to the lifetime of the provisioner.
+	// This allows the Stop method to cancel any in-flight requests.
+	ctx    context.Context
+	cancel context.CancelFunc
+}
+
+func (p *provisioner) GetSchema() (resp provisioners.GetSchemaResponse) {
+	schema := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"command": {
+				Type:     cty.String,
+				Required: true,
+			},
+			"interpreter": {
+				Type:     cty.List(cty.String),
+				Optional: true,
+			},
+			"working_dir": {
+				Type:     cty.String,
+				Optional: true,
+			},
+			"environment": {
+				Type:     cty.Map(cty.String),
+				Optional: true,
+			},
+			"quiet": {
+				Type:     cty.Bool,
+				Optional: true,
+			},
+		},
+	}
+
+	resp.Provisioner = schema
+	return resp
+}
+
+func (p *provisioner) ValidateProvisionerConfig(req provisioners.ValidateProvisionerConfigRequest) (resp provisioners.ValidateProvisionerConfigResponse) {
+	if _, err := p.GetSchema().Provisioner.CoerceValue(req.Config); err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"Invalid local-exec provisioner configuration",
+			err.Error(),
+		))
+	}
+	return resp
+}
+
+func (p *provisioner) ProvisionResource(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+	command := req.Config.GetAttr("command").AsString()
+	if command == "" {
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"Invalid local-exec provisioner command",
+			"The command must be a non-empty string.",
+		))
+		return resp
+	}
+
+	envVal := req.Config.GetAttr("environment")
+	var env []string
+
+	if !envVal.IsNull() {
+		for k, v := range envVal.AsValueMap() {
+			if !v.IsNull() {
+				entry := fmt.Sprintf("%s=%s", k, v.AsString())
+				env = append(env, entry)
+			}
+		}
+	}
+
+	// Execute the command using a shell
+	intrVal := req.Config.GetAttr("interpreter")
+
+	var cmdargs []string
+	if !intrVal.IsNull() && intrVal.LengthInt() > 0 {
+		for _, v := range intrVal.AsValueSlice() {
+			if !v.IsNull() {
+				cmdargs = append(cmdargs, v.AsString())
+			}
+		}
+	} else {
+		if runtime.GOOS == "windows" {
+			cmdargs = []string{"cmd", "/C"}
+		} else {
+			cmdargs = []string{"/bin/sh", "-c"}
+		}
+	}
+
+	cmdargs = append(cmdargs, command)
+
+	workingdir := ""
+	if wdVal := req.Config.GetAttr("working_dir"); !wdVal.IsNull() {
+		workingdir = wdVal.AsString()
+	}
+
+	// Set up the reader that will read the output from the command.
+	// We use an os.Pipe so that the *os.File can be passed directly to the
+	// process, and not rely on goroutines copying the data which may block.
+	// See golang.org/issue/18874
+	pr, pw, err := os.Pipe()
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"local-exec provisioner error",
+			fmt.Sprintf("Failed to initialize pipe for output: %s", err),
+		))
+		return resp
+	}
+
+	var cmdEnv []string
+	cmdEnv = os.Environ()
+	cmdEnv = append(cmdEnv, env...)
+
+	// Set up the command
+	cmd := exec.CommandContext(p.ctx, cmdargs[0], cmdargs[1:]...)
+	cmd.Stderr = pw
+	cmd.Stdout = pw
+	// Dir specifies the working directory of the command.
+	// If Dir is the empty string (this is default), runs the command
+	// in the calling process's current directory.
+	cmd.Dir = workingdir
+	// Env specifies the environment of the command.
+	// By default will use the calling process's environment
+	cmd.Env = cmdEnv
+
+	output, _ := circbuf.NewBuffer(maxBufSize)
+
+	// Write everything we read from the pipe to the output buffer too
+	tee := io.TeeReader(pr, output)
+
+	// copy the teed output to the UI output
+	copyDoneCh := make(chan struct{})
+	go copyUIOutput(req.UIOutput, tee, copyDoneCh)
+
+	// Output what we're about to run
+	if quietVal := req.Config.GetAttr("quiet"); !quietVal.IsNull() && quietVal.True() {
+		req.UIOutput.Output("local-exec: Executing: Suppressed by quiet=true")
+	} else {
+		req.UIOutput.Output(fmt.Sprintf("Executing: %q", cmdargs))
+	}
+
+	// Start the command
+	err = cmd.Start()
+	if err == nil {
+		err = cmd.Wait()
+	}
+
+	// Close the write-end of the pipe so that the goroutine mirroring output
+	// ends properly.
+	pw.Close()
+
+	// Cancelling the command may block the pipe reader if the file descriptor
+	// was passed to a child process which hasn't closed it. In this case the
+	// copyOutput goroutine will just hang out until exit.
+	select {
+	case <-copyDoneCh:
+	case <-p.ctx.Done():
+	}
+
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"local-exec provisioner error",
+			fmt.Sprintf("Error running command '%s': %v. Output: %s", command, err, output.Bytes()),
+		))
+		return resp
+	}
+
+	return resp
+}
+
+func (p *provisioner) Stop() error {
+	p.cancel()
+	return nil
+}
+
+func (p *provisioner) Close() error {
+	return nil
+}
+
+func copyUIOutput(o provisioners.UIOutput, r io.Reader, doneCh chan<- struct{}) {
+	defer close(doneCh)
+	lr := linereader.New(r)
+	for line := range lr.Ch {
+		o.Output(line)
+	}
+}
diff --git a/v1.5.7/internal/builtin/provisioners/local-exec/resource_provisioner_test.go b/v1.5.7/internal/builtin/provisioners/local-exec/resource_provisioner_test.go
new file mode 100644
index 0000000..2afb9e5
--- /dev/null
+++ b/v1.5.7/internal/builtin/provisioners/local-exec/resource_provisioner_test.go
@@ -0,0 +1,255 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package localexec
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/mitchellh/cli"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestResourceProvider_Apply(t *testing.T) {
+	defer os.Remove("test_out")
+	output := cli.NewMockUi()
+	p := New()
+	schema := p.GetSchema().Provisioner
+	c, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
+		"command": cty.StringVal("echo foo > test_out"),
+	}))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	resp := p.ProvisionResource(provisioners.ProvisionResourceRequest{
+		Config:   c,
+		UIOutput: output,
+	})
+
+	if resp.Diagnostics.HasErrors() {
+		t.Fatalf("err: %v", resp.Diagnostics.Err())
+	}
+
+	// Check the file
+	raw, err := ioutil.ReadFile("test_out")
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	actual := strings.TrimSpace(string(raw))
+	expected := "foo"
+	if actual != expected {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceProvider_stop(t *testing.T) {
+	output := cli.NewMockUi()
+	p := New()
+	schema := p.GetSchema().Provisioner
+
+	c, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
+		// bash/zsh/ksh will exec a single command in the same process. This
+		// makes certain there's a subprocess in the shell.
+		"command": cty.StringVal("sleep 30; sleep 30"),
+	}))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	doneCh := make(chan struct{})
+	startTime := time.Now()
+	go func() {
+		defer close(doneCh)
+		// The functionality of p.Apply is tested in TestResourceProvider_Apply.
+		// Because p.Apply is called in a goroutine, trying to t.Fatal() on its
+		// result would be ignored or would cause a panic if the parent goroutine
+		// has already completed.
+		_ = p.ProvisionResource(provisioners.ProvisionResourceRequest{
+			Config:   c,
+			UIOutput: output,
+		})
+	}()
+
+	mustExceed := (50 * time.Millisecond)
+	select {
+	case <-doneCh:
+		t.Fatalf("expected to finish sometime after %s finished in %s", mustExceed, time.Since(startTime))
+	case <-time.After(mustExceed):
+		t.Logf("correctly took longer than %s", mustExceed)
+	}
+
+	// Stop it
+	stopTime := time.Now()
+	p.Stop()
+
+	maxTempl := "expected to finish under %s, finished in %s"
+	finishWithin := (2 * time.Second)
+	select {
+	case <-doneCh:
+		t.Logf(maxTempl, finishWithin, time.Since(stopTime))
+	case <-time.After(finishWithin):
+		t.Fatalf(maxTempl, finishWithin, time.Since(stopTime))
+	}
+}
+
+func TestResourceProvider_ApplyCustomInterpreter(t *testing.T) {
+	output := cli.NewMockUi()
+	p := New()
+
+	schema := p.GetSchema().Provisioner
+
+	c, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
+		"interpreter": cty.ListVal([]cty.Value{cty.StringVal("echo"), cty.StringVal("is")}),
+		"command":     cty.StringVal("not really an interpreter"),
+	}))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	resp := p.ProvisionResource(provisioners.ProvisionResourceRequest{
+		Config:   c,
+		UIOutput: output,
+	})
+
+	if resp.Diagnostics.HasErrors() {
+		t.Fatal(resp.Diagnostics.Err())
+	}
+
+	got := strings.TrimSpace(output.OutputWriter.String())
+	want := `Executing: ["echo" "is" "not really an interpreter"]
+is not really an interpreter`
+	if got != want {
+		t.Errorf("wrong output\ngot:  %s\nwant: %s", got, want)
+	}
+}
+
+func TestResourceProvider_ApplyCustomWorkingDirectory(t *testing.T) {
+	testdir := "working_dir_test"
+	os.Mkdir(testdir, 0755)
+	defer os.Remove(testdir)
+
+	output := cli.NewMockUi()
+	p := New()
+	schema := p.GetSchema().Provisioner
+
+	c, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
+		"working_dir": cty.StringVal(testdir),
+		"command":     cty.StringVal("echo `pwd`"),
+	}))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	resp := p.ProvisionResource(provisioners.ProvisionResourceRequest{
+		Config:   c,
+		UIOutput: output,
+	})
+
+	if resp.Diagnostics.HasErrors() {
+		t.Fatal(resp.Diagnostics.Err())
+	}
+
+	dir, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	got := strings.TrimSpace(output.OutputWriter.String())
+	want := "Executing: [\"/bin/sh\" \"-c\" \"echo `pwd`\"]\n" + dir + "/" + testdir
+	if got != want {
+		t.Errorf("wrong output\ngot:  %s\nwant: %s", got, want)
+	}
+}
+
+func TestResourceProvider_ApplyCustomEnv(t *testing.T) {
+	output := cli.NewMockUi()
+	p := New()
+	schema := p.GetSchema().Provisioner
+
+	c, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
+		"command": cty.StringVal("echo $FOO $BAR $BAZ"),
+		"environment": cty.MapVal(map[string]cty.Value{
+			"FOO": cty.StringVal("BAR"),
+			"BAR": cty.StringVal("1"),
+			"BAZ": cty.StringVal("true"),
+		}),
+	}))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	resp := p.ProvisionResource(provisioners.ProvisionResourceRequest{
+		Config:   c,
+		UIOutput: output,
+	})
+	if resp.Diagnostics.HasErrors() {
+		t.Fatal(resp.Diagnostics.Err())
+	}
+
+	got := strings.TrimSpace(output.OutputWriter.String())
+	want := `Executing: ["/bin/sh" "-c" "echo $FOO $BAR $BAZ"]
+BAR 1 true`
+	if got != want {
+		t.Errorf("wrong output\ngot:  %s\nwant: %s", got, want)
+	}
+}
+
+// Validate that Stop can Close can be called even when not provisioning.
+func TestResourceProvisioner_StopClose(t *testing.T) {
+	p := New()
+	p.Stop()
+	p.Close()
+}
+
+func TestResourceProvisioner_nullsInOptionals(t *testing.T) {
+	output := cli.NewMockUi()
+	p := New()
+	schema := p.GetSchema().Provisioner
+
+	for i, cfg := range []cty.Value{
+		cty.ObjectVal(map[string]cty.Value{
+			"command": cty.StringVal("echo OK"),
+			"environment": cty.MapVal(map[string]cty.Value{
+				"FOO": cty.NullVal(cty.String),
+			}),
+		}),
+		cty.ObjectVal(map[string]cty.Value{
+			"command":     cty.StringVal("echo OK"),
+			"environment": cty.NullVal(cty.Map(cty.String)),
+		}),
+		cty.ObjectVal(map[string]cty.Value{
+			"command":     cty.StringVal("echo OK"),
+			"interpreter": cty.ListVal([]cty.Value{cty.NullVal(cty.String)}),
+		}),
+		cty.ObjectVal(map[string]cty.Value{
+			"command":     cty.StringVal("echo OK"),
+			"interpreter": cty.NullVal(cty.List(cty.String)),
+		}),
+		cty.ObjectVal(map[string]cty.Value{
+			"command":     cty.StringVal("echo OK"),
+			"working_dir": cty.NullVal(cty.String),
+		}),
+	} {
+		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+
+			cfg, err := schema.CoerceValue(cfg)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			// verifying there are no panics
+			p.ProvisionResource(provisioners.ProvisionResourceRequest{
+				Config:   cfg,
+				UIOutput: output,
+			})
+		})
+	}
+}
diff --git a/v1.5.7/internal/builtin/provisioners/remote-exec/resource_provisioner.go b/v1.5.7/internal/builtin/provisioners/remote-exec/resource_provisioner.go
new file mode 100644
index 0000000..b292288
--- /dev/null
+++ b/v1.5.7/internal/builtin/provisioners/remote-exec/resource_provisioner.go
@@ -0,0 +1,297 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remoteexec
+
+import (
+	"bytes"
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/communicator"
+	"github.com/hashicorp/terraform/internal/communicator/remote"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/mitchellh/go-linereader"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func New() provisioners.Interface {
+	ctx, cancel := context.WithCancel(context.Background())
+	return &provisioner{
+		ctx:    ctx,
+		cancel: cancel,
+	}
+}
+
+type provisioner struct {
+	// We store a context here tied to the lifetime of the provisioner.
+	// This allows the Stop method to cancel any in-flight requests.
+	ctx    context.Context
+	cancel context.CancelFunc
+}
+
+func (p *provisioner) GetSchema() (resp provisioners.GetSchemaResponse) {
+	schema := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"inline": {
+				Type:     cty.List(cty.String),
+				Optional: true,
+			},
+			"script": {
+				Type:     cty.String,
+				Optional: true,
+			},
+			"scripts": {
+				Type:     cty.List(cty.String),
+				Optional: true,
+			},
+		},
+	}
+
+	resp.Provisioner = schema
+	return resp
+}
+
+func (p *provisioner) ValidateProvisionerConfig(req provisioners.ValidateProvisionerConfigRequest) (resp provisioners.ValidateProvisionerConfigResponse) {
+	cfg, err := p.GetSchema().Provisioner.CoerceValue(req.Config)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"Invalid remote-exec provisioner configuration",
+			err.Error(),
+		))
+		return resp
+	}
+
+	inline := cfg.GetAttr("inline")
+	script := cfg.GetAttr("script")
+	scripts := cfg.GetAttr("scripts")
+
+	set := 0
+	if !inline.IsNull() {
+		set++
+	}
+	if !script.IsNull() {
+		set++
+	}
+	if !scripts.IsNull() {
+		set++
+	}
+	if set != 1 {
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"Invalid remote-exec provisioner configuration",
+			`Only one of "inline", "script", or "scripts" must be set`,
+		))
+	}
+	return resp
+}
+
+func (p *provisioner) ProvisionResource(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+	if req.Connection.IsNull() {
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"remote-exec provisioner error",
+			"Missing connection configuration for provisioner.",
+		))
+		return resp
+	}
+
+	comm, err := communicator.New(req.Connection)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"remote-exec provisioner error",
+			err.Error(),
+		))
+		return resp
+	}
+
+	// Collect the scripts
+	scripts, err := collectScripts(req.Config)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"remote-exec provisioner error",
+			err.Error(),
+		))
+		return resp
+	}
+	for _, s := range scripts {
+		defer s.Close()
+	}
+
+	// Copy and execute each script
+	if err := runScripts(p.ctx, req.UIOutput, comm, scripts); err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"remote-exec provisioner error",
+			err.Error(),
+		))
+		return resp
+	}
+
+	return resp
+}
+
+func (p *provisioner) Stop() error {
+	p.cancel()
+	return nil
+}
+
+func (p *provisioner) Close() error {
+	return nil
+}
+
+// generateScripts takes the configuration and creates a script from each inline config
+func generateScripts(inline cty.Value) ([]string, error) {
+	var lines []string
+	for _, l := range inline.AsValueSlice() {
+		if l.IsNull() {
+			return nil, errors.New("invalid null string in 'scripts'")
+		}
+
+		s := l.AsString()
+		if s == "" {
+			return nil, errors.New("invalid empty string in 'scripts'")
+		}
+		lines = append(lines, s)
+	}
+	lines = append(lines, "")
+
+	return []string{strings.Join(lines, "\n")}, nil
+}
+
+// collectScripts is used to collect all the scripts we need
+// to execute in preparation for copying them.
+func collectScripts(v cty.Value) ([]io.ReadCloser, error) {
+	// Check if inline
+	if inline := v.GetAttr("inline"); !inline.IsNull() {
+		scripts, err := generateScripts(inline)
+		if err != nil {
+			return nil, err
+		}
+
+		var r []io.ReadCloser
+		for _, script := range scripts {
+			r = append(r, ioutil.NopCloser(bytes.NewReader([]byte(script))))
+		}
+
+		return r, nil
+	}
+
+	// Collect scripts
+	var scripts []string
+	if script := v.GetAttr("script"); !script.IsNull() {
+		s := script.AsString()
+		if s == "" {
+			return nil, errors.New("invalid empty string in 'script'")
+		}
+		scripts = append(scripts, s)
+	}
+
+	if scriptList := v.GetAttr("scripts"); !scriptList.IsNull() {
+		for _, script := range scriptList.AsValueSlice() {
+			if script.IsNull() {
+				return nil, errors.New("invalid null string in 'script'")
+			}
+			s := script.AsString()
+			if s == "" {
+				return nil, errors.New("invalid empty string in 'script'")
+			}
+			scripts = append(scripts, s)
+		}
+	}
+
+	// Open all the scripts
+	var fhs []io.ReadCloser
+	for _, s := range scripts {
+		fh, err := os.Open(s)
+		if err != nil {
+			for _, fh := range fhs {
+				fh.Close()
+			}
+			return nil, fmt.Errorf("Failed to open script '%s': %v", s, err)
+		}
+		fhs = append(fhs, fh)
+	}
+
+	// Done, return the file handles
+	return fhs, nil
+}
+
+// runScripts is used to copy and execute a set of scripts
+func runScripts(ctx context.Context, o provisioners.UIOutput, comm communicator.Communicator, scripts []io.ReadCloser) error {
+	retryCtx, cancel := context.WithTimeout(ctx, comm.Timeout())
+	defer cancel()
+
+	// Wait and retry until we establish the connection
+	err := communicator.Retry(retryCtx, func() error {
+		return comm.Connect(o)
+	})
+	if err != nil {
+		return err
+	}
+
+	// Wait for the context to end and then disconnect
+	go func() {
+		<-ctx.Done()
+		comm.Disconnect()
+	}()
+
+	for _, script := range scripts {
+		var cmd *remote.Cmd
+
+		outR, outW := io.Pipe()
+		errR, errW := io.Pipe()
+		defer outW.Close()
+		defer errW.Close()
+
+		go copyUIOutput(o, outR)
+		go copyUIOutput(o, errR)
+
+		remotePath := comm.ScriptPath()
+
+		if err := comm.UploadScript(remotePath, script); err != nil {
+			return fmt.Errorf("Failed to upload script: %v", err)
+		}
+
+		cmd = &remote.Cmd{
+			Command: remotePath,
+			Stdout:  outW,
+			Stderr:  errW,
+		}
+		if err := comm.Start(cmd); err != nil {
+			return fmt.Errorf("Error starting script: %v", err)
+		}
+
+		if err := cmd.Wait(); err != nil {
+			return err
+		}
+
+		// Upload a blank follow up file in the same path to prevent residual
+		// script contents from remaining on remote machine
+		empty := bytes.NewReader([]byte(""))
+		if err := comm.Upload(remotePath, empty); err != nil {
+			// This feature is best-effort.
+			log.Printf("[WARN] Failed to upload empty follow up script: %v", err)
+		}
+	}
+
+	return nil
+}
+
+func copyUIOutput(o provisioners.UIOutput, r io.Reader) {
+	lr := linereader.New(r)
+	for line := range lr.Ch {
+		o.Output(line)
+	}
+}
diff --git a/v1.5.7/internal/builtin/provisioners/remote-exec/resource_provisioner_test.go b/v1.5.7/internal/builtin/provisioners/remote-exec/resource_provisioner_test.go
new file mode 100644
index 0000000..13e53e4
--- /dev/null
+++ b/v1.5.7/internal/builtin/provisioners/remote-exec/resource_provisioner_test.go
@@ -0,0 +1,323 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remoteexec
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"io"
+	"log"
+	"testing"
+	"time"
+
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/communicator"
+	"github.com/hashicorp/terraform/internal/communicator/remote"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/mitchellh/cli"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestResourceProvider_Validate_good(t *testing.T) {
+	c := cty.ObjectVal(map[string]cty.Value{
+		"inline": cty.ListVal([]cty.Value{cty.StringVal("echo foo")}),
+	})
+
+	resp := New().ValidateProvisionerConfig(provisioners.ValidateProvisionerConfigRequest{
+		Config: c,
+	})
+	if len(resp.Diagnostics) > 0 {
+		t.Fatal(resp.Diagnostics.ErrWithWarnings())
+	}
+}
+
+func TestResourceProvider_Validate_bad(t *testing.T) {
+	c := cty.ObjectVal(map[string]cty.Value{
+		"invalid": cty.StringVal("nope"),
+	})
+
+	resp := New().ValidateProvisionerConfig(provisioners.ValidateProvisionerConfigRequest{
+		Config: c,
+	})
+	if !resp.Diagnostics.HasErrors() {
+		t.Fatalf("Should have errors")
+	}
+}
+
+var expectedScriptOut = `cd /tmp
+wget http://foobar
+exit 0
+`
+
+func TestResourceProvider_generateScript(t *testing.T) {
+	inline := cty.ListVal([]cty.Value{
+		cty.StringVal("cd /tmp"),
+		cty.StringVal("wget http://foobar"),
+		cty.StringVal("exit 0"),
+	})
+
+	out, err := generateScripts(inline)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if len(out) != 1 {
+		t.Fatal("expected 1 out")
+	}
+
+	if out[0] != expectedScriptOut {
+		t.Fatalf("bad: %v", out)
+	}
+}
+
+func TestResourceProvider_generateScriptEmptyInline(t *testing.T) {
+	inline := cty.ListVal([]cty.Value{cty.StringVal("")})
+
+	_, err := generateScripts(inline)
+	if err == nil {
+		t.Fatal("expected error, got none")
+	}
+
+	if !strings.Contains(err.Error(), "empty string") {
+		t.Fatalf("expected empty string error, got: %s", err)
+	}
+}
+
+func TestResourceProvider_CollectScripts_inline(t *testing.T) {
+	conf := map[string]cty.Value{
+		"inline": cty.ListVal([]cty.Value{
+			cty.StringVal("cd /tmp"),
+			cty.StringVal("wget http://foobar"),
+			cty.StringVal("exit 0"),
+		}),
+	}
+
+	scripts, err := collectScripts(cty.ObjectVal(conf))
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if len(scripts) != 1 {
+		t.Fatalf("bad: %v", scripts)
+	}
+
+	var out bytes.Buffer
+	_, err = io.Copy(&out, scripts[0])
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if out.String() != expectedScriptOut {
+		t.Fatalf("bad: %v", out.String())
+	}
+}
+
+func TestResourceProvider_CollectScripts_script(t *testing.T) {
+	p := New()
+	schema := p.GetSchema().Provisioner
+
+	conf, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
+		"scripts": cty.ListVal([]cty.Value{
+			cty.StringVal("testdata/script1.sh"),
+		}),
+	}))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	scripts, err := collectScripts(conf)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if len(scripts) != 1 {
+		t.Fatalf("bad: %v", scripts)
+	}
+
+	var out bytes.Buffer
+	_, err = io.Copy(&out, scripts[0])
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if out.String() != expectedScriptOut {
+		t.Fatalf("bad: %v", out.String())
+	}
+}
+
+func TestResourceProvider_CollectScripts_scripts(t *testing.T) {
+	p := New()
+	schema := p.GetSchema().Provisioner
+
+	conf, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
+		"scripts": cty.ListVal([]cty.Value{
+			cty.StringVal("testdata/script1.sh"),
+			cty.StringVal("testdata/script1.sh"),
+			cty.StringVal("testdata/script1.sh"),
+		}),
+	}))
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	scripts, err := collectScripts(conf)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if len(scripts) != 3 {
+		t.Fatalf("bad: %v", scripts)
+	}
+
+	for idx := range scripts {
+		var out bytes.Buffer
+		_, err = io.Copy(&out, scripts[idx])
+		if err != nil {
+			t.Fatalf("err: %v", err)
+		}
+
+		if out.String() != expectedScriptOut {
+			t.Fatalf("bad: %v", out.String())
+		}
+	}
+}
+
+func TestResourceProvider_CollectScripts_scriptsEmpty(t *testing.T) {
+	p := New()
+	schema := p.GetSchema().Provisioner
+
+	conf, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
+		"scripts": cty.ListVal([]cty.Value{cty.StringVal("")}),
+	}))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = collectScripts(conf)
+	if err == nil {
+		t.Fatal("expected error")
+	}
+
+	if !strings.Contains(err.Error(), "empty string") {
+		t.Fatalf("Expected empty string error, got: %s", err)
+	}
+}
+
+func TestProvisionerTimeout(t *testing.T) {
+	o := cli.NewMockUi()
+	c := new(communicator.MockCommunicator)
+
+	disconnected := make(chan struct{})
+	c.DisconnectFunc = func() error {
+		close(disconnected)
+		return nil
+	}
+
+	completed := make(chan struct{})
+	c.CommandFunc = func(cmd *remote.Cmd) error {
+		defer close(completed)
+		cmd.Init()
+		time.Sleep(2 * time.Second)
+		cmd.SetExitStatus(0, nil)
+		return nil
+	}
+	c.ConnTimeout = time.Second
+	c.UploadScripts = map[string]string{"hello": "echo hello"}
+	c.RemoteScriptPath = "hello"
+
+	conf := map[string]cty.Value{
+		"inline": cty.ListVal([]cty.Value{cty.StringVal("echo hello")}),
+	}
+
+	scripts, err := collectScripts(cty.ObjectVal(conf))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	ctx := context.Background()
+
+	done := make(chan struct{})
+
+	var runErr error
+	go func() {
+		defer close(done)
+		runErr = runScripts(ctx, o, c, scripts)
+	}()
+
+	select {
+	case <-disconnected:
+		t.Fatal("communicator disconnected before command completed")
+	case <-completed:
+	}
+
+	<-done
+	if runErr != nil {
+		t.Fatal(err)
+	}
+}
+
+// Validate that Stop can Close can be called even when not provisioning.
+func TestResourceProvisioner_StopClose(t *testing.T) {
+	p := New()
+	p.Stop()
+	p.Close()
+}
+
+func TestResourceProvisioner_connectionRequired(t *testing.T) {
+	p := New()
+	resp := p.ProvisionResource(provisioners.ProvisionResourceRequest{})
+	if !resp.Diagnostics.HasErrors() {
+		t.Fatal("expected error")
+	}
+
+	got := resp.Diagnostics.Err().Error()
+	if !strings.Contains(got, "Missing connection") {
+		t.Fatalf("expected 'Missing connection' error: got %q", got)
+	}
+}
+
+func TestResourceProvisioner_nullsInOptionals(t *testing.T) {
+	output := cli.NewMockUi()
+	p := New()
+	schema := p.GetSchema().Provisioner
+
+	for i, cfg := range []cty.Value{
+		cty.ObjectVal(map[string]cty.Value{
+			"script": cty.StringVal("echo"),
+			"inline": cty.NullVal(cty.List(cty.String)),
+		}),
+		cty.ObjectVal(map[string]cty.Value{
+			"inline": cty.ListVal([]cty.Value{
+				cty.NullVal(cty.String),
+			}),
+		}),
+		cty.ObjectVal(map[string]cty.Value{
+			"script": cty.NullVal(cty.String),
+		}),
+		cty.ObjectVal(map[string]cty.Value{
+			"scripts": cty.NullVal(cty.List(cty.String)),
+		}),
+		cty.ObjectVal(map[string]cty.Value{
+			"scripts": cty.ListVal([]cty.Value{
+				cty.NullVal(cty.String),
+			}),
+		}),
+	} {
+		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+
+			cfg, err := schema.CoerceValue(cfg)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			// verifying there are no panics
+			p.ProvisionResource(provisioners.ProvisionResourceRequest{
+				Config:   cfg,
+				UIOutput: output,
+			})
+		})
+	}
+}
diff --git a/v1.5.7/internal/builtin/provisioners/remote-exec/testdata/script1.sh b/v1.5.7/internal/builtin/provisioners/remote-exec/testdata/script1.sh
new file mode 100755
index 0000000..81b3d5a
--- /dev/null
+++ b/v1.5.7/internal/builtin/provisioners/remote-exec/testdata/script1.sh
@@ -0,0 +1,3 @@
+cd /tmp
+wget http://foobar
+exit 0
diff --git a/v1.5.7/internal/checks/doc.go b/v1.5.7/internal/checks/doc.go
new file mode 100644
index 0000000..c1f1378
--- /dev/null
+++ b/v1.5.7/internal/checks/doc.go
@@ -0,0 +1,8 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package checks contains the models for representing various kinds of
+// declarative condition checks that can be defined in a Terraform module
+// and then evaluated and reported by Terraform Core during plan and apply
+// operations.
+package checks
diff --git a/v1.5.7/internal/checks/state.go b/v1.5.7/internal/checks/state.go
new file mode 100644
index 0000000..bde8341
--- /dev/null
+++ b/v1.5.7/internal/checks/state.go
@@ -0,0 +1,293 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package checks
+
+import (
+	"fmt"
+	"sort"
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+)
+
+// State is a container for state tracking of all of the the checks declared in
+// a particular Terraform configuration and their current statuses.
+//
+// A State object is mutable during plan and apply operations but should
+// otherwise be treated as a read-only snapshot of the status of checks
+// at a particular moment.
+//
+// The checks State tracks a few different concepts:
+//   - configuration objects: items in the configuration which statically
+//     declare some checks associated with zero or more checkable objects.
+//   - checkable objects: dynamically-determined objects that are each
+//     associated with one configuration object.
+//   - checks: a single check that is declared as part of a configuration
+//     object and then resolved once for each of its associated checkable
+//     objects.
+//   - check statuses: the current state of a particular check associated
+//     with a particular checkable object.
+//
+// This container type is concurrency-safe for both reads and writes through
+// its various methods.
+type State struct {
+	mu sync.Mutex
+
+	statuses    addrs.Map[addrs.ConfigCheckable, *configCheckableState]
+	failureMsgs addrs.Map[addrs.CheckRule, string]
+}
+
+// configCheckableState is an internal part of type State that represents
+// the evaluation status for a particular addrs.ConfigCheckable address.
+//
+// Its initial state, at the beginning of a run, is that it doesn't even know
+// how many checkable objects will be dynamically-declared yet. Terraform Core
+// will notify the State object of the associated Checkables once
+// it has decided the appropriate expansion of that configuration object,
+// and then will gradually report the results of each check once the graph
+// walk reaches it.
+//
+// This must be accessed only while holding the mutex inside the associated
+// State object.
+type configCheckableState struct {
+	// checkTypes captures the expected number of checks of each type
+	// associated with object declared by this configuration construct. Since
+	// checks are statically declared (even though the checkable objects
+	// aren't) we can compute this only from the configuration.
+	checkTypes map[addrs.CheckRuleType]int
+
+	// objects represents the set of dynamic checkable objects associated
+	// with this configuration construct. This is initially nil to represent
+	// that we don't know the objects yet, and is replaced by a non-nil map
+	// once Terraform Core reports the expansion of this configuration
+	// construct.
+	//
+	// The leaf Status values will initially be StatusUnknown
+	// and then gradually updated by Terraform Core as it visits the
+	// individual checkable objects and reports their status.
+	objects addrs.Map[addrs.Checkable, map[addrs.CheckRuleType][]Status]
+}
+
+// NOTE: For the "Report"-prefixed methods that we use to gradually update
+// the structure with results during a plan or apply operation, see the
+// state_report.go file also in this package.
+
+// NewState returns a new State object representing the check statuses of
+// objects declared in the given configuration.
+//
+// The configuration determines which configuration objects and associated
+// checks we'll be expecting to see, so that we can seed their statuses as
+// all unknown until we see affirmative reports sent by the Report-prefixed
+// methods on Checks.
+func NewState(config *configs.Config) *State {
+	return &State{
+		statuses: initialStatuses(config),
+	}
+}
+
+// ConfigHasChecks returns true if and only if the given address refers to
+// a configuration object that this State object is expecting to recieve
+// statuses for.
+//
+// Other methods of Checks will typically panic if given a config address
+// that would not have returned true from ConfigHasChecked.
+func (c *State) ConfigHasChecks(addr addrs.ConfigCheckable) bool {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	return c.statuses.Has(addr)
+}
+
+// AllConfigAddrs returns all of the addresses of all configuration objects
+// that could potentially produce checkable objects at runtime.
+//
+// This is a good starting point for reporting on the outcome of all of the
+// configured checks at the configuration level of granularity, e.g. for
+// automated testing reports where we want to report the status of all
+// configured checks even if the graph walk aborted before we reached any
+// of their objects.
+func (c *State) AllConfigAddrs() addrs.Set[addrs.ConfigCheckable] {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	return c.statuses.Keys()
+}
+
+// ObjectAddrs returns the addresses of individual checkable objects belonging
+// to the configuration object with the given address.
+//
+// This will panic if the given address isn't a known configuration object
+// that has checks.
+func (c *State) ObjectAddrs(configAddr addrs.ConfigCheckable) addrs.Set[addrs.Checkable] {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	st, ok := c.statuses.GetOk(configAddr)
+	if !ok {
+		panic(fmt.Sprintf("unknown configuration object %s", configAddr))
+	}
+
+	ret := addrs.MakeSet[addrs.Checkable]()
+	for _, elem := range st.objects.Elems {
+		ret.Add(elem.Key)
+	}
+	return ret
+
+}
+
+// AggregateCheckStatus returns a summarization of all of the check results
+// for a particular configuration object into a single status.
+//
+// The given address must refer to an object within the configuration that
+// this Checks was instantiated from, or this method will panic.
+func (c *State) AggregateCheckStatus(addr addrs.ConfigCheckable) Status {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	st, ok := c.statuses.GetOk(addr)
+	if !ok {
+		panic(fmt.Sprintf("request for status of unknown configuration object %s", addr))
+	}
+
+	if st.objects.Elems == nil {
+		// If we don't even know how many objects we have for this
+		// configuration construct then that summarizes as unknown.
+		// (Note: this is different than Elems being a non-nil empty map,
+		// which means that we know there are zero objects and therefore
+		// the aggregate result will be pass to pass below.)
+		return StatusUnknown
+	}
+
+	// Otherwise, our result depends on how many of our known objects are
+	// in each status.
+	errorCount := 0
+	failCount := 0
+	unknownCount := 0
+
+	for _, objects := range st.objects.Elems {
+		for _, checks := range objects.Value {
+			for _, status := range checks {
+				switch status {
+				case StatusPass:
+					// ok
+				case StatusFail:
+					failCount++
+				case StatusError:
+					errorCount++
+				default:
+					unknownCount++
+				}
+			}
+		}
+	}
+
+	return summarizeCheckStatuses(errorCount, failCount, unknownCount)
+}
+
+// ObjectCheckStatus returns a summarization of all of the check results
+// for a particular checkable object into a single status.
+//
+// The given address must refer to a checkable object that Terraform Core
+// previously reported while doing a graph walk, or this method will panic.
+func (c *State) ObjectCheckStatus(addr addrs.Checkable) Status {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	configAddr := addr.ConfigCheckable()
+
+	st, ok := c.statuses.GetOk(configAddr)
+	if !ok {
+		panic(fmt.Sprintf("request for status of unknown object %s", addr))
+	}
+	if st.objects.Elems == nil {
+		panic(fmt.Sprintf("request for status of %s before establishing the checkable objects for %s", addr, configAddr))
+	}
+	checks, ok := st.objects.GetOk(addr)
+	if !ok {
+		panic(fmt.Sprintf("request for status of unknown object %s", addr))
+	}
+
+	errorCount := 0
+	failCount := 0
+	unknownCount := 0
+	for _, statuses := range checks {
+		for _, status := range statuses {
+			switch status {
+			case StatusPass:
+				// ok
+			case StatusFail:
+				failCount++
+			case StatusError:
+				errorCount++
+			default:
+				unknownCount++
+			}
+		}
+	}
+	return summarizeCheckStatuses(errorCount, failCount, unknownCount)
+}
+
+// ObjectFailureMessages returns the zero or more failure messages reported
+// for the object with the given address.
+//
+// Failure messages are recorded only for checks whose status is StatusFail,
+// but since this aggregates together the results of all of the checks
+// on the given object it's possible for there to be a mixture of failures
+// and errors at the same time, which would aggregate as StatusError in
+// ObjectCheckStatus's result because errors are defined as "stronger"
+// than failures.
+func (c *State) ObjectFailureMessages(addr addrs.Checkable) []string {
+	var ret []string
+
+	configAddr := addr.ConfigCheckable()
+
+	st, ok := c.statuses.GetOk(configAddr)
+	if !ok {
+		panic(fmt.Sprintf("request for status of unknown object %s", addr))
+	}
+	if st.objects.Elems == nil {
+		panic(fmt.Sprintf("request for status of %s before establishing the checkable objects for %s", addr, configAddr))
+	}
+	checksByType, ok := st.objects.GetOk(addr)
+	if !ok {
+		panic(fmt.Sprintf("request for status of unknown object %s", addr))
+	}
+
+	for checkType, checks := range checksByType {
+		for i, status := range checks {
+			if status == StatusFail {
+				checkAddr := addrs.NewCheckRule(addr, checkType, i)
+				msg := c.failureMsgs.Get(checkAddr)
+				if msg != "" {
+					ret = append(ret, msg)
+				}
+			}
+		}
+	}
+
+	// We always return the messages in a lexical sort order just so that
+	// it'll be consistent between runs if we still have the same problems.
+	sort.Strings(ret)
+
+	return ret
+}
+
+func summarizeCheckStatuses(errorCount, failCount, unknownCount int) Status {
+	switch {
+	case errorCount > 0:
+		// If we saw any errors then we'll treat the whole thing as errored.
+		return StatusError
+	case failCount > 0:
+		// If anything failed then this whole configuration construct failed.
+		return StatusFail
+	case unknownCount > 0:
+		// If nothing failed but we still have unknowns then our outcome isn't
+		// known yet.
+		return StatusUnknown
+	default:
+		// If we have no failures and no unknowns then either we have all
+		// passes or no checkable objects at all, both of which summarize as
+		// a pass.
+		return StatusPass
+	}
+}
diff --git a/v1.5.7/internal/checks/state_init.go b/v1.5.7/internal/checks/state_init.go
new file mode 100644
index 0000000..9acd40d
--- /dev/null
+++ b/v1.5.7/internal/checks/state_init.go
@@ -0,0 +1,96 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package checks
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+)
+
+func initialStatuses(cfg *configs.Config) addrs.Map[addrs.ConfigCheckable, *configCheckableState] {
+	ret := addrs.MakeMap[addrs.ConfigCheckable, *configCheckableState]()
+	if cfg == nil {
+		// This should not happen in normal use, but can arise in some
+		// unit tests that are not working with a full configuration and
+		// don't care about checks.
+		return ret
+	}
+
+	collectInitialStatuses(ret, cfg)
+
+	return ret
+}
+
+func collectInitialStatuses(into addrs.Map[addrs.ConfigCheckable, *configCheckableState], cfg *configs.Config) {
+	moduleAddr := cfg.Path
+
+	for _, rc := range cfg.Module.ManagedResources {
+		addr := rc.Addr().InModule(moduleAddr)
+		collectInitialStatusForResource(into, addr, rc)
+	}
+	for _, rc := range cfg.Module.DataResources {
+		addr := rc.Addr().InModule(moduleAddr)
+		collectInitialStatusForResource(into, addr, rc)
+	}
+
+	for _, oc := range cfg.Module.Outputs {
+		addr := oc.Addr().InModule(moduleAddr)
+
+		ct := len(oc.Preconditions)
+		if ct == 0 {
+			// We just ignore output values that don't declare any checks.
+			continue
+		}
+
+		st := &configCheckableState{}
+
+		st.checkTypes = map[addrs.CheckRuleType]int{
+			addrs.OutputPrecondition: ct,
+		}
+
+		into.Put(addr, st)
+	}
+
+	for _, c := range cfg.Module.Checks {
+		addr := c.Addr().InModule(moduleAddr)
+
+		st := &configCheckableState{
+			checkTypes: map[addrs.CheckRuleType]int{
+				addrs.CheckAssertion: len(c.Asserts),
+			},
+		}
+
+		if c.DataResource != nil {
+			st.checkTypes[addrs.CheckDataResource] = 1
+		}
+
+		into.Put(addr, st)
+	}
+
+	// Must also visit child modules to collect everything
+	for _, child := range cfg.Children {
+		collectInitialStatuses(into, child)
+	}
+}
+
+func collectInitialStatusForResource(into addrs.Map[addrs.ConfigCheckable, *configCheckableState], addr addrs.ConfigResource, rc *configs.Resource) {
+	if (len(rc.Preconditions) + len(rc.Postconditions)) == 0 {
+		// Don't bother with any resource that doesn't have at least
+		// one condition.
+		return
+	}
+
+	st := &configCheckableState{
+		checkTypes: make(map[addrs.CheckRuleType]int),
+	}
+
+	if ct := len(rc.Preconditions); ct > 0 {
+		st.checkTypes[addrs.ResourcePrecondition] = ct
+	}
+	if ct := len(rc.Postconditions); ct > 0 {
+		st.checkTypes[addrs.ResourcePostcondition] = ct
+	}
+
+	into.Put(addr, st)
+}
diff --git a/v1.5.7/internal/checks/state_report.go b/v1.5.7/internal/checks/state_report.go
new file mode 100644
index 0000000..7c478c5
--- /dev/null
+++ b/v1.5.7/internal/checks/state_report.go
@@ -0,0 +1,118 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package checks
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// These are the "Report"-prefixed methods of Checks used by Terraform Core
+// to gradually signal the results of checks during a plan or apply operation.
+
+// ReportCheckableObjects is the interface by which Terraform Core should
+// tell the State object which specific checkable objects were declared
+// by the given configuration object.
+//
+// This method will panic if the given configuration address isn't one known
+// by this Checks to have pending checks, and if any of the given object
+// addresses don't belong to the given configuration address.
+func (c *State) ReportCheckableObjects(configAddr addrs.ConfigCheckable, objectAddrs addrs.Set[addrs.Checkable]) {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	st, ok := c.statuses.GetOk(configAddr)
+	if !ok {
+		panic(fmt.Sprintf("checkable objects report for unknown configuration object %s", configAddr))
+	}
+	if st.objects.Elems != nil {
+		// Can only report checkable objects once per configuration object
+		panic(fmt.Sprintf("duplicate checkable objects report for %s ", configAddr))
+	}
+
+	// At this point we pre-populate all of the check results as StatusUnknown,
+	// so that even if we never hear from Terraform Core again we'll still
+	// remember that these results were all pending.
+	st.objects = addrs.MakeMap[addrs.Checkable, map[addrs.CheckRuleType][]Status]()
+	for _, objectAddr := range objectAddrs {
+		if gotConfigAddr := objectAddr.ConfigCheckable(); !addrs.Equivalent(configAddr, gotConfigAddr) {
+			// All of the given object addresses must belong to the specified configuration address
+			panic(fmt.Sprintf("%s belongs to %s, not %s", objectAddr, gotConfigAddr, configAddr))
+		}
+
+		checks := make(map[addrs.CheckRuleType][]Status, len(st.checkTypes))
+		for checkType, count := range st.checkTypes {
+			// NOTE: This is intentionally a slice of count of the zero value
+			// of Status, which is StatusUnknown to represent that we don't
+			// yet have a report for that particular check.
+			checks[checkType] = make([]Status, count)
+		}
+
+		st.objects.Put(objectAddr, checks)
+	}
+}
+
+// ReportCheckResult is the interface by which Terraform Core should tell the
+// State object the result of a specific check for an object that was
+// previously registered with ReportCheckableObjects.
+//
+// If the given object address doesn't match a previously-reported object,
+// or if the check index is out of bounds for the number of checks expected
+// of the given type, this method will panic to indicate a bug in the caller.
+//
+// This method will also panic if the specified check already had a known
+// status; each check should have its result reported only once.
+func (c *State) ReportCheckResult(objectAddr addrs.Checkable, checkType addrs.CheckRuleType, index int, status Status) {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	c.reportCheckResult(objectAddr, checkType, index, status)
+}
+
+// ReportCheckFailure is a more specialized version of ReportCheckResult which
+// captures a failure outcome in particular, giving the opportunity to capture
+// an author-specified error message string along with the failure.
+//
+// This always records the given check as having StatusFail. Don't use this for
+// situations where the check condition was itself invalid, because that
+// should be represented by StatusError instead, and the error signalled via
+// diagnostics as normal.
+func (c *State) ReportCheckFailure(objectAddr addrs.Checkable, checkType addrs.CheckRuleType, index int, errorMessage string) {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	c.reportCheckResult(objectAddr, checkType, index, StatusFail)
+	if c.failureMsgs.Elems == nil {
+		c.failureMsgs = addrs.MakeMap[addrs.CheckRule, string]()
+	}
+	checkAddr := addrs.NewCheckRule(objectAddr, checkType, index)
+	c.failureMsgs.Put(checkAddr, errorMessage)
+}
+
+// reportCheckResult is shared between both ReportCheckResult and
+// ReportCheckFailure, and assumes its caller already holds the mutex.
+func (c *State) reportCheckResult(objectAddr addrs.Checkable, checkType addrs.CheckRuleType, index int, status Status) {
+	configAddr := objectAddr.ConfigCheckable()
+
+	st, ok := c.statuses.GetOk(configAddr)
+	if !ok {
+		panic(fmt.Sprintf("checkable object status report for unknown configuration object %s", configAddr))
+	}
+
+	checks, ok := st.objects.GetOk(objectAddr)
+	if !ok {
+		panic(fmt.Sprintf("checkable object status report for unexpected checkable object %s", objectAddr))
+	}
+
+	if index >= len(checks[checkType]) {
+		panic(fmt.Sprintf("%s index %d out of range for %s", checkType, index, objectAddr))
+	}
+	if checks[checkType][index] != StatusUnknown {
+		panic(fmt.Sprintf("duplicate status report for %s %s %d", objectAddr, checkType, index))
+	}
+
+	checks[checkType][index] = status
+
+}
diff --git a/v1.5.7/internal/checks/state_test.go b/v1.5.7/internal/checks/state_test.go
new file mode 100644
index 0000000..e8f77bf
--- /dev/null
+++ b/v1.5.7/internal/checks/state_test.go
@@ -0,0 +1,227 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package checks
+
+import (
+	"context"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/initwd"
+)
+
+func TestChecksHappyPath(t *testing.T) {
+	const fixtureDir = "testdata/happypath"
+	loader, close := configload.NewLoaderForTests(t)
+	defer close()
+	inst := initwd.NewModuleInstaller(loader.ModulesDir(), loader, nil)
+	_, instDiags := inst.InstallModules(context.Background(), fixtureDir, true, initwd.ModuleInstallHooksImpl{})
+	if instDiags.HasErrors() {
+		t.Fatal(instDiags.Err())
+	}
+	if err := loader.RefreshModules(); err != nil {
+		t.Fatalf("failed to refresh modules after installation: %s", err)
+	}
+
+	/////////////////////////////////////////////////////////////////////////
+
+	cfg, hclDiags := loader.LoadConfig(fixtureDir)
+	if hclDiags.HasErrors() {
+		t.Fatalf("invalid configuration: %s", hclDiags.Error())
+	}
+
+	resourceA := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "null_resource",
+		Name: "a",
+	}.InModule(addrs.RootModule)
+	resourceNoChecks := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "null_resource",
+		Name: "no_checks",
+	}.InModule(addrs.RootModule)
+	resourceNonExist := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "null_resource",
+		Name: "nonexist",
+	}.InModule(addrs.RootModule)
+	rootOutput := addrs.OutputValue{
+		Name: "a",
+	}.InModule(addrs.RootModule)
+	moduleChild := addrs.RootModule.Child("child")
+	resourceB := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "null_resource",
+		Name: "b",
+	}.InModule(moduleChild)
+	resourceC := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "null_resource",
+		Name: "c",
+	}.InModule(moduleChild)
+	childOutput := addrs.OutputValue{
+		Name: "b",
+	}.InModule(moduleChild)
+	checkBlock := addrs.Check{
+		Name: "check",
+	}.InModule(addrs.RootModule)
+
+	// First some consistency checks to make sure our configuration is the
+	// shape we are relying on it to be.
+	if addr := resourceA; cfg.Module.ResourceByAddr(addr.Resource) == nil {
+		t.Fatalf("configuration does not include %s", addr)
+	}
+	if addr := resourceB; cfg.Children["child"].Module.ResourceByAddr(addr.Resource) == nil {
+		t.Fatalf("configuration does not include %s", addr)
+	}
+	if addr := resourceNoChecks; cfg.Module.ResourceByAddr(addr.Resource) == nil {
+		t.Fatalf("configuration does not include %s", addr)
+	}
+	if addr := resourceNonExist; cfg.Module.ResourceByAddr(addr.Resource) != nil {
+		t.Fatalf("configuration includes %s, which is not supposed to exist", addr)
+	}
+	if addr := checkBlock; cfg.Module.Checks[addr.Check.Name] == nil {
+		t.Fatalf("configuration does not include %s", addr)
+	}
+
+	/////////////////////////////////////////////////////////////////////////
+
+	checks := NewState(cfg)
+
+	missing := 0
+	if addr := resourceA; !checks.ConfigHasChecks(addr) {
+		t.Errorf("checks not detected for %s", addr)
+		missing++
+	}
+	if addr := resourceB; !checks.ConfigHasChecks(addr) {
+		t.Errorf("checks not detected for %s", addr)
+		missing++
+	}
+	if addr := resourceC; !checks.ConfigHasChecks(addr) {
+		t.Errorf("checks not detected for %s", addr)
+		missing++
+	}
+	if addr := rootOutput; !checks.ConfigHasChecks(addr) {
+		t.Errorf("checks not detected for %s", addr)
+		missing++
+	}
+	if addr := childOutput; !checks.ConfigHasChecks(addr) {
+		t.Errorf("checks not detected for %s", addr)
+		missing++
+	}
+	if addr := resourceNoChecks; checks.ConfigHasChecks(addr) {
+		t.Errorf("checks detected for %s, even though it has none", addr)
+	}
+	if addr := resourceNonExist; checks.ConfigHasChecks(addr) {
+		t.Errorf("checks detected for %s, even though it doesn't exist", addr)
+	}
+	if addr := checkBlock; !checks.ConfigHasChecks(addr) {
+		t.Errorf("checks not detected for %s", addr)
+		missing++
+	}
+	if missing > 0 {
+		t.Fatalf("missing some configuration objects we'd need for subsequent testing")
+	}
+
+	/////////////////////////////////////////////////////////////////////////
+
+	// Everything should start with status unknown.
+
+	{
+		wantConfigAddrs := addrs.MakeSet[addrs.ConfigCheckable](
+			resourceA,
+			resourceB,
+			resourceC,
+			rootOutput,
+			childOutput,
+			checkBlock,
+		)
+		gotConfigAddrs := checks.AllConfigAddrs()
+		if diff := cmp.Diff(wantConfigAddrs, gotConfigAddrs); diff != "" {
+			t.Errorf("wrong detected config addresses\n%s", diff)
+		}
+
+		for _, configAddr := range gotConfigAddrs {
+			if got, want := checks.AggregateCheckStatus(configAddr), StatusUnknown; got != want {
+				t.Errorf("incorrect initial aggregate check status for %s: %s, but want %s", configAddr, got, want)
+			}
+		}
+	}
+
+	/////////////////////////////////////////////////////////////////////////
+
+	// The following are steps that would normally be done by Terraform Core
+	// as part of visiting checkable objects during the graph walk. We're
+	// simulating a likely sequence of calls here for testing purposes, but
+	// Terraform Core won't necessarily visit all of these in exactly the
+	// same order every time and so this is just one possible valid ordering
+	// of calls.
+
+	resourceInstA := resourceA.Resource.Absolute(addrs.RootModuleInstance).Instance(addrs.NoKey)
+	rootOutputInst := rootOutput.OutputValue.Absolute(addrs.RootModuleInstance)
+	moduleChildInst := addrs.RootModuleInstance.Child("child", addrs.NoKey)
+	resourceInstB := resourceB.Resource.Absolute(moduleChildInst).Instance(addrs.NoKey)
+	resourceInstC0 := resourceC.Resource.Absolute(moduleChildInst).Instance(addrs.IntKey(0))
+	resourceInstC1 := resourceC.Resource.Absolute(moduleChildInst).Instance(addrs.IntKey(1))
+	childOutputInst := childOutput.OutputValue.Absolute(moduleChildInst)
+	checkBlockInst := checkBlock.Check.Absolute(addrs.RootModuleInstance)
+
+	checks.ReportCheckableObjects(resourceA, addrs.MakeSet[addrs.Checkable](resourceInstA))
+	checks.ReportCheckResult(resourceInstA, addrs.ResourcePrecondition, 0, StatusPass)
+	checks.ReportCheckResult(resourceInstA, addrs.ResourcePrecondition, 1, StatusPass)
+	checks.ReportCheckResult(resourceInstA, addrs.ResourcePostcondition, 0, StatusPass)
+
+	checks.ReportCheckableObjects(resourceB, addrs.MakeSet[addrs.Checkable](resourceInstB))
+	checks.ReportCheckResult(resourceInstB, addrs.ResourcePrecondition, 0, StatusPass)
+
+	checks.ReportCheckableObjects(resourceC, addrs.MakeSet[addrs.Checkable](resourceInstC0, resourceInstC1))
+	checks.ReportCheckResult(resourceInstC0, addrs.ResourcePostcondition, 0, StatusPass)
+	checks.ReportCheckResult(resourceInstC1, addrs.ResourcePostcondition, 0, StatusPass)
+
+	checks.ReportCheckableObjects(childOutput, addrs.MakeSet[addrs.Checkable](childOutputInst))
+	checks.ReportCheckResult(childOutputInst, addrs.OutputPrecondition, 0, StatusPass)
+
+	checks.ReportCheckableObjects(rootOutput, addrs.MakeSet[addrs.Checkable](rootOutputInst))
+	checks.ReportCheckResult(rootOutputInst, addrs.OutputPrecondition, 0, StatusPass)
+
+	checks.ReportCheckableObjects(checkBlock, addrs.MakeSet[addrs.Checkable](checkBlockInst))
+	checks.ReportCheckResult(checkBlockInst, addrs.CheckAssertion, 0, StatusPass)
+
+	/////////////////////////////////////////////////////////////////////////
+
+	// This "section" is simulating what we might do to report the results
+	// of the checks after a run completes.
+
+	{
+		configCount := 0
+		for _, configAddr := range checks.AllConfigAddrs() {
+			configCount++
+			if got, want := checks.AggregateCheckStatus(configAddr), StatusPass; got != want {
+				t.Errorf("incorrect final aggregate check status for %s: %s, but want %s", configAddr, got, want)
+			}
+		}
+		if got, want := configCount, 6; got != want {
+			t.Errorf("incorrect number of known config addresses %d; want %d", got, want)
+		}
+	}
+
+	{
+		objAddrs := addrs.MakeSet[addrs.Checkable](
+			resourceInstA,
+			rootOutputInst,
+			resourceInstB,
+			resourceInstC0,
+			resourceInstC1,
+			childOutputInst,
+			checkBlockInst,
+		)
+		for _, addr := range objAddrs {
+			if got, want := checks.ObjectCheckStatus(addr), StatusPass; got != want {
+				t.Errorf("incorrect final check status for object %s: %s, but want %s", addr, got, want)
+			}
+		}
+	}
+}
diff --git a/v1.5.7/internal/checks/status.go b/v1.5.7/internal/checks/status.go
new file mode 100644
index 0000000..84b7bdc
--- /dev/null
+++ b/v1.5.7/internal/checks/status.go
@@ -0,0 +1,77 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package checks
+
+import (
+	"fmt"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Status represents the status of an individual check associated with a
+// checkable object.
+type Status rune
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=Status
+
+const (
+	// StatusUnknown represents that there is not yet a conclusive result
+	// for the check, either because we haven't yet visited its associated
+	// object or because the check condition itself depends on a value not
+	// yet known during planning.
+	StatusUnknown Status = 0
+	// NOTE: Our implementation relies on StatusUnknown being the zero value
+	// of Status.
+
+	// StatusPass represents that Terraform Core has evaluated the check's
+	// condition and it returned true, indicating success.
+	StatusPass Status = 'P'
+
+	// StatusFail represents that Terraform Core has evaluated the check's
+	// condition and it returned false, indicating failure.
+	StatusFail Status = 'F'
+
+	// StatusError represents that Terraform Core tried to evaluate the check's
+	// condition but encountered an error while evaluating the check expression.
+	//
+	// This is different than StatusFail because StatusFail indiciates that
+	// the condition was valid and returned false, whereas StatusError
+	// indicates that the condition was not valid at all.
+	StatusError Status = 'E'
+)
+
+// StatusForCtyValue returns the Status value corresponding to the given
+// cty Value, which must be one of either cty.True, cty.False, or
+// cty.UnknownVal(cty.Bool) or else this function will panic.
+//
+// The current behavior of this function is:
+//
+//	cty.True                  StatusPass
+//	cty.False                 StatusFail
+//	cty.UnknownVal(cty.Bool)  StatusUnknown
+//
+// Any other input will panic. Note that there's no value that can produce
+// StatusError, because in case of a condition error there will not typically
+// be a result value at all.
+func StatusForCtyValue(v cty.Value) Status {
+	if !v.Type().Equals(cty.Bool) {
+		panic(fmt.Sprintf("cannot use %s as check status", v.Type().FriendlyName()))
+	}
+	if v.IsNull() {
+		panic("cannot use null as check status")
+	}
+
+	switch {
+	case v == cty.True:
+		return StatusPass
+	case v == cty.False:
+		return StatusFail
+	case !v.IsKnown():
+		return StatusUnknown
+	default:
+		// Should be impossible to get here unless something particularly
+		// weird is going on, like a marked condition result.
+		panic(fmt.Sprintf("cannot use %#v as check status", v))
+	}
+}
diff --git a/v1.5.7/internal/checks/status_string.go b/v1.5.7/internal/checks/status_string.go
new file mode 100644
index 0000000..3cee235
--- /dev/null
+++ b/v1.5.7/internal/checks/status_string.go
@@ -0,0 +1,39 @@
+// Code generated by "stringer -type=Status"; DO NOT EDIT.
+
+package checks
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[StatusUnknown-0]
+	_ = x[StatusPass-80]
+	_ = x[StatusFail-70]
+	_ = x[StatusError-69]
+}
+
+const (
+	_Status_name_0 = "StatusUnknown"
+	_Status_name_1 = "StatusErrorStatusFail"
+	_Status_name_2 = "StatusPass"
+)
+
+var (
+	_Status_index_1 = [...]uint8{0, 11, 21}
+)
+
+func (i Status) String() string {
+	switch {
+	case i == 0:
+		return _Status_name_0
+	case 69 <= i && i <= 70:
+		i -= 69
+		return _Status_name_1[_Status_index_1[i]:_Status_index_1[i+1]]
+	case i == 80:
+		return _Status_name_2
+	default:
+		return "Status(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/v1.5.7/internal/checks/testdata/happypath/checks-happypath.tf b/v1.5.7/internal/checks/testdata/happypath/checks-happypath.tf
new file mode 100644
index 0000000..a9cd055
--- /dev/null
+++ b/v1.5.7/internal/checks/testdata/happypath/checks-happypath.tf
@@ -0,0 +1,39 @@
+resource "null_resource" "a" {
+  lifecycle {
+    precondition {
+      condition     = null_resource.no_checks == ""
+      error_message = "Impossible."
+    }
+    precondition {
+      condition     = null_resource.no_checks == ""
+      error_message = "Also impossible."
+    }
+    postcondition {
+      condition     = null_resource.no_checks == ""
+      error_message = "Definitely not possible."
+    }
+  }
+}
+
+resource "null_resource" "no_checks" {
+}
+
+module "child" {
+  source = "./child"
+}
+
+output "a" {
+  value = null_resource.a.id
+
+  precondition {
+    condition     = null_resource.a.id != ""
+    error_message = "A has no id."
+  }
+}
+
+check "check" {
+  assert {
+    condition = null_resource.a.id != ""
+    error_message = "check block: A has no id"
+  }
+}
diff --git a/v1.5.7/internal/checks/testdata/happypath/child/checks-happypath-child.tf b/v1.5.7/internal/checks/testdata/happypath/child/checks-happypath-child.tf
new file mode 100644
index 0000000..d067bc2
--- /dev/null
+++ b/v1.5.7/internal/checks/testdata/happypath/child/checks-happypath-child.tf
@@ -0,0 +1,29 @@
+resource "null_resource" "b" {
+  lifecycle {
+    precondition {
+      condition     = self.id == ""
+      error_message = "Impossible."
+    }
+  }
+}
+
+resource "null_resource" "c" {
+  count = 2
+
+  lifecycle {
+    postcondition {
+      condition     = self.id == ""
+      error_message = "Impossible."
+    }
+  }
+}
+
+output "b" {
+  value = null_resource.b.id
+
+  precondition {
+    condition     = null_resource.b.id != ""
+    error_message = "B has no id."
+  }
+}
+
diff --git a/v1.5.7/internal/cloud/backend.go b/v1.5.7/internal/cloud/backend.go
new file mode 100644
index 0000000..1529343
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend.go
@@ -0,0 +1,1220 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"log"
+	"net/http"
+	"net/url"
+	"os"
+	"sort"
+	"strings"
+	"sync"
+	"time"
+
+	tfe "github.com/hashicorp/go-tfe"
+	version "github.com/hashicorp/go-version"
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/mitchellh/cli"
+	"github.com/mitchellh/colorstring"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/gocty"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/jsonformat"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	tfversion "github.com/hashicorp/terraform/version"
+
+	backendLocal "github.com/hashicorp/terraform/internal/backend/local"
+)
+
+const (
+	defaultHostname    = "app.terraform.io"
+	defaultParallelism = 10
+	tfeServiceID       = "tfe.v2"
+	headerSourceKey    = "X-Terraform-Integration"
+	headerSourceValue  = "cloud"
+	genericHostname    = "localterraform.com"
+)
+
+// Cloud is an implementation of EnhancedBackend in service of the Terraform Cloud/Enterprise
+// integration for Terraform CLI. This backend is not intended to be surfaced at the user level and
+// is instead an implementation detail of cloud.Cloud.
+type Cloud struct {
+	// CLI and Colorize control the CLI output. If CLI is nil then no CLI
+	// output will be done. If CLIColor is nil then no coloring will be done.
+	CLI      cli.Ui
+	CLIColor *colorstring.Colorize
+
+	// ContextOpts are the base context options to set when initializing a
+	// new Terraform context. Many of these will be overridden or merged by
+	// Operation. See Operation for more details.
+	ContextOpts *terraform.ContextOpts
+
+	// client is the Terraform Cloud/Enterprise API client.
+	client *tfe.Client
+
+	// lastRetry is set to the last time a request was retried.
+	lastRetry time.Time
+
+	// hostname of Terraform Cloud or Terraform Enterprise
+	hostname string
+
+	// token for Terraform Cloud or Terraform Enterprise
+	token string
+
+	// organization is the organization that contains the target workspaces.
+	organization string
+
+	// WorkspaceMapping contains strategies for mapping CLI workspaces in the working directory
+	// to remote Terraform Cloud workspaces.
+	WorkspaceMapping WorkspaceMapping
+
+	// services is used for service discovery
+	services *disco.Disco
+
+	// renderer is used for rendering JSON plan output and streamed logs.
+	renderer *jsonformat.Renderer
+
+	// local allows local operations, where Terraform Cloud serves as a state storage backend.
+	local backend.Enhanced
+
+	// forceLocal, if true, will force the use of the local backend.
+	forceLocal bool
+
+	// opLock locks operations
+	opLock sync.Mutex
+
+	// ignoreVersionConflict, if true, will disable the requirement that the
+	// local Terraform version matches the remote workspace's configured
+	// version. This will also cause VerifyWorkspaceTerraformVersion to return
+	// a warning diagnostic instead of an error.
+	ignoreVersionConflict bool
+
+	runningInAutomation bool
+
+	// input stores the value of the -input flag, since it will be used
+	// to determine whether or not to ask the user for approval of a run.
+	input bool
+}
+
+var _ backend.Backend = (*Cloud)(nil)
+var _ backend.Enhanced = (*Cloud)(nil)
+var _ backend.Local = (*Cloud)(nil)
+
+// New creates a new initialized cloud backend.
+func New(services *disco.Disco) *Cloud {
+	return &Cloud{
+		services: services,
+	}
+}
+
+// ConfigSchema implements backend.Enhanced.
+func (b *Cloud) ConfigSchema() *configschema.Block {
+	return &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"hostname": {
+				Type:        cty.String,
+				Optional:    true,
+				Description: schemaDescriptionHostname,
+			},
+			"organization": {
+				Type:        cty.String,
+				Optional:    true,
+				Description: schemaDescriptionOrganization,
+			},
+			"token": {
+				Type:        cty.String,
+				Optional:    true,
+				Description: schemaDescriptionToken,
+			},
+		},
+
+		BlockTypes: map[string]*configschema.NestedBlock{
+			"workspaces": {
+				Block: configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"name": {
+							Type:        cty.String,
+							Optional:    true,
+							Description: schemaDescriptionName,
+						},
+						"tags": {
+							Type:        cty.Set(cty.String),
+							Optional:    true,
+							Description: schemaDescriptionTags,
+						},
+					},
+				},
+				Nesting: configschema.NestingSingle,
+			},
+		},
+	}
+}
+
+// PrepareConfig implements backend.Backend.
+func (b *Cloud) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	if obj.IsNull() {
+		return obj, diags
+	}
+
+	// check if organization is specified in the config.
+	if val := obj.GetAttr("organization"); val.IsNull() || val.AsString() == "" {
+		// organization is specified in the config but is invalid, so
+		// we'll fallback on TF_CLOUD_ORGANIZATION
+		if val := os.Getenv("TF_CLOUD_ORGANIZATION"); val == "" {
+			diags = diags.Append(missingConfigAttributeAndEnvVar("organization", "TF_CLOUD_ORGANIZATION"))
+		}
+	}
+
+	WorkspaceMapping := WorkspaceMapping{}
+	if workspaces := obj.GetAttr("workspaces"); !workspaces.IsNull() {
+		if val := workspaces.GetAttr("name"); !val.IsNull() {
+			WorkspaceMapping.Name = val.AsString()
+		}
+		if val := workspaces.GetAttr("tags"); !val.IsNull() {
+			err := gocty.FromCtyValue(val, &WorkspaceMapping.Tags)
+			if err != nil {
+				log.Panicf("An unxpected error occurred: %s", err)
+			}
+		}
+	} else {
+		WorkspaceMapping.Name = os.Getenv("TF_WORKSPACE")
+	}
+
+	switch WorkspaceMapping.Strategy() {
+	// Make sure have a workspace mapping strategy present
+	case WorkspaceNoneStrategy:
+		diags = diags.Append(invalidWorkspaceConfigMissingValues)
+	// Make sure that a workspace name is configured.
+	case WorkspaceInvalidStrategy:
+		diags = diags.Append(invalidWorkspaceConfigMisconfiguration)
+	}
+
+	return obj, diags
+}
+
+func (b *Cloud) ServiceDiscoveryAliases() ([]backend.HostAlias, error) {
+	aliasHostname, err := svchost.ForComparison(genericHostname)
+	if err != nil {
+		// This should never happen because the hostname is statically defined.
+		return nil, fmt.Errorf("failed to create backend alias from alias %q. The hostname is not in the correct format. This is a bug in the backend", genericHostname)
+	}
+
+	targetHostname, err := svchost.ForComparison(b.hostname)
+	if err != nil {
+		// This should never happen because the 'to' alias is the backend host, which has
+		// already been ev
+		return nil, fmt.Errorf("failed to create backend alias to target %q. The hostname is not in the correct format.", b.hostname)
+	}
+
+	return []backend.HostAlias{
+		{
+			From: aliasHostname,
+			To:   targetHostname,
+		},
+	}, nil
+}
+
+// Configure implements backend.Enhanced.
+func (b *Cloud) Configure(obj cty.Value) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+	if obj.IsNull() {
+		return diags
+	}
+
+	diagErr := b.setConfigurationFields(obj)
+	if diagErr.HasErrors() {
+		return diagErr
+	}
+
+	// Discover the service URL to confirm that it provides the Terraform Cloud/Enterprise API
+	service, err := b.discover()
+
+	// Check for errors before we continue.
+	if err != nil {
+		diags = diags.Append(tfdiags.AttributeValue(
+			tfdiags.Error,
+			strings.ToUpper(err.Error()[:1])+err.Error()[1:],
+			"", // no description is needed here, the error is clear
+			cty.Path{cty.GetAttrStep{Name: "hostname"}},
+		))
+		return diags
+	}
+
+	// First we'll retrieve the token from the configuration
+	var token string
+	if val := obj.GetAttr("token"); !val.IsNull() {
+		token = val.AsString()
+	}
+
+	// Get the token from the CLI Config File in the credentials section
+	// if no token was not set in the configuration
+	if token == "" {
+		token, err = b.cliConfigToken()
+		if err != nil {
+			diags = diags.Append(tfdiags.AttributeValue(
+				tfdiags.Error,
+				strings.ToUpper(err.Error()[:1])+err.Error()[1:],
+				"", // no description is needed here, the error is clear
+				cty.Path{cty.GetAttrStep{Name: "hostname"}},
+			))
+			return diags
+		}
+	}
+
+	// Return an error if we still don't have a token at this point.
+	if token == "" {
+		loginCommand := "terraform login"
+		if b.hostname != defaultHostname {
+			loginCommand = loginCommand + " " + b.hostname
+		}
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Required token could not be found",
+			fmt.Sprintf(
+				"Run the following command to generate a token for %s:\n    %s",
+				b.hostname,
+				loginCommand,
+			),
+		))
+		return diags
+	}
+
+	b.token = token
+
+	if b.client == nil {
+		cfg := &tfe.Config{
+			Address:      service.String(),
+			BasePath:     service.Path,
+			Token:        token,
+			Headers:      make(http.Header),
+			RetryLogHook: b.retryLogHook,
+		}
+
+		// Set the version header to the current version.
+		cfg.Headers.Set(tfversion.Header, tfversion.Version)
+		cfg.Headers.Set(headerSourceKey, headerSourceValue)
+
+		// Create the TFC/E API client.
+		b.client, err = tfe.NewClient(cfg)
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to create the Terraform Cloud/Enterprise client",
+				fmt.Sprintf(
+					`Encountered an unexpected error while creating the `+
+						`Terraform Cloud/Enterprise client: %s.`, err,
+				),
+			))
+			return diags
+		}
+	}
+
+	// Check if the organization exists by reading its entitlements.
+	entitlements, err := b.client.Organizations.ReadEntitlements(context.Background(), b.organization)
+	if err != nil {
+		if err == tfe.ErrResourceNotFound {
+			err = fmt.Errorf("organization %q at host %s not found.\n\n"+
+				"Please ensure that the organization and hostname are correct "+
+				"and that your API token for %s is valid.",
+				b.organization, b.hostname, b.hostname)
+		}
+		diags = diags.Append(tfdiags.AttributeValue(
+			tfdiags.Error,
+			fmt.Sprintf("Failed to read organization %q at host %s", b.organization, b.hostname),
+			fmt.Sprintf("Encountered an unexpected error while reading the "+
+				"organization settings: %s", err),
+			cty.Path{cty.GetAttrStep{Name: "organization"}},
+		))
+		return diags
+	}
+
+	if ws, ok := os.LookupEnv("TF_WORKSPACE"); ok {
+		if ws == b.WorkspaceMapping.Name || b.WorkspaceMapping.Strategy() == WorkspaceTagsStrategy {
+			diag := b.validWorkspaceEnvVar(context.Background(), b.organization, ws)
+			if diag != nil {
+				diags = diags.Append(diag)
+				return diags
+			}
+		}
+	}
+
+	// Check for the minimum version of Terraform Enterprise required.
+	//
+	// For API versions prior to 2.3, RemoteAPIVersion will return an empty string,
+	// so if there's an error when parsing the RemoteAPIVersion, it's handled as
+	// equivalent to an API version < 2.3.
+	currentAPIVersion, parseErr := version.NewVersion(b.client.RemoteAPIVersion())
+	desiredAPIVersion, _ := version.NewVersion("2.5")
+
+	if parseErr != nil || currentAPIVersion.LessThan(desiredAPIVersion) {
+		log.Printf("[TRACE] API version check failed; want: >= %s, got: %s", desiredAPIVersion.Original(), currentAPIVersion)
+		if b.runningInAutomation {
+			// It should never be possible for this Terraform process to be mistakenly
+			// used internally within an unsupported Terraform Enterprise install - but
+			// just in case it happens, give an actionable error.
+			diags = diags.Append(
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Unsupported Terraform Enterprise version",
+					cloudIntegrationUsedInUnsupportedTFE,
+				),
+			)
+		} else {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Unsupported Terraform Enterprise version",
+				`The 'cloud' option is not supported with this version of Terraform Enterprise.`,
+			),
+			)
+		}
+	}
+
+	// Configure a local backend for when we need to run operations locally.
+	b.local = backendLocal.NewWithBackend(b)
+	b.forceLocal = b.forceLocal || !entitlements.Operations
+
+	// Enable retries for server errors as the backend is now fully configured.
+	b.client.RetryServerErrors(true)
+
+	return diags
+}
+
+func (b *Cloud) setConfigurationFields(obj cty.Value) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	// Get the hostname.
+	b.hostname = os.Getenv("TF_CLOUD_HOSTNAME")
+	if val := obj.GetAttr("hostname"); !val.IsNull() && val.AsString() != "" {
+		b.hostname = val.AsString()
+	} else if b.hostname == "" {
+		b.hostname = defaultHostname
+	}
+
+	// We can have two options, setting the organization via the config
+	// or using TF_CLOUD_ORGANIZATION. Since PrepareConfig() validates that one of these
+	// values must exist, we'll initially set it to the env var and override it if
+	// specified in the configuration.
+	b.organization = os.Getenv("TF_CLOUD_ORGANIZATION")
+
+	// Check if the organization is present and valid in the config.
+	if val := obj.GetAttr("organization"); !val.IsNull() && val.AsString() != "" {
+		b.organization = val.AsString()
+	}
+
+	// Get the workspaces configuration block and retrieve the
+	// default workspace name.
+	if workspaces := obj.GetAttr("workspaces"); !workspaces.IsNull() {
+
+		// PrepareConfig checks that you cannot set both of these.
+		if val := workspaces.GetAttr("name"); !val.IsNull() {
+			b.WorkspaceMapping.Name = val.AsString()
+		}
+		if val := workspaces.GetAttr("tags"); !val.IsNull() {
+			var tags []string
+			err := gocty.FromCtyValue(val, &tags)
+			if err != nil {
+				log.Panicf("An unexpected error occurred: %s", err)
+			}
+
+			b.WorkspaceMapping.Tags = tags
+		}
+	} else {
+		b.WorkspaceMapping.Name = os.Getenv("TF_WORKSPACE")
+	}
+
+	// Determine if we are forced to use the local backend.
+	b.forceLocal = os.Getenv("TF_FORCE_LOCAL_BACKEND") != ""
+
+	return diags
+}
+
+// discover the TFC/E API service URL and version constraints.
+func (b *Cloud) discover() (*url.URL, error) {
+	hostname, err := svchost.ForComparison(b.hostname)
+	if err != nil {
+		return nil, err
+	}
+
+	host, err := b.services.Discover(hostname)
+	if err != nil {
+		var serviceDiscoErr *disco.ErrServiceDiscoveryNetworkRequest
+
+		switch {
+		case errors.As(err, &serviceDiscoErr):
+			err = fmt.Errorf("a network issue prevented cloud configuration; %w", err)
+			return nil, err
+		default:
+			return nil, err
+		}
+	}
+
+	service, err := host.ServiceURL(tfeServiceID)
+	// Return the error, unless its a disco.ErrVersionNotSupported error.
+	if _, ok := err.(*disco.ErrVersionNotSupported); !ok && err != nil {
+		return nil, err
+	}
+
+	return service, err
+}
+
+// cliConfigToken returns the token for this host as configured in the credentials
+// section of the CLI Config File. If no token was configured, an empty
+// string will be returned instead.
+func (b *Cloud) cliConfigToken() (string, error) {
+	hostname, err := svchost.ForComparison(b.hostname)
+	if err != nil {
+		return "", err
+	}
+	creds, err := b.services.CredentialsForHost(hostname)
+	if err != nil {
+		log.Printf("[WARN] Failed to get credentials for %s: %s (ignoring)", b.hostname, err)
+		return "", nil
+	}
+	if creds != nil {
+		return creds.Token(), nil
+	}
+	return "", nil
+}
+
+// retryLogHook is invoked each time a request is retried allowing the
+// backend to log any connection issues to prevent data loss.
+func (b *Cloud) retryLogHook(attemptNum int, resp *http.Response) {
+	if b.CLI != nil {
+		// Ignore the first retry to make sure any delayed output will
+		// be written to the console before we start logging retries.
+		//
+		// The retry logic in the TFE client will retry both rate limited
+		// requests and server errors, but in the cloud backend we only
+		// care about server errors so we ignore rate limit (429) errors.
+		if attemptNum == 0 || (resp != nil && resp.StatusCode == 429) {
+			// Reset the last retry time.
+			b.lastRetry = time.Now()
+			return
+		}
+
+		if attemptNum == 1 {
+			b.CLI.Output(b.Colorize().Color(strings.TrimSpace(initialRetryError)))
+		} else {
+			b.CLI.Output(b.Colorize().Color(strings.TrimSpace(
+				fmt.Sprintf(repeatedRetryError, time.Since(b.lastRetry).Round(time.Second)))))
+		}
+	}
+}
+
+// Workspaces implements backend.Enhanced, returning a filtered list of workspace names according to
+// the workspace mapping strategy configured.
+func (b *Cloud) Workspaces() ([]string, error) {
+	// Create a slice to contain all the names.
+	var names []string
+
+	// If configured for a single workspace, return that exact name only.  The StateMgr for this
+	// backend will automatically create the remote workspace if it does not yet exist.
+	if b.WorkspaceMapping.Strategy() == WorkspaceNameStrategy {
+		names = append(names, b.WorkspaceMapping.Name)
+		return names, nil
+	}
+
+	// Otherwise, multiple workspaces are being mapped. Query Terraform Cloud for all the remote
+	// workspaces by the provided mapping strategy.
+	options := &tfe.WorkspaceListOptions{}
+	if b.WorkspaceMapping.Strategy() == WorkspaceTagsStrategy {
+		taglist := strings.Join(b.WorkspaceMapping.Tags, ",")
+		options.Tags = taglist
+	}
+
+	for {
+		wl, err := b.client.Workspaces.List(context.Background(), b.organization, options)
+		if err != nil {
+			return nil, err
+		}
+
+		for _, w := range wl.Items {
+			names = append(names, w.Name)
+		}
+
+		// Exit the loop when we've seen all pages.
+		if wl.CurrentPage >= wl.TotalPages {
+			break
+		}
+
+		// Update the page number to get the next page.
+		options.PageNumber = wl.NextPage
+	}
+
+	// Sort the result so we have consistent output.
+	sort.StringSlice(names).Sort()
+
+	return names, nil
+}
+
+// DeleteWorkspace implements backend.Enhanced.
+func (b *Cloud) DeleteWorkspace(name string, force bool) error {
+	if name == backend.DefaultStateName {
+		return backend.ErrDefaultWorkspaceNotSupported
+	}
+
+	if b.WorkspaceMapping.Strategy() == WorkspaceNameStrategy {
+		return backend.ErrWorkspacesNotSupported
+	}
+
+	workspace, err := b.client.Workspaces.Read(context.Background(), b.organization, name)
+	if err == tfe.ErrResourceNotFound {
+		return nil // If the workspace does not exist, succeed
+	}
+
+	if err != nil {
+		return fmt.Errorf("failed to retrieve workspace %s: %v", name, err)
+	}
+
+	// Configure the remote workspace name.
+	State := &State{tfeClient: b.client, organization: b.organization, workspace: workspace}
+	return State.Delete(force)
+}
+
+// StateMgr implements backend.Enhanced.
+func (b *Cloud) StateMgr(name string) (statemgr.Full, error) {
+	var remoteTFVersion string
+
+	if name == backend.DefaultStateName {
+		return nil, backend.ErrDefaultWorkspaceNotSupported
+	}
+
+	if b.WorkspaceMapping.Strategy() == WorkspaceNameStrategy && name != b.WorkspaceMapping.Name {
+		return nil, backend.ErrWorkspacesNotSupported
+	}
+
+	workspace, err := b.client.Workspaces.Read(context.Background(), b.organization, name)
+	if err != nil && err != tfe.ErrResourceNotFound {
+		return nil, fmt.Errorf("Failed to retrieve workspace %s: %v", name, err)
+	}
+	if workspace != nil {
+		remoteTFVersion = workspace.TerraformVersion
+	}
+
+	if err == tfe.ErrResourceNotFound {
+		// Create a workspace
+		options := tfe.WorkspaceCreateOptions{
+			Name: tfe.String(name),
+			Tags: b.WorkspaceMapping.tfeTags(),
+		}
+
+		log.Printf("[TRACE] cloud: Creating Terraform Cloud workspace %s/%s", b.organization, name)
+		workspace, err = b.client.Workspaces.Create(context.Background(), b.organization, options)
+		if err != nil {
+			return nil, fmt.Errorf("Error creating workspace %s: %v", name, err)
+		}
+
+		remoteTFVersion = workspace.TerraformVersion
+
+		// Attempt to set the new workspace to use this version of Terraform. This
+		// can fail if there's no enabled tool_version whose name matches our
+		// version string, but that's expected sometimes -- just warn and continue.
+		versionOptions := tfe.WorkspaceUpdateOptions{
+			TerraformVersion: tfe.String(tfversion.String()),
+		}
+		_, err := b.client.Workspaces.UpdateByID(context.Background(), workspace.ID, versionOptions)
+		if err == nil {
+			remoteTFVersion = tfversion.String()
+		} else {
+			// TODO: Ideally we could rely on the client to tell us what the actual
+			// problem was, but we currently can't get enough context from the error
+			// object to do a nicely formatted message, so we're just assuming the
+			// issue was that the version wasn't available since that's probably what
+			// happened.
+			log.Printf("[TRACE] cloud: Attempted to select version %s for TFC workspace; unavailable, so %s will be used instead.", tfversion.String(), workspace.TerraformVersion)
+			if b.CLI != nil {
+				versionUnavailable := fmt.Sprintf(unavailableTerraformVersion, tfversion.String(), workspace.TerraformVersion)
+				b.CLI.Output(b.Colorize().Color(versionUnavailable))
+			}
+		}
+	}
+
+	if b.workspaceTagsRequireUpdate(workspace, b.WorkspaceMapping) {
+		options := tfe.WorkspaceAddTagsOptions{
+			Tags: b.WorkspaceMapping.tfeTags(),
+		}
+		log.Printf("[TRACE] cloud: Adding tags for Terraform Cloud workspace %s/%s", b.organization, name)
+		err = b.client.Workspaces.AddTags(context.Background(), workspace.ID, options)
+		if err != nil {
+			return nil, fmt.Errorf("Error updating workspace %s: %v", name, err)
+		}
+	}
+
+	// This is a fallback error check. Most code paths should use other
+	// mechanisms to check the version, then set the ignoreVersionConflict
+	// field to true. This check is only in place to ensure that we don't
+	// accidentally upgrade state with a new code path, and the version check
+	// logic is coarser and simpler.
+	if !b.ignoreVersionConflict {
+		// Explicitly ignore the pseudo-version "latest" here, as it will cause
+		// plan and apply to always fail.
+		if remoteTFVersion != tfversion.String() && remoteTFVersion != "latest" {
+			return nil, fmt.Errorf("Remote workspace Terraform version %q does not match local Terraform version %q", remoteTFVersion, tfversion.String())
+		}
+	}
+
+	return &State{tfeClient: b.client, organization: b.organization, workspace: workspace}, nil
+}
+
+// Operation implements backend.Enhanced.
+func (b *Cloud) Operation(ctx context.Context, op *backend.Operation) (*backend.RunningOperation, error) {
+	// Retrieve the workspace for this operation.
+	w, err := b.fetchWorkspace(ctx, b.organization, op.Workspace)
+	if err != nil {
+		return nil, err
+	}
+
+	// Terraform remote version conflicts are not a concern for operations. We
+	// are in one of three states:
+	//
+	// - Running remotely, in which case the local version is irrelevant;
+	// - Workspace configured for local operations, in which case the remote
+	//   version is meaningless;
+	// - Forcing local operations, which should only happen in the Terraform Cloud worker, in
+	//   which case the Terraform versions by definition match.
+	b.IgnoreVersionConflict()
+
+	// Check if we need to use the local backend to run the operation.
+	if b.forceLocal || isLocalExecutionMode(w.ExecutionMode) {
+		// Record that we're forced to run operations locally to allow the
+		// command package UI to operate correctly
+		b.forceLocal = true
+		return b.local.Operation(ctx, op)
+	}
+
+	// Set the remote workspace name.
+	op.Workspace = w.Name
+
+	// Determine the function to call for our operation
+	var f func(context.Context, context.Context, *backend.Operation, *tfe.Workspace) (*tfe.Run, error)
+	switch op.Type {
+	case backend.OperationTypePlan:
+		f = b.opPlan
+	case backend.OperationTypeApply:
+		f = b.opApply
+	case backend.OperationTypeRefresh:
+		// The `terraform refresh` command has been deprecated in favor of `terraform apply -refresh-state`.
+		// Rather than respond with an error telling the user to run the other command we can just run
+		// that command instead. We will tell the user what we are doing, and then do it.
+		if b.CLI != nil {
+			b.CLI.Output(b.Colorize().Color(strings.TrimSpace(refreshToApplyRefresh) + "\n"))
+		}
+		op.PlanMode = plans.RefreshOnlyMode
+		op.PlanRefresh = true
+		op.AutoApprove = true
+		f = b.opApply
+	default:
+		return nil, fmt.Errorf(
+			"\n\nTerraform Cloud does not support the %q operation.", op.Type)
+	}
+
+	// Lock
+	b.opLock.Lock()
+
+	// Build our running operation
+	// the runninCtx is only used to block until the operation returns.
+	runningCtx, done := context.WithCancel(context.Background())
+	runningOp := &backend.RunningOperation{
+		Context:   runningCtx,
+		PlanEmpty: true,
+	}
+
+	// stopCtx wraps the context passed in, and is used to signal a graceful Stop.
+	stopCtx, stop := context.WithCancel(ctx)
+	runningOp.Stop = stop
+
+	// cancelCtx is used to cancel the operation immediately, usually
+	// indicating that the process is exiting.
+	cancelCtx, cancel := context.WithCancel(context.Background())
+	runningOp.Cancel = cancel
+
+	// Do it.
+	go func() {
+		defer done()
+		defer stop()
+		defer cancel()
+
+		defer b.opLock.Unlock()
+
+		r, opErr := f(stopCtx, cancelCtx, op, w)
+		if opErr != nil && opErr != context.Canceled {
+			var diags tfdiags.Diagnostics
+			diags = diags.Append(opErr)
+			op.ReportResult(runningOp, diags)
+			return
+		}
+
+		if r == nil && opErr == context.Canceled {
+			runningOp.Result = backend.OperationFailure
+			return
+		}
+
+		if r != nil {
+			// Retrieve the run to get its current status.
+			r, err := b.client.Runs.Read(cancelCtx, r.ID)
+			if err != nil {
+				var diags tfdiags.Diagnostics
+				diags = diags.Append(generalError("Failed to retrieve run", err))
+				op.ReportResult(runningOp, diags)
+				return
+			}
+
+			// Record if there are any changes.
+			runningOp.PlanEmpty = !r.HasChanges
+
+			if opErr == context.Canceled {
+				if err := b.cancel(cancelCtx, op, r); err != nil {
+					var diags tfdiags.Diagnostics
+					diags = diags.Append(generalError("Failed to retrieve run", err))
+					op.ReportResult(runningOp, diags)
+					return
+				}
+			}
+
+			if r.Status == tfe.RunCanceled || r.Status == tfe.RunErrored {
+				runningOp.Result = backend.OperationFailure
+			}
+		}
+	}()
+
+	// Return the running operation.
+	return runningOp, nil
+}
+
+func (b *Cloud) cancel(cancelCtx context.Context, op *backend.Operation, r *tfe.Run) error {
+	if r.Actions.IsCancelable {
+		// Only ask if the remote operation should be canceled
+		// if the auto approve flag is not set.
+		if !op.AutoApprove {
+			v, err := op.UIIn.Input(cancelCtx, &terraform.InputOpts{
+				Id:          "cancel",
+				Query:       "\nDo you want to cancel the remote operation?",
+				Description: "Only 'yes' will be accepted to cancel.",
+			})
+			if err != nil {
+				return generalError("Failed asking to cancel", err)
+			}
+			if v != "yes" {
+				if b.CLI != nil {
+					b.CLI.Output(b.Colorize().Color(strings.TrimSpace(operationNotCanceled)))
+				}
+				return nil
+			}
+		} else {
+			if b.CLI != nil {
+				// Insert a blank line to separate the ouputs.
+				b.CLI.Output("")
+			}
+		}
+
+		// Try to cancel the remote operation.
+		err := b.client.Runs.Cancel(cancelCtx, r.ID, tfe.RunCancelOptions{})
+		if err != nil {
+			return generalError("Failed to cancel run", err)
+		}
+		if b.CLI != nil {
+			b.CLI.Output(b.Colorize().Color(strings.TrimSpace(operationCanceled)))
+		}
+	}
+
+	return nil
+}
+
+// IgnoreVersionConflict allows commands to disable the fall-back check that
+// the local Terraform version matches the remote workspace's configured
+// Terraform version. This should be called by commands where this check is
+// unnecessary, such as those performing remote operations, or read-only
+// operations. It will also be called if the user uses a command-line flag to
+// override this check.
+func (b *Cloud) IgnoreVersionConflict() {
+	b.ignoreVersionConflict = true
+}
+
+// VerifyWorkspaceTerraformVersion compares the local Terraform version against
+// the workspace's configured Terraform version. If they are compatible, this
+// means that there are no state compatibility concerns, so it returns no
+// diagnostics.
+//
+// If the versions aren't compatible, it returns an error (or, if
+// b.ignoreVersionConflict is set, a warning).
+func (b *Cloud) VerifyWorkspaceTerraformVersion(workspaceName string) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	workspace, err := b.getRemoteWorkspace(context.Background(), workspaceName)
+	if err != nil {
+		// If the workspace doesn't exist, there can be no compatibility
+		// problem, so we can return. This is most likely to happen when
+		// migrating state from a local backend to a new workspace.
+		if err == tfe.ErrResourceNotFound {
+			return nil
+		}
+
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Error looking up workspace",
+			fmt.Sprintf("Workspace read failed: %s", err),
+		))
+		return diags
+	}
+
+	// If the workspace has the pseudo-version "latest", all bets are off. We
+	// cannot reasonably determine what the intended Terraform version is, so
+	// we'll skip version verification.
+	if workspace.TerraformVersion == "latest" {
+		return nil
+	}
+
+	// If the workspace has execution-mode set to local, the remote Terraform
+	// version is effectively meaningless, so we'll skip version verification.
+	if isLocalExecutionMode(workspace.ExecutionMode) {
+		return nil
+	}
+
+	remoteConstraint, err := version.NewConstraint(workspace.TerraformVersion)
+	if err != nil {
+		message := fmt.Sprintf(
+			"The remote workspace specified an invalid Terraform version or constraint (%s), "+
+				"and it isn't possible to determine whether the local Terraform version (%s) is compatible.",
+			workspace.TerraformVersion,
+			tfversion.String(),
+		)
+		diags = diags.Append(incompatibleWorkspaceTerraformVersion(message, b.ignoreVersionConflict))
+		return diags
+	}
+
+	remoteVersion, _ := version.NewSemver(workspace.TerraformVersion)
+
+	// We can use a looser version constraint if the workspace specifies a
+	// literal Terraform version, and it is not a prerelease. The latter
+	// restriction is because we cannot compare prerelease versions with any
+	// operator other than simple equality.
+	if remoteVersion != nil && remoteVersion.Prerelease() == "" {
+		v014 := version.Must(version.NewSemver("0.14.0"))
+		v130 := version.Must(version.NewSemver("1.3.0"))
+
+		// Versions from 0.14 through the early 1.x series should be compatible
+		// (though we don't know about 1.3 yet).
+		if remoteVersion.GreaterThanOrEqual(v014) && remoteVersion.LessThan(v130) {
+			early1xCompatible, err := version.NewConstraint(fmt.Sprintf(">= 0.14.0, < %s", v130.String()))
+			if err != nil {
+				panic(err)
+			}
+			remoteConstraint = early1xCompatible
+		}
+
+		// Any future new state format will require at least a minor version
+		// increment, so x.y.* will always be compatible with each other.
+		if remoteVersion.GreaterThanOrEqual(v130) {
+			rwvs := remoteVersion.Segments64()
+			if len(rwvs) >= 3 {
+				// ~> x.y.0
+				minorVersionCompatible, err := version.NewConstraint(fmt.Sprintf("~> %d.%d.0", rwvs[0], rwvs[1]))
+				if err != nil {
+					panic(err)
+				}
+				remoteConstraint = minorVersionCompatible
+			}
+		}
+	}
+
+	// Re-parsing tfversion.String because tfversion.SemVer omits the prerelease
+	// prefix, and we want to allow constraints like `~> 1.2.0-beta1`.
+	fullTfversion := version.Must(version.NewSemver(tfversion.String()))
+
+	if remoteConstraint.Check(fullTfversion) {
+		return diags
+	}
+
+	message := fmt.Sprintf(
+		"The local Terraform version (%s) does not meet the version requirements for remote workspace %s/%s (%s).",
+		tfversion.String(),
+		b.organization,
+		workspace.Name,
+		remoteConstraint,
+	)
+	diags = diags.Append(incompatibleWorkspaceTerraformVersion(message, b.ignoreVersionConflict))
+	return diags
+}
+
+func (b *Cloud) IsLocalOperations() bool {
+	return b.forceLocal
+}
+
+// Colorize returns the Colorize structure that can be used for colorizing
+// output. This is guaranteed to always return a non-nil value and so useful
+// as a helper to wrap any potentially colored strings.
+//
+// TODO SvH: Rename this back to Colorize as soon as we can pass -no-color.
+//
+//lint:ignore U1000 see above todo
+func (b *Cloud) cliColorize() *colorstring.Colorize {
+	if b.CLIColor != nil {
+		return b.CLIColor
+	}
+
+	return &colorstring.Colorize{
+		Colors:  colorstring.DefaultColors,
+		Disable: true,
+	}
+}
+
+func (b *Cloud) workspaceTagsRequireUpdate(workspace *tfe.Workspace, workspaceMapping WorkspaceMapping) bool {
+	if workspaceMapping.Strategy() != WorkspaceTagsStrategy {
+		return false
+	}
+
+	existingTags := map[string]struct{}{}
+	for _, t := range workspace.TagNames {
+		existingTags[t] = struct{}{}
+	}
+
+	for _, tag := range workspaceMapping.Tags {
+		if _, ok := existingTags[tag]; !ok {
+			return true
+		}
+	}
+
+	return false
+}
+
+type WorkspaceMapping struct {
+	Name string
+	Tags []string
+}
+
+type workspaceStrategy string
+
+const (
+	WorkspaceTagsStrategy    workspaceStrategy = "tags"
+	WorkspaceNameStrategy    workspaceStrategy = "name"
+	WorkspaceNoneStrategy    workspaceStrategy = "none"
+	WorkspaceInvalidStrategy workspaceStrategy = "invalid"
+)
+
+func (wm WorkspaceMapping) Strategy() workspaceStrategy {
+	switch {
+	case len(wm.Tags) > 0 && wm.Name == "":
+		return WorkspaceTagsStrategy
+	case len(wm.Tags) == 0 && wm.Name != "":
+		return WorkspaceNameStrategy
+	case len(wm.Tags) == 0 && wm.Name == "":
+		return WorkspaceNoneStrategy
+	default:
+		// Any other combination is invalid as each strategy is mutually exclusive
+		return WorkspaceInvalidStrategy
+	}
+}
+
+func isLocalExecutionMode(execMode string) bool {
+	return execMode == "local"
+}
+
+func (b *Cloud) fetchWorkspace(ctx context.Context, organization string, workspace string) (*tfe.Workspace, error) {
+	// Retrieve the workspace for this operation.
+	w, err := b.client.Workspaces.Read(ctx, organization, workspace)
+	if err != nil {
+		switch err {
+		case context.Canceled:
+			return nil, err
+		case tfe.ErrResourceNotFound:
+			return nil, fmt.Errorf(
+				"workspace %s not found\n\n"+
+					"For security, Terraform Cloud returns '404 Not Found' responses for resources\n"+
+					"for resources that a user doesn't have access to, in addition to resources that\n"+
+					"do not exist. If the resource does exist, please check the permissions of the provided token.",
+				workspace,
+			)
+		default:
+			err := fmt.Errorf(
+				"Terraform Cloud returned an unexpected error:\n\n%s",
+				err,
+			)
+			return nil, err
+		}
+	}
+
+	return w, nil
+}
+
+// validWorkspaceEnvVar ensures we have selected a valid workspace using TF_WORKSPACE:
+// First, it ensures the workspace specified by TF_WORKSPACE exists in the organization
+// Second, if tags are specified in the configuration, it ensures TF_WORKSPACE belongs to the set
+// of available workspaces with those given tags.
+func (b *Cloud) validWorkspaceEnvVar(ctx context.Context, organization, workspace string) tfdiags.Diagnostic {
+	// first ensure the workspace exists
+	_, err := b.client.Workspaces.Read(ctx, organization, workspace)
+	if err != nil && err != tfe.ErrResourceNotFound {
+		return tfdiags.Sourceless(
+			tfdiags.Error,
+			"Terraform Cloud returned an unexpected error",
+			err.Error(),
+		)
+	}
+
+	if err == tfe.ErrResourceNotFound {
+		return tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid workspace selection",
+			fmt.Sprintf(`Terraform failed to find workspace %q in organization %s.`, workspace, organization),
+		)
+	}
+
+	// if the configuration has specified tags, we need to ensure TF_WORKSPACE
+	// is a valid member
+	if b.WorkspaceMapping.Strategy() == WorkspaceTagsStrategy {
+		opts := &tfe.WorkspaceListOptions{}
+		opts.Tags = strings.Join(b.WorkspaceMapping.Tags, ",")
+
+		for {
+			wl, err := b.client.Workspaces.List(ctx, b.organization, opts)
+			if err != nil {
+				return tfdiags.Sourceless(
+					tfdiags.Error,
+					"Terraform Cloud returned an unexpected error",
+					err.Error(),
+				)
+			}
+
+			for _, ws := range wl.Items {
+				if ws.Name == workspace {
+					return nil
+				}
+			}
+
+			if wl.CurrentPage >= wl.TotalPages {
+				break
+			}
+
+			opts.PageNumber = wl.NextPage
+		}
+
+		return tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid workspace selection",
+			fmt.Sprintf(
+				"Terraform failed to find workspace %q with the tags specified in your configuration:\n[%s]",
+				workspace,
+				strings.ReplaceAll(opts.Tags, ",", ", "),
+			),
+		)
+	}
+
+	return nil
+}
+
+func (wm WorkspaceMapping) tfeTags() []*tfe.Tag {
+	var tags []*tfe.Tag
+
+	if wm.Strategy() != WorkspaceTagsStrategy {
+		return tags
+	}
+
+	for _, tag := range wm.Tags {
+		t := tfe.Tag{Name: tag}
+		tags = append(tags, &t)
+	}
+
+	return tags
+}
+
+func generalError(msg string, err error) error {
+	var diags tfdiags.Diagnostics
+
+	if urlErr, ok := err.(*url.Error); ok {
+		err = urlErr.Err
+	}
+
+	switch err {
+	case context.Canceled:
+		return err
+	case tfe.ErrResourceNotFound:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			fmt.Sprintf("%s: %v", msg, err),
+			"For security, Terraform Cloud returns '404 Not Found' responses for resources\n"+
+				"for resources that a user doesn't have access to, in addition to resources that\n"+
+				"do not exist. If the resource does exist, please check the permissions of the provided token.",
+		))
+		return diags.Err()
+	default:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			fmt.Sprintf("%s: %v", msg, err),
+			`Terraform Cloud returned an unexpected error. Sometimes `+
+				`this is caused by network connection problems, in which case you could retry `+
+				`the command. If the issue persists please open a support ticket to get help `+
+				`resolving the problem.`,
+		))
+		return diags.Err()
+	}
+}
+
+// The newline in this error is to make it look good in the CLI!
+const initialRetryError = `
+[reset][yellow]There was an error connecting to Terraform Cloud. Please do not exit
+Terraform to prevent data loss! Trying to restore the connection...
+[reset]
+`
+
+const repeatedRetryError = `
+[reset][yellow]Still trying to restore the connection... (%s elapsed)[reset]
+`
+
+const operationCanceled = `
+[reset][red]The remote operation was successfully cancelled.[reset]
+`
+
+const operationNotCanceled = `
+[reset][red]The remote operation was not cancelled.[reset]
+`
+
+const refreshToApplyRefresh = `[bold][yellow]Proceeding with 'terraform apply -refresh-only -auto-approve'.[reset]`
+
+const unavailableTerraformVersion = `
+[reset][yellow]The local Terraform version (%s) is not available in Terraform Cloud, or your
+organization does not have access to it. The new workspace will use %s. You can
+change this later in the workspace settings.[reset]`
+
+const cloudIntegrationUsedInUnsupportedTFE = `
+This version of Terraform Cloud/Enterprise does not support the state mechanism
+attempting to be used by the platform. This should never happen.
+
+Please reach out to HashiCorp Support to resolve this issue.`
+
+var (
+	workspaceConfigurationHelp = fmt.Sprintf(
+		`The 'workspaces' block configures how Terraform CLI maps its workspaces for this single
+configuration to workspaces within a Terraform Cloud organization. Two strategies are available:
+
+[bold]tags[reset] - %s
+
+[bold]name[reset] - %s`, schemaDescriptionTags, schemaDescriptionName)
+
+	schemaDescriptionHostname = `The Terraform Enterprise hostname to connect to. This optional argument defaults to app.terraform.io
+for use with Terraform Cloud.`
+
+	schemaDescriptionOrganization = `The name of the organization containing the targeted workspace(s).`
+
+	schemaDescriptionToken = `The token used to authenticate with Terraform Cloud/Enterprise. Typically this argument should not
+be set, and 'terraform login' used instead; your credentials will then be fetched from your CLI
+configuration file or configured credential helper.`
+
+	schemaDescriptionTags = `A set of tags used to select remote Terraform Cloud workspaces to be used for this single
+configuration. New workspaces will automatically be tagged with these tag values. Generally, this
+is the primary and recommended strategy to use.  This option conflicts with "name".`
+
+	schemaDescriptionName = `The name of a single Terraform Cloud workspace to be used with this configuration.
+When configured, only the specified workspace can be used. This option conflicts with "tags".`
+)
diff --git a/v1.5.7/internal/cloud/backend_apply.go b/v1.5.7/internal/cloud/backend_apply.go
new file mode 100644
index 0000000..4813d38
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_apply.go
@@ -0,0 +1,231 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"bufio"
+	"context"
+	"encoding/json"
+	"io"
+	"log"
+
+	tfe "github.com/hashicorp/go-tfe"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/jsonformat"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func (b *Cloud) opApply(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
+	log.Printf("[INFO] cloud: starting Apply operation")
+
+	var diags tfdiags.Diagnostics
+
+	// We should remove the `CanUpdate` part of this test, but for now
+	// (to remain compatible with tfe.v2.1) we'll leave it in here.
+	if !w.Permissions.CanUpdate && !w.Permissions.CanQueueApply {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Insufficient rights to apply changes",
+			"The provided credentials have insufficient rights to apply changes. In order "+
+				"to apply changes at least write permissions on the workspace are required.",
+		))
+		return nil, diags.Err()
+	}
+
+	if w.VCSRepo != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Apply not allowed for workspaces with a VCS connection",
+			"A workspace that is connected to a VCS requires the VCS-driven workflow "+
+				"to ensure that the VCS remains the single source of truth.",
+		))
+		return nil, diags.Err()
+	}
+
+	if b.ContextOpts != nil && b.ContextOpts.Parallelism != defaultParallelism {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Custom parallelism values are currently not supported",
+			`Terraform Cloud does not support setting a custom parallelism `+
+				`value at this time.`,
+		))
+	}
+
+	if op.PlanFile != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Applying a saved plan is currently not supported",
+			`Terraform Cloud currently requires configuration to be present and `+
+				`does not accept an existing saved plan as an argument at this time.`,
+		))
+	}
+
+	if !op.HasConfig() && op.PlanMode != plans.DestroyMode {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"No configuration files found",
+			`Apply requires configuration to be present. Applying without a configuration `+
+				`would mark everything for destruction, which is normally not what is desired. `+
+				`If you would like to destroy everything, please run 'terraform destroy' which `+
+				`does not require any configuration files.`,
+		))
+	}
+
+	// Return if there are any errors.
+	if diags.HasErrors() {
+		return nil, diags.Err()
+	}
+
+	// Run the plan phase.
+	r, err := b.plan(stopCtx, cancelCtx, op, w)
+	if err != nil {
+		return r, err
+	}
+
+	// This check is also performed in the plan method to determine if
+	// the policies should be checked, but we need to check the values
+	// here again to determine if we are done and should return.
+	if !r.HasChanges || r.Status == tfe.RunCanceled || r.Status == tfe.RunErrored {
+		return r, nil
+	}
+
+	// Retrieve the run to get its current status.
+	r, err = b.client.Runs.Read(stopCtx, r.ID)
+	if err != nil {
+		return r, generalError("Failed to retrieve run", err)
+	}
+
+	// Return if the run cannot be confirmed.
+	if !op.AutoApprove && !r.Actions.IsConfirmable {
+		return r, nil
+	}
+
+	mustConfirm := (op.UIIn != nil && op.UIOut != nil) && !op.AutoApprove
+
+	if mustConfirm && b.input {
+		opts := &terraform.InputOpts{Id: "approve"}
+
+		if op.PlanMode == plans.DestroyMode {
+			opts.Query = "\nDo you really want to destroy all resources in workspace \"" + op.Workspace + "\"?"
+			opts.Description = "Terraform will destroy all your managed infrastructure, as shown above.\n" +
+				"There is no undo. Only 'yes' will be accepted to confirm."
+		} else {
+			opts.Query = "\nDo you want to perform these actions in workspace \"" + op.Workspace + "\"?"
+			opts.Description = "Terraform will perform the actions described above.\n" +
+				"Only 'yes' will be accepted to approve."
+		}
+
+		err = b.confirm(stopCtx, op, opts, r, "yes")
+		if err != nil && err != errRunApproved {
+			return r, err
+		}
+	} else if mustConfirm && !b.input {
+		return r, errApplyNeedsUIConfirmation
+	} else {
+		// If we don't need to ask for confirmation, insert a blank
+		// line to separate the ouputs.
+		if b.CLI != nil {
+			b.CLI.Output("")
+		}
+	}
+
+	if !op.AutoApprove && err != errRunApproved {
+		if err = b.client.Runs.Apply(stopCtx, r.ID, tfe.RunApplyOptions{}); err != nil {
+			return r, generalError("Failed to approve the apply command", err)
+		}
+	}
+
+	// Retrieve the run to get task stages.
+	// Task Stages are calculated upfront so we only need to call this once for the run.
+	taskStages, err := b.runTaskStages(stopCtx, b.client, r.ID)
+	if err != nil {
+		return r, err
+	}
+
+	if stage, ok := taskStages[tfe.PreApply]; ok {
+		if err := b.waitTaskStage(stopCtx, cancelCtx, op, r, stage.ID, "Pre-apply Tasks"); err != nil {
+			return r, err
+		}
+	}
+
+	r, err = b.waitForRun(stopCtx, cancelCtx, op, "apply", r, w)
+	if err != nil {
+		return r, err
+	}
+
+	err = b.renderApplyLogs(stopCtx, r)
+	if err != nil {
+		return r, err
+	}
+
+	return r, nil
+}
+
+func (b *Cloud) renderApplyLogs(ctx context.Context, run *tfe.Run) error {
+	logs, err := b.client.Applies.Logs(ctx, run.Apply.ID)
+	if err != nil {
+		return err
+	}
+
+	if b.CLI != nil {
+		reader := bufio.NewReaderSize(logs, 64*1024)
+		skip := 0
+
+		for next := true; next; {
+			var l, line []byte
+			var err error
+
+			for isPrefix := true; isPrefix; {
+				l, isPrefix, err = reader.ReadLine()
+				if err != nil {
+					if err != io.EOF {
+						return generalError("Failed to read logs", err)
+					}
+					next = false
+				}
+
+				line = append(line, l...)
+			}
+
+			// Apply logs show the same Terraform info logs as shown in the plan logs
+			// (which contain version and os/arch information), we therefore skip to prevent duplicate output.
+			if skip < 3 {
+				skip++
+				continue
+			}
+
+			if next || len(line) > 0 {
+				log := &jsonformat.JSONLog{}
+				if err := json.Unmarshal(line, log); err != nil {
+					// If we can not parse the line as JSON, we will simply
+					// print the line. This maintains backwards compatibility for
+					// users who do not wish to enable structured output in their
+					// workspace.
+					b.CLI.Output(string(line))
+					continue
+				}
+
+				if b.renderer != nil {
+					// Otherwise, we will print the log
+					err := b.renderer.RenderLog(log)
+					if err != nil {
+						return err
+					}
+				}
+			}
+		}
+	}
+
+	return nil
+}
+
+const applyDefaultHeader = `
+[reset][yellow]Running apply in Terraform Cloud. Output will stream here. Pressing Ctrl-C
+will cancel the remote apply if it's still pending. If the apply started it
+will stop streaming the logs, but will not stop the apply running remotely.[reset]
+
+Preparing the remote apply...
+`
diff --git a/v1.5.7/internal/cloud/backend_apply_test.go b/v1.5.7/internal/cloud/backend_apply_test.go
new file mode 100644
index 0000000..cf0022e
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_apply_test.go
@@ -0,0 +1,1901 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"context"
+	"fmt"
+	"os"
+	"os/signal"
+	"strings"
+	"syscall"
+	"testing"
+	"time"
+
+	gomock "github.com/golang/mock/gomock"
+	"github.com/google/go-cmp/cmp"
+	tfe "github.com/hashicorp/go-tfe"
+	mocks "github.com/hashicorp/go-tfe/mocks"
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/jsonformat"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+	tfversion "github.com/hashicorp/terraform/version"
+	"github.com/mitchellh/cli"
+)
+
+func testOperationApply(t *testing.T, configDir string) (*backend.Operation, func(), func(*testing.T) *terminal.TestOutput) {
+	t.Helper()
+
+	return testOperationApplyWithTimeout(t, configDir, 0)
+}
+
+func testOperationApplyWithTimeout(t *testing.T, configDir string, timeout time.Duration) (*backend.Operation, func(), func(*testing.T) *terminal.TestOutput) {
+	t.Helper()
+
+	_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewView(streams)
+	stateLockerView := views.NewStateLocker(arguments.ViewHuman, view)
+	operationView := views.NewOperation(arguments.ViewHuman, false, view)
+
+	// Many of our tests use an overridden "null" provider that's just in-memory
+	// inside the test process, not a separate plugin on disk.
+	depLocks := depsfile.NewLocks()
+	depLocks.SetProviderOverridden(addrs.MustParseProviderSourceString("registry.terraform.io/hashicorp/null"))
+
+	return &backend.Operation{
+		ConfigDir:       configDir,
+		ConfigLoader:    configLoader,
+		PlanRefresh:     true,
+		StateLocker:     clistate.NewLocker(timeout, stateLockerView),
+		Type:            backend.OperationTypeApply,
+		View:            operationView,
+		DependencyLocks: depLocks,
+	}, configCleanup, done
+}
+
+func TestCloud_applyBasic(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+
+	stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
+	// An error suggests that the state was not unlocked after apply
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after apply: %s", err.Error())
+	}
+}
+
+func TestCloud_applyJSONBasic(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	stream, close := terminal.StreamsForTesting(t)
+
+	b.renderer = &jsonformat.Renderer{
+		Streams:  stream,
+		Colorize: mockColorize(),
+	}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-json")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	mockSROWorkspace(t, b, op.Workspace)
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	outp := close(t)
+	gotOut := outp.Stdout()
+
+	if !strings.Contains(gotOut, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", gotOut)
+	}
+	if !strings.Contains(gotOut, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summary in output: %s", gotOut)
+	}
+
+	stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
+	// An error suggests that the state was not unlocked after apply
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after apply: %s", err.Error())
+	}
+}
+
+func TestCloud_applyJSONWithOutputs(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	stream, close := terminal.StreamsForTesting(t)
+
+	b.renderer = &jsonformat.Renderer{
+		Streams:  stream,
+		Colorize: mockColorize(),
+	}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-json-with-outputs")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	mockSROWorkspace(t, b, op.Workspace)
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	outp := close(t)
+	gotOut := outp.Stdout()
+	expectedSimpleOutput := `simple = [
+        "some",
+        "list",
+    ]`
+	expectedSensitiveOutput := `secret = (sensitive value)`
+	expectedComplexOutput := `complex = {
+        keyA = {
+            someList = [
+                1,
+                2,
+                3,
+            ]
+        }
+        keyB = {
+            someBool = true
+            someStr  = "hello"
+        }
+    }`
+
+	if !strings.Contains(gotOut, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", gotOut)
+	}
+	if !strings.Contains(gotOut, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summary in output: %s", gotOut)
+	}
+	if !strings.Contains(gotOut, "Outputs:") {
+		t.Fatalf("expected output header: %s", gotOut)
+	}
+	if !strings.Contains(gotOut, expectedSimpleOutput) {
+		t.Fatalf("expected output: %s, got: %s", expectedSimpleOutput, gotOut)
+	}
+	if !strings.Contains(gotOut, expectedSensitiveOutput) {
+		t.Fatalf("expected output: %s, got: %s", expectedSensitiveOutput, gotOut)
+	}
+	if !strings.Contains(gotOut, expectedComplexOutput) {
+		t.Fatalf("expected output: %s, got: %s", expectedComplexOutput, gotOut)
+	}
+	stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
+	// An error suggests that the state was not unlocked after apply
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after apply: %s", err.Error())
+	}
+}
+
+func TestCloud_applyCanceled(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	// Stop the run to simulate a Ctrl-C.
+	run.Stop()
+
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+
+	stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after cancelling apply: %s", err.Error())
+	}
+}
+
+func TestCloud_applyWithoutPermissions(t *testing.T) {
+	b, bCleanup := testBackendWithTags(t)
+	defer bCleanup()
+
+	// Create a named workspace without permissions.
+	w, err := b.client.Workspaces.Create(
+		context.Background(),
+		b.organization,
+		tfe.WorkspaceCreateOptions{
+			Name: tfe.String("prod"),
+		},
+	)
+	if err != nil {
+		t.Fatalf("error creating named workspace: %v", err)
+	}
+	w.Permissions.CanQueueApply = false
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+
+	op.UIOut = b.CLI
+	op.Workspace = "prod"
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "Insufficient rights to apply changes") {
+		t.Fatalf("expected a permissions error, got: %v", errOutput)
+	}
+}
+
+func TestCloud_applyWithVCS(t *testing.T) {
+	b, bCleanup := testBackendWithTags(t)
+	defer bCleanup()
+
+	// Create a named workspace with a VCS.
+	_, err := b.client.Workspaces.Create(
+		context.Background(),
+		b.organization,
+		tfe.WorkspaceCreateOptions{
+			Name:    tfe.String("prod"),
+			VCSRepo: &tfe.VCSRepoOptions{},
+		},
+	)
+	if err != nil {
+		t.Fatalf("error creating named workspace: %v", err)
+	}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+
+	op.Workspace = "prod"
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "not allowed for workspaces with a VCS") {
+		t.Fatalf("expected a VCS error, got: %v", errOutput)
+	}
+}
+
+func TestCloud_applyWithParallelism(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+
+	if b.ContextOpts == nil {
+		b.ContextOpts = &terraform.ContextOpts{}
+	}
+	b.ContextOpts.Parallelism = 3
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "parallelism values are currently not supported") {
+		t.Fatalf("expected a parallelism error, got: %v", errOutput)
+	}
+}
+
+func TestCloud_applyWithPlan(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+
+	op.PlanFile = &planfile.Reader{}
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "saved plan is currently not supported") {
+		t.Fatalf("expected a saved plan error, got: %v", errOutput)
+	}
+}
+
+func TestCloud_applyWithoutRefresh(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	op.PlanRefresh = false
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected plan to be non-empty")
+	}
+
+	// We should find a run inside the mock client that has refresh set
+	// to false.
+	runsAPI := b.client.Runs.(*MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff(false, run.Refresh); diff != "" {
+			t.Errorf("wrong Refresh setting in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestCloud_applyWithRefreshOnly(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	op.PlanMode = plans.RefreshOnlyMode
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected plan to be non-empty")
+	}
+
+	// We should find a run inside the mock client that has refresh-only set
+	// to true.
+	runsAPI := b.client.Runs.(*MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff(true, run.RefreshOnly); diff != "" {
+			t.Errorf("wrong RefreshOnly setting in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestCloud_applyWithTarget(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	addr, _ := addrs.ParseAbsResourceStr("null_resource.foo")
+
+	op.Targets = []addrs.Targetable{addr}
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatal("expected apply operation to succeed")
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected plan to be non-empty")
+	}
+
+	// We should find a run inside the mock client that has the same
+	// target address we requested above.
+	runsAPI := b.client.Runs.(*MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff([]string{"null_resource.foo"}, run.TargetAddrs); diff != "" {
+			t.Errorf("wrong TargetAddrs in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestCloud_applyWithReplace(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	addr, _ := addrs.ParseAbsResourceInstanceStr("null_resource.foo")
+
+	op.ForceReplace = []addrs.AbsResourceInstance{addr}
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatal("expected plan operation to succeed")
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected plan to be non-empty")
+	}
+
+	// We should find a run inside the mock client that has the same
+	// refresh address we requested above.
+	runsAPI := b.client.Runs.(*MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff([]string{"null_resource.foo"}, run.ReplaceAddrs); diff != "" {
+			t.Errorf("wrong ReplaceAddrs in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestCloud_applyWithRequiredVariables(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-variables")
+	defer configCleanup()
+	defer done(t)
+
+	op.Variables = testVariables(terraform.ValueFromNamedFile, "foo") // "bar" variable value missing
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	// The usual error of a required variable being missing is deferred and the operation
+	// is successful
+	if run.Result != backend.OperationSuccess {
+		t.Fatal("expected plan operation to succeed")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in Terraform Cloud") {
+		t.Fatalf("unexpected TFC header in output: %s", output)
+	}
+}
+
+func TestCloud_applyNoConfig(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/empty")
+	defer configCleanup()
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "configuration files found") {
+		t.Fatalf("expected configuration files error, got: %v", errOutput)
+	}
+
+	stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
+	// An error suggests that the state was not unlocked after apply
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after failed apply: %s", err.Error())
+	}
+}
+
+func TestCloud_applyNoChanges(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-no-changes")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "No changes. Infrastructure is up-to-date.") {
+		t.Fatalf("expected no changes in plan summery: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: true") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+}
+
+func TestCloud_applyNoApprove(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+
+	input := testInput(t, map[string]string{
+		"approve": "no",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "Apply discarded") {
+		t.Fatalf("expected an apply discarded error, got: %v", errOutput)
+	}
+}
+
+func TestCloud_applyAutoApprove(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+	ctrl := gomock.NewController(t)
+
+	applyMock := mocks.NewMockApplies(ctrl)
+	// This needs three new lines because we check for a minimum of three lines
+	// in the parsing of logs in `opApply` function.
+	logs := strings.NewReader(applySuccessOneResourceAdded)
+	applyMock.EXPECT().Logs(gomock.Any(), gomock.Any()).Return(logs, nil)
+	b.client.Applies = applyMock
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "no",
+	})
+
+	op.AutoApprove = true
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) != 1 {
+		t.Fatalf("expected an unused answer, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+}
+
+func TestCloud_applyApprovedExternally(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "wait-for-external-update",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	ctx := context.Background()
+
+	run, err := b.Operation(ctx, op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	// Wait 50 milliseconds to make sure the run started.
+	time.Sleep(50 * time.Millisecond)
+
+	wl, err := b.client.Workspaces.List(
+		ctx,
+		b.organization,
+		nil,
+	)
+	if err != nil {
+		t.Fatalf("unexpected error listing workspaces: %v", err)
+	}
+	if len(wl.Items) != 1 {
+		t.Fatalf("expected 1 workspace, got %d workspaces", len(wl.Items))
+	}
+
+	rl, err := b.client.Runs.List(ctx, wl.Items[0].ID, nil)
+	if err != nil {
+		t.Fatalf("unexpected error listing runs: %v", err)
+	}
+	if len(rl.Items) != 1 {
+		t.Fatalf("expected 1 run, got %d runs", len(rl.Items))
+	}
+
+	err = b.client.Runs.Apply(context.Background(), rl.Items[0].ID, tfe.RunApplyOptions{})
+	if err != nil {
+		t.Fatalf("unexpected error approving run: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "approved using the UI or API") {
+		t.Fatalf("expected external approval in output: %s", output)
+	}
+	if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+}
+
+func TestCloud_applyDiscardedExternally(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "wait-for-external-update",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	ctx := context.Background()
+
+	run, err := b.Operation(ctx, op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	// Wait 50 milliseconds to make sure the run started.
+	time.Sleep(50 * time.Millisecond)
+
+	wl, err := b.client.Workspaces.List(
+		ctx,
+		b.organization,
+		nil,
+	)
+	if err != nil {
+		t.Fatalf("unexpected error listing workspaces: %v", err)
+	}
+	if len(wl.Items) != 1 {
+		t.Fatalf("expected 1 workspace, got %d workspaces", len(wl.Items))
+	}
+
+	rl, err := b.client.Runs.List(ctx, wl.Items[0].ID, nil)
+	if err != nil {
+		t.Fatalf("unexpected error listing runs: %v", err)
+	}
+	if len(rl.Items) != 1 {
+		t.Fatalf("expected 1 run, got %d runs", len(rl.Items))
+	}
+
+	err = b.client.Runs.Discard(context.Background(), rl.Items[0].ID, tfe.RunDiscardOptions{})
+	if err != nil {
+		t.Fatalf("unexpected error discarding run: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "discarded using the UI or API") {
+		t.Fatalf("expected external discard output: %s", output)
+	}
+	if strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("unexpected apply summery in output: %s", output)
+	}
+}
+
+func TestCloud_applyWithAutoApprove(t *testing.T) {
+	b, bCleanup := testBackendWithTags(t)
+	defer bCleanup()
+	ctrl := gomock.NewController(t)
+
+	applyMock := mocks.NewMockApplies(ctrl)
+	// This needs three new lines because we check for a minimum of three lines
+	// in the parsing of logs in `opApply` function.
+	logs := strings.NewReader(applySuccessOneResourceAdded)
+	applyMock.EXPECT().Logs(gomock.Any(), gomock.Any()).Return(logs, nil)
+	b.client.Applies = applyMock
+
+	// Create a named workspace that auto applies.
+	_, err := b.client.Workspaces.Create(
+		context.Background(),
+		b.organization,
+		tfe.WorkspaceCreateOptions{
+			Name: tfe.String("prod"),
+		},
+	)
+	if err != nil {
+		t.Fatalf("error creating named workspace: %v", err)
+	}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = "prod"
+	op.AutoApprove = true
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) != 1 {
+		t.Fatalf("expected an unused answer, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+}
+
+func TestCloud_applyForceLocal(t *testing.T) {
+	// Set TF_FORCE_LOCAL_BACKEND so the cloud backend will use
+	// the local backend with itself as embedded backend.
+	if err := os.Setenv("TF_FORCE_LOCAL_BACKEND", "1"); err != nil {
+		t.Fatalf("error setting environment variable TF_FORCE_LOCAL_BACKEND: %v", err)
+	}
+	defer os.Unsetenv("TF_FORCE_LOCAL_BACKEND")
+
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams))
+	op.View = view
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if strings.Contains(output, "Running apply in Terraform Cloud") {
+		t.Fatalf("unexpected TFC header in output: %s", output)
+	}
+	if output := done(t).Stdout(); !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+	if !run.State.HasManagedResourceInstanceObjects() {
+		t.Fatalf("expected resources in state")
+	}
+}
+
+func TestCloud_applyWorkspaceWithoutOperations(t *testing.T) {
+	b, bCleanup := testBackendWithTags(t)
+	defer bCleanup()
+
+	ctx := context.Background()
+
+	// Create a named workspace that doesn't allow operations.
+	_, err := b.client.Workspaces.Create(
+		ctx,
+		b.organization,
+		tfe.WorkspaceCreateOptions{
+			Name: tfe.String("no-operations"),
+		},
+	)
+	if err != nil {
+		t.Fatalf("error creating named workspace: %v", err)
+	}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = "no-operations"
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams))
+	op.View = view
+
+	run, err := b.Operation(ctx, op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if strings.Contains(output, "Running apply in Terraform Cloud") {
+		t.Fatalf("unexpected TFC header in output: %s", output)
+	}
+	if output := done(t).Stdout(); !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+	if !run.State.HasManagedResourceInstanceObjects() {
+		t.Fatalf("expected resources in state")
+	}
+}
+
+func TestCloud_applyLockTimeout(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	ctx := context.Background()
+
+	// Retrieve the workspace used to run this operation in.
+	w, err := b.client.Workspaces.Read(ctx, b.organization, b.WorkspaceMapping.Name)
+	if err != nil {
+		t.Fatalf("error retrieving workspace: %v", err)
+	}
+
+	// Create a new configuration version.
+	c, err := b.client.ConfigurationVersions.Create(ctx, w.ID, tfe.ConfigurationVersionCreateOptions{})
+	if err != nil {
+		t.Fatalf("error creating configuration version: %v", err)
+	}
+
+	// Create a pending run to block this run.
+	_, err = b.client.Runs.Create(ctx, tfe.RunCreateOptions{
+		ConfigurationVersion: c,
+		Workspace:            w,
+	})
+	if err != nil {
+		t.Fatalf("error creating pending run: %v", err)
+	}
+
+	op, configCleanup, done := testOperationApplyWithTimeout(t, "./testdata/apply", 50*time.Millisecond)
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"cancel":  "yes",
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	_, err = b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	sigint := make(chan os.Signal, 1)
+	signal.Notify(sigint, syscall.SIGINT)
+	select {
+	case <-sigint:
+		// Stop redirecting SIGINT signals.
+		signal.Stop(sigint)
+	case <-time.After(200 * time.Millisecond):
+		t.Fatalf("expected lock timeout after 50 milliseconds, waited 200 milliseconds")
+	}
+
+	if len(input.answers) != 2 {
+		t.Fatalf("expected unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "Lock timeout exceeded") {
+		t.Fatalf("expected lock timout error in output: %s", output)
+	}
+	if strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("unexpected plan summery in output: %s", output)
+	}
+	if strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("unexpected apply summery in output: %s", output)
+	}
+}
+
+func TestCloud_applyDestroy(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-destroy")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.PlanMode = plans.DestroyMode
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "0 to add, 0 to change, 1 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "0 added, 0 changed, 1 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+}
+
+func TestCloud_applyDestroyNoConfig(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/empty")
+	defer configCleanup()
+	defer done(t)
+
+	op.PlanMode = plans.DestroyMode
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+}
+
+func TestCloud_applyJSONWithProvisioner(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	stream, close := terminal.StreamsForTesting(t)
+
+	b.renderer = &jsonformat.Renderer{
+		Streams:  stream,
+		Colorize: mockColorize(),
+	}
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-json-with-provisioner")
+	defer configCleanup()
+	defer done(t)
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	mockSROWorkspace(t, b, op.Workspace)
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	outp := close(t)
+	gotOut := outp.Stdout()
+	if !strings.Contains(gotOut, "null_resource.foo: Provisioning with 'local-exec'") {
+		t.Fatalf("expected provisioner local-exec start in logs: %s", gotOut)
+	}
+
+	if !strings.Contains(gotOut, "null_resource.foo: (local-exec):") {
+		t.Fatalf("expected provisioner local-exec progress in logs: %s", gotOut)
+	}
+
+	if !strings.Contains(gotOut, "Hello World!") {
+		t.Fatalf("expected provisioner local-exec output in logs: %s", gotOut)
+	}
+
+	stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
+	// An error suggests that the state was not unlocked after apply
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after apply: %s", err.Error())
+	}
+}
+
+func TestCloud_applyJSONWithProvisionerError(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	stream, close := terminal.StreamsForTesting(t)
+
+	b.renderer = &jsonformat.Renderer{
+		Streams:  stream,
+		Colorize: mockColorize(),
+	}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-json-with-provisioner-error")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	mockSROWorkspace(t, b, op.Workspace)
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+
+	outp := close(t)
+	gotOut := outp.Stdout()
+
+	if !strings.Contains(gotOut, "local-exec provisioner error") {
+		t.Fatalf("unexpected error in apply logs: %s", gotOut)
+	}
+}
+
+func TestCloud_applyPolicyPass(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-policy-passed")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: true") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+	if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+}
+
+func TestCloud_applyPolicyHardFail(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-policy-hard-failed")
+	defer configCleanup()
+
+	input := testInput(t, map[string]string{
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	viewOutput := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	if len(input.answers) != 1 {
+		t.Fatalf("expected an unused answers, got: %v", input.answers)
+	}
+
+	errOutput := viewOutput.Stderr()
+	if !strings.Contains(errOutput, "hard failed") {
+		t.Fatalf("expected a policy check error, got: %v", errOutput)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: false") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+	if strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("unexpected apply summery in output: %s", output)
+	}
+}
+
+func TestCloud_applyPolicySoftFail(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-policy-soft-failed")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"override": "override",
+		"approve":  "yes",
+	})
+
+	op.AutoApprove = false
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) > 0 {
+		t.Fatalf("expected no unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: false") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+	if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+}
+
+func TestCloud_applyPolicySoftFailAutoApproveSuccess(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+	ctrl := gomock.NewController(t)
+
+	policyCheckMock := mocks.NewMockPolicyChecks(ctrl)
+	// This needs three new lines because we check for a minimum of three lines
+	// in the parsing of logs in `opApply` function.
+	logs := strings.NewReader(fmt.Sprintf("%s\n%s", sentinelSoftFail, applySuccessOneResourceAdded))
+
+	pc := &tfe.PolicyCheck{
+		ID: "pc-1",
+		Actions: &tfe.PolicyActions{
+			IsOverridable: true,
+		},
+		Permissions: &tfe.PolicyPermissions{
+			CanOverride: true,
+		},
+		Scope:  tfe.PolicyScopeOrganization,
+		Status: tfe.PolicySoftFailed,
+	}
+	policyCheckMock.EXPECT().Read(gomock.Any(), gomock.Any()).Return(pc, nil)
+	policyCheckMock.EXPECT().Logs(gomock.Any(), gomock.Any()).Return(logs, nil)
+	policyCheckMock.EXPECT().Override(gomock.Any(), gomock.Any()).Return(nil, nil)
+	b.client.PolicyChecks = policyCheckMock
+	applyMock := mocks.NewMockApplies(ctrl)
+	// This needs three new lines because we check for a minimum of three lines
+	// in the parsing of logs in `opApply` function.
+	logs = strings.NewReader("\n\n\n1 added, 0 changed, 0 destroyed")
+	applyMock.EXPECT().Logs(gomock.Any(), gomock.Any()).Return(logs, nil)
+	b.client.Applies = applyMock
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-policy-soft-failed")
+	defer configCleanup()
+
+	input := testInput(t, map[string]string{})
+
+	op.AutoApprove = true
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	viewOutput := done(t)
+	if run.Result != backend.OperationSuccess {
+		t.Fatal("expected apply operation to success due to auto-approve")
+	}
+
+	if run.PlanEmpty {
+		t.Fatalf("expected plan to not be empty, plan opertion completed without error")
+	}
+
+	if len(input.answers) != 0 {
+		t.Fatalf("expected no answers, got: %v", input.answers)
+	}
+
+	errOutput := viewOutput.Stderr()
+	if strings.Contains(errOutput, "soft failed") {
+		t.Fatalf("expected no policy check errors, instead got: %v", errOutput)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Sentinel Result: false") {
+		t.Fatalf("expected policy check to be false, insead got: %s", output)
+	}
+	if !strings.Contains(output, "Apply complete!") {
+		t.Fatalf("expected apply to be complete, instead got: %s", output)
+	}
+
+	if !strings.Contains(output, "Resources: 1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected resources, instead got: %s", output)
+	}
+}
+
+func TestCloud_applyPolicySoftFailAutoApprove(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+	ctrl := gomock.NewController(t)
+
+	applyMock := mocks.NewMockApplies(ctrl)
+	// This needs three new lines because we check for a minimum of three lines
+	// in the parsing of logs in `opApply` function.
+	logs := strings.NewReader(applySuccessOneResourceAdded)
+	applyMock.EXPECT().Logs(gomock.Any(), gomock.Any()).Return(logs, nil)
+	b.client.Applies = applyMock
+
+	// Create a named workspace that auto applies.
+	_, err := b.client.Workspaces.Create(
+		context.Background(),
+		b.organization,
+		tfe.WorkspaceCreateOptions{
+			Name: tfe.String("prod"),
+		},
+	)
+	if err != nil {
+		t.Fatalf("error creating named workspace: %v", err)
+	}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-policy-soft-failed")
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"override": "override",
+		"approve":  "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = "prod"
+	op.AutoApprove = true
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	if len(input.answers) != 2 {
+		t.Fatalf("expected an unused answer, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running apply in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summery in output: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: false") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+	if !strings.Contains(output, "1 added, 0 changed, 0 destroyed") {
+		t.Fatalf("expected apply summery in output: %s", output)
+	}
+}
+
+func TestCloud_applyWithRemoteError(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-with-error")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if run.Result.ExitStatus() != 1 {
+		t.Fatalf("expected exit code 1, got %d", run.Result.ExitStatus())
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "null_resource.foo: 1 error") {
+		t.Fatalf("expected apply error in output: %s", output)
+	}
+}
+
+func TestCloud_applyJSONWithRemoteError(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	stream, close := terminal.StreamsForTesting(t)
+
+	b.renderer = &jsonformat.Renderer{
+		Streams:  stream,
+		Colorize: mockColorize(),
+	}
+
+	op, configCleanup, done := testOperationApply(t, "./testdata/apply-json-with-error")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	mockSROWorkspace(t, b, op.Workspace)
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected apply operation to fail")
+	}
+	if run.Result.ExitStatus() != 1 {
+		t.Fatalf("expected exit code 1, got %d", run.Result.ExitStatus())
+	}
+
+	outp := close(t)
+	gotOut := outp.Stdout()
+
+	if !strings.Contains(gotOut, "Unsupported block type") {
+		t.Fatalf("unexpected plan error in output: %s", gotOut)
+	}
+}
+
+func TestCloud_applyVersionCheck(t *testing.T) {
+	testCases := map[string]struct {
+		localVersion  string
+		remoteVersion string
+		forceLocal    bool
+		executionMode string
+		wantErr       string
+	}{
+		"versions can be different for remote apply": {
+			localVersion:  "0.14.0",
+			remoteVersion: "0.13.5",
+			executionMode: "remote",
+		},
+		"versions can be different for local apply": {
+			localVersion:  "0.14.0",
+			remoteVersion: "0.13.5",
+			executionMode: "local",
+		},
+		"force local with remote operations and different versions is acceptable": {
+			localVersion:  "0.14.0",
+			remoteVersion: "0.14.0-acme-provider-bundle",
+			forceLocal:    true,
+			executionMode: "remote",
+		},
+		"no error if versions are identical": {
+			localVersion:  "0.14.0",
+			remoteVersion: "0.14.0",
+			forceLocal:    true,
+			executionMode: "remote",
+		},
+		"no error if force local but workspace has remote operations disabled": {
+			localVersion:  "0.14.0",
+			remoteVersion: "0.13.5",
+			forceLocal:    true,
+			executionMode: "local",
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			b, bCleanup := testBackendWithName(t)
+			defer bCleanup()
+
+			// SETUP: Save original local version state and restore afterwards
+			p := tfversion.Prerelease
+			v := tfversion.Version
+			s := tfversion.SemVer
+			defer func() {
+				tfversion.Prerelease = p
+				tfversion.Version = v
+				tfversion.SemVer = s
+			}()
+
+			// SETUP: Set local version for the test case
+			tfversion.Prerelease = ""
+			tfversion.Version = tc.localVersion
+			tfversion.SemVer = version.Must(version.NewSemver(tc.localVersion))
+
+			// SETUP: Set force local for the test case
+			b.forceLocal = tc.forceLocal
+
+			ctx := context.Background()
+
+			// SETUP: set the operations and Terraform Version fields on the
+			// remote workspace
+			_, err := b.client.Workspaces.Update(
+				ctx,
+				b.organization,
+				b.WorkspaceMapping.Name,
+				tfe.WorkspaceUpdateOptions{
+					ExecutionMode:    tfe.String(tc.executionMode),
+					TerraformVersion: tfe.String(tc.remoteVersion),
+				},
+			)
+			if err != nil {
+				t.Fatalf("error creating named workspace: %v", err)
+			}
+
+			// RUN: prepare the apply operation and run it
+			op, configCleanup, opDone := testOperationApply(t, "./testdata/apply")
+			defer configCleanup()
+			defer opDone(t)
+
+			streams, done := terminal.StreamsForTesting(t)
+			view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams))
+			op.View = view
+
+			input := testInput(t, map[string]string{
+				"approve": "yes",
+			})
+
+			op.UIIn = input
+			op.UIOut = b.CLI
+			op.Workspace = testBackendSingleWorkspaceName
+
+			run, err := b.Operation(ctx, op)
+			if err != nil {
+				t.Fatalf("error starting operation: %v", err)
+			}
+
+			// RUN: wait for completion
+			<-run.Done()
+			output := done(t)
+
+			if tc.wantErr != "" {
+				// ASSERT: if the test case wants an error, check for failure
+				// and the error message
+				if run.Result != backend.OperationFailure {
+					t.Fatalf("expected run to fail, but result was %#v", run.Result)
+				}
+				errOutput := output.Stderr()
+				if !strings.Contains(errOutput, tc.wantErr) {
+					t.Fatalf("missing error %q\noutput: %s", tc.wantErr, errOutput)
+				}
+			} else {
+				// ASSERT: otherwise, check for success and appropriate output
+				// based on whether the run should be local or remote
+				if run.Result != backend.OperationSuccess {
+					t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+				}
+				output := b.CLI.(*cli.MockUi).OutputWriter.String()
+				hasRemote := strings.Contains(output, "Running apply in Terraform Cloud")
+				hasSummary := strings.Contains(output, "1 added, 0 changed, 0 destroyed")
+				hasResources := run.State.HasManagedResourceInstanceObjects()
+				if !tc.forceLocal && !isLocalExecutionMode(tc.executionMode) {
+					if !hasRemote {
+						t.Errorf("missing TFC header in output: %s", output)
+					}
+					if !hasSummary {
+						t.Errorf("expected apply summary in output: %s", output)
+					}
+				} else {
+					if hasRemote {
+						t.Errorf("unexpected TFC header in output: %s", output)
+					}
+					if !hasResources {
+						t.Errorf("expected resources in state")
+					}
+				}
+			}
+		})
+	}
+}
+
+const applySuccessOneResourceAdded = `
+Terraform v0.11.10
+
+Initializing plugins and modules...
+null_resource.hello: Creating...
+null_resource.hello: Creation complete after 0s (ID: 8657651096157629581)
+
+Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
+`
+
+const sentinelSoftFail = `
+Sentinel Result: false
+
+Sentinel evaluated to false because one or more Sentinel policies evaluated
+to false. This false was not due to an undefined value or runtime error.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (soft-mandatory)
+
+Result: false
+
+FALSE - Passthrough.sentinel:1:1 - Rule "main"
+`
diff --git a/v1.5.7/internal/cloud/backend_cli.go b/v1.5.7/internal/cloud/backend_cli.go
new file mode 100644
index 0000000..656eeac
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_cli.go
@@ -0,0 +1,30 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/jsonformat"
+)
+
+// CLIInit implements backend.CLI
+func (b *Cloud) CLIInit(opts *backend.CLIOpts) error {
+	if cli, ok := b.local.(backend.CLI); ok {
+		if err := cli.CLIInit(opts); err != nil {
+			return err
+		}
+	}
+
+	b.CLI = opts.CLI
+	b.CLIColor = opts.CLIColor
+	b.ContextOpts = opts.ContextOpts
+	b.runningInAutomation = opts.RunningInAutomation
+	b.input = opts.Input
+	b.renderer = &jsonformat.Renderer{
+		Streams:  opts.Streams,
+		Colorize: opts.CLIColor,
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/cloud/backend_colorize.go b/v1.5.7/internal/cloud/backend_colorize.go
new file mode 100644
index 0000000..2dcf79c
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_colorize.go
@@ -0,0 +1,53 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"regexp"
+
+	"github.com/mitchellh/colorstring"
+)
+
+// TODO SvH: This file should be deleted and the type cliColorize should be
+// renamed back to Colorize as soon as we can pass -no-color to the backend.
+
+// colorsRe is used to find ANSI escaped color codes.
+var colorsRe = regexp.MustCompile("\033\\[\\d{1,3}m")
+
+// Colorer is the interface that must be implemented to colorize strings.
+type Colorer interface {
+	Color(v string) string
+}
+
+// Colorize is used to print output when the -no-color flag is used. It will
+// strip all ANSI escaped color codes which are set while the operation was
+// executed in Terraform Enterprise.
+//
+// When Terraform Enterprise supports run specific variables, this code can be
+// removed as we can then pass the CLI flag to the backend and prevent the color
+// codes from being written to the output.
+type Colorize struct {
+	cliColor *colorstring.Colorize
+}
+
+// Color will strip all ANSI escaped color codes and return a uncolored string.
+func (c *Colorize) Color(v string) string {
+	return colorsRe.ReplaceAllString(c.cliColor.Color(v), "")
+}
+
+// Colorize returns the Colorize structure that can be used for colorizing
+// output. This is guaranteed to always return a non-nil value and so is useful
+// as a helper to wrap any potentially colored strings.
+func (b *Cloud) Colorize() Colorer {
+	if b.CLIColor != nil && !b.CLIColor.Disable {
+		return b.CLIColor
+	}
+	if b.CLIColor != nil {
+		return &Colorize{cliColor: b.CLIColor}
+	}
+	return &Colorize{cliColor: &colorstring.Colorize{
+		Colors:  colorstring.DefaultColors,
+		Disable: true,
+	}}
+}
diff --git a/v1.5.7/internal/cloud/backend_common.go b/v1.5.7/internal/cloud/backend_common.go
new file mode 100644
index 0000000..c4b4ee2
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_common.go
@@ -0,0 +1,638 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"bufio"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"math"
+	"net/http"
+	"net/url"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/hashicorp/go-retryablehttp"
+	tfe "github.com/hashicorp/go-tfe"
+	"github.com/hashicorp/jsonapi"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/jsonformat"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+var (
+	backoffMin = 1000.0
+	backoffMax = 3000.0
+
+	runPollInterval = 3 * time.Second
+)
+
+// backoff will perform exponential backoff based on the iteration and
+// limited by the provided min and max (in milliseconds) durations.
+func backoff(min, max float64, iter int) time.Duration {
+	backoff := math.Pow(2, float64(iter)/5) * min
+	if backoff > max {
+		backoff = max
+	}
+	return time.Duration(backoff) * time.Millisecond
+}
+
+func (b *Cloud) waitForRun(stopCtx, cancelCtx context.Context, op *backend.Operation, opType string, r *tfe.Run, w *tfe.Workspace) (*tfe.Run, error) {
+	started := time.Now()
+	updated := started
+	for i := 0; ; i++ {
+		select {
+		case <-stopCtx.Done():
+			return r, stopCtx.Err()
+		case <-cancelCtx.Done():
+			return r, cancelCtx.Err()
+		case <-time.After(backoff(backoffMin, backoffMax, i)):
+			// Timer up, show status
+		}
+
+		// Retrieve the run to get its current status.
+		r, err := b.client.Runs.Read(stopCtx, r.ID)
+		if err != nil {
+			return r, generalError("Failed to retrieve run", err)
+		}
+
+		// Return if the run is no longer pending.
+		if r.Status != tfe.RunPending && r.Status != tfe.RunConfirmed {
+			if i == 0 && opType == "plan" && b.CLI != nil {
+				b.CLI.Output(b.Colorize().Color(fmt.Sprintf("Waiting for the %s to start...\n", opType)))
+			}
+			if i > 0 && b.CLI != nil {
+				// Insert a blank line to separate the ouputs.
+				b.CLI.Output("")
+			}
+			return r, nil
+		}
+
+		// Check if 30 seconds have passed since the last update.
+		current := time.Now()
+		if b.CLI != nil && (i == 0 || current.Sub(updated).Seconds() > 30) {
+			updated = current
+			position := 0
+			elapsed := ""
+
+			// Calculate and set the elapsed time.
+			if i > 0 {
+				elapsed = fmt.Sprintf(
+					" (%s elapsed)", current.Sub(started).Truncate(30*time.Second))
+			}
+
+			// Retrieve the workspace used to run this operation in.
+			w, err = b.client.Workspaces.Read(stopCtx, b.organization, w.Name)
+			if err != nil {
+				return nil, generalError("Failed to retrieve workspace", err)
+			}
+
+			// If the workspace is locked the run will not be queued and we can
+			// update the status without making any expensive calls.
+			if w.Locked && w.CurrentRun != nil {
+				cr, err := b.client.Runs.Read(stopCtx, w.CurrentRun.ID)
+				if err != nil {
+					return r, generalError("Failed to retrieve current run", err)
+				}
+				if cr.Status == tfe.RunPending {
+					b.CLI.Output(b.Colorize().Color(
+						"Waiting for the manually locked workspace to be unlocked..." + elapsed))
+					continue
+				}
+			}
+
+			// Skip checking the workspace queue when we are the current run.
+			if w.CurrentRun == nil || w.CurrentRun.ID != r.ID {
+				found := false
+				options := &tfe.RunListOptions{}
+			runlist:
+				for {
+					rl, err := b.client.Runs.List(stopCtx, w.ID, options)
+					if err != nil {
+						return r, generalError("Failed to retrieve run list", err)
+					}
+
+					// Loop through all runs to calculate the workspace queue position.
+					for _, item := range rl.Items {
+						if !found {
+							if r.ID == item.ID {
+								found = true
+							}
+							continue
+						}
+
+						// If the run is in a final state, ignore it and continue.
+						switch item.Status {
+						case tfe.RunApplied, tfe.RunCanceled, tfe.RunDiscarded, tfe.RunErrored:
+							continue
+						case tfe.RunPlanned:
+							if op.Type == backend.OperationTypePlan {
+								continue
+							}
+						}
+
+						// Increase the workspace queue position.
+						position++
+
+						// Stop searching when we reached the current run.
+						if w.CurrentRun != nil && w.CurrentRun.ID == item.ID {
+							break runlist
+						}
+					}
+
+					// Exit the loop when we've seen all pages.
+					if rl.CurrentPage >= rl.TotalPages {
+						break
+					}
+
+					// Update the page number to get the next page.
+					options.PageNumber = rl.NextPage
+				}
+
+				if position > 0 {
+					b.CLI.Output(b.Colorize().Color(fmt.Sprintf(
+						"Waiting for %d run(s) to finish before being queued...%s",
+						position,
+						elapsed,
+					)))
+					continue
+				}
+			}
+
+			options := tfe.ReadRunQueueOptions{}
+		search:
+			for {
+				rq, err := b.client.Organizations.ReadRunQueue(stopCtx, b.organization, options)
+				if err != nil {
+					return r, generalError("Failed to retrieve queue", err)
+				}
+
+				// Search through all queued items to find our run.
+				for _, item := range rq.Items {
+					if r.ID == item.ID {
+						position = item.PositionInQueue
+						break search
+					}
+				}
+
+				// Exit the loop when we've seen all pages.
+				if rq.CurrentPage >= rq.TotalPages {
+					break
+				}
+
+				// Update the page number to get the next page.
+				options.PageNumber = rq.NextPage
+			}
+
+			if position > 0 {
+				c, err := b.client.Organizations.ReadCapacity(stopCtx, b.organization)
+				if err != nil {
+					return r, generalError("Failed to retrieve capacity", err)
+				}
+				b.CLI.Output(b.Colorize().Color(fmt.Sprintf(
+					"Waiting for %d queued run(s) to finish before starting...%s",
+					position-c.Running,
+					elapsed,
+				)))
+				continue
+			}
+
+			b.CLI.Output(b.Colorize().Color(fmt.Sprintf(
+				"Waiting for the %s to start...%s", opType, elapsed)))
+		}
+	}
+}
+
+func (b *Cloud) waitTaskStage(stopCtx, cancelCtx context.Context, op *backend.Operation, r *tfe.Run, stageID string, outputTitle string) error {
+	integration := &IntegrationContext{
+		B:             b,
+		StopContext:   stopCtx,
+		CancelContext: cancelCtx,
+		Op:            op,
+		Run:           r,
+	}
+	return b.runTaskStage(integration, integration.BeginOutput(outputTitle), stageID)
+}
+
+func (b *Cloud) costEstimate(stopCtx, cancelCtx context.Context, op *backend.Operation, r *tfe.Run) error {
+	if r.CostEstimate == nil {
+		return nil
+	}
+
+	msgPrefix := "Cost Estimation"
+	started := time.Now()
+	updated := started
+	for i := 0; ; i++ {
+		select {
+		case <-stopCtx.Done():
+			return stopCtx.Err()
+		case <-cancelCtx.Done():
+			return cancelCtx.Err()
+		case <-time.After(backoff(backoffMin, backoffMax, i)):
+		}
+
+		// Retrieve the cost estimate to get its current status.
+		ce, err := b.client.CostEstimates.Read(stopCtx, r.CostEstimate.ID)
+		if err != nil {
+			return generalError("Failed to retrieve cost estimate", err)
+		}
+
+		// If the run is canceled or errored, but the cost-estimate still has
+		// no result, there is nothing further to render.
+		if ce.Status != tfe.CostEstimateFinished {
+			if r.Status == tfe.RunCanceled || r.Status == tfe.RunErrored {
+				return nil
+			}
+		}
+
+		// checking if i == 0 so as to avoid printing this starting horizontal-rule
+		// every retry, and that it only prints it on the first (i=0) attempt.
+		if b.CLI != nil && i == 0 {
+			b.CLI.Output("\n------------------------------------------------------------------------\n")
+		}
+
+		switch ce.Status {
+		case tfe.CostEstimateFinished:
+			delta, err := strconv.ParseFloat(ce.DeltaMonthlyCost, 64)
+			if err != nil {
+				return generalError("Unexpected error", err)
+			}
+
+			sign := "+"
+			if delta < 0 {
+				sign = "-"
+			}
+
+			deltaRepr := strings.Replace(ce.DeltaMonthlyCost, "-", "", 1)
+
+			if b.CLI != nil {
+				b.CLI.Output(b.Colorize().Color("[bold]" + msgPrefix + ":\n"))
+				b.CLI.Output(b.Colorize().Color(fmt.Sprintf("Resources: %d of %d estimated", ce.MatchedResourcesCount, ce.ResourcesCount)))
+				b.CLI.Output(b.Colorize().Color(fmt.Sprintf("           $%s/mo %s$%s", ce.ProposedMonthlyCost, sign, deltaRepr)))
+
+				if len(r.PolicyChecks) == 0 && r.HasChanges && op.Type == backend.OperationTypeApply {
+					b.CLI.Output("\n------------------------------------------------------------------------")
+				}
+			}
+
+			return nil
+		case tfe.CostEstimatePending, tfe.CostEstimateQueued:
+			// Check if 30 seconds have passed since the last update.
+			current := time.Now()
+			if b.CLI != nil && (i == 0 || current.Sub(updated).Seconds() > 30) {
+				updated = current
+				elapsed := ""
+
+				// Calculate and set the elapsed time.
+				if i > 0 {
+					elapsed = fmt.Sprintf(
+						" (%s elapsed)", current.Sub(started).Truncate(30*time.Second))
+				}
+				b.CLI.Output(b.Colorize().Color("[bold]" + msgPrefix + ":\n"))
+				b.CLI.Output(b.Colorize().Color("Waiting for cost estimate to complete..." + elapsed + "\n"))
+			}
+			continue
+		case tfe.CostEstimateSkippedDueToTargeting:
+			b.CLI.Output(b.Colorize().Color("[bold]" + msgPrefix + ":\n"))
+			b.CLI.Output("Not available for this plan, because it was created with the -target option.")
+			b.CLI.Output("\n------------------------------------------------------------------------")
+			return nil
+		case tfe.CostEstimateErrored:
+			b.CLI.Output(msgPrefix + " errored.\n")
+			b.CLI.Output("\n------------------------------------------------------------------------")
+			return nil
+		case tfe.CostEstimateCanceled:
+			return fmt.Errorf(msgPrefix + " canceled.")
+		default:
+			return fmt.Errorf("Unknown or unexpected cost estimate state: %s", ce.Status)
+		}
+	}
+}
+
+func (b *Cloud) checkPolicy(stopCtx, cancelCtx context.Context, op *backend.Operation, r *tfe.Run) error {
+	if b.CLI != nil {
+		b.CLI.Output("\n------------------------------------------------------------------------\n")
+	}
+	for i, pc := range r.PolicyChecks {
+		// Read the policy check logs. This is a blocking call that will only
+		// return once the policy check is complete.
+		logs, err := b.client.PolicyChecks.Logs(stopCtx, pc.ID)
+		if err != nil {
+			return generalError("Failed to retrieve policy check logs", err)
+		}
+		reader := bufio.NewReaderSize(logs, 64*1024)
+
+		// Retrieve the policy check to get its current status.
+		pc, err := b.client.PolicyChecks.Read(stopCtx, pc.ID)
+		if err != nil {
+			return generalError("Failed to retrieve policy check", err)
+		}
+
+		// If the run is canceled or errored, but the policy check still has
+		// no result, there is nothing further to render.
+		if r.Status == tfe.RunCanceled || r.Status == tfe.RunErrored {
+			switch pc.Status {
+			case tfe.PolicyPending, tfe.PolicyQueued, tfe.PolicyUnreachable:
+				continue
+			}
+		}
+
+		var msgPrefix string
+		switch pc.Scope {
+		case tfe.PolicyScopeOrganization:
+			msgPrefix = "Organization Policy Check"
+		case tfe.PolicyScopeWorkspace:
+			msgPrefix = "Workspace Policy Check"
+		default:
+			msgPrefix = fmt.Sprintf("Unknown policy check (%s)", pc.Scope)
+		}
+
+		if b.CLI != nil {
+			b.CLI.Output(b.Colorize().Color("[bold]" + msgPrefix + ":\n"))
+		}
+
+		if b.CLI != nil {
+			for next := true; next; {
+				var l, line []byte
+
+				for isPrefix := true; isPrefix; {
+					l, isPrefix, err = reader.ReadLine()
+					if err != nil {
+						if err != io.EOF {
+							return generalError("Failed to read logs", err)
+						}
+						next = false
+					}
+					line = append(line, l...)
+				}
+
+				if next || len(line) > 0 {
+					b.CLI.Output(b.Colorize().Color(string(line)))
+				}
+			}
+		}
+
+		switch pc.Status {
+		case tfe.PolicyPasses:
+			if (r.HasChanges && op.Type == backend.OperationTypeApply || i < len(r.PolicyChecks)-1) && b.CLI != nil {
+				b.CLI.Output("\n------------------------------------------------------------------------")
+			}
+			continue
+		case tfe.PolicyErrored:
+			return fmt.Errorf(msgPrefix + " errored.")
+		case tfe.PolicyHardFailed:
+			return fmt.Errorf(msgPrefix + " hard failed.")
+		case tfe.PolicySoftFailed:
+			runUrl := fmt.Sprintf(runHeader, b.hostname, b.organization, op.Workspace, r.ID)
+
+			if op.Type == backend.OperationTypePlan || op.UIOut == nil || op.UIIn == nil ||
+				!pc.Actions.IsOverridable || !pc.Permissions.CanOverride {
+				return fmt.Errorf(msgPrefix + " soft failed.\n" + runUrl)
+			}
+
+			if op.AutoApprove {
+				if _, err = b.client.PolicyChecks.Override(stopCtx, pc.ID); err != nil {
+					return generalError(fmt.Sprintf("Failed to override policy check.\n%s", runUrl), err)
+				}
+			} else if !b.input {
+				return errPolicyOverrideNeedsUIConfirmation
+			} else {
+				opts := &terraform.InputOpts{
+					Id:          "override",
+					Query:       "\nDo you want to override the soft failed policy check?",
+					Description: "Only 'override' will be accepted to override.",
+				}
+				err = b.confirm(stopCtx, op, opts, r, "override")
+				if err != nil && err != errRunOverridden {
+					return fmt.Errorf(
+						fmt.Sprintf("Failed to override: %s\n%s\n", err.Error(), runUrl),
+					)
+				}
+
+				if err != errRunOverridden {
+					if _, err = b.client.PolicyChecks.Override(stopCtx, pc.ID); err != nil {
+						return generalError(fmt.Sprintf("Failed to override policy check.\n%s", runUrl), err)
+					}
+				} else {
+					b.CLI.Output(fmt.Sprintf("The run needs to be manually overridden or discarded.\n%s\n", runUrl))
+				}
+			}
+
+			if b.CLI != nil {
+				b.CLI.Output("------------------------------------------------------------------------")
+			}
+		default:
+			return fmt.Errorf("Unknown or unexpected policy state: %s", pc.Status)
+		}
+	}
+
+	return nil
+}
+
+func (b *Cloud) confirm(stopCtx context.Context, op *backend.Operation, opts *terraform.InputOpts, r *tfe.Run, keyword string) error {
+	doneCtx, cancel := context.WithCancel(stopCtx)
+	result := make(chan error, 2)
+
+	go func() {
+		// Make sure we cancel doneCtx before we return
+		// so the input command is also canceled.
+		defer cancel()
+
+		for {
+			select {
+			case <-doneCtx.Done():
+				return
+			case <-stopCtx.Done():
+				return
+			case <-time.After(runPollInterval):
+				// Retrieve the run again to get its current status.
+				r, err := b.client.Runs.Read(stopCtx, r.ID)
+				if err != nil {
+					result <- generalError("Failed to retrieve run", err)
+					return
+				}
+
+				switch keyword {
+				case "override":
+					if r.Status != tfe.RunPolicyOverride && r.Status != tfe.RunPostPlanAwaitingDecision {
+						if r.Status == tfe.RunDiscarded {
+							err = errRunDiscarded
+						} else {
+							err = errRunOverridden
+						}
+					}
+				case "yes":
+					if !r.Actions.IsConfirmable {
+						if r.Status == tfe.RunDiscarded {
+							err = errRunDiscarded
+						} else {
+							err = errRunApproved
+						}
+					}
+				}
+
+				if err != nil {
+					if b.CLI != nil {
+						b.CLI.Output(b.Colorize().Color(
+							fmt.Sprintf("[reset][yellow]%s[reset]", err.Error())))
+					}
+
+					if err == errRunDiscarded {
+						err = errApplyDiscarded
+						if op.PlanMode == plans.DestroyMode {
+							err = errDestroyDiscarded
+						}
+					}
+
+					result <- err
+					return
+				}
+			}
+		}
+	}()
+
+	result <- func() error {
+		v, err := op.UIIn.Input(doneCtx, opts)
+		if err != nil && err != context.Canceled && stopCtx.Err() != context.Canceled {
+			return fmt.Errorf("Error asking %s: %v", opts.Id, err)
+		}
+
+		// We return the error of our parent channel as we don't
+		// care about the error of the doneCtx which is only used
+		// within this function. So if the doneCtx was canceled
+		// because stopCtx was canceled, this will properly return
+		// a context.Canceled error and otherwise it returns nil.
+		if doneCtx.Err() == context.Canceled || stopCtx.Err() == context.Canceled {
+			return stopCtx.Err()
+		}
+
+		// Make sure we cancel the context here so the loop that
+		// checks for external changes to the run is ended before
+		// we start to make changes ourselves.
+		cancel()
+
+		if v != keyword {
+			// Retrieve the run again to get its current status.
+			r, err = b.client.Runs.Read(stopCtx, r.ID)
+			if err != nil {
+				return generalError("Failed to retrieve run", err)
+			}
+
+			// Make sure we discard the run if possible.
+			if r.Actions.IsDiscardable {
+				err = b.client.Runs.Discard(stopCtx, r.ID, tfe.RunDiscardOptions{})
+				if err != nil {
+					if op.PlanMode == plans.DestroyMode {
+						return generalError("Failed to discard destroy", err)
+					}
+					return generalError("Failed to discard apply", err)
+				}
+			}
+
+			// Even if the run was discarded successfully, we still
+			// return an error as the apply command was canceled.
+			if op.PlanMode == plans.DestroyMode {
+				return errDestroyDiscarded
+			}
+			return errApplyDiscarded
+		}
+
+		return nil
+	}()
+
+	return <-result
+}
+
+// This method will fetch the redacted plan output and marshal the response into
+// a struct the jsonformat.Renderer expects.
+//
+// Note: Apologies for the lengthy definition, this is a result of not being able to mock receiver methods
+var readRedactedPlan func(context.Context, url.URL, string, string) (*jsonformat.Plan, error) = func(ctx context.Context, baseURL url.URL, token string, planID string) (*jsonformat.Plan, error) {
+	client := retryablehttp.NewClient()
+	client.RetryMax = 10
+	client.RetryWaitMin = 100 * time.Millisecond
+	client.RetryWaitMax = 400 * time.Millisecond
+	client.Logger = logging.HCLogger()
+
+	u, err := baseURL.Parse(fmt.Sprintf(
+		"plans/%s/json-output-redacted", url.QueryEscape(planID)))
+	if err != nil {
+		return nil, err
+	}
+
+	req, err := retryablehttp.NewRequest("GET", u.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	req.Header.Set("Authorization", "Bearer "+token)
+	req.Header.Set("Accept", "application/json")
+
+	p := &jsonformat.Plan{}
+	resp, err := client.Do(req)
+	if err != nil {
+		return nil, err
+	}
+	defer resp.Body.Close()
+
+	if err = checkResponseCode(resp); err != nil {
+		return nil, err
+	}
+
+	if err := json.NewDecoder(resp.Body).Decode(p); err != nil {
+		return nil, err
+	}
+
+	return p, nil
+}
+
+func checkResponseCode(r *http.Response) error {
+	if r.StatusCode >= 200 && r.StatusCode <= 299 {
+		return nil
+	}
+
+	var errs []string
+	var err error
+
+	switch r.StatusCode {
+	case 401:
+		return tfe.ErrUnauthorized
+	case 404:
+		return tfe.ErrResourceNotFound
+	}
+
+	errs, err = decodeErrorPayload(r)
+	if err != nil {
+		return err
+	}
+
+	return errors.New(strings.Join(errs, "\n"))
+}
+
+func decodeErrorPayload(r *http.Response) ([]string, error) {
+	// Decode the error payload.
+	var errs []string
+	errPayload := &jsonapi.ErrorsPayload{}
+	err := json.NewDecoder(r.Body).Decode(errPayload)
+	if err != nil || len(errPayload.Errors) == 0 {
+		return errs, errors.New(r.Status)
+	}
+
+	// Parse and format the errors.
+	for _, e := range errPayload.Errors {
+		if e.Detail == "" {
+			errs = append(errs, e.Title)
+		} else {
+			errs = append(errs, fmt.Sprintf("%s\n\n%s", e.Title, e.Detail))
+		}
+	}
+
+	return errs, nil
+}
diff --git a/v1.5.7/internal/cloud/backend_context.go b/v1.5.7/internal/cloud/backend_context.go
new file mode 100644
index 0000000..655c86d
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_context.go
@@ -0,0 +1,295 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"context"
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/hcl/v2"
+
+	tfe "github.com/hashicorp/go-tfe"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// LocalRun implements backend.Local
+func (b *Cloud) LocalRun(op *backend.Operation) (*backend.LocalRun, statemgr.Full, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	ret := &backend.LocalRun{
+		PlanOpts: &terraform.PlanOpts{
+			Mode:    op.PlanMode,
+			Targets: op.Targets,
+		},
+	}
+
+	op.StateLocker = op.StateLocker.WithContext(context.Background())
+
+	// Get the remote workspace name.
+	remoteWorkspaceName := b.getRemoteWorkspaceName(op.Workspace)
+
+	// Get the latest state.
+	log.Printf("[TRACE] cloud: requesting state manager for workspace %q", remoteWorkspaceName)
+	stateMgr, err := b.StateMgr(op.Workspace)
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("error loading state: %w", err))
+		return nil, nil, diags
+	}
+
+	log.Printf("[TRACE] cloud: requesting state lock for workspace %q", remoteWorkspaceName)
+	if diags := op.StateLocker.Lock(stateMgr, op.Type.String()); diags.HasErrors() {
+		return nil, nil, diags
+	}
+
+	defer func() {
+		// If we're returning with errors, and thus not producing a valid
+		// context, we'll want to avoid leaving the remote workspace locked.
+		if diags.HasErrors() {
+			diags = diags.Append(op.StateLocker.Unlock())
+		}
+	}()
+
+	log.Printf("[TRACE] cloud: reading remote state for workspace %q", remoteWorkspaceName)
+	if err := stateMgr.RefreshState(); err != nil {
+		diags = diags.Append(fmt.Errorf("error loading state: %w", err))
+		return nil, nil, diags
+	}
+
+	// Initialize our context options
+	var opts terraform.ContextOpts
+	if v := b.ContextOpts; v != nil {
+		opts = *v
+	}
+
+	// Copy set options from the operation
+	opts.UIInput = op.UIIn
+
+	// Load the latest state. If we enter contextFromPlanFile below then the
+	// state snapshot in the plan file must match this, or else it'll return
+	// error diagnostics.
+	log.Printf("[TRACE] cloud: retrieving remote state snapshot for workspace %q", remoteWorkspaceName)
+	ret.InputState = stateMgr.State()
+
+	log.Printf("[TRACE] cloud: loading configuration for the current working directory")
+	config, configDiags := op.ConfigLoader.LoadConfig(op.ConfigDir)
+	diags = diags.Append(configDiags)
+	if configDiags.HasErrors() {
+		return nil, nil, diags
+	}
+	ret.Config = config
+
+	if op.AllowUnsetVariables {
+		// If we're not going to use the variables in an operation we'll be
+		// more lax about them, stubbing out any unset ones as unknown.
+		// This gives us enough information to produce a consistent context,
+		// but not enough information to run a real operation (plan, apply, etc)
+		ret.PlanOpts.SetVariables = stubAllVariables(op.Variables, config.Module.Variables)
+	} else {
+		// The underlying API expects us to use the opaque workspace id to request
+		// variables, so we'll need to look that up using our organization name
+		// and workspace name.
+		remoteWorkspaceID, err := b.getRemoteWorkspaceID(context.Background(), op.Workspace)
+		if err != nil {
+			diags = diags.Append(fmt.Errorf("error finding remote workspace: %w", err))
+			return nil, nil, diags
+		}
+		w, err := b.fetchWorkspace(context.Background(), b.organization, op.Workspace)
+		if err != nil {
+			diags = diags.Append(fmt.Errorf("error loading workspace: %w", err))
+			return nil, nil, diags
+		}
+
+		if isLocalExecutionMode(w.ExecutionMode) {
+			log.Printf("[TRACE] skipping retrieving variables from workspace %s/%s (%s), workspace is in Local Execution mode", remoteWorkspaceName, b.organization, remoteWorkspaceID)
+		} else {
+			log.Printf("[TRACE] cloud: retrieving variables from workspace %s/%s (%s)", remoteWorkspaceName, b.organization, remoteWorkspaceID)
+			tfeVariables, err := b.client.Variables.List(context.Background(), remoteWorkspaceID, nil)
+			if err != nil && err != tfe.ErrResourceNotFound {
+				diags = diags.Append(fmt.Errorf("error loading variables: %w", err))
+				return nil, nil, diags
+			}
+
+			if tfeVariables != nil {
+				if op.Variables == nil {
+					op.Variables = make(map[string]backend.UnparsedVariableValue)
+				}
+
+				for _, v := range tfeVariables.Items {
+					if v.Category == tfe.CategoryTerraform {
+						if _, ok := op.Variables[v.Key]; !ok {
+							op.Variables[v.Key] = &remoteStoredVariableValue{
+								definition: v,
+							}
+						}
+					}
+				}
+			}
+		}
+
+		if op.Variables != nil {
+			variables, varDiags := backend.ParseVariableValues(op.Variables, config.Module.Variables)
+			diags = diags.Append(varDiags)
+			if diags.HasErrors() {
+				return nil, nil, diags
+			}
+			ret.PlanOpts.SetVariables = variables
+		}
+	}
+
+	tfCtx, ctxDiags := terraform.NewContext(&opts)
+	diags = diags.Append(ctxDiags)
+	ret.Core = tfCtx
+
+	log.Printf("[TRACE] cloud: finished building terraform.Context")
+
+	return ret, stateMgr, diags
+}
+
+func (b *Cloud) getRemoteWorkspaceName(localWorkspaceName string) string {
+	switch {
+	case localWorkspaceName == backend.DefaultStateName:
+		// The default workspace name is a special case
+		return b.WorkspaceMapping.Name
+	default:
+		return localWorkspaceName
+	}
+}
+
+func (b *Cloud) getRemoteWorkspace(ctx context.Context, localWorkspaceName string) (*tfe.Workspace, error) {
+	remoteWorkspaceName := b.getRemoteWorkspaceName(localWorkspaceName)
+
+	log.Printf("[TRACE] cloud: looking up workspace for %s/%s", b.organization, remoteWorkspaceName)
+	remoteWorkspace, err := b.client.Workspaces.Read(ctx, b.organization, remoteWorkspaceName)
+	if err != nil {
+		return nil, err
+	}
+
+	return remoteWorkspace, nil
+}
+
+func (b *Cloud) getRemoteWorkspaceID(ctx context.Context, localWorkspaceName string) (string, error) {
+	remoteWorkspace, err := b.getRemoteWorkspace(ctx, localWorkspaceName)
+	if err != nil {
+		return "", err
+	}
+
+	return remoteWorkspace.ID, nil
+}
+
+func stubAllVariables(vv map[string]backend.UnparsedVariableValue, decls map[string]*configs.Variable) terraform.InputValues {
+	ret := make(terraform.InputValues, len(decls))
+
+	for name, cfg := range decls {
+		raw, exists := vv[name]
+		if !exists {
+			ret[name] = &terraform.InputValue{
+				Value:      cty.UnknownVal(cfg.Type),
+				SourceType: terraform.ValueFromConfig,
+			}
+			continue
+		}
+
+		val, diags := raw.ParseVariableValue(cfg.ParsingMode)
+		if diags.HasErrors() {
+			ret[name] = &terraform.InputValue{
+				Value:      cty.UnknownVal(cfg.Type),
+				SourceType: terraform.ValueFromConfig,
+			}
+			continue
+		}
+		ret[name] = val
+	}
+
+	return ret
+}
+
+// remoteStoredVariableValue is a backend.UnparsedVariableValue implementation
+// that translates from the go-tfe representation of stored variables into
+// the Terraform Core backend representation of variables.
+type remoteStoredVariableValue struct {
+	definition *tfe.Variable
+}
+
+var _ backend.UnparsedVariableValue = (*remoteStoredVariableValue)(nil)
+
+func (v *remoteStoredVariableValue) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	var val cty.Value
+
+	switch {
+	case v.definition.Sensitive:
+		// If it's marked as sensitive then it's not available for use in
+		// local operations. We'll use an unknown value as a placeholder for
+		// it so that operations that don't need it might still work, but
+		// we'll also produce a warning about it to add context for any
+		// errors that might result here.
+		val = cty.DynamicVal
+		if !v.definition.HCL {
+			// If it's not marked as HCL then we at least know that the
+			// value must be a string, so we'll set that in case it allows
+			// us to do some more precise type checking.
+			val = cty.UnknownVal(cty.String)
+		}
+
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Warning,
+			fmt.Sprintf("Value for var.%s unavailable", v.definition.Key),
+			fmt.Sprintf("The value of variable %q is marked as sensitive in the remote workspace. This operation always runs locally, so the value for that variable is not available.", v.definition.Key),
+		))
+
+	case v.definition.HCL:
+		// If the variable value is marked as being in HCL syntax, we need to
+		// parse it the same way as it would be interpreted in a .tfvars
+		// file because that is how it would get passed to Terraform CLI for
+		// a remote operation and we want to mimic that result as closely as
+		// possible.
+		var exprDiags hcl.Diagnostics
+		expr, exprDiags := hclsyntax.ParseExpression([]byte(v.definition.Value), "<remote workspace>", hcl.Pos{Line: 1, Column: 1})
+		if expr != nil {
+			var moreDiags hcl.Diagnostics
+			val, moreDiags = expr.Value(nil)
+			exprDiags = append(exprDiags, moreDiags...)
+		} else {
+			// We'll have already put some errors in exprDiags above, so we'll
+			// just stub out the value here.
+			val = cty.DynamicVal
+		}
+
+		// We don't have sufficient context to return decent error messages
+		// for syntax errors in the remote values, so we'll just return a
+		// generic message instead for now.
+		// (More complete error messages will still result from true remote
+		// operations, because they'll run on the remote system where we've
+		// materialized the values into a tfvars file we can report from.)
+		if exprDiags.HasErrors() {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				fmt.Sprintf("Invalid expression for var.%s", v.definition.Key),
+				fmt.Sprintf("The value of variable %q is marked in the remote workspace as being specified in HCL syntax, but the given value is not valid HCL. Stored variable values must be valid literal expressions and may not contain references to other variables or calls to functions.", v.definition.Key),
+			))
+		}
+
+	default:
+		// A variable value _not_ marked as HCL is always be a string, given
+		// literally.
+		val = cty.StringVal(v.definition.Value)
+	}
+
+	return &terraform.InputValue{
+		Value: val,
+
+		// We mark these as "from input" with the rationale that entering
+		// variable values into the Terraform Cloud or Enterprise UI is,
+		// roughly speaking, a similar idea to entering variable values at
+		// the interactive CLI prompts. It's not a perfect correspondance,
+		// but it's closer than the other options.
+		SourceType: terraform.ValueFromInput,
+	}, diags
+}
diff --git a/v1.5.7/internal/cloud/backend_context_test.go b/v1.5.7/internal/cloud/backend_context_test.go
new file mode 100644
index 0000000..16b73ab
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_context_test.go
@@ -0,0 +1,458 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"context"
+	"reflect"
+	"testing"
+
+	tfe "github.com/hashicorp/go-tfe"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestRemoteStoredVariableValue(t *testing.T) {
+	tests := map[string]struct {
+		Def       *tfe.Variable
+		Want      cty.Value
+		WantError string
+	}{
+		"string literal": {
+			&tfe.Variable{
+				Key:       "test",
+				Value:     "foo",
+				HCL:       false,
+				Sensitive: false,
+			},
+			cty.StringVal("foo"),
+			``,
+		},
+		"string HCL": {
+			&tfe.Variable{
+				Key:       "test",
+				Value:     `"foo"`,
+				HCL:       true,
+				Sensitive: false,
+			},
+			cty.StringVal("foo"),
+			``,
+		},
+		"list HCL": {
+			&tfe.Variable{
+				Key:       "test",
+				Value:     `[]`,
+				HCL:       true,
+				Sensitive: false,
+			},
+			cty.EmptyTupleVal,
+			``,
+		},
+		"null HCL": {
+			&tfe.Variable{
+				Key:       "test",
+				Value:     `null`,
+				HCL:       true,
+				Sensitive: false,
+			},
+			cty.NullVal(cty.DynamicPseudoType),
+			``,
+		},
+		"literal sensitive": {
+			&tfe.Variable{
+				Key:       "test",
+				HCL:       false,
+				Sensitive: true,
+			},
+			cty.UnknownVal(cty.String),
+			``,
+		},
+		"HCL sensitive": {
+			&tfe.Variable{
+				Key:       "test",
+				HCL:       true,
+				Sensitive: true,
+			},
+			cty.DynamicVal,
+			``,
+		},
+		"HCL computation": {
+			// This (stored expressions containing computation) is not a case
+			// we intentionally supported, but it became possible for remote
+			// operations in Terraform 0.12 (due to Terraform Cloud/Enterprise
+			// just writing the HCL verbatim into generated `.tfvars` files).
+			// We support it here for consistency, and we continue to support
+			// it in both places for backward-compatibility. In practice,
+			// there's little reason to do computation in a stored variable
+			// value because references are not supported.
+			&tfe.Variable{
+				Key:       "test",
+				Value:     `[for v in ["a"] : v]`,
+				HCL:       true,
+				Sensitive: false,
+			},
+			cty.TupleVal([]cty.Value{cty.StringVal("a")}),
+			``,
+		},
+		"HCL syntax error": {
+			&tfe.Variable{
+				Key:       "test",
+				Value:     `[`,
+				HCL:       true,
+				Sensitive: false,
+			},
+			cty.DynamicVal,
+			`Invalid expression for var.test: The value of variable "test" is marked in the remote workspace as being specified in HCL syntax, but the given value is not valid HCL. Stored variable values must be valid literal expressions and may not contain references to other variables or calls to functions.`,
+		},
+		"HCL with references": {
+			&tfe.Variable{
+				Key:       "test",
+				Value:     `foo.bar`,
+				HCL:       true,
+				Sensitive: false,
+			},
+			cty.DynamicVal,
+			`Invalid expression for var.test: The value of variable "test" is marked in the remote workspace as being specified in HCL syntax, but the given value is not valid HCL. Stored variable values must be valid literal expressions and may not contain references to other variables or calls to functions.`,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			v := &remoteStoredVariableValue{
+				definition: test.Def,
+			}
+			// This ParseVariableValue implementation ignores the parsing mode,
+			// so we'll just always parse literal here. (The parsing mode is
+			// selected by the remote server, not by our local configuration.)
+			gotIV, diags := v.ParseVariableValue(configs.VariableParseLiteral)
+			if test.WantError != "" {
+				if !diags.HasErrors() {
+					t.Fatalf("missing expected error\ngot:  <no error>\nwant: %s", test.WantError)
+				}
+				errStr := diags.Err().Error()
+				if errStr != test.WantError {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", errStr, test.WantError)
+				}
+			} else {
+				if diags.HasErrors() {
+					t.Fatalf("unexpected error\ngot:  %s\nwant: <no error>", diags.Err().Error())
+				}
+				got := gotIV.Value
+				if !test.Want.RawEquals(got) {
+					t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+				}
+			}
+		})
+	}
+}
+
+func TestRemoteContextWithVars(t *testing.T) {
+	catTerraform := tfe.CategoryTerraform
+	catEnv := tfe.CategoryEnv
+
+	tests := map[string]struct {
+		Opts      *tfe.VariableCreateOptions
+		WantError string
+	}{
+		"Terraform variable": {
+			&tfe.VariableCreateOptions{
+				Category: &catTerraform,
+			},
+			`Value for undeclared variable: A variable named "key" was assigned a value, but the root module does not declare a variable of that name. To use this value, add a "variable" block to the configuration.`,
+		},
+		"environment variable": {
+			&tfe.VariableCreateOptions{
+				Category: &catEnv,
+			},
+			``,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			configDir := "./testdata/empty"
+
+			b, bCleanup := testBackendWithName(t)
+			defer bCleanup()
+
+			_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
+			defer configCleanup()
+
+			workspaceID, err := b.getRemoteWorkspaceID(context.Background(), testBackendSingleWorkspaceName)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			streams, _ := terminal.StreamsForTesting(t)
+			view := views.NewStateLocker(arguments.ViewHuman, views.NewView(streams))
+
+			op := &backend.Operation{
+				ConfigDir:    configDir,
+				ConfigLoader: configLoader,
+				StateLocker:  clistate.NewLocker(0, view),
+				Workspace:    testBackendSingleWorkspaceName,
+			}
+
+			v := test.Opts
+			if v.Key == nil {
+				key := "key"
+				v.Key = &key
+			}
+			b.client.Variables.Create(context.TODO(), workspaceID, *v)
+
+			_, _, diags := b.LocalRun(op)
+
+			if test.WantError != "" {
+				if !diags.HasErrors() {
+					t.Fatalf("missing expected error\ngot:  <no error>\nwant: %s", test.WantError)
+				}
+				errStr := diags.Err().Error()
+				if errStr != test.WantError {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", errStr, test.WantError)
+				}
+				// When Context() returns an error, it should unlock the state,
+				// so re-locking it is expected to succeed.
+				stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
+				if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+					t.Fatalf("unexpected error locking state: %s", err.Error())
+				}
+			} else {
+				if diags.HasErrors() {
+					t.Fatalf("unexpected error\ngot:  %s\nwant: <no error>", diags.Err().Error())
+				}
+				// When Context() succeeds, this should fail w/ "workspace already locked"
+				stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
+				if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err == nil {
+					t.Fatal("unexpected success locking state after Context")
+				}
+			}
+		})
+	}
+}
+
+func TestRemoteVariablesDoNotOverride(t *testing.T) {
+	catTerraform := tfe.CategoryTerraform
+
+	varName1 := "key1"
+	varName2 := "key2"
+	varName3 := "key3"
+
+	varValue1 := "value1"
+	varValue2 := "value2"
+	varValue3 := "value3"
+
+	tests := map[string]struct {
+		localVariables    map[string]backend.UnparsedVariableValue
+		remoteVariables   []*tfe.VariableCreateOptions
+		expectedVariables terraform.InputValues
+	}{
+		"no local variables": {
+			map[string]backend.UnparsedVariableValue{},
+			[]*tfe.VariableCreateOptions{
+				{
+					Key:      &varName1,
+					Value:    &varValue1,
+					Category: &catTerraform,
+				},
+				{
+					Key:      &varName2,
+					Value:    &varValue2,
+					Category: &catTerraform,
+				},
+				{
+					Key:      &varName3,
+					Value:    &varValue3,
+					Category: &catTerraform,
+				},
+			},
+			terraform.InputValues{
+				varName1: &terraform.InputValue{
+					Value:      cty.StringVal(varValue1),
+					SourceType: terraform.ValueFromInput,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "",
+						Start:    tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+					},
+				},
+				varName2: &terraform.InputValue{
+					Value:      cty.StringVal(varValue2),
+					SourceType: terraform.ValueFromInput,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "",
+						Start:    tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+					},
+				},
+				varName3: &terraform.InputValue{
+					Value:      cty.StringVal(varValue3),
+					SourceType: terraform.ValueFromInput,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "",
+						Start:    tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+					},
+				},
+			},
+		},
+		"single conflicting local variable": {
+			map[string]backend.UnparsedVariableValue{
+				varName3: testUnparsedVariableValue{source: terraform.ValueFromNamedFile, value: cty.StringVal(varValue3)},
+			},
+			[]*tfe.VariableCreateOptions{
+				{
+					Key:      &varName1,
+					Value:    &varValue1,
+					Category: &catTerraform,
+				}, {
+					Key:      &varName2,
+					Value:    &varValue2,
+					Category: &catTerraform,
+				}, {
+					Key:      &varName3,
+					Value:    &varValue3,
+					Category: &catTerraform,
+				},
+			},
+			terraform.InputValues{
+				varName1: &terraform.InputValue{
+					Value:      cty.StringVal(varValue1),
+					SourceType: terraform.ValueFromInput,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "",
+						Start:    tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+					},
+				},
+				varName2: &terraform.InputValue{
+					Value:      cty.StringVal(varValue2),
+					SourceType: terraform.ValueFromInput,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "",
+						Start:    tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+					},
+				},
+				varName3: &terraform.InputValue{
+					Value:      cty.StringVal(varValue3),
+					SourceType: terraform.ValueFromNamedFile,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "fake.tfvars",
+						Start:    tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					},
+				},
+			},
+		},
+		"no conflicting local variable": {
+			map[string]backend.UnparsedVariableValue{
+				varName3: testUnparsedVariableValue{source: terraform.ValueFromNamedFile, value: cty.StringVal(varValue3)},
+			},
+			[]*tfe.VariableCreateOptions{
+				{
+					Key:      &varName1,
+					Value:    &varValue1,
+					Category: &catTerraform,
+				}, {
+					Key:      &varName2,
+					Value:    &varValue2,
+					Category: &catTerraform,
+				},
+			},
+			terraform.InputValues{
+				varName1: &terraform.InputValue{
+					Value:      cty.StringVal(varValue1),
+					SourceType: terraform.ValueFromInput,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "",
+						Start:    tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+					},
+				},
+				varName2: &terraform.InputValue{
+					Value:      cty.StringVal(varValue2),
+					SourceType: terraform.ValueFromInput,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "",
+						Start:    tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0},
+					},
+				},
+				varName3: &terraform.InputValue{
+					Value:      cty.StringVal(varValue3),
+					SourceType: terraform.ValueFromNamedFile,
+					SourceRange: tfdiags.SourceRange{
+						Filename: "fake.tfvars",
+						Start:    tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+						End:      tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+					},
+				},
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			configDir := "./testdata/variables"
+
+			b, bCleanup := testBackendWithName(t)
+			defer bCleanup()
+
+			_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
+			defer configCleanup()
+
+			workspaceID, err := b.getRemoteWorkspaceID(context.Background(), testBackendSingleWorkspaceName)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			streams, _ := terminal.StreamsForTesting(t)
+			view := views.NewStateLocker(arguments.ViewHuman, views.NewView(streams))
+
+			op := &backend.Operation{
+				ConfigDir:    configDir,
+				ConfigLoader: configLoader,
+				StateLocker:  clistate.NewLocker(0, view),
+				Workspace:    testBackendSingleWorkspaceName,
+				Variables:    test.localVariables,
+			}
+
+			for _, v := range test.remoteVariables {
+				b.client.Variables.Create(context.TODO(), workspaceID, *v)
+			}
+
+			lr, _, diags := b.LocalRun(op)
+
+			if diags.HasErrors() {
+				t.Fatalf("unexpected error\ngot:  %s\nwant: <no error>", diags.Err().Error())
+			}
+			// When Context() succeeds, this should fail w/ "workspace already locked"
+			stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
+			if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err == nil {
+				t.Fatal("unexpected success locking state after Context")
+			}
+
+			actual := lr.PlanOpts.SetVariables
+			expected := test.expectedVariables
+
+			for expectedKey := range expected {
+				actualValue := actual[expectedKey]
+				expectedValue := expected[expectedKey]
+
+				if !reflect.DeepEqual(*actualValue, *expectedValue) {
+					t.Fatalf("unexpected variable '%s'\ngot:  %v\nwant: %v", expectedKey, actualValue, expectedValue)
+				}
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/cloud/backend_plan.go b/v1.5.7/internal/cloud/backend_plan.go
new file mode 100644
index 0000000..b01943d
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_plan.go
@@ -0,0 +1,619 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"bufio"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"syscall"
+	"time"
+
+	tfe "github.com/hashicorp/go-tfe"
+	version "github.com/hashicorp/go-version"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/jsonformat"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/genconfig"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+var planConfigurationVersionsPollInterval = 500 * time.Millisecond
+
+func (b *Cloud) opPlan(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
+	log.Printf("[INFO] cloud: starting Plan operation")
+
+	var diags tfdiags.Diagnostics
+
+	if !w.Permissions.CanQueueRun {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Insufficient rights to generate a plan",
+			"The provided credentials have insufficient rights to generate a plan. In order "+
+				"to generate plans, at least plan permissions on the workspace are required.",
+		))
+		return nil, diags.Err()
+	}
+
+	if b.ContextOpts != nil && b.ContextOpts.Parallelism != defaultParallelism {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Custom parallelism values are currently not supported",
+			`Terraform Cloud does not support setting a custom parallelism `+
+				`value at this time.`,
+		))
+	}
+
+	if op.PlanFile != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Displaying a saved plan is currently not supported",
+			`Terraform Cloud currently requires configuration to be present and `+
+				`does not accept an existing saved plan as an argument at this time.`,
+		))
+	}
+
+	if op.PlanOutPath != "" {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Saving a generated plan is currently not supported",
+			`Terraform Cloud does not support saving the generated execution `+
+				`plan locally at this time.`,
+		))
+	}
+
+	if !op.HasConfig() && op.PlanMode != plans.DestroyMode {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"No configuration files found",
+			`Plan requires configuration to be present. Planning without a configuration `+
+				`would mark everything for destruction, which is normally not what is desired. `+
+				`If you would like to destroy everything, please run plan with the "-destroy" `+
+				`flag or create a single empty configuration file. Otherwise, please create `+
+				`a Terraform configuration file in the path being executed and try again.`,
+		))
+	}
+
+	if len(op.GenerateConfigOut) > 0 {
+		diags = diags.Append(genconfig.ValidateTargetFile(op.GenerateConfigOut))
+	}
+
+	// Return if there are any errors.
+	if diags.HasErrors() {
+		return nil, diags.Err()
+	}
+
+	return b.plan(stopCtx, cancelCtx, op, w)
+}
+
+func (b *Cloud) plan(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
+	if b.CLI != nil {
+		header := planDefaultHeader
+		if op.Type == backend.OperationTypeApply || op.Type == backend.OperationTypeRefresh {
+			header = applyDefaultHeader
+		}
+		b.CLI.Output(b.Colorize().Color(strings.TrimSpace(header) + "\n"))
+	}
+
+	configOptions := tfe.ConfigurationVersionCreateOptions{
+		AutoQueueRuns: tfe.Bool(false),
+		Speculative:   tfe.Bool(op.Type == backend.OperationTypePlan),
+	}
+
+	cv, err := b.client.ConfigurationVersions.Create(stopCtx, w.ID, configOptions)
+	if err != nil {
+		return nil, generalError("Failed to create configuration version", err)
+	}
+
+	var configDir string
+	if op.ConfigDir != "" {
+		// De-normalize the configuration directory path.
+		configDir, err = filepath.Abs(op.ConfigDir)
+		if err != nil {
+			return nil, generalError(
+				"Failed to get absolute path of the configuration directory: %v", err)
+		}
+
+		// Make sure to take the working directory into account by removing
+		// the working directory from the current path. This will result in
+		// a path that points to the expected root of the workspace.
+		configDir = filepath.Clean(strings.TrimSuffix(
+			filepath.Clean(configDir),
+			filepath.Clean(w.WorkingDirectory),
+		))
+
+		// If the workspace has a subdirectory as its working directory then
+		// our configDir will be some parent directory of the current working
+		// directory. Users are likely to find that surprising, so we'll
+		// produce an explicit message about it to be transparent about what
+		// we are doing and why.
+		if w.WorkingDirectory != "" && filepath.Base(configDir) != w.WorkingDirectory {
+			if b.CLI != nil {
+				b.CLI.Output(fmt.Sprintf(strings.TrimSpace(`
+The remote workspace is configured to work with configuration at
+%s relative to the target repository.
+
+Terraform will upload the contents of the following directory,
+excluding files or directories as defined by a .terraformignore file
+at %s/.terraformignore (if it is present),
+in order to capture the filesystem context the remote workspace expects:
+    %s
+`), w.WorkingDirectory, configDir, configDir) + "\n")
+			}
+		}
+
+	} else {
+		// We did a check earlier to make sure we either have a config dir,
+		// or the plan is run with -destroy. So this else clause will only
+		// be executed when we are destroying and doesn't need the config.
+		configDir, err = ioutil.TempDir("", "tf")
+		if err != nil {
+			return nil, generalError("Failed to create temporary directory", err)
+		}
+		defer os.RemoveAll(configDir)
+
+		// Make sure the configured working directory exists.
+		err = os.MkdirAll(filepath.Join(configDir, w.WorkingDirectory), 0700)
+		if err != nil {
+			return nil, generalError(
+				"Failed to create temporary working directory", err)
+		}
+	}
+
+	err = b.client.ConfigurationVersions.Upload(stopCtx, cv.UploadURL, configDir)
+	if err != nil {
+		return nil, generalError("Failed to upload configuration files", err)
+	}
+
+	uploaded := false
+	for i := 0; i < 60 && !uploaded; i++ {
+		select {
+		case <-stopCtx.Done():
+			return nil, context.Canceled
+		case <-cancelCtx.Done():
+			return nil, context.Canceled
+		case <-time.After(planConfigurationVersionsPollInterval):
+			cv, err = b.client.ConfigurationVersions.Read(stopCtx, cv.ID)
+			if err != nil {
+				return nil, generalError("Failed to retrieve configuration version", err)
+			}
+
+			if cv.Status == tfe.ConfigurationUploaded {
+				uploaded = true
+			}
+		}
+	}
+
+	if !uploaded {
+		return nil, generalError(
+			"Failed to upload configuration files", errors.New("operation timed out"))
+	}
+
+	runOptions := tfe.RunCreateOptions{
+		ConfigurationVersion: cv,
+		Refresh:              tfe.Bool(op.PlanRefresh),
+		Workspace:            w,
+		AutoApply:            tfe.Bool(op.AutoApprove),
+	}
+
+	switch op.PlanMode {
+	case plans.NormalMode:
+		// okay, but we don't need to do anything special for this
+	case plans.RefreshOnlyMode:
+		runOptions.RefreshOnly = tfe.Bool(true)
+	case plans.DestroyMode:
+		runOptions.IsDestroy = tfe.Bool(true)
+	default:
+		// Shouldn't get here because we should update this for each new
+		// plan mode we add, mapping it to the corresponding RunCreateOptions
+		// field.
+		return nil, generalError(
+			"Invalid plan mode",
+			fmt.Errorf("Terraform Cloud doesn't support %s", op.PlanMode),
+		)
+	}
+
+	if len(op.Targets) != 0 {
+		runOptions.TargetAddrs = make([]string, 0, len(op.Targets))
+		for _, addr := range op.Targets {
+			runOptions.TargetAddrs = append(runOptions.TargetAddrs, addr.String())
+		}
+	}
+
+	if len(op.ForceReplace) != 0 {
+		runOptions.ReplaceAddrs = make([]string, 0, len(op.ForceReplace))
+		for _, addr := range op.ForceReplace {
+			runOptions.ReplaceAddrs = append(runOptions.ReplaceAddrs, addr.String())
+		}
+	}
+
+	config, _, configDiags := op.ConfigLoader.LoadConfigWithSnapshot(op.ConfigDir)
+	if configDiags.HasErrors() {
+		return nil, fmt.Errorf("error loading config with snapshot: %w", configDiags.Errs()[0])
+	}
+
+	variables, varDiags := ParseCloudRunVariables(op.Variables, config.Module.Variables)
+
+	if varDiags.HasErrors() {
+		return nil, varDiags.Err()
+	}
+
+	runVariables := make([]*tfe.RunVariable, 0, len(variables))
+	for name, value := range variables {
+		runVariables = append(runVariables, &tfe.RunVariable{
+			Key:   name,
+			Value: value,
+		})
+	}
+	runOptions.Variables = runVariables
+
+	if len(op.GenerateConfigOut) > 0 {
+		runOptions.AllowConfigGeneration = tfe.Bool(true)
+	}
+
+	r, err := b.client.Runs.Create(stopCtx, runOptions)
+	if err != nil {
+		return r, generalError("Failed to create run", err)
+	}
+
+	// When the lock timeout is set, if the run is still pending and
+	// cancellable after that period, we attempt to cancel it.
+	if lockTimeout := op.StateLocker.Timeout(); lockTimeout > 0 {
+		go func() {
+			select {
+			case <-stopCtx.Done():
+				return
+			case <-cancelCtx.Done():
+				return
+			case <-time.After(lockTimeout):
+				// Retrieve the run to get its current status.
+				r, err := b.client.Runs.Read(cancelCtx, r.ID)
+				if err != nil {
+					log.Printf("[ERROR] error reading run: %v", err)
+					return
+				}
+
+				if r.Status == tfe.RunPending && r.Actions.IsCancelable {
+					if b.CLI != nil {
+						b.CLI.Output(b.Colorize().Color(strings.TrimSpace(lockTimeoutErr)))
+					}
+
+					// We abuse the auto aprove flag to indicate that we do not
+					// want to ask if the remote operation should be canceled.
+					op.AutoApprove = true
+
+					p, err := os.FindProcess(os.Getpid())
+					if err != nil {
+						log.Printf("[ERROR] error searching process ID: %v", err)
+						return
+					}
+					p.Signal(syscall.SIGINT)
+				}
+			}
+		}()
+	}
+
+	if b.CLI != nil {
+		b.CLI.Output(b.Colorize().Color(strings.TrimSpace(fmt.Sprintf(
+			runHeader, b.hostname, b.organization, op.Workspace, r.ID)) + "\n"))
+	}
+
+	// Render any warnings that were raised during run creation
+	if err := b.renderRunWarnings(stopCtx, b.client, r.ID); err != nil {
+		return r, err
+	}
+
+	// Retrieve the run to get task stages.
+	// Task Stages are calculated upfront so we only need to call this once for the run.
+	taskStages, err := b.runTaskStages(stopCtx, b.client, r.ID)
+	if err != nil {
+		return r, err
+	}
+
+	if stage, ok := taskStages[tfe.PrePlan]; ok {
+		if err := b.waitTaskStage(stopCtx, cancelCtx, op, r, stage.ID, "Pre-plan Tasks"); err != nil {
+			return r, err
+		}
+	}
+
+	r, err = b.waitForRun(stopCtx, cancelCtx, op, "plan", r, w)
+	if err != nil {
+		return r, err
+	}
+
+	err = b.renderPlanLogs(stopCtx, op, r)
+	if err != nil {
+		return r, err
+	}
+
+	// Retrieve the run to get its current status.
+	r, err = b.client.Runs.Read(stopCtx, r.ID)
+	if err != nil {
+		return r, generalError("Failed to retrieve run", err)
+	}
+
+	// If the run is canceled or errored, we still continue to the
+	// cost-estimation and policy check phases to ensure we render any
+	// results available. In the case of a hard-failed policy check, the
+	// status of the run will be "errored", but there is still policy
+	// information which should be shown.
+
+	if stage, ok := taskStages[tfe.PostPlan]; ok {
+		if err := b.waitTaskStage(stopCtx, cancelCtx, op, r, stage.ID, "Post-plan Tasks"); err != nil {
+			return r, err
+		}
+	}
+
+	// Show any cost estimation output.
+	if r.CostEstimate != nil {
+		err = b.costEstimate(stopCtx, cancelCtx, op, r)
+		if err != nil {
+			return r, err
+		}
+	}
+
+	// Check any configured sentinel policies.
+	if len(r.PolicyChecks) > 0 {
+		err = b.checkPolicy(stopCtx, cancelCtx, op, r)
+		if err != nil {
+			return r, err
+		}
+	}
+
+	return r, nil
+}
+
+// AssertImportCompatible errors if the user is attempting to use configuration-
+// driven import and the version of the agent or API is too low to support it.
+func (b *Cloud) AssertImportCompatible(config *configs.Config) error {
+	// Check TFC_RUN_ID is populated, indicating we are running in a remote TFC
+	// execution environment.
+	if len(config.Module.Import) > 0 && os.Getenv("TFC_RUN_ID") != "" {
+		// First, check the remote API version is high enough.
+		currentAPIVersion, err := version.NewVersion(b.client.RemoteAPIVersion())
+		if err != nil {
+			return fmt.Errorf("Error parsing remote API version. To proceed, please remove any import blocks from your config. Please report the following error to the Terraform team: %s", err)
+		}
+		desiredAPIVersion, _ := version.NewVersion("2.6")
+		if currentAPIVersion.LessThan(desiredAPIVersion) {
+			return fmt.Errorf("Import blocks are not supported in this version of Terraform Enterprise. Please remove any import blocks from your config or upgrade Terraform Enterprise.")
+		}
+
+		// Second, check the agent version is high enough.
+		agentEnv, isSet := os.LookupEnv("TFC_AGENT_VERSION")
+		if !isSet {
+			return fmt.Errorf("Error reading TFC agent version. To proceed, please remove any import blocks from your config. Please report the following error to the Terraform team: TFC_AGENT_VERSION not present.")
+		}
+		currentAgentVersion, err := version.NewVersion(agentEnv)
+		if err != nil {
+			return fmt.Errorf("Error parsing TFC agent version. To proceed, please remove any import blocks from your config. Please report the following error to the Terraform team: %s", err)
+		}
+		desiredAgentVersion, _ := version.NewVersion("1.10")
+		if currentAgentVersion.LessThan(desiredAgentVersion) {
+			return fmt.Errorf("Import blocks are not supported in this version of the Terraform Cloud Agent. You are using agent version %s, but this feature requires version %s. Please remove any import blocks from your config or upgrade your agent.", currentAgentVersion, desiredAgentVersion)
+		}
+	}
+	return nil
+}
+
+// renderPlanLogs reads the streamed plan JSON logs and calls the JSON Plan renderer (jsonformat.RenderPlan) to
+// render the plan output. The plan output is fetched from the redacted output endpoint.
+func (b *Cloud) renderPlanLogs(ctx context.Context, op *backend.Operation, run *tfe.Run) error {
+	logs, err := b.client.Plans.Logs(ctx, run.Plan.ID)
+	if err != nil {
+		return err
+	}
+
+	if b.CLI != nil {
+		reader := bufio.NewReaderSize(logs, 64*1024)
+
+		for next := true; next; {
+			var l, line []byte
+			var err error
+
+			for isPrefix := true; isPrefix; {
+				l, isPrefix, err = reader.ReadLine()
+				if err != nil {
+					if err != io.EOF {
+						return generalError("Failed to read logs", err)
+					}
+					next = false
+				}
+
+				line = append(line, l...)
+			}
+
+			if next || len(line) > 0 {
+				log := &jsonformat.JSONLog{}
+				if err := json.Unmarshal(line, log); err != nil {
+					// If we can not parse the line as JSON, we will simply
+					// print the line. This maintains backwards compatibility for
+					// users who do not wish to enable structured output in their
+					// workspace.
+					b.CLI.Output(string(line))
+					continue
+				}
+
+				// We will ignore plan output, change summary or outputs logs
+				// during the plan phase.
+				if log.Type == jsonformat.LogOutputs ||
+					log.Type == jsonformat.LogChangeSummary ||
+					log.Type == jsonformat.LogPlannedChange {
+					continue
+				}
+
+				if b.renderer != nil {
+					// Otherwise, we will print the log
+					err := b.renderer.RenderLog(log)
+					if err != nil {
+						return err
+					}
+				}
+			}
+		}
+	}
+
+	// Get the run's current status and include the workspace and plan. We will check if
+	// the run has errored, if structured output is enabled, and if the plan
+	run, err = b.client.Runs.ReadWithOptions(ctx, run.ID, &tfe.RunReadOptions{
+		Include: []tfe.RunIncludeOpt{tfe.RunWorkspace, tfe.RunPlan},
+	})
+	if err != nil {
+		return err
+	}
+
+	// If the run was errored, canceled, or discarded we will not resume the rest
+	// of this logic and attempt to render the plan, except in certain special circumstances
+	// where the plan errored but successfully generated configuration during an
+	// import operation. In that case, we need to keep going so we can load the JSON plan
+	// and use it to write the generated config to the specified output file.
+	shouldGenerateConfig := shouldGenerateConfig(op.GenerateConfigOut, run)
+	shouldRenderPlan := shouldRenderPlan(run)
+	if !shouldRenderPlan && !shouldGenerateConfig {
+		// We won't return an error here since we need to resume the logic that
+		// follows after rendering the logs (run tasks, cost estimation, etc.)
+		return nil
+	}
+
+	// Fetch the redacted JSON plan if we need it for either rendering the plan
+	// or writing out generated configuration.
+	var redactedPlan *jsonformat.Plan
+	renderSRO, err := b.shouldRenderStructuredRunOutput(run)
+	if err != nil {
+		return err
+	}
+	if renderSRO || shouldGenerateConfig {
+		redactedPlan, err = readRedactedPlan(ctx, b.client.BaseURL(), b.token, run.Plan.ID)
+		if err != nil {
+			return generalError("Failed to read JSON plan", err)
+		}
+	}
+
+	// Write any generated config before rendering the plan, so we can stop in case of errors
+	if shouldGenerateConfig {
+		diags := maybeWriteGeneratedConfig(redactedPlan, op.GenerateConfigOut)
+		if diags.HasErrors() {
+			return diags.Err()
+		}
+	}
+
+	// Only generate the human readable output from the plan if structured run output is
+	// enabled. Otherwise we risk duplicate plan output since plan output may also be
+	// shown in the streamed logs.
+	if shouldRenderPlan && renderSRO {
+		b.renderer.RenderHumanPlan(*redactedPlan, op.PlanMode)
+	}
+
+	return nil
+}
+
+// maybeWriteGeneratedConfig attempts to write any generated configuration from the JSON plan
+// to the specified output file, if generated configuration exists and the correct flag was
+// passed to the plan command.
+func maybeWriteGeneratedConfig(plan *jsonformat.Plan, out string) (diags tfdiags.Diagnostics) {
+	if genconfig.ShouldWriteConfig(out) {
+		diags := genconfig.ValidateTargetFile(out)
+		if diags.HasErrors() {
+			return diags
+		}
+
+		var writer io.Writer
+		for _, c := range plan.ResourceChanges {
+			change := genconfig.Change{
+				Addr:            c.Address,
+				GeneratedConfig: c.Change.GeneratedConfig,
+			}
+			if c.Change.Importing != nil {
+				change.ImportID = c.Change.Importing.ID
+			}
+
+			var moreDiags tfdiags.Diagnostics
+			writer, _, moreDiags = change.MaybeWriteConfig(writer, out)
+			if moreDiags.HasErrors() {
+				return diags.Append(moreDiags)
+			}
+		}
+	}
+
+	return diags
+}
+
+// shouldRenderStructuredRunOutput ensures the remote workspace has structured
+// run output enabled and, if using Terraform Enterprise, ensures it is a release
+// that supports enabling SRO for CLI-driven runs. The plan output will have
+// already been rendered when the logs were read if this wasn't the case.
+func (b *Cloud) shouldRenderStructuredRunOutput(run *tfe.Run) (bool, error) {
+	if b.renderer == nil || !run.Workspace.StructuredRunOutputEnabled {
+		return false, nil
+	}
+
+	// If the cloud backend is configured against TFC, we only require that
+	// the workspace has structured run output enabled.
+	if b.client.IsCloud() && run.Workspace.StructuredRunOutputEnabled {
+		return true, nil
+	}
+
+	// If the cloud backend is configured against TFE, ensure the release version
+	// supports enabling SRO for CLI runs.
+	if b.client.IsEnterprise() {
+		tfeVersion := b.client.RemoteTFEVersion()
+		if tfeVersion != "" {
+			v := strings.Split(tfeVersion[1:], "-")
+			releaseDate, err := strconv.Atoi(v[0])
+			if err != nil {
+				return false, err
+			}
+
+			// Any release older than 202302-1 will not support enabling SRO for
+			// CLI-driven runs
+			if releaseDate < 202302 {
+				return false, nil
+			} else if run.Workspace.StructuredRunOutputEnabled {
+				return true, nil
+			}
+		}
+	}
+
+	// Version of TFE is unknowable
+	return false, nil
+}
+
+func shouldRenderPlan(run *tfe.Run) bool {
+	return !(run.Status == tfe.RunErrored || run.Status == tfe.RunCanceled ||
+		run.Status == tfe.RunDiscarded)
+}
+
+func shouldGenerateConfig(out string, run *tfe.Run) bool {
+	return (run.Plan.Status == tfe.PlanErrored || run.Plan.Status == tfe.PlanFinished) &&
+		run.Plan.GeneratedConfiguration && len(out) > 0
+}
+
+const planDefaultHeader = `
+[reset][yellow]Running plan in Terraform Cloud. Output will stream here. Pressing Ctrl-C
+will stop streaming the logs, but will not stop the plan running remotely.[reset]
+
+Preparing the remote plan...
+`
+
+const runHeader = `
+[reset][yellow]To view this run in a browser, visit:
+https://%s/app/%s/%s/runs/%s[reset]
+`
+
+// The newline in this error is to make it look good in the CLI!
+const lockTimeoutErr = `
+[reset][red]Lock timeout exceeded, sending interrupt to cancel the remote operation.
+[reset]
+`
diff --git a/v1.5.7/internal/cloud/backend_plan_test.go b/v1.5.7/internal/cloud/backend_plan_test.go
new file mode 100644
index 0000000..530ed0f
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_plan_test.go
@@ -0,0 +1,1518 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"context"
+	"net/http"
+	"os"
+	"os/signal"
+	"path/filepath"
+	"strings"
+	"syscall"
+	"testing"
+	"time"
+
+	"github.com/google/go-cmp/cmp"
+	tfe "github.com/hashicorp/go-tfe"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/jsonformat"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/mitchellh/cli"
+)
+
+func testOperationPlan(t *testing.T, configDir string) (*backend.Operation, func(), func(*testing.T) *terminal.TestOutput) {
+	t.Helper()
+
+	return testOperationPlanWithTimeout(t, configDir, 0)
+}
+
+func testOperationPlanWithTimeout(t *testing.T, configDir string, timeout time.Duration) (*backend.Operation, func(), func(*testing.T) *terminal.TestOutput) {
+	t.Helper()
+
+	_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewView(streams)
+	stateLockerView := views.NewStateLocker(arguments.ViewHuman, view)
+	operationView := views.NewOperation(arguments.ViewHuman, false, view)
+
+	// Many of our tests use an overridden "null" provider that's just in-memory
+	// inside the test process, not a separate plugin on disk.
+	depLocks := depsfile.NewLocks()
+	depLocks.SetProviderOverridden(addrs.MustParseProviderSourceString("registry.terraform.io/hashicorp/null"))
+
+	return &backend.Operation{
+		ConfigDir:       configDir,
+		ConfigLoader:    configLoader,
+		PlanRefresh:     true,
+		StateLocker:     clistate.NewLocker(timeout, stateLockerView),
+		Type:            backend.OperationTypePlan,
+		View:            operationView,
+		DependencyLocks: depLocks,
+	}, configCleanup, done
+}
+
+func TestCloud_planBasic(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatal("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+
+	stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
+	// An error suggests that the state was not unlocked after the operation finished
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after successful plan: %s", err.Error())
+	}
+}
+
+func TestCloud_planJSONBasic(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	stream, close := terminal.StreamsForTesting(t)
+
+	b.renderer = &jsonformat.Renderer{
+		Streams:  stream,
+		Colorize: mockColorize(),
+	}
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-json-basic")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	mockSROWorkspace(t, b, op.Workspace)
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatal("expected a non-empty plan")
+	}
+
+	outp := close(t)
+	gotOut := outp.Stdout()
+
+	if !strings.Contains(gotOut, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", gotOut)
+	}
+
+	stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
+	// An error suggests that the state was not unlocked after the operation finished
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after successful plan: %s", err.Error())
+	}
+}
+
+func TestCloud_planCanceled(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	// Stop the run to simulate a Ctrl-C.
+	run.Stop()
+
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+
+	stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
+	// An error suggests that the state was not unlocked after the operation finished
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after cancelled plan: %s", err.Error())
+	}
+}
+
+func TestCloud_planLongLine(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-long-line")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatal("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestCloud_planJSONFull(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	stream, close := terminal.StreamsForTesting(t)
+
+	b.renderer = &jsonformat.Renderer{
+		Streams:  stream,
+		Colorize: mockColorize(),
+	}
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-json-full")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	mockSROWorkspace(t, b, op.Workspace)
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatal("expected a non-empty plan")
+	}
+
+	outp := close(t)
+	gotOut := outp.Stdout()
+
+	if !strings.Contains(gotOut, "tfcoremock_simple_resource.example: Refreshing state... [id=my-simple-resource]") {
+		t.Fatalf("expected plan log: %s", gotOut)
+	}
+
+	if !strings.Contains(gotOut, "2 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", gotOut)
+	}
+
+	stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
+	// An error suggests that the state was not unlocked after the operation finished
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after successful plan: %s", err.Error())
+	}
+}
+
+func TestCloud_planWithoutPermissions(t *testing.T) {
+	b, bCleanup := testBackendWithTags(t)
+	defer bCleanup()
+
+	// Create a named workspace without permissions.
+	w, err := b.client.Workspaces.Create(
+		context.Background(),
+		b.organization,
+		tfe.WorkspaceCreateOptions{
+			Name: tfe.String("prod"),
+		},
+	)
+	if err != nil {
+		t.Fatalf("error creating named workspace: %v", err)
+	}
+	w.Permissions.CanQueueRun = false
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+
+	op.Workspace = "prod"
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "Insufficient rights to generate a plan") {
+		t.Fatalf("expected a permissions error, got: %v", errOutput)
+	}
+}
+
+func TestCloud_planWithParallelism(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+
+	if b.ContextOpts == nil {
+		b.ContextOpts = &terraform.ContextOpts{}
+	}
+	b.ContextOpts.Parallelism = 3
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "parallelism values are currently not supported") {
+		t.Fatalf("expected a parallelism error, got: %v", errOutput)
+	}
+}
+
+func TestCloud_planWithPlan(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+
+	op.PlanFile = &planfile.Reader{}
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "saved plan is currently not supported") {
+		t.Fatalf("expected a saved plan error, got: %v", errOutput)
+	}
+}
+
+func TestCloud_planWithPath(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+
+	op.PlanOutPath = "./testdata/plan"
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "generated plan is currently not supported") {
+		t.Fatalf("expected a generated plan error, got: %v", errOutput)
+	}
+}
+
+func TestCloud_planWithoutRefresh(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.PlanRefresh = false
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatal("expected a non-empty plan")
+	}
+
+	// We should find a run inside the mock client that has refresh set
+	// to false.
+	runsAPI := b.client.Runs.(*MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff(false, run.Refresh); diff != "" {
+			t.Errorf("wrong Refresh setting in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestCloud_planWithRefreshOnly(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.PlanMode = plans.RefreshOnlyMode
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatal("expected a non-empty plan")
+	}
+
+	// We should find a run inside the mock client that has refresh-only set
+	// to true.
+	runsAPI := b.client.Runs.(*MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff(true, run.RefreshOnly); diff != "" {
+			t.Errorf("wrong RefreshOnly setting in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestCloud_planWithTarget(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	// When the backend code creates a new run, we'll tweak it so that it
+	// has a cost estimation object with the "skipped_due_to_targeting" status,
+	// emulating how a real server is expected to behave in that case.
+	b.client.Runs.(*MockRuns).ModifyNewRun = func(client *MockClient, options tfe.RunCreateOptions, run *tfe.Run) {
+		const fakeID = "fake"
+		// This is the cost estimate object embedded in the run itself which
+		// the backend will use to learn the ID to request from the cost
+		// estimates endpoint. It's pending to simulate what a freshly-created
+		// run is likely to look like.
+		run.CostEstimate = &tfe.CostEstimate{
+			ID:     fakeID,
+			Status: "pending",
+		}
+		// The backend will then use the main cost estimation API to retrieve
+		// the same ID indicated in the object above, where we'll then return
+		// the status "skipped_due_to_targeting" to trigger the special skip
+		// message in the backend output.
+		client.CostEstimates.Estimations[fakeID] = &tfe.CostEstimate{
+			ID:     fakeID,
+			Status: "skipped_due_to_targeting",
+		}
+	}
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	addr, _ := addrs.ParseAbsResourceStr("null_resource.foo")
+
+	op.Targets = []addrs.Targetable{addr}
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatal("expected plan operation to succeed")
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected plan to be non-empty")
+	}
+
+	// testBackendDefault above attached a "mock UI" to our backend, so we
+	// can retrieve its non-error output via the OutputWriter in-memory buffer.
+	gotOutput := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if wantOutput := "Not available for this plan, because it was created with the -target option."; !strings.Contains(gotOutput, wantOutput) {
+		t.Errorf("missing message about skipped cost estimation\ngot:\n%s\nwant substring: %s", gotOutput, wantOutput)
+	}
+
+	// We should find a run inside the mock client that has the same
+	// target address we requested above.
+	runsAPI := b.client.Runs.(*MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff([]string{"null_resource.foo"}, run.TargetAddrs); diff != "" {
+			t.Errorf("wrong TargetAddrs in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestCloud_planWithReplace(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	addr, _ := addrs.ParseAbsResourceInstanceStr("null_resource.foo")
+
+	op.ForceReplace = []addrs.AbsResourceInstance{addr}
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatal("expected plan operation to succeed")
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected plan to be non-empty")
+	}
+
+	// We should find a run inside the mock client that has the same
+	// refresh address we requested above.
+	runsAPI := b.client.Runs.(*MockRuns)
+	if got, want := len(runsAPI.Runs), 1; got != want {
+		t.Fatalf("wrong number of runs in the mock client %d; want %d", got, want)
+	}
+	for _, run := range runsAPI.Runs {
+		if diff := cmp.Diff([]string{"null_resource.foo"}, run.ReplaceAddrs); diff != "" {
+			t.Errorf("wrong ReplaceAddrs in the created run\n%s", diff)
+		}
+	}
+}
+
+func TestCloud_planWithRequiredVariables(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-variables")
+	defer configCleanup()
+	defer done(t)
+
+	op.Variables = testVariables(terraform.ValueFromCLIArg, "foo") // "bar" variable defined in config is  missing
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	// The usual error of a required variable being missing is deferred and the operation
+	// is successful.
+	if run.Result != backend.OperationSuccess {
+		t.Fatal("expected plan operation to succeed")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in Terraform Cloud") {
+		t.Fatalf("unexpected TFC header in output: %s", output)
+	}
+}
+
+func TestCloud_planNoConfig(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/empty")
+	defer configCleanup()
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "configuration files found") {
+		t.Fatalf("expected configuration files error, got: %v", errOutput)
+	}
+}
+
+func TestCloud_planNoChanges(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-no-changes")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "No changes. Infrastructure is up-to-date.") {
+		t.Fatalf("expected no changes in plan summary: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: true") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+}
+
+func TestCloud_planForceLocal(t *testing.T) {
+	// Set TF_FORCE_LOCAL_BACKEND so the cloud backend will use
+	// the local backend with itself as embedded backend.
+	if err := os.Setenv("TF_FORCE_LOCAL_BACKEND", "1"); err != nil {
+		t.Fatalf("error setting environment variable TF_FORCE_LOCAL_BACKEND: %v", err)
+	}
+	defer os.Unsetenv("TF_FORCE_LOCAL_BACKEND")
+
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams))
+	op.View = view
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if strings.Contains(output, "Running plan in Terraform Cloud") {
+		t.Fatalf("unexpected TFC header in output: %s", output)
+	}
+	if output := done(t).Stdout(); !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestCloud_planWithoutOperationsEntitlement(t *testing.T) {
+	b, bCleanup := testBackendNoOperations(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams))
+	op.View = view
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if strings.Contains(output, "Running plan in Terraform Cloud") {
+		t.Fatalf("unexpected TFC header in output: %s", output)
+	}
+	if output := done(t).Stdout(); !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestCloud_planWorkspaceWithoutOperations(t *testing.T) {
+	b, bCleanup := testBackendWithTags(t)
+	defer bCleanup()
+
+	ctx := context.Background()
+
+	// Create a named workspace that doesn't allow operations.
+	_, err := b.client.Workspaces.Create(
+		ctx,
+		b.organization,
+		tfe.WorkspaceCreateOptions{
+			Name: tfe.String("no-operations"),
+		},
+	)
+	if err != nil {
+		t.Fatalf("error creating named workspace: %v", err)
+	}
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = "no-operations"
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams))
+	op.View = view
+
+	run, err := b.Operation(ctx, op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if strings.Contains(output, "Running plan in Terraform Cloud") {
+		t.Fatalf("unexpected TFC header in output: %s", output)
+	}
+	if output := done(t).Stdout(); !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestCloud_planLockTimeout(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	ctx := context.Background()
+
+	// Retrieve the workspace used to run this operation in.
+	w, err := b.client.Workspaces.Read(ctx, b.organization, b.WorkspaceMapping.Name)
+	if err != nil {
+		t.Fatalf("error retrieving workspace: %v", err)
+	}
+
+	// Create a new configuration version.
+	c, err := b.client.ConfigurationVersions.Create(ctx, w.ID, tfe.ConfigurationVersionCreateOptions{})
+	if err != nil {
+		t.Fatalf("error creating configuration version: %v", err)
+	}
+
+	// Create a pending run to block this run.
+	_, err = b.client.Runs.Create(ctx, tfe.RunCreateOptions{
+		ConfigurationVersion: c,
+		Workspace:            w,
+	})
+	if err != nil {
+		t.Fatalf("error creating pending run: %v", err)
+	}
+
+	op, configCleanup, done := testOperationPlanWithTimeout(t, "./testdata/plan", 50)
+	defer configCleanup()
+	defer done(t)
+
+	input := testInput(t, map[string]string{
+		"cancel":  "yes",
+		"approve": "yes",
+	})
+
+	op.UIIn = input
+	op.UIOut = b.CLI
+	op.Workspace = testBackendSingleWorkspaceName
+
+	_, err = b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	sigint := make(chan os.Signal, 1)
+	signal.Notify(sigint, syscall.SIGINT)
+	select {
+	case <-sigint:
+		// Stop redirecting SIGINT signals.
+		signal.Stop(sigint)
+	case <-time.After(200 * time.Millisecond):
+		t.Fatalf("expected lock timeout after 50 milliseconds, waited 200 milliseconds")
+	}
+
+	if len(input.answers) != 2 {
+		t.Fatalf("expected unused answers, got: %v", input.answers)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "Lock timeout exceeded") {
+		t.Fatalf("expected lock timout error in output: %s", output)
+	}
+	if strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("unexpected plan summary in output: %s", output)
+	}
+}
+
+func TestCloud_planDestroy(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.PlanMode = plans.DestroyMode
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+}
+
+func TestCloud_planDestroyNoConfig(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/empty")
+	defer configCleanup()
+	defer done(t)
+
+	op.PlanMode = plans.DestroyMode
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+}
+
+func TestCloud_planWithWorkingDirectory(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	options := tfe.WorkspaceUpdateOptions{
+		WorkingDirectory: tfe.String("terraform"),
+	}
+
+	// Configure the workspace to use a custom working directory.
+	_, err := b.client.Workspaces.Update(context.Background(), b.organization, b.WorkspaceMapping.Name, options)
+	if err != nil {
+		t.Fatalf("error configuring working directory: %v", err)
+	}
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-with-working-directory/terraform")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "The remote workspace is configured to work with configuration") {
+		t.Fatalf("expected working directory warning: %s", output)
+	}
+	if !strings.Contains(output, "Running plan in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestCloud_planWithWorkingDirectoryFromCurrentPath(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	options := tfe.WorkspaceUpdateOptions{
+		WorkingDirectory: tfe.String("terraform"),
+	}
+
+	// Configure the workspace to use a custom working directory.
+	_, err := b.client.Workspaces.Update(context.Background(), b.organization, b.WorkspaceMapping.Name, options)
+	if err != nil {
+		t.Fatalf("error configuring working directory: %v", err)
+	}
+
+	wd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("error getting current working directory: %v", err)
+	}
+
+	// We need to change into the configuration directory to make sure
+	// the logic to upload the correct slug is working as expected.
+	if err := os.Chdir("./testdata/plan-with-working-directory/terraform"); err != nil {
+		t.Fatalf("error changing directory: %v", err)
+	}
+	defer os.Chdir(wd) // Make sure we change back again when were done.
+
+	// For this test we need to give our current directory instead of the
+	// full path to the configuration as we already changed directories.
+	op, configCleanup, done := testOperationPlan(t, ".")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestCloud_planCostEstimation(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-cost-estimation")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "Resources: 1 of 1 estimated") {
+		t.Fatalf("expected cost estimate result in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestCloud_planPolicyPass(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-policy-passed")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatalf("expected a non-empty plan")
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: true") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestCloud_planPolicyHardFail(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-policy-hard-failed")
+	defer configCleanup()
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	viewOutput := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := viewOutput.Stderr()
+	if !strings.Contains(errOutput, "hard failed") {
+		t.Fatalf("expected a policy check error, got: %v", errOutput)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: false") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestCloud_planPolicySoftFail(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-policy-soft-failed")
+	defer configCleanup()
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	viewOutput := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if !run.PlanEmpty {
+		t.Fatalf("expected plan to be empty")
+	}
+
+	errOutput := viewOutput.Stderr()
+	if !strings.Contains(errOutput, "soft failed") {
+		t.Fatalf("expected a policy check error, got: %v", errOutput)
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "Sentinel Result: false") {
+		t.Fatalf("expected policy check result in output: %s", output)
+	}
+	if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", output)
+	}
+}
+
+func TestCloud_planWithRemoteError(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-with-error")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if run.Result.ExitStatus() != 1 {
+		t.Fatalf("expected exit code 1, got %d", run.Result.ExitStatus())
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Running plan in Terraform Cloud") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+	if !strings.Contains(output, "null_resource.foo: 1 error") {
+		t.Fatalf("expected plan error in output: %s", output)
+	}
+}
+
+func TestCloud_planJSONWithRemoteError(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	stream, close := terminal.StreamsForTesting(t)
+
+	// Initialize the plan renderer
+	b.renderer = &jsonformat.Renderer{
+		Streams:  stream,
+		Colorize: mockColorize(),
+	}
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-json-error")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	mockSROWorkspace(t, b, op.Workspace)
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+	if run.Result.ExitStatus() != 1 {
+		t.Fatalf("expected exit code 1, got %d", run.Result.ExitStatus())
+	}
+
+	outp := close(t)
+	gotOut := outp.Stdout()
+
+	if !strings.Contains(gotOut, "Unsupported block type") {
+		t.Fatalf("unexpected plan error in output: %s", gotOut)
+	}
+}
+
+func TestCloud_planOtherError(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	op.Workspace = "network-error" // custom error response in backend_mock.go
+
+	_, err := b.Operation(context.Background(), op)
+	if err == nil {
+		t.Errorf("expected error, got success")
+	}
+
+	if !strings.Contains(err.Error(),
+		"Terraform Cloud returned an unexpected error:\n\nI'm a little teacup") {
+		t.Fatalf("expected error message, got: %s", err.Error())
+	}
+}
+
+func TestCloud_planImportConfigGeneration(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	stream, close := terminal.StreamsForTesting(t)
+
+	b.renderer = &jsonformat.Renderer{
+		Streams:  stream,
+		Colorize: mockColorize(),
+	}
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-import-config-gen")
+	defer configCleanup()
+	defer done(t)
+
+	genPath := filepath.Join(op.ConfigDir, "generated.tf")
+	op.GenerateConfigOut = genPath
+	defer os.Remove(genPath)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	mockSROWorkspace(t, b, op.Workspace)
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+	if run.PlanEmpty {
+		t.Fatal("expected a non-empty plan")
+	}
+	outp := close(t)
+	gotOut := outp.Stdout()
+
+	if !strings.Contains(gotOut, "1 to import, 0 to add, 0 to change, 0 to destroy") {
+		t.Fatalf("expected plan summary in output: %s", gotOut)
+	}
+
+	stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
+	// An error suggests that the state was not unlocked after the operation finished
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after successful plan: %s", err.Error())
+	}
+
+	testFileEquals(t, genPath, filepath.Join(op.ConfigDir, "generated.tf.expected"))
+}
+
+func TestCloud_planImportGenerateInvalidConfig(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	stream, close := terminal.StreamsForTesting(t)
+
+	b.renderer = &jsonformat.Renderer{
+		Streams:  stream,
+		Colorize: mockColorize(),
+	}
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-import-config-gen-validation-error")
+	defer configCleanup()
+	defer done(t)
+
+	genPath := filepath.Join(op.ConfigDir, "generated.tf")
+	op.GenerateConfigOut = genPath
+	defer os.Remove(genPath)
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	mockSROWorkspace(t, b, op.Workspace)
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationFailure {
+		t.Fatalf("expected operation to fail")
+	}
+	if run.Result.ExitStatus() != 1 {
+		t.Fatalf("expected exit code 1, got %d", run.Result.ExitStatus())
+	}
+
+	outp := close(t)
+	gotOut := outp.Stdout()
+
+	if !strings.Contains(gotOut, "Conflicting configuration arguments") {
+		t.Fatalf("Expected error in output: %s", gotOut)
+	}
+
+	testFileEquals(t, genPath, filepath.Join(op.ConfigDir, "generated.tf.expected"))
+}
+
+func TestCloud_planInvalidGenConfigOutPath(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan-import-config-gen-exists")
+	defer configCleanup()
+
+	genPath := filepath.Join(op.ConfigDir, "generated.tf")
+	op.GenerateConfigOut = genPath
+
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	output := done(t)
+	if run.Result == backend.OperationSuccess {
+		t.Fatal("expected plan operation to fail")
+	}
+
+	errOutput := output.Stderr()
+	if !strings.Contains(errOutput, "generated file already exists") {
+		t.Fatalf("expected configuration files error, got: %v", errOutput)
+	}
+}
+
+func TestCloud_planShouldRenderSRO(t *testing.T) {
+	t.Run("when instance is TFC", func(t *testing.T) {
+		handlers := map[string]func(http.ResponseWriter, *http.Request){
+			"/api/v2/ping": func(w http.ResponseWriter, r *http.Request) {
+				w.Header().Set("Content-Type", "application/json")
+				w.Header().Set("TFP-API-Version", "2.5")
+				w.Header().Set("TFP-AppName", "Terraform Cloud")
+			},
+		}
+		b, bCleanup := testBackendWithHandlers(t, handlers)
+		t.Cleanup(bCleanup)
+		b.renderer = &jsonformat.Renderer{}
+
+		t.Run("and SRO is enabled", func(t *testing.T) {
+			r := &tfe.Run{
+				Workspace: &tfe.Workspace{
+					StructuredRunOutputEnabled: true,
+				},
+			}
+			assertSRORendered(t, b, r, true)
+		})
+
+		t.Run("and SRO is not enabled", func(t *testing.T) {
+			r := &tfe.Run{
+				Workspace: &tfe.Workspace{
+					StructuredRunOutputEnabled: false,
+				},
+			}
+			assertSRORendered(t, b, r, false)
+		})
+
+	})
+
+	t.Run("when instance is TFE and version supports CLI SRO", func(t *testing.T) {
+		handlers := map[string]func(http.ResponseWriter, *http.Request){
+			"/api/v2/ping": func(w http.ResponseWriter, r *http.Request) {
+				w.Header().Set("Content-Type", "application/json")
+				w.Header().Set("TFP-API-Version", "2.5")
+				w.Header().Set("TFP-AppName", "Terraform Enterprise")
+				w.Header().Set("X-TFE-Version", "v202303-1")
+			},
+		}
+		b, bCleanup := testBackendWithHandlers(t, handlers)
+		t.Cleanup(bCleanup)
+		b.renderer = &jsonformat.Renderer{}
+
+		t.Run("and SRO is enabled", func(t *testing.T) {
+			r := &tfe.Run{
+				Workspace: &tfe.Workspace{
+					StructuredRunOutputEnabled: true,
+				},
+			}
+			assertSRORendered(t, b, r, true)
+		})
+
+		t.Run("and SRO is not enabled", func(t *testing.T) {
+			r := &tfe.Run{
+				Workspace: &tfe.Workspace{
+					StructuredRunOutputEnabled: false,
+				},
+			}
+			assertSRORendered(t, b, r, false)
+		})
+	})
+
+	t.Run("when instance is a known unsupported TFE release", func(t *testing.T) {
+		handlers := map[string]func(http.ResponseWriter, *http.Request){
+			"/api/v2/ping": func(w http.ResponseWriter, r *http.Request) {
+				w.Header().Set("Content-Type", "application/json")
+				w.Header().Set("TFP-API-Version", "2.5")
+				w.Header().Set("TFP-AppName", "Terraform Enterprise")
+				w.Header().Set("X-TFE-Version", "v202208-1")
+			},
+		}
+		b, bCleanup := testBackendWithHandlers(t, handlers)
+		t.Cleanup(bCleanup)
+		b.renderer = &jsonformat.Renderer{}
+
+		r := &tfe.Run{
+			Workspace: &tfe.Workspace{
+				StructuredRunOutputEnabled: true,
+			},
+		}
+		assertSRORendered(t, b, r, false)
+	})
+
+	t.Run("when instance is an unknown TFE release", func(t *testing.T) {
+		handlers := map[string]func(http.ResponseWriter, *http.Request){
+			"/api/v2/ping": func(w http.ResponseWriter, r *http.Request) {
+				w.Header().Set("Content-Type", "application/json")
+				w.Header().Set("TFP-API-Version", "2.5")
+			},
+		}
+		b, bCleanup := testBackendWithHandlers(t, handlers)
+		t.Cleanup(bCleanup)
+		b.renderer = &jsonformat.Renderer{}
+
+		r := &tfe.Run{
+			Workspace: &tfe.Workspace{
+				StructuredRunOutputEnabled: true,
+			},
+		}
+		assertSRORendered(t, b, r, false)
+	})
+
+}
+
+func assertSRORendered(t *testing.T, b *Cloud, r *tfe.Run, shouldRender bool) {
+	got, err := b.shouldRenderStructuredRunOutput(r)
+	if err != nil {
+		t.Fatalf("expected no error: %v", err)
+	}
+	if shouldRender != got {
+		t.Fatalf("expected SRO to be rendered: %t, got %t", shouldRender, got)
+	}
+}
+
+func testFileEquals(t *testing.T, got, want string) {
+	t.Helper()
+
+	actual, err := os.ReadFile(got)
+	if err != nil {
+		t.Fatalf("error reading %s", got)
+	}
+
+	expected, err := os.ReadFile(want)
+	if err != nil {
+		t.Fatalf("error reading %s", want)
+	}
+
+	if diff := cmp.Diff(string(actual), string(expected)); len(diff) > 0 {
+		t.Fatalf("got:\n%s\nwant:\n%s\ndiff:\n%s", actual, expected, diff)
+	}
+}
diff --git a/v1.5.7/internal/cloud/backend_refresh_test.go b/v1.5.7/internal/cloud/backend_refresh_test.go
new file mode 100644
index 0000000..29cc846
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_refresh_test.go
@@ -0,0 +1,82 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"context"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/mitchellh/cli"
+)
+
+func testOperationRefresh(t *testing.T, configDir string) (*backend.Operation, func(), func(*testing.T) *terminal.TestOutput) {
+	t.Helper()
+
+	return testOperationRefreshWithTimeout(t, configDir, 0)
+}
+
+func testOperationRefreshWithTimeout(t *testing.T, configDir string, timeout time.Duration) (*backend.Operation, func(), func(*testing.T) *terminal.TestOutput) {
+	t.Helper()
+
+	_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
+
+	streams, done := terminal.StreamsForTesting(t)
+	view := views.NewView(streams)
+	stateLockerView := views.NewStateLocker(arguments.ViewHuman, view)
+	operationView := views.NewOperation(arguments.ViewHuman, false, view)
+
+	return &backend.Operation{
+		ConfigDir:    configDir,
+		ConfigLoader: configLoader,
+		PlanRefresh:  true,
+		StateLocker:  clistate.NewLocker(timeout, stateLockerView),
+		Type:         backend.OperationTypeRefresh,
+		View:         operationView,
+	}, configCleanup, done
+}
+
+func TestCloud_refreshBasicActuallyRunsApplyRefresh(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	op, configCleanup, done := testOperationRefresh(t, "./testdata/refresh")
+	defer configCleanup()
+	defer done(t)
+
+	op.UIOut = b.CLI
+	b.CLIColor = b.cliColorize()
+	op.PlanMode = plans.RefreshOnlyMode
+	op.Workspace = testBackendSingleWorkspaceName
+
+	run, err := b.Operation(context.Background(), op)
+	if err != nil {
+		t.Fatalf("error starting operation: %v", err)
+	}
+
+	<-run.Done()
+	if run.Result != backend.OperationSuccess {
+		t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
+	}
+
+	output := b.CLI.(*cli.MockUi).OutputWriter.String()
+	if !strings.Contains(output, "Proceeding with 'terraform apply -refresh-only -auto-approve'") {
+		t.Fatalf("expected TFC header in output: %s", output)
+	}
+
+	stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
+	// An error suggests that the state was not unlocked after apply
+	if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
+		t.Fatalf("unexpected error locking state after apply: %s", err.Error())
+	}
+}
diff --git a/v1.5.7/internal/cloud/backend_run_warning.go b/v1.5.7/internal/cloud/backend_run_warning.go
new file mode 100644
index 0000000..c9c766c
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_run_warning.go
@@ -0,0 +1,49 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"context"
+	"fmt"
+	"strings"
+
+	tfe "github.com/hashicorp/go-tfe"
+)
+
+const (
+	changedPolicyEnforcementAction = "changed_policy_enforcements"
+	changedTaskEnforcementAction   = "changed_task_enforcements"
+	ignoredPolicySetAction         = "ignored_policy_sets"
+)
+
+func (b *Cloud) renderRunWarnings(ctx context.Context, client *tfe.Client, runId string) error {
+	if b.CLI == nil {
+		return nil
+	}
+
+	result, err := client.RunEvents.List(ctx, runId, nil)
+	if err != nil {
+		return err
+	}
+	if result == nil {
+		return nil
+	}
+
+	// We don't have to worry about paging as the API doesn't support it yet
+	for _, re := range result.Items {
+		switch re.Action {
+		case changedPolicyEnforcementAction, changedTaskEnforcementAction, ignoredPolicySetAction:
+			if re.Description != "" {
+				b.CLI.Warn(b.Colorize().Color(strings.TrimSpace(fmt.Sprintf(
+					runWarningHeader, re.Description)) + "\n"))
+			}
+		}
+	}
+
+	return nil
+}
+
+const runWarningHeader = `
+[reset][yellow]Warning:[reset] %s
+`
diff --git a/v1.5.7/internal/cloud/backend_run_warning_test.go b/v1.5.7/internal/cloud/backend_run_warning_test.go
new file mode 100644
index 0000000..34fe27f
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_run_warning_test.go
@@ -0,0 +1,156 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"context"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/golang/mock/gomock"
+	"github.com/hashicorp/go-tfe"
+	tfemocks "github.com/hashicorp/go-tfe/mocks"
+	"github.com/mitchellh/cli"
+)
+
+func MockAllRunEvents(t *testing.T, client *tfe.Client) (fullRunID string, emptyRunID string) {
+	ctrl := gomock.NewController(t)
+
+	fullRunID = "run-full"
+	emptyRunID = "run-empty"
+
+	mockRunEventsAPI := tfemocks.NewMockRunEvents(ctrl)
+
+	emptyList := tfe.RunEventList{
+		Items: []*tfe.RunEvent{},
+	}
+	fullList := tfe.RunEventList{
+		Items: []*tfe.RunEvent{
+			{
+				Action:      "created",
+				CreatedAt:   time.Now(),
+				Description: "",
+			},
+			{
+				Action:      "changed_task_enforcements",
+				CreatedAt:   time.Now(),
+				Description: "The enforcement level for task 'MockTask' was changed to 'advisory' because the run task limit was exceeded.",
+			},
+			{
+				Action:      "changed_policy_enforcements",
+				CreatedAt:   time.Now(),
+				Description: "The enforcement level for policy 'MockPolicy' was changed to 'advisory' because the policy limit was exceeded.",
+			},
+			{
+				Action:      "ignored_policy_sets",
+				CreatedAt:   time.Now(),
+				Description: "The policy set 'MockPolicySet' was ignored because the versioned policy set limit was exceeded.",
+			},
+			{
+				Action:      "queued",
+				CreatedAt:   time.Now(),
+				Description: "",
+			},
+		},
+	}
+	// Mock Full Request
+	mockRunEventsAPI.
+		EXPECT().
+		List(gomock.Any(), fullRunID, gomock.Any()).
+		Return(&fullList, nil).
+		AnyTimes()
+
+	// Mock Full Request
+	mockRunEventsAPI.
+		EXPECT().
+		List(gomock.Any(), emptyRunID, gomock.Any()).
+		Return(&emptyList, nil).
+		AnyTimes()
+
+	// Mock a bad Read response
+	mockRunEventsAPI.
+		EXPECT().
+		List(gomock.Any(), gomock.Any(), gomock.Any()).
+		Return(nil, tfe.ErrInvalidRunID).
+		AnyTimes()
+
+	// Wire up the mock interfaces
+	client.RunEvents = mockRunEventsAPI
+	return
+}
+
+func TestRunEventWarningsAll(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	config := &tfe.Config{
+		Token: "not-a-token",
+	}
+	client, _ := tfe.NewClient(config)
+	fullRunID, _ := MockAllRunEvents(t, client)
+
+	ctx := context.TODO()
+
+	err := b.renderRunWarnings(ctx, client, fullRunID)
+	if err != nil {
+		t.Fatalf("Expected to not error but received %s", err)
+	}
+
+	output := b.CLI.(*cli.MockUi).ErrorWriter.String()
+	testString := "The enforcement level for task 'MockTask'"
+	if !strings.Contains(output, testString) {
+		t.Fatalf("Expected %q to contain %q but it did not", output, testString)
+	}
+	testString = "The enforcement level for policy 'MockPolicy'"
+	if !strings.Contains(output, testString) {
+		t.Fatalf("Expected %q to contain %q but it did not", output, testString)
+	}
+	testString = "The policy set 'MockPolicySet'"
+	if !strings.Contains(output, testString) {
+		t.Fatalf("Expected %q to contain %q but it did not", output, testString)
+	}
+}
+
+func TestRunEventWarningsEmpty(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	config := &tfe.Config{
+		Token: "not-a-token",
+	}
+	client, _ := tfe.NewClient(config)
+	_, emptyRunID := MockAllRunEvents(t, client)
+
+	ctx := context.TODO()
+
+	err := b.renderRunWarnings(ctx, client, emptyRunID)
+	if err != nil {
+		t.Fatalf("Expected to not error but received %s", err)
+	}
+
+	output := b.CLI.(*cli.MockUi).ErrorWriter.String()
+	if output != "" {
+		t.Fatalf("Expected %q to be empty but it was not", output)
+	}
+}
+
+func TestRunEventWarningsWithError(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	config := &tfe.Config{
+		Token: "not-a-token",
+	}
+	client, _ := tfe.NewClient(config)
+	MockAllRunEvents(t, client)
+
+	ctx := context.TODO()
+
+	err := b.renderRunWarnings(ctx, client, "bad run id")
+
+	if err == nil {
+		t.Error("Expected to error but did not")
+	}
+}
diff --git a/v1.5.7/internal/cloud/backend_taskStage_policyEvaluation.go b/v1.5.7/internal/cloud/backend_taskStage_policyEvaluation.go
new file mode 100644
index 0000000..06c8a3a
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_taskStage_policyEvaluation.go
@@ -0,0 +1,160 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/go-tfe"
+)
+
+type policyEvaluationSummary struct {
+	unreachable bool
+	pending     int
+	failed      int
+	passed      int
+}
+
+type Symbol rune
+
+const (
+	Tick          Symbol = '\u2713'
+	Cross         Symbol = '\u00d7'
+	Warning       Symbol = '\u24be'
+	Arrow         Symbol = '\u2192'
+	DownwardArrow Symbol = '\u21b3'
+)
+
+type policyEvaluationSummarizer struct {
+	finished bool
+	cloud    *Cloud
+	counter  int
+}
+
+func newPolicyEvaluationSummarizer(b *Cloud, ts *tfe.TaskStage) taskStageSummarizer {
+	if len(ts.PolicyEvaluations) == 0 {
+		return nil
+	}
+	return &policyEvaluationSummarizer{
+		finished: false,
+		cloud:    b,
+	}
+}
+
+func (pes *policyEvaluationSummarizer) Summarize(context *IntegrationContext, output IntegrationOutputWriter, ts *tfe.TaskStage) (bool, *string, error) {
+	if pes.counter == 0 {
+		output.Output("[bold]OPA Policy Evaluation\n")
+		pes.counter++
+	}
+
+	if pes.finished {
+		return false, nil, nil
+	}
+
+	counts := summarizePolicyEvaluationResults(ts.PolicyEvaluations)
+
+	if counts.pending != 0 {
+		pendingMessage := "Evaluating ... "
+		return true, &pendingMessage, nil
+	}
+
+	if counts.unreachable {
+		output.Output("Skipping policy evaluation.")
+		output.End()
+		return false, nil, nil
+	}
+
+	// Print out the summary
+	if err := pes.taskStageWithPolicyEvaluation(context, output, ts.PolicyEvaluations); err != nil {
+		return false, nil, err
+	}
+	// Mark as finished
+	pes.finished = true
+
+	return false, nil, nil
+}
+
+func summarizePolicyEvaluationResults(policyEvaluations []*tfe.PolicyEvaluation) *policyEvaluationSummary {
+	var pendingCount, errCount, passedCount int
+	for _, policyEvaluation := range policyEvaluations {
+		switch policyEvaluation.Status {
+		case "unreachable":
+			return &policyEvaluationSummary{
+				unreachable: true,
+			}
+		case "running", "pending", "queued":
+			pendingCount++
+		case "passed":
+			passedCount++
+		default:
+			// Everything else is a failure
+			errCount++
+		}
+	}
+
+	return &policyEvaluationSummary{
+		unreachable: false,
+		pending:     pendingCount,
+		failed:      errCount,
+		passed:      passedCount,
+	}
+}
+
+func (pes *policyEvaluationSummarizer) taskStageWithPolicyEvaluation(context *IntegrationContext, output IntegrationOutputWriter, policyEvaluation []*tfe.PolicyEvaluation) error {
+	var result, message string
+	// Currently only one policy evaluation supported : OPA
+	for _, polEvaluation := range policyEvaluation {
+		if polEvaluation.Status == tfe.PolicyEvaluationPassed {
+			message = "[dim] This result means that all OPA policies passed and the protected behavior is allowed"
+			result = fmt.Sprintf("[green]%s", strings.ToUpper(string(tfe.PolicyEvaluationPassed)))
+			if polEvaluation.ResultCount.AdvisoryFailed > 0 {
+				result += " (with advisory)"
+			}
+		} else {
+			message = "[dim] This result means that one or more OPA policies failed. More than likely, this was due to the discovery of violations by the main rule and other sub rules"
+			result = fmt.Sprintf("[red]%s", strings.ToUpper(string(tfe.PolicyEvaluationFailed)))
+		}
+
+		output.Output(fmt.Sprintf("[bold]%c%c Overall Result: %s", Arrow, Arrow, result))
+
+		output.Output(message)
+
+		total := getPolicyCount(polEvaluation.ResultCount)
+
+		output.Output(fmt.Sprintf("%d policies evaluated\n", total))
+
+		policyOutcomes, err := pes.cloud.client.PolicySetOutcomes.List(context.StopContext, polEvaluation.ID, nil)
+		if err != nil {
+			return err
+		}
+
+		for i, out := range policyOutcomes.Items {
+			output.Output(fmt.Sprintf("%c Policy set %d: [bold]%s (%d)", Arrow, i+1, out.PolicySetName, len(out.Outcomes)))
+			for _, outcome := range out.Outcomes {
+				output.Output(fmt.Sprintf("  %c Policy name: [bold]%s", DownwardArrow, outcome.PolicyName))
+				switch outcome.Status {
+				case "passed":
+					output.Output(fmt.Sprintf("     | [green][bold]%c Passed", Tick))
+				case "failed":
+					if outcome.EnforcementLevel == tfe.EnforcementAdvisory {
+						output.Output(fmt.Sprintf("     | [blue][bold]%c Advisory", Warning))
+					} else {
+						output.Output(fmt.Sprintf("     | [red][bold]%c Failed", Cross))
+					}
+				}
+				if outcome.Description != "" {
+					output.Output(fmt.Sprintf("     | [dim]%s", outcome.Description))
+				} else {
+					output.Output("     | [dim]No description available")
+				}
+			}
+		}
+	}
+	return nil
+}
+
+func getPolicyCount(resultCount *tfe.PolicyResultCount) int {
+	return resultCount.AdvisoryFailed + resultCount.MandatoryFailed + resultCount.Errored + resultCount.Passed
+}
diff --git a/v1.5.7/internal/cloud/backend_taskStage_policyEvaluation_test.go b/v1.5.7/internal/cloud/backend_taskStage_policyEvaluation_test.go
new file mode 100644
index 0000000..d73169b
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_taskStage_policyEvaluation_test.go
@@ -0,0 +1,100 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/go-tfe"
+)
+
+func TestCloud_runTaskStageWithPolicyEvaluation(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	integrationContext, writer := newMockIntegrationContext(b, t)
+
+	cases := map[string]struct {
+		taskStage       func() *tfe.TaskStage
+		context         *IntegrationContext
+		writer          *testIntegrationOutput
+		expectedOutputs []string
+		isError         bool
+	}{
+		"all-succeeded": {
+			taskStage: func() *tfe.TaskStage {
+				ts := &tfe.TaskStage{}
+				ts.PolicyEvaluations = []*tfe.PolicyEvaluation{
+					{ID: "pol-pass", ResultCount: &tfe.PolicyResultCount{Passed: 1}, Status: "passed"},
+				}
+				return ts
+			},
+			writer:          writer,
+			context:         integrationContext,
+			expectedOutputs: []string{"│ [bold]OPA Policy Evaluation\n\n│ [bold]→→ Overall Result: [green]PASSED\n│ [dim] This result means that all OPA policies passed and the protected behavior is allowed\n│ 1 policies evaluated\n\n│ → Policy set 1: [bold]policy-set-that-passes (1)\n│   ↳ Policy name: [bold]policy-pass\n│      | [green][bold]✓ Passed\n│      | [dim]This policy will pass\n"},
+			isError:         false,
+		},
+		"mandatory-failed": {
+			taskStage: func() *tfe.TaskStage {
+				ts := &tfe.TaskStage{}
+				ts.PolicyEvaluations = []*tfe.PolicyEvaluation{
+					{ID: "pol-fail", ResultCount: &tfe.PolicyResultCount{MandatoryFailed: 1}, Status: "failed"},
+				}
+				return ts
+			},
+			writer:          writer,
+			context:         integrationContext,
+			expectedOutputs: []string{"│ [bold]→→ Overall Result: [red]FAILED\n│ [dim] This result means that one or more OPA policies failed. More than likely, this was due to the discovery of violations by the main rule and other sub rules\n│ 1 policies evaluated\n\n│ → Policy set 1: [bold]policy-set-that-fails (1)\n│   ↳ Policy name: [bold]policy-fail\n│      | [red][bold]× Failed\n│      | [dim]This policy will fail"},
+			isError:         true,
+		},
+		"advisory-failed": {
+			taskStage: func() *tfe.TaskStage {
+				ts := &tfe.TaskStage{}
+				ts.PolicyEvaluations = []*tfe.PolicyEvaluation{
+					{ID: "adv-fail", ResultCount: &tfe.PolicyResultCount{AdvisoryFailed: 1}, Status: "failed"},
+				}
+				return ts
+			},
+			writer:          writer,
+			context:         integrationContext,
+			expectedOutputs: []string{"│ [bold]OPA Policy Evaluation\n\n│ [bold]→→ Overall Result: [red]FAILED\n│ [dim] This result means that one or more OPA policies failed. More than likely, this was due to the discovery of violations by the main rule and other sub rules\n│ 1 policies evaluated\n\n│ → Policy set 1: [bold]policy-set-that-fails (1)\n│   ↳ Policy name: [bold]policy-fail\n│      | [blue][bold]Ⓘ Advisory\n│      | [dim]This policy will fail"},
+			isError:         false,
+		},
+		"unreachable": {
+			taskStage: func() *tfe.TaskStage {
+				ts := &tfe.TaskStage{}
+				ts.PolicyEvaluations = []*tfe.PolicyEvaluation{
+					{ID: "adv-fail", ResultCount: &tfe.PolicyResultCount{Errored: 1}, Status: "unreachable"},
+				}
+				return ts
+			},
+			writer:          writer,
+			context:         integrationContext,
+			expectedOutputs: []string{"Skipping policy evaluation."},
+			isError:         false,
+		},
+	}
+
+	for _, c := range cases {
+		c.writer.output.Reset()
+		trs := policyEvaluationSummarizer{
+			cloud: b,
+		}
+		c.context.Poll(0, 0, func(i int) (bool, error) {
+			cont, _, _ := trs.Summarize(c.context, c.writer, c.taskStage())
+			if cont {
+				return true, nil
+			}
+
+			output := c.writer.output.String()
+			for _, expected := range c.expectedOutputs {
+				if !strings.Contains(output, expected) {
+					t.Fatalf("Expected output to contain '%s' but it was:\n\n%s", expected, output)
+				}
+			}
+			return false, nil
+		})
+	}
+}
diff --git a/v1.5.7/internal/cloud/backend_taskStage_taskResults.go b/v1.5.7/internal/cloud/backend_taskStage_taskResults.go
new file mode 100644
index 0000000..d12ee29
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_taskStage_taskResults.go
@@ -0,0 +1,150 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/go-tfe"
+)
+
+type taskResultSummary struct {
+	unreachable     bool
+	pending         int
+	failed          int
+	failedMandatory int
+	passed          int
+}
+
+type taskResultSummarizer struct {
+	finished bool
+	cloud    *Cloud
+	counter  int
+}
+
+func newTaskResultSummarizer(b *Cloud, ts *tfe.TaskStage) taskStageSummarizer {
+	if len(ts.TaskResults) == 0 {
+		return nil
+	}
+	return &taskResultSummarizer{
+		finished: false,
+		cloud:    b,
+	}
+}
+
+func (trs *taskResultSummarizer) Summarize(context *IntegrationContext, output IntegrationOutputWriter, ts *tfe.TaskStage) (bool, *string, error) {
+	if trs.finished {
+		return false, nil, nil
+	}
+	trs.counter++
+
+	counts := summarizeTaskResults(ts.TaskResults)
+
+	if counts.pending != 0 {
+		pendingMessage := "%d tasks still pending, %d passed, %d failed ... "
+		message := fmt.Sprintf(pendingMessage, counts.pending, counts.passed, counts.failed)
+		return true, &message, nil
+	}
+	if counts.unreachable {
+		output.Output("Skipping task results.")
+		output.End()
+		return false, nil, nil
+	}
+
+	// Print out the summary
+	trs.runTasksWithTaskResults(output, ts.TaskResults, counts)
+
+	// Mark as finished
+	trs.finished = true
+
+	return false, nil, nil
+}
+
+func summarizeTaskResults(taskResults []*tfe.TaskResult) *taskResultSummary {
+	var pendingCount, errCount, errMandatoryCount, passedCount int
+	for _, task := range taskResults {
+		if task.Status == tfe.TaskUnreachable {
+			return &taskResultSummary{
+				unreachable: true,
+			}
+		} else if task.Status == tfe.TaskRunning || task.Status == tfe.TaskPending {
+			pendingCount++
+		} else if task.Status == tfe.TaskPassed {
+			passedCount++
+		} else {
+			// Everything else is a failure
+			errCount++
+			if task.WorkspaceTaskEnforcementLevel == tfe.Mandatory {
+				errMandatoryCount++
+			}
+		}
+	}
+
+	return &taskResultSummary{
+		unreachable:     false,
+		pending:         pendingCount,
+		failed:          errCount,
+		failedMandatory: errMandatoryCount,
+		passed:          passedCount,
+	}
+}
+
+func (trs *taskResultSummarizer) runTasksWithTaskResults(output IntegrationOutputWriter, taskResults []*tfe.TaskResult, count *taskResultSummary) {
+	// Track the first task name that is a mandatory enforcement level breach.
+	var firstMandatoryTaskFailed *string = nil
+
+	if trs.counter == 0 {
+		output.Output(fmt.Sprintf("All tasks completed! %d passed, %d failed", count.passed, count.failed))
+	} else {
+		output.OutputElapsed(fmt.Sprintf("All tasks completed! %d passed, %d failed", count.passed, count.failed), 50)
+	}
+
+	output.Output("")
+
+	for _, t := range taskResults {
+		capitalizedStatus := string(t.Status)
+		capitalizedStatus = strings.ToUpper(capitalizedStatus[:1]) + capitalizedStatus[1:]
+
+		status := "[green]" + capitalizedStatus
+		if t.Status != "passed" {
+			level := string(t.WorkspaceTaskEnforcementLevel)
+			level = strings.ToUpper(level[:1]) + level[1:]
+			status = fmt.Sprintf("[red]%s (%s)", capitalizedStatus, level)
+
+			if t.WorkspaceTaskEnforcementLevel == "mandatory" && firstMandatoryTaskFailed == nil {
+				firstMandatoryTaskFailed = &t.TaskName
+			}
+		}
+
+		title := fmt.Sprintf(`%s ⸺   %s`, t.TaskName, status)
+		output.SubOutput(title)
+
+		if len(t.Message) > 0 {
+			output.SubOutput(fmt.Sprintf("[dim]%s", t.Message))
+		}
+		if len(t.URL) > 0 {
+			output.SubOutput(fmt.Sprintf("[dim]Details: %s", t.URL))
+		}
+		output.SubOutput("")
+	}
+
+	// If a mandatory enforcement level is breached, return an error.
+	var overall string = "[green]Passed"
+	if firstMandatoryTaskFailed != nil {
+		overall = "[red]Failed"
+		if count.failedMandatory > 1 {
+			output.Output(fmt.Sprintf("[reset][bold][red]Error:[reset][bold]the run failed because %d mandatory tasks are required to succeed", count.failedMandatory))
+		} else {
+			output.Output(fmt.Sprintf("[reset][bold][red]Error: [reset][bold]the run failed because the run task, %s, is required to succeed", *firstMandatoryTaskFailed))
+		}
+	} else if count.failed > 0 { // we have failures but none of them mandatory
+		overall = "[green]Passed with advisory failures"
+	}
+
+	output.SubOutput("")
+	output.SubOutput("[bold]Overall Result: " + overall)
+
+	output.End()
+}
diff --git a/v1.5.7/internal/cloud/backend_taskStage_taskResults_test.go b/v1.5.7/internal/cloud/backend_taskStage_taskResults_test.go
new file mode 100644
index 0000000..1e272da
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_taskStage_taskResults_test.go
@@ -0,0 +1,172 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"context"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/go-tfe"
+)
+
+type testIntegrationOutput struct {
+	ctx    *IntegrationContext
+	output *strings.Builder
+	t      *testing.T
+}
+
+var _ IntegrationOutputWriter = (*testIntegrationOutput)(nil) // Compile time check
+
+func (s *testIntegrationOutput) End() {
+	s.output.WriteString("END\n")
+}
+
+func (s *testIntegrationOutput) SubOutput(str string) {
+	s.output.WriteString(s.ctx.B.Colorize().Color("[reset]│ "+str) + "\n")
+}
+
+func (s *testIntegrationOutput) Output(str string) {
+	s.output.WriteString(s.ctx.B.Colorize().Color("[reset]│ ") + str + "\n")
+}
+
+func (s *testIntegrationOutput) OutputElapsed(message string, maxMessage int) {
+	s.output.WriteString("PENDING MESSAGE: " + message)
+}
+
+func newMockIntegrationContext(b *Cloud, t *testing.T) (*IntegrationContext, *testIntegrationOutput) {
+	ctx := context.Background()
+
+	// Retrieve the workspace used to run this operation in.
+	w, err := b.client.Workspaces.Read(ctx, b.organization, b.WorkspaceMapping.Name)
+	if err != nil {
+		t.Fatalf("error retrieving workspace: %v", err)
+	}
+
+	// Create a new configuration version.
+	c, err := b.client.ConfigurationVersions.Create(ctx, w.ID, tfe.ConfigurationVersionCreateOptions{})
+	if err != nil {
+		t.Fatalf("error creating configuration version: %v", err)
+	}
+
+	// Create a pending run to block this run.
+	r, err := b.client.Runs.Create(ctx, tfe.RunCreateOptions{
+		ConfigurationVersion: c,
+		Workspace:            w,
+	})
+	if err != nil {
+		t.Fatalf("error creating pending run: %v", err)
+	}
+
+	op, configCleanup, done := testOperationPlan(t, "./testdata/plan")
+	defer configCleanup()
+	defer done(t)
+
+	integrationContext := &IntegrationContext{
+		B:             b,
+		StopContext:   ctx,
+		CancelContext: ctx,
+		Op:            op,
+		Run:           r,
+	}
+
+	return integrationContext, &testIntegrationOutput{
+		ctx:    integrationContext,
+		output: &strings.Builder{},
+		t:      t,
+	}
+}
+
+func TestCloud_runTasksWithTaskResults(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	integrationContext, writer := newMockIntegrationContext(b, t)
+
+	cases := map[string]struct {
+		taskStage       func() *tfe.TaskStage
+		context         *IntegrationContext
+		writer          *testIntegrationOutput
+		expectedOutputs []string
+		isError         bool
+	}{
+		"all-succeeded": {
+			taskStage: func() *tfe.TaskStage {
+				ts := &tfe.TaskStage{}
+				ts.TaskResults = []*tfe.TaskResult{
+					{ID: "1", TaskName: "Mandatory", Message: "A-OK", Status: "passed", WorkspaceTaskEnforcementLevel: "mandatory"},
+					{ID: "2", TaskName: "Advisory", Message: "A-OK", Status: "passed", WorkspaceTaskEnforcementLevel: "advisory"},
+				}
+				return ts
+			},
+			writer:          writer,
+			context:         integrationContext,
+			expectedOutputs: []string{"Overall Result: Passed\n"},
+			isError:         false,
+		},
+		"mandatory-failed": {
+			taskStage: func() *tfe.TaskStage {
+				ts := &tfe.TaskStage{}
+				ts.TaskResults = []*tfe.TaskResult{
+					{ID: "1", TaskName: "Mandatory", Message: "500 Error", Status: "failed", WorkspaceTaskEnforcementLevel: "mandatory"},
+					{ID: "2", TaskName: "Advisory", Message: "A-OK", Status: "passed", WorkspaceTaskEnforcementLevel: "advisory"},
+				}
+				return ts
+			},
+			writer:          writer,
+			context:         integrationContext,
+			expectedOutputs: []string{"Passed\n", "A-OK\n", "Overall Result: Failed\n"},
+			isError:         true,
+		},
+		"advisory-failed": {
+			taskStage: func() *tfe.TaskStage {
+				ts := &tfe.TaskStage{}
+				ts.TaskResults = []*tfe.TaskResult{
+					{ID: "1", TaskName: "Mandatory", Message: "A-OK", Status: "passed", WorkspaceTaskEnforcementLevel: "mandatory"},
+					{ID: "2", TaskName: "Advisory", Message: "500 Error", Status: "failed", WorkspaceTaskEnforcementLevel: "advisory"},
+				}
+				return ts
+			},
+			writer:          writer,
+			context:         integrationContext,
+			expectedOutputs: []string{"Failed (Advisory)", "Overall Result: Passed with advisory failure"},
+			isError:         false,
+		},
+		"unreachable": {
+			taskStage: func() *tfe.TaskStage {
+				ts := &tfe.TaskStage{}
+				ts.TaskResults = []*tfe.TaskResult{
+					{ID: "1", TaskName: "Mandatory", Message: "", Status: "unreachable", WorkspaceTaskEnforcementLevel: "mandatory"},
+					{ID: "2", TaskName: "Advisory", Message: "", Status: "unreachable", WorkspaceTaskEnforcementLevel: "advisory"},
+				}
+				return ts
+			},
+			writer:          writer,
+			context:         integrationContext,
+			expectedOutputs: []string{"Skipping"},
+			isError:         false,
+		},
+	}
+
+	for _, c := range cases {
+		c.writer.output.Reset()
+		trs := taskResultSummarizer{
+			cloud: b,
+		}
+		c.context.Poll(0, 0, func(i int) (bool, error) {
+			cont, _, _ := trs.Summarize(c.context, c.writer, c.taskStage())
+			if cont {
+				return true, nil
+			}
+
+			output := c.writer.output.String()
+			for _, expected := range c.expectedOutputs {
+				if !strings.Contains(output, expected) {
+					t.Fatalf("Expected output to contain '%s' but it was:\n\n%s", expected, output)
+				}
+			}
+			return false, nil
+		})
+	}
+}
diff --git a/v1.5.7/internal/cloud/backend_taskStages.go b/v1.5.7/internal/cloud/backend_taskStages.go
new file mode 100644
index 0000000..953484b
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_taskStages.go
@@ -0,0 +1,195 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"context"
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/go-multierror"
+	tfe "github.com/hashicorp/go-tfe"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+type taskStages map[tfe.Stage]*tfe.TaskStage
+
+const (
+	taskStageBackoffMin = 4000.0
+	taskStageBackoffMax = 12000.0
+)
+
+const taskStageHeader = `
+To view this run in a browser, visit:
+https://%s/app/%s/%s/runs/%s
+`
+
+type taskStageSummarizer interface {
+	// Summarize takes an IntegrationContext, IntegrationOutputWriter for
+	// writing output and a pointer to a tfe.TaskStage object as arguments.
+	// This function summarizes and outputs the results of the task stage.
+	// It returns a boolean which signifies whether we should continue polling
+	// for results, an optional message string to print while it is polling
+	// and an error if any.
+	Summarize(*IntegrationContext, IntegrationOutputWriter, *tfe.TaskStage) (bool, *string, error)
+}
+
+func (b *Cloud) runTaskStages(ctx context.Context, client *tfe.Client, runId string) (taskStages, error) {
+	taskStages := make(taskStages, 0)
+	result, err := client.Runs.ReadWithOptions(ctx, runId, &tfe.RunReadOptions{
+		Include: []tfe.RunIncludeOpt{tfe.RunTaskStages},
+	})
+	if err == nil {
+		for _, t := range result.TaskStages {
+			if t != nil {
+				taskStages[t.Stage] = t
+			}
+		}
+	} else {
+		// This error would be expected for older versions of TFE that do not allow
+		// fetching task_stages.
+		if !strings.HasSuffix(err.Error(), "Invalid include parameter") {
+			return taskStages, generalError("Failed to retrieve run", err)
+		}
+	}
+
+	return taskStages, nil
+}
+
+func (b *Cloud) getTaskStageWithAllOptions(ctx *IntegrationContext, stageID string) (*tfe.TaskStage, error) {
+	options := tfe.TaskStageReadOptions{
+		Include: []tfe.TaskStageIncludeOpt{tfe.TaskStageTaskResults, tfe.PolicyEvaluationsTaskResults},
+	}
+	stage, err := b.client.TaskStages.Read(ctx.StopContext, stageID, &options)
+	if err != nil {
+		return nil, generalError("Failed to retrieve task stage", err)
+	} else {
+		return stage, nil
+	}
+}
+
+func (b *Cloud) runTaskStage(ctx *IntegrationContext, output IntegrationOutputWriter, stageID string) error {
+	var errs *multierror.Error
+
+	// Create our summarizers
+	summarizers := make([]taskStageSummarizer, 0)
+	ts, err := b.getTaskStageWithAllOptions(ctx, stageID)
+	if err != nil {
+		return err
+	}
+
+	if s := newTaskResultSummarizer(b, ts); s != nil {
+		summarizers = append(summarizers, s)
+	}
+
+	if s := newPolicyEvaluationSummarizer(b, ts); s != nil {
+		summarizers = append(summarizers, s)
+	}
+
+	return ctx.Poll(taskStageBackoffMin, taskStageBackoffMax, func(i int) (bool, error) {
+		options := tfe.TaskStageReadOptions{
+			Include: []tfe.TaskStageIncludeOpt{tfe.TaskStageTaskResults, tfe.PolicyEvaluationsTaskResults},
+		}
+		stage, err := b.client.TaskStages.Read(ctx.StopContext, stageID, &options)
+		if err != nil {
+			return false, generalError("Failed to retrieve task stage", err)
+		}
+
+		switch stage.Status {
+		case tfe.TaskStagePending:
+			// Waiting for it to start
+			return true, nil
+		case tfe.TaskStageRunning:
+			if _, e := processSummarizers(ctx, output, stage, summarizers, errs); e != nil {
+				errs = e
+			}
+			// not a terminal status so we continue to poll
+			return true, nil
+		// Note: Terminal statuses need to print out one last time just in case
+		case tfe.TaskStagePassed:
+			ok, e := processSummarizers(ctx, output, stage, summarizers, errs)
+			if e != nil {
+				errs = e
+			}
+			if ok {
+				return true, nil
+			}
+		case tfe.TaskStageCanceled, tfe.TaskStageErrored, tfe.TaskStageFailed:
+			ok, e := processSummarizers(ctx, output, stage, summarizers, errs)
+			if e != nil {
+				errs = e
+			}
+			if ok {
+				return true, nil
+			}
+			return false, fmt.Errorf("Task Stage %s.", stage.Status)
+		case tfe.TaskStageAwaitingOverride:
+			ok, e := processSummarizers(ctx, output, stage, summarizers, errs)
+			if e != nil {
+				errs = e
+			}
+			if ok {
+				return true, nil
+			}
+			cont, err := b.processStageOverrides(ctx, output, stage.ID)
+			if err != nil {
+				errs = multierror.Append(errs, err)
+			} else {
+				return cont, nil
+			}
+		case tfe.TaskStageUnreachable:
+			return false, nil
+		default:
+			return false, fmt.Errorf("Invalid Task stage status: %s ", stage.Status)
+		}
+		return false, errs.ErrorOrNil()
+	})
+}
+
+func processSummarizers(ctx *IntegrationContext, output IntegrationOutputWriter, stage *tfe.TaskStage, summarizers []taskStageSummarizer, errs *multierror.Error) (bool, *multierror.Error) {
+	for _, s := range summarizers {
+		cont, msg, err := s.Summarize(ctx, output, stage)
+		if err != nil {
+			errs = multierror.Append(errs, err)
+			break
+		}
+
+		if !cont {
+			continue
+		}
+
+		// cont is true and we must continue to poll
+		if msg != nil {
+			output.OutputElapsed(*msg, len(*msg)) // Up to 2 digits are allowed by the max message allocation
+		}
+		return true, nil
+	}
+	return false, errs
+}
+
+func (b *Cloud) processStageOverrides(context *IntegrationContext, output IntegrationOutputWriter, taskStageID string) (bool, error) {
+	opts := &terraform.InputOpts{
+		Id:          fmt.Sprintf("%c%c [bold]Override", Arrow, Arrow),
+		Query:       "\nDo you want to override the failed policy check?",
+		Description: "Only 'override' will be accepted to override.",
+	}
+	runUrl := fmt.Sprintf(taskStageHeader, b.hostname, b.organization, context.Op.Workspace, context.Run.ID)
+	err := b.confirm(context.StopContext, context.Op, opts, context.Run, "override")
+	if err != nil && err != errRunOverridden {
+		return false, fmt.Errorf(
+			fmt.Sprintf("Failed to override: %s\n%s\n", err.Error(), runUrl),
+		)
+	}
+
+	if err != errRunOverridden {
+		if _, err = b.client.TaskStages.Override(context.StopContext, taskStageID, tfe.TaskStageOverrideOptions{}); err != nil {
+			return false, generalError(fmt.Sprintf("Failed to override policy check.\n%s", runUrl), err)
+		} else {
+			return true, nil
+		}
+	} else {
+		output.Output(fmt.Sprintf("The run needs to be manually overridden or discarded.\n%s\n", runUrl))
+	}
+	return false, nil
+}
diff --git a/v1.5.7/internal/cloud/backend_taskStages_test.go b/v1.5.7/internal/cloud/backend_taskStages_test.go
new file mode 100644
index 0000000..3a88cf8
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_taskStages_test.go
@@ -0,0 +1,278 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"context"
+	"errors"
+	"strings"
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	"github.com/hashicorp/go-tfe"
+	tfemocks "github.com/hashicorp/go-tfe/mocks"
+)
+
+func MockAllTaskStages(t *testing.T, client *tfe.Client) (RunID string) {
+	ctrl := gomock.NewController(t)
+
+	RunID = "run-all_task_stages"
+
+	mockRunsAPI := tfemocks.NewMockRuns(ctrl)
+
+	goodRun := tfe.Run{
+		TaskStages: []*tfe.TaskStage{
+			{
+				Stage: tfe.PrePlan,
+			},
+			{
+				Stage: tfe.PostPlan,
+			},
+			{
+				Stage: tfe.PreApply,
+			},
+		},
+	}
+	mockRunsAPI.
+		EXPECT().
+		ReadWithOptions(gomock.Any(), RunID, gomock.Any()).
+		Return(&goodRun, nil).
+		AnyTimes()
+
+	// Mock a bad Read response
+	mockRunsAPI.
+		EXPECT().
+		ReadWithOptions(gomock.Any(), gomock.Any(), gomock.Any()).
+		Return(nil, tfe.ErrInvalidOrg).
+		AnyTimes()
+
+	// Wire up the mock interfaces
+	client.Runs = mockRunsAPI
+	return
+}
+
+func MockPrePlanTaskStage(t *testing.T, client *tfe.Client) (RunID string) {
+	ctrl := gomock.NewController(t)
+
+	RunID = "run-pre_plan_task_stage"
+
+	mockRunsAPI := tfemocks.NewMockRuns(ctrl)
+
+	goodRun := tfe.Run{
+		TaskStages: []*tfe.TaskStage{
+			{
+				Stage: tfe.PrePlan,
+			},
+		},
+	}
+	mockRunsAPI.
+		EXPECT().
+		ReadWithOptions(gomock.Any(), RunID, gomock.Any()).
+		Return(&goodRun, nil).
+		AnyTimes()
+
+	// Mock a bad Read response
+	mockRunsAPI.
+		EXPECT().
+		ReadWithOptions(gomock.Any(), gomock.Any(), gomock.Any()).
+		Return(nil, tfe.ErrInvalidOrg).
+		AnyTimes()
+
+	// Wire up the mock interfaces
+	client.Runs = mockRunsAPI
+	return
+}
+
+func MockTaskStageUnsupported(t *testing.T, client *tfe.Client) (RunID string) {
+	ctrl := gomock.NewController(t)
+
+	RunID = "run-unsupported_task_stage"
+
+	mockRunsAPI := tfemocks.NewMockRuns(ctrl)
+
+	mockRunsAPI.
+		EXPECT().
+		ReadWithOptions(gomock.Any(), RunID, gomock.Any()).
+		Return(nil, errors.New("Invalid include parameter")).
+		AnyTimes()
+
+	mockRunsAPI.
+		EXPECT().
+		ReadWithOptions(gomock.Any(), gomock.Any(), gomock.Any()).
+		Return(nil, tfe.ErrInvalidOrg).
+		AnyTimes()
+
+	client.Runs = mockRunsAPI
+	return
+}
+
+func TestTaskStagesWithAllStages(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	config := &tfe.Config{
+		Token: "not-a-token",
+	}
+	client, _ := tfe.NewClient(config)
+	runID := MockAllTaskStages(t, client)
+
+	ctx := context.TODO()
+	taskStages, err := b.runTaskStages(ctx, client, runID)
+
+	if err != nil {
+		t.Fatalf("Expected to not error but received %s", err)
+	}
+
+	for _, stageName := range []tfe.Stage{
+		tfe.PrePlan,
+		tfe.PostPlan,
+		tfe.PreApply,
+	} {
+		if stage, ok := taskStages[stageName]; ok {
+			if stage.Stage != stageName {
+				t.Errorf("Expected task stage indexed by %s to find a Task Stage with the same index, but receieved %s", stageName, stage.Stage)
+			}
+		} else {
+			t.Errorf("Expected task stage indexed by %s to exist, but it did not", stageName)
+		}
+	}
+}
+
+func TestTaskStagesWithOneStage(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	config := &tfe.Config{
+		Token: "not-a-token",
+	}
+	client, _ := tfe.NewClient(config)
+	runID := MockPrePlanTaskStage(t, client)
+
+	ctx := context.TODO()
+	taskStages, err := b.runTaskStages(ctx, client, runID)
+
+	if err != nil {
+		t.Fatalf("Expected to not error but received %s", err)
+	}
+
+	if _, ok := taskStages[tfe.PrePlan]; !ok {
+		t.Errorf("Expected task stage indexed by %s to exist, but it did not", tfe.PrePlan)
+	}
+
+	for _, stageName := range []tfe.Stage{
+		tfe.PostPlan,
+		tfe.PreApply,
+	} {
+		if _, ok := taskStages[stageName]; ok {
+			t.Errorf("Expected task stage indexed by %s to not exist, but it did", stageName)
+		}
+	}
+}
+
+func TestTaskStagesWithOldTFC(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	config := &tfe.Config{
+		Token: "not-a-token",
+	}
+	client, _ := tfe.NewClient(config)
+	runID := MockTaskStageUnsupported(t, client)
+
+	ctx := context.TODO()
+	taskStages, err := b.runTaskStages(ctx, client, runID)
+
+	if err != nil {
+		t.Fatalf("Expected to not error but received %s", err)
+	}
+
+	if len(taskStages) != 0 {
+		t.Errorf("Expected task stage to be empty, but found %d stages", len(taskStages))
+	}
+}
+
+func TestTaskStagesWithErrors(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	config := &tfe.Config{
+		Token: "not-a-token",
+	}
+	client, _ := tfe.NewClient(config)
+	MockTaskStageUnsupported(t, client)
+
+	ctx := context.TODO()
+	_, err := b.runTaskStages(ctx, client, "this run ID will not exist is invalid anyway")
+
+	if err == nil {
+		t.Error("Expected to error but did not")
+	}
+}
+
+func TestTaskStageOverride(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	integrationContext, writer := newMockIntegrationContext(b, t)
+
+	integrationContext.Op.UIOut = b.CLI
+
+	cases := map[string]struct {
+		taskStageID string
+		isError     bool
+		errMsg      string
+		input       *mockInput
+		cont        bool
+	}{
+		"override-pass": {
+			taskStageID: "ts-pass",
+			isError:     false,
+			input: testInput(t, map[string]string{
+				"→→ [bold]Override": "override",
+			}),
+			errMsg: "",
+			cont:   true,
+		},
+		"override-fail": {
+			taskStageID: "ts-err",
+			isError:     true,
+			input: testInput(t, map[string]string{
+				"→→ [bold]Override": "override",
+			}),
+			errMsg: "",
+			cont:   false,
+		},
+		"skip-override": {
+			taskStageID: "ts-err",
+			isError:     true,
+			errMsg:      "Failed to override: Apply discarded.",
+			input: testInput(t, map[string]string{
+				"→→ [bold]Override": "no",
+			}),
+			cont: false,
+		},
+	}
+	for _, c := range cases {
+		integrationContext.Op.UIIn = c.input
+		cont, err := b.processStageOverrides(integrationContext, writer, c.taskStageID)
+		if c.isError {
+			if err == nil {
+				t.Fatalf("Expected to fail with some error")
+			}
+			if c.errMsg != "" {
+				if !strings.Contains(err.Error(), c.errMsg) {
+					t.Fatalf("Expected: %s, got: %s", c.errMsg, err.Error())
+				}
+			}
+
+		} else {
+			if err != nil {
+				t.Fatalf("Expected to pass, got err: %s", err)
+			}
+		}
+		if c.cont != cont {
+			t.Fatalf("expected polling continue: %t, got: %t", c.cont, cont)
+		}
+	}
+}
diff --git a/v1.5.7/internal/cloud/backend_test.go b/v1.5.7/internal/cloud/backend_test.go
new file mode 100644
index 0000000..8591390
--- /dev/null
+++ b/v1.5.7/internal/cloud/backend_test.go
@@ -0,0 +1,1248 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"os"
+	"strings"
+	"testing"
+
+	tfe "github.com/hashicorp/go-tfe"
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	tfversion "github.com/hashicorp/terraform/version"
+	"github.com/zclconf/go-cty/cty"
+
+	backendLocal "github.com/hashicorp/terraform/internal/backend/local"
+)
+
+func TestCloud(t *testing.T) {
+	var _ backend.Enhanced = New(nil)
+	var _ backend.CLI = New(nil)
+}
+
+func TestCloud_backendWithName(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	workspaces, err := b.Workspaces()
+	if err != nil {
+		t.Fatalf("error: %v", err)
+	}
+
+	if len(workspaces) != 1 || workspaces[0] != testBackendSingleWorkspaceName {
+		t.Fatalf("should only have a single configured workspace matching the configured 'name' strategy, but got: %#v", workspaces)
+	}
+
+	if _, err := b.StateMgr("foo"); err != backend.ErrWorkspacesNotSupported {
+		t.Fatalf("expected fetching a state which is NOT the single configured workspace to have an ErrWorkspacesNotSupported error, but got: %v", err)
+	}
+
+	if err := b.DeleteWorkspace(testBackendSingleWorkspaceName, true); err != backend.ErrWorkspacesNotSupported {
+		t.Fatalf("expected deleting the single configured workspace name to result in an error, but got: %v", err)
+	}
+
+	if err := b.DeleteWorkspace("foo", true); err != backend.ErrWorkspacesNotSupported {
+		t.Fatalf("expected deleting a workspace which is NOT the configured workspace name to result in an error, but got: %v", err)
+	}
+}
+
+func TestCloud_backendWithTags(t *testing.T) {
+	b, bCleanup := testBackendWithTags(t)
+	defer bCleanup()
+
+	backend.TestBackendStates(t, b)
+
+	// Test pagination works
+	for i := 0; i < 25; i++ {
+		_, err := b.StateMgr(fmt.Sprintf("foo-%d", i+1))
+		if err != nil {
+			t.Fatalf("error: %s", err)
+		}
+	}
+
+	workspaces, err := b.Workspaces()
+	if err != nil {
+		t.Fatalf("error: %s", err)
+	}
+	actual := len(workspaces)
+	if actual != 26 {
+		t.Errorf("expected 26 workspaces (over one standard paginated response), got %d", actual)
+	}
+}
+
+func TestCloud_PrepareConfig(t *testing.T) {
+	cases := map[string]struct {
+		config      cty.Value
+		expectedErr string
+	}{
+		"null organization": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"organization": cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			expectedErr: `Invalid or missing required argument: "organization" must be set in the cloud configuration or as an environment variable: TF_CLOUD_ORGANIZATION.`,
+		},
+		"null workspace": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"organization": cty.StringVal("org"),
+				"workspaces":   cty.NullVal(cty.String),
+			}),
+			expectedErr: `Invalid workspaces configuration: Missing workspace mapping strategy. Either workspace "tags" or "name" is required.`,
+		},
+		"workspace: empty tags, name": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"organization": cty.StringVal("org"),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.NullVal(cty.String),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			expectedErr: `Invalid workspaces configuration: Missing workspace mapping strategy. Either workspace "tags" or "name" is required.`,
+		},
+		"workspace: name present": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"organization": cty.StringVal("org"),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			expectedErr: `Invalid workspaces configuration: Only one of workspace "tags" or "name" is allowed.`,
+		},
+		"workspace: name and tags present": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"organization": cty.StringVal("org"),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.SetVal(
+						[]cty.Value{
+							cty.StringVal("billing"),
+						},
+					),
+				}),
+			}),
+			expectedErr: `Invalid workspaces configuration: Only one of workspace "tags" or "name" is allowed.`,
+		},
+	}
+
+	for name, tc := range cases {
+		s := testServer(t)
+		b := New(testDisco(s))
+
+		// Validate
+		_, valDiags := b.PrepareConfig(tc.config)
+		if valDiags.Err() != nil && tc.expectedErr != "" {
+			actualErr := valDiags.Err().Error()
+			if !strings.Contains(actualErr, tc.expectedErr) {
+				t.Fatalf("%s: unexpected validation result: %v", name, valDiags.Err())
+			}
+		}
+	}
+}
+
+func TestCloud_PrepareConfigWithEnvVars(t *testing.T) {
+	cases := map[string]struct {
+		config      cty.Value
+		vars        map[string]string
+		expectedErr string
+	}{
+		"with no organization": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"organization": cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			vars: map[string]string{
+				"TF_CLOUD_ORGANIZATION": "example-org",
+			},
+		},
+		"with no organization attribute or env var": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"organization": cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			vars:        map[string]string{},
+			expectedErr: `Invalid or missing required argument: "organization" must be set in the cloud configuration or as an environment variable: TF_CLOUD_ORGANIZATION.`,
+		},
+		"null workspace": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"organization": cty.StringVal("hashicorp"),
+				"workspaces":   cty.NullVal(cty.String),
+			}),
+			vars: map[string]string{
+				"TF_WORKSPACE": "my-workspace",
+			},
+		},
+		"organization and workspace env var": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"organization": cty.NullVal(cty.String),
+				"workspaces":   cty.NullVal(cty.String),
+			}),
+			vars: map[string]string{
+				"TF_CLOUD_ORGANIZATION": "hashicorp",
+				"TF_WORKSPACE":          "my-workspace",
+			},
+		},
+	}
+
+	for name, tc := range cases {
+		t.Run(name, func(t *testing.T) {
+			s := testServer(t)
+			b := New(testDisco(s))
+
+			for k, v := range tc.vars {
+				os.Setenv(k, v)
+			}
+			t.Cleanup(func() {
+				for k := range tc.vars {
+					os.Unsetenv(k)
+				}
+			})
+
+			_, valDiags := b.PrepareConfig(tc.config)
+			if valDiags.Err() != nil && tc.expectedErr != "" {
+				actualErr := valDiags.Err().Error()
+				if !strings.Contains(actualErr, tc.expectedErr) {
+					t.Fatalf("%s: unexpected validation result: %v", name, valDiags.Err())
+				}
+			}
+		})
+	}
+}
+
+func TestCloud_configWithEnvVars(t *testing.T) {
+	cases := map[string]struct {
+		setup                 func(b *Cloud)
+		config                cty.Value
+		vars                  map[string]string
+		expectedOrganization  string
+		expectedHostname      string
+		expectedWorkspaceName string
+		expectedErr           string
+	}{
+		"with no organization specified": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"token":        cty.NullVal(cty.String),
+				"organization": cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			vars: map[string]string{
+				"TF_CLOUD_ORGANIZATION": "hashicorp",
+			},
+			expectedOrganization: "hashicorp",
+		},
+		"with both organization and env var specified": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"token":        cty.NullVal(cty.String),
+				"organization": cty.StringVal("hashicorp"),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			vars: map[string]string{
+				"TF_CLOUD_ORGANIZATION": "we-should-not-see-this",
+			},
+			expectedOrganization: "hashicorp",
+		},
+		"with no hostname specified": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"token":        cty.NullVal(cty.String),
+				"organization": cty.StringVal("hashicorp"),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			vars: map[string]string{
+				"TF_CLOUD_HOSTNAME": "private.hashicorp.engineering",
+			},
+			expectedHostname: "private.hashicorp.engineering",
+		},
+		"with hostname and env var specified": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.StringVal("private.hashicorp.engineering"),
+				"token":        cty.NullVal(cty.String),
+				"organization": cty.StringVal("hashicorp"),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			vars: map[string]string{
+				"TF_CLOUD_HOSTNAME": "mycool.tfe-host.io",
+			},
+			expectedHostname: "private.hashicorp.engineering",
+		},
+		"an invalid workspace env var": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"token":        cty.NullVal(cty.String),
+				"organization": cty.StringVal("hashicorp"),
+				"workspaces": cty.NullVal(cty.Object(map[string]cty.Type{
+					"name": cty.String,
+					"tags": cty.Set(cty.String),
+				})),
+			}),
+			vars: map[string]string{
+				"TF_WORKSPACE": "i-dont-exist-in-org",
+			},
+			expectedErr: `Invalid workspace selection: Terraform failed to find workspace "i-dont-exist-in-org" in organization hashicorp`,
+		},
+		"workspaces and env var specified": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"token":        cty.NullVal(cty.String),
+				"organization": cty.StringVal("mordor"),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("mt-doom"),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			vars: map[string]string{
+				"TF_WORKSPACE": "shire",
+			},
+			expectedWorkspaceName: "mt-doom",
+		},
+		"env var workspace does not have specified tag": {
+			setup: func(b *Cloud) {
+				b.client.Organizations.Create(context.Background(), tfe.OrganizationCreateOptions{
+					Name: tfe.String("mordor"),
+				})
+
+				b.client.Workspaces.Create(context.Background(), "mordor", tfe.WorkspaceCreateOptions{
+					Name: tfe.String("shire"),
+				})
+			},
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"token":        cty.NullVal(cty.String),
+				"organization": cty.StringVal("mordor"),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.NullVal(cty.String),
+					"tags": cty.SetVal([]cty.Value{
+						cty.StringVal("cloud"),
+					}),
+				}),
+			}),
+			vars: map[string]string{
+				"TF_WORKSPACE": "shire",
+			},
+			expectedErr: "Terraform failed to find workspace \"shire\" with the tags specified in your configuration:\n[cloud]",
+		},
+		"env var workspace has specified tag": {
+			setup: func(b *Cloud) {
+				b.client.Organizations.Create(context.Background(), tfe.OrganizationCreateOptions{
+					Name: tfe.String("mordor"),
+				})
+
+				b.client.Workspaces.Create(context.Background(), "mordor", tfe.WorkspaceCreateOptions{
+					Name: tfe.String("shire"),
+					Tags: []*tfe.Tag{
+						{
+							Name: "hobbity",
+						},
+					},
+				})
+			},
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"token":        cty.NullVal(cty.String),
+				"organization": cty.StringVal("mordor"),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.NullVal(cty.String),
+					"tags": cty.SetVal([]cty.Value{
+						cty.StringVal("hobbity"),
+					}),
+				}),
+			}),
+			vars: map[string]string{
+				"TF_WORKSPACE": "shire",
+			},
+			expectedWorkspaceName: "", // No error is raised, but workspace is not set
+		},
+		"with everything set as env vars": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"token":        cty.NullVal(cty.String),
+				"organization": cty.NullVal(cty.String),
+				"workspaces":   cty.NullVal(cty.String),
+			}),
+			vars: map[string]string{
+				"TF_CLOUD_ORGANIZATION": "mordor",
+				"TF_WORKSPACE":          "mt-doom",
+				"TF_CLOUD_HOSTNAME":     "mycool.tfe-host.io",
+			},
+			expectedOrganization:  "mordor",
+			expectedWorkspaceName: "mt-doom",
+			expectedHostname:      "mycool.tfe-host.io",
+		},
+	}
+
+	for name, tc := range cases {
+		t.Run(name, func(t *testing.T) {
+			b, cleanup := testUnconfiguredBackend(t)
+			t.Cleanup(cleanup)
+
+			for k, v := range tc.vars {
+				os.Setenv(k, v)
+			}
+
+			t.Cleanup(func() {
+				for k := range tc.vars {
+					os.Unsetenv(k)
+				}
+			})
+
+			_, valDiags := b.PrepareConfig(tc.config)
+			if valDiags.Err() != nil {
+				t.Fatalf("%s: unexpected validation result: %v", name, valDiags.Err())
+			}
+
+			if tc.setup != nil {
+				tc.setup(b)
+			}
+
+			diags := b.Configure(tc.config)
+			if (diags.Err() != nil || tc.expectedErr != "") &&
+				(diags.Err() == nil || !strings.Contains(diags.Err().Error(), tc.expectedErr)) {
+				t.Fatalf("%s: unexpected configure result: %v", name, diags.Err())
+			}
+
+			if tc.expectedOrganization != "" && tc.expectedOrganization != b.organization {
+				t.Fatalf("%s: organization not valid: %s, expected: %s", name, b.organization, tc.expectedOrganization)
+			}
+
+			if tc.expectedHostname != "" && tc.expectedHostname != b.hostname {
+				t.Fatalf("%s: hostname not valid: %s, expected: %s", name, b.hostname, tc.expectedHostname)
+			}
+
+			if tc.expectedWorkspaceName != "" && tc.expectedWorkspaceName != b.WorkspaceMapping.Name {
+				t.Fatalf("%s: workspace name not valid: %s, expected: %s", name, b.WorkspaceMapping.Name, tc.expectedWorkspaceName)
+			}
+		})
+	}
+}
+
+func TestCloud_config(t *testing.T) {
+	cases := map[string]struct {
+		config  cty.Value
+		confErr string
+		valErr  string
+	}{
+		"with_a_non_tfe_host": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.StringVal("nontfe.local"),
+				"organization": cty.StringVal("hashicorp"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			confErr: "Host nontfe.local does not provide a tfe service",
+		},
+		// localhost advertises TFE services, but has no token in the credentials
+		"without_a_token": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.StringVal("localhost"),
+				"organization": cty.StringVal("hashicorp"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			confErr: "terraform login localhost",
+		},
+		"with_tags": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"organization": cty.StringVal("hashicorp"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.NullVal(cty.String),
+					"tags": cty.SetVal(
+						[]cty.Value{
+							cty.StringVal("billing"),
+						},
+					),
+				}),
+			}),
+		},
+		"with_a_name": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"organization": cty.StringVal("hashicorp"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+		},
+		"without_a_name_tags": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"organization": cty.StringVal("hashicorp"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.NullVal(cty.String),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			valErr: `Missing workspace mapping strategy.`,
+		},
+		"with_both_a_name_and_tags": {
+			config: cty.ObjectVal(map[string]cty.Value{
+				"hostname":     cty.NullVal(cty.String),
+				"organization": cty.StringVal("hashicorp"),
+				"token":        cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.SetVal(
+						[]cty.Value{
+							cty.StringVal("billing"),
+						},
+					),
+				}),
+			}),
+			valErr: `Only one of workspace "tags" or "name" is allowed.`,
+		},
+		"null config": {
+			config: cty.NullVal(cty.EmptyObject),
+		},
+	}
+
+	for name, tc := range cases {
+		t.Run(name, func(t *testing.T) {
+			b, cleanup := testUnconfiguredBackend(t)
+			t.Cleanup(cleanup)
+
+			// Validate
+			_, valDiags := b.PrepareConfig(tc.config)
+			if (valDiags.Err() != nil || tc.valErr != "") &&
+				(valDiags.Err() == nil || !strings.Contains(valDiags.Err().Error(), tc.valErr)) {
+				t.Fatalf("unexpected validation result: %v", valDiags.Err())
+			}
+
+			// Configure
+			confDiags := b.Configure(tc.config)
+			if (confDiags.Err() != nil || tc.confErr != "") &&
+				(confDiags.Err() == nil || !strings.Contains(confDiags.Err().Error(), tc.confErr)) {
+				t.Fatalf("unexpected configure result: %v", confDiags.Err())
+			}
+		})
+	}
+}
+
+func TestCloud_configVerifyMinimumTFEVersion(t *testing.T) {
+	config := cty.ObjectVal(map[string]cty.Value{
+		"hostname":     cty.NullVal(cty.String),
+		"organization": cty.StringVal("hashicorp"),
+		"token":        cty.NullVal(cty.String),
+		"workspaces": cty.ObjectVal(map[string]cty.Value{
+			"name": cty.NullVal(cty.String),
+			"tags": cty.SetVal(
+				[]cty.Value{
+					cty.StringVal("billing"),
+				},
+			),
+		}),
+	})
+
+	handlers := map[string]func(http.ResponseWriter, *http.Request){
+		"/api/v2/ping": func(w http.ResponseWriter, r *http.Request) {
+			w.Header().Set("Content-Type", "application/json")
+			w.Header().Set("TFP-API-Version", "2.4")
+		},
+	}
+	s := testServerWithHandlers(handlers)
+
+	b := New(testDisco(s))
+
+	confDiags := b.Configure(config)
+	if confDiags.Err() == nil {
+		t.Fatalf("expected configure to error")
+	}
+
+	expected := `The 'cloud' option is not supported with this version of Terraform Enterprise.`
+	if !strings.Contains(confDiags.Err().Error(), expected) {
+		t.Fatalf("expected configure to error with %q, got %q", expected, confDiags.Err().Error())
+	}
+}
+
+func TestCloud_configVerifyMinimumTFEVersionInAutomation(t *testing.T) {
+	config := cty.ObjectVal(map[string]cty.Value{
+		"hostname":     cty.NullVal(cty.String),
+		"organization": cty.StringVal("hashicorp"),
+		"token":        cty.NullVal(cty.String),
+		"workspaces": cty.ObjectVal(map[string]cty.Value{
+			"name": cty.NullVal(cty.String),
+			"tags": cty.SetVal(
+				[]cty.Value{
+					cty.StringVal("billing"),
+				},
+			),
+		}),
+	})
+
+	handlers := map[string]func(http.ResponseWriter, *http.Request){
+		"/api/v2/ping": func(w http.ResponseWriter, r *http.Request) {
+			w.Header().Set("Content-Type", "application/json")
+			w.Header().Set("TFP-API-Version", "2.4")
+		},
+	}
+	s := testServerWithHandlers(handlers)
+
+	b := New(testDisco(s))
+	b.runningInAutomation = true
+
+	confDiags := b.Configure(config)
+	if confDiags.Err() == nil {
+		t.Fatalf("expected configure to error")
+	}
+
+	expected := `This version of Terraform Cloud/Enterprise does not support the state mechanism
+attempting to be used by the platform. This should never happen.`
+	if !strings.Contains(confDiags.Err().Error(), expected) {
+		t.Fatalf("expected configure to error with %q, got %q", expected, confDiags.Err().Error())
+	}
+}
+
+func TestCloud_setUnavailableTerraformVersion(t *testing.T) {
+	// go-tfe returns an error IRL if you try to set a Terraform version that's
+	// not available in your TFC instance. To test this, tfe_client_mock errors if
+	// you try to set any Terraform version for this specific workspace name.
+	workspaceName := "unavailable-terraform-version"
+
+	config := cty.ObjectVal(map[string]cty.Value{
+		"hostname":     cty.NullVal(cty.String),
+		"organization": cty.StringVal("hashicorp"),
+		"token":        cty.NullVal(cty.String),
+		"workspaces": cty.ObjectVal(map[string]cty.Value{
+			"name": cty.NullVal(cty.String),
+			"tags": cty.SetVal(
+				[]cty.Value{
+					cty.StringVal("sometag"),
+				},
+			),
+		}),
+	})
+
+	b, bCleanup := testBackend(t, config, nil)
+	defer bCleanup()
+
+	// Make sure the workspace doesn't exist yet -- otherwise, we can't test what
+	// happens when a workspace gets created. This is why we can't use "name" in
+	// the backend config above, btw: if you do, testBackend() creates the default
+	// workspace before we get a chance to do anything.
+	_, err := b.client.Workspaces.Read(context.Background(), b.organization, workspaceName)
+	if err != tfe.ErrResourceNotFound {
+		t.Fatalf("the workspace we were about to try and create (%s/%s) already exists in the mocks somehow, so this test isn't trustworthy anymore", b.organization, workspaceName)
+	}
+
+	_, err = b.StateMgr(workspaceName)
+	if err != nil {
+		t.Fatalf("expected no error from StateMgr, despite not being able to set remote Terraform version: %#v", err)
+	}
+	// Make sure the workspace was created:
+	workspace, err := b.client.Workspaces.Read(context.Background(), b.organization, workspaceName)
+	if err != nil {
+		t.Fatalf("b.StateMgr() didn't actually create the desired workspace")
+	}
+	// Make sure our mocks still error as expected, using the same update function b.StateMgr() would call:
+	_, err = b.client.Workspaces.UpdateByID(
+		context.Background(),
+		workspace.ID,
+		tfe.WorkspaceUpdateOptions{TerraformVersion: tfe.String("1.1.0")},
+	)
+	if err == nil {
+		t.Fatalf("the mocks aren't emulating a nonexistent remote Terraform version correctly, so this test isn't trustworthy anymore")
+	}
+}
+
+func TestCloud_setConfigurationFields(t *testing.T) {
+	originalForceBackendEnv := os.Getenv("TF_FORCE_LOCAL_BACKEND")
+
+	cases := map[string]struct {
+		obj                   cty.Value
+		expectedHostname      string
+		expectedOrganziation  string
+		expectedWorkspaceName string
+		expectedWorkspaceTags []string
+		expectedForceLocal    bool
+		setEnv                func()
+		resetEnv              func()
+		expectedErr           string
+	}{
+		"with hostname set": {
+			obj: cty.ObjectVal(map[string]cty.Value{
+				"organization": cty.StringVal("hashicorp"),
+				"hostname":     cty.StringVal("hashicorp.com"),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			expectedHostname:     "hashicorp.com",
+			expectedOrganziation: "hashicorp",
+		},
+		"with hostname not set, set to default hostname": {
+			obj: cty.ObjectVal(map[string]cty.Value{
+				"organization": cty.StringVal("hashicorp"),
+				"hostname":     cty.NullVal(cty.String),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			expectedHostname:     defaultHostname,
+			expectedOrganziation: "hashicorp",
+		},
+		"with workspace name set": {
+			obj: cty.ObjectVal(map[string]cty.Value{
+				"organization": cty.StringVal("hashicorp"),
+				"hostname":     cty.StringVal("hashicorp.com"),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("prod"),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			expectedHostname:      "hashicorp.com",
+			expectedOrganziation:  "hashicorp",
+			expectedWorkspaceName: "prod",
+		},
+		"with workspace tags set": {
+			obj: cty.ObjectVal(map[string]cty.Value{
+				"organization": cty.StringVal("hashicorp"),
+				"hostname":     cty.StringVal("hashicorp.com"),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.NullVal(cty.String),
+					"tags": cty.SetVal(
+						[]cty.Value{
+							cty.StringVal("billing"),
+						},
+					),
+				}),
+			}),
+			expectedHostname:      "hashicorp.com",
+			expectedOrganziation:  "hashicorp",
+			expectedWorkspaceTags: []string{"billing"},
+		},
+		"with force local set": {
+			obj: cty.ObjectVal(map[string]cty.Value{
+				"organization": cty.StringVal("hashicorp"),
+				"hostname":     cty.StringVal("hashicorp.com"),
+				"workspaces": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.NullVal(cty.String),
+					"tags": cty.NullVal(cty.Set(cty.String)),
+				}),
+			}),
+			expectedHostname:     "hashicorp.com",
+			expectedOrganziation: "hashicorp",
+			setEnv: func() {
+				os.Setenv("TF_FORCE_LOCAL_BACKEND", "1")
+			},
+			resetEnv: func() {
+				os.Setenv("TF_FORCE_LOCAL_BACKEND", originalForceBackendEnv)
+			},
+			expectedForceLocal: true,
+		},
+	}
+
+	for name, tc := range cases {
+		b := &Cloud{}
+
+		// if `setEnv` is set, then we expect `resetEnv` to also be set
+		if tc.setEnv != nil {
+			tc.setEnv()
+			defer tc.resetEnv()
+		}
+
+		errDiags := b.setConfigurationFields(tc.obj)
+		if errDiags.HasErrors() || tc.expectedErr != "" {
+			actualErr := errDiags.Err().Error()
+			if !strings.Contains(actualErr, tc.expectedErr) {
+				t.Fatalf("%s: unexpected validation result: %v", name, errDiags.Err())
+			}
+		}
+
+		if tc.expectedHostname != "" && b.hostname != tc.expectedHostname {
+			t.Fatalf("%s: expected hostname %s to match configured hostname %s", name, b.hostname, tc.expectedHostname)
+		}
+		if tc.expectedOrganziation != "" && b.organization != tc.expectedOrganziation {
+			t.Fatalf("%s: expected organization (%s) to match configured organization (%s)", name, b.organization, tc.expectedOrganziation)
+		}
+		if tc.expectedWorkspaceName != "" && b.WorkspaceMapping.Name != tc.expectedWorkspaceName {
+			t.Fatalf("%s: expected workspace name mapping (%s) to match configured workspace name (%s)", name, b.WorkspaceMapping.Name, tc.expectedWorkspaceName)
+		}
+		if len(tc.expectedWorkspaceTags) > 0 {
+			presentSet := make(map[string]struct{})
+			for _, tag := range b.WorkspaceMapping.Tags {
+				presentSet[tag] = struct{}{}
+			}
+
+			expectedSet := make(map[string]struct{})
+			for _, tag := range tc.expectedWorkspaceTags {
+				expectedSet[tag] = struct{}{}
+			}
+
+			var missing []string
+			var unexpected []string
+
+			for _, expected := range tc.expectedWorkspaceTags {
+				if _, ok := presentSet[expected]; !ok {
+					missing = append(missing, expected)
+				}
+			}
+
+			for _, actual := range b.WorkspaceMapping.Tags {
+				if _, ok := expectedSet[actual]; !ok {
+					unexpected = append(unexpected, actual)
+				}
+			}
+
+			if len(missing) > 0 {
+				t.Fatalf("%s: expected workspace tag mapping (%s) to contain the following tags: %s", name, b.WorkspaceMapping.Tags, missing)
+			}
+
+			if len(unexpected) > 0 {
+				t.Fatalf("%s: expected workspace tag mapping (%s) to NOT contain the following tags: %s", name, b.WorkspaceMapping.Tags, unexpected)
+			}
+
+		}
+		if tc.expectedForceLocal != false && b.forceLocal != tc.expectedForceLocal {
+			t.Fatalf("%s: expected force local backend to be set ", name)
+		}
+	}
+}
+
+func TestCloud_localBackend(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	local, ok := b.local.(*backendLocal.Local)
+	if !ok {
+		t.Fatalf("expected b.local to be \"*local.Local\", got: %T", b.local)
+	}
+
+	cloud, ok := local.Backend.(*Cloud)
+	if !ok {
+		t.Fatalf("expected local.Backend to be *cloud.Cloud, got: %T", cloud)
+	}
+}
+
+func TestCloud_addAndRemoveWorkspacesDefault(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	if _, err := b.StateMgr(testBackendSingleWorkspaceName); err != nil {
+		t.Fatalf("expected no error, got %v", err)
+	}
+
+	if err := b.DeleteWorkspace(testBackendSingleWorkspaceName, true); err != backend.ErrWorkspacesNotSupported {
+		t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err)
+	}
+}
+
+func TestCloud_StateMgr_versionCheck(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	// Some fixed versions for testing with. This logic is a simple string
+	// comparison, so we don't need many test cases.
+	v0135 := version.Must(version.NewSemver("0.13.5"))
+	v0140 := version.Must(version.NewSemver("0.14.0"))
+
+	// Save original local version state and restore afterwards
+	p := tfversion.Prerelease
+	v := tfversion.Version
+	s := tfversion.SemVer
+	defer func() {
+		tfversion.Prerelease = p
+		tfversion.Version = v
+		tfversion.SemVer = s
+	}()
+
+	// For this test, the local Terraform version is set to 0.14.0
+	tfversion.Prerelease = ""
+	tfversion.Version = v0140.String()
+	tfversion.SemVer = v0140
+
+	// Update the mock remote workspace Terraform version to match the local
+	// Terraform version
+	if _, err := b.client.Workspaces.Update(
+		context.Background(),
+		b.organization,
+		b.WorkspaceMapping.Name,
+		tfe.WorkspaceUpdateOptions{
+			TerraformVersion: tfe.String(v0140.String()),
+		},
+	); err != nil {
+		t.Fatalf("error: %v", err)
+	}
+
+	// This should succeed
+	if _, err := b.StateMgr(testBackendSingleWorkspaceName); err != nil {
+		t.Fatalf("expected no error, got %v", err)
+	}
+
+	// Now change the remote workspace to a different Terraform version
+	if _, err := b.client.Workspaces.Update(
+		context.Background(),
+		b.organization,
+		b.WorkspaceMapping.Name,
+		tfe.WorkspaceUpdateOptions{
+			TerraformVersion: tfe.String(v0135.String()),
+		},
+	); err != nil {
+		t.Fatalf("error: %v", err)
+	}
+
+	// This should fail
+	want := `Remote workspace Terraform version "0.13.5" does not match local Terraform version "0.14.0"`
+	if _, err := b.StateMgr(testBackendSingleWorkspaceName); err.Error() != want {
+		t.Fatalf("wrong error\n got: %v\nwant: %v", err.Error(), want)
+	}
+}
+
+func TestCloud_StateMgr_versionCheckLatest(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	v0140 := version.Must(version.NewSemver("0.14.0"))
+
+	// Save original local version state and restore afterwards
+	p := tfversion.Prerelease
+	v := tfversion.Version
+	s := tfversion.SemVer
+	defer func() {
+		tfversion.Prerelease = p
+		tfversion.Version = v
+		tfversion.SemVer = s
+	}()
+
+	// For this test, the local Terraform version is set to 0.14.0
+	tfversion.Prerelease = ""
+	tfversion.Version = v0140.String()
+	tfversion.SemVer = v0140
+
+	// Update the remote workspace to the pseudo-version "latest"
+	if _, err := b.client.Workspaces.Update(
+		context.Background(),
+		b.organization,
+		b.WorkspaceMapping.Name,
+		tfe.WorkspaceUpdateOptions{
+			TerraformVersion: tfe.String("latest"),
+		},
+	); err != nil {
+		t.Fatalf("error: %v", err)
+	}
+
+	// This should succeed despite not being a string match
+	if _, err := b.StateMgr(testBackendSingleWorkspaceName); err != nil {
+		t.Fatalf("expected no error, got %v", err)
+	}
+}
+
+func TestCloud_VerifyWorkspaceTerraformVersion(t *testing.T) {
+	testCases := []struct {
+		local         string
+		remote        string
+		executionMode string
+		wantErr       bool
+	}{
+		{"0.13.5", "0.13.5", "agent", false},
+		{"0.14.0", "0.13.5", "remote", true},
+		{"0.14.0", "0.13.5", "local", false},
+		{"0.14.0", "0.14.1", "remote", false},
+		{"0.14.0", "1.0.99", "remote", false},
+		{"0.14.0", "1.1.0", "remote", false},
+		{"0.14.0", "1.3.0", "remote", true},
+		{"1.2.0", "1.2.99", "remote", false},
+		{"1.2.0", "1.3.0", "remote", true},
+		{"0.15.0", "latest", "remote", false},
+		{"1.1.5", "~> 1.1.1", "remote", false},
+		{"1.1.5", "> 1.1.0, < 1.3.0", "remote", false},
+		{"1.1.5", "~> 1.0.1", "remote", true},
+		// pre-release versions are comparable within their pre-release stage (dev,
+		// alpha, beta), but not comparable to different stages and not comparable
+		// to final releases.
+		{"1.1.0-beta1", "1.1.0-beta1", "remote", false},
+		{"1.1.0-beta1", "~> 1.1.0-beta", "remote", false},
+		{"1.1.0", "~> 1.1.0-beta", "remote", true},
+		{"1.1.0-beta1", "~> 1.1.0-dev", "remote", true},
+	}
+	for _, tc := range testCases {
+		t.Run(fmt.Sprintf("local %s, remote %s", tc.local, tc.remote), func(t *testing.T) {
+			b, bCleanup := testBackendWithName(t)
+			defer bCleanup()
+
+			local := version.Must(version.NewSemver(tc.local))
+
+			// Save original local version state and restore afterwards
+			p := tfversion.Prerelease
+			v := tfversion.Version
+			s := tfversion.SemVer
+			defer func() {
+				tfversion.Prerelease = p
+				tfversion.Version = v
+				tfversion.SemVer = s
+			}()
+
+			// Override local version as specified
+			tfversion.Prerelease = ""
+			tfversion.Version = local.String()
+			tfversion.SemVer = local
+
+			// Update the mock remote workspace Terraform version to the
+			// specified remote version
+			if _, err := b.client.Workspaces.Update(
+				context.Background(),
+				b.organization,
+				b.WorkspaceMapping.Name,
+				tfe.WorkspaceUpdateOptions{
+					ExecutionMode:    &tc.executionMode,
+					TerraformVersion: tfe.String(tc.remote),
+				},
+			); err != nil {
+				t.Fatalf("error: %v", err)
+			}
+
+			diags := b.VerifyWorkspaceTerraformVersion(backend.DefaultStateName)
+			if tc.wantErr {
+				if len(diags) != 1 {
+					t.Fatal("expected diag, but none returned")
+				}
+				if got := diags.Err().Error(); !strings.Contains(got, "Incompatible Terraform version") {
+					t.Fatalf("unexpected error: %s", got)
+				}
+			} else {
+				if len(diags) != 0 {
+					t.Fatalf("unexpected diags: %s", diags.Err())
+				}
+			}
+		})
+	}
+}
+
+func TestCloud_VerifyWorkspaceTerraformVersion_workspaceErrors(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	// Attempting to check the version against a workspace which doesn't exist
+	// should result in no errors
+	diags := b.VerifyWorkspaceTerraformVersion("invalid-workspace")
+	if len(diags) != 0 {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+
+	// Use a special workspace ID to trigger a 500 error, which should result
+	// in a failed check
+	diags = b.VerifyWorkspaceTerraformVersion("network-error")
+	if len(diags) != 1 {
+		t.Fatal("expected diag, but none returned")
+	}
+	if got := diags.Err().Error(); !strings.Contains(got, "Error looking up workspace: Workspace read failed") {
+		t.Fatalf("unexpected error: %s", got)
+	}
+
+	// Update the mock remote workspace Terraform version to an invalid version
+	if _, err := b.client.Workspaces.Update(
+		context.Background(),
+		b.organization,
+		b.WorkspaceMapping.Name,
+		tfe.WorkspaceUpdateOptions{
+			TerraformVersion: tfe.String("1.0.cheetarah"),
+		},
+	); err != nil {
+		t.Fatalf("error: %v", err)
+	}
+	diags = b.VerifyWorkspaceTerraformVersion(backend.DefaultStateName)
+
+	if len(diags) != 1 {
+		t.Fatal("expected diag, but none returned")
+	}
+	if got := diags.Err().Error(); !strings.Contains(got, "Incompatible Terraform version: The remote workspace specified") {
+		t.Fatalf("unexpected error: %s", got)
+	}
+}
+
+func TestCloud_VerifyWorkspaceTerraformVersion_ignoreFlagSet(t *testing.T) {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	// If the ignore flag is set, the behaviour changes
+	b.IgnoreVersionConflict()
+
+	// Different local & remote versions to cause an error
+	local := version.Must(version.NewSemver("0.14.0"))
+	remote := version.Must(version.NewSemver("0.13.5"))
+
+	// Save original local version state and restore afterwards
+	p := tfversion.Prerelease
+	v := tfversion.Version
+	s := tfversion.SemVer
+	defer func() {
+		tfversion.Prerelease = p
+		tfversion.Version = v
+		tfversion.SemVer = s
+	}()
+
+	// Override local version as specified
+	tfversion.Prerelease = ""
+	tfversion.Version = local.String()
+	tfversion.SemVer = local
+
+	// Update the mock remote workspace Terraform version to the
+	// specified remote version
+	if _, err := b.client.Workspaces.Update(
+		context.Background(),
+		b.organization,
+		b.WorkspaceMapping.Name,
+		tfe.WorkspaceUpdateOptions{
+			TerraformVersion: tfe.String(remote.String()),
+		},
+	); err != nil {
+		t.Fatalf("error: %v", err)
+	}
+
+	diags := b.VerifyWorkspaceTerraformVersion(backend.DefaultStateName)
+	if len(diags) != 1 {
+		t.Fatal("expected diag, but none returned")
+	}
+
+	if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
+		t.Errorf("wrong severity: got %#v, want %#v", got, want)
+	}
+	if got, want := diags[0].Description().Summary, "Incompatible Terraform version"; got != want {
+		t.Errorf("wrong summary: got %s, want %s", got, want)
+	}
+	wantDetail := "The local Terraform version (0.14.0) does not meet the version requirements for remote workspace hashicorp/app-prod (0.13.5)."
+	if got := diags[0].Description().Detail; got != wantDetail {
+		t.Errorf("wrong summary: got %s, want %s", got, wantDetail)
+	}
+}
+
+func TestCloudBackend_DeleteWorkspace_SafeAndForce(t *testing.T) {
+	b, bCleanup := testBackendWithTags(t)
+	defer bCleanup()
+	safeDeleteWorkspaceName := "safe-delete-workspace"
+	forceDeleteWorkspaceName := "force-delete-workspace"
+
+	_, err := b.StateMgr(safeDeleteWorkspaceName)
+	if err != nil {
+		t.Fatalf("error: %s", err)
+	}
+
+	_, err = b.StateMgr(forceDeleteWorkspaceName)
+	if err != nil {
+		t.Fatalf("error: %s", err)
+	}
+
+	// sanity check that the mock now contains two workspaces
+	wl, err := b.Workspaces()
+	if err != nil {
+		t.Fatalf("error fetching workspace names: %v", err)
+	}
+	if len(wl) != 2 {
+		t.Fatalf("expected 2 workspaced but got %d", len(wl))
+	}
+
+	c := context.Background()
+	safeDeleteWorkspace, err := b.client.Workspaces.Read(c, b.organization, safeDeleteWorkspaceName)
+	if err != nil {
+		t.Fatalf("error fetching workspace: %v", err)
+	}
+
+	// Lock a workspace so that it should fail to be safe deleted
+	_, err = b.client.Workspaces.Lock(context.Background(), safeDeleteWorkspace.ID, tfe.WorkspaceLockOptions{Reason: tfe.String("test")})
+	if err != nil {
+		t.Fatalf("error locking workspace: %v", err)
+	}
+	err = b.DeleteWorkspace(safeDeleteWorkspaceName, false)
+	if err == nil {
+		t.Fatalf("workspace should have failed to safe delete")
+	}
+
+	// unlock the workspace and confirm that safe-delete now works
+	_, err = b.client.Workspaces.Unlock(context.Background(), safeDeleteWorkspace.ID)
+	if err != nil {
+		t.Fatalf("error unlocking workspace: %v", err)
+	}
+	err = b.DeleteWorkspace(safeDeleteWorkspaceName, false)
+	if err != nil {
+		t.Fatalf("error safe deleting workspace: %v", err)
+	}
+
+	// lock a workspace and then confirm that force deleting it works
+	forceDeleteWorkspace, err := b.client.Workspaces.Read(c, b.organization, forceDeleteWorkspaceName)
+	if err != nil {
+		t.Fatalf("error fetching workspace: %v", err)
+	}
+	_, err = b.client.Workspaces.Lock(context.Background(), forceDeleteWorkspace.ID, tfe.WorkspaceLockOptions{Reason: tfe.String("test")})
+	if err != nil {
+		t.Fatalf("error locking workspace: %v", err)
+	}
+	err = b.DeleteWorkspace(forceDeleteWorkspaceName, true)
+	if err != nil {
+		t.Fatalf("error force deleting workspace: %v", err)
+	}
+}
+
+func TestCloudBackend_DeleteWorkspace_DoesNotExist(t *testing.T) {
+	b, bCleanup := testBackendWithTags(t)
+	defer bCleanup()
+
+	err := b.DeleteWorkspace("non-existent-workspace", false)
+	if err != nil {
+		t.Fatalf("expected deleting a workspace which does not exist to succeed")
+	}
+}
+
+func TestCloud_ServiceDiscoveryAliases(t *testing.T) {
+	s := testServer(t)
+	b := New(testDisco(s))
+
+	diag := b.Configure(cty.ObjectVal(map[string]cty.Value{
+		"hostname":     cty.NullVal(cty.String), // Forces aliasing to test server
+		"organization": cty.StringVal("hashicorp"),
+		"token":        cty.NullVal(cty.String),
+		"workspaces": cty.ObjectVal(map[string]cty.Value{
+			"name": cty.StringVal("prod"),
+			"tags": cty.NullVal(cty.Set(cty.String)),
+		}),
+	}))
+	if diag.HasErrors() {
+		t.Fatalf("expected no diagnostic errors, got %s", diag.Err())
+	}
+
+	aliases, err := b.ServiceDiscoveryAliases()
+	if err != nil {
+		t.Fatalf("expected no errors, got %s", err)
+	}
+	if len(aliases) != 1 {
+		t.Fatalf("expected 1 alias but got %d", len(aliases))
+	}
+}
diff --git a/v1.5.7/internal/cloud/cloud_integration.go b/v1.5.7/internal/cloud/cloud_integration.go
new file mode 100644
index 0000000..d453e45
--- /dev/null
+++ b/v1.5.7/internal/cloud/cloud_integration.go
@@ -0,0 +1,115 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"context"
+	"fmt"
+	"strconv"
+	"time"
+
+	"github.com/hashicorp/go-tfe"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/mitchellh/cli"
+)
+
+// IntegrationOutputWriter is an interface used to to write output tailored for
+// Terraform Cloud integrations
+type IntegrationOutputWriter interface {
+	End()
+	OutputElapsed(message string, maxMessage int)
+	Output(str string)
+	SubOutput(str string)
+}
+
+// IntegrationContext is a set of data that is useful when performing Terraform Cloud integration operations
+type IntegrationContext struct {
+	B             *Cloud
+	StopContext   context.Context
+	CancelContext context.Context
+	Op            *backend.Operation
+	Run           *tfe.Run
+}
+
+// integrationCLIOutput implements IntegrationOutputWriter
+type integrationCLIOutput struct {
+	CLI       cli.Ui
+	Colorizer Colorer
+	started   time.Time
+}
+
+var _ IntegrationOutputWriter = (*integrationCLIOutput)(nil) // Compile time check
+
+func (s *IntegrationContext) Poll(backoffMinInterval float64, backoffMaxInterval float64, every func(i int) (bool, error)) error {
+	for i := 0; ; i++ {
+		select {
+		case <-s.StopContext.Done():
+			return s.StopContext.Err()
+		case <-s.CancelContext.Done():
+			return s.CancelContext.Err()
+		case <-time.After(backoff(backoffMinInterval, backoffMaxInterval, i)):
+			// blocks for a time between min and max
+		}
+
+		cont, err := every(i)
+		if !cont {
+			return err
+		}
+	}
+}
+
+// BeginOutput writes a preamble to the CLI and creates a new IntegrationOutputWriter interface
+// to write the remaining CLI output to. Use IntegrationOutputWriter.End() to complete integration
+// output
+func (s *IntegrationContext) BeginOutput(name string) IntegrationOutputWriter {
+	var result IntegrationOutputWriter = &integrationCLIOutput{
+		CLI:       s.B.CLI,
+		Colorizer: s.B.Colorize(),
+		started:   time.Now(),
+	}
+
+	result.Output("\n[bold]" + name + ":\n")
+
+	return result
+}
+
+// End writes the termination output for the integration
+func (s *integrationCLIOutput) End() {
+	if s.CLI == nil {
+		return
+	}
+
+	s.CLI.Output("\n------------------------------------------------------------------------\n")
+}
+
+// Output writes a string after colorizing it using any [colorstrings](https://github.com/mitchellh/colorstring) it contains
+func (s *integrationCLIOutput) Output(str string) {
+	if s.CLI == nil {
+		return
+	}
+	s.CLI.Output(s.Colorizer.Color(str))
+}
+
+// SubOutput writes a string prefixed by a "│ " after colorizing it using any [colorstrings](https://github.com/mitchellh/colorstring) it contains
+func (s *integrationCLIOutput) SubOutput(str string) {
+	if s.CLI == nil {
+		return
+	}
+	s.CLI.Output(s.Colorizer.Color(fmt.Sprintf("[reset]│ %s", str)))
+}
+
+// OutputElapsed writes a string followed by the amount of time that has elapsed since calling BeginOutput.
+// Example pending output; the variable spacing (50 chars) allows up to 99 tasks (two digits) in each category:
+// ---------------
+// 13 tasks still pending, 0 passed, 0 failed ...
+// 13 tasks still pending, 0 passed, 0 failed ...       (8s elapsed)
+// 13 tasks still pending, 0 passed, 0 failed ...       (19s elapsed)
+// 13 tasks still pending, 0 passed, 0 failed ...       (33s elapsed)
+func (s *integrationCLIOutput) OutputElapsed(message string, maxMessage int) {
+	if s.CLI == nil {
+		return
+	}
+	elapsed := time.Since(s.started).Truncate(1 * time.Second)
+	s.CLI.Output(fmt.Sprintf("%-"+strconv.FormatInt(int64(maxMessage), 10)+"s", message) + s.Colorizer.Color(fmt.Sprintf("[dim](%s elapsed)", elapsed)))
+}
diff --git a/v1.5.7/internal/cloud/cloud_variables.go b/v1.5.7/internal/cloud/cloud_variables.go
new file mode 100644
index 0000000..c4cab0e
--- /dev/null
+++ b/v1.5.7/internal/cloud/cloud_variables.go
@@ -0,0 +1,45 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"github.com/hashicorp/hcl/v2/hclwrite"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func allowedSourceType(source terraform.ValueSourceType) bool {
+	return source == terraform.ValueFromNamedFile || source == terraform.ValueFromCLIArg || source == terraform.ValueFromEnvVar
+}
+
+// ParseCloudRunVariables accepts a mapping of unparsed values and a mapping of variable
+// declarations and returns a name/value variable map appropriate for an API run context,
+// that is, containing variables only sourced from non-file inputs like CLI args
+// and environment variables. However, all variable parsing diagnostics are returned
+// in order to allow callers to short circuit cloud runs that contain variable
+// declaration or parsing errors. The only exception is that missing required values are not
+// considered errors because they may be defined within the cloud workspace.
+func ParseCloudRunVariables(vv map[string]backend.UnparsedVariableValue, decls map[string]*configs.Variable) (map[string]string, tfdiags.Diagnostics) {
+	declared, diags := backend.ParseDeclaredVariableValues(vv, decls)
+	_, undedeclaredDiags := backend.ParseUndeclaredVariableValues(vv, decls)
+	diags = diags.Append(undedeclaredDiags)
+
+	ret := make(map[string]string, len(declared))
+
+	// Even if there are parsing or declaration errors, populate the return map with the
+	// variables that could be used for cloud runs
+	for name, v := range declared {
+		if !allowedSourceType(v.SourceType) {
+			continue
+		}
+
+		// RunVariables are always expressed as HCL strings
+		tokens := hclwrite.TokensForValue(v.Value)
+		ret[name] = string(tokens.Bytes())
+	}
+
+	return ret, diags
+}
diff --git a/v1.5.7/internal/cloud/cloud_variables_test.go b/v1.5.7/internal/cloud/cloud_variables_test.go
new file mode 100644
index 0000000..914862f
--- /dev/null
+++ b/v1.5.7/internal/cloud/cloud_variables_test.go
@@ -0,0 +1,186 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestParseCloudRunVariables(t *testing.T) {
+	t.Run("populates variables from allowed sources", func(t *testing.T) {
+		vv := map[string]backend.UnparsedVariableValue{
+			"undeclared":                      testUnparsedVariableValue{source: terraform.ValueFromCLIArg, value: cty.StringVal("0")},
+			"declaredFromConfig":              testUnparsedVariableValue{source: terraform.ValueFromConfig, value: cty.StringVal("1")},
+			"declaredFromNamedFileMapString":  testUnparsedVariableValue{source: terraform.ValueFromNamedFile, value: cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("bar")})},
+			"declaredFromNamedFileBool":       testUnparsedVariableValue{source: terraform.ValueFromNamedFile, value: cty.BoolVal(true)},
+			"declaredFromNamedFileNumber":     testUnparsedVariableValue{source: terraform.ValueFromNamedFile, value: cty.NumberIntVal(2)},
+			"declaredFromNamedFileListString": testUnparsedVariableValue{source: terraform.ValueFromNamedFile, value: cty.ListVal([]cty.Value{cty.StringVal("2a"), cty.StringVal("2b")})},
+			"declaredFromNamedFileNull":       testUnparsedVariableValue{source: terraform.ValueFromNamedFile, value: cty.NullVal(cty.String)},
+			"declaredFromNamedMapComplex":     testUnparsedVariableValue{source: terraform.ValueFromNamedFile, value: cty.MapVal(map[string]cty.Value{"foo": cty.ObjectVal(map[string]cty.Value{"qux": cty.ListVal([]cty.Value{cty.BoolVal(true), cty.BoolVal(false)})})})},
+			"declaredFromCLIArg":              testUnparsedVariableValue{source: terraform.ValueFromCLIArg, value: cty.StringVal("3")},
+			"declaredFromEnvVar":              testUnparsedVariableValue{source: terraform.ValueFromEnvVar, value: cty.StringVal("4")},
+		}
+
+		decls := map[string]*configs.Variable{
+			"declaredFromConfig": {
+				Name:           "declaredFromConfig",
+				Type:           cty.String,
+				ConstraintType: cty.String,
+				ParsingMode:    configs.VariableParseLiteral,
+				DeclRange: hcl.Range{
+					Filename: "fake.tf",
+					Start:    hcl.Pos{Line: 2, Column: 1, Byte: 0},
+					End:      hcl.Pos{Line: 2, Column: 1, Byte: 0},
+				},
+			},
+			"declaredFromNamedFileMapString": {
+				Name:           "declaredFromNamedFileMapString",
+				Type:           cty.Map(cty.String),
+				ConstraintType: cty.Map(cty.String),
+				ParsingMode:    configs.VariableParseHCL,
+				DeclRange: hcl.Range{
+					Filename: "fake.tf",
+					Start:    hcl.Pos{Line: 2, Column: 1, Byte: 0},
+					End:      hcl.Pos{Line: 2, Column: 1, Byte: 0},
+				},
+			},
+			"declaredFromNamedFileBool": {
+				Name:           "declaredFromNamedFileBool",
+				Type:           cty.Bool,
+				ConstraintType: cty.Bool,
+				ParsingMode:    configs.VariableParseLiteral,
+				DeclRange: hcl.Range{
+					Filename: "fake.tf",
+					Start:    hcl.Pos{Line: 2, Column: 1, Byte: 0},
+					End:      hcl.Pos{Line: 2, Column: 1, Byte: 0},
+				},
+			},
+			"declaredFromNamedFileNumber": {
+				Name:           "declaredFromNamedFileNumber",
+				Type:           cty.Number,
+				ConstraintType: cty.Number,
+				ParsingMode:    configs.VariableParseLiteral,
+				DeclRange: hcl.Range{
+					Filename: "fake.tf",
+					Start:    hcl.Pos{Line: 2, Column: 1, Byte: 0},
+					End:      hcl.Pos{Line: 2, Column: 1, Byte: 0},
+				},
+			},
+			"declaredFromNamedFileListString": {
+				Name:           "declaredFromNamedFileListString",
+				Type:           cty.List(cty.String),
+				ConstraintType: cty.List(cty.String),
+				ParsingMode:    configs.VariableParseHCL,
+				DeclRange: hcl.Range{
+					Filename: "fake.tf",
+					Start:    hcl.Pos{Line: 2, Column: 1, Byte: 0},
+					End:      hcl.Pos{Line: 2, Column: 1, Byte: 0},
+				},
+			},
+			"declaredFromNamedFileNull": {
+				Name:           "declaredFromNamedFileNull",
+				Type:           cty.String,
+				ConstraintType: cty.String,
+				ParsingMode:    configs.VariableParseHCL,
+				DeclRange: hcl.Range{
+					Filename: "fake.tf",
+					Start:    hcl.Pos{Line: 2, Column: 1, Byte: 0},
+					End:      hcl.Pos{Line: 2, Column: 1, Byte: 0},
+				},
+			},
+			"declaredFromNamedMapComplex": {
+				Name:           "declaredFromNamedMapComplex",
+				Type:           cty.DynamicPseudoType,
+				ConstraintType: cty.DynamicPseudoType,
+				ParsingMode:    configs.VariableParseHCL,
+				DeclRange: hcl.Range{
+					Filename: "fake.tf",
+					Start:    hcl.Pos{Line: 2, Column: 1, Byte: 0},
+					End:      hcl.Pos{Line: 2, Column: 1, Byte: 0},
+				},
+			},
+			"declaredFromCLIArg": {
+				Name:           "declaredFromCLIArg",
+				Type:           cty.String,
+				ConstraintType: cty.String,
+				ParsingMode:    configs.VariableParseLiteral,
+				DeclRange: hcl.Range{
+					Filename: "fake.tf",
+					Start:    hcl.Pos{Line: 2, Column: 1, Byte: 0},
+					End:      hcl.Pos{Line: 2, Column: 1, Byte: 0},
+				},
+			},
+			"declaredFromEnvVar": {
+				Name:           "declaredFromEnvVar",
+				Type:           cty.String,
+				ConstraintType: cty.String,
+				ParsingMode:    configs.VariableParseLiteral,
+				DeclRange: hcl.Range{
+					Filename: "fake.tf",
+					Start:    hcl.Pos{Line: 2, Column: 1, Byte: 0},
+					End:      hcl.Pos{Line: 2, Column: 1, Byte: 0},
+				},
+			},
+			"missing": {
+				Name:           "missing",
+				Type:           cty.String,
+				ConstraintType: cty.String,
+				Default:        cty.StringVal("2"),
+				ParsingMode:    configs.VariableParseLiteral,
+				DeclRange: hcl.Range{
+					Filename: "fake.tf",
+					Start:    hcl.Pos{Line: 2, Column: 1, Byte: 0},
+					End:      hcl.Pos{Line: 2, Column: 1, Byte: 0},
+				},
+			},
+		}
+		wantVals := make(map[string]string)
+		wantVals["declaredFromNamedFileBool"] = "true"
+		wantVals["declaredFromNamedFileNumber"] = "2"
+		wantVals["declaredFromNamedFileListString"] = `["2a", "2b"]`
+		wantVals["declaredFromNamedFileNull"] = "null"
+		wantVals["declaredFromNamedFileMapString"] = "{\n  foo = \"bar\"\n}"
+		wantVals["declaredFromNamedMapComplex"] = "{\n  foo = {\n    qux = [true, false]\n  }\n}"
+		wantVals["declaredFromCLIArg"] = `"3"`
+		wantVals["declaredFromEnvVar"] = `"4"`
+
+		gotVals, diags := ParseCloudRunVariables(vv, decls)
+		if diff := cmp.Diff(wantVals, gotVals, cmp.Comparer(cty.Value.RawEquals)); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+
+		if got, want := len(diags), 1; got != want {
+			t.Fatalf("expected 1 variable error: %v, got %v", diags.Err(), want)
+		}
+
+		if got, want := diags[0].Description().Summary, "Value for undeclared variable"; got != want {
+			t.Errorf("wrong summary for diagnostic 0\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+}
+
+type testUnparsedVariableValue struct {
+	source terraform.ValueSourceType
+	value  cty.Value
+}
+
+func (v testUnparsedVariableValue) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) {
+	return &terraform.InputValue{
+		Value:      v.value,
+		SourceType: v.source,
+		SourceRange: tfdiags.SourceRange{
+			Filename: "fake.tfvars",
+			Start:    tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+			End:      tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
+		},
+	}, nil
+}
diff --git a/v1.5.7/internal/cloud/configchangemode_string.go b/v1.5.7/internal/cloud/configchangemode_string.go
new file mode 100644
index 0000000..b60692b
--- /dev/null
+++ b/v1.5.7/internal/cloud/configchangemode_string.go
@@ -0,0 +1,37 @@
+// Code generated by "stringer -type ConfigChangeMode"; DO NOT EDIT.
+
+package cloud
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[ConfigMigrationIn-8600]
+	_ = x[ConfigMigrationOut-8598]
+	_ = x[ConfigChangeInPlace-8635]
+	_ = x[ConfigChangeIrrelevant-129335]
+}
+
+const (
+	_ConfigChangeMode_name_0 = "ConfigMigrationOut"
+	_ConfigChangeMode_name_1 = "ConfigMigrationIn"
+	_ConfigChangeMode_name_2 = "ConfigChangeInPlace"
+	_ConfigChangeMode_name_3 = "ConfigChangeIrrelevant"
+)
+
+func (i ConfigChangeMode) String() string {
+	switch {
+	case i == 8598:
+		return _ConfigChangeMode_name_0
+	case i == 8600:
+		return _ConfigChangeMode_name_1
+	case i == 8635:
+		return _ConfigChangeMode_name_2
+	case i == 129335:
+		return _ConfigChangeMode_name_3
+	default:
+		return "ConfigChangeMode(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/v1.5.7/internal/cloud/e2e/README.md b/v1.5.7/internal/cloud/e2e/README.md
new file mode 100644
index 0000000..7928fc3
--- /dev/null
+++ b/v1.5.7/internal/cloud/e2e/README.md
@@ -0,0 +1,24 @@
+# How to run tests
+
+To run them, use:
+```
+TFE_TOKEN=<token> TFE_HOSTNAME=<hostname> TF_ACC=1 go test  ./internal/cloud/e2e/... -ldflags "-X \"github.com/hashicorp/terraform/version.Prerelease=<PRE-RELEASE>\""
+```
+
+Required flags
+* `TF_ACC=1`. This variable is used as part of terraform for tests that make 
+  external network calls. This is needed to run these tests. Without it, the
+  tests do not run.
+* `TFE_TOKEN=<admin token>` and `TFE_HOSTNAME=<hostname>`. The helpers
+for these tests require admin access to a TFC/TFE instance.
+* `-timeout=30m`. Some of these tests take longer than the default 10m timeout for `go test`.
+
+### Flags
+
+* Use the `-v` flag for normal verbose mode.
+* Use the `-tfoutput` flag to print the terraform output to standard out.
+*  Use `-ldflags` to change the version Prerelease to match a version
+available remotely. Some behaviors rely on the exact local version Terraform
+being available in TFC/TFE, and manipulating the Prerelease during build is
+often the only way to ensure this.
+[(More on `-ldflags`.)](https://www.digitalocean.com/community/tutorials/using-ldflags-to-set-version-information-for-go-applications)
diff --git a/v1.5.7/internal/cloud/e2e/apply_auto_approve_test.go b/v1.5.7/internal/cloud/e2e/apply_auto_approve_test.go
new file mode 100644
index 0000000..a30899a
--- /dev/null
+++ b/v1.5.7/internal/cloud/e2e/apply_auto_approve_test.go
@@ -0,0 +1,181 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"context"
+	"testing"
+
+	tfe "github.com/hashicorp/go-tfe"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+func Test_terraform_apply_autoApprove(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+	skipWithoutRemoteTerraformVersion(t)
+
+	ctx := context.Background()
+
+	cases := testCases{
+		"workspace manual apply, terraform apply without auto-approve, expect prompt": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "app"
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String(wsName),
+							TerraformVersion: tfe.String(tfversion.String()),
+							AutoApply:        tfe.Bool(false),
+						})
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+						{
+							command:           []string{"apply"},
+							expectedCmdOutput: `Do you want to perform these actions in workspace "app"?`,
+							userInput:         []string{"yes"},
+							postInputOutput:   []string{`Apply complete!`},
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				workspace, err := tfeClient.Workspaces.ReadWithOptions(ctx, orgName, "app", &tfe.WorkspaceReadOptions{Include: []tfe.WSIncludeOpt{tfe.WSCurrentRun}})
+				if err != nil {
+					t.Fatal(err)
+				}
+				if workspace.CurrentRun == nil {
+					t.Fatal("Expected workspace to have run, but got nil")
+				}
+				if workspace.CurrentRun.Status != tfe.RunApplied {
+					t.Fatalf("Expected run status to be `applied`, but is %s", workspace.CurrentRun.Status)
+				}
+			},
+		},
+		"workspace auto apply, terraform apply without auto-approve, expect prompt": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "app"
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String(wsName),
+							TerraformVersion: tfe.String(tfversion.String()),
+							AutoApply:        tfe.Bool(true),
+						})
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+						{
+							command:           []string{"apply"},
+							expectedCmdOutput: `Do you want to perform these actions in workspace "app"?`,
+							userInput:         []string{"yes"},
+							postInputOutput:   []string{`Apply complete!`},
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				workspace, err := tfeClient.Workspaces.ReadWithOptions(ctx, orgName, "app", &tfe.WorkspaceReadOptions{Include: []tfe.WSIncludeOpt{tfe.WSCurrentRun}})
+				if err != nil {
+					t.Fatal(err)
+				}
+				if workspace.CurrentRun == nil {
+					t.Fatal("Expected workspace to have run, but got nil")
+				}
+				if workspace.CurrentRun.Status != tfe.RunApplied {
+					t.Fatalf("Expected run status to be `applied`, but is %s", workspace.CurrentRun.Status)
+				}
+			},
+		},
+		"workspace manual apply, terraform apply with auto-approve, no prompt": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "app"
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String(wsName),
+							TerraformVersion: tfe.String(tfversion.String()),
+							AutoApply:        tfe.Bool(false),
+						})
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+						{
+							command:           []string{"apply", "-auto-approve"},
+							expectedCmdOutput: `Apply complete!`,
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				workspace, err := tfeClient.Workspaces.ReadWithOptions(ctx, orgName, "app", &tfe.WorkspaceReadOptions{Include: []tfe.WSIncludeOpt{tfe.WSCurrentRun}})
+				if err != nil {
+					t.Fatal(err)
+				}
+				if workspace.CurrentRun == nil {
+					t.Fatal("Expected workspace to have run, but got nil")
+				}
+				if workspace.CurrentRun.Status != tfe.RunApplied {
+					t.Fatalf("Expected run status to be `applied`, but is %s", workspace.CurrentRun.Status)
+				}
+			},
+		},
+		"workspace auto apply, terraform apply with auto-approve, no prompt": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "app"
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String(wsName),
+							TerraformVersion: tfe.String(tfversion.String()),
+							AutoApply:        tfe.Bool(true),
+						})
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+						{
+							command:           []string{"apply", "-auto-approve"},
+							expectedCmdOutput: `Apply complete!`,
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				workspace, err := tfeClient.Workspaces.ReadWithOptions(ctx, orgName, "app", &tfe.WorkspaceReadOptions{Include: []tfe.WSIncludeOpt{tfe.WSCurrentRun}})
+				if err != nil {
+					t.Fatal(err)
+				}
+				if workspace.CurrentRun == nil {
+					t.Fatal("Expected workspace to have run, but got nil")
+				}
+				if workspace.CurrentRun.Status != tfe.RunApplied {
+					t.Fatalf("Expected run status to be `applied`, but is %s", workspace.CurrentRun.Status)
+				}
+			},
+		},
+	}
+
+	testRunner(t, cases, 1)
+}
diff --git a/v1.5.7/internal/cloud/e2e/apply_no_input_flag_test.go b/v1.5.7/internal/cloud/e2e/apply_no_input_flag_test.go
new file mode 100644
index 0000000..2311551
--- /dev/null
+++ b/v1.5.7/internal/cloud/e2e/apply_no_input_flag_test.go
@@ -0,0 +1,61 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"testing"
+)
+
+func Test_apply_no_input_flag(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+
+	cases := testCases{
+		"terraform apply with -input=false": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "new-workspace"
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init", "-input=false"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized`,
+						},
+						{
+							command:           []string{"apply", "-input=false"},
+							expectedCmdOutput: `Cannot confirm apply due to -input=false. Please handle run confirmation in the UI.`,
+							expectError:       true,
+						},
+					},
+				},
+			},
+		},
+		"terraform apply with auto approve and -input=false": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "cloud-workspace"
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init", "-input=false"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized`,
+						},
+						{
+							command:           []string{"apply", "-auto-approve", "-input=false"},
+							expectedCmdOutput: `Apply complete!`,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testRunner(t, cases, 1)
+}
diff --git a/v1.5.7/internal/cloud/e2e/backend_apply_before_init_test.go b/v1.5.7/internal/cloud/e2e/backend_apply_before_init_test.go
new file mode 100644
index 0000000..2c0bc28
--- /dev/null
+++ b/v1.5.7/internal/cloud/e2e/backend_apply_before_init_test.go
@@ -0,0 +1,71 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"testing"
+)
+
+func Test_backend_apply_before_init(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+	skipWithoutRemoteTerraformVersion(t)
+
+	cases := testCases{
+		"terraform apply with cloud block - blank state": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "new-workspace"
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"apply"},
+							expectedCmdOutput: `Terraform Cloud initialization required: please run "terraform init"`,
+							expectError:       true,
+						},
+					},
+				},
+			},
+		},
+		"terraform apply with cloud block - local state": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigLocalBackend()
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Successfully configured the backend "local"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "new-workspace"
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"apply"},
+							expectedCmdOutput: `Terraform Cloud initialization required: please run "terraform init"`,
+							expectError:       true,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testRunner(t, cases, 1)
+}
diff --git a/v1.5.7/internal/cloud/e2e/env_variables_test.go b/v1.5.7/internal/cloud/e2e/env_variables_test.go
new file mode 100644
index 0000000..d187edf
--- /dev/null
+++ b/v1.5.7/internal/cloud/e2e/env_variables_test.go
@@ -0,0 +1,267 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"context"
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/go-tfe"
+)
+
+func Test_cloud_organization_env_var(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+
+	ctx := context.Background()
+	org, cleanup := createOrganization(t)
+	t.Cleanup(cleanup)
+
+	cases := testCases{
+		"with TF_CLOUD_ORGANIZATION set": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						remoteWorkspace := "cloud-workspace"
+						tfBlock := terraformConfigCloudBackendOmitOrg(remoteWorkspace)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				expectedName := "cloud-workspace"
+				ws, err := tfeClient.Workspaces.Read(ctx, org.Name, expectedName)
+				if err != nil {
+					t.Fatal(err)
+				}
+				if ws == nil {
+					t.Fatalf("Expected workspace %s to be present, but is not.", expectedName)
+				}
+			},
+		},
+	}
+
+	testRunner(t, cases, 0, fmt.Sprintf("TF_CLOUD_ORGANIZATION=%s", org.Name))
+}
+
+func Test_cloud_workspace_name_env_var(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+
+	org, orgCleanup := createOrganization(t)
+	t.Cleanup(orgCleanup)
+
+	wk := createWorkspace(t, org.Name, tfe.WorkspaceCreateOptions{
+		Name: tfe.String("cloud-workspace"),
+	})
+
+	validCases := testCases{
+		"a workspace that exists": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigCloudBackendOmitWorkspaces(org.Name)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigCloudBackendOmitWorkspaces(org.Name)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: wk.Name,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	errCases := testCases{
+		"a workspace that doesn't exist": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigCloudBackendOmitWorkspaces(org.Name)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:     []string{"init"},
+							expectError: true,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testRunner(t, validCases, 0, fmt.Sprintf(`TF_WORKSPACE=%s`, wk.Name))
+	testRunner(t, errCases, 0, fmt.Sprintf(`TF_WORKSPACE=%s`, "the-fires-of-mt-doom"))
+}
+
+func Test_cloud_workspace_tags_env_var(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+
+	org, orgCleanup := createOrganization(t)
+	t.Cleanup(orgCleanup)
+
+	wkValid := createWorkspace(t, org.Name, tfe.WorkspaceCreateOptions{
+		Name: tfe.String("cloud-workspace"),
+		Tags: []*tfe.Tag{
+			{Name: "cloud"},
+		},
+	})
+
+	// this will be a workspace that won't have a tag listed in our test configuration
+	wkInvalid := createWorkspace(t, org.Name, tfe.WorkspaceCreateOptions{
+		Name: tfe.String("cloud-workspace-2"),
+	})
+
+	validCases := testCases{
+		"a workspace with valid tag": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigCloudBackendTags(org.Name, wkValid.TagNames[0])
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigCloudBackendTags(org.Name, wkValid.TagNames[0])
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: wkValid.Name,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	errCases := testCases{
+		"a workspace not specified by tags": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigCloudBackendTags(org.Name, wkValid.TagNames[0])
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:     []string{"init"},
+							expectError: true,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testRunner(t, validCases, 0, fmt.Sprintf(`TF_WORKSPACE=%s`, wkValid.Name))
+	testRunner(t, errCases, 0, fmt.Sprintf(`TF_WORKSPACE=%s`, wkInvalid.Name))
+}
+
+func Test_cloud_null_config(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+
+	org, cleanup := createOrganization(t)
+	t.Cleanup(cleanup)
+
+	wk := createWorkspace(t, org.Name, tfe.WorkspaceCreateOptions{
+		Name: tfe.String("cloud-workspace"),
+	})
+
+	cases := testCases{
+		"with all env vars set": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigCloudBackendOmitConfig()
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigCloudBackendOmitConfig()
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: wk.Name,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testRunner(t, cases, 1,
+		fmt.Sprintf(`TF_CLOUD_ORGANIZATION=%s`, org.Name),
+		fmt.Sprintf(`TF_CLOUD_HOSTNAME=%s`, tfeHostname),
+		fmt.Sprintf(`TF_WORKSPACE=%s`, wk.Name))
+}
diff --git a/v1.5.7/internal/cloud/e2e/helper_test.go b/v1.5.7/internal/cloud/e2e/helper_test.go
new file mode 100644
index 0000000..6582a4f
--- /dev/null
+++ b/v1.5.7/internal/cloud/e2e/helper_test.go
@@ -0,0 +1,304 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"context"
+	"fmt"
+	"os"
+	"testing"
+	"time"
+
+	expect "github.com/Netflix/go-expect"
+	tfe "github.com/hashicorp/go-tfe"
+	"github.com/hashicorp/go-uuid"
+	goversion "github.com/hashicorp/go-version"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+const (
+	// We need to give the console enough time to hear back.
+	// 1 minute was too short in some cases, so this gives it ample time.
+	expectConsoleTimeout = 3 * time.Minute
+)
+
+type tfCommand struct {
+	command           []string
+	expectedCmdOutput string
+	expectError       bool
+	userInput         []string
+	postInputOutput   []string
+}
+
+type operationSets struct {
+	commands []tfCommand
+	prep     func(t *testing.T, orgName, dir string)
+}
+
+type testCases map[string]struct {
+	operations  []operationSets
+	validations func(t *testing.T, orgName string)
+}
+
+func defaultOpts() []expect.ConsoleOpt {
+	opts := []expect.ConsoleOpt{
+		expect.WithDefaultTimeout(expectConsoleTimeout),
+	}
+	if verboseMode {
+		opts = append(opts, expect.WithStdout(os.Stdout))
+	}
+	return opts
+}
+
+func createOrganization(t *testing.T) (*tfe.Organization, func()) {
+	ctx := context.Background()
+	org, err := tfeClient.Organizations.Create(ctx, tfe.OrganizationCreateOptions{
+		Name:                  tfe.String("tst-" + randomString(t)),
+		Email:                 tfe.String(fmt.Sprintf("%s@tfe.local", randomString(t))),
+		CostEstimationEnabled: tfe.Bool(false),
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = tfeClient.Admin.Organizations.Update(ctx, org.Name, tfe.AdminOrganizationUpdateOptions{
+		AccessBetaTools: tfe.Bool(true),
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	return org, func() {
+		if err := tfeClient.Organizations.Delete(ctx, org.Name); err != nil {
+			t.Errorf("Error destroying organization! WARNING: Dangling resources\n"+
+				"may exist! The full error is shown below.\n\n"+
+				"Organization: %s\nError: %s", org.Name, err)
+		}
+	}
+}
+
+func createWorkspace(t *testing.T, orgName string, wOpts tfe.WorkspaceCreateOptions) *tfe.Workspace {
+	ctx := context.Background()
+	w, err := tfeClient.Workspaces.Create(ctx, orgName, wOpts)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	return w
+}
+
+func getWorkspace(workspaces []*tfe.Workspace, workspace string) (*tfe.Workspace, bool) {
+	for _, ws := range workspaces {
+		if ws.Name == workspace {
+			return ws, false
+		}
+	}
+	return nil, true
+}
+
+func randomString(t *testing.T) string {
+	v, err := uuid.GenerateUUID()
+	if err != nil {
+		t.Fatal(err)
+	}
+	return v
+}
+
+func terraformConfigLocalBackend() string {
+	return `
+terraform {
+  backend "local" {
+  }
+}
+
+output "val" {
+  value = "${terraform.workspace}"
+}
+`
+}
+
+func terraformConfigRemoteBackendName(org, name string) string {
+	return fmt.Sprintf(`
+terraform {
+  backend "remote" {
+    hostname = "%s"
+    organization = "%s"
+
+    workspaces {
+      name = "%s"
+    }
+  }
+}
+
+output "val" {
+  value = "${terraform.workspace}"
+}
+`, tfeHostname, org, name)
+}
+
+func terraformConfigRemoteBackendPrefix(org, prefix string) string {
+	return fmt.Sprintf(`
+terraform {
+  backend "remote" {
+    hostname = "%s"
+    organization = "%s"
+
+    workspaces {
+      prefix = "%s"
+    }
+  }
+}
+
+output "val" {
+  value = "${terraform.workspace}"
+}
+`, tfeHostname, org, prefix)
+}
+
+func terraformConfigCloudBackendTags(org, tag string) string {
+	return fmt.Sprintf(`
+terraform {
+  cloud {
+    hostname = "%s"
+    organization = "%s"
+
+    workspaces {
+      tags = ["%s"]
+    }
+  }
+}
+
+output "tag_val" {
+  value = "%s"
+}
+`, tfeHostname, org, tag, tag)
+}
+
+func terraformConfigCloudBackendName(org, name string) string {
+	return fmt.Sprintf(`
+terraform {
+  cloud {
+    hostname = "%s"
+    organization = "%s"
+
+    workspaces {
+      name = "%s"
+    }
+  }
+}
+
+output "val" {
+  value = "${terraform.workspace}"
+}
+`, tfeHostname, org, name)
+}
+
+func terraformConfigCloudBackendOmitOrg(workspaceName string) string {
+	return fmt.Sprintf(`
+terraform {
+  cloud {
+    hostname = "%s"
+
+	workspaces {
+	  name = "%s"
+	}
+  }
+}
+
+output "val" {
+  value = "${terraform.workspace}"
+}
+`, tfeHostname, workspaceName)
+}
+
+func terraformConfigCloudBackendOmitWorkspaces(orgName string) string {
+	return fmt.Sprintf(`
+terraform {
+  cloud {
+    hostname = "%s"
+	organization = "%s"
+  }
+}
+
+output "val" {
+  value = "${terraform.workspace}"
+}
+`, tfeHostname, orgName)
+}
+
+func terraformConfigCloudBackendOmitConfig() string {
+	return `
+terraform {
+  cloud {}
+}
+
+output "val" {
+  value = "${terraform.workspace}"
+}
+`
+}
+
+func writeMainTF(t *testing.T, block string, dir string) {
+	f, err := os.Create(fmt.Sprintf("%s/main.tf", dir))
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = f.WriteString(block)
+	if err != nil {
+		t.Fatal(err)
+	}
+	f.Close()
+}
+
+// The e2e tests rely on the fact that the terraform version in TFC/E is able to
+// run the `cloud` configuration block, which is available in 1.1 and will
+// continue to be available in later versions. So this function checks that
+// there is a version that is >= 1.1.
+func skipWithoutRemoteTerraformVersion(t *testing.T) {
+	version := tfversion.Version
+	baseVersion, err := goversion.NewVersion(version)
+	if err != nil {
+		t.Fatalf(fmt.Sprintf("Error instantiating go-version for %s", version))
+	}
+	opts := &tfe.AdminTerraformVersionsListOptions{
+		ListOptions: tfe.ListOptions{
+			PageNumber: 1,
+			PageSize:   100,
+		},
+	}
+	hasVersion := false
+
+findTfVersion:
+	for {
+		// TODO: update go-tfe Read() to retrieve a terraform version by name.
+		// Currently you can only retrieve by ID.
+		tfVersionList, err := tfeClient.Admin.TerraformVersions.List(context.Background(), opts)
+		if err != nil {
+			t.Fatalf("Could not retrieve list of terraform versions: %v", err)
+		}
+		for _, item := range tfVersionList.Items {
+			availableVersion, err := goversion.NewVersion(item.Version)
+			if err != nil {
+				t.Logf("Error instantiating go-version for %s", item.Version)
+				continue
+			}
+			if availableVersion.Core().GreaterThanOrEqual(baseVersion.Core()) {
+				hasVersion = true
+				break findTfVersion
+			}
+		}
+
+		// Exit the loop when we've seen all pages.
+		if tfVersionList.CurrentPage >= tfVersionList.TotalPages {
+			break
+		}
+
+		// Update the page number to get the next page.
+		opts.PageNumber = tfVersionList.NextPage
+	}
+
+	if !hasVersion {
+		t.Skipf("Skipping test because TFC/E does not have current Terraform version to test with (%s)", version)
+	}
+}
diff --git a/v1.5.7/internal/cloud/e2e/init_with_empty_tags_test.go b/v1.5.7/internal/cloud/e2e/init_with_empty_tags_test.go
new file mode 100644
index 0000000..5b1099d
--- /dev/null
+++ b/v1.5.7/internal/cloud/e2e/init_with_empty_tags_test.go
@@ -0,0 +1,38 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"testing"
+)
+
+func Test_init_with_empty_tags(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+	skipWithoutRemoteTerraformVersion(t)
+
+	cases := testCases{
+		"terraform init with cloud block - no tagged workspaces exist yet": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsTag := "emptytag"
+						tfBlock := terraformConfigCloudBackendTags(orgName, wsTag)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `There are no workspaces with the configured tags`,
+							userInput:         []string{"emptytag-prod"},
+							postInputOutput:   []string{`Terraform Cloud has been successfully initialized!`},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testRunner(t, cases, 1)
+}
diff --git a/v1.5.7/internal/cloud/e2e/main_test.go b/v1.5.7/internal/cloud/e2e/main_test.go
new file mode 100644
index 0000000..548c9f0
--- /dev/null
+++ b/v1.5.7/internal/cloud/e2e/main_test.go
@@ -0,0 +1,252 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"strings"
+	"testing"
+
+	expect "github.com/Netflix/go-expect"
+	tfe "github.com/hashicorp/go-tfe"
+	"github.com/hashicorp/terraform/internal/e2e"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+var terraformBin string
+var cliConfigFileEnv string
+
+var tfeClient *tfe.Client
+var tfeHostname string
+var tfeToken string
+var verboseMode bool
+
+func TestMain(m *testing.M) {
+	teardown := setup()
+	code := m.Run()
+	teardown()
+
+	os.Exit(code)
+}
+
+func accTest() bool {
+	// TF_ACC is set when we want to run acceptance tests, meaning it relies on
+	// network access.
+	return os.Getenv("TF_ACC") != ""
+}
+
+func hasHostname() bool {
+	return os.Getenv("TFE_HOSTNAME") != ""
+}
+
+func hasToken() bool {
+	return os.Getenv("TFE_TOKEN") != ""
+}
+
+func hasRequiredEnvVars() bool {
+	return accTest() && hasHostname() && hasToken()
+}
+
+func skipIfMissingEnvVar(t *testing.T) {
+	if !hasRequiredEnvVars() {
+		t.Skip("Skipping test, required environment variables missing. Use `TF_ACC`, `TFE_HOSTNAME`, `TFE_TOKEN`")
+	}
+}
+
+func setup() func() {
+	tfOutput := flag.Bool("tfoutput", false, "This flag produces the terraform output from tests.")
+	flag.Parse()
+	verboseMode = *tfOutput
+
+	setTfeClient()
+	teardown := setupBinary()
+
+	return func() {
+		teardown()
+	}
+}
+func testRunner(t *testing.T, cases testCases, orgCount int, tfEnvFlags ...string) {
+	for name, tc := range cases {
+		tc := tc // rebind tc into this lexical scope
+		t.Run(name, func(subtest *testing.T) {
+			subtest.Parallel()
+
+			orgNames := []string{}
+			for i := 0; i < orgCount; i++ {
+				organization, cleanup := createOrganization(t)
+				t.Cleanup(cleanup)
+				orgNames = append(orgNames, organization.Name)
+			}
+
+			exp, err := expect.NewConsole(defaultOpts()...)
+			if err != nil {
+				subtest.Fatal(err)
+			}
+			defer exp.Close()
+
+			tmpDir := t.TempDir()
+
+			tf := e2e.NewBinary(t, terraformBin, tmpDir)
+			tfEnvFlags = append(tfEnvFlags, "TF_LOG=INFO")
+			tfEnvFlags = append(tfEnvFlags, cliConfigFileEnv)
+			for _, env := range tfEnvFlags {
+				tf.AddEnv(env)
+			}
+
+			var orgName string
+			for index, op := range tc.operations {
+				switch orgCount {
+				case 0:
+					orgName = ""
+				case 1:
+					orgName = orgNames[0]
+				default:
+					orgName = orgNames[index]
+				}
+
+				op.prep(t, orgName, tf.WorkDir())
+				for _, tfCmd := range op.commands {
+					cmd := tf.Cmd(tfCmd.command...)
+					cmd.Stdin = exp.Tty()
+					cmd.Stdout = exp.Tty()
+					cmd.Stderr = exp.Tty()
+
+					err = cmd.Start()
+					if err != nil {
+						subtest.Fatal(err)
+					}
+
+					if tfCmd.expectedCmdOutput != "" {
+						got, err := exp.ExpectString(tfCmd.expectedCmdOutput)
+						if err != nil {
+							subtest.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got)
+						}
+					}
+
+					lenInput := len(tfCmd.userInput)
+					lenInputOutput := len(tfCmd.postInputOutput)
+					if lenInput > 0 {
+						for i := 0; i < lenInput; i++ {
+							input := tfCmd.userInput[i]
+							exp.SendLine(input)
+							// use the index to find the corresponding
+							// output that matches the input.
+							if lenInputOutput-1 >= i {
+								output := tfCmd.postInputOutput[i]
+								_, err := exp.ExpectString(output)
+								if err != nil {
+									subtest.Fatal(err)
+								}
+							}
+						}
+					}
+
+					err = cmd.Wait()
+					if err != nil && !tfCmd.expectError {
+						subtest.Fatal(err)
+					}
+				}
+			}
+
+			if tc.validations != nil {
+				tc.validations(t, orgName)
+			}
+		})
+	}
+}
+
+func setTfeClient() {
+	tfeHostname = os.Getenv("TFE_HOSTNAME")
+	tfeToken = os.Getenv("TFE_TOKEN")
+
+	cfg := &tfe.Config{
+		Address: fmt.Sprintf("https://%s", tfeHostname),
+		Token:   tfeToken,
+	}
+
+	if tfeHostname != "" && tfeToken != "" {
+		// Create a new TFE client.
+		client, err := tfe.NewClient(cfg)
+		if err != nil {
+			fmt.Printf("Could not create new tfe client: %v\n", err)
+			os.Exit(1)
+		}
+		tfeClient = client
+	}
+}
+
+func setupBinary() func() {
+	log.Println("Setting up terraform binary")
+	tmpTerraformBinaryDir, err := ioutil.TempDir("", "terraform-test")
+	if err != nil {
+		fmt.Printf("Could not create temp directory: %v\n", err)
+		os.Exit(1)
+	}
+	log.Println(tmpTerraformBinaryDir)
+	currentDir, err := os.Getwd()
+	defer os.Chdir(currentDir)
+	if err != nil {
+		fmt.Printf("Could not change directories: %v\n", err)
+		os.Exit(1)
+	}
+	// Getting top level dir
+	dirPaths := strings.Split(currentDir, "/")
+	log.Println(currentDir)
+	topLevel := len(dirPaths) - 3
+	topDir := strings.Join(dirPaths[0:topLevel], "/")
+
+	if err := os.Chdir(topDir); err != nil {
+		fmt.Printf("Could not change directories: %v\n", err)
+		os.Exit(1)
+	}
+
+	cmd := exec.Command(
+		"go",
+		"build",
+		"-o", tmpTerraformBinaryDir,
+		"-ldflags", fmt.Sprintf("-X \"github.com/hashicorp/terraform/version.Prerelease=%s\"", tfversion.Prerelease),
+	)
+	err = cmd.Run()
+	if err != nil {
+		fmt.Printf("Could not run exec command: %v\n", err)
+		os.Exit(1)
+	}
+
+	credFile := fmt.Sprintf("%s/dev.tfrc", tmpTerraformBinaryDir)
+	writeCredRC(credFile)
+
+	terraformBin = fmt.Sprintf("%s/terraform", tmpTerraformBinaryDir)
+	cliConfigFileEnv = fmt.Sprintf("TF_CLI_CONFIG_FILE=%s", credFile)
+
+	return func() {
+		os.RemoveAll(tmpTerraformBinaryDir)
+	}
+}
+
+func writeCredRC(file string) {
+	creds := credentialBlock()
+	f, err := os.Create(file)
+	if err != nil {
+		fmt.Printf("Could not create file: %v\n", err)
+		os.Exit(1)
+	}
+	_, err = f.WriteString(creds)
+	if err != nil {
+		fmt.Printf("Could not write credentials: %v\n", err)
+		os.Exit(1)
+	}
+	f.Close()
+}
+
+func credentialBlock() string {
+	return fmt.Sprintf(`
+credentials "%s" {
+  token = "%s"
+}`, tfeHostname, tfeToken)
+}
diff --git a/v1.5.7/internal/cloud/e2e/migrate_state_multi_to_tfc_test.go b/v1.5.7/internal/cloud/e2e/migrate_state_multi_to_tfc_test.go
new file mode 100644
index 0000000..eee1a13
--- /dev/null
+++ b/v1.5.7/internal/cloud/e2e/migrate_state_multi_to_tfc_test.go
@@ -0,0 +1,443 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"context"
+	"testing"
+
+	tfe "github.com/hashicorp/go-tfe"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+func Test_migrate_multi_to_tfc_cloud_name_strategy(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+	skipWithoutRemoteTerraformVersion(t)
+
+	ctx := context.Background()
+
+	cases := testCases{
+		"migrating multiple workspaces to cloud using name strategy; current workspace is 'default'": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigLocalBackend()
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Successfully configured the backend "local"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+						{
+							command:           []string{"workspace", "new", "prod"},
+							expectedCmdOutput: `Created and switched to workspace "prod"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+						{
+							command:           []string{"workspace", "select", "default"},
+							expectedCmdOutput: `Switched to workspace "default".`,
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "new-workspace"
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Do you want to copy only your current workspace?`,
+							userInput:         []string{"yes"},
+							postInputOutput:   []string{`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: `new-workspace`, // this comes from the `prep` function
+						},
+						{
+							command:           []string{"output"},
+							expectedCmdOutput: `val = "default"`, // this was the output of the current workspace selected before migration
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				wsList, err := tfeClient.Workspaces.List(ctx, orgName, nil)
+				if err != nil {
+					t.Fatal(err)
+				}
+				if len(wsList.Items) != 1 {
+					t.Fatalf("Expected the number of workspaces to be 1, but got %d", len(wsList.Items))
+				}
+				ws := wsList.Items[0]
+				// this workspace name is what exists in the cloud backend configuration block
+				if ws.Name != "new-workspace" {
+					t.Fatalf("Expected workspace to be `new-workspace`, but is %s", ws.Name)
+				}
+			},
+		},
+		"migrating multiple workspaces to cloud using name strategy; current workspace is 'prod'": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigLocalBackend()
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Successfully configured the backend "local"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+						{
+							command:           []string{"workspace", "new", "prod"},
+							expectedCmdOutput: `Created and switched to workspace "prod"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "new-workspace"
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Do you want to copy only your current workspace?`,
+							userInput:         []string{"yes"},
+							postInputOutput:   []string{`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"workspace", "list"},
+							expectedCmdOutput: `new-workspace`, // this comes from the `prep` function
+						},
+						{
+							command:           []string{"output"},
+							expectedCmdOutput: `val = "prod"`,
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				wsList, err := tfeClient.Workspaces.List(ctx, orgName, nil)
+				if err != nil {
+					t.Fatal(err)
+				}
+				ws := wsList.Items[0]
+				// this workspace name is what exists in the cloud backend configuration block
+				if ws.Name != "new-workspace" {
+					t.Fatalf("Expected workspace to be `new-workspace`, but is %s", ws.Name)
+				}
+			},
+		},
+		"migrating multiple workspaces to cloud using name strategy; 'default' workspace is empty": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigLocalBackend()
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Successfully configured the backend "local"!`,
+						},
+						{
+							command:           []string{"workspace", "new", "workspace1"},
+							expectedCmdOutput: `Created and switched to workspace "workspace1"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+						{
+							command:           []string{"workspace", "new", "workspace2"},
+							expectedCmdOutput: `Created and switched to workspace "workspace2"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "new-workspace"
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Do you want to copy only your current workspace?`,
+							userInput:         []string{"yes"},
+							postInputOutput:   []string{`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:     []string{"workspace", "select", "default"},
+							expectError: true,
+						},
+						{
+							command:           []string{"output"},
+							expectedCmdOutput: `val = "workspace2"`, // this was the output of the current workspace selected before migration
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				wsList, err := tfeClient.Workspaces.List(ctx, orgName, nil)
+				if err != nil {
+					t.Fatal(err)
+				}
+				if len(wsList.Items) != 1 {
+					t.Fatalf("Expected the number of workspaces to be 1, but got %d", len(wsList.Items))
+				}
+				ws := wsList.Items[0]
+				// this workspace name is what exists in the cloud backend configuration block
+				if ws.Name != "new-workspace" {
+					t.Fatalf("Expected workspace to be `new-workspace`, but is %s", ws.Name)
+				}
+			},
+		},
+	}
+
+	testRunner(t, cases, 1)
+}
+
+func Test_migrate_multi_to_tfc_cloud_tags_strategy(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+	skipWithoutRemoteTerraformVersion(t)
+
+	ctx := context.Background()
+
+	cases := map[string]struct {
+		operations  []operationSets
+		validations func(t *testing.T, orgName string)
+	}{
+		"migrating multiple workspaces to cloud using tags strategy; pattern is using prefix `app-*`": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigLocalBackend()
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Successfully configured the backend "local"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+						{
+							command:           []string{"workspace", "new", "prod"},
+							expectedCmdOutput: `Created and switched to workspace "prod"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+						{
+							command:           []string{"workspace", "select", "default"},
+							expectedCmdOutput: `Switched to workspace "default".`,
+						},
+						{
+							command:           []string{"output"},
+							expectedCmdOutput: `val = "default"`,
+						},
+						{
+							command:           []string{"workspace", "select", "prod"},
+							expectedCmdOutput: `Switched to workspace "prod".`,
+						},
+						{
+							command:           []string{"output"},
+							expectedCmdOutput: `val = "prod"`,
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tag := "app"
+						tfBlock := terraformConfigCloudBackendTags(orgName, tag)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud requires all workspaces to be given an explicit name.`,
+							userInput:         []string{"dev", "1", "app-*"},
+							postInputOutput: []string{
+								`Would you like to rename your workspaces?`,
+								"How would you like to rename your workspaces?",
+								"Terraform Cloud has been successfully initialized!"},
+						},
+						{
+							command:           []string{"workspace", "select", "app-dev"},
+							expectedCmdOutput: `Switched to workspace "app-dev".`,
+						},
+						{
+							command:           []string{"output"},
+							expectedCmdOutput: `val = "default"`,
+						},
+						{
+							command:           []string{"workspace", "select", "app-prod"},
+							expectedCmdOutput: `Switched to workspace "app-prod".`,
+						},
+						{
+							command:           []string{"output"},
+							expectedCmdOutput: `val = "prod"`,
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				wsList, err := tfeClient.Workspaces.List(ctx, orgName, &tfe.WorkspaceListOptions{
+					Tags: "app",
+				})
+				if err != nil {
+					t.Fatal(err)
+				}
+				if len(wsList.Items) != 2 {
+					t.Fatalf("Expected the number of workspaecs to be 2, but got %d", len(wsList.Items))
+				}
+				expectedWorkspaceNames := []string{"app-prod", "app-dev"}
+				for _, ws := range wsList.Items {
+					hasName := false
+					for _, expectedNames := range expectedWorkspaceNames {
+						if expectedNames == ws.Name {
+							hasName = true
+						}
+					}
+					if !hasName {
+						t.Fatalf("Worksapce %s is not in the expected list of workspaces", ws.Name)
+					}
+				}
+			},
+		},
+		"migrating multiple workspaces to cloud using tags strategy; existing workspaces": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigLocalBackend()
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Successfully configured the backend "local"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+						{
+							command:           []string{"workspace", "new", "identity"},
+							expectedCmdOutput: `Created and switched to workspace "identity"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+						{
+							command:           []string{"workspace", "new", "billing"},
+							expectedCmdOutput: `Created and switched to workspace "billing"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+						{
+							command:           []string{"workspace", "select", "default"},
+							expectedCmdOutput: `Switched to workspace "default".`,
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tag := "app"
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String("identity"),
+							TerraformVersion: tfe.String(tfversion.String()),
+						})
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String("billing"),
+							TerraformVersion: tfe.String(tfversion.String()),
+						})
+						tfBlock := terraformConfigCloudBackendTags(orgName, tag)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud requires all workspaces to be given an explicit name.`,
+							userInput:         []string{"dev", "1", "app-*"},
+							postInputOutput: []string{
+								`Would you like to rename your workspaces?`,
+								"How would you like to rename your workspaces?",
+								"Terraform Cloud has been successfully initialized!"},
+						},
+						{
+							command:           []string{"workspace", "select", "app-billing"},
+							expectedCmdOutput: `Switched to workspace "app-billing".`,
+						},
+						{
+							command:           []string{"workspace", "select", "app-identity"},
+							expectedCmdOutput: `Switched to workspace "app-identity".`,
+						},
+						{
+							command:           []string{"workspace", "select", "app-dev"},
+							expectedCmdOutput: `Switched to workspace "app-dev".`,
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				wsList, err := tfeClient.Workspaces.List(ctx, orgName, &tfe.WorkspaceListOptions{
+					Tags: "app",
+				})
+				if err != nil {
+					t.Fatal(err)
+				}
+				if len(wsList.Items) != 3 {
+					t.Fatalf("Expected the number of workspaecs to be 3, but got %d", len(wsList.Items))
+				}
+				expectedWorkspaceNames := []string{"app-billing", "app-dev", "app-identity"}
+				for _, ws := range wsList.Items {
+					hasName := false
+					for _, expectedNames := range expectedWorkspaceNames {
+						if expectedNames == ws.Name {
+							hasName = true
+						}
+					}
+					if !hasName {
+						t.Fatalf("Worksapce %s is not in the expected list of workspaces", ws.Name)
+					}
+				}
+			},
+		},
+	}
+
+	testRunner(t, cases, 1)
+}
diff --git a/v1.5.7/internal/cloud/e2e/migrate_state_remote_backend_to_tfc_test.go b/v1.5.7/internal/cloud/e2e/migrate_state_remote_backend_to_tfc_test.go
new file mode 100644
index 0000000..2fbb903
--- /dev/null
+++ b/v1.5.7/internal/cloud/e2e/migrate_state_remote_backend_to_tfc_test.go
@@ -0,0 +1,526 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"context"
+	"testing"
+
+	tfe "github.com/hashicorp/go-tfe"
+)
+
+func Test_migrate_remote_backend_single_org(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+	skipWithoutRemoteTerraformVersion(t)
+
+	ctx := context.Background()
+	cases := testCases{
+		"migrate remote backend name to tfc name": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						remoteWorkspace := "remote-workspace"
+						tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Successfully configured the backend "remote"!`,
+						},
+						{
+							command:           []string{"apply", "-auto-approve"},
+							expectedCmdOutput: `Apply complete!`,
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "cloud-workspace"
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init", "-ignore-remote-version"},
+							expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`,
+							userInput:         []string{"yes", "yes"},
+							postInputOutput: []string{
+								`Should Terraform migrate your existing state?`,
+								`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: `cloud-workspace`,
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				expectedName := "cloud-workspace"
+				ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName)
+				if err != nil {
+					t.Fatal(err)
+				}
+				if ws == nil {
+					t.Fatalf("Expected workspace %s to be present, but is not.", expectedName)
+				}
+			},
+		},
+		"migrate remote backend name to tfc same name": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						remoteWorkspace := "remote-workspace"
+						tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Successfully configured the backend "remote"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "remote-workspace"
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init", "-ignore-remote-version"},
+							expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`,
+							userInput:         []string{"yes", "yes"},
+							postInputOutput: []string{
+								`Should Terraform migrate your existing state?`,
+								`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: `remote-workspace`,
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				expectedName := "remote-workspace"
+				ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName)
+				if err != nil {
+					t.Fatal(err)
+				}
+				if ws == nil {
+					t.Fatalf("Expected workspace %s to be present, but is not.", expectedName)
+				}
+			},
+		},
+		"migrate remote backend name to tfc tags": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						remoteWorkspace := "remote-workspace"
+						tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Successfully configured the backend "remote"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: `default`,
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tag := "app"
+						tfBlock := terraformConfigCloudBackendTags(orgName, tag)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init", "-ignore-remote-version"},
+							expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`,
+							userInput:         []string{"yes", "cloud-workspace", "yes"},
+							postInputOutput: []string{
+								`Should Terraform migrate your existing state?`,
+								`Terraform Cloud requires all workspaces to be given an explicit name.`,
+								`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: `cloud-workspace`,
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				wsList, err := tfeClient.Workspaces.List(ctx, orgName, &tfe.WorkspaceListOptions{
+					Tags: "app",
+				})
+				if err != nil {
+					t.Fatal(err)
+				}
+				if len(wsList.Items) != 1 {
+					t.Fatalf("Expected number of workspaces to be 1, but got %d", len(wsList.Items))
+				}
+				ws := wsList.Items[0]
+				if ws.Name != "cloud-workspace" {
+					t.Fatalf("Expected workspace to be `cloud-workspace`, but is %s", ws.Name)
+				}
+			},
+		},
+		"migrate remote backend prefix to tfc name strategy single workspace": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")})
+						prefix := "app-"
+						tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform has been successfully initialized!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "cloud-workspace"
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init", "-ignore-remote-version"},
+							expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`,
+							userInput:         []string{"yes", "yes"},
+							postInputOutput: []string{
+								`Should Terraform migrate your existing state?`,
+								`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: `cloud-workspace`,
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				expectedName := "cloud-workspace"
+				ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName)
+				if err != nil {
+					t.Fatal(err)
+				}
+				if ws == nil {
+					t.Fatalf("Expected workspace %s to be present, but is not.", expectedName)
+				}
+			},
+		},
+		"migrate remote backend prefix to tfc name strategy multi workspace": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")})
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-two")})
+						prefix := "app-"
+						tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `The currently selected workspace (default) does not exist.`,
+							userInput:         []string{"1"},
+							postInputOutput:   []string{`Terraform has been successfully initialized!`},
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+						{
+							command:           []string{"workspace", "list"},
+							expectedCmdOutput: "* one", // app name retrieved via prefix
+						},
+						{
+							command:           []string{"workspace", "select", "two"},
+							expectedCmdOutput: `Switched to workspace "two".`, // app name retrieved via prefix
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "cloud-workspace"
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init", "-ignore-remote-version"},
+							expectedCmdOutput: `Do you want to copy only your current workspace?`,
+							userInput:         []string{"yes"},
+							postInputOutput: []string{
+								`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: `cloud-workspace`,
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				expectedName := "cloud-workspace"
+				ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName)
+				if err != nil {
+					t.Fatal(err)
+				}
+				if ws == nil {
+					t.Fatalf("Expected workspace %s to be present, but is not.", expectedName)
+				}
+				wsList, err := tfeClient.Workspaces.List(ctx, orgName, nil)
+				if err != nil {
+					t.Fatal(err)
+				}
+				if len(wsList.Items) != 3 {
+					t.Fatalf("expected number of workspaces in this org to be 3, but got %d", len(wsList.Items))
+				}
+				_, empty := getWorkspace(wsList.Items, "cloud-workspace")
+				if empty {
+					t.Fatalf("expected workspaces to include 'cloud-workspace' but didn't.")
+				}
+				_, empty = getWorkspace(wsList.Items, "app-one")
+				if empty {
+					t.Fatalf("expected workspaces to include 'app-one' but didn't.")
+				}
+				_, empty = getWorkspace(wsList.Items, "app-two")
+				if empty {
+					t.Fatalf("expected workspaces to include 'app-two' but didn't.")
+				}
+			},
+		},
+		"migrate remote backend prefix to tfc tags strategy single workspace": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")})
+						prefix := "app-"
+						tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform has been successfully initialized!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tag := "app"
+						tfBlock := terraformConfigCloudBackendTags(orgName, tag)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init", "-ignore-remote-version"},
+							expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`,
+							userInput:         []string{"yes", "cloud-workspace", "yes"},
+							postInputOutput: []string{
+								`Should Terraform migrate your existing state?`,
+								`Terraform Cloud requires all workspaces to be given an explicit name.`,
+								`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"workspace", "list"},
+							expectedCmdOutput: `cloud-workspace`,
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				expectedName := "cloud-workspace"
+				ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName)
+				if err != nil {
+					t.Fatal(err)
+				}
+				if ws == nil {
+					t.Fatalf("Expected workspace %s to be present, but is not.", expectedName)
+				}
+			},
+		},
+		"migrate remote backend prefix to tfc tags strategy multi workspace": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")})
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-two")})
+						prefix := "app-"
+						tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `The currently selected workspace (default) does not exist.`,
+							userInput:         []string{"1"},
+							postInputOutput:   []string{`Terraform has been successfully initialized!`},
+						},
+						{
+							command:           []string{"apply"},
+							expectedCmdOutput: `Do you want to perform these actions in workspace "app-one"?`,
+							userInput:         []string{"yes"},
+							postInputOutput:   []string{`Apply complete!`},
+						},
+						{
+							command: []string{"workspace", "select", "two"},
+						},
+						{
+							command:           []string{"apply"},
+							expectedCmdOutput: `Do you want to perform these actions in workspace "app-two"?`,
+							userInput:         []string{"yes"},
+							postInputOutput:   []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tag := "app"
+						tfBlock := terraformConfigCloudBackendTags(orgName, tag)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init", "-ignore-remote-version"},
+							expectedCmdOutput: `Do you wish to proceed?`,
+							userInput:         []string{"yes"},
+							postInputOutput:   []string{`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: "app-two",
+						},
+						{
+							command:           []string{"workspace", "select", "app-one"},
+							expectedCmdOutput: `Switched to workspace "app-one".`,
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				wsList, err := tfeClient.Workspaces.List(ctx, orgName, &tfe.WorkspaceListOptions{
+					Tags: "app",
+				})
+				if err != nil {
+					t.Fatal(err)
+				}
+				if len(wsList.Items) != 2 {
+					t.Logf("Expected the number of workspaces to be 2, but got %d", len(wsList.Items))
+				}
+				ws, empty := getWorkspace(wsList.Items, "app-one")
+				if empty {
+					t.Fatalf("expected workspaces to include 'app-one' but didn't.")
+				}
+				if len(ws.TagNames) == 0 {
+					t.Fatalf("expected workspaces 'one' to have tags.")
+				}
+				ws, empty = getWorkspace(wsList.Items, "app-two")
+				if empty {
+					t.Fatalf("expected workspaces to include 'app-two' but didn't.")
+				}
+				if len(ws.TagNames) == 0 {
+					t.Fatalf("expected workspaces 'app-two' to have tags.")
+				}
+			},
+		},
+	}
+
+	testRunner(t, cases, 1)
+}
+
+func Test_migrate_remote_backend_multi_org(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+	skipWithoutRemoteTerraformVersion(t)
+
+	ctx := context.Background()
+	cases := testCases{
+		"migrate remote backend name to tfc name": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						remoteWorkspace := "remote-workspace"
+						tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Successfully configured the backend "remote"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "remote-workspace"
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init", "-ignore-remote-version"},
+							expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`,
+							userInput:         []string{"yes", "yes"},
+							postInputOutput: []string{
+								`Should Terraform migrate your existing state?`,
+								`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: `remote-workspace`,
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				expectedName := "remote-workspace"
+				ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName)
+				if err != nil {
+					t.Fatal(err)
+				}
+				if ws == nil {
+					t.Fatalf("Expected workspace %s to be present, but is not.", expectedName)
+				}
+			},
+		},
+	}
+
+	testRunner(t, cases, 2)
+}
diff --git a/v1.5.7/internal/cloud/e2e/migrate_state_single_to_tfc_test.go b/v1.5.7/internal/cloud/e2e/migrate_state_single_to_tfc_test.go
new file mode 100644
index 0000000..b16069a
--- /dev/null
+++ b/v1.5.7/internal/cloud/e2e/migrate_state_single_to_tfc_test.go
@@ -0,0 +1,129 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"context"
+	"testing"
+
+	tfe "github.com/hashicorp/go-tfe"
+)
+
+func Test_migrate_single_to_tfc(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+	skipWithoutRemoteTerraformVersion(t)
+
+	ctx := context.Background()
+
+	cases := testCases{
+		"migrate using cloud workspace name strategy": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigLocalBackend()
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Successfully configured the backend "local"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "new-workspace"
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Migrating from backend "local" to Terraform Cloud.`,
+							userInput:         []string{"yes", "yes"},
+							postInputOutput: []string{
+								`Should Terraform migrate your existing state?`,
+								`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"workspace", "list"},
+							expectedCmdOutput: `new-workspace`,
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				wsList, err := tfeClient.Workspaces.List(ctx, orgName, nil)
+				if err != nil {
+					t.Fatal(err)
+				}
+				ws := wsList.Items[0]
+				if ws.Name != "new-workspace" {
+					t.Fatalf("Expected workspace to be `new-workspace`, but is %s", ws.Name)
+				}
+			},
+		},
+		"migrate using cloud workspace tags strategy": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigLocalBackend()
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Successfully configured the backend "local"!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tag := "app"
+						tfBlock := terraformConfigCloudBackendTags(orgName, tag)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Migrating from backend "local" to Terraform Cloud.`,
+							userInput:         []string{"yes", "new-workspace", "yes"},
+							postInputOutput: []string{
+								`Should Terraform migrate your existing state?`,
+								`Terraform Cloud requires all workspaces to be given an explicit name.`,
+								`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"workspace", "list"},
+							expectedCmdOutput: `new-workspace`,
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				wsList, err := tfeClient.Workspaces.List(ctx, orgName, &tfe.WorkspaceListOptions{
+					Tags: "app",
+				})
+				if err != nil {
+					t.Fatal(err)
+				}
+				ws := wsList.Items[0]
+				if ws.Name != "new-workspace" {
+					t.Fatalf("Expected workspace to be `new-workspace`, but is %s", ws.Name)
+				}
+			},
+		},
+	}
+
+	testRunner(t, cases, 1)
+}
diff --git a/v1.5.7/internal/cloud/e2e/migrate_state_tfc_to_other_test.go b/v1.5.7/internal/cloud/e2e/migrate_state_tfc_to_other_test.go
new file mode 100644
index 0000000..fe8c35f
--- /dev/null
+++ b/v1.5.7/internal/cloud/e2e/migrate_state_tfc_to_other_test.go
@@ -0,0 +1,48 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"testing"
+)
+
+func Test_migrate_tfc_to_other(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+
+	cases := testCases{
+		"migrate from cloud to local backend": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "new-workspace"
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tfBlock := terraformConfigLocalBackend()
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Migrating state from Terraform Cloud to another backend is not yet implemented.`,
+							expectError:       true,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testRunner(t, cases, 1)
+}
diff --git a/v1.5.7/internal/cloud/e2e/migrate_state_tfc_to_tfc_test.go b/v1.5.7/internal/cloud/e2e/migrate_state_tfc_to_tfc_test.go
new file mode 100644
index 0000000..6050bd9
--- /dev/null
+++ b/v1.5.7/internal/cloud/e2e/migrate_state_tfc_to_tfc_test.go
@@ -0,0 +1,372 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"context"
+	"testing"
+
+	tfe "github.com/hashicorp/go-tfe"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+	skipWithoutRemoteTerraformVersion(t)
+
+	ctx := context.Background()
+
+	cases := testCases{
+		"migrating from name to name": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "prod"
+						// Creating the workspace here instead of it being created
+						// dynamically in the Cloud StateMgr because we want to ensure that
+						// the terraform version selected for the workspace matches the
+						// terraform version of this current branch.
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String("prod"),
+							TerraformVersion: tfe.String(tfversion.String()),
+						})
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: `prod`, // this comes from the `prep` function
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "dev"
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String(wsName),
+							TerraformVersion: tfe.String(tfversion.String()),
+						})
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:         []string{"init", "-ignore-remote-version"},
+							postInputOutput: []string{`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: `dev`, // this comes from the `prep` function
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				wsList, err := tfeClient.Workspaces.List(ctx, orgName, nil)
+				if err != nil {
+					t.Fatal(err)
+				}
+				// this workspace name is what exists in the cloud backend configuration block
+				if len(wsList.Items) != 2 {
+					t.Fatal("Expected number of workspaces to be 2")
+				}
+			},
+		},
+		"migrating from name to tags": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "prod"
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String("prod"),
+							TerraformVersion: tfe.String(tfversion.String()),
+						})
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tag := "app"
+						tfBlock := terraformConfigCloudBackendTags(orgName, tag)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init", "-ignore-remote-version"},
+							expectedCmdOutput: `There are no workspaces with the configured tags (app)`,
+							userInput:         []string{"new-workspace"},
+							postInputOutput: []string{
+								`Terraform can create a properly tagged workspace for you now.`,
+								`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: `new-workspace`, // this comes from the `prep` function
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				wsList, err := tfeClient.Workspaces.List(ctx, orgName, &tfe.WorkspaceListOptions{
+					Tags: "app",
+				})
+				if err != nil {
+					t.Fatal(err)
+				}
+				// this workspace name is what exists in the cloud backend configuration block
+				if len(wsList.Items) != 1 {
+					t.Fatal("Expected number of workspaces to be 1")
+				}
+			},
+		},
+		"migrating from name to tags without ignore-version flag": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "prod"
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String("prod"),
+							TerraformVersion: tfe.String(tfversion.String()),
+						})
+						tfBlock := terraformConfigCloudBackendName(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tag := "app"
+						// This is only here to ensure that the updated terraform version is
+						// present in the workspace, and it does not default to a lower
+						// version that does not support `cloud`.
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String("new-workspace"),
+							TerraformVersion: tfe.String(tfversion.String()),
+						})
+						tfBlock := terraformConfigCloudBackendTags(orgName, tag)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `There are no workspaces with the configured tags (app)`,
+							userInput:         []string{"new-workspace"},
+							postInputOutput: []string{
+								`Terraform can create a properly tagged workspace for you now.`,
+								`Terraform Cloud has been successfully initialized!`},
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				// We created the workspace, so it will be there. We could not complete the state migration,
+				// though, so the workspace should be empty.
+				ws, err := tfeClient.Workspaces.ReadWithOptions(ctx, orgName, "new-workspace", &tfe.WorkspaceReadOptions{Include: []tfe.WSIncludeOpt{tfe.WSCurrentRun}})
+				if err != nil {
+					t.Fatal(err)
+				}
+				if ws.CurrentRun != nil {
+					t.Fatal("Expected to workspace be empty")
+				}
+			},
+		},
+	}
+
+	testRunner(t, cases, 1)
+}
+
+func Test_migrate_tfc_to_tfc_multiple_workspace(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+	skipWithoutRemoteTerraformVersion(t)
+
+	ctx := context.Background()
+
+	cases := testCases{
+		"migrating from multiple workspaces via tags to name": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tag := "app"
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String("app-prod"),
+							Tags:             []*tfe.Tag{{Name: tag}},
+							TerraformVersion: tfe.String(tfversion.String()),
+						})
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String("app-staging"),
+							Tags:             []*tfe.Tag{{Name: tag}},
+							TerraformVersion: tfe.String(tfversion.String()),
+						})
+						tfBlock := terraformConfigCloudBackendTags(orgName, tag)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `The currently selected workspace (default) does not exist.`,
+							userInput:         []string{"1"},
+							postInputOutput:   []string{`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"apply"},
+							expectedCmdOutput: `Do you want to perform these actions in workspace "app-prod"?`,
+							userInput:         []string{"yes"},
+							postInputOutput:   []string{`Apply complete!`},
+						},
+						{
+							command:           []string{"workspace", "select", "app-staging"},
+							expectedCmdOutput: `Switched to workspace "app-staging".`,
+						},
+						{
+							command:         []string{"apply", "-auto-approve"},
+							postInputOutput: []string{`Apply complete!`},
+						},
+						{
+							command:           []string{"output"},
+							expectedCmdOutput: `tag_val = "app"`,
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						name := "service"
+						// Doing this here instead of relying on dynamic workspace creation
+						// because we want to set the terraform version here so that it is
+						// using the right version for post init operations.
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String(name),
+							TerraformVersion: tfe.String(tfversion.String()),
+						})
+						tfBlock := terraformConfigCloudBackendName(orgName, name)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init", "-ignore-remote-version"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+							postInputOutput:   []string{`tag_val = "service"`},
+						},
+						{
+							command:           []string{"workspace", "show"},
+							expectedCmdOutput: `service`, // this comes from the `prep` function
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				ws, err := tfeClient.Workspaces.Read(ctx, orgName, "service")
+				if err != nil {
+					t.Fatal(err)
+				}
+				if ws == nil {
+					t.Fatal("Expected to workspace not be empty")
+				}
+			},
+		},
+		"migrating from multiple workspaces via tags to other tags": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tag := "app"
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String("app-prod"),
+							Tags:             []*tfe.Tag{{Name: tag}},
+							TerraformVersion: tfe.String(tfversion.String()),
+						})
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String("app-staging"),
+							Tags:             []*tfe.Tag{{Name: tag}},
+							TerraformVersion: tfe.String(tfversion.String()),
+						})
+						tfBlock := terraformConfigCloudBackendTags(orgName, tag)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `The currently selected workspace (default) does not exist.`,
+							userInput:         []string{"1"},
+							postInputOutput:   []string{`Terraform Cloud has been successfully initialized!`},
+						},
+						{
+							command:           []string{"apply", "-auto-approve"},
+							expectedCmdOutput: `Apply complete!`,
+						},
+						{
+							command:           []string{"workspace", "select", "app-staging"},
+							expectedCmdOutput: `Switched to workspace "app-staging".`,
+						},
+						{
+							command:           []string{"apply", "-auto-approve"},
+							expectedCmdOutput: `Apply complete!`,
+						},
+					},
+				},
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						tag := "billing"
+						tfBlock := terraformConfigCloudBackendTags(orgName, tag)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init", "-ignore-remote-version"},
+							expectedCmdOutput: `There are no workspaces with the configured tags (billing)`,
+							userInput:         []string{"new-app-prod"},
+							postInputOutput:   []string{`Terraform Cloud has been successfully initialized!`},
+						},
+					},
+				},
+			},
+			validations: func(t *testing.T, orgName string) {
+				wsList, err := tfeClient.Workspaces.List(ctx, orgName, &tfe.WorkspaceListOptions{
+					Tags: "billing",
+				})
+				if err != nil {
+					t.Fatal(err)
+				}
+				if len(wsList.Items) != 1 {
+					t.Logf("Expected the number of workspaces to be 2, but got %d", len(wsList.Items))
+				}
+				_, empty := getWorkspace(wsList.Items, "new-app-prod")
+				if empty {
+					t.Fatalf("expected workspaces to include 'new-app-prod' but didn't.")
+				}
+			},
+		},
+	}
+
+	testRunner(t, cases, 1)
+}
diff --git a/v1.5.7/internal/cloud/e2e/run_variables_test.go b/v1.5.7/internal/cloud/e2e/run_variables_test.go
new file mode 100644
index 0000000..469d5ee
--- /dev/null
+++ b/v1.5.7/internal/cloud/e2e/run_variables_test.go
@@ -0,0 +1,84 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"fmt"
+	"testing"
+
+	tfe "github.com/hashicorp/go-tfe"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+func terraformConfigRequiredVariable(org, name string) string {
+	return fmt.Sprintf(`
+terraform {
+  cloud {
+    hostname = "%s"
+    organization = "%s"
+
+    workspaces {
+      name = "%s"
+    }
+  }
+}
+
+variable "foo" {
+  type = string
+}
+
+variable "baz" {
+	type = string
+}
+
+output "test_cli" {
+  value = var.foo
+}
+
+output "test_env" {
+  value = var.baz
+}
+
+`, tfeHostname, org, name)
+}
+
+func Test_cloud_run_variables(t *testing.T) {
+	t.Parallel()
+	skipIfMissingEnvVar(t)
+	skipWithoutRemoteTerraformVersion(t)
+
+	cases := testCases{
+		"run variables from CLI arg": {
+			operations: []operationSets{
+				{
+					prep: func(t *testing.T, orgName, dir string) {
+						wsName := "new-workspace"
+						_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
+							Name:             tfe.String(wsName),
+							TerraformVersion: tfe.String(tfversion.String()),
+						})
+						tfBlock := terraformConfigRequiredVariable(orgName, wsName)
+						writeMainTF(t, tfBlock, dir)
+					},
+					commands: []tfCommand{
+						{
+							command:           []string{"init"},
+							expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
+						},
+						{
+							command:           []string{"plan", "-var", "foo=bar"},
+							expectedCmdOutput: `  + test_cli = "bar"`,
+						},
+						{
+							command:           []string{"plan", "-var", "foo=bar"},
+							expectedCmdOutput: `  + test_env = "qux"`,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testRunner(t, cases, 1, "TF_CLI_ARGS=-no-color", "TF_VAR_baz=qux")
+}
diff --git a/v1.5.7/internal/cloud/errors.go b/v1.5.7/internal/cloud/errors.go
new file mode 100644
index 0000000..f6d2f91
--- /dev/null
+++ b/v1.5.7/internal/cloud/errors.go
@@ -0,0 +1,63 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"errors"
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// String based errors
+var (
+	errApplyDiscarded                    = errors.New("Apply discarded.")
+	errDestroyDiscarded                  = errors.New("Destroy discarded.")
+	errRunApproved                       = errors.New("approved using the UI or API")
+	errRunDiscarded                      = errors.New("discarded using the UI or API")
+	errRunOverridden                     = errors.New("overridden using the UI or API")
+	errApplyNeedsUIConfirmation          = errors.New("Cannot confirm apply due to -input=false. Please handle run confirmation in the UI.")
+	errPolicyOverrideNeedsUIConfirmation = errors.New("Cannot override soft failed policy checks when -input=false. Please open the run in the UI to override.")
+)
+
+// Diagnostic error messages
+var (
+	invalidWorkspaceConfigMissingValues = tfdiags.AttributeValue(
+		tfdiags.Error,
+		"Invalid workspaces configuration",
+		fmt.Sprintf("Missing workspace mapping strategy. Either workspace \"tags\" or \"name\" is required.\n\n%s", workspaceConfigurationHelp),
+		cty.Path{cty.GetAttrStep{Name: "workspaces"}},
+	)
+
+	invalidWorkspaceConfigMisconfiguration = tfdiags.AttributeValue(
+		tfdiags.Error,
+		"Invalid workspaces configuration",
+		fmt.Sprintf("Only one of workspace \"tags\" or \"name\" is allowed.\n\n%s", workspaceConfigurationHelp),
+		cty.Path{cty.GetAttrStep{Name: "workspaces"}},
+	)
+)
+
+const ignoreRemoteVersionHelp = "If you're sure you want to upgrade the state, you can force Terraform to continue using the -ignore-remote-version flag. This may result in an unusable workspace."
+
+func missingConfigAttributeAndEnvVar(attribute string, envVar string) tfdiags.Diagnostic {
+	detail := strings.TrimSpace(fmt.Sprintf("\"%s\" must be set in the cloud configuration or as an environment variable: %s.\n", attribute, envVar))
+	return tfdiags.AttributeValue(
+		tfdiags.Error,
+		"Invalid or missing required argument",
+		detail,
+		cty.Path{cty.GetAttrStep{Name: attribute}})
+}
+
+func incompatibleWorkspaceTerraformVersion(message string, ignoreVersionConflict bool) tfdiags.Diagnostic {
+	severity := tfdiags.Error
+	suggestion := ignoreRemoteVersionHelp
+	if ignoreVersionConflict {
+		severity = tfdiags.Warning
+		suggestion = ""
+	}
+	description := strings.TrimSpace(fmt.Sprintf("%s\n\n%s", message, suggestion))
+	return tfdiags.Sourceless(severity, "Incompatible Terraform version", description)
+}
diff --git a/v1.5.7/internal/cloud/migration.go b/v1.5.7/internal/cloud/migration.go
new file mode 100644
index 0000000..43b96b0
--- /dev/null
+++ b/v1.5.7/internal/cloud/migration.go
@@ -0,0 +1,109 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"github.com/hashicorp/terraform/internal/configs"
+	legacy "github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+// Most of the logic for migrating into and out of "cloud mode" actually lives
+// in the "command" package as part of the general backend init mechanisms,
+// but we have some cloud-specific helper functionality here.
+
+// ConfigChangeMode is a rough way to think about different situations that
+// our backend change and state migration codepaths need to distinguish in
+// the context of Cloud integration mode.
+type ConfigChangeMode rune
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type ConfigChangeMode
+
+const (
+	// ConfigMigrationIn represents when the configuration calls for using
+	// Cloud mode but the working directory state disagrees.
+	ConfigMigrationIn ConfigChangeMode = '↘'
+
+	// ConfigMigrationOut represents when the working directory state calls
+	// for using Cloud mode but the working directory state disagrees.
+	ConfigMigrationOut ConfigChangeMode = '↖'
+
+	// ConfigChangeInPlace represents when both the working directory state
+	// and the config call for using Cloud mode, and so there might be
+	// (but won't necessarily be) cloud settings changing, but we don't
+	// need to do any actual migration.
+	ConfigChangeInPlace ConfigChangeMode = '↻'
+
+	// ConfigChangeIrrelevant represents when the config and working directory
+	// state disagree but neither calls for using Cloud mode, and so the
+	// Cloud integration is not involved in dealing with this.
+	ConfigChangeIrrelevant ConfigChangeMode = '🤷'
+)
+
+// DetectConfigChangeType encapsulates the fiddly logic for deciding what kind
+// of Cloud configuration change we seem to be making, based on the existing
+// working directory state (if any) and the current configuration.
+//
+// This is a pretty specialized sort of thing focused on finicky details of
+// the way we currently model working directory settings and config, so its
+// signature probably won't survive any non-trivial refactoring of how
+// the CLI layer thinks about backends/state storage.
+func DetectConfigChangeType(wdState *legacy.BackendState, config *configs.Backend, haveLocalStates bool) ConfigChangeMode {
+	// Although externally the cloud integration isn't really a "backend",
+	// internally we treat it a bit like one just to preserve all of our
+	// existing interfaces that assume backends. "cloud" is the placeholder
+	// name we use for it, even though that isn't a backend that's actually
+	// available for selection in the usual way.
+	wdIsCloud := wdState != nil && wdState.Type == "cloud"
+	configIsCloud := config != nil && config.Type == "cloud"
+
+	// "uninit" here means that the working directory is totally uninitialized,
+	// even taking into account the possibility of implied local state that
+	// therefore doesn't typically require explicit "terraform init".
+	wdIsUninit := wdState == nil && !haveLocalStates
+
+	switch {
+	case configIsCloud:
+		switch {
+		case wdIsCloud || wdIsUninit:
+			// If config has cloud and the working directory is completely
+			// uninitialized then we assume we're doing the initial activation
+			// of this working directory for an already-migrated-to-cloud
+			// remote state.
+			return ConfigChangeInPlace
+		default:
+			// Otherwise, we seem to be migrating into cloud mode from a backend.
+			return ConfigMigrationIn
+		}
+	default:
+		switch {
+		case wdIsCloud:
+			// If working directory is already cloud but config isn't, we're
+			// migrating away from cloud to a backend.
+			return ConfigMigrationOut
+		default:
+			// Otherwise, this situation seems to be something unrelated to
+			// cloud mode and so outside of our scope here.
+			return ConfigChangeIrrelevant
+		}
+	}
+
+}
+
+func (m ConfigChangeMode) InvolvesCloud() bool {
+	switch m {
+	case ConfigMigrationIn, ConfigMigrationOut, ConfigChangeInPlace:
+		return true
+	default:
+		return false
+	}
+}
+
+func (m ConfigChangeMode) IsCloudMigration() bool {
+	switch m {
+	case ConfigMigrationIn, ConfigMigrationOut:
+		return true
+	default:
+		return false
+	}
+}
diff --git a/v1.5.7/internal/cloud/migration_test.go b/v1.5.7/internal/cloud/migration_test.go
new file mode 100644
index 0000000..ddc6260
--- /dev/null
+++ b/v1.5.7/internal/cloud/migration_test.go
@@ -0,0 +1,141 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/configs"
+	legacy "github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+func TestDetectConfigChangeType(t *testing.T) {
+	tests := map[string]struct {
+		stateType            string
+		configType           string
+		localStates          bool
+		want                 ConfigChangeMode
+		wantInvolvesCloud    bool
+		wantIsCloudMigration bool
+	}{
+		"init cloud": {
+			``, `cloud`, false,
+			ConfigChangeInPlace,
+			true, false,
+		},
+		"reinit cloud": {
+			`cloud`, `cloud`, false,
+			ConfigChangeInPlace,
+			true, false,
+		},
+		"migrate default local to cloud with existing local state": {
+			``, `cloud`, true,
+			ConfigMigrationIn,
+			true, true,
+		},
+		"migrate local to cloud": {
+			`local`, `cloud`, false,
+			ConfigMigrationIn,
+			true, true,
+		},
+		"migrate remote to cloud": {
+			`local`, `cloud`, false,
+			ConfigMigrationIn,
+			true, true,
+		},
+		"migrate cloud to local": {
+			`cloud`, `local`, false,
+			ConfigMigrationOut,
+			true, true,
+		},
+		"migrate cloud to remote": {
+			`cloud`, `remote`, false,
+			ConfigMigrationOut,
+			true, true,
+		},
+		"migrate cloud to default local": {
+			`cloud`, ``, false,
+			ConfigMigrationOut,
+			true, true,
+		},
+
+		// Various other cases can potentially be valid (decided by the
+		// Terraform CLI layer) but are irrelevant for Cloud mode purposes.
+		"init default local": {
+			``, ``, false,
+			ConfigChangeIrrelevant,
+			false, false,
+		},
+		"init default local with existing local state": {
+			``, ``, true,
+			ConfigChangeIrrelevant,
+			false, false,
+		},
+		"init remote backend": {
+			``, `remote`, false,
+			ConfigChangeIrrelevant,
+			false, false,
+		},
+		"init remote backend with existing local state": {
+			``, `remote`, true,
+			ConfigChangeIrrelevant,
+			false, false,
+		},
+		"reinit remote backend": {
+			`remote`, `remote`, false,
+			ConfigChangeIrrelevant,
+			false, false,
+		},
+		"migrate local to remote backend": {
+			`local`, `remote`, false,
+			ConfigChangeIrrelevant,
+			false, false,
+		},
+		"migrate remote to default local": {
+			`remote`, ``, false,
+			ConfigChangeIrrelevant,
+			false, false,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			var state *legacy.BackendState
+			var config *configs.Backend
+			if test.stateType != "" {
+				state = &legacy.BackendState{
+					Type: test.stateType,
+					// everything else is irrelevant for our purposes here
+				}
+			}
+			if test.configType != "" {
+				config = &configs.Backend{
+					Type: test.configType,
+					// everything else is irrelevant for our purposes here
+				}
+			}
+			got := DetectConfigChangeType(state, config, test.localStates)
+
+			if got != test.want {
+				t.Errorf(
+					"wrong result\nstate type:   %s\nconfig type:  %s\nlocal states: %t\n\ngot:  %s\nwant: %s",
+					test.stateType, test.configType, test.localStates,
+					got, test.want,
+				)
+			}
+			if got, want := got.InvolvesCloud(), test.wantInvolvesCloud; got != want {
+				t.Errorf(
+					"wrong InvolvesCloud result\ngot:  %t\nwant: %t",
+					got, want,
+				)
+			}
+			if got, want := got.IsCloudMigration(), test.wantIsCloudMigration; got != want {
+				t.Errorf(
+					"wrong IsCloudMigration result\ngot:  %t\nwant: %t",
+					got, want,
+				)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/cloud/remote_test.go b/v1.5.7/internal/cloud/remote_test.go
new file mode 100644
index 0000000..dfc76c8
--- /dev/null
+++ b/v1.5.7/internal/cloud/remote_test.go
@@ -0,0 +1,28 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"flag"
+	"os"
+	"testing"
+	"time"
+
+	_ "github.com/hashicorp/terraform/internal/logging"
+)
+
+func TestMain(m *testing.M) {
+	flag.Parse()
+
+	// Make sure TF_FORCE_LOCAL_BACKEND is unset
+	os.Unsetenv("TF_FORCE_LOCAL_BACKEND")
+
+	// Reduce delays to make tests run faster
+	backoffMin = 1.0
+	backoffMax = 1.0
+	planConfigurationVersionsPollInterval = 1 * time.Millisecond
+	runPollInterval = 1 * time.Millisecond
+
+	os.Exit(m.Run())
+}
diff --git a/v1.5.7/internal/cloud/state.go b/v1.5.7/internal/cloud/state.go
new file mode 100644
index 0000000..f3abc0b
--- /dev/null
+++ b/v1.5.7/internal/cloud/state.go
@@ -0,0 +1,566 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"bytes"
+	"context"
+	"crypto/md5"
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"log"
+	"net/http"
+	"os"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/gocty"
+
+	tfe "github.com/hashicorp/go-tfe"
+	uuid "github.com/hashicorp/go-uuid"
+
+	"github.com/hashicorp/terraform/internal/backend/local"
+	"github.com/hashicorp/terraform/internal/command/jsonstate"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/remote"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// State implements the State interfaces in the state package to handle
+// reading and writing the remote state to TFC. This State on its own does no
+// local caching so every persist will go to the remote storage and local
+// writes will go to memory.
+type State struct {
+	mu sync.Mutex
+
+	// We track two pieces of meta data in addition to the state itself:
+	//
+	// lineage - the state's unique ID
+	// serial  - the monotonic counter of "versions" of the state
+	//
+	// Both of these (along with state) have a sister field
+	// that represents the values read in from an existing source.
+	// All three of these values are used to determine if the new
+	// state has changed from an existing state we read in.
+	lineage, readLineage string
+	serial, readSerial   uint64
+	state, readState     *states.State
+	disableLocks         bool
+	tfeClient            *tfe.Client
+	organization         string
+	workspace            *tfe.Workspace
+	stateUploadErr       bool
+	forcePush            bool
+	lockInfo             *statemgr.LockInfo
+
+	// The server can optionally return an X-Terraform-Snapshot-Interval header
+	// in its response to the "Create State Version" operation, which specifies
+	// a number of seconds the server would prefer us to wait before trying
+	// to write a new snapshot. If this is non-zero then we'll wait at least
+	// this long before allowing another intermediate snapshot. This does
+	// not effect final snapshots after an operation, which will always
+	// be written to the remote API.
+	stateSnapshotInterval time.Duration
+}
+
+var ErrStateVersionUnauthorizedUpgradeState = errors.New(strings.TrimSpace(`
+You are not authorized to read the full state version containing outputs.
+State versions created by terraform v1.3.0 and newer do not require this level
+of authorization and therefore this error can usually be fixed by upgrading the
+remote state version.
+`))
+
+var _ statemgr.Full = (*State)(nil)
+var _ statemgr.Migrator = (*State)(nil)
+var _ local.IntermediateStateConditionalPersister = (*State)(nil)
+
+// statemgr.Reader impl.
+func (s *State) State() *states.State {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	return s.state.DeepCopy()
+}
+
+// StateForMigration is part of our implementation of statemgr.Migrator.
+func (s *State) StateForMigration() *statefile.File {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	return statefile.New(s.state.DeepCopy(), s.lineage, s.serial)
+}
+
+// WriteStateForMigration is part of our implementation of statemgr.Migrator.
+func (s *State) WriteStateForMigration(f *statefile.File, force bool) error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	if !force {
+		checkFile := statefile.New(s.state, s.lineage, s.serial)
+		if err := statemgr.CheckValidImport(f, checkFile); err != nil {
+			return err
+		}
+	}
+
+	// We create a deep copy of the state here, because the caller also has
+	// a reference to the given object and can potentially go on to mutate
+	// it after we return, but we want the snapshot at this point in time.
+	s.state = f.State.DeepCopy()
+	s.lineage = f.Lineage
+	s.serial = f.Serial
+	s.forcePush = force
+
+	return nil
+}
+
+// DisableLocks turns the Lock and Unlock methods into no-ops. This is intended
+// to be called during initialization of a state manager and should not be
+// called after any of the statemgr.Full interface methods have been called.
+func (s *State) DisableLocks() {
+	s.disableLocks = true
+}
+
+// StateSnapshotMeta returns the metadata from the most recently persisted
+// or refreshed persistent state snapshot.
+//
+// This is an implementation of statemgr.PersistentMeta.
+func (s *State) StateSnapshotMeta() statemgr.SnapshotMeta {
+	return statemgr.SnapshotMeta{
+		Lineage: s.lineage,
+		Serial:  s.serial,
+	}
+}
+
+// statemgr.Writer impl.
+func (s *State) WriteState(state *states.State) error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	// We create a deep copy of the state here, because the caller also has
+	// a reference to the given object and can potentially go on to mutate
+	// it after we return, but we want the snapshot at this point in time.
+	s.state = state.DeepCopy()
+	s.forcePush = false
+
+	return nil
+}
+
+// PersistState uploads a snapshot of the latest state as a StateVersion to Terraform Cloud
+func (s *State) PersistState(schemas *terraform.Schemas) error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	log.Printf("[DEBUG] cloud/state: state read serial is: %d; serial is: %d", s.readSerial, s.serial)
+	log.Printf("[DEBUG] cloud/state: state read lineage is: %s; lineage is: %s", s.readLineage, s.lineage)
+
+	if s.readState != nil {
+		lineageUnchanged := s.readLineage != "" && s.lineage == s.readLineage
+		serialUnchanged := s.readSerial != 0 && s.serial == s.readSerial
+		stateUnchanged := statefile.StatesMarshalEqual(s.state, s.readState)
+		if stateUnchanged && lineageUnchanged && serialUnchanged {
+			// If the state, lineage or serial haven't changed at all then we have nothing to do.
+			return nil
+		}
+		s.serial++
+	} else {
+		// We might be writing a new state altogether, but before we do that
+		// we'll check to make sure there isn't already a snapshot present
+		// that we ought to be updating.
+		err := s.refreshState()
+		if err != nil {
+			return fmt.Errorf("failed checking for existing remote state: %s", err)
+		}
+		log.Printf("[DEBUG] cloud/state: after refresh, state read serial is: %d; serial is: %d", s.readSerial, s.serial)
+		log.Printf("[DEBUG] cloud/state: after refresh, state read lineage is: %s; lineage is: %s", s.readLineage, s.lineage)
+
+		if s.lineage == "" { // indicates that no state snapshot is present yet
+			lineage, err := uuid.GenerateUUID()
+			if err != nil {
+				return fmt.Errorf("failed to generate initial lineage: %v", err)
+			}
+			s.lineage = lineage
+			s.serial++
+		}
+	}
+
+	f := statefile.New(s.state, s.lineage, s.serial)
+
+	var buf bytes.Buffer
+	err := statefile.Write(f, &buf)
+	if err != nil {
+		return err
+	}
+
+	var jsonState []byte
+	if schemas != nil {
+		jsonState, err = jsonstate.Marshal(f, schemas)
+		if err != nil {
+			return err
+		}
+	}
+
+	stateFile, err := statefile.Read(bytes.NewReader(buf.Bytes()))
+	if err != nil {
+		return fmt.Errorf("failed to read state: %w", err)
+	}
+
+	ov, err := jsonstate.MarshalOutputs(stateFile.State.RootModule().OutputValues)
+	if err != nil {
+		return fmt.Errorf("failed to translate outputs: %w", err)
+	}
+	jsonStateOutputs, err := json.Marshal(ov)
+	if err != nil {
+		return fmt.Errorf("failed to marshal outputs to json: %w", err)
+	}
+
+	err = s.uploadState(s.lineage, s.serial, s.forcePush, buf.Bytes(), jsonState, jsonStateOutputs)
+	if err != nil {
+		s.stateUploadErr = true
+		return fmt.Errorf("error uploading state: %w", err)
+	}
+	// After we've successfully persisted, what we just wrote is our new
+	// reference state until someone calls RefreshState again.
+	// We've potentially overwritten (via force) the state, lineage
+	// and / or serial (and serial was incremented) so we copy over all
+	// three fields so everything matches the new state and a subsequent
+	// operation would correctly detect no changes to the lineage, serial or state.
+	s.readState = s.state.DeepCopy()
+	s.readLineage = s.lineage
+	s.readSerial = s.serial
+	return nil
+}
+
+// ShouldPersistIntermediateState implements local.IntermediateStateConditionalPersister
+func (s *State) ShouldPersistIntermediateState(info *local.IntermediateStatePersistInfo) bool {
+	if info.ForcePersist {
+		return true
+	}
+
+	// Our persist interval is the largest of either the caller's requested
+	// interval or the server's requested interval.
+	wantInterval := info.RequestedPersistInterval
+	if s.stateSnapshotInterval > wantInterval {
+		wantInterval = s.stateSnapshotInterval
+	}
+
+	currentInterval := time.Since(info.LastPersist)
+	return currentInterval >= wantInterval
+}
+
+func (s *State) uploadState(lineage string, serial uint64, isForcePush bool, state, jsonState, jsonStateOutputs []byte) error {
+	ctx := context.Background()
+
+	options := tfe.StateVersionCreateOptions{
+		Lineage:          tfe.String(lineage),
+		Serial:           tfe.Int64(int64(serial)),
+		MD5:              tfe.String(fmt.Sprintf("%x", md5.Sum(state))),
+		State:            tfe.String(base64.StdEncoding.EncodeToString(state)),
+		Force:            tfe.Bool(isForcePush),
+		JSONState:        tfe.String(base64.StdEncoding.EncodeToString(jsonState)),
+		JSONStateOutputs: tfe.String(base64.StdEncoding.EncodeToString(jsonStateOutputs)),
+	}
+
+	// If we have a run ID, make sure to add it to the options
+	// so the state will be properly associated with the run.
+	runID := os.Getenv("TFE_RUN_ID")
+	if runID != "" {
+		options.Run = &tfe.Run{ID: runID}
+	}
+
+	// The server is allowed to dynamically request a different time interval
+	// than we'd normally use, for example if it's currently under heavy load
+	// and needs clients to backoff for a while.
+	ctx = tfe.ContextWithResponseHeaderHook(ctx, func(status int, header http.Header) {
+		intervalStr := header.Get("x-terraform-snapshot-interval")
+
+		if intervalSecs, err := strconv.ParseInt(intervalStr, 10, 64); err == nil {
+			if intervalSecs > 3600 {
+				// More than an hour is an unreasonable delay, so we'll just
+				// saturate at one hour.
+				intervalSecs = 3600
+			} else if intervalSecs < 0 {
+				intervalSecs = 0
+			}
+			s.stateSnapshotInterval = time.Duration(intervalSecs) * time.Second
+		} else {
+			// If the header field is either absent or invalid then we'll
+			// just choose zero, which effectively means that we'll just use
+			// the caller's requested interval instead.
+			s.stateSnapshotInterval = time.Duration(0)
+		}
+	})
+
+	// Create the new state.
+	_, err := s.tfeClient.StateVersions.Create(ctx, s.workspace.ID, options)
+	return err
+}
+
+// Lock calls the Client's Lock method if it's implemented.
+func (s *State) Lock(info *statemgr.LockInfo) (string, error) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	if s.disableLocks {
+		return "", nil
+	}
+	ctx := context.Background()
+
+	lockErr := &statemgr.LockError{Info: s.lockInfo}
+
+	// Lock the workspace.
+	_, err := s.tfeClient.Workspaces.Lock(ctx, s.workspace.ID, tfe.WorkspaceLockOptions{
+		Reason: tfe.String("Locked by Terraform"),
+	})
+	if err != nil {
+		if err == tfe.ErrWorkspaceLocked {
+			lockErr.Info = info
+			err = fmt.Errorf("%s (lock ID: \"%s/%s\")", err, s.organization, s.workspace.Name)
+		}
+		lockErr.Err = err
+		return "", lockErr
+	}
+
+	s.lockInfo = info
+
+	return s.lockInfo.ID, nil
+}
+
+// statemgr.Refresher impl.
+func (s *State) RefreshState() error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	return s.refreshState()
+}
+
+// refreshState is the main implementation of RefreshState, but split out so
+// that we can make internal calls to it from methods that are already holding
+// the s.mu lock.
+func (s *State) refreshState() error {
+	payload, err := s.getStatePayload()
+	if err != nil {
+		return err
+	}
+
+	// no remote state is OK
+	if payload == nil {
+		s.readState = nil
+		s.lineage = ""
+		s.serial = 0
+		return nil
+	}
+
+	stateFile, err := statefile.Read(bytes.NewReader(payload.Data))
+	if err != nil {
+		return err
+	}
+
+	s.lineage = stateFile.Lineage
+	s.serial = stateFile.Serial
+	s.state = stateFile.State
+
+	// Properties from the remote must be separate so we can
+	// track changes as lineage, serial and/or state are mutated
+	s.readLineage = stateFile.Lineage
+	s.readSerial = stateFile.Serial
+	s.readState = s.state.DeepCopy()
+	return nil
+}
+
+func (s *State) getStatePayload() (*remote.Payload, error) {
+	ctx := context.Background()
+
+	sv, err := s.tfeClient.StateVersions.ReadCurrent(ctx, s.workspace.ID)
+	if err != nil {
+		if err == tfe.ErrResourceNotFound {
+			// If no state exists, then return nil.
+			return nil, nil
+		}
+		return nil, fmt.Errorf("error retrieving state: %v", err)
+	}
+
+	state, err := s.tfeClient.StateVersions.Download(ctx, sv.DownloadURL)
+	if err != nil {
+		return nil, fmt.Errorf("error downloading state: %v", err)
+	}
+
+	// If the state is empty, then return nil.
+	if len(state) == 0 {
+		return nil, nil
+	}
+
+	// Get the MD5 checksum of the state.
+	sum := md5.Sum(state)
+
+	return &remote.Payload{
+		Data: state,
+		MD5:  sum[:],
+	}, nil
+}
+
+// Unlock calls the Client's Unlock method if it's implemented.
+func (s *State) Unlock(id string) error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	if s.disableLocks {
+		return nil
+	}
+
+	ctx := context.Background()
+
+	// We first check if there was an error while uploading the latest
+	// state. If so, we will not unlock the workspace to prevent any
+	// changes from being applied until the correct state is uploaded.
+	if s.stateUploadErr {
+		return nil
+	}
+
+	lockErr := &statemgr.LockError{Info: s.lockInfo}
+
+	// With lock info this should be treated as a normal unlock.
+	if s.lockInfo != nil {
+		// Verify the expected lock ID.
+		if s.lockInfo.ID != id {
+			lockErr.Err = fmt.Errorf("lock ID does not match existing lock")
+			return lockErr
+		}
+
+		// Unlock the workspace.
+		_, err := s.tfeClient.Workspaces.Unlock(ctx, s.workspace.ID)
+		if err != nil {
+			lockErr.Err = err
+			return lockErr
+		}
+
+		return nil
+	}
+
+	// Verify the optional force-unlock lock ID.
+	if s.organization+"/"+s.workspace.Name != id {
+		lockErr.Err = fmt.Errorf(
+			"lock ID %q does not match existing lock ID \"%s/%s\"",
+			id,
+			s.organization,
+			s.workspace.Name,
+		)
+		return lockErr
+	}
+
+	// Force unlock the workspace.
+	_, err := s.tfeClient.Workspaces.ForceUnlock(ctx, s.workspace.ID)
+	if err != nil {
+		lockErr.Err = err
+		return lockErr
+	}
+
+	return nil
+}
+
+// Delete the remote state.
+func (s *State) Delete(force bool) error {
+
+	var err error
+
+	isSafeDeleteSupported := s.workspace.Permissions.CanForceDelete != nil
+	if force || !isSafeDeleteSupported {
+		err = s.tfeClient.Workspaces.Delete(context.Background(), s.organization, s.workspace.Name)
+	} else {
+		err = s.tfeClient.Workspaces.SafeDelete(context.Background(), s.organization, s.workspace.Name)
+	}
+
+	if err != nil && err != tfe.ErrResourceNotFound {
+		return fmt.Errorf("error deleting workspace %s: %v", s.workspace.Name, err)
+	}
+
+	return nil
+}
+
+// GetRootOutputValues fetches output values from Terraform Cloud
+func (s *State) GetRootOutputValues() (map[string]*states.OutputValue, error) {
+	ctx := context.Background()
+
+	so, err := s.tfeClient.StateVersionOutputs.ReadCurrent(ctx, s.workspace.ID)
+
+	if err != nil {
+		return nil, fmt.Errorf("could not read state version outputs: %w", err)
+	}
+
+	result := make(map[string]*states.OutputValue)
+
+	for _, output := range so.Items {
+		if output.DetailedType == nil {
+			// If there is no detailed type information available, this state was probably created
+			// with a version of terraform < 1.3.0. In this case, we'll eject completely from this
+			// function and fall back to the old behavior of reading the entire state file, which
+			// requires a higher level of authorization.
+			log.Printf("[DEBUG] falling back to reading full state")
+
+			if err := s.RefreshState(); err != nil {
+				return nil, fmt.Errorf("failed to load state: %w", err)
+			}
+
+			state := s.State()
+			if state == nil {
+				// We know that there is supposed to be state (and this is not simply a new workspace
+				// without state) because the fallback is only invoked when outputs are present but
+				// detailed types are not available.
+				return nil, ErrStateVersionUnauthorizedUpgradeState
+			}
+
+			return state.RootModule().OutputValues, nil
+		}
+
+		if output.Sensitive {
+			// Since this is a sensitive value, the output must be requested explicitly in order to
+			// read its value, which is assumed to be present by callers
+			sensitiveOutput, err := s.tfeClient.StateVersionOutputs.Read(ctx, output.ID)
+			if err != nil {
+				return nil, fmt.Errorf("could not read state version output %s: %w", output.ID, err)
+			}
+			output.Value = sensitiveOutput.Value
+		}
+
+		cval, err := tfeOutputToCtyValue(*output)
+		if err != nil {
+			return nil, fmt.Errorf("could not decode output %s (ID %s)", output.Name, output.ID)
+		}
+
+		result[output.Name] = &states.OutputValue{
+			Value:     cval,
+			Sensitive: output.Sensitive,
+		}
+	}
+
+	return result, nil
+}
+
+// tfeOutputToCtyValue decodes a combination of TFE output value and detailed-type to create a
+// cty value that is suitable for use in terraform.
+func tfeOutputToCtyValue(output tfe.StateVersionOutput) (cty.Value, error) {
+	var result cty.Value
+	bufType, err := json.Marshal(output.DetailedType)
+	if err != nil {
+		return result, fmt.Errorf("could not marshal output %s type: %w", output.ID, err)
+	}
+
+	var ctype cty.Type
+	err = ctype.UnmarshalJSON(bufType)
+	if err != nil {
+		return result, fmt.Errorf("could not interpret output %s type: %w", output.ID, err)
+	}
+
+	result, err = gocty.ToCtyValue(output.Value, ctype)
+	if err != nil {
+		return result, fmt.Errorf("could not interpret value %v as type %s for output %s: %w", result, ctype.FriendlyName(), output.ID, err)
+	}
+
+	return result, nil
+}
diff --git a/v1.5.7/internal/cloud/state_test.go b/v1.5.7/internal/cloud/state_test.go
new file mode 100644
index 0000000..d29ce5b
--- /dev/null
+++ b/v1.5.7/internal/cloud/state_test.go
@@ -0,0 +1,505 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"io/ioutil"
+	"net/http"
+	"net/http/httptest"
+	"strconv"
+	"testing"
+	"time"
+
+	tfe "github.com/hashicorp/go-tfe"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend/local"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestState_impl(t *testing.T) {
+	var _ statemgr.Reader = new(State)
+	var _ statemgr.Writer = new(State)
+	var _ statemgr.Persister = new(State)
+	var _ statemgr.Refresher = new(State)
+	var _ statemgr.OutputReader = new(State)
+	var _ statemgr.Locker = new(State)
+}
+
+type ExpectedOutput struct {
+	Name      string
+	Sensitive bool
+	IsNull    bool
+}
+
+func TestState_GetRootOutputValues(t *testing.T) {
+	b, bCleanup := testBackendWithOutputs(t)
+	defer bCleanup()
+
+	state := &State{tfeClient: b.client, organization: b.organization, workspace: &tfe.Workspace{
+		ID: "ws-abcd",
+	}}
+	outputs, err := state.GetRootOutputValues()
+
+	if err != nil {
+		t.Fatalf("error returned from GetRootOutputValues: %s", err)
+	}
+
+	cases := []ExpectedOutput{
+		{
+			Name:      "sensitive_output",
+			Sensitive: true,
+			IsNull:    false,
+		},
+		{
+			Name:      "nonsensitive_output",
+			Sensitive: false,
+			IsNull:    false,
+		},
+		{
+			Name:      "object_output",
+			Sensitive: false,
+			IsNull:    false,
+		},
+		{
+			Name:      "list_output",
+			Sensitive: false,
+			IsNull:    false,
+		},
+	}
+
+	if len(outputs) != len(cases) {
+		t.Errorf("Expected %d item but %d were returned", len(cases), len(outputs))
+	}
+
+	for _, testCase := range cases {
+		so, ok := outputs[testCase.Name]
+		if !ok {
+			t.Fatalf("Expected key %s but it was not found", testCase.Name)
+		}
+		if so.Value.IsNull() != testCase.IsNull {
+			t.Errorf("Key %s does not match null expectation %v", testCase.Name, testCase.IsNull)
+		}
+		if so.Sensitive != testCase.Sensitive {
+			t.Errorf("Key %s does not match sensitive expectation %v", testCase.Name, testCase.Sensitive)
+		}
+	}
+}
+
+func TestState(t *testing.T) {
+	var buf bytes.Buffer
+	s := statemgr.TestFullInitialState()
+	sf := statefile.New(s, "stub-lineage", 2)
+	err := statefile.Write(sf, &buf)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	data := buf.Bytes()
+
+	state := testCloudState(t)
+
+	jsonState, err := ioutil.ReadFile("../command/testdata/show-json-state/sensitive-variables/output.json")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	jsonStateOutputs := []byte(`
+{
+	"outputs": {
+			"foo": {
+					"type": "string",
+					"value": "bar"
+			}
+	}
+}`)
+
+	if err := state.uploadState(state.lineage, state.serial, state.forcePush, data, jsonState, jsonStateOutputs); err != nil {
+		t.Fatalf("put: %s", err)
+	}
+
+	payload, err := state.getStatePayload()
+	if err != nil {
+		t.Fatalf("get: %s", err)
+	}
+	if !bytes.Equal(payload.Data, data) {
+		t.Fatalf("expected full state %q\n\ngot: %q", string(payload.Data), string(data))
+	}
+
+	if err := state.Delete(true); err != nil {
+		t.Fatalf("delete: %s", err)
+	}
+
+	p, err := state.getStatePayload()
+	if err != nil {
+		t.Fatalf("get: %s", err)
+	}
+	if p != nil {
+		t.Fatalf("expected empty state, got: %q", string(p.Data))
+	}
+}
+
+func TestCloudLocks(t *testing.T) {
+	back, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	a, err := back.StateMgr(testBackendSingleWorkspaceName)
+	if err != nil {
+		t.Fatalf("expected no error, got %v", err)
+	}
+	b, err := back.StateMgr(testBackendSingleWorkspaceName)
+	if err != nil {
+		t.Fatalf("expected no error, got %v", err)
+	}
+
+	lockerA, ok := a.(statemgr.Locker)
+	if !ok {
+		t.Fatal("client A not a statemgr.Locker")
+	}
+
+	lockerB, ok := b.(statemgr.Locker)
+	if !ok {
+		t.Fatal("client B not a statemgr.Locker")
+	}
+
+	infoA := statemgr.NewLockInfo()
+	infoA.Operation = "test"
+	infoA.Who = "clientA"
+
+	infoB := statemgr.NewLockInfo()
+	infoB.Operation = "test"
+	infoB.Who = "clientB"
+
+	lockIDA, err := lockerA.Lock(infoA)
+	if err != nil {
+		t.Fatal("unable to get initial lock:", err)
+	}
+
+	_, err = lockerB.Lock(infoB)
+	if err == nil {
+		lockerA.Unlock(lockIDA)
+		t.Fatal("client B obtained lock while held by client A")
+	}
+	if _, ok := err.(*statemgr.LockError); !ok {
+		t.Errorf("expected a LockError, but was %t: %s", err, err)
+	}
+
+	if err := lockerA.Unlock(lockIDA); err != nil {
+		t.Fatal("error unlocking client A", err)
+	}
+
+	lockIDB, err := lockerB.Lock(infoB)
+	if err != nil {
+		t.Fatal("unable to obtain lock from client B")
+	}
+
+	if lockIDB == lockIDA {
+		t.Fatalf("duplicate lock IDs: %q", lockIDB)
+	}
+
+	if err = lockerB.Unlock(lockIDB); err != nil {
+		t.Fatal("error unlocking client B:", err)
+	}
+}
+
+func TestDelete_SafeDeleteNotSupported(t *testing.T) {
+	state := testCloudState(t)
+	workspaceId := state.workspace.ID
+	state.workspace.Permissions.CanForceDelete = nil
+	state.workspace.ResourceCount = 5
+
+	// Typically delete(false) should safe-delete a cloud workspace, which should fail on this workspace with resources
+	// However, since we have set the workspace canForceDelete permission to nil, we should fall back to force delete
+	if err := state.Delete(false); err != nil {
+		t.Fatalf("delete: %s", err)
+	}
+	workspace, err := state.tfeClient.Workspaces.ReadByID(context.Background(), workspaceId)
+	if workspace != nil || err != tfe.ErrResourceNotFound {
+		t.Fatalf("workspace %s not deleted", workspaceId)
+	}
+}
+
+func TestDelete_ForceDelete(t *testing.T) {
+	state := testCloudState(t)
+	workspaceId := state.workspace.ID
+	state.workspace.Permissions.CanForceDelete = tfe.Bool(true)
+	state.workspace.ResourceCount = 5
+
+	if err := state.Delete(true); err != nil {
+		t.Fatalf("delete: %s", err)
+	}
+	workspace, err := state.tfeClient.Workspaces.ReadByID(context.Background(), workspaceId)
+	if workspace != nil || err != tfe.ErrResourceNotFound {
+		t.Fatalf("workspace %s not deleted", workspaceId)
+	}
+}
+
+func TestDelete_SafeDelete(t *testing.T) {
+	state := testCloudState(t)
+	workspaceId := state.workspace.ID
+	state.workspace.Permissions.CanForceDelete = tfe.Bool(false)
+	state.workspace.ResourceCount = 5
+
+	// safe-deleting a workspace with resources should fail
+	err := state.Delete(false)
+	if err == nil {
+		t.Fatalf("workspace should have failed to safe delete")
+	}
+
+	// safe-deleting a workspace with resources should succeed once it has no resources
+	state.workspace.ResourceCount = 0
+	if err = state.Delete(false); err != nil {
+		t.Fatalf("workspace safe-delete err: %s", err)
+	}
+
+	workspace, err := state.tfeClient.Workspaces.ReadByID(context.Background(), workspaceId)
+	if workspace != nil || err != tfe.ErrResourceNotFound {
+		t.Fatalf("workspace %s not deleted", workspaceId)
+	}
+}
+
+func TestState_PersistState(t *testing.T) {
+	t.Run("Initial PersistState", func(t *testing.T) {
+		cloudState := testCloudState(t)
+
+		if cloudState.readState != nil {
+			t.Fatal("expected nil initial readState")
+		}
+
+		err := cloudState.PersistState(nil)
+		if err != nil {
+			t.Fatalf("expected no error, got %q", err)
+		}
+
+		var expectedSerial uint64 = 1
+		if cloudState.readSerial != expectedSerial {
+			t.Fatalf("expected initial state readSerial to be %d, got %d", expectedSerial, cloudState.readSerial)
+		}
+	})
+
+	t.Run("Snapshot Interval Backpressure Header", func(t *testing.T) {
+		// The "Create a State Version" API is allowed to return a special
+		// HTTP response header X-Terraform-Snapshot-Interval, in which case
+		// we should remember the number of seconds it specifies and delay
+		// creating any more intermediate state snapshots for that many seconds.
+
+		cloudState := testCloudState(t)
+
+		if cloudState.stateSnapshotInterval != 0 {
+			t.Error("state manager already has a nonzero snapshot interval")
+		}
+
+		// For this test we'll use a real client talking to a fake server,
+		// since HTTP-level concerns like headers are out of scope for the
+		// mock client we typically use in other tests in this package, which
+		// aim to abstract away HTTP altogether.
+		var serverURL string
+		server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+			t.Log(r.Method, r.URL.String())
+
+			if r.URL.Path == "/state-json" {
+				t.Log("pretending to be Archivist")
+				fakeState := states.NewState()
+				fakeStateFile := statefile.New(fakeState, "boop", 1)
+				var buf bytes.Buffer
+				statefile.Write(fakeStateFile, &buf)
+				respBody := buf.Bytes()
+				w.Header().Set("content-type", "application/json")
+				w.Header().Set("content-length", strconv.FormatInt(int64(len(respBody)), 10))
+				w.WriteHeader(http.StatusOK)
+				w.Write(respBody)
+				return
+			}
+			if r.URL.Path == "/api/ping" {
+				t.Log("pretending to be Ping")
+				w.WriteHeader(http.StatusNoContent)
+				return
+			}
+
+			fakeBody := map[string]any{
+				"data": map[string]any{
+					"type": "state-versions",
+					"attributes": map[string]any{
+						"hosted-state-download-url": serverURL + "/state-json",
+					},
+				},
+			}
+			fakeBodyRaw, err := json.Marshal(fakeBody)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			w.Header().Set("content-type", "application/json")
+			w.Header().Set("content-length", strconv.FormatInt(int64(len(fakeBodyRaw)), 10))
+
+			switch r.Method {
+			case "POST":
+				t.Log("pretending to be Create a State Version")
+				w.Header().Set("x-terraform-snapshot-interval", "300")
+				w.WriteHeader(http.StatusAccepted)
+			case "GET":
+				t.Log("pretending to be Fetch the Current State Version for a Workspace")
+				w.WriteHeader(http.StatusOK)
+			default:
+				t.Fatal("don't know what API operation this was supposed to be")
+			}
+
+			w.WriteHeader(http.StatusOK)
+			w.Write(fakeBodyRaw)
+		}))
+		defer server.Close()
+		serverURL = server.URL
+		cfg := &tfe.Config{
+			Address:  server.URL,
+			BasePath: "api",
+			Token:    "placeholder",
+		}
+		client, err := tfe.NewClient(cfg)
+		if err != nil {
+			t.Fatal(err)
+		}
+		cloudState.tfeClient = client
+
+		err = cloudState.RefreshState()
+		if err != nil {
+			t.Fatal(err)
+		}
+		cloudState.WriteState(states.BuildState(func(s *states.SyncState) {
+			s.SetOutputValue(
+				addrs.OutputValue{Name: "boop"}.Absolute(addrs.RootModuleInstance),
+				cty.StringVal("beep"), false,
+			)
+		}))
+
+		err = cloudState.PersistState(nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		// The PersistState call above should have sent a request to the test
+		// server and got back the x-terraform-snapshot-interval header, whose
+		// value should therefore now be recorded in the relevant field.
+		if got, want := cloudState.stateSnapshotInterval, 300*time.Second; got != want {
+			t.Errorf("wrong state snapshot interval after PersistState\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+}
+
+func TestState_ShouldPersistIntermediateState(t *testing.T) {
+	cloudState := testCloudState(t)
+
+	// We'll specify a normal interval and a server-supplied interval that
+	// have enough time between them that we can be confident that the
+	// fake timestamps we'll pass into ShouldPersistIntermediateState are
+	// either too soon for normal, long enough for normal but not for server,
+	// or too long for server.
+	shortServerInterval := 5 * time.Second
+	normalInterval := 60 * time.Second
+	longServerInterval := 120 * time.Second
+	beforeNormalInterval := 20 * time.Second
+	betweenInterval := 90 * time.Second
+	afterLongServerInterval := 200 * time.Second
+
+	// Before making any requests the state manager should just respect the
+	// normal interval, because it hasn't yet heard a request from the server.
+	{
+		should := cloudState.ShouldPersistIntermediateState(&local.IntermediateStatePersistInfo{
+			RequestedPersistInterval: normalInterval,
+			LastPersist:              time.Now().Add(-beforeNormalInterval),
+		})
+		if should {
+			t.Errorf("indicated that should persist before normal interval")
+		}
+	}
+	{
+		should := cloudState.ShouldPersistIntermediateState(&local.IntermediateStatePersistInfo{
+			RequestedPersistInterval: normalInterval,
+			LastPersist:              time.Now().Add(-betweenInterval),
+		})
+		if !should {
+			t.Errorf("indicated that should not persist after normal interval")
+		}
+	}
+
+	// After making a request to the "Create a State Version" operation, the
+	// server might return a header that causes us to set this field:
+	cloudState.stateSnapshotInterval = shortServerInterval
+
+	// The short server interval is shorter than the normal interval, so the
+	// normal interval takes priority here.
+	{
+		should := cloudState.ShouldPersistIntermediateState(&local.IntermediateStatePersistInfo{
+			RequestedPersistInterval: normalInterval,
+			LastPersist:              time.Now().Add(-beforeNormalInterval),
+		})
+		if should {
+			t.Errorf("indicated that should persist before normal interval")
+		}
+	}
+	{
+		should := cloudState.ShouldPersistIntermediateState(&local.IntermediateStatePersistInfo{
+			RequestedPersistInterval: normalInterval,
+			LastPersist:              time.Now().Add(-betweenInterval),
+		})
+		if !should {
+			t.Errorf("indicated that should not persist after normal interval")
+		}
+	}
+
+	// The server might instead request a longer interval.
+	cloudState.stateSnapshotInterval = longServerInterval
+	{
+		should := cloudState.ShouldPersistIntermediateState(&local.IntermediateStatePersistInfo{
+			RequestedPersistInterval: normalInterval,
+			LastPersist:              time.Now().Add(-beforeNormalInterval),
+		})
+		if should {
+			t.Errorf("indicated that should persist before server interval")
+		}
+	}
+	{
+		should := cloudState.ShouldPersistIntermediateState(&local.IntermediateStatePersistInfo{
+			RequestedPersistInterval: normalInterval,
+			LastPersist:              time.Now().Add(-betweenInterval),
+		})
+		if should {
+			t.Errorf("indicated that should persist before server interval")
+		}
+	}
+	{
+		should := cloudState.ShouldPersistIntermediateState(&local.IntermediateStatePersistInfo{
+			RequestedPersistInterval: normalInterval,
+			LastPersist:              time.Now().Add(-afterLongServerInterval),
+		})
+		if !should {
+			t.Errorf("indicated that should not persist after server interval")
+		}
+	}
+
+	// The "force" mode should always win, regardless of how much time has passed.
+	{
+		should := cloudState.ShouldPersistIntermediateState(&local.IntermediateStatePersistInfo{
+			RequestedPersistInterval: normalInterval,
+			LastPersist:              time.Now().Add(-beforeNormalInterval),
+			ForcePersist:             true,
+		})
+		if !should {
+			t.Errorf("ignored ForcePersist")
+		}
+	}
+	{
+		should := cloudState.ShouldPersistIntermediateState(&local.IntermediateStatePersistInfo{
+			RequestedPersistInterval: normalInterval,
+			LastPersist:              time.Now().Add(-betweenInterval),
+			ForcePersist:             true,
+		})
+		if !should {
+			t.Errorf("ignored ForcePersist")
+		}
+	}
+}
diff --git a/v1.5.7/internal/cloud/testdata/.gitignore b/v1.5.7/internal/cloud/testdata/.gitignore
new file mode 100644
index 0000000..15498bb
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/.gitignore
@@ -0,0 +1 @@
+!*.log
diff --git a/v1.5.7/internal/cloud/testdata/apply-destroy/apply.log b/v1.5.7/internal/cloud/testdata/apply-destroy/apply.log
new file mode 100644
index 0000000..d126547
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-destroy/apply.log
@@ -0,0 +1,7 @@
+Terraform v0.11.10
+
+Initializing plugins and modules...
+null_resource.hello: Destroying... (ID: 8657651096157629581)
+null_resource.hello: Destruction complete after 0s
+
+Apply complete! Resources: 0 added, 0 changed, 1 destroyed.
diff --git a/v1.5.7/internal/cloud/testdata/apply-destroy/main.tf b/v1.5.7/internal/cloud/testdata/apply-destroy/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-destroy/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/apply-destroy/plan.log b/v1.5.7/internal/cloud/testdata/apply-destroy/plan.log
new file mode 100644
index 0000000..1d38d41
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-destroy/plan.log
@@ -0,0 +1,22 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+null_resource.hello: Refreshing state... (ID: 8657651096157629581)
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  - destroy
+
+Terraform will perform the following actions:
+
+  - null_resource.hello
+
+
+Plan: 0 to add, 0 to change, 1 to destroy.
diff --git a/v1.5.7/internal/cloud/testdata/apply-json-with-error/main.tf b/v1.5.7/internal/cloud/testdata/apply-json-with-error/main.tf
new file mode 100644
index 0000000..6fa9534
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json-with-error/main.tf
@@ -0,0 +1,5 @@
+resource "null_resource" "foo" {
+  triggers = {
+    random = "${guid()}"
+  }
+}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json-with-error/plan-redacted.json b/v1.5.7/internal/cloud/testdata/apply-json-with-error/plan-redacted.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json-with-error/plan-redacted.json
@@ -0,0 +1 @@
+{}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json-with-error/plan.log b/v1.5.7/internal/cloud/testdata/apply-json-with-error/plan.log
new file mode 100644
index 0000000..b877f1e
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json-with-error/plan.log
@@ -0,0 +1,2 @@
+{"@level":"info","@message":"Terraform 1.3.7","@module":"terraform.ui","@timestamp":"2023-01-20T12:12:25.477403-05:00","terraform":"1.3.7","type":"version","ui":"1.0"}
+{"@level":"error","@message":"Error: Unsupported block type","@module":"terraform.ui","@timestamp":"2023-01-20T12:12:25.615995-05:00","diagnostic":{"severity":"error","summary":"Unsupported block type","detail":"Blocks of type \"triggers\" are not expected here. Did you mean to define argument \"triggers\"? If so, use the equals sign to assign it a value.","range":{"filename":"main.tf","start":{"line":2,"column":3,"byte":35},"end":{"line":2,"column":11,"byte":43}},"snippet":{"context":"resource \"null_resource\" \"foo\"","code":"  triggers {","start_line":2,"highlight_start_offset":2,"highlight_end_offset":10,"values":[]}},"type":"diagnostic"}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json-with-outputs/apply.log b/v1.5.7/internal/cloud/testdata/apply-json-with-outputs/apply.log
new file mode 100644
index 0000000..fe26806
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json-with-outputs/apply.log
@@ -0,0 +1,5 @@
+{"@level":"info","@message":"Terraform 1.3.7","@module":"terraform.ui","@timestamp":"2023-01-20T21:13:14.916732Z","terraform":"1.3.7","type":"version","ui":"1.0"}
+{"@level":"info","@message":"null_resource.foo: Creating...","@module":"terraform.ui","@timestamp":"2023-01-20T21:13:16.390332Z","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"create"},"type":"apply_start"}
+{"@level":"info","@message":"null_resource.foo: Creation complete after 0s [id=7091618264040236234]","@module":"terraform.ui","@timestamp":"2023-01-20T21:13:16.391654Z","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"create","id_key":"id","id_value":"7091618264040236234","elapsed_seconds":0},"type":"apply_complete"}
+{"@level":"info","@message":"Apply complete! Resources: 1 added, 0 changed, 0 destroyed.","@module":"terraform.ui","@timestamp":"2023-01-20T21:13:16.992073Z","changes":{"add":1,"change":0,"remove":0,"operation":"apply"},"type":"change_summary"}
+{"@level":"info","@message":"Outputs: 3","@module":"terraform.ui","@timestamp":"2023-01-20T21:13:16.992183Z","outputs":{"complex":{"sensitive":false,"type":["object",{"keyA":["object",{"someList":["tuple",["number","number","number"]]}],"keyB":["object",{"someBool":"bool","someStr":"string"}]}],"value":{"keyA":{"someList":[1,2,3]},"keyB":{"someBool":true,"someStr":"hello"}}},"secret":{"sensitive":true,"type":"string","value":"my-secret"},"simple":{"sensitive":false,"type":["tuple",["string","string"]],"value":["some","list"]}},"type":"outputs"}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json-with-outputs/main.tf b/v1.5.7/internal/cloud/testdata/apply-json-with-outputs/main.tf
new file mode 100644
index 0000000..d801668
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json-with-outputs/main.tf
@@ -0,0 +1,22 @@
+resource "null_resource" "foo" {}
+
+output "simple" {
+  value = ["some", "list"]
+}
+
+output "secret" {
+  value = "my-secret"
+  sensitive = true
+}
+
+output "complex" {
+  value = {
+    keyA = {
+      someList = [1, 2, 3]
+    }
+    keyB = {
+      someBool = true
+      someStr = "hello"
+    }
+  }
+}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json-with-outputs/plan-redacted.json b/v1.5.7/internal/cloud/testdata/apply-json-with-outputs/plan-redacted.json
new file mode 100644
index 0000000..c6ee277
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json-with-outputs/plan-redacted.json
@@ -0,0 +1 @@
+{"plan_format_version":"1.1","resource_drift":[],"resource_changes":[{"address":"null_resource.foo","mode":"managed","type":"null_resource","name":"foo","provider_name":"registry.terraform.io/hashicorp/null","change":{"actions":["create"],"before":null,"after":{"triggers":null},"after_unknown":{"id":true},"before_sensitive":false,"after_sensitive":{}}}],"relevant_attributes":[],"output_changes":{"complex":{"actions":["create"],"before":null,"after":{"keyA":{"someList":[1,2,3]},"keyB":{"someBool":true,"someStr":"hello"}},"after_unknown":false,"before_sensitive":false,"after_sensitive":false},"secret":{"actions":["create"],"before":null,"after":"8517896e47af3c9ca19a694ea0d6cc30b0dccf08598f33d93e583721fd5f3032","after_unknown":false,"before_sensitive":true,"after_sensitive":true},"simple":{"actions":["create"],"before":null,"after":["some","list"],"after_unknown":false,"before_sensitive":false,"after_sensitive":false}},"provider_schemas":{"registry.terraform.io/hashicorp/null":{"provider":{"version":0,"block":{"description_kind":"plain"}},"resource_schemas":{"null_resource":{"version":0,"block":{"attributes":{"id":{"type":"string","description":"This is set to a random value at create time.","description_kind":"plain","computed":true},"triggers":{"type":["map","string"],"description":"A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners.","description_kind":"plain","optional":true}},"description":"The `null_resource` resource implements the standard resource lifecycle but takes no further action.\n\nThe `triggers` argument allows specifying an arbitrary set of values that, when changed, will cause the resource to be replaced.","description_kind":"plain"}}},"data_source_schemas":{"null_data_source":{"version":0,"block":{"attributes":{"has_computed_default":{"type":"string","description":"If set, its literal value will be stored and returned. If not, its value defaults to `\"default\"`. This argument exists primarily for testing and has little practical use.","description_kind":"plain","optional":true,"computed":true},"id":{"type":"string","description":"This attribute is only present for some legacy compatibility issues and should not be used. It will be removed in a future version.","description_kind":"plain","deprecated":true,"computed":true},"inputs":{"type":["map","string"],"description":"A map of arbitrary strings that is copied into the `outputs` attribute, and accessible directly for interpolation.","description_kind":"plain","optional":true},"outputs":{"type":["map","string"],"description":"After the data source is \"read\", a copy of the `inputs` map.","description_kind":"plain","computed":true},"random":{"type":"string","description":"A random value. This is primarily for testing and has little practical use; prefer the [hashicorp/random provider](https://registry.terraform.io/providers/hashicorp/random) for more practical random number use-cases.","description_kind":"plain","computed":true}},"description":"The `null_data_source` data source implements the standard data source lifecycle but does not\ninteract with any external APIs.\n\nHistorically, the `null_data_source` was typically used to construct intermediate values to re-use elsewhere in configuration. The\nsame can now be achieved using [locals](https://www.terraform.io/docs/language/values/locals.html).\n","description_kind":"plain","deprecated":true}}}}},"provider_format_version":"1.0"}
\ No newline at end of file
diff --git a/v1.5.7/internal/cloud/testdata/apply-json-with-outputs/plan.log b/v1.5.7/internal/cloud/testdata/apply-json-with-outputs/plan.log
new file mode 100644
index 0000000..357586a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json-with-outputs/plan.log
@@ -0,0 +1,6 @@
+{"@level":"info","@message":"Terraform 1.3.7","@module":"terraform.ui","@timestamp":"2023-01-20T21:13:02.177699Z","terraform":"1.3.7","type":"version","ui":"1.0"}
+{"@level":"info","@message":"null_resource.foo: Plan to create","@module":"terraform.ui","@timestamp":"2023-01-20T21:13:03.842915Z","change":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"create"},"type":"planned_change"}
+{"@level":"info","@message":"Plan: 1 to add, 0 to change, 0 to destroy.","@module":"terraform.ui","@timestamp":"2023-01-20T21:13:03.842951Z","changes":{"add":1,"change":0,"remove":0,"operation":"plan"},"type":"change_summary"}
+{"@level":"info","@message":"Outputs: 3","@module":"terraform.ui","@timestamp":"2023-01-20T21:13:03.842965Z","outputs":{"complex":{"sensitive":false,"action":"create"},"secret":{"sensitive":true,"action":"create"},"simple":{"sensitive":false,"action":"create"}},"type":"outputs"}
+
+
diff --git a/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner-error/apply.log b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner-error/apply.log
new file mode 100644
index 0000000..64f949f
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner-error/apply.log
@@ -0,0 +1,9 @@
+{"@level":"info","@message":"Terraform 1.3.7","@module":"terraform.ui","@timestamp":"2023-01-20T15:50:04.623068-05:00","terraform":"1.3.7","type":"version","ui":"1.0"}
+{"@level":"info","@message":"null_resource.foo: Destroying... [id=5383176453498935794]","@module":"terraform.ui","@timestamp":"2023-02-16T10:13:14.725584-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"delete","id_key":"id","id_value":"5383176453498935794"},"type":"apply_start"}
+{"@level":"info","@message":"null_resource.foo: Destruction complete after 0s","@module":"terraform.ui","@timestamp":"2023-02-16T10:13:14.728526-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"delete","elapsed_seconds":0},"type":"apply_complete"}
+{"@level":"info","@message":"null_resource.foo: Creating...","@module":"terraform.ui","@timestamp":"2023-02-16T10:13:14.745016-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"create"},"type":"apply_start"}
+{"@level":"info","@message":"null_resource.foo: Provisioning with 'local-exec'...","@module":"terraform.ui","@timestamp":"2023-02-16T10:13:14.748796-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"provisioner":"local-exec"},"type":"provision_start"}
+{"@level":"info","@message":"null_resource.foo: (local-exec): Executing: [\"/bin/sh\" \"-c\" \"exit 125\"]","@module":"terraform.ui","@timestamp":"2023-02-16T10:13:14.749082-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"provisioner":"local-exec","output":"Executing: [\"/bin/sh\" \"-c\" \"exit 125\"]"},"type":"provision_progress"}
+{"@level":"info","@message":"null_resource.foo: (local-exec) Provisioning errored","@module":"terraform.ui","@timestamp":"2023-02-16T10:13:14.751770-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"provisioner":"local-exec"},"type":"provision_errored"}
+{"@level":"info","@message":"null_resource.foo: Creation errored after 0s","@module":"terraform.ui","@timestamp":"2023-02-16T10:13:14.752082-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"create","elapsed_seconds":0},"type":"apply_errored"}
+{"@level":"error","@message":"Error: local-exec provisioner error","@module":"terraform.ui","@timestamp":"2023-02-16T10:13:14.761681-05:00","diagnostic":{"severity":"error","summary":"local-exec provisioner error","detail":"Error running command 'exit 125': exit status 125. Output: ","address":"null_resource.foo","range":{"filename":"main.tf","start":{"line":2,"column":28,"byte":60},"end":{"line":2,"column":29,"byte":61}},"snippet":{"context":"resource \"null_resource\" \"foo\"","code":"  provisioner \"local-exec\" {","start_line":2,"highlight_start_offset":27,"highlight_end_offset":28,"values":[]}},"type":"diagnostic"}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner-error/main.tf b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner-error/main.tf
new file mode 100644
index 0000000..fb1ce03
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner-error/main.tf
@@ -0,0 +1,5 @@
+resource "null_resource" "foo" {
+  provisioner "local-exec" {
+    command = "exit 125"
+  }
+}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner-error/plan-redacted.json b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner-error/plan-redacted.json
new file mode 100644
index 0000000..9becf1b
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner-error/plan-redacted.json
@@ -0,0 +1,116 @@
+{
+  "plan_format_version": "1.1",
+  "resource_drift": [],
+  "resource_changes": [
+    {
+      "address": "null_resource.foo",
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "foo",
+      "provider_name": "registry.terraform.io/hashicorp/null",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "triggers": null
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    }
+  ],
+  "relevant_attributes": [],
+  "output_changes": {},
+  "provider_schemas": {
+    "registry.terraform.io/hashicorp/null": {
+      "provider": {
+        "version": 0,
+        "block": {
+          "description_kind": "plain"
+        }
+      },
+      "resource_schemas": {
+        "null_resource": {
+          "version": 0,
+          "block": {
+            "attributes": {
+              "id": {
+                "type": "string",
+                "description": "This is set to a random value at create time.",
+                "description_kind": "plain",
+                "computed": true
+              },
+              "triggers": {
+                "type": [
+                  "map",
+                  "string"
+                ],
+                "description": "A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners.",
+                "description_kind": "plain",
+                "optional": true
+              }
+            },
+            "description": "The `null_resource` resource implements the standard resource lifecycle but takes no further action.\n\nThe `triggers` argument allows specifying an arbitrary set of values that, when changed, will cause the resource to be replaced.",
+            "description_kind": "plain"
+          }
+        }
+      },
+      "data_source_schemas": {
+        "null_data_source": {
+          "version": 0,
+          "block": {
+            "attributes": {
+              "has_computed_default": {
+                "type": "string",
+                "description": "If set, its literal value will be stored and returned. If not, its value defaults to `\"default\"`. This argument exists primarily for testing and has little practical use.",
+                "description_kind": "plain",
+                "optional": true,
+                "computed": true
+              },
+              "id": {
+                "type": "string",
+                "description": "This attribute is only present for some legacy compatibility issues and should not be used. It will be removed in a future version.",
+                "description_kind": "plain",
+                "deprecated": true,
+                "computed": true
+              },
+              "inputs": {
+                "type": [
+                  "map",
+                  "string"
+                ],
+                "description": "A map of arbitrary strings that is copied into the `outputs` attribute, and accessible directly for interpolation.",
+                "description_kind": "plain",
+                "optional": true
+              },
+              "outputs": {
+                "type": [
+                  "map",
+                  "string"
+                ],
+                "description": "After the data source is \"read\", a copy of the `inputs` map.",
+                "description_kind": "plain",
+                "computed": true
+              },
+              "random": {
+                "type": "string",
+                "description": "A random value. This is primarily for testing and has little practical use; prefer the [hashicorp/random provider](https://registry.terraform.io/providers/hashicorp/random) for more practical random number use-cases.",
+                "description_kind": "plain",
+                "computed": true
+              }
+            },
+            "description": "The `null_data_source` data source implements the standard data source lifecycle but does not\ninteract with any external APIs.\n\nHistorically, the `null_data_source` was typically used to construct intermediate values to re-use elsewhere in configuration. The\nsame can now be achieved using [locals](https://www.terraform.io/docs/language/values/locals.html).\n",
+            "description_kind": "plain",
+            "deprecated": true
+          }
+        }
+      }
+    }
+  },
+  "provider_format_version": "1.0"
+}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner-error/plan.log b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner-error/plan.log
new file mode 100644
index 0000000..26d3921
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner-error/plan.log
@@ -0,0 +1,3 @@
+{"@level":"info","@message":"Terraform 1.3.7","@module":"terraform.ui","@timestamp":"2023-01-20T15:50:04.623068-05:00","terraform":"1.3.7","type":"version","ui":"1.0"}
+{"@level":"info","@message":"null_resource.foo: Plan to create","@module":"terraform.ui","@timestamp":"2023-01-20T15:50:04.822722-05:00","change":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"create"},"type":"planned_change"}
+{"@level":"info","@message":"Plan: 1 to add, 0 to change, 0 to destroy.","@module":"terraform.ui","@timestamp":"2023-01-20T15:50:04.822787-05:00","changes":{"add":1,"change":0,"remove":0,"operation":"plan"},"type":"change_summary"}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner/apply.log b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner/apply.log
new file mode 100644
index 0000000..78acd78
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner/apply.log
@@ -0,0 +1,10 @@
+{"@level":"info","@message":"null_resource.foo: Destroying... [id=102500065134967380]","@module":"terraform.ui","@timestamp":"2023-02-16T10:15:39.614616-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"delete","id_key":"id","id_value":"102500065134967380"},"type":"apply_start"}
+{"@level":"info","@message":"null_resource.foo: Destruction complete after 0s","@module":"terraform.ui","@timestamp":"2023-02-16T10:15:39.615777-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"delete","elapsed_seconds":0},"type":"apply_complete"}
+{"@level":"info","@message":"null_resource.foo: Creating...","@module":"terraform.ui","@timestamp":"2023-02-16T10:15:39.621975-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"create"},"type":"apply_start"}
+{"@level":"info","@message":"null_resource.foo: Provisioning with 'local-exec'...","@module":"terraform.ui","@timestamp":"2023-02-16T10:15:39.622630-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"provisioner":"local-exec"},"type":"provision_start"}
+{"@level":"info","@message":"null_resource.foo: (local-exec): Executing: [\"/bin/sh\" \"-c\" \"echo Hello World!\"]","@module":"terraform.ui","@timestamp":"2023-02-16T10:15:39.622702-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"provisioner":"local-exec","output":"Executing: [\"/bin/sh\" \"-c\" \"echo Hello World!\"]"},"type":"provision_progress"}
+{"@level":"info","@message":"null_resource.foo: (local-exec): Hello World!","@module":"terraform.ui","@timestamp":"2023-02-16T10:15:39.623236-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"provisioner":"local-exec","output":"Hello World!"},"type":"provision_progress"}
+{"@level":"info","@message":"null_resource.foo: (local-exec) Provisioning complete","@module":"terraform.ui","@timestamp":"2023-02-16T10:15:39.623275-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"provisioner":"local-exec"},"type":"provision_complete"}
+{"@level":"info","@message":"null_resource.foo: Creation complete after 0s [id=7836952171100801169]","@module":"terraform.ui","@timestamp":"2023-02-16T10:15:39.623320-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"create","id_key":"id","id_value":"7836952171100801169","elapsed_seconds":0},"type":"apply_complete"}
+{"@level":"info","@message":"Apply complete! Resources: 1 added, 0 changed, 1 destroyed.","@module":"terraform.ui","@timestamp":"2023-02-16T10:15:39.631098-05:00","changes":{"add":1,"change":0,"remove":1,"operation":"apply"},"type":"change_summary"}
+{"@level":"info","@message":"Outputs: 0","@module":"terraform.ui","@timestamp":"2023-02-16T10:15:39.631112-05:00","outputs":{},"type":"outputs"}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner/main.tf b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner/main.tf
new file mode 100644
index 0000000..20bf745
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner/main.tf
@@ -0,0 +1,5 @@
+resource "null_resource" "foo" {
+  provisioner "local-exec" {
+    command = "echo Hello World!"
+  }
+}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner/plan-redacted.json b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner/plan-redacted.json
new file mode 100644
index 0000000..9becf1b
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner/plan-redacted.json
@@ -0,0 +1,116 @@
+{
+  "plan_format_version": "1.1",
+  "resource_drift": [],
+  "resource_changes": [
+    {
+      "address": "null_resource.foo",
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "foo",
+      "provider_name": "registry.terraform.io/hashicorp/null",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "triggers": null
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    }
+  ],
+  "relevant_attributes": [],
+  "output_changes": {},
+  "provider_schemas": {
+    "registry.terraform.io/hashicorp/null": {
+      "provider": {
+        "version": 0,
+        "block": {
+          "description_kind": "plain"
+        }
+      },
+      "resource_schemas": {
+        "null_resource": {
+          "version": 0,
+          "block": {
+            "attributes": {
+              "id": {
+                "type": "string",
+                "description": "This is set to a random value at create time.",
+                "description_kind": "plain",
+                "computed": true
+              },
+              "triggers": {
+                "type": [
+                  "map",
+                  "string"
+                ],
+                "description": "A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners.",
+                "description_kind": "plain",
+                "optional": true
+              }
+            },
+            "description": "The `null_resource` resource implements the standard resource lifecycle but takes no further action.\n\nThe `triggers` argument allows specifying an arbitrary set of values that, when changed, will cause the resource to be replaced.",
+            "description_kind": "plain"
+          }
+        }
+      },
+      "data_source_schemas": {
+        "null_data_source": {
+          "version": 0,
+          "block": {
+            "attributes": {
+              "has_computed_default": {
+                "type": "string",
+                "description": "If set, its literal value will be stored and returned. If not, its value defaults to `\"default\"`. This argument exists primarily for testing and has little practical use.",
+                "description_kind": "plain",
+                "optional": true,
+                "computed": true
+              },
+              "id": {
+                "type": "string",
+                "description": "This attribute is only present for some legacy compatibility issues and should not be used. It will be removed in a future version.",
+                "description_kind": "plain",
+                "deprecated": true,
+                "computed": true
+              },
+              "inputs": {
+                "type": [
+                  "map",
+                  "string"
+                ],
+                "description": "A map of arbitrary strings that is copied into the `outputs` attribute, and accessible directly for interpolation.",
+                "description_kind": "plain",
+                "optional": true
+              },
+              "outputs": {
+                "type": [
+                  "map",
+                  "string"
+                ],
+                "description": "After the data source is \"read\", a copy of the `inputs` map.",
+                "description_kind": "plain",
+                "computed": true
+              },
+              "random": {
+                "type": "string",
+                "description": "A random value. This is primarily for testing and has little practical use; prefer the [hashicorp/random provider](https://registry.terraform.io/providers/hashicorp/random) for more practical random number use-cases.",
+                "description_kind": "plain",
+                "computed": true
+              }
+            },
+            "description": "The `null_data_source` data source implements the standard data source lifecycle but does not\ninteract with any external APIs.\n\nHistorically, the `null_data_source` was typically used to construct intermediate values to re-use elsewhere in configuration. The\nsame can now be achieved using [locals](https://www.terraform.io/docs/language/values/locals.html).\n",
+            "description_kind": "plain",
+            "deprecated": true
+          }
+        }
+      }
+    }
+  },
+  "provider_format_version": "1.0"
+}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner/plan.log b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner/plan.log
new file mode 100644
index 0000000..26d3921
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json-with-provisioner/plan.log
@@ -0,0 +1,3 @@
+{"@level":"info","@message":"Terraform 1.3.7","@module":"terraform.ui","@timestamp":"2023-01-20T15:50:04.623068-05:00","terraform":"1.3.7","type":"version","ui":"1.0"}
+{"@level":"info","@message":"null_resource.foo: Plan to create","@module":"terraform.ui","@timestamp":"2023-01-20T15:50:04.822722-05:00","change":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"create"},"type":"planned_change"}
+{"@level":"info","@message":"Plan: 1 to add, 0 to change, 0 to destroy.","@module":"terraform.ui","@timestamp":"2023-01-20T15:50:04.822787-05:00","changes":{"add":1,"change":0,"remove":0,"operation":"plan"},"type":"change_summary"}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json/apply.log b/v1.5.7/internal/cloud/testdata/apply-json/apply.log
new file mode 100644
index 0000000..1238b4c
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json/apply.log
@@ -0,0 +1,5 @@
+{"@level":"info","@message":"Terraform 1.3.7","@module":"terraform.ui","@timestamp":"2023-01-20T15:50:04.623068-05:00","terraform":"1.3.7","type":"version","ui":"1.0"}
+{"@level":"info","@message":"null_resource.foo: Creating...","@module":"terraform.ui","@timestamp":"2023-01-20T15:50:04.874882-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"create"},"type":"apply_start"}
+{"@level":"info","@message":"null_resource.foo: Creation complete after 0s [id=3573948886993018026]","@module":"terraform.ui","@timestamp":"2023-01-20T15:50:04.878389-05:00","hook":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"create","id_key":"id","id_value":"3573948886993018026","elapsed_seconds":0},"type":"apply_complete"}
+{"@level":"info","@message":"Apply complete! Resources: 1 added, 0 changed, 0 destroyed.","@module":"terraform.ui","@timestamp":"2023-01-20T15:50:04.887223-05:00","changes":{"add":1,"change":0,"remove":0,"operation":"apply"},"type":"change_summary"}
+{"@level":"info","@message":"Outputs: 0","@module":"terraform.ui","@timestamp":"2023-01-20T15:50:04.887259-05:00","outputs":{},"type":"outputs"}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json/main.tf b/v1.5.7/internal/cloud/testdata/apply-json/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json/plan-redacted.json b/v1.5.7/internal/cloud/testdata/apply-json/plan-redacted.json
new file mode 100644
index 0000000..9becf1b
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json/plan-redacted.json
@@ -0,0 +1,116 @@
+{
+  "plan_format_version": "1.1",
+  "resource_drift": [],
+  "resource_changes": [
+    {
+      "address": "null_resource.foo",
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "foo",
+      "provider_name": "registry.terraform.io/hashicorp/null",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "triggers": null
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    }
+  ],
+  "relevant_attributes": [],
+  "output_changes": {},
+  "provider_schemas": {
+    "registry.terraform.io/hashicorp/null": {
+      "provider": {
+        "version": 0,
+        "block": {
+          "description_kind": "plain"
+        }
+      },
+      "resource_schemas": {
+        "null_resource": {
+          "version": 0,
+          "block": {
+            "attributes": {
+              "id": {
+                "type": "string",
+                "description": "This is set to a random value at create time.",
+                "description_kind": "plain",
+                "computed": true
+              },
+              "triggers": {
+                "type": [
+                  "map",
+                  "string"
+                ],
+                "description": "A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners.",
+                "description_kind": "plain",
+                "optional": true
+              }
+            },
+            "description": "The `null_resource` resource implements the standard resource lifecycle but takes no further action.\n\nThe `triggers` argument allows specifying an arbitrary set of values that, when changed, will cause the resource to be replaced.",
+            "description_kind": "plain"
+          }
+        }
+      },
+      "data_source_schemas": {
+        "null_data_source": {
+          "version": 0,
+          "block": {
+            "attributes": {
+              "has_computed_default": {
+                "type": "string",
+                "description": "If set, its literal value will be stored and returned. If not, its value defaults to `\"default\"`. This argument exists primarily for testing and has little practical use.",
+                "description_kind": "plain",
+                "optional": true,
+                "computed": true
+              },
+              "id": {
+                "type": "string",
+                "description": "This attribute is only present for some legacy compatibility issues and should not be used. It will be removed in a future version.",
+                "description_kind": "plain",
+                "deprecated": true,
+                "computed": true
+              },
+              "inputs": {
+                "type": [
+                  "map",
+                  "string"
+                ],
+                "description": "A map of arbitrary strings that is copied into the `outputs` attribute, and accessible directly for interpolation.",
+                "description_kind": "plain",
+                "optional": true
+              },
+              "outputs": {
+                "type": [
+                  "map",
+                  "string"
+                ],
+                "description": "After the data source is \"read\", a copy of the `inputs` map.",
+                "description_kind": "plain",
+                "computed": true
+              },
+              "random": {
+                "type": "string",
+                "description": "A random value. This is primarily for testing and has little practical use; prefer the [hashicorp/random provider](https://registry.terraform.io/providers/hashicorp/random) for more practical random number use-cases.",
+                "description_kind": "plain",
+                "computed": true
+              }
+            },
+            "description": "The `null_data_source` data source implements the standard data source lifecycle but does not\ninteract with any external APIs.\n\nHistorically, the `null_data_source` was typically used to construct intermediate values to re-use elsewhere in configuration. The\nsame can now be achieved using [locals](https://www.terraform.io/docs/language/values/locals.html).\n",
+            "description_kind": "plain",
+            "deprecated": true
+          }
+        }
+      }
+    }
+  },
+  "provider_format_version": "1.0"
+}
diff --git a/v1.5.7/internal/cloud/testdata/apply-json/plan.log b/v1.5.7/internal/cloud/testdata/apply-json/plan.log
new file mode 100644
index 0000000..3ac5e43
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-json/plan.log
@@ -0,0 +1,4 @@
+{"@level":"info","@message":"Terraform 1.3.7","@module":"terraform.ui","@timestamp":"2023-01-20T15:50:04.623068-05:00","terraform":"1.3.7","type":"version","ui":"1.0"}
+{"@level":"info","@message":"null_resource.foo: Plan to create","@module":"terraform.ui","@timestamp":"2023-01-20T15:50:04.822722-05:00","change":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"create"},"type":"planned_change"}
+{"@level":"info","@message":"Plan: 1 to add, 0 to change, 0 to destroy.","@module":"terraform.ui","@timestamp":"2023-01-20T15:50:04.822787-05:00","changes":{"add":1,"change":0,"remove":0,"operation":"plan"},"type":"change_summary"}
+
diff --git a/v1.5.7/internal/cloud/testdata/apply-no-changes/main.tf b/v1.5.7/internal/cloud/testdata/apply-no-changes/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-no-changes/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/apply-no-changes/plan.log b/v1.5.7/internal/cloud/testdata/apply-no-changes/plan.log
new file mode 100644
index 0000000..7041681
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-no-changes/plan.log
@@ -0,0 +1,17 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+null_resource.hello: Refreshing state... (ID: 8657651096157629581)
+
+------------------------------------------------------------------------
+
+No changes. Infrastructure is up-to-date.
+
+This means that Terraform did not detect any differences between your
+configuration and real physical resources that exist. As a result, no
+actions need to be performed.
diff --git a/v1.5.7/internal/cloud/testdata/apply-no-changes/policy.log b/v1.5.7/internal/cloud/testdata/apply-no-changes/policy.log
new file mode 100644
index 0000000..b0cb1e5
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-no-changes/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: true
+
+This result means that Sentinel policies returned true and the protected
+behavior is allowed by Sentinel policies.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (soft-mandatory)
+
+Result: true
+
+TRUE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/cloud/testdata/apply-policy-hard-failed/main.tf b/v1.5.7/internal/cloud/testdata/apply-policy-hard-failed/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-policy-hard-failed/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/apply-policy-hard-failed/plan.log b/v1.5.7/internal/cloud/testdata/apply-policy-hard-failed/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-policy-hard-failed/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/cloud/testdata/apply-policy-hard-failed/policy.log b/v1.5.7/internal/cloud/testdata/apply-policy-hard-failed/policy.log
new file mode 100644
index 0000000..5d6e693
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-policy-hard-failed/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: false
+
+Sentinel evaluated to false because one or more Sentinel policies evaluated
+to false. This false was not due to an undefined value or runtime error.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (hard-mandatory)
+
+Result: false
+
+FALSE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/cloud/testdata/apply-policy-passed/apply.log b/v1.5.7/internal/cloud/testdata/apply-policy-passed/apply.log
new file mode 100644
index 0000000..9019948
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-policy-passed/apply.log
@@ -0,0 +1,7 @@
+Terraform v0.11.10
+
+Initializing plugins and modules...
+null_resource.hello: Creating...
+null_resource.hello: Creation complete after 0s (ID: 8657651096157629581)
+
+Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
diff --git a/v1.5.7/internal/cloud/testdata/apply-policy-passed/main.tf b/v1.5.7/internal/cloud/testdata/apply-policy-passed/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-policy-passed/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/apply-policy-passed/plan.log b/v1.5.7/internal/cloud/testdata/apply-policy-passed/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-policy-passed/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/cloud/testdata/apply-policy-passed/policy.log b/v1.5.7/internal/cloud/testdata/apply-policy-passed/policy.log
new file mode 100644
index 0000000..b0cb1e5
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-policy-passed/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: true
+
+This result means that Sentinel policies returned true and the protected
+behavior is allowed by Sentinel policies.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (soft-mandatory)
+
+Result: true
+
+TRUE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/cloud/testdata/apply-policy-soft-failed/apply.log b/v1.5.7/internal/cloud/testdata/apply-policy-soft-failed/apply.log
new file mode 100644
index 0000000..9019948
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-policy-soft-failed/apply.log
@@ -0,0 +1,7 @@
+Terraform v0.11.10
+
+Initializing plugins and modules...
+null_resource.hello: Creating...
+null_resource.hello: Creation complete after 0s (ID: 8657651096157629581)
+
+Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
diff --git a/v1.5.7/internal/cloud/testdata/apply-policy-soft-failed/main.tf b/v1.5.7/internal/cloud/testdata/apply-policy-soft-failed/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-policy-soft-failed/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/apply-policy-soft-failed/plan.log b/v1.5.7/internal/cloud/testdata/apply-policy-soft-failed/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-policy-soft-failed/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/cloud/testdata/apply-policy-soft-failed/policy.log b/v1.5.7/internal/cloud/testdata/apply-policy-soft-failed/policy.log
new file mode 100644
index 0000000..3e4ebed
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-policy-soft-failed/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: false
+
+Sentinel evaluated to false because one or more Sentinel policies evaluated
+to false. This false was not due to an undefined value or runtime error.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (soft-mandatory)
+
+Result: false
+
+FALSE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/cloud/testdata/apply-variables/apply.log b/v1.5.7/internal/cloud/testdata/apply-variables/apply.log
new file mode 100644
index 0000000..9019948
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-variables/apply.log
@@ -0,0 +1,7 @@
+Terraform v0.11.10
+
+Initializing plugins and modules...
+null_resource.hello: Creating...
+null_resource.hello: Creation complete after 0s (ID: 8657651096157629581)
+
+Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
diff --git a/v1.5.7/internal/cloud/testdata/apply-variables/main.tf b/v1.5.7/internal/cloud/testdata/apply-variables/main.tf
new file mode 100644
index 0000000..955e8b4
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-variables/main.tf
@@ -0,0 +1,4 @@
+variable "foo" {}
+variable "bar" {}
+
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/apply-variables/plan.log b/v1.5.7/internal/cloud/testdata/apply-variables/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-variables/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/cloud/testdata/apply-with-error/main.tf b/v1.5.7/internal/cloud/testdata/apply-with-error/main.tf
new file mode 100644
index 0000000..bc45f28
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-with-error/main.tf
@@ -0,0 +1,5 @@
+resource "null_resource" "foo" {
+  triggers {
+    random = "${guid()}"
+  }
+}
diff --git a/v1.5.7/internal/cloud/testdata/apply-with-error/plan.log b/v1.5.7/internal/cloud/testdata/apply-with-error/plan.log
new file mode 100644
index 0000000..4344a37
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply-with-error/plan.log
@@ -0,0 +1,10 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+
+Error: null_resource.foo: 1 error(s) occurred:
+
+* null_resource.foo: 1:3: unknown function called: guid in:
+
+${guid()}
diff --git a/v1.5.7/internal/cloud/testdata/apply/apply.log b/v1.5.7/internal/cloud/testdata/apply/apply.log
new file mode 100644
index 0000000..9019948
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply/apply.log
@@ -0,0 +1,7 @@
+Terraform v0.11.10
+
+Initializing plugins and modules...
+null_resource.hello: Creating...
+null_resource.hello: Creation complete after 0s (ID: 8657651096157629581)
+
+Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
diff --git a/v1.5.7/internal/cloud/testdata/apply/main.tf b/v1.5.7/internal/cloud/testdata/apply/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/apply/plan.log b/v1.5.7/internal/cloud/testdata/apply/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/apply/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/cloud/testdata/empty/.gitignore b/v1.5.7/internal/cloud/testdata/empty/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/empty/.gitignore
diff --git a/v1.5.7/internal/cloud/testdata/plan-cost-estimation/ce.log b/v1.5.7/internal/cloud/testdata/plan-cost-estimation/ce.log
new file mode 100644
index 0000000..e51fef1
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-cost-estimation/ce.log
@@ -0,0 +1,6 @@
++---------+------+-----+-------------+----------------------+
+| PRODUCT | NAME | SKU | DESCRIPTION |        DELTA         |
++---------+------+-----+-------------+----------------------+
++---------+------+-----+-------------+----------------------+
+|                           TOTAL    | $0.000 USD / 720 HRS |
++---------+------+-----+-------------+----------------------+
diff --git a/v1.5.7/internal/cloud/testdata/plan-cost-estimation/cost-estimate.log b/v1.5.7/internal/cloud/testdata/plan-cost-estimation/cost-estimate.log
new file mode 100644
index 0000000..67a5092
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-cost-estimation/cost-estimate.log
@@ -0,0 +1,5 @@
+Cost estimation:
+
+Waiting for cost estimation to complete...
+Resources: 1 of 1 estimated
+           $25.488/mo +$25.488
\ No newline at end of file
diff --git a/v1.5.7/internal/cloud/testdata/plan-cost-estimation/main.tf b/v1.5.7/internal/cloud/testdata/plan-cost-estimation/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-cost-estimation/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/plan-cost-estimation/plan.log b/v1.5.7/internal/cloud/testdata/plan-cost-estimation/plan.log
new file mode 100644
index 0000000..fae287f
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-cost-estimation/plan.log
@@ -0,0 +1,20 @@
+Terraform v0.12.9
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/cloud/testdata/plan-import-config-gen-exists/generated.tf b/v1.5.7/internal/cloud/testdata/plan-import-config-gen-exists/generated.tf
new file mode 100644
index 0000000..1efdb23
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-import-config-gen-exists/generated.tf
@@ -0,0 +1,8 @@
+# __generated__ by Terraform
+# Please review these resources and move them into your main configuration files.
+
+# __generated__ by Terraform from "bar"
+resource "terraform_data" "foo" {
+  input            = null
+  triggers_replace = null
+}
diff --git a/v1.5.7/internal/cloud/testdata/plan-import-config-gen-exists/main.tf b/v1.5.7/internal/cloud/testdata/plan-import-config-gen-exists/main.tf
new file mode 100644
index 0000000..8257ac5
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-import-config-gen-exists/main.tf
@@ -0,0 +1,4 @@
+import {
+  id = "bar"
+  to = terraform_data.foo
+}
diff --git a/v1.5.7/internal/cloud/testdata/plan-import-config-gen-validation-error/generated.tf.expected b/v1.5.7/internal/cloud/testdata/plan-import-config-gen-validation-error/generated.tf.expected
new file mode 100644
index 0000000..1efdb23
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-import-config-gen-validation-error/generated.tf.expected
@@ -0,0 +1,8 @@
+# __generated__ by Terraform
+# Please review these resources and move them into your main configuration files.
+
+# __generated__ by Terraform from "bar"
+resource "terraform_data" "foo" {
+  input            = null
+  triggers_replace = null
+}
diff --git a/v1.5.7/internal/cloud/testdata/plan-import-config-gen-validation-error/main.tf b/v1.5.7/internal/cloud/testdata/plan-import-config-gen-validation-error/main.tf
new file mode 100644
index 0000000..8257ac5
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-import-config-gen-validation-error/main.tf
@@ -0,0 +1,4 @@
+import {
+  id = "bar"
+  to = terraform_data.foo
+}
diff --git a/v1.5.7/internal/cloud/testdata/plan-import-config-gen-validation-error/plan-redacted.json b/v1.5.7/internal/cloud/testdata/plan-import-config-gen-validation-error/plan-redacted.json
new file mode 100644
index 0000000..9e24e22
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-import-config-gen-validation-error/plan-redacted.json
@@ -0,0 +1,127 @@
+{
+  "format_version": "1.2",
+  "terraform_version": "1.5.0",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "terraform_data.foo",
+          "mode": "managed",
+          "type": "terraform_data",
+          "name": "foo",
+          "provider_name": "terraform.io/builtin/terraform",
+          "schema_version": 0,
+          "values": {
+            "id": "bar",
+            "input": null,
+            "output": null,
+            "triggers_replace": null
+          },
+          "sensitive_values": {}
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "terraform_data.foo",
+      "mode": "managed",
+      "type": "terraform_data",
+      "name": "foo",
+      "provider_name": "terraform.io/builtin/terraform",
+      "change": {
+        "actions": [
+          "no-op"
+        ],
+        "before": {
+          "id": "bar",
+          "input": null,
+          "output": null,
+          "triggers_replace": null
+        },
+        "after": {
+          "id": "bar",
+          "input": null,
+          "output": null,
+          "triggers_replace": null
+        },
+        "after_unknown": {},
+        "before_sensitive": {},
+        "after_sensitive": {},
+        "importing": {
+          "id": "bar"
+        },
+        "generated_config": "resource \"terraform_data\" \"foo\" {\n  input            = null\n  triggers_replace = null\n}"
+      }
+    }
+  ],
+  "prior_state": {
+    "format_version": "1.0",
+    "terraform_version": "1.6.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "terraform_data.foo",
+            "mode": "managed",
+            "type": "terraform_data",
+            "name": "foo",
+            "provider_name": "terraform.io/builtin/terraform",
+            "schema_version": 0,
+            "values": {
+              "id": "bar",
+              "input": null,
+              "output": null,
+              "triggers_replace": null
+            },
+            "sensitive_values": {}
+          }
+        ]
+      }
+    }
+  },
+  "configuration": {
+    "provider_config": {
+      "terraform": {
+        "name": "terraform",
+        "full_name": "terraform.io/builtin/terraform"
+      }
+    },
+    "root_module": {}
+  },
+  "provider_schemas": {
+    "terraform.io/builtin/terraform": {
+      "resource_schemas": {
+        "terraform_data": {
+          "version": 0,
+          "block": {
+            "attributes": {
+              "id": {
+                "type": "string",
+                "description_kind": "plain",
+                "computed": true
+              },
+              "input": {
+                "type": "dynamic",
+                "description_kind": "plain",
+                "optional": true
+              },
+              "output": {
+                "type": "dynamic",
+                "description_kind": "plain",
+                "computed": true
+              },
+              "triggers_replace": {
+                "type": "dynamic",
+                "description_kind": "plain",
+                "optional": true
+              }
+            },
+            "description_kind": "plain"
+          }
+        }
+      }
+    }
+  },
+  "timestamp": "2023-05-30T03:34:55Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/cloud/testdata/plan-import-config-gen-validation-error/plan.log b/v1.5.7/internal/cloud/testdata/plan-import-config-gen-validation-error/plan.log
new file mode 100644
index 0000000..192b2b8
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-import-config-gen-validation-error/plan.log
@@ -0,0 +1,3 @@
+{"@level":"info","@message":"Terraform 1.5.0","@module":"terraform.ui","@timestamp":"2023-05-29T21:30:07.206963-07:00","terraform":"1.5.0","type":"version","ui":"1.1"}
+{"@level":"info","@message":"Plan: 0 to add, 0 to change, 0 to destroy.","@module":"terraform.ui","@timestamp":"2023-05-29T21:30:08.302799-07:00","changes":{"add":0,"change":0,"import":0,"remove":0,"operation":"plan"},"type":"change_summary"}
+{"@level":"error","@message":"Error: Conflicting configuration arguments","@module":"terraform.ui","@timestamp":"2023-05-29T21:30:08.302847-07:00","diagnostic":{"severity":"error","summary":"Conflicting configuration arguments","detail":"Not allowed","address":"terraform_data.foo","range":{"filename":"generated.tf","start":{"line":22,"column":33,"byte":867},"end":{"line":22,"column":35,"byte":869}}},"type":"diagnostic"}
\ No newline at end of file
diff --git a/v1.5.7/internal/cloud/testdata/plan-import-config-gen/generated.tf.expected b/v1.5.7/internal/cloud/testdata/plan-import-config-gen/generated.tf.expected
new file mode 100644
index 0000000..1efdb23
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-import-config-gen/generated.tf.expected
@@ -0,0 +1,8 @@
+# __generated__ by Terraform
+# Please review these resources and move them into your main configuration files.
+
+# __generated__ by Terraform from "bar"
+resource "terraform_data" "foo" {
+  input            = null
+  triggers_replace = null
+}
diff --git a/v1.5.7/internal/cloud/testdata/plan-import-config-gen/main.tf b/v1.5.7/internal/cloud/testdata/plan-import-config-gen/main.tf
new file mode 100644
index 0000000..8257ac5
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-import-config-gen/main.tf
@@ -0,0 +1,4 @@
+import {
+  id = "bar"
+  to = terraform_data.foo
+}
diff --git a/v1.5.7/internal/cloud/testdata/plan-import-config-gen/plan-redacted.json b/v1.5.7/internal/cloud/testdata/plan-import-config-gen/plan-redacted.json
new file mode 100644
index 0000000..9e24e22
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-import-config-gen/plan-redacted.json
@@ -0,0 +1,127 @@
+{
+  "format_version": "1.2",
+  "terraform_version": "1.5.0",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "terraform_data.foo",
+          "mode": "managed",
+          "type": "terraform_data",
+          "name": "foo",
+          "provider_name": "terraform.io/builtin/terraform",
+          "schema_version": 0,
+          "values": {
+            "id": "bar",
+            "input": null,
+            "output": null,
+            "triggers_replace": null
+          },
+          "sensitive_values": {}
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "terraform_data.foo",
+      "mode": "managed",
+      "type": "terraform_data",
+      "name": "foo",
+      "provider_name": "terraform.io/builtin/terraform",
+      "change": {
+        "actions": [
+          "no-op"
+        ],
+        "before": {
+          "id": "bar",
+          "input": null,
+          "output": null,
+          "triggers_replace": null
+        },
+        "after": {
+          "id": "bar",
+          "input": null,
+          "output": null,
+          "triggers_replace": null
+        },
+        "after_unknown": {},
+        "before_sensitive": {},
+        "after_sensitive": {},
+        "importing": {
+          "id": "bar"
+        },
+        "generated_config": "resource \"terraform_data\" \"foo\" {\n  input            = null\n  triggers_replace = null\n}"
+      }
+    }
+  ],
+  "prior_state": {
+    "format_version": "1.0",
+    "terraform_version": "1.6.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "terraform_data.foo",
+            "mode": "managed",
+            "type": "terraform_data",
+            "name": "foo",
+            "provider_name": "terraform.io/builtin/terraform",
+            "schema_version": 0,
+            "values": {
+              "id": "bar",
+              "input": null,
+              "output": null,
+              "triggers_replace": null
+            },
+            "sensitive_values": {}
+          }
+        ]
+      }
+    }
+  },
+  "configuration": {
+    "provider_config": {
+      "terraform": {
+        "name": "terraform",
+        "full_name": "terraform.io/builtin/terraform"
+      }
+    },
+    "root_module": {}
+  },
+  "provider_schemas": {
+    "terraform.io/builtin/terraform": {
+      "resource_schemas": {
+        "terraform_data": {
+          "version": 0,
+          "block": {
+            "attributes": {
+              "id": {
+                "type": "string",
+                "description_kind": "plain",
+                "computed": true
+              },
+              "input": {
+                "type": "dynamic",
+                "description_kind": "plain",
+                "optional": true
+              },
+              "output": {
+                "type": "dynamic",
+                "description_kind": "plain",
+                "computed": true
+              },
+              "triggers_replace": {
+                "type": "dynamic",
+                "description_kind": "plain",
+                "optional": true
+              }
+            },
+            "description_kind": "plain"
+          }
+        }
+      }
+    }
+  },
+  "timestamp": "2023-05-30T03:34:55Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/cloud/testdata/plan-import-config-gen/plan.log b/v1.5.7/internal/cloud/testdata/plan-import-config-gen/plan.log
new file mode 100644
index 0000000..2771305
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-import-config-gen/plan.log
@@ -0,0 +1,3 @@
+{"@level":"info","@message":"Terraform 1.5.0","@module":"terraform.ui","@timestamp":"2023-05-29T20:30:14.113797-07:00","terraform":"1.5.0","type":"version","ui":"1.1"}
+{"@level":"info","@message":"terraform_data.foo: Plan to import","@module":"terraform.ui","@timestamp":"2023-05-29T20:30:14.130354-07:00","change":{"resource":{"addr":"terraform_data.foo","module":"","resource":"terraform_data.foo","implied_provider":"terraform","resource_type":"terraform_data","resource_name":"foo","resource_key":null},"action":"import","importing":{"id":"bar"},"generated_config":"resource \"terraform_data\" \"foo\" {\n  input            = null\n  triggers_replace = null\n}"},"type":"planned_change"}
+{"@level":"info","@message":"Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.","@module":"terraform.ui","@timestamp":"2023-05-29T20:30:14.130392-07:00","changes":{"add":0,"change":0,"import":1,"remove":0,"operation":"plan"},"type":"change_summary"}
\ No newline at end of file
diff --git a/v1.5.7/internal/cloud/testdata/plan-json-basic/main.tf b/v1.5.7/internal/cloud/testdata/plan-json-basic/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-json-basic/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/plan-json-basic/plan-redacted.json b/v1.5.7/internal/cloud/testdata/plan-json-basic/plan-redacted.json
new file mode 100644
index 0000000..9becf1b
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-json-basic/plan-redacted.json
@@ -0,0 +1,116 @@
+{
+  "plan_format_version": "1.1",
+  "resource_drift": [],
+  "resource_changes": [
+    {
+      "address": "null_resource.foo",
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "foo",
+      "provider_name": "registry.terraform.io/hashicorp/null",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "triggers": null
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    }
+  ],
+  "relevant_attributes": [],
+  "output_changes": {},
+  "provider_schemas": {
+    "registry.terraform.io/hashicorp/null": {
+      "provider": {
+        "version": 0,
+        "block": {
+          "description_kind": "plain"
+        }
+      },
+      "resource_schemas": {
+        "null_resource": {
+          "version": 0,
+          "block": {
+            "attributes": {
+              "id": {
+                "type": "string",
+                "description": "This is set to a random value at create time.",
+                "description_kind": "plain",
+                "computed": true
+              },
+              "triggers": {
+                "type": [
+                  "map",
+                  "string"
+                ],
+                "description": "A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners.",
+                "description_kind": "plain",
+                "optional": true
+              }
+            },
+            "description": "The `null_resource` resource implements the standard resource lifecycle but takes no further action.\n\nThe `triggers` argument allows specifying an arbitrary set of values that, when changed, will cause the resource to be replaced.",
+            "description_kind": "plain"
+          }
+        }
+      },
+      "data_source_schemas": {
+        "null_data_source": {
+          "version": 0,
+          "block": {
+            "attributes": {
+              "has_computed_default": {
+                "type": "string",
+                "description": "If set, its literal value will be stored and returned. If not, its value defaults to `\"default\"`. This argument exists primarily for testing and has little practical use.",
+                "description_kind": "plain",
+                "optional": true,
+                "computed": true
+              },
+              "id": {
+                "type": "string",
+                "description": "This attribute is only present for some legacy compatibility issues and should not be used. It will be removed in a future version.",
+                "description_kind": "plain",
+                "deprecated": true,
+                "computed": true
+              },
+              "inputs": {
+                "type": [
+                  "map",
+                  "string"
+                ],
+                "description": "A map of arbitrary strings that is copied into the `outputs` attribute, and accessible directly for interpolation.",
+                "description_kind": "plain",
+                "optional": true
+              },
+              "outputs": {
+                "type": [
+                  "map",
+                  "string"
+                ],
+                "description": "After the data source is \"read\", a copy of the `inputs` map.",
+                "description_kind": "plain",
+                "computed": true
+              },
+              "random": {
+                "type": "string",
+                "description": "A random value. This is primarily for testing and has little practical use; prefer the [hashicorp/random provider](https://registry.terraform.io/providers/hashicorp/random) for more practical random number use-cases.",
+                "description_kind": "plain",
+                "computed": true
+              }
+            },
+            "description": "The `null_data_source` data source implements the standard data source lifecycle but does not\ninteract with any external APIs.\n\nHistorically, the `null_data_source` was typically used to construct intermediate values to re-use elsewhere in configuration. The\nsame can now be achieved using [locals](https://www.terraform.io/docs/language/values/locals.html).\n",
+            "description_kind": "plain",
+            "deprecated": true
+          }
+        }
+      }
+    }
+  },
+  "provider_format_version": "1.0"
+}
diff --git a/v1.5.7/internal/cloud/testdata/plan-json-basic/plan.log b/v1.5.7/internal/cloud/testdata/plan-json-basic/plan.log
new file mode 100644
index 0000000..6e7352e
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-json-basic/plan.log
@@ -0,0 +1,3 @@
+{"@level":"info","@message":"Terraform 1.3.7","@module":"terraform.ui","@timestamp":"2023-01-19T10:47:27.409143-05:00","terraform":"1.3.7","type":"version","ui":"1.0"}
+{"@level":"info","@message":"null_resource.foo: Plan to create","@module":"terraform.ui","@timestamp":"2023-01-19T10:47:27.605841-05:00","change":{"resource":{"addr":"null_resource.foo","module":"","resource":"null_resource.foo","implied_provider":"null","resource_type":"null_resource","resource_name":"foo","resource_key":null},"action":"create"},"type":"planned_change"}
+{"@level":"info","@message":"Plan: 1 to add, 0 to change, 0 to destroy.","@module":"terraform.ui","@timestamp":"2023-01-19T10:47:27.605906-05:00","changes":{"add":1,"change":0,"remove":0,"operation":"plan"},"type":"change_summary"}
diff --git a/v1.5.7/internal/cloud/testdata/plan-json-error/main.tf b/v1.5.7/internal/cloud/testdata/plan-json-error/main.tf
new file mode 100644
index 0000000..bc45f28
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-json-error/main.tf
@@ -0,0 +1,5 @@
+resource "null_resource" "foo" {
+  triggers {
+    random = "${guid()}"
+  }
+}
diff --git a/v1.5.7/internal/cloud/testdata/plan-json-error/plan-redacted.json b/v1.5.7/internal/cloud/testdata/plan-json-error/plan-redacted.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-json-error/plan-redacted.json
@@ -0,0 +1 @@
+{}
diff --git a/v1.5.7/internal/cloud/testdata/plan-json-error/plan.log b/v1.5.7/internal/cloud/testdata/plan-json-error/plan.log
new file mode 100644
index 0000000..b877f1e
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-json-error/plan.log
@@ -0,0 +1,2 @@
+{"@level":"info","@message":"Terraform 1.3.7","@module":"terraform.ui","@timestamp":"2023-01-20T12:12:25.477403-05:00","terraform":"1.3.7","type":"version","ui":"1.0"}
+{"@level":"error","@message":"Error: Unsupported block type","@module":"terraform.ui","@timestamp":"2023-01-20T12:12:25.615995-05:00","diagnostic":{"severity":"error","summary":"Unsupported block type","detail":"Blocks of type \"triggers\" are not expected here. Did you mean to define argument \"triggers\"? If so, use the equals sign to assign it a value.","range":{"filename":"main.tf","start":{"line":2,"column":3,"byte":35},"end":{"line":2,"column":11,"byte":43}},"snippet":{"context":"resource \"null_resource\" \"foo\"","code":"  triggers {","start_line":2,"highlight_start_offset":2,"highlight_end_offset":10,"values":[]}},"type":"diagnostic"}
diff --git a/v1.5.7/internal/cloud/testdata/plan-json-full/main.tf b/v1.5.7/internal/cloud/testdata/plan-json-full/main.tf
new file mode 100644
index 0000000..d6e43c5
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-json-full/main.tf
@@ -0,0 +1,82 @@
+provider "tfcoremock" {}
+
+# In order to generate the JSON logs contained in plan.log
+# First ONLY apply tfcoremock_simple_resource.example (set the bool attribute
+# to true). Make sure the complex_resource is commented out.
+# Once applied, change the bool attribute to false and uncomment the complex
+# resource.
+
+resource "tfcoremock_simple_resource" "example" {
+  id      = "my-simple-resource"
+  bool    = false
+  number  = 0
+  string  = "Hello, world!"
+  float   = 0
+  integer = 0
+}
+
+resource "tfcoremock_complex_resource" "example" {
+  id = "my-complex-resource"
+
+  bool    = true
+  number  = 0
+  string  = "Hello, world!"
+  float   = 0
+  integer = 0
+
+  list = [
+    {
+      string = "list.one"
+    },
+    {
+      string = "list.two"
+    }
+  ]
+
+  set = [
+    {
+      string = "set.one"
+    },
+    {
+      string = "set.two"
+    }
+  ]
+
+  map = {
+    "one" : {
+      string = "map.one"
+    },
+    "two" : {
+      string = "map.two"
+    }
+  }
+
+  object = {
+
+    string = "nested object"
+
+    object = {
+      string = "nested nested object"
+    }
+  }
+
+  list_block {
+    string = "list_block.one"
+  }
+
+  list_block {
+    string = "list_block.two"
+  }
+
+  list_block {
+    string = "list_block.three"
+  }
+
+  set_block {
+    string = "set_block.one"
+  }
+
+  set_block {
+    string = "set_block.two"
+  }
+}
diff --git a/v1.5.7/internal/cloud/testdata/plan-json-full/plan-redacted.json b/v1.5.7/internal/cloud/testdata/plan-json-full/plan-redacted.json
new file mode 100644
index 0000000..eb20b24
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-json-full/plan-redacted.json
@@ -0,0 +1 @@
+{"plan_format_version":"1.1","resource_drift":[{"address":"tfcoremock_simple_resource.example","mode":"managed","type":"tfcoremock_simple_resource","name":"example","provider_name":"registry.terraform.io/hashicorp/tfcoremock","change":{"actions":["delete"],"before":{"bool":true,"float":0,"id":"my-simple-resource","integer":0,"number":0,"string":"Hello, world!"},"after":null,"after_unknown":{},"before_sensitive":{},"after_sensitive":false}}],"resource_changes":[{"address":"tfcoremock_complex_resource.example","mode":"managed","type":"tfcoremock_complex_resource","name":"example","provider_name":"registry.terraform.io/hashicorp/tfcoremock","change":{"actions":["create"],"before":null,"after":{"bool":true,"float":0,"id":"my-complex-resource","integer":0,"list":[{"bool":null,"float":null,"integer":null,"list":null,"map":null,"number":null,"object":null,"set":null,"string":"list.one"},{"bool":null,"float":null,"integer":null,"list":null,"map":null,"number":null,"object":null,"set":null,"string":"list.two"}],"list_block":[{"bool":null,"float":null,"integer":null,"list":null,"list_block":[],"map":null,"number":null,"object":null,"set":null,"set_block":[],"string":"list_block.one"},{"bool":null,"float":null,"integer":null,"list":null,"list_block":[],"map":null,"number":null,"object":null,"set":null,"set_block":[],"string":"list_block.two"},{"bool":null,"float":null,"integer":null,"list":null,"list_block":[],"map":null,"number":null,"object":null,"set":null,"set_block":[],"string":"list_block.three"}],"map":{"one":{"bool":null,"float":null,"integer":null,"list":null,"map":null,"number":null,"object":null,"set":null,"string":"map.one"},"two":{"bool":null,"float":null,"integer":null,"list":null,"map":null,"number":null,"object":null,"set":null,"string":"map.two"}},"number":0,"object":{"bool":null,"float":null,"integer":null,"list":null,"map":null,"number":null,"object":{"bool":null,"float":null,"integer":null,"list":null,"map":null,"number":null,"object":null,"set":null,"string":"nested nested object"},"set":null,"string":"nested object"},"set":[{"bool":null,"float":null,"integer":null,"list":null,"map":null,"number":null,"object":null,"set":null,"string":"set.one"},{"bool":null,"float":null,"integer":null,"list":null,"map":null,"number":null,"object":null,"set":null,"string":"set.two"}],"set_block":[{"bool":null,"float":null,"integer":null,"list":null,"list_block":[],"map":null,"number":null,"object":null,"set":null,"set_block":[],"string":"set_block.one"},{"bool":null,"float":null,"integer":null,"list":null,"list_block":[],"map":null,"number":null,"object":null,"set":null,"set_block":[],"string":"set_block.two"}],"string":"Hello, world!"},"after_unknown":{},"before_sensitive":false,"after_sensitive":{"list":[{},{}],"list_block":[{"list_block":[],"set_block":[]},{"list_block":[],"set_block":[]},{"list_block":[],"set_block":[]}],"map":{"one":{},"two":{}},"object":{"object":{}},"set":[{},{}],"set_block":[{"list_block":[],"set_block":[]},{"list_block":[],"set_block":[]}]}}},{"address":"tfcoremock_simple_resource.example","mode":"managed","type":"tfcoremock_simple_resource","name":"example","provider_name":"registry.terraform.io/hashicorp/tfcoremock","change":{"actions":["create"],"before":null,"after":{"bool":false,"float":0,"id":"my-simple-resource","integer":0,"number":0,"string":"Hello, world!"},"after_unknown":{},"before_sensitive":false,"after_sensitive":{}}}],"relevant_attributes":[],"output_changes":{},"provider_schemas":{"registry.terraform.io/hashicorp/tfcoremock":{"provider":{"version":0,"block":{"attributes":{"data_directory":{"type":"string","description":"The directory that the provider should use to read the human-readable JSON files for each requested data source. Defaults to `data.resource`.","description_kind":"markdown","optional":true},"resource_directory":{"type":"string","description":"The directory that the provider should use to write the human-readable JSON files for each managed resource. If `use_only_state` is set to `true` then this value does not matter. Defaults to `terraform.resource`.","description_kind":"markdown","optional":true},"use_only_state":{"type":"bool","description":"If set to true the provider will rely only on the Terraform state file to load managed resources and will not write anything to disk. Defaults to `false`.","description_kind":"markdown","optional":true}},"description":"The `tfcoremock` provider is intended to aid with testing the Terraform core libraries and the Terraform CLI. This provider should allow users to define all possible Terraform configurations and run them through the Terraform core platform.\n\nThe provider supplies two static resources:\n\n- `tfcoremock_simple_resource`\n- `tfcoremock_complex_resource`\n \nUsers can then define additional dynamic resources by supplying a `dynamic_resources.json` file alongside their root Terraform configuration. These dynamic resources can be used to model any Terraform configuration not covered by the provided static resources.\n\nBy default, all resources created by the provider are then converted into a human-readable JSON format and written out to the resource directory. This behaviour can be disabled by turning on the `use_only_state` flag in the provider schema (this is useful when running the provider in a Terraform Cloud environment). The resource directory defaults to `terraform.resource`.\n\nAll resources supplied by the provider (including the simple and complex resource as well as any dynamic resources) are duplicated into data sources. The data sources should be supplied in the JSON format that resources are written into. The provider looks into the data directory, which defaults to `terraform.data`.\n\nFinally, all resources (and data sources) supplied by the provider have an `id` attribute that is generated if not set by the configuration. Dynamic resources cannot define an `id` attribute as the provider will create one for them. The `id` attribute is used as name of the human-readable JSON files held in the resource and data directories.","description_kind":"markdown"}},"resource_schemas":{"tfcoremock_complex_resource":{"version":0,"block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"id":{"type":"string","description_kind":"plain","optional":true,"computed":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"block_types":{"list_block":{"nesting_mode":"list","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"block_types":{"list_block":{"nesting_mode":"list","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"block_types":{"list_block":{"nesting_mode":"list","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A list block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}},"set_block":{"nesting_mode":"set","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A set block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}}},"description":"A list block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}},"set_block":{"nesting_mode":"set","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"block_types":{"list_block":{"nesting_mode":"list","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A list block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}},"set_block":{"nesting_mode":"set","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A set block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}}},"description":"A set block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}}},"description":"A list block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}},"set_block":{"nesting_mode":"set","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"block_types":{"list_block":{"nesting_mode":"list","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"block_types":{"list_block":{"nesting_mode":"list","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A list block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}},"set_block":{"nesting_mode":"set","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A set block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}}},"description":"A list block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}},"set_block":{"nesting_mode":"set","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"block_types":{"list_block":{"nesting_mode":"list","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A list block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}},"set_block":{"nesting_mode":"set","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A set block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}}},"description":"A set block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}}},"description":"A set block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}}},"description":"A complex resource that contains five basic attributes, four complex attributes, and two nested blocks.\n\nThe five basic attributes are `boolean`, `number`, `string`, `float`, and `integer` (as with the `tfcoremock_simple_resource`).\n\nThe complex attributes are a `map`, a `list`, a `set`, and an `object`. The `object` type contains the same set of attributes as the schema itself, making a recursive structure. The `list`, `set` and `map` all contain objects which are also recursive. Blocks cannot go into attributes, so the complex attributes do not recurse on the block types.\n\nThe blocks are a nested `list_block` and a nested `set_block`. The blocks contain the same set of attributes and blocks as the schema itself, also making a recursive structure. Note, blocks contain both attributes and more blocks so the block types are fully recursive.\n\nThe complex and block types are nested 3 times, at the leaf level of recursion the complex attributes and blocks only contain the simple (ie. non-recursive) attributes. This prevents a potentially infinite level of recursion.","description_kind":"markdown"}},"tfcoremock_simple_resource":{"version":0,"block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"id":{"type":"string","description_kind":"plain","optional":true,"computed":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A simple resource that holds optional attributes for the five basic types: `bool`, `number`, `string`, `float`, and `integer`.","description_kind":"markdown"}}},"data_source_schemas":{"tfcoremock_complex_resource":{"version":0,"block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"id":{"type":"string","description_kind":"plain","required":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"block_types":{"list_block":{"nesting_mode":"list","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"block_types":{"list_block":{"nesting_mode":"list","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"block_types":{"list_block":{"nesting_mode":"list","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A list block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}},"set_block":{"nesting_mode":"set","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A set block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}}},"description":"A list block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}},"set_block":{"nesting_mode":"set","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"block_types":{"list_block":{"nesting_mode":"list","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A list block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}},"set_block":{"nesting_mode":"set","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A set block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}}},"description":"A set block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}}},"description":"A list block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}},"set_block":{"nesting_mode":"set","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"block_types":{"list_block":{"nesting_mode":"list","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"block_types":{"list_block":{"nesting_mode":"list","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A list block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}},"set_block":{"nesting_mode":"set","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A set block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}}},"description":"A list block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}},"set_block":{"nesting_mode":"set","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"list":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"list"},"description":"A list attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"map":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"map"},"description":"A map attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"object":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"single"},"description":"An object attribute that matches the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"set":{"nested_type":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"nesting_mode":"set"},"description":"A set attribute that contains objects that match the root schema, allowing for nested collections and objects to be modelled.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"block_types":{"list_block":{"nesting_mode":"list","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A list block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}},"set_block":{"nesting_mode":"set","block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A set block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}}},"description":"A set block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}}},"description":"A set block that contains the same attributes and blocks as the root schema, allowing nested blocks and objects to be modelled.","description_kind":"markdown"}}},"description":"A complex resource that contains five basic attributes, four complex attributes, and two nested blocks.\n\nThe five basic attributes are `boolean`, `number`, `string`, `float`, and `integer` (as with the `tfcoremock_simple_resource`).\n\nThe complex attributes are a `map`, a `list`, a `set`, and an `object`. The `object` type contains the same set of attributes as the schema itself, making a recursive structure. The `list`, `set` and `map` all contain objects which are also recursive. Blocks cannot go into attributes, so the complex attributes do not recurse on the block types.\n\nThe blocks are a nested `list_block` and a nested `set_block`. The blocks contain the same set of attributes and blocks as the schema itself, also making a recursive structure. Note, blocks contain both attributes and more blocks so the block types are fully recursive.\n\nThe complex and block types are nested 3 times, at the leaf level of recursion the complex attributes and blocks only contain the simple (ie. non-recursive) attributes. This prevents a potentially infinite level of recursion.","description_kind":"markdown"}},"tfcoremock_simple_resource":{"version":0,"block":{"attributes":{"bool":{"type":"bool","description":"An optional boolean attribute, can be true or false.","description_kind":"markdown","optional":true},"float":{"type":"number","description":"An optional float attribute.","description_kind":"markdown","optional":true},"id":{"type":"string","description_kind":"plain","required":true},"integer":{"type":"number","description":"An optional integer attribute.","description_kind":"markdown","optional":true},"number":{"type":"number","description":"An optional number attribute, can be an integer or a float.","description_kind":"markdown","optional":true},"string":{"type":"string","description":"An optional string attribute.","description_kind":"markdown","optional":true}},"description":"A simple resource that holds optional attributes for the five basic types: `bool`, `number`, `string`, `float`, and `integer`.","description_kind":"markdown"}}}}},"provider_format_version":"1.0"}
\ No newline at end of file
diff --git a/v1.5.7/internal/cloud/testdata/plan-json-full/plan.log b/v1.5.7/internal/cloud/testdata/plan-json-full/plan.log
new file mode 100644
index 0000000..59fa3cb
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-json-full/plan.log
@@ -0,0 +1,6 @@
+{"@level":"info","@message":"Terraform 1.3.7","@module":"terraform.ui","@timestamp":"2023-01-19T13:28:29.004160-05:00","terraform":"1.3.7","type":"version","ui":"1.0"}
+{"@level":"info","@message":"tfcoremock_simple_resource.example: Refreshing state... [id=my-simple-resource]","@module":"terraform.ui","@timestamp":"2023-01-19T13:28:29.232274-05:00","hook":{"resource":{"addr":"tfcoremock_simple_resource.example","module":"","resource":"tfcoremock_simple_resource.example","implied_provider":"tfcoremock","resource_type":"tfcoremock_simple_resource","resource_name":"example","resource_key":null},"id_key":"id","id_value":"my-simple-resource"},"type":"refresh_start"}
+{"@level":"info","@message":"tfcoremock_simple_resource.example: Refresh complete [id=my-simple-resource]","@module":"terraform.ui","@timestamp":"2023-01-19T13:28:29.232882-05:00","hook":{"resource":{"addr":"tfcoremock_simple_resource.example","module":"","resource":"tfcoremock_simple_resource.example","implied_provider":"tfcoremock","resource_type":"tfcoremock_simple_resource","resource_name":"example","resource_key":null},"id_key":"id","id_value":"my-simple-resource"},"type":"refresh_complete"}
+{"@level":"info","@message":"tfcoremock_simple_resource.example: Plan to update","@module":"terraform.ui","@timestamp":"2023-01-19T13:28:29.289259-05:00","change":{"resource":{"addr":"tfcoremock_simple_resource.example","module":"","resource":"tfcoremock_simple_resource.example","implied_provider":"tfcoremock","resource_type":"tfcoremock_simple_resource","resource_name":"example","resource_key":null},"action":"update"},"type":"planned_change"}
+{"@level":"info","@message":"tfcoremock_complex_resource.example: Plan to create","@module":"terraform.ui","@timestamp":"2023-01-19T13:28:29.289320-05:00","change":{"resource":{"addr":"tfcoremock_complex_resource.example","module":"","resource":"tfcoremock_complex_resource.example","implied_provider":"tfcoremock","resource_type":"tfcoremock_complex_resource","resource_name":"example","resource_key":null},"action":"create"},"type":"planned_change"}
+{"@level":"info","@message":"Plan: 1 to add, 1 to change, 0 to destroy.","@module":"terraform.ui","@timestamp":"2023-01-19T13:28:29.289330-05:00","changes":{"add":1,"change":1,"remove":0,"operation":"plan"},"type":"change_summary"}
diff --git a/v1.5.7/internal/cloud/testdata/plan-long-line/main.tf b/v1.5.7/internal/cloud/testdata/plan-long-line/main.tf
new file mode 100644
index 0000000..0a8d623
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-long-line/main.tf
@@ -0,0 +1,5 @@
+resource "null_resource" "foo" {
+  triggers {
+    long_line = "[{'_id':'5c5ab0ed7de45e993ffb9eeb','index':0,'guid':'e734d772-6b5a-4cb0-805c-91cd5e560e20','isActive':false,'balance':'$1,472.03','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Darlene','last':'Garza'},'company':'GEEKOSIS','email':'darlene.garza@geekosis.io','phone':'+1 (850) 506-3347','address':'165 Kiely Place, Como, New Mexico, 4335','about':'Officia ullamco et sunt magna voluptate culpa cupidatat ea tempor laboris cupidatat ea anim laboris. Minim enim quis enim esse laborum est veniam. Lorem excepteur elit Lorem cupidatat elit ea anim irure fugiat fugiat sunt mollit. Consectetur ad nulla dolor amet esse occaecat aliquip sit. Magna sit elit adipisicing ut reprehenderit anim exercitation sit quis ea pariatur Lorem magna dolore.','registered':'Wednesday, March 11, 2015 12:58 PM','latitude':'20.729127','longitude':'-127.343593','tags':['minim','in','deserunt','occaecat','fugiat'],'greeting':'Hello, Darlene! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eda9117d15f1c1f112','index':1,'guid':'f0d1eed2-c6a9-4535-8800-d4bd53fe7eee','isActive':true,'balance':'$2,901.90','picture':'http://placehold.it/32x32','age':28,'eyeColor':'brown','name':{'first':'Flora','last':'Short'},'company':'SIGNITY','email':'flora.short@signity.me','phone':'+1 (840) 520-2666','address':'636 Johnson Avenue, Gerber, Wisconsin, 9139','about':'Veniam dolore deserunt Lorem aliqua qui eiusmod. Amet tempor fugiat duis incididunt amet adipisicing. Id ea nisi veniam eiusmod.','registered':'Wednesday, May 2, 2018 5:59 AM','latitude':'-63.267612','longitude':'4.224102','tags':['veniam','incididunt','id','aliqua','reprehenderit'],'greeting':'Hello, Flora! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed83fd574d8041fa16','index':2,'guid':'29499a07-414a-436f-ba62-6634ca16bdcc','isActive':true,'balance':'$2,781.28','picture':'http://placehold.it/32x32','age':22,'eyeColor':'green','name':{'first':'Trevino','last':'Marks'},'company':'KEGULAR','email':'trevino.marks@kegular.com','phone':'+1 (843) 571-2269','address':'200 Alabama Avenue, Grenelefe, Florida, 7963','about':'Occaecat nisi exercitation Lorem mollit laborum magna adipisicing culpa dolor proident dolore. Non consequat ea amet et id mollit incididunt minim anim amet nostrud labore tempor. Proident eu sint commodo nisi consequat voluptate do fugiat proident. Laboris eiusmod veniam non et elit nulla nisi labore incididunt Lorem consequat consectetur voluptate.','registered':'Saturday, January 25, 2014 5:56 AM','latitude':'65.044005','longitude':'-127.454864','tags':['anim','duis','velit','pariatur','enim'],'greeting':'Hello, Trevino! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed784eb6e350ff0a07','index':3,'guid':'40ed47e2-1747-4665-ab59-cdb3630a7642','isActive':true,'balance':'$2,000.78','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Solis','last':'Mckinney'},'company':'QABOOS','email':'solis.mckinney@qaboos.org','phone':'+1 (924) 405-2560','address':'712 Herkimer Court, Klondike, Ohio, 8133','about':'Minim ad anim minim tempor mollit magna tempor et non commodo amet. Nisi cupidatat labore culpa consectetur exercitation laborum adipisicing fugiat officia adipisicing consequat non. Qui voluptate tempor laboris exercitation qui non adipisicing occaecat voluptate sunt do nostrud velit. Consequat tempor officia laboris tempor irure cupidatat aliquip voluptate nostrud velit ex nulla tempor laboris. Qui pariatur pariatur enim aliquip velit. Officia mollit ullamco laboris velit velit eiusmod enim amet incididunt consectetur sunt.','registered':'Wednesday, April 12, 2017 6:59 AM','latitude':'-25.055596','longitude':'-140.126525','tags':['ipsum','adipisicing','amet','nulla','dolore'],'greeting':'Hello, Solis! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed02ce1ea9a2155d51','index':4,'guid':'1b5fb7d3-3b9a-4382-81b5-9ab01a27e74b','isActive':true,'balance':'$1,373.67','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Janell','last':'Battle'},'company':'GEEKMOSIS','email':'janell.battle@geekmosis.net','phone':'+1 (810) 591-3014','address':'517 Onderdonk Avenue, Shrewsbury, District Of Columbia, 2335','about':'Reprehenderit ad proident do anim qui officia magna magna duis cillum esse minim est. Excepteur ipsum anim ad laboris. In occaecat dolore nulla ea Lorem tempor et culpa in sint. Officia eu eu incididunt sit amet. Culpa duis id reprehenderit ut anim sit sunt. Duis dolore proident velit incididunt adipisicing pariatur fugiat incididunt eiusmod eu veniam irure.','registered':'Thursday, February 8, 2018 1:44 AM','latitude':'-33.254864','longitude':'-154.145885','tags':['aute','deserunt','ipsum','eiusmod','laborum'],'greeting':'Hello, Janell! You have 5 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edab58604bd7d3dd1c','index':5,'guid':'6354c035-af22-44c9-8be9-b2ea9decc24d','isActive':true,'balance':'$3,535.68','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Combs','last':'Kirby'},'company':'LUXURIA','email':'combs.kirby@luxuria.name','phone':'+1 (900) 498-3266','address':'377 Kingsland Avenue, Ruckersville, Maine, 9916','about':'Lorem duis ipsum pariatur aliquip sunt. Commodo esse laborum incididunt mollit quis est laboris ea ea quis fugiat. Enim elit ullamco velit et fugiat veniam irure deserunt aliqua ad irure veniam.','registered':'Tuesday, February 21, 2017 4:04 PM','latitude':'-70.20591','longitude':'162.546871','tags':['reprehenderit','est','enim','aute','ad'],'greeting':'Hello, Combs! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edf7fafeffc6357c51','index':6,'guid':'02523e0b-cc90-4309-b6b2-f493dc6076f6','isActive':false,'balance':'$3,754.30','picture':'http://placehold.it/32x32','age':29,'eyeColor':'green','name':{'first':'Macias','last':'Calderon'},'company':'AMTAP','email':'macias.calderon@amtap.us','phone':'+1 (996) 569-3667','address':'305 Royce Street, Glidden, Iowa, 9248','about':'Exercitation nulla deserunt pariatur adipisicing. In commodo deserunt incididunt ut velit minim qui ut quis. Labore elit ullamco eiusmod voluptate in eu do est fugiat aute mollit deserunt. Eu duis proident velit fugiat velit ut. Ut non esse amet laborum nisi tempor in nulla.','registered':'Thursday, October 23, 2014 10:28 PM','latitude':'32.371629','longitude':'60.155135','tags':['commodo','elit','velit','excepteur','aliqua'],'greeting':'Hello, Macias! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed0e8a6109e7fabf17','index':7,'guid':'675ff6b6-197b-4154-9775-813d661df822','isActive':false,'balance':'$2,850.62','picture':'http://placehold.it/32x32','age':37,'eyeColor':'green','name':{'first':'Stefanie','last':'Rivers'},'company':'RECRITUBE','email':'stefanie.rivers@recritube.biz','phone':'+1 (994) 591-3551','address':'995 Campus Road, Abrams, Virginia, 3251','about':'Esse aute non laborum Lorem nulla irure. Veniam elit aute ut et dolor non deserunt laboris tempor. Ipsum quis cupidatat laborum laboris voluptate esse duis eiusmod excepteur consectetur commodo ullamco qui occaecat. Culpa velit cillum occaecat minim nisi.','registered':'Thursday, June 9, 2016 3:40 PM','latitude':'-18.526825','longitude':'149.670782','tags':['occaecat','sunt','reprehenderit','ipsum','magna'],'greeting':'Hello, Stefanie! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edf7d9bc2db4e476e3','index':8,'guid':'adaefc55-f6ea-4bd1-a147-0e31c3ce7a21','isActive':true,'balance':'$2,555.13','picture':'http://placehold.it/32x32','age':20,'eyeColor':'blue','name':{'first':'Hillary','last':'Lancaster'},'company':'OLUCORE','email':'hillary.lancaster@olucore.ca','phone':'+1 (964) 474-3018','address':'232 Berriman Street, Kaka, Massachusetts, 6792','about':'Veniam ad laboris quis reprehenderit aliquip nisi sunt excepteur ea aute laborum excepteur incididunt. Nisi exercitation aliquip do culpa commodo ex officia ut enim mollit in deserunt in amet. Anim eu deserunt dolore non cupidatat ut enim incididunt aute dolore voluptate. Do cillum mollit laborum non incididunt occaecat aute voluptate nisi irure.','registered':'Thursday, June 4, 2015 9:45 PM','latitude':'88.075919','longitude':'-148.951368','tags':['reprehenderit','veniam','ad','aute','anim'],'greeting':'Hello, Hillary! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed7b7192ad6a0f267c','index':9,'guid':'0ca9b8ea-f671-474e-be26-4a49cae4838a','isActive':true,'balance':'$3,684.51','picture':'http://placehold.it/32x32','age':40,'eyeColor':'brown','name':{'first':'Jill','last':'Conner'},'company':'EXOZENT','email':'jill.conner@exozent.info','phone':'+1 (887) 467-2168','address':'751 Thames Street, Juarez, American Samoa, 8386','about':'Enim voluptate et non est in magna laborum aliqua enim aliqua est non nostrud. Tempor est nulla ipsum consectetur esse nostrud est id. Consequat do voluptate cupidatat eu fugiat et fugiat velit id. Sint dolore ad qui tempor anim eu amet consectetur do elit aute adipisicing consequat ex.','registered':'Sunday, October 22, 2017 7:35 AM','latitude':'84.384911','longitude':'40.305648','tags':['tempor','sint','irure','et','ex'],'greeting':'Hello, Jill! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed713fe676575aa72b','index':10,'guid':'c28023cf-cc57-4c2e-8d91-dfbe6bafadcd','isActive':false,'balance':'$2,792.45','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Hurley','last':'George'},'company':'ZAJ','email':'hurley.george@zaj.tv','phone':'+1 (984) 547-3284','address':'727 Minna Street, Lacomb, Colorado, 2557','about':'Ex velit cupidatat veniam culpa. Eiusmod ut fugiat adipisicing incididunt consectetur exercitation Lorem exercitation ex. Incididunt anim aute incididunt fugiat cupidatat qui eu non reprehenderit. Eiusmod dolor nisi culpa excepteur ut velit minim dolor voluptate amet commodo culpa in.','registered':'Thursday, February 16, 2017 6:41 AM','latitude':'25.989949','longitude':'10.200053','tags':['minim','ut','sunt','consequat','ullamco'],'greeting':'Hello, Hurley! You have 8 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1e56732746c70d8b','index':11,'guid':'e9766f13-766c-4450-b4d2-8b04580f60b7','isActive':true,'balance':'$3,874.26','picture':'http://placehold.it/32x32','age':35,'eyeColor':'green','name':{'first':'Leticia','last':'Pace'},'company':'HONOTRON','email':'leticia.pace@honotron.co.uk','phone':'+1 (974) 536-3322','address':'365 Goodwin Place, Savage, Nevada, 9191','about':'Nisi Lorem aliqua esse eiusmod magna. Ad minim incididunt proident ut Lorem cupidatat qui velit aliqua ullamco et ipsum in. Aliquip elit consectetur pariatur esse exercitation et officia quis. Occaecat tempor proident cillum anim ad commodo velit ut voluptate. Tempor et occaecat sit sint aliquip tempor nulla velit magna nisi proident exercitation Lorem id.','registered':'Saturday, August 4, 2018 5:05 AM','latitude':'70.620386','longitude':'-86.335813','tags':['occaecat','velit','labore','laboris','esse'],'greeting':'Hello, Leticia! You have 8 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed941337fe42f47426','index':12,'guid':'6d390762-17ea-4b58-9a36-b0c9a8748a42','isActive':true,'balance':'$1,049.61','picture':'http://placehold.it/32x32','age':38,'eyeColor':'green','name':{'first':'Rose','last':'Humphrey'},'company':'MYOPIUM','email':'rose.humphrey@myopium.io','phone':'+1 (828) 426-3086','address':'389 Sapphire Street, Saticoy, Marshall Islands, 1423','about':'Aliquip enim excepteur adipisicing ex. Consequat aliqua consequat nostrud do occaecat deserunt excepteur sit et ipsum sunt dolor eu. Dolore laborum commodo excepteur tempor ad adipisicing proident excepteur magna non Lorem proident consequat aute. Fugiat minim consequat occaecat voluptate esse velit officia laboris nostrud nisi ut voluptate.','registered':'Monday, April 16, 2018 12:38 PM','latitude':'-47.083742','longitude':'109.022423','tags':['aute','non','sit','adipisicing','mollit'],'greeting':'Hello, Rose! You have 9 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd0c02fc3fdc01a40','index':13,'guid':'07755618-6fdf-4b33-af50-364c18909227','isActive':true,'balance':'$1,823.61','picture':'http://placehold.it/32x32','age':36,'eyeColor':'green','name':{'first':'Judith','last':'Hale'},'company':'COLLAIRE','email':'judith.hale@collaire.me','phone':'+1 (922) 508-2843','address':'193 Coffey Street, Castleton, North Dakota, 3638','about':'Minim non ullamco ad anim nostrud dolore nostrud veniam consequat id eiusmod veniam laboris. Lorem irure esse mollit non velit aute id cupidatat est mollit occaecat magna excepteur. Adipisicing tempor nisi sit aliquip tempor pariatur tempor eu consectetur nulla amet nulla. Quis nisi nisi ea incididunt culpa et do. Esse officia eu pariatur velit sunt quis proident amet consectetur consequat. Nisi excepteur culpa nulla sit dolor deserunt excepteur dolor consequat elit cillum tempor Lorem.','registered':'Wednesday, August 24, 2016 12:29 AM','latitude':'-80.15514','longitude':'39.91007','tags':['consectetur','incididunt','aliquip','dolor','consequat'],'greeting':'Hello, Judith! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edb3e1e29caa4f728b','index':14,'guid':'2c6617a2-e7a9-4ff7-a8b9-e99554fe70fe','isActive':true,'balance':'$1,971.00','picture':'http://placehold.it/32x32','age':39,'eyeColor':'blue','name':{'first':'Estes','last':'Sweet'},'company':'GEEKKO','email':'estes.sweet@geekko.com','phone':'+1 (866) 448-3032','address':'847 Cove Lane, Kula, Mississippi, 9178','about':'Veniam consectetur occaecat est excepteur consequat ipsum cillum sit consectetur. Ut cupidatat et reprehenderit dolore enim do cillum qui pariatur ad laborum incididunt esse. Fugiat sunt dolor veniam laboris ipsum deserunt proident reprehenderit laboris non nostrud. Magna excepteur sint magna laborum tempor sit exercitation ipsum labore est ullamco ullamco. Cillum voluptate cillum ea laborum Lorem. Excepteur sint ut nisi est esse non. Minim excepteur ullamco velit nisi ut in elit exercitation ut dolore.','registered':'Sunday, August 12, 2018 5:06 PM','latitude':'-9.57771','longitude':'-159.94577','tags':['culpa','dolor','velit','anim','pariatur'],'greeting':'Hello, Estes! You have 7 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edbcf088c6fd593091','index':15,'guid':'2cc79958-1b40-4e2c-907a-433903fd3da9','isActive':false,'balance':'$3,751.53','picture':'http://placehold.it/32x32','age':34,'eyeColor':'brown','name':{'first':'Kemp','last':'Spence'},'company':'EXOBLUE','email':'kemp.spence@exoblue.org','phone':'+1 (864) 487-2992','address':'217 Clay Street, Monument, North Carolina, 1460','about':'Nostrud duis cillum sint non commodo dolor aute aliqua adipisicing ad nulla non excepteur proident. Fugiat labore elit tempor cillum veniam reprehenderit laboris consectetur dolore amet qui cupidatat. Amet aliqua elit anim et consequat commodo excepteur officia anim aliqua ea eu labore cillum. Et ex dolor duis dolore commodo veniam et nisi.','registered':'Monday, October 29, 2018 5:23 AM','latitude':'-70.304222','longitude':'83.582371','tags':['velit','duis','consequat','incididunt','duis'],'greeting':'Hello, Kemp! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed6400479feb3de505','index':16,'guid':'91ccae6d-a3ea-43cf-bb00-3f2729256cc9','isActive':false,'balance':'$2,477.79','picture':'http://placehold.it/32x32','age':40,'eyeColor':'blue','name':{'first':'Ronda','last':'Burris'},'company':'EQUITOX','email':'ronda.burris@equitox.net','phone':'+1 (817) 553-3228','address':'708 Lawton Street, Deputy, Wyoming, 8598','about':'Excepteur voluptate aliquip consequat cillum est duis sit cillum eu eiusmod et laborum ullamco. Et minim reprehenderit aute voluptate amet ullamco. Amet sit enim ad irure deserunt nostrud anim veniam consequat dolor commodo. Consequat do occaecat do exercitation ullamco dolor ut. Id laboris consequat est dolor dolore tempor ullamco anim do ut nulla deserunt labore. Mollit ex Lorem ullamco mollit.','registered':'Monday, April 23, 2018 5:27 PM','latitude':'-31.227208','longitude':'0.63785','tags':['ipsum','magna','consectetur','sit','irure'],'greeting':'Hello, Ronda! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eddbeab2e53e04d563','index':17,'guid':'a86d4eb6-6bd8-48c2-a8fc-1c933c835852','isActive':false,'balance':'$3,709.03','picture':'http://placehold.it/32x32','age':37,'eyeColor':'blue','name':{'first':'Rosario','last':'Dillard'},'company':'BARKARAMA','email':'rosario.dillard@barkarama.name','phone':'+1 (933) 525-3898','address':'730 Chauncey Street, Forbestown, South Carolina, 6894','about':'Est eu fugiat aliquip ea ad qui ad mollit ad tempor voluptate et incididunt reprehenderit. Incididunt fugiat commodo minim adipisicing culpa consectetur duis eu ut commodo consequat voluptate labore. Nostrud irure labore adipisicing irure quis magna consequat dolor Lorem sint enim. Sint excepteur eu dolore elit ut do mollit sunt enim est. Labore id nostrud sint Lorem esse nostrud.','registered':'Friday, December 25, 2015 8:59 PM','latitude':'37.440827','longitude':'44.580474','tags':['Lorem','sit','ipsum','ea','ut'],'greeting':'Hello, Rosario! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eddf8e9b9c031d04e8','index':18,'guid':'a96f997c-daf8-40d4-92e1-be07e2cf0f60','isActive':false,'balance':'$1,878.37','picture':'http://placehold.it/32x32','age':37,'eyeColor':'brown','name':{'first':'Sondra','last':'Gonzales'},'company':'XUMONK','email':'sondra.gonzales@xumonk.us','phone':'+1 (838) 560-2255','address':'230 Cox Place, Geyserville, Georgia, 6805','about':'Laborum sunt voluptate ea laboris nostrud. Amet deserunt aliqua Lorem voluptate velit deserunt occaecat minim ullamco. Lorem occaecat sit labore adipisicing ad magna mollit labore ullamco proident. Ea velit do proident fugiat esse commodo ex nostrud eu mollit pariatur. Labore laborum qui voluptate quis proident reprehenderit tempor dolore duis deserunt esse aliqua aliquip. Non veniam enim pariatur cupidatat ipsum dolore est reprehenderit. Non exercitation adipisicing proident magna elit occaecat non magna.','registered':'Sunday, June 26, 2016 4:02 AM','latitude':'62.247742','longitude':'-44.90666','tags':['ea','aute','in','voluptate','magna'],'greeting':'Hello, Sondra! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed2c1bcd06781f677e','index':19,'guid':'6ac47a16-eed4-4460-92ee-e0dd33c1fbb5','isActive':false,'balance':'$3,730.64','picture':'http://placehold.it/32x32','age':20,'eyeColor':'brown','name':{'first':'Anastasia','last':'Vega'},'company':'FIREWAX','email':'anastasia.vega@firewax.biz','phone':'+1 (867) 493-3698','address':'803 Arlington Avenue, Rosburg, Northern Mariana Islands, 8769','about':'Sint ex nisi tempor sunt voluptate non et eiusmod irure. Aute reprehenderit dolor mollit aliqua Lorem voluptate occaecat. Sint laboris deserunt Lorem incididunt nulla cupidatat do.','registered':'Friday, March 18, 2016 12:02 PM','latitude':'-32.010216','longitude':'-87.874753','tags':['aliquip','mollit','mollit','ad','laborum'],'greeting':'Hello, Anastasia! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed727fd645854bbf43','index':20,'guid':'67bd8cdb-ce6b-455c-944c-a80e17c6fa75','isActive':true,'balance':'$2,868.06','picture':'http://placehold.it/32x32','age':29,'eyeColor':'green','name':{'first':'Lucinda','last':'Cox'},'company':'ENDIPINE','email':'lucinda.cox@endipine.ca','phone':'+1 (990) 428-3002','address':'412 Thatford Avenue, Lafferty, New Jersey, 5271','about':'Esse nulla sunt ut consequat aute mollit. Est occaecat sunt nisi irure id anim est commodo. Elit mollit amet dolore sunt adipisicing ea laborum quis ea reprehenderit non consequat dolore. Minim sunt occaecat quis aute commodo dolore quis commodo proident. Sunt sint duis ullamco sit ea esse Lorem. Consequat pariatur eiusmod laboris adipisicing labore in laboris adipisicing adipisicing consequat aute ea et.','registered':'Friday, May 1, 2015 10:16 PM','latitude':'-14.200957','longitude':'-82.211386','tags':['do','sit','qui','officia','aliquip'],'greeting':'Hello, Lucinda! You have 9 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed5a97284eb2cbd3a8','index':21,'guid':'f9fc999d-515c-4fc4-b339-76300e1b4bf2','isActive':true,'balance':'$1,172.57','picture':'http://placehold.it/32x32','age':35,'eyeColor':'brown','name':{'first':'Conrad','last':'Bradley'},'company':'FUELWORKS','email':'conrad.bradley@fuelworks.info','phone':'+1 (956) 561-3226','address':'685 Fenimore Street, Esmont, Maryland, 7523','about':'Labore reprehenderit anim nisi sunt do nisi in. Est anim cillum id minim exercitation ullamco voluptate ipsum eu. Elit culpa consequat reprehenderit laborum in eu. Laboris amet voluptate laboris qui voluptate duis minim reprehenderit. Commodo sunt irure dolore sunt occaecat velit nisi eu minim minim.','registered':'Wednesday, January 18, 2017 11:13 PM','latitude':'31.665993','longitude':'38.868968','tags':['excepteur','exercitation','est','nisi','mollit'],'greeting':'Hello, Conrad! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edc4eaf6f760c38218','index':22,'guid':'8794ef5f-da2f-46f0-a755-c18a16409fd5','isActive':false,'balance':'$3,594.73','picture':'http://placehold.it/32x32','age':27,'eyeColor':'blue','name':{'first':'Marquez','last':'Vargas'},'company':'MALATHION','email':'marquez.vargas@malathion.tv','phone':'+1 (976) 438-3126','address':'296 Hall Street, National, Texas, 2067','about':'Proident cillum aute minim fugiat sunt aliqua non occaecat est duis id id tempor. Qui deserunt nisi amet pariatur proident eu laboris esse adipisicing magna. Anim anim mollit aute non magna nisi aute magna labore ullamco reprehenderit voluptate et ad. Proident adipisicing aute eiusmod nostrud nostrud deserunt culpa. Elit eu ullamco nisi aliqua dolor sint pariatur excepteur sit consectetur tempor. Consequat Lorem ullamco commodo veniam qui sint magna. Sit mollit ad aliquip est id eu officia id adipisicing duis ad.','registered':'Tuesday, November 17, 2015 6:16 PM','latitude':'-36.443667','longitude':'22.336776','tags':['aliquip','veniam','ipsum','Lorem','ex'],'greeting':'Hello, Marquez! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edd7c718518ee0466a','index':23,'guid':'ad8781a2-059e-4288-9879-309d53a99bf5','isActive':true,'balance':'$3,570.68','picture':'http://placehold.it/32x32','age':21,'eyeColor':'brown','name':{'first':'Snider','last':'Frost'},'company':'ZILODYNE','email':'snider.frost@zilodyne.co.uk','phone':'+1 (913) 485-3275','address':'721 Lincoln Road, Richmond, Utah, 672','about':'Minim enim Lorem esse incididunt do reprehenderit velit laborum ullamco. In aute eiusmod esse aliqua et labore tempor sunt ex mollit veniam tempor. Nulla elit cillum qui ullamco dolore amet deserunt magna amet laborum.','registered':'Saturday, August 23, 2014 12:58 AM','latitude':'-88.682554','longitude':'74.063179','tags':['nulla','ea','sint','aliquip','duis'],'greeting':'Hello, Snider! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edf026fece8e2c0970','index':24,'guid':'1b7d81e1-1dba-4322-bb1a-eaa6a24cccea','isActive':false,'balance':'$2,037.91','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Snyder','last':'Fletcher'},'company':'COMTEST','email':'snyder.fletcher@comtest.io','phone':'+1 (830) 538-3860','address':'221 Lewis Place, Zortman, Idaho, 572','about':'Elit anim enim esse dolore exercitation. Laboris esse sint adipisicing fugiat sint do occaecat ut voluptate sint nulla. Ad sint ut reprehenderit nostrud irure id consectetur officia velit consequat.','registered':'Sunday, January 1, 2017 1:13 AM','latitude':'-54.742604','longitude':'69.534932','tags':['exercitation','commodo','in','id','aliqua'],'greeting':'Hello, Snyder! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed4b9a7f83da6d2dfd','index':25,'guid':'0b2cc6b6-0044-4b1c-aa31-bd72963457a0','isActive':false,'balance':'$1,152.76','picture':'http://placehold.it/32x32','age':27,'eyeColor':'blue','name':{'first':'Regina','last':'James'},'company':'TELPOD','email':'regina.james@telpod.me','phone':'+1 (989) 455-3228','address':'688 Essex Street, Clayville, Alabama, 2772','about':'Eiusmod elit culpa reprehenderit ea veniam. Officia irure culpa duis aute ut. Irure duis cillum officia ea pariatur velit ut dolor incididunt reprehenderit ex elit laborum. Est pariatur veniam ad irure. Labore velit sunt esse laboris aliqua velit deserunt deserunt sit. Elit eiusmod ad laboris aliquip minim irure excepteur enim quis. Quis incididunt adipisicing ut magna cupidatat sit amet culpa.','registered':'Tuesday, April 25, 2017 10:16 PM','latitude':'-75.088027','longitude':'47.209828','tags':['elit','nisi','est','voluptate','proident'],'greeting':'Hello, Regina! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed10884f32f779f2bf','index':26,'guid':'1f6fb522-0002-46ff-8dac-451247f28168','isActive':true,'balance':'$1,948.79','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Collins','last':'Mcpherson'},'company':'DIGIGEN','email':'collins.mcpherson@digigen.com','phone':'+1 (991) 519-2334','address':'317 Merit Court, Sanford, Michigan, 6468','about':'Magna qui culpa dolor officia labore mollit ex excepteur duis eiusmod. Ea cupidatat ex ipsum mollit do minim duis. Nisi eiusmod minim tempor id esse commodo sunt sunt ullamco ut do laborum ullamco magna. Aliquip laborum dolor officia officia eu nostrud velit minim est anim. Ex elit laborum sunt magna exercitation nisi cillum sunt aute qui ea ullamco. Cupidatat ea sunt aute dolor duis nisi Lorem ullamco eiusmod. Sit ea velit ad veniam aliqua ad elit cupidatat ut magna in.','registered':'Friday, June 10, 2016 4:38 PM','latitude':'25.513996','longitude':'14.911124','tags':['exercitation','non','sit','velit','officia'],'greeting':'Hello, Collins! You have 5 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed8a575110efb15c6c','index':27,'guid':'2a904c82-068b-4ded-9ae6-cfeb6d7e62c9','isActive':true,'balance':'$3,427.91','picture':'http://placehold.it/32x32','age':24,'eyeColor':'green','name':{'first':'Mckay','last':'Barrera'},'company':'COMVEYER','email':'mckay.barrera@comveyer.org','phone':'+1 (853) 470-2560','address':'907 Glenwood Road, Churchill, Oregon, 8583','about':'In voluptate esse dolore enim sint quis dolor do exercitation sint et labore nisi. Eiusmod tempor exercitation dolore elit sit velit sint et. Sit magna adipisicing eiusmod do anim velit deserunt laboris ad ea pariatur. Irure nisi anim mollit elit commodo nulla. Aute eiusmod sit nulla eiusmod. Eiusmod est officia commodo mollit laboris do deserunt eu do nisi amet. Proident ad duis eiusmod laboris Lorem ut culpa pariatur Lorem reprehenderit minim aliquip irure sunt.','registered':'Saturday, December 19, 2015 2:49 PM','latitude':'-55.243287','longitude':'138.035406','tags':['non','quis','laboris','enim','nisi'],'greeting':'Hello, Mckay! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edcd49ab6a73ff7f32','index':28,'guid':'5d3e0dae-3f58-437f-b12d-de24667a904d','isActive':true,'balance':'$3,270.52','picture':'http://placehold.it/32x32','age':35,'eyeColor':'blue','name':{'first':'Mabel','last':'Leonard'},'company':'QUADEEBO','email':'mabel.leonard@quadeebo.net','phone':'+1 (805) 432-2356','address':'965 Underhill Avenue, Falconaire, Minnesota, 4450','about':'Cupidatat amet sunt est ipsum occaecat sit fugiat excepteur Lorem Lorem ex ea ipsum. Ad incididunt est irure magna excepteur occaecat nostrud. Minim dolor id anim ipsum qui nostrud ullamco aute ex Lorem magna deserunt excepteur Lorem.','registered':'Saturday, March 28, 2015 5:55 AM','latitude':'27.388359','longitude':'156.408728','tags':['quis','velit','deserunt','dolore','sit'],'greeting':'Hello, Mabel! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edde16ac2dc2fbb6c1','index':29,'guid':'d50c2233-70fc-4748-8ebf-02d45ac2a446','isActive':false,'balance':'$3,100.70','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Pace','last':'Duke'},'company':'SEQUITUR','email':'pace.duke@sequitur.name','phone':'+1 (983) 568-3119','address':'895 Melrose Street, Reno, Connecticut, 6259','about':'Ex veniam aliquip exercitation mollit elit est minim veniam aliqua labore deserunt. Dolor sunt sint cillum Lorem nisi ea irure cupidatat. Velit ut culpa cupidatat consequat cillum. Sint voluptate quis laboris qui incididunt do elit Lorem qui ullamco ut eu pariatur occaecat.','registered':'Saturday, August 18, 2018 2:18 PM','latitude':'31.930443','longitude':'-129.494784','tags':['culpa','est','nostrud','quis','aliquip'],'greeting':'Hello, Pace! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edb908d85642ba77e8','index':30,'guid':'3edb6e42-367a-403d-a511-eb78bcc11f60','isActive':true,'balance':'$1,912.07','picture':'http://placehold.it/32x32','age':24,'eyeColor':'green','name':{'first':'Cohen','last':'Morrison'},'company':'POWERNET','email':'cohen.morrison@powernet.us','phone':'+1 (888) 597-2141','address':'565 Troutman Street, Idledale, West Virginia, 3196','about':'Ullamco voluptate duis commodo amet occaecat consequat et occaecat dolore nulla eu. Do aliqua sunt deserunt occaecat laboris labore voluptate cupidatat ullamco exercitation aliquip elit voluptate anim. Occaecat deserunt in labore cillum aute deserunt ea excepteur laboris sunt. Officia irure sint incididunt labore sint ipsum ullamco ea elit. Fugiat nostrud sunt ut officia mollit proident sunt dolor fugiat esse tempor do.','registered':'Friday, January 1, 2016 5:42 AM','latitude':'-20.01215','longitude':'26.361552','tags':['consectetur','sunt','nulla','reprehenderit','dolore'],'greeting':'Hello, Cohen! You have 10 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed91c77aa25a64a757','index':31,'guid':'8999a97b-0035-4f19-b555-91dd69aaa9b8','isActive':false,'balance':'$3,097.67','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Stout','last':'Valdez'},'company':'UPLINX','email':'stout.valdez@uplinx.biz','phone':'+1 (854) 480-3633','address':'880 Chestnut Avenue, Lowgap, Hawaii, 1537','about':'Cupidatat enim dolore non voluptate. Aliqua ut non Lorem in exercitation reprehenderit voluptate. Excepteur deserunt tempor laboris quis.','registered':'Wednesday, March 16, 2016 6:53 AM','latitude':'50.328393','longitude':'-25.990308','tags':['ea','fugiat','duis','consectetur','enim'],'greeting':'Hello, Stout! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed0f52176c8c3e1bed','index':32,'guid':'743abcbd-1fab-4aed-8cb7-3c935eb64c74','isActive':false,'balance':'$1,118.54','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Ortega','last':'Joseph'},'company':'APEXIA','email':'ortega.joseph@apexia.ca','phone':'+1 (872) 596-3024','address':'304 Canda Avenue, Mulino, New York, 8721','about':'Ipsum elit id cupidatat minim nisi minim. Ea ex amet ea ipsum Lorem deserunt. Occaecat cupidatat magna cillum aliquip sint id quis amet nostrud officia enim laborum. Aliqua deserunt amet commodo laboris labore mollit est. Officia voluptate Lorem esse mollit aliquip laboris cupidatat minim et. Labore esse incididunt officia nostrud pariatur reprehenderit.','registered':'Tuesday, January 31, 2017 6:06 AM','latitude':'43.861714','longitude':'33.771783','tags':['ut','Lorem','esse','quis','fugiat'],'greeting':'Hello, Ortega! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed2c00cdd101b6cd52','index':33,'guid':'4f6f99cf-f692-4d03-b23a-26f2b27273bd','isActive':true,'balance':'$1,682.91','picture':'http://placehold.it/32x32','age':20,'eyeColor':'blue','name':{'first':'Sampson','last':'Taylor'},'company':'GEOFORMA','email':'sampson.taylor@geoforma.info','phone':'+1 (911) 482-2993','address':'582 Kent Street, Umapine, Virgin Islands, 5300','about':'Voluptate laboris occaecat laboris tempor cillum quis cupidatat qui pariatur. Lorem minim commodo mollit adipisicing Lorem ut dolor consectetur ipsum. Sint sit voluptate labore aliqua ex labore velit. Ullamco tempor consectetur voluptate deserunt voluptate minim enim. Cillum commodo duis reprehenderit eu duis.','registered':'Thursday, November 9, 2017 11:24 PM','latitude':'24.949379','longitude':'155.034468','tags':['Lorem','cupidatat','elit','reprehenderit','commodo'],'greeting':'Hello, Sampson! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed4b7210ba0bc0d508','index':34,'guid':'73fd415f-f8cf-43e0-a86c-e725d000abd4','isActive':false,'balance':'$1,289.37','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Shari','last':'Melendez'},'company':'DIGIPRINT','email':'shari.melendez@digiprint.tv','phone':'+1 (914) 475-3995','address':'950 Wolf Place, Enetai, Alaska, 693','about':'Dolor incididunt et est commodo aliquip labore ad ullamco. Velit ex cillum nulla elit ex esse. Consectetur mollit fugiat cillum proident elit sunt non officia cillum ex laboris sint eu. Esse nulla eu officia in Lorem sint minim esse velit. Est Lorem ipsum enim aute. Elit minim eiusmod officia reprehenderit officia ut irure Lorem.','registered':'Wednesday, August 23, 2017 11:12 PM','latitude':'-70.347863','longitude':'94.812072','tags':['ea','ex','fugiat','duis','eu'],'greeting':'Hello, Shari! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed85ac364619d892ef','index':35,'guid':'c1905f34-14ff-4bd8-b683-02cac4d52623','isActive':false,'balance':'$2,538.50','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Santiago','last':'Joyner'},'company':'BRAINCLIP','email':'santiago.joyner@brainclip.co.uk','phone':'+1 (835) 405-2676','address':'554 Rose Street, Muir, Kentucky, 7752','about':'Quis culpa dolore fugiat magna culpa non deserunt consectetur elit. Id cupidatat occaecat duis irure ullamco elit in labore magna pariatur cillum est. Mollit dolore velit ipsum anim aliqua culpa sint. Occaecat aute anim ut sunt eu.','registered':'Thursday, January 18, 2018 4:49 PM','latitude':'57.057918','longitude':'-50.472596','tags':['ullamco','ullamco','sunt','voluptate','irure'],'greeting':'Hello, Santiago! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1763f56b1121fa88','index':36,'guid':'a7f50659-4ae3-4f3e-a9d8-087e05334b51','isActive':false,'balance':'$1,435.16','picture':'http://placehold.it/32x32','age':37,'eyeColor':'blue','name':{'first':'Adeline','last':'Hoffman'},'company':'BITREX','email':'adeline.hoffman@bitrex.io','phone':'+1 (823) 488-3201','address':'221 Corbin Place, Edmund, Palau, 193','about':'Magna ullamco consectetur velit adipisicing cillum ea. Est qui incididunt est ullamco ex aute exercitation irure. Cupidatat consectetur proident qui fugiat do. Labore magna aliqua consectetur fugiat. Excepteur deserunt sit qui dolor fugiat aute sunt anim ipsum magna ea commodo qui. Minim eu adipisicing ut irure excepteur eiusmod aliqua. Voluptate nisi ad consequat qui.','registered':'Tuesday, June 14, 2016 9:26 AM','latitude':'-53.123355','longitude':'88.180776','tags':['non','est','commodo','ut','aliquip'],'greeting':'Hello, Adeline! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed945d079f63e3185e','index':37,'guid':'1f4619e0-9289-4bea-a9db-a75f4cba1138','isActive':true,'balance':'$2,019.54','picture':'http://placehold.it/32x32','age':36,'eyeColor':'blue','name':{'first':'Porter','last':'Morse'},'company':'COMVOY','email':'porter.morse@comvoy.me','phone':'+1 (933) 562-3220','address':'416 India Street, Bourg, Rhode Island, 2266','about':'Et sint anim et sunt. Non mollit sunt cillum veniam sunt sint amet non mollit. Fugiat ea ullamco pariatur deserunt ex do minim irure irure.','registered':'Saturday, July 16, 2016 10:03 PM','latitude':'-81.782545','longitude':'69.783509','tags':['irure','consequat','veniam','nulla','velit'],'greeting':'Hello, Porter! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed411dd0f06c66bba6','index':38,'guid':'93c900f0-54c0-4c4c-b21d-d59d8d7c6177','isActive':true,'balance':'$3,764.84','picture':'http://placehold.it/32x32','age':26,'eyeColor':'green','name':{'first':'Fitzgerald','last':'Logan'},'company':'UTARIAN','email':'fitzgerald.logan@utarian.com','phone':'+1 (815) 461-2709','address':'498 Logan Street, Tonopah, Arkansas, 6652','about':'Quis Lorem sit est et dolor est esse in veniam. Mollit anim nostrud laboris consequat voluptate qui ad ipsum sint laborum exercitation quis ipsum. Incididunt cupidatat esse ea amet deserunt consequat eu proident duis adipisicing pariatur. Amet deserunt mollit aliquip mollit consequat sunt quis labore laboris quis. Magna cillum fugiat anim velit Lorem duis. Lorem duis amet veniam occaecat est excepteur ut ea velit esse non pariatur. Do veniam quis eu consequat ad duis incididunt minim dolore sit non minim adipisicing et.','registered':'Wednesday, August 9, 2017 9:20 PM','latitude':'24.480657','longitude':'-108.693421','tags':['dolore','ad','occaecat','quis','labore'],'greeting':'Hello, Fitzgerald! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edbb6f14559d8a7b28','index':39,'guid':'9434f48b-70a0-4161-8d06-c53bf8b9df94','isActive':true,'balance':'$3,713.47','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Mcconnell','last':'Nash'},'company':'TETAK','email':'mcconnell.nash@tetak.org','phone':'+1 (956) 477-3586','address':'853 Turnbull Avenue, Clarence, Missouri, 1599','about':'Culpa excepteur minim anim magna dolor dolore ad ex eu. In cupidatat cillum elit dolore in est minim dolore consectetur reprehenderit voluptate laborum. Deserunt id velit ad dolor mollit.','registered':'Saturday, November 10, 2018 9:27 AM','latitude':'1.691589','longitude':'143.704377','tags':['ut','deserunt','sit','cupidatat','ea'],'greeting':'Hello, Mcconnell! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed1a87ea0390733ffa','index':40,'guid':'ec8a55f7-7114-4787-b1ff-4e631731bc2c','isActive':true,'balance':'$2,200.71','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Kitty','last':'Meyers'},'company':'FIBEROX','email':'kitty.meyers@fiberox.net','phone':'+1 (864) 458-3826','address':'537 Georgia Avenue, Thermal, Illinois, 7930','about':'Non excepteur laboris Lorem magna adipisicing exercitation. Anim esse in pariatur minim ipsum qui voluptate irure. Pariatur Lorem pariatur esse commodo aute adipisicing anim commodo. Exercitation nostrud aliqua duis et amet amet tempor.','registered':'Tuesday, September 13, 2016 8:16 PM','latitude':'19.59506','longitude':'-57.814297','tags':['duis','ullamco','velit','sint','consequat'],'greeting':'Hello, Kitty! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed4dc76717bf1217b3','index':41,'guid':'40521cde-f835-4620-902b-af7abf185d8d','isActive':false,'balance':'$2,907.02','picture':'http://placehold.it/32x32','age':26,'eyeColor':'green','name':{'first':'Klein','last':'Goodwin'},'company':'PLASTO','email':'klein.goodwin@plasto.name','phone':'+1 (950) 563-3104','address':'764 Devoe Street, Lindcove, Oklahoma, 458','about':'Amet aliqua magna ea veniam non aliquip irure esse id ipsum cillum sint tempor dolor. Ullamco deserunt fugiat amet pariatur culpa nostrud commodo commodo. Ad occaecat magna adipisicing voluptate. Minim ad adipisicing cupidatat elit nostrud eu irure. Cupidatat occaecat aute magna consectetur dolore anim et. Ex voluptate velit exercitation laborum ad ullamco ad. Aliquip nulla ipsum dolore cillum qui nostrud eu adipisicing amet tempor do.','registered':'Tuesday, February 13, 2018 3:56 PM','latitude':'-27.168725','longitude':'-29.499285','tags':['minim','labore','do','deserunt','dolor'],'greeting':'Hello, Klein! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1ac77396b29aee9e','index':42,'guid':'7cfc03e3-30e9-4ae1-a1f5-f6c3223ca770','isActive':true,'balance':'$2,986.47','picture':'http://placehold.it/32x32','age':22,'eyeColor':'brown','name':{'first':'Isabelle','last':'Bishop'},'company':'GEEKNET','email':'isabelle.bishop@geeknet.us','phone':'+1 (908) 418-2642','address':'729 Willmohr Street, Aguila, Montana, 7510','about':'In nulla commodo nostrud sint. Elit et occaecat et aliqua aliquip magna esse commodo duis Lorem dolor magna enim deserunt. Ipsum pariatur reprehenderit ipsum adipisicing mollit incididunt ut. Sunt in consequat ex ut minim non qui anim labore. Deserunt minim voluptate in nulla occaecat.','registered':'Monday, September 15, 2014 6:22 AM','latitude':'-81.686947','longitude':'38.409291','tags':['proident','est','aliqua','veniam','anim'],'greeting':'Hello, Isabelle! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edb3a070c9469a4893','index':43,'guid':'3dec76b4-0b55-4765-a2fd-b8dbd9c82f8f','isActive':true,'balance':'$2,501.24','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Josefina','last':'Turner'},'company':'COMSTAR','email':'josefina.turner@comstar.biz','phone':'+1 (908) 566-3029','address':'606 Schenck Place, Brutus, Vermont, 8681','about':'Enim consectetur pariatur sint dolor nostrud est deserunt nulla quis pariatur sit. Ad aute incididunt nisi excepteur duis est velit voluptate ullamco occaecat magna reprehenderit aliquip. Proident deserunt consectetur non et exercitation elit dolore enim aliqua incididunt anim amet. Ex esse sint commodo minim aliqua ut irure. Proident ex culpa voluptate fugiat nisi. Sint commodo laboris excepteur minim ipsum labore tempor quis magna.','registered':'Saturday, December 31, 2016 6:38 AM','latitude':'35.275088','longitude':'24.30485','tags':['minim','ut','irure','Lorem','veniam'],'greeting':'Hello, Josefina! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1aa7d74128ee3d0f','index':44,'guid':'10599279-c367-46c4-9f7a-744c2e4bf6c9','isActive':true,'balance':'$1,753.06','picture':'http://placehold.it/32x32','age':27,'eyeColor':'blue','name':{'first':'Lily','last':'Haynes'},'company':'KIOSK','email':'lily.haynes@kiosk.ca','phone':'+1 (872) 451-2301','address':'509 Balfour Place, Grazierville, New Hampshire, 2750','about':'Nisi aliquip occaecat nostrud do sint qui nisi officia Lorem. Ad et et laboris nisi dolore aliqua eu. Aliqua veniam quis eu pariatur incididunt mollit id deserunt officia eiusmod. Consequat adipisicing do nisi voluptate eiusmod minim pariatur minim nisi nostrud culpa cupidatat. Irure consectetur id consequat adipisicing ullamco occaecat do. Ex proident ea quis nulla incididunt sunt excepteur incididunt. Aliquip minim nostrud non anim Lorem.','registered':'Tuesday, November 20, 2018 9:28 AM','latitude':'-12.677798','longitude':'114.506787','tags':['culpa','amet','elit','officia','irure'],'greeting':'Hello, Lily! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed74c76f2e84e201ce','index':45,'guid':'ec0a68d4-629e-46c9-9af7-f6ea867f02ba','isActive':true,'balance':'$1,477.93','picture':'http://placehold.it/32x32','age':23,'eyeColor':'green','name':{'first':'Shauna','last':'Pitts'},'company':'SPACEWAX','email':'shauna.pitts@spacewax.info','phone':'+1 (841) 406-2360','address':'348 Tabor Court, Westwood, Puerto Rico, 8297','about':'Aliquip irure officia magna ea magna mollit ea non amet deserunt. Veniam mollit labore culpa magna aliqua quis consequat est consectetur ea reprehenderit nostrud consequat aliqua. Mollit do ipsum mollit eiusmod.','registered':'Thursday, October 2, 2014 2:48 AM','latitude':'-55.17388','longitude':'-13.370494','tags':['anim','consectetur','cillum','veniam','duis'],'greeting':'Hello, Shauna! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed419e718484b16722','index':46,'guid':'b2d6101d-5646-43f4-8207-284494e5a990','isActive':false,'balance':'$2,006.96','picture':'http://placehold.it/32x32','age':27,'eyeColor':'brown','name':{'first':'Lawrence','last':'Boyer'},'company':'SKYPLEX','email':'lawrence.boyer@skyplex.tv','phone':'+1 (953) 548-2618','address':'464 Pilling Street, Blandburg, Arizona, 5531','about':'Culpa sit minim pariatur mollit cupidatat sunt duis. Nisi ea proident veniam exercitation adipisicing Lorem aliquip amet dolor voluptate in nisi. Non commodo anim sunt est fugiat laborum nisi aliqua non Lorem exercitation dolor. Laboris dolore do minim ut eiusmod enim magna cillum laborum consectetur aliquip minim enim Lorem. Veniam ex veniam occaecat aliquip elit aliquip est eiusmod minim minim adipisicing.','registered':'Wednesday, July 30, 2014 2:17 AM','latitude':'-78.681255','longitude':'139.960626','tags':['consequat','Lorem','incididunt','dolor','esse'],'greeting':'Hello, Lawrence! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed08a9024998292c70','index':47,'guid':'277de142-ebeb-4828-906a-7fd8bc0a738a','isActive':true,'balance':'$1,273.19','picture':'http://placehold.it/32x32','age':27,'eyeColor':'brown','name':{'first':'Sonya','last':'Stafford'},'company':'AQUACINE','email':'sonya.stafford@aquacine.co.uk','phone':'+1 (824) 581-3927','address':'641 Bowery Street, Hillsboro, Delaware, 7893','about':'Culpa labore ex reprehenderit mollit cupidatat dolore et ut quis in. Sint esse culpa enim culpa tempor exercitation veniam minim consectetur. Sunt est laboris minim quis incididunt exercitation laboris cupidatat fugiat ad. Deserunt ipsum do dolor cillum excepteur incididunt.','registered':'Thursday, March 26, 2015 1:10 PM','latitude':'-84.750592','longitude':'165.493533','tags':['minim','officia','dolore','ipsum','est'],'greeting':'Hello, Sonya! You have 8 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd5037f2c79ecde68','index':48,'guid':'2dc6532f-9a26-49aa-b444-8923896db89c','isActive':false,'balance':'$3,168.93','picture':'http://placehold.it/32x32','age':36,'eyeColor':'brown','name':{'first':'Marguerite','last':'Stuart'},'company':'ACCUFARM','email':'marguerite.stuart@accufarm.io','phone':'+1 (848) 535-2253','address':'301 Menahan Street, Sunnyside, Nebraska, 4809','about':'Deserunt sint labore voluptate amet anim culpa nostrud adipisicing enim cupidatat ullamco exercitation fugiat est. Magna dolor aute incididunt ea ad adipisicing. Do cupidatat ut officia officia culpa sit do.','registered':'Thursday, May 8, 2014 1:25 PM','latitude':'21.82277','longitude':'-7.368347','tags':['labore','nulla','ullamco','irure','adipisicing'],'greeting':'Hello, Marguerite! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edb26d315635818dae','index':49,'guid':'083a5eda-0a70-4f89-87f7-2cd386c0f22a','isActive':false,'balance':'$2,576.25','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Louella','last':'Holloway'},'company':'BEDDER','email':'louella.holloway@bedder.me','phone':'+1 (801) 425-3761','address':'545 Lafayette Avenue, Caledonia, Louisiana, 2816','about':'Qui exercitation occaecat dolore mollit. Fugiat cupidatat proident culpa fugiat quis. In cupidatat commodo elit ea enim occaecat esse exercitation nostrud occaecat veniam laboris fugiat. Nisi sunt reprehenderit aliqua reprehenderit tempor id dolore ullamco pariatur reprehenderit et eu ex pariatur.','registered':'Wednesday, November 5, 2014 1:10 AM','latitude':'36.385637','longitude':'77.949423','tags':['eu','irure','velit','non','aliquip'],'greeting':'Hello, Louella! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed77cd60a1abc1ecce','index':50,'guid':'2887c3c1-3eba-4237-a0db-1977eed94554','isActive':true,'balance':'$1,633.51','picture':'http://placehold.it/32x32','age':22,'eyeColor':'green','name':{'first':'Bates','last':'Carrillo'},'company':'ZOMBOID','email':'bates.carrillo@zomboid.com','phone':'+1 (934) 405-2006','address':'330 Howard Alley, Troy, Kansas, 4881','about':'Voluptate esse est ullamco anim tempor ea reprehenderit. Occaecat pariatur deserunt cillum laboris labore id exercitation esse ipsum ipsum ex aliquip. Sunt non elit est ea occaecat. Magna deserunt commodo aliqua ipsum est cillum dolor nisi. Ex duis est tempor tempor laboris do do quis id magna. Dolor do est elit eu laborum ullamco culpa consequat velit eiusmod tempor.','registered':'Saturday, May 28, 2016 3:56 AM','latitude':'83.310134','longitude':'-105.862836','tags':['est','commodo','ea','commodo','sunt'],'greeting':'Hello, Bates! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed5ec0ec299b471fb5','index':51,'guid':'512b5e67-f785-492e-9d94-e43ef8b399b8','isActive':false,'balance':'$3,032.22','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Floyd','last':'Yang'},'company':'FRENEX','email':'floyd.yang@frenex.org','phone':'+1 (924) 566-3304','address':'418 Quay Street, Chumuckla, Guam, 7743','about':'Irure sit velit exercitation dolore est nisi incididunt ut quis consectetur incididunt est dolor. Aute nisi enim esse aliquip enim culpa commodo consectetur. Duis laborum magna ad duis ipsum aliqua eiusmod cillum. Consectetur et duis eiusmod irure ad est nisi incididunt eiusmod labore. Pariatur proident in Lorem adipisicing mollit proident excepteur nulla do nostrud mollit eiusmod. Duis ad dolore irure fugiat anim laboris ipsum et sit duis ipsum voluptate. Lorem non aute exercitation qui ullamco officia minim sint pariatur ut dolor.','registered':'Wednesday, January 18, 2017 2:01 AM','latitude':'45.888721','longitude':'-41.232793','tags':['elit','in','esse','ea','officia'],'greeting':'Hello, Floyd! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed51e26ca89e5caf49','index':52,'guid':'4e0907f6-facc-46df-8952-73561a53fe33','isActive':true,'balance':'$3,767.41','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Gardner','last':'Carey'},'company':'KLUGGER','email':'gardner.carey@klugger.net','phone':'+1 (876) 481-3502','address':'131 Utica Avenue, Cannondale, Federated States Of Micronesia, 610','about':'Amet ad pariatur excepteur anim ex officia commodo proident aliqua occaecat consequat Lorem officia sit. Id minim velit nisi laboris nisi nulla incididunt eiusmod velit. Deserunt labore quis et tempor. Et labore exercitation laborum officia ullamco nostrud adipisicing laboris esse laborum aute anim elit. Sunt ad officia tempor esse et quis aliquip irure pariatur laborum id quis ex. Eu consequat nisi deserunt id eu proident ex minim aute nulla tempor ex.','registered':'Friday, February 21, 2014 6:42 AM','latitude':'-54.740231','longitude':'15.01484','tags':['commodo','laboris','occaecat','aliquip','adipisicing'],'greeting':'Hello, Gardner! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed52e3c9407105093a','index':53,'guid':'1d3b9e7a-1bc3-40ea-b808-1c33f0d48c70','isActive':true,'balance':'$1,113.30','picture':'http://placehold.it/32x32','age':26,'eyeColor':'blue','name':{'first':'Herman','last':'Rogers'},'company':'TALENDULA','email':'herman.rogers@talendula.name','phone':'+1 (818) 521-2005','address':'541 Norman Avenue, Winfred, Tennessee, 447','about':'Culpa ex laborum non ad ullamco officia. Nisi mollit mollit voluptate sit sint ullamco. Lorem exercitation nulla anim eiusmod deserunt magna sint. Officia sunt eiusmod aliqua reprehenderit sunt mollit sit cupidatat sint.','registered':'Wednesday, July 11, 2018 1:05 AM','latitude':'-20.708105','longitude':'-151.294563','tags':['exercitation','minim','officia','qui','enim'],'greeting':'Hello, Herman! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edfcb123d545b6edb4','index':54,'guid':'c0e0c669-4eed-43ee-bdd0-78fe6e9ca4d5','isActive':true,'balance':'$3,309.64','picture':'http://placehold.it/32x32','age':22,'eyeColor':'green','name':{'first':'Whitley','last':'Stark'},'company':'MUSAPHICS','email':'whitley.stark@musaphics.us','phone':'+1 (803) 476-2151','address':'548 Cobek Court, Chamizal, Indiana, 204','about':'Adipisicing veniam dolor ex sint sit id eu voluptate. Excepteur veniam proident exercitation id eu et sunt pariatur. Qui occaecat culpa aliqua nisi excepteur minim veniam. Est duis nulla laborum excepteur cillum pariatur sint incididunt. Velit commodo eu incididunt voluptate. Amet laboris laboris id adipisicing labore eiusmod consequat minim cillum et.','registered':'Thursday, March 27, 2014 9:10 AM','latitude':'71.219596','longitude':'51.012855','tags':['reprehenderit','mollit','laborum','voluptate','aliquip'],'greeting':'Hello, Whitley! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed81510dfc61602fcf','index':55,'guid':'7ec5c24d-f169-4399-a2a3-300c0f45e52e','isActive':false,'balance':'$3,721.04','picture':'http://placehold.it/32x32','age':23,'eyeColor':'green','name':{'first':'Gretchen','last':'Wade'},'company':'EWEVILLE','email':'gretchen.wade@eweville.biz','phone':'+1 (977) 598-3700','address':'721 Colonial Road, Brookfield, South Dakota, 3888','about':'Fugiat consequat sint ut ut et ullamco eiusmod deserunt pariatur. Veniam eiusmod esse fugiat mollit. Proident laboris minim qui do ipsum excepteur exercitation irure anim. Aliqua labore quis eu fugiat dolore ullamco velit Lorem voluptate ipsum nostrud eiusmod laborum proident.','registered':'Friday, October 12, 2018 10:59 AM','latitude':'41.937653','longitude':'63.378531','tags':['aute','cillum','ea','ex','aute'],'greeting':'Hello, Gretchen! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edf78f77d4a7d557bb','index':56,'guid':'8718ada7-6fd0-49ef-a405-29850503948b','isActive':false,'balance':'$3,341.33','picture':'http://placehold.it/32x32','age':32,'eyeColor':'blue','name':{'first':'Naomi','last':'Frye'},'company':'MAZUDA','email':'naomi.frye@mazuda.ca','phone':'+1 (825) 427-2255','address':'741 Coyle Street, Comptche, Pennsylvania, 8441','about':'Aliqua fugiat laborum quis ullamco cupidatat sit dolor nulla dolore. Do Lorem et ipsum culpa irure sit do dolor qui sit laboris aliqua. Ex consectetur irure in veniam reprehenderit amet do elit eiusmod est magna.','registered':'Thursday, January 9, 2014 7:18 AM','latitude':'41.078645','longitude':'-50.241966','tags':['do','aliquip','eiusmod','velit','id'],'greeting':'Hello, Naomi! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edbf45db2e072a48b4','index':57,'guid':'c158ebf7-fb8b-4ea8-adbf-8c51c6486715','isActive':true,'balance':'$2,811.55','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Lamb','last':'Johns'},'company':'DOGTOWN','email':'lamb.johns@dogtown.info','phone':'+1 (946) 530-3057','address':'559 Malbone Street, Kennedyville, California, 2052','about':'Eiusmod dolor labore cillum ad veniam elit voluptate voluptate pariatur est cupidatat. Laboris ut qui in cillum sunt dolore ut enim. Minim nostrud ex qui quis reprehenderit magna ipsum cupidatat irure minim laboris veniam irure. Fugiat velit deserunt aliquip in esse proident excepteur labore reprehenderit excepteur sunt in cupidatat exercitation. Ex pariatur irure mollit tempor non magna ex.','registered':'Friday, April 21, 2017 1:51 AM','latitude':'-61.403599','longitude':'-93.447102','tags':['aliquip','tempor','sint','enim','ipsum'],'greeting':'Hello, Lamb! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edbb9c88190cb59cf2','index':58,'guid':'f0de5ac5-eb28-491b-81c5-76d447c9055e','isActive':true,'balance':'$1,611.99','picture':'http://placehold.it/32x32','age':37,'eyeColor':'brown','name':{'first':'Lynette','last':'Cleveland'},'company':'ARTWORLDS','email':'lynette.cleveland@artworlds.tv','phone':'+1 (889) 596-3723','address':'439 Montauk Avenue, Felt, New Mexico, 9681','about':'Incididunt aliquip est aliquip est ullamco do consectetur dolor. Lorem mollit mollit dolor et ipsum ut qui veniam aute ea. Adipisicing reprehenderit culpa velit laborum adipisicing amet consectetur velit nisi. Ut qui proident ad cillum excepteur adipisicing quis labore. Duis velit culpa et excepteur eiusmod ex labore in nisi nostrud. Et ullamco minim excepteur ut enim reprehenderit consequat eiusmod laboris Lorem commodo exercitation qui laborum.','registered':'Wednesday, August 26, 2015 12:53 PM','latitude':'49.861336','longitude':'86.865926','tags':['reprehenderit','minim','in','minim','nostrud'],'greeting':'Hello, Lynette! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed5b760ddde7295fa8','index':59,'guid':'f8180d3f-c5c0-48b2-966e-a0b2a80f8e84','isActive':true,'balance':'$3,376.75','picture':'http://placehold.it/32x32','age':32,'eyeColor':'green','name':{'first':'Obrien','last':'Page'},'company':'GLASSTEP','email':'obrien.page@glasstep.co.uk','phone':'+1 (902) 583-3086','address':'183 Ridgewood Avenue, Vicksburg, Wisconsin, 7430','about':'Aute excepteur cillum exercitation duis Lorem irure labore elit. Labore magna cupidatat velit consectetur minim do Lorem in excepteur commodo ea consequat ullamco laborum. Ut in id occaecat eu quis duis id ea deserunt veniam.','registered':'Wednesday, March 29, 2017 12:13 AM','latitude':'-40.156154','longitude':'72.76301','tags':['excepteur','non','anim','nulla','anim'],'greeting':'Hello, Obrien! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed52985d3d8901d653','index':60,'guid':'d2e14fa1-8c54-4bcb-8a58-eb2e6f8d0e45','isActive':true,'balance':'$1,659.47','picture':'http://placehold.it/32x32','age':33,'eyeColor':'brown','name':{'first':'Knowles','last':'Goodman'},'company':'CENTREE','email':'knowles.goodman@centree.io','phone':'+1 (862) 563-3692','address':'504 Lott Street, Allensworth, Florida, 7148','about':'Do aliquip voluptate aliqua nostrud. Eu dolore ex occaecat pariatur aute laborum aute nulla aute amet. Excepteur sit laboris ad non anim ut officia ut ad exercitation officia dolore laboris. Esse voluptate minim deserunt nostrud exercitation laborum voluptate exercitation id laborum fugiat proident cupidatat proident. Nulla nostrud est sint adipisicing incididunt exercitation dolor sit et elit tempor occaecat sint culpa. Pariatur occaecat laboris pariatur laboris ad pariatur in cillum fugiat est fugiat. Proident eu id irure excepteur esse aute cillum adipisicing.','registered':'Wednesday, October 15, 2014 6:17 PM','latitude':'-15.73863','longitude':'87.422009','tags':['consequat','sint','tempor','veniam','culpa'],'greeting':'Hello, Knowles! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0eda00b73bdb7ea54e9','index':61,'guid':'c8a064db-0ec6-4832-9820-7280a0333709','isActive':true,'balance':'$3,701.14','picture':'http://placehold.it/32x32','age':35,'eyeColor':'brown','name':{'first':'Shepherd','last':'Todd'},'company':'ECRATIC','email':'shepherd.todd@ecratic.me','phone':'+1 (881) 444-3389','address':'450 Frank Court, Temperanceville, Ohio, 7006','about':'Voluptate cillum ad fugiat velit adipisicing sint consequat veniam Lorem reprehenderit. Cillum sit non deserunt consequat. Amet sunt pariatur non mollit ullamco proident sint dolore anim elit cupidatat anim do ullamco. Lorem Lorem incididunt ea elit consequat laboris enim duis quis Lorem id aute veniam consequat. Cillum veniam cillum sint qui Lorem fugiat culpa consequat. Est sint duis ut qui fugiat. Laborum pariatur velit et sunt mollit eiusmod excepteur culpa ex et officia.','registered':'Tuesday, October 10, 2017 2:01 AM','latitude':'82.951563','longitude':'-4.866954','tags':['eu','qui','proident','esse','ex'],'greeting':'Hello, Shepherd! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed0e51d1a7e2d9e559','index':62,'guid':'739c3d38-200d-4531-84d8-4e7c39ae5b8c','isActive':true,'balance':'$3,679.01','picture':'http://placehold.it/32x32','age':31,'eyeColor':'brown','name':{'first':'Rosalyn','last':'Heath'},'company':'ZAYA','email':'rosalyn.heath@zaya.com','phone':'+1 (865) 403-3520','address':'303 Henderson Walk, Hoehne, District Of Columbia, 4306','about':'Sint occaecat nulla mollit sint fugiat eu proident dolor labore consequat. Occaecat tempor excepteur do fugiat incididunt Lorem in ullamco dolore laborum. Cillum mollit aliquip excepteur aliquip sint sunt minim non irure irure. Cillum fugiat aliqua enim dolore. Nulla culpa culpa nostrud ad. Eiusmod culpa proident proident non est cupidatat eu sunt sit incididunt id nisi.','registered':'Wednesday, April 22, 2015 12:35 PM','latitude':'33.628504','longitude':'110.772802','tags':['consequat','ut','ex','labore','consectetur'],'greeting':'Hello, Rosalyn! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd5274c01d353d0c5','index':63,'guid':'8815fe55-8af1-4708-a62a-d554dbd74a4a','isActive':true,'balance':'$2,126.01','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Queen','last':'Harper'},'company':'TRI@TRIBALOG','email':'queen.harper@tri@tribalog.org','phone':'+1 (903) 592-3145','address':'926 Heath Place, Wawona, Maine, 7340','about':'Laborum cupidatat commodo aliquip reprehenderit. Excepteur eu labore duis minim minim voluptate aute nostrud deserunt ut velit ullamco. Adipisicing nisi occaecat laborum proident. Id reprehenderit eiusmod cupidatat qui aute consequat amet enim commodo duis non ipsum. Amet ut aliqua magna qui proident mollit aute.','registered':'Saturday, April 9, 2016 5:12 AM','latitude':'51.814216','longitude':'177.348115','tags':['cillum','ut','dolor','do','nisi'],'greeting':'Hello, Queen! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed126298b6ce62ed56','index':64,'guid':'001c87fe-182f-450f-903b-2e29a9bb0322','isActive':true,'balance':'$3,578.29','picture':'http://placehold.it/32x32','age':20,'eyeColor':'green','name':{'first':'Pauline','last':'Mills'},'company':'CRUSTATIA','email':'pauline.mills@crustatia.net','phone':'+1 (984) 582-3899','address':'899 Revere Place, Welch, Iowa, 216','about':'Tempor eu exercitation ut id. Deserunt ex reprehenderit veniam nisi. Aute laborum veniam velit dolore ut deserunt Lorem sit esse quis dolor ex do nisi. In dolor tempor officia id. Velit nisi culpa nostrud laborum officia incididunt laborum velit non quis id exercitation exercitation. Anim elit ullamco in enim Lorem culpa aliqua Lorem.','registered':'Monday, June 2, 2014 2:03 PM','latitude':'56.427576','longitude':'172.183669','tags':['pariatur','pariatur','pariatur','fugiat','Lorem'],'greeting':'Hello, Pauline! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed3e332ad9e8a178d8','index':65,'guid':'5ad7292b-feef-4a7e-b485-142cadfbe8ea','isActive':false,'balance':'$3,916.54','picture':'http://placehold.it/32x32','age':22,'eyeColor':'brown','name':{'first':'Garrett','last':'Richmond'},'company':'XYQAG','email':'garrett.richmond@xyqag.name','phone':'+1 (952) 584-3794','address':'233 Grove Street, Summerfield, Virginia, 4735','about':'Nostrud quis pariatur occaecat laborum laboris aliqua ut fugiat dolor. Commodo tempor excepteur enim nostrud Lorem. Aute elit nulla labore ad pariatur cupidatat Lorem qui cupidatat velit deserunt excepteur esse. Excepteur nulla et nostrud quis labore est veniam enim nisi laboris ut enim. Ea esse nulla anim excepteur reprehenderit deserunt voluptate minim qui labore adipisicing amet eu enim.','registered':'Wednesday, March 5, 2014 4:35 PM','latitude':'68.665041','longitude':'148.799524','tags':['irure','reprehenderit','minim','ea','do'],'greeting':'Hello, Garrett! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed541aa2ec47466ace','index':66,'guid':'9cda6f3c-c9ab-451c-bb19-2e4c8463d011','isActive':true,'balance':'$3,352.52','picture':'http://placehold.it/32x32','age':30,'eyeColor':'brown','name':{'first':'Cobb','last':'Whitley'},'company':'UNIA','email':'cobb.whitley@unia.us','phone':'+1 (888) 490-3342','address':'864 Belmont Avenue, Needmore, Massachusetts, 8286','about':'Nisi aliquip fugiat ipsum nisi ullamco minim pariatur labore. Sint labore anim do ad ad esse eu nostrud nulla commodo anim. Cillum anim enim duis cillum non do nisi aliquip veniam voluptate commodo aliqua laborum. Exercitation in do eu qui sint aliquip. Esse adipisicing deserunt deserunt qui anim aliqua occaecat et nostrud elit ea in anim cillum. Tempor mollit proident tempor sunt est sint laborum ullamco incididunt non. Velit aliqua sunt excepteur nisi qui eiusmod ipsum dolore aliquip velit ullamco ullamco.','registered':'Friday, May 23, 2014 7:11 PM','latitude':'-32.950581','longitude':'147.772494','tags':['mollit','adipisicing','irure','ad','minim'],'greeting':'Hello, Cobb! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed8186c3d6f34c2be3','index':67,'guid':'fee98f6d-d68a-4189-8180-b6cb337e537e','isActive':false,'balance':'$1,698.42','picture':'http://placehold.it/32x32','age':20,'eyeColor':'blue','name':{'first':'Brennan','last':'Tyler'},'company':'PODUNK','email':'brennan.tyler@podunk.biz','phone':'+1 (867) 498-2727','address':'599 Harkness Avenue, Gorst, American Samoa, 322','about':'Reprehenderit id sit qui id qui aute ea sit magna in qui proident. Excepteur ad nostrud do nostrud in incididunt voluptate adipisicing sint anim. Ullamco consequat minim nulla irure ex est irure reprehenderit deserunt voluptate dolore anim sunt. Occaecat dolore voluptate voluptate elit commodo nulla laborum ad do irure.','registered':'Friday, February 9, 2018 5:40 PM','latitude':'11.150893','longitude':'-85.298004','tags':['quis','minim','deserunt','cillum','laboris'],'greeting':'Hello, Brennan! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed075c9c4f7439818d','index':68,'guid':'1ef76b18-6b8d-4c3c-aca3-9fa2b43f0242','isActive':false,'balance':'$2,091.17','picture':'http://placehold.it/32x32','age':26,'eyeColor':'brown','name':{'first':'Neal','last':'Stephenson'},'company':'OTHERSIDE','email':'neal.stephenson@otherside.ca','phone':'+1 (820) 496-3344','address':'867 Wilson Street, Kidder, Colorado, 4599','about':'Do laboris enim proident in qui velit adipisicing magna anim. Amet proident non exercitation ipsum aliqua excepteur nostrud. Enim esse non sit in nostrud deserunt id laborum cillum deserunt consequat. Anim velit exercitation qui sit voluptate. Irure duis non veniam velit mollit exercitation id exercitation.','registered':'Thursday, November 13, 2014 11:00 PM','latitude':'54.809693','longitude':'1.877241','tags':['anim','duis','in','officia','sint'],'greeting':'Hello, Neal! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0eda0a2dc24db64b638','index':69,'guid':'194744fd-089b-40b6-a290-98a6ec30a415','isActive':false,'balance':'$3,191.67','picture':'http://placehold.it/32x32','age':24,'eyeColor':'brown','name':{'first':'Shields','last':'Hubbard'},'company':'MIRACULA','email':'shields.hubbard@miracula.info','phone':'+1 (885) 582-2001','address':'529 Eagle Street, Guilford, Nevada, 1460','about':'Eiusmod exercitation ut incididunt veniam commodo culpa ullamco mollit id adipisicing exercitation ad sint. Nostrud excepteur amet aliqua mollit incididunt laborum voluptate id anim. Nulla sint laboris dolor esse cupidatat laborum ex sint. Ex non sunt sit nulla.','registered':'Monday, February 13, 2017 6:22 AM','latitude':'-69.145209','longitude':'-40.69755','tags':['tempor','enim','qui','velit','elit'],'greeting':'Hello, Shields! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edf939c130177e074d','index':70,'guid':'303b176c-7803-4ed2-a35f-3e3c831793ef','isActive':false,'balance':'$2,359.09','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Coleen','last':'Knight'},'company':'BLEEKO','email':'coleen.knight@bleeko.tv','phone':'+1 (867) 423-3146','address':'527 Broadway , Bonanza, Marshall Islands, 4988','about':'Laboris nulla pariatur laborum ad aute excepteur sunt pariatur exercitation. Do nostrud qui ipsum ullamco et sint do Lorem cillum ullamco do. Exercitation labore excepteur commodo incididunt eiusmod proident consectetur adipisicing nostrud aute voluptate laboris. Commodo anim proident eiusmod pariatur est ea laborum incididunt qui tempor reprehenderit ullamco id. Eiusmod commodo nisi consectetur ut qui quis aliqua sit minim nostrud sunt laborum eiusmod adipisicing.','registered':'Sunday, May 6, 2018 8:03 AM','latitude':'70.729041','longitude':'113.052761','tags':['Lorem','ullamco','nulla','ullamco','commodo'],'greeting':'Hello, Coleen! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edae8b1ce688b61223','index':71,'guid':'7d6f3b1a-c367-4068-9e8e-1717d513ece3','isActive':false,'balance':'$2,911.07','picture':'http://placehold.it/32x32','age':21,'eyeColor':'brown','name':{'first':'Clark','last':'Ryan'},'company':'ECLIPSENT','email':'clark.ryan@eclipsent.co.uk','phone':'+1 (938) 562-2740','address':'500 Lewis Avenue, Rockbridge, North Dakota, 5133','about':'Adipisicing exercitation officia sit excepteur excepteur sunt sint amet. Aliqua ipsum sint laboris eiusmod esse culpa elit sunt. Dolore est consectetur est quis quis magna. Aliquip nostrud dolore ex pariatur. Anim nostrud duis exercitation ut magna magna culpa. Nisi irure id mollit labore non sit mollit occaecat Lorem est ipsum. Nulla est fugiat cillum nisi aliqua consectetur amet nulla nostrud esse.','registered':'Friday, July 24, 2015 9:28 AM','latitude':'-68.055815','longitude':'-50.926966','tags':['deserunt','ad','ad','ut','id'],'greeting':'Hello, Clark! You have 7 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed5d1e8df45d8ab4db','index':72,'guid':'ce85db37-7d04-4f4c-a4b0-78003533e5c6','isActive':false,'balance':'$1,127.43','picture':'http://placehold.it/32x32','age':21,'eyeColor':'green','name':{'first':'Dillon','last':'Hooper'},'company':'MEDESIGN','email':'dillon.hooper@medesign.io','phone':'+1 (929) 600-3797','address':'652 Mill Avenue, Elliston, Mississippi, 2958','about':'Dolore culpa qui exercitation nostrud do. Irure duis in ad ipsum aliqua aliquip nulla sit veniam officia quis occaecat est. Magna qui eiusmod pariatur aliquip minim commodo. Qui ex dolor excepteur consequat eiusmod occaecat. In officia ipsum do Lorem excepteur proident pariatur labore.','registered':'Monday, May 26, 2014 2:38 AM','latitude':'-36.032189','longitude':'86.865529','tags':['non','ut','ex','Lorem','quis'],'greeting':'Hello, Dillon! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edb84814579c3121b3','index':73,'guid':'d7303901-5186-4595-a759-22306f67d0a3','isActive':true,'balance':'$2,326.59','picture':'http://placehold.it/32x32','age':33,'eyeColor':'green','name':{'first':'Moreno','last':'Hull'},'company':'ZEAM','email':'moreno.hull@zeam.me','phone':'+1 (984) 586-3738','address':'265 Pine Street, Talpa, North Carolina, 6041','about':'Fugiat exercitation est ullamco anim. Exercitation proident id sunt culpa Lorem amet. Consectetur anim consectetur pariatur consequat consectetur amet excepteur voluptate ea velit duis eiusmod proident. In sint laborum cupidatat ea amet ex. Reprehenderit amet sunt dolor ullamco est ex deserunt.','registered':'Wednesday, January 24, 2018 8:52 PM','latitude':'84.956857','longitude':'113.210051','tags':['est','excepteur','anim','Lorem','dolor'],'greeting':'Hello, Moreno! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eda4eb9dcb92c82d06','index':74,'guid':'8ee28651-802e-4523-b676-c713f6e874b8','isActive':true,'balance':'$3,783.97','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Tracie','last':'Price'},'company':'ICOLOGY','email':'tracie.price@icology.com','phone':'+1 (897) 403-3768','address':'487 Sheffield Avenue, Vallonia, Wyoming, 276','about':'Voluptate laboris laborum aute ex sint voluptate officia proident. Sit esse nostrud cupidatat in veniam sit duis est. Do mollit elit exercitation aliqua id irure ex. Lorem reprehenderit do ullamco sint ea ad nisi ad ut.','registered':'Saturday, December 10, 2016 9:44 AM','latitude':'77.770464','longitude':'151.392903','tags':['incididunt','labore','aliquip','anim','minim'],'greeting':'Hello, Tracie! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed68ab1a55d1c35e6c','index':75,'guid':'deedd26a-8928-4064-9666-5c59ea8144b4','isActive':true,'balance':'$2,848.08','picture':'http://placehold.it/32x32','age':32,'eyeColor':'brown','name':{'first':'Montgomery','last':'Bruce'},'company':'CYTREK','email':'montgomery.bruce@cytrek.org','phone':'+1 (824) 414-2731','address':'397 Beach Place, Ellerslie, South Carolina, 967','about':'Mollit minim excepteur magna velit cillum excepteur exercitation anim id labore deserunt do. Fugiat ex et id ad. Duis excepteur laboris est nulla do id irure quis eiusmod do esse ut culpa in.','registered':'Tuesday, August 25, 2015 6:42 AM','latitude':'79.722631','longitude':'-7.516885','tags':['Lorem','sint','voluptate','proident','incididunt'],'greeting':'Hello, Montgomery! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd90e0abb1cc2b0aa','index':76,'guid':'a072159d-12db-4747-9c2a-e2486a53d043','isActive':false,'balance':'$2,723.54','picture':'http://placehold.it/32x32','age':40,'eyeColor':'green','name':{'first':'Zelma','last':'Salinas'},'company':'IMAGEFLOW','email':'zelma.salinas@imageflow.net','phone':'+1 (964) 555-3856','address':'584 Reeve Place, Nord, Georgia, 7473','about':'Aliqua proident excepteur duis cupidatat cillum amet esse esse consectetur ea. Officia sunt consequat nostrud minim enim dolore dolor duis cillum. Esse labore veniam sint laborum excepteur sint tempor do ad cupidatat aliquip laboris elit id. Velit reprehenderit ullamco velit ullamco adipisicing velit esse irure velit et.','registered':'Thursday, February 25, 2016 8:18 PM','latitude':'-32.880524','longitude':'115.180489','tags':['id','nulla','reprehenderit','consequat','reprehenderit'],'greeting':'Hello, Zelma! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed98d836c8da283bb2','index':77,'guid':'838bebad-cc20-44e9-9eb7-902a8ca25efb','isActive':false,'balance':'$3,488.91','picture':'http://placehold.it/32x32','age':20,'eyeColor':'green','name':{'first':'Shaw','last':'Parsons'},'company':'PEARLESEX','email':'shaw.parsons@pearlesex.name','phone':'+1 (912) 567-3580','address':'606 Ocean Avenue, Tyro, Northern Mariana Islands, 3367','about':'Laborum labore occaecat culpa pariatur nisi non adipisicing esse consectetur officia officia. Deserunt velit eu enim consectetur ut cillum aliqua occaecat dolor qui esse. Incididunt ad est ex eu culpa anim aliquip laborum. Aliqua consectetur velit exercitation magna minim nulla do ut excepteur enim aliquip et. Nostrud enim sunt amet amet proident aliqua velit dolore. Consectetur ipsum fugiat proident id est reprehenderit tempor irure commodo. Sit excepteur fugiat occaecat nulla Lorem et cillum.','registered':'Thursday, April 19, 2018 1:41 AM','latitude':'69.715573','longitude':'-118.481237','tags':['laboris','adipisicing','magna','voluptate','id'],'greeting':'Hello, Shaw! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed1101734633c6ebba','index':78,'guid':'8fd0c52a-9d74-4984-a608-d612ecd8ddf0','isActive':true,'balance':'$3,820.02','picture':'http://placehold.it/32x32','age':39,'eyeColor':'brown','name':{'first':'Jaime','last':'Beard'},'company':'IZZBY','email':'jaime.beard@izzby.us','phone':'+1 (820) 412-3806','address':'362 Hudson Avenue, Delco, New Jersey, 5684','about':'Ut cupidatat veniam nulla magna commodo sit duis veniam consectetur cupidatat elit quis tempor. Duis officia ullamco proident sunt non mollit excepteur. Nisi ex amet laboris proident duis reprehenderit et est aliqua mollit amet ad. Enim eu elit excepteur eu exercitation duis consequat culpa. Adipisicing reprehenderit duis Lorem reprehenderit dolor aliqua incididunt eiusmod consequat ad occaecat fugiat do laborum. Qui ad aliquip ex do sunt. Fugiat non ut fugiat eu.','registered':'Sunday, March 9, 2014 3:41 PM','latitude':'17.926318','longitude':'108.985996','tags':['ut','voluptate','veniam','non','commodo'],'greeting':'Hello, Jaime! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edcd125a89dcf18e0d','index':79,'guid':'eccaa4ca-0fa7-4b00-a1e3-fe7953403894','isActive':true,'balance':'$1,521.33','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Terra','last':'Sullivan'},'company':'ZANITY','email':'terra.sullivan@zanity.biz','phone':'+1 (995) 498-2714','address':'346 Congress Street, Tuttle, Maryland, 3152','about':'Incididunt enim veniam ut veniam quis dolore pariatur culpa ex. Cillum laboris dolor exercitation officia. Officia irure magna aliqua veniam officia ullamco culpa. Cillum enim velit ea sint sint officia labore ea adipisicing culpa laboris. Anim aute sint commodo culpa ex quis minim ut laborum.','registered':'Sunday, June 1, 2014 5:38 AM','latitude':'-4.655435','longitude':'5.851803','tags':['anim','non','anim','laborum','pariatur'],'greeting':'Hello, Terra! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed9b9fc3041a674c87','index':80,'guid':'9f95fa36-4e45-4c3f-9362-3d4d809bf57f','isActive':true,'balance':'$3,403.16','picture':'http://placehold.it/32x32','age':39,'eyeColor':'brown','name':{'first':'Sharpe','last':'Berger'},'company':'ZILLAN','email':'sharpe.berger@zillan.ca','phone':'+1 (913) 498-3005','address':'277 Bragg Street, Faywood, Texas, 6487','about':'Dolor duis id aute ea veniam amet ullamco id. Culpa deserunt irure mollit tempor dolore veniam culpa officia culpa laborum eiusmod. Ullamco tempor qui aliqua cupidatat veniam cillum eu ut ex minim eu in. Quis exercitation anim eiusmod tempor esse mollit exercitation cillum ipsum reprehenderit. Sint voluptate ipsum officia sint magna nulla tempor eiusmod eiusmod veniam. Consectetur non ad veniam exercitation voluptate non nostrud.','registered':'Tuesday, June 27, 2017 12:58 AM','latitude':'-0.54085','longitude':'106.258693','tags':['proident','eiusmod','commodo','excepteur','pariatur'],'greeting':'Hello, Sharpe! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed1a1866757bf675e0','index':81,'guid':'1b944a01-01d3-4846-94e3-630f4d0e51a3','isActive':true,'balance':'$2,038.61','picture':'http://placehold.it/32x32','age':28,'eyeColor':'brown','name':{'first':'Blanchard','last':'Ewing'},'company':'CONJURICA','email':'blanchard.ewing@conjurica.info','phone':'+1 (859) 593-3212','address':'252 Beaver Street, Kiskimere, Utah, 3255','about':'Labore magna aute adipisicing ut dolor sit ea. Officia culpa aute occaecat sit ex ullamco aliquip ad sit culpa. Ex in enim dolore ex est sit. Do irure nulla magna sint aliquip in duis aute. Magna ullamco sit labore ea tempor voluptate.','registered':'Monday, May 4, 2015 10:50 AM','latitude':'76.207595','longitude':'0.672563','tags':['proident','pariatur','officia','in','culpa'],'greeting':'Hello, Blanchard! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed987d82f4e22d939c','index':82,'guid':'97a90aee-3cee-4678-819e-24fb94279dc1','isActive':false,'balance':'$1,201.55','picture':'http://placehold.it/32x32','age':28,'eyeColor':'blue','name':{'first':'Wells','last':'Solomon'},'company':'CORPULSE','email':'wells.solomon@corpulse.tv','phone':'+1 (840) 539-3349','address':'159 Radde Place, Linganore, Idaho, 230','about':'Consequat dolore mollit sit irure cupidatat commodo. Incididunt cillum reprehenderit ullamco sit proident cupidatat occaecat reprehenderit officia. Ad anim Lorem elit in officia minim proident nisi commodo eiusmod ea Lorem dolore voluptate. Dolor aliquip est commodo Lorem dolor ut aliquip ut. Sit anim officia dolore excepteur aute enim cillum.','registered':'Friday, January 6, 2017 1:59 PM','latitude':'70.020883','longitude':'14.503588','tags':['mollit','aute','officia','nostrud','laboris'],'greeting':'Hello, Wells! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eddf7a904ea0d0bc2a','index':83,'guid':'fe639a0c-7517-43e6-b0da-cd9ca5b9e267','isActive':false,'balance':'$3,664.47','picture':'http://placehold.it/32x32','age':33,'eyeColor':'blue','name':{'first':'Natalia','last':'Brown'},'company':'SYNTAC','email':'natalia.brown@syntac.co.uk','phone':'+1 (952) 595-3513','address':'332 Lenox Road, Springville, Alabama, 8406','about':'Nulla consequat officia commodo ea sunt irure anim velit aliquip aliquip. Labore ullamco occaecat proident voluptate cillum labore minim nostrud excepteur. Qui fugiat nostrud cillum fugiat ullamco id commodo aliqua voluptate mollit id id laboris. Cillum qui duis duis sit adipisicing elit ut aliqua eu. Anim nisi aliqua sit mollit.','registered':'Sunday, July 30, 2017 1:02 PM','latitude':'31.937613','longitude':'-9.957927','tags':['magna','adipisicing','exercitation','tempor','consectetur'],'greeting':'Hello, Natalia! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed8823fa385cad4aa3','index':84,'guid':'5cf280da-f5f0-4cc6-9063-e9d5863c8c89','isActive':false,'balance':'$1,624.17','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Greene','last':'Waller'},'company':'ISOTRACK','email':'greene.waller@isotrack.io','phone':'+1 (838) 406-3608','address':'362 Albemarle Road, Gardiner, Michigan, 2764','about':'Ut nisi sit sint nulla dolor magna. Culpa occaecat adipisicing veniam proident excepteur tempor quis ex. Fugiat tempor laborum dolor adipisicing irure anim cupidatat ut exercitation ex sit. Cupidatat exercitation commodo sunt ex irure fugiat eu esse do ullamco mollit dolore cupidatat. Cupidatat magna incididunt officia dolore esse voluptate deserunt in laborum dolor. Sit fugiat Lorem eu ullamco. Laboris veniam quis cillum tempor ex fugiat cillum cupidatat.','registered':'Sunday, June 10, 2018 10:32 PM','latitude':'0.256921','longitude':'-96.141941','tags':['magna','dolore','deserunt','aliquip','cillum'],'greeting':'Hello, Greene! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eda7c905c2d24c7d31','index':85,'guid':'aa30a9fb-8a16-48eb-8bb7-1307d1e1f191','isActive':false,'balance':'$1,974.04','picture':'http://placehold.it/32x32','age':36,'eyeColor':'green','name':{'first':'Carlene','last':'Hanson'},'company':'DIGIRANG','email':'carlene.hanson@digirang.me','phone':'+1 (981) 417-3209','address':'435 Clark Street, Choctaw, Oregon, 9888','about':'Amet labore esse cillum irure laborum consectetur occaecat non aliquip aliquip proident. Nisi magna nulla officia duis labore aute nulla laborum duis tempor minim. Velit elit reprehenderit nisi exercitation officia incididunt amet cupidatat excepteur proident consectetur.','registered':'Thursday, April 20, 2017 6:13 AM','latitude':'68.529086','longitude':'68.802409','tags':['pariatur','nulla','qui','amet','labore'],'greeting':'Hello, Carlene! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed6fbee12ce9e55dbf','index':86,'guid':'0fce89aa-3310-48df-862a-68bd3d776644','isActive':false,'balance':'$3,909.64','picture':'http://placehold.it/32x32','age':40,'eyeColor':'brown','name':{'first':'Doris','last':'Collins'},'company':'ZIORE','email':'doris.collins@ziore.com','phone':'+1 (914) 405-2360','address':'301 Lorraine Street, Stouchsburg, Minnesota, 7476','about':'Nisi deserunt aliquip et deserunt ipsum ad consectetur est non ullamco. Dolore do ut voluptate do eiusmod. Culpa ad in eiusmod nisi cillum do. Officia magna cillum sint aliqua reprehenderit amet est ipsum. Eiusmod deserunt commodo proident consequat. Amet minim dolor consequat aliquip aliquip culpa non exercitation non.','registered':'Wednesday, February 25, 2015 9:15 PM','latitude':'-57.364906','longitude':'130.766587','tags':['nulla','deserunt','cillum','eiusmod','adipisicing'],'greeting':'Hello, Doris! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edede9402476c398c0','index':87,'guid':'60cf0aa6-bc6d-4305-8842-d27e6af1306f','isActive':false,'balance':'$2,817.53','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Cline','last':'Hayden'},'company':'ECRAZE','email':'cline.hayden@ecraze.org','phone':'+1 (965) 507-2138','address':'352 Rutland Road, Ebro, Connecticut, 1196','about':'Dolor eiusmod enim anim sit enim ea tempor. Tempor amet consectetur aliquip culpa do ex excepteur deserunt. Dolor commodo veniam culpa sint. Commodo consectetur pariatur irure nisi deserunt cillum est dolor ipsum ea.','registered':'Thursday, September 29, 2016 5:58 AM','latitude':'62.50713','longitude':'86.247286','tags':['enim','tempor','anim','veniam','proident'],'greeting':'Hello, Cline! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edeb72f151994a551b','index':88,'guid':'dbb49c62-86b1-409f-b8b8-f609c709d2a8','isActive':false,'balance':'$3,122.56','picture':'http://placehold.it/32x32','age':39,'eyeColor':'green','name':{'first':'Janelle','last':'Rutledge'},'company':'TERRAGEN','email':'janelle.rutledge@terragen.net','phone':'+1 (914) 581-3749','address':'170 Falmouth Street, Alderpoint, West Virginia, 642','about':'Laboris proident cillum sunt qui ea sunt. Officia adipisicing exercitation dolore magna reprehenderit amet anim id. Laboris commodo sit irure irure. Excepteur est mollit fugiat incididunt consectetur veniam irure ea mollit. Cillum enim consequat sunt sunt nisi incididunt tempor enim.','registered':'Monday, February 16, 2015 5:46 AM','latitude':'-46.392023','longitude':'32.054562','tags':['eu','eu','nisi','labore','deserunt'],'greeting':'Hello, Janelle! You have 9 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edc9c2604846ff9a0d','index':89,'guid':'c4d7a365-f1d3-4584-b78e-008394c219f7','isActive':true,'balance':'$1,807.19','picture':'http://placehold.it/32x32','age':24,'eyeColor':'green','name':{'first':'Abby','last':'Lopez'},'company':'GRAINSPOT','email':'abby.lopez@grainspot.name','phone':'+1 (917) 442-3955','address':'488 Kensington Walk, Winston, Hawaii, 9109','about':'Incididunt deserunt Lorem proident magna tempor enim quis duis eu ut adipisicing in. Ex mollit non irure aliqua officia. Fugiat id ipsum consequat irure id ullamco culpa quis nulla enim aliquip consequat et. Dolor ut anim velit irure consequat cillum eu. Aute occaecat laborum est aliqua.','registered':'Sunday, April 1, 2018 11:28 PM','latitude':'-10.177041','longitude':'-165.756718','tags':['est','laborum','culpa','non','quis'],'greeting':'Hello, Abby! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed03237438b158af9e','index':90,'guid':'36c4a19f-2d00-4e40-bd49-155fd2ce0a6c','isActive':false,'balance':'$2,757.86','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Whitney','last':'Sheppard'},'company':'ANACHO','email':'whitney.sheppard@anacho.us','phone':'+1 (922) 437-2383','address':'951 Beekman Place, Homeworth, New York, 6088','about':'Sint minim nisi minim non minim aliqua pariatur ullamco do sint qui labore. Aute elit reprehenderit ad do fugiat est amet. In incididunt tempor commodo cillum tempor est labore anim.','registered':'Tuesday, September 13, 2016 6:43 PM','latitude':'-49.732527','longitude':'-171.846715','tags':['exercitation','veniam','sunt','est','proident'],'greeting':'Hello, Whitney! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edb99dd3aa53d2cb7f','index':91,'guid':'17afd430-f37f-4d55-958c-72f35cdb5997','isActive':false,'balance':'$3,683.86','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Ilene','last':'Blackwell'},'company':'ENQUILITY','email':'ilene.blackwell@enquility.biz','phone':'+1 (817) 555-2616','address':'950 Varanda Place, Belgreen, Virgin Islands, 1765','about':'Id eiusmod deserunt eiusmod adipisicing adipisicing est enim pariatur esse duis. Qui velit duis irure magna consectetur dolore reprehenderit. Cillum dolore minim consectetur irure non qui velit cillum veniam adipisicing incididunt. Deserunt veniam excepteur veniam velit aliquip labore quis exercitation magna do non dolor. Aliquip occaecat minim adipisicing deserunt fugiat nulla occaecat proident irure consectetur eiusmod irure. Enim Lorem deserunt amet Lorem commodo eiusmod reprehenderit occaecat adipisicing dolor voluptate cillum.','registered':'Thursday, February 1, 2018 8:39 AM','latitude':'57.393644','longitude':'-3.704258','tags':['adipisicing','dolor','commodo','Lorem','Lorem'],'greeting':'Hello, Ilene! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed353f4deb62c3342a','index':92,'guid':'9953e285-2095-4f1c-978b-9ece2a867e9d','isActive':false,'balance':'$1,202.44','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Dawson','last':'Herman'},'company':'BITENDREX','email':'dawson.herman@bitendrex.ca','phone':'+1 (843) 522-2655','address':'471 Channel Avenue, Denio, Alaska, 5040','about':'Nisi occaecat mollit reprehenderit nisi minim Lorem mollit. Ea proident irure cillum quis. Deserunt consectetur consectetur consequat quis enim minim ea ipsum proident nisi ad non aliquip. Veniam aute minim consequat irure voluptate aute amet excepteur exercitation cillum duis quis adipisicing nostrud.','registered':'Tuesday, December 8, 2015 5:40 PM','latitude':'-55.602721','longitude':'-26.683234','tags':['qui','dolor','deserunt','eiusmod','labore'],'greeting':'Hello, Dawson! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd5464bc50a5310ad','index':93,'guid':'724b2434-4dbd-417d-aa07-6065715f434f','isActive':false,'balance':'$1,595.98','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Alice','last':'Christian'},'company':'ZENOLUX','email':'alice.christian@zenolux.info','phone':'+1 (954) 466-2650','address':'875 Gerritsen Avenue, Townsend, Kentucky, 6568','about':'Nulla labore occaecat ex culpa magna. Commodo occaecat et in consequat cillum laborum magna adipisicing excepteur. Do ut Lorem esse voluptate officia ea aliquip proident amet veniam minim nulla adipisicing. Enim consectetur incididunt laborum voluptate tempor deserunt non laboris. Aliquip deserunt aute irure dolore magna anim aliquip sint magna Lorem. Officia laboris nulla officia sint labore nisi. Do Lorem id in est esse adipisicing id fugiat enim esse laborum.','registered':'Wednesday, October 3, 2018 9:26 PM','latitude':'-88.790637','longitude':'138.817328','tags':['duis','ea','magna','ea','incididunt'],'greeting':'Hello, Alice! You have 8 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0eda01886247b6a4f3d','index':94,'guid':'17c9f4d3-7d72-44e3-8f7c-08d7de920f46','isActive':false,'balance':'$3,173.29','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Schwartz','last':'Mccormick'},'company':'EVIDENDS','email':'schwartz.mccormick@evidends.tv','phone':'+1 (924) 531-2802','address':'160 Midwood Street, Indio, Palau, 4241','about':'Anim reprehenderit et et adipisicing voluptate consequat elit. Sint Lorem laboris Lorem minim nostrud aute reprehenderit elit aute quis nulla. Officia aute eiusmod mollit cillum eu aliquip non enim ea occaecat quis fugiat occaecat officia. Eiusmod culpa exercitation dolor aliqua enim occaecat nisi cupidatat duis ex dolore id. Id consequat aliqua cupidatat ut. Sit nisi est sunt culpa ullamco excepteur sunt pariatur incididunt amet. Ut tempor duis velit eu ut id culpa aute anim occaecat labore.','registered':'Thursday, March 2, 2017 5:57 PM','latitude':'38.618587','longitude':'-165.142529','tags':['ad','reprehenderit','magna','elit','mollit'],'greeting':'Hello, Schwartz! You have 10 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed51be4df456ec2bc9','index':95,'guid':'44f68f65-959b-4ec2-bd2a-1f30035f76fc','isActive':false,'balance':'$3,242.24','picture':'http://placehold.it/32x32','age':39,'eyeColor':'blue','name':{'first':'Bonita','last':'Stevens'},'company':'SLOFAST','email':'bonita.stevens@slofast.co.uk','phone':'+1 (886) 473-2105','address':'459 Bushwick Court, Kilbourne, Rhode Island, 9450','about':'Consequat reprehenderit qui reprehenderit nisi sit est in qui aliquip amet. Ex deserunt cupidatat amet cillum eiusmod irure anim in amet proident voluptate. Ad officia culpa in non incididunt do.','registered':'Saturday, August 22, 2015 5:23 AM','latitude':'60.013542','longitude':'58.242132','tags':['aute','adipisicing','in','cillum','officia'],'greeting':'Hello, Bonita! You have 5 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed50a55e3587993f68','index':96,'guid':'652e434f-221e-4899-af12-38dca5c9621d','isActive':false,'balance':'$2,720.06','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Charmaine','last':'Jackson'},'company':'FLUM','email':'charmaine.jackson@flum.io','phone':'+1 (947) 573-2692','address':'788 Windsor Place, Highland, Arkansas, 8869','about':'Dolore reprehenderit irure excepteur eu reprehenderit sint Lorem ut amet in. Consequat anim elit sunt aliquip incididunt. Culpa consequat do exercitation dolor enim dolor sunt sit excepteur ad anim. Dolor aute elit velit mollit minim eu.','registered':'Wednesday, April 6, 2016 7:54 PM','latitude':'25.756553','longitude':'-5.482531','tags':['amet','sint','consequat','est','ex'],'greeting':'Hello, Charmaine! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed213621949bbdd5d3','index':97,'guid':'7d7d93d8-3e37-4b4a-9fa2-591fb7d153ce','isActive':true,'balance':'$1,370.63','picture':'http://placehold.it/32x32','age':36,'eyeColor':'brown','name':{'first':'Petersen','last':'Cooley'},'company':'ROTODYNE','email':'petersen.cooley@rotodyne.me','phone':'+1 (929) 563-3339','address':'338 Pioneer Street, Carbonville, Missouri, 3030','about':'Cillum elit dolore labore aute. Cillum ea incididunt cupidatat consequat sint eu mollit. Excepteur commodo eiusmod ex Lorem enim velit minim.','registered':'Friday, December 8, 2017 5:53 AM','latitude':'-10.576254','longitude':'-111.176861','tags':['veniam','eu','eiusmod','dolore','voluptate'],'greeting':'Hello, Petersen! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed3e938138d58ed453','index':98,'guid':'d6fea4a3-03f6-46ee-90b9-8ec51a585e29','isActive':true,'balance':'$1,216.54','picture':'http://placehold.it/32x32','age':39,'eyeColor':'blue','name':{'first':'Rosanne','last':'Terry'},'company':'EXTREMO','email':'rosanne.terry@extremo.com','phone':'+1 (812) 496-2691','address':'368 Rockaway Avenue, Gloucester, Illinois, 7913','about':'Duis et nostrud duis quis minim eiusmod culpa do ea ad pariatur tempor. Velit veniam aliqua aliquip est enim ex et culpa dolor ullamco culpa officia. Eu id occaecat aute cillum aute sit aute laboris ipsum voluptate ex. Amet tempor minim tempor Lorem quis dolore. Pariatur consequat dolore nulla veniam dolor exercitation consequat nulla laboris incididunt do. Dolore do tempor deserunt exercitation incididunt officia incididunt ut do reprehenderit do eiusmod nulla.','registered':'Sunday, August 6, 2017 12:46 PM','latitude':'-43.257964','longitude':'-45.147686','tags':['et','incididunt','esse','commodo','ipsum'],'greeting':'Hello, Rosanne! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed632b1a1d65501d6b','index':99,'guid':'bf8c6ac1-ee18-48ee-ae94-ea515a53c951','isActive':true,'balance':'$2,905.58','picture':'http://placehold.it/32x32','age':21,'eyeColor':'blue','name':{'first':'Irene','last':'Castro'},'company':'POLARIA','email':'irene.castro@polaria.org','phone':'+1 (818) 417-3761','address':'901 Dupont Street, Sperryville, Oklahoma, 953','about':'Pariatur minim laboris aliqua dolor aliquip consequat ea do duis voluptate id Lorem. In reprehenderit et adipisicing anim elit incididunt velit in laborum laborum. Qui minim magna et amet sit do voluptate reprehenderit ea sit sint velit.','registered':'Tuesday, August 18, 2015 10:48 AM','latitude':'-7.004055','longitude':'116.052433','tags':['sit','proident','enim','ullamco','non'],'greeting':'Hello, Irene! You have 10 unread messages.','favoriteFruit':'apple'}]"
+  }
+}
diff --git a/v1.5.7/internal/cloud/testdata/plan-long-line/plan.log b/v1.5.7/internal/cloud/testdata/plan-long-line/plan.log
new file mode 100644
index 0000000..f34ed17
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-long-line/plan.log
@@ -0,0 +1,23 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id:                 <computed>
+      triggers.%:         "1"
+      triggers.long_line: "[{'_id':'5c5ab0ed7de45e993ffb9eeb','index':0,'guid':'e734d772-6b5a-4cb0-805c-91cd5e560e20','isActive':false,'balance':'$1,472.03','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Darlene','last':'Garza'},'company':'GEEKOSIS','email':'darlene.garza@geekosis.io','phone':'+1 (850) 506-3347','address':'165 Kiely Place, Como, New Mexico, 4335','about':'Officia ullamco et sunt magna voluptate culpa cupidatat ea tempor laboris cupidatat ea anim laboris. Minim enim quis enim esse laborum est veniam. Lorem excepteur elit Lorem cupidatat elit ea anim irure fugiat fugiat sunt mollit. Consectetur ad nulla dolor amet esse occaecat aliquip sit. Magna sit elit adipisicing ut reprehenderit anim exercitation sit quis ea pariatur Lorem magna dolore.','registered':'Wednesday, March 11, 2015 12:58 PM','latitude':'20.729127','longitude':'-127.343593','tags':['minim','in','deserunt','occaecat','fugiat'],'greeting':'Hello, Darlene! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eda9117d15f1c1f112','index':1,'guid':'f0d1eed2-c6a9-4535-8800-d4bd53fe7eee','isActive':true,'balance':'$2,901.90','picture':'http://placehold.it/32x32','age':28,'eyeColor':'brown','name':{'first':'Flora','last':'Short'},'company':'SIGNITY','email':'flora.short@signity.me','phone':'+1 (840) 520-2666','address':'636 Johnson Avenue, Gerber, Wisconsin, 9139','about':'Veniam dolore deserunt Lorem aliqua qui eiusmod. Amet tempor fugiat duis incididunt amet adipisicing. Id ea nisi veniam eiusmod.','registered':'Wednesday, May 2, 2018 5:59 AM','latitude':'-63.267612','longitude':'4.224102','tags':['veniam','incididunt','id','aliqua','reprehenderit'],'greeting':'Hello, Flora! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed83fd574d8041fa16','index':2,'guid':'29499a07-414a-436f-ba62-6634ca16bdcc','isActive':true,'balance':'$2,781.28','picture':'http://placehold.it/32x32','age':22,'eyeColor':'green','name':{'first':'Trevino','last':'Marks'},'company':'KEGULAR','email':'trevino.marks@kegular.com','phone':'+1 (843) 571-2269','address':'200 Alabama Avenue, Grenelefe, Florida, 7963','about':'Occaecat nisi exercitation Lorem mollit laborum magna adipisicing culpa dolor proident dolore. Non consequat ea amet et id mollit incididunt minim anim amet nostrud labore tempor. Proident eu sint commodo nisi consequat voluptate do fugiat proident. Laboris eiusmod veniam non et elit nulla nisi labore incididunt Lorem consequat consectetur voluptate.','registered':'Saturday, January 25, 2014 5:56 AM','latitude':'65.044005','longitude':'-127.454864','tags':['anim','duis','velit','pariatur','enim'],'greeting':'Hello, Trevino! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed784eb6e350ff0a07','index':3,'guid':'40ed47e2-1747-4665-ab59-cdb3630a7642','isActive':true,'balance':'$2,000.78','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Solis','last':'Mckinney'},'company':'QABOOS','email':'solis.mckinney@qaboos.org','phone':'+1 (924) 405-2560','address':'712 Herkimer Court, Klondike, Ohio, 8133','about':'Minim ad anim minim tempor mollit magna tempor et non commodo amet. Nisi cupidatat labore culpa consectetur exercitation laborum adipisicing fugiat officia adipisicing consequat non. Qui voluptate tempor laboris exercitation qui non adipisicing occaecat voluptate sunt do nostrud velit. Consequat tempor officia laboris tempor irure cupidatat aliquip voluptate nostrud velit ex nulla tempor laboris. Qui pariatur pariatur enim aliquip velit. Officia mollit ullamco laboris velit velit eiusmod enim amet incididunt consectetur sunt.','registered':'Wednesday, April 12, 2017 6:59 AM','latitude':'-25.055596','longitude':'-140.126525','tags':['ipsum','adipisicing','amet','nulla','dolore'],'greeting':'Hello, Solis! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed02ce1ea9a2155d51','index':4,'guid':'1b5fb7d3-3b9a-4382-81b5-9ab01a27e74b','isActive':true,'balance':'$1,373.67','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Janell','last':'Battle'},'company':'GEEKMOSIS','email':'janell.battle@geekmosis.net','phone':'+1 (810) 591-3014','address':'517 Onderdonk Avenue, Shrewsbury, District Of Columbia, 2335','about':'Reprehenderit ad proident do anim qui officia magna magna duis cillum esse minim est. Excepteur ipsum anim ad laboris. In occaecat dolore nulla ea Lorem tempor et culpa in sint. Officia eu eu incididunt sit amet. Culpa duis id reprehenderit ut anim sit sunt. Duis dolore proident velit incididunt adipisicing pariatur fugiat incididunt eiusmod eu veniam irure.','registered':'Thursday, February 8, 2018 1:44 AM','latitude':'-33.254864','longitude':'-154.145885','tags':['aute','deserunt','ipsum','eiusmod','laborum'],'greeting':'Hello, Janell! You have 5 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edab58604bd7d3dd1c','index':5,'guid':'6354c035-af22-44c9-8be9-b2ea9decc24d','isActive':true,'balance':'$3,535.68','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Combs','last':'Kirby'},'company':'LUXURIA','email':'combs.kirby@luxuria.name','phone':'+1 (900) 498-3266','address':'377 Kingsland Avenue, Ruckersville, Maine, 9916','about':'Lorem duis ipsum pariatur aliquip sunt. Commodo esse laborum incididunt mollit quis est laboris ea ea quis fugiat. Enim elit ullamco velit et fugiat veniam irure deserunt aliqua ad irure veniam.','registered':'Tuesday, February 21, 2017 4:04 PM','latitude':'-70.20591','longitude':'162.546871','tags':['reprehenderit','est','enim','aute','ad'],'greeting':'Hello, Combs! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edf7fafeffc6357c51','index':6,'guid':'02523e0b-cc90-4309-b6b2-f493dc6076f6','isActive':false,'balance':'$3,754.30','picture':'http://placehold.it/32x32','age':29,'eyeColor':'green','name':{'first':'Macias','last':'Calderon'},'company':'AMTAP','email':'macias.calderon@amtap.us','phone':'+1 (996) 569-3667','address':'305 Royce Street, Glidden, Iowa, 9248','about':'Exercitation nulla deserunt pariatur adipisicing. In commodo deserunt incididunt ut velit minim qui ut quis. Labore elit ullamco eiusmod voluptate in eu do est fugiat aute mollit deserunt. Eu duis proident velit fugiat velit ut. Ut non esse amet laborum nisi tempor in nulla.','registered':'Thursday, October 23, 2014 10:28 PM','latitude':'32.371629','longitude':'60.155135','tags':['commodo','elit','velit','excepteur','aliqua'],'greeting':'Hello, Macias! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed0e8a6109e7fabf17','index':7,'guid':'675ff6b6-197b-4154-9775-813d661df822','isActive':false,'balance':'$2,850.62','picture':'http://placehold.it/32x32','age':37,'eyeColor':'green','name':{'first':'Stefanie','last':'Rivers'},'company':'RECRITUBE','email':'stefanie.rivers@recritube.biz','phone':'+1 (994) 591-3551','address':'995 Campus Road, Abrams, Virginia, 3251','about':'Esse aute non laborum Lorem nulla irure. Veniam elit aute ut et dolor non deserunt laboris tempor. Ipsum quis cupidatat laborum laboris voluptate esse duis eiusmod excepteur consectetur commodo ullamco qui occaecat. Culpa velit cillum occaecat minim nisi.','registered':'Thursday, June 9, 2016 3:40 PM','latitude':'-18.526825','longitude':'149.670782','tags':['occaecat','sunt','reprehenderit','ipsum','magna'],'greeting':'Hello, Stefanie! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edf7d9bc2db4e476e3','index':8,'guid':'adaefc55-f6ea-4bd1-a147-0e31c3ce7a21','isActive':true,'balance':'$2,555.13','picture':'http://placehold.it/32x32','age':20,'eyeColor':'blue','name':{'first':'Hillary','last':'Lancaster'},'company':'OLUCORE','email':'hillary.lancaster@olucore.ca','phone':'+1 (964) 474-3018','address':'232 Berriman Street, Kaka, Massachusetts, 6792','about':'Veniam ad laboris quis reprehenderit aliquip nisi sunt excepteur ea aute laborum excepteur incididunt. Nisi exercitation aliquip do culpa commodo ex officia ut enim mollit in deserunt in amet. Anim eu deserunt dolore non cupidatat ut enim incididunt aute dolore voluptate. Do cillum mollit laborum non incididunt occaecat aute voluptate nisi irure.','registered':'Thursday, June 4, 2015 9:45 PM','latitude':'88.075919','longitude':'-148.951368','tags':['reprehenderit','veniam','ad','aute','anim'],'greeting':'Hello, Hillary! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed7b7192ad6a0f267c','index':9,'guid':'0ca9b8ea-f671-474e-be26-4a49cae4838a','isActive':true,'balance':'$3,684.51','picture':'http://placehold.it/32x32','age':40,'eyeColor':'brown','name':{'first':'Jill','last':'Conner'},'company':'EXOZENT','email':'jill.conner@exozent.info','phone':'+1 (887) 467-2168','address':'751 Thames Street, Juarez, American Samoa, 8386','about':'Enim voluptate et non est in magna laborum aliqua enim aliqua est non nostrud. Tempor est nulla ipsum consectetur esse nostrud est id. Consequat do voluptate cupidatat eu fugiat et fugiat velit id. Sint dolore ad qui tempor anim eu amet consectetur do elit aute adipisicing consequat ex.','registered':'Sunday, October 22, 2017 7:35 AM','latitude':'84.384911','longitude':'40.305648','tags':['tempor','sint','irure','et','ex'],'greeting':'Hello, Jill! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed713fe676575aa72b','index':10,'guid':'c28023cf-cc57-4c2e-8d91-dfbe6bafadcd','isActive':false,'balance':'$2,792.45','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Hurley','last':'George'},'company':'ZAJ','email':'hurley.george@zaj.tv','phone':'+1 (984) 547-3284','address':'727 Minna Street, Lacomb, Colorado, 2557','about':'Ex velit cupidatat veniam culpa. Eiusmod ut fugiat adipisicing incididunt consectetur exercitation Lorem exercitation ex. Incididunt anim aute incididunt fugiat cupidatat qui eu non reprehenderit. Eiusmod dolor nisi culpa excepteur ut velit minim dolor voluptate amet commodo culpa in.','registered':'Thursday, February 16, 2017 6:41 AM','latitude':'25.989949','longitude':'10.200053','tags':['minim','ut','sunt','consequat','ullamco'],'greeting':'Hello, Hurley! You have 8 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1e56732746c70d8b','index':11,'guid':'e9766f13-766c-4450-b4d2-8b04580f60b7','isActive':true,'balance':'$3,874.26','picture':'http://placehold.it/32x32','age':35,'eyeColor':'green','name':{'first':'Leticia','last':'Pace'},'company':'HONOTRON','email':'leticia.pace@honotron.co.uk','phone':'+1 (974) 536-3322','address':'365 Goodwin Place, Savage, Nevada, 9191','about':'Nisi Lorem aliqua esse eiusmod magna. Ad minim incididunt proident ut Lorem cupidatat qui velit aliqua ullamco et ipsum in. Aliquip elit consectetur pariatur esse exercitation et officia quis. Occaecat tempor proident cillum anim ad commodo velit ut voluptate. Tempor et occaecat sit sint aliquip tempor nulla velit magna nisi proident exercitation Lorem id.','registered':'Saturday, August 4, 2018 5:05 AM','latitude':'70.620386','longitude':'-86.335813','tags':['occaecat','velit','labore','laboris','esse'],'greeting':'Hello, Leticia! You have 8 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed941337fe42f47426','index':12,'guid':'6d390762-17ea-4b58-9a36-b0c9a8748a42','isActive':true,'balance':'$1,049.61','picture':'http://placehold.it/32x32','age':38,'eyeColor':'green','name':{'first':'Rose','last':'Humphrey'},'company':'MYOPIUM','email':'rose.humphrey@myopium.io','phone':'+1 (828) 426-3086','address':'389 Sapphire Street, Saticoy, Marshall Islands, 1423','about':'Aliquip enim excepteur adipisicing ex. Consequat aliqua consequat nostrud do occaecat deserunt excepteur sit et ipsum sunt dolor eu. Dolore laborum commodo excepteur tempor ad adipisicing proident excepteur magna non Lorem proident consequat aute. Fugiat minim consequat occaecat voluptate esse velit officia laboris nostrud nisi ut voluptate.','registered':'Monday, April 16, 2018 12:38 PM','latitude':'-47.083742','longitude':'109.022423','tags':['aute','non','sit','adipisicing','mollit'],'greeting':'Hello, Rose! You have 9 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd0c02fc3fdc01a40','index':13,'guid':'07755618-6fdf-4b33-af50-364c18909227','isActive':true,'balance':'$1,823.61','picture':'http://placehold.it/32x32','age':36,'eyeColor':'green','name':{'first':'Judith','last':'Hale'},'company':'COLLAIRE','email':'judith.hale@collaire.me','phone':'+1 (922) 508-2843','address':'193 Coffey Street, Castleton, North Dakota, 3638','about':'Minim non ullamco ad anim nostrud dolore nostrud veniam consequat id eiusmod veniam laboris. Lorem irure esse mollit non velit aute id cupidatat est mollit occaecat magna excepteur. Adipisicing tempor nisi sit aliquip tempor pariatur tempor eu consectetur nulla amet nulla. Quis nisi nisi ea incididunt culpa et do. Esse officia eu pariatur velit sunt quis proident amet consectetur consequat. Nisi excepteur culpa nulla sit dolor deserunt excepteur dolor consequat elit cillum tempor Lorem.','registered':'Wednesday, August 24, 2016 12:29 AM','latitude':'-80.15514','longitude':'39.91007','tags':['consectetur','incididunt','aliquip','dolor','consequat'],'greeting':'Hello, Judith! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edb3e1e29caa4f728b','index':14,'guid':'2c6617a2-e7a9-4ff7-a8b9-e99554fe70fe','isActive':true,'balance':'$1,971.00','picture':'http://placehold.it/32x32','age':39,'eyeColor':'blue','name':{'first':'Estes','last':'Sweet'},'company':'GEEKKO','email':'estes.sweet@geekko.com','phone':'+1 (866) 448-3032','address':'847 Cove Lane, Kula, Mississippi, 9178','about':'Veniam consectetur occaecat est excepteur consequat ipsum cillum sit consectetur. Ut cupidatat et reprehenderit dolore enim do cillum qui pariatur ad laborum incididunt esse. Fugiat sunt dolor veniam laboris ipsum deserunt proident reprehenderit laboris non nostrud. Magna excepteur sint magna laborum tempor sit exercitation ipsum labore est ullamco ullamco. Cillum voluptate cillum ea laborum Lorem. Excepteur sint ut nisi est esse non. Minim excepteur ullamco velit nisi ut in elit exercitation ut dolore.','registered':'Sunday, August 12, 2018 5:06 PM','latitude':'-9.57771','longitude':'-159.94577','tags':['culpa','dolor','velit','anim','pariatur'],'greeting':'Hello, Estes! You have 7 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edbcf088c6fd593091','index':15,'guid':'2cc79958-1b40-4e2c-907a-433903fd3da9','isActive':false,'balance':'$3,751.53','picture':'http://placehold.it/32x32','age':34,'eyeColor':'brown','name':{'first':'Kemp','last':'Spence'},'company':'EXOBLUE','email':'kemp.spence@exoblue.org','phone':'+1 (864) 487-2992','address':'217 Clay Street, Monument, North Carolina, 1460','about':'Nostrud duis cillum sint non commodo dolor aute aliqua adipisicing ad nulla non excepteur proident. Fugiat labore elit tempor cillum veniam reprehenderit laboris consectetur dolore amet qui cupidatat. Amet aliqua elit anim et consequat commodo excepteur officia anim aliqua ea eu labore cillum. Et ex dolor duis dolore commodo veniam et nisi.','registered':'Monday, October 29, 2018 5:23 AM','latitude':'-70.304222','longitude':'83.582371','tags':['velit','duis','consequat','incididunt','duis'],'greeting':'Hello, Kemp! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed6400479feb3de505','index':16,'guid':'91ccae6d-a3ea-43cf-bb00-3f2729256cc9','isActive':false,'balance':'$2,477.79','picture':'http://placehold.it/32x32','age':40,'eyeColor':'blue','name':{'first':'Ronda','last':'Burris'},'company':'EQUITOX','email':'ronda.burris@equitox.net','phone':'+1 (817) 553-3228','address':'708 Lawton Street, Deputy, Wyoming, 8598','about':'Excepteur voluptate aliquip consequat cillum est duis sit cillum eu eiusmod et laborum ullamco. Et minim reprehenderit aute voluptate amet ullamco. Amet sit enim ad irure deserunt nostrud anim veniam consequat dolor commodo. Consequat do occaecat do exercitation ullamco dolor ut. Id laboris consequat est dolor dolore tempor ullamco anim do ut nulla deserunt labore. Mollit ex Lorem ullamco mollit.','registered':'Monday, April 23, 2018 5:27 PM','latitude':'-31.227208','longitude':'0.63785','tags':['ipsum','magna','consectetur','sit','irure'],'greeting':'Hello, Ronda! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eddbeab2e53e04d563','index':17,'guid':'a86d4eb6-6bd8-48c2-a8fc-1c933c835852','isActive':false,'balance':'$3,709.03','picture':'http://placehold.it/32x32','age':37,'eyeColor':'blue','name':{'first':'Rosario','last':'Dillard'},'company':'BARKARAMA','email':'rosario.dillard@barkarama.name','phone':'+1 (933) 525-3898','address':'730 Chauncey Street, Forbestown, South Carolina, 6894','about':'Est eu fugiat aliquip ea ad qui ad mollit ad tempor voluptate et incididunt reprehenderit. Incididunt fugiat commodo minim adipisicing culpa consectetur duis eu ut commodo consequat voluptate labore. Nostrud irure labore adipisicing irure quis magna consequat dolor Lorem sint enim. Sint excepteur eu dolore elit ut do mollit sunt enim est. Labore id nostrud sint Lorem esse nostrud.','registered':'Friday, December 25, 2015 8:59 PM','latitude':'37.440827','longitude':'44.580474','tags':['Lorem','sit','ipsum','ea','ut'],'greeting':'Hello, Rosario! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eddf8e9b9c031d04e8','index':18,'guid':'a96f997c-daf8-40d4-92e1-be07e2cf0f60','isActive':false,'balance':'$1,878.37','picture':'http://placehold.it/32x32','age':37,'eyeColor':'brown','name':{'first':'Sondra','last':'Gonzales'},'company':'XUMONK','email':'sondra.gonzales@xumonk.us','phone':'+1 (838) 560-2255','address':'230 Cox Place, Geyserville, Georgia, 6805','about':'Laborum sunt voluptate ea laboris nostrud. Amet deserunt aliqua Lorem voluptate velit deserunt occaecat minim ullamco. Lorem occaecat sit labore adipisicing ad magna mollit labore ullamco proident. Ea velit do proident fugiat esse commodo ex nostrud eu mollit pariatur. Labore laborum qui voluptate quis proident reprehenderit tempor dolore duis deserunt esse aliqua aliquip. Non veniam enim pariatur cupidatat ipsum dolore est reprehenderit. Non exercitation adipisicing proident magna elit occaecat non magna.','registered':'Sunday, June 26, 2016 4:02 AM','latitude':'62.247742','longitude':'-44.90666','tags':['ea','aute','in','voluptate','magna'],'greeting':'Hello, Sondra! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed2c1bcd06781f677e','index':19,'guid':'6ac47a16-eed4-4460-92ee-e0dd33c1fbb5','isActive':false,'balance':'$3,730.64','picture':'http://placehold.it/32x32','age':20,'eyeColor':'brown','name':{'first':'Anastasia','last':'Vega'},'company':'FIREWAX','email':'anastasia.vega@firewax.biz','phone':'+1 (867) 493-3698','address':'803 Arlington Avenue, Rosburg, Northern Mariana Islands, 8769','about':'Sint ex nisi tempor sunt voluptate non et eiusmod irure. Aute reprehenderit dolor mollit aliqua Lorem voluptate occaecat. Sint laboris deserunt Lorem incididunt nulla cupidatat do.','registered':'Friday, March 18, 2016 12:02 PM','latitude':'-32.010216','longitude':'-87.874753','tags':['aliquip','mollit','mollit','ad','laborum'],'greeting':'Hello, Anastasia! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed727fd645854bbf43','index':20,'guid':'67bd8cdb-ce6b-455c-944c-a80e17c6fa75','isActive':true,'balance':'$2,868.06','picture':'http://placehold.it/32x32','age':29,'eyeColor':'green','name':{'first':'Lucinda','last':'Cox'},'company':'ENDIPINE','email':'lucinda.cox@endipine.ca','phone':'+1 (990) 428-3002','address':'412 Thatford Avenue, Lafferty, New Jersey, 5271','about':'Esse nulla sunt ut consequat aute mollit. Est occaecat sunt nisi irure id anim est commodo. Elit mollit amet dolore sunt adipisicing ea laborum quis ea reprehenderit non consequat dolore. Minim sunt occaecat quis aute commodo dolore quis commodo proident. Sunt sint duis ullamco sit ea esse Lorem. Consequat pariatur eiusmod laboris adipisicing labore in laboris adipisicing adipisicing consequat aute ea et.','registered':'Friday, May 1, 2015 10:16 PM','latitude':'-14.200957','longitude':'-82.211386','tags':['do','sit','qui','officia','aliquip'],'greeting':'Hello, Lucinda! You have 9 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed5a97284eb2cbd3a8','index':21,'guid':'f9fc999d-515c-4fc4-b339-76300e1b4bf2','isActive':true,'balance':'$1,172.57','picture':'http://placehold.it/32x32','age':35,'eyeColor':'brown','name':{'first':'Conrad','last':'Bradley'},'company':'FUELWORKS','email':'conrad.bradley@fuelworks.info','phone':'+1 (956) 561-3226','address':'685 Fenimore Street, Esmont, Maryland, 7523','about':'Labore reprehenderit anim nisi sunt do nisi in. Est anim cillum id minim exercitation ullamco voluptate ipsum eu. Elit culpa consequat reprehenderit laborum in eu. Laboris amet voluptate laboris qui voluptate duis minim reprehenderit. Commodo sunt irure dolore sunt occaecat velit nisi eu minim minim.','registered':'Wednesday, January 18, 2017 11:13 PM','latitude':'31.665993','longitude':'38.868968','tags':['excepteur','exercitation','est','nisi','mollit'],'greeting':'Hello, Conrad! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edc4eaf6f760c38218','index':22,'guid':'8794ef5f-da2f-46f0-a755-c18a16409fd5','isActive':false,'balance':'$3,594.73','picture':'http://placehold.it/32x32','age':27,'eyeColor':'blue','name':{'first':'Marquez','last':'Vargas'},'company':'MALATHION','email':'marquez.vargas@malathion.tv','phone':'+1 (976) 438-3126','address':'296 Hall Street, National, Texas, 2067','about':'Proident cillum aute minim fugiat sunt aliqua non occaecat est duis id id tempor. Qui deserunt nisi amet pariatur proident eu laboris esse adipisicing magna. Anim anim mollit aute non magna nisi aute magna labore ullamco reprehenderit voluptate et ad. Proident adipisicing aute eiusmod nostrud nostrud deserunt culpa. Elit eu ullamco nisi aliqua dolor sint pariatur excepteur sit consectetur tempor. Consequat Lorem ullamco commodo veniam qui sint magna. Sit mollit ad aliquip est id eu officia id adipisicing duis ad.','registered':'Tuesday, November 17, 2015 6:16 PM','latitude':'-36.443667','longitude':'22.336776','tags':['aliquip','veniam','ipsum','Lorem','ex'],'greeting':'Hello, Marquez! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edd7c718518ee0466a','index':23,'guid':'ad8781a2-059e-4288-9879-309d53a99bf5','isActive':true,'balance':'$3,570.68','picture':'http://placehold.it/32x32','age':21,'eyeColor':'brown','name':{'first':'Snider','last':'Frost'},'company':'ZILODYNE','email':'snider.frost@zilodyne.co.uk','phone':'+1 (913) 485-3275','address':'721 Lincoln Road, Richmond, Utah, 672','about':'Minim enim Lorem esse incididunt do reprehenderit velit laborum ullamco. In aute eiusmod esse aliqua et labore tempor sunt ex mollit veniam tempor. Nulla elit cillum qui ullamco dolore amet deserunt magna amet laborum.','registered':'Saturday, August 23, 2014 12:58 AM','latitude':'-88.682554','longitude':'74.063179','tags':['nulla','ea','sint','aliquip','duis'],'greeting':'Hello, Snider! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edf026fece8e2c0970','index':24,'guid':'1b7d81e1-1dba-4322-bb1a-eaa6a24cccea','isActive':false,'balance':'$2,037.91','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Snyder','last':'Fletcher'},'company':'COMTEST','email':'snyder.fletcher@comtest.io','phone':'+1 (830) 538-3860','address':'221 Lewis Place, Zortman, Idaho, 572','about':'Elit anim enim esse dolore exercitation. Laboris esse sint adipisicing fugiat sint do occaecat ut voluptate sint nulla. Ad sint ut reprehenderit nostrud irure id consectetur officia velit consequat.','registered':'Sunday, January 1, 2017 1:13 AM','latitude':'-54.742604','longitude':'69.534932','tags':['exercitation','commodo','in','id','aliqua'],'greeting':'Hello, Snyder! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed4b9a7f83da6d2dfd','index':25,'guid':'0b2cc6b6-0044-4b1c-aa31-bd72963457a0','isActive':false,'balance':'$1,152.76','picture':'http://placehold.it/32x32','age':27,'eyeColor':'blue','name':{'first':'Regina','last':'James'},'company':'TELPOD','email':'regina.james@telpod.me','phone':'+1 (989) 455-3228','address':'688 Essex Street, Clayville, Alabama, 2772','about':'Eiusmod elit culpa reprehenderit ea veniam. Officia irure culpa duis aute ut. Irure duis cillum officia ea pariatur velit ut dolor incididunt reprehenderit ex elit laborum. Est pariatur veniam ad irure. Labore velit sunt esse laboris aliqua velit deserunt deserunt sit. Elit eiusmod ad laboris aliquip minim irure excepteur enim quis. Quis incididunt adipisicing ut magna cupidatat sit amet culpa.','registered':'Tuesday, April 25, 2017 10:16 PM','latitude':'-75.088027','longitude':'47.209828','tags':['elit','nisi','est','voluptate','proident'],'greeting':'Hello, Regina! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed10884f32f779f2bf','index':26,'guid':'1f6fb522-0002-46ff-8dac-451247f28168','isActive':true,'balance':'$1,948.79','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Collins','last':'Mcpherson'},'company':'DIGIGEN','email':'collins.mcpherson@digigen.com','phone':'+1 (991) 519-2334','address':'317 Merit Court, Sanford, Michigan, 6468','about':'Magna qui culpa dolor officia labore mollit ex excepteur duis eiusmod. Ea cupidatat ex ipsum mollit do minim duis. Nisi eiusmod minim tempor id esse commodo sunt sunt ullamco ut do laborum ullamco magna. Aliquip laborum dolor officia officia eu nostrud velit minim est anim. Ex elit laborum sunt magna exercitation nisi cillum sunt aute qui ea ullamco. Cupidatat ea sunt aute dolor duis nisi Lorem ullamco eiusmod. Sit ea velit ad veniam aliqua ad elit cupidatat ut magna in.','registered':'Friday, June 10, 2016 4:38 PM','latitude':'25.513996','longitude':'14.911124','tags':['exercitation','non','sit','velit','officia'],'greeting':'Hello, Collins! You have 5 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed8a575110efb15c6c','index':27,'guid':'2a904c82-068b-4ded-9ae6-cfeb6d7e62c9','isActive':true,'balance':'$3,427.91','picture':'http://placehold.it/32x32','age':24,'eyeColor':'green','name':{'first':'Mckay','last':'Barrera'},'company':'COMVEYER','email':'mckay.barrera@comveyer.org','phone':'+1 (853) 470-2560','address':'907 Glenwood Road, Churchill, Oregon, 8583','about':'In voluptate esse dolore enim sint quis dolor do exercitation sint et labore nisi. Eiusmod tempor exercitation dolore elit sit velit sint et. Sit magna adipisicing eiusmod do anim velit deserunt laboris ad ea pariatur. Irure nisi anim mollit elit commodo nulla. Aute eiusmod sit nulla eiusmod. Eiusmod est officia commodo mollit laboris do deserunt eu do nisi amet. Proident ad duis eiusmod laboris Lorem ut culpa pariatur Lorem reprehenderit minim aliquip irure sunt.','registered':'Saturday, December 19, 2015 2:49 PM','latitude':'-55.243287','longitude':'138.035406','tags':['non','quis','laboris','enim','nisi'],'greeting':'Hello, Mckay! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edcd49ab6a73ff7f32','index':28,'guid':'5d3e0dae-3f58-437f-b12d-de24667a904d','isActive':true,'balance':'$3,270.52','picture':'http://placehold.it/32x32','age':35,'eyeColor':'blue','name':{'first':'Mabel','last':'Leonard'},'company':'QUADEEBO','email':'mabel.leonard@quadeebo.net','phone':'+1 (805) 432-2356','address':'965 Underhill Avenue, Falconaire, Minnesota, 4450','about':'Cupidatat amet sunt est ipsum occaecat sit fugiat excepteur Lorem Lorem ex ea ipsum. Ad incididunt est irure magna excepteur occaecat nostrud. Minim dolor id anim ipsum qui nostrud ullamco aute ex Lorem magna deserunt excepteur Lorem.','registered':'Saturday, March 28, 2015 5:55 AM','latitude':'27.388359','longitude':'156.408728','tags':['quis','velit','deserunt','dolore','sit'],'greeting':'Hello, Mabel! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edde16ac2dc2fbb6c1','index':29,'guid':'d50c2233-70fc-4748-8ebf-02d45ac2a446','isActive':false,'balance':'$3,100.70','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Pace','last':'Duke'},'company':'SEQUITUR','email':'pace.duke@sequitur.name','phone':'+1 (983) 568-3119','address':'895 Melrose Street, Reno, Connecticut, 6259','about':'Ex veniam aliquip exercitation mollit elit est minim veniam aliqua labore deserunt. Dolor sunt sint cillum Lorem nisi ea irure cupidatat. Velit ut culpa cupidatat consequat cillum. Sint voluptate quis laboris qui incididunt do elit Lorem qui ullamco ut eu pariatur occaecat.','registered':'Saturday, August 18, 2018 2:18 PM','latitude':'31.930443','longitude':'-129.494784','tags':['culpa','est','nostrud','quis','aliquip'],'greeting':'Hello, Pace! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edb908d85642ba77e8','index':30,'guid':'3edb6e42-367a-403d-a511-eb78bcc11f60','isActive':true,'balance':'$1,912.07','picture':'http://placehold.it/32x32','age':24,'eyeColor':'green','name':{'first':'Cohen','last':'Morrison'},'company':'POWERNET','email':'cohen.morrison@powernet.us','phone':'+1 (888) 597-2141','address':'565 Troutman Street, Idledale, West Virginia, 3196','about':'Ullamco voluptate duis commodo amet occaecat consequat et occaecat dolore nulla eu. Do aliqua sunt deserunt occaecat laboris labore voluptate cupidatat ullamco exercitation aliquip elit voluptate anim. Occaecat deserunt in labore cillum aute deserunt ea excepteur laboris sunt. Officia irure sint incididunt labore sint ipsum ullamco ea elit. Fugiat nostrud sunt ut officia mollit proident sunt dolor fugiat esse tempor do.','registered':'Friday, January 1, 2016 5:42 AM','latitude':'-20.01215','longitude':'26.361552','tags':['consectetur','sunt','nulla','reprehenderit','dolore'],'greeting':'Hello, Cohen! You have 10 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed91c77aa25a64a757','index':31,'guid':'8999a97b-0035-4f19-b555-91dd69aaa9b8','isActive':false,'balance':'$3,097.67','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Stout','last':'Valdez'},'company':'UPLINX','email':'stout.valdez@uplinx.biz','phone':'+1 (854) 480-3633','address':'880 Chestnut Avenue, Lowgap, Hawaii, 1537','about':'Cupidatat enim dolore non voluptate. Aliqua ut non Lorem in exercitation reprehenderit voluptate. Excepteur deserunt tempor laboris quis.','registered':'Wednesday, March 16, 2016 6:53 AM','latitude':'50.328393','longitude':'-25.990308','tags':['ea','fugiat','duis','consectetur','enim'],'greeting':'Hello, Stout! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed0f52176c8c3e1bed','index':32,'guid':'743abcbd-1fab-4aed-8cb7-3c935eb64c74','isActive':false,'balance':'$1,118.54','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Ortega','last':'Joseph'},'company':'APEXIA','email':'ortega.joseph@apexia.ca','phone':'+1 (872) 596-3024','address':'304 Canda Avenue, Mulino, New York, 8721','about':'Ipsum elit id cupidatat minim nisi minim. Ea ex amet ea ipsum Lorem deserunt. Occaecat cupidatat magna cillum aliquip sint id quis amet nostrud officia enim laborum. Aliqua deserunt amet commodo laboris labore mollit est. Officia voluptate Lorem esse mollit aliquip laboris cupidatat minim et. Labore esse incididunt officia nostrud pariatur reprehenderit.','registered':'Tuesday, January 31, 2017 6:06 AM','latitude':'43.861714','longitude':'33.771783','tags':['ut','Lorem','esse','quis','fugiat'],'greeting':'Hello, Ortega! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed2c00cdd101b6cd52','index':33,'guid':'4f6f99cf-f692-4d03-b23a-26f2b27273bd','isActive':true,'balance':'$1,682.91','picture':'http://placehold.it/32x32','age':20,'eyeColor':'blue','name':{'first':'Sampson','last':'Taylor'},'company':'GEOFORMA','email':'sampson.taylor@geoforma.info','phone':'+1 (911) 482-2993','address':'582 Kent Street, Umapine, Virgin Islands, 5300','about':'Voluptate laboris occaecat laboris tempor cillum quis cupidatat qui pariatur. Lorem minim commodo mollit adipisicing Lorem ut dolor consectetur ipsum. Sint sit voluptate labore aliqua ex labore velit. Ullamco tempor consectetur voluptate deserunt voluptate minim enim. Cillum commodo duis reprehenderit eu duis.','registered':'Thursday, November 9, 2017 11:24 PM','latitude':'24.949379','longitude':'155.034468','tags':['Lorem','cupidatat','elit','reprehenderit','commodo'],'greeting':'Hello, Sampson! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed4b7210ba0bc0d508','index':34,'guid':'73fd415f-f8cf-43e0-a86c-e725d000abd4','isActive':false,'balance':'$1,289.37','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Shari','last':'Melendez'},'company':'DIGIPRINT','email':'shari.melendez@digiprint.tv','phone':'+1 (914) 475-3995','address':'950 Wolf Place, Enetai, Alaska, 693','about':'Dolor incididunt et est commodo aliquip labore ad ullamco. Velit ex cillum nulla elit ex esse. Consectetur mollit fugiat cillum proident elit sunt non officia cillum ex laboris sint eu. Esse nulla eu officia in Lorem sint minim esse velit. Est Lorem ipsum enim aute. Elit minim eiusmod officia reprehenderit officia ut irure Lorem.','registered':'Wednesday, August 23, 2017 11:12 PM','latitude':'-70.347863','longitude':'94.812072','tags':['ea','ex','fugiat','duis','eu'],'greeting':'Hello, Shari! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed85ac364619d892ef','index':35,'guid':'c1905f34-14ff-4bd8-b683-02cac4d52623','isActive':false,'balance':'$2,538.50','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Santiago','last':'Joyner'},'company':'BRAINCLIP','email':'santiago.joyner@brainclip.co.uk','phone':'+1 (835) 405-2676','address':'554 Rose Street, Muir, Kentucky, 7752','about':'Quis culpa dolore fugiat magna culpa non deserunt consectetur elit. Id cupidatat occaecat duis irure ullamco elit in labore magna pariatur cillum est. Mollit dolore velit ipsum anim aliqua culpa sint. Occaecat aute anim ut sunt eu.','registered':'Thursday, January 18, 2018 4:49 PM','latitude':'57.057918','longitude':'-50.472596','tags':['ullamco','ullamco','sunt','voluptate','irure'],'greeting':'Hello, Santiago! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1763f56b1121fa88','index':36,'guid':'a7f50659-4ae3-4f3e-a9d8-087e05334b51','isActive':false,'balance':'$1,435.16','picture':'http://placehold.it/32x32','age':37,'eyeColor':'blue','name':{'first':'Adeline','last':'Hoffman'},'company':'BITREX','email':'adeline.hoffman@bitrex.io','phone':'+1 (823) 488-3201','address':'221 Corbin Place, Edmund, Palau, 193','about':'Magna ullamco consectetur velit adipisicing cillum ea. Est qui incididunt est ullamco ex aute exercitation irure. Cupidatat consectetur proident qui fugiat do. Labore magna aliqua consectetur fugiat. Excepteur deserunt sit qui dolor fugiat aute sunt anim ipsum magna ea commodo qui. Minim eu adipisicing ut irure excepteur eiusmod aliqua. Voluptate nisi ad consequat qui.','registered':'Tuesday, June 14, 2016 9:26 AM','latitude':'-53.123355','longitude':'88.180776','tags':['non','est','commodo','ut','aliquip'],'greeting':'Hello, Adeline! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed945d079f63e3185e','index':37,'guid':'1f4619e0-9289-4bea-a9db-a75f4cba1138','isActive':true,'balance':'$2,019.54','picture':'http://placehold.it/32x32','age':36,'eyeColor':'blue','name':{'first':'Porter','last':'Morse'},'company':'COMVOY','email':'porter.morse@comvoy.me','phone':'+1 (933) 562-3220','address':'416 India Street, Bourg, Rhode Island, 2266','about':'Et sint anim et sunt. Non mollit sunt cillum veniam sunt sint amet non mollit. Fugiat ea ullamco pariatur deserunt ex do minim irure irure.','registered':'Saturday, July 16, 2016 10:03 PM','latitude':'-81.782545','longitude':'69.783509','tags':['irure','consequat','veniam','nulla','velit'],'greeting':'Hello, Porter! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed411dd0f06c66bba6','index':38,'guid':'93c900f0-54c0-4c4c-b21d-d59d8d7c6177','isActive':true,'balance':'$3,764.84','picture':'http://placehold.it/32x32','age':26,'eyeColor':'green','name':{'first':'Fitzgerald','last':'Logan'},'company':'UTARIAN','email':'fitzgerald.logan@utarian.com','phone':'+1 (815) 461-2709','address':'498 Logan Street, Tonopah, Arkansas, 6652','about':'Quis Lorem sit est et dolor est esse in veniam. Mollit anim nostrud laboris consequat voluptate qui ad ipsum sint laborum exercitation quis ipsum. Incididunt cupidatat esse ea amet deserunt consequat eu proident duis adipisicing pariatur. Amet deserunt mollit aliquip mollit consequat sunt quis labore laboris quis. Magna cillum fugiat anim velit Lorem duis. Lorem duis amet veniam occaecat est excepteur ut ea velit esse non pariatur. Do veniam quis eu consequat ad duis incididunt minim dolore sit non minim adipisicing et.','registered':'Wednesday, August 9, 2017 9:20 PM','latitude':'24.480657','longitude':'-108.693421','tags':['dolore','ad','occaecat','quis','labore'],'greeting':'Hello, Fitzgerald! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edbb6f14559d8a7b28','index':39,'guid':'9434f48b-70a0-4161-8d06-c53bf8b9df94','isActive':true,'balance':'$3,713.47','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Mcconnell','last':'Nash'},'company':'TETAK','email':'mcconnell.nash@tetak.org','phone':'+1 (956) 477-3586','address':'853 Turnbull Avenue, Clarence, Missouri, 1599','about':'Culpa excepteur minim anim magna dolor dolore ad ex eu. In cupidatat cillum elit dolore in est minim dolore consectetur reprehenderit voluptate laborum. Deserunt id velit ad dolor mollit.','registered':'Saturday, November 10, 2018 9:27 AM','latitude':'1.691589','longitude':'143.704377','tags':['ut','deserunt','sit','cupidatat','ea'],'greeting':'Hello, Mcconnell! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed1a87ea0390733ffa','index':40,'guid':'ec8a55f7-7114-4787-b1ff-4e631731bc2c','isActive':true,'balance':'$2,200.71','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Kitty','last':'Meyers'},'company':'FIBEROX','email':'kitty.meyers@fiberox.net','phone':'+1 (864) 458-3826','address':'537 Georgia Avenue, Thermal, Illinois, 7930','about':'Non excepteur laboris Lorem magna adipisicing exercitation. Anim esse in pariatur minim ipsum qui voluptate irure. Pariatur Lorem pariatur esse commodo aute adipisicing anim commodo. Exercitation nostrud aliqua duis et amet amet tempor.','registered':'Tuesday, September 13, 2016 8:16 PM','latitude':'19.59506','longitude':'-57.814297','tags':['duis','ullamco','velit','sint','consequat'],'greeting':'Hello, Kitty! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed4dc76717bf1217b3','index':41,'guid':'40521cde-f835-4620-902b-af7abf185d8d','isActive':false,'balance':'$2,907.02','picture':'http://placehold.it/32x32','age':26,'eyeColor':'green','name':{'first':'Klein','last':'Goodwin'},'company':'PLASTO','email':'klein.goodwin@plasto.name','phone':'+1 (950) 563-3104','address':'764 Devoe Street, Lindcove, Oklahoma, 458','about':'Amet aliqua magna ea veniam non aliquip irure esse id ipsum cillum sint tempor dolor. Ullamco deserunt fugiat amet pariatur culpa nostrud commodo commodo. Ad occaecat magna adipisicing voluptate. Minim ad adipisicing cupidatat elit nostrud eu irure. Cupidatat occaecat aute magna consectetur dolore anim et. Ex voluptate velit exercitation laborum ad ullamco ad. Aliquip nulla ipsum dolore cillum qui nostrud eu adipisicing amet tempor do.','registered':'Tuesday, February 13, 2018 3:56 PM','latitude':'-27.168725','longitude':'-29.499285','tags':['minim','labore','do','deserunt','dolor'],'greeting':'Hello, Klein! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1ac77396b29aee9e','index':42,'guid':'7cfc03e3-30e9-4ae1-a1f5-f6c3223ca770','isActive':true,'balance':'$2,986.47','picture':'http://placehold.it/32x32','age':22,'eyeColor':'brown','name':{'first':'Isabelle','last':'Bishop'},'company':'GEEKNET','email':'isabelle.bishop@geeknet.us','phone':'+1 (908) 418-2642','address':'729 Willmohr Street, Aguila, Montana, 7510','about':'In nulla commodo nostrud sint. Elit et occaecat et aliqua aliquip magna esse commodo duis Lorem dolor magna enim deserunt. Ipsum pariatur reprehenderit ipsum adipisicing mollit incididunt ut. Sunt in consequat ex ut minim non qui anim labore. Deserunt minim voluptate in nulla occaecat.','registered':'Monday, September 15, 2014 6:22 AM','latitude':'-81.686947','longitude':'38.409291','tags':['proident','est','aliqua','veniam','anim'],'greeting':'Hello, Isabelle! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edb3a070c9469a4893','index':43,'guid':'3dec76b4-0b55-4765-a2fd-b8dbd9c82f8f','isActive':true,'balance':'$2,501.24','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Josefina','last':'Turner'},'company':'COMSTAR','email':'josefina.turner@comstar.biz','phone':'+1 (908) 566-3029','address':'606 Schenck Place, Brutus, Vermont, 8681','about':'Enim consectetur pariatur sint dolor nostrud est deserunt nulla quis pariatur sit. Ad aute incididunt nisi excepteur duis est velit voluptate ullamco occaecat magna reprehenderit aliquip. Proident deserunt consectetur non et exercitation elit dolore enim aliqua incididunt anim amet. Ex esse sint commodo minim aliqua ut irure. Proident ex culpa voluptate fugiat nisi. Sint commodo laboris excepteur minim ipsum labore tempor quis magna.','registered':'Saturday, December 31, 2016 6:38 AM','latitude':'35.275088','longitude':'24.30485','tags':['minim','ut','irure','Lorem','veniam'],'greeting':'Hello, Josefina! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed1aa7d74128ee3d0f','index':44,'guid':'10599279-c367-46c4-9f7a-744c2e4bf6c9','isActive':true,'balance':'$1,753.06','picture':'http://placehold.it/32x32','age':27,'eyeColor':'blue','name':{'first':'Lily','last':'Haynes'},'company':'KIOSK','email':'lily.haynes@kiosk.ca','phone':'+1 (872) 451-2301','address':'509 Balfour Place, Grazierville, New Hampshire, 2750','about':'Nisi aliquip occaecat nostrud do sint qui nisi officia Lorem. Ad et et laboris nisi dolore aliqua eu. Aliqua veniam quis eu pariatur incididunt mollit id deserunt officia eiusmod. Consequat adipisicing do nisi voluptate eiusmod minim pariatur minim nisi nostrud culpa cupidatat. Irure consectetur id consequat adipisicing ullamco occaecat do. Ex proident ea quis nulla incididunt sunt excepteur incididunt. Aliquip minim nostrud non anim Lorem.','registered':'Tuesday, November 20, 2018 9:28 AM','latitude':'-12.677798','longitude':'114.506787','tags':['culpa','amet','elit','officia','irure'],'greeting':'Hello, Lily! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed74c76f2e84e201ce','index':45,'guid':'ec0a68d4-629e-46c9-9af7-f6ea867f02ba','isActive':true,'balance':'$1,477.93','picture':'http://placehold.it/32x32','age':23,'eyeColor':'green','name':{'first':'Shauna','last':'Pitts'},'company':'SPACEWAX','email':'shauna.pitts@spacewax.info','phone':'+1 (841) 406-2360','address':'348 Tabor Court, Westwood, Puerto Rico, 8297','about':'Aliquip irure officia magna ea magna mollit ea non amet deserunt. Veniam mollit labore culpa magna aliqua quis consequat est consectetur ea reprehenderit nostrud consequat aliqua. Mollit do ipsum mollit eiusmod.','registered':'Thursday, October 2, 2014 2:48 AM','latitude':'-55.17388','longitude':'-13.370494','tags':['anim','consectetur','cillum','veniam','duis'],'greeting':'Hello, Shauna! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed419e718484b16722','index':46,'guid':'b2d6101d-5646-43f4-8207-284494e5a990','isActive':false,'balance':'$2,006.96','picture':'http://placehold.it/32x32','age':27,'eyeColor':'brown','name':{'first':'Lawrence','last':'Boyer'},'company':'SKYPLEX','email':'lawrence.boyer@skyplex.tv','phone':'+1 (953) 548-2618','address':'464 Pilling Street, Blandburg, Arizona, 5531','about':'Culpa sit minim pariatur mollit cupidatat sunt duis. Nisi ea proident veniam exercitation adipisicing Lorem aliquip amet dolor voluptate in nisi. Non commodo anim sunt est fugiat laborum nisi aliqua non Lorem exercitation dolor. Laboris dolore do minim ut eiusmod enim magna cillum laborum consectetur aliquip minim enim Lorem. Veniam ex veniam occaecat aliquip elit aliquip est eiusmod minim minim adipisicing.','registered':'Wednesday, July 30, 2014 2:17 AM','latitude':'-78.681255','longitude':'139.960626','tags':['consequat','Lorem','incididunt','dolor','esse'],'greeting':'Hello, Lawrence! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed08a9024998292c70','index':47,'guid':'277de142-ebeb-4828-906a-7fd8bc0a738a','isActive':true,'balance':'$1,273.19','picture':'http://placehold.it/32x32','age':27,'eyeColor':'brown','name':{'first':'Sonya','last':'Stafford'},'company':'AQUACINE','email':'sonya.stafford@aquacine.co.uk','phone':'+1 (824) 581-3927','address':'641 Bowery Street, Hillsboro, Delaware, 7893','about':'Culpa labore ex reprehenderit mollit cupidatat dolore et ut quis in. Sint esse culpa enim culpa tempor exercitation veniam minim consectetur. Sunt est laboris minim quis incididunt exercitation laboris cupidatat fugiat ad. Deserunt ipsum do dolor cillum excepteur incididunt.','registered':'Thursday, March 26, 2015 1:10 PM','latitude':'-84.750592','longitude':'165.493533','tags':['minim','officia','dolore','ipsum','est'],'greeting':'Hello, Sonya! You have 8 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd5037f2c79ecde68','index':48,'guid':'2dc6532f-9a26-49aa-b444-8923896db89c','isActive':false,'balance':'$3,168.93','picture':'http://placehold.it/32x32','age':36,'eyeColor':'brown','name':{'first':'Marguerite','last':'Stuart'},'company':'ACCUFARM','email':'marguerite.stuart@accufarm.io','phone':'+1 (848) 535-2253','address':'301 Menahan Street, Sunnyside, Nebraska, 4809','about':'Deserunt sint labore voluptate amet anim culpa nostrud adipisicing enim cupidatat ullamco exercitation fugiat est. Magna dolor aute incididunt ea ad adipisicing. Do cupidatat ut officia officia culpa sit do.','registered':'Thursday, May 8, 2014 1:25 PM','latitude':'21.82277','longitude':'-7.368347','tags':['labore','nulla','ullamco','irure','adipisicing'],'greeting':'Hello, Marguerite! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edb26d315635818dae','index':49,'guid':'083a5eda-0a70-4f89-87f7-2cd386c0f22a','isActive':false,'balance':'$2,576.25','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Louella','last':'Holloway'},'company':'BEDDER','email':'louella.holloway@bedder.me','phone':'+1 (801) 425-3761','address':'545 Lafayette Avenue, Caledonia, Louisiana, 2816','about':'Qui exercitation occaecat dolore mollit. Fugiat cupidatat proident culpa fugiat quis. In cupidatat commodo elit ea enim occaecat esse exercitation nostrud occaecat veniam laboris fugiat. Nisi sunt reprehenderit aliqua reprehenderit tempor id dolore ullamco pariatur reprehenderit et eu ex pariatur.','registered':'Wednesday, November 5, 2014 1:10 AM','latitude':'36.385637','longitude':'77.949423','tags':['eu','irure','velit','non','aliquip'],'greeting':'Hello, Louella! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed77cd60a1abc1ecce','index':50,'guid':'2887c3c1-3eba-4237-a0db-1977eed94554','isActive':true,'balance':'$1,633.51','picture':'http://placehold.it/32x32','age':22,'eyeColor':'green','name':{'first':'Bates','last':'Carrillo'},'company':'ZOMBOID','email':'bates.carrillo@zomboid.com','phone':'+1 (934) 405-2006','address':'330 Howard Alley, Troy, Kansas, 4881','about':'Voluptate esse est ullamco anim tempor ea reprehenderit. Occaecat pariatur deserunt cillum laboris labore id exercitation esse ipsum ipsum ex aliquip. Sunt non elit est ea occaecat. Magna deserunt commodo aliqua ipsum est cillum dolor nisi. Ex duis est tempor tempor laboris do do quis id magna. Dolor do est elit eu laborum ullamco culpa consequat velit eiusmod tempor.','registered':'Saturday, May 28, 2016 3:56 AM','latitude':'83.310134','longitude':'-105.862836','tags':['est','commodo','ea','commodo','sunt'],'greeting':'Hello, Bates! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed5ec0ec299b471fb5','index':51,'guid':'512b5e67-f785-492e-9d94-e43ef8b399b8','isActive':false,'balance':'$3,032.22','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Floyd','last':'Yang'},'company':'FRENEX','email':'floyd.yang@frenex.org','phone':'+1 (924) 566-3304','address':'418 Quay Street, Chumuckla, Guam, 7743','about':'Irure sit velit exercitation dolore est nisi incididunt ut quis consectetur incididunt est dolor. Aute nisi enim esse aliquip enim culpa commodo consectetur. Duis laborum magna ad duis ipsum aliqua eiusmod cillum. Consectetur et duis eiusmod irure ad est nisi incididunt eiusmod labore. Pariatur proident in Lorem adipisicing mollit proident excepteur nulla do nostrud mollit eiusmod. Duis ad dolore irure fugiat anim laboris ipsum et sit duis ipsum voluptate. Lorem non aute exercitation qui ullamco officia minim sint pariatur ut dolor.','registered':'Wednesday, January 18, 2017 2:01 AM','latitude':'45.888721','longitude':'-41.232793','tags':['elit','in','esse','ea','officia'],'greeting':'Hello, Floyd! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed51e26ca89e5caf49','index':52,'guid':'4e0907f6-facc-46df-8952-73561a53fe33','isActive':true,'balance':'$3,767.41','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Gardner','last':'Carey'},'company':'KLUGGER','email':'gardner.carey@klugger.net','phone':'+1 (876) 481-3502','address':'131 Utica Avenue, Cannondale, Federated States Of Micronesia, 610','about':'Amet ad pariatur excepteur anim ex officia commodo proident aliqua occaecat consequat Lorem officia sit. Id minim velit nisi laboris nisi nulla incididunt eiusmod velit. Deserunt labore quis et tempor. Et labore exercitation laborum officia ullamco nostrud adipisicing laboris esse laborum aute anim elit. Sunt ad officia tempor esse et quis aliquip irure pariatur laborum id quis ex. Eu consequat nisi deserunt id eu proident ex minim aute nulla tempor ex.','registered':'Friday, February 21, 2014 6:42 AM','latitude':'-54.740231','longitude':'15.01484','tags':['commodo','laboris','occaecat','aliquip','adipisicing'],'greeting':'Hello, Gardner! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed52e3c9407105093a','index':53,'guid':'1d3b9e7a-1bc3-40ea-b808-1c33f0d48c70','isActive':true,'balance':'$1,113.30','picture':'http://placehold.it/32x32','age':26,'eyeColor':'blue','name':{'first':'Herman','last':'Rogers'},'company':'TALENDULA','email':'herman.rogers@talendula.name','phone':'+1 (818) 521-2005','address':'541 Norman Avenue, Winfred, Tennessee, 447','about':'Culpa ex laborum non ad ullamco officia. Nisi mollit mollit voluptate sit sint ullamco. Lorem exercitation nulla anim eiusmod deserunt magna sint. Officia sunt eiusmod aliqua reprehenderit sunt mollit sit cupidatat sint.','registered':'Wednesday, July 11, 2018 1:05 AM','latitude':'-20.708105','longitude':'-151.294563','tags':['exercitation','minim','officia','qui','enim'],'greeting':'Hello, Herman! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edfcb123d545b6edb4','index':54,'guid':'c0e0c669-4eed-43ee-bdd0-78fe6e9ca4d5','isActive':true,'balance':'$3,309.64','picture':'http://placehold.it/32x32','age':22,'eyeColor':'green','name':{'first':'Whitley','last':'Stark'},'company':'MUSAPHICS','email':'whitley.stark@musaphics.us','phone':'+1 (803) 476-2151','address':'548 Cobek Court, Chamizal, Indiana, 204','about':'Adipisicing veniam dolor ex sint sit id eu voluptate. Excepteur veniam proident exercitation id eu et sunt pariatur. Qui occaecat culpa aliqua nisi excepteur minim veniam. Est duis nulla laborum excepteur cillum pariatur sint incididunt. Velit commodo eu incididunt voluptate. Amet laboris laboris id adipisicing labore eiusmod consequat minim cillum et.','registered':'Thursday, March 27, 2014 9:10 AM','latitude':'71.219596','longitude':'51.012855','tags':['reprehenderit','mollit','laborum','voluptate','aliquip'],'greeting':'Hello, Whitley! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed81510dfc61602fcf','index':55,'guid':'7ec5c24d-f169-4399-a2a3-300c0f45e52e','isActive':false,'balance':'$3,721.04','picture':'http://placehold.it/32x32','age':23,'eyeColor':'green','name':{'first':'Gretchen','last':'Wade'},'company':'EWEVILLE','email':'gretchen.wade@eweville.biz','phone':'+1 (977) 598-3700','address':'721 Colonial Road, Brookfield, South Dakota, 3888','about':'Fugiat consequat sint ut ut et ullamco eiusmod deserunt pariatur. Veniam eiusmod esse fugiat mollit. Proident laboris minim qui do ipsum excepteur exercitation irure anim. Aliqua labore quis eu fugiat dolore ullamco velit Lorem voluptate ipsum nostrud eiusmod laborum proident.','registered':'Friday, October 12, 2018 10:59 AM','latitude':'41.937653','longitude':'63.378531','tags':['aute','cillum','ea','ex','aute'],'greeting':'Hello, Gretchen! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edf78f77d4a7d557bb','index':56,'guid':'8718ada7-6fd0-49ef-a405-29850503948b','isActive':false,'balance':'$3,341.33','picture':'http://placehold.it/32x32','age':32,'eyeColor':'blue','name':{'first':'Naomi','last':'Frye'},'company':'MAZUDA','email':'naomi.frye@mazuda.ca','phone':'+1 (825) 427-2255','address':'741 Coyle Street, Comptche, Pennsylvania, 8441','about':'Aliqua fugiat laborum quis ullamco cupidatat sit dolor nulla dolore. Do Lorem et ipsum culpa irure sit do dolor qui sit laboris aliqua. Ex consectetur irure in veniam reprehenderit amet do elit eiusmod est magna.','registered':'Thursday, January 9, 2014 7:18 AM','latitude':'41.078645','longitude':'-50.241966','tags':['do','aliquip','eiusmod','velit','id'],'greeting':'Hello, Naomi! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edbf45db2e072a48b4','index':57,'guid':'c158ebf7-fb8b-4ea8-adbf-8c51c6486715','isActive':true,'balance':'$2,811.55','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Lamb','last':'Johns'},'company':'DOGTOWN','email':'lamb.johns@dogtown.info','phone':'+1 (946) 530-3057','address':'559 Malbone Street, Kennedyville, California, 2052','about':'Eiusmod dolor labore cillum ad veniam elit voluptate voluptate pariatur est cupidatat. Laboris ut qui in cillum sunt dolore ut enim. Minim nostrud ex qui quis reprehenderit magna ipsum cupidatat irure minim laboris veniam irure. Fugiat velit deserunt aliquip in esse proident excepteur labore reprehenderit excepteur sunt in cupidatat exercitation. Ex pariatur irure mollit tempor non magna ex.','registered':'Friday, April 21, 2017 1:51 AM','latitude':'-61.403599','longitude':'-93.447102','tags':['aliquip','tempor','sint','enim','ipsum'],'greeting':'Hello, Lamb! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edbb9c88190cb59cf2','index':58,'guid':'f0de5ac5-eb28-491b-81c5-76d447c9055e','isActive':true,'balance':'$1,611.99','picture':'http://placehold.it/32x32','age':37,'eyeColor':'brown','name':{'first':'Lynette','last':'Cleveland'},'company':'ARTWORLDS','email':'lynette.cleveland@artworlds.tv','phone':'+1 (889) 596-3723','address':'439 Montauk Avenue, Felt, New Mexico, 9681','about':'Incididunt aliquip est aliquip est ullamco do consectetur dolor. Lorem mollit mollit dolor et ipsum ut qui veniam aute ea. Adipisicing reprehenderit culpa velit laborum adipisicing amet consectetur velit nisi. Ut qui proident ad cillum excepteur adipisicing quis labore. Duis velit culpa et excepteur eiusmod ex labore in nisi nostrud. Et ullamco minim excepteur ut enim reprehenderit consequat eiusmod laboris Lorem commodo exercitation qui laborum.','registered':'Wednesday, August 26, 2015 12:53 PM','latitude':'49.861336','longitude':'86.865926','tags':['reprehenderit','minim','in','minim','nostrud'],'greeting':'Hello, Lynette! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed5b760ddde7295fa8','index':59,'guid':'f8180d3f-c5c0-48b2-966e-a0b2a80f8e84','isActive':true,'balance':'$3,376.75','picture':'http://placehold.it/32x32','age':32,'eyeColor':'green','name':{'first':'Obrien','last':'Page'},'company':'GLASSTEP','email':'obrien.page@glasstep.co.uk','phone':'+1 (902) 583-3086','address':'183 Ridgewood Avenue, Vicksburg, Wisconsin, 7430','about':'Aute excepteur cillum exercitation duis Lorem irure labore elit. Labore magna cupidatat velit consectetur minim do Lorem in excepteur commodo ea consequat ullamco laborum. Ut in id occaecat eu quis duis id ea deserunt veniam.','registered':'Wednesday, March 29, 2017 12:13 AM','latitude':'-40.156154','longitude':'72.76301','tags':['excepteur','non','anim','nulla','anim'],'greeting':'Hello, Obrien! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed52985d3d8901d653','index':60,'guid':'d2e14fa1-8c54-4bcb-8a58-eb2e6f8d0e45','isActive':true,'balance':'$1,659.47','picture':'http://placehold.it/32x32','age':33,'eyeColor':'brown','name':{'first':'Knowles','last':'Goodman'},'company':'CENTREE','email':'knowles.goodman@centree.io','phone':'+1 (862) 563-3692','address':'504 Lott Street, Allensworth, Florida, 7148','about':'Do aliquip voluptate aliqua nostrud. Eu dolore ex occaecat pariatur aute laborum aute nulla aute amet. Excepteur sit laboris ad non anim ut officia ut ad exercitation officia dolore laboris. Esse voluptate minim deserunt nostrud exercitation laborum voluptate exercitation id laborum fugiat proident cupidatat proident. Nulla nostrud est sint adipisicing incididunt exercitation dolor sit et elit tempor occaecat sint culpa. Pariatur occaecat laboris pariatur laboris ad pariatur in cillum fugiat est fugiat. Proident eu id irure excepteur esse aute cillum adipisicing.','registered':'Wednesday, October 15, 2014 6:17 PM','latitude':'-15.73863','longitude':'87.422009','tags':['consequat','sint','tempor','veniam','culpa'],'greeting':'Hello, Knowles! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0eda00b73bdb7ea54e9','index':61,'guid':'c8a064db-0ec6-4832-9820-7280a0333709','isActive':true,'balance':'$3,701.14','picture':'http://placehold.it/32x32','age':35,'eyeColor':'brown','name':{'first':'Shepherd','last':'Todd'},'company':'ECRATIC','email':'shepherd.todd@ecratic.me','phone':'+1 (881) 444-3389','address':'450 Frank Court, Temperanceville, Ohio, 7006','about':'Voluptate cillum ad fugiat velit adipisicing sint consequat veniam Lorem reprehenderit. Cillum sit non deserunt consequat. Amet sunt pariatur non mollit ullamco proident sint dolore anim elit cupidatat anim do ullamco. Lorem Lorem incididunt ea elit consequat laboris enim duis quis Lorem id aute veniam consequat. Cillum veniam cillum sint qui Lorem fugiat culpa consequat. Est sint duis ut qui fugiat. Laborum pariatur velit et sunt mollit eiusmod excepteur culpa ex et officia.','registered':'Tuesday, October 10, 2017 2:01 AM','latitude':'82.951563','longitude':'-4.866954','tags':['eu','qui','proident','esse','ex'],'greeting':'Hello, Shepherd! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed0e51d1a7e2d9e559','index':62,'guid':'739c3d38-200d-4531-84d8-4e7c39ae5b8c','isActive':true,'balance':'$3,679.01','picture':'http://placehold.it/32x32','age':31,'eyeColor':'brown','name':{'first':'Rosalyn','last':'Heath'},'company':'ZAYA','email':'rosalyn.heath@zaya.com','phone':'+1 (865) 403-3520','address':'303 Henderson Walk, Hoehne, District Of Columbia, 4306','about':'Sint occaecat nulla mollit sint fugiat eu proident dolor labore consequat. Occaecat tempor excepteur do fugiat incididunt Lorem in ullamco dolore laborum. Cillum mollit aliquip excepteur aliquip sint sunt minim non irure irure. Cillum fugiat aliqua enim dolore. Nulla culpa culpa nostrud ad. Eiusmod culpa proident proident non est cupidatat eu sunt sit incididunt id nisi.','registered':'Wednesday, April 22, 2015 12:35 PM','latitude':'33.628504','longitude':'110.772802','tags':['consequat','ut','ex','labore','consectetur'],'greeting':'Hello, Rosalyn! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd5274c01d353d0c5','index':63,'guid':'8815fe55-8af1-4708-a62a-d554dbd74a4a','isActive':true,'balance':'$2,126.01','picture':'http://placehold.it/32x32','age':30,'eyeColor':'blue','name':{'first':'Queen','last':'Harper'},'company':'TRI@TRIBALOG','email':'queen.harper@tri@tribalog.org','phone':'+1 (903) 592-3145','address':'926 Heath Place, Wawona, Maine, 7340','about':'Laborum cupidatat commodo aliquip reprehenderit. Excepteur eu labore duis minim minim voluptate aute nostrud deserunt ut velit ullamco. Adipisicing nisi occaecat laborum proident. Id reprehenderit eiusmod cupidatat qui aute consequat amet enim commodo duis non ipsum. Amet ut aliqua magna qui proident mollit aute.','registered':'Saturday, April 9, 2016 5:12 AM','latitude':'51.814216','longitude':'177.348115','tags':['cillum','ut','dolor','do','nisi'],'greeting':'Hello, Queen! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed126298b6ce62ed56','index':64,'guid':'001c87fe-182f-450f-903b-2e29a9bb0322','isActive':true,'balance':'$3,578.29','picture':'http://placehold.it/32x32','age':20,'eyeColor':'green','name':{'first':'Pauline','last':'Mills'},'company':'CRUSTATIA','email':'pauline.mills@crustatia.net','phone':'+1 (984) 582-3899','address':'899 Revere Place, Welch, Iowa, 216','about':'Tempor eu exercitation ut id. Deserunt ex reprehenderit veniam nisi. Aute laborum veniam velit dolore ut deserunt Lorem sit esse quis dolor ex do nisi. In dolor tempor officia id. Velit nisi culpa nostrud laborum officia incididunt laborum velit non quis id exercitation exercitation. Anim elit ullamco in enim Lorem culpa aliqua Lorem.','registered':'Monday, June 2, 2014 2:03 PM','latitude':'56.427576','longitude':'172.183669','tags':['pariatur','pariatur','pariatur','fugiat','Lorem'],'greeting':'Hello, Pauline! You have 8 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed3e332ad9e8a178d8','index':65,'guid':'5ad7292b-feef-4a7e-b485-142cadfbe8ea','isActive':false,'balance':'$3,916.54','picture':'http://placehold.it/32x32','age':22,'eyeColor':'brown','name':{'first':'Garrett','last':'Richmond'},'company':'XYQAG','email':'garrett.richmond@xyqag.name','phone':'+1 (952) 584-3794','address':'233 Grove Street, Summerfield, Virginia, 4735','about':'Nostrud quis pariatur occaecat laborum laboris aliqua ut fugiat dolor. Commodo tempor excepteur enim nostrud Lorem. Aute elit nulla labore ad pariatur cupidatat Lorem qui cupidatat velit deserunt excepteur esse. Excepteur nulla et nostrud quis labore est veniam enim nisi laboris ut enim. Ea esse nulla anim excepteur reprehenderit deserunt voluptate minim qui labore adipisicing amet eu enim.','registered':'Wednesday, March 5, 2014 4:35 PM','latitude':'68.665041','longitude':'148.799524','tags':['irure','reprehenderit','minim','ea','do'],'greeting':'Hello, Garrett! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed541aa2ec47466ace','index':66,'guid':'9cda6f3c-c9ab-451c-bb19-2e4c8463d011','isActive':true,'balance':'$3,352.52','picture':'http://placehold.it/32x32','age':30,'eyeColor':'brown','name':{'first':'Cobb','last':'Whitley'},'company':'UNIA','email':'cobb.whitley@unia.us','phone':'+1 (888) 490-3342','address':'864 Belmont Avenue, Needmore, Massachusetts, 8286','about':'Nisi aliquip fugiat ipsum nisi ullamco minim pariatur labore. Sint labore anim do ad ad esse eu nostrud nulla commodo anim. Cillum anim enim duis cillum non do nisi aliquip veniam voluptate commodo aliqua laborum. Exercitation in do eu qui sint aliquip. Esse adipisicing deserunt deserunt qui anim aliqua occaecat et nostrud elit ea in anim cillum. Tempor mollit proident tempor sunt est sint laborum ullamco incididunt non. Velit aliqua sunt excepteur nisi qui eiusmod ipsum dolore aliquip velit ullamco ullamco.','registered':'Friday, May 23, 2014 7:11 PM','latitude':'-32.950581','longitude':'147.772494','tags':['mollit','adipisicing','irure','ad','minim'],'greeting':'Hello, Cobb! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed8186c3d6f34c2be3','index':67,'guid':'fee98f6d-d68a-4189-8180-b6cb337e537e','isActive':false,'balance':'$1,698.42','picture':'http://placehold.it/32x32','age':20,'eyeColor':'blue','name':{'first':'Brennan','last':'Tyler'},'company':'PODUNK','email':'brennan.tyler@podunk.biz','phone':'+1 (867) 498-2727','address':'599 Harkness Avenue, Gorst, American Samoa, 322','about':'Reprehenderit id sit qui id qui aute ea sit magna in qui proident. Excepteur ad nostrud do nostrud in incididunt voluptate adipisicing sint anim. Ullamco consequat minim nulla irure ex est irure reprehenderit deserunt voluptate dolore anim sunt. Occaecat dolore voluptate voluptate elit commodo nulla laborum ad do irure.','registered':'Friday, February 9, 2018 5:40 PM','latitude':'11.150893','longitude':'-85.298004','tags':['quis','minim','deserunt','cillum','laboris'],'greeting':'Hello, Brennan! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed075c9c4f7439818d','index':68,'guid':'1ef76b18-6b8d-4c3c-aca3-9fa2b43f0242','isActive':false,'balance':'$2,091.17','picture':'http://placehold.it/32x32','age':26,'eyeColor':'brown','name':{'first':'Neal','last':'Stephenson'},'company':'OTHERSIDE','email':'neal.stephenson@otherside.ca','phone':'+1 (820) 496-3344','address':'867 Wilson Street, Kidder, Colorado, 4599','about':'Do laboris enim proident in qui velit adipisicing magna anim. Amet proident non exercitation ipsum aliqua excepteur nostrud. Enim esse non sit in nostrud deserunt id laborum cillum deserunt consequat. Anim velit exercitation qui sit voluptate. Irure duis non veniam velit mollit exercitation id exercitation.','registered':'Thursday, November 13, 2014 11:00 PM','latitude':'54.809693','longitude':'1.877241','tags':['anim','duis','in','officia','sint'],'greeting':'Hello, Neal! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0eda0a2dc24db64b638','index':69,'guid':'194744fd-089b-40b6-a290-98a6ec30a415','isActive':false,'balance':'$3,191.67','picture':'http://placehold.it/32x32','age':24,'eyeColor':'brown','name':{'first':'Shields','last':'Hubbard'},'company':'MIRACULA','email':'shields.hubbard@miracula.info','phone':'+1 (885) 582-2001','address':'529 Eagle Street, Guilford, Nevada, 1460','about':'Eiusmod exercitation ut incididunt veniam commodo culpa ullamco mollit id adipisicing exercitation ad sint. Nostrud excepteur amet aliqua mollit incididunt laborum voluptate id anim. Nulla sint laboris dolor esse cupidatat laborum ex sint. Ex non sunt sit nulla.','registered':'Monday, February 13, 2017 6:22 AM','latitude':'-69.145209','longitude':'-40.69755','tags':['tempor','enim','qui','velit','elit'],'greeting':'Hello, Shields! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edf939c130177e074d','index':70,'guid':'303b176c-7803-4ed2-a35f-3e3c831793ef','isActive':false,'balance':'$2,359.09','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Coleen','last':'Knight'},'company':'BLEEKO','email':'coleen.knight@bleeko.tv','phone':'+1 (867) 423-3146','address':'527 Broadway , Bonanza, Marshall Islands, 4988','about':'Laboris nulla pariatur laborum ad aute excepteur sunt pariatur exercitation. Do nostrud qui ipsum ullamco et sint do Lorem cillum ullamco do. Exercitation labore excepteur commodo incididunt eiusmod proident consectetur adipisicing nostrud aute voluptate laboris. Commodo anim proident eiusmod pariatur est ea laborum incididunt qui tempor reprehenderit ullamco id. Eiusmod commodo nisi consectetur ut qui quis aliqua sit minim nostrud sunt laborum eiusmod adipisicing.','registered':'Sunday, May 6, 2018 8:03 AM','latitude':'70.729041','longitude':'113.052761','tags':['Lorem','ullamco','nulla','ullamco','commodo'],'greeting':'Hello, Coleen! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edae8b1ce688b61223','index':71,'guid':'7d6f3b1a-c367-4068-9e8e-1717d513ece3','isActive':false,'balance':'$2,911.07','picture':'http://placehold.it/32x32','age':21,'eyeColor':'brown','name':{'first':'Clark','last':'Ryan'},'company':'ECLIPSENT','email':'clark.ryan@eclipsent.co.uk','phone':'+1 (938) 562-2740','address':'500 Lewis Avenue, Rockbridge, North Dakota, 5133','about':'Adipisicing exercitation officia sit excepteur excepteur sunt sint amet. Aliqua ipsum sint laboris eiusmod esse culpa elit sunt. Dolore est consectetur est quis quis magna. Aliquip nostrud dolore ex pariatur. Anim nostrud duis exercitation ut magna magna culpa. Nisi irure id mollit labore non sit mollit occaecat Lorem est ipsum. Nulla est fugiat cillum nisi aliqua consectetur amet nulla nostrud esse.','registered':'Friday, July 24, 2015 9:28 AM','latitude':'-68.055815','longitude':'-50.926966','tags':['deserunt','ad','ad','ut','id'],'greeting':'Hello, Clark! You have 7 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed5d1e8df45d8ab4db','index':72,'guid':'ce85db37-7d04-4f4c-a4b0-78003533e5c6','isActive':false,'balance':'$1,127.43','picture':'http://placehold.it/32x32','age':21,'eyeColor':'green','name':{'first':'Dillon','last':'Hooper'},'company':'MEDESIGN','email':'dillon.hooper@medesign.io','phone':'+1 (929) 600-3797','address':'652 Mill Avenue, Elliston, Mississippi, 2958','about':'Dolore culpa qui exercitation nostrud do. Irure duis in ad ipsum aliqua aliquip nulla sit veniam officia quis occaecat est. Magna qui eiusmod pariatur aliquip minim commodo. Qui ex dolor excepteur consequat eiusmod occaecat. In officia ipsum do Lorem excepteur proident pariatur labore.','registered':'Monday, May 26, 2014 2:38 AM','latitude':'-36.032189','longitude':'86.865529','tags':['non','ut','ex','Lorem','quis'],'greeting':'Hello, Dillon! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edb84814579c3121b3','index':73,'guid':'d7303901-5186-4595-a759-22306f67d0a3','isActive':true,'balance':'$2,326.59','picture':'http://placehold.it/32x32','age':33,'eyeColor':'green','name':{'first':'Moreno','last':'Hull'},'company':'ZEAM','email':'moreno.hull@zeam.me','phone':'+1 (984) 586-3738','address':'265 Pine Street, Talpa, North Carolina, 6041','about':'Fugiat exercitation est ullamco anim. Exercitation proident id sunt culpa Lorem amet. Consectetur anim consectetur pariatur consequat consectetur amet excepteur voluptate ea velit duis eiusmod proident. In sint laborum cupidatat ea amet ex. Reprehenderit amet sunt dolor ullamco est ex deserunt.','registered':'Wednesday, January 24, 2018 8:52 PM','latitude':'84.956857','longitude':'113.210051','tags':['est','excepteur','anim','Lorem','dolor'],'greeting':'Hello, Moreno! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eda4eb9dcb92c82d06','index':74,'guid':'8ee28651-802e-4523-b676-c713f6e874b8','isActive':true,'balance':'$3,783.97','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Tracie','last':'Price'},'company':'ICOLOGY','email':'tracie.price@icology.com','phone':'+1 (897) 403-3768','address':'487 Sheffield Avenue, Vallonia, Wyoming, 276','about':'Voluptate laboris laborum aute ex sint voluptate officia proident. Sit esse nostrud cupidatat in veniam sit duis est. Do mollit elit exercitation aliqua id irure ex. Lorem reprehenderit do ullamco sint ea ad nisi ad ut.','registered':'Saturday, December 10, 2016 9:44 AM','latitude':'77.770464','longitude':'151.392903','tags':['incididunt','labore','aliquip','anim','minim'],'greeting':'Hello, Tracie! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed68ab1a55d1c35e6c','index':75,'guid':'deedd26a-8928-4064-9666-5c59ea8144b4','isActive':true,'balance':'$2,848.08','picture':'http://placehold.it/32x32','age':32,'eyeColor':'brown','name':{'first':'Montgomery','last':'Bruce'},'company':'CYTREK','email':'montgomery.bruce@cytrek.org','phone':'+1 (824) 414-2731','address':'397 Beach Place, Ellerslie, South Carolina, 967','about':'Mollit minim excepteur magna velit cillum excepteur exercitation anim id labore deserunt do. Fugiat ex et id ad. Duis excepteur laboris est nulla do id irure quis eiusmod do esse ut culpa in.','registered':'Tuesday, August 25, 2015 6:42 AM','latitude':'79.722631','longitude':'-7.516885','tags':['Lorem','sint','voluptate','proident','incididunt'],'greeting':'Hello, Montgomery! You have 6 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd90e0abb1cc2b0aa','index':76,'guid':'a072159d-12db-4747-9c2a-e2486a53d043','isActive':false,'balance':'$2,723.54','picture':'http://placehold.it/32x32','age':40,'eyeColor':'green','name':{'first':'Zelma','last':'Salinas'},'company':'IMAGEFLOW','email':'zelma.salinas@imageflow.net','phone':'+1 (964) 555-3856','address':'584 Reeve Place, Nord, Georgia, 7473','about':'Aliqua proident excepteur duis cupidatat cillum amet esse esse consectetur ea. Officia sunt consequat nostrud minim enim dolore dolor duis cillum. Esse labore veniam sint laborum excepteur sint tempor do ad cupidatat aliquip laboris elit id. Velit reprehenderit ullamco velit ullamco adipisicing velit esse irure velit et.','registered':'Thursday, February 25, 2016 8:18 PM','latitude':'-32.880524','longitude':'115.180489','tags':['id','nulla','reprehenderit','consequat','reprehenderit'],'greeting':'Hello, Zelma! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed98d836c8da283bb2','index':77,'guid':'838bebad-cc20-44e9-9eb7-902a8ca25efb','isActive':false,'balance':'$3,488.91','picture':'http://placehold.it/32x32','age':20,'eyeColor':'green','name':{'first':'Shaw','last':'Parsons'},'company':'PEARLESEX','email':'shaw.parsons@pearlesex.name','phone':'+1 (912) 567-3580','address':'606 Ocean Avenue, Tyro, Northern Mariana Islands, 3367','about':'Laborum labore occaecat culpa pariatur nisi non adipisicing esse consectetur officia officia. Deserunt velit eu enim consectetur ut cillum aliqua occaecat dolor qui esse. Incididunt ad est ex eu culpa anim aliquip laborum. Aliqua consectetur velit exercitation magna minim nulla do ut excepteur enim aliquip et. Nostrud enim sunt amet amet proident aliqua velit dolore. Consectetur ipsum fugiat proident id est reprehenderit tempor irure commodo. Sit excepteur fugiat occaecat nulla Lorem et cillum.','registered':'Thursday, April 19, 2018 1:41 AM','latitude':'69.715573','longitude':'-118.481237','tags':['laboris','adipisicing','magna','voluptate','id'],'greeting':'Hello, Shaw! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed1101734633c6ebba','index':78,'guid':'8fd0c52a-9d74-4984-a608-d612ecd8ddf0','isActive':true,'balance':'$3,820.02','picture':'http://placehold.it/32x32','age':39,'eyeColor':'brown','name':{'first':'Jaime','last':'Beard'},'company':'IZZBY','email':'jaime.beard@izzby.us','phone':'+1 (820) 412-3806','address':'362 Hudson Avenue, Delco, New Jersey, 5684','about':'Ut cupidatat veniam nulla magna commodo sit duis veniam consectetur cupidatat elit quis tempor. Duis officia ullamco proident sunt non mollit excepteur. Nisi ex amet laboris proident duis reprehenderit et est aliqua mollit amet ad. Enim eu elit excepteur eu exercitation duis consequat culpa. Adipisicing reprehenderit duis Lorem reprehenderit dolor aliqua incididunt eiusmod consequat ad occaecat fugiat do laborum. Qui ad aliquip ex do sunt. Fugiat non ut fugiat eu.','registered':'Sunday, March 9, 2014 3:41 PM','latitude':'17.926318','longitude':'108.985996','tags':['ut','voluptate','veniam','non','commodo'],'greeting':'Hello, Jaime! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edcd125a89dcf18e0d','index':79,'guid':'eccaa4ca-0fa7-4b00-a1e3-fe7953403894','isActive':true,'balance':'$1,521.33','picture':'http://placehold.it/32x32','age':30,'eyeColor':'green','name':{'first':'Terra','last':'Sullivan'},'company':'ZANITY','email':'terra.sullivan@zanity.biz','phone':'+1 (995) 498-2714','address':'346 Congress Street, Tuttle, Maryland, 3152','about':'Incididunt enim veniam ut veniam quis dolore pariatur culpa ex. Cillum laboris dolor exercitation officia. Officia irure magna aliqua veniam officia ullamco culpa. Cillum enim velit ea sint sint officia labore ea adipisicing culpa laboris. Anim aute sint commodo culpa ex quis minim ut laborum.','registered':'Sunday, June 1, 2014 5:38 AM','latitude':'-4.655435','longitude':'5.851803','tags':['anim','non','anim','laborum','pariatur'],'greeting':'Hello, Terra! You have 5 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed9b9fc3041a674c87','index':80,'guid':'9f95fa36-4e45-4c3f-9362-3d4d809bf57f','isActive':true,'balance':'$3,403.16','picture':'http://placehold.it/32x32','age':39,'eyeColor':'brown','name':{'first':'Sharpe','last':'Berger'},'company':'ZILLAN','email':'sharpe.berger@zillan.ca','phone':'+1 (913) 498-3005','address':'277 Bragg Street, Faywood, Texas, 6487','about':'Dolor duis id aute ea veniam amet ullamco id. Culpa deserunt irure mollit tempor dolore veniam culpa officia culpa laborum eiusmod. Ullamco tempor qui aliqua cupidatat veniam cillum eu ut ex minim eu in. Quis exercitation anim eiusmod tempor esse mollit exercitation cillum ipsum reprehenderit. Sint voluptate ipsum officia sint magna nulla tempor eiusmod eiusmod veniam. Consectetur non ad veniam exercitation voluptate non nostrud.','registered':'Tuesday, June 27, 2017 12:58 AM','latitude':'-0.54085','longitude':'106.258693','tags':['proident','eiusmod','commodo','excepteur','pariatur'],'greeting':'Hello, Sharpe! You have 5 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed1a1866757bf675e0','index':81,'guid':'1b944a01-01d3-4846-94e3-630f4d0e51a3','isActive':true,'balance':'$2,038.61','picture':'http://placehold.it/32x32','age':28,'eyeColor':'brown','name':{'first':'Blanchard','last':'Ewing'},'company':'CONJURICA','email':'blanchard.ewing@conjurica.info','phone':'+1 (859) 593-3212','address':'252 Beaver Street, Kiskimere, Utah, 3255','about':'Labore magna aute adipisicing ut dolor sit ea. Officia culpa aute occaecat sit ex ullamco aliquip ad sit culpa. Ex in enim dolore ex est sit. Do irure nulla magna sint aliquip in duis aute. Magna ullamco sit labore ea tempor voluptate.','registered':'Monday, May 4, 2015 10:50 AM','latitude':'76.207595','longitude':'0.672563','tags':['proident','pariatur','officia','in','culpa'],'greeting':'Hello, Blanchard! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed987d82f4e22d939c','index':82,'guid':'97a90aee-3cee-4678-819e-24fb94279dc1','isActive':false,'balance':'$1,201.55','picture':'http://placehold.it/32x32','age':28,'eyeColor':'blue','name':{'first':'Wells','last':'Solomon'},'company':'CORPULSE','email':'wells.solomon@corpulse.tv','phone':'+1 (840) 539-3349','address':'159 Radde Place, Linganore, Idaho, 230','about':'Consequat dolore mollit sit irure cupidatat commodo. Incididunt cillum reprehenderit ullamco sit proident cupidatat occaecat reprehenderit officia. Ad anim Lorem elit in officia minim proident nisi commodo eiusmod ea Lorem dolore voluptate. Dolor aliquip est commodo Lorem dolor ut aliquip ut. Sit anim officia dolore excepteur aute enim cillum.','registered':'Friday, January 6, 2017 1:59 PM','latitude':'70.020883','longitude':'14.503588','tags':['mollit','aute','officia','nostrud','laboris'],'greeting':'Hello, Wells! You have 7 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eddf7a904ea0d0bc2a','index':83,'guid':'fe639a0c-7517-43e6-b0da-cd9ca5b9e267','isActive':false,'balance':'$3,664.47','picture':'http://placehold.it/32x32','age':33,'eyeColor':'blue','name':{'first':'Natalia','last':'Brown'},'company':'SYNTAC','email':'natalia.brown@syntac.co.uk','phone':'+1 (952) 595-3513','address':'332 Lenox Road, Springville, Alabama, 8406','about':'Nulla consequat officia commodo ea sunt irure anim velit aliquip aliquip. Labore ullamco occaecat proident voluptate cillum labore minim nostrud excepteur. Qui fugiat nostrud cillum fugiat ullamco id commodo aliqua voluptate mollit id id laboris. Cillum qui duis duis sit adipisicing elit ut aliqua eu. Anim nisi aliqua sit mollit.','registered':'Sunday, July 30, 2017 1:02 PM','latitude':'31.937613','longitude':'-9.957927','tags':['magna','adipisicing','exercitation','tempor','consectetur'],'greeting':'Hello, Natalia! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed8823fa385cad4aa3','index':84,'guid':'5cf280da-f5f0-4cc6-9063-e9d5863c8c89','isActive':false,'balance':'$1,624.17','picture':'http://placehold.it/32x32','age':25,'eyeColor':'blue','name':{'first':'Greene','last':'Waller'},'company':'ISOTRACK','email':'greene.waller@isotrack.io','phone':'+1 (838) 406-3608','address':'362 Albemarle Road, Gardiner, Michigan, 2764','about':'Ut nisi sit sint nulla dolor magna. Culpa occaecat adipisicing veniam proident excepteur tempor quis ex. Fugiat tempor laborum dolor adipisicing irure anim cupidatat ut exercitation ex sit. Cupidatat exercitation commodo sunt ex irure fugiat eu esse do ullamco mollit dolore cupidatat. Cupidatat magna incididunt officia dolore esse voluptate deserunt in laborum dolor. Sit fugiat Lorem eu ullamco. Laboris veniam quis cillum tempor ex fugiat cillum cupidatat.','registered':'Sunday, June 10, 2018 10:32 PM','latitude':'0.256921','longitude':'-96.141941','tags':['magna','dolore','deserunt','aliquip','cillum'],'greeting':'Hello, Greene! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0eda7c905c2d24c7d31','index':85,'guid':'aa30a9fb-8a16-48eb-8bb7-1307d1e1f191','isActive':false,'balance':'$1,974.04','picture':'http://placehold.it/32x32','age':36,'eyeColor':'green','name':{'first':'Carlene','last':'Hanson'},'company':'DIGIRANG','email':'carlene.hanson@digirang.me','phone':'+1 (981) 417-3209','address':'435 Clark Street, Choctaw, Oregon, 9888','about':'Amet labore esse cillum irure laborum consectetur occaecat non aliquip aliquip proident. Nisi magna nulla officia duis labore aute nulla laborum duis tempor minim. Velit elit reprehenderit nisi exercitation officia incididunt amet cupidatat excepteur proident consectetur.','registered':'Thursday, April 20, 2017 6:13 AM','latitude':'68.529086','longitude':'68.802409','tags':['pariatur','nulla','qui','amet','labore'],'greeting':'Hello, Carlene! You have 10 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed6fbee12ce9e55dbf','index':86,'guid':'0fce89aa-3310-48df-862a-68bd3d776644','isActive':false,'balance':'$3,909.64','picture':'http://placehold.it/32x32','age':40,'eyeColor':'brown','name':{'first':'Doris','last':'Collins'},'company':'ZIORE','email':'doris.collins@ziore.com','phone':'+1 (914) 405-2360','address':'301 Lorraine Street, Stouchsburg, Minnesota, 7476','about':'Nisi deserunt aliquip et deserunt ipsum ad consectetur est non ullamco. Dolore do ut voluptate do eiusmod. Culpa ad in eiusmod nisi cillum do. Officia magna cillum sint aliqua reprehenderit amet est ipsum. Eiusmod deserunt commodo proident consequat. Amet minim dolor consequat aliquip aliquip culpa non exercitation non.','registered':'Wednesday, February 25, 2015 9:15 PM','latitude':'-57.364906','longitude':'130.766587','tags':['nulla','deserunt','cillum','eiusmod','adipisicing'],'greeting':'Hello, Doris! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0edede9402476c398c0','index':87,'guid':'60cf0aa6-bc6d-4305-8842-d27e6af1306f','isActive':false,'balance':'$2,817.53','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Cline','last':'Hayden'},'company':'ECRAZE','email':'cline.hayden@ecraze.org','phone':'+1 (965) 507-2138','address':'352 Rutland Road, Ebro, Connecticut, 1196','about':'Dolor eiusmod enim anim sit enim ea tempor. Tempor amet consectetur aliquip culpa do ex excepteur deserunt. Dolor commodo veniam culpa sint. Commodo consectetur pariatur irure nisi deserunt cillum est dolor ipsum ea.','registered':'Thursday, September 29, 2016 5:58 AM','latitude':'62.50713','longitude':'86.247286','tags':['enim','tempor','anim','veniam','proident'],'greeting':'Hello, Cline! You have 9 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edeb72f151994a551b','index':88,'guid':'dbb49c62-86b1-409f-b8b8-f609c709d2a8','isActive':false,'balance':'$3,122.56','picture':'http://placehold.it/32x32','age':39,'eyeColor':'green','name':{'first':'Janelle','last':'Rutledge'},'company':'TERRAGEN','email':'janelle.rutledge@terragen.net','phone':'+1 (914) 581-3749','address':'170 Falmouth Street, Alderpoint, West Virginia, 642','about':'Laboris proident cillum sunt qui ea sunt. Officia adipisicing exercitation dolore magna reprehenderit amet anim id. Laboris commodo sit irure irure. Excepteur est mollit fugiat incididunt consectetur veniam irure ea mollit. Cillum enim consequat sunt sunt nisi incididunt tempor enim.','registered':'Monday, February 16, 2015 5:46 AM','latitude':'-46.392023','longitude':'32.054562','tags':['eu','eu','nisi','labore','deserunt'],'greeting':'Hello, Janelle! You have 9 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edc9c2604846ff9a0d','index':89,'guid':'c4d7a365-f1d3-4584-b78e-008394c219f7','isActive':true,'balance':'$1,807.19','picture':'http://placehold.it/32x32','age':24,'eyeColor':'green','name':{'first':'Abby','last':'Lopez'},'company':'GRAINSPOT','email':'abby.lopez@grainspot.name','phone':'+1 (917) 442-3955','address':'488 Kensington Walk, Winston, Hawaii, 9109','about':'Incididunt deserunt Lorem proident magna tempor enim quis duis eu ut adipisicing in. Ex mollit non irure aliqua officia. Fugiat id ipsum consequat irure id ullamco culpa quis nulla enim aliquip consequat et. Dolor ut anim velit irure consequat cillum eu. Aute occaecat laborum est aliqua.','registered':'Sunday, April 1, 2018 11:28 PM','latitude':'-10.177041','longitude':'-165.756718','tags':['est','laborum','culpa','non','quis'],'greeting':'Hello, Abby! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed03237438b158af9e','index':90,'guid':'36c4a19f-2d00-4e40-bd49-155fd2ce0a6c','isActive':false,'balance':'$2,757.86','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Whitney','last':'Sheppard'},'company':'ANACHO','email':'whitney.sheppard@anacho.us','phone':'+1 (922) 437-2383','address':'951 Beekman Place, Homeworth, New York, 6088','about':'Sint minim nisi minim non minim aliqua pariatur ullamco do sint qui labore. Aute elit reprehenderit ad do fugiat est amet. In incididunt tempor commodo cillum tempor est labore anim.','registered':'Tuesday, September 13, 2016 6:43 PM','latitude':'-49.732527','longitude':'-171.846715','tags':['exercitation','veniam','sunt','est','proident'],'greeting':'Hello, Whitney! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0edb99dd3aa53d2cb7f','index':91,'guid':'17afd430-f37f-4d55-958c-72f35cdb5997','isActive':false,'balance':'$3,683.86','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Ilene','last':'Blackwell'},'company':'ENQUILITY','email':'ilene.blackwell@enquility.biz','phone':'+1 (817) 555-2616','address':'950 Varanda Place, Belgreen, Virgin Islands, 1765','about':'Id eiusmod deserunt eiusmod adipisicing adipisicing est enim pariatur esse duis. Qui velit duis irure magna consectetur dolore reprehenderit. Cillum dolore minim consectetur irure non qui velit cillum veniam adipisicing incididunt. Deserunt veniam excepteur veniam velit aliquip labore quis exercitation magna do non dolor. Aliquip occaecat minim adipisicing deserunt fugiat nulla occaecat proident irure consectetur eiusmod irure. Enim Lorem deserunt amet Lorem commodo eiusmod reprehenderit occaecat adipisicing dolor voluptate cillum.','registered':'Thursday, February 1, 2018 8:39 AM','latitude':'57.393644','longitude':'-3.704258','tags':['adipisicing','dolor','commodo','Lorem','Lorem'],'greeting':'Hello, Ilene! You have 6 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed353f4deb62c3342a','index':92,'guid':'9953e285-2095-4f1c-978b-9ece2a867e9d','isActive':false,'balance':'$1,202.44','picture':'http://placehold.it/32x32','age':38,'eyeColor':'blue','name':{'first':'Dawson','last':'Herman'},'company':'BITENDREX','email':'dawson.herman@bitendrex.ca','phone':'+1 (843) 522-2655','address':'471 Channel Avenue, Denio, Alaska, 5040','about':'Nisi occaecat mollit reprehenderit nisi minim Lorem mollit. Ea proident irure cillum quis. Deserunt consectetur consectetur consequat quis enim minim ea ipsum proident nisi ad non aliquip. Veniam aute minim consequat irure voluptate aute amet excepteur exercitation cillum duis quis adipisicing nostrud.','registered':'Tuesday, December 8, 2015 5:40 PM','latitude':'-55.602721','longitude':'-26.683234','tags':['qui','dolor','deserunt','eiusmod','labore'],'greeting':'Hello, Dawson! You have 7 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0edd5464bc50a5310ad','index':93,'guid':'724b2434-4dbd-417d-aa07-6065715f434f','isActive':false,'balance':'$1,595.98','picture':'http://placehold.it/32x32','age':25,'eyeColor':'brown','name':{'first':'Alice','last':'Christian'},'company':'ZENOLUX','email':'alice.christian@zenolux.info','phone':'+1 (954) 466-2650','address':'875 Gerritsen Avenue, Townsend, Kentucky, 6568','about':'Nulla labore occaecat ex culpa magna. Commodo occaecat et in consequat cillum laborum magna adipisicing excepteur. Do ut Lorem esse voluptate officia ea aliquip proident amet veniam minim nulla adipisicing. Enim consectetur incididunt laborum voluptate tempor deserunt non laboris. Aliquip deserunt aute irure dolore magna anim aliquip sint magna Lorem. Officia laboris nulla officia sint labore nisi. Do Lorem id in est esse adipisicing id fugiat enim esse laborum.','registered':'Wednesday, October 3, 2018 9:26 PM','latitude':'-88.790637','longitude':'138.817328','tags':['duis','ea','magna','ea','incididunt'],'greeting':'Hello, Alice! You have 8 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0eda01886247b6a4f3d','index':94,'guid':'17c9f4d3-7d72-44e3-8f7c-08d7de920f46','isActive':false,'balance':'$3,173.29','picture':'http://placehold.it/32x32','age':31,'eyeColor':'blue','name':{'first':'Schwartz','last':'Mccormick'},'company':'EVIDENDS','email':'schwartz.mccormick@evidends.tv','phone':'+1 (924) 531-2802','address':'160 Midwood Street, Indio, Palau, 4241','about':'Anim reprehenderit et et adipisicing voluptate consequat elit. Sint Lorem laboris Lorem minim nostrud aute reprehenderit elit aute quis nulla. Officia aute eiusmod mollit cillum eu aliquip non enim ea occaecat quis fugiat occaecat officia. Eiusmod culpa exercitation dolor aliqua enim occaecat nisi cupidatat duis ex dolore id. Id consequat aliqua cupidatat ut. Sit nisi est sunt culpa ullamco excepteur sunt pariatur incididunt amet. Ut tempor duis velit eu ut id culpa aute anim occaecat labore.','registered':'Thursday, March 2, 2017 5:57 PM','latitude':'38.618587','longitude':'-165.142529','tags':['ad','reprehenderit','magna','elit','mollit'],'greeting':'Hello, Schwartz! You have 10 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed51be4df456ec2bc9','index':95,'guid':'44f68f65-959b-4ec2-bd2a-1f30035f76fc','isActive':false,'balance':'$3,242.24','picture':'http://placehold.it/32x32','age':39,'eyeColor':'blue','name':{'first':'Bonita','last':'Stevens'},'company':'SLOFAST','email':'bonita.stevens@slofast.co.uk','phone':'+1 (886) 473-2105','address':'459 Bushwick Court, Kilbourne, Rhode Island, 9450','about':'Consequat reprehenderit qui reprehenderit nisi sit est in qui aliquip amet. Ex deserunt cupidatat amet cillum eiusmod irure anim in amet proident voluptate. Ad officia culpa in non incididunt do.','registered':'Saturday, August 22, 2015 5:23 AM','latitude':'60.013542','longitude':'58.242132','tags':['aute','adipisicing','in','cillum','officia'],'greeting':'Hello, Bonita! You have 5 unread messages.','favoriteFruit':'banana'},{'_id':'5c5ab0ed50a55e3587993f68','index':96,'guid':'652e434f-221e-4899-af12-38dca5c9621d','isActive':false,'balance':'$2,720.06','picture':'http://placehold.it/32x32','age':28,'eyeColor':'green','name':{'first':'Charmaine','last':'Jackson'},'company':'FLUM','email':'charmaine.jackson@flum.io','phone':'+1 (947) 573-2692','address':'788 Windsor Place, Highland, Arkansas, 8869','about':'Dolore reprehenderit irure excepteur eu reprehenderit sint Lorem ut amet in. Consequat anim elit sunt aliquip incididunt. Culpa consequat do exercitation dolor enim dolor sunt sit excepteur ad anim. Dolor aute elit velit mollit minim eu.','registered':'Wednesday, April 6, 2016 7:54 PM','latitude':'25.756553','longitude':'-5.482531','tags':['amet','sint','consequat','est','ex'],'greeting':'Hello, Charmaine! You have 10 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed213621949bbdd5d3','index':97,'guid':'7d7d93d8-3e37-4b4a-9fa2-591fb7d153ce','isActive':true,'balance':'$1,370.63','picture':'http://placehold.it/32x32','age':36,'eyeColor':'brown','name':{'first':'Petersen','last':'Cooley'},'company':'ROTODYNE','email':'petersen.cooley@rotodyne.me','phone':'+1 (929) 563-3339','address':'338 Pioneer Street, Carbonville, Missouri, 3030','about':'Cillum elit dolore labore aute. Cillum ea incididunt cupidatat consequat sint eu mollit. Excepteur commodo eiusmod ex Lorem enim velit minim.','registered':'Friday, December 8, 2017 5:53 AM','latitude':'-10.576254','longitude':'-111.176861','tags':['veniam','eu','eiusmod','dolore','voluptate'],'greeting':'Hello, Petersen! You have 9 unread messages.','favoriteFruit':'apple'},{'_id':'5c5ab0ed3e938138d58ed453','index':98,'guid':'d6fea4a3-03f6-46ee-90b9-8ec51a585e29','isActive':true,'balance':'$1,216.54','picture':'http://placehold.it/32x32','age':39,'eyeColor':'blue','name':{'first':'Rosanne','last':'Terry'},'company':'EXTREMO','email':'rosanne.terry@extremo.com','phone':'+1 (812) 496-2691','address':'368 Rockaway Avenue, Gloucester, Illinois, 7913','about':'Duis et nostrud duis quis minim eiusmod culpa do ea ad pariatur tempor. Velit veniam aliqua aliquip est enim ex et culpa dolor ullamco culpa officia. Eu id occaecat aute cillum aute sit aute laboris ipsum voluptate ex. Amet tempor minim tempor Lorem quis dolore. Pariatur consequat dolore nulla veniam dolor exercitation consequat nulla laboris incididunt do. Dolore do tempor deserunt exercitation incididunt officia incididunt ut do reprehenderit do eiusmod nulla.','registered':'Sunday, August 6, 2017 12:46 PM','latitude':'-43.257964','longitude':'-45.147686','tags':['et','incididunt','esse','commodo','ipsum'],'greeting':'Hello, Rosanne! You have 6 unread messages.','favoriteFruit':'strawberry'},{'_id':'5c5ab0ed632b1a1d65501d6b','index':99,'guid':'bf8c6ac1-ee18-48ee-ae94-ea515a53c951','isActive':true,'balance':'$2,905.58','picture':'http://placehold.it/32x32','age':21,'eyeColor':'blue','name':{'first':'Irene','last':'Castro'},'company':'POLARIA','email':'irene.castro@polaria.org','phone':'+1 (818) 417-3761','address':'901 Dupont Street, Sperryville, Oklahoma, 953','about':'Pariatur minim laboris aliqua dolor aliquip consequat ea do duis voluptate id Lorem. In reprehenderit et adipisicing anim elit incididunt velit in laborum laborum. Qui minim magna et amet sit do voluptate reprehenderit ea sit sint velit.','registered':'Tuesday, August 18, 2015 10:48 AM','latitude':'-7.004055','longitude':'116.052433','tags':['sit','proident','enim','ullamco','non'],'greeting':'Hello, Irene! You have 10 unread messages.','favoriteFruit':'apple'}]"
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/cloud/testdata/plan-no-changes/main.tf b/v1.5.7/internal/cloud/testdata/plan-no-changes/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-no-changes/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/plan-no-changes/plan.log b/v1.5.7/internal/cloud/testdata/plan-no-changes/plan.log
new file mode 100644
index 0000000..7041681
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-no-changes/plan.log
@@ -0,0 +1,17 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+null_resource.hello: Refreshing state... (ID: 8657651096157629581)
+
+------------------------------------------------------------------------
+
+No changes. Infrastructure is up-to-date.
+
+This means that Terraform did not detect any differences between your
+configuration and real physical resources that exist. As a result, no
+actions need to be performed.
diff --git a/v1.5.7/internal/cloud/testdata/plan-no-changes/policy.log b/v1.5.7/internal/cloud/testdata/plan-no-changes/policy.log
new file mode 100644
index 0000000..b0cb1e5
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-no-changes/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: true
+
+This result means that Sentinel policies returned true and the protected
+behavior is allowed by Sentinel policies.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (soft-mandatory)
+
+Result: true
+
+TRUE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/cloud/testdata/plan-policy-hard-failed/main.tf b/v1.5.7/internal/cloud/testdata/plan-policy-hard-failed/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-policy-hard-failed/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/plan-policy-hard-failed/plan.log b/v1.5.7/internal/cloud/testdata/plan-policy-hard-failed/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-policy-hard-failed/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/cloud/testdata/plan-policy-hard-failed/policy.log b/v1.5.7/internal/cloud/testdata/plan-policy-hard-failed/policy.log
new file mode 100644
index 0000000..5d6e693
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-policy-hard-failed/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: false
+
+Sentinel evaluated to false because one or more Sentinel policies evaluated
+to false. This false was not due to an undefined value or runtime error.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (hard-mandatory)
+
+Result: false
+
+FALSE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/cloud/testdata/plan-policy-passed/main.tf b/v1.5.7/internal/cloud/testdata/plan-policy-passed/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-policy-passed/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/plan-policy-passed/plan.log b/v1.5.7/internal/cloud/testdata/plan-policy-passed/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-policy-passed/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/cloud/testdata/plan-policy-passed/policy.log b/v1.5.7/internal/cloud/testdata/plan-policy-passed/policy.log
new file mode 100644
index 0000000..b0cb1e5
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-policy-passed/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: true
+
+This result means that Sentinel policies returned true and the protected
+behavior is allowed by Sentinel policies.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (soft-mandatory)
+
+Result: true
+
+TRUE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/cloud/testdata/plan-policy-soft-failed/main.tf b/v1.5.7/internal/cloud/testdata/plan-policy-soft-failed/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-policy-soft-failed/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/plan-policy-soft-failed/plan.log b/v1.5.7/internal/cloud/testdata/plan-policy-soft-failed/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-policy-soft-failed/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/cloud/testdata/plan-policy-soft-failed/policy.log b/v1.5.7/internal/cloud/testdata/plan-policy-soft-failed/policy.log
new file mode 100644
index 0000000..3e4ebed
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-policy-soft-failed/policy.log
@@ -0,0 +1,12 @@
+Sentinel Result: false
+
+Sentinel evaluated to false because one or more Sentinel policies evaluated
+to false. This false was not due to an undefined value or runtime error.
+
+1 policies evaluated.
+
+## Policy 1: Passthrough.sentinel (soft-mandatory)
+
+Result: false
+
+FALSE - Passthrough.sentinel:1:1 - Rule "main"
diff --git a/v1.5.7/internal/cloud/testdata/plan-variables/main.tf b/v1.5.7/internal/cloud/testdata/plan-variables/main.tf
new file mode 100644
index 0000000..955e8b4
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-variables/main.tf
@@ -0,0 +1,4 @@
+variable "foo" {}
+variable "bar" {}
+
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/plan-variables/plan.log b/v1.5.7/internal/cloud/testdata/plan-variables/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-variables/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/cloud/testdata/plan-with-error/main.tf b/v1.5.7/internal/cloud/testdata/plan-with-error/main.tf
new file mode 100644
index 0000000..bc45f28
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-with-error/main.tf
@@ -0,0 +1,5 @@
+resource "null_resource" "foo" {
+  triggers {
+    random = "${guid()}"
+  }
+}
diff --git a/v1.5.7/internal/cloud/testdata/plan-with-error/plan.log b/v1.5.7/internal/cloud/testdata/plan-with-error/plan.log
new file mode 100644
index 0000000..4344a37
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-with-error/plan.log
@@ -0,0 +1,10 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+
+Error: null_resource.foo: 1 error(s) occurred:
+
+* null_resource.foo: 1:3: unknown function called: guid in:
+
+${guid()}
diff --git a/v1.5.7/internal/cloud/testdata/plan-with-working-directory/terraform/main.tf b/v1.5.7/internal/cloud/testdata/plan-with-working-directory/terraform/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-with-working-directory/terraform/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/plan-with-working-directory/terraform/plan.log b/v1.5.7/internal/cloud/testdata/plan-with-working-directory/terraform/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan-with-working-directory/terraform/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/cloud/testdata/plan/main.tf b/v1.5.7/internal/cloud/testdata/plan/main.tf
new file mode 100644
index 0000000..3911a2a
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan/main.tf
@@ -0,0 +1 @@
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/cloud/testdata/plan/plan.log b/v1.5.7/internal/cloud/testdata/plan/plan.log
new file mode 100644
index 0000000..5849e57
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/plan/plan.log
@@ -0,0 +1,21 @@
+Terraform v0.11.7
+
+Configuring remote state backend...
+Initializing Terraform configuration...
+Refreshing Terraform state in-memory prior to plan...
+The refreshed state will be used to calculate this plan, but will not be
+persisted to local or remote state storage.
+
+------------------------------------------------------------------------
+
+An execution plan has been generated and is shown below.
+Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  + null_resource.foo
+      id: <computed>
+
+
+Plan: 1 to add, 0 to change, 0 to destroy.
diff --git a/v1.5.7/internal/cloud/testdata/refresh/main.tf b/v1.5.7/internal/cloud/testdata/refresh/main.tf
new file mode 100644
index 0000000..8d61d5f
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/refresh/main.tf
@@ -0,0 +1,6 @@
+resource "random_pet" "always_new" {
+  keepers = {
+    uuid = uuid() # Force a new name each time
+  }
+  length = 3
+}
diff --git a/v1.5.7/internal/cloud/testdata/variables/main.tf b/v1.5.7/internal/cloud/testdata/variables/main.tf
new file mode 100644
index 0000000..9e1a0a4
--- /dev/null
+++ b/v1.5.7/internal/cloud/testdata/variables/main.tf
@@ -0,0 +1,8 @@
+variable "key1" {
+}
+
+variable "key2" {
+}
+
+variable "key3" {
+}
diff --git a/v1.5.7/internal/cloud/testing.go b/v1.5.7/internal/cloud/testing.go
new file mode 100644
index 0000000..0168f8b
--- /dev/null
+++ b/v1.5.7/internal/cloud/testing.go
@@ -0,0 +1,525 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"path"
+	"testing"
+	"time"
+
+	tfe "github.com/hashicorp/go-tfe"
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform-svchost/auth"
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/mitchellh/cli"
+	"github.com/mitchellh/colorstring"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/jsonformat"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/httpclient"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/hashicorp/terraform/version"
+
+	backendLocal "github.com/hashicorp/terraform/internal/backend/local"
+)
+
+const (
+	testCred = "test-auth-token"
+)
+
+var (
+	tfeHost  = svchost.Hostname(defaultHostname)
+	credsSrc = auth.StaticCredentialsSource(map[svchost.Hostname]map[string]interface{}{
+		tfeHost: {"token": testCred},
+	})
+	testBackendSingleWorkspaceName = "app-prod"
+	defaultTFCPing                 = map[string]func(http.ResponseWriter, *http.Request){
+		"/api/v2/ping": func(w http.ResponseWriter, r *http.Request) {
+			w.Header().Set("Content-Type", "application/json")
+			w.Header().Set("TFP-API-Version", "2.5")
+			w.Header().Set("TFP-AppName", "Terraform Cloud")
+		},
+	}
+)
+
+// mockInput is a mock implementation of terraform.UIInput.
+type mockInput struct {
+	answers map[string]string
+}
+
+func (m *mockInput) Input(ctx context.Context, opts *terraform.InputOpts) (string, error) {
+	v, ok := m.answers[opts.Id]
+	if !ok {
+		return "", fmt.Errorf("unexpected input request in test: %s", opts.Id)
+	}
+	if v == "wait-for-external-update" {
+		select {
+		case <-ctx.Done():
+		case <-time.After(time.Minute):
+		}
+	}
+	delete(m.answers, opts.Id)
+	return v, nil
+}
+
+func testInput(t *testing.T, answers map[string]string) *mockInput {
+	return &mockInput{answers: answers}
+}
+
+func testBackendWithName(t *testing.T) (*Cloud, func()) {
+	obj := cty.ObjectVal(map[string]cty.Value{
+		"hostname":     cty.NullVal(cty.String),
+		"organization": cty.StringVal("hashicorp"),
+		"token":        cty.NullVal(cty.String),
+		"workspaces": cty.ObjectVal(map[string]cty.Value{
+			"name": cty.StringVal(testBackendSingleWorkspaceName),
+			"tags": cty.NullVal(cty.Set(cty.String)),
+		}),
+	})
+	return testBackend(t, obj, defaultTFCPing)
+}
+
+func testBackendWithTags(t *testing.T) (*Cloud, func()) {
+	obj := cty.ObjectVal(map[string]cty.Value{
+		"hostname":     cty.NullVal(cty.String),
+		"organization": cty.StringVal("hashicorp"),
+		"token":        cty.NullVal(cty.String),
+		"workspaces": cty.ObjectVal(map[string]cty.Value{
+			"name": cty.NullVal(cty.String),
+			"tags": cty.SetVal(
+				[]cty.Value{
+					cty.StringVal("billing"),
+				},
+			),
+		}),
+	})
+	return testBackend(t, obj, nil)
+}
+
+func testBackendNoOperations(t *testing.T) (*Cloud, func()) {
+	obj := cty.ObjectVal(map[string]cty.Value{
+		"hostname":     cty.NullVal(cty.String),
+		"organization": cty.StringVal("no-operations"),
+		"token":        cty.NullVal(cty.String),
+		"workspaces": cty.ObjectVal(map[string]cty.Value{
+			"name": cty.StringVal(testBackendSingleWorkspaceName),
+			"tags": cty.NullVal(cty.Set(cty.String)),
+		}),
+	})
+	return testBackend(t, obj, nil)
+}
+
+func testBackendWithHandlers(t *testing.T, handlers map[string]func(http.ResponseWriter, *http.Request)) (*Cloud, func()) {
+	obj := cty.ObjectVal(map[string]cty.Value{
+		"hostname":     cty.NullVal(cty.String),
+		"organization": cty.StringVal("hashicorp"),
+		"token":        cty.NullVal(cty.String),
+		"workspaces": cty.ObjectVal(map[string]cty.Value{
+			"name": cty.StringVal(testBackendSingleWorkspaceName),
+			"tags": cty.NullVal(cty.Set(cty.String)),
+		}),
+	})
+	return testBackend(t, obj, handlers)
+}
+
+func testCloudState(t *testing.T) *State {
+	b, bCleanup := testBackendWithName(t)
+	defer bCleanup()
+
+	raw, err := b.StateMgr(testBackendSingleWorkspaceName)
+	if err != nil {
+		t.Fatalf("error: %v", err)
+	}
+
+	return raw.(*State)
+}
+
+func testBackendWithOutputs(t *testing.T) (*Cloud, func()) {
+	b, cleanup := testBackendWithName(t)
+
+	// Get a new mock client to use for adding outputs
+	mc := NewMockClient()
+
+	mc.StateVersionOutputs.create("svo-abcd", &tfe.StateVersionOutput{
+		ID:           "svo-abcd",
+		Value:        "foobar",
+		Sensitive:    true,
+		Type:         "string",
+		Name:         "sensitive_output",
+		DetailedType: "string",
+	})
+
+	mc.StateVersionOutputs.create("svo-zyxw", &tfe.StateVersionOutput{
+		ID:           "svo-zyxw",
+		Value:        "bazqux",
+		Type:         "string",
+		Name:         "nonsensitive_output",
+		DetailedType: "string",
+	})
+
+	var dt interface{}
+	var val interface{}
+	err := json.Unmarshal([]byte(`["object", {"foo":"string"}]`), &dt)
+	if err != nil {
+		t.Fatalf("could not unmarshal detailed type: %s", err)
+	}
+	err = json.Unmarshal([]byte(`{"foo":"bar"}`), &val)
+	if err != nil {
+		t.Fatalf("could not unmarshal value: %s", err)
+	}
+	mc.StateVersionOutputs.create("svo-efgh", &tfe.StateVersionOutput{
+		ID:           "svo-efgh",
+		Value:        val,
+		Type:         "object",
+		Name:         "object_output",
+		DetailedType: dt,
+	})
+
+	err = json.Unmarshal([]byte(`["list", "bool"]`), &dt)
+	if err != nil {
+		t.Fatalf("could not unmarshal detailed type: %s", err)
+	}
+	err = json.Unmarshal([]byte(`[true, false, true, true]`), &val)
+	if err != nil {
+		t.Fatalf("could not unmarshal value: %s", err)
+	}
+	mc.StateVersionOutputs.create("svo-ijkl", &tfe.StateVersionOutput{
+		ID:           "svo-ijkl",
+		Value:        val,
+		Type:         "array",
+		Name:         "list_output",
+		DetailedType: dt,
+	})
+
+	b.client.StateVersionOutputs = mc.StateVersionOutputs
+
+	return b, cleanup
+}
+
+func testBackend(t *testing.T, obj cty.Value, handlers map[string]func(http.ResponseWriter, *http.Request)) (*Cloud, func()) {
+	var s *httptest.Server
+	if handlers != nil {
+		s = testServerWithHandlers(handlers)
+	} else {
+		s = testServer(t)
+	}
+	b := New(testDisco(s))
+
+	// Configure the backend so the client is created.
+	newObj, valDiags := b.PrepareConfig(obj)
+	if len(valDiags) != 0 {
+		t.Fatalf("testBackend: backend.PrepareConfig() failed: %s", valDiags.ErrWithWarnings())
+	}
+	obj = newObj
+
+	confDiags := b.Configure(obj)
+	if len(confDiags) != 0 {
+		t.Fatalf("testBackend: backend.Configure() failed: %s", confDiags.ErrWithWarnings())
+	}
+
+	// Get a new mock client.
+	mc := NewMockClient()
+
+	// Replace the services we use with our mock services.
+	b.CLI = cli.NewMockUi()
+	b.client.Applies = mc.Applies
+	b.client.ConfigurationVersions = mc.ConfigurationVersions
+	b.client.CostEstimates = mc.CostEstimates
+	b.client.Organizations = mc.Organizations
+	b.client.Plans = mc.Plans
+	b.client.TaskStages = mc.TaskStages
+	b.client.PolicySetOutcomes = mc.PolicySetOutcomes
+	b.client.PolicyChecks = mc.PolicyChecks
+	b.client.Runs = mc.Runs
+	b.client.RunEvents = mc.RunEvents
+	b.client.StateVersions = mc.StateVersions
+	b.client.StateVersionOutputs = mc.StateVersionOutputs
+	b.client.Variables = mc.Variables
+	b.client.Workspaces = mc.Workspaces
+
+	// Set local to a local test backend.
+	b.local = testLocalBackend(t, b)
+	b.input = true
+
+	baseURL, err := url.Parse("https://app.terraform.io")
+	if err != nil {
+		t.Fatalf("testBackend: failed to parse base URL for client")
+	}
+	baseURL.Path = "/api/v2/"
+
+	readRedactedPlan = func(ctx context.Context, baseURL url.URL, token, planID string) (*jsonformat.Plan, error) {
+		return mc.RedactedPlans.Read(ctx, baseURL.Hostname(), token, planID)
+	}
+
+	ctx := context.Background()
+
+	// Create the organization.
+	_, err = b.client.Organizations.Create(ctx, tfe.OrganizationCreateOptions{
+		Name: tfe.String(b.organization),
+	})
+	if err != nil {
+		t.Fatalf("error: %v", err)
+	}
+
+	// Create the default workspace if required.
+	if b.WorkspaceMapping.Name != "" {
+		_, err = b.client.Workspaces.Create(ctx, b.organization, tfe.WorkspaceCreateOptions{
+			Name: tfe.String(b.WorkspaceMapping.Name),
+		})
+		if err != nil {
+			t.Fatalf("error: %v", err)
+		}
+	}
+
+	return b, s.Close
+}
+
+// testUnconfiguredBackend is used for testing the configuration of the backend
+// with the mock client
+func testUnconfiguredBackend(t *testing.T) (*Cloud, func()) {
+	s := testServer(t)
+	b := New(testDisco(s))
+
+	// Normally, the client is created during configuration, but the configuration uses the
+	// client to read entitlements.
+	var err error
+	b.client, err = tfe.NewClient(&tfe.Config{
+		Token: "fake-token",
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Get a new mock client.
+	mc := NewMockClient()
+
+	// Replace the services we use with our mock services.
+	b.CLI = cli.NewMockUi()
+	b.client.Applies = mc.Applies
+	b.client.ConfigurationVersions = mc.ConfigurationVersions
+	b.client.CostEstimates = mc.CostEstimates
+	b.client.Organizations = mc.Organizations
+	b.client.Plans = mc.Plans
+	b.client.PolicySetOutcomes = mc.PolicySetOutcomes
+	b.client.PolicyChecks = mc.PolicyChecks
+	b.client.Runs = mc.Runs
+	b.client.RunEvents = mc.RunEvents
+	b.client.StateVersions = mc.StateVersions
+	b.client.Variables = mc.Variables
+	b.client.Workspaces = mc.Workspaces
+
+	baseURL, err := url.Parse("https://app.terraform.io")
+	if err != nil {
+		t.Fatalf("testBackend: failed to parse base URL for client")
+	}
+	baseURL.Path = "/api/v2/"
+
+	readRedactedPlan = func(ctx context.Context, baseURL url.URL, token, planID string) (*jsonformat.Plan, error) {
+		return mc.RedactedPlans.Read(ctx, baseURL.Hostname(), token, planID)
+	}
+
+	// Set local to a local test backend.
+	b.local = testLocalBackend(t, b)
+
+	return b, s.Close
+}
+
+func testLocalBackend(t *testing.T, cloud *Cloud) backend.Enhanced {
+	b := backendLocal.NewWithBackend(cloud)
+
+	// Add a test provider to the local backend.
+	p := backendLocal.TestLocalProvider(t, b, "null", &terraform.ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"null_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{NewState: cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("yes"),
+	})}
+
+	return b
+}
+
+// testServer returns a started *httptest.Server used for local testing with the default set of
+// request handlers.
+func testServer(t *testing.T) *httptest.Server {
+	return testServerWithHandlers(testDefaultRequestHandlers)
+}
+
+// testServerWithHandlers returns a started *httptest.Server with the given set of request handlers
+// overriding any default request handlers (testDefaultRequestHandlers).
+func testServerWithHandlers(handlers map[string]func(http.ResponseWriter, *http.Request)) *httptest.Server {
+	mux := http.NewServeMux()
+	for route, handler := range handlers {
+		mux.HandleFunc(route, handler)
+	}
+	for route, handler := range testDefaultRequestHandlers {
+		if handlers[route] == nil {
+			mux.HandleFunc(route, handler)
+		}
+	}
+
+	return httptest.NewServer(mux)
+}
+
+// testDefaultRequestHandlers is a map of request handlers intended to be used in a request
+// multiplexer for a test server. A caller may use testServerWithHandlers to start a server with
+// this base set of routes, and override a particular route for whatever edge case is being tested.
+var testDefaultRequestHandlers = map[string]func(http.ResponseWriter, *http.Request){
+	// Respond to service discovery calls.
+	"/well-known/terraform.json": func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/json")
+		io.WriteString(w, `{
+  "tfe.v2": "/api/v2/",
+}`)
+	},
+
+	// Respond to service version constraints calls.
+	"/v1/versions/": func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/json")
+		io.WriteString(w, fmt.Sprintf(`{
+  "service": "%s",
+  "product": "terraform",
+  "minimum": "0.1.0",
+  "maximum": "10.0.0"
+}`, path.Base(r.URL.Path)))
+	},
+
+	// Respond to pings to get the API version header.
+	"/api/v2/ping": func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/json")
+		w.Header().Set("TFP-API-Version", "2.5")
+	},
+
+	// Respond to the initial query to read the hashicorp org entitlements.
+	"/api/v2/organizations/hashicorp/entitlement-set": func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/vnd.api+json")
+		io.WriteString(w, `{
+  "data": {
+    "id": "org-GExadygjSbKP8hsY",
+    "type": "entitlement-sets",
+    "attributes": {
+      "operations": true,
+      "private-module-registry": true,
+      "sentinel": true,
+      "state-storage": true,
+      "teams": true,
+      "vcs-integrations": true
+    }
+  }
+}`)
+	},
+
+	// Respond to the initial query to read the no-operations org entitlements.
+	"/api/v2/organizations/no-operations/entitlement-set": func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/vnd.api+json")
+		io.WriteString(w, `{
+  "data": {
+    "id": "org-ufxa3y8jSbKP8hsT",
+    "type": "entitlement-sets",
+    "attributes": {
+      "operations": false,
+      "private-module-registry": true,
+      "sentinel": true,
+      "state-storage": true,
+      "teams": true,
+      "vcs-integrations": true
+    }
+  }
+}`)
+	},
+
+	// All tests that are assumed to pass will use the hashicorp organization,
+	// so for all other organization requests we will return a 404.
+	"/api/v2/organizations/": func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(404)
+		io.WriteString(w, `{
+  "errors": [
+    {
+      "status": "404",
+      "title": "not found"
+    }
+  ]
+}`)
+	},
+}
+
+func mockColorize() *colorstring.Colorize {
+	colors := make(map[string]string)
+	for k, v := range colorstring.DefaultColors {
+		colors[k] = v
+	}
+	colors["purple"] = "38;5;57"
+
+	return &colorstring.Colorize{
+		Colors:  colors,
+		Disable: false,
+		Reset:   true,
+	}
+}
+
+func mockSROWorkspace(t *testing.T, b *Cloud, workspaceName string) {
+	_, err := b.client.Workspaces.Update(context.Background(), "hashicorp", workspaceName, tfe.WorkspaceUpdateOptions{
+		StructuredRunOutputEnabled: tfe.Bool(true),
+		TerraformVersion:           tfe.String("1.4.0"),
+	})
+	if err != nil {
+		t.Fatalf("Error enabling SRO on workspace %s: %v", workspaceName, err)
+	}
+}
+
+// testDisco returns a *disco.Disco mapping app.terraform.io and
+// localhost to a local test server.
+func testDisco(s *httptest.Server) *disco.Disco {
+	services := map[string]interface{}{
+		"tfe.v2": fmt.Sprintf("%s/api/v2/", s.URL),
+	}
+	d := disco.NewWithCredentialsSource(credsSrc)
+	d.SetUserAgent(httpclient.TerraformUserAgent(version.String()))
+
+	d.ForceHostServices(svchost.Hostname(defaultHostname), services)
+	d.ForceHostServices(svchost.Hostname("localhost"), services)
+	d.ForceHostServices(svchost.Hostname("nontfe.local"), nil)
+	return d
+}
+
+type unparsedVariableValue struct {
+	value  string
+	source terraform.ValueSourceType
+}
+
+func (v *unparsedVariableValue) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) {
+	return &terraform.InputValue{
+		Value:      cty.StringVal(v.value),
+		SourceType: v.source,
+	}, tfdiags.Diagnostics{}
+}
+
+// testVariable returns a backend.UnparsedVariableValue used for testing.
+func testVariables(s terraform.ValueSourceType, vs ...string) map[string]backend.UnparsedVariableValue {
+	vars := make(map[string]backend.UnparsedVariableValue, len(vs))
+	for _, v := range vs {
+		vars[v] = &unparsedVariableValue{
+			value:  v,
+			source: s,
+		}
+	}
+	return vars
+}
diff --git a/v1.5.7/internal/cloud/tfe_client_mock.go b/v1.5.7/internal/cloud/tfe_client_mock.go
new file mode 100644
index 0000000..83878c7
--- /dev/null
+++ b/v1.5.7/internal/cloud/tfe_client_mock.go
@@ -0,0 +1,1805 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cloud
+
+import (
+	"bytes"
+	"context"
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"math/rand"
+	"os"
+	"path/filepath"
+	"strings"
+	"sync"
+	"time"
+
+	tfe "github.com/hashicorp/go-tfe"
+	"github.com/mitchellh/copystructure"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+type MockClient struct {
+	Applies               *MockApplies
+	ConfigurationVersions *MockConfigurationVersions
+	CostEstimates         *MockCostEstimates
+	Organizations         *MockOrganizations
+	Plans                 *MockPlans
+	PolicySetOutcomes     *MockPolicySetOutcomes
+	TaskStages            *MockTaskStages
+	RedactedPlans         *MockRedactedPlans
+	PolicyChecks          *MockPolicyChecks
+	Runs                  *MockRuns
+	RunEvents             *MockRunEvents
+	StateVersions         *MockStateVersions
+	StateVersionOutputs   *MockStateVersionOutputs
+	Variables             *MockVariables
+	Workspaces            *MockWorkspaces
+}
+
+func NewMockClient() *MockClient {
+	c := &MockClient{}
+	c.Applies = newMockApplies(c)
+	c.ConfigurationVersions = newMockConfigurationVersions(c)
+	c.CostEstimates = newMockCostEstimates(c)
+	c.Organizations = newMockOrganizations(c)
+	c.Plans = newMockPlans(c)
+	c.TaskStages = newMockTaskStages(c)
+	c.PolicySetOutcomes = newMockPolicySetOutcomes(c)
+	c.PolicyChecks = newMockPolicyChecks(c)
+	c.Runs = newMockRuns(c)
+	c.RunEvents = newMockRunEvents(c)
+	c.StateVersions = newMockStateVersions(c)
+	c.StateVersionOutputs = newMockStateVersionOutputs(c)
+	c.Variables = newMockVariables(c)
+	c.Workspaces = newMockWorkspaces(c)
+	c.RedactedPlans = newMockRedactedPlans(c)
+	return c
+}
+
+type MockApplies struct {
+	client  *MockClient
+	applies map[string]*tfe.Apply
+	logs    map[string]string
+}
+
+func newMockApplies(client *MockClient) *MockApplies {
+	return &MockApplies{
+		client:  client,
+		applies: make(map[string]*tfe.Apply),
+		logs:    make(map[string]string),
+	}
+}
+
+// create is a helper function to create a mock apply that uses the configured
+// working directory to find the logfile.
+func (m *MockApplies) create(cvID, workspaceID string) (*tfe.Apply, error) {
+	c, ok := m.client.ConfigurationVersions.configVersions[cvID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	if c.Speculative {
+		// Speculative means its plan-only so we don't create a Apply.
+		return nil, nil
+	}
+
+	id := GenerateID("apply-")
+	url := fmt.Sprintf("https://app.terraform.io/_archivist/%s", id)
+
+	a := &tfe.Apply{
+		ID:         id,
+		LogReadURL: url,
+		Status:     tfe.ApplyPending,
+	}
+
+	w, ok := m.client.Workspaces.workspaceIDs[workspaceID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	if w.AutoApply {
+		a.Status = tfe.ApplyRunning
+	}
+
+	m.logs[url] = filepath.Join(
+		m.client.ConfigurationVersions.uploadPaths[cvID],
+		w.WorkingDirectory,
+		"apply.log",
+	)
+	m.applies[a.ID] = a
+
+	return a, nil
+}
+
+func (m *MockApplies) Read(ctx context.Context, applyID string) (*tfe.Apply, error) {
+	a, ok := m.applies[applyID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	// Together with the mockLogReader this allows testing queued runs.
+	if a.Status == tfe.ApplyRunning {
+		a.Status = tfe.ApplyFinished
+	}
+	return a, nil
+}
+
+func (m *MockApplies) Logs(ctx context.Context, applyID string) (io.Reader, error) {
+	a, err := m.Read(ctx, applyID)
+	if err != nil {
+		return nil, err
+	}
+
+	logfile, ok := m.logs[a.LogReadURL]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	if _, err := os.Stat(logfile); os.IsNotExist(err) {
+		return bytes.NewBufferString("logfile does not exist"), nil
+	}
+
+	logs, err := ioutil.ReadFile(logfile)
+	if err != nil {
+		return nil, err
+	}
+
+	done := func() (bool, error) {
+		a, err := m.Read(ctx, applyID)
+		if err != nil {
+			return false, err
+		}
+		if a.Status != tfe.ApplyFinished {
+			return false, nil
+		}
+		return true, nil
+	}
+
+	return &mockLogReader{
+		done: done,
+		logs: bytes.NewBuffer(logs),
+	}, nil
+}
+
+type MockConfigurationVersions struct {
+	client         *MockClient
+	configVersions map[string]*tfe.ConfigurationVersion
+	uploadPaths    map[string]string
+	uploadURLs     map[string]*tfe.ConfigurationVersion
+}
+
+func newMockConfigurationVersions(client *MockClient) *MockConfigurationVersions {
+	return &MockConfigurationVersions{
+		client:         client,
+		configVersions: make(map[string]*tfe.ConfigurationVersion),
+		uploadPaths:    make(map[string]string),
+		uploadURLs:     make(map[string]*tfe.ConfigurationVersion),
+	}
+}
+
+func (m *MockConfigurationVersions) List(ctx context.Context, workspaceID string, options *tfe.ConfigurationVersionListOptions) (*tfe.ConfigurationVersionList, error) {
+	cvl := &tfe.ConfigurationVersionList{}
+	for _, cv := range m.configVersions {
+		cvl.Items = append(cvl.Items, cv)
+	}
+
+	cvl.Pagination = &tfe.Pagination{
+		CurrentPage:  1,
+		NextPage:     1,
+		PreviousPage: 1,
+		TotalPages:   1,
+		TotalCount:   len(cvl.Items),
+	}
+
+	return cvl, nil
+}
+
+func (m *MockConfigurationVersions) Create(ctx context.Context, workspaceID string, options tfe.ConfigurationVersionCreateOptions) (*tfe.ConfigurationVersion, error) {
+	id := GenerateID("cv-")
+	url := fmt.Sprintf("https://app.terraform.io/_archivist/%s", id)
+
+	cv := &tfe.ConfigurationVersion{
+		ID:        id,
+		Status:    tfe.ConfigurationPending,
+		UploadURL: url,
+	}
+
+	m.configVersions[cv.ID] = cv
+	m.uploadURLs[url] = cv
+
+	return cv, nil
+}
+
+func (m *MockConfigurationVersions) Read(ctx context.Context, cvID string) (*tfe.ConfigurationVersion, error) {
+	cv, ok := m.configVersions[cvID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	return cv, nil
+}
+
+func (m *MockConfigurationVersions) ReadWithOptions(ctx context.Context, cvID string, options *tfe.ConfigurationVersionReadOptions) (*tfe.ConfigurationVersion, error) {
+	cv, ok := m.configVersions[cvID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	return cv, nil
+}
+
+func (m *MockConfigurationVersions) Upload(ctx context.Context, url, path string) error {
+	cv, ok := m.uploadURLs[url]
+	if !ok {
+		return errors.New("404 not found")
+	}
+	m.uploadPaths[cv.ID] = path
+	cv.Status = tfe.ConfigurationUploaded
+
+	return m.UploadTarGzip(ctx, url, nil)
+}
+
+func (m *MockConfigurationVersions) UploadTarGzip(ctx context.Context, url string, archive io.Reader) error {
+	return nil
+}
+
+func (m *MockConfigurationVersions) Archive(ctx context.Context, cvID string) error {
+	panic("not implemented")
+}
+
+func (m *MockConfigurationVersions) Download(ctx context.Context, cvID string) ([]byte, error) {
+	panic("not implemented")
+}
+
+type MockCostEstimates struct {
+	client      *MockClient
+	Estimations map[string]*tfe.CostEstimate
+	logs        map[string]string
+}
+
+func newMockCostEstimates(client *MockClient) *MockCostEstimates {
+	return &MockCostEstimates{
+		client:      client,
+		Estimations: make(map[string]*tfe.CostEstimate),
+		logs:        make(map[string]string),
+	}
+}
+
+// create is a helper function to create a mock cost estimation that uses the
+// configured working directory to find the logfile.
+func (m *MockCostEstimates) create(cvID, workspaceID string) (*tfe.CostEstimate, error) {
+	id := GenerateID("ce-")
+
+	ce := &tfe.CostEstimate{
+		ID:                    id,
+		MatchedResourcesCount: 1,
+		ResourcesCount:        1,
+		DeltaMonthlyCost:      "0.00",
+		ProposedMonthlyCost:   "0.00",
+		Status:                tfe.CostEstimateFinished,
+	}
+
+	w, ok := m.client.Workspaces.workspaceIDs[workspaceID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	logfile := filepath.Join(
+		m.client.ConfigurationVersions.uploadPaths[cvID],
+		w.WorkingDirectory,
+		"cost-estimate.log",
+	)
+
+	if _, err := os.Stat(logfile); os.IsNotExist(err) {
+		return nil, nil
+	}
+
+	m.logs[ce.ID] = logfile
+	m.Estimations[ce.ID] = ce
+
+	return ce, nil
+}
+
+func (m *MockCostEstimates) Read(ctx context.Context, costEstimateID string) (*tfe.CostEstimate, error) {
+	ce, ok := m.Estimations[costEstimateID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	return ce, nil
+}
+
+func (m *MockCostEstimates) Logs(ctx context.Context, costEstimateID string) (io.Reader, error) {
+	ce, ok := m.Estimations[costEstimateID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	logfile, ok := m.logs[ce.ID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	if _, err := os.Stat(logfile); os.IsNotExist(err) {
+		return bytes.NewBufferString("logfile does not exist"), nil
+	}
+
+	logs, err := ioutil.ReadFile(logfile)
+	if err != nil {
+		return nil, err
+	}
+
+	ce.Status = tfe.CostEstimateFinished
+
+	return bytes.NewBuffer(logs), nil
+}
+
+type MockOrganizations struct {
+	client        *MockClient
+	organizations map[string]*tfe.Organization
+}
+
+func newMockOrganizations(client *MockClient) *MockOrganizations {
+	return &MockOrganizations{
+		client:        client,
+		organizations: make(map[string]*tfe.Organization),
+	}
+}
+
+func (m *MockOrganizations) List(ctx context.Context, options *tfe.OrganizationListOptions) (*tfe.OrganizationList, error) {
+	orgl := &tfe.OrganizationList{}
+	for _, org := range m.organizations {
+		orgl.Items = append(orgl.Items, org)
+	}
+
+	orgl.Pagination = &tfe.Pagination{
+		CurrentPage:  1,
+		NextPage:     1,
+		PreviousPage: 1,
+		TotalPages:   1,
+		TotalCount:   len(orgl.Items),
+	}
+
+	return orgl, nil
+}
+
+// mockLogReader is a mock logreader that enables testing queued runs.
+type mockLogReader struct {
+	done func() (bool, error)
+	logs *bytes.Buffer
+}
+
+func (m *mockLogReader) Read(l []byte) (int, error) {
+	for {
+		if written, err := m.read(l); err != io.ErrNoProgress {
+			return written, err
+		}
+		time.Sleep(1 * time.Millisecond)
+	}
+}
+
+func (m *mockLogReader) read(l []byte) (int, error) {
+	done, err := m.done()
+	if err != nil {
+		return 0, err
+	}
+	if !done {
+		return 0, io.ErrNoProgress
+	}
+	return m.logs.Read(l)
+}
+
+func (m *MockOrganizations) Create(ctx context.Context, options tfe.OrganizationCreateOptions) (*tfe.Organization, error) {
+	org := &tfe.Organization{Name: *options.Name}
+	m.organizations[org.Name] = org
+	return org, nil
+}
+
+func (m *MockOrganizations) Read(ctx context.Context, name string) (*tfe.Organization, error) {
+	return m.ReadWithOptions(ctx, name, tfe.OrganizationReadOptions{})
+}
+
+func (m *MockOrganizations) ReadWithOptions(ctx context.Context, name string, options tfe.OrganizationReadOptions) (*tfe.Organization, error) {
+	org, ok := m.organizations[name]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	return org, nil
+}
+
+func (m *MockOrganizations) Update(ctx context.Context, name string, options tfe.OrganizationUpdateOptions) (*tfe.Organization, error) {
+	org, ok := m.organizations[name]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	org.Name = *options.Name
+	return org, nil
+
+}
+
+func (m *MockOrganizations) Delete(ctx context.Context, name string) error {
+	delete(m.organizations, name)
+	return nil
+}
+
+func (m *MockOrganizations) ReadCapacity(ctx context.Context, name string) (*tfe.Capacity, error) {
+	var pending, running int
+	for _, r := range m.client.Runs.Runs {
+		if r.Status == tfe.RunPending {
+			pending++
+			continue
+		}
+		running++
+	}
+	return &tfe.Capacity{Pending: pending, Running: running}, nil
+}
+
+func (m *MockOrganizations) ReadEntitlements(ctx context.Context, name string) (*tfe.Entitlements, error) {
+	return &tfe.Entitlements{
+		Operations:            true,
+		PrivateModuleRegistry: true,
+		Sentinel:              true,
+		StateStorage:          true,
+		Teams:                 true,
+		VCSIntegrations:       true,
+	}, nil
+}
+
+func (m *MockOrganizations) ReadRunQueue(ctx context.Context, name string, options tfe.ReadRunQueueOptions) (*tfe.RunQueue, error) {
+	rq := &tfe.RunQueue{}
+
+	for _, r := range m.client.Runs.Runs {
+		rq.Items = append(rq.Items, r)
+	}
+
+	rq.Pagination = &tfe.Pagination{
+		CurrentPage:  1,
+		NextPage:     1,
+		PreviousPage: 1,
+		TotalPages:   1,
+		TotalCount:   len(rq.Items),
+	}
+
+	return rq, nil
+}
+
+type MockRedactedPlans struct {
+	client        *MockClient
+	redactedPlans map[string]*jsonformat.Plan
+}
+
+func newMockRedactedPlans(client *MockClient) *MockRedactedPlans {
+	return &MockRedactedPlans{
+		client:        client,
+		redactedPlans: make(map[string]*jsonformat.Plan),
+	}
+}
+
+func (m *MockRedactedPlans) create(cvID, workspaceID, planID string) error {
+	w, ok := m.client.Workspaces.workspaceIDs[workspaceID]
+	if !ok {
+		return tfe.ErrResourceNotFound
+	}
+
+	planPath := filepath.Join(
+		m.client.ConfigurationVersions.uploadPaths[cvID],
+		w.WorkingDirectory,
+		"plan-redacted.json",
+	)
+
+	redactedPlanFile, err := os.Open(planPath)
+	if err != nil {
+		return err
+	}
+
+	raw, err := ioutil.ReadAll(redactedPlanFile)
+	if err != nil {
+		return err
+	}
+
+	redactedPlan := &jsonformat.Plan{}
+	err = json.Unmarshal(raw, redactedPlan)
+	if err != nil {
+		return err
+	}
+
+	m.redactedPlans[planID] = redactedPlan
+
+	return nil
+}
+
+func (m *MockRedactedPlans) Read(ctx context.Context, hostname, token, planID string) (*jsonformat.Plan, error) {
+	if p, ok := m.redactedPlans[planID]; ok {
+		return p, nil
+	}
+	return nil, tfe.ErrResourceNotFound
+}
+
+type MockPlans struct {
+	client      *MockClient
+	logs        map[string]string
+	planOutputs map[string]string
+	plans       map[string]*tfe.Plan
+}
+
+func newMockPlans(client *MockClient) *MockPlans {
+	return &MockPlans{
+		client:      client,
+		logs:        make(map[string]string),
+		planOutputs: make(map[string]string),
+		plans:       make(map[string]*tfe.Plan),
+	}
+}
+
+// create is a helper function to create a mock plan that uses the configured
+// working directory to find the logfile.
+func (m *MockPlans) create(cvID, workspaceID string) (*tfe.Plan, error) {
+	id := GenerateID("plan-")
+	url := fmt.Sprintf("https://app.terraform.io/_archivist/%s", id)
+
+	p := &tfe.Plan{
+		ID:         id,
+		LogReadURL: url,
+		Status:     tfe.PlanPending,
+	}
+
+	w, ok := m.client.Workspaces.workspaceIDs[workspaceID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	m.logs[url] = filepath.Join(
+		m.client.ConfigurationVersions.uploadPaths[cvID],
+		w.WorkingDirectory,
+		"plan.log",
+	)
+	m.plans[p.ID] = p
+
+	return p, nil
+}
+
+func (m *MockPlans) Read(ctx context.Context, planID string) (*tfe.Plan, error) {
+	p, ok := m.plans[planID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	// Together with the mockLogReader this allows testing queued runs.
+	if p.Status == tfe.PlanRunning {
+		p.Status = tfe.PlanFinished
+	}
+	return p, nil
+}
+
+func (m *MockPlans) Logs(ctx context.Context, planID string) (io.Reader, error) {
+	p, err := m.Read(ctx, planID)
+	if err != nil {
+		return nil, err
+	}
+
+	logfile, ok := m.logs[p.LogReadURL]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	if _, err := os.Stat(logfile); os.IsNotExist(err) {
+		return bytes.NewBufferString("logfile does not exist"), nil
+	}
+
+	logs, err := ioutil.ReadFile(logfile)
+	if err != nil {
+		return nil, err
+	}
+
+	done := func() (bool, error) {
+		p, err := m.Read(ctx, planID)
+		if err != nil {
+			return false, err
+		}
+		if p.Status != tfe.PlanFinished {
+			return false, nil
+		}
+		return true, nil
+	}
+
+	return &mockLogReader{
+		done: done,
+		logs: bytes.NewBuffer(logs),
+	}, nil
+}
+
+func (m *MockPlans) ReadJSONOutput(ctx context.Context, planID string) ([]byte, error) {
+	planOutput, ok := m.planOutputs[planID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	return []byte(planOutput), nil
+}
+
+type MockTaskStages struct {
+	client *MockClient
+}
+
+func newMockTaskStages(client *MockClient) *MockTaskStages {
+	return &MockTaskStages{
+		client: client,
+	}
+}
+
+func (m *MockTaskStages) Override(ctx context.Context, taskStageID string, options tfe.TaskStageOverrideOptions) (*tfe.TaskStage, error) {
+	switch taskStageID {
+	case "ts-err":
+		return nil, errors.New("test error")
+
+	default:
+		return nil, nil
+	}
+}
+
+func (m *MockTaskStages) Read(ctx context.Context, taskStageID string, options *tfe.TaskStageReadOptions) (*tfe.TaskStage, error) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m *MockTaskStages) List(ctx context.Context, runID string, options *tfe.TaskStageListOptions) (*tfe.TaskStageList, error) {
+	//TODO implement me
+	panic("implement me")
+}
+
+type MockPolicySetOutcomes struct {
+	client *MockClient
+}
+
+func newMockPolicySetOutcomes(client *MockClient) *MockPolicySetOutcomes {
+	return &MockPolicySetOutcomes{
+		client: client,
+	}
+}
+
+func (m *MockPolicySetOutcomes) List(ctx context.Context, policyEvaluationID string, options *tfe.PolicySetOutcomeListOptions) (*tfe.PolicySetOutcomeList, error) {
+	switch policyEvaluationID {
+	case "pol-pass":
+		return &tfe.PolicySetOutcomeList{
+			Items: []*tfe.PolicySetOutcome{
+				{
+					ID: policyEvaluationID,
+					Outcomes: []tfe.Outcome{
+						{
+							EnforcementLevel: "mandatory",
+							Query:            "data.example.rule",
+							Status:           "passed",
+							PolicyName:       "policy-pass",
+							Description:      "This policy will pass",
+						},
+					},
+					Overridable:          tfe.Bool(true),
+					Error:                "",
+					PolicySetName:        "policy-set-that-passes",
+					PolicySetDescription: "This policy set will always pass",
+					ResultCount: tfe.PolicyResultCount{
+						AdvisoryFailed:  0,
+						MandatoryFailed: 0,
+						Passed:          1,
+						Errored:         0,
+					},
+				},
+			},
+		}, nil
+	case "pol-fail":
+		return &tfe.PolicySetOutcomeList{
+			Items: []*tfe.PolicySetOutcome{
+				{
+					ID: policyEvaluationID,
+					Outcomes: []tfe.Outcome{
+						{
+							EnforcementLevel: "mandatory",
+							Query:            "data.example.rule",
+							Status:           "failed",
+							PolicyName:       "policy-fail",
+							Description:      "This policy will fail",
+						},
+					},
+					Overridable:          tfe.Bool(true),
+					Error:                "",
+					PolicySetName:        "policy-set-that-fails",
+					PolicySetDescription: "This policy set will always fail",
+					ResultCount: tfe.PolicyResultCount{
+						AdvisoryFailed:  0,
+						MandatoryFailed: 1,
+						Passed:          0,
+						Errored:         0,
+					},
+				},
+			},
+		}, nil
+
+	case "adv-fail":
+		return &tfe.PolicySetOutcomeList{
+			Items: []*tfe.PolicySetOutcome{
+				{
+					ID: policyEvaluationID,
+					Outcomes: []tfe.Outcome{
+						{
+							EnforcementLevel: "advisory",
+							Query:            "data.example.rule",
+							Status:           "failed",
+							PolicyName:       "policy-fail",
+							Description:      "This policy will fail",
+						},
+					},
+					Overridable:          tfe.Bool(true),
+					Error:                "",
+					PolicySetName:        "policy-set-that-fails",
+					PolicySetDescription: "This policy set will always fail",
+					ResultCount: tfe.PolicyResultCount{
+						AdvisoryFailed:  1,
+						MandatoryFailed: 0,
+						Passed:          0,
+						Errored:         0,
+					},
+				},
+			},
+		}, nil
+	default:
+		return &tfe.PolicySetOutcomeList{
+			Items: []*tfe.PolicySetOutcome{
+				{
+					ID: policyEvaluationID,
+					Outcomes: []tfe.Outcome{
+						{
+							EnforcementLevel: "mandatory",
+							Query:            "data.example.rule",
+							Status:           "passed",
+							PolicyName:       "policy-pass",
+							Description:      "This policy will pass",
+						},
+					},
+					Overridable:          tfe.Bool(true),
+					Error:                "",
+					PolicySetName:        "policy-set-that-passes",
+					PolicySetDescription: "This policy set will always pass",
+					ResultCount: tfe.PolicyResultCount{
+						AdvisoryFailed:  0,
+						MandatoryFailed: 0,
+						Passed:          1,
+						Errored:         0,
+					},
+				},
+			},
+		}, nil
+	}
+}
+
+func (m *MockPolicySetOutcomes) Read(ctx context.Context, policySetOutcomeID string) (*tfe.PolicySetOutcome, error) {
+	return nil, nil
+}
+
+type MockPolicyChecks struct {
+	client *MockClient
+	checks map[string]*tfe.PolicyCheck
+	logs   map[string]string
+}
+
+func newMockPolicyChecks(client *MockClient) *MockPolicyChecks {
+	return &MockPolicyChecks{
+		client: client,
+		checks: make(map[string]*tfe.PolicyCheck),
+		logs:   make(map[string]string),
+	}
+}
+
+// create is a helper function to create a mock policy check that uses the
+// configured working directory to find the logfile.
+func (m *MockPolicyChecks) create(cvID, workspaceID string) (*tfe.PolicyCheck, error) {
+	id := GenerateID("pc-")
+
+	pc := &tfe.PolicyCheck{
+		ID:          id,
+		Actions:     &tfe.PolicyActions{},
+		Permissions: &tfe.PolicyPermissions{},
+		Scope:       tfe.PolicyScopeOrganization,
+		Status:      tfe.PolicyPending,
+	}
+
+	w, ok := m.client.Workspaces.workspaceIDs[workspaceID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	logfile := filepath.Join(
+		m.client.ConfigurationVersions.uploadPaths[cvID],
+		w.WorkingDirectory,
+		"policy.log",
+	)
+
+	if _, err := os.Stat(logfile); os.IsNotExist(err) {
+		return nil, nil
+	}
+
+	m.logs[pc.ID] = logfile
+	m.checks[pc.ID] = pc
+
+	return pc, nil
+}
+
+func (m *MockPolicyChecks) List(ctx context.Context, runID string, options *tfe.PolicyCheckListOptions) (*tfe.PolicyCheckList, error) {
+	_, ok := m.client.Runs.Runs[runID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	pcl := &tfe.PolicyCheckList{}
+	for _, pc := range m.checks {
+		pcl.Items = append(pcl.Items, pc)
+	}
+
+	pcl.Pagination = &tfe.Pagination{
+		CurrentPage:  1,
+		NextPage:     1,
+		PreviousPage: 1,
+		TotalPages:   1,
+		TotalCount:   len(pcl.Items),
+	}
+
+	return pcl, nil
+}
+
+func (m *MockPolicyChecks) Read(ctx context.Context, policyCheckID string) (*tfe.PolicyCheck, error) {
+	pc, ok := m.checks[policyCheckID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	logfile, ok := m.logs[pc.ID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	if _, err := os.Stat(logfile); os.IsNotExist(err) {
+		return nil, fmt.Errorf("logfile does not exist")
+	}
+
+	logs, err := ioutil.ReadFile(logfile)
+	if err != nil {
+		return nil, err
+	}
+
+	switch {
+	case bytes.Contains(logs, []byte("Sentinel Result: true")):
+		pc.Status = tfe.PolicyPasses
+	case bytes.Contains(logs, []byte("Sentinel Result: false")):
+		switch {
+		case bytes.Contains(logs, []byte("hard-mandatory")):
+			pc.Status = tfe.PolicyHardFailed
+		case bytes.Contains(logs, []byte("soft-mandatory")):
+			pc.Actions.IsOverridable = true
+			pc.Permissions.CanOverride = true
+			pc.Status = tfe.PolicySoftFailed
+		}
+	default:
+		// As this is an unexpected state, we say the policy errored.
+		pc.Status = tfe.PolicyErrored
+	}
+
+	return pc, nil
+}
+
+func (m *MockPolicyChecks) Override(ctx context.Context, policyCheckID string) (*tfe.PolicyCheck, error) {
+	pc, ok := m.checks[policyCheckID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	pc.Status = tfe.PolicyOverridden
+	return pc, nil
+}
+
+func (m *MockPolicyChecks) Logs(ctx context.Context, policyCheckID string) (io.Reader, error) {
+	pc, ok := m.checks[policyCheckID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	logfile, ok := m.logs[pc.ID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	if _, err := os.Stat(logfile); os.IsNotExist(err) {
+		return bytes.NewBufferString("logfile does not exist"), nil
+	}
+
+	logs, err := ioutil.ReadFile(logfile)
+	if err != nil {
+		return nil, err
+	}
+
+	switch {
+	case bytes.Contains(logs, []byte("Sentinel Result: true")):
+		pc.Status = tfe.PolicyPasses
+	case bytes.Contains(logs, []byte("Sentinel Result: false")):
+		switch {
+		case bytes.Contains(logs, []byte("hard-mandatory")):
+			pc.Status = tfe.PolicyHardFailed
+		case bytes.Contains(logs, []byte("soft-mandatory")):
+			pc.Actions.IsOverridable = true
+			pc.Permissions.CanOverride = true
+			pc.Status = tfe.PolicySoftFailed
+		}
+	default:
+		// As this is an unexpected state, we say the policy errored.
+		pc.Status = tfe.PolicyErrored
+	}
+
+	return bytes.NewBuffer(logs), nil
+}
+
+type MockRuns struct {
+	sync.Mutex
+
+	client     *MockClient
+	Runs       map[string]*tfe.Run
+	workspaces map[string][]*tfe.Run
+
+	// If ModifyNewRun is non-nil, the create method will call it just before
+	// saving a new run in the runs map, so that a calling test can mimic
+	// side-effects that a real server might apply in certain situations.
+	ModifyNewRun func(client *MockClient, options tfe.RunCreateOptions, run *tfe.Run)
+}
+
+func newMockRuns(client *MockClient) *MockRuns {
+	return &MockRuns{
+		client:     client,
+		Runs:       make(map[string]*tfe.Run),
+		workspaces: make(map[string][]*tfe.Run),
+	}
+}
+
+func (m *MockRuns) List(ctx context.Context, workspaceID string, options *tfe.RunListOptions) (*tfe.RunList, error) {
+	m.Lock()
+	defer m.Unlock()
+
+	w, ok := m.client.Workspaces.workspaceIDs[workspaceID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	rl := &tfe.RunList{}
+	for _, run := range m.workspaces[w.ID] {
+		rc, err := copystructure.Copy(run)
+		if err != nil {
+			panic(err)
+		}
+		rl.Items = append(rl.Items, rc.(*tfe.Run))
+	}
+
+	rl.Pagination = &tfe.Pagination{
+		CurrentPage:  1,
+		NextPage:     1,
+		PreviousPage: 1,
+		TotalPages:   1,
+		TotalCount:   len(rl.Items),
+	}
+
+	return rl, nil
+}
+
+func (m *MockRuns) Create(ctx context.Context, options tfe.RunCreateOptions) (*tfe.Run, error) {
+	m.Lock()
+	defer m.Unlock()
+
+	a, err := m.client.Applies.create(options.ConfigurationVersion.ID, options.Workspace.ID)
+	if err != nil {
+		return nil, err
+	}
+
+	ce, err := m.client.CostEstimates.create(options.ConfigurationVersion.ID, options.Workspace.ID)
+	if err != nil {
+		return nil, err
+	}
+
+	p, err := m.client.Plans.create(options.ConfigurationVersion.ID, options.Workspace.ID)
+	if err != nil {
+		return nil, err
+	}
+
+	pc, err := m.client.PolicyChecks.create(options.ConfigurationVersion.ID, options.Workspace.ID)
+	if err != nil {
+		return nil, err
+	}
+
+	r := &tfe.Run{
+		ID:                    GenerateID("run-"),
+		Actions:               &tfe.RunActions{IsCancelable: true},
+		Apply:                 a,
+		CostEstimate:          ce,
+		HasChanges:            false,
+		Permissions:           &tfe.RunPermissions{},
+		Plan:                  p,
+		ReplaceAddrs:          options.ReplaceAddrs,
+		Status:                tfe.RunPending,
+		TargetAddrs:           options.TargetAddrs,
+		AllowConfigGeneration: options.AllowConfigGeneration,
+	}
+
+	if options.Message != nil {
+		r.Message = *options.Message
+	}
+
+	if pc != nil {
+		r.PolicyChecks = []*tfe.PolicyCheck{pc}
+	}
+
+	if options.IsDestroy != nil {
+		r.IsDestroy = *options.IsDestroy
+	}
+
+	if options.Refresh != nil {
+		r.Refresh = *options.Refresh
+	}
+
+	if options.RefreshOnly != nil {
+		r.RefreshOnly = *options.RefreshOnly
+	}
+
+	if options.AllowConfigGeneration != nil && *options.AllowConfigGeneration {
+		r.Plan.GeneratedConfiguration = true
+	}
+
+	w, ok := m.client.Workspaces.workspaceIDs[options.Workspace.ID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	if w.CurrentRun == nil {
+		w.CurrentRun = r
+	}
+
+	r.Workspace = &tfe.Workspace{
+		ID:                         w.ID,
+		StructuredRunOutputEnabled: w.StructuredRunOutputEnabled,
+		TerraformVersion:           w.TerraformVersion,
+	}
+
+	if w.StructuredRunOutputEnabled {
+		err := m.client.RedactedPlans.create(options.ConfigurationVersion.ID, options.Workspace.ID, p.ID)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	if m.ModifyNewRun != nil {
+		// caller-provided callback may modify the run in-place to mimic
+		// side-effects that a real server might take in some situations.
+		m.ModifyNewRun(m.client, options, r)
+	}
+
+	m.Runs[r.ID] = r
+	m.workspaces[options.Workspace.ID] = append(m.workspaces[options.Workspace.ID], r)
+
+	return r, nil
+}
+
+func (m *MockRuns) Read(ctx context.Context, runID string) (*tfe.Run, error) {
+	return m.ReadWithOptions(ctx, runID, nil)
+}
+
+func (m *MockRuns) ReadWithOptions(ctx context.Context, runID string, _ *tfe.RunReadOptions) (*tfe.Run, error) {
+	m.Lock()
+	defer m.Unlock()
+
+	r, ok := m.Runs[runID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	pending := false
+	for _, r := range m.Runs {
+		if r.ID != runID && r.Status == tfe.RunPending {
+			pending = true
+			break
+		}
+	}
+
+	if !pending && r.Status == tfe.RunPending {
+		// Only update the status if there are no other pending runs.
+		r.Status = tfe.RunPlanning
+		r.Plan.Status = tfe.PlanRunning
+	}
+
+	logs, _ := ioutil.ReadFile(m.client.Plans.logs[r.Plan.LogReadURL])
+	if r.Status == tfe.RunPlanning && r.Plan.Status == tfe.PlanFinished {
+		hasChanges := r.IsDestroy ||
+			bytes.Contains(logs, []byte("1 to add")) ||
+			bytes.Contains(logs, []byte("1 to change")) ||
+			bytes.Contains(logs, []byte("1 to import"))
+		if hasChanges {
+			r.Actions.IsCancelable = false
+			r.Actions.IsConfirmable = true
+			r.HasChanges = true
+			r.Permissions.CanApply = true
+		}
+
+		hasError := bytes.Contains(logs, []byte("null_resource.foo: 1 error")) ||
+			bytes.Contains(logs, []byte("Error: Unsupported block type")) ||
+			bytes.Contains(logs, []byte("Error: Conflicting configuration arguments"))
+		if hasError {
+			r.Actions.IsCancelable = false
+			r.HasChanges = false
+			r.Status = tfe.RunErrored
+		}
+	}
+
+	// we must return a copy for the client
+	rc, err := copystructure.Copy(r)
+	if err != nil {
+		panic(err)
+	}
+
+	return rc.(*tfe.Run), nil
+}
+
+func (m *MockRuns) Apply(ctx context.Context, runID string, options tfe.RunApplyOptions) error {
+	m.Lock()
+	defer m.Unlock()
+
+	r, ok := m.Runs[runID]
+	if !ok {
+		return tfe.ErrResourceNotFound
+	}
+	if r.Status != tfe.RunPending {
+		// Only update the status if the run is not pending anymore.
+		r.Status = tfe.RunApplying
+		r.Actions.IsConfirmable = false
+		r.Apply.Status = tfe.ApplyRunning
+	}
+	return nil
+}
+
+func (m *MockRuns) Cancel(ctx context.Context, runID string, options tfe.RunCancelOptions) error {
+	panic("not implemented")
+}
+
+func (m *MockRuns) ForceCancel(ctx context.Context, runID string, options tfe.RunForceCancelOptions) error {
+	panic("not implemented")
+}
+
+func (m *MockRuns) ForceExecute(ctx context.Context, runID string) error {
+	panic("implement me")
+}
+
+func (m *MockRuns) Discard(ctx context.Context, runID string, options tfe.RunDiscardOptions) error {
+	m.Lock()
+	defer m.Unlock()
+
+	r, ok := m.Runs[runID]
+	if !ok {
+		return tfe.ErrResourceNotFound
+	}
+	r.Status = tfe.RunDiscarded
+	r.Actions.IsConfirmable = false
+	return nil
+}
+
+type MockRunEvents struct{}
+
+func newMockRunEvents(_ *MockClient) *MockRunEvents {
+	return &MockRunEvents{}
+}
+
+// List all the runs events of the given run.
+func (m *MockRunEvents) List(ctx context.Context, runID string, options *tfe.RunEventListOptions) (*tfe.RunEventList, error) {
+	return &tfe.RunEventList{
+		Items: []*tfe.RunEvent{},
+	}, nil
+}
+
+func (m *MockRunEvents) Read(ctx context.Context, runEventID string) (*tfe.RunEvent, error) {
+	return m.ReadWithOptions(ctx, runEventID, nil)
+}
+
+func (m *MockRunEvents) ReadWithOptions(ctx context.Context, runEventID string, options *tfe.RunEventReadOptions) (*tfe.RunEvent, error) {
+	return &tfe.RunEvent{
+		ID:        GenerateID("re-"),
+		Action:    "created",
+		CreatedAt: time.Now(),
+	}, nil
+}
+
+type MockStateVersions struct {
+	client        *MockClient
+	states        map[string][]byte
+	stateVersions map[string]*tfe.StateVersion
+	workspaces    map[string][]string
+	outputStates  map[string][]byte
+}
+
+func newMockStateVersions(client *MockClient) *MockStateVersions {
+	return &MockStateVersions{
+		client:        client,
+		states:        make(map[string][]byte),
+		stateVersions: make(map[string]*tfe.StateVersion),
+		workspaces:    make(map[string][]string),
+		outputStates:  make(map[string][]byte),
+	}
+}
+
+func (m *MockStateVersions) List(ctx context.Context, options *tfe.StateVersionListOptions) (*tfe.StateVersionList, error) {
+	svl := &tfe.StateVersionList{}
+	for _, sv := range m.stateVersions {
+		svl.Items = append(svl.Items, sv)
+	}
+
+	svl.Pagination = &tfe.Pagination{
+		CurrentPage:  1,
+		NextPage:     1,
+		PreviousPage: 1,
+		TotalPages:   1,
+		TotalCount:   len(svl.Items),
+	}
+
+	return svl, nil
+}
+
+func (m *MockStateVersions) Create(ctx context.Context, workspaceID string, options tfe.StateVersionCreateOptions) (*tfe.StateVersion, error) {
+	id := GenerateID("sv-")
+	runID := os.Getenv("TFE_RUN_ID")
+	url := fmt.Sprintf("https://app.terraform.io/_archivist/%s", id)
+
+	if runID != "" && (options.Run == nil || runID != options.Run.ID) {
+		return nil, fmt.Errorf("option.Run.ID does not contain the ID exported by TFE_RUN_ID")
+	}
+
+	sv := &tfe.StateVersion{
+		ID:          id,
+		DownloadURL: url,
+		Serial:      *options.Serial,
+	}
+
+	state, err := base64.StdEncoding.DecodeString(*options.State)
+	if err != nil {
+		return nil, err
+	}
+
+	m.states[sv.DownloadURL] = state
+	m.outputStates[sv.ID] = []byte(*options.JSONStateOutputs)
+	m.stateVersions[sv.ID] = sv
+	m.workspaces[workspaceID] = append(m.workspaces[workspaceID], sv.ID)
+
+	return sv, nil
+}
+
+func (m *MockStateVersions) Read(ctx context.Context, svID string) (*tfe.StateVersion, error) {
+	return m.ReadWithOptions(ctx, svID, nil)
+}
+
+func (m *MockStateVersions) ReadWithOptions(ctx context.Context, svID string, options *tfe.StateVersionReadOptions) (*tfe.StateVersion, error) {
+	sv, ok := m.stateVersions[svID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	return sv, nil
+}
+
+func (m *MockStateVersions) ReadCurrent(ctx context.Context, workspaceID string) (*tfe.StateVersion, error) {
+	return m.ReadCurrentWithOptions(ctx, workspaceID, nil)
+}
+
+func (m *MockStateVersions) ReadCurrentWithOptions(ctx context.Context, workspaceID string, options *tfe.StateVersionCurrentOptions) (*tfe.StateVersion, error) {
+	w, ok := m.client.Workspaces.workspaceIDs[workspaceID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	svs, ok := m.workspaces[w.ID]
+	if !ok || len(svs) == 0 {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	sv, ok := m.stateVersions[svs[len(svs)-1]]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	return sv, nil
+}
+
+func (m *MockStateVersions) Download(ctx context.Context, url string) ([]byte, error) {
+	state, ok := m.states[url]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	return state, nil
+}
+
+func (m *MockStateVersions) ListOutputs(ctx context.Context, svID string, options *tfe.StateVersionOutputsListOptions) (*tfe.StateVersionOutputsList, error) {
+	panic("not implemented")
+}
+
+type MockStateVersionOutputs struct {
+	client  *MockClient
+	outputs map[string]*tfe.StateVersionOutput
+}
+
+func newMockStateVersionOutputs(client *MockClient) *MockStateVersionOutputs {
+	return &MockStateVersionOutputs{
+		client:  client,
+		outputs: make(map[string]*tfe.StateVersionOutput),
+	}
+}
+
+// This is a helper function in order to create mocks to be read later
+func (m *MockStateVersionOutputs) create(id string, svo *tfe.StateVersionOutput) {
+	m.outputs[id] = svo
+}
+
+func (m *MockStateVersionOutputs) Read(ctx context.Context, outputID string) (*tfe.StateVersionOutput, error) {
+	result, ok := m.outputs[outputID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	return result, nil
+}
+
+func (m *MockStateVersionOutputs) ReadCurrent(ctx context.Context, workspaceID string) (*tfe.StateVersionOutputsList, error) {
+	svl := &tfe.StateVersionOutputsList{}
+	for _, sv := range m.outputs {
+		svl.Items = append(svl.Items, sv)
+	}
+
+	svl.Pagination = &tfe.Pagination{
+		CurrentPage:  1,
+		NextPage:     1,
+		PreviousPage: 1,
+		TotalPages:   1,
+		TotalCount:   len(svl.Items),
+	}
+
+	return svl, nil
+}
+
+type MockVariables struct {
+	client     *MockClient
+	workspaces map[string]*tfe.VariableList
+}
+
+var _ tfe.Variables = (*MockVariables)(nil)
+
+func newMockVariables(client *MockClient) *MockVariables {
+	return &MockVariables{
+		client:     client,
+		workspaces: make(map[string]*tfe.VariableList),
+	}
+}
+
+func (m *MockVariables) List(ctx context.Context, workspaceID string, options *tfe.VariableListOptions) (*tfe.VariableList, error) {
+	vl := m.workspaces[workspaceID]
+	return vl, nil
+}
+
+func (m *MockVariables) Create(ctx context.Context, workspaceID string, options tfe.VariableCreateOptions) (*tfe.Variable, error) {
+	v := &tfe.Variable{
+		ID:       GenerateID("var-"),
+		Key:      *options.Key,
+		Category: *options.Category,
+	}
+	if options.Value != nil {
+		v.Value = *options.Value
+	}
+	if options.HCL != nil {
+		v.HCL = *options.HCL
+	}
+	if options.Sensitive != nil {
+		v.Sensitive = *options.Sensitive
+	}
+
+	workspace := workspaceID
+
+	if m.workspaces[workspace] == nil {
+		m.workspaces[workspace] = &tfe.VariableList{}
+	}
+
+	vl := m.workspaces[workspace]
+	vl.Items = append(vl.Items, v)
+
+	return v, nil
+}
+
+func (m *MockVariables) Read(ctx context.Context, workspaceID string, variableID string) (*tfe.Variable, error) {
+	panic("not implemented")
+}
+
+func (m *MockVariables) Update(ctx context.Context, workspaceID string, variableID string, options tfe.VariableUpdateOptions) (*tfe.Variable, error) {
+	panic("not implemented")
+}
+
+func (m *MockVariables) Delete(ctx context.Context, workspaceID string, variableID string) error {
+	panic("not implemented")
+}
+
+type MockWorkspaces struct {
+	client         *MockClient
+	workspaceIDs   map[string]*tfe.Workspace
+	workspaceNames map[string]*tfe.Workspace
+}
+
+func newMockWorkspaces(client *MockClient) *MockWorkspaces {
+	return &MockWorkspaces{
+		client:         client,
+		workspaceIDs:   make(map[string]*tfe.Workspace),
+		workspaceNames: make(map[string]*tfe.Workspace),
+	}
+}
+
+func (m *MockWorkspaces) List(ctx context.Context, organization string, options *tfe.WorkspaceListOptions) (*tfe.WorkspaceList, error) {
+	wl := &tfe.WorkspaceList{}
+	// Get all the workspaces that match the Search value
+	searchValue := ""
+	var ws []*tfe.Workspace
+	var tags []string
+
+	if options != nil {
+		if len(options.Search) > 0 {
+			searchValue = options.Search
+		}
+		if len(options.Tags) > 0 {
+			tags = strings.Split(options.Tags, ",")
+		}
+	}
+
+	for _, w := range m.workspaceIDs {
+		wTags := make(map[string]struct{})
+		for _, wTag := range w.Tags {
+			wTags[wTag.Name] = struct{}{}
+		}
+
+		if strings.Contains(w.Name, searchValue) {
+			tagsSatisfied := true
+			for _, tag := range tags {
+				if _, ok := wTags[tag]; !ok {
+					tagsSatisfied = false
+				}
+			}
+			if tagsSatisfied {
+				ws = append(ws, w)
+			}
+		}
+	}
+
+	// Return an empty result if we have no matches.
+	if len(ws) == 0 {
+		wl.Pagination = &tfe.Pagination{
+			CurrentPage: 1,
+		}
+		return wl, nil
+	}
+
+	numPages := (len(ws) / 20) + 1
+	currentPage := 1
+	if options != nil {
+		if options.PageNumber != 0 {
+			currentPage = options.PageNumber
+		}
+	}
+	previousPage := currentPage - 1
+	nextPage := currentPage + 1
+
+	for i := ((currentPage - 1) * 20); i < ((currentPage-1)*20)+20; i++ {
+		if i > (len(ws) - 1) {
+			break
+		}
+		wl.Items = append(wl.Items, ws[i])
+	}
+
+	wl.Pagination = &tfe.Pagination{
+		CurrentPage:  currentPage,
+		NextPage:     nextPage,
+		PreviousPage: previousPage,
+		TotalPages:   numPages,
+		TotalCount:   len(wl.Items),
+	}
+
+	return wl, nil
+}
+
+func (m *MockWorkspaces) Create(ctx context.Context, organization string, options tfe.WorkspaceCreateOptions) (*tfe.Workspace, error) {
+	// for TestCloud_setUnavailableTerraformVersion
+	if *options.Name == "unavailable-terraform-version" && options.TerraformVersion != nil {
+		return nil, fmt.Errorf("requested Terraform version not available in this TFC instance")
+	}
+	if strings.HasSuffix(*options.Name, "no-operations") {
+		options.Operations = tfe.Bool(false)
+		options.ExecutionMode = tfe.String("local")
+	} else if options.Operations == nil {
+		options.Operations = tfe.Bool(true)
+		options.ExecutionMode = tfe.String("remote")
+	}
+	w := &tfe.Workspace{
+		ID:                         GenerateID("ws-"),
+		Name:                       *options.Name,
+		ExecutionMode:              *options.ExecutionMode,
+		Operations:                 *options.Operations,
+		StructuredRunOutputEnabled: false,
+		Permissions: &tfe.WorkspacePermissions{
+			CanQueueApply:  true,
+			CanQueueRun:    true,
+			CanForceDelete: tfe.Bool(true),
+		},
+	}
+	if options.AutoApply != nil {
+		w.AutoApply = *options.AutoApply
+	}
+	if options.VCSRepo != nil {
+		w.VCSRepo = &tfe.VCSRepo{}
+	}
+
+	if options.TerraformVersion != nil {
+		w.TerraformVersion = *options.TerraformVersion
+	} else {
+		w.TerraformVersion = tfversion.String()
+	}
+
+	var tags []*tfe.Tag
+	for _, tag := range options.Tags {
+		tags = append(tags, tag)
+		w.TagNames = append(w.TagNames, tag.Name)
+	}
+	w.Tags = tags
+	m.workspaceIDs[w.ID] = w
+	m.workspaceNames[w.Name] = w
+	return w, nil
+}
+
+func (m *MockWorkspaces) Read(ctx context.Context, organization, workspace string) (*tfe.Workspace, error) {
+	// custom error for TestCloud_plan500 in backend_plan_test.go
+	if workspace == "network-error" {
+		return nil, errors.New("I'm a little teacup")
+	}
+
+	w, ok := m.workspaceNames[workspace]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	return w, nil
+}
+
+func (m *MockWorkspaces) ReadByID(ctx context.Context, workspaceID string) (*tfe.Workspace, error) {
+	w, ok := m.workspaceIDs[workspaceID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	return w, nil
+}
+
+func (m *MockWorkspaces) ReadWithOptions(ctx context.Context, organization string, workspace string, options *tfe.WorkspaceReadOptions) (*tfe.Workspace, error) {
+	panic("not implemented")
+}
+
+func (m *MockWorkspaces) ReadByIDWithOptions(ctx context.Context, workspaceID string, options *tfe.WorkspaceReadOptions) (*tfe.Workspace, error) {
+	w, ok := m.workspaceIDs[workspaceID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	return w, nil
+}
+
+func (m *MockWorkspaces) Update(ctx context.Context, organization, workspace string, options tfe.WorkspaceUpdateOptions) (*tfe.Workspace, error) {
+	w, ok := m.workspaceNames[workspace]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	err := updateMockWorkspaceAttributes(w, options)
+	if err != nil {
+		return nil, err
+	}
+
+	delete(m.workspaceNames, workspace)
+	m.workspaceNames[w.Name] = w
+
+	return w, nil
+}
+
+func (m *MockWorkspaces) UpdateByID(ctx context.Context, workspaceID string, options tfe.WorkspaceUpdateOptions) (*tfe.Workspace, error) {
+	w, ok := m.workspaceIDs[workspaceID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+
+	originalName := w.Name
+	err := updateMockWorkspaceAttributes(w, options)
+	if err != nil {
+		return nil, err
+	}
+
+	delete(m.workspaceNames, originalName)
+	m.workspaceNames[w.Name] = w
+
+	return w, nil
+}
+
+func updateMockWorkspaceAttributes(w *tfe.Workspace, options tfe.WorkspaceUpdateOptions) error {
+	// for TestCloud_setUnavailableTerraformVersion
+	if w.Name == "unavailable-terraform-version" && options.TerraformVersion != nil {
+		return fmt.Errorf("requested Terraform version not available in this TFC instance")
+	}
+
+	if options.Operations != nil {
+		w.Operations = *options.Operations
+	}
+	if options.ExecutionMode != nil {
+		w.ExecutionMode = *options.ExecutionMode
+	}
+	if options.Name != nil {
+		w.Name = *options.Name
+	}
+	if options.TerraformVersion != nil {
+		w.TerraformVersion = *options.TerraformVersion
+	}
+	if options.WorkingDirectory != nil {
+		w.WorkingDirectory = *options.WorkingDirectory
+	}
+
+	if options.StructuredRunOutputEnabled != nil {
+		w.StructuredRunOutputEnabled = *options.StructuredRunOutputEnabled
+	}
+
+	return nil
+}
+
+func (m *MockWorkspaces) Delete(ctx context.Context, organization, workspace string) error {
+	if w, ok := m.workspaceNames[workspace]; ok {
+		delete(m.workspaceIDs, w.ID)
+	}
+	delete(m.workspaceNames, workspace)
+	return nil
+}
+
+func (m *MockWorkspaces) DeleteByID(ctx context.Context, workspaceID string) error {
+	if w, ok := m.workspaceIDs[workspaceID]; ok {
+		delete(m.workspaceIDs, w.Name)
+	}
+	delete(m.workspaceIDs, workspaceID)
+	return nil
+}
+
+func (m *MockWorkspaces) SafeDelete(ctx context.Context, organization, workspace string) error {
+	w, ok := m.client.Workspaces.workspaceNames[workspace]
+
+	if !ok {
+		return tfe.ErrResourceNotFound
+	}
+
+	if w.Locked {
+		return errors.New("cannot safe delete locked workspace")
+	}
+
+	if w.ResourceCount > 0 {
+		return fmt.Errorf("cannot safe delete workspace with %d resources", w.ResourceCount)
+	}
+
+	return m.Delete(ctx, organization, workspace)
+}
+
+func (m *MockWorkspaces) SafeDeleteByID(ctx context.Context, workspaceID string) error {
+	w, ok := m.client.Workspaces.workspaceIDs[workspaceID]
+	if !ok {
+		return tfe.ErrResourceNotFound
+	}
+
+	if w.Locked {
+		return errors.New("cannot safe delete locked workspace")
+	}
+
+	if w.ResourceCount > 0 {
+		return fmt.Errorf("cannot safe delete workspace with %d resources", w.ResourceCount)
+	}
+
+	return m.DeleteByID(ctx, workspaceID)
+}
+
+func (m *MockWorkspaces) RemoveVCSConnection(ctx context.Context, organization, workspace string) (*tfe.Workspace, error) {
+	w, ok := m.workspaceNames[workspace]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	w.VCSRepo = nil
+	return w, nil
+}
+
+func (m *MockWorkspaces) RemoveVCSConnectionByID(ctx context.Context, workspaceID string) (*tfe.Workspace, error) {
+	w, ok := m.workspaceIDs[workspaceID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	w.VCSRepo = nil
+	return w, nil
+}
+
+func (m *MockWorkspaces) Lock(ctx context.Context, workspaceID string, options tfe.WorkspaceLockOptions) (*tfe.Workspace, error) {
+	w, ok := m.workspaceIDs[workspaceID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	if w.Locked {
+		return nil, tfe.ErrWorkspaceLocked
+	}
+	w.Locked = true
+	return w, nil
+}
+
+func (m *MockWorkspaces) Unlock(ctx context.Context, workspaceID string) (*tfe.Workspace, error) {
+	w, ok := m.workspaceIDs[workspaceID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	if !w.Locked {
+		return nil, tfe.ErrWorkspaceNotLocked
+	}
+	w.Locked = false
+	return w, nil
+}
+
+func (m *MockWorkspaces) ForceUnlock(ctx context.Context, workspaceID string) (*tfe.Workspace, error) {
+	w, ok := m.workspaceIDs[workspaceID]
+	if !ok {
+		return nil, tfe.ErrResourceNotFound
+	}
+	if !w.Locked {
+		return nil, tfe.ErrWorkspaceNotLocked
+	}
+	w.Locked = false
+	return w, nil
+}
+
+func (m *MockWorkspaces) AssignSSHKey(ctx context.Context, workspaceID string, options tfe.WorkspaceAssignSSHKeyOptions) (*tfe.Workspace, error) {
+	panic("not implemented")
+}
+
+func (m *MockWorkspaces) UnassignSSHKey(ctx context.Context, workspaceID string) (*tfe.Workspace, error) {
+	panic("not implemented")
+}
+
+func (m *MockWorkspaces) ListRemoteStateConsumers(ctx context.Context, workspaceID string, options *tfe.RemoteStateConsumersListOptions) (*tfe.WorkspaceList, error) {
+	panic("not implemented")
+}
+
+func (m *MockWorkspaces) AddRemoteStateConsumers(ctx context.Context, workspaceID string, options tfe.WorkspaceAddRemoteStateConsumersOptions) error {
+	panic("not implemented")
+}
+
+func (m *MockWorkspaces) RemoveRemoteStateConsumers(ctx context.Context, workspaceID string, options tfe.WorkspaceRemoveRemoteStateConsumersOptions) error {
+	panic("not implemented")
+}
+
+func (m *MockWorkspaces) UpdateRemoteStateConsumers(ctx context.Context, workspaceID string, options tfe.WorkspaceUpdateRemoteStateConsumersOptions) error {
+	panic("not implemented")
+}
+
+func (m *MockWorkspaces) Readme(ctx context.Context, workspaceID string) (io.Reader, error) {
+	panic("not implemented")
+}
+
+func (m *MockWorkspaces) ListTags(ctx context.Context, workspaceID string, options *tfe.WorkspaceTagListOptions) (*tfe.TagList, error) {
+	panic("not implemented")
+}
+
+func (m *MockWorkspaces) AddTags(ctx context.Context, workspaceID string, options tfe.WorkspaceAddTagsOptions) error {
+	return nil
+}
+
+func (m *MockWorkspaces) RemoveTags(ctx context.Context, workspaceID string, options tfe.WorkspaceRemoveTagsOptions) error {
+	panic("not implemented")
+}
+
+const alphanumeric = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+
+func GenerateID(s string) string {
+	b := make([]byte, 16)
+	for i := range b {
+		b[i] = alphanumeric[rand.Intn(len(alphanumeric))]
+	}
+	return s + string(b)
+}
diff --git a/v1.5.7/internal/command/apply.go b/v1.5.7/internal/command/apply.go
new file mode 100644
index 0000000..c9341d9
--- /dev/null
+++ b/v1.5.7/internal/command/apply.go
@@ -0,0 +1,396 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ApplyCommand is a Command implementation that applies a Terraform
+// configuration and actually builds or changes infrastructure.
+type ApplyCommand struct {
+	Meta
+
+	// If true, then this apply command will become the "destroy"
+	// command. It is just like apply but only processes a destroy.
+	Destroy bool
+}
+
+func (c *ApplyCommand) Run(rawArgs []string) int {
+	var diags tfdiags.Diagnostics
+
+	// Parse and apply global view arguments
+	common, rawArgs := arguments.ParseView(rawArgs)
+	c.View.Configure(common)
+
+	// Propagate -no-color for legacy use of Ui.  The remote backend and
+	// cloud package use this; it should be removed when/if they are
+	// migrated to views.
+	c.Meta.color = !common.NoColor
+	c.Meta.Color = c.Meta.color
+
+	// Parse and validate flags
+	var args *arguments.Apply
+	switch {
+	case c.Destroy:
+		args, diags = arguments.ParseApplyDestroy(rawArgs)
+	default:
+		args, diags = arguments.ParseApply(rawArgs)
+	}
+
+	// Instantiate the view, even if there are flag errors, so that we render
+	// diagnostics according to the desired view
+	view := views.NewApply(args.ViewType, c.Destroy, c.View)
+
+	if diags.HasErrors() {
+		view.Diagnostics(diags)
+		view.HelpPrompt()
+		return 1
+	}
+
+	// Check for user-supplied plugin path
+	var err error
+	if c.pluginPath, err = c.loadPluginPath(); err != nil {
+		diags = diags.Append(err)
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	// Attempt to load the plan file, if specified
+	planFile, diags := c.LoadPlanFile(args.PlanPath)
+	if diags.HasErrors() {
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	// Check for invalid combination of plan file and variable overrides
+	if planFile != nil && !args.Vars.Empty() {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Can't set variables when applying a saved plan",
+			"The -var and -var-file options cannot be used when applying a saved plan file, because a saved plan includes the variable values that were set when it was created.",
+		))
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	// FIXME: the -input flag value is needed to initialize the backend and the
+	// operation, but there is no clear path to pass this value down, so we
+	// continue to mutate the Meta object state for now.
+	c.Meta.input = args.InputEnabled
+
+	// FIXME: the -parallelism flag is used to control the concurrency of
+	// Terraform operations. At the moment, this value is used both to
+	// initialize the backend via the ContextOpts field inside CLIOpts, and to
+	// set a largely unused field on the Operation request. Again, there is no
+	// clear path to pass this value down, so we continue to mutate the Meta
+	// object state for now.
+	c.Meta.parallelism = args.Operation.Parallelism
+
+	// Prepare the backend, passing the plan file if present, and the
+	// backend-specific arguments
+	be, beDiags := c.PrepareBackend(planFile, args.State, args.ViewType)
+	diags = diags.Append(beDiags)
+	if diags.HasErrors() {
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	// Build the operation request
+	opReq, opDiags := c.OperationRequest(be, view, args.ViewType, planFile, args.Operation, args.AutoApprove)
+	diags = diags.Append(opDiags)
+
+	// Collect variable value and add them to the operation request
+	diags = diags.Append(c.GatherVariables(opReq, args.Vars))
+
+	// Before we delegate to the backend, we'll print any warning diagnostics
+	// we've accumulated here, since the backend will start fresh with its own
+	// diagnostics.
+	view.Diagnostics(diags)
+	if diags.HasErrors() {
+		return 1
+	}
+	diags = nil
+
+	// Run the operation
+	op, err := c.RunOperation(be, opReq)
+	if err != nil {
+		diags = diags.Append(err)
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	if op.Result != backend.OperationSuccess {
+		return op.Result.ExitStatus()
+	}
+
+	// Render the resource count and outputs, unless those counts are being
+	// rendered already in a remote Terraform process.
+	if rb, isRemoteBackend := be.(BackendWithRemoteTerraformVersion); !isRemoteBackend || rb.IsLocalOperations() {
+		view.ResourceCount(args.State.StateOutPath)
+		if !c.Destroy && op.State != nil {
+			view.Outputs(op.State.RootModule().OutputValues)
+		}
+	}
+
+	view.Diagnostics(diags)
+
+	if diags.HasErrors() {
+		return 1
+	}
+
+	return 0
+}
+
+func (c *ApplyCommand) LoadPlanFile(path string) (*planfile.Reader, tfdiags.Diagnostics) {
+	var planFile *planfile.Reader
+	var diags tfdiags.Diagnostics
+
+	// Try to load plan if path is specified
+	if path != "" {
+		var err error
+		planFile, err = c.PlanFile(path)
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				fmt.Sprintf("Failed to load %q as a plan file", path),
+				fmt.Sprintf("Error: %s", err),
+			))
+			return nil, diags
+		}
+
+		// If the path doesn't look like a plan, both planFile and err will be
+		// nil. In that case, the user is probably trying to use the positional
+		// argument to specify a configuration path. Point them at -chdir.
+		if planFile == nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				fmt.Sprintf("Failed to load %q as a plan file", path),
+				"The specified path is a directory, not a plan file. You can use the global -chdir flag to use this directory as the configuration root.",
+			))
+			return nil, diags
+		}
+
+		// If we successfully loaded a plan but this is a destroy operation,
+		// explain that this is not supported.
+		if c.Destroy {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Destroy can't be called with a plan file",
+				fmt.Sprintf("If this plan was created using plan -destroy, apply it using:\n  terraform apply %q", path),
+			))
+			return nil, diags
+		}
+	}
+
+	return planFile, diags
+}
+
+func (c *ApplyCommand) PrepareBackend(planFile *planfile.Reader, args *arguments.State, viewType arguments.ViewType) (backend.Enhanced, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// FIXME: we need to apply the state arguments to the meta object here
+	// because they are later used when initializing the backend. Carving a
+	// path to pass these arguments to the functions that need them is
+	// difficult but would make their use easier to understand.
+	c.Meta.applyStateArguments(args)
+
+	// Load the backend
+	var be backend.Enhanced
+	var beDiags tfdiags.Diagnostics
+	if planFile == nil {
+		backendConfig, configDiags := c.loadBackendConfig(".")
+		diags = diags.Append(configDiags)
+		if configDiags.HasErrors() {
+			return nil, diags
+		}
+
+		be, beDiags = c.Backend(&BackendOpts{
+			Config:   backendConfig,
+			ViewType: viewType,
+		})
+	} else {
+		plan, err := planFile.ReadPlan()
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to read plan from plan file",
+				fmt.Sprintf("Cannot read the plan from the given plan file: %s.", err),
+			))
+			return nil, diags
+		}
+		if plan.Backend.Config == nil {
+			// Should never happen; always indicates a bug in the creation of the plan file
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to read plan from plan file",
+				"The given plan file does not have a valid backend configuration. This is a bug in the Terraform command that generated this plan file.",
+			))
+			return nil, diags
+		}
+		be, beDiags = c.BackendForPlan(plan.Backend)
+	}
+
+	diags = diags.Append(beDiags)
+	if beDiags.HasErrors() {
+		return nil, diags
+	}
+	return be, diags
+}
+
+func (c *ApplyCommand) OperationRequest(
+	be backend.Enhanced,
+	view views.Apply,
+	viewType arguments.ViewType,
+	planFile *planfile.Reader,
+	args *arguments.Operation,
+	autoApprove bool,
+) (*backend.Operation, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// Applying changes with dev overrides in effect could make it impossible
+	// to switch back to a release version if the schema isn't compatible,
+	// so we'll warn about it.
+	diags = diags.Append(c.providerDevOverrideRuntimeWarnings())
+
+	// Build the operation
+	opReq := c.Operation(be, viewType)
+	opReq.AutoApprove = autoApprove
+	opReq.ConfigDir = "."
+	opReq.PlanMode = args.PlanMode
+	opReq.Hooks = view.Hooks()
+	opReq.PlanFile = planFile
+	opReq.PlanRefresh = args.Refresh
+	opReq.Targets = args.Targets
+	opReq.ForceReplace = args.ForceReplace
+	opReq.Type = backend.OperationTypeApply
+	opReq.View = view.Operation()
+
+	var err error
+	opReq.ConfigLoader, err = c.initConfigLoader()
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Failed to initialize config loader: %s", err))
+		return nil, diags
+	}
+
+	return opReq, diags
+}
+
+func (c *ApplyCommand) GatherVariables(opReq *backend.Operation, args *arguments.Vars) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	// FIXME the arguments package currently trivially gathers variable related
+	// arguments in a heterogenous slice, in order to minimize the number of
+	// code paths gathering variables during the transition to this structure.
+	// Once all commands that gather variables have been converted to this
+	// structure, we could move the variable gathering code to the arguments
+	// package directly, removing this shim layer.
+
+	varArgs := args.All()
+	items := make([]rawFlag, len(varArgs))
+	for i := range varArgs {
+		items[i].Name = varArgs[i].Name
+		items[i].Value = varArgs[i].Value
+	}
+	c.Meta.variableArgs = rawFlags{items: &items}
+	opReq.Variables, diags = c.collectVariableValues()
+
+	return diags
+}
+
+func (c *ApplyCommand) Help() string {
+	if c.Destroy {
+		return c.helpDestroy()
+	}
+
+	return c.helpApply()
+}
+
+func (c *ApplyCommand) Synopsis() string {
+	if c.Destroy {
+		return "Destroy previously-created infrastructure"
+	}
+
+	return "Create or update infrastructure"
+}
+
+func (c *ApplyCommand) helpApply() string {
+	helpText := `
+Usage: terraform [global options] apply [options] [PLAN]
+
+  Creates or updates infrastructure according to Terraform configuration
+  files in the current directory.
+
+  By default, Terraform will generate a new plan and present it for your
+  approval before taking any action. You can optionally provide a plan
+  file created by a previous call to "terraform plan", in which case
+  Terraform will take the actions described in that plan without any
+  confirmation prompt.
+
+Options:
+
+  -auto-approve          Skip interactive approval of plan before applying.
+
+  -backup=path           Path to backup the existing state file before
+                         modifying. Defaults to the "-state-out" path with
+                         ".backup" extension. Set to "-" to disable backup.
+
+  -compact-warnings      If Terraform produces any warnings that are not
+                         accompanied by errors, show them in a more compact
+                         form that includes only the summary messages.
+
+  -destroy               Destroy Terraform-managed infrastructure.
+                         The command "terraform destroy" is a convenience alias
+                         for this option.
+
+  -lock=false            Don't hold a state lock during the operation. This is
+                         dangerous if others might concurrently run commands
+                         against the same workspace.
+
+  -lock-timeout=0s       Duration to retry a state lock.
+
+  -input=true            Ask for input for variables if not directly set.
+
+  -no-color              If specified, output won't contain any color.
+
+  -parallelism=n         Limit the number of parallel resource operations.
+                         Defaults to 10.
+
+  -state=path            Path to read and save state (unless state-out
+                         is specified). Defaults to "terraform.tfstate".
+
+  -state-out=path        Path to write state to that is different than
+                         "-state". This can be used to preserve the old
+                         state.
+
+  If you don't provide a saved plan file then this command will also accept
+  all of the plan-customization options accepted by the terraform plan command.
+  For more information on those options, run:
+      terraform plan -help
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *ApplyCommand) helpDestroy() string {
+	helpText := `
+Usage: terraform [global options] destroy [options]
+
+  Destroy Terraform-managed infrastructure.
+
+  This command is a convenience alias for:
+      terraform apply -destroy
+
+  This command also accepts many of the plan-customization options accepted by
+  the terraform plan command. For more information on those options, run:
+      terraform plan -help
+`
+	return strings.TrimSpace(helpText)
+}
diff --git a/v1.5.7/internal/command/apply_destroy_test.go b/v1.5.7/internal/command/apply_destroy_test.go
new file mode 100644
index 0000000..8d4208a
--- /dev/null
+++ b/v1.5.7/internal/command/apply_destroy_test.go
@@ -0,0 +1,675 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"os"
+	"strings"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/mitchellh/cli"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+)
+
+func TestApply_destroy(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, originalState)
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":  {Type: cty.String, Computed: true},
+						"ami": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Destroy: true,
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	// Run the apply command pointing to our existing state
+	args := []string{
+		"-auto-approve",
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Log(output.Stdout())
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// Verify a new state exists
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	f, err := os.Open(statePath)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer f.Close()
+
+	stateFile, err := statefile.Read(f)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if stateFile.State == nil {
+		t.Fatal("state should not be nil")
+	}
+
+	actualStr := strings.TrimSpace(stateFile.State.String())
+	expectedStr := strings.TrimSpace(testApplyDestroyStr)
+	if actualStr != expectedStr {
+		t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr)
+	}
+
+	// Should have a backup file
+	f, err = os.Open(statePath + DefaultBackupExtension)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	backupStateFile, err := statefile.Read(f)
+	f.Close()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actualStr = strings.TrimSpace(backupStateFile.State.String())
+	expectedStr = strings.TrimSpace(originalState.String())
+	if actualStr != expectedStr {
+		t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr)
+	}
+}
+
+func TestApply_destroyApproveNo(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	// Create some existing state
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, originalState)
+
+	p := applyFixtureProvider()
+
+	defer testInputMap(t, map[string]string{
+		"approve": "no",
+	})()
+
+	// Do not use the NewMockUi initializer here, as we want to delay
+	// the call to init until after setting up the input mocks
+	ui := new(cli.MockUi)
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Destroy: true,
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 1 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stdout())
+	}
+	if got, want := output.Stdout(), "Destroy cancelled"; !strings.Contains(got, want) {
+		t.Fatalf("expected output to include %q, but was:\n%s", want, got)
+	}
+
+	state := testStateRead(t, statePath)
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+	actualStr := strings.TrimSpace(state.String())
+	expectedStr := strings.TrimSpace(originalState.String())
+	if actualStr != expectedStr {
+		t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr)
+	}
+}
+
+func TestApply_destroyApproveYes(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	// Create some existing state
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, originalState)
+
+	p := applyFixtureProvider()
+
+	defer testInputMap(t, map[string]string{
+		"approve": "yes",
+	})()
+
+	// Do not use the NewMockUi initializer here, as we want to delay
+	// the call to init until after setting up the input mocks
+	ui := new(cli.MockUi)
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Destroy: true,
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Log(output.Stdout())
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	state := testStateRead(t, statePath)
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+
+	actualStr := strings.TrimSpace(state.String())
+	expectedStr := strings.TrimSpace(testApplyDestroyStr)
+	if actualStr != expectedStr {
+		t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr)
+	}
+}
+
+func TestApply_destroyLockedState(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, originalState)
+
+	unlock, err := testLockState(t, testDataDir, statePath)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer unlock()
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Destroy: true,
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	// Run the apply command pointing to our existing state
+	args := []string{
+		"-auto-approve",
+		"-state", statePath,
+	}
+
+	code := c.Run(args)
+	output := done(t)
+	if code == 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stdout())
+	}
+
+	if !strings.Contains(output.Stderr(), "lock") {
+		t.Fatal("command output does not look like a lock error:", output.Stderr())
+	}
+}
+
+func TestApply_destroyPlan(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	planPath := testPlanFileNoop(t)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Destroy: true,
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	// Run the apply command pointing to our existing state
+	args := []string{
+		planPath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 1 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stdout())
+	}
+	if !strings.Contains(output.Stderr(), "plan file") {
+		t.Fatal("expected command output to refer to plan file, but got:", output.Stderr())
+	}
+}
+
+func TestApply_destroyPath(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	p := applyFixtureProvider()
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Destroy: true,
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-auto-approve",
+		testFixturePath("apply"),
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 1 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stdout())
+	}
+	if !strings.Contains(output.Stderr(), "-chdir") {
+		t.Fatal("expected command output to refer to -chdir flag, but got:", output.Stderr())
+	}
+}
+
+// Config with multiple resources with dependencies, targeting destroy of a
+// root node, expecting all other resources to be destroyed due to
+// dependencies.
+func TestApply_destroyTargetedDependencies(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-destroy-targeted"), td)
+	defer testChdir(t, td)()
+
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"i-ab123"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_load_balancer",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON:    []byte(`{"id":"i-abc123"}`),
+				Dependencies: []addrs.ConfigResource{mustResourceAddr("test_instance.foo")},
+				Status:       states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, originalState)
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Computed: true},
+					},
+				},
+			},
+			"test_load_balancer": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":        {Type: cty.String, Computed: true},
+						"instances": {Type: cty.List(cty.String), Optional: true},
+					},
+				},
+			},
+		},
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Destroy: true,
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	// Run the apply command pointing to our existing state
+	args := []string{
+		"-auto-approve",
+		"-target", "test_instance.foo",
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Log(output.Stdout())
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// Verify a new state exists
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	f, err := os.Open(statePath)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer f.Close()
+
+	stateFile, err := statefile.Read(f)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if stateFile == nil || stateFile.State == nil {
+		t.Fatal("state should not be nil")
+	}
+
+	spew.Config.DisableMethods = true
+	if !stateFile.State.Empty() {
+		t.Fatalf("unexpected final state\ngot: %s\nwant: empty state", spew.Sdump(stateFile.State))
+	}
+
+	// Should have a backup file
+	f, err = os.Open(statePath + DefaultBackupExtension)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	backupStateFile, err := statefile.Read(f)
+	f.Close()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actualStr := strings.TrimSpace(backupStateFile.State.String())
+	expectedStr := strings.TrimSpace(originalState.String())
+	if actualStr != expectedStr {
+		t.Fatalf("bad:\n\nactual:\n%s\n\nexpected:\nb%s", actualStr, expectedStr)
+	}
+}
+
+// Config with multiple resources with dependencies, targeting destroy of a
+// leaf node, expecting the other resources to remain.
+func TestApply_destroyTargeted(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-destroy-targeted"), td)
+	defer testChdir(t, td)()
+
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"i-ab123"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_load_balancer",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON:    []byte(`{"id":"i-abc123"}`),
+				Dependencies: []addrs.ConfigResource{mustResourceAddr("test_instance.foo")},
+				Status:       states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	wantState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"i-ab123"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, originalState)
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Computed: true},
+					},
+				},
+			},
+			"test_load_balancer": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":        {Type: cty.String, Computed: true},
+						"instances": {Type: cty.List(cty.String), Optional: true},
+					},
+				},
+			},
+		},
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Destroy: true,
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	// Run the apply command pointing to our existing state
+	args := []string{
+		"-auto-approve",
+		"-target", "test_load_balancer.foo",
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Log(output.Stdout())
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// Verify a new state exists
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	f, err := os.Open(statePath)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer f.Close()
+
+	stateFile, err := statefile.Read(f)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if stateFile == nil || stateFile.State == nil {
+		t.Fatal("state should not be nil")
+	}
+
+	actualStr := strings.TrimSpace(stateFile.State.String())
+	expectedStr := strings.TrimSpace(wantState.String())
+	if actualStr != expectedStr {
+		t.Fatalf("bad:\n\nactual:\n%s\n\nexpected:\nb%s", actualStr, expectedStr)
+	}
+
+	// Should have a backup file
+	f, err = os.Open(statePath + DefaultBackupExtension)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	backupStateFile, err := statefile.Read(f)
+	f.Close()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	backupActualStr := strings.TrimSpace(backupStateFile.State.String())
+	backupExpectedStr := strings.TrimSpace(originalState.String())
+	if backupActualStr != backupExpectedStr {
+		t.Fatalf("bad:\n\nactual:\n%s\n\nexpected:\nb%s", backupActualStr, backupExpectedStr)
+	}
+}
+
+const testApplyDestroyStr = `
+<no state>
+`
diff --git a/v1.5.7/internal/command/apply_test.go b/v1.5.7/internal/command/apply_test.go
new file mode 100644
index 0000000..4518b8d
--- /dev/null
+++ b/v1.5.7/internal/command/apply_test.go
@@ -0,0 +1,2235 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"reflect"
+	"strings"
+	"sync"
+	"testing"
+	"time"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/mitchellh/cli"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestApply(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	statePath := testTempFile(t)
+
+	p := applyFixtureProvider()
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-auto-approve",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	state := testStateRead(t, statePath)
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+}
+
+func TestApply_path(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	p := applyFixtureProvider()
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-auto-approve",
+		testFixturePath("apply"),
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 1 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+	if !strings.Contains(output.Stderr(), "-chdir") {
+		t.Fatal("expected command output to refer to -chdir flag, but got:", output.Stderr())
+	}
+}
+
+func TestApply_approveNo(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	statePath := testTempFile(t)
+
+	defer testInputMap(t, map[string]string{
+		"approve": "no",
+	})()
+
+	// Do not use the NewMockUi initializer here, as we want to delay
+	// the call to init until after setting up the input mocks
+	ui := new(cli.MockUi)
+
+	p := applyFixtureProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 1 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+	if got, want := output.Stdout(), "Apply cancelled"; !strings.Contains(got, want) {
+		t.Fatalf("expected output to include %q, but was:\n%s", want, got)
+	}
+
+	if _, err := os.Stat(statePath); err == nil || !os.IsNotExist(err) {
+		t.Fatalf("state file should not exist")
+	}
+}
+
+func TestApply_approveYes(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	statePath := testTempFile(t)
+
+	p := applyFixtureProvider()
+
+	defer testInputMap(t, map[string]string{
+		"approve": "yes",
+	})()
+
+	// Do not use the NewMockUi initializer here, as we want to delay
+	// the call to init until after setting up the input mocks
+	ui := new(cli.MockUi)
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	state := testStateRead(t, statePath)
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+}
+
+// test apply with locked state
+func TestApply_lockedState(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	statePath := testTempFile(t)
+
+	unlock, err := testLockState(t, testDataDir, statePath)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer unlock()
+
+	p := applyFixtureProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-auto-approve",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code == 0 {
+		t.Fatal("expected error")
+	}
+
+	if !strings.Contains(output.Stderr(), "lock") {
+		t.Fatal("command output does not look like a lock error:", output.Stderr())
+	}
+}
+
+// test apply with locked state, waiting for unlock
+func TestApply_lockedStateWait(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	statePath := testTempFile(t)
+
+	unlock, err := testLockState(t, testDataDir, statePath)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// unlock during apply
+	go func() {
+		time.Sleep(500 * time.Millisecond)
+		unlock()
+	}()
+
+	p := applyFixtureProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	// wait 4s just in case the lock process doesn't release in under a second,
+	// and we want our context to be alive for a second retry at the 3s mark.
+	args := []string{
+		"-state", statePath,
+		"-lock-timeout", "4s",
+		"-auto-approve",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("lock should have succeeded in less than 3s: %s", output.Stderr())
+	}
+}
+
+// Verify that the parallelism flag allows no more than the desired number of
+// concurrent calls to ApplyResourceChange.
+func TestApply_parallelism(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("parallelism"), td)
+	defer testChdir(t, td)()
+
+	statePath := testTempFile(t)
+
+	par := 4
+
+	// started is a semaphore that we use to ensure that we never have more
+	// than "par" apply operations happening concurrently
+	started := make(chan struct{}, par)
+
+	// beginCtx is used as a starting gate to hold back ApplyResourceChange
+	// calls until we reach the desired concurrency. The cancel func "begin" is
+	// called once we reach the desired concurrency, allowing all apply calls
+	// to proceed in unison.
+	beginCtx, begin := context.WithCancel(context.Background())
+
+	// Since our mock provider has its own mutex preventing concurrent calls
+	// to ApplyResourceChange, we need to use a number of separate providers
+	// here. They will all have the same mock implementation function assigned
+	// but crucially they will each have their own mutex.
+	providerFactories := map[addrs.Provider]providers.Factory{}
+	for i := 0; i < 10; i++ {
+		name := fmt.Sprintf("test%d", i)
+		provider := &terraform.MockProvider{}
+		provider.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+			ResourceTypes: map[string]providers.Schema{
+				name + "_instance": {Block: &configschema.Block{}},
+			},
+		}
+		provider.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+			return providers.PlanResourceChangeResponse{
+				PlannedState: req.ProposedNewState,
+			}
+		}
+		provider.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+
+			// If we ever have more than our intended parallelism number of
+			// apply operations running concurrently, the semaphore will fail.
+			select {
+			case started <- struct{}{}:
+				defer func() {
+					<-started
+				}()
+			default:
+				t.Fatal("too many concurrent apply operations")
+			}
+
+			// If we never reach our intended parallelism, the context will
+			// never be canceled and the test will time out.
+			if len(started) >= par {
+				begin()
+			}
+			<-beginCtx.Done()
+
+			// do some "work"
+			// Not required for correctness, but makes it easier to spot a
+			// failure when there is more overlap.
+			time.Sleep(10 * time.Millisecond)
+
+			return providers.ApplyResourceChangeResponse{
+				NewState: cty.EmptyObjectVal,
+			}
+		}
+		providerFactories[addrs.NewDefaultProvider(name)] = providers.FactoryFixed(provider)
+	}
+	testingOverrides := &testingOverrides{
+		Providers: providerFactories,
+	}
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: testingOverrides,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-auto-approve",
+		fmt.Sprintf("-parallelism=%d", par),
+	}
+
+	res := c.Run(args)
+	output := done(t)
+	if res != 0 {
+		t.Fatal(output.Stdout())
+	}
+}
+
+func TestApply_configInvalid(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-config-invalid"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", testTempFile(t),
+		"-auto-approve",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 1 {
+		t.Fatalf("bad: \n%s", output.Stdout())
+	}
+}
+
+func TestApply_defaultState(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	statePath := filepath.Join(td, DefaultStateFilename)
+
+	// Change to the temporary directory
+	cwd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if err := os.Chdir(filepath.Dir(statePath)); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer os.Chdir(cwd)
+
+	p := applyFixtureProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	// create an existing state file
+	localState := statemgr.NewFilesystem(statePath)
+	if err := localState.WriteState(states.NewState()); err != nil {
+		t.Fatal(err)
+	}
+
+	args := []string{
+		"-auto-approve",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	state := testStateRead(t, statePath)
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+}
+
+func TestApply_error(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-error"), td)
+	defer testChdir(t, td)()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	var lock sync.Mutex
+	errored := false
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		lock.Lock()
+		defer lock.Unlock()
+
+		if !errored {
+			errored = true
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
+		}
+
+		s := req.PlannedState.AsValueMap()
+		s["id"] = cty.StringVal("foo")
+
+		resp.NewState = cty.ObjectVal(s)
+		return
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		s := req.ProposedNewState.AsValueMap()
+		s["id"] = cty.UnknownVal(cty.String)
+		resp.PlannedState = cty.ObjectVal(s)
+		return
+	}
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":    {Type: cty.String, Optional: true, Computed: true},
+						"ami":   {Type: cty.String, Optional: true},
+						"error": {Type: cty.Bool, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-auto-approve",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 1 {
+		t.Fatalf("wrong exit code %d; want 1\n%s", code, output.Stdout())
+	}
+
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	state := testStateRead(t, statePath)
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+	if len(state.RootModule().Resources) == 0 {
+		t.Fatal("no resources in state")
+	}
+}
+
+func TestApply_input(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-input"), td)
+	defer testChdir(t, td)()
+
+	// Disable test mode so input would be asked
+	test = false
+	defer func() { test = true }()
+
+	// The configuration for this test includes a declaration of variable
+	// "foo" with no default, and we don't set it on the command line below,
+	// so the apply command will produce an interactive prompt for the
+	// value of var.foo. We'll answer "foo" here, and we expect the output
+	// value "result" to echo that back to us below.
+	defaultInputReader = bytes.NewBufferString("foo\n")
+	defaultInputWriter = new(bytes.Buffer)
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-auto-approve",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	expected := strings.TrimSpace(`
+<no state>
+Outputs:
+
+result = foo
+	`)
+	testStateOutput(t, statePath, expected)
+}
+
+// When only a partial set of the variables are set, Terraform
+// should still ask for the unset ones by default (with -input=true)
+func TestApply_inputPartial(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-input-partial"), td)
+	defer testChdir(t, td)()
+
+	// Disable test mode so input would be asked
+	test = false
+	defer func() { test = true }()
+
+	// Set some default reader/writers for the inputs
+	defaultInputReader = bytes.NewBufferString("one\ntwo\n")
+	defaultInputWriter = new(bytes.Buffer)
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-auto-approve",
+		"-var", "foo=foovalue",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	expected := strings.TrimSpace(`
+<no state>
+Outputs:
+
+bar = one
+foo = foovalue
+	`)
+	testStateOutput(t, statePath, expected)
+}
+
+func TestApply_noArgs(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	statePath := testTempFile(t)
+
+	p := applyFixtureProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-auto-approve",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	state := testStateRead(t, statePath)
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+}
+
+func TestApply_plan(t *testing.T) {
+	// Disable test mode so input would be asked
+	test = false
+	defer func() { test = true }()
+
+	// Set some default reader/writers for the inputs
+	defaultInputReader = new(bytes.Buffer)
+	defaultInputWriter = new(bytes.Buffer)
+
+	planPath := applyFixturePlanFile(t)
+	statePath := testTempFile(t)
+
+	p := applyFixtureProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state-out", statePath,
+		planPath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	state := testStateRead(t, statePath)
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+}
+
+func TestApply_plan_backup(t *testing.T) {
+	statePath := testTempFile(t)
+	backupPath := testTempFile(t)
+
+	p := applyFixtureProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	// create a state file that needs to be backed up
+	fs := statemgr.NewFilesystem(statePath)
+	fs.StateSnapshotMeta()
+	err := fs.WriteState(states.NewState())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// the plan file must contain the metadata from the prior state to be
+	// backed up
+	planPath := applyFixturePlanFileMatchState(t, fs.StateSnapshotMeta())
+
+	args := []string{
+		"-state", statePath,
+		"-backup", backupPath,
+		planPath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// Should have a backup file
+	testStateRead(t, backupPath)
+}
+
+func TestApply_plan_noBackup(t *testing.T) {
+	planPath := applyFixturePlanFile(t)
+	statePath := testTempFile(t)
+
+	p := applyFixtureProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state-out", statePath,
+		"-backup", "-",
+		planPath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// Ensure there is no backup
+	_, err := os.Stat(statePath + DefaultBackupExtension)
+	if err == nil || !os.IsNotExist(err) {
+		t.Fatalf("backup should not exist")
+	}
+
+	// Ensure there is no literal "-"
+	_, err = os.Stat("-")
+	if err == nil || !os.IsNotExist(err) {
+		t.Fatalf("backup should not exist")
+	}
+}
+
+func TestApply_plan_remoteState(t *testing.T) {
+	// Disable test mode so input would be asked
+	test = false
+	defer func() { test = true }()
+	tmp := testCwd(t)
+	remoteStatePath := filepath.Join(tmp, DefaultDataDir, DefaultStateFilename)
+	if err := os.MkdirAll(filepath.Dir(remoteStatePath), 0755); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Set some default reader/writers for the inputs
+	defaultInputReader = new(bytes.Buffer)
+	defaultInputWriter = new(bytes.Buffer)
+
+	// Create a remote state
+	state := testState()
+	_, srv := testRemoteState(t, state, 200)
+	defer srv.Close()
+
+	_, snap := testModuleWithSnapshot(t, "apply")
+	backendConfig := cty.ObjectVal(map[string]cty.Value{
+		"address":                   cty.StringVal(srv.URL),
+		"update_method":             cty.NullVal(cty.String),
+		"lock_address":              cty.NullVal(cty.String),
+		"unlock_address":            cty.NullVal(cty.String),
+		"lock_method":               cty.NullVal(cty.String),
+		"unlock_method":             cty.NullVal(cty.String),
+		"username":                  cty.NullVal(cty.String),
+		"password":                  cty.NullVal(cty.String),
+		"skip_cert_verification":    cty.NullVal(cty.Bool),
+		"retry_max":                 cty.NullVal(cty.String),
+		"retry_wait_min":            cty.NullVal(cty.String),
+		"retry_wait_max":            cty.NullVal(cty.String),
+		"client_ca_certificate_pem": cty.NullVal(cty.String),
+		"client_certificate_pem":    cty.NullVal(cty.String),
+		"client_private_key_pem":    cty.NullVal(cty.String),
+	})
+	backendConfigRaw, err := plans.NewDynamicValue(backendConfig, backendConfig.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	planPath := testPlanFile(t, snap, state, &plans.Plan{
+		Backend: plans.Backend{
+			Type:   "http",
+			Config: backendConfigRaw,
+		},
+		Changes: plans.NewChanges(),
+	})
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		planPath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// State file should be not be installed
+	if _, err := os.Stat(filepath.Join(tmp, DefaultStateFilename)); err == nil {
+		data, _ := ioutil.ReadFile(DefaultStateFilename)
+		t.Fatalf("State path should not exist: %s", string(data))
+	}
+
+	// Check that there is no remote state config
+	if src, err := ioutil.ReadFile(remoteStatePath); err == nil {
+		t.Fatalf("has %s file; should not\n%s", remoteStatePath, src)
+	}
+}
+
+func TestApply_planWithVarFile(t *testing.T) {
+	varFileDir := testTempDir(t)
+	varFilePath := filepath.Join(varFileDir, "terraform.tfvars")
+	if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	planPath := applyFixturePlanFile(t)
+	statePath := testTempFile(t)
+
+	cwd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if err := os.Chdir(varFileDir); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer os.Chdir(cwd)
+
+	p := applyFixtureProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state-out", statePath,
+		planPath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	state := testStateRead(t, statePath)
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+}
+
+func TestApply_planVars(t *testing.T) {
+	planPath := applyFixturePlanFile(t)
+	statePath := testTempFile(t)
+
+	p := applyFixtureProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-var", "foo=bar",
+		planPath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code == 0 {
+		t.Fatal("should've failed: ", output.Stdout())
+	}
+}
+
+// we should be able to apply a plan file with no other file dependencies
+func TestApply_planNoModuleFiles(t *testing.T) {
+	// temporary data directory which we can remove between commands
+	td := testTempDir(t)
+	defer os.RemoveAll(td)
+
+	defer testChdir(t, td)()
+
+	p := applyFixtureProvider()
+	planPath := applyFixturePlanFile(t)
+	view, done := testView(t)
+	apply := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               new(cli.MockUi),
+			View:             view,
+		},
+	}
+	args := []string{
+		planPath,
+	}
+	apply.Run(args)
+	done(t)
+}
+
+func TestApply_refresh(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"ami":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, originalState)
+
+	p := applyFixtureProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-auto-approve",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if !p.ReadResourceCalled {
+		t.Fatal("should call ReadResource")
+	}
+
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	state := testStateRead(t, statePath)
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+
+	// Should have a backup file
+	backupState := testStateRead(t, statePath+DefaultBackupExtension)
+
+	actualStr := strings.TrimSpace(backupState.String())
+	expectedStr := strings.TrimSpace(originalState.String())
+	if actualStr != expectedStr {
+		t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr)
+	}
+}
+
+func TestApply_refreshFalse(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"ami":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, originalState)
+
+	p := applyFixtureProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-auto-approve",
+		"-refresh=false",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if p.ReadResourceCalled {
+		t.Fatal("should not call ReadResource when refresh=false")
+	}
+}
+func TestApply_shutdown(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-shutdown"), td)
+	defer testChdir(t, td)()
+
+	cancelled := make(chan struct{})
+	shutdownCh := make(chan struct{})
+
+	statePath := testTempFile(t)
+	p := testProvider()
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+			ShutdownCh:       shutdownCh,
+		},
+	}
+
+	p.StopFn = func() error {
+		close(cancelled)
+		return nil
+	}
+
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		resp.PlannedState = req.ProposedNewState
+		return
+	}
+
+	var once sync.Once
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		// only cancel once
+		once.Do(func() {
+			shutdownCh <- struct{}{}
+		})
+
+		// Because of the internal lock in the MockProvider, we can't
+		// coordiante directly with the calling of Stop, and making the
+		// MockProvider concurrent is disruptive to a lot of existing tests.
+		// Wait here a moment to help make sure the main goroutine gets to the
+		// Stop call before we exit, or the plan may finish before it can be
+		// canceled.
+		time.Sleep(200 * time.Millisecond)
+
+		resp.NewState = req.PlannedState
+		return
+	}
+
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"ami": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-auto-approve",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 1 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	select {
+	case <-cancelled:
+	default:
+		t.Fatal("command not cancelled")
+	}
+
+	state := testStateRead(t, statePath)
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+}
+
+func TestApply_state(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"ami":"foo"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, originalState)
+
+	p := applyFixtureProvider()
+	p.PlanResourceChangeResponse = &providers.PlanResourceChangeResponse{
+		PlannedState: cty.ObjectVal(map[string]cty.Value{
+			"ami": cty.StringVal("bar"),
+		}),
+	}
+	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"ami": cty.StringVal("bar"),
+		}),
+	}
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	// Run the apply command pointing to our existing state
+	args := []string{
+		"-state", statePath,
+		"-auto-approve",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// Verify that the provider was called with the existing state
+	actual := p.PlanResourceChangeRequest.PriorState
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"id":  cty.NullVal(cty.String),
+		"ami": cty.StringVal("foo"),
+	})
+	if !expected.RawEquals(actual) {
+		t.Fatalf("wrong prior state during plan\ngot: %#v\nwant: %#v", actual, expected)
+	}
+
+	actual = p.ApplyResourceChangeRequest.PriorState
+	expected = cty.ObjectVal(map[string]cty.Value{
+		"id":  cty.NullVal(cty.String),
+		"ami": cty.StringVal("foo"),
+	})
+	if !expected.RawEquals(actual) {
+		t.Fatalf("wrong prior state during apply\ngot: %#v\nwant: %#v", actual, expected)
+	}
+
+	// Verify a new state exists
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	state := testStateRead(t, statePath)
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+
+	backupState := testStateRead(t, statePath+DefaultBackupExtension)
+
+	actualStr := strings.TrimSpace(backupState.String())
+	expectedStr := strings.TrimSpace(originalState.String())
+	if actualStr != expectedStr {
+		t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr)
+	}
+}
+
+func TestApply_stateNoExist(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	p := applyFixtureProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"idontexist.tfstate",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 1 {
+		t.Fatalf("bad: \n%s", output.Stdout())
+	}
+}
+
+func TestApply_sensitiveOutput(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-sensitive-output"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	statePath := testTempFile(t)
+
+	args := []string{
+		"-state", statePath,
+		"-auto-approve",
+	}
+
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: \n%s", output.Stdout())
+	}
+
+	stdout := output.Stdout()
+	if !strings.Contains(stdout, "notsensitive = \"Hello world\"") {
+		t.Fatalf("bad: output should contain 'notsensitive' output\n%s", stdout)
+	}
+	if !strings.Contains(stdout, "sensitive = <sensitive>") {
+		t.Fatalf("bad: output should contain 'sensitive' output\n%s", stdout)
+	}
+}
+
+func TestApply_vars(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-vars"), td)
+	defer testChdir(t, td)()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	actual := ""
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"value": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		return providers.ApplyResourceChangeResponse{
+			NewState: req.PlannedState,
+		}
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		actual = req.ProposedNewState.GetAttr("value").AsString()
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+
+	args := []string{
+		"-auto-approve",
+		"-var", "foo=bar",
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if actual != "bar" {
+		t.Fatal("didn't work")
+	}
+}
+
+func TestApply_varFile(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-vars"), td)
+	defer testChdir(t, td)()
+
+	varFilePath := testTempFile(t)
+	if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	actual := ""
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"value": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		return providers.ApplyResourceChangeResponse{
+			NewState: req.PlannedState,
+		}
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		actual = req.ProposedNewState.GetAttr("value").AsString()
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+
+	args := []string{
+		"-auto-approve",
+		"-var-file", varFilePath,
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if actual != "bar" {
+		t.Fatal("didn't work")
+	}
+}
+
+func TestApply_varFileDefault(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-vars"), td)
+	defer testChdir(t, td)()
+
+	varFilePath := filepath.Join(td, "terraform.tfvars")
+	if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	actual := ""
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"value": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		return providers.ApplyResourceChangeResponse{
+			NewState: req.PlannedState,
+		}
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		actual = req.ProposedNewState.GetAttr("value").AsString()
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+
+	args := []string{
+		"-auto-approve",
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if actual != "bar" {
+		t.Fatal("didn't work")
+	}
+}
+
+func TestApply_varFileDefaultJSON(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-vars"), td)
+	defer testChdir(t, td)()
+
+	varFilePath := filepath.Join(td, "terraform.tfvars.json")
+	if err := ioutil.WriteFile(varFilePath, []byte(applyVarFileJSON), 0644); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	actual := ""
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"value": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		return providers.ApplyResourceChangeResponse{
+			NewState: req.PlannedState,
+		}
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		actual = req.ProposedNewState.GetAttr("value").AsString()
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+
+	args := []string{
+		"-auto-approve",
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if actual != "bar" {
+		t.Fatal("didn't work")
+	}
+}
+
+func TestApply_backup(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte("{\n            \"id\": \"bar\"\n          }"),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, originalState)
+	backupPath := testTempFile(t)
+
+	p := applyFixtureProvider()
+	p.PlanResourceChangeResponse = &providers.PlanResourceChangeResponse{
+		PlannedState: cty.ObjectVal(map[string]cty.Value{
+			"ami": cty.StringVal("bar"),
+		}),
+	}
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	// Run the apply command pointing to our existing state
+	args := []string{
+		"-auto-approve",
+		"-state", statePath,
+		"-backup", backupPath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// Verify a new state exists
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	state := testStateRead(t, statePath)
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+
+	backupState := testStateRead(t, backupPath)
+
+	actual := backupState.RootModule().Resources["test_instance.foo"]
+	expected := originalState.RootModule().Resources["test_instance.foo"]
+	if !cmp.Equal(actual, expected, cmpopts.EquateEmpty()) {
+		t.Fatalf(
+			"wrong aws_instance.foo state\n%s",
+			cmp.Diff(expected, actual, cmp.Transformer("bytesAsString", func(b []byte) string {
+				return string(b)
+			})),
+		)
+	}
+}
+
+func TestApply_disableBackup(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	originalState := testState()
+	statePath := testStateFile(t, originalState)
+
+	p := applyFixtureProvider()
+	p.PlanResourceChangeResponse = &providers.PlanResourceChangeResponse{
+		PlannedState: cty.ObjectVal(map[string]cty.Value{
+			"ami": cty.StringVal("bar"),
+		}),
+	}
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	// Run the apply command pointing to our existing state
+	args := []string{
+		"-auto-approve",
+		"-state", statePath,
+		"-backup", "-",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// Verify that the provider was called with the existing state
+	actual := p.PlanResourceChangeRequest.PriorState
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"id":  cty.StringVal("bar"),
+		"ami": cty.NullVal(cty.String),
+	})
+	if !expected.RawEquals(actual) {
+		t.Fatalf("wrong prior state during plan\ngot:  %#v\nwant: %#v", actual, expected)
+	}
+
+	actual = p.ApplyResourceChangeRequest.PriorState
+	expected = cty.ObjectVal(map[string]cty.Value{
+		"id":  cty.StringVal("bar"),
+		"ami": cty.NullVal(cty.String),
+	})
+	if !expected.RawEquals(actual) {
+		t.Fatalf("wrong prior state during apply\ngot:  %#v\nwant: %#v", actual, expected)
+	}
+
+	// Verify a new state exists
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	state := testStateRead(t, statePath)
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+
+	// Ensure there is no backup
+	_, err := os.Stat(statePath + DefaultBackupExtension)
+	if err == nil || !os.IsNotExist(err) {
+		t.Fatalf("backup should not exist")
+	}
+
+	// Ensure there is no literal "-"
+	_, err = os.Stat("-")
+	if err == nil || !os.IsNotExist(err) {
+		t.Fatalf("backup should not exist")
+	}
+}
+
+// Test that the Terraform env is passed through
+func TestApply_terraformEnv(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-terraform-env"), td)
+	defer testChdir(t, td)()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-auto-approve",
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	expected := strings.TrimSpace(`
+<no state>
+Outputs:
+
+output = default
+	`)
+	testStateOutput(t, statePath, expected)
+}
+
+// Test that the Terraform env is passed through
+func TestApply_terraformEnvNonDefault(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-terraform-env"), td)
+	defer testChdir(t, td)()
+
+	// Create new env
+	{
+		ui := new(cli.MockUi)
+		newCmd := &WorkspaceNewCommand{
+			Meta: Meta{
+				Ui: ui,
+			},
+		}
+		if code := newCmd.Run([]string{"test"}); code != 0 {
+			t.Fatal("error creating workspace")
+		}
+	}
+
+	// Switch to it
+	{
+		args := []string{"test"}
+		ui := new(cli.MockUi)
+		selCmd := &WorkspaceSelectCommand{
+			Meta: Meta{
+				Ui: ui,
+			},
+		}
+		if code := selCmd.Run(args); code != 0 {
+			t.Fatal("error switching workspace")
+		}
+	}
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-auto-approve",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	statePath := filepath.Join("terraform.tfstate.d", "test", "terraform.tfstate")
+	expected := strings.TrimSpace(`
+<no state>
+Outputs:
+
+output = test
+	`)
+	testStateOutput(t, statePath, expected)
+}
+
+// Config with multiple resources, targeting apply of a subset
+func TestApply_targeted(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-targeted"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Computed: true},
+					},
+				},
+			},
+		},
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-auto-approve",
+		"-target", "test_instance.foo",
+		"-target", "test_instance.baz",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if got, want := output.Stdout(), "3 added, 0 changed, 0 destroyed"; !strings.Contains(got, want) {
+		t.Fatalf("bad change summary, want %q, got:\n%s", want, got)
+	}
+}
+
+// Diagnostics for invalid -target flags
+func TestApply_targetFlagsDiags(t *testing.T) {
+	testCases := map[string]string{
+		"test_instance.": "Dot must be followed by attribute name.",
+		"test_instance":  "Resource specification must include a resource type and name.",
+	}
+
+	for target, wantDiag := range testCases {
+		t.Run(target, func(t *testing.T) {
+			td := testTempDir(t)
+			defer os.RemoveAll(td)
+			defer testChdir(t, td)()
+
+			view, done := testView(t)
+			c := &ApplyCommand{
+				Meta: Meta{
+					View: view,
+				},
+			}
+
+			args := []string{
+				"-auto-approve",
+				"-target", target,
+			}
+			code := c.Run(args)
+			output := done(t)
+			if code != 1 {
+				t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+			}
+
+			got := output.Stderr()
+			if !strings.Contains(got, target) {
+				t.Fatalf("bad error output, want %q, got:\n%s", target, got)
+			}
+			if !strings.Contains(got, wantDiag) {
+				t.Fatalf("bad error output, want %q, got:\n%s", wantDiag, got)
+			}
+		})
+	}
+}
+
+func TestApply_replace(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-replace"), td)
+	defer testChdir(t, td)()
+
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "a",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"hello"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, originalState)
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Computed: true},
+					},
+				},
+			},
+		},
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+	createCount := 0
+	deleteCount := 0
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		if req.PriorState.IsNull() {
+			createCount++
+		}
+		if req.PlannedState.IsNull() {
+			deleteCount++
+		}
+		return providers.ApplyResourceChangeResponse{
+			NewState: req.PlannedState,
+		}
+	}
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-auto-approve",
+		"-state", statePath,
+		"-replace", "test_instance.a",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("wrong exit code %d\n\n%s", code, output.Stderr())
+	}
+
+	if got, want := output.Stdout(), "1 added, 0 changed, 1 destroyed"; !strings.Contains(got, want) {
+		t.Errorf("wrong change summary\ngot output:\n%s\n\nwant substring: %s", got, want)
+	}
+
+	if got, want := createCount, 1; got != want {
+		t.Errorf("wrong create count %d; want %d", got, want)
+	}
+	if got, want := deleteCount, 1; got != want {
+		t.Errorf("wrong create count %d; want %d", got, want)
+	}
+}
+
+func TestApply_pluginPath(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	statePath := testTempFile(t)
+
+	p := applyFixtureProvider()
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	pluginPath := []string{"a", "b", "c"}
+
+	if err := c.Meta.storePluginPath(pluginPath); err != nil {
+		t.Fatal(err)
+	}
+	c.Meta.pluginPath = nil
+
+	args := []string{
+		"-state", statePath,
+		"-auto-approve",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if !reflect.DeepEqual(pluginPath, c.Meta.pluginPath) {
+		t.Fatalf("expected plugin path %#v, got %#v", pluginPath, c.Meta.pluginPath)
+	}
+}
+
+func TestApply_jsonGoldenReference(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	statePath := testTempFile(t)
+
+	p := applyFixtureProvider()
+
+	view, done := testView(t)
+	c := &ApplyCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-json",
+		"-state", statePath,
+		"-auto-approve",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if _, err := os.Stat(statePath); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	state := testStateRead(t, statePath)
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+
+	checkGoldenReference(t, output, "apply")
+}
+
+func TestApply_warnings(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = applyFixtureSchema()
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+			Diagnostics: tfdiags.Diagnostics{
+				tfdiags.SimpleWarning("warning 1"),
+				tfdiags.SimpleWarning("warning 2"),
+			},
+		}
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		return providers.ApplyResourceChangeResponse{
+			NewState: cty.UnknownAsNull(req.PlannedState),
+		}
+	}
+
+	t.Run("full warnings", func(t *testing.T) {
+		view, done := testView(t)
+		c := &ApplyCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				View:             view,
+			},
+		}
+
+		args := []string{"-auto-approve"}
+		code := c.Run(args)
+		output := done(t)
+		if code != 0 {
+			t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+		}
+		wantWarnings := []string{
+			"warning 1",
+			"warning 2",
+		}
+		for _, want := range wantWarnings {
+			if !strings.Contains(output.Stdout(), want) {
+				t.Errorf("missing warning %s", want)
+			}
+		}
+	})
+
+	t.Run("compact warnings", func(t *testing.T) {
+		view, done := testView(t)
+		c := &ApplyCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				View:             view,
+			},
+		}
+
+		code := c.Run([]string{"-auto-approve", "-compact-warnings"})
+		output := done(t)
+		if code != 0 {
+			t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+		}
+		// the output should contain 2 warnings and a message about -compact-warnings
+		wantWarnings := []string{
+			"warning 1",
+			"warning 2",
+			"To see the full warning notes, run Terraform without -compact-warnings.",
+		}
+		for _, want := range wantWarnings {
+			if !strings.Contains(output.Stdout(), want) {
+				t.Errorf("missing warning %s", want)
+			}
+		}
+	})
+}
+
+// applyFixtureSchema returns a schema suitable for processing the
+// configuration in testdata/apply . This schema should be
+// assigned to a mock provider named "test".
+func applyFixtureSchema() *providers.GetProviderSchemaResponse {
+	return &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":  {Type: cty.String, Optional: true, Computed: true},
+						"ami": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+}
+
+// applyFixtureProvider returns a mock provider that is configured for basic
+// operation with the configuration in testdata/apply. This mock has
+// GetSchemaResponse, PlanResourceChangeFn, and ApplyResourceChangeFn populated,
+// with the plan/apply steps just passing through the data determined by
+// Terraform Core.
+func applyFixtureProvider() *terraform.MockProvider {
+	p := testProvider()
+	p.GetProviderSchemaResponse = applyFixtureSchema()
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		return providers.ApplyResourceChangeResponse{
+			NewState: cty.UnknownAsNull(req.PlannedState),
+		}
+	}
+	return p
+}
+
+// applyFixturePlanFile creates a plan file at a temporary location containing
+// a single change to create the test_instance.foo that is included in the
+// "apply" test fixture, returning the location of that plan file.
+func applyFixturePlanFile(t *testing.T) string {
+	return applyFixturePlanFileMatchState(t, statemgr.SnapshotMeta{})
+}
+
+// applyFixturePlanFileMatchState creates a planfile like applyFixturePlanFile,
+// but inserts the state meta information if that plan must match a preexisting
+// state.
+func applyFixturePlanFileMatchState(t *testing.T, stateMeta statemgr.SnapshotMeta) string {
+	_, snap := testModuleWithSnapshot(t, "apply")
+	plannedVal := cty.ObjectVal(map[string]cty.Value{
+		"id":  cty.UnknownVal(cty.String),
+		"ami": cty.StringVal("bar"),
+	})
+	priorValRaw, err := plans.NewDynamicValue(cty.NullVal(plannedVal.Type()), plannedVal.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	plannedValRaw, err := plans.NewDynamicValue(plannedVal, plannedVal.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	plan := testPlan(t)
+	plan.Changes.SyncWrapper().AppendResourceInstanceChange(&plans.ResourceInstanceChangeSrc{
+		Addr: addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: "foo",
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+		ProviderAddr: addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+		ChangeSrc: plans.ChangeSrc{
+			Action: plans.Create,
+			Before: priorValRaw,
+			After:  plannedValRaw,
+		},
+	})
+	return testPlanFileMatchState(
+		t,
+		snap,
+		states.NewState(),
+		plan,
+		stateMeta,
+	)
+}
+
+const applyVarFile = `
+foo = "bar"
+`
+
+const applyVarFileJSON = `
+{ "foo": "bar" }
+`
diff --git a/v1.5.7/internal/command/arguments/apply.go b/v1.5.7/internal/command/arguments/apply.go
new file mode 100644
index 0000000..552896b
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/apply.go
@@ -0,0 +1,150 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Apply represents the command-line arguments for the apply command.
+type Apply struct {
+	// State, Operation, and Vars are the common extended flags
+	State     *State
+	Operation *Operation
+	Vars      *Vars
+
+	// AutoApprove skips the manual verification step for the apply operation.
+	AutoApprove bool
+
+	// InputEnabled is used to disable interactive input for unspecified
+	// variable and backend config values. Default is true.
+	InputEnabled bool
+
+	// PlanPath contains an optional path to a stored plan file
+	PlanPath string
+
+	// ViewType specifies which output format to use
+	ViewType ViewType
+}
+
+// ParseApply processes CLI arguments, returning an Apply value and errors.
+// If errors are encountered, an Apply value is still returned representing
+// the best effort interpretation of the arguments.
+func ParseApply(args []string) (*Apply, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	apply := &Apply{
+		State:     &State{},
+		Operation: &Operation{},
+		Vars:      &Vars{},
+	}
+
+	cmdFlags := extendedFlagSet("apply", apply.State, apply.Operation, apply.Vars)
+	cmdFlags.BoolVar(&apply.AutoApprove, "auto-approve", false, "auto-approve")
+	cmdFlags.BoolVar(&apply.InputEnabled, "input", true, "input")
+
+	var json bool
+	cmdFlags.BoolVar(&json, "json", false, "json")
+
+	if err := cmdFlags.Parse(args); err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to parse command-line flags",
+			err.Error(),
+		))
+	}
+
+	args = cmdFlags.Args()
+	if len(args) > 0 {
+		apply.PlanPath = args[0]
+		args = args[1:]
+	}
+
+	if len(args) > 0 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Too many command line arguments",
+			"Expected at most one positional argument.",
+		))
+	}
+
+	// JSON view currently does not support input, so we disable it here.
+	if json {
+		apply.InputEnabled = false
+	}
+
+	// JSON view cannot confirm apply, so we require either a plan file or
+	// auto-approve to be specified. We intentionally fail here rather than
+	// override auto-approve, which would be dangerous.
+	if json && apply.PlanPath == "" && !apply.AutoApprove {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Plan file or auto-approve required",
+			"Terraform cannot ask for interactive approval when -json is set. You can either apply a saved plan file, or enable the -auto-approve option.",
+		))
+	}
+
+	diags = diags.Append(apply.Operation.Parse())
+
+	switch {
+	case json:
+		apply.ViewType = ViewJSON
+	default:
+		apply.ViewType = ViewHuman
+	}
+
+	return apply, diags
+}
+
+// ParseApplyDestroy is a special case of ParseApply that deals with the
+// "terraform destroy" command, which is effectively an alias for
+// "terraform apply -destroy".
+func ParseApplyDestroy(args []string) (*Apply, tfdiags.Diagnostics) {
+	apply, diags := ParseApply(args)
+
+	// So far ParseApply was using the command line options like -destroy
+	// and -refresh-only to determine the plan mode. For "terraform destroy"
+	// we expect neither of those arguments to be set, and so the plan mode
+	// should currently be set to NormalMode, which we'll replace with
+	// DestroyMode here. If it's already set to something else then that
+	// suggests incorrect usage.
+	switch apply.Operation.PlanMode {
+	case plans.NormalMode:
+		// This indicates that the user didn't specify any mode options at
+		// all, which is correct, although we know from the command that
+		// they actually intended to use DestroyMode here.
+		apply.Operation.PlanMode = plans.DestroyMode
+	case plans.DestroyMode:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid mode option",
+			"The -destroy option is not valid for \"terraform destroy\", because this command always runs in destroy mode.",
+		))
+	case plans.RefreshOnlyMode:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid mode option",
+			"The -refresh-only option is not valid for \"terraform destroy\".",
+		))
+	default:
+		// This is a non-ideal error message for if we forget to handle a
+		// newly-handled plan mode in Operation.Parse. Ideally they should all
+		// have cases above so we can produce better error messages.
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid mode option",
+			fmt.Sprintf("The \"terraform destroy\" command doesn't support %s.", apply.Operation.PlanMode),
+		))
+	}
+
+	// NOTE: It's also invalid to have apply.PlanPath set in this codepath,
+	// but we don't check that in here because we'll return a different error
+	// message depending on whether the given path seems to refer to a saved
+	// plan file or to a configuration directory. The apply command
+	// implementation itself therefore handles this situation.
+
+	return apply, diags
+}
diff --git a/v1.5.7/internal/command/arguments/apply_test.go b/v1.5.7/internal/command/arguments/apply_test.go
new file mode 100644
index 0000000..ebf2e27
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/apply_test.go
@@ -0,0 +1,392 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+func TestParseApply_basicValid(t *testing.T) {
+	testCases := map[string]struct {
+		args []string
+		want *Apply
+	}{
+		"defaults": {
+			nil,
+			&Apply{
+				AutoApprove:  false,
+				InputEnabled: true,
+				PlanPath:     "",
+				ViewType:     ViewHuman,
+				State:        &State{Lock: true},
+				Vars:         &Vars{},
+				Operation: &Operation{
+					PlanMode:    plans.NormalMode,
+					Parallelism: 10,
+					Refresh:     true,
+				},
+			},
+		},
+		"auto-approve, disabled input, and plan path": {
+			[]string{"-auto-approve", "-input=false", "saved.tfplan"},
+			&Apply{
+				AutoApprove:  true,
+				InputEnabled: false,
+				PlanPath:     "saved.tfplan",
+				ViewType:     ViewHuman,
+				State:        &State{Lock: true},
+				Vars:         &Vars{},
+				Operation: &Operation{
+					PlanMode:    plans.NormalMode,
+					Parallelism: 10,
+					Refresh:     true,
+				},
+			},
+		},
+		"destroy mode": {
+			[]string{"-destroy"},
+			&Apply{
+				AutoApprove:  false,
+				InputEnabled: true,
+				PlanPath:     "",
+				ViewType:     ViewHuman,
+				State:        &State{Lock: true},
+				Vars:         &Vars{},
+				Operation: &Operation{
+					PlanMode:    plans.DestroyMode,
+					Parallelism: 10,
+					Refresh:     true,
+				},
+			},
+		},
+		"JSON view disables input": {
+			[]string{"-json", "-auto-approve"},
+			&Apply{
+				AutoApprove:  true,
+				InputEnabled: false,
+				PlanPath:     "",
+				ViewType:     ViewJSON,
+				State:        &State{Lock: true},
+				Vars:         &Vars{},
+				Operation: &Operation{
+					PlanMode:    plans.NormalMode,
+					Parallelism: 10,
+					Refresh:     true,
+				},
+			},
+		},
+	}
+
+	cmpOpts := cmpopts.IgnoreUnexported(Operation{}, Vars{}, State{})
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, diags := ParseApply(tc.args)
+			if len(diags) > 0 {
+				t.Fatalf("unexpected diags: %v", diags)
+			}
+			if diff := cmp.Diff(tc.want, got, cmpOpts); diff != "" {
+				t.Errorf("unexpected result\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestParseApply_json(t *testing.T) {
+	testCases := map[string]struct {
+		args        []string
+		wantSuccess bool
+	}{
+		"-json": {
+			[]string{"-json"},
+			false,
+		},
+		"-json -auto-approve": {
+			[]string{"-json", "-auto-approve"},
+			true,
+		},
+		"-json saved.tfplan": {
+			[]string{"-json", "saved.tfplan"},
+			true,
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, diags := ParseApply(tc.args)
+
+			if tc.wantSuccess {
+				if len(diags) > 0 {
+					t.Errorf("unexpected diags: %v", diags)
+				}
+			} else {
+				if got, want := diags.Err().Error(), "Plan file or auto-approve required"; !strings.Contains(got, want) {
+					t.Errorf("wrong diags\n got: %s\nwant: %s", got, want)
+				}
+			}
+
+			if got.ViewType != ViewJSON {
+				t.Errorf("unexpected view type. got: %#v, want: %#v", got.ViewType, ViewJSON)
+			}
+		})
+	}
+}
+
+func TestParseApply_invalid(t *testing.T) {
+	got, diags := ParseApply([]string{"-frob"})
+	if len(diags) == 0 {
+		t.Fatal("expected diags but got none")
+	}
+	if got, want := diags.Err().Error(), "flag provided but not defined"; !strings.Contains(got, want) {
+		t.Fatalf("wrong diags\n got: %s\nwant: %s", got, want)
+	}
+	if got.ViewType != ViewHuman {
+		t.Fatalf("wrong view type, got %#v, want %#v", got.ViewType, ViewHuman)
+	}
+}
+
+func TestParseApply_tooManyArguments(t *testing.T) {
+	got, diags := ParseApply([]string{"saved.tfplan", "please"})
+	if len(diags) == 0 {
+		t.Fatal("expected diags but got none")
+	}
+	if got, want := diags.Err().Error(), "Too many command line arguments"; !strings.Contains(got, want) {
+		t.Fatalf("wrong diags\n got: %s\nwant: %s", got, want)
+	}
+	if got.ViewType != ViewHuman {
+		t.Fatalf("wrong view type, got %#v, want %#v", got.ViewType, ViewHuman)
+	}
+}
+
+func TestParseApply_targets(t *testing.T) {
+	foobarbaz, _ := addrs.ParseTargetStr("foo_bar.baz")
+	boop, _ := addrs.ParseTargetStr("module.boop")
+	testCases := map[string]struct {
+		args    []string
+		want    []addrs.Targetable
+		wantErr string
+	}{
+		"no targets by default": {
+			args: nil,
+			want: nil,
+		},
+		"one target": {
+			args: []string{"-target=foo_bar.baz"},
+			want: []addrs.Targetable{foobarbaz.Subject},
+		},
+		"two targets": {
+			args: []string{"-target=foo_bar.baz", "-target", "module.boop"},
+			want: []addrs.Targetable{foobarbaz.Subject, boop.Subject},
+		},
+		"invalid traversal": {
+			args:    []string{"-target=foo."},
+			want:    nil,
+			wantErr: "Dot must be followed by attribute name",
+		},
+		"invalid target": {
+			args:    []string{"-target=data[0].foo"},
+			want:    nil,
+			wantErr: "A data source name is required",
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, diags := ParseApply(tc.args)
+			if len(diags) > 0 {
+				if tc.wantErr == "" {
+					t.Fatalf("unexpected diags: %v", diags)
+				} else if got := diags.Err().Error(); !strings.Contains(got, tc.wantErr) {
+					t.Fatalf("wrong diags\n got: %s\nwant: %s", got, tc.wantErr)
+				}
+			}
+			if !cmp.Equal(got.Operation.Targets, tc.want) {
+				t.Fatalf("unexpected result\n%s", cmp.Diff(got.Operation.Targets, tc.want))
+			}
+		})
+	}
+}
+
+func TestParseApply_replace(t *testing.T) {
+	foobarbaz, _ := addrs.ParseAbsResourceInstanceStr("foo_bar.baz")
+	foobarbeep, _ := addrs.ParseAbsResourceInstanceStr("foo_bar.beep")
+	testCases := map[string]struct {
+		args    []string
+		want    []addrs.AbsResourceInstance
+		wantErr string
+	}{
+		"no addresses by default": {
+			args: nil,
+			want: nil,
+		},
+		"one address": {
+			args: []string{"-replace=foo_bar.baz"},
+			want: []addrs.AbsResourceInstance{foobarbaz},
+		},
+		"two addresses": {
+			args: []string{"-replace=foo_bar.baz", "-replace", "foo_bar.beep"},
+			want: []addrs.AbsResourceInstance{foobarbaz, foobarbeep},
+		},
+		"non-resource-instance address": {
+			args:    []string{"-replace=module.boop"},
+			want:    nil,
+			wantErr: "A resource instance address is required here.",
+		},
+		"data resource address": {
+			args:    []string{"-replace=data.foo.bar"},
+			want:    nil,
+			wantErr: "Only managed resources can be used",
+		},
+		"invalid traversal": {
+			args:    []string{"-replace=foo."},
+			want:    nil,
+			wantErr: "Dot must be followed by attribute name",
+		},
+		"invalid address": {
+			args:    []string{"-replace=data[0].foo"},
+			want:    nil,
+			wantErr: "A data source name is required",
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, diags := ParseApply(tc.args)
+			if len(diags) > 0 {
+				if tc.wantErr == "" {
+					t.Fatalf("unexpected diags: %v", diags)
+				} else if got := diags.Err().Error(); !strings.Contains(got, tc.wantErr) {
+					t.Fatalf("wrong diags\n got: %s\nwant: %s", got, tc.wantErr)
+				}
+			}
+			if !cmp.Equal(got.Operation.ForceReplace, tc.want) {
+				t.Fatalf("unexpected result\n%s", cmp.Diff(got.Operation.Targets, tc.want))
+			}
+		})
+	}
+}
+
+func TestParseApply_vars(t *testing.T) {
+	testCases := map[string]struct {
+		args []string
+		want []FlagNameValue
+	}{
+		"no var flags by default": {
+			args: nil,
+			want: nil,
+		},
+		"one var": {
+			args: []string{"-var", "foo=bar"},
+			want: []FlagNameValue{
+				{Name: "-var", Value: "foo=bar"},
+			},
+		},
+		"one var-file": {
+			args: []string{"-var-file", "cool.tfvars"},
+			want: []FlagNameValue{
+				{Name: "-var-file", Value: "cool.tfvars"},
+			},
+		},
+		"ordering preserved": {
+			args: []string{
+				"-var", "foo=bar",
+				"-var-file", "cool.tfvars",
+				"-var", "boop=beep",
+			},
+			want: []FlagNameValue{
+				{Name: "-var", Value: "foo=bar"},
+				{Name: "-var-file", Value: "cool.tfvars"},
+				{Name: "-var", Value: "boop=beep"},
+			},
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, diags := ParseApply(tc.args)
+			if len(diags) > 0 {
+				t.Fatalf("unexpected diags: %v", diags)
+			}
+			if vars := got.Vars.All(); !cmp.Equal(vars, tc.want) {
+				t.Fatalf("unexpected result\n%s", cmp.Diff(vars, tc.want))
+			}
+			if got, want := got.Vars.Empty(), len(tc.want) == 0; got != want {
+				t.Fatalf("expected Empty() to return %t, but was %t", want, got)
+			}
+		})
+	}
+}
+
+func TestParseApplyDestroy_basicValid(t *testing.T) {
+	testCases := map[string]struct {
+		args []string
+		want *Apply
+	}{
+		"defaults": {
+			nil,
+			&Apply{
+				AutoApprove:  false,
+				InputEnabled: true,
+				ViewType:     ViewHuman,
+				State:        &State{Lock: true},
+				Vars:         &Vars{},
+				Operation: &Operation{
+					PlanMode:    plans.DestroyMode,
+					Parallelism: 10,
+					Refresh:     true,
+				},
+			},
+		},
+		"auto-approve and disabled input": {
+			[]string{"-auto-approve", "-input=false"},
+			&Apply{
+				AutoApprove:  true,
+				InputEnabled: false,
+				ViewType:     ViewHuman,
+				State:        &State{Lock: true},
+				Vars:         &Vars{},
+				Operation: &Operation{
+					PlanMode:    plans.DestroyMode,
+					Parallelism: 10,
+					Refresh:     true,
+				},
+			},
+		},
+	}
+
+	cmpOpts := cmpopts.IgnoreUnexported(Operation{}, Vars{}, State{})
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, diags := ParseApplyDestroy(tc.args)
+			if len(diags) > 0 {
+				t.Fatalf("unexpected diags: %v", diags)
+			}
+			if diff := cmp.Diff(tc.want, got, cmpOpts); diff != "" {
+				t.Errorf("unexpected result\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestParseApplyDestroy_invalid(t *testing.T) {
+	t.Run("explicit destroy mode", func(t *testing.T) {
+		got, diags := ParseApplyDestroy([]string{"-destroy"})
+		if len(diags) == 0 {
+			t.Fatal("expected diags but got none")
+		}
+		if got, want := diags.Err().Error(), "Invalid mode option:"; !strings.Contains(got, want) {
+			t.Fatalf("wrong diags\n got: %s\nwant: %s", got, want)
+		}
+		if got.ViewType != ViewHuman {
+			t.Fatalf("wrong view type, got %#v, want %#v", got.ViewType, ViewHuman)
+		}
+	})
+}
diff --git a/v1.5.7/internal/command/arguments/default.go b/v1.5.7/internal/command/arguments/default.go
new file mode 100644
index 0000000..27626f7
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/default.go
@@ -0,0 +1,19 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"flag"
+	"io/ioutil"
+)
+
+// defaultFlagSet creates a FlagSet with the common settings to override
+// the flag package's noisy defaults.
+func defaultFlagSet(name string) *flag.FlagSet {
+	f := flag.NewFlagSet(name, flag.ContinueOnError)
+	f.SetOutput(ioutil.Discard)
+	f.Usage = func() {}
+
+	return f
+}
diff --git a/v1.5.7/internal/command/arguments/extended.go b/v1.5.7/internal/command/arguments/extended.go
new file mode 100644
index 0000000..a36e18b
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/extended.go
@@ -0,0 +1,245 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"flag"
+	"fmt"
+	"time"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// DefaultParallelism is the limit Terraform places on total parallel
+// operations as it walks the dependency graph.
+const DefaultParallelism = 10
+
+// State describes arguments which are used to define how Terraform interacts
+// with state.
+type State struct {
+	// Lock controls whether or not the state manager is used to lock state
+	// during operations.
+	Lock bool
+
+	// LockTimeout allows setting a time limit on acquiring the state lock.
+	// The default is 0, meaning no limit.
+	LockTimeout time.Duration
+
+	// StatePath specifies a non-default location for the state file. The
+	// default value is blank, which is interpeted as "terraform.tfstate".
+	StatePath string
+
+	// StateOutPath specifies a different path to write the final state file.
+	// The default value is blank, which results in state being written back to
+	// StatePath.
+	StateOutPath string
+
+	// BackupPath specifies the path where a backup copy of the state file will
+	// be stored before the new state is written. The default value is blank,
+	// which is interpreted as StateOutPath +
+	// ".backup".
+	BackupPath string
+}
+
+// Operation describes arguments which are used to configure how a Terraform
+// operation such as a plan or apply executes.
+type Operation struct {
+	// PlanMode selects one of the mutually-exclusive planning modes that
+	// decides the overall goal of a plan operation. This field is relevant
+	// only for an operation that produces a plan.
+	PlanMode plans.Mode
+
+	// Parallelism is the limit Terraform places on total parallel operations
+	// as it walks the dependency graph.
+	Parallelism int
+
+	// Refresh controls whether or not the operation should refresh existing
+	// state before proceeding. Default is true.
+	Refresh bool
+
+	// Targets allow limiting an operation to a set of resource addresses and
+	// their dependencies.
+	Targets []addrs.Targetable
+
+	// ForceReplace addresses cause Terraform to force a particular set of
+	// resource instances to generate "replace" actions in any plan where they
+	// would normally have generated "no-op" or "update" actions.
+	//
+	// This is currently limited to specific instances because typical uses
+	// of replace are associated with only specific remote objects that the
+	// user has somehow learned to be malfunctioning, in which case it
+	// would be unusual and potentially dangerous to replace everything under
+	// a module all at once. We could potentially loosen this later if we
+	// learn a use-case for broader matching.
+	ForceReplace []addrs.AbsResourceInstance
+
+	// These private fields are used only temporarily during decoding. Use
+	// method Parse to populate the exported fields from these, validating
+	// the raw values in the process.
+	targetsRaw      []string
+	forceReplaceRaw []string
+	destroyRaw      bool
+	refreshOnlyRaw  bool
+}
+
+// Parse must be called on Operation after initial flag parse. This processes
+// the raw target flags into addrs.Targetable values, returning diagnostics if
+// invalid.
+func (o *Operation) Parse() tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	o.Targets = nil
+
+	for _, tr := range o.targetsRaw {
+		traversal, syntaxDiags := hclsyntax.ParseTraversalAbs([]byte(tr), "", hcl.Pos{Line: 1, Column: 1})
+		if syntaxDiags.HasErrors() {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				fmt.Sprintf("Invalid target %q", tr),
+				syntaxDiags[0].Detail,
+			))
+			continue
+		}
+
+		target, targetDiags := addrs.ParseTarget(traversal)
+		if targetDiags.HasErrors() {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				fmt.Sprintf("Invalid target %q", tr),
+				targetDiags[0].Description().Detail,
+			))
+			continue
+		}
+
+		o.Targets = append(o.Targets, target.Subject)
+	}
+
+	for _, raw := range o.forceReplaceRaw {
+		traversal, syntaxDiags := hclsyntax.ParseTraversalAbs([]byte(raw), "", hcl.Pos{Line: 1, Column: 1})
+		if syntaxDiags.HasErrors() {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				fmt.Sprintf("Invalid force-replace address %q", raw),
+				syntaxDiags[0].Detail,
+			))
+			continue
+		}
+
+		addr, addrDiags := addrs.ParseAbsResourceInstance(traversal)
+		if addrDiags.HasErrors() {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				fmt.Sprintf("Invalid force-replace address %q", raw),
+				addrDiags[0].Description().Detail,
+			))
+			continue
+		}
+
+		if addr.Resource.Resource.Mode != addrs.ManagedResourceMode {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				fmt.Sprintf("Invalid force-replace address %q", raw),
+				"Only managed resources can be used with the -replace=... option.",
+			))
+			continue
+		}
+
+		o.ForceReplace = append(o.ForceReplace, addr)
+	}
+
+	// If you add a new possible value for o.PlanMode here, consider also
+	// adding a specialized error message for it in ParseApplyDestroy.
+	switch {
+	case o.destroyRaw && o.refreshOnlyRaw:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Incompatible plan mode options",
+			"The -destroy and -refresh-only options are mutually-exclusive.",
+		))
+	case o.destroyRaw:
+		o.PlanMode = plans.DestroyMode
+	case o.refreshOnlyRaw:
+		o.PlanMode = plans.RefreshOnlyMode
+		if !o.Refresh {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Incompatible refresh options",
+				"It doesn't make sense to use -refresh-only at the same time as -refresh=false, because Terraform would have nothing to do.",
+			))
+		}
+	default:
+		o.PlanMode = plans.NormalMode
+	}
+
+	return diags
+}
+
+// Vars describes arguments which specify non-default variable values. This
+// interfce is unfortunately obscure, because the order of the CLI arguments
+// determines the final value of the gathered variables. In future it might be
+// desirable for the arguments package to handle the gathering of variables
+// directly, returning a map of variable values.
+type Vars struct {
+	vars     *flagNameValueSlice
+	varFiles *flagNameValueSlice
+}
+
+func (v *Vars) All() []FlagNameValue {
+	if v.vars == nil {
+		return nil
+	}
+	return v.vars.AllItems()
+}
+
+func (v *Vars) Empty() bool {
+	if v.vars == nil {
+		return true
+	}
+	return v.vars.Empty()
+}
+
+// extendedFlagSet creates a FlagSet with common backend, operation, and vars
+// flags used in many commands. Target structs for each subset of flags must be
+// provided in order to support those flags.
+func extendedFlagSet(name string, state *State, operation *Operation, vars *Vars) *flag.FlagSet {
+	f := defaultFlagSet(name)
+
+	if state == nil && operation == nil && vars == nil {
+		panic("use defaultFlagSet")
+	}
+
+	if state != nil {
+		f.BoolVar(&state.Lock, "lock", true, "lock")
+		f.DurationVar(&state.LockTimeout, "lock-timeout", 0, "lock-timeout")
+		f.StringVar(&state.StatePath, "state", "", "state-path")
+		f.StringVar(&state.StateOutPath, "state-out", "", "state-path")
+		f.StringVar(&state.BackupPath, "backup", "", "backup-path")
+	}
+
+	if operation != nil {
+		f.IntVar(&operation.Parallelism, "parallelism", DefaultParallelism, "parallelism")
+		f.BoolVar(&operation.Refresh, "refresh", true, "refresh")
+		f.BoolVar(&operation.destroyRaw, "destroy", false, "destroy")
+		f.BoolVar(&operation.refreshOnlyRaw, "refresh-only", false, "refresh-only")
+		f.Var((*flagStringSlice)(&operation.targetsRaw), "target", "target")
+		f.Var((*flagStringSlice)(&operation.forceReplaceRaw), "replace", "replace")
+	}
+
+	// Gather all -var and -var-file arguments into one heterogenous structure
+	// to preserve the overall order.
+	if vars != nil {
+		varsFlags := newFlagNameValueSlice("-var")
+		varFilesFlags := varsFlags.Alias("-var-file")
+		vars.vars = &varsFlags
+		vars.varFiles = &varFilesFlags
+		f.Var(vars.vars, "var", "var")
+		f.Var(vars.varFiles, "var-file", "var-file")
+	}
+
+	return f
+}
diff --git a/v1.5.7/internal/command/arguments/flags.go b/v1.5.7/internal/command/arguments/flags.go
new file mode 100644
index 0000000..442037b
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/flags.go
@@ -0,0 +1,100 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"flag"
+	"fmt"
+)
+
+// flagStringSlice is a flag.Value implementation which allows collecting
+// multiple instances of a single flag into a slice. This is used for flags
+// such as -target=aws_instance.foo and -var x=y.
+type flagStringSlice []string
+
+var _ flag.Value = (*flagStringSlice)(nil)
+
+func (v *flagStringSlice) String() string {
+	return ""
+}
+func (v *flagStringSlice) Set(raw string) error {
+	*v = append(*v, raw)
+
+	return nil
+}
+
+// flagNameValueSlice is a flag.Value implementation that appends raw flag
+// names and values to a slice. This is used to collect a sequence of flags
+// with possibly different names, preserving the overall order.
+//
+// FIXME: this is a copy of rawFlags from command/meta_config.go, with the
+// eventual aim of replacing it altogether by gathering variables in the
+// arguments package.
+type flagNameValueSlice struct {
+	flagName string
+	items    *[]FlagNameValue
+}
+
+var _ flag.Value = flagNameValueSlice{}
+
+func newFlagNameValueSlice(flagName string) flagNameValueSlice {
+	var items []FlagNameValue
+	return flagNameValueSlice{
+		flagName: flagName,
+		items:    &items,
+	}
+}
+
+func (f flagNameValueSlice) Empty() bool {
+	if f.items == nil {
+		return true
+	}
+	return len(*f.items) == 0
+}
+
+func (f flagNameValueSlice) AllItems() []FlagNameValue {
+	if f.items == nil {
+		return nil
+	}
+	return *f.items
+}
+
+func (f flagNameValueSlice) Alias(flagName string) flagNameValueSlice {
+	return flagNameValueSlice{
+		flagName: flagName,
+		items:    f.items,
+	}
+}
+
+func (f flagNameValueSlice) String() string {
+	return ""
+}
+
+func (f flagNameValueSlice) Set(str string) error {
+	*f.items = append(*f.items, FlagNameValue{
+		Name:  f.flagName,
+		Value: str,
+	})
+	return nil
+}
+
+type FlagNameValue struct {
+	Name  string
+	Value string
+}
+
+func (f FlagNameValue) String() string {
+	return fmt.Sprintf("%s=%q", f.Name, f.Value)
+}
+
+// FlagIsSet returns whether a flag is explicitly set in a set of flags
+func FlagIsSet(flags *flag.FlagSet, name string) bool {
+	isSet := false
+	flags.Visit(func(f *flag.Flag) {
+		if f.Name == name {
+			isSet = true
+		}
+	})
+	return isSet
+}
diff --git a/v1.5.7/internal/command/arguments/output.go b/v1.5.7/internal/command/arguments/output.go
new file mode 100644
index 0000000..7b67420
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/output.go
@@ -0,0 +1,91 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Output represents the command-line arguments for the output command.
+type Output struct {
+	// Name identifies which root module output to show.  If empty, show all
+	// outputs.
+	Name string
+
+	// StatePath is an optional path to a state file, from which outputs will
+	// be loaded.
+	StatePath string
+
+	// ViewType specifies which output format to use: human, JSON, or "raw".
+	ViewType ViewType
+}
+
+// ParseOutput processes CLI arguments, returning an Output value and errors.
+// If errors are encountered, an Output value is still returned representing
+// the best effort interpretation of the arguments.
+func ParseOutput(args []string) (*Output, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	output := &Output{}
+
+	var jsonOutput, rawOutput bool
+	var statePath string
+	cmdFlags := defaultFlagSet("output")
+	cmdFlags.BoolVar(&jsonOutput, "json", false, "json")
+	cmdFlags.BoolVar(&rawOutput, "raw", false, "raw")
+	cmdFlags.StringVar(&statePath, "state", "", "path")
+
+	if err := cmdFlags.Parse(args); err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to parse command-line flags",
+			err.Error(),
+		))
+	}
+
+	args = cmdFlags.Args()
+	if len(args) > 1 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Unexpected argument",
+			"The output command expects exactly one argument with the name of an output variable or no arguments to show all outputs.",
+		))
+	}
+
+	if jsonOutput && rawOutput {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid output format",
+			"The -raw and -json options are mutually-exclusive.",
+		))
+
+		// Since the desired output format is unknowable, fall back to default
+		jsonOutput = false
+		rawOutput = false
+	}
+
+	output.StatePath = statePath
+
+	if len(args) > 0 {
+		output.Name = args[0]
+	}
+
+	if rawOutput && output.Name == "" {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Output name required",
+			"You must give the name of a single output value when using the -raw option.",
+		))
+	}
+
+	switch {
+	case jsonOutput:
+		output.ViewType = ViewJSON
+	case rawOutput:
+		output.ViewType = ViewRaw
+	default:
+		output.ViewType = ViewHuman
+	}
+
+	return output, diags
+}
diff --git a/v1.5.7/internal/command/arguments/output_test.go b/v1.5.7/internal/command/arguments/output_test.go
new file mode 100644
index 0000000..c3cebb7
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/output_test.go
@@ -0,0 +1,145 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestParseOutput_valid(t *testing.T) {
+	testCases := map[string]struct {
+		args []string
+		want *Output
+	}{
+		"defaults": {
+			nil,
+			&Output{
+				Name:      "",
+				ViewType:  ViewHuman,
+				StatePath: "",
+			},
+		},
+		"json": {
+			[]string{"-json"},
+			&Output{
+				Name:      "",
+				ViewType:  ViewJSON,
+				StatePath: "",
+			},
+		},
+		"raw": {
+			[]string{"-raw", "foo"},
+			&Output{
+				Name:      "foo",
+				ViewType:  ViewRaw,
+				StatePath: "",
+			},
+		},
+		"state": {
+			[]string{"-state=foobar.tfstate", "-raw", "foo"},
+			&Output{
+				Name:      "foo",
+				ViewType:  ViewRaw,
+				StatePath: "foobar.tfstate",
+			},
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, diags := ParseOutput(tc.args)
+			if len(diags) > 0 {
+				t.Fatalf("unexpected diags: %v", diags)
+			}
+			if *got != *tc.want {
+				t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
+			}
+		})
+	}
+}
+
+func TestParseOutput_invalid(t *testing.T) {
+	testCases := map[string]struct {
+		args      []string
+		want      *Output
+		wantDiags tfdiags.Diagnostics
+	}{
+		"unknown flag": {
+			[]string{"-boop"},
+			&Output{
+				Name:      "",
+				ViewType:  ViewHuman,
+				StatePath: "",
+			},
+			tfdiags.Diagnostics{
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to parse command-line flags",
+					"flag provided but not defined: -boop",
+				),
+			},
+		},
+		"json and raw specified": {
+			[]string{"-json", "-raw"},
+			&Output{
+				Name:      "",
+				ViewType:  ViewHuman,
+				StatePath: "",
+			},
+			tfdiags.Diagnostics{
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid output format",
+					"The -raw and -json options are mutually-exclusive.",
+				),
+			},
+		},
+		"raw with no name": {
+			[]string{"-raw"},
+			&Output{
+				Name:      "",
+				ViewType:  ViewRaw,
+				StatePath: "",
+			},
+			tfdiags.Diagnostics{
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Output name required",
+					"You must give the name of a single output value when using the -raw option.",
+				),
+			},
+		},
+		"too many arguments": {
+			[]string{"-raw", "-state=foo.tfstate", "bar", "baz"},
+			&Output{
+				Name:      "bar",
+				ViewType:  ViewRaw,
+				StatePath: "foo.tfstate",
+			},
+			tfdiags.Diagnostics{
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Unexpected argument",
+					"The output command expects exactly one argument with the name of an output variable or no arguments to show all outputs.",
+				),
+			},
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, gotDiags := ParseOutput(tc.args)
+			if *got != *tc.want {
+				t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
+			}
+			if !reflect.DeepEqual(gotDiags, tc.wantDiags) {
+				t.Errorf("wrong result\ngot: %s\nwant: %s", spew.Sdump(gotDiags), spew.Sdump(tc.wantDiags))
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/arguments/plan.go b/v1.5.7/internal/command/arguments/plan.go
new file mode 100644
index 0000000..1b7b092
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/plan.go
@@ -0,0 +1,90 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Plan represents the command-line arguments for the plan command.
+type Plan struct {
+	// State, Operation, and Vars are the common extended flags
+	State     *State
+	Operation *Operation
+	Vars      *Vars
+
+	// DetailedExitCode enables different exit codes for error, success with
+	// changes, and success with no changes.
+	DetailedExitCode bool
+
+	// InputEnabled is used to disable interactive input for unspecified
+	// variable and backend config values. Default is true.
+	InputEnabled bool
+
+	// OutPath contains an optional path to store the plan file
+	OutPath string
+
+	// GenerateConfigPath tells Terraform that config should be generated for
+	// unmatched import target paths and which path the generated file should
+	// be written to.
+	GenerateConfigPath string
+
+	// ViewType specifies which output format to use
+	ViewType ViewType
+}
+
+// ParsePlan processes CLI arguments, returning a Plan value and errors.
+// If errors are encountered, a Plan value is still returned representing
+// the best effort interpretation of the arguments.
+func ParsePlan(args []string) (*Plan, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	plan := &Plan{
+		State:     &State{},
+		Operation: &Operation{},
+		Vars:      &Vars{},
+	}
+
+	cmdFlags := extendedFlagSet("plan", plan.State, plan.Operation, plan.Vars)
+	cmdFlags.BoolVar(&plan.DetailedExitCode, "detailed-exitcode", false, "detailed-exitcode")
+	cmdFlags.BoolVar(&plan.InputEnabled, "input", true, "input")
+	cmdFlags.StringVar(&plan.OutPath, "out", "", "out")
+	cmdFlags.StringVar(&plan.GenerateConfigPath, "generate-config-out", "", "generate-config-out")
+
+	var json bool
+	cmdFlags.BoolVar(&json, "json", false, "json")
+
+	if err := cmdFlags.Parse(args); err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to parse command-line flags",
+			err.Error(),
+		))
+	}
+
+	args = cmdFlags.Args()
+
+	if len(args) > 0 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Too many command line arguments",
+			"To specify a working directory for the plan, use the global -chdir flag.",
+		))
+	}
+
+	diags = diags.Append(plan.Operation.Parse())
+
+	// JSON view currently does not support input, so we disable it here
+	if json {
+		plan.InputEnabled = false
+	}
+
+	switch {
+	case json:
+		plan.ViewType = ViewJSON
+	default:
+		plan.ViewType = ViewHuman
+	}
+
+	return plan, diags
+}
diff --git a/v1.5.7/internal/command/arguments/plan_test.go b/v1.5.7/internal/command/arguments/plan_test.go
new file mode 100644
index 0000000..60b9c20
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/plan_test.go
@@ -0,0 +1,210 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+func TestParsePlan_basicValid(t *testing.T) {
+	testCases := map[string]struct {
+		args []string
+		want *Plan
+	}{
+		"defaults": {
+			nil,
+			&Plan{
+				DetailedExitCode: false,
+				InputEnabled:     true,
+				OutPath:          "",
+				ViewType:         ViewHuman,
+				State:            &State{Lock: true},
+				Vars:             &Vars{},
+				Operation: &Operation{
+					PlanMode:    plans.NormalMode,
+					Parallelism: 10,
+					Refresh:     true,
+				},
+			},
+		},
+		"setting all options": {
+			[]string{"-destroy", "-detailed-exitcode", "-input=false", "-out=saved.tfplan"},
+			&Plan{
+				DetailedExitCode: true,
+				InputEnabled:     false,
+				OutPath:          "saved.tfplan",
+				ViewType:         ViewHuman,
+				State:            &State{Lock: true},
+				Vars:             &Vars{},
+				Operation: &Operation{
+					PlanMode:    plans.DestroyMode,
+					Parallelism: 10,
+					Refresh:     true,
+				},
+			},
+		},
+		"JSON view disables input": {
+			[]string{"-json"},
+			&Plan{
+				DetailedExitCode: false,
+				InputEnabled:     false,
+				OutPath:          "",
+				ViewType:         ViewJSON,
+				State:            &State{Lock: true},
+				Vars:             &Vars{},
+				Operation: &Operation{
+					PlanMode:    plans.NormalMode,
+					Parallelism: 10,
+					Refresh:     true,
+				},
+			},
+		},
+	}
+
+	cmpOpts := cmpopts.IgnoreUnexported(Operation{}, Vars{}, State{})
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, diags := ParsePlan(tc.args)
+			if len(diags) > 0 {
+				t.Fatalf("unexpected diags: %v", diags)
+			}
+			if diff := cmp.Diff(tc.want, got, cmpOpts); diff != "" {
+				t.Errorf("unexpected result\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestParsePlan_invalid(t *testing.T) {
+	got, diags := ParsePlan([]string{"-frob"})
+	if len(diags) == 0 {
+		t.Fatal("expected diags but got none")
+	}
+	if got, want := diags.Err().Error(), "flag provided but not defined"; !strings.Contains(got, want) {
+		t.Fatalf("wrong diags\n got: %s\nwant: %s", got, want)
+	}
+	if got.ViewType != ViewHuman {
+		t.Fatalf("wrong view type, got %#v, want %#v", got.ViewType, ViewHuman)
+	}
+}
+
+func TestParsePlan_tooManyArguments(t *testing.T) {
+	got, diags := ParsePlan([]string{"saved.tfplan"})
+	if len(diags) == 0 {
+		t.Fatal("expected diags but got none")
+	}
+	if got, want := diags.Err().Error(), "Too many command line arguments"; !strings.Contains(got, want) {
+		t.Fatalf("wrong diags\n got: %s\nwant: %s", got, want)
+	}
+	if got.ViewType != ViewHuman {
+		t.Fatalf("wrong view type, got %#v, want %#v", got.ViewType, ViewHuman)
+	}
+}
+
+func TestParsePlan_targets(t *testing.T) {
+	foobarbaz, _ := addrs.ParseTargetStr("foo_bar.baz")
+	boop, _ := addrs.ParseTargetStr("module.boop")
+	testCases := map[string]struct {
+		args    []string
+		want    []addrs.Targetable
+		wantErr string
+	}{
+		"no targets by default": {
+			args: nil,
+			want: nil,
+		},
+		"one target": {
+			args: []string{"-target=foo_bar.baz"},
+			want: []addrs.Targetable{foobarbaz.Subject},
+		},
+		"two targets": {
+			args: []string{"-target=foo_bar.baz", "-target", "module.boop"},
+			want: []addrs.Targetable{foobarbaz.Subject, boop.Subject},
+		},
+		"invalid traversal": {
+			args:    []string{"-target=foo."},
+			want:    nil,
+			wantErr: "Dot must be followed by attribute name",
+		},
+		"invalid target": {
+			args:    []string{"-target=data[0].foo"},
+			want:    nil,
+			wantErr: "A data source name is required",
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, diags := ParsePlan(tc.args)
+			if len(diags) > 0 {
+				if tc.wantErr == "" {
+					t.Fatalf("unexpected diags: %v", diags)
+				} else if got := diags.Err().Error(); !strings.Contains(got, tc.wantErr) {
+					t.Fatalf("wrong diags\n got: %s\nwant: %s", got, tc.wantErr)
+				}
+			}
+			if !cmp.Equal(got.Operation.Targets, tc.want) {
+				t.Fatalf("unexpected result\n%s", cmp.Diff(got.Operation.Targets, tc.want))
+			}
+		})
+	}
+}
+
+func TestParsePlan_vars(t *testing.T) {
+	testCases := map[string]struct {
+		args []string
+		want []FlagNameValue
+	}{
+		"no var flags by default": {
+			args: nil,
+			want: nil,
+		},
+		"one var": {
+			args: []string{"-var", "foo=bar"},
+			want: []FlagNameValue{
+				{Name: "-var", Value: "foo=bar"},
+			},
+		},
+		"one var-file": {
+			args: []string{"-var-file", "cool.tfvars"},
+			want: []FlagNameValue{
+				{Name: "-var-file", Value: "cool.tfvars"},
+			},
+		},
+		"ordering preserved": {
+			args: []string{
+				"-var", "foo=bar",
+				"-var-file", "cool.tfvars",
+				"-var", "boop=beep",
+			},
+			want: []FlagNameValue{
+				{Name: "-var", Value: "foo=bar"},
+				{Name: "-var-file", Value: "cool.tfvars"},
+				{Name: "-var", Value: "boop=beep"},
+			},
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, diags := ParsePlan(tc.args)
+			if len(diags) > 0 {
+				t.Fatalf("unexpected diags: %v", diags)
+			}
+			if vars := got.Vars.All(); !cmp.Equal(vars, tc.want) {
+				t.Fatalf("unexpected result\n%s", cmp.Diff(vars, tc.want))
+			}
+			if got, want := got.Vars.Empty(), len(tc.want) == 0; got != want {
+				t.Fatalf("expected Empty() to return %t, but was %t", want, got)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/arguments/refresh.go b/v1.5.7/internal/command/arguments/refresh.go
new file mode 100644
index 0000000..30819ed
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/refresh.go
@@ -0,0 +1,74 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Refresh represents the command-line arguments for the apply command.
+type Refresh struct {
+	// State, Operation, and Vars are the common extended flags
+	State     *State
+	Operation *Operation
+	Vars      *Vars
+
+	// InputEnabled is used to disable interactive input for unspecified
+	// variable and backend config values. Default is true.
+	InputEnabled bool
+
+	// ViewType specifies which output format to use
+	ViewType ViewType
+}
+
+// ParseRefresh processes CLI arguments, returning a Refresh value and errors.
+// If errors are encountered, a Refresh value is still returned representing
+// the best effort interpretation of the arguments.
+func ParseRefresh(args []string) (*Refresh, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	refresh := &Refresh{
+		State:     &State{},
+		Operation: &Operation{},
+		Vars:      &Vars{},
+	}
+
+	cmdFlags := extendedFlagSet("refresh", refresh.State, refresh.Operation, refresh.Vars)
+	cmdFlags.BoolVar(&refresh.InputEnabled, "input", true, "input")
+
+	var json bool
+	cmdFlags.BoolVar(&json, "json", false, "json")
+
+	if err := cmdFlags.Parse(args); err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to parse command-line flags",
+			err.Error(),
+		))
+	}
+
+	args = cmdFlags.Args()
+	if len(args) > 0 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Too many command line arguments",
+			"Expected at most one positional argument.",
+		))
+	}
+
+	diags = diags.Append(refresh.Operation.Parse())
+
+	// JSON view currently does not support input, so we disable it here
+	if json {
+		refresh.InputEnabled = false
+	}
+
+	switch {
+	case json:
+		refresh.ViewType = ViewJSON
+	default:
+		refresh.ViewType = ViewHuman
+	}
+
+	return refresh, diags
+}
diff --git a/v1.5.7/internal/command/arguments/refresh_test.go b/v1.5.7/internal/command/arguments/refresh_test.go
new file mode 100644
index 0000000..fab1d37
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/refresh_test.go
@@ -0,0 +1,183 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestParseRefresh_basicValid(t *testing.T) {
+	testCases := map[string]struct {
+		args []string
+		want *Refresh
+	}{
+		"defaults": {
+			nil,
+			&Refresh{
+				InputEnabled: true,
+				ViewType:     ViewHuman,
+			},
+		},
+		"input=false": {
+			[]string{"-input=false"},
+			&Refresh{
+				InputEnabled: false,
+				ViewType:     ViewHuman,
+			},
+		},
+		"JSON view disables input": {
+			[]string{"-json"},
+			&Refresh{
+				InputEnabled: false,
+				ViewType:     ViewJSON,
+			},
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, diags := ParseRefresh(tc.args)
+			if len(diags) > 0 {
+				t.Fatalf("unexpected diags: %v", diags)
+			}
+			// Ignore the extended arguments for simplicity
+			got.State = nil
+			got.Operation = nil
+			got.Vars = nil
+			if *got != *tc.want {
+				t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
+			}
+		})
+	}
+}
+
+func TestParseRefresh_invalid(t *testing.T) {
+	got, diags := ParseRefresh([]string{"-frob"})
+	if len(diags) == 0 {
+		t.Fatal("expected diags but got none")
+	}
+	if got, want := diags.Err().Error(), "flag provided but not defined"; !strings.Contains(got, want) {
+		t.Fatalf("wrong diags\n got: %s\nwant: %s", got, want)
+	}
+	if got.ViewType != ViewHuman {
+		t.Fatalf("wrong view type, got %#v, want %#v", got.ViewType, ViewHuman)
+	}
+}
+
+func TestParseRefresh_tooManyArguments(t *testing.T) {
+	got, diags := ParseRefresh([]string{"saved.tfplan"})
+	if len(diags) == 0 {
+		t.Fatal("expected diags but got none")
+	}
+	if got, want := diags.Err().Error(), "Too many command line arguments"; !strings.Contains(got, want) {
+		t.Fatalf("wrong diags\n got: %s\nwant: %s", got, want)
+	}
+	if got.ViewType != ViewHuman {
+		t.Fatalf("wrong view type, got %#v, want %#v", got.ViewType, ViewHuman)
+	}
+}
+
+func TestParseRefresh_targets(t *testing.T) {
+	foobarbaz, _ := addrs.ParseTargetStr("foo_bar.baz")
+	boop, _ := addrs.ParseTargetStr("module.boop")
+	testCases := map[string]struct {
+		args    []string
+		want    []addrs.Targetable
+		wantErr string
+	}{
+		"no targets by default": {
+			args: nil,
+			want: nil,
+		},
+		"one target": {
+			args: []string{"-target=foo_bar.baz"},
+			want: []addrs.Targetable{foobarbaz.Subject},
+		},
+		"two targets": {
+			args: []string{"-target=foo_bar.baz", "-target", "module.boop"},
+			want: []addrs.Targetable{foobarbaz.Subject, boop.Subject},
+		},
+		"invalid traversal": {
+			args:    []string{"-target=foo."},
+			want:    nil,
+			wantErr: "Dot must be followed by attribute name",
+		},
+		"invalid target": {
+			args:    []string{"-target=data[0].foo"},
+			want:    nil,
+			wantErr: "A data source name is required",
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, diags := ParseRefresh(tc.args)
+			if len(diags) > 0 {
+				if tc.wantErr == "" {
+					t.Fatalf("unexpected diags: %v", diags)
+				} else if got := diags.Err().Error(); !strings.Contains(got, tc.wantErr) {
+					t.Fatalf("wrong diags\n got: %s\nwant: %s", got, tc.wantErr)
+				}
+			}
+			if !cmp.Equal(got.Operation.Targets, tc.want) {
+				t.Fatalf("unexpected result\n%s", cmp.Diff(got.Operation.Targets, tc.want))
+			}
+		})
+	}
+}
+
+func TestParseRefresh_vars(t *testing.T) {
+	testCases := map[string]struct {
+		args []string
+		want []FlagNameValue
+	}{
+		"no var flags by default": {
+			args: nil,
+			want: nil,
+		},
+		"one var": {
+			args: []string{"-var", "foo=bar"},
+			want: []FlagNameValue{
+				{Name: "-var", Value: "foo=bar"},
+			},
+		},
+		"one var-file": {
+			args: []string{"-var-file", "cool.tfvars"},
+			want: []FlagNameValue{
+				{Name: "-var-file", Value: "cool.tfvars"},
+			},
+		},
+		"ordering preserved": {
+			args: []string{
+				"-var", "foo=bar",
+				"-var-file", "cool.tfvars",
+				"-var", "boop=beep",
+			},
+			want: []FlagNameValue{
+				{Name: "-var", Value: "foo=bar"},
+				{Name: "-var-file", Value: "cool.tfvars"},
+				{Name: "-var", Value: "boop=beep"},
+			},
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, diags := ParseRefresh(tc.args)
+			if len(diags) > 0 {
+				t.Fatalf("unexpected diags: %v", diags)
+			}
+			if vars := got.Vars.All(); !cmp.Equal(vars, tc.want) {
+				t.Fatalf("unexpected result\n%s", cmp.Diff(vars, tc.want))
+			}
+			if got, want := got.Vars.Empty(), len(tc.want) == 0; got != want {
+				t.Fatalf("expected Empty() to return %t, but was %t", want, got)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/arguments/show.go b/v1.5.7/internal/command/arguments/show.go
new file mode 100644
index 0000000..fa644a2
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/show.go
@@ -0,0 +1,62 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Show represents the command-line arguments for the show command.
+type Show struct {
+	// Path is the path to the state file or plan file to be displayed. If
+	// unspecified, show will display the latest state snapshot.
+	Path string
+
+	// ViewType specifies which output format to use: human, JSON, or "raw".
+	ViewType ViewType
+}
+
+// ParseShow processes CLI arguments, returning a Show value and errors.
+// If errors are encountered, a Show value is still returned representing
+// the best effort interpretation of the arguments.
+func ParseShow(args []string) (*Show, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	show := &Show{
+		Path: "",
+	}
+
+	var jsonOutput bool
+	cmdFlags := defaultFlagSet("show")
+	cmdFlags.BoolVar(&jsonOutput, "json", false, "json")
+
+	if err := cmdFlags.Parse(args); err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to parse command-line flags",
+			err.Error(),
+		))
+	}
+
+	args = cmdFlags.Args()
+	if len(args) > 1 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Too many command line arguments",
+			"Expected at most one positional argument.",
+		))
+	}
+
+	if len(args) > 0 {
+		show.Path = args[0]
+	}
+
+	switch {
+	case jsonOutput:
+		show.ViewType = ViewJSON
+	default:
+		show.ViewType = ViewHuman
+	}
+
+	return show, diags
+}
diff --git a/v1.5.7/internal/command/arguments/show_test.go b/v1.5.7/internal/command/arguments/show_test.go
new file mode 100644
index 0000000..11c6ac8
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/show_test.go
@@ -0,0 +1,102 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestParseShow_valid(t *testing.T) {
+	testCases := map[string]struct {
+		args []string
+		want *Show
+	}{
+		"defaults": {
+			nil,
+			&Show{
+				Path:     "",
+				ViewType: ViewHuman,
+			},
+		},
+		"json": {
+			[]string{"-json"},
+			&Show{
+				Path:     "",
+				ViewType: ViewJSON,
+			},
+		},
+		"path": {
+			[]string{"-json", "foo"},
+			&Show{
+				Path:     "foo",
+				ViewType: ViewJSON,
+			},
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, diags := ParseShow(tc.args)
+			if len(diags) > 0 {
+				t.Fatalf("unexpected diags: %v", diags)
+			}
+			if *got != *tc.want {
+				t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
+			}
+		})
+	}
+}
+
+func TestParseShow_invalid(t *testing.T) {
+	testCases := map[string]struct {
+		args      []string
+		want      *Show
+		wantDiags tfdiags.Diagnostics
+	}{
+		"unknown flag": {
+			[]string{"-boop"},
+			&Show{
+				Path:     "",
+				ViewType: ViewHuman,
+			},
+			tfdiags.Diagnostics{
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to parse command-line flags",
+					"flag provided but not defined: -boop",
+				),
+			},
+		},
+		"too many arguments": {
+			[]string{"-json", "bar", "baz"},
+			&Show{
+				Path:     "bar",
+				ViewType: ViewJSON,
+			},
+			tfdiags.Diagnostics{
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Too many command line arguments",
+					"Expected at most one positional argument.",
+				),
+			},
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, gotDiags := ParseShow(tc.args)
+			if *got != *tc.want {
+				t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
+			}
+			if !reflect.DeepEqual(gotDiags, tc.wantDiags) {
+				t.Errorf("wrong result\ngot: %s\nwant: %s", spew.Sdump(gotDiags), spew.Sdump(tc.wantDiags))
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/arguments/test.go b/v1.5.7/internal/command/arguments/test.go
new file mode 100644
index 0000000..f7427a3
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/test.go
@@ -0,0 +1,66 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"flag"
+	"io/ioutil"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Test represents the command line arguments for the "terraform test" command.
+type Test struct {
+	Output TestOutput
+}
+
+// TestOutput represents a subset of the arguments for "terraform test"
+// related to how it presents its results. That is, it's the arguments that
+// are relevant to the command's view rather than its controller.
+type TestOutput struct {
+	// If not an empty string, JUnitXMLFile gives a filename where JUnit-style
+	// XML test result output should be written, in addition to the normal
+	// output printed to the standard output and error streams.
+	// (The typical usage pattern for tools that can consume this file format
+	// is to configure them to look for a separate test result file on disk
+	// after running the tests.)
+	JUnitXMLFile string
+}
+
+// ParseTest interprets a slice of raw command line arguments into a
+// Test value.
+func ParseTest(args []string) (Test, tfdiags.Diagnostics) {
+	var ret Test
+	var diags tfdiags.Diagnostics
+
+	// NOTE: ParseTest should still return at least a partial
+	// Test even on error, containing enough information for the
+	// command to report error diagnostics in a suitable way.
+
+	f := flag.NewFlagSet("test", flag.ContinueOnError)
+	f.SetOutput(ioutil.Discard)
+	f.Usage = func() {}
+	f.StringVar(&ret.Output.JUnitXMLFile, "junit-xml", "", "Write a JUnit XML file describing the results")
+
+	err := f.Parse(args)
+	if err != nil {
+		diags = diags.Append(err)
+		return ret, diags
+	}
+
+	// We'll now discard all of the arguments that the flag package handled,
+	// and focus only on the positional arguments for the rest of the function.
+	args = f.Args()
+
+	if len(args) != 0 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid command arguments",
+			"The test command doesn't expect any positional command-line arguments.",
+		))
+		return ret, diags
+	}
+
+	return ret, diags
+}
diff --git a/v1.5.7/internal/command/arguments/test_test.go b/v1.5.7/internal/command/arguments/test_test.go
new file mode 100644
index 0000000..06500d0
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/test_test.go
@@ -0,0 +1,86 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"testing"
+
+	"github.com/apparentlymart/go-shquot/shquot"
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestParseTest(t *testing.T) {
+	tests := []struct {
+		Input     []string
+		Want      Test
+		WantError string
+	}{
+		{
+			nil,
+			Test{
+				Output: TestOutput{
+					JUnitXMLFile: "",
+				},
+			},
+			``,
+		},
+		{
+			[]string{"-invalid"},
+			Test{
+				Output: TestOutput{
+					JUnitXMLFile: "",
+				},
+			},
+			`flag provided but not defined: -invalid`,
+		},
+		{
+			[]string{"-junit-xml=result.xml"},
+			Test{
+				Output: TestOutput{
+					JUnitXMLFile: "result.xml",
+				},
+			},
+			``,
+		},
+		{
+			[]string{"baz"},
+			Test{
+				Output: TestOutput{
+					JUnitXMLFile: "",
+				},
+			},
+			`Invalid command arguments`,
+		},
+	}
+
+	baseCmdline := []string{"terraform", "test"}
+	for _, test := range tests {
+		name := shquot.POSIXShell(append(baseCmdline, test.Input...))
+		t.Run(name, func(t *testing.T) {
+			t.Log(name)
+			got, diags := ParseTest(test.Input)
+
+			if test.WantError != "" {
+				if len(diags) != 1 {
+					t.Fatalf("got %d diagnostics; want exactly 1\n%s", len(diags), diags.Err().Error())
+				}
+				if diags[0].Severity() != tfdiags.Error {
+					t.Fatalf("got a warning; want an error\n%s", diags.Err().Error())
+				}
+				if desc := diags[0].Description(); desc.Summary != test.WantError {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", desc.Summary, test.WantError)
+				}
+			} else {
+				if len(diags) != 0 {
+					t.Fatalf("got %d diagnostics; want none\n%s", len(diags), diags.Err().Error())
+				}
+			}
+
+			if diff := cmp.Diff(test.Want, got); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/arguments/types.go b/v1.5.7/internal/command/arguments/types.go
new file mode 100644
index 0000000..183a123
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/types.go
@@ -0,0 +1,31 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+// ViewType represents which view layer to use for a given command. Not all
+// commands will support all view types, and validation that the type is
+// supported should happen in the view constructor.
+type ViewType rune
+
+const (
+	ViewNone  ViewType = 0
+	ViewHuman ViewType = 'H'
+	ViewJSON  ViewType = 'J'
+	ViewRaw   ViewType = 'R'
+)
+
+func (vt ViewType) String() string {
+	switch vt {
+	case ViewNone:
+		return "none"
+	case ViewHuman:
+		return "human"
+	case ViewJSON:
+		return "json"
+	case ViewRaw:
+		return "raw"
+	default:
+		return "unknown"
+	}
+}
diff --git a/v1.5.7/internal/command/arguments/validate.go b/v1.5.7/internal/command/arguments/validate.go
new file mode 100644
index 0000000..f08d5e6
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/validate.go
@@ -0,0 +1,62 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Validate represents the command-line arguments for the validate command.
+type Validate struct {
+	// Path is the directory containing the configuration to be validated. If
+	// unspecified, validate will use the current directory.
+	Path string
+
+	// ViewType specifies which output format to use: human, JSON, or "raw".
+	ViewType ViewType
+}
+
+// ParseValidate processes CLI arguments, returning a Validate value and errors.
+// If errors are encountered, a Validate value is still returned representing
+// the best effort interpretation of the arguments.
+func ParseValidate(args []string) (*Validate, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	validate := &Validate{
+		Path: ".",
+	}
+
+	var jsonOutput bool
+	cmdFlags := defaultFlagSet("validate")
+	cmdFlags.BoolVar(&jsonOutput, "json", false, "json")
+
+	if err := cmdFlags.Parse(args); err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to parse command-line flags",
+			err.Error(),
+		))
+	}
+
+	args = cmdFlags.Args()
+	if len(args) > 1 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Too many command line arguments",
+			"Expected at most one positional argument.",
+		))
+	}
+
+	if len(args) > 0 {
+		validate.Path = args[0]
+	}
+
+	switch {
+	case jsonOutput:
+		validate.ViewType = ViewJSON
+	default:
+		validate.ViewType = ViewHuman
+	}
+
+	return validate, diags
+}
diff --git a/v1.5.7/internal/command/arguments/validate_test.go b/v1.5.7/internal/command/arguments/validate_test.go
new file mode 100644
index 0000000..65a63b9
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/validate_test.go
@@ -0,0 +1,102 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestParseValidate_valid(t *testing.T) {
+	testCases := map[string]struct {
+		args []string
+		want *Validate
+	}{
+		"defaults": {
+			nil,
+			&Validate{
+				Path:     ".",
+				ViewType: ViewHuman,
+			},
+		},
+		"json": {
+			[]string{"-json"},
+			&Validate{
+				Path:     ".",
+				ViewType: ViewJSON,
+			},
+		},
+		"path": {
+			[]string{"-json", "foo"},
+			&Validate{
+				Path:     "foo",
+				ViewType: ViewJSON,
+			},
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, diags := ParseValidate(tc.args)
+			if len(diags) > 0 {
+				t.Fatalf("unexpected diags: %v", diags)
+			}
+			if *got != *tc.want {
+				t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
+			}
+		})
+	}
+}
+
+func TestParseValidate_invalid(t *testing.T) {
+	testCases := map[string]struct {
+		args      []string
+		want      *Validate
+		wantDiags tfdiags.Diagnostics
+	}{
+		"unknown flag": {
+			[]string{"-boop"},
+			&Validate{
+				Path:     ".",
+				ViewType: ViewHuman,
+			},
+			tfdiags.Diagnostics{
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to parse command-line flags",
+					"flag provided but not defined: -boop",
+				),
+			},
+		},
+		"too many arguments": {
+			[]string{"-json", "bar", "baz"},
+			&Validate{
+				Path:     "bar",
+				ViewType: ViewJSON,
+			},
+			tfdiags.Diagnostics{
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Too many command line arguments",
+					"Expected at most one positional argument.",
+				),
+			},
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, gotDiags := ParseValidate(tc.args)
+			if *got != *tc.want {
+				t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
+			}
+			if !reflect.DeepEqual(gotDiags, tc.wantDiags) {
+				t.Errorf("wrong result\ngot: %s\nwant: %s", spew.Sdump(gotDiags), spew.Sdump(tc.wantDiags))
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/arguments/view.go b/v1.5.7/internal/command/arguments/view.go
new file mode 100644
index 0000000..2eee63e
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/view.go
@@ -0,0 +1,46 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+// View represents the global command-line arguments which configure the view.
+type View struct {
+	// NoColor is used to disable the use of terminal color codes in all
+	// output.
+	NoColor bool
+
+	// CompactWarnings is used to coalesce duplicate warnings, to reduce the
+	// level of noise when multiple instances of the same warning are raised
+	// for a configuration.
+	CompactWarnings bool
+}
+
+// ParseView processes CLI arguments, returning a View value and a
+// possibly-modified slice of arguments. If any of the supported flags are
+// found, they will be removed from the slice.
+func ParseView(args []string) (*View, []string) {
+	common := &View{}
+
+	// Keep track of the length of the returned slice. When we find an
+	// argument we support, i will not be incremented.
+	i := 0
+	for _, v := range args {
+		switch v {
+		case "-no-color":
+			common.NoColor = true
+		case "-compact-warnings":
+			common.CompactWarnings = true
+		default:
+			// Unsupported argument: move left to the current position, and
+			// increment the index.
+			args[i] = v
+			i++
+		}
+	}
+
+	// Reduce the slice to the number of unsupported arguments. Any remaining
+	// to the right of i have already been moved left.
+	args = args[:i]
+
+	return common, args
+}
diff --git a/v1.5.7/internal/command/arguments/view_test.go b/v1.5.7/internal/command/arguments/view_test.go
new file mode 100644
index 0000000..0a33bac
--- /dev/null
+++ b/v1.5.7/internal/command/arguments/view_test.go
@@ -0,0 +1,65 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package arguments
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+)
+
+func TestParseView(t *testing.T) {
+	testCases := map[string]struct {
+		args     []string
+		want     *View
+		wantArgs []string
+	}{
+		"nil": {
+			nil,
+			&View{NoColor: false, CompactWarnings: false},
+			nil,
+		},
+		"empty": {
+			[]string{},
+			&View{NoColor: false, CompactWarnings: false},
+			[]string{},
+		},
+		"none matching": {
+			[]string{"-foo", "bar", "-baz"},
+			&View{NoColor: false, CompactWarnings: false},
+			[]string{"-foo", "bar", "-baz"},
+		},
+		"no-color": {
+			[]string{"-foo", "-no-color", "-baz"},
+			&View{NoColor: true, CompactWarnings: false},
+			[]string{"-foo", "-baz"},
+		},
+		"compact-warnings": {
+			[]string{"-foo", "-compact-warnings", "-baz"},
+			&View{NoColor: false, CompactWarnings: true},
+			[]string{"-foo", "-baz"},
+		},
+		"both": {
+			[]string{"-foo", "-no-color", "-compact-warnings", "-baz"},
+			&View{NoColor: true, CompactWarnings: true},
+			[]string{"-foo", "-baz"},
+		},
+		"both, resulting in empty args": {
+			[]string{"-no-color", "-compact-warnings"},
+			&View{NoColor: true, CompactWarnings: true},
+			[]string{},
+		},
+	}
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got, gotArgs := ParseView(tc.args)
+			if *got != *tc.want {
+				t.Errorf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
+			}
+			if !cmp.Equal(gotArgs, tc.wantArgs) {
+				t.Errorf("unexpected args\n got: %#v\nwant: %#v", gotArgs, tc.wantArgs)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/autocomplete.go b/v1.5.7/internal/command/autocomplete.go
new file mode 100644
index 0000000..766379e
--- /dev/null
+++ b/v1.5.7/internal/command/autocomplete.go
@@ -0,0 +1,66 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"github.com/posener/complete"
+)
+
+// This file contains some re-usable predictors for auto-complete. The
+// command-specific autocomplete configurations live within each command's
+// own source file, as AutocompleteArgs and AutocompleteFlags methods on each
+// Command implementation.
+
+// For completing the value of boolean flags like -foo false
+var completePredictBoolean = complete.PredictSet("true", "false")
+
+// We don't currently have a real predictor for module sources, but
+// we'll probably add one later.
+var completePredictModuleSource = complete.PredictAnything
+
+type completePredictSequence []complete.Predictor
+
+func (s completePredictSequence) Predict(a complete.Args) []string {
+	// Nested subcommands do not require any placeholder entry for their subcommand name.
+	idx := len(a.Completed)
+	if idx >= len(s) {
+		return nil
+	}
+
+	return s[idx].Predict(a)
+}
+
+func (m *Meta) completePredictWorkspaceName() complete.Predictor {
+	return complete.PredictFunc(func(a complete.Args) []string {
+		// There are lot of things that can fail in here, so if we encounter
+		// any error then we'll just return nothing and not support autocomplete
+		// until whatever error is fixed. (The user can't actually see the error
+		// here, but other commands should produce a user-visible error before
+		// too long.)
+
+		// We assume here that we want to autocomplete for the current working
+		// directory, since we don't have enough context to know where to
+		// find any config path argument, and it might be _after_ the argument
+		// we're trying to complete here anyway.
+		configPath, err := ModulePath(nil)
+		if err != nil {
+			return nil
+		}
+
+		backendConfig, diags := m.loadBackendConfig(configPath)
+		if diags.HasErrors() {
+			return nil
+		}
+
+		b, diags := m.Backend(&BackendOpts{
+			Config: backendConfig,
+		})
+		if diags.HasErrors() {
+			return nil
+		}
+
+		names, _ := b.Workspaces()
+		return names
+	})
+}
diff --git a/v1.5.7/internal/command/autocomplete_test.go b/v1.5.7/internal/command/autocomplete_test.go
new file mode 100644
index 0000000..bee6418
--- /dev/null
+++ b/v1.5.7/internal/command/autocomplete_test.go
@@ -0,0 +1,40 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"io/ioutil"
+	"os"
+	"reflect"
+	"testing"
+
+	"github.com/mitchellh/cli"
+	"github.com/posener/complete"
+)
+
+func TestMetaCompletePredictWorkspaceName(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	// make sure a vars file doesn't interfere
+	err := ioutil.WriteFile(DefaultVarsFilename, nil, 0644)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	ui := new(cli.MockUi)
+	meta := &Meta{Ui: ui}
+
+	predictor := meta.completePredictWorkspaceName()
+
+	got := predictor.Predict(complete.Args{
+		Last: "",
+	})
+	want := []string{"default"}
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
diff --git a/v1.5.7/internal/command/cli_ui.go b/v1.5.7/internal/command/cli_ui.go
new file mode 100644
index 0000000..6e0cc20
--- /dev/null
+++ b/v1.5.7/internal/command/cli_ui.go
@@ -0,0 +1,54 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+
+	"github.com/mitchellh/cli"
+	"github.com/mitchellh/colorstring"
+)
+
+// ColoredUi is a Ui implementation that colors its output according
+// to the given color schemes for the given type of output.
+type ColorizeUi struct {
+	Colorize    *colorstring.Colorize
+	OutputColor string
+	InfoColor   string
+	ErrorColor  string
+	WarnColor   string
+	Ui          cli.Ui
+}
+
+func (u *ColorizeUi) Ask(query string) (string, error) {
+	return u.Ui.Ask(u.colorize(query, u.OutputColor))
+}
+
+func (u *ColorizeUi) AskSecret(query string) (string, error) {
+	return u.Ui.AskSecret(u.colorize(query, u.OutputColor))
+}
+
+func (u *ColorizeUi) Output(message string) {
+	u.Ui.Output(u.colorize(message, u.OutputColor))
+}
+
+func (u *ColorizeUi) Info(message string) {
+	u.Ui.Info(u.colorize(message, u.InfoColor))
+}
+
+func (u *ColorizeUi) Error(message string) {
+	u.Ui.Error(u.colorize(message, u.ErrorColor))
+}
+
+func (u *ColorizeUi) Warn(message string) {
+	u.Ui.Warn(u.colorize(message, u.WarnColor))
+}
+
+func (u *ColorizeUi) colorize(message string, color string) string {
+	if color == "" {
+		return message
+	}
+
+	return u.Colorize.Color(fmt.Sprintf("%s%s[reset]", color, message))
+}
diff --git a/v1.5.7/internal/command/cli_ui_test.go b/v1.5.7/internal/command/cli_ui_test.go
new file mode 100644
index 0000000..7a3ee84
--- /dev/null
+++ b/v1.5.7/internal/command/cli_ui_test.go
@@ -0,0 +1,14 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"testing"
+
+	"github.com/mitchellh/cli"
+)
+
+func TestColorizeUi_impl(t *testing.T) {
+	var _ cli.Ui = new(ColorizeUi)
+}
diff --git a/v1.5.7/internal/command/cliconfig/cliconfig.go b/v1.5.7/internal/command/cliconfig/cliconfig.go
new file mode 100644
index 0000000..f0b292c
--- /dev/null
+++ b/v1.5.7/internal/command/cliconfig/cliconfig.go
@@ -0,0 +1,459 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package cliconfig has the types representing and the logic to load CLI-level
+// configuration settings.
+//
+// The CLI config is a small collection of settings that a user can override via
+// some files in their home directory or, in some cases, via environment
+// variables. The CLI config is not the same thing as a Terraform configuration
+// written in the Terraform language; the logic for those lives in the top-level
+// directory "configs".
+package cliconfig
+
+import (
+	"errors"
+	"fmt"
+	"io/fs"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/hashicorp/hcl"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+const pluginCacheDirEnvVar = "TF_PLUGIN_CACHE_DIR"
+const pluginCacheMayBreakLockFileEnvVar = "TF_PLUGIN_CACHE_MAY_BREAK_DEPENDENCY_LOCK_FILE"
+
+// Config is the structure of the configuration for the Terraform CLI.
+//
+// This is not the configuration for Terraform itself. That is in the
+// "config" package.
+type Config struct {
+	Providers    map[string]string
+	Provisioners map[string]string
+
+	DisableCheckpoint          bool `hcl:"disable_checkpoint"`
+	DisableCheckpointSignature bool `hcl:"disable_checkpoint_signature"`
+
+	// If set, enables local caching of plugins in this directory to
+	// avoid repeatedly re-downloading over the Internet.
+	PluginCacheDir string `hcl:"plugin_cache_dir"`
+
+	// PluginCacheMayBreakDependencyLockFile is an interim accommodation for
+	// those who wish to use the Plugin Cache Dir even in cases where doing so
+	// will cause the dependency lock file to be incomplete.
+	//
+	// This is likely to become a silent no-op in future Terraform versions but
+	// is here in recognition of the fact that the dependency lock file is not
+	// yet a good fit for all Terraform workflows and folks in that category
+	// would prefer to have the plugin cache dir's behavior to take priority
+	// over the requirements of the dependency lock file.
+	PluginCacheMayBreakDependencyLockFile bool `hcl:"plugin_cache_may_break_dependency_lock_file"`
+
+	Hosts map[string]*ConfigHost `hcl:"host"`
+
+	Credentials        map[string]map[string]interface{}   `hcl:"credentials"`
+	CredentialsHelpers map[string]*ConfigCredentialsHelper `hcl:"credentials_helper"`
+
+	// ProviderInstallation represents any provider_installation blocks
+	// in the configuration. Only one of these is allowed across the whole
+	// configuration, but we decode into a slice here so that we can handle
+	// that validation at validation time rather than initial decode time.
+	ProviderInstallation []*ProviderInstallation
+}
+
+// ConfigHost is the structure of the "host" nested block within the CLI
+// configuration, which can be used to override the default service host
+// discovery behavior for a particular hostname.
+type ConfigHost struct {
+	Services map[string]interface{} `hcl:"services"`
+}
+
+// ConfigCredentialsHelper is the structure of the "credentials_helper"
+// nested block within the CLI configuration.
+type ConfigCredentialsHelper struct {
+	Args []string `hcl:"args"`
+}
+
+// BuiltinConfig is the built-in defaults for the configuration. These
+// can be overridden by user configurations.
+var BuiltinConfig Config
+
+// ConfigFile returns the default path to the configuration file.
+//
+// On Unix-like systems this is the ".terraformrc" file in the home directory.
+// On Windows, this is the "terraform.rc" file in the application data
+// directory.
+func ConfigFile() (string, error) {
+	return configFile()
+}
+
+// ConfigDir returns the configuration directory for Terraform.
+func ConfigDir() (string, error) {
+	return configDir()
+}
+
+// LoadConfig reads the CLI configuration from the various filesystem locations
+// and from the environment, returning a merged configuration along with any
+// diagnostics (errors and warnings) encountered along the way.
+func LoadConfig() (*Config, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	configVal := BuiltinConfig // copy
+	config := &configVal
+
+	if mainFilename, mainFileDiags := cliConfigFile(); len(mainFileDiags) == 0 {
+		if _, err := os.Stat(mainFilename); err == nil {
+			mainConfig, mainDiags := loadConfigFile(mainFilename)
+			diags = diags.Append(mainDiags)
+			config = config.Merge(mainConfig)
+		}
+	} else {
+		diags = diags.Append(mainFileDiags)
+	}
+
+	// Unless the user has specifically overridden the configuration file
+	// location using an environment variable, we'll also load what we find
+	// in the config directory. We skip the config directory when source
+	// file override is set because we interpret the environment variable
+	// being set as an intention to ignore the default set of CLI config
+	// files because we're doing something special, like running Terraform
+	// in automation with a locally-customized configuration.
+	if cliConfigFileOverride() == "" {
+		if configDir, err := ConfigDir(); err == nil {
+			if info, err := os.Stat(configDir); err == nil && info.IsDir() {
+				dirConfig, dirDiags := loadConfigDir(configDir)
+				diags = diags.Append(dirDiags)
+				config = config.Merge(dirConfig)
+			}
+		}
+	} else {
+		log.Printf("[DEBUG] Not reading CLI config directory because config location is overridden by environment variable")
+	}
+
+	if envConfig := EnvConfig(); envConfig != nil {
+		// envConfig takes precedence
+		config = envConfig.Merge(config)
+	}
+
+	diags = diags.Append(config.Validate())
+
+	return config, diags
+}
+
+// loadConfigFile loads the CLI configuration from ".terraformrc" files.
+func loadConfigFile(path string) (*Config, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	result := &Config{}
+
+	log.Printf("Loading CLI configuration from %s", path)
+
+	// Read the HCL file and prepare for parsing
+	d, err := ioutil.ReadFile(path)
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Error reading %s: %s", path, err))
+		return result, diags
+	}
+
+	// Parse it
+	obj, err := hcl.Parse(string(d))
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Error parsing %s: %s", path, err))
+		return result, diags
+	}
+
+	// Build up the result
+	if err := hcl.DecodeObject(&result, obj); err != nil {
+		diags = diags.Append(fmt.Errorf("Error parsing %s: %s", path, err))
+		return result, diags
+	}
+
+	// Deal with the provider_installation block, which is not handled using
+	// DecodeObject because its structure is not compatible with the
+	// limitations of that function.
+	providerInstBlocks, moreDiags := decodeProviderInstallationFromConfig(obj)
+	diags = diags.Append(moreDiags)
+	result.ProviderInstallation = providerInstBlocks
+
+	// Replace all env vars
+	for k, v := range result.Providers {
+		result.Providers[k] = os.ExpandEnv(v)
+	}
+	for k, v := range result.Provisioners {
+		result.Provisioners[k] = os.ExpandEnv(v)
+	}
+
+	if result.PluginCacheDir != "" {
+		result.PluginCacheDir = os.ExpandEnv(result.PluginCacheDir)
+	}
+
+	return result, diags
+}
+
+func loadConfigDir(path string) (*Config, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	result := &Config{}
+
+	entries, err := ioutil.ReadDir(path)
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Error reading %s: %s", path, err))
+		return result, diags
+	}
+
+	for _, entry := range entries {
+		name := entry.Name()
+		// Ignoring errors here because it is used only to indicate pattern
+		// syntax errors, and our patterns are hard-coded here.
+		hclMatched, _ := filepath.Match("*.tfrc", name)
+		jsonMatched, _ := filepath.Match("*.tfrc.json", name)
+		if !(hclMatched || jsonMatched) {
+			continue
+		}
+
+		filePath := filepath.Join(path, name)
+		fileConfig, fileDiags := loadConfigFile(filePath)
+		diags = diags.Append(fileDiags)
+		result = result.Merge(fileConfig)
+	}
+
+	return result, diags
+}
+
+// EnvConfig returns a Config populated from environment variables.
+//
+// Any values specified in this config should override those set in the
+// configuration file.
+func EnvConfig() *Config {
+	env := makeEnvMap(os.Environ())
+	return envConfig(env)
+}
+
+func envConfig(env map[string]string) *Config {
+	config := &Config{}
+
+	if envPluginCacheDir := env[pluginCacheDirEnvVar]; envPluginCacheDir != "" {
+		// No Expandenv here, because expanding environment variables inside
+		// an environment variable would be strange and seems unnecessary.
+		// (User can expand variables into the value while setting it using
+		// standard shell features.)
+		config.PluginCacheDir = envPluginCacheDir
+	}
+
+	if envMayBreak := env[pluginCacheMayBreakLockFileEnvVar]; envMayBreak != "" && envMayBreak != "0" {
+		// This is an environment variable analog to the
+		// plugin_cache_may_break_dependency_lock_file setting. If either this
+		// or the config file setting are enabled then it's enabled; there is
+		// no way to override back to false if either location sets this to
+		// true.
+		config.PluginCacheMayBreakDependencyLockFile = true
+	}
+
+	return config
+}
+
+func makeEnvMap(environ []string) map[string]string {
+	if len(environ) == 0 {
+		return nil
+	}
+
+	ret := make(map[string]string, len(environ))
+	for _, entry := range environ {
+		eq := strings.IndexByte(entry, '=')
+		if eq == -1 {
+			continue
+		}
+		ret[entry[:eq]] = entry[eq+1:]
+	}
+	return ret
+}
+
+// Validate checks for errors in the configuration that cannot be detected
+// just by HCL decoding, returning any problems as diagnostics.
+//
+// On success, the returned diagnostics will return false from the HasErrors
+// method. A non-nil diagnostics is not necessarily an error, since it may
+// contain just warnings.
+func (c *Config) Validate() tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	if c == nil {
+		return diags
+	}
+
+	// FIXME: Right now our config parsing doesn't retain enough information
+	// to give proper source references to any errors. We should improve
+	// on this when we change the CLI config parser to use HCL2.
+
+	// Check that all "host" blocks have valid hostnames.
+	for givenHost := range c.Hosts {
+		_, err := svchost.ForComparison(givenHost)
+		if err != nil {
+			diags = diags.Append(
+				fmt.Errorf("The host %q block has an invalid hostname: %s", givenHost, err),
+			)
+		}
+	}
+
+	// Check that all "credentials" blocks have valid hostnames.
+	for givenHost := range c.Credentials {
+		_, err := svchost.ForComparison(givenHost)
+		if err != nil {
+			diags = diags.Append(
+				fmt.Errorf("The credentials %q block has an invalid hostname: %s", givenHost, err),
+			)
+		}
+	}
+
+	// Should have zero or one "credentials_helper" blocks
+	if len(c.CredentialsHelpers) > 1 {
+		diags = diags.Append(
+			fmt.Errorf("No more than one credentials_helper block may be specified"),
+		)
+	}
+
+	// Should have zero or one "provider_installation" blocks
+	if len(c.ProviderInstallation) > 1 {
+		diags = diags.Append(
+			fmt.Errorf("No more than one provider_installation block may be specified"),
+		)
+	}
+
+	if c.PluginCacheDir != "" {
+		_, err := os.Stat(c.PluginCacheDir)
+		if err != nil {
+			diags = diags.Append(
+				fmt.Errorf("The specified plugin cache dir %s cannot be opened: %s", c.PluginCacheDir, err),
+			)
+		}
+	}
+
+	return diags
+}
+
+// Merge merges two configurations and returns a third entirely
+// new configuration with the two merged.
+func (c *Config) Merge(c2 *Config) *Config {
+	var result Config
+	result.Providers = make(map[string]string)
+	result.Provisioners = make(map[string]string)
+	for k, v := range c.Providers {
+		result.Providers[k] = v
+	}
+	for k, v := range c2.Providers {
+		if v1, ok := c.Providers[k]; ok {
+			log.Printf("[INFO] Local %s provider configuration '%s' overrides '%s'", k, v, v1)
+		}
+		result.Providers[k] = v
+	}
+	for k, v := range c.Provisioners {
+		result.Provisioners[k] = v
+	}
+	for k, v := range c2.Provisioners {
+		if v1, ok := c.Provisioners[k]; ok {
+			log.Printf("[INFO] Local %s provisioner configuration '%s' overrides '%s'", k, v, v1)
+		}
+		result.Provisioners[k] = v
+	}
+	result.DisableCheckpoint = c.DisableCheckpoint || c2.DisableCheckpoint
+	result.DisableCheckpointSignature = c.DisableCheckpointSignature || c2.DisableCheckpointSignature
+
+	result.PluginCacheDir = c.PluginCacheDir
+	if result.PluginCacheDir == "" {
+		result.PluginCacheDir = c2.PluginCacheDir
+	}
+
+	if c.PluginCacheMayBreakDependencyLockFile || c2.PluginCacheMayBreakDependencyLockFile {
+		// This setting saturates to "on"; once either configuration sets it,
+		// there is no way to override it back to off again.
+		result.PluginCacheMayBreakDependencyLockFile = true
+	}
+
+	if (len(c.Hosts) + len(c2.Hosts)) > 0 {
+		result.Hosts = make(map[string]*ConfigHost)
+		for name, host := range c.Hosts {
+			result.Hosts[name] = host
+		}
+		for name, host := range c2.Hosts {
+			result.Hosts[name] = host
+		}
+	}
+
+	if (len(c.Credentials) + len(c2.Credentials)) > 0 {
+		result.Credentials = make(map[string]map[string]interface{})
+		for host, creds := range c.Credentials {
+			result.Credentials[host] = creds
+		}
+		for host, creds := range c2.Credentials {
+			// We just clobber an entry from the other file right now. Will
+			// improve on this later using the more-robust merging behavior
+			// built in to HCL2.
+			result.Credentials[host] = creds
+		}
+	}
+
+	if (len(c.CredentialsHelpers) + len(c2.CredentialsHelpers)) > 0 {
+		result.CredentialsHelpers = make(map[string]*ConfigCredentialsHelper)
+		for name, helper := range c.CredentialsHelpers {
+			result.CredentialsHelpers[name] = helper
+		}
+		for name, helper := range c2.CredentialsHelpers {
+			result.CredentialsHelpers[name] = helper
+		}
+	}
+
+	if (len(c.ProviderInstallation) + len(c2.ProviderInstallation)) > 0 {
+		result.ProviderInstallation = append(result.ProviderInstallation, c.ProviderInstallation...)
+		result.ProviderInstallation = append(result.ProviderInstallation, c2.ProviderInstallation...)
+	}
+
+	return &result
+}
+
+func cliConfigFile() (string, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	mustExist := true
+
+	configFilePath := cliConfigFileOverride()
+	if configFilePath == "" {
+		var err error
+		configFilePath, err = ConfigFile()
+		mustExist = false
+
+		if err != nil {
+			log.Printf(
+				"[ERROR] Error detecting default CLI config file path: %s",
+				err)
+		}
+	}
+
+	log.Printf("[DEBUG] Attempting to open CLI config file: %s", configFilePath)
+	f, err := os.Open(configFilePath)
+	if err == nil {
+		f.Close()
+		return configFilePath, diags
+	}
+
+	if mustExist || !errors.Is(err, fs.ErrNotExist) {
+		diags = append(diags, tfdiags.Sourceless(
+			tfdiags.Warning,
+			"Unable to open CLI configuration file",
+			fmt.Sprintf("The CLI configuration file at %q does not exist.", configFilePath),
+		))
+	}
+
+	log.Println("[DEBUG] File doesn't exist, but doesn't need to. Ignoring.")
+	return "", diags
+}
+
+func cliConfigFileOverride() string {
+	configFilePath := os.Getenv("TF_CLI_CONFIG_FILE")
+	if configFilePath == "" {
+		configFilePath = os.Getenv("TERRAFORM_CONFIG")
+	}
+	return configFilePath
+}
diff --git a/v1.5.7/internal/command/cliconfig/cliconfig_test.go b/v1.5.7/internal/command/cliconfig/cliconfig_test.go
new file mode 100644
index 0000000..77a4e94
--- /dev/null
+++ b/v1.5.7/internal/command/cliconfig/cliconfig_test.go
@@ -0,0 +1,551 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cliconfig
+
+import (
+	"os"
+	"path/filepath"
+	"reflect"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// This is the directory where our test fixtures are.
+const fixtureDir = "./testdata"
+
+func TestLoadConfig(t *testing.T) {
+	c, err := loadConfigFile(filepath.Join(fixtureDir, "config"))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := &Config{
+		Providers: map[string]string{
+			"aws": "foo",
+			"do":  "bar",
+		},
+	}
+
+	if !reflect.DeepEqual(c, expected) {
+		t.Fatalf("bad: %#v", c)
+	}
+}
+
+func TestLoadConfig_envSubst(t *testing.T) {
+	defer os.Unsetenv("TFTEST")
+	os.Setenv("TFTEST", "hello")
+
+	c, err := loadConfigFile(filepath.Join(fixtureDir, "config-env"))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := &Config{
+		Providers: map[string]string{
+			"aws":    "hello",
+			"google": "bar",
+		},
+		Provisioners: map[string]string{
+			"local": "hello",
+		},
+	}
+
+	if !reflect.DeepEqual(c, expected) {
+		t.Fatalf("bad: %#v", c)
+	}
+}
+
+func TestLoadConfig_non_existing_file(t *testing.T) {
+	tmpDir := os.TempDir()
+	cliTmpFile := filepath.Join(tmpDir, "dev.tfrc")
+
+	os.Setenv("TF_CLI_CONFIG_FILE", cliTmpFile)
+	defer os.Unsetenv("TF_CLI_CONFIG_FILE")
+
+	c, errs := LoadConfig()
+	if errs.HasErrors() || c.Validate().HasErrors() {
+		t.Fatalf("err: %s", errs)
+	}
+
+	hasOpenFileWarn := false
+	for _, err := range errs {
+		if err.Severity() == tfdiags.Warning && err.Description().Summary == "Unable to open CLI configuration file" {
+			hasOpenFileWarn = true
+			break
+		}
+	}
+
+	if !hasOpenFileWarn {
+		t.Fatal("expecting a warning message because of nonexisting CLI configuration file")
+	}
+}
+
+func TestEnvConfig(t *testing.T) {
+	tests := map[string]struct {
+		env  map[string]string
+		want *Config
+	}{
+		"no environment variables": {
+			nil,
+			&Config{},
+		},
+		"TF_PLUGIN_CACHE_DIR=boop": {
+			map[string]string{
+				"TF_PLUGIN_CACHE_DIR": "boop",
+			},
+			&Config{
+				PluginCacheDir: "boop",
+			},
+		},
+		"TF_PLUGIN_CACHE_MAY_BREAK_DEPENDENCY_LOCK_FILE=anything_except_zero": {
+			map[string]string{
+				"TF_PLUGIN_CACHE_MAY_BREAK_DEPENDENCY_LOCK_FILE": "anything_except_zero",
+			},
+			&Config{
+				PluginCacheMayBreakDependencyLockFile: true,
+			},
+		},
+		"TF_PLUGIN_CACHE_MAY_BREAK_DEPENDENCY_LOCK_FILE=0": {
+			map[string]string{
+				"TF_PLUGIN_CACHE_MAY_BREAK_DEPENDENCY_LOCK_FILE": "0",
+			},
+			&Config{},
+		},
+		"TF_PLUGIN_CACHE_DIR and TF_PLUGIN_CACHE_MAY_BREAK_DEPENDENCY_LOCK_FILE": {
+			map[string]string{
+				"TF_PLUGIN_CACHE_DIR":                            "beep",
+				"TF_PLUGIN_CACHE_MAY_BREAK_DEPENDENCY_LOCK_FILE": "1",
+			},
+			&Config{
+				PluginCacheDir:                        "beep",
+				PluginCacheMayBreakDependencyLockFile: true,
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got := envConfig(test.env)
+			want := test.want
+
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestMakeEnvMap(t *testing.T) {
+	tests := map[string]struct {
+		environ []string
+		want    map[string]string
+	}{
+		"nil": {
+			nil,
+			nil,
+		},
+		"one": {
+			[]string{
+				"FOO=bar",
+			},
+			map[string]string{
+				"FOO": "bar",
+			},
+		},
+		"many": {
+			[]string{
+				"FOO=1",
+				"BAR=2",
+				"BAZ=3",
+			},
+			map[string]string{
+				"FOO": "1",
+				"BAR": "2",
+				"BAZ": "3",
+			},
+		},
+		"conflict": {
+			[]string{
+				"FOO=1",
+				"BAR=1",
+				"FOO=2",
+			},
+			map[string]string{
+				"BAR": "1",
+				"FOO": "2", // Last entry of each name wins
+			},
+		},
+		"empty_val": {
+			[]string{
+				"FOO=",
+			},
+			map[string]string{
+				"FOO": "",
+			},
+		},
+		"no_equals": {
+			[]string{
+				"FOO=bar",
+				"INVALID",
+			},
+			map[string]string{
+				"FOO": "bar",
+			},
+		},
+		"multi_equals": {
+			[]string{
+				"FOO=bar=baz=boop",
+			},
+			map[string]string{
+				"FOO": "bar=baz=boop",
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got := makeEnvMap(test.environ)
+			want := test.want
+
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+	}
+
+}
+
+func TestLoadConfig_hosts(t *testing.T) {
+	got, diags := loadConfigFile(filepath.Join(fixtureDir, "hosts"))
+	if len(diags) != 0 {
+		t.Fatalf("%s", diags.Err())
+	}
+
+	want := &Config{
+		Hosts: map[string]*ConfigHost{
+			"example.com": {
+				Services: map[string]interface{}{
+					"modules.v1": "https://example.com/",
+				},
+			},
+		},
+	}
+
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("wrong result\ngot:  %swant: %s", spew.Sdump(got), spew.Sdump(want))
+	}
+}
+
+func TestLoadConfig_credentials(t *testing.T) {
+	got, err := loadConfigFile(filepath.Join(fixtureDir, "credentials"))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	want := &Config{
+		Credentials: map[string]map[string]interface{}{
+			"example.com": map[string]interface{}{
+				"token": "foo the bar baz",
+			},
+			"example.net": map[string]interface{}{
+				"username": "foo",
+				"password": "baz",
+			},
+		},
+		CredentialsHelpers: map[string]*ConfigCredentialsHelper{
+			"foo": &ConfigCredentialsHelper{
+				Args: []string{"bar", "baz"},
+			},
+		},
+	}
+
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("wrong result\ngot:  %swant: %s", spew.Sdump(got), spew.Sdump(want))
+	}
+}
+
+func TestConfigValidate(t *testing.T) {
+	tests := map[string]struct {
+		Config    *Config
+		DiagCount int
+	}{
+		"nil": {
+			nil,
+			0,
+		},
+		"empty": {
+			&Config{},
+			0,
+		},
+		"host good": {
+			&Config{
+				Hosts: map[string]*ConfigHost{
+					"example.com": {},
+				},
+			},
+			0,
+		},
+		"host with bad hostname": {
+			&Config{
+				Hosts: map[string]*ConfigHost{
+					"example..com": {},
+				},
+			},
+			1, // host block has invalid hostname
+		},
+		"credentials good": {
+			&Config{
+				Credentials: map[string]map[string]interface{}{
+					"example.com": map[string]interface{}{
+						"token": "foo",
+					},
+				},
+			},
+			0,
+		},
+		"credentials with bad hostname": {
+			&Config{
+				Credentials: map[string]map[string]interface{}{
+					"example..com": map[string]interface{}{
+						"token": "foo",
+					},
+				},
+			},
+			1, // credentials block has invalid hostname
+		},
+		"credentials helper good": {
+			&Config{
+				CredentialsHelpers: map[string]*ConfigCredentialsHelper{
+					"foo": {},
+				},
+			},
+			0,
+		},
+		"credentials helper too many": {
+			&Config{
+				CredentialsHelpers: map[string]*ConfigCredentialsHelper{
+					"foo": {},
+					"bar": {},
+				},
+			},
+			1, // no more than one credentials_helper block allowed
+		},
+		"provider_installation good none": {
+			&Config{
+				ProviderInstallation: nil,
+			},
+			0,
+		},
+		"provider_installation good one": {
+			&Config{
+				ProviderInstallation: []*ProviderInstallation{
+					{},
+				},
+			},
+			0,
+		},
+		"provider_installation too many": {
+			&Config{
+				ProviderInstallation: []*ProviderInstallation{
+					{},
+					{},
+				},
+			},
+			1, // no more than one provider_installation block allowed
+		},
+		"plugin_cache_dir does not exist": {
+			&Config{
+				PluginCacheDir: "fake",
+			},
+			1, // The specified plugin cache dir %s cannot be opened
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			diags := test.Config.Validate()
+			if len(diags) != test.DiagCount {
+				t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.DiagCount)
+				for _, diag := range diags {
+					t.Logf("- %#v", diag.Description())
+				}
+			}
+		})
+	}
+}
+
+func TestConfig_Merge(t *testing.T) {
+	c1 := &Config{
+		Providers: map[string]string{
+			"foo": "bar",
+			"bar": "blah",
+		},
+		Provisioners: map[string]string{
+			"local":  "local",
+			"remote": "bad",
+		},
+		Hosts: map[string]*ConfigHost{
+			"example.com": {
+				Services: map[string]interface{}{
+					"modules.v1": "http://example.com/",
+				},
+			},
+		},
+		Credentials: map[string]map[string]interface{}{
+			"foo": {
+				"bar": "baz",
+			},
+		},
+		CredentialsHelpers: map[string]*ConfigCredentialsHelper{
+			"buz": {},
+		},
+		ProviderInstallation: []*ProviderInstallation{
+			{
+				Methods: []*ProviderInstallationMethod{
+					{Location: ProviderInstallationFilesystemMirror("a")},
+					{Location: ProviderInstallationFilesystemMirror("b")},
+				},
+			},
+			{
+				Methods: []*ProviderInstallationMethod{
+					{Location: ProviderInstallationFilesystemMirror("c")},
+				},
+			},
+		},
+	}
+
+	c2 := &Config{
+		Providers: map[string]string{
+			"bar": "baz",
+			"baz": "what",
+		},
+		Provisioners: map[string]string{
+			"remote": "remote",
+		},
+		Hosts: map[string]*ConfigHost{
+			"example.net": {
+				Services: map[string]interface{}{
+					"modules.v1": "https://example.net/",
+				},
+			},
+		},
+		Credentials: map[string]map[string]interface{}{
+			"fee": {
+				"bur": "bez",
+			},
+		},
+		CredentialsHelpers: map[string]*ConfigCredentialsHelper{
+			"biz": {},
+		},
+		ProviderInstallation: []*ProviderInstallation{
+			{
+				Methods: []*ProviderInstallationMethod{
+					{Location: ProviderInstallationFilesystemMirror("d")},
+				},
+			},
+		},
+		PluginCacheMayBreakDependencyLockFile: true,
+	}
+
+	expected := &Config{
+		Providers: map[string]string{
+			"foo": "bar",
+			"bar": "baz",
+			"baz": "what",
+		},
+		Provisioners: map[string]string{
+			"local":  "local",
+			"remote": "remote",
+		},
+		Hosts: map[string]*ConfigHost{
+			"example.com": {
+				Services: map[string]interface{}{
+					"modules.v1": "http://example.com/",
+				},
+			},
+			"example.net": {
+				Services: map[string]interface{}{
+					"modules.v1": "https://example.net/",
+				},
+			},
+		},
+		Credentials: map[string]map[string]interface{}{
+			"foo": {
+				"bar": "baz",
+			},
+			"fee": {
+				"bur": "bez",
+			},
+		},
+		CredentialsHelpers: map[string]*ConfigCredentialsHelper{
+			"buz": {},
+			"biz": {},
+		},
+		ProviderInstallation: []*ProviderInstallation{
+			{
+				Methods: []*ProviderInstallationMethod{
+					{Location: ProviderInstallationFilesystemMirror("a")},
+					{Location: ProviderInstallationFilesystemMirror("b")},
+				},
+			},
+			{
+				Methods: []*ProviderInstallationMethod{
+					{Location: ProviderInstallationFilesystemMirror("c")},
+				},
+			},
+			{
+				Methods: []*ProviderInstallationMethod{
+					{Location: ProviderInstallationFilesystemMirror("d")},
+				},
+			},
+		},
+		PluginCacheMayBreakDependencyLockFile: true,
+	}
+
+	actual := c1.Merge(c2)
+	if diff := cmp.Diff(expected, actual); diff != "" {
+		t.Fatalf("wrong result\n%s", diff)
+	}
+}
+
+func TestConfig_Merge_disableCheckpoint(t *testing.T) {
+	c1 := &Config{
+		DisableCheckpoint: true,
+	}
+
+	c2 := &Config{}
+
+	expected := &Config{
+		Providers:         map[string]string{},
+		Provisioners:      map[string]string{},
+		DisableCheckpoint: true,
+	}
+
+	actual := c1.Merge(c2)
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestConfig_Merge_disableCheckpointSignature(t *testing.T) {
+	c1 := &Config{
+		DisableCheckpointSignature: true,
+	}
+
+	c2 := &Config{}
+
+	expected := &Config{
+		Providers:                  map[string]string{},
+		Provisioners:               map[string]string{},
+		DisableCheckpointSignature: true,
+	}
+
+	actual := c1.Merge(c2)
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
diff --git a/v1.5.7/internal/command/cliconfig/config_unix.go b/v1.5.7/internal/command/cliconfig/config_unix.go
new file mode 100644
index 0000000..e044b9a
--- /dev/null
+++ b/v1.5.7/internal/command/cliconfig/config_unix.go
@@ -0,0 +1,56 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build !windows
+// +build !windows
+
+package cliconfig
+
+import (
+	"errors"
+	"os"
+	"os/user"
+	"path/filepath"
+)
+
+func configFile() (string, error) {
+	dir, err := homeDir()
+	if err != nil {
+		return "", err
+	}
+
+	return filepath.Join(dir, ".terraformrc"), nil
+}
+
+func configDir() (string, error) {
+	dir, err := homeDir()
+	if err != nil {
+		return "", err
+	}
+
+	return filepath.Join(dir, ".terraform.d"), nil
+}
+
+func homeDir() (string, error) {
+	// First prefer the HOME environmental variable
+	if home := os.Getenv("HOME"); home != "" {
+		// FIXME: homeDir gets called from globalPluginDirs during init, before
+		// the logging is set up.  We should move meta initializtion outside of
+		// init, but in the meantime we just need to silence this output.
+		//log.Printf("[DEBUG] Detected home directory from env var: %s", home)
+
+		return home, nil
+	}
+
+	// If that fails, try build-in module
+	user, err := user.Current()
+	if err != nil {
+		return "", err
+	}
+
+	if user.HomeDir == "" {
+		return "", errors.New("blank output")
+	}
+
+	return user.HomeDir, nil
+}
diff --git a/v1.5.7/internal/command/cliconfig/config_windows.go b/v1.5.7/internal/command/cliconfig/config_windows.go
new file mode 100644
index 0000000..1997460
--- /dev/null
+++ b/v1.5.7/internal/command/cliconfig/config_windows.go
@@ -0,0 +1,50 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build windows
+// +build windows
+
+package cliconfig
+
+import (
+	"path/filepath"
+	"syscall"
+	"unsafe"
+)
+
+var (
+	shell         = syscall.MustLoadDLL("Shell32.dll")
+	getFolderPath = shell.MustFindProc("SHGetFolderPathW")
+)
+
+const CSIDL_APPDATA = 26
+
+func configFile() (string, error) {
+	dir, err := homeDir()
+	if err != nil {
+		return "", err
+	}
+
+	return filepath.Join(dir, "terraform.rc"), nil
+}
+
+func configDir() (string, error) {
+	dir, err := homeDir()
+	if err != nil {
+		return "", err
+	}
+
+	return filepath.Join(dir, "terraform.d"), nil
+}
+
+func homeDir() (string, error) {
+	b := make([]uint16, syscall.MAX_PATH)
+
+	// See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb762181(v=vs.85).aspx
+	r, _, err := getFolderPath.Call(0, CSIDL_APPDATA, 0, 0, uintptr(unsafe.Pointer(&b[0])))
+	if uint32(r) != 0 {
+		return "", err
+	}
+
+	return syscall.UTF16ToString(b), nil
+}
diff --git a/v1.5.7/internal/command/cliconfig/credentials.go b/v1.5.7/internal/command/cliconfig/credentials.go
new file mode 100644
index 0000000..c9f01a6
--- /dev/null
+++ b/v1.5.7/internal/command/cliconfig/credentials.go
@@ -0,0 +1,528 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cliconfig
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+	svcauth "github.com/hashicorp/terraform-svchost/auth"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	pluginDiscovery "github.com/hashicorp/terraform/internal/plugin/discovery"
+	"github.com/hashicorp/terraform/internal/replacefile"
+)
+
+// credentialsConfigFile returns the path for the special configuration file
+// that the credentials source will use when asked to save or forget credentials
+// and when a "credentials helper" program is not active.
+func credentialsConfigFile() (string, error) {
+	configDir, err := ConfigDir()
+	if err != nil {
+		return "", err
+	}
+	return filepath.Join(configDir, "credentials.tfrc.json"), nil
+}
+
+// CredentialsSource creates and returns a service credentials source whose
+// behavior depends on which "credentials" and "credentials_helper" blocks,
+// if any, are present in the receiving config.
+func (c *Config) CredentialsSource(helperPlugins pluginDiscovery.PluginMetaSet) (*CredentialsSource, error) {
+	credentialsFilePath, err := credentialsConfigFile()
+	if err != nil {
+		// If we managed to load a Config object at all then we would already
+		// have located this file, so this error is very unlikely.
+		return nil, fmt.Errorf("can't locate credentials file: %s", err)
+	}
+
+	var helper svcauth.CredentialsSource
+	var helperType string
+	for givenType, givenConfig := range c.CredentialsHelpers {
+		available := helperPlugins.WithName(givenType)
+		if available.Count() == 0 {
+			log.Printf("[ERROR] Unable to find credentials helper %q; ignoring", givenType)
+			break
+		}
+
+		selected := available.Newest()
+
+		helperSource := svcauth.HelperProgramCredentialsSource(selected.Path, givenConfig.Args...)
+		helper = svcauth.CachingCredentialsSource(helperSource) // cached because external operation may be slow/expensive
+		helperType = givenType
+
+		// There should only be zero or one "credentials_helper" blocks. We
+		// assume that the config was validated earlier and so we don't check
+		// for extras here.
+		break
+	}
+
+	return c.credentialsSource(helperType, helper, credentialsFilePath), nil
+}
+
+// EmptyCredentialsSourceForTests constructs a CredentialsSource with
+// no credentials pre-loaded and which writes new credentials to a file
+// at the given path.
+//
+// As the name suggests, this function is here only for testing and should not
+// be used in normal application code.
+func EmptyCredentialsSourceForTests(credentialsFilePath string) *CredentialsSource {
+	cfg := &Config{}
+	return cfg.credentialsSource("", nil, credentialsFilePath)
+}
+
+// credentialsSource is an internal factory for the credentials source which
+// allows overriding the credentials file path, which allows setting it to
+// a temporary file location when testing.
+func (c *Config) credentialsSource(helperType string, helper svcauth.CredentialsSource, credentialsFilePath string) *CredentialsSource {
+	configured := map[svchost.Hostname]cty.Value{}
+	for userHost, creds := range c.Credentials {
+		host, err := svchost.ForComparison(userHost)
+		if err != nil {
+			// We expect the config was already validated by the time we get
+			// here, so we'll just ignore invalid hostnames.
+			continue
+		}
+
+		// For now our CLI config continues to use HCL 1.0, so we'll shim it
+		// over to HCL 2.0 types. In future we will hopefully migrate it to
+		// HCL 2.0 instead, and so it'll be a cty.Value already.
+		credsV := hcl2shim.HCL2ValueFromConfigValue(creds)
+		configured[host] = credsV
+	}
+
+	writableLocal := readHostsInCredentialsFile(credentialsFilePath)
+	unwritableLocal := map[svchost.Hostname]cty.Value{}
+	for host, v := range configured {
+		if _, exists := writableLocal[host]; !exists {
+			unwritableLocal[host] = v
+		}
+	}
+
+	return &CredentialsSource{
+		configured:          configured,
+		unwritable:          unwritableLocal,
+		credentialsFilePath: credentialsFilePath,
+		helper:              helper,
+		helperType:          helperType,
+	}
+}
+
+func collectCredentialsFromEnv() map[svchost.Hostname]string {
+	const prefix = "TF_TOKEN_"
+
+	ret := make(map[svchost.Hostname]string)
+	for _, ev := range os.Environ() {
+		eqIdx := strings.Index(ev, "=")
+		if eqIdx < 0 {
+			continue
+		}
+		name := ev[:eqIdx]
+		value := ev[eqIdx+1:]
+		if !strings.HasPrefix(name, prefix) {
+			continue
+		}
+		rawHost := name[len(prefix):]
+
+		// We accept double underscores in place of hyphens because hyphens are not valid
+		// identifiers in most shells and are therefore hard to set.
+		// This is unambiguous with replacing single underscores below because
+		// hyphens are not allowed at the beginning or end of a label and therefore
+		// odd numbers of underscores will not appear together in a valid variable name.
+		rawHost = strings.ReplaceAll(rawHost, "__", "-")
+
+		// We accept underscores in place of dots because dots are not valid
+		// identifiers in most shells and are therefore hard to set.
+		// Underscores are not valid in hostnames, so this is unambiguous for
+		// valid hostnames.
+		rawHost = strings.ReplaceAll(rawHost, "_", ".")
+
+		// Because environment variables are often set indirectly by OS
+		// libraries that might interfere with how they are encoded, we'll
+		// be tolerant of them being given either directly as UTF-8 IDNs
+		// or in Punycode form, normalizing to Punycode form here because
+		// that is what the Terraform credentials helper protocol will
+		// use in its requests.
+		//
+		// Using ForDisplay first here makes this more liberal than Terraform
+		// itself would usually be in that it will tolerate pre-punycoded
+		// hostnames that Terraform normally rejects in other contexts in order
+		// to ensure stored hostnames are human-readable.
+		dispHost := svchost.ForDisplay(rawHost)
+		hostname, err := svchost.ForComparison(dispHost)
+		if err != nil {
+			// Ignore invalid hostnames
+			continue
+		}
+
+		ret[hostname] = value
+	}
+
+	return ret
+}
+
+// hostCredentialsFromEnv returns a token credential by searching for a hostname-specific
+// environment variable. The host parameter is expected to be in the "comparison" form,
+// for example, hostnames containing non-ASCII characters like "café.fr"
+// should be expressed as "xn--caf-dma.fr". If the variable based on the hostname is not
+// defined, nil is returned.
+//
+// Hyphen and period characters are allowed in environment variable names, but are not valid POSIX
+// variable names. However, it's still possible to set variable names with these characters using
+// utilities like env or docker. Variable names may have periods translated to underscores and
+// hyphens translated to double underscores in the variable name.
+// For the example "café.fr", you may use the variable names "TF_TOKEN_xn____caf__dma_fr",
+// "TF_TOKEN_xn--caf-dma_fr", or "TF_TOKEN_xn--caf-dma.fr"
+func hostCredentialsFromEnv(host svchost.Hostname) svcauth.HostCredentials {
+	token, ok := collectCredentialsFromEnv()[host]
+	if !ok {
+		return nil
+	}
+	return svcauth.HostCredentialsToken(token)
+}
+
+// CredentialsSource is an implementation of svcauth.CredentialsSource
+// that can read and write the CLI configuration, and possibly also delegate
+// to a credentials helper when configured.
+type CredentialsSource struct {
+	// configured describes the credentials explicitly configured in the CLI
+	// config via "credentials" blocks. This map will also change to reflect
+	// any writes to the special credentials.tfrc.json file.
+	configured map[svchost.Hostname]cty.Value
+
+	// unwritable describes any credentials explicitly configured in the
+	// CLI config in any file other than credentials.tfrc.json. We cannot update
+	// these automatically because only credentials.tfrc.json is subject to
+	// editing by this credentials source.
+	unwritable map[svchost.Hostname]cty.Value
+
+	// credentialsFilePath is the full path to the credentials.tfrc.json file
+	// that we'll update if any changes to credentials are requested and if
+	// a credentials helper isn't available to use instead.
+	//
+	// (This is a field here rather than just calling credentialsConfigFile
+	// directly just so that we can use temporary file location instead during
+	// testing.)
+	credentialsFilePath string
+
+	// helper is the credentials source representing the configured credentials
+	// helper, if any. When this is non-nil, it will be consulted for any
+	// hostnames not explicitly represented in "configured". Any writes to
+	// the credentials store will also be sent to a configured helper instead
+	// of the credentials.tfrc.json file.
+	helper svcauth.CredentialsSource
+
+	// helperType is the name of the type of credentials helper that is
+	// referenced in "helper", or the empty string if "helper" is nil.
+	helperType string
+}
+
+// Assertion that credentialsSource implements CredentialsSource
+var _ svcauth.CredentialsSource = (*CredentialsSource)(nil)
+
+func (s *CredentialsSource) ForHost(host svchost.Hostname) (svcauth.HostCredentials, error) {
+	// The first order of precedence for credentials is a host-specific environment variable
+	if envCreds := hostCredentialsFromEnv(host); envCreds != nil {
+		return envCreds, nil
+	}
+
+	// Then, any credentials block present in the CLI config
+	v, ok := s.configured[host]
+	if ok {
+		return svcauth.HostCredentialsFromObject(v), nil
+	}
+
+	// And finally, the credentials helper
+	if s.helper != nil {
+		return s.helper.ForHost(host)
+	}
+
+	return nil, nil
+}
+
+func (s *CredentialsSource) StoreForHost(host svchost.Hostname, credentials svcauth.HostCredentialsWritable) error {
+	return s.updateHostCredentials(host, credentials)
+}
+
+func (s *CredentialsSource) ForgetForHost(host svchost.Hostname) error {
+	return s.updateHostCredentials(host, nil)
+}
+
+// HostCredentialsLocation returns a value indicating what type of storage is
+// currently used for the credentials for the given hostname.
+//
+// The current location of credentials determines whether updates are possible
+// at all and, if they are, where any updates will be written.
+func (s *CredentialsSource) HostCredentialsLocation(host svchost.Hostname) CredentialsLocation {
+	if _, unwritable := s.unwritable[host]; unwritable {
+		return CredentialsInOtherFile
+	}
+	if _, exists := s.configured[host]; exists {
+		return CredentialsInPrimaryFile
+	}
+	if s.helper != nil {
+		return CredentialsViaHelper
+	}
+	return CredentialsNotAvailable
+}
+
+// CredentialsFilePath returns the full path to the local credentials
+// configuration file, so that a caller can mention this path in order to
+// be transparent about where credentials will be stored.
+//
+// This file will be used for writes only if HostCredentialsLocation for the
+// relevant host returns CredentialsInPrimaryFile or CredentialsNotAvailable.
+//
+// The credentials file path is found relative to the current user's home
+// directory, so this function will return an error in the unlikely event that
+// we cannot determine a suitable home directory to resolve relative to.
+func (s *CredentialsSource) CredentialsFilePath() (string, error) {
+	return s.credentialsFilePath, nil
+}
+
+// CredentialsHelperType returns the name of the configured credentials helper
+// type, or an empty string if no credentials helper is configured.
+func (s *CredentialsSource) CredentialsHelperType() string {
+	return s.helperType
+}
+
+func (s *CredentialsSource) updateHostCredentials(host svchost.Hostname, new svcauth.HostCredentialsWritable) error {
+	switch loc := s.HostCredentialsLocation(host); loc {
+	case CredentialsInOtherFile:
+		return ErrUnwritableHostCredentials(host)
+	case CredentialsInPrimaryFile, CredentialsNotAvailable:
+		// If the host already has credentials stored locally then we'll update
+		// them locally too, even if there's a credentials helper configured,
+		// because the user might be intentionally retaining this particular
+		// host locally for some reason, e.g. if the credentials helper is
+		// talking to some shared remote service like HashiCorp Vault.
+		return s.updateLocalHostCredentials(host, new)
+	case CredentialsViaHelper:
+		// Delegate entirely to the helper, then.
+		if new == nil {
+			return s.helper.ForgetForHost(host)
+		}
+		return s.helper.StoreForHost(host, new)
+	default:
+		// Should never happen because the above cases are exhaustive
+		return fmt.Errorf("invalid credentials location %#v", loc)
+	}
+}
+
+func (s *CredentialsSource) updateLocalHostCredentials(host svchost.Hostname, new svcauth.HostCredentialsWritable) error {
+	// This function updates the local credentials file in particular,
+	// regardless of whether a credentials helper is active. It should be
+	// called only indirectly via updateHostCredentials.
+
+	filename, err := s.CredentialsFilePath()
+	if err != nil {
+		return fmt.Errorf("unable to determine credentials file path: %s", err)
+	}
+
+	oldSrc, err := ioutil.ReadFile(filename)
+	if err != nil && !os.IsNotExist(err) {
+		return fmt.Errorf("cannot read %s: %s", filename, err)
+	}
+
+	var raw map[string]interface{}
+
+	if len(oldSrc) > 0 {
+		// When decoding we use a custom decoder so we can decode any numbers as
+		// json.Number and thus avoid losing any accuracy in our round-trip.
+		dec := json.NewDecoder(bytes.NewReader(oldSrc))
+		dec.UseNumber()
+		err = dec.Decode(&raw)
+		if err != nil {
+			return fmt.Errorf("cannot read %s: %s", filename, err)
+		}
+	} else {
+		raw = make(map[string]interface{})
+	}
+
+	rawCredsI, ok := raw["credentials"]
+	if !ok {
+		rawCredsI = make(map[string]interface{})
+		raw["credentials"] = rawCredsI
+	}
+	rawCredsMap, ok := rawCredsI.(map[string]interface{})
+	if !ok {
+		return fmt.Errorf("credentials file %s has invalid value for \"credentials\" property: must be a JSON object", filename)
+	}
+
+	// We use display-oriented hostnames in our file to mimick how a human user
+	// would write it, so we need to search for and remove any key that
+	// normalizes to our target hostname so we won't generate something invalid
+	// when the existing entry is slightly different.
+	for givenHost := range rawCredsMap {
+		canonHost, err := svchost.ForComparison(givenHost)
+		if err == nil && canonHost == host {
+			delete(rawCredsMap, givenHost)
+		}
+	}
+
+	// If we have a new object to store we'll write it in now. If the previous
+	// object had the hostname written in a different way then this will
+	// appear to change it into our canonical display form, with all the
+	// letters in lowercase and other transforms from the Internationalized
+	// Domain Names specification.
+	if new != nil {
+		toStore := new.ToStore()
+		rawCredsMap[host.ForDisplay()] = ctyjson.SimpleJSONValue{
+			Value: toStore,
+		}
+	}
+
+	newSrc, err := json.MarshalIndent(raw, "", "  ")
+	if err != nil {
+		return fmt.Errorf("cannot serialize updated credentials file: %s", err)
+	}
+
+	// Now we'll write our new content over the top of the existing file.
+	// Because we updated the data structure surgically here we should not
+	// have disturbed the meaning of any other content in the file, but it
+	// might have a different JSON layout than before.
+	// We'll create a new file with a different name first and then rename
+	// it over the old file in order to make the change as atomically as
+	// the underlying OS/filesystem will allow.
+	{
+		dir, file := filepath.Split(filename)
+		f, err := ioutil.TempFile(dir, file)
+		if err != nil {
+			return fmt.Errorf("cannot create temporary file to update credentials: %s", err)
+		}
+		tmpName := f.Name()
+		moved := false
+		defer func(f *os.File, name string) {
+			// Remove the temporary file if it hasn't been moved yet. We're
+			// ignoring errors here because there's nothing we can do about
+			// them anyway.
+			if !moved {
+				os.Remove(name)
+			}
+		}(f, tmpName)
+
+		// Write the credentials to the temporary file, then immediately close
+		// it, whether or not the write succeeds.
+		_, err = f.Write(newSrc)
+		f.Close()
+		if err != nil {
+			return fmt.Errorf("cannot write to temporary file %s: %s", tmpName, err)
+		}
+
+		// Temporary file now replaces the original file, as atomically as
+		// possible. (At the very least, we should not end up with a file
+		// containing only a partial JSON object.)
+		err = replacefile.AtomicRename(tmpName, filename)
+		if err != nil {
+			return fmt.Errorf("failed to replace %s with temporary file %s: %s", filename, tmpName, err)
+		}
+
+		// Credentials file should be readable only by its owner. (This may
+		// not be effective on all platforms, but should at least work on
+		// Unix-like targets and should be harmless elsewhere.)
+		if err := os.Chmod(filename, 0600); err != nil {
+			return fmt.Errorf("cannot set mode for credentials file %s: %s", filename, err)
+		}
+
+		moved = true
+	}
+
+	if new != nil {
+		s.configured[host] = new.ToStore()
+	} else {
+		delete(s.configured, host)
+	}
+
+	return nil
+}
+
+// readHostsInCredentialsFile discovers which hosts have credentials configured
+// in the credentials file specifically, as opposed to in any other CLI
+// config file.
+//
+// If the credentials file isn't present or is unreadable for any reason then
+// this returns an empty set, reflecting that effectively no credentials are
+// stored there.
+func readHostsInCredentialsFile(filename string) map[svchost.Hostname]struct{} {
+	src, err := ioutil.ReadFile(filename)
+	if err != nil {
+		return nil
+	}
+
+	var raw map[string]interface{}
+	err = json.Unmarshal(src, &raw)
+	if err != nil {
+		return nil
+	}
+
+	rawCredsI, ok := raw["credentials"]
+	if !ok {
+		return nil
+	}
+	rawCredsMap, ok := rawCredsI.(map[string]interface{})
+	if !ok {
+		return nil
+	}
+
+	ret := make(map[svchost.Hostname]struct{})
+	for givenHost := range rawCredsMap {
+		host, err := svchost.ForComparison(givenHost)
+		if err != nil {
+			// We expect the config was already validated by the time we get
+			// here, so we'll just ignore invalid hostnames.
+			continue
+		}
+		ret[host] = struct{}{}
+	}
+	return ret
+}
+
+// ErrUnwritableHostCredentials is an error type that is returned when a caller
+// tries to write credentials for a host that has existing credentials configured
+// in a file that we cannot automatically update.
+type ErrUnwritableHostCredentials svchost.Hostname
+
+func (err ErrUnwritableHostCredentials) Error() string {
+	return fmt.Sprintf("cannot change credentials for %s: existing manually-configured credentials in a CLI config file", svchost.Hostname(err).ForDisplay())
+}
+
+// Hostname returns the host that could not be written.
+func (err ErrUnwritableHostCredentials) Hostname() svchost.Hostname {
+	return svchost.Hostname(err)
+}
+
+// CredentialsLocation describes a type of storage used for the credentials
+// for a particular hostname.
+type CredentialsLocation rune
+
+const (
+	// CredentialsNotAvailable means that we know that there are no credential
+	// available for the host.
+	//
+	// Note that CredentialsViaHelper might also lead to no credentials being
+	// available, depending on how the helper answers when we request credentials
+	// from it.
+	CredentialsNotAvailable CredentialsLocation = 0
+
+	// CredentialsInPrimaryFile means that there is already a credentials object
+	// for the host in the credentials.tfrc.json file.
+	CredentialsInPrimaryFile CredentialsLocation = 'P'
+
+	// CredentialsInOtherFile means that there is already a credentials object
+	// for the host in a CLI config file other than credentials.tfrc.json.
+	CredentialsInOtherFile CredentialsLocation = 'O'
+
+	// CredentialsViaHelper indicates that no statically-configured credentials
+	// are available for the host but a helper program is available that may
+	// or may not have credentials for the host.
+	CredentialsViaHelper CredentialsLocation = 'H'
+)
diff --git a/v1.5.7/internal/command/cliconfig/credentials_test.go b/v1.5.7/internal/command/cliconfig/credentials_test.go
new file mode 100644
index 0000000..2d15a13
--- /dev/null
+++ b/v1.5.7/internal/command/cliconfig/credentials_test.go
@@ -0,0 +1,475 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cliconfig
+
+import (
+	"net/http"
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+	svcauth "github.com/hashicorp/terraform-svchost/auth"
+)
+
+func TestCredentialsForHost(t *testing.T) {
+	credSrc := &CredentialsSource{
+		configured: map[svchost.Hostname]cty.Value{
+			"configured.example.com": cty.ObjectVal(map[string]cty.Value{
+				"token": cty.StringVal("configured"),
+			}),
+			"unused.example.com": cty.ObjectVal(map[string]cty.Value{
+				"token": cty.StringVal("incorrectly-configured"),
+			}),
+		},
+
+		// We'll use a static source to stand in for what would normally be
+		// a credentials helper program, since we're only testing the logic
+		// for choosing when to delegate to the helper here. The logic for
+		// interacting with a helper program is tested in the svcauth package.
+		helper: svcauth.StaticCredentialsSource(map[svchost.Hostname]map[string]interface{}{
+			"from-helper.example.com": {
+				"token": "from-helper",
+			},
+
+			// This should be shadowed by the "configured" entry with the same
+			// hostname above.
+			"configured.example.com": {
+				"token": "incorrectly-from-helper",
+			},
+		}),
+		helperType: "fake",
+	}
+
+	testReqAuthHeader := func(t *testing.T, creds svcauth.HostCredentials) string {
+		t.Helper()
+
+		if creds == nil {
+			return ""
+		}
+
+		req, err := http.NewRequest("GET", "http://example.com/", nil)
+		if err != nil {
+			t.Fatalf("cannot construct HTTP request: %s", err)
+		}
+		creds.PrepareRequest(req)
+		return req.Header.Get("Authorization")
+	}
+
+	t.Run("configured", func(t *testing.T) {
+		creds, err := credSrc.ForHost(svchost.Hostname("configured.example.com"))
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if got, want := testReqAuthHeader(t, creds), "Bearer configured"; got != want {
+			t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run("from helper", func(t *testing.T) {
+		creds, err := credSrc.ForHost(svchost.Hostname("from-helper.example.com"))
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if got, want := testReqAuthHeader(t, creds), "Bearer from-helper"; got != want {
+			t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run("not available", func(t *testing.T) {
+		creds, err := credSrc.ForHost(svchost.Hostname("unavailable.example.com"))
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if got, want := testReqAuthHeader(t, creds), ""; got != want {
+			t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run("set in environment", func(t *testing.T) {
+		envName := "TF_TOKEN_configured_example_com"
+		t.Cleanup(func() {
+			os.Unsetenv(envName)
+		})
+
+		expectedToken := "configured-by-env"
+		os.Setenv(envName, expectedToken)
+
+		creds, err := credSrc.ForHost(svchost.Hostname("configured.example.com"))
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+
+		if creds == nil {
+			t.Fatal("no credentials found")
+		}
+
+		if got := creds.Token(); got != expectedToken {
+			t.Errorf("wrong result\ngot: %s\nwant: %s", got, expectedToken)
+		}
+	})
+
+	t.Run("punycode name set in environment", func(t *testing.T) {
+		envName := "TF_TOKEN_env_xn--eckwd4c7cu47r2wf_com"
+		t.Cleanup(func() {
+			os.Unsetenv(envName)
+		})
+
+		expectedToken := "configured-by-env"
+		os.Setenv(envName, expectedToken)
+
+		hostname, _ := svchost.ForComparison("env.ドメイン名例.com")
+		creds, err := credSrc.ForHost(hostname)
+
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+
+		if creds == nil {
+			t.Fatal("no credentials found")
+		}
+
+		if got := creds.Token(); got != expectedToken {
+			t.Errorf("wrong result\ngot: %s\nwant: %s", got, expectedToken)
+		}
+	})
+
+	t.Run("hyphens can be encoded as double underscores", func(t *testing.T) {
+		envName := "TF_TOKEN_env_xn____caf__dma_fr"
+		expectedToken := "configured-by-fallback"
+		t.Cleanup(func() {
+			os.Unsetenv(envName)
+		})
+
+		os.Setenv(envName, expectedToken)
+
+		hostname, _ := svchost.ForComparison("env.café.fr")
+		creds, err := credSrc.ForHost(hostname)
+
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+
+		if creds == nil {
+			t.Fatal("no credentials found")
+		}
+
+		if got := creds.Token(); got != expectedToken {
+			t.Errorf("wrong result\ngot: %s\nwant: %s", got, expectedToken)
+		}
+	})
+
+	t.Run("periods are ok", func(t *testing.T) {
+		envName := "TF_TOKEN_configured.example.com"
+		expectedToken := "configured-by-env"
+		t.Cleanup(func() {
+			os.Unsetenv(envName)
+		})
+
+		os.Setenv(envName, expectedToken)
+
+		hostname, _ := svchost.ForComparison("configured.example.com")
+		creds, err := credSrc.ForHost(hostname)
+
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+
+		if creds == nil {
+			t.Fatal("no credentials found")
+		}
+
+		if got := creds.Token(); got != expectedToken {
+			t.Errorf("wrong result\ngot: %s\nwant: %s", got, expectedToken)
+		}
+	})
+
+	t.Run("casing is insensitive", func(t *testing.T) {
+		envName := "TF_TOKEN_CONFIGUREDUPPERCASE_EXAMPLE_COM"
+		expectedToken := "configured-by-env"
+
+		os.Setenv(envName, expectedToken)
+		t.Cleanup(func() {
+			os.Unsetenv(envName)
+		})
+
+		hostname, _ := svchost.ForComparison("configureduppercase.example.com")
+		creds, err := credSrc.ForHost(hostname)
+
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+
+		if creds == nil {
+			t.Fatal("no credentials found")
+		}
+
+		if got := creds.Token(); got != expectedToken {
+			t.Errorf("wrong result\ngot: %s\nwant: %s", got, expectedToken)
+		}
+	})
+}
+
+func TestCredentialsStoreForget(t *testing.T) {
+	d := t.TempDir()
+
+	mockCredsFilename := filepath.Join(d, "credentials.tfrc.json")
+
+	cfg := &Config{
+		// This simulates there being a credentials block manually configured
+		// in some file _other than_ credentials.tfrc.json.
+		Credentials: map[string]map[string]interface{}{
+			"manually-configured.example.com": {
+				"token": "manually-configured",
+			},
+		},
+	}
+
+	// We'll initially use a credentials source with no credentials helper at
+	// all, and thus with credentials stored in the credentials file.
+	credSrc := cfg.credentialsSource(
+		"", nil,
+		mockCredsFilename,
+	)
+
+	testReqAuthHeader := func(t *testing.T, creds svcauth.HostCredentials) string {
+		t.Helper()
+
+		if creds == nil {
+			return ""
+		}
+
+		req, err := http.NewRequest("GET", "http://example.com/", nil)
+		if err != nil {
+			t.Fatalf("cannot construct HTTP request: %s", err)
+		}
+		creds.PrepareRequest(req)
+		return req.Header.Get("Authorization")
+	}
+
+	// Because these store/forget calls have side-effects, we'll bail out with
+	// t.Fatal (or equivalent) as soon as anything unexpected happens.
+	// Otherwise downstream tests might fail in confusing ways.
+	{
+		err := credSrc.StoreForHost(
+			svchost.Hostname("manually-configured.example.com"),
+			svcauth.HostCredentialsToken("not-manually-configured"),
+		)
+		if err == nil {
+			t.Fatalf("successfully stored for manually-configured; want error")
+		}
+		if _, ok := err.(ErrUnwritableHostCredentials); !ok {
+			t.Fatalf("wrong error type %T; want ErrUnwritableHostCredentials", err)
+		}
+	}
+	{
+		err := credSrc.ForgetForHost(
+			svchost.Hostname("manually-configured.example.com"),
+		)
+		if err == nil {
+			t.Fatalf("successfully forgot for manually-configured; want error")
+		}
+		if _, ok := err.(ErrUnwritableHostCredentials); !ok {
+			t.Fatalf("wrong error type %T; want ErrUnwritableHostCredentials", err)
+		}
+	}
+	{
+		// We don't have a credentials file at all yet, so this first call
+		// must create it.
+		err := credSrc.StoreForHost(
+			svchost.Hostname("stored-locally.example.com"),
+			svcauth.HostCredentialsToken("stored-locally"),
+		)
+		if err != nil {
+			t.Fatalf("unexpected error storing locally: %s", err)
+		}
+
+		creds, err := credSrc.ForHost(svchost.Hostname("stored-locally.example.com"))
+		if err != nil {
+			t.Fatalf("failed to read back stored-locally credentials: %s", err)
+		}
+
+		if got, want := testReqAuthHeader(t, creds), "Bearer stored-locally"; got != want {
+			t.Fatalf("wrong header value for stored-locally\ngot:  %s\nwant: %s", got, want)
+		}
+
+		got := readHostsInCredentialsFile(mockCredsFilename)
+		want := map[svchost.Hostname]struct{}{
+			svchost.Hostname("stored-locally.example.com"): struct{}{},
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Fatalf("wrong credentials file content\n%s", diff)
+		}
+	}
+
+	// Now we'll switch to having a credential helper active.
+	// If we were loading the real CLI config from disk here then this
+	// entry would already be in cfg.Credentials, but we need to fake that
+	// in the test because we're constructing this *Config value directly.
+	cfg.Credentials["stored-locally.example.com"] = map[string]interface{}{
+		"token": "stored-locally",
+	}
+	mockHelper := &mockCredentialsHelper{current: make(map[svchost.Hostname]cty.Value)}
+	credSrc = cfg.credentialsSource(
+		"mock", mockHelper,
+		mockCredsFilename,
+	)
+	{
+		err := credSrc.StoreForHost(
+			svchost.Hostname("manually-configured.example.com"),
+			svcauth.HostCredentialsToken("not-manually-configured"),
+		)
+		if err == nil {
+			t.Fatalf("successfully stored for manually-configured with helper active; want error")
+		}
+	}
+	{
+		err := credSrc.StoreForHost(
+			svchost.Hostname("stored-in-helper.example.com"),
+			svcauth.HostCredentialsToken("stored-in-helper"),
+		)
+		if err != nil {
+			t.Fatalf("unexpected error storing in helper: %s", err)
+		}
+
+		creds, err := credSrc.ForHost(svchost.Hostname("stored-in-helper.example.com"))
+		if err != nil {
+			t.Fatalf("failed to read back stored-in-helper credentials: %s", err)
+		}
+
+		if got, want := testReqAuthHeader(t, creds), "Bearer stored-in-helper"; got != want {
+			t.Fatalf("wrong header value for stored-in-helper\ngot:  %s\nwant: %s", got, want)
+		}
+
+		// Nothing should have changed in the saved credentials file
+		got := readHostsInCredentialsFile(mockCredsFilename)
+		want := map[svchost.Hostname]struct{}{
+			svchost.Hostname("stored-locally.example.com"): struct{}{},
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Fatalf("wrong credentials file content\n%s", diff)
+		}
+	}
+	{
+		// Because stored-locally is already in the credentials file, a new
+		// store should be sent there rather than to the credentials helper.
+		err := credSrc.StoreForHost(
+			svchost.Hostname("stored-locally.example.com"),
+			svcauth.HostCredentialsToken("stored-locally-again"),
+		)
+		if err != nil {
+			t.Fatalf("unexpected error storing locally again: %s", err)
+		}
+
+		creds, err := credSrc.ForHost(svchost.Hostname("stored-locally.example.com"))
+		if err != nil {
+			t.Fatalf("failed to read back stored-locally credentials: %s", err)
+		}
+
+		if got, want := testReqAuthHeader(t, creds), "Bearer stored-locally-again"; got != want {
+			t.Fatalf("wrong header value for stored-locally\ngot:  %s\nwant: %s", got, want)
+		}
+	}
+	{
+		// Forgetting a host already in the credentials file should remove it
+		// from the credentials file, not from the helper.
+		err := credSrc.ForgetForHost(
+			svchost.Hostname("stored-locally.example.com"),
+		)
+		if err != nil {
+			t.Fatalf("unexpected error forgetting locally: %s", err)
+		}
+
+		creds, err := credSrc.ForHost(svchost.Hostname("stored-locally.example.com"))
+		if err != nil {
+			t.Fatalf("failed to read back stored-locally credentials: %s", err)
+		}
+
+		if got, want := testReqAuthHeader(t, creds), ""; got != want {
+			t.Fatalf("wrong header value for stored-locally\ngot:  %s\nwant: %s", got, want)
+		}
+
+		// Should not be present in the credentials file anymore
+		got := readHostsInCredentialsFile(mockCredsFilename)
+		want := map[svchost.Hostname]struct{}{}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Fatalf("wrong credentials file content\n%s", diff)
+		}
+	}
+	{
+		err := credSrc.ForgetForHost(
+			svchost.Hostname("stored-in-helper.example.com"),
+		)
+		if err != nil {
+			t.Fatalf("unexpected error forgetting in helper: %s", err)
+		}
+
+		creds, err := credSrc.ForHost(svchost.Hostname("stored-in-helper.example.com"))
+		if err != nil {
+			t.Fatalf("failed to read back stored-in-helper credentials: %s", err)
+		}
+
+		if got, want := testReqAuthHeader(t, creds), ""; got != want {
+			t.Fatalf("wrong header value for stored-in-helper\ngot:  %s\nwant: %s", got, want)
+		}
+	}
+
+	{
+		// Finally, the log in our mock helper should show that it was only
+		// asked to deal with stored-in-helper, not stored-locally.
+		got := mockHelper.log
+		want := []mockCredentialsHelperChange{
+			{
+				Host:   svchost.Hostname("stored-in-helper.example.com"),
+				Action: "store",
+			},
+			{
+				Host:   svchost.Hostname("stored-in-helper.example.com"),
+				Action: "forget",
+			},
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("unexpected credentials helper operation log\n%s", diff)
+		}
+	}
+}
+
+type mockCredentialsHelperChange struct {
+	Host   svchost.Hostname
+	Action string
+}
+
+type mockCredentialsHelper struct {
+	current map[svchost.Hostname]cty.Value
+	log     []mockCredentialsHelperChange
+}
+
+// Assertion that mockCredentialsHelper implements svcauth.CredentialsSource
+var _ svcauth.CredentialsSource = (*mockCredentialsHelper)(nil)
+
+func (s *mockCredentialsHelper) ForHost(hostname svchost.Hostname) (svcauth.HostCredentials, error) {
+	v, ok := s.current[hostname]
+	if !ok {
+		return nil, nil
+	}
+	return svcauth.HostCredentialsFromObject(v), nil
+}
+
+func (s *mockCredentialsHelper) StoreForHost(hostname svchost.Hostname, new svcauth.HostCredentialsWritable) error {
+	s.log = append(s.log, mockCredentialsHelperChange{
+		Host:   hostname,
+		Action: "store",
+	})
+	s.current[hostname] = new.ToStore()
+	return nil
+}
+
+func (s *mockCredentialsHelper) ForgetForHost(hostname svchost.Hostname) error {
+	s.log = append(s.log, mockCredentialsHelperChange{
+		Host:   hostname,
+		Action: "forget",
+	})
+	delete(s.current, hostname)
+	return nil
+}
diff --git a/v1.5.7/internal/command/cliconfig/provider_installation.go b/v1.5.7/internal/command/cliconfig/provider_installation.go
new file mode 100644
index 0000000..a082e29
--- /dev/null
+++ b/v1.5.7/internal/command/cliconfig/provider_installation.go
@@ -0,0 +1,340 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cliconfig
+
+import (
+	"fmt"
+	"path/filepath"
+
+	"github.com/hashicorp/hcl"
+	hclast "github.com/hashicorp/hcl/hcl/ast"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ProviderInstallation is the structure of the "provider_installation"
+// nested block within the CLI configuration.
+type ProviderInstallation struct {
+	Methods []*ProviderInstallationMethod
+
+	// DevOverrides allows overriding the normal selection process for
+	// a particular subset of providers to force using a particular
+	// local directory and disregard version numbering altogether.
+	// This is here to allow provider developers to conveniently test
+	// local builds of their plugins in a development environment, without
+	// having to fuss with version constraints, dependency lock files, and
+	// so forth.
+	//
+	// This is _not_ intended for "production" use because it bypasses the
+	// usual version selection and checksum verification mechanisms for
+	// the providers in question. To make that intent/effect clearer, some
+	// Terraform commands emit warnings when overrides are present. Local
+	// mirror directories are a better way to distribute "released"
+	// providers, because they are still subject to version constraints and
+	// checksum verification.
+	DevOverrides map[addrs.Provider]getproviders.PackageLocalDir
+}
+
+// decodeProviderInstallationFromConfig uses the HCL AST API directly to
+// decode "provider_installation" blocks from the given file.
+//
+// This uses the HCL AST directly, rather than HCL's decoder, because the
+// intended configuration structure can't be represented using the HCL
+// decoder's struct tags. This structure is intended as something that would
+// be relatively easier to deal with in HCL 2 once we eventually migrate
+// CLI config over to that, and so this function is stricter than HCL 1's
+// decoder would be in terms of exactly what configuration shape it is
+// expecting.
+//
+// Note that this function wants the top-level file object which might or
+// might not contain provider_installation blocks, not a provider_installation
+// block directly itself.
+func decodeProviderInstallationFromConfig(hclFile *hclast.File) ([]*ProviderInstallation, tfdiags.Diagnostics) {
+	var ret []*ProviderInstallation
+	var diags tfdiags.Diagnostics
+
+	root := hclFile.Node.(*hclast.ObjectList)
+
+	// This is a rather odd hybrid: it's a HCL 2-like decode implemented using
+	// the HCL 1 AST API. That makes it a bit awkward in places, but it allows
+	// us to mimick the strictness of HCL 2 (making a later migration easier)
+	// and to support a block structure that the HCL 1 decoder can't represent.
+	for _, block := range root.Items {
+		if block.Keys[0].Token.Value() != "provider_installation" {
+			continue
+		}
+		// HCL only tracks whether the input was JSON or native syntax inside
+		// individual tokens, so we'll use our block type token to decide
+		// and assume that the rest of the block must be written in the same
+		// syntax, because syntax is a whole-file idea.
+		isJSON := block.Keys[0].Token.JSON
+		if block.Assign.Line != 0 && !isJSON {
+			// Seems to be an attribute rather than a block
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid provider_installation block",
+				fmt.Sprintf("The provider_installation block at %s must not be introduced with an equals sign.", block.Pos()),
+			))
+			continue
+		}
+		if len(block.Keys) > 1 && !isJSON {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid provider_installation block",
+				fmt.Sprintf("The provider_installation block at %s must not have any labels.", block.Pos()),
+			))
+		}
+
+		pi := &ProviderInstallation{}
+		devOverrides := make(map[addrs.Provider]getproviders.PackageLocalDir)
+
+		body, ok := block.Val.(*hclast.ObjectType)
+		if !ok {
+			// We can't get in here with native HCL syntax because we
+			// already checked above that we're using block syntax, but
+			// if we're reading JSON then our value could potentially be
+			// anything.
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid provider_installation block",
+				fmt.Sprintf("The provider_installation block at %s must not be introduced with an equals sign.", block.Pos()),
+			))
+			continue
+		}
+
+		for _, methodBlock := range body.List.Items {
+			if methodBlock.Assign.Line != 0 && !isJSON {
+				// Seems to be an attribute rather than a block
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid provider_installation method block",
+					fmt.Sprintf("The items inside the provider_installation block at %s must all be blocks.", block.Pos()),
+				))
+				continue
+			}
+			if len(methodBlock.Keys) > 1 && !isJSON {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid provider_installation method block",
+					fmt.Sprintf("The blocks inside the provider_installation block at %s may not have any labels.", block.Pos()),
+				))
+			}
+
+			methodBody, ok := methodBlock.Val.(*hclast.ObjectType)
+			if !ok {
+				// We can't get in here with native HCL syntax because we
+				// already checked above that we're using block syntax, but
+				// if we're reading JSON then our value could potentially be
+				// anything.
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid provider_installation method block",
+					fmt.Sprintf("The items inside the provider_installation block at %s must all be blocks.", block.Pos()),
+				))
+				continue
+			}
+
+			methodTypeStr := methodBlock.Keys[0].Token.Value().(string)
+			var location ProviderInstallationLocation
+			var include, exclude []string
+			switch methodTypeStr {
+			case "direct":
+				type BodyContent struct {
+					Include []string `hcl:"include"`
+					Exclude []string `hcl:"exclude"`
+				}
+				var bodyContent BodyContent
+				err := hcl.DecodeObject(&bodyContent, methodBody)
+				if err != nil {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Invalid provider_installation method block",
+						fmt.Sprintf("Invalid %s block at %s: %s.", methodTypeStr, block.Pos(), err),
+					))
+					continue
+				}
+				location = ProviderInstallationDirect
+				include = bodyContent.Include
+				exclude = bodyContent.Exclude
+			case "filesystem_mirror":
+				type BodyContent struct {
+					Path    string   `hcl:"path"`
+					Include []string `hcl:"include"`
+					Exclude []string `hcl:"exclude"`
+				}
+				var bodyContent BodyContent
+				err := hcl.DecodeObject(&bodyContent, methodBody)
+				if err != nil {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Invalid provider_installation method block",
+						fmt.Sprintf("Invalid %s block at %s: %s.", methodTypeStr, block.Pos(), err),
+					))
+					continue
+				}
+				if bodyContent.Path == "" {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Invalid provider_installation method block",
+						fmt.Sprintf("Invalid %s block at %s: \"path\" argument is required.", methodTypeStr, block.Pos()),
+					))
+					continue
+				}
+				location = ProviderInstallationFilesystemMirror(bodyContent.Path)
+				include = bodyContent.Include
+				exclude = bodyContent.Exclude
+			case "network_mirror":
+				type BodyContent struct {
+					URL     string   `hcl:"url"`
+					Include []string `hcl:"include"`
+					Exclude []string `hcl:"exclude"`
+				}
+				var bodyContent BodyContent
+				err := hcl.DecodeObject(&bodyContent, methodBody)
+				if err != nil {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Invalid provider_installation method block",
+						fmt.Sprintf("Invalid %s block at %s: %s.", methodTypeStr, block.Pos(), err),
+					))
+					continue
+				}
+				if bodyContent.URL == "" {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Invalid provider_installation method block",
+						fmt.Sprintf("Invalid %s block at %s: \"url\" argument is required.", methodTypeStr, block.Pos()),
+					))
+					continue
+				}
+				location = ProviderInstallationNetworkMirror(bodyContent.URL)
+				include = bodyContent.Include
+				exclude = bodyContent.Exclude
+			case "dev_overrides":
+				if len(pi.Methods) > 0 {
+					// We require dev_overrides to appear first if it's present,
+					// because dev_overrides effectively bypass the normal
+					// selection process for a particular provider altogether,
+					// and so they don't participate in the usual
+					// include/exclude arguments and priority ordering.
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Invalid provider_installation method block",
+						fmt.Sprintf("The dev_overrides block at at %s must appear before all other installation methods, because development overrides always have the highest priority.", methodBlock.Pos()),
+					))
+					continue
+				}
+
+				// The content of a dev_overrides block is a mapping from
+				// provider source addresses to local filesystem paths. To get
+				// our decoding started, we'll use the normal HCL decoder to
+				// populate a map of strings and then decode further from
+				// that.
+				var rawItems map[string]string
+				err := hcl.DecodeObject(&rawItems, methodBody)
+				if err != nil {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Invalid provider_installation method block",
+						fmt.Sprintf("Invalid %s block at %s: %s.", methodTypeStr, block.Pos(), err),
+					))
+					continue
+				}
+
+				for rawAddr, rawPath := range rawItems {
+					addr, moreDiags := addrs.ParseProviderSourceString(rawAddr)
+					if moreDiags.HasErrors() {
+						diags = diags.Append(tfdiags.Sourceless(
+							tfdiags.Error,
+							"Invalid provider installation dev overrides",
+							fmt.Sprintf("The entry %q in %s is not a valid provider source string.\n\n%s", rawAddr, block.Pos(), moreDiags.Err().Error()),
+						))
+						continue
+					}
+					dirPath := filepath.Clean(rawPath)
+					devOverrides[addr] = getproviders.PackageLocalDir(dirPath)
+				}
+
+				continue // We won't add anything to pi.Methods for this one
+
+			default:
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid provider_installation method block",
+					fmt.Sprintf("Unknown provider installation method %q at %s.", methodTypeStr, methodBlock.Pos()),
+				))
+				continue
+			}
+
+			pi.Methods = append(pi.Methods, &ProviderInstallationMethod{
+				Location: location,
+				Include:  include,
+				Exclude:  exclude,
+			})
+		}
+
+		if len(devOverrides) > 0 {
+			pi.DevOverrides = devOverrides
+		}
+
+		ret = append(ret, pi)
+	}
+
+	return ret, diags
+}
+
+// ProviderInstallationMethod represents an installation method block inside
+// a provider_installation block.
+type ProviderInstallationMethod struct {
+	Location ProviderInstallationLocation
+	Include  []string `hcl:"include"`
+	Exclude  []string `hcl:"exclude"`
+}
+
+// ProviderInstallationLocation is an interface type representing the
+// different installation location types. The concrete implementations of
+// this interface are:
+//
+//   - [ProviderInstallationDirect]:                 install from the provider's origin registry
+//   - [ProviderInstallationFilesystemMirror] (dir): install from a local filesystem mirror
+//   - [ProviderInstallationNetworkMirror] (host):   install from a network mirror
+type ProviderInstallationLocation interface {
+	providerInstallationLocation()
+}
+
+type providerInstallationDirect [0]byte
+
+func (i providerInstallationDirect) providerInstallationLocation() {}
+
+// ProviderInstallationDirect is a ProviderInstallationSourceLocation
+// representing installation from a provider's origin registry.
+var ProviderInstallationDirect ProviderInstallationLocation = providerInstallationDirect{}
+
+func (i providerInstallationDirect) GoString() string {
+	return "cliconfig.ProviderInstallationDirect"
+}
+
+// ProviderInstallationFilesystemMirror is a ProviderInstallationSourceLocation
+// representing installation from a particular local filesystem mirror. The
+// string value is the filesystem path to the mirror directory.
+type ProviderInstallationFilesystemMirror string
+
+func (i ProviderInstallationFilesystemMirror) providerInstallationLocation() {}
+
+func (i ProviderInstallationFilesystemMirror) GoString() string {
+	return fmt.Sprintf("cliconfig.ProviderInstallationFilesystemMirror(%q)", i)
+}
+
+// ProviderInstallationNetworkMirror is a ProviderInstallationSourceLocation
+// representing installation from a particular local network mirror. The
+// string value is the HTTP base URL exactly as written in the configuration,
+// without any normalization.
+type ProviderInstallationNetworkMirror string
+
+func (i ProviderInstallationNetworkMirror) providerInstallationLocation() {}
+
+func (i ProviderInstallationNetworkMirror) GoString() string {
+	return fmt.Sprintf("cliconfig.ProviderInstallationNetworkMirror(%q)", i)
+}
diff --git a/v1.5.7/internal/command/cliconfig/provider_installation_test.go b/v1.5.7/internal/command/cliconfig/provider_installation_test.go
new file mode 100644
index 0000000..84370c1
--- /dev/null
+++ b/v1.5.7/internal/command/cliconfig/provider_installation_test.go
@@ -0,0 +1,80 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package cliconfig
+
+import (
+	"path/filepath"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+func TestLoadConfig_providerInstallation(t *testing.T) {
+	for _, configFile := range []string{"provider-installation", "provider-installation.json"} {
+		t.Run(configFile, func(t *testing.T) {
+			got, diags := loadConfigFile(filepath.Join(fixtureDir, configFile))
+			if diags.HasErrors() {
+				t.Errorf("unexpected diagnostics: %s", diags.Err().Error())
+			}
+
+			want := &Config{
+				ProviderInstallation: []*ProviderInstallation{
+					{
+						Methods: []*ProviderInstallationMethod{
+							{
+								Location: ProviderInstallationFilesystemMirror("/tmp/example1"),
+								Include:  []string{"example.com/*/*"},
+							},
+							{
+								Location: ProviderInstallationNetworkMirror("https://tf-Mirror.example.com/"),
+								Include:  []string{"registry.terraform.io/*/*"},
+								Exclude:  []string{"registry.Terraform.io/foobar/*"},
+							},
+							{
+								Location: ProviderInstallationFilesystemMirror("/tmp/example2"),
+							},
+							{
+								Location: ProviderInstallationDirect,
+								Exclude:  []string{"example.com/*/*"},
+							},
+						},
+
+						DevOverrides: map[addrs.Provider]getproviders.PackageLocalDir{
+							addrs.MustParseProviderSourceString("hashicorp/boop"):  getproviders.PackageLocalDir(filepath.FromSlash("/tmp/boop")),
+							addrs.MustParseProviderSourceString("hashicorp/blorp"): getproviders.PackageLocalDir(filepath.FromSlash("/tmp/blorp")),
+						},
+					},
+				},
+			}
+
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestLoadConfig_providerInstallationErrors(t *testing.T) {
+	_, diags := loadConfigFile(filepath.Join(fixtureDir, "provider-installation-errors"))
+	want := `7 problems:
+
+- Invalid provider_installation method block: Unknown provider installation method "not_a_thing" at 2:3.
+- Invalid provider_installation method block: Invalid filesystem_mirror block at 1:1: "path" argument is required.
+- Invalid provider_installation method block: Invalid network_mirror block at 1:1: "url" argument is required.
+- Invalid provider_installation method block: The items inside the provider_installation block at 1:1 must all be blocks.
+- Invalid provider_installation method block: The blocks inside the provider_installation block at 1:1 may not have any labels.
+- Invalid provider_installation block: The provider_installation block at 9:1 must not have any labels.
+- Invalid provider_installation block: The provider_installation block at 11:1 must not be introduced with an equals sign.`
+
+	// The above error messages include only line/column location information
+	// and not file location information because HCL 1 does not store
+	// information about the filename a location belongs to. (There is a field
+	// for it in token.Pos but it's always an empty string in practice.)
+
+	if got := diags.Err().Error(); got != want {
+		t.Errorf("wrong diagnostics\ngot:\n%s\nwant:\n%s", got, want)
+	}
+}
diff --git a/v1.5.7/internal/command/cliconfig/testdata/config b/v1.5.7/internal/command/cliconfig/testdata/config
new file mode 100644
index 0000000..4cc9899
--- /dev/null
+++ b/v1.5.7/internal/command/cliconfig/testdata/config
@@ -0,0 +1,4 @@
+providers {
+  aws = "foo"
+  do = "bar"
+}
diff --git a/v1.5.7/internal/command/cliconfig/testdata/config-env b/v1.5.7/internal/command/cliconfig/testdata/config-env
new file mode 100644
index 0000000..e127b13
--- /dev/null
+++ b/v1.5.7/internal/command/cliconfig/testdata/config-env
@@ -0,0 +1,8 @@
+providers {
+  aws = "$TFTEST"
+  google = "bar"
+}
+
+provisioners {
+  local = "$TFTEST"
+}
diff --git a/v1.5.7/internal/command/cliconfig/testdata/credentials b/v1.5.7/internal/command/cliconfig/testdata/credentials
new file mode 100644
index 0000000..404c491
--- /dev/null
+++ b/v1.5.7/internal/command/cliconfig/testdata/credentials
@@ -0,0 +1,17 @@
+
+credentials "example.com" {
+  token = "foo the bar baz"
+}
+
+credentials "example.net" {
+  # Username and password are not currently supported, but we want to tolerate
+  # unknown keys in case future versions add new keys when both old and new
+  # versions of Terraform are installed on a system, sharing the same
+  # CLI config.
+  username = "foo"
+  password = "baz"
+}
+
+credentials_helper "foo" {
+  args = ["bar", "baz"]
+}
diff --git a/v1.5.7/internal/command/cliconfig/testdata/hosts b/v1.5.7/internal/command/cliconfig/testdata/hosts
new file mode 100644
index 0000000..1726404
--- /dev/null
+++ b/v1.5.7/internal/command/cliconfig/testdata/hosts
@@ -0,0 +1,6 @@
+
+host "example.com" {
+  services = {
+    "modules.v1" = "https://example.com/",
+  }
+}
diff --git a/v1.5.7/internal/command/cliconfig/testdata/provider-installation b/v1.5.7/internal/command/cliconfig/testdata/provider-installation
new file mode 100644
index 0000000..1fa5dbd
--- /dev/null
+++ b/v1.5.7/internal/command/cliconfig/testdata/provider-installation
@@ -0,0 +1,21 @@
+provider_installation {
+  dev_overrides {
+    "hashicorp/boop" = "/tmp/bloop/../boop"
+    "hashicorp/blorp" = "/tmp/blorp"
+  }
+  filesystem_mirror {
+    path    = "/tmp/example1"
+    include = ["example.com/*/*"]
+  }
+  network_mirror {
+    url     = "https://tf-Mirror.example.com/"
+    include = ["registry.terraform.io/*/*"]
+    exclude = ["registry.Terraform.io/foobar/*"]
+  }
+  filesystem_mirror {
+    path    = "/tmp/example2"
+  }
+  direct {
+    exclude = ["example.com/*/*"]
+  }
+}
diff --git a/v1.5.7/internal/command/cliconfig/testdata/provider-installation-errors b/v1.5.7/internal/command/cliconfig/testdata/provider-installation-errors
new file mode 100644
index 0000000..8cf634e
--- /dev/null
+++ b/v1.5.7/internal/command/cliconfig/testdata/provider-installation-errors
@@ -0,0 +1,11 @@
+provider_installation {
+  not_a_thing {} # unknown source type
+  filesystem_mirror {} # missing "path" argument
+  network_mirror {} # missing "host" argument
+  direct = {} # should be a block, not an argument
+  direct "what" {} # should not have a label
+}
+
+provider_installation "what" {} # should not have a label
+
+provider_installation = {} # should be a block, not an argument
diff --git a/v1.5.7/internal/command/cliconfig/testdata/provider-installation.json b/v1.5.7/internal/command/cliconfig/testdata/provider-installation.json
new file mode 100644
index 0000000..c640113
--- /dev/null
+++ b/v1.5.7/internal/command/cliconfig/testdata/provider-installation.json
@@ -0,0 +1,23 @@
+{
+  "provider_installation": {
+    "dev_overrides": {
+      "hashicorp/boop": "/tmp/bloop/../boop",
+      "hashicorp/blorp": "/tmp/blorp"
+    },
+    "filesystem_mirror": [{
+      "path": "/tmp/example1",
+      "include": ["example.com/*/*"]
+    }],
+    "network_mirror": [{
+      "url": "https://tf-Mirror.example.com/",
+      "include": ["registry.terraform.io/*/*"],
+      "exclude": ["registry.Terraform.io/foobar/*"]
+    }],
+    "filesystem_mirror": [{
+      "path": "/tmp/example2"
+    }],
+    "direct": [{
+      "exclude": ["example.com/*/*"]
+    }]
+  }
+}
diff --git a/v1.5.7/internal/command/clistate/local_state.go b/v1.5.7/internal/command/clistate/local_state.go
new file mode 100644
index 0000000..bd2ce60
--- /dev/null
+++ b/v1.5.7/internal/command/clistate/local_state.go
@@ -0,0 +1,317 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package clistate
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"sync"
+	"time"
+
+	multierror "github.com/hashicorp/go-multierror"
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+// LocalState manages a state storage that is local to the filesystem.
+type LocalState struct {
+	mu sync.Mutex
+
+	// Path is the path to read the state from. PathOut is the path to
+	// write the state to. If PathOut is not specified, Path will be used.
+	// If PathOut already exists, it will be overwritten.
+	Path    string
+	PathOut string
+
+	// the file handle corresponding to PathOut
+	stateFileOut *os.File
+
+	// While the stateFileOut will correspond to the lock directly,
+	// store and check the lock ID to maintain a strict state.Locker
+	// implementation.
+	lockID string
+
+	// created is set to true if stateFileOut didn't exist before we created it.
+	// This is mostly so we can clean up empty files during tests, but doesn't
+	// hurt to remove file we never wrote to.
+	created bool
+
+	state     *terraform.State
+	readState *terraform.State
+	written   bool
+}
+
+// SetState will force a specific state in-memory for this local state.
+func (s *LocalState) SetState(state *terraform.State) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	s.state = state.DeepCopy()
+	s.readState = state.DeepCopy()
+}
+
+// StateReader impl.
+func (s *LocalState) State() *terraform.State {
+	return s.state.DeepCopy()
+}
+
+// WriteState for LocalState always persists the state as well.
+// TODO: this should use a more robust method of writing state, by first
+// writing to a temp file on the same filesystem, and renaming the file over
+// the original.
+//
+// StateWriter impl.
+func (s *LocalState) WriteState(state *terraform.State) error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	if s.stateFileOut == nil {
+		if err := s.createStateFiles(); err != nil {
+			return nil
+		}
+	}
+	defer s.stateFileOut.Sync()
+
+	s.state = state.DeepCopy() // don't want mutations before we actually get this written to disk
+
+	if s.readState != nil && s.state != nil {
+		// We don't trust callers to properly manage serials. Instead, we assume
+		// that a WriteState is always for the next version after what was
+		// most recently read.
+		s.state.Serial = s.readState.Serial
+	}
+
+	if _, err := s.stateFileOut.Seek(0, io.SeekStart); err != nil {
+		return err
+	}
+	if err := s.stateFileOut.Truncate(0); err != nil {
+		return err
+	}
+
+	if state == nil {
+		// if we have no state, don't write anything else.
+		return nil
+	}
+
+	if !s.state.MarshalEqual(s.readState) {
+		s.state.Serial++
+	}
+
+	if err := terraform.WriteState(s.state, s.stateFileOut); err != nil {
+		return err
+	}
+
+	s.written = true
+	return nil
+}
+
+// PersistState for LocalState is a no-op since WriteState always persists.
+//
+// StatePersister impl.
+func (s *LocalState) PersistState() error {
+	return nil
+}
+
+// StateRefresher impl.
+func (s *LocalState) RefreshState() error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	if s.PathOut == "" {
+		s.PathOut = s.Path
+	}
+
+	var reader io.Reader
+
+	// The s.Path file is only OK to read if we have not written any state out
+	// (in which case the same state needs to be read in), and no state output file
+	// has been opened (possibly via a lock) or the input path is different
+	// than the output path.
+	// This is important for Windows, as if the input file is the same as the
+	// output file, and the output file has been locked already, we can't open
+	// the file again.
+	if !s.written && (s.stateFileOut == nil || s.Path != s.PathOut) {
+		// we haven't written a state file yet, so load from Path
+		f, err := os.Open(s.Path)
+		if err != nil {
+			// It is okay if the file doesn't exist, we treat that as a nil state
+			if !os.IsNotExist(err) {
+				return err
+			}
+
+			// we need a non-nil reader for ReadState and an empty buffer works
+			// to return EOF immediately
+			reader = bytes.NewBuffer(nil)
+
+		} else {
+			defer f.Close()
+			reader = f
+		}
+	} else {
+		// no state to refresh
+		if s.stateFileOut == nil {
+			return nil
+		}
+
+		// we have a state file, make sure we're at the start
+		s.stateFileOut.Seek(0, io.SeekStart)
+		reader = s.stateFileOut
+	}
+
+	state, err := terraform.ReadState(reader)
+	// if there's no state we just assign the nil return value
+	if err != nil && err != terraform.ErrNoState {
+		return err
+	}
+
+	s.state = state
+	s.readState = s.state.DeepCopy()
+	return nil
+}
+
+// Lock implements a local filesystem state.Locker.
+func (s *LocalState) Lock(info *statemgr.LockInfo) (string, error) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	if s.stateFileOut == nil {
+		if err := s.createStateFiles(); err != nil {
+			return "", err
+		}
+	}
+
+	if s.lockID != "" {
+		return "", fmt.Errorf("state %q already locked", s.stateFileOut.Name())
+	}
+
+	if err := s.lock(); err != nil {
+		info, infoErr := s.lockInfo()
+		if infoErr != nil {
+			err = multierror.Append(err, infoErr)
+		}
+
+		lockErr := &statemgr.LockError{
+			Info: info,
+			Err:  err,
+		}
+
+		return "", lockErr
+	}
+
+	s.lockID = info.ID
+	return s.lockID, s.writeLockInfo(info)
+}
+
+func (s *LocalState) Unlock(id string) error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	if s.lockID == "" {
+		return fmt.Errorf("LocalState not locked")
+	}
+
+	if id != s.lockID {
+		idErr := fmt.Errorf("invalid lock id: %q. current id: %q", id, s.lockID)
+		info, err := s.lockInfo()
+		if err != nil {
+			idErr = multierror.Append(idErr, err)
+		}
+
+		return &statemgr.LockError{
+			Err:  idErr,
+			Info: info,
+		}
+	}
+
+	os.Remove(s.lockInfoPath())
+
+	fileName := s.stateFileOut.Name()
+
+	unlockErr := s.unlock()
+
+	s.stateFileOut.Close()
+	s.stateFileOut = nil
+	s.lockID = ""
+
+	// clean up the state file if we created it an never wrote to it
+	stat, err := os.Stat(fileName)
+	if err == nil && stat.Size() == 0 && s.created {
+		os.Remove(fileName)
+	}
+
+	return unlockErr
+}
+
+// Open the state file, creating the directories and file as needed.
+func (s *LocalState) createStateFiles() error {
+	if s.PathOut == "" {
+		s.PathOut = s.Path
+	}
+
+	// yes this could race, but we only use it to clean up empty files
+	if _, err := os.Stat(s.PathOut); os.IsNotExist(err) {
+		s.created = true
+	}
+
+	// Create all the directories
+	if err := os.MkdirAll(filepath.Dir(s.PathOut), 0755); err != nil {
+		return err
+	}
+
+	f, err := os.OpenFile(s.PathOut, os.O_RDWR|os.O_CREATE, 0666)
+	if err != nil {
+		return err
+	}
+
+	s.stateFileOut = f
+	return nil
+}
+
+// return the path for the lockInfo metadata.
+func (s *LocalState) lockInfoPath() string {
+	stateDir, stateName := filepath.Split(s.Path)
+	if stateName == "" {
+		panic("empty state file path")
+	}
+
+	if stateName[0] == '.' {
+		stateName = stateName[1:]
+	}
+
+	return filepath.Join(stateDir, fmt.Sprintf(".%s.lock.info", stateName))
+}
+
+// lockInfo returns the data in a lock info file
+func (s *LocalState) lockInfo() (*statemgr.LockInfo, error) {
+	path := s.lockInfoPath()
+	infoData, err := ioutil.ReadFile(path)
+	if err != nil {
+		return nil, err
+	}
+
+	info := statemgr.LockInfo{}
+	err = json.Unmarshal(infoData, &info)
+	if err != nil {
+		return nil, fmt.Errorf("state file %q locked, but could not unmarshal lock info: %s", s.Path, err)
+	}
+	return &info, nil
+}
+
+// write a new lock info file
+func (s *LocalState) writeLockInfo(info *statemgr.LockInfo) error {
+	path := s.lockInfoPath()
+	info.Path = s.Path
+	info.Created = time.Now().UTC()
+
+	err := ioutil.WriteFile(path, info.Marshal(), 0600)
+	if err != nil {
+		return fmt.Errorf("could not write lock info for %q: %s", s.Path, err)
+	}
+	return nil
+}
diff --git a/v1.5.7/internal/command/clistate/local_state_lock_unix.go b/v1.5.7/internal/command/clistate/local_state_lock_unix.go
new file mode 100644
index 0000000..4d74bc2
--- /dev/null
+++ b/v1.5.7/internal/command/clistate/local_state_lock_unix.go
@@ -0,0 +1,38 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build !windows
+// +build !windows
+
+package clistate
+
+import (
+	"io"
+	"syscall"
+)
+
+// use fcntl POSIX locks for the most consistent behavior across platforms, and
+// hopefully some campatibility over NFS and CIFS.
+func (s *LocalState) lock() error {
+	flock := &syscall.Flock_t{
+		Type:   syscall.F_RDLCK | syscall.F_WRLCK,
+		Whence: int16(io.SeekStart),
+		Start:  0,
+		Len:    0,
+	}
+
+	fd := s.stateFileOut.Fd()
+	return syscall.FcntlFlock(fd, syscall.F_SETLK, flock)
+}
+
+func (s *LocalState) unlock() error {
+	flock := &syscall.Flock_t{
+		Type:   syscall.F_UNLCK,
+		Whence: int16(io.SeekStart),
+		Start:  0,
+		Len:    0,
+	}
+
+	fd := s.stateFileOut.Fd()
+	return syscall.FcntlFlock(fd, syscall.F_SETLK, flock)
+}
diff --git a/v1.5.7/internal/command/clistate/local_state_lock_windows.go b/v1.5.7/internal/command/clistate/local_state_lock_windows.go
new file mode 100644
index 0000000..d36980b
--- /dev/null
+++ b/v1.5.7/internal/command/clistate/local_state_lock_windows.go
@@ -0,0 +1,112 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build windows
+// +build windows
+
+package clistate
+
+import (
+	"math"
+	"syscall"
+	"unsafe"
+)
+
+var (
+	modkernel32      = syscall.NewLazyDLL("kernel32.dll")
+	procLockFileEx   = modkernel32.NewProc("LockFileEx")
+	procCreateEventW = modkernel32.NewProc("CreateEventW")
+)
+
+const (
+	// dwFlags defined for LockFileEx
+	// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
+	_LOCKFILE_FAIL_IMMEDIATELY = 1
+	_LOCKFILE_EXCLUSIVE_LOCK   = 2
+)
+
+func (s *LocalState) lock() error {
+	// even though we're failing immediately, an overlapped event structure is
+	// required
+	ol, err := newOverlapped()
+	if err != nil {
+		return err
+	}
+	defer syscall.CloseHandle(ol.HEvent)
+
+	return lockFileEx(
+		syscall.Handle(s.stateFileOut.Fd()),
+		_LOCKFILE_EXCLUSIVE_LOCK|_LOCKFILE_FAIL_IMMEDIATELY,
+		0,              // reserved
+		0,              // bytes low
+		math.MaxUint32, // bytes high
+		ol,
+	)
+}
+
+func (s *LocalState) unlock() error {
+	// the file is closed in Unlock
+	return nil
+}
+
+func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
+	r1, _, e1 := syscall.Syscall6(
+		procLockFileEx.Addr(),
+		6,
+		uintptr(h),
+		uintptr(flags),
+		uintptr(reserved),
+		uintptr(locklow),
+		uintptr(lockhigh),
+		uintptr(unsafe.Pointer(ol)),
+	)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+// newOverlapped creates a structure used to track asynchronous
+// I/O requests that have been issued.
+func newOverlapped() (*syscall.Overlapped, error) {
+	event, err := createEvent(nil, true, false, nil)
+	if err != nil {
+		return nil, err
+	}
+	return &syscall.Overlapped{HEvent: event}, nil
+}
+
+func createEvent(sa *syscall.SecurityAttributes, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) {
+	var _p0 uint32
+	if manualReset {
+		_p0 = 1
+	}
+	var _p1 uint32
+	if initialState {
+		_p1 = 1
+	}
+
+	r0, _, e1 := syscall.Syscall6(
+		procCreateEventW.Addr(),
+		4,
+		uintptr(unsafe.Pointer(sa)),
+		uintptr(_p0),
+		uintptr(_p1),
+		uintptr(unsafe.Pointer(name)),
+		0,
+		0,
+	)
+	handle = syscall.Handle(r0)
+	if handle == syscall.InvalidHandle {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
diff --git a/v1.5.7/internal/command/clistate/state.go b/v1.5.7/internal/command/clistate/state.go
new file mode 100644
index 0000000..f781c7b
--- /dev/null
+++ b/v1.5.7/internal/command/clistate/state.go
@@ -0,0 +1,193 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package state exposes common helpers for working with state from the CLI.
+//
+// This is a separate package so that backends can use this for consistent
+// messaging without creating a circular reference to the command package.
+package clistate
+
+import (
+	"context"
+	"fmt"
+	"sync"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/helper/slowmessage"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+const (
+	LockThreshold    = 400 * time.Millisecond
+	LockErrorMessage = `Error message: %s
+
+Terraform acquires a state lock to protect the state from being written
+by multiple users at the same time. Please resolve the issue above and try
+again. For most commands, you can disable locking with the "-lock=false"
+flag, but this is not recommended.`
+
+	UnlockErrorMessage = `Error message: %s
+
+Terraform acquires a lock when accessing your state to prevent others
+running Terraform to potentially modify the state at the same time. An
+error occurred while releasing this lock. This could mean that the lock
+did or did not release properly. If the lock didn't release properly,
+Terraform may not be able to run future commands since it'll appear as if
+the lock is held.
+
+In this scenario, please call the "force-unlock" command to unlock the
+state manually. This is a very dangerous operation since if it is done
+erroneously it could result in two people modifying state at the same time.
+Only call this command if you're certain that the unlock above failed and
+that no one else is holding a lock.`
+)
+
+// Locker allows for more convenient usage of the lower-level statemgr.Locker
+// implementations.
+// The statemgr.Locker API requires passing in a statemgr.LockInfo struct. Locker
+// implementations are expected to create the required LockInfo struct when
+// Lock is called, populate the Operation field with the "reason" string
+// provided, and pass that on to the underlying statemgr.Locker.
+// Locker implementations are also expected to store any state required to call
+// Unlock, which is at a minimum the LockID string returned by the
+// statemgr.Locker.
+type Locker interface {
+	// Returns a shallow copy of the locker with its context changed to ctx.
+	WithContext(ctx context.Context) Locker
+
+	// Lock the provided state manager, storing the reason string in the LockInfo.
+	Lock(s statemgr.Locker, reason string) tfdiags.Diagnostics
+
+	// Unlock the previously locked state.
+	Unlock() tfdiags.Diagnostics
+
+	// Timeout returns the configured timeout duration
+	Timeout() time.Duration
+}
+
+type locker struct {
+	mu      sync.Mutex
+	ctx     context.Context
+	timeout time.Duration
+	state   statemgr.Locker
+	view    views.StateLocker
+	lockID  string
+}
+
+var _ Locker = (*locker)(nil)
+
+// Create a new Locker.
+// This Locker uses state.LockWithContext to retry the lock until the provided
+// timeout is reached, or the context is canceled. Lock progress will be be
+// reported to the user through the provided UI.
+func NewLocker(timeout time.Duration, view views.StateLocker) Locker {
+	return &locker{
+		ctx:     context.Background(),
+		timeout: timeout,
+		view:    view,
+	}
+}
+
+// WithContext returns a new Locker with the specified context, copying the
+// timeout and view parameters from the original Locker.
+func (l *locker) WithContext(ctx context.Context) Locker {
+	if ctx == nil {
+		panic("nil context")
+	}
+	return &locker{
+		ctx:     ctx,
+		timeout: l.timeout,
+		view:    l.view,
+	}
+}
+
+// Locker locks the given state and outputs to the user if locking is taking
+// longer than the threshold. The lock is retried until the context is
+// cancelled.
+func (l *locker) Lock(s statemgr.Locker, reason string) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	l.mu.Lock()
+	defer l.mu.Unlock()
+
+	l.state = s
+
+	ctx, cancel := context.WithTimeout(l.ctx, l.timeout)
+	defer cancel()
+
+	lockInfo := statemgr.NewLockInfo()
+	lockInfo.Operation = reason
+
+	err := slowmessage.Do(LockThreshold, func() error {
+		id, err := statemgr.LockWithContext(ctx, s, lockInfo)
+		l.lockID = id
+		return err
+	}, l.view.Locking)
+
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Error acquiring the state lock",
+			fmt.Sprintf(LockErrorMessage, err),
+		))
+	}
+
+	return diags
+}
+
+func (l *locker) Unlock() tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	l.mu.Lock()
+	defer l.mu.Unlock()
+
+	if l.lockID == "" {
+		return diags
+	}
+
+	err := slowmessage.Do(LockThreshold, func() error {
+		return l.state.Unlock(l.lockID)
+	}, l.view.Unlocking)
+
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Error releasing the state lock",
+			fmt.Sprintf(UnlockErrorMessage, err),
+		))
+	}
+
+	return diags
+
+}
+
+func (l *locker) Timeout() time.Duration {
+	return l.timeout
+}
+
+type noopLocker struct{}
+
+// NewNoopLocker returns a valid Locker that does nothing.
+func NewNoopLocker() Locker {
+	return noopLocker{}
+}
+
+var _ Locker = noopLocker{}
+
+func (l noopLocker) WithContext(ctx context.Context) Locker {
+	return l
+}
+
+func (l noopLocker) Lock(statemgr.Locker, string) tfdiags.Diagnostics {
+	return nil
+}
+
+func (l noopLocker) Unlock() tfdiags.Diagnostics {
+	return nil
+}
+
+func (l noopLocker) Timeout() time.Duration {
+	return 0
+}
diff --git a/v1.5.7/internal/command/clistate/state_test.go b/v1.5.7/internal/command/clistate/state_test.go
new file mode 100644
index 0000000..bd00a8e
--- /dev/null
+++ b/v1.5.7/internal/command/clistate/state_test.go
@@ -0,0 +1,28 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package clistate
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terminal"
+)
+
+func TestUnlock(t *testing.T) {
+	streams, _ := terminal.StreamsForTesting(t)
+	view := views.NewView(streams)
+
+	l := NewLocker(0, views.NewStateLocker(arguments.ViewHuman, view))
+	l.Lock(statemgr.NewUnlockErrorFull(nil, nil), "test-lock")
+
+	diags := l.Unlock()
+	if diags.HasErrors() {
+		t.Log(diags.Err().Error())
+	} else {
+		t.Error("expected error")
+	}
+}
diff --git a/v1.5.7/internal/command/command.go b/v1.5.7/internal/command/command.go
new file mode 100644
index 0000000..a18ef34
--- /dev/null
+++ b/v1.5.7/internal/command/command.go
@@ -0,0 +1,74 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"os"
+	"runtime"
+)
+
+// Set to true when we're testing
+var test bool = false
+
+// DefaultDataDir is the default directory for storing local data.
+const DefaultDataDir = ".terraform"
+
+// PluginPathFile is the name of the file in the data dir which stores the list
+// of directories supplied by the user with the `-plugin-dir` flag during init.
+const PluginPathFile = "plugin_path"
+
+// pluginMachineName is the directory name used in new plugin paths.
+const pluginMachineName = runtime.GOOS + "_" + runtime.GOARCH
+
+// DefaultPluginVendorDir is the location in the config directory to look for
+// user-added plugin binaries. Terraform only reads from this path if it
+// exists, it is never created by terraform.
+const DefaultPluginVendorDir = "terraform.d/plugins/" + pluginMachineName
+
+// DefaultStateFilename is the default filename used for the state file.
+const DefaultStateFilename = "terraform.tfstate"
+
+// DefaultVarsFilename is the default filename used for vars
+const DefaultVarsFilename = "terraform.tfvars"
+
+// DefaultBackupExtension is added to the state file to form the path
+const DefaultBackupExtension = ".backup"
+
+// DefaultParallelism is the limit Terraform places on total parallel
+// operations as it walks the dependency graph.
+const DefaultParallelism = 10
+
+// ErrUnsupportedLocalOp is the common error message shown for operations
+// that require a backend.Local.
+const ErrUnsupportedLocalOp = `The configured backend doesn't support this operation.
+
+The "backend" in Terraform defines how Terraform operates. The default
+backend performs all operations locally on your machine. Your configuration
+is configured to use a non-local backend. This backend doesn't support this
+operation.
+`
+
+// ModulePath returns the path to the root module and validates CLI arguments.
+//
+// This centralizes the logic for any commands that previously accepted
+// a module path via CLI arguments. This will error if any extraneous arguments
+// are given and suggest using the -chdir flag instead.
+//
+// If your command accepts more than one arg, then change the slice bounds
+// to pass validation.
+func ModulePath(args []string) (string, error) {
+	// TODO: test
+
+	if len(args) > 0 {
+		return "", fmt.Errorf("Too many command line arguments. Did you mean to use -chdir?")
+	}
+
+	path, err := os.Getwd()
+	if err != nil {
+		return "", fmt.Errorf("Error getting pwd: %s", err)
+	}
+
+	return path, nil
+}
diff --git a/v1.5.7/internal/command/command_test.go b/v1.5.7/internal/command/command_test.go
new file mode 100644
index 0000000..7e634be
--- /dev/null
+++ b/v1.5.7/internal/command/command_test.go
@@ -0,0 +1,1167 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"context"
+	"crypto/md5"
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/http/httptest"
+	"os"
+	"os/exec"
+	"path"
+	"path/filepath"
+	"strings"
+	"syscall"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/addrs"
+	backendInit "github.com/hashicorp/terraform/internal/backend/init"
+	backendLocal "github.com/hashicorp/terraform/internal/backend/local"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/command/workdir"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/copy"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/hashicorp/terraform/internal/initwd"
+	legacy "github.com/hashicorp/terraform/internal/legacy/terraform"
+	_ "github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/registry"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/version"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// These are the directories for our test data and fixtures.
+var (
+	fixtureDir  = "./testdata"
+	testDataDir = "./testdata"
+)
+
+func init() {
+	test = true
+
+	// Initialize the backends
+	backendInit.Init(nil)
+
+	// Expand the data and fixture dirs on init because
+	// we change the working directory in some tests.
+	var err error
+	fixtureDir, err = filepath.Abs(fixtureDir)
+	if err != nil {
+		panic(err)
+	}
+
+	testDataDir, err = filepath.Abs(testDataDir)
+	if err != nil {
+		panic(err)
+	}
+}
+
+func TestMain(m *testing.M) {
+	// Make sure backend init is initialized, since our tests tend to assume it.
+	backendInit.Init(nil)
+
+	os.Exit(m.Run())
+}
+
+// tempWorkingDir constructs a workdir.Dir object referring to a newly-created
+// temporary directory. The temporary directory is automatically removed when
+// the test and all its subtests complete.
+//
+// Although workdir.Dir is built to support arbitrary base directories, the
+// not-yet-migrated behaviors in command.Meta tend to expect the root module
+// directory to be the real process working directory, and so if you intend
+// to use the result inside a command.Meta object you must use a pattern
+// similar to the following when initializing your test:
+//
+//	wd := tempWorkingDir(t)
+//	defer testChdir(t, wd.RootModuleDir())()
+//
+// Note that testChdir modifies global state for the test process, and so a
+// test using this pattern must never call t.Parallel().
+func tempWorkingDir(t *testing.T) *workdir.Dir {
+	t.Helper()
+
+	dirPath := t.TempDir()
+	t.Logf("temporary directory %s", dirPath)
+
+	return workdir.NewDir(dirPath)
+}
+
+// tempWorkingDirFixture is like tempWorkingDir but it also copies the content
+// from a fixture directory into the temporary directory before returning it.
+//
+// The same caveats about working directory apply as for testWorkingDir. See
+// the testWorkingDir commentary for an example of how to use this function
+// along with testChdir to meet the expectations of command.Meta legacy
+// functionality.
+func tempWorkingDirFixture(t *testing.T, fixtureName string) *workdir.Dir {
+	t.Helper()
+
+	dirPath := testTempDir(t)
+	t.Logf("temporary directory %s with fixture %q", dirPath, fixtureName)
+
+	fixturePath := testFixturePath(fixtureName)
+	testCopyDir(t, fixturePath, dirPath)
+	// NOTE: Unfortunately because testCopyDir immediately aborts the test
+	// on failure, a failure to copy will prevent us from cleaning up the
+	// temporary directory. Oh well. :(
+
+	return workdir.NewDir(dirPath)
+}
+
+func testFixturePath(name string) string {
+	return filepath.Join(fixtureDir, name)
+}
+
+func metaOverridesForProvider(p providers.Interface) *testingOverrides {
+	return &testingOverrides{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"):                                           providers.FactoryFixed(p),
+			addrs.NewProvider(addrs.DefaultProviderRegistryHost, "hashicorp2", "test"): providers.FactoryFixed(p),
+		},
+	}
+}
+
+func testModuleWithSnapshot(t *testing.T, name string) (*configs.Config, *configload.Snapshot) {
+	t.Helper()
+
+	dir := filepath.Join(fixtureDir, name)
+	// FIXME: We're not dealing with the cleanup function here because
+	// this testModule function is used all over and so we don't want to
+	// change its interface at this late stage.
+	loader, _ := configload.NewLoaderForTests(t)
+
+	// Test modules usually do not refer to remote sources, and for local
+	// sources only this ultimately just records all of the module paths
+	// in a JSON file so that we can load them below.
+	inst := initwd.NewModuleInstaller(loader.ModulesDir(), loader, registry.NewClient(nil, nil))
+	_, instDiags := inst.InstallModules(context.Background(), dir, true, initwd.ModuleInstallHooksImpl{})
+	if instDiags.HasErrors() {
+		t.Fatal(instDiags.Err())
+	}
+
+	config, snap, diags := loader.LoadConfigWithSnapshot(dir)
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	return config, snap
+}
+
+// testPlan returns a non-nil noop plan.
+func testPlan(t *testing.T) *plans.Plan {
+	t.Helper()
+
+	// This is what an empty configuration block would look like after being
+	// decoded with the schema of the "local" backend.
+	backendConfig := cty.ObjectVal(map[string]cty.Value{
+		"path":          cty.NullVal(cty.String),
+		"workspace_dir": cty.NullVal(cty.String),
+	})
+	backendConfigRaw, err := plans.NewDynamicValue(backendConfig, backendConfig.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	return &plans.Plan{
+		Backend: plans.Backend{
+			// This is just a placeholder so that the plan file can be written
+			// out. Caller may wish to override it to something more "real"
+			// where the plan will actually be subsequently applied.
+			Type:   "local",
+			Config: backendConfigRaw,
+		},
+		Changes: plans.NewChanges(),
+	}
+}
+
+func testPlanFile(t *testing.T, configSnap *configload.Snapshot, state *states.State, plan *plans.Plan) string {
+	return testPlanFileMatchState(t, configSnap, state, plan, statemgr.SnapshotMeta{})
+}
+
+func testPlanFileMatchState(t *testing.T, configSnap *configload.Snapshot, state *states.State, plan *plans.Plan, stateMeta statemgr.SnapshotMeta) string {
+	t.Helper()
+
+	stateFile := &statefile.File{
+		Lineage:          stateMeta.Lineage,
+		Serial:           stateMeta.Serial,
+		State:            state,
+		TerraformVersion: version.SemVer,
+	}
+	prevStateFile := &statefile.File{
+		Lineage:          stateMeta.Lineage,
+		Serial:           stateMeta.Serial,
+		State:            state, // we just assume no changes detected during refresh
+		TerraformVersion: version.SemVer,
+	}
+
+	path := testTempFile(t)
+	err := planfile.Create(path, planfile.CreateArgs{
+		ConfigSnapshot:       configSnap,
+		PreviousRunStateFile: prevStateFile,
+		StateFile:            stateFile,
+		Plan:                 plan,
+		DependencyLocks:      depsfile.NewLocks(),
+	})
+	if err != nil {
+		t.Fatalf("failed to create temporary plan file: %s", err)
+	}
+
+	return path
+}
+
+// testPlanFileNoop is a shortcut function that creates a plan file that
+// represents no changes and returns its path. This is useful when a test
+// just needs any plan file, and it doesn't matter what is inside it.
+func testPlanFileNoop(t *testing.T) string {
+	snap := &configload.Snapshot{
+		Modules: map[string]*configload.SnapshotModule{
+			"": {
+				Dir: ".",
+				Files: map[string][]byte{
+					"main.tf": nil,
+				},
+			},
+		},
+	}
+	state := states.NewState()
+	plan := testPlan(t)
+	return testPlanFile(t, snap, state, plan)
+}
+
+func testFileEquals(t *testing.T, got, want string) {
+	t.Helper()
+
+	actual, err := os.ReadFile(got)
+	if err != nil {
+		t.Fatalf("error reading %s", got)
+	}
+
+	expected, err := os.ReadFile(want)
+	if err != nil {
+		t.Fatalf("error reading %s", want)
+	}
+
+	if diff := cmp.Diff(string(actual), string(expected)); len(diff) > 0 {
+		t.Fatalf("got:\n%s\nwant:\n%s\ndiff:\n%s", actual, expected, diff)
+	}
+}
+
+func testReadPlan(t *testing.T, path string) *plans.Plan {
+	t.Helper()
+
+	f, err := planfile.Open(path)
+	if err != nil {
+		t.Fatalf("error opening plan file %q: %s", path, err)
+	}
+	defer f.Close()
+
+	p, err := f.ReadPlan()
+	if err != nil {
+		t.Fatalf("error reading plan from plan file %q: %s", path, err)
+	}
+
+	return p
+}
+
+// testState returns a test State structure that we use for a lot of tests.
+func testState() *states.State {
+	return states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				// The weird whitespace here is reflective of how this would
+				// get written out in a real state file, due to the indentation
+				// of all of the containing wrapping objects and arrays.
+				AttrsJSON:    []byte("{\n            \"id\": \"bar\"\n          }"),
+				Status:       states.ObjectReady,
+				Dependencies: []addrs.ConfigResource{},
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		// DeepCopy is used here to ensure our synthetic state matches exactly
+		// with a state that will have been copied during the command
+		// operation, and all fields have been copied correctly.
+	}).DeepCopy()
+}
+
+// writeStateForTesting is a helper that writes the given naked state to the
+// given writer, generating a stub *statefile.File wrapper which is then
+// immediately discarded.
+func writeStateForTesting(state *states.State, w io.Writer) error {
+	sf := &statefile.File{
+		Serial:  0,
+		Lineage: "fake-for-testing",
+		State:   state,
+	}
+	return statefile.Write(sf, w)
+}
+
+// testStateMgrCurrentLineage returns the current lineage for the given state
+// manager, or the empty string if it does not use lineage. This is primarily
+// for testing against the local backend, which always supports lineage.
+func testStateMgrCurrentLineage(mgr statemgr.Persistent) string {
+	if pm, ok := mgr.(statemgr.PersistentMeta); ok {
+		m := pm.StateSnapshotMeta()
+		return m.Lineage
+	}
+	return ""
+}
+
+// markStateForMatching is a helper that writes a specific marker value to
+// a state so that it can be recognized later with getStateMatchingMarker.
+//
+// Internally this just sets a root module output value called "testing_mark"
+// to the given string value. If the state is being checked in other ways,
+// the test code may need to compensate for the addition or overwriting of this
+// special output value name.
+//
+// The given mark string is returned verbatim, to allow the following pattern
+// in tests:
+//
+//	mark := markStateForMatching(state, "foo")
+//	// (do stuff to the state)
+//	assertStateHasMarker(state, mark)
+func markStateForMatching(state *states.State, mark string) string {
+	state.RootModule().SetOutputValue("testing_mark", cty.StringVal(mark), false)
+	return mark
+}
+
+// getStateMatchingMarker is used with markStateForMatching to retrieve the
+// mark string previously added to the given state. If no such mark is present,
+// the result is an empty string.
+func getStateMatchingMarker(state *states.State) string {
+	os := state.RootModule().OutputValues["testing_mark"]
+	if os == nil {
+		return ""
+	}
+	v := os.Value
+	if v.Type() == cty.String && v.IsKnown() && !v.IsNull() {
+		return v.AsString()
+	}
+	return ""
+}
+
+// stateHasMarker is a helper around getStateMatchingMarker that also includes
+// the equality test, for more convenient use in test assertion branches.
+func stateHasMarker(state *states.State, want string) bool {
+	return getStateMatchingMarker(state) == want
+}
+
+// assertStateHasMarker wraps stateHasMarker to automatically generate a
+// fatal test result (i.e. t.Fatal) if the marker doesn't match.
+func assertStateHasMarker(t *testing.T, state *states.State, want string) {
+	if !stateHasMarker(state, want) {
+		t.Fatalf("wrong state marker\ngot:  %q\nwant: %q", getStateMatchingMarker(state), want)
+	}
+}
+
+func testStateFile(t *testing.T, s *states.State) string {
+	t.Helper()
+
+	path := testTempFile(t)
+
+	f, err := os.Create(path)
+	if err != nil {
+		t.Fatalf("failed to create temporary state file %s: %s", path, err)
+	}
+	defer f.Close()
+
+	err = writeStateForTesting(s, f)
+	if err != nil {
+		t.Fatalf("failed to write state to temporary file %s: %s", path, err)
+	}
+
+	return path
+}
+
+// testStateFileDefault writes the state out to the default statefile
+// in the cwd. Use `testCwd` to change into a temp cwd.
+func testStateFileDefault(t *testing.T, s *states.State) {
+	t.Helper()
+
+	f, err := os.Create(DefaultStateFilename)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer f.Close()
+
+	if err := writeStateForTesting(s, f); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+}
+
+// testStateFileWorkspaceDefault writes the state out to the default statefile
+// for the given workspace in the cwd. Use `testCwd` to change into a temp cwd.
+func testStateFileWorkspaceDefault(t *testing.T, workspace string, s *states.State) string {
+	t.Helper()
+
+	workspaceDir := filepath.Join(backendLocal.DefaultWorkspaceDir, workspace)
+	err := os.MkdirAll(workspaceDir, os.ModePerm)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	path := filepath.Join(workspaceDir, DefaultStateFilename)
+	f, err := os.Create(path)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer f.Close()
+
+	if err := writeStateForTesting(s, f); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	return path
+}
+
+// testStateFileRemote writes the state out to the remote statefile
+// in the cwd. Use `testCwd` to change into a temp cwd.
+func testStateFileRemote(t *testing.T, s *legacy.State) string {
+	t.Helper()
+
+	path := filepath.Join(DefaultDataDir, DefaultStateFilename)
+	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	f, err := os.Create(path)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer f.Close()
+
+	if err := legacy.WriteState(s, f); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	return path
+}
+
+// testStateRead reads the state from a file
+func testStateRead(t *testing.T, path string) *states.State {
+	t.Helper()
+
+	f, err := os.Open(path)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer f.Close()
+
+	sf, err := statefile.Read(f)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	return sf.State
+}
+
+// testDataStateRead reads a "data state", which is a file format resembling
+// our state format v3 that is used only to track current backend settings.
+//
+// This old format still uses *legacy.State, but should be replaced with
+// a more specialized type in a later release.
+func testDataStateRead(t *testing.T, path string) *legacy.State {
+	t.Helper()
+
+	f, err := os.Open(path)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer f.Close()
+
+	s, err := legacy.ReadState(f)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	return s
+}
+
+// testStateOutput tests that the state at the given path contains
+// the expected state string.
+func testStateOutput(t *testing.T, path string, expected string) {
+	t.Helper()
+
+	newState := testStateRead(t, path)
+	actual := strings.TrimSpace(newState.String())
+	expected = strings.TrimSpace(expected)
+	if actual != expected {
+		t.Fatalf("expected:\n%s\nactual:\n%s", expected, actual)
+	}
+}
+
+func testProvider() *terraform.MockProvider {
+	p := new(terraform.MockProvider)
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		resp.PlannedState = req.ProposedNewState
+		return resp
+	}
+
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		return providers.ReadResourceResponse{
+			NewState: req.PriorState,
+		}
+	}
+	return p
+}
+
+func testTempFile(t *testing.T) string {
+	t.Helper()
+
+	return filepath.Join(testTempDir(t), "state.tfstate")
+}
+
+func testTempDir(t *testing.T) string {
+	t.Helper()
+	d, err := filepath.EvalSymlinks(t.TempDir())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	return d
+}
+
+// testChdir changes the directory and returns a function to defer to
+// revert the old cwd.
+func testChdir(t *testing.T, new string) func() {
+	t.Helper()
+
+	old, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if err := os.Chdir(new); err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	return func() {
+		// Re-run the function ignoring the defer result
+		testChdir(t, old)
+	}
+}
+
+// testCwd is used to change the current working directory into a temporary
+// directory. The cleanup is performed automatically after the test and all its
+// subtests complete.
+func testCwd(t *testing.T) string {
+	t.Helper()
+
+	tmp := t.TempDir()
+
+	cwd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if err := os.Chdir(tmp); err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	t.Cleanup(func() {
+		if err := os.Chdir(cwd); err != nil {
+			t.Fatalf("err: %v", err)
+		}
+	})
+
+	return tmp
+}
+
+// testStdinPipe changes os.Stdin to be a pipe that sends the data from
+// the reader before closing the pipe.
+//
+// The returned function should be deferred to properly clean up and restore
+// the original stdin.
+func testStdinPipe(t *testing.T, src io.Reader) func() {
+	t.Helper()
+
+	r, w, err := os.Pipe()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Modify stdin to point to our new pipe
+	old := os.Stdin
+	os.Stdin = r
+
+	// Copy the data from the reader to the pipe
+	go func() {
+		defer w.Close()
+		io.Copy(w, src)
+	}()
+
+	return func() {
+		// Close our read end
+		r.Close()
+
+		// Reset stdin
+		os.Stdin = old
+	}
+}
+
+// Modify os.Stdout to write to the given buffer. Note that this is generally
+// not useful since the commands are configured to write to a cli.Ui, not
+// Stdout directly. Commands like `console` though use the raw stdout.
+func testStdoutCapture(t *testing.T, dst io.Writer) func() {
+	t.Helper()
+
+	r, w, err := os.Pipe()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Modify stdout
+	old := os.Stdout
+	os.Stdout = w
+
+	// Copy
+	doneCh := make(chan struct{})
+	go func() {
+		defer close(doneCh)
+		defer r.Close()
+		io.Copy(dst, r)
+	}()
+
+	return func() {
+		// Close the writer end of the pipe
+		w.Sync()
+		w.Close()
+
+		// Reset stdout
+		os.Stdout = old
+
+		// Wait for the data copy to complete to avoid a race reading data
+		<-doneCh
+	}
+}
+
+// testInteractiveInput configures tests so that the answers given are sent
+// in order to interactive prompts. The returned function must be called
+// in a defer to clean up.
+func testInteractiveInput(t *testing.T, answers []string) func() {
+	t.Helper()
+
+	// Disable test mode so input is called
+	test = false
+
+	// Set up reader/writers
+	testInputResponse = answers
+	defaultInputReader = bytes.NewBufferString("")
+	defaultInputWriter = new(bytes.Buffer)
+
+	// Return the cleanup
+	return func() {
+		test = true
+		testInputResponse = nil
+	}
+}
+
+// testInputMap configures tests so that the given answers are returned
+// for calls to Input when the right question is asked. The key is the
+// question "Id" that is used.
+func testInputMap(t *testing.T, answers map[string]string) func() {
+	t.Helper()
+
+	// Disable test mode so input is called
+	test = false
+
+	// Set up reader/writers
+	defaultInputReader = bytes.NewBufferString("")
+	defaultInputWriter = new(bytes.Buffer)
+
+	// Setup answers
+	testInputResponse = nil
+	testInputResponseMap = answers
+
+	// Return the cleanup
+	return func() {
+		var unusedAnswers = testInputResponseMap
+
+		// First, clean up!
+		test = true
+		testInputResponseMap = nil
+
+		if len(unusedAnswers) > 0 {
+			t.Fatalf("expected no unused answers provided to command.testInputMap, got: %v", unusedAnswers)
+		}
+	}
+}
+
+// testBackendState is used to make a test HTTP server to test a configured
+// backend. This returns the complete state that can be saved. Use
+// `testStateFileRemote` to write the returned state.
+//
+// When using this function, the configuration fixture for the test must
+// include an empty configuration block for the HTTP backend, like this:
+//
+//	terraform {
+//	  backend "http" {
+//	  }
+//	}
+//
+// If such a block isn't present, or if it isn't empty, then an error will
+// be returned about the backend configuration having changed and that
+// "terraform init" must be run, since the test backend config cache created
+// by this function contains the hash for an empty configuration.
+func testBackendState(t *testing.T, s *states.State, c int) (*legacy.State, *httptest.Server) {
+	t.Helper()
+
+	var b64md5 string
+	buf := bytes.NewBuffer(nil)
+
+	cb := func(resp http.ResponseWriter, req *http.Request) {
+		if req.Method == "PUT" {
+			resp.WriteHeader(c)
+			return
+		}
+		if s == nil {
+			resp.WriteHeader(404)
+			return
+		}
+
+		resp.Header().Set("Content-MD5", b64md5)
+		resp.Write(buf.Bytes())
+	}
+
+	// If a state was given, make sure we calculate the proper b64md5
+	if s != nil {
+		err := statefile.Write(&statefile.File{State: s}, buf)
+		if err != nil {
+			t.Fatalf("err: %v", err)
+		}
+		md5 := md5.Sum(buf.Bytes())
+		b64md5 = base64.StdEncoding.EncodeToString(md5[:16])
+	}
+
+	srv := httptest.NewServer(http.HandlerFunc(cb))
+
+	backendConfig := &configs.Backend{
+		Type:   "http",
+		Config: configs.SynthBody("<testBackendState>", map[string]cty.Value{}),
+	}
+	b := backendInit.Backend("http")()
+	configSchema := b.ConfigSchema()
+	hash := backendConfig.Hash(configSchema)
+
+	state := legacy.NewState()
+	state.Backend = &legacy.BackendState{
+		Type:      "http",
+		ConfigRaw: json.RawMessage(fmt.Sprintf(`{"address":%q}`, srv.URL)),
+		Hash:      uint64(hash),
+	}
+
+	return state, srv
+}
+
+// testRemoteState is used to make a test HTTP server to return a given
+// state file that can be used for testing legacy remote state.
+//
+// The return values are a *legacy.State instance that should be written
+// as the "data state" (really: backend state) and the server that the
+// returned data state refers to.
+func testRemoteState(t *testing.T, s *states.State, c int) (*legacy.State, *httptest.Server) {
+	t.Helper()
+
+	var b64md5 string
+	buf := bytes.NewBuffer(nil)
+
+	cb := func(resp http.ResponseWriter, req *http.Request) {
+		if req.Method == "PUT" {
+			resp.WriteHeader(c)
+			return
+		}
+		if s == nil {
+			resp.WriteHeader(404)
+			return
+		}
+
+		resp.Header().Set("Content-MD5", b64md5)
+		resp.Write(buf.Bytes())
+	}
+
+	retState := legacy.NewState()
+
+	srv := httptest.NewServer(http.HandlerFunc(cb))
+	b := &legacy.BackendState{
+		Type: "http",
+	}
+	b.SetConfig(cty.ObjectVal(map[string]cty.Value{
+		"address": cty.StringVal(srv.URL),
+	}), &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"address": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	})
+	retState.Backend = b
+
+	if s != nil {
+		err := statefile.Write(&statefile.File{State: s}, buf)
+		if err != nil {
+			t.Fatalf("failed to write initial state: %v", err)
+		}
+	}
+
+	return retState, srv
+}
+
+// testlockState calls a separate process to the lock the state file at path.
+// deferFunc should be called in the caller to properly unlock the file.
+// Since many tests change the working directory, the sourcedir argument must be
+// supplied to locate the statelocker.go source.
+func testLockState(t *testing.T, sourceDir, path string) (func(), error) {
+	// build and run the binary ourselves so we can quickly terminate it for cleanup
+	buildDir := t.TempDir()
+
+	source := filepath.Join(sourceDir, "statelocker.go")
+	lockBin := filepath.Join(buildDir, "statelocker")
+
+	cmd := exec.Command("go", "build", "-o", lockBin, source)
+	cmd.Dir = filepath.Dir(sourceDir)
+
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		return nil, fmt.Errorf("%s %s", err, out)
+	}
+
+	locker := exec.Command(lockBin, path)
+	pr, pw, err := os.Pipe()
+	if err != nil {
+		return nil, err
+	}
+	defer pr.Close()
+	defer pw.Close()
+	locker.Stderr = pw
+	locker.Stdout = pw
+
+	if err := locker.Start(); err != nil {
+		return nil, err
+	}
+	deferFunc := func() {
+		locker.Process.Signal(syscall.SIGTERM)
+		locker.Wait()
+	}
+
+	// wait for the process to lock
+	buf := make([]byte, 1024)
+	n, err := pr.Read(buf)
+	if err != nil {
+		return deferFunc, fmt.Errorf("read from statelocker returned: %s", err)
+	}
+
+	output := string(buf[:n])
+	if !strings.HasPrefix(output, "LOCKID") {
+		return deferFunc, fmt.Errorf("statelocker wrote: %s", string(buf[:n]))
+	}
+	return deferFunc, nil
+}
+
+// testCopyDir recursively copies a directory tree, attempting to preserve
+// permissions. Source directory must exist, destination directory may exist
+// but will be created if not; it should typically be a temporary directory,
+// and thus already created using os.MkdirTemp or similar.
+// Symlinks are ignored and skipped.
+func testCopyDir(t *testing.T, src, dst string) {
+	t.Helper()
+
+	src = filepath.Clean(src)
+	dst = filepath.Clean(dst)
+
+	si, err := os.Stat(src)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !si.IsDir() {
+		t.Fatal("source is not a directory")
+	}
+
+	_, err = os.Stat(dst)
+	if err != nil && !os.IsNotExist(err) {
+		t.Fatal(err)
+	}
+
+	err = os.MkdirAll(dst, si.Mode())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	entries, err := ioutil.ReadDir(src)
+	if err != nil {
+		return
+	}
+
+	for _, entry := range entries {
+		srcPath := filepath.Join(src, entry.Name())
+		dstPath := filepath.Join(dst, entry.Name())
+
+		// If the entry is a symlink, we copy the contents
+		for entry.Mode()&os.ModeSymlink != 0 {
+			target, err := os.Readlink(srcPath)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			entry, err = os.Stat(target)
+			if err != nil {
+				t.Fatal(err)
+			}
+		}
+
+		if entry.IsDir() {
+			testCopyDir(t, srcPath, dstPath)
+		} else {
+			err = copy.CopyFile(srcPath, dstPath)
+			if err != nil {
+				t.Fatal(err)
+			}
+		}
+	}
+}
+
+// normalizeJSON removes all insignificant whitespace from the given JSON buffer
+// and returns it as a string for easier comparison.
+func normalizeJSON(t *testing.T, src []byte) string {
+	t.Helper()
+	var buf bytes.Buffer
+	err := json.Compact(&buf, src)
+	if err != nil {
+		t.Fatalf("error normalizing JSON: %s", err)
+	}
+	return buf.String()
+}
+
+func mustResourceAddr(s string) addrs.ConfigResource {
+	addr, diags := addrs.ParseAbsResourceStr(s)
+	if diags.HasErrors() {
+		panic(diags.Err())
+	}
+	return addr.Config()
+}
+
+// This map from provider type name to namespace is used by the fake registry
+// when called via LookupLegacyProvider. Providers not in this map will return
+// a 404 Not Found error.
+var legacyProviderNamespaces = map[string]string{
+	"foo": "hashicorp",
+	"bar": "hashicorp",
+	"baz": "terraform-providers",
+	"qux": "hashicorp",
+}
+
+// This map is used to mock the provider redirect feature.
+var movedProviderNamespaces = map[string]string{
+	"qux": "acme",
+}
+
+// testServices starts up a local HTTP server running a fake provider registry
+// service which responds only to discovery requests and legacy provider lookup
+// API calls.
+//
+// The final return value is a function to call at the end of a test function
+// to shut down the test server. After you call that function, the discovery
+// object becomes useless.
+func testServices(t *testing.T) (services *disco.Disco, cleanup func()) {
+	server := httptest.NewServer(http.HandlerFunc(fakeRegistryHandler))
+
+	services = disco.New()
+	services.ForceHostServices(svchost.Hostname("registry.terraform.io"), map[string]interface{}{
+		"providers.v1": server.URL + "/providers/v1/",
+	})
+
+	return services, func() {
+		server.Close()
+	}
+}
+
+// testRegistrySource is a wrapper around testServices that uses the created
+// discovery object to produce a Source instance that is ready to use with the
+// fake registry services.
+//
+// As with testServices, the final return value is a function to call at the end
+// of your test in order to shut down the test server.
+func testRegistrySource(t *testing.T) (source *getproviders.RegistrySource, cleanup func()) {
+	services, close := testServices(t)
+	source = getproviders.NewRegistrySource(services)
+	return source, close
+}
+
+func fakeRegistryHandler(resp http.ResponseWriter, req *http.Request) {
+	path := req.URL.EscapedPath()
+
+	if !strings.HasPrefix(path, "/providers/v1/") {
+		resp.WriteHeader(404)
+		resp.Write([]byte(`not a provider registry endpoint`))
+		return
+	}
+
+	pathParts := strings.Split(path, "/")[3:]
+
+	if len(pathParts) != 3 {
+		resp.WriteHeader(404)
+		resp.Write([]byte(`unrecognized path scheme`))
+		return
+	}
+
+	if pathParts[2] != "versions" {
+		resp.WriteHeader(404)
+		resp.Write([]byte(`this registry only supports legacy namespace lookup requests`))
+		return
+	}
+
+	name := pathParts[1]
+
+	// Legacy lookup
+	if pathParts[0] == "-" {
+		if namespace, ok := legacyProviderNamespaces[name]; ok {
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			if movedNamespace, ok := movedProviderNamespaces[name]; ok {
+				resp.Write([]byte(fmt.Sprintf(`{"id":"%s/%s","moved_to":"%s/%s","versions":[{"version":"1.0.0","protocols":["4"]}]}`, namespace, name, movedNamespace, name)))
+			} else {
+				resp.Write([]byte(fmt.Sprintf(`{"id":"%s/%s","versions":[{"version":"1.0.0","protocols":["4"]}]}`, namespace, name)))
+			}
+		} else {
+			resp.WriteHeader(404)
+			resp.Write([]byte(`provider not found`))
+		}
+		return
+	}
+
+	// Also return versions for redirect target
+	if namespace, ok := movedProviderNamespaces[name]; ok && pathParts[0] == namespace {
+		resp.Header().Set("Content-Type", "application/json")
+		resp.WriteHeader(200)
+		resp.Write([]byte(fmt.Sprintf(`{"id":"%s/%s","versions":[{"version":"1.0.0","protocols":["4"]}]}`, namespace, name)))
+	} else {
+		resp.WriteHeader(404)
+		resp.Write([]byte(`provider not found`))
+	}
+}
+
+func testView(t *testing.T) (*views.View, func(*testing.T) *terminal.TestOutput) {
+	streams, done := terminal.StreamsForTesting(t)
+	return views.NewView(streams), done
+}
+
+// checkGoldenReference compares the given test output with a known "golden" output log
+// located under the specified fixture path.
+//
+// If any of these tests fail, please communicate with Terraform Cloud folks before resolving,
+// as changes to UI output may also affect the behavior of Terraform Cloud's structured run output.
+func checkGoldenReference(t *testing.T, output *terminal.TestOutput, fixturePathName string) {
+	t.Helper()
+
+	// Load the golden reference fixture
+	wantFile, err := os.Open(path.Join(testFixturePath(fixturePathName), "output.jsonlog"))
+	if err != nil {
+		t.Fatalf("failed to open output file: %s", err)
+	}
+	defer wantFile.Close()
+	wantBytes, err := ioutil.ReadAll(wantFile)
+	if err != nil {
+		t.Fatalf("failed to read output file: %s", err)
+	}
+	want := string(wantBytes)
+
+	got := output.Stdout()
+
+	// Split the output and the reference into lines so that we can compare
+	// messages
+	got = strings.TrimSuffix(got, "\n")
+	gotLines := strings.Split(got, "\n")
+
+	want = strings.TrimSuffix(want, "\n")
+	wantLines := strings.Split(want, "\n")
+
+	if len(gotLines) != len(wantLines) {
+		t.Errorf("unexpected number of log lines: got %d, want %d\n"+
+			"NOTE: This failure may indicate a UI change affecting the behavior of structured run output on TFC.\n"+
+			"Please communicate with Terraform Cloud team before resolving", len(gotLines), len(wantLines))
+	}
+
+	// Verify that the log starts with a version message
+	type versionMessage struct {
+		Level     string `json:"@level"`
+		Message   string `json:"@message"`
+		Type      string `json:"type"`
+		Terraform string `json:"terraform"`
+		UI        string `json:"ui"`
+	}
+	var gotVersion versionMessage
+	if err := json.Unmarshal([]byte(gotLines[0]), &gotVersion); err != nil {
+		t.Errorf("failed to unmarshal version line: %s\n%s", err, gotLines[0])
+	}
+	wantVersion := versionMessage{
+		"info",
+		fmt.Sprintf("Terraform %s", version.String()),
+		"version",
+		version.String(),
+		views.JSON_UI_VERSION,
+	}
+	if !cmp.Equal(wantVersion, gotVersion) {
+		t.Errorf("unexpected first message:\n%s", cmp.Diff(wantVersion, gotVersion))
+	}
+
+	// Compare the rest of the lines against the golden reference
+	var gotLineMaps []map[string]interface{}
+	for i, line := range gotLines[1:] {
+		index := i + 1
+		var gotMap map[string]interface{}
+		if err := json.Unmarshal([]byte(line), &gotMap); err != nil {
+			t.Errorf("failed to unmarshal got line %d: %s\n%s", index, err, gotLines[index])
+		}
+		if _, ok := gotMap["@timestamp"]; !ok {
+			t.Errorf("missing @timestamp field in log: %s", gotLines[index])
+		}
+		delete(gotMap, "@timestamp")
+		gotLineMaps = append(gotLineMaps, gotMap)
+	}
+	var wantLineMaps []map[string]interface{}
+	for i, line := range wantLines[1:] {
+		index := i + 1
+		var wantMap map[string]interface{}
+		if err := json.Unmarshal([]byte(line), &wantMap); err != nil {
+			t.Errorf("failed to unmarshal want line %d: %s\n%s", index, err, gotLines[index])
+		}
+		wantLineMaps = append(wantLineMaps, wantMap)
+	}
+	if diff := cmp.Diff(wantLineMaps, gotLineMaps); diff != "" {
+		t.Errorf("wrong output lines\n%s\n"+
+			"NOTE: This failure may indicate a UI change affecting the behavior of structured run output on TFC.\n"+
+			"Please communicate with Terraform Cloud team before resolving", diff)
+	}
+}
diff --git a/v1.5.7/internal/command/console.go b/v1.5.7/internal/command/console.go
new file mode 100644
index 0000000..16c669b
--- /dev/null
+++ b/v1.5.7/internal/command/console.go
@@ -0,0 +1,224 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bufio"
+	"fmt"
+	"os"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/repl"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+
+	"github.com/mitchellh/cli"
+)
+
+// ConsoleCommand is a Command implementation that applies a Terraform
+// configuration and actually builds or changes infrastructure.
+type ConsoleCommand struct {
+	Meta
+}
+
+func (c *ConsoleCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	cmdFlags := c.Meta.extendedFlagSet("console")
+	cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	configPath, err := ModulePath(cmdFlags.Args())
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+	configPath = c.Meta.normalizePath(configPath)
+
+	// Check for user-supplied plugin path
+	if c.pluginPath, err = c.loadPluginPath(); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error loading plugin path: %s", err))
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	backendConfig, backendDiags := c.loadBackendConfig(configPath)
+	diags = diags.Append(backendDiags)
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(&BackendOpts{
+		Config: backendConfig,
+	})
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// We require a local backend
+	local, ok := b.(backend.Local)
+	if !ok {
+		c.showDiagnostics(diags) // in case of any warnings in here
+		c.Ui.Error(ErrUnsupportedLocalOp)
+		return 1
+	}
+
+	// This is a read-only command
+	c.ignoreRemoteVersionConflict(b)
+
+	// Build the operation
+	opReq := c.Operation(b, arguments.ViewHuman)
+	opReq.ConfigDir = configPath
+	opReq.ConfigLoader, err = c.initConfigLoader()
+	opReq.AllowUnsetVariables = true // we'll just evaluate them as unknown
+	if err != nil {
+		diags = diags.Append(err)
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	{
+		var moreDiags tfdiags.Diagnostics
+		opReq.Variables, moreDiags = c.collectVariableValues()
+		diags = diags.Append(moreDiags)
+		if moreDiags.HasErrors() {
+			c.showDiagnostics(diags)
+			return 1
+		}
+	}
+
+	// Get the context
+	lr, _, ctxDiags := local.LocalRun(opReq)
+	diags = diags.Append(ctxDiags)
+	if ctxDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Successfully creating the context can result in a lock, so ensure we release it
+	defer func() {
+		diags := opReq.StateLocker.Unlock()
+		if diags.HasErrors() {
+			c.showDiagnostics(diags)
+		}
+	}()
+
+	// Set up the UI so we can output directly to stdout
+	ui := &cli.BasicUi{
+		Writer:      os.Stdout,
+		ErrorWriter: os.Stderr,
+	}
+
+	evalOpts := &terraform.EvalOpts{}
+	if lr.PlanOpts != nil {
+		// the LocalRun type is built primarily to support the main operations,
+		// so the variable values end up in the "PlanOpts" even though we're
+		// not actually making a plan.
+		evalOpts.SetVariables = lr.PlanOpts.SetVariables
+	}
+
+	// Before we can evaluate expressions, we must compute and populate any
+	// derived values (input variables, local values, output values)
+	// that are not stored in the persistent state.
+	scope, scopeDiags := lr.Core.Eval(lr.Config, lr.InputState, addrs.RootModuleInstance, evalOpts)
+	diags = diags.Append(scopeDiags)
+	if scope == nil {
+		// scope is nil if there are errors so bad that we can't even build a scope.
+		// Otherwise, we'll try to eval anyway.
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// set the ConsoleMode to true so any available console-only functions included.
+	scope.ConsoleMode = true
+
+	if diags.HasErrors() {
+		diags = diags.Append(tfdiags.SimpleWarning("Due to the problems above, some expressions may produce unexpected results."))
+	}
+
+	// Before we become interactive we'll show any diagnostics we encountered
+	// during initialization, and then afterwards the driver will manage any
+	// further diagnostics itself.
+	c.showDiagnostics(diags)
+
+	// IO Loop
+	session := &repl.Session{
+		Scope: scope,
+	}
+
+	// Determine if stdin is a pipe. If so, we evaluate directly.
+	if c.StdinPiped() {
+		return c.modePiped(session, ui)
+	}
+
+	return c.modeInteractive(session, ui)
+}
+
+func (c *ConsoleCommand) modePiped(session *repl.Session, ui cli.Ui) int {
+	var lastResult string
+	scanner := bufio.NewScanner(os.Stdin)
+	for scanner.Scan() {
+		result, exit, diags := session.Handle(strings.TrimSpace(scanner.Text()))
+		if diags.HasErrors() {
+			// In piped mode we'll exit immediately on error.
+			c.showDiagnostics(diags)
+			return 1
+		}
+		if exit {
+			return 0
+		}
+
+		// Store the last result
+		lastResult = result
+	}
+
+	// Output the final result
+	ui.Output(lastResult)
+
+	return 0
+}
+
+func (c *ConsoleCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] console [options]
+
+  Starts an interactive console for experimenting with Terraform
+  interpolations.
+
+  This will open an interactive console that you can use to type
+  interpolations into and inspect their values. This command loads the
+  current state. This lets you explore and test interpolations before
+  using them in future configurations.
+
+  This command will never modify your state.
+
+Options:
+
+  -state=path       Legacy option for the local backend only. See the local
+                    backend's documentation for more information.
+
+  -var 'foo=bar'    Set a variable in the Terraform configuration. This
+                    flag can be set multiple times.
+
+  -var-file=foo     Set variables in the Terraform configuration from
+                    a file. If "terraform.tfvars" or any ".auto.tfvars"
+                    files are present, they will be automatically loaded.
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *ConsoleCommand) Synopsis() string {
+	return "Try Terraform expressions at an interactive command prompt"
+}
diff --git a/v1.5.7/internal/command/console_interactive.go b/v1.5.7/internal/command/console_interactive.go
new file mode 100644
index 0000000..bcf02f6
--- /dev/null
+++ b/v1.5.7/internal/command/console_interactive.go
@@ -0,0 +1,67 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build !solaris
+// +build !solaris
+
+// The readline library we use doesn't currently support solaris so
+// we just build tag it off.
+
+package command
+
+import (
+	"fmt"
+	"io"
+	"os"
+
+	"github.com/hashicorp/terraform/internal/repl"
+
+	"github.com/chzyer/readline"
+	"github.com/mitchellh/cli"
+)
+
+func (c *ConsoleCommand) modeInteractive(session *repl.Session, ui cli.Ui) int {
+	// Configure input
+	l, err := readline.NewEx(&readline.Config{
+		Prompt:            "> ",
+		InterruptPrompt:   "^C",
+		EOFPrompt:         "exit",
+		HistorySearchFold: true,
+		Stdin:             os.Stdin,
+		Stdout:            os.Stdout,
+		Stderr:            os.Stderr,
+	})
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf(
+			"Error initializing console: %s",
+			err))
+		return 1
+	}
+	defer l.Close()
+
+	for {
+		// Read a line
+		line, err := l.Readline()
+		if err == readline.ErrInterrupt {
+			if len(line) == 0 {
+				break
+			} else {
+				continue
+			}
+		} else if err == io.EOF {
+			break
+		}
+
+		out, exit, diags := session.Handle(line)
+		if diags.HasErrors() {
+			c.showDiagnostics(diags)
+		}
+		if exit {
+			break
+		}
+
+		ui.Output(out)
+	}
+
+	return 0
+}
diff --git a/v1.5.7/internal/command/console_interactive_solaris.go b/v1.5.7/internal/command/console_interactive_solaris.go
new file mode 100644
index 0000000..f58c634
--- /dev/null
+++ b/v1.5.7/internal/command/console_interactive_solaris.go
@@ -0,0 +1,22 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build solaris
+// +build solaris
+
+package command
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/repl"
+	"github.com/mitchellh/cli"
+)
+
+func (c *ConsoleCommand) modeInteractive(session *repl.Session, ui cli.Ui) int {
+	ui.Error(fmt.Sprintf(
+		"The readline library Terraform currently uses for the interactive\n" +
+			"console is not supported by Solaris. Interactive mode is therefore\n" +
+			"not supported on Solaris currently."))
+	return 1
+}
diff --git a/v1.5.7/internal/command/console_test.go b/v1.5.7/internal/command/console_test.go
new file mode 100644
index 0000000..3c8ed5b
--- /dev/null
+++ b/v1.5.7/internal/command/console_test.go
@@ -0,0 +1,241 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"io/ioutil"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/mitchellh/cli"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// ConsoleCommand is tested primarily with tests in the "repl" package.
+// It is not tested here because the Console uses a readline-like library
+// that takes over stdin/stdout. It is difficult to test directly. The
+// core logic is tested in "repl"
+//
+// This file still contains some tests using the stdin-based input.
+
+func TestConsole_basic(t *testing.T) {
+	testCwd(t)
+
+	p := testProvider()
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	c := &ConsoleCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	var output bytes.Buffer
+	defer testStdinPipe(t, strings.NewReader("1+5\n"))()
+	outCloser := testStdoutCapture(t, &output)
+
+	args := []string{}
+	code := c.Run(args)
+	outCloser()
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	actual := output.String()
+	if actual != "6\n" {
+		t.Fatalf("bad: %q", actual)
+	}
+}
+
+func TestConsole_tfvars(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-vars"), td)
+	defer testChdir(t, td)()
+
+	// Write a terraform.tvars
+	varFilePath := filepath.Join(td, "terraform.tfvars")
+	if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"value": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	c := &ConsoleCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	var output bytes.Buffer
+	defer testStdinPipe(t, strings.NewReader("var.foo\n"))()
+	outCloser := testStdoutCapture(t, &output)
+
+	args := []string{}
+	code := c.Run(args)
+	outCloser()
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	actual := output.String()
+	if actual != "\"bar\"\n" {
+		t.Fatalf("bad: %q", actual)
+	}
+}
+
+func TestConsole_unsetRequiredVars(t *testing.T) {
+	// This test is verifying that it's possible to run "terraform console"
+	// without providing values for all required variables, without
+	// "terraform console" producing an interactive prompt for those variables
+	// or producing errors. Instead, it should allow evaluation in that
+	// partial context but see the unset variables values as being unknown.
+	//
+	// This test fixture includes variable "foo" {}, which we are
+	// intentionally not setting here.
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-vars"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"value": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	c := &ConsoleCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	var output bytes.Buffer
+	defer testStdinPipe(t, strings.NewReader("var.foo\n"))()
+	outCloser := testStdoutCapture(t, &output)
+
+	args := []string{}
+	code := c.Run(args)
+	outCloser()
+
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	if got, want := output.String(), "(known after apply)\n"; got != want {
+		t.Fatalf("unexpected output\n got: %q\nwant: %q", got, want)
+	}
+}
+
+func TestConsole_variables(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("variables"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	c := &ConsoleCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	commands := map[string]string{
+		"var.foo\n":          "\"bar\"\n",
+		"var.snack\n":        "\"popcorn\"\n",
+		"var.secret_snack\n": "(sensitive value)\n",
+		"local.snack_bar\n":  "[\n  \"popcorn\",\n  (sensitive value),\n]\n",
+	}
+
+	args := []string{}
+
+	for cmd, val := range commands {
+		var output bytes.Buffer
+		defer testStdinPipe(t, strings.NewReader(cmd))()
+		outCloser := testStdoutCapture(t, &output)
+		code := c.Run(args)
+		outCloser()
+		if code != 0 {
+			t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+		}
+
+		actual := output.String()
+		if output.String() != val {
+			t.Fatalf("bad: %q, expected %q", actual, val)
+		}
+	}
+}
+
+func TestConsole_modules(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("modules"), td)
+	defer testChdir(t, td)()
+
+	p := applyFixtureProvider()
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+
+	c := &ConsoleCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	commands := map[string]string{
+		"module.child.myoutput\n":          "\"bar\"\n",
+		"module.count_child[0].myoutput\n": "\"bar\"\n",
+		"local.foo\n":                      "3\n",
+	}
+
+	args := []string{}
+
+	for cmd, val := range commands {
+		var output bytes.Buffer
+		defer testStdinPipe(t, strings.NewReader(cmd))()
+		outCloser := testStdoutCapture(t, &output)
+		code := c.Run(args)
+		outCloser()
+		if code != 0 {
+			t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+		}
+
+		actual := output.String()
+		if output.String() != val {
+			t.Fatalf("bad: %q, expected %q", actual, val)
+		}
+	}
+}
diff --git a/v1.5.7/internal/command/e2etest/.gitignore b/v1.5.7/internal/command/e2etest/.gitignore
new file mode 100644
index 0000000..a007fea
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/.gitignore
@@ -0,0 +1 @@
+build/*
diff --git a/v1.5.7/internal/command/e2etest/automation_test.go b/v1.5.7/internal/command/e2etest/automation_test.go
new file mode 100644
index 0000000..a50d8c7
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/automation_test.go
@@ -0,0 +1,247 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"path/filepath"
+	"reflect"
+	"sort"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/e2e"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+// The tests in this file run through different scenarios recommended in our
+// "Running Terraform in Automation" guide:
+//     https://www.terraform.io/guides/running-terraform-in-automation.html
+
+// TestPlanApplyInAutomation runs through the "main case" of init, plan, apply
+// using the specific command line options suggested in the guide.
+func TestPlanApplyInAutomation(t *testing.T) {
+	t.Parallel()
+
+	// This test reaches out to releases.hashicorp.com to download the
+	// template and null providers, so it can only run if network access is
+	// allowed.
+	skipIfCannotAccessNetwork(t)
+
+	fixturePath := filepath.Join("testdata", "full-workflow-null")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	// We advertise that _any_ non-empty value works, so we'll test something
+	// unconventional here.
+	tf.AddEnv("TF_IN_AUTOMATION=yes-please")
+
+	//// INIT
+	stdout, stderr, err := tf.Run("init", "-input=false")
+	if err != nil {
+		t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	// Make sure we actually downloaded the plugins, rather than picking up
+	// copies that might be already installed globally on the system.
+	if !strings.Contains(stdout, "Installing hashicorp/template v") {
+		t.Errorf("template provider download message is missing from init output:\n%s", stdout)
+		t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)")
+	}
+	if !strings.Contains(stdout, "Installing hashicorp/null v") {
+		t.Errorf("null provider download message is missing from init output:\n%s", stdout)
+		t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)")
+	}
+
+	//// PLAN
+	stdout, stderr, err = tf.Run("plan", "-out=tfplan", "-input=false")
+	if err != nil {
+		t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !strings.Contains(stdout, "1 to add, 0 to change, 0 to destroy") {
+		t.Errorf("incorrect plan tally; want 1 to add:\n%s", stdout)
+	}
+
+	// Because we're running with TF_IN_AUTOMATION set, we should not see
+	// any mention of the plan file in the output.
+	if strings.Contains(stdout, "tfplan") {
+		t.Errorf("unwanted mention of \"tfplan\" file in plan output\n%s", stdout)
+	}
+
+	plan, err := tf.Plan("tfplan")
+	if err != nil {
+		t.Fatalf("failed to read plan file: %s", err)
+	}
+
+	// stateResources := plan.Changes.Resources
+	diffResources := plan.Changes.Resources
+	if len(diffResources) != 1 {
+		t.Errorf("incorrect number of resources in plan")
+	}
+
+	expected := map[string]plans.Action{
+		"null_resource.test": plans.Create,
+	}
+
+	for _, r := range diffResources {
+		expectedAction, ok := expected[r.Addr.String()]
+		if !ok {
+			t.Fatalf("unexpected change for %q", r.Addr)
+		}
+		if r.Action != expectedAction {
+			t.Fatalf("unexpected action %q for %q", r.Action, r.Addr)
+		}
+	}
+
+	//// APPLY
+	stdout, stderr, err = tf.Run("apply", "-input=false", "tfplan")
+	if err != nil {
+		t.Fatalf("unexpected apply error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !strings.Contains(stdout, "Resources: 1 added, 0 changed, 0 destroyed") {
+		t.Errorf("incorrect apply tally; want 1 added:\n%s", stdout)
+	}
+
+	state, err := tf.LocalState()
+	if err != nil {
+		t.Fatalf("failed to read state file: %s", err)
+	}
+
+	stateResources := state.RootModule().Resources
+	var gotResources []string
+	for n := range stateResources {
+		gotResources = append(gotResources, n)
+	}
+	sort.Strings(gotResources)
+
+	wantResources := []string{
+		"data.template_file.test",
+		"null_resource.test",
+	}
+
+	if !reflect.DeepEqual(gotResources, wantResources) {
+		t.Errorf("wrong resources in state\ngot: %#v\nwant: %#v", gotResources, wantResources)
+	}
+}
+
+// TestAutoApplyInAutomation tests the scenario where the caller skips creating
+// an explicit plan and instead forces automatic application of changes.
+func TestAutoApplyInAutomation(t *testing.T) {
+	t.Parallel()
+
+	// This test reaches out to releases.hashicorp.com to download the
+	// template and null providers, so it can only run if network access is
+	// allowed.
+	skipIfCannotAccessNetwork(t)
+
+	fixturePath := filepath.Join("testdata", "full-workflow-null")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	// We advertise that _any_ non-empty value works, so we'll test something
+	// unconventional here.
+	tf.AddEnv("TF_IN_AUTOMATION=very-much-so")
+
+	//// INIT
+	stdout, stderr, err := tf.Run("init", "-input=false")
+	if err != nil {
+		t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	// Make sure we actually downloaded the plugins, rather than picking up
+	// copies that might be already installed globally on the system.
+	if !strings.Contains(stdout, "Installing hashicorp/template v") {
+		t.Errorf("template provider download message is missing from init output:\n%s", stdout)
+		t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)")
+	}
+	if !strings.Contains(stdout, "Installing hashicorp/null v") {
+		t.Errorf("null provider download message is missing from init output:\n%s", stdout)
+		t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)")
+	}
+
+	//// APPLY
+	stdout, stderr, err = tf.Run("apply", "-input=false", "-auto-approve")
+	if err != nil {
+		t.Fatalf("unexpected apply error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !strings.Contains(stdout, "Resources: 1 added, 0 changed, 0 destroyed") {
+		t.Errorf("incorrect apply tally; want 1 added:\n%s", stdout)
+	}
+
+	state, err := tf.LocalState()
+	if err != nil {
+		t.Fatalf("failed to read state file: %s", err)
+	}
+
+	stateResources := state.RootModule().Resources
+	var gotResources []string
+	for n := range stateResources {
+		gotResources = append(gotResources, n)
+	}
+	sort.Strings(gotResources)
+
+	wantResources := []string{
+		"data.template_file.test",
+		"null_resource.test",
+	}
+
+	if !reflect.DeepEqual(gotResources, wantResources) {
+		t.Errorf("wrong resources in state\ngot: %#v\nwant: %#v", gotResources, wantResources)
+	}
+}
+
+// TestPlanOnlyInAutomation tests the scenario of creating a "throwaway" plan,
+// which we recommend as a way to verify a pull request.
+func TestPlanOnlyInAutomation(t *testing.T) {
+	t.Parallel()
+
+	// This test reaches out to releases.hashicorp.com to download the
+	// template and null providers, so it can only run if network access is
+	// allowed.
+	skipIfCannotAccessNetwork(t)
+
+	fixturePath := filepath.Join("testdata", "full-workflow-null")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	// We advertise that _any_ non-empty value works, so we'll test something
+	// unconventional here.
+	tf.AddEnv("TF_IN_AUTOMATION=verily")
+
+	//// INIT
+	stdout, stderr, err := tf.Run("init", "-input=false")
+	if err != nil {
+		t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	// Make sure we actually downloaded the plugins, rather than picking up
+	// copies that might be already installed globally on the system.
+	if !strings.Contains(stdout, "Installing hashicorp/template v") {
+		t.Errorf("template provider download message is missing from init output:\n%s", stdout)
+		t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)")
+	}
+	if !strings.Contains(stdout, "Installing hashicorp/null v") {
+		t.Errorf("null provider download message is missing from init output:\n%s", stdout)
+		t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)")
+	}
+
+	//// PLAN
+	stdout, stderr, err = tf.Run("plan", "-input=false")
+	if err != nil {
+		t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !strings.Contains(stdout, "1 to add, 0 to change, 0 to destroy") {
+		t.Errorf("incorrect plan tally; want 1 to add:\n%s", stdout)
+	}
+
+	// Because we're running with TF_IN_AUTOMATION set, we should not see
+	// any mention of the the "terraform apply" command in the output.
+	if strings.Contains(stdout, "terraform apply") {
+		t.Errorf("unwanted mention of \"terraform apply\" in plan output\n%s", stdout)
+	}
+
+	if tf.FileExists("tfplan") {
+		t.Error("plan file was created, but was not expected")
+	}
+}
diff --git a/v1.5.7/internal/command/e2etest/doc.go b/v1.5.7/internal/command/e2etest/doc.go
new file mode 100644
index 0000000..612c6ce
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/doc.go
@@ -0,0 +1,32 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package e2etest contains a set of tests that run against a real Terraform
+// binary, compiled on the fly at the start of the test run.
+//
+// These tests help ensure that key end-to-end Terraform use-cases are working
+// for a real binary, whereas other tests always have at least _some_ amount
+// of test stubbing.
+//
+// The goal of this package is not to duplicate the functional testing done
+// in other packages but rather to fully exercise a few important workflows
+// in a realistic way.
+//
+// These tests can be used in two ways. The simplest way is to just run them
+// with "go test" as normal:
+//
+//	go test -v github.com/hashicorp/terraform/internal/command/e2etest
+//
+// This will compile on the fly a Terraform binary and run the tests against
+// it.
+//
+// Alternatively, the make-archive.sh script can be used to produce a
+// self-contained zip file that can be shipped to another machine to run
+// the tests there without needing a locally-installed Go compiler. This
+// is primarily useful for testing cross-compiled builds during our release
+// process. For more information, see the commentary in make-archive.sh.
+//
+// The TF_ACC environment variable must be set for the tests to reach out
+// to external network services. Since these are end-to-end tests, only a
+// few very basic tests can execute without this environment variable set.
+package e2etest
diff --git a/v1.5.7/internal/command/e2etest/init_test.go b/v1.5.7/internal/command/e2etest/init_test.go
new file mode 100644
index 0000000..b65b3ea
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/init_test.go
@@ -0,0 +1,411 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"bytes"
+	"fmt"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+
+	"github.com/hashicorp/terraform/internal/e2e"
+)
+
+func TestInitProviders(t *testing.T) {
+	t.Parallel()
+
+	// This test reaches out to releases.hashicorp.com to download the
+	// template provider, so it can only run if network access is allowed.
+	// We intentionally don't try to stub this here, because there's already
+	// a stubbed version of this in the "command" package and so the goal here
+	// is to test the interaction with the real repository.
+	skipIfCannotAccessNetwork(t)
+
+	fixturePath := filepath.Join("testdata", "template-provider")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	stdout, stderr, err := tf.Run("init")
+	if err != nil {
+		t.Errorf("unexpected error: %s", err)
+	}
+
+	if stderr != "" {
+		t.Errorf("unexpected stderr output:\n%s", stderr)
+	}
+
+	if !strings.Contains(stdout, "Terraform has been successfully initialized!") {
+		t.Errorf("success message is missing from output:\n%s", stdout)
+	}
+
+	if !strings.Contains(stdout, "- Installing hashicorp/template v") {
+		t.Errorf("provider download message is missing from output:\n%s", stdout)
+		t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)")
+	}
+
+	if !strings.Contains(stdout, "Terraform has created a lock file") {
+		t.Errorf("lock file notification is missing from output:\n%s", stdout)
+	}
+
+}
+
+func TestInitProvidersInternal(t *testing.T) {
+	t.Parallel()
+
+	// This test should _not_ reach out anywhere because the "terraform"
+	// provider is internal to the core terraform binary.
+
+	fixturePath := filepath.Join("testdata", "terraform-provider")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	stdout, stderr, err := tf.Run("init")
+	if err != nil {
+		t.Errorf("unexpected error: %s", err)
+	}
+
+	if stderr != "" {
+		t.Errorf("unexpected stderr output:\n%s", stderr)
+	}
+
+	if !strings.Contains(stdout, "Terraform has been successfully initialized!") {
+		t.Errorf("success message is missing from output:\n%s", stdout)
+	}
+
+	if strings.Contains(stdout, "Installing hashicorp/terraform") {
+		// Shouldn't have downloaded anything with this config, because the
+		// provider is built in.
+		t.Errorf("provider download message appeared in output:\n%s", stdout)
+	}
+
+	if strings.Contains(stdout, "Installing terraform.io/builtin/terraform") {
+		// Shouldn't have downloaded anything with this config, because the
+		// provider is built in.
+		t.Errorf("provider download message appeared in output:\n%s", stdout)
+	}
+}
+
+func TestInitProvidersVendored(t *testing.T) {
+	t.Parallel()
+
+	// This test will try to reach out to registry.terraform.io as one of the
+	// possible installation locations for
+	// hashicorp/null, where it will find that
+	// versions do exist but will ultimately select the version that is
+	// vendored due to the version constraint.
+	skipIfCannotAccessNetwork(t)
+
+	fixturePath := filepath.Join("testdata", "vendored-provider")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	// Our fixture dir has a generic os_arch dir, which we need to customize
+	// to the actual OS/arch where this test is running in order to get the
+	// desired result.
+	fixtMachineDir := tf.Path("terraform.d/plugins/registry.terraform.io/hashicorp/null/1.0.0+local/os_arch")
+	wantMachineDir := tf.Path("terraform.d/plugins/registry.terraform.io/hashicorp/null/1.0.0+local/", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
+	err := os.Rename(fixtMachineDir, wantMachineDir)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	stdout, stderr, err := tf.Run("init")
+	if err != nil {
+		t.Errorf("unexpected error: %s", err)
+	}
+
+	if stderr != "" {
+		t.Errorf("unexpected stderr output:\n%s", stderr)
+	}
+
+	if !strings.Contains(stdout, "Terraform has been successfully initialized!") {
+		t.Errorf("success message is missing from output:\n%s", stdout)
+	}
+
+	if !strings.Contains(stdout, "- Installing hashicorp/null v1.0.0+local") {
+		t.Errorf("provider download message is missing from output:\n%s", stdout)
+		t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)")
+	}
+
+}
+
+func TestInitProvidersLocalOnly(t *testing.T) {
+	t.Parallel()
+
+	// This test should not reach out to the network if it is behaving as
+	// intended. If it _does_ try to access an upstream registry and encounter
+	// an error doing so then that's a legitimate test failure that should be
+	// fixed. (If it incorrectly reaches out anywhere then it's likely to be
+	// to the host "example.com", which is the placeholder domain we use in
+	// the test fixture.)
+
+	fixturePath := filepath.Join("testdata", "local-only-provider")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+	// If you run this test on a workstation with a plugin-cache directory
+	// configured, it will leave a bad directory behind and terraform init will
+	// not work until you remove it.
+	//
+	// To avoid this, we will  "zero out" any existing cli config file.
+	tf.AddEnv("TF_CLI_CONFIG_FILE=")
+
+	// Our fixture dir has a generic os_arch dir, which we need to customize
+	// to the actual OS/arch where this test is running in order to get the
+	// desired result.
+	fixtMachineDir := tf.Path("terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/os_arch")
+	wantMachineDir := tf.Path("terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
+	err := os.Rename(fixtMachineDir, wantMachineDir)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	stdout, stderr, err := tf.Run("init")
+	if err != nil {
+		t.Errorf("unexpected error: %s", err)
+	}
+
+	if stderr != "" {
+		t.Errorf("unexpected stderr output:\n%s", stderr)
+	}
+
+	if !strings.Contains(stdout, "Terraform has been successfully initialized!") {
+		t.Errorf("success message is missing from output:\n%s", stdout)
+	}
+
+	if !strings.Contains(stdout, "- Installing example.com/awesomecorp/happycloud v1.2.0") {
+		t.Errorf("provider download message is missing from output:\n%s", stdout)
+		t.Logf("(this can happen if you have a conflicting copy of the plugin in one of the global plugin search dirs)")
+	}
+}
+
+func TestInitProvidersCustomMethod(t *testing.T) {
+	t.Parallel()
+
+	// This test should not reach out to the network if it is behaving as
+	// intended. If it _does_ try to access an upstream registry and encounter
+	// an error doing so then that's a legitimate test failure that should be
+	// fixed. (If it incorrectly reaches out anywhere then it's likely to be
+	// to the host "example.com", which is the placeholder domain we use in
+	// the test fixture.)
+
+	for _, configFile := range []string{"cliconfig.tfrc", "cliconfig.tfrc.json"} {
+		t.Run(configFile, func(t *testing.T) {
+			fixturePath := filepath.Join("testdata", "custom-provider-install-method")
+			tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+			// Our fixture dir has a generic os_arch dir, which we need to customize
+			// to the actual OS/arch where this test is running in order to get the
+			// desired result.
+			fixtMachineDir := tf.Path("fs-mirror/example.com/awesomecorp/happycloud/1.2.0/os_arch")
+			wantMachineDir := tf.Path("fs-mirror/example.com/awesomecorp/happycloud/1.2.0/", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
+			err := os.Rename(fixtMachineDir, wantMachineDir)
+			if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			// We'll use a local CLI configuration file taken from our fixture
+			// directory so we can force a custom installation method config.
+			tf.AddEnv("TF_CLI_CONFIG_FILE=" + tf.Path(configFile))
+
+			stdout, stderr, err := tf.Run("init")
+			if err != nil {
+				t.Errorf("unexpected error: %s", err)
+			}
+
+			if stderr != "" {
+				t.Errorf("unexpected stderr output:\n%s", stderr)
+			}
+
+			if !strings.Contains(stdout, "Terraform has been successfully initialized!") {
+				t.Errorf("success message is missing from output:\n%s", stdout)
+			}
+
+			if !strings.Contains(stdout, "- Installing example.com/awesomecorp/happycloud v1.2.0") {
+				t.Errorf("provider download message is missing from output:\n%s", stdout)
+			}
+		})
+	}
+}
+
+func TestInitProviders_pluginCache(t *testing.T) {
+	t.Parallel()
+
+	// This test reaches out to releases.hashicorp.com to access plugin
+	// metadata, and download the null plugin, though the template plugin
+	// should come from local cache.
+	skipIfCannotAccessNetwork(t)
+
+	fixturePath := filepath.Join("testdata", "plugin-cache")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	// Our fixture dir has a generic os_arch dir, which we need to customize
+	// to the actual OS/arch where this test is running in order to get the
+	// desired result.
+	fixtMachineDir := tf.Path("cache/registry.terraform.io/hashicorp/template/2.1.0/os_arch")
+	wantMachineDir := tf.Path("cache/registry.terraform.io/hashicorp/template/2.1.0/", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
+	err := os.Rename(fixtMachineDir, wantMachineDir)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	cmd := tf.Cmd("init")
+
+	// convert the slashes if building for windows.
+	p := filepath.FromSlash("./cache")
+	cmd.Env = append(cmd.Env, "TF_PLUGIN_CACHE_DIR="+p)
+	err = cmd.Run()
+	if err != nil {
+		t.Errorf("unexpected error: %s", err)
+	}
+
+	path := filepath.FromSlash(fmt.Sprintf(".terraform/providers/registry.terraform.io/hashicorp/template/2.1.0/%s_%s/terraform-provider-template_v2.1.0_x4", runtime.GOOS, runtime.GOARCH))
+	content, err := tf.ReadFile(path)
+	if err != nil {
+		t.Fatalf("failed to read installed plugin from %s: %s", path, err)
+	}
+	if strings.TrimSpace(string(content)) != "this is not a real plugin" {
+		t.Errorf("template plugin was not installed from local cache")
+	}
+
+	nullLinkPath := filepath.FromSlash(fmt.Sprintf(".terraform/providers/registry.terraform.io/hashicorp/null/2.1.0/%s_%s/terraform-provider-null_v2.1.0_x4", runtime.GOOS, runtime.GOARCH))
+	if runtime.GOOS == "windows" {
+		nullLinkPath = nullLinkPath + ".exe"
+	}
+	if !tf.FileExists(nullLinkPath) {
+		t.Errorf("null plugin was not installed into %s", nullLinkPath)
+	}
+
+	nullCachePath := filepath.FromSlash(fmt.Sprintf("cache/registry.terraform.io/hashicorp/null/2.1.0/%s_%s/terraform-provider-null_v2.1.0_x4", runtime.GOOS, runtime.GOARCH))
+	if runtime.GOOS == "windows" {
+		nullCachePath = nullCachePath + ".exe"
+	}
+	if !tf.FileExists(nullCachePath) {
+		t.Errorf("null plugin is not in cache after install. expected in: %s", nullCachePath)
+	}
+}
+
+func TestInit_fromModule(t *testing.T) {
+	t.Parallel()
+
+	// This test reaches out to registry.terraform.io and github.com to lookup
+	// and fetch a module.
+	skipIfCannotAccessNetwork(t)
+
+	fixturePath := filepath.Join("testdata", "empty")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	cmd := tf.Cmd("init", "-from-module=hashicorp/vault/aws")
+	cmd.Stdin = nil
+	cmd.Stderr = &bytes.Buffer{}
+
+	err := cmd.Run()
+	if err != nil {
+		t.Errorf("unexpected error: %s", err)
+	}
+
+	stderr := cmd.Stderr.(*bytes.Buffer).String()
+	if stderr != "" {
+		t.Errorf("unexpected stderr output:\n%s", stderr)
+	}
+
+	content, err := tf.ReadFile("main.tf")
+	if err != nil {
+		t.Fatalf("failed to read main.tf: %s", err)
+	}
+	if !bytes.Contains(content, []byte("vault")) {
+		t.Fatalf("main.tf doesn't appear to be a vault configuration: \n%s", content)
+	}
+}
+
+func TestInitProviderNotFound(t *testing.T) {
+	t.Parallel()
+
+	// This test will reach out to registry.terraform.io as one of the possible
+	// installation locations for hashicorp/nonexist, which should not exist.
+	skipIfCannotAccessNetwork(t)
+
+	fixturePath := filepath.Join("testdata", "provider-not-found")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	t.Run("registry provider not found", func(t *testing.T) {
+		_, stderr, err := tf.Run("init", "-no-color")
+		if err == nil {
+			t.Fatal("expected error, got success")
+		}
+
+		oneLineStderr := strings.ReplaceAll(stderr, "\n", " ")
+		if !strings.Contains(oneLineStderr, "provider registry registry.terraform.io does not have a provider named registry.terraform.io/hashicorp/nonexist") {
+			t.Errorf("expected error message is missing from output:\n%s", stderr)
+		}
+
+		if !strings.Contains(oneLineStderr, "All modules should specify their required_providers") {
+			t.Errorf("expected error message is missing from output:\n%s", stderr)
+		}
+	})
+
+	t.Run("local provider not found", func(t *testing.T) {
+		// The -plugin-dir directory must exist for the provider installer to search it.
+		pluginDir := tf.Path("empty")
+		if err := os.Mkdir(pluginDir, os.ModePerm); err != nil {
+			t.Fatal(err)
+		}
+
+		_, stderr, err := tf.Run("init", "-no-color", "-plugin-dir="+pluginDir)
+		if err == nil {
+			t.Fatal("expected error, got success")
+		}
+
+		if !strings.Contains(stderr, "provider registry.terraform.io/hashicorp/nonexist was not\nfound in any of the search locations\n\n  - "+pluginDir) {
+			t.Errorf("expected error message is missing from output:\n%s", stderr)
+		}
+	})
+
+	t.Run("special characters enabled", func(t *testing.T) {
+		_, stderr, err := tf.Run("init")
+		if err == nil {
+			t.Fatal("expected error, got success")
+		}
+
+		expectedErr := `╷
+│ Error: Failed to query available provider packages
+│` + ` ` + `
+│ Could not retrieve the list of available versions for provider
+│ hashicorp/nonexist: provider registry registry.terraform.io does not have a
+│ provider named registry.terraform.io/hashicorp/nonexist
+│ 
+│ All modules should specify their required_providers so that external
+│ consumers will get the correct providers when using a module. To see which
+│ modules are currently depending on hashicorp/nonexist, run the following
+│ command:
+│     terraform providers
+╵
+
+`
+		if stripAnsi(stderr) != expectedErr {
+			t.Errorf("wrong output:\n%s", cmp.Diff(stripAnsi(stderr), expectedErr))
+		}
+	})
+}
+
+func TestInitProviderWarnings(t *testing.T) {
+	t.Parallel()
+
+	// This test will reach out to registry.terraform.io as one of the possible
+	// installation locations for hashicorp/nonexist, which should not exist.
+	skipIfCannotAccessNetwork(t)
+
+	fixturePath := filepath.Join("testdata", "provider-warnings")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	stdout, _, err := tf.Run("init")
+	if err == nil {
+		t.Fatal("expected error, got success")
+	}
+
+	if !strings.Contains(stdout, "This provider is archived and no longer needed.") {
+		t.Errorf("expected warning message is missing from output:\n%s", stdout)
+	}
+
+}
diff --git a/v1.5.7/internal/command/e2etest/main_test.go b/v1.5.7/internal/command/e2etest/main_test.go
new file mode 100644
index 0000000..3ab67a2
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/main_test.go
@@ -0,0 +1,79 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/e2e"
+)
+
+var terraformBin string
+
+// canRunGoBuild is a short-term compromise to account for the fact that we
+// have a small number of tests that work by building helper programs using
+// "go build" at runtime, but we can't do that in our isolated test mode
+// driven by the make-archive.sh script.
+//
+// FIXME: Rework this a bit so that we build the necessary helper programs
+// (test plugins, etc) as part of the initial suite setup, and in the
+// make-archive.sh script, so that we can run all of the tests in both
+// situations with the tests just using the executable already built for
+// them, as we do for terraformBin.
+var canRunGoBuild bool
+
+func TestMain(m *testing.M) {
+	teardown := setup()
+	code := m.Run()
+	teardown()
+	os.Exit(code)
+}
+
+func setup() func() {
+	if terraformBin != "" {
+		// this is pre-set when we're running in a binary produced from
+		// the make-archive.sh script, since that is for testing an
+		// executable obtained from a real release package. However, we do
+		// need to turn it into an absolute path so that we can find it
+		// when we change the working directory during tests.
+		var err error
+		terraformBin, err = filepath.Abs(terraformBin)
+		if err != nil {
+			panic(fmt.Sprintf("failed to find absolute path of terraform executable: %s", err))
+		}
+		return func() {}
+	}
+
+	tmpFilename := e2e.GoBuild("github.com/hashicorp/terraform", "terraform")
+
+	// Make the executable available for use in tests
+	terraformBin = tmpFilename
+
+	// Tests running in the ad-hoc testing mode are allowed to use "go build"
+	// and similar to produce other test executables.
+	// (See the comment on this variable's declaration for more information.)
+	canRunGoBuild = true
+
+	return func() {
+		os.Remove(tmpFilename)
+	}
+}
+
+func canAccessNetwork() bool {
+	// We re-use the flag normally used for acceptance tests since that's
+	// established as a way to opt-in to reaching out to real systems that
+	// may suffer transient errors.
+	return os.Getenv("TF_ACC") != ""
+}
+
+func skipIfCannotAccessNetwork(t *testing.T) {
+	t.Helper()
+
+	if !canAccessNetwork() {
+		t.Skip("network access not allowed; use TF_ACC=1 to enable")
+	}
+}
diff --git a/v1.5.7/internal/command/e2etest/make-archive.sh b/v1.5.7/internal/command/e2etest/make-archive.sh
new file mode 100755
index 0000000..e797787
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/make-archive.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+
+# For normal use this package can just be tested with "go test" as standard,
+# but this script is an alternative to allow the tests to be run somewhere
+# other than where they are built.
+
+# The primary use for this is cross-compilation, where e.g. we can produce an
+# archive that can be extracted on a Windows system to run the e2e tests there:
+#    $ GOOS=windows GOARCH=amd64 ./make-archive.sh
+#
+# This will produce a zip file build/terraform-e2etest_windows_amd64.zip which
+# can be shipped off to a Windows amd64 system, extracted to some directory,
+# and then executed as follows:
+#    set TF_ACC=1
+#    ./e2etest.exe
+#
+# Because separated e2etest harnesses are intended for testing against "real"
+# release executables, the generated archives don't include a copy of
+# the Terraform executable. Instead, the caller of the tests must retrieve
+# and extract a release package into the working directory before running
+# the e2etest executable, so that "e2etest" can find and execute it.
+
+set +euo pipefail
+
+# Always run from the directory where this script lives
+cd "$( dirname "${BASH_SOURCE[0]}" )"
+
+GOOS="$(go env GOOS)"
+GOARCH="$(go env GOARCH)"
+GOEXE="$(go env GOEXE)"
+OUTDIR="build/${GOOS}_${GOARCH}"
+OUTFILE="terraform-e2etest_${GOOS}_${GOARCH}.zip"
+
+LDFLAGS="-X github.com/hashicorp/terraform/internal/command/e2etest.terraformBin=./terraform$GOEXE"
+# Caller may pass in the environment variable GO_LDFLAGS with additional
+# flags we'll use when building.
+if [ -n "${GO_LDFLAGS+set}" ]; then
+    LDFLAGS="${GO_LDFLAGS} ${LDFLAGS}"
+fi
+
+mkdir -p "$OUTDIR"
+
+# We need the test fixtures available when we run the tests.
+cp -r testdata "$OUTDIR/testdata"
+
+# Build the test program
+go test -o "$OUTDIR/e2etest$GOEXE" -c -ldflags "$LDFLAGS" github.com/hashicorp/terraform/internal/command/e2etest
+
+# Now bundle it all together for easy shipping!
+cd "$OUTDIR"
+zip -r "../$OUTFILE" *
+
+echo "e2etest archive created at build/$OUTFILE"
diff --git a/v1.5.7/internal/command/e2etest/module_archive_test.go b/v1.5.7/internal/command/e2etest/module_archive_test.go
new file mode 100644
index 0000000..b8e78b7
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/module_archive_test.go
@@ -0,0 +1,35 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/e2e"
+)
+
+func TestInitModuleArchive(t *testing.T) {
+	t.Parallel()
+
+	// this fetches a module archive from github
+	skipIfCannotAccessNetwork(t)
+
+	fixturePath := filepath.Join("testdata", "module-archive")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	stdout, stderr, err := tf.Run("init")
+	if err != nil {
+		t.Errorf("unexpected error: %s", err)
+	}
+
+	if stderr != "" {
+		t.Errorf("unexpected stderr output:\n%s", stderr)
+	}
+
+	if !strings.Contains(stdout, "Terraform has been successfully initialized!") {
+		t.Errorf("success message is missing from output:\n%s", stdout)
+	}
+}
diff --git a/v1.5.7/internal/command/e2etest/primary_test.go b/v1.5.7/internal/command/e2etest/primary_test.go
new file mode 100644
index 0000000..bdb160d
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/primary_test.go
@@ -0,0 +1,232 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"path/filepath"
+	"reflect"
+	"sort"
+	"strings"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/hashicorp/terraform/internal/e2e"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// The tests in this file are for the "primary workflow", which includes
+// variants of the following sequence, with different details:
+// terraform init
+// terraform plan
+// terraform apply
+// terraform destroy
+
+func TestPrimarySeparatePlan(t *testing.T) {
+	t.Parallel()
+
+	// This test reaches out to releases.hashicorp.com to download the
+	// template and null providers, so it can only run if network access is
+	// allowed.
+	skipIfCannotAccessNetwork(t)
+
+	fixturePath := filepath.Join("testdata", "full-workflow-null")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	//// INIT
+	stdout, stderr, err := tf.Run("init")
+	if err != nil {
+		t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	// Make sure we actually downloaded the plugins, rather than picking up
+	// copies that might be already installed globally on the system.
+	if !strings.Contains(stdout, "Installing hashicorp/template v") {
+		t.Errorf("template provider download message is missing from init output:\n%s", stdout)
+		t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)")
+	}
+	if !strings.Contains(stdout, "Installing hashicorp/null v") {
+		t.Errorf("null provider download message is missing from init output:\n%s", stdout)
+		t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)")
+	}
+
+	//// PLAN
+	stdout, stderr, err = tf.Run("plan", "-out=tfplan")
+	if err != nil {
+		t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !strings.Contains(stdout, "1 to add, 0 to change, 0 to destroy") {
+		t.Errorf("incorrect plan tally; want 1 to add:\n%s", stdout)
+	}
+
+	if !strings.Contains(stdout, "Saved the plan to: tfplan") {
+		t.Errorf("missing \"Saved the plan to...\" message in plan output\n%s", stdout)
+	}
+	if !strings.Contains(stdout, "terraform apply \"tfplan\"") {
+		t.Errorf("missing next-step instruction in plan output\n%s", stdout)
+	}
+
+	plan, err := tf.Plan("tfplan")
+	if err != nil {
+		t.Fatalf("failed to read plan file: %s", err)
+	}
+
+	diffResources := plan.Changes.Resources
+	if len(diffResources) != 1 {
+		t.Errorf("incorrect number of resources in plan")
+	}
+
+	expected := map[string]plans.Action{
+		"null_resource.test": plans.Create,
+	}
+
+	for _, r := range diffResources {
+		expectedAction, ok := expected[r.Addr.String()]
+		if !ok {
+			t.Fatalf("unexpected change for %q", r.Addr)
+		}
+		if r.Action != expectedAction {
+			t.Fatalf("unexpected action %q for %q", r.Action, r.Addr)
+		}
+	}
+
+	//// APPLY
+	stdout, stderr, err = tf.Run("apply", "tfplan")
+	if err != nil {
+		t.Fatalf("unexpected apply error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !strings.Contains(stdout, "Resources: 1 added, 0 changed, 0 destroyed") {
+		t.Errorf("incorrect apply tally; want 1 added:\n%s", stdout)
+	}
+
+	state, err := tf.LocalState()
+	if err != nil {
+		t.Fatalf("failed to read state file: %s", err)
+	}
+
+	stateResources := state.RootModule().Resources
+	var gotResources []string
+	for n := range stateResources {
+		gotResources = append(gotResources, n)
+	}
+	sort.Strings(gotResources)
+
+	wantResources := []string{
+		"data.template_file.test",
+		"null_resource.test",
+	}
+
+	if !reflect.DeepEqual(gotResources, wantResources) {
+		t.Errorf("wrong resources in state\ngot: %#v\nwant: %#v", gotResources, wantResources)
+	}
+
+	//// DESTROY
+	stdout, stderr, err = tf.Run("destroy", "-auto-approve")
+	if err != nil {
+		t.Fatalf("unexpected destroy error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !strings.Contains(stdout, "Resources: 1 destroyed") {
+		t.Errorf("incorrect destroy tally; want 1 destroyed:\n%s", stdout)
+	}
+
+	state, err = tf.LocalState()
+	if err != nil {
+		t.Fatalf("failed to read state file after destroy: %s", err)
+	}
+
+	stateResources = state.RootModule().Resources
+	if len(stateResources) != 0 {
+		t.Errorf("wrong resources in state after destroy; want none, but still have:%s", spew.Sdump(stateResources))
+	}
+
+}
+
+func TestPrimaryChdirOption(t *testing.T) {
+	t.Parallel()
+
+	// This test case does not include any provider dependencies, so it's
+	// safe to run it even when network access is disallowed.
+
+	fixturePath := filepath.Join("testdata", "chdir-option")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	//// INIT
+	_, stderr, err := tf.Run("-chdir=subdir", "init")
+	if err != nil {
+		t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	//// PLAN
+	stdout, stderr, err := tf.Run("-chdir=subdir", "plan", "-out=tfplan")
+	if err != nil {
+		t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if want := "You can apply this plan to save these new output values"; !strings.Contains(stdout, want) {
+		t.Errorf("missing expected message for an outputs-only plan\ngot:\n%s\n\nwant substring: %s", stdout, want)
+	}
+
+	if !strings.Contains(stdout, "Saved the plan to: tfplan") {
+		t.Errorf("missing \"Saved the plan to...\" message in plan output\n%s", stdout)
+	}
+	if !strings.Contains(stdout, "terraform apply \"tfplan\"") {
+		t.Errorf("missing next-step instruction in plan output\n%s", stdout)
+	}
+
+	// The saved plan is in the subdirectory because -chdir switched there
+	plan, err := tf.Plan("subdir/tfplan")
+	if err != nil {
+		t.Fatalf("failed to read plan file: %s", err)
+	}
+
+	diffResources := plan.Changes.Resources
+	if len(diffResources) != 0 {
+		t.Errorf("incorrect diff in plan; want no resource changes, but have:\n%s", spew.Sdump(diffResources))
+	}
+
+	//// APPLY
+	stdout, stderr, err = tf.Run("-chdir=subdir", "apply", "tfplan")
+	if err != nil {
+		t.Fatalf("unexpected apply error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !strings.Contains(stdout, "Resources: 0 added, 0 changed, 0 destroyed") {
+		t.Errorf("incorrect apply tally; want 0 added:\n%s", stdout)
+	}
+
+	// The state file is in subdir because -chdir changed the current working directory.
+	state, err := tf.StateFromFile("subdir/terraform.tfstate")
+	if err != nil {
+		t.Fatalf("failed to read state file: %s", err)
+	}
+
+	gotOutput := state.RootModule().OutputValues["cwd"]
+	wantOutputValue := cty.StringVal(filepath.ToSlash(tf.Path())) // path.cwd returns the original path, because path.root is how we get the overridden path
+	if gotOutput == nil || !wantOutputValue.RawEquals(gotOutput.Value) {
+		t.Errorf("incorrect value for cwd output\ngot: %#v\nwant Value: %#v", gotOutput, wantOutputValue)
+	}
+
+	gotOutput = state.RootModule().OutputValues["root"]
+	wantOutputValue = cty.StringVal(filepath.ToSlash(tf.Path("subdir"))) // path.root is a relative path, but the text fixture uses abspath on it.
+	if gotOutput == nil || !wantOutputValue.RawEquals(gotOutput.Value) {
+		t.Errorf("incorrect value for root output\ngot: %#v\nwant Value: %#v", gotOutput, wantOutputValue)
+	}
+
+	if len(state.RootModule().Resources) != 0 {
+		t.Errorf("unexpected resources in state")
+	}
+
+	//// DESTROY
+	stdout, stderr, err = tf.Run("-chdir=subdir", "destroy", "-auto-approve")
+	if err != nil {
+		t.Fatalf("unexpected destroy error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !strings.Contains(stdout, "Resources: 0 destroyed") {
+		t.Errorf("incorrect destroy tally; want 0 destroyed:\n%s", stdout)
+	}
+}
diff --git a/v1.5.7/internal/command/e2etest/provider_dev_test.go b/v1.5.7/internal/command/e2etest/provider_dev_test.go
new file mode 100644
index 0000000..5246541
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/provider_dev_test.go
@@ -0,0 +1,98 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/e2e"
+)
+
+// TestProviderDevOverrides is a test for the special dev_overrides setting
+// in the provider_installation section of the CLI configuration file, which
+// is our current answer to smoothing provider development by allowing
+// developers to opt out of the version number and checksum verification
+// we normally do, so they can just overwrite the same local executable
+// in-place to iterate faster.
+func TestProviderDevOverrides(t *testing.T) {
+	if !canRunGoBuild {
+		// We're running in a separate-build-then-run context, so we can't
+		// currently execute this test which depends on being able to build
+		// new executable at runtime.
+		//
+		// (See the comment on canRunGoBuild's declaration for more information.)
+		t.Skip("can't run without building a new provider executable")
+	}
+	t.Parallel()
+
+	tf := e2e.NewBinary(t, terraformBin, "testdata/provider-dev-override")
+
+	// In order to do a decent end-to-end test for this case we will need a
+	// real enough provider plugin to try to run and make sure we are able
+	// to actually run it. For now we'll use the "test" provider for that,
+	// because it happens to be in this repository and therefore allows
+	// us to avoid drawing in anything external, but we might revisit this
+	// strategy in future if other needs cause us to evolve the test
+	// provider in a way that makes it less suitable for this particular test,
+	// such as if it stops being buildable into an independent executable.
+	providerExeDir := filepath.Join(tf.WorkDir(), "pkgdir")
+	providerExePrefix := filepath.Join(providerExeDir, "terraform-provider-test_")
+	providerExe := e2e.GoBuild("github.com/hashicorp/terraform/internal/provider-simple/main", providerExePrefix)
+	t.Logf("temporary provider executable is %s", providerExe)
+
+	err := ioutil.WriteFile(filepath.Join(tf.WorkDir(), "dev.tfrc"), []byte(fmt.Sprintf(`
+		provider_installation {
+			dev_overrides {
+				"example.com/test/test" = %q
+			}
+		}
+	`, providerExeDir)), os.ModePerm)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	tf.AddEnv("TF_CLI_CONFIG_FILE=dev.tfrc")
+
+	stdout, stderr, err := tf.Run("providers")
+	if err != nil {
+		t.Fatalf("unexpected error: %s\n%s", err, stderr)
+	}
+	if got, want := stdout, `provider[example.com/test/test]`; !strings.Contains(got, want) {
+		t.Errorf("configuration should depend on %s, but doesn't\n%s", want, got)
+	}
+
+	// NOTE: We're intentionally not running "terraform init" here, because
+	// dev overrides are always ready to use and don't need any special action
+	// to "install" them. This test is mimicking the a happy path of going
+	// directly from "go build" to validate/plan/apply without interacting
+	// with any registries, mirrors, lock files, etc. To verify "terraform
+	// init" does actually show a warning, that behavior is tested at the end.
+	stdout, stderr, err = tf.Run("validate")
+	if err != nil {
+		t.Fatalf("unexpected error: %s\n%s", err, stderr)
+	}
+
+	if got, want := stdout, `The configuration is valid, but`; !strings.Contains(got, want) {
+		t.Errorf("stdout doesn't include the success message\nwant: %s\n%s", want, got)
+	}
+	if got, want := stdout, `Provider development overrides are in effect`; !strings.Contains(got, want) {
+		t.Errorf("stdout doesn't include the warning about development overrides\nwant: %s\n%s", want, got)
+	}
+
+	stdout, stderr, err = tf.Run("init")
+	if err == nil {
+		t.Fatal("expected error: Failed to query available provider packages")
+	}
+	if got, want := stdout, `Provider development overrides are in effect`; !strings.Contains(got, want) {
+		t.Errorf("stdout doesn't include the warning about development overrides\nwant: %s\n%s", want, got)
+	}
+	if got, want := stderr, `Failed to query available provider packages`; !strings.Contains(got, want) {
+		t.Errorf("stderr doesn't include the error about listing unavailable development provider\nwant: %s\n%s", want, got)
+	}
+}
diff --git a/v1.5.7/internal/command/e2etest/provider_plugin_test.go b/v1.5.7/internal/command/e2etest/provider_plugin_test.go
new file mode 100644
index 0000000..7d93741
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/provider_plugin_test.go
@@ -0,0 +1,90 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/e2e"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+// TestProviderProtocols verifies that Terraform can execute provider plugins
+// with both supported protocol versions.
+func TestProviderProtocols(t *testing.T) {
+	if !canRunGoBuild {
+		// We're running in a separate-build-then-run context, so we can't
+		// currently execute this test which depends on being able to build
+		// new executable at runtime.
+		//
+		// (See the comment on canRunGoBuild's declaration for more information.)
+		t.Skip("can't run without building a new provider executable")
+	}
+	t.Parallel()
+
+	tf := e2e.NewBinary(t, terraformBin, "testdata/provider-plugin")
+
+	// In order to do a decent end-to-end test for this case we will need a real
+	// enough provider plugin to try to run and make sure we are able to
+	// actually run it. Here will build the simple and simple6 (built with
+	// protocol v6) providers.
+	simple6Provider := filepath.Join(tf.WorkDir(), "terraform-provider-simple6")
+	simple6ProviderExe := e2e.GoBuild("github.com/hashicorp/terraform/internal/provider-simple-v6/main", simple6Provider)
+
+	simpleProvider := filepath.Join(tf.WorkDir(), "terraform-provider-simple")
+	simpleProviderExe := e2e.GoBuild("github.com/hashicorp/terraform/internal/provider-simple/main", simpleProvider)
+
+	// Move the provider binaries into a directory that we will point terraform
+	// to using the -plugin-dir cli flag.
+	platform := getproviders.CurrentPlatform.String()
+	hashiDir := "cache/registry.terraform.io/hashicorp/"
+	if err := os.MkdirAll(tf.Path(hashiDir, "simple6/0.0.1/", platform), os.ModePerm); err != nil {
+		t.Fatal(err)
+	}
+	if err := os.Rename(simple6ProviderExe, tf.Path(hashiDir, "simple6/0.0.1/", platform, "terraform-provider-simple6")); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := os.MkdirAll(tf.Path(hashiDir, "simple/0.0.1/", platform), os.ModePerm); err != nil {
+		t.Fatal(err)
+	}
+	if err := os.Rename(simpleProviderExe, tf.Path(hashiDir, "simple/0.0.1/", platform, "terraform-provider-simple")); err != nil {
+		t.Fatal(err)
+	}
+
+	//// INIT
+	_, stderr, err := tf.Run("init", "-plugin-dir=cache")
+	if err != nil {
+		t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	//// PLAN
+	_, stderr, err = tf.Run("plan", "-out=tfplan")
+	if err != nil {
+		t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	//// APPLY
+	stdout, stderr, err := tf.Run("apply", "tfplan")
+	if err != nil {
+		t.Fatalf("unexpected apply error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !strings.Contains(stdout, "Apply complete! Resources: 2 added, 0 changed, 0 destroyed.") {
+		t.Fatalf("wrong output:\nstdout:%s\nstderr%s", stdout, stderr)
+	}
+
+	/// DESTROY
+	stdout, stderr, err = tf.Run("destroy", "-auto-approve")
+	if err != nil {
+		t.Fatalf("unexpected apply error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !strings.Contains(stdout, "Resources: 2 destroyed") {
+		t.Fatalf("wrong destroy output\nstdout:%s\nstderr:%s", stdout, stderr)
+	}
+}
diff --git a/v1.5.7/internal/command/e2etest/providers_mirror_test.go b/v1.5.7/internal/command/e2etest/providers_mirror_test.go
new file mode 100644
index 0000000..8e1ff99
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/providers_mirror_test.go
@@ -0,0 +1,84 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"os"
+	"path/filepath"
+	"sort"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/e2e"
+)
+
+// The tests in this file are for the "terraform providers mirror" command,
+// which is tested in an e2etest mode rather than a unit test mode because it
+// interacts directly with Terraform Registry and the full details of that are
+// tricky to mock. Such a mock is _possible_, but we're using e2etest as a
+// compromise for now to keep these tests relatively simple.
+
+func TestTerraformProvidersMirror(t *testing.T) {
+	testTerraformProvidersMirror(t, "terraform-providers-mirror")
+}
+
+func TestTerraformProvidersMirrorWithLockFile(t *testing.T) {
+	testTerraformProvidersMirror(t, "terraform-providers-mirror-with-lock-file")
+}
+
+func testTerraformProvidersMirror(t *testing.T, fixture string) {
+	// This test reaches out to releases.hashicorp.com to download the
+	// template and null providers, so it can only run if network access is
+	// allowed.
+	skipIfCannotAccessNetwork(t)
+
+	outputDir := t.TempDir()
+	t.Logf("creating mirror directory in %s", outputDir)
+
+	fixturePath := filepath.Join("testdata", fixture)
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	stdout, stderr, err := tf.Run("providers", "mirror", "-platform=linux_amd64", "-platform=windows_386", outputDir)
+	if err != nil {
+		t.Fatalf("unexpected error: %s\nstdout:\n%s\nstderr:\n%s", err, stdout, stderr)
+	}
+
+	// The test fixture includes exact version constraints for the two
+	// providers it depends on so that the following should remain stable.
+	// In the (unlikely) event that these particular versions of these
+	// providers are removed from the registry, this test will start to fail.
+	want := []string{
+		"registry.terraform.io/hashicorp/null/2.1.0.json",
+		"registry.terraform.io/hashicorp/null/index.json",
+		"registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip",
+		"registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_windows_386.zip",
+		"registry.terraform.io/hashicorp/template/2.1.1.json",
+		"registry.terraform.io/hashicorp/template/index.json",
+		"registry.terraform.io/hashicorp/template/terraform-provider-template_2.1.1_linux_amd64.zip",
+		"registry.terraform.io/hashicorp/template/terraform-provider-template_2.1.1_windows_386.zip",
+	}
+	var got []string
+	walkErr := filepath.Walk(outputDir, func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+		if info.IsDir() {
+			return nil // we only care about leaf files for this test
+		}
+		relPath, err := filepath.Rel(outputDir, path)
+		if err != nil {
+			return err
+		}
+		got = append(got, filepath.ToSlash(relPath))
+		return nil
+	})
+	if walkErr != nil {
+		t.Fatal(walkErr)
+	}
+	sort.Strings(got)
+
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Errorf("unexpected files in result\n%s", diff)
+	}
+}
diff --git a/v1.5.7/internal/command/e2etest/providers_tamper_test.go b/v1.5.7/internal/command/e2etest/providers_tamper_test.go
new file mode 100644
index 0000000..bea5f8f
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/providers_tamper_test.go
@@ -0,0 +1,273 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/e2e"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+// TestProviderTampering tests various ways that the provider plugins in the
+// local cache directory might be modified after an initial "terraform init",
+// which other Terraform commands which use those plugins should catch and
+// report early.
+func TestProviderTampering(t *testing.T) {
+	// General setup: we'll do a one-off init of a test directory as our
+	// starting point, and then we'll clone that result for each test so
+	// that we can save the cost of a repeated re-init with the same
+	// provider.
+	t.Parallel()
+
+	// This test reaches out to releases.hashicorp.com to download the
+	// null provider, so it can only run if network access is allowed.
+	skipIfCannotAccessNetwork(t)
+
+	fixturePath := filepath.Join("testdata", "provider-tampering-base")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	stdout, stderr, err := tf.Run("init")
+	if err != nil {
+		t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
+	}
+	if !strings.Contains(stdout, "Installing hashicorp/null v") {
+		t.Errorf("null provider download message is missing from init output:\n%s", stdout)
+		t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)")
+	}
+
+	seedDir := tf.WorkDir()
+	const providerVersion = "3.1.0" // must match the version in the fixture config
+	pluginDir := filepath.Join(".terraform", "providers", "registry.terraform.io", "hashicorp", "null", providerVersion, getproviders.CurrentPlatform.String())
+	pluginExe := filepath.Join(pluginDir, "terraform-provider-null_v"+providerVersion+"_x5")
+	if getproviders.CurrentPlatform.OS == "windows" {
+		pluginExe += ".exe" // ugh
+	}
+
+	// filepath.Join here to make sure we get the right path separator
+	// for whatever OS we're running these tests on.
+	providerCacheDir := filepath.Join(".terraform", "providers")
+
+	t.Run("cache dir totally gone", func(t *testing.T) {
+		tf := e2e.NewBinary(t, terraformBin, seedDir)
+		workDir := tf.WorkDir()
+
+		err := os.RemoveAll(filepath.Join(workDir, ".terraform"))
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		stdout, stderr, err := tf.Run("plan")
+		if err == nil {
+			t.Fatalf("unexpected plan success\nstdout:\n%s", stdout)
+		}
+		if want := `registry.terraform.io/hashicorp/null: there is no package for registry.terraform.io/hashicorp/null 3.1.0 cached in ` + providerCacheDir; !strings.Contains(stderr, want) {
+			t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
+		}
+		if want := `terraform init`; !strings.Contains(stderr, want) {
+			t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
+		}
+
+		// Running init as suggested resolves the problem
+		_, stderr, err = tf.Run("init")
+		if err != nil {
+			t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
+		}
+		_, stderr, err = tf.Run("plan")
+		if err != nil {
+			t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
+		}
+	})
+	t.Run("cache dir totally gone, explicit backend", func(t *testing.T) {
+		tf := e2e.NewBinary(t, terraformBin, seedDir)
+		workDir := tf.WorkDir()
+
+		err := ioutil.WriteFile(filepath.Join(workDir, "backend.tf"), []byte(localBackendConfig), 0600)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		err = os.RemoveAll(filepath.Join(workDir, ".terraform"))
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		stdout, stderr, err := tf.Run("plan")
+		if err == nil {
+			t.Fatalf("unexpected plan success\nstdout:\n%s", stdout)
+		}
+		if want := `Initial configuration of the requested backend "local"`; !strings.Contains(stderr, want) {
+			t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
+		}
+		if want := `terraform init`; !strings.Contains(stderr, want) {
+			t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
+		}
+
+		// Running init as suggested resolves the problem
+		_, stderr, err = tf.Run("init")
+		if err != nil {
+			t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
+		}
+		_, stderr, err = tf.Run("plan")
+		if err != nil {
+			t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
+		}
+	})
+	t.Run("null plugin package modified before plan", func(t *testing.T) {
+		tf := e2e.NewBinary(t, terraformBin, seedDir)
+		workDir := tf.WorkDir()
+
+		err := ioutil.WriteFile(filepath.Join(workDir, pluginExe), []byte("tamper"), 0600)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		stdout, stderr, err := tf.Run("plan")
+		if err == nil {
+			t.Fatalf("unexpected plan success\nstdout:\n%s", stdout)
+		}
+		if want := `registry.terraform.io/hashicorp/null: the cached package for registry.terraform.io/hashicorp/null 3.1.0 (in ` + providerCacheDir + `) does not match any of the checksums recorded in the dependency lock file`; !strings.Contains(stderr, want) {
+			t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
+		}
+		if want := `terraform init`; !strings.Contains(stderr, want) {
+			t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
+		}
+	})
+	t.Run("version constraint changed in config before plan", func(t *testing.T) {
+		tf := e2e.NewBinary(t, terraformBin, seedDir)
+		workDir := tf.WorkDir()
+
+		err := ioutil.WriteFile(filepath.Join(workDir, "provider-tampering-base.tf"), []byte(`
+			terraform {
+				required_providers {
+					null = {
+						source  = "hashicorp/null"
+						version = "1.0.0"
+					}
+				}
+			}
+		`), 0600)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		stdout, stderr, err := tf.Run("plan")
+		if err == nil {
+			t.Fatalf("unexpected plan success\nstdout:\n%s", stdout)
+		}
+		if want := `provider registry.terraform.io/hashicorp/null: locked version selection 3.1.0 doesn't match the updated version constraints "1.0.0"`; !strings.Contains(stderr, want) {
+			t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
+		}
+		if want := `terraform init -upgrade`; !strings.Contains(stderr, want) {
+			t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
+		}
+	})
+	t.Run("lock file modified before plan", func(t *testing.T) {
+		tf := e2e.NewBinary(t, terraformBin, seedDir)
+		workDir := tf.WorkDir()
+
+		// NOTE: We're just emptying out the lock file here because that's
+		// good enough for what we're trying to assert. The leaf codepath
+		// that generates this family of errors has some different variations
+		// of this error message for otehr sorts of inconsistency, but those
+		// are tested more thoroughly over in the "configs" package, which is
+		// ultimately responsible for that logic.
+		err := ioutil.WriteFile(filepath.Join(workDir, ".terraform.lock.hcl"), []byte(``), 0600)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		stdout, stderr, err := tf.Run("plan")
+		if err == nil {
+			t.Fatalf("unexpected plan success\nstdout:\n%s", stdout)
+		}
+		if want := `provider registry.terraform.io/hashicorp/null: required by this configuration but no version is selected`; !strings.Contains(stderr, want) {
+			t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
+		}
+		if want := `terraform init`; !strings.Contains(stderr, want) {
+			t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
+		}
+	})
+	t.Run("lock file modified after plan", func(t *testing.T) {
+		tf := e2e.NewBinary(t, terraformBin, seedDir)
+		workDir := tf.WorkDir()
+
+		_, stderr, err := tf.Run("plan", "-out", "tfplan")
+		if err != nil {
+			t.Fatalf("unexpected plan failure\nstderr:\n%s", stderr)
+		}
+
+		err = os.Remove(filepath.Join(workDir, ".terraform.lock.hcl"))
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		stdout, stderr, err := tf.Run("apply", "tfplan")
+		if err == nil {
+			t.Fatalf("unexpected apply success\nstdout:\n%s", stdout)
+		}
+		if want := `provider registry.terraform.io/hashicorp/null: required by this configuration but no version is selected`; !strings.Contains(stderr, want) {
+			t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
+		}
+		if want := `Create a new plan from the updated configuration.`; !strings.Contains(stderr, want) {
+			t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
+		}
+	})
+	t.Run("plugin cache dir entirely removed after plan", func(t *testing.T) {
+		tf := e2e.NewBinary(t, terraformBin, seedDir)
+		workDir := tf.WorkDir()
+
+		_, stderr, err := tf.Run("plan", "-out", "tfplan")
+		if err != nil {
+			t.Fatalf("unexpected plan failure\nstderr:\n%s", stderr)
+		}
+
+		err = os.RemoveAll(filepath.Join(workDir, ".terraform"))
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		stdout, stderr, err := tf.Run("apply", "tfplan")
+		if err == nil {
+			t.Fatalf("unexpected apply success\nstdout:\n%s", stdout)
+		}
+		if want := `registry.terraform.io/hashicorp/null: there is no package for registry.terraform.io/hashicorp/null 3.1.0 cached in ` + providerCacheDir; !strings.Contains(stderr, want) {
+			t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
+		}
+	})
+	t.Run("null plugin package modified after plan", func(t *testing.T) {
+		tf := e2e.NewBinary(t, terraformBin, seedDir)
+		workDir := tf.WorkDir()
+
+		_, stderr, err := tf.Run("plan", "-out", "tfplan")
+		if err != nil {
+			t.Fatalf("unexpected plan failure\nstderr:\n%s", stderr)
+		}
+
+		err = ioutil.WriteFile(filepath.Join(workDir, pluginExe), []byte("tamper"), 0600)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		stdout, stderr, err := tf.Run("apply", "tfplan")
+		if err == nil {
+			t.Fatalf("unexpected apply success\nstdout:\n%s", stdout)
+		}
+		if want := `registry.terraform.io/hashicorp/null: the cached package for registry.terraform.io/hashicorp/null 3.1.0 (in ` + providerCacheDir + `) does not match any of the checksums recorded in the dependency lock file`; !strings.Contains(stderr, want) {
+			t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
+		}
+	})
+}
+
+const localBackendConfig = `
+terraform {
+  backend "local" {
+    path = "terraform.tfstate"
+  }
+}
+`
diff --git a/v1.5.7/internal/command/e2etest/provisioner_plugin_test.go b/v1.5.7/internal/command/e2etest/provisioner_plugin_test.go
new file mode 100644
index 0000000..352d12a
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/provisioner_plugin_test.go
@@ -0,0 +1,75 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/e2e"
+)
+
+// TestProvisionerPlugin is a test that terraform can execute a 3rd party
+// provisioner plugin.
+func TestProvisionerPlugin(t *testing.T) {
+	if !canRunGoBuild {
+		// We're running in a separate-build-then-run context, so we can't
+		// currently execute this test which depends on being able to build
+		// new executable at runtime.
+		//
+		// (See the comment on canRunGoBuild's declaration for more information.)
+		t.Skip("can't run without building a new provisioner executable")
+	}
+	t.Parallel()
+
+	// This test reaches out to releases.hashicorp.com to download the
+	// template and null providers, so it can only run if network access is
+	// allowed.
+	skipIfCannotAccessNetwork(t)
+
+	tf := e2e.NewBinary(t, terraformBin, "testdata/provisioner-plugin")
+
+	// In order to do a decent end-to-end test for this case we will need a
+	// real enough provisioner plugin to try to run and make sure we are able
+	// to actually run it. Here will build the local-exec provisioner into a
+	// binary called test-provisioner
+	provisionerExePrefix := filepath.Join(tf.WorkDir(), "terraform-provisioner-test_")
+	provisionerExe := e2e.GoBuild("github.com/hashicorp/terraform/internal/provisioner-local-exec/main", provisionerExePrefix)
+
+	// provisioners must use the old binary name format, so rename this binary
+	newExe := filepath.Join(tf.WorkDir(), "terraform-provisioner-test")
+	if _, err := os.Stat(newExe); !os.IsNotExist(err) {
+		t.Fatalf("%q already exists", newExe)
+	}
+	if err := os.Rename(provisionerExe, newExe); err != nil {
+		t.Fatalf("error renaming provisioner binary: %v", err)
+	}
+	provisionerExe = newExe
+
+	t.Logf("temporary provisioner executable is %s", provisionerExe)
+
+	//// INIT
+	_, stderr, err := tf.Run("init")
+	if err != nil {
+		t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	//// PLAN
+	_, stderr, err = tf.Run("plan", "-out=tfplan")
+	if err != nil {
+		t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	//// APPLY
+	stdout, stderr, err := tf.Run("apply", "tfplan")
+	if err != nil {
+		t.Fatalf("unexpected apply error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !strings.Contains(stdout, "HelloProvisioner") {
+		t.Fatalf("missing provisioner output:\n%s", stdout)
+	}
+}
diff --git a/v1.5.7/internal/command/e2etest/provisioner_test.go b/v1.5.7/internal/command/e2etest/provisioner_test.go
new file mode 100644
index 0000000..e5f716f
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/provisioner_test.go
@@ -0,0 +1,46 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/e2e"
+)
+
+// TestProviderDevOverrides is a test that terraform can execute a 3rd party
+// provisioner plugin.
+func TestProvisioner(t *testing.T) {
+	t.Parallel()
+
+	// This test reaches out to releases.hashicorp.com to download the
+	// template and null providers, so it can only run if network access is
+	// allowed.
+	skipIfCannotAccessNetwork(t)
+
+	tf := e2e.NewBinary(t, terraformBin, "testdata/provisioner")
+
+	//// INIT
+	_, stderr, err := tf.Run("init")
+	if err != nil {
+		t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	//// PLAN
+	_, stderr, err = tf.Run("plan", "-out=tfplan")
+	if err != nil {
+		t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	//// APPLY
+	stdout, stderr, err := tf.Run("apply", "tfplan")
+	if err != nil {
+		t.Fatalf("unexpected apply error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !strings.Contains(stdout, "HelloProvisioner") {
+		t.Fatalf("missing provisioner output:\n%s", stdout)
+	}
+}
diff --git a/v1.5.7/internal/command/e2etest/remote_state_test.go b/v1.5.7/internal/command/e2etest/remote_state_test.go
new file mode 100644
index 0000000..cfa9b72
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/remote_state_test.go
@@ -0,0 +1,31 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"path/filepath"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/e2e"
+)
+
+func TestTerraformProviderRead(t *testing.T) {
+	// Ensure the terraform provider can correctly read a remote state
+
+	t.Parallel()
+	fixturePath := filepath.Join("testdata", "terraform-provider")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	//// INIT
+	_, stderr, err := tf.Run("init")
+	if err != nil {
+		t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	//// PLAN
+	_, stderr, err = tf.Run("plan")
+	if err != nil {
+		t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
+	}
+}
diff --git a/v1.5.7/internal/command/e2etest/strip_ansi.go b/v1.5.7/internal/command/e2etest/strip_ansi.go
new file mode 100644
index 0000000..1d92fe6
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/strip_ansi.go
@@ -0,0 +1,16 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"regexp"
+)
+
+const ansi = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"
+
+var ansiRe = regexp.MustCompile(ansi)
+
+func stripAnsi(str string) string {
+	return ansiRe.ReplaceAllString(str, "")
+}
diff --git a/v1.5.7/internal/command/e2etest/terraform_test.go b/v1.5.7/internal/command/e2etest/terraform_test.go
new file mode 100644
index 0000000..0dce47c
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/terraform_test.go
@@ -0,0 +1,58 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/e2e"
+)
+
+func TestTerraformProviderData(t *testing.T) {
+
+	fixturePath := filepath.Join("testdata", "terraform-managed-data")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	_, stderr, err := tf.Run("init", "-input=false")
+	if err != nil {
+		t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	stdout, stderr, err := tf.Run("plan", "-out=tfplan", "-input=false")
+	if err != nil {
+		t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !strings.Contains(stdout, "4 to add, 0 to change, 0 to destroy") {
+		t.Errorf("incorrect plan tally; want 4 to add:\n%s", stdout)
+	}
+
+	stdout, stderr, err = tf.Run("apply", "-input=false", "tfplan")
+	if err != nil {
+		t.Fatalf("unexpected apply error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !strings.Contains(stdout, "Resources: 4 added, 0 changed, 0 destroyed") {
+		t.Errorf("incorrect apply tally; want 4 added:\n%s", stdout)
+	}
+
+	state, err := tf.LocalState()
+	if err != nil {
+		t.Fatalf("failed to read state file: %s", err)
+	}
+
+	// we'll check the final output to validate the resources
+	d := state.Module(addrs.RootModuleInstance).OutputValues["d"].Value
+	input := d.GetAttr("input")
+	output := d.GetAttr("output")
+	if input.IsNull() {
+		t.Fatal("missing input from resource d")
+	}
+	if !input.RawEquals(output) {
+		t.Fatalf("input %#v does not equal output %#v\n", input, output)
+	}
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/chdir-option/subdir/main.tf b/v1.5.7/internal/command/e2etest/testdata/chdir-option/subdir/main.tf
new file mode 100644
index 0000000..eddb200
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/chdir-option/subdir/main.tf
@@ -0,0 +1,7 @@
+output "cwd" {
+  value = path.cwd
+}
+
+output "root" {
+  value = abspath(path.root)
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc b/v1.5.7/internal/command/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc
new file mode 100644
index 0000000..4b4dbef
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc
@@ -0,0 +1,8 @@
+provider_installation {
+  filesystem_mirror {
+    path = "./fs-mirror"
+  }
+  direct {
+    exclude = ["example.com/*/*"]
+  }
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc.json b/v1.5.7/internal/command/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc.json
new file mode 100644
index 0000000..6e5e946
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc.json
@@ -0,0 +1,9 @@
+{
+  "provider_installation": {
+    "filesystem_mirror": [
+      {
+        "path": "./fs-mirror"
+      }
+    ]
+  }
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/custom-provider-install-method/fs-mirror/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0 b/v1.5.7/internal/command/e2etest/testdata/custom-provider-install-method/fs-mirror/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0
new file mode 100644
index 0000000..3299bec
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/custom-provider-install-method/fs-mirror/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0
@@ -0,0 +1,2 @@
+This is not a real plugin executable. It's just here to be discovered by the
+provider installation process.
diff --git a/v1.5.7/internal/command/e2etest/testdata/custom-provider-install-method/main.tf b/v1.5.7/internal/command/e2etest/testdata/custom-provider-install-method/main.tf
new file mode 100644
index 0000000..a521cf0
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/custom-provider-install-method/main.tf
@@ -0,0 +1,21 @@
+# The purpose of this test is to refer to a provider whose address contains
+# a hostname that is only used for namespacing purposes and doesn't actually
+# have a provider registry deployed at it.
+#
+# A user can install such a provider in one of the implied local filesystem
+# directories and Terraform should accept that as the selection for that
+# provider without producing any errors about the fact that example.com
+# does not have a provider registry.
+#
+# For this test in particular we're using the "vendor" directory that is
+# the documented way to include provider plugins directly inside a
+# configuration uploaded to Terraform Cloud, but this functionality applies
+# to all of the implicit local filesystem search directories.
+
+terraform {
+  required_providers {
+    happycloud = {
+      source = "example.com/awesomecorp/happycloud"
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/empty/.exists b/v1.5.7/internal/command/e2etest/testdata/empty/.exists
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/empty/.exists
diff --git a/v1.5.7/internal/command/e2etest/testdata/full-workflow-null/main.tf b/v1.5.7/internal/command/e2etest/testdata/full-workflow-null/main.tf
new file mode 100644
index 0000000..1c3fc36
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/full-workflow-null/main.tf
@@ -0,0 +1,22 @@
+
+variable "name" {
+  default = "world"
+}
+
+data "template_file" "test" {
+  template = "Hello, $${name}"
+
+  vars = {
+    name = "${var.name}"
+  }
+}
+
+resource "null_resource" "test" {
+  triggers = {
+    greeting = "${data.template_file.test.rendered}"
+  }
+}
+
+output "greeting" {
+  value = "${null_resource.test.triggers["greeting"]}"
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/local-only-provider/main.tf b/v1.5.7/internal/command/e2etest/testdata/local-only-provider/main.tf
new file mode 100644
index 0000000..a521cf0
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/local-only-provider/main.tf
@@ -0,0 +1,21 @@
+# The purpose of this test is to refer to a provider whose address contains
+# a hostname that is only used for namespacing purposes and doesn't actually
+# have a provider registry deployed at it.
+#
+# A user can install such a provider in one of the implied local filesystem
+# directories and Terraform should accept that as the selection for that
+# provider without producing any errors about the fact that example.com
+# does not have a provider registry.
+#
+# For this test in particular we're using the "vendor" directory that is
+# the documented way to include provider plugins directly inside a
+# configuration uploaded to Terraform Cloud, but this functionality applies
+# to all of the implicit local filesystem search directories.
+
+terraform {
+  required_providers {
+    happycloud = {
+      source = "example.com/awesomecorp/happycloud"
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/local-only-provider/terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0 b/v1.5.7/internal/command/e2etest/testdata/local-only-provider/terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0
new file mode 100644
index 0000000..3299bec
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/local-only-provider/terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0
@@ -0,0 +1,2 @@
+This is not a real plugin executable. It's just here to be discovered by the
+provider installation process.
diff --git a/v1.5.7/internal/command/e2etest/testdata/module-archive/main.tf b/v1.5.7/internal/command/e2etest/testdata/module-archive/main.tf
new file mode 100644
index 0000000..8101c80
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/module-archive/main.tf
@@ -0,0 +1,5 @@
+// this should be able to unpack the tarball and change the module directory to
+// the archive directory regardless of its name.
+module "bucket" {
+  source = "https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/archive/v3.3.0.tar.gz//*?archive=tar.gz"
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/plugin-cache/.terraform.lock.hcl b/v1.5.7/internal/command/e2etest/testdata/plugin-cache/.terraform.lock.hcl
new file mode 100644
index 0000000..a96e3e4
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/plugin-cache/.terraform.lock.hcl
@@ -0,0 +1,14 @@
+# The global cache is only an eligible installation source if there's already
+# a lock entry for the given provider and it contains at least one checksum
+# that matches the cache entry.
+#
+# This lock file therefore matches the "not a real provider" fake executable
+# under the "cache" directory, rather than the real provider from upstream,
+# so that Terraform CLI will consider the cache entry as valid.
+
+provider "registry.terraform.io/hashicorp/template" {
+  version = "2.1.0"
+  hashes = [
+    "h1:e7YvVlRZlaZJ8ED5KnH0dAg0kPL0nAU7eEoCAZ/sOos=",
+  ]
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/plugin-cache/cache/registry.terraform.io/hashicorp/template/2.1.0/os_arch/terraform-provider-template_v2.1.0_x4 b/v1.5.7/internal/command/e2etest/testdata/plugin-cache/cache/registry.terraform.io/hashicorp/template/2.1.0/os_arch/terraform-provider-template_v2.1.0_x4
new file mode 100644
index 0000000..c92a59a
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/plugin-cache/cache/registry.terraform.io/hashicorp/template/2.1.0/os_arch/terraform-provider-template_v2.1.0_x4
@@ -0,0 +1 @@
+this is not a real plugin
diff --git a/v1.5.7/internal/command/e2etest/testdata/plugin-cache/main.tf b/v1.5.7/internal/command/e2etest/testdata/plugin-cache/main.tf
new file mode 100644
index 0000000..f52d482
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/plugin-cache/main.tf
@@ -0,0 +1,7 @@
+provider "template" {
+  version = "2.1.0"
+}
+
+provider "null" {
+  version = "2.1.0"
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/provider-dev-override/pkgdir/.exists b/v1.5.7/internal/command/e2etest/testdata/provider-dev-override/pkgdir/.exists
new file mode 100644
index 0000000..052e1ad
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/provider-dev-override/pkgdir/.exists
@@ -0,0 +1 @@
+This is where the test will place the temporary build of the test provider.
diff --git a/v1.5.7/internal/command/e2etest/testdata/provider-dev-override/provider-dev-override.tf b/v1.5.7/internal/command/e2etest/testdata/provider-dev-override/provider-dev-override.tf
new file mode 100644
index 0000000..9c629f7
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/provider-dev-override/provider-dev-override.tf
@@ -0,0 +1,11 @@
+terraform {
+  required_providers {
+    simple = {
+      source  = "example.com/test/test"
+      version = "2.0.0"
+    }
+  }
+}
+
+data "simple_resource" "test" {
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/provider-not-found-non-default/main.tf b/v1.5.7/internal/command/e2etest/testdata/provider-not-found-non-default/main.tf
new file mode 100644
index 0000000..fe51127
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/provider-not-found-non-default/main.tf
@@ -0,0 +1,7 @@
+terraform {
+  required_providers {
+    nonexist = {
+      source = "teamterraform/nonexist"
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/provider-not-found/main.tf b/v1.5.7/internal/command/e2etest/testdata/provider-not-found/main.tf
new file mode 100644
index 0000000..3305c61
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/provider-not-found/main.tf
@@ -0,0 +1,7 @@
+terraform {
+  required_providers {
+    nonexist = {
+      source = "registry.terraform.io/hashicorp/nonexist"
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/provider-plugin/main.tf b/v1.5.7/internal/command/e2etest/testdata/provider-plugin/main.tf
new file mode 100644
index 0000000..ea4de02
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/provider-plugin/main.tf
@@ -0,0 +1,20 @@
+// the provider-plugin tests uses the -plugin-cache flag so terraform pulls the
+// test binaries instead of reaching out to the registry.
+terraform {
+  required_providers {
+    simple5 = {
+      source = "registry.terraform.io/hashicorp/simple"
+    }
+    simple6 = {
+      source = "registry.terraform.io/hashicorp/simple6"
+    }
+  }
+}
+
+resource "simple_resource" "test-proto5" {
+  provider = simple5
+}
+
+resource "simple_resource" "test-proto6" {
+  provider = simple6
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/provider-tampering-base/provider-tampering-base.tf b/v1.5.7/internal/command/e2etest/testdata/provider-tampering-base/provider-tampering-base.tf
new file mode 100644
index 0000000..87bd9ac
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/provider-tampering-base/provider-tampering-base.tf
@@ -0,0 +1,12 @@
+terraform {
+  required_providers {
+    null = {
+      # Our version is intentionally fixed so that we have a fixed
+      # test case here, though we might have to update this in future
+      # if e.g. Terraform stops supporting plugin protocol 5, or if
+      # the null provider is yanked from the registry for some reason.
+      source  = "hashicorp/null"
+      version = "3.1.0"
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/provider-warnings/main.tf b/v1.5.7/internal/command/e2etest/testdata/provider-warnings/main.tf
new file mode 100644
index 0000000..4300f04
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/provider-warnings/main.tf
@@ -0,0 +1,12 @@
+terraform {
+    required_providers {
+        terraform = {
+            // hashicorp/terraform is published in the registry, but it is
+            // archived (since it is internal) and returns a warning:
+            //
+            // "This provider is archived and no longer needed. The terraform_remote_state
+            // data source is built into the latest Terraform release."
+            source = "hashicorp/terraform"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/provisioner-plugin/main.tf b/v1.5.7/internal/command/e2etest/testdata/provisioner-plugin/main.tf
new file mode 100644
index 0000000..8e6268b
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/provisioner-plugin/main.tf
@@ -0,0 +1,5 @@
+resource "null_resource" "a" {
+  provisioner "test" {
+    command = "echo HelloProvisioner"
+  }
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/provisioner/main.tf b/v1.5.7/internal/command/e2etest/testdata/provisioner/main.tf
new file mode 100644
index 0000000..c37ad38
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/provisioner/main.tf
@@ -0,0 +1,5 @@
+resource "null_resource" "a" {
+  provisioner "local-exec" {
+    command = "echo HelloProvisioner"
+  }
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/template-provider/main.tf b/v1.5.7/internal/command/e2etest/testdata/template-provider/main.tf
new file mode 100644
index 0000000..31af451
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/template-provider/main.tf
@@ -0,0 +1,7 @@
+provider "template" {
+
+}
+
+data "template_file" "test" {
+  template = "Hello World"
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/terraform-managed-data/main.tf b/v1.5.7/internal/command/e2etest/testdata/terraform-managed-data/main.tf
new file mode 100644
index 0000000..271888e
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/terraform-managed-data/main.tf
@@ -0,0 +1,18 @@
+resource "terraform_data" "a" {
+}
+
+resource "terraform_data" "b" {
+  input = terraform_data.a.id
+}
+
+resource "terraform_data" "c" {
+  triggers_replace = terraform_data.b
+}
+
+resource "terraform_data" "d" {
+  input = [ terraform_data.b, terraform_data.c ]
+}
+
+output "d" {
+  value = terraform_data.d
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/terraform-provider/main.tf b/v1.5.7/internal/command/e2etest/testdata/terraform-provider/main.tf
new file mode 100644
index 0000000..bd9887e
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/terraform-provider/main.tf
@@ -0,0 +1,10 @@
+provider "terraform" {
+
+}
+
+data "terraform_remote_state" "test" {
+  backend = "local"
+  config = {
+    path = "test.tfstate"
+  }
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/terraform-provider/test.tfstate b/v1.5.7/internal/command/e2etest/testdata/terraform-provider/test.tfstate
new file mode 100644
index 0000000..fb1012d
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/terraform-provider/test.tfstate
@@ -0,0 +1,13 @@
+{
+  "version": 4,
+  "terraform_version": "0.13.0",
+  "serial": 1,
+  "lineage": "8fab7b5a-511c-d586-988e-250f99c8feb4",
+  "outputs": {
+    "out": {
+      "value": "test",
+      "type": "string"
+    }
+  },
+  "resources": []
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/.terraform.lock.hcl b/v1.5.7/internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/.terraform.lock.hcl
new file mode 100644
index 0000000..64d78c2
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/.terraform.lock.hcl
@@ -0,0 +1,44 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/null" {
+  version     = "2.1.0"
+  constraints = "2.1.0"
+  hashes = [
+    "h1:J/XPKw4nOAsE0iHHqkR0oIBfchtt3pokNj4gFlHqVvk=",
+    "h1:uugNjv4FEabvXfifTzRCqSerdraltZR0UwXzH8QYPUQ=",
+    "zh:022eb9cefb72d25cb39aebf17787ae5a1a239544abae7ac11fdc2b5a464c06f8",
+    "zh:089aec7ba6b9843741fec84e0bc046d97d2e41a9fedbe5d77124e66227395c63",
+    "zh:09e9a6fe88e8d33e4656a4f3768275c0f959f4624886a3a96d250e1067afec8c",
+    "zh:0fa2d6a05874405eb8b2a7ececb6b7522be25642e31838d23620bf7b4f371c9d",
+    "zh:2a7ab2f42d86e8bd4db3cdf94287a6d91c61456b59a0ce2d0f5d6992a08b668b",
+    "zh:6526bfa4f547223d4a14d7bf9098a4f7177a5c886a7edc65056df1cb98f6aad9",
+    "zh:8e58a5a130d377e8fc0da8ad526f33738c320b19463679f7d68212c5c939bad4",
+    "zh:9dc5be5713fca7dbfa99e9673450aaa7216915bffbc043b30798e037a8f2c870",
+    "zh:ab7671e33198b718a1ae3272dcea0380f357926324f96c3be0c6ef9423ebece1",
+    "zh:b27db66404ea0704fb076ef26bb5b5c556a31b81a8b2302ec705a7e46d93d3e0",
+    "zh:bcc4a07ce1fb3bdee4ea360dd9549e099ecc2e9d80aab7f8daf54387a87a5f8e",
+    "zh:bf44f8693075f46ae833303fee17e0b0649c72e9347027670fa30e9fbce37fc4",
+  ]
+}
+
+provider "registry.terraform.io/hashicorp/template" {
+  version     = "2.1.1"
+  constraints = "2.1.1"
+  hashes = [
+    "h1:fBNBluCX4pWlYEw5ZyCTHB00E+3BDSe7GjRzF1ojcvU=",
+    "h1:x2/zuJFN/oOUpE1C1nSk4n86AA2zASOyy2BUdFYcpXw=",
+    "zh:05fddf3cacb607f623c2b221c3e9ab724079deca0b703b2738e9d55c10e31717",
+    "zh:1a250b29274f3e340ea775bf9bd57476e982bca1fb4b59343fb3126e75dfd85c",
+    "zh:284735b9bd0e416ec02c0844e7f4ebbd4b5744140a21606e33f16eb14640cbf1",
+    "zh:2e9d246094ac8a68951015d40f42145e795b31d7c84fee20fa9f997b3d428906",
+    "zh:65e8e73860662a0c0698c8a8d35c857302f1fe3f41947e7c048c49a541a9c7f1",
+    "zh:70dacd22d0c93b2000948c06ded67fa147d992a0353737438f24a61e3f956c41",
+    "zh:aa1a0321e79e08ffb52789ab0af3896c493d436de7396d154d09a0be7d5d50e1",
+    "zh:bea4c276c4df9d117f19c4266d060db9b48c865ac7a71d2e77a27866c19bfaf5",
+    "zh:de04cb0cb046dad184f5bb783659cf98d88c6798db038cbf5a2c3c08e853d444",
+    "zh:de3c45a4fa1f756aa4db3350c021d1c0f9b23640cff77e0ba4df4eeb8eae957f",
+    "zh:e3cf2db204f64ad4e288af00fabc6a8af13a6687aba60a7e1ce0ea215a9580b1",
+    "zh:f795833225207d2eee022b91d26bee18d5e518e70912dd7a1d2a0eff2cbe4f1d",
+  ]
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/terraform-providers-mirror.tf b/v1.5.7/internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/terraform-providers-mirror.tf
new file mode 100644
index 0000000..1598a27
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/terraform-providers-mirror.tf
@@ -0,0 +1,7 @@
+terraform {
+  required_providers {
+    template  = { source = "hashicorp/template" }
+    null      = { source = "hashicorp/null" }
+    terraform = { source = "terraform.io/builtin/terraform" }
+  }
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/terraform-providers-mirror/terraform-providers-mirror.tf b/v1.5.7/internal/command/e2etest/testdata/terraform-providers-mirror/terraform-providers-mirror.tf
new file mode 100644
index 0000000..4b31e03
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/terraform-providers-mirror/terraform-providers-mirror.tf
@@ -0,0 +1,7 @@
+terraform {
+  required_providers {
+    template  = { version = "2.1.1" }
+    null      = { source = "hashicorp/null", version = "2.1.0" }
+    terraform = { source = "terraform.io/builtin/terraform" }
+  }
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/test-provider/main.tf b/v1.5.7/internal/command/e2etest/testdata/test-provider/main.tf
new file mode 100644
index 0000000..a4de134
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/test-provider/main.tf
@@ -0,0 +1,10 @@
+terraform {
+  required_providers {
+    simple = {
+      source = "hashicorp/test"
+    }
+  }
+}
+
+resource "simple_resource" "test" {
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/vendored-provider/main.tf b/v1.5.7/internal/command/e2etest/testdata/vendored-provider/main.tf
new file mode 100644
index 0000000..3cb6215
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/vendored-provider/main.tf
@@ -0,0 +1,8 @@
+terraform {
+  required_providers {
+    null = {
+      source  = "hashicorp/null"
+      version = "1.0.0+local"
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/e2etest/testdata/vendored-provider/terraform.d/plugins/registry.terraform.io/hashicorp/null/1.0.0+local/os_arch/terraform-provider-null_v1.0.0 b/v1.5.7/internal/command/e2etest/testdata/vendored-provider/terraform.d/plugins/registry.terraform.io/hashicorp/null/1.0.0+local/os_arch/terraform-provider-null_v1.0.0
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/testdata/vendored-provider/terraform.d/plugins/registry.terraform.io/hashicorp/null/1.0.0+local/os_arch/terraform-provider-null_v1.0.0
diff --git a/v1.5.7/internal/command/e2etest/unmanaged_test.go b/v1.5.7/internal/command/e2etest/unmanaged_test.go
new file mode 100644
index 0000000..51d6349
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/unmanaged_test.go
@@ -0,0 +1,356 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"context"
+	"encoding/json"
+	"io/ioutil"
+	"path/filepath"
+	"strings"
+	"sync"
+	"testing"
+
+	"github.com/hashicorp/go-hclog"
+	"github.com/hashicorp/go-plugin"
+	"github.com/hashicorp/terraform/internal/e2e"
+	"github.com/hashicorp/terraform/internal/grpcwrap"
+	tfplugin5 "github.com/hashicorp/terraform/internal/plugin"
+	tfplugin "github.com/hashicorp/terraform/internal/plugin6"
+	simple5 "github.com/hashicorp/terraform/internal/provider-simple"
+	simple "github.com/hashicorp/terraform/internal/provider-simple-v6"
+	proto5 "github.com/hashicorp/terraform/internal/tfplugin5"
+	proto "github.com/hashicorp/terraform/internal/tfplugin6"
+)
+
+// The tests in this file are for the "unmanaged provider workflow", which
+// includes variants of the following sequence, with different details:
+// terraform init
+// terraform plan
+// terraform apply
+//
+// These tests are run against an in-process server, and checked to make sure
+// they're not trying to control the lifecycle of the binary. They are not
+// checked for correctness of the operations themselves.
+
+type reattachConfig struct {
+	Protocol        string
+	ProtocolVersion int
+	Pid             int
+	Test            bool
+	Addr            reattachConfigAddr
+}
+
+type reattachConfigAddr struct {
+	Network string
+	String  string
+}
+
+type providerServer struct {
+	sync.Mutex
+	proto.ProviderServer
+	planResourceChangeCalled  bool
+	applyResourceChangeCalled bool
+}
+
+func (p *providerServer) PlanResourceChange(ctx context.Context, req *proto.PlanResourceChange_Request) (*proto.PlanResourceChange_Response, error) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.planResourceChangeCalled = true
+	return p.ProviderServer.PlanResourceChange(ctx, req)
+}
+
+func (p *providerServer) ApplyResourceChange(ctx context.Context, req *proto.ApplyResourceChange_Request) (*proto.ApplyResourceChange_Response, error) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.applyResourceChangeCalled = true
+	return p.ProviderServer.ApplyResourceChange(ctx, req)
+}
+
+func (p *providerServer) PlanResourceChangeCalled() bool {
+	p.Lock()
+	defer p.Unlock()
+
+	return p.planResourceChangeCalled
+}
+func (p *providerServer) ResetPlanResourceChangeCalled() {
+	p.Lock()
+	defer p.Unlock()
+
+	p.planResourceChangeCalled = false
+}
+
+func (p *providerServer) ApplyResourceChangeCalled() bool {
+	p.Lock()
+	defer p.Unlock()
+
+	return p.applyResourceChangeCalled
+}
+func (p *providerServer) ResetApplyResourceChangeCalled() {
+	p.Lock()
+	defer p.Unlock()
+
+	p.applyResourceChangeCalled = false
+}
+
+type providerServer5 struct {
+	sync.Mutex
+	proto5.ProviderServer
+	planResourceChangeCalled  bool
+	applyResourceChangeCalled bool
+}
+
+func (p *providerServer5) PlanResourceChange(ctx context.Context, req *proto5.PlanResourceChange_Request) (*proto5.PlanResourceChange_Response, error) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.planResourceChangeCalled = true
+	return p.ProviderServer.PlanResourceChange(ctx, req)
+}
+
+func (p *providerServer5) ApplyResourceChange(ctx context.Context, req *proto5.ApplyResourceChange_Request) (*proto5.ApplyResourceChange_Response, error) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.applyResourceChangeCalled = true
+	return p.ProviderServer.ApplyResourceChange(ctx, req)
+}
+
+func (p *providerServer5) PlanResourceChangeCalled() bool {
+	p.Lock()
+	defer p.Unlock()
+
+	return p.planResourceChangeCalled
+}
+func (p *providerServer5) ResetPlanResourceChangeCalled() {
+	p.Lock()
+	defer p.Unlock()
+
+	p.planResourceChangeCalled = false
+}
+
+func (p *providerServer5) ApplyResourceChangeCalled() bool {
+	p.Lock()
+	defer p.Unlock()
+
+	return p.applyResourceChangeCalled
+}
+func (p *providerServer5) ResetApplyResourceChangeCalled() {
+	p.Lock()
+	defer p.Unlock()
+
+	p.applyResourceChangeCalled = false
+}
+
+func TestUnmanagedSeparatePlan(t *testing.T) {
+	t.Parallel()
+
+	fixturePath := filepath.Join("testdata", "test-provider")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	reattachCh := make(chan *plugin.ReattachConfig)
+	closeCh := make(chan struct{})
+	provider := &providerServer{
+		ProviderServer: grpcwrap.Provider6(simple.Provider()),
+	}
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	go plugin.Serve(&plugin.ServeConfig{
+		Logger: hclog.New(&hclog.LoggerOptions{
+			Name:   "plugintest",
+			Level:  hclog.Trace,
+			Output: ioutil.Discard,
+		}),
+		Test: &plugin.ServeTestConfig{
+			Context:          ctx,
+			ReattachConfigCh: reattachCh,
+			CloseCh:          closeCh,
+		},
+		GRPCServer: plugin.DefaultGRPCServer,
+		VersionedPlugins: map[int]plugin.PluginSet{
+			6: {
+				"provider": &tfplugin.GRPCProviderPlugin{
+					GRPCProvider: func() proto.ProviderServer {
+						return provider
+					},
+				},
+			},
+		},
+	})
+	config := <-reattachCh
+	if config == nil {
+		t.Fatalf("no reattach config received")
+	}
+	reattachStr, err := json.Marshal(map[string]reattachConfig{
+		"hashicorp/test": {
+			Protocol:        string(config.Protocol),
+			ProtocolVersion: 6,
+			Pid:             config.Pid,
+			Test:            true,
+			Addr: reattachConfigAddr{
+				Network: config.Addr.Network(),
+				String:  config.Addr.String(),
+			},
+		},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	tf.AddEnv("TF_REATTACH_PROVIDERS=" + string(reattachStr))
+
+	//// INIT
+	stdout, stderr, err := tf.Run("init")
+	if err != nil {
+		t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	// Make sure we didn't download the binary
+	if strings.Contains(stdout, "Installing hashicorp/test v") {
+		t.Errorf("test provider download message is present in init output:\n%s", stdout)
+	}
+	if tf.FileExists(filepath.Join(".terraform", "plugins", "registry.terraform.io", "hashicorp", "test")) {
+		t.Errorf("test provider binary found in .terraform dir")
+	}
+
+	//// PLAN
+	_, stderr, err = tf.Run("plan", "-out=tfplan")
+	if err != nil {
+		t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !provider.PlanResourceChangeCalled() {
+		t.Error("PlanResourceChange not called on un-managed provider")
+	}
+
+	//// APPLY
+	_, stderr, err = tf.Run("apply", "tfplan")
+	if err != nil {
+		t.Fatalf("unexpected apply error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !provider.ApplyResourceChangeCalled() {
+		t.Error("ApplyResourceChange not called on un-managed provider")
+	}
+	provider.ResetApplyResourceChangeCalled()
+
+	//// DESTROY
+	_, stderr, err = tf.Run("destroy", "-auto-approve")
+	if err != nil {
+		t.Fatalf("unexpected destroy error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !provider.ApplyResourceChangeCalled() {
+		t.Error("ApplyResourceChange (destroy) not called on in-process provider")
+	}
+	cancel()
+	<-closeCh
+}
+
+func TestUnmanagedSeparatePlan_proto5(t *testing.T) {
+	t.Parallel()
+
+	fixturePath := filepath.Join("testdata", "test-provider")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	reattachCh := make(chan *plugin.ReattachConfig)
+	closeCh := make(chan struct{})
+	provider := &providerServer5{
+		ProviderServer: grpcwrap.Provider(simple5.Provider()),
+	}
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	go plugin.Serve(&plugin.ServeConfig{
+		Logger: hclog.New(&hclog.LoggerOptions{
+			Name:   "plugintest",
+			Level:  hclog.Trace,
+			Output: ioutil.Discard,
+		}),
+		Test: &plugin.ServeTestConfig{
+			Context:          ctx,
+			ReattachConfigCh: reattachCh,
+			CloseCh:          closeCh,
+		},
+		GRPCServer: plugin.DefaultGRPCServer,
+		VersionedPlugins: map[int]plugin.PluginSet{
+			5: {
+				"provider": &tfplugin5.GRPCProviderPlugin{
+					GRPCProvider: func() proto5.ProviderServer {
+						return provider
+					},
+				},
+			},
+		},
+	})
+	config := <-reattachCh
+	if config == nil {
+		t.Fatalf("no reattach config received")
+	}
+	reattachStr, err := json.Marshal(map[string]reattachConfig{
+		"hashicorp/test": {
+			Protocol:        string(config.Protocol),
+			ProtocolVersion: 5,
+			Pid:             config.Pid,
+			Test:            true,
+			Addr: reattachConfigAddr{
+				Network: config.Addr.Network(),
+				String:  config.Addr.String(),
+			},
+		},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	tf.AddEnv("TF_REATTACH_PROVIDERS=" + string(reattachStr))
+
+	//// INIT
+	stdout, stderr, err := tf.Run("init")
+	if err != nil {
+		t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	// Make sure we didn't download the binary
+	if strings.Contains(stdout, "Installing hashicorp/test v") {
+		t.Errorf("test provider download message is present in init output:\n%s", stdout)
+	}
+	if tf.FileExists(filepath.Join(".terraform", "plugins", "registry.terraform.io", "hashicorp", "test")) {
+		t.Errorf("test provider binary found in .terraform dir")
+	}
+
+	//// PLAN
+	_, stderr, err = tf.Run("plan", "-out=tfplan")
+	if err != nil {
+		t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !provider.PlanResourceChangeCalled() {
+		t.Error("PlanResourceChange not called on un-managed provider")
+	}
+
+	//// APPLY
+	_, stderr, err = tf.Run("apply", "tfplan")
+	if err != nil {
+		t.Fatalf("unexpected apply error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !provider.ApplyResourceChangeCalled() {
+		t.Error("ApplyResourceChange not called on un-managed provider")
+	}
+	provider.ResetApplyResourceChangeCalled()
+
+	//// DESTROY
+	_, stderr, err = tf.Run("destroy", "-auto-approve")
+	if err != nil {
+		t.Fatalf("unexpected destroy error: %s\nstderr:\n%s", err, stderr)
+	}
+
+	if !provider.ApplyResourceChangeCalled() {
+		t.Error("ApplyResourceChange (destroy) not called on in-process provider")
+	}
+	cancel()
+	<-closeCh
+}
diff --git a/v1.5.7/internal/command/e2etest/version_test.go b/v1.5.7/internal/command/e2etest/version_test.go
new file mode 100644
index 0000000..5200a20
--- /dev/null
+++ b/v1.5.7/internal/command/e2etest/version_test.go
@@ -0,0 +1,97 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2etest
+
+import (
+	"fmt"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/e2e"
+	"github.com/hashicorp/terraform/version"
+)
+
+func TestVersion(t *testing.T) {
+	// Along with testing the "version" command in particular, this serves
+	// as a good smoke test for whether the Terraform binary can even be
+	// compiled and run, since it doesn't require any external network access
+	// to do its job.
+
+	t.Parallel()
+
+	fixturePath := filepath.Join("testdata", "empty")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	stdout, stderr, err := tf.Run("version")
+	if err != nil {
+		t.Errorf("unexpected error: %s", err)
+	}
+
+	if stderr != "" {
+		t.Errorf("unexpected stderr output:\n%s", stderr)
+	}
+
+	wantVersion := fmt.Sprintf("Terraform v%s", version.String())
+	if !strings.Contains(stdout, wantVersion) {
+		t.Errorf("output does not contain our current version %q:\n%s", wantVersion, stdout)
+	}
+}
+
+func TestVersionWithProvider(t *testing.T) {
+	// This is a more elaborate use of "version" that shows the selected
+	// versions of plugins too.
+	t.Parallel()
+
+	// This test reaches out to releases.hashicorp.com to download the
+	// template and null providers, so it can only run if network access is
+	// allowed.
+	skipIfCannotAccessNetwork(t)
+
+	fixturePath := filepath.Join("testdata", "template-provider")
+	tf := e2e.NewBinary(t, terraformBin, fixturePath)
+
+	// Initial run (before "init") should work without error but will not
+	// include the provider version, since we've not "locked" one yet.
+	{
+		stdout, stderr, err := tf.Run("version")
+		if err != nil {
+			t.Errorf("unexpected error: %s", err)
+		}
+
+		if stderr != "" {
+			t.Errorf("unexpected stderr output:\n%s", stderr)
+		}
+
+		wantVersion := fmt.Sprintf("Terraform v%s", version.String())
+		if !strings.Contains(stdout, wantVersion) {
+			t.Errorf("output does not contain our current version %q:\n%s", wantVersion, stdout)
+		}
+	}
+
+	{
+		_, _, err := tf.Run("init")
+		if err != nil {
+			t.Errorf("unexpected error: %s", err)
+		}
+	}
+
+	// After running init, we additionally include information about the
+	// selected version of the "template" provider.
+	{
+		stdout, stderr, err := tf.Run("version")
+		if err != nil {
+			t.Errorf("unexpected error: %s", err)
+		}
+
+		if stderr != "" {
+			t.Errorf("unexpected stderr output:\n%s", stderr)
+		}
+
+		wantMsg := "+ provider registry.terraform.io/hashicorp/template v" // we don't know which version we'll get here
+		if !strings.Contains(stdout, wantMsg) {
+			t.Errorf("output does not contain provider information %q:\n%s", wantMsg, stdout)
+		}
+	}
+}
diff --git a/v1.5.7/internal/command/flag_kv.go b/v1.5.7/internal/command/flag_kv.go
new file mode 100644
index 0000000..d788f19
--- /dev/null
+++ b/v1.5.7/internal/command/flag_kv.go
@@ -0,0 +1,46 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+)
+
+// FlagStringKV is a flag.Value implementation for parsing user variables
+// from the command-line in the format of '-var key=value', where value is
+// only ever a primitive.
+type FlagStringKV map[string]string
+
+func (v *FlagStringKV) String() string {
+	return ""
+}
+
+func (v *FlagStringKV) Set(raw string) error {
+	idx := strings.Index(raw, "=")
+	if idx == -1 {
+		return fmt.Errorf("No '=' value in arg: %s", raw)
+	}
+
+	if *v == nil {
+		*v = make(map[string]string)
+	}
+
+	key, value := raw[0:idx], raw[idx+1:]
+	(*v)[key] = value
+	return nil
+}
+
+// FlagStringSlice is a flag.Value implementation for parsing targets from the
+// command line, e.g. -target=aws_instance.foo -target=aws_vpc.bar
+type FlagStringSlice []string
+
+func (v *FlagStringSlice) String() string {
+	return ""
+}
+func (v *FlagStringSlice) Set(raw string) error {
+	*v = append(*v, raw)
+
+	return nil
+}
diff --git a/v1.5.7/internal/command/flag_kv_test.go b/v1.5.7/internal/command/flag_kv_test.go
new file mode 100644
index 0000000..15dac0c
--- /dev/null
+++ b/v1.5.7/internal/command/flag_kv_test.go
@@ -0,0 +1,71 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"flag"
+	"reflect"
+	"testing"
+)
+
+func TestFlagStringKV_impl(t *testing.T) {
+	var _ flag.Value = new(FlagStringKV)
+}
+
+func TestFlagStringKV(t *testing.T) {
+	cases := []struct {
+		Input  string
+		Output map[string]string
+		Error  bool
+	}{
+		{
+			"key=value",
+			map[string]string{"key": "value"},
+			false,
+		},
+
+		{
+			"key=",
+			map[string]string{"key": ""},
+			false,
+		},
+
+		{
+			"key=foo=bar",
+			map[string]string{"key": "foo=bar"},
+			false,
+		},
+
+		{
+			"map.key=foo",
+			map[string]string{"map.key": "foo"},
+			false,
+		},
+
+		{
+			"key",
+			nil,
+			true,
+		},
+
+		{
+			"key=/path",
+			map[string]string{"key": "/path"},
+			false,
+		},
+	}
+
+	for _, tc := range cases {
+		f := new(FlagStringKV)
+		err := f.Set(tc.Input)
+		if err != nil != tc.Error {
+			t.Fatalf("bad error. Input: %#v\n\nError: %s", tc.Input, err)
+		}
+
+		actual := map[string]string(*f)
+		if !reflect.DeepEqual(actual, tc.Output) {
+			t.Fatalf("bad: %#v", actual)
+		}
+	}
+}
diff --git a/v1.5.7/internal/command/fmt.go b/v1.5.7/internal/command/fmt.go
new file mode 100644
index 0000000..3d8f51f
--- /dev/null
+++ b/v1.5.7/internal/command/fmt.go
@@ -0,0 +1,594 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/hcl/v2/hclwrite"
+	"github.com/mitchellh/cli"
+
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+const (
+	stdinArg = "-"
+)
+
+// FmtCommand is a Command implementation that rewrites Terraform config
+// files to a canonical format and style.
+type FmtCommand struct {
+	Meta
+	list      bool
+	write     bool
+	diff      bool
+	check     bool
+	recursive bool
+	input     io.Reader // STDIN if nil
+}
+
+func (c *FmtCommand) Run(args []string) int {
+	if c.input == nil {
+		c.input = os.Stdin
+	}
+
+	args = c.Meta.process(args)
+	cmdFlags := c.Meta.defaultFlagSet("fmt")
+	cmdFlags.BoolVar(&c.list, "list", true, "list")
+	cmdFlags.BoolVar(&c.write, "write", true, "write")
+	cmdFlags.BoolVar(&c.diff, "diff", false, "diff")
+	cmdFlags.BoolVar(&c.check, "check", false, "check")
+	cmdFlags.BoolVar(&c.recursive, "recursive", false, "recursive")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	args = cmdFlags.Args()
+
+	var paths []string
+	if len(args) == 0 {
+		paths = []string{"."}
+	} else if args[0] == stdinArg {
+		c.list = false
+		c.write = false
+	} else {
+		paths = args
+	}
+
+	var output io.Writer
+	list := c.list // preserve the original value of -list
+	if c.check {
+		// set to true so we can use the list output to check
+		// if the input needs formatting
+		c.list = true
+		c.write = false
+		output = &bytes.Buffer{}
+	} else {
+		output = &cli.UiWriter{Ui: c.Ui}
+	}
+
+	diags := c.fmt(paths, c.input, output)
+	c.showDiagnostics(diags)
+	if diags.HasErrors() {
+		return 2
+	}
+
+	if c.check {
+		buf := output.(*bytes.Buffer)
+		ok := buf.Len() == 0
+		if list {
+			io.Copy(&cli.UiWriter{Ui: c.Ui}, buf)
+		}
+		if ok {
+			return 0
+		} else {
+			return 3
+		}
+	}
+
+	return 0
+}
+
+func (c *FmtCommand) fmt(paths []string, stdin io.Reader, stdout io.Writer) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	if len(paths) == 0 { // Assuming stdin, then.
+		if c.write {
+			diags = diags.Append(fmt.Errorf("Option -write cannot be used when reading from stdin"))
+			return diags
+		}
+		fileDiags := c.processFile("<stdin>", stdin, stdout, true)
+		diags = diags.Append(fileDiags)
+		return diags
+	}
+
+	for _, path := range paths {
+		path = c.normalizePath(path)
+		info, err := os.Stat(path)
+		if err != nil {
+			diags = diags.Append(fmt.Errorf("No file or directory at %s", path))
+			return diags
+		}
+		if info.IsDir() {
+			dirDiags := c.processDir(path, stdout)
+			diags = diags.Append(dirDiags)
+		} else {
+			switch filepath.Ext(path) {
+			case ".tf", ".tfvars":
+				f, err := os.Open(path)
+				if err != nil {
+					// Open does not produce error messages that are end-user-appropriate,
+					// so we'll need to simplify here.
+					diags = diags.Append(fmt.Errorf("Failed to read file %s", path))
+					continue
+				}
+
+				fileDiags := c.processFile(c.normalizePath(path), f, stdout, false)
+				diags = diags.Append(fileDiags)
+				f.Close()
+			default:
+				diags = diags.Append(fmt.Errorf("Only .tf and .tfvars files can be processed with terraform fmt"))
+				continue
+			}
+		}
+	}
+
+	return diags
+}
+
+func (c *FmtCommand) processFile(path string, r io.Reader, w io.Writer, isStdout bool) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	log.Printf("[TRACE] terraform fmt: Formatting %s", path)
+
+	src, err := ioutil.ReadAll(r)
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Failed to read %s", path))
+		return diags
+	}
+
+	// Register this path as a synthetic configuration source, so that any
+	// diagnostic errors can include the source code snippet
+	c.registerSynthConfigSource(path, src)
+
+	// File must be parseable as HCL native syntax before we'll try to format
+	// it. If not, the formatter is likely to make drastic changes that would
+	// be hard for the user to undo.
+	_, syntaxDiags := hclsyntax.ParseConfig(src, path, hcl.Pos{Line: 1, Column: 1})
+	if syntaxDiags.HasErrors() {
+		diags = diags.Append(syntaxDiags)
+		return diags
+	}
+
+	result := c.formatSourceCode(src, path)
+
+	if !bytes.Equal(src, result) {
+		// Something was changed
+		if c.list {
+			fmt.Fprintln(w, path)
+		}
+		if c.write {
+			err := ioutil.WriteFile(path, result, 0644)
+			if err != nil {
+				diags = diags.Append(fmt.Errorf("Failed to write %s", path))
+				return diags
+			}
+		}
+		if c.diff {
+			diff, err := bytesDiff(src, result, path)
+			if err != nil {
+				diags = diags.Append(fmt.Errorf("Failed to generate diff for %s: %s", path, err))
+				return diags
+			}
+			w.Write(diff)
+		}
+	}
+
+	if !c.list && !c.write && !c.diff {
+		_, err = w.Write(result)
+		if err != nil {
+			diags = diags.Append(fmt.Errorf("Failed to write result"))
+		}
+	}
+
+	return diags
+}
+
+func (c *FmtCommand) processDir(path string, stdout io.Writer) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	log.Printf("[TRACE] terraform fmt: looking for files in %s", path)
+
+	entries, err := ioutil.ReadDir(path)
+	if err != nil {
+		switch {
+		case os.IsNotExist(err):
+			diags = diags.Append(fmt.Errorf("There is no configuration directory at %s", path))
+		default:
+			// ReadDir does not produce error messages that are end-user-appropriate,
+			// so we'll need to simplify here.
+			diags = diags.Append(fmt.Errorf("Cannot read directory %s", path))
+		}
+		return diags
+	}
+
+	for _, info := range entries {
+		name := info.Name()
+		if configs.IsIgnoredFile(name) {
+			continue
+		}
+		subPath := filepath.Join(path, name)
+		if info.IsDir() {
+			if c.recursive {
+				subDiags := c.processDir(subPath, stdout)
+				diags = diags.Append(subDiags)
+			}
+
+			// We do not recurse into child directories by default because we
+			// want to mimic the file-reading behavior of "terraform plan", etc,
+			// operating on one module at a time.
+			continue
+		}
+
+		ext := filepath.Ext(name)
+		switch ext {
+		case ".tf", ".tfvars":
+			f, err := os.Open(subPath)
+			if err != nil {
+				// Open does not produce error messages that are end-user-appropriate,
+				// so we'll need to simplify here.
+				diags = diags.Append(fmt.Errorf("Failed to read file %s", subPath))
+				continue
+			}
+
+			fileDiags := c.processFile(c.normalizePath(subPath), f, stdout, false)
+			diags = diags.Append(fileDiags)
+			f.Close()
+		}
+	}
+
+	return diags
+}
+
+// formatSourceCode is the formatting logic itself, applied to each file that
+// is selected (directly or indirectly) on the command line.
+func (c *FmtCommand) formatSourceCode(src []byte, filename string) []byte {
+	f, diags := hclwrite.ParseConfig(src, filename, hcl.InitialPos)
+	if diags.HasErrors() {
+		// It would be weird to get here because the caller should already have
+		// checked for syntax errors and returned them. We'll just do nothing
+		// in this case, returning the input exactly as given.
+		return src
+	}
+
+	c.formatBody(f.Body(), nil)
+
+	return f.Bytes()
+}
+
+func (c *FmtCommand) formatBody(body *hclwrite.Body, inBlocks []string) {
+	attrs := body.Attributes()
+	for name, attr := range attrs {
+		if len(inBlocks) == 1 && inBlocks[0] == "variable" && name == "type" {
+			cleanedExprTokens := c.formatTypeExpr(attr.Expr().BuildTokens(nil))
+			body.SetAttributeRaw(name, cleanedExprTokens)
+			continue
+		}
+		cleanedExprTokens := c.formatValueExpr(attr.Expr().BuildTokens(nil))
+		body.SetAttributeRaw(name, cleanedExprTokens)
+	}
+
+	blocks := body.Blocks()
+	for _, block := range blocks {
+		// Normalize the label formatting, removing any weird stuff like
+		// interleaved inline comments and using the idiomatic quoted
+		// label syntax.
+		block.SetLabels(block.Labels())
+
+		inBlocks := append(inBlocks, block.Type())
+		c.formatBody(block.Body(), inBlocks)
+	}
+}
+
+func (c *FmtCommand) formatValueExpr(tokens hclwrite.Tokens) hclwrite.Tokens {
+	if len(tokens) < 5 {
+		// Can't possibly be a "${ ... }" sequence without at least enough
+		// tokens for the delimiters and one token inside them.
+		return tokens
+	}
+	oQuote := tokens[0]
+	oBrace := tokens[1]
+	cBrace := tokens[len(tokens)-2]
+	cQuote := tokens[len(tokens)-1]
+	if oQuote.Type != hclsyntax.TokenOQuote || oBrace.Type != hclsyntax.TokenTemplateInterp || cBrace.Type != hclsyntax.TokenTemplateSeqEnd || cQuote.Type != hclsyntax.TokenCQuote {
+		// Not an interpolation sequence at all, then.
+		return tokens
+	}
+
+	inside := tokens[2 : len(tokens)-2]
+
+	// We're only interested in sequences that are provable to be single
+	// interpolation sequences, which we'll determine by hunting inside
+	// the interior tokens for any other interpolation sequences. This is
+	// likely to produce false negatives sometimes, but that's better than
+	// false positives and we're mainly interested in catching the easy cases
+	// here.
+	quotes := 0
+	for _, token := range inside {
+		if token.Type == hclsyntax.TokenOQuote {
+			quotes++
+			continue
+		}
+		if token.Type == hclsyntax.TokenCQuote {
+			quotes--
+			continue
+		}
+		if quotes > 0 {
+			// Interpolation sequences inside nested quotes are okay, because
+			// they are part of a nested expression.
+			// "${foo("${bar}")}"
+			continue
+		}
+		if token.Type == hclsyntax.TokenTemplateInterp || token.Type == hclsyntax.TokenTemplateSeqEnd {
+			// We've found another template delimiter within our interior
+			// tokens, which suggests that we've found something like this:
+			// "${foo}${bar}"
+			// That isn't unwrappable, so we'll leave the whole expression alone.
+			return tokens
+		}
+		if token.Type == hclsyntax.TokenQuotedLit {
+			// If there's any literal characters in the outermost
+			// quoted sequence then it is not unwrappable.
+			return tokens
+		}
+	}
+
+	// If we got down here without an early return then this looks like
+	// an unwrappable sequence, but we'll trim any leading and trailing
+	// newlines that might result in an invalid result if we were to
+	// naively trim something like this:
+	// "${
+	//    foo
+	// }"
+	trimmed := c.trimNewlines(inside)
+
+	// Finally, we check if the unwrapped expression is on multiple lines. If
+	// so, we ensure that it is surrounded by parenthesis to make sure that it
+	// parses correctly after unwrapping. This may be redundant in some cases,
+	// but is required for at least multi-line ternary expressions.
+	isMultiLine := false
+	hasLeadingParen := false
+	hasTrailingParen := false
+	for i, token := range trimmed {
+		switch {
+		case i == 0 && token.Type == hclsyntax.TokenOParen:
+			hasLeadingParen = true
+		case token.Type == hclsyntax.TokenNewline:
+			isMultiLine = true
+		case i == len(trimmed)-1 && token.Type == hclsyntax.TokenCParen:
+			hasTrailingParen = true
+		}
+	}
+	if isMultiLine && !(hasLeadingParen && hasTrailingParen) {
+		wrapped := make(hclwrite.Tokens, 0, len(trimmed)+2)
+		wrapped = append(wrapped, &hclwrite.Token{
+			Type:  hclsyntax.TokenOParen,
+			Bytes: []byte("("),
+		})
+		wrapped = append(wrapped, trimmed...)
+		wrapped = append(wrapped, &hclwrite.Token{
+			Type:  hclsyntax.TokenCParen,
+			Bytes: []byte(")"),
+		})
+
+		return wrapped
+	}
+
+	return trimmed
+}
+
+func (c *FmtCommand) formatTypeExpr(tokens hclwrite.Tokens) hclwrite.Tokens {
+	switch len(tokens) {
+	case 1:
+		kwTok := tokens[0]
+		if kwTok.Type != hclsyntax.TokenIdent {
+			// Not a single type keyword, then.
+			return tokens
+		}
+
+		// Collection types without an explicit element type mean
+		// the element type is "any", so we'll normalize that.
+		switch string(kwTok.Bytes) {
+		case "list", "map", "set":
+			return hclwrite.Tokens{
+				kwTok,
+				{
+					Type:  hclsyntax.TokenOParen,
+					Bytes: []byte("("),
+				},
+				{
+					Type:  hclsyntax.TokenIdent,
+					Bytes: []byte("any"),
+				},
+				{
+					Type:  hclsyntax.TokenCParen,
+					Bytes: []byte(")"),
+				},
+			}
+		default:
+			return tokens
+		}
+
+	case 3:
+		// A pre-0.12 legacy quoted string type, like "string".
+		oQuote := tokens[0]
+		strTok := tokens[1]
+		cQuote := tokens[2]
+		if oQuote.Type != hclsyntax.TokenOQuote || strTok.Type != hclsyntax.TokenQuotedLit || cQuote.Type != hclsyntax.TokenCQuote {
+			// Not a quoted string sequence, then.
+			return tokens
+		}
+
+		// Because this quoted syntax is from Terraform 0.11 and
+		// earlier, which didn't have the idea of "any" as an,
+		// element type, we use string as the default element
+		// type. That will avoid oddities if somehow the configuration
+		// was relying on numeric values being auto-converted to
+		// string, as 0.11 would do. This mimicks what terraform
+		// 0.12upgrade used to do, because we'd found real-world
+		// modules that were depending on the auto-stringing.)
+		switch string(strTok.Bytes) {
+		case "string":
+			return hclwrite.Tokens{
+				{
+					Type:  hclsyntax.TokenIdent,
+					Bytes: []byte("string"),
+				},
+			}
+		case "list":
+			return hclwrite.Tokens{
+				{
+					Type:  hclsyntax.TokenIdent,
+					Bytes: []byte("list"),
+				},
+				{
+					Type:  hclsyntax.TokenOParen,
+					Bytes: []byte("("),
+				},
+				{
+					Type:  hclsyntax.TokenIdent,
+					Bytes: []byte("string"),
+				},
+				{
+					Type:  hclsyntax.TokenCParen,
+					Bytes: []byte(")"),
+				},
+			}
+		case "map":
+			return hclwrite.Tokens{
+				{
+					Type:  hclsyntax.TokenIdent,
+					Bytes: []byte("map"),
+				},
+				{
+					Type:  hclsyntax.TokenOParen,
+					Bytes: []byte("("),
+				},
+				{
+					Type:  hclsyntax.TokenIdent,
+					Bytes: []byte("string"),
+				},
+				{
+					Type:  hclsyntax.TokenCParen,
+					Bytes: []byte(")"),
+				},
+			}
+		default:
+			// Something else we're not expecting, then.
+			return tokens
+		}
+	default:
+		return tokens
+	}
+}
+
+func (c *FmtCommand) trimNewlines(tokens hclwrite.Tokens) hclwrite.Tokens {
+	if len(tokens) == 0 {
+		return nil
+	}
+	var start, end int
+	for start = 0; start < len(tokens); start++ {
+		if tokens[start].Type != hclsyntax.TokenNewline {
+			break
+		}
+	}
+	for end = len(tokens); end > 0; end-- {
+		if tokens[end-1].Type != hclsyntax.TokenNewline {
+			break
+		}
+	}
+	return tokens[start:end]
+}
+
+func (c *FmtCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] fmt [options] [target...]
+
+  Rewrites all Terraform configuration files to a canonical format. Both
+  configuration files (.tf) and variables files (.tfvars) are updated.
+  JSON files (.tf.json or .tfvars.json) are not modified.
+
+  By default, fmt scans the current directory for configuration files. If you
+  provide a directory for the target argument, then fmt will scan that
+  directory instead. If you provide a file, then fmt will process just that
+  file. If you provide a single dash ("-"), then fmt will read from standard
+  input (STDIN).
+
+  The content must be in the Terraform language native syntax; JSON is not
+  supported.
+
+Options:
+
+  -list=false    Don't list files whose formatting differs
+                 (always disabled if using STDIN)
+
+  -write=false   Don't write to source files
+                 (always disabled if using STDIN or -check)
+
+  -diff          Display diffs of formatting changes
+
+  -check         Check if the input is formatted. Exit status will be 0 if all
+                 input is properly formatted and non-zero otherwise.
+
+  -no-color      If specified, output won't contain any color.
+
+  -recursive     Also process files in subdirectories. By default, only the
+                 given directory (or current directory) is processed.
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *FmtCommand) Synopsis() string {
+	return "Reformat your configuration in the standard style"
+}
+
+func bytesDiff(b1, b2 []byte, path string) (data []byte, err error) {
+	f1, err := ioutil.TempFile("", "")
+	if err != nil {
+		return
+	}
+	defer os.Remove(f1.Name())
+	defer f1.Close()
+
+	f2, err := ioutil.TempFile("", "")
+	if err != nil {
+		return
+	}
+	defer os.Remove(f2.Name())
+	defer f2.Close()
+
+	f1.Write(b1)
+	f2.Write(b2)
+
+	data, err = exec.Command("diff", "--label=old/"+path, "--label=new/"+path, "-u", f1.Name(), f2.Name()).CombinedOutput()
+	if len(data) > 0 {
+		// diff exits with a non-zero status when the files don't match.
+		// Ignore that failure as long as we get output.
+		err = nil
+	}
+	return
+}
diff --git a/v1.5.7/internal/command/fmt_test.go b/v1.5.7/internal/command/fmt_test.go
new file mode 100644
index 0000000..1e73622
--- /dev/null
+++ b/v1.5.7/internal/command/fmt_test.go
@@ -0,0 +1,420 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/mitchellh/cli"
+)
+
+func TestFmt(t *testing.T) {
+	const inSuffix = "_in.tf"
+	const outSuffix = "_out.tf"
+	const gotSuffix = "_got.tf"
+	entries, err := ioutil.ReadDir("testdata/fmt")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	tmpDir, err := filepath.EvalSymlinks(t.TempDir())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, info := range entries {
+		if info.IsDir() {
+			continue
+		}
+		filename := info.Name()
+		if !strings.HasSuffix(filename, inSuffix) {
+			continue
+		}
+		testName := filename[:len(filename)-len(inSuffix)]
+		t.Run(testName, func(t *testing.T) {
+			inFile := filepath.Join("testdata", "fmt", testName+inSuffix)
+			wantFile := filepath.Join("testdata", "fmt", testName+outSuffix)
+			gotFile := filepath.Join(tmpDir, testName+gotSuffix)
+			input, err := ioutil.ReadFile(inFile)
+			if err != nil {
+				t.Fatal(err)
+			}
+			want, err := ioutil.ReadFile(wantFile)
+			if err != nil {
+				t.Fatal(err)
+			}
+			err = ioutil.WriteFile(gotFile, input, 0700)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			ui := cli.NewMockUi()
+			c := &FmtCommand{
+				Meta: Meta{
+					testingOverrides: metaOverridesForProvider(testProvider()),
+					Ui:               ui,
+				},
+			}
+			args := []string{gotFile}
+			if code := c.Run(args); code != 0 {
+				t.Fatalf("fmt command was unsuccessful:\n%s", ui.ErrorWriter.String())
+			}
+
+			got, err := ioutil.ReadFile(gotFile)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			if diff := cmp.Diff(string(want), string(got)); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestFmt_nonexist(t *testing.T) {
+	tempDir := fmtFixtureWriteDir(t)
+
+	ui := new(cli.MockUi)
+	c := &FmtCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+		},
+	}
+
+	missingDir := filepath.Join(tempDir, "doesnotexist")
+	args := []string{missingDir}
+	if code := c.Run(args); code != 2 {
+		t.Fatalf("wrong exit code. errors: \n%s", ui.ErrorWriter.String())
+	}
+
+	expected := "No file or directory at"
+	if actual := ui.ErrorWriter.String(); !strings.Contains(actual, expected) {
+		t.Fatalf("expected:\n%s\n\nto include: %q", actual, expected)
+	}
+}
+
+func TestFmt_syntaxError(t *testing.T) {
+	tempDir := testTempDir(t)
+
+	invalidSrc := `
+a = 1 +
+`
+
+	err := ioutil.WriteFile(filepath.Join(tempDir, "invalid.tf"), []byte(invalidSrc), 0644)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	ui := new(cli.MockUi)
+	c := &FmtCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{tempDir}
+	if code := c.Run(args); code != 2 {
+		t.Fatalf("wrong exit code. errors: \n%s", ui.ErrorWriter.String())
+	}
+
+	expected := "Invalid expression"
+	if actual := ui.ErrorWriter.String(); !strings.Contains(actual, expected) {
+		t.Fatalf("expected:\n%s\n\nto include: %q", actual, expected)
+	}
+}
+
+func TestFmt_snippetInError(t *testing.T) {
+	tempDir := testTempDir(t)
+
+	backendSrc := `terraform {backend "s3" {}}`
+
+	err := ioutil.WriteFile(filepath.Join(tempDir, "backend.tf"), []byte(backendSrc), 0644)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	ui := new(cli.MockUi)
+	c := &FmtCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{tempDir}
+	if code := c.Run(args); code != 2 {
+		t.Fatalf("wrong exit code. errors: \n%s", ui.ErrorWriter.String())
+	}
+
+	substrings := []string{
+		"Argument definition required",
+		"line 1, in terraform",
+		`1: terraform {backend "s3" {}}`,
+	}
+	for _, substring := range substrings {
+		if actual := ui.ErrorWriter.String(); !strings.Contains(actual, substring) {
+			t.Errorf("expected:\n%s\n\nto include: %q", actual, substring)
+		}
+	}
+}
+
+func TestFmt_manyArgs(t *testing.T) {
+	tempDir := fmtFixtureWriteDir(t)
+	// Add a second file
+	secondSrc := `locals { x = 1 }`
+
+	err := ioutil.WriteFile(filepath.Join(tempDir, "second.tf"), []byte(secondSrc), 0644)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	ui := new(cli.MockUi)
+	c := &FmtCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{
+		filepath.Join(tempDir, "main.tf"),
+		filepath.Join(tempDir, "second.tf"),
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("wrong exit code. errors: \n%s", ui.ErrorWriter.String())
+	}
+
+	got, err := filepath.Abs(strings.TrimSpace(ui.OutputWriter.String()))
+	if err != nil {
+		t.Fatal(err)
+	}
+	want := filepath.Join(tempDir, fmtFixture.filename)
+
+	if got != want {
+		t.Fatalf("wrong output\ngot:  %s\nwant: %s", got, want)
+	}
+}
+
+func TestFmt_workingDirectory(t *testing.T) {
+	tempDir := fmtFixtureWriteDir(t)
+
+	cwd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	err = os.Chdir(tempDir)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer os.Chdir(cwd)
+
+	ui := new(cli.MockUi)
+	c := &FmtCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("wrong exit code. errors: \n%s", ui.ErrorWriter.String())
+	}
+
+	expected := fmt.Sprintf("%s\n", fmtFixture.filename)
+	if actual := ui.OutputWriter.String(); actual != expected {
+		t.Fatalf("got: %q\nexpected: %q", actual, expected)
+	}
+}
+
+func TestFmt_directoryArg(t *testing.T) {
+	tempDir := fmtFixtureWriteDir(t)
+
+	ui := new(cli.MockUi)
+	c := &FmtCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{tempDir}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("wrong exit code. errors: \n%s", ui.ErrorWriter.String())
+	}
+
+	got, err := filepath.Abs(strings.TrimSpace(ui.OutputWriter.String()))
+	if err != nil {
+		t.Fatal(err)
+	}
+	want := filepath.Join(tempDir, fmtFixture.filename)
+
+	if got != want {
+		t.Fatalf("wrong output\ngot:  %s\nwant: %s", got, want)
+	}
+}
+
+func TestFmt_fileArg(t *testing.T) {
+	tempDir := fmtFixtureWriteDir(t)
+
+	ui := new(cli.MockUi)
+	c := &FmtCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{filepath.Join(tempDir, fmtFixture.filename)}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("wrong exit code. errors: \n%s", ui.ErrorWriter.String())
+	}
+
+	got, err := filepath.Abs(strings.TrimSpace(ui.OutputWriter.String()))
+	if err != nil {
+		t.Fatal(err)
+	}
+	want := filepath.Join(tempDir, fmtFixture.filename)
+
+	if got != want {
+		t.Fatalf("wrong output\ngot:  %s\nwant: %s", got, want)
+	}
+}
+
+func TestFmt_stdinArg(t *testing.T) {
+	input := new(bytes.Buffer)
+	input.Write(fmtFixture.input)
+
+	ui := new(cli.MockUi)
+	c := &FmtCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+		},
+		input: input,
+	}
+
+	args := []string{"-"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("wrong exit code. errors: \n%s", ui.ErrorWriter.String())
+	}
+
+	expected := fmtFixture.golden
+	if actual := ui.OutputWriter.Bytes(); !bytes.Equal(actual, expected) {
+		t.Fatalf("got: %q\nexpected: %q", actual, expected)
+	}
+}
+
+func TestFmt_nonDefaultOptions(t *testing.T) {
+	tempDir := fmtFixtureWriteDir(t)
+
+	ui := new(cli.MockUi)
+	c := &FmtCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{
+		"-list=false",
+		"-write=false",
+		"-diff",
+		tempDir,
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("wrong exit code. errors: \n%s", ui.ErrorWriter.String())
+	}
+
+	expected := fmt.Sprintf("-%s+%s", fmtFixture.input, fmtFixture.golden)
+	if actual := ui.OutputWriter.String(); !strings.Contains(actual, expected) {
+		t.Fatalf("expected:\n%s\n\nto include: %q", actual, expected)
+	}
+}
+
+func TestFmt_check(t *testing.T) {
+	tempDir := fmtFixtureWriteDir(t)
+
+	ui := new(cli.MockUi)
+	c := &FmtCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{
+		"-check",
+		tempDir,
+	}
+	if code := c.Run(args); code != 3 {
+		t.Fatalf("wrong exit code. expected 3")
+	}
+
+	// Given that we give relative paths back to the user, normalize this temp
+	// dir so that we're comparing against a relative-ized (normalized) path
+	tempDir = c.normalizePath(tempDir)
+
+	if actual := ui.OutputWriter.String(); !strings.Contains(actual, tempDir) {
+		t.Fatalf("expected:\n%s\n\nto include: %q", actual, tempDir)
+	}
+}
+
+func TestFmt_checkStdin(t *testing.T) {
+	input := new(bytes.Buffer)
+	input.Write(fmtFixture.input)
+
+	ui := new(cli.MockUi)
+	c := &FmtCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+		},
+		input: input,
+	}
+
+	args := []string{
+		"-check",
+		"-",
+	}
+	if code := c.Run(args); code != 3 {
+		t.Fatalf("wrong exit code. expected 3, got %d", code)
+	}
+
+	if ui.OutputWriter != nil {
+		t.Fatalf("expected no output, got: %q", ui.OutputWriter.String())
+	}
+}
+
+var fmtFixture = struct {
+	filename      string
+	input, golden []byte
+}{
+	"main.tf",
+	[]byte(`  foo  =  "bar"
+`),
+	[]byte(`foo = "bar"
+`),
+}
+
+func fmtFixtureWriteDir(t *testing.T) string {
+	dir := testTempDir(t)
+
+	err := ioutil.WriteFile(filepath.Join(dir, fmtFixture.filename), fmtFixture.input, 0644)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	return dir
+}
diff --git a/v1.5.7/internal/command/format/diagnostic.go b/v1.5.7/internal/command/format/diagnostic.go
new file mode 100644
index 0000000..2e60885
--- /dev/null
+++ b/v1.5.7/internal/command/format/diagnostic.go
@@ -0,0 +1,322 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package format
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"sort"
+	"strings"
+
+	viewsjson "github.com/hashicorp/terraform/internal/command/views/json"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+
+	"github.com/mitchellh/colorstring"
+	wordwrap "github.com/mitchellh/go-wordwrap"
+)
+
+var disabledColorize = &colorstring.Colorize{
+	Colors:  colorstring.DefaultColors,
+	Disable: true,
+}
+
+// Diagnostic formats a single diagnostic message.
+//
+// The width argument specifies at what column the diagnostic messages will
+// be wrapped. If set to zero, messages will not be wrapped by this function
+// at all. Although the long-form text parts of the message are wrapped,
+// not all aspects of the message are guaranteed to fit within the specified
+// terminal width.
+func Diagnostic(diag tfdiags.Diagnostic, sources map[string][]byte, color *colorstring.Colorize, width int) string {
+	return DiagnosticFromJSON(viewsjson.NewDiagnostic(diag, sources), color, width)
+}
+
+func DiagnosticFromJSON(diag *viewsjson.Diagnostic, color *colorstring.Colorize, width int) string {
+	if diag == nil {
+		// No good reason to pass a nil diagnostic in here...
+		return ""
+	}
+
+	var buf bytes.Buffer
+
+	// these leftRule* variables are markers for the beginning of the lines
+	// containing the diagnostic that are intended to help sighted users
+	// better understand the information hierarchy when diagnostics appear
+	// alongside other information or alongside other diagnostics.
+	//
+	// Without this, it seems (based on folks sharing incomplete messages when
+	// asking questions, or including extra content that's not part of the
+	// diagnostic) that some readers have trouble easily identifying which
+	// text belongs to the diagnostic and which does not.
+	var leftRuleLine, leftRuleStart, leftRuleEnd string
+	var leftRuleWidth int // in visual character cells
+
+	switch diag.Severity {
+	case viewsjson.DiagnosticSeverityError:
+		buf.WriteString(color.Color("[bold][red]Error: [reset]"))
+		leftRuleLine = color.Color("[red]│[reset] ")
+		leftRuleStart = color.Color("[red]╷[reset]")
+		leftRuleEnd = color.Color("[red]╵[reset]")
+		leftRuleWidth = 2
+	case viewsjson.DiagnosticSeverityWarning:
+		buf.WriteString(color.Color("[bold][yellow]Warning: [reset]"))
+		leftRuleLine = color.Color("[yellow]│[reset] ")
+		leftRuleStart = color.Color("[yellow]╷[reset]")
+		leftRuleEnd = color.Color("[yellow]╵[reset]")
+		leftRuleWidth = 2
+	default:
+		// Clear out any coloring that might be applied by Terraform's UI helper,
+		// so our result is not context-sensitive.
+		buf.WriteString(color.Color("\n[reset]"))
+	}
+
+	// We don't wrap the summary, since we expect it to be terse, and since
+	// this is where we put the text of a native Go error it may not always
+	// be pure text that lends itself well to word-wrapping.
+	fmt.Fprintf(&buf, color.Color("[bold]%s[reset]\n\n"), diag.Summary)
+
+	appendSourceSnippets(&buf, diag, color)
+
+	if diag.Detail != "" {
+		paraWidth := width - leftRuleWidth - 1 // leave room for the left rule
+		if paraWidth > 0 {
+			lines := strings.Split(diag.Detail, "\n")
+			for _, line := range lines {
+				if !strings.HasPrefix(line, " ") {
+					line = wordwrap.WrapString(line, uint(paraWidth))
+				}
+				fmt.Fprintf(&buf, "%s\n", line)
+			}
+		} else {
+			fmt.Fprintf(&buf, "%s\n", diag.Detail)
+		}
+	}
+
+	// Before we return, we'll finally add the left rule prefixes to each
+	// line so that the overall message is visually delimited from what's
+	// around it. We'll do that by scanning over what we already generated
+	// and adding the prefix for each line.
+	var ruleBuf strings.Builder
+	sc := bufio.NewScanner(&buf)
+	ruleBuf.WriteString(leftRuleStart)
+	ruleBuf.WriteByte('\n')
+	for sc.Scan() {
+		line := sc.Text()
+		prefix := leftRuleLine
+		if line == "" {
+			// Don't print the space after the line if there would be nothing
+			// after it anyway.
+			prefix = strings.TrimSpace(prefix)
+		}
+		ruleBuf.WriteString(prefix)
+		ruleBuf.WriteString(line)
+		ruleBuf.WriteByte('\n')
+	}
+	ruleBuf.WriteString(leftRuleEnd)
+	ruleBuf.WriteByte('\n')
+
+	return ruleBuf.String()
+}
+
+// DiagnosticPlain is an alternative to Diagnostic which minimises the use of
+// virtual terminal formatting sequences.
+//
+// It is intended for use in automation and other contexts in which diagnostic
+// messages are parsed from the Terraform output.
+func DiagnosticPlain(diag tfdiags.Diagnostic, sources map[string][]byte, width int) string {
+	return DiagnosticPlainFromJSON(viewsjson.NewDiagnostic(diag, sources), width)
+}
+
+func DiagnosticPlainFromJSON(diag *viewsjson.Diagnostic, width int) string {
+	if diag == nil {
+		// No good reason to pass a nil diagnostic in here...
+		return ""
+	}
+
+	var buf bytes.Buffer
+
+	switch diag.Severity {
+	case viewsjson.DiagnosticSeverityError:
+		buf.WriteString("\nError: ")
+	case viewsjson.DiagnosticSeverityWarning:
+		buf.WriteString("\nWarning: ")
+	default:
+		buf.WriteString("\n")
+	}
+
+	// We don't wrap the summary, since we expect it to be terse, and since
+	// this is where we put the text of a native Go error it may not always
+	// be pure text that lends itself well to word-wrapping.
+	fmt.Fprintf(&buf, "%s\n\n", diag.Summary)
+
+	appendSourceSnippets(&buf, diag, disabledColorize)
+
+	if diag.Detail != "" {
+		if width > 1 {
+			lines := strings.Split(diag.Detail, "\n")
+			for _, line := range lines {
+				if !strings.HasPrefix(line, " ") {
+					line = wordwrap.WrapString(line, uint(width-1))
+				}
+				fmt.Fprintf(&buf, "%s\n", line)
+			}
+		} else {
+			fmt.Fprintf(&buf, "%s\n", diag.Detail)
+		}
+	}
+
+	return buf.String()
+}
+
+// DiagnosticWarningsCompact is an alternative to Diagnostic for when all of
+// the given diagnostics are warnings and we want to show them compactly,
+// with only two lines per warning and excluding all of the detail information.
+//
+// The caller may optionally pre-process the given diagnostics with
+// ConsolidateWarnings, in which case this function will recognize consolidated
+// messages and include an indication that they are consolidated.
+//
+// Do not pass non-warning diagnostics to this function, or the result will
+// be nonsense.
+func DiagnosticWarningsCompact(diags tfdiags.Diagnostics, color *colorstring.Colorize) string {
+	var b strings.Builder
+	b.WriteString(color.Color("[bold][yellow]Warnings:[reset]\n\n"))
+	for _, diag := range diags {
+		sources := tfdiags.WarningGroupSourceRanges(diag)
+		b.WriteString(fmt.Sprintf("- %s\n", diag.Description().Summary))
+		if len(sources) > 0 {
+			mainSource := sources[0]
+			if mainSource.Subject != nil {
+				if len(sources) > 1 {
+					b.WriteString(fmt.Sprintf(
+						"  on %s line %d (and %d more)\n",
+						mainSource.Subject.Filename,
+						mainSource.Subject.Start.Line,
+						len(sources)-1,
+					))
+				} else {
+					b.WriteString(fmt.Sprintf(
+						"  on %s line %d\n",
+						mainSource.Subject.Filename,
+						mainSource.Subject.Start.Line,
+					))
+				}
+			} else if len(sources) > 1 {
+				b.WriteString(fmt.Sprintf(
+					"  (%d occurences of this warning)\n",
+					len(sources),
+				))
+			}
+		}
+	}
+
+	return b.String()
+}
+
+func appendSourceSnippets(buf *bytes.Buffer, diag *viewsjson.Diagnostic, color *colorstring.Colorize) {
+	if diag.Address != "" {
+		fmt.Fprintf(buf, "  with %s,\n", diag.Address)
+	}
+
+	if diag.Range == nil {
+		return
+	}
+
+	if diag.Snippet == nil {
+		// This should generally not happen, as long as sources are always
+		// loaded through the main loader. We may load things in other
+		// ways in weird cases, so we'll tolerate it at the expense of
+		// a not-so-helpful error message.
+		fmt.Fprintf(buf, "  on %s line %d:\n  (source code not available)\n", diag.Range.Filename, diag.Range.Start.Line)
+	} else {
+		snippet := diag.Snippet
+		code := snippet.Code
+
+		var contextStr string
+		if snippet.Context != nil {
+			contextStr = fmt.Sprintf(", in %s", *snippet.Context)
+		}
+		fmt.Fprintf(buf, "  on %s line %d%s:\n", diag.Range.Filename, diag.Range.Start.Line, contextStr)
+
+		// Split the snippet and render the highlighted section with underlines
+		start := snippet.HighlightStartOffset
+		end := snippet.HighlightEndOffset
+
+		// Only buggy diagnostics can have an end range before the start, but
+		// we need to ensure we don't crash here if that happens.
+		if end < start {
+			end = start + 1
+			if end > len(code) {
+				end = len(code)
+			}
+		}
+
+		// If either start or end is out of range for the code buffer then
+		// we'll cap them at the bounds just to avoid a panic, although
+		// this would happen only if there's a bug in the code generating
+		// the snippet objects.
+		if start < 0 {
+			start = 0
+		} else if start > len(code) {
+			start = len(code)
+		}
+		if end < 0 {
+			end = 0
+		} else if end > len(code) {
+			end = len(code)
+		}
+
+		before, highlight, after := code[0:start], code[start:end], code[end:]
+		code = fmt.Sprintf(color.Color("%s[underline]%s[reset]%s"), before, highlight, after)
+
+		// Split the snippet into lines and render one at a time
+		lines := strings.Split(code, "\n")
+		for i, line := range lines {
+			fmt.Fprintf(
+				buf, "%4d: %s\n",
+				snippet.StartLine+i,
+				line,
+			)
+		}
+
+		if len(snippet.Values) > 0 || (snippet.FunctionCall != nil && snippet.FunctionCall.Signature != nil) {
+			// The diagnostic may also have information about the dynamic
+			// values of relevant variables at the point of evaluation.
+			// This is particularly useful for expressions that get evaluated
+			// multiple times with different values, such as blocks using
+			// "count" and "for_each", or within "for" expressions.
+			values := make([]viewsjson.DiagnosticExpressionValue, len(snippet.Values))
+			copy(values, snippet.Values)
+			sort.Slice(values, func(i, j int) bool {
+				return values[i].Traversal < values[j].Traversal
+			})
+
+			fmt.Fprint(buf, color.Color("    [dark_gray]├────────────────[reset]\n"))
+			if callInfo := snippet.FunctionCall; callInfo != nil && callInfo.Signature != nil {
+
+				fmt.Fprintf(buf, color.Color("    [dark_gray]│[reset] while calling [bold]%s[reset]("), callInfo.CalledAs)
+				for i, param := range callInfo.Signature.Params {
+					if i > 0 {
+						buf.WriteString(", ")
+					}
+					buf.WriteString(param.Name)
+				}
+				if param := callInfo.Signature.VariadicParam; param != nil {
+					if len(callInfo.Signature.Params) > 0 {
+						buf.WriteString(", ")
+					}
+					buf.WriteString(param.Name)
+					buf.WriteString("...")
+				}
+				buf.WriteString(")\n")
+			}
+			for _, value := range values {
+				fmt.Fprintf(buf, color.Color("    [dark_gray]│[reset] [bold]%s[reset] %s\n"), value.Traversal, value.Statement)
+			}
+		}
+	}
+
+	buf.WriteByte('\n')
+}
diff --git a/v1.5.7/internal/command/format/diagnostic_test.go b/v1.5.7/internal/command/format/diagnostic_test.go
new file mode 100644
index 0000000..3bb53bb
--- /dev/null
+++ b/v1.5.7/internal/command/format/diagnostic_test.go
@@ -0,0 +1,948 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package format
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/hcl/v2/hcltest"
+	"github.com/mitchellh/colorstring"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+
+	viewsjson "github.com/hashicorp/terraform/internal/command/views/json"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestDiagnostic(t *testing.T) {
+
+	tests := map[string]struct {
+		Diag interface{}
+		Want string
+	}{
+		"sourceless error": {
+			tfdiags.Sourceless(
+				tfdiags.Error,
+				"A sourceless error",
+				"It has no source references but it does have a pretty long detail that should wrap over multiple lines.",
+			),
+			`[red]╷[reset]
+[red]│[reset] [bold][red]Error: [reset][bold]A sourceless error[reset]
+[red]│[reset]
+[red]│[reset] It has no source references but it
+[red]│[reset] does have a pretty long detail that
+[red]│[reset] should wrap over multiple lines.
+[red]╵[reset]
+`,
+		},
+		"sourceless warning": {
+			tfdiags.Sourceless(
+				tfdiags.Warning,
+				"A sourceless warning",
+				"It has no source references but it does have a pretty long detail that should wrap over multiple lines.",
+			),
+			`[yellow]╷[reset]
+[yellow]│[reset] [bold][yellow]Warning: [reset][bold]A sourceless warning[reset]
+[yellow]│[reset]
+[yellow]│[reset] It has no source references but it
+[yellow]│[reset] does have a pretty long detail that
+[yellow]│[reset] should wrap over multiple lines.
+[yellow]╵[reset]
+`,
+		},
+		"error with source code subject": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Bad bad bad",
+				Detail:   "Whatever shall we do?",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 6, Byte: 5},
+					End:      hcl.Pos{Line: 1, Column: 12, Byte: 11},
+				},
+			},
+			`[red]╷[reset]
+[red]│[reset] [bold][red]Error: [reset][bold]Bad bad bad[reset]
+[red]│[reset]
+[red]│[reset]   on test.tf line 1:
+[red]│[reset]    1: test [underline]source[reset] code
+[red]│[reset]
+[red]│[reset] Whatever shall we do?
+[red]╵[reset]
+`,
+		},
+		"error with source code subject and known expression": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Bad bad bad",
+				Detail:   "Whatever shall we do?",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 6, Byte: 5},
+					End:      hcl.Pos{Line: 1, Column: 12, Byte: 11},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "boop"},
+					hcl.TraverseAttr{Name: "beep"},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"boop": cty.ObjectVal(map[string]cty.Value{
+							"beep": cty.StringVal("blah"),
+						}),
+					},
+				},
+			},
+			`[red]╷[reset]
+[red]│[reset] [bold][red]Error: [reset][bold]Bad bad bad[reset]
+[red]│[reset]
+[red]│[reset]   on test.tf line 1:
+[red]│[reset]    1: test [underline]source[reset] code
+[red]│[reset]     [dark_gray]├────────────────[reset]
+[red]│[reset]     [dark_gray]│[reset] [bold]boop.beep[reset] is "blah"
+[red]│[reset]
+[red]│[reset] Whatever shall we do?
+[red]╵[reset]
+`,
+		},
+		"error with source code subject and expression referring to sensitive value": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Bad bad bad",
+				Detail:   "Whatever shall we do?",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 6, Byte: 5},
+					End:      hcl.Pos{Line: 1, Column: 12, Byte: 11},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "boop"},
+					hcl.TraverseAttr{Name: "beep"},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"boop": cty.ObjectVal(map[string]cty.Value{
+							"beep": cty.StringVal("blah").Mark(marks.Sensitive),
+						}),
+					},
+				},
+				Extra: diagnosticCausedBySensitive(true),
+			},
+			`[red]╷[reset]
+[red]│[reset] [bold][red]Error: [reset][bold]Bad bad bad[reset]
+[red]│[reset]
+[red]│[reset]   on test.tf line 1:
+[red]│[reset]    1: test [underline]source[reset] code
+[red]│[reset]     [dark_gray]├────────────────[reset]
+[red]│[reset]     [dark_gray]│[reset] [bold]boop.beep[reset] has a sensitive value
+[red]│[reset]
+[red]│[reset] Whatever shall we do?
+[red]╵[reset]
+`,
+		},
+		"error with source code subject and unknown string expression": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Bad bad bad",
+				Detail:   "Whatever shall we do?",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 6, Byte: 5},
+					End:      hcl.Pos{Line: 1, Column: 12, Byte: 11},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "boop"},
+					hcl.TraverseAttr{Name: "beep"},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"boop": cty.ObjectVal(map[string]cty.Value{
+							"beep": cty.UnknownVal(cty.String),
+						}),
+					},
+				},
+				Extra: diagnosticCausedByUnknown(true),
+			},
+			`[red]╷[reset]
+[red]│[reset] [bold][red]Error: [reset][bold]Bad bad bad[reset]
+[red]│[reset]
+[red]│[reset]   on test.tf line 1:
+[red]│[reset]    1: test [underline]source[reset] code
+[red]│[reset]     [dark_gray]├────────────────[reset]
+[red]│[reset]     [dark_gray]│[reset] [bold]boop.beep[reset] is a string, known only after apply
+[red]│[reset]
+[red]│[reset] Whatever shall we do?
+[red]╵[reset]
+`,
+		},
+		"error with source code subject and unknown expression of unknown type": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Bad bad bad",
+				Detail:   "Whatever shall we do?",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 6, Byte: 5},
+					End:      hcl.Pos{Line: 1, Column: 12, Byte: 11},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "boop"},
+					hcl.TraverseAttr{Name: "beep"},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"boop": cty.ObjectVal(map[string]cty.Value{
+							"beep": cty.UnknownVal(cty.DynamicPseudoType),
+						}),
+					},
+				},
+				Extra: diagnosticCausedByUnknown(true),
+			},
+			`[red]╷[reset]
+[red]│[reset] [bold][red]Error: [reset][bold]Bad bad bad[reset]
+[red]│[reset]
+[red]│[reset]   on test.tf line 1:
+[red]│[reset]    1: test [underline]source[reset] code
+[red]│[reset]     [dark_gray]├────────────────[reset]
+[red]│[reset]     [dark_gray]│[reset] [bold]boop.beep[reset] will be known only after apply
+[red]│[reset]
+[red]│[reset] Whatever shall we do?
+[red]╵[reset]
+`,
+		},
+		"error with source code subject and function call annotation": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Bad bad bad",
+				Detail:   "Whatever shall we do?",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 6, Byte: 5},
+					End:      hcl.Pos{Line: 1, Column: 12, Byte: 11},
+				},
+				Expression: hcltest.MockExprLiteral(cty.True),
+				EvalContext: &hcl.EvalContext{
+					Functions: map[string]function.Function{
+						"beep": function.New(&function.Spec{
+							Params: []function.Parameter{
+								{
+									Name: "pos_param_0",
+									Type: cty.String,
+								},
+								{
+									Name: "pos_param_1",
+									Type: cty.Number,
+								},
+							},
+							VarParam: &function.Parameter{
+								Name: "var_param",
+								Type: cty.Bool,
+							},
+						}),
+					},
+				},
+				// This is simulating what the HCL function call expression
+				// type would generate on evaluation, by implementing the
+				// same interface it uses.
+				Extra: fakeDiagFunctionCallExtra("beep"),
+			},
+			`[red]╷[reset]
+[red]│[reset] [bold][red]Error: [reset][bold]Bad bad bad[reset]
+[red]│[reset]
+[red]│[reset]   on test.tf line 1:
+[red]│[reset]    1: test [underline]source[reset] code
+[red]│[reset]     [dark_gray]├────────────────[reset]
+[red]│[reset]     [dark_gray]│[reset] while calling [bold]beep[reset](pos_param_0, pos_param_1, var_param...)
+[red]│[reset]
+[red]│[reset] Whatever shall we do?
+[red]╵[reset]
+`,
+		},
+	}
+
+	sources := map[string][]byte{
+		"test.tf": []byte(`test source code`),
+	}
+
+	// This empty Colorize just passes through all of the formatting codes
+	// untouched, because it doesn't define any formatting keywords.
+	colorize := &colorstring.Colorize{}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			var diags tfdiags.Diagnostics
+			diags = diags.Append(test.Diag) // to normalize it into a tfdiag.Diagnostic
+			diag := diags[0]
+			got := strings.TrimSpace(Diagnostic(diag, sources, colorize, 40))
+			want := strings.TrimSpace(test.Want)
+			if got != want {
+				t.Errorf("wrong result\ngot:\n%s\n\nwant:\n%s\n\n", got, want)
+			}
+		})
+	}
+}
+
+func TestDiagnosticPlain(t *testing.T) {
+
+	tests := map[string]struct {
+		Diag interface{}
+		Want string
+	}{
+		"sourceless error": {
+			tfdiags.Sourceless(
+				tfdiags.Error,
+				"A sourceless error",
+				"It has no source references but it does have a pretty long detail that should wrap over multiple lines.",
+			),
+			`
+Error: A sourceless error
+
+It has no source references but it does
+have a pretty long detail that should
+wrap over multiple lines.
+`,
+		},
+		"sourceless warning": {
+			tfdiags.Sourceless(
+				tfdiags.Warning,
+				"A sourceless warning",
+				"It has no source references but it does have a pretty long detail that should wrap over multiple lines.",
+			),
+			`
+Warning: A sourceless warning
+
+It has no source references but it does
+have a pretty long detail that should
+wrap over multiple lines.
+`,
+		},
+		"error with source code subject": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Bad bad bad",
+				Detail:   "Whatever shall we do?",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 6, Byte: 5},
+					End:      hcl.Pos{Line: 1, Column: 12, Byte: 11},
+				},
+			},
+			`
+Error: Bad bad bad
+
+  on test.tf line 1:
+   1: test source code
+
+Whatever shall we do?
+`,
+		},
+		"error with source code subject and known expression": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Bad bad bad",
+				Detail:   "Whatever shall we do?",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 6, Byte: 5},
+					End:      hcl.Pos{Line: 1, Column: 12, Byte: 11},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "boop"},
+					hcl.TraverseAttr{Name: "beep"},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"boop": cty.ObjectVal(map[string]cty.Value{
+							"beep": cty.StringVal("blah"),
+						}),
+					},
+				},
+			},
+			`
+Error: Bad bad bad
+
+  on test.tf line 1:
+   1: test source code
+    ├────────────────
+    │ boop.beep is "blah"
+
+Whatever shall we do?
+`,
+		},
+		"error with source code subject and expression referring to sensitive value": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Bad bad bad",
+				Detail:   "Whatever shall we do?",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 6, Byte: 5},
+					End:      hcl.Pos{Line: 1, Column: 12, Byte: 11},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "boop"},
+					hcl.TraverseAttr{Name: "beep"},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"boop": cty.ObjectVal(map[string]cty.Value{
+							"beep": cty.StringVal("blah").Mark(marks.Sensitive),
+						}),
+					},
+				},
+				Extra: diagnosticCausedBySensitive(true),
+			},
+			`
+Error: Bad bad bad
+
+  on test.tf line 1:
+   1: test source code
+    ├────────────────
+    │ boop.beep has a sensitive value
+
+Whatever shall we do?
+`,
+		},
+		"error with source code subject and expression referring to sensitive value when not related to sensitivity": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Bad bad bad",
+				Detail:   "Whatever shall we do?",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 6, Byte: 5},
+					End:      hcl.Pos{Line: 1, Column: 12, Byte: 11},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "boop"},
+					hcl.TraverseAttr{Name: "beep"},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"boop": cty.ObjectVal(map[string]cty.Value{
+							"beep": cty.StringVal("blah").Mark(marks.Sensitive),
+						}),
+					},
+				},
+			},
+			`
+Error: Bad bad bad
+
+  on test.tf line 1:
+   1: test source code
+
+Whatever shall we do?
+`,
+		},
+		"error with source code subject and unknown string expression": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Bad bad bad",
+				Detail:   "Whatever shall we do?",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 6, Byte: 5},
+					End:      hcl.Pos{Line: 1, Column: 12, Byte: 11},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "boop"},
+					hcl.TraverseAttr{Name: "beep"},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"boop": cty.ObjectVal(map[string]cty.Value{
+							"beep": cty.UnknownVal(cty.String),
+						}),
+					},
+				},
+				Extra: diagnosticCausedByUnknown(true),
+			},
+			`
+Error: Bad bad bad
+
+  on test.tf line 1:
+   1: test source code
+    ├────────────────
+    │ boop.beep is a string, known only after apply
+
+Whatever shall we do?
+`,
+		},
+		"error with source code subject and unknown string expression when problem isn't unknown-related": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Bad bad bad",
+				Detail:   "Whatever shall we do?",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 6, Byte: 5},
+					End:      hcl.Pos{Line: 1, Column: 12, Byte: 11},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "boop"},
+					hcl.TraverseAttr{Name: "beep"},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"boop": cty.ObjectVal(map[string]cty.Value{
+							"beep": cty.UnknownVal(cty.String),
+						}),
+					},
+				},
+			},
+			`
+Error: Bad bad bad
+
+  on test.tf line 1:
+   1: test source code
+    ├────────────────
+    │ boop.beep is a string
+
+Whatever shall we do?
+`,
+		},
+		"error with source code subject and unknown expression of unknown type": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Bad bad bad",
+				Detail:   "Whatever shall we do?",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 6, Byte: 5},
+					End:      hcl.Pos{Line: 1, Column: 12, Byte: 11},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "boop"},
+					hcl.TraverseAttr{Name: "beep"},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"boop": cty.ObjectVal(map[string]cty.Value{
+							"beep": cty.UnknownVal(cty.DynamicPseudoType),
+						}),
+					},
+				},
+				Extra: diagnosticCausedByUnknown(true),
+			},
+			`
+Error: Bad bad bad
+
+  on test.tf line 1:
+   1: test source code
+    ├────────────────
+    │ boop.beep will be known only after apply
+
+Whatever shall we do?
+`,
+		},
+		"error with source code subject and unknown expression of unknown type when problem isn't unknown-related": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Bad bad bad",
+				Detail:   "Whatever shall we do?",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 6, Byte: 5},
+					End:      hcl.Pos{Line: 1, Column: 12, Byte: 11},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "boop"},
+					hcl.TraverseAttr{Name: "beep"},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"boop": cty.ObjectVal(map[string]cty.Value{
+							"beep": cty.UnknownVal(cty.DynamicPseudoType),
+						}),
+					},
+				},
+			},
+			`
+Error: Bad bad bad
+
+  on test.tf line 1:
+   1: test source code
+
+Whatever shall we do?
+`,
+		},
+	}
+
+	sources := map[string][]byte{
+		"test.tf": []byte(`test source code`),
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			var diags tfdiags.Diagnostics
+			diags = diags.Append(test.Diag) // to normalize it into a tfdiag.Diagnostic
+			diag := diags[0]
+			got := strings.TrimSpace(DiagnosticPlain(diag, sources, 40))
+			want := strings.TrimSpace(test.Want)
+			if got != want {
+				t.Errorf("wrong result\ngot:\n%s\n\nwant:\n%s\n\n", got, want)
+			}
+		})
+	}
+}
+
+func TestDiagnosticWarningsCompact(t *testing.T) {
+	var diags tfdiags.Diagnostics
+	diags = diags.Append(tfdiags.SimpleWarning("foo"))
+	diags = diags.Append(tfdiags.SimpleWarning("foo"))
+	diags = diags.Append(tfdiags.SimpleWarning("bar"))
+	diags = diags.Append(&hcl.Diagnostic{
+		Severity: hcl.DiagWarning,
+		Summary:  "source foo",
+		Detail:   "...",
+		Subject: &hcl.Range{
+			Filename: "source.tf",
+			Start:    hcl.Pos{Line: 2, Column: 1, Byte: 5},
+			End:      hcl.Pos{Line: 2, Column: 1, Byte: 5},
+		},
+	})
+	diags = diags.Append(&hcl.Diagnostic{
+		Severity: hcl.DiagWarning,
+		Summary:  "source foo",
+		Detail:   "...",
+		Subject: &hcl.Range{
+			Filename: "source.tf",
+			Start:    hcl.Pos{Line: 3, Column: 1, Byte: 7},
+			End:      hcl.Pos{Line: 3, Column: 1, Byte: 7},
+		},
+	})
+	diags = diags.Append(&hcl.Diagnostic{
+		Severity: hcl.DiagWarning,
+		Summary:  "source bar",
+		Detail:   "...",
+		Subject: &hcl.Range{
+			Filename: "source2.tf",
+			Start:    hcl.Pos{Line: 1, Column: 1, Byte: 1},
+			End:      hcl.Pos{Line: 1, Column: 1, Byte: 1},
+		},
+	})
+
+	// ConsolidateWarnings groups together the ones
+	// that have source location information and that
+	// have the same summary text.
+	diags = diags.ConsolidateWarnings(1)
+
+	// A zero-value Colorize just passes all the formatting
+	// codes back to us, so we can test them literally.
+	got := DiagnosticWarningsCompact(diags, &colorstring.Colorize{})
+	want := `[bold][yellow]Warnings:[reset]
+
+- foo
+- foo
+- bar
+- source foo
+  on source.tf line 2 (and 1 more)
+- source bar
+  on source2.tf line 1
+`
+	if got != want {
+		t.Errorf(
+			"wrong result\ngot:\n%s\n\nwant:\n%s\n\ndiff:\n%s",
+			got, want, cmp.Diff(want, got),
+		)
+	}
+}
+
+// Test case via https://github.com/hashicorp/terraform/issues/21359
+func TestDiagnostic_nonOverlappingHighlightContext(t *testing.T) {
+	var diags tfdiags.Diagnostics
+
+	diags = diags.Append(&hcl.Diagnostic{
+		Severity: hcl.DiagError,
+		Summary:  "Some error",
+		Detail:   "...",
+		Subject: &hcl.Range{
+			Filename: "source.tf",
+			Start:    hcl.Pos{Line: 1, Column: 5, Byte: 5},
+			End:      hcl.Pos{Line: 1, Column: 5, Byte: 5},
+		},
+		Context: &hcl.Range{
+			Filename: "source.tf",
+			Start:    hcl.Pos{Line: 1, Column: 5, Byte: 5},
+			End:      hcl.Pos{Line: 4, Column: 2, Byte: 60},
+		},
+	})
+	sources := map[string][]byte{
+		"source.tf": []byte(`x = somefunc("testing", {
+  alpha = "foo"
+  beta  = "bar"
+})
+`),
+	}
+	color := &colorstring.Colorize{
+		Colors:  colorstring.DefaultColors,
+		Reset:   true,
+		Disable: true,
+	}
+	expected := `╷
+│ Error: Some error
+│
+│   on source.tf line 1:
+│    1: x = somefunc("testing", {
+│    2:   alpha = "foo"
+│    3:   beta  = "bar"
+│    4: })
+│
+│ ...
+╵
+`
+	output := Diagnostic(diags[0], sources, color, 80)
+
+	if output != expected {
+		t.Fatalf("unexpected output: got:\n%s\nwant\n%s\n", output, expected)
+	}
+}
+
+func TestDiagnostic_emptyOverlapHighlightContext(t *testing.T) {
+	var diags tfdiags.Diagnostics
+
+	diags = diags.Append(&hcl.Diagnostic{
+		Severity: hcl.DiagError,
+		Summary:  "Some error",
+		Detail:   "...",
+		Subject: &hcl.Range{
+			Filename: "source.tf",
+			Start:    hcl.Pos{Line: 3, Column: 10, Byte: 38},
+			End:      hcl.Pos{Line: 4, Column: 1, Byte: 39},
+		},
+		Context: &hcl.Range{
+			Filename: "source.tf",
+			Start:    hcl.Pos{Line: 2, Column: 13, Byte: 27},
+			End:      hcl.Pos{Line: 4, Column: 1, Byte: 39},
+		},
+	})
+	sources := map[string][]byte{
+		"source.tf": []byte(`variable "x" {
+  default = {
+    "foo"
+  }
+`),
+	}
+	color := &colorstring.Colorize{
+		Colors:  colorstring.DefaultColors,
+		Reset:   true,
+		Disable: true,
+	}
+	expected := `╷
+│ Error: Some error
+│
+│   on source.tf line 3, in variable "x":
+│    2:   default = {
+│    3:     "foo"
+│    4:   }
+│
+│ ...
+╵
+`
+	output := Diagnostic(diags[0], sources, color, 80)
+
+	if output != expected {
+		t.Fatalf("unexpected output: got:\n%s\nwant\n%s\n", output, expected)
+	}
+}
+
+func TestDiagnosticPlain_emptyOverlapHighlightContext(t *testing.T) {
+	var diags tfdiags.Diagnostics
+
+	diags = diags.Append(&hcl.Diagnostic{
+		Severity: hcl.DiagError,
+		Summary:  "Some error",
+		Detail:   "...",
+		Subject: &hcl.Range{
+			Filename: "source.tf",
+			Start:    hcl.Pos{Line: 3, Column: 10, Byte: 38},
+			End:      hcl.Pos{Line: 4, Column: 1, Byte: 39},
+		},
+		Context: &hcl.Range{
+			Filename: "source.tf",
+			Start:    hcl.Pos{Line: 2, Column: 13, Byte: 27},
+			End:      hcl.Pos{Line: 4, Column: 1, Byte: 39},
+		},
+	})
+	sources := map[string][]byte{
+		"source.tf": []byte(`variable "x" {
+  default = {
+    "foo"
+  }
+`),
+	}
+
+	expected := `
+Error: Some error
+
+  on source.tf line 3, in variable "x":
+   2:   default = {
+   3:     "foo"
+   4:   }
+
+...
+`
+	output := DiagnosticPlain(diags[0], sources, 80)
+
+	if output != expected {
+		t.Fatalf("unexpected output: got:\n%s\nwant\n%s\n", output, expected)
+	}
+}
+
+func TestDiagnostic_wrapDetailIncludingCommand(t *testing.T) {
+	var diags tfdiags.Diagnostics
+
+	diags = diags.Append(&hcl.Diagnostic{
+		Severity: hcl.DiagError,
+		Summary:  "Everything went wrong",
+		Detail:   "This is a very long sentence about whatever went wrong which is supposed to wrap onto multiple lines. Thank-you very much for listening.\n\nTo fix this, run this very long command:\n  terraform read-my-mind -please -thanks -but-do-not-wrap-this-line-because-it-is-prefixed-with-spaces\n\nHere is a coda which is also long enough to wrap and so it should eventually make it onto multiple lines. THE END",
+	})
+	color := &colorstring.Colorize{
+		Colors:  colorstring.DefaultColors,
+		Reset:   true,
+		Disable: true,
+	}
+	expected := `╷
+│ Error: Everything went wrong
+│
+│ This is a very long sentence about whatever went wrong which is supposed
+│ to wrap onto multiple lines. Thank-you very much for listening.
+│
+│ To fix this, run this very long command:
+│   terraform read-my-mind -please -thanks -but-do-not-wrap-this-line-because-it-is-prefixed-with-spaces
+│
+│ Here is a coda which is also long enough to wrap and so it should
+│ eventually make it onto multiple lines. THE END
+╵
+`
+	output := Diagnostic(diags[0], nil, color, 76)
+
+	if output != expected {
+		t.Fatalf("unexpected output: got:\n%s\nwant\n%s\n", output, expected)
+	}
+}
+
+func TestDiagnosticPlain_wrapDetailIncludingCommand(t *testing.T) {
+	var diags tfdiags.Diagnostics
+
+	diags = diags.Append(&hcl.Diagnostic{
+		Severity: hcl.DiagError,
+		Summary:  "Everything went wrong",
+		Detail:   "This is a very long sentence about whatever went wrong which is supposed to wrap onto multiple lines. Thank-you very much for listening.\n\nTo fix this, run this very long command:\n  terraform read-my-mind -please -thanks -but-do-not-wrap-this-line-because-it-is-prefixed-with-spaces\n\nHere is a coda which is also long enough to wrap and so it should eventually make it onto multiple lines. THE END",
+	})
+
+	expected := `
+Error: Everything went wrong
+
+This is a very long sentence about whatever went wrong which is supposed to
+wrap onto multiple lines. Thank-you very much for listening.
+
+To fix this, run this very long command:
+  terraform read-my-mind -please -thanks -but-do-not-wrap-this-line-because-it-is-prefixed-with-spaces
+
+Here is a coda which is also long enough to wrap and so it should
+eventually make it onto multiple lines. THE END
+`
+	output := DiagnosticPlain(diags[0], nil, 76)
+
+	if output != expected {
+		t.Fatalf("unexpected output: got:\n%s\nwant\n%s\n", output, expected)
+	}
+}
+
+// Test cases covering invalid JSON diagnostics which should still render
+// correctly. These JSON diagnostic values cannot be generated from the
+// json.NewDiagnostic code path, but we may read and display JSON diagnostics
+// in future from other sources.
+func TestDiagnosticFromJSON_invalid(t *testing.T) {
+	tests := map[string]struct {
+		Diag *viewsjson.Diagnostic
+		Want string
+	}{
+		"zero-value end range and highlight end byte": {
+			&viewsjson.Diagnostic{
+				Severity: viewsjson.DiagnosticSeverityError,
+				Summary:  "Bad end",
+				Detail:   "It all went wrong.",
+				Range: &viewsjson.DiagnosticRange{
+					Filename: "ohno.tf",
+					Start:    viewsjson.Pos{Line: 1, Column: 23, Byte: 22},
+					End:      viewsjson.Pos{Line: 0, Column: 0, Byte: 0},
+				},
+				Snippet: &viewsjson.DiagnosticSnippet{
+					Code:                 `resource "foo_bar "baz" {`,
+					StartLine:            1,
+					HighlightStartOffset: 22,
+					HighlightEndOffset:   0,
+				},
+			},
+			`[red]╷[reset]
+[red]│[reset] [bold][red]Error: [reset][bold]Bad end[reset]
+[red]│[reset]
+[red]│[reset]   on ohno.tf line 1:
+[red]│[reset]    1: resource "foo_bar "baz[underline]"[reset] {
+[red]│[reset]
+[red]│[reset] It all went wrong.
+[red]╵[reset]
+`,
+		},
+	}
+
+	// This empty Colorize just passes through all of the formatting codes
+	// untouched, because it doesn't define any formatting keywords.
+	colorize := &colorstring.Colorize{}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got := strings.TrimSpace(DiagnosticFromJSON(test.Diag, colorize, 40))
+			want := strings.TrimSpace(test.Want)
+			if got != want {
+				t.Errorf("wrong result\ngot:\n%s\n\nwant:\n%s\n\n", got, want)
+			}
+		})
+	}
+}
+
+// fakeDiagFunctionCallExtra is a fake implementation of the interface that
+// HCL uses to provide "extra information" associated with diagnostics that
+// describe errors during a function call.
+type fakeDiagFunctionCallExtra string
+
+var _ hclsyntax.FunctionCallDiagExtra = fakeDiagFunctionCallExtra("")
+
+func (e fakeDiagFunctionCallExtra) CalledFunctionName() string {
+	return string(e)
+}
+
+func (e fakeDiagFunctionCallExtra) FunctionCallError() error {
+	return nil
+}
+
+// diagnosticCausedByUnknown is a testing helper for exercising our logic
+// for selectively showing unknown values alongside our source snippets for
+// diagnostics that are explicitly marked as being caused by unknown values.
+type diagnosticCausedByUnknown bool
+
+var _ tfdiags.DiagnosticExtraBecauseUnknown = diagnosticCausedByUnknown(true)
+
+func (e diagnosticCausedByUnknown) DiagnosticCausedByUnknown() bool {
+	return bool(e)
+}
+
+// diagnosticCausedBySensitive is a testing helper for exercising our logic
+// for selectively showing sensitive values alongside our source snippets for
+// diagnostics that are explicitly marked as being caused by sensitive values.
+type diagnosticCausedBySensitive bool
+
+var _ tfdiags.DiagnosticExtraBecauseSensitive = diagnosticCausedBySensitive(true)
+
+func (e diagnosticCausedBySensitive) DiagnosticCausedBySensitive() bool {
+	return bool(e)
+}
diff --git a/v1.5.7/internal/command/format/format.go b/v1.5.7/internal/command/format/format.go
new file mode 100644
index 0000000..52496f0
--- /dev/null
+++ b/v1.5.7/internal/command/format/format.go
@@ -0,0 +1,38 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package format contains helpers for formatting various Terraform
+// structures for human-readabout output.
+//
+// This package is used by the official Terraform CLI in formatting any
+// output and is exported to encourage non-official frontends to mimic the
+// output formatting as much as possible so that text formats of Terraform
+// structures have a consistent look and feel.
+package format
+
+import "github.com/hashicorp/terraform/internal/plans"
+
+// DiffActionSymbol returns a string that, once passed through a
+// colorstring.Colorize, will produce a result that can be written
+// to a terminal to produce a symbol made of three printable
+// characters, possibly interspersed with VT100 color codes.
+func DiffActionSymbol(action plans.Action) string {
+	switch action {
+	case plans.DeleteThenCreate:
+		return "[red]-[reset]/[green]+[reset]"
+	case plans.CreateThenDelete:
+		return "[green]+[reset]/[red]-[reset]"
+	case plans.Create:
+		return "  [green]+[reset]"
+	case plans.Delete:
+		return "  [red]-[reset]"
+	case plans.Read:
+		return " [cyan]<=[reset]"
+	case plans.Update:
+		return "  [yellow]~[reset]"
+	case plans.NoOp:
+		return "   "
+	default:
+		return "  ?"
+	}
+}
diff --git a/v1.5.7/internal/command/format/object_id.go b/v1.5.7/internal/command/format/object_id.go
new file mode 100644
index 0000000..b51c33c
--- /dev/null
+++ b/v1.5.7/internal/command/format/object_id.go
@@ -0,0 +1,153 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package format
+
+import (
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// ObjectValueID takes a value that is assumed to be an object representation
+// of some resource instance object and attempts to heuristically find an
+// attribute of it that is likely to be a unique identifier in the remote
+// system that it belongs to which will be useful to the user.
+//
+// If such an attribute is found, its name and string value intended for
+// display are returned. Both returned strings are empty if no such attribute
+// exists, in which case the caller should assume that the resource instance
+// address within the Terraform configuration is the best available identifier.
+//
+// This is only a best-effort sort of thing, relying on naming conventions in
+// our resource type schemas. The result is not guaranteed to be unique, but
+// should generally be suitable for display to an end-user anyway.
+//
+// This function will panic if the given value is not of an object type.
+func ObjectValueID(obj cty.Value) (k, v string) {
+	if obj.IsNull() || !obj.IsKnown() {
+		return "", ""
+	}
+
+	atys := obj.Type().AttributeTypes()
+
+	switch {
+
+	case atys["id"] == cty.String:
+		v := obj.GetAttr("id")
+		if v.HasMark(marks.Sensitive) {
+			break
+		}
+		v, _ = v.Unmark()
+
+		if v.IsKnown() && !v.IsNull() {
+			return "id", v.AsString()
+		}
+
+	case atys["name"] == cty.String:
+		// "name" isn't always globally unique, but if there isn't also an
+		// "id" then it _often_ is, in practice.
+		v := obj.GetAttr("name")
+		if v.HasMark(marks.Sensitive) {
+			break
+		}
+		v, _ = v.Unmark()
+
+		if v.IsKnown() && !v.IsNull() {
+			return "name", v.AsString()
+		}
+	}
+
+	return "", ""
+}
+
+// ObjectValueName takes a value that is assumed to be an object representation
+// of some resource instance object and attempts to heuristically find an
+// attribute of it that is likely to be a human-friendly name in the remote
+// system that it belongs to which will be useful to the user.
+//
+// If such an attribute is found, its name and string value intended for
+// display are returned. Both returned strings are empty if no such attribute
+// exists, in which case the caller should assume that the resource instance
+// address within the Terraform configuration is the best available identifier.
+//
+// This is only a best-effort sort of thing, relying on naming conventions in
+// our resource type schemas. The result is not guaranteed to be unique, but
+// should generally be suitable for display to an end-user anyway.
+//
+// Callers that use both ObjectValueName and ObjectValueID at the same time
+// should be prepared to get the same attribute key and value from both in
+// some cases, since there is overlap betweek the id-extraction and
+// name-extraction heuristics.
+//
+// This function will panic if the given value is not of an object type.
+func ObjectValueName(obj cty.Value) (k, v string) {
+	if obj.IsNull() || !obj.IsKnown() {
+		return "", ""
+	}
+
+	atys := obj.Type().AttributeTypes()
+
+	switch {
+
+	case atys["name"] == cty.String:
+		v := obj.GetAttr("name")
+		if v.HasMark(marks.Sensitive) {
+			break
+		}
+		v, _ = v.Unmark()
+
+		if v.IsKnown() && !v.IsNull() {
+			return "name", v.AsString()
+		}
+
+	case atys["tags"].IsMapType() && atys["tags"].ElementType() == cty.String:
+		tags := obj.GetAttr("tags")
+		if tags.IsNull() || !tags.IsWhollyKnown() || tags.HasMark(marks.Sensitive) {
+			break
+		}
+		tags, _ = tags.Unmark()
+
+		switch {
+		case tags.HasIndex(cty.StringVal("name")).RawEquals(cty.True):
+			v := tags.Index(cty.StringVal("name"))
+			if v.HasMark(marks.Sensitive) {
+				break
+			}
+			v, _ = v.Unmark()
+
+			if v.IsKnown() && !v.IsNull() {
+				return "tags.name", v.AsString()
+			}
+		case tags.HasIndex(cty.StringVal("Name")).RawEquals(cty.True):
+			// AWS-style naming convention
+			v := tags.Index(cty.StringVal("Name"))
+			if v.HasMark(marks.Sensitive) {
+				break
+			}
+			v, _ = v.Unmark()
+
+			if v.IsKnown() && !v.IsNull() {
+				return "tags.Name", v.AsString()
+			}
+		}
+	}
+
+	return "", ""
+}
+
+// ObjectValueIDOrName is a convenience wrapper around both ObjectValueID
+// and ObjectValueName (in that preference order) to try to extract some sort
+// of human-friendly descriptive string value for an object as additional
+// context about an object when it is being displayed in a compact way (where
+// not all of the attributes are visible.)
+//
+// Just as with the two functions it wraps, it is a best-effort and may return
+// two empty strings if no suitable attribute can be found for a given object.
+func ObjectValueIDOrName(obj cty.Value) (k, v string) {
+	k, v = ObjectValueID(obj)
+	if k != "" {
+		return
+	}
+	k, v = ObjectValueName(obj)
+	return
+}
diff --git a/v1.5.7/internal/command/format/object_id_test.go b/v1.5.7/internal/command/format/object_id_test.go
new file mode 100644
index 0000000..42eecc7
--- /dev/null
+++ b/v1.5.7/internal/command/format/object_id_test.go
@@ -0,0 +1,216 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package format
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestObjectValueIDOrName(t *testing.T) {
+	tests := []struct {
+		obj    cty.Value
+		id     [2]string
+		name   [2]string
+		either [2]string
+	}{
+		{
+			cty.NullVal(cty.EmptyObject),
+			[...]string{"", ""},
+			[...]string{"", ""},
+			[...]string{"", ""},
+		},
+		{
+			cty.UnknownVal(cty.EmptyObject),
+			[...]string{"", ""},
+			[...]string{"", ""},
+			[...]string{"", ""},
+		},
+		{
+			cty.EmptyObjectVal,
+			[...]string{"", ""},
+			[...]string{"", ""},
+			[...]string{"", ""},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("foo-123"),
+			}),
+			[...]string{"id", "foo-123"},
+			[...]string{"", ""},
+			[...]string{"id", "foo-123"},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.StringVal("foo-123"),
+				"name": cty.StringVal("awesome-foo"),
+			}),
+			[...]string{"id", "foo-123"},
+			[...]string{"name", "awesome-foo"},
+			[...]string{"id", "foo-123"},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("awesome-foo"),
+			}),
+			[...]string{"name", "awesome-foo"},
+			[...]string{"name", "awesome-foo"},
+			[...]string{"name", "awesome-foo"},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("awesome-foo").Mark(marks.Sensitive),
+			}),
+			[...]string{"", ""},
+			[...]string{"", ""},
+			[...]string{"", ""},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("awesome-foo"),
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.StringVal("My Awesome Foo"),
+				}),
+			}),
+			[...]string{"name", "awesome-foo"},
+			[...]string{"name", "awesome-foo"},
+			[...]string{"name", "awesome-foo"},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.StringVal("My Awesome Foo"),
+					"name": cty.StringVal("awesome-foo"),
+				}),
+			}),
+			[...]string{"", ""},
+			[...]string{"tags.name", "awesome-foo"},
+			[...]string{"tags.name", "awesome-foo"},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.StringVal("My Awesome Foo"),
+				}),
+			}),
+			[...]string{"", ""},
+			[...]string{"tags.Name", "My Awesome Foo"},
+			[...]string{"tags.Name", "My Awesome Foo"},
+		},
+
+		// The following are degenerate cases, included to make sure we don't
+		// crash when we encounter them. If you're here fixing a reported panic
+		// in this formatter, this is the place to add a new test case.
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.True,
+			}),
+			[...]string{"", ""},
+			[...]string{"", ""},
+			[...]string{"", ""},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.NullVal(cty.String),
+			}),
+			[...]string{"", ""},
+			[...]string{"", ""},
+			[...]string{"", ""},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+			}),
+			[...]string{"", ""},
+			[...]string{"", ""},
+			[...]string{"", ""},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"tags": cty.StringVal("foo"),
+			}),
+			[...]string{"", ""},
+			[...]string{"", ""},
+			[...]string{"", ""},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"tags": cty.NullVal(cty.Map(cty.String)),
+			}),
+			[...]string{"", ""},
+			[...]string{"", ""},
+			[...]string{"", ""},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"tags": cty.UnknownVal(cty.Map(cty.String)),
+			}),
+			[...]string{"", ""},
+			[...]string{"", ""},
+			[...]string{"", ""},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.True,
+				}),
+			}),
+			[...]string{"", ""},
+			[...]string{"", ""},
+			[...]string{"", ""},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.UnknownVal(cty.String),
+				}),
+			}),
+			[...]string{"", ""},
+			[...]string{"", ""},
+			[...]string{"", ""},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.UnknownVal(cty.String).Mark(marks.Sensitive),
+				}),
+			}),
+			[...]string{"", ""},
+			[...]string{"", ""},
+			[...]string{"", ""},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.NullVal(cty.String),
+				}),
+			}),
+			[...]string{"", ""},
+			[...]string{"", ""},
+			[...]string{"", ""},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%#v", test.obj), func(t *testing.T) {
+			obj := test.obj
+			gotIDKey, gotIDVal := ObjectValueID(obj)
+			gotNameKey, gotNameVal := ObjectValueName(obj)
+			gotEitherKey, gotEitherVal := ObjectValueIDOrName(obj)
+
+			if got, want := [...]string{gotIDKey, gotIDVal}, test.id; got != want {
+				t.Errorf("wrong ObjectValueID result\ngot:  %#v\nwant: %#v", got, want)
+			}
+			if got, want := [...]string{gotNameKey, gotNameVal}, test.name; got != want {
+				t.Errorf("wrong ObjectValueName result\ngot:  %#v\nwant: %#v", got, want)
+			}
+			if got, want := [...]string{gotEitherKey, gotEitherVal}, test.either; got != want {
+				t.Errorf("wrong ObjectValueIDOrName result\ngot:  %#v\nwant: %#v", got, want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/format/trivia.go b/v1.5.7/internal/command/format/trivia.go
new file mode 100644
index 0000000..fad9140
--- /dev/null
+++ b/v1.5.7/internal/command/format/trivia.go
@@ -0,0 +1,61 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package format
+
+import (
+	"strings"
+
+	"github.com/mitchellh/colorstring"
+	wordwrap "github.com/mitchellh/go-wordwrap"
+)
+
+// HorizontalRule returns a newline character followed by a number of
+// horizontal line characters to fill the given width.
+//
+// If the given colorize has colors enabled, the rule will also be given a
+// dark grey color to attempt to visually de-emphasize it for sighted users.
+//
+// This is intended for printing to the UI via mitchellh/cli.UI.Output, or
+// similar, which will automatically append a trailing newline too.
+func HorizontalRule(color *colorstring.Colorize, width int) string {
+	if width <= 1 {
+		return "\n"
+	}
+	rule := strings.Repeat("─", width-1)
+	if color == nil { // sometimes unit tests don't populate this properly
+		return "\n" + rule
+	}
+	return color.Color("[dark_gray]\n" + rule)
+}
+
+// WordWrap takes a string containing unbroken lines of text and inserts
+// newline characters to try to make the text fit within the given width.
+//
+// The string can already contain newline characters, for example if you are
+// trying to render multiple paragraphs of text. (In that case, our usual
+// style would be to have _two_ newline characters as the paragraph separator.)
+//
+// As a special case, any line that begins with at least one space will be left
+// unbroken. This allows including literal segments in the output, such as
+// code snippets or filenames, where word wrapping would be confusing.
+func WordWrap(str string, width int) string {
+	if width <= 1 {
+		// Silly edge case. We'll just return the original string to avoid
+		// panicking or doing other weird stuff.
+		return str
+	}
+
+	var buf strings.Builder
+	lines := strings.Split(str, "\n")
+	for i, line := range lines {
+		if !strings.HasPrefix(line, " ") {
+			line = wordwrap.WrapString(line, uint(width-1))
+		}
+		if i > 0 {
+			buf.WriteByte('\n') // reintroduce the newlines we skipped in Scan
+		}
+		buf.WriteString(line)
+	}
+	return buf.String()
+}
diff --git a/v1.5.7/internal/command/get.go b/v1.5.7/internal/command/get.go
new file mode 100644
index 0000000..fc19997
--- /dev/null
+++ b/v1.5.7/internal/command/get.go
@@ -0,0 +1,85 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// GetCommand is a Command implementation that takes a Terraform
+// configuration and downloads all the modules.
+type GetCommand struct {
+	Meta
+}
+
+func (c *GetCommand) Run(args []string) int {
+	var update bool
+
+	args = c.Meta.process(args)
+	cmdFlags := c.Meta.defaultFlagSet("get")
+	cmdFlags.BoolVar(&update, "update", false, "update")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	path, err := ModulePath(cmdFlags.Args())
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	path = c.normalizePath(path)
+
+	abort, diags := getModules(&c.Meta, path, update)
+	c.showDiagnostics(diags)
+	if abort || diags.HasErrors() {
+		return 1
+	}
+
+	return 0
+}
+
+func (c *GetCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] get [options]
+
+  Downloads and installs modules needed for the configuration in the 
+  current working directory.
+
+  This recursively downloads all modules needed, such as modules
+  imported by modules imported by the root and so on. If a module is
+  already downloaded, it will not be redownloaded or checked for updates
+  unless the -update flag is specified.
+
+  Module installation also happens automatically by default as part of
+  the "terraform init" command, so you should rarely need to run this
+  command separately.
+
+Options:
+
+  -update             Check already-downloaded modules for available updates
+                      and install the newest versions available.
+
+  -no-color           Disable text coloring in the output.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *GetCommand) Synopsis() string {
+	return "Install or upgrade remote Terraform modules"
+}
+
+func getModules(m *Meta, path string, upgrade bool) (abort bool, diags tfdiags.Diagnostics) {
+	hooks := uiModuleInstallHooks{
+		Ui:             m.Ui,
+		ShowLocalPaths: true,
+	}
+	return m.installModules(path, upgrade, hooks)
+}
diff --git a/v1.5.7/internal/command/get_test.go b/v1.5.7/internal/command/get_test.go
new file mode 100644
index 0000000..e20cc90
--- /dev/null
+++ b/v1.5.7/internal/command/get_test.go
@@ -0,0 +1,115 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/mitchellh/cli"
+)
+
+func TestGet(t *testing.T) {
+	wd := tempWorkingDirFixture(t, "get")
+	defer testChdir(t, wd.RootModuleDir())()
+
+	ui := cli.NewMockUi()
+	c := &GetCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			WorkingDir:       wd,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	output := ui.OutputWriter.String()
+	if !strings.Contains(output, "- foo in") {
+		t.Fatalf("doesn't look like get: %s", output)
+	}
+}
+
+func TestGet_multipleArgs(t *testing.T) {
+	wd := tempWorkingDir(t)
+	defer testChdir(t, wd.RootModuleDir())()
+
+	ui := cli.NewMockUi()
+	c := &GetCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			WorkingDir:       wd,
+		},
+	}
+
+	args := []string{
+		"bad",
+		"bad",
+	}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad: \n%s", ui.OutputWriter.String())
+	}
+}
+
+func TestGet_update(t *testing.T) {
+	wd := tempWorkingDirFixture(t, "get")
+	defer testChdir(t, wd.RootModuleDir())()
+
+	ui := cli.NewMockUi()
+	c := &GetCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			WorkingDir:       wd,
+		},
+	}
+
+	args := []string{
+		"-update",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	output := ui.OutputWriter.String()
+	if !strings.Contains(output, `- foo in`) {
+		t.Fatalf("doesn't look like get: %s", output)
+	}
+}
+
+func TestGet_cancel(t *testing.T) {
+	// This test runs `terraform get` as if SIGINT (or similar on other
+	// platforms) were sent to it, testing that it is interruptible.
+
+	wd := tempWorkingDirFixture(t, "init-registry-module")
+	defer testChdir(t, wd.RootModuleDir())()
+
+	// Our shutdown channel is pre-closed so init will exit as soon as it
+	// starts a cancelable portion of the process.
+	shutdownCh := make(chan struct{})
+	close(shutdownCh)
+
+	ui := cli.NewMockUi()
+	c := &GetCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			WorkingDir:       wd,
+			ShutdownCh:       shutdownCh,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code == 0 {
+		t.Fatalf("succeeded; wanted error\n%s", ui.OutputWriter.String())
+	}
+
+	if got, want := ui.ErrorWriter.String(), `Module installation was canceled by an interrupt signal`; !strings.Contains(got, want) {
+		t.Fatalf("wrong error message\nshould contain: %s\ngot:\n%s", want, got)
+	}
+}
diff --git a/v1.5.7/internal/command/graph.go b/v1.5.7/internal/command/graph.go
new file mode 100644
index 0000000..f83ad02
--- /dev/null
+++ b/v1.5.7/internal/command/graph.go
@@ -0,0 +1,228 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// GraphCommand is a Command implementation that takes a Terraform
+// configuration and outputs the dependency tree in graphical form.
+type GraphCommand struct {
+	Meta
+}
+
+func (c *GraphCommand) Run(args []string) int {
+	var drawCycles bool
+	var graphTypeStr string
+	var moduleDepth int
+	var verbose bool
+	var planPath string
+
+	args = c.Meta.process(args)
+	cmdFlags := c.Meta.defaultFlagSet("graph")
+	cmdFlags.BoolVar(&drawCycles, "draw-cycles", false, "draw-cycles")
+	cmdFlags.StringVar(&graphTypeStr, "type", "", "type")
+	cmdFlags.IntVar(&moduleDepth, "module-depth", -1, "module-depth")
+	cmdFlags.BoolVar(&verbose, "verbose", false, "verbose")
+	cmdFlags.StringVar(&planPath, "plan", "", "plan")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	configPath, err := ModulePath(cmdFlags.Args())
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	// Check for user-supplied plugin path
+	if c.pluginPath, err = c.loadPluginPath(); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error loading plugin path: %s", err))
+		return 1
+	}
+
+	// Try to load plan if path is specified
+	var planFile *planfile.Reader
+	if planPath != "" {
+		planFile, err = c.PlanFile(planPath)
+		if err != nil {
+			c.Ui.Error(err.Error())
+			return 1
+		}
+	}
+
+	var diags tfdiags.Diagnostics
+
+	backendConfig, backendDiags := c.loadBackendConfig(configPath)
+	diags = diags.Append(backendDiags)
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(&BackendOpts{
+		Config: backendConfig,
+	})
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// We require a local backend
+	local, ok := b.(backend.Local)
+	if !ok {
+		c.showDiagnostics(diags) // in case of any warnings in here
+		c.Ui.Error(ErrUnsupportedLocalOp)
+		return 1
+	}
+
+	// This is a read-only command
+	c.ignoreRemoteVersionConflict(b)
+
+	// Build the operation
+	opReq := c.Operation(b, arguments.ViewHuman)
+	opReq.ConfigDir = configPath
+	opReq.ConfigLoader, err = c.initConfigLoader()
+	opReq.PlanFile = planFile
+	opReq.AllowUnsetVariables = true
+	if err != nil {
+		diags = diags.Append(err)
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Get the context
+	lr, _, ctxDiags := local.LocalRun(opReq)
+	diags = diags.Append(ctxDiags)
+	if ctxDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	if graphTypeStr == "" {
+		switch {
+		case lr.Plan != nil:
+			graphTypeStr = "apply"
+		default:
+			graphTypeStr = "plan"
+		}
+	}
+
+	var g *terraform.Graph
+	var graphDiags tfdiags.Diagnostics
+	switch graphTypeStr {
+	case "plan":
+		g, graphDiags = lr.Core.PlanGraphForUI(lr.Config, lr.InputState, plans.NormalMode)
+	case "plan-refresh-only":
+		g, graphDiags = lr.Core.PlanGraphForUI(lr.Config, lr.InputState, plans.RefreshOnlyMode)
+	case "plan-destroy":
+		g, graphDiags = lr.Core.PlanGraphForUI(lr.Config, lr.InputState, plans.DestroyMode)
+	case "apply":
+		plan := lr.Plan
+
+		// Historically "terraform graph" would allow the nonsensical request to
+		// render an apply graph without a plan, so we continue to support that
+		// here, though perhaps one day this should be an error.
+		if lr.Plan == nil {
+			plan = &plans.Plan{
+				Changes:      plans.NewChanges(),
+				UIMode:       plans.NormalMode,
+				PriorState:   lr.InputState,
+				PrevRunState: lr.InputState,
+			}
+		}
+
+		g, graphDiags = lr.Core.ApplyGraphForUI(plan, lr.Config)
+	case "eval", "validate":
+		// Terraform v0.12 through v1.0 supported both of these, but the
+		// graph variants for "eval" and "validate" are purely implementation
+		// details and don't reveal anything (user-model-wise) that you can't
+		// see in the plan graph.
+		graphDiags = graphDiags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Graph type no longer available",
+			fmt.Sprintf("The graph type %q is no longer available. Use -type=plan instead to get a similar result.", graphTypeStr),
+		))
+	default:
+		graphDiags = graphDiags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Unsupported graph type",
+			`The -type=... argument must be either "plan", "plan-refresh-only", "plan-destroy", or "apply".`,
+		))
+	}
+	diags = diags.Append(graphDiags)
+	if graphDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	graphStr, err := terraform.GraphDot(g, &dag.DotOpts{
+		DrawCycles: drawCycles,
+		MaxDepth:   moduleDepth,
+		Verbose:    verbose,
+	})
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Error converting graph: %s", err))
+		return 1
+	}
+
+	if diags.HasErrors() {
+		// For this command we only show diagnostics if there are errors,
+		// because printing out naked warnings could upset a naive program
+		// consuming our dot output.
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	c.Ui.Output(graphStr)
+
+	return 0
+}
+
+func (c *GraphCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] graph [options]
+
+  Produces a representation of the dependency graph between different
+  objects in the current configuration and state.
+
+  The graph is presented in the DOT language. The typical program that can
+  read this format is GraphViz, but many web services are also available
+  to read this format.
+
+Options:
+
+  -plan=tfplan     Render graph using the specified plan file instead of the
+                   configuration in the current directory.
+
+  -draw-cycles     Highlight any cycles in the graph with colored edges.
+                   This helps when diagnosing cycle errors.
+
+  -type=plan       Type of graph to output. Can be: plan, plan-refresh-only,
+                   plan-destroy, or apply. By default Terraform chooses
+				   "plan", or "apply" if you also set the -plan=... option.
+
+  -module-depth=n  (deprecated) In prior versions of Terraform, specified the
+				   depth of modules to show in the output.
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *GraphCommand) Synopsis() string {
+	return "Generate a Graphviz graph of the steps in an operation"
+}
diff --git a/v1.5.7/internal/command/graph_test.go b/v1.5.7/internal/command/graph_test.go
new file mode 100644
index 0000000..f8f321b
--- /dev/null
+++ b/v1.5.7/internal/command/graph_test.go
@@ -0,0 +1,162 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"os"
+	"strings"
+	"testing"
+
+	"github.com/mitchellh/cli"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestGraph(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("graph"), td)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	c := &GraphCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(applyFixtureProvider()),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	output := ui.OutputWriter.String()
+	if !strings.Contains(output, `provider[\"registry.terraform.io/hashicorp/test\"]`) {
+		t.Fatalf("doesn't look like digraph: %s", output)
+	}
+}
+
+func TestGraph_multipleArgs(t *testing.T) {
+	ui := new(cli.MockUi)
+	c := &GraphCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(applyFixtureProvider()),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{
+		"bad",
+		"bad",
+	}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad: \n%s", ui.OutputWriter.String())
+	}
+}
+
+func TestGraph_noArgs(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("graph"), td)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	c := &GraphCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(applyFixtureProvider()),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	output := ui.OutputWriter.String()
+	if !strings.Contains(output, `provider[\"registry.terraform.io/hashicorp/test\"]`) {
+		t.Fatalf("doesn't look like digraph: %s", output)
+	}
+}
+
+func TestGraph_noConfig(t *testing.T) {
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	c := &GraphCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(applyFixtureProvider()),
+			Ui:               ui,
+		},
+	}
+
+	// Running the graph command without a config should not panic,
+	// but this may be an error at some point in the future.
+	args := []string{"-type", "apply"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+}
+
+func TestGraph_plan(t *testing.T) {
+	testCwd(t)
+
+	plan := &plans.Plan{
+		Changes: plans.NewChanges(),
+	}
+	plan.Changes.Resources = append(plan.Changes.Resources, &plans.ResourceInstanceChangeSrc{
+		Addr: addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: "bar",
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+		ChangeSrc: plans.ChangeSrc{
+			Action: plans.Delete,
+			Before: plans.DynamicValue(`{}`),
+			After:  plans.DynamicValue(`null`),
+		},
+		ProviderAddr: addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	})
+	emptyConfig, err := plans.NewDynamicValue(cty.EmptyObjectVal, cty.EmptyObject)
+	if err != nil {
+		t.Fatal(err)
+	}
+	plan.Backend = plans.Backend{
+		// Doesn't actually matter since we aren't going to activate the backend
+		// for this command anyway, but we need something here for the plan
+		// file writer to succeed.
+		Type:   "placeholder",
+		Config: emptyConfig,
+	}
+	_, configSnap := testModuleWithSnapshot(t, "graph")
+
+	planPath := testPlanFile(t, configSnap, states.NewState(), plan)
+
+	ui := new(cli.MockUi)
+	c := &GraphCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(applyFixtureProvider()),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{
+		"-plan", planPath,
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	output := ui.OutputWriter.String()
+	if !strings.Contains(output, `provider[\"registry.terraform.io/hashicorp/test\"]`) {
+		t.Fatalf("doesn't look like digraph: %s", output)
+	}
+}
diff --git a/v1.5.7/internal/command/helper.go b/v1.5.7/internal/command/helper.go
new file mode 100644
index 0000000..afd382f
--- /dev/null
+++ b/v1.5.7/internal/command/helper.go
@@ -0,0 +1,31 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/cloud"
+)
+
+const failedToLoadSchemasMessage = `
+Warning: Failed to update data for external integrations
+
+Terraform was unable to generate a description of the updated
+state for use with external integrations in Terraform Cloud.
+Any integrations configured for this workspace which depend on
+information from the state may not work correctly when using the
+result of this action.
+
+This problem occurs when Terraform cannot read the schema for
+one or more of the providers used in the state. The next successful
+apply will correct the problem by re-generating the JSON description
+of the state:
+    terraform apply
+`
+
+func isCloudMode(b backend.Enhanced) bool {
+	_, ok := b.(*cloud.Cloud)
+
+	return ok
+}
diff --git a/v1.5.7/internal/command/hook_module_install.go b/v1.5.7/internal/command/hook_module_install.go
new file mode 100644
index 0000000..19687fd
--- /dev/null
+++ b/v1.5.7/internal/command/hook_module_install.go
@@ -0,0 +1,36 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/mitchellh/cli"
+)
+
+type uiModuleInstallHooks struct {
+	initwd.ModuleInstallHooksImpl
+	Ui             cli.Ui
+	ShowLocalPaths bool
+}
+
+var _ initwd.ModuleInstallHooks = uiModuleInstallHooks{}
+
+func (h uiModuleInstallHooks) Download(modulePath, packageAddr string, v *version.Version) {
+	if v != nil {
+		h.Ui.Info(fmt.Sprintf("Downloading %s %s for %s...", packageAddr, v, modulePath))
+	} else {
+		h.Ui.Info(fmt.Sprintf("Downloading %s for %s...", packageAddr, modulePath))
+	}
+}
+
+func (h uiModuleInstallHooks) Install(modulePath string, v *version.Version, localDir string) {
+	if h.ShowLocalPaths {
+		h.Ui.Info(fmt.Sprintf("- %s in %s", modulePath, localDir))
+	} else {
+		h.Ui.Info(fmt.Sprintf("- %s", modulePath))
+	}
+}
diff --git a/v1.5.7/internal/command/import.go b/v1.5.7/internal/command/import.go
new file mode 100644
index 0000000..e79054b
--- /dev/null
+++ b/v1.5.7/internal/command/import.go
@@ -0,0 +1,359 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"errors"
+	"fmt"
+	"log"
+	"os"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ImportCommand is a cli.Command implementation that imports resources
+// into the Terraform state.
+type ImportCommand struct {
+	Meta
+}
+
+func (c *ImportCommand) Run(args []string) int {
+	// Get the pwd since its our default -config flag value
+	pwd, err := os.Getwd()
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Error getting pwd: %s", err))
+		return 1
+	}
+
+	var configPath string
+	args = c.Meta.process(args)
+
+	cmdFlags := c.Meta.extendedFlagSet("import")
+	cmdFlags.BoolVar(&c.ignoreRemoteVersion, "ignore-remote-version", false, "continue even if remote and local Terraform versions are incompatible")
+	cmdFlags.IntVar(&c.Meta.parallelism, "parallelism", DefaultParallelism, "parallelism")
+	cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path")
+	cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
+	cmdFlags.StringVar(&c.Meta.backupPath, "backup", "", "path")
+	cmdFlags.StringVar(&configPath, "config", pwd, "path")
+	cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
+	cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		return 1
+	}
+
+	args = cmdFlags.Args()
+	if len(args) != 2 {
+		c.Ui.Error("The import command expects two arguments.")
+		cmdFlags.Usage()
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	// Parse the provided resource address.
+	traversalSrc := []byte(args[0])
+	traversal, travDiags := hclsyntax.ParseTraversalAbs(traversalSrc, "<import-address>", hcl.Pos{Line: 1, Column: 1})
+	diags = diags.Append(travDiags)
+	if travDiags.HasErrors() {
+		c.registerSynthConfigSource("<import-address>", traversalSrc) // so we can include a source snippet
+		c.showDiagnostics(diags)
+		c.Ui.Info(importCommandInvalidAddressReference)
+		return 1
+	}
+	addr, addrDiags := addrs.ParseAbsResourceInstance(traversal)
+	diags = diags.Append(addrDiags)
+	if addrDiags.HasErrors() {
+		c.registerSynthConfigSource("<import-address>", traversalSrc) // so we can include a source snippet
+		c.showDiagnostics(diags)
+		c.Ui.Info(importCommandInvalidAddressReference)
+		return 1
+	}
+
+	if addr.Resource.Resource.Mode != addrs.ManagedResourceMode {
+		diags = diags.Append(errors.New("A managed resource address is required. Importing into a data resource is not allowed."))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	if !c.dirIsConfigPath(configPath) {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "No Terraform configuration files",
+			Detail: fmt.Sprintf(
+				"The directory %s does not contain any Terraform configuration files (.tf or .tf.json). To specify a different configuration directory, use the -config=\"...\" command line option.",
+				configPath,
+			),
+		})
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Load the full config, so we can verify that the target resource is
+	// already configured.
+	config, configDiags := c.loadConfig(configPath)
+	diags = diags.Append(configDiags)
+	if configDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Verify that the given address points to something that exists in config.
+	// This is to reduce the risk that a typo in the resource address will
+	// import something that Terraform will want to immediately destroy on
+	// the next plan, and generally acts as a reassurance of user intent.
+	targetConfig := config.DescendentForInstance(addr.Module)
+	if targetConfig == nil {
+		modulePath := addr.Module.String()
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Import to non-existent module",
+			Detail: fmt.Sprintf(
+				"%s is not defined in the configuration. Please add configuration for this module before importing into it.",
+				modulePath,
+			),
+		})
+		c.showDiagnostics(diags)
+		return 1
+	}
+	targetMod := targetConfig.Module
+	rcs := targetMod.ManagedResources
+	var rc *configs.Resource
+	resourceRelAddr := addr.Resource.Resource
+	for _, thisRc := range rcs {
+		if resourceRelAddr.Type == thisRc.Type && resourceRelAddr.Name == thisRc.Name {
+			rc = thisRc
+			break
+		}
+	}
+	if rc == nil {
+		modulePath := addr.Module.String()
+		if modulePath == "" {
+			modulePath = "the root module"
+		}
+
+		c.showDiagnostics(diags)
+
+		// This is not a diagnostic because currently our diagnostics printer
+		// doesn't support having a code example in the detail, and there's
+		// a code example in this message.
+		// TODO: Improve the diagnostics printer so we can use it for this
+		// message.
+		c.Ui.Error(fmt.Sprintf(
+			importCommandMissingResourceFmt,
+			addr, modulePath, resourceRelAddr.Type, resourceRelAddr.Name,
+		))
+		return 1
+	}
+
+	// Check for user-supplied plugin path
+	if c.pluginPath, err = c.loadPluginPath(); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error loading plugin path: %s", err))
+		return 1
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(&BackendOpts{
+		Config: config.Module.Backend,
+	})
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// We require a backend.Local to build a context.
+	// This isn't necessarily a "local.Local" backend, which provides local
+	// operations, however that is the only current implementation. A
+	// "local.Local" backend also doesn't necessarily provide local state, as
+	// that may be delegated to a "remotestate.Backend".
+	local, ok := b.(backend.Local)
+	if !ok {
+		c.Ui.Error(ErrUnsupportedLocalOp)
+		return 1
+	}
+
+	// Build the operation
+	opReq := c.Operation(b, arguments.ViewHuman)
+	opReq.ConfigDir = configPath
+	opReq.ConfigLoader, err = c.initConfigLoader()
+	if err != nil {
+		diags = diags.Append(err)
+		c.showDiagnostics(diags)
+		return 1
+	}
+	opReq.Hooks = []terraform.Hook{c.uiHook()}
+	{
+		var moreDiags tfdiags.Diagnostics
+		opReq.Variables, moreDiags = c.collectVariableValues()
+		diags = diags.Append(moreDiags)
+		if moreDiags.HasErrors() {
+			c.showDiagnostics(diags)
+			return 1
+		}
+	}
+	opReq.View = views.NewOperation(arguments.ViewHuman, c.RunningInAutomation, c.View)
+
+	// Check remote Terraform version is compatible
+	remoteVersionDiags := c.remoteVersionCheck(b, opReq.Workspace)
+	diags = diags.Append(remoteVersionDiags)
+	c.showDiagnostics(diags)
+	if diags.HasErrors() {
+		return 1
+	}
+
+	// Get the context
+	lr, state, ctxDiags := local.LocalRun(opReq)
+	diags = diags.Append(ctxDiags)
+	if ctxDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Successfully creating the context can result in a lock, so ensure we release it
+	defer func() {
+		diags := opReq.StateLocker.Unlock()
+		if diags.HasErrors() {
+			c.showDiagnostics(diags)
+		}
+	}()
+
+	// Perform the import. Note that as you can see it is possible for this
+	// API to import more than one resource at once. For now, we only allow
+	// one while we stabilize this feature.
+	newState, importDiags := lr.Core.Import(lr.Config, lr.InputState, &terraform.ImportOpts{
+		Targets: []*terraform.ImportTarget{
+			{
+				Addr: addr,
+				ID:   args[1],
+			},
+		},
+
+		// The LocalRun idea is designed around our primary operations, so
+		// the input variables end up represented as plan options even though
+		// this particular operation isn't really a plan.
+		SetVariables: lr.PlanOpts.SetVariables,
+	})
+	diags = diags.Append(importDiags)
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Get schemas, if possible, before writing state
+	var schemas *terraform.Schemas
+	if isCloudMode(b) {
+		var schemaDiags tfdiags.Diagnostics
+		schemas, schemaDiags = c.MaybeGetSchemas(newState, nil)
+		diags = diags.Append(schemaDiags)
+	}
+
+	// Persist the final state
+	log.Printf("[INFO] Writing state output to: %s", c.Meta.StateOutPath())
+	if err := state.WriteState(newState); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
+		return 1
+	}
+	if err := state.PersistState(schemas); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
+		return 1
+	}
+
+	c.Ui.Output(c.Colorize().Color("[reset][green]\n" + importCommandSuccessMsg))
+
+	c.showDiagnostics(diags)
+	if diags.HasErrors() {
+		return 1
+	}
+
+	return 0
+}
+
+func (c *ImportCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] import [options] ADDR ID
+
+  Import existing infrastructure into your Terraform state.
+
+  This will find and import the specified resource into your Terraform
+  state, allowing existing infrastructure to come under Terraform
+  management without having to be initially created by Terraform.
+
+  The ADDR specified is the address to import the resource to. Please
+  see the documentation online for resource addresses. The ID is a
+  resource-specific ID to identify that resource being imported. Please
+  reference the documentation for the resource type you're importing to
+  determine the ID syntax to use. It typically matches directly to the ID
+  that the provider uses.
+
+  This command will not modify your infrastructure, but it will make
+  network requests to inspect parts of your infrastructure relevant to
+  the resource being imported.
+
+Options:
+
+  -config=path            Path to a directory of Terraform configuration files
+                          to use to configure the provider. Defaults to pwd.
+                          If no config files are present, they must be provided
+                          via the input prompts or env vars.
+
+  -input=false            Disable interactive input prompts.
+
+  -lock=false             Don't hold a state lock during the operation. This is
+                          dangerous if others might concurrently run commands
+                          against the same workspace.
+
+  -lock-timeout=0s        Duration to retry a state lock.
+
+  -no-color               If specified, output won't contain any color.
+
+  -var 'foo=bar'          Set a variable in the Terraform configuration. This
+                          flag can be set multiple times. This is only useful
+                          with the "-config" flag.
+
+  -var-file=foo           Set variables in the Terraform configuration from
+                          a file. If "terraform.tfvars" or any ".auto.tfvars"
+                          files are present, they will be automatically loaded.
+
+  -ignore-remote-version  A rare option used for the remote backend only. See
+                          the remote backend documentation for more information.
+
+  -state, state-out, and -backup are legacy options supported for the local
+  backend only. For more information, see the local backend's documentation.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *ImportCommand) Synopsis() string {
+	return "Associate existing infrastructure with a Terraform resource"
+}
+
+const importCommandInvalidAddressReference = `For information on valid syntax, see:
+https://www.terraform.io/docs/cli/state/resource-addressing.html`
+
+const importCommandMissingResourceFmt = `[reset][bold][red]Error:[reset][bold] resource address %q does not exist in the configuration.[reset]
+
+Before importing this resource, please create its configuration in %s. For example:
+
+resource %q %q {
+  # (resource arguments)
+}
+`
+
+const importCommandSuccessMsg = `Import successful!
+
+The resources that were imported are shown above. These resources are now in
+your Terraform state and will henceforth be managed by Terraform.
+`
diff --git a/v1.5.7/internal/command/import_test.go b/v1.5.7/internal/command/import_test.go
new file mode 100644
index 0000000..6f9d8bc
--- /dev/null
+++ b/v1.5.7/internal/command/import_test.go
@@ -0,0 +1,982 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/mitchellh/cli"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/copy"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestImport(t *testing.T) {
+	defer testChdir(t, testFixturePath("import-provider-implicit"))()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	p.ImportResourceStateFn = nil
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("yay"),
+				}),
+			},
+		},
+	}
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Optional: true, Computed: true},
+					},
+				},
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+		"bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	if !p.ImportResourceStateCalled {
+		t.Fatal("ImportResourceState should be called")
+	}
+
+	testStateOutput(t, statePath, testImportStr)
+}
+
+func TestImport_providerConfig(t *testing.T) {
+	defer testChdir(t, testFixturePath("import-provider"))()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	p.ImportResourceStateFn = nil
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("yay"),
+				}),
+			},
+		},
+	}
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Optional: true, Computed: true},
+					},
+				},
+			},
+		},
+	}
+
+	configured := false
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
+		configured = true
+
+		cfg := req.Config
+		if !cfg.Type().HasAttribute("foo") {
+			return providers.ConfigureProviderResponse{
+				Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("configuration has no foo argument")),
+			}
+		}
+		if got, want := cfg.GetAttr("foo"), cty.StringVal("bar"); !want.RawEquals(got) {
+			return providers.ConfigureProviderResponse{
+				Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("foo argument is %#v, but want %#v", got, want)),
+			}
+		}
+
+		return providers.ConfigureProviderResponse{}
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+		"bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Verify that we were called
+	if !configured {
+		t.Fatal("Configure should be called")
+	}
+
+	if !p.ImportResourceStateCalled {
+		t.Fatal("ImportResourceState should be called")
+	}
+
+	testStateOutput(t, statePath, testImportStr)
+}
+
+// "remote" state provided by the "local" backend
+func TestImport_remoteState(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("import-provider-remote-state"), td)
+	defer testChdir(t, td)()
+
+	statePath := "imported.tfstate"
+
+	providerSource, close := newMockProviderSource(t, map[string][]string{
+		"test": []string{"1.2.3"},
+	})
+	defer close()
+
+	// init our backend
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	m := Meta{
+		testingOverrides: metaOverridesForProvider(testProvider()),
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	ic := &InitCommand{
+		Meta: m,
+	}
+
+	// (Using log here rather than t.Log so that these messages interleave with other trace logs)
+	log.Print("[TRACE] TestImport_remoteState running: terraform init")
+	if code := ic.Run([]string{}); code != 0 {
+		t.Fatalf("init failed\n%s", ui.ErrorWriter)
+	}
+
+	p := testProvider()
+	ui = new(cli.MockUi)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	p.ImportResourceStateFn = nil
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("yay"),
+				}),
+			},
+		},
+	}
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Optional: true, Computed: true},
+					},
+				},
+			},
+		},
+	}
+
+	configured := false
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
+		var diags tfdiags.Diagnostics
+		configured = true
+		if got, want := req.Config.GetAttr("foo"), cty.StringVal("bar"); !want.RawEquals(got) {
+			diags = diags.Append(fmt.Errorf("wrong \"foo\" value %#v; want %#v", got, want))
+		}
+		return providers.ConfigureProviderResponse{
+			Diagnostics: diags,
+		}
+	}
+
+	args := []string{
+		"test_instance.foo",
+		"bar",
+	}
+	log.Printf("[TRACE] TestImport_remoteState running: terraform import %s %s", args[0], args[1])
+	if code := c.Run(args); code != 0 {
+		fmt.Println(ui.OutputWriter)
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// verify that the local state was unlocked after import
+	if _, err := os.Stat(filepath.Join(td, fmt.Sprintf(".%s.lock.info", statePath))); !os.IsNotExist(err) {
+		t.Fatal("state left locked after import")
+	}
+
+	// Verify that we were called
+	if !configured {
+		t.Fatal("Configure should be called")
+	}
+
+	if !p.ImportResourceStateCalled {
+		t.Fatal("ImportResourceState should be called")
+	}
+
+	testStateOutput(t, statePath, testImportStr)
+}
+
+// early failure on import should not leave stale lock
+func TestImport_initializationErrorShouldUnlock(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("import-provider-remote-state"), td)
+	defer testChdir(t, td)()
+
+	statePath := "imported.tfstate"
+
+	providerSource, close := newMockProviderSource(t, map[string][]string{
+		"test": []string{"1.2.3"},
+	})
+	defer close()
+
+	// init our backend
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	m := Meta{
+		testingOverrides: metaOverridesForProvider(testProvider()),
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	ic := &InitCommand{
+		Meta: m,
+	}
+
+	// (Using log here rather than t.Log so that these messages interleave with other trace logs)
+	log.Print("[TRACE] TestImport_initializationErrorShouldUnlock running: terraform init")
+	if code := ic.Run([]string{}); code != 0 {
+		t.Fatalf("init failed\n%s", ui.ErrorWriter)
+	}
+
+	// overwrite the config with one including a resource from an invalid provider
+	copy.CopyFile(filepath.Join(testFixturePath("import-provider-invalid"), "main.tf"), filepath.Join(td, "main.tf"))
+
+	p := testProvider()
+	ui = new(cli.MockUi)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"unknown_instance.baz",
+		"bar",
+	}
+	log.Printf("[TRACE] TestImport_initializationErrorShouldUnlock running: terraform import %s %s", args[0], args[1])
+
+	// this should fail
+	if code := c.Run(args); code != 1 {
+		fmt.Println(ui.OutputWriter)
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// specifically, it should fail due to a missing provider
+	msg := strings.ReplaceAll(ui.ErrorWriter.String(), "\n", " ")
+	if want := `provider registry.terraform.io/hashicorp/unknown: required by this configuration but no version is selected`; !strings.Contains(msg, want) {
+		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
+	}
+
+	// verify that the local state was unlocked after initialization error
+	if _, err := os.Stat(filepath.Join(td, fmt.Sprintf(".%s.lock.info", statePath))); !os.IsNotExist(err) {
+		t.Fatal("state left locked after import")
+	}
+}
+
+func TestImport_providerConfigWithVar(t *testing.T) {
+	defer testChdir(t, testFixturePath("import-provider-var"))()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	p.ImportResourceStateFn = nil
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("yay"),
+				}),
+			},
+		},
+	}
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Optional: true, Computed: true},
+					},
+				},
+			},
+		},
+	}
+
+	configured := false
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
+		var diags tfdiags.Diagnostics
+		configured = true
+		if got, want := req.Config.GetAttr("foo"), cty.StringVal("bar"); !want.RawEquals(got) {
+			diags = diags.Append(fmt.Errorf("wrong \"foo\" value %#v; want %#v", got, want))
+		}
+		return providers.ConfigureProviderResponse{
+			Diagnostics: diags,
+		}
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-var", "foo=bar",
+		"test_instance.foo",
+		"bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Verify that we were called
+	if !configured {
+		t.Fatal("Configure should be called")
+	}
+
+	if !p.ImportResourceStateCalled {
+		t.Fatal("ImportResourceState should be called")
+	}
+
+	testStateOutput(t, statePath, testImportStr)
+}
+
+func TestImport_providerConfigWithDataSource(t *testing.T) {
+	defer testChdir(t, testFixturePath("import-provider-datasource"))()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	p.ImportResourceStateFn = nil
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("yay"),
+				}),
+			},
+		},
+	}
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Optional: true, Computed: true},
+					},
+				},
+			},
+		},
+		DataSources: map[string]providers.Schema{
+			"test_data": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+		"bar",
+	}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad, wanted error: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+}
+
+func TestImport_providerConfigWithVarDefault(t *testing.T) {
+	defer testChdir(t, testFixturePath("import-provider-var-default"))()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	p.ImportResourceStateFn = nil
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("yay"),
+				}),
+			},
+		},
+	}
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Optional: true, Computed: true},
+					},
+				},
+			},
+		},
+	}
+
+	configured := false
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
+		var diags tfdiags.Diagnostics
+		configured = true
+		if got, want := req.Config.GetAttr("foo"), cty.StringVal("bar"); !want.RawEquals(got) {
+			diags = diags.Append(fmt.Errorf("wrong \"foo\" value %#v; want %#v", got, want))
+		}
+		return providers.ConfigureProviderResponse{
+			Diagnostics: diags,
+		}
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+		"bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Verify that we were called
+	if !configured {
+		t.Fatal("Configure should be called")
+	}
+
+	if !p.ImportResourceStateCalled {
+		t.Fatal("ImportResourceState should be called")
+	}
+
+	testStateOutput(t, statePath, testImportStr)
+}
+
+func TestImport_providerConfigWithVarFile(t *testing.T) {
+	defer testChdir(t, testFixturePath("import-provider-var-file"))()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	p.ImportResourceStateFn = nil
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("yay"),
+				}),
+			},
+		},
+	}
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Optional: true, Computed: true},
+					},
+				},
+			},
+		},
+	}
+
+	configured := false
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
+		var diags tfdiags.Diagnostics
+		configured = true
+		if got, want := req.Config.GetAttr("foo"), cty.StringVal("bar"); !want.RawEquals(got) {
+			diags = diags.Append(fmt.Errorf("wrong \"foo\" value %#v; want %#v", got, want))
+		}
+		return providers.ConfigureProviderResponse{
+			Diagnostics: diags,
+		}
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-var-file", "blah.tfvars",
+		"test_instance.foo",
+		"bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Verify that we were called
+	if !configured {
+		t.Fatal("Configure should be called")
+	}
+
+	if !p.ImportResourceStateCalled {
+		t.Fatal("ImportResourceState should be called")
+	}
+
+	testStateOutput(t, statePath, testImportStr)
+}
+
+func TestImport_emptyConfig(t *testing.T) {
+	defer testChdir(t, testFixturePath("empty"))()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+		"bar",
+	}
+	code := c.Run(args)
+	if code != 1 {
+		t.Fatalf("import succeeded; expected failure")
+	}
+
+	msg := ui.ErrorWriter.String()
+	if want := `No Terraform configuration files`; !strings.Contains(msg, want) {
+		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
+	}
+}
+
+func TestImport_missingResourceConfig(t *testing.T) {
+	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+		"bar",
+	}
+	code := c.Run(args)
+	if code != 1 {
+		t.Fatalf("import succeeded; expected failure")
+	}
+
+	msg := ui.ErrorWriter.String()
+	if want := `resource address "test_instance.foo" does not exist`; !strings.Contains(msg, want) {
+		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
+	}
+}
+
+func TestImport_missingModuleConfig(t *testing.T) {
+	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"module.baz.test_instance.foo",
+		"bar",
+	}
+	code := c.Run(args)
+	if code != 1 {
+		t.Fatalf("import succeeded; expected failure")
+	}
+
+	msg := ui.ErrorWriter.String()
+	if want := `module.baz is not defined in the configuration`; !strings.Contains(msg, want) {
+		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
+	}
+}
+
+func TestImportModuleVarFile(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("import-module-var-file"), td)
+	defer testChdir(t, td)()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	providerSource, close := newMockProviderSource(t, map[string][]string{
+		"test": []string{"1.2.3"},
+	})
+	defer close()
+
+	// init to install the module
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	m := Meta{
+		testingOverrides: metaOverridesForProvider(testProvider()),
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	ic := &InitCommand{
+		Meta: m,
+	}
+	if code := ic.Run([]string{}); code != 0 {
+		t.Fatalf("init failed\n%s", ui.ErrorWriter)
+	}
+
+	// import
+	ui = new(cli.MockUi)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+	args := []string{
+		"-state", statePath,
+		"module.child.test_instance.foo",
+		"bar",
+	}
+	code := c.Run(args)
+	if code != 0 {
+		t.Fatalf("import failed; expected success")
+	}
+}
+
+// This test covers an edge case where a module with a complex input variable
+// of nested objects has an invalid default which is overridden by the calling
+// context, and is used in locals. If we don't evaluate module call variables
+// for the import walk, this results in an error.
+//
+// The specific example has a variable "foo" which is a nested object:
+//
+//	foo = { bar = { baz = true } }
+//
+// This is used as foo = var.foo in the call to the child module, which then
+// uses the traversal foo.bar.baz in a local. A default value in the child
+// module of {} causes this local evaluation to error, breaking import.
+func TestImportModuleInputVariableEvaluation(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("import-module-input-variable"), td)
+	defer testChdir(t, td)()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	providerSource, close := newMockProviderSource(t, map[string][]string{
+		"test": {"1.2.3"},
+	})
+	defer close()
+
+	// init to install the module
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	m := Meta{
+		testingOverrides: metaOverridesForProvider(testProvider()),
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	ic := &InitCommand{
+		Meta: m,
+	}
+	if code := ic.Run([]string{}); code != 0 {
+		t.Fatalf("init failed\n%s", ui.ErrorWriter)
+	}
+
+	// import
+	ui = new(cli.MockUi)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+	args := []string{
+		"-state", statePath,
+		"module.child.test_instance.foo",
+		"bar",
+	}
+	code := c.Run(args)
+	if code != 0 {
+		t.Fatalf("import failed; expected success")
+	}
+}
+
+func TestImport_dataResource(t *testing.T) {
+	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"data.test_data_source.foo",
+		"bar",
+	}
+	code := c.Run(args)
+	if code != 1 {
+		t.Fatalf("import succeeded; expected failure")
+	}
+
+	msg := ui.ErrorWriter.String()
+	if want := `A managed resource address is required`; !strings.Contains(msg, want) {
+		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
+	}
+}
+
+func TestImport_invalidResourceAddr(t *testing.T) {
+	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"bananas",
+		"bar",
+	}
+	code := c.Run(args)
+	if code != 1 {
+		t.Fatalf("import succeeded; expected failure")
+	}
+
+	msg := ui.ErrorWriter.String()
+	if want := `Error: Invalid address`; !strings.Contains(msg, want) {
+		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
+	}
+}
+
+func TestImport_targetIsModule(t *testing.T) {
+	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
+
+	statePath := testTempFile(t)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &ImportCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"module.foo",
+		"bar",
+	}
+	code := c.Run(args)
+	if code != 1 {
+		t.Fatalf("import succeeded; expected failure")
+	}
+
+	msg := ui.ErrorWriter.String()
+	if want := `Error: Invalid address`; !strings.Contains(msg, want) {
+		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
+	}
+}
+
+const testImportStr = `
+test_instance.foo:
+  ID = yay
+  provider = provider["registry.terraform.io/hashicorp/test"]
+`
diff --git a/v1.5.7/internal/command/init.go b/v1.5.7/internal/command/init.go
new file mode 100644
index 0000000..9177260
--- /dev/null
+++ b/v1.5.7/internal/command/init.go
@@ -0,0 +1,1245 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"reflect"
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/posener/complete"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	backendInit "github.com/hashicorp/terraform/internal/backend/init"
+	"github.com/hashicorp/terraform/internal/cloud"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/hashicorp/terraform/internal/providercache"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+// InitCommand is a Command implementation that takes a Terraform
+// module and clones it to the working directory.
+type InitCommand struct {
+	Meta
+}
+
+func (c *InitCommand) Run(args []string) int {
+	var flagFromModule, flagLockfile string
+	var flagBackend, flagCloud, flagGet, flagUpgrade bool
+	var flagPluginPath FlagStringSlice
+	flagConfigExtra := newRawFlags("-backend-config")
+
+	args = c.Meta.process(args)
+	cmdFlags := c.Meta.extendedFlagSet("init")
+	cmdFlags.BoolVar(&flagBackend, "backend", true, "")
+	cmdFlags.BoolVar(&flagCloud, "cloud", true, "")
+	cmdFlags.Var(flagConfigExtra, "backend-config", "")
+	cmdFlags.StringVar(&flagFromModule, "from-module", "", "copy the source of the given module into the directory before init")
+	cmdFlags.BoolVar(&flagGet, "get", true, "")
+	cmdFlags.BoolVar(&c.forceInitCopy, "force-copy", false, "suppress prompts about copying state data")
+	cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
+	cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
+	cmdFlags.BoolVar(&c.reconfigure, "reconfigure", false, "reconfigure")
+	cmdFlags.BoolVar(&c.migrateState, "migrate-state", false, "migrate state")
+	cmdFlags.BoolVar(&flagUpgrade, "upgrade", false, "")
+	cmdFlags.Var(&flagPluginPath, "plugin-dir", "plugin directory")
+	cmdFlags.StringVar(&flagLockfile, "lockfile", "", "Set a dependency lockfile mode")
+	cmdFlags.BoolVar(&c.Meta.ignoreRemoteVersion, "ignore-remote-version", false, "continue even if remote and local Terraform versions are incompatible")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		return 1
+	}
+
+	backendFlagSet := arguments.FlagIsSet(cmdFlags, "backend")
+	cloudFlagSet := arguments.FlagIsSet(cmdFlags, "cloud")
+
+	switch {
+	case backendFlagSet && cloudFlagSet:
+		c.Ui.Error("The -backend and -cloud options are aliases of one another and mutually-exclusive in their use")
+		return 1
+	case backendFlagSet:
+		flagCloud = flagBackend
+	case cloudFlagSet:
+		flagBackend = flagCloud
+	}
+
+	if c.migrateState && c.reconfigure {
+		c.Ui.Error("The -migrate-state and -reconfigure options are mutually-exclusive")
+		return 1
+	}
+
+	// Copying the state only happens during backend migration, so setting
+	// -force-copy implies -migrate-state
+	if c.forceInitCopy {
+		c.migrateState = true
+	}
+
+	var diags tfdiags.Diagnostics
+
+	if len(flagPluginPath) > 0 {
+		c.pluginPath = flagPluginPath
+	}
+
+	// Validate the arg count and get the working directory
+	args = cmdFlags.Args()
+	path, err := ModulePath(args)
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	if err := c.storePluginPath(c.pluginPath); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error saving -plugin-path values: %s", err))
+		return 1
+	}
+
+	// This will track whether we outputted anything so that we know whether
+	// to output a newline before the success message
+	var header bool
+
+	if flagFromModule != "" {
+		src := flagFromModule
+
+		empty, err := configs.IsEmptyDir(path)
+		if err != nil {
+			c.Ui.Error(fmt.Sprintf("Error validating destination directory: %s", err))
+			return 1
+		}
+		if !empty {
+			c.Ui.Error(strings.TrimSpace(errInitCopyNotEmpty))
+			return 1
+		}
+
+		c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
+			"[reset][bold]Copying configuration[reset] from %q...", src,
+		)))
+		header = true
+
+		hooks := uiModuleInstallHooks{
+			Ui:             c.Ui,
+			ShowLocalPaths: false, // since they are in a weird location for init
+		}
+
+		initDirFromModuleAbort, initDirFromModuleDiags := c.initDirFromModule(path, src, hooks)
+		diags = diags.Append(initDirFromModuleDiags)
+		if initDirFromModuleAbort || initDirFromModuleDiags.HasErrors() {
+			c.showDiagnostics(diags)
+			return 1
+		}
+
+		c.Ui.Output("")
+	}
+
+	// If our directory is empty, then we're done. We can't get or set up
+	// the backend with an empty directory.
+	empty, err := configs.IsEmptyDir(path)
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Error checking configuration: %s", err))
+		c.showDiagnostics(diags)
+		return 1
+	}
+	if empty {
+		c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputInitEmpty)))
+		return 0
+	}
+
+	// Load just the root module to begin backend and module initialization
+	rootModEarly, earlyConfDiags := c.loadSingleModule(path)
+
+	// There may be parsing errors in config loading but these will be shown later _after_
+	// checking for core version requirement errors. Not meeting the version requirement should
+	// be the first error displayed if that is an issue, but other operations are required
+	// before being able to check core version requirements.
+	if rootModEarly == nil {
+		c.Ui.Error(c.Colorize().Color(strings.TrimSpace(errInitConfigError)))
+		diags = diags.Append(earlyConfDiags)
+		c.showDiagnostics(diags)
+
+		return 1
+	}
+
+	var back backend.Backend
+
+	// There may be config errors or backend init errors but these will be shown later _after_
+	// checking for core version requirement errors.
+	var backDiags tfdiags.Diagnostics
+	var backendOutput bool
+
+	switch {
+	case flagCloud && rootModEarly.CloudConfig != nil:
+		back, backendOutput, backDiags = c.initCloud(rootModEarly, flagConfigExtra)
+	case flagBackend:
+		back, backendOutput, backDiags = c.initBackend(rootModEarly, flagConfigExtra)
+	default:
+		// load the previously-stored backend config
+		back, backDiags = c.Meta.backendFromState()
+	}
+	if backendOutput {
+		header = true
+	}
+
+	var state *states.State
+
+	// If we have a functional backend (either just initialized or initialized
+	// on a previous run) we'll use the current state as a potential source
+	// of provider dependencies.
+	if back != nil {
+		c.ignoreRemoteVersionConflict(back)
+		workspace, err := c.Workspace()
+		if err != nil {
+			c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err))
+			return 1
+		}
+		sMgr, err := back.StateMgr(workspace)
+		if err != nil {
+			c.Ui.Error(fmt.Sprintf("Error loading state: %s", err))
+			return 1
+		}
+
+		if err := sMgr.RefreshState(); err != nil {
+			c.Ui.Error(fmt.Sprintf("Error refreshing state: %s", err))
+			return 1
+		}
+
+		state = sMgr.State()
+	}
+
+	if flagGet {
+		modsOutput, modsAbort, modsDiags := c.getModules(path, rootModEarly, flagUpgrade)
+		diags = diags.Append(modsDiags)
+		if modsAbort || modsDiags.HasErrors() {
+			c.showDiagnostics(diags)
+			return 1
+		}
+		if modsOutput {
+			header = true
+		}
+	}
+
+	// With all of the modules (hopefully) installed, we can now try to load the
+	// whole configuration tree.
+	config, confDiags := c.loadConfig(path)
+	// configDiags will be handled after the version constraint check, since an
+	// incorrect version of terraform may be producing errors for configuration
+	// constructs added in later versions.
+
+	// Before we go further, we'll check to make sure none of the modules in
+	// the configuration declare that they don't support this Terraform
+	// version, so we can produce a version-related error message rather than
+	// potentially-confusing downstream errors.
+	versionDiags := terraform.CheckCoreVersionRequirements(config)
+	if versionDiags.HasErrors() {
+		c.showDiagnostics(versionDiags)
+		return 1
+	}
+
+	// We've passed the core version check, now we can show errors from the
+	// configuration and backend initialisation.
+
+	// Now, we can check the diagnostics from the early configuration and the
+	// backend.
+	diags = diags.Append(earlyConfDiags)
+	diags = diags.Append(backDiags)
+	if earlyConfDiags.HasErrors() {
+		c.Ui.Error(strings.TrimSpace(errInitConfigError))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Now, we can show any errors from initializing the backend, but we won't
+	// show the errInitConfigError preamble as we didn't detect problems with
+	// the early configuration.
+	if backDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// If everything is ok with the core version check and backend initialization,
+	// show other errors from loading the full configuration tree.
+	diags = diags.Append(confDiags)
+	if confDiags.HasErrors() {
+		c.Ui.Error(strings.TrimSpace(errInitConfigError))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	if cb, ok := back.(*cloud.Cloud); ok {
+		if c.RunningInAutomation {
+			if err := cb.AssertImportCompatible(config); err != nil {
+				diags = diags.Append(tfdiags.Sourceless(tfdiags.Error, "Compatibility error", err.Error()))
+				c.showDiagnostics(diags)
+				return 1
+			}
+		}
+	}
+
+	// Now that we have loaded all modules, check the module tree for missing providers.
+	providersOutput, providersAbort, providerDiags := c.getProviders(config, state, flagUpgrade, flagPluginPath, flagLockfile)
+	diags = diags.Append(providerDiags)
+	if providersAbort || providerDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+	if providersOutput {
+		header = true
+	}
+
+	// If we outputted information, then we need to output a newline
+	// so that our success message is nicely spaced out from prior text.
+	if header {
+		c.Ui.Output("")
+	}
+
+	// If we accumulated any warnings along the way that weren't accompanied
+	// by errors then we'll output them here so that the success message is
+	// still the final thing shown.
+	c.showDiagnostics(diags)
+	_, cloud := back.(*cloud.Cloud)
+	output := outputInitSuccess
+	if cloud {
+		output = outputInitSuccessCloud
+	}
+
+	c.Ui.Output(c.Colorize().Color(strings.TrimSpace(output)))
+
+	if !c.RunningInAutomation {
+		// If we're not running in an automation wrapper, give the user
+		// some more detailed next steps that are appropriate for interactive
+		// shell usage.
+		output = outputInitSuccessCLI
+		if cloud {
+			output = outputInitSuccessCLICloud
+		}
+		c.Ui.Output(c.Colorize().Color(strings.TrimSpace(output)))
+	}
+	return 0
+}
+
+func (c *InitCommand) getModules(path string, earlyRoot *configs.Module, upgrade bool) (output bool, abort bool, diags tfdiags.Diagnostics) {
+	if len(earlyRoot.ModuleCalls) == 0 {
+		// Nothing to do
+		return false, false, nil
+	}
+
+	if upgrade {
+		c.Ui.Output(c.Colorize().Color("[reset][bold]Upgrading modules..."))
+	} else {
+		c.Ui.Output(c.Colorize().Color("[reset][bold]Initializing modules..."))
+	}
+
+	hooks := uiModuleInstallHooks{
+		Ui:             c.Ui,
+		ShowLocalPaths: true,
+	}
+
+	installAbort, installDiags := c.installModules(path, upgrade, hooks)
+	diags = diags.Append(installDiags)
+
+	// At this point, installModules may have generated error diags or been
+	// aborted by SIGINT. In any case we continue and the manifest as best
+	// we can.
+
+	// Since module installer has modified the module manifest on disk, we need
+	// to refresh the cache of it in the loader.
+	if c.configLoader != nil {
+		if err := c.configLoader.RefreshModules(); err != nil {
+			// Should never happen
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to read module manifest",
+				fmt.Sprintf("After installing modules, Terraform could not re-read the manifest of installed modules. This is a bug in Terraform. %s.", err),
+			))
+		}
+	}
+
+	return true, installAbort, diags
+}
+
+func (c *InitCommand) initCloud(root *configs.Module, extraConfig rawFlags) (be backend.Backend, output bool, diags tfdiags.Diagnostics) {
+	c.Ui.Output(c.Colorize().Color("\n[reset][bold]Initializing Terraform Cloud..."))
+
+	if len(extraConfig.AllItems()) != 0 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid command-line option",
+			"The -backend-config=... command line option is only for state backends, and is not applicable to Terraform Cloud-based configurations.\n\nTo change the set of workspaces associated with this configuration, edit the Cloud configuration block in the root module.",
+		))
+		return nil, true, diags
+	}
+
+	backendConfig := root.CloudConfig.ToBackendConfig()
+
+	opts := &BackendOpts{
+		Config: &backendConfig,
+		Init:   true,
+	}
+
+	back, backDiags := c.Backend(opts)
+	diags = diags.Append(backDiags)
+	return back, true, diags
+}
+
+func (c *InitCommand) initBackend(root *configs.Module, extraConfig rawFlags) (be backend.Backend, output bool, diags tfdiags.Diagnostics) {
+	c.Ui.Output(c.Colorize().Color("\n[reset][bold]Initializing the backend..."))
+
+	var backendConfig *configs.Backend
+	var backendConfigOverride hcl.Body
+	if root.Backend != nil {
+		backendType := root.Backend.Type
+		if backendType == "cloud" {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Unsupported backend type",
+				Detail:   fmt.Sprintf("There is no explicit backend type named %q. To configure Terraform Cloud, declare a 'cloud' block instead.", backendType),
+				Subject:  &root.Backend.TypeRange,
+			})
+			return nil, true, diags
+		}
+
+		bf := backendInit.Backend(backendType)
+		if bf == nil {
+			detail := fmt.Sprintf("There is no backend type named %q.", backendType)
+			if msg, removed := backendInit.RemovedBackends[backendType]; removed {
+				detail = msg
+			}
+
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Unsupported backend type",
+				Detail:   detail,
+				Subject:  &root.Backend.TypeRange,
+			})
+			return nil, true, diags
+		}
+
+		b := bf()
+		backendSchema := b.ConfigSchema()
+		backendConfig = root.Backend
+
+		var overrideDiags tfdiags.Diagnostics
+		backendConfigOverride, overrideDiags = c.backendConfigOverrideBody(extraConfig, backendSchema)
+		diags = diags.Append(overrideDiags)
+		if overrideDiags.HasErrors() {
+			return nil, true, diags
+		}
+	} else {
+		// If the user supplied a -backend-config on the CLI but no backend
+		// block was found in the configuration, it's likely - but not
+		// necessarily - a mistake. Return a warning.
+		if !extraConfig.Empty() {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Warning,
+				"Missing backend configuration",
+				`-backend-config was used without a "backend" block in the configuration.
+
+If you intended to override the default local backend configuration,
+no action is required, but you may add an explicit backend block to your
+configuration to clear this warning:
+
+terraform {
+  backend "local" {}
+}
+
+However, if you intended to override a defined backend, please verify that
+the backend configuration is present and valid.
+`,
+			))
+		}
+	}
+
+	opts := &BackendOpts{
+		Config:         backendConfig,
+		ConfigOverride: backendConfigOverride,
+		Init:           true,
+	}
+
+	back, backDiags := c.Backend(opts)
+	diags = diags.Append(backDiags)
+	return back, true, diags
+}
+
+// Load the complete module tree, and fetch any missing providers.
+// This method outputs its own Ui.
+func (c *InitCommand) getProviders(config *configs.Config, state *states.State, upgrade bool, pluginDirs []string, flagLockfile string) (output, abort bool, diags tfdiags.Diagnostics) {
+	// Dev overrides cause the result of "terraform init" to be irrelevant for
+	// any overridden providers, so we'll warn about it to avoid later
+	// confusion when Terraform ends up using a different provider than the
+	// lock file called for.
+	diags = diags.Append(c.providerDevOverrideInitWarnings())
+
+	// First we'll collect all the provider dependencies we can see in the
+	// configuration and the state.
+	reqs, hclDiags := config.ProviderRequirements()
+	diags = diags.Append(hclDiags)
+	if hclDiags.HasErrors() {
+		return false, true, diags
+	}
+	if state != nil {
+		stateReqs := state.ProviderRequirements()
+		reqs = reqs.Merge(stateReqs)
+	}
+
+	for providerAddr := range reqs {
+		if providerAddr.IsLegacy() {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid legacy provider address",
+				fmt.Sprintf(
+					"This configuration or its associated state refers to the unqualified provider %q.\n\nYou must complete the Terraform 0.13 upgrade process before upgrading to later versions.",
+					providerAddr.Type,
+				),
+			))
+		}
+	}
+
+	previousLocks, moreDiags := c.lockedDependencies()
+	diags = diags.Append(moreDiags)
+
+	if diags.HasErrors() {
+		return false, true, diags
+	}
+
+	var inst *providercache.Installer
+	if len(pluginDirs) == 0 {
+		// By default we use a source that looks for providers in all of the
+		// standard locations, possibly customized by the user in CLI config.
+		inst = c.providerInstaller()
+	} else {
+		// If the user passes at least one -plugin-dir then that circumvents
+		// the usual sources and forces Terraform to consult only the given
+		// directories. Anything not available in one of those directories
+		// is not available for installation.
+		source := c.providerCustomLocalDirectorySource(pluginDirs)
+		inst = c.providerInstallerCustomSource(source)
+
+		// The default (or configured) search paths are logged earlier, in provider_source.go
+		// Log that those are being overridden by the `-plugin-dir` command line options
+		log.Println("[DEBUG] init: overriding provider plugin search paths")
+		log.Printf("[DEBUG] will search for provider plugins in %s", pluginDirs)
+	}
+
+	// Installation can be aborted by interruption signals
+	ctx, done := c.InterruptibleContext()
+	defer done()
+
+	// We want to print out a nice warning if we don't manage to pull
+	// checksums for all our providers. This is tracked via callbacks
+	// and incomplete providers are stored here for later analysis.
+	var incompleteProviders []string
+
+	// Because we're currently just streaming a series of events sequentially
+	// into the terminal, we're showing only a subset of the events to keep
+	// things relatively concise. Later it'd be nice to have a progress UI
+	// where statuses update in-place, but we can't do that as long as we
+	// are shimming our vt100 output to the legacy console API on Windows.
+	evts := &providercache.InstallerEvents{
+		PendingProviders: func(reqs map[addrs.Provider]getproviders.VersionConstraints) {
+			c.Ui.Output(c.Colorize().Color(
+				"\n[reset][bold]Initializing provider plugins...",
+			))
+		},
+		ProviderAlreadyInstalled: func(provider addrs.Provider, selectedVersion getproviders.Version) {
+			c.Ui.Info(fmt.Sprintf("- Using previously-installed %s v%s", provider.ForDisplay(), selectedVersion))
+		},
+		BuiltInProviderAvailable: func(provider addrs.Provider) {
+			c.Ui.Info(fmt.Sprintf("- %s is built in to Terraform", provider.ForDisplay()))
+		},
+		BuiltInProviderFailure: func(provider addrs.Provider, err error) {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid dependency on built-in provider",
+				fmt.Sprintf("Cannot use %s: %s.", provider.ForDisplay(), err),
+			))
+		},
+		QueryPackagesBegin: func(provider addrs.Provider, versionConstraints getproviders.VersionConstraints, locked bool) {
+			if locked {
+				c.Ui.Info(fmt.Sprintf("- Reusing previous version of %s from the dependency lock file", provider.ForDisplay()))
+			} else {
+				if len(versionConstraints) > 0 {
+					c.Ui.Info(fmt.Sprintf("- Finding %s versions matching %q...", provider.ForDisplay(), getproviders.VersionConstraintsString(versionConstraints)))
+				} else {
+					c.Ui.Info(fmt.Sprintf("- Finding latest version of %s...", provider.ForDisplay()))
+				}
+			}
+		},
+		LinkFromCacheBegin: func(provider addrs.Provider, version getproviders.Version, cacheRoot string) {
+			c.Ui.Info(fmt.Sprintf("- Using %s v%s from the shared cache directory", provider.ForDisplay(), version))
+		},
+		FetchPackageBegin: func(provider addrs.Provider, version getproviders.Version, location getproviders.PackageLocation) {
+			c.Ui.Info(fmt.Sprintf("- Installing %s v%s...", provider.ForDisplay(), version))
+		},
+		QueryPackagesFailure: func(provider addrs.Provider, err error) {
+			switch errorTy := err.(type) {
+			case getproviders.ErrProviderNotFound:
+				sources := errorTy.Sources
+				displaySources := make([]string, len(sources))
+				for i, source := range sources {
+					displaySources[i] = fmt.Sprintf("  - %s", source)
+				}
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to query available provider packages",
+					fmt.Sprintf("Could not retrieve the list of available versions for provider %s: %s\n\n%s",
+						provider.ForDisplay(), err, strings.Join(displaySources, "\n"),
+					),
+				))
+			case getproviders.ErrRegistryProviderNotKnown:
+				// We might be able to suggest an alternative provider to use
+				// instead of this one.
+				suggestion := fmt.Sprintf("\n\nAll modules should specify their required_providers so that external consumers will get the correct providers when using a module. To see which modules are currently depending on %s, run the following command:\n    terraform providers", provider.ForDisplay())
+				alternative := getproviders.MissingProviderSuggestion(ctx, provider, inst.ProviderSource(), reqs)
+				if alternative != provider {
+					suggestion = fmt.Sprintf(
+						"\n\nDid you intend to use %s? If so, you must specify that source address in each module which requires that provider. To see which modules are currently depending on %s, run the following command:\n    terraform providers",
+						alternative.ForDisplay(), provider.ForDisplay(),
+					)
+				}
+
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to query available provider packages",
+					fmt.Sprintf("Could not retrieve the list of available versions for provider %s: %s%s",
+						provider.ForDisplay(), err, suggestion,
+					),
+				))
+			case getproviders.ErrHostNoProviders:
+				switch {
+				case errorTy.Hostname == svchost.Hostname("github.com") && !errorTy.HasOtherVersion:
+					// If a user copies the URL of a GitHub repository into
+					// the source argument and removes the schema to make it
+					// provider-address-shaped then that's one way we can end up
+					// here. We'll use a specialized error message in anticipation
+					// of that mistake. We only do this if github.com isn't a
+					// provider registry, to allow for the (admittedly currently
+					// rather unlikely) possibility that github.com starts being
+					// a real Terraform provider registry in the future.
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Invalid provider registry host",
+						fmt.Sprintf("The given source address %q specifies a GitHub repository rather than a Terraform provider. Refer to the documentation of the provider to find the correct source address to use.",
+							provider.String(),
+						),
+					))
+
+				case errorTy.HasOtherVersion:
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Invalid provider registry host",
+						fmt.Sprintf("The host %q given in provider source address %q does not offer a Terraform provider registry that is compatible with this Terraform version, but it may be compatible with a different Terraform version.",
+							errorTy.Hostname, provider.String(),
+						),
+					))
+
+				default:
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Invalid provider registry host",
+						fmt.Sprintf("The host %q given in provider source address %q does not offer a Terraform provider registry.",
+							errorTy.Hostname, provider.String(),
+						),
+					))
+				}
+
+			case getproviders.ErrRequestCanceled:
+				// We don't attribute cancellation to any particular operation,
+				// but rather just emit a single general message about it at
+				// the end, by checking ctx.Err().
+
+			default:
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to query available provider packages",
+					fmt.Sprintf("Could not retrieve the list of available versions for provider %s: %s",
+						provider.ForDisplay(), err,
+					),
+				))
+			}
+
+		},
+		QueryPackagesWarning: func(provider addrs.Provider, warnings []string) {
+			displayWarnings := make([]string, len(warnings))
+			for i, warning := range warnings {
+				displayWarnings[i] = fmt.Sprintf("- %s", warning)
+			}
+
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Warning,
+				"Additional provider information from registry",
+				fmt.Sprintf("The remote registry returned warnings for %s:\n%s",
+					provider.String(),
+					strings.Join(displayWarnings, "\n"),
+				),
+			))
+		},
+		LinkFromCacheFailure: func(provider addrs.Provider, version getproviders.Version, err error) {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to install provider from shared cache",
+				fmt.Sprintf("Error while importing %s v%s from the shared cache directory: %s.", provider.ForDisplay(), version, err),
+			))
+		},
+		FetchPackageFailure: func(provider addrs.Provider, version getproviders.Version, err error) {
+			const summaryIncompatible = "Incompatible provider version"
+			switch err := err.(type) {
+			case getproviders.ErrProtocolNotSupported:
+				closestAvailable := err.Suggestion
+				switch {
+				case closestAvailable == getproviders.UnspecifiedVersion:
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						summaryIncompatible,
+						fmt.Sprintf(errProviderVersionIncompatible, provider.String()),
+					))
+				case version.GreaterThan(closestAvailable):
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						summaryIncompatible,
+						fmt.Sprintf(providerProtocolTooNew, provider.ForDisplay(),
+							version, tfversion.String(), closestAvailable, closestAvailable,
+							getproviders.VersionConstraintsString(reqs[provider]),
+						),
+					))
+				default: // version is less than closestAvailable
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						summaryIncompatible,
+						fmt.Sprintf(providerProtocolTooOld, provider.ForDisplay(),
+							version, tfversion.String(), closestAvailable, closestAvailable,
+							getproviders.VersionConstraintsString(reqs[provider]),
+						),
+					))
+				}
+			case getproviders.ErrPlatformNotSupported:
+				switch {
+				case err.MirrorURL != nil:
+					// If we're installing from a mirror then it may just be
+					// the mirror lacking the package, rather than it being
+					// unavailable from upstream.
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						summaryIncompatible,
+						fmt.Sprintf(
+							"Your chosen provider mirror at %s does not have a %s v%s package available for your current platform, %s.\n\nProvider releases are separate from Terraform CLI releases, so this provider might not support your current platform. Alternatively, the mirror itself might have only a subset of the plugin packages available in the origin registry, at %s.",
+							err.MirrorURL, err.Provider, err.Version, err.Platform,
+							err.Provider.Hostname,
+						),
+					))
+				default:
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						summaryIncompatible,
+						fmt.Sprintf(
+							"Provider %s v%s does not have a package available for your current platform, %s.\n\nProvider releases are separate from Terraform CLI releases, so not all providers are available for all platforms. Other versions of this provider may have different platforms supported.",
+							err.Provider, err.Version, err.Platform,
+						),
+					))
+				}
+
+			case getproviders.ErrRequestCanceled:
+				// We don't attribute cancellation to any particular operation,
+				// but rather just emit a single general message about it at
+				// the end, by checking ctx.Err().
+
+			default:
+				// We can potentially end up in here under cancellation too,
+				// in spite of our getproviders.ErrRequestCanceled case above,
+				// because not all of the outgoing requests we do under the
+				// "fetch package" banner are source metadata requests.
+				// In that case we will emit a redundant error here about
+				// the request being cancelled, but we'll still detect it
+				// as a cancellation after the installer returns and do the
+				// normal cancellation handling.
+
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to install provider",
+					fmt.Sprintf("Error while installing %s v%s: %s", provider.ForDisplay(), version, err),
+				))
+			}
+		},
+		FetchPackageSuccess: func(provider addrs.Provider, version getproviders.Version, localDir string, authResult *getproviders.PackageAuthenticationResult) {
+			var keyID string
+			if authResult != nil && authResult.ThirdPartySigned() {
+				keyID = authResult.KeyID
+			}
+			if keyID != "" {
+				keyID = c.Colorize().Color(fmt.Sprintf(", key ID [reset][bold]%s[reset]", keyID))
+			}
+
+			c.Ui.Info(fmt.Sprintf("- Installed %s v%s (%s%s)", provider.ForDisplay(), version, authResult, keyID))
+		},
+		ProvidersLockUpdated: func(provider addrs.Provider, version getproviders.Version, localHashes []getproviders.Hash, signedHashes []getproviders.Hash, priorHashes []getproviders.Hash) {
+			// We're going to use this opportunity to track if we have any
+			// "incomplete" installs of providers. An incomplete install is
+			// when we are only going to write the local hashes into our lock
+			// file which means a `terraform init` command will fail in future
+			// when used on machines of a different architecture.
+			//
+			// We want to print a warning about this.
+
+			if len(signedHashes) > 0 {
+				// If we have any signedHashes hashes then we don't worry - as
+				// we know we retrieved all available hashes for this version
+				// anyway.
+				return
+			}
+
+			// If local hashes and prior hashes are exactly the same then
+			// it means we didn't record any signed hashes previously, and
+			// we know we're not adding any extra in now (because we already
+			// checked the signedHashes), so that's a problem.
+			//
+			// In the actual check here, if we have any priorHashes and those
+			// hashes are not the same as the local hashes then we're going to
+			// accept that this provider has been configured correctly.
+			if len(priorHashes) > 0 && !reflect.DeepEqual(localHashes, priorHashes) {
+				return
+			}
+
+			// Now, either signedHashes is empty, or priorHashes is exactly the
+			// same as our localHashes which means we never retrieved the
+			// signedHashes previously.
+			//
+			// Either way, this is bad. Let's complain/warn.
+			incompleteProviders = append(incompleteProviders, provider.ForDisplay())
+		},
+		ProvidersFetched: func(authResults map[addrs.Provider]*getproviders.PackageAuthenticationResult) {
+			thirdPartySigned := false
+			for _, authResult := range authResults {
+				if authResult.ThirdPartySigned() {
+					thirdPartySigned = true
+					break
+				}
+			}
+			if thirdPartySigned {
+				c.Ui.Info(fmt.Sprintf("\nPartner and community providers are signed by their developers.\n" +
+					"If you'd like to know more about provider signing, you can read about it here:\n" +
+					"https://www.terraform.io/docs/cli/plugins/signing.html"))
+			}
+		},
+	}
+	ctx = evts.OnContext(ctx)
+
+	mode := providercache.InstallNewProvidersOnly
+	if upgrade {
+		if flagLockfile == "readonly" {
+			c.Ui.Error("The -upgrade flag conflicts with -lockfile=readonly.")
+			return true, true, diags
+		}
+
+		mode = providercache.InstallUpgrades
+	}
+	newLocks, err := inst.EnsureProviderVersions(ctx, previousLocks, reqs, mode)
+	if ctx.Err() == context.Canceled {
+		c.showDiagnostics(diags)
+		c.Ui.Error("Provider installation was canceled by an interrupt signal.")
+		return true, true, diags
+	}
+	if err != nil {
+		// The errors captured in "err" should be redundant with what we
+		// received via the InstallerEvents callbacks above, so we'll
+		// just return those as long as we have some.
+		if !diags.HasErrors() {
+			diags = diags.Append(err)
+		}
+
+		return true, true, diags
+	}
+
+	// If the provider dependencies have changed since the last run then we'll
+	// say a little about that in case the reader wasn't expecting a change.
+	// (When we later integrate module dependencies into the lock file we'll
+	// probably want to refactor this so that we produce one lock-file related
+	// message for all changes together, but this is here for now just because
+	// it's the smallest change relative to what came before it, which was
+	// a hidden JSON file specifically for tracking providers.)
+	if !newLocks.Equal(previousLocks) {
+		// if readonly mode
+		if flagLockfile == "readonly" {
+			// check if required provider dependences change
+			if !newLocks.EqualProviderAddress(previousLocks) {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					`Provider dependency changes detected`,
+					`Changes to the required provider dependencies were detected, but the lock file is read-only. To use and record these requirements, run "terraform init" without the "-lockfile=readonly" flag.`,
+				))
+				return true, true, diags
+			}
+
+			// suppress updating the file to record any new information it learned,
+			// such as a hash using a new scheme.
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Warning,
+				`Provider lock file not updated`,
+				`Changes to the provider selections were detected, but not saved in the .terraform.lock.hcl file. To record these selections, run "terraform init" without the "-lockfile=readonly" flag.`,
+			))
+			return true, false, diags
+		}
+
+		// Jump in here and add a warning if any of the providers are incomplete.
+		if len(incompleteProviders) > 0 {
+			// We don't really care about the order here, we just want the
+			// output to be deterministic.
+			sort.Slice(incompleteProviders, func(i, j int) bool {
+				return incompleteProviders[i] < incompleteProviders[j]
+			})
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Warning,
+				incompleteLockFileInformationHeader,
+				fmt.Sprintf(
+					incompleteLockFileInformationBody,
+					strings.Join(incompleteProviders, "\n  - "),
+					getproviders.CurrentPlatform.String())))
+		}
+
+		if previousLocks.Empty() {
+			// A change from empty to non-empty is special because it suggests
+			// we're running "terraform init" for the first time against a
+			// new configuration. In that case we'll take the opportunity to
+			// say a little about what the dependency lock file is, for new
+			// users or those who are upgrading from a previous Terraform
+			// version that didn't have dependency lock files.
+			c.Ui.Output(c.Colorize().Color(`
+Terraform has created a lock file [bold].terraform.lock.hcl[reset] to record the provider
+selections it made above. Include this file in your version control repository
+so that Terraform can guarantee to make the same selections by default when
+you run "terraform init" in the future.`))
+		} else {
+			c.Ui.Output(c.Colorize().Color(`
+Terraform has made some changes to the provider dependency selections recorded
+in the .terraform.lock.hcl file. Review those changes and commit them to your
+version control system if they represent changes you intended to make.`))
+		}
+
+		moreDiags = c.replaceLockedDependencies(newLocks)
+		diags = diags.Append(moreDiags)
+	}
+
+	return true, false, diags
+}
+
+// backendConfigOverrideBody interprets the raw values of -backend-config
+// arguments into a hcl Body that should override the backend settings given
+// in the configuration.
+//
+// If the result is nil then no override needs to be provided.
+//
+// If the returned diagnostics contains errors then the returned body may be
+// incomplete or invalid.
+func (c *InitCommand) backendConfigOverrideBody(flags rawFlags, schema *configschema.Block) (hcl.Body, tfdiags.Diagnostics) {
+	items := flags.AllItems()
+	if len(items) == 0 {
+		return nil, nil
+	}
+
+	var ret hcl.Body
+	var diags tfdiags.Diagnostics
+	synthVals := make(map[string]cty.Value)
+
+	mergeBody := func(newBody hcl.Body) {
+		if ret == nil {
+			ret = newBody
+		} else {
+			ret = configs.MergeBodies(ret, newBody)
+		}
+	}
+	flushVals := func() {
+		if len(synthVals) == 0 {
+			return
+		}
+		newBody := configs.SynthBody("-backend-config=...", synthVals)
+		mergeBody(newBody)
+		synthVals = make(map[string]cty.Value)
+	}
+
+	if len(items) == 1 && items[0].Value == "" {
+		// Explicitly remove all -backend-config options.
+		// We do this by setting an empty but non-nil ConfigOverrides.
+		return configs.SynthBody("-backend-config=''", synthVals), diags
+	}
+
+	for _, item := range items {
+		eq := strings.Index(item.Value, "=")
+
+		if eq == -1 {
+			// The value is interpreted as a filename.
+			newBody, fileDiags := c.loadHCLFile(item.Value)
+			diags = diags.Append(fileDiags)
+			if fileDiags.HasErrors() {
+				continue
+			}
+			// Generate an HCL body schema for the backend block.
+			var bodySchema hcl.BodySchema
+			for name := range schema.Attributes {
+				// We intentionally ignore the `Required` attribute here
+				// because backend config override files can be partial. The
+				// goal is to make sure we're not loading a file with
+				// extraneous attributes or blocks.
+				bodySchema.Attributes = append(bodySchema.Attributes, hcl.AttributeSchema{
+					Name: name,
+				})
+			}
+			for name, block := range schema.BlockTypes {
+				var labelNames []string
+				if block.Nesting == configschema.NestingMap {
+					labelNames = append(labelNames, "key")
+				}
+				bodySchema.Blocks = append(bodySchema.Blocks, hcl.BlockHeaderSchema{
+					Type:       name,
+					LabelNames: labelNames,
+				})
+			}
+			// Verify that the file body matches the expected backend schema.
+			_, schemaDiags := newBody.Content(&bodySchema)
+			diags = diags.Append(schemaDiags)
+			if schemaDiags.HasErrors() {
+				continue
+			}
+			flushVals() // deal with any accumulated individual values first
+			mergeBody(newBody)
+		} else {
+			name := item.Value[:eq]
+			rawValue := item.Value[eq+1:]
+			attrS := schema.Attributes[name]
+			if attrS == nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid backend configuration argument",
+					fmt.Sprintf("The backend configuration argument %q given on the command line is not expected for the selected backend type.", name),
+				))
+				continue
+			}
+			value, valueDiags := configValueFromCLI(item.String(), rawValue, attrS.Type)
+			diags = diags.Append(valueDiags)
+			if valueDiags.HasErrors() {
+				continue
+			}
+			synthVals[name] = value
+		}
+	}
+
+	flushVals()
+
+	return ret, diags
+}
+
+func (c *InitCommand) AutocompleteArgs() complete.Predictor {
+	return complete.PredictDirs("")
+}
+
+func (c *InitCommand) AutocompleteFlags() complete.Flags {
+	return complete.Flags{
+		"-backend":        completePredictBoolean,
+		"-cloud":          completePredictBoolean,
+		"-backend-config": complete.PredictFiles("*.tfvars"), // can also be key=value, but we can't "predict" that
+		"-force-copy":     complete.PredictNothing,
+		"-from-module":    completePredictModuleSource,
+		"-get":            completePredictBoolean,
+		"-input":          completePredictBoolean,
+		"-lock":           completePredictBoolean,
+		"-lock-timeout":   complete.PredictAnything,
+		"-no-color":       complete.PredictNothing,
+		"-plugin-dir":     complete.PredictDirs(""),
+		"-reconfigure":    complete.PredictNothing,
+		"-migrate-state":  complete.PredictNothing,
+		"-upgrade":        completePredictBoolean,
+	}
+}
+
+func (c *InitCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] init [options]
+
+  Initialize a new or existing Terraform working directory by creating
+  initial files, loading any remote state, downloading modules, etc.
+
+  This is the first command that should be run for any new or existing
+  Terraform configuration per machine. This sets up all the local data
+  necessary to run Terraform that is typically not committed to version
+  control.
+
+  This command is always safe to run multiple times. Though subsequent runs
+  may give errors, this command will never delete your configuration or
+  state. Even so, if you have important information, please back it up prior
+  to running this command, just in case.
+
+Options:
+
+  -backend=false          Disable backend or Terraform Cloud initialization
+                          for this configuration and use what was previously
+                          initialized instead.
+
+                          aliases: -cloud=false
+
+  -backend-config=path    Configuration to be merged with what is in the
+                          configuration file's 'backend' block. This can be
+                          either a path to an HCL file with key/value
+                          assignments (same format as terraform.tfvars) or a
+                          'key=value' format, and can be specified multiple
+                          times. The backend type must be in the configuration
+                          itself.
+
+  -force-copy             Suppress prompts about copying state data when
+                          initializating a new state backend. This is
+                          equivalent to providing a "yes" to all confirmation
+                          prompts.
+
+  -from-module=SOURCE     Copy the contents of the given module into the target
+                          directory before initialization.
+
+  -get=false              Disable downloading modules for this configuration.
+
+  -input=false            Disable interactive prompts. Note that some actions may
+                          require interactive prompts and will error if input is
+                          disabled.
+
+  -lock=false             Don't hold a state lock during backend migration.
+                          This is dangerous if others might concurrently run
+                          commands against the same workspace.
+
+  -lock-timeout=0s        Duration to retry a state lock.
+
+  -no-color               If specified, output won't contain any color.
+
+  -plugin-dir             Directory containing plugin binaries. This overrides all
+                          default search paths for plugins, and prevents the
+                          automatic installation of plugins. This flag can be used
+                          multiple times.
+
+  -reconfigure            Reconfigure a backend, ignoring any saved
+                          configuration.
+
+  -migrate-state          Reconfigure a backend, and attempt to migrate any
+                          existing state.
+
+  -upgrade                Install the latest module and provider versions
+                          allowed within configured constraints, overriding the
+                          default behavior of selecting exactly the version
+                          recorded in the dependency lockfile.
+
+  -lockfile=MODE          Set a dependency lockfile mode.
+                          Currently only "readonly" is valid.
+
+  -ignore-remote-version  A rare option used for Terraform Cloud and the remote backend
+                          only. Set this to ignore checking that the local and remote
+                          Terraform versions use compatible state representations, making
+                          an operation proceed even when there is a potential mismatch.
+                          See the documentation on configuring Terraform with
+                          Terraform Cloud for more information.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *InitCommand) Synopsis() string {
+	return "Prepare your working directory for other commands"
+}
+
+const errInitConfigError = `
+[reset]Terraform encountered problems during initialisation, including problems
+with the configuration, described below.
+
+The Terraform configuration must be valid before initialization so that
+Terraform can determine which modules and providers need to be installed.
+`
+
+const errInitCopyNotEmpty = `
+The working directory already contains files. The -from-module option requires
+an empty directory into which a copy of the referenced module will be placed.
+
+To initialize the configuration already in this working directory, omit the
+-from-module option.
+`
+
+const outputInitEmpty = `
+[reset][bold]Terraform initialized in an empty directory![reset]
+
+The directory has no Terraform configuration files. You may begin working
+with Terraform immediately by creating Terraform configuration files.
+`
+
+const outputInitSuccess = `
+[reset][bold][green]Terraform has been successfully initialized![reset][green]
+`
+
+const outputInitSuccessCloud = `
+[reset][bold][green]Terraform Cloud has been successfully initialized![reset][green]
+`
+
+const outputInitSuccessCLI = `[reset][green]
+You may now begin working with Terraform. Try running "terraform plan" to see
+any changes that are required for your infrastructure. All Terraform commands
+should now work.
+
+If you ever set or change modules or backend configuration for Terraform,
+rerun this command to reinitialize your working directory. If you forget, other
+commands will detect it and remind you to do so if necessary.
+`
+
+const outputInitSuccessCLICloud = `[reset][green]
+You may now begin working with Terraform Cloud. Try running "terraform plan" to
+see any changes that are required for your infrastructure.
+
+If you ever set or change modules or Terraform Settings, run "terraform init"
+again to reinitialize your working directory.
+`
+
+// providerProtocolTooOld is a message sent to the CLI UI if the provider's
+// supported protocol versions are too old for the user's version of terraform,
+// but a newer version of the provider is compatible.
+const providerProtocolTooOld = `Provider %q v%s is not compatible with Terraform %s.
+Provider version %s is the latest compatible version. Select it with the following version constraint:
+	version = %q
+
+Terraform checked all of the plugin versions matching the given constraint:
+	%s
+
+Consult the documentation for this provider for more information on compatibility between provider and Terraform versions.
+`
+
+// providerProtocolTooNew is a message sent to the CLI UI if the provider's
+// supported protocol versions are too new for the user's version of terraform,
+// and the user could either upgrade terraform or choose an older version of the
+// provider.
+const providerProtocolTooNew = `Provider %q v%s is not compatible with Terraform %s.
+You need to downgrade to v%s or earlier. Select it with the following constraint:
+	version = %q
+
+Terraform checked all of the plugin versions matching the given constraint:
+	%s
+
+Consult the documentation for this provider for more information on compatibility between provider and Terraform versions.
+Alternatively, upgrade to the latest version of Terraform for compatibility with newer provider releases.
+`
+
+// No version of the provider is compatible.
+const errProviderVersionIncompatible = `No compatible versions of provider %s were found.`
+
+// incompleteLockFileInformationHeader is the summary displayed to users when
+// the lock file has only recorded local hashes.
+const incompleteLockFileInformationHeader = `Incomplete lock file information for providers`
+
+// incompleteLockFileInformationBody is the body of text displayed to users when
+// the lock file has only recorded local hashes.
+const incompleteLockFileInformationBody = `Due to your customized provider installation methods, Terraform was forced to calculate lock file checksums locally for the following providers:
+  - %s
+
+The current .terraform.lock.hcl file only includes checksums for %s, so Terraform running on another platform will fail to install these providers.
+
+To calculate additional checksums for another platform, run:
+  terraform providers lock -platform=linux_amd64
+(where linux_amd64 is the platform to generate)`
diff --git a/v1.5.7/internal/command/init_test.go b/v1.5.7/internal/command/init_test.go
new file mode 100644
index 0000000..5162bc6
--- /dev/null
+++ b/v1.5.7/internal/command/init_test.go
@@ -0,0 +1,2884 @@
+package command
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/google/go-cmp/cmp"
+	"github.com/mitchellh/cli"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/go-version"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/hashicorp/terraform/internal/providercache"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+func TestInit_empty(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+}
+
+func TestInit_multipleArgs(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"bad",
+		"bad",
+	}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad: \n%s", ui.OutputWriter.String())
+	}
+}
+
+func TestInit_fromModule_cwdDest(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	os.MkdirAll(td, os.ModePerm)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-from-module=" + testFixturePath("init"),
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	if _, err := os.Stat(filepath.Join(td, "hello.tf")); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+}
+
+// https://github.com/hashicorp/terraform/issues/518
+func TestInit_fromModule_dstInSrc(t *testing.T) {
+	dir := t.TempDir()
+	if err := os.MkdirAll(dir, 0755); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Change to the temporary directory
+	cwd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if err := os.Chdir(dir); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer os.Chdir(cwd)
+
+	if err := os.Mkdir("foo", os.ModePerm); err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err := os.Create("issue518.tf"); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if err := os.Chdir("foo"); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-from-module=./..",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	if _, err := os.Stat(filepath.Join(dir, "foo", "issue518.tf")); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+}
+
+func TestInit_get(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-get"), td)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	// Check output
+	output := ui.OutputWriter.String()
+	if !strings.Contains(output, "foo in foo") {
+		t.Fatalf("doesn't look like we installed module 'foo': %s", output)
+	}
+}
+
+func TestInit_getUpgradeModules(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-get"), td)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-get=true",
+		"-upgrade",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("command did not complete successfully:\n%s", ui.ErrorWriter.String())
+	}
+
+	// Check output
+	output := ui.OutputWriter.String()
+	if !strings.Contains(output, "Upgrading modules...") {
+		t.Fatalf("doesn't look like get upgrade: %s", output)
+	}
+}
+
+func TestInit_backend(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend"), td)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	if _, err := os.Stat(filepath.Join(DefaultDataDir, DefaultStateFilename)); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+}
+
+func TestInit_backendUnset(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend"), td)
+	defer testChdir(t, td)()
+
+	{
+		log.Printf("[TRACE] TestInit_backendUnset: beginning first init")
+
+		ui := cli.NewMockUi()
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(testProvider()),
+				Ui:               ui,
+				View:             view,
+			},
+		}
+
+		// Init
+		args := []string{}
+		if code := c.Run(args); code != 0 {
+			t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+		}
+		log.Printf("[TRACE] TestInit_backendUnset: first init complete")
+		t.Logf("First run output:\n%s", ui.OutputWriter.String())
+		t.Logf("First run errors:\n%s", ui.ErrorWriter.String())
+
+		if _, err := os.Stat(filepath.Join(DefaultDataDir, DefaultStateFilename)); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		log.Printf("[TRACE] TestInit_backendUnset: beginning second init")
+
+		// Unset
+		if err := ioutil.WriteFile("main.tf", []byte(""), 0644); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		ui := cli.NewMockUi()
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(testProvider()),
+				Ui:               ui,
+				View:             view,
+			},
+		}
+
+		args := []string{"-force-copy"}
+		if code := c.Run(args); code != 0 {
+			t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+		}
+		log.Printf("[TRACE] TestInit_backendUnset: second init complete")
+		t.Logf("Second run output:\n%s", ui.OutputWriter.String())
+		t.Logf("Second run errors:\n%s", ui.ErrorWriter.String())
+
+		s := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
+		if !s.Backend.Empty() {
+			t.Fatal("should not have backend config")
+		}
+	}
+}
+
+func TestInit_backendConfigFile(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend-config-file"), td)
+	defer testChdir(t, td)()
+
+	t.Run("good-config-file", func(t *testing.T) {
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(testProvider()),
+				Ui:               ui,
+				View:             view,
+			},
+		}
+		args := []string{"-backend-config", "input.config"}
+		if code := c.Run(args); code != 0 {
+			t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+		}
+
+		// Read our saved backend config and verify we have our settings
+		state := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
+		if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":"hello","workspace_dir":null}`; got != want {
+			t.Errorf("wrong config\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+
+	// the backend config file must not be a full terraform block
+	t.Run("full-backend-config-file", func(t *testing.T) {
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(testProvider()),
+				Ui:               ui,
+				View:             view,
+			},
+		}
+		args := []string{"-backend-config", "backend.config"}
+		if code := c.Run(args); code != 1 {
+			t.Fatalf("expected error, got success\n")
+		}
+		if !strings.Contains(ui.ErrorWriter.String(), "Unsupported block type") {
+			t.Fatalf("wrong error: %s", ui.ErrorWriter)
+		}
+	})
+
+	// the backend config file must match the schema for the backend
+	t.Run("invalid-config-file", func(t *testing.T) {
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(testProvider()),
+				Ui:               ui,
+				View:             view,
+			},
+		}
+		args := []string{"-backend-config", "invalid.config"}
+		if code := c.Run(args); code != 1 {
+			t.Fatalf("expected error, got success\n")
+		}
+		if !strings.Contains(ui.ErrorWriter.String(), "Unsupported argument") {
+			t.Fatalf("wrong error: %s", ui.ErrorWriter)
+		}
+	})
+
+	// missing file is an error
+	t.Run("missing-config-file", func(t *testing.T) {
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(testProvider()),
+				Ui:               ui,
+				View:             view,
+			},
+		}
+		args := []string{"-backend-config", "missing.config"}
+		if code := c.Run(args); code != 1 {
+			t.Fatalf("expected error, got success\n")
+		}
+		if !strings.Contains(ui.ErrorWriter.String(), "Failed to read file") {
+			t.Fatalf("wrong error: %s", ui.ErrorWriter)
+		}
+	})
+
+	// blank filename clears the backend config
+	t.Run("blank-config-file", func(t *testing.T) {
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(testProvider()),
+				Ui:               ui,
+				View:             view,
+			},
+		}
+		args := []string{"-backend-config=", "-migrate-state"}
+		if code := c.Run(args); code != 0 {
+			t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+		}
+
+		// Read our saved backend config and verify the backend config is empty
+		state := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
+		if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":null,"workspace_dir":null}`; got != want {
+			t.Errorf("wrong config\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+
+	// simulate the local backend having a required field which is not
+	// specified in the override file
+	t.Run("required-argument", func(t *testing.T) {
+		c := &InitCommand{}
+		schema := &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"path": {
+					Type:     cty.String,
+					Optional: true,
+				},
+				"workspace_dir": {
+					Type:     cty.String,
+					Required: true,
+				},
+			},
+		}
+		flagConfigExtra := newRawFlags("-backend-config")
+		flagConfigExtra.Set("input.config")
+		_, diags := c.backendConfigOverrideBody(flagConfigExtra, schema)
+		if len(diags) != 0 {
+			t.Errorf("expected no diags, got: %s", diags.Err())
+		}
+	})
+}
+
+func TestInit_backendConfigFilePowershellConfusion(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend-config-file"), td)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	// SUBTLE: when using -flag=value with Powershell, unquoted values are
+	// broken into separate arguments. This results in the init command
+	// interpreting the flags as an empty backend-config setting (which is
+	// semantically valid!) followed by a custom configuration path.
+	//
+	// Adding the "=" here forces this codepath to be checked, and it should
+	// result in an early exit with a diagnostic that the provided
+	// configuration file is not a diretory.
+	args := []string{"-backend-config=", "./input.config"}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
+	}
+
+	output := ui.ErrorWriter.String()
+	if got, want := output, `Too many command line arguments`; !strings.Contains(got, want) {
+		t.Fatalf("wrong output\ngot:\n%s\n\nwant: message containing %q", got, want)
+	}
+}
+
+func TestInit_backendReconfigure(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend"), td)
+	defer testChdir(t, td)()
+
+	providerSource, close := newMockProviderSource(t, map[string][]string{
+		"hashicorp/test": {"1.2.3"},
+	})
+	defer close()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			ProviderSource:   providerSource,
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	// create some state, so the backend has something to migrate.
+	f, err := os.Create("foo") // this is the path" in the backend config
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	err = writeStateForTesting(testState(), f)
+	f.Close()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	// now run init again, changing the path.
+	// The -reconfigure flag prevents init from migrating
+	// Without -reconfigure, the test fails since the backend asks for input on migrating state
+	args = []string{"-reconfigure", "-backend-config", "path=changed"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+}
+
+func TestInit_backendConfigFileChange(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend-config-file-change"), td)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"-backend-config", "input.config", "-migrate-state"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	// Read our saved backend config and verify we have our settings
+	state := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
+	if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":"hello","workspace_dir":null}`; got != want {
+		t.Errorf("wrong config\ngot:  %s\nwant: %s", got, want)
+	}
+}
+
+func TestInit_backendMigrateWhileLocked(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend-migrate-while-locked"), td)
+	defer testChdir(t, td)()
+
+	providerSource, close := newMockProviderSource(t, map[string][]string{
+		"hashicorp/test": {"1.2.3"},
+	})
+	defer close()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			ProviderSource:   providerSource,
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	// Create some state, so the backend has something to migrate from
+	f, err := os.Create("local-state.tfstate")
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	err = writeStateForTesting(testState(), f)
+	f.Close()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Lock the source state
+	unlock, err := testLockState(t, testDataDir, "local-state.tfstate")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer unlock()
+
+	// Attempt to migrate
+	args := []string{"-backend-config", "input.config", "-migrate-state", "-force-copy"}
+	if code := c.Run(args); code == 0 {
+		t.Fatalf("expected nonzero exit code: %s", ui.OutputWriter.String())
+	}
+
+	// Disabling locking should work
+	args = []string{"-backend-config", "input.config", "-migrate-state", "-force-copy", "-lock=false"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("expected zero exit code, got %d: %s", code, ui.ErrorWriter.String())
+	}
+}
+
+func TestInit_backendConfigFileChangeWithExistingState(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend-config-file-change-migrate-existing"), td)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+		},
+	}
+
+	oldState := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
+
+	// we deliberately do not provide the answer for backend-migrate-copy-to-empty to trigger error
+	args := []string{"-migrate-state", "-backend-config", "input.config", "-input=true"}
+	if code := c.Run(args); code == 0 {
+		t.Fatal("expected error")
+	}
+
+	// Read our backend config and verify new settings are not saved
+	state := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
+	if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":"local-state.tfstate"}`; got != want {
+		t.Errorf("wrong config\ngot:  %s\nwant: %s", got, want)
+	}
+
+	// without changing config, hash should not change
+	if oldState.Backend.Hash != state.Backend.Hash {
+		t.Errorf("backend hash should not have changed\ngot:  %d\nwant: %d", state.Backend.Hash, oldState.Backend.Hash)
+	}
+}
+
+func TestInit_backendConfigKV(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend-config-kv"), td)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"-backend-config", "path=hello"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	// Read our saved backend config and verify we have our settings
+	state := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
+	if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":"hello","workspace_dir":null}`; got != want {
+		t.Errorf("wrong config\ngot:  %s\nwant: %s", got, want)
+	}
+}
+
+func TestInit_backendConfigKVReInit(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend-config-kv"), td)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"-backend-config", "path=test"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	ui = new(cli.MockUi)
+	c = &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	// a second init should require no changes, nor should it change the backend.
+	args = []string{"-input=false"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	// make sure the backend is configured how we expect
+	configState := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
+	cfg := map[string]interface{}{}
+	if err := json.Unmarshal(configState.Backend.ConfigRaw, &cfg); err != nil {
+		t.Fatal(err)
+	}
+	if cfg["path"] != "test" {
+		t.Fatalf(`expected backend path="test", got path="%v"`, cfg["path"])
+	}
+
+	// override the -backend-config options by settings
+	args = []string{"-input=false", "-backend-config", "", "-migrate-state"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	// make sure the backend is configured how we expect
+	configState = testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
+	cfg = map[string]interface{}{}
+	if err := json.Unmarshal(configState.Backend.ConfigRaw, &cfg); err != nil {
+		t.Fatal(err)
+	}
+	if cfg["path"] != nil {
+		t.Fatalf(`expected backend path="<nil>", got path="%v"`, cfg["path"])
+	}
+}
+
+func TestInit_backendConfigKVReInitWithConfigDiff(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend"), td)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"-input=false"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	ui = new(cli.MockUi)
+	c = &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	// a second init with identical config should require no changes, nor
+	// should it change the backend.
+	args = []string{"-input=false", "-backend-config", "path=foo"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	// make sure the backend is configured how we expect
+	configState := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
+	cfg := map[string]interface{}{}
+	if err := json.Unmarshal(configState.Backend.ConfigRaw, &cfg); err != nil {
+		t.Fatal(err)
+	}
+	if cfg["path"] != "foo" {
+		t.Fatalf(`expected backend path="foo", got path="%v"`, cfg["foo"])
+	}
+}
+
+func TestInit_backendCli_no_config_block(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init"), td)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"-backend-config", "path=test"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("got exit status %d; want 0\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
+	}
+
+	errMsg := ui.ErrorWriter.String()
+	if !strings.Contains(errMsg, "Warning: Missing backend configuration") {
+		t.Fatal("expected missing backend block warning, got", errMsg)
+	}
+}
+
+func TestInit_backendReinitWithExtra(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend-empty"), td)
+	defer testChdir(t, td)()
+
+	m := testMetaBackend(t, nil)
+	opts := &BackendOpts{
+		ConfigOverride: configs.SynthBody("synth", map[string]cty.Value{
+			"path": cty.StringVal("hello"),
+		}),
+		Init: true,
+	}
+
+	_, cHash, err := m.backendConfig(opts)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"-backend-config", "path=hello"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	// Read our saved backend config and verify we have our settings
+	state := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
+	if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":"hello","workspace_dir":null}`; got != want {
+		t.Errorf("wrong config\ngot:  %s\nwant: %s", got, want)
+	}
+
+	if state.Backend.Hash != uint64(cHash) {
+		t.Fatal("mismatched state and config backend hashes")
+	}
+
+	// init again and make sure nothing changes
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+	state = testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
+	if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":"hello","workspace_dir":null}`; got != want {
+		t.Errorf("wrong config\ngot:  %s\nwant: %s", got, want)
+	}
+	if state.Backend.Hash != uint64(cHash) {
+		t.Fatal("mismatched state and config backend hashes")
+	}
+}
+
+// move option from config to -backend-config args
+func TestInit_backendReinitConfigToExtra(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend"), td)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	if code := c.Run([]string{"-input=false"}); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	// Read our saved backend config and verify we have our settings
+	state := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
+	if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":"foo","workspace_dir":null}`; got != want {
+		t.Errorf("wrong config\ngot:  %s\nwant: %s", got, want)
+	}
+
+	backendHash := state.Backend.Hash
+
+	// init again but remove the path option from the config
+	cfg := "terraform {\n  backend \"local\" {}\n}\n"
+	if err := ioutil.WriteFile("main.tf", []byte(cfg), 0644); err != nil {
+		t.Fatal(err)
+	}
+
+	// We need a fresh InitCommand here because the old one now has our configuration
+	// file cached inside it, so it won't re-read the modification we just made.
+	c = &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"-input=false", "-backend-config=path=foo"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+	state = testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
+	if got, want := normalizeJSON(t, state.Backend.ConfigRaw), `{"path":"foo","workspace_dir":null}`; got != want {
+		t.Errorf("wrong config after moving to arg\ngot:  %s\nwant: %s", got, want)
+	}
+
+	if state.Backend.Hash == backendHash {
+		t.Fatal("state.Backend.Hash was not updated")
+	}
+}
+
+func TestInit_backendCloudInvalidOptions(t *testing.T) {
+	// There are various "terraform init" options that are only for
+	// traditional backends and not applicable to Terraform Cloud mode.
+	// For those, we want to return an explicit error rather than
+	// just silently ignoring them, so that users will be aware that
+	// Cloud mode has more of an expected "happy path" than the
+	// less-vertically-integrated backends do, and to avoid these
+	// unapplicable options becoming compatibility constraints for
+	// future evolution of Cloud mode.
+
+	// We use the same starting fixture for all of these tests, but some
+	// of them will customize it a bit as part of their work.
+	setupTempDir := func(t *testing.T) func() {
+		t.Helper()
+		td := t.TempDir()
+		testCopyDir(t, testFixturePath("init-cloud-simple"), td)
+		unChdir := testChdir(t, td)
+		return unChdir
+	}
+
+	// Some of the tests need a non-empty placeholder state file to work
+	// with.
+	fakeState := states.BuildState(func(cb *states.SyncState) {
+		// Having a root module output value should be enough for this
+		// state file to be considered "non-empty" and thus a candidate
+		// for migration.
+		cb.SetOutputValue(
+			addrs.OutputValue{Name: "a"}.Absolute(addrs.RootModuleInstance),
+			cty.True,
+			false,
+		)
+	})
+	fakeStateFile := &statefile.File{
+		Lineage:          "boop",
+		Serial:           4,
+		TerraformVersion: version.Must(version.NewVersion("1.0.0")),
+		State:            fakeState,
+	}
+	var fakeStateBuf bytes.Buffer
+	err := statefile.WriteForTest(fakeStateFile, &fakeStateBuf)
+	if err != nil {
+		t.Error(err)
+	}
+	fakeStateBytes := fakeStateBuf.Bytes()
+
+	t.Run("-backend-config", func(t *testing.T) {
+		defer setupTempDir(t)()
+
+		// We have -backend-config as a pragmatic way to dynamically set
+		// certain settings of backends that tend to vary depending on
+		// where Terraform is running, such as AWS authentication profiles
+		// that are naturally local only to the machine where Terraform is
+		// running. Those needs don't apply to Terraform Cloud, because
+		// the remote workspace encapsulates all of the details of how
+		// operations and state work in that case, and so the Cloud
+		// configuration is only about which workspaces we'll be working
+		// with.
+		ui := cli.NewMockUi()
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				Ui:   ui,
+				View: view,
+			},
+		}
+		args := []string{"-backend-config=anything"}
+		if code := c.Run(args); code == 0 {
+			t.Fatalf("unexpected success\n%s", ui.OutputWriter.String())
+		}
+
+		gotStderr := ui.ErrorWriter.String()
+		wantStderr := `
+Error: Invalid command-line option
+
+The -backend-config=... command line option is only for state backends, and
+is not applicable to Terraform Cloud-based configurations.
+
+To change the set of workspaces associated with this configuration, edit the
+Cloud configuration block in the root module.
+
+`
+		if diff := cmp.Diff(wantStderr, gotStderr); diff != "" {
+			t.Errorf("wrong error output\n%s", diff)
+		}
+	})
+	t.Run("-reconfigure", func(t *testing.T) {
+		defer setupTempDir(t)()
+
+		// The -reconfigure option was originally imagined as a way to force
+		// skipping state migration when migrating between backends, but it
+		// has a historical flaw that it doesn't work properly when the
+		// initial situation is the implicit local backend with a state file
+		// present. The Terraform Cloud migration path has some additional
+		// steps to take care of more details automatically, and so
+		// -reconfigure doesn't really make sense in that context, particularly
+		// with its design bug with the handling of the implicit local backend.
+		ui := cli.NewMockUi()
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				Ui:   ui,
+				View: view,
+			},
+		}
+		args := []string{"-reconfigure"}
+		if code := c.Run(args); code == 0 {
+			t.Fatalf("unexpected success\n%s", ui.OutputWriter.String())
+		}
+
+		gotStderr := ui.ErrorWriter.String()
+		wantStderr := `
+Error: Invalid command-line option
+
+The -reconfigure option is for in-place reconfiguration of state backends
+only, and is not needed when changing Terraform Cloud settings.
+
+When using Terraform Cloud, initialization automatically activates any new
+Cloud configuration settings.
+
+`
+		if diff := cmp.Diff(wantStderr, gotStderr); diff != "" {
+			t.Errorf("wrong error output\n%s", diff)
+		}
+	})
+	t.Run("-reconfigure when migrating in", func(t *testing.T) {
+		defer setupTempDir(t)()
+
+		// We have a slightly different error message for the case where we
+		// seem to be trying to migrate to Terraform Cloud with existing
+		// state or explicit backend already present.
+
+		if err := os.WriteFile("terraform.tfstate", fakeStateBytes, 0644); err != nil {
+			t.Fatal(err)
+		}
+
+		ui := cli.NewMockUi()
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				Ui:   ui,
+				View: view,
+			},
+		}
+		args := []string{"-reconfigure"}
+		if code := c.Run(args); code == 0 {
+			t.Fatalf("unexpected success\n%s", ui.OutputWriter.String())
+		}
+
+		gotStderr := ui.ErrorWriter.String()
+		wantStderr := `
+Error: Invalid command-line option
+
+The -reconfigure option is unsupported when migrating to Terraform Cloud,
+because activating Terraform Cloud involves some additional steps.
+
+`
+		if diff := cmp.Diff(wantStderr, gotStderr); diff != "" {
+			t.Errorf("wrong error output\n%s", diff)
+		}
+	})
+	t.Run("-migrate-state", func(t *testing.T) {
+		defer setupTempDir(t)()
+
+		// In Cloud mode, migrating in or out always proposes migrating state
+		// and changing configuration while staying in cloud mode never migrates
+		// state, so this special option isn't relevant.
+		ui := cli.NewMockUi()
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				Ui:   ui,
+				View: view,
+			},
+		}
+		args := []string{"-migrate-state"}
+		if code := c.Run(args); code == 0 {
+			t.Fatalf("unexpected success\n%s", ui.OutputWriter.String())
+		}
+
+		gotStderr := ui.ErrorWriter.String()
+		wantStderr := `
+Error: Invalid command-line option
+
+The -migrate-state option is for migration between state backends only, and
+is not applicable when using Terraform Cloud.
+
+State storage is handled automatically by Terraform Cloud and so the state
+storage location is not configurable.
+
+`
+		if diff := cmp.Diff(wantStderr, gotStderr); diff != "" {
+			t.Errorf("wrong error output\n%s", diff)
+		}
+	})
+	t.Run("-migrate-state when migrating in", func(t *testing.T) {
+		defer setupTempDir(t)()
+
+		// We have a slightly different error message for the case where we
+		// seem to be trying to migrate to Terraform Cloud with existing
+		// state or explicit backend already present.
+
+		if err := os.WriteFile("terraform.tfstate", fakeStateBytes, 0644); err != nil {
+			t.Fatal(err)
+		}
+
+		ui := cli.NewMockUi()
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				Ui:   ui,
+				View: view,
+			},
+		}
+		args := []string{"-migrate-state"}
+		if code := c.Run(args); code == 0 {
+			t.Fatalf("unexpected success\n%s", ui.OutputWriter.String())
+		}
+
+		gotStderr := ui.ErrorWriter.String()
+		wantStderr := `
+Error: Invalid command-line option
+
+The -migrate-state option is for migration between state backends only, and
+is not applicable when using Terraform Cloud.
+
+Terraform Cloud migration has additional steps, configured by interactive
+prompts.
+
+`
+		if diff := cmp.Diff(wantStderr, gotStderr); diff != "" {
+			t.Errorf("wrong error output\n%s", diff)
+		}
+	})
+	t.Run("-force-copy", func(t *testing.T) {
+		defer setupTempDir(t)()
+
+		// In Cloud mode, migrating in or out always proposes migrating state
+		// and changing configuration while staying in cloud mode never migrates
+		// state, so this special option isn't relevant.
+		ui := cli.NewMockUi()
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				Ui:   ui,
+				View: view,
+			},
+		}
+		args := []string{"-force-copy"}
+		if code := c.Run(args); code == 0 {
+			t.Fatalf("unexpected success\n%s", ui.OutputWriter.String())
+		}
+
+		gotStderr := ui.ErrorWriter.String()
+		wantStderr := `
+Error: Invalid command-line option
+
+The -force-copy option is for migration between state backends only, and is
+not applicable when using Terraform Cloud.
+
+State storage is handled automatically by Terraform Cloud and so the state
+storage location is not configurable.
+
+`
+		if diff := cmp.Diff(wantStderr, gotStderr); diff != "" {
+			t.Errorf("wrong error output\n%s", diff)
+		}
+	})
+	t.Run("-force-copy when migrating in", func(t *testing.T) {
+		defer setupTempDir(t)()
+
+		// We have a slightly different error message for the case where we
+		// seem to be trying to migrate to Terraform Cloud with existing
+		// state or explicit backend already present.
+
+		if err := os.WriteFile("terraform.tfstate", fakeStateBytes, 0644); err != nil {
+			t.Fatal(err)
+		}
+
+		ui := cli.NewMockUi()
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				Ui:   ui,
+				View: view,
+			},
+		}
+		args := []string{"-force-copy"}
+		if code := c.Run(args); code == 0 {
+			t.Fatalf("unexpected success\n%s", ui.OutputWriter.String())
+		}
+
+		gotStderr := ui.ErrorWriter.String()
+		wantStderr := `
+Error: Invalid command-line option
+
+The -force-copy option is for migration between state backends only, and is
+not applicable when using Terraform Cloud.
+
+Terraform Cloud migration has additional steps, configured by interactive
+prompts.
+
+`
+		if diff := cmp.Diff(wantStderr, gotStderr); diff != "" {
+			t.Errorf("wrong error output\n%s", diff)
+		}
+	})
+
+}
+
+// make sure inputFalse stops execution on migrate
+func TestInit_inputFalse(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend"), td)
+	defer testChdir(t, td)()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"-input=false", "-backend-config=path=foo"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter)
+	}
+
+	// write different states for foo and bar
+	fooState := states.BuildState(func(s *states.SyncState) {
+		s.SetOutputValue(
+			addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance),
+			cty.StringVal("foo"),
+			false, // not sensitive
+		)
+	})
+	if err := statemgr.NewFilesystem("foo").WriteState(fooState); err != nil {
+		t.Fatal(err)
+	}
+	barState := states.BuildState(func(s *states.SyncState) {
+		s.SetOutputValue(
+			addrs.OutputValue{Name: "bar"}.Absolute(addrs.RootModuleInstance),
+			cty.StringVal("bar"),
+			false, // not sensitive
+		)
+	})
+	if err := statemgr.NewFilesystem("bar").WriteState(barState); err != nil {
+		t.Fatal(err)
+	}
+
+	ui = new(cli.MockUi)
+	c = &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args = []string{"-input=false", "-backend-config=path=bar", "-migrate-state"}
+	if code := c.Run(args); code == 0 {
+		t.Fatal("init should have failed", ui.OutputWriter)
+	}
+
+	errMsg := ui.ErrorWriter.String()
+	if !strings.Contains(errMsg, "interactive input is disabled") {
+		t.Fatal("expected input disabled error, got", errMsg)
+	}
+
+	ui = new(cli.MockUi)
+	c = &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	// A missing input=false should abort rather than loop infinitely
+	args = []string{"-backend-config=path=baz"}
+	if code := c.Run(args); code == 0 {
+		t.Fatal("init should have failed", ui.OutputWriter)
+	}
+}
+
+func TestInit_getProvider(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-get-providers"), td)
+	defer testChdir(t, td)()
+
+	overrides := metaOverridesForProvider(testProvider())
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	providerSource, close := newMockProviderSource(t, map[string][]string{
+		// looking for an exact version
+		"exact": {"1.2.3"},
+		// config requires >= 2.3.3
+		"greater-than": {"2.3.4", "2.3.3", "2.3.0"},
+		// config specifies
+		"between": {"3.4.5", "2.3.4", "1.2.3"},
+	})
+	defer close()
+	m := Meta{
+		testingOverrides: overrides,
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	args := []string{
+		"-backend=false", // should be possible to install plugins without backend init
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	// check that we got the providers for our config
+	exactPath := fmt.Sprintf(".terraform/providers/registry.terraform.io/hashicorp/exact/1.2.3/%s", getproviders.CurrentPlatform)
+	if _, err := os.Stat(exactPath); os.IsNotExist(err) {
+		t.Fatal("provider 'exact' not downloaded")
+	}
+	greaterThanPath := fmt.Sprintf(".terraform/providers/registry.terraform.io/hashicorp/greater-than/2.3.4/%s", getproviders.CurrentPlatform)
+	if _, err := os.Stat(greaterThanPath); os.IsNotExist(err) {
+		t.Fatal("provider 'greater-than' not downloaded")
+	}
+	betweenPath := fmt.Sprintf(".terraform/providers/registry.terraform.io/hashicorp/between/2.3.4/%s", getproviders.CurrentPlatform)
+	if _, err := os.Stat(betweenPath); os.IsNotExist(err) {
+		t.Fatal("provider 'between' not downloaded")
+	}
+
+	t.Run("future-state", func(t *testing.T) {
+		// getting providers should fail if a state from a newer version of
+		// terraform exists, since InitCommand.getProviders needs to inspect that
+		// state.
+
+		f, err := os.Create(DefaultStateFilename)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		defer f.Close()
+
+		// Construct a mock state file from the far future
+		type FutureState struct {
+			Version          uint                     `json:"version"`
+			Lineage          string                   `json:"lineage"`
+			TerraformVersion string                   `json:"terraform_version"`
+			Outputs          map[string]interface{}   `json:"outputs"`
+			Resources        []map[string]interface{} `json:"resources"`
+		}
+		fs := &FutureState{
+			Version:          999,
+			Lineage:          "123-456-789",
+			TerraformVersion: "999.0.0",
+			Outputs:          make(map[string]interface{}),
+			Resources:        make([]map[string]interface{}, 0),
+		}
+		src, err := json.MarshalIndent(fs, "", "  ")
+		if err != nil {
+			t.Fatalf("failed to marshal future state: %s", err)
+		}
+		src = append(src, '\n')
+		_, err = f.Write(src)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		m.Ui = ui
+		m.View = view
+		c := &InitCommand{
+			Meta: m,
+		}
+
+		if code := c.Run(nil); code == 0 {
+			t.Fatal("expected error, got:", ui.OutputWriter)
+		}
+
+		errMsg := ui.ErrorWriter.String()
+		if !strings.Contains(errMsg, "Unsupported state file format") {
+			t.Fatal("unexpected error:", errMsg)
+		}
+	})
+}
+
+func TestInit_getProviderSource(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-get-provider-source"), td)
+	defer testChdir(t, td)()
+
+	overrides := metaOverridesForProvider(testProvider())
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	providerSource, close := newMockProviderSource(t, map[string][]string{
+		// looking for an exact version
+		"acme/alpha": {"1.2.3"},
+		// config doesn't specify versions for other providers
+		"registry.example.com/acme/beta": {"1.0.0"},
+		"gamma":                          {"2.0.0"},
+	})
+	defer close()
+	m := Meta{
+		testingOverrides: overrides,
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	args := []string{
+		"-backend=false", // should be possible to install plugins without backend init
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	// check that we got the providers for our config
+	exactPath := fmt.Sprintf(".terraform/providers/registry.terraform.io/acme/alpha/1.2.3/%s", getproviders.CurrentPlatform)
+	if _, err := os.Stat(exactPath); os.IsNotExist(err) {
+		t.Error("provider 'alpha' not downloaded")
+	}
+	greaterThanPath := fmt.Sprintf(".terraform/providers/registry.example.com/acme/beta/1.0.0/%s", getproviders.CurrentPlatform)
+	if _, err := os.Stat(greaterThanPath); os.IsNotExist(err) {
+		t.Error("provider 'beta' not downloaded")
+	}
+	betweenPath := fmt.Sprintf(".terraform/providers/registry.terraform.io/hashicorp/gamma/2.0.0/%s", getproviders.CurrentPlatform)
+	if _, err := os.Stat(betweenPath); os.IsNotExist(err) {
+		t.Error("provider 'gamma' not downloaded")
+	}
+}
+
+func TestInit_getProviderLegacyFromState(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-get-provider-legacy-from-state"), td)
+	defer testChdir(t, td)()
+
+	overrides := metaOverridesForProvider(testProvider())
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	providerSource, close := newMockProviderSource(t, map[string][]string{
+		"acme/alpha": {"1.2.3"},
+	})
+	defer close()
+	m := Meta{
+		testingOverrides: overrides,
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	if code := c.Run(nil); code != 1 {
+		t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
+	}
+
+	// Expect this diagnostic output
+	wants := []string{
+		"Invalid legacy provider address",
+		"You must complete the Terraform 0.13 upgrade process",
+	}
+	got := ui.ErrorWriter.String()
+	for _, want := range wants {
+		if !strings.Contains(got, want) {
+			t.Fatalf("expected output to contain %q, got:\n\n%s", want, got)
+		}
+	}
+}
+
+func TestInit_getProviderInvalidPackage(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-get-provider-invalid-package"), td)
+	defer testChdir(t, td)()
+
+	overrides := metaOverridesForProvider(testProvider())
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+
+	// create a provider source which allows installing an invalid package
+	addr := addrs.MustParseProviderSourceString("invalid/package")
+	version := getproviders.MustParseVersion("1.0.0")
+	meta, close, err := getproviders.FakeInstallablePackageMeta(
+		addr,
+		version,
+		getproviders.VersionList{getproviders.MustParseVersion("5.0")},
+		getproviders.CurrentPlatform,
+		"terraform-package", // should be "terraform-provider-package"
+	)
+	defer close()
+	if err != nil {
+		t.Fatalf("failed to prepare fake package for %s %s: %s", addr.ForDisplay(), version, err)
+	}
+	providerSource := getproviders.NewMockSource([]getproviders.PackageMeta{meta}, nil)
+
+	m := Meta{
+		testingOverrides: overrides,
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	args := []string{
+		"-backend=false", // should be possible to install plugins without backend init
+	}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
+	}
+
+	// invalid provider should be installed
+	packagePath := fmt.Sprintf(".terraform/providers/registry.terraform.io/invalid/package/1.0.0/%s/terraform-package", getproviders.CurrentPlatform)
+	if _, err := os.Stat(packagePath); os.IsNotExist(err) {
+		t.Fatal("provider 'invalid/package' not downloaded")
+	}
+
+	wantErrors := []string{
+		"Failed to install provider",
+		"could not find executable file starting with terraform-provider-package",
+	}
+	got := ui.ErrorWriter.String()
+	for _, wantError := range wantErrors {
+		if !strings.Contains(got, wantError) {
+			t.Fatalf("missing error:\nwant: %q\ngot:\n%s", wantError, got)
+		}
+	}
+}
+
+func TestInit_getProviderDetectedLegacy(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-get-provider-detected-legacy"), td)
+	defer testChdir(t, td)()
+
+	// We need to construct a multisource with a mock source and a registry
+	// source: the mock source will return ErrRegistryProviderNotKnown for an
+	// unknown provider, and the registry source will allow us to look up the
+	// appropriate namespace if possible.
+	providerSource, psClose := newMockProviderSource(t, map[string][]string{
+		"hashicorp/foo":           {"1.2.3"},
+		"terraform-providers/baz": {"2.3.4"}, // this will not be installed
+	})
+	defer psClose()
+	registrySource, rsClose := testRegistrySource(t)
+	defer rsClose()
+	multiSource := getproviders.MultiSource{
+		{Source: providerSource},
+		{Source: registrySource},
+	}
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	m := Meta{
+		Ui:             ui,
+		View:           view,
+		ProviderSource: multiSource,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	args := []string{
+		"-backend=false", // should be possible to install plugins without backend init
+	}
+	if code := c.Run(args); code == 0 {
+		t.Fatalf("expected error, got output: \n%s", ui.OutputWriter.String())
+	}
+
+	// foo should be installed
+	fooPath := fmt.Sprintf(".terraform/providers/registry.terraform.io/hashicorp/foo/1.2.3/%s", getproviders.CurrentPlatform)
+	if _, err := os.Stat(fooPath); os.IsNotExist(err) {
+		t.Error("provider 'foo' not installed")
+	}
+	// baz should not be installed
+	bazPath := fmt.Sprintf(".terraform/providers/registry.terraform.io/terraform-providers/baz/2.3.4/%s", getproviders.CurrentPlatform)
+	if _, err := os.Stat(bazPath); !os.IsNotExist(err) {
+		t.Error("provider 'baz' installed, but should not be")
+	}
+
+	// error output is the main focus of this test
+	errOutput := ui.ErrorWriter.String()
+	errors := []string{
+		"Failed to query available provider packages",
+		"Could not retrieve the list of available versions",
+		"registry.terraform.io/hashicorp/baz",
+		"registry.terraform.io/hashicorp/frob",
+	}
+	for _, want := range errors {
+		if !strings.Contains(errOutput, want) {
+			t.Fatalf("expected error %q: %s", want, errOutput)
+		}
+	}
+}
+
+func TestInit_providerSource(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-required-providers"), td)
+	defer testChdir(t, td)()
+
+	providerSource, close := newMockProviderSource(t, map[string][]string{
+		"test":      {"1.2.3", "1.2.4"},
+		"test-beta": {"1.2.4"},
+		"source":    {"1.2.2", "1.2.3", "1.2.1"},
+	})
+	defer close()
+
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	m := Meta{
+		testingOverrides: metaOverridesForProvider(testProvider()),
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	args := []string{}
+
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+	if strings.Contains(ui.OutputWriter.String(), "Terraform has initialized, but configuration upgrades may be needed") {
+		t.Fatalf("unexpected \"configuration upgrade\" warning in output")
+	}
+
+	cacheDir := m.providerLocalCacheDir()
+	gotPackages := cacheDir.AllAvailablePackages()
+	wantPackages := map[addrs.Provider][]providercache.CachedProvider{
+		addrs.NewDefaultProvider("test"): {
+			{
+				Provider:   addrs.NewDefaultProvider("test"),
+				Version:    getproviders.MustParseVersion("1.2.3"),
+				PackageDir: expectedPackageInstallPath("test", "1.2.3", false),
+			},
+		},
+		addrs.NewDefaultProvider("test-beta"): {
+			{
+				Provider:   addrs.NewDefaultProvider("test-beta"),
+				Version:    getproviders.MustParseVersion("1.2.4"),
+				PackageDir: expectedPackageInstallPath("test-beta", "1.2.4", false),
+			},
+		},
+		addrs.NewDefaultProvider("source"): {
+			{
+				Provider:   addrs.NewDefaultProvider("source"),
+				Version:    getproviders.MustParseVersion("1.2.3"),
+				PackageDir: expectedPackageInstallPath("source", "1.2.3", false),
+			},
+		},
+	}
+	if diff := cmp.Diff(wantPackages, gotPackages); diff != "" {
+		t.Errorf("wrong cache directory contents after upgrade\n%s", diff)
+	}
+
+	locks, err := m.lockedDependencies()
+	if err != nil {
+		t.Fatalf("failed to get locked dependencies: %s", err)
+	}
+	gotProviderLocks := locks.AllProviders()
+	wantProviderLocks := map[addrs.Provider]*depsfile.ProviderLock{
+		addrs.NewDefaultProvider("test-beta"): depsfile.NewProviderLock(
+			addrs.NewDefaultProvider("test-beta"),
+			getproviders.MustParseVersion("1.2.4"),
+			getproviders.MustParseVersionConstraints("= 1.2.4"),
+			[]getproviders.Hash{
+				getproviders.HashScheme1.New("see6W06w09Ea+AobFJ+mbvPTie6ASqZAAdlFZbs8BSM="),
+			},
+		),
+		addrs.NewDefaultProvider("test"): depsfile.NewProviderLock(
+			addrs.NewDefaultProvider("test"),
+			getproviders.MustParseVersion("1.2.3"),
+			getproviders.MustParseVersionConstraints("= 1.2.3"),
+			[]getproviders.Hash{
+				getproviders.HashScheme1.New("wlbEC2mChQZ2hhgUhl6SeVLPP7fMqOFUZAQhQ9GIIno="),
+			},
+		),
+		addrs.NewDefaultProvider("source"): depsfile.NewProviderLock(
+			addrs.NewDefaultProvider("source"),
+			getproviders.MustParseVersion("1.2.3"),
+			getproviders.MustParseVersionConstraints("= 1.2.3"),
+			[]getproviders.Hash{
+				getproviders.HashScheme1.New("myS3qb3px3tRBq1ZWRYJeUH+kySWpBc0Yy8rw6W7/p4="),
+			},
+		),
+	}
+
+	if diff := cmp.Diff(gotProviderLocks, wantProviderLocks, depsfile.ProviderLockComparer); diff != "" {
+		t.Errorf("wrong version selections after upgrade\n%s", diff)
+	}
+
+	if got, want := ui.OutputWriter.String(), "Installed hashicorp/test v1.2.3 (verified checksum)"; !strings.Contains(got, want) {
+		t.Fatalf("unexpected output: %s\nexpected to include %q", got, want)
+	}
+	if got, want := ui.ErrorWriter.String(), "\n  - hashicorp/source\n  - hashicorp/test\n  - hashicorp/test-beta"; !strings.Contains(got, want) {
+		t.Fatalf("wrong error message\nshould contain: %s\ngot:\n%s", want, got)
+	}
+}
+
+func TestInit_cancelModules(t *testing.T) {
+	// This test runs `terraform init` as if SIGINT (or similar on other
+	// platforms) were sent to it, testing that it is interruptible.
+
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-registry-module"), td)
+	defer testChdir(t, td)()
+
+	// Our shutdown channel is pre-closed so init will exit as soon as it
+	// starts a cancelable portion of the process.
+	shutdownCh := make(chan struct{})
+	close(shutdownCh)
+
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	m := Meta{
+		testingOverrides: metaOverridesForProvider(testProvider()),
+		Ui:               ui,
+		View:             view,
+		ShutdownCh:       shutdownCh,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	args := []string{}
+
+	if code := c.Run(args); code == 0 {
+		t.Fatalf("succeeded; wanted error\n%s", ui.OutputWriter.String())
+	}
+
+	if got, want := ui.ErrorWriter.String(), `Module installation was canceled by an interrupt signal`; !strings.Contains(got, want) {
+		t.Fatalf("wrong error message\nshould contain: %s\ngot:\n%s", want, got)
+	}
+}
+
+func TestInit_cancelProviders(t *testing.T) {
+	// This test runs `terraform init` as if SIGINT (or similar on other
+	// platforms) were sent to it, testing that it is interruptible.
+
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-required-providers"), td)
+	defer testChdir(t, td)()
+
+	// Use a provider source implementation which is designed to hang indefinitely,
+	// to avoid a race between the closed shutdown channel and the provider source
+	// operations.
+	providerSource := &getproviders.HangingSource{}
+
+	// Our shutdown channel is pre-closed so init will exit as soon as it
+	// starts a cancelable portion of the process.
+	shutdownCh := make(chan struct{})
+	close(shutdownCh)
+
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	m := Meta{
+		testingOverrides: metaOverridesForProvider(testProvider()),
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+		ShutdownCh:       shutdownCh,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	args := []string{}
+
+	if code := c.Run(args); code == 0 {
+		t.Fatalf("succeeded; wanted error\n%s", ui.OutputWriter.String())
+	}
+	// Currently the first operation that is cancelable is provider
+	// installation, so our error message comes from there. If we
+	// make the earlier steps cancelable in future then it'd be
+	// expected for this particular message to change.
+	if got, want := ui.ErrorWriter.String(), `Provider installation was canceled by an interrupt signal`; !strings.Contains(got, want) {
+		t.Fatalf("wrong error message\nshould contain: %s\ngot:\n%s", want, got)
+	}
+}
+
+func TestInit_getUpgradePlugins(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-get-providers"), td)
+	defer testChdir(t, td)()
+
+	providerSource, close := newMockProviderSource(t, map[string][]string{
+		// looking for an exact version
+		"exact": {"1.2.3"},
+		// config requires >= 2.3.3
+		"greater-than": {"2.3.4", "2.3.3", "2.3.0"},
+		// config specifies > 1.0.0 , < 3.0.0
+		"between": {"3.4.5", "2.3.4", "1.2.3"},
+	})
+	defer close()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	m := Meta{
+		testingOverrides: metaOverridesForProvider(testProvider()),
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	installFakeProviderPackages(t, &m, map[string][]string{
+		"exact":        {"0.0.1"},
+		"greater-than": {"2.3.3"},
+	})
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	args := []string{
+		"-upgrade=true",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("command did not complete successfully:\n%s", ui.ErrorWriter.String())
+	}
+
+	cacheDir := m.providerLocalCacheDir()
+	gotPackages := cacheDir.AllAvailablePackages()
+	wantPackages := map[addrs.Provider][]providercache.CachedProvider{
+		// "between" wasn't previously installed at all, so we installed
+		// the newest available version that matched the version constraints.
+		addrs.NewDefaultProvider("between"): {
+			{
+				Provider:   addrs.NewDefaultProvider("between"),
+				Version:    getproviders.MustParseVersion("2.3.4"),
+				PackageDir: expectedPackageInstallPath("between", "2.3.4", false),
+			},
+		},
+		// The existing version of "exact" did not match the version constraints,
+		// so we installed what the configuration selected as well.
+		addrs.NewDefaultProvider("exact"): {
+			{
+				Provider:   addrs.NewDefaultProvider("exact"),
+				Version:    getproviders.MustParseVersion("1.2.3"),
+				PackageDir: expectedPackageInstallPath("exact", "1.2.3", false),
+			},
+			// Previous version is still there, but not selected
+			{
+				Provider:   addrs.NewDefaultProvider("exact"),
+				Version:    getproviders.MustParseVersion("0.0.1"),
+				PackageDir: expectedPackageInstallPath("exact", "0.0.1", false),
+			},
+		},
+		// The existing version of "greater-than" _did_ match the constraints,
+		// but a newer version was available and the user specified
+		// -upgrade and so we upgraded it anyway.
+		addrs.NewDefaultProvider("greater-than"): {
+			{
+				Provider:   addrs.NewDefaultProvider("greater-than"),
+				Version:    getproviders.MustParseVersion("2.3.4"),
+				PackageDir: expectedPackageInstallPath("greater-than", "2.3.4", false),
+			},
+			// Previous version is still there, but not selected
+			{
+				Provider:   addrs.NewDefaultProvider("greater-than"),
+				Version:    getproviders.MustParseVersion("2.3.3"),
+				PackageDir: expectedPackageInstallPath("greater-than", "2.3.3", false),
+			},
+		},
+	}
+	if diff := cmp.Diff(wantPackages, gotPackages); diff != "" {
+		t.Errorf("wrong cache directory contents after upgrade\n%s", diff)
+	}
+
+	locks, err := m.lockedDependencies()
+	if err != nil {
+		t.Fatalf("failed to get locked dependencies: %s", err)
+	}
+	gotProviderLocks := locks.AllProviders()
+	wantProviderLocks := map[addrs.Provider]*depsfile.ProviderLock{
+		addrs.NewDefaultProvider("between"): depsfile.NewProviderLock(
+			addrs.NewDefaultProvider("between"),
+			getproviders.MustParseVersion("2.3.4"),
+			getproviders.MustParseVersionConstraints("> 1.0.0, < 3.0.0"),
+			[]getproviders.Hash{
+				getproviders.HashScheme1.New("JVqAvZz88A+hS2wHVtTWQkHaxoA/LrUAz0H3jPBWPIA="),
+			},
+		),
+		addrs.NewDefaultProvider("exact"): depsfile.NewProviderLock(
+			addrs.NewDefaultProvider("exact"),
+			getproviders.MustParseVersion("1.2.3"),
+			getproviders.MustParseVersionConstraints("= 1.2.3"),
+			[]getproviders.Hash{
+				getproviders.HashScheme1.New("H1TxWF8LyhBb6B4iUdKhLc/S9sC/jdcrCykpkbGcfbg="),
+			},
+		),
+		addrs.NewDefaultProvider("greater-than"): depsfile.NewProviderLock(
+			addrs.NewDefaultProvider("greater-than"),
+			getproviders.MustParseVersion("2.3.4"),
+			getproviders.MustParseVersionConstraints(">= 2.3.3"),
+			[]getproviders.Hash{
+				getproviders.HashScheme1.New("SJPpXx/yoFE/W+7eCipjJ+G21xbdnTBD7lWodZ8hWkU="),
+			},
+		),
+	}
+	if diff := cmp.Diff(gotProviderLocks, wantProviderLocks, depsfile.ProviderLockComparer); diff != "" {
+		t.Errorf("wrong version selections after upgrade\n%s", diff)
+	}
+}
+
+func TestInit_getProviderMissing(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-get-providers"), td)
+	defer testChdir(t, td)()
+
+	providerSource, close := newMockProviderSource(t, map[string][]string{
+		// looking for exact version 1.2.3
+		"exact": {"1.2.4"},
+		// config requires >= 2.3.3
+		"greater-than": {"2.3.4", "2.3.3", "2.3.0"},
+		// config specifies
+		"between": {"3.4.5", "2.3.4", "1.2.3"},
+	})
+	defer close()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	m := Meta{
+		testingOverrides: metaOverridesForProvider(testProvider()),
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	args := []string{}
+	if code := c.Run(args); code == 0 {
+		t.Fatalf("expected error, got output: \n%s", ui.OutputWriter.String())
+	}
+
+	if !strings.Contains(ui.ErrorWriter.String(), "no available releases match") {
+		t.Fatalf("unexpected error output: %s", ui.ErrorWriter)
+	}
+}
+
+func TestInit_checkRequiredVersion(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-check-required-version"), td)
+	defer testChdir(t, td)()
+
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
+	}
+	errStr := ui.ErrorWriter.String()
+	if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) {
+		t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr)
+	}
+	if strings.Contains(errStr, `required_version = ">= 0.13.0"`) {
+		t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr)
+	}
+}
+
+// Verify that init will error out with an invalid version constraint, even if
+// there are other invalid configuration constructs.
+func TestInit_checkRequiredVersionFirst(t *testing.T) {
+	t.Run("root_module", func(t *testing.T) {
+		td := t.TempDir()
+		testCopyDir(t, testFixturePath("init-check-required-version-first"), td)
+		defer testChdir(t, td)()
+
+		ui := cli.NewMockUi()
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(testProvider()),
+				Ui:               ui,
+				View:             view,
+			},
+		}
+
+		args := []string{}
+		if code := c.Run(args); code != 1 {
+			t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
+		}
+		errStr := ui.ErrorWriter.String()
+		if !strings.Contains(errStr, `Unsupported Terraform Core version`) {
+			t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr)
+		}
+	})
+	t.Run("sub_module", func(t *testing.T) {
+		td := t.TempDir()
+		testCopyDir(t, testFixturePath("init-check-required-version-first-module"), td)
+		defer testChdir(t, td)()
+
+		ui := cli.NewMockUi()
+		view, _ := testView(t)
+		c := &InitCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(testProvider()),
+				Ui:               ui,
+				View:             view,
+			},
+		}
+
+		args := []string{}
+		if code := c.Run(args); code != 1 {
+			t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
+		}
+		errStr := ui.ErrorWriter.String()
+		if !strings.Contains(errStr, `Unsupported Terraform Core version`) {
+			t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr)
+		}
+	})
+}
+
+func TestInit_providerLockFile(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-provider-lock-file"), td)
+	// The temporary directory does not have write permission (dr-xr-xr-x) after the copy
+	defer os.Chmod(td, os.ModePerm)
+	defer testChdir(t, td)()
+
+	providerSource, close := newMockProviderSource(t, map[string][]string{
+		"test": {"1.2.3"},
+	})
+	defer close()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	m := Meta{
+		testingOverrides: metaOverridesForProvider(testProvider()),
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	lockFile := ".terraform.lock.hcl"
+	buf, err := ioutil.ReadFile(lockFile)
+	if err != nil {
+		t.Fatalf("failed to read dependency lock file %s: %s", lockFile, err)
+	}
+	buf = bytes.TrimSpace(buf)
+	// The hash in here is for the fake package that newMockProviderSource produces
+	// (so it'll change if newMockProviderSource starts producing different contents)
+	wantLockFile := strings.TrimSpace(`
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/test" {
+  version     = "1.2.3"
+  constraints = "1.2.3"
+  hashes = [
+    "h1:wlbEC2mChQZ2hhgUhl6SeVLPP7fMqOFUZAQhQ9GIIno=",
+  ]
+}
+`)
+	if diff := cmp.Diff(wantLockFile, string(buf)); diff != "" {
+		t.Errorf("wrong dependency lock file contents\n%s", diff)
+	}
+
+	// Make the local directory read-only, and verify that rerunning init
+	// succeeds, to ensure that we don't try to rewrite an unchanged lock file
+	os.Chmod(".", 0555)
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+}
+
+func TestInit_providerLockFileReadonly(t *testing.T) {
+	// The hash in here is for the fake package that newMockProviderSource produces
+	// (so it'll change if newMockProviderSource starts producing different contents)
+	inputLockFile := strings.TrimSpace(`
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/test" {
+  version     = "1.2.3"
+  constraints = "1.2.3"
+  hashes = [
+    "zh:e919b507a91e23a00da5c2c4d0b64bcc7900b68d43b3951ac0f6e5d80387fbdc",
+  ]
+}
+`)
+
+	badLockFile := strings.TrimSpace(`
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/test" {
+  version     = "1.2.3"
+  constraints = "1.2.3"
+  hashes = [
+    "zh:0000000000000000000000000000000000000000000000000000000000000000",
+  ]
+}
+`)
+
+	updatedLockFile := strings.TrimSpace(`
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/test" {
+  version     = "1.2.3"
+  constraints = "1.2.3"
+  hashes = [
+    "h1:wlbEC2mChQZ2hhgUhl6SeVLPP7fMqOFUZAQhQ9GIIno=",
+    "zh:e919b507a91e23a00da5c2c4d0b64bcc7900b68d43b3951ac0f6e5d80387fbdc",
+  ]
+}
+`)
+
+	emptyUpdatedLockFile := strings.TrimSpace(`
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+`)
+
+	cases := []struct {
+		desc      string
+		fixture   string
+		providers map[string][]string
+		input     string
+		args      []string
+		ok        bool
+		want      string
+	}{
+		{
+			desc:      "default",
+			fixture:   "init-provider-lock-file",
+			providers: map[string][]string{"test": {"1.2.3"}},
+			input:     inputLockFile,
+			args:      []string{},
+			ok:        true,
+			want:      updatedLockFile,
+		},
+		{
+			desc:      "unused provider",
+			fixture:   "init-provider-now-unused",
+			providers: map[string][]string{"test": {"1.2.3"}},
+			input:     inputLockFile,
+			args:      []string{},
+			ok:        true,
+			want:      emptyUpdatedLockFile,
+		},
+		{
+			desc:      "readonly",
+			fixture:   "init-provider-lock-file",
+			providers: map[string][]string{"test": {"1.2.3"}},
+			input:     inputLockFile,
+			args:      []string{"-lockfile=readonly"},
+			ok:        true,
+			want:      inputLockFile,
+		},
+		{
+			desc:      "unused provider readonly",
+			fixture:   "init-provider-now-unused",
+			providers: map[string][]string{"test": {"1.2.3"}},
+			input:     inputLockFile,
+			args:      []string{"-lockfile=readonly"},
+			ok:        false,
+			want:      inputLockFile,
+		},
+		{
+			desc:      "conflict",
+			fixture:   "init-provider-lock-file",
+			providers: map[string][]string{"test": {"1.2.3"}},
+			input:     inputLockFile,
+			args:      []string{"-lockfile=readonly", "-upgrade"},
+			ok:        false,
+			want:      inputLockFile,
+		},
+		{
+			desc:      "checksum mismatch",
+			fixture:   "init-provider-lock-file",
+			providers: map[string][]string{"test": {"1.2.3"}},
+			input:     badLockFile,
+			args:      []string{"-lockfile=readonly"},
+			ok:        false,
+			want:      badLockFile,
+		},
+		{
+			desc:    "reject to change required provider dependences",
+			fixture: "init-provider-lock-file-readonly-add",
+			providers: map[string][]string{
+				"test": {"1.2.3"},
+				"foo":  {"1.0.0"},
+			},
+			input: inputLockFile,
+			args:  []string{"-lockfile=readonly"},
+			ok:    false,
+			want:  inputLockFile,
+		},
+	}
+
+	for _, tc := range cases {
+		t.Run(tc.desc, func(t *testing.T) {
+			// Create a temporary working directory that is empty
+			td := t.TempDir()
+			testCopyDir(t, testFixturePath(tc.fixture), td)
+			defer testChdir(t, td)()
+
+			providerSource, close := newMockProviderSource(t, tc.providers)
+			defer close()
+
+			ui := new(cli.MockUi)
+			m := Meta{
+				testingOverrides: metaOverridesForProvider(testProvider()),
+				Ui:               ui,
+				ProviderSource:   providerSource,
+			}
+
+			c := &InitCommand{
+				Meta: m,
+			}
+
+			// write input lockfile
+			lockFile := ".terraform.lock.hcl"
+			if err := ioutil.WriteFile(lockFile, []byte(tc.input), 0644); err != nil {
+				t.Fatalf("failed to write input lockfile: %s", err)
+			}
+
+			code := c.Run(tc.args)
+			if tc.ok && code != 0 {
+				t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+			}
+			if !tc.ok && code == 0 {
+				t.Fatalf("expected error, got output: \n%s", ui.OutputWriter.String())
+			}
+
+			buf, err := ioutil.ReadFile(lockFile)
+			if err != nil {
+				t.Fatalf("failed to read dependency lock file %s: %s", lockFile, err)
+			}
+			buf = bytes.TrimSpace(buf)
+			if diff := cmp.Diff(tc.want, string(buf)); diff != "" {
+				t.Errorf("wrong dependency lock file contents\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestInit_pluginDirReset(t *testing.T) {
+	td := testTempDir(t)
+	defer os.RemoveAll(td)
+	defer testChdir(t, td)()
+
+	// An empty provider source
+	providerSource, close := newMockProviderSource(t, nil)
+	defer close()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+			ProviderSource:   providerSource,
+		},
+	}
+
+	// make our vendor paths
+	pluginPath := []string{"a", "b", "c"}
+	for _, p := range pluginPath {
+		if err := os.MkdirAll(p, 0755); err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	// run once and save the -plugin-dir
+	args := []string{"-plugin-dir", "a"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter)
+	}
+
+	pluginDirs, err := c.loadPluginPath()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(pluginDirs) != 1 || pluginDirs[0] != "a" {
+		t.Fatalf(`expected plugin dir ["a"], got %q`, pluginDirs)
+	}
+
+	ui = new(cli.MockUi)
+	c = &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+			ProviderSource:   providerSource, // still empty
+		},
+	}
+
+	// make sure we remove the plugin-dir record
+	args = []string{"-plugin-dir="}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter)
+	}
+
+	pluginDirs, err = c.loadPluginPath()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(pluginDirs) != 0 {
+		t.Fatalf("expected no plugin dirs got %q", pluginDirs)
+	}
+}
+
+// Test user-supplied -plugin-dir
+func TestInit_pluginDirProviders(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-get-providers"), td)
+	defer testChdir(t, td)()
+
+	// An empty provider source
+	providerSource, close := newMockProviderSource(t, nil)
+	defer close()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	m := Meta{
+		testingOverrides: metaOverridesForProvider(testProvider()),
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	// make our vendor paths
+	pluginPath := []string{"a", "b", "c"}
+	for _, p := range pluginPath {
+		if err := os.MkdirAll(p, 0755); err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	// We'll put some providers in our plugin dirs. To do this, we'll pretend
+	// for a moment that they are provider cache directories just because that
+	// allows us to lean on our existing test helper functions to do this.
+	for i, def := range [][]string{
+		{"exact", "1.2.3"},
+		{"greater-than", "2.3.4"},
+		{"between", "2.3.4"},
+	} {
+		name, version := def[0], def[1]
+		dir := providercache.NewDir(pluginPath[i])
+		installFakeProviderPackagesElsewhere(t, dir, map[string][]string{
+			name: {version},
+		})
+	}
+
+	args := []string{
+		"-plugin-dir", "a",
+		"-plugin-dir", "b",
+		"-plugin-dir", "c",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter)
+	}
+
+	locks, err := m.lockedDependencies()
+	if err != nil {
+		t.Fatalf("failed to get locked dependencies: %s", err)
+	}
+	gotProviderLocks := locks.AllProviders()
+	wantProviderLocks := map[addrs.Provider]*depsfile.ProviderLock{
+		addrs.NewDefaultProvider("between"): depsfile.NewProviderLock(
+			addrs.NewDefaultProvider("between"),
+			getproviders.MustParseVersion("2.3.4"),
+			getproviders.MustParseVersionConstraints("> 1.0.0, < 3.0.0"),
+			[]getproviders.Hash{
+				getproviders.HashScheme1.New("JVqAvZz88A+hS2wHVtTWQkHaxoA/LrUAz0H3jPBWPIA="),
+			},
+		),
+		addrs.NewDefaultProvider("exact"): depsfile.NewProviderLock(
+			addrs.NewDefaultProvider("exact"),
+			getproviders.MustParseVersion("1.2.3"),
+			getproviders.MustParseVersionConstraints("= 1.2.3"),
+			[]getproviders.Hash{
+				getproviders.HashScheme1.New("H1TxWF8LyhBb6B4iUdKhLc/S9sC/jdcrCykpkbGcfbg="),
+			},
+		),
+		addrs.NewDefaultProvider("greater-than"): depsfile.NewProviderLock(
+			addrs.NewDefaultProvider("greater-than"),
+			getproviders.MustParseVersion("2.3.4"),
+			getproviders.MustParseVersionConstraints(">= 2.3.3"),
+			[]getproviders.Hash{
+				getproviders.HashScheme1.New("SJPpXx/yoFE/W+7eCipjJ+G21xbdnTBD7lWodZ8hWkU="),
+			},
+		),
+	}
+	if diff := cmp.Diff(gotProviderLocks, wantProviderLocks, depsfile.ProviderLockComparer); diff != "" {
+		t.Errorf("wrong version selections after upgrade\n%s", diff)
+	}
+
+	// -plugin-dir overrides the normal provider source, so it should not have
+	// seen any calls at all.
+	if calls := providerSource.CallLog(); len(calls) > 0 {
+		t.Errorf("unexpected provider source calls (want none)\n%s", spew.Sdump(calls))
+	}
+}
+
+// Test user-supplied -plugin-dir doesn't allow auto-install
+func TestInit_pluginDirProvidersDoesNotGet(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-get-providers"), td)
+	defer testChdir(t, td)()
+
+	// Our provider source has a suitable package for "between" available,
+	// but we should ignore it because -plugin-dir is set and thus this
+	// source is temporarily overridden during install.
+	providerSource, close := newMockProviderSource(t, map[string][]string{
+		"between": {"2.3.4"},
+	})
+	defer close()
+
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	m := Meta{
+		testingOverrides: metaOverridesForProvider(testProvider()),
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	// make our vendor paths
+	pluginPath := []string{"a", "b"}
+	for _, p := range pluginPath {
+		if err := os.MkdirAll(p, 0755); err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	// We'll put some providers in our plugin dirs. To do this, we'll pretend
+	// for a moment that they are provider cache directories just because that
+	// allows us to lean on our existing test helper functions to do this.
+	for i, def := range [][]string{
+		{"exact", "1.2.3"},
+		{"greater-than", "2.3.4"},
+	} {
+		name, version := def[0], def[1]
+		dir := providercache.NewDir(pluginPath[i])
+		installFakeProviderPackagesElsewhere(t, dir, map[string][]string{
+			name: {version},
+		})
+	}
+
+	args := []string{
+		"-plugin-dir", "a",
+		"-plugin-dir", "b",
+	}
+	if code := c.Run(args); code == 0 {
+		// should have been an error
+		t.Fatalf("succeeded; want error\nstdout:\n%s\nstderr\n%s", ui.OutputWriter, ui.ErrorWriter)
+	}
+
+	// The error output should mention the "between" provider but should not
+	// mention either the "exact" or "greater-than" provider, because the
+	// latter two are available via the -plugin-dir directories.
+	errStr := ui.ErrorWriter.String()
+	if subStr := "hashicorp/between"; !strings.Contains(errStr, subStr) {
+		t.Errorf("error output should mention the 'between' provider\nwant substr: %s\ngot:\n%s", subStr, errStr)
+	}
+	if subStr := "hashicorp/exact"; strings.Contains(errStr, subStr) {
+		t.Errorf("error output should not mention the 'exact' provider\ndo not want substr: %s\ngot:\n%s", subStr, errStr)
+	}
+	if subStr := "hashicorp/greater-than"; strings.Contains(errStr, subStr) {
+		t.Errorf("error output should not mention the 'greater-than' provider\ndo not want substr: %s\ngot:\n%s", subStr, errStr)
+	}
+
+	if calls := providerSource.CallLog(); len(calls) > 0 {
+		t.Errorf("unexpected provider source calls (want none)\n%s", spew.Sdump(calls))
+	}
+}
+
+// Verify that plugin-dir doesn't prevent discovery of internal providers
+func TestInit_pluginDirWithBuiltIn(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-internal"), td)
+	defer testChdir(t, td)()
+
+	// An empty provider source
+	providerSource, close := newMockProviderSource(t, nil)
+	defer close()
+
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	m := Meta{
+		testingOverrides: metaOverridesForProvider(testProvider()),
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	args := []string{"-plugin-dir", "./"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("error: %s", ui.ErrorWriter)
+	}
+
+	outputStr := ui.OutputWriter.String()
+	if subStr := "terraform.io/builtin/terraform is built in to Terraform"; !strings.Contains(outputStr, subStr) {
+		t.Errorf("output should mention the terraform provider\nwant substr: %s\ngot:\n%s", subStr, outputStr)
+	}
+}
+
+func TestInit_invalidBuiltInProviders(t *testing.T) {
+	// This test fixture includes two invalid provider dependencies:
+	// - an implied dependency on terraform.io/builtin/terraform with an
+	//   explicit version number, which is not allowed because it's builtin.
+	// - an explicit dependency on terraform.io/builtin/nonexist, which does
+	//   not exist at all.
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-internal-invalid"), td)
+	defer testChdir(t, td)()
+
+	// An empty provider source
+	providerSource, close := newMockProviderSource(t, nil)
+	defer close()
+
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	m := Meta{
+		testingOverrides: metaOverridesForProvider(testProvider()),
+		Ui:               ui,
+		View:             view,
+		ProviderSource:   providerSource,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	if code := c.Run(nil); code == 0 {
+		t.Fatalf("succeeded, but was expecting error\nstdout:\n%s\nstderr:\n%s", ui.OutputWriter, ui.ErrorWriter)
+	}
+
+	errStr := ui.ErrorWriter.String()
+	if subStr := "Cannot use terraform.io/builtin/terraform: built-in"; !strings.Contains(errStr, subStr) {
+		t.Errorf("error output should mention the terraform provider\nwant substr: %s\ngot:\n%s", subStr, errStr)
+	}
+	if subStr := "Cannot use terraform.io/builtin/nonexist: this Terraform release"; !strings.Contains(errStr, subStr) {
+		t.Errorf("error output should mention the 'nonexist' provider\nwant substr: %s\ngot:\n%s", subStr, errStr)
+	}
+}
+
+func TestInit_invalidSyntaxNoBackend(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-syntax-invalid-no-backend"), td)
+	defer testChdir(t, td)()
+
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	m := Meta{
+		Ui:   ui,
+		View: view,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	if code := c.Run(nil); code == 0 {
+		t.Fatalf("succeeded, but was expecting error\nstdout:\n%s\nstderr:\n%s", ui.OutputWriter, ui.ErrorWriter)
+	}
+
+	errStr := ui.ErrorWriter.String()
+	if subStr := "Terraform encountered problems during initialisation, including problems\nwith the configuration, described below."; !strings.Contains(errStr, subStr) {
+		t.Errorf("Error output should include preamble\nwant substr: %s\ngot:\n%s", subStr, errStr)
+	}
+	if subStr := "Error: Unsupported block type"; !strings.Contains(errStr, subStr) {
+		t.Errorf("Error output should mention the syntax problem\nwant substr: %s\ngot:\n%s", subStr, errStr)
+	}
+}
+
+func TestInit_invalidSyntaxWithBackend(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-syntax-invalid-with-backend"), td)
+	defer testChdir(t, td)()
+
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	m := Meta{
+		Ui:   ui,
+		View: view,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	if code := c.Run(nil); code == 0 {
+		t.Fatalf("succeeded, but was expecting error\nstdout:\n%s\nstderr:\n%s", ui.OutputWriter, ui.ErrorWriter)
+	}
+
+	errStr := ui.ErrorWriter.String()
+	if subStr := "Terraform encountered problems during initialisation, including problems\nwith the configuration, described below."; !strings.Contains(errStr, subStr) {
+		t.Errorf("Error output should include preamble\nwant substr: %s\ngot:\n%s", subStr, errStr)
+	}
+	if subStr := "Error: Unsupported block type"; !strings.Contains(errStr, subStr) {
+		t.Errorf("Error output should mention the syntax problem\nwant substr: %s\ngot:\n%s", subStr, errStr)
+	}
+}
+
+func TestInit_invalidSyntaxInvalidBackend(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-syntax-invalid-backend-invalid"), td)
+	defer testChdir(t, td)()
+
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	m := Meta{
+		Ui:   ui,
+		View: view,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	if code := c.Run(nil); code == 0 {
+		t.Fatalf("succeeded, but was expecting error\nstdout:\n%s\nstderr:\n%s", ui.OutputWriter, ui.ErrorWriter)
+	}
+
+	errStr := ui.ErrorWriter.String()
+	if subStr := "Terraform encountered problems during initialisation, including problems\nwith the configuration, described below."; !strings.Contains(errStr, subStr) {
+		t.Errorf("Error output should include preamble\nwant substr: %s\ngot:\n%s", subStr, errStr)
+	}
+	if subStr := "Error: Unsupported block type"; !strings.Contains(errStr, subStr) {
+		t.Errorf("Error output should mention syntax errors\nwant substr: %s\ngot:\n%s", subStr, errStr)
+	}
+	if subStr := "Error: Unsupported backend type"; !strings.Contains(errStr, subStr) {
+		t.Errorf("Error output should mention the invalid backend\nwant substr: %s\ngot:\n%s", subStr, errStr)
+	}
+}
+
+func TestInit_invalidSyntaxBackendAttribute(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-syntax-invalid-backend-attribute-invalid"), td)
+	defer testChdir(t, td)()
+
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	m := Meta{
+		Ui:   ui,
+		View: view,
+	}
+
+	c := &InitCommand{
+		Meta: m,
+	}
+
+	if code := c.Run(nil); code == 0 {
+		t.Fatalf("succeeded, but was expecting error\nstdout:\n%s\nstderr:\n%s", ui.OutputWriter, ui.ErrorWriter)
+	}
+
+	errStr := ui.ErrorWriter.String()
+	if subStr := "Terraform encountered problems during initialisation, including problems\nwith the configuration, described below."; !strings.Contains(errStr, subStr) {
+		t.Errorf("Error output should include preamble\nwant substr: %s\ngot:\n%s", subStr, errStr)
+	}
+	if subStr := "Error: Invalid character"; !strings.Contains(errStr, subStr) {
+		t.Errorf("Error output should mention the invalid character\nwant substr: %s\ngot:\n%s", subStr, errStr)
+	}
+	if subStr := "Error: Invalid expression"; !strings.Contains(errStr, subStr) {
+		t.Errorf("Error output should mention the invalid expression\nwant substr: %s\ngot:\n%s", subStr, errStr)
+	}
+}
+
+// newMockProviderSource is a helper to succinctly construct a mock provider
+// source that contains a set of packages matching the given provider versions
+// that are available for installation (from temporary local files).
+//
+// The caller must call the returned close callback once the source is no
+// longer needed, at which point it will clean up all of the temporary files
+// and the packages in the source will no longer be available for installation.
+//
+// Provider addresses must be valid source strings, and passing only the
+// provider name will be interpreted as a "default" provider under
+// registry.terraform.io/hashicorp. If you need more control over the
+// provider addresses, pass a full provider source string.
+//
+// This function also registers providers as belonging to the current platform,
+// to ensure that they will be available to a provider installer operating in
+// its default configuration.
+//
+// In case of any errors while constructing the source, this function will
+// abort the current test using the given testing.T. Therefore a caller can
+// assume that if this function returns then the result is valid and ready
+// to use.
+func newMockProviderSource(t *testing.T, availableProviderVersions map[string][]string) (source *getproviders.MockSource, close func()) {
+	t.Helper()
+	var packages []getproviders.PackageMeta
+	var closes []func()
+	close = func() {
+		for _, f := range closes {
+			f()
+		}
+	}
+	for source, versions := range availableProviderVersions {
+		addr := addrs.MustParseProviderSourceString(source)
+		for _, versionStr := range versions {
+			version, err := getproviders.ParseVersion(versionStr)
+			if err != nil {
+				close()
+				t.Fatalf("failed to parse %q as a version number for %q: %s", versionStr, addr.ForDisplay(), err)
+			}
+			meta, close, err := getproviders.FakeInstallablePackageMeta(addr, version, getproviders.VersionList{getproviders.MustParseVersion("5.0")}, getproviders.CurrentPlatform, "")
+			if err != nil {
+				close()
+				t.Fatalf("failed to prepare fake package for %s %s: %s", addr.ForDisplay(), versionStr, err)
+			}
+			closes = append(closes, close)
+			packages = append(packages, meta)
+		}
+	}
+
+	return getproviders.NewMockSource(packages, nil), close
+}
+
+// installFakeProviderPackages installs a fake package for the given provider
+// names (interpreted as a "default" provider address) and versions into the
+// local plugin cache for the given "meta".
+//
+// Any test using this must be using testChdir or some similar mechanism to
+// make sure that it isn't writing directly into a test fixture or source
+// directory within the codebase.
+//
+// If a requested package cannot be installed for some reason, this function
+// will abort the test using the given testing.T. Therefore if this function
+// returns the caller can assume that the requested providers have been
+// installed.
+func installFakeProviderPackages(t *testing.T, meta *Meta, providerVersions map[string][]string) {
+	t.Helper()
+
+	cacheDir := meta.providerLocalCacheDir()
+	installFakeProviderPackagesElsewhere(t, cacheDir, providerVersions)
+}
+
+// installFakeProviderPackagesElsewhere is a variant of installFakeProviderPackages
+// that will install packages into the given provider cache directory, rather
+// than forcing the use of the local cache of the current "Meta".
+func installFakeProviderPackagesElsewhere(t *testing.T, cacheDir *providercache.Dir, providerVersions map[string][]string) {
+	t.Helper()
+
+	// It can be hard to spot the mistake of forgetting to run testChdir before
+	// modifying the working directory, so we'll use a simple heuristic here
+	// to try to detect that mistake and make a noisy error about it instead.
+	wd, err := os.Getwd()
+	if err == nil {
+		wd = filepath.Clean(wd)
+		// If the directory we're in is named "command" or if we're under a
+		// directory named "testdata" then we'll assume a mistake and generate
+		// an error. This will cause the test to fail but won't block it from
+		// running.
+		if filepath.Base(wd) == "command" || filepath.Base(wd) == "testdata" || strings.Contains(filepath.ToSlash(wd), "/testdata/") {
+			t.Errorf("installFakeProviderPackage may be used only by tests that switch to a temporary working directory, e.g. using testChdir")
+		}
+	}
+
+	for name, versions := range providerVersions {
+		addr := addrs.NewDefaultProvider(name)
+		for _, versionStr := range versions {
+			version, err := getproviders.ParseVersion(versionStr)
+			if err != nil {
+				t.Fatalf("failed to parse %q as a version number for %q: %s", versionStr, name, err)
+			}
+			meta, close, err := getproviders.FakeInstallablePackageMeta(addr, version, getproviders.VersionList{getproviders.MustParseVersion("5.0")}, getproviders.CurrentPlatform, "")
+			// We're going to install all these fake packages before we return,
+			// so we don't need to preserve them afterwards.
+			defer close()
+			if err != nil {
+				t.Fatalf("failed to prepare fake package for %s %s: %s", name, versionStr, err)
+			}
+			_, err = cacheDir.InstallPackage(context.Background(), meta, nil)
+			if err != nil {
+				t.Fatalf("failed to install fake package for %s %s: %s", name, versionStr, err)
+			}
+		}
+	}
+}
+
+// expectedPackageInstallPath is a companion to installFakeProviderPackages
+// that returns the path where the provider with the given name and version
+// would be installed and, relatedly, where the installer will expect to
+// find an already-installed version.
+//
+// Just as with installFakeProviderPackages, this function is a shortcut helper
+// for "default-namespaced" providers as we commonly use in tests. If you need
+// more control over the provider addresses, use functions of the underlying
+// getproviders and providercache packages instead.
+//
+// The result always uses forward slashes, even on Windows, for consistency
+// with how the getproviders and providercache packages build paths.
+func expectedPackageInstallPath(name, version string, exe bool) string {
+	platform := getproviders.CurrentPlatform
+	baseDir := ".terraform/providers"
+	if exe {
+		p := fmt.Sprintf("registry.terraform.io/hashicorp/%s/%s/%s/terraform-provider-%s_%s", name, version, platform, name, version)
+		if platform.OS == "windows" {
+			p += ".exe"
+		}
+		return filepath.ToSlash(filepath.Join(baseDir, p))
+	}
+	return filepath.ToSlash(filepath.Join(
+		baseDir, fmt.Sprintf("registry.terraform.io/hashicorp/%s/%s/%s", name, version, platform),
+	))
+}
diff --git a/v1.5.7/internal/command/jsonchecks/checks.go b/v1.5.7/internal/command/jsonchecks/checks.go
new file mode 100644
index 0000000..2536341
--- /dev/null
+++ b/v1.5.7/internal/command/jsonchecks/checks.go
@@ -0,0 +1,119 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonchecks
+
+import (
+	"encoding/json"
+	"fmt"
+	"sort"
+
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// MarshalCheckStates is the main entry-point for this package, which takes
+// the top-level model object for checks in state and plan, and returns a
+// JSON representation of it suitable for use in public integration points.
+func MarshalCheckStates(results *states.CheckResults) []byte {
+	jsonResults := make([]checkResultStatic, 0, results.ConfigResults.Len())
+
+	for _, elem := range results.ConfigResults.Elems {
+		staticAddr := elem.Key
+		aggrResult := elem.Value
+
+		objects := make([]checkResultDynamic, 0, aggrResult.ObjectResults.Len())
+		for _, elem := range aggrResult.ObjectResults.Elems {
+			dynamicAddr := elem.Key
+			result := elem.Value
+
+			problems := make([]checkProblem, 0, len(result.FailureMessages))
+			for _, msg := range result.FailureMessages {
+				problems = append(problems, checkProblem{
+					Message: msg,
+				})
+			}
+			sort.Slice(problems, func(i, j int) bool {
+				return problems[i].Message < problems[j].Message
+			})
+
+			objects = append(objects, checkResultDynamic{
+				Address:  makeDynamicObjectAddr(dynamicAddr),
+				Status:   checkStatusForJSON(result.Status),
+				Problems: problems,
+			})
+		}
+
+		sort.Slice(objects, func(i, j int) bool {
+			return objects[i].Address["to_display"].(string) < objects[j].Address["to_display"].(string)
+		})
+
+		jsonResults = append(jsonResults, checkResultStatic{
+			Address:   makeStaticObjectAddr(staticAddr),
+			Status:    checkStatusForJSON(aggrResult.Status),
+			Instances: objects,
+		})
+	}
+
+	sort.Slice(jsonResults, func(i, j int) bool {
+		return jsonResults[i].Address["to_display"].(string) < jsonResults[j].Address["to_display"].(string)
+	})
+
+	ret, err := json.Marshal(jsonResults)
+	if err != nil {
+		// We totally control the input to json.Marshal, so any error here
+		// is a bug in the code above.
+		panic(fmt.Sprintf("invalid input to json.Marshal: %s", err))
+	}
+	return ret
+}
+
+// checkResultStatic is the container for the static, configuration-driven
+// idea of "checkable object" -- a resource block with conditions, for example --
+// which ensures that we can always say _something_ about each checkable
+// object in the configuration even if Terraform Core encountered an error
+// before being able to determine the dynamic instances of the checkable object.
+type checkResultStatic struct {
+	// Address is the address of the checkable object this result relates to.
+	Address staticObjectAddr `json:"address"`
+
+	// Status is the aggregate status for all of the dynamic objects belonging
+	// to this static object.
+	Status checkStatus `json:"status"`
+
+	// Instances contains the results for each individual dynamic object that
+	// belongs to this static object.
+	Instances []checkResultDynamic `json:"instances,omitempty"`
+}
+
+// checkResultDynamic describes the check result for a dynamic object, which
+// results from Terraform Core evaluating the "expansion" (e.g. count or for_each)
+// of the containing object or its own containing module(s).
+type checkResultDynamic struct {
+	// Address augments the Address of the containing checkResultStatic with
+	// instance-specific extra properties or overridden properties.
+	Address dynamicObjectAddr `json:"address"`
+
+	// Status is the status for this specific dynamic object.
+	Status checkStatus `json:"status"`
+
+	// Problems describes some optional details associated with a failure
+	// status, describing what fails.
+	//
+	// This does not include the errors for status "error", because Terraform
+	// Core emits those separately as normal diagnostics. However, if a
+	// particular object has a mixture of conditions that failed and conditions
+	// that were invalid then status can be "error" while simultaneously
+	// returning problems in this property.
+	Problems []checkProblem `json:"problems,omitempty"`
+}
+
+// checkProblem describes one of potentially several problems that led to
+// a check being classified as status "fail".
+type checkProblem struct {
+	// Message is the condition error message provided by the author.
+	Message string `json:"message"`
+
+	// We don't currently have any other problem-related data, but this is
+	// intentionally an object to allow us to add other data over time, such
+	// as the source location where the failing condition was defined.
+}
diff --git a/v1.5.7/internal/command/jsonchecks/checks_test.go b/v1.5.7/internal/command/jsonchecks/checks_test.go
new file mode 100644
index 0000000..cb23173
--- /dev/null
+++ b/v1.5.7/internal/command/jsonchecks/checks_test.go
@@ -0,0 +1,243 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonchecks
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestMarshalCheckStates(t *testing.T) {
+	resourceAAddr := addrs.ConfigCheckable(addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test",
+		Name: "a",
+	}.InModule(addrs.RootModule))
+	resourceAInstAddr := addrs.Checkable(addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test",
+		Name: "a",
+	}.Instance(addrs.StringKey("foo")).Absolute(addrs.RootModuleInstance))
+	moduleChildAddr := addrs.RootModuleInstance.Child("child", addrs.IntKey(0))
+	resourceBAddr := addrs.ConfigCheckable(addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test",
+		Name: "b",
+	}.InModule(moduleChildAddr.Module()))
+	resourceBInstAddr := addrs.Checkable(addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test",
+		Name: "b",
+	}.Instance(addrs.NoKey).Absolute(moduleChildAddr))
+	outputAAddr := addrs.ConfigCheckable(addrs.OutputValue{Name: "a"}.InModule(addrs.RootModule))
+	outputAInstAddr := addrs.Checkable(addrs.OutputValue{Name: "a"}.Absolute(addrs.RootModuleInstance))
+	outputBAddr := addrs.ConfigCheckable(addrs.OutputValue{Name: "b"}.InModule(moduleChildAddr.Module()))
+	outputBInstAddr := addrs.Checkable(addrs.OutputValue{Name: "b"}.Absolute(moduleChildAddr))
+	checkBlockAAddr := addrs.ConfigCheckable(addrs.Check{Name: "a"}.InModule(addrs.RootModule))
+	checkBlockAInstAddr := addrs.Checkable(addrs.Check{Name: "a"}.Absolute(addrs.RootModuleInstance))
+
+	tests := map[string]struct {
+		Input *states.CheckResults
+		Want  any
+	}{
+		"empty": {
+			&states.CheckResults{},
+			[]any{},
+		},
+		"failures": {
+			&states.CheckResults{
+				ConfigResults: addrs.MakeMap(
+					addrs.MakeMapElem(resourceAAddr, &states.CheckResultAggregate{
+						Status: checks.StatusFail,
+						ObjectResults: addrs.MakeMap(
+							addrs.MakeMapElem(resourceAInstAddr, &states.CheckResultObject{
+								Status: checks.StatusFail,
+								FailureMessages: []string{
+									"Not enough boops.",
+									"Too many beeps.",
+								},
+							}),
+						),
+					}),
+					addrs.MakeMapElem(resourceBAddr, &states.CheckResultAggregate{
+						Status: checks.StatusFail,
+						ObjectResults: addrs.MakeMap(
+							addrs.MakeMapElem(resourceBInstAddr, &states.CheckResultObject{
+								Status: checks.StatusFail,
+								FailureMessages: []string{
+									"Splines are too pointy.",
+								},
+							}),
+						),
+					}),
+					addrs.MakeMapElem(outputAAddr, &states.CheckResultAggregate{
+						Status: checks.StatusFail,
+						ObjectResults: addrs.MakeMap(
+							addrs.MakeMapElem(outputAInstAddr, &states.CheckResultObject{
+								Status: checks.StatusFail,
+							}),
+						),
+					}),
+					addrs.MakeMapElem(outputBAddr, &states.CheckResultAggregate{
+						Status: checks.StatusFail,
+						ObjectResults: addrs.MakeMap(
+							addrs.MakeMapElem(outputBInstAddr, &states.CheckResultObject{
+								Status: checks.StatusFail,
+								FailureMessages: []string{
+									"Not object-oriented enough.",
+								},
+							}),
+						),
+					}),
+					addrs.MakeMapElem(checkBlockAAddr, &states.CheckResultAggregate{
+						Status: checks.StatusFail,
+						ObjectResults: addrs.MakeMap(
+							addrs.MakeMapElem(checkBlockAInstAddr, &states.CheckResultObject{
+								Status: checks.StatusFail,
+								FailureMessages: []string{
+									"Couldn't reverse the polarity.",
+								},
+							}),
+						),
+					}),
+				),
+			},
+			[]any{
+				map[string]any{
+					"address": map[string]any{
+						"kind":       "check",
+						"to_display": "check.a",
+						"name":       "a",
+					},
+					"instances": []any{
+						map[string]any{
+							"address": map[string]any{
+								"to_display": `check.a`,
+							},
+							"problems": []any{
+								map[string]any{
+									"message": "Couldn't reverse the polarity.",
+								},
+							},
+							"status": "fail",
+						},
+					},
+					"status": "fail",
+				},
+				map[string]any{
+					"address": map[string]any{
+						"kind":       "output_value",
+						"module":     "module.child",
+						"name":       "b",
+						"to_display": "module.child.output.b",
+					},
+					"instances": []any{
+						map[string]any{
+							"address": map[string]any{
+								"module":     "module.child[0]",
+								"to_display": "module.child[0].output.b",
+							},
+							"problems": []any{
+								map[string]any{
+									"message": "Not object-oriented enough.",
+								},
+							},
+							"status": "fail",
+						},
+					},
+					"status": "fail",
+				},
+				map[string]any{
+					"address": map[string]any{
+						"kind":       "resource",
+						"mode":       "managed",
+						"module":     "module.child",
+						"name":       "b",
+						"to_display": "module.child.test.b",
+						"type":       "test",
+					},
+					"instances": []any{
+						map[string]any{
+							"address": map[string]any{
+								"module":     "module.child[0]",
+								"to_display": "module.child[0].test.b",
+							},
+							"problems": []any{
+								map[string]any{
+									"message": "Splines are too pointy.",
+								},
+							},
+							"status": "fail",
+						},
+					},
+					"status": "fail",
+				},
+				map[string]any{
+					"address": map[string]any{
+						"kind":       "output_value",
+						"name":       "a",
+						"to_display": "output.a",
+					},
+					"instances": []any{
+						map[string]any{
+							"address": map[string]any{
+								"to_display": "output.a",
+							},
+							"status": "fail",
+						},
+					},
+					"status": "fail",
+				},
+				map[string]any{
+					"address": map[string]any{
+						"kind":       "resource",
+						"mode":       "managed",
+						"name":       "a",
+						"to_display": "test.a",
+						"type":       "test",
+					},
+					"instances": []any{
+						map[string]any{
+							"address": map[string]any{
+								"to_display":   `test.a["foo"]`,
+								"instance_key": "foo",
+							},
+							"problems": []any{
+								map[string]any{
+									"message": "Not enough boops.",
+								},
+								map[string]any{
+									"message": "Too many beeps.",
+								},
+							},
+							"status": "fail",
+						},
+					},
+					"status": "fail",
+				},
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			gotBytes := MarshalCheckStates(test.Input)
+
+			var got any
+			err := json.Unmarshal(gotBytes, &got)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			if diff := cmp.Diff(test.Want, got); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/jsonchecks/doc.go b/v1.5.7/internal/command/jsonchecks/doc.go
new file mode 100644
index 0000000..adee52a
--- /dev/null
+++ b/v1.5.7/internal/command/jsonchecks/doc.go
@@ -0,0 +1,7 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package jsonchecks implements the common JSON representation of check
+// results/statuses that we use across both the JSON plan and JSON state
+// representations.
+package jsonchecks
diff --git a/v1.5.7/internal/command/jsonchecks/objects.go b/v1.5.7/internal/command/jsonchecks/objects.go
new file mode 100644
index 0000000..32c8a66
--- /dev/null
+++ b/v1.5.7/internal/command/jsonchecks/objects.go
@@ -0,0 +1,97 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonchecks
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+type staticObjectAddr map[string]interface{}
+
+func makeStaticObjectAddr(addr addrs.ConfigCheckable) staticObjectAddr {
+	ret := map[string]interface{}{
+		"to_display": addr.String(),
+	}
+
+	switch addr := addr.(type) {
+	case addrs.ConfigResource:
+		if kind := addr.CheckableKind(); kind != addrs.CheckableResource {
+			// Something has gone very wrong
+			panic(fmt.Sprintf("%T has CheckableKind %s", addr, kind))
+		}
+
+		ret["kind"] = "resource"
+		switch addr.Resource.Mode {
+		case addrs.ManagedResourceMode:
+			ret["mode"] = "managed"
+		case addrs.DataResourceMode:
+			ret["mode"] = "data"
+		default:
+			panic(fmt.Sprintf("unsupported resource mode %#v", addr.Resource.Mode))
+		}
+		ret["type"] = addr.Resource.Type
+		ret["name"] = addr.Resource.Name
+		if !addr.Module.IsRoot() {
+			ret["module"] = addr.Module.String()
+		}
+	case addrs.ConfigOutputValue:
+		if kind := addr.CheckableKind(); kind != addrs.CheckableOutputValue {
+			// Something has gone very wrong
+			panic(fmt.Sprintf("%T has CheckableKind %s", addr, kind))
+		}
+
+		ret["kind"] = "output_value"
+		ret["name"] = addr.OutputValue.Name
+		if !addr.Module.IsRoot() {
+			ret["module"] = addr.Module.String()
+		}
+	case addrs.ConfigCheck:
+		if kind := addr.CheckableKind(); kind != addrs.CheckableCheck {
+			// Something has gone very wrong
+			panic(fmt.Sprintf("%T has CheckableKind %s", addr, kind))
+		}
+
+		ret["kind"] = "check"
+		ret["name"] = addr.Check.Name
+		if !addr.Module.IsRoot() {
+			ret["module"] = addr.Module.String()
+		}
+	default:
+		panic(fmt.Sprintf("unsupported ConfigCheckable implementation %T", addr))
+	}
+
+	return ret
+}
+
+type dynamicObjectAddr map[string]interface{}
+
+func makeDynamicObjectAddr(addr addrs.Checkable) dynamicObjectAddr {
+	ret := map[string]interface{}{
+		"to_display": addr.String(),
+	}
+
+	switch addr := addr.(type) {
+	case addrs.AbsResourceInstance:
+		if !addr.Module.IsRoot() {
+			ret["module"] = addr.Module.String()
+		}
+		if addr.Resource.Key != addrs.NoKey {
+			ret["instance_key"] = addr.Resource.Key
+		}
+	case addrs.AbsOutputValue:
+		if !addr.Module.IsRoot() {
+			ret["module"] = addr.Module.String()
+		}
+	case addrs.AbsCheck:
+		if !addr.Module.IsRoot() {
+			ret["module"] = addr.Module.String()
+		}
+	default:
+		panic(fmt.Sprintf("unsupported Checkable implementation %T", addr))
+	}
+
+	return ret
+}
diff --git a/v1.5.7/internal/command/jsonchecks/status.go b/v1.5.7/internal/command/jsonchecks/status.go
new file mode 100644
index 0000000..57e1fb5
--- /dev/null
+++ b/v1.5.7/internal/command/jsonchecks/status.go
@@ -0,0 +1,30 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonchecks
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/checks"
+)
+
+type checkStatus []byte
+
+func checkStatusForJSON(s checks.Status) checkStatus {
+	if ret, ok := checkStatuses[s]; ok {
+		return ret
+	}
+	panic(fmt.Sprintf("unsupported check status %#v", s))
+}
+
+func (s checkStatus) MarshalJSON() ([]byte, error) {
+	return []byte(s), nil
+}
+
+var checkStatuses = map[checks.Status]checkStatus{
+	checks.StatusPass:    checkStatus(`"pass"`),
+	checks.StatusFail:    checkStatus(`"fail"`),
+	checks.StatusError:   checkStatus(`"error"`),
+	checks.StatusUnknown: checkStatus(`"unknown"`),
+}
diff --git a/v1.5.7/internal/command/jsonconfig/config.go b/v1.5.7/internal/command/jsonconfig/config.go
new file mode 100644
index 0000000..a5e5f10
--- /dev/null
+++ b/v1.5.7/internal/command/jsonconfig/config.go
@@ -0,0 +1,568 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonconfig
+
+import (
+	"encoding/json"
+	"fmt"
+	"sort"
+
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// Config represents the complete configuration source
+type config struct {
+	ProviderConfigs map[string]providerConfig `json:"provider_config,omitempty"`
+	RootModule      module                    `json:"root_module,omitempty"`
+}
+
+// ProviderConfig describes all of the provider configurations throughout the
+// configuration tree, flattened into a single map for convenience since
+// provider configurations are the one concept in Terraform that can span across
+// module boundaries.
+type providerConfig struct {
+	Name              string                 `json:"name,omitempty"`
+	FullName          string                 `json:"full_name,omitempty"`
+	Alias             string                 `json:"alias,omitempty"`
+	VersionConstraint string                 `json:"version_constraint,omitempty"`
+	ModuleAddress     string                 `json:"module_address,omitempty"`
+	Expressions       map[string]interface{} `json:"expressions,omitempty"`
+	parentKey         string
+}
+
+type module struct {
+	Outputs map[string]output `json:"outputs,omitempty"`
+	// Resources are sorted in a user-friendly order that is undefined at this
+	// time, but consistent.
+	Resources   []resource            `json:"resources,omitempty"`
+	ModuleCalls map[string]moduleCall `json:"module_calls,omitempty"`
+	Variables   variables             `json:"variables,omitempty"`
+}
+
+type moduleCall struct {
+	Source            string                 `json:"source,omitempty"`
+	Expressions       map[string]interface{} `json:"expressions,omitempty"`
+	CountExpression   *expression            `json:"count_expression,omitempty"`
+	ForEachExpression *expression            `json:"for_each_expression,omitempty"`
+	Module            module                 `json:"module,omitempty"`
+	VersionConstraint string                 `json:"version_constraint,omitempty"`
+	DependsOn         []string               `json:"depends_on,omitempty"`
+}
+
+// variables is the JSON representation of the variables provided to the current
+// plan.
+type variables map[string]*variable
+
+type variable struct {
+	Default     json.RawMessage `json:"default,omitempty"`
+	Description string          `json:"description,omitempty"`
+	Sensitive   bool            `json:"sensitive,omitempty"`
+}
+
+// Resource is the representation of a resource in the config
+type resource struct {
+	// Address is the absolute resource address
+	Address string `json:"address,omitempty"`
+
+	// Mode can be "managed" or "data"
+	Mode string `json:"mode,omitempty"`
+
+	Type string `json:"type,omitempty"`
+	Name string `json:"name,omitempty"`
+
+	// ProviderConfigKey is the key into "provider_configs" (shown above) for
+	// the provider configuration that this resource is associated with.
+	//
+	// NOTE: If a given resource is in a ModuleCall, and the provider was
+	// configured outside of the module (in a higher level configuration file),
+	// the ProviderConfigKey will not match a key in the ProviderConfigs map.
+	ProviderConfigKey string `json:"provider_config_key,omitempty"`
+
+	// Provisioners is an optional field which describes any provisioners.
+	// Connection info will not be included here.
+	Provisioners []provisioner `json:"provisioners,omitempty"`
+
+	// Expressions" describes the resource-type-specific  content of the
+	// configuration block.
+	Expressions map[string]interface{} `json:"expressions,omitempty"`
+
+	// SchemaVersion indicates which version of the resource type schema the
+	// "values" property conforms to.
+	SchemaVersion uint64 `json:"schema_version"`
+
+	// CountExpression and ForEachExpression describe the expressions given for
+	// the corresponding meta-arguments in the resource configuration block.
+	// These are omitted if the corresponding argument isn't set.
+	CountExpression   *expression `json:"count_expression,omitempty"`
+	ForEachExpression *expression `json:"for_each_expression,omitempty"`
+
+	DependsOn []string `json:"depends_on,omitempty"`
+}
+
+type output struct {
+	Sensitive   bool       `json:"sensitive,omitempty"`
+	Expression  expression `json:"expression,omitempty"`
+	DependsOn   []string   `json:"depends_on,omitempty"`
+	Description string     `json:"description,omitempty"`
+}
+
+type provisioner struct {
+	Type        string                 `json:"type,omitempty"`
+	Expressions map[string]interface{} `json:"expressions,omitempty"`
+}
+
+// Marshal returns the json encoding of terraform configuration.
+func Marshal(c *configs.Config, schemas *terraform.Schemas) ([]byte, error) {
+	var output config
+
+	pcs := make(map[string]providerConfig)
+	marshalProviderConfigs(c, schemas, pcs)
+
+	rootModule, err := marshalModule(c, schemas, "")
+	if err != nil {
+		return nil, err
+	}
+	output.RootModule = rootModule
+
+	normalizeModuleProviderKeys(&rootModule, pcs)
+
+	for name, pc := range pcs {
+		if pc.parentKey != "" {
+			delete(pcs, name)
+		}
+	}
+	output.ProviderConfigs = pcs
+
+	ret, err := json.Marshal(output)
+	return ret, err
+}
+
+func marshalProviderConfigs(
+	c *configs.Config,
+	schemas *terraform.Schemas,
+	m map[string]providerConfig,
+) {
+	if c == nil {
+		return
+	}
+
+	// We want to determine only the provider requirements from this module,
+	// ignoring any descendants.  Disregard any diagnostics when determining
+	// requirements because we want this marshalling to succeed even if there
+	// are invalid constraints.
+	reqs, _ := c.ProviderRequirementsShallow()
+
+	// Add an entry for each provider configuration block in the module.
+	for k, pc := range c.Module.ProviderConfigs {
+		providerFqn := c.ProviderForConfigAddr(addrs.LocalProviderConfig{LocalName: pc.Name})
+		schema := schemas.ProviderConfig(providerFqn)
+
+		p := providerConfig{
+			Name:          pc.Name,
+			FullName:      providerFqn.String(),
+			Alias:         pc.Alias,
+			ModuleAddress: c.Path.String(),
+			Expressions:   marshalExpressions(pc.Config, schema),
+		}
+
+		// Store the fully resolved provider version constraint, rather than
+		// using the version argument in the configuration block. This is both
+		// future proof (for when we finish the deprecation of the provider config
+		// version argument) and more accurate (as it reflects the full set of
+		// constraints, in case there are multiple).
+		if vc, ok := reqs[providerFqn]; ok {
+			p.VersionConstraint = getproviders.VersionConstraintsString(vc)
+		}
+
+		key := opaqueProviderKey(k, c.Path.String())
+
+		m[key] = p
+	}
+
+	// Ensure that any required providers with no associated configuration
+	// block are included in the set.
+	for k, pr := range c.Module.ProviderRequirements.RequiredProviders {
+		// If a provider has aliases defined, process those first.
+		for _, alias := range pr.Aliases {
+			// If there exists a value for this provider, we have nothing to add
+			// to it, so skip.
+			key := opaqueProviderKey(alias.StringCompact(), c.Path.String())
+			if _, exists := m[key]; exists {
+				continue
+			}
+			// Given no provider configuration block exists, the only fields we can
+			// fill here are the local name, FQN, module address, and version
+			// constraints.
+			p := providerConfig{
+				Name:          pr.Name,
+				FullName:      pr.Type.String(),
+				ModuleAddress: c.Path.String(),
+			}
+
+			if vc, ok := reqs[pr.Type]; ok {
+				p.VersionConstraint = getproviders.VersionConstraintsString(vc)
+			}
+
+			m[key] = p
+		}
+
+		// If there exists a value for this provider, we have nothing to add
+		// to it, so skip.
+		key := opaqueProviderKey(k, c.Path.String())
+		if _, exists := m[key]; exists {
+			continue
+		}
+
+		// Given no provider configuration block exists, the only fields we can
+		// fill here are the local name, module address, and version
+		// constraints.
+		p := providerConfig{
+			Name:          pr.Name,
+			FullName:      pr.Type.String(),
+			ModuleAddress: c.Path.String(),
+		}
+
+		if vc, ok := reqs[pr.Type]; ok {
+			p.VersionConstraint = getproviders.VersionConstraintsString(vc)
+		}
+
+		if c.Parent != nil {
+			parentKey := opaqueProviderKey(pr.Name, c.Parent.Path.String())
+			p.parentKey = findSourceProviderKey(parentKey, p.FullName, m)
+		}
+
+		m[key] = p
+	}
+
+	// Providers could be implicitly created or inherited from the parent module
+	// when no requirements and configuration block defined.
+	for req := range reqs {
+		// Only default providers could implicitly exist,
+		// so the provider name must be same as the provider type.
+		key := opaqueProviderKey(req.Type, c.Path.String())
+		if _, exists := m[key]; exists {
+			continue
+		}
+
+		p := providerConfig{
+			Name:          req.Type,
+			FullName:      req.String(),
+			ModuleAddress: c.Path.String(),
+		}
+
+		// In child modules, providers defined in the parent module can be implicitly used.
+		if c.Parent != nil {
+			parentKey := opaqueProviderKey(req.Type, c.Parent.Path.String())
+			p.parentKey = findSourceProviderKey(parentKey, p.FullName, m)
+		}
+
+		m[key] = p
+	}
+
+	// Must also visit our child modules, recursively.
+	for name, mc := range c.Module.ModuleCalls {
+		// Keys in c.Children are guaranteed to match those in c.Module.ModuleCalls
+		cc := c.Children[name]
+
+		// Add provider config map entries for passed provider configs,
+		// pointing at the passed configuration
+		for _, ppc := range mc.Providers {
+			// These provider names include aliases, if set
+			moduleProviderName := ppc.InChild.String()
+			parentProviderName := ppc.InParent.String()
+
+			// Look up the provider FQN from the module context, using the non-aliased local name
+			providerFqn := cc.ProviderForConfigAddr(addrs.LocalProviderConfig{LocalName: ppc.InChild.Name})
+
+			// The presence of passed provider configs means that we cannot have
+			// any configuration expressions or version constraints here
+			p := providerConfig{
+				Name:          moduleProviderName,
+				FullName:      providerFqn.String(),
+				ModuleAddress: cc.Path.String(),
+			}
+
+			key := opaqueProviderKey(moduleProviderName, cc.Path.String())
+			parentKey := opaqueProviderKey(parentProviderName, cc.Parent.Path.String())
+			p.parentKey = findSourceProviderKey(parentKey, p.FullName, m)
+
+			m[key] = p
+		}
+
+		// Finally, marshal any other provider configs within the called module.
+		// It is safe to do this last because it is invalid to configure a
+		// provider which has passed provider configs in the module call.
+		marshalProviderConfigs(cc, schemas, m)
+	}
+}
+
+func marshalModule(c *configs.Config, schemas *terraform.Schemas, addr string) (module, error) {
+	var module module
+	var rs []resource
+
+	managedResources, err := marshalResources(c.Module.ManagedResources, schemas, addr)
+	if err != nil {
+		return module, err
+	}
+	dataResources, err := marshalResources(c.Module.DataResources, schemas, addr)
+	if err != nil {
+		return module, err
+	}
+
+	rs = append(managedResources, dataResources...)
+	module.Resources = rs
+
+	outputs := make(map[string]output)
+	for _, v := range c.Module.Outputs {
+		o := output{
+			Sensitive:  v.Sensitive,
+			Expression: marshalExpression(v.Expr),
+		}
+		if v.Description != "" {
+			o.Description = v.Description
+		}
+		if len(v.DependsOn) > 0 {
+			dependencies := make([]string, len(v.DependsOn))
+			for i, d := range v.DependsOn {
+				ref, diags := addrs.ParseRef(d)
+				// we should not get an error here, because `terraform validate`
+				// would have complained well before this point, but if we do we'll
+				// silenty skip it.
+				if !diags.HasErrors() {
+					dependencies[i] = ref.Subject.String()
+				}
+			}
+			o.DependsOn = dependencies
+		}
+
+		outputs[v.Name] = o
+	}
+	module.Outputs = outputs
+
+	module.ModuleCalls = marshalModuleCalls(c, schemas)
+
+	if len(c.Module.Variables) > 0 {
+		vars := make(variables, len(c.Module.Variables))
+		for k, v := range c.Module.Variables {
+			var defaultValJSON []byte
+			if v.Default == cty.NilVal {
+				defaultValJSON = nil
+			} else {
+				defaultValJSON, err = ctyjson.Marshal(v.Default, v.Default.Type())
+				if err != nil {
+					return module, err
+				}
+			}
+			vars[k] = &variable{
+				Default:     defaultValJSON,
+				Description: v.Description,
+				Sensitive:   v.Sensitive,
+			}
+		}
+		module.Variables = vars
+	}
+
+	return module, nil
+}
+
+func marshalModuleCalls(c *configs.Config, schemas *terraform.Schemas) map[string]moduleCall {
+	ret := make(map[string]moduleCall)
+
+	for name, mc := range c.Module.ModuleCalls {
+		mcConfig := c.Children[name]
+		ret[name] = marshalModuleCall(mcConfig, mc, schemas)
+	}
+
+	return ret
+}
+
+func marshalModuleCall(c *configs.Config, mc *configs.ModuleCall, schemas *terraform.Schemas) moduleCall {
+	// It is possible to have a module call with a nil config.
+	if c == nil {
+		return moduleCall{}
+	}
+
+	ret := moduleCall{
+		// We're intentionally echoing back exactly what the user entered
+		// here, rather than the normalized version in SourceAddr, because
+		// historically we only _had_ the raw address and thus it would be
+		// a (admittedly minor) breaking change to start normalizing them
+		// now, in case consumers of this data are expecting a particular
+		// non-normalized syntax.
+		Source:            mc.SourceAddrRaw,
+		VersionConstraint: mc.Version.Required.String(),
+	}
+	cExp := marshalExpression(mc.Count)
+	if !cExp.Empty() {
+		ret.CountExpression = &cExp
+	} else {
+		fExp := marshalExpression(mc.ForEach)
+		if !fExp.Empty() {
+			ret.ForEachExpression = &fExp
+		}
+	}
+
+	schema := &configschema.Block{}
+	schema.Attributes = make(map[string]*configschema.Attribute)
+	for _, variable := range c.Module.Variables {
+		schema.Attributes[variable.Name] = &configschema.Attribute{
+			Required: variable.Default == cty.NilVal,
+		}
+	}
+
+	ret.Expressions = marshalExpressions(mc.Config, schema)
+
+	module, _ := marshalModule(c, schemas, c.Path.String())
+
+	ret.Module = module
+
+	if len(mc.DependsOn) > 0 {
+		dependencies := make([]string, len(mc.DependsOn))
+		for i, d := range mc.DependsOn {
+			ref, diags := addrs.ParseRef(d)
+			// we should not get an error here, because `terraform validate`
+			// would have complained well before this point, but if we do we'll
+			// silenty skip it.
+			if !diags.HasErrors() {
+				dependencies[i] = ref.Subject.String()
+			}
+		}
+		ret.DependsOn = dependencies
+	}
+
+	return ret
+}
+
+func marshalResources(resources map[string]*configs.Resource, schemas *terraform.Schemas, moduleAddr string) ([]resource, error) {
+	var rs []resource
+	for _, v := range resources {
+		providerConfigKey := opaqueProviderKey(v.ProviderConfigAddr().StringCompact(), moduleAddr)
+		r := resource{
+			Address:           v.Addr().String(),
+			Type:              v.Type,
+			Name:              v.Name,
+			ProviderConfigKey: providerConfigKey,
+		}
+
+		switch v.Mode {
+		case addrs.ManagedResourceMode:
+			r.Mode = "managed"
+		case addrs.DataResourceMode:
+			r.Mode = "data"
+		default:
+			return rs, fmt.Errorf("resource %s has an unsupported mode %s", r.Address, v.Mode.String())
+		}
+
+		cExp := marshalExpression(v.Count)
+		if !cExp.Empty() {
+			r.CountExpression = &cExp
+		} else {
+			fExp := marshalExpression(v.ForEach)
+			if !fExp.Empty() {
+				r.ForEachExpression = &fExp
+			}
+		}
+
+		schema, schemaVer := schemas.ResourceTypeConfig(
+			v.Provider,
+			v.Mode,
+			v.Type,
+		)
+		if schema == nil {
+			return nil, fmt.Errorf("no schema found for %s (in provider %s)", v.Addr().String(), v.Provider)
+		}
+		r.SchemaVersion = schemaVer
+
+		r.Expressions = marshalExpressions(v.Config, schema)
+
+		// Managed is populated only for Mode = addrs.ManagedResourceMode
+		if v.Managed != nil && len(v.Managed.Provisioners) > 0 {
+			var provisioners []provisioner
+			for _, p := range v.Managed.Provisioners {
+				schema := schemas.ProvisionerConfig(p.Type)
+				prov := provisioner{
+					Type:        p.Type,
+					Expressions: marshalExpressions(p.Config, schema),
+				}
+				provisioners = append(provisioners, prov)
+			}
+			r.Provisioners = provisioners
+		}
+
+		if len(v.DependsOn) > 0 {
+			dependencies := make([]string, len(v.DependsOn))
+			for i, d := range v.DependsOn {
+				ref, diags := addrs.ParseRef(d)
+				// we should not get an error here, because `terraform validate`
+				// would have complained well before this point, but if we do we'll
+				// silenty skip it.
+				if !diags.HasErrors() {
+					dependencies[i] = ref.Subject.String()
+				}
+			}
+			r.DependsOn = dependencies
+		}
+
+		rs = append(rs, r)
+	}
+	sort.Slice(rs, func(i, j int) bool {
+		return rs[i].Address < rs[j].Address
+	})
+	return rs, nil
+}
+
+// Flatten all resource provider keys in a module and its descendents, such
+// that any resources from providers using a configuration passed through the
+// module call have a direct refernce to that provider configuration.
+func normalizeModuleProviderKeys(m *module, pcs map[string]providerConfig) {
+	for i, r := range m.Resources {
+		if pc, exists := pcs[r.ProviderConfigKey]; exists {
+			if _, hasParent := pcs[pc.parentKey]; hasParent {
+				m.Resources[i].ProviderConfigKey = pc.parentKey
+			}
+		}
+	}
+
+	for _, mc := range m.ModuleCalls {
+		normalizeModuleProviderKeys(&mc.Module, pcs)
+	}
+}
+
+// opaqueProviderKey generates a unique absProviderConfig-like string from the module
+// address and provider
+func opaqueProviderKey(provider string, addr string) (key string) {
+	key = provider
+	if addr != "" {
+		key = fmt.Sprintf("%s:%s", addr, provider)
+	}
+	return key
+}
+
+// Traverse up the module call tree until we find the provider
+// configuration which has no linked parent config. This is then
+// the source of the configuration used in this module call, so
+// we link to it directly
+func findSourceProviderKey(startKey string, fullName string, m map[string]providerConfig) string {
+	var parentKey string
+
+	key := startKey
+	for key != "" {
+		parent, exists := m[key]
+		if !exists || parent.FullName != fullName {
+			break
+		}
+
+		parentKey = key
+		key = parent.parentKey
+	}
+
+	return parentKey
+}
diff --git a/v1.5.7/internal/command/jsonconfig/config_test.go b/v1.5.7/internal/command/jsonconfig/config_test.go
new file mode 100644
index 0000000..a018636
--- /dev/null
+++ b/v1.5.7/internal/command/jsonconfig/config_test.go
@@ -0,0 +1,103 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonconfig
+
+import (
+	"testing"
+)
+
+func TestFindSourceProviderConfig(t *testing.T) {
+	tests := []struct {
+		StartKey    string
+		FullName    string
+		ProviderMap map[string]providerConfig
+		Want        string
+	}{
+		{
+			StartKey:    "null",
+			FullName:    "hashicorp/null",
+			ProviderMap: map[string]providerConfig{},
+			Want:        "",
+		},
+		{
+			StartKey: "null",
+			FullName: "hashicorp/null",
+			ProviderMap: map[string]providerConfig{
+				"null": {
+					Name:          "null",
+					FullName:      "hashicorp/null",
+					ModuleAddress: "",
+				},
+			},
+			Want: "null",
+		},
+		{
+			StartKey: "null2",
+			FullName: "hashicorp/null",
+			ProviderMap: map[string]providerConfig{
+				"null": {
+					Name:          "null",
+					FullName:      "hashicorp/null",
+					ModuleAddress: "",
+				},
+			},
+			Want: "",
+		},
+		{
+			StartKey: "null",
+			FullName: "hashicorp2/null",
+			ProviderMap: map[string]providerConfig{
+				"null": {
+					Name:          "null",
+					FullName:      "hashicorp/null",
+					ModuleAddress: "",
+				},
+			},
+			Want: "",
+		},
+		{
+			StartKey: "module.a:null",
+			FullName: "hashicorp/null",
+			ProviderMap: map[string]providerConfig{
+				"null": {
+					Name:          "null",
+					FullName:      "hashicorp/null",
+					ModuleAddress: "",
+				},
+				"module.a:null": {
+					Name:          "module.a:null",
+					FullName:      "hashicorp/null",
+					ModuleAddress: "module.a",
+					parentKey:     "null",
+				},
+			},
+			Want: "null",
+		},
+		{
+			StartKey: "module.a:null",
+			FullName: "hashicorp2/null",
+			ProviderMap: map[string]providerConfig{
+				"null": {
+					Name:          "null",
+					FullName:      "hashicorp/null",
+					ModuleAddress: "",
+				},
+				"module.a:null": {
+					Name:          "module.a:null",
+					FullName:      "hashicorp2/null",
+					ModuleAddress: "module.a",
+					parentKey:     "null",
+				},
+			},
+			Want: "module.a:null",
+		},
+	}
+
+	for _, test := range tests {
+		got := findSourceProviderKey(test.StartKey, test.FullName, test.ProviderMap)
+		if got != test.Want {
+			t.Errorf("wrong result:\nGot: %#v\nWant: %#v\n", got, test.Want)
+		}
+	}
+}
diff --git a/v1.5.7/internal/command/jsonconfig/doc.go b/v1.5.7/internal/command/jsonconfig/doc.go
new file mode 100644
index 0000000..1b9d33a
--- /dev/null
+++ b/v1.5.7/internal/command/jsonconfig/doc.go
@@ -0,0 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package jsonconfig implements methods for outputting a configuration snapshot
+// in machine-readable json format
+package jsonconfig
diff --git a/v1.5.7/internal/command/jsonconfig/expression.go b/v1.5.7/internal/command/jsonconfig/expression.go
new file mode 100644
index 0000000..d6acca7
--- /dev/null
+++ b/v1.5.7/internal/command/jsonconfig/expression.go
@@ -0,0 +1,184 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonconfig
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcldec"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/lang/blocktoattr"
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+)
+
+// expression represents any unparsed expression
+type expression struct {
+	// "constant_value" is set only if the expression contains no references to
+	// other objects, in which case it gives the resulting constant value. This
+	// is mapped as for the individual values in the common value
+	// representation.
+	ConstantValue json.RawMessage `json:"constant_value,omitempty"`
+
+	// Alternatively, "references" will be set to a list of references in the
+	// expression. Multi-step references will be unwrapped and duplicated for
+	// each significant traversal step, allowing callers to more easily
+	// recognize the objects they care about without attempting to parse the
+	// expressions. Callers should only use string equality checks here, since
+	// the syntax may be extended in future releases.
+	References []string `json:"references,omitempty"`
+}
+
+func marshalExpression(ex hcl.Expression) expression {
+	var ret expression
+	if ex == nil {
+		return ret
+	}
+
+	val, _ := ex.Value(nil)
+	if val != cty.NilVal {
+		valJSON, _ := ctyjson.Marshal(val, val.Type())
+		ret.ConstantValue = valJSON
+	}
+
+	refs, _ := lang.ReferencesInExpr(ex)
+	if len(refs) > 0 {
+		var varString []string
+		for _, ref := range refs {
+			// We work backwards here, starting with the full reference +
+			// reamining traversal, and then unwrapping the remaining traversals
+			// into parts until we end up at the smallest referencable address.
+			remains := ref.Remaining
+			for len(remains) > 0 {
+				varString = append(varString, fmt.Sprintf("%s%s", ref.Subject, traversalStr(remains)))
+				remains = remains[:(len(remains) - 1)]
+			}
+			varString = append(varString, ref.Subject.String())
+
+			switch ref.Subject.(type) {
+			case addrs.ModuleCallInstance:
+				if ref.Subject.(addrs.ModuleCallInstance).Key != addrs.NoKey {
+					// Include the module call, without the key
+					varString = append(varString, ref.Subject.(addrs.ModuleCallInstance).Call.String())
+				}
+			case addrs.ResourceInstance:
+				if ref.Subject.(addrs.ResourceInstance).Key != addrs.NoKey {
+					// Include the resource, without the key
+					varString = append(varString, ref.Subject.(addrs.ResourceInstance).Resource.String())
+				}
+			case addrs.ModuleCallInstanceOutput:
+				// Include the module name, without the output name
+				varString = append(varString, ref.Subject.(addrs.ModuleCallInstanceOutput).Call.String())
+			}
+		}
+		ret.References = varString
+	}
+
+	return ret
+}
+
+func (e *expression) Empty() bool {
+	return e.ConstantValue == nil && e.References == nil
+}
+
+// expressions is used to represent the entire content of a block. Attribute
+// arguments are mapped directly with the attribute name as key and an
+// expression as value.
+type expressions map[string]interface{}
+
+func marshalExpressions(body hcl.Body, schema *configschema.Block) expressions {
+	// Since we want the raw, un-evaluated expressions we need to use the
+	// low-level HCL API here, rather than the hcldec decoder API. That means we
+	// need the low-level schema.
+	lowSchema := hcldec.ImpliedSchema(schema.DecoderSpec())
+	// (lowSchema is an hcl.BodySchema:
+	// https://godoc.org/github.com/hashicorp/hcl/v2/hcl#BodySchema )
+
+	// fix any ConfigModeAttr blocks present from legacy providers
+	body = blocktoattr.FixUpBlockAttrs(body, schema)
+
+	// Use the low-level schema with the body to decode one level We'll just
+	// ignore any additional content that's not covered by the schema, which
+	// will effectively ignore "dynamic" blocks, and may also ignore other
+	// unknown stuff but anything else would get flagged by Terraform as an
+	// error anyway, and so we wouldn't end up in here.
+	content, _, _ := body.PartialContent(lowSchema)
+	if content == nil {
+		// Should never happen for a valid body, but we'll just generate empty
+		// if there were any problems.
+		return nil
+	}
+
+	ret := make(expressions)
+
+	// Any attributes we encode directly as expression objects.
+	for name, attr := range content.Attributes {
+		ret[name] = marshalExpression(attr.Expr) // note: singular expression for this one
+	}
+
+	// Any nested blocks require a recursive call to produce nested expressions
+	// objects.
+	for _, block := range content.Blocks {
+		typeName := block.Type
+		blockS, exists := schema.BlockTypes[typeName]
+		if !exists {
+			// Should never happen since only block types in the schema would be
+			// put in blocks list
+			continue
+		}
+
+		switch blockS.Nesting {
+		case configschema.NestingSingle, configschema.NestingGroup:
+			ret[typeName] = marshalExpressions(block.Body, &blockS.Block)
+		case configschema.NestingList, configschema.NestingSet:
+			if _, exists := ret[typeName]; !exists {
+				ret[typeName] = make([]map[string]interface{}, 0, 1)
+			}
+			ret[typeName] = append(ret[typeName].([]map[string]interface{}), marshalExpressions(block.Body, &blockS.Block))
+		case configschema.NestingMap:
+			if _, exists := ret[typeName]; !exists {
+				ret[typeName] = make(map[string]map[string]interface{})
+			}
+			// NestingMap blocks always have the key in the first (and only) label
+			key := block.Labels[0]
+			retMap := ret[typeName].(map[string]map[string]interface{})
+			retMap[key] = marshalExpressions(block.Body, &blockS.Block)
+		}
+	}
+
+	return ret
+}
+
+// traversalStr produces a representation of an HCL traversal that is compact,
+// resembles HCL native syntax, and is suitable for display in the UI.
+//
+// This was copied (and simplified) from internal/command/views/json/diagnostic.go.
+func traversalStr(traversal hcl.Traversal) string {
+	var buf bytes.Buffer
+	for _, step := range traversal {
+		switch tStep := step.(type) {
+		case hcl.TraverseRoot:
+			buf.WriteString(tStep.Name)
+		case hcl.TraverseAttr:
+			buf.WriteByte('.')
+			buf.WriteString(tStep.Name)
+		case hcl.TraverseIndex:
+			buf.WriteByte('[')
+			switch tStep.Key.Type() {
+			case cty.String:
+				buf.WriteString(fmt.Sprintf("%q", tStep.Key.AsString()))
+			case cty.Number:
+				bf := tStep.Key.AsBigFloat()
+				buf.WriteString(bf.Text('g', 10))
+			}
+			buf.WriteByte(']')
+		}
+	}
+	return buf.String()
+}
diff --git a/v1.5.7/internal/command/jsonconfig/expression_test.go b/v1.5.7/internal/command/jsonconfig/expression_test.go
new file mode 100644
index 0000000..6e1da0a
--- /dev/null
+++ b/v1.5.7/internal/command/jsonconfig/expression_test.go
@@ -0,0 +1,150 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonconfig
+
+import (
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/hcl/v2/hcltest"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+func TestMarshalExpressions(t *testing.T) {
+	tests := []struct {
+		Input hcl.Body
+		Want  expressions
+	}{
+		{
+			&hclsyntax.Body{
+				Attributes: hclsyntax.Attributes{
+					"foo": &hclsyntax.Attribute{
+						Expr: &hclsyntax.LiteralValueExpr{
+							Val: cty.StringVal("bar"),
+						},
+					},
+				},
+			},
+			expressions{
+				"foo": expression{
+					ConstantValue: json.RawMessage([]byte(`"bar"`)),
+					References:    []string(nil),
+				},
+			},
+		},
+		{
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"foo": {
+						Name: "foo",
+						Expr: hcltest.MockExprTraversalSrc(`var.list[1]`),
+					},
+				},
+			}),
+			expressions{
+				"foo": expression{
+					References: []string{"var.list[1]", "var.list"},
+				},
+			},
+		},
+		{
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"foo": {
+						Name: "foo",
+						Expr: hcltest.MockExprTraversalSrc(`data.template_file.foo[1].vars["baz"]`),
+					},
+				},
+			}),
+			expressions{
+				"foo": expression{
+					References: []string{"data.template_file.foo[1].vars[\"baz\"]", "data.template_file.foo[1].vars", "data.template_file.foo[1]", "data.template_file.foo"},
+				},
+			},
+		},
+		{
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"foo": {
+						Name: "foo",
+						Expr: hcltest.MockExprTraversalSrc(`module.foo.bar`),
+					},
+				},
+			}),
+			expressions{
+				"foo": expression{
+					References: []string{"module.foo.bar", "module.foo"},
+				},
+			},
+		},
+		{
+			hcltest.MockBody(&hcl.BodyContent{
+				Blocks: hcl.Blocks{
+					{
+						Type: "block_to_attr",
+						Body: hcltest.MockBody(&hcl.BodyContent{
+
+							Attributes: hcl.Attributes{
+								"foo": {
+									Name: "foo",
+									Expr: hcltest.MockExprTraversalSrc(`module.foo.bar`),
+								},
+							},
+						}),
+					},
+				},
+			}),
+			expressions{
+				"block_to_attr": expression{
+					References: []string{"module.foo.bar", "module.foo"},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		schema := &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"foo": {
+					Type:     cty.String,
+					Optional: true,
+				},
+				"block_to_attr": {
+					Type: cty.List(cty.Object(map[string]cty.Type{
+						"foo": cty.String,
+					})),
+				},
+			},
+		}
+
+		got := marshalExpressions(test.Input, schema)
+		if !reflect.DeepEqual(got, test.Want) {
+			t.Errorf("wrong result:\nGot: %#v\nWant: %#v\n", got, test.Want)
+		}
+	}
+}
+
+func TestMarshalExpression(t *testing.T) {
+	tests := []struct {
+		Input hcl.Expression
+		Want  expression
+	}{
+		{
+			nil,
+			expression{},
+		},
+	}
+
+	for _, test := range tests {
+		got := marshalExpression(test.Input)
+		if !reflect.DeepEqual(got, test.Want) {
+			t.Fatalf("wrong result:\nGot: %#v\nWant: %#v\n", got, test.Want)
+		}
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/README.md b/v1.5.7/internal/command/jsonformat/README.md
new file mode 100644
index 0000000..c19cbc7
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/README.md
@@ -0,0 +1,244 @@
+# jsonformat
+
+This package contains functionality around formatting and displaying the JSON
+structured output produced by adding the `-json` flag to various Terraform
+commands.
+
+## Terraform Structured Plan Renderer
+
+As of January 2023, this package contains only a single structure: the 
+`Renderer`.
+
+The renderer accepts the JSON structured output produced by the 
+`terraform show <plan-file> -json` command and writes it in a human-readable
+format.
+
+Implementation details and decisions for the `Renderer` are discussed in the
+following sections.
+
+### Implementation
+
+There are two subpackages within the `jsonformat` renderer package. The `differ`
+package compares the `before` and `after` values of the given plan and produces
+`Diff` objects from the `computed` package.
+
+This approach is aimed at ensuring the process by which the plan difference is
+calculated is separated from the rendering itself. In this way it should be 
+possible to modify the rendering or add new renderer formats without being
+concerned with the complex diff calculations.
+
+#### The `differ` package
+
+The `differ` package operates on `Change` objects. These are produced from
+`jsonplan.Change` objects (which are produced by the `terraform show` command).
+Each `jsonplan.Change` object represents a single resource within the overall
+Terraform configuration.
+
+The `differ` package will iterate through the `Change` objects and produce a 
+single `Diff` that represents a processed summary of the changes described by 
+the `Change`. You will see that the produced changes are nested so a change to a
+list attribute will contain a slice of changes, this is discussed in the 
+"[The computed package](#the-computed-package)" section.
+
+##### The `Change` object
+
+The `Change` objects contain raw Golang representations of JSON objects (generic
+`interface{}` fields). These are produced by parsing the `json.RawMessage` 
+objects within the provided changes.
+
+The fields the differ cares about from the provided changes are:
+
+- `Before`: The value before the proposed change.
+- `After`: The value after the proposed change.
+- `Unknown`: If the value is being computed during the change.
+- `BeforeSensitive`: If the value was sensitive before the change.
+- `AfterSensitive`: If the value is sensitive after the change.
+- `ReplacePaths`: If the change is causing the overall resource to be replaced.
+
+In addition, the changes define two additional meta fields that they set and
+manipulate internally:
+
+- `BeforeExplicit`: If the value in `Before` is explicit or an implied result due to a change elsewhere.
+- `AfterExplicit`: If the value in `After` is explicit or an implied result due to a change elsewhere.
+
+The actual concrete type of each of the generic fields is determined by the 
+overall schema. The changes are also recursive, this means as we iterate through 
+the `Change` we create relevant child values based on the schema for the given 
+resource.
+
+For example, the initial change is always a `block` type which means the 
+`Before` and `After` values will actually be `map[string]interface{}` types 
+mapping each attribute and block to their relevant values. The
+`Unknown`, `BeforeSensitive`, `AfterSensitive` values will all be either a
+`map[string]interface{}` which maps each attribute or nested block to their
+unknown and sensitive status, or it could simply be a `boolean` which generally
+means the entire block and all children are sensitive or computed.
+
+In total, a `Change` can represent the following types:
+
+- `Attribute`
+  - `map`: Values will typically be `map[string]interface{}`.
+  - `list`: Values will typically be `[]interface{}`.
+  - `set`: Values will typically be `[]interface{}`.
+  - `object`: Values will typically be `map[string]interface{}`.
+  - `tuple`: Values will typically be `[]interface{}`.
+  - `bool`: Values will typically be a `bool`.
+  - `number`: Values will typically be a `float64`.
+  - `string`: Values will typically be a `string`.
+- `Block`: Values will typically be `map[string]interface{}`, but they can be
+           split between nested blocks and attributes.
+- `Output`
+  - Outputs are interesting as we don't have a schema for them, as such they
+    can be any JSON type.
+  - We also use the Output type to represent dynamic attributes, since in both 
+    cases we work out the type based on the JSON representation instead of the
+    schema.
+
+The `ReplacePaths` field is unique in that it's value doesn't actually change
+based on the schema - it's always a slice of index slices. An index in this
+context will either be an integer pointing to a child of a set or a list or a
+string pointing to the child of a map, object or block. As we iterate through 
+the value we manipulate the outer slice to remove child slices where the index
+doesn't match and propagate paths that do match onto the children.
+
+*Quick note on explicit vs implicit:* In practice, it is only possible to get 
+implicit changes when you manipulate a collection. That is to say child values 
+of a modified collection will insert `nil` entries into the relevant before 
+or after fields of their child changes to represent their values being deleted
+or created. It is also possible for users to explicitly put null values into 
+their collections, and this behaviour is different to deleting an item in the
+collection. With the `BeforeExplicit` and `AfterExplicit` values we can tell the
+difference between whether this value was removed from a collection or this 
+value was set to null in a collection.
+
+*Quick note on the go-cty Value and Type objects:* The `Before` and `After` 
+fields are actually go-cty values, but we cannot convert them directly because 
+of the  Terraform Cloud redacted endpoint. The redacted endpoint turns sensitive
+values into strings regardless of their types. Because of this, we cannot just 
+do a direct conversion using the ctyjson package. We would have to iterate 
+through the schema first, find the sensitive values and their mapped types, 
+update the types inside the schema to strings, and then go back and do the 
+overall conversion. This isn't including any of the more complicated parts 
+around what happens if something was sensitive before and isn't sensitive after 
+or vice versa. This would mean the type would need to change between the before 
+and after value. It is in fact just easier to iterate through the values as 
+generic JSON interfaces, and obfuscate the sensitive values as we never need to 
+print them anyway.
+
+##### Iterating through changes
+
+The `differ` package will recursively create child `Change` objects for the 
+complex objects.
+
+There are two key subtypes of a `Change`: `SliceChange` and `MapChange`. 
+`SliceChange` values are used by list, set, and tuple attributes. `MapChange` 
+values are used by map and object attributes, and blocks. For what it is worth 
+outputs and dynamic types can end up using both, but they're kind of special as 
+the processing for dynamic types works out the type from the JSON struct and 
+then just passes it into the relevant real types for actual processing.
+
+The two subtypes implement `GetChild` functions that retrieve a child change
+for a relevant index (`int` for slice, `string` for map). These functions build
+an entirely populated `Change` object, and the package will then recursively 
+compute the change for the child (and all other children). When a complex change
+has all the children changes, it then passes that into the relevant complex 
+diff type.
+
+#### The `computed` package
+
+A computed `Diff` should contain all the relevant information it needs to render 
+itself.
+
+The `Diff` itself contains the action (eg. `Create`, `Delete`, `Update`), and
+whether this change is causing the overall resource to be replaced (read from 
+the `ReplacePaths` field discussed in the previous section). The actual content 
+of the diffs is passed directly into the internal renderer field. The internal
+renderer is then an implementation that knows the actual content of the changes
+and what they represent.
+
+For example to instantiate a diff resulting from updating a list of 
+primitives:
+
+```go
+    listDiff := computed.NewDiff(renderers.List([]computed.Diff{
+        computed.NewDiff(renderers.Primitive(0.0, 0.0, cty.Number), plans.NoOp, false),
+        computed.NewDiff(renderers.Primitive(1.0, nil, cty.Number), plans.Delete, false),
+        computed.NewDiff(renderers.Primitive(nil, 4.0, cty.Number), plans.Create, false),
+        computed.NewDiff(renderers.Primitive(2.0, 2.0, cty.Number), plans.NoOp, false)
+    }, plans.Update, false))
+```
+
+##### The `RenderHuman` function
+
+Currently, there is only one way to render a change, and it is implemented via
+the `RenderHuman` function. In the future, there may be additional rendering 
+capabilities, but for now the `RenderHuman` function just passes the call 
+directly onto the internal renderer.
+
+Rendering the above diff with: `listDiff.RenderHuman(0, RenderOpts{})` would
+produce:
+
+```text
+[
+    0,
+  - 1 -> null,
+  + 4, 
+    2,
+]    
+```
+
+Note, the render function itself doesn't print out metadata about its own change
+(eg. there's no `~` symbol in front of the opening bracket). The expectation is
+that parent changes control how child changes are rendered, so are responsible
+for deciding on their opening indentation, whether they have a key (as in maps, 
+objects, and blocks), or how the action symbol is displayed.
+
+In the above example, the primitive renderer would print out only `1 -> null` 
+while the surrounding list renderer is providing the indentation, the symbol and
+the line ending commas.
+
+##### Implementing new diff types
+
+To implement a new diff type, you must implement the internal Renderer 
+functionality. To do this you create a new implementation of the 
+`computed.DiffRenderer`, make sure it accepts all the data you need, and 
+implement the `RenderHuman` function (and any other additional render functions 
+that may exist).
+
+Some changes publish warnings that should be displayed alongside them. 
+If your new change has no warnings you can use the `NoWarningsRenderer` to avoid
+implementing the additional `Warnings` function.
+
+If/when new Renderer types are implemented, additional `Render` like functions
+will be added. You should implement all of these with your new change type.
+
+##### Implementing new renderer types for changes
+
+As of January 2023, there is only a single type of renderer (the human-readable)
+renderer. As such, the `Diff` structure provides a single `RenderHuman` 
+function.
+
+To implement a new renderer:
+
+1. Add a new render function onto the internal `DiffRenderer` interface.
+2. Add a new render function onto the `Diff` struct that passes the call onto
+   the internal renderer.
+3. Implement the new function on all the existing internal interfaces.
+
+Since each internal renderer contains all the information it needs to provide
+change information about itself, your new Render function should pass in 
+anything it needs.
+
+### New types of Renderer
+
+In the future, we may wish to add in different kinds of renderer, such as a 
+compact renderer, or an interactive renderer. To do this, you'll need to modify
+the Renderer struct or create a new type of Renderer.
+
+The logic around creating the `Diff` structures will be shared (ie. calling 
+into the differ package should be consistent across renderers). But when it 
+comes to rendering the changes, I'd expect the `Diff` structures to implement
+additional functions that allow them to internally organise the data as required
+and return a relevant object. For the existing human-readable renderer that is 
+simply a string, but for a future interactive renderer it might be a model from
+an MVC pattern.
diff --git a/v1.5.7/internal/command/jsonformat/collections/action.go b/v1.5.7/internal/command/jsonformat/collections/action.go
new file mode 100644
index 0000000..671fa77
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/collections/action.go
@@ -0,0 +1,19 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package collections
+
+import "github.com/hashicorp/terraform/internal/plans"
+
+// CompareActions will compare current and next, and return plans.Update if they
+// are different, and current if they are the same.
+func CompareActions(current, next plans.Action) plans.Action {
+	if next == plans.NoOp {
+		return current
+	}
+
+	if current != next {
+		return plans.Update
+	}
+	return current
+}
diff --git a/v1.5.7/internal/command/jsonformat/collections/map.go b/v1.5.7/internal/command/jsonformat/collections/map.go
new file mode 100644
index 0000000..23a46d6
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/collections/map.go
@@ -0,0 +1,29 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package collections
+
+import (
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+type ProcessKey func(key string) computed.Diff
+
+func TransformMap[Input any](before, after map[string]Input, keys []string, process ProcessKey) (map[string]computed.Diff, plans.Action) {
+	current := plans.NoOp
+	if before != nil && after == nil {
+		current = plans.Delete
+	}
+	if before == nil && after != nil {
+		current = plans.Create
+	}
+
+	elements := make(map[string]computed.Diff)
+	for _, key := range keys {
+		elements[key] = process(key)
+		current = CompareActions(current, elements[key].Action)
+	}
+
+	return elements, current
+}
diff --git a/v1.5.7/internal/command/jsonformat/collections/slice.go b/v1.5.7/internal/command/jsonformat/collections/slice.go
new file mode 100644
index 0000000..9b0cfc9
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/collections/slice.go
@@ -0,0 +1,75 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package collections
+
+import (
+	"reflect"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/objchange"
+)
+
+type TransformIndices func(before, after int) computed.Diff
+type ProcessIndices func(before, after int)
+type IsObjType[Input any] func(input Input) bool
+
+func TransformSlice[Input any](before, after []Input, process TransformIndices, isObjType IsObjType[Input]) ([]computed.Diff, plans.Action) {
+	current := plans.NoOp
+	if before != nil && after == nil {
+		current = plans.Delete
+	}
+	if before == nil && after != nil {
+		current = plans.Create
+	}
+
+	var elements []computed.Diff
+	ProcessSlice(before, after, func(before, after int) {
+		element := process(before, after)
+		elements = append(elements, element)
+		current = CompareActions(current, element.Action)
+	}, isObjType)
+	return elements, current
+}
+
+func ProcessSlice[Input any](before, after []Input, process ProcessIndices, isObjType IsObjType[Input]) {
+	lcs := objchange.LongestCommonSubsequence(before, after, func(before, after Input) bool {
+		return reflect.DeepEqual(before, after)
+	})
+
+	var beforeIx, afterIx, lcsIx int
+	for beforeIx < len(before) || afterIx < len(after) || lcsIx < len(lcs) {
+		// Step through all the before values until we hit the next item in the
+		// longest common subsequence. We are going to just say that all of
+		// these have been deleted.
+		for beforeIx < len(before) && (lcsIx >= len(lcs) || !reflect.DeepEqual(before[beforeIx], lcs[lcsIx])) {
+			isObjectDiff := isObjType(before[beforeIx]) && afterIx < len(after) && isObjType(after[afterIx]) && (lcsIx >= len(lcs) || !reflect.DeepEqual(after[afterIx], lcs[lcsIx]))
+			if isObjectDiff {
+				process(beforeIx, afterIx)
+				beforeIx++
+				afterIx++
+				continue
+			}
+
+			process(beforeIx, len(after))
+			beforeIx++
+		}
+
+		// Now, step through all the after values until hit the next item in the
+		// LCS. We are going to say that all of these have been created.
+		for afterIx < len(after) && (lcsIx >= len(lcs) || !reflect.DeepEqual(after[afterIx], lcs[lcsIx])) {
+			process(len(before), afterIx)
+			afterIx++
+		}
+
+		// Finally, add the item in common as unchanged.
+		if lcsIx < len(lcs) {
+			process(beforeIx, afterIx)
+			beforeIx++
+			afterIx++
+			lcsIx++
+		}
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/diff.go b/v1.5.7/internal/command/jsonformat/computed/diff.go
new file mode 100644
index 0000000..54a6f2f
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/diff.go
@@ -0,0 +1,123 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package computed
+
+import (
+	"github.com/mitchellh/colorstring"
+
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+// Diff captures the computed diff for a single block, element or attribute.
+//
+// It essentially merges common functionality across all types of changes,
+// namely the replace logic and the action / change type. Any remaining
+// behaviour can be offloaded to the renderer which will be unique for the
+// various change types (eg. maps, objects, lists, blocks, primitives, etc.).
+type Diff struct {
+	// Renderer captures the uncommon functionality across the different kinds
+	// of changes. Each type of change (lists, blocks, sets, etc.) will have a
+	// unique renderer.
+	Renderer DiffRenderer
+
+	// Action is the action described by this change (such as create, delete,
+	// update, etc.).
+	Action plans.Action
+
+	// Replace tells the Change that it should add the `# forces replacement`
+	// suffix.
+	//
+	// Every single change could potentially add this suffix, so we embed it in
+	// the change as common functionality instead of in the specific renderers.
+	Replace bool
+}
+
+// NewDiff creates a new Diff object with the provided renderer, action and
+// replace context.
+func NewDiff(renderer DiffRenderer, action plans.Action, replace bool) Diff {
+	return Diff{
+		Renderer: renderer,
+		Action:   action,
+		Replace:  replace,
+	}
+}
+
+// RenderHuman prints the Change into a human-readable string referencing the
+// specified RenderOpts.
+//
+// If the returned string is a single line, then indent should be ignored.
+//
+// If the return string is multiple lines, then indent should be used to offset
+// the beginning of all lines but the first by the specified amount.
+func (diff Diff) RenderHuman(indent int, opts RenderHumanOpts) string {
+	return diff.Renderer.RenderHuman(diff, indent, opts)
+}
+
+// WarningsHuman returns a list of strings that should be rendered as warnings
+// before a given change is rendered.
+//
+// As with the RenderHuman function, the indent should only be applied on
+// multiline warnings and on the second and following lines.
+func (diff Diff) WarningsHuman(indent int, opts RenderHumanOpts) []string {
+	return diff.Renderer.WarningsHuman(diff, indent, opts)
+}
+
+type DiffRenderer interface {
+	RenderHuman(diff Diff, indent int, opts RenderHumanOpts) string
+	WarningsHuman(diff Diff, indent int, opts RenderHumanOpts) []string
+}
+
+// RenderHumanOpts contains options that can control how the human render
+// function of the DiffRenderer will function.
+type RenderHumanOpts struct {
+	Colorize *colorstring.Colorize
+
+	// OverrideNullSuffix tells the Renderer not to display the `-> null` suffix
+	// that is normally displayed when an element, attribute, or block is
+	// deleted.
+	OverrideNullSuffix bool
+
+	// OverrideForcesReplacement tells the Renderer to display the
+	// `# forces replacement` suffix, even if a diff doesn't have the Replace
+	// field set.
+	//
+	// Some renderers (like the Set renderer) don't display the suffix
+	// themselves but force their child diffs to display it instead.
+	OverrideForcesReplacement bool
+
+	// ShowUnchangedChildren instructs the Renderer to render all children of a
+	// given complex change, instead of hiding unchanged items and compressing
+	// them into a single line.
+	ShowUnchangedChildren bool
+
+	// HideDiffActionSymbols tells the renderer not to show the '+'/'-' symbols
+	// and to skip the places where the symbols would result in an offset.
+	HideDiffActionSymbols bool
+}
+
+// NewRenderHumanOpts creates a new RenderHumanOpts struct with the required
+// fields set.
+func NewRenderHumanOpts(colorize *colorstring.Colorize) RenderHumanOpts {
+	return RenderHumanOpts{
+		Colorize: colorize,
+	}
+}
+
+// Clone returns a new RenderOpts object, that matches the original but can be
+// edited without changing the original.
+func (opts RenderHumanOpts) Clone() RenderHumanOpts {
+	return RenderHumanOpts{
+		Colorize: opts.Colorize,
+
+		OverrideNullSuffix:    opts.OverrideNullSuffix,
+		ShowUnchangedChildren: opts.ShowUnchangedChildren,
+		HideDiffActionSymbols: opts.HideDiffActionSymbols,
+
+		// OverrideForcesReplacement is a special case in that it doesn't
+		// cascade. So each diff should decide independently whether it's direct
+		// children should override their internal Replace logic, instead of
+		// an ancestor making the switch and affecting the entire tree.
+		OverrideForcesReplacement: false,
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/doc.go b/v1.5.7/internal/command/jsonformat/computed/doc.go
new file mode 100644
index 0000000..8066682
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/doc.go
@@ -0,0 +1,10 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package computed contains types that represent the computed diffs for
+// Terraform blocks, attributes, and outputs.
+//
+// Each Diff struct is made up of a renderer, an action, and a boolean
+// describing the diff. The renderer internally holds child diffs or concrete
+// values that allow it to know how to render the diff appropriately.
+package computed
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/block.go b/v1.5.7/internal/command/jsonformat/computed/renderers/block.go
new file mode 100644
index 0000000..576fac1
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/block.go
@@ -0,0 +1,184 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"bytes"
+	"fmt"
+	"sort"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+var (
+	_ computed.DiffRenderer = (*blockRenderer)(nil)
+
+	importantAttributes = []string{
+		"id",
+		"name",
+		"tags",
+	}
+)
+
+func importantAttribute(attr string) bool {
+	for _, attribute := range importantAttributes {
+		if attribute == attr {
+			return true
+		}
+	}
+	return false
+}
+
+func Block(attributes map[string]computed.Diff, blocks Blocks) computed.DiffRenderer {
+	return &blockRenderer{
+		attributes: attributes,
+		blocks:     blocks,
+	}
+}
+
+type blockRenderer struct {
+	NoWarningsRenderer
+
+	attributes map[string]computed.Diff
+	blocks     Blocks
+}
+
+func (renderer blockRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string {
+	if len(renderer.attributes) == 0 && len(renderer.blocks.GetAllKeys()) == 0 {
+		return fmt.Sprintf("{}%s", forcesReplacement(diff.Replace, opts))
+	}
+
+	unchangedAttributes := 0
+	unchangedBlocks := 0
+
+	maximumAttributeKeyLen := 0
+	var attributeKeys []string
+	escapedAttributeKeys := make(map[string]string)
+	for key := range renderer.attributes {
+		attributeKeys = append(attributeKeys, key)
+		escapedKey := EnsureValidAttributeName(key)
+		escapedAttributeKeys[key] = escapedKey
+		if maximumAttributeKeyLen < len(escapedKey) {
+			maximumAttributeKeyLen = len(escapedKey)
+		}
+	}
+	sort.Strings(attributeKeys)
+
+	importantAttributeOpts := opts.Clone()
+	importantAttributeOpts.ShowUnchangedChildren = true
+
+	attributeOpts := opts.Clone()
+
+	var buf bytes.Buffer
+	buf.WriteString(fmt.Sprintf("{%s\n", forcesReplacement(diff.Replace, opts)))
+	for _, key := range attributeKeys {
+		attribute := renderer.attributes[key]
+		if importantAttribute(key) {
+
+			// Always display the important attributes.
+			for _, warning := range attribute.WarningsHuman(indent+1, importantAttributeOpts) {
+				buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning))
+			}
+			buf.WriteString(fmt.Sprintf("%s%s%-*s = %s\n", formatIndent(indent+1), writeDiffActionSymbol(attribute.Action, importantAttributeOpts), maximumAttributeKeyLen, key, attribute.RenderHuman(indent+1, importantAttributeOpts)))
+			continue
+		}
+		if attribute.Action == plans.NoOp && !opts.ShowUnchangedChildren {
+			unchangedAttributes++
+			continue
+		}
+
+		for _, warning := range attribute.WarningsHuman(indent+1, opts) {
+			buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning))
+		}
+		buf.WriteString(fmt.Sprintf("%s%s%-*s = %s\n", formatIndent(indent+1), writeDiffActionSymbol(attribute.Action, attributeOpts), maximumAttributeKeyLen, escapedAttributeKeys[key], attribute.RenderHuman(indent+1, attributeOpts)))
+	}
+
+	if unchangedAttributes > 0 {
+		buf.WriteString(fmt.Sprintf("%s%s%s\n", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), unchanged("attribute", unchangedAttributes, opts)))
+	}
+
+	blockKeys := renderer.blocks.GetAllKeys()
+	for _, key := range blockKeys {
+
+		foundChangedBlock := false
+		renderBlock := func(diff computed.Diff, mapKey string, opts computed.RenderHumanOpts) {
+
+			creatingSensitiveValue := diff.Action == plans.Create && renderer.blocks.AfterSensitiveBlocks[key]
+			deletingSensitiveValue := diff.Action == plans.Delete && renderer.blocks.BeforeSensitiveBlocks[key]
+			modifyingSensitiveValue := (diff.Action == plans.Update || diff.Action == plans.NoOp) && (renderer.blocks.AfterSensitiveBlocks[key] || renderer.blocks.BeforeSensitiveBlocks[key])
+
+			if creatingSensitiveValue || deletingSensitiveValue || modifyingSensitiveValue {
+				// Intercept the renderer here if the sensitive data was set
+				// across all the blocks instead of individually.
+				action := diff.Action
+				if diff.Action == plans.NoOp && renderer.blocks.BeforeSensitiveBlocks[key] != renderer.blocks.AfterSensitiveBlocks[key] {
+					action = plans.Update
+				}
+
+				diff = computed.NewDiff(SensitiveBlock(diff, renderer.blocks.BeforeSensitiveBlocks[key], renderer.blocks.AfterSensitiveBlocks[key]), action, diff.Replace)
+			}
+
+			if diff.Action == plans.NoOp && !opts.ShowUnchangedChildren {
+				unchangedBlocks++
+				return
+			}
+
+			if !foundChangedBlock && len(renderer.attributes) > 0 {
+				// We always want to put an extra new line between the
+				// attributes and blocks, and between groups of blocks.
+				buf.WriteString("\n")
+				foundChangedBlock = true
+			}
+
+			// If the force replacement metadata was set for every entry in the
+			// block we need to override that here. Our child blocks will only
+			// know about the replace function if it was set on them
+			// specifically, and not if it was set for all the blocks.
+			blockOpts := opts.Clone()
+			blockOpts.OverrideForcesReplacement = renderer.blocks.ReplaceBlocks[key]
+
+			for _, warning := range diff.WarningsHuman(indent+1, blockOpts) {
+				buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning))
+			}
+			buf.WriteString(fmt.Sprintf("%s%s%s%s %s\n", formatIndent(indent+1), writeDiffActionSymbol(diff.Action, blockOpts), EnsureValidAttributeName(key), mapKey, diff.RenderHuman(indent+1, blockOpts)))
+
+		}
+
+		switch {
+		case renderer.blocks.IsSingleBlock(key):
+			renderBlock(renderer.blocks.SingleBlocks[key], "", opts)
+		case renderer.blocks.IsMapBlock(key):
+			var keys []string
+			for key := range renderer.blocks.MapBlocks[key] {
+				keys = append(keys, key)
+			}
+			sort.Strings(keys)
+
+			for _, innerKey := range keys {
+				renderBlock(renderer.blocks.MapBlocks[key][innerKey], fmt.Sprintf(" %q", innerKey), opts)
+			}
+		case renderer.blocks.IsSetBlock(key):
+
+			setOpts := opts.Clone()
+			setOpts.OverrideForcesReplacement = diff.Replace
+
+			for _, block := range renderer.blocks.SetBlocks[key] {
+				renderBlock(block, "", opts)
+			}
+		case renderer.blocks.IsListBlock(key):
+			for _, block := range renderer.blocks.ListBlocks[key] {
+				renderBlock(block, "", opts)
+			}
+		}
+	}
+
+	if unchangedBlocks > 0 {
+		buf.WriteString(fmt.Sprintf("\n%s%s%s\n", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), unchanged("block", unchangedBlocks, opts)))
+	}
+
+	buf.WriteString(fmt.Sprintf("%s%s}", formatIndent(indent), writeDiffActionSymbol(plans.NoOp, opts)))
+	return buf.String()
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/blocks.go b/v1.5.7/internal/command/jsonformat/computed/renderers/blocks.go
new file mode 100644
index 0000000..2237fbf
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/blocks.go
@@ -0,0 +1,96 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"sort"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+)
+
+// Blocks is a helper struct for collating the different kinds of blocks in a
+// simple way for rendering.
+type Blocks struct {
+	SingleBlocks map[string]computed.Diff
+	ListBlocks   map[string][]computed.Diff
+	SetBlocks    map[string][]computed.Diff
+	MapBlocks    map[string]map[string]computed.Diff
+
+	// ReplaceBlocks and Before/AfterSensitiveBlocks carry forward the
+	// information about an entire group of blocks (eg. if all the blocks for a
+	// given list block are sensitive that isn't captured in the individual
+	// blocks as they are processed independently). These maps allow the
+	// renderer to check the metadata on the overall groups and respond
+	// accordingly.
+
+	ReplaceBlocks         map[string]bool
+	BeforeSensitiveBlocks map[string]bool
+	AfterSensitiveBlocks  map[string]bool
+}
+
+func (blocks *Blocks) GetAllKeys() []string {
+	var keys []string
+	for key := range blocks.SingleBlocks {
+		keys = append(keys, key)
+	}
+	for key := range blocks.ListBlocks {
+		keys = append(keys, key)
+	}
+	for key := range blocks.SetBlocks {
+		keys = append(keys, key)
+	}
+	for key := range blocks.MapBlocks {
+		keys = append(keys, key)
+	}
+	sort.Strings(keys)
+	return keys
+}
+
+func (blocks *Blocks) IsSingleBlock(key string) bool {
+	_, ok := blocks.SingleBlocks[key]
+	return ok
+}
+
+func (blocks *Blocks) IsListBlock(key string) bool {
+	_, ok := blocks.ListBlocks[key]
+	return ok
+}
+
+func (blocks *Blocks) IsMapBlock(key string) bool {
+	_, ok := blocks.MapBlocks[key]
+	return ok
+}
+
+func (blocks *Blocks) IsSetBlock(key string) bool {
+	_, ok := blocks.SetBlocks[key]
+	return ok
+}
+
+func (blocks *Blocks) AddSingleBlock(key string, diff computed.Diff, replace, beforeSensitive, afterSensitive bool) {
+	blocks.SingleBlocks[key] = diff
+	blocks.ReplaceBlocks[key] = replace
+	blocks.BeforeSensitiveBlocks[key] = beforeSensitive
+	blocks.AfterSensitiveBlocks[key] = afterSensitive
+}
+
+func (blocks *Blocks) AddAllListBlock(key string, diffs []computed.Diff, replace, beforeSensitive, afterSensitive bool) {
+	blocks.ListBlocks[key] = diffs
+	blocks.ReplaceBlocks[key] = replace
+	blocks.BeforeSensitiveBlocks[key] = beforeSensitive
+	blocks.AfterSensitiveBlocks[key] = afterSensitive
+}
+
+func (blocks *Blocks) AddAllSetBlock(key string, diffs []computed.Diff, replace, beforeSensitive, afterSensitive bool) {
+	blocks.SetBlocks[key] = diffs
+	blocks.ReplaceBlocks[key] = replace
+	blocks.BeforeSensitiveBlocks[key] = beforeSensitive
+	blocks.AfterSensitiveBlocks[key] = afterSensitive
+}
+
+func (blocks *Blocks) AddAllMapBlocks(key string, diffs map[string]computed.Diff, replace, beforeSensitive, afterSensitive bool) {
+	blocks.MapBlocks[key] = diffs
+	blocks.ReplaceBlocks[key] = replace
+	blocks.BeforeSensitiveBlocks[key] = beforeSensitive
+	blocks.AfterSensitiveBlocks[key] = afterSensitive
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/json.go b/v1.5.7/internal/command/jsonformat/computed/renderers/json.go
new file mode 100644
index 0000000..25244d4
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/json.go
@@ -0,0 +1,41 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/jsondiff"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+// RendererJsonOpts creates a jsondiff.JsonOpts object that returns the correct
+// embedded renderers for each JSON type.
+//
+// We need to define this in our renderers package in order to avoid cycles, and
+// to help with reuse between the output processing in the differs package, and
+// our JSON string rendering here.
+func RendererJsonOpts() jsondiff.JsonOpts {
+	return jsondiff.JsonOpts{
+		Primitive: func(before, after interface{}, ctype cty.Type, action plans.Action) computed.Diff {
+			return computed.NewDiff(Primitive(before, after, ctype), action, false)
+		},
+		Object: func(elements map[string]computed.Diff, action plans.Action) computed.Diff {
+			return computed.NewDiff(Object(elements), action, false)
+		},
+		Array: func(elements []computed.Diff, action plans.Action) computed.Diff {
+			return computed.NewDiff(List(elements), action, false)
+		},
+		Unknown: func(diff computed.Diff, action plans.Action) computed.Diff {
+			return computed.NewDiff(Unknown(diff), action, false)
+		},
+		Sensitive: func(diff computed.Diff, beforeSensitive bool, afterSensitive bool, action plans.Action) computed.Diff {
+			return computed.NewDiff(Sensitive(diff, beforeSensitive, afterSensitive), action, false)
+		},
+		TypeChange: func(before, after computed.Diff, action plans.Action) computed.Diff {
+			return computed.NewDiff(TypeChange(before, after), action, false)
+		},
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/list.go b/v1.5.7/internal/command/jsonformat/computed/renderers/list.go
new file mode 100644
index 0000000..f3d95c9
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/list.go
@@ -0,0 +1,127 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"bytes"
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+var _ computed.DiffRenderer = (*listRenderer)(nil)
+
+func List(elements []computed.Diff) computed.DiffRenderer {
+	return &listRenderer{
+		displayContext: true,
+		elements:       elements,
+	}
+}
+
+func NestedList(elements []computed.Diff) computed.DiffRenderer {
+	return &listRenderer{
+		elements: elements,
+	}
+}
+
+type listRenderer struct {
+	NoWarningsRenderer
+
+	displayContext bool
+	elements       []computed.Diff
+}
+
+func (renderer listRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string {
+	if len(renderer.elements) == 0 {
+		return fmt.Sprintf("[]%s%s", nullSuffix(diff.Action, opts), forcesReplacement(diff.Replace, opts))
+	}
+
+	elementOpts := opts.Clone()
+	elementOpts.OverrideNullSuffix = true
+
+	unchangedElementOpts := opts.Clone()
+	unchangedElementOpts.ShowUnchangedChildren = true
+
+	var unchangedElements []computed.Diff
+
+	// renderNext tells the renderer to print out the next element in the list
+	// whatever state it is in. So, even if a change is a NoOp we will still
+	// print it out if the last change we processed wants us to.
+	renderNext := false
+
+	var buf bytes.Buffer
+	buf.WriteString(fmt.Sprintf("[%s\n", forcesReplacement(diff.Replace, opts)))
+	for _, element := range renderer.elements {
+		if element.Action == plans.NoOp && !renderNext && !opts.ShowUnchangedChildren {
+			unchangedElements = append(unchangedElements, element)
+			continue
+		}
+		renderNext = false
+
+		opts := elementOpts
+
+		// If we want to display the context around this change, we want to
+		// render the change immediately before this change in the list, and the
+		// change immediately after in the list, even if both these changes are
+		// NoOps. This will give the user reading the diff some context as to
+		// where in the list these changes are being made, as order matters.
+		if renderer.displayContext {
+			// If our list of unchanged elements contains more than one entry
+			// we'll print out a count of the number of unchanged elements that
+			// we skipped. Note, this is the length of the unchanged elements
+			// minus 1 as the most recent unchanged element will be printed out
+			// in full.
+			if len(unchangedElements) > 1 {
+				buf.WriteString(fmt.Sprintf("%s%s%s\n", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), unchanged("element", len(unchangedElements)-1, opts)))
+			}
+			// If our list of unchanged elements contains at least one entry,
+			// we're going to print out the most recent change in full. That's
+			// what happens here.
+			if len(unchangedElements) > 0 {
+				lastElement := unchangedElements[len(unchangedElements)-1]
+				buf.WriteString(fmt.Sprintf("%s%s%s,\n", formatIndent(indent+1), writeDiffActionSymbol(lastElement.Action, unchangedElementOpts), lastElement.RenderHuman(indent+1, unchangedElementOpts)))
+			}
+			// We now reset the unchanged elements list, we've printed out a
+			// count of all the elements we skipped so we start counting from
+			// scratch again. This means that if we process a run of changed
+			// elements, they won't all start printing out summaries of every
+			// change that happened previously.
+			unchangedElements = nil
+
+			if element.Action == plans.NoOp {
+				// If this is a NoOp action then we're going to render it below
+				// so we need to just override the opts we're going to use to
+				// make sure we use the unchanged opts.
+				opts = unchangedElementOpts
+			} else {
+				// As we also want to render the element immediately after any
+				// changes, we make a note here to say we should render the next
+				// change whatever it is. But, we only want to render the next
+				// change if the current change isn't a NoOp. If the current change
+				// is a NoOp then it was told to print by the last change and we
+				// don't want to cascade and print all changes from now on.
+				renderNext = true
+			}
+		}
+
+		for _, warning := range element.WarningsHuman(indent+1, opts) {
+			buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning))
+		}
+		buf.WriteString(fmt.Sprintf("%s%s%s,\n", formatIndent(indent+1), writeDiffActionSymbol(element.Action, opts), element.RenderHuman(indent+1, opts)))
+	}
+
+	// If we were not displaying any context alongside our changes then the
+	// unchangedElements list will contain every unchanged element, and we'll
+	// print that out as we do with every other collection.
+	//
+	// If we were displaying context, then this will contain any unchanged
+	// elements since our last change, so we should also print it out.
+	if len(unchangedElements) > 0 {
+		buf.WriteString(fmt.Sprintf("%s%s%s\n", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), unchanged("element", len(unchangedElements), opts)))
+	}
+
+	buf.WriteString(fmt.Sprintf("%s%s]%s", formatIndent(indent), writeDiffActionSymbol(plans.NoOp, opts), nullSuffix(diff.Action, opts)))
+	return buf.String()
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/map.go b/v1.5.7/internal/command/jsonformat/computed/renderers/map.go
new file mode 100644
index 0000000..4a1e229
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/map.go
@@ -0,0 +1,110 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"bytes"
+	"fmt"
+	"sort"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+var _ computed.DiffRenderer = (*mapRenderer)(nil)
+
+func Map(elements map[string]computed.Diff) computed.DiffRenderer {
+	return &mapRenderer{
+		elements:  elements,
+		alignKeys: true,
+	}
+}
+
+func NestedMap(elements map[string]computed.Diff) computed.DiffRenderer {
+	return &mapRenderer{
+		elements:                  elements,
+		overrideNullSuffix:        true,
+		overrideForcesReplacement: true,
+	}
+}
+
+type mapRenderer struct {
+	NoWarningsRenderer
+
+	elements map[string]computed.Diff
+
+	overrideNullSuffix        bool
+	overrideForcesReplacement bool
+	alignKeys                 bool
+}
+
+func (renderer mapRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string {
+	forcesReplacementSelf := diff.Replace && !renderer.overrideForcesReplacement
+	forcesReplacementChildren := diff.Replace && renderer.overrideForcesReplacement
+
+	if len(renderer.elements) == 0 {
+		return fmt.Sprintf("{}%s%s", nullSuffix(diff.Action, opts), forcesReplacement(forcesReplacementSelf, opts))
+	}
+
+	// Sort the map elements by key, so we have a deterministic ordering in
+	// the output.
+	var keys []string
+
+	// We need to make sure the keys are capable of rendering properly.
+	escapedKeys := make(map[string]string)
+
+	maximumKeyLen := 0
+	for key := range renderer.elements {
+		keys = append(keys, key)
+
+		escapedKey := hclEscapeString(key)
+		escapedKeys[key] = escapedKey
+		if maximumKeyLen < len(escapedKey) {
+			maximumKeyLen = len(escapedKey)
+		}
+	}
+	sort.Strings(keys)
+
+	unchangedElements := 0
+
+	elementOpts := opts.Clone()
+	elementOpts.OverrideNullSuffix = diff.Action == plans.Delete || renderer.overrideNullSuffix
+	elementOpts.OverrideForcesReplacement = forcesReplacementChildren
+
+	var buf bytes.Buffer
+	buf.WriteString(fmt.Sprintf("{%s\n", forcesReplacement(forcesReplacementSelf, opts)))
+	for _, key := range keys {
+		element := renderer.elements[key]
+
+		if element.Action == plans.NoOp && !opts.ShowUnchangedChildren {
+			// Don't render NoOp operations when we are compact display.
+			unchangedElements++
+			continue
+		}
+
+		for _, warning := range element.WarningsHuman(indent+1, opts) {
+			buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning))
+		}
+		// Only show commas between elements for objects.
+		comma := ""
+		if _, ok := element.Renderer.(*objectRenderer); ok {
+			comma = ","
+		}
+
+		if renderer.alignKeys {
+			buf.WriteString(fmt.Sprintf("%s%s%-*s = %s%s\n", formatIndent(indent+1), writeDiffActionSymbol(element.Action, elementOpts), maximumKeyLen, escapedKeys[key], element.RenderHuman(indent+1, elementOpts), comma))
+		} else {
+			buf.WriteString(fmt.Sprintf("%s%s%s = %s%s\n", formatIndent(indent+1), writeDiffActionSymbol(element.Action, elementOpts), escapedKeys[key], element.RenderHuman(indent+1, elementOpts), comma))
+		}
+
+	}
+
+	if unchangedElements > 0 {
+		buf.WriteString(fmt.Sprintf("%s%s%s\n", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), unchanged("element", unchangedElements, opts)))
+	}
+
+	buf.WriteString(fmt.Sprintf("%s%s}%s", formatIndent(indent), writeDiffActionSymbol(plans.NoOp, opts), nullSuffix(diff.Action, opts)))
+	return buf.String()
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/object.go b/v1.5.7/internal/command/jsonformat/computed/renderers/object.go
new file mode 100644
index 0000000..3be0bf7
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/object.go
@@ -0,0 +1,98 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"bytes"
+	"fmt"
+	"sort"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+var _ computed.DiffRenderer = (*objectRenderer)(nil)
+
+func Object(attributes map[string]computed.Diff) computed.DiffRenderer {
+	return &objectRenderer{
+		attributes:         attributes,
+		overrideNullSuffix: true,
+	}
+}
+
+func NestedObject(attributes map[string]computed.Diff) computed.DiffRenderer {
+	return &objectRenderer{
+		attributes:         attributes,
+		overrideNullSuffix: false,
+	}
+}
+
+type objectRenderer struct {
+	NoWarningsRenderer
+
+	attributes         map[string]computed.Diff
+	overrideNullSuffix bool
+}
+
+func (renderer objectRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string {
+	if len(renderer.attributes) == 0 {
+		return fmt.Sprintf("{}%s%s", nullSuffix(diff.Action, opts), forcesReplacement(diff.Replace, opts))
+	}
+
+	attributeOpts := opts.Clone()
+	attributeOpts.OverrideNullSuffix = renderer.overrideNullSuffix
+
+	// We need to keep track of our keys in two ways. The first is the order in
+	// which we will display them. The second is a mapping to their safely
+	// escaped equivalent.
+
+	maximumKeyLen := 0
+	var keys []string
+	escapedKeys := make(map[string]string)
+	for key := range renderer.attributes {
+		keys = append(keys, key)
+		escapedKey := EnsureValidAttributeName(key)
+		escapedKeys[key] = escapedKey
+		if maximumKeyLen < len(escapedKey) {
+			maximumKeyLen = len(escapedKey)
+		}
+	}
+	sort.Strings(keys)
+
+	unchangedAttributes := 0
+	var buf bytes.Buffer
+	buf.WriteString(fmt.Sprintf("{%s\n", forcesReplacement(diff.Replace, opts)))
+	for _, key := range keys {
+		attribute := renderer.attributes[key]
+
+		if importantAttribute(key) {
+			importantAttributeOpts := attributeOpts.Clone()
+			importantAttributeOpts.ShowUnchangedChildren = true
+
+			for _, warning := range attribute.WarningsHuman(indent+1, importantAttributeOpts) {
+				buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning))
+			}
+			buf.WriteString(fmt.Sprintf("%s%s%-*s = %s\n", formatIndent(indent+1), writeDiffActionSymbol(attribute.Action, importantAttributeOpts), maximumKeyLen, escapedKeys[key], attribute.RenderHuman(indent+1, importantAttributeOpts)))
+			continue
+		}
+
+		if attribute.Action == plans.NoOp && !opts.ShowUnchangedChildren {
+			// Don't render NoOp operations when we are compact display.
+			unchangedAttributes++
+			continue
+		}
+
+		for _, warning := range attribute.WarningsHuman(indent+1, opts) {
+			buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning))
+		}
+		buf.WriteString(fmt.Sprintf("%s%s%-*s = %s\n", formatIndent(indent+1), writeDiffActionSymbol(attribute.Action, attributeOpts), maximumKeyLen, escapedKeys[key], attribute.RenderHuman(indent+1, attributeOpts)))
+	}
+
+	if unchangedAttributes > 0 {
+		buf.WriteString(fmt.Sprintf("%s%s%s\n", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), unchanged("attribute", unchangedAttributes, opts)))
+	}
+
+	buf.WriteString(fmt.Sprintf("%s%s}%s", formatIndent(indent), writeDiffActionSymbol(plans.NoOp, opts), nullSuffix(diff.Action, opts)))
+	return buf.String()
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/primitive.go b/v1.5.7/internal/command/jsonformat/computed/renderers/primitive.go
new file mode 100644
index 0000000..55dd1b9
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/primitive.go
@@ -0,0 +1,242 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"fmt"
+	"math/big"
+	"strings"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/collections"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+var _ computed.DiffRenderer = (*primitiveRenderer)(nil)
+
+func Primitive(before, after interface{}, ctype cty.Type) computed.DiffRenderer {
+	return &primitiveRenderer{
+		before: before,
+		after:  after,
+		ctype:  ctype,
+	}
+}
+
+type primitiveRenderer struct {
+	NoWarningsRenderer
+
+	before interface{}
+	after  interface{}
+	ctype  cty.Type
+}
+
+func (renderer primitiveRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string {
+	if renderer.ctype == cty.String {
+		return renderer.renderStringDiff(diff, indent, opts)
+	}
+
+	beforeValue := renderPrimitiveValue(renderer.before, renderer.ctype, opts)
+	afterValue := renderPrimitiveValue(renderer.after, renderer.ctype, opts)
+
+	switch diff.Action {
+	case plans.Create:
+		return fmt.Sprintf("%s%s", afterValue, forcesReplacement(diff.Replace, opts))
+	case plans.Delete:
+		return fmt.Sprintf("%s%s%s", beforeValue, nullSuffix(diff.Action, opts), forcesReplacement(diff.Replace, opts))
+	case plans.NoOp:
+		return fmt.Sprintf("%s%s", beforeValue, forcesReplacement(diff.Replace, opts))
+	default:
+		return fmt.Sprintf("%s %s %s%s", beforeValue, opts.Colorize.Color("[yellow]->[reset]"), afterValue, forcesReplacement(diff.Replace, opts))
+	}
+}
+
+func renderPrimitiveValue(value interface{}, t cty.Type, opts computed.RenderHumanOpts) string {
+	if value == nil {
+		return opts.Colorize.Color("[dark_gray]null[reset]")
+	}
+
+	switch {
+	case t == cty.Bool:
+		if value.(bool) {
+			return "true"
+		}
+		return "false"
+	case t == cty.Number:
+		bf := big.NewFloat(value.(float64))
+		return bf.Text('f', -1)
+	default:
+		panic("unrecognized primitive type: " + t.FriendlyName())
+	}
+}
+
+func (renderer primitiveRenderer) renderStringDiff(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string {
+
+	// We process multiline strings at the end of the switch statement.
+	var lines []string
+
+	switch diff.Action {
+	case plans.Create, plans.NoOp:
+		str := evaluatePrimitiveString(renderer.after, opts)
+
+		if str.Json != nil {
+			if diff.Action == plans.NoOp {
+				return renderer.renderStringDiffAsJson(diff, indent, opts, str, str)
+			} else {
+				return renderer.renderStringDiffAsJson(diff, indent, opts, evaluatedString{}, str)
+			}
+		}
+
+		if !str.IsMultiline {
+			return fmt.Sprintf("%s%s", str.RenderSimple(), forcesReplacement(diff.Replace, opts))
+		}
+
+		// We are creating a single multiline string, so let's split by the new
+		// line character. While we are doing this, we are going to insert our
+		// indents and make sure each line is formatted correctly.
+		lines = strings.Split(strings.ReplaceAll(str.String, "\n", fmt.Sprintf("\n%s%s", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts))), "\n")
+
+		// We now just need to do the same for the first entry in lines, because
+		// we split on the new line characters which won't have been at the
+		// beginning of the first line.
+		lines[0] = fmt.Sprintf("%s%s%s", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), lines[0])
+	case plans.Delete:
+		str := evaluatePrimitiveString(renderer.before, opts)
+		if str.IsNull {
+			// We don't put the null suffix (-> null) here because the final
+			// render or null -> null would look silly.
+			return fmt.Sprintf("%s%s", str.RenderSimple(), forcesReplacement(diff.Replace, opts))
+		}
+
+		if str.Json != nil {
+			return renderer.renderStringDiffAsJson(diff, indent, opts, str, evaluatedString{})
+		}
+
+		if !str.IsMultiline {
+			return fmt.Sprintf("%s%s%s", str.RenderSimple(), nullSuffix(diff.Action, opts), forcesReplacement(diff.Replace, opts))
+		}
+
+		// We are creating a single multiline string, so let's split by the new
+		// line character. While we are doing this, we are going to insert our
+		// indents and make sure each line is formatted correctly.
+		lines = strings.Split(strings.ReplaceAll(str.String, "\n", fmt.Sprintf("\n%s%s", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts))), "\n")
+
+		// We now just need to do the same for the first entry in lines, because
+		// we split on the new line characters which won't have been at the
+		// beginning of the first line.
+		lines[0] = fmt.Sprintf("%s%s%s", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), lines[0])
+	default:
+		beforeString := evaluatePrimitiveString(renderer.before, opts)
+		afterString := evaluatePrimitiveString(renderer.after, opts)
+
+		if beforeString.Json != nil && afterString.Json != nil {
+			return renderer.renderStringDiffAsJson(diff, indent, opts, beforeString, afterString)
+		}
+
+		if beforeString.Json != nil || afterString.Json != nil {
+			// This means one of the strings is JSON and one isn't. We're going
+			// to be a little inefficient here, but we can just reuse another
+			// renderer for this so let's keep it simple.
+			return computed.NewDiff(
+				TypeChange(
+					computed.NewDiff(Primitive(renderer.before, nil, cty.String), plans.Delete, false),
+					computed.NewDiff(Primitive(nil, renderer.after, cty.String), plans.Create, false)),
+				diff.Action,
+				diff.Replace).RenderHuman(indent, opts)
+		}
+
+		if !beforeString.IsMultiline && !afterString.IsMultiline {
+			return fmt.Sprintf("%s %s %s%s", beforeString.RenderSimple(), opts.Colorize.Color("[yellow]->[reset]"), afterString.RenderSimple(), forcesReplacement(diff.Replace, opts))
+		}
+
+		beforeLines := strings.Split(beforeString.String, "\n")
+		afterLines := strings.Split(afterString.String, "\n")
+
+		processIndices := func(beforeIx, afterIx int) {
+			if beforeIx < 0 || beforeIx >= len(beforeLines) {
+				lines = append(lines, fmt.Sprintf("%s%s%s", formatIndent(indent+1), writeDiffActionSymbol(plans.Create, opts), afterLines[afterIx]))
+				return
+			}
+
+			if afterIx < 0 || afterIx >= len(afterLines) {
+				lines = append(lines, fmt.Sprintf("%s%s%s", formatIndent(indent+1), writeDiffActionSymbol(plans.Delete, opts), beforeLines[beforeIx]))
+				return
+			}
+
+			lines = append(lines, fmt.Sprintf("%s%s%s", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), beforeLines[beforeIx]))
+		}
+		isObjType := func(_ string) bool {
+			return false
+		}
+
+		collections.ProcessSlice(beforeLines, afterLines, processIndices, isObjType)
+	}
+
+	// We return early if we find non-multiline strings or JSON strings, so we
+	// know here that we just render the lines slice properly.
+	return fmt.Sprintf("<<-EOT%s\n%s\n%s%sEOT%s",
+		forcesReplacement(diff.Replace, opts),
+		strings.Join(lines, "\n"),
+		formatIndent(indent),
+		writeDiffActionSymbol(plans.NoOp, opts),
+		nullSuffix(diff.Action, opts))
+}
+
+func (renderer primitiveRenderer) renderStringDiffAsJson(diff computed.Diff, indent int, opts computed.RenderHumanOpts, before evaluatedString, after evaluatedString) string {
+	jsonDiff := RendererJsonOpts().Transform(structured.Change{
+		BeforeExplicit:     diff.Action != plans.Create,
+		AfterExplicit:      diff.Action != plans.Delete,
+		Before:             before.Json,
+		After:              after.Json,
+		Unknown:            false,
+		BeforeSensitive:    false,
+		AfterSensitive:     false,
+		ReplacePaths:       attribute_path.Empty(false),
+		RelevantAttributes: attribute_path.AlwaysMatcher(),
+	})
+
+	action := diff.Action
+
+	jsonOpts := opts.Clone()
+	jsonOpts.OverrideNullSuffix = true
+
+	var whitespace, replace string
+	if jsonDiff.Action == plans.NoOp && diff.Action == plans.Update {
+		// Then this means we are rendering a whitespace only change. The JSON
+		// differ will have ignored the whitespace changes so that makes the
+		// diff we are about to print out very confusing without extra
+		// explanation.
+		if diff.Replace {
+			whitespace = " # whitespace changes force replacement"
+		} else {
+			whitespace = " # whitespace changes"
+		}
+
+		// Because we'd be showing no changes otherwise:
+		jsonOpts.ShowUnchangedChildren = true
+
+		// Whitespace changes should not appear as if edited.
+		action = plans.NoOp
+	} else {
+		// We only show the replace suffix if we didn't print something out
+		// about whitespace changes.
+		replace = forcesReplacement(diff.Replace, opts)
+	}
+
+	renderedJsonDiff := jsonDiff.RenderHuman(indent+1, jsonOpts)
+
+	if diff.Action == plans.Create || diff.Action == plans.Delete {
+		// We don't display the '+' or '-' symbols on the JSON diffs, we should
+		// still display the '~' for an update action though.
+		action = plans.NoOp
+	}
+
+	if strings.Contains(renderedJsonDiff, "\n") {
+		return fmt.Sprintf("jsonencode(%s\n%s%s%s%s\n%s%s)%s", whitespace, formatIndent(indent+1), writeDiffActionSymbol(action, opts), renderedJsonDiff, replace, formatIndent(indent), writeDiffActionSymbol(plans.NoOp, opts), nullSuffix(diff.Action, opts))
+	}
+	return fmt.Sprintf("jsonencode(%s)%s%s", renderedJsonDiff, whitespace, replace)
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/renderer_test.go b/v1.5.7/internal/command/jsonformat/computed/renderers/renderer_test.go
new file mode 100644
index 0000000..83483dd
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/renderer_test.go
@@ -0,0 +1,2217 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/mitchellh/colorstring"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+func TestRenderers_Human(t *testing.T) {
+	colorize := colorstring.Colorize{
+		Colors:  colorstring.DefaultColors,
+		Disable: true,
+	}
+
+	tcs := map[string]struct {
+		diff     computed.Diff
+		expected string
+		opts     computed.RenderHumanOpts
+	}{
+		// We're using the string "null" in these tests to demonstrate the
+		// difference between rendering an actual string and rendering a null
+		// value.
+		"primitive_create_string": {
+			diff: computed.Diff{
+				Renderer: Primitive(nil, "null", cty.String),
+				Action:   plans.Create,
+			},
+			expected: "\"null\"",
+		},
+		"primitive_delete_string": {
+			diff: computed.Diff{
+				Renderer: Primitive("null", nil, cty.String),
+				Action:   plans.Delete,
+			},
+			expected: "\"null\" -> null",
+		},
+		"primitive_update_string_to_null": {
+			diff: computed.Diff{
+				Renderer: Primitive("null", nil, cty.String),
+				Action:   plans.Update,
+			},
+			expected: "\"null\" -> null",
+		},
+		"primitive_update_string_from_null": {
+			diff: computed.Diff{
+				Renderer: Primitive(nil, "null", cty.String),
+				Action:   plans.Update,
+			},
+			expected: "null -> \"null\"",
+		},
+		"primitive_update_multiline_string_to_null": {
+			diff: computed.Diff{
+				Renderer: Primitive("nu\nll", nil, cty.String),
+				Action:   plans.Update,
+			},
+			expected: `
+<<-EOT
+      - nu
+      - ll
+      + null
+    EOT
+`,
+		},
+		"primitive_update_multiline_string_from_null": {
+			diff: computed.Diff{
+				Renderer: Primitive(nil, "nu\nll", cty.String),
+				Action:   plans.Update,
+			},
+			expected: `
+<<-EOT
+      - null
+      + nu
+      + ll
+    EOT
+`,
+		},
+		"primitive_update_json_string_to_null": {
+			diff: computed.Diff{
+				Renderer: Primitive("[null]", nil, cty.String),
+				Action:   plans.Update,
+			},
+			expected: `
+jsonencode(
+        [
+          - null,
+        ]
+    ) -> null
+`,
+		},
+		"primitive_update_json_string_from_null": {
+			diff: computed.Diff{
+				Renderer: Primitive(nil, "[null]", cty.String),
+				Action:   plans.Update,
+			},
+			expected: `
+null -> jsonencode(
+        [
+          + null,
+        ]
+    )
+`,
+		},
+		"primitive_create_null_string": {
+			diff: computed.Diff{
+				Renderer: Primitive(nil, nil, cty.String),
+				Action:   plans.Create,
+			},
+			expected: "null",
+		},
+		"primitive_delete_null_string": {
+			diff: computed.Diff{
+				Renderer: Primitive(nil, nil, cty.String),
+				Action:   plans.Delete,
+			},
+			expected: "null",
+		},
+		"primitive_create": {
+			diff: computed.Diff{
+				Renderer: Primitive(nil, 1.0, cty.Number),
+				Action:   plans.Create,
+			},
+			expected: "1",
+		},
+		"primitive_delete": {
+			diff: computed.Diff{
+				Renderer: Primitive(1.0, nil, cty.Number),
+				Action:   plans.Delete,
+			},
+			expected: "1 -> null",
+		},
+		"primitive_delete_override": {
+			diff: computed.Diff{
+				Renderer: Primitive(1.0, nil, cty.Number),
+				Action:   plans.Delete,
+			},
+			opts:     computed.RenderHumanOpts{OverrideNullSuffix: true},
+			expected: "1",
+		},
+		"primitive_update_to_null": {
+			diff: computed.Diff{
+				Renderer: Primitive(1.0, nil, cty.Number),
+				Action:   plans.Update,
+			},
+			expected: "1 -> null",
+		},
+		"primitive_update_from_null": {
+			diff: computed.Diff{
+				Renderer: Primitive(nil, 1.0, cty.Number),
+				Action:   plans.Update,
+			},
+			expected: "null -> 1",
+		},
+		"primitive_update": {
+			diff: computed.Diff{
+				Renderer: Primitive(0.0, 1.0, cty.Number),
+				Action:   plans.Update,
+			},
+			expected: "0 -> 1",
+		},
+		"primitive_update_long_float": {
+			diff: computed.Diff{
+				Renderer: Primitive(123456789.0, 987654321.0, cty.Number),
+				Action:   plans.Update,
+			},
+			expected: "123456789 -> 987654321",
+		},
+		"primitive_update_replace": {
+			diff: computed.Diff{
+				Renderer: Primitive(0.0, 1.0, cty.Number),
+				Action:   plans.Update,
+				Replace:  true,
+			},
+			expected: "0 -> 1 # forces replacement",
+		},
+		"primitive_multiline_string_create": {
+			diff: computed.Diff{
+				Renderer: Primitive(nil, "hello\nworld", cty.String),
+				Action:   plans.Create,
+			},
+			expected: `
+<<-EOT
+        hello
+        world
+    EOT
+`,
+		},
+		"primitive_multiline_string_delete": {
+			diff: computed.Diff{
+				Renderer: Primitive("hello\nworld", nil, cty.String),
+				Action:   plans.Delete,
+			},
+			expected: `
+<<-EOT
+        hello
+        world
+    EOT -> null
+`,
+		},
+		"primitive_multiline_string_update": {
+			diff: computed.Diff{
+				Renderer: Primitive("hello\nold\nworld", "hello\nnew\nworld", cty.String),
+				Action:   plans.Update,
+			},
+			expected: `
+<<-EOT
+        hello
+      - old
+      + new
+        world
+    EOT
+`,
+		},
+		"primitive_json_string_create": {
+			diff: computed.Diff{
+				Renderer: Primitive(nil, "{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", cty.String),
+				Action:   plans.Create,
+			},
+			expected: `
+jsonencode(
+        {
+          + key_one = "value_one"
+          + key_two = "value_two"
+        }
+    )
+`,
+		},
+		"primitive_json_string_delete": {
+			diff: computed.Diff{
+				Renderer: Primitive("{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", nil, cty.String),
+				Action:   plans.Delete,
+			},
+			expected: `
+jsonencode(
+        {
+          - key_one = "value_one"
+          - key_two = "value_two"
+        }
+    ) -> null
+`,
+		},
+		"primitive_json_string_update": {
+			diff: computed.Diff{
+				Renderer: Primitive("{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", "{\"key_one\": \"value_one\",\"key_two\":\"value_two\",\"key_three\":\"value_three\"}", cty.String),
+				Action:   plans.Update,
+			},
+			expected: `
+jsonencode(
+      ~ {
+          + key_three = "value_three"
+            # (2 unchanged attributes hidden)
+        }
+    )
+`,
+		},
+		"primitive_json_explicit_nulls": {
+			diff: computed.Diff{
+				Renderer: Primitive("{\"key_one\":\"value_one\",\"key_two\":\"value_two\"}", "{\"key_one\":null}", cty.String),
+				Action:   plans.Update,
+			},
+			expected: `
+jsonencode(
+      ~ {
+          ~ key_one = "value_one" -> null
+          - key_two = "value_two"
+        }
+    )
+`,
+		},
+		"primitive_fake_json_string_update": {
+			diff: computed.Diff{
+				// This isn't valid JSON, our renderer should be okay with it.
+				Renderer: Primitive("{\"key_one\": \"value_one\",\"key_two\":\"value_two\"", "{\"key_one\": \"value_one\",\"key_two\":\"value_two\",\"key_three\":\"value_three\"", cty.String),
+				Action:   plans.Update,
+			},
+			expected: "\"{\\\"key_one\\\": \\\"value_one\\\",\\\"key_two\\\":\\\"value_two\\\"\" -> \"{\\\"key_one\\\": \\\"value_one\\\",\\\"key_two\\\":\\\"value_two\\\",\\\"key_three\\\":\\\"value_three\\\"\"",
+		},
+		"primitive_multiline_to_json_update": {
+			diff: computed.Diff{
+				Renderer: Primitive("hello\nworld", "{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", cty.String),
+				Action:   plans.Update,
+			},
+			expected: `
+<<-EOT
+        hello
+        world
+    EOT -> jsonencode(
+        {
+          + key_one = "value_one"
+          + key_two = "value_two"
+        }
+    )
+`,
+		},
+		"primitive_json_to_multiline_update": {
+			diff: computed.Diff{
+				Renderer: Primitive("{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", "hello\nworld", cty.String),
+				Action:   plans.Update,
+			},
+			expected: `
+jsonencode(
+        {
+          - key_one = "value_one"
+          - key_two = "value_two"
+        }
+    ) -> <<-EOT
+        hello
+        world
+    EOT
+`,
+		},
+		"primitive_json_to_string_update": {
+			diff: computed.Diff{
+				Renderer: Primitive("{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", "hello world", cty.String),
+				Action:   plans.Update,
+			},
+			expected: `
+jsonencode(
+        {
+          - key_one = "value_one"
+          - key_two = "value_two"
+        }
+    ) -> "hello world"
+`,
+		},
+		"primitive_string_to_json_update": {
+			diff: computed.Diff{
+				Renderer: Primitive("hello world", "{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", cty.String),
+				Action:   plans.Update,
+			},
+			expected: `
+"hello world" -> jsonencode(
+        {
+          + key_one = "value_one"
+          + key_two = "value_two"
+        }
+    )
+`,
+		},
+		"primitive_multi_to_single_update": {
+			diff: computed.Diff{
+				Renderer: Primitive("hello\nworld", "hello world", cty.String),
+				Action:   plans.Update,
+			},
+			expected: `
+<<-EOT
+      - hello
+      - world
+      + hello world
+    EOT
+`,
+		},
+		"primitive_single_to_multi_update": {
+			diff: computed.Diff{
+				Renderer: Primitive("hello world", "hello\nworld", cty.String),
+				Action:   plans.Update,
+			},
+			expected: `
+<<-EOT
+      - hello world
+      + hello
+      + world
+    EOT
+`,
+		},
+		"sensitive_update": {
+			diff: computed.Diff{
+				Renderer: Sensitive(computed.Diff{
+					Renderer: Primitive(0.0, 1.0, cty.Number),
+					Action:   plans.Update,
+				}, true, true),
+				Action: plans.Update,
+			},
+			expected: "(sensitive value)",
+		},
+		"sensitive_update_replace": {
+			diff: computed.Diff{
+				Renderer: Sensitive(computed.Diff{
+					Renderer: Primitive(0.0, 1.0, cty.Number),
+					Action:   plans.Update,
+					Replace:  true,
+				}, true, true),
+				Action:  plans.Update,
+				Replace: true,
+			},
+			expected: "(sensitive value) # forces replacement",
+		},
+		"computed_create": {
+			diff: computed.Diff{
+				Renderer: Unknown(computed.Diff{}),
+				Action:   plans.Create,
+			},
+			expected: "(known after apply)",
+		},
+		"computed_update": {
+			diff: computed.Diff{
+				Renderer: Unknown(computed.Diff{
+					Renderer: Primitive(0.0, nil, cty.Number),
+					Action:   plans.Delete,
+				}),
+				Action: plans.Update,
+			},
+			expected: "0 -> (known after apply)",
+		},
+		"computed_create_forces_replacement": {
+			diff: computed.Diff{
+				Renderer: Unknown(computed.Diff{}),
+				Action:   plans.Create,
+				Replace:  true,
+			},
+			expected: "(known after apply) # forces replacement",
+		},
+		"computed_update_forces_replacement": {
+			diff: computed.Diff{
+				Renderer: Unknown(computed.Diff{
+					Renderer: Primitive(0.0, nil, cty.Number),
+					Action:   plans.Delete,
+				}),
+				Action:  plans.Update,
+				Replace: true,
+			},
+			expected: "0 -> (known after apply) # forces replacement",
+		},
+		"object_created": {
+			diff: computed.Diff{
+				Renderer: Object(map[string]computed.Diff{}),
+				Action:   plans.Create,
+			},
+			expected: "{}",
+		},
+		"object_created_with_attributes": {
+			diff: computed.Diff{
+				Renderer: Object(map[string]computed.Diff{
+					"attribute_one": {
+						Renderer: Primitive(nil, 0.0, cty.Number),
+						Action:   plans.Create,
+					},
+				}),
+				Action: plans.Create,
+			},
+			expected: `
+{
+      + attribute_one = 0
+    }
+`,
+		},
+		"object_deleted": {
+			diff: computed.Diff{
+				Renderer: Object(map[string]computed.Diff{}),
+				Action:   plans.Delete,
+			},
+			expected: "{} -> null",
+		},
+		"object_deleted_with_attributes": {
+			diff: computed.Diff{
+				Renderer: Object(map[string]computed.Diff{
+					"attribute_one": {
+						Renderer: Primitive(0.0, nil, cty.Number),
+						Action:   plans.Delete,
+					},
+				}),
+				Action: plans.Delete,
+			},
+			expected: `
+{
+      - attribute_one = 0
+    } -> null
+`,
+		},
+		"nested_object_deleted": {
+			diff: computed.Diff{
+				Renderer: NestedObject(map[string]computed.Diff{}),
+				Action:   plans.Delete,
+			},
+			expected: "{} -> null",
+		},
+		"nested_object_deleted_with_attributes": {
+			diff: computed.Diff{
+				Renderer: NestedObject(map[string]computed.Diff{
+					"attribute_one": {
+						Renderer: Primitive(0.0, nil, cty.Number),
+						Action:   plans.Delete,
+					},
+				}),
+				Action: plans.Delete,
+			},
+			expected: `
+{
+      - attribute_one = 0 -> null
+    } -> null
+`,
+		},
+		"object_create_attribute": {
+			diff: computed.Diff{
+				Renderer: Object(map[string]computed.Diff{
+					"attribute_one": {
+						Renderer: Primitive(nil, 0.0, cty.Number),
+						Action:   plans.Create,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      + attribute_one = 0
+    }
+`,
+		},
+		"object_update_attribute": {
+			diff: computed.Diff{
+				Renderer: Object(map[string]computed.Diff{
+					"attribute_one": {
+						Renderer: Primitive(0.0, 1.0, cty.Number),
+						Action:   plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      ~ attribute_one = 0 -> 1
+    }
+`,
+		},
+		"object_update_attribute_forces_replacement": {
+			diff: computed.Diff{
+				Renderer: Object(map[string]computed.Diff{
+					"attribute_one": {
+						Renderer: Primitive(0.0, 1.0, cty.Number),
+						Action:   plans.Update,
+					},
+				}),
+				Action:  plans.Update,
+				Replace: true,
+			},
+			expected: `
+{ # forces replacement
+      ~ attribute_one = 0 -> 1
+    }
+`,
+		},
+		"object_delete_attribute": {
+			diff: computed.Diff{
+				Renderer: Object(map[string]computed.Diff{
+					"attribute_one": {
+						Renderer: Primitive(0.0, nil, cty.Number),
+						Action:   plans.Delete,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      - attribute_one = 0
+    }
+`,
+		},
+		"object_ignore_unchanged_attributes": {
+			diff: computed.Diff{
+				Renderer: Object(map[string]computed.Diff{
+					"attribute_one": {
+						Renderer: Primitive(0.0, 1.0, cty.Number),
+						Action:   plans.Update,
+					},
+					"attribute_two": {
+						Renderer: Primitive(0.0, 0.0, cty.Number),
+						Action:   plans.NoOp,
+					},
+					"attribute_three": {
+						Renderer: Primitive(nil, 1.0, cty.Number),
+						Action:   plans.Create,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      ~ attribute_one   = 0 -> 1
+      + attribute_three = 1
+        # (1 unchanged attribute hidden)
+    }
+`,
+		},
+		"object_create_sensitive_attribute": {
+			diff: computed.Diff{
+				Renderer: Object(map[string]computed.Diff{
+					"attribute_one": {
+						Renderer: Sensitive(computed.Diff{
+							Renderer: Primitive(nil, 1.0, cty.Number),
+							Action:   plans.Create,
+						}, false, true),
+						Action: plans.Create,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      + attribute_one = (sensitive value)
+    }
+`,
+		},
+		"object_update_sensitive_attribute": {
+			diff: computed.Diff{
+				Renderer: Object(map[string]computed.Diff{
+					"attribute_one": {
+						Renderer: Sensitive(computed.Diff{
+							Renderer: Primitive(0.0, 1.0, cty.Number),
+							Action:   plans.Update,
+						}, true, true),
+						Action: plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      ~ attribute_one = (sensitive value)
+    }
+`,
+		},
+		"object_delete_sensitive_attribute": {
+			diff: computed.Diff{
+				Renderer: Object(map[string]computed.Diff{
+					"attribute_one": {
+						Renderer: Sensitive(computed.Diff{
+							Renderer: Primitive(0.0, nil, cty.Number),
+							Action:   plans.Delete,
+						}, true, false),
+						Action: plans.Delete,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      - attribute_one = (sensitive value)
+    }
+`,
+		},
+		"object_create_computed_attribute": {
+			diff: computed.Diff{
+				Renderer: Object(map[string]computed.Diff{
+					"attribute_one": {
+						Renderer: Unknown(computed.Diff{Renderer: nil}),
+						Action:   plans.Create,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      + attribute_one = (known after apply)
+    }
+`,
+		},
+		"object_update_computed_attribute": {
+			diff: computed.Diff{
+				Renderer: Object(map[string]computed.Diff{
+					"attribute_one": {
+						Renderer: Unknown(computed.Diff{
+							Renderer: Primitive(1.0, nil, cty.Number),
+							Action:   plans.Delete,
+						}),
+						Action: plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      ~ attribute_one = 1 -> (known after apply)
+    }
+`,
+		},
+		"object_escapes_attribute_keys": {
+			diff: computed.Diff{
+				Renderer: Object(map[string]computed.Diff{
+					"attribute_one": {
+						Renderer: Primitive(1.0, 2.0, cty.Number),
+						Action:   plans.Update,
+					},
+					"attribute:two": {
+						Renderer: Primitive(2.0, 3.0, cty.Number),
+						Action:   plans.Update,
+					},
+					"attribute_six": {
+						Renderer: Primitive(3.0, 4.0, cty.Number),
+						Action:   plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      ~ "attribute:two" = 2 -> 3
+      ~ attribute_one   = 1 -> 2
+      ~ attribute_six   = 3 -> 4
+    }
+`,
+		},
+		"map_create_empty": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{}),
+				Action:   plans.Create,
+			},
+			expected: "{}",
+		},
+		"map_create": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{
+					"element_one": {
+						Renderer: Primitive(nil, "new", cty.String),
+						Action:   plans.Create,
+					},
+				}),
+				Action: plans.Create,
+			},
+			expected: `
+{
+      + "element_one" = "new"
+    }
+`,
+		},
+		"map_delete_empty": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{}),
+				Action:   plans.Delete,
+			},
+			expected: "{} -> null",
+		},
+		"map_delete": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{
+					"element_one": {
+						Renderer: Primitive("old", nil, cty.String),
+						Action:   plans.Delete,
+					},
+				}),
+				Action: plans.Delete,
+			},
+			expected: `
+{
+      - "element_one" = "old"
+    } -> null
+`,
+		},
+		"map_create_element": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{
+					"element_one": {
+						Renderer: Primitive(nil, "new", cty.String),
+						Action:   plans.Create,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      + "element_one" = "new"
+    }
+`,
+		},
+		"map_update_element": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{
+					"element_one": {
+						Renderer: Primitive("old", "new", cty.String),
+						Action:   plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      ~ "element_one" = "old" -> "new"
+    }
+`,
+		},
+		"map_delete_element": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{
+					"element_one": {
+						Renderer: Primitive("old", nil, cty.String),
+						Action:   plans.Delete,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      - "element_one" = "old" -> null
+    }
+`,
+		},
+		"map_update_forces_replacement": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{
+					"element_one": {
+						Renderer: Primitive("old", "new", cty.String),
+						Action:   plans.Update,
+					},
+				}),
+				Action:  plans.Update,
+				Replace: true,
+			},
+			expected: `
+{ # forces replacement
+      ~ "element_one" = "old" -> "new"
+    }
+`,
+		},
+		"map_ignore_unchanged_elements": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{
+					"element_one": {
+						Renderer: Primitive(nil, "new", cty.String),
+						Action:   plans.Create,
+					},
+					"element_two": {
+						Renderer: Primitive("old", "old", cty.String),
+						Action:   plans.NoOp,
+					},
+					"element_three": {
+						Renderer: Primitive("old", "new", cty.String),
+						Action:   plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      + "element_one"   = "new"
+      ~ "element_three" = "old" -> "new"
+        # (1 unchanged element hidden)
+    }
+`,
+		},
+		"map_create_sensitive_element": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{
+					"element_one": {
+						Renderer: Sensitive(computed.Diff{
+							Renderer: Primitive(nil, 1.0, cty.Number),
+							Action:   plans.Create,
+						}, false, true),
+						Action: plans.Create,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      + "element_one" = (sensitive value)
+    }
+`,
+		},
+		"map_update_sensitive_element": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{
+					"element_one": {
+						Renderer: Sensitive(computed.Diff{
+							Renderer: Primitive(0.0, 1.0, cty.Number),
+							Action:   plans.Update,
+						}, true, true),
+						Action: plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      ~ "element_one" = (sensitive value)
+    }
+`,
+		},
+		"map_update_sensitive_element_status": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{
+					"element_one": {
+						Renderer: Sensitive(computed.Diff{
+							Renderer: Primitive(0.0, 0.0, cty.Number),
+							Action:   plans.NoOp,
+						}, true, false),
+						Action: plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      # Warning: this attribute value will no longer be marked as sensitive
+      # after applying this change. The value is unchanged.
+      ~ "element_one" = (sensitive value)
+    }
+`,
+		},
+		"map_delete_sensitive_element": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{
+					"element_one": {
+						Renderer: Sensitive(computed.Diff{
+							Renderer: Primitive(0.0, nil, cty.Number),
+							Action:   plans.Delete,
+						}, true, false),
+						Action: plans.Delete,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      - "element_one" = (sensitive value) -> null
+    }
+`,
+		},
+		"map_create_computed_element": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{
+					"element_one": {
+						Renderer: Unknown(computed.Diff{}),
+						Action:   plans.Create,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      + "element_one" = (known after apply)
+    }
+`,
+		},
+		"map_update_computed_element": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{
+					"element_one": {
+						Renderer: Unknown(computed.Diff{
+							Renderer: Primitive(1.0, nil, cty.Number),
+							Action:   plans.Delete,
+						}),
+						Action: plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      ~ "element_one" = 1 -> (known after apply)
+    }
+`,
+		},
+		"map_aligns_key": {
+			diff: computed.Diff{
+				Renderer: Map(map[string]computed.Diff{
+					"element_one": {
+						Renderer: Primitive(1.0, 2.0, cty.Number),
+						Action:   plans.Update,
+					},
+					"element_two": {
+						Renderer: Primitive(1.0, 3.0, cty.Number),
+						Action:   plans.Update,
+					},
+					"element_three": {
+						Renderer: Primitive(1.0, 4.0, cty.Number),
+						Action:   plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      ~ "element_one"   = 1 -> 2
+      ~ "element_three" = 1 -> 4
+      ~ "element_two"   = 1 -> 3
+    }
+`,
+		},
+		"nested_map_does_not_align_keys": {
+			diff: computed.Diff{
+				Renderer: NestedMap(map[string]computed.Diff{
+					"element_one": {
+						Renderer: Primitive(1.0, 2.0, cty.Number),
+						Action:   plans.Update,
+					},
+					"element_two": {
+						Renderer: Primitive(1.0, 3.0, cty.Number),
+						Action:   plans.Update,
+					},
+					"element_three": {
+						Renderer: Primitive(1.0, 4.0, cty.Number),
+						Action:   plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      ~ "element_one" = 1 -> 2
+      ~ "element_three" = 1 -> 4
+      ~ "element_two" = 1 -> 3
+    }
+`,
+		},
+		"list_create_empty": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{}),
+				Action:   plans.Create,
+			},
+			expected: "[]",
+		},
+		"list_create": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{
+					{
+						Renderer: Primitive(nil, 1.0, cty.Number),
+						Action:   plans.Create,
+					},
+				}),
+				Action: plans.Create,
+			},
+			expected: `
+[
+      + 1,
+    ]
+`,
+		},
+		"list_delete_empty": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{}),
+				Action:   plans.Delete,
+			},
+			expected: "[] -> null",
+		},
+		"list_delete": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{
+					{
+						Renderer: Primitive(1.0, nil, cty.Number),
+						Action:   plans.Delete,
+					},
+				}),
+				Action: plans.Delete,
+			},
+			expected: `
+[
+      - 1,
+    ] -> null
+`,
+		},
+		"list_create_element": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{
+					{
+						Renderer: Primitive(nil, 1.0, cty.Number),
+						Action:   plans.Create,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      + 1,
+    ]
+`,
+		},
+		"list_update_element": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{
+					{
+						Renderer: Primitive(0.0, 1.0, cty.Number),
+						Action:   plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      ~ 0 -> 1,
+    ]
+`,
+		},
+		"list_replace_element": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{
+					{
+						Renderer: Primitive(0.0, nil, cty.Number),
+						Action:   plans.Delete,
+					},
+					{
+						Renderer: Primitive(nil, 1.0, cty.Number),
+						Action:   plans.Create,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      - 0,
+      + 1,
+    ]
+`,
+		},
+		"list_delete_element": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{
+					{
+						Renderer: Primitive(0.0, nil, cty.Number),
+						Action:   plans.Delete,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      - 0,
+    ]
+`,
+		},
+		"list_update_forces_replacement": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{
+					{
+						Renderer: Primitive(0.0, 1.0, cty.Number),
+						Action:   plans.Update,
+					},
+				}),
+				Action:  plans.Update,
+				Replace: true,
+			},
+			expected: `
+[ # forces replacement
+      ~ 0 -> 1,
+    ]
+`,
+		},
+		"list_update_ignores_unchanged": {
+			diff: computed.Diff{
+				Renderer: NestedList([]computed.Diff{
+					{
+						Renderer: Primitive(0.0, 0.0, cty.Number),
+						Action:   plans.NoOp,
+					},
+					{
+						Renderer: Primitive(1.0, 1.0, cty.Number),
+						Action:   plans.NoOp,
+					},
+					{
+						Renderer: Primitive(2.0, 5.0, cty.Number),
+						Action:   plans.Update,
+					},
+					{
+						Renderer: Primitive(3.0, 3.0, cty.Number),
+						Action:   plans.NoOp,
+					},
+					{
+						Renderer: Primitive(4.0, 4.0, cty.Number),
+						Action:   plans.NoOp,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      ~ 2 -> 5,
+        # (4 unchanged elements hidden)
+    ]
+`,
+		},
+		"list_update_ignored_unchanged_with_context": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{
+					{
+						Renderer: Primitive(0.0, 0.0, cty.Number),
+						Action:   plans.NoOp,
+					},
+					{
+						Renderer: Primitive(1.0, 1.0, cty.Number),
+						Action:   plans.NoOp,
+					},
+					{
+						Renderer: Primitive(2.0, 5.0, cty.Number),
+						Action:   plans.Update,
+					},
+					{
+						Renderer: Primitive(3.0, 3.0, cty.Number),
+						Action:   plans.NoOp,
+					},
+					{
+						Renderer: Primitive(4.0, 4.0, cty.Number),
+						Action:   plans.NoOp,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+        # (1 unchanged element hidden)
+        1,
+      ~ 2 -> 5,
+        3,
+        # (1 unchanged element hidden)
+    ]
+`,
+		},
+		"list_create_sensitive_element": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{
+					{
+						Renderer: Sensitive(computed.Diff{
+							Renderer: Primitive(nil, 1.0, cty.Number),
+							Action:   plans.Create,
+						}, false, true),
+						Action: plans.Create,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      + (sensitive value),
+    ]
+`,
+		},
+		"list_delete_sensitive_element": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{
+					{
+						Renderer: Sensitive(computed.Diff{
+							Renderer: Primitive(1.0, nil, cty.Number),
+							Action:   plans.Delete,
+						}, true, false),
+						Action: plans.Delete,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      - (sensitive value),
+    ]
+`,
+		},
+		"list_update_sensitive_element": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{
+					{
+						Renderer: Sensitive(computed.Diff{
+							Renderer: Primitive(0.0, 1.0, cty.Number),
+							Action:   plans.Update,
+						}, true, true),
+						Action: plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      ~ (sensitive value),
+    ]
+`,
+		},
+		"list_update_sensitive_element_status": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{
+					{
+						Renderer: Sensitive(computed.Diff{
+							Renderer: Primitive(1.0, 1.0, cty.Number),
+							Action:   plans.NoOp,
+						}, false, true),
+						Action: plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      # Warning: this attribute value will be marked as sensitive and will not
+      # display in UI output after applying this change. The value is unchanged.
+      ~ (sensitive value),
+    ]
+`,
+		},
+		"list_create_computed_element": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{
+					{
+						Renderer: Unknown(computed.Diff{}),
+						Action:   plans.Create,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      + (known after apply),
+    ]
+`,
+		},
+		"list_update_computed_element": {
+			diff: computed.Diff{
+				Renderer: List([]computed.Diff{
+					{
+						Renderer: Unknown(computed.Diff{
+							Renderer: Primitive(0.0, nil, cty.Number),
+							Action:   plans.Delete,
+						}),
+						Action: plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      ~ 0 -> (known after apply),
+    ]
+`,
+		},
+		"set_create_empty": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{}),
+				Action:   plans.Create,
+			},
+			expected: "[]",
+		},
+		"set_create": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{
+					{
+						Renderer: Primitive(nil, 1.0, cty.Number),
+						Action:   plans.Create,
+					},
+				}),
+				Action: plans.Create,
+			},
+			expected: `
+[
+      + 1,
+    ]
+`,
+		},
+		"set_delete_empty": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{}),
+				Action:   plans.Delete,
+			},
+			expected: "[] -> null",
+		},
+		"set_delete": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{
+					{
+						Renderer: Primitive(1.0, nil, cty.Number),
+						Action:   plans.Delete,
+					},
+				}),
+				Action: plans.Delete,
+			},
+			expected: `
+[
+      - 1,
+    ] -> null
+`,
+		},
+		"set_create_element": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{
+					{
+						Renderer: Primitive(nil, 1.0, cty.Number),
+						Action:   plans.Create,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      + 1,
+    ]
+`,
+		},
+		"set_update_element": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{
+					{
+						Renderer: Primitive(0.0, 1.0, cty.Number),
+						Action:   plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      ~ 0 -> 1,
+    ]
+`,
+		},
+		"set_replace_element": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{
+					{
+						Renderer: Primitive(0.0, nil, cty.Number),
+						Action:   plans.Delete,
+					},
+					{
+						Renderer: Primitive(nil, 1.0, cty.Number),
+						Action:   plans.Create,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      - 0,
+      + 1,
+    ]
+`,
+		},
+		"set_delete_element": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{
+					{
+						Renderer: Primitive(0.0, nil, cty.Number),
+						Action:   plans.Delete,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      - 0,
+    ]
+`,
+		},
+		"set_update_forces_replacement": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{
+					{
+						Renderer: Primitive(0.0, 1.0, cty.Number),
+						Action:   plans.Update,
+					},
+				}),
+				Action:  plans.Update,
+				Replace: true,
+			},
+			expected: `
+[ # forces replacement
+      ~ 0 -> 1,
+    ]
+`,
+		},
+		"nested_set_update_forces_replacement": {
+			diff: computed.Diff{
+				Renderer: NestedSet([]computed.Diff{
+					{
+						Renderer: Object(map[string]computed.Diff{
+							"attribute_one": {
+								Renderer: Primitive(0.0, 1.0, cty.Number),
+								Action:   plans.Update,
+							},
+						}),
+						Action: plans.Update,
+					},
+				}),
+				Action:  plans.Update,
+				Replace: true,
+			},
+			expected: `
+[
+      ~ { # forces replacement
+          ~ attribute_one = 0 -> 1
+        },
+    ]
+`,
+		},
+		"set_update_ignores_unchanged": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{
+					{
+						Renderer: Primitive(0.0, 0.0, cty.Number),
+						Action:   plans.NoOp,
+					},
+					{
+						Renderer: Primitive(1.0, 1.0, cty.Number),
+						Action:   plans.NoOp,
+					},
+					{
+						Renderer: Primitive(2.0, 5.0, cty.Number),
+						Action:   plans.Update,
+					},
+					{
+						Renderer: Primitive(3.0, 3.0, cty.Number),
+						Action:   plans.NoOp,
+					},
+					{
+						Renderer: Primitive(4.0, 4.0, cty.Number),
+						Action:   plans.NoOp,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      ~ 2 -> 5,
+        # (4 unchanged elements hidden)
+    ]
+`,
+		},
+		"set_create_sensitive_element": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{
+					{
+						Renderer: Sensitive(computed.Diff{
+							Renderer: Primitive(nil, 1.0, cty.Number),
+							Action:   plans.Create,
+						}, false, true),
+						Action: plans.Create,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      + (sensitive value),
+    ]
+`,
+		},
+		"set_delete_sensitive_element": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{
+					{
+						Renderer: Sensitive(computed.Diff{
+							Renderer: Primitive(1.0, nil, cty.Number),
+							Action:   plans.Delete,
+						}, false, true),
+						Action: plans.Delete,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      - (sensitive value),
+    ]
+`,
+		},
+		"set_update_sensitive_element": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{
+					{
+						Renderer: Sensitive(computed.Diff{
+							Renderer: Primitive(0.0, 1.0, cty.Number),
+							Action:   plans.Update,
+						}, true, true),
+						Action: plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      ~ (sensitive value),
+    ]
+`,
+		},
+		"set_update_sensitive_element_status": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{
+					{
+						Renderer: Sensitive(computed.Diff{
+							Renderer: Primitive(1.0, 2.0, cty.Number),
+							Action:   plans.Update,
+						}, false, true),
+						Action: plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      # Warning: this attribute value will be marked as sensitive and will not
+      # display in UI output after applying this change.
+      ~ (sensitive value),
+    ]
+`,
+		},
+		"set_create_computed_element": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{
+					{
+						Renderer: Unknown(computed.Diff{}),
+						Action:   plans.Create,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      + (known after apply),
+    ]
+`,
+		},
+		"set_update_computed_element": {
+			diff: computed.Diff{
+				Renderer: Set([]computed.Diff{
+					{
+						Renderer: Unknown(computed.Diff{
+							Renderer: Primitive(0.0, nil, cty.Number),
+							Action:   plans.Delete,
+						}),
+						Action: plans.Update,
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+[
+      ~ 0 -> (known after apply),
+    ]
+`,
+		},
+		"create_empty_block": {
+			diff: computed.Diff{
+				Renderer: Block(nil, Blocks{}),
+				Action:   plans.Create,
+			},
+			expected: "{}",
+		},
+		"create_populated_block": {
+			diff: computed.Diff{
+				Renderer: Block(map[string]computed.Diff{
+					"string": {
+						Renderer: Primitive(nil, "root", cty.String),
+						Action:   plans.Create,
+					},
+					"boolean": {
+						Renderer: Primitive(nil, true, cty.Bool),
+						Action:   plans.Create,
+					},
+				}, Blocks{
+					SingleBlocks: map[string]computed.Diff{
+						"nested_block": {
+							Renderer: Block(map[string]computed.Diff{
+								"string": {
+									Renderer: Primitive(nil, "one", cty.String),
+									Action:   plans.Create,
+								},
+							}, Blocks{}),
+							Action: plans.Create,
+						},
+						"nested_block_two": {
+							Renderer: Block(map[string]computed.Diff{
+								"string": {
+									Renderer: Primitive(nil, "two", cty.String),
+									Action:   plans.Create,
+								},
+							}, Blocks{}),
+							Action: plans.Create,
+						},
+					},
+				}),
+				Action: plans.Create,
+			},
+			expected: `
+{
+      + boolean = true
+      + string  = "root"
+
+      + nested_block {
+          + string = "one"
+        }
+
+      + nested_block_two {
+          + string = "two"
+        }
+    }`,
+		},
+		"update_empty_block": {
+			diff: computed.Diff{
+				Renderer: Block(map[string]computed.Diff{
+					"string": {
+						Renderer: Primitive(nil, "root", cty.String),
+						Action:   plans.Create,
+					},
+					"boolean": {
+						Renderer: Primitive(nil, true, cty.Bool),
+						Action:   plans.Create,
+					},
+				}, Blocks{
+					SingleBlocks: map[string]computed.Diff{
+						"nested_block": {
+
+							Renderer: Block(map[string]computed.Diff{
+								"string": {
+									Renderer: Primitive(nil, "one", cty.String),
+									Action:   plans.Create,
+								},
+							}, Blocks{}),
+							Action: plans.Create,
+						},
+						"nested_block_two": {
+
+							Renderer: Block(map[string]computed.Diff{
+								"string": {
+									Renderer: Primitive(nil, "two", cty.String),
+									Action:   plans.Create,
+								},
+							}, Blocks{}),
+							Action: plans.Create,
+						},
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      + boolean = true
+      + string  = "root"
+
+      + nested_block {
+          + string = "one"
+        }
+
+      + nested_block_two {
+          + string = "two"
+        }
+    }`,
+		},
+		"update_populated_block": {
+			diff: computed.Diff{
+				Renderer: Block(map[string]computed.Diff{
+					"string": {
+						Renderer: Primitive(nil, "root", cty.String),
+						Action:   plans.Create,
+					},
+					"boolean": {
+						Renderer: Primitive(false, true, cty.Bool),
+						Action:   plans.Update,
+					},
+				}, Blocks{
+					SingleBlocks: map[string]computed.Diff{
+						"nested_block": {
+							Renderer: Block(map[string]computed.Diff{
+								"string": {
+									Renderer: Primitive(nil, "one", cty.String),
+									Action:   plans.NoOp,
+								},
+							}, Blocks{}),
+							Action: plans.NoOp,
+						},
+						"nested_block_two": {
+							Renderer: Block(map[string]computed.Diff{
+								"string": {
+									Renderer: Primitive(nil, "two", cty.String),
+									Action:   plans.Create,
+								},
+							}, Blocks{}),
+							Action: plans.Create,
+						},
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      ~ boolean = false -> true
+      + string  = "root"
+
+      + nested_block_two {
+          + string = "two"
+        }
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+		"clear_populated_block": {
+			diff: computed.Diff{
+				Renderer: Block(map[string]computed.Diff{
+					"string": {
+						Renderer: Primitive("root", nil, cty.String),
+						Action:   plans.Delete,
+					},
+					"boolean": {
+						Renderer: Primitive(true, nil, cty.Bool),
+						Action:   plans.Delete,
+					},
+				}, Blocks{
+					SingleBlocks: map[string]computed.Diff{
+						"nested_block": {
+							Renderer: Block(map[string]computed.Diff{
+								"string": {
+									Renderer: Primitive("one", nil, cty.String),
+									Action:   plans.Delete,
+								},
+							}, Blocks{}),
+							Action: plans.Delete,
+						},
+						"nested_block_two": {
+							Renderer: Block(map[string]computed.Diff{
+								"string": {
+									Renderer: Primitive("two", nil, cty.String),
+									Action:   plans.Delete,
+								},
+							}, Blocks{}),
+							Action: plans.Delete,
+						},
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      - boolean = true -> null
+      - string  = "root" -> null
+
+      - nested_block {
+          - string = "one" -> null
+        }
+
+      - nested_block_two {
+          - string = "two" -> null
+        }
+    }`,
+		},
+		"delete_populated_block": {
+			diff: computed.Diff{
+				Renderer: Block(map[string]computed.Diff{
+					"string": {
+						Renderer: Primitive("root", nil, cty.String),
+						Action:   plans.Delete,
+					},
+					"boolean": {
+						Renderer: Primitive(true, nil, cty.Bool),
+						Action:   plans.Delete,
+					},
+				}, Blocks{
+					SingleBlocks: map[string]computed.Diff{
+						"nested_block": {
+							Renderer: Block(map[string]computed.Diff{
+								"string": {
+									Renderer: Primitive("one", nil, cty.String),
+									Action:   plans.Delete,
+								},
+							}, Blocks{}),
+							Action: plans.Delete,
+						},
+						"nested_block_two": {
+							Renderer: Block(map[string]computed.Diff{
+								"string": {
+									Renderer: Primitive("two", nil, cty.String),
+									Action:   plans.Delete,
+								},
+							}, Blocks{}),
+							Action: plans.Delete,
+						},
+					},
+				}),
+				Action: plans.Delete,
+			},
+			expected: `
+{
+      - boolean = true -> null
+      - string  = "root" -> null
+
+      - nested_block {
+          - string = "one" -> null
+        }
+
+      - nested_block_two {
+          - string = "two" -> null
+        }
+    }`,
+		},
+		"list_block_update": {
+			diff: computed.Diff{
+				Renderer: Block(
+					nil,
+					Blocks{
+						ListBlocks: map[string][]computed.Diff{
+							"list_blocks": {
+								{
+									Renderer: Block(map[string]computed.Diff{
+										"number": {
+											Renderer: Primitive(1.0, 2.0, cty.Number),
+											Action:   plans.Update,
+										},
+										"string": {
+											Renderer: Primitive(nil, "new", cty.String),
+											Action:   plans.Create,
+										},
+									}, Blocks{}),
+									Action: plans.Update,
+								},
+								{
+									Renderer: Block(map[string]computed.Diff{
+										"number": {
+											Renderer: Primitive(1.0, nil, cty.Number),
+											Action:   plans.Delete,
+										},
+										"string": {
+											Renderer: Primitive("old", "new", cty.String),
+											Action:   plans.Update,
+										},
+									}, Blocks{}),
+									Action: plans.Update,
+								},
+							},
+						},
+					}),
+			},
+			expected: `
+{
+      ~ list_blocks {
+          ~ number = 1 -> 2
+          + string = "new"
+        }
+      ~ list_blocks {
+          - number = 1 -> null
+          ~ string = "old" -> "new"
+        }
+    }`,
+		},
+		"set_block_update": {
+			diff: computed.Diff{
+				Renderer: Block(
+					nil,
+					Blocks{
+						SetBlocks: map[string][]computed.Diff{
+							"set_blocks": {
+								{
+									Renderer: Block(map[string]computed.Diff{
+										"number": {
+											Renderer: Primitive(1.0, 2.0, cty.Number),
+											Action:   plans.Update,
+										},
+										"string": {
+											Renderer: Primitive(nil, "new", cty.String),
+											Action:   plans.Create,
+										},
+									}, Blocks{}),
+									Action: plans.Update,
+								},
+								{
+									Renderer: Block(map[string]computed.Diff{
+										"number": {
+											Renderer: Primitive(1.0, nil, cty.Number),
+											Action:   plans.Delete,
+										},
+										"string": {
+											Renderer: Primitive("old", "new", cty.String),
+											Action:   plans.Update,
+										},
+									}, Blocks{}),
+									Action: plans.Update,
+								},
+							},
+						},
+					}),
+			},
+			expected: `
+{
+      ~ set_blocks {
+          ~ number = 1 -> 2
+          + string = "new"
+        }
+      ~ set_blocks {
+          - number = 1 -> null
+          ~ string = "old" -> "new"
+        }
+    }`,
+		},
+		"map_block_update": {
+			diff: computed.Diff{
+				Renderer: Block(
+					nil,
+					Blocks{
+						MapBlocks: map[string]map[string]computed.Diff{
+							"list_blocks": {
+								"key_one": {
+									Renderer: Block(map[string]computed.Diff{
+										"number": {
+											Renderer: Primitive(1.0, 2.0, cty.Number),
+											Action:   plans.Update,
+										},
+										"string": {
+											Renderer: Primitive(nil, "new", cty.String),
+											Action:   plans.Create,
+										},
+									}, Blocks{}),
+									Action: plans.Update,
+								},
+								"key:two": {
+									Renderer: Block(map[string]computed.Diff{
+										"number": {
+											Renderer: Primitive(1.0, nil, cty.Number),
+											Action:   plans.Delete,
+										},
+										"string": {
+											Renderer: Primitive("old", "new", cty.String),
+											Action:   plans.Update,
+										},
+									}, Blocks{}),
+									Action: plans.Update,
+								},
+							},
+						},
+					}),
+			},
+			expected: `
+{
+      ~ list_blocks "key:two" {
+          - number = 1 -> null
+          ~ string = "old" -> "new"
+        }
+      ~ list_blocks "key_one" {
+          ~ number = 1 -> 2
+          + string = "new"
+        }
+    }
+`,
+		},
+		"sensitive_block": {
+			diff: computed.Diff{
+				Renderer: SensitiveBlock(computed.Diff{
+					Renderer: Block(nil, Blocks{}),
+					Action:   plans.NoOp,
+				}, true, true),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      # At least one attribute in this block is (or was) sensitive,
+      # so its contents will not be displayed.
+    }
+`,
+		},
+		"delete_empty_block": {
+			diff: computed.Diff{
+				Renderer: Block(nil, Blocks{}),
+				Action:   plans.Delete,
+			},
+			expected: "{}",
+		},
+		"block_escapes_keys": {
+			diff: computed.Diff{
+				Renderer: Block(map[string]computed.Diff{
+					"attribute_one": {
+						Renderer: Primitive(1.0, 2.0, cty.Number),
+						Action:   plans.Update,
+					},
+					"attribute:two": {
+						Renderer: Primitive(2.0, 3.0, cty.Number),
+						Action:   plans.Update,
+					},
+					"attribute_six": {
+						Renderer: Primitive(3.0, 4.0, cty.Number),
+						Action:   plans.Update,
+					},
+				}, Blocks{
+					SingleBlocks: map[string]computed.Diff{
+						"nested_block:one": {
+							Renderer: Block(map[string]computed.Diff{
+								"string": {
+									Renderer: Primitive("one", "four", cty.String),
+									Action:   plans.Update,
+								},
+							}, Blocks{}),
+							Action: plans.Update,
+						},
+						"nested_block_two": {
+							Renderer: Block(map[string]computed.Diff{
+								"string": {
+									Renderer: Primitive("two", "three", cty.String),
+									Action:   plans.Update,
+								},
+							}, Blocks{}),
+							Action: plans.Update,
+						},
+					},
+				}),
+				Action: plans.Update,
+			},
+			expected: `
+{
+      ~ "attribute:two" = 2 -> 3
+      ~ attribute_one   = 1 -> 2
+      ~ attribute_six   = 3 -> 4
+
+      ~ "nested_block:one" {
+          ~ string = "one" -> "four"
+        }
+
+      ~ nested_block_two {
+          ~ string = "two" -> "three"
+        }
+    }`,
+		},
+		"block_always_includes_important_attributes": {
+			diff: computed.Diff{
+				Renderer: Block(map[string]computed.Diff{
+					"id": {
+						Renderer: Primitive("root", "root", cty.String),
+						Action:   plans.NoOp,
+					},
+					"boolean": {
+						Renderer: Primitive(false, false, cty.Bool),
+						Action:   plans.NoOp,
+					},
+				}, Blocks{
+					SingleBlocks: map[string]computed.Diff{
+						"nested_block": {
+							Renderer: Block(map[string]computed.Diff{
+								"string": {
+									Renderer: Primitive("one", "one", cty.String),
+									Action:   plans.NoOp,
+								},
+							}, Blocks{}),
+							Action: plans.NoOp,
+						},
+						"nested_block_two": {
+							Renderer: Block(map[string]computed.Diff{
+								"string": {
+									Renderer: Primitive("two", "two", cty.String),
+									Action:   plans.NoOp,
+								},
+							}, Blocks{}),
+							Action: plans.NoOp,
+						},
+					},
+				}),
+				Action: plans.NoOp,
+			},
+			expected: `
+{
+        id      = "root"
+        # (1 unchanged attribute hidden)
+
+        # (2 unchanged blocks hidden)
+    }`,
+		},
+		"output_map_to_list": {
+			diff: computed.Diff{
+				Renderer: TypeChange(computed.Diff{
+					Renderer: Map(map[string]computed.Diff{
+						"element_one": {
+							Renderer: Primitive(0.0, nil, cty.Number),
+							Action:   plans.Delete,
+						},
+						"element_two": {
+							Renderer: Primitive(1.0, nil, cty.Number),
+							Action:   plans.Delete,
+						},
+					}),
+					Action: plans.Delete,
+				}, computed.Diff{
+					Renderer: List([]computed.Diff{
+						{
+							Renderer: Primitive(nil, 0.0, cty.Number),
+							Action:   plans.Create,
+						},
+						{
+							Renderer: Primitive(nil, 1.0, cty.Number),
+							Action:   plans.Create,
+						},
+					}),
+					Action: plans.Create,
+				}),
+			},
+			expected: `
+{
+      - "element_one" = 0
+      - "element_two" = 1
+    } -> [
+      + 0,
+      + 1,
+    ]
+`,
+		},
+		"json_string_no_symbols": {
+			diff: computed.Diff{
+				Renderer: Primitive("{\"key\":\"value\"}", "{\"key\":\"value\"}", cty.String),
+				Action:   plans.NoOp,
+			},
+			opts: computed.RenderHumanOpts{
+				HideDiffActionSymbols: true,
+				ShowUnchangedChildren: true,
+			},
+			expected: `
+jsonencode(
+    {
+        key = "value"
+    }
+)
+`,
+		},
+	}
+	for name, tc := range tcs {
+		t.Run(name, func(t *testing.T) {
+
+			opts := tc.opts.Clone()
+			opts.Colorize = &colorize
+
+			expected := strings.TrimSpace(tc.expected)
+			actual := tc.diff.RenderHuman(0, opts)
+			if diff := cmp.Diff(expected, actual); len(diff) > 0 {
+				t.Fatalf("\nexpected:\n%s\nactual:\n%s\ndiff:\n%s\n", expected, actual, diff)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/sensitive.go b/v1.5.7/internal/command/jsonformat/computed/renderers/sensitive.go
new file mode 100644
index 0000000..75a18c3
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/sensitive.go
@@ -0,0 +1,53 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+var _ computed.DiffRenderer = (*sensitiveRenderer)(nil)
+
+func Sensitive(change computed.Diff, beforeSensitive, afterSensitive bool) computed.DiffRenderer {
+	return &sensitiveRenderer{
+		inner:           change,
+		beforeSensitive: beforeSensitive,
+		afterSensitive:  afterSensitive,
+	}
+}
+
+type sensitiveRenderer struct {
+	inner computed.Diff
+
+	beforeSensitive bool
+	afterSensitive  bool
+}
+
+func (renderer sensitiveRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string {
+	return fmt.Sprintf("(sensitive value)%s%s", nullSuffix(diff.Action, opts), forcesReplacement(diff.Replace, opts))
+}
+
+func (renderer sensitiveRenderer) WarningsHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) []string {
+	if (renderer.beforeSensitive == renderer.afterSensitive) || renderer.inner.Action == plans.Create || renderer.inner.Action == plans.Delete {
+		// Only display warnings for sensitive values if they are changing from
+		// being sensitive or to being sensitive and if they are not being
+		// destroyed or created.
+		return []string{}
+	}
+
+	var warning string
+	if renderer.beforeSensitive {
+		warning = opts.Colorize.Color(fmt.Sprintf("  # [yellow]Warning[reset]: this attribute value will no longer be marked as sensitive\n%s  # after applying this change.", formatIndent(indent)))
+	} else {
+		warning = opts.Colorize.Color(fmt.Sprintf("  # [yellow]Warning[reset]: this attribute value will be marked as sensitive and will not\n%s  # display in UI output after applying this change.", formatIndent(indent)))
+	}
+
+	if renderer.inner.Action == plans.NoOp {
+		return []string{fmt.Sprintf("%s The value is unchanged.", warning)}
+	}
+	return []string{warning}
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/sensitive_block.go b/v1.5.7/internal/command/jsonformat/computed/renderers/sensitive_block.go
new file mode 100644
index 0000000..7b54deb
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/sensitive_block.go
@@ -0,0 +1,47 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+func SensitiveBlock(diff computed.Diff, beforeSensitive, afterSensitive bool) computed.DiffRenderer {
+	return &sensitiveBlockRenderer{
+		inner:           diff,
+		beforeSensitive: beforeSensitive,
+		afterSensitive:  afterSensitive,
+	}
+}
+
+type sensitiveBlockRenderer struct {
+	inner computed.Diff
+
+	afterSensitive  bool
+	beforeSensitive bool
+}
+
+func (renderer sensitiveBlockRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string {
+	cachedLinePrefix := fmt.Sprintf("%s%s", formatIndent(indent), writeDiffActionSymbol(plans.NoOp, opts))
+	return fmt.Sprintf("{%s\n%s  # At least one attribute in this block is (or was) sensitive,\n%s  # so its contents will not be displayed.\n%s}",
+		forcesReplacement(diff.Replace, opts), cachedLinePrefix, cachedLinePrefix, cachedLinePrefix)
+}
+
+func (renderer sensitiveBlockRenderer) WarningsHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) []string {
+	if (renderer.beforeSensitive == renderer.afterSensitive) || renderer.inner.Action == plans.Create || renderer.inner.Action == plans.Delete {
+		// Only display warnings for sensitive values if they are changing from
+		// being sensitive or to being sensitive and if they are not being
+		// destroyed or created.
+		return []string{}
+	}
+
+	if renderer.beforeSensitive {
+		return []string{opts.Colorize.Color(fmt.Sprintf("  # [yellow]Warning[reset]: this block will no longer be marked as sensitive\n%s  # after applying this change.", formatIndent(indent)))}
+	} else {
+		return []string{opts.Colorize.Color(fmt.Sprintf("  # [yellow]Warning[reset]: this block will be marked as sensitive and will not\n%s  # display in UI output after applying this change.", formatIndent(indent)))}
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/set.go b/v1.5.7/internal/command/jsonformat/computed/renderers/set.go
new file mode 100644
index 0000000..f82cbbc
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/set.go
@@ -0,0 +1,75 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"bytes"
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+var _ computed.DiffRenderer = (*setRenderer)(nil)
+
+func Set(elements []computed.Diff) computed.DiffRenderer {
+	return &setRenderer{
+		elements: elements,
+	}
+}
+
+func NestedSet(elements []computed.Diff) computed.DiffRenderer {
+	return &setRenderer{
+		elements:                  elements,
+		overrideForcesReplacement: true,
+	}
+}
+
+type setRenderer struct {
+	NoWarningsRenderer
+
+	elements []computed.Diff
+
+	overrideForcesReplacement bool
+}
+
+func (renderer setRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string {
+	// Sets are a bit finicky, nested sets don't render the forces replacement
+	// suffix themselves, but push it onto their children. So if we are
+	// overriding the forces replacement setting, we set it to true for children
+	// and false for ourselves.
+	displayForcesReplacementInSelf := diff.Replace && !renderer.overrideForcesReplacement
+	displayForcesReplacementInChildren := diff.Replace && renderer.overrideForcesReplacement
+
+	if len(renderer.elements) == 0 {
+		return fmt.Sprintf("[]%s%s", nullSuffix(diff.Action, opts), forcesReplacement(displayForcesReplacementInSelf, opts))
+	}
+
+	elementOpts := opts.Clone()
+	elementOpts.OverrideNullSuffix = true
+	elementOpts.OverrideForcesReplacement = displayForcesReplacementInChildren
+
+	unchangedElements := 0
+
+	var buf bytes.Buffer
+	buf.WriteString(fmt.Sprintf("[%s\n", forcesReplacement(displayForcesReplacementInSelf, opts)))
+	for _, element := range renderer.elements {
+		if element.Action == plans.NoOp && !opts.ShowUnchangedChildren {
+			unchangedElements++
+			continue
+		}
+
+		for _, warning := range element.WarningsHuman(indent+1, opts) {
+			buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning))
+		}
+		buf.WriteString(fmt.Sprintf("%s%s%s,\n", formatIndent(indent+1), writeDiffActionSymbol(element.Action, elementOpts), element.RenderHuman(indent+1, elementOpts)))
+	}
+
+	if unchangedElements > 0 {
+		buf.WriteString(fmt.Sprintf("%s%s%s\n", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), unchanged("element", unchangedElements, opts)))
+	}
+
+	buf.WriteString(fmt.Sprintf("%s%s]%s", formatIndent(indent), writeDiffActionSymbol(plans.NoOp, opts), nullSuffix(diff.Action, opts)))
+	return buf.String()
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/string.go b/v1.5.7/internal/command/jsonformat/computed/renderers/string.go
new file mode 100644
index 0000000..9266d93
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/string.go
@@ -0,0 +1,59 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"encoding/json"
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+)
+
+type evaluatedString struct {
+	String string
+	Json   interface{}
+
+	IsMultiline bool
+	IsNull      bool
+}
+
+func evaluatePrimitiveString(value interface{}, opts computed.RenderHumanOpts) evaluatedString {
+	if value == nil {
+		return evaluatedString{
+			String: opts.Colorize.Color("[dark_gray]null[reset]"),
+			IsNull: true,
+		}
+	}
+
+	str := value.(string)
+
+	if strings.HasPrefix(str, "{") || strings.HasPrefix(str, "[") {
+		var jv interface{}
+		if err := json.Unmarshal([]byte(str), &jv); err == nil {
+			return evaluatedString{
+				String: str,
+				Json:   jv,
+			}
+		}
+	}
+
+	if strings.Contains(str, "\n") {
+		return evaluatedString{
+			String:      strings.TrimSpace(str),
+			IsMultiline: true,
+		}
+	}
+
+	return evaluatedString{
+		String: str,
+	}
+}
+
+func (e evaluatedString) RenderSimple() string {
+	if e.IsNull {
+		return e.String
+	}
+	return fmt.Sprintf("%q", e.String)
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/testing.go b/v1.5.7/internal/command/jsonformat/computed/renderers/testing.go
new file mode 100644
index 0000000..adaafc2
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/testing.go
@@ -0,0 +1,321 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"sort"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+type ValidateDiffFunction func(t *testing.T, diff computed.Diff)
+
+func validateDiff(t *testing.T, diff computed.Diff, expectedAction plans.Action, expectedReplace bool) {
+	if diff.Replace != expectedReplace || diff.Action != expectedAction {
+		t.Errorf("\nreplace:\n\texpected:%t\n\tactual:%t\naction:\n\texpected:%s\n\tactual:%s", expectedReplace, diff.Replace, expectedAction, diff.Action)
+	}
+}
+
+func ValidatePrimitive(before, after interface{}, action plans.Action, replace bool) ValidateDiffFunction {
+	return func(t *testing.T, diff computed.Diff) {
+		validateDiff(t, diff, action, replace)
+
+		primitive, ok := diff.Renderer.(*primitiveRenderer)
+		if !ok {
+			t.Errorf("invalid renderer type: %T", diff.Renderer)
+			return
+		}
+
+		beforeDiff := cmp.Diff(primitive.before, before)
+		afterDiff := cmp.Diff(primitive.after, after)
+
+		if len(beforeDiff) > 0 || len(afterDiff) > 0 {
+			t.Errorf("before diff: (%s), after diff: (%s)", beforeDiff, afterDiff)
+		}
+	}
+}
+
+func ValidateObject(attributes map[string]ValidateDiffFunction, action plans.Action, replace bool) ValidateDiffFunction {
+	return func(t *testing.T, diff computed.Diff) {
+		validateDiff(t, diff, action, replace)
+
+		object, ok := diff.Renderer.(*objectRenderer)
+		if !ok {
+			t.Errorf("invalid renderer type: %T", diff.Renderer)
+			return
+		}
+
+		if !object.overrideNullSuffix {
+			t.Errorf("created the wrong type of object renderer")
+		}
+
+		validateMapType(t, object.attributes, attributes)
+	}
+}
+
+func ValidateNestedObject(attributes map[string]ValidateDiffFunction, action plans.Action, replace bool) ValidateDiffFunction {
+	return func(t *testing.T, diff computed.Diff) {
+		validateDiff(t, diff, action, replace)
+
+		object, ok := diff.Renderer.(*objectRenderer)
+		if !ok {
+			t.Errorf("invalid renderer type: %T", diff.Renderer)
+			return
+		}
+
+		if object.overrideNullSuffix {
+			t.Errorf("created the wrong type of object renderer")
+		}
+
+		validateMapType(t, object.attributes, attributes)
+	}
+}
+
+func ValidateMap(elements map[string]ValidateDiffFunction, action plans.Action, replace bool) ValidateDiffFunction {
+	return func(t *testing.T, diff computed.Diff) {
+		validateDiff(t, diff, action, replace)
+
+		m, ok := diff.Renderer.(*mapRenderer)
+		if !ok {
+			t.Errorf("invalid renderer type: %T", diff.Renderer)
+			return
+		}
+
+		validateMapType(t, m.elements, elements)
+	}
+}
+
+func validateMapType(t *testing.T, actual map[string]computed.Diff, expected map[string]ValidateDiffFunction) {
+	validateKeys(t, actual, expected)
+
+	for key, expected := range expected {
+		if actual, ok := actual[key]; ok {
+			expected(t, actual)
+		}
+	}
+}
+
+func validateKeys[C, V any](t *testing.T, actual map[string]C, expected map[string]V) {
+	if len(actual) != len(expected) {
+
+		var actualAttributes []string
+		var expectedAttributes []string
+
+		for key := range actual {
+			actualAttributes = append(actualAttributes, key)
+		}
+		for key := range expected {
+			expectedAttributes = append(expectedAttributes, key)
+		}
+
+		sort.Strings(actualAttributes)
+		sort.Strings(expectedAttributes)
+
+		if diff := cmp.Diff(actualAttributes, expectedAttributes); len(diff) > 0 {
+			t.Errorf("actual and expected attributes did not match: %s", diff)
+		}
+	}
+}
+
+func ValidateList(elements []ValidateDiffFunction, action plans.Action, replace bool) ValidateDiffFunction {
+	return func(t *testing.T, diff computed.Diff) {
+		validateDiff(t, diff, action, replace)
+
+		list, ok := diff.Renderer.(*listRenderer)
+		if !ok {
+			t.Errorf("invalid renderer type: %T", diff.Renderer)
+			return
+		}
+
+		if !list.displayContext {
+			t.Errorf("created the wrong type of list renderer")
+		}
+
+		validateSliceType(t, list.elements, elements)
+	}
+}
+
+func ValidateNestedList(elements []ValidateDiffFunction, action plans.Action, replace bool) ValidateDiffFunction {
+	return func(t *testing.T, diff computed.Diff) {
+		validateDiff(t, diff, action, replace)
+
+		list, ok := diff.Renderer.(*listRenderer)
+		if !ok {
+			t.Errorf("invalid renderer type: %T", diff.Renderer)
+			return
+		}
+
+		if list.displayContext {
+			t.Errorf("created the wrong type of list renderer")
+		}
+
+		validateSliceType(t, list.elements, elements)
+	}
+}
+
+func ValidateSet(elements []ValidateDiffFunction, action plans.Action, replace bool) ValidateDiffFunction {
+	return func(t *testing.T, diff computed.Diff) {
+		validateDiff(t, diff, action, replace)
+
+		set, ok := diff.Renderer.(*setRenderer)
+		if !ok {
+			t.Errorf("invalid renderer type: %T", diff.Renderer)
+			return
+		}
+
+		validateSliceType(t, set.elements, elements)
+	}
+}
+
+func validateSliceType(t *testing.T, actual []computed.Diff, expected []ValidateDiffFunction) {
+	if len(actual) != len(expected) {
+		t.Errorf("expected %d elements but found %d elements", len(expected), len(actual))
+		return
+	}
+
+	for ix := 0; ix < len(expected); ix++ {
+		expected[ix](t, actual[ix])
+	}
+}
+
+func ValidateBlock(
+	attributes map[string]ValidateDiffFunction,
+	singleBlocks map[string]ValidateDiffFunction,
+	listBlocks map[string][]ValidateDiffFunction,
+	mapBlocks map[string]map[string]ValidateDiffFunction,
+	setBlocks map[string][]ValidateDiffFunction,
+	action plans.Action,
+	replace bool) ValidateDiffFunction {
+	return func(t *testing.T, diff computed.Diff) {
+		validateDiff(t, diff, action, replace)
+
+		block, ok := diff.Renderer.(*blockRenderer)
+		if !ok {
+			t.Errorf("invalid renderer type: %T", diff.Renderer)
+			return
+		}
+
+		validateKeys(t, block.attributes, attributes)
+		validateKeys(t, block.blocks.SingleBlocks, singleBlocks)
+		validateKeys(t, block.blocks.ListBlocks, listBlocks)
+		validateKeys(t, block.blocks.MapBlocks, mapBlocks)
+		validateKeys(t, block.blocks.SetBlocks, setBlocks)
+
+		for key, expected := range attributes {
+			if actual, ok := block.attributes[key]; ok {
+				expected(t, actual)
+			}
+		}
+
+		for key, expected := range singleBlocks {
+			expected(t, block.blocks.SingleBlocks[key])
+		}
+
+		for key, expected := range listBlocks {
+			if actual, ok := block.blocks.ListBlocks[key]; ok {
+				if len(actual) != len(expected) {
+					t.Errorf("expected %d blocks within %s but found %d elements", len(expected), key, len(actual))
+				}
+				for ix := range expected {
+					expected[ix](t, actual[ix])
+				}
+			}
+		}
+
+		for key, expected := range setBlocks {
+			if actual, ok := block.blocks.SetBlocks[key]; ok {
+				if len(actual) != len(expected) {
+					t.Errorf("expected %d blocks within %s but found %d elements", len(expected), key, len(actual))
+				}
+				for ix := range expected {
+					expected[ix](t, actual[ix])
+				}
+			}
+		}
+
+		for key, expected := range setBlocks {
+			if actual, ok := block.blocks.SetBlocks[key]; ok {
+				if len(actual) != len(expected) {
+					t.Errorf("expected %d blocks within %s but found %d elements", len(expected), key, len(actual))
+				}
+				for ix := range expected {
+					expected[ix](t, actual[ix])
+				}
+			}
+		}
+
+		for key, expected := range mapBlocks {
+			if actual, ok := block.blocks.MapBlocks[key]; ok {
+				if len(actual) != len(expected) {
+					t.Errorf("expected %d blocks within %s but found %d elements", len(expected), key, len(actual))
+				}
+				for dKey := range expected {
+					expected[dKey](t, actual[dKey])
+				}
+			}
+		}
+	}
+}
+
+func ValidateTypeChange(before, after ValidateDiffFunction, action plans.Action, replace bool) ValidateDiffFunction {
+	return func(t *testing.T, diff computed.Diff) {
+		validateDiff(t, diff, action, replace)
+
+		typeChange, ok := diff.Renderer.(*typeChangeRenderer)
+		if !ok {
+			t.Errorf("invalid renderer type: %T", diff.Renderer)
+			return
+		}
+
+		before(t, typeChange.before)
+		after(t, typeChange.after)
+	}
+}
+
+func ValidateSensitive(inner ValidateDiffFunction, beforeSensitive, afterSensitive bool, action plans.Action, replace bool) ValidateDiffFunction {
+	return func(t *testing.T, diff computed.Diff) {
+		validateDiff(t, diff, action, replace)
+
+		sensitive, ok := diff.Renderer.(*sensitiveRenderer)
+		if !ok {
+			t.Errorf("invalid renderer type: %T", diff.Renderer)
+			return
+		}
+
+		if beforeSensitive != sensitive.beforeSensitive || afterSensitive != sensitive.afterSensitive {
+			t.Errorf("before or after sensitive values don't match:\n\texpected; before: %t after: %t\n\tactual; before: %t, after: %t", beforeSensitive, afterSensitive, sensitive.beforeSensitive, sensitive.afterSensitive)
+		}
+
+		inner(t, sensitive.inner)
+	}
+}
+
+func ValidateUnknown(before ValidateDiffFunction, action plans.Action, replace bool) ValidateDiffFunction {
+	return func(t *testing.T, diff computed.Diff) {
+		validateDiff(t, diff, action, replace)
+
+		unknown, ok := diff.Renderer.(*unknownRenderer)
+		if !ok {
+			t.Errorf("invalid renderer type: %T", diff.Renderer)
+			return
+		}
+
+		if before == nil {
+			if unknown.before.Renderer != nil {
+				t.Errorf("did not expect a before renderer, but found one")
+			}
+			return
+		}
+
+		if unknown.before.Renderer == nil {
+			t.Errorf("expected a before renderer, but found none")
+		}
+
+		before(t, unknown.before)
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/type_change.go b/v1.5.7/internal/command/jsonformat/computed/renderers/type_change.go
new file mode 100644
index 0000000..2346072
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/type_change.go
@@ -0,0 +1,31 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+)
+
+var _ computed.DiffRenderer = (*typeChangeRenderer)(nil)
+
+func TypeChange(before, after computed.Diff) computed.DiffRenderer {
+	return &typeChangeRenderer{
+		before: before,
+		after:  after,
+	}
+}
+
+type typeChangeRenderer struct {
+	NoWarningsRenderer
+
+	before computed.Diff
+	after  computed.Diff
+}
+
+func (renderer typeChangeRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string {
+	opts.OverrideNullSuffix = true // Never render null suffix for children of type changes.
+	return fmt.Sprintf("%s %s %s", renderer.before.RenderHuman(indent, opts), opts.Colorize.Color("[yellow]->[reset]"), renderer.after.RenderHuman(indent, opts))
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/unknown.go b/v1.5.7/internal/command/jsonformat/computed/renderers/unknown.go
new file mode 100644
index 0000000..1f67097
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/unknown.go
@@ -0,0 +1,36 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+var _ computed.DiffRenderer = (*unknownRenderer)(nil)
+
+func Unknown(before computed.Diff) computed.DiffRenderer {
+	return &unknownRenderer{
+		before: before,
+	}
+}
+
+type unknownRenderer struct {
+	NoWarningsRenderer
+
+	before computed.Diff
+}
+
+func (renderer unknownRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string {
+	if diff.Action == plans.Create {
+		return fmt.Sprintf("(known after apply)%s", forcesReplacement(diff.Replace, opts))
+	}
+
+	// Never render null suffix for children of unknown changes.
+	opts.OverrideNullSuffix = true
+	return fmt.Sprintf("%s -> (known after apply)%s", renderer.before.RenderHuman(indent, opts), forcesReplacement(diff.Replace, opts))
+}
diff --git a/v1.5.7/internal/command/jsonformat/computed/renderers/util.go b/v1.5.7/internal/command/jsonformat/computed/renderers/util.go
new file mode 100644
index 0000000..a12ae2c
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/computed/renderers/util.go
@@ -0,0 +1,93 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package renderers
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/command/format"
+
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+// NoWarningsRenderer defines a Warnings function that returns an empty list of
+// warnings. This can be used by other renderers to ensure we don't see lots of
+// repeats of this empty function.
+type NoWarningsRenderer struct{}
+
+// WarningsHuman returns an empty slice, as the name NoWarningsRenderer suggests.
+func (render NoWarningsRenderer) WarningsHuman(_ computed.Diff, _ int, _ computed.RenderHumanOpts) []string {
+	return nil
+}
+
+// nullSuffix returns the `-> null` suffix if the change is a delete action, and
+// it has not been overridden.
+func nullSuffix(action plans.Action, opts computed.RenderHumanOpts) string {
+	if !opts.OverrideNullSuffix && action == plans.Delete {
+		return opts.Colorize.Color(" [dark_gray]-> null[reset]")
+	}
+	return ""
+}
+
+// forcesReplacement returns the `# forces replacement` suffix if this change is
+// driving the entire resource to be replaced.
+func forcesReplacement(replace bool, opts computed.RenderHumanOpts) string {
+	if replace || opts.OverrideForcesReplacement {
+		return opts.Colorize.Color(" [red]# forces replacement[reset]")
+	}
+	return ""
+}
+
+// indent returns whitespace that is the required length for the specified
+// indent.
+func formatIndent(indent int) string {
+	return strings.Repeat("    ", indent)
+}
+
+// unchanged prints out a description saying how many of 'keyword' have been
+// hidden because they are unchanged or noop actions.
+func unchanged(keyword string, count int, opts computed.RenderHumanOpts) string {
+	if count == 1 {
+		return opts.Colorize.Color(fmt.Sprintf("[dark_gray]# (%d unchanged %s hidden)[reset]", count, keyword))
+	}
+	return opts.Colorize.Color(fmt.Sprintf("[dark_gray]# (%d unchanged %ss hidden)[reset]", count, keyword))
+}
+
+// EnsureValidAttributeName checks if `name` contains any HCL syntax and calls
+// and returns hclEscapeString.
+func EnsureValidAttributeName(name string) string {
+	if !hclsyntax.ValidIdentifier(name) {
+		return hclEscapeString(name)
+	}
+	return name
+}
+
+// hclEscapeString formats the input string into a format that is safe for
+// rendering within HCL.
+//
+// Note, this function doesn't actually do a very good job of this currently. We
+// need to expose some internal functions from HCL in a future version and call
+// them from here. For now, just use "%q" formatting.
+func hclEscapeString(str string) string {
+	// TODO: Replace this with more complete HCL logic instead of the simple
+	// go workaround.
+	return fmt.Sprintf("%q", str)
+}
+
+// writeDiffActionSymbol writes out the symbols for the associated action, and
+// handles localized colorization of the symbol as well as indenting the symbol
+// to be 4 spaces wide.
+//
+// If the opts has HideDiffActionSymbols set then this function returns an empty
+// string.
+func writeDiffActionSymbol(action plans.Action, opts computed.RenderHumanOpts) string {
+	if opts.HideDiffActionSymbols {
+		return ""
+	}
+	return fmt.Sprintf("%s ", opts.Colorize.Color(format.DiffActionSymbol(action)))
+}
diff --git a/v1.5.7/internal/command/jsonformat/diff.go b/v1.5.7/internal/command/jsonformat/diff.go
new file mode 100644
index 0000000..03ba5f9
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/diff.go
@@ -0,0 +1,106 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonformat
+
+import (
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/differ"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path"
+	"github.com/hashicorp/terraform/internal/command/jsonplan"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+func precomputeDiffs(plan Plan, mode plans.Mode) diffs {
+	diffs := diffs{
+		outputs: make(map[string]computed.Diff),
+	}
+
+	for _, drift := range plan.ResourceDrift {
+
+		var relevantAttrs attribute_path.Matcher
+		if mode == plans.RefreshOnlyMode {
+			// For a refresh only plan, we show all the drift.
+			relevantAttrs = attribute_path.AlwaysMatcher()
+		} else {
+			matcher := attribute_path.Empty(true)
+
+			// Otherwise we only want to show the drift changes that are
+			// relevant.
+			for _, attr := range plan.RelevantAttributes {
+				if len(attr.Resource) == 0 || attr.Resource == drift.Address {
+					matcher = attribute_path.AppendSingle(matcher, attr.Attr)
+				}
+			}
+
+			if len(matcher.Paths) > 0 {
+				relevantAttrs = matcher
+			}
+		}
+
+		if relevantAttrs == nil {
+			// If we couldn't build a relevant attribute matcher, then we are
+			// not going to show anything for this drift.
+			continue
+		}
+
+		schema := plan.getSchema(drift)
+		change := structured.FromJsonChange(drift.Change, relevantAttrs)
+		diffs.drift = append(diffs.drift, diff{
+			change: drift,
+			diff:   differ.ComputeDiffForBlock(change, schema.Block),
+		})
+	}
+
+	for _, change := range plan.ResourceChanges {
+		schema := plan.getSchema(change)
+		structuredChange := structured.FromJsonChange(change.Change, attribute_path.AlwaysMatcher())
+		diffs.changes = append(diffs.changes, diff{
+			change: change,
+			diff:   differ.ComputeDiffForBlock(structuredChange, schema.Block),
+		})
+	}
+
+	for key, output := range plan.OutputChanges {
+		change := structured.FromJsonChange(output, attribute_path.AlwaysMatcher())
+		diffs.outputs[key] = differ.ComputeDiffForOutput(change)
+	}
+
+	return diffs
+}
+
+type diffs struct {
+	drift   []diff
+	changes []diff
+	outputs map[string]computed.Diff
+}
+
+func (d diffs) Empty() bool {
+	for _, change := range d.changes {
+		if change.diff.Action != plans.NoOp || change.Moved() {
+			return false
+		}
+	}
+
+	for _, output := range d.outputs {
+		if output.Action != plans.NoOp {
+			return false
+		}
+	}
+
+	return true
+}
+
+type diff struct {
+	change jsonplan.ResourceChange
+	diff   computed.Diff
+}
+
+func (d diff) Moved() bool {
+	return len(d.change.PreviousAddress) > 0 && d.change.PreviousAddress != d.change.Address
+}
+
+func (d diff) Importing() bool {
+	return d.change.Change.Importing != nil
+}
diff --git a/v1.5.7/internal/command/jsonformat/differ/attribute.go b/v1.5.7/internal/command/jsonformat/differ/attribute.go
new file mode 100644
index 0000000..d76ebb8
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/differ/attribute.go
@@ -0,0 +1,87 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package differ
+
+import (
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+)
+
+func ComputeDiffForAttribute(change structured.Change, attribute *jsonprovider.Attribute) computed.Diff {
+	if attribute.AttributeNestedType != nil {
+		return computeDiffForNestedAttribute(change, attribute.AttributeNestedType)
+	}
+	return ComputeDiffForType(change, unmarshalAttribute(attribute))
+}
+
+func computeDiffForNestedAttribute(change structured.Change, nested *jsonprovider.NestedType) computed.Diff {
+	if sensitive, ok := checkForSensitiveNestedAttribute(change, nested); ok {
+		return sensitive
+	}
+
+	if computed, ok := checkForUnknownNestedAttribute(change, nested); ok {
+		return computed
+	}
+
+	switch NestingMode(nested.NestingMode) {
+	case nestingModeSingle, nestingModeGroup:
+		return computeAttributeDiffAsNestedObject(change, nested.Attributes)
+	case nestingModeMap:
+		return computeAttributeDiffAsNestedMap(change, nested.Attributes)
+	case nestingModeList:
+		return computeAttributeDiffAsNestedList(change, nested.Attributes)
+	case nestingModeSet:
+		return computeAttributeDiffAsNestedSet(change, nested.Attributes)
+	default:
+		panic("unrecognized nesting mode: " + nested.NestingMode)
+	}
+}
+
+func ComputeDiffForType(change structured.Change, ctype cty.Type) computed.Diff {
+	if sensitive, ok := checkForSensitiveType(change, ctype); ok {
+		return sensitive
+	}
+
+	if computed, ok := checkForUnknownType(change, ctype); ok {
+		return computed
+	}
+
+	switch {
+	case ctype == cty.NilType, ctype == cty.DynamicPseudoType:
+		// Forward nil or dynamic types over to be processed as outputs.
+		// There is nothing particularly special about the way outputs are
+		// processed that make this unsafe, we could just as easily call this
+		// function computeChangeForDynamicValues(), but external callers will
+		// only be in this situation when processing outputs so this function
+		// is named for their benefit.
+		return ComputeDiffForOutput(change)
+	case ctype.IsPrimitiveType():
+		return computeAttributeDiffAsPrimitive(change, ctype)
+	case ctype.IsObjectType():
+		return computeAttributeDiffAsObject(change, ctype.AttributeTypes())
+	case ctype.IsMapType():
+		return computeAttributeDiffAsMap(change, ctype.ElementType())
+	case ctype.IsListType():
+		return computeAttributeDiffAsList(change, ctype.ElementType())
+	case ctype.IsTupleType():
+		return computeAttributeDiffAsTuple(change, ctype.TupleElementTypes())
+	case ctype.IsSetType():
+		return computeAttributeDiffAsSet(change, ctype.ElementType())
+	default:
+		panic("unrecognized type: " + ctype.FriendlyName())
+	}
+}
+
+func unmarshalAttribute(attribute *jsonprovider.Attribute) cty.Type {
+	ctyType, err := ctyjson.UnmarshalType(attribute.AttributeType)
+	if err != nil {
+		panic("could not unmarshal attribute type: " + err.Error())
+	}
+	return ctyType
+}
diff --git a/v1.5.7/internal/command/jsonformat/differ/block.go b/v1.5.7/internal/command/jsonformat/differ/block.go
new file mode 100644
index 0000000..dd67974
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/differ/block.go
@@ -0,0 +1,121 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package differ
+
+import (
+	"github.com/hashicorp/terraform/internal/command/jsonformat/collections"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+func ComputeDiffForBlock(change structured.Change, block *jsonprovider.Block) computed.Diff {
+	if sensitive, ok := checkForSensitiveBlock(change, block); ok {
+		return sensitive
+	}
+
+	if unknown, ok := checkForUnknownBlock(change, block); ok {
+		return unknown
+	}
+
+	current := change.GetDefaultActionForIteration()
+
+	blockValue := change.AsMap()
+
+	attributes := make(map[string]computed.Diff)
+	for key, attr := range block.Attributes {
+		childValue := blockValue.GetChild(key)
+
+		if !childValue.RelevantAttributes.MatchesPartial() {
+			// Mark non-relevant attributes as unchanged.
+			childValue = childValue.AsNoOp()
+		}
+
+		// Empty strings in blocks should be considered null for legacy reasons.
+		// The SDK doesn't support null strings yet, so we work around this now.
+		if before, ok := childValue.Before.(string); ok && len(before) == 0 {
+			childValue.Before = nil
+		}
+		if after, ok := childValue.After.(string); ok && len(after) == 0 {
+			childValue.After = nil
+		}
+
+		// Always treat changes to blocks as implicit.
+		childValue.BeforeExplicit = false
+		childValue.AfterExplicit = false
+
+		childChange := ComputeDiffForAttribute(childValue, attr)
+		if childChange.Action == plans.NoOp && childValue.Before == nil && childValue.After == nil {
+			// Don't record nil values at all in blocks.
+			continue
+		}
+
+		attributes[key] = childChange
+		current = collections.CompareActions(current, childChange.Action)
+	}
+
+	blocks := renderers.Blocks{
+		ReplaceBlocks:         make(map[string]bool),
+		BeforeSensitiveBlocks: make(map[string]bool),
+		AfterSensitiveBlocks:  make(map[string]bool),
+		SingleBlocks:          make(map[string]computed.Diff),
+		ListBlocks:            make(map[string][]computed.Diff),
+		SetBlocks:             make(map[string][]computed.Diff),
+		MapBlocks:             make(map[string]map[string]computed.Diff),
+	}
+
+	for key, blockType := range block.BlockTypes {
+		childValue := blockValue.GetChild(key)
+
+		if !childValue.RelevantAttributes.MatchesPartial() {
+			// Mark non-relevant attributes as unchanged.
+			childValue = childValue.AsNoOp()
+		}
+
+		beforeSensitive := childValue.IsBeforeSensitive()
+		afterSensitive := childValue.IsAfterSensitive()
+		forcesReplacement := childValue.ReplacePaths.Matches()
+
+		switch NestingMode(blockType.NestingMode) {
+		case nestingModeSet:
+			diffs, action := computeBlockDiffsAsSet(childValue, blockType.Block)
+			if action == plans.NoOp && childValue.Before == nil && childValue.After == nil {
+				// Don't record nil values in blocks.
+				continue
+			}
+			blocks.AddAllSetBlock(key, diffs, forcesReplacement, beforeSensitive, afterSensitive)
+			current = collections.CompareActions(current, action)
+		case nestingModeList:
+			diffs, action := computeBlockDiffsAsList(childValue, blockType.Block)
+			if action == plans.NoOp && childValue.Before == nil && childValue.After == nil {
+				// Don't record nil values in blocks.
+				continue
+			}
+			blocks.AddAllListBlock(key, diffs, forcesReplacement, beforeSensitive, afterSensitive)
+			current = collections.CompareActions(current, action)
+		case nestingModeMap:
+			diffs, action := computeBlockDiffsAsMap(childValue, blockType.Block)
+			if action == plans.NoOp && childValue.Before == nil && childValue.After == nil {
+				// Don't record nil values in blocks.
+				continue
+			}
+			blocks.AddAllMapBlocks(key, diffs, forcesReplacement, beforeSensitive, afterSensitive)
+			current = collections.CompareActions(current, action)
+		case nestingModeSingle, nestingModeGroup:
+			diff := ComputeDiffForBlock(childValue, blockType.Block)
+			if diff.Action == plans.NoOp && childValue.Before == nil && childValue.After == nil {
+				// Don't record nil values in blocks.
+				continue
+			}
+			blocks.AddSingleBlock(key, diff, forcesReplacement, beforeSensitive, afterSensitive)
+			current = collections.CompareActions(current, diff.Action)
+		default:
+			panic("unrecognized nesting mode: " + blockType.NestingMode)
+		}
+	}
+
+	return computed.NewDiff(renderers.Block(attributes, blocks), current, change.ReplacePaths.Matches())
+}
diff --git a/v1.5.7/internal/command/jsonformat/differ/differ.go b/v1.5.7/internal/command/jsonformat/differ/differ.go
new file mode 100644
index 0000000..c0d0af4
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/differ/differ.go
@@ -0,0 +1,15 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package differ
+
+import (
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+)
+
+// asDiff is a helper function to abstract away some simple and common
+// functionality when converting a renderer into a concrete diff.
+func asDiff(change structured.Change, renderer computed.DiffRenderer) computed.Diff {
+	return computed.NewDiff(renderer, change.CalculateAction(), change.ReplacePaths.Matches())
+}
diff --git a/v1.5.7/internal/command/jsonformat/differ/differ_test.go b/v1.5.7/internal/command/jsonformat/differ/differ_test.go
new file mode 100644
index 0000000..611b574
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/differ/differ_test.go
@@ -0,0 +1,2946 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package differ
+
+import (
+	"encoding/json"
+	"fmt"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+type SetDiff struct {
+	Before SetDiffEntry
+	After  SetDiffEntry
+}
+
+type SetDiffEntry struct {
+	SingleDiff renderers.ValidateDiffFunction
+	ObjectDiff map[string]renderers.ValidateDiffFunction
+
+	Replace bool
+	Action  plans.Action
+}
+
+func (entry SetDiffEntry) Validate(obj func(attributes map[string]renderers.ValidateDiffFunction, action plans.Action, replace bool) renderers.ValidateDiffFunction) renderers.ValidateDiffFunction {
+	if entry.SingleDiff != nil {
+		return entry.SingleDiff
+	}
+
+	return obj(entry.ObjectDiff, entry.Action, entry.Replace)
+}
+
+func TestValue_SimpleBlocks(t *testing.T) {
+	// Most of the other test functions wrap the test cases in various
+	// collections or blocks. This function just very simply lets you specify
+	// individual test cases within blocks for some simple tests.
+
+	tcs := map[string]struct {
+		input    structured.Change
+		block    *jsonprovider.Block
+		validate renderers.ValidateDiffFunction
+	}{
+		"delete_with_null_sensitive_value": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"normal_attribute": "some value",
+				},
+				After: nil,
+				BeforeSensitive: map[string]interface{}{
+					"sensitive_attribute": true,
+				},
+				AfterSensitive: false,
+			},
+			block: &jsonprovider.Block{
+				Attributes: map[string]*jsonprovider.Attribute{
+					"normal_attribute": {
+						AttributeType: unmarshalType(t, cty.String),
+					},
+					"sensitive_attribute": {
+						AttributeType: unmarshalType(t, cty.String),
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+				"normal_attribute": renderers.ValidatePrimitive("some value", nil, plans.Delete, false),
+			}, nil, nil, nil, nil, plans.Delete, false),
+		},
+		"create_with_null_sensitive_value": {
+			input: structured.Change{
+				Before: nil,
+				After: map[string]interface{}{
+					"normal_attribute": "some value",
+				},
+				BeforeSensitive: map[string]interface{}{
+					"sensitive_attribute": true,
+				},
+				AfterSensitive: false,
+			},
+			block: &jsonprovider.Block{
+				Attributes: map[string]*jsonprovider.Attribute{
+					"normal_attribute": {
+						AttributeType: unmarshalType(t, cty.String),
+					},
+					"sensitive_attribute": {
+						AttributeType: unmarshalType(t, cty.String),
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+				"normal_attribute": renderers.ValidatePrimitive(nil, "some value", plans.Create, false),
+			}, nil, nil, nil, nil, plans.Create, false),
+		},
+	}
+	for name, tc := range tcs {
+		// Set some default values
+		if tc.input.ReplacePaths == nil {
+			tc.input.ReplacePaths = &attribute_path.PathMatcher{}
+		}
+
+		if tc.input.RelevantAttributes == nil {
+			tc.input.RelevantAttributes = attribute_path.AlwaysMatcher()
+		}
+
+		t.Run(name, func(t *testing.T) {
+			tc.validate(t, ComputeDiffForBlock(tc.input, tc.block))
+		})
+	}
+}
+
+func TestValue_ObjectAttributes(t *testing.T) {
+	// This function holds a range of test cases creating, deleting and editing
+	// objects. It is built in such a way that it can automatically test these
+	// operations on objects both directly and nested, as well as within all
+	// types of collections.
+
+	tcs := map[string]struct {
+		input                structured.Change
+		attributes           map[string]cty.Type
+		validateSingleDiff   renderers.ValidateDiffFunction
+		validateObject       renderers.ValidateDiffFunction
+		validateNestedObject renderers.ValidateDiffFunction
+		validateDiffs        map[string]renderers.ValidateDiffFunction
+		validateList         renderers.ValidateDiffFunction
+		validateReplace      bool
+		validateAction       plans.Action
+		// Sets break changes out differently to the other collections, so they
+		// have their own entry.
+		validateSetDiffs *SetDiff
+	}{
+		"create": {
+			input: structured.Change{
+				Before: nil,
+				After: map[string]interface{}{
+					"attribute_one": "new",
+				},
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateDiffs: map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+			},
+			validateAction:  plans.Create,
+			validateReplace: false,
+		},
+		"delete": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"attribute_one": "old",
+				},
+				After: nil,
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateDiffs: map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+			},
+			validateAction:  plans.Delete,
+			validateReplace: false,
+		},
+		"create_sensitive": {
+			input: structured.Change{
+				Before: nil,
+				After: map[string]interface{}{
+					"attribute_one": "new",
+				},
+				AfterSensitive: true,
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateSingleDiff: renderers.ValidateSensitive(renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+			}, plans.Create, false),
+				false,
+				true,
+				plans.Create,
+				false),
+			validateNestedObject: renderers.ValidateSensitive(renderers.ValidateNestedObject(map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+			}, plans.Create, false),
+				false,
+				true,
+				plans.Create,
+				false),
+		},
+		"delete_sensitive": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"attribute_one": "old",
+				},
+				BeforeSensitive: true,
+				After:           nil,
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateSingleDiff: renderers.ValidateSensitive(renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+			}, plans.Delete, false), true, false, plans.Delete, false),
+			validateNestedObject: renderers.ValidateSensitive(renderers.ValidateNestedObject(map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+			}, plans.Delete, false), true, false, plans.Delete, false),
+		},
+		"create_unknown": {
+			input: structured.Change{
+				Before:  nil,
+				After:   nil,
+				Unknown: true,
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateSingleDiff: renderers.ValidateUnknown(nil, plans.Create, false),
+		},
+		"update_unknown": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"attribute_one": "old",
+				},
+				After:   nil,
+				Unknown: true,
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateObject: renderers.ValidateUnknown(renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+			}, plans.Delete, false), plans.Update, false),
+			validateNestedObject: renderers.ValidateUnknown(renderers.ValidateNestedObject(map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidateUnknown(renderers.ValidatePrimitive("old", nil, plans.Delete, false), plans.Update, false),
+			}, plans.Update, false), plans.Update, false),
+			validateSetDiffs: &SetDiff{
+				Before: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+					},
+					Action:  plans.Delete,
+					Replace: false,
+				},
+				After: SetDiffEntry{
+					SingleDiff: renderers.ValidateUnknown(nil, plans.Create, false),
+				},
+			},
+		},
+		"create_attribute": {
+			input: structured.Change{
+				Before: map[string]interface{}{},
+				After: map[string]interface{}{
+					"attribute_one": "new",
+				},
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateDiffs: map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+			},
+			validateAction:  plans.Update,
+			validateReplace: false,
+			validateSetDiffs: &SetDiff{
+				Before: SetDiffEntry{
+					ObjectDiff: nil,
+					Action:     plans.Delete,
+					Replace:    false,
+				},
+				After: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+					},
+					Action:  plans.Create,
+					Replace: false,
+				},
+			},
+		},
+		"create_attribute_from_explicit_null": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"attribute_one": nil,
+				},
+				After: map[string]interface{}{
+					"attribute_one": "new",
+				},
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateDiffs: map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+			},
+			validateAction:  plans.Update,
+			validateReplace: false,
+			validateSetDiffs: &SetDiff{
+				Before: SetDiffEntry{
+					ObjectDiff: nil,
+					Action:     plans.Delete,
+					Replace:    false,
+				},
+				After: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+					},
+					Action:  plans.Create,
+					Replace: false,
+				},
+			},
+		},
+		"delete_attribute": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"attribute_one": "old",
+				},
+				After: map[string]interface{}{},
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateDiffs: map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+			},
+			validateAction:  plans.Update,
+			validateReplace: false,
+			validateSetDiffs: &SetDiff{
+				Before: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+					},
+					Action:  plans.Delete,
+					Replace: false,
+				},
+				After: SetDiffEntry{
+					ObjectDiff: nil,
+					Action:     plans.Create,
+					Replace:    false,
+				},
+			},
+		},
+		"delete_attribute_to_explicit_null": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"attribute_one": "old",
+				},
+				After: map[string]interface{}{
+					"attribute_one": nil,
+				},
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateDiffs: map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+			},
+			validateAction:  plans.Update,
+			validateReplace: false,
+			validateSetDiffs: &SetDiff{
+				Before: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+					},
+					Action:  plans.Delete,
+					Replace: false,
+				},
+				After: SetDiffEntry{
+					ObjectDiff: nil,
+					Action:     plans.Create,
+					Replace:    false,
+				},
+			},
+		},
+		"update_attribute": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"attribute_one": "old",
+				},
+				After: map[string]interface{}{
+					"attribute_one": "new",
+				},
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateDiffs: map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive("old", "new", plans.Update, false),
+			},
+			validateAction:  plans.Update,
+			validateReplace: false,
+			validateSetDiffs: &SetDiff{
+				Before: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+					},
+					Action:  plans.Delete,
+					Replace: false,
+				},
+				After: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+					},
+					Action:  plans.Create,
+					Replace: false,
+				},
+			},
+		},
+		"create_sensitive_attribute": {
+			input: structured.Change{
+				Before: map[string]interface{}{},
+				After: map[string]interface{}{
+					"attribute_one": "new",
+				},
+				AfterSensitive: map[string]interface{}{
+					"attribute_one": true,
+				},
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateDiffs: map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidateSensitive(renderers.ValidatePrimitive(nil, "new", plans.Create, false), false, true, plans.Create, false),
+			},
+			validateAction:  plans.Update,
+			validateReplace: false,
+			validateSetDiffs: &SetDiff{
+				Before: SetDiffEntry{
+					ObjectDiff: nil,
+					Action:     plans.Delete,
+					Replace:    false,
+				},
+				After: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidateSensitive(renderers.ValidatePrimitive(nil, "new", plans.Create, false), false, true, plans.Create, false),
+					},
+					Action:  plans.Create,
+					Replace: false,
+				},
+			},
+		},
+		"delete_sensitive_attribute": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"attribute_one": "old",
+				},
+				BeforeSensitive: map[string]interface{}{
+					"attribute_one": true,
+				},
+				After: map[string]interface{}{},
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateDiffs: map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidateSensitive(renderers.ValidatePrimitive("old", nil, plans.Delete, false), true, false, plans.Delete, false),
+			},
+			validateAction:  plans.Update,
+			validateReplace: false,
+			validateSetDiffs: &SetDiff{
+				Before: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidateSensitive(renderers.ValidatePrimitive("old", nil, plans.Delete, false), true, false, plans.Delete, false),
+					},
+					Action:  plans.Delete,
+					Replace: false,
+				},
+				After: SetDiffEntry{
+					ObjectDiff: nil,
+					Action:     plans.Create,
+					Replace:    false,
+				},
+			},
+		},
+		"update_sensitive_attribute": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"attribute_one": "old",
+				},
+				BeforeSensitive: map[string]interface{}{
+					"attribute_one": true,
+				},
+				After: map[string]interface{}{
+					"attribute_one": "new",
+				},
+				AfterSensitive: map[string]interface{}{
+					"attribute_one": true,
+				},
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateDiffs: map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidateSensitive(renderers.ValidatePrimitive("old", "new", plans.Update, false), true, true, plans.Update, false),
+			},
+			validateAction:  plans.Update,
+			validateReplace: false,
+			validateSetDiffs: &SetDiff{
+				Before: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidateSensitive(renderers.ValidatePrimitive("old", nil, plans.Delete, false), true, false, plans.Delete, false),
+					},
+					Action:  plans.Delete,
+					Replace: false,
+				},
+				After: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidateSensitive(renderers.ValidatePrimitive(nil, "new", plans.Create, false), false, true, plans.Create, false),
+					},
+					Action:  plans.Create,
+					Replace: false,
+				},
+			},
+		},
+		"create_computed_attribute": {
+			input: structured.Change{
+				Before: map[string]interface{}{},
+				After:  map[string]interface{}{},
+				Unknown: map[string]interface{}{
+					"attribute_one": true,
+				},
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateDiffs: map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidateUnknown(nil, plans.Create, false),
+			},
+			validateAction:  plans.Update,
+			validateReplace: false,
+		},
+		"update_computed_attribute": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"attribute_one": "old",
+				},
+				After: map[string]interface{}{},
+				Unknown: map[string]interface{}{
+					"attribute_one": true,
+				},
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateDiffs: map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidateUnknown(
+					renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+					plans.Update,
+					false),
+			},
+			validateAction:  plans.Update,
+			validateReplace: false,
+			validateSetDiffs: &SetDiff{
+				Before: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+					},
+					Action:  plans.Delete,
+					Replace: false,
+				},
+				After: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidateUnknown(nil, plans.Create, false),
+					},
+					Action:  plans.Create,
+					Replace: false,
+				},
+			},
+		},
+		"ignores_unset_fields": {
+			input: structured.Change{
+				Before: map[string]interface{}{},
+				After:  map[string]interface{}{},
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateDiffs:   map[string]renderers.ValidateDiffFunction{},
+			validateAction:  plans.NoOp,
+			validateReplace: false,
+		},
+		"update_replace_self": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"attribute_one": "old",
+				},
+				After: map[string]interface{}{
+					"attribute_one": "new",
+				},
+				ReplacePaths: &attribute_path.PathMatcher{
+					Paths: [][]interface{}{
+						{},
+					},
+				},
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateDiffs: map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive("old", "new", plans.Update, false),
+			},
+			validateAction:  plans.Update,
+			validateReplace: true,
+			validateSetDiffs: &SetDiff{
+				Before: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+					},
+					Action:  plans.Delete,
+					Replace: true,
+				},
+				After: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+					},
+					Action:  plans.Create,
+					Replace: true,
+				},
+			},
+		},
+		"update_replace_attribute": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"attribute_one": "old",
+				},
+				After: map[string]interface{}{
+					"attribute_one": "new",
+				},
+				ReplacePaths: &attribute_path.PathMatcher{
+					Paths: [][]interface{}{
+						{"attribute_one"},
+					},
+				},
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+			},
+			validateDiffs: map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive("old", "new", plans.Update, true),
+			},
+			validateAction:  plans.Update,
+			validateReplace: false,
+			validateSetDiffs: &SetDiff{
+				Before: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, true),
+					},
+					Action:  plans.Delete,
+					Replace: false,
+				},
+				After: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, true),
+					},
+					Action:  plans.Create,
+					Replace: false,
+				},
+			},
+		},
+		"update_includes_relevant_attributes": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"attribute_one": "old_one",
+					"attribute_two": "old_two",
+				},
+				After: map[string]interface{}{
+					"attribute_one": "new_one",
+					"attribute_two": "new_two",
+				},
+				RelevantAttributes: &attribute_path.PathMatcher{
+					Paths: [][]interface{}{
+						{"attribute_one"},
+					},
+				},
+			},
+			attributes: map[string]cty.Type{
+				"attribute_one": cty.String,
+				"attribute_two": cty.String,
+			},
+			validateDiffs: map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive("old_one", "new_one", plans.Update, false),
+				"attribute_two": renderers.ValidatePrimitive("old_two", "old_two", plans.NoOp, false),
+			},
+			validateList: renderers.ValidateList([]renderers.ValidateDiffFunction{
+				renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+					// Lists are a bit special, and in this case is actually
+					// going to ignore the relevant attributes. This is
+					// deliberate. See the comments in list.go for an
+					// explanation.
+					"attribute_one": renderers.ValidatePrimitive("old_one", "new_one", plans.Update, false),
+					"attribute_two": renderers.ValidatePrimitive("old_two", "new_two", plans.Update, false),
+				}, plans.Update, false),
+			}, plans.Update, false),
+			validateAction:  plans.Update,
+			validateReplace: false,
+			validateSetDiffs: &SetDiff{
+				Before: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive("old_one", nil, plans.Delete, false),
+						"attribute_two": renderers.ValidatePrimitive("old_two", nil, plans.Delete, false),
+					},
+					Action:  plans.Delete,
+					Replace: false,
+				},
+				After: SetDiffEntry{
+					ObjectDiff: map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive(nil, "new_one", plans.Create, false),
+						"attribute_two": renderers.ValidatePrimitive(nil, "new_two", plans.Create, false),
+					},
+					Action:  plans.Create,
+					Replace: false,
+				},
+			},
+		},
+	}
+
+	for name, tmp := range tcs {
+		tc := tmp
+
+		// Let's set some default values on the input.
+		if tc.input.RelevantAttributes == nil {
+			tc.input.RelevantAttributes = attribute_path.AlwaysMatcher()
+		}
+		if tc.input.ReplacePaths == nil {
+			tc.input.ReplacePaths = &attribute_path.PathMatcher{}
+		}
+
+		collectionDefaultAction := plans.Update
+		if name == "ignores_unset_fields" {
+			// Special case for this test, as it is the only one that doesn't
+			// have the collection types return an update.
+			collectionDefaultAction = plans.NoOp
+		}
+
+		t.Run(name, func(t *testing.T) {
+			t.Run("object", func(t *testing.T) {
+				attribute := &jsonprovider.Attribute{
+					AttributeType: unmarshalType(t, cty.Object(tc.attributes)),
+				}
+
+				if tc.validateObject != nil {
+					tc.validateObject(t, ComputeDiffForAttribute(tc.input, attribute))
+					return
+				}
+
+				if tc.validateSingleDiff != nil {
+					tc.validateSingleDiff(t, ComputeDiffForAttribute(tc.input, attribute))
+					return
+				}
+
+				validate := renderers.ValidateObject(tc.validateDiffs, tc.validateAction, tc.validateReplace)
+				validate(t, ComputeDiffForAttribute(tc.input, attribute))
+			})
+
+			t.Run("map", func(t *testing.T) {
+				attribute := &jsonprovider.Attribute{
+					AttributeType: unmarshalType(t, cty.Map(cty.Object(tc.attributes))),
+				}
+
+				input := wrapChangeInMap(tc.input)
+
+				if tc.validateObject != nil {
+					validate := renderers.ValidateMap(map[string]renderers.ValidateDiffFunction{
+						"element": tc.validateObject,
+					}, collectionDefaultAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				if tc.validateSingleDiff != nil {
+					validate := renderers.ValidateMap(map[string]renderers.ValidateDiffFunction{
+						"element": tc.validateSingleDiff,
+					}, collectionDefaultAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				validate := renderers.ValidateMap(map[string]renderers.ValidateDiffFunction{
+					"element": renderers.ValidateObject(tc.validateDiffs, tc.validateAction, tc.validateReplace),
+				}, collectionDefaultAction, false)
+				validate(t, ComputeDiffForAttribute(input, attribute))
+			})
+
+			t.Run("list", func(t *testing.T) {
+				attribute := &jsonprovider.Attribute{
+					AttributeType: unmarshalType(t, cty.List(cty.Object(tc.attributes))),
+				}
+
+				input := wrapChangeInSlice(tc.input)
+
+				if tc.validateList != nil {
+					tc.validateList(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				if tc.validateObject != nil {
+					validate := renderers.ValidateList([]renderers.ValidateDiffFunction{
+						tc.validateObject,
+					}, collectionDefaultAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				if tc.validateSingleDiff != nil {
+					validate := renderers.ValidateList([]renderers.ValidateDiffFunction{
+						tc.validateSingleDiff,
+					}, collectionDefaultAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				validate := renderers.ValidateList([]renderers.ValidateDiffFunction{
+					renderers.ValidateObject(tc.validateDiffs, tc.validateAction, tc.validateReplace),
+				}, collectionDefaultAction, false)
+				validate(t, ComputeDiffForAttribute(input, attribute))
+			})
+
+			t.Run("set", func(t *testing.T) {
+				attribute := &jsonprovider.Attribute{
+					AttributeType: unmarshalType(t, cty.Set(cty.Object(tc.attributes))),
+				}
+
+				input := wrapChangeInSlice(tc.input)
+
+				if tc.validateSetDiffs != nil {
+					validate := renderers.ValidateSet(func() []renderers.ValidateDiffFunction {
+						var ret []renderers.ValidateDiffFunction
+						ret = append(ret, tc.validateSetDiffs.Before.Validate(renderers.ValidateObject))
+						ret = append(ret, tc.validateSetDiffs.After.Validate(renderers.ValidateObject))
+						return ret
+					}(), collectionDefaultAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				if tc.validateObject != nil {
+					validate := renderers.ValidateSet([]renderers.ValidateDiffFunction{
+						tc.validateObject,
+					}, collectionDefaultAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				if tc.validateSingleDiff != nil {
+					validate := renderers.ValidateSet([]renderers.ValidateDiffFunction{
+						tc.validateSingleDiff,
+					}, collectionDefaultAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				validate := renderers.ValidateSet([]renderers.ValidateDiffFunction{
+					renderers.ValidateObject(tc.validateDiffs, tc.validateAction, tc.validateReplace),
+				}, collectionDefaultAction, false)
+				validate(t, ComputeDiffForAttribute(input, attribute))
+			})
+		})
+
+		t.Run(fmt.Sprintf("nested_%s", name), func(t *testing.T) {
+			t.Run("object", func(t *testing.T) {
+				attribute := &jsonprovider.Attribute{
+					AttributeNestedType: &jsonprovider.NestedType{
+						Attributes: func() map[string]*jsonprovider.Attribute {
+							attributes := make(map[string]*jsonprovider.Attribute)
+							for key, attribute := range tc.attributes {
+								attributes[key] = &jsonprovider.Attribute{
+									AttributeType: unmarshalType(t, attribute),
+								}
+							}
+							return attributes
+						}(),
+						NestingMode: "single",
+					},
+				}
+
+				if tc.validateNestedObject != nil {
+					tc.validateNestedObject(t, ComputeDiffForAttribute(tc.input, attribute))
+					return
+				}
+
+				if tc.validateSingleDiff != nil {
+					tc.validateSingleDiff(t, ComputeDiffForAttribute(tc.input, attribute))
+					return
+				}
+
+				validate := renderers.ValidateNestedObject(tc.validateDiffs, tc.validateAction, tc.validateReplace)
+				validate(t, ComputeDiffForAttribute(tc.input, attribute))
+			})
+
+			t.Run("map", func(t *testing.T) {
+				attribute := &jsonprovider.Attribute{
+					AttributeNestedType: &jsonprovider.NestedType{
+						Attributes: func() map[string]*jsonprovider.Attribute {
+							attributes := make(map[string]*jsonprovider.Attribute)
+							for key, attribute := range tc.attributes {
+								attributes[key] = &jsonprovider.Attribute{
+									AttributeType: unmarshalType(t, attribute),
+								}
+							}
+							return attributes
+						}(),
+						NestingMode: "map",
+					},
+				}
+
+				input := wrapChangeInMap(tc.input)
+
+				if tc.validateNestedObject != nil {
+					validate := renderers.ValidateMap(map[string]renderers.ValidateDiffFunction{
+						"element": tc.validateNestedObject,
+					}, collectionDefaultAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				if tc.validateSingleDiff != nil {
+					validate := renderers.ValidateMap(map[string]renderers.ValidateDiffFunction{
+						"element": tc.validateSingleDiff,
+					}, collectionDefaultAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				validate := renderers.ValidateMap(map[string]renderers.ValidateDiffFunction{
+					"element": renderers.ValidateNestedObject(tc.validateDiffs, tc.validateAction, tc.validateReplace),
+				}, collectionDefaultAction, false)
+				validate(t, ComputeDiffForAttribute(input, attribute))
+			})
+
+			t.Run("list", func(t *testing.T) {
+				attribute := &jsonprovider.Attribute{
+					AttributeNestedType: &jsonprovider.NestedType{
+						Attributes: func() map[string]*jsonprovider.Attribute {
+							attributes := make(map[string]*jsonprovider.Attribute)
+							for key, attribute := range tc.attributes {
+								attributes[key] = &jsonprovider.Attribute{
+									AttributeType: unmarshalType(t, attribute),
+								}
+							}
+							return attributes
+						}(),
+						NestingMode: "list",
+					},
+				}
+
+				input := wrapChangeInSlice(tc.input)
+
+				if tc.validateNestedObject != nil {
+					validate := renderers.ValidateNestedList([]renderers.ValidateDiffFunction{
+						tc.validateNestedObject,
+					}, collectionDefaultAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				if tc.validateSingleDiff != nil {
+					validate := renderers.ValidateNestedList([]renderers.ValidateDiffFunction{
+						tc.validateSingleDiff,
+					}, collectionDefaultAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				validate := renderers.ValidateNestedList([]renderers.ValidateDiffFunction{
+					renderers.ValidateNestedObject(tc.validateDiffs, tc.validateAction, tc.validateReplace),
+				}, collectionDefaultAction, false)
+				validate(t, ComputeDiffForAttribute(input, attribute))
+			})
+
+			t.Run("set", func(t *testing.T) {
+				attribute := &jsonprovider.Attribute{
+					AttributeNestedType: &jsonprovider.NestedType{
+						Attributes: func() map[string]*jsonprovider.Attribute {
+							attributes := make(map[string]*jsonprovider.Attribute)
+							for key, attribute := range tc.attributes {
+								attributes[key] = &jsonprovider.Attribute{
+									AttributeType: unmarshalType(t, attribute),
+								}
+							}
+							return attributes
+						}(),
+						NestingMode: "set",
+					},
+				}
+
+				input := wrapChangeInSlice(tc.input)
+
+				if tc.validateSetDiffs != nil {
+					validate := renderers.ValidateSet(func() []renderers.ValidateDiffFunction {
+						var ret []renderers.ValidateDiffFunction
+						ret = append(ret, tc.validateSetDiffs.Before.Validate(renderers.ValidateNestedObject))
+						ret = append(ret, tc.validateSetDiffs.After.Validate(renderers.ValidateNestedObject))
+						return ret
+					}(), collectionDefaultAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				if tc.validateNestedObject != nil {
+					validate := renderers.ValidateSet([]renderers.ValidateDiffFunction{
+						tc.validateNestedObject,
+					}, collectionDefaultAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				if tc.validateSingleDiff != nil {
+					validate := renderers.ValidateSet([]renderers.ValidateDiffFunction{
+						tc.validateSingleDiff,
+					}, collectionDefaultAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				validate := renderers.ValidateSet([]renderers.ValidateDiffFunction{
+					renderers.ValidateNestedObject(tc.validateDiffs, tc.validateAction, tc.validateReplace),
+				}, collectionDefaultAction, false)
+				validate(t, ComputeDiffForAttribute(input, attribute))
+			})
+		})
+	}
+}
+
+func TestValue_BlockAttributesAndNestedBlocks(t *testing.T) {
+	// This function tests manipulating simple attributes and blocks within
+	// blocks. It automatically tests these operations within the contexts of
+	// different block types.
+
+	tcs := map[string]struct {
+		before      interface{}
+		after       interface{}
+		block       *jsonprovider.Block
+		validate    renderers.ValidateDiffFunction
+		validateSet []renderers.ValidateDiffFunction
+	}{
+		"create_attribute": {
+			before: map[string]interface{}{},
+			after: map[string]interface{}{
+				"attribute_one": "new",
+			},
+			block: &jsonprovider.Block{
+				Attributes: map[string]*jsonprovider.Attribute{
+					"attribute_one": {
+						AttributeType: unmarshalType(t, cty.String),
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+			}, nil, nil, nil, nil, plans.Update, false),
+			validateSet: []renderers.ValidateDiffFunction{
+				renderers.ValidateBlock(nil, nil, nil, nil, nil, plans.Delete, false),
+				renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+					"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+				}, nil, nil, nil, nil, plans.Create, false),
+			},
+		},
+		"update_attribute": {
+			before: map[string]interface{}{
+				"attribute_one": "old",
+			},
+			after: map[string]interface{}{
+				"attribute_one": "new",
+			},
+			block: &jsonprovider.Block{
+				Attributes: map[string]*jsonprovider.Attribute{
+					"attribute_one": {
+						AttributeType: unmarshalType(t, cty.String),
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive("old", "new", plans.Update, false),
+			}, nil, nil, nil, nil, plans.Update, false),
+			validateSet: []renderers.ValidateDiffFunction{
+				renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+					"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+				}, nil, nil, nil, nil, plans.Delete, false),
+				renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+					"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+				}, nil, nil, nil, nil, plans.Create, false),
+			},
+		},
+		"delete_attribute": {
+			before: map[string]interface{}{
+				"attribute_one": "old",
+			},
+			after: map[string]interface{}{},
+			block: &jsonprovider.Block{
+				Attributes: map[string]*jsonprovider.Attribute{
+					"attribute_one": {
+						AttributeType: unmarshalType(t, cty.String),
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+				"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+			}, nil, nil, nil, nil, plans.Update, false),
+			validateSet: []renderers.ValidateDiffFunction{
+				renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+					"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+				}, nil, nil, nil, nil, plans.Delete, false),
+				renderers.ValidateBlock(nil, nil, nil, nil, nil, plans.Create, false),
+			},
+		},
+		"create_block": {
+			before: map[string]interface{}{},
+			after: map[string]interface{}{
+				"block_one": map[string]interface{}{
+					"attribute_one": "new",
+				},
+			},
+			block: &jsonprovider.Block{
+				BlockTypes: map[string]*jsonprovider.BlockType{
+					"block_one": {
+						Block: &jsonprovider.Block{
+							Attributes: map[string]*jsonprovider.Attribute{
+								"attribute_one": {
+									AttributeType: unmarshalType(t, cty.String),
+								},
+							},
+						},
+						NestingMode: "single",
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(nil, map[string]renderers.ValidateDiffFunction{
+				"block_one": renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+					"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+				}, nil, nil, nil, nil, plans.Create, false),
+			}, nil, nil, nil, plans.Update, false),
+			validateSet: []renderers.ValidateDiffFunction{
+				renderers.ValidateBlock(nil, nil, nil, nil, nil, plans.Delete, false),
+				renderers.ValidateBlock(nil, map[string]renderers.ValidateDiffFunction{
+					"block_one": renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+					}, nil, nil, nil, nil, plans.Create, false),
+				}, nil, nil, nil, plans.Create, false),
+			},
+		},
+		"update_block": {
+			before: map[string]interface{}{
+				"block_one": map[string]interface{}{
+					"attribute_one": "old",
+				},
+			},
+			after: map[string]interface{}{
+				"block_one": map[string]interface{}{
+					"attribute_one": "new",
+				},
+			},
+			block: &jsonprovider.Block{
+				BlockTypes: map[string]*jsonprovider.BlockType{
+					"block_one": {
+						Block: &jsonprovider.Block{
+							Attributes: map[string]*jsonprovider.Attribute{
+								"attribute_one": {
+									AttributeType: unmarshalType(t, cty.String),
+								},
+							},
+						},
+						NestingMode: "single",
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(nil, map[string]renderers.ValidateDiffFunction{
+				"block_one": renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+					"attribute_one": renderers.ValidatePrimitive("old", "new", plans.Update, false),
+				}, nil, nil, nil, nil, plans.Update, false),
+			}, nil, nil, nil, plans.Update, false),
+			validateSet: []renderers.ValidateDiffFunction{
+				renderers.ValidateBlock(nil, map[string]renderers.ValidateDiffFunction{
+					"block_one": renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+					}, nil, nil, nil, nil, plans.Delete, false),
+				}, nil, nil, nil, plans.Delete, false),
+				renderers.ValidateBlock(nil, map[string]renderers.ValidateDiffFunction{
+					"block_one": renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+					}, nil, nil, nil, nil, plans.Create, false),
+				}, nil, nil, nil, plans.Create, false),
+			},
+		},
+		"delete_block": {
+			before: map[string]interface{}{
+				"block_one": map[string]interface{}{
+					"attribute_one": "old",
+				},
+			},
+			after: map[string]interface{}{},
+			block: &jsonprovider.Block{
+				BlockTypes: map[string]*jsonprovider.BlockType{
+					"block_one": {
+						Block: &jsonprovider.Block{
+							Attributes: map[string]*jsonprovider.Attribute{
+								"attribute_one": {
+									AttributeType: unmarshalType(t, cty.String),
+								},
+							},
+						},
+						NestingMode: "single",
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(nil, map[string]renderers.ValidateDiffFunction{
+				"block_one": renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+					"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+				}, nil, nil, nil, nil, plans.Delete, false),
+			}, nil, nil, nil, plans.Update, false),
+			validateSet: []renderers.ValidateDiffFunction{
+				renderers.ValidateBlock(nil, map[string]renderers.ValidateDiffFunction{
+					"block_one": renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+						"attribute_one": renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+					}, nil, nil, nil, nil, plans.Delete, false),
+				}, nil, nil, nil, plans.Delete, false),
+				renderers.ValidateBlock(nil, nil, nil, nil, nil, plans.Create, false),
+			},
+		},
+	}
+	for name, tmp := range tcs {
+		tc := tmp
+
+		t.Run(name, func(t *testing.T) {
+			t.Run("single", func(t *testing.T) {
+				input := structured.Change{
+					Before: map[string]interface{}{
+						"block_type": tc.before,
+					},
+					After: map[string]interface{}{
+						"block_type": tc.after,
+					},
+					ReplacePaths:       &attribute_path.PathMatcher{},
+					RelevantAttributes: attribute_path.AlwaysMatcher(),
+				}
+
+				block := &jsonprovider.Block{
+					BlockTypes: map[string]*jsonprovider.BlockType{
+						"block_type": {
+							Block:       tc.block,
+							NestingMode: "single",
+						},
+					},
+				}
+
+				validate := renderers.ValidateBlock(nil, map[string]renderers.ValidateDiffFunction{
+					"block_type": tc.validate,
+				}, nil, nil, nil, plans.Update, false)
+				validate(t, ComputeDiffForBlock(input, block))
+			})
+			t.Run("map", func(t *testing.T) {
+				input := structured.Change{
+					Before: map[string]interface{}{
+						"block_type": map[string]interface{}{
+							"one": tc.before,
+						},
+					},
+					After: map[string]interface{}{
+						"block_type": map[string]interface{}{
+							"one": tc.after,
+						},
+					},
+					ReplacePaths:       &attribute_path.PathMatcher{},
+					RelevantAttributes: attribute_path.AlwaysMatcher(),
+				}
+
+				block := &jsonprovider.Block{
+					BlockTypes: map[string]*jsonprovider.BlockType{
+						"block_type": {
+							Block:       tc.block,
+							NestingMode: "map",
+						},
+					},
+				}
+
+				validate := renderers.ValidateBlock(nil, nil, nil, map[string]map[string]renderers.ValidateDiffFunction{
+					"block_type": {
+						"one": tc.validate,
+					},
+				}, nil, plans.Update, false)
+				validate(t, ComputeDiffForBlock(input, block))
+			})
+			t.Run("list", func(t *testing.T) {
+				input := structured.Change{
+					Before: map[string]interface{}{
+						"block_type": []interface{}{
+							tc.before,
+						},
+					},
+					After: map[string]interface{}{
+						"block_type": []interface{}{
+							tc.after,
+						},
+					},
+					ReplacePaths:       &attribute_path.PathMatcher{},
+					RelevantAttributes: attribute_path.AlwaysMatcher(),
+				}
+
+				block := &jsonprovider.Block{
+					BlockTypes: map[string]*jsonprovider.BlockType{
+						"block_type": {
+							Block:       tc.block,
+							NestingMode: "list",
+						},
+					},
+				}
+
+				validate := renderers.ValidateBlock(nil, nil, map[string][]renderers.ValidateDiffFunction{
+					"block_type": {
+						tc.validate,
+					},
+				}, nil, nil, plans.Update, false)
+				validate(t, ComputeDiffForBlock(input, block))
+			})
+			t.Run("set", func(t *testing.T) {
+				input := structured.Change{
+					Before: map[string]interface{}{
+						"block_type": []interface{}{
+							tc.before,
+						},
+					},
+					After: map[string]interface{}{
+						"block_type": []interface{}{
+							tc.after,
+						},
+					},
+					ReplacePaths:       &attribute_path.PathMatcher{},
+					RelevantAttributes: attribute_path.AlwaysMatcher(),
+				}
+
+				block := &jsonprovider.Block{
+					BlockTypes: map[string]*jsonprovider.BlockType{
+						"block_type": {
+							Block:       tc.block,
+							NestingMode: "set",
+						},
+					},
+				}
+
+				validate := renderers.ValidateBlock(nil, nil, nil, nil, map[string][]renderers.ValidateDiffFunction{
+					"block_type": func() []renderers.ValidateDiffFunction {
+						if tc.validateSet != nil {
+							return tc.validateSet
+						}
+						return []renderers.ValidateDiffFunction{tc.validate}
+					}(),
+				}, plans.Update, false)
+				validate(t, ComputeDiffForBlock(input, block))
+			})
+		})
+	}
+}
+
+func TestValue_Outputs(t *testing.T) {
+	tcs := map[string]struct {
+		input        structured.Change
+		validateDiff renderers.ValidateDiffFunction
+	}{
+		"primitive_create": {
+			input: structured.Change{
+				Before: nil,
+				After:  "new",
+			},
+			validateDiff: renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+		},
+		"object_create": {
+			input: structured.Change{
+				Before: nil,
+				After: map[string]interface{}{
+					"element_one": "new_one",
+					"element_two": "new_two",
+				},
+			},
+			validateDiff: renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+				"element_one": renderers.ValidatePrimitive(nil, "new_one", plans.Create, false),
+				"element_two": renderers.ValidatePrimitive(nil, "new_two", plans.Create, false),
+			}, plans.Create, false),
+		},
+		"list_create": {
+			input: structured.Change{
+				Before: nil,
+				After: []interface{}{
+					"new_one",
+					"new_two",
+				},
+			},
+			validateDiff: renderers.ValidateList([]renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive(nil, "new_one", plans.Create, false),
+				renderers.ValidatePrimitive(nil, "new_two", plans.Create, false),
+			}, plans.Create, false),
+		},
+		"primitive_update": {
+			input: structured.Change{
+				Before: "old",
+				After:  "new",
+			},
+			validateDiff: renderers.ValidatePrimitive("old", "new", plans.Update, false),
+		},
+		"object_update": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"element_one": "old_one",
+					"element_two": "old_two",
+				},
+				After: map[string]interface{}{
+					"element_one": "new_one",
+					"element_two": "new_two",
+				},
+			},
+			validateDiff: renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+				"element_one": renderers.ValidatePrimitive("old_one", "new_one", plans.Update, false),
+				"element_two": renderers.ValidatePrimitive("old_two", "new_two", plans.Update, false),
+			}, plans.Update, false),
+		},
+		"list_update": {
+			input: structured.Change{
+				Before: []interface{}{
+					"old_one",
+					"old_two",
+				},
+				After: []interface{}{
+					"new_one",
+					"new_two",
+				},
+			},
+			validateDiff: renderers.ValidateList([]renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive("old_one", nil, plans.Delete, false),
+				renderers.ValidatePrimitive("old_two", nil, plans.Delete, false),
+				renderers.ValidatePrimitive(nil, "new_one", plans.Create, false),
+				renderers.ValidatePrimitive(nil, "new_two", plans.Create, false),
+			}, plans.Update, false),
+		},
+		"primitive_delete": {
+			input: structured.Change{
+				Before: "old",
+				After:  nil,
+			},
+			validateDiff: renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+		},
+		"object_delete": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"element_one": "old_one",
+					"element_two": "old_two",
+				},
+				After: nil,
+			},
+			validateDiff: renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+				"element_one": renderers.ValidatePrimitive("old_one", nil, plans.Delete, false),
+				"element_two": renderers.ValidatePrimitive("old_two", nil, plans.Delete, false),
+			}, plans.Delete, false),
+		},
+		"list_delete": {
+			input: structured.Change{
+				Before: []interface{}{
+					"old_one",
+					"old_two",
+				},
+				After: nil,
+			},
+			validateDiff: renderers.ValidateList([]renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive("old_one", nil, plans.Delete, false),
+				renderers.ValidatePrimitive("old_two", nil, plans.Delete, false),
+			}, plans.Delete, false),
+		},
+		"primitive_to_list": {
+			input: structured.Change{
+				Before: "old",
+				After: []interface{}{
+					"new_one",
+					"new_two",
+				},
+			},
+			validateDiff: renderers.ValidateTypeChange(
+				renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+				renderers.ValidateList([]renderers.ValidateDiffFunction{
+					renderers.ValidatePrimitive(nil, "new_one", plans.Create, false),
+					renderers.ValidatePrimitive(nil, "new_two", plans.Create, false),
+				}, plans.Create, false), plans.Update, false),
+		},
+		"primitive_to_object": {
+			input: structured.Change{
+				Before: "old",
+				After: map[string]interface{}{
+					"element_one": "new_one",
+					"element_two": "new_two",
+				},
+			},
+			validateDiff: renderers.ValidateTypeChange(
+				renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+				renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+					"element_one": renderers.ValidatePrimitive(nil, "new_one", plans.Create, false),
+					"element_two": renderers.ValidatePrimitive(nil, "new_two", plans.Create, false),
+				}, plans.Create, false), plans.Update, false),
+		},
+		"list_to_primitive": {
+			input: structured.Change{
+				Before: []interface{}{
+					"old_one",
+					"old_two",
+				},
+				After: "new",
+			},
+			validateDiff: renderers.ValidateTypeChange(
+				renderers.ValidateList([]renderers.ValidateDiffFunction{
+					renderers.ValidatePrimitive("old_one", nil, plans.Delete, false),
+					renderers.ValidatePrimitive("old_two", nil, plans.Delete, false),
+				}, plans.Delete, false),
+				renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+				plans.Update, false),
+		},
+		"list_to_object": {
+			input: structured.Change{
+				Before: []interface{}{
+					"old_one",
+					"old_two",
+				},
+				After: map[string]interface{}{
+					"element_one": "new_one",
+					"element_two": "new_two",
+				},
+			},
+			validateDiff: renderers.ValidateTypeChange(
+				renderers.ValidateList([]renderers.ValidateDiffFunction{
+					renderers.ValidatePrimitive("old_one", nil, plans.Delete, false),
+					renderers.ValidatePrimitive("old_two", nil, plans.Delete, false),
+				}, plans.Delete, false),
+				renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+					"element_one": renderers.ValidatePrimitive(nil, "new_one", plans.Create, false),
+					"element_two": renderers.ValidatePrimitive(nil, "new_two", plans.Create, false),
+				}, plans.Create, false), plans.Update, false),
+		},
+		"object_to_primitive": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"element_one": "old_one",
+					"element_two": "old_two",
+				},
+				After: "new",
+			},
+			validateDiff: renderers.ValidateTypeChange(
+				renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+					"element_one": renderers.ValidatePrimitive("old_one", nil, plans.Delete, false),
+					"element_two": renderers.ValidatePrimitive("old_two", nil, plans.Delete, false),
+				}, plans.Delete, false),
+				renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+				plans.Update, false),
+		},
+		"object_to_list": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"element_one": "old_one",
+					"element_two": "old_two",
+				},
+				After: []interface{}{
+					"new_one",
+					"new_two",
+				},
+			},
+			validateDiff: renderers.ValidateTypeChange(
+				renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+					"element_one": renderers.ValidatePrimitive("old_one", nil, plans.Delete, false),
+					"element_two": renderers.ValidatePrimitive("old_two", nil, plans.Delete, false),
+				}, plans.Delete, false),
+				renderers.ValidateList([]renderers.ValidateDiffFunction{
+					renderers.ValidatePrimitive(nil, "new_one", plans.Create, false),
+					renderers.ValidatePrimitive(nil, "new_two", plans.Create, false),
+				}, plans.Create, false), plans.Update, false),
+		},
+	}
+
+	for name, tc := range tcs {
+
+		// Let's set some default values on the input.
+		if tc.input.RelevantAttributes == nil {
+			tc.input.RelevantAttributes = attribute_path.AlwaysMatcher()
+		}
+		if tc.input.ReplacePaths == nil {
+			tc.input.ReplacePaths = &attribute_path.PathMatcher{}
+		}
+
+		t.Run(name, func(t *testing.T) {
+			tc.validateDiff(t, ComputeDiffForOutput(tc.input))
+		})
+	}
+}
+
+func TestValue_PrimitiveAttributes(t *testing.T) {
+	// This function tests manipulating primitives: creating, deleting and
+	// updating. It also automatically tests these operations within the
+	// contexts of collections.
+
+	tcs := map[string]struct {
+		input              structured.Change
+		attribute          cty.Type
+		validateDiff       renderers.ValidateDiffFunction
+		validateSliceDiffs []renderers.ValidateDiffFunction // Lists are special in some cases.
+	}{
+		"primitive_create": {
+			input: structured.Change{
+				After: "new",
+			},
+			attribute:    cty.String,
+			validateDiff: renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+		},
+		"primitive_delete": {
+			input: structured.Change{
+				Before: "old",
+			},
+			attribute:    cty.String,
+			validateDiff: renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+		},
+		"primitive_update": {
+			input: structured.Change{
+				Before: "old",
+				After:  "new",
+			},
+			attribute:    cty.String,
+			validateDiff: renderers.ValidatePrimitive("old", "new", plans.Update, false),
+			validateSliceDiffs: []renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+				renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+			},
+		},
+		"primitive_set_explicit_null": {
+			input: structured.Change{
+				Before:        "old",
+				After:         nil,
+				AfterExplicit: true,
+			},
+			attribute:    cty.String,
+			validateDiff: renderers.ValidatePrimitive("old", nil, plans.Update, false),
+			validateSliceDiffs: []renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+				renderers.ValidatePrimitive(nil, nil, plans.Create, false),
+			},
+		},
+		"primitive_unset_explicit_null": {
+			input: structured.Change{
+				BeforeExplicit: true,
+				Before:         nil,
+				After:          "new",
+			},
+			attribute:    cty.String,
+			validateDiff: renderers.ValidatePrimitive(nil, "new", plans.Update, false),
+			validateSliceDiffs: []renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive(nil, nil, plans.Delete, false),
+				renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+			},
+		},
+		"primitive_create_sensitive": {
+			input: structured.Change{
+				Before:         nil,
+				After:          "new",
+				AfterSensitive: true,
+			},
+			attribute:    cty.String,
+			validateDiff: renderers.ValidateSensitive(renderers.ValidatePrimitive(nil, "new", plans.Create, false), false, true, plans.Create, false),
+		},
+		"primitive_delete_sensitive": {
+			input: structured.Change{
+				Before:          "old",
+				BeforeSensitive: true,
+				After:           nil,
+			},
+			attribute:    cty.String,
+			validateDiff: renderers.ValidateSensitive(renderers.ValidatePrimitive("old", nil, plans.Delete, false), true, false, plans.Delete, false),
+		},
+		"primitive_update_sensitive": {
+			input: structured.Change{
+				Before:          "old",
+				BeforeSensitive: true,
+				After:           "new",
+				AfterSensitive:  true,
+			},
+			attribute:    cty.String,
+			validateDiff: renderers.ValidateSensitive(renderers.ValidatePrimitive("old", "new", plans.Update, false), true, true, plans.Update, false),
+			validateSliceDiffs: []renderers.ValidateDiffFunction{
+				renderers.ValidateSensitive(renderers.ValidatePrimitive("old", nil, plans.Delete, false), true, false, plans.Delete, false),
+				renderers.ValidateSensitive(renderers.ValidatePrimitive(nil, "new", plans.Create, false), false, true, plans.Create, false),
+			},
+		},
+		"primitive_create_computed": {
+			input: structured.Change{
+				Before:  nil,
+				After:   nil,
+				Unknown: true,
+			},
+			attribute:    cty.String,
+			validateDiff: renderers.ValidateUnknown(nil, plans.Create, false),
+		},
+		"primitive_update_computed": {
+			input: structured.Change{
+				Before:  "old",
+				After:   nil,
+				Unknown: true,
+			},
+			attribute:    cty.String,
+			validateDiff: renderers.ValidateUnknown(renderers.ValidatePrimitive("old", nil, plans.Delete, false), plans.Update, false),
+			validateSliceDiffs: []renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+				renderers.ValidateUnknown(nil, plans.Create, false),
+			},
+		},
+		"primitive_update_replace": {
+			input: structured.Change{
+				Before: "old",
+				After:  "new",
+				ReplacePaths: &attribute_path.PathMatcher{
+					Paths: [][]interface{}{
+						{}, // An empty path suggests replace should be true.
+					},
+				},
+			},
+			attribute:    cty.String,
+			validateDiff: renderers.ValidatePrimitive("old", "new", plans.Update, true),
+			validateSliceDiffs: []renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive("old", nil, plans.Delete, true),
+				renderers.ValidatePrimitive(nil, "new", plans.Create, true),
+			},
+		},
+		"noop": {
+			input: structured.Change{
+				Before: "old",
+				After:  "old",
+			},
+			attribute:    cty.String,
+			validateDiff: renderers.ValidatePrimitive("old", "old", plans.NoOp, false),
+		},
+		"dynamic": {
+			input: structured.Change{
+				Before: "old",
+				After:  "new",
+			},
+			attribute:    cty.DynamicPseudoType,
+			validateDiff: renderers.ValidatePrimitive("old", "new", plans.Update, false),
+			validateSliceDiffs: []renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+				renderers.ValidatePrimitive(nil, "new", plans.Create, false),
+			},
+		},
+		"dynamic_type_change": {
+			input: structured.Change{
+				Before: "old",
+				After:  4.0,
+			},
+			attribute: cty.DynamicPseudoType,
+			validateDiff: renderers.ValidateTypeChange(
+				renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+				renderers.ValidatePrimitive(nil, 4.0, plans.Create, false),
+				plans.Update, false),
+			validateSliceDiffs: []renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive("old", nil, plans.Delete, false),
+				renderers.ValidatePrimitive(nil, 4.0, plans.Create, false),
+			},
+		},
+	}
+	for name, tmp := range tcs {
+		tc := tmp
+
+		// Let's set some default values on the input.
+		if tc.input.RelevantAttributes == nil {
+			tc.input.RelevantAttributes = attribute_path.AlwaysMatcher()
+		}
+		if tc.input.ReplacePaths == nil {
+			tc.input.ReplacePaths = &attribute_path.PathMatcher{}
+		}
+
+		defaultCollectionsAction := plans.Update
+		if name == "noop" {
+			defaultCollectionsAction = plans.NoOp
+		}
+
+		t.Run(name, func(t *testing.T) {
+			t.Run("direct", func(t *testing.T) {
+				tc.validateDiff(t, ComputeDiffForAttribute(tc.input, &jsonprovider.Attribute{
+					AttributeType: unmarshalType(t, tc.attribute),
+				}))
+			})
+
+			t.Run("map", func(t *testing.T) {
+				input := wrapChangeInMap(tc.input)
+				attribute := &jsonprovider.Attribute{
+					AttributeType: unmarshalType(t, cty.Map(tc.attribute)),
+				}
+
+				validate := renderers.ValidateMap(map[string]renderers.ValidateDiffFunction{
+					"element": tc.validateDiff,
+				}, defaultCollectionsAction, false)
+				validate(t, ComputeDiffForAttribute(input, attribute))
+			})
+
+			t.Run("list", func(t *testing.T) {
+				input := wrapChangeInSlice(tc.input)
+				attribute := &jsonprovider.Attribute{
+					AttributeType: unmarshalType(t, cty.List(tc.attribute)),
+				}
+
+				if tc.validateSliceDiffs != nil {
+					validate := renderers.ValidateList(tc.validateSliceDiffs, defaultCollectionsAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				validate := renderers.ValidateList([]renderers.ValidateDiffFunction{
+					tc.validateDiff,
+				}, defaultCollectionsAction, false)
+				validate(t, ComputeDiffForAttribute(input, attribute))
+			})
+
+			t.Run("set", func(t *testing.T) {
+				input := wrapChangeInSlice(tc.input)
+				attribute := &jsonprovider.Attribute{
+					AttributeType: unmarshalType(t, cty.Set(tc.attribute)),
+				}
+
+				if tc.validateSliceDiffs != nil {
+					validate := renderers.ValidateSet(tc.validateSliceDiffs, defaultCollectionsAction, false)
+					validate(t, ComputeDiffForAttribute(input, attribute))
+					return
+				}
+
+				validate := renderers.ValidateSet([]renderers.ValidateDiffFunction{
+					tc.validateDiff,
+				}, defaultCollectionsAction, false)
+				validate(t, ComputeDiffForAttribute(input, attribute))
+			})
+		})
+	}
+}
+
+func TestValue_CollectionAttributes(t *testing.T) {
+	// This function tests creating and deleting collections. Note, it does not
+	// generally cover editing collections except in special cases as editing
+	// collections is handled automatically by other functions.
+	tcs := map[string]struct {
+		input        structured.Change
+		attribute    *jsonprovider.Attribute
+		validateDiff renderers.ValidateDiffFunction
+	}{
+		"map_create_empty": {
+			input: structured.Change{
+				Before: nil,
+				After:  map[string]interface{}{},
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Map(cty.String)),
+			},
+			validateDiff: renderers.ValidateMap(nil, plans.Create, false),
+		},
+		"map_create_populated": {
+			input: structured.Change{
+				Before: nil,
+				After: map[string]interface{}{
+					"element_one": "one",
+					"element_two": "two",
+				},
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Map(cty.String)),
+			},
+			validateDiff: renderers.ValidateMap(map[string]renderers.ValidateDiffFunction{
+				"element_one": renderers.ValidatePrimitive(nil, "one", plans.Create, false),
+				"element_two": renderers.ValidatePrimitive(nil, "two", plans.Create, false),
+			}, plans.Create, false),
+		},
+		"map_delete_empty": {
+			input: structured.Change{
+				Before: map[string]interface{}{},
+				After:  nil,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Map(cty.String)),
+			},
+			validateDiff: renderers.ValidateMap(nil, plans.Delete, false),
+		},
+		"map_delete_populated": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"element_one": "one",
+					"element_two": "two",
+				},
+				After: nil,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Map(cty.String)),
+			},
+			validateDiff: renderers.ValidateMap(map[string]renderers.ValidateDiffFunction{
+				"element_one": renderers.ValidatePrimitive("one", nil, plans.Delete, false),
+				"element_two": renderers.ValidatePrimitive("two", nil, plans.Delete, false),
+			}, plans.Delete, false),
+		},
+		"map_create_sensitive": {
+			input: structured.Change{
+				Before:         nil,
+				After:          map[string]interface{}{},
+				AfterSensitive: true,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Map(cty.String)),
+			},
+			validateDiff: renderers.ValidateSensitive(renderers.ValidateMap(nil, plans.Create, false), false, true, plans.Create, false),
+		},
+		"map_update_sensitive": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"element": "one",
+				},
+				BeforeSensitive: true,
+				After:           map[string]interface{}{},
+				AfterSensitive:  true,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Map(cty.String)),
+			},
+			validateDiff: renderers.ValidateSensitive(renderers.ValidateMap(map[string]renderers.ValidateDiffFunction{
+				"element": renderers.ValidatePrimitive("one", nil, plans.Delete, false),
+			}, plans.Update, false), true, true, plans.Update, false),
+		},
+		"map_delete_sensitive": {
+			input: structured.Change{
+				Before:          map[string]interface{}{},
+				BeforeSensitive: true,
+				After:           nil,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Map(cty.String)),
+			},
+			validateDiff: renderers.ValidateSensitive(renderers.ValidateMap(nil, plans.Delete, false), true, false, plans.Delete, false),
+		},
+		"map_create_unknown": {
+			input: structured.Change{
+				Before:  nil,
+				After:   map[string]interface{}{},
+				Unknown: true,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Map(cty.String)),
+			},
+			validateDiff: renderers.ValidateUnknown(nil, plans.Create, false),
+		},
+		"map_update_unknown": {
+			input: structured.Change{
+				Before: map[string]interface{}{},
+				After: map[string]interface{}{
+					"element": "one",
+				},
+				Unknown: true,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Map(cty.String)),
+			},
+			validateDiff: renderers.ValidateUnknown(renderers.ValidateMap(nil, plans.Delete, false), plans.Update, false),
+		},
+		"list_create_empty": {
+			input: structured.Change{
+				Before: nil,
+				After:  []interface{}{},
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.List(cty.String)),
+			},
+			validateDiff: renderers.ValidateList(nil, plans.Create, false),
+		},
+		"list_create_populated": {
+			input: structured.Change{
+				Before: nil,
+				After:  []interface{}{"one", "two"},
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.List(cty.String)),
+			},
+			validateDiff: renderers.ValidateList([]renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive(nil, "one", plans.Create, false),
+				renderers.ValidatePrimitive(nil, "two", plans.Create, false),
+			}, plans.Create, false),
+		},
+		"list_delete_empty": {
+			input: structured.Change{
+				Before: []interface{}{},
+				After:  nil,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.List(cty.String)),
+			},
+			validateDiff: renderers.ValidateList(nil, plans.Delete, false),
+		},
+		"list_delete_populated": {
+			input: structured.Change{
+				Before: []interface{}{"one", "two"},
+				After:  nil,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.List(cty.String)),
+			},
+			validateDiff: renderers.ValidateList([]renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive("one", nil, plans.Delete, false),
+				renderers.ValidatePrimitive("two", nil, plans.Delete, false),
+			}, plans.Delete, false),
+		},
+		"list_create_sensitive": {
+			input: structured.Change{
+				Before:         nil,
+				After:          []interface{}{},
+				AfterSensitive: true,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.List(cty.String)),
+			},
+			validateDiff: renderers.ValidateSensitive(renderers.ValidateList(nil, plans.Create, false), false, true, plans.Create, false),
+		},
+		"list_update_sensitive": {
+			input: structured.Change{
+				Before:          []interface{}{"one"},
+				BeforeSensitive: true,
+				After:           []interface{}{},
+				AfterSensitive:  true,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.List(cty.String)),
+			},
+			validateDiff: renderers.ValidateSensitive(renderers.ValidateList([]renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive("one", nil, plans.Delete, false),
+			}, plans.Update, false), true, true, plans.Update, false),
+		},
+		"list_delete_sensitive": {
+			input: structured.Change{
+				Before:          []interface{}{},
+				BeforeSensitive: true,
+				After:           nil,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.List(cty.String)),
+			},
+			validateDiff: renderers.ValidateSensitive(renderers.ValidateList(nil, plans.Delete, false), true, false, plans.Delete, false),
+		},
+		"list_create_unknown": {
+			input: structured.Change{
+				Before:  nil,
+				After:   []interface{}{},
+				Unknown: true,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.List(cty.String)),
+			},
+			validateDiff: renderers.ValidateUnknown(nil, plans.Create, false),
+		},
+		"list_update_unknown": {
+			input: structured.Change{
+				Before:  []interface{}{},
+				After:   []interface{}{"one"},
+				Unknown: true,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.List(cty.String)),
+			},
+			validateDiff: renderers.ValidateUnknown(renderers.ValidateList(nil, plans.Delete, false), plans.Update, false),
+		},
+		"set_create_empty": {
+			input: structured.Change{
+				Before: nil,
+				After:  []interface{}{},
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Set(cty.String)),
+			},
+			validateDiff: renderers.ValidateSet(nil, plans.Create, false),
+		},
+		"set_create_populated": {
+			input: structured.Change{
+				Before: nil,
+				After:  []interface{}{"one", "two"},
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Set(cty.String)),
+			},
+			validateDiff: renderers.ValidateSet([]renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive(nil, "one", plans.Create, false),
+				renderers.ValidatePrimitive(nil, "two", plans.Create, false),
+			}, plans.Create, false),
+		},
+		"set_delete_empty": {
+			input: structured.Change{
+				Before: []interface{}{},
+				After:  nil,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Set(cty.String)),
+			},
+			validateDiff: renderers.ValidateSet(nil, plans.Delete, false),
+		},
+		"set_delete_populated": {
+			input: structured.Change{
+				Before: []interface{}{"one", "two"},
+				After:  nil,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Set(cty.String)),
+			},
+			validateDiff: renderers.ValidateSet([]renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive("one", nil, plans.Delete, false),
+				renderers.ValidatePrimitive("two", nil, plans.Delete, false),
+			}, plans.Delete, false),
+		},
+		"set_create_sensitive": {
+			input: structured.Change{
+				Before:         nil,
+				After:          []interface{}{},
+				AfterSensitive: true,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Set(cty.String)),
+			},
+			validateDiff: renderers.ValidateSensitive(renderers.ValidateSet(nil, plans.Create, false), false, true, plans.Create, false),
+		},
+		"set_update_sensitive": {
+			input: structured.Change{
+				Before:          []interface{}{"one"},
+				BeforeSensitive: true,
+				After:           []interface{}{},
+				AfterSensitive:  true,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Set(cty.String)),
+			},
+			validateDiff: renderers.ValidateSensitive(renderers.ValidateSet([]renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive("one", nil, plans.Delete, false),
+			}, plans.Update, false), true, true, plans.Update, false),
+		},
+		"set_delete_sensitive": {
+			input: structured.Change{
+				Before:          []interface{}{},
+				BeforeSensitive: true,
+				After:           nil,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Set(cty.String)),
+			},
+			validateDiff: renderers.ValidateSensitive(renderers.ValidateSet(nil, plans.Delete, false), true, false, plans.Delete, false),
+		},
+		"set_create_unknown": {
+			input: structured.Change{
+				Before:  nil,
+				After:   []interface{}{},
+				Unknown: true,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Set(cty.String)),
+			},
+			validateDiff: renderers.ValidateUnknown(nil, plans.Create, false),
+		},
+		"set_update_unknown": {
+			input: structured.Change{
+				Before:  []interface{}{},
+				After:   []interface{}{"one"},
+				Unknown: true,
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Set(cty.String)),
+			},
+			validateDiff: renderers.ValidateUnknown(renderers.ValidateSet(nil, plans.Delete, false), plans.Update, false),
+		},
+		"tuple_primitive": {
+			input: structured.Change{
+				Before: []interface{}{
+					"one",
+					2.0,
+					"three",
+				},
+				After: []interface{}{
+					"one",
+					4.0,
+					"three",
+				},
+			},
+			attribute: &jsonprovider.Attribute{
+				AttributeType: unmarshalType(t, cty.Tuple([]cty.Type{cty.String, cty.Number, cty.String})),
+			},
+			validateDiff: renderers.ValidateList([]renderers.ValidateDiffFunction{
+				renderers.ValidatePrimitive("one", "one", plans.NoOp, false),
+				renderers.ValidatePrimitive(2.0, 4.0, plans.Update, false),
+				renderers.ValidatePrimitive("three", "three", plans.NoOp, false),
+			}, plans.Update, false),
+		},
+	}
+
+	for name, tc := range tcs {
+
+		// Let's set some default values on the input.
+		if tc.input.RelevantAttributes == nil {
+			tc.input.RelevantAttributes = attribute_path.AlwaysMatcher()
+		}
+		if tc.input.ReplacePaths == nil {
+			tc.input.ReplacePaths = &attribute_path.PathMatcher{}
+		}
+
+		t.Run(name, func(t *testing.T) {
+			tc.validateDiff(t, ComputeDiffForAttribute(tc.input, tc.attribute))
+		})
+	}
+}
+
+func TestRelevantAttributes(t *testing.T) {
+	tcs := map[string]struct {
+		input    structured.Change
+		block    *jsonprovider.Block
+		validate renderers.ValidateDiffFunction
+	}{
+		"simple_attributes": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"id":     "old_id",
+					"ignore": "doesn't matter",
+				},
+				After: map[string]interface{}{
+					"id":     "new_id",
+					"ignore": "doesn't matter but modified",
+				},
+				RelevantAttributes: &attribute_path.PathMatcher{
+					Paths: [][]interface{}{
+						{
+							"id",
+						},
+					},
+				},
+			},
+			block: &jsonprovider.Block{
+				Attributes: map[string]*jsonprovider.Attribute{
+					"id": {
+						AttributeType: unmarshalType(t, cty.String),
+					},
+					"ignore": {
+						AttributeType: unmarshalType(t, cty.String),
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+				"id":     renderers.ValidatePrimitive("old_id", "new_id", plans.Update, false),
+				"ignore": renderers.ValidatePrimitive("doesn't matter", "doesn't matter", plans.NoOp, false),
+			}, nil, nil, nil, nil, plans.Update, false),
+		},
+		"nested_attributes": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"list_block": []interface{}{
+						map[string]interface{}{
+							"id": "old_one",
+						},
+						map[string]interface{}{
+							"id": "ignored",
+						},
+					},
+				},
+				After: map[string]interface{}{
+					"list_block": []interface{}{
+						map[string]interface{}{
+							"id": "new_one",
+						},
+						map[string]interface{}{
+							"id": "ignored_but_changed",
+						},
+					},
+				},
+				RelevantAttributes: &attribute_path.PathMatcher{
+					Paths: [][]interface{}{
+						{
+							"list_block",
+							float64(0),
+							"id",
+						},
+					},
+				},
+			},
+			block: &jsonprovider.Block{
+				BlockTypes: map[string]*jsonprovider.BlockType{
+					"list_block": {
+						Block: &jsonprovider.Block{
+							Attributes: map[string]*jsonprovider.Attribute{
+								"id": {
+									AttributeType: unmarshalType(t, cty.String),
+								},
+							},
+						},
+						NestingMode: "list",
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(nil, nil, map[string][]renderers.ValidateDiffFunction{
+				"list_block": {
+					renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+						"id": renderers.ValidatePrimitive("old_one", "new_one", plans.Update, false),
+					}, nil, nil, nil, nil, plans.Update, false),
+					renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+						"id": renderers.ValidatePrimitive("ignored", "ignored", plans.NoOp, false),
+					}, nil, nil, nil, nil, plans.NoOp, false),
+				},
+			}, nil, nil, plans.Update, false),
+		},
+		"nested_attributes_in_object": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"object": map[string]interface{}{
+						"id": "old_id",
+					},
+				},
+				After: map[string]interface{}{
+					"object": map[string]interface{}{
+						"id": "new_id",
+					},
+				},
+				RelevantAttributes: &attribute_path.PathMatcher{
+					Propagate: true,
+					Paths: [][]interface{}{
+						{
+							"object", // Even though we just specify object, it should now include every below object as well.
+						},
+					},
+				},
+			},
+			block: &jsonprovider.Block{
+				Attributes: map[string]*jsonprovider.Attribute{
+					"object": {
+						AttributeType: unmarshalType(t, cty.Object(map[string]cty.Type{
+							"id": cty.String,
+						})),
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+				"object": renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+					"id": renderers.ValidatePrimitive("old_id", "new_id", plans.Update, false),
+				}, plans.Update, false),
+			}, nil, nil, nil, nil, plans.Update, false),
+		},
+		"elements_in_list": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"list": []interface{}{
+						0, 1, 2, 3, 4,
+					},
+				},
+				After: map[string]interface{}{
+					"list": []interface{}{
+						0, 5, 6, 7, 4,
+					},
+				},
+				RelevantAttributes: &attribute_path.PathMatcher{
+					Paths: [][]interface{}{ // The list is actually just going to ignore this.
+						{
+							"list",
+							float64(0),
+						},
+						{
+							"list",
+							float64(2),
+						},
+						{
+							"list",
+							float64(4),
+						},
+					},
+				},
+			},
+			block: &jsonprovider.Block{
+				Attributes: map[string]*jsonprovider.Attribute{
+					"list": {
+						AttributeType: unmarshalType(t, cty.List(cty.Number)),
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+				// The list validator below just ignores our relevant
+				// attributes. This is deliberate.
+				"list": renderers.ValidateList([]renderers.ValidateDiffFunction{
+					renderers.ValidatePrimitive(0, 0, plans.NoOp, false),
+					renderers.ValidatePrimitive(1, nil, plans.Delete, false),
+					renderers.ValidatePrimitive(2, nil, plans.Delete, false),
+					renderers.ValidatePrimitive(3, nil, plans.Delete, false),
+					renderers.ValidatePrimitive(nil, 5, plans.Create, false),
+					renderers.ValidatePrimitive(nil, 6, plans.Create, false),
+					renderers.ValidatePrimitive(nil, 7, plans.Create, false),
+					renderers.ValidatePrimitive(4, 4, plans.NoOp, false),
+				}, plans.Update, false),
+			}, nil, nil, nil, nil, plans.Update, false),
+		},
+		"elements_in_map": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"map": map[string]interface{}{
+						"key_one":   "value_one",
+						"key_two":   "value_two",
+						"key_three": "value_three",
+					},
+				},
+				After: map[string]interface{}{
+					"map": map[string]interface{}{
+						"key_one":  "value_three",
+						"key_two":  "value_seven",
+						"key_four": "value_four",
+					},
+				},
+				RelevantAttributes: &attribute_path.PathMatcher{
+					Paths: [][]interface{}{
+						{
+							"map",
+							"key_one",
+						},
+						{
+							"map",
+							"key_three",
+						},
+						{
+							"map",
+							"key_four",
+						},
+					},
+				},
+			},
+			block: &jsonprovider.Block{
+				Attributes: map[string]*jsonprovider.Attribute{
+					"map": {
+						AttributeType: unmarshalType(t, cty.Map(cty.String)),
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+				"map": renderers.ValidateMap(map[string]renderers.ValidateDiffFunction{
+					"key_one":   renderers.ValidatePrimitive("value_one", "value_three", plans.Update, false),
+					"key_two":   renderers.ValidatePrimitive("value_two", "value_two", plans.NoOp, false),
+					"key_three": renderers.ValidatePrimitive("value_three", nil, plans.Delete, false),
+					"key_four":  renderers.ValidatePrimitive(nil, "value_four", plans.Create, false),
+				}, plans.Update, false),
+			}, nil, nil, nil, nil, plans.Update, false),
+		},
+		"elements_in_set": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"set": []interface{}{
+						0, 1, 2, 3, 4,
+					},
+				},
+				After: map[string]interface{}{
+					"set": []interface{}{
+						0, 2, 4, 5, 6,
+					},
+				},
+				RelevantAttributes: &attribute_path.PathMatcher{
+					Propagate: true,
+					Paths: [][]interface{}{
+						{
+							"set",
+						},
+					},
+				},
+			},
+			block: &jsonprovider.Block{
+				Attributes: map[string]*jsonprovider.Attribute{
+					"set": {
+						AttributeType: unmarshalType(t, cty.Set(cty.Number)),
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+				"set": renderers.ValidateSet([]renderers.ValidateDiffFunction{
+					renderers.ValidatePrimitive(0, 0, plans.NoOp, false),
+					renderers.ValidatePrimitive(1, nil, plans.Delete, false),
+					renderers.ValidatePrimitive(2, 2, plans.NoOp, false),
+					renderers.ValidatePrimitive(3, nil, plans.Delete, false),
+					renderers.ValidatePrimitive(4, 4, plans.NoOp, false),
+					renderers.ValidatePrimitive(nil, 5, plans.Create, false),
+					renderers.ValidatePrimitive(nil, 6, plans.Create, false),
+				}, plans.Update, false),
+			}, nil, nil, nil, nil, plans.Update, false),
+		},
+		"dynamic_types": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"dynamic_nested_type": map[string]interface{}{
+						"nested_id": "nomatch",
+						"nested_object": map[string]interface{}{
+							"nested_nested_id": "matched",
+						},
+					},
+					"dynamic_nested_type_match": map[string]interface{}{
+						"nested_id": "allmatch",
+						"nested_object": map[string]interface{}{
+							"nested_nested_id": "allmatch",
+						},
+					},
+				},
+				After: map[string]interface{}{
+					"dynamic_nested_type": map[string]interface{}{
+						"nested_id": "nomatch_changed",
+						"nested_object": map[string]interface{}{
+							"nested_nested_id": "matched",
+						},
+					},
+					"dynamic_nested_type_match": map[string]interface{}{
+						"nested_id": "allmatch",
+						"nested_object": map[string]interface{}{
+							"nested_nested_id": "allmatch",
+						},
+					},
+				},
+				RelevantAttributes: &attribute_path.PathMatcher{
+					Propagate: true,
+					Paths: [][]interface{}{
+						{
+							"dynamic_nested_type",
+							"nested_object",
+							"nested_nested_id",
+						},
+						{
+							"dynamic_nested_type_match",
+						},
+					},
+				},
+			},
+			block: &jsonprovider.Block{
+				Attributes: map[string]*jsonprovider.Attribute{
+					"dynamic_nested_type": {
+						AttributeType: unmarshalType(t, cty.DynamicPseudoType),
+					},
+					"dynamic_nested_type_match": {
+						AttributeType: unmarshalType(t, cty.DynamicPseudoType),
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+				"dynamic_nested_type": renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+					"nested_id": renderers.ValidatePrimitive("nomatch", "nomatch", plans.NoOp, false),
+					"nested_object": renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+						"nested_nested_id": renderers.ValidatePrimitive("matched", "matched", plans.NoOp, false),
+					}, plans.NoOp, false),
+				}, plans.NoOp, false),
+				"dynamic_nested_type_match": renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+					"nested_id": renderers.ValidatePrimitive("allmatch", "allmatch", plans.NoOp, false),
+					"nested_object": renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+						"nested_nested_id": renderers.ValidatePrimitive("allmatch", "allmatch", plans.NoOp, false),
+					}, plans.NoOp, false),
+				}, plans.NoOp, false),
+			}, nil, nil, nil, nil, plans.NoOp, false),
+		},
+	}
+	for name, tc := range tcs {
+		if tc.input.ReplacePaths == nil {
+			tc.input.ReplacePaths = &attribute_path.PathMatcher{}
+		}
+		t.Run(name, func(t *testing.T) {
+			tc.validate(t, ComputeDiffForBlock(tc.input, tc.block))
+		})
+	}
+}
+
+func TestDynamicPseudoType(t *testing.T) {
+	tcs := map[string]struct {
+		input    structured.Change
+		validate renderers.ValidateDiffFunction
+	}{
+		"after_sensitive_in_dynamic_type": {
+			input: structured.Change{
+				Before: nil,
+				After: map[string]interface{}{
+					"key": "value",
+				},
+				Unknown:         false,
+				BeforeSensitive: false,
+				AfterSensitive: map[string]interface{}{
+					"key": true,
+				},
+				ReplacePaths:       attribute_path.Empty(false),
+				RelevantAttributes: attribute_path.AlwaysMatcher(),
+			},
+			validate: renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+				"key": renderers.ValidateSensitive(renderers.ValidatePrimitive(nil, "value", plans.Create, false), false, true, plans.Create, false),
+			}, plans.Create, false),
+		},
+		"before_sensitive_in_dynamic_type": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"key": "value",
+				},
+				After:   nil,
+				Unknown: false,
+				BeforeSensitive: map[string]interface{}{
+					"key": true,
+				},
+				AfterSensitive:     false,
+				ReplacePaths:       attribute_path.Empty(false),
+				RelevantAttributes: attribute_path.AlwaysMatcher(),
+			},
+			validate: renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+				"key": renderers.ValidateSensitive(renderers.ValidatePrimitive("value", nil, plans.Delete, false), true, false, plans.Delete, false),
+			}, plans.Delete, false),
+		},
+		"sensitive_in_dynamic_type": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"key": "before",
+				},
+				After: map[string]interface{}{
+					"key": "after",
+				},
+				Unknown: false,
+				BeforeSensitive: map[string]interface{}{
+					"key": true,
+				},
+				AfterSensitive: map[string]interface{}{
+					"key": true,
+				},
+				ReplacePaths:       attribute_path.Empty(false),
+				RelevantAttributes: attribute_path.AlwaysMatcher(),
+			},
+			validate: renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+				"key": renderers.ValidateSensitive(renderers.ValidatePrimitive("before", "after", plans.Update, false), true, true, plans.Update, false),
+			}, plans.Update, false),
+		},
+		"create_unknown_in_dynamic_type": {
+			input: structured.Change{
+				Before: nil,
+				After:  map[string]interface{}{},
+				Unknown: map[string]interface{}{
+					"key": true,
+				},
+				BeforeSensitive:    false,
+				AfterSensitive:     false,
+				ReplacePaths:       attribute_path.Empty(false),
+				RelevantAttributes: attribute_path.AlwaysMatcher(),
+			},
+			validate: renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+				"key": renderers.ValidateUnknown(nil, plans.Create, false),
+			}, plans.Create, false),
+		},
+		"update_unknown_in_dynamic_type": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"key": "before",
+				},
+				After: map[string]interface{}{},
+				Unknown: map[string]interface{}{
+					"key": true,
+				},
+				BeforeSensitive:    false,
+				AfterSensitive:     false,
+				ReplacePaths:       attribute_path.Empty(false),
+				RelevantAttributes: attribute_path.AlwaysMatcher(),
+			},
+			validate: renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+				"key": renderers.ValidateUnknown(renderers.ValidatePrimitive("before", nil, plans.Delete, false), plans.Update, false),
+			}, plans.Update, false),
+		},
+	}
+	for key, tc := range tcs {
+		t.Run(key, func(t *testing.T) {
+			tc.validate(t, ComputeDiffForType(tc.input, cty.DynamicPseudoType))
+		})
+	}
+}
+
+func TestSpecificCases(t *testing.T) {
+	// This is a special test that can contain any combination of individual
+	// cases and will execute against them. For testing/fixing specific issues
+	// you can generally put the test case in here.
+	tcs := map[string]struct {
+		input    structured.Change
+		block    *jsonprovider.Block
+		validate renderers.ValidateDiffFunction
+	}{
+		"issues/33016/unknown": {
+			input: structured.Change{
+				Before: nil,
+				After: map[string]interface{}{
+					"triggers": map[string]interface{}{},
+				},
+				Unknown: map[string]interface{}{
+					"id": true,
+					"triggers": map[string]interface{}{
+						"rotation": true,
+					},
+				},
+				BeforeSensitive: false,
+				AfterSensitive: map[string]interface{}{
+					"triggers": map[string]interface{}{},
+				},
+				ReplacePaths:       attribute_path.Empty(false),
+				RelevantAttributes: attribute_path.AlwaysMatcher(),
+			},
+			block: &jsonprovider.Block{
+				Attributes: map[string]*jsonprovider.Attribute{
+					"id": {
+						AttributeType: unmarshalType(t, cty.String),
+					},
+					"triggers": {
+						AttributeType: unmarshalType(t, cty.Map(cty.String)),
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+				"id": renderers.ValidateUnknown(nil, plans.Create, false),
+				"triggers": renderers.ValidateMap(map[string]renderers.ValidateDiffFunction{
+					"rotation": renderers.ValidateUnknown(nil, plans.Create, false),
+				}, plans.Create, false),
+			}, nil, nil, nil, nil, plans.Create, false),
+		},
+		"issues/33016/null": {
+			input: structured.Change{
+				Before: nil,
+				After: map[string]interface{}{
+					"triggers": map[string]interface{}{
+						"rotation": nil,
+					},
+				},
+				Unknown: map[string]interface{}{
+					"id":       true,
+					"triggers": map[string]interface{}{},
+				},
+				BeforeSensitive: false,
+				AfterSensitive: map[string]interface{}{
+					"triggers": map[string]interface{}{},
+				},
+				ReplacePaths:       attribute_path.Empty(false),
+				RelevantAttributes: attribute_path.AlwaysMatcher(),
+			},
+			block: &jsonprovider.Block{
+				Attributes: map[string]*jsonprovider.Attribute{
+					"id": {
+						AttributeType: unmarshalType(t, cty.String),
+					},
+					"triggers": {
+						AttributeType: unmarshalType(t, cty.Map(cty.String)),
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+				"id": renderers.ValidateUnknown(nil, plans.Create, false),
+				"triggers": renderers.ValidateMap(map[string]renderers.ValidateDiffFunction{
+					"rotation": renderers.ValidatePrimitive(nil, nil, plans.Create, false),
+				}, plans.Create, false),
+			}, nil, nil, nil, nil, plans.Create, false),
+		},
+
+		// The following tests are from issue 33472. Basically Terraform allows
+		// callers to treat numbers as strings in references and expects us
+		// to coerce the strings into numbers. For example the following are
+		// equivalent.
+		//    - test_resource.resource.list[0].attribute
+		//    - test_resource.resource.list["0"].attribute
+		//
+		// We need our attribute_path package (used within the ReplacePaths and
+		// RelevantAttributes fields) to handle coercing strings into numbers
+		// when it's expected.
+
+		"issues/33472/expected": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"list": []interface{}{
+						map[string]interface{}{
+							"number": -1,
+						},
+					},
+				},
+				After: map[string]interface{}{
+					"list": []interface{}{
+						map[string]interface{}{
+							"number": 2,
+						},
+					},
+				},
+				Unknown:         false,
+				BeforeSensitive: false,
+				AfterSensitive:  false,
+				ReplacePaths:    attribute_path.Empty(false),
+				RelevantAttributes: &attribute_path.PathMatcher{
+					Propagate: true,
+					Paths: [][]interface{}{
+						{
+							"list",
+							0.0, // This is normal and expected so easy case.
+							"number",
+						},
+					},
+				},
+			},
+			block: &jsonprovider.Block{
+				Attributes: map[string]*jsonprovider.Attribute{
+					"list": {
+						AttributeType: unmarshalType(t, cty.List(cty.Object(map[string]cty.Type{
+							"number": cty.Number,
+						}))),
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+				"list": renderers.ValidateList([]renderers.ValidateDiffFunction{
+					renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+						"number": renderers.ValidatePrimitive(-1, 2, plans.Update, false),
+					}, plans.Update, false),
+				}, plans.Update, false),
+			}, nil, nil, nil, nil, plans.Update, false),
+		},
+
+		"issues/33472/coerce": {
+			input: structured.Change{
+				Before: map[string]interface{}{
+					"list": []interface{}{
+						map[string]interface{}{
+							"number": -1,
+						},
+					},
+				},
+				After: map[string]interface{}{
+					"list": []interface{}{
+						map[string]interface{}{
+							"number": 2,
+						},
+					},
+				},
+				Unknown:         false,
+				BeforeSensitive: false,
+				AfterSensitive:  false,
+				ReplacePaths:    attribute_path.Empty(false),
+				RelevantAttributes: &attribute_path.PathMatcher{
+					Propagate: true,
+					Paths: [][]interface{}{
+						{
+							"list",
+							"0", // Difficult but allowed, we need to handle this.
+							"number",
+						},
+					},
+				},
+			},
+			block: &jsonprovider.Block{
+				Attributes: map[string]*jsonprovider.Attribute{
+					"list": {
+						AttributeType: unmarshalType(t, cty.List(cty.Object(map[string]cty.Type{
+							"number": cty.Number,
+						}))),
+					},
+				},
+			},
+			validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
+				"list": renderers.ValidateList([]renderers.ValidateDiffFunction{
+					renderers.ValidateObject(map[string]renderers.ValidateDiffFunction{
+						"number": renderers.ValidatePrimitive(-1, 2, plans.Update, false),
+					}, plans.Update, false),
+				}, plans.Update, false),
+			}, nil, nil, nil, nil, plans.Update, false),
+		},
+	}
+	for name, tc := range tcs {
+		t.Run(name, func(t *testing.T) {
+			tc.validate(t, ComputeDiffForBlock(tc.input, tc.block))
+		})
+	}
+}
+
+// unmarshalType converts a cty.Type into a json.RawMessage understood by the
+// schema. It also lets the testing framework handle any errors to keep the API
+// clean.
+func unmarshalType(t *testing.T, ctyType cty.Type) json.RawMessage {
+	msg, err := ctyjson.MarshalType(ctyType)
+	if err != nil {
+		t.Fatalf("invalid type: %s", ctyType.FriendlyName())
+	}
+	return msg
+}
+
+// wrapChangeInSlice does the same as wrapChangeInMap, except it wraps it into a
+// slice internally.
+func wrapChangeInSlice(input structured.Change) structured.Change {
+	return wrapChange(input, float64(0), func(value interface{}, unknown interface{}, explicit bool) interface{} {
+		switch value.(type) {
+		case nil:
+			if set, ok := unknown.(bool); (set && ok) || explicit {
+				return []interface{}{nil}
+
+			}
+			return []interface{}{}
+		default:
+			return []interface{}{value}
+		}
+	})
+}
+
+// wrapChangeInMap access a single structured.Change and returns a new
+// structured.Change that represents a map with a single element. That single
+// element is the input value.
+func wrapChangeInMap(input structured.Change) structured.Change {
+	return wrapChange(input, "element", func(value interface{}, unknown interface{}, explicit bool) interface{} {
+		switch value.(type) {
+		case nil:
+			if set, ok := unknown.(bool); (set && ok) || explicit {
+				return map[string]interface{}{
+					"element": nil,
+				}
+			}
+			return map[string]interface{}{}
+		default:
+			return map[string]interface{}{
+				"element": value,
+			}
+		}
+	})
+}
+
+func wrapChange(input structured.Change, step interface{}, wrap func(interface{}, interface{}, bool) interface{}) structured.Change {
+
+	replacePaths := &attribute_path.PathMatcher{}
+	for _, path := range input.ReplacePaths.(*attribute_path.PathMatcher).Paths {
+		var updated []interface{}
+		updated = append(updated, step)
+		updated = append(updated, path...)
+		replacePaths.Paths = append(replacePaths.Paths, updated)
+	}
+
+	// relevantAttributes usually default to AlwaysMatcher, which means we can
+	// just ignore it. But if we have had some paths specified we need to wrap
+	// those as well.
+	relevantAttributes := input.RelevantAttributes
+	if concrete, ok := relevantAttributes.(*attribute_path.PathMatcher); ok {
+
+		newRelevantAttributes := &attribute_path.PathMatcher{}
+		for _, path := range concrete.Paths {
+			var updated []interface{}
+			updated = append(updated, step)
+			updated = append(updated, path...)
+			newRelevantAttributes.Paths = append(newRelevantAttributes.Paths, updated)
+		}
+		relevantAttributes = newRelevantAttributes
+	}
+
+	return structured.Change{
+		Before:             wrap(input.Before, nil, input.BeforeExplicit),
+		After:              wrap(input.After, input.Unknown, input.AfterExplicit),
+		Unknown:            wrap(input.Unknown, nil, false),
+		BeforeSensitive:    wrap(input.BeforeSensitive, nil, false),
+		AfterSensitive:     wrap(input.AfterSensitive, nil, false),
+		ReplacePaths:       replacePaths,
+		RelevantAttributes: relevantAttributes,
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/differ/list.go b/v1.5.7/internal/command/jsonformat/differ/list.go
new file mode 100644
index 0000000..79cc428
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/differ/list.go
@@ -0,0 +1,90 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package differ
+
+import (
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/collections"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+func computeAttributeDiffAsList(change structured.Change, elementType cty.Type) computed.Diff {
+	sliceValue := change.AsSlice()
+
+	processIndices := func(beforeIx, afterIx int) computed.Diff {
+		value := sliceValue.GetChild(beforeIx, afterIx)
+
+		// It's actually really difficult to render the diffs when some indices
+		// within a slice are relevant and others aren't. To make this simpler
+		// we just treat all children of a relevant list or set as also
+		// relevant.
+		//
+		// Interestingly the terraform plan builder also agrees with this, and
+		// never sets relevant attributes beneath lists or sets. We're just
+		// going to enforce this logic here as well. If the collection is
+		// relevant (decided elsewhere), then every element in the collection is
+		// also relevant. To be clear, in practice even if we didn't do the
+		// following explicitly the effect would be the same. It's just nicer
+		// for us to be clear about the behaviour we expect.
+		//
+		// What makes this difficult is the fact that the beforeIx and afterIx
+		// can be different, and it's quite difficult to work out which one is
+		// the relevant one. For nested lists, block lists, and tuples it's much
+		// easier because we always process the same indices in the before and
+		// after.
+		value.RelevantAttributes = attribute_path.AlwaysMatcher()
+
+		return ComputeDiffForType(value, elementType)
+	}
+
+	isObjType := func(_ interface{}) bool {
+		return elementType.IsObjectType()
+	}
+
+	elements, current := collections.TransformSlice(sliceValue.Before, sliceValue.After, processIndices, isObjType)
+	return computed.NewDiff(renderers.List(elements), current, change.ReplacePaths.Matches())
+}
+
+func computeAttributeDiffAsNestedList(change structured.Change, attributes map[string]*jsonprovider.Attribute) computed.Diff {
+	var elements []computed.Diff
+	current := change.GetDefaultActionForIteration()
+	processNestedList(change, func(value structured.Change) {
+		element := computeDiffForNestedAttribute(value, &jsonprovider.NestedType{
+			Attributes:  attributes,
+			NestingMode: "single",
+		})
+		elements = append(elements, element)
+		current = collections.CompareActions(current, element.Action)
+	})
+	return computed.NewDiff(renderers.NestedList(elements), current, change.ReplacePaths.Matches())
+}
+
+func computeBlockDiffsAsList(change structured.Change, block *jsonprovider.Block) ([]computed.Diff, plans.Action) {
+	var elements []computed.Diff
+	current := change.GetDefaultActionForIteration()
+	processNestedList(change, func(value structured.Change) {
+		element := ComputeDiffForBlock(value, block)
+		elements = append(elements, element)
+		current = collections.CompareActions(current, element.Action)
+	})
+	return elements, current
+}
+
+func processNestedList(change structured.Change, process func(value structured.Change)) {
+	sliceValue := change.AsSlice()
+	for ix := 0; ix < len(sliceValue.Before) || ix < len(sliceValue.After); ix++ {
+		value := sliceValue.GetChild(ix, ix)
+		if !value.RelevantAttributes.MatchesPartial() {
+			// Mark non-relevant attributes as unchanged.
+			value = value.AsNoOp()
+		}
+		process(value)
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/differ/map.go b/v1.5.7/internal/command/jsonformat/differ/map.go
new file mode 100644
index 0000000..604ca2c
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/differ/map.go
@@ -0,0 +1,56 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package differ
+
+import (
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/collections"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+func computeAttributeDiffAsMap(change structured.Change, elementType cty.Type) computed.Diff {
+	mapValue := change.AsMap()
+	elements, current := collections.TransformMap(mapValue.Before, mapValue.After, mapValue.AllKeys(), func(key string) computed.Diff {
+		value := mapValue.GetChild(key)
+		if !value.RelevantAttributes.MatchesPartial() {
+			// Mark non-relevant attributes as unchanged.
+			value = value.AsNoOp()
+		}
+		return ComputeDiffForType(value, elementType)
+	})
+	return computed.NewDiff(renderers.Map(elements), current, change.ReplacePaths.Matches())
+}
+
+func computeAttributeDiffAsNestedMap(change structured.Change, attributes map[string]*jsonprovider.Attribute) computed.Diff {
+	mapValue := change.AsMap()
+	elements, current := collections.TransformMap(mapValue.Before, mapValue.After, mapValue.ExplicitKeys(), func(key string) computed.Diff {
+		value := mapValue.GetChild(key)
+		if !value.RelevantAttributes.MatchesPartial() {
+			// Mark non-relevant attributes as unchanged.
+			value = value.AsNoOp()
+		}
+		return computeDiffForNestedAttribute(value, &jsonprovider.NestedType{
+			Attributes:  attributes,
+			NestingMode: "single",
+		})
+	})
+	return computed.NewDiff(renderers.NestedMap(elements), current, change.ReplacePaths.Matches())
+}
+
+func computeBlockDiffsAsMap(change structured.Change, block *jsonprovider.Block) (map[string]computed.Diff, plans.Action) {
+	mapValue := change.AsMap()
+	return collections.TransformMap(mapValue.Before, mapValue.After, mapValue.ExplicitKeys(), func(key string) computed.Diff {
+		value := mapValue.GetChild(key)
+		if !value.RelevantAttributes.MatchesPartial() {
+			// Mark non-relevant attributes as unchanged.
+			value = value.AsNoOp()
+		}
+		return ComputeDiffForBlock(value, block)
+	})
+}
diff --git a/v1.5.7/internal/command/jsonformat/differ/object.go b/v1.5.7/internal/command/jsonformat/differ/object.go
new file mode 100644
index 0000000..15447f2
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/differ/object.go
@@ -0,0 +1,70 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package differ
+
+import (
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/collections"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+func computeAttributeDiffAsObject(change structured.Change, attributes map[string]cty.Type) computed.Diff {
+	attributeDiffs, action := processObject(change, attributes, func(value structured.Change, ctype cty.Type) computed.Diff {
+		return ComputeDiffForType(value, ctype)
+	})
+	return computed.NewDiff(renderers.Object(attributeDiffs), action, change.ReplacePaths.Matches())
+}
+
+func computeAttributeDiffAsNestedObject(change structured.Change, attributes map[string]*jsonprovider.Attribute) computed.Diff {
+	attributeDiffs, action := processObject(change, attributes, func(value structured.Change, attribute *jsonprovider.Attribute) computed.Diff {
+		return ComputeDiffForAttribute(value, attribute)
+	})
+	return computed.NewDiff(renderers.NestedObject(attributeDiffs), action, change.ReplacePaths.Matches())
+}
+
+// processObject steps through the children of value as if it is an object and
+// calls out to the provided computeDiff function once it has collated the
+// diffs for each child attribute.
+//
+// We have to make this generic as attributes and nested objects process either
+// cty.Type or jsonprovider.Attribute children respectively. And we want to
+// reuse as much code as possible.
+//
+// Also, as it generic we cannot make this function a method on Change as you
+// can't create generic methods on structs. Instead, we make this a generic
+// function that receives the value as an argument.
+func processObject[T any](v structured.Change, attributes map[string]T, computeDiff func(structured.Change, T) computed.Diff) (map[string]computed.Diff, plans.Action) {
+	attributeDiffs := make(map[string]computed.Diff)
+	mapValue := v.AsMap()
+
+	currentAction := v.GetDefaultActionForIteration()
+	for key, attribute := range attributes {
+		attributeValue := mapValue.GetChild(key)
+
+		if !attributeValue.RelevantAttributes.MatchesPartial() {
+			// Mark non-relevant attributes as unchanged.
+			attributeValue = attributeValue.AsNoOp()
+		}
+
+		// We always assume changes to object are implicit.
+		attributeValue.BeforeExplicit = false
+		attributeValue.AfterExplicit = false
+
+		attributeDiff := computeDiff(attributeValue, attribute)
+		if attributeDiff.Action == plans.NoOp && attributeValue.Before == nil && attributeValue.After == nil {
+			// We skip attributes of objects that are null both before and
+			// after. We don't even count these as unchanged attributes.
+			continue
+		}
+		attributeDiffs[key] = attributeDiff
+		currentAction = collections.CompareActions(currentAction, attributeDiff.Action)
+	}
+
+	return attributeDiffs, currentAction
+}
diff --git a/v1.5.7/internal/command/jsonformat/differ/output.go b/v1.5.7/internal/command/jsonformat/differ/output.go
new file mode 100644
index 0000000..a1d85fc
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/differ/output.go
@@ -0,0 +1,25 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package differ
+
+import (
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+)
+
+func ComputeDiffForOutput(change structured.Change) computed.Diff {
+	if sensitive, ok := checkForSensitiveType(change, cty.DynamicPseudoType); ok {
+		return sensitive
+	}
+
+	if unknown, ok := checkForUnknownType(change, cty.DynamicPseudoType); ok {
+		return unknown
+	}
+
+	jsonOpts := renderers.RendererJsonOpts()
+	return jsonOpts.Transform(change)
+}
diff --git a/v1.5.7/internal/command/jsonformat/differ/primitive.go b/v1.5.7/internal/command/jsonformat/differ/primitive.go
new file mode 100644
index 0000000..a6b80e5
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/differ/primitive.go
@@ -0,0 +1,16 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package differ
+
+import (
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+)
+
+func computeAttributeDiffAsPrimitive(change structured.Change, ctype cty.Type) computed.Diff {
+	return asDiff(change, renderers.Primitive(change.Before, change.After, ctype))
+}
diff --git a/v1.5.7/internal/command/jsonformat/differ/sensitive.go b/v1.5.7/internal/command/jsonformat/differ/sensitive.go
new file mode 100644
index 0000000..1d147f9
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/differ/sensitive.go
@@ -0,0 +1,46 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package differ
+
+import (
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+type CreateSensitiveRenderer func(computed.Diff, bool, bool) computed.DiffRenderer
+
+func checkForSensitiveType(change structured.Change, ctype cty.Type) (computed.Diff, bool) {
+	return change.CheckForSensitive(
+		func(value structured.Change) computed.Diff {
+			return ComputeDiffForType(value, ctype)
+		}, func(inner computed.Diff, beforeSensitive, afterSensitive bool, action plans.Action) computed.Diff {
+			return computed.NewDiff(renderers.Sensitive(inner, beforeSensitive, afterSensitive), action, change.ReplacePaths.Matches())
+		},
+	)
+}
+
+func checkForSensitiveNestedAttribute(change structured.Change, attribute *jsonprovider.NestedType) (computed.Diff, bool) {
+	return change.CheckForSensitive(
+		func(value structured.Change) computed.Diff {
+			return computeDiffForNestedAttribute(value, attribute)
+		}, func(inner computed.Diff, beforeSensitive, afterSensitive bool, action plans.Action) computed.Diff {
+			return computed.NewDiff(renderers.Sensitive(inner, beforeSensitive, afterSensitive), action, change.ReplacePaths.Matches())
+		},
+	)
+}
+
+func checkForSensitiveBlock(change structured.Change, block *jsonprovider.Block) (computed.Diff, bool) {
+	return change.CheckForSensitive(
+		func(value structured.Change) computed.Diff {
+			return ComputeDiffForBlock(value, block)
+		}, func(inner computed.Diff, beforeSensitive, afterSensitive bool, action plans.Action) computed.Diff {
+			return computed.NewDiff(renderers.SensitiveBlock(inner, beforeSensitive, afterSensitive), action, change.ReplacePaths.Matches())
+		},
+	)
+}
diff --git a/v1.5.7/internal/command/jsonformat/differ/set.go b/v1.5.7/internal/command/jsonformat/differ/set.go
new file mode 100644
index 0000000..1508eea
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/differ/set.go
@@ -0,0 +1,135 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package differ
+
+import (
+	"reflect"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/collections"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+func computeAttributeDiffAsSet(change structured.Change, elementType cty.Type) computed.Diff {
+	var elements []computed.Diff
+	current := change.GetDefaultActionForIteration()
+	processSet(change, func(value structured.Change) {
+		element := ComputeDiffForType(value, elementType)
+		elements = append(elements, element)
+		current = collections.CompareActions(current, element.Action)
+	})
+	return computed.NewDiff(renderers.Set(elements), current, change.ReplacePaths.Matches())
+}
+
+func computeAttributeDiffAsNestedSet(change structured.Change, attributes map[string]*jsonprovider.Attribute) computed.Diff {
+	var elements []computed.Diff
+	current := change.GetDefaultActionForIteration()
+	processSet(change, func(value structured.Change) {
+		element := computeDiffForNestedAttribute(value, &jsonprovider.NestedType{
+			Attributes:  attributes,
+			NestingMode: "single",
+		})
+		elements = append(elements, element)
+		current = collections.CompareActions(current, element.Action)
+	})
+	return computed.NewDiff(renderers.NestedSet(elements), current, change.ReplacePaths.Matches())
+}
+
+func computeBlockDiffsAsSet(change structured.Change, block *jsonprovider.Block) ([]computed.Diff, plans.Action) {
+	var elements []computed.Diff
+	current := change.GetDefaultActionForIteration()
+	processSet(change, func(value structured.Change) {
+		element := ComputeDiffForBlock(value, block)
+		elements = append(elements, element)
+		current = collections.CompareActions(current, element.Action)
+	})
+	return elements, current
+}
+
+func processSet(change structured.Change, process func(value structured.Change)) {
+	sliceValue := change.AsSlice()
+
+	foundInBefore := make(map[int]int)
+	foundInAfter := make(map[int]int)
+
+	// O(n^2) operation here to find matching pairs in the set, so we can make
+	// the display look pretty. There might be a better way to do this, so look
+	// here for potential optimisations.
+
+	for ix := 0; ix < len(sliceValue.Before); ix++ {
+		matched := false
+		for jx := 0; jx < len(sliceValue.After); jx++ {
+			if _, ok := foundInAfter[jx]; ok {
+				// We've already found a match for this after value.
+				continue
+			}
+
+			child := sliceValue.GetChild(ix, jx)
+			if reflect.DeepEqual(child.Before, child.After) && child.IsBeforeSensitive() == child.IsAfterSensitive() && !child.IsUnknown() {
+				matched = true
+				foundInBefore[ix] = jx
+				foundInAfter[jx] = ix
+			}
+		}
+
+		if !matched {
+			foundInBefore[ix] = -1
+		}
+	}
+
+	clearRelevantStatus := func(change structured.Change) structured.Change {
+		// It's actually really difficult to render the diffs when some indices
+		// within a slice are relevant and others aren't. To make this simpler
+		// we just treat all children of a relevant list or set as also
+		// relevant.
+		//
+		// Interestingly the terraform plan builder also agrees with this, and
+		// never sets relevant attributes beneath lists or sets. We're just
+		// going to enforce this logic here as well. If the collection is
+		// relevant (decided elsewhere), then every element in the collection is
+		// also relevant. To be clear, in practice even if we didn't do the
+		// following explicitly the effect would be the same. It's just nicer
+		// for us to be clear about the behaviour we expect.
+		//
+		// What makes this difficult is the fact that the beforeIx and afterIx
+		// can be different, and it's quite difficult to work out which one is
+		// the relevant one. For nested lists, block lists, and tuples it's much
+		// easier because we always process the same indices in the before and
+		// after.
+		change.RelevantAttributes = attribute_path.AlwaysMatcher()
+		return change
+	}
+
+	// Now everything in before should be a key in foundInBefore and a value
+	// in foundInAfter. If a key is mapped to -1 in foundInBefore it means it
+	// does not have an equivalent in foundInAfter and so has been deleted.
+	// Everything in foundInAfter has a matching value in foundInBefore, but
+	// some values in after may not be in foundInAfter. This means these values
+	// are newly created.
+
+	for ix := 0; ix < len(sliceValue.Before); ix++ {
+		if jx := foundInBefore[ix]; jx >= 0 {
+			child := clearRelevantStatus(sliceValue.GetChild(ix, jx))
+			process(child)
+			continue
+		}
+		child := clearRelevantStatus(sliceValue.GetChild(ix, len(sliceValue.After)))
+		process(child)
+	}
+
+	for jx := 0; jx < len(sliceValue.After); jx++ {
+		if _, ok := foundInAfter[jx]; ok {
+			// Then this value was handled in the previous for loop.
+			continue
+		}
+		child := clearRelevantStatus(sliceValue.GetChild(len(sliceValue.Before), jx))
+		process(child)
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/differ/tuple.go b/v1.5.7/internal/command/jsonformat/differ/tuple.go
new file mode 100644
index 0000000..84c9064
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/differ/tuple.go
@@ -0,0 +1,30 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package differ
+
+import (
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/collections"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+)
+
+func computeAttributeDiffAsTuple(change structured.Change, elementTypes []cty.Type) computed.Diff {
+	var elements []computed.Diff
+	current := change.GetDefaultActionForIteration()
+	sliceValue := change.AsSlice()
+	for ix, elementType := range elementTypes {
+		childValue := sliceValue.GetChild(ix, ix)
+		if !childValue.RelevantAttributes.MatchesPartial() {
+			// Mark non-relevant attributes as unchanged.
+			childValue = childValue.AsNoOp()
+		}
+		element := ComputeDiffForType(childValue, elementType)
+		elements = append(elements, element)
+		current = collections.CompareActions(current, element.Action)
+	}
+	return computed.NewDiff(renderers.List(elements), current, change.ReplacePaths.Matches())
+}
diff --git a/v1.5.7/internal/command/jsonformat/differ/types.go b/v1.5.7/internal/command/jsonformat/differ/types.go
new file mode 100644
index 0000000..aaed20e
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/differ/types.go
@@ -0,0 +1,17 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package differ
+
+// NestingMode is a wrapper around a string type to describe the various
+// different kinds of nesting modes that can be applied to nested blocks and
+// objects.
+type NestingMode string
+
+const (
+	nestingModeSet    NestingMode = "set"
+	nestingModeList   NestingMode = "list"
+	nestingModeMap    NestingMode = "map"
+	nestingModeSingle NestingMode = "single"
+	nestingModeGroup  NestingMode = "group"
+)
diff --git a/v1.5.7/internal/command/jsonformat/differ/unknown.go b/v1.5.7/internal/command/jsonformat/differ/unknown.go
new file mode 100644
index 0000000..0b34199
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/differ/unknown.go
@@ -0,0 +1,66 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package differ
+
+import (
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+)
+
+func checkForUnknownType(change structured.Change, ctype cty.Type) (computed.Diff, bool) {
+	return change.CheckForUnknown(
+		false,
+		processUnknown,
+		createProcessUnknownWithBefore(func(value structured.Change) computed.Diff {
+			return ComputeDiffForType(value, ctype)
+		}))
+}
+
+func checkForUnknownNestedAttribute(change structured.Change, attribute *jsonprovider.NestedType) (computed.Diff, bool) {
+
+	// We want our child attributes to show up as computed instead of deleted.
+	// Let's populate that here.
+	childUnknown := make(map[string]interface{})
+	for key := range attribute.Attributes {
+		childUnknown[key] = true
+	}
+
+	return change.CheckForUnknown(
+		childUnknown,
+		processUnknown,
+		createProcessUnknownWithBefore(func(value structured.Change) computed.Diff {
+			return computeDiffForNestedAttribute(value, attribute)
+		}))
+}
+
+func checkForUnknownBlock(change structured.Change, block *jsonprovider.Block) (computed.Diff, bool) {
+
+	// We want our child attributes to show up as computed instead of deleted.
+	// Let's populate that here.
+	childUnknown := make(map[string]interface{})
+	for key := range block.Attributes {
+		childUnknown[key] = true
+	}
+
+	return change.CheckForUnknown(
+		childUnknown,
+		processUnknown,
+		createProcessUnknownWithBefore(func(value structured.Change) computed.Diff {
+			return ComputeDiffForBlock(value, block)
+		}))
+}
+
+func processUnknown(current structured.Change) computed.Diff {
+	return asDiff(current, renderers.Unknown(computed.Diff{}))
+}
+
+func createProcessUnknownWithBefore(computeDiff func(value structured.Change) computed.Diff) structured.ProcessUnknownWithBefore {
+	return func(current structured.Change, before structured.Change) computed.Diff {
+		return asDiff(current, renderers.Unknown(computeDiff(before)))
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/jsondiff/diff.go b/v1.5.7/internal/command/jsonformat/jsondiff/diff.go
new file mode 100644
index 0000000..c30647d
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/jsondiff/diff.go
@@ -0,0 +1,151 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsondiff
+
+import (
+	"reflect"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/collections"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+type TransformPrimitiveJson func(before, after interface{}, ctype cty.Type, action plans.Action) computed.Diff
+type TransformObjectJson func(map[string]computed.Diff, plans.Action) computed.Diff
+type TransformArrayJson func([]computed.Diff, plans.Action) computed.Diff
+type TransformUnknownJson func(computed.Diff, plans.Action) computed.Diff
+type TransformSensitiveJson func(computed.Diff, bool, bool, plans.Action) computed.Diff
+type TransformTypeChangeJson func(before, after computed.Diff, action plans.Action) computed.Diff
+
+// JsonOpts defines the external callback functions that callers should
+// implement to process the supplied diffs.
+type JsonOpts struct {
+	Primitive  TransformPrimitiveJson
+	Object     TransformObjectJson
+	Array      TransformArrayJson
+	Unknown    TransformUnknownJson
+	Sensitive  TransformSensitiveJson
+	TypeChange TransformTypeChangeJson
+}
+
+// Transform accepts a generic before and after value that is assumed to be JSON
+// formatted and transforms it into a computed.Diff, using the callbacks
+// supplied in the JsonOpts class.
+func (opts JsonOpts) Transform(change structured.Change) computed.Diff {
+	if sensitive, ok := opts.processSensitive(change); ok {
+		return sensitive
+	}
+
+	if unknown, ok := opts.processUnknown(change); ok {
+		return unknown
+	}
+
+	beforeType := GetType(change.Before)
+	afterType := GetType(change.After)
+
+	deleted := afterType == Null && !change.AfterExplicit
+	created := beforeType == Null && !change.BeforeExplicit
+
+	if beforeType == afterType || (created || deleted) {
+		targetType := beforeType
+		if targetType == Null {
+			targetType = afterType
+		}
+		return opts.processUpdate(change, targetType)
+	}
+
+	b := opts.processUpdate(change.AsDelete(), beforeType)
+	a := opts.processUpdate(change.AsCreate(), afterType)
+	return opts.TypeChange(b, a, plans.Update)
+}
+
+func (opts JsonOpts) processUpdate(change structured.Change, jtype Type) computed.Diff {
+	switch jtype {
+	case Null:
+		return opts.processPrimitive(change, cty.NilType)
+	case Bool:
+		return opts.processPrimitive(change, cty.Bool)
+	case String:
+		return opts.processPrimitive(change, cty.String)
+	case Number:
+		return opts.processPrimitive(change, cty.Number)
+	case Object:
+		return opts.processObject(change.AsMap())
+	case Array:
+		return opts.processArray(change.AsSlice())
+	default:
+		panic("unrecognized json type: " + jtype)
+	}
+}
+
+func (opts JsonOpts) processPrimitive(change structured.Change, ctype cty.Type) computed.Diff {
+	beforeMissing := change.Before == nil && !change.BeforeExplicit
+	afterMissing := change.After == nil && !change.AfterExplicit
+
+	var action plans.Action
+	switch {
+	case beforeMissing && !afterMissing:
+		action = plans.Create
+	case !beforeMissing && afterMissing:
+		action = plans.Delete
+	case reflect.DeepEqual(change.Before, change.After):
+		action = plans.NoOp
+	default:
+		action = plans.Update
+	}
+
+	return opts.Primitive(change.Before, change.After, ctype, action)
+}
+
+func (opts JsonOpts) processArray(change structured.ChangeSlice) computed.Diff {
+	processIndices := func(beforeIx, afterIx int) computed.Diff {
+		// It's actually really difficult to render the diffs when some indices
+		// within a list are relevant and others aren't. To make this simpler
+		// we just treat all children of a relevant list as also relevant, so we
+		// ignore the relevant attributes field.
+		//
+		// Interestingly the terraform plan builder also agrees with this, and
+		// never sets relevant attributes beneath lists or sets. We're just
+		// going to enforce this logic here as well. If the list is relevant
+		// (decided elsewhere), then every element in the list is also relevant.
+		return opts.Transform(change.GetChild(beforeIx, afterIx))
+	}
+
+	isObjType := func(value interface{}) bool {
+		return GetType(value) == Object
+	}
+
+	return opts.Array(collections.TransformSlice(change.Before, change.After, processIndices, isObjType))
+}
+
+func (opts JsonOpts) processObject(change structured.ChangeMap) computed.Diff {
+	return opts.Object(collections.TransformMap(change.Before, change.After, change.AllKeys(), func(key string) computed.Diff {
+		child := change.GetChild(key)
+		if !child.RelevantAttributes.MatchesPartial() {
+			child = child.AsNoOp()
+		}
+
+		return opts.Transform(child)
+	}))
+}
+
+func (opts JsonOpts) processUnknown(change structured.Change) (computed.Diff, bool) {
+	return change.CheckForUnknown(
+		false,
+		func(current structured.Change) computed.Diff {
+			return opts.Unknown(computed.Diff{}, plans.Create)
+		}, func(current structured.Change, before structured.Change) computed.Diff {
+			return opts.Unknown(opts.Transform(before), plans.Update)
+		},
+	)
+}
+
+func (opts JsonOpts) processSensitive(change structured.Change) (computed.Diff, bool) {
+	return change.CheckForSensitive(opts.Transform, func(inner computed.Diff, beforeSensitive, afterSensitive bool, action plans.Action) computed.Diff {
+		return opts.Sensitive(inner, beforeSensitive, afterSensitive, action)
+	})
+}
diff --git a/v1.5.7/internal/command/jsonformat/jsondiff/types.go b/v1.5.7/internal/command/jsonformat/jsondiff/types.go
new file mode 100644
index 0000000..eaa8c1b
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/jsondiff/types.go
@@ -0,0 +1,36 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsondiff
+
+import "fmt"
+
+type Type string
+
+const (
+	Number Type = "number"
+	Object Type = "object"
+	Array  Type = "array"
+	Bool   Type = "bool"
+	String Type = "string"
+	Null   Type = "null"
+)
+
+func GetType(json interface{}) Type {
+	switch json.(type) {
+	case []interface{}:
+		return Array
+	case float64:
+		return Number
+	case string:
+		return String
+	case bool:
+		return Bool
+	case nil:
+		return Null
+	case map[string]interface{}:
+		return Object
+	default:
+		panic(fmt.Sprintf("unrecognized json type %T", json))
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/plan.go b/v1.5.7/internal/command/jsonformat/plan.go
new file mode 100644
index 0000000..cd92e1a
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/plan.go
@@ -0,0 +1,534 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonformat
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/command/format"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers"
+	"github.com/hashicorp/terraform/internal/command/jsonplan"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/command/jsonstate"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+type PlanRendererOpt int
+
+const (
+	detectedDrift  string = "drift"
+	proposedChange string = "change"
+
+	Errored PlanRendererOpt = iota
+	CanNotApply
+)
+
+type Plan struct {
+	PlanFormatVersion  string                     `json:"plan_format_version"`
+	OutputChanges      map[string]jsonplan.Change `json:"output_changes"`
+	ResourceChanges    []jsonplan.ResourceChange  `json:"resource_changes"`
+	ResourceDrift      []jsonplan.ResourceChange  `json:"resource_drift"`
+	RelevantAttributes []jsonplan.ResourceAttr    `json:"relevant_attributes"`
+
+	ProviderFormatVersion string                            `json:"provider_format_version"`
+	ProviderSchemas       map[string]*jsonprovider.Provider `json:"provider_schemas"`
+}
+
+func (plan Plan) getSchema(change jsonplan.ResourceChange) *jsonprovider.Schema {
+	switch change.Mode {
+	case jsonstate.ManagedResourceMode:
+		return plan.ProviderSchemas[change.ProviderName].ResourceSchemas[change.Type]
+	case jsonstate.DataResourceMode:
+		return plan.ProviderSchemas[change.ProviderName].DataSourceSchemas[change.Type]
+	default:
+		panic("found unrecognized resource mode: " + change.Mode)
+	}
+}
+
+func (plan Plan) renderHuman(renderer Renderer, mode plans.Mode, opts ...PlanRendererOpt) {
+	checkOpts := func(target PlanRendererOpt) bool {
+		for _, opt := range opts {
+			if opt == target {
+				return true
+			}
+		}
+		return false
+	}
+
+	diffs := precomputeDiffs(plan, mode)
+	haveRefreshChanges := renderHumanDiffDrift(renderer, diffs, mode)
+
+	willPrintResourceChanges := false
+	counts := make(map[plans.Action]int)
+	importingCount := 0
+	var changes []diff
+	for _, diff := range diffs.changes {
+		action := jsonplan.UnmarshalActions(diff.change.Change.Actions)
+		if action == plans.NoOp && !diff.Moved() && !diff.Importing() {
+			// Don't show anything for NoOp changes.
+			continue
+		}
+		if action == plans.Delete && diff.change.Mode != jsonstate.ManagedResourceMode {
+			// Don't render anything for deleted data sources.
+			continue
+		}
+
+		changes = append(changes, diff)
+
+		if diff.Importing() {
+			importingCount++
+		}
+
+		// Don't count move-only changes
+		if action != plans.NoOp {
+			willPrintResourceChanges = true
+			counts[action]++
+		}
+	}
+
+	// Precompute the outputs early, so we can make a decision about whether we
+	// display the "there are no changes messages".
+	outputs := renderHumanDiffOutputs(renderer, diffs.outputs)
+
+	if len(changes) == 0 && len(outputs) == 0 {
+		// If we didn't find any changes to report at all then this is a
+		// "No changes" plan. How we'll present this depends on whether
+		// the plan is "applyable" and, if so, whether it had refresh changes
+		// that we already would've presented above.
+
+		if checkOpts(Errored) {
+			if haveRefreshChanges {
+				renderer.Streams.Print(format.HorizontalRule(renderer.Colorize, renderer.Streams.Stdout.Columns()))
+				renderer.Streams.Println()
+			}
+			renderer.Streams.Print(
+				renderer.Colorize.Color("\n[reset][bold][red]Planning failed.[reset][bold] Terraform encountered an error while generating this plan.[reset]\n\n"),
+			)
+		} else {
+			switch mode {
+			case plans.RefreshOnlyMode:
+				if haveRefreshChanges {
+					// We already generated a sufficient prompt about what will
+					// happen if applying this change above, so we don't need to
+					// say anything more.
+					return
+				}
+
+				renderer.Streams.Print(renderer.Colorize.Color("\n[reset][bold][green]No changes.[reset][bold] Your infrastructure still matches the configuration.[reset]\n\n"))
+				renderer.Streams.Println(format.WordWrap(
+					"Terraform has checked that the real remote objects still match the result of your most recent changes, and found no differences.",
+					renderer.Streams.Stdout.Columns()))
+			case plans.DestroyMode:
+				if haveRefreshChanges {
+					renderer.Streams.Print(format.HorizontalRule(renderer.Colorize, renderer.Streams.Stdout.Columns()))
+					fmt.Fprintln(renderer.Streams.Stdout.File)
+				}
+				renderer.Streams.Print(renderer.Colorize.Color("\n[reset][bold][green]No changes.[reset][bold] No objects need to be destroyed.[reset]\n\n"))
+				renderer.Streams.Println(format.WordWrap(
+					"Either you have not created any objects yet or the existing objects were already deleted outside of Terraform.",
+					renderer.Streams.Stdout.Columns()))
+			default:
+				if haveRefreshChanges {
+					renderer.Streams.Print(format.HorizontalRule(renderer.Colorize, renderer.Streams.Stdout.Columns()))
+					renderer.Streams.Println("")
+				}
+				renderer.Streams.Print(
+					renderer.Colorize.Color("\n[reset][bold][green]No changes.[reset][bold] Your infrastructure matches the configuration.[reset]\n\n"),
+				)
+
+				if haveRefreshChanges {
+					if !checkOpts(CanNotApply) {
+						// In this case, applying this plan will not change any
+						// remote objects but _will_ update the state to match what
+						// we detected during refresh, so we'll reassure the user
+						// about that.
+						renderer.Streams.Println(format.WordWrap(
+							"Your configuration already matches the changes detected above, so applying this plan will only update the state to include the changes detected above and won't change any real infrastructure.",
+							renderer.Streams.Stdout.Columns(),
+						))
+					} else {
+						// In this case we detected changes during refresh but this isn't
+						// a planning mode where we consider those to be applyable. The
+						// user must re-run in refresh-only mode in order to update the
+						// state to match the upstream changes.
+						suggestion := "."
+						if !renderer.RunningInAutomation {
+							// The normal message includes a specific command line to run.
+							suggestion = ":\n  terraform apply -refresh-only"
+						}
+						renderer.Streams.Println(format.WordWrap(
+							"Your configuration already matches the changes detected above. If you'd like to update the Terraform state to match, create and apply a refresh-only plan"+suggestion,
+							renderer.Streams.Stdout.Columns(),
+						))
+					}
+					return
+				}
+
+				// If we get down here then we're just in the simple situation where
+				// the plan isn't applyable at all.
+				renderer.Streams.Println(format.WordWrap(
+					"Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.",
+					renderer.Streams.Stdout.Columns(),
+				))
+			}
+		}
+	}
+
+	if haveRefreshChanges {
+		renderer.Streams.Print(format.HorizontalRule(renderer.Colorize, renderer.Streams.Stdout.Columns()))
+		renderer.Streams.Println()
+	}
+
+	if willPrintResourceChanges {
+		renderer.Streams.Println(format.WordWrap(
+			"\nTerraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:",
+			renderer.Streams.Stdout.Columns()))
+		if counts[plans.Create] > 0 {
+			renderer.Streams.Println(renderer.Colorize.Color(actionDescription(plans.Create)))
+		}
+		if counts[plans.Update] > 0 {
+			renderer.Streams.Println(renderer.Colorize.Color(actionDescription(plans.Update)))
+		}
+		if counts[plans.Delete] > 0 {
+			renderer.Streams.Println(renderer.Colorize.Color(actionDescription(plans.Delete)))
+		}
+		if counts[plans.DeleteThenCreate] > 0 {
+			renderer.Streams.Println(renderer.Colorize.Color(actionDescription(plans.DeleteThenCreate)))
+		}
+		if counts[plans.CreateThenDelete] > 0 {
+			renderer.Streams.Println(renderer.Colorize.Color(actionDescription(plans.CreateThenDelete)))
+		}
+		if counts[plans.Read] > 0 {
+			renderer.Streams.Println(renderer.Colorize.Color(actionDescription(plans.Read)))
+		}
+	}
+
+	if len(changes) > 0 {
+		if checkOpts(Errored) {
+			renderer.Streams.Printf("\nTerraform planned the following actions, but then encountered a problem:\n")
+		} else {
+			renderer.Streams.Printf("\nTerraform will perform the following actions:\n")
+		}
+
+		for _, change := range changes {
+			diff, render := renderHumanDiff(renderer, change, proposedChange)
+			if render {
+				fmt.Fprintln(renderer.Streams.Stdout.File)
+				renderer.Streams.Println(diff)
+			}
+		}
+
+		if importingCount > 0 {
+			renderer.Streams.Printf(
+				renderer.Colorize.Color("\n[bold]Plan:[reset] %d to import, %d to add, %d to change, %d to destroy.\n"),
+				importingCount,
+				counts[plans.Create]+counts[plans.DeleteThenCreate]+counts[plans.CreateThenDelete],
+				counts[plans.Update],
+				counts[plans.Delete]+counts[plans.DeleteThenCreate]+counts[plans.CreateThenDelete])
+		} else {
+			renderer.Streams.Printf(
+				renderer.Colorize.Color("\n[bold]Plan:[reset] %d to add, %d to change, %d to destroy.\n"),
+				counts[plans.Create]+counts[plans.DeleteThenCreate]+counts[plans.CreateThenDelete],
+				counts[plans.Update],
+				counts[plans.Delete]+counts[plans.DeleteThenCreate]+counts[plans.CreateThenDelete])
+		}
+	}
+
+	if len(outputs) > 0 {
+		renderer.Streams.Print("\nChanges to Outputs:\n")
+		renderer.Streams.Printf("%s\n", outputs)
+
+		if len(counts) == 0 {
+			// If we have output changes but not resource changes then we
+			// won't have output any indication about the changes at all yet,
+			// so we need some extra context about what it would mean to
+			// apply a change that _only_ includes output changes.
+			renderer.Streams.Println(format.WordWrap(
+				"\nYou can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.",
+				renderer.Streams.Stdout.Columns()))
+		}
+	}
+}
+
+func renderHumanDiffOutputs(renderer Renderer, outputs map[string]computed.Diff) string {
+	var rendered []string
+
+	var keys []string
+	escapedKeys := make(map[string]string)
+	var escapedKeyMaxLen int
+	for key := range outputs {
+		escapedKey := renderers.EnsureValidAttributeName(key)
+		keys = append(keys, key)
+		escapedKeys[key] = escapedKey
+		if len(escapedKey) > escapedKeyMaxLen {
+			escapedKeyMaxLen = len(escapedKey)
+		}
+	}
+	sort.Strings(keys)
+
+	for _, key := range keys {
+		output := outputs[key]
+		if output.Action != plans.NoOp {
+			rendered = append(rendered, fmt.Sprintf("%s %-*s = %s", renderer.Colorize.Color(format.DiffActionSymbol(output.Action)), escapedKeyMaxLen, escapedKeys[key], output.RenderHuman(0, computed.NewRenderHumanOpts(renderer.Colorize))))
+		}
+	}
+	return strings.Join(rendered, "\n")
+}
+
+func renderHumanDiffDrift(renderer Renderer, diffs diffs, mode plans.Mode) bool {
+	var drs []diff
+
+	// In refresh-only mode, we show all resources marked as drifted,
+	// including those which have moved without other changes. In other plan
+	// modes, move-only changes will be rendered in the planned changes, so
+	// we skip them here.
+
+	if mode == plans.RefreshOnlyMode {
+		drs = diffs.drift
+	} else {
+		for _, dr := range diffs.drift {
+			if dr.diff.Action != plans.NoOp {
+				drs = append(drs, dr)
+			}
+		}
+	}
+
+	if len(drs) == 0 {
+		return false
+	}
+
+	// If the overall plan is empty, and it's not a refresh only plan then we
+	// won't show any drift changes.
+	if diffs.Empty() && mode != plans.RefreshOnlyMode {
+		return false
+	}
+
+	renderer.Streams.Print(renderer.Colorize.Color("\n[bold][cyan]Note:[reset][bold] Objects have changed outside of Terraform\n"))
+	renderer.Streams.Println()
+	renderer.Streams.Print(format.WordWrap(
+		"Terraform detected the following changes made outside of Terraform since the last \"terraform apply\" which may have affected this plan:\n",
+		renderer.Streams.Stdout.Columns()))
+
+	for _, drift := range drs {
+		diff, render := renderHumanDiff(renderer, drift, detectedDrift)
+		if render {
+			renderer.Streams.Println()
+			renderer.Streams.Println(diff)
+		}
+	}
+
+	switch mode {
+	case plans.RefreshOnlyMode:
+		renderer.Streams.Println(format.WordWrap(
+			"\n\nThis is a refresh-only plan, so Terraform will not take any actions to undo these. If you were expecting these changes then you can apply this plan to record the updated values in the Terraform state without changing any remote objects.",
+			renderer.Streams.Stdout.Columns(),
+		))
+	default:
+		renderer.Streams.Println(format.WordWrap(
+			"\n\nUnless you have made equivalent changes to your configuration, or ignored the relevant attributes using ignore_changes, the following plan may include actions to undo or respond to these changes.",
+			renderer.Streams.Stdout.Columns(),
+		))
+	}
+
+	return true
+}
+
+func renderHumanDiff(renderer Renderer, diff diff, cause string) (string, bool) {
+
+	// Internally, our computed diffs can't tell the difference between a
+	// replace action (eg. CreateThenDestroy, DestroyThenCreate) and a simple
+	// update action. So, at the top most level we rely on the action provided
+	// by the plan itself instead of what we compute. Nested attributes and
+	// blocks however don't have the replace type of actions, so we can trust
+	// the computed actions of these.
+
+	action := jsonplan.UnmarshalActions(diff.change.Change.Actions)
+	if action == plans.NoOp && !diff.Moved() && !diff.Importing() {
+		// Skip resource changes that have nothing interesting to say.
+		return "", false
+	}
+
+	var buf bytes.Buffer
+	buf.WriteString(renderer.Colorize.Color(resourceChangeComment(diff.change, action, cause)))
+
+	opts := computed.NewRenderHumanOpts(renderer.Colorize)
+	opts.ShowUnchangedChildren = diff.Importing()
+
+	buf.WriteString(fmt.Sprintf("%s %s %s", renderer.Colorize.Color(format.DiffActionSymbol(action)), resourceChangeHeader(diff.change), diff.diff.RenderHuman(0, opts)))
+	return buf.String(), true
+}
+
+func resourceChangeComment(resource jsonplan.ResourceChange, action plans.Action, changeCause string) string {
+	var buf bytes.Buffer
+
+	dispAddr := resource.Address
+	if len(resource.Deposed) != 0 {
+		dispAddr = fmt.Sprintf("%s (deposed object %s)", dispAddr, resource.Deposed)
+	}
+
+	var printedMoved bool
+	var printedImported bool
+
+	switch action {
+	case plans.Create:
+		buf.WriteString(fmt.Sprintf("[bold]  # %s[reset] will be created", dispAddr))
+	case plans.Read:
+		buf.WriteString(fmt.Sprintf("[bold]  # %s[reset] will be read during apply", dispAddr))
+		switch resource.ActionReason {
+		case jsonplan.ResourceInstanceReadBecauseConfigUnknown:
+			buf.WriteString("\n  # (config refers to values not yet known)")
+		case jsonplan.ResourceInstanceReadBecauseDependencyPending:
+			buf.WriteString("\n  # (depends on a resource or a module with changes pending)")
+		case jsonplan.ResourceInstanceReadBecauseCheckNested:
+			buf.WriteString("\n  # (config will be reloaded to verify a check block)")
+		}
+	case plans.Update:
+		switch changeCause {
+		case proposedChange:
+			buf.WriteString(fmt.Sprintf("[bold]  # %s[reset] will be updated in-place", dispAddr))
+		case detectedDrift:
+			buf.WriteString(fmt.Sprintf("[bold]  # %s[reset] has changed", dispAddr))
+		default:
+			buf.WriteString(fmt.Sprintf("[bold]  # %s[reset] update (unknown reason %s)", dispAddr, changeCause))
+		}
+	case plans.CreateThenDelete, plans.DeleteThenCreate:
+		switch resource.ActionReason {
+		case jsonplan.ResourceInstanceReplaceBecauseTainted:
+			buf.WriteString(fmt.Sprintf("[bold]  # %s[reset] is tainted, so must be [bold][red]replaced[reset]", dispAddr))
+		case jsonplan.ResourceInstanceReplaceByRequest:
+			buf.WriteString(fmt.Sprintf("[bold]  # %s[reset] will be [bold][red]replaced[reset], as requested", dispAddr))
+		case jsonplan.ResourceInstanceReplaceByTriggers:
+			buf.WriteString(fmt.Sprintf("[bold]  # %s[reset] will be [bold][red]replaced[reset] due to changes in replace_triggered_by", dispAddr))
+		default:
+			buf.WriteString(fmt.Sprintf("[bold]  # %s[reset] must be [bold][red]replaced[reset]", dispAddr))
+		}
+	case plans.Delete:
+		switch changeCause {
+		case proposedChange:
+			buf.WriteString(fmt.Sprintf("[bold]  # %s[reset] will be [bold][red]destroyed[reset]", dispAddr))
+		case detectedDrift:
+			buf.WriteString(fmt.Sprintf("[bold]  # %s[reset] has been deleted", dispAddr))
+		default:
+			buf.WriteString(fmt.Sprintf("[bold]  # %s[reset] delete (unknown reason %s)", dispAddr, changeCause))
+		}
+		// We can sometimes give some additional detail about why we're
+		// proposing to delete. We show this as additional notes, rather than
+		// as additional wording in the main action statement, in an attempt
+		// to make the "will be destroyed" message prominent and consistent
+		// in all cases, for easier scanning of this often-risky action.
+		switch resource.ActionReason {
+		case jsonplan.ResourceInstanceDeleteBecauseNoResourceConfig:
+			buf.WriteString(fmt.Sprintf("\n  # (because %s.%s is not in configuration)", resource.Type, resource.Name))
+		case jsonplan.ResourceInstanceDeleteBecauseNoMoveTarget:
+			buf.WriteString(fmt.Sprintf("\n  # (because %s was moved to %s, which is not in configuration)", resource.PreviousAddress, resource.Address))
+		case jsonplan.ResourceInstanceDeleteBecauseNoModule:
+			// FIXME: Ideally we'd truncate addr.Module to reflect the earliest
+			// step that doesn't exist, so it's clearer which call this refers
+			// to, but we don't have enough information out here in the UI layer
+			// to decide that; only the "expander" in Terraform Core knows
+			// which module instance keys are actually declared.
+			buf.WriteString(fmt.Sprintf("\n  # (because %s is not in configuration)", resource.ModuleAddress))
+		case jsonplan.ResourceInstanceDeleteBecauseWrongRepetition:
+			var index interface{}
+			if resource.Index != nil {
+				if err := json.Unmarshal(resource.Index, &index); err != nil {
+					panic(err)
+				}
+			}
+
+			// We have some different variations of this one
+			switch index.(type) {
+			case nil:
+				buf.WriteString("\n  # (because resource uses count or for_each)")
+			case float64:
+				buf.WriteString("\n  # (because resource does not use count)")
+			case string:
+				buf.WriteString("\n  # (because resource does not use for_each)")
+			}
+		case jsonplan.ResourceInstanceDeleteBecauseCountIndex:
+			buf.WriteString(fmt.Sprintf("\n  # (because index [%s] is out of range for count)", resource.Index))
+		case jsonplan.ResourceInstanceDeleteBecauseEachKey:
+			buf.WriteString(fmt.Sprintf("\n  # (because key [%s] is not in for_each map)", resource.Index))
+		}
+		if len(resource.Deposed) != 0 {
+			// Some extra context about this unusual situation.
+			buf.WriteString("\n  # (left over from a partially-failed replacement of this instance)")
+		}
+	case plans.NoOp:
+		if len(resource.PreviousAddress) > 0 && resource.PreviousAddress != resource.Address {
+			buf.WriteString(fmt.Sprintf("[bold]  # %s[reset] has moved to [bold]%s[reset]", resource.PreviousAddress, dispAddr))
+			printedMoved = true
+			break
+		}
+		if resource.Change.Importing != nil {
+			buf.WriteString(fmt.Sprintf("[bold]  # %s[reset] will be imported", dispAddr))
+			if len(resource.Change.GeneratedConfig) > 0 {
+				buf.WriteString("\n  #[reset] (config will be generated)")
+			}
+			printedImported = true
+			break
+		}
+		fallthrough
+	default:
+		// should never happen, since the above is exhaustive
+		buf.WriteString(fmt.Sprintf("%s has an action the plan renderer doesn't support (this is a bug)", dispAddr))
+	}
+	buf.WriteString("\n")
+
+	if len(resource.PreviousAddress) > 0 && resource.PreviousAddress != resource.Address && !printedMoved {
+		buf.WriteString(fmt.Sprintf("  # [reset](moved from %s)\n", resource.PreviousAddress))
+	}
+	if resource.Change.Importing != nil && !printedImported {
+		// We want to make this as forward compatible as possible, and we know
+		// the ID may be removed from the Importing metadata in favour of
+		// something else.
+		// As Importing metadata is loaded from a JSON struct, the effect of it
+		// being removed in the future will mean this renderer will receive it
+		// as an empty string
+		if len(resource.Change.Importing.ID) > 0 {
+			buf.WriteString(fmt.Sprintf("  # [reset](imported from \"%s\")\n", resource.Change.Importing.ID))
+		} else {
+			// This means we're trying to render a plan from a future version
+			// and we didn't get given the ID. So we'll do our best.
+			buf.WriteString("  # [reset](will be imported first)\n")
+		}
+	}
+	if resource.Change.Importing != nil && (action == plans.CreateThenDelete || action == plans.DeleteThenCreate) {
+		buf.WriteString("  # [reset][yellow]Warning: this will destroy the imported resource[reset]\n")
+	}
+
+	return buf.String()
+}
+
+func resourceChangeHeader(change jsonplan.ResourceChange) string {
+	mode := "resource"
+	if change.Mode != jsonstate.ManagedResourceMode {
+		mode = "data"
+	}
+	return fmt.Sprintf("%s \"%s\" \"%s\"", mode, change.Type, change.Name)
+}
+
+func actionDescription(action plans.Action) string {
+	switch action {
+	case plans.Create:
+		return "  [green]+[reset] create"
+	case plans.Delete:
+		return "  [red]-[reset] destroy"
+	case plans.Update:
+		return "  [yellow]~[reset] update in-place"
+	case plans.CreateThenDelete:
+		return "[green]+[reset]/[red]-[reset] create replacement and then destroy"
+	case plans.DeleteThenCreate:
+		return "[red]-[reset]/[green]+[reset] destroy and then create replacement"
+	case plans.Read:
+		return " [cyan]<=[reset] read (data resources)"
+	default:
+		panic(fmt.Sprintf("unrecognized change type: %s", action.String()))
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/plan_test.go b/v1.5.7/internal/command/jsonformat/plan_test.go
new file mode 100644
index 0000000..061fad6
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/plan_test.go
@@ -0,0 +1,7314 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonformat
+
+import (
+	"encoding/json"
+	"fmt"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/mitchellh/colorstring"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/differ"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path"
+	"github.com/hashicorp/terraform/internal/command/jsonplan"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+func TestRenderHuman_EmptyPlan(t *testing.T) {
+	color := &colorstring.Colorize{Colors: colorstring.DefaultColors, Disable: true}
+	streams, done := terminal.StreamsForTesting(t)
+
+	plan := Plan{}
+
+	renderer := Renderer{Colorize: color, Streams: streams}
+	plan.renderHuman(renderer, plans.NormalMode)
+
+	want := `
+No changes. Your infrastructure matches the configuration.
+
+Terraform has compared your real infrastructure against your configuration
+and found no differences, so no changes are needed.
+`
+
+	got := done(t).Stdout()
+	if diff := cmp.Diff(want, got); len(diff) > 0 {
+		t.Errorf("unexpected output\ngot:\n%s\nwant:\n%s\ndiff:\n%s", got, want, diff)
+	}
+}
+
+func TestRenderHuman_EmptyOutputs(t *testing.T) {
+	color := &colorstring.Colorize{Colors: colorstring.DefaultColors, Disable: true}
+	streams, done := terminal.StreamsForTesting(t)
+
+	outputVal, _ := json.Marshal("some-text")
+	plan := Plan{
+		OutputChanges: map[string]jsonplan.Change{
+			"a_string": {
+				Actions: []string{"no-op"},
+				Before:  outputVal,
+				After:   outputVal,
+			},
+		},
+	}
+
+	renderer := Renderer{Colorize: color, Streams: streams}
+	plan.renderHuman(renderer, plans.NormalMode)
+
+	want := `
+No changes. Your infrastructure matches the configuration.
+
+Terraform has compared your real infrastructure against your configuration
+and found no differences, so no changes are needed.
+`
+
+	got := done(t).Stdout()
+	if diff := cmp.Diff(want, got); len(diff) > 0 {
+		t.Errorf("unexpected output\ngot:\n%s\nwant:\n%s\ndiff:\n%s", got, want, diff)
+	}
+}
+
+func TestRenderHuman_Imports(t *testing.T) {
+	color := &colorstring.Colorize{Colors: colorstring.DefaultColors, Disable: true}
+
+	schemas := map[string]*jsonprovider.Provider{
+		"test": {
+			ResourceSchemas: map[string]*jsonprovider.Schema{
+				"test_resource": {
+					Block: &jsonprovider.Block{
+						Attributes: map[string]*jsonprovider.Attribute{
+							"id": {
+								AttributeType: marshalJson(t, "string"),
+							},
+							"value": {
+								AttributeType: marshalJson(t, "string"),
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	tcs := map[string]struct {
+		plan   Plan
+		output string
+	}{
+		"simple_import": {
+			plan: Plan{
+				ResourceChanges: []jsonplan.ResourceChange{
+					{
+						Address:      "test_resource.resource",
+						Mode:         "managed",
+						Type:         "test_resource",
+						Name:         "resource",
+						ProviderName: "test",
+						Change: jsonplan.Change{
+							Actions: []string{"no-op"},
+							Before: marshalJson(t, map[string]interface{}{
+								"id":    "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+								"value": "Hello, World!",
+							}),
+							After: marshalJson(t, map[string]interface{}{
+								"id":    "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+								"value": "Hello, World!",
+							}),
+							Importing: &jsonplan.Importing{
+								ID: "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+							},
+						},
+					},
+				},
+			},
+			output: `
+Terraform will perform the following actions:
+
+  # test_resource.resource will be imported
+    resource "test_resource" "resource" {
+        id    = "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E"
+        value = "Hello, World!"
+    }
+
+Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.
+`,
+		},
+		"simple_import_with_generated_config": {
+			plan: Plan{
+				ResourceChanges: []jsonplan.ResourceChange{
+					{
+						Address:      "test_resource.resource",
+						Mode:         "managed",
+						Type:         "test_resource",
+						Name:         "resource",
+						ProviderName: "test",
+						Change: jsonplan.Change{
+							Actions: []string{"no-op"},
+							Before: marshalJson(t, map[string]interface{}{
+								"id":    "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+								"value": "Hello, World!",
+							}),
+							After: marshalJson(t, map[string]interface{}{
+								"id":    "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+								"value": "Hello, World!",
+							}),
+							Importing: &jsonplan.Importing{
+								ID: "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+							},
+							GeneratedConfig: `resource "test_resource" "resource" {
+  id = "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E"
+  value = "Hello, World!"
+}`,
+						},
+					},
+				},
+			},
+			output: `
+Terraform will perform the following actions:
+
+  # test_resource.resource will be imported
+  # (config will be generated)
+    resource "test_resource" "resource" {
+        id    = "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E"
+        value = "Hello, World!"
+    }
+
+Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.
+`,
+		},
+		"import_and_move": {
+			plan: Plan{
+				ResourceChanges: []jsonplan.ResourceChange{
+					{
+						Address:         "test_resource.after",
+						PreviousAddress: "test_resource.before",
+						Mode:            "managed",
+						Type:            "test_resource",
+						Name:            "after",
+						ProviderName:    "test",
+						Change: jsonplan.Change{
+							Actions: []string{"no-op"},
+							Before: marshalJson(t, map[string]interface{}{
+								"id":    "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+								"value": "Hello, World!",
+							}),
+							After: marshalJson(t, map[string]interface{}{
+								"id":    "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+								"value": "Hello, World!",
+							}),
+							Importing: &jsonplan.Importing{
+								ID: "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+							},
+						},
+					},
+				},
+			},
+			output: `
+Terraform will perform the following actions:
+
+  # test_resource.before has moved to test_resource.after
+  # (imported from "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E")
+    resource "test_resource" "after" {
+        id    = "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E"
+        value = "Hello, World!"
+    }
+
+Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.
+`,
+		},
+		"import_move_and_update": {
+			plan: Plan{
+				ResourceChanges: []jsonplan.ResourceChange{
+					{
+						Address:         "test_resource.after",
+						PreviousAddress: "test_resource.before",
+						Mode:            "managed",
+						Type:            "test_resource",
+						Name:            "after",
+						ProviderName:    "test",
+						Change: jsonplan.Change{
+							Actions: []string{"update"},
+							Before: marshalJson(t, map[string]interface{}{
+								"id":    "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+								"value": "Hello, World!",
+							}),
+							After: marshalJson(t, map[string]interface{}{
+								"id":    "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+								"value": "Hello, Universe!",
+							}),
+							Importing: &jsonplan.Importing{
+								ID: "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+							},
+						},
+					},
+				},
+			},
+			output: `
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # test_resource.after will be updated in-place
+  # (moved from test_resource.before)
+  # (imported from "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E")
+  ~ resource "test_resource" "after" {
+        id    = "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E"
+      ~ value = "Hello, World!" -> "Hello, Universe!"
+    }
+
+Plan: 1 to import, 0 to add, 1 to change, 0 to destroy.
+`,
+		},
+		"import_and_update": {
+			plan: Plan{
+				ResourceChanges: []jsonplan.ResourceChange{
+					{
+						Address:      "test_resource.resource",
+						Mode:         "managed",
+						Type:         "test_resource",
+						Name:         "resource",
+						ProviderName: "test",
+						Change: jsonplan.Change{
+							Actions: []string{"update"},
+							Before: marshalJson(t, map[string]interface{}{
+								"id":    "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+								"value": "Hello, World!",
+							}),
+							After: marshalJson(t, map[string]interface{}{
+								"id":    "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+								"value": "Hello, Universe!",
+							}),
+							Importing: &jsonplan.Importing{
+								ID: "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+							},
+						},
+					},
+				},
+			},
+			output: `
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # test_resource.resource will be updated in-place
+  # (imported from "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E")
+  ~ resource "test_resource" "resource" {
+        id    = "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E"
+      ~ value = "Hello, World!" -> "Hello, Universe!"
+    }
+
+Plan: 1 to import, 0 to add, 1 to change, 0 to destroy.
+`,
+		},
+		"import_and_update_with_no_id": {
+			plan: Plan{
+				ResourceChanges: []jsonplan.ResourceChange{
+					{
+						Address:      "test_resource.resource",
+						Mode:         "managed",
+						Type:         "test_resource",
+						Name:         "resource",
+						ProviderName: "test",
+						Change: jsonplan.Change{
+							Actions: []string{"update"},
+							Before: marshalJson(t, map[string]interface{}{
+								"id":    "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+								"value": "Hello, World!",
+							}),
+							After: marshalJson(t, map[string]interface{}{
+								"id":    "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+								"value": "Hello, Universe!",
+							}),
+							Importing: &jsonplan.Importing{},
+						},
+					},
+				},
+			},
+			output: `
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # test_resource.resource will be updated in-place
+  # (will be imported first)
+  ~ resource "test_resource" "resource" {
+        id    = "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E"
+      ~ value = "Hello, World!" -> "Hello, Universe!"
+    }
+
+Plan: 1 to import, 0 to add, 1 to change, 0 to destroy.
+`,
+		},
+		"import_and_replace": {
+			plan: Plan{
+				ResourceChanges: []jsonplan.ResourceChange{
+					{
+						Address:      "test_resource.resource",
+						Mode:         "managed",
+						Type:         "test_resource",
+						Name:         "resource",
+						ProviderName: "test",
+						Change: jsonplan.Change{
+							Actions: []string{"create", "delete"},
+							Before: marshalJson(t, map[string]interface{}{
+								"id":    "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+								"value": "Hello, World!",
+							}),
+							After: marshalJson(t, map[string]interface{}{
+								"id":    "9794FB1F-7260-442F-830C-F2D450E90CE3",
+								"value": "Hello, World!",
+							}),
+							ReplacePaths: marshalJson(t, [][]string{{"id"}}),
+							Importing: &jsonplan.Importing{
+								ID: "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E",
+							},
+						},
+						ActionReason: "",
+					},
+				},
+			},
+			output: `
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
++/- create replacement and then destroy
+
+Terraform will perform the following actions:
+
+  # test_resource.resource must be replaced
+  # (imported from "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E")
+  # Warning: this will destroy the imported resource
++/- resource "test_resource" "resource" {
+      ~ id    = "1D5F5E9E-F2E5-401B-9ED5-692A215AC67E" -> "9794FB1F-7260-442F-830C-F2D450E90CE3" # forces replacement
+        value = "Hello, World!"
+    }
+
+Plan: 1 to import, 1 to add, 0 to change, 1 to destroy.
+`,
+		},
+	}
+	for name, tc := range tcs {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+
+			plan := tc.plan
+			plan.PlanFormatVersion = jsonplan.FormatVersion
+			plan.ProviderFormatVersion = jsonprovider.FormatVersion
+			plan.ProviderSchemas = schemas
+
+			renderer := Renderer{
+				Colorize: color,
+				Streams:  streams,
+			}
+			plan.renderHuman(renderer, plans.NormalMode)
+
+			got := done(t).Stdout()
+			want := tc.output
+			if diff := cmp.Diff(want, got); len(diff) > 0 {
+				t.Errorf("unexpected output\ngot:\n%s\nwant:\n%s\ndiff:\n%s", got, want, diff)
+			}
+		})
+	}
+}
+
+func TestResourceChange_primitiveTypes(t *testing.T) {
+	testCases := map[string]testCase{
+		"creation": {
+			Action: plans.Create,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.NullVal(cty.EmptyObject),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Computed: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be created
+  + resource "test_instance" "example" {
+      + id = (known after apply)
+    }`,
+		},
+		"creation (null string)": {
+			Action: plans.Create,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.NullVal(cty.EmptyObject),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"string": cty.StringVal("null"),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"string": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be created
+  + resource "test_instance" "example" {
+      + string = "null"
+    }`,
+		},
+		"creation (null string with extra whitespace)": {
+			Action: plans.Create,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.NullVal(cty.EmptyObject),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"string": cty.StringVal("null "),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"string": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be created
+  + resource "test_instance" "example" {
+      + string = "null "
+    }`,
+		},
+		"creation (object with quoted keys)": {
+			Action: plans.Create,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.NullVal(cty.EmptyObject),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"object": cty.ObjectVal(map[string]cty.Value{
+					"unquoted":   cty.StringVal("value"),
+					"quoted:key": cty.StringVal("some-value"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"object": {Type: cty.Object(map[string]cty.Type{
+						"unquoted":   cty.String,
+						"quoted:key": cty.String,
+					}), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be created
+  + resource "test_instance" "example" {
+      + object = {
+          + "quoted:key" = "some-value"
+          + unquoted     = "value"
+        }
+    }`,
+		},
+		"deletion": {
+			Action: plans.Delete,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("i-02ae66f368e8518a9"),
+			}),
+			After: cty.NullVal(cty.EmptyObject),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Computed: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be destroyed
+  - resource "test_instance" "example" {
+      - id = "i-02ae66f368e8518a9" -> null
+    }`,
+		},
+		"deletion of deposed object": {
+			Action:     plans.Delete,
+			Mode:       addrs.ManagedResourceMode,
+			DeposedKey: states.DeposedKey("byebye"),
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("i-02ae66f368e8518a9"),
+			}),
+			After: cty.NullVal(cty.EmptyObject),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Computed: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example (deposed object byebye) will be destroyed
+  # (left over from a partially-failed replacement of this instance)
+  - resource "test_instance" "example" {
+      - id = "i-02ae66f368e8518a9" -> null
+    }`,
+		},
+		"deletion (empty string)": {
+			Action: plans.Delete,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":                 cty.StringVal("i-02ae66f368e8518a9"),
+				"intentionally_long": cty.StringVal(""),
+			}),
+			After: cty.NullVal(cty.EmptyObject),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":                 {Type: cty.String, Computed: true},
+					"intentionally_long": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be destroyed
+  - resource "test_instance" "example" {
+      - id = "i-02ae66f368e8518a9" -> null
+    }`,
+		},
+		"string in-place update": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Optional: true, Computed: true},
+					"ami": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami = "ami-BEFORE" -> "ami-AFTER"
+        id  = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"update with quoted key": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":       cty.StringVal("i-02ae66f368e8518a9"),
+				"saml:aud": cty.StringVal("https://example.com/saml"),
+				"zeta":     cty.StringVal("alpha"),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":       cty.StringVal("i-02ae66f368e8518a9"),
+				"saml:aud": cty.StringVal("https://saml.example.com"),
+				"zeta":     cty.StringVal("alpha"),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":       {Type: cty.String, Optional: true, Computed: true},
+					"saml:aud": {Type: cty.String, Optional: true},
+					"zeta":     {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+        id         = "i-02ae66f368e8518a9"
+      ~ "saml:aud" = "https://example.com/saml" -> "https://saml.example.com"
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"string force-new update": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Optional: true, Computed: true},
+					"ami": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(cty.Path{
+				cty.GetAttrStep{Name: "ami"},
+			}),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ ami = "ami-BEFORE" -> "ami-AFTER" # forces replacement
+        id  = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"string in-place update (null values)": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":        cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":       cty.StringVal("ami-BEFORE"),
+				"unchanged": cty.NullVal(cty.String),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":        cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":       cty.StringVal("ami-AFTER"),
+				"unchanged": cty.NullVal(cty.String),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"unchanged": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami = "ami-BEFORE" -> "ami-AFTER"
+        id  = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"in-place update of multi-line string field": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("i-02ae66f368e8518a9"),
+				"more_lines": cty.StringVal(`original
+long
+multi-line
+string
+field`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"more_lines": cty.StringVal(`original
+extremely long
+multi-line
+string
+field`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"more_lines": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ more_lines = <<-EOT
+            original
+          - long
+          + extremely long
+            multi-line
+            string
+            field
+        EOT
+    }`,
+		},
+		"addition of multi-line string field": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"more_lines": cty.NullVal(cty.String),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"more_lines": cty.StringVal(`original
+new line`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"more_lines": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      + more_lines = <<-EOT
+            original
+            new line
+        EOT
+    }`,
+		},
+		"force-new update of multi-line string field": {
+			Action: plans.DeleteThenCreate,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"more_lines": cty.StringVal(`original`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"more_lines": cty.StringVal(`original
+new line`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"more_lines": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(cty.Path{
+				cty.GetAttrStep{Name: "more_lines"},
+			}),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ more_lines = <<-EOT # forces replacement
+            original
+          + new line
+        EOT
+    }`,
+		},
+
+		// Sensitive
+
+		"creation with sensitive field": {
+			Action: plans.Create,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.NullVal(cty.EmptyObject),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":       cty.UnknownVal(cty.String),
+				"password": cty.StringVal("top-secret"),
+				"conn_info": cty.ObjectVal(map[string]cty.Value{
+					"user":     cty.StringVal("not-secret"),
+					"password": cty.StringVal("top-secret"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":       {Type: cty.String, Computed: true},
+					"password": {Type: cty.String, Optional: true, Sensitive: true},
+					"conn_info": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSingle,
+							Attributes: map[string]*configschema.Attribute{
+								"user":     {Type: cty.String, Optional: true},
+								"password": {Type: cty.String, Optional: true, Sensitive: true},
+							},
+						},
+					},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be created
+  + resource "test_instance" "example" {
+      + conn_info = {
+          + password = (sensitive value)
+          + user     = "not-secret"
+        }
+      + id        = (known after apply)
+      + password  = (sensitive value)
+    }`,
+		},
+		"update with equal sensitive field": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":       cty.StringVal("blah"),
+				"str":      cty.StringVal("before"),
+				"password": cty.StringVal("top-secret"),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":       cty.UnknownVal(cty.String),
+				"str":      cty.StringVal("after"),
+				"password": cty.StringVal("top-secret"),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":       {Type: cty.String, Computed: true},
+					"str":      {Type: cty.String, Optional: true},
+					"password": {Type: cty.String, Optional: true, Sensitive: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id       = "blah" -> (known after apply)
+      ~ str      = "before" -> "after"
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+
+		// tainted objects
+		"replace tainted resource": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseTainted,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-AFTER"),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Optional: true, Computed: true},
+					"ami": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(cty.Path{
+				cty.GetAttrStep{Name: "ami"},
+			}),
+			ExpectedOutput: `  # test_instance.example is tainted, so must be replaced
+-/+ resource "test_instance" "example" {
+      ~ ami = "ami-BEFORE" -> "ami-AFTER" # forces replacement
+      ~ id  = "i-02ae66f368e8518a9" -> (known after apply)
+    }`,
+		},
+		"force replacement with empty before value": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"name":   cty.StringVal("name"),
+				"forced": cty.NullVal(cty.String),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"name":   cty.StringVal("name"),
+				"forced": cty.StringVal("example"),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"name":   {Type: cty.String, Optional: true},
+					"forced": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(cty.Path{
+				cty.GetAttrStep{Name: "forced"},
+			}),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      + forced = "example" # forces replacement
+        name   = "name"
+    }`,
+		},
+		"force replacement with empty before value legacy": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"name":   cty.StringVal("name"),
+				"forced": cty.StringVal(""),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"name":   cty.StringVal("name"),
+				"forced": cty.StringVal("example"),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"name":   {Type: cty.String, Optional: true},
+					"forced": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(cty.Path{
+				cty.GetAttrStep{Name: "forced"},
+			}),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      + forced = "example" # forces replacement
+        name   = "name"
+    }`,
+		},
+		"read during apply because of unknown configuration": {
+			Action:       plans.Read,
+			ActionReason: plans.ResourceInstanceReadBecauseConfigUnknown,
+			Mode:         addrs.DataResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("name"),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("name"),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"name": {Type: cty.String, Optional: true},
+				},
+			},
+			ExpectedOutput: `  # data.test_instance.example will be read during apply
+  # (config refers to values not yet known)
+ <= data "test_instance" "example" {
+        name = "name"
+    }`,
+		},
+		"read during apply because of pending changes to upstream dependency": {
+			Action:       plans.Read,
+			ActionReason: plans.ResourceInstanceReadBecauseDependencyPending,
+			Mode:         addrs.DataResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("name"),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("name"),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"name": {Type: cty.String, Optional: true},
+				},
+			},
+			ExpectedOutput: `  # data.test_instance.example will be read during apply
+  # (depends on a resource or a module with changes pending)
+ <= data "test_instance" "example" {
+        name = "name"
+    }`,
+		},
+		"read during apply for unspecified reason": {
+			Action: plans.Read,
+			Mode:   addrs.DataResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("name"),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("name"),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"name": {Type: cty.String, Optional: true},
+				},
+			},
+			ExpectedOutput: `  # data.test_instance.example will be read during apply
+ <= data "test_instance" "example" {
+        name = "name"
+    }`,
+		},
+		"show all identifying attributes even if unchanged": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":  cty.StringVal("ami-BEFORE"),
+				"bar":  cty.StringVal("bar"),
+				"foo":  cty.StringVal("foo"),
+				"name": cty.StringVal("alice"),
+				"tags": cty.MapVal(map[string]cty.Value{
+					"name": cty.StringVal("bob"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":  cty.StringVal("ami-AFTER"),
+				"bar":  cty.StringVal("bar"),
+				"foo":  cty.StringVal("foo"),
+				"name": cty.StringVal("alice"),
+				"tags": cty.MapVal(map[string]cty.Value{
+					"name": cty.StringVal("bob"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":   {Type: cty.String, Optional: true, Computed: true},
+					"ami":  {Type: cty.String, Optional: true},
+					"bar":  {Type: cty.String, Optional: true},
+					"foo":  {Type: cty.String, Optional: true},
+					"name": {Type: cty.String, Optional: true},
+					"tags": {Type: cty.Map(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami  = "ami-BEFORE" -> "ami-AFTER"
+        id   = "i-02ae66f368e8518a9"
+        name = "alice"
+        tags = {
+            "name" = "bob"
+        }
+        # (2 unchanged attributes hidden)
+    }`,
+		},
+	}
+
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_JSON(t *testing.T) {
+	testCases := map[string]testCase{
+		"creation": {
+			Action: plans.Create,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.NullVal(cty.EmptyObject),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`{
+					"str": "value",
+					"list":["a","b", 234, true],
+					"obj": {"key": "val"}
+				}`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be created
+  + resource "test_instance" "example" {
+      + id         = (known after apply)
+      + json_field = jsonencode(
+            {
+              + list = [
+                  + "a",
+                  + "b",
+                  + 234,
+                  + true,
+                ]
+              + obj  = {
+                  + key = "val"
+                }
+              + str  = "value"
+            }
+        )
+    }`,
+		},
+		"in-place update of object": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`{"aaa": "value","ccc": 5}`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`{"aaa": "value", "bbb": "new_value"}`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode(
+          ~ {
+              + bbb = "new_value"
+              - ccc = 5
+                # (1 unchanged attribute hidden)
+            }
+        )
+    }`,
+		},
+		"in-place update of object with quoted keys": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`{"aaa": "value", "c:c": "old_value"}`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`{"aaa": "value", "b:bb": "new_value"}`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode(
+          ~ {
+              + "b:bb" = "new_value"
+              - "c:c"  = "old_value"
+                # (1 unchanged attribute hidden)
+            }
+        )
+    }`,
+		},
+		"in-place update (from empty tuple)": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`{"aaa": []}`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`{"aaa": ["value"]}`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode(
+          ~ {
+              ~ aaa = [
+                  + "value",
+                ]
+            }
+        )
+    }`,
+		},
+		"in-place update (to empty tuple)": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`{"aaa": ["value"]}`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`{"aaa": []}`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode(
+          ~ {
+              ~ aaa = [
+                  - "value",
+                ]
+            }
+        )
+    }`,
+		},
+		"in-place update (tuple of different types)": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`{"aaa": [42, {"foo":"bar"}, "value"]}`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`{"aaa": [42, {"foo":"baz"}, "value"]}`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode(
+          ~ {
+              ~ aaa = [
+                    42,
+                  ~ {
+                      ~ foo = "bar" -> "baz"
+                    },
+                    "value",
+                ]
+            }
+        )
+    }`,
+		},
+		"force-new update": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`{"aaa": "value"}`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`{"aaa": "value", "bbb": "new_value"}`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(cty.Path{
+				cty.GetAttrStep{Name: "json_field"},
+			}),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode(
+          ~ {
+              + bbb = "new_value"
+                # (1 unchanged attribute hidden)
+            } # forces replacement
+        )
+    }`,
+		},
+		"in-place update (whitespace change)": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`{"aaa": "value", "bbb": "another"}`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`{"aaa":"value",
+					"bbb":"another"}`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode( # whitespace changes
+            {
+                aaa = "value"
+                bbb = "another"
+            }
+        )
+    }`,
+		},
+		"force-new update (whitespace change)": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`{"aaa": "value", "bbb": "another"}`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`{"aaa":"value",
+					"bbb":"another"}`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(cty.Path{
+				cty.GetAttrStep{Name: "json_field"},
+			}),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode( # whitespace changes force replacement
+            {
+                aaa = "value"
+                bbb = "another"
+            }
+        )
+    }`,
+		},
+		"creation (empty)": {
+			Action: plans.Create,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.NullVal(cty.EmptyObject),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`{}`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be created
+  + resource "test_instance" "example" {
+      + id         = (known after apply)
+      + json_field = jsonencode({})
+    }`,
+		},
+		"JSON list item removal": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`["first","second","third"]`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`["first","second"]`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode(
+          ~ [
+                # (1 unchanged element hidden)
+                "second",
+              - "third",
+            ]
+        )
+    }`,
+		},
+		"JSON list item addition": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`["first","second"]`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`["first","second","third"]`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode(
+          ~ [
+                # (1 unchanged element hidden)
+                "second",
+              + "third",
+            ]
+        )
+    }`,
+		},
+		"JSON list object addition": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`{"first":"111"}`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`{"first":"111","second":"222"}`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode(
+          ~ {
+              + second = "222"
+                # (1 unchanged attribute hidden)
+            }
+        )
+    }`,
+		},
+		"JSON object with nested list": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`{
+		  "Statement": ["first"]
+		}`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`{
+		  "Statement": ["first", "second"]
+		}`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode(
+          ~ {
+              ~ Statement = [
+                    "first",
+                  + "second",
+                ]
+            }
+        )
+    }`,
+		},
+		"JSON list of objects - adding item": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`[{"one": "111"}]`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`[{"one": "111"}, {"two": "222"}]`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode(
+          ~ [
+                {
+                    one = "111"
+                },
+              + {
+                  + two = "222"
+                },
+            ]
+        )
+    }`,
+		},
+		"JSON list of objects - removing item": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`[{"one": "111"}, {"two": "222"}, {"three": "333"}]`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`[{"one": "111"}, {"three": "333"}]`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode(
+          ~ [
+                {
+                    one = "111"
+                },
+              - {
+                  - two = "222"
+                },
+                {
+                    three = "333"
+                },
+            ]
+        )
+    }`,
+		},
+		"JSON object with list of objects": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`{"parent":[{"one": "111"}]}`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`{"parent":[{"one": "111"}, {"two": "222"}]}`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode(
+          ~ {
+              ~ parent = [
+                    {
+                        one = "111"
+                    },
+                  + {
+                      + two = "222"
+                    },
+                ]
+            }
+        )
+    }`,
+		},
+		"JSON object double nested lists": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`{"parent":[{"another_list": ["111"]}]}`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`{"parent":[{"another_list": ["111", "222"]}]}`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode(
+          ~ {
+              ~ parent = [
+                  ~ {
+                      ~ another_list = [
+                            "111",
+                          + "222",
+                        ]
+                    },
+                ]
+            }
+        )
+    }`,
+		},
+		"in-place update from object to tuple": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"json_field": cty.StringVal(`{"aaa": [42, {"foo":"bar"}, "value"]}`),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"json_field": cty.StringVal(`["aaa", 42, "something"]`),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"json_field": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ json_field = jsonencode(
+          ~ {
+              - aaa = [
+                  - 42,
+                  - {
+                      - foo = "bar"
+                    },
+                  - "value",
+                ]
+            } -> [
+              + "aaa",
+              + 42,
+              + "something",
+            ]
+        )
+    }`,
+		},
+	}
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_listObject(t *testing.T) {
+	testCases := map[string]testCase{
+		// https://github.com/hashicorp/terraform/issues/30641
+		"updating non-identifying attribute": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("i-02ae66f368e8518a9"),
+				"accounts": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"id":     cty.StringVal("1"),
+						"name":   cty.StringVal("production"),
+						"status": cty.StringVal("ACTIVE"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"id":     cty.StringVal("2"),
+						"name":   cty.StringVal("staging"),
+						"status": cty.StringVal("ACTIVE"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"id":     cty.StringVal("3"),
+						"name":   cty.StringVal("disaster-recovery"),
+						"status": cty.StringVal("ACTIVE"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"accounts": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"id":     cty.StringVal("1"),
+						"name":   cty.StringVal("production"),
+						"status": cty.StringVal("ACTIVE"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"id":     cty.StringVal("2"),
+						"name":   cty.StringVal("staging"),
+						"status": cty.StringVal("EXPLODED"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"id":     cty.StringVal("3"),
+						"name":   cty.StringVal("disaster-recovery"),
+						"status": cty.StringVal("ACTIVE"),
+					}),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Optional: true, Computed: true},
+					"accounts": {
+						Type: cty.List(cty.Object(map[string]cty.Type{
+							"id":     cty.String,
+							"name":   cty.String,
+							"status": cty.String,
+						})),
+					},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ accounts = [
+            {
+                id     = "1"
+                name   = "production"
+                status = "ACTIVE"
+            },
+          ~ {
+                id     = "2"
+                name   = "staging"
+              ~ status = "ACTIVE" -> "EXPLODED"
+            },
+            {
+                id     = "3"
+                name   = "disaster-recovery"
+                status = "ACTIVE"
+            },
+        ]
+      ~ id       = "i-02ae66f368e8518a9" -> (known after apply)
+    }`,
+		},
+	}
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_primitiveList(t *testing.T) {
+	testCases := map[string]testCase{
+		"in-place update - creation": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":        cty.StringVal("ami-STATIC"),
+				"list_field": cty.NullVal(cty.List(cty.String)),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("new-element"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"ami":        {Type: cty.String, Optional: true},
+					"list_field": {Type: cty.List(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      + list_field = [
+          + "new-element",
+        ]
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"in-place update - first addition": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":        cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListValEmpty(cty.String),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("new-element"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"ami":        {Type: cty.String, Optional: true},
+					"list_field": {Type: cty.List(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ list_field = [
+          + "new-element",
+        ]
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"in-place update - insertion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("bbbb"),
+					cty.StringVal("dddd"),
+					cty.StringVal("eeee"),
+					cty.StringVal("ffff"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("bbbb"),
+					cty.StringVal("cccc"),
+					cty.StringVal("dddd"),
+					cty.StringVal("eeee"),
+					cty.StringVal("ffff"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"ami":        {Type: cty.String, Optional: true},
+					"list_field": {Type: cty.List(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ list_field = [
+            # (1 unchanged element hidden)
+            "bbbb",
+          + "cccc",
+            "dddd",
+            # (2 unchanged elements hidden)
+        ]
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"force-new update - insertion": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("cccc"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("bbbb"),
+					cty.StringVal("cccc"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"ami":        {Type: cty.String, Optional: true},
+					"list_field": {Type: cty.List(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(cty.Path{
+				cty.GetAttrStep{Name: "list_field"},
+			}),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ list_field = [ # forces replacement
+            "aaaa",
+          + "bbbb",
+            "cccc",
+        ]
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"in-place update - deletion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("bbbb"),
+					cty.StringVal("cccc"),
+					cty.StringVal("dddd"),
+					cty.StringVal("eeee"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("bbbb"),
+					cty.StringVal("dddd"),
+					cty.StringVal("eeee"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"ami":        {Type: cty.String, Optional: true},
+					"list_field": {Type: cty.List(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ list_field = [
+          - "aaaa",
+            "bbbb",
+          - "cccc",
+            "dddd",
+            # (1 unchanged element hidden)
+        ]
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"creation - empty list": {
+			Action: plans.Create,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.NullVal(cty.EmptyObject),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"ami":        cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListValEmpty(cty.String),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"ami":        {Type: cty.String, Optional: true},
+					"list_field": {Type: cty.List(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be created
+  + resource "test_instance" "example" {
+      + ami        = "ami-STATIC"
+      + id         = (known after apply)
+      + list_field = []
+    }`,
+		},
+		"in-place update - full to empty": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("bbbb"),
+					cty.StringVal("cccc"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"ami":        cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListValEmpty(cty.String),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"ami":        {Type: cty.String, Optional: true},
+					"list_field": {Type: cty.List(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ list_field = [
+          - "aaaa",
+          - "bbbb",
+          - "cccc",
+        ]
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"in-place update - null to empty": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":        cty.StringVal("ami-STATIC"),
+				"list_field": cty.NullVal(cty.List(cty.String)),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"ami":        cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListValEmpty(cty.String),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"ami":        {Type: cty.String, Optional: true},
+					"list_field": {Type: cty.List(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      + list_field = []
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"update to unknown element": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("bbbb"),
+					cty.StringVal("cccc"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.UnknownVal(cty.String),
+					cty.StringVal("cccc"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"ami":        {Type: cty.String, Optional: true},
+					"list_field": {Type: cty.List(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ list_field = [
+            "aaaa",
+          - "bbbb",
+          + (known after apply),
+            "cccc",
+        ]
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"update - two new unknown elements": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("bbbb"),
+					cty.StringVal("cccc"),
+					cty.StringVal("dddd"),
+					cty.StringVal("eeee"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.UnknownVal(cty.String),
+					cty.UnknownVal(cty.String),
+					cty.StringVal("cccc"),
+					cty.StringVal("dddd"),
+					cty.StringVal("eeee"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"ami":        {Type: cty.String, Optional: true},
+					"list_field": {Type: cty.List(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id         = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ list_field = [
+            "aaaa",
+          - "bbbb",
+          + (known after apply),
+          + (known after apply),
+            "cccc",
+            # (2 unchanged elements hidden)
+        ]
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+	}
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_primitiveTuple(t *testing.T) {
+	testCases := map[string]testCase{
+		"in-place update": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("i-02ae66f368e8518a9"),
+				"tuple_field": cty.TupleVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("bbbb"),
+					cty.StringVal("dddd"),
+					cty.StringVal("eeee"),
+					cty.StringVal("ffff"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("i-02ae66f368e8518a9"),
+				"tuple_field": cty.TupleVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("bbbb"),
+					cty.StringVal("cccc"),
+					cty.StringVal("eeee"),
+					cty.StringVal("ffff"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":          {Type: cty.String, Required: true},
+					"tuple_field": {Type: cty.Tuple([]cty.Type{cty.String, cty.String, cty.String, cty.String, cty.String}), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+        id          = "i-02ae66f368e8518a9"
+      ~ tuple_field = [
+            # (1 unchanged element hidden)
+            "bbbb",
+          ~ "dddd" -> "cccc",
+            "eeee",
+            # (1 unchanged element hidden)
+        ]
+    }`,
+		},
+	}
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_primitiveSet(t *testing.T) {
+	testCases := map[string]testCase{
+		"in-place update - creation": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":        cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":       cty.StringVal("ami-STATIC"),
+				"set_field": cty.NullVal(cty.Set(cty.String)),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetVal([]cty.Value{
+					cty.StringVal("new-element"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"set_field": {Type: cty.Set(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id        = "i-02ae66f368e8518a9" -> (known after apply)
+      + set_field = [
+          + "new-element",
+        ]
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"in-place update - first insertion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":        cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":       cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetValEmpty(cty.String),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetVal([]cty.Value{
+					cty.StringVal("new-element"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"set_field": {Type: cty.Set(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id        = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ set_field = [
+          + "new-element",
+        ]
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"in-place update - insertion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("cccc"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("bbbb"),
+					cty.StringVal("cccc"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"set_field": {Type: cty.Set(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id        = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ set_field = [
+          + "bbbb",
+            # (2 unchanged elements hidden)
+        ]
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"force-new update - insertion": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("cccc"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("bbbb"),
+					cty.StringVal("cccc"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"set_field": {Type: cty.Set(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(cty.Path{
+				cty.GetAttrStep{Name: "set_field"},
+			}),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ id        = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ set_field = [ # forces replacement
+          + "bbbb",
+            # (2 unchanged elements hidden)
+        ]
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"in-place update - deletion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("bbbb"),
+					cty.StringVal("cccc"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetVal([]cty.Value{
+					cty.StringVal("bbbb"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"set_field": {Type: cty.Set(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id        = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ set_field = [
+          - "aaaa",
+          - "cccc",
+            # (1 unchanged element hidden)
+        ]
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"creation - empty set": {
+			Action: plans.Create,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.NullVal(cty.EmptyObject),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":        cty.UnknownVal(cty.String),
+				"ami":       cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetValEmpty(cty.String),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"set_field": {Type: cty.Set(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be created
+  + resource "test_instance" "example" {
+      + ami       = "ami-STATIC"
+      + id        = (known after apply)
+      + set_field = []
+    }`,
+		},
+		"in-place update - full to empty set": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("bbbb"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":        cty.UnknownVal(cty.String),
+				"ami":       cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetValEmpty(cty.String),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"set_field": {Type: cty.Set(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id        = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ set_field = [
+          - "aaaa",
+          - "bbbb",
+        ]
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"in-place update - null to empty set": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":        cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":       cty.StringVal("ami-STATIC"),
+				"set_field": cty.NullVal(cty.Set(cty.String)),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":        cty.UnknownVal(cty.String),
+				"ami":       cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetValEmpty(cty.String),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"set_field": {Type: cty.Set(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id        = "i-02ae66f368e8518a9" -> (known after apply)
+      + set_field = []
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"in-place update to unknown": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("bbbb"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":        cty.UnknownVal(cty.String),
+				"ami":       cty.StringVal("ami-STATIC"),
+				"set_field": cty.UnknownVal(cty.Set(cty.String)),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"set_field": {Type: cty.Set(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id        = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ set_field = [
+          - "aaaa",
+          - "bbbb",
+        ] -> (known after apply)
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"in-place update to unknown element": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.StringVal("bbbb"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"set_field": cty.SetVal([]cty.Value{
+					cty.StringVal("aaaa"),
+					cty.UnknownVal(cty.String),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"set_field": {Type: cty.Set(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id        = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ set_field = [
+          - "bbbb",
+          + (known after apply),
+            # (1 unchanged element hidden)
+        ]
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+	}
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_map(t *testing.T) {
+	testCases := map[string]testCase{
+		"in-place update - creation": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":        cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":       cty.StringVal("ami-STATIC"),
+				"map_field": cty.NullVal(cty.Map(cty.String)),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"map_field": cty.MapVal(map[string]cty.Value{
+					"new-key": cty.StringVal("new-element"),
+					"be:ep":   cty.StringVal("boop"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"map_field": {Type: cty.Map(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id        = "i-02ae66f368e8518a9" -> (known after apply)
+      + map_field = {
+          + "be:ep"   = "boop"
+          + "new-key" = "new-element"
+        }
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"in-place update - first insertion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":        cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":       cty.StringVal("ami-STATIC"),
+				"map_field": cty.MapValEmpty(cty.String),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"map_field": cty.MapVal(map[string]cty.Value{
+					"new-key": cty.StringVal("new-element"),
+					"be:ep":   cty.StringVal("boop"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"map_field": {Type: cty.Map(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id        = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ map_field = {
+          + "be:ep"   = "boop"
+          + "new-key" = "new-element"
+        }
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"in-place update - insertion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"map_field": cty.MapVal(map[string]cty.Value{
+					"a": cty.StringVal("aaaa"),
+					"c": cty.StringVal("cccc"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"map_field": cty.MapVal(map[string]cty.Value{
+					"a":   cty.StringVal("aaaa"),
+					"b":   cty.StringVal("bbbb"),
+					"b:b": cty.StringVal("bbbb"),
+					"c":   cty.StringVal("cccc"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"map_field": {Type: cty.Map(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id        = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ map_field = {
+          + "b"   = "bbbb"
+          + "b:b" = "bbbb"
+            # (2 unchanged elements hidden)
+        }
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"force-new update - insertion": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"map_field": cty.MapVal(map[string]cty.Value{
+					"a": cty.StringVal("aaaa"),
+					"c": cty.StringVal("cccc"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"map_field": cty.MapVal(map[string]cty.Value{
+					"a": cty.StringVal("aaaa"),
+					"b": cty.StringVal("bbbb"),
+					"c": cty.StringVal("cccc"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"map_field": {Type: cty.Map(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(cty.Path{
+				cty.GetAttrStep{Name: "map_field"},
+			}),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ id        = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ map_field = { # forces replacement
+          + "b" = "bbbb"
+            # (2 unchanged elements hidden)
+        }
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"in-place update - deletion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"map_field": cty.MapVal(map[string]cty.Value{
+					"a": cty.StringVal("aaaa"),
+					"b": cty.StringVal("bbbb"),
+					"c": cty.StringVal("cccc"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"map_field": cty.MapVal(map[string]cty.Value{
+					"b": cty.StringVal("bbbb"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"map_field": {Type: cty.Map(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id        = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ map_field = {
+          - "a" = "aaaa" -> null
+          - "c" = "cccc" -> null
+            # (1 unchanged element hidden)
+        }
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"creation - empty": {
+			Action: plans.Create,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.NullVal(cty.EmptyObject),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":        cty.UnknownVal(cty.String),
+				"ami":       cty.StringVal("ami-STATIC"),
+				"map_field": cty.MapValEmpty(cty.String),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"map_field": {Type: cty.Map(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be created
+  + resource "test_instance" "example" {
+      + ami       = "ami-STATIC"
+      + id        = (known after apply)
+      + map_field = {}
+    }`,
+		},
+		"update to unknown element": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-STATIC"),
+				"map_field": cty.MapVal(map[string]cty.Value{
+					"a": cty.StringVal("aaaa"),
+					"b": cty.StringVal("bbbb"),
+					"c": cty.StringVal("cccc"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"ami": cty.StringVal("ami-STATIC"),
+				"map_field": cty.MapVal(map[string]cty.Value{
+					"a": cty.StringVal("aaaa"),
+					"b": cty.UnknownVal(cty.String),
+					"c": cty.StringVal("cccc"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":        {Type: cty.String, Optional: true, Computed: true},
+					"ami":       {Type: cty.String, Optional: true},
+					"map_field": {Type: cty.Map(cty.String), Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ id        = "i-02ae66f368e8518a9" -> (known after apply)
+      ~ map_field = {
+          ~ "b" = "bbbb" -> (known after apply)
+            # (2 unchanged elements hidden)
+        }
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+	}
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_nestedList(t *testing.T) {
+	testCases := map[string]testCase{
+		"in-place update - equal": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"root_block_device": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"root_block_device": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingList),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+        id    = "i-02ae66f368e8518a9"
+        # (1 unchanged attribute hidden)
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+		"in-place update - creation": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"root_block_device": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+				})),
+				"disks": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+					"mount_point": cty.StringVal("/var/diska"),
+					"size":        cty.StringVal("50GB"),
+				})}),
+				"root_block_device": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingList),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = [
+          + {
+              + mount_point = "/var/diska"
+              + size        = "50GB"
+            },
+        ]
+        id    = "i-02ae66f368e8518a9"
+
+      + root_block_device {}
+    }`,
+		},
+		"in-place update - first insertion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"root_block_device": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+				})),
+				"disks": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.NullVal(cty.String),
+					}),
+				}),
+				"root_block_device": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingList),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = [
+          + {
+              + mount_point = "/var/diska"
+            },
+        ]
+        id    = "i-02ae66f368e8518a9"
+
+      + root_block_device {
+          + volume_type = "gp2"
+        }
+    }`,
+		},
+		"in-place update - insertion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.NullVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diskb"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diskb"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaPlus(configschema.NestingList),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = [
+          ~ {
+              + size        = "50GB"
+                # (1 unchanged attribute hidden)
+            },
+            # (1 unchanged element hidden)
+        ]
+        id    = "i-02ae66f368e8518a9"
+
+      ~ root_block_device {
+          + new_field   = "new_value"
+            # (1 unchanged attribute hidden)
+        }
+    }`,
+		},
+		"force-new update (inside blocks)": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diskb"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("different"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(
+				cty.Path{
+					cty.GetAttrStep{Name: "root_block_device"},
+					cty.IndexStep{Key: cty.NumberIntVal(0)},
+					cty.GetAttrStep{Name: "volume_type"},
+				},
+				cty.Path{
+					cty.GetAttrStep{Name: "disks"},
+					cty.IndexStep{Key: cty.NumberIntVal(0)},
+					cty.GetAttrStep{Name: "mount_point"},
+				},
+			),
+			Schema: testSchema(configschema.NestingList),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = [
+          ~ {
+              ~ mount_point = "/var/diska" -> "/var/diskb" # forces replacement
+                # (1 unchanged attribute hidden)
+            },
+        ]
+        id    = "i-02ae66f368e8518a9"
+
+      ~ root_block_device {
+          ~ volume_type = "gp2" -> "different" # forces replacement
+        }
+    }`,
+		},
+		"force-new update (whole block)": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diskb"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("different"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(
+				cty.Path{cty.GetAttrStep{Name: "root_block_device"}},
+				cty.Path{cty.GetAttrStep{Name: "disks"}},
+			),
+			Schema: testSchema(configschema.NestingList),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = [ # forces replacement
+          ~ {
+              ~ mount_point = "/var/diska" -> "/var/diskb"
+                # (1 unchanged attribute hidden)
+            },
+        ]
+        id    = "i-02ae66f368e8518a9"
+
+      ~ root_block_device { # forces replacement
+          ~ volume_type = "gp2" -> "different"
+        }
+    }`,
+		},
+		"in-place update - deletion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+				"root_block_device": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+				})),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingList),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = [
+          - {
+              - mount_point = "/var/diska" -> null
+              - size        = "50GB" -> null
+            },
+        ]
+        id    = "i-02ae66f368e8518a9"
+
+      - root_block_device {
+          - volume_type = "gp2" -> null
+        }
+    }`,
+		},
+		"with dynamically-typed attribute": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"block": cty.EmptyTupleVal,
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"block": cty.TupleVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"attr": cty.StringVal("foo"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"attr": cty.True,
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema: &configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"block": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"attr": {Type: cty.DynamicPseudoType, Optional: true},
+							},
+						},
+						Nesting: configschema.NestingList,
+					},
+				},
+			},
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      + block {
+          + attr = "foo"
+        }
+      + block {
+          + attr = true
+        }
+    }`,
+		},
+		"in-place sequence update - deletion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"list": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{"attr": cty.StringVal("x")}),
+					cty.ObjectVal(map[string]cty.Value{"attr": cty.StringVal("y")}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"list": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{"attr": cty.StringVal("y")}),
+					cty.ObjectVal(map[string]cty.Value{"attr": cty.StringVal("z")}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema: &configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"list": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"attr": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+						Nesting: configschema.NestingList,
+					},
+				},
+			},
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ list {
+          ~ attr = "x" -> "y"
+        }
+      ~ list {
+          ~ attr = "y" -> "z"
+        }
+    }`,
+		},
+		"in-place update - unknown": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.UnknownVal(cty.List(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				}))),
+				"root_block_device": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaPlus(configschema.NestingList),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = [
+          - {
+              - mount_point = "/var/diska" -> null
+              - size        = "50GB" -> null
+            },
+        ] -> (known after apply)
+        id    = "i-02ae66f368e8518a9"
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+		"in-place update - modification": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diskb"),
+						"size":        cty.StringVal("50GB"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diskc"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diskb"),
+						"size":        cty.StringVal("75GB"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diskc"),
+						"size":        cty.StringVal("25GB"),
+					}),
+				}),
+				"root_block_device": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaPlus(configschema.NestingList),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = [
+          ~ {
+              ~ size        = "50GB" -> "75GB"
+                # (1 unchanged attribute hidden)
+            },
+          ~ {
+              ~ size        = "50GB" -> "25GB"
+                # (1 unchanged attribute hidden)
+            },
+            # (1 unchanged element hidden)
+        ]
+        id    = "i-02ae66f368e8518a9"
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+	}
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_nestedSet(t *testing.T) {
+	testCases := map[string]testCase{
+		"creation from null - sensitive set": {
+			Action: plans.Create,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.NullVal(cty.Object(map[string]cty.Type{
+				"id":  cty.String,
+				"ami": cty.String,
+				"disks": cty.Set(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+				"root_block_device": cty.Set(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+				})),
+			})),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.NullVal(cty.String),
+					}),
+				}),
+				"root_block_device": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			AfterValMarks: []cty.PathValueMarks{
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "disks"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingSet),
+			ExpectedOutput: `  # test_instance.example will be created
+  + resource "test_instance" "example" {
+      + ami   = "ami-AFTER"
+      + disks = (sensitive value)
+      + id    = "i-02ae66f368e8518a9"
+
+      + root_block_device {
+          + volume_type = "gp2"
+        }
+    }`,
+		},
+		"in-place update - creation": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+				"root_block_device": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+				})),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.NullVal(cty.String),
+					}),
+				}),
+				"root_block_device": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingSet),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = [
+          + {
+              + mount_point = "/var/diska"
+            },
+        ]
+        id    = "i-02ae66f368e8518a9"
+
+      + root_block_device {
+          + volume_type = "gp2"
+        }
+    }`,
+		},
+		"in-place update - creation - sensitive set": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+				"root_block_device": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+				})),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.NullVal(cty.String),
+					}),
+				}),
+				"root_block_device": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			AfterValMarks: []cty.PathValueMarks{
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "disks"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingSet),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      # Warning: this attribute value will be marked as sensitive and will not
+      # display in UI output after applying this change.
+      ~ disks = (sensitive value)
+        id    = "i-02ae66f368e8518a9"
+
+      + root_block_device {
+          + volume_type = "gp2"
+        }
+    }`,
+		},
+		"in-place update - marking set sensitive": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+				})),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+				})),
+			}),
+			AfterValMarks: []cty.PathValueMarks{
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "disks"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingSet),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      # Warning: this attribute value will be marked as sensitive and will not
+      # display in UI output after applying this change. The value is unchanged.
+      ~ disks = (sensitive value)
+        id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"in-place update - insertion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.NullVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diskb"),
+						"size":        cty.StringVal("100GB"),
+					}),
+				}),
+				"root_block_device": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diskb"),
+						"size":        cty.StringVal("100GB"),
+					}),
+				}),
+				"root_block_device": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaPlus(configschema.NestingSet),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = [
+          - {
+              - mount_point = "/var/diska" -> null
+            },
+          + {
+              + mount_point = "/var/diska"
+              + size        = "50GB"
+            },
+            # (1 unchanged element hidden)
+        ]
+        id    = "i-02ae66f368e8518a9"
+
+      - root_block_device {
+          - volume_type = "gp2" -> null
+        }
+      + root_block_device {
+          + new_field   = "new_value"
+          + volume_type = "gp2"
+        }
+    }`,
+		},
+		"force-new update (whole block)": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"root_block_device": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"root_block_device": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("different"),
+					}),
+				}),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diskb"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(
+				cty.Path{cty.GetAttrStep{Name: "root_block_device"}},
+				cty.Path{cty.GetAttrStep{Name: "disks"}},
+			),
+			Schema: testSchema(configschema.NestingSet),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = [
+          - { # forces replacement
+              - mount_point = "/var/diska" -> null
+              - size        = "50GB" -> null
+            },
+          + { # forces replacement
+              + mount_point = "/var/diskb"
+              + size        = "50GB"
+            },
+        ]
+        id    = "i-02ae66f368e8518a9"
+
+      - root_block_device { # forces replacement
+          - volume_type = "gp2" -> null
+        }
+      + root_block_device { # forces replacement
+          + volume_type = "different"
+        }
+    }`,
+		},
+		"in-place update - deletion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"root_block_device": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"root_block_device": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+					"new_field":   cty.String,
+				})),
+				"disks": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaPlus(configschema.NestingSet),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = [
+          - {
+              - mount_point = "/var/diska" -> null
+              - size        = "50GB" -> null
+            },
+        ]
+        id    = "i-02ae66f368e8518a9"
+
+      - root_block_device {
+          - new_field   = "new_value" -> null
+          - volume_type = "gp2" -> null
+        }
+    }`,
+		},
+		"in-place update - empty nested sets": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				}))),
+				"root_block_device": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+				})),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+				"root_block_device": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+				})),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingSet),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      + disks = []
+        id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"in-place update - null insertion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				}))),
+				"root_block_device": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaPlus(configschema.NestingSet),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      + disks = [
+          + {
+              + mount_point = "/var/diska"
+              + size        = "50GB"
+            },
+        ]
+        id    = "i-02ae66f368e8518a9"
+
+      - root_block_device {
+          - volume_type = "gp2" -> null
+        }
+      + root_block_device {
+          + new_field   = "new_value"
+          + volume_type = "gp2"
+        }
+    }`,
+		},
+		"in-place update - unknown": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.UnknownVal(cty.Set(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				}))),
+				"root_block_device": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaPlus(configschema.NestingSet),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = [
+          - {
+              - mount_point = "/var/diska" -> null
+              - size        = "50GB" -> null
+            },
+        ] -> (known after apply)
+        id    = "i-02ae66f368e8518a9"
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+	}
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_nestedMap(t *testing.T) {
+	testCases := map[string]testCase{
+		"creation from null": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.NullVal(cty.String),
+				"ami": cty.NullVal(cty.String),
+				"disks": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				}))),
+				"root_block_device": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+				}))),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.NullVal(cty.String),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      + ami   = "ami-AFTER"
+      + disks = {
+          + "disk_a" = {
+              + mount_point = "/var/diska"
+            },
+        }
+      + id    = "i-02ae66f368e8518a9"
+
+      + root_block_device "a" {
+          + volume_type = "gp2"
+        }
+    }`,
+		},
+		"in-place update - creation": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapValEmpty(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+				"root_block_device": cty.MapValEmpty(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+				})),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.NullVal(cty.String),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = {
+          + "disk_a" = {
+              + mount_point = "/var/diska"
+            },
+        }
+        id    = "i-02ae66f368e8518a9"
+
+      + root_block_device "a" {
+          + volume_type = "gp2"
+        }
+    }`,
+		},
+		"in-place update - change attr": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.NullVal(cty.String),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaPlus(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = {
+          ~ "disk_a" = {
+              + size        = "50GB"
+                # (1 unchanged attribute hidden)
+            },
+        }
+        id    = "i-02ae66f368e8518a9"
+
+      ~ root_block_device "a" {
+          + new_field   = "new_value"
+            # (1 unchanged attribute hidden)
+        }
+    }`,
+		},
+		"in-place update - insertion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+					"disk_2": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/disk2"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.NullVal(cty.String),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaPlus(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = {
+          + "disk_2" = {
+              + mount_point = "/var/disk2"
+              + size        = "50GB"
+            },
+            # (1 unchanged element hidden)
+        }
+        id    = "i-02ae66f368e8518a9"
+
+      + root_block_device "b" {
+          + new_field   = "new_value"
+          + volume_type = "gp2"
+        }
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+		"force-new update (whole block)": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("standard"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("100GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("different"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("standard"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(cty.Path{
+				cty.GetAttrStep{Name: "root_block_device"},
+				cty.IndexStep{Key: cty.StringVal("a")},
+			},
+				cty.Path{cty.GetAttrStep{Name: "disks"}},
+			),
+			Schema: testSchema(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = {
+          ~ "disk_a" = { # forces replacement
+              ~ size        = "50GB" -> "100GB"
+                # (1 unchanged attribute hidden)
+            },
+        }
+        id    = "i-02ae66f368e8518a9"
+
+      ~ root_block_device "a" { # forces replacement
+          ~ volume_type = "gp2" -> "different"
+        }
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+		"in-place update - deletion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapValEmpty(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+				"root_block_device": cty.MapValEmpty(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+					"new_field":   cty.String,
+				})),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaPlus(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = {
+          - "disk_a" = {
+              - mount_point = "/var/diska" -> null
+              - size        = "50GB" -> null
+            },
+        }
+        id    = "i-02ae66f368e8518a9"
+
+      - root_block_device "a" {
+          - new_field   = "new_value" -> null
+          - volume_type = "gp2" -> null
+        }
+    }`,
+		},
+		"in-place update - unknown": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.UnknownVal(cty.Map(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				}))),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaPlus(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = {
+          - "disk_a" = {
+              - mount_point = "/var/diska" -> null
+              - size        = "50GB" -> null
+            },
+        } -> (known after apply)
+        id    = "i-02ae66f368e8518a9"
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+		"in-place update - insertion sensitive": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapValEmpty(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+						"new_field":   cty.StringVal("new_value"),
+					}),
+				}),
+			}),
+			AfterValMarks: []cty.PathValueMarks{
+				{
+					Path: cty.Path{cty.GetAttrStep{Name: "disks"},
+						cty.IndexStep{Key: cty.StringVal("disk_a")},
+						cty.GetAttrStep{Name: "mount_point"},
+					},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaPlus(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = {
+          + "disk_a" = {
+              + mount_point = (sensitive value)
+              + size        = "50GB"
+            },
+        }
+        id    = "i-02ae66f368e8518a9"
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+		"in-place update - multiple unchanged blocks": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+        id    = "i-02ae66f368e8518a9"
+        # (1 unchanged attribute hidden)
+
+        # (2 unchanged blocks hidden)
+    }`,
+		},
+		"in-place update - multiple blocks first changed": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp3"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+        id    = "i-02ae66f368e8518a9"
+        # (1 unchanged attribute hidden)
+
+      ~ root_block_device "b" {
+          ~ volume_type = "gp2" -> "gp3"
+        }
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+		"in-place update - multiple blocks second changed": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp3"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+        id    = "i-02ae66f368e8518a9"
+        # (1 unchanged attribute hidden)
+
+      ~ root_block_device "a" {
+          ~ volume_type = "gp2" -> "gp3"
+        }
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+		"in-place update - multiple blocks changed": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp3"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp3"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+        id    = "i-02ae66f368e8518a9"
+        # (1 unchanged attribute hidden)
+
+      ~ root_block_device "a" {
+          ~ volume_type = "gp2" -> "gp3"
+        }
+      ~ root_block_device "b" {
+          ~ volume_type = "gp2" -> "gp3"
+        }
+    }`,
+		},
+		"in-place update - multiple different unchanged blocks": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+				"leaf_block_device": cty.MapVal(map[string]cty.Value{
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+				"leaf_block_device": cty.MapVal(map[string]cty.Value{
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaMultipleBlocks(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+        id    = "i-02ae66f368e8518a9"
+        # (1 unchanged attribute hidden)
+
+        # (2 unchanged blocks hidden)
+    }`,
+		},
+		"in-place update - multiple different blocks first changed": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+				"leaf_block_device": cty.MapVal(map[string]cty.Value{
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+				"leaf_block_device": cty.MapVal(map[string]cty.Value{
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp3"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaMultipleBlocks(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+        id    = "i-02ae66f368e8518a9"
+        # (1 unchanged attribute hidden)
+
+      ~ leaf_block_device "b" {
+          ~ volume_type = "gp2" -> "gp3"
+        }
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+		"in-place update - multiple different blocks second changed": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+				"leaf_block_device": cty.MapVal(map[string]cty.Value{
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp3"),
+					}),
+				}),
+				"leaf_block_device": cty.MapVal(map[string]cty.Value{
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaMultipleBlocks(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+        id    = "i-02ae66f368e8518a9"
+        # (1 unchanged attribute hidden)
+
+      ~ root_block_device "a" {
+          ~ volume_type = "gp2" -> "gp3"
+        }
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+		"in-place update - multiple different blocks changed": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+				"leaf_block_device": cty.MapVal(map[string]cty.Value{
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp3"),
+					}),
+				}),
+				"leaf_block_device": cty.MapVal(map[string]cty.Value{
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp3"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaMultipleBlocks(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+        id    = "i-02ae66f368e8518a9"
+        # (1 unchanged attribute hidden)
+
+      ~ leaf_block_device "b" {
+          ~ volume_type = "gp2" -> "gp3"
+        }
+
+      ~ root_block_device "a" {
+          ~ volume_type = "gp2" -> "gp3"
+        }
+    }`,
+		},
+		"in-place update - mixed blocks unchanged": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+				"leaf_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+				"leaf_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaMultipleBlocks(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+        id    = "i-02ae66f368e8518a9"
+        # (1 unchanged attribute hidden)
+
+        # (4 unchanged blocks hidden)
+    }`,
+		},
+		"in-place update - mixed blocks changed": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+				"leaf_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+				"root_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp3"),
+					}),
+				}),
+				"leaf_block_device": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp2"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"volume_type": cty.StringVal("gp3"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaMultipleBlocks(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+        id    = "i-02ae66f368e8518a9"
+        # (1 unchanged attribute hidden)
+
+      ~ leaf_block_device "b" {
+          ~ volume_type = "gp2" -> "gp3"
+        }
+
+      ~ root_block_device "b" {
+          ~ volume_type = "gp2" -> "gp3"
+        }
+
+        # (2 unchanged blocks hidden)
+    }`,
+		},
+	}
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_nestedSingle(t *testing.T) {
+	testCases := map[string]testCase{
+		"in-place update - equal": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"root_block_device": cty.ObjectVal(map[string]cty.Value{
+					"volume_type": cty.StringVal("gp2"),
+				}),
+				"disk": cty.ObjectVal(map[string]cty.Value{
+					"mount_point": cty.StringVal("/var/diska"),
+					"size":        cty.StringVal("50GB"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"root_block_device": cty.ObjectVal(map[string]cty.Value{
+					"volume_type": cty.StringVal("gp2"),
+				}),
+				"disk": cty.ObjectVal(map[string]cty.Value{
+					"mount_point": cty.StringVal("/var/diska"),
+					"size":        cty.StringVal("50GB"),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingSingle),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami  = "ami-BEFORE" -> "ami-AFTER"
+        id   = "i-02ae66f368e8518a9"
+        # (1 unchanged attribute hidden)
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+		"in-place update - creation": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"root_block_device": cty.NullVal(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+				})),
+				"disk": cty.NullVal(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disk": cty.ObjectVal(map[string]cty.Value{
+					"mount_point": cty.StringVal("/var/diska"),
+					"size":        cty.StringVal("50GB"),
+				}),
+				"root_block_device": cty.ObjectVal(map[string]cty.Value{
+					"volume_type": cty.NullVal(cty.String),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingSingle),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami  = "ami-BEFORE" -> "ami-AFTER"
+      + disk = {
+          + mount_point = "/var/diska"
+          + size        = "50GB"
+        }
+        id   = "i-02ae66f368e8518a9"
+
+      + root_block_device {}
+    }`,
+		},
+		"force-new update (inside blocks)": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disk": cty.ObjectVal(map[string]cty.Value{
+					"mount_point": cty.StringVal("/var/diska"),
+					"size":        cty.StringVal("50GB"),
+				}),
+				"root_block_device": cty.ObjectVal(map[string]cty.Value{
+					"volume_type": cty.StringVal("gp2"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disk": cty.ObjectVal(map[string]cty.Value{
+					"mount_point": cty.StringVal("/var/diskb"),
+					"size":        cty.StringVal("50GB"),
+				}),
+				"root_block_device": cty.ObjectVal(map[string]cty.Value{
+					"volume_type": cty.StringVal("different"),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(
+				cty.Path{
+					cty.GetAttrStep{Name: "root_block_device"},
+					cty.GetAttrStep{Name: "volume_type"},
+				},
+				cty.Path{
+					cty.GetAttrStep{Name: "disk"},
+					cty.GetAttrStep{Name: "mount_point"},
+				},
+			),
+			Schema: testSchema(configschema.NestingSingle),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ ami  = "ami-BEFORE" -> "ami-AFTER"
+      ~ disk = {
+          ~ mount_point = "/var/diska" -> "/var/diskb" # forces replacement
+            # (1 unchanged attribute hidden)
+        }
+        id   = "i-02ae66f368e8518a9"
+
+      ~ root_block_device {
+          ~ volume_type = "gp2" -> "different" # forces replacement
+        }
+    }`,
+		},
+		"force-new update (whole block)": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disk": cty.ObjectVal(map[string]cty.Value{
+					"mount_point": cty.StringVal("/var/diska"),
+					"size":        cty.StringVal("50GB"),
+				}),
+				"root_block_device": cty.ObjectVal(map[string]cty.Value{
+					"volume_type": cty.StringVal("gp2"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disk": cty.ObjectVal(map[string]cty.Value{
+					"mount_point": cty.StringVal("/var/diskb"),
+					"size":        cty.StringVal("50GB"),
+				}),
+				"root_block_device": cty.ObjectVal(map[string]cty.Value{
+					"volume_type": cty.StringVal("different"),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(
+				cty.Path{cty.GetAttrStep{Name: "root_block_device"}},
+				cty.Path{cty.GetAttrStep{Name: "disk"}},
+			),
+			Schema: testSchema(configschema.NestingSingle),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ ami  = "ami-BEFORE" -> "ami-AFTER"
+      ~ disk = { # forces replacement
+          ~ mount_point = "/var/diska" -> "/var/diskb"
+            # (1 unchanged attribute hidden)
+        }
+        id   = "i-02ae66f368e8518a9"
+
+      ~ root_block_device { # forces replacement
+          ~ volume_type = "gp2" -> "different"
+        }
+    }`,
+		},
+		"in-place update - deletion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disk": cty.ObjectVal(map[string]cty.Value{
+					"mount_point": cty.StringVal("/var/diska"),
+					"size":        cty.StringVal("50GB"),
+				}),
+				"root_block_device": cty.ObjectVal(map[string]cty.Value{
+					"volume_type": cty.StringVal("gp2"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"root_block_device": cty.NullVal(cty.Object(map[string]cty.Type{
+					"volume_type": cty.String,
+				})),
+				"disk": cty.NullVal(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchema(configschema.NestingSingle),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami  = "ami-BEFORE" -> "ami-AFTER"
+      - disk = {
+          - mount_point = "/var/diska" -> null
+          - size        = "50GB" -> null
+        } -> null
+        id   = "i-02ae66f368e8518a9"
+
+      - root_block_device {
+          - volume_type = "gp2" -> null
+        }
+    }`,
+		},
+		"with dynamically-typed attribute": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"block": cty.NullVal(cty.Object(map[string]cty.Type{
+					"attr": cty.String,
+				})),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"block": cty.ObjectVal(map[string]cty.Value{
+					"attr": cty.StringVal("foo"),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema: &configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"block": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"attr": {Type: cty.DynamicPseudoType, Optional: true},
+							},
+						},
+						Nesting: configschema.NestingSingle,
+					},
+				},
+			},
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      + block {
+          + attr = "foo"
+        }
+    }`,
+		},
+		"in-place update - unknown": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disk": cty.ObjectVal(map[string]cty.Value{
+					"mount_point": cty.StringVal("/var/diska"),
+					"size":        cty.StringVal("50GB"),
+				}),
+				"root_block_device": cty.ObjectVal(map[string]cty.Value{
+					"volume_type": cty.StringVal("gp2"),
+					"new_field":   cty.StringVal("new_value"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disk": cty.UnknownVal(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+				"root_block_device": cty.ObjectVal(map[string]cty.Value{
+					"volume_type": cty.StringVal("gp2"),
+					"new_field":   cty.StringVal("new_value"),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaPlus(configschema.NestingSingle),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami  = "ami-BEFORE" -> "ami-AFTER"
+      ~ disk = {
+          ~ mount_point = "/var/diska" -> (known after apply)
+          ~ size        = "50GB" -> (known after apply)
+        } -> (known after apply)
+        id   = "i-02ae66f368e8518a9"
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+		"in-place update - modification": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disk": cty.ObjectVal(map[string]cty.Value{
+					"mount_point": cty.StringVal("/var/diska"),
+					"size":        cty.StringVal("50GB"),
+				}),
+				"root_block_device": cty.ObjectVal(map[string]cty.Value{
+					"volume_type": cty.StringVal("gp2"),
+					"new_field":   cty.StringVal("new_value"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disk": cty.ObjectVal(map[string]cty.Value{
+					"mount_point": cty.StringVal("/var/diska"),
+					"size":        cty.StringVal("25GB"),
+				}),
+				"root_block_device": cty.ObjectVal(map[string]cty.Value{
+					"volume_type": cty.StringVal("gp2"),
+					"new_field":   cty.StringVal("new_value"),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaPlus(configschema.NestingSingle),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami  = "ami-BEFORE" -> "ami-AFTER"
+      ~ disk = {
+          ~ size        = "50GB" -> "25GB"
+            # (1 unchanged attribute hidden)
+        }
+        id   = "i-02ae66f368e8518a9"
+
+        # (1 unchanged block hidden)
+    }`,
+		},
+	}
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_nestedMapSensitiveSchema(t *testing.T) {
+	testCases := map[string]testCase{
+		"creation from null": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.NullVal(cty.String),
+				"ami": cty.NullVal(cty.String),
+				"disks": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				}))),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaSensitive(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      + ami   = "ami-AFTER"
+      + disks = (sensitive value)
+      + id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"in-place update": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapValEmpty(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaSensitive(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = (sensitive value)
+        id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"force-new update (whole block)": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("100GB"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(
+				cty.Path{cty.GetAttrStep{Name: "disks"}},
+			),
+			Schema: testSchemaSensitive(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = (sensitive value) # forces replacement
+        id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"in-place update - deletion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				}))),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaSensitive(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      - disks = (sensitive value) -> null
+        id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"in-place update - unknown": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.MapVal(map[string]cty.Value{
+					"disk_a": cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.UnknownVal(cty.Map(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				}))),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaSensitive(configschema.NestingMap),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = (sensitive value)
+        id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+	}
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_nestedListSensitiveSchema(t *testing.T) {
+	testCases := map[string]testCase{
+		"creation from null": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.NullVal(cty.String),
+				"ami": cty.NullVal(cty.String),
+				"disks": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				}))),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaSensitive(configschema.NestingList),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      + ami   = "ami-AFTER"
+      + disks = (sensitive value)
+      + id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"in-place update": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaSensitive(configschema.NestingList),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = (sensitive value)
+        id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"force-new update (whole block)": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("100GB"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(
+				cty.Path{cty.GetAttrStep{Name: "disks"}},
+			),
+			Schema: testSchemaSensitive(configschema.NestingList),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = (sensitive value) # forces replacement
+        id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"in-place update - deletion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				}))),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaSensitive(configschema.NestingList),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      - disks = (sensitive value) -> null
+        id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"in-place update - unknown": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.UnknownVal(cty.List(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				}))),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaSensitive(configschema.NestingList),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = (sensitive value)
+        id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+	}
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_nestedSetSensitiveSchema(t *testing.T) {
+	testCases := map[string]testCase{
+		"creation from null": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.NullVal(cty.String),
+				"ami": cty.NullVal(cty.String),
+				"disks": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				}))),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaSensitive(configschema.NestingSet),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      + ami   = "ami-AFTER"
+      + disks = (sensitive value)
+      + id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"in-place update": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				})),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaSensitive(configschema.NestingSet),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = (sensitive value)
+        id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"force-new update (whole block)": {
+			Action:       plans.DeleteThenCreate,
+			ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:         addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("100GB"),
+					}),
+				}),
+			}),
+			RequiredReplace: cty.NewPathSet(
+				cty.Path{cty.GetAttrStep{Name: "disks"}},
+			),
+			Schema: testSchemaSensitive(configschema.NestingSet),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = (sensitive value) # forces replacement
+        id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"in-place update - deletion": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				}))),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaSensitive(configschema.NestingSet),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      - disks = (sensitive value) -> null
+        id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"in-place update - unknown": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"disks": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"mount_point": cty.StringVal("/var/diska"),
+						"size":        cty.StringVal("50GB"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"disks": cty.UnknownVal(cty.Set(cty.Object(map[string]cty.Type{
+					"mount_point": cty.String,
+					"size":        cty.String,
+				}))),
+			}),
+			RequiredReplace: cty.NewPathSet(),
+			Schema:          testSchemaSensitive(configschema.NestingSet),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami   = "ami-BEFORE" -> "ami-AFTER"
+      ~ disks = (sensitive value)
+        id    = "i-02ae66f368e8518a9"
+    }`,
+		},
+	}
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_actionReason(t *testing.T) {
+	emptySchema := &configschema.Block{}
+	nullVal := cty.NullVal(cty.EmptyObject)
+	emptyVal := cty.EmptyObjectVal
+
+	testCases := map[string]testCase{
+		"delete for no particular reason": {
+			Action:          plans.Delete,
+			ActionReason:    plans.ResourceInstanceChangeNoReason,
+			Mode:            addrs.ManagedResourceMode,
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be destroyed
+  - resource "test_instance" "example" {}`,
+		},
+		"delete because of wrong repetition mode (NoKey)": {
+			Action:          plans.Delete,
+			ActionReason:    plans.ResourceInstanceDeleteBecauseWrongRepetition,
+			Mode:            addrs.ManagedResourceMode,
+			InstanceKey:     addrs.NoKey,
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be destroyed
+  # (because resource uses count or for_each)
+  - resource "test_instance" "example" {}`,
+		},
+		"delete because of wrong repetition mode (IntKey)": {
+			Action:          plans.Delete,
+			ActionReason:    plans.ResourceInstanceDeleteBecauseWrongRepetition,
+			Mode:            addrs.ManagedResourceMode,
+			InstanceKey:     addrs.IntKey(1),
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example[1] will be destroyed
+  # (because resource does not use count)
+  - resource "test_instance" "example" {}`,
+		},
+		"delete because of wrong repetition mode (StringKey)": {
+			Action:          plans.Delete,
+			ActionReason:    plans.ResourceInstanceDeleteBecauseWrongRepetition,
+			Mode:            addrs.ManagedResourceMode,
+			InstanceKey:     addrs.StringKey("a"),
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example["a"] will be destroyed
+  # (because resource does not use for_each)
+  - resource "test_instance" "example" {}`,
+		},
+		"delete because no resource configuration": {
+			Action:          plans.Delete,
+			ActionReason:    plans.ResourceInstanceDeleteBecauseNoResourceConfig,
+			ModuleInst:      addrs.RootModuleInstance.Child("foo", addrs.NoKey),
+			Mode:            addrs.ManagedResourceMode,
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # module.foo.test_instance.example will be destroyed
+  # (because test_instance.example is not in configuration)
+  - resource "test_instance" "example" {}`,
+		},
+		"delete because no module": {
+			Action:          plans.Delete,
+			ActionReason:    plans.ResourceInstanceDeleteBecauseNoModule,
+			ModuleInst:      addrs.RootModuleInstance.Child("foo", addrs.IntKey(1)),
+			Mode:            addrs.ManagedResourceMode,
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # module.foo[1].test_instance.example will be destroyed
+  # (because module.foo[1] is not in configuration)
+  - resource "test_instance" "example" {}`,
+		},
+		"delete because out of range for count": {
+			Action:          plans.Delete,
+			ActionReason:    plans.ResourceInstanceDeleteBecauseCountIndex,
+			Mode:            addrs.ManagedResourceMode,
+			InstanceKey:     addrs.IntKey(1),
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example[1] will be destroyed
+  # (because index [1] is out of range for count)
+  - resource "test_instance" "example" {}`,
+		},
+		"delete because out of range for for_each": {
+			Action:          plans.Delete,
+			ActionReason:    plans.ResourceInstanceDeleteBecauseEachKey,
+			Mode:            addrs.ManagedResourceMode,
+			InstanceKey:     addrs.StringKey("boop"),
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example["boop"] will be destroyed
+  # (because key ["boop"] is not in for_each map)
+  - resource "test_instance" "example" {}`,
+		},
+		"replace for no particular reason (delete first)": {
+			Action:          plans.DeleteThenCreate,
+			ActionReason:    plans.ResourceInstanceChangeNoReason,
+			Mode:            addrs.ManagedResourceMode,
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {}`,
+		},
+		"replace for no particular reason (create first)": {
+			Action:          plans.CreateThenDelete,
+			ActionReason:    plans.ResourceInstanceChangeNoReason,
+			Mode:            addrs.ManagedResourceMode,
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example must be replaced
++/- resource "test_instance" "example" {}`,
+		},
+		"replace by request (delete first)": {
+			Action:          plans.DeleteThenCreate,
+			ActionReason:    plans.ResourceInstanceReplaceByRequest,
+			Mode:            addrs.ManagedResourceMode,
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be replaced, as requested
+-/+ resource "test_instance" "example" {}`,
+		},
+		"replace by request (create first)": {
+			Action:          plans.CreateThenDelete,
+			ActionReason:    plans.ResourceInstanceReplaceByRequest,
+			Mode:            addrs.ManagedResourceMode,
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be replaced, as requested
++/- resource "test_instance" "example" {}`,
+		},
+		"replace because tainted (delete first)": {
+			Action:          plans.DeleteThenCreate,
+			ActionReason:    plans.ResourceInstanceReplaceBecauseTainted,
+			Mode:            addrs.ManagedResourceMode,
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example is tainted, so must be replaced
+-/+ resource "test_instance" "example" {}`,
+		},
+		"replace because tainted (create first)": {
+			Action:          plans.CreateThenDelete,
+			ActionReason:    plans.ResourceInstanceReplaceBecauseTainted,
+			Mode:            addrs.ManagedResourceMode,
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example is tainted, so must be replaced
++/- resource "test_instance" "example" {}`,
+		},
+		"replace because cannot update (delete first)": {
+			Action:          plans.DeleteThenCreate,
+			ActionReason:    plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:            addrs.ManagedResourceMode,
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			// This one has no special message, because the fuller explanation
+			// typically appears inline as a "# forces replacement" comment.
+			// (not shown here)
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {}`,
+		},
+		"replace because cannot update (create first)": {
+			Action:          plans.CreateThenDelete,
+			ActionReason:    plans.ResourceInstanceReplaceBecauseCannotUpdate,
+			Mode:            addrs.ManagedResourceMode,
+			Before:          emptyVal,
+			After:           nullVal,
+			Schema:          emptySchema,
+			RequiredReplace: cty.NewPathSet(),
+			// This one has no special message, because the fuller explanation
+			// typically appears inline as a "# forces replacement" comment.
+			// (not shown here)
+			ExpectedOutput: `  # test_instance.example must be replaced
++/- resource "test_instance" "example" {}`,
+		},
+	}
+
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_sensitiveVariable(t *testing.T) {
+	testCases := map[string]testCase{
+		"creation": {
+			Action: plans.Create,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.NullVal(cty.EmptyObject),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-123"),
+				"map_key": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.NumberIntVal(800),
+					"dinner":    cty.NumberIntVal(2000),
+				}),
+				"map_whole": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.StringVal("pizza"),
+					"dinner":    cty.StringVal("pizza"),
+				}),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("hello"),
+					cty.StringVal("friends"),
+					cty.StringVal("!"),
+				}),
+				"nested_block_list": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.StringVal("secretval"),
+						"another": cty.StringVal("not secret"),
+					}),
+				}),
+				"nested_block_set": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.StringVal("secretval"),
+						"another": cty.StringVal("not secret"),
+					}),
+				}),
+			}),
+			AfterValMarks: []cty.PathValueMarks{
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "ami"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "list_field"}, cty.IndexStep{Key: cty.NumberIntVal(1)}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "map_whole"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "map_key"}, cty.IndexStep{Key: cty.StringVal("dinner")}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					// Nested blocks/sets will mark the whole set/block as sensitive
+					Path:  cty.Path{cty.GetAttrStep{Name: "nested_block_list"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "nested_block_set"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"ami":        {Type: cty.String, Optional: true},
+					"map_whole":  {Type: cty.Map(cty.String), Optional: true},
+					"map_key":    {Type: cty.Map(cty.Number), Optional: true},
+					"list_field": {Type: cty.List(cty.String), Optional: true},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"nested_block_list": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"an_attr": {Type: cty.String, Optional: true},
+								"another": {Type: cty.String, Optional: true},
+							},
+						},
+						Nesting: configschema.NestingList,
+					},
+					"nested_block_set": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"an_attr": {Type: cty.String, Optional: true},
+								"another": {Type: cty.String, Optional: true},
+							},
+						},
+						Nesting: configschema.NestingSet,
+					},
+				},
+			},
+			ExpectedOutput: `  # test_instance.example will be created
+  + resource "test_instance" "example" {
+      + ami        = (sensitive value)
+      + id         = "i-02ae66f368e8518a9"
+      + list_field = [
+          + "hello",
+          + (sensitive value),
+          + "!",
+        ]
+      + map_key    = {
+          + "breakfast" = 800
+          + "dinner"    = (sensitive value)
+        }
+      + map_whole  = (sensitive value)
+
+      + nested_block_list {
+          # At least one attribute in this block is (or was) sensitive,
+          # so its contents will not be displayed.
+        }
+
+      + nested_block_set {
+          # At least one attribute in this block is (or was) sensitive,
+          # so its contents will not be displayed.
+        }
+    }`,
+		},
+		"in-place update - before sensitive": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":          cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":         cty.StringVal("ami-BEFORE"),
+				"special":     cty.BoolVal(true),
+				"some_number": cty.NumberIntVal(1),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("hello"),
+					cty.StringVal("friends"),
+					cty.StringVal("!"),
+				}),
+				"map_key": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.NumberIntVal(800),
+					"dinner":    cty.NumberIntVal(2000), // sensitive key
+				}),
+				"map_whole": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.StringVal("pizza"),
+					"dinner":    cty.StringVal("pizza"),
+				}),
+				"nested_block": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.StringVal("secretval"),
+					}),
+				}),
+				"nested_block_set": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.StringVal("secretval"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":          cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":         cty.StringVal("ami-AFTER"),
+				"special":     cty.BoolVal(false),
+				"some_number": cty.NumberIntVal(2),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("hello"),
+					cty.StringVal("friends"),
+					cty.StringVal("."),
+				}),
+				"map_key": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.NumberIntVal(800),
+					"dinner":    cty.NumberIntVal(1900),
+				}),
+				"map_whole": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.StringVal("cereal"),
+					"dinner":    cty.StringVal("pizza"),
+				}),
+				"nested_block": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.StringVal("changed"),
+					}),
+				}),
+				"nested_block_set": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.StringVal("changed"),
+					}),
+				}),
+			}),
+			BeforeValMarks: []cty.PathValueMarks{
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "ami"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "special"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "some_number"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "list_field"}, cty.IndexStep{Key: cty.NumberIntVal(2)}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "map_key"}, cty.IndexStep{Key: cty.StringVal("dinner")}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "map_whole"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "nested_block"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "nested_block_set"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":          {Type: cty.String, Optional: true, Computed: true},
+					"ami":         {Type: cty.String, Optional: true},
+					"list_field":  {Type: cty.List(cty.String), Optional: true},
+					"special":     {Type: cty.Bool, Optional: true},
+					"some_number": {Type: cty.Number, Optional: true},
+					"map_key":     {Type: cty.Map(cty.Number), Optional: true},
+					"map_whole":   {Type: cty.Map(cty.String), Optional: true},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"nested_block": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"an_attr": {Type: cty.String, Optional: true},
+							},
+						},
+						Nesting: configschema.NestingList,
+					},
+					"nested_block_set": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"an_attr": {Type: cty.String, Optional: true},
+							},
+						},
+						Nesting: configschema.NestingSet,
+					},
+				},
+			},
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      # Warning: this attribute value will no longer be marked as sensitive
+      # after applying this change.
+      ~ ami         = (sensitive value)
+        id          = "i-02ae66f368e8518a9"
+      ~ list_field  = [
+            # (1 unchanged element hidden)
+            "friends",
+          - (sensitive value),
+          + ".",
+        ]
+      ~ map_key     = {
+          # Warning: this attribute value will no longer be marked as sensitive
+          # after applying this change.
+          ~ "dinner"    = (sensitive value)
+            # (1 unchanged element hidden)
+        }
+      # Warning: this attribute value will no longer be marked as sensitive
+      # after applying this change.
+      ~ map_whole   = (sensitive value)
+      # Warning: this attribute value will no longer be marked as sensitive
+      # after applying this change.
+      ~ some_number = (sensitive value)
+      # Warning: this attribute value will no longer be marked as sensitive
+      # after applying this change.
+      ~ special     = (sensitive value)
+
+      # Warning: this block will no longer be marked as sensitive
+      # after applying this change.
+      ~ nested_block {
+          # At least one attribute in this block is (or was) sensitive,
+          # so its contents will not be displayed.
+        }
+
+      - nested_block_set {
+          # At least one attribute in this block is (or was) sensitive,
+          # so its contents will not be displayed.
+        }
+      + nested_block_set {
+          + an_attr = "changed"
+        }
+    }`,
+		},
+		"in-place update - after sensitive": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("i-02ae66f368e8518a9"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("hello"),
+					cty.StringVal("friends"),
+				}),
+				"map_key": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.NumberIntVal(800),
+					"dinner":    cty.NumberIntVal(2000), // sensitive key
+				}),
+				"map_whole": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.StringVal("pizza"),
+					"dinner":    cty.StringVal("pizza"),
+				}),
+				"nested_block_single": cty.ObjectVal(map[string]cty.Value{
+					"an_attr": cty.StringVal("original"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("i-02ae66f368e8518a9"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("goodbye"),
+					cty.StringVal("friends"),
+				}),
+				"map_key": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.NumberIntVal(700),
+					"dinner":    cty.NumberIntVal(2100), // sensitive key
+				}),
+				"map_whole": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.StringVal("cereal"),
+					"dinner":    cty.StringVal("pizza"),
+				}),
+				"nested_block_single": cty.ObjectVal(map[string]cty.Value{
+					"an_attr": cty.StringVal("changed"),
+				}),
+			}),
+			AfterValMarks: []cty.PathValueMarks{
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "tags"}, cty.IndexStep{Key: cty.StringVal("address")}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "list_field"}, cty.IndexStep{Key: cty.NumberIntVal(0)}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "map_key"}, cty.IndexStep{Key: cty.StringVal("dinner")}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "map_whole"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "nested_block_single"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"list_field": {Type: cty.List(cty.String), Optional: true},
+					"map_key":    {Type: cty.Map(cty.Number), Optional: true},
+					"map_whole":  {Type: cty.Map(cty.String), Optional: true},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"nested_block_single": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"an_attr": {Type: cty.String, Optional: true},
+							},
+						},
+						Nesting: configschema.NestingSingle,
+					},
+				},
+			},
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+        id         = "i-02ae66f368e8518a9"
+      ~ list_field = [
+          - "hello",
+          + (sensitive value),
+            "friends",
+        ]
+      ~ map_key    = {
+          ~ "breakfast" = 800 -> 700
+          # Warning: this attribute value will be marked as sensitive and will not
+          # display in UI output after applying this change.
+          ~ "dinner"    = (sensitive value)
+        }
+      # Warning: this attribute value will be marked as sensitive and will not
+      # display in UI output after applying this change.
+      ~ map_whole  = (sensitive value)
+
+      # Warning: this block will be marked as sensitive and will not
+      # display in UI output after applying this change.
+      ~ nested_block_single {
+          # At least one attribute in this block is (or was) sensitive,
+          # so its contents will not be displayed.
+        }
+    }`,
+		},
+		"in-place update - both sensitive": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("hello"),
+					cty.StringVal("friends"),
+				}),
+				"map_key": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.NumberIntVal(800),
+					"dinner":    cty.NumberIntVal(2000), // sensitive key
+				}),
+				"map_whole": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.StringVal("pizza"),
+					"dinner":    cty.StringVal("pizza"),
+				}),
+				"nested_block_map": cty.MapVal(map[string]cty.Value{
+					"foo": cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.StringVal("original"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("goodbye"),
+					cty.StringVal("friends"),
+				}),
+				"map_key": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.NumberIntVal(800),
+					"dinner":    cty.NumberIntVal(1800), // sensitive key
+				}),
+				"map_whole": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.StringVal("cereal"),
+					"dinner":    cty.StringVal("pizza"),
+				}),
+				"nested_block_map": cty.MapVal(map[string]cty.Value{
+					"foo": cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.UnknownVal(cty.String),
+					}),
+				}),
+			}),
+			BeforeValMarks: []cty.PathValueMarks{
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "ami"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "list_field"}, cty.IndexStep{Key: cty.NumberIntVal(0)}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "map_key"}, cty.IndexStep{Key: cty.StringVal("dinner")}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "map_whole"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "nested_block_map"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			AfterValMarks: []cty.PathValueMarks{
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "ami"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "list_field"}, cty.IndexStep{Key: cty.NumberIntVal(0)}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "map_key"}, cty.IndexStep{Key: cty.StringVal("dinner")}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "map_whole"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "nested_block_map"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"ami":        {Type: cty.String, Optional: true},
+					"list_field": {Type: cty.List(cty.String), Optional: true},
+					"map_key":    {Type: cty.Map(cty.Number), Optional: true},
+					"map_whole":  {Type: cty.Map(cty.String), Optional: true},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"nested_block_map": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"an_attr": {Type: cty.String, Optional: true},
+							},
+						},
+						Nesting: configschema.NestingMap,
+					},
+				},
+			},
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      ~ ami        = (sensitive value)
+        id         = "i-02ae66f368e8518a9"
+      ~ list_field = [
+          - (sensitive value),
+          + (sensitive value),
+            "friends",
+        ]
+      ~ map_key    = {
+          ~ "dinner"    = (sensitive value)
+            # (1 unchanged element hidden)
+        }
+      ~ map_whole  = (sensitive value)
+
+      ~ nested_block_map "foo" {
+          # At least one attribute in this block is (or was) sensitive,
+          # so its contents will not be displayed.
+        }
+    }`,
+		},
+		"in-place update - value unchanged, sensitivity changes": {
+			Action: plans.Update,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":          cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":         cty.StringVal("ami-BEFORE"),
+				"special":     cty.BoolVal(true),
+				"some_number": cty.NumberIntVal(1),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("hello"),
+					cty.StringVal("friends"),
+					cty.StringVal("!"),
+				}),
+				"map_key": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.NumberIntVal(800),
+					"dinner":    cty.NumberIntVal(2000), // sensitive key
+				}),
+				"map_whole": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.StringVal("pizza"),
+					"dinner":    cty.StringVal("pizza"),
+				}),
+				"nested_block": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.StringVal("secretval"),
+					}),
+				}),
+				"nested_block_set": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.StringVal("secretval"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":          cty.StringVal("i-02ae66f368e8518a9"),
+				"ami":         cty.StringVal("ami-BEFORE"),
+				"special":     cty.BoolVal(true),
+				"some_number": cty.NumberIntVal(1),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("hello"),
+					cty.StringVal("friends"),
+					cty.StringVal("!"),
+				}),
+				"map_key": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.NumberIntVal(800),
+					"dinner":    cty.NumberIntVal(2000), // sensitive key
+				}),
+				"map_whole": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.StringVal("pizza"),
+					"dinner":    cty.StringVal("pizza"),
+				}),
+				"nested_block": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.StringVal("secretval"),
+					}),
+				}),
+				"nested_block_set": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.StringVal("secretval"),
+					}),
+				}),
+			}),
+			BeforeValMarks: []cty.PathValueMarks{
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "ami"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "special"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "some_number"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "list_field"}, cty.IndexStep{Key: cty.NumberIntVal(2)}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "map_key"}, cty.IndexStep{Key: cty.StringVal("dinner")}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "map_whole"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "nested_block"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "nested_block_set"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":          {Type: cty.String, Optional: true, Computed: true},
+					"ami":         {Type: cty.String, Optional: true},
+					"list_field":  {Type: cty.List(cty.String), Optional: true},
+					"special":     {Type: cty.Bool, Optional: true},
+					"some_number": {Type: cty.Number, Optional: true},
+					"map_key":     {Type: cty.Map(cty.Number), Optional: true},
+					"map_whole":   {Type: cty.Map(cty.String), Optional: true},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"nested_block": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"an_attr": {Type: cty.String, Optional: true},
+							},
+						},
+						Nesting: configschema.NestingList,
+					},
+					"nested_block_set": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"an_attr": {Type: cty.String, Optional: true},
+							},
+						},
+						Nesting: configschema.NestingSet,
+					},
+				},
+			},
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  ~ resource "test_instance" "example" {
+      # Warning: this attribute value will no longer be marked as sensitive
+      # after applying this change. The value is unchanged.
+      ~ ami         = (sensitive value)
+        id          = "i-02ae66f368e8518a9"
+      ~ list_field  = [
+            # (1 unchanged element hidden)
+            "friends",
+          # Warning: this attribute value will no longer be marked as sensitive
+          # after applying this change. The value is unchanged.
+          ~ (sensitive value),
+        ]
+      ~ map_key     = {
+          # Warning: this attribute value will no longer be marked as sensitive
+          # after applying this change. The value is unchanged.
+          ~ "dinner"    = (sensitive value)
+            # (1 unchanged element hidden)
+        }
+      # Warning: this attribute value will no longer be marked as sensitive
+      # after applying this change. The value is unchanged.
+      ~ map_whole   = (sensitive value)
+      # Warning: this attribute value will no longer be marked as sensitive
+      # after applying this change. The value is unchanged.
+      ~ some_number = (sensitive value)
+      # Warning: this attribute value will no longer be marked as sensitive
+      # after applying this change. The value is unchanged.
+      ~ special     = (sensitive value)
+
+      # Warning: this block will no longer be marked as sensitive
+      # after applying this change.
+      ~ nested_block {
+          # At least one attribute in this block is (or was) sensitive,
+          # so its contents will not be displayed.
+        }
+
+      # Warning: this block will no longer be marked as sensitive
+      # after applying this change.
+      ~ nested_block_set {
+          # At least one attribute in this block is (or was) sensitive,
+          # so its contents will not be displayed.
+        }
+    }`,
+		},
+		"deletion": {
+			Action: plans.Delete,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"list_field": cty.ListVal([]cty.Value{
+					cty.StringVal("hello"),
+					cty.StringVal("friends"),
+				}),
+				"map_key": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.NumberIntVal(800),
+					"dinner":    cty.NumberIntVal(2000), // sensitive key
+				}),
+				"map_whole": cty.MapVal(map[string]cty.Value{
+					"breakfast": cty.StringVal("pizza"),
+					"dinner":    cty.StringVal("pizza"),
+				}),
+				"nested_block": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.StringVal("secret"),
+						"another": cty.StringVal("not secret"),
+					}),
+				}),
+				"nested_block_set": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.StringVal("secret"),
+						"another": cty.StringVal("not secret"),
+					}),
+				}),
+			}),
+			After: cty.NullVal(cty.EmptyObject),
+			BeforeValMarks: []cty.PathValueMarks{
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "ami"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "list_field"}, cty.IndexStep{Key: cty.NumberIntVal(1)}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "map_key"}, cty.IndexStep{Key: cty.StringVal("dinner")}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "map_whole"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "nested_block"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "nested_block_set"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Optional: true, Computed: true},
+					"ami":        {Type: cty.String, Optional: true},
+					"list_field": {Type: cty.List(cty.String), Optional: true},
+					"map_key":    {Type: cty.Map(cty.Number), Optional: true},
+					"map_whole":  {Type: cty.Map(cty.String), Optional: true},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"nested_block_set": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"an_attr": {Type: cty.String, Optional: true},
+								"another": {Type: cty.String, Optional: true},
+							},
+						},
+						Nesting: configschema.NestingSet,
+					},
+				},
+			},
+			ExpectedOutput: `  # test_instance.example will be destroyed
+  - resource "test_instance" "example" {
+      - ami        = (sensitive value) -> null
+      - id         = "i-02ae66f368e8518a9" -> null
+      - list_field = [
+          - "hello",
+          - (sensitive value),
+        ] -> null
+      - map_key    = {
+          - "breakfast" = 800
+          - "dinner"    = (sensitive value)
+        } -> null
+      - map_whole  = (sensitive value) -> null
+
+      - nested_block_set {
+          # At least one attribute in this block is (or was) sensitive,
+          # so its contents will not be displayed.
+        }
+    }`,
+		},
+		"update with sensitive value forcing replacement": {
+			Action: plans.DeleteThenCreate,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+				"nested_block_set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.StringVal("secret"),
+					}),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+				"nested_block_set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"an_attr": cty.StringVal("changed"),
+					}),
+				}),
+			}),
+			BeforeValMarks: []cty.PathValueMarks{
+				{
+					Path:  cty.GetAttrPath("ami"),
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.GetAttrPath("nested_block_set"),
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			AfterValMarks: []cty.PathValueMarks{
+				{
+					Path:  cty.GetAttrPath("ami"),
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				{
+					Path:  cty.GetAttrPath("nested_block_set"),
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Optional: true, Computed: true},
+					"ami": {Type: cty.String, Optional: true},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"nested_block_set": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"an_attr": {Type: cty.String, Required: true},
+							},
+						},
+						Nesting: configschema.NestingSet,
+					},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(
+				cty.GetAttrPath("ami"),
+				cty.GetAttrPath("nested_block_set"),
+			),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ ami = (sensitive value) # forces replacement
+        id  = "i-02ae66f368e8518a9"
+
+      - nested_block_set { # forces replacement
+          # At least one attribute in this block is (or was) sensitive,
+          # so its contents will not be displayed.
+        }
+      + nested_block_set { # forces replacement
+          # At least one attribute in this block is (or was) sensitive,
+          # so its contents will not be displayed.
+        }
+    }`,
+		},
+		"update with sensitive attribute forcing replacement": {
+			Action: plans.DeleteThenCreate,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-BEFORE"),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("i-02ae66f368e8518a9"),
+				"ami": cty.StringVal("ami-AFTER"),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Optional: true, Computed: true},
+					"ami": {Type: cty.String, Optional: true, Computed: true, Sensitive: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(
+				cty.GetAttrPath("ami"),
+			),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ ami = (sensitive value) # forces replacement
+        id  = "i-02ae66f368e8518a9"
+    }`,
+		},
+		"update with sensitive nested type attribute forcing replacement": {
+			Action: plans.DeleteThenCreate,
+			Mode:   addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("i-02ae66f368e8518a9"),
+				"conn_info": cty.ObjectVal(map[string]cty.Value{
+					"user":     cty.StringVal("not-secret"),
+					"password": cty.StringVal("top-secret"),
+				}),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("i-02ae66f368e8518a9"),
+				"conn_info": cty.ObjectVal(map[string]cty.Value{
+					"user":     cty.StringVal("not-secret"),
+					"password": cty.StringVal("new-secret"),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Optional: true, Computed: true},
+					"conn_info": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSingle,
+							Attributes: map[string]*configschema.Attribute{
+								"user":     {Type: cty.String, Optional: true},
+								"password": {Type: cty.String, Optional: true, Sensitive: true},
+							},
+						},
+					},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(
+				cty.GetAttrPath("conn_info"),
+				cty.GetAttrPath("password"),
+			),
+			ExpectedOutput: `  # test_instance.example must be replaced
+-/+ resource "test_instance" "example" {
+      ~ conn_info = { # forces replacement
+          ~ password = (sensitive value)
+            # (1 unchanged attribute hidden)
+        }
+        id        = "i-02ae66f368e8518a9"
+    }`,
+		},
+	}
+	runTestCases(t, testCases)
+}
+
+func TestResourceChange_moved(t *testing.T) {
+	prevRunAddr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "previous",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	testCases := map[string]testCase{
+		"moved and updated": {
+			PrevRunAddr: prevRunAddr,
+			Action:      plans.Update,
+			Mode:        addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("12345"),
+				"foo": cty.StringVal("hello"),
+				"bar": cty.StringVal("baz"),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("12345"),
+				"foo": cty.StringVal("hello"),
+				"bar": cty.StringVal("boop"),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Computed: true},
+					"foo": {Type: cty.String, Optional: true},
+					"bar": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.example will be updated in-place
+  # (moved from test_instance.previous)
+  ~ resource "test_instance" "example" {
+      ~ bar = "baz" -> "boop"
+        id  = "12345"
+        # (1 unchanged attribute hidden)
+    }`,
+		},
+		"moved without changes": {
+			PrevRunAddr: prevRunAddr,
+			Action:      plans.NoOp,
+			Mode:        addrs.ManagedResourceMode,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("12345"),
+				"foo": cty.StringVal("hello"),
+				"bar": cty.StringVal("baz"),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("12345"),
+				"foo": cty.StringVal("hello"),
+				"bar": cty.StringVal("baz"),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Computed: true},
+					"foo": {Type: cty.String, Optional: true},
+					"bar": {Type: cty.String, Optional: true},
+				},
+			},
+			RequiredReplace: cty.NewPathSet(),
+			ExpectedOutput: `  # test_instance.previous has moved to test_instance.example
+    resource "test_instance" "example" {
+        id  = "12345"
+        # (2 unchanged attributes hidden)
+    }`,
+		},
+	}
+
+	runTestCases(t, testCases)
+}
+
+type testCase struct {
+	Action          plans.Action
+	ActionReason    plans.ResourceInstanceChangeActionReason
+	ModuleInst      addrs.ModuleInstance
+	Mode            addrs.ResourceMode
+	InstanceKey     addrs.InstanceKey
+	DeposedKey      states.DeposedKey
+	Before          cty.Value
+	BeforeValMarks  []cty.PathValueMarks
+	AfterValMarks   []cty.PathValueMarks
+	After           cty.Value
+	Schema          *configschema.Block
+	RequiredReplace cty.PathSet
+	ExpectedOutput  string
+	PrevRunAddr     addrs.AbsResourceInstance
+}
+
+func runTestCases(t *testing.T, testCases map[string]testCase) {
+	color := &colorstring.Colorize{Colors: colorstring.DefaultColors, Disable: true}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			ty := tc.Schema.ImpliedType()
+
+			beforeVal := tc.Before
+			switch { // Some fixups to make the test cases a little easier to write
+			case beforeVal.IsNull():
+				beforeVal = cty.NullVal(ty) // allow mistyped nulls
+			case !beforeVal.IsKnown():
+				beforeVal = cty.UnknownVal(ty) // allow mistyped unknowns
+			}
+
+			afterVal := tc.After
+			switch { // Some fixups to make the test cases a little easier to write
+			case afterVal.IsNull():
+				afterVal = cty.NullVal(ty) // allow mistyped nulls
+			case !afterVal.IsKnown():
+				afterVal = cty.UnknownVal(ty) // allow mistyped unknowns
+			}
+
+			addr := addrs.Resource{
+				Mode: tc.Mode,
+				Type: "test_instance",
+				Name: "example",
+			}.Instance(tc.InstanceKey).Absolute(tc.ModuleInst)
+
+			prevRunAddr := tc.PrevRunAddr
+			// If no previous run address is given, reuse the current address
+			// to make initialization easier
+			if prevRunAddr.Resource.Resource.Type == "" {
+				prevRunAddr = addr
+			}
+
+			beforeDynamicValue, err := plans.NewDynamicValue(beforeVal, ty)
+			if err != nil {
+				t.Fatalf("failed to create dynamic before value: " + err.Error())
+			}
+
+			afterDynamicValue, err := plans.NewDynamicValue(afterVal, ty)
+			if err != nil {
+				t.Fatalf("failed to create dynamic after value: " + err.Error())
+			}
+
+			src := &plans.ResourceInstanceChangeSrc{
+				ChangeSrc: plans.ChangeSrc{
+					Action:         tc.Action,
+					Before:         beforeDynamicValue,
+					BeforeValMarks: tc.BeforeValMarks,
+					After:          afterDynamicValue,
+					AfterValMarks:  tc.AfterValMarks,
+				},
+
+				Addr:        addr,
+				PrevRunAddr: prevRunAddr,
+				DeposedKey:  tc.DeposedKey,
+				ProviderAddr: addrs.AbsProviderConfig{
+					Provider: addrs.NewDefaultProvider("test"),
+					Module:   addrs.RootModule,
+				},
+				ActionReason:    tc.ActionReason,
+				RequiredReplace: tc.RequiredReplace,
+			}
+
+			tfschemas := &terraform.Schemas{
+				Providers: map[addrs.Provider]*providers.Schemas{
+					src.ProviderAddr.Provider: {
+						ResourceTypes: map[string]*configschema.Block{
+							src.Addr.Resource.Resource.Type: tc.Schema,
+						},
+						DataSources: map[string]*configschema.Block{
+							src.Addr.Resource.Resource.Type: tc.Schema,
+						},
+					},
+				},
+			}
+			jsonchanges, err := jsonplan.MarshalResourceChanges([]*plans.ResourceInstanceChangeSrc{src}, tfschemas)
+			if err != nil {
+				t.Errorf("failed to marshal resource changes: " + err.Error())
+				return
+			}
+
+			jsonschemas := jsonprovider.MarshalForRenderer(tfschemas)
+			change := structured.FromJsonChange(jsonchanges[0].Change, attribute_path.AlwaysMatcher())
+			renderer := Renderer{Colorize: color}
+			diff := diff{
+				change: jsonchanges[0],
+				diff:   differ.ComputeDiffForBlock(change, jsonschemas[jsonchanges[0].ProviderName].ResourceSchemas[jsonchanges[0].Type].Block),
+			}
+			output, _ := renderHumanDiff(renderer, diff, proposedChange)
+			if diff := cmp.Diff(output, tc.ExpectedOutput); diff != "" {
+				t.Errorf("wrong output\nexpected:\n%s\nactual:\n%s\ndiff:\n%s\n", tc.ExpectedOutput, output, diff)
+			}
+		})
+	}
+}
+
+func TestOutputChanges(t *testing.T) {
+	color := &colorstring.Colorize{Colors: colorstring.DefaultColors, Disable: true}
+
+	testCases := map[string]struct {
+		changes []*plans.OutputChangeSrc
+		output  string
+	}{
+		"new output value": {
+			[]*plans.OutputChangeSrc{
+				outputChange(
+					"foo",
+					cty.NullVal(cty.DynamicPseudoType),
+					cty.StringVal("bar"),
+					false,
+				),
+			},
+			`  + foo = "bar"`,
+		},
+		"removed output": {
+			[]*plans.OutputChangeSrc{
+				outputChange(
+					"foo",
+					cty.StringVal("bar"),
+					cty.NullVal(cty.DynamicPseudoType),
+					false,
+				),
+			},
+			`  - foo = "bar" -> null`,
+		},
+		"single string change": {
+			[]*plans.OutputChangeSrc{
+				outputChange(
+					"foo",
+					cty.StringVal("bar"),
+					cty.StringVal("baz"),
+					false,
+				),
+			},
+			`  ~ foo = "bar" -> "baz"`,
+		},
+		"element added to list": {
+			[]*plans.OutputChangeSrc{
+				outputChange(
+					"foo",
+					cty.ListVal([]cty.Value{
+						cty.StringVal("alpha"),
+						cty.StringVal("beta"),
+						cty.StringVal("delta"),
+						cty.StringVal("epsilon"),
+					}),
+					cty.ListVal([]cty.Value{
+						cty.StringVal("alpha"),
+						cty.StringVal("beta"),
+						cty.StringVal("gamma"),
+						cty.StringVal("delta"),
+						cty.StringVal("epsilon"),
+					}),
+					false,
+				),
+			},
+			`  ~ foo = [
+        # (1 unchanged element hidden)
+        "beta",
+      + "gamma",
+        "delta",
+        # (1 unchanged element hidden)
+    ]`,
+		},
+		"multiple outputs changed, one sensitive": {
+			[]*plans.OutputChangeSrc{
+				outputChange(
+					"a",
+					cty.NumberIntVal(1),
+					cty.NumberIntVal(2),
+					false,
+				),
+				outputChange(
+					"b",
+					cty.StringVal("hunter2"),
+					cty.StringVal("correct-horse-battery-staple"),
+					true,
+				),
+				outputChange(
+					"c",
+					cty.BoolVal(false),
+					cty.BoolVal(true),
+					false,
+				),
+			},
+			`  ~ a = 1 -> 2
+  ~ b = (sensitive value)
+  ~ c = false -> true`,
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			changes := &plans.Changes{
+				Outputs: tc.changes,
+			}
+
+			outputs, err := jsonplan.MarshalOutputChanges(changes)
+			if err != nil {
+				t.Fatalf("failed to marshal output changes")
+			}
+
+			renderer := Renderer{Colorize: color}
+			diffs := precomputeDiffs(Plan{
+				OutputChanges: outputs,
+			}, plans.NormalMode)
+
+			output := renderHumanDiffOutputs(renderer, diffs.outputs)
+			if output != tc.output {
+				t.Errorf("Unexpected diff.\ngot:\n%s\nwant:\n%s\n", output, tc.output)
+			}
+		})
+	}
+}
+
+func outputChange(name string, before, after cty.Value, sensitive bool) *plans.OutputChangeSrc {
+	addr := addrs.AbsOutputValue{
+		OutputValue: addrs.OutputValue{Name: name},
+	}
+
+	change := &plans.OutputChange{
+		Addr: addr, Change: plans.Change{
+			Before: before,
+			After:  after,
+		},
+		Sensitive: sensitive,
+	}
+
+	changeSrc, err := change.Encode()
+	if err != nil {
+		panic(fmt.Sprintf("failed to encode change for %s: %s", addr, err))
+	}
+
+	return changeSrc
+}
+
+// A basic test schema using a configurable NestingMode for one (NestedType) attribute and one block
+func testSchema(nesting configschema.NestingMode) *configschema.Block {
+	var diskKey = "disks"
+	if nesting == configschema.NestingSingle {
+		diskKey = "disk"
+	}
+
+	return &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"id":  {Type: cty.String, Optional: true, Computed: true},
+			"ami": {Type: cty.String, Optional: true},
+			diskKey: {
+				NestedType: &configschema.Object{
+					Attributes: map[string]*configschema.Attribute{
+						"mount_point": {Type: cty.String, Optional: true},
+						"size":        {Type: cty.String, Optional: true},
+					},
+					Nesting: nesting,
+				},
+			},
+		},
+		BlockTypes: map[string]*configschema.NestedBlock{
+			"root_block_device": {
+				Block: configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"volume_type": {
+							Type:     cty.String,
+							Optional: true,
+							Computed: true,
+						},
+					},
+				},
+				Nesting: nesting,
+			},
+		},
+	}
+}
+
+// A basic test schema using a configurable NestingMode for one (NestedType)
+// attribute marked sensitive.
+func testSchemaSensitive(nesting configschema.NestingMode) *configschema.Block {
+	return &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"id":  {Type: cty.String, Optional: true, Computed: true},
+			"ami": {Type: cty.String, Optional: true},
+			"disks": {
+				Sensitive: true,
+				NestedType: &configschema.Object{
+					Attributes: map[string]*configschema.Attribute{
+						"mount_point": {Type: cty.String, Optional: true},
+						"size":        {Type: cty.String, Optional: true},
+					},
+					Nesting: nesting,
+				},
+			},
+		},
+	}
+}
+
+func testSchemaMultipleBlocks(nesting configschema.NestingMode) *configschema.Block {
+	return &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"id":  {Type: cty.String, Optional: true, Computed: true},
+			"ami": {Type: cty.String, Optional: true},
+			"disks": {
+				NestedType: &configschema.Object{
+					Attributes: map[string]*configschema.Attribute{
+						"mount_point": {Type: cty.String, Optional: true},
+						"size":        {Type: cty.String, Optional: true},
+					},
+					Nesting: nesting,
+				},
+			},
+		},
+		BlockTypes: map[string]*configschema.NestedBlock{
+			"root_block_device": {
+				Block: configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"volume_type": {
+							Type:     cty.String,
+							Optional: true,
+							Computed: true,
+						},
+					},
+				},
+				Nesting: nesting,
+			},
+			"leaf_block_device": {
+				Block: configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"volume_type": {
+							Type:     cty.String,
+							Optional: true,
+							Computed: true,
+						},
+					},
+				},
+				Nesting: nesting,
+			},
+		},
+	}
+}
+
+// similar to testSchema with the addition of a "new_field" block
+func testSchemaPlus(nesting configschema.NestingMode) *configschema.Block {
+	var diskKey = "disks"
+	if nesting == configschema.NestingSingle {
+		diskKey = "disk"
+	}
+
+	return &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"id":  {Type: cty.String, Optional: true, Computed: true},
+			"ami": {Type: cty.String, Optional: true},
+			diskKey: {
+				NestedType: &configschema.Object{
+					Attributes: map[string]*configschema.Attribute{
+						"mount_point": {Type: cty.String, Optional: true},
+						"size":        {Type: cty.String, Optional: true},
+					},
+					Nesting: nesting,
+				},
+			},
+		},
+		BlockTypes: map[string]*configschema.NestedBlock{
+			"root_block_device": {
+				Block: configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"volume_type": {
+							Type:     cty.String,
+							Optional: true,
+							Computed: true,
+						},
+						"new_field": {
+							Type:     cty.String,
+							Optional: true,
+							Computed: true,
+						},
+					},
+				},
+				Nesting: nesting,
+			},
+		},
+	}
+}
+
+func marshalJson(t *testing.T, data interface{}) json.RawMessage {
+	result, err := json.Marshal(data)
+	if err != nil {
+		t.Fatalf("failed to marshal json: %v", err)
+	}
+	return result
+}
diff --git a/v1.5.7/internal/command/jsonformat/renderer.go b/v1.5.7/internal/command/jsonformat/renderer.go
new file mode 100644
index 0000000..6c8c1ad
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/renderer.go
@@ -0,0 +1,177 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonformat
+
+import (
+	"fmt"
+	"strconv"
+
+	"github.com/mitchellh/colorstring"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/command/format"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/differ"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+	"github.com/hashicorp/terraform/internal/command/jsonplan"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/command/jsonstate"
+	viewsjson "github.com/hashicorp/terraform/internal/command/views/json"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/terminal"
+)
+
+type JSONLogType string
+
+type JSONLog struct {
+	Message    string                 `json:"@message"`
+	Type       JSONLogType            `json:"type"`
+	Diagnostic *viewsjson.Diagnostic  `json:"diagnostic"`
+	Outputs    viewsjson.Outputs      `json:"outputs"`
+	Hook       map[string]interface{} `json:"hook"`
+}
+
+const (
+	LogApplyComplete     JSONLogType = "apply_complete"
+	LogApplyErrored      JSONLogType = "apply_errored"
+	LogApplyStart        JSONLogType = "apply_start"
+	LogChangeSummary     JSONLogType = "change_summary"
+	LogDiagnostic        JSONLogType = "diagnostic"
+	LogPlannedChange     JSONLogType = "planned_change"
+	LogProvisionComplete JSONLogType = "provision_complete"
+	LogProvisionErrored  JSONLogType = "provision_errored"
+	LogProvisionProgress JSONLogType = "provision_progress"
+	LogProvisionStart    JSONLogType = "provision_start"
+	LogOutputs           JSONLogType = "outputs"
+	LogRefreshComplete   JSONLogType = "refresh_complete"
+	LogRefreshStart      JSONLogType = "refresh_start"
+	LogResourceDrift     JSONLogType = "resource_drift"
+	LogVersion           JSONLogType = "version"
+)
+
+func incompatibleVersions(localVersion, remoteVersion string) bool {
+	var parsedLocal, parsedRemote float64
+	var err error
+
+	if parsedLocal, err = strconv.ParseFloat(localVersion, 64); err != nil {
+		return false
+	}
+	if parsedRemote, err = strconv.ParseFloat(remoteVersion, 64); err != nil {
+		return false
+	}
+
+	// If the local version is less than the remote version then the remote
+	// version might contain things the local version doesn't know about, so
+	// we're going to say they are incompatible.
+	//
+	// So far, we have built the renderer and the json packages to be backwards
+	// compatible so if the local version is greater than the remote version
+	// then that is okay, we'll still render a complete and correct plan.
+	//
+	// Note, this might change in the future. For example, if we introduce a
+	// new major version in one of the formats the renderer may no longer be
+	// backward compatible.
+	return parsedLocal < parsedRemote
+}
+
+type Renderer struct {
+	Streams  *terminal.Streams
+	Colorize *colorstring.Colorize
+
+	RunningInAutomation bool
+}
+
+func (renderer Renderer) RenderHumanPlan(plan Plan, mode plans.Mode, opts ...PlanRendererOpt) {
+	if incompatibleVersions(jsonplan.FormatVersion, plan.PlanFormatVersion) || incompatibleVersions(jsonprovider.FormatVersion, plan.ProviderFormatVersion) {
+		renderer.Streams.Println(format.WordWrap(
+			renderer.Colorize.Color("\n[bold][red]Warning:[reset][bold] This plan was generated using a different version of Terraform, the diff presented here may be missing representations of recent features."),
+			renderer.Streams.Stdout.Columns()))
+	}
+
+	plan.renderHuman(renderer, mode, opts...)
+}
+
+func (renderer Renderer) RenderHumanState(state State) {
+	if incompatibleVersions(jsonstate.FormatVersion, state.StateFormatVersion) || incompatibleVersions(jsonprovider.FormatVersion, state.ProviderFormatVersion) {
+		renderer.Streams.Println(format.WordWrap(
+			renderer.Colorize.Color("\n[bold][red]Warning:[reset][bold] This state was retrieved using a different version of Terraform, the state presented here maybe missing representations of recent features."),
+			renderer.Streams.Stdout.Columns()))
+	}
+
+	if state.Empty() {
+		renderer.Streams.Println("The state file is empty. No resources are represented.")
+		return
+	}
+
+	opts := computed.NewRenderHumanOpts(renderer.Colorize)
+	opts.ShowUnchangedChildren = true
+	opts.HideDiffActionSymbols = true
+
+	state.renderHumanStateModule(renderer, state.RootModule, opts, true)
+	state.renderHumanStateOutputs(renderer, opts)
+}
+
+func (renderer Renderer) RenderLog(log *JSONLog) error {
+	switch log.Type {
+	case LogRefreshComplete,
+		LogVersion,
+		LogPlannedChange,
+		LogProvisionComplete,
+		LogProvisionErrored,
+		LogApplyErrored:
+		// We won't display these types of logs
+		return nil
+
+	case LogApplyStart, LogApplyComplete, LogRefreshStart, LogProvisionStart, LogResourceDrift:
+		msg := fmt.Sprintf(renderer.Colorize.Color("[bold]%s[reset]"), log.Message)
+		renderer.Streams.Println(msg)
+
+	case LogDiagnostic:
+		diag := format.DiagnosticFromJSON(log.Diagnostic, renderer.Colorize, 78)
+		renderer.Streams.Print(diag)
+
+	case LogOutputs:
+		if len(log.Outputs) > 0 {
+			renderer.Streams.Println(renderer.Colorize.Color("[bold][green]Outputs:[reset]"))
+			for name, output := range log.Outputs {
+				change := structured.FromJsonViewsOutput(output)
+				ctype, err := ctyjson.UnmarshalType(output.Type)
+				if err != nil {
+					return err
+				}
+
+				opts := computed.NewRenderHumanOpts(renderer.Colorize)
+				opts.ShowUnchangedChildren = true
+
+				outputDiff := differ.ComputeDiffForType(change, ctype)
+				outputStr := outputDiff.RenderHuman(0, opts)
+
+				msg := fmt.Sprintf("%s = %s", name, outputStr)
+				renderer.Streams.Println(msg)
+			}
+		}
+
+	case LogProvisionProgress:
+		provisioner := log.Hook["provisioner"].(string)
+		output := log.Hook["output"].(string)
+		resource := log.Hook["resource"].(map[string]interface{})
+		resourceAddr := resource["addr"].(string)
+
+		msg := fmt.Sprintf(renderer.Colorize.Color("[bold]%s: (%s):[reset] %s"),
+			resourceAddr, provisioner, output)
+		renderer.Streams.Println(msg)
+
+	case LogChangeSummary:
+		// Normally, we will only render the apply change summary since the renderer
+		// generates a plan change summary for us
+		msg := fmt.Sprintf(renderer.Colorize.Color("[bold][green]%s[reset]"), log.Message)
+		renderer.Streams.Println("\n" + msg + "\n")
+
+	default:
+		// If the log type is not a known log type, we will just print the log message
+		renderer.Streams.Println(log.Message)
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/command/jsonformat/renderer_test.go b/v1.5.7/internal/command/jsonformat/renderer_test.go
new file mode 100644
index 0000000..cbc08d9
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/renderer_test.go
@@ -0,0 +1,60 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonformat
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/command/jsonplan"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/command/jsonstate"
+)
+
+func TestIncompatibleVersions(t *testing.T) {
+	tcs := map[string]struct {
+		local    string
+		remote   string
+		expected bool
+	}{
+		"matching": {
+			local:    "1.1",
+			remote:   "1.1",
+			expected: false,
+		},
+		"local_latest": {
+			local:    "1.2",
+			remote:   "1.1",
+			expected: false,
+		},
+		"local_earliest": {
+			local:    "1.1",
+			remote:   "1.2",
+			expected: true,
+		},
+		"parses_state_version": {
+			local:    jsonstate.FormatVersion,
+			remote:   jsonstate.FormatVersion,
+			expected: false,
+		},
+		"parses_provider_version": {
+			local:    jsonprovider.FormatVersion,
+			remote:   jsonprovider.FormatVersion,
+			expected: false,
+		},
+		"parses_plan_version": {
+			local:    jsonplan.FormatVersion,
+			remote:   jsonplan.FormatVersion,
+			expected: false,
+		},
+	}
+
+	for name, tc := range tcs {
+		t.Run(name, func(t *testing.T) {
+			actual := incompatibleVersions(tc.local, tc.remote)
+			if actual != tc.expected {
+				t.Errorf("expected %t but found %t", tc.expected, actual)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/state.go b/v1.5.7/internal/command/jsonformat/state.go
new file mode 100644
index 0000000..8ac2e28
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/state.go
@@ -0,0 +1,111 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonformat
+
+import (
+	"sort"
+
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/differ"
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/command/jsonstate"
+)
+
+type State struct {
+	StateFormatVersion string                      `json:"state_format_version"`
+	RootModule         jsonstate.Module            `json:"root"`
+	RootModuleOutputs  map[string]jsonstate.Output `json:"root_module_outputs"`
+
+	ProviderFormatVersion string                            `json:"provider_format_version"`
+	ProviderSchemas       map[string]*jsonprovider.Provider `json:"provider_schemas"`
+}
+
+func (state State) Empty() bool {
+	return len(state.RootModuleOutputs) == 0 && len(state.RootModule.Resources) == 0 && len(state.RootModule.ChildModules) == 0
+}
+
+func (state State) GetSchema(resource jsonstate.Resource) *jsonprovider.Schema {
+	switch resource.Mode {
+	case jsonstate.ManagedResourceMode:
+		return state.ProviderSchemas[resource.ProviderName].ResourceSchemas[resource.Type]
+	case jsonstate.DataResourceMode:
+		return state.ProviderSchemas[resource.ProviderName].DataSourceSchemas[resource.Type]
+	default:
+		panic("found unrecognized resource mode: " + resource.Mode)
+	}
+}
+
+func (state State) renderHumanStateModule(renderer Renderer, module jsonstate.Module, opts computed.RenderHumanOpts, first bool) {
+	if len(module.Resources) > 0 && !first {
+		renderer.Streams.Println()
+	}
+
+	for _, resource := range module.Resources {
+
+		if !first {
+			renderer.Streams.Println()
+		}
+
+		if first {
+			first = false
+		}
+
+		if len(resource.DeposedKey) > 0 {
+			renderer.Streams.Printf("# %s: (deposed object %s)", resource.Address, resource.DeposedKey)
+		} else if resource.Tainted {
+			renderer.Streams.Printf("# %s: (tainted)", resource.Address)
+		} else {
+			renderer.Streams.Printf("# %s:", resource.Address)
+		}
+
+		renderer.Streams.Println()
+
+		schema := state.GetSchema(resource)
+		switch resource.Mode {
+		case jsonstate.ManagedResourceMode:
+			change := structured.FromJsonResource(resource)
+			renderer.Streams.Printf("resource %q %q %s", resource.Type, resource.Name, differ.ComputeDiffForBlock(change, schema.Block).RenderHuman(0, opts))
+		case jsonstate.DataResourceMode:
+			change := structured.FromJsonResource(resource)
+			renderer.Streams.Printf("data %q %q %s", resource.Type, resource.Name, differ.ComputeDiffForBlock(change, schema.Block).RenderHuman(0, opts))
+		default:
+			panic("found unrecognized resource mode: " + resource.Mode)
+		}
+
+		renderer.Streams.Println()
+	}
+
+	for _, child := range module.ChildModules {
+		state.renderHumanStateModule(renderer, child, opts, first)
+	}
+}
+
+func (state State) renderHumanStateOutputs(renderer Renderer, opts computed.RenderHumanOpts) {
+
+	if len(state.RootModuleOutputs) > 0 {
+		renderer.Streams.Printf("\n\nOutputs:\n\n")
+
+		var keys []string
+		for key := range state.RootModuleOutputs {
+			keys = append(keys, key)
+		}
+		sort.Strings(keys)
+
+		for _, key := range keys {
+			output := state.RootModuleOutputs[key]
+			change := structured.FromJsonOutput(output)
+			ctype, err := ctyjson.UnmarshalType(output.Type)
+			if err != nil {
+				// We can actually do this without the type, so even if we fail
+				// to work out the type let's just render this anyway.
+				renderer.Streams.Printf("%s = %s\n", key, differ.ComputeDiffForOutput(change).RenderHuman(0, opts))
+			} else {
+				renderer.Streams.Printf("%s = %s\n", key, differ.ComputeDiffForType(change, ctype).RenderHuman(0, opts))
+			}
+		}
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/state_test.go b/v1.5.7/internal/command/jsonformat/state_test.go
new file mode 100644
index 0000000..7166501
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/state_test.go
@@ -0,0 +1,422 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonformat
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/mitchellh/colorstring"
+
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/command/jsonstate"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/terminal"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+func TestState(t *testing.T) {
+	color := &colorstring.Colorize{Colors: colorstring.DefaultColors, Disable: true}
+
+	tests := []struct {
+		State   *states.State
+		Schemas *terraform.Schemas
+		Want    string
+	}{
+		{
+			State:   &states.State{},
+			Schemas: &terraform.Schemas{},
+			Want:    "The state file is empty. No resources are represented.\n",
+		},
+		{
+			State:   basicState(t),
+			Schemas: testSchemas(),
+			Want:    basicStateOutput,
+		},
+		{
+			State:   nestedState(t),
+			Schemas: testSchemas(),
+			Want:    nestedStateOutput,
+		},
+		{
+			State:   deposedState(t),
+			Schemas: testSchemas(),
+			Want:    deposedNestedStateOutput,
+		},
+		{
+			State:   onlyDeposedState(t),
+			Schemas: testSchemas(),
+			Want:    onlyDeposedOutput,
+		},
+		{
+			State:   stateWithMoreOutputs(t),
+			Schemas: testSchemas(),
+			Want:    stateWithMoreOutputsOutput,
+		},
+	}
+
+	for i, tt := range tests {
+		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+
+			root, outputs, err := jsonstate.MarshalForRenderer(&statefile.File{
+				State: tt.State,
+			}, tt.Schemas)
+
+			if err != nil {
+				t.Errorf("found err: %v", err)
+				return
+			}
+
+			streams, done := terminal.StreamsForTesting(t)
+			renderer := Renderer{
+				Colorize: color,
+				Streams:  streams,
+			}
+
+			renderer.RenderHumanState(State{
+				StateFormatVersion:    jsonstate.FormatVersion,
+				RootModule:            root,
+				RootModuleOutputs:     outputs,
+				ProviderFormatVersion: jsonprovider.FormatVersion,
+				ProviderSchemas:       jsonprovider.MarshalForRenderer(tt.Schemas),
+			})
+
+			result := done(t).All()
+			if diff := cmp.Diff(result, tt.Want); diff != "" {
+				t.Errorf("wrong output\nexpected:\n%s\nactual:\n%s\ndiff:\n%s\n", tt.Want, result, diff)
+			}
+		})
+	}
+}
+
+func testProvider() *terraform.MockProvider {
+	p := new(terraform.MockProvider)
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		return providers.ReadResourceResponse{NewState: req.PriorState}
+	}
+
+	p.GetProviderSchemaResponse = testProviderSchema()
+
+	return p
+}
+
+func testProviderSchema() *providers.GetProviderSchemaResponse {
+	return &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"region": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_resource": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":      {Type: cty.String, Computed: true},
+						"foo":     {Type: cty.String, Optional: true},
+						"woozles": {Type: cty.String, Optional: true},
+					},
+					BlockTypes: map[string]*configschema.NestedBlock{
+						"nested": {
+							Nesting: configschema.NestingList,
+							Block: configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"compute": {Type: cty.String, Optional: true},
+									"value":   {Type: cty.String, Optional: true},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		DataSources: map[string]providers.Schema{
+			"test_data_source": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"compute": {Type: cty.String, Optional: true},
+						"value":   {Type: cty.String, Computed: true},
+					},
+				},
+			},
+		},
+	}
+}
+
+func testSchemas() *terraform.Schemas {
+	provider := testProvider()
+	return &terraform.Schemas{
+		Providers: map[addrs.Provider]*terraform.ProviderSchema{
+			addrs.NewDefaultProvider("test"): provider.ProviderSchema(),
+		},
+	}
+}
+
+const basicStateOutput = `# data.test_data_source.data:
+data "test_data_source" "data" {
+    compute = "sure"
+}
+
+# test_resource.baz[0]:
+resource "test_resource" "baz" {
+    woozles = "confuzles"
+}
+
+
+Outputs:
+
+bar = "bar value"
+`
+
+const nestedStateOutput = `# test_resource.baz[0]:
+resource "test_resource" "baz" {
+    woozles = "confuzles"
+
+    nested {
+        value = "42"
+    }
+}
+`
+
+const deposedNestedStateOutput = `# test_resource.baz[0]:
+resource "test_resource" "baz" {
+    woozles = "confuzles"
+
+    nested {
+        value = "42"
+    }
+}
+
+# test_resource.baz[0]: (deposed object 1234)
+resource "test_resource" "baz" {
+    woozles = "confuzles"
+
+    nested {
+        value = "42"
+    }
+}
+`
+
+const onlyDeposedOutput = `# test_resource.baz[0]: (deposed object 1234)
+resource "test_resource" "baz" {
+    woozles = "confuzles"
+
+    nested {
+        value = "42"
+    }
+}
+
+# test_resource.baz[0]: (deposed object 5678)
+resource "test_resource" "baz" {
+    woozles = "confuzles"
+
+    nested {
+        value = "42"
+    }
+}
+`
+
+const stateWithMoreOutputsOutput = `# test_resource.baz[0]:
+resource "test_resource" "baz" {
+    woozles = "confuzles"
+}
+
+
+Outputs:
+
+bool_var = true
+int_var = 42
+map_var = {
+    "first"  = "foo"
+    "second" = "bar"
+}
+sensitive_var = (sensitive value)
+string_var = "string value"
+`
+
+func basicState(t *testing.T) *states.State {
+	state := states.NewState()
+
+	rootModule := state.RootModule()
+	if rootModule == nil {
+		t.Errorf("root module is nil; want valid object")
+	}
+
+	rootModule.SetLocalValue("foo", cty.StringVal("foo value"))
+	rootModule.SetOutputValue("bar", cty.StringVal("bar value"), false)
+	rootModule.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_resource",
+			Name: "baz",
+		}.Instance(addrs.IntKey(0)),
+		&states.ResourceInstanceObjectSrc{
+			Status:        states.ObjectReady,
+			SchemaVersion: 0,
+			AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	rootModule.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.DataResourceMode,
+			Type: "test_data_source",
+			Name: "data",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:        states.ObjectReady,
+			SchemaVersion: 0,
+			AttrsJSON:     []byte(`{"compute":"sure"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	return state
+}
+
+func stateWithMoreOutputs(t *testing.T) *states.State {
+	state := states.NewState()
+
+	rootModule := state.RootModule()
+	if rootModule == nil {
+		t.Errorf("root module is nil; want valid object")
+	}
+
+	rootModule.SetOutputValue("string_var", cty.StringVal("string value"), false)
+	rootModule.SetOutputValue("int_var", cty.NumberIntVal(42), false)
+	rootModule.SetOutputValue("bool_var", cty.BoolVal(true), false)
+	rootModule.SetOutputValue("sensitive_var", cty.StringVal("secret!!!"), true)
+	rootModule.SetOutputValue("map_var", cty.MapVal(map[string]cty.Value{
+		"first":  cty.StringVal("foo"),
+		"second": cty.StringVal("bar"),
+	}), false)
+
+	rootModule.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_resource",
+			Name: "baz",
+		}.Instance(addrs.IntKey(0)),
+		&states.ResourceInstanceObjectSrc{
+			Status:        states.ObjectReady,
+			SchemaVersion: 0,
+			AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	return state
+}
+
+func nestedState(t *testing.T) *states.State {
+	state := states.NewState()
+
+	rootModule := state.RootModule()
+	if rootModule == nil {
+		t.Errorf("root module is nil; want valid object")
+	}
+
+	rootModule.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_resource",
+			Name: "baz",
+		}.Instance(addrs.IntKey(0)),
+		&states.ResourceInstanceObjectSrc{
+			Status:        states.ObjectReady,
+			SchemaVersion: 0,
+			AttrsJSON:     []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	return state
+}
+
+func deposedState(t *testing.T) *states.State {
+	state := nestedState(t)
+	rootModule := state.RootModule()
+	rootModule.SetResourceInstanceDeposed(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_resource",
+			Name: "baz",
+		}.Instance(addrs.IntKey(0)),
+		states.DeposedKey("1234"),
+		&states.ResourceInstanceObjectSrc{
+			Status:        states.ObjectReady,
+			SchemaVersion: 0,
+			AttrsJSON:     []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	return state
+}
+
+// replicate a corrupt resource where only a deposed exists
+func onlyDeposedState(t *testing.T) *states.State {
+	state := states.NewState()
+
+	rootModule := state.RootModule()
+	if rootModule == nil {
+		t.Errorf("root module is nil; want valid object")
+	}
+
+	rootModule.SetResourceInstanceDeposed(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_resource",
+			Name: "baz",
+		}.Instance(addrs.IntKey(0)),
+		states.DeposedKey("1234"),
+		&states.ResourceInstanceObjectSrc{
+			Status:        states.ObjectReady,
+			SchemaVersion: 0,
+			AttrsJSON:     []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	rootModule.SetResourceInstanceDeposed(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_resource",
+			Name: "baz",
+		}.Instance(addrs.IntKey(0)),
+		states.DeposedKey("5678"),
+		&states.ResourceInstanceObjectSrc{
+			Status:        states.ObjectReady,
+			SchemaVersion: 0,
+			AttrsJSON:     []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	return state
+}
diff --git a/v1.5.7/internal/command/jsonformat/structured/attribute_path/matcher.go b/v1.5.7/internal/command/jsonformat/structured/attribute_path/matcher.go
new file mode 100644
index 0000000..409fc60
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/structured/attribute_path/matcher.go
@@ -0,0 +1,232 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package attribute_path
+
+import (
+	"encoding/json"
+	"fmt"
+	"strconv"
+)
+
+// Matcher provides an interface for stepping through changes following an
+// attribute path.
+//
+// GetChildWithKey and GetChildWithIndex will check if any of the internal paths
+// match the provided key or index, and return a new Matcher that will match
+// that children or potentially it's children.
+//
+// The caller of the above functions is required to know whether the next value
+// in the path is a list type or an object type and call the relevant function,
+// otherwise these functions will crash/panic.
+//
+// The Matches function returns true if the paths you have traversed until now
+// ends.
+type Matcher interface {
+	// Matches returns true if we have reached the end of a path and found an
+	// exact match.
+	Matches() bool
+
+	// MatchesPartial returns true if the current attribute is part of a path
+	// but not necessarily at the end of the path.
+	MatchesPartial() bool
+
+	GetChildWithKey(key string) Matcher
+	GetChildWithIndex(index int) Matcher
+}
+
+// Parse accepts a json.RawMessage and outputs a formatted Matcher object.
+//
+// Parse expects the message to be a JSON array of JSON arrays containing
+// strings and floats. This function happily accepts a null input representing
+// none of the changes in this resource are causing a replacement. The propagate
+// argument tells the matcher to propagate any matches to the matched attributes
+// children.
+//
+// In general, this function is designed to accept messages that have been
+// produced by the lossy cty.Paths conversion functions within the jsonplan
+// package. There is nothing particularly special about that conversion process
+// though, it just produces the nested JSON arrays described above.
+func Parse(message json.RawMessage, propagate bool) Matcher {
+	matcher := &PathMatcher{
+		Propagate: propagate,
+	}
+	if message == nil {
+		return matcher
+	}
+
+	if err := json.Unmarshal(message, &matcher.Paths); err != nil {
+		panic("failed to unmarshal attribute paths: " + err.Error())
+	}
+
+	return matcher
+}
+
+// Empty returns an empty PathMatcher that will by default match nothing.
+//
+// We give direct access to the PathMatcher struct so a matcher can be built
+// in parts with the Append and AppendSingle functions.
+func Empty(propagate bool) *PathMatcher {
+	return &PathMatcher{
+		Propagate: propagate,
+	}
+}
+
+// Append accepts an existing PathMatcher and returns a new one that attaches
+// all the paths from message with the existing paths.
+//
+// The new PathMatcher is created fresh, and the existing one is unchanged.
+func Append(matcher *PathMatcher, message json.RawMessage) *PathMatcher {
+	var values [][]interface{}
+	if err := json.Unmarshal(message, &values); err != nil {
+		panic("failed to unmarshal attribute paths: " + err.Error())
+	}
+
+	return &PathMatcher{
+		Propagate: matcher.Propagate,
+		Paths:     append(matcher.Paths, values...),
+	}
+}
+
+// AppendSingle accepts an existing PathMatcher and returns a new one that
+// attaches the single path from message with the existing paths.
+//
+// The new PathMatcher is created fresh, and the existing one is unchanged.
+func AppendSingle(matcher *PathMatcher, message json.RawMessage) *PathMatcher {
+	var values []interface{}
+	if err := json.Unmarshal(message, &values); err != nil {
+		panic("failed to unmarshal attribute paths: " + err.Error())
+	}
+
+	return &PathMatcher{
+		Propagate: matcher.Propagate,
+		Paths:     append(matcher.Paths, values),
+	}
+}
+
+// PathMatcher contains a slice of paths that represent paths through the values
+// to relevant/tracked attributes.
+type PathMatcher struct {
+	// We represent our internal paths as a [][]interface{} as the cty.Paths
+	// conversion process is lossy. Since the type information is lost there
+	// is no (easy) way to reproduce the original cty.Paths object. Instead,
+	// we simply rely on the external callers to know the type information and
+	// call the correct GetChild function.
+	Paths [][]interface{}
+
+	// Propagate tells the matcher that it should propagate any matches it finds
+	// onto the children of that match.
+	Propagate bool
+}
+
+func (p *PathMatcher) Matches() bool {
+	for _, path := range p.Paths {
+		if len(path) == 0 {
+			return true
+		}
+	}
+	return false
+}
+
+func (p *PathMatcher) MatchesPartial() bool {
+	return len(p.Paths) > 0
+}
+
+func (p *PathMatcher) GetChildWithKey(key string) Matcher {
+	child := &PathMatcher{
+		Propagate: p.Propagate,
+	}
+	for _, path := range p.Paths {
+		if len(path) == 0 {
+			// This means that the current value matched, but not necessarily
+			// it's child.
+
+			if p.Propagate {
+				// If propagate is true, then our child match our matches
+				child.Paths = append(child.Paths, path)
+			}
+
+			// If not we would simply drop this path from our set of paths but
+			// either way we just continue.
+			continue
+		}
+
+		if path[0].(string) == key {
+			child.Paths = append(child.Paths, path[1:])
+		}
+	}
+	return child
+}
+
+func (p *PathMatcher) GetChildWithIndex(index int) Matcher {
+	child := &PathMatcher{
+		Propagate: p.Propagate,
+	}
+	for _, path := range p.Paths {
+		if len(path) == 0 {
+			// This means that the current value matched, but not necessarily
+			// it's child.
+
+			if p.Propagate {
+				// If propagate is true, then our child match our matches
+				child.Paths = append(child.Paths, path)
+			}
+
+			// If not we would simply drop this path from our set of paths but
+			// either way we just continue.
+			continue
+		}
+
+		// Terraform actually allows user to provide strings into indexes as
+		// long as the string can be interpreted into a number. For example, the
+		// following are equivalent and we need to support them.
+		//    - test_resource.resource.list[0].attribute
+		//    - test_resource.resource.list["0"].attribute
+		//
+		// Note, that Terraform will raise a validation error if the string
+		// can't be coerced into a number, so we will panic here if anything
+		// goes wrong safe in the knowledge the validation should stop this from
+		// happening.
+
+		switch val := path[0].(type) {
+		case float64:
+			if int(path[0].(float64)) == index {
+				child.Paths = append(child.Paths, path[1:])
+			}
+		case string:
+			f, err := strconv.ParseFloat(val, 64)
+			if err != nil {
+				panic(fmt.Errorf("found invalid type within path (%v:%T), the validation shouldn't have allowed this to happen; this is a bug in Terraform, please report it", val, val))
+			}
+			if int(f) == index {
+				child.Paths = append(child.Paths, path[1:])
+			}
+		default:
+			panic(fmt.Errorf("found invalid type within path (%v:%T), the validation shouldn't have allowed this to happen; this is a bug in Terraform, please report it", val, val))
+		}
+	}
+	return child
+}
+
+// AlwaysMatcher returns a matcher that will always match all paths.
+func AlwaysMatcher() Matcher {
+	return &alwaysMatcher{}
+}
+
+type alwaysMatcher struct{}
+
+func (a *alwaysMatcher) Matches() bool {
+	return true
+}
+
+func (a *alwaysMatcher) MatchesPartial() bool {
+	return true
+}
+
+func (a *alwaysMatcher) GetChildWithKey(_ string) Matcher {
+	return a
+}
+
+func (a *alwaysMatcher) GetChildWithIndex(_ int) Matcher {
+	return a
+}
diff --git a/v1.5.7/internal/command/jsonformat/structured/attribute_path/matcher_test.go b/v1.5.7/internal/command/jsonformat/structured/attribute_path/matcher_test.go
new file mode 100644
index 0000000..a893aae
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/structured/attribute_path/matcher_test.go
@@ -0,0 +1,256 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package attribute_path
+
+import "testing"
+
+func TestPathMatcher_FollowsPath(t *testing.T) {
+	var matcher Matcher
+
+	matcher = &PathMatcher{
+		Paths: [][]interface{}{
+			{
+				float64(0),
+				"key",
+				float64(0),
+			},
+		},
+	}
+
+	if matcher.Matches() {
+		t.Errorf("should not have exact matched at base level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at base level")
+	}
+
+	matcher = matcher.GetChildWithIndex(0)
+
+	if matcher.Matches() {
+		t.Errorf("should not have exact matched at first level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at first level")
+	}
+
+	matcher = matcher.GetChildWithKey("key")
+
+	if matcher.Matches() {
+		t.Errorf("should not have exact matched at second level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at second level")
+	}
+
+	matcher = matcher.GetChildWithIndex(0)
+
+	if !matcher.Matches() {
+		t.Errorf("should have exact matched at leaf level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at leaf level")
+	}
+}
+func TestPathMatcher_Propagates(t *testing.T) {
+	var matcher Matcher
+
+	matcher = &PathMatcher{
+		Paths: [][]interface{}{
+			{
+				float64(0),
+				"key",
+			},
+		},
+		Propagate: true,
+	}
+
+	if matcher.Matches() {
+		t.Errorf("should not have exact matched at base level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at base level")
+	}
+
+	matcher = matcher.GetChildWithIndex(0)
+
+	if matcher.Matches() {
+		t.Errorf("should not have exact matched at first level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at first level")
+	}
+
+	matcher = matcher.GetChildWithKey("key")
+
+	if !matcher.Matches() {
+		t.Errorf("should have exact matched at second level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at second level")
+	}
+
+	matcher = matcher.GetChildWithIndex(0)
+
+	if !matcher.Matches() {
+		t.Errorf("should have exact matched at leaf level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at leaf level")
+	}
+}
+func TestPathMatcher_DoesNotPropagate(t *testing.T) {
+	var matcher Matcher
+
+	matcher = &PathMatcher{
+		Paths: [][]interface{}{
+			{
+				float64(0),
+				"key",
+			},
+		},
+	}
+
+	if matcher.Matches() {
+		t.Errorf("should not have exact matched at base level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at base level")
+	}
+
+	matcher = matcher.GetChildWithIndex(0)
+
+	if matcher.Matches() {
+		t.Errorf("should not have exact matched at first level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at first level")
+	}
+
+	matcher = matcher.GetChildWithKey("key")
+
+	if !matcher.Matches() {
+		t.Errorf("should have exact matched at second level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at second level")
+	}
+
+	matcher = matcher.GetChildWithIndex(0)
+
+	if matcher.Matches() {
+		t.Errorf("should not have exact matched at leaf level")
+	}
+	if matcher.MatchesPartial() {
+		t.Errorf("should not have partial matched at leaf level")
+	}
+}
+
+func TestPathMatcher_BreaksPath(t *testing.T) {
+	var matcher Matcher
+
+	matcher = &PathMatcher{
+		Paths: [][]interface{}{
+			{
+				float64(0),
+				"key",
+				float64(0),
+			},
+		},
+	}
+
+	if matcher.Matches() {
+		t.Errorf("should not have exact matched at base level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at base level")
+	}
+
+	matcher = matcher.GetChildWithIndex(0)
+
+	if matcher.Matches() {
+		t.Errorf("should not have exact matched at first level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at first level")
+	}
+
+	matcher = matcher.GetChildWithKey("invalid")
+
+	if matcher.Matches() {
+		t.Errorf("should not have exact matched at second level")
+	}
+	if matcher.MatchesPartial() {
+		t.Errorf("should not have partial matched at second level")
+
+	}
+}
+
+func TestPathMatcher_MultiplePaths(t *testing.T) {
+	var matcher Matcher
+
+	matcher = &PathMatcher{
+		Paths: [][]interface{}{
+			{
+				float64(0),
+				"key",
+				float64(0),
+			},
+			{
+				float64(0),
+				"key",
+				float64(1),
+			},
+		},
+	}
+
+	if matcher.Matches() {
+		t.Errorf("should not have exact matched at base level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at base level")
+	}
+
+	matcher = matcher.GetChildWithIndex(0)
+
+	if matcher.Matches() {
+		t.Errorf("should not have exact matched at first level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at first level")
+	}
+
+	matcher = matcher.GetChildWithKey("key")
+
+	if matcher.Matches() {
+		t.Errorf("should not have exact matched at second level")
+	}
+	if !matcher.MatchesPartial() {
+		t.Errorf("should have partial matched at second level")
+	}
+
+	validZero := matcher.GetChildWithIndex(0)
+	validOne := matcher.GetChildWithIndex(1)
+	invalid := matcher.GetChildWithIndex(2)
+
+	if !validZero.Matches() {
+		t.Errorf("should have exact matched at leaf level")
+	}
+	if !validZero.MatchesPartial() {
+		t.Errorf("should have partial matched at leaf level")
+	}
+
+	if !validOne.Matches() {
+		t.Errorf("should have exact matched at leaf level")
+	}
+	if !validOne.MatchesPartial() {
+		t.Errorf("should have partial matched at leaf level")
+	}
+
+	if invalid.Matches() {
+		t.Errorf("should not have exact matched at leaf level")
+	}
+	if invalid.MatchesPartial() {
+		t.Errorf("should not have partial matched at leaf level")
+	}
+}
diff --git a/v1.5.7/internal/command/jsonformat/structured/change.go b/v1.5.7/internal/command/jsonformat/structured/change.go
new file mode 100644
index 0000000..5dab87a
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/structured/change.go
@@ -0,0 +1,280 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package structured
+
+import (
+	"encoding/json"
+	"reflect"
+
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path"
+	"github.com/hashicorp/terraform/internal/command/jsonplan"
+	"github.com/hashicorp/terraform/internal/command/jsonstate"
+	viewsjson "github.com/hashicorp/terraform/internal/command/views/json"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+// Change contains the unmarshalled generic interface{} types that are output by
+// the JSON functions in the various json packages (such as jsonplan and
+// jsonprovider).
+//
+// A Change can be converted into a computed.Diff, ready for rendering, with the
+// ComputeDiffForAttribute, ComputeDiffForOutput, and ComputeDiffForBlock
+// functions.
+//
+// The Before and After fields are actually go-cty values, but we cannot convert
+// them directly because of the Terraform Cloud redacted endpoint. The redacted
+// endpoint turns sensitive values into strings regardless of their types.
+// Because of this, we cannot just do a direct conversion using the ctyjson
+// package. We would have to iterate through the schema first, find the
+// sensitive values and their mapped types, update the types inside the schema
+// to strings, and then go back and do the overall conversion. This isn't
+// including any of the more complicated parts around what happens if something
+// was sensitive before and isn't sensitive after or vice versa. This would mean
+// the type would need to change between the before and after value. It is in
+// fact just easier to iterate through the values as generic JSON interfaces.
+type Change struct {
+
+	// BeforeExplicit matches AfterExplicit except references the Before value.
+	BeforeExplicit bool
+
+	// AfterExplicit refers to whether the After value is explicit or
+	// implicit. It is explicit if it has been specified by the user, and
+	// implicit if it has been set as a consequence of other changes.
+	//
+	// For example, explicitly setting a value to null in a list should result
+	// in After being null and AfterExplicit being true. In comparison,
+	// removing an element from a list should also result in After being null
+	// and AfterExplicit being false. Without the explicit information our
+	// functions would not be able to tell the difference between these two
+	// cases.
+	AfterExplicit bool
+
+	// Before contains the value before the proposed change.
+	//
+	// The type of the value should be informed by the schema and cast
+	// appropriately when needed.
+	Before interface{}
+
+	// After contains the value after the proposed change.
+	//
+	// The type of the value should be informed by the schema and cast
+	// appropriately when needed.
+	After interface{}
+
+	// Unknown describes whether the After value is known or unknown at the time
+	// of the plan. In practice, this means the after value should be rendered
+	// simply as `(known after apply)`.
+	//
+	// The concrete value could be a boolean describing whether the entirety of
+	// the After value is unknown, or it could be a list or a map depending on
+	// the schema describing whether specific elements or attributes within the
+	// value are unknown.
+	Unknown interface{}
+
+	// BeforeSensitive matches Unknown, but references whether the Before value
+	// is sensitive.
+	BeforeSensitive interface{}
+
+	// AfterSensitive matches Unknown, but references whether the After value is
+	// sensitive.
+	AfterSensitive interface{}
+
+	// ReplacePaths contains a set of paths that point to attributes/elements
+	// that are causing the overall resource to be replaced rather than simply
+	// updated.
+	ReplacePaths attribute_path.Matcher
+
+	// RelevantAttributes contains a set of paths that point attributes/elements
+	// that we should display. Any element/attribute not matched by this Matcher
+	// should be skipped.
+	RelevantAttributes attribute_path.Matcher
+}
+
+// FromJsonChange unmarshals the raw []byte values in the jsonplan.Change
+// structs into generic interface{} types that can be reasoned about.
+func FromJsonChange(change jsonplan.Change, relevantAttributes attribute_path.Matcher) Change {
+	return Change{
+		Before:             unmarshalGeneric(change.Before),
+		After:              unmarshalGeneric(change.After),
+		Unknown:            unmarshalGeneric(change.AfterUnknown),
+		BeforeSensitive:    unmarshalGeneric(change.BeforeSensitive),
+		AfterSensitive:     unmarshalGeneric(change.AfterSensitive),
+		ReplacePaths:       attribute_path.Parse(change.ReplacePaths, false),
+		RelevantAttributes: relevantAttributes,
+	}
+}
+
+// FromJsonResource unmarshals the raw values in the jsonstate.Resource structs
+// into generic interface{} types that can be reasoned about.
+func FromJsonResource(resource jsonstate.Resource) Change {
+	return Change{
+		// We model resource formatting as NoOps.
+		Before: unwrapAttributeValues(resource.AttributeValues),
+		After:  unwrapAttributeValues(resource.AttributeValues),
+
+		// We have some sensitive values, but we don't have any unknown values.
+		Unknown:         false,
+		BeforeSensitive: unmarshalGeneric(resource.SensitiveValues),
+		AfterSensitive:  unmarshalGeneric(resource.SensitiveValues),
+
+		// We don't display replacement data for resources, and all attributes
+		// are relevant.
+		ReplacePaths:       attribute_path.Empty(false),
+		RelevantAttributes: attribute_path.AlwaysMatcher(),
+	}
+}
+
+// FromJsonOutput unmarshals the raw values in the jsonstate.Output structs into
+// generic interface{} types that can be reasoned about.
+func FromJsonOutput(output jsonstate.Output) Change {
+	return Change{
+		// We model resource formatting as NoOps.
+		Before: unmarshalGeneric(output.Value),
+		After:  unmarshalGeneric(output.Value),
+
+		// We have some sensitive values, but we don't have any unknown values.
+		Unknown:         false,
+		BeforeSensitive: output.Sensitive,
+		AfterSensitive:  output.Sensitive,
+
+		// We don't display replacement data for resources, and all attributes
+		// are relevant.
+		ReplacePaths:       attribute_path.Empty(false),
+		RelevantAttributes: attribute_path.AlwaysMatcher(),
+	}
+}
+
+// FromJsonViewsOutput unmarshals the raw values in the viewsjson.Output structs into
+// generic interface{} types that can be reasoned about.
+func FromJsonViewsOutput(output viewsjson.Output) Change {
+	return Change{
+		// We model resource formatting as NoOps.
+		Before: unmarshalGeneric(output.Value),
+		After:  unmarshalGeneric(output.Value),
+
+		// We have some sensitive values, but we don't have any unknown values.
+		Unknown:         false,
+		BeforeSensitive: output.Sensitive,
+		AfterSensitive:  output.Sensitive,
+
+		// We don't display replacement data for resources, and all attributes
+		// are relevant.
+		ReplacePaths:       attribute_path.Empty(false),
+		RelevantAttributes: attribute_path.AlwaysMatcher(),
+	}
+}
+
+// CalculateAction does a very simple analysis to make the best guess at the
+// action this change describes. For complex types such as objects, maps, lists,
+// or sets it is likely more efficient to work out the action directly instead
+// of relying on this function.
+func (change Change) CalculateAction() plans.Action {
+	if (change.Before == nil && !change.BeforeExplicit) && (change.After != nil || change.AfterExplicit) {
+		return plans.Create
+	}
+	if (change.After == nil && !change.AfterExplicit) && (change.Before != nil || change.BeforeExplicit) {
+		return plans.Delete
+	}
+
+	if reflect.DeepEqual(change.Before, change.After) && change.AfterExplicit == change.BeforeExplicit && change.IsAfterSensitive() == change.IsBeforeSensitive() {
+		return plans.NoOp
+	}
+
+	return plans.Update
+}
+
+// GetDefaultActionForIteration is used to guess what the change could be for
+// complex attributes (collections and objects) and blocks.
+//
+// You can't really tell the difference between a NoOp and an Update just by
+// looking at the attribute itself as you need to inspect the children.
+//
+// This function returns a Delete or a Create action if the before or after
+// values were null, and returns a NoOp for all other cases. It should be used
+// in conjunction with compareActions to calculate the actual action based on
+// the actions of the children.
+func (change Change) GetDefaultActionForIteration() plans.Action {
+	if change.Before == nil && change.After == nil {
+		return plans.NoOp
+	}
+
+	if change.Before == nil {
+		return plans.Create
+	}
+	if change.After == nil {
+		return plans.Delete
+	}
+	return plans.NoOp
+}
+
+// AsNoOp returns the current change as if it is a NoOp operation.
+//
+// Basically it replaces all the after values with the before values.
+func (change Change) AsNoOp() Change {
+	return Change{
+		BeforeExplicit:     change.BeforeExplicit,
+		AfterExplicit:      change.BeforeExplicit,
+		Before:             change.Before,
+		After:              change.Before,
+		Unknown:            false,
+		BeforeSensitive:    change.BeforeSensitive,
+		AfterSensitive:     change.BeforeSensitive,
+		ReplacePaths:       change.ReplacePaths,
+		RelevantAttributes: change.RelevantAttributes,
+	}
+}
+
+// AsDelete returns the current change as if it is a Delete operation.
+//
+// Basically it replaces all the after values with nil or false.
+func (change Change) AsDelete() Change {
+	return Change{
+		BeforeExplicit:     change.BeforeExplicit,
+		AfterExplicit:      false,
+		Before:             change.Before,
+		After:              nil,
+		Unknown:            nil,
+		BeforeSensitive:    change.BeforeSensitive,
+		AfterSensitive:     nil,
+		ReplacePaths:       change.ReplacePaths,
+		RelevantAttributes: change.RelevantAttributes,
+	}
+}
+
+// AsCreate returns the current change as if it is a Create operation.
+//
+// Basically it replaces all the before values with nil or false.
+func (change Change) AsCreate() Change {
+	return Change{
+		BeforeExplicit:     false,
+		AfterExplicit:      change.AfterExplicit,
+		Before:             nil,
+		After:              change.After,
+		Unknown:            change.Unknown,
+		BeforeSensitive:    nil,
+		AfterSensitive:     change.AfterSensitive,
+		ReplacePaths:       change.ReplacePaths,
+		RelevantAttributes: change.RelevantAttributes,
+	}
+}
+
+func unmarshalGeneric(raw json.RawMessage) interface{} {
+	if raw == nil {
+		return nil
+	}
+
+	var out interface{}
+	if err := json.Unmarshal(raw, &out); err != nil {
+		panic("unrecognized json type: " + err.Error())
+	}
+	return out
+}
+
+func unwrapAttributeValues(values jsonstate.AttributeValues) map[string]interface{} {
+	out := make(map[string]interface{})
+	for key, value := range values {
+		out[key] = unmarshalGeneric(value)
+	}
+	return out
+}
diff --git a/v1.5.7/internal/command/jsonformat/structured/doc.go b/v1.5.7/internal/command/jsonformat/structured/doc.go
new file mode 100644
index 0000000..2270d0e
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/structured/doc.go
@@ -0,0 +1,9 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package structured contains the structured representation of the JSON changes
+// returned by the jsonplan package.
+//
+// Placing these in a dedicated package allows for greater reuse across the
+// various type of renderers.
+package structured
diff --git a/v1.5.7/internal/command/jsonformat/structured/map.go b/v1.5.7/internal/command/jsonformat/structured/map.go
new file mode 100644
index 0000000..54e9353
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/structured/map.go
@@ -0,0 +1,163 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package structured
+
+import (
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path"
+)
+
+// ChangeMap is a Change that represents a Map or an Object type, and has
+// converted the relevant interfaces into maps for easier access.
+type ChangeMap struct {
+	// Before contains the value before the proposed change.
+	Before map[string]interface{}
+
+	// After contains the value after the proposed change.
+	After map[string]interface{}
+
+	// Unknown contains the unknown status of any elements/attributes of this
+	// map/object.
+	Unknown map[string]interface{}
+
+	// BeforeSensitive contains the before sensitive status of any
+	// elements/attributes of this map/object.
+	BeforeSensitive map[string]interface{}
+
+	// AfterSensitive contains the after sensitive status of any
+	// elements/attributes of this map/object.
+	AfterSensitive map[string]interface{}
+
+	// ReplacePaths matches the same attributes in Change exactly.
+	ReplacePaths attribute_path.Matcher
+
+	// RelevantAttributes matches the same attributes in Change exactly.
+	RelevantAttributes attribute_path.Matcher
+}
+
+// AsMap converts the Change into an object or map representation by converting
+// the internal Before, After, Unknown, BeforeSensitive, and AfterSensitive
+// data structures into generic maps.
+func (change Change) AsMap() ChangeMap {
+	return ChangeMap{
+		Before:             genericToMap(change.Before),
+		After:              genericToMap(change.After),
+		Unknown:            genericToMap(change.Unknown),
+		BeforeSensitive:    genericToMap(change.BeforeSensitive),
+		AfterSensitive:     genericToMap(change.AfterSensitive),
+		ReplacePaths:       change.ReplacePaths,
+		RelevantAttributes: change.RelevantAttributes,
+	}
+}
+
+// GetChild safely packages up a Change object for the given child, handling
+// all the cases where the data might be null or a static boolean.
+func (m ChangeMap) GetChild(key string) Change {
+	before, beforeExplicit := getFromGenericMap(m.Before, key)
+	after, afterExplicit := getFromGenericMap(m.After, key)
+	unknown, _ := getFromGenericMap(m.Unknown, key)
+	beforeSensitive, _ := getFromGenericMap(m.BeforeSensitive, key)
+	afterSensitive, _ := getFromGenericMap(m.AfterSensitive, key)
+
+	return Change{
+		BeforeExplicit:     beforeExplicit,
+		AfterExplicit:      afterExplicit,
+		Before:             before,
+		After:              after,
+		Unknown:            unknown,
+		BeforeSensitive:    beforeSensitive,
+		AfterSensitive:     afterSensitive,
+		ReplacePaths:       m.ReplacePaths.GetChildWithKey(key),
+		RelevantAttributes: m.RelevantAttributes.GetChildWithKey(key),
+	}
+}
+
+// ExplicitKeys returns the keys in the Before and After, as opposed to AllKeys
+// which also includes keys from the additional meta structures (like the
+// sensitive and unknown values).
+//
+// This function is useful for processing nested attributes and repeated blocks
+// where the unknown and sensitive structs contain information about the actual
+// attributes, while the before and after structs hold the actual nested values.
+func (m ChangeMap) ExplicitKeys() []string {
+	keys := make(map[string]bool)
+	for before := range m.Before {
+		if _, ok := keys[before]; ok {
+			continue
+		}
+		keys[before] = true
+	}
+	for after := range m.After {
+		if _, ok := keys[after]; ok {
+			continue
+		}
+		keys[after] = true
+	}
+
+	var dedupedKeys []string
+	for key := range keys {
+		dedupedKeys = append(dedupedKeys, key)
+	}
+	return dedupedKeys
+}
+
+// AllKeys returns all the possible keys for this map. The keys for the map are
+// potentially hidden and spread across multiple internal data structures and
+// so this function conveniently packages them up.
+func (m ChangeMap) AllKeys() []string {
+	keys := make(map[string]bool)
+	for before := range m.Before {
+		if _, ok := keys[before]; ok {
+			continue
+		}
+		keys[before] = true
+	}
+	for after := range m.After {
+		if _, ok := keys[after]; ok {
+			continue
+		}
+		keys[after] = true
+	}
+	for unknown := range m.Unknown {
+		if _, ok := keys[unknown]; ok {
+			continue
+		}
+		keys[unknown] = true
+	}
+	for sensitive := range m.AfterSensitive {
+		if _, ok := keys[sensitive]; ok {
+			continue
+		}
+		keys[sensitive] = true
+	}
+	for sensitive := range m.BeforeSensitive {
+		if _, ok := keys[sensitive]; ok {
+			continue
+		}
+		keys[sensitive] = true
+	}
+
+	var dedupedKeys []string
+	for key := range keys {
+		dedupedKeys = append(dedupedKeys, key)
+	}
+	return dedupedKeys
+}
+
+func getFromGenericMap(generic map[string]interface{}, key string) (interface{}, bool) {
+	if generic == nil {
+		return nil, false
+	}
+
+	if child, ok := generic[key]; ok {
+		return child, ok
+	}
+	return nil, false
+}
+
+func genericToMap(generic interface{}) map[string]interface{} {
+	if concrete, ok := generic.(map[string]interface{}); ok {
+		return concrete
+	}
+	return nil
+}
diff --git a/v1.5.7/internal/command/jsonformat/structured/sensitive.go b/v1.5.7/internal/command/jsonformat/structured/sensitive.go
new file mode 100644
index 0000000..ea07391
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/structured/sensitive.go
@@ -0,0 +1,92 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package structured
+
+import (
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+type ProcessSensitiveInner func(change Change) computed.Diff
+type CreateSensitiveDiff func(inner computed.Diff, beforeSensitive, afterSensitive bool, action plans.Action) computed.Diff
+
+func (change Change) IsBeforeSensitive() bool {
+	if sensitive, ok := change.BeforeSensitive.(bool); ok {
+		return sensitive
+	}
+	return false
+}
+
+func (change Change) IsAfterSensitive() bool {
+	if sensitive, ok := change.AfterSensitive.(bool); ok {
+		return sensitive
+	}
+	return false
+}
+
+// CheckForSensitive is a helper function that handles all common functionality
+// for processing a sensitive value.
+//
+// It returns the computed sensitive diff and true if this value was sensitive
+// and needs to be rendered as such, otherwise it returns the second return
+// value as false and the first value can be discarded.
+//
+// The actual processing of sensitive values happens within the
+// ProcessSensitiveInner and CreateSensitiveDiff functions. Callers should
+// implement these functions as appropriate when using this function.
+//
+// The ProcessSensitiveInner function should simply return a computed.Diff for
+// the provided Change. The provided Change will be the same as the original
+// change but with the sensitive metadata removed. The new inner diff is then
+// passed into the actual CreateSensitiveDiff function which should return the
+// actual sensitive diff.
+//
+// We include the inner change into the sensitive diff as a way to let the
+// sensitive renderer have as much information as possible, while still letting
+// it do the actual rendering.
+func (change Change) CheckForSensitive(processInner ProcessSensitiveInner, createDiff CreateSensitiveDiff) (computed.Diff, bool) {
+	beforeSensitive := change.IsBeforeSensitive()
+	afterSensitive := change.IsAfterSensitive()
+
+	if !beforeSensitive && !afterSensitive {
+		return computed.Diff{}, false
+	}
+
+	// We are still going to give the change the contents of the actual change.
+	// So we create a new Change with everything matching the current value,
+	// except for the sensitivity.
+	//
+	// The change can choose what to do with this information, in most cases
+	// it will just be ignored in favour of printing `(sensitive value)`.
+
+	value := Change{
+		BeforeExplicit:     change.BeforeExplicit,
+		AfterExplicit:      change.AfterExplicit,
+		Before:             change.Before,
+		After:              change.After,
+		Unknown:            change.Unknown,
+		BeforeSensitive:    false,
+		AfterSensitive:     false,
+		ReplacePaths:       change.ReplacePaths,
+		RelevantAttributes: change.RelevantAttributes,
+	}
+
+	inner := processInner(value)
+
+	action := inner.Action
+	sensitiveStatusChanged := beforeSensitive != afterSensitive
+
+	// nullNoOp is a stronger NoOp, where not only is there no change happening
+	// but the before and after values are not explicitly set and are both
+	// null. This will override even the sensitive state changing.
+	nullNoOp := change.Before == nil && !change.BeforeExplicit && change.After == nil && !change.AfterExplicit
+
+	if action == plans.NoOp && sensitiveStatusChanged && !nullNoOp {
+		// Let's override this, since it means the sensitive status has changed
+		// rather than the actual content of the value.
+		action = plans.Update
+	}
+
+	return createDiff(inner, beforeSensitive, afterSensitive, action), true
+}
diff --git a/v1.5.7/internal/command/jsonformat/structured/slice.go b/v1.5.7/internal/command/jsonformat/structured/slice.go
new file mode 100644
index 0000000..560f397
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/structured/slice.go
@@ -0,0 +1,94 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package structured
+
+import (
+	"github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path"
+)
+
+// ChangeSlice is a Change that represents a Tuple, Set, or List type, and has
+// converted the relevant interfaces into slices for easier access.
+type ChangeSlice struct {
+	// Before contains the value before the proposed change.
+	Before []interface{}
+
+	// After contains the value after the proposed change.
+	After []interface{}
+
+	// Unknown contains the unknown status of any elements of this list/set.
+	Unknown []interface{}
+
+	// BeforeSensitive contains the before sensitive status of any elements of
+	//this list/set.
+	BeforeSensitive []interface{}
+
+	// AfterSensitive contains the after sensitive status of any elements of
+	//this list/set.
+	AfterSensitive []interface{}
+
+	// ReplacePaths matches the same attributes in Change exactly.
+	ReplacePaths attribute_path.Matcher
+
+	// RelevantAttributes matches the same attributes in Change exactly.
+	RelevantAttributes attribute_path.Matcher
+}
+
+// AsSlice converts the Change into a slice representation by converting the
+// internal Before, After, Unknown, BeforeSensitive, and AfterSensitive data
+// structures into generic slices.
+func (change Change) AsSlice() ChangeSlice {
+	return ChangeSlice{
+		Before:             genericToSlice(change.Before),
+		After:              genericToSlice(change.After),
+		Unknown:            genericToSlice(change.Unknown),
+		BeforeSensitive:    genericToSlice(change.BeforeSensitive),
+		AfterSensitive:     genericToSlice(change.AfterSensitive),
+		ReplacePaths:       change.ReplacePaths,
+		RelevantAttributes: change.RelevantAttributes,
+	}
+}
+
+// GetChild safely packages up a Change object for the given child, handling
+// all the cases where the data might be null or a static boolean.
+func (s ChangeSlice) GetChild(beforeIx, afterIx int) Change {
+	before, beforeExplicit := getFromGenericSlice(s.Before, beforeIx)
+	after, afterExplicit := getFromGenericSlice(s.After, afterIx)
+	unknown, _ := getFromGenericSlice(s.Unknown, afterIx)
+	beforeSensitive, _ := getFromGenericSlice(s.BeforeSensitive, beforeIx)
+	afterSensitive, _ := getFromGenericSlice(s.AfterSensitive, afterIx)
+
+	mostRelevantIx := beforeIx
+	if beforeIx < 0 || beforeIx >= len(s.Before) {
+		mostRelevantIx = afterIx
+	}
+
+	return Change{
+		BeforeExplicit:     beforeExplicit,
+		AfterExplicit:      afterExplicit,
+		Before:             before,
+		After:              after,
+		Unknown:            unknown,
+		BeforeSensitive:    beforeSensitive,
+		AfterSensitive:     afterSensitive,
+		ReplacePaths:       s.ReplacePaths.GetChildWithIndex(mostRelevantIx),
+		RelevantAttributes: s.RelevantAttributes.GetChildWithIndex(mostRelevantIx),
+	}
+}
+
+func getFromGenericSlice(generic []interface{}, ix int) (interface{}, bool) {
+	if generic == nil {
+		return nil, false
+	}
+	if ix < 0 || ix >= len(generic) {
+		return nil, false
+	}
+	return generic[ix], true
+}
+
+func genericToSlice(generic interface{}) []interface{} {
+	if concrete, ok := generic.([]interface{}); ok {
+		return concrete
+	}
+	return nil
+}
diff --git a/v1.5.7/internal/command/jsonformat/structured/unknown.go b/v1.5.7/internal/command/jsonformat/structured/unknown.go
new file mode 100644
index 0000000..319824a
--- /dev/null
+++ b/v1.5.7/internal/command/jsonformat/structured/unknown.go
@@ -0,0 +1,65 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package structured
+
+import (
+	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
+)
+
+type ProcessUnknown func(current Change) computed.Diff
+type ProcessUnknownWithBefore func(current Change, before Change) computed.Diff
+
+func (change Change) IsUnknown() bool {
+	if unknown, ok := change.Unknown.(bool); ok {
+		return unknown
+	}
+	return false
+}
+
+// CheckForUnknown is a helper function that handles all common functionality
+// for processing an unknown value.
+//
+// It returns the computed unknown diff and true if this value was unknown and
+// needs to be rendered as such, otherwise it returns the second return value as
+// false and the first return value should be discarded.
+//
+// The actual processing of unknown values happens in the ProcessUnknown and
+// ProcessUnknownWithBefore functions. If a value is unknown and is being
+// created, the ProcessUnknown function is called and the caller should decide
+// how to create the unknown value. If a value is being updated the
+// ProcessUnknownWithBefore function is called and the function provides the
+// before value as if it is being deleted for the caller to handle. Note that
+// values being deleted will never be marked as unknown so this case isn't
+// handled.
+//
+// The childUnknown argument is meant to allow callers with extra information
+// about the type being processed to provide a list of known children that might
+// not be present in the before or after values. These values will be propagated
+// as the unknown values in the before value should it be needed.
+func (change Change) CheckForUnknown(childUnknown interface{}, process ProcessUnknown, processBefore ProcessUnknownWithBefore) (computed.Diff, bool) {
+	unknown := change.IsUnknown()
+
+	if !unknown {
+		return computed.Diff{}, false
+	}
+
+	// No matter what we do here, we want to treat the after value as explicit.
+	// This is because it is going to be null in the value, and we don't want
+	// the functions in this package to assume this means it has been deleted.
+	change.AfterExplicit = true
+
+	if change.Before == nil {
+		return process(change), true
+	}
+
+	// If we get here, then we have a before value. We're going to model a
+	// delete operation and our renderer later can render the overall change
+	// accurately.
+	before := change.AsDelete()
+
+	// We also let our callers override the unknown values in any before, this
+	// is the renderers can display them as being computed instead of deleted.
+	before.Unknown = childUnknown
+	return processBefore(change, before), true
+}
diff --git a/v1.5.7/internal/command/jsonfunction/function.go b/v1.5.7/internal/command/jsonfunction/function.go
new file mode 100644
index 0000000..2652c83
--- /dev/null
+++ b/v1.5.7/internal/command/jsonfunction/function.go
@@ -0,0 +1,148 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonfunction
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+)
+
+// FormatVersion represents the version of the json format and will be
+// incremented for any change to this format that requires changes to a
+// consuming parser.
+const FormatVersion = "1.0"
+
+// functions is the top-level object returned when exporting function signatures
+type functions struct {
+	FormatVersion string                        `json:"format_version"`
+	Signatures    map[string]*FunctionSignature `json:"function_signatures,omitempty"`
+}
+
+// FunctionSignature represents a function signature.
+type FunctionSignature struct {
+	// Description is an optional human-readable description
+	// of the function
+	Description string `json:"description,omitempty"`
+
+	// ReturnTypes is the ctyjson representation of the function's
+	// return types based on supplying all parameters using
+	// dynamic types. Functions can have dynamic return types.
+	ReturnType cty.Type `json:"return_type"`
+
+	// Parameters describes the function's fixed positional parameters.
+	Parameters []*parameter `json:"parameters,omitempty"`
+
+	// VariadicParameter describes the function's variadic
+	// parameters, if any are supported.
+	VariadicParameter *parameter `json:"variadic_parameter,omitempty"`
+}
+
+func newFunctions() *functions {
+	signatures := make(map[string]*FunctionSignature)
+	return &functions{
+		FormatVersion: FormatVersion,
+		Signatures:    signatures,
+	}
+}
+
+func Marshal(f map[string]function.Function) ([]byte, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	signatures := newFunctions()
+
+	for name, v := range f {
+		if name == "can" {
+			signatures.Signatures[name] = marshalCan(v)
+		} else if name == "try" {
+			signatures.Signatures[name] = marshalTry(v)
+		} else {
+			signature, err := marshalFunction(v)
+			if err != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					fmt.Sprintf("Failed to serialize function %q", name),
+					err.Error(),
+				))
+			}
+			signatures.Signatures[name] = signature
+		}
+	}
+
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	ret, err := json.Marshal(signatures)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to serialize functions",
+			err.Error(),
+		))
+		return nil, diags
+	}
+	return ret, nil
+}
+
+func marshalFunction(f function.Function) (*FunctionSignature, error) {
+	var err error
+	var vp *parameter
+	if f.VarParam() != nil {
+		vp = marshalParameter(f.VarParam())
+	}
+
+	var p []*parameter
+	if len(f.Params()) > 0 {
+		p = marshalParameters(f.Params())
+	}
+
+	r, err := getReturnType(f)
+	if err != nil {
+		return nil, err
+	}
+
+	return &FunctionSignature{
+		Description:       f.Description(),
+		ReturnType:        r,
+		Parameters:        p,
+		VariadicParameter: vp,
+	}, nil
+}
+
+// marshalTry returns a static function signature for the try function.
+// We need this exception because the function implementation uses capsule
+// types that we can't marshal.
+func marshalTry(try function.Function) *FunctionSignature {
+	return &FunctionSignature{
+		Description: try.Description(),
+		ReturnType:  cty.DynamicPseudoType,
+		VariadicParameter: &parameter{
+			Name:        try.VarParam().Name,
+			Description: try.VarParam().Description,
+			IsNullable:  try.VarParam().AllowNull,
+			Type:        cty.DynamicPseudoType,
+		},
+	}
+}
+
+// marshalCan returns a static function signature for the can function.
+// We need this exception because the function implementation uses capsule
+// types that we can't marshal.
+func marshalCan(can function.Function) *FunctionSignature {
+	return &FunctionSignature{
+		Description: can.Description(),
+		ReturnType:  cty.Bool,
+		Parameters: []*parameter{
+			{
+				Name:        can.Params()[0].Name,
+				Description: can.Params()[0].Description,
+				IsNullable:  can.Params()[0].AllowNull,
+				Type:        cty.DynamicPseudoType,
+			},
+		},
+	}
+}
diff --git a/v1.5.7/internal/command/jsonfunction/function_test.go b/v1.5.7/internal/command/jsonfunction/function_test.go
new file mode 100644
index 0000000..818293b
--- /dev/null
+++ b/v1.5.7/internal/command/jsonfunction/function_test.go
@@ -0,0 +1,137 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonfunction
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty-debug/ctydebug"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+)
+
+func TestMarshal(t *testing.T) {
+	tests := []struct {
+		Name    string
+		Input   map[string]function.Function
+		Want    string
+		WantErr string
+	}{
+		{
+			"minimal function",
+			map[string]function.Function{
+				"fun": function.New(&function.Spec{
+					Type: function.StaticReturnType(cty.Bool),
+				}),
+			},
+			`{"format_version":"1.0","function_signatures":{"fun":{"return_type":"bool"}}}`,
+			"",
+		},
+		{
+			"function with description",
+			map[string]function.Function{
+				"fun": function.New(&function.Spec{
+					Description: "`timestamp` returns a UTC timestamp string.",
+					Type:        function.StaticReturnType(cty.String),
+				}),
+			},
+			"{\"format_version\":\"1.0\",\"function_signatures\":{\"fun\":{\"description\":\"`timestamp` returns a UTC timestamp string.\",\"return_type\":\"string\"}}}",
+			"",
+		},
+		{
+			"function with parameters",
+			map[string]function.Function{
+				"fun": function.New(&function.Spec{
+					Params: []function.Parameter{
+						{
+							Name:        "timestamp",
+							Description: "timestamp text",
+							Type:        cty.String,
+						},
+						{
+							Name:        "duration",
+							Description: "duration text",
+							Type:        cty.String,
+						},
+					},
+					Type: function.StaticReturnType(cty.String),
+				}),
+			},
+			`{"format_version":"1.0","function_signatures":{"fun":{"return_type":"string","parameters":[{"name":"timestamp","description":"timestamp text","type":"string"},{"name":"duration","description":"duration text","type":"string"}]}}}`,
+			"",
+		},
+		{
+			"function with variadic parameter",
+			map[string]function.Function{
+				"fun": function.New(&function.Spec{
+					VarParam: &function.Parameter{
+						Name:             "default",
+						Description:      "default description",
+						Type:             cty.DynamicPseudoType,
+						AllowUnknown:     true,
+						AllowDynamicType: true,
+						AllowNull:        true,
+						AllowMarked:      true,
+					},
+					Type: function.StaticReturnType(cty.DynamicPseudoType),
+				}),
+			},
+			`{"format_version":"1.0","function_signatures":{"fun":{"return_type":"dynamic","variadic_parameter":{"name":"default","description":"default description","is_nullable":true,"type":"dynamic"}}}}`,
+			"",
+		},
+		{
+			"function with list types",
+			map[string]function.Function{
+				"fun": function.New(&function.Spec{
+					Params: []function.Parameter{
+						{
+							Name: "list",
+							Type: cty.List(cty.String),
+						},
+					},
+					Type: function.StaticReturnType(cty.List(cty.String)),
+				}),
+			},
+			`{"format_version":"1.0","function_signatures":{"fun":{"return_type":["list","string"],"parameters":[{"name":"list","type":["list","string"]}]}}}`,
+			"",
+		},
+		{
+			"returns diagnostics on failure",
+			map[string]function.Function{
+				"fun": function.New(&function.Spec{
+					Params: []function.Parameter{},
+					Type: func(args []cty.Value) (ret cty.Type, err error) {
+						return cty.DynamicPseudoType, fmt.Errorf("error")
+					},
+				}),
+			},
+			"",
+			"Failed to serialize function \"fun\": error",
+		},
+	}
+
+	for i, test := range tests {
+		t.Run(fmt.Sprintf("%d-%s", i, test.Name), func(t *testing.T) {
+			got, diags := Marshal(test.Input)
+			if test.WantErr != "" {
+				if !diags.HasErrors() {
+					t.Fatal("expected error, got none")
+				}
+				if diags.Err().Error() != test.WantErr {
+					t.Fatalf("expected error %q, got %q", test.WantErr, diags.Err())
+				}
+			} else {
+				if diags.HasErrors() {
+					t.Fatal(diags)
+				}
+
+				if diff := cmp.Diff(test.Want, string(got), ctydebug.CmpOptions); diff != "" {
+					t.Fatalf("mismatch of function signature: %s", diff)
+				}
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/jsonfunction/parameter.go b/v1.5.7/internal/command/jsonfunction/parameter.go
new file mode 100644
index 0000000..ac90797
--- /dev/null
+++ b/v1.5.7/internal/command/jsonfunction/parameter.go
@@ -0,0 +1,46 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonfunction
+
+import (
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+)
+
+// parameter represents a parameter to a function.
+type parameter struct {
+	// Name is an optional name for the argument.
+	Name string `json:"name,omitempty"`
+
+	// Description is an optional human-readable description
+	// of the argument
+	Description string `json:"description,omitempty"`
+
+	// IsNullable is true if null is acceptable value for the argument
+	IsNullable bool `json:"is_nullable,omitempty"`
+
+	// A type that any argument for this parameter must conform to.
+	Type cty.Type `json:"type"`
+}
+
+func marshalParameter(p *function.Parameter) *parameter {
+	if p == nil {
+		return &parameter{}
+	}
+
+	return &parameter{
+		Name:        p.Name,
+		Description: p.Description,
+		IsNullable:  p.AllowNull,
+		Type:        p.Type,
+	}
+}
+
+func marshalParameters(parameters []function.Parameter) []*parameter {
+	ret := make([]*parameter, len(parameters))
+	for k, p := range parameters {
+		ret[k] = marshalParameter(&p)
+	}
+	return ret
+}
diff --git a/v1.5.7/internal/command/jsonfunction/parameter_test.go b/v1.5.7/internal/command/jsonfunction/parameter_test.go
new file mode 100644
index 0000000..1afef3c
--- /dev/null
+++ b/v1.5.7/internal/command/jsonfunction/parameter_test.go
@@ -0,0 +1,67 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonfunction
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty-debug/ctydebug"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+)
+
+func TestMarshalParameter(t *testing.T) {
+	tests := []struct {
+		Name  string
+		Input *function.Parameter
+		Want  *parameter
+	}{
+		{
+			"call with nil",
+			nil,
+			&parameter{},
+		},
+		{
+			"parameter with description",
+			&function.Parameter{
+				Name:        "timestamp",
+				Description: "`timestamp` returns a UTC timestamp string in [RFC 3339]",
+				Type:        cty.String,
+			},
+			&parameter{
+				Name:        "timestamp",
+				Description: "`timestamp` returns a UTC timestamp string in [RFC 3339]",
+				Type:        cty.String,
+			},
+		},
+		{
+			"parameter with additional properties",
+			&function.Parameter{
+				Name:             "value",
+				Type:             cty.DynamicPseudoType,
+				AllowUnknown:     true,
+				AllowNull:        true,
+				AllowMarked:      true,
+				AllowDynamicType: true,
+			},
+			&parameter{
+				Name:       "value",
+				Type:       cty.DynamicPseudoType,
+				IsNullable: true,
+			},
+		},
+	}
+
+	for i, test := range tests {
+		t.Run(fmt.Sprintf("%d-%s", i, test.Name), func(t *testing.T) {
+			got := marshalParameter(test.Input)
+
+			if diff := cmp.Diff(test.Want, got, ctydebug.CmpOptions); diff != "" {
+				t.Fatalf("mismatch of parameter signature: %s", diff)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/jsonfunction/return_type.go b/v1.5.7/internal/command/jsonfunction/return_type.go
new file mode 100644
index 0000000..d6889c3
--- /dev/null
+++ b/v1.5.7/internal/command/jsonfunction/return_type.go
@@ -0,0 +1,21 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonfunction
+
+import (
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+)
+
+func getReturnType(f function.Function) (cty.Type, error) {
+	args := make([]cty.Type, 0)
+	for _, param := range f.Params() {
+		args = append(args, param.Type)
+	}
+	if f.VarParam() != nil {
+		args = append(args, f.VarParam().Type)
+	}
+
+	return f.ReturnType(args)
+}
diff --git a/v1.5.7/internal/command/jsonplan/doc.go b/v1.5.7/internal/command/jsonplan/doc.go
new file mode 100644
index 0000000..e005b60
--- /dev/null
+++ b/v1.5.7/internal/command/jsonplan/doc.go
@@ -0,0 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package jsonplan implements methods for outputting a plan in a
+// machine-readable json format
+package jsonplan
diff --git a/v1.5.7/internal/command/jsonplan/module.go b/v1.5.7/internal/command/jsonplan/module.go
new file mode 100644
index 0000000..289da7f
--- /dev/null
+++ b/v1.5.7/internal/command/jsonplan/module.go
@@ -0,0 +1,19 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonplan
+
+// module is the representation of a module in state. This can be the root
+// module or a child module.
+type module struct {
+	// Resources are sorted in a user-friendly order that is undefined at this
+	// time, but consistent.
+	Resources []resource `json:"resources,omitempty"`
+
+	// Address is the absolute module address, omitted for the root module
+	Address string `json:"address,omitempty"`
+
+	// Each module object can optionally have its own nested "child_modules",
+	// recursively describing the full module tree.
+	ChildModules []module `json:"child_modules,omitempty"`
+}
diff --git a/v1.5.7/internal/command/jsonplan/plan.go b/v1.5.7/internal/command/jsonplan/plan.go
new file mode 100644
index 0000000..a209761
--- /dev/null
+++ b/v1.5.7/internal/command/jsonplan/plan.go
@@ -0,0 +1,906 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonplan
+
+import (
+	"encoding/json"
+	"fmt"
+	"sort"
+	"strings"
+	"time"
+
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/jsonchecks"
+	"github.com/hashicorp/terraform/internal/command/jsonconfig"
+	"github.com/hashicorp/terraform/internal/command/jsonstate"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/version"
+)
+
+// FormatVersion represents the version of the json format and will be
+// incremented for any change to this format that requires changes to a
+// consuming parser.
+const (
+	FormatVersion = "1.2"
+
+	ResourceInstanceReplaceBecauseCannotUpdate    = "replace_because_cannot_update"
+	ResourceInstanceReplaceBecauseTainted         = "replace_because_tainted"
+	ResourceInstanceReplaceByRequest              = "replace_by_request"
+	ResourceInstanceReplaceByTriggers             = "replace_by_triggers"
+	ResourceInstanceDeleteBecauseNoResourceConfig = "delete_because_no_resource_config"
+	ResourceInstanceDeleteBecauseWrongRepetition  = "delete_because_wrong_repetition"
+	ResourceInstanceDeleteBecauseCountIndex       = "delete_because_count_index"
+	ResourceInstanceDeleteBecauseEachKey          = "delete_because_each_key"
+	ResourceInstanceDeleteBecauseNoModule         = "delete_because_no_module"
+	ResourceInstanceDeleteBecauseNoMoveTarget     = "delete_because_no_move_target"
+	ResourceInstanceReadBecauseConfigUnknown      = "read_because_config_unknown"
+	ResourceInstanceReadBecauseDependencyPending  = "read_because_dependency_pending"
+	ResourceInstanceReadBecauseCheckNested        = "read_because_check_nested"
+)
+
+// Plan is the top-level representation of the json format of a plan. It includes
+// the complete config and current state.
+type plan struct {
+	FormatVersion    string      `json:"format_version,omitempty"`
+	TerraformVersion string      `json:"terraform_version,omitempty"`
+	Variables        variables   `json:"variables,omitempty"`
+	PlannedValues    stateValues `json:"planned_values,omitempty"`
+	// ResourceDrift and ResourceChanges are sorted in a user-friendly order
+	// that is undefined at this time, but consistent.
+	ResourceDrift      []ResourceChange  `json:"resource_drift,omitempty"`
+	ResourceChanges    []ResourceChange  `json:"resource_changes,omitempty"`
+	OutputChanges      map[string]Change `json:"output_changes,omitempty"`
+	PriorState         json.RawMessage   `json:"prior_state,omitempty"`
+	Config             json.RawMessage   `json:"configuration,omitempty"`
+	RelevantAttributes []ResourceAttr    `json:"relevant_attributes,omitempty"`
+	Checks             json.RawMessage   `json:"checks,omitempty"`
+	Timestamp          string            `json:"timestamp,omitempty"`
+}
+
+func newPlan() *plan {
+	return &plan{
+		FormatVersion: FormatVersion,
+	}
+}
+
+// ResourceAttr contains the address and attribute of an external for the
+// RelevantAttributes in the plan.
+type ResourceAttr struct {
+	Resource string          `json:"resource"`
+	Attr     json.RawMessage `json:"attribute"`
+}
+
+// Change is the representation of a proposed change for an object.
+type Change struct {
+	// Actions are the actions that will be taken on the object selected by the
+	// properties below. Valid actions values are:
+	//    ["no-op"]
+	//    ["create"]
+	//    ["read"]
+	//    ["update"]
+	//    ["delete", "create"]
+	//    ["create", "delete"]
+	//    ["delete"]
+	// The two "replace" actions are represented in this way to allow callers to
+	// e.g. just scan the list for "delete" to recognize all three situations
+	// where the object will be deleted, allowing for any new deletion
+	// combinations that might be added in future.
+	Actions []string `json:"actions,omitempty"`
+
+	// Before and After are representations of the object value both before and
+	// after the action. For ["create"] and ["delete"] actions, either "before"
+	// or "after" is unset (respectively). For ["no-op"], the before and after
+	// values are identical. The "after" value will be incomplete if there are
+	// values within it that won't be known until after apply.
+	Before json.RawMessage `json:"before,omitempty"`
+	After  json.RawMessage `json:"after,omitempty"`
+
+	// AfterUnknown is an object value with similar structure to After, but
+	// with all unknown leaf values replaced with true, and all known leaf
+	// values omitted.  This can be combined with After to reconstruct a full
+	// value after the action, including values which will only be known after
+	// apply.
+	AfterUnknown json.RawMessage `json:"after_unknown,omitempty"`
+
+	// BeforeSensitive and AfterSensitive are object values with similar
+	// structure to Before and After, but with all sensitive leaf values
+	// replaced with true, and all non-sensitive leaf values omitted. These
+	// objects should be combined with Before and After to prevent accidental
+	// display of sensitive values in user interfaces.
+	BeforeSensitive json.RawMessage `json:"before_sensitive,omitempty"`
+	AfterSensitive  json.RawMessage `json:"after_sensitive,omitempty"`
+
+	// ReplacePaths is an array of arrays representing a set of paths into the
+	// object value which resulted in the action being "replace". This will be
+	// omitted if the action is not replace, or if no paths caused the
+	// replacement (for example, if the resource was tainted). Each path
+	// consists of one or more steps, each of which will be a number or a
+	// string.
+	ReplacePaths json.RawMessage `json:"replace_paths,omitempty"`
+
+	// Importing contains the import metadata about this operation. If importing
+	// is present (ie. not null) then the change is an import operation in
+	// addition to anything mentioned in the actions field. The actual contents
+	// of the Importing struct is subject to change, so downstream consumers
+	// should treat any values in here as strictly optional.
+	Importing *Importing `json:"importing,omitempty"`
+
+	// GeneratedConfig contains any HCL config generated for this resource
+	// during planning as a string.
+	//
+	// If this is populated, then Importing should also be populated but this
+	// might change in the future. However, nNot all Importing changes will
+	// contain generated config.
+	GeneratedConfig string `json:"generated_config,omitempty"`
+}
+
+// Importing is a nested object for the resource import metadata.
+type Importing struct {
+	// The original ID of this resource used to target it as part of planned
+	// import operation.
+	ID string `json:"id,omitempty"`
+}
+
+type output struct {
+	Sensitive bool            `json:"sensitive"`
+	Type      json.RawMessage `json:"type,omitempty"`
+	Value     json.RawMessage `json:"value,omitempty"`
+}
+
+// variables is the JSON representation of the variables provided to the current
+// plan.
+type variables map[string]*variable
+
+type variable struct {
+	Value json.RawMessage `json:"value,omitempty"`
+}
+
+// MarshalForRenderer returns the pre-json encoding changes of the requested
+// plan, in a format available to the structured renderer.
+//
+// This function does a small part of the Marshal function, as it only returns
+// the part of the plan required by the jsonformat.Plan renderer.
+func MarshalForRenderer(
+	p *plans.Plan,
+	schemas *terraform.Schemas,
+) (map[string]Change, []ResourceChange, []ResourceChange, []ResourceAttr, error) {
+	output := newPlan()
+
+	var err error
+	if output.OutputChanges, err = MarshalOutputChanges(p.Changes); err != nil {
+		return nil, nil, nil, nil, err
+	}
+
+	if output.ResourceChanges, err = MarshalResourceChanges(p.Changes.Resources, schemas); err != nil {
+		return nil, nil, nil, nil, err
+	}
+
+	if len(p.DriftedResources) > 0 {
+		// In refresh-only mode, we render all resources marked as drifted,
+		// including those which have moved without other changes. In other plan
+		// modes, move-only changes will be included in the planned changes, so
+		// we skip them here.
+		var driftedResources []*plans.ResourceInstanceChangeSrc
+		if p.UIMode == plans.RefreshOnlyMode {
+			driftedResources = p.DriftedResources
+		} else {
+			for _, dr := range p.DriftedResources {
+				if dr.Action != plans.NoOp {
+					driftedResources = append(driftedResources, dr)
+				}
+			}
+		}
+		output.ResourceDrift, err = MarshalResourceChanges(driftedResources, schemas)
+		if err != nil {
+			return nil, nil, nil, nil, err
+		}
+	}
+
+	if err := output.marshalRelevantAttrs(p); err != nil {
+		return nil, nil, nil, nil, err
+	}
+
+	return output.OutputChanges, output.ResourceChanges, output.ResourceDrift, output.RelevantAttributes, nil
+}
+
+// Marshal returns the json encoding of a terraform plan.
+func Marshal(
+	config *configs.Config,
+	p *plans.Plan,
+	sf *statefile.File,
+	schemas *terraform.Schemas,
+) ([]byte, error) {
+	output := newPlan()
+	output.TerraformVersion = version.String()
+	output.Timestamp = p.Timestamp.Format(time.RFC3339)
+
+	err := output.marshalPlanVariables(p.VariableValues, config.Module.Variables)
+	if err != nil {
+		return nil, fmt.Errorf("error in marshalPlanVariables: %s", err)
+	}
+
+	// output.PlannedValues
+	err = output.marshalPlannedValues(p.Changes, schemas)
+	if err != nil {
+		return nil, fmt.Errorf("error in marshalPlannedValues: %s", err)
+	}
+
+	// output.ResourceDrift
+	if len(p.DriftedResources) > 0 {
+		// In refresh-only mode, we render all resources marked as drifted,
+		// including those which have moved without other changes. In other plan
+		// modes, move-only changes will be included in the planned changes, so
+		// we skip them here.
+		var driftedResources []*plans.ResourceInstanceChangeSrc
+		if p.UIMode == plans.RefreshOnlyMode {
+			driftedResources = p.DriftedResources
+		} else {
+			for _, dr := range p.DriftedResources {
+				if dr.Action != plans.NoOp {
+					driftedResources = append(driftedResources, dr)
+				}
+			}
+		}
+		output.ResourceDrift, err = MarshalResourceChanges(driftedResources, schemas)
+		if err != nil {
+			return nil, fmt.Errorf("error in marshaling resource drift: %s", err)
+		}
+	}
+
+	if err := output.marshalRelevantAttrs(p); err != nil {
+		return nil, fmt.Errorf("error marshaling relevant attributes for external changes: %s", err)
+	}
+
+	// output.ResourceChanges
+	if p.Changes != nil {
+		output.ResourceChanges, err = MarshalResourceChanges(p.Changes.Resources, schemas)
+		if err != nil {
+			return nil, fmt.Errorf("error in marshaling resource changes: %s", err)
+		}
+	}
+
+	// output.OutputChanges
+	if output.OutputChanges, err = MarshalOutputChanges(p.Changes); err != nil {
+		return nil, fmt.Errorf("error in marshaling output changes: %s", err)
+	}
+
+	// output.Checks
+	if p.Checks != nil && p.Checks.ConfigResults.Len() > 0 {
+		output.Checks = jsonchecks.MarshalCheckStates(p.Checks)
+	}
+
+	// output.PriorState
+	if sf != nil && !sf.State.Empty() {
+		output.PriorState, err = jsonstate.Marshal(sf, schemas)
+		if err != nil {
+			return nil, fmt.Errorf("error marshaling prior state: %s", err)
+		}
+	}
+
+	// output.Config
+	output.Config, err = jsonconfig.Marshal(config, schemas)
+	if err != nil {
+		return nil, fmt.Errorf("error marshaling config: %s", err)
+	}
+
+	ret, err := json.Marshal(output)
+	return ret, err
+}
+
+func (p *plan) marshalPlanVariables(vars map[string]plans.DynamicValue, decls map[string]*configs.Variable) error {
+	p.Variables = make(variables, len(vars))
+
+	for k, v := range vars {
+		val, err := v.Decode(cty.DynamicPseudoType)
+		if err != nil {
+			return err
+		}
+		valJSON, err := ctyjson.Marshal(val, val.Type())
+		if err != nil {
+			return err
+		}
+		p.Variables[k] = &variable{
+			Value: valJSON,
+		}
+	}
+
+	// In Terraform v1.1 and earlier we had some confusion about which subsystem
+	// of Terraform was the one responsible for substituting in default values
+	// for unset module variables, with root module variables being handled in
+	// three different places while child module variables were only handled
+	// during the Terraform Core graph walk.
+	//
+	// For Terraform v1.2 and later we rationalized that by having the Terraform
+	// Core graph walk always be responsible for selecting defaults regardless
+	// of root vs. child module, but unfortunately our earlier accidental
+	// misbehavior bled out into the public interface by making the defaults
+	// show up in the "vars" map to this function. Those are now correctly
+	// omitted (so that the plan file only records the variables _actually_
+	// set by the caller) but consumers of the JSON plan format may be depending
+	// on our old behavior and so we'll fake it here just in time so that
+	// outside consumers won't see a behavior change.
+	for name, decl := range decls {
+		if _, ok := p.Variables[name]; ok {
+			continue
+		}
+		if val := decl.Default; val != cty.NilVal {
+			valJSON, err := ctyjson.Marshal(val, val.Type())
+			if err != nil {
+				return err
+			}
+			p.Variables[name] = &variable{
+				Value: valJSON,
+			}
+		}
+	}
+
+	if len(p.Variables) == 0 {
+		p.Variables = nil // omit this property if there are no variables to describe
+	}
+
+	return nil
+}
+
+// MarshalResourceChanges converts the provided internal representation of
+// ResourceInstanceChangeSrc objects into the public structured JSON changes.
+//
+// This function is referenced directly from the structured renderer tests, to
+// ensure parity between the renderers. It probably shouldn't be used anywhere
+// else.
+func MarshalResourceChanges(resources []*plans.ResourceInstanceChangeSrc, schemas *terraform.Schemas) ([]ResourceChange, error) {
+	var ret []ResourceChange
+
+	var sortedResources []*plans.ResourceInstanceChangeSrc
+	sortedResources = append(sortedResources, resources...)
+	sort.Slice(sortedResources, func(i, j int) bool {
+		if !sortedResources[i].Addr.Equal(sortedResources[j].Addr) {
+			return sortedResources[i].Addr.Less(sortedResources[j].Addr)
+		}
+		return sortedResources[i].DeposedKey < sortedResources[j].DeposedKey
+	})
+
+	for _, rc := range sortedResources {
+		var r ResourceChange
+		addr := rc.Addr
+		r.Address = addr.String()
+		if !addr.Equal(rc.PrevRunAddr) {
+			r.PreviousAddress = rc.PrevRunAddr.String()
+		}
+
+		dataSource := addr.Resource.Resource.Mode == addrs.DataResourceMode
+		// We create "delete" actions for data resources so we can clean up
+		// their entries in state, but this is an implementation detail that
+		// users shouldn't see.
+		if dataSource && rc.Action == plans.Delete {
+			continue
+		}
+
+		schema, _ := schemas.ResourceTypeConfig(
+			rc.ProviderAddr.Provider,
+			addr.Resource.Resource.Mode,
+			addr.Resource.Resource.Type,
+		)
+		if schema == nil {
+			return nil, fmt.Errorf("no schema found for %s (in provider %s)", r.Address, rc.ProviderAddr.Provider)
+		}
+
+		changeV, err := rc.Decode(schema.ImpliedType())
+		if err != nil {
+			return nil, err
+		}
+		// We drop the marks from the change, as decoding is only an
+		// intermediate step to re-encode the values as json
+		changeV.Before, _ = changeV.Before.UnmarkDeep()
+		changeV.After, _ = changeV.After.UnmarkDeep()
+
+		var before, after []byte
+		var beforeSensitive, afterSensitive []byte
+		var afterUnknown cty.Value
+
+		if changeV.Before != cty.NilVal {
+			before, err = ctyjson.Marshal(changeV.Before, changeV.Before.Type())
+			if err != nil {
+				return nil, err
+			}
+			marks := rc.BeforeValMarks
+			if schema.ContainsSensitive() {
+				marks = append(marks, schema.ValueMarks(changeV.Before, nil)...)
+			}
+			bs := jsonstate.SensitiveAsBool(changeV.Before.MarkWithPaths(marks))
+			beforeSensitive, err = ctyjson.Marshal(bs, bs.Type())
+			if err != nil {
+				return nil, err
+			}
+		}
+		if changeV.After != cty.NilVal {
+			if changeV.After.IsWhollyKnown() {
+				after, err = ctyjson.Marshal(changeV.After, changeV.After.Type())
+				if err != nil {
+					return nil, err
+				}
+				afterUnknown = cty.EmptyObjectVal
+			} else {
+				filteredAfter := omitUnknowns(changeV.After)
+				if filteredAfter.IsNull() {
+					after = nil
+				} else {
+					after, err = ctyjson.Marshal(filteredAfter, filteredAfter.Type())
+					if err != nil {
+						return nil, err
+					}
+				}
+				afterUnknown = unknownAsBool(changeV.After)
+			}
+			marks := rc.AfterValMarks
+			if schema.ContainsSensitive() {
+				marks = append(marks, schema.ValueMarks(changeV.After, nil)...)
+			}
+			as := jsonstate.SensitiveAsBool(changeV.After.MarkWithPaths(marks))
+			afterSensitive, err = ctyjson.Marshal(as, as.Type())
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		a, err := ctyjson.Marshal(afterUnknown, afterUnknown.Type())
+		if err != nil {
+			return nil, err
+		}
+		replacePaths, err := encodePaths(rc.RequiredReplace)
+		if err != nil {
+			return nil, err
+		}
+
+		var importing *Importing
+		if rc.Importing != nil {
+			importing = &Importing{ID: rc.Importing.ID}
+		}
+
+		r.Change = Change{
+			Actions:         actionString(rc.Action.String()),
+			Before:          json.RawMessage(before),
+			After:           json.RawMessage(after),
+			AfterUnknown:    a,
+			BeforeSensitive: json.RawMessage(beforeSensitive),
+			AfterSensitive:  json.RawMessage(afterSensitive),
+			ReplacePaths:    replacePaths,
+			Importing:       importing,
+			GeneratedConfig: rc.GeneratedConfig,
+		}
+
+		if rc.DeposedKey != states.NotDeposed {
+			r.Deposed = rc.DeposedKey.String()
+		}
+
+		key := addr.Resource.Key
+		if key != nil {
+			value := key.Value()
+			if r.Index, err = ctyjson.Marshal(value, value.Type()); err != nil {
+				return nil, err
+			}
+		}
+
+		switch addr.Resource.Resource.Mode {
+		case addrs.ManagedResourceMode:
+			r.Mode = jsonstate.ManagedResourceMode
+		case addrs.DataResourceMode:
+			r.Mode = jsonstate.DataResourceMode
+		default:
+			return nil, fmt.Errorf("resource %s has an unsupported mode %s", r.Address, addr.Resource.Resource.Mode.String())
+		}
+		r.ModuleAddress = addr.Module.String()
+		r.Name = addr.Resource.Resource.Name
+		r.Type = addr.Resource.Resource.Type
+		r.ProviderName = rc.ProviderAddr.Provider.String()
+
+		switch rc.ActionReason {
+		case plans.ResourceInstanceChangeNoReason:
+			r.ActionReason = "" // will be omitted in output
+		case plans.ResourceInstanceReplaceBecauseCannotUpdate:
+			r.ActionReason = ResourceInstanceReplaceBecauseCannotUpdate
+		case plans.ResourceInstanceReplaceBecauseTainted:
+			r.ActionReason = ResourceInstanceReplaceBecauseTainted
+		case plans.ResourceInstanceReplaceByRequest:
+			r.ActionReason = ResourceInstanceReplaceByRequest
+		case plans.ResourceInstanceReplaceByTriggers:
+			r.ActionReason = ResourceInstanceReplaceByTriggers
+		case plans.ResourceInstanceDeleteBecauseNoResourceConfig:
+			r.ActionReason = ResourceInstanceDeleteBecauseNoResourceConfig
+		case plans.ResourceInstanceDeleteBecauseWrongRepetition:
+			r.ActionReason = ResourceInstanceDeleteBecauseWrongRepetition
+		case plans.ResourceInstanceDeleteBecauseCountIndex:
+			r.ActionReason = ResourceInstanceDeleteBecauseCountIndex
+		case plans.ResourceInstanceDeleteBecauseEachKey:
+			r.ActionReason = ResourceInstanceDeleteBecauseEachKey
+		case plans.ResourceInstanceDeleteBecauseNoModule:
+			r.ActionReason = ResourceInstanceDeleteBecauseNoModule
+		case plans.ResourceInstanceDeleteBecauseNoMoveTarget:
+			r.ActionReason = ResourceInstanceDeleteBecauseNoMoveTarget
+		case plans.ResourceInstanceReadBecauseConfigUnknown:
+			r.ActionReason = ResourceInstanceReadBecauseConfigUnknown
+		case plans.ResourceInstanceReadBecauseDependencyPending:
+			r.ActionReason = ResourceInstanceReadBecauseDependencyPending
+		case plans.ResourceInstanceReadBecauseCheckNested:
+			r.ActionReason = ResourceInstanceReadBecauseCheckNested
+		default:
+			return nil, fmt.Errorf("resource %s has an unsupported action reason %s", r.Address, rc.ActionReason)
+		}
+
+		ret = append(ret, r)
+
+	}
+
+	return ret, nil
+}
+
+// MarshalOutputChanges converts the provided internal representation of
+// Changes objects into the structured JSON representation.
+//
+// This function is referenced directly from the structured renderer tests, to
+// ensure parity between the renderers. It probably shouldn't be used anywhere
+// else.
+func MarshalOutputChanges(changes *plans.Changes) (map[string]Change, error) {
+	if changes == nil {
+		// Nothing to do!
+		return nil, nil
+	}
+
+	outputChanges := make(map[string]Change, len(changes.Outputs))
+	for _, oc := range changes.Outputs {
+
+		// Skip output changes that are not from the root module.
+		// These are automatically stripped from plans that are written to disk
+		// elsewhere, we just need to duplicate the logic here in case anyone
+		// is converting this plan directly from memory.
+		if !oc.Addr.Module.IsRoot() {
+			continue
+		}
+
+		changeV, err := oc.Decode()
+		if err != nil {
+			return nil, err
+		}
+		// We drop the marks from the change, as decoding is only an
+		// intermediate step to re-encode the values as json
+		changeV.Before, _ = changeV.Before.UnmarkDeep()
+		changeV.After, _ = changeV.After.UnmarkDeep()
+
+		var before, after []byte
+		var afterUnknown cty.Value
+
+		if changeV.Before != cty.NilVal {
+			before, err = ctyjson.Marshal(changeV.Before, changeV.Before.Type())
+			if err != nil {
+				return nil, err
+			}
+		}
+		if changeV.After != cty.NilVal {
+			if changeV.After.IsWhollyKnown() {
+				after, err = ctyjson.Marshal(changeV.After, changeV.After.Type())
+				if err != nil {
+					return nil, err
+				}
+				afterUnknown = cty.False
+			} else {
+				filteredAfter := omitUnknowns(changeV.After)
+				if filteredAfter.IsNull() {
+					after = nil
+				} else {
+					after, err = ctyjson.Marshal(filteredAfter, filteredAfter.Type())
+					if err != nil {
+						return nil, err
+					}
+				}
+				afterUnknown = unknownAsBool(changeV.After)
+			}
+		}
+
+		// The only information we have in the plan about output sensitivity is
+		// a boolean which is true if the output was or is marked sensitive. As
+		// a result, BeforeSensitive and AfterSensitive will be identical, and
+		// either false or true.
+		outputSensitive := cty.False
+		if oc.Sensitive {
+			outputSensitive = cty.True
+		}
+		sensitive, err := ctyjson.Marshal(outputSensitive, outputSensitive.Type())
+		if err != nil {
+			return nil, err
+		}
+
+		a, _ := ctyjson.Marshal(afterUnknown, afterUnknown.Type())
+
+		c := Change{
+			Actions:         actionString(oc.Action.String()),
+			Before:          json.RawMessage(before),
+			After:           json.RawMessage(after),
+			AfterUnknown:    a,
+			BeforeSensitive: json.RawMessage(sensitive),
+			AfterSensitive:  json.RawMessage(sensitive),
+
+			// Just to be explicit, outputs cannot be imported so this is always
+			// nil.
+			Importing: nil,
+		}
+
+		outputChanges[oc.Addr.OutputValue.Name] = c
+	}
+
+	return outputChanges, nil
+}
+
+func (p *plan) marshalPlannedValues(changes *plans.Changes, schemas *terraform.Schemas) error {
+	// marshal the planned changes into a module
+	plan, err := marshalPlannedValues(changes, schemas)
+	if err != nil {
+		return err
+	}
+	p.PlannedValues.RootModule = plan
+
+	// marshalPlannedOutputs
+	outputs, err := marshalPlannedOutputs(changes)
+	if err != nil {
+		return err
+	}
+	p.PlannedValues.Outputs = outputs
+
+	return nil
+}
+
+func (p *plan) marshalRelevantAttrs(plan *plans.Plan) error {
+	for _, ra := range plan.RelevantAttributes {
+		addr := ra.Resource.String()
+		path, err := encodePath(ra.Attr)
+		if err != nil {
+			return err
+		}
+
+		p.RelevantAttributes = append(p.RelevantAttributes, ResourceAttr{addr, path})
+	}
+	return nil
+}
+
+// omitUnknowns recursively walks the src cty.Value and returns a new cty.Value,
+// omitting any unknowns.
+//
+// The result also normalizes some types: all sequence types are turned into
+// tuple types and all mapping types are converted to object types, since we
+// assume the result of this is just going to be serialized as JSON (and thus
+// lose those distinctions) anyway.
+func omitUnknowns(val cty.Value) cty.Value {
+	ty := val.Type()
+	switch {
+	case val.IsNull():
+		return val
+	case !val.IsKnown():
+		return cty.NilVal
+	case ty.IsPrimitiveType():
+		return val
+	case ty.IsListType() || ty.IsTupleType() || ty.IsSetType():
+		var vals []cty.Value
+		it := val.ElementIterator()
+		for it.Next() {
+			_, v := it.Element()
+			newVal := omitUnknowns(v)
+			if newVal != cty.NilVal {
+				vals = append(vals, newVal)
+			} else if newVal == cty.NilVal {
+				// element order is how we correlate unknownness, so we must
+				// replace unknowns with nulls
+				vals = append(vals, cty.NullVal(v.Type()))
+			}
+		}
+		// We use tuple types always here, because the work we did above
+		// may have caused the individual elements to have different types,
+		// and we're doing this work to produce JSON anyway and JSON marshalling
+		// represents all of these sequence types as an array.
+		return cty.TupleVal(vals)
+	case ty.IsMapType() || ty.IsObjectType():
+		vals := make(map[string]cty.Value)
+		it := val.ElementIterator()
+		for it.Next() {
+			k, v := it.Element()
+			newVal := omitUnknowns(v)
+			if newVal != cty.NilVal {
+				vals[k.AsString()] = newVal
+			}
+		}
+		// We use object types always here, because the work we did above
+		// may have caused the individual elements to have different types,
+		// and we're doing this work to produce JSON anyway and JSON marshalling
+		// represents both of these mapping types as an object.
+		return cty.ObjectVal(vals)
+	default:
+		// Should never happen, since the above should cover all types
+		panic(fmt.Sprintf("omitUnknowns cannot handle %#v", val))
+	}
+}
+
+// recursively iterate through a cty.Value, replacing unknown values (including
+// null) with cty.True and known values with cty.False.
+//
+// The result also normalizes some types: all sequence types are turned into
+// tuple types and all mapping types are converted to object types, since we
+// assume the result of this is just going to be serialized as JSON (and thus
+// lose those distinctions) anyway.
+//
+// For map/object values, all known attribute values will be omitted instead of
+// returning false, as this results in a more compact serialization.
+func unknownAsBool(val cty.Value) cty.Value {
+	ty := val.Type()
+	switch {
+	case val.IsNull():
+		return cty.False
+	case !val.IsKnown():
+		if ty.IsPrimitiveType() || ty.Equals(cty.DynamicPseudoType) {
+			return cty.True
+		}
+		fallthrough
+	case ty.IsPrimitiveType():
+		return cty.BoolVal(!val.IsKnown())
+	case ty.IsListType() || ty.IsTupleType() || ty.IsSetType():
+		length := val.LengthInt()
+		if length == 0 {
+			// If there are no elements then we can't have unknowns
+			return cty.EmptyTupleVal
+		}
+		vals := make([]cty.Value, 0, length)
+		it := val.ElementIterator()
+		for it.Next() {
+			_, v := it.Element()
+			vals = append(vals, unknownAsBool(v))
+		}
+		// The above transform may have changed the types of some of the
+		// elements, so we'll always use a tuple here in case we've now made
+		// different elements have different types. Our ultimate goal is to
+		// marshal to JSON anyway, and all of these sequence types are
+		// indistinguishable in JSON.
+		return cty.TupleVal(vals)
+	case ty.IsMapType() || ty.IsObjectType():
+		var length int
+		switch {
+		case ty.IsMapType():
+			length = val.LengthInt()
+		default:
+			length = len(val.Type().AttributeTypes())
+		}
+		if length == 0 {
+			// If there are no elements then we can't have unknowns
+			return cty.EmptyObjectVal
+		}
+		vals := make(map[string]cty.Value)
+		it := val.ElementIterator()
+		for it.Next() {
+			k, v := it.Element()
+			vAsBool := unknownAsBool(v)
+			// Omit all of the "false"s for known values for more compact
+			// serialization
+			if !vAsBool.RawEquals(cty.False) {
+				vals[k.AsString()] = vAsBool
+			}
+		}
+		// The above transform may have changed the types of some of the
+		// elements, so we'll always use an object here in case we've now made
+		// different elements have different types. Our ultimate goal is to
+		// marshal to JSON anyway, and all of these mapping types are
+		// indistinguishable in JSON.
+		return cty.ObjectVal(vals)
+	default:
+		// Should never happen, since the above should cover all types
+		panic(fmt.Sprintf("unknownAsBool cannot handle %#v", val))
+	}
+}
+
+func actionString(action string) []string {
+	switch {
+	case action == "NoOp":
+		return []string{"no-op"}
+	case action == "Create":
+		return []string{"create"}
+	case action == "Delete":
+		return []string{"delete"}
+	case action == "Update":
+		return []string{"update"}
+	case action == "CreateThenDelete":
+		return []string{"create", "delete"}
+	case action == "Read":
+		return []string{"read"}
+	case action == "DeleteThenCreate":
+		return []string{"delete", "create"}
+	default:
+		return []string{action}
+	}
+}
+
+// UnmarshalActions reverses the actionString function.
+func UnmarshalActions(actions []string) plans.Action {
+	if len(actions) == 2 {
+		if actions[0] == "create" && actions[1] == "delete" {
+			return plans.CreateThenDelete
+		}
+
+		if actions[0] == "delete" && actions[1] == "create" {
+			return plans.DeleteThenCreate
+		}
+	}
+
+	if len(actions) == 1 {
+		switch actions[0] {
+		case "create":
+			return plans.Create
+		case "delete":
+			return plans.Delete
+		case "update":
+			return plans.Update
+		case "read":
+			return plans.Read
+		case "no-op":
+			return plans.NoOp
+		}
+	}
+
+	panic("unrecognized action slice: " + strings.Join(actions, ", "))
+}
+
+// encodePaths lossily encodes a cty.PathSet into an array of arrays of step
+// values, such as:
+//
+//	[["length"],["triggers",0,"value"]]
+//
+// The lossiness is that we cannot distinguish between an IndexStep with string
+// key and a GetAttr step. This is fine with JSON output, because JSON's type
+// system means that those two steps are equivalent anyway: both are object
+// indexes.
+//
+// JavaScript (or similar dynamic language) consumers of these values can
+// iterate over the the steps starting from the root object to reach the
+// value that each path is describing.
+func encodePaths(pathSet cty.PathSet) (json.RawMessage, error) {
+	if pathSet.Empty() {
+		return nil, nil
+	}
+
+	pathList := pathSet.List()
+	jsonPaths := make([]json.RawMessage, 0, len(pathList))
+
+	for _, path := range pathList {
+		jsonPath, err := encodePath(path)
+		if err != nil {
+			return nil, err
+		}
+		jsonPaths = append(jsonPaths, jsonPath)
+	}
+
+	return json.Marshal(jsonPaths)
+}
+
+func encodePath(path cty.Path) (json.RawMessage, error) {
+	steps := make([]json.RawMessage, 0, len(path))
+	for _, step := range path {
+		switch s := step.(type) {
+		case cty.IndexStep:
+			key, err := ctyjson.Marshal(s.Key, s.Key.Type())
+			if err != nil {
+				return nil, fmt.Errorf("Failed to marshal index step key %#v: %s", s.Key, err)
+			}
+			steps = append(steps, key)
+		case cty.GetAttrStep:
+			name, err := json.Marshal(s.Name)
+			if err != nil {
+				return nil, fmt.Errorf("Failed to marshal get attr step name %#v: %s", s.Name, err)
+			}
+			steps = append(steps, name)
+		default:
+			return nil, fmt.Errorf("Unsupported path step %#v (%t)", step, step)
+		}
+	}
+	return json.Marshal(steps)
+}
diff --git a/v1.5.7/internal/command/jsonplan/plan_test.go b/v1.5.7/internal/command/jsonplan/plan_test.go
new file mode 100644
index 0000000..bc83bda
--- /dev/null
+++ b/v1.5.7/internal/command/jsonplan/plan_test.go
@@ -0,0 +1,472 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonplan
+
+import (
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+func TestOmitUnknowns(t *testing.T) {
+	tests := []struct {
+		Input cty.Value
+		Want  cty.Value
+	}{
+		{
+			cty.StringVal("hello"),
+			cty.StringVal("hello"),
+		},
+		{
+			cty.NullVal(cty.String),
+			cty.NullVal(cty.String),
+		},
+		{
+			cty.UnknownVal(cty.String),
+			cty.NilVal,
+		},
+		{
+			cty.ListValEmpty(cty.String),
+			cty.EmptyTupleVal,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
+			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
+		},
+		{
+			cty.ListVal([]cty.Value{cty.NullVal(cty.String)}),
+			cty.TupleVal([]cty.Value{cty.NullVal(cty.String)}),
+		},
+		{
+			cty.ListVal([]cty.Value{cty.UnknownVal(cty.String)}),
+			cty.TupleVal([]cty.Value{cty.NullVal(cty.String)}),
+		},
+		{
+			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
+			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
+		},
+		//
+		{
+			cty.ListVal([]cty.Value{
+				cty.StringVal("hello"),
+				cty.UnknownVal(cty.String)}),
+			cty.TupleVal([]cty.Value{
+				cty.StringVal("hello"),
+				cty.NullVal(cty.String),
+			}),
+		},
+		{
+			cty.MapVal(map[string]cty.Value{
+				"hello": cty.True,
+				"world": cty.UnknownVal(cty.Bool),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"hello": cty.True,
+			}),
+		},
+		{
+			cty.TupleVal([]cty.Value{
+				cty.StringVal("alpha"),
+				cty.UnknownVal(cty.String),
+				cty.StringVal("charlie"),
+			}),
+			cty.TupleVal([]cty.Value{
+				cty.StringVal("alpha"),
+				cty.NullVal(cty.String),
+				cty.StringVal("charlie"),
+			}),
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.StringVal("dev"),
+				cty.StringVal("foo"),
+				cty.StringVal("stg"),
+				cty.UnknownVal(cty.String),
+			}),
+			cty.TupleVal([]cty.Value{
+				cty.StringVal("dev"),
+				cty.StringVal("foo"),
+				cty.StringVal("stg"),
+				cty.NullVal(cty.String),
+			}),
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.UnknownVal(cty.String),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.StringVal("known"),
+				}),
+			}),
+			cty.TupleVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.StringVal("known"),
+				}),
+				cty.EmptyObjectVal,
+			}),
+		},
+	}
+
+	for _, test := range tests {
+		got := omitUnknowns(test.Input)
+		if !reflect.DeepEqual(got, test.Want) {
+			t.Errorf(
+				"wrong result\ninput: %#v\ngot:   %#v\nwant:  %#v",
+				test.Input, got, test.Want,
+			)
+		}
+	}
+}
+
+func TestUnknownAsBool(t *testing.T) {
+	tests := []struct {
+		Input cty.Value
+		Want  cty.Value
+	}{
+		{
+			cty.StringVal("hello"),
+			cty.False,
+		},
+		{
+			cty.NullVal(cty.String),
+			cty.False,
+		},
+		{
+			cty.UnknownVal(cty.String),
+			cty.True,
+		},
+
+		{
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.False,
+		},
+		{
+			cty.NullVal(cty.Object(map[string]cty.Type{"test": cty.String})),
+			cty.False,
+		},
+		{
+			cty.DynamicVal,
+			cty.True,
+		},
+
+		{
+			cty.ListValEmpty(cty.String),
+			cty.EmptyTupleVal,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
+			cty.TupleVal([]cty.Value{cty.False}),
+		},
+		{
+			cty.ListVal([]cty.Value{cty.NullVal(cty.String)}),
+			cty.TupleVal([]cty.Value{cty.False}),
+		},
+		{
+			cty.ListVal([]cty.Value{cty.UnknownVal(cty.String)}),
+			cty.TupleVal([]cty.Value{cty.True}),
+		},
+		{
+			cty.SetValEmpty(cty.String),
+			cty.EmptyTupleVal,
+		},
+		{
+			cty.SetVal([]cty.Value{cty.StringVal("hello")}),
+			cty.TupleVal([]cty.Value{cty.False}),
+		},
+		{
+			cty.SetVal([]cty.Value{cty.NullVal(cty.String)}),
+			cty.TupleVal([]cty.Value{cty.False}),
+		},
+		{
+			cty.SetVal([]cty.Value{cty.UnknownVal(cty.String)}),
+			cty.TupleVal([]cty.Value{cty.True}),
+		},
+		{
+			cty.EmptyTupleVal,
+			cty.EmptyTupleVal,
+		},
+		{
+			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
+			cty.TupleVal([]cty.Value{cty.False}),
+		},
+		{
+			cty.TupleVal([]cty.Value{cty.NullVal(cty.String)}),
+			cty.TupleVal([]cty.Value{cty.False}),
+		},
+		{
+			cty.TupleVal([]cty.Value{cty.UnknownVal(cty.String)}),
+			cty.TupleVal([]cty.Value{cty.True}),
+		},
+		{
+			cty.MapValEmpty(cty.String),
+			cty.EmptyObjectVal,
+		},
+		{
+			cty.MapVal(map[string]cty.Value{"greeting": cty.StringVal("hello")}),
+			cty.EmptyObjectVal,
+		},
+		{
+			cty.MapVal(map[string]cty.Value{"greeting": cty.NullVal(cty.String)}),
+			cty.EmptyObjectVal,
+		},
+		{
+			cty.MapVal(map[string]cty.Value{"greeting": cty.UnknownVal(cty.String)}),
+			cty.ObjectVal(map[string]cty.Value{"greeting": cty.True}),
+		},
+		{
+			cty.EmptyObjectVal,
+			cty.EmptyObjectVal,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{"greeting": cty.StringVal("hello")}),
+			cty.EmptyObjectVal,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{"greeting": cty.NullVal(cty.String)}),
+			cty.EmptyObjectVal,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{"greeting": cty.UnknownVal(cty.String)}),
+			cty.ObjectVal(map[string]cty.Value{"greeting": cty.True}),
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.UnknownVal(cty.String),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.StringVal("known"),
+				}),
+			}),
+			cty.TupleVal([]cty.Value{
+				cty.EmptyObjectVal,
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.True,
+				}),
+			}),
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.MapValEmpty(cty.String),
+				cty.MapVal(map[string]cty.Value{
+					"a": cty.StringVal("known"),
+				}),
+				cty.MapVal(map[string]cty.Value{
+					"a": cty.UnknownVal(cty.String),
+				}),
+			}),
+			cty.TupleVal([]cty.Value{
+				cty.EmptyObjectVal,
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.True,
+				}),
+				cty.EmptyObjectVal,
+			}),
+		},
+	}
+
+	for _, test := range tests {
+		got := unknownAsBool(test.Input)
+		if !reflect.DeepEqual(got, test.Want) {
+			t.Errorf(
+				"wrong result\ninput: %#v\ngot:   %#v\nwant:  %#v",
+				test.Input, got, test.Want,
+			)
+		}
+	}
+}
+
+func TestEncodePaths(t *testing.T) {
+	tests := map[string]struct {
+		Input cty.PathSet
+		Want  json.RawMessage
+	}{
+		"empty set": {
+			cty.NewPathSet(),
+			json.RawMessage(nil),
+		},
+		"index path with string and int steps": {
+			cty.NewPathSet(cty.IndexStringPath("boop").IndexInt(0)),
+			json.RawMessage(`[["boop",0]]`),
+		},
+		"get attr path with one step": {
+			cty.NewPathSet(cty.GetAttrPath("triggers")),
+			json.RawMessage(`[["triggers"]]`),
+		},
+		"multiple paths of different types": {
+			cty.NewPathSet(
+				cty.GetAttrPath("alpha").GetAttr("beta").GetAttr("gamma"),
+				cty.GetAttrPath("triggers").IndexString("name"),
+				cty.IndexIntPath(0).IndexInt(1).IndexInt(2).IndexInt(3),
+			),
+			json.RawMessage(`[["alpha","beta","gamma"],["triggers","name"],[0,1,2,3]]`),
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got, err := encodePaths(test.Input)
+			if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+			if !cmp.Equal(got, test.Want) {
+				t.Errorf("wrong result:\n %v\n", cmp.Diff(got, test.Want))
+			}
+		})
+	}
+}
+
+func TestOutputs(t *testing.T) {
+	root := addrs.RootModuleInstance
+
+	child, diags := addrs.ParseModuleInstanceStr("module.child")
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	tests := map[string]struct {
+		changes  *plans.Changes
+		expected map[string]Change
+	}{
+		"copies all outputs": {
+			changes: &plans.Changes{
+				Outputs: []*plans.OutputChangeSrc{
+					{
+						Addr: root.OutputValue("first"),
+						ChangeSrc: plans.ChangeSrc{
+							Action: plans.Create,
+						},
+					},
+					{
+						Addr: root.OutputValue("second"),
+						ChangeSrc: plans.ChangeSrc{
+							Action: plans.Create,
+						},
+					},
+				},
+			},
+			expected: map[string]Change{
+				"first": {
+					Actions:         []string{"create"},
+					Before:          json.RawMessage("null"),
+					After:           json.RawMessage("null"),
+					AfterUnknown:    json.RawMessage("false"),
+					BeforeSensitive: json.RawMessage("false"),
+					AfterSensitive:  json.RawMessage("false"),
+				},
+				"second": {
+					Actions:         []string{"create"},
+					Before:          json.RawMessage("null"),
+					After:           json.RawMessage("null"),
+					AfterUnknown:    json.RawMessage("false"),
+					BeforeSensitive: json.RawMessage("false"),
+					AfterSensitive:  json.RawMessage("false"),
+				},
+			},
+		},
+		"skips non root modules": {
+			changes: &plans.Changes{
+				Outputs: []*plans.OutputChangeSrc{
+					{
+						Addr: root.OutputValue("first"),
+						ChangeSrc: plans.ChangeSrc{
+							Action: plans.Create,
+						},
+					},
+					{
+						Addr: child.OutputValue("second"),
+						ChangeSrc: plans.ChangeSrc{
+							Action: plans.Create,
+						},
+					},
+				},
+			},
+			expected: map[string]Change{
+				"first": {
+					Actions:         []string{"create"},
+					Before:          json.RawMessage("null"),
+					After:           json.RawMessage("null"),
+					AfterUnknown:    json.RawMessage("false"),
+					BeforeSensitive: json.RawMessage("false"),
+					AfterSensitive:  json.RawMessage("false"),
+				},
+			},
+		},
+	}
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			changes, err := MarshalOutputChanges(test.changes)
+			if err != nil {
+				t.Fatalf("unexpected err: %s", err)
+			}
+
+			if !cmp.Equal(changes, test.expected) {
+				t.Errorf("wrong result:\n %v\n", cmp.Diff(changes, test.expected))
+			}
+		})
+	}
+}
+
+func deepObjectValue(depth int) cty.Value {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"a": cty.StringVal("a"),
+		"b": cty.NumberIntVal(2),
+		"c": cty.True,
+		"d": cty.UnknownVal(cty.String),
+	})
+
+	result := v
+
+	for i := 0; i < depth; i++ {
+		result = cty.ObjectVal(map[string]cty.Value{
+			"a": result,
+			"b": result,
+			"c": result,
+		})
+	}
+
+	return result
+}
+
+func BenchmarkUnknownAsBool_2(b *testing.B) {
+	value := deepObjectValue(2)
+	for n := 0; n < b.N; n++ {
+		unknownAsBool(value)
+	}
+}
+
+func BenchmarkUnknownAsBool_3(b *testing.B) {
+	value := deepObjectValue(3)
+	for n := 0; n < b.N; n++ {
+		unknownAsBool(value)
+	}
+}
+
+func BenchmarkUnknownAsBool_5(b *testing.B) {
+	value := deepObjectValue(5)
+	for n := 0; n < b.N; n++ {
+		unknownAsBool(value)
+	}
+}
+
+func BenchmarkUnknownAsBool_7(b *testing.B) {
+	value := deepObjectValue(7)
+	for n := 0; n < b.N; n++ {
+		unknownAsBool(value)
+	}
+}
+
+func BenchmarkUnknownAsBool_9(b *testing.B) {
+	value := deepObjectValue(9)
+	for n := 0; n < b.N; n++ {
+		unknownAsBool(value)
+	}
+}
diff --git a/v1.5.7/internal/command/jsonplan/resource.go b/v1.5.7/internal/command/jsonplan/resource.go
new file mode 100644
index 0000000..f237b9b
--- /dev/null
+++ b/v1.5.7/internal/command/jsonplan/resource.go
@@ -0,0 +1,95 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonplan
+
+import (
+	"encoding/json"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// Resource is the representation of a resource in the json plan
+type resource struct {
+	// Address is the absolute resource address
+	Address string `json:"address,omitempty"`
+
+	// Mode can be "managed" or "data"
+	Mode string `json:"mode,omitempty"`
+
+	Type string `json:"type,omitempty"`
+	Name string `json:"name,omitempty"`
+
+	// Index is omitted for a resource not using `count` or `for_each`
+	Index addrs.InstanceKey `json:"index,omitempty"`
+
+	// ProviderName allows the property "type" to be interpreted unambiguously
+	// in the unusual situation where a provider offers a resource type whose
+	// name does not start with its own name, such as the "googlebeta" provider
+	// offering "google_compute_instance".
+	ProviderName string `json:"provider_name,omitempty"`
+
+	// SchemaVersion indicates which version of the resource type schema the
+	// "values" property conforms to.
+	SchemaVersion uint64 `json:"schema_version"`
+
+	// AttributeValues is the JSON representation of the attribute values of the
+	// resource, whose structure depends on the resource type schema. Any
+	// unknown values are omitted or set to null, making them indistinguishable
+	// from absent values.
+	AttributeValues attributeValues `json:"values,omitempty"`
+
+	// SensitiveValues is similar to AttributeValues, but with all sensitive
+	// values replaced with true, and all non-sensitive leaf values omitted.
+	SensitiveValues json.RawMessage `json:"sensitive_values,omitempty"`
+}
+
+// ResourceChange is a description of an individual change action that Terraform
+// plans to use to move from the prior state to a new state matching the
+// configuration.
+type ResourceChange struct {
+	// Address is the absolute resource address
+	Address string `json:"address,omitempty"`
+
+	// PreviousAddress is the absolute address that this resource instance had
+	// at the conclusion of a previous run.
+	//
+	// This will typically be omitted, but will be present if the previous
+	// resource instance was subject to a "moved" block that we handled in the
+	// process of creating this plan.
+	//
+	// Note that this behavior diverges from the internal plan data structure,
+	// where the previous address is set equal to the current address in the
+	// common case, rather than being omitted.
+	PreviousAddress string `json:"previous_address,omitempty"`
+
+	// ModuleAddress is the module portion of the above address. Omitted if the
+	// instance is in the root module.
+	ModuleAddress string `json:"module_address,omitempty"`
+
+	// "managed" or "data"
+	Mode string `json:"mode,omitempty"`
+
+	Type         string          `json:"type,omitempty"`
+	Name         string          `json:"name,omitempty"`
+	Index        json.RawMessage `json:"index,omitempty"`
+	ProviderName string          `json:"provider_name,omitempty"`
+
+	// "deposed", if set, indicates that this action applies to a "deposed"
+	// object of the given instance rather than to its "current" object. Omitted
+	// for changes to the current object.
+	Deposed string `json:"deposed,omitempty"`
+
+	// Change describes the change that will be made to this object
+	Change Change `json:"change,omitempty"`
+
+	// ActionReason is a keyword representing some optional extra context
+	// for why the actions in Change.Actions were chosen.
+	//
+	// This extra detail is only for display purposes, to help a UI layer
+	// present some additional explanation to a human user. The possible
+	// values here might grow and change over time, so any consumer of this
+	// information should be resilient to encountering unrecognized values
+	// and treat them as an unspecified reason.
+	ActionReason string `json:"action_reason,omitempty"`
+}
diff --git a/v1.5.7/internal/command/jsonplan/values.go b/v1.5.7/internal/command/jsonplan/values.go
new file mode 100644
index 0000000..d186091
--- /dev/null
+++ b/v1.5.7/internal/command/jsonplan/values.go
@@ -0,0 +1,285 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonplan
+
+import (
+	"encoding/json"
+	"fmt"
+	"sort"
+
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/jsonstate"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// stateValues is the common representation of resolved values for both the
+// prior state (which is always complete) and the planned new state.
+type stateValues struct {
+	Outputs    map[string]output `json:"outputs,omitempty"`
+	RootModule module            `json:"root_module,omitempty"`
+}
+
+// attributeValues is the JSON representation of the attribute values of the
+// resource, whose structure depends on the resource type schema.
+type attributeValues map[string]interface{}
+
+func marshalAttributeValues(value cty.Value, schema *configschema.Block) attributeValues {
+	if value == cty.NilVal || value.IsNull() {
+		return nil
+	}
+	ret := make(attributeValues)
+
+	it := value.ElementIterator()
+	for it.Next() {
+		k, v := it.Element()
+		vJSON, _ := ctyjson.Marshal(v, v.Type())
+		ret[k.AsString()] = json.RawMessage(vJSON)
+	}
+	return ret
+}
+
+// marshalPlannedOutputs takes a list of changes and returns a map of output
+// values
+func marshalPlannedOutputs(changes *plans.Changes) (map[string]output, error) {
+	if changes.Outputs == nil {
+		// No changes - we're done here!
+		return nil, nil
+	}
+
+	ret := make(map[string]output)
+
+	for _, oc := range changes.Outputs {
+		if oc.ChangeSrc.Action == plans.Delete {
+			continue
+		}
+
+		var after, afterType []byte
+		changeV, err := oc.Decode()
+		if err != nil {
+			return ret, err
+		}
+		// The values may be marked, but we must rely on the Sensitive flag
+		// as the decoded value is only an intermediate step in transcoding
+		// this to a json format.
+		changeV.After, _ = changeV.After.UnmarkDeep()
+
+		if changeV.After != cty.NilVal && changeV.After.IsWhollyKnown() {
+			ty := changeV.After.Type()
+			after, err = ctyjson.Marshal(changeV.After, ty)
+			if err != nil {
+				return ret, err
+			}
+			afterType, err = ctyjson.MarshalType(ty)
+			if err != nil {
+				return ret, err
+			}
+		}
+
+		ret[oc.Addr.OutputValue.Name] = output{
+			Value:     json.RawMessage(after),
+			Type:      json.RawMessage(afterType),
+			Sensitive: oc.Sensitive,
+		}
+	}
+
+	return ret, nil
+
+}
+
+func marshalPlannedValues(changes *plans.Changes, schemas *terraform.Schemas) (module, error) {
+	var ret module
+
+	// build two maps:
+	// 		module name -> [resource addresses]
+	// 		module -> [children modules]
+	moduleResourceMap := make(map[string][]addrs.AbsResourceInstance)
+	moduleMap := make(map[string][]addrs.ModuleInstance)
+	seenModules := make(map[string]bool)
+
+	for _, resource := range changes.Resources {
+		// If the resource is being deleted, skip over it.
+		// Deposed instances are always conceptually a destroy, but if they
+		// were gone during refresh then the change becomes a noop.
+		if resource.Action != plans.Delete && resource.DeposedKey == states.NotDeposed {
+			containingModule := resource.Addr.Module.String()
+			moduleResourceMap[containingModule] = append(moduleResourceMap[containingModule], resource.Addr)
+
+			// the root module has no parents
+			if !resource.Addr.Module.IsRoot() {
+				parent := resource.Addr.Module.Parent().String()
+				// we expect to see multiple resources in one module, so we
+				// only need to report the "parent" module for each child module
+				// once.
+				if !seenModules[containingModule] {
+					moduleMap[parent] = append(moduleMap[parent], resource.Addr.Module)
+					seenModules[containingModule] = true
+				}
+
+				// If any given parent module has no resources, it needs to be
+				// added to the moduleMap. This walks through the current
+				// resources' modules' ancestors, taking advantage of the fact
+				// that Ancestors() returns an ordered slice, and verifies that
+				// each one is in the map.
+				ancestors := resource.Addr.Module.Ancestors()
+				for i, ancestor := range ancestors[:len(ancestors)-1] {
+					aStr := ancestor.String()
+
+					// childStr here is the immediate child of the current step
+					childStr := ancestors[i+1].String()
+					// we likely will see multiple resources in one module, so we
+					// only need to report the "parent" module for each child module
+					// once.
+					if !seenModules[childStr] {
+						moduleMap[aStr] = append(moduleMap[aStr], ancestors[i+1])
+						seenModules[childStr] = true
+					}
+				}
+			}
+		}
+	}
+
+	// start with the root module
+	resources, err := marshalPlanResources(changes, moduleResourceMap[""], schemas)
+	if err != nil {
+		return ret, err
+	}
+	ret.Resources = resources
+
+	childModules, err := marshalPlanModules(changes, schemas, moduleMap[""], moduleMap, moduleResourceMap)
+	if err != nil {
+		return ret, err
+	}
+	sort.Slice(childModules, func(i, j int) bool {
+		return childModules[i].Address < childModules[j].Address
+	})
+
+	ret.ChildModules = childModules
+
+	return ret, nil
+}
+
+// marshalPlanResources
+func marshalPlanResources(changes *plans.Changes, ris []addrs.AbsResourceInstance, schemas *terraform.Schemas) ([]resource, error) {
+	var ret []resource
+
+	for _, ri := range ris {
+		r := changes.ResourceInstance(ri)
+		if r.Action == plans.Delete {
+			continue
+		}
+
+		resource := resource{
+			Address:      r.Addr.String(),
+			Type:         r.Addr.Resource.Resource.Type,
+			Name:         r.Addr.Resource.Resource.Name,
+			ProviderName: r.ProviderAddr.Provider.String(),
+			Index:        r.Addr.Resource.Key,
+		}
+
+		switch r.Addr.Resource.Resource.Mode {
+		case addrs.ManagedResourceMode:
+			resource.Mode = "managed"
+		case addrs.DataResourceMode:
+			resource.Mode = "data"
+		default:
+			return nil, fmt.Errorf("resource %s has an unsupported mode %s",
+				r.Addr.String(),
+				r.Addr.Resource.Resource.Mode.String(),
+			)
+		}
+
+		schema, schemaVer := schemas.ResourceTypeConfig(
+			r.ProviderAddr.Provider,
+			r.Addr.Resource.Resource.Mode,
+			resource.Type,
+		)
+		if schema == nil {
+			return nil, fmt.Errorf("no schema found for %s", r.Addr.String())
+		}
+		resource.SchemaVersion = schemaVer
+		changeV, err := r.Decode(schema.ImpliedType())
+		if err != nil {
+			return nil, err
+		}
+
+		// copy the marked After values so we can use these in marshalSensitiveValues
+		markedAfter := changeV.After
+
+		// The values may be marked, but we must rely on the Sensitive flag
+		// as the decoded value is only an intermediate step in transcoding
+		// this to a json format.
+		changeV.Before, _ = changeV.Before.UnmarkDeep()
+		changeV.After, _ = changeV.After.UnmarkDeep()
+
+		if changeV.After != cty.NilVal {
+			if changeV.After.IsWhollyKnown() {
+				resource.AttributeValues = marshalAttributeValues(changeV.After, schema)
+			} else {
+				knowns := omitUnknowns(changeV.After)
+				resource.AttributeValues = marshalAttributeValues(knowns, schema)
+			}
+		}
+
+		s := jsonstate.SensitiveAsBool(markedAfter)
+		v, err := ctyjson.Marshal(s, s.Type())
+		if err != nil {
+			return nil, err
+		}
+		resource.SensitiveValues = v
+
+		ret = append(ret, resource)
+	}
+
+	sort.Slice(ret, func(i, j int) bool {
+		return ret[i].Address < ret[j].Address
+	})
+
+	return ret, nil
+}
+
+// marshalPlanModules iterates over a list of modules to recursively describe
+// the full module tree.
+func marshalPlanModules(
+	changes *plans.Changes,
+	schemas *terraform.Schemas,
+	childModules []addrs.ModuleInstance,
+	moduleMap map[string][]addrs.ModuleInstance,
+	moduleResourceMap map[string][]addrs.AbsResourceInstance,
+) ([]module, error) {
+
+	var ret []module
+
+	for _, child := range childModules {
+		moduleResources := moduleResourceMap[child.String()]
+		// cm for child module, naming things is hard.
+		var cm module
+		// don't populate the address for the root module
+		if child.String() != "" {
+			cm.Address = child.String()
+		}
+		rs, err := marshalPlanResources(changes, moduleResources, schemas)
+		if err != nil {
+			return nil, err
+		}
+		cm.Resources = rs
+
+		if len(moduleMap[child.String()]) > 0 {
+			moreChildModules, err := marshalPlanModules(changes, schemas, moduleMap[child.String()], moduleMap, moduleResourceMap)
+			if err != nil {
+				return nil, err
+			}
+			cm.ChildModules = moreChildModules
+		}
+
+		ret = append(ret, cm)
+	}
+
+	return ret, nil
+}
diff --git a/v1.5.7/internal/command/jsonplan/values_test.go b/v1.5.7/internal/command/jsonplan/values_test.go
new file mode 100644
index 0000000..2ac7ec5
--- /dev/null
+++ b/v1.5.7/internal/command/jsonplan/values_test.go
@@ -0,0 +1,377 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonplan
+
+import (
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestMarshalAttributeValues(t *testing.T) {
+	tests := []struct {
+		Attr   cty.Value
+		Schema *configschema.Block
+		Want   attributeValues
+	}{
+		{
+			cty.NilVal,
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			nil,
+		},
+		{
+			cty.NullVal(cty.String),
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			nil,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+			}),
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			attributeValues{"foo": json.RawMessage(`"bar"`)},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(cty.String),
+			}),
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			attributeValues{"foo": json.RawMessage(`null`)},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"bar": cty.MapVal(map[string]cty.Value{
+					"hello": cty.StringVal("world"),
+				}),
+				"baz": cty.ListVal([]cty.Value{
+					cty.StringVal("goodnight"),
+					cty.StringVal("moon"),
+				}),
+			}),
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"bar": {
+						Type:     cty.Map(cty.String),
+						Required: true,
+					},
+					"baz": {
+						Type:     cty.List(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			attributeValues{
+				"bar": json.RawMessage(`{"hello":"world"}`),
+				"baz": json.RawMessage(`["goodnight","moon"]`),
+			},
+		},
+	}
+
+	for _, test := range tests {
+		got := marshalAttributeValues(test.Attr, test.Schema)
+		eq := reflect.DeepEqual(got, test.Want)
+		if !eq {
+			t.Fatalf("wrong result:\nGot: %#v\nWant: %#v\n", got, test.Want)
+		}
+	}
+}
+
+func TestMarshalPlannedOutputs(t *testing.T) {
+	after, _ := plans.NewDynamicValue(cty.StringVal("after"), cty.DynamicPseudoType)
+
+	tests := []struct {
+		Changes *plans.Changes
+		Want    map[string]output
+		Err     bool
+	}{
+		{
+			&plans.Changes{},
+			nil,
+			false,
+		},
+		{
+			&plans.Changes{
+				Outputs: []*plans.OutputChangeSrc{
+					{
+						Addr: addrs.OutputValue{Name: "bar"}.Absolute(addrs.RootModuleInstance),
+						ChangeSrc: plans.ChangeSrc{
+							Action: plans.Create,
+							After:  after,
+						},
+						Sensitive: false,
+					},
+				},
+			},
+			map[string]output{
+				"bar": {
+					Sensitive: false,
+					Type:      json.RawMessage(`"string"`),
+					Value:     json.RawMessage(`"after"`),
+				},
+			},
+			false,
+		},
+		{ // Delete action
+			&plans.Changes{
+				Outputs: []*plans.OutputChangeSrc{
+					{
+						Addr: addrs.OutputValue{Name: "bar"}.Absolute(addrs.RootModuleInstance),
+						ChangeSrc: plans.ChangeSrc{
+							Action: plans.Delete,
+						},
+						Sensitive: false,
+					},
+				},
+			},
+			map[string]output{},
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		got, err := marshalPlannedOutputs(test.Changes)
+		if test.Err {
+			if err == nil {
+				t.Fatal("succeeded; want error")
+			}
+			return
+		} else if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+
+		eq := reflect.DeepEqual(got, test.Want)
+		if !eq {
+			t.Fatalf("wrong result:\nGot: %#v\nWant: %#v\n", got, test.Want)
+		}
+	}
+}
+
+func TestMarshalPlanResources(t *testing.T) {
+	tests := map[string]struct {
+		Action plans.Action
+		Before cty.Value
+		After  cty.Value
+		Want   []resource
+		Err    bool
+	}{
+		"create with unknowns": {
+			Action: plans.Create,
+			Before: cty.NullVal(cty.EmptyObject),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"woozles": cty.UnknownVal(cty.String),
+				"foozles": cty.UnknownVal(cty.String),
+			}),
+			Want: []resource{{
+				Address:         "test_thing.example",
+				Mode:            "managed",
+				Type:            "test_thing",
+				Name:            "example",
+				Index:           addrs.InstanceKey(nil),
+				ProviderName:    "registry.terraform.io/hashicorp/test",
+				SchemaVersion:   1,
+				AttributeValues: attributeValues{},
+				SensitiveValues: json.RawMessage("{}"),
+			}},
+			Err: false,
+		},
+		"delete with null and nil": {
+			Action: plans.Delete,
+			Before: cty.NullVal(cty.EmptyObject),
+			After:  cty.NilVal,
+			Want:   nil,
+			Err:    false,
+		},
+		"delete": {
+			Action: plans.Delete,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"woozles": cty.StringVal("foo"),
+				"foozles": cty.StringVal("bar"),
+			}),
+			After: cty.NullVal(cty.Object(map[string]cty.Type{
+				"woozles": cty.String,
+				"foozles": cty.String,
+			})),
+			Want: nil,
+			Err:  false,
+		},
+		"update without unknowns": {
+			Action: plans.Update,
+			Before: cty.ObjectVal(map[string]cty.Value{
+				"woozles": cty.StringVal("foo"),
+				"foozles": cty.StringVal("bar"),
+			}),
+			After: cty.ObjectVal(map[string]cty.Value{
+				"woozles": cty.StringVal("baz"),
+				"foozles": cty.StringVal("bat"),
+			}),
+			Want: []resource{{
+				Address:       "test_thing.example",
+				Mode:          "managed",
+				Type:          "test_thing",
+				Name:          "example",
+				Index:         addrs.InstanceKey(nil),
+				ProviderName:  "registry.terraform.io/hashicorp/test",
+				SchemaVersion: 1,
+				AttributeValues: attributeValues{
+					"woozles": json.RawMessage(`"baz"`),
+					"foozles": json.RawMessage(`"bat"`),
+				},
+				SensitiveValues: json.RawMessage("{}"),
+			}},
+			Err: false,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			before, err := plans.NewDynamicValue(test.Before, test.Before.Type())
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			after, err := plans.NewDynamicValue(test.After, test.After.Type())
+			if err != nil {
+				t.Fatal(err)
+			}
+			testChange := &plans.Changes{
+				Resources: []*plans.ResourceInstanceChangeSrc{
+					{
+						Addr: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "example",
+						}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+						ProviderAddr: addrs.AbsProviderConfig{
+							Provider: addrs.NewDefaultProvider("test"),
+							Module:   addrs.RootModule,
+						},
+						ChangeSrc: plans.ChangeSrc{
+							Action: test.Action,
+							Before: before,
+							After:  after,
+						},
+					},
+				},
+			}
+
+			ris := testResourceAddrs()
+
+			got, err := marshalPlanResources(testChange, ris, testSchemas())
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			eq := reflect.DeepEqual(got, test.Want)
+			if !eq {
+				t.Fatalf("wrong result:\nGot: %#v\nWant: %#v\n", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestMarshalPlanValuesNoopDeposed(t *testing.T) {
+	dynamicNull, err := plans.NewDynamicValue(cty.NullVal(cty.DynamicPseudoType), cty.DynamicPseudoType)
+	if err != nil {
+		t.Fatal(err)
+	}
+	testChange := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: addrs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "test_thing",
+					Name: "example",
+				}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+				DeposedKey: "12345678",
+				ProviderAddr: addrs.AbsProviderConfig{
+					Provider: addrs.NewDefaultProvider("test"),
+					Module:   addrs.RootModule,
+				},
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.NoOp,
+					Before: dynamicNull,
+					After:  dynamicNull,
+				},
+			},
+		},
+	}
+
+	_, err = marshalPlannedValues(testChange, testSchemas())
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func testSchemas() *terraform.Schemas {
+	return &terraform.Schemas{
+		Providers: map[addrs.Provider]*terraform.ProviderSchema{
+			addrs.NewDefaultProvider("test"): &terraform.ProviderSchema{
+				ResourceTypes: map[string]*configschema.Block{
+					"test_thing": {
+						Attributes: map[string]*configschema.Attribute{
+							"woozles": {Type: cty.String, Optional: true, Computed: true},
+							"foozles": {Type: cty.String, Optional: true},
+						},
+					},
+				},
+				ResourceTypeSchemaVersions: map[string]uint64{
+					"test_thing": 1,
+				},
+			},
+		},
+	}
+}
+
+func testResourceAddrs() []addrs.AbsResourceInstance {
+	return []addrs.AbsResourceInstance{
+		mustAddr("test_thing.example"),
+	}
+}
+
+func mustAddr(str string) addrs.AbsResourceInstance {
+	addr, diags := addrs.ParseAbsResourceInstanceStr(str)
+	if diags.HasErrors() {
+		panic(diags.Err())
+	}
+	return addr
+}
diff --git a/v1.5.7/internal/command/jsonprovider/attribute.go b/v1.5.7/internal/command/jsonprovider/attribute.go
new file mode 100644
index 0000000..b1e6b4f
--- /dev/null
+++ b/v1.5.7/internal/command/jsonprovider/attribute.go
@@ -0,0 +1,70 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonprovider
+
+import (
+	"encoding/json"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/zclconf/go-cty/cty"
+)
+
+type Attribute struct {
+	AttributeType       json.RawMessage `json:"type,omitempty"`
+	AttributeNestedType *NestedType     `json:"nested_type,omitempty"`
+	Description         string          `json:"description,omitempty"`
+	DescriptionKind     string          `json:"description_kind,omitempty"`
+	Deprecated          bool            `json:"deprecated,omitempty"`
+	Required            bool            `json:"required,omitempty"`
+	Optional            bool            `json:"optional,omitempty"`
+	Computed            bool            `json:"computed,omitempty"`
+	Sensitive           bool            `json:"sensitive,omitempty"`
+}
+
+type NestedType struct {
+	Attributes  map[string]*Attribute `json:"attributes,omitempty"`
+	NestingMode string                `json:"nesting_mode,omitempty"`
+}
+
+func marshalStringKind(sk configschema.StringKind) string {
+	switch sk {
+	default:
+		return "plain"
+	case configschema.StringMarkdown:
+		return "markdown"
+	}
+}
+
+func marshalAttribute(attr *configschema.Attribute) *Attribute {
+	ret := &Attribute{
+		Description:     attr.Description,
+		DescriptionKind: marshalStringKind(attr.DescriptionKind),
+		Required:        attr.Required,
+		Optional:        attr.Optional,
+		Computed:        attr.Computed,
+		Sensitive:       attr.Sensitive,
+		Deprecated:      attr.Deprecated,
+	}
+
+	// we're not concerned about errors because at this point the schema has
+	// already been checked and re-checked.
+	if attr.Type != cty.NilType {
+		attrTy, _ := attr.Type.MarshalJSON()
+		ret.AttributeType = attrTy
+	}
+
+	if attr.NestedType != nil {
+		nestedTy := NestedType{
+			NestingMode: nestingModeString(attr.NestedType.Nesting),
+		}
+		attrs := make(map[string]*Attribute, len(attr.NestedType.Attributes))
+		for k, attr := range attr.NestedType.Attributes {
+			attrs[k] = marshalAttribute(attr)
+		}
+		nestedTy.Attributes = attrs
+		ret.AttributeNestedType = &nestedTy
+	}
+
+	return ret
+}
diff --git a/v1.5.7/internal/command/jsonprovider/attribute_test.go b/v1.5.7/internal/command/jsonprovider/attribute_test.go
new file mode 100644
index 0000000..824b67c
--- /dev/null
+++ b/v1.5.7/internal/command/jsonprovider/attribute_test.go
@@ -0,0 +1,47 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonprovider
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+func TestMarshalAttribute(t *testing.T) {
+	tests := []struct {
+		Input *configschema.Attribute
+		Want  *Attribute
+	}{
+		{
+			&configschema.Attribute{Type: cty.String, Optional: true, Computed: true},
+			&Attribute{
+				AttributeType:   json.RawMessage(`"string"`),
+				Optional:        true,
+				Computed:        true,
+				DescriptionKind: "plain",
+			},
+		},
+		{ // collection types look a little odd.
+			&configschema.Attribute{Type: cty.Map(cty.String), Optional: true, Computed: true},
+			&Attribute{
+				AttributeType:   json.RawMessage(`["map","string"]`),
+				Optional:        true,
+				Computed:        true,
+				DescriptionKind: "plain",
+			},
+		},
+	}
+
+	for _, test := range tests {
+		got := marshalAttribute(test.Input)
+		if !cmp.Equal(got, test.Want) {
+			t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, test.Want))
+		}
+	}
+}
diff --git a/v1.5.7/internal/command/jsonprovider/block.go b/v1.5.7/internal/command/jsonprovider/block.go
new file mode 100644
index 0000000..19ab237
--- /dev/null
+++ b/v1.5.7/internal/command/jsonprovider/block.go
@@ -0,0 +1,83 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonprovider
+
+import (
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+type Block struct {
+	Attributes      map[string]*Attribute `json:"attributes,omitempty"`
+	BlockTypes      map[string]*BlockType `json:"block_types,omitempty"`
+	Description     string                `json:"description,omitempty"`
+	DescriptionKind string                `json:"description_kind,omitempty"`
+	Deprecated      bool                  `json:"deprecated,omitempty"`
+}
+
+type BlockType struct {
+	NestingMode string `json:"nesting_mode,omitempty"`
+	Block       *Block `json:"block,omitempty"`
+	MinItems    uint64 `json:"min_items,omitempty"`
+	MaxItems    uint64 `json:"max_items,omitempty"`
+}
+
+func marshalBlockTypes(nestedBlock *configschema.NestedBlock) *BlockType {
+	if nestedBlock == nil {
+		return &BlockType{}
+	}
+	ret := &BlockType{
+		Block:       marshalBlock(&nestedBlock.Block),
+		MinItems:    uint64(nestedBlock.MinItems),
+		MaxItems:    uint64(nestedBlock.MaxItems),
+		NestingMode: nestingModeString(nestedBlock.Nesting),
+	}
+	return ret
+}
+
+func marshalBlock(configBlock *configschema.Block) *Block {
+	if configBlock == nil {
+		return &Block{}
+	}
+
+	ret := Block{
+		Deprecated:      configBlock.Deprecated,
+		Description:     configBlock.Description,
+		DescriptionKind: marshalStringKind(configBlock.DescriptionKind),
+	}
+
+	if len(configBlock.Attributes) > 0 {
+		attrs := make(map[string]*Attribute, len(configBlock.Attributes))
+		for k, attr := range configBlock.Attributes {
+			attrs[k] = marshalAttribute(attr)
+		}
+		ret.Attributes = attrs
+	}
+
+	if len(configBlock.BlockTypes) > 0 {
+		blockTypes := make(map[string]*BlockType, len(configBlock.BlockTypes))
+		for k, bt := range configBlock.BlockTypes {
+			blockTypes[k] = marshalBlockTypes(bt)
+		}
+		ret.BlockTypes = blockTypes
+	}
+
+	return &ret
+}
+
+func nestingModeString(mode configschema.NestingMode) string {
+	switch mode {
+	case configschema.NestingSingle:
+		return "single"
+	case configschema.NestingGroup:
+		return "group"
+	case configschema.NestingList:
+		return "list"
+	case configschema.NestingSet:
+		return "set"
+	case configschema.NestingMap:
+		return "map"
+	default:
+		return "invalid"
+	}
+}
diff --git a/v1.5.7/internal/command/jsonprovider/block_test.go b/v1.5.7/internal/command/jsonprovider/block_test.go
new file mode 100644
index 0000000..bfd1629
--- /dev/null
+++ b/v1.5.7/internal/command/jsonprovider/block_test.go
@@ -0,0 +1,71 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonprovider
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+func TestMarshalBlock(t *testing.T) {
+	tests := []struct {
+		Input *configschema.Block
+		Want  *Block
+	}{
+		{
+			nil,
+			&Block{},
+		},
+		{
+			Input: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Optional: true, Computed: true},
+					"ami": {Type: cty.String, Optional: true},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"network_interface": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"device_index": {Type: cty.String, Optional: true},
+								"description":  {Type: cty.String, Optional: true},
+							},
+						},
+					},
+				},
+			},
+			Want: &Block{
+				Attributes: map[string]*Attribute{
+					"ami": {AttributeType: json.RawMessage(`"string"`), Optional: true, DescriptionKind: "plain"},
+					"id":  {AttributeType: json.RawMessage(`"string"`), Optional: true, Computed: true, DescriptionKind: "plain"},
+				},
+				BlockTypes: map[string]*BlockType{
+					"network_interface": {
+						NestingMode: "list",
+						Block: &Block{
+							Attributes: map[string]*Attribute{
+								"description":  {AttributeType: json.RawMessage(`"string"`), Optional: true, DescriptionKind: "plain"},
+								"device_index": {AttributeType: json.RawMessage(`"string"`), Optional: true, DescriptionKind: "plain"},
+							},
+							DescriptionKind: "plain",
+						},
+					},
+				},
+				DescriptionKind: "plain",
+			},
+		},
+	}
+
+	for _, test := range tests {
+		got := marshalBlock(test.Input)
+		if !cmp.Equal(got, test.Want) {
+			t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, test.Want))
+		}
+	}
+}
diff --git a/v1.5.7/internal/command/jsonprovider/doc.go b/v1.5.7/internal/command/jsonprovider/doc.go
new file mode 100644
index 0000000..3ea5002
--- /dev/null
+++ b/v1.5.7/internal/command/jsonprovider/doc.go
@@ -0,0 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package jsonprovider contains types and functions to marshal terraform
+// provider schemas into a json formatted output.
+package jsonprovider
diff --git a/v1.5.7/internal/command/jsonprovider/provider.go b/v1.5.7/internal/command/jsonprovider/provider.go
new file mode 100644
index 0000000..17cd841
--- /dev/null
+++ b/v1.5.7/internal/command/jsonprovider/provider.go
@@ -0,0 +1,81 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonprovider
+
+import (
+	"encoding/json"
+
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// FormatVersion represents the version of the json format and will be
+// incremented for any change to this format that requires changes to a
+// consuming parser.
+const FormatVersion = "1.0"
+
+// providers is the top-level object returned when exporting provider schemas
+type providers struct {
+	FormatVersion string               `json:"format_version"`
+	Schemas       map[string]*Provider `json:"provider_schemas,omitempty"`
+}
+
+type Provider struct {
+	Provider          *Schema            `json:"provider,omitempty"`
+	ResourceSchemas   map[string]*Schema `json:"resource_schemas,omitempty"`
+	DataSourceSchemas map[string]*Schema `json:"data_source_schemas,omitempty"`
+}
+
+func newProviders() *providers {
+	schemas := make(map[string]*Provider)
+	return &providers{
+		FormatVersion: FormatVersion,
+		Schemas:       schemas,
+	}
+}
+
+// MarshalForRenderer converts the provided internation representation of the
+// schema into the public structured JSON versions.
+//
+// This is a format that can be read by the structured plan renderer.
+func MarshalForRenderer(s *terraform.Schemas) map[string]*Provider {
+	schemas := make(map[string]*Provider, len(s.Providers))
+	for k, v := range s.Providers {
+		schemas[k.String()] = marshalProvider(v)
+	}
+	return schemas
+}
+
+func Marshal(s *terraform.Schemas) ([]byte, error) {
+	providers := newProviders()
+	providers.Schemas = MarshalForRenderer(s)
+	ret, err := json.Marshal(providers)
+	return ret, err
+}
+
+func marshalProvider(tps *terraform.ProviderSchema) *Provider {
+	if tps == nil {
+		return &Provider{}
+	}
+
+	var ps *Schema
+	var rs, ds map[string]*Schema
+
+	if tps.Provider != nil {
+		ps = marshalSchema(tps.Provider)
+	}
+
+	if tps.ResourceTypes != nil {
+		rs = marshalSchemas(tps.ResourceTypes, tps.ResourceTypeSchemaVersions)
+	}
+
+	if tps.DataSources != nil {
+		ds = marshalSchemas(tps.DataSources, tps.ResourceTypeSchemaVersions)
+	}
+
+	return &Provider{
+		Provider:          ps,
+		ResourceSchemas:   rs,
+		DataSourceSchemas: ds,
+	}
+}
diff --git a/v1.5.7/internal/command/jsonprovider/provider_test.go b/v1.5.7/internal/command/jsonprovider/provider_test.go
new file mode 100644
index 0000000..9fa8a07
--- /dev/null
+++ b/v1.5.7/internal/command/jsonprovider/provider_test.go
@@ -0,0 +1,215 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonprovider
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+func TestMarshalProvider(t *testing.T) {
+	tests := []struct {
+		Input *terraform.ProviderSchema
+		Want  *Provider
+	}{
+		{
+			nil,
+			&Provider{},
+		},
+		{
+			testProvider(),
+			&Provider{
+				Provider: &Schema{
+					Block: &Block{
+						Attributes: map[string]*Attribute{
+							"region": {
+								AttributeType:   json.RawMessage(`"string"`),
+								Required:        true,
+								DescriptionKind: "plain",
+							},
+						},
+						DescriptionKind: "plain",
+					},
+				},
+				ResourceSchemas: map[string]*Schema{
+					"test_instance": {
+						Version: 42,
+						Block: &Block{
+							Attributes: map[string]*Attribute{
+								"id": {
+									AttributeType:   json.RawMessage(`"string"`),
+									Optional:        true,
+									Computed:        true,
+									DescriptionKind: "plain",
+								},
+								"ami": {
+									AttributeType:   json.RawMessage(`"string"`),
+									Optional:        true,
+									DescriptionKind: "plain",
+								},
+								"volumes": {
+									AttributeNestedType: &NestedType{
+										NestingMode: "list",
+										Attributes: map[string]*Attribute{
+											"size": {
+												AttributeType:   json.RawMessage(`"string"`),
+												Required:        true,
+												DescriptionKind: "plain",
+											},
+											"mount_point": {
+												AttributeType:   json.RawMessage(`"string"`),
+												Required:        true,
+												DescriptionKind: "plain",
+											},
+										},
+									},
+									Optional:        true,
+									DescriptionKind: "plain",
+								},
+							},
+							BlockTypes: map[string]*BlockType{
+								"network_interface": {
+									Block: &Block{
+										Attributes: map[string]*Attribute{
+											"device_index": {
+												AttributeType:   json.RawMessage(`"string"`),
+												Optional:        true,
+												DescriptionKind: "plain",
+											},
+											"description": {
+												AttributeType:   json.RawMessage(`"string"`),
+												Optional:        true,
+												DescriptionKind: "plain",
+											},
+										},
+										DescriptionKind: "plain",
+									},
+									NestingMode: "list",
+								},
+							},
+							DescriptionKind: "plain",
+						},
+					},
+				},
+				DataSourceSchemas: map[string]*Schema{
+					"test_data_source": {
+						Version: 3,
+						Block: &Block{
+							Attributes: map[string]*Attribute{
+								"id": {
+									AttributeType:   json.RawMessage(`"string"`),
+									Optional:        true,
+									Computed:        true,
+									DescriptionKind: "plain",
+								},
+								"ami": {
+									AttributeType:   json.RawMessage(`"string"`),
+									Optional:        true,
+									DescriptionKind: "plain",
+								},
+							},
+							BlockTypes: map[string]*BlockType{
+								"network_interface": {
+									Block: &Block{
+										Attributes: map[string]*Attribute{
+											"device_index": {
+												AttributeType:   json.RawMessage(`"string"`),
+												Optional:        true,
+												DescriptionKind: "plain",
+											},
+											"description": {
+												AttributeType:   json.RawMessage(`"string"`),
+												Optional:        true,
+												DescriptionKind: "plain",
+											},
+										},
+										DescriptionKind: "plain",
+									},
+									NestingMode: "list",
+								},
+							},
+							DescriptionKind: "plain",
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		got := marshalProvider(test.Input)
+		if !cmp.Equal(got, test.Want) {
+			t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, test.Want))
+		}
+	}
+}
+
+func testProvider() *terraform.ProviderSchema {
+	return &terraform.ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"region": {Type: cty.String, Required: true},
+			},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Optional: true, Computed: true},
+					"ami": {Type: cty.String, Optional: true},
+					"volumes": {
+						Optional: true,
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"size":        {Type: cty.String, Required: true},
+								"mount_point": {Type: cty.String, Required: true},
+							},
+						},
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"network_interface": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"device_index": {Type: cty.String, Optional: true},
+								"description":  {Type: cty.String, Optional: true},
+							},
+						},
+					},
+				},
+			},
+		},
+		DataSources: map[string]*configschema.Block{
+			"test_data_source": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Optional: true, Computed: true},
+					"ami": {Type: cty.String, Optional: true},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"network_interface": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"device_index": {Type: cty.String, Optional: true},
+								"description":  {Type: cty.String, Optional: true},
+							},
+						},
+					},
+				},
+			},
+		},
+
+		ResourceTypeSchemaVersions: map[string]uint64{
+			"test_instance":    42,
+			"test_data_source": 3,
+		},
+	}
+}
diff --git a/v1.5.7/internal/command/jsonprovider/schema.go b/v1.5.7/internal/command/jsonprovider/schema.go
new file mode 100644
index 0000000..b5c5d53
--- /dev/null
+++ b/v1.5.7/internal/command/jsonprovider/schema.go
@@ -0,0 +1,41 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonprovider
+
+import (
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+type Schema struct {
+	Version uint64 `json:"version"`
+	Block   *Block `json:"block,omitempty"`
+}
+
+// marshalSchema is a convenience wrapper around mashalBlock. Schema version
+// should be set by the caller.
+func marshalSchema(block *configschema.Block) *Schema {
+	if block == nil {
+		return &Schema{}
+	}
+
+	var ret Schema
+	ret.Block = marshalBlock(block)
+
+	return &ret
+}
+
+func marshalSchemas(blocks map[string]*configschema.Block, rVersions map[string]uint64) map[string]*Schema {
+	if blocks == nil {
+		return map[string]*Schema{}
+	}
+	ret := make(map[string]*Schema, len(blocks))
+	for k, v := range blocks {
+		ret[k] = marshalSchema(v)
+		version, ok := rVersions[k]
+		if ok {
+			ret[k].Version = version
+		}
+	}
+	return ret
+}
diff --git a/v1.5.7/internal/command/jsonprovider/schema_test.go b/v1.5.7/internal/command/jsonprovider/schema_test.go
new file mode 100644
index 0000000..3797b61
--- /dev/null
+++ b/v1.5.7/internal/command/jsonprovider/schema_test.go
@@ -0,0 +1,52 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonprovider
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+func TestMarshalSchemas(t *testing.T) {
+	tests := []struct {
+		Input    map[string]*configschema.Block
+		Versions map[string]uint64
+		Want     map[string]*Schema
+	}{
+		{
+			nil,
+			map[string]uint64{},
+			map[string]*Schema{},
+		},
+	}
+
+	for _, test := range tests {
+		got := marshalSchemas(test.Input, test.Versions)
+		if !cmp.Equal(got, test.Want) {
+			t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, test.Want))
+		}
+	}
+}
+
+func TestMarshalSchema(t *testing.T) {
+	tests := map[string]struct {
+		Input *configschema.Block
+		Want  *Schema
+	}{
+		"nil_block": {
+			nil,
+			&Schema{},
+		},
+	}
+
+	for _, test := range tests {
+		got := marshalSchema(test.Input)
+		if !cmp.Equal(got, test.Want) {
+			t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, test.Want))
+		}
+	}
+}
diff --git a/v1.5.7/internal/command/jsonstate/doc.go b/v1.5.7/internal/command/jsonstate/doc.go
new file mode 100644
index 0000000..d7382d0
--- /dev/null
+++ b/v1.5.7/internal/command/jsonstate/doc.go
@@ -0,0 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package jsonstate implements methods for outputting a state in a
+// machine-readable json format
+package jsonstate
diff --git a/v1.5.7/internal/command/jsonstate/state.go b/v1.5.7/internal/command/jsonstate/state.go
new file mode 100644
index 0000000..7d3adcb
--- /dev/null
+++ b/v1.5.7/internal/command/jsonstate/state.go
@@ -0,0 +1,556 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonstate
+
+import (
+	"encoding/json"
+	"fmt"
+	"sort"
+
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/jsonchecks"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+const (
+	// FormatVersion represents the version of the json format and will be
+	// incremented for any change to this format that requires changes to a
+	// consuming parser.
+	FormatVersion = "1.0"
+
+	ManagedResourceMode = "managed"
+	DataResourceMode    = "data"
+)
+
+// state is the top-level representation of the json format of a terraform
+// state.
+type state struct {
+	FormatVersion    string          `json:"format_version,omitempty"`
+	TerraformVersion string          `json:"terraform_version,omitempty"`
+	Values           *stateValues    `json:"values,omitempty"`
+	Checks           json.RawMessage `json:"checks,omitempty"`
+}
+
+// stateValues is the common representation of resolved values for both the prior
+// state (which is always complete) and the planned new state.
+type stateValues struct {
+	Outputs    map[string]Output `json:"outputs,omitempty"`
+	RootModule Module            `json:"root_module,omitempty"`
+}
+
+type Output struct {
+	Sensitive bool            `json:"sensitive"`
+	Value     json.RawMessage `json:"value,omitempty"`
+	Type      json.RawMessage `json:"type,omitempty"`
+}
+
+// Module is the representation of a module in state. This can be the root module
+// or a child module
+type Module struct {
+	// Resources are sorted in a user-friendly order that is undefined at this
+	// time, but consistent.
+	Resources []Resource `json:"resources,omitempty"`
+
+	// Address is the absolute module address, omitted for the root module
+	Address string `json:"address,omitempty"`
+
+	// Each module object can optionally have its own nested "child_modules",
+	// recursively describing the full module tree.
+	ChildModules []Module `json:"child_modules,omitempty"`
+}
+
+// Resource is the representation of a resource in the state.
+type Resource struct {
+	// Address is the absolute resource address
+	Address string `json:"address,omitempty"`
+
+	// Mode can be "managed" or "data"
+	Mode string `json:"mode,omitempty"`
+
+	Type string `json:"type,omitempty"`
+	Name string `json:"name,omitempty"`
+
+	// Index is omitted for a resource not using `count` or `for_each`.
+	Index json.RawMessage `json:"index,omitempty"`
+
+	// ProviderName allows the property "type" to be interpreted unambiguously
+	// in the unusual situation where a provider offers a resource type whose
+	// name does not start with its own name, such as the "googlebeta" provider
+	// offering "google_compute_instance".
+	ProviderName string `json:"provider_name"`
+
+	// SchemaVersion indicates which version of the resource type schema the
+	// "values" property conforms to.
+	SchemaVersion uint64 `json:"schema_version"`
+
+	// AttributeValues is the JSON representation of the attribute values of the
+	// resource, whose structure depends on the resource type schema. Any
+	// unknown values are omitted or set to null, making them indistinguishable
+	// from absent values.
+	AttributeValues AttributeValues `json:"values,omitempty"`
+
+	// SensitiveValues is similar to AttributeValues, but with all sensitive
+	// values replaced with true, and all non-sensitive leaf values omitted.
+	SensitiveValues json.RawMessage `json:"sensitive_values,omitempty"`
+
+	// DependsOn contains a list of the resource's dependencies. The entries are
+	// addresses relative to the containing module.
+	DependsOn []string `json:"depends_on,omitempty"`
+
+	// Tainted is true if the resource is tainted in terraform state.
+	Tainted bool `json:"tainted,omitempty"`
+
+	// Deposed is set if the resource is deposed in terraform state.
+	DeposedKey string `json:"deposed_key,omitempty"`
+}
+
+// AttributeValues is the JSON representation of the attribute values of the
+// resource, whose structure depends on the resource type schema.
+type AttributeValues map[string]json.RawMessage
+
+func marshalAttributeValues(value cty.Value) AttributeValues {
+	// unmark our value to show all values
+	value, _ = value.UnmarkDeep()
+
+	if value == cty.NilVal || value.IsNull() {
+		return nil
+	}
+
+	ret := make(AttributeValues)
+
+	it := value.ElementIterator()
+	for it.Next() {
+		k, v := it.Element()
+		vJSON, _ := ctyjson.Marshal(v, v.Type())
+		ret[k.AsString()] = json.RawMessage(vJSON)
+	}
+	return ret
+}
+
+// newState() returns a minimally-initialized state
+func newState() *state {
+	return &state{
+		FormatVersion: FormatVersion,
+	}
+}
+
+// MarshalForRenderer returns the pre-json encoding changes of the state, in a
+// format available to the structured renderer.
+func MarshalForRenderer(sf *statefile.File, schemas *terraform.Schemas) (Module, map[string]Output, error) {
+	if sf.State.Modules == nil {
+		// Empty state case.
+		return Module{}, nil, nil
+	}
+
+	outputs, err := MarshalOutputs(sf.State.RootModule().OutputValues)
+	if err != nil {
+		return Module{}, nil, err
+	}
+
+	root, err := marshalRootModule(sf.State, schemas)
+	if err != nil {
+		return Module{}, nil, err
+	}
+
+	return root, outputs, err
+}
+
+// Marshal returns the json encoding of a terraform state.
+func Marshal(sf *statefile.File, schemas *terraform.Schemas) ([]byte, error) {
+	output := newState()
+
+	if sf == nil || sf.State.Empty() {
+		ret, err := json.Marshal(output)
+		return ret, err
+	}
+
+	if sf.TerraformVersion != nil {
+		output.TerraformVersion = sf.TerraformVersion.String()
+	}
+
+	// output.StateValues
+	err := output.marshalStateValues(sf.State, schemas)
+	if err != nil {
+		return nil, err
+	}
+
+	// output.Checks
+	if sf.State.CheckResults != nil && sf.State.CheckResults.ConfigResults.Len() > 0 {
+		output.Checks = jsonchecks.MarshalCheckStates(sf.State.CheckResults)
+	}
+
+	ret, err := json.Marshal(output)
+	return ret, err
+}
+
+func (jsonstate *state) marshalStateValues(s *states.State, schemas *terraform.Schemas) error {
+	var sv stateValues
+	var err error
+
+	// only marshal the root module outputs
+	sv.Outputs, err = MarshalOutputs(s.RootModule().OutputValues)
+	if err != nil {
+		return err
+	}
+
+	// use the state and module map to build up the module structure
+	sv.RootModule, err = marshalRootModule(s, schemas)
+	if err != nil {
+		return err
+	}
+
+	jsonstate.Values = &sv
+	return nil
+}
+
+// MarshalOutputs translates a map of states.OutputValue to a map of jsonstate.Output,
+// which are defined for json encoding.
+func MarshalOutputs(outputs map[string]*states.OutputValue) (map[string]Output, error) {
+	if outputs == nil {
+		return nil, nil
+	}
+
+	ret := make(map[string]Output)
+	for k, v := range outputs {
+		ty := v.Value.Type()
+		ov, err := ctyjson.Marshal(v.Value, ty)
+		if err != nil {
+			return ret, err
+		}
+		ot, err := ctyjson.MarshalType(ty)
+		if err != nil {
+			return ret, err
+		}
+		ret[k] = Output{
+			Value:     ov,
+			Type:      ot,
+			Sensitive: v.Sensitive,
+		}
+	}
+
+	return ret, nil
+}
+
+func marshalRootModule(s *states.State, schemas *terraform.Schemas) (Module, error) {
+	var ret Module
+	var err error
+
+	ret.Address = ""
+	rs, err := marshalResources(s.RootModule().Resources, addrs.RootModuleInstance, schemas)
+	if err != nil {
+		return ret, err
+	}
+	ret.Resources = rs
+
+	// build a map of module -> set[child module addresses]
+	moduleChildSet := make(map[string]map[string]struct{})
+	for _, mod := range s.Modules {
+		if mod.Addr.IsRoot() {
+			continue
+		} else {
+			for childAddr := mod.Addr; !childAddr.IsRoot(); childAddr = childAddr.Parent() {
+				if _, ok := moduleChildSet[childAddr.Parent().String()]; !ok {
+					moduleChildSet[childAddr.Parent().String()] = map[string]struct{}{}
+				}
+				moduleChildSet[childAddr.Parent().String()][childAddr.String()] = struct{}{}
+			}
+		}
+	}
+
+	// transform the previous map into map of module -> [child module addresses]
+	moduleMap := make(map[string][]addrs.ModuleInstance)
+	for parent, children := range moduleChildSet {
+		for child := range children {
+			childModuleInstance, diags := addrs.ParseModuleInstanceStr(child)
+			if diags.HasErrors() {
+				return ret, diags.Err()
+			}
+			moduleMap[parent] = append(moduleMap[parent], childModuleInstance)
+		}
+	}
+
+	// use the state and module map to build up the module structure
+	ret.ChildModules, err = marshalModules(s, schemas, moduleMap[""], moduleMap)
+	return ret, err
+}
+
+// marshalModules is an ungainly recursive function to build a module structure
+// out of terraform state.
+func marshalModules(
+	s *states.State,
+	schemas *terraform.Schemas,
+	modules []addrs.ModuleInstance,
+	moduleMap map[string][]addrs.ModuleInstance,
+) ([]Module, error) {
+	var ret []Module
+	for _, child := range modules {
+		// cm for child module, naming things is hard.
+		cm := Module{Address: child.String()}
+
+		// the module may be resourceless and contain only submodules, it will then be nil here
+		stateMod := s.Module(child)
+		if stateMod != nil {
+			rs, err := marshalResources(stateMod.Resources, stateMod.Addr, schemas)
+			if err != nil {
+				return nil, err
+			}
+			cm.Resources = rs
+		}
+
+		if moduleMap[child.String()] != nil {
+			moreChildModules, err := marshalModules(s, schemas, moduleMap[child.String()], moduleMap)
+			if err != nil {
+				return nil, err
+			}
+			cm.ChildModules = moreChildModules
+		}
+
+		ret = append(ret, cm)
+	}
+
+	// sort the child modules by address for consistency.
+	sort.Slice(ret, func(i, j int) bool {
+		return ret[i].Address < ret[j].Address
+	})
+
+	return ret, nil
+}
+
+func marshalResources(resources map[string]*states.Resource, module addrs.ModuleInstance, schemas *terraform.Schemas) ([]Resource, error) {
+	var ret []Resource
+
+	var sortedResources []*states.Resource
+	for _, r := range resources {
+		sortedResources = append(sortedResources, r)
+	}
+	sort.Slice(sortedResources, func(i, j int) bool {
+		return sortedResources[i].Addr.Less(sortedResources[j].Addr)
+	})
+
+	for _, r := range sortedResources {
+
+		var sortedKeys []addrs.InstanceKey
+		for k := range r.Instances {
+			sortedKeys = append(sortedKeys, k)
+		}
+		sort.Slice(sortedKeys, func(i, j int) bool {
+			return addrs.InstanceKeyLess(sortedKeys[i], sortedKeys[j])
+		})
+
+		for _, k := range sortedKeys {
+			ri := r.Instances[k]
+
+			var err error
+
+			resAddr := r.Addr.Resource
+
+			current := Resource{
+				Address:      r.Addr.Instance(k).String(),
+				Type:         resAddr.Type,
+				Name:         resAddr.Name,
+				ProviderName: r.ProviderConfig.Provider.String(),
+			}
+
+			if k != nil {
+				index := k.Value()
+				if current.Index, err = ctyjson.Marshal(index, index.Type()); err != nil {
+					return nil, err
+				}
+			}
+
+			switch resAddr.Mode {
+			case addrs.ManagedResourceMode:
+				current.Mode = ManagedResourceMode
+			case addrs.DataResourceMode:
+				current.Mode = DataResourceMode
+			default:
+				return ret, fmt.Errorf("resource %s has an unsupported mode %s",
+					resAddr.String(),
+					resAddr.Mode.String(),
+				)
+			}
+
+			schema, version := schemas.ResourceTypeConfig(
+				r.ProviderConfig.Provider,
+				resAddr.Mode,
+				resAddr.Type,
+			)
+
+			// It is possible that the only instance is deposed
+			if ri.Current != nil {
+				if version != ri.Current.SchemaVersion {
+					return nil, fmt.Errorf("schema version %d for %s in state does not match version %d from the provider", ri.Current.SchemaVersion, resAddr, version)
+				}
+
+				current.SchemaVersion = ri.Current.SchemaVersion
+
+				if schema == nil {
+					return nil, fmt.Errorf("no schema found for %s (in provider %s)", resAddr.String(), r.ProviderConfig.Provider)
+				}
+				riObj, err := ri.Current.Decode(schema.ImpliedType())
+				if err != nil {
+					return nil, err
+				}
+
+				current.AttributeValues = marshalAttributeValues(riObj.Value)
+
+				value, marks := riObj.Value.UnmarkDeepWithPaths()
+				if schema.ContainsSensitive() {
+					marks = append(marks, schema.ValueMarks(value, nil)...)
+				}
+				s := SensitiveAsBool(value.MarkWithPaths(marks))
+				v, err := ctyjson.Marshal(s, s.Type())
+				if err != nil {
+					return nil, err
+				}
+				current.SensitiveValues = v
+
+				if len(riObj.Dependencies) > 0 {
+					dependencies := make([]string, len(riObj.Dependencies))
+					for i, v := range riObj.Dependencies {
+						dependencies[i] = v.String()
+					}
+					current.DependsOn = dependencies
+				}
+
+				if riObj.Status == states.ObjectTainted {
+					current.Tainted = true
+				}
+				ret = append(ret, current)
+			}
+
+			var sortedDeposedKeys []string
+			for k := range ri.Deposed {
+				sortedDeposedKeys = append(sortedDeposedKeys, string(k))
+			}
+			sort.Strings(sortedDeposedKeys)
+
+			for _, deposedKey := range sortedDeposedKeys {
+				rios := ri.Deposed[states.DeposedKey(deposedKey)]
+
+				// copy the base fields from the current instance
+				deposed := Resource{
+					Address:      current.Address,
+					Type:         current.Type,
+					Name:         current.Name,
+					ProviderName: current.ProviderName,
+					Mode:         current.Mode,
+					Index:        current.Index,
+				}
+
+				riObj, err := rios.Decode(schema.ImpliedType())
+				if err != nil {
+					return nil, err
+				}
+
+				deposed.AttributeValues = marshalAttributeValues(riObj.Value)
+
+				value, marks := riObj.Value.UnmarkDeepWithPaths()
+				if schema.ContainsSensitive() {
+					marks = append(marks, schema.ValueMarks(value, nil)...)
+				}
+				s := SensitiveAsBool(value.MarkWithPaths(marks))
+				v, err := ctyjson.Marshal(s, s.Type())
+				if err != nil {
+					return nil, err
+				}
+				deposed.SensitiveValues = v
+
+				if len(riObj.Dependencies) > 0 {
+					dependencies := make([]string, len(riObj.Dependencies))
+					for i, v := range riObj.Dependencies {
+						dependencies[i] = v.String()
+					}
+					deposed.DependsOn = dependencies
+				}
+
+				if riObj.Status == states.ObjectTainted {
+					deposed.Tainted = true
+				}
+				deposed.DeposedKey = deposedKey
+				ret = append(ret, deposed)
+			}
+		}
+	}
+
+	return ret, nil
+}
+
+func SensitiveAsBool(val cty.Value) cty.Value {
+	if val.HasMark(marks.Sensitive) {
+		return cty.True
+	}
+
+	ty := val.Type()
+	switch {
+	case val.IsNull(), ty.IsPrimitiveType(), ty.Equals(cty.DynamicPseudoType):
+		return cty.False
+	case ty.IsListType() || ty.IsTupleType() || ty.IsSetType():
+		if !val.IsKnown() {
+			// If the collection is unknown we can't say anything about the
+			// sensitivity of its contents
+			return cty.EmptyTupleVal
+		}
+		length := val.LengthInt()
+		if length == 0 {
+			// If there are no elements then we can't have sensitive values
+			return cty.EmptyTupleVal
+		}
+		vals := make([]cty.Value, 0, length)
+		it := val.ElementIterator()
+		for it.Next() {
+			_, v := it.Element()
+			vals = append(vals, SensitiveAsBool(v))
+		}
+		// The above transform may have changed the types of some of the
+		// elements, so we'll always use a tuple here in case we've now made
+		// different elements have different types. Our ultimate goal is to
+		// marshal to JSON anyway, and all of these sequence types are
+		// indistinguishable in JSON.
+		return cty.TupleVal(vals)
+	case ty.IsMapType() || ty.IsObjectType():
+		if !val.IsKnown() {
+			// If the map/object is unknown we can't say anything about the
+			// sensitivity of its attributes
+			return cty.EmptyObjectVal
+		}
+		var length int
+		switch {
+		case ty.IsMapType():
+			length = val.LengthInt()
+		default:
+			length = len(val.Type().AttributeTypes())
+		}
+		if length == 0 {
+			// If there are no elements then we can't have sensitive values
+			return cty.EmptyObjectVal
+		}
+		vals := make(map[string]cty.Value)
+		it := val.ElementIterator()
+		for it.Next() {
+			k, v := it.Element()
+			s := SensitiveAsBool(v)
+			// Omit all of the "false"s for non-sensitive values for more
+			// compact serialization
+			if !s.RawEquals(cty.False) {
+				vals[k.AsString()] = s
+			}
+		}
+		// The above transform may have changed the types of some of the
+		// elements, so we'll always use an object here in case we've now made
+		// different elements have different types. Our ultimate goal is to
+		// marshal to JSON anyway, and all of these mapping types are
+		// indistinguishable in JSON.
+		return cty.ObjectVal(vals)
+	default:
+		// Should never happen, since the above should cover all types
+		panic(fmt.Sprintf("sensitiveAsBool cannot handle %#v", val))
+	}
+}
diff --git a/v1.5.7/internal/command/jsonstate/state_test.go b/v1.5.7/internal/command/jsonstate/state_test.go
new file mode 100644
index 0000000..27544de
--- /dev/null
+++ b/v1.5.7/internal/command/jsonstate/state_test.go
@@ -0,0 +1,1047 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package jsonstate
+
+import (
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+func TestMarshalOutputs(t *testing.T) {
+	tests := []struct {
+		Outputs map[string]*states.OutputValue
+		Want    map[string]Output
+		Err     bool
+	}{
+		{
+			nil,
+			nil,
+			false,
+		},
+		{
+			map[string]*states.OutputValue{
+				"test": {
+					Sensitive: true,
+					Value:     cty.StringVal("sekret"),
+				},
+			},
+			map[string]Output{
+				"test": {
+					Sensitive: true,
+					Value:     json.RawMessage(`"sekret"`),
+					Type:      json.RawMessage(`"string"`),
+				},
+			},
+			false,
+		},
+		{
+			map[string]*states.OutputValue{
+				"test": {
+					Sensitive: false,
+					Value:     cty.StringVal("not_so_sekret"),
+				},
+			},
+			map[string]Output{
+				"test": {
+					Sensitive: false,
+					Value:     json.RawMessage(`"not_so_sekret"`),
+					Type:      json.RawMessage(`"string"`),
+				},
+			},
+			false,
+		},
+		{
+			map[string]*states.OutputValue{
+				"mapstring": {
+					Sensitive: false,
+					Value: cty.MapVal(map[string]cty.Value{
+						"beep": cty.StringVal("boop"),
+					}),
+				},
+				"setnumber": {
+					Sensitive: false,
+					Value: cty.SetVal([]cty.Value{
+						cty.NumberIntVal(3),
+						cty.NumberIntVal(5),
+						cty.NumberIntVal(7),
+						cty.NumberIntVal(11),
+					}),
+				},
+			},
+			map[string]Output{
+				"mapstring": {
+					Sensitive: false,
+					Value:     json.RawMessage(`{"beep":"boop"}`),
+					Type:      json.RawMessage(`["map","string"]`),
+				},
+				"setnumber": {
+					Sensitive: false,
+					Value:     json.RawMessage(`[3,5,7,11]`),
+					Type:      json.RawMessage(`["set","number"]`),
+				},
+			},
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		got, err := MarshalOutputs(test.Outputs)
+		if test.Err {
+			if err == nil {
+				t.Fatal("succeeded; want error")
+			}
+			return
+		} else if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if !cmp.Equal(test.Want, got) {
+			t.Fatalf("wrong result:\n%s", cmp.Diff(test.Want, got))
+		}
+	}
+}
+
+func TestMarshalAttributeValues(t *testing.T) {
+	tests := []struct {
+		Attr cty.Value
+		Want AttributeValues
+	}{
+		{
+			cty.NilVal,
+			nil,
+		},
+		{
+			cty.NullVal(cty.String),
+			nil,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+			}),
+			AttributeValues{"foo": json.RawMessage(`"bar"`)},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(cty.String),
+			}),
+			AttributeValues{"foo": json.RawMessage(`null`)},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"bar": cty.MapVal(map[string]cty.Value{
+					"hello": cty.StringVal("world"),
+				}),
+				"baz": cty.ListVal([]cty.Value{
+					cty.StringVal("goodnight"),
+					cty.StringVal("moon"),
+				}),
+			}),
+			AttributeValues{
+				"bar": json.RawMessage(`{"hello":"world"}`),
+				"baz": json.RawMessage(`["goodnight","moon"]`),
+			},
+		},
+		// Marked values
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"bar": cty.MapVal(map[string]cty.Value{
+					"hello": cty.StringVal("world"),
+				}),
+				"baz": cty.ListVal([]cty.Value{
+					cty.StringVal("goodnight"),
+					cty.StringVal("moon").Mark(marks.Sensitive),
+				}),
+			}),
+			AttributeValues{
+				"bar": json.RawMessage(`{"hello":"world"}`),
+				"baz": json.RawMessage(`["goodnight","moon"]`),
+			},
+		},
+	}
+
+	for _, test := range tests {
+		got := marshalAttributeValues(test.Attr)
+		eq := reflect.DeepEqual(got, test.Want)
+		if !eq {
+			t.Fatalf("wrong result:\nGot: %#v\nWant: %#v\n", got, test.Want)
+		}
+	}
+}
+
+func TestMarshalResources(t *testing.T) {
+	deposedKey := states.NewDeposedKey()
+	tests := map[string]struct {
+		Resources map[string]*states.Resource
+		Schemas   *terraform.Schemas
+		Want      []Resource
+		Err       bool
+	}{
+		"nil": {
+			nil,
+			nil,
+			nil,
+			false,
+		},
+		"single resource": {
+			map[string]*states.Resource{
+				"test_thing.baz": {
+					Addr: addrs.AbsResource{
+						Resource: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "bar",
+						},
+					},
+					Instances: map[addrs.InstanceKey]*states.ResourceInstance{
+						addrs.NoKey: {
+							Current: &states.ResourceInstanceObjectSrc{
+								Status:    states.ObjectReady,
+								AttrsJSON: []byte(`{"woozles":"confuzles"}`),
+							},
+						},
+					},
+					ProviderConfig: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("test"),
+						Module:   addrs.RootModule,
+					},
+				},
+			},
+			testSchemas(),
+			[]Resource{
+				{
+					Address:      "test_thing.bar",
+					Mode:         "managed",
+					Type:         "test_thing",
+					Name:         "bar",
+					Index:        nil,
+					ProviderName: "registry.terraform.io/hashicorp/test",
+					AttributeValues: AttributeValues{
+						"foozles": json.RawMessage(`null`),
+						"woozles": json.RawMessage(`"confuzles"`),
+					},
+					SensitiveValues: json.RawMessage("{\"foozles\":true}"),
+				},
+			},
+			false,
+		},
+		"single resource_with_sensitive": {
+			map[string]*states.Resource{
+				"test_thing.baz": {
+					Addr: addrs.AbsResource{
+						Resource: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "bar",
+						},
+					},
+					Instances: map[addrs.InstanceKey]*states.ResourceInstance{
+						addrs.NoKey: {
+							Current: &states.ResourceInstanceObjectSrc{
+								Status:    states.ObjectReady,
+								AttrsJSON: []byte(`{"woozles":"confuzles","foozles":"sensuzles"}`),
+							},
+						},
+					},
+					ProviderConfig: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("test"),
+						Module:   addrs.RootModule,
+					},
+				},
+			},
+			testSchemas(),
+			[]Resource{
+				{
+					Address:      "test_thing.bar",
+					Mode:         "managed",
+					Type:         "test_thing",
+					Name:         "bar",
+					Index:        nil,
+					ProviderName: "registry.terraform.io/hashicorp/test",
+					AttributeValues: AttributeValues{
+						"foozles": json.RawMessage(`"sensuzles"`),
+						"woozles": json.RawMessage(`"confuzles"`),
+					},
+					SensitiveValues: json.RawMessage("{\"foozles\":true}"),
+				},
+			},
+			false,
+		},
+		"resource with marks": {
+			map[string]*states.Resource{
+				"test_thing.bar": {
+					Addr: addrs.AbsResource{
+						Resource: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "bar",
+						},
+					},
+					Instances: map[addrs.InstanceKey]*states.ResourceInstance{
+						addrs.NoKey: {
+							Current: &states.ResourceInstanceObjectSrc{
+								Status:    states.ObjectReady,
+								AttrsJSON: []byte(`{"foozles":"confuzles"}`),
+								AttrSensitivePaths: []cty.PathValueMarks{{
+									Path:  cty.Path{cty.GetAttrStep{Name: "foozles"}},
+									Marks: cty.NewValueMarks(marks.Sensitive)},
+								},
+							},
+						},
+					},
+					ProviderConfig: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("test"),
+						Module:   addrs.RootModule,
+					},
+				},
+			},
+			testSchemas(),
+			[]Resource{
+				{
+					Address:      "test_thing.bar",
+					Mode:         "managed",
+					Type:         "test_thing",
+					Name:         "bar",
+					Index:        nil,
+					ProviderName: "registry.terraform.io/hashicorp/test",
+					AttributeValues: AttributeValues{
+						"foozles": json.RawMessage(`"confuzles"`),
+						"woozles": json.RawMessage(`null`),
+					},
+					SensitiveValues: json.RawMessage(`{"foozles":true}`),
+				},
+			},
+			false,
+		},
+		"single resource wrong schema": {
+			map[string]*states.Resource{
+				"test_thing.baz": {
+					Addr: addrs.AbsResource{
+						Resource: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "bar",
+						},
+					},
+					Instances: map[addrs.InstanceKey]*states.ResourceInstance{
+						addrs.NoKey: {
+							Current: &states.ResourceInstanceObjectSrc{
+								SchemaVersion: 1,
+								Status:        states.ObjectReady,
+								AttrsJSON:     []byte(`{"woozles":["confuzles"]}`),
+							},
+						},
+					},
+					ProviderConfig: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("test"),
+						Module:   addrs.RootModule,
+					},
+				},
+			},
+			testSchemas(),
+			nil,
+			true,
+		},
+		"resource with count": {
+			map[string]*states.Resource{
+				"test_thing.bar": {
+					Addr: addrs.AbsResource{
+						Resource: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "bar",
+						},
+					},
+					Instances: map[addrs.InstanceKey]*states.ResourceInstance{
+						addrs.IntKey(0): {
+							Current: &states.ResourceInstanceObjectSrc{
+								Status:    states.ObjectReady,
+								AttrsJSON: []byte(`{"woozles":"confuzles"}`),
+							},
+						},
+					},
+					ProviderConfig: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("test"),
+						Module:   addrs.RootModule,
+					},
+				},
+			},
+			testSchemas(),
+			[]Resource{
+				{
+					Address:      "test_thing.bar[0]",
+					Mode:         "managed",
+					Type:         "test_thing",
+					Name:         "bar",
+					Index:        json.RawMessage(`0`),
+					ProviderName: "registry.terraform.io/hashicorp/test",
+					AttributeValues: AttributeValues{
+						"foozles": json.RawMessage(`null`),
+						"woozles": json.RawMessage(`"confuzles"`),
+					},
+					SensitiveValues: json.RawMessage("{\"foozles\":true}"),
+				},
+			},
+			false,
+		},
+		"resource with for_each": {
+			map[string]*states.Resource{
+				"test_thing.bar": {
+					Addr: addrs.AbsResource{
+						Resource: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "bar",
+						},
+					},
+					Instances: map[addrs.InstanceKey]*states.ResourceInstance{
+						addrs.StringKey("rockhopper"): {
+							Current: &states.ResourceInstanceObjectSrc{
+								Status:    states.ObjectReady,
+								AttrsJSON: []byte(`{"woozles":"confuzles"}`),
+							},
+						},
+					},
+					ProviderConfig: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("test"),
+						Module:   addrs.RootModule,
+					},
+				},
+			},
+			testSchemas(),
+			[]Resource{
+				{
+					Address:      "test_thing.bar[\"rockhopper\"]",
+					Mode:         "managed",
+					Type:         "test_thing",
+					Name:         "bar",
+					Index:        json.RawMessage(`"rockhopper"`),
+					ProviderName: "registry.terraform.io/hashicorp/test",
+					AttributeValues: AttributeValues{
+						"foozles": json.RawMessage(`null`),
+						"woozles": json.RawMessage(`"confuzles"`),
+					},
+					SensitiveValues: json.RawMessage("{\"foozles\":true}"),
+				},
+			},
+			false,
+		},
+		"deposed resource": {
+			map[string]*states.Resource{
+				"test_thing.baz": {
+					Addr: addrs.AbsResource{
+						Resource: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "bar",
+						},
+					},
+					Instances: map[addrs.InstanceKey]*states.ResourceInstance{
+						addrs.NoKey: {
+							Deposed: map[states.DeposedKey]*states.ResourceInstanceObjectSrc{
+								states.DeposedKey(deposedKey): {
+									Status:    states.ObjectReady,
+									AttrsJSON: []byte(`{"woozles":"confuzles"}`),
+								},
+							},
+						},
+					},
+					ProviderConfig: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("test"),
+						Module:   addrs.RootModule,
+					},
+				},
+			},
+			testSchemas(),
+			[]Resource{
+				{
+					Address:      "test_thing.bar",
+					Mode:         "managed",
+					Type:         "test_thing",
+					Name:         "bar",
+					Index:        nil,
+					ProviderName: "registry.terraform.io/hashicorp/test",
+					DeposedKey:   deposedKey.String(),
+					AttributeValues: AttributeValues{
+						"foozles": json.RawMessage(`null`),
+						"woozles": json.RawMessage(`"confuzles"`),
+					},
+					SensitiveValues: json.RawMessage("{\"foozles\":true}"),
+				},
+			},
+			false,
+		},
+		"deposed and current resource": {
+			map[string]*states.Resource{
+				"test_thing.baz": {
+					Addr: addrs.AbsResource{
+						Resource: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "bar",
+						},
+					},
+					Instances: map[addrs.InstanceKey]*states.ResourceInstance{
+						addrs.NoKey: {
+							Deposed: map[states.DeposedKey]*states.ResourceInstanceObjectSrc{
+								states.DeposedKey(deposedKey): {
+									Status:    states.ObjectReady,
+									AttrsJSON: []byte(`{"woozles":"confuzles"}`),
+								},
+							},
+							Current: &states.ResourceInstanceObjectSrc{
+								Status:    states.ObjectReady,
+								AttrsJSON: []byte(`{"woozles":"confuzles"}`),
+							},
+						},
+					},
+					ProviderConfig: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("test"),
+						Module:   addrs.RootModule,
+					},
+				},
+			},
+			testSchemas(),
+			[]Resource{
+				{
+					Address:      "test_thing.bar",
+					Mode:         "managed",
+					Type:         "test_thing",
+					Name:         "bar",
+					Index:        nil,
+					ProviderName: "registry.terraform.io/hashicorp/test",
+					AttributeValues: AttributeValues{
+						"foozles": json.RawMessage(`null`),
+						"woozles": json.RawMessage(`"confuzles"`),
+					},
+					SensitiveValues: json.RawMessage("{\"foozles\":true}"),
+				},
+				{
+					Address:      "test_thing.bar",
+					Mode:         "managed",
+					Type:         "test_thing",
+					Name:         "bar",
+					Index:        nil,
+					ProviderName: "registry.terraform.io/hashicorp/test",
+					DeposedKey:   deposedKey.String(),
+					AttributeValues: AttributeValues{
+						"foozles": json.RawMessage(`null`),
+						"woozles": json.RawMessage(`"confuzles"`),
+					},
+					SensitiveValues: json.RawMessage("{\"foozles\":true}"),
+				},
+			},
+			false,
+		},
+		"resource with marked map attr": {
+			map[string]*states.Resource{
+				"test_map_attr.bar": {
+					Addr: addrs.AbsResource{
+						Resource: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_map_attr",
+							Name: "bar",
+						},
+					},
+					Instances: map[addrs.InstanceKey]*states.ResourceInstance{
+						addrs.NoKey: {
+							Current: &states.ResourceInstanceObjectSrc{
+								Status:    states.ObjectReady,
+								AttrsJSON: []byte(`{"data":{"woozles":"confuzles"}}`),
+								AttrSensitivePaths: []cty.PathValueMarks{{
+									Path:  cty.Path{cty.GetAttrStep{Name: "data"}},
+									Marks: cty.NewValueMarks(marks.Sensitive)},
+								},
+							},
+						},
+					},
+					ProviderConfig: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("test"),
+						Module:   addrs.RootModule,
+					},
+				},
+			},
+			testSchemas(),
+			[]Resource{
+				{
+					Address:      "test_map_attr.bar",
+					Mode:         "managed",
+					Type:         "test_map_attr",
+					Name:         "bar",
+					Index:        nil,
+					ProviderName: "registry.terraform.io/hashicorp/test",
+					AttributeValues: AttributeValues{
+						"data": json.RawMessage(`{"woozles":"confuzles"}`),
+					},
+					SensitiveValues: json.RawMessage(`{"data":true}`),
+				},
+			},
+			false,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got, err := marshalResources(test.Resources, addrs.RootModuleInstance, test.Schemas)
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			diff := cmp.Diff(got, test.Want)
+			if diff != "" {
+				t.Fatalf("wrong result: %s\n", diff)
+			}
+
+		})
+	}
+}
+
+func TestMarshalModules_basic(t *testing.T) {
+	childModule, _ := addrs.ParseModuleInstanceStr("module.child")
+	subModule, _ := addrs.ParseModuleInstanceStr("module.submodule")
+	testState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(childModule),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   childModule.Module(),
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(subModule),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   subModule.Module(),
+			},
+		)
+	})
+	moduleMap := make(map[string][]addrs.ModuleInstance)
+	moduleMap[""] = []addrs.ModuleInstance{childModule, subModule}
+
+	got, err := marshalModules(testState, testSchemas(), moduleMap[""], moduleMap)
+
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err.Error())
+	}
+
+	if len(got) != 2 {
+		t.Fatalf("wrong result! got %d modules, expected 2", len(got))
+	}
+
+	if got[0].Address != "module.child" || got[1].Address != "module.submodule" {
+		t.Fatalf("wrong result! got %#v\n", got)
+	}
+
+}
+
+func TestMarshalModules_nested(t *testing.T) {
+	childModule, _ := addrs.ParseModuleInstanceStr("module.child")
+	subModule, _ := addrs.ParseModuleInstanceStr("module.child.module.submodule")
+	testState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(childModule),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   childModule.Module(),
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(subModule),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   subModule.Module(),
+			},
+		)
+	})
+	moduleMap := make(map[string][]addrs.ModuleInstance)
+	moduleMap[""] = []addrs.ModuleInstance{childModule}
+	moduleMap[childModule.String()] = []addrs.ModuleInstance{subModule}
+
+	got, err := marshalModules(testState, testSchemas(), moduleMap[""], moduleMap)
+
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err.Error())
+	}
+
+	if len(got) != 1 {
+		t.Fatalf("wrong result! got %d modules, expected 1", len(got))
+	}
+
+	if got[0].Address != "module.child" {
+		t.Fatalf("wrong result! got %#v\n", got)
+	}
+
+	if got[0].ChildModules[0].Address != "module.child.module.submodule" {
+		t.Fatalf("wrong result! got %#v\n", got)
+	}
+}
+
+func TestMarshalModules_parent_no_resources(t *testing.T) {
+	subModule, _ := addrs.ParseModuleInstanceStr("module.child.module.submodule")
+	testState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(subModule),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   subModule.Module(),
+			},
+		)
+	})
+	got, err := marshalRootModule(testState, testSchemas())
+
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err.Error())
+	}
+
+	if len(got.ChildModules) != 1 {
+		t.Fatalf("wrong result! got %d modules, expected 1", len(got.ChildModules))
+	}
+
+	if got.ChildModules[0].Address != "module.child" {
+		t.Fatalf("wrong result! got %#v\n", got)
+	}
+
+	if got.ChildModules[0].ChildModules[0].Address != "module.child.module.submodule" {
+		t.Fatalf("wrong result! got %#v\n", got)
+	}
+}
+
+func testSchemas() *terraform.Schemas {
+	return &terraform.Schemas{
+		Providers: map[addrs.Provider]*terraform.ProviderSchema{
+			addrs.NewDefaultProvider("test"): {
+				ResourceTypes: map[string]*configschema.Block{
+					"test_thing": {
+						Attributes: map[string]*configschema.Attribute{
+							"woozles": {Type: cty.String, Optional: true, Computed: true},
+							"foozles": {Type: cty.String, Optional: true, Sensitive: true},
+						},
+					},
+					"test_instance": {
+						Attributes: map[string]*configschema.Attribute{
+							"id":  {Type: cty.String, Optional: true, Computed: true},
+							"foo": {Type: cty.String, Optional: true},
+							"bar": {Type: cty.String, Optional: true},
+						},
+					},
+					"test_map_attr": {
+						Attributes: map[string]*configschema.Attribute{
+							"data": {Type: cty.Map(cty.String), Optional: true, Computed: true, Sensitive: true},
+						},
+					},
+				},
+			},
+		},
+	}
+}
+
+func TestSensitiveAsBool(t *testing.T) {
+	tests := []struct {
+		Input cty.Value
+		Want  cty.Value
+	}{
+		{
+			cty.StringVal("hello"),
+			cty.False,
+		},
+		{
+			cty.NullVal(cty.String),
+			cty.False,
+		},
+		{
+			cty.StringVal("hello").Mark(marks.Sensitive),
+			cty.True,
+		},
+		{
+			cty.NullVal(cty.String).Mark(marks.Sensitive),
+			cty.True,
+		},
+
+		{
+			cty.NullVal(cty.DynamicPseudoType).Mark(marks.Sensitive),
+			cty.True,
+		},
+		{
+			cty.NullVal(cty.Object(map[string]cty.Type{"test": cty.String})),
+			cty.False,
+		},
+		{
+			cty.NullVal(cty.Object(map[string]cty.Type{"test": cty.String})).Mark(marks.Sensitive),
+			cty.True,
+		},
+		{
+			cty.DynamicVal,
+			cty.False,
+		},
+		{
+			cty.DynamicVal.Mark(marks.Sensitive),
+			cty.True,
+		},
+
+		{
+			cty.ListValEmpty(cty.String),
+			cty.EmptyTupleVal,
+		},
+		{
+			cty.ListValEmpty(cty.String).Mark(marks.Sensitive),
+			cty.True,
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.StringVal("hello"),
+				cty.StringVal("friend").Mark(marks.Sensitive),
+			}),
+			cty.TupleVal([]cty.Value{
+				cty.False,
+				cty.True,
+			}),
+		},
+		{
+			cty.SetValEmpty(cty.String),
+			cty.EmptyTupleVal,
+		},
+		{
+			cty.SetValEmpty(cty.String).Mark(marks.Sensitive),
+			cty.True,
+		},
+		{
+			cty.SetVal([]cty.Value{cty.StringVal("hello")}),
+			cty.TupleVal([]cty.Value{cty.False}),
+		},
+		{
+			cty.SetVal([]cty.Value{cty.StringVal("hello").Mark(marks.Sensitive)}),
+			cty.True,
+		},
+		{
+			cty.EmptyTupleVal.Mark(marks.Sensitive),
+			cty.True,
+		},
+		{
+			cty.TupleVal([]cty.Value{
+				cty.StringVal("hello"),
+				cty.StringVal("friend").Mark(marks.Sensitive),
+			}),
+			cty.TupleVal([]cty.Value{
+				cty.False,
+				cty.True,
+			}),
+		},
+		{
+			cty.MapValEmpty(cty.String),
+			cty.EmptyObjectVal,
+		},
+		{
+			cty.MapValEmpty(cty.String).Mark(marks.Sensitive),
+			cty.True,
+		},
+		{
+			cty.MapVal(map[string]cty.Value{
+				"greeting": cty.StringVal("hello"),
+				"animal":   cty.StringVal("horse"),
+			}),
+			cty.EmptyObjectVal,
+		},
+		{
+			cty.MapVal(map[string]cty.Value{
+				"greeting": cty.StringVal("hello"),
+				"animal":   cty.StringVal("horse").Mark(marks.Sensitive),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"animal": cty.True,
+			}),
+		},
+		{
+			cty.MapVal(map[string]cty.Value{
+				"greeting": cty.StringVal("hello"),
+				"animal":   cty.StringVal("horse").Mark(marks.Sensitive),
+			}).Mark(marks.Sensitive),
+			cty.True,
+		},
+		{
+			cty.EmptyObjectVal,
+			cty.EmptyObjectVal,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"greeting": cty.StringVal("hello"),
+				"animal":   cty.StringVal("horse"),
+			}),
+			cty.EmptyObjectVal,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"greeting": cty.StringVal("hello"),
+				"animal":   cty.StringVal("horse").Mark(marks.Sensitive),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"animal": cty.True,
+			}),
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"greeting": cty.StringVal("hello"),
+				"animal":   cty.StringVal("horse").Mark(marks.Sensitive),
+			}).Mark(marks.Sensitive),
+			cty.True,
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.UnknownVal(cty.String),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.StringVal("known").Mark(marks.Sensitive),
+				}),
+			}),
+			cty.TupleVal([]cty.Value{
+				cty.EmptyObjectVal,
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.True,
+				}),
+			}),
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.MapValEmpty(cty.String),
+				cty.MapVal(map[string]cty.Value{
+					"a": cty.StringVal("known").Mark(marks.Sensitive),
+				}),
+				cty.MapVal(map[string]cty.Value{
+					"a": cty.UnknownVal(cty.String),
+				}),
+			}),
+			cty.TupleVal([]cty.Value{
+				cty.EmptyObjectVal,
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.True,
+				}),
+				cty.EmptyObjectVal,
+			}),
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"list":   cty.UnknownVal(cty.List(cty.String)),
+				"set":    cty.UnknownVal(cty.Set(cty.Bool)),
+				"tuple":  cty.UnknownVal(cty.Tuple([]cty.Type{cty.String, cty.Number})),
+				"map":    cty.UnknownVal(cty.Map(cty.String)),
+				"object": cty.UnknownVal(cty.Object(map[string]cty.Type{"a": cty.String})),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"list":   cty.EmptyTupleVal,
+				"set":    cty.EmptyTupleVal,
+				"tuple":  cty.EmptyTupleVal,
+				"map":    cty.EmptyObjectVal,
+				"object": cty.EmptyObjectVal,
+			}),
+		},
+	}
+
+	for _, test := range tests {
+		got := SensitiveAsBool(test.Input)
+		if !reflect.DeepEqual(got, test.Want) {
+			t.Errorf(
+				"wrong result\ninput: %#v\ngot:   %#v\nwant:  %#v",
+				test.Input, got, test.Want,
+			)
+		}
+	}
+}
diff --git a/v1.5.7/internal/command/login.go b/v1.5.7/internal/command/login.go
new file mode 100644
index 0000000..be5d783
--- /dev/null
+++ b/v1.5.7/internal/command/login.go
@@ -0,0 +1,803 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"context"
+	"crypto/sha256"
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"math/rand"
+	"net"
+	"net/http"
+	"net/url"
+	"path/filepath"
+	"strings"
+
+	tfe "github.com/hashicorp/go-tfe"
+	svchost "github.com/hashicorp/terraform-svchost"
+	svcauth "github.com/hashicorp/terraform-svchost/auth"
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/command/cliconfig"
+	"github.com/hashicorp/terraform/internal/httpclient"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+
+	uuid "github.com/hashicorp/go-uuid"
+	"golang.org/x/oauth2"
+)
+
+// LoginCommand is a Command implementation that runs an interactive login
+// flow for a remote service host. It then stashes credentials in a tfrc
+// file in the user's home directory.
+type LoginCommand struct {
+	Meta
+}
+
+// Run implements cli.Command.
+func (c *LoginCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	cmdFlags := c.Meta.extendedFlagSet("login")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		return 1
+	}
+
+	args = cmdFlags.Args()
+	if len(args) > 1 {
+		c.Ui.Error(
+			"The login command expects at most one argument: the host to log in to.")
+		cmdFlags.Usage()
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	if !c.input {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Login is an interactive command",
+			"The \"terraform login\" command uses interactive prompts to obtain and record credentials, so it can't be run with input disabled.\n\nTo configure credentials in a non-interactive context, write existing credentials directly to a CLI configuration file.",
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	givenHostname := "app.terraform.io"
+	if len(args) != 0 {
+		givenHostname = args[0]
+	}
+
+	hostname, err := svchost.ForComparison(givenHostname)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid hostname",
+			fmt.Sprintf("The given hostname %q is not valid: %s.", givenHostname, err.Error()),
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// From now on, since we've validated the given hostname, we should use
+	// dispHostname in the UI to ensure we're presenting it in the canonical
+	// form, in case that helpers users with debugging when things aren't
+	// working as expected. (Perhaps the normalization is part of the cause.)
+	dispHostname := hostname.ForDisplay()
+
+	host, err := c.Services.Discover(hostname)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Service discovery failed for "+dispHostname,
+
+			// Contrary to usual Go idiom, the Discover function returns
+			// full sentences with initial capitalization in its error messages,
+			// and they are written with the end-user as the audience. We
+			// only need to add the trailing period to make them consistent
+			// with our usual error reporting standards.
+			err.Error()+".",
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	creds := c.Services.CredentialsSource().(*cliconfig.CredentialsSource)
+	filename, _ := creds.CredentialsFilePath()
+	credsCtx := &loginCredentialsContext{
+		Location:      creds.HostCredentialsLocation(hostname),
+		LocalFilename: filename, // empty in the very unlikely event that we can't select a config directory for this user
+		HelperType:    creds.CredentialsHelperType(),
+	}
+
+	clientConfig, err := host.ServiceOAuthClient("login.v1")
+	switch err.(type) {
+	case nil:
+		// Great! No problem, then.
+	case *disco.ErrServiceNotProvided:
+		// This is also fine! We'll try the manual token creation process.
+	case *disco.ErrVersionNotSupported:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Warning,
+			"Host does not support Terraform login",
+			fmt.Sprintf("The given hostname %q allows creating Terraform authorization tokens, but requires a newer version of Terraform CLI to do so.", dispHostname),
+		))
+	default:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Warning,
+			"Host does not support Terraform login",
+			fmt.Sprintf("The given hostname %q cannot support \"terraform login\": %s.", dispHostname, err),
+		))
+	}
+
+	// If login service is unavailable, check for a TFE v2 API as fallback
+	var tfeservice *url.URL
+	if clientConfig == nil {
+		tfeservice, err = host.ServiceURL("tfe.v2")
+		switch err.(type) {
+		case nil:
+			// Success!
+		case *disco.ErrServiceNotProvided:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Host does not support Terraform tokens API",
+				fmt.Sprintf("The given hostname %q does not support creating Terraform authorization tokens.", dispHostname),
+			))
+		case *disco.ErrVersionNotSupported:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Host does not support Terraform tokens API",
+				fmt.Sprintf("The given hostname %q allows creating Terraform authorization tokens, but requires a newer version of Terraform CLI to do so.", dispHostname),
+			))
+		default:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Host does not support Terraform tokens API",
+				fmt.Sprintf("The given hostname %q cannot support \"terraform login\": %s.", dispHostname, err),
+			))
+		}
+	}
+
+	if credsCtx.Location == cliconfig.CredentialsInOtherFile {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			fmt.Sprintf("Credentials for %s are manually configured", dispHostname),
+			"The \"terraform login\" command cannot log in because credentials for this host are already configured in a CLI configuration file.\n\nTo log in, first revoke the existing credentials and remove that block from the CLI configuration.",
+		))
+	}
+
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	var token svcauth.HostCredentialsToken
+	var tokenDiags tfdiags.Diagnostics
+
+	// Prefer Terraform login if available
+	if clientConfig != nil {
+		var oauthToken *oauth2.Token
+
+		switch {
+		case clientConfig.SupportedGrantTypes.Has(disco.OAuthAuthzCodeGrant):
+			// We prefer an OAuth code grant if the server supports it.
+			oauthToken, tokenDiags = c.interactiveGetTokenByCode(hostname, credsCtx, clientConfig)
+		case clientConfig.SupportedGrantTypes.Has(disco.OAuthOwnerPasswordGrant) && hostname == svchost.Hostname("app.terraform.io"):
+			// The password grant type is allowed only for Terraform Cloud SaaS.
+			// Note this case is purely theoretical at this point, as TFC currently uses
+			// its own bespoke login protocol (tfe)
+			oauthToken, tokenDiags = c.interactiveGetTokenByPassword(hostname, credsCtx, clientConfig)
+		default:
+			tokenDiags = tokenDiags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Host does not support Terraform login",
+				fmt.Sprintf("The given hostname %q does not allow any OAuth grant types that are supported by this version of Terraform.", dispHostname),
+			))
+		}
+		if oauthToken != nil {
+			token = svcauth.HostCredentialsToken(oauthToken.AccessToken)
+		}
+	} else if tfeservice != nil {
+		token, tokenDiags = c.interactiveGetTokenByUI(hostname, credsCtx, tfeservice)
+	}
+
+	diags = diags.Append(tokenDiags)
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	err = creds.StoreForHost(hostname, token)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to save API token",
+			fmt.Sprintf("The given host returned an API token, but Terraform failed to save it: %s.", err),
+		))
+	}
+
+	c.showDiagnostics(diags)
+	if diags.HasErrors() {
+		return 1
+	}
+
+	c.Ui.Output("\n---------------------------------------------------------------------------------\n")
+	if hostname == "app.terraform.io" { // Terraform Cloud
+		var motd struct {
+			Message string        `json:"msg"`
+			Errors  []interface{} `json:"errors"`
+		}
+
+		// Throughout the entire process of fetching a MOTD from TFC, use a default
+		// message if the platform-provided message is unavailable for any reason -
+		// be it the service isn't provided, the request failed, or any sort of
+		// platform error returned.
+
+		motdServiceURL, err := host.ServiceURL("motd.v1")
+		if err != nil {
+			c.logMOTDError(err)
+			c.outputDefaultTFCLoginSuccess()
+			return 0
+		}
+
+		req, err := http.NewRequest("GET", motdServiceURL.String(), nil)
+		if err != nil {
+			c.logMOTDError(err)
+			c.outputDefaultTFCLoginSuccess()
+			return 0
+		}
+
+		req.Header.Set("Authorization", "Bearer "+token.Token())
+
+		resp, err := httpclient.New().Do(req)
+		if err != nil {
+			c.logMOTDError(err)
+			c.outputDefaultTFCLoginSuccess()
+			return 0
+		}
+
+		body, err := ioutil.ReadAll(resp.Body)
+		if err != nil {
+			c.logMOTDError(err)
+			c.outputDefaultTFCLoginSuccess()
+			return 0
+		}
+
+		defer resp.Body.Close()
+		json.Unmarshal(body, &motd)
+
+		if motd.Errors == nil && motd.Message != "" {
+			c.Ui.Output(
+				c.Colorize().Color(motd.Message),
+			)
+			return 0
+		} else {
+			c.logMOTDError(fmt.Errorf("platform responded with errors or an empty message"))
+			c.outputDefaultTFCLoginSuccess()
+			return 0
+		}
+	}
+
+	if tfeservice != nil { // Terraform Enterprise
+		c.outputDefaultTFELoginSuccess(dispHostname)
+	} else {
+		c.Ui.Output(
+			fmt.Sprintf(
+				c.Colorize().Color(strings.TrimSpace(`
+[green][bold]Success![reset] [bold]Terraform has obtained and saved an API token.[reset]
+
+The new API token will be used for any future Terraform command that must make
+authenticated requests to %s.
+`)),
+				dispHostname,
+			) + "\n",
+		)
+	}
+
+	return 0
+}
+
+func (c *LoginCommand) outputDefaultTFELoginSuccess(dispHostname string) {
+	c.Ui.Output(
+		fmt.Sprintf(
+			c.Colorize().Color(strings.TrimSpace(`
+[green][bold]Success![reset] [bold]Logged in to Terraform Enterprise (%s)[reset]
+`)),
+			dispHostname,
+		) + "\n",
+	)
+}
+
+func (c *LoginCommand) outputDefaultTFCLoginSuccess() {
+	c.Ui.Output(c.Colorize().Color(strings.TrimSpace(`
+[green][bold]Success![reset] [bold]Logged in to Terraform Cloud[reset]
+` + "\n")))
+}
+
+func (c *LoginCommand) logMOTDError(err error) {
+	log.Printf("[TRACE] login: An error occurred attempting to fetch a message of the day for Terraform Cloud: %s", err)
+}
+
+// Help implements cli.Command.
+func (c *LoginCommand) Help() string {
+	defaultFile := c.defaultOutputFile()
+	if defaultFile == "" {
+		// Because this is just for the help message and it's very unlikely
+		// that a user wouldn't have a functioning home directory anyway,
+		// we'll just use a placeholder here. The real command has some
+		// more complex behavior for this case. This result is not correct
+		// on all platforms, but given how unlikely we are to hit this case
+		// that seems okay.
+		defaultFile = "~/.terraform/credentials.tfrc.json"
+	}
+
+	helpText := fmt.Sprintf(`
+Usage: terraform [global options] login [hostname]
+
+  Retrieves an authentication token for the given hostname, if it supports
+  automatic login, and saves it in a credentials file in your home directory.
+
+  If no hostname is provided, the default hostname is app.terraform.io, to
+  log in to Terraform Cloud.
+
+  If not overridden by credentials helper settings in the CLI configuration,
+  the credentials will be written to the following local file:
+      %s
+`, defaultFile)
+	return strings.TrimSpace(helpText)
+}
+
+// Synopsis implements cli.Command.
+func (c *LoginCommand) Synopsis() string {
+	return "Obtain and save credentials for a remote host"
+}
+
+func (c *LoginCommand) defaultOutputFile() string {
+	if c.CLIConfigDir == "" {
+		return "" // no default available
+	}
+	return filepath.Join(c.CLIConfigDir, "credentials.tfrc.json")
+}
+
+func (c *LoginCommand) interactiveGetTokenByCode(hostname svchost.Hostname, credsCtx *loginCredentialsContext, clientConfig *disco.OAuthClient) (*oauth2.Token, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	confirm, confirmDiags := c.interactiveContextConsent(hostname, disco.OAuthAuthzCodeGrant, credsCtx)
+	diags = diags.Append(confirmDiags)
+	if !confirm {
+		diags = diags.Append(errors.New("Login cancelled"))
+		return nil, diags
+	}
+
+	// We'll use an entirely pseudo-random UUID for our temporary request
+	// state. The OAuth server must echo this back to us in the callback
+	// request to make it difficult for some other running process to
+	// interfere by sending its own request to our temporary server.
+	reqState, err := uuid.GenerateUUID()
+	if err != nil {
+		// This should be very unlikely, but could potentially occur if e.g.
+		// there's not enough pseudo-random entropy available.
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Can't generate login request state",
+			fmt.Sprintf("Cannot generate random request identifier for login request: %s.", err),
+		))
+		return nil, diags
+	}
+
+	proofKey, proofKeyChallenge, err := c.proofKey()
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Can't generate login request state",
+			fmt.Sprintf("Cannot generate random prrof key for login request: %s.", err),
+		))
+		return nil, diags
+	}
+
+	listener, callbackURL, err := c.listenerForCallback(clientConfig.MinPort, clientConfig.MaxPort)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Can't start temporary login server",
+			fmt.Sprintf(
+				"The login process uses OAuth, which requires starting a temporary HTTP server on localhost. However, no TCP port numbers between %d and %d are available to create such a server.",
+				clientConfig.MinPort, clientConfig.MaxPort,
+			),
+		))
+		return nil, diags
+	}
+
+	// codeCh will allow our temporary HTTP server to transmit the OAuth code
+	// to the main execution path that follows.
+	codeCh := make(chan string)
+	server := &http.Server{
+		Handler: http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
+			log.Printf("[TRACE] login: request to callback server")
+			err := req.ParseForm()
+			if err != nil {
+				log.Printf("[ERROR] login: cannot ParseForm on callback request: %s", err)
+				resp.WriteHeader(400)
+				return
+			}
+			gotState := req.Form.Get("state")
+			if gotState != reqState {
+				log.Printf("[ERROR] login: incorrect \"state\" value in callback request")
+				resp.WriteHeader(400)
+				return
+			}
+			gotCode := req.Form.Get("code")
+			if gotCode == "" {
+				log.Printf("[ERROR] login: no \"code\" argument in callback request")
+				resp.WriteHeader(400)
+				return
+			}
+
+			log.Printf("[TRACE] login: request contains an authorization code")
+
+			// Send the code to our blocking wait below, so that the token
+			// fetching process can continue.
+			codeCh <- gotCode
+			close(codeCh)
+
+			log.Printf("[TRACE] login: returning response from callback server")
+
+			resp.Header().Add("Content-Type", "text/html")
+			resp.WriteHeader(200)
+			resp.Write([]byte(callbackSuccessMessage))
+		}),
+	}
+	go func() {
+		defer logging.PanicHandler()
+		err := server.Serve(listener)
+		if err != nil && err != http.ErrServerClosed {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Can't start temporary login server",
+				fmt.Sprintf(
+					"The login process uses OAuth, which requires starting a temporary HTTP server on localhost. However, no TCP port numbers between %d and %d are available to create such a server.",
+					clientConfig.MinPort, clientConfig.MaxPort,
+				),
+			))
+			close(codeCh)
+		}
+	}()
+
+	oauthConfig := &oauth2.Config{
+		ClientID:    clientConfig.ID,
+		Endpoint:    clientConfig.Endpoint(),
+		RedirectURL: callbackURL,
+		Scopes:      clientConfig.Scopes,
+	}
+
+	authCodeURL := oauthConfig.AuthCodeURL(
+		reqState,
+		oauth2.SetAuthURLParam("code_challenge", proofKeyChallenge),
+		oauth2.SetAuthURLParam("code_challenge_method", "S256"),
+	)
+
+	launchBrowserManually := false
+	if c.BrowserLauncher != nil {
+		err = c.BrowserLauncher.OpenURL(authCodeURL)
+		if err == nil {
+			c.Ui.Output(fmt.Sprintf("Terraform must now open a web browser to the login page for %s.\n", hostname.ForDisplay()))
+			c.Ui.Output(fmt.Sprintf("If a browser does not open this automatically, open the following URL to proceed:\n    %s\n", authCodeURL))
+		} else {
+			// Assume we're on a platform where opening a browser isn't possible.
+			launchBrowserManually = true
+		}
+	} else {
+		launchBrowserManually = true
+	}
+
+	if launchBrowserManually {
+		c.Ui.Output(fmt.Sprintf("Open the following URL to access the login page for %s:\n    %s\n", hostname.ForDisplay(), authCodeURL))
+	}
+
+	c.Ui.Output("Terraform will now wait for the host to signal that login was successful.\n")
+
+	code, ok := <-codeCh
+	if !ok {
+		// If we got no code at all then the server wasn't able to start
+		// up, so we'll just give up.
+		return nil, diags
+	}
+
+	if err := server.Close(); err != nil {
+		// The server will close soon enough when our process exits anyway,
+		// so we won't fuss about it for right now.
+		log.Printf("[WARN] login: callback server can't shut down: %s", err)
+	}
+
+	ctx := context.WithValue(context.Background(), oauth2.HTTPClient, httpclient.New())
+	token, err := oauthConfig.Exchange(
+		ctx, code,
+		oauth2.SetAuthURLParam("code_verifier", proofKey),
+	)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to obtain auth token",
+			fmt.Sprintf("The remote server did not assign an auth token: %s.", err),
+		))
+		return nil, diags
+	}
+
+	return token, diags
+}
+
+func (c *LoginCommand) interactiveGetTokenByPassword(hostname svchost.Hostname, credsCtx *loginCredentialsContext, clientConfig *disco.OAuthClient) (*oauth2.Token, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	confirm, confirmDiags := c.interactiveContextConsent(hostname, disco.OAuthOwnerPasswordGrant, credsCtx)
+	diags = diags.Append(confirmDiags)
+	if !confirm {
+		diags = diags.Append(errors.New("Login cancelled"))
+		return nil, diags
+	}
+
+	c.Ui.Output("\n---------------------------------------------------------------------------------\n")
+	c.Ui.Output("Terraform must temporarily use your password to request an API token.\nThis password will NOT be saved locally.\n")
+
+	username, err := c.UIInput().Input(context.Background(), &terraform.InputOpts{
+		Id:    "username",
+		Query: fmt.Sprintf("Username for %s:", hostname.ForDisplay()),
+	})
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Failed to request username: %s", err))
+		return nil, diags
+	}
+	password, err := c.UIInput().Input(context.Background(), &terraform.InputOpts{
+		Id:     "password",
+		Query:  fmt.Sprintf("Password for %s:", hostname.ForDisplay()),
+		Secret: true,
+	})
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Failed to request password: %s", err))
+		return nil, diags
+	}
+
+	oauthConfig := &oauth2.Config{
+		ClientID: clientConfig.ID,
+		Endpoint: clientConfig.Endpoint(),
+		Scopes:   clientConfig.Scopes,
+	}
+	token, err := oauthConfig.PasswordCredentialsToken(context.Background(), username, password)
+	if err != nil {
+		// FIXME: The OAuth2 library generates errors that are not appropriate
+		// for a Terraform end-user audience, so once we have more experience
+		// with which errors are most common we should try to recognize them
+		// here and produce better error messages for them.
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to retrieve API token",
+			fmt.Sprintf("The remote host did not issue an API token: %s.", err),
+		))
+	}
+
+	return token, diags
+}
+
+func (c *LoginCommand) interactiveGetTokenByUI(hostname svchost.Hostname, credsCtx *loginCredentialsContext, service *url.URL) (svcauth.HostCredentialsToken, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	confirm, confirmDiags := c.interactiveContextConsent(hostname, disco.OAuthGrantType(""), credsCtx)
+	diags = diags.Append(confirmDiags)
+	if !confirm {
+		diags = diags.Append(errors.New("Login cancelled"))
+		return "", diags
+	}
+
+	c.Ui.Output("\n---------------------------------------------------------------------------------\n")
+
+	tokensURL := url.URL{
+		Scheme:   "https",
+		Host:     service.Hostname(),
+		Path:     "/app/settings/tokens",
+		RawQuery: "source=terraform-login",
+	}
+
+	launchBrowserManually := false
+	if c.BrowserLauncher != nil {
+		err := c.BrowserLauncher.OpenURL(tokensURL.String())
+		if err == nil {
+			c.Ui.Output(fmt.Sprintf("Terraform must now open a web browser to the tokens page for %s.\n", hostname.ForDisplay()))
+			c.Ui.Output(fmt.Sprintf("If a browser does not open this automatically, open the following URL to proceed:\n    %s\n", tokensURL.String()))
+		} else {
+			log.Printf("[DEBUG] error opening web browser: %s", err)
+			// Assume we're on a platform where opening a browser isn't possible.
+			launchBrowserManually = true
+		}
+	} else {
+		launchBrowserManually = true
+	}
+
+	if launchBrowserManually {
+		c.Ui.Output(fmt.Sprintf("Open the following URL to access the tokens page for %s:\n    %s\n", hostname.ForDisplay(), tokensURL.String()))
+	}
+
+	c.Ui.Output("\n---------------------------------------------------------------------------------\n")
+	c.Ui.Output("Generate a token using your browser, and copy-paste it into this prompt.\n")
+
+	// credsCtx might not be set if we're using a mock credentials source
+	// in a test, but it should always be set in normal use.
+	if credsCtx != nil {
+		switch credsCtx.Location {
+		case cliconfig.CredentialsViaHelper:
+			c.Ui.Output(fmt.Sprintf("Terraform will store the token in the configured %q credentials helper\nfor use by subsequent commands.\n", credsCtx.HelperType))
+		case cliconfig.CredentialsInPrimaryFile, cliconfig.CredentialsNotAvailable:
+			c.Ui.Output(fmt.Sprintf("Terraform will store the token in plain text in the following file\nfor use by subsequent commands:\n    %s\n", credsCtx.LocalFilename))
+		}
+	}
+
+	token, err := c.UIInput().Input(context.Background(), &terraform.InputOpts{
+		Id:     "token",
+		Query:  fmt.Sprintf("Token for %s:", hostname.ForDisplay()),
+		Secret: true,
+	})
+	if err != nil {
+		diags := diags.Append(fmt.Errorf("Failed to retrieve token: %s", err))
+		return "", diags
+	}
+
+	token = strings.TrimSpace(token)
+	cfg := &tfe.Config{
+		Address:  service.String(),
+		BasePath: service.Path,
+		Token:    token,
+		Headers:  make(http.Header),
+	}
+	client, err := tfe.NewClient(cfg)
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Failed to create API client: %s", err))
+		return "", diags
+	}
+	user, err := client.Users.ReadCurrent(context.Background())
+	if err == tfe.ErrUnauthorized {
+		diags = diags.Append(fmt.Errorf("Token is invalid: %s", err))
+		return "", diags
+	} else if err != nil {
+		diags = diags.Append(fmt.Errorf("Failed to retrieve user account details: %s", err))
+		return "", diags
+	}
+	c.Ui.Output(fmt.Sprintf(c.Colorize().Color("\nRetrieved token for user [bold]%s[reset]\n"), user.Username))
+
+	return svcauth.HostCredentialsToken(token), nil
+}
+
+func (c *LoginCommand) interactiveContextConsent(hostname svchost.Hostname, grantType disco.OAuthGrantType, credsCtx *loginCredentialsContext) (bool, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	mechanism := "OAuth"
+	if grantType == "" {
+		mechanism = "your browser"
+	}
+
+	c.Ui.Output(fmt.Sprintf("Terraform will request an API token for %s using %s.\n", hostname.ForDisplay(), mechanism))
+
+	if grantType.UsesAuthorizationEndpoint() {
+		c.Ui.Output(
+			"This will work only if you are able to use a web browser on this computer to\ncomplete a login process. If not, you must obtain an API token by another\nmeans and configure it in the CLI configuration manually.\n",
+		)
+	}
+
+	// credsCtx might not be set if we're using a mock credentials source
+	// in a test, but it should always be set in normal use.
+	if credsCtx != nil {
+		switch credsCtx.Location {
+		case cliconfig.CredentialsViaHelper:
+			c.Ui.Output(fmt.Sprintf("If login is successful, Terraform will store the token in the configured\n%q credentials helper for use by subsequent commands.\n", credsCtx.HelperType))
+		case cliconfig.CredentialsInPrimaryFile, cliconfig.CredentialsNotAvailable:
+			c.Ui.Output(fmt.Sprintf("If login is successful, Terraform will store the token in plain text in\nthe following file for use by subsequent commands:\n    %s\n", credsCtx.LocalFilename))
+		}
+	}
+
+	v, err := c.UIInput().Input(context.Background(), &terraform.InputOpts{
+		Id:          "approve",
+		Query:       "Do you want to proceed?",
+		Description: `Only 'yes' will be accepted to confirm.`,
+	})
+	if err != nil {
+		// Should not happen because this command checks that input is enabled
+		// before we get to this point.
+		diags = diags.Append(err)
+		return false, diags
+	}
+
+	return strings.ToLower(v) == "yes", diags
+}
+
+func (c *LoginCommand) listenerForCallback(minPort, maxPort uint16) (net.Listener, string, error) {
+	if minPort < 1024 || maxPort < 1024 {
+		// This should never happen because it should've been checked by
+		// the svchost/disco package when reading the service description,
+		// but we'll prefer to fail hard rather than inadvertently trying
+		// to open an unprivileged port if there are bugs at that layer.
+		panic("listenerForCallback called with privileged port number")
+	}
+
+	availCount := int(maxPort) - int(minPort)
+
+	// We're going to try port numbers within the range at random, so we need
+	// to terminate eventually in case _none_ of the ports are available.
+	// We'll make that 150% of the number of ports just to give us some room
+	// for the random number generator to generate the same port more than
+	// once.
+	// Note that we don't really care about true randomness here... we're just
+	// trying to hop around in the available port space rather than always
+	// working up from the lowest, because we have no information to predict
+	// that any particular number will be more likely to be available than
+	// another.
+	maxTries := availCount + (availCount / 2)
+
+	for tries := 0; tries < maxTries; tries++ {
+		port := rand.Intn(availCount) + int(minPort)
+		addr := fmt.Sprintf("127.0.0.1:%d", port)
+		log.Printf("[TRACE] login: trying %s as a listen address for temporary OAuth callback server", addr)
+		l, err := net.Listen("tcp4", addr)
+		if err == nil {
+			// We use a path that doesn't end in a slash here because some
+			// OAuth server implementations don't allow callback URLs to
+			// end with slashes.
+			callbackURL := fmt.Sprintf("http://localhost:%d/login", port)
+			log.Printf("[TRACE] login: callback URL will be %s", callbackURL)
+			return l, callbackURL, nil
+		}
+	}
+
+	return nil, "", fmt.Errorf("no suitable TCP ports (between %d and %d) are available for the temporary OAuth callback server", minPort, maxPort)
+}
+
+func (c *LoginCommand) proofKey() (key, challenge string, err error) {
+	// Wel use a UUID-like string as the "proof key for code exchange" (PKCE)
+	// that will eventually authenticate our request to the token endpoint.
+	// Standard UUIDs are explicitly not suitable as secrets according to the
+	// UUID spec, but our go-uuid just generates totally random number sequences
+	// formatted in the conventional UUID syntax, so that concern does not
+	// apply here: this is just a 128-bit crypto-random number.
+	uu, err := uuid.GenerateUUID()
+	if err != nil {
+		return "", "", err
+	}
+
+	key = fmt.Sprintf("%s.%09d", uu, rand.Intn(999999999))
+
+	h := sha256.New()
+	h.Write([]byte(key))
+	challenge = base64.RawURLEncoding.EncodeToString(h.Sum(nil))
+
+	return key, challenge, nil
+}
+
+type loginCredentialsContext struct {
+	Location      cliconfig.CredentialsLocation
+	LocalFilename string
+	HelperType    string
+}
+
+const callbackSuccessMessage = `
+<html>
+<head>
+<title>Terraform Login</title>
+<style type="text/css">
+body {
+	font-family: monospace;
+	color: #fff;
+	background-color: #000;
+}
+</style>
+</head>
+<body>
+
+<p>The login server has returned an authentication code to Terraform.</p>
+<p>Now close this page and return to the terminal where <tt>terraform login</tt>
+is running to see the result of the login process.</p>
+
+</body>
+</html>
+`
diff --git a/v1.5.7/internal/command/login_test.go b/v1.5.7/internal/command/login_test.go
new file mode 100644
index 0000000..2aefa32
--- /dev/null
+++ b/v1.5.7/internal/command/login_test.go
@@ -0,0 +1,293 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"context"
+	"net/http/httptest"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/mitchellh/cli"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/command/cliconfig"
+	oauthserver "github.com/hashicorp/terraform/internal/command/testdata/login-oauth-server"
+	tfeserver "github.com/hashicorp/terraform/internal/command/testdata/login-tfe-server"
+	"github.com/hashicorp/terraform/internal/command/webbrowser"
+	"github.com/hashicorp/terraform/internal/httpclient"
+	"github.com/hashicorp/terraform/version"
+)
+
+func TestLogin(t *testing.T) {
+	// oauthserver.Handler is a stub OAuth server implementation that will,
+	// on success, always issue a bearer token named "good-token".
+	s := httptest.NewServer(oauthserver.Handler)
+	defer s.Close()
+
+	// tfeserver.Handler is a stub TFE API implementation which will respond
+	// to ping and current account requests, when requests are authenticated
+	// with token "good-token"
+	ts := httptest.NewServer(tfeserver.Handler)
+	defer ts.Close()
+
+	loginTestCase := func(test func(t *testing.T, c *LoginCommand, ui *cli.MockUi)) func(t *testing.T) {
+		return func(t *testing.T) {
+			t.Helper()
+			workDir := t.TempDir()
+
+			// We'll use this context to avoid asynchronous tasks outliving
+			// a single test run.
+			ctx, cancel := context.WithCancel(context.Background())
+			defer cancel()
+
+			// Do not use the NewMockUi initializer here, as we want to delay
+			// the call to init until after setting up the input mocks
+			ui := new(cli.MockUi)
+
+			browserLauncher := webbrowser.NewMockLauncher(ctx)
+			creds := cliconfig.EmptyCredentialsSourceForTests(filepath.Join(workDir, "credentials.tfrc.json"))
+			svcs := disco.NewWithCredentialsSource(creds)
+			svcs.SetUserAgent(httpclient.TerraformUserAgent(version.String()))
+
+			svcs.ForceHostServices(svchost.Hostname("example.com"), map[string]interface{}{
+				"login.v1": map[string]interface{}{
+					// For this fake hostname we'll use a conventional OAuth flow,
+					// with browser-based consent that we'll mock away using a
+					// mock browser launcher below.
+					"client": "anything-goes",
+					"authz":  s.URL + "/authz",
+					"token":  s.URL + "/token",
+				},
+			})
+			svcs.ForceHostServices(svchost.Hostname("with-scopes.example.com"), map[string]interface{}{
+				"login.v1": map[string]interface{}{
+					// with scopes
+					// mock browser launcher below.
+					"client": "scopes_test",
+					"authz":  s.URL + "/authz",
+					"token":  s.URL + "/token",
+					"scopes": []interface{}{"app1.full_access", "app2.read_only"},
+				},
+			})
+			svcs.ForceHostServices(svchost.Hostname("app.terraform.io"), map[string]interface{}{
+				// This represents Terraform Cloud, which does not yet support the
+				// login API, but does support its own bespoke tokens API.
+				"tfe.v2":   ts.URL + "/api/v2",
+				"tfe.v2.1": ts.URL + "/api/v2",
+				"tfe.v2.2": ts.URL + "/api/v2",
+				"motd.v1":  ts.URL + "/api/terraform/motd",
+			})
+			svcs.ForceHostServices(svchost.Hostname("tfe.acme.com"), map[string]interface{}{
+				// This represents a Terraform Enterprise instance which does not
+				// yet support the login API, but does support its own bespoke tokens API.
+				"tfe.v2":   ts.URL + "/api/v2",
+				"tfe.v2.1": ts.URL + "/api/v2",
+				"tfe.v2.2": ts.URL + "/api/v2",
+			})
+			svcs.ForceHostServices(svchost.Hostname("unsupported.example.net"), map[string]interface{}{
+				// This host intentionally left blank.
+			})
+
+			c := &LoginCommand{
+				Meta: Meta{
+					Ui:              ui,
+					BrowserLauncher: browserLauncher,
+					Services:        svcs,
+				},
+			}
+
+			test(t, c, ui)
+		}
+	}
+
+	t.Run("app.terraform.io (no login support)", loginTestCase(func(t *testing.T, c *LoginCommand, ui *cli.MockUi) {
+		// Enter "yes" at the consent prompt, then paste a token with some
+		// accidental whitespace.
+		defer testInputMap(t, map[string]string{
+			"approve": "yes",
+			"token":   "  good-token ",
+		})()
+		status := c.Run([]string{"app.terraform.io"})
+		if status != 0 {
+			t.Fatalf("unexpected error code %d\nstderr:\n%s", status, ui.ErrorWriter.String())
+		}
+
+		credsSrc := c.Services.CredentialsSource()
+		creds, err := credsSrc.ForHost(svchost.Hostname("app.terraform.io"))
+		if err != nil {
+			t.Errorf("failed to retrieve credentials: %s", err)
+		}
+		if got, want := creds.Token(), "good-token"; got != want {
+			t.Errorf("wrong token %q; want %q", got, want)
+		}
+		if got, want := ui.OutputWriter.String(), "Welcome to Terraform Cloud!"; !strings.Contains(got, want) {
+			t.Errorf("expected output to contain %q, but was:\n%s", want, got)
+		}
+	}))
+
+	t.Run("example.com with authorization code flow", loginTestCase(func(t *testing.T, c *LoginCommand, ui *cli.MockUi) {
+		// Enter "yes" at the consent prompt.
+		defer testInputMap(t, map[string]string{
+			"approve": "yes",
+		})()
+		status := c.Run([]string{"example.com"})
+		if status != 0 {
+			t.Fatalf("unexpected error code %d\nstderr:\n%s", status, ui.ErrorWriter.String())
+		}
+
+		credsSrc := c.Services.CredentialsSource()
+		creds, err := credsSrc.ForHost(svchost.Hostname("example.com"))
+		if err != nil {
+			t.Errorf("failed to retrieve credentials: %s", err)
+		}
+		if got, want := creds.Token(), "good-token"; got != want {
+			t.Errorf("wrong token %q; want %q", got, want)
+		}
+
+		if got, want := ui.OutputWriter.String(), "Terraform has obtained and saved an API token."; !strings.Contains(got, want) {
+			t.Errorf("expected output to contain %q, but was:\n%s", want, got)
+		}
+	}))
+
+	t.Run("example.com results in no scopes", loginTestCase(func(t *testing.T, c *LoginCommand, ui *cli.MockUi) {
+
+		host, _ := c.Services.Discover("example.com")
+		client, _ := host.ServiceOAuthClient("login.v1")
+		if len(client.Scopes) != 0 {
+			t.Errorf("unexpected scopes %q; expected none", client.Scopes)
+		}
+	}))
+
+	t.Run("with-scopes.example.com with authorization code flow and scopes", loginTestCase(func(t *testing.T, c *LoginCommand, ui *cli.MockUi) {
+		// Enter "yes" at the consent prompt.
+		defer testInputMap(t, map[string]string{
+			"approve": "yes",
+		})()
+		status := c.Run([]string{"with-scopes.example.com"})
+		if status != 0 {
+			t.Fatalf("unexpected error code %d\nstderr:\n%s", status, ui.ErrorWriter.String())
+		}
+
+		credsSrc := c.Services.CredentialsSource()
+		creds, err := credsSrc.ForHost(svchost.Hostname("with-scopes.example.com"))
+
+		if err != nil {
+			t.Errorf("failed to retrieve credentials: %s", err)
+		}
+
+		if got, want := creds.Token(), "good-token"; got != want {
+			t.Errorf("wrong token %q; want %q", got, want)
+		}
+
+		if got, want := ui.OutputWriter.String(), "Terraform has obtained and saved an API token."; !strings.Contains(got, want) {
+			t.Errorf("expected output to contain %q, but was:\n%s", want, got)
+		}
+	}))
+
+	t.Run("with-scopes.example.com results in expected scopes", loginTestCase(func(t *testing.T, c *LoginCommand, ui *cli.MockUi) {
+
+		host, _ := c.Services.Discover("with-scopes.example.com")
+		client, _ := host.ServiceOAuthClient("login.v1")
+
+		expectedScopes := [2]string{"app1.full_access", "app2.read_only"}
+
+		var foundScopes [2]string
+		copy(foundScopes[:], client.Scopes)
+
+		if foundScopes != expectedScopes || len(client.Scopes) != len(expectedScopes) {
+			t.Errorf("unexpected scopes %q; want %q", client.Scopes, expectedScopes)
+		}
+	}))
+
+	t.Run("TFE host without login support", loginTestCase(func(t *testing.T, c *LoginCommand, ui *cli.MockUi) {
+		// Enter "yes" at the consent prompt, then paste a token with some
+		// accidental whitespace.
+		defer testInputMap(t, map[string]string{
+			"approve": "yes",
+			"token":   "  good-token ",
+		})()
+		status := c.Run([]string{"tfe.acme.com"})
+		if status != 0 {
+			t.Fatalf("unexpected error code %d\nstderr:\n%s", status, ui.ErrorWriter.String())
+		}
+
+		credsSrc := c.Services.CredentialsSource()
+		creds, err := credsSrc.ForHost(svchost.Hostname("tfe.acme.com"))
+		if err != nil {
+			t.Errorf("failed to retrieve credentials: %s", err)
+		}
+		if got, want := creds.Token(), "good-token"; got != want {
+			t.Errorf("wrong token %q; want %q", got, want)
+		}
+
+		if got, want := ui.OutputWriter.String(), "Logged in to Terraform Enterprise"; !strings.Contains(got, want) {
+			t.Errorf("expected output to contain %q, but was:\n%s", want, got)
+		}
+	}))
+
+	t.Run("TFE host without login support, incorrectly pasted token", loginTestCase(func(t *testing.T, c *LoginCommand, ui *cli.MockUi) {
+		// Enter "yes" at the consent prompt, then paste an invalid token.
+		defer testInputMap(t, map[string]string{
+			"approve": "yes",
+			"token":   "good-tok",
+		})()
+		status := c.Run([]string{"tfe.acme.com"})
+		if status != 1 {
+			t.Fatalf("unexpected error code %d\nstderr:\n%s", status, ui.ErrorWriter.String())
+		}
+
+		credsSrc := c.Services.CredentialsSource()
+		creds, err := credsSrc.ForHost(svchost.Hostname("tfe.acme.com"))
+		if err != nil {
+			t.Errorf("failed to retrieve credentials: %s", err)
+		}
+		if creds != nil {
+			t.Errorf("wrong token %q; should have no token", creds.Token())
+		}
+	}))
+
+	t.Run("host without login or TFE API support", loginTestCase(func(t *testing.T, c *LoginCommand, ui *cli.MockUi) {
+		status := c.Run([]string{"unsupported.example.net"})
+		if status == 0 {
+			t.Fatalf("successful exit; want error")
+		}
+
+		if got, want := ui.ErrorWriter.String(), "Error: Host does not support Terraform tokens API"; !strings.Contains(got, want) {
+			t.Fatalf("missing expected error message\nwant: %s\nfull output:\n%s", want, got)
+		}
+	}))
+
+	t.Run("answering no cancels", loginTestCase(func(t *testing.T, c *LoginCommand, ui *cli.MockUi) {
+		// Enter "no" at the consent prompt
+		defer testInputMap(t, map[string]string{
+			"approve": "no",
+		})()
+		status := c.Run(nil)
+		if status != 1 {
+			t.Fatalf("unexpected error code %d\nstderr:\n%s", status, ui.ErrorWriter.String())
+		}
+
+		if got, want := ui.ErrorWriter.String(), "Login cancelled"; !strings.Contains(got, want) {
+			t.Fatalf("missing expected error message\nwant: %s\nfull output:\n%s", want, got)
+		}
+	}))
+
+	t.Run("answering y cancels", loginTestCase(func(t *testing.T, c *LoginCommand, ui *cli.MockUi) {
+		// Enter "y" at the consent prompt
+		defer testInputMap(t, map[string]string{
+			"approve": "y",
+		})()
+		status := c.Run(nil)
+		if status != 1 {
+			t.Fatalf("unexpected error code %d\nstderr:\n%s", status, ui.ErrorWriter.String())
+		}
+
+		if got, want := ui.ErrorWriter.String(), "Login cancelled"; !strings.Contains(got, want) {
+			t.Fatalf("missing expected error message\nwant: %s\nfull output:\n%s", want, got)
+		}
+	}))
+}
diff --git a/v1.5.7/internal/command/logout.go b/v1.5.7/internal/command/logout.go
new file mode 100644
index 0000000..43f9167
--- /dev/null
+++ b/v1.5.7/internal/command/logout.go
@@ -0,0 +1,157 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"path/filepath"
+	"strings"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform/internal/command/cliconfig"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// LogoutCommand is a Command implementation which removes stored credentials
+// for a remote service host.
+type LogoutCommand struct {
+	Meta
+}
+
+// Run implements cli.Command.
+func (c *LogoutCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	cmdFlags := c.Meta.defaultFlagSet("logout")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		return 1
+	}
+
+	args = cmdFlags.Args()
+	if len(args) > 1 {
+		c.Ui.Error(
+			"The logout command expects at most one argument: the host to log out of.")
+		cmdFlags.Usage()
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	givenHostname := "app.terraform.io"
+	if len(args) != 0 {
+		givenHostname = args[0]
+	}
+
+	hostname, err := svchost.ForComparison(givenHostname)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid hostname",
+			fmt.Sprintf("The given hostname %q is not valid: %s.", givenHostname, err.Error()),
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// From now on, since we've validated the given hostname, we should use
+	// dispHostname in the UI to ensure we're presenting it in the canonical
+	// form, in case that helps users with debugging when things aren't
+	// working as expected. (Perhaps the normalization is part of the cause.)
+	dispHostname := hostname.ForDisplay()
+
+	creds := c.Services.CredentialsSource().(*cliconfig.CredentialsSource)
+	filename, _ := creds.CredentialsFilePath()
+	credsCtx := &loginCredentialsContext{
+		Location:      creds.HostCredentialsLocation(hostname),
+		LocalFilename: filename, // empty in the very unlikely event that we can't select a config directory for this user
+		HelperType:    creds.CredentialsHelperType(),
+	}
+
+	if credsCtx.Location == cliconfig.CredentialsInOtherFile {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			fmt.Sprintf("Credentials for %s are manually configured", dispHostname),
+			"The \"terraform logout\" command cannot log out because credentials for this host are manually configured in a CLI configuration file.\n\nTo log out, revoke the existing credentials and remove that block from the CLI configuration.",
+		))
+	}
+
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	switch credsCtx.Location {
+	case cliconfig.CredentialsNotAvailable:
+		c.Ui.Output(fmt.Sprintf("No credentials for %s are stored.\n", dispHostname))
+		return 0
+	case cliconfig.CredentialsViaHelper:
+		c.Ui.Output(fmt.Sprintf("Removing the stored credentials for %s from the configured\n%q credentials helper.\n", dispHostname, credsCtx.HelperType))
+	case cliconfig.CredentialsInPrimaryFile:
+		c.Ui.Output(fmt.Sprintf("Removing the stored credentials for %s from the following file:\n    %s\n", dispHostname, credsCtx.LocalFilename))
+	}
+
+	err = creds.ForgetForHost(hostname)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to remove API token",
+			fmt.Sprintf("Unable to remove stored API token: %s", err),
+		))
+	}
+
+	c.showDiagnostics(diags)
+	if diags.HasErrors() {
+		return 1
+	}
+
+	c.Ui.Output(
+		fmt.Sprintf(
+			c.Colorize().Color(strings.TrimSpace(`
+[green][bold]Success![reset] [bold]Terraform has removed the stored API token for %s.[reset]
+`)),
+			dispHostname,
+		) + "\n",
+	)
+
+	return 0
+}
+
+// Help implements cli.Command.
+func (c *LogoutCommand) Help() string {
+	defaultFile := c.defaultOutputFile()
+	if defaultFile == "" {
+		// Because this is just for the help message and it's very unlikely
+		// that a user wouldn't have a functioning home directory anyway,
+		// we'll just use a placeholder here. The real command has some
+		// more complex behavior for this case. This result is not correct
+		// on all platforms, but given how unlikely we are to hit this case
+		// that seems okay.
+		defaultFile = "~/.terraform/credentials.tfrc.json"
+	}
+
+	helpText := `
+Usage: terraform [global options] logout [hostname]
+
+  Removes locally-stored credentials for specified hostname.
+
+  Note: the API token is only removed from local storage, not destroyed on the
+  remote server, so it will remain valid until manually revoked.
+
+  If no hostname is provided, the default hostname is app.terraform.io.
+      %s
+`
+	return strings.TrimSpace(helpText)
+}
+
+// Synopsis implements cli.Command.
+func (c *LogoutCommand) Synopsis() string {
+	return "Remove locally-stored credentials for a remote host"
+}
+
+func (c *LogoutCommand) defaultOutputFile() string {
+	if c.CLIConfigDir == "" {
+		return "" // no default available
+	}
+	return filepath.Join(c.CLIConfigDir, "credentials.tfrc.json")
+}
diff --git a/v1.5.7/internal/command/logout_test.go b/v1.5.7/internal/command/logout_test.go
new file mode 100644
index 0000000..d5c8339
--- /dev/null
+++ b/v1.5.7/internal/command/logout_test.go
@@ -0,0 +1,78 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"path/filepath"
+	"testing"
+
+	"github.com/mitchellh/cli"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+	svcauth "github.com/hashicorp/terraform-svchost/auth"
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/command/cliconfig"
+)
+
+func TestLogout(t *testing.T) {
+	workDir := t.TempDir()
+
+	ui := cli.NewMockUi()
+	credsSrc := cliconfig.EmptyCredentialsSourceForTests(filepath.Join(workDir, "credentials.tfrc.json"))
+
+	c := &LogoutCommand{
+		Meta: Meta{
+			Ui:       ui,
+			Services: disco.NewWithCredentialsSource(credsSrc),
+		},
+	}
+
+	testCases := []struct {
+		// Hostname to associate a pre-stored token
+		hostname string
+		// Command-line arguments
+		args []string
+		// true iff the token at hostname should be removed by the command
+		shouldRemove bool
+	}{
+		// If no command-line arguments given, should remove app.terraform.io token
+		{"app.terraform.io", []string{}, true},
+
+		// Can still specify app.terraform.io explicitly
+		{"app.terraform.io", []string{"app.terraform.io"}, true},
+
+		// Can remove tokens for other hostnames
+		{"tfe.example.com", []string{"tfe.example.com"}, true},
+
+		// Logout does not remove tokens for other hostnames
+		{"tfe.example.com", []string{"other-tfe.acme.com"}, false},
+	}
+	for _, tc := range testCases {
+		host := svchost.Hostname(tc.hostname)
+		token := svcauth.HostCredentialsToken("some-token")
+		err := credsSrc.StoreForHost(host, token)
+		if err != nil {
+			t.Fatalf("unexpected error storing credentials: %s", err)
+		}
+
+		status := c.Run(tc.args)
+		if status != 0 {
+			t.Fatalf("unexpected error code %d\nstderr:\n%s", status, ui.ErrorWriter.String())
+		}
+
+		creds, err := credsSrc.ForHost(host)
+		if err != nil {
+			t.Errorf("failed to retrieve credentials: %s", err)
+		}
+		if tc.shouldRemove {
+			if creds != nil {
+				t.Errorf("wrong token %q; should have no token", creds.Token())
+			}
+		} else {
+			if got, want := creds.Token(), "some-token"; got != want {
+				t.Errorf("wrong token %q; want %q", got, want)
+			}
+		}
+	}
+}
diff --git a/v1.5.7/internal/command/meta.go b/v1.5.7/internal/command/meta.go
new file mode 100644
index 0000000..0d69a5d
--- /dev/null
+++ b/v1.5.7/internal/command/meta.go
@@ -0,0 +1,847 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"context"
+	"errors"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"time"
+
+	plugin "github.com/hashicorp/go-plugin"
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/mitchellh/cli"
+	"github.com/mitchellh/colorstring"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/backend/local"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/format"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/command/webbrowser"
+	"github.com/hashicorp/terraform/internal/command/workdir"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	legacy "github.com/hashicorp/terraform/internal/legacy/terraform"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Meta are the meta-options that are available on all or most commands.
+type Meta struct {
+	// The exported fields below should be set by anyone using a
+	// command with a Meta field. These are expected to be set externally
+	// (not from within the command itself).
+
+	// WorkingDir is an object representing the "working directory" where we're
+	// running commands. In the normal case this literally refers to the
+	// working directory of the Terraform process, though this can take on
+	// a more symbolic meaning when the user has overridden default behavior
+	// to specify a different working directory or to override the special
+	// data directory where we'll persist settings that must survive between
+	// consecutive commands.
+	//
+	// We're currently gradually migrating the various bits of state that
+	// must persist between consecutive commands in a session to be encapsulated
+	// in here, but we're not there yet and so there are also some methods on
+	// Meta which directly read and modify paths inside the data directory.
+	WorkingDir *workdir.Dir
+
+	// Streams tracks the raw Stdout, Stderr, and Stdin handles along with
+	// some basic metadata about them, such as whether each is connected to
+	// a terminal, how wide the possible terminal is, etc.
+	//
+	// For historical reasons this might not be set in unit test code, and
+	// so functions working with this field must check if it's nil and
+	// do some default behavior instead if so, rather than panicking.
+	Streams *terminal.Streams
+
+	View *views.View
+
+	Color            bool     // True if output should be colored
+	GlobalPluginDirs []string // Additional paths to search for plugins
+	Ui               cli.Ui   // Ui for output
+
+	// Services provides access to remote endpoint information for
+	// "terraform-native' services running at a specific user-facing hostname.
+	Services *disco.Disco
+
+	// RunningInAutomation indicates that commands are being run by an
+	// automated system rather than directly at a command prompt.
+	//
+	// This is a hint to various command routines that it may be confusing
+	// to print out messages that suggest running specific follow-up
+	// commands, since the user consuming the output will not be
+	// in a position to run such commands.
+	//
+	// The intended use-case of this flag is when Terraform is running in
+	// some sort of workflow orchestration tool which is abstracting away
+	// the specific commands being run.
+	RunningInAutomation bool
+
+	// CLIConfigDir is the directory from which CLI configuration files were
+	// read by the caller and the directory where any changes to CLI
+	// configuration files by commands should be made.
+	//
+	// If this is empty then no configuration directory is available and
+	// commands which require one cannot proceed.
+	CLIConfigDir string
+
+	// PluginCacheDir, if non-empty, enables caching of downloaded plugins
+	// into the given directory.
+	PluginCacheDir string
+
+	// PluginCacheMayBreakDependencyLockFile is a temporary CLI configuration-based
+	// opt out for the behavior of only using the plugin cache dir if its
+	// contents match checksums recorded in the dependency lock file.
+	//
+	// This is an accommodation for those who currently essentially ignore the
+	// dependency lock file -- treating it only as transient working directory
+	// state -- and therefore don't care if the plugin cache dir causes the
+	// checksums inside to only be sufficient for the computer where Terraform
+	// is currently running.
+	//
+	// We intend to remove this exception again (making the CLI configuration
+	// setting a silent no-op) in future once we've improved the dependency
+	// lock file mechanism so that it's usable for everyone and there are no
+	// longer any compelling reasons for folks to not lock their dependencies.
+	PluginCacheMayBreakDependencyLockFile bool
+
+	// ProviderSource allows determining the available versions of a provider
+	// and determines where a distribution package for a particular
+	// provider version can be obtained.
+	ProviderSource getproviders.Source
+
+	// BrowserLauncher is used by commands that need to open a URL in a
+	// web browser.
+	BrowserLauncher webbrowser.Launcher
+
+	// When this channel is closed, the command will be cancelled.
+	ShutdownCh <-chan struct{}
+
+	// ProviderDevOverrides are providers where we ignore the lock file, the
+	// configured version constraints, and the local cache directory and just
+	// always use exactly the path specified. This is intended to allow
+	// provider developers to easily test local builds without worrying about
+	// what version number they might eventually be released as, or what
+	// checksums they have.
+	ProviderDevOverrides map[addrs.Provider]getproviders.PackageLocalDir
+
+	// UnmanagedProviders are a set of providers that exist as processes
+	// predating Terraform, which Terraform should use but not worry about the
+	// lifecycle of.
+	//
+	// This is essentially a more extreme version of ProviderDevOverrides where
+	// Terraform doesn't even worry about how the provider server gets launched,
+	// just trusting that someone else did it before running Terraform.
+	UnmanagedProviders map[addrs.Provider]*plugin.ReattachConfig
+
+	// AllowExperimentalFeatures controls whether a command that embeds this
+	// Meta is permitted to make use of experimental Terraform features.
+	//
+	// Set this field only during the initial creation of Meta. If you change
+	// this field after calling methods of type Meta then the resulting
+	// behavior is undefined.
+	//
+	// In normal code this would be set by package main only in builds
+	// explicitly marked as being alpha releases or development snapshots,
+	// making experimental features unavailable otherwise. Test code may
+	// choose to set this if it needs to exercise experimental features.
+	//
+	// Some experiments predated the addition of this setting, and may
+	// therefore still be available even if this flag is false. Our intent
+	// is that all/most _future_ experiments will be unavailable unless this
+	// flag is set, to reinforce that experiments are not for production use.
+	AllowExperimentalFeatures bool
+
+	//----------------------------------------------------------
+	// Protected: commands can set these
+	//----------------------------------------------------------
+
+	// pluginPath is a user defined set of directories to look for plugins.
+	// This is set during init with the `-plugin-dir` flag, saved to a file in
+	// the data directory.
+	// This overrides all other search paths when discovering plugins.
+	pluginPath []string
+
+	// Override certain behavior for tests within this package
+	testingOverrides *testingOverrides
+
+	//----------------------------------------------------------
+	// Private: do not set these
+	//----------------------------------------------------------
+
+	// configLoader is a shared configuration loader that is used by
+	// LoadConfig and other commands that access configuration files.
+	// It is initialized on first use.
+	configLoader *configload.Loader
+
+	// backendState is the currently active backend state
+	backendState *legacy.BackendState
+
+	// Variables for the context (private)
+	variableArgs rawFlags
+	input        bool
+
+	// Targets for this context (private)
+	targets     []addrs.Targetable
+	targetFlags []string
+
+	// Internal fields
+	color bool
+	oldUi cli.Ui
+
+	// The fields below are expected to be set by the command via
+	// command line flags. See the Apply command for an example.
+	//
+	// statePath is the path to the state file. If this is empty, then
+	// no state will be loaded. It is also okay for this to be a path to
+	// a file that doesn't exist; it is assumed that this means that there
+	// is simply no state.
+	//
+	// stateOutPath is used to override the output path for the state.
+	// If not provided, the StatePath is used causing the old state to
+	// be overridden.
+	//
+	// backupPath is used to backup the state file before writing a modified
+	// version. It defaults to stateOutPath + DefaultBackupExtension
+	//
+	// parallelism is used to control the number of concurrent operations
+	// allowed when walking the graph
+	//
+	// provider is to specify specific resource providers
+	//
+	// stateLock is set to false to disable state locking
+	//
+	// stateLockTimeout is the optional duration to retry a state locks locks
+	// when it is already locked by another process.
+	//
+	// forceInitCopy suppresses confirmation for copying state data during
+	// init.
+	//
+	// reconfigure forces init to ignore any stored configuration.
+	//
+	// migrateState confirms the user wishes to migrate from the prior backend
+	// configuration to a new configuration.
+	//
+	// compactWarnings (-compact-warnings) selects a more compact presentation
+	// of warnings in the output when they are not accompanied by errors.
+	statePath        string
+	stateOutPath     string
+	backupPath       string
+	parallelism      int
+	stateLock        bool
+	stateLockTimeout time.Duration
+	forceInitCopy    bool
+	reconfigure      bool
+	migrateState     bool
+	compactWarnings  bool
+
+	// Used with commands which write state to allow users to write remote
+	// state even if the remote and local Terraform versions don't match.
+	ignoreRemoteVersion bool
+}
+
+type testingOverrides struct {
+	Providers    map[addrs.Provider]providers.Factory
+	Provisioners map[string]provisioners.Factory
+}
+
+// initStatePaths is used to initialize the default values for
+// statePath, stateOutPath, and backupPath
+func (m *Meta) initStatePaths() {
+	if m.statePath == "" {
+		m.statePath = DefaultStateFilename
+	}
+	if m.stateOutPath == "" {
+		m.stateOutPath = m.statePath
+	}
+	if m.backupPath == "" {
+		m.backupPath = m.stateOutPath + DefaultBackupExtension
+	}
+}
+
+// StateOutPath returns the true output path for the state file
+func (m *Meta) StateOutPath() string {
+	return m.stateOutPath
+}
+
+// Colorize returns the colorization structure for a command.
+func (m *Meta) Colorize() *colorstring.Colorize {
+	colors := make(map[string]string)
+	for k, v := range colorstring.DefaultColors {
+		colors[k] = v
+	}
+	colors["purple"] = "38;5;57"
+
+	return &colorstring.Colorize{
+		Colors:  colors,
+		Disable: !m.color,
+		Reset:   true,
+	}
+}
+
+// fixupMissingWorkingDir is a compensation for various existing tests which
+// directly construct incomplete "Meta" objects. Specifically, it deals with
+// a test that omits a WorkingDir value by constructing one just-in-time.
+//
+// We shouldn't ever rely on this in any real codepath, because it doesn't
+// take into account the various ways users can override our default
+// directory selection behaviors.
+func (m *Meta) fixupMissingWorkingDir() {
+	if m.WorkingDir == nil {
+		log.Printf("[WARN] This 'Meta' object is missing its WorkingDir, so we're creating a default one suitable only for tests")
+		m.WorkingDir = workdir.NewDir(".")
+	}
+}
+
+// DataDir returns the directory where local data will be stored.
+// Defaults to DefaultDataDir in the current working directory.
+func (m *Meta) DataDir() string {
+	m.fixupMissingWorkingDir()
+	return m.WorkingDir.DataDir()
+}
+
+const (
+	// InputModeEnvVar is the environment variable that, if set to "false" or
+	// "0", causes terraform commands to behave as if the `-input=false` flag was
+	// specified.
+	InputModeEnvVar = "TF_INPUT"
+)
+
+// InputMode returns the type of input we should ask for in the form of
+// terraform.InputMode which is passed directly to Context.Input.
+func (m *Meta) InputMode() terraform.InputMode {
+	if test || !m.input {
+		return 0
+	}
+
+	if envVar := os.Getenv(InputModeEnvVar); envVar != "" {
+		if v, err := strconv.ParseBool(envVar); err == nil {
+			if !v {
+				return 0
+			}
+		}
+	}
+
+	var mode terraform.InputMode
+	mode |= terraform.InputModeProvider
+
+	return mode
+}
+
+// UIInput returns a UIInput object to be used for asking for input.
+func (m *Meta) UIInput() terraform.UIInput {
+	return &UIInput{
+		Colorize: m.Colorize(),
+	}
+}
+
+// OutputColumns returns the number of columns that normal (non-error) UI
+// output should be wrapped to fill.
+//
+// This is the column count to use if you'll be printing your message via
+// the Output or Info methods of m.Ui.
+func (m *Meta) OutputColumns() int {
+	if m.Streams == nil {
+		// A default for unit tests that don't populate Meta fully.
+		return 78
+	}
+	return m.Streams.Stdout.Columns()
+}
+
+// ErrorColumns returns the number of columns that error UI output should be
+// wrapped to fill.
+//
+// This is the column count to use if you'll be printing your message via
+// the Error or Warn methods of m.Ui.
+func (m *Meta) ErrorColumns() int {
+	if m.Streams == nil {
+		// A default for unit tests that don't populate Meta fully.
+		return 78
+	}
+	return m.Streams.Stderr.Columns()
+}
+
+// StdinPiped returns true if the input is piped.
+func (m *Meta) StdinPiped() bool {
+	if m.Streams == nil {
+		// If we don't have m.Streams populated then we're presumably in a unit
+		// test that doesn't properly populate Meta, so we'll just say the
+		// output _isn't_ piped because that's the common case and so most likely
+		// to be useful to a unit test.
+		return false
+	}
+	return !m.Streams.Stdin.IsTerminal()
+}
+
+// InterruptibleContext returns a context.Context that will be cancelled
+// if the process is interrupted by a platform-specific interrupt signal.
+//
+// As usual with cancelable contexts, the caller must always call the given
+// cancel function once all operations are complete in order to make sure
+// that the context resources will still be freed even if there is no
+// interruption.
+func (m *Meta) InterruptibleContext() (context.Context, context.CancelFunc) {
+	base := context.Background()
+	if m.ShutdownCh == nil {
+		// If we're running in a unit testing context without a shutdown
+		// channel populated then we'll return an uncancelable channel.
+		return base, func() {}
+	}
+
+	ctx, cancel := context.WithCancel(base)
+	go func() {
+		select {
+		case <-m.ShutdownCh:
+			cancel()
+		case <-ctx.Done():
+			// finished without being interrupted
+		}
+	}()
+	return ctx, cancel
+}
+
+// RunOperation executes the given operation on the given backend, blocking
+// until that operation completes or is interrupted, and then returns
+// the RunningOperation object representing the completed or
+// aborted operation that is, despite the name, no longer running.
+//
+// An error is returned if the operation either fails to start or is cancelled.
+// If the operation runs to completion then no error is returned even if the
+// operation itself is unsuccessful. Use the "Result" field of the
+// returned operation object to recognize operation-level failure.
+func (m *Meta) RunOperation(b backend.Enhanced, opReq *backend.Operation) (*backend.RunningOperation, error) {
+	if opReq.View == nil {
+		panic("RunOperation called with nil View")
+	}
+	if opReq.ConfigDir != "" {
+		opReq.ConfigDir = m.normalizePath(opReq.ConfigDir)
+	}
+
+	op, err := b.Operation(context.Background(), opReq)
+	if err != nil {
+		return nil, fmt.Errorf("error starting operation: %s", err)
+	}
+
+	// Wait for the operation to complete or an interrupt to occur
+	select {
+	case <-m.ShutdownCh:
+		// gracefully stop the operation
+		op.Stop()
+
+		// Notify the user
+		opReq.View.Interrupted()
+
+		// Still get the result, since there is still one
+		select {
+		case <-m.ShutdownCh:
+			opReq.View.FatalInterrupt()
+
+			// cancel the operation completely
+			op.Cancel()
+
+			// the operation should return asap
+			// but timeout just in case
+			select {
+			case <-op.Done():
+			case <-time.After(5 * time.Second):
+			}
+
+			return nil, errors.New("operation canceled")
+
+		case <-op.Done():
+			// operation completed after Stop
+		}
+	case <-op.Done():
+		// operation completed normally
+	}
+
+	return op, nil
+}
+
+// contextOpts returns the options to use to initialize a Terraform
+// context with the settings from this Meta.
+func (m *Meta) contextOpts() (*terraform.ContextOpts, error) {
+	workspace, err := m.Workspace()
+	if err != nil {
+		return nil, err
+	}
+
+	var opts terraform.ContextOpts
+
+	opts.UIInput = m.UIInput()
+	opts.Parallelism = m.parallelism
+
+	// If testingOverrides are set, we'll skip the plugin discovery process
+	// and just work with what we've been given, thus allowing the tests
+	// to provide mock providers and provisioners.
+	if m.testingOverrides != nil {
+		opts.Providers = m.testingOverrides.Providers
+		opts.Provisioners = m.testingOverrides.Provisioners
+	} else {
+		var providerFactories map[addrs.Provider]providers.Factory
+		providerFactories, err = m.providerFactories()
+		opts.Providers = providerFactories
+		opts.Provisioners = m.provisionerFactories()
+	}
+
+	opts.Meta = &terraform.ContextMeta{
+		Env:                workspace,
+		OriginalWorkingDir: m.WorkingDir.OriginalWorkingDir(),
+	}
+
+	return &opts, err
+}
+
+// defaultFlagSet creates a default flag set for commands.
+// See also command/arguments/default.go
+func (m *Meta) defaultFlagSet(n string) *flag.FlagSet {
+	f := flag.NewFlagSet(n, flag.ContinueOnError)
+	f.SetOutput(ioutil.Discard)
+
+	// Set the default Usage to empty
+	f.Usage = func() {}
+
+	return f
+}
+
+// ignoreRemoteVersionFlagSet add the ignore-remote version flag to suppress
+// the error when the configured Terraform version on the remote workspace
+// does not match the local Terraform version.
+func (m *Meta) ignoreRemoteVersionFlagSet(n string) *flag.FlagSet {
+	f := m.defaultFlagSet(n)
+
+	f.BoolVar(&m.ignoreRemoteVersion, "ignore-remote-version", false, "continue even if remote and local Terraform versions are incompatible")
+
+	return f
+}
+
+// extendedFlagSet adds custom flags that are mostly used by commands
+// that are used to run an operation like plan or apply.
+func (m *Meta) extendedFlagSet(n string) *flag.FlagSet {
+	f := m.defaultFlagSet(n)
+
+	f.BoolVar(&m.input, "input", true, "input")
+	f.Var((*FlagStringSlice)(&m.targetFlags), "target", "resource to target")
+	f.BoolVar(&m.compactWarnings, "compact-warnings", false, "use compact warnings")
+
+	if m.variableArgs.items == nil {
+		m.variableArgs = newRawFlags("-var")
+	}
+	varValues := m.variableArgs.Alias("-var")
+	varFiles := m.variableArgs.Alias("-var-file")
+	f.Var(varValues, "var", "variables")
+	f.Var(varFiles, "var-file", "variable file")
+
+	// commands that bypass locking will supply their own flag on this var,
+	// but set the initial meta value to true as a failsafe.
+	m.stateLock = true
+
+	return f
+}
+
+// process will process any -no-color entries out of the arguments. This
+// will potentially modify the args in-place. It will return the resulting
+// slice, and update the Meta and Ui.
+func (m *Meta) process(args []string) []string {
+	// We do this so that we retain the ability to technically call
+	// process multiple times, even if we have no plans to do so
+	if m.oldUi != nil {
+		m.Ui = m.oldUi
+	}
+
+	// Set colorization
+	m.color = m.Color
+	i := 0 // output index
+	for _, v := range args {
+		if v == "-no-color" {
+			m.color = false
+			m.Color = false
+		} else {
+			// copy and increment index
+			args[i] = v
+			i++
+		}
+	}
+	args = args[:i]
+
+	// Set the UI
+	m.oldUi = m.Ui
+	m.Ui = &cli.ConcurrentUi{
+		Ui: &ColorizeUi{
+			Colorize:   m.Colorize(),
+			ErrorColor: "[red]",
+			WarnColor:  "[yellow]",
+			Ui:         m.oldUi,
+		},
+	}
+
+	// Reconfigure the view. This is necessary for commands which use both
+	// views.View and cli.Ui during the migration phase.
+	if m.View != nil {
+		m.View.Configure(&arguments.View{
+			CompactWarnings: m.compactWarnings,
+			NoColor:         !m.Color,
+		})
+	}
+
+	return args
+}
+
+// uiHook returns the UiHook to use with the context.
+func (m *Meta) uiHook() *views.UiHook {
+	return views.NewUiHook(m.View)
+}
+
+// confirm asks a yes/no confirmation.
+func (m *Meta) confirm(opts *terraform.InputOpts) (bool, error) {
+	if !m.Input() {
+		return false, errors.New("input is disabled")
+	}
+
+	for i := 0; i < 2; i++ {
+		v, err := m.UIInput().Input(context.Background(), opts)
+		if err != nil {
+			return false, fmt.Errorf(
+				"Error asking for confirmation: %s", err)
+		}
+
+		switch strings.ToLower(v) {
+		case "no":
+			return false, nil
+		case "yes":
+			return true, nil
+		}
+	}
+	return false, nil
+}
+
+// showDiagnostics displays error and warning messages in the UI.
+//
+// "Diagnostics" here means the Diagnostics type from the tfdiag package,
+// though as a convenience this function accepts anything that could be
+// passed to the "Append" method on that type, converting it to Diagnostics
+// before displaying it.
+//
+// Internally this function uses Diagnostics.Append, and so it will panic
+// if given unsupported value types, just as Append does.
+func (m *Meta) showDiagnostics(vals ...interface{}) {
+	var diags tfdiags.Diagnostics
+	diags = diags.Append(vals...)
+	diags.Sort()
+
+	if len(diags) == 0 {
+		return
+	}
+
+	outputWidth := m.ErrorColumns()
+
+	diags = diags.ConsolidateWarnings(1)
+
+	// Since warning messages are generally competing
+	if m.compactWarnings {
+		// If the user selected compact warnings and all of the diagnostics are
+		// warnings then we'll use a more compact representation of the warnings
+		// that only includes their summaries.
+		// We show full warnings if there are also errors, because a warning
+		// can sometimes serve as good context for a subsequent error.
+		useCompact := true
+		for _, diag := range diags {
+			if diag.Severity() != tfdiags.Warning {
+				useCompact = false
+				break
+			}
+		}
+		if useCompact {
+			msg := format.DiagnosticWarningsCompact(diags, m.Colorize())
+			msg = "\n" + msg + "\nTo see the full warning notes, run Terraform without -compact-warnings.\n"
+			m.Ui.Warn(msg)
+			return
+		}
+	}
+
+	for _, diag := range diags {
+		var msg string
+		if m.Color {
+			msg = format.Diagnostic(diag, m.configSources(), m.Colorize(), outputWidth)
+		} else {
+			msg = format.DiagnosticPlain(diag, m.configSources(), outputWidth)
+		}
+
+		switch diag.Severity() {
+		case tfdiags.Error:
+			m.Ui.Error(msg)
+		case tfdiags.Warning:
+			m.Ui.Warn(msg)
+		default:
+			m.Ui.Output(msg)
+		}
+	}
+}
+
+// WorkspaceNameEnvVar is the name of the environment variable that can be used
+// to set the name of the Terraform workspace, overriding the workspace chosen
+// by `terraform workspace select`.
+//
+// Note that this environment variable is ignored by `terraform workspace new`
+// and `terraform workspace delete`.
+const WorkspaceNameEnvVar = "TF_WORKSPACE"
+
+var errInvalidWorkspaceNameEnvVar = fmt.Errorf("Invalid workspace name set using %s", WorkspaceNameEnvVar)
+
+// Workspace returns the name of the currently configured workspace, corresponding
+// to the desired named state.
+func (m *Meta) Workspace() (string, error) {
+	current, overridden := m.WorkspaceOverridden()
+	if overridden && !validWorkspaceName(current) {
+		return "", errInvalidWorkspaceNameEnvVar
+	}
+	return current, nil
+}
+
+// WorkspaceOverridden returns the name of the currently configured workspace,
+// corresponding to the desired named state, as well as a bool saying whether
+// this was set via the TF_WORKSPACE environment variable.
+func (m *Meta) WorkspaceOverridden() (string, bool) {
+	if envVar := os.Getenv(WorkspaceNameEnvVar); envVar != "" {
+		return envVar, true
+	}
+
+	envData, err := ioutil.ReadFile(filepath.Join(m.DataDir(), local.DefaultWorkspaceFile))
+	current := string(bytes.TrimSpace(envData))
+	if current == "" {
+		current = backend.DefaultStateName
+	}
+
+	if err != nil && !os.IsNotExist(err) {
+		// always return the default if we can't get a workspace name
+		log.Printf("[ERROR] failed to read current workspace: %s", err)
+	}
+
+	return current, false
+}
+
+// SetWorkspace saves the given name as the current workspace in the local
+// filesystem.
+func (m *Meta) SetWorkspace(name string) error {
+	err := os.MkdirAll(m.DataDir(), 0755)
+	if err != nil {
+		return err
+	}
+
+	err = ioutil.WriteFile(filepath.Join(m.DataDir(), local.DefaultWorkspaceFile), []byte(name), 0644)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// isAutoVarFile determines if the file ends with .auto.tfvars or .auto.tfvars.json
+func isAutoVarFile(path string) bool {
+	return strings.HasSuffix(path, ".auto.tfvars") ||
+		strings.HasSuffix(path, ".auto.tfvars.json")
+}
+
+// FIXME: as an interim refactoring step, we apply the contents of the state
+// arguments directly to the Meta object. Future work would ideally update the
+// code paths which use these arguments to be passed them directly for clarity.
+func (m *Meta) applyStateArguments(args *arguments.State) {
+	m.stateLock = args.Lock
+	m.stateLockTimeout = args.LockTimeout
+	m.statePath = args.StatePath
+	m.stateOutPath = args.StateOutPath
+	m.backupPath = args.BackupPath
+}
+
+// checkRequiredVersion loads the config and check if the
+// core version requirements are satisfied.
+func (m *Meta) checkRequiredVersion() tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	loader, err := m.initConfigLoader()
+	if err != nil {
+		diags = diags.Append(err)
+		return diags
+	}
+
+	pwd, err := os.Getwd()
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Error getting pwd: %s", err))
+		return diags
+	}
+
+	config, configDiags := loader.LoadConfig(pwd)
+	if configDiags.HasErrors() {
+		diags = diags.Append(configDiags)
+		return diags
+	}
+
+	versionDiags := terraform.CheckCoreVersionRequirements(config)
+	if versionDiags.HasErrors() {
+		diags = diags.Append(versionDiags)
+		return diags
+	}
+
+	return nil
+}
+
+// MaybeGetSchemas attempts to load and return the schemas
+// If there is not enough information to return the schemas,
+// it could potentially return nil without errors. It is the
+// responsibility of the caller to handle the lack of schema
+// information accordingly
+func (c *Meta) MaybeGetSchemas(state *states.State, config *configs.Config) (*terraform.Schemas, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	path, err := os.Getwd()
+	if err != nil {
+		diags.Append(tfdiags.SimpleWarning(failedToLoadSchemasMessage))
+		return nil, diags
+	}
+
+	if config == nil {
+		config, diags = c.loadConfig(path)
+		if diags.HasErrors() {
+			diags.Append(tfdiags.SimpleWarning(failedToLoadSchemasMessage))
+			return nil, diags
+		}
+	}
+
+	if config != nil || state != nil {
+		opts, err := c.contextOpts()
+		if err != nil {
+			diags = diags.Append(err)
+			return nil, diags
+		}
+		tfCtx, ctxDiags := terraform.NewContext(opts)
+		diags = diags.Append(ctxDiags)
+		if ctxDiags.HasErrors() {
+			return nil, diags
+		}
+		var schemaDiags tfdiags.Diagnostics
+		schemas, schemaDiags := tfCtx.Schemas(config, state)
+		diags = diags.Append(schemaDiags)
+		if schemaDiags.HasErrors() {
+			return nil, diags
+		}
+		return schemas, diags
+
+	}
+	return nil, diags
+}
diff --git a/v1.5.7/internal/command/meta_backend.go b/v1.5.7/internal/command/meta_backend.go
new file mode 100644
index 0000000..2a69da2
--- /dev/null
+++ b/v1.5.7/internal/command/meta_backend.go
@@ -0,0 +1,1687 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+// This file contains all the Backend-related function calls on Meta,
+// exported and private.
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"log"
+	"path/filepath"
+	"strconv"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcldec"
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/cloud"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+
+	backendInit "github.com/hashicorp/terraform/internal/backend/init"
+	backendLocal "github.com/hashicorp/terraform/internal/backend/local"
+	legacy "github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+// BackendOpts are the options used to initialize a backend.Backend.
+type BackendOpts struct {
+	// Config is a representation of the backend configuration block given in
+	// the root module, or nil if no such block is present.
+	Config *configs.Backend
+
+	// ConfigOverride is an hcl.Body that, if non-nil, will be used with
+	// configs.MergeBodies to override the type-specific backend configuration
+	// arguments in Config.
+	ConfigOverride hcl.Body
+
+	// Init should be set to true if initialization is allowed. If this is
+	// false, then any configuration that requires configuration will show
+	// an error asking the user to reinitialize.
+	Init bool
+
+	// ForceLocal will force a purely local backend, including state.
+	// You probably don't want to set this.
+	ForceLocal bool
+
+	// ViewType will set console output format for the
+	// initialization operation (JSON or human-readable).
+	ViewType arguments.ViewType
+}
+
+// BackendWithRemoteTerraformVersion is a shared interface between the 'remote' and 'cloud' backends
+// for simplified type checking when calling functions common to those particular backends.
+type BackendWithRemoteTerraformVersion interface {
+	IgnoreVersionConflict()
+	VerifyWorkspaceTerraformVersion(workspace string) tfdiags.Diagnostics
+	IsLocalOperations() bool
+}
+
+// Backend initializes and returns the backend for this CLI session.
+//
+// The backend is used to perform the actual Terraform operations. This
+// abstraction enables easily sliding in new Terraform behavior such as
+// remote state storage, remote operations, etc. while allowing the CLI
+// to remain mostly identical.
+//
+// This will initialize a new backend for each call, which can carry some
+// overhead with it. Please reuse the returned value for optimal behavior.
+//
+// Only one backend should be used per Meta. This function is stateful
+// and is unsafe to create multiple backends used at once. This function
+// can be called multiple times with each backend being "live" (usable)
+// one at a time.
+//
+// A side-effect of this method is the population of m.backendState, recording
+// the final resolved backend configuration after dealing with overrides from
+// the "terraform init" command line, etc.
+func (m *Meta) Backend(opts *BackendOpts) (backend.Enhanced, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// If no opts are set, then initialize
+	if opts == nil {
+		opts = &BackendOpts{}
+	}
+
+	// Initialize a backend from the config unless we're forcing a purely
+	// local operation.
+	var b backend.Backend
+	if !opts.ForceLocal {
+		var backendDiags tfdiags.Diagnostics
+		b, backendDiags = m.backendFromConfig(opts)
+		diags = diags.Append(backendDiags)
+
+		if diags.HasErrors() {
+			return nil, diags
+		}
+
+		log.Printf("[TRACE] Meta.Backend: instantiated backend of type %T", b)
+	}
+
+	// Set up the CLI opts we pass into backends that support it.
+	cliOpts, err := m.backendCLIOpts()
+	if err != nil {
+		if errs := providerPluginErrors(nil); errors.As(err, &errs) {
+			// This is a special type returned by m.providerFactories, which
+			// indicates one or more inconsistencies between the dependency
+			// lock file and the provider plugins actually available in the
+			// local cache directory.
+			//
+			// If initialization is allowed, we ignore this error, as it may
+			// be resolved by the later step where providers are fetched.
+			if !opts.Init {
+				var buf bytes.Buffer
+				for addr, err := range errs {
+					fmt.Fprintf(&buf, "\n  - %s: %s", addr, err)
+				}
+				suggestion := "To download the plugins required for this configuration, run:\n  terraform init"
+				if m.RunningInAutomation {
+					// Don't mention "terraform init" specifically if we're running in an automation wrapper
+					suggestion = "You must install the required plugins before running Terraform operations."
+				}
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Required plugins are not installed",
+					fmt.Sprintf(
+						"The installed provider plugins are not consistent with the packages selected in the dependency lock file:%s\n\nTerraform uses external plugins to integrate with a variety of different infrastructure services. %s",
+						buf.String(), suggestion,
+					),
+				))
+				return nil, diags
+			}
+		} else {
+			// All other errors just get generic handling.
+			diags = diags.Append(err)
+			return nil, diags
+		}
+	}
+	cliOpts.Validation = true
+
+	// If the backend supports CLI initialization, do it.
+	if cli, ok := b.(backend.CLI); ok {
+		if err := cli.CLIInit(cliOpts); err != nil {
+			diags = diags.Append(fmt.Errorf(
+				"Error initializing backend %T: %s\n\n"+
+					"This is a bug; please report it to the backend developer",
+				b, err,
+			))
+			return nil, diags
+		}
+	}
+
+	// If the result of loading the backend is an enhanced backend,
+	// then return that as-is. This works even if b == nil (it will be !ok).
+	if enhanced, ok := b.(backend.Enhanced); ok {
+		log.Printf("[TRACE] Meta.Backend: backend %T supports operations", b)
+		return enhanced, nil
+	}
+
+	// We either have a non-enhanced backend or no backend configured at
+	// all. In either case, we use local as our enhanced backend and the
+	// non-enhanced (if any) as the state backend.
+
+	if !opts.ForceLocal {
+		log.Printf("[TRACE] Meta.Backend: backend %T does not support operations, so wrapping it in a local backend", b)
+	}
+
+	// Build the local backend
+	local := backendLocal.NewWithBackend(b)
+	if err := local.CLIInit(cliOpts); err != nil {
+		// Local backend isn't allowed to fail. It would be a bug.
+		panic(err)
+	}
+
+	// If we got here from backendFromConfig returning nil then m.backendState
+	// won't be set, since that codepath considers that to be no backend at all,
+	// but our caller considers that to be the local backend with no config
+	// and so we'll synthesize a backend state so other code doesn't need to
+	// care about this special case.
+	//
+	// FIXME: We should refactor this so that we more directly and explicitly
+	// treat the local backend as the default, including in the UI shown to
+	// the user, since the local backend should only be used when learning or
+	// in exceptional cases and so it's better to help the user learn that
+	// by introducing it as a concept.
+	if m.backendState == nil {
+		// NOTE: This synthetic object is intentionally _not_ retained in the
+		// on-disk record of the backend configuration, which was already dealt
+		// with inside backendFromConfig, because we still need that codepath
+		// to be able to recognize the lack of a config as distinct from
+		// explicitly setting local until we do some more refactoring here.
+		m.backendState = &legacy.BackendState{
+			Type:      "local",
+			ConfigRaw: json.RawMessage("{}"),
+		}
+	}
+
+	return local, nil
+}
+
+// selectWorkspace gets a list of existing workspaces and then checks
+// if the currently selected workspace is valid. If not, it will ask
+// the user to select a workspace from the list.
+func (m *Meta) selectWorkspace(b backend.Backend) error {
+	workspaces, err := b.Workspaces()
+	if err == backend.ErrWorkspacesNotSupported {
+		return nil
+	}
+	if err != nil {
+		return fmt.Errorf("Failed to get existing workspaces: %s", err)
+	}
+	if len(workspaces) == 0 {
+		if c, ok := b.(*cloud.Cloud); ok && m.input {
+			// len is always 1 if using Name; 0 means we're using Tags and there
+			// aren't any matching workspaces. Which might be normal and fine, so
+			// let's just ask:
+			name, err := m.UIInput().Input(context.Background(), &terraform.InputOpts{
+				Id:          "create-workspace",
+				Query:       "\n[reset][bold][yellow]No workspaces found.[reset]",
+				Description: fmt.Sprintf(inputCloudInitCreateWorkspace, strings.Join(c.WorkspaceMapping.Tags, ", ")),
+			})
+			if err != nil {
+				return fmt.Errorf("Couldn't create initial workspace: %w", err)
+			}
+			name = strings.TrimSpace(name)
+			if name == "" {
+				return fmt.Errorf("Couldn't create initial workspace: no name provided")
+			}
+			log.Printf("[TRACE] Meta.selectWorkspace: selecting the new TFC workspace requested by the user (%s)", name)
+			return m.SetWorkspace(name)
+		} else {
+			return fmt.Errorf(strings.TrimSpace(errBackendNoExistingWorkspaces))
+		}
+	}
+
+	// Get the currently selected workspace.
+	workspace, err := m.Workspace()
+	if err != nil {
+		return err
+	}
+
+	// Check if any of the existing workspaces matches the selected
+	// workspace and create a numbered list of existing workspaces.
+	var list strings.Builder
+	for i, w := range workspaces {
+		if w == workspace {
+			log.Printf("[TRACE] Meta.selectWorkspace: the currently selected workspace is present in the configured backend (%s)", workspace)
+			return nil
+		}
+		fmt.Fprintf(&list, "%d. %s\n", i+1, w)
+	}
+
+	// If the backend only has a single workspace, select that as the current workspace
+	if len(workspaces) == 1 {
+		log.Printf("[TRACE] Meta.selectWorkspace: automatically selecting the single workspace provided by the backend (%s)", workspaces[0])
+		return m.SetWorkspace(workspaces[0])
+	}
+
+	if !m.input {
+		return fmt.Errorf("Currently selected workspace %q does not exist", workspace)
+	}
+
+	// Otherwise, ask the user to select a workspace from the list of existing workspaces.
+	v, err := m.UIInput().Input(context.Background(), &terraform.InputOpts{
+		Id: "select-workspace",
+		Query: fmt.Sprintf(
+			"\n[reset][bold][yellow]The currently selected workspace (%s) does not exist.[reset]",
+			workspace),
+		Description: fmt.Sprintf(
+			strings.TrimSpace(inputBackendSelectWorkspace), list.String()),
+	})
+	if err != nil {
+		return fmt.Errorf("Failed to select workspace: %s", err)
+	}
+
+	idx, err := strconv.Atoi(v)
+	if err != nil || (idx < 1 || idx > len(workspaces)) {
+		return fmt.Errorf("Failed to select workspace: input not a valid number")
+	}
+
+	workspace = workspaces[idx-1]
+	log.Printf("[TRACE] Meta.selectWorkspace: setting the current workspace according to user selection (%s)", workspace)
+	return m.SetWorkspace(workspace)
+}
+
+// BackendForPlan is similar to Backend, but uses backend settings that were
+// stored in a plan.
+//
+// The current workspace name is also stored as part of the plan, and so this
+// method will check that it matches the currently-selected workspace name
+// and produce error diagnostics if not.
+func (m *Meta) BackendForPlan(settings plans.Backend) (backend.Enhanced, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	f := backendInit.Backend(settings.Type)
+	if f == nil {
+		diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), settings.Type))
+		return nil, diags
+	}
+	b := f()
+	log.Printf("[TRACE] Meta.BackendForPlan: instantiated backend of type %T", b)
+
+	schema := b.ConfigSchema()
+	configVal, err := settings.Config.Decode(schema.ImpliedType())
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("saved backend configuration is invalid: %w", err))
+		return nil, diags
+	}
+
+	newVal, validateDiags := b.PrepareConfig(configVal)
+	diags = diags.Append(validateDiags)
+	if validateDiags.HasErrors() {
+		return nil, diags
+	}
+
+	configureDiags := b.Configure(newVal)
+	diags = diags.Append(configureDiags)
+	if configureDiags.HasErrors() {
+		return nil, diags
+	}
+
+	// If the backend supports CLI initialization, do it.
+	if cli, ok := b.(backend.CLI); ok {
+		cliOpts, err := m.backendCLIOpts()
+		if err != nil {
+			diags = diags.Append(err)
+			return nil, diags
+		}
+		if err := cli.CLIInit(cliOpts); err != nil {
+			diags = diags.Append(fmt.Errorf(
+				"Error initializing backend %T: %s\n\n"+
+					"This is a bug; please report it to the backend developer",
+				b, err,
+			))
+			return nil, diags
+		}
+	}
+
+	// If the result of loading the backend is an enhanced backend,
+	// then return that as-is. This works even if b == nil (it will be !ok).
+	if enhanced, ok := b.(backend.Enhanced); ok {
+		log.Printf("[TRACE] Meta.BackendForPlan: backend %T supports operations", b)
+		if err := m.setupEnhancedBackendAliases(enhanced); err != nil {
+			diags = diags.Append(err)
+			return nil, diags
+		}
+		return enhanced, nil
+	}
+
+	// Otherwise, we'll wrap our state-only remote backend in the local backend
+	// to cause any operations to be run locally.
+	log.Printf("[TRACE] Meta.Backend: backend %T does not support operations, so wrapping it in a local backend", b)
+	cliOpts, err := m.backendCLIOpts()
+	if err != nil {
+		diags = diags.Append(err)
+		return nil, diags
+	}
+	cliOpts.Validation = false // don't validate here in case config contains file(...) calls where the file doesn't exist
+	local := backendLocal.NewWithBackend(b)
+	if err := local.CLIInit(cliOpts); err != nil {
+		// Local backend should never fail, so this is always a bug.
+		panic(err)
+	}
+
+	return local, diags
+}
+
+// backendCLIOpts returns a backend.CLIOpts object that should be passed to
+// a backend that supports local CLI operations.
+func (m *Meta) backendCLIOpts() (*backend.CLIOpts, error) {
+	contextOpts, err := m.contextOpts()
+	if contextOpts == nil && err != nil {
+		return nil, err
+	}
+	return &backend.CLIOpts{
+		CLI:                 m.Ui,
+		CLIColor:            m.Colorize(),
+		Streams:             m.Streams,
+		StatePath:           m.statePath,
+		StateOutPath:        m.stateOutPath,
+		StateBackupPath:     m.backupPath,
+		ContextOpts:         contextOpts,
+		Input:               m.Input(),
+		RunningInAutomation: m.RunningInAutomation,
+	}, err
+}
+
+// Operation initializes a new backend.Operation struct.
+//
+// This prepares the operation. After calling this, the caller is expected
+// to modify fields of the operation such as Sequence to specify what will
+// be called.
+func (m *Meta) Operation(b backend.Backend, vt arguments.ViewType) *backend.Operation {
+	schema := b.ConfigSchema()
+	workspace, err := m.Workspace()
+	if err != nil {
+		// An invalid workspace error would have been raised when creating the
+		// backend, and the caller should have already exited. Seeing the error
+		// here first is a bug, so panic.
+		panic(fmt.Sprintf("invalid workspace: %s", err))
+	}
+	planOutBackend, err := m.backendState.ForPlan(schema, workspace)
+	if err != nil {
+		// Always indicates an implementation error in practice, because
+		// errors here indicate invalid encoding of the backend configuration
+		// in memory, and we should always have validated that by the time
+		// we get here.
+		panic(fmt.Sprintf("failed to encode backend configuration for plan: %s", err))
+	}
+
+	stateLocker := clistate.NewNoopLocker()
+	if m.stateLock {
+		view := views.NewStateLocker(vt, m.View)
+		stateLocker = clistate.NewLocker(m.stateLockTimeout, view)
+	}
+
+	depLocks, diags := m.lockedDependencies()
+	if diags.HasErrors() {
+		// We can't actually report errors from here, but m.lockedDependencies
+		// should always have been called earlier to prepare the "ContextOpts"
+		// for the backend anyway, so we should never actually get here in
+		// a real situation. If we do get here then the backend will inevitably
+		// fail downstream somwhere if it tries to use the empty depLocks.
+		log.Printf("[WARN] Failed to load dependency locks while preparing backend operation (ignored): %s", diags.Err().Error())
+	}
+
+	return &backend.Operation{
+		PlanOutBackend:  planOutBackend,
+		Targets:         m.targets,
+		UIIn:            m.UIInput(),
+		UIOut:           m.Ui,
+		Workspace:       workspace,
+		StateLocker:     stateLocker,
+		DependencyLocks: depLocks,
+	}
+}
+
+// backendConfig returns the local configuration for the backend
+func (m *Meta) backendConfig(opts *BackendOpts) (*configs.Backend, int, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	if opts.Config == nil {
+		// check if the config was missing, or just not required
+		conf, moreDiags := m.loadBackendConfig(".")
+		diags = diags.Append(moreDiags)
+		if moreDiags.HasErrors() {
+			return nil, 0, diags
+		}
+
+		if conf == nil {
+			log.Println("[TRACE] Meta.Backend: no config given or present on disk, so returning nil config")
+			return nil, 0, nil
+		}
+
+		log.Printf("[TRACE] Meta.Backend: BackendOpts.Config not set, so using settings loaded from %s", conf.DeclRange)
+		opts.Config = conf
+	}
+
+	c := opts.Config
+
+	if c == nil {
+		log.Println("[TRACE] Meta.Backend: no explicit backend config, so returning nil config")
+		return nil, 0, nil
+	}
+
+	bf := backendInit.Backend(c.Type)
+	if bf == nil {
+		detail := fmt.Sprintf("There is no backend type named %q.", c.Type)
+		if msg, removed := backendInit.RemovedBackends[c.Type]; removed {
+			detail = msg
+		}
+
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid backend type",
+			Detail:   detail,
+			Subject:  &c.TypeRange,
+		})
+		return nil, 0, diags
+	}
+	b := bf()
+
+	configSchema := b.ConfigSchema()
+	configBody := c.Config
+	configHash := c.Hash(configSchema)
+
+	// If we have an override configuration body then we must apply it now.
+	if opts.ConfigOverride != nil {
+		log.Println("[TRACE] Meta.Backend: merging -backend-config=... CLI overrides into backend configuration")
+		configBody = configs.MergeBodies(configBody, opts.ConfigOverride)
+	}
+
+	log.Printf("[TRACE] Meta.Backend: built configuration for %q backend with hash value %d", c.Type, configHash)
+
+	// We'll shallow-copy configs.Backend here so that we can replace the
+	// body without affecting others that hold this reference.
+	configCopy := *c
+	configCopy.Config = configBody
+	return &configCopy, configHash, diags
+}
+
+// backendFromConfig returns the initialized (not configured) backend
+// directly from the config/state..
+//
+// This function handles various edge cases around backend config loading. For
+// example: new config changes, backend type changes, etc.
+//
+// As of the 0.12 release it can no longer migrate from legacy remote state
+// to backends, and will instead instruct users to use 0.11 or earlier as
+// a stepping-stone to do that migration.
+//
+// This function may query the user for input unless input is disabled, in
+// which case this function will error.
+func (m *Meta) backendFromConfig(opts *BackendOpts) (backend.Backend, tfdiags.Diagnostics) {
+	// Get the local backend configuration.
+	c, cHash, diags := m.backendConfig(opts)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	// ------------------------------------------------------------------------
+	// For historical reasons, current backend configuration for a working
+	// directory is kept in a *state-like* file, using the legacy state
+	// structures in the Terraform package. It is not actually a Terraform
+	// state, and so only the "backend" portion of it is actually used.
+	//
+	// The remainder of this code often confusingly refers to this as a "state",
+	// so it's unfortunately important to remember that this is not actually
+	// what we _usually_ think of as "state", and is instead a local working
+	// directory "backend configuration state" that is never persisted anywhere.
+	//
+	// Since the "real" state has since moved on to be represented by
+	// states.State, we can recognize the special meaning of state that applies
+	// to this function and its callees by their continued use of the
+	// otherwise-obsolete terraform.State.
+	// ------------------------------------------------------------------------
+
+	// Get the path to where we store a local cache of backend configuration
+	// if we're using a remote backend. This may not yet exist which means
+	// we haven't used a non-local backend before. That is okay.
+	statePath := filepath.Join(m.DataDir(), DefaultStateFilename)
+	sMgr := &clistate.LocalState{Path: statePath}
+	if err := sMgr.RefreshState(); err != nil {
+		diags = diags.Append(fmt.Errorf("Failed to load state: %s", err))
+		return nil, diags
+	}
+
+	// Load the state, it must be non-nil for the tests below but can be empty
+	s := sMgr.State()
+	if s == nil {
+		log.Printf("[TRACE] Meta.Backend: backend has not previously been initialized in this working directory")
+		s = legacy.NewState()
+	} else if s.Backend != nil {
+		log.Printf("[TRACE] Meta.Backend: working directory was previously initialized for %q backend", s.Backend.Type)
+	} else {
+		log.Printf("[TRACE] Meta.Backend: working directory was previously initialized but has no backend (is using legacy remote state?)")
+	}
+
+	// if we want to force reconfiguration of the backend, we set the backend
+	// state to nil on this copy. This will direct us through the correct
+	// configuration path in the switch statement below.
+	if m.reconfigure {
+		s.Backend = nil
+	}
+
+	// Upon return, we want to set the state we're using in-memory so that
+	// we can access it for commands.
+	m.backendState = nil
+	defer func() {
+		if s := sMgr.State(); s != nil && !s.Backend.Empty() {
+			m.backendState = s.Backend
+		}
+	}()
+
+	if !s.Remote.Empty() {
+		// Legacy remote state is no longer supported. User must first
+		// migrate with Terraform 0.11 or earlier.
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Legacy remote state not supported",
+			"This working directory is configured for legacy remote state, which is no longer supported from Terraform v0.12 onwards. To migrate this environment, first run \"terraform init\" under a Terraform 0.11 release, and then upgrade Terraform again.",
+		))
+		return nil, diags
+	}
+
+	// This switch statement covers all the different combinations of
+	// configuring new backends, updating previously-configured backends, etc.
+	switch {
+	// No configuration set at all. Pure local state.
+	case c == nil && s.Backend.Empty():
+		log.Printf("[TRACE] Meta.Backend: using default local state only (no backend configuration, and no existing initialized backend)")
+		return nil, nil
+
+	// We're unsetting a backend (moving from backend => local)
+	case c == nil && !s.Backend.Empty():
+		log.Printf("[TRACE] Meta.Backend: previously-initialized %q backend is no longer present in config", s.Backend.Type)
+
+		initReason := fmt.Sprintf("Unsetting the previously set backend %q", s.Backend.Type)
+		if !opts.Init {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Backend initialization required, please run \"terraform init\"",
+				fmt.Sprintf(strings.TrimSpace(errBackendInit), initReason),
+			))
+			return nil, diags
+		}
+
+		if s.Backend.Type != "cloud" && !m.migrateState {
+			diags = diags.Append(migrateOrReconfigDiag)
+			return nil, diags
+		}
+
+		return m.backend_c_r_S(c, cHash, sMgr, true, opts)
+
+	// Configuring a backend for the first time or -reconfigure flag was used
+	case c != nil && s.Backend.Empty():
+		log.Printf("[TRACE] Meta.Backend: moving from default local state only to %q backend", c.Type)
+		if !opts.Init {
+			if c.Type == "cloud" {
+				initReason := "Initial configuration of Terraform Cloud"
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Terraform Cloud initialization required: please run \"terraform init\"",
+					fmt.Sprintf(strings.TrimSpace(errBackendInitCloud), initReason),
+				))
+			} else {
+				initReason := fmt.Sprintf("Initial configuration of the requested backend %q", c.Type)
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Backend initialization required, please run \"terraform init\"",
+					fmt.Sprintf(strings.TrimSpace(errBackendInit), initReason),
+				))
+			}
+			return nil, diags
+		}
+		return m.backend_C_r_s(c, cHash, sMgr, opts)
+	// Potentially changing a backend configuration
+	case c != nil && !s.Backend.Empty():
+		// We are not going to migrate if...
+		//
+		// We're not initializing
+		// AND the backend cache hash values match, indicating that the stored config is valid and completely unchanged.
+		// AND we're not providing any overrides. An override can mean a change overriding an unchanged backend block (indicated by the hash value).
+		if (uint64(cHash) == s.Backend.Hash) && (!opts.Init || opts.ConfigOverride == nil) {
+			log.Printf("[TRACE] Meta.Backend: using already-initialized, unchanged %q backend configuration", c.Type)
+			savedBackend, diags := m.savedBackend(sMgr)
+			// Verify that selected workspace exist. Otherwise prompt user to create one
+			if opts.Init && savedBackend != nil {
+				if err := m.selectWorkspace(savedBackend); err != nil {
+					diags = diags.Append(err)
+					return nil, diags
+				}
+			}
+			return savedBackend, diags
+		}
+
+		// If our configuration (the result of both the literal configuration and given
+		// -backend-config options) is the same, then we're just initializing a previously
+		// configured backend. The literal configuration may differ, however, so while we
+		// don't need to migrate, we update the backend cache hash value.
+		if !m.backendConfigNeedsMigration(c, s.Backend) {
+			log.Printf("[TRACE] Meta.Backend: using already-initialized %q backend configuration", c.Type)
+			savedBackend, moreDiags := m.savedBackend(sMgr)
+			diags = diags.Append(moreDiags)
+			if moreDiags.HasErrors() {
+				return nil, diags
+			}
+
+			// It's possible for a backend to be unchanged, and the config itself to
+			// have changed by moving a parameter from the config to `-backend-config`
+			// In this case, we update the Hash.
+			moreDiags = m.updateSavedBackendHash(cHash, sMgr)
+			if moreDiags.HasErrors() {
+				return nil, diags
+			}
+			// Verify that selected workspace exist. Otherwise prompt user to create one
+			if opts.Init && savedBackend != nil {
+				if err := m.selectWorkspace(savedBackend); err != nil {
+					diags = diags.Append(err)
+					return nil, diags
+				}
+			}
+
+			return savedBackend, diags
+		}
+		log.Printf("[TRACE] Meta.Backend: backend configuration has changed (from type %q to type %q)", s.Backend.Type, c.Type)
+
+		cloudMode := cloud.DetectConfigChangeType(s.Backend, c, false)
+
+		if !opts.Init {
+			//user ran another cmd that is not init but they are required to initialize because of a potential relevant change to their backend configuration
+			initDiag := m.determineInitReason(s.Backend.Type, c.Type, cloudMode)
+			diags = diags.Append(initDiag)
+			return nil, diags
+		}
+
+		if !cloudMode.InvolvesCloud() && !m.migrateState {
+			diags = diags.Append(migrateOrReconfigDiag)
+			return nil, diags
+		}
+
+		log.Printf("[WARN] backend config has changed since last init")
+		return m.backend_C_r_S_changed(c, cHash, sMgr, true, opts)
+
+	default:
+		diags = diags.Append(fmt.Errorf(
+			"Unhandled backend configuration state. This is a bug. Please\n"+
+				"report this error with the following information.\n\n"+
+				"Config Nil: %v\n"+
+				"Saved Backend Empty: %v\n",
+			c == nil, s.Backend.Empty(),
+		))
+		return nil, diags
+	}
+}
+
+func (m *Meta) determineInitReason(previousBackendType string, currentBackendType string, cloudMode cloud.ConfigChangeMode) tfdiags.Diagnostics {
+	initReason := ""
+	switch cloudMode {
+	case cloud.ConfigMigrationIn:
+		initReason = fmt.Sprintf("Changed from backend %q to Terraform Cloud", previousBackendType)
+	case cloud.ConfigMigrationOut:
+		initReason = fmt.Sprintf("Changed from Terraform Cloud to backend %q", previousBackendType)
+	case cloud.ConfigChangeInPlace:
+		initReason = "Terraform Cloud configuration block has changed"
+	default:
+		switch {
+		case previousBackendType != currentBackendType:
+			initReason = fmt.Sprintf("Backend type changed from %q to %q", previousBackendType, currentBackendType)
+		default:
+			initReason = "Backend configuration block has changed"
+		}
+	}
+
+	var diags tfdiags.Diagnostics
+	switch cloudMode {
+	case cloud.ConfigChangeInPlace:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Terraform Cloud initialization required: please run \"terraform init\"",
+			fmt.Sprintf(strings.TrimSpace(errBackendInitCloud), initReason),
+		))
+	case cloud.ConfigMigrationIn:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Terraform Cloud initialization required: please run \"terraform init\"",
+			fmt.Sprintf(strings.TrimSpace(errBackendInitCloud), initReason),
+		))
+	default:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Backend initialization required: please run \"terraform init\"",
+			fmt.Sprintf(strings.TrimSpace(errBackendInit), initReason),
+		))
+	}
+
+	return diags
+}
+
+// backendFromState returns the initialized (not configured) backend directly
+// from the state. This should be used only when a user runs `terraform init
+// -backend=false`. This function returns a local backend if there is no state
+// or no backend configured.
+func (m *Meta) backendFromState() (backend.Backend, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	// Get the path to where we store a local cache of backend configuration
+	// if we're using a remote backend. This may not yet exist which means
+	// we haven't used a non-local backend before. That is okay.
+	statePath := filepath.Join(m.DataDir(), DefaultStateFilename)
+	sMgr := &clistate.LocalState{Path: statePath}
+	if err := sMgr.RefreshState(); err != nil {
+		diags = diags.Append(fmt.Errorf("Failed to load state: %s", err))
+		return nil, diags
+	}
+	s := sMgr.State()
+	if s == nil {
+		// no state, so return a local backend
+		log.Printf("[TRACE] Meta.Backend: backend has not previously been initialized in this working directory")
+		return backendLocal.New(), diags
+	}
+	if s.Backend == nil {
+		// s.Backend is nil, so return a local backend
+		log.Printf("[TRACE] Meta.Backend: working directory was previously initialized but has no backend (is using legacy remote state?)")
+		return backendLocal.New(), diags
+	}
+	log.Printf("[TRACE] Meta.Backend: working directory was previously initialized for %q backend", s.Backend.Type)
+
+	//backend init function
+	if s.Backend.Type == "" {
+		return backendLocal.New(), diags
+	}
+	f := backendInit.Backend(s.Backend.Type)
+	if f == nil {
+		diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Backend.Type))
+		return nil, diags
+	}
+	b := f()
+
+	// The configuration saved in the working directory state file is used
+	// in this case, since it will contain any additional values that
+	// were provided via -backend-config arguments on terraform init.
+	schema := b.ConfigSchema()
+	configVal, err := s.Backend.Config(schema)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to decode current backend config",
+			fmt.Sprintf("The backend configuration created by the most recent run of \"terraform init\" could not be decoded: %s. The configuration may have been initialized by an earlier version that used an incompatible configuration structure. Run \"terraform init -reconfigure\" to force re-initialization of the backend.", err),
+		))
+		return nil, diags
+	}
+
+	// Validate the config and then configure the backend
+	newVal, validDiags := b.PrepareConfig(configVal)
+	diags = diags.Append(validDiags)
+	if validDiags.HasErrors() {
+		return nil, diags
+	}
+
+	configDiags := b.Configure(newVal)
+	diags = diags.Append(configDiags)
+	if configDiags.HasErrors() {
+		return nil, diags
+	}
+
+	// If the result of loading the backend is an enhanced backend,
+	// then set up enhanced backend service aliases.
+	if enhanced, ok := b.(backend.Enhanced); ok {
+		log.Printf("[TRACE] Meta.BackendForPlan: backend %T supports operations", b)
+
+		if err := m.setupEnhancedBackendAliases(enhanced); err != nil {
+			diags = diags.Append(err)
+			return nil, diags
+		}
+	}
+
+	return b, diags
+}
+
+//-------------------------------------------------------------------
+// Backend Config Scenarios
+//
+// The functions below cover handling all the various scenarios that
+// can exist when loading a backend. They are named in the format of
+// "backend_C_R_S" where C, R, S may be upper or lowercase. Lowercase
+// means it is false, uppercase means it is true. The full set of eight
+// possible cases is handled.
+//
+// The fields are:
+//
+//   * C - Backend configuration is set and changed in TF files
+//   * R - Legacy remote state is set
+//   * S - Backend configuration is set in the state
+//
+//-------------------------------------------------------------------
+
+// Unconfiguring a backend (moving from backend => local).
+func (m *Meta) backend_c_r_S(
+	c *configs.Backend, cHash int, sMgr *clistate.LocalState, output bool, opts *BackendOpts) (backend.Backend, tfdiags.Diagnostics) {
+
+	var diags tfdiags.Diagnostics
+
+	vt := arguments.ViewJSON
+	// Set default viewtype if none was set as the StateLocker needs to know exactly
+	// what viewType we want to have.
+	if opts == nil || opts.ViewType != vt {
+		vt = arguments.ViewHuman
+	}
+
+	s := sMgr.State()
+
+	cloudMode := cloud.DetectConfigChangeType(s.Backend, c, false)
+	diags = diags.Append(m.assertSupportedCloudInitOptions(cloudMode))
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	// Get the backend type for output
+	backendType := s.Backend.Type
+
+	if cloudMode == cloud.ConfigMigrationOut {
+		m.Ui.Output("Migrating from Terraform Cloud to local state.")
+	} else {
+		m.Ui.Output(fmt.Sprintf(strings.TrimSpace(outputBackendMigrateLocal), s.Backend.Type))
+	}
+
+	// Grab a purely local backend to get the local state if it exists
+	localB, moreDiags := m.Backend(&BackendOpts{ForceLocal: true, Init: true})
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		return nil, diags
+	}
+
+	// Initialize the configured backend
+	b, moreDiags := m.savedBackend(sMgr)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		return nil, diags
+	}
+
+	// Perform the migration
+	err := m.backendMigrateState(&backendMigrateOpts{
+		SourceType:      s.Backend.Type,
+		DestinationType: "local",
+		Source:          b,
+		Destination:     localB,
+		ViewType:        vt,
+	})
+	if err != nil {
+		diags = diags.Append(err)
+		return nil, diags
+	}
+
+	// Remove the stored metadata
+	s.Backend = nil
+	if err := sMgr.WriteState(s); err != nil {
+		diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err))
+		return nil, diags
+	}
+	if err := sMgr.PersistState(); err != nil {
+		diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err))
+		return nil, diags
+	}
+
+	if output {
+		m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
+			"[reset][green]\n\n"+
+				strings.TrimSpace(successBackendUnset), backendType)))
+	}
+
+	// Return no backend
+	return nil, diags
+}
+
+// Configuring a backend for the first time.
+func (m *Meta) backend_C_r_s(c *configs.Backend, cHash int, sMgr *clistate.LocalState, opts *BackendOpts) (backend.Backend, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	vt := arguments.ViewJSON
+	// Set default viewtype if none was set as the StateLocker needs to know exactly
+	// what viewType we want to have.
+	if opts == nil || opts.ViewType != vt {
+		vt = arguments.ViewHuman
+	}
+
+	// Grab a purely local backend to get the local state if it exists
+	localB, localBDiags := m.Backend(&BackendOpts{ForceLocal: true, Init: true})
+	if localBDiags.HasErrors() {
+		diags = diags.Append(localBDiags)
+		return nil, diags
+	}
+
+	workspaces, err := localB.Workspaces()
+	if err != nil {
+		diags = diags.Append(fmt.Errorf(errBackendLocalRead, err))
+		return nil, diags
+	}
+
+	var localStates []statemgr.Full
+	for _, workspace := range workspaces {
+		localState, err := localB.StateMgr(workspace)
+		if err != nil {
+			diags = diags.Append(fmt.Errorf(errBackendLocalRead, err))
+			return nil, diags
+		}
+		if err := localState.RefreshState(); err != nil {
+			diags = diags.Append(fmt.Errorf(errBackendLocalRead, err))
+			return nil, diags
+		}
+
+		// We only care about non-empty states.
+		if localS := localState.State(); !localS.Empty() {
+			log.Printf("[TRACE] Meta.Backend: will need to migrate workspace states because of existing %q workspace", workspace)
+			localStates = append(localStates, localState)
+		} else {
+			log.Printf("[TRACE] Meta.Backend: ignoring local %q workspace because its state is empty", workspace)
+		}
+	}
+
+	cloudMode := cloud.DetectConfigChangeType(nil, c, len(localStates) > 0)
+	diags = diags.Append(m.assertSupportedCloudInitOptions(cloudMode))
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	// Get the backend
+	b, configVal, moreDiags := m.backendInitFromConfig(c)
+	diags = diags.Append(moreDiags)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	if len(localStates) > 0 {
+		// Perform the migration
+		err = m.backendMigrateState(&backendMigrateOpts{
+			SourceType:      "local",
+			DestinationType: c.Type,
+			Source:          localB,
+			Destination:     b,
+			ViewType:        vt,
+		})
+		if err != nil {
+			diags = diags.Append(err)
+			return nil, diags
+		}
+
+		// we usually remove the local state after migration to prevent
+		// confusion, but adding a default local backend block to the config
+		// can get us here too. Don't delete our state if the old and new paths
+		// are the same.
+		erase := true
+		if newLocalB, ok := b.(*backendLocal.Local); ok {
+			if localB, ok := localB.(*backendLocal.Local); ok {
+				if newLocalB.PathsConflictWith(localB) {
+					erase = false
+					log.Printf("[TRACE] Meta.Backend: both old and new backends share the same local state paths, so not erasing old state")
+				}
+			}
+		}
+
+		if erase {
+			log.Printf("[TRACE] Meta.Backend: removing old state snapshots from old backend")
+			for _, localState := range localStates {
+				// We always delete the local state, unless that was our new state too.
+				if err := localState.WriteState(nil); err != nil {
+					diags = diags.Append(fmt.Errorf(errBackendMigrateLocalDelete, err))
+					return nil, diags
+				}
+				if err := localState.PersistState(nil); err != nil {
+					diags = diags.Append(fmt.Errorf(errBackendMigrateLocalDelete, err))
+					return nil, diags
+				}
+			}
+		}
+	}
+
+	if m.stateLock {
+		view := views.NewStateLocker(vt, m.View)
+		stateLocker := clistate.NewLocker(m.stateLockTimeout, view)
+		if err := stateLocker.Lock(sMgr, "backend from plan"); err != nil {
+			diags = diags.Append(fmt.Errorf("Error locking state: %s", err))
+			return nil, diags
+		}
+		defer stateLocker.Unlock()
+	}
+
+	configJSON, err := ctyjson.Marshal(configVal, b.ConfigSchema().ImpliedType())
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Can't serialize backend configuration as JSON: %s", err))
+		return nil, diags
+	}
+
+	// Store the metadata in our saved state location
+	s := sMgr.State()
+	if s == nil {
+		s = legacy.NewState()
+	}
+	s.Backend = &legacy.BackendState{
+		Type:      c.Type,
+		ConfigRaw: json.RawMessage(configJSON),
+		Hash:      uint64(cHash),
+	}
+
+	// Verify that selected workspace exists in the backend.
+	if opts.Init && b != nil {
+		err := m.selectWorkspace(b)
+		if err != nil {
+			diags = diags.Append(err)
+
+			// FIXME: A compatibility oddity with the 'remote' backend.
+			// As an awkward legacy UX, when the remote backend is configured and there
+			// are no workspaces, the output to the user saying that there are none and
+			// the user should create one with 'workspace new' takes the form of an
+			// error message - even though it's happy path, expected behavior.
+			//
+			// Therefore, only return nil with errored diags for everything else, and
+			// allow the remote backend to continue and write its configuration to state
+			// even though no workspace is selected.
+			if c.Type != "remote" {
+				return nil, diags
+			}
+		}
+	}
+
+	if err := sMgr.WriteState(s); err != nil {
+		diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
+		return nil, diags
+	}
+	if err := sMgr.PersistState(); err != nil {
+		diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
+		return nil, diags
+	}
+
+	// By now the backend is successfully configured.  If using Terraform Cloud, the success
+	// message is handled as part of the final init message
+	if _, ok := b.(*cloud.Cloud); !ok {
+		m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
+			"[reset][green]\n"+strings.TrimSpace(successBackendSet), s.Backend.Type)))
+	}
+
+	return b, diags
+}
+
+// Changing a previously saved backend.
+func (m *Meta) backend_C_r_S_changed(c *configs.Backend, cHash int, sMgr *clistate.LocalState, output bool, opts *BackendOpts) (backend.Backend, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	vt := arguments.ViewJSON
+	// Set default viewtype if none was set as the StateLocker needs to know exactly
+	// what viewType we want to have.
+	if opts == nil || opts.ViewType != vt {
+		vt = arguments.ViewHuman
+	}
+
+	// Get the old state
+	s := sMgr.State()
+
+	cloudMode := cloud.DetectConfigChangeType(s.Backend, c, false)
+	diags = diags.Append(m.assertSupportedCloudInitOptions(cloudMode))
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	if output {
+		// Notify the user
+		switch cloudMode {
+		case cloud.ConfigChangeInPlace:
+			m.Ui.Output("Terraform Cloud configuration has changed.")
+		case cloud.ConfigMigrationIn:
+			m.Ui.Output(fmt.Sprintf("Migrating from backend %q to Terraform Cloud.", s.Backend.Type))
+		case cloud.ConfigMigrationOut:
+			m.Ui.Output(fmt.Sprintf("Migrating from Terraform Cloud to backend %q.", c.Type))
+		default:
+			if s.Backend.Type != c.Type {
+				output := fmt.Sprintf(outputBackendMigrateChange, s.Backend.Type, c.Type)
+				m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
+					"[reset]%s\n",
+					strings.TrimSpace(output))))
+			} else {
+				m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
+					"[reset]%s\n",
+					strings.TrimSpace(outputBackendReconfigure))))
+			}
+		}
+	}
+
+	// Get the backend
+	b, configVal, moreDiags := m.backendInitFromConfig(c)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		return nil, diags
+	}
+
+	// If this is a migration into, out of, or irrelevant to Terraform Cloud
+	// mode then we will do state migration here. Otherwise, we just update
+	// the working directory initialization directly, because Terraform Cloud
+	// doesn't have configurable state storage anyway -- we're only changing
+	// which workspaces are relevant to this configuration, not where their
+	// state lives.
+	if cloudMode != cloud.ConfigChangeInPlace {
+		// Grab the existing backend
+		oldB, oldBDiags := m.savedBackend(sMgr)
+		diags = diags.Append(oldBDiags)
+		if oldBDiags.HasErrors() {
+			return nil, diags
+		}
+
+		// Perform the migration
+		err := m.backendMigrateState(&backendMigrateOpts{
+			SourceType:      s.Backend.Type,
+			DestinationType: c.Type,
+			Source:          oldB,
+			Destination:     b,
+			ViewType:        vt,
+		})
+		if err != nil {
+			diags = diags.Append(err)
+			return nil, diags
+		}
+
+		if m.stateLock {
+			view := views.NewStateLocker(vt, m.View)
+			stateLocker := clistate.NewLocker(m.stateLockTimeout, view)
+			if err := stateLocker.Lock(sMgr, "backend from plan"); err != nil {
+				diags = diags.Append(fmt.Errorf("Error locking state: %s", err))
+				return nil, diags
+			}
+			defer stateLocker.Unlock()
+		}
+	}
+
+	configJSON, err := ctyjson.Marshal(configVal, b.ConfigSchema().ImpliedType())
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Can't serialize backend configuration as JSON: %s", err))
+		return nil, diags
+	}
+
+	// Update the backend state
+	s = sMgr.State()
+	if s == nil {
+		s = legacy.NewState()
+	}
+	s.Backend = &legacy.BackendState{
+		Type:      c.Type,
+		ConfigRaw: json.RawMessage(configJSON),
+		Hash:      uint64(cHash),
+	}
+
+	// Verify that selected workspace exist. Otherwise prompt user to create one
+	if opts.Init && b != nil {
+		if err := m.selectWorkspace(b); err != nil {
+			diags = diags.Append(err)
+			return b, diags
+		}
+	}
+
+	if err := sMgr.WriteState(s); err != nil {
+		diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
+		return nil, diags
+	}
+	if err := sMgr.PersistState(); err != nil {
+		diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
+		return nil, diags
+	}
+
+	if output {
+		// By now the backend is successfully configured.  If using Terraform Cloud, the success
+		// message is handled as part of the final init message
+		if _, ok := b.(*cloud.Cloud); !ok {
+			m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
+				"[reset][green]\n"+strings.TrimSpace(successBackendSet), s.Backend.Type)))
+		}
+	}
+
+	return b, diags
+}
+
+// Initializing a saved backend from the cache file (legacy state file)
+//
+// TODO: This is extremely similar to Meta.backendFromState() but for legacy reasons this is the
+// function used by the migration APIs within this file. The other handles 'init -backend=false',
+// specifically.
+func (m *Meta) savedBackend(sMgr *clistate.LocalState) (backend.Backend, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	s := sMgr.State()
+
+	// Get the backend
+	f := backendInit.Backend(s.Backend.Type)
+	if f == nil {
+		diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Backend.Type))
+		return nil, diags
+	}
+	b := f()
+
+	// The configuration saved in the working directory state file is used
+	// in this case, since it will contain any additional values that
+	// were provided via -backend-config arguments on terraform init.
+	schema := b.ConfigSchema()
+	configVal, err := s.Backend.Config(schema)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to decode current backend config",
+			fmt.Sprintf("The backend configuration created by the most recent run of \"terraform init\" could not be decoded: %s. The configuration may have been initialized by an earlier version that used an incompatible configuration structure. Run \"terraform init -reconfigure\" to force re-initialization of the backend.", err),
+		))
+		return nil, diags
+	}
+
+	// Validate the config and then configure the backend
+	newVal, validDiags := b.PrepareConfig(configVal)
+	diags = diags.Append(validDiags)
+	if validDiags.HasErrors() {
+		return nil, diags
+	}
+
+	configDiags := b.Configure(newVal)
+	diags = diags.Append(configDiags)
+	if configDiags.HasErrors() {
+		return nil, diags
+	}
+
+	// If the result of loading the backend is an enhanced backend,
+	// then set up enhanced backend service aliases.
+	if enhanced, ok := b.(backend.Enhanced); ok {
+		log.Printf("[TRACE] Meta.BackendForPlan: backend %T supports operations", b)
+
+		if err := m.setupEnhancedBackendAliases(enhanced); err != nil {
+			diags = diags.Append(err)
+			return nil, diags
+		}
+	}
+
+	return b, diags
+}
+
+func (m *Meta) updateSavedBackendHash(cHash int, sMgr *clistate.LocalState) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	s := sMgr.State()
+
+	if s.Backend.Hash != uint64(cHash) {
+		s.Backend.Hash = uint64(cHash)
+		if err := sMgr.WriteState(s); err != nil {
+			diags = diags.Append(err)
+		}
+	}
+
+	return diags
+}
+
+//-------------------------------------------------------------------
+// Reusable helper functions for backend management
+//-------------------------------------------------------------------
+
+// backendConfigNeedsMigration returns true if migration might be required to
+// move from the configured backend to the given cached backend config.
+//
+// This must be called with the synthetic *configs.Backend that results from
+// merging in any command-line options for correct behavior.
+//
+// If either the given configuration or cached configuration are invalid then
+// this function will conservatively assume that migration is required,
+// expecting that the migration code will subsequently deal with the same
+// errors.
+func (m *Meta) backendConfigNeedsMigration(c *configs.Backend, s *legacy.BackendState) bool {
+	if s == nil || s.Empty() {
+		log.Print("[TRACE] backendConfigNeedsMigration: no cached config, so migration is required")
+		return true
+	}
+	if c.Type != s.Type {
+		log.Printf("[TRACE] backendConfigNeedsMigration: type changed from %q to %q, so migration is required", s.Type, c.Type)
+		return true
+	}
+
+	// We need the backend's schema to do our comparison here.
+	f := backendInit.Backend(c.Type)
+	if f == nil {
+		log.Printf("[TRACE] backendConfigNeedsMigration: no backend of type %q, which migration codepath must handle", c.Type)
+		return true // let the migration codepath deal with the missing backend
+	}
+	b := f()
+
+	schema := b.ConfigSchema()
+	decSpec := schema.NoneRequired().DecoderSpec()
+	givenVal, diags := hcldec.Decode(c.Config, decSpec, nil)
+	if diags.HasErrors() {
+		log.Printf("[TRACE] backendConfigNeedsMigration: failed to decode given config; migration codepath must handle problem: %s", diags.Error())
+		return true // let the migration codepath deal with these errors
+	}
+
+	cachedVal, err := s.Config(schema)
+	if err != nil {
+		log.Printf("[TRACE] backendConfigNeedsMigration: failed to decode cached config; migration codepath must handle problem: %s", err)
+		return true // let the migration codepath deal with the error
+	}
+
+	// If we get all the way down here then it's the exact equality of the
+	// two decoded values that decides our outcome. It's safe to use RawEquals
+	// here (rather than Equals) because we know that unknown values can
+	// never appear in backend configurations.
+	if cachedVal.RawEquals(givenVal) {
+		log.Print("[TRACE] backendConfigNeedsMigration: given configuration matches cached configuration, so no migration is required")
+		return false
+	}
+	log.Print("[TRACE] backendConfigNeedsMigration: configuration values have changed, so migration is required")
+	return true
+}
+
+func (m *Meta) backendInitFromConfig(c *configs.Backend) (backend.Backend, cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// Get the backend
+	f := backendInit.Backend(c.Type)
+	if f == nil {
+		diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendNewUnknown), c.Type))
+		return nil, cty.NilVal, diags
+	}
+	b := f()
+
+	schema := b.ConfigSchema()
+	decSpec := schema.NoneRequired().DecoderSpec()
+	configVal, hclDiags := hcldec.Decode(c.Config, decSpec, nil)
+	diags = diags.Append(hclDiags)
+	if hclDiags.HasErrors() {
+		return nil, cty.NilVal, diags
+	}
+
+	if !configVal.IsWhollyKnown() {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Unknown values within backend definition",
+			"The `terraform` configuration block should contain only concrete and static values. Another diagnostic should contain more information about which part of the configuration is problematic."))
+		return nil, cty.NilVal, diags
+	}
+
+	// TODO: test
+	if m.Input() {
+		var err error
+		configVal, err = m.inputForSchema(configVal, schema)
+		if err != nil {
+			diags = diags.Append(fmt.Errorf("Error asking for input to configure backend %q: %s", c.Type, err))
+		}
+
+		// We get an unknown here if the if the user aborted input, but we can't
+		// turn that into a config value, so set it to null and let the provider
+		// handle it in PrepareConfig.
+		if !configVal.IsKnown() {
+			configVal = cty.NullVal(configVal.Type())
+		}
+	}
+
+	newVal, validateDiags := b.PrepareConfig(configVal)
+	diags = diags.Append(validateDiags.InConfigBody(c.Config, ""))
+	if validateDiags.HasErrors() {
+		return nil, cty.NilVal, diags
+	}
+
+	configureDiags := b.Configure(newVal)
+	diags = diags.Append(configureDiags.InConfigBody(c.Config, ""))
+
+	// If the result of loading the backend is an enhanced backend,
+	// then set up enhanced backend service aliases.
+	if enhanced, ok := b.(backend.Enhanced); ok {
+		log.Printf("[TRACE] Meta.BackendForPlan: backend %T supports operations", b)
+		if err := m.setupEnhancedBackendAliases(enhanced); err != nil {
+			diags = diags.Append(err)
+			return nil, cty.NilVal, diags
+		}
+	}
+
+	return b, configVal, diags
+}
+
+// Helper method to get aliases from the enhanced backend and alias them
+// in the Meta service discovery. It's unfortunate that the Meta backend
+// is modifying the service discovery at this level, but the owner
+// of the service discovery pointer does not have easy access to the backend.
+func (m *Meta) setupEnhancedBackendAliases(b backend.Enhanced) error {
+	// Set up the service discovery aliases specified by the enhanced backend.
+	serviceAliases, err := b.ServiceDiscoveryAliases()
+	if err != nil {
+		return err
+	}
+
+	for _, alias := range serviceAliases {
+		m.Services.Alias(alias.From, alias.To)
+	}
+	return nil
+}
+
+// Helper method to ignore remote/cloud backend version conflicts. Only call this
+// for commands which cannot accidentally upgrade remote state files.
+func (m *Meta) ignoreRemoteVersionConflict(b backend.Backend) {
+	if back, ok := b.(BackendWithRemoteTerraformVersion); ok {
+		back.IgnoreVersionConflict()
+	}
+}
+
+// Helper method to check the local Terraform version against the configured
+// version in the remote workspace, returning diagnostics if they conflict.
+func (m *Meta) remoteVersionCheck(b backend.Backend, workspace string) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	if back, ok := b.(BackendWithRemoteTerraformVersion); ok {
+		// Allow user override based on command-line flag
+		if m.ignoreRemoteVersion {
+			back.IgnoreVersionConflict()
+		}
+		// If the override is set, this check will return a warning instead of
+		// an error
+		versionDiags := back.VerifyWorkspaceTerraformVersion(workspace)
+		diags = diags.Append(versionDiags)
+		// If there are no errors resulting from this check, we do not need to
+		// check again
+		if !diags.HasErrors() {
+			back.IgnoreVersionConflict()
+		}
+	}
+
+	return diags
+}
+
+// assertSupportedCloudInitOptions returns diagnostics with errors if the
+// init-related command line options (implied inside the Meta receiver)
+// are incompatible with the given cloud configuration change mode.
+func (m *Meta) assertSupportedCloudInitOptions(mode cloud.ConfigChangeMode) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+	if mode.InvolvesCloud() {
+		log.Printf("[TRACE] Meta.Backend: Terraform Cloud mode initialization type: %s", mode)
+		if m.reconfigure {
+			if mode.IsCloudMigration() {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid command-line option",
+					"The -reconfigure option is unsupported when migrating to Terraform Cloud, because activating Terraform Cloud involves some additional steps.",
+				))
+			} else {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid command-line option",
+					"The -reconfigure option is for in-place reconfiguration of state backends only, and is not needed when changing Terraform Cloud settings.\n\nWhen using Terraform Cloud, initialization automatically activates any new Cloud configuration settings.",
+				))
+			}
+		}
+		if m.migrateState {
+			name := "-migrate-state"
+			if m.forceInitCopy {
+				// -force copy implies -migrate-state in "terraform init",
+				// so m.migrateState is forced to true in this case even if
+				// the user didn't actually specify it. We'll use the other
+				// name here to avoid being confusing, then.
+				name = "-force-copy"
+			}
+			if mode.IsCloudMigration() {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid command-line option",
+					fmt.Sprintf("The %s option is for migration between state backends only, and is not applicable when using Terraform Cloud.\n\nTerraform Cloud migration has additional steps, configured by interactive prompts.", name),
+				))
+			} else {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid command-line option",
+					fmt.Sprintf("The %s option is for migration between state backends only, and is not applicable when using Terraform Cloud.\n\nState storage is handled automatically by Terraform Cloud and so the state storage location is not configurable.", name),
+				))
+			}
+		}
+	}
+	return diags
+}
+
+//-------------------------------------------------------------------
+// Output constants and initialization code
+//-------------------------------------------------------------------
+
+const errBackendLocalRead = `
+Error reading local state: %s
+
+Terraform is trying to read your local state to determine if there is
+state to migrate to your newly configured backend. Terraform can't continue
+without this check because that would risk losing state. Please resolve the
+error above and try again.
+`
+
+const errBackendMigrateLocalDelete = `
+Error deleting local state after migration: %s
+
+Your local state is deleted after successfully migrating it to the newly
+configured backend. As part of the deletion process, a backup is made at
+the standard backup path unless explicitly asked not to. To cleanly operate
+with a backend, we must delete the local state file. Please resolve the
+issue above and retry the command.
+`
+
+const errBackendNewUnknown = `
+The backend %q could not be found.
+
+This is the backend specified in your Terraform configuration file.
+This error could be a simple typo in your configuration, but it can also
+be caused by using a Terraform version that doesn't support the specified
+backend type. Please check your configuration and your Terraform version.
+
+If you'd like to run Terraform and store state locally, you can fix this
+error by removing the backend configuration from your configuration.
+`
+
+const errBackendNoExistingWorkspaces = `
+No existing workspaces.
+
+Use the "terraform workspace" command to create and select a new workspace.
+If the backend already contains existing workspaces, you may need to update
+the backend configuration.
+`
+
+const errBackendSavedUnknown = `
+The backend %q could not be found.
+
+This is the backend that this Terraform environment is configured to use
+both in your configuration and saved locally as your last-used backend.
+If it isn't found, it could mean an alternate version of Terraform was
+used with this configuration. Please use the proper version of Terraform that
+contains support for this backend.
+
+If you'd like to force remove this backend, you must update your configuration
+to not use the backend and run "terraform init" (or any other command) again.
+`
+
+const errBackendClearSaved = `
+Error clearing the backend configuration: %s
+
+Terraform removes the saved backend configuration when you're removing a
+configured backend. This must be done so future Terraform runs know to not
+use the backend configuration. Please look at the error above, resolve it,
+and try again.
+`
+
+const errBackendInit = `
+Reason: %s
+
+The "backend" is the interface that Terraform uses to store state,
+perform operations, etc. If this message is showing up, it means that the
+Terraform configuration you're using is using a custom configuration for
+the Terraform backend.
+
+Changes to backend configurations require reinitialization. This allows
+Terraform to set up the new configuration, copy existing state, etc. Please run
+"terraform init" with either the "-reconfigure" or "-migrate-state" flags to
+use the current configuration.
+
+If the change reason above is incorrect, please verify your configuration
+hasn't changed and try again. At this point, no changes to your existing
+configuration or state have been made.
+`
+
+const errBackendInitCloud = `
+Reason: %s.
+
+Changes to the Terraform Cloud configuration block require reinitialization, to discover any changes to the available workspaces.
+
+To re-initialize, run:
+  terraform init
+
+Terraform has not yet made changes to your existing configuration or state.
+`
+
+const errBackendWriteSaved = `
+Error saving the backend configuration: %s
+
+Terraform saves the complete backend configuration in a local file for
+configuring the backend on future operations. This cannot be disabled. Errors
+are usually due to simple file permission errors. Please look at the error
+above, resolve it, and try again.
+`
+
+const outputBackendMigrateChange = `
+Terraform detected that the backend type changed from %q to %q.
+`
+
+const outputBackendMigrateLocal = `
+Terraform has detected you're unconfiguring your previously set %q backend.
+`
+
+const outputBackendReconfigure = `
+[reset][bold]Backend configuration changed![reset]
+
+Terraform has detected that the configuration specified for the backend
+has changed. Terraform will now check for existing state in the backends.
+`
+
+const inputCloudInitCreateWorkspace = `
+There are no workspaces with the configured tags (%s)
+in your Terraform Cloud organization. To finish initializing, Terraform needs at
+least one workspace available.
+
+Terraform can create a properly tagged workspace for you now. Please enter a
+name to create a new Terraform Cloud workspace.
+`
+
+const successBackendUnset = `
+Successfully unset the backend %q. Terraform will now operate locally.
+`
+
+const successBackendSet = `
+Successfully configured the backend %q! Terraform will automatically
+use this backend unless the backend configuration changes.
+`
+
+var migrateOrReconfigDiag = tfdiags.Sourceless(
+	tfdiags.Error,
+	"Backend configuration changed",
+	"A change in the backend configuration has been detected, which may require migrating existing state.\n\n"+
+		"If you wish to attempt automatic migration of the state, use \"terraform init -migrate-state\".\n"+
+		`If you wish to store the current configuration with no changes to the state, use "terraform init -reconfigure".`)
diff --git a/v1.5.7/internal/command/meta_backend_migrate.go b/v1.5.7/internal/command/meta_backend_migrate.go
new file mode 100644
index 0000000..013f8c1
--- /dev/null
+++ b/v1.5.7/internal/command/meta_backend_migrate.go
@@ -0,0 +1,1128 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"context"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/backend/remote"
+	"github.com/hashicorp/terraform/internal/cloud"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+type backendMigrateOpts struct {
+	SourceType, DestinationType string
+	Source, Destination         backend.Backend
+	ViewType                    arguments.ViewType
+
+	// Fields below are set internally when migrate is called
+
+	sourceWorkspace      string
+	destinationWorkspace string
+	force                bool // if true, won't ask for confirmation
+}
+
+// backendMigrateState handles migrating (copying) state from one backend
+// to another. This function handles asking the user for confirmation
+// as well as the copy itself.
+//
+// This function can handle all scenarios of state migration regardless
+// of the existence of state in either backend.
+//
+// After migrating the state, the existing state in the first backend
+// remains untouched.
+//
+// This will attempt to lock both states for the migration.
+func (m *Meta) backendMigrateState(opts *backendMigrateOpts) error {
+	log.Printf("[INFO] backendMigrateState: need to migrate from %q to %q backend config", opts.SourceType, opts.DestinationType)
+	// We need to check what the named state status is. If we're converting
+	// from multi-state to single-state for example, we need to handle that.
+	var sourceSingleState, destinationSingleState, sourceTFC, destinationTFC bool
+
+	_, sourceTFC = opts.Source.(*cloud.Cloud)
+	_, destinationTFC = opts.Destination.(*cloud.Cloud)
+
+	sourceWorkspaces, sourceSingleState, err := retrieveWorkspaces(opts.Source, opts.SourceType)
+	if err != nil {
+		return err
+	}
+	destinationWorkspaces, destinationSingleState, err := retrieveWorkspaces(opts.Destination, opts.SourceType)
+	if err != nil {
+		return err
+	}
+
+	// Set up defaults
+	opts.sourceWorkspace = backend.DefaultStateName
+	opts.destinationWorkspace = backend.DefaultStateName
+	opts.force = m.forceInitCopy
+
+	// Disregard remote Terraform version for the state source backend. If it's a
+	// Terraform Cloud remote backend, we don't care about the remote version,
+	// as we are migrating away and will not break a remote workspace.
+	m.ignoreRemoteVersionConflict(opts.Source)
+
+	// Disregard remote Terraform version if instructed to do so via CLI flag.
+	if m.ignoreRemoteVersion {
+		m.ignoreRemoteVersionConflict(opts.Destination)
+	} else {
+		// Check the remote Terraform version for the state destination backend. If
+		// it's a Terraform Cloud remote backend, we want to ensure that we don't
+		// break the workspace by uploading an incompatible state file.
+		for _, workspace := range destinationWorkspaces {
+			diags := m.remoteVersionCheck(opts.Destination, workspace)
+			if diags.HasErrors() {
+				return diags.Err()
+			}
+		}
+		// If there are no specified destination workspaces, perform a remote
+		// backend version check with the default workspace.
+		// Ensure that we are not dealing with Terraform Cloud migrations, as it
+		// does not support the default name.
+		if len(destinationWorkspaces) == 0 && !destinationTFC {
+			diags := m.remoteVersionCheck(opts.Destination, backend.DefaultStateName)
+			if diags.HasErrors() {
+				return diags.Err()
+			}
+		}
+	}
+
+	// Determine migration behavior based on whether the source/destination
+	// supports multi-state.
+	switch {
+	case sourceTFC || destinationTFC:
+		return m.backendMigrateTFC(opts)
+
+	// Single-state to single-state. This is the easiest case: we just
+	// copy the default state directly.
+	case sourceSingleState && destinationSingleState:
+		return m.backendMigrateState_s_s(opts)
+
+	// Single-state to multi-state. This is easy since we just copy
+	// the default state and ignore the rest in the destination.
+	case sourceSingleState && !destinationSingleState:
+		return m.backendMigrateState_s_s(opts)
+
+	// Multi-state to single-state. If the source has more than the default
+	// state this is complicated since we have to ask the user what to do.
+	case !sourceSingleState && destinationSingleState:
+		// If the source only has one state and it is the default,
+		// treat it as if it doesn't support multi-state.
+		if len(sourceWorkspaces) == 1 && sourceWorkspaces[0] == backend.DefaultStateName {
+			return m.backendMigrateState_s_s(opts)
+		}
+
+		return m.backendMigrateState_S_s(opts)
+
+	// Multi-state to multi-state. We merge the states together (migrating
+	// each from the source to the destination one by one).
+	case !sourceSingleState && !destinationSingleState:
+		// If the source only has one state and it is the default,
+		// treat it as if it doesn't support multi-state.
+		if len(sourceWorkspaces) == 1 && sourceWorkspaces[0] == backend.DefaultStateName {
+			return m.backendMigrateState_s_s(opts)
+		}
+
+		return m.backendMigrateState_S_S(opts)
+	}
+
+	return nil
+}
+
+//-------------------------------------------------------------------
+// State Migration Scenarios
+//
+// The functions below cover handling all the various scenarios that
+// can exist when migrating state. They are named in an immediately not
+// obvious format but is simple:
+//
+// Format: backendMigrateState_s1_s2[_suffix]
+//
+// When s1 or s2 is lower case, it means that it is a single state backend.
+// When either is uppercase, it means that state is a multi-state backend.
+// The suffix is used to disambiguate multiple cases with the same type of
+// states.
+//
+//-------------------------------------------------------------------
+
+// Multi-state to multi-state.
+func (m *Meta) backendMigrateState_S_S(opts *backendMigrateOpts) error {
+	log.Print("[INFO] backendMigrateState: migrating all named workspaces")
+
+	migrate := opts.force
+	if !migrate {
+		var err error
+		// Ask the user if they want to migrate their existing remote state
+		migrate, err = m.confirm(&terraform.InputOpts{
+			Id: "backend-migrate-multistate-to-multistate",
+			Query: fmt.Sprintf(
+				"Do you want to migrate all workspaces to %q?",
+				opts.DestinationType),
+			Description: fmt.Sprintf(
+				strings.TrimSpace(inputBackendMigrateMultiToMulti),
+				opts.SourceType, opts.DestinationType),
+		})
+		if err != nil {
+			return fmt.Errorf(
+				"Error asking for state migration action: %s", err)
+		}
+	}
+	if !migrate {
+		return fmt.Errorf("Migration aborted by user.")
+	}
+
+	// Read all the states
+	sourceWorkspaces, err := opts.Source.Workspaces()
+	if err != nil {
+		return fmt.Errorf(strings.TrimSpace(
+			errMigrateLoadStates), opts.SourceType, err)
+	}
+
+	// Sort the states so they're always copied alphabetically
+	sort.Strings(sourceWorkspaces)
+
+	// Go through each and migrate
+	for _, name := range sourceWorkspaces {
+		// Copy the same names
+		opts.sourceWorkspace = name
+		opts.destinationWorkspace = name
+
+		// Force it, we confirmed above
+		opts.force = true
+
+		// Perform the migration
+		if err := m.backendMigrateState_s_s(opts); err != nil {
+			return fmt.Errorf(strings.TrimSpace(
+				errMigrateMulti), name, opts.SourceType, opts.DestinationType, err)
+		}
+	}
+
+	return nil
+}
+
+// Multi-state to single state.
+func (m *Meta) backendMigrateState_S_s(opts *backendMigrateOpts) error {
+	log.Printf("[INFO] backendMigrateState: destination backend type %q does not support named workspaces", opts.DestinationType)
+
+	currentWorkspace, err := m.Workspace()
+	if err != nil {
+		return err
+	}
+
+	migrate := opts.force
+	if !migrate {
+		var err error
+		// Ask the user if they want to migrate their existing remote state
+		migrate, err = m.confirm(&terraform.InputOpts{
+			Id: "backend-migrate-multistate-to-single",
+			Query: fmt.Sprintf(
+				"Destination state %q doesn't support workspaces.\n"+
+					"Do you want to copy only your current workspace?",
+				opts.DestinationType),
+			Description: fmt.Sprintf(
+				strings.TrimSpace(inputBackendMigrateMultiToSingle),
+				opts.SourceType, opts.DestinationType, currentWorkspace),
+		})
+		if err != nil {
+			return fmt.Errorf(
+				"Error asking for state migration action: %s", err)
+		}
+	}
+
+	if !migrate {
+		return fmt.Errorf("Migration aborted by user.")
+	}
+
+	// Copy the default state
+	opts.sourceWorkspace = currentWorkspace
+
+	// now switch back to the default env so we can acccess the new backend
+	m.SetWorkspace(backend.DefaultStateName)
+
+	return m.backendMigrateState_s_s(opts)
+}
+
+// Single state to single state, assumed default state name.
+func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
+	log.Printf("[INFO] backendMigrateState: single-to-single migrating %q workspace to %q workspace", opts.sourceWorkspace, opts.destinationWorkspace)
+
+	sourceState, err := opts.Source.StateMgr(opts.sourceWorkspace)
+	if err != nil {
+		return fmt.Errorf(strings.TrimSpace(
+			errMigrateSingleLoadDefault), opts.SourceType, err)
+	}
+	if err := sourceState.RefreshState(); err != nil {
+		return fmt.Errorf(strings.TrimSpace(
+			errMigrateSingleLoadDefault), opts.SourceType, err)
+	}
+
+	// Do not migrate workspaces without state.
+	if sourceState.State().Empty() {
+		log.Print("[TRACE] backendMigrateState: source workspace has empty state, so nothing to migrate")
+		return nil
+	}
+
+	destinationState, err := opts.Destination.StateMgr(opts.destinationWorkspace)
+	if err == backend.ErrDefaultWorkspaceNotSupported {
+		// If the backend doesn't support using the default state, we ask the user
+		// for a new name and migrate the default state to the given named state.
+		destinationState, err = func() (statemgr.Full, error) {
+			log.Print("[TRACE] backendMigrateState: destination doesn't support a default workspace, so we must prompt for a new name")
+			name, err := m.promptNewWorkspaceName(opts.DestinationType)
+			if err != nil {
+				return nil, err
+			}
+
+			// Update the name of the destination state.
+			opts.destinationWorkspace = name
+
+			destinationState, err := opts.Destination.StateMgr(opts.destinationWorkspace)
+			if err != nil {
+				return nil, err
+			}
+
+			// Ignore invalid workspace name as it is irrelevant in this context.
+			workspace, _ := m.Workspace()
+
+			// If the currently selected workspace is the default workspace, then set
+			// the named workspace as the new selected workspace.
+			if workspace == backend.DefaultStateName {
+				if err := m.SetWorkspace(opts.destinationWorkspace); err != nil {
+					return nil, fmt.Errorf("Failed to set new workspace: %s", err)
+				}
+			}
+
+			return destinationState, nil
+		}()
+	}
+	if err != nil {
+		return fmt.Errorf(strings.TrimSpace(
+			errMigrateSingleLoadDefault), opts.DestinationType, err)
+	}
+	if err := destinationState.RefreshState(); err != nil {
+		return fmt.Errorf(strings.TrimSpace(
+			errMigrateSingleLoadDefault), opts.DestinationType, err)
+	}
+
+	// Check if we need migration at all.
+	// This is before taking a lock, because they may also correspond to the same lock.
+	source := sourceState.State()
+	destination := destinationState.State()
+
+	// no reason to migrate if the state is already there
+	if source.Equal(destination) {
+		// Equal isn't identical; it doesn't check lineage.
+		sm1, _ := sourceState.(statemgr.PersistentMeta)
+		sm2, _ := destinationState.(statemgr.PersistentMeta)
+		if source != nil && destination != nil {
+			if sm1 == nil || sm2 == nil {
+				log.Print("[TRACE] backendMigrateState: both source and destination workspaces have no state, so no migration is needed")
+				return nil
+			}
+			if sm1.StateSnapshotMeta().Lineage == sm2.StateSnapshotMeta().Lineage {
+				log.Printf("[TRACE] backendMigrateState: both source and destination workspaces have equal state with lineage %q, so no migration is needed", sm1.StateSnapshotMeta().Lineage)
+				return nil
+			}
+		}
+	}
+
+	if m.stateLock {
+		lockCtx := context.Background()
+		vt := arguments.ViewJSON
+		// Set default viewtype if none was set as the StateLocker needs to know exactly
+		// what viewType we want to have.
+		if opts == nil || opts.ViewType != vt {
+			vt = arguments.ViewHuman
+		}
+		view := views.NewStateLocker(vt, m.View)
+		locker := clistate.NewLocker(m.stateLockTimeout, view)
+
+		lockerSource := locker.WithContext(lockCtx)
+		if diags := lockerSource.Lock(sourceState, "migration source state"); diags.HasErrors() {
+			return diags.Err()
+		}
+		defer lockerSource.Unlock()
+
+		lockerDestination := locker.WithContext(lockCtx)
+		if diags := lockerDestination.Lock(destinationState, "migration destination state"); diags.HasErrors() {
+			return diags.Err()
+		}
+		defer lockerDestination.Unlock()
+
+		// We now own a lock, so double check that we have the version
+		// corresponding to the lock.
+		log.Print("[TRACE] backendMigrateState: refreshing source workspace state")
+		if err := sourceState.RefreshState(); err != nil {
+			return fmt.Errorf(strings.TrimSpace(
+				errMigrateSingleLoadDefault), opts.SourceType, err)
+		}
+		log.Print("[TRACE] backendMigrateState: refreshing destination workspace state")
+		if err := destinationState.RefreshState(); err != nil {
+			return fmt.Errorf(strings.TrimSpace(
+				errMigrateSingleLoadDefault), opts.SourceType, err)
+		}
+
+		source = sourceState.State()
+		destination = destinationState.State()
+	}
+
+	var confirmFunc func(statemgr.Full, statemgr.Full, *backendMigrateOpts) (bool, error)
+	switch {
+	// No migration necessary
+	case source.Empty() && destination.Empty():
+		log.Print("[TRACE] backendMigrateState: both source and destination workspaces have empty state, so no migration is required")
+		return nil
+
+	// No migration necessary if we're inheriting state.
+	case source.Empty() && !destination.Empty():
+		log.Print("[TRACE] backendMigrateState: source workspace has empty state, so no migration is required")
+		return nil
+
+	// We have existing state moving into no state. Ask the user if
+	// they'd like to do this.
+	case !source.Empty() && destination.Empty():
+		if opts.SourceType == "cloud" || opts.DestinationType == "cloud" {
+			// HACK: backendMigrateTFC has its own earlier prompt for
+			// whether to migrate state in the cloud case, so we'll skip
+			// this later prompt for Cloud, even though we do still need it
+			// for state backends.
+			confirmFunc = func(statemgr.Full, statemgr.Full, *backendMigrateOpts) (bool, error) {
+				return true, nil // the answer is implied to be "yes" if we reached this point
+			}
+		} else {
+			log.Print("[TRACE] backendMigrateState: destination workspace has empty state, so might copy source workspace state")
+			confirmFunc = m.backendMigrateEmptyConfirm
+		}
+
+	// Both states are non-empty, meaning we need to determine which
+	// state should be used and update accordingly.
+	case !source.Empty() && !destination.Empty():
+		log.Print("[TRACE] backendMigrateState: both source and destination workspaces have states, so might overwrite destination with source")
+		confirmFunc = m.backendMigrateNonEmptyConfirm
+	}
+
+	if confirmFunc == nil {
+		panic("confirmFunc must not be nil")
+	}
+
+	if !opts.force {
+		// Abort if we can't ask for input.
+		if !m.input {
+			log.Print("[TRACE] backendMigrateState: can't prompt for input, so aborting migration")
+			return errors.New(strings.TrimSpace(errInteractiveInputDisabled))
+		}
+
+		// Confirm with the user whether we want to copy state over
+		confirm, err := confirmFunc(sourceState, destinationState, opts)
+		if err != nil {
+			log.Print("[TRACE] backendMigrateState: error reading input, so aborting migration")
+			return err
+		}
+		if !confirm {
+			log.Print("[TRACE] backendMigrateState: user cancelled at confirmation prompt, so aborting migration")
+			return nil
+		}
+	}
+
+	// Confirmed! We'll have the statemgr package handle the migration, which
+	// includes preserving any lineage/serial information where possible, if
+	// both managers support such metadata.
+	log.Print("[TRACE] backendMigrateState: migration confirmed, so migrating")
+	if err := statemgr.Migrate(destinationState, sourceState); err != nil {
+		return fmt.Errorf(strings.TrimSpace(errBackendStateCopy),
+			opts.SourceType, opts.DestinationType, err)
+	}
+	// The backend is currently handled before providers are installed during init,
+	// so requiring schemas here could lead to a catch-22 where it requires some manual
+	// intervention to proceed far enough for provider installation. To avoid this,
+	// when migrating to TFC backend, the initial JSON varient of state won't be generated and stored.
+	if err := destinationState.PersistState(nil); err != nil {
+		return fmt.Errorf(strings.TrimSpace(errBackendStateCopy),
+			opts.SourceType, opts.DestinationType, err)
+	}
+
+	// And we're done.
+	return nil
+}
+
+func (m *Meta) backendMigrateEmptyConfirm(source, destination statemgr.Full, opts *backendMigrateOpts) (bool, error) {
+	var inputOpts *terraform.InputOpts
+	if opts.DestinationType == "cloud" {
+		inputOpts = &terraform.InputOpts{
+			Id:          "backend-migrate-copy-to-empty-cloud",
+			Query:       "Do you want to copy existing state to Terraform Cloud?",
+			Description: fmt.Sprintf(strings.TrimSpace(inputBackendMigrateEmptyCloud), opts.SourceType),
+		}
+	} else {
+		inputOpts = &terraform.InputOpts{
+			Id:    "backend-migrate-copy-to-empty",
+			Query: "Do you want to copy existing state to the new backend?",
+			Description: fmt.Sprintf(
+				strings.TrimSpace(inputBackendMigrateEmpty),
+				opts.SourceType, opts.DestinationType),
+		}
+	}
+
+	return m.confirm(inputOpts)
+}
+
+func (m *Meta) backendMigrateNonEmptyConfirm(
+	sourceState, destinationState statemgr.Full, opts *backendMigrateOpts) (bool, error) {
+	// We need to grab both states so we can write them to a file
+	source := sourceState.State()
+	destination := destinationState.State()
+
+	// Save both to a temporary
+	td, err := ioutil.TempDir("", "terraform")
+	if err != nil {
+		return false, fmt.Errorf("Error creating temporary directory: %s", err)
+	}
+	defer os.RemoveAll(td)
+
+	// Helper to write the state
+	saveHelper := func(n, path string, s *states.State) error {
+		mgr := statemgr.NewFilesystem(path)
+		return mgr.WriteState(s)
+	}
+
+	// Write the states
+	sourcePath := filepath.Join(td, fmt.Sprintf("1-%s.tfstate", opts.SourceType))
+	destinationPath := filepath.Join(td, fmt.Sprintf("2-%s.tfstate", opts.DestinationType))
+	if err := saveHelper(opts.SourceType, sourcePath, source); err != nil {
+		return false, fmt.Errorf("Error saving temporary state: %s", err)
+	}
+	if err := saveHelper(opts.DestinationType, destinationPath, destination); err != nil {
+		return false, fmt.Errorf("Error saving temporary state: %s", err)
+	}
+
+	// Ask for confirmation
+	var inputOpts *terraform.InputOpts
+	if opts.DestinationType == "cloud" {
+		inputOpts = &terraform.InputOpts{
+			Id:    "backend-migrate-to-tfc",
+			Query: "Do you want to copy existing state to Terraform Cloud?",
+			Description: fmt.Sprintf(
+				strings.TrimSpace(inputBackendMigrateNonEmptyCloud),
+				opts.SourceType, sourcePath, destinationPath),
+		}
+	} else {
+		inputOpts = &terraform.InputOpts{
+			Id:    "backend-migrate-to-backend",
+			Query: "Do you want to copy existing state to the new backend?",
+			Description: fmt.Sprintf(
+				strings.TrimSpace(inputBackendMigrateNonEmpty),
+				opts.SourceType, opts.DestinationType, sourcePath, destinationPath),
+		}
+	}
+
+	// Confirm with the user that the copy should occur
+	return m.confirm(inputOpts)
+}
+
+func retrieveWorkspaces(back backend.Backend, sourceType string) ([]string, bool, error) {
+	var singleState bool
+	var err error
+	workspaces, err := back.Workspaces()
+	if err == backend.ErrWorkspacesNotSupported {
+		singleState = true
+		err = nil
+	}
+	if err != nil {
+		return nil, singleState, fmt.Errorf(strings.TrimSpace(
+			errMigrateLoadStates), sourceType, err)
+	}
+
+	return workspaces, singleState, err
+}
+
+func (m *Meta) backendMigrateTFC(opts *backendMigrateOpts) error {
+	_, sourceTFC := opts.Source.(*cloud.Cloud)
+	cloudBackendDestination, destinationTFC := opts.Destination.(*cloud.Cloud)
+
+	sourceWorkspaces, sourceSingleState, err := retrieveWorkspaces(opts.Source, opts.SourceType)
+	if err != nil {
+		return err
+	}
+	//to be used below, not yet implamented
+	// destinationWorkspaces, destinationSingleState
+	_, _, err = retrieveWorkspaces(opts.Destination, opts.SourceType)
+	if err != nil {
+		return err
+	}
+
+	// from TFC to non-TFC backend
+	if sourceTFC && !destinationTFC {
+		// From Terraform Cloud to another backend. This is not yet implemented, and
+		// we recommend people to use the TFC API.
+		return fmt.Errorf(strings.TrimSpace(errTFCMigrateNotYetImplemented))
+	}
+
+	// Everything below, by the above two conditionals, now assumes that the
+	// destination is always Terraform Cloud (TFC).
+
+	sourceSingle := sourceSingleState || (len(sourceWorkspaces) == 1)
+	if sourceSingle {
+		if cloudBackendDestination.WorkspaceMapping.Strategy() == cloud.WorkspaceNameStrategy {
+			// If we know the name via WorkspaceNameStrategy, then set the
+			// destinationWorkspace to the new Name and skip the user prompt. Here the
+			// destinationWorkspace is not set to `default` thereby we will create it
+			// in TFC if it does not exist.
+			opts.destinationWorkspace = cloudBackendDestination.WorkspaceMapping.Name
+		}
+
+		currentWorkspace, err := m.Workspace()
+		if err != nil {
+			return err
+		}
+		opts.sourceWorkspace = currentWorkspace
+
+		log.Printf("[INFO] backendMigrateTFC: single-to-single migration from source %s to destination %q", opts.sourceWorkspace, opts.destinationWorkspace)
+
+		// If the current workspace is has no state we do not need to ask
+		// if they want to migrate the state.
+		sourceState, err := opts.Source.StateMgr(currentWorkspace)
+		if err != nil {
+			return err
+		}
+		if err := sourceState.RefreshState(); err != nil {
+			return err
+		}
+		if sourceState.State().Empty() {
+			log.Printf("[INFO] backendMigrateTFC: skipping migration because source %s is empty", opts.sourceWorkspace)
+			return nil
+		}
+
+		// Run normal single-to-single state migration.
+		// This will handle both situations where the new cloud backend
+		// configuration is using a workspace.name strategy or workspace.tags
+		// strategy.
+		//
+		// We do prompt first though, because state migration is mandatory
+		// for moving to Cloud and the user should get an opportunity to
+		// confirm that first.
+		if migrate, err := m.promptSingleToCloudSingleStateMigration(opts); err != nil {
+			return err
+		} else if !migrate {
+			return nil //skip migrating but return successfully
+		}
+
+		return m.backendMigrateState_s_s(opts)
+	}
+
+	destinationTagsStrategy := cloudBackendDestination.WorkspaceMapping.Strategy() == cloud.WorkspaceTagsStrategy
+	destinationNameStrategy := cloudBackendDestination.WorkspaceMapping.Strategy() == cloud.WorkspaceNameStrategy
+
+	multiSource := !sourceSingleState && len(sourceWorkspaces) > 1
+	if multiSource && destinationNameStrategy {
+		currentWorkspace, err := m.Workspace()
+		if err != nil {
+			return err
+		}
+
+		opts.sourceWorkspace = currentWorkspace
+		opts.destinationWorkspace = cloudBackendDestination.WorkspaceMapping.Name
+		if err := m.promptMultiToSingleCloudMigration(opts); err != nil {
+			return err
+		}
+
+		log.Printf("[INFO] backendMigrateTFC: multi-to-single migration from source %s to destination %q", opts.sourceWorkspace, opts.destinationWorkspace)
+
+		return m.backendMigrateState_s_s(opts)
+	}
+
+	// Multiple sources, and using tags strategy. So migrate every source
+	// workspace over to new one, prompt for workspace name pattern (*),
+	// and start migrating, and create tags for each workspace.
+	if multiSource && destinationTagsStrategy {
+		log.Printf("[INFO] backendMigrateTFC: multi-to-multi migration from source workspaces %q", sourceWorkspaces)
+		return m.backendMigrateState_S_TFC(opts, sourceWorkspaces)
+	}
+
+	// TODO(omar): after the check for sourceSingle is done, everything following
+	// it has to be multi. So rework the code to not need to check for multi, adn
+	// return m.backendMigrateState_S_TFC here.
+	return nil
+}
+
+// migrates a multi-state backend to Terraform Cloud
+func (m *Meta) backendMigrateState_S_TFC(opts *backendMigrateOpts, sourceWorkspaces []string) error {
+	log.Print("[TRACE] backendMigrateState: migrating all named workspaces")
+
+	currentWorkspace, err := m.Workspace()
+	if err != nil {
+		return err
+	}
+	newCurrentWorkspace := ""
+
+	// This map is used later when doing the migration per source/destination.
+	// If a source has 'default' and has state, then we ask what the new name should be.
+	// And further down when we actually run state migration for each
+	// source/destination workspace, we use this new name (where source is 'default')
+	// and set as destinationWorkspace. If the default workspace does not have
+	// state we will not prompt the user for a new name because empty workspaces
+	// do not get migrated.
+	defaultNewName := map[string]string{}
+	for i := 0; i < len(sourceWorkspaces); i++ {
+		if sourceWorkspaces[i] == backend.DefaultStateName {
+			// For the default workspace we want to look to see if there is any state
+			// before we ask for a workspace name to migrate the default workspace into.
+			sourceState, err := opts.Source.StateMgr(backend.DefaultStateName)
+			if err != nil {
+				return fmt.Errorf(strings.TrimSpace(
+					errMigrateSingleLoadDefault), opts.SourceType, err)
+			}
+			// RefreshState is what actually pulls the state to be evaluated.
+			if err := sourceState.RefreshState(); err != nil {
+				return fmt.Errorf(strings.TrimSpace(
+					errMigrateSingleLoadDefault), opts.SourceType, err)
+			}
+			if !sourceState.State().Empty() {
+				newName, err := m.promptNewWorkspaceName(opts.DestinationType)
+				if err != nil {
+					return err
+				}
+				defaultNewName[sourceWorkspaces[i]] = newName
+			}
+		}
+	}
+
+	// Fetch the pattern that will be used to rename the workspaces for Terraform Cloud.
+	//
+	// * For the general case, this will be a pattern provided by the user.
+	//
+	// * Specifically for a migration from the "remote" backend using 'prefix', we will
+	//   instead 'migrate' the workspaces using a pattern based on the old prefix+name,
+	//   not allowing a user to accidentally input the wrong pattern to line up with
+	//   what the the remote backend was already using before (which presumably already
+	//   meets the naming considerations for Terraform Cloud).
+	//   In other words, this is a fast-track migration path from the remote backend, retaining
+	//   how things already are in Terraform Cloud with no user intervention needed.
+	pattern := ""
+	if remoteBackend, ok := opts.Source.(*remote.Remote); ok {
+		if err := m.promptRemotePrefixToCloudTagsMigration(opts); err != nil {
+			return err
+		}
+		pattern = remoteBackend.WorkspaceNamePattern()
+		log.Printf("[TRACE] backendMigrateTFC: Remote backend reports workspace name pattern as: %q", pattern)
+	}
+
+	if pattern == "" {
+		pattern, err = m.promptMultiStateMigrationPattern(opts.SourceType)
+		if err != nil {
+			return err
+		}
+	}
+
+	// Go through each and migrate
+	for _, name := range sourceWorkspaces {
+
+		// Copy the same names
+		opts.sourceWorkspace = name
+		if newName, ok := defaultNewName[name]; ok {
+			// this has to be done before setting destinationWorkspace
+			name = newName
+		}
+		opts.destinationWorkspace = strings.Replace(pattern, "*", name, -1)
+
+		// Force it, we confirmed above
+		opts.force = true
+
+		// Perform the migration
+		log.Printf("[INFO] backendMigrateTFC: multi-to-multi migration, source workspace %q to destination workspace %q", opts.sourceWorkspace, opts.destinationWorkspace)
+		if err := m.backendMigrateState_s_s(opts); err != nil {
+			return fmt.Errorf(strings.TrimSpace(
+				errMigrateMulti), name, opts.SourceType, opts.DestinationType, err)
+		}
+
+		if currentWorkspace == opts.sourceWorkspace {
+			newCurrentWorkspace = opts.destinationWorkspace
+		}
+	}
+
+	// After migrating multiple workspaces, we need to reselect the current workspace as it may
+	// have been renamed. Query the backend first to be sure it now exists.
+	workspaces, err := opts.Destination.Workspaces()
+	if err != nil {
+		return err
+	}
+
+	var workspacePresent bool
+	for _, name := range workspaces {
+		if name == newCurrentWorkspace {
+			workspacePresent = true
+		}
+	}
+
+	// If we couldn't select the workspace automatically from the backend (maybe it was empty
+	// and wasn't migrated, for instance), ask the user to select one instead and be done.
+	if !workspacePresent {
+		if err = m.selectWorkspace(opts.Destination); err != nil {
+			return err
+		}
+		return nil
+	}
+
+	// The newly renamed current workspace is present, so we'll automatically select it for the
+	// user, as well as display the equivalent of 'workspace list' to show how the workspaces
+	// were changed (as well as the newly selected current workspace).
+	if err = m.SetWorkspace(newCurrentWorkspace); err != nil {
+		return err
+	}
+
+	m.Ui.Output(m.Colorize().Color("[reset][bold]Migration complete! Your workspaces are as follows:[reset]"))
+	var out bytes.Buffer
+	for _, name := range workspaces {
+		if name == newCurrentWorkspace {
+			out.WriteString("* ")
+		} else {
+			out.WriteString("  ")
+		}
+		out.WriteString(name + "\n")
+	}
+
+	m.Ui.Output(out.String())
+
+	return nil
+}
+
+func (m *Meta) promptSingleToCloudSingleStateMigration(opts *backendMigrateOpts) (bool, error) {
+	if !m.input {
+		log.Print("[TRACE] backendMigrateState: can't prompt for input, so aborting migration")
+		return false, errors.New(strings.TrimSpace(errInteractiveInputDisabled))
+	}
+	migrate := opts.force
+	if !migrate {
+		var err error
+		migrate, err = m.confirm(&terraform.InputOpts{
+			Id:          "backend-migrate-state-single-to-cloud-single",
+			Query:       "Do you wish to proceed?",
+			Description: strings.TrimSpace(tfcInputBackendMigrateStateSingleToCloudSingle),
+		})
+		if err != nil {
+			return false, fmt.Errorf("Error asking for state migration action: %s", err)
+		}
+	}
+
+	return migrate, nil
+}
+
+func (m *Meta) promptRemotePrefixToCloudTagsMigration(opts *backendMigrateOpts) error {
+	if !m.input {
+		log.Print("[TRACE] backendMigrateState: can't prompt for input, so aborting migration")
+		return errors.New(strings.TrimSpace(errInteractiveInputDisabled))
+	}
+	migrate := opts.force
+	if !migrate {
+		var err error
+		migrate, err = m.confirm(&terraform.InputOpts{
+			Id:          "backend-migrate-remote-multistate-to-cloud",
+			Query:       "Do you wish to proceed?",
+			Description: strings.TrimSpace(tfcInputBackendMigrateRemoteMultiToCloud),
+		})
+		if err != nil {
+			return fmt.Errorf("Error asking for state migration action: %s", err)
+		}
+	}
+
+	if !migrate {
+		return fmt.Errorf("Migration aborted by user.")
+	}
+
+	return nil
+}
+
+// Multi-state to single state.
+func (m *Meta) promptMultiToSingleCloudMigration(opts *backendMigrateOpts) error {
+	if !m.input {
+		log.Print("[TRACE] backendMigrateState: can't prompt for input, so aborting migration")
+		return errors.New(strings.TrimSpace(errInteractiveInputDisabled))
+	}
+	migrate := opts.force
+	if !migrate {
+		var err error
+		// Ask the user if they want to migrate their existing remote state
+		migrate, err = m.confirm(&terraform.InputOpts{
+			Id:    "backend-migrate-multistate-to-single",
+			Query: "Do you want to copy only your current workspace?",
+			Description: fmt.Sprintf(
+				strings.TrimSpace(tfcInputBackendMigrateMultiToSingle),
+				opts.SourceType, opts.destinationWorkspace),
+		})
+		if err != nil {
+			return fmt.Errorf("Error asking for state migration action: %s", err)
+		}
+	}
+
+	if !migrate {
+		return fmt.Errorf("Migration aborted by user.")
+	}
+
+	return nil
+}
+
+func (m *Meta) promptNewWorkspaceName(destinationType string) (string, error) {
+	message := fmt.Sprintf("[reset][bold][yellow]The %q backend configuration only allows "+
+		"named workspaces![reset]", destinationType)
+	if destinationType == "cloud" {
+		if !m.input {
+			log.Print("[TRACE] backendMigrateState: can't prompt for input, so aborting migration")
+			return "", errors.New(strings.TrimSpace(errInteractiveInputDisabled))
+		}
+		message = `[reset][bold][yellow]Terraform Cloud requires all workspaces to be given an explicit name.[reset]`
+	}
+	name, err := m.UIInput().Input(context.Background(), &terraform.InputOpts{
+		Id:          "new-state-name",
+		Query:       message,
+		Description: strings.TrimSpace(inputBackendNewWorkspaceName),
+	})
+	if err != nil {
+		return "", fmt.Errorf("Error asking for new state name: %s", err)
+	}
+
+	return name, nil
+}
+
+func (m *Meta) promptMultiStateMigrationPattern(sourceType string) (string, error) {
+	// This is not the first prompt a user would be presented with in the migration to TFC, so no
+	// guard on m.input is needed here.
+	renameWorkspaces, err := m.UIInput().Input(context.Background(), &terraform.InputOpts{
+		Id:          "backend-migrate-multistate-to-tfc",
+		Query:       fmt.Sprintf("[reset][bold][yellow]%s[reset]", "Would you like to rename your workspaces?"),
+		Description: fmt.Sprintf(strings.TrimSpace(tfcInputBackendMigrateMultiToMulti), sourceType),
+	})
+	if err != nil {
+		return "", fmt.Errorf("Error asking for state migration action: %s", err)
+	}
+	if renameWorkspaces != "2" && renameWorkspaces != "1" {
+		return "", fmt.Errorf("Please select 1 or 2 as part of this option.")
+	}
+	if renameWorkspaces == "2" {
+		// this means they did not want to rename their workspaces, and we are
+		// returning a generic '*' that means use the same workspace name during
+		// migration.
+		return "*", nil
+	}
+
+	pattern, err := m.UIInput().Input(context.Background(), &terraform.InputOpts{
+		Id:          "backend-migrate-multistate-to-tfc-pattern",
+		Query:       fmt.Sprintf("[reset][bold][yellow]%s[reset]", "How would you like to rename your workspaces?"),
+		Description: strings.TrimSpace(tfcInputBackendMigrateMultiToMultiPattern),
+	})
+	if err != nil {
+		return "", fmt.Errorf("Error asking for state migration action: %s", err)
+	}
+	if !strings.Contains(pattern, "*") {
+		return "", fmt.Errorf("The pattern must have an '*'")
+	}
+
+	if count := strings.Count(pattern, "*"); count > 1 {
+		return "", fmt.Errorf("The pattern '*' cannot be used more than once.")
+	}
+
+	return pattern, nil
+}
+
+const errMigrateLoadStates = `
+Error inspecting states in the %q backend:
+    %s
+
+Prior to changing backends, Terraform inspects the source and destination
+states to determine what kind of migration steps need to be taken, if any.
+Terraform failed to load the states. The data in both the source and the
+destination remain unmodified. Please resolve the above error and try again.
+`
+
+const errMigrateSingleLoadDefault = `
+Error loading state:
+    %[2]s
+
+Terraform failed to load the default state from the %[1]q backend.
+State migration cannot occur unless the state can be loaded. Backend
+modification and state migration has been aborted. The state in both the
+source and the destination remain unmodified. Please resolve the
+above error and try again.
+`
+
+const errMigrateMulti = `
+Error migrating the workspace %q from the previous %q backend
+to the newly configured %q backend:
+    %s
+
+Terraform copies workspaces in alphabetical order. Any workspaces
+alphabetically earlier than this one have been copied. Any workspaces
+later than this haven't been modified in the destination. No workspaces
+in the source state have been modified.
+
+Please resolve the error above and run the initialization command again.
+This will attempt to copy (with permission) all workspaces again.
+`
+
+const errBackendStateCopy = `
+Error copying state from the previous %q backend to the newly configured
+%q backend:
+    %s
+
+The state in the previous backend remains intact and unmodified. Please resolve
+the error above and try again.
+`
+
+const errTFCMigrateNotYetImplemented = `
+Migrating state from Terraform Cloud to another backend is not yet implemented.
+
+Please use the API to do this: https://www.terraform.io/docs/cloud/api/state-versions.html
+`
+
+const errInteractiveInputDisabled = `
+Can't ask approval for state migration when interactive input is disabled.
+
+Please remove the "-input=false" option and try again.
+`
+
+const tfcInputBackendMigrateMultiToMultiPattern = `
+Enter a pattern with an asterisk (*) to rename all workspaces based on their
+previous names. The asterisk represents the current workspace name.
+
+For example, if a workspace is currently named 'prod', the pattern 'app-*' would yield
+'app-prod' for a new workspace name; 'app-*-region1' would  yield 'app-prod-region1'.
+`
+
+const tfcInputBackendMigrateMultiToMulti = `
+Unlike typical Terraform workspaces representing an environment associated with a particular
+configuration (e.g. production, staging, development), Terraform Cloud workspaces are named uniquely
+across all configurations used within an organization. A typical strategy to start with is
+<COMPONENT>-<ENVIRONMENT>-<REGION> (e.g. networking-prod-us-east, networking-staging-us-east).
+
+For more information on workspace naming, see https://www.terraform.io/docs/cloud/workspaces/naming.html
+
+When migrating existing workspaces from the backend %[1]q to Terraform Cloud, would you like to
+rename your workspaces? Enter 1 or 2.
+
+1. Yes, I'd like to rename all workspaces according to a pattern I will provide.
+2. No, I would not like to rename my workspaces. Migrate them as currently named.
+`
+
+const tfcInputBackendMigrateMultiToSingle = `
+The previous backend %[1]q has multiple workspaces, but Terraform Cloud has
+been configured to use a single workspace (%[2]q). By continuing, you will
+only migrate your current workspace. If you wish to migrate all workspaces
+from the previous backend, you may cancel this operation and use the 'tags'
+strategy in your workspace configuration block instead.
+
+Enter "yes" to proceed or "no" to cancel.
+`
+
+const tfcInputBackendMigrateStateSingleToCloudSingle = `
+As part of migrating to Terraform Cloud, Terraform can optionally copy your
+current workspace state to the configured Terraform Cloud workspace.
+
+Answer "yes" to copy the latest state snapshot to the configured
+Terraform Cloud workspace.
+
+Answer "no" to ignore the existing state and just activate the configured
+Terraform Cloud workspace with its existing state, if any.
+
+Should Terraform migrate your existing state?
+`
+
+const tfcInputBackendMigrateRemoteMultiToCloud = `
+When migrating from the 'remote' backend to Terraform's native integration
+with Terraform Cloud, Terraform will automatically create or use existing
+workspaces based on the previous backend configuration's 'prefix' value.
+
+When the migration is complete, workspace names in Terraform will match the
+fully qualified Terraform Cloud workspace name. If necessary, the workspace
+tags configured in the 'cloud' option block will be added to the associated
+Terraform Cloud workspaces.
+
+Enter "yes" to proceed or "no" to cancel.
+`
+
+const inputBackendMigrateEmpty = `
+Pre-existing state was found while migrating the previous %q backend to the
+newly configured %q backend. No existing state was found in the newly
+configured %[2]q backend. Do you want to copy this state to the new %[2]q
+backend? Enter "yes" to copy and "no" to start with an empty state.
+`
+
+const inputBackendMigrateEmptyCloud = `
+Pre-existing state was found while migrating the previous %q backend to Terraform Cloud.
+No existing state was found in Terraform Cloud. Do you want to copy this state to Terraform Cloud?
+Enter "yes" to copy and "no" to start with an empty state.
+`
+
+const inputBackendMigrateNonEmpty = `
+Pre-existing state was found while migrating the previous %q backend to the
+newly configured %q backend. An existing non-empty state already exists in
+the new backend. The two states have been saved to temporary files that will be
+removed after responding to this query.
+
+Previous (type %[1]q): %[3]s
+New      (type %[2]q): %[4]s
+
+Do you want to overwrite the state in the new backend with the previous state?
+Enter "yes" to copy and "no" to start with the existing state in the newly
+configured %[2]q backend.
+`
+
+const inputBackendMigrateNonEmptyCloud = `
+Pre-existing state was found while migrating the previous %q backend to
+Terraform Cloud. An existing non-empty state already exists in Terraform Cloud.
+The two states have been saved to temporary files that will be removed after
+responding to this query.
+
+Previous (type %[1]q): %[2]s
+New      (Terraform Cloud): %[3]s
+
+Do you want to overwrite the state in Terraform Cloud with the previous state?
+Enter "yes" to copy and "no" to start with the existing state in Terraform Cloud.
+`
+
+const inputBackendMigrateMultiToSingle = `
+The existing %[1]q backend supports workspaces and you currently are
+using more than one. The newly configured %[2]q backend doesn't support
+workspaces. If you continue, Terraform will copy your current workspace %[3]q
+to the default workspace in the new backend. Your existing workspaces in the
+source backend won't be modified. If you want to switch workspaces, back them
+up, or cancel altogether, answer "no" and Terraform will abort.
+`
+
+const inputBackendMigrateMultiToMulti = `
+Both the existing %[1]q backend and the newly configured %[2]q backend
+support workspaces. When migrating between backends, Terraform will copy
+all workspaces (with the same names). THIS WILL OVERWRITE any conflicting
+states in the destination.
+
+Terraform initialization doesn't currently migrate only select workspaces.
+If you want to migrate a select number of workspaces, you must manually
+pull and push those states.
+
+If you answer "yes", Terraform will migrate all states. If you answer
+"no", Terraform will abort.
+`
+
+const inputBackendNewWorkspaceName = `
+Please provide a new workspace name (e.g. dev, test) that will be used
+to migrate the existing default workspace.
+`
+
+const inputBackendSelectWorkspace = `
+This is expected behavior when the selected workspace did not have an
+existing non-empty state. Please enter a number to select a workspace:
+
+%s
+`
diff --git a/v1.5.7/internal/command/meta_backend_migrate_test.go b/v1.5.7/internal/command/meta_backend_migrate_test.go
new file mode 100644
index 0000000..70c72f1
--- /dev/null
+++ b/v1.5.7/internal/command/meta_backend_migrate_test.go
@@ -0,0 +1,64 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"testing"
+)
+
+func TestBackendMigrate_promptMultiStatePattern(t *testing.T) {
+	// Setup the meta
+
+	cases := map[string]struct {
+		renamePrompt  string
+		patternPrompt string
+		expectedErr   string
+	}{
+		"valid pattern": {
+			renamePrompt:  "1",
+			patternPrompt: "hello-*",
+			expectedErr:   "",
+		},
+		"invalid pattern, only one asterisk allowed": {
+			renamePrompt:  "1",
+			patternPrompt: "hello-*-world-*",
+			expectedErr:   "The pattern '*' cannot be used more than once.",
+		},
+		"invalid pattern, missing asterisk": {
+			renamePrompt:  "1",
+			patternPrompt: "hello-world",
+			expectedErr:   "The pattern must have an '*'",
+		},
+		"invalid rename": {
+			renamePrompt: "3",
+			expectedErr:  "Please select 1 or 2 as part of this option.",
+		},
+		"no rename": {
+			renamePrompt: "2",
+		},
+	}
+	for name, tc := range cases {
+		t.Log("Test: ", name)
+		m := testMetaBackend(t, nil)
+		input := map[string]string{}
+		cleanup := testInputMap(t, input)
+		if tc.renamePrompt != "" {
+			input["backend-migrate-multistate-to-tfc"] = tc.renamePrompt
+		}
+		if tc.patternPrompt != "" {
+			input["backend-migrate-multistate-to-tfc-pattern"] = tc.patternPrompt
+		}
+
+		sourceType := "cloud"
+		_, err := m.promptMultiStateMigrationPattern(sourceType)
+		if tc.expectedErr == "" && err != nil {
+			t.Fatalf("expected error to be nil, but was %s", err.Error())
+		}
+		if tc.expectedErr != "" && tc.expectedErr != err.Error() {
+			t.Fatalf("expected error to eq %s but got %s", tc.expectedErr, err.Error())
+		}
+
+		cleanup()
+	}
+}
diff --git a/v1.5.7/internal/command/meta_backend_test.go b/v1.5.7/internal/command/meta_backend_test.go
new file mode 100644
index 0000000..8f29018
--- /dev/null
+++ b/v1.5.7/internal/command/meta_backend_test.go
@@ -0,0 +1,1967 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"reflect"
+	"sort"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/copy"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/mitchellh/cli"
+	"github.com/zclconf/go-cty/cty"
+
+	backendInit "github.com/hashicorp/terraform/internal/backend/init"
+	backendLocal "github.com/hashicorp/terraform/internal/backend/local"
+	backendInmem "github.com/hashicorp/terraform/internal/backend/remote-state/inmem"
+)
+
+// Test empty directory with no config/state creates a local state.
+func TestMetaBackend_emptyDir(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	// Get the backend
+	m := testMetaBackend(t, nil)
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Write some state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	s.WriteState(testState())
+	if err := s.PersistState(nil); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Verify it exists where we expect it to
+	if isEmptyState(DefaultStateFilename) {
+		t.Fatalf("no state was written")
+	}
+
+	// Verify no backup since it was empty to start
+	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
+		t.Fatal("backup state should be empty")
+	}
+
+	// Verify no backend state was made
+	if !isEmptyState(filepath.Join(m.DataDir(), DefaultStateFilename)) {
+		t.Fatal("backend state should be empty")
+	}
+}
+
+// check for no state. Either the file doesn't exist, or is empty
+func isEmptyState(path string) bool {
+	fi, err := os.Stat(path)
+	if os.IsNotExist(err) {
+		return true
+	}
+
+	if fi.Size() == 0 {
+		return true
+	}
+
+	return false
+}
+
+// Test a directory with a legacy state and no config continues to
+// use the legacy state.
+func TestMetaBackend_emptyWithDefaultState(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	// Write the legacy state
+	statePath := DefaultStateFilename
+	{
+		f, err := os.Create(statePath)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		err = writeStateForTesting(testState(), f)
+		f.Close()
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	// Get the backend
+	m := testMetaBackend(t, nil)
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if actual := s.State().String(); actual != testState().String() {
+		t.Fatalf("bad: %s", actual)
+	}
+
+	// Verify it exists where we expect it to
+	if _, err := os.Stat(DefaultStateFilename); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	stateName := filepath.Join(m.DataDir(), DefaultStateFilename)
+	if !isEmptyState(stateName) {
+		t.Fatal("expected no state at", stateName)
+	}
+
+	// Write some state
+	next := testState()
+	next.RootModule().SetOutputValue("foo", cty.StringVal("bar"), false)
+	s.WriteState(next)
+	if err := s.PersistState(nil); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Verify a backup was made since we're modifying a pre-existing state
+	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
+		t.Fatal("backup state should not be empty")
+	}
+}
+
+// Test an empty directory with an explicit state path (outside the dir)
+func TestMetaBackend_emptyWithExplicitState(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	// Create another directory to store our state
+	stateDir := t.TempDir()
+	os.MkdirAll(stateDir, 0755)
+
+	// Write the legacy state
+	statePath := filepath.Join(stateDir, "foo")
+	{
+		f, err := os.Create(statePath)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		err = writeStateForTesting(testState(), f)
+		f.Close()
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+	m.statePath = statePath
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if actual := s.State().String(); actual != testState().String() {
+		t.Fatalf("bad: %s", actual)
+	}
+
+	// Verify neither defaults exist
+	if _, err := os.Stat(DefaultStateFilename); err == nil {
+		t.Fatal("file should not exist")
+	}
+
+	stateName := filepath.Join(m.DataDir(), DefaultStateFilename)
+	if !isEmptyState(stateName) {
+		t.Fatal("expected no state at", stateName)
+	}
+
+	// Write some state
+	next := testState()
+	markStateForMatching(next, "bar") // just any change so it shows as different than before
+	s.WriteState(next)
+	if err := s.PersistState(nil); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Verify a backup was made since we're modifying a pre-existing state
+	if isEmptyState(statePath + DefaultBackupExtension) {
+		t.Fatal("backup state should not be empty")
+	}
+}
+
+// Verify that interpolations result in an error
+func TestMetaBackend_configureInterpolation(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-new-interp"), td)
+	defer testChdir(t, td)()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	_, err := m.Backend(&BackendOpts{Init: true})
+	if err == nil {
+		t.Fatal("should error")
+	}
+}
+
+// Newly configured backend
+func TestMetaBackend_configureNew(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-new"), td)
+	defer testChdir(t, td)()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state := s.State()
+	if state != nil {
+		t.Fatal("state should be nil")
+	}
+
+	// Write some state
+	state = states.NewState()
+	mark := markStateForMatching(state, "changing")
+
+	s.WriteState(state)
+	if err := s.PersistState(nil); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Verify the state is where we expect
+	{
+		f, err := os.Open("local-state.tfstate")
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		actual, err := statefile.Read(f)
+		f.Close()
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		assertStateHasMarker(t, actual.State, mark)
+	}
+
+	// Verify the default paths don't exist
+	if _, err := os.Stat(DefaultStateFilename); err == nil {
+		t.Fatal("file should not exist")
+	}
+
+	// Verify a backup doesn't exist
+	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
+		t.Fatal("file should not exist")
+	}
+}
+
+// Newly configured backend with prior local state and no remote state
+func TestMetaBackend_configureNewWithState(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-new-migrate"), td)
+	defer testChdir(t, td)()
+
+	// Ask input
+	defer testInteractiveInput(t, []string{"yes"})()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// This combination should not require the extra -migrate-state flag, since
+	// there is no existing backend config
+	m.migrateState = false
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state, err := statemgr.RefreshAndRead(s)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if state == nil {
+		t.Fatal("state is nil")
+	}
+
+	if got, want := testStateMgrCurrentLineage(s), "backend-new-migrate"; got != want {
+		t.Fatalf("lineage changed during migration\nnow: %s\nwas: %s", got, want)
+	}
+
+	// Write some state
+	state = states.NewState()
+	mark := markStateForMatching(state, "changing")
+
+	if err := statemgr.WriteAndPersist(s, state, nil); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Verify the state is where we expect
+	{
+		f, err := os.Open("local-state.tfstate")
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		actual, err := statefile.Read(f)
+		f.Close()
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		assertStateHasMarker(t, actual.State, mark)
+	}
+
+	// Verify the default paths don't exist
+	if !isEmptyState(DefaultStateFilename) {
+		data, _ := ioutil.ReadFile(DefaultStateFilename)
+
+		t.Fatal("state should not exist, but contains:\n", string(data))
+	}
+
+	// Verify a backup does exist
+	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
+		t.Fatal("backup state is empty or missing")
+	}
+}
+
+// Newly configured backend with matching local and remote state doesn't prompt
+// for copy.
+func TestMetaBackend_configureNewWithoutCopy(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-new-migrate"), td)
+	defer testChdir(t, td)()
+
+	if err := copy.CopyFile(DefaultStateFilename, "local-state.tfstate"); err != nil {
+		t.Fatal(err)
+	}
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+	m.input = false
+
+	// init the backend
+	_, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Verify the state is where we expect
+	f, err := os.Open("local-state.tfstate")
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	actual, err := statefile.Read(f)
+	f.Close()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if actual.Lineage != "backend-new-migrate" {
+		t.Fatalf("incorrect state lineage: %q", actual.Lineage)
+	}
+
+	// Verify the default paths don't exist
+	if !isEmptyState(DefaultStateFilename) {
+		data, _ := ioutil.ReadFile(DefaultStateFilename)
+
+		t.Fatal("state should not exist, but contains:\n", string(data))
+	}
+
+	// Verify a backup does exist
+	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
+		t.Fatal("backup state is empty or missing")
+	}
+}
+
+// Newly configured backend with prior local state and no remote state,
+// but opting to not migrate.
+func TestMetaBackend_configureNewWithStateNoMigrate(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-new-migrate"), td)
+	defer testChdir(t, td)()
+
+	// Ask input
+	defer testInteractiveInput(t, []string{"no"})()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if state := s.State(); state != nil {
+		t.Fatal("state is not nil")
+	}
+
+	// Verify the default paths don't exist
+	if !isEmptyState(DefaultStateFilename) {
+		data, _ := ioutil.ReadFile(DefaultStateFilename)
+
+		t.Fatal("state should not exist, but contains:\n", string(data))
+	}
+
+	// Verify a backup does exist
+	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
+		t.Fatal("backup state is empty or missing")
+	}
+}
+
+// Newly configured backend with prior local state and remote state
+func TestMetaBackend_configureNewWithStateExisting(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-new-migrate-existing"), td)
+	defer testChdir(t, td)()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+	// suppress input
+	m.forceInitCopy = true
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state := s.State()
+	if state == nil {
+		t.Fatal("state is nil")
+	}
+	if got, want := testStateMgrCurrentLineage(s), "local"; got != want {
+		t.Fatalf("wrong lineage %q; want %q", got, want)
+	}
+
+	// Write some state
+	state = states.NewState()
+	mark := markStateForMatching(state, "changing")
+
+	s.WriteState(state)
+	if err := s.PersistState(nil); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Verify the state is where we expect
+	{
+		f, err := os.Open("local-state.tfstate")
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		actual, err := statefile.Read(f)
+		f.Close()
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		assertStateHasMarker(t, actual.State, mark)
+	}
+
+	// Verify the default paths don't exist
+	if !isEmptyState(DefaultStateFilename) {
+		data, _ := ioutil.ReadFile(DefaultStateFilename)
+
+		t.Fatal("state should not exist, but contains:\n", string(data))
+	}
+
+	// Verify a backup does exist
+	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
+		t.Fatal("backup state is empty or missing")
+	}
+}
+
+// Newly configured backend with prior local state and remote state
+func TestMetaBackend_configureNewWithStateExistingNoMigrate(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-new-migrate-existing"), td)
+	defer testChdir(t, td)()
+
+	// Ask input
+	defer testInteractiveInput(t, []string{"no"})()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state := s.State()
+	if state == nil {
+		t.Fatal("state is nil")
+	}
+	if testStateMgrCurrentLineage(s) != "remote" {
+		t.Fatalf("bad: %#v", state)
+	}
+
+	// Write some state
+	state = states.NewState()
+	mark := markStateForMatching(state, "changing")
+	s.WriteState(state)
+	if err := s.PersistState(nil); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Verify the state is where we expect
+	{
+		f, err := os.Open("local-state.tfstate")
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		actual, err := statefile.Read(f)
+		f.Close()
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		assertStateHasMarker(t, actual.State, mark)
+	}
+
+	// Verify the default paths don't exist
+	if !isEmptyState(DefaultStateFilename) {
+		data, _ := ioutil.ReadFile(DefaultStateFilename)
+
+		t.Fatal("state should not exist, but contains:\n", string(data))
+	}
+
+	// Verify a backup does exist
+	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
+		t.Fatal("backup state is empty or missing")
+	}
+}
+
+// Saved backend state matching config
+func TestMetaBackend_configuredUnchanged(t *testing.T) {
+	defer testChdir(t, testFixturePath("backend-unchanged"))()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state := s.State()
+	if state == nil {
+		t.Fatal("nil state")
+	}
+	if testStateMgrCurrentLineage(s) != "configuredUnchanged" {
+		t.Fatalf("bad: %#v", state)
+	}
+
+	// Verify the default paths don't exist
+	if _, err := os.Stat(DefaultStateFilename); err == nil {
+		t.Fatal("file should not exist")
+	}
+
+	// Verify a backup doesn't exist
+	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
+		t.Fatal("file should not exist")
+	}
+}
+
+// Changing a configured backend
+func TestMetaBackend_configuredChange(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-change"), td)
+	defer testChdir(t, td)()
+
+	// Ask input
+	defer testInteractiveInput(t, []string{"no"})()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state := s.State()
+	if state != nil {
+		t.Fatal("state should be nil")
+	}
+
+	// Verify the default paths don't exist
+	if _, err := os.Stat(DefaultStateFilename); err == nil {
+		t.Fatal("file should not exist")
+	}
+
+	// Verify a backup doesn't exist
+	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
+		t.Fatal("file should not exist")
+	}
+
+	// Write some state
+	state = states.NewState()
+	mark := markStateForMatching(state, "changing")
+
+	s.WriteState(state)
+	if err := s.PersistState(nil); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Verify the state is where we expect
+	{
+		f, err := os.Open("local-state-2.tfstate")
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		actual, err := statefile.Read(f)
+		f.Close()
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		assertStateHasMarker(t, actual.State, mark)
+	}
+
+	// Verify no local state
+	if _, err := os.Stat(DefaultStateFilename); err == nil {
+		t.Fatal("file should not exist")
+	}
+
+	// Verify no local backup
+	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
+		t.Fatal("file should not exist")
+	}
+}
+
+// Reconfiguring with an already configured backend.
+// This should ignore the existing backend config, and configure the new
+// backend is if this is the first time.
+func TestMetaBackend_reconfigureChange(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-change-single-to-single"), td)
+	defer testChdir(t, td)()
+
+	// Register the single-state backend
+	backendInit.Set("local-single", backendLocal.TestNewLocalSingle)
+	defer backendInit.Set("local-single", nil)
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// this should not ask for input
+	m.input = false
+
+	// cli flag -reconfigure
+	m.reconfigure = true
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	newState := s.State()
+	if newState != nil || !newState.Empty() {
+		t.Fatal("state should be nil/empty after forced reconfiguration")
+	}
+
+	// verify that the old state is still there
+	s = statemgr.NewFilesystem("local-state.tfstate")
+	if err := s.RefreshState(); err != nil {
+		t.Fatal(err)
+	}
+	oldState := s.State()
+	if oldState == nil || oldState.Empty() {
+		t.Fatal("original state should be untouched")
+	}
+}
+
+// Initializing a backend which supports workspaces and does *not* have
+// the currently selected workspace should prompt the user with a list of
+// workspaces to choose from to select a valid one, if more than one workspace
+// is available.
+func TestMetaBackend_initSelectedWorkspaceDoesNotExist(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend-selected-workspace-doesnt-exist-multi"), td)
+	defer testChdir(t, td)()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	defer testInputMap(t, map[string]string{
+		"select-workspace": "2",
+	})()
+
+	// Get the backend
+	_, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	expected := "foo"
+	actual, err := m.Workspace()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if actual != expected {
+		t.Fatalf("expected selected workspace to be %q, but was %q", expected, actual)
+	}
+}
+
+// Initializing a backend which supports workspaces and does *not* have the
+// currently selected workspace - and which only has a single workspace - should
+// automatically select that single workspace.
+func TestMetaBackend_initSelectedWorkspaceDoesNotExistAutoSelect(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend-selected-workspace-doesnt-exist-single"), td)
+	defer testChdir(t, td)()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// this should not ask for input
+	m.input = false
+
+	// Assert test precondition: The current selected workspace is "bar"
+	previousName, err := m.Workspace()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if previousName != "bar" {
+		t.Fatalf("expected test fixture to start with 'bar' as the current selected workspace")
+	}
+
+	// Get the backend
+	_, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	expected := "default"
+	actual, err := m.Workspace()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if actual != expected {
+		t.Fatalf("expected selected workspace to be %q, but was %q", expected, actual)
+	}
+}
+
+// Initializing a backend which supports workspaces and does *not* have
+// the currently selected workspace with input=false should fail.
+func TestMetaBackend_initSelectedWorkspaceDoesNotExistInputFalse(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend-selected-workspace-doesnt-exist-multi"), td)
+	defer testChdir(t, td)()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+	m.input = false
+
+	// Get the backend
+	_, diags := m.Backend(&BackendOpts{Init: true})
+
+	// Should fail immediately
+	if got, want := diags.ErrWithWarnings().Error(), `Currently selected workspace "bar" does not exist`; !strings.Contains(got, want) {
+		t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+	}
+}
+
+// Changing a configured backend, copying state
+func TestMetaBackend_configuredChangeCopy(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-change"), td)
+	defer testChdir(t, td)()
+
+	// Ask input
+	defer testInteractiveInput(t, []string{"yes", "yes"})()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state := s.State()
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+	if testStateMgrCurrentLineage(s) != "backend-change" {
+		t.Fatalf("bad: %#v", state)
+	}
+
+	// Verify no local state
+	if _, err := os.Stat(DefaultStateFilename); err == nil {
+		t.Fatal("file should not exist")
+	}
+
+	// Verify no local backup
+	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
+		t.Fatal("file should not exist")
+	}
+}
+
+// Changing a configured backend that supports only single states to another
+// backend that only supports single states.
+func TestMetaBackend_configuredChangeCopy_singleState(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-change-single-to-single"), td)
+	defer testChdir(t, td)()
+
+	// Register the single-state backend
+	backendInit.Set("local-single", backendLocal.TestNewLocalSingle)
+	defer backendInit.Set("local-single", nil)
+
+	// Ask input
+	defer testInputMap(t, map[string]string{
+		"backend-migrate-copy-to-empty": "yes",
+	})()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state := s.State()
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+	if testStateMgrCurrentLineage(s) != "backend-change" {
+		t.Fatalf("bad: %#v", state)
+	}
+
+	// Verify no local state
+	if _, err := os.Stat(DefaultStateFilename); err == nil {
+		t.Fatal("file should not exist")
+	}
+
+	// Verify no local backup
+	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
+		t.Fatal("file should not exist")
+	}
+}
+
+// Changing a configured backend that supports multi-state to a
+// backend that only supports single states. The multi-state only has
+// a default state.
+func TestMetaBackend_configuredChangeCopy_multiToSingleDefault(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-change-multi-default-to-single"), td)
+	defer testChdir(t, td)()
+
+	// Register the single-state backend
+	backendInit.Set("local-single", backendLocal.TestNewLocalSingle)
+	defer backendInit.Set("local-single", nil)
+
+	// Ask input
+	defer testInputMap(t, map[string]string{
+		"backend-migrate-copy-to-empty": "yes",
+	})()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state := s.State()
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+	if testStateMgrCurrentLineage(s) != "backend-change" {
+		t.Fatalf("bad: %#v", state)
+	}
+
+	// Verify no local state
+	if _, err := os.Stat(DefaultStateFilename); err == nil {
+		t.Fatal("file should not exist")
+	}
+
+	// Verify no local backup
+	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
+		t.Fatal("file should not exist")
+	}
+}
+
+// Changing a configured backend that supports multi-state to a
+// backend that only supports single states.
+func TestMetaBackend_configuredChangeCopy_multiToSingle(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-change-multi-to-single"), td)
+	defer testChdir(t, td)()
+
+	// Register the single-state backend
+	backendInit.Set("local-single", backendLocal.TestNewLocalSingle)
+	defer backendInit.Set("local-single", nil)
+
+	// Ask input
+	defer testInputMap(t, map[string]string{
+		"backend-migrate-multistate-to-single": "yes",
+		"backend-migrate-copy-to-empty":        "yes",
+	})()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state := s.State()
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+	if testStateMgrCurrentLineage(s) != "backend-change" {
+		t.Fatalf("bad: %#v", state)
+	}
+
+	// Verify no local state
+	if _, err := os.Stat(DefaultStateFilename); err == nil {
+		t.Fatal("file should not exist")
+	}
+
+	// Verify no local backup
+	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
+		t.Fatal("file should not exist")
+	}
+
+	// Verify existing workspaces exist
+	envPath := filepath.Join(backendLocal.DefaultWorkspaceDir, "env2", backendLocal.DefaultStateFilename)
+	if _, err := os.Stat(envPath); err != nil {
+		t.Fatal("env should exist")
+	}
+
+	// Verify we are now in the default env, or we may not be able to access the new backend
+	env, err := m.Workspace()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if env != backend.DefaultStateName {
+		t.Fatal("using non-default env with single-env backend")
+	}
+}
+
+// Changing a configured backend that supports multi-state to a
+// backend that only supports single states.
+func TestMetaBackend_configuredChangeCopy_multiToSingleCurrentEnv(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-change-multi-to-single"), td)
+	defer testChdir(t, td)()
+
+	// Register the single-state backend
+	backendInit.Set("local-single", backendLocal.TestNewLocalSingle)
+	defer backendInit.Set("local-single", nil)
+
+	// Ask input
+	defer testInputMap(t, map[string]string{
+		"backend-migrate-multistate-to-single": "yes",
+		"backend-migrate-copy-to-empty":        "yes",
+	})()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Change env
+	if err := m.SetWorkspace("env2"); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state := s.State()
+	if state == nil {
+		t.Fatal("state should not be nil")
+	}
+	if testStateMgrCurrentLineage(s) != "backend-change-env2" {
+		t.Fatalf("bad: %#v", state)
+	}
+
+	// Verify no local state
+	if _, err := os.Stat(DefaultStateFilename); err == nil {
+		t.Fatal("file should not exist")
+	}
+
+	// Verify no local backup
+	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
+		t.Fatal("file should not exist")
+	}
+
+	// Verify existing workspaces exist
+	envPath := filepath.Join(backendLocal.DefaultWorkspaceDir, "env2", backendLocal.DefaultStateFilename)
+	if _, err := os.Stat(envPath); err != nil {
+		t.Fatal("env should exist")
+	}
+}
+
+// Changing a configured backend that supports multi-state to a
+// backend that also supports multi-state.
+func TestMetaBackend_configuredChangeCopy_multiToMulti(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-change-multi-to-multi"), td)
+	defer testChdir(t, td)()
+
+	// Ask input
+	defer testInputMap(t, map[string]string{
+		"backend-migrate-multistate-to-multistate": "yes",
+	})()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check resulting states
+	workspaces, err := b.Workspaces()
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	sort.Strings(workspaces)
+	expected := []string{"default", "env2"}
+	if !reflect.DeepEqual(workspaces, expected) {
+		t.Fatalf("bad: %#v", workspaces)
+	}
+
+	{
+		// Check the default state
+		s, err := b.StateMgr(backend.DefaultStateName)
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if err := s.RefreshState(); err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		state := s.State()
+		if state == nil {
+			t.Fatal("state should not be nil")
+		}
+		if testStateMgrCurrentLineage(s) != "backend-change" {
+			t.Fatalf("bad: %#v", state)
+		}
+	}
+
+	{
+		// Check the other state
+		s, err := b.StateMgr("env2")
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if err := s.RefreshState(); err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		state := s.State()
+		if state == nil {
+			t.Fatal("state should not be nil")
+		}
+		if testStateMgrCurrentLineage(s) != "backend-change-env2" {
+			t.Fatalf("bad: %#v", state)
+		}
+	}
+
+	// Verify no local backup
+	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
+		t.Fatal("file should not exist")
+	}
+
+	{
+		// Verify existing workspaces exist
+		envPath := filepath.Join(backendLocal.DefaultWorkspaceDir, "env2", backendLocal.DefaultStateFilename)
+		if _, err := os.Stat(envPath); err != nil {
+			t.Fatalf("%s should exist, but does not", envPath)
+		}
+	}
+
+	{
+		// Verify new workspaces exist
+		envPath := filepath.Join("envdir-new", "env2", backendLocal.DefaultStateFilename)
+		if _, err := os.Stat(envPath); err != nil {
+			t.Fatalf("%s should exist, but does not", envPath)
+		}
+	}
+}
+
+// Changing a configured backend that supports multi-state to a
+// backend that also supports multi-state, but doesn't allow a
+// default state while the default state is non-empty.
+func TestMetaBackend_configuredChangeCopy_multiToNoDefaultWithDefault(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-change-multi-to-no-default-with-default"), td)
+	defer testChdir(t, td)()
+
+	// Register the single-state backend
+	backendInit.Set("local-no-default", backendLocal.TestNewLocalNoDefault)
+	defer backendInit.Set("local-no-default", nil)
+
+	// Ask input
+	defer testInputMap(t, map[string]string{
+		"backend-migrate-multistate-to-multistate": "yes",
+		"new-state-name": "env1",
+	})()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check resulting states
+	workspaces, err := b.Workspaces()
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	sort.Strings(workspaces)
+	expected := []string{"env1", "env2"}
+	if !reflect.DeepEqual(workspaces, expected) {
+		t.Fatalf("bad: %#v", workspaces)
+	}
+
+	{
+		// Check the renamed default state
+		s, err := b.StateMgr("env1")
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if err := s.RefreshState(); err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		state := s.State()
+		if state == nil {
+			t.Fatal("state should not be nil")
+		}
+		if testStateMgrCurrentLineage(s) != "backend-change-env1" {
+			t.Fatalf("bad: %#v", state)
+		}
+	}
+
+	{
+		// Verify existing workspaces exist
+		envPath := filepath.Join(backendLocal.DefaultWorkspaceDir, "env2", backendLocal.DefaultStateFilename)
+		if _, err := os.Stat(envPath); err != nil {
+			t.Fatal("env should exist")
+		}
+	}
+
+	{
+		// Verify new workspaces exist
+		envPath := filepath.Join("envdir-new", "env2", backendLocal.DefaultStateFilename)
+		if _, err := os.Stat(envPath); err != nil {
+			t.Fatal("env should exist")
+		}
+	}
+}
+
+// Changing a configured backend that supports multi-state to a
+// backend that also supports multi-state, but doesn't allow a
+// default state while the default state is empty.
+func TestMetaBackend_configuredChangeCopy_multiToNoDefaultWithoutDefault(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-change-multi-to-no-default-without-default"), td)
+	defer testChdir(t, td)()
+
+	// Register the single-state backend
+	backendInit.Set("local-no-default", backendLocal.TestNewLocalNoDefault)
+	defer backendInit.Set("local-no-default", nil)
+
+	// Ask input
+	defer testInputMap(t, map[string]string{
+		"backend-migrate-multistate-to-multistate": "yes",
+	})()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check resulting states
+	workspaces, err := b.Workspaces()
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	sort.Strings(workspaces)
+	expected := []string{"env2"} // default is skipped because it is absent in the source backend
+	if !reflect.DeepEqual(workspaces, expected) {
+		t.Fatalf("wrong workspaces\ngot:  %#v\nwant: %#v", workspaces, expected)
+	}
+
+	{
+		// Check the named state
+		s, err := b.StateMgr("env2")
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if err := s.RefreshState(); err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		state := s.State()
+		if state == nil {
+			t.Fatal("state should not be nil")
+		}
+		if testStateMgrCurrentLineage(s) != "backend-change-env2" {
+			t.Fatalf("bad: %#v", state)
+		}
+	}
+
+	{
+		// Verify existing workspaces exist
+		envPath := filepath.Join(backendLocal.DefaultWorkspaceDir, "env2", backendLocal.DefaultStateFilename)
+		if _, err := os.Stat(envPath); err != nil {
+			t.Fatalf("%s should exist, but does not", envPath)
+		}
+	}
+
+	{
+		// Verify new workspaces exist
+		envPath := filepath.Join("envdir-new", "env2", backendLocal.DefaultStateFilename)
+		if _, err := os.Stat(envPath); err != nil {
+			t.Fatalf("%s should exist, but does not", envPath)
+		}
+	}
+}
+
+// Unsetting a saved backend
+func TestMetaBackend_configuredUnset(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-unset"), td)
+	defer testChdir(t, td)()
+
+	// Ask input
+	defer testInteractiveInput(t, []string{"no"})()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state := s.State()
+	if state != nil {
+		t.Fatal("state should be nil")
+	}
+
+	// Verify the default paths don't exist
+	if !isEmptyState(DefaultStateFilename) {
+		data, _ := ioutil.ReadFile(DefaultStateFilename)
+		t.Fatal("state should not exist, but contains:\n", string(data))
+	}
+
+	// Verify a backup doesn't exist
+	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
+		data, _ := ioutil.ReadFile(DefaultStateFilename + DefaultBackupExtension)
+		t.Fatal("backup should not exist, but contains:\n", string(data))
+	}
+
+	// Write some state
+	s.WriteState(testState())
+	if err := s.PersistState(nil); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Verify it exists where we expect it to
+	if isEmptyState(DefaultStateFilename) {
+		t.Fatal(DefaultStateFilename, "is empty")
+	}
+
+	// Verify no backup since it was empty to start
+	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
+		data, _ := ioutil.ReadFile(DefaultStateFilename + DefaultBackupExtension)
+		t.Fatal("backup state should be empty, but contains:\n", string(data))
+	}
+}
+
+// Unsetting a saved backend and copying the remote state
+func TestMetaBackend_configuredUnsetCopy(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-unset"), td)
+	defer testChdir(t, td)()
+
+	// Ask input
+	defer testInteractiveInput(t, []string{"yes", "yes"})()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state := s.State()
+	if state == nil {
+		t.Fatal("state is nil")
+	}
+	if got, want := testStateMgrCurrentLineage(s), "configuredUnset"; got != want {
+		t.Fatalf("wrong state lineage %q; want %q", got, want)
+	}
+
+	// Verify a backup doesn't exist
+	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
+		t.Fatalf("backup state should be empty")
+	}
+
+	// Write some state
+	s.WriteState(testState())
+	if err := s.PersistState(nil); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Verify it exists where we expect it to
+	if _, err := os.Stat(DefaultStateFilename); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Verify a backup since it wasn't empty to start
+	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
+		t.Fatal("backup is empty")
+	}
+}
+
+// A plan that has uses the local backend
+func TestMetaBackend_planLocal(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-plan-local"), td)
+	defer testChdir(t, td)()
+
+	backendConfigBlock := cty.ObjectVal(map[string]cty.Value{
+		"path":          cty.NullVal(cty.String),
+		"workspace_dir": cty.NullVal(cty.String),
+	})
+	backendConfigRaw, err := plans.NewDynamicValue(backendConfigBlock, backendConfigBlock.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	backendConfig := plans.Backend{
+		Type:      "local",
+		Config:    backendConfigRaw,
+		Workspace: "default",
+	}
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.BackendForPlan(backendConfig)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state := s.State()
+	if state != nil {
+		t.Fatalf("state should be nil: %#v", state)
+	}
+
+	// The default state file should not exist yet
+	if !isEmptyState(DefaultStateFilename) {
+		t.Fatal("expected empty state")
+	}
+
+	// A backup file shouldn't exist yet either.
+	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
+		t.Fatal("expected empty backup")
+	}
+
+	// Verify we have no configured backend
+	path := filepath.Join(m.DataDir(), DefaultStateFilename)
+	if _, err := os.Stat(path); err == nil {
+		t.Fatalf("should not have backend configured")
+	}
+
+	// Write some state
+	state = states.NewState()
+	mark := markStateForMatching(state, "changing")
+
+	s.WriteState(state)
+	if err := s.PersistState(nil); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Verify the state is where we expect
+	{
+		f, err := os.Open(DefaultStateFilename)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		actual, err := statefile.Read(f)
+		f.Close()
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		assertStateHasMarker(t, actual.State, mark)
+	}
+
+	// Verify no local backup
+	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
+		t.Fatalf("backup state should be empty")
+	}
+}
+
+// A plan with a custom state save path
+func TestMetaBackend_planLocalStatePath(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-plan-local"), td)
+	defer testChdir(t, td)()
+
+	original := testState()
+	markStateForMatching(original, "hello")
+
+	backendConfigBlock := cty.ObjectVal(map[string]cty.Value{
+		"path":          cty.NullVal(cty.String),
+		"workspace_dir": cty.NullVal(cty.String),
+	})
+	backendConfigRaw, err := plans.NewDynamicValue(backendConfigBlock, backendConfigBlock.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	plannedBackend := plans.Backend{
+		Type:      "local",
+		Config:    backendConfigRaw,
+		Workspace: "default",
+	}
+
+	// Create an alternate output path
+	statePath := "foo.tfstate"
+
+	// put an initial state there that needs to be backed up
+	err = (statemgr.NewFilesystem(statePath)).WriteState(original)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+	m.stateOutPath = statePath
+
+	// Get the backend
+	b, diags := m.BackendForPlan(plannedBackend)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state := s.State()
+	if state != nil {
+		t.Fatal("default workspace state is not nil, but should be because we've not put anything there")
+	}
+
+	// Verify the default path doesn't exist
+	if _, err := os.Stat(DefaultStateFilename); err == nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Verify a backup doesn't exists
+	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
+		t.Fatal("file should not exist")
+	}
+
+	// Verify we have no configured backend/legacy
+	path := filepath.Join(m.DataDir(), DefaultStateFilename)
+	if _, err := os.Stat(path); err == nil {
+		t.Fatalf("should not have backend configured")
+	}
+
+	// Write some state
+	state = states.NewState()
+	mark := markStateForMatching(state, "changing")
+
+	s.WriteState(state)
+	if err := s.PersistState(nil); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Verify the state is where we expect
+	{
+		f, err := os.Open(statePath)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		actual, err := statefile.Read(f)
+		f.Close()
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		assertStateHasMarker(t, actual.State, mark)
+	}
+
+	// Verify we have a backup
+	if isEmptyState(statePath + DefaultBackupExtension) {
+		t.Fatal("backup is empty")
+	}
+}
+
+// A plan that has no backend config, matching local state
+func TestMetaBackend_planLocalMatch(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-plan-local-match"), td)
+	defer testChdir(t, td)()
+
+	backendConfigBlock := cty.ObjectVal(map[string]cty.Value{
+		"path":          cty.NullVal(cty.String),
+		"workspace_dir": cty.NullVal(cty.String),
+	})
+	backendConfigRaw, err := plans.NewDynamicValue(backendConfigBlock, backendConfigBlock.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	backendConfig := plans.Backend{
+		Type:      "local",
+		Config:    backendConfigRaw,
+		Workspace: "default",
+	}
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+
+	// Get the backend
+	b, diags := m.BackendForPlan(backendConfig)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s, err := b.StateMgr(backend.DefaultStateName)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	state := s.State()
+	if state == nil {
+		t.Fatal("should is nil")
+	}
+	if testStateMgrCurrentLineage(s) != "hello" {
+		t.Fatalf("bad: %#v", state)
+	}
+
+	// Verify the default path
+	if isEmptyState(DefaultStateFilename) {
+		t.Fatal("state is empty")
+	}
+
+	// Verify we have no configured backend/legacy
+	path := filepath.Join(m.DataDir(), DefaultStateFilename)
+	if _, err := os.Stat(path); err == nil {
+		t.Fatalf("should not have backend configured")
+	}
+
+	// Write some state
+	state = states.NewState()
+	mark := markStateForMatching(state, "changing")
+
+	s.WriteState(state)
+	if err := s.PersistState(nil); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Verify the state is where we expect
+	{
+		f, err := os.Open(DefaultStateFilename)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		actual, err := statefile.Read(f)
+		f.Close()
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		assertStateHasMarker(t, actual.State, mark)
+	}
+
+	// Verify local backup
+	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
+		t.Fatal("backup is empty")
+	}
+}
+
+// init a backend using -backend-config options multiple times
+func TestMetaBackend_configureWithExtra(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend-empty"), td)
+	defer testChdir(t, td)()
+
+	extras := map[string]cty.Value{"path": cty.StringVal("hello")}
+	m := testMetaBackend(t, nil)
+	opts := &BackendOpts{
+		ConfigOverride: configs.SynthBody("synth", extras),
+		Init:           true,
+	}
+
+	_, cHash, err := m.backendConfig(opts)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// init the backend
+	_, diags := m.Backend(&BackendOpts{
+		ConfigOverride: configs.SynthBody("synth", extras),
+		Init:           true,
+	})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// Check the state
+	s := testDataStateRead(t, filepath.Join(DefaultDataDir, backendLocal.DefaultStateFilename))
+	if s.Backend.Hash != uint64(cHash) {
+		t.Fatal("mismatched state and config backend hashes")
+	}
+
+	// init the backend again with the same options
+	m = testMetaBackend(t, nil)
+	_, err = m.Backend(&BackendOpts{
+		ConfigOverride: configs.SynthBody("synth", extras),
+		Init:           true,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Check the state
+	s = testDataStateRead(t, filepath.Join(DefaultDataDir, backendLocal.DefaultStateFilename))
+	if s.Backend.Hash != uint64(cHash) {
+		t.Fatal("mismatched state and config backend hashes")
+	}
+}
+
+// when configuring a default local state, don't delete local state
+func TestMetaBackend_localDoesNotDeleteLocal(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend-empty"), td)
+	defer testChdir(t, td)()
+
+	// // create our local state
+	orig := states.NewState()
+	orig.Module(addrs.RootModuleInstance).SetOutputValue("foo", cty.StringVal("bar"), false)
+	testStateFileDefault(t, orig)
+
+	m := testMetaBackend(t, nil)
+	m.forceInitCopy = true
+	// init the backend
+	_, diags := m.Backend(&BackendOpts{Init: true})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// check that we can read the state
+	s := testStateRead(t, DefaultStateFilename)
+	if s.Empty() {
+		t.Fatal("our state was deleted")
+	}
+}
+
+// move options from config to -backend-config
+func TestMetaBackend_configToExtra(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend"), td)
+	defer testChdir(t, td)()
+
+	// init the backend
+	m := testMetaBackend(t, nil)
+	_, err := m.Backend(&BackendOpts{
+		Init: true,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Check the state
+	s := testDataStateRead(t, filepath.Join(DefaultDataDir, backendLocal.DefaultStateFilename))
+	backendHash := s.Backend.Hash
+
+	// init again but remove the path option from the config
+	cfg := "terraform {\n  backend \"local\" {}\n}\n"
+	if err := ioutil.WriteFile("main.tf", []byte(cfg), 0644); err != nil {
+		t.Fatal(err)
+	}
+
+	// init the backend again with the  options
+	extras := map[string]cty.Value{"path": cty.StringVal("hello")}
+	m = testMetaBackend(t, nil)
+	m.forceInitCopy = true
+	_, diags := m.Backend(&BackendOpts{
+		ConfigOverride: configs.SynthBody("synth", extras),
+		Init:           true,
+	})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	s = testDataStateRead(t, filepath.Join(DefaultDataDir, backendLocal.DefaultStateFilename))
+
+	if s.Backend.Hash == backendHash {
+		t.Fatal("state.Backend.Hash was not updated")
+	}
+}
+
+// no config; return inmem backend stored in state
+func TestBackendFromState(t *testing.T) {
+	wd := tempWorkingDirFixture(t, "backend-from-state")
+	defer testChdir(t, wd.RootModuleDir())()
+
+	// Setup the meta
+	m := testMetaBackend(t, nil)
+	m.WorkingDir = wd
+	// terraform caches a small "state" file that stores the backend config.
+	// This test must override m.dataDir so it loads the "terraform.tfstate" file in the
+	// test directory as the backend config cache. This fixture is really a
+	// fixture for the data dir rather than the module dir, so we'll override
+	// them to match just for this test.
+	wd.OverrideDataDir(".")
+
+	stateBackend, diags := m.backendFromState()
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	if _, ok := stateBackend.(*backendInmem.Backend); !ok {
+		t.Fatal("did not get expected inmem backend")
+	}
+}
+
+func testMetaBackend(t *testing.T, args []string) *Meta {
+	var m Meta
+	m.Ui = new(cli.MockUi)
+	view, _ := testView(t)
+	m.View = view
+	m.process(args)
+	f := m.extendedFlagSet("test")
+	if err := f.Parse(args); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// metaBackend tests are verifying migrate actions
+	m.migrateState = true
+
+	return &m
+}
diff --git a/v1.5.7/internal/command/meta_config.go b/v1.5.7/internal/command/meta_config.go
new file mode 100644
index 0000000..5a86d84
--- /dev/null
+++ b/v1.5.7/internal/command/meta_config.go
@@ -0,0 +1,433 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"context"
+	"fmt"
+	"os"
+	"path/filepath"
+	"sort"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/registry"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/convert"
+)
+
+// normalizePath normalizes a given path so that it is, if possible, relative
+// to the current working directory. This is primarily used to prepare
+// paths used to load configuration, because we want to prefer recording
+// relative paths in source code references within the configuration.
+func (m *Meta) normalizePath(path string) string {
+	m.fixupMissingWorkingDir()
+	return m.WorkingDir.NormalizePath(path)
+}
+
+// loadConfig reads a configuration from the given directory, which should
+// contain a root module and have already have any required descendent modules
+// installed.
+func (m *Meta) loadConfig(rootDir string) (*configs.Config, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	rootDir = m.normalizePath(rootDir)
+
+	loader, err := m.initConfigLoader()
+	if err != nil {
+		diags = diags.Append(err)
+		return nil, diags
+	}
+
+	config, hclDiags := loader.LoadConfig(rootDir)
+	diags = diags.Append(hclDiags)
+	return config, diags
+}
+
+// loadSingleModule reads configuration from the given directory and returns
+// a description of that module only, without attempting to assemble a module
+// tree for referenced child modules.
+//
+// Most callers should use loadConfig. This method exists to support early
+// initialization use-cases where the root module must be inspected in order
+// to determine what else needs to be installed before the full configuration
+// can be used.
+func (m *Meta) loadSingleModule(dir string) (*configs.Module, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	dir = m.normalizePath(dir)
+
+	loader, err := m.initConfigLoader()
+	if err != nil {
+		diags = diags.Append(err)
+		return nil, diags
+	}
+
+	module, hclDiags := loader.Parser().LoadConfigDir(dir)
+	diags = diags.Append(hclDiags)
+	return module, diags
+}
+
+// dirIsConfigPath checks if the given path is a directory that contains at
+// least one Terraform configuration file (.tf or .tf.json), returning true
+// if so.
+//
+// In the unlikely event that the underlying config loader cannot be initalized,
+// this function optimistically returns true, assuming that the caller will
+// then do some other operation that requires the config loader and get an
+// error at that point.
+func (m *Meta) dirIsConfigPath(dir string) bool {
+	loader, err := m.initConfigLoader()
+	if err != nil {
+		return true
+	}
+
+	return loader.IsConfigDir(dir)
+}
+
+// loadBackendConfig reads configuration from the given directory and returns
+// the backend configuration defined by that module, if any. Nil is returned
+// if the specified module does not have an explicit backend configuration.
+//
+// This is a convenience method for command code that will delegate to the
+// configured backend to do most of its work, since in that case it is the
+// backend that will do the full configuration load.
+//
+// Although this method returns only the backend configuration, at present it
+// actually loads and validates the entire configuration first. Therefore errors
+// returned may be about other aspects of the configuration. This behavior may
+// change in future, so callers must not rely on it. (That is, they must expect
+// that a call to loadSingleModule or loadConfig could fail on the same
+// directory even if loadBackendConfig succeeded.)
+func (m *Meta) loadBackendConfig(rootDir string) (*configs.Backend, tfdiags.Diagnostics) {
+	mod, diags := m.loadSingleModule(rootDir)
+
+	// Only return error diagnostics at this point. Any warnings will be caught
+	// again later and duplicated in the output.
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	if mod.CloudConfig != nil {
+		backendConfig := mod.CloudConfig.ToBackendConfig()
+		return &backendConfig, nil
+	}
+
+	return mod.Backend, nil
+}
+
+// loadHCLFile reads an arbitrary HCL file and returns the unprocessed body
+// representing its toplevel. Most callers should use one of the more
+// specialized "load..." methods to get a higher-level representation.
+func (m *Meta) loadHCLFile(filename string) (hcl.Body, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	filename = m.normalizePath(filename)
+
+	loader, err := m.initConfigLoader()
+	if err != nil {
+		diags = diags.Append(err)
+		return nil, diags
+	}
+
+	body, hclDiags := loader.Parser().LoadHCLFile(filename)
+	diags = diags.Append(hclDiags)
+	return body, diags
+}
+
+// installModules reads a root module from the given directory and attempts
+// recursively to install all of its descendent modules.
+//
+// The given hooks object will be notified of installation progress, which
+// can then be relayed to the end-user. The uiModuleInstallHooks type in
+// this package has a reasonable implementation for displaying notifications
+// via a provided cli.Ui.
+func (m *Meta) installModules(rootDir string, upgrade bool, hooks initwd.ModuleInstallHooks) (abort bool, diags tfdiags.Diagnostics) {
+	rootDir = m.normalizePath(rootDir)
+
+	err := os.MkdirAll(m.modulesDir(), os.ModePerm)
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("failed to create local modules directory: %s", err))
+		return true, diags
+	}
+
+	loader, err := m.initConfigLoader()
+	if err != nil {
+		diags = diags.Append(err)
+		return true, diags
+	}
+
+	inst := initwd.NewModuleInstaller(m.modulesDir(), loader, m.registryClient())
+
+	// Installation can be aborted by interruption signals
+	ctx, done := m.InterruptibleContext()
+	defer done()
+
+	_, moreDiags := inst.InstallModules(ctx, rootDir, upgrade, hooks)
+	diags = diags.Append(moreDiags)
+
+	if ctx.Err() == context.Canceled {
+		m.showDiagnostics(diags)
+		m.Ui.Error("Module installation was canceled by an interrupt signal.")
+		return true, diags
+	}
+
+	return false, diags
+}
+
+// initDirFromModule initializes the given directory (which should be
+// pre-verified as empty by the caller) by copying the source code from the
+// given module address.
+//
+// Internally this runs similar steps to installModules.
+// The given hooks object will be notified of installation progress, which
+// can then be relayed to the end-user. The uiModuleInstallHooks type in
+// this package has a reasonable implementation for displaying notifications
+// via a provided cli.Ui.
+func (m *Meta) initDirFromModule(targetDir string, addr string, hooks initwd.ModuleInstallHooks) (abort bool, diags tfdiags.Diagnostics) {
+	// Installation can be aborted by interruption signals
+	ctx, done := m.InterruptibleContext()
+	defer done()
+
+	loader, err := m.initConfigLoader()
+	if err != nil {
+		diags = diags.Append(err)
+		return true, diags
+	}
+
+	targetDir = m.normalizePath(targetDir)
+	moreDiags := initwd.DirFromModule(ctx, loader, targetDir, m.modulesDir(), addr, m.registryClient(), hooks)
+	diags = diags.Append(moreDiags)
+	if ctx.Err() == context.Canceled {
+		m.showDiagnostics(diags)
+		m.Ui.Error("Module initialization was canceled by an interrupt signal.")
+		return true, diags
+	}
+	return false, diags
+}
+
+// inputForSchema uses interactive prompts to try to populate any
+// not-yet-populated required attributes in the given object value to
+// comply with the given schema.
+//
+// An error will be returned if input is disabled for this meta or if
+// values cannot be obtained for some other operational reason. Errors are
+// not returned for invalid input since the input loop itself will report
+// that interactively.
+//
+// It is not guaranteed that the result will be valid, since certain attribute
+// types and nested blocks are not supported for input.
+//
+// The given value must conform to the given schema. If not, this method will
+// panic.
+func (m *Meta) inputForSchema(given cty.Value, schema *configschema.Block) (cty.Value, error) {
+	if given.IsNull() || !given.IsKnown() {
+		// This is not reasonable input, but we'll tolerate it anyway and
+		// just pass it through for the caller to handle downstream.
+		return given, nil
+	}
+
+	retVals := given.AsValueMap()
+	names := make([]string, 0, len(schema.Attributes))
+	for name, attrS := range schema.Attributes {
+		if attrS.Required && retVals[name].IsNull() && attrS.Type.IsPrimitiveType() {
+			names = append(names, name)
+		}
+	}
+	sort.Strings(names)
+
+	input := m.UIInput()
+	for _, name := range names {
+		attrS := schema.Attributes[name]
+
+		for {
+			strVal, err := input.Input(context.Background(), &terraform.InputOpts{
+				Id:          name,
+				Query:       name,
+				Description: attrS.Description,
+			})
+			if err != nil {
+				return cty.UnknownVal(schema.ImpliedType()), fmt.Errorf("%s: %s", name, err)
+			}
+
+			val := cty.StringVal(strVal)
+			val, err = convert.Convert(val, attrS.Type)
+			if err != nil {
+				m.showDiagnostics(fmt.Errorf("Invalid value: %s", err))
+				continue
+			}
+
+			retVals[name] = val
+			break
+		}
+	}
+
+	return cty.ObjectVal(retVals), nil
+}
+
+// configSources returns the source cache from the receiver's config loader,
+// which the caller must not modify.
+//
+// If a config loader has not yet been instantiated then no files could have
+// been loaded already, so this method returns a nil map in that case.
+func (m *Meta) configSources() map[string][]byte {
+	if m.configLoader == nil {
+		return nil
+	}
+
+	return m.configLoader.Sources()
+}
+
+func (m *Meta) modulesDir() string {
+	return filepath.Join(m.DataDir(), "modules")
+}
+
+// registerSynthConfigSource allows commands to add synthetic additional source
+// buffers to the config loader's cache of sources (as returned by
+// configSources), which is useful when a command is directly parsing something
+// from the command line that may produce diagnostics, so that diagnostic
+// snippets can still be produced.
+//
+// If this is called before a configLoader has been initialized then it will
+// try to initialize the loader but ignore any initialization failure, turning
+// the call into a no-op. (We presume that a caller will later call a different
+// function that also initializes the config loader as a side effect, at which
+// point those errors can be returned.)
+func (m *Meta) registerSynthConfigSource(filename string, src []byte) {
+	loader, err := m.initConfigLoader()
+	if err != nil || loader == nil {
+		return // treated as no-op, since this is best-effort
+	}
+	loader.Parser().ForceFileSource(filename, src)
+}
+
+// initConfigLoader initializes the shared configuration loader if it isn't
+// already initialized.
+//
+// If the loader cannot be created for some reason then an error is returned
+// and no loader is created. Subsequent calls will presumably see the same
+// error. Loader initialization errors will tend to prevent any further use
+// of most Terraform features, so callers should report any error and safely
+// terminate.
+func (m *Meta) initConfigLoader() (*configload.Loader, error) {
+	if m.configLoader == nil {
+		loader, err := configload.NewLoader(&configload.Config{
+			ModulesDir: m.modulesDir(),
+			Services:   m.Services,
+		})
+		if err != nil {
+			return nil, err
+		}
+		loader.AllowLanguageExperiments(m.AllowExperimentalFeatures)
+		m.configLoader = loader
+		if m.View != nil {
+			m.View.SetConfigSources(loader.Sources)
+		}
+	}
+	return m.configLoader, nil
+}
+
+// registryClient instantiates and returns a new Terraform Registry client.
+func (m *Meta) registryClient() *registry.Client {
+	return registry.NewClient(m.Services, nil)
+}
+
+// configValueFromCLI parses a configuration value that was provided in a
+// context in the CLI where only strings can be provided, such as on the
+// command line or in an environment variable, and returns the resulting
+// value.
+func configValueFromCLI(synthFilename, rawValue string, wantType cty.Type) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	switch {
+	case wantType.IsPrimitiveType():
+		// Primitive types are handled as conversions from string.
+		val := cty.StringVal(rawValue)
+		var err error
+		val, err = convert.Convert(val, wantType)
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid backend configuration value",
+				fmt.Sprintf("Invalid backend configuration argument %s: %s", synthFilename, err),
+			))
+			val = cty.DynamicVal // just so we return something valid-ish
+		}
+		return val, diags
+	default:
+		// Non-primitives are parsed as HCL expressions
+		src := []byte(rawValue)
+		expr, hclDiags := hclsyntax.ParseExpression(src, synthFilename, hcl.Pos{Line: 1, Column: 1})
+		diags = diags.Append(hclDiags)
+		if hclDiags.HasErrors() {
+			return cty.DynamicVal, diags
+		}
+		val, hclDiags := expr.Value(nil)
+		diags = diags.Append(hclDiags)
+		if hclDiags.HasErrors() {
+			val = cty.DynamicVal
+		}
+		return val, diags
+	}
+}
+
+// rawFlags is a flag.Value implementation that just appends raw flag
+// names and values to a slice.
+type rawFlags struct {
+	flagName string
+	items    *[]rawFlag
+}
+
+func newRawFlags(flagName string) rawFlags {
+	var items []rawFlag
+	return rawFlags{
+		flagName: flagName,
+		items:    &items,
+	}
+}
+
+func (f rawFlags) Empty() bool {
+	if f.items == nil {
+		return true
+	}
+	return len(*f.items) == 0
+}
+
+func (f rawFlags) AllItems() []rawFlag {
+	if f.items == nil {
+		return nil
+	}
+	return *f.items
+}
+
+func (f rawFlags) Alias(flagName string) rawFlags {
+	return rawFlags{
+		flagName: flagName,
+		items:    f.items,
+	}
+}
+
+func (f rawFlags) String() string {
+	return ""
+}
+
+func (f rawFlags) Set(str string) error {
+	*f.items = append(*f.items, rawFlag{
+		Name:  f.flagName,
+		Value: str,
+	})
+	return nil
+}
+
+type rawFlag struct {
+	Name  string
+	Value string
+}
+
+func (f rawFlag) String() string {
+	return fmt.Sprintf("%s=%q", f.Name, f.Value)
+}
diff --git a/v1.5.7/internal/command/meta_dependencies.go b/v1.5.7/internal/command/meta_dependencies.go
new file mode 100644
index 0000000..a99ae2e
--- /dev/null
+++ b/v1.5.7/internal/command/meta_dependencies.go
@@ -0,0 +1,96 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"log"
+	"os"
+
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// dependenclyLockFilename is the filename of the dependency lock file.
+//
+// This file should live in the same directory as the .tf files for the
+// root module of the configuration, alongside the .terraform directory
+// as long as that directory's path isn't overridden by the TF_DATA_DIR
+// environment variable.
+//
+// We always expect to find this file in the current working directory
+// because that should also be the root module directory.
+//
+// Some commands have legacy command line arguments that make the root module
+// directory something other than the root module directory; when using those,
+// the lock file will be written in the "wrong" place (the current working
+// directory instead of the root module directory) but we do that intentionally
+// to match where the ".terraform" directory would also be written in that
+// case. Eventually we will phase out those legacy arguments in favor of the
+// global -chdir=... option, which _does_ preserve the intended invariant
+// that the root module directory is always the current working directory.
+const dependencyLockFilename = ".terraform.lock.hcl"
+
+// lockedDependencies reads the dependency lock information from the lock file
+// in the current working directory.
+//
+// If the lock file doesn't exist at the time of the call, lockedDependencies
+// indicates success and returns an empty Locks object. If the file does
+// exist then the result is either a representation of the contents of that
+// file at the instant of the call or error diagnostics explaining some way
+// in which the lock file is invalid.
+//
+// The result is a snapshot of the locked dependencies at the time of the call
+// and does not update as a result of calling replaceLockedDependencies
+// or any other modification method.
+func (m *Meta) lockedDependencies() (*depsfile.Locks, tfdiags.Diagnostics) {
+	// We check that the file exists first, because the underlying HCL
+	// parser doesn't distinguish that error from other error types
+	// in a machine-readable way but we want to treat that as a success
+	// with no locks. There is in theory a race condition here in that
+	// the file could be created or removed in the meantime, but we're not
+	// promising to support two concurrent dependency installation processes.
+	_, err := os.Stat(dependencyLockFilename)
+	if os.IsNotExist(err) {
+		return m.annotateDependencyLocksWithOverrides(depsfile.NewLocks()), nil
+	}
+
+	ret, diags := depsfile.LoadLocksFromFile(dependencyLockFilename)
+	return m.annotateDependencyLocksWithOverrides(ret), diags
+}
+
+// replaceLockedDependencies creates or overwrites the lock file in the
+// current working directory to contain the information recorded in the given
+// locks object.
+func (m *Meta) replaceLockedDependencies(new *depsfile.Locks) tfdiags.Diagnostics {
+	return depsfile.SaveLocksToFile(new, dependencyLockFilename)
+}
+
+// annotateDependencyLocksWithOverrides modifies the given Locks object in-place
+// to track as overridden any provider address that's subject to testing
+// overrides, development overrides, or "unmanaged provider" status.
+//
+// This is just an implementation detail of the lockedDependencies method,
+// not intended for use anywhere else.
+func (m *Meta) annotateDependencyLocksWithOverrides(ret *depsfile.Locks) *depsfile.Locks {
+	if ret == nil {
+		return ret
+	}
+
+	for addr := range m.ProviderDevOverrides {
+		log.Printf("[DEBUG] Provider %s is overridden by dev_overrides", addr)
+		ret.SetProviderOverridden(addr)
+	}
+	for addr := range m.UnmanagedProviders {
+		log.Printf("[DEBUG] Provider %s is overridden as an \"unmanaged provider\"", addr)
+		ret.SetProviderOverridden(addr)
+	}
+	if m.testingOverrides != nil {
+		for addr := range m.testingOverrides.Providers {
+			log.Printf("[DEBUG] Provider %s is overridden in Meta.testingOverrides", addr)
+			ret.SetProviderOverridden(addr)
+		}
+	}
+
+	return ret
+}
diff --git a/v1.5.7/internal/command/meta_new.go b/v1.5.7/internal/command/meta_new.go
new file mode 100644
index 0000000..0cb38bf
--- /dev/null
+++ b/v1.5.7/internal/command/meta_new.go
@@ -0,0 +1,49 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"os"
+	"strconv"
+
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+)
+
+// NOTE: Temporary file until this branch is cleaned up.
+
+// Input returns whether or not input asking is enabled.
+func (m *Meta) Input() bool {
+	if test || !m.input {
+		return false
+	}
+
+	if envVar := os.Getenv(InputModeEnvVar); envVar != "" {
+		if v, err := strconv.ParseBool(envVar); err == nil && !v {
+			return false
+		}
+	}
+
+	return true
+}
+
+// PlanFile returns a reader for the plan file at the given path.
+//
+// If the return value and error are both nil, the given path exists but seems
+// to be a configuration directory instead.
+//
+// Error will be non-nil if path refers to something which looks like a plan
+// file and loading the file fails.
+func (m *Meta) PlanFile(path string) (*planfile.Reader, error) {
+	fi, err := os.Stat(path)
+	if err != nil {
+		return nil, err
+	}
+
+	if fi.IsDir() {
+		// Looks like a configuration directory.
+		return nil, nil
+	}
+
+	return planfile.Open(path)
+}
diff --git a/v1.5.7/internal/command/meta_providers.go b/v1.5.7/internal/command/meta_providers.go
new file mode 100644
index 0000000..f96347d
--- /dev/null
+++ b/v1.5.7/internal/command/meta_providers.go
@@ -0,0 +1,508 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"log"
+	"os"
+	"os/exec"
+	"strings"
+
+	plugin "github.com/hashicorp/go-plugin"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	terraformProvider "github.com/hashicorp/terraform/internal/builtin/providers/terraform"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/moduletest"
+	tfplugin "github.com/hashicorp/terraform/internal/plugin"
+	tfplugin6 "github.com/hashicorp/terraform/internal/plugin6"
+	"github.com/hashicorp/terraform/internal/providercache"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// The TF_DISABLE_PLUGIN_TLS environment variable is intended only for use by
+// the plugin SDK test framework, to reduce startup overhead when rapidly
+// launching and killing lots of instances of the same provider.
+//
+// This is not intended to be set by end-users.
+var enableProviderAutoMTLS = os.Getenv("TF_DISABLE_PLUGIN_TLS") == ""
+
+// providerInstaller returns an object that knows how to install providers and
+// how to recover the selections from a prior installation process.
+//
+// The resulting provider installer is constructed from the results of
+// the other methods providerLocalCacheDir, providerGlobalCacheDir, and
+// providerInstallSource.
+//
+// Only one object returned from this method should be live at any time,
+// because objects inside contain caches that must be maintained properly.
+// Because this method wraps a result from providerLocalCacheDir, that
+// limitation applies also to results from that method.
+func (m *Meta) providerInstaller() *providercache.Installer {
+	return m.providerInstallerCustomSource(m.providerInstallSource())
+}
+
+// providerInstallerCustomSource is a variant of providerInstaller that
+// allows the caller to specify a different installation source than the one
+// that would naturally be selected.
+//
+// The result of this method has the same dependencies and constraints as
+// providerInstaller.
+//
+// The result of providerInstallerCustomSource differs from
+// providerInstaller only in how it determines package installation locations
+// during EnsureProviderVersions. A caller that doesn't call
+// EnsureProviderVersions (anything other than "terraform init") can safely
+// just use the providerInstaller method unconditionally.
+func (m *Meta) providerInstallerCustomSource(source getproviders.Source) *providercache.Installer {
+	targetDir := m.providerLocalCacheDir()
+	globalCacheDir := m.providerGlobalCacheDir()
+	inst := providercache.NewInstaller(targetDir, source)
+	if globalCacheDir != nil {
+		inst.SetGlobalCacheDir(globalCacheDir)
+		inst.SetGlobalCacheDirMayBreakDependencyLockFile(m.PluginCacheMayBreakDependencyLockFile)
+	}
+	var builtinProviderTypes []string
+	for ty := range m.internalProviders() {
+		builtinProviderTypes = append(builtinProviderTypes, ty)
+	}
+	inst.SetBuiltInProviderTypes(builtinProviderTypes)
+	unmanagedProviderTypes := make(map[addrs.Provider]struct{}, len(m.UnmanagedProviders))
+	for ty := range m.UnmanagedProviders {
+		unmanagedProviderTypes[ty] = struct{}{}
+	}
+	inst.SetUnmanagedProviderTypes(unmanagedProviderTypes)
+	return inst
+}
+
+// providerCustomLocalDirectorySource produces a provider source that consults
+// only the given local filesystem directories for plugins to install.
+//
+// This is used to implement the -plugin-dir option for "terraform init", where
+// the result of this method is used instead of what would've been returned
+// from m.providerInstallSource.
+//
+// If the given list of directories is empty then the resulting source will
+// have no providers available for installation at all.
+func (m *Meta) providerCustomLocalDirectorySource(dirs []string) getproviders.Source {
+	var ret getproviders.MultiSource
+	for _, dir := range dirs {
+		ret = append(ret, getproviders.MultiSourceSelector{
+			Source: getproviders.NewFilesystemMirrorSource(dir),
+		})
+	}
+	return ret
+}
+
+// providerLocalCacheDir returns an object representing the
+// configuration-specific local cache directory. This is the
+// only location consulted for provider plugin packages for Terraform
+// operations other than provider installation.
+//
+// Only the provider installer (in "terraform init") is permitted to make
+// modifications to this cache directory. All other commands must treat it
+// as read-only.
+//
+// Only one object returned from this method should be live at any time,
+// because objects inside contain caches that must be maintained properly.
+func (m *Meta) providerLocalCacheDir() *providercache.Dir {
+	m.fixupMissingWorkingDir()
+	dir := m.WorkingDir.ProviderLocalCacheDir()
+	return providercache.NewDir(dir)
+}
+
+// providerGlobalCacheDir returns an object representing the shared global
+// provider cache directory, used as a read-through cache when installing
+// new provider plugin packages.
+//
+// This function may return nil, in which case there is no global cache
+// configured and new packages should be downloaded directly into individual
+// configuration-specific cache directories.
+//
+// Only one object returned from this method should be live at any time,
+// because objects inside contain caches that must be maintained properly.
+func (m *Meta) providerGlobalCacheDir() *providercache.Dir {
+	dir := m.PluginCacheDir
+	if dir == "" {
+		return nil // cache disabled
+	}
+	return providercache.NewDir(dir)
+}
+
+// providerInstallSource returns an object that knows how to consult one or
+// more external sources to determine the availability of and package
+// locations for versions of Terraform providers that are available for
+// automatic installation.
+//
+// This returns the standard provider install source that consults a number
+// of directories selected either automatically or via the CLI configuration.
+// Users may choose to override this during a "terraform init" command by
+// specifying one or more -plugin-dir options, in which case the installation
+// process will construct its own source consulting only those directories
+// and use that instead.
+func (m *Meta) providerInstallSource() getproviders.Source {
+	// A provider source should always be provided in normal use, but our
+	// unit tests might not always populate Meta fully and so we'll be robust
+	// by returning a non-nil source that just always answers that no plugins
+	// are available.
+	if m.ProviderSource == nil {
+		// A multi-source with no underlying sources is effectively an
+		// always-empty source.
+		return getproviders.MultiSource(nil)
+	}
+	return m.ProviderSource
+}
+
+// providerDevOverrideInitWarnings returns a diagnostics that contains at
+// least one warning if and only if there is at least one provider development
+// override in effect. If not, the result is always empty. The result never
+// contains error diagnostics.
+//
+// The init command can use this to include a warning that the results
+// may differ from what's expected due to the development overrides. For
+// other commands, providerDevOverrideRuntimeWarnings should be used.
+func (m *Meta) providerDevOverrideInitWarnings() tfdiags.Diagnostics {
+	if len(m.ProviderDevOverrides) == 0 {
+		return nil
+	}
+	var detailMsg strings.Builder
+	detailMsg.WriteString("The following provider development overrides are set in the CLI configuration:\n")
+	for addr, path := range m.ProviderDevOverrides {
+		detailMsg.WriteString(fmt.Sprintf(" - %s in %s\n", addr.ForDisplay(), path))
+	}
+	detailMsg.WriteString("\nSkip terraform init when using provider development overrides. It is not necessary and may error unexpectedly.")
+	return tfdiags.Diagnostics{
+		tfdiags.Sourceless(
+			tfdiags.Warning,
+			"Provider development overrides are in effect",
+			detailMsg.String(),
+		),
+	}
+}
+
+// providerDevOverrideRuntimeWarnings returns a diagnostics that contains at
+// least one warning if and only if there is at least one provider development
+// override in effect. If not, the result is always empty. The result never
+// contains error diagnostics.
+//
+// Certain commands can use this to include a warning that their results
+// may differ from what's expected due to the development overrides. It's
+// not necessary to bother the user with this warning on every command, but
+// it's helpful to return it on commands that have externally-visible side
+// effects and on commands that are used to verify conformance to schemas.
+//
+// See providerDevOverrideInitWarnings for warnings specific to the init
+// command.
+func (m *Meta) providerDevOverrideRuntimeWarnings() tfdiags.Diagnostics {
+	if len(m.ProviderDevOverrides) == 0 {
+		return nil
+	}
+	var detailMsg strings.Builder
+	detailMsg.WriteString("The following provider development overrides are set in the CLI configuration:\n")
+	for addr, path := range m.ProviderDevOverrides {
+		detailMsg.WriteString(fmt.Sprintf(" - %s in %s\n", addr.ForDisplay(), path))
+	}
+	detailMsg.WriteString("\nThe behavior may therefore not match any released version of the provider and applying changes may cause the state to become incompatible with published releases.")
+	return tfdiags.Diagnostics{
+		tfdiags.Sourceless(
+			tfdiags.Warning,
+			"Provider development overrides are in effect",
+			detailMsg.String(),
+		),
+	}
+}
+
+// providerFactories uses the selections made previously by an installer in
+// the local cache directory (m.providerLocalCacheDir) to produce a map
+// from provider addresses to factory functions to create instances of
+// those providers.
+//
+// providerFactories will return an error if the installer's selections cannot
+// be honored with what is currently in the cache, such as if a selected
+// package has been removed from the cache or if the contents of a selected
+// package have been modified outside of the installer. If it returns an error,
+// the returned map may be incomplete or invalid, but will be as complete
+// as possible given the cause of the error.
+func (m *Meta) providerFactories() (map[addrs.Provider]providers.Factory, error) {
+	locks, diags := m.lockedDependencies()
+	if diags.HasErrors() {
+		return nil, fmt.Errorf("failed to read dependency lock file: %s", diags.Err())
+	}
+
+	// We'll always run through all of our providers, even if one of them
+	// encounters an error, so that we can potentially report multiple errors
+	// where appropriate and so that callers can potentially make use of the
+	// partial result we return if e.g. they want to enumerate which providers
+	// are available, or call into one of the providers that didn't fail.
+	errs := make(map[addrs.Provider]error)
+
+	// For the providers from the lock file, we expect them to be already
+	// available in the provider cache because "terraform init" should already
+	// have put them there.
+	providerLocks := locks.AllProviders()
+	cacheDir := m.providerLocalCacheDir()
+
+	// The internal providers are _always_ available, even if the configuration
+	// doesn't request them, because they don't need any special installation
+	// and they'll just be ignored if not used.
+	internalFactories := m.internalProviders()
+
+	// We have two different special cases aimed at provider development
+	// use-cases, which are not for "production" use:
+	// - The CLI config can specify that a particular provider should always
+	// use a plugin from a particular local directory, ignoring anything the
+	// lock file or cache directory might have to say about it. This is useful
+	// for manual testing of local development builds.
+	// - The Terraform SDK test harness (and possibly other callers in future)
+	// can ask that we use its own already-started provider servers, which we
+	// call "unmanaged" because Terraform isn't responsible for starting
+	// and stopping them. This is intended for automated testing where a
+	// calling harness is responsible both for starting the provider server
+	// and orchestrating one or more non-interactive Terraform runs that then
+	// exercise it.
+	// Unmanaged providers take precedence over overridden providers because
+	// overrides are typically a "session-level" setting while unmanaged
+	// providers are typically scoped to a single unattended command.
+	devOverrideProviders := m.ProviderDevOverrides
+	unmanagedProviders := m.UnmanagedProviders
+
+	factories := make(map[addrs.Provider]providers.Factory, len(providerLocks)+len(internalFactories)+len(unmanagedProviders))
+	for name, factory := range internalFactories {
+		factories[addrs.NewBuiltInProvider(name)] = factory
+	}
+	for provider, lock := range providerLocks {
+		reportError := func(thisErr error) {
+			errs[provider] = thisErr
+			// We'll populate a provider factory that just echoes our error
+			// again if called, which allows us to still report a helpful
+			// error even if it gets detected downstream somewhere from the
+			// caller using our partial result.
+			factories[provider] = providerFactoryError(thisErr)
+		}
+
+		if locks.ProviderIsOverridden(provider) {
+			// Overridden providers we'll handle with the other separate
+			// loops below, for dev overrides etc.
+			continue
+		}
+
+		version := lock.Version()
+		cached := cacheDir.ProviderVersion(provider, version)
+		if cached == nil {
+			reportError(fmt.Errorf(
+				"there is no package for %s %s cached in %s",
+				provider, version, cacheDir.BasePath(),
+			))
+			continue
+		}
+		// The cached package must match one of the checksums recorded in
+		// the lock file, if any.
+		if allowedHashes := lock.PreferredHashes(); len(allowedHashes) != 0 {
+			matched, err := cached.MatchesAnyHash(allowedHashes)
+			if err != nil {
+				reportError(fmt.Errorf(
+					"failed to verify checksum of %s %s package cached in in %s: %s",
+					provider, version, cacheDir.BasePath(), err,
+				))
+				continue
+			}
+			if !matched {
+				reportError(fmt.Errorf(
+					"the cached package for %s %s (in %s) does not match any of the checksums recorded in the dependency lock file",
+					provider, version, cacheDir.BasePath(),
+				))
+				continue
+			}
+		}
+		factories[provider] = providerFactory(cached)
+	}
+	for provider, localDir := range devOverrideProviders {
+		factories[provider] = devOverrideProviderFactory(provider, localDir)
+	}
+	for provider, reattach := range unmanagedProviders {
+		factories[provider] = unmanagedProviderFactory(provider, reattach)
+	}
+
+	var err error
+	if len(errs) > 0 {
+		err = providerPluginErrors(errs)
+	}
+	return factories, err
+}
+
+func (m *Meta) internalProviders() map[string]providers.Factory {
+	return map[string]providers.Factory{
+		"terraform": func() (providers.Interface, error) {
+			return terraformProvider.NewProvider(), nil
+		},
+		"test": func() (providers.Interface, error) {
+			return moduletest.NewProvider(), nil
+		},
+	}
+}
+
+// providerFactory produces a provider factory that runs up the executable
+// file in the given cache package and uses go-plugin to implement
+// providers.Interface against it.
+func providerFactory(meta *providercache.CachedProvider) providers.Factory {
+	return func() (providers.Interface, error) {
+		execFile, err := meta.ExecutableFile()
+		if err != nil {
+			return nil, err
+		}
+
+		config := &plugin.ClientConfig{
+			HandshakeConfig:  tfplugin.Handshake,
+			Logger:           logging.NewProviderLogger(""),
+			AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
+			Managed:          true,
+			Cmd:              exec.Command(execFile),
+			AutoMTLS:         enableProviderAutoMTLS,
+			VersionedPlugins: tfplugin.VersionedPlugins,
+			SyncStdout:       logging.PluginOutputMonitor(fmt.Sprintf("%s:stdout", meta.Provider)),
+			SyncStderr:       logging.PluginOutputMonitor(fmt.Sprintf("%s:stderr", meta.Provider)),
+		}
+
+		client := plugin.NewClient(config)
+		rpcClient, err := client.Client()
+		if err != nil {
+			return nil, err
+		}
+
+		raw, err := rpcClient.Dispense(tfplugin.ProviderPluginName)
+		if err != nil {
+			return nil, err
+		}
+
+		// store the client so that the plugin can kill the child process
+		protoVer := client.NegotiatedVersion()
+		switch protoVer {
+		case 5:
+			p := raw.(*tfplugin.GRPCProvider)
+			p.PluginClient = client
+			return p, nil
+		case 6:
+			p := raw.(*tfplugin6.GRPCProvider)
+			p.PluginClient = client
+			return p, nil
+		default:
+			panic("unsupported protocol version")
+		}
+	}
+}
+
+func devOverrideProviderFactory(provider addrs.Provider, localDir getproviders.PackageLocalDir) providers.Factory {
+	// A dev override is essentially a synthetic cache entry for our purposes
+	// here, so that's how we'll construct it. The providerFactory function
+	// doesn't actually care about the version, so we can leave it
+	// unspecified: overridden providers are not explicitly versioned.
+	log.Printf("[DEBUG] Provider %s is overridden to load from %s", provider, localDir)
+	return providerFactory(&providercache.CachedProvider{
+		Provider:   provider,
+		Version:    getproviders.UnspecifiedVersion,
+		PackageDir: string(localDir),
+	})
+}
+
+// unmanagedProviderFactory produces a provider factory that uses the passed
+// reattach information to connect to go-plugin processes that are already
+// running, and implements providers.Interface against it.
+func unmanagedProviderFactory(provider addrs.Provider, reattach *plugin.ReattachConfig) providers.Factory {
+	return func() (providers.Interface, error) {
+		config := &plugin.ClientConfig{
+			HandshakeConfig:  tfplugin.Handshake,
+			Logger:           logging.NewProviderLogger("unmanaged."),
+			AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
+			Managed:          false,
+			Reattach:         reattach,
+			SyncStdout:       logging.PluginOutputMonitor(fmt.Sprintf("%s:stdout", provider)),
+			SyncStderr:       logging.PluginOutputMonitor(fmt.Sprintf("%s:stderr", provider)),
+		}
+
+		if reattach.ProtocolVersion == 0 {
+			// As of the 0.15 release, sdk.v2 doesn't include the protocol
+			// version in the ReattachConfig (only recently added to
+			// go-plugin), so client.NegotiatedVersion() always returns 0. We
+			// assume that an unmanaged provider reporting protocol version 0 is
+			// actually using proto v5 for backwards compatibility.
+			if defaultPlugins, ok := tfplugin.VersionedPlugins[5]; ok {
+				config.Plugins = defaultPlugins
+			} else {
+				return nil, errors.New("no supported plugins for protocol 0")
+			}
+		} else if plugins, ok := tfplugin.VersionedPlugins[reattach.ProtocolVersion]; !ok {
+			return nil, fmt.Errorf("no supported plugins for protocol %d", reattach.ProtocolVersion)
+		} else {
+			config.Plugins = plugins
+		}
+
+		client := plugin.NewClient(config)
+		rpcClient, err := client.Client()
+		if err != nil {
+			return nil, err
+		}
+
+		raw, err := rpcClient.Dispense(tfplugin.ProviderPluginName)
+		if err != nil {
+			return nil, err
+		}
+
+		// store the client so that the plugin can kill the child process
+		protoVer := client.NegotiatedVersion()
+		switch protoVer {
+		case 0, 5:
+			// As of the 0.15 release, sdk.v2 doesn't include the protocol
+			// version in the ReattachConfig (only recently added to
+			// go-plugin), so client.NegotiatedVersion() always returns 0. We
+			// assume that an unmanaged provider reporting protocol version 0 is
+			// actually using proto v5 for backwards compatibility.
+			p := raw.(*tfplugin.GRPCProvider)
+			p.PluginClient = client
+			return p, nil
+		case 6:
+			p := raw.(*tfplugin6.GRPCProvider)
+			p.PluginClient = client
+			return p, nil
+		default:
+			return nil, fmt.Errorf("unsupported protocol version %d", protoVer)
+		}
+	}
+}
+
+// providerFactoryError is a stub providers.Factory that returns an error
+// when called. It's used to allow providerFactories to still produce a
+// factory for each available provider in an error case, for situations
+// where the caller can do something useful with that partial result.
+func providerFactoryError(err error) providers.Factory {
+	return func() (providers.Interface, error) {
+		return nil, err
+	}
+}
+
+// providerPluginErrors is an error implementation we can return from
+// Meta.providerFactories to capture potentially multiple errors about the
+// locally-cached plugins (or lack thereof) for particular external providers.
+//
+// Some functions closer to the UI layer can sniff for this error type in order
+// to return a more helpful error message.
+type providerPluginErrors map[addrs.Provider]error
+
+func (errs providerPluginErrors) Error() string {
+	if len(errs) == 1 {
+		for addr, err := range errs {
+			return fmt.Sprintf("%s: %s", addr, err)
+		}
+	}
+	var buf bytes.Buffer
+	fmt.Fprintf(&buf, "missing or corrupted provider plugins:")
+	for addr, err := range errs {
+		fmt.Fprintf(&buf, "\n  - %s: %s", addr, err)
+	}
+	return buf.String()
+}
diff --git a/v1.5.7/internal/command/meta_test.go b/v1.5.7/internal/command/meta_test.go
new file mode 100644
index 0000000..9419f7d
--- /dev/null
+++ b/v1.5.7/internal/command/meta_test.go
@@ -0,0 +1,418 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"reflect"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/backend/local"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/mitchellh/cli"
+)
+
+func TestMetaColorize(t *testing.T) {
+	var m *Meta
+	var args, args2 []string
+
+	// Test basic, color
+	m = new(Meta)
+	m.Color = true
+	args = []string{"foo", "bar"}
+	args2 = []string{"foo", "bar"}
+	args = m.process(args)
+	if !reflect.DeepEqual(args, args2) {
+		t.Fatalf("bad: %#v", args)
+	}
+	if m.Colorize().Disable {
+		t.Fatal("should not be disabled")
+	}
+
+	// Test basic, no change
+	m = new(Meta)
+	args = []string{"foo", "bar"}
+	args2 = []string{"foo", "bar"}
+	args = m.process(args)
+	if !reflect.DeepEqual(args, args2) {
+		t.Fatalf("bad: %#v", args)
+	}
+	if !m.Colorize().Disable {
+		t.Fatal("should be disabled")
+	}
+
+	// Test disable #1
+	m = new(Meta)
+	m.Color = true
+	args = []string{"foo", "-no-color", "bar"}
+	args2 = []string{"foo", "bar"}
+	args = m.process(args)
+	if !reflect.DeepEqual(args, args2) {
+		t.Fatalf("bad: %#v", args)
+	}
+	if !m.Colorize().Disable {
+		t.Fatal("should be disabled")
+	}
+
+	// Test disable #2
+	// Verify multiple -no-color options are removed from args slice.
+	// E.g. an additional -no-color arg could be added by TF_CLI_ARGS.
+	m = new(Meta)
+	m.Color = true
+	args = []string{"foo", "-no-color", "bar", "-no-color"}
+	args2 = []string{"foo", "bar"}
+	args = m.process(args)
+	if !reflect.DeepEqual(args, args2) {
+		t.Fatalf("bad: %#v", args)
+	}
+	if !m.Colorize().Disable {
+		t.Fatal("should be disabled")
+	}
+}
+
+func TestMetaInputMode(t *testing.T) {
+	test = false
+	defer func() { test = true }()
+
+	m := new(Meta)
+	args := []string{}
+
+	fs := m.extendedFlagSet("foo")
+	if err := fs.Parse(args); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if m.InputMode() != terraform.InputModeStd {
+		t.Fatalf("bad: %#v", m.InputMode())
+	}
+}
+
+func TestMetaInputMode_envVar(t *testing.T) {
+	test = false
+	defer func() { test = true }()
+	old := os.Getenv(InputModeEnvVar)
+	defer os.Setenv(InputModeEnvVar, old)
+
+	m := new(Meta)
+	args := []string{}
+
+	fs := m.extendedFlagSet("foo")
+	if err := fs.Parse(args); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	off := terraform.InputMode(0)
+	on := terraform.InputModeStd
+	cases := []struct {
+		EnvVar   string
+		Expected terraform.InputMode
+	}{
+		{"false", off},
+		{"0", off},
+		{"true", on},
+		{"1", on},
+	}
+
+	for _, tc := range cases {
+		os.Setenv(InputModeEnvVar, tc.EnvVar)
+		if m.InputMode() != tc.Expected {
+			t.Fatalf("expected InputMode: %#v, got: %#v", tc.Expected, m.InputMode())
+		}
+	}
+}
+
+func TestMetaInputMode_disable(t *testing.T) {
+	test = false
+	defer func() { test = true }()
+
+	m := new(Meta)
+	args := []string{"-input=false"}
+
+	fs := m.extendedFlagSet("foo")
+	if err := fs.Parse(args); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if m.InputMode() > 0 {
+		t.Fatalf("bad: %#v", m.InputMode())
+	}
+}
+
+func TestMeta_initStatePaths(t *testing.T) {
+	m := new(Meta)
+	m.initStatePaths()
+
+	if m.statePath != DefaultStateFilename {
+		t.Fatalf("bad: %#v", m)
+	}
+	if m.stateOutPath != DefaultStateFilename {
+		t.Fatalf("bad: %#v", m)
+	}
+	if m.backupPath != DefaultStateFilename+DefaultBackupExtension {
+		t.Fatalf("bad: %#v", m)
+	}
+
+	m = new(Meta)
+	m.statePath = "foo"
+	m.initStatePaths()
+
+	if m.stateOutPath != "foo" {
+		t.Fatalf("bad: %#v", m)
+	}
+	if m.backupPath != "foo"+DefaultBackupExtension {
+		t.Fatalf("bad: %#v", m)
+	}
+
+	m = new(Meta)
+	m.stateOutPath = "foo"
+	m.initStatePaths()
+
+	if m.statePath != DefaultStateFilename {
+		t.Fatalf("bad: %#v", m)
+	}
+	if m.backupPath != "foo"+DefaultBackupExtension {
+		t.Fatalf("bad: %#v", m)
+	}
+}
+
+func TestMeta_Env(t *testing.T) {
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	m := new(Meta)
+
+	env, err := m.Workspace()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if env != backend.DefaultStateName {
+		t.Fatalf("expected env %q, got env %q", backend.DefaultStateName, env)
+	}
+
+	testEnv := "test_env"
+	if err := m.SetWorkspace(testEnv); err != nil {
+		t.Fatal("error setting env:", err)
+	}
+
+	env, _ = m.Workspace()
+	if env != testEnv {
+		t.Fatalf("expected env %q, got env %q", testEnv, env)
+	}
+
+	if err := m.SetWorkspace(backend.DefaultStateName); err != nil {
+		t.Fatal("error setting env:", err)
+	}
+
+	env, _ = m.Workspace()
+	if env != backend.DefaultStateName {
+		t.Fatalf("expected env %q, got env %q", backend.DefaultStateName, env)
+	}
+}
+
+func TestMeta_Workspace_override(t *testing.T) {
+	defer func(value string) {
+		os.Setenv(WorkspaceNameEnvVar, value)
+	}(os.Getenv(WorkspaceNameEnvVar))
+
+	m := new(Meta)
+
+	testCases := map[string]struct {
+		workspace string
+		err       error
+	}{
+		"": {
+			"default",
+			nil,
+		},
+		"development": {
+			"development",
+			nil,
+		},
+		"invalid name": {
+			"",
+			errInvalidWorkspaceNameEnvVar,
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			os.Setenv(WorkspaceNameEnvVar, name)
+			workspace, err := m.Workspace()
+			if workspace != tc.workspace {
+				t.Errorf("Unexpected workspace\n got: %s\nwant: %s\n", workspace, tc.workspace)
+			}
+			if err != tc.err {
+				t.Errorf("Unexpected error\n got: %s\nwant: %s\n", err, tc.err)
+			}
+		})
+	}
+}
+
+func TestMeta_Workspace_invalidSelected(t *testing.T) {
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	// this is an invalid workspace name
+	workspace := "test workspace"
+
+	// create the workspace directories
+	if err := os.MkdirAll(filepath.Join(local.DefaultWorkspaceDir, workspace), 0755); err != nil {
+		t.Fatal(err)
+	}
+
+	// create the workspace file to select it
+	if err := os.MkdirAll(DefaultDataDir, 0755); err != nil {
+		t.Fatal(err)
+	}
+	if err := ioutil.WriteFile(filepath.Join(DefaultDataDir, local.DefaultWorkspaceFile), []byte(workspace), 0644); err != nil {
+		t.Fatal(err)
+	}
+
+	m := new(Meta)
+
+	ws, err := m.Workspace()
+	if ws != workspace {
+		t.Errorf("Unexpected workspace\n got: %s\nwant: %s\n", ws, workspace)
+	}
+	if err != nil {
+		t.Errorf("Unexpected error: %s", err)
+	}
+}
+
+func TestMeta_process(t *testing.T) {
+	test = false
+	defer func() { test = true }()
+
+	// Create a temporary directory for our cwd
+	d := t.TempDir()
+	os.MkdirAll(d, 0755)
+	defer testChdir(t, d)()
+
+	// At one point it was the responsibility of this process function to
+	// insert fake additional -var-file options into the command line
+	// if the automatic tfvars files were present. This is no longer the
+	// responsibility of process (it happens in collectVariableValues instead)
+	// but we're still testing with these files in place to verify that
+	// they _aren't_ being interpreted by process, since that could otherwise
+	// cause them to be added more than once and mess up the precedence order.
+	defaultVarsfile := "terraform.tfvars"
+	err := ioutil.WriteFile(
+		filepath.Join(d, defaultVarsfile),
+		[]byte(""),
+		0644)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	fileFirstAlphabetical := "a-file.auto.tfvars"
+	err = ioutil.WriteFile(
+		filepath.Join(d, fileFirstAlphabetical),
+		[]byte(""),
+		0644)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	fileLastAlphabetical := "z-file.auto.tfvars"
+	err = ioutil.WriteFile(
+		filepath.Join(d, fileLastAlphabetical),
+		[]byte(""),
+		0644)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	// Regular tfvars files will not be autoloaded
+	fileIgnored := "ignored.tfvars"
+	err = ioutil.WriteFile(
+		filepath.Join(d, fileIgnored),
+		[]byte(""),
+		0644)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	tests := []struct {
+		GivenArgs    []string
+		FilteredArgs []string
+		ExtraCheck   func(*testing.T, *Meta)
+	}{
+		{
+			[]string{},
+			[]string{},
+			func(t *testing.T, m *Meta) {
+				if got, want := m.color, true; got != want {
+					t.Errorf("wrong m.color value %#v; want %#v", got, want)
+				}
+				if got, want := m.Color, true; got != want {
+					t.Errorf("wrong m.Color value %#v; want %#v", got, want)
+				}
+			},
+		},
+		{
+			[]string{"-no-color"},
+			[]string{},
+			func(t *testing.T, m *Meta) {
+				if got, want := m.color, false; got != want {
+					t.Errorf("wrong m.color value %#v; want %#v", got, want)
+				}
+				if got, want := m.Color, false; got != want {
+					t.Errorf("wrong m.Color value %#v; want %#v", got, want)
+				}
+			},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%s", test.GivenArgs), func(t *testing.T) {
+			m := new(Meta)
+			m.Color = true // this is the default also for normal use, overridden by -no-color
+			args := test.GivenArgs
+			args = m.process(args)
+
+			if !cmp.Equal(test.FilteredArgs, args) {
+				t.Errorf("wrong filtered arguments\n%s", cmp.Diff(test.FilteredArgs, args))
+			}
+
+			if test.ExtraCheck != nil {
+				test.ExtraCheck(t, m)
+			}
+		})
+	}
+}
+
+func TestCommand_checkRequiredVersion(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("command-check-required-version"), td)
+	defer testChdir(t, td)()
+
+	ui := cli.NewMockUi()
+	meta := Meta{
+		Ui: ui,
+	}
+
+	diags := meta.checkRequiredVersion()
+	if diags == nil {
+		t.Fatalf("diagnostics should contain unmet version constraint, but is nil")
+	}
+
+	meta.showDiagnostics(diags)
+
+	// Required version diags are correct
+	errStr := ui.ErrorWriter.String()
+	if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) {
+		t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr)
+	}
+	if strings.Contains(errStr, `required_version = ">= 0.13.0"`) {
+		t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr)
+	}
+}
diff --git a/v1.5.7/internal/command/meta_vars.go b/v1.5.7/internal/command/meta_vars.go
new file mode 100644
index 0000000..5cbec0d
--- /dev/null
+++ b/v1.5.7/internal/command/meta_vars.go
@@ -0,0 +1,268 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	hcljson "github.com/hashicorp/hcl/v2/json"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// VarEnvPrefix is the prefix for environment variables that represent values
+// for root module input variables.
+const VarEnvPrefix = "TF_VAR_"
+
+// collectVariableValues inspects the various places that root module input variable
+// values can come from and constructs a map ready to be passed to the
+// backend as part of a backend.Operation.
+//
+// This method returns diagnostics relating to the collection of the values,
+// but the values themselves may produce additional diagnostics when finally
+// parsed.
+func (m *Meta) collectVariableValues() (map[string]backend.UnparsedVariableValue, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	ret := map[string]backend.UnparsedVariableValue{}
+
+	// First we'll deal with environment variables, since they have the lowest
+	// precedence.
+	{
+		env := os.Environ()
+		for _, raw := range env {
+			if !strings.HasPrefix(raw, VarEnvPrefix) {
+				continue
+			}
+			raw = raw[len(VarEnvPrefix):] // trim the prefix
+
+			eq := strings.Index(raw, "=")
+			if eq == -1 {
+				// Seems invalid, so we'll ignore it.
+				continue
+			}
+
+			name := raw[:eq]
+			rawVal := raw[eq+1:]
+
+			ret[name] = unparsedVariableValueString{
+				str:        rawVal,
+				name:       name,
+				sourceType: terraform.ValueFromEnvVar,
+			}
+		}
+	}
+
+	// Next up we have some implicit files that are loaded automatically
+	// if they are present. There's the original terraform.tfvars
+	// (DefaultVarsFilename) along with the later-added search for all files
+	// ending in .auto.tfvars.
+	if _, err := os.Stat(DefaultVarsFilename); err == nil {
+		moreDiags := m.addVarsFromFile(DefaultVarsFilename, terraform.ValueFromAutoFile, ret)
+		diags = diags.Append(moreDiags)
+	}
+	const defaultVarsFilenameJSON = DefaultVarsFilename + ".json"
+	if _, err := os.Stat(defaultVarsFilenameJSON); err == nil {
+		moreDiags := m.addVarsFromFile(defaultVarsFilenameJSON, terraform.ValueFromAutoFile, ret)
+		diags = diags.Append(moreDiags)
+	}
+	if infos, err := ioutil.ReadDir("."); err == nil {
+		// "infos" is already sorted by name, so we just need to filter it here.
+		for _, info := range infos {
+			name := info.Name()
+			if !isAutoVarFile(name) {
+				continue
+			}
+			moreDiags := m.addVarsFromFile(name, terraform.ValueFromAutoFile, ret)
+			diags = diags.Append(moreDiags)
+		}
+	}
+
+	// Finally we process values given explicitly on the command line, either
+	// as individual literal settings or as additional files to read.
+	for _, rawFlag := range m.variableArgs.AllItems() {
+		switch rawFlag.Name {
+		case "-var":
+			// Value should be in the form "name=value", where value is a
+			// raw string whose interpretation will depend on the variable's
+			// parsing mode.
+			raw := rawFlag.Value
+			eq := strings.Index(raw, "=")
+			if eq == -1 {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid -var option",
+					fmt.Sprintf("The given -var option %q is not correctly specified. Must be a variable name and value separated by an equals sign, like -var=\"key=value\".", raw),
+				))
+				continue
+			}
+			name := raw[:eq]
+			rawVal := raw[eq+1:]
+			if strings.HasSuffix(name, " ") {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid -var option",
+					fmt.Sprintf("Variable name %q is invalid due to trailing space. Did you mean -var=\"%s=%s\"?", name, strings.TrimSuffix(name, " "), strings.TrimPrefix(rawVal, " ")),
+				))
+				continue
+			}
+			ret[name] = unparsedVariableValueString{
+				str:        rawVal,
+				name:       name,
+				sourceType: terraform.ValueFromCLIArg,
+			}
+
+		case "-var-file":
+			moreDiags := m.addVarsFromFile(rawFlag.Value, terraform.ValueFromNamedFile, ret)
+			diags = diags.Append(moreDiags)
+
+		default:
+			// Should never happen; always a bug in the code that built up
+			// the contents of m.variableArgs.
+			diags = diags.Append(fmt.Errorf("unsupported variable option name %q (this is a bug in Terraform)", rawFlag.Name))
+		}
+	}
+
+	return ret, diags
+}
+
+func (m *Meta) addVarsFromFile(filename string, sourceType terraform.ValueSourceType, to map[string]backend.UnparsedVariableValue) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	src, err := ioutil.ReadFile(filename)
+	if err != nil {
+		if os.IsNotExist(err) {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to read variables file",
+				fmt.Sprintf("Given variables file %s does not exist.", filename),
+			))
+		} else {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to read variables file",
+				fmt.Sprintf("Error while reading %s: %s.", filename, err),
+			))
+		}
+		return diags
+	}
+
+	loader, err := m.initConfigLoader()
+	if err != nil {
+		diags = diags.Append(err)
+		return diags
+	}
+
+	// Record the file source code for snippets in diagnostic messages.
+	loader.Parser().ForceFileSource(filename, src)
+
+	var f *hcl.File
+	if strings.HasSuffix(filename, ".json") {
+		var hclDiags hcl.Diagnostics
+		f, hclDiags = hcljson.Parse(src, filename)
+		diags = diags.Append(hclDiags)
+		if f == nil || f.Body == nil {
+			return diags
+		}
+	} else {
+		var hclDiags hcl.Diagnostics
+		f, hclDiags = hclsyntax.ParseConfig(src, filename, hcl.Pos{Line: 1, Column: 1})
+		diags = diags.Append(hclDiags)
+		if f == nil || f.Body == nil {
+			return diags
+		}
+	}
+
+	// Before we do our real decode, we'll probe to see if there are any blocks
+	// of type "variable" in this body, since it's a common mistake for new
+	// users to put variable declarations in tfvars rather than variable value
+	// definitions, and otherwise our error message for that case is not so
+	// helpful.
+	{
+		content, _, _ := f.Body.PartialContent(&hcl.BodySchema{
+			Blocks: []hcl.BlockHeaderSchema{
+				{
+					Type:       "variable",
+					LabelNames: []string{"name"},
+				},
+			},
+		})
+		for _, block := range content.Blocks {
+			name := block.Labels[0]
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Variable declaration in .tfvars file",
+				Detail:   fmt.Sprintf("A .tfvars file is used to assign values to variables that have already been declared in .tf files, not to declare new variables. To declare variable %q, place this block in one of your .tf files, such as variables.tf.\n\nTo set a value for this variable in %s, use the definition syntax instead:\n    %s = <value>", name, block.TypeRange.Filename, name),
+				Subject:  &block.TypeRange,
+			})
+		}
+		if diags.HasErrors() {
+			// If we already found problems then JustAttributes below will find
+			// the same problems with less-helpful messages, so we'll bail for
+			// now to let the user focus on the immediate problem.
+			return diags
+		}
+	}
+
+	attrs, hclDiags := f.Body.JustAttributes()
+	diags = diags.Append(hclDiags)
+
+	for name, attr := range attrs {
+		to[name] = unparsedVariableValueExpression{
+			expr:       attr.Expr,
+			sourceType: sourceType,
+		}
+	}
+	return diags
+}
+
+// unparsedVariableValueLiteral is a backend.UnparsedVariableValue
+// implementation that was actually already parsed (!). This is
+// intended to deal with expressions inside "tfvars" files.
+type unparsedVariableValueExpression struct {
+	expr       hcl.Expression
+	sourceType terraform.ValueSourceType
+}
+
+func (v unparsedVariableValueExpression) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	val, hclDiags := v.expr.Value(nil) // nil because no function calls or variable references are allowed here
+	diags = diags.Append(hclDiags)
+
+	rng := tfdiags.SourceRangeFromHCL(v.expr.Range())
+
+	return &terraform.InputValue{
+		Value:       val,
+		SourceType:  v.sourceType,
+		SourceRange: rng,
+	}, diags
+}
+
+// unparsedVariableValueString is a backend.UnparsedVariableValue
+// implementation that parses its value from a string. This can be used
+// to deal with values given directly on the command line and via environment
+// variables.
+type unparsedVariableValueString struct {
+	str        string
+	name       string
+	sourceType terraform.ValueSourceType
+}
+
+func (v unparsedVariableValueString) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	val, hclDiags := mode.Parse(v.name, v.str)
+	diags = diags.Append(hclDiags)
+
+	return &terraform.InputValue{
+		Value:      val,
+		SourceType: v.sourceType,
+	}, diags
+}
diff --git a/v1.5.7/internal/command/metadata_command.go b/v1.5.7/internal/command/metadata_command.go
new file mode 100644
index 0000000..6219630
--- /dev/null
+++ b/v1.5.7/internal/command/metadata_command.go
@@ -0,0 +1,34 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"strings"
+
+	"github.com/mitchellh/cli"
+)
+
+// MetadataCommand is a Command implementation that just shows help for
+// the subcommands nested below it.
+type MetadataCommand struct {
+	Meta
+}
+
+func (c *MetadataCommand) Run(args []string) int {
+	return cli.RunResultHelp
+}
+
+func (c *MetadataCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] metadata <subcommand> [options] [args]
+
+  This command has subcommands for metadata related purposes.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *MetadataCommand) Synopsis() string {
+	return "Metadata related commands"
+}
diff --git a/v1.5.7/internal/command/metadata_functions.go b/v1.5.7/internal/command/metadata_functions.go
new file mode 100644
index 0000000..feb67c7
--- /dev/null
+++ b/v1.5.7/internal/command/metadata_functions.go
@@ -0,0 +1,84 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/command/jsonfunction"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/zclconf/go-cty/cty/function"
+)
+
+var (
+	ignoredFunctions = []string{"map", "list"}
+)
+
+// MetadataFunctionsCommand is a Command implementation that prints out information
+// about the available functions in Terraform.
+type MetadataFunctionsCommand struct {
+	Meta
+}
+
+func (c *MetadataFunctionsCommand) Help() string {
+	return metadataFunctionsCommandHelp
+}
+
+func (c *MetadataFunctionsCommand) Synopsis() string {
+	return "Show signatures and descriptions for the available functions"
+}
+
+func (c *MetadataFunctionsCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	cmdFlags := c.Meta.defaultFlagSet("metadata functions")
+	var jsonOutput bool
+	cmdFlags.BoolVar(&jsonOutput, "json", false, "produce JSON output")
+
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	if !jsonOutput {
+		c.Ui.Error(
+			"The `terraform metadata functions` command requires the `-json` flag.\n")
+		cmdFlags.Usage()
+		return 1
+	}
+
+	scope := &lang.Scope{}
+	funcs := scope.Functions()
+	filteredFuncs := make(map[string]function.Function)
+	for k, v := range funcs {
+		if isIgnoredFunction(k) {
+			continue
+		}
+		filteredFuncs[k] = v
+	}
+
+	jsonFunctions, marshalDiags := jsonfunction.Marshal(filteredFuncs)
+	if marshalDiags.HasErrors() {
+		c.showDiagnostics(marshalDiags)
+		return 1
+	}
+	c.Ui.Output(string(jsonFunctions))
+
+	return 0
+}
+
+const metadataFunctionsCommandHelp = `
+Usage: terraform [global options] metadata functions -json
+
+  Prints out a json representation of the available function signatures.
+`
+
+func isIgnoredFunction(name string) bool {
+	for _, i := range ignoredFunctions {
+		if i == name {
+			return true
+		}
+	}
+	return false
+}
diff --git a/v1.5.7/internal/command/metadata_functions_test.go b/v1.5.7/internal/command/metadata_functions_test.go
new file mode 100644
index 0000000..0c41dc3
--- /dev/null
+++ b/v1.5.7/internal/command/metadata_functions_test.go
@@ -0,0 +1,74 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/mitchellh/cli"
+)
+
+func TestMetadataFunctions_error(t *testing.T) {
+	ui := new(cli.MockUi)
+	c := &MetadataFunctionsCommand{
+		Meta: Meta{
+			Ui: ui,
+		},
+	}
+
+	// This test will always error because it's missing the -json flag
+	if code := c.Run(nil); code != 1 {
+		t.Fatalf("expected error, got:\n%s", ui.OutputWriter.String())
+	}
+}
+
+func TestMetadataFunctions_output(t *testing.T) {
+	ui := new(cli.MockUi)
+	m := Meta{Ui: ui}
+	c := &MetadataFunctionsCommand{Meta: m}
+
+	if code := c.Run([]string{"-json"}); code != 0 {
+		t.Fatalf("wrong exit status %d; want 0\nstderr: %s", code, ui.ErrorWriter.String())
+	}
+
+	var got functions
+	gotString := ui.OutputWriter.String()
+	err := json.Unmarshal([]byte(gotString), &got)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(got.Signatures) < 100 {
+		t.Fatalf("expected at least 100 function signatures, got %d", len(got.Signatures))
+	}
+
+	// check if one particular stable function is correct
+	gotMax, ok := got.Signatures["max"]
+	wantMax := "{\"description\":\"`max` takes one or more numbers and returns the greatest number from the set.\",\"return_type\":\"number\",\"variadic_parameter\":{\"name\":\"numbers\",\"type\":\"number\"}}"
+	if !ok {
+		t.Fatal(`missing function signature for "max"`)
+	}
+	if string(gotMax) != wantMax {
+		t.Fatalf("wrong function signature for \"max\":\ngot: %q\nwant: %q", gotMax, wantMax)
+	}
+
+	stderr := ui.ErrorWriter.String()
+	if stderr != "" {
+		t.Fatalf("expected empty stderr, got:\n%s", stderr)
+	}
+
+	// test that ignored functions are not part of the json
+	for _, v := range ignoredFunctions {
+		_, ok := got.Signatures[v]
+		if ok {
+			t.Fatalf("found ignored function %q inside output", v)
+		}
+	}
+}
+
+type functions struct {
+	FormatVersion string                     `json:"format_version"`
+	Signatures    map[string]json.RawMessage `json:"function_signatures,omitempty"`
+}
diff --git a/v1.5.7/internal/command/output.go b/v1.5.7/internal/command/output.go
new file mode 100644
index 0000000..cbd8f88
--- /dev/null
+++ b/v1.5.7/internal/command/output.go
@@ -0,0 +1,126 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// OutputCommand is a Command implementation that reads an output
+// from a Terraform state and prints it.
+type OutputCommand struct {
+	Meta
+}
+
+func (c *OutputCommand) Run(rawArgs []string) int {
+	// Parse and apply global view arguments
+	common, rawArgs := arguments.ParseView(rawArgs)
+	c.View.Configure(common)
+
+	// Parse and validate flags
+	args, diags := arguments.ParseOutput(rawArgs)
+	if diags.HasErrors() {
+		c.View.Diagnostics(diags)
+		c.View.HelpPrompt("output")
+		return 1
+	}
+
+	view := views.NewOutput(args.ViewType, c.View)
+
+	// Fetch data from state
+	outputs, diags := c.Outputs(args.StatePath)
+	if diags.HasErrors() {
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	// Render the view
+	viewDiags := view.Output(args.Name, outputs)
+	diags = diags.Append(viewDiags)
+
+	view.Diagnostics(diags)
+
+	if diags.HasErrors() {
+		return 1
+	}
+
+	return 0
+}
+
+func (c *OutputCommand) Outputs(statePath string) (map[string]*states.OutputValue, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// Allow state path override
+	if statePath != "" {
+		c.Meta.statePath = statePath
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(nil)
+	diags = diags.Append(backendDiags)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	// This is a read-only command
+	c.ignoreRemoteVersionConflict(b)
+
+	env, err := c.Workspace()
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Error selecting workspace: %s", err))
+		return nil, diags
+	}
+
+	// Get the state
+	stateStore, err := b.StateMgr(env)
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Failed to load state: %s", err))
+		return nil, diags
+	}
+
+	output, err := stateStore.GetRootOutputValues()
+	if err != nil {
+		return nil, diags.Append(err)
+	}
+
+	return output, diags
+}
+
+func (c *OutputCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] output [options] [NAME]
+
+  Reads an output variable from a Terraform state file and prints
+  the value. With no additional arguments, output will display all
+  the outputs for the root module.  If NAME is not specified, all
+  outputs are printed.
+
+Options:
+
+  -state=path      Path to the state file to read. Defaults to
+                   "terraform.tfstate". Ignored when remote 
+                   state is used.
+
+  -no-color        If specified, output won't contain any color.
+
+  -json            If specified, machine readable output will be
+                   printed in JSON format.
+
+  -raw             For value types that can be automatically
+                   converted to a string, will print the raw
+                   string directly, rather than a human-oriented
+                   representation of the value.
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *OutputCommand) Synopsis() string {
+	return "Show output values from your root module"
+}
diff --git a/v1.5.7/internal/command/output_test.go b/v1.5.7/internal/command/output_test.go
new file mode 100644
index 0000000..7f030dd
--- /dev/null
+++ b/v1.5.7/internal/command/output_test.go
@@ -0,0 +1,325 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestOutput(t *testing.T) {
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetOutputValue(
+			addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance),
+			cty.StringVal("bar"),
+			false,
+		)
+	})
+
+	statePath := testStateFile(t, originalState)
+
+	view, done := testView(t)
+	c := &OutputCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"foo",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: \n%s", output.Stderr())
+	}
+
+	actual := strings.TrimSpace(output.Stdout())
+	if actual != `"bar"` {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestOutput_json(t *testing.T) {
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetOutputValue(
+			addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance),
+			cty.StringVal("bar"),
+			false,
+		)
+	})
+
+	statePath := testStateFile(t, originalState)
+
+	view, done := testView(t)
+	c := &OutputCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-json",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: \n%s", output.Stderr())
+	}
+
+	actual := strings.TrimSpace(output.Stdout())
+	expected := "{\n  \"foo\": {\n    \"sensitive\": false,\n    \"type\": \"string\",\n    \"value\": \"bar\"\n  }\n}"
+	if actual != expected {
+		t.Fatalf("wrong output\ngot:  %#v\nwant: %#v", actual, expected)
+	}
+}
+
+func TestOutput_emptyOutputs(t *testing.T) {
+	originalState := states.NewState()
+	statePath := testStateFile(t, originalState)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &OutputCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-no-color",
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: \n%s", output.Stderr())
+	}
+	// Warning diagnostics should go to stdout
+	if got, want := output.Stdout(), "Warning: No outputs found"; !strings.Contains(got, want) {
+		t.Fatalf("bad output: expected to contain %q, got:\n%s", want, got)
+	}
+}
+
+func TestOutput_badVar(t *testing.T) {
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetOutputValue(
+			addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance),
+			cty.StringVal("bar"),
+			false,
+		)
+	})
+	statePath := testStateFile(t, originalState)
+
+	view, done := testView(t)
+	c := &OutputCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"bar",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 1 {
+		t.Fatalf("bad: \n%s", output.Stderr())
+	}
+}
+
+func TestOutput_blank(t *testing.T) {
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetOutputValue(
+			addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance),
+			cty.StringVal("bar"),
+			false,
+		)
+		s.SetOutputValue(
+			addrs.OutputValue{Name: "name"}.Absolute(addrs.RootModuleInstance),
+			cty.StringVal("john-doe"),
+			false,
+		)
+	})
+	statePath := testStateFile(t, originalState)
+
+	view, done := testView(t)
+	c := &OutputCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"",
+	}
+
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: \n%s", output.Stderr())
+	}
+
+	expectedOutput := "foo = \"bar\"\nname = \"john-doe\"\n"
+	if got := output.Stdout(); got != expectedOutput {
+		t.Fatalf("wrong output\ngot:  %#v\nwant: %#v", got, expectedOutput)
+	}
+}
+
+func TestOutput_manyArgs(t *testing.T) {
+	view, done := testView(t)
+	c := &OutputCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"bad",
+		"bad",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 1 {
+		t.Fatalf("bad: \n%s", output.Stdout())
+	}
+}
+
+func TestOutput_noArgs(t *testing.T) {
+	view, done := testView(t)
+	c := &OutputCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: \n%s", output.Stdout())
+	}
+}
+
+func TestOutput_noState(t *testing.T) {
+	originalState := states.NewState()
+	statePath := testStateFile(t, originalState)
+
+	view, done := testView(t)
+	c := &OutputCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"foo",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: \n%s", output.Stderr())
+	}
+}
+
+func TestOutput_noVars(t *testing.T) {
+	originalState := states.NewState()
+
+	statePath := testStateFile(t, originalState)
+
+	view, done := testView(t)
+	c := &OutputCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"bar",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: \n%s", output.Stderr())
+	}
+}
+
+func TestOutput_stateDefault(t *testing.T) {
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetOutputValue(
+			addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance),
+			cty.StringVal("bar"),
+			false,
+		)
+	})
+
+	// Write the state file in a temporary directory with the
+	// default filename.
+	td := testTempDir(t)
+	statePath := filepath.Join(td, DefaultStateFilename)
+
+	f, err := os.Create(statePath)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	err = writeStateForTesting(originalState, f)
+	f.Close()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Change to that directory
+	cwd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if err := os.Chdir(filepath.Dir(statePath)); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer os.Chdir(cwd)
+
+	view, done := testView(t)
+	c := &OutputCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"foo",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: \n%s", output.Stderr())
+	}
+
+	actual := strings.TrimSpace(output.Stdout())
+	if actual != `"bar"` {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
diff --git a/v1.5.7/internal/command/plan.go b/v1.5.7/internal/command/plan.go
new file mode 100644
index 0000000..e42d020
--- /dev/null
+++ b/v1.5.7/internal/command/plan.go
@@ -0,0 +1,292 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// PlanCommand is a Command implementation that compares a Terraform
+// configuration to an actual infrastructure and shows the differences.
+type PlanCommand struct {
+	Meta
+}
+
+func (c *PlanCommand) Run(rawArgs []string) int {
+	// Parse and apply global view arguments
+	common, rawArgs := arguments.ParseView(rawArgs)
+	c.View.Configure(common)
+
+	// Propagate -no-color for legacy use of Ui.  The remote backend and
+	// cloud package use this; it should be removed when/if they are
+	// migrated to views.
+	c.Meta.color = !common.NoColor
+	c.Meta.Color = c.Meta.color
+
+	// Parse and validate flags
+	args, diags := arguments.ParsePlan(rawArgs)
+
+	// Instantiate the view, even if there are flag errors, so that we render
+	// diagnostics according to the desired view
+	view := views.NewPlan(args.ViewType, c.View)
+
+	if diags.HasErrors() {
+		view.Diagnostics(diags)
+		view.HelpPrompt()
+		return 1
+	}
+
+	// Check for user-supplied plugin path
+	var err error
+	if c.pluginPath, err = c.loadPluginPath(); err != nil {
+		diags = diags.Append(err)
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	// FIXME: the -input flag value is needed to initialize the backend and the
+	// operation, but there is no clear path to pass this value down, so we
+	// continue to mutate the Meta object state for now.
+	c.Meta.input = args.InputEnabled
+
+	// FIXME: the -parallelism flag is used to control the concurrency of
+	// Terraform operations. At the moment, this value is used both to
+	// initialize the backend via the ContextOpts field inside CLIOpts, and to
+	// set a largely unused field on the Operation request. Again, there is no
+	// clear path to pass this value down, so we continue to mutate the Meta
+	// object state for now.
+	c.Meta.parallelism = args.Operation.Parallelism
+
+	diags = diags.Append(c.providerDevOverrideRuntimeWarnings())
+
+	// Prepare the backend with the backend-specific arguments
+	be, beDiags := c.PrepareBackend(args.State, args.ViewType)
+	diags = diags.Append(beDiags)
+	if diags.HasErrors() {
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	// Build the operation request
+	opReq, opDiags := c.OperationRequest(be, view, args.ViewType, args.Operation, args.OutPath, args.GenerateConfigPath)
+	diags = diags.Append(opDiags)
+	if diags.HasErrors() {
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	// Collect variable value and add them to the operation request
+	diags = diags.Append(c.GatherVariables(opReq, args.Vars))
+	if diags.HasErrors() {
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	// Before we delegate to the backend, we'll print any warning diagnostics
+	// we've accumulated here, since the backend will start fresh with its own
+	// diagnostics.
+	view.Diagnostics(diags)
+	diags = nil
+
+	// Perform the operation
+	op, err := c.RunOperation(be, opReq)
+	if err != nil {
+		diags = diags.Append(err)
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	if op.Result != backend.OperationSuccess {
+		return op.Result.ExitStatus()
+	}
+	if args.DetailedExitCode && !op.PlanEmpty {
+		return 2
+	}
+
+	return op.Result.ExitStatus()
+}
+
+func (c *PlanCommand) PrepareBackend(args *arguments.State, viewType arguments.ViewType) (backend.Enhanced, tfdiags.Diagnostics) {
+	// FIXME: we need to apply the state arguments to the meta object here
+	// because they are later used when initializing the backend. Carving a
+	// path to pass these arguments to the functions that need them is
+	// difficult but would make their use easier to understand.
+	c.Meta.applyStateArguments(args)
+
+	backendConfig, diags := c.loadBackendConfig(".")
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	// Load the backend
+	be, beDiags := c.Backend(&BackendOpts{
+		Config:   backendConfig,
+		ViewType: viewType,
+	})
+	diags = diags.Append(beDiags)
+	if beDiags.HasErrors() {
+		return nil, diags
+	}
+
+	return be, diags
+}
+
+func (c *PlanCommand) OperationRequest(
+	be backend.Enhanced,
+	view views.Plan,
+	viewType arguments.ViewType,
+	args *arguments.Operation,
+	planOutPath string,
+	generateConfigOut string,
+) (*backend.Operation, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// Build the operation
+	opReq := c.Operation(be, viewType)
+	opReq.ConfigDir = "."
+	opReq.PlanMode = args.PlanMode
+	opReq.Hooks = view.Hooks()
+	opReq.PlanRefresh = args.Refresh
+	opReq.PlanOutPath = planOutPath
+	opReq.GenerateConfigOut = generateConfigOut
+	opReq.Targets = args.Targets
+	opReq.ForceReplace = args.ForceReplace
+	opReq.Type = backend.OperationTypePlan
+	opReq.View = view.Operation()
+
+	var err error
+	opReq.ConfigLoader, err = c.initConfigLoader()
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Failed to initialize config loader: %s", err))
+		return nil, diags
+	}
+
+	return opReq, diags
+}
+
+func (c *PlanCommand) GatherVariables(opReq *backend.Operation, args *arguments.Vars) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	// FIXME the arguments package currently trivially gathers variable related
+	// arguments in a heterogenous slice, in order to minimize the number of
+	// code paths gathering variables during the transition to this structure.
+	// Once all commands that gather variables have been converted to this
+	// structure, we could move the variable gathering code to the arguments
+	// package directly, removing this shim layer.
+
+	varArgs := args.All()
+	items := make([]rawFlag, len(varArgs))
+	for i := range varArgs {
+		items[i].Name = varArgs[i].Name
+		items[i].Value = varArgs[i].Value
+	}
+	c.Meta.variableArgs = rawFlags{items: &items}
+	opReq.Variables, diags = c.collectVariableValues()
+
+	return diags
+}
+
+func (c *PlanCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] plan [options]
+
+  Generates a speculative execution plan, showing what actions Terraform
+  would take to apply the current configuration. This command will not
+  actually perform the planned actions.
+
+  You can optionally save the plan to a file, which you can then pass to
+  the "apply" command to perform exactly the actions described in the plan.
+
+Plan Customization Options:
+
+  The following options customize how Terraform will produce its plan. You
+  can also use these options when you run "terraform apply" without passing
+  it a saved plan, in order to plan and apply in a single command.
+
+  -destroy            Select the "destroy" planning mode, which creates a plan
+                      to destroy all objects currently managed by this
+                      Terraform configuration instead of the usual behavior.
+
+  -refresh-only       Select the "refresh only" planning mode, which checks
+                      whether remote objects still match the outcome of the
+                      most recent Terraform apply but does not propose any
+                      actions to undo any changes made outside of Terraform.
+
+  -refresh=false      Skip checking for external changes to remote objects
+                      while creating the plan. This can potentially make
+                      planning faster, but at the expense of possibly planning
+                      against a stale record of the remote system state.
+
+  -replace=resource   Force replacement of a particular resource instance using
+                      its resource address. If the plan would've normally
+                      produced an update or no-op action for this instance,
+                      Terraform will plan to replace it instead. You can use
+                      this option multiple times to replace more than one object.
+
+  -target=resource    Limit the planning operation to only the given module,
+                      resource, or resource instance and all of its
+                      dependencies. You can use this option multiple times to
+                      include more than one object. This is for exceptional
+                      use only.
+
+  -var 'foo=bar'      Set a value for one of the input variables in the root
+                      module of the configuration. Use this option more than
+                      once to set more than one variable.
+
+  -var-file=filename  Load variable values from the given file, in addition
+                      to the default files terraform.tfvars and *.auto.tfvars.
+                      Use this option more than once to include more than one
+                      variables file.
+
+Other Options:
+
+  -compact-warnings          If Terraform produces any warnings that are not
+                             accompanied by errors, shows them in a more compact
+                             form that includes only the summary messages.
+
+  -detailed-exitcode         Return detailed exit codes when the command exits.
+                             This will change the meaning of exit codes to:
+                             0 - Succeeded, diff is empty (no changes)
+                             1 - Errored
+                             2 - Succeeded, there is a diff
+
+  -generate-config-out=path  (Experimental) If import blocks are present in
+                             configuration, instructs Terraform to generate HCL
+                             for any imported resources not already present. The
+                             configuration is written to a new file at PATH,
+                             which must not already exist. Terraform may still
+                             attempt to write configuration if the plan errors.
+
+  -input=true                Ask for input for variables if not directly set.
+
+  -lock=false                Don't hold a state lock during the operation. This
+                             is dangerous if others might concurrently run
+                             commands against the same workspace.
+
+  -lock-timeout=0s           Duration to retry a state lock.
+
+  -no-color                  If specified, output won't contain any color.
+
+  -out=path                  Write a plan file to the given path. This can be
+                             used as input to the "apply" command.
+
+  -parallelism=n             Limit the number of concurrent operations. Defaults
+                             to 10.
+
+  -state=statefile           A legacy option used for the local backend only.
+                             See the local backend's documentation for more
+                             information.
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *PlanCommand) Synopsis() string {
+	return "Show changes required by the current configuration"
+}
diff --git a/v1.5.7/internal/command/plan_test.go b/v1.5.7/internal/command/plan_test.go
new file mode 100644
index 0000000..7d83070
--- /dev/null
+++ b/v1.5.7/internal/command/plan_test.go
@@ -0,0 +1,1666 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path"
+	"path/filepath"
+	"strings"
+	"sync"
+	"testing"
+	"time"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	backendinit "github.com/hashicorp/terraform/internal/backend/init"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestPlan(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan"), td)
+	defer testChdir(t, td)()
+
+	p := planFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+}
+
+func TestPlan_lockedState(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan"), td)
+	defer testChdir(t, td)()
+
+	unlock, err := testLockState(t, testDataDir, filepath.Join(td, DefaultStateFilename))
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer unlock()
+
+	p := planFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{}
+	code := c.Run(args)
+	if code == 0 {
+		t.Fatal("expected error", done(t).Stdout())
+	}
+
+	output := done(t).Stderr()
+	if !strings.Contains(output, "lock") {
+		t.Fatal("command output does not look like a lock error:", output)
+	}
+}
+
+func TestPlan_plan(t *testing.T) {
+	testCwd(t)
+
+	planPath := testPlanFileNoop(t)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{planPath}
+	code := c.Run(args)
+	output := done(t)
+	if code != 1 {
+		t.Fatalf("wrong exit status %d; want 1\nstderr: %s", code, output.Stderr())
+	}
+}
+
+func TestPlan_destroy(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan"), td)
+	defer testChdir(t, td)()
+
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	outPath := testTempFile(t)
+	statePath := testStateFile(t, originalState)
+
+	p := planFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-destroy",
+		"-out", outPath,
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	plan := testReadPlan(t, outPath)
+	for _, rc := range plan.Changes.Resources {
+		if got, want := rc.Action, plans.Delete; got != want {
+			t.Fatalf("wrong action %s for %s; want %s\nplanned change: %s", got, rc.Addr, want, spew.Sdump(rc))
+		}
+	}
+}
+
+func TestPlan_noState(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan"), td)
+	defer testChdir(t, td)()
+
+	p := planFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// Verify that refresh was called
+	if p.ReadResourceCalled {
+		t.Fatal("ReadResource should not be called")
+	}
+
+	// Verify that the provider was called with the existing state
+	actual := p.PlanResourceChangeRequest.PriorState
+	expected := cty.NullVal(p.GetProviderSchemaResponse.ResourceTypes["test_instance"].Block.ImpliedType())
+	if !expected.RawEquals(actual) {
+		t.Fatalf("wrong prior state\ngot:  %#v\nwant: %#v", actual, expected)
+	}
+}
+
+func TestPlan_generatedConfigPath(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan-import-config-gen"), td)
+	defer testChdir(t, td)()
+
+	genPath := filepath.Join(td, "generated.tf")
+
+	p := planFixtureProvider()
+	view, done := testView(t)
+
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("bar"),
+				}),
+				Private: nil,
+			},
+		},
+	}
+
+	args := []string{
+		"-generate-config-out", genPath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	testFileEquals(t, genPath, filepath.Join(td, "generated.tf.expected"))
+}
+
+func TestPlan_outPath(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan"), td)
+	defer testChdir(t, td)()
+
+	outPath := filepath.Join(td, "test.plan")
+
+	p := planFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	p.PlanResourceChangeResponse = &providers.PlanResourceChangeResponse{
+		PlannedState: cty.NullVal(cty.EmptyObject),
+	}
+
+	args := []string{
+		"-out", outPath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	testReadPlan(t, outPath) // will call t.Fatal itself if the file cannot be read
+}
+
+func TestPlan_outPathNoChange(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan"), td)
+	defer testChdir(t, td)()
+
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				// Aside from "id" (which is computed) the values here must
+				// exactly match the values in the "plan" test fixture in order
+				// to produce the empty plan we need for this test.
+				AttrsJSON: []byte(`{"id":"bar","ami":"bar","network_interface":[{"description":"Main network interface","device_index":"0"}]}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, originalState)
+
+	outPath := filepath.Join(td, "test.plan")
+
+	p := planFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-out", outPath,
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	plan := testReadPlan(t, outPath)
+	if !plan.Changes.Empty() {
+		t.Fatalf("Expected empty plan to be written to plan file, got: %s", spew.Sdump(plan))
+	}
+}
+
+func TestPlan_outPathWithError(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan-fail-condition"), td)
+	defer testChdir(t, td)()
+
+	outPath := filepath.Join(td, "test.plan")
+
+	p := planFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	p.PlanResourceChangeResponse = &providers.PlanResourceChangeResponse{
+		PlannedState: cty.NullVal(cty.EmptyObject),
+	}
+
+	args := []string{
+		"-out", outPath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code == 0 {
+		t.Fatal("expected non-zero exit status", output)
+	}
+
+	plan := testReadPlan(t, outPath) // will call t.Fatal itself if the file cannot be read
+	if !plan.Errored {
+		t.Fatal("plan should be marked with Errored")
+	}
+
+	if plan.Checks == nil {
+		t.Fatal("plan contains no checks")
+	}
+
+	// the checks should only contain one failure
+	results := plan.Checks.ConfigResults.Elements()
+	if len(results) != 1 {
+		t.Fatal("incorrect number of check results", len(results))
+	}
+	if results[0].Value.Status != checks.StatusFail {
+		t.Errorf("incorrect status, got %s", results[0].Value.Status)
+	}
+}
+
+// When using "-out" with a backend, the plan should encode the backend config
+func TestPlan_outBackend(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan-out-backend"), td)
+	defer testChdir(t, td)()
+
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","ami":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	// Set up our backend state
+	dataState, srv := testBackendState(t, originalState, 200)
+	defer srv.Close()
+	testStateFileRemote(t, dataState)
+
+	outPath := "foo"
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {
+							Type:     cty.String,
+							Computed: true,
+						},
+						"ami": {
+							Type:     cty.String,
+							Optional: true,
+						},
+					},
+				},
+			},
+		},
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-out", outPath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Logf("stdout: %s", output.Stdout())
+		t.Fatalf("plan command failed with exit code %d\n\n%s", code, output.Stderr())
+	}
+
+	plan := testReadPlan(t, outPath)
+	if !plan.Changes.Empty() {
+		t.Fatalf("Expected empty plan to be written to plan file, got: %s", spew.Sdump(plan))
+	}
+
+	if got, want := plan.Backend.Type, "http"; got != want {
+		t.Errorf("wrong backend type %q; want %q", got, want)
+	}
+	if got, want := plan.Backend.Workspace, "default"; got != want {
+		t.Errorf("wrong backend workspace %q; want %q", got, want)
+	}
+	{
+		httpBackend := backendinit.Backend("http")()
+		schema := httpBackend.ConfigSchema()
+		got, err := plan.Backend.Config.Decode(schema.ImpliedType())
+		if err != nil {
+			t.Fatalf("failed to decode backend config in plan: %s", err)
+		}
+		want, err := dataState.Backend.Config(schema)
+		if err != nil {
+			t.Fatalf("failed to decode cached config: %s", err)
+		}
+		if !want.RawEquals(got) {
+			t.Errorf("wrong backend config\ngot:  %#v\nwant: %#v", got, want)
+		}
+	}
+}
+
+func TestPlan_refreshFalse(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan"), td)
+	defer testChdir(t, td)()
+
+	p := planFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-refresh=false",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if p.ReadResourceCalled {
+		t.Fatal("ReadResource should not have been called")
+	}
+}
+
+func TestPlan_state(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan"), td)
+	defer testChdir(t, td)()
+
+	originalState := testState()
+	statePath := testStateFile(t, originalState)
+
+	p := planFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// Verify that the provider was called with the existing state
+	actual := p.PlanResourceChangeRequest.PriorState
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"id":  cty.StringVal("bar"),
+		"ami": cty.NullVal(cty.String),
+		"network_interface": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+			"device_index": cty.String,
+			"description":  cty.String,
+		})),
+	})
+	if !expected.RawEquals(actual) {
+		t.Fatalf("wrong prior state\ngot:  %#v\nwant: %#v", actual, expected)
+	}
+}
+
+func TestPlan_stateDefault(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan"), td)
+	defer testChdir(t, td)()
+
+	// Generate state and move it to the default path
+	originalState := testState()
+	statePath := testStateFile(t, originalState)
+	os.Rename(statePath, path.Join(td, "terraform.tfstate"))
+
+	p := planFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// Verify that the provider was called with the existing state
+	actual := p.PlanResourceChangeRequest.PriorState
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"id":  cty.StringVal("bar"),
+		"ami": cty.NullVal(cty.String),
+		"network_interface": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+			"device_index": cty.String,
+			"description":  cty.String,
+		})),
+	})
+	if !expected.RawEquals(actual) {
+		t.Fatalf("wrong prior state\ngot:  %#v\nwant: %#v", actual, expected)
+	}
+}
+
+func TestPlan_validate(t *testing.T) {
+	// This is triggered by not asking for input so we have to set this to false
+	test = false
+	defer func() { test = true }()
+
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan-invalid"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Optional: true, Computed: true},
+					},
+				},
+			},
+		},
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{"-no-color"}
+	code := c.Run(args)
+	output := done(t)
+	if code != 1 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	actual := output.Stderr()
+	if want := "Error: Invalid count argument"; !strings.Contains(actual, want) {
+		t.Fatalf("unexpected error output\ngot:\n%s\n\nshould contain: %s", actual, want)
+	}
+	if want := "9:   count = timestamp()"; !strings.Contains(actual, want) {
+		t.Fatalf("unexpected error output\ngot:\n%s\n\nshould contain: %s", actual, want)
+	}
+}
+
+func TestPlan_vars(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan-vars"), td)
+	defer testChdir(t, td)()
+
+	p := planVarsFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	actual := ""
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		actual = req.ProposedNewState.GetAttr("value").AsString()
+		resp.PlannedState = req.ProposedNewState
+		return
+	}
+
+	args := []string{
+		"-var", "foo=bar",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if actual != "bar" {
+		t.Fatal("didn't work")
+	}
+}
+
+func TestPlan_varsInvalid(t *testing.T) {
+	testCases := []struct {
+		args    []string
+		wantErr string
+	}{
+		{
+			[]string{"-var", "foo"},
+			`The given -var option "foo" is not correctly specified.`,
+		},
+		{
+			[]string{"-var", "foo = bar"},
+			`Variable name "foo " is invalid due to trailing space.`,
+		},
+	}
+
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan-vars"), td)
+	defer testChdir(t, td)()
+
+	for _, tc := range testCases {
+		t.Run(strings.Join(tc.args, " "), func(t *testing.T) {
+			p := planVarsFixtureProvider()
+			view, done := testView(t)
+			c := &PlanCommand{
+				Meta: Meta{
+					testingOverrides: metaOverridesForProvider(p),
+					View:             view,
+				},
+			}
+
+			code := c.Run(tc.args)
+			output := done(t)
+			if code != 1 {
+				t.Fatalf("bad: %d\n\n%s", code, output.Stdout())
+			}
+
+			got := output.Stderr()
+			if !strings.Contains(got, tc.wantErr) {
+				t.Fatalf("bad error output, want %q, got:\n%s", tc.wantErr, got)
+			}
+		})
+	}
+}
+
+func TestPlan_varsUnset(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan-vars"), td)
+	defer testChdir(t, td)()
+
+	// The plan command will prompt for interactive input of var.foo.
+	// We'll answer "bar" to that prompt, which should then allow this
+	// configuration to apply even though var.foo doesn't have a
+	// default value and there are no -var arguments on our command line.
+
+	// This will (helpfully) panic if more than one variable is requested during plan:
+	// https://github.com/hashicorp/terraform/issues/26027
+	close := testInteractiveInput(t, []string{"bar"})
+	defer close()
+
+	p := planVarsFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+}
+
+// This test adds a required argument to the test provider to validate
+// processing of user input:
+// https://github.com/hashicorp/terraform/issues/26035
+func TestPlan_providerArgumentUnset(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan"), td)
+	defer testChdir(t, td)()
+
+	// Disable test mode so input would be asked
+	test = false
+	defer func() { test = true }()
+
+	// The plan command will prompt for interactive input of provider.test.region
+	defaultInputReader = bytes.NewBufferString("us-east-1\n")
+
+	p := planFixtureProvider()
+	// override the planFixtureProvider schema to include a required provider argument
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"region": {Type: cty.String, Required: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":  {Type: cty.String, Optional: true, Computed: true},
+						"ami": {Type: cty.String, Optional: true, Computed: true},
+					},
+					BlockTypes: map[string]*configschema.NestedBlock{
+						"network_interface": {
+							Nesting: configschema.NestingList,
+							Block: configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"device_index": {Type: cty.String, Optional: true},
+									"description":  {Type: cty.String, Optional: true},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		DataSources: map[string]providers.Schema{
+			"test_data_source": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {
+							Type:     cty.String,
+							Required: true,
+						},
+						"valid": {
+							Type:     cty.Bool,
+							Computed: true,
+						},
+					},
+				},
+			},
+		},
+	}
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+}
+
+// Test that terraform properly merges provider configuration that's split
+// between config files and interactive input variables.
+// https://github.com/hashicorp/terraform/issues/28956
+func TestPlan_providerConfigMerge(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan-provider-input"), td)
+	defer testChdir(t, td)()
+
+	// Disable test mode so input would be asked
+	test = false
+	defer func() { test = true }()
+
+	// The plan command will prompt for interactive input of provider.test.region
+	defaultInputReader = bytes.NewBufferString("us-east-1\n")
+
+	p := planFixtureProvider()
+	// override the planFixtureProvider schema to include a required provider argument and a nested block
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"region": {Type: cty.String, Required: true},
+					"url":    {Type: cty.String, Required: true},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"auth": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"user":     {Type: cty.String, Required: true},
+								"password": {Type: cty.String, Required: true},
+							},
+						},
+					},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Optional: true, Computed: true},
+					},
+				},
+			},
+		},
+	}
+
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if !p.ConfigureProviderCalled {
+		t.Fatal("configure provider not called")
+	}
+
+	// For this test, we want to confirm that we've sent the expected config
+	// value *to* the provider.
+	got := p.ConfigureProviderRequest.Config
+	want := cty.ObjectVal(map[string]cty.Value{
+		"auth": cty.ListVal([]cty.Value{
+			cty.ObjectVal(map[string]cty.Value{
+				"user":     cty.StringVal("one"),
+				"password": cty.StringVal("onepw"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"user":     cty.StringVal("two"),
+				"password": cty.StringVal("twopw"),
+			}),
+		}),
+		"region": cty.StringVal("us-east-1"),
+		"url":    cty.StringVal("example.com"),
+	})
+
+	if !got.RawEquals(want) {
+		t.Fatal("wrong provider config")
+	}
+
+}
+
+func TestPlan_varFile(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan-vars"), td)
+	defer testChdir(t, td)()
+
+	varFilePath := testTempFile(t)
+	if err := ioutil.WriteFile(varFilePath, []byte(planVarFile), 0644); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	p := planVarsFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	actual := ""
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		actual = req.ProposedNewState.GetAttr("value").AsString()
+		resp.PlannedState = req.ProposedNewState
+		return
+	}
+
+	args := []string{
+		"-var-file", varFilePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if actual != "bar" {
+		t.Fatal("didn't work")
+	}
+}
+
+func TestPlan_varFileDefault(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan-vars"), td)
+	defer testChdir(t, td)()
+
+	varFilePath := filepath.Join(td, "terraform.tfvars")
+	if err := ioutil.WriteFile(varFilePath, []byte(planVarFile), 0644); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	p := planVarsFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	actual := ""
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		actual = req.ProposedNewState.GetAttr("value").AsString()
+		resp.PlannedState = req.ProposedNewState
+		return
+	}
+
+	args := []string{}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if actual != "bar" {
+		t.Fatal("didn't work")
+	}
+}
+
+func TestPlan_varFileWithDecls(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan-vars"), td)
+	defer testChdir(t, td)()
+
+	varFilePath := testTempFile(t)
+	if err := ioutil.WriteFile(varFilePath, []byte(planVarFileWithDecl), 0644); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	p := planVarsFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-var-file", varFilePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code == 0 {
+		t.Fatalf("succeeded; want failure\n\n%s", output.Stdout())
+	}
+
+	msg := output.Stderr()
+	if got, want := msg, "Variable declaration in .tfvars file"; !strings.Contains(got, want) {
+		t.Fatalf("missing expected error message\nwant message containing %q\ngot:\n%s", want, got)
+	}
+}
+
+func TestPlan_detailedExitcode(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan"), td)
+	defer testChdir(t, td)()
+
+	t.Run("return 1", func(t *testing.T) {
+		view, done := testView(t)
+		c := &PlanCommand{
+			Meta: Meta{
+				// Running plan without setting testingOverrides is similar to plan without init
+				View: view,
+			},
+		}
+		code := c.Run([]string{"-detailed-exitcode"})
+		output := done(t)
+		if code != 1 {
+			t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+		}
+	})
+
+	t.Run("return 2", func(t *testing.T) {
+		p := planFixtureProvider()
+		view, done := testView(t)
+		c := &PlanCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				View:             view,
+			},
+		}
+
+		code := c.Run([]string{"-detailed-exitcode"})
+		output := done(t)
+		if code != 2 {
+			t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+		}
+	})
+}
+
+func TestPlan_detailedExitcode_emptyDiff(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan-emptydiff"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{"-detailed-exitcode"}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+}
+
+func TestPlan_shutdown(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-shutdown"), td)
+	defer testChdir(t, td)()
+
+	cancelled := make(chan struct{})
+	shutdownCh := make(chan struct{})
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+			ShutdownCh:       shutdownCh,
+		},
+	}
+
+	p.StopFn = func() error {
+		close(cancelled)
+		return nil
+	}
+
+	var once sync.Once
+
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		once.Do(func() {
+			shutdownCh <- struct{}{}
+		})
+
+		// Because of the internal lock in the MockProvider, we can't
+		// coordinate directly with the calling of Stop, and making the
+		// MockProvider concurrent is disruptive to a lot of existing tests.
+		// Wait here a moment to help make sure the main goroutine gets to the
+		// Stop call before we exit, or the plan may finish before it can be
+		// canceled.
+		time.Sleep(200 * time.Millisecond)
+
+		s := req.ProposedNewState.AsValueMap()
+		s["ami"] = cty.StringVal("bar")
+		resp.PlannedState = cty.ObjectVal(s)
+		return
+	}
+
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"ami": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	code := c.Run([]string{})
+	output := done(t)
+	if code != 1 {
+		t.Errorf("wrong exit code %d; want 1\noutput:\n%s", code, output.Stdout())
+	}
+
+	select {
+	case <-cancelled:
+	default:
+		t.Error("command not cancelled")
+	}
+}
+
+func TestPlan_init_required(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan"), td)
+	defer testChdir(t, td)()
+
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			// Running plan without setting testingOverrides is similar to plan without init
+			View: view,
+		},
+	}
+
+	args := []string{"-no-color"}
+	code := c.Run(args)
+	output := done(t)
+	if code != 1 {
+		t.Fatalf("expected error, got success")
+	}
+	got := output.Stderr()
+	if !(strings.Contains(got, "terraform init") && strings.Contains(got, "provider registry.terraform.io/hashicorp/test: required by this configuration but no version is selected")) {
+		t.Fatal("wrong error message in output:", got)
+	}
+}
+
+// Config with multiple resources, targeting plan of a subset
+func TestPlan_targeted(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply-targeted"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Computed: true},
+					},
+				},
+			},
+		},
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-target", "test_instance.foo",
+		"-target", "test_instance.baz",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if got, want := output.Stdout(), "3 to add, 0 to change, 0 to destroy"; !strings.Contains(got, want) {
+		t.Fatalf("bad change summary, want %q, got:\n%s", want, got)
+	}
+}
+
+// Diagnostics for invalid -target flags
+func TestPlan_targetFlagsDiags(t *testing.T) {
+	testCases := map[string]string{
+		"test_instance.": "Dot must be followed by attribute name.",
+		"test_instance":  "Resource specification must include a resource type and name.",
+	}
+
+	for target, wantDiag := range testCases {
+		t.Run(target, func(t *testing.T) {
+			td := testTempDir(t)
+			defer os.RemoveAll(td)
+			defer testChdir(t, td)()
+
+			view, done := testView(t)
+			c := &PlanCommand{
+				Meta: Meta{
+					View: view,
+				},
+			}
+
+			args := []string{
+				"-target", target,
+			}
+			code := c.Run(args)
+			output := done(t)
+			if code != 1 {
+				t.Fatalf("bad: %d\n\n%s", code, output.Stdout())
+			}
+
+			got := output.Stderr()
+			if !strings.Contains(got, target) {
+				t.Fatalf("bad error output, want %q, got:\n%s", target, got)
+			}
+			if !strings.Contains(got, wantDiag) {
+				t.Fatalf("bad error output, want %q, got:\n%s", wantDiag, got)
+			}
+		})
+	}
+}
+
+func TestPlan_replace(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan-replace"), td)
+	defer testChdir(t, td)()
+
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "a",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"hello"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, originalState)
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Computed: true},
+					},
+				},
+			},
+		},
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-no-color",
+		"-replace", "test_instance.a",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("wrong exit code %d\n\n%s", code, output.Stderr())
+	}
+
+	stdout := output.Stdout()
+	if got, want := stdout, "1 to add, 0 to change, 1 to destroy"; !strings.Contains(got, want) {
+		t.Errorf("wrong plan summary\ngot output:\n%s\n\nwant substring: %s", got, want)
+	}
+	if got, want := stdout, "test_instance.a will be replaced, as requested"; !strings.Contains(got, want) {
+		t.Errorf("missing replace explanation\ngot output:\n%s\n\nwant substring: %s", got, want)
+	}
+}
+
+// Verify that the parallelism flag allows no more than the desired number of
+// concurrent calls to PlanResourceChange.
+func TestPlan_parallelism(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("parallelism"), td)
+	defer testChdir(t, td)()
+
+	par := 4
+
+	// started is a semaphore that we use to ensure that we never have more
+	// than "par" plan operations happening concurrently
+	started := make(chan struct{}, par)
+
+	// beginCtx is used as a starting gate to hold back PlanResourceChange
+	// calls until we reach the desired concurrency. The cancel func "begin" is
+	// called once we reach the desired concurrency, allowing all apply calls
+	// to proceed in unison.
+	beginCtx, begin := context.WithCancel(context.Background())
+
+	// Since our mock provider has its own mutex preventing concurrent calls
+	// to ApplyResourceChange, we need to use a number of separate providers
+	// here. They will all have the same mock implementation function assigned
+	// but crucially they will each have their own mutex.
+	providerFactories := map[addrs.Provider]providers.Factory{}
+	for i := 0; i < 10; i++ {
+		name := fmt.Sprintf("test%d", i)
+		provider := &terraform.MockProvider{}
+		provider.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+			ResourceTypes: map[string]providers.Schema{
+				name + "_instance": {Block: &configschema.Block{}},
+			},
+		}
+		provider.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+			// If we ever have more than our intended parallelism number of
+			// plan operations running concurrently, the semaphore will fail.
+			select {
+			case started <- struct{}{}:
+				defer func() {
+					<-started
+				}()
+			default:
+				t.Fatal("too many concurrent apply operations")
+			}
+
+			// If we never reach our intended parallelism, the context will
+			// never be canceled and the test will time out.
+			if len(started) >= par {
+				begin()
+			}
+			<-beginCtx.Done()
+
+			// do some "work"
+			// Not required for correctness, but makes it easier to spot a
+			// failure when there is more overlap.
+			time.Sleep(10 * time.Millisecond)
+			return providers.PlanResourceChangeResponse{
+				PlannedState: req.ProposedNewState,
+			}
+		}
+		providerFactories[addrs.NewDefaultProvider(name)] = providers.FactoryFixed(provider)
+	}
+	testingOverrides := &testingOverrides{
+		Providers: providerFactories,
+	}
+
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: testingOverrides,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		fmt.Sprintf("-parallelism=%d", par),
+	}
+
+	res := c.Run(args)
+	output := done(t)
+	if res != 0 {
+		t.Fatal(output.Stdout())
+	}
+}
+
+func TestPlan_warnings(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan"), td)
+	defer testChdir(t, td)()
+
+	t.Run("full warnings", func(t *testing.T) {
+		p := planWarningsFixtureProvider()
+		view, done := testView(t)
+		c := &PlanCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				View:             view,
+			},
+		}
+		code := c.Run([]string{})
+		output := done(t)
+		if code != 0 {
+			t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+		}
+		// the output should contain 3 warnings (returned by planWarningsFixtureProvider())
+		wantWarnings := []string{
+			"warning 1",
+			"warning 2",
+			"warning 3",
+		}
+		for _, want := range wantWarnings {
+			if !strings.Contains(output.Stdout(), want) {
+				t.Errorf("missing warning %s", want)
+			}
+		}
+	})
+
+	t.Run("compact warnings", func(t *testing.T) {
+		p := planWarningsFixtureProvider()
+		view, done := testView(t)
+		c := &PlanCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				View:             view,
+			},
+		}
+		code := c.Run([]string{"-compact-warnings"})
+		output := done(t)
+		if code != 0 {
+			t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+		}
+		// the output should contain 3 warnings (returned by planWarningsFixtureProvider())
+		// and the message that plan was run with -compact-warnings
+		wantWarnings := []string{
+			"warning 1",
+			"warning 2",
+			"warning 3",
+			"To see the full warning notes, run Terraform without -compact-warnings.",
+		}
+		for _, want := range wantWarnings {
+			if !strings.Contains(output.Stdout(), want) {
+				t.Errorf("missing warning %s", want)
+			}
+		}
+	})
+}
+
+func TestPlan_jsonGoldenReference(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("plan"), td)
+	defer testChdir(t, td)()
+
+	p := planFixtureProvider()
+	view, done := testView(t)
+	c := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-json",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	checkGoldenReference(t, output, "plan")
+}
+
+// planFixtureSchema returns a schema suitable for processing the
+// configuration in testdata/plan . This schema should be
+// assigned to a mock provider named "test".
+func planFixtureSchema() *providers.GetProviderSchemaResponse {
+	return &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":  {Type: cty.String, Optional: true, Computed: true},
+						"ami": {Type: cty.String, Optional: true},
+					},
+					BlockTypes: map[string]*configschema.NestedBlock{
+						"network_interface": {
+							Nesting: configschema.NestingList,
+							Block: configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"device_index": {Type: cty.String, Optional: true},
+									"description":  {Type: cty.String, Optional: true},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		DataSources: map[string]providers.Schema{
+			"test_data_source": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {
+							Type:     cty.String,
+							Required: true,
+						},
+						"valid": {
+							Type:     cty.Bool,
+							Computed: true,
+						},
+					},
+				},
+			},
+		},
+	}
+}
+
+// planFixtureProvider returns a mock provider that is configured for basic
+// operation with the configuration in testdata/plan. This mock has
+// GetSchemaResponse and PlanResourceChangeFn populated, with the plan
+// step just passing through the new object proposed by Terraform Core.
+func planFixtureProvider() *terraform.MockProvider {
+	p := testProvider()
+	p.GetProviderSchemaResponse = planFixtureSchema()
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		return providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.StringVal("zzzzz"),
+				"valid": cty.BoolVal(true),
+			}),
+		}
+	}
+	return p
+}
+
+// planVarsFixtureSchema returns a schema suitable for processing the
+// configuration in testdata/plan-vars . This schema should be
+// assigned to a mock provider named "test".
+func planVarsFixtureSchema() *providers.GetProviderSchemaResponse {
+	return &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":    {Type: cty.String, Optional: true, Computed: true},
+						"value": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+}
+
+// planVarsFixtureProvider returns a mock provider that is configured for basic
+// operation with the configuration in testdata/plan-vars. This mock has
+// GetSchemaResponse and PlanResourceChangeFn populated, with the plan
+// step just passing through the new object proposed by Terraform Core.
+func planVarsFixtureProvider() *terraform.MockProvider {
+	p := testProvider()
+	p.GetProviderSchemaResponse = planVarsFixtureSchema()
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		return providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.StringVal("zzzzz"),
+				"valid": cty.BoolVal(true),
+			}),
+		}
+	}
+	return p
+}
+
+// planFixtureProvider returns a mock provider that is configured for basic
+// operation with the configuration in testdata/plan. This mock has
+// GetSchemaResponse and PlanResourceChangeFn populated, returning 3 warnings.
+func planWarningsFixtureProvider() *terraform.MockProvider {
+	p := testProvider()
+	p.GetProviderSchemaResponse = planFixtureSchema()
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			Diagnostics: tfdiags.Diagnostics{
+				tfdiags.SimpleWarning("warning 1"),
+				tfdiags.SimpleWarning("warning 2"),
+				tfdiags.SimpleWarning("warning 3"),
+			},
+			PlannedState: req.ProposedNewState,
+		}
+	}
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		return providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.StringVal("zzzzz"),
+				"valid": cty.BoolVal(true),
+			}),
+		}
+	}
+	return p
+}
+
+const planVarFile = `
+foo = "bar"
+`
+
+const planVarFileWithDecl = `
+foo = "bar"
+
+variable "nope" {
+}
+`
diff --git a/v1.5.7/internal/command/plugins.go b/v1.5.7/internal/command/plugins.go
new file mode 100644
index 0000000..5f2612a
--- /dev/null
+++ b/v1.5.7/internal/command/plugins.go
@@ -0,0 +1,174 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"log"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+
+	plugin "github.com/hashicorp/go-plugin"
+	"github.com/kardianos/osext"
+
+	fileprovisioner "github.com/hashicorp/terraform/internal/builtin/provisioners/file"
+	localexec "github.com/hashicorp/terraform/internal/builtin/provisioners/local-exec"
+	remoteexec "github.com/hashicorp/terraform/internal/builtin/provisioners/remote-exec"
+	"github.com/hashicorp/terraform/internal/logging"
+	tfplugin "github.com/hashicorp/terraform/internal/plugin"
+	"github.com/hashicorp/terraform/internal/plugin/discovery"
+	"github.com/hashicorp/terraform/internal/provisioners"
+)
+
+// NOTE WELL: The logic in this file is primarily about plugin types OTHER THAN
+// providers, which use an older set of approaches implemented here.
+//
+// The provider-related functions live primarily in meta_providers.go, and
+// lean on some different underlying mechanisms in order to support automatic
+// installation and a hierarchical addressing namespace, neither of which
+// are supported for other plugin types.
+
+// store the user-supplied path for plugin discovery
+func (m *Meta) storePluginPath(pluginPath []string) error {
+	if len(pluginPath) == 0 {
+		return nil
+	}
+
+	m.fixupMissingWorkingDir()
+
+	// remove the plugin dir record if the path was set to an empty string
+	if len(pluginPath) == 1 && (pluginPath[0] == "") {
+		return m.WorkingDir.SetForcedPluginDirs(nil)
+	}
+
+	return m.WorkingDir.SetForcedPluginDirs(pluginPath)
+}
+
+// Load the user-defined plugin search path into Meta.pluginPath if the file
+// exists.
+func (m *Meta) loadPluginPath() ([]string, error) {
+	m.fixupMissingWorkingDir()
+	return m.WorkingDir.ForcedPluginDirs()
+}
+
+// the default location for automatically installed plugins
+func (m *Meta) pluginDir() string {
+	return filepath.Join(m.DataDir(), "plugins", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
+}
+
+// pluginDirs return a list of directories to search for plugins.
+//
+// Earlier entries in this slice get priority over later when multiple copies
+// of the same plugin version are found, but newer versions always override
+// older versions where both satisfy the provider version constraints.
+func (m *Meta) pluginDirs(includeAutoInstalled bool) []string {
+	// user defined paths take precedence
+	if len(m.pluginPath) > 0 {
+		return m.pluginPath
+	}
+
+	// When searching the following directories, earlier entries get precedence
+	// if the same plugin version is found twice, but newer versions will
+	// always get preference below regardless of where they are coming from.
+	// TODO: Add auto-install dir, default vendor dir and optional override
+	// vendor dir(s).
+	dirs := []string{"."}
+
+	// Look in the same directory as the Terraform executable.
+	// If found, this replaces what we found in the config path.
+	exePath, err := osext.Executable()
+	if err != nil {
+		log.Printf("[ERROR] Error discovering exe directory: %s", err)
+	} else {
+		dirs = append(dirs, filepath.Dir(exePath))
+	}
+
+	// add the user vendor directory
+	dirs = append(dirs, DefaultPluginVendorDir)
+
+	if includeAutoInstalled {
+		dirs = append(dirs, m.pluginDir())
+	}
+	dirs = append(dirs, m.GlobalPluginDirs...)
+
+	return dirs
+}
+
+func (m *Meta) provisionerFactories() map[string]provisioners.Factory {
+	dirs := m.pluginDirs(true)
+	plugins := discovery.FindPlugins("provisioner", dirs)
+	plugins, _ = plugins.ValidateVersions()
+
+	// For now our goal is to just find the latest version of each plugin
+	// we have on the system. All provisioners should be at version 0.0.0
+	// currently, so there should actually only be one instance of each plugin
+	// name here, even though the discovery interface forces us to pretend
+	// that might not be true.
+
+	factories := make(map[string]provisioners.Factory)
+
+	// Wire up the internal provisioners first. These might be overridden
+	// by discovered provisioners below.
+	for name, factory := range internalProvisionerFactories() {
+		factories[name] = factory
+	}
+
+	byName := plugins.ByName()
+	for name, metas := range byName {
+		// Since we validated versions above and we partitioned the sets
+		// by name, we're guaranteed that the metas in our set all have
+		// valid versions and that there's at least one meta.
+		newest := metas.Newest()
+
+		factories[name] = provisionerFactory(newest)
+	}
+
+	return factories
+}
+
+func provisionerFactory(meta discovery.PluginMeta) provisioners.Factory {
+	return func() (provisioners.Interface, error) {
+		cfg := &plugin.ClientConfig{
+			Cmd:              exec.Command(meta.Path),
+			HandshakeConfig:  tfplugin.Handshake,
+			VersionedPlugins: tfplugin.VersionedPlugins,
+			Managed:          true,
+			Logger:           logging.NewLogger("provisioner"),
+			AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
+			AutoMTLS:         enableProviderAutoMTLS,
+			SyncStdout:       logging.PluginOutputMonitor(fmt.Sprintf("%s:stdout", meta.Name)),
+			SyncStderr:       logging.PluginOutputMonitor(fmt.Sprintf("%s:stderr", meta.Name)),
+		}
+		client := plugin.NewClient(cfg)
+		return newProvisionerClient(client)
+	}
+}
+
+func internalProvisionerFactories() map[string]provisioners.Factory {
+	return map[string]provisioners.Factory{
+		"file":        provisioners.FactoryFixed(fileprovisioner.New()),
+		"local-exec":  provisioners.FactoryFixed(localexec.New()),
+		"remote-exec": provisioners.FactoryFixed(remoteexec.New()),
+	}
+}
+
+func newProvisionerClient(client *plugin.Client) (provisioners.Interface, error) {
+	// Request the RPC client so we can get the provisioner
+	// so we can build the actual RPC-implemented provisioner.
+	rpcClient, err := client.Client()
+	if err != nil {
+		return nil, err
+	}
+
+	raw, err := rpcClient.Dispense(tfplugin.ProvisionerPluginName)
+	if err != nil {
+		return nil, err
+	}
+
+	// store the client so that the plugin can kill the child process
+	p := raw.(*tfplugin.GRPCProvisioner)
+	p.PluginClient = client
+	return p, nil
+}
diff --git a/v1.5.7/internal/command/plugins_lock.go b/v1.5.7/internal/command/plugins_lock.go
new file mode 100644
index 0000000..ed77d72
--- /dev/null
+++ b/v1.5.7/internal/command/plugins_lock.go
@@ -0,0 +1,59 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"log"
+)
+
+type pluginSHA256LockFile struct {
+	Filename string
+}
+
+// Read loads the lock information from the file and returns it. If the file
+// cannot be read, an empty map is returned to indicate that _no_ providers
+// are acceptable, since the user must run "terraform init" to lock some
+// providers before a context can be created.
+func (pf *pluginSHA256LockFile) Read() map[string][]byte {
+	// Returning an empty map is different than nil because it causes
+	// us to reject all plugins as uninitialized, rather than applying no
+	// constraints at all.
+	//
+	// We don't surface any specific errors here because we want it to all
+	// roll up into our more-user-friendly error that appears when plugin
+	// constraint verification fails during context creation.
+	digests := make(map[string][]byte)
+
+	buf, err := ioutil.ReadFile(pf.Filename)
+	if err != nil {
+		// This is expected if the user runs any context-using command before
+		// running "terraform init".
+		log.Printf("[INFO] Failed to read plugin lock file %s: %s", pf.Filename, err)
+		return digests
+	}
+
+	var strDigests map[string]string
+	err = json.Unmarshal(buf, &strDigests)
+	if err != nil {
+		// This should never happen unless the user directly edits the file.
+		log.Printf("[WARN] Plugin lock file %s failed to parse as JSON: %s", pf.Filename, err)
+		return digests
+	}
+
+	for name, strDigest := range strDigests {
+		var digest []byte
+		_, err := fmt.Sscanf(strDigest, "%x", &digest)
+		if err == nil {
+			digests[name] = digest
+		} else {
+			// This should never happen unless the user directly edits the file.
+			log.Printf("[WARN] Plugin lock file %s has invalid digest for %q", pf.Filename, name)
+		}
+	}
+
+	return digests
+}
diff --git a/v1.5.7/internal/command/plugins_lock_test.go b/v1.5.7/internal/command/plugins_lock_test.go
new file mode 100644
index 0000000..ecda985
--- /dev/null
+++ b/v1.5.7/internal/command/plugins_lock_test.go
@@ -0,0 +1,30 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"io/ioutil"
+	"os"
+	"reflect"
+	"testing"
+)
+
+func TestPluginSHA256LockFile_Read(t *testing.T) {
+	f, err := ioutil.TempFile(t.TempDir(), "tf-pluginsha1lockfile-test-")
+	if err != nil {
+		t.Fatalf("failed to create temporary file: %s", err)
+	}
+	f.Close()
+	defer os.Remove(f.Name())
+
+	plf := &pluginSHA256LockFile{
+		Filename: f.Name(),
+	}
+
+	// Initially the file is invalid, so we should get an empty map.
+	digests := plf.Read()
+	if !reflect.DeepEqual(digests, map[string][]byte{}) {
+		t.Errorf("wrong initial content %#v; want empty map", digests)
+	}
+}
diff --git a/v1.5.7/internal/command/plugins_test.go b/v1.5.7/internal/command/plugins_test.go
new file mode 100644
index 0000000..ff1a2e9
--- /dev/null
+++ b/v1.5.7/internal/command/plugins_test.go
@@ -0,0 +1,47 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"os"
+	"reflect"
+	"testing"
+)
+
+func TestPluginPath(t *testing.T) {
+	td := testTempDir(t)
+	defer os.RemoveAll(td)
+	defer testChdir(t, td)()
+
+	pluginPath := []string{"a", "b", "c"}
+
+	m := Meta{}
+	if err := m.storePluginPath(pluginPath); err != nil {
+		t.Fatal(err)
+	}
+
+	restoredPath, err := m.loadPluginPath()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !reflect.DeepEqual(pluginPath, restoredPath) {
+		t.Fatalf("expected plugin path %#v, got %#v", pluginPath, restoredPath)
+	}
+}
+
+func TestInternalProviders(t *testing.T) {
+	m := Meta{}
+	internal := m.internalProviders()
+	tfProvider, err := internal["terraform"]()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	schema := tfProvider.GetProviderSchema()
+	_, found := schema.DataSources["terraform_remote_state"]
+	if !found {
+		t.Errorf("didn't find terraform_remote_state in internal \"terraform\" provider")
+	}
+}
diff --git a/v1.5.7/internal/command/providers.go b/v1.5.7/internal/command/providers.go
new file mode 100644
index 0000000..f631d9f
--- /dev/null
+++ b/v1.5.7/internal/command/providers.go
@@ -0,0 +1,164 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"path/filepath"
+
+	"github.com/xlab/treeprint"
+
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ProvidersCommand is a Command implementation that prints out information
+// about the providers used in the current configuration/state.
+type ProvidersCommand struct {
+	Meta
+}
+
+func (c *ProvidersCommand) Help() string {
+	return providersCommandHelp
+}
+
+func (c *ProvidersCommand) Synopsis() string {
+	return "Show the providers required for this configuration"
+}
+
+func (c *ProvidersCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	cmdFlags := c.Meta.defaultFlagSet("providers")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	configPath, err := ModulePath(cmdFlags.Args())
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	empty, err := configs.IsEmptyDir(configPath)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Error validating configuration directory",
+			fmt.Sprintf("Terraform encountered an unexpected error while verifying that the given configuration directory is valid: %s.", err),
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+	if empty {
+		absPath, err := filepath.Abs(configPath)
+		if err != nil {
+			absPath = configPath
+		}
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"No configuration files",
+			fmt.Sprintf("The directory %s contains no Terraform configuration files.", absPath),
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	config, configDiags := c.loadConfig(configPath)
+	diags = diags.Append(configDiags)
+	if configDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(&BackendOpts{
+		Config: config.Module.Backend,
+	})
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// This is a read-only command
+	c.ignoreRemoteVersionConflict(b)
+
+	// Get the state
+	env, err := c.Workspace()
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err))
+		return 1
+	}
+	s, err := b.StateMgr(env)
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
+		return 1
+	}
+	if err := s.RefreshState(); err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
+		return 1
+	}
+
+	reqs, reqDiags := config.ProviderRequirementsByModule()
+	diags = diags.Append(reqDiags)
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	state := s.State()
+	var stateReqs getproviders.Requirements
+	if state != nil {
+		stateReqs = state.ProviderRequirements()
+	}
+
+	printRoot := treeprint.New()
+	c.populateTreeNode(printRoot, reqs)
+
+	c.Ui.Output("\nProviders required by configuration:")
+	c.Ui.Output(printRoot.String())
+
+	if len(stateReqs) > 0 {
+		c.Ui.Output("Providers required by state:\n")
+		for fqn := range stateReqs {
+			c.Ui.Output(fmt.Sprintf("    provider[%s]\n", fqn.String()))
+		}
+	}
+
+	c.showDiagnostics(diags)
+	if diags.HasErrors() {
+		return 1
+	}
+	return 0
+}
+
+func (c *ProvidersCommand) populateTreeNode(tree treeprint.Tree, node *configs.ModuleRequirements) {
+	for fqn, dep := range node.Requirements {
+		versionsStr := getproviders.VersionConstraintsString(dep)
+		if versionsStr != "" {
+			versionsStr = " " + versionsStr
+		}
+		tree.AddNode(fmt.Sprintf("provider[%s]%s", fqn.String(), versionsStr))
+	}
+	for name, childNode := range node.Children {
+		branch := tree.AddBranch(fmt.Sprintf("module.%s", name))
+		c.populateTreeNode(branch, childNode)
+	}
+}
+
+const providersCommandHelp = `
+Usage: terraform [global options] providers [DIR]
+
+  Prints out a tree of modules in the referenced configuration annotated with
+  their provider requirements.
+
+  This provides an overview of all of the provider requirements across all
+  referenced modules, as an aid to understanding why particular provider
+  plugins are needed and why particular versions are selected.
+`
diff --git a/v1.5.7/internal/command/providers_lock.go b/v1.5.7/internal/command/providers_lock.go
new file mode 100644
index 0000000..94e7f39
--- /dev/null
+++ b/v1.5.7/internal/command/providers_lock.go
@@ -0,0 +1,429 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"io/ioutil"
+	"net/url"
+	"os"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/hashicorp/terraform/internal/providercache"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+type providersLockChangeType string
+
+const (
+	providersLockChangeTypeNoChange    providersLockChangeType = "providersLockChangeTypeNoChange"
+	providersLockChangeTypeNewProvider providersLockChangeType = "providersLockChangeTypeNewProvider"
+	providersLockChangeTypeNewHashes   providersLockChangeType = "providersLockChangeTypeNewHashes"
+)
+
+// ProvidersLockCommand is a Command implementation that implements the
+// "terraform providers lock" command, which creates or updates the current
+// configuration's dependency lock file using information from upstream
+// registries, regardless of the provider installation configuration that
+// is configured for normal provider installation.
+type ProvidersLockCommand struct {
+	Meta
+}
+
+func (c *ProvidersLockCommand) Synopsis() string {
+	return "Write out dependency locks for the configured providers"
+}
+
+func (c *ProvidersLockCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	cmdFlags := c.Meta.defaultFlagSet("providers lock")
+	var optPlatforms FlagStringSlice
+	var fsMirrorDir string
+	var netMirrorURL string
+	cmdFlags.Var(&optPlatforms, "platform", "target platform")
+	cmdFlags.StringVar(&fsMirrorDir, "fs-mirror", "", "filesystem mirror directory")
+	cmdFlags.StringVar(&netMirrorURL, "net-mirror", "", "network mirror base URL")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	if fsMirrorDir != "" && netMirrorURL != "" {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid installation method options",
+			"The -fs-mirror and -net-mirror command line options are mutually-exclusive.",
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	providerStrs := cmdFlags.Args()
+
+	var platforms []getproviders.Platform
+	if len(optPlatforms) == 0 {
+		platforms = []getproviders.Platform{getproviders.CurrentPlatform}
+	} else {
+		platforms = make([]getproviders.Platform, 0, len(optPlatforms))
+		for _, platformStr := range optPlatforms {
+			platform, err := getproviders.ParsePlatform(platformStr)
+			if err != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid target platform",
+					fmt.Sprintf("The string %q given in the -platform option is not a valid target platform: %s.", platformStr, err),
+				))
+				continue
+			}
+			platforms = append(platforms, platform)
+		}
+	}
+
+	// Unlike other commands, this command ignores the installation methods
+	// selected in the CLI configuration and instead chooses an installation
+	// method based on CLI options.
+	//
+	// This is so that folks who use a local mirror for everyday use can
+	// use this command to populate their lock files from upstream so
+	// subsequent "terraform init" calls can then verify the local mirror
+	// against the upstream checksums.
+	var source getproviders.Source
+	switch {
+	case fsMirrorDir != "":
+		source = getproviders.NewFilesystemMirrorSource(fsMirrorDir)
+	case netMirrorURL != "":
+		u, err := url.Parse(netMirrorURL)
+		if err != nil || u.Scheme != "https" {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid network mirror URL",
+				"The -net-mirror option requires a valid https: URL as the mirror base URL.",
+			))
+			c.showDiagnostics(diags)
+			return 1
+		}
+		source = getproviders.NewHTTPMirrorSource(u, c.Services.CredentialsSource())
+	default:
+		// With no special options we consult upstream registries directly,
+		// because that gives us the most information to produce as complete
+		// and portable as possible a lock entry.
+		source = getproviders.NewRegistrySource(c.Services)
+	}
+
+	config, confDiags := c.loadConfig(".")
+	diags = diags.Append(confDiags)
+	reqs, hclDiags := config.ProviderRequirements()
+	diags = diags.Append(hclDiags)
+
+	// If we have explicit provider selections on the command line then
+	// we'll modify "reqs" to only include those. Modifying this is okay
+	// because config.ProviderRequirements generates a fresh map result
+	// for each call.
+	if len(providerStrs) != 0 {
+		providers := map[addrs.Provider]struct{}{}
+		for _, raw := range providerStrs {
+			addr, moreDiags := addrs.ParseProviderSourceString(raw)
+			diags = diags.Append(moreDiags)
+			if moreDiags.HasErrors() {
+				continue
+			}
+			providers[addr] = struct{}{}
+			if _, exists := reqs[addr]; !exists {
+				// Can't request a provider that isn't required by the
+				// current configuration.
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid provider argument",
+					fmt.Sprintf("The provider %s is not required by the current configuration.", addr.String()),
+				))
+			}
+		}
+
+		for addr := range reqs {
+			if _, exists := providers[addr]; !exists {
+				delete(reqs, addr)
+			}
+		}
+	}
+
+	// We'll also ignore any providers that don't participate in locking.
+	for addr := range reqs {
+		if !depsfile.ProviderIsLockable(addr) {
+			delete(reqs, addr)
+		}
+	}
+
+	// We'll start our work with whatever locks we already have, so that
+	// we'll honor any existing version selections and just add additional
+	// hashes for them.
+	oldLocks, moreDiags := c.lockedDependencies()
+	diags = diags.Append(moreDiags)
+
+	// If we have any error diagnostics already then we won't proceed further.
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Our general strategy here is to install the requested providers into
+	// a separate temporary directory -- thus ensuring that the results won't
+	// ever be inadvertently executed by other Terraform commands -- and then
+	// use the results of that installation to update the lock file for the
+	// current working directory. Because we throwaway the packages we
+	// downloaded after completing our work, a subsequent "terraform init" will
+	// then respect the CLI configuration's provider installation strategies
+	// but will verify the packages against the hashes we found upstream.
+
+	// Because our Installer abstraction is a per-platform idea, we'll
+	// instantiate one for each of the platforms the user requested, and then
+	// merge all of the generated locks together at the end.
+	updatedLocks := map[getproviders.Platform]*depsfile.Locks{}
+	selectedVersions := map[addrs.Provider]getproviders.Version{}
+	ctx, cancel := c.InterruptibleContext()
+	defer cancel()
+	for _, platform := range platforms {
+		tempDir, err := ioutil.TempDir("", "terraform-providers-lock")
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Could not create temporary directory",
+				fmt.Sprintf("Failed to create a temporary directory for staging the requested provider packages: %s.", err),
+			))
+			break
+		}
+		defer os.RemoveAll(tempDir)
+
+		evts := &providercache.InstallerEvents{
+			// Our output from this command is minimal just to show that
+			// we're making progress, rather than just silently hanging.
+			FetchPackageBegin: func(provider addrs.Provider, version getproviders.Version, loc getproviders.PackageLocation) {
+				c.Ui.Output(fmt.Sprintf("- Fetching %s %s for %s...", provider.ForDisplay(), version, platform))
+				if prevVersion, exists := selectedVersions[provider]; exists && version != prevVersion {
+					// This indicates a weird situation where we ended up
+					// selecting a different version for one platform than
+					// for another. We won't be able to merge the result
+					// in that case, so we'll generate an error.
+					//
+					// This could potentially happen if there's a provider
+					// we've not previously recorded in the lock file and
+					// the available versions change while we're running. To
+					// avoid that would require pre-locking all of the
+					// providers, which is complicated to do with the building
+					// blocks we have here, and so we'll wait to do it only
+					// if this situation arises often in practice.
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Inconsistent provider versions",
+						fmt.Sprintf(
+							"The version constraint for %s selected inconsistent versions for different platforms, which is unexpected.\n\nThe upstream registry may have changed its available versions during Terraform's work. If so, re-running this command may produce a successful result.",
+							provider,
+						),
+					))
+				}
+				selectedVersions[provider] = version
+			},
+			FetchPackageSuccess: func(provider addrs.Provider, version getproviders.Version, localDir string, auth *getproviders.PackageAuthenticationResult) {
+				var keyID string
+				if auth != nil && auth.ThirdPartySigned() {
+					keyID = auth.KeyID
+				}
+				if keyID != "" {
+					keyID = c.Colorize().Color(fmt.Sprintf(", key ID [reset][bold]%s[reset]", keyID))
+				}
+				c.Ui.Output(fmt.Sprintf("- Retrieved %s %s for %s (%s%s)", provider.ForDisplay(), version, platform, auth, keyID))
+			},
+		}
+		ctx := evts.OnContext(ctx)
+
+		dir := providercache.NewDirWithPlatform(tempDir, platform)
+		installer := providercache.NewInstaller(dir, source)
+
+		newLocks, err := installer.EnsureProviderVersions(ctx, oldLocks, reqs, providercache.InstallNewProvidersForce)
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Could not retrieve providers for locking",
+				fmt.Sprintf("Terraform failed to fetch the requested providers for %s in order to calculate their checksums: %s.", platform, err),
+			))
+			break
+		}
+		updatedLocks[platform] = newLocks
+	}
+
+	// If we have any error diagnostics from installation then we won't
+	// proceed to merging and updating the lock file on disk.
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Track whether we've made any changes to the lock file as part of this
+	// operation. We can customise the final message based on our actions.
+	madeAnyChange := false
+
+	// We now have a separate updated locks object for each platform. We need
+	// to merge those all together so that the final result has the union of
+	// all of the checksums we saw for each of the providers we've worked on.
+	//
+	// We'll copy the old locks first because we want to retain any existing
+	// locks for providers that we _didn't_ visit above.
+	newLocks := oldLocks.DeepCopy()
+	for provider := range reqs {
+		oldLock := oldLocks.Provider(provider)
+
+		var version getproviders.Version
+		var constraints getproviders.VersionConstraints
+		var hashes []getproviders.Hash
+		if oldLock != nil {
+			version = oldLock.Version()
+			constraints = oldLock.VersionConstraints()
+			hashes = append(hashes, oldLock.AllHashes()...)
+		}
+		for platform, platformLocks := range updatedLocks {
+			platformLock := platformLocks.Provider(provider)
+			if platformLock == nil {
+				continue // weird, but we'll tolerate it to avoid crashing
+			}
+			version = platformLock.Version()
+			constraints = platformLock.VersionConstraints()
+
+			// We don't make any effort to deduplicate hashes between different
+			// platforms here, because the SetProvider method we call below
+			// handles that automatically.
+			hashes = append(hashes, platformLock.AllHashes()...)
+
+			// At this point, we've merged all the hashes for this (provider, platform)
+			// combo into the combined hashes for this provider. Let's take this
+			// opportunity to print out a summary for this particular combination.
+			switch providersLockCalculateChangeType(oldLock, platformLock) {
+			case providersLockChangeTypeNewProvider:
+				madeAnyChange = true
+				c.Ui.Output(
+					fmt.Sprintf(
+						"- Obtained %s checksums for %s; This was a new provider and the checksums for this platform are now tracked in the lock file",
+						provider.ForDisplay(),
+						platform))
+			case providersLockChangeTypeNewHashes:
+				madeAnyChange = true
+				c.Ui.Output(
+					fmt.Sprintf(
+						"- Obtained %s checksums for %s; Additional checksums for this platform are now tracked in the lock file",
+						provider.ForDisplay(),
+						platform))
+			case providersLockChangeTypeNoChange:
+				c.Ui.Output(
+					fmt.Sprintf(
+						"- Obtained %s checksums for %s; All checksums for this platform were already tracked in the lock file",
+						provider.ForDisplay(),
+						platform))
+			}
+		}
+		newLocks.SetProvider(provider, version, constraints, hashes)
+	}
+
+	moreDiags = c.replaceLockedDependencies(newLocks)
+	diags = diags.Append(moreDiags)
+
+	c.showDiagnostics(diags)
+	if diags.HasErrors() {
+		return 1
+	}
+
+	if madeAnyChange {
+		c.Ui.Output(c.Colorize().Color("\n[bold][green]Success![reset] [bold]Terraform has updated the lock file.[reset]"))
+		c.Ui.Output("\nReview the changes in .terraform.lock.hcl and then commit to your\nversion control system to retain the new checksums.\n")
+	} else {
+		c.Ui.Output(c.Colorize().Color("\n[bold][green]Success![reset] [bold]Terraform has validated the lock file and found no need for changes.[reset]"))
+	}
+	return 0
+}
+
+func (c *ProvidersLockCommand) Help() string {
+	return `
+Usage: terraform [global options] providers lock [options] [providers...]
+
+  Normally the dependency lock file (.terraform.lock.hcl) is updated
+  automatically by "terraform init", but the information available to the
+  normal provider installer can be constrained when you're installing providers
+  from filesystem or network mirrors, and so the generated lock file can end
+  up incomplete.
+
+  The "providers lock" subcommand addresses that by updating the lock file
+  based on the official packages available in the origin registry, ignoring
+  the currently-configured installation strategy.
+
+  After this command succeeds, the lock file will contain suitable checksums
+  to allow installation of the providers needed by the current configuration
+  on all of the selected platforms.
+
+  By default this command updates the lock file for every provider declared
+  in the configuration. You can override that behavior by providing one or
+  more provider source addresses on the command line.
+
+Options:
+
+  -fs-mirror=dir     Consult the given filesystem mirror directory instead
+                     of the origin registry for each of the given providers.
+
+                     This would be necessary to generate lock file entries for
+                     a provider that is available only via a mirror, and not
+                     published in an upstream registry. In this case, the set
+                     of valid checksums will be limited only to what Terraform
+                     can learn from the data in the mirror directory.
+
+  -net-mirror=url    Consult the given network mirror (given as a base URL)
+                     instead of the origin registry for each of the given
+                     providers.
+
+                     This would be necessary to generate lock file entries for
+                     a provider that is available only via a mirror, and not
+                     published in an upstream registry. In this case, the set
+                     of valid checksums will be limited only to what Terraform
+                     can learn from the data in the mirror indices.
+
+  -platform=os_arch  Choose a target platform to request package checksums
+                     for.
+
+                     By default Terraform will request package checksums
+                     suitable only for the platform where you run this
+                     command. Use this option multiple times to include
+                     checksums for multiple target systems.
+
+                     Target names consist of an operating system and a CPU
+                     architecture. For example, "linux_amd64" selects the
+                     Linux operating system running on an AMD64 or x86_64
+                     CPU. Each provider is available only for a limited
+                     set of target platforms.
+`
+}
+
+// providersLockCalculateChangeType works out whether there is any difference
+// between oldLock and newLock and returns a variable the main function can use
+// to decide on which message to print.
+//
+// One assumption made here that is not obvious without the context from the
+// main function is that while platformLock contains the lock information for a
+// single platform after the current run, oldLock contains the combined
+// information of all platforms from when the versions were last checked. A
+// simple equality check is not sufficient for deciding on change as we expect
+// that oldLock will be a superset of platformLock if no new hashes have been
+// found.
+//
+// We've separated this function out so we can write unit tests around the
+// logic. This function assumes the platformLock is not nil, as the main
+// function explicitly checks this before calling this function.
+func providersLockCalculateChangeType(oldLock *depsfile.ProviderLock, platformLock *depsfile.ProviderLock) providersLockChangeType {
+	if oldLock == nil {
+		return providersLockChangeTypeNewProvider
+	}
+	if oldLock.ContainsAll(platformLock) {
+		return providersLockChangeTypeNoChange
+	}
+	return providersLockChangeTypeNewHashes
+}
diff --git a/v1.5.7/internal/command/providers_lock_test.go b/v1.5.7/internal/command/providers_lock_test.go
new file mode 100644
index 0000000..31438cd
--- /dev/null
+++ b/v1.5.7/internal/command/providers_lock_test.go
@@ -0,0 +1,259 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/mitchellh/cli"
+)
+
+func TestProvidersLock(t *testing.T) {
+	t.Run("noop", func(t *testing.T) {
+		// in the most basic case, running providers lock in a directory with no configuration at all should succeed.
+		// create an empty working directory
+		td := t.TempDir()
+		os.MkdirAll(td, 0755)
+		defer testChdir(t, td)()
+
+		ui := new(cli.MockUi)
+		c := &ProvidersLockCommand{
+			Meta: Meta{
+				Ui: ui,
+			},
+		}
+		code := c.Run([]string{})
+		if code != 0 {
+			t.Fatalf("wrong exit code; expected 0, got %d", code)
+		}
+	})
+
+	// This test depends on the -fs-mirror argument, so we always know what results to expect
+	t.Run("basic", func(t *testing.T) {
+		testDirectory := "providers-lock/basic"
+		expected := `# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/test" {
+  version = "1.0.0"
+  hashes = [
+    "h1:7MjN4eFisdTv4tlhXH5hL4QQd39Jy4baPhFxwAd/EFE=",
+  ]
+}
+`
+		runProviderLockGenericTest(t, testDirectory, expected)
+	})
+
+	// This test depends on the -fs-mirror argument, so we always know what results to expect
+	t.Run("append", func(t *testing.T) {
+		testDirectory := "providers-lock/append"
+		expected := `# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/test" {
+  version = "1.0.0"
+  hashes = [
+    "h1:7MjN4eFisdTv4tlhXH5hL4QQd39Jy4baPhFxwAd/EFE=",
+    "h1:invalid",
+  ]
+}
+`
+		runProviderLockGenericTest(t, testDirectory, expected)
+	})
+}
+
+func runProviderLockGenericTest(t *testing.T, testDirectory, expected string) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath(testDirectory), td)
+	defer testChdir(t, td)()
+
+	// Our fixture dir has a generic os_arch dir, which we need to customize
+	// to the actual OS/arch where this test is running in order to get the
+	// desired result.
+	fixtMachineDir := filepath.Join(td, "fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch")
+	wantMachineDir := filepath.Join(td, "fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
+	err := os.Rename(fixtMachineDir, wantMachineDir)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	c := &ProvidersLockCommand{
+		Meta: Meta{
+			Ui:               ui,
+			testingOverrides: metaOverridesForProvider(p),
+		},
+	}
+
+	args := []string{"-fs-mirror=fs-mirror"}
+	code := c.Run(args)
+	if code != 0 {
+		t.Fatalf("wrong exit code; expected 0, got %d", code)
+	}
+
+	lockfile, err := os.ReadFile(".terraform.lock.hcl")
+	if err != nil {
+		t.Fatal("error reading lockfile")
+	}
+
+	if string(lockfile) != expected {
+		t.Fatalf("wrong lockfile content")
+	}
+}
+
+func TestProvidersLock_args(t *testing.T) {
+
+	t.Run("mirror collision", func(t *testing.T) {
+		ui := new(cli.MockUi)
+		c := &ProvidersLockCommand{
+			Meta: Meta{
+				Ui: ui,
+			},
+		}
+
+		// only one of these arguments can be used at a time
+		args := []string{
+			"-fs-mirror=/foo/",
+			"-net-mirror=www.foo.com",
+		}
+		code := c.Run(args)
+
+		if code != 1 {
+			t.Fatalf("wrong exit code; expected 1, got %d", code)
+		}
+		output := ui.ErrorWriter.String()
+		if !strings.Contains(output, "The -fs-mirror and -net-mirror command line options are mutually-exclusive.") {
+			t.Fatalf("missing expected error message: %s", output)
+		}
+	})
+
+	t.Run("invalid platform", func(t *testing.T) {
+		ui := new(cli.MockUi)
+		c := &ProvidersLockCommand{
+			Meta: Meta{
+				Ui: ui,
+			},
+		}
+
+		// not a valid platform
+		args := []string{"-platform=arbitrary_nonsense_that_isnt_valid"}
+		code := c.Run(args)
+
+		if code != 1 {
+			t.Fatalf("wrong exit code; expected 1, got %d", code)
+		}
+		output := ui.ErrorWriter.String()
+		if !strings.Contains(output, "must be two words separated by an underscore.") {
+			t.Fatalf("missing expected error message: %s", output)
+		}
+	})
+
+	t.Run("invalid provider argument", func(t *testing.T) {
+		ui := new(cli.MockUi)
+		c := &ProvidersLockCommand{
+			Meta: Meta{
+				Ui: ui,
+			},
+		}
+
+		// There is no configuration, so it's not valid to use any provider argument
+		args := []string{"hashicorp/random"}
+		code := c.Run(args)
+
+		if code != 1 {
+			t.Fatalf("wrong exit code; expected 1, got %d", code)
+		}
+		output := ui.ErrorWriter.String()
+		if !strings.Contains(output, "The provider registry.terraform.io/hashicorp/random is not required by the\ncurrent configuration.") {
+			t.Fatalf("missing expected error message: %s", output)
+		}
+	})
+}
+
+func TestProvidersLockCalculateChangeType(t *testing.T) {
+	provider := addrs.NewDefaultProvider("provider")
+	v2 := getproviders.MustParseVersion("2.0.0")
+	v2EqConstraints := getproviders.MustParseVersionConstraints("2.0.0")
+
+	t.Run("oldLock == nil", func(t *testing.T) {
+		platformLock := depsfile.NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
+			"9r3i9a9QmASqMnQM",
+			"K43RHM2klOoywtyW",
+			"swJPXfuCNhJsTM5c",
+		})
+
+		if ct := providersLockCalculateChangeType(nil, platformLock); ct != providersLockChangeTypeNewProvider {
+			t.Fatalf("output was %s but should be %s", ct, providersLockChangeTypeNewProvider)
+		}
+	})
+
+	t.Run("oldLock == platformLock", func(t *testing.T) {
+		platformLock := depsfile.NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
+			"9r3i9a9QmASqMnQM",
+			"K43RHM2klOoywtyW",
+			"swJPXfuCNhJsTM5c",
+		})
+
+		oldLock := depsfile.NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
+			"9r3i9a9QmASqMnQM",
+			"K43RHM2klOoywtyW",
+			"swJPXfuCNhJsTM5c",
+		})
+
+		if ct := providersLockCalculateChangeType(oldLock, platformLock); ct != providersLockChangeTypeNoChange {
+			t.Fatalf("output was %s but should be %s", ct, providersLockChangeTypeNoChange)
+		}
+	})
+
+	t.Run("oldLock > platformLock", func(t *testing.T) {
+		platformLock := depsfile.NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
+			"9r3i9a9QmASqMnQM",
+			"K43RHM2klOoywtyW",
+			"swJPXfuCNhJsTM5c",
+		})
+
+		oldLock := depsfile.NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
+			"9r3i9a9QmASqMnQM",
+			"1ZAChGWUMWn4zmIk",
+			"K43RHM2klOoywtyW",
+			"HWjRvIuWZ1LVatnc",
+			"swJPXfuCNhJsTM5c",
+			"KwhJK4p/U2dqbKhI",
+		})
+
+		if ct := providersLockCalculateChangeType(oldLock, platformLock); ct != providersLockChangeTypeNoChange {
+			t.Fatalf("output was %s but should be %s", ct, providersLockChangeTypeNoChange)
+		}
+	})
+
+	t.Run("oldLock < platformLock", func(t *testing.T) {
+		platformLock := depsfile.NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
+			"9r3i9a9QmASqMnQM",
+			"1ZAChGWUMWn4zmIk",
+			"K43RHM2klOoywtyW",
+			"HWjRvIuWZ1LVatnc",
+			"swJPXfuCNhJsTM5c",
+			"KwhJK4p/U2dqbKhI",
+		})
+
+		oldLock := depsfile.NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
+			"9r3i9a9QmASqMnQM",
+			"K43RHM2klOoywtyW",
+			"swJPXfuCNhJsTM5c",
+		})
+
+		if ct := providersLockCalculateChangeType(oldLock, platformLock); ct != providersLockChangeTypeNewHashes {
+			t.Fatalf("output was %s but should be %s", ct, providersLockChangeTypeNoChange)
+		}
+	})
+}
diff --git a/v1.5.7/internal/command/providers_mirror.go b/v1.5.7/internal/command/providers_mirror.go
new file mode 100644
index 0000000..13d22c5
--- /dev/null
+++ b/v1.5.7/internal/command/providers_mirror.go
@@ -0,0 +1,380 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"net/url"
+	"os"
+	"path/filepath"
+
+	"github.com/apparentlymart/go-versions/versions"
+	"github.com/hashicorp/go-getter"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/hashicorp/terraform/internal/httpclient"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ProvidersMirrorCommand is a Command implementation that implements the
+// "terraform providers mirror" command, which populates a directory with
+// local copies of provider plugins needed by the current configuration so
+// that the mirror can be used to work offline, or similar.
+type ProvidersMirrorCommand struct {
+	Meta
+}
+
+func (c *ProvidersMirrorCommand) Synopsis() string {
+	return "Save local copies of all required provider plugins"
+}
+
+func (c *ProvidersMirrorCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	cmdFlags := c.Meta.defaultFlagSet("providers mirror")
+	var optPlatforms FlagStringSlice
+	cmdFlags.Var(&optPlatforms, "platform", "target platform")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	args = cmdFlags.Args()
+	if len(args) != 1 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"No output directory specified",
+			"The providers mirror command requires an output directory as a command-line argument.",
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+	outputDir := args[0]
+
+	var platforms []getproviders.Platform
+	if len(optPlatforms) == 0 {
+		platforms = []getproviders.Platform{getproviders.CurrentPlatform}
+	} else {
+		platforms = make([]getproviders.Platform, 0, len(optPlatforms))
+		for _, platformStr := range optPlatforms {
+			platform, err := getproviders.ParsePlatform(platformStr)
+			if err != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid target platform",
+					fmt.Sprintf("The string %q given in the -platform option is not a valid target platform: %s.", platformStr, err),
+				))
+				continue
+			}
+			platforms = append(platforms, platform)
+		}
+	}
+
+	config, confDiags := c.loadConfig(".")
+	diags = diags.Append(confDiags)
+	reqs, moreDiags := config.ProviderRequirements()
+	diags = diags.Append(moreDiags)
+
+	// Read lock file
+	lockedDeps, lockedDepsDiags := c.Meta.lockedDependencies()
+	diags = diags.Append(lockedDepsDiags)
+
+	// If we have any error diagnostics already then we won't proceed further.
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// If lock file is present, validate it against configuration
+	if !lockedDeps.Empty() {
+		if errs := config.VerifyDependencySelections(lockedDeps); len(errs) > 0 {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Inconsistent dependency lock file",
+				fmt.Sprintf("To update the locked dependency selections to match a changed configuration, run:\n  terraform init -upgrade\n got:%v", errs),
+			))
+		}
+	}
+
+	// Unlike other commands, this command always consults the origin registry
+	// for every provider so that it can be used to update a local mirror
+	// directory without needing to first disable that local mirror
+	// in the CLI configuration.
+	source := getproviders.NewMemoizeSource(
+		getproviders.NewRegistrySource(c.Services),
+	)
+
+	// Providers from registries always use HTTP, so we don't need the full
+	// generality of go-getter but it's still handy to use the HTTP getter
+	// as an easy way to download over HTTP into a file on disk.
+	httpGetter := getter.HttpGetter{
+		Client:                httpclient.New(),
+		Netrc:                 true,
+		XTerraformGetDisabled: true,
+	}
+
+	// The following logic is similar to that used by the provider installer
+	// in package providercache, but different in a few ways:
+	// - It produces the packed directory layout rather than the unpacked
+	//   layout we require in provider cache directories.
+	// - It generates JSON index files that can be read by the
+	//   getproviders.HTTPMirrorSource installation method if the result were
+	//   copied into the docroot of an HTTP server.
+	// - It can mirror packages for potentially many different target platforms,
+	//   so that we can construct a multi-platform mirror regardless of which
+	//   platform we run this command on.
+	// - It ignores what's already present and just always downloads everything
+	//   that the configuration requires. This is a command intended to be run
+	//   infrequently to update a mirror, so it doesn't need to optimize away
+	//   fetches of packages that might already be present.
+
+	ctx, cancel := c.InterruptibleContext()
+	defer cancel()
+	for provider, constraints := range reqs {
+		if provider.IsBuiltIn() {
+			c.Ui.Output(fmt.Sprintf("- Skipping %s because it is built in to Terraform CLI", provider.ForDisplay()))
+			continue
+		}
+		constraintsStr := getproviders.VersionConstraintsString(constraints)
+		c.Ui.Output(fmt.Sprintf("- Mirroring %s...", provider.ForDisplay()))
+		// First we'll look for the latest version that matches the given
+		// constraint, which we'll then try to mirror for each target platform.
+		acceptable := versions.MeetingConstraints(constraints)
+		avail, _, err := source.AvailableVersions(ctx, provider)
+		candidates := avail.Filter(acceptable)
+		if err == nil && len(candidates) == 0 {
+			err = fmt.Errorf("no releases match the given constraints %s", constraintsStr)
+		}
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Provider not available",
+				fmt.Sprintf("Failed to download %s from its origin registry: %s.", provider.String(), err),
+			))
+			continue
+		}
+		selected := candidates.Newest()
+		if !lockedDeps.Empty() {
+			selected = lockedDeps.Provider(provider).Version()
+			c.Ui.Output(fmt.Sprintf("  - Selected v%s to match dependency lock file", selected.String()))
+		} else if len(constraintsStr) > 0 {
+			c.Ui.Output(fmt.Sprintf("  - Selected v%s to meet constraints %s", selected.String(), constraintsStr))
+		} else {
+			c.Ui.Output(fmt.Sprintf("  - Selected v%s with no constraints", selected.String()))
+		}
+		for _, platform := range platforms {
+			c.Ui.Output(fmt.Sprintf("  - Downloading package for %s...", platform.String()))
+			meta, err := source.PackageMeta(ctx, provider, selected, platform)
+			if err != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Provider release not available",
+					fmt.Sprintf("Failed to download %s v%s for %s: %s.", provider.String(), selected.String(), platform.String(), err),
+				))
+				continue
+			}
+			urlStr, ok := meta.Location.(getproviders.PackageHTTPURL)
+			if !ok {
+				// We don't expect to get non-HTTP locations here because we're
+				// using the registry source, so this seems like a bug in the
+				// registry source.
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Provider release not available",
+					fmt.Sprintf("Failed to download %s v%s for %s: Terraform's provider registry client returned unexpected location type %T. This is a bug in Terraform.", provider.String(), selected.String(), platform.String(), meta.Location),
+				))
+				continue
+			}
+			urlObj, err := url.Parse(string(urlStr))
+			if err != nil {
+				// We don't expect to get non-HTTP locations here because we're
+				// using the registry source, so this seems like a bug in the
+				// registry source.
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid URL for provider release",
+					fmt.Sprintf("The origin registry for %s returned an invalid URL for v%s on %s: %s.", provider.String(), selected.String(), platform.String(), err),
+				))
+				continue
+			}
+			// targetPath is the path where we ultimately want to place the
+			// downloaded archive, but we'll place it initially at stagingPath
+			// so we can verify its checksums and signatures before making
+			// it discoverable to mirror clients. (stagingPath intentionally
+			// does not follow the filesystem mirror file naming convention.)
+			targetPath := meta.PackedFilePath(outputDir)
+			stagingPath := filepath.Join(filepath.Dir(targetPath), "."+filepath.Base(targetPath))
+			err = httpGetter.GetFile(stagingPath, urlObj)
+			if err != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Cannot download provider release",
+					fmt.Sprintf("Failed to download %s v%s for %s: %s.", provider.String(), selected.String(), platform.String(), err),
+				))
+				continue
+			}
+			if meta.Authentication != nil {
+				result, err := meta.Authentication.AuthenticatePackage(getproviders.PackageLocalArchive(stagingPath))
+				if err != nil {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Invalid provider package",
+						fmt.Sprintf("Failed to authenticate %s v%s for %s: %s.", provider.String(), selected.String(), platform.String(), err),
+					))
+					continue
+				}
+				c.Ui.Output(fmt.Sprintf("  - Package authenticated: %s", result))
+			}
+			os.Remove(targetPath) // okay if it fails because we're going to try to rename over it next anyway
+			err = os.Rename(stagingPath, targetPath)
+			if err != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Cannot download provider release",
+					fmt.Sprintf("Failed to place %s package into mirror directory: %s.", provider.String(), err),
+				))
+				continue
+			}
+		}
+	}
+
+	// Now we'll generate or update the JSON index files in the directory.
+	// We do this by scanning the directory to see what is present, rather than
+	// by relying on the selections we made above, because we want to still
+	// include in the indices any packages that were already present and
+	// not affected by the changes we just made.
+	available, err := getproviders.SearchLocalDirectory(outputDir)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to update indexes",
+			fmt.Sprintf("Could not scan the output directory to get package metadata for the JSON indexes: %s.", err),
+		))
+		available = nil // the following loop will be a no-op
+	}
+	for provider, metas := range available {
+		if len(metas) == 0 {
+			continue // should never happen, but we'll be resilient
+		}
+		// The index files live in the same directory as the package files,
+		// so to figure that out without duplicating the path-building logic
+		// we'll ask the getproviders package to build an archive filename
+		// for a fictitious package and then use the directory portion of it.
+		indexDir := filepath.Dir(getproviders.PackedFilePathForPackage(
+			outputDir, provider, versions.Unspecified, getproviders.CurrentPlatform,
+		))
+		indexVersions := map[string]interface{}{}
+		indexArchives := map[getproviders.Version]map[string]interface{}{}
+		for _, meta := range metas {
+			archivePath, ok := meta.Location.(getproviders.PackageLocalArchive)
+			if !ok {
+				// only archive files are eligible to be included in JSON
+				// indices for a network mirror.
+				continue
+			}
+			archiveFilename := filepath.Base(string(archivePath))
+			version := meta.Version
+			platform := meta.TargetPlatform
+			hash, err := meta.Hash()
+			if err != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to update indexes",
+					fmt.Sprintf("Failed to determine a hash value for %s v%s on %s: %s.", provider, version, platform, err),
+				))
+				continue
+			}
+			indexVersions[meta.Version.String()] = map[string]interface{}{}
+			if _, ok := indexArchives[version]; !ok {
+				indexArchives[version] = map[string]interface{}{}
+			}
+			indexArchives[version][platform.String()] = map[string]interface{}{
+				"url":    archiveFilename,         // a relative URL from the index file's URL
+				"hashes": []string{hash.String()}, // an array to allow for additional hash formats in future
+			}
+		}
+		mainIndex := map[string]interface{}{
+			"versions": indexVersions,
+		}
+		mainIndexJSON, err := json.MarshalIndent(mainIndex, "", "  ")
+		if err != nil {
+			// Should never happen because the input here is entirely under
+			// our control.
+			panic(fmt.Sprintf("failed to encode main index: %s", err))
+		}
+		// TODO: Ideally we would do these updates as atomic swap operations by
+		// creating a new file and then renaming it over the old one, in case
+		// this directory is the docroot of a live mirror. An atomic swap
+		// requires platform-specific code though: os.Rename alone can't do it
+		// when running on Windows as of Go 1.13. We should revisit this once
+		// we're supporting network mirrors, to avoid having them briefly
+		// become corrupted during updates.
+		err = ioutil.WriteFile(filepath.Join(indexDir, "index.json"), mainIndexJSON, 0644)
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to update indexes",
+				fmt.Sprintf("Failed to write an updated JSON index for %s: %s.", provider, err),
+			))
+		}
+		for version, archiveIndex := range indexArchives {
+			versionIndex := map[string]interface{}{
+				"archives": archiveIndex,
+			}
+			versionIndexJSON, err := json.MarshalIndent(versionIndex, "", "  ")
+			if err != nil {
+				// Should never happen because the input here is entirely under
+				// our control.
+				panic(fmt.Sprintf("failed to encode version index: %s", err))
+			}
+			err = ioutil.WriteFile(filepath.Join(indexDir, version.String()+".json"), versionIndexJSON, 0644)
+			if err != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to update indexes",
+					fmt.Sprintf("Failed to write an updated JSON index for %s v%s: %s.", provider, version, err),
+				))
+			}
+		}
+	}
+
+	c.showDiagnostics(diags)
+	if diags.HasErrors() {
+		return 1
+	}
+	return 0
+}
+
+func (c *ProvidersMirrorCommand) Help() string {
+	return `
+Usage: terraform [global options] providers mirror [options] <target-dir>
+
+  Populates a local directory with copies of the provider plugins needed for
+  the current configuration, so that the directory can be used either directly
+  as a filesystem mirror or as the basis for a network mirror and thus obtain
+  those providers without access to their origin registries in future.
+
+  The mirror directory will contain JSON index files that can be published
+  along with the mirrored packages on a static HTTP file server to produce
+  a network mirror. Those index files will be ignored if the directory is
+  used instead as a local filesystem mirror.
+
+Options:
+
+  -platform=os_arch  Choose which target platform to build a mirror for.
+                     By default Terraform will obtain plugin packages
+                     suitable for the platform where you run this command.
+                     Use this flag multiple times to include packages for
+                     multiple target systems.
+
+                     Target names consist of an operating system and a CPU
+                     architecture. For example, "linux_amd64" selects the
+                     Linux operating system running on an AMD64 or x86_64
+                     CPU. Each provider is available only for a limited
+                     set of target platforms.
+`
+}
diff --git a/v1.5.7/internal/command/providers_mirror_test.go b/v1.5.7/internal/command/providers_mirror_test.go
new file mode 100644
index 0000000..303c088
--- /dev/null
+++ b/v1.5.7/internal/command/providers_mirror_test.go
@@ -0,0 +1,39 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/mitchellh/cli"
+)
+
+// More thorough tests for providers mirror can be found in the e2etest
+func TestProvidersMirror(t *testing.T) {
+	// noop example
+	t.Run("noop", func(t *testing.T) {
+		c := &ProvidersMirrorCommand{}
+		code := c.Run([]string{"."})
+		if code != 0 {
+			t.Fatalf("wrong exit code. expected 0, got %d", code)
+		}
+	})
+
+	t.Run("missing arg error", func(t *testing.T) {
+		ui := new(cli.MockUi)
+		c := &ProvidersMirrorCommand{
+			Meta: Meta{Ui: ui},
+		}
+		code := c.Run([]string{})
+		if code != 1 {
+			t.Fatalf("wrong exit code. expected 1, got %d", code)
+		}
+
+		got := ui.ErrorWriter.String()
+		if !strings.Contains(got, "Error: No output directory specified") {
+			t.Fatalf("missing directory error from output, got:\n%s\n", got)
+		}
+	})
+}
diff --git a/v1.5.7/internal/command/providers_schema.go b/v1.5.7/internal/command/providers_schema.go
new file mode 100644
index 0000000..a0d84ef
--- /dev/null
+++ b/v1.5.7/internal/command/providers_schema.go
@@ -0,0 +1,125 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ProvidersCommand is a Command implementation that prints out information
+// about the providers used in the current configuration/state.
+type ProvidersSchemaCommand struct {
+	Meta
+}
+
+func (c *ProvidersSchemaCommand) Help() string {
+	return providersSchemaCommandHelp
+}
+
+func (c *ProvidersSchemaCommand) Synopsis() string {
+	return "Show schemas for the providers used in the configuration"
+}
+
+func (c *ProvidersSchemaCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	cmdFlags := c.Meta.defaultFlagSet("providers schema")
+	var jsonOutput bool
+	cmdFlags.BoolVar(&jsonOutput, "json", false, "produce JSON output")
+
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	if !jsonOutput {
+		c.Ui.Error(
+			"The `terraform providers schema` command requires the `-json` flag.\n")
+		cmdFlags.Usage()
+		return 1
+	}
+
+	// Check for user-supplied plugin path
+	var err error
+	if c.pluginPath, err = c.loadPluginPath(); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error loading plugin path: %s", err))
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	// Load the backend
+	b, backendDiags := c.Backend(nil)
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// We require a local backend
+	local, ok := b.(backend.Local)
+	if !ok {
+		c.showDiagnostics(diags) // in case of any warnings in here
+		c.Ui.Error(ErrUnsupportedLocalOp)
+		return 1
+	}
+
+	// This is a read-only command
+	c.ignoreRemoteVersionConflict(b)
+
+	// we expect that the config dir is the cwd
+	cwd, err := os.Getwd()
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Error getting cwd: %s", err))
+		return 1
+	}
+
+	// Build the operation
+	opReq := c.Operation(b, arguments.ViewJSON)
+	opReq.ConfigDir = cwd
+	opReq.ConfigLoader, err = c.initConfigLoader()
+	opReq.AllowUnsetVariables = true
+	if err != nil {
+		diags = diags.Append(err)
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Get the context
+	lr, _, ctxDiags := local.LocalRun(opReq)
+	diags = diags.Append(ctxDiags)
+	if ctxDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	schemas, moreDiags := lr.Core.Schemas(lr.Config, lr.InputState)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	jsonSchemas, err := jsonprovider.Marshal(schemas)
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to marshal provider schemas to json: %s", err))
+		return 1
+	}
+	c.Ui.Output(string(jsonSchemas))
+
+	return 0
+}
+
+const providersSchemaCommandHelp = `
+Usage: terraform [global options] providers schema -json
+
+  Prints out a json representation of the schemas for all providers used 
+  in the current configuration.
+`
diff --git a/v1.5.7/internal/command/providers_schema_test.go b/v1.5.7/internal/command/providers_schema_test.go
new file mode 100644
index 0000000..416698e
--- /dev/null
+++ b/v1.5.7/internal/command/providers_schema_test.go
@@ -0,0 +1,157 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/mitchellh/cli"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestProvidersSchema_error(t *testing.T) {
+	ui := new(cli.MockUi)
+	c := &ProvidersSchemaCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+		},
+	}
+
+	if code := c.Run(nil); code != 1 {
+		fmt.Println(ui.OutputWriter.String())
+		t.Fatalf("expected error: \n%s", ui.OutputWriter.String())
+	}
+}
+
+func TestProvidersSchema_output(t *testing.T) {
+	fixtureDir := "testdata/providers-schema"
+	testDirs, err := ioutil.ReadDir(fixtureDir)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, entry := range testDirs {
+		if !entry.IsDir() {
+			continue
+		}
+		t.Run(entry.Name(), func(t *testing.T) {
+			td := t.TempDir()
+			inputDir := filepath.Join(fixtureDir, entry.Name())
+			testCopyDir(t, inputDir, td)
+			defer testChdir(t, td)()
+
+			providerSource, close := newMockProviderSource(t, map[string][]string{
+				"test": {"1.2.3"},
+			})
+			defer close()
+
+			p := providersSchemaFixtureProvider()
+			ui := new(cli.MockUi)
+			m := Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				ProviderSource:   providerSource,
+			}
+
+			// `terrafrom init`
+			ic := &InitCommand{
+				Meta: m,
+			}
+			if code := ic.Run([]string{}); code != 0 {
+				t.Fatalf("init failed\n%s", ui.ErrorWriter)
+			}
+
+			// flush the init output from the mock ui
+			ui.OutputWriter.Reset()
+
+			// `terraform provider schemas` command
+			pc := &ProvidersSchemaCommand{Meta: m}
+			if code := pc.Run([]string{"-json"}); code != 0 {
+				t.Fatalf("wrong exit status %d; want 0\nstderr: %s", code, ui.ErrorWriter.String())
+			}
+			var got, want providerSchemas
+
+			gotString := ui.OutputWriter.String()
+			json.Unmarshal([]byte(gotString), &got)
+
+			wantFile, err := os.Open("output.json")
+			if err != nil {
+				t.Fatalf("err: %s", err)
+			}
+			defer wantFile.Close()
+			byteValue, err := ioutil.ReadAll(wantFile)
+			if err != nil {
+				t.Fatalf("err: %s", err)
+			}
+			json.Unmarshal([]byte(byteValue), &want)
+
+			if !cmp.Equal(got, want) {
+				t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, want))
+			}
+		})
+	}
+}
+
+type providerSchemas struct {
+	FormatVersion string                    `json:"format_version"`
+	Schemas       map[string]providerSchema `json:"provider_schemas"`
+}
+
+type providerSchema struct {
+	Provider          interface{}            `json:"provider,omitempty"`
+	ResourceSchemas   map[string]interface{} `json:"resource_schemas,omitempty"`
+	DataSourceSchemas map[string]interface{} `json:"data_source_schemas,omitempty"`
+}
+
+// testProvider returns a mock provider that is configured for basic
+// operation with the configuration in testdata/providers-schema.
+func providersSchemaFixtureProvider() *terraform.MockProvider {
+	p := testProvider()
+	p.GetProviderSchemaResponse = providersSchemaFixtureSchema()
+	return p
+}
+
+// providersSchemaFixtureSchema returns a schema suitable for processing the
+// configuration in testdata/providers-schema.ß
+func providersSchemaFixtureSchema() *providers.GetProviderSchemaResponse {
+	return &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"region": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":  {Type: cty.String, Optional: true, Computed: true},
+						"ami": {Type: cty.String, Optional: true},
+						"volumes": {
+							NestedType: &configschema.Object{
+								Nesting: configschema.NestingList,
+								Attributes: map[string]*configschema.Attribute{
+									"size":        {Type: cty.String, Required: true},
+									"mount_point": {Type: cty.String, Required: true},
+								},
+							},
+							Optional: true,
+						},
+					},
+				},
+			},
+		},
+	}
+}
diff --git a/v1.5.7/internal/command/providers_test.go b/v1.5.7/internal/command/providers_test.go
new file mode 100644
index 0000000..697966a
--- /dev/null
+++ b/v1.5.7/internal/command/providers_test.go
@@ -0,0 +1,168 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"os"
+	"strings"
+	"testing"
+
+	"github.com/mitchellh/cli"
+)
+
+func TestProviders(t *testing.T) {
+	cwd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if err := os.Chdir(testFixturePath("providers/basic")); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer os.Chdir(cwd)
+
+	ui := new(cli.MockUi)
+	c := &ProvidersCommand{
+		Meta: Meta{
+			Ui: ui,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	wantOutput := []string{
+		"provider[registry.terraform.io/hashicorp/foo]",
+		"provider[registry.terraform.io/hashicorp/bar]",
+		"provider[registry.terraform.io/hashicorp/baz]",
+	}
+
+	output := ui.OutputWriter.String()
+	for _, want := range wantOutput {
+		if !strings.Contains(output, want) {
+			t.Errorf("output missing %s:\n%s", want, output)
+		}
+	}
+}
+
+func TestProviders_noConfigs(t *testing.T) {
+	cwd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if err := os.Chdir(testFixturePath("")); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer os.Chdir(cwd)
+
+	ui := new(cli.MockUi)
+	c := &ProvidersCommand{
+		Meta: Meta{
+			Ui: ui,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code == 0 {
+		t.Fatal("expected command to return non-zero exit code" +
+			" when no configs are available")
+	}
+
+	output := ui.ErrorWriter.String()
+	expectedErrMsg := "No configuration files"
+	if !strings.Contains(output, expectedErrMsg) {
+		t.Errorf("Expected error message: %s\nGiven output: %s", expectedErrMsg, output)
+	}
+}
+
+func TestProviders_modules(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("providers/modules"), td)
+	defer testChdir(t, td)()
+
+	// first run init with mock provider sources to install the module
+	initUi := new(cli.MockUi)
+	providerSource, close := newMockProviderSource(t, map[string][]string{
+		"foo": {"1.0.0"},
+		"bar": {"2.0.0"},
+		"baz": {"1.2.2"},
+	})
+	defer close()
+	m := Meta{
+		testingOverrides: metaOverridesForProvider(testProvider()),
+		Ui:               initUi,
+		ProviderSource:   providerSource,
+	}
+	ic := &InitCommand{
+		Meta: m,
+	}
+	if code := ic.Run([]string{}); code != 0 {
+		t.Fatalf("init failed\n%s", initUi.ErrorWriter)
+	}
+
+	// Providers command
+	ui := new(cli.MockUi)
+	c := &ProvidersCommand{
+		Meta: Meta{
+			Ui: ui,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	wantOutput := []string{
+		"provider[registry.terraform.io/hashicorp/foo] 1.0.0", // from required_providers
+		"provider[registry.terraform.io/hashicorp/bar] 2.0.0", // from provider config
+		"── module.kiddo",                               // tree node for child module
+		"provider[registry.terraform.io/hashicorp/baz]", // implied by a resource in the child module
+	}
+
+	output := ui.OutputWriter.String()
+	for _, want := range wantOutput {
+		if !strings.Contains(output, want) {
+			t.Errorf("output missing %s:\n%s", want, output)
+		}
+	}
+}
+
+func TestProviders_state(t *testing.T) {
+	cwd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if err := os.Chdir(testFixturePath("providers/state")); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer os.Chdir(cwd)
+
+	ui := new(cli.MockUi)
+	c := &ProvidersCommand{
+		Meta: Meta{
+			Ui: ui,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	wantOutput := []string{
+		"provider[registry.terraform.io/hashicorp/foo] 1.0.0", // from required_providers
+		"provider[registry.terraform.io/hashicorp/bar] 2.0.0", // from a provider config block
+		"Providers required by state",                         // header for state providers
+		"provider[registry.terraform.io/hashicorp/baz]",       // from a resouce in state (only)
+	}
+
+	output := ui.OutputWriter.String()
+	for _, want := range wantOutput {
+		if !strings.Contains(output, want) {
+			t.Errorf("output missing %s:\n%s", want, output)
+		}
+	}
+}
diff --git a/v1.5.7/internal/command/push.go b/v1.5.7/internal/command/push.go
new file mode 100644
index 0000000..8b434e1
--- /dev/null
+++ b/v1.5.7/internal/command/push.go
@@ -0,0 +1,39 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+type PushCommand struct {
+	Meta
+}
+
+func (c *PushCommand) Run(args []string) int {
+	// This command is no longer supported, but we'll retain it just to
+	// give the user some next-steps after upgrading.
+	c.showDiagnostics(tfdiags.Sourceless(
+		tfdiags.Error,
+		"Command \"terraform push\" is no longer supported",
+		"This command was used to push configuration to Terraform Enterprise legacy (v1), which has now reached end-of-life. To push configuration to Terraform Enterprise v2, use its REST API. Contact Terraform Enterprise support for more information.",
+	))
+	return 1
+}
+
+func (c *PushCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] push [options] [DIR]
+
+  This command was for the legacy version of Terraform Enterprise (v1), which
+  has now reached end-of-life. Therefore this command is no longer supported.
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *PushCommand) Synopsis() string {
+	return "Obsolete command for Terraform Enterprise legacy (v1)"
+}
diff --git a/v1.5.7/internal/command/refresh.go b/v1.5.7/internal/command/refresh.go
new file mode 100644
index 0000000..7798eab
--- /dev/null
+++ b/v1.5.7/internal/command/refresh.go
@@ -0,0 +1,230 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// RefreshCommand is a cli.Command implementation that refreshes the state
+// file.
+type RefreshCommand struct {
+	Meta
+}
+
+func (c *RefreshCommand) Run(rawArgs []string) int {
+	var diags tfdiags.Diagnostics
+
+	// Parse and apply global view arguments
+	common, rawArgs := arguments.ParseView(rawArgs)
+	c.View.Configure(common)
+
+	// Propagate -no-color for legacy use of Ui.  The remote backend and
+	// cloud package use this; it should be removed when/if they are
+	// migrated to views.
+	c.Meta.color = !common.NoColor
+	c.Meta.Color = c.Meta.color
+
+	// Parse and validate flags
+	args, diags := arguments.ParseRefresh(rawArgs)
+
+	// Instantiate the view, even if there are flag errors, so that we render
+	// diagnostics according to the desired view
+	view := views.NewRefresh(args.ViewType, c.View)
+
+	if diags.HasErrors() {
+		view.Diagnostics(diags)
+		view.HelpPrompt()
+		return 1
+	}
+
+	// Check for user-supplied plugin path
+	var err error
+	if c.pluginPath, err = c.loadPluginPath(); err != nil {
+		diags = diags.Append(err)
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	// FIXME: the -input flag value is needed to initialize the backend and the
+	// operation, but there is no clear path to pass this value down, so we
+	// continue to mutate the Meta object state for now.
+	c.Meta.input = args.InputEnabled
+
+	// FIXME: the -parallelism flag is used to control the concurrency of
+	// Terraform operations. At the moment, this value is used both to
+	// initialize the backend via the ContextOpts field inside CLIOpts, and to
+	// set a largely unused field on the Operation request. Again, there is no
+	// clear path to pass this value down, so we continue to mutate the Meta
+	// object state for now.
+	c.Meta.parallelism = args.Operation.Parallelism
+
+	// Prepare the backend with the backend-specific arguments
+	be, beDiags := c.PrepareBackend(args.State, args.ViewType)
+	diags = diags.Append(beDiags)
+	if diags.HasErrors() {
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	// Build the operation request
+	opReq, opDiags := c.OperationRequest(be, view, args.ViewType, args.Operation)
+	diags = diags.Append(opDiags)
+	if diags.HasErrors() {
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	// Collect variable value and add them to the operation request
+	diags = diags.Append(c.GatherVariables(opReq, args.Vars))
+	if diags.HasErrors() {
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	// Before we delegate to the backend, we'll print any warning diagnostics
+	// we've accumulated here, since the backend will start fresh with its own
+	// diagnostics.
+	view.Diagnostics(diags)
+	diags = nil
+
+	// Perform the operation
+	op, err := c.RunOperation(be, opReq)
+	if err != nil {
+		diags = diags.Append(err)
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	if op.State != nil {
+		view.Outputs(op.State.RootModule().OutputValues)
+	}
+
+	return op.Result.ExitStatus()
+}
+
+func (c *RefreshCommand) PrepareBackend(args *arguments.State, viewType arguments.ViewType) (backend.Enhanced, tfdiags.Diagnostics) {
+	// FIXME: we need to apply the state arguments to the meta object here
+	// because they are later used when initializing the backend. Carving a
+	// path to pass these arguments to the functions that need them is
+	// difficult but would make their use easier to understand.
+	c.Meta.applyStateArguments(args)
+
+	backendConfig, diags := c.loadBackendConfig(".")
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	// Load the backend
+	be, beDiags := c.Backend(&BackendOpts{
+		Config:   backendConfig,
+		ViewType: viewType,
+	})
+	diags = diags.Append(beDiags)
+	if beDiags.HasErrors() {
+		return nil, diags
+	}
+
+	return be, diags
+}
+
+func (c *RefreshCommand) OperationRequest(be backend.Enhanced, view views.Refresh, viewType arguments.ViewType, args *arguments.Operation,
+) (*backend.Operation, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// Build the operation
+	opReq := c.Operation(be, viewType)
+	opReq.ConfigDir = "."
+	opReq.Hooks = view.Hooks()
+	opReq.Targets = args.Targets
+	opReq.Type = backend.OperationTypeRefresh
+	opReq.View = view.Operation()
+
+	var err error
+	opReq.ConfigLoader, err = c.initConfigLoader()
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("Failed to initialize config loader: %s", err))
+		return nil, diags
+	}
+
+	return opReq, diags
+}
+
+func (c *RefreshCommand) GatherVariables(opReq *backend.Operation, args *arguments.Vars) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	// FIXME the arguments package currently trivially gathers variable related
+	// arguments in a heterogenous slice, in order to minimize the number of
+	// code paths gathering variables during the transition to this structure.
+	// Once all commands that gather variables have been converted to this
+	// structure, we could move the variable gathering code to the arguments
+	// package directly, removing this shim layer.
+
+	varArgs := args.All()
+	items := make([]rawFlag, len(varArgs))
+	for i := range varArgs {
+		items[i].Name = varArgs[i].Name
+		items[i].Value = varArgs[i].Value
+	}
+	c.Meta.variableArgs = rawFlags{items: &items}
+	opReq.Variables, diags = c.collectVariableValues()
+
+	return diags
+}
+
+func (c *RefreshCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] refresh [options]
+
+  Update the state file of your infrastructure with metadata that matches
+  the physical resources they are tracking.
+
+  This will not modify your infrastructure, but it can modify your
+  state file to update metadata. This metadata might cause new changes
+  to occur when you generate a plan or call apply next.
+
+Options:
+
+  -compact-warnings   If Terraform produces any warnings that are not
+                      accompanied by errors, show them in a more compact form
+                      that includes only the summary messages.
+
+  -input=true         Ask for input for variables if not directly set.
+
+  -lock=false         Don't hold a state lock during the operation. This is
+                      dangerous if others might concurrently run commands
+                      against the same workspace.
+
+  -lock-timeout=0s    Duration to retry a state lock.
+
+  -no-color           If specified, output won't contain any color.
+
+  -parallelism=n      Limit the number of concurrent operations. Defaults to 10.
+
+  -target=resource    Resource to target. Operation will be limited to this
+                      resource and its dependencies. This flag can be used
+                      multiple times.
+
+  -var 'foo=bar'      Set a variable in the Terraform configuration. This
+                      flag can be set multiple times.
+
+  -var-file=foo       Set variables in the Terraform configuration from
+                      a file. If "terraform.tfvars" or any ".auto.tfvars"
+                      files are present, they will be automatically loaded.
+
+  -state, state-out, and -backup are legacy options supported for the local
+  backend only. For more information, see the local backend's documentation.
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *RefreshCommand) Synopsis() string {
+	return "Update the state to match remote systems"
+}
diff --git a/v1.5.7/internal/command/refresh_test.go b/v1.5.7/internal/command/refresh_test.go
new file mode 100644
index 0000000..df5c831
--- /dev/null
+++ b/v1.5.7/internal/command/refresh_test.go
@@ -0,0 +1,978 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"reflect"
+	"strings"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/mitchellh/cli"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+var equateEmpty = cmpopts.EquateEmpty()
+
+func TestRefresh(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("refresh"), td)
+	defer testChdir(t, td)()
+
+	state := testState()
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &RefreshCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	p.GetProviderSchemaResponse = refreshFixtureSchema()
+	p.ReadResourceFn = nil
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"id": cty.StringVal("yes"),
+		}),
+	}
+
+	args := []string{
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if !p.ReadResourceCalled {
+		t.Fatal("ReadResource should have been called")
+	}
+
+	f, err := os.Open(statePath)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	newStateFile, err := statefile.Read(f)
+	f.Close()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(newStateFile.State.String())
+	expected := strings.TrimSpace(testRefreshStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+func TestRefresh_empty(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("refresh-empty"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &RefreshCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	p.ReadResourceFn = nil
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"id": cty.StringVal("yes"),
+		}),
+	}
+
+	args := []string{}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if p.ReadResourceCalled {
+		t.Fatal("ReadResource should not have been called")
+	}
+}
+
+func TestRefresh_lockedState(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("refresh"), td)
+	defer testChdir(t, td)()
+
+	state := testState()
+	statePath := testStateFile(t, state)
+
+	unlock, err := testLockState(t, testDataDir, statePath)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer unlock()
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &RefreshCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	p.GetProviderSchemaResponse = refreshFixtureSchema()
+	p.ReadResourceFn = nil
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"id": cty.StringVal("yes"),
+		}),
+	}
+
+	args := []string{
+		"-state", statePath,
+	}
+
+	code := c.Run(args)
+	output := done(t)
+	if code == 0 {
+		t.Fatal("expected error")
+	}
+
+	got := output.Stderr()
+	if !strings.Contains(got, "lock") {
+		t.Fatal("command output does not look like a lock error:", got)
+	}
+}
+
+func TestRefresh_cwd(t *testing.T) {
+	cwd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if err := os.Chdir(testFixturePath("refresh")); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer os.Chdir(cwd)
+
+	state := testState()
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &RefreshCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	p.GetProviderSchemaResponse = refreshFixtureSchema()
+	p.ReadResourceFn = nil
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"id": cty.StringVal("yes"),
+		}),
+	}
+
+	args := []string{
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if !p.ReadResourceCalled {
+		t.Fatal("ReadResource should have been called")
+	}
+
+	f, err := os.Open(statePath)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	newStateFile, err := statefile.Read(f)
+	f.Close()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(newStateFile.State.String())
+	expected := strings.TrimSpace(testRefreshCwdStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+func TestRefresh_defaultState(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("refresh"), td)
+	defer testChdir(t, td)()
+
+	originalState := testState()
+
+	// Write the state file in a temporary directory with the
+	// default filename.
+	statePath := testStateFile(t, originalState)
+
+	localState := statemgr.NewFilesystem(statePath)
+	if err := localState.RefreshState(); err != nil {
+		t.Fatal(err)
+	}
+	s := localState.State()
+	if s == nil {
+		t.Fatal("empty test state")
+	}
+
+	// Change to that directory
+	cwd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if err := os.Chdir(filepath.Dir(statePath)); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer os.Chdir(cwd)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &RefreshCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	p.GetProviderSchemaResponse = refreshFixtureSchema()
+	p.ReadResourceFn = nil
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"id": cty.StringVal("yes"),
+		}),
+	}
+
+	args := []string{
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if !p.ReadResourceCalled {
+		t.Fatal("ReadResource should have been called")
+	}
+
+	newState := testStateRead(t, statePath)
+
+	actual := newState.RootModule().Resources["test_instance.foo"].Instances[addrs.NoKey].Current
+	expected := &states.ResourceInstanceObjectSrc{
+		Status:       states.ObjectReady,
+		AttrsJSON:    []byte("{\n            \"ami\": null,\n            \"id\": \"yes\"\n          }"),
+		Dependencies: []addrs.ConfigResource{},
+	}
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("wrong new object\ngot:  %swant: %s", spew.Sdump(actual), spew.Sdump(expected))
+	}
+
+	backupState := testStateRead(t, statePath+DefaultBackupExtension)
+
+	actual = backupState.RootModule().Resources["test_instance.foo"].Instances[addrs.NoKey].Current
+	expected = originalState.RootModule().Resources["test_instance.foo"].Instances[addrs.NoKey].Current
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("wrong new object\ngot:  %swant: %s", spew.Sdump(actual), spew.Sdump(expected))
+	}
+}
+
+func TestRefresh_outPath(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("refresh"), td)
+	defer testChdir(t, td)()
+
+	state := testState()
+	statePath := testStateFile(t, state)
+
+	// Output path
+	outf, err := ioutil.TempFile(td, "tf")
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	outPath := outf.Name()
+	outf.Close()
+	os.Remove(outPath)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &RefreshCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	p.GetProviderSchemaResponse = refreshFixtureSchema()
+	p.ReadResourceFn = nil
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"id": cty.StringVal("yes"),
+		}),
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-state-out", outPath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	newState := testStateRead(t, statePath)
+	if !reflect.DeepEqual(newState, state) {
+		t.Fatalf("bad: %#v", newState)
+	}
+
+	newState = testStateRead(t, outPath)
+	actual := newState.RootModule().Resources["test_instance.foo"].Instances[addrs.NoKey].Current
+	expected := &states.ResourceInstanceObjectSrc{
+		Status:       states.ObjectReady,
+		AttrsJSON:    []byte("{\n            \"ami\": null,\n            \"id\": \"yes\"\n          }"),
+		Dependencies: []addrs.ConfigResource{},
+	}
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("wrong new object\ngot:  %swant: %s", spew.Sdump(actual), spew.Sdump(expected))
+	}
+
+	if _, err := os.Stat(outPath + DefaultBackupExtension); !os.IsNotExist(err) {
+		if err != nil {
+			t.Fatalf("failed to test for backup file: %s", err)
+		}
+		t.Fatalf("backup file exists, but it should not because output file did not initially exist")
+	}
+}
+
+func TestRefresh_var(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("refresh-var"), td)
+	defer testChdir(t, td)()
+
+	state := testState()
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &RefreshCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+	p.GetProviderSchemaResponse = refreshVarFixtureSchema()
+
+	args := []string{
+		"-var", "foo=bar",
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if !p.ConfigureProviderCalled {
+		t.Fatal("configure should be called")
+	}
+	if got, want := p.ConfigureProviderRequest.Config.GetAttr("value"), cty.StringVal("bar"); !want.RawEquals(got) {
+		t.Fatalf("wrong provider configuration\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestRefresh_varFile(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("refresh-var"), td)
+	defer testChdir(t, td)()
+
+	state := testState()
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &RefreshCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+	p.GetProviderSchemaResponse = refreshVarFixtureSchema()
+
+	varFilePath := testTempFile(t)
+	if err := ioutil.WriteFile(varFilePath, []byte(refreshVarFile), 0644); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	args := []string{
+		"-var-file", varFilePath,
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if !p.ConfigureProviderCalled {
+		t.Fatal("configure should be called")
+	}
+	if got, want := p.ConfigureProviderRequest.Config.GetAttr("value"), cty.StringVal("bar"); !want.RawEquals(got) {
+		t.Fatalf("wrong provider configuration\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestRefresh_varFileDefault(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("refresh-var"), td)
+	defer testChdir(t, td)()
+
+	state := testState()
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &RefreshCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+	p.GetProviderSchemaResponse = refreshVarFixtureSchema()
+
+	varFilePath := filepath.Join(td, "terraform.tfvars")
+	if err := ioutil.WriteFile(varFilePath, []byte(refreshVarFile), 0644); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	args := []string{
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	if !p.ConfigureProviderCalled {
+		t.Fatal("configure should be called")
+	}
+	if got, want := p.ConfigureProviderRequest.Config.GetAttr("value"), cty.StringVal("bar"); !want.RawEquals(got) {
+		t.Fatalf("wrong provider configuration\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestRefresh_varsUnset(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("refresh-unset-var"), td)
+	defer testChdir(t, td)()
+
+	// Disable test mode so input would be asked
+	test = false
+	defer func() { test = true }()
+
+	defaultInputReader = bytes.NewBufferString("bar\n")
+
+	state := testState()
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, done := testView(t)
+	c := &RefreshCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":  {Type: cty.String, Optional: true, Computed: true},
+						"ami": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+}
+
+func TestRefresh_backup(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("refresh"), td)
+	defer testChdir(t, td)()
+
+	state := testState()
+	statePath := testStateFile(t, state)
+
+	// Output path
+	outf, err := ioutil.TempFile(td, "tf")
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	outPath := outf.Name()
+	defer outf.Close()
+
+	// Need to put some state content in the output file so that there's
+	// something to back up.
+	err = statefile.Write(statefile.New(state, "baz", 0), outf)
+	if err != nil {
+		t.Fatalf("error writing initial output state file %s", err)
+	}
+
+	// Backup path
+	backupf, err := ioutil.TempFile(td, "tf")
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	backupPath := backupf.Name()
+	backupf.Close()
+	os.Remove(backupPath)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &RefreshCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	p.GetProviderSchemaResponse = refreshFixtureSchema()
+	p.ReadResourceFn = nil
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"id": cty.StringVal("changed"),
+		}),
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-state-out", outPath,
+		"-backup", backupPath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	newState := testStateRead(t, statePath)
+	if !cmp.Equal(newState, state, cmpopts.EquateEmpty()) {
+		t.Fatalf("got:\n%s\nexpected:\n%s\n", newState, state)
+	}
+
+	newState = testStateRead(t, outPath)
+	actual := newState.RootModule().Resources["test_instance.foo"].Instances[addrs.NoKey].Current
+	expected := &states.ResourceInstanceObjectSrc{
+		Status:       states.ObjectReady,
+		AttrsJSON:    []byte("{\n            \"ami\": null,\n            \"id\": \"changed\"\n          }"),
+		Dependencies: []addrs.ConfigResource{},
+	}
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("wrong new object\ngot:  %swant: %s", spew.Sdump(actual), spew.Sdump(expected))
+	}
+
+	backupState := testStateRead(t, backupPath)
+	actualStr := strings.TrimSpace(backupState.String())
+	expectedStr := strings.TrimSpace(state.String())
+	if actualStr != expectedStr {
+		t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr)
+	}
+}
+
+func TestRefresh_disableBackup(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("refresh"), td)
+	defer testChdir(t, td)()
+
+	state := testState()
+	statePath := testStateFile(t, state)
+
+	// Output path
+	outf, err := ioutil.TempFile(td, "tf")
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	outPath := outf.Name()
+	outf.Close()
+	os.Remove(outPath)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &RefreshCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	p.GetProviderSchemaResponse = refreshFixtureSchema()
+	p.ReadResourceFn = nil
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"id": cty.StringVal("yes"),
+		}),
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-state-out", outPath,
+		"-backup", "-",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	newState := testStateRead(t, statePath)
+	if !cmp.Equal(state, newState, equateEmpty) {
+		spew.Config.DisableMethods = true
+		fmt.Println(cmp.Diff(state, newState, equateEmpty))
+		t.Fatalf("bad: %s", newState)
+	}
+
+	newState = testStateRead(t, outPath)
+	actual := newState.RootModule().Resources["test_instance.foo"].Instances[addrs.NoKey].Current
+	expected := &states.ResourceInstanceObjectSrc{
+		Status:       states.ObjectReady,
+		AttrsJSON:    []byte("{\n            \"ami\": null,\n            \"id\": \"yes\"\n          }"),
+		Dependencies: []addrs.ConfigResource{},
+	}
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("wrong new object\ngot:  %swant: %s", spew.Sdump(actual), spew.Sdump(expected))
+	}
+
+	// Ensure there is no backup
+	_, err = os.Stat(outPath + DefaultBackupExtension)
+	if err == nil || !os.IsNotExist(err) {
+		t.Fatalf("backup should not exist")
+	}
+	_, err = os.Stat("-")
+	if err == nil || !os.IsNotExist(err) {
+		t.Fatalf("backup should not exist")
+	}
+}
+
+func TestRefresh_displaysOutputs(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("refresh-output"), td)
+	defer testChdir(t, td)()
+
+	state := testState()
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	view, done := testView(t)
+	c := &RefreshCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":  {Type: cty.String, Optional: true, Computed: true},
+						"ami": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// Test that outputs were displayed
+	outputValue := "foo.example.com"
+	actual := output.Stdout()
+	if !strings.Contains(actual, outputValue) {
+		t.Fatalf("Expected:\n%s\n\nTo include: %q", actual, outputValue)
+	}
+}
+
+// Config with multiple resources, targeting refresh of a subset
+func TestRefresh_targeted(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("refresh-targeted"), td)
+	defer testChdir(t, td)()
+
+	state := testState()
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Computed: true},
+					},
+				},
+			},
+		},
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+
+	view, done := testView(t)
+	c := &RefreshCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-target", "test_instance.foo",
+		"-state", statePath,
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	got := output.Stdout()
+	if want := "test_instance.foo: Refreshing"; !strings.Contains(got, want) {
+		t.Fatalf("expected output to contain %q, got:\n%s", want, got)
+	}
+	if doNotWant := "test_instance.bar: Refreshing"; strings.Contains(got, doNotWant) {
+		t.Fatalf("expected output not to contain %q, got:\n%s", doNotWant, got)
+	}
+}
+
+// Diagnostics for invalid -target flags
+func TestRefresh_targetFlagsDiags(t *testing.T) {
+	testCases := map[string]string{
+		"test_instance.": "Dot must be followed by attribute name.",
+		"test_instance":  "Resource specification must include a resource type and name.",
+	}
+
+	for target, wantDiag := range testCases {
+		t.Run(target, func(t *testing.T) {
+			td := testTempDir(t)
+			defer os.RemoveAll(td)
+			defer testChdir(t, td)()
+
+			view, done := testView(t)
+			c := &RefreshCommand{
+				Meta: Meta{
+					View: view,
+				},
+			}
+
+			args := []string{
+				"-target", target,
+			}
+			code := c.Run(args)
+			output := done(t)
+			if code != 1 {
+				t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+			}
+
+			got := output.Stderr()
+			if !strings.Contains(got, target) {
+				t.Fatalf("bad error output, want %q, got:\n%s", target, got)
+			}
+			if !strings.Contains(got, wantDiag) {
+				t.Fatalf("bad error output, want %q, got:\n%s", wantDiag, got)
+			}
+		})
+	}
+}
+
+func TestRefresh_warnings(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("apply"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = refreshFixtureSchema()
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+			Diagnostics: tfdiags.Diagnostics{
+				tfdiags.SimpleWarning("warning 1"),
+				tfdiags.SimpleWarning("warning 2"),
+			},
+		}
+	}
+
+	t.Run("full warnings", func(t *testing.T) {
+		view, done := testView(t)
+		c := &RefreshCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				View:             view,
+			},
+		}
+
+		code := c.Run([]string{})
+		output := done(t)
+		if code != 0 {
+			t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+		}
+		wantWarnings := []string{
+			"warning 1",
+			"warning 2",
+		}
+		for _, want := range wantWarnings {
+			if !strings.Contains(output.Stdout(), want) {
+				t.Errorf("missing warning %s", want)
+			}
+		}
+	})
+
+	t.Run("compact warnings", func(t *testing.T) {
+		view, done := testView(t)
+		c := &RefreshCommand{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				View:             view,
+			},
+		}
+
+		code := c.Run([]string{"-compact-warnings"})
+		output := done(t)
+		if code != 0 {
+			t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+		}
+		// the output should contain 2 warnings and a message about -compact-warnings
+		wantWarnings := []string{
+			"warning 1",
+			"warning 2",
+			"To see the full warning notes, run Terraform without -compact-warnings.",
+		}
+		for _, want := range wantWarnings {
+			if !strings.Contains(output.Stdout(), want) {
+				t.Errorf("missing warning %s", want)
+			}
+		}
+	})
+}
+
+// configuration in testdata/refresh . This schema should be
+// assigned to a mock provider named "test".
+func refreshFixtureSchema() *providers.GetProviderSchemaResponse {
+	return &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":  {Type: cty.String, Optional: true, Computed: true},
+						"ami": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+}
+
+// refreshVarFixtureSchema returns a schema suitable for processing the
+// configuration in testdata/refresh-var . This schema should be
+// assigned to a mock provider named "test".
+func refreshVarFixtureSchema() *providers.GetProviderSchemaResponse {
+	return &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"value": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Optional: true, Computed: true},
+					},
+				},
+			},
+		},
+	}
+}
+
+const refreshVarFile = `
+foo = "bar"
+`
+
+const testRefreshStr = `
+test_instance.foo:
+  ID = yes
+  provider = provider["registry.terraform.io/hashicorp/test"]
+`
+const testRefreshCwdStr = `
+test_instance.foo:
+  ID = yes
+  provider = provider["registry.terraform.io/hashicorp/test"]
+`
diff --git a/v1.5.7/internal/command/show.go b/v1.5.7/internal/command/show.go
new file mode 100644
index 0000000..3b83a3c
--- /dev/null
+++ b/v1.5.7/internal/command/show.go
@@ -0,0 +1,241 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"os"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ShowCommand is a Command implementation that reads and outputs the
+// contents of a Terraform plan or state file.
+type ShowCommand struct {
+	Meta
+}
+
+func (c *ShowCommand) Run(rawArgs []string) int {
+	// Parse and apply global view arguments
+	common, rawArgs := arguments.ParseView(rawArgs)
+	c.View.Configure(common)
+
+	// Parse and validate flags
+	args, diags := arguments.ParseShow(rawArgs)
+	if diags.HasErrors() {
+		c.View.Diagnostics(diags)
+		c.View.HelpPrompt("show")
+		return 1
+	}
+
+	// Set up view
+	view := views.NewShow(args.ViewType, c.View)
+
+	// Check for user-supplied plugin path
+	var err error
+	if c.pluginPath, err = c.loadPluginPath(); err != nil {
+		diags = diags.Append(fmt.Errorf("error loading plugin path: %s", err))
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	// Get the data we need to display
+	plan, stateFile, config, schemas, showDiags := c.show(args.Path)
+	diags = diags.Append(showDiags)
+	if showDiags.HasErrors() {
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	// Display the data
+	return view.Display(config, plan, stateFile, schemas)
+}
+
+func (c *ShowCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] show [options] [path]
+
+  Reads and outputs a Terraform state or plan file in a human-readable
+  form. If no path is specified, the current state will be shown.
+
+Options:
+
+  -no-color           If specified, output won't contain any color.
+  -json               If specified, output the Terraform plan or state in
+                      a machine-readable form.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *ShowCommand) Synopsis() string {
+	return "Show the current state or a saved plan"
+}
+
+func (c *ShowCommand) show(path string) (*plans.Plan, *statefile.File, *configs.Config, *terraform.Schemas, tfdiags.Diagnostics) {
+	var diags, showDiags tfdiags.Diagnostics
+	var plan *plans.Plan
+	var stateFile *statefile.File
+	var config *configs.Config
+	var schemas *terraform.Schemas
+
+	// No plan file or state file argument provided,
+	// so get the latest state snapshot
+	if path == "" {
+		stateFile, showDiags = c.showFromLatestStateSnapshot()
+		diags = diags.Append(showDiags)
+		if showDiags.HasErrors() {
+			return plan, stateFile, config, schemas, diags
+		}
+	}
+
+	// Plan file or state file argument provided,
+	// so try to load the argument as a plan file first.
+	// If that fails, try to load it as a statefile.
+	if path != "" {
+		plan, stateFile, config, showDiags = c.showFromPath(path)
+		diags = diags.Append(showDiags)
+		if showDiags.HasErrors() {
+			return plan, stateFile, config, schemas, diags
+		}
+	}
+
+	// Get schemas, if possible
+	if config != nil || stateFile != nil {
+		schemas, diags = c.MaybeGetSchemas(stateFile.State, config)
+		if diags.HasErrors() {
+			return plan, stateFile, config, schemas, diags
+		}
+	}
+
+	return plan, stateFile, config, schemas, diags
+}
+func (c *ShowCommand) showFromLatestStateSnapshot() (*statefile.File, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// Load the backend
+	b, backendDiags := c.Backend(nil)
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		return nil, diags
+	}
+	c.ignoreRemoteVersionConflict(b)
+
+	// Load the workspace
+	workspace, err := c.Workspace()
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("error selecting workspace: %s", err))
+		return nil, diags
+	}
+
+	// Get the latest state snapshot from the backend for the current workspace
+	stateFile, stateErr := getStateFromBackend(b, workspace)
+	if stateErr != nil {
+		diags = diags.Append(stateErr)
+		return nil, diags
+	}
+
+	return stateFile, diags
+}
+
+func (c *ShowCommand) showFromPath(path string) (*plans.Plan, *statefile.File, *configs.Config, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	var planErr, stateErr error
+	var plan *plans.Plan
+	var stateFile *statefile.File
+	var config *configs.Config
+
+	// Try to get the plan file and associated data from
+	// the path argument. If that fails, try to get the
+	// statefile from the path argument.
+	plan, stateFile, config, planErr = getPlanFromPath(path)
+	if planErr != nil {
+		stateFile, stateErr = getStateFromPath(path)
+		if stateErr != nil {
+			diags = diags.Append(
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to read the given file as a state or plan file",
+					fmt.Sprintf("State read error: %s\n\nPlan read error: %s", stateErr, planErr),
+				),
+			)
+			return nil, nil, nil, diags
+		}
+	}
+	return plan, stateFile, config, diags
+}
+
+// getPlanFromPath returns a plan, statefile, and config if the user-supplied
+// path points to a plan file. If both plan and error are nil, the path is likely
+// a directory. An error could suggest that the given path points to a statefile.
+func getPlanFromPath(path string) (*plans.Plan, *statefile.File, *configs.Config, error) {
+	planReader, err := planfile.Open(path)
+	if err != nil {
+		return nil, nil, nil, err
+	}
+
+	// Get plan
+	plan, err := planReader.ReadPlan()
+	if err != nil {
+		return nil, nil, nil, err
+	}
+
+	// Get statefile
+	stateFile, err := planReader.ReadStateFile()
+	if err != nil {
+		return nil, nil, nil, err
+	}
+
+	// Get config
+	config, diags := planReader.ReadConfig()
+	if diags.HasErrors() {
+		return nil, nil, nil, diags.Err()
+	}
+
+	return plan, stateFile, config, err
+}
+
+// getStateFromPath returns a statefile if the user-supplied path points to a statefile.
+func getStateFromPath(path string) (*statefile.File, error) {
+	file, err := os.Open(path)
+	if err != nil {
+		return nil, fmt.Errorf("Error loading statefile: %s", err)
+	}
+	defer file.Close()
+
+	var stateFile *statefile.File
+	stateFile, err = statefile.Read(file)
+	if err != nil {
+		return nil, fmt.Errorf("Error reading %s as a statefile: %s", path, err)
+	}
+	return stateFile, nil
+}
+
+// getStateFromBackend returns the State for the current workspace, if available.
+func getStateFromBackend(b backend.Backend, workspace string) (*statefile.File, error) {
+	// Get the state store for the given workspace
+	stateStore, err := b.StateMgr(workspace)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to load state manager: %s", err)
+	}
+
+	// Refresh the state store with the latest state snapshot from persistent storage
+	if err := stateStore.RefreshState(); err != nil {
+		return nil, fmt.Errorf("Failed to load state: %s", err)
+	}
+
+	// Get the latest state snapshot and return it
+	stateFile := statemgr.Export(stateStore)
+	return stateFile, nil
+}
diff --git a/v1.5.7/internal/command/show_test.go b/v1.5.7/internal/command/show_test.go
new file mode 100644
index 0000000..7ddeea0
--- /dev/null
+++ b/v1.5.7/internal/command/show_test.go
@@ -0,0 +1,1159 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/version"
+	"github.com/mitchellh/cli"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestShow_badArgs(t *testing.T) {
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"bad",
+		"bad",
+		"-no-color",
+	}
+
+	code := c.Run(args)
+	output := done(t)
+
+	if code != 1 {
+		t.Fatalf("unexpected exit status %d; want 1\ngot: %s", code, output.Stdout())
+	}
+}
+
+func TestShow_noArgsNoState(t *testing.T) {
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	code := c.Run([]string{})
+	output := done(t)
+
+	if code != 0 {
+		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr())
+	}
+
+	got := output.Stdout()
+	want := `No state.`
+	if !strings.Contains(got, want) {
+		t.Fatalf("unexpected output\ngot: %s\nwant: %s", got, want)
+	}
+}
+
+func TestShow_noArgsWithState(t *testing.T) {
+	// Get a temp cwd
+	testCwd(t)
+	// Create the default state
+	testStateFileDefault(t, testState())
+
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(showFixtureProvider()),
+			View:             view,
+		},
+	}
+
+	code := c.Run([]string{})
+	output := done(t)
+
+	if code != 0 {
+		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr())
+	}
+
+	got := output.Stdout()
+	want := `# test_instance.foo:`
+	if !strings.Contains(got, want) {
+		t.Fatalf("unexpected output\ngot: %s\nwant: %s", got, want)
+	}
+}
+
+func TestShow_argsWithState(t *testing.T) {
+	// Create the default state
+	statePath := testStateFile(t, testState())
+	stateDir := filepath.Dir(statePath)
+	defer os.RemoveAll(stateDir)
+	defer testChdir(t, stateDir)()
+
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(showFixtureProvider()),
+			View:             view,
+		},
+	}
+
+	path := filepath.Base(statePath)
+	args := []string{
+		path,
+		"-no-color",
+	}
+	code := c.Run(args)
+	output := done(t)
+
+	if code != 0 {
+		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr())
+	}
+}
+
+// https://github.com/hashicorp/terraform/issues/21462
+func TestShow_argsWithStateAliasedProvider(t *testing.T) {
+	// Create the default state with aliased resource
+	testState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				// The weird whitespace here is reflective of how this would
+				// get written out in a real state file, due to the indentation
+				// of all of the containing wrapping objects and arrays.
+				AttrsJSON:    []byte("{\n            \"id\": \"bar\"\n          }"),
+				Status:       states.ObjectReady,
+				Dependencies: []addrs.ConfigResource{},
+			},
+			addrs.RootModuleInstance.ProviderConfigAliased(addrs.NewDefaultProvider("test"), "alias"),
+		)
+	})
+
+	statePath := testStateFile(t, testState)
+	stateDir := filepath.Dir(statePath)
+	defer os.RemoveAll(stateDir)
+	defer testChdir(t, stateDir)()
+
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(showFixtureProvider()),
+			View:             view,
+		},
+	}
+
+	path := filepath.Base(statePath)
+	args := []string{
+		path,
+		"-no-color",
+	}
+	code := c.Run(args)
+	output := done(t)
+
+	if code != 0 {
+		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr())
+	}
+
+	got := output.Stdout()
+	want := `# missing schema for provider \"test.alias\"`
+	if strings.Contains(got, want) {
+		t.Fatalf("unexpected output\ngot: %s", got)
+	}
+}
+
+func TestShow_argsPlanFileDoesNotExist(t *testing.T) {
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"doesNotExist.tfplan",
+		"-no-color",
+	}
+	code := c.Run(args)
+	output := done(t)
+
+	if code != 1 {
+		t.Fatalf("unexpected exit status %d; want 1\ngot: %s", code, output.Stdout())
+	}
+
+	got := output.Stderr()
+	want := `Plan read error: open doesNotExist.tfplan:`
+	if !strings.Contains(got, want) {
+		t.Errorf("unexpected output\ngot: %s\nwant:\n%s", got, want)
+	}
+}
+
+func TestShow_argsStatefileDoesNotExist(t *testing.T) {
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"doesNotExist.tfstate",
+		"-no-color",
+	}
+	code := c.Run(args)
+	output := done(t)
+
+	if code != 1 {
+		t.Fatalf("unexpected exit status %d; want 1\ngot: %s", code, output.Stdout())
+	}
+
+	got := output.Stderr()
+	want := `State read error: Error loading statefile:`
+	if !strings.Contains(got, want) {
+		t.Errorf("unexpected output\ngot: %s\nwant:\n%s", got, want)
+	}
+}
+
+func TestShow_json_argsPlanFileDoesNotExist(t *testing.T) {
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-json",
+		"doesNotExist.tfplan",
+		"-no-color",
+	}
+	code := c.Run(args)
+	output := done(t)
+
+	if code != 1 {
+		t.Fatalf("unexpected exit status %d; want 1\ngot: %s", code, output.Stdout())
+	}
+
+	got := output.Stderr()
+	want := `Plan read error: open doesNotExist.tfplan:`
+	if !strings.Contains(got, want) {
+		t.Errorf("unexpected output\ngot: %s\nwant:\n%s", got, want)
+	}
+}
+
+func TestShow_json_argsStatefileDoesNotExist(t *testing.T) {
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-json",
+		"doesNotExist.tfstate",
+		"-no-color",
+	}
+	code := c.Run(args)
+	output := done(t)
+
+	if code != 1 {
+		t.Fatalf("unexpected exit status %d; want 1\ngot: %s", code, output.Stdout())
+	}
+
+	got := output.Stderr()
+	want := `State read error: Error loading statefile:`
+	if !strings.Contains(got, want) {
+		t.Errorf("unexpected output\ngot: %s\nwant:\n%s", got, want)
+	}
+}
+
+func TestShow_planNoop(t *testing.T) {
+	planPath := testPlanFileNoop(t)
+
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		planPath,
+		"-no-color",
+	}
+	code := c.Run(args)
+	output := done(t)
+
+	if code != 0 {
+		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr())
+	}
+
+	got := output.Stdout()
+	want := `No changes. Your infrastructure matches the configuration.`
+	if !strings.Contains(got, want) {
+		t.Errorf("unexpected output\ngot: %s\nwant:\n%s", got, want)
+	}
+}
+
+func TestShow_planWithChanges(t *testing.T) {
+	planPathWithChanges := showFixturePlanFile(t, plans.DeleteThenCreate)
+
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(showFixtureProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		planPathWithChanges,
+		"-no-color",
+	}
+	code := c.Run(args)
+	output := done(t)
+
+	if code != 0 {
+		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr())
+	}
+
+	got := output.Stdout()
+	want := `test_instance.foo must be replaced`
+	if !strings.Contains(got, want) {
+		t.Fatalf("unexpected output\ngot: %s\nwant: %s", got, want)
+	}
+}
+
+func TestShow_planWithForceReplaceChange(t *testing.T) {
+	// The main goal of this test is to see that the "replace by request"
+	// resource instance action reason can round-trip through a plan file and
+	// be reflected correctly in the "terraform show" output, the same way
+	// as it would appear in "terraform plan" output.
+
+	_, snap := testModuleWithSnapshot(t, "show")
+	plannedVal := cty.ObjectVal(map[string]cty.Value{
+		"id":  cty.UnknownVal(cty.String),
+		"ami": cty.StringVal("bar"),
+	})
+	priorValRaw, err := plans.NewDynamicValue(cty.NullVal(plannedVal.Type()), plannedVal.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	plannedValRaw, err := plans.NewDynamicValue(plannedVal, plannedVal.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	plan := testPlan(t)
+	plan.Changes.SyncWrapper().AppendResourceInstanceChange(&plans.ResourceInstanceChangeSrc{
+		Addr: addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: "foo",
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+		ProviderAddr: addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+		ChangeSrc: plans.ChangeSrc{
+			Action: plans.CreateThenDelete,
+			Before: priorValRaw,
+			After:  plannedValRaw,
+		},
+		ActionReason: plans.ResourceInstanceReplaceByRequest,
+	})
+	planFilePath := testPlanFile(
+		t,
+		snap,
+		states.NewState(),
+		plan,
+	)
+
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(showFixtureProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		planFilePath,
+		"-no-color",
+	}
+	code := c.Run(args)
+	output := done(t)
+
+	if code != 0 {
+		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr())
+	}
+
+	got := output.Stdout()
+	want := `test_instance.foo will be replaced, as requested`
+	if !strings.Contains(got, want) {
+		t.Fatalf("unexpected output\ngot: %s\nwant: %s", got, want)
+	}
+
+	want = `Plan: 1 to add, 0 to change, 1 to destroy.`
+	if !strings.Contains(got, want) {
+		t.Fatalf("unexpected output\ngot: %s\nwant: %s", got, want)
+	}
+
+}
+
+func TestShow_plan_json(t *testing.T) {
+	planPath := showFixturePlanFile(t, plans.Create)
+
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(showFixtureProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-json",
+		planPath,
+		"-no-color",
+	}
+	code := c.Run(args)
+	output := done(t)
+
+	if code != 0 {
+		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr())
+	}
+}
+
+func TestShow_state(t *testing.T) {
+	originalState := testState()
+	root := originalState.RootModule()
+	root.SetOutputValue("test", cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.NullVal(cty.DynamicPseudoType),
+		"null": cty.NullVal(cty.String),
+		"list": cty.ListVal([]cty.Value{cty.NullVal(cty.Number)}),
+	}), false)
+
+	statePath := testStateFile(t, originalState)
+	defer os.RemoveAll(filepath.Dir(statePath))
+
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(showFixtureProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		statePath,
+		"-no-color",
+	}
+	code := c.Run(args)
+	output := done(t)
+
+	if code != 0 {
+		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr())
+	}
+}
+
+func TestShow_json_output(t *testing.T) {
+	fixtureDir := "testdata/show-json"
+	testDirs, err := ioutil.ReadDir(fixtureDir)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, entry := range testDirs {
+		if !entry.IsDir() {
+			continue
+		}
+
+		t.Run(entry.Name(), func(t *testing.T) {
+			td := t.TempDir()
+			inputDir := filepath.Join(fixtureDir, entry.Name())
+			testCopyDir(t, inputDir, td)
+			defer testChdir(t, td)()
+
+			expectError := strings.Contains(entry.Name(), "error")
+
+			providerSource, close := newMockProviderSource(t, map[string][]string{
+				"test":            {"1.2.3"},
+				"hashicorp2/test": {"1.2.3"},
+			})
+			defer close()
+
+			p := showFixtureProvider()
+
+			// init
+			ui := new(cli.MockUi)
+			ic := &InitCommand{
+				Meta: Meta{
+					testingOverrides: metaOverridesForProvider(p),
+					Ui:               ui,
+					ProviderSource:   providerSource,
+				},
+			}
+			if code := ic.Run([]string{}); code != 0 {
+				if expectError {
+					// this should error, but not panic.
+					return
+				}
+				t.Fatalf("init failed\n%s", ui.ErrorWriter)
+			}
+
+			// plan
+			planView, planDone := testView(t)
+			pc := &PlanCommand{
+				Meta: Meta{
+					testingOverrides: metaOverridesForProvider(p),
+					View:             planView,
+					ProviderSource:   providerSource,
+				},
+			}
+
+			args := []string{
+				"-out=terraform.plan",
+			}
+
+			code := pc.Run(args)
+			planOutput := planDone(t)
+
+			if code != 0 {
+				t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, planOutput.Stderr())
+			}
+
+			// show
+			showView, showDone := testView(t)
+			sc := &ShowCommand{
+				Meta: Meta{
+					testingOverrides: metaOverridesForProvider(p),
+					View:             showView,
+					ProviderSource:   providerSource,
+				},
+			}
+
+			args = []string{
+				"-json",
+				"terraform.plan",
+			}
+			defer os.Remove("terraform.plan")
+			code = sc.Run(args)
+			showOutput := showDone(t)
+
+			if code != 0 {
+				t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, showOutput.Stderr())
+			}
+
+			// compare view output to wanted output
+			var got, want plan
+
+			gotString := showOutput.Stdout()
+			json.Unmarshal([]byte(gotString), &got)
+
+			wantFile, err := os.Open("output.json")
+			if err != nil {
+				t.Fatalf("unexpected err: %s", err)
+			}
+			defer wantFile.Close()
+			byteValue, err := ioutil.ReadAll(wantFile)
+			if err != nil {
+				t.Fatalf("unexpected err: %s", err)
+			}
+			json.Unmarshal([]byte(byteValue), &want)
+
+			// Disregard format version to reduce needless test fixture churn
+			want.FormatVersion = got.FormatVersion
+
+			if !cmp.Equal(got, want) {
+				t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, want))
+			}
+		})
+	}
+}
+
+func TestShow_json_output_sensitive(t *testing.T) {
+	td := t.TempDir()
+	inputDir := "testdata/show-json-sensitive"
+	testCopyDir(t, inputDir, td)
+	defer testChdir(t, td)()
+
+	providerSource, close := newMockProviderSource(t, map[string][]string{"test": {"1.2.3"}})
+	defer close()
+
+	p := showFixtureSensitiveProvider()
+
+	// init
+	ui := new(cli.MockUi)
+	ic := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			ProviderSource:   providerSource,
+		},
+	}
+	if code := ic.Run([]string{}); code != 0 {
+		t.Fatalf("init failed\n%s", ui.ErrorWriter)
+	}
+
+	// plan
+	planView, planDone := testView(t)
+	pc := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             planView,
+			ProviderSource:   providerSource,
+		},
+	}
+
+	args := []string{
+		"-out=terraform.plan",
+	}
+	code := pc.Run(args)
+	planOutput := planDone(t)
+
+	if code != 0 {
+		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, planOutput.Stderr())
+	}
+
+	// show
+	showView, showDone := testView(t)
+	sc := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             showView,
+			ProviderSource:   providerSource,
+		},
+	}
+
+	args = []string{
+		"-json",
+		"terraform.plan",
+	}
+	defer os.Remove("terraform.plan")
+	code = sc.Run(args)
+	showOutput := showDone(t)
+
+	if code != 0 {
+		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, showOutput.Stderr())
+	}
+
+	// compare ui output to wanted output
+	var got, want plan
+
+	gotString := showOutput.Stdout()
+	json.Unmarshal([]byte(gotString), &got)
+
+	wantFile, err := os.Open("output.json")
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	defer wantFile.Close()
+	byteValue, err := ioutil.ReadAll(wantFile)
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	json.Unmarshal([]byte(byteValue), &want)
+
+	// Disregard format version to reduce needless test fixture churn
+	want.FormatVersion = got.FormatVersion
+
+	if !cmp.Equal(got, want) {
+		t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, want))
+	}
+}
+
+// Failing conditions are only present in JSON output for refresh-only plans,
+// so we test that separately here.
+func TestShow_json_output_conditions_refresh_only(t *testing.T) {
+	td := t.TempDir()
+	inputDir := "testdata/show-json/conditions"
+	testCopyDir(t, inputDir, td)
+	defer testChdir(t, td)()
+
+	providerSource, close := newMockProviderSource(t, map[string][]string{"test": {"1.2.3"}})
+	defer close()
+
+	p := showFixtureSensitiveProvider()
+
+	// init
+	ui := new(cli.MockUi)
+	ic := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			ProviderSource:   providerSource,
+		},
+	}
+	if code := ic.Run([]string{}); code != 0 {
+		t.Fatalf("init failed\n%s", ui.ErrorWriter)
+	}
+
+	// plan
+	planView, planDone := testView(t)
+	pc := &PlanCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             planView,
+			ProviderSource:   providerSource,
+		},
+	}
+
+	args := []string{
+		"-refresh-only",
+		"-out=terraform.plan",
+		"-var=ami=bad-ami",
+		"-state=for-refresh.tfstate",
+	}
+	code := pc.Run(args)
+	planOutput := planDone(t)
+
+	if code != 0 {
+		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, planOutput.Stderr())
+	}
+
+	// show
+	showView, showDone := testView(t)
+	sc := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             showView,
+			ProviderSource:   providerSource,
+		},
+	}
+
+	args = []string{
+		"-json",
+		"terraform.plan",
+	}
+	defer os.Remove("terraform.plan")
+	code = sc.Run(args)
+	showOutput := showDone(t)
+
+	if code != 0 {
+		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, showOutput.Stderr())
+	}
+
+	// compare JSON output to wanted output
+	var got, want plan
+
+	gotString := showOutput.Stdout()
+	json.Unmarshal([]byte(gotString), &got)
+
+	wantFile, err := os.Open("output-refresh-only.json")
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	defer wantFile.Close()
+	byteValue, err := ioutil.ReadAll(wantFile)
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	json.Unmarshal([]byte(byteValue), &want)
+
+	// Disregard format version to reduce needless test fixture churn
+	want.FormatVersion = got.FormatVersion
+
+	if !cmp.Equal(got, want) {
+		t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, want))
+	}
+}
+
+// similar test as above, without the plan
+func TestShow_json_output_state(t *testing.T) {
+	fixtureDir := "testdata/show-json-state"
+	testDirs, err := ioutil.ReadDir(fixtureDir)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, entry := range testDirs {
+		if !entry.IsDir() {
+			continue
+		}
+
+		t.Run(entry.Name(), func(t *testing.T) {
+			td := t.TempDir()
+			inputDir := filepath.Join(fixtureDir, entry.Name())
+			testCopyDir(t, inputDir, td)
+			defer testChdir(t, td)()
+
+			providerSource, close := newMockProviderSource(t, map[string][]string{
+				"test": {"1.2.3"},
+			})
+			defer close()
+
+			p := showFixtureProvider()
+
+			// init
+			ui := new(cli.MockUi)
+			ic := &InitCommand{
+				Meta: Meta{
+					testingOverrides: metaOverridesForProvider(p),
+					Ui:               ui,
+					ProviderSource:   providerSource,
+				},
+			}
+			if code := ic.Run([]string{}); code != 0 {
+				t.Fatalf("init failed\n%s", ui.ErrorWriter)
+			}
+
+			// show
+			showView, showDone := testView(t)
+			sc := &ShowCommand{
+				Meta: Meta{
+					testingOverrides: metaOverridesForProvider(p),
+					View:             showView,
+					ProviderSource:   providerSource,
+				},
+			}
+
+			code := sc.Run([]string{"-json"})
+			showOutput := showDone(t)
+
+			if code != 0 {
+				t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, showOutput.Stderr())
+			}
+
+			// compare ui output to wanted output
+			type state struct {
+				FormatVersion    string                 `json:"format_version,omitempty"`
+				TerraformVersion string                 `json:"terraform_version"`
+				Values           map[string]interface{} `json:"values,omitempty"`
+				SensitiveValues  map[string]bool        `json:"sensitive_values,omitempty"`
+			}
+			var got, want state
+
+			gotString := showOutput.Stdout()
+			json.Unmarshal([]byte(gotString), &got)
+
+			wantFile, err := os.Open("output.json")
+			if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+			defer wantFile.Close()
+			byteValue, err := ioutil.ReadAll(wantFile)
+			if err != nil {
+				t.Fatalf("unexpected err: %s", err)
+			}
+			json.Unmarshal([]byte(byteValue), &want)
+
+			if !cmp.Equal(got, want) {
+				t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, want))
+			}
+		})
+	}
+}
+
+func TestShow_planWithNonDefaultStateLineage(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("show"), td)
+	defer testChdir(t, td)()
+
+	// Write default state file with a testing lineage ("fake-for-testing")
+	testStateFileDefault(t, testState())
+
+	// Create a plan with a different lineage, which we should still be able
+	// to show
+	_, snap := testModuleWithSnapshot(t, "show")
+	state := testState()
+	plan := testPlan(t)
+	stateMeta := statemgr.SnapshotMeta{
+		Lineage:          "fake-for-plan",
+		Serial:           1,
+		TerraformVersion: version.SemVer,
+	}
+	planPath := testPlanFileMatchState(t, snap, state, plan, stateMeta)
+
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{
+		planPath,
+		"-no-color",
+	}
+	code := c.Run(args)
+	output := done(t)
+
+	if code != 0 {
+		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr())
+	}
+
+	got := output.Stdout()
+	want := `No changes. Your infrastructure matches the configuration.`
+	if !strings.Contains(got, want) {
+		t.Fatalf("unexpected output\ngot: %s\nwant: %s", got, want)
+	}
+}
+
+func TestShow_corruptStatefile(t *testing.T) {
+	td := t.TempDir()
+	inputDir := "testdata/show-corrupt-statefile"
+	testCopyDir(t, inputDir, td)
+	defer testChdir(t, td)()
+
+	view, done := testView(t)
+	c := &ShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	code := c.Run([]string{})
+	output := done(t)
+
+	if code != 1 {
+		t.Fatalf("unexpected exit status %d; want 1\ngot: %s", code, output.Stdout())
+	}
+
+	got := output.Stderr()
+	want := `Unsupported state file format`
+	if !strings.Contains(got, want) {
+		t.Errorf("unexpected output\ngot: %s\nwant:\n%s", got, want)
+	}
+}
+
+// showFixtureSchema returns a schema suitable for processing the configuration
+// in testdata/show. This schema should be assigned to a mock provider
+// named "test".
+func showFixtureSchema() *providers.GetProviderSchemaResponse {
+	return &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"region": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":  {Type: cty.String, Optional: true, Computed: true},
+						"ami": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+}
+
+// showFixtureSensitiveSchema returns a schema suitable for processing the configuration
+// in testdata/show. This schema should be assigned to a mock provider
+// named "test". It includes a sensitive attribute.
+func showFixtureSensitiveSchema() *providers.GetProviderSchemaResponse {
+	return &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"region": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":       {Type: cty.String, Optional: true, Computed: true},
+						"ami":      {Type: cty.String, Optional: true},
+						"password": {Type: cty.String, Optional: true, Sensitive: true},
+					},
+				},
+			},
+		},
+	}
+}
+
+// showFixtureProvider returns a mock provider that is configured for basic
+// operation with the configuration in testdata/show. This mock has
+// GetSchemaResponse, PlanResourceChangeFn, and ApplyResourceChangeFn populated,
+// with the plan/apply steps just passing through the data determined by
+// Terraform Core.
+func showFixtureProvider() *terraform.MockProvider {
+	p := testProvider()
+	p.GetProviderSchemaResponse = showFixtureSchema()
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		idVal := req.PriorState.GetAttr("id")
+		amiVal := req.PriorState.GetAttr("ami")
+		if amiVal.RawEquals(cty.StringVal("refresh-me")) {
+			amiVal = cty.StringVal("refreshed")
+		}
+		return providers.ReadResourceResponse{
+			NewState: cty.ObjectVal(map[string]cty.Value{
+				"id":  idVal,
+				"ami": amiVal,
+			}),
+			Private: req.Private,
+		}
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		// this is a destroy plan,
+		if req.ProposedNewState.IsNull() {
+			resp.PlannedState = req.ProposedNewState
+			resp.PlannedPrivate = req.PriorPrivate
+			return resp
+		}
+
+		idVal := req.ProposedNewState.GetAttr("id")
+		amiVal := req.ProposedNewState.GetAttr("ami")
+		if idVal.IsNull() {
+			idVal = cty.UnknownVal(cty.String)
+		}
+		var reqRep []cty.Path
+		if amiVal.RawEquals(cty.StringVal("force-replace")) {
+			reqRep = append(reqRep, cty.GetAttrPath("ami"))
+		}
+		return providers.PlanResourceChangeResponse{
+			PlannedState: cty.ObjectVal(map[string]cty.Value{
+				"id":  idVal,
+				"ami": amiVal,
+			}),
+			RequiresReplace: reqRep,
+		}
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		idVal := req.PlannedState.GetAttr("id")
+		amiVal := req.PlannedState.GetAttr("ami")
+		if !idVal.IsKnown() {
+			idVal = cty.StringVal("placeholder")
+		}
+		return providers.ApplyResourceChangeResponse{
+			NewState: cty.ObjectVal(map[string]cty.Value{
+				"id":  idVal,
+				"ami": amiVal,
+			}),
+		}
+	}
+	return p
+}
+
+// showFixtureSensitiveProvider returns a mock provider that is configured for basic
+// operation with the configuration in testdata/show. This mock has
+// GetSchemaResponse, PlanResourceChangeFn, and ApplyResourceChangeFn populated,
+// with the plan/apply steps just passing through the data determined by
+// Terraform Core. It also has a sensitive attribute in the provider schema.
+func showFixtureSensitiveProvider() *terraform.MockProvider {
+	p := testProvider()
+	p.GetProviderSchemaResponse = showFixtureSensitiveSchema()
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		idVal := req.ProposedNewState.GetAttr("id")
+		if idVal.IsNull() {
+			idVal = cty.UnknownVal(cty.String)
+		}
+		return providers.PlanResourceChangeResponse{
+			PlannedState: cty.ObjectVal(map[string]cty.Value{
+				"id":       idVal,
+				"ami":      req.ProposedNewState.GetAttr("ami"),
+				"password": req.ProposedNewState.GetAttr("password"),
+			}),
+		}
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		idVal := req.PlannedState.GetAttr("id")
+		if !idVal.IsKnown() {
+			idVal = cty.StringVal("placeholder")
+		}
+		return providers.ApplyResourceChangeResponse{
+			NewState: cty.ObjectVal(map[string]cty.Value{
+				"id":       idVal,
+				"ami":      req.PlannedState.GetAttr("ami"),
+				"password": req.PlannedState.GetAttr("password"),
+			}),
+		}
+	}
+	return p
+}
+
+// showFixturePlanFile creates a plan file at a temporary location containing a
+// single change to create or update the test_instance.foo that is included in the "show"
+// test fixture, returning the location of that plan file.
+// `action` is the planned change you would like to elicit
+func showFixturePlanFile(t *testing.T, action plans.Action) string {
+	_, snap := testModuleWithSnapshot(t, "show")
+	plannedVal := cty.ObjectVal(map[string]cty.Value{
+		"id":  cty.UnknownVal(cty.String),
+		"ami": cty.StringVal("bar"),
+	})
+	priorValRaw, err := plans.NewDynamicValue(cty.NullVal(plannedVal.Type()), plannedVal.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	plannedValRaw, err := plans.NewDynamicValue(plannedVal, plannedVal.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	plan := testPlan(t)
+	plan.Changes.SyncWrapper().AppendResourceInstanceChange(&plans.ResourceInstanceChangeSrc{
+		Addr: addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: "foo",
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+		ProviderAddr: addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+		ChangeSrc: plans.ChangeSrc{
+			Action: action,
+			Before: priorValRaw,
+			After:  plannedValRaw,
+		},
+	})
+	return testPlanFile(
+		t,
+		snap,
+		states.NewState(),
+		plan,
+	)
+}
+
+// this simplified plan struct allows us to preserve field order when marshaling
+// the command output. NOTE: we are leaving "terraform_version" out of this test
+// to avoid needing to constantly update the expected output; as a potential
+// TODO we could write a jsonplan compare function.
+type plan struct {
+	FormatVersion   string                 `json:"format_version,omitempty"`
+	Variables       map[string]interface{} `json:"variables,omitempty"`
+	PlannedValues   map[string]interface{} `json:"planned_values,omitempty"`
+	ResourceDrift   []interface{}          `json:"resource_drift,omitempty"`
+	ResourceChanges []interface{}          `json:"resource_changes,omitempty"`
+	OutputChanges   map[string]interface{} `json:"output_changes,omitempty"`
+	PriorState      priorState             `json:"prior_state,omitempty"`
+	Config          map[string]interface{} `json:"configuration,omitempty"`
+}
+
+type priorState struct {
+	FormatVersion   string                 `json:"format_version,omitempty"`
+	Values          map[string]interface{} `json:"values,omitempty"`
+	SensitiveValues map[string]bool        `json:"sensitive_values,omitempty"`
+}
diff --git a/v1.5.7/internal/command/state_command.go b/v1.5.7/internal/command/state_command.go
new file mode 100644
index 0000000..e02c980
--- /dev/null
+++ b/v1.5.7/internal/command/state_command.go
@@ -0,0 +1,43 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"strings"
+
+	"github.com/mitchellh/cli"
+)
+
+// StateCommand is a Command implementation that just shows help for
+// the subcommands nested below it.
+type StateCommand struct {
+	StateMeta
+}
+
+func (c *StateCommand) Run(args []string) int {
+	return cli.RunResultHelp
+}
+
+func (c *StateCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] state <subcommand> [options] [args]
+
+  This command has subcommands for advanced state management.
+
+  These subcommands can be used to slice and dice the Terraform state.
+  This is sometimes necessary in advanced cases. For your safety, all
+  state management commands that modify the state create a timestamped
+  backup of the state prior to making modifications.
+
+  The structure and output of the commands is specifically tailored to work
+  well with the common Unix utilities such as grep, awk, etc. We recommend
+  using those tools to perform more advanced state tasks.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *StateCommand) Synopsis() string {
+	return "Advanced state management"
+}
diff --git a/v1.5.7/internal/command/state_list.go b/v1.5.7/internal/command/state_list.go
new file mode 100644
index 0000000..c452e71
--- /dev/null
+++ b/v1.5.7/internal/command/state_list.go
@@ -0,0 +1,145 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/mitchellh/cli"
+)
+
+// StateListCommand is a Command implementation that lists the resources
+// within a state file.
+type StateListCommand struct {
+	Meta
+	StateMeta
+}
+
+func (c *StateListCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	var statePath string
+	cmdFlags := c.Meta.defaultFlagSet("state list")
+	cmdFlags.StringVar(&statePath, "state", "", "path")
+	lookupId := cmdFlags.String("id", "", "Restrict output to paths with a resource having the specified ID.")
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return cli.RunResultHelp
+	}
+	args = cmdFlags.Args()
+
+	if statePath != "" {
+		c.Meta.statePath = statePath
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(nil)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(backendDiags)
+		return 1
+	}
+
+	// This is a read-only command
+	c.ignoreRemoteVersionConflict(b)
+
+	// Get the state
+	env, err := c.Workspace()
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err))
+		return 1
+	}
+	stateMgr, err := b.StateMgr(env)
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
+		return 1
+	}
+	if err := stateMgr.RefreshState(); err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
+		return 1
+	}
+
+	state := stateMgr.State()
+	if state == nil {
+		c.Ui.Error(errStateNotFound)
+		return 1
+	}
+
+	var addrs []addrs.AbsResourceInstance
+	var diags tfdiags.Diagnostics
+	if len(args) == 0 {
+		addrs, diags = c.lookupAllResourceInstanceAddrs(state)
+	} else {
+		addrs, diags = c.lookupResourceInstanceAddrs(state, args...)
+	}
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	for _, addr := range addrs {
+		if is := state.ResourceInstance(addr); is != nil {
+			if *lookupId == "" || *lookupId == states.LegacyInstanceObjectID(is.Current) {
+				c.Ui.Output(addr.String())
+			}
+		}
+	}
+
+	c.showDiagnostics(diags)
+
+	return 0
+}
+
+func (c *StateListCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] state list [options] [address...]
+
+  List resources in the Terraform state.
+
+  This command lists resource instances in the Terraform state. The address
+  argument can be used to filter the instances by resource or module. If
+  no pattern is given, all resource instances are listed.
+
+  The addresses must either be module addresses or absolute resource
+  addresses, such as:
+      aws_instance.example
+      module.example
+      module.example.module.child
+      module.example.aws_instance.example
+
+  An error will be returned if any of the resources or modules given as
+  filter addresses do not exist in the state.
+
+Options:
+
+  -state=statefile    Path to a Terraform state file to use to look
+                      up Terraform-managed resources. By default, Terraform
+                      will consult the state of the currently-selected
+                      workspace.
+
+  -id=ID              Filters the results to include only instances whose
+                      resource types have an attribute named "id" whose value
+                      equals the given id string.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *StateListCommand) Synopsis() string {
+	return "List resources in the state"
+}
+
+const errStateLoadingState = `Error loading the state: %[1]s
+
+Please ensure that your Terraform state exists and that you've
+configured it properly. You can use the "-state" flag to point
+Terraform at another state file.`
+
+const errStateNotFound = `No state file was found!
+
+State management commands require a state file. Run this command
+in a directory where Terraform has been run or use the -state flag
+to point the command to a specific state location.`
diff --git a/v1.5.7/internal/command/state_list_test.go b/v1.5.7/internal/command/state_list_test.go
new file mode 100644
index 0000000..fb102f8
--- /dev/null
+++ b/v1.5.7/internal/command/state_list_test.go
@@ -0,0 +1,273 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/mitchellh/cli"
+)
+
+func TestStateList(t *testing.T) {
+	state := testState()
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := cli.NewMockUi()
+	c := &StateListCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test that outputs were displayed
+	expected := strings.TrimSpace(testStateListOutput) + "\n"
+	actual := ui.OutputWriter.String()
+	if actual != expected {
+		t.Fatalf("Expected:\n%q\n\nTo equal: %q", actual, expected)
+	}
+}
+
+func TestStateListWithID(t *testing.T) {
+	state := testState()
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := cli.NewMockUi()
+	c := &StateListCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-id", "bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test that outputs were displayed
+	expected := strings.TrimSpace(testStateListOutput) + "\n"
+	actual := ui.OutputWriter.String()
+	if actual != expected {
+		t.Fatalf("Expected:\n%q\n\nTo equal: %q", actual, expected)
+	}
+}
+
+func TestStateListWithNonExistentID(t *testing.T) {
+	state := testState()
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := cli.NewMockUi()
+	c := &StateListCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-id", "baz",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test that output is empty
+	if ui.OutputWriter != nil {
+		actual := ui.OutputWriter.String()
+		if actual != "" {
+			t.Fatalf("Expected an empty output but got: %q", actual)
+		}
+	}
+}
+
+func TestStateList_backendDefaultState(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("state-list-backend-default"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	ui := cli.NewMockUi()
+	c := &StateListCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test that outputs were displayed
+	expected := "null_resource.a\n"
+	actual := ui.OutputWriter.String()
+	if actual != expected {
+		t.Fatalf("Expected:\n%q\n\nTo equal: %q", actual, expected)
+	}
+}
+
+func TestStateList_backendCustomState(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("state-list-backend-custom"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	ui := cli.NewMockUi()
+	c := &StateListCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test that outputs were displayed
+	expected := "null_resource.a\n"
+	actual := ui.OutputWriter.String()
+	if actual != expected {
+		t.Fatalf("Expected:\n%q\n\nTo equal: %q", actual, expected)
+	}
+}
+
+func TestStateList_backendOverrideState(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("state-list-backend-custom"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	ui := cli.NewMockUi()
+	c := &StateListCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+		},
+	}
+
+	// This test is configured to use a local backend that has
+	// a custom path defined. So we test if we can still pass
+	// is a user defined state file that will then override the
+	// one configured in the backend. As this file does not exist
+	// it should exit with a no state found error.
+	args := []string{"-state=" + DefaultStateFilename}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad: %d", code)
+	}
+	if !strings.Contains(ui.ErrorWriter.String(), "No state file was found!") {
+		t.Fatalf("expected a no state file error, got: %s", ui.ErrorWriter.String())
+	}
+}
+
+func TestStateList_noState(t *testing.T) {
+	testCwd(t)
+
+	p := testProvider()
+	ui := cli.NewMockUi()
+	c := &StateListCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad: %d", code)
+	}
+}
+
+func TestStateList_modules(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("state-list-nested-modules"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	ui := cli.NewMockUi()
+	c := &StateListCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+		},
+	}
+
+	t.Run("list resources in module and submodules", func(t *testing.T) {
+		args := []string{"module.nest"}
+		if code := c.Run(args); code != 0 {
+			t.Fatalf("bad: %d", code)
+		}
+
+		// resources in the module and any submodules should be included in the outputs
+		expected := "module.nest.test_instance.nest\nmodule.nest.module.subnest.test_instance.subnest\n"
+		actual := ui.OutputWriter.String()
+		if actual != expected {
+			t.Fatalf("Expected:\n%q\n\nTo equal: %q", actual, expected)
+		}
+	})
+
+	t.Run("submodule has resources only", func(t *testing.T) {
+		// now get the state for a module that has no resources, only another nested module
+		ui.OutputWriter.Reset()
+		args := []string{"module.nonexist"}
+		if code := c.Run(args); code != 0 {
+			t.Fatalf("bad: %d", code)
+		}
+		expected := "module.nonexist.module.child.test_instance.child\n"
+		actual := ui.OutputWriter.String()
+		if actual != expected {
+			t.Fatalf("Expected:\n%q\n\nTo equal: %q", actual, expected)
+		}
+	})
+
+	t.Run("expanded module", func(t *testing.T) {
+		// finally get the state for a module with an index
+		ui.OutputWriter.Reset()
+		args := []string{"module.count"}
+		if code := c.Run(args); code != 0 {
+			t.Fatalf("bad: %d", code)
+		}
+		expected := "module.count[0].test_instance.count\nmodule.count[1].test_instance.count\n"
+		actual := ui.OutputWriter.String()
+		if actual != expected {
+			t.Fatalf("Expected:\n%q\n\nTo equal: %q", actual, expected)
+		}
+	})
+
+	t.Run("completely nonexistent module", func(t *testing.T) {
+		// finally get the state for a module with an index
+		ui.OutputWriter.Reset()
+		args := []string{"module.notevenalittlebit"}
+		if code := c.Run(args); code != 1 {
+			t.Fatalf("bad: %d", code)
+		}
+	})
+
+}
+
+const testStateListOutput = `
+test_instance.foo
+`
diff --git a/v1.5.7/internal/command/state_meta.go b/v1.5.7/internal/command/state_meta.go
new file mode 100644
index 0000000..b563d30
--- /dev/null
+++ b/v1.5.7/internal/command/state_meta.go
@@ -0,0 +1,226 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"sort"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+
+	backendLocal "github.com/hashicorp/terraform/internal/backend/local"
+)
+
+// StateMeta is the meta struct that should be embedded in state subcommands.
+type StateMeta struct {
+	Meta
+}
+
+// State returns the state for this meta. This gets the appropriate state from
+// the backend, but changes the way that backups are done. This configures
+// backups to be timestamped rather than just the original state path plus a
+// backup path.
+func (c *StateMeta) State() (statemgr.Full, error) {
+	var realState statemgr.Full
+	backupPath := c.backupPath
+	stateOutPath := c.statePath
+
+	// use the specified state
+	if c.statePath != "" {
+		realState = statemgr.NewFilesystem(c.statePath)
+	} else {
+		// Load the backend
+		b, backendDiags := c.Backend(nil)
+		if backendDiags.HasErrors() {
+			return nil, backendDiags.Err()
+		}
+
+		workspace, err := c.Workspace()
+		if err != nil {
+			return nil, err
+		}
+
+		// Check remote Terraform version is compatible
+		remoteVersionDiags := c.remoteVersionCheck(b, workspace)
+		c.showDiagnostics(remoteVersionDiags)
+		if remoteVersionDiags.HasErrors() {
+			return nil, fmt.Errorf("Error checking remote Terraform version")
+		}
+
+		// Get the state
+		s, err := b.StateMgr(workspace)
+		if err != nil {
+			return nil, err
+		}
+
+		// Get a local backend
+		localRaw, backendDiags := c.Backend(&BackendOpts{ForceLocal: true})
+		if backendDiags.HasErrors() {
+			// This should never fail
+			panic(backendDiags.Err())
+		}
+		localB := localRaw.(*backendLocal.Local)
+		_, stateOutPath, _ = localB.StatePaths(workspace)
+		if err != nil {
+			return nil, err
+		}
+
+		realState = s
+	}
+
+	// We always backup state commands, so set the back if none was specified
+	// (the default is "-", but some tests bypass the flag parsing).
+	if backupPath == "-" || backupPath == "" {
+		// Determine the backup path. stateOutPath is set to the resulting
+		// file where state is written (cached in the case of remote state)
+		backupPath = fmt.Sprintf(
+			"%s.%d%s",
+			stateOutPath,
+			time.Now().UTC().Unix(),
+			DefaultBackupExtension)
+	}
+
+	// If the backend is local (which it should always be, given our asserting
+	// of it above) we can now enable backups for it.
+	if lb, ok := realState.(*statemgr.Filesystem); ok {
+		lb.SetBackupPath(backupPath)
+	}
+
+	return realState, nil
+}
+
+func (c *StateMeta) lookupResourceInstanceAddr(state *states.State, allowMissing bool, addrStr string) ([]addrs.AbsResourceInstance, tfdiags.Diagnostics) {
+	target, diags := addrs.ParseTargetStr(addrStr)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	targetAddr := target.Subject
+	var ret []addrs.AbsResourceInstance
+	switch addr := targetAddr.(type) {
+	case addrs.ModuleInstance:
+		// Matches all instances within the indicated module and all of its
+		// descendent modules.
+
+		// found is used to identify cases where the selected module has no
+		// resources, but one or more of its submodules does.
+		found := false
+		ms := state.Module(addr)
+		if ms != nil {
+			found = true
+			ret = append(ret, c.collectModuleResourceInstances(ms)...)
+		}
+		for _, cms := range state.Modules {
+			if !addr.Equal(cms.Addr) {
+				if addr.IsAncestor(cms.Addr) || addr.TargetContains(cms.Addr) {
+					found = true
+					ret = append(ret, c.collectModuleResourceInstances(cms)...)
+				}
+			}
+		}
+
+		if !found && !allowMissing {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Unknown module",
+				fmt.Sprintf(`The current state contains no module at %s. If you've just added this module to the configuration, you must run "terraform apply" first to create the module's entry in the state.`, addr),
+			))
+		}
+
+	case addrs.AbsResource:
+		// Matches all instances of the specific selected resource.
+		rs := state.Resource(addr)
+		if rs == nil {
+			if !allowMissing {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Unknown resource",
+					fmt.Sprintf(`The current state contains no resource %s. If you've just added this resource to the configuration, you must run "terraform apply" first to create the resource's entry in the state.`, addr),
+				))
+			}
+			break
+		}
+		ret = append(ret, c.collectResourceInstances(addr.Module, rs)...)
+	case addrs.AbsResourceInstance:
+		is := state.ResourceInstance(addr)
+		if is == nil {
+			if !allowMissing {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Unknown resource instance",
+					fmt.Sprintf(`The current state contains no resource instance %s. If you've just added its resource to the configuration or have changed the count or for_each arguments, you must run "terraform apply" first to update the resource's entry in the state.`, addr),
+				))
+			}
+			break
+		}
+		ret = append(ret, addr)
+	}
+	sort.Slice(ret, func(i, j int) bool {
+		return ret[i].Less(ret[j])
+	})
+
+	return ret, diags
+}
+
+func (c *StateMeta) lookupSingleStateObjectAddr(state *states.State, addrStr string) (addrs.Targetable, tfdiags.Diagnostics) {
+	target, diags := addrs.ParseTargetStr(addrStr)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+	return target.Subject, diags
+}
+
+func (c *StateMeta) lookupResourceInstanceAddrs(state *states.State, addrStrs ...string) ([]addrs.AbsResourceInstance, tfdiags.Diagnostics) {
+	var ret []addrs.AbsResourceInstance
+	var diags tfdiags.Diagnostics
+	for _, addrStr := range addrStrs {
+		moreAddrs, moreDiags := c.lookupResourceInstanceAddr(state, false, addrStr)
+		ret = append(ret, moreAddrs...)
+		diags = diags.Append(moreDiags)
+	}
+	return ret, diags
+}
+
+func (c *StateMeta) lookupAllResourceInstanceAddrs(state *states.State) ([]addrs.AbsResourceInstance, tfdiags.Diagnostics) {
+	var ret []addrs.AbsResourceInstance
+	var diags tfdiags.Diagnostics
+	for _, ms := range state.Modules {
+		ret = append(ret, c.collectModuleResourceInstances(ms)...)
+	}
+	sort.Slice(ret, func(i, j int) bool {
+		return ret[i].Less(ret[j])
+	})
+	return ret, diags
+}
+
+func (c *StateMeta) collectModuleResourceInstances(ms *states.Module) []addrs.AbsResourceInstance {
+	var ret []addrs.AbsResourceInstance
+	for _, rs := range ms.Resources {
+		ret = append(ret, c.collectResourceInstances(ms.Addr, rs)...)
+	}
+	return ret
+}
+
+func (c *StateMeta) collectResourceInstances(moduleAddr addrs.ModuleInstance, rs *states.Resource) []addrs.AbsResourceInstance {
+	var ret []addrs.AbsResourceInstance
+	for key := range rs.Instances {
+		ret = append(ret, rs.Addr.Instance(key))
+	}
+	return ret
+}
+
+func (c *StateMeta) lookupAllResources(state *states.State) ([]*states.Resource, tfdiags.Diagnostics) {
+	var ret []*states.Resource
+	var diags tfdiags.Diagnostics
+	for _, ms := range state.Modules {
+		for _, resource := range ms.Resources {
+			ret = append(ret, resource)
+		}
+	}
+	return ret, diags
+}
diff --git a/v1.5.7/internal/command/state_mv.go b/v1.5.7/internal/command/state_mv.go
new file mode 100644
index 0000000..9fa40f0
--- /dev/null
+++ b/v1.5.7/internal/command/state_mv.go
@@ -0,0 +1,567 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/mitchellh/cli"
+)
+
+// StateMvCommand is a Command implementation that shows a single resource.
+type StateMvCommand struct {
+	StateMeta
+}
+
+func (c *StateMvCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	// We create two metas to track the two states
+	var backupPathOut, statePathOut string
+
+	var dryRun bool
+	cmdFlags := c.Meta.ignoreRemoteVersionFlagSet("state mv")
+	cmdFlags.BoolVar(&dryRun, "dry-run", false, "dry run")
+	cmdFlags.StringVar(&c.backupPath, "backup", "-", "backup")
+	cmdFlags.StringVar(&backupPathOut, "backup-out", "-", "backup")
+	cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock states")
+	cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
+	cmdFlags.StringVar(&c.statePath, "state", "", "path")
+	cmdFlags.StringVar(&statePathOut, "state-out", "", "path")
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+	args = cmdFlags.Args()
+	if len(args) != 2 {
+		c.Ui.Error("Exactly two arguments expected.\n")
+		return cli.RunResultHelp
+	}
+
+	if diags := c.Meta.checkRequiredVersion(); diags != nil {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// If backup or backup-out options are set
+	// and the state option is not set, make sure
+	// the backend is local
+	backupOptionSetWithoutStateOption := c.backupPath != "-" && c.statePath == ""
+	backupOutOptionSetWithoutStateOption := backupPathOut != "-" && c.statePath == ""
+
+	var setLegacyLocalBackendOptions []string
+	if backupOptionSetWithoutStateOption {
+		setLegacyLocalBackendOptions = append(setLegacyLocalBackendOptions, "-backup")
+	}
+	if backupOutOptionSetWithoutStateOption {
+		setLegacyLocalBackendOptions = append(setLegacyLocalBackendOptions, "-backup-out")
+	}
+
+	if len(setLegacyLocalBackendOptions) > 0 {
+		currentBackend, diags := c.backendFromConfig(&BackendOpts{})
+		if diags.HasErrors() {
+			c.showDiagnostics(diags)
+			return 1
+		}
+
+		// If currentBackend is nil and diags didn't have errors,
+		// this means we have an implicit local backend
+		_, isLocalBackend := currentBackend.(backend.Local)
+		if currentBackend != nil && !isLocalBackend {
+			diags = diags.Append(
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					fmt.Sprintf("Invalid command line options: %s", strings.Join(setLegacyLocalBackendOptions[:], ", ")),
+					"Command line options -backup and -backup-out are legacy options that operate on a local state file only. You must specify a local state file with the -state option or switch to the local backend.",
+				),
+			)
+			c.showDiagnostics(diags)
+			return 1
+		}
+	}
+
+	// Read the from state
+	stateFromMgr, err := c.State()
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
+		return 1
+	}
+
+	if c.stateLock {
+		stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
+		if diags := stateLocker.Lock(stateFromMgr, "state-mv"); diags.HasErrors() {
+			c.showDiagnostics(diags)
+			return 1
+		}
+		defer func() {
+			if diags := stateLocker.Unlock(); diags.HasErrors() {
+				c.showDiagnostics(diags)
+			}
+		}()
+	}
+
+	if err := stateFromMgr.RefreshState(); err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to refresh source state: %s", err))
+		return 1
+	}
+
+	stateFrom := stateFromMgr.State()
+	if stateFrom == nil {
+		c.Ui.Error(errStateNotFound)
+		return 1
+	}
+
+	// Read the destination state
+	stateToMgr := stateFromMgr
+	stateTo := stateFrom
+
+	if statePathOut != "" {
+		c.statePath = statePathOut
+		c.backupPath = backupPathOut
+
+		stateToMgr, err = c.State()
+		if err != nil {
+			c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
+			return 1
+		}
+
+		if c.stateLock {
+			stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
+			if diags := stateLocker.Lock(stateToMgr, "state-mv"); diags.HasErrors() {
+				c.showDiagnostics(diags)
+				return 1
+			}
+			defer func() {
+				if diags := stateLocker.Unlock(); diags.HasErrors() {
+					c.showDiagnostics(diags)
+				}
+			}()
+		}
+
+		if err := stateToMgr.RefreshState(); err != nil {
+			c.Ui.Error(fmt.Sprintf("Failed to refresh destination state: %s", err))
+			return 1
+		}
+
+		stateTo = stateToMgr.State()
+		if stateTo == nil {
+			stateTo = states.NewState()
+		}
+	}
+
+	var diags tfdiags.Diagnostics
+	sourceAddr, moreDiags := c.lookupSingleStateObjectAddr(stateFrom, args[0])
+	diags = diags.Append(moreDiags)
+	destAddr, moreDiags := c.lookupSingleStateObjectAddr(stateFrom, args[1])
+	diags = diags.Append(moreDiags)
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	prefix := "Move"
+	if dryRun {
+		prefix = "Would move"
+	}
+
+	const msgInvalidSource = "Invalid source address"
+	const msgInvalidTarget = "Invalid target address"
+
+	var moved int
+	ssFrom := stateFrom.SyncWrapper()
+	sourceAddrs := c.sourceObjectAddrs(stateFrom, sourceAddr)
+	if len(sourceAddrs) == 0 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			msgInvalidSource,
+			fmt.Sprintf("Cannot move %s: does not match anything in the current state.", sourceAddr),
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+	for _, rawAddrFrom := range sourceAddrs {
+		switch addrFrom := rawAddrFrom.(type) {
+		case addrs.ModuleInstance:
+			search := sourceAddr.(addrs.ModuleInstance)
+			addrTo, ok := destAddr.(addrs.ModuleInstance)
+			if !ok {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					msgInvalidTarget,
+					fmt.Sprintf("Cannot move %s to %s: the target must also be a module.", addrFrom, destAddr),
+				))
+				c.showDiagnostics(diags)
+				return 1
+			}
+
+			if len(search) < len(addrFrom) {
+				n := make(addrs.ModuleInstance, 0, len(addrTo)+len(addrFrom)-len(search))
+				n = append(n, addrTo...)
+				n = append(n, addrFrom[len(search):]...)
+				addrTo = n
+			}
+
+			if stateTo.Module(addrTo) != nil {
+				c.Ui.Error(fmt.Sprintf(errStateMv, "destination module already exists"))
+				return 1
+			}
+
+			ms := ssFrom.Module(addrFrom)
+			if ms == nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					msgInvalidSource,
+					fmt.Sprintf("The current state does not contain %s.", addrFrom),
+				))
+				c.showDiagnostics(diags)
+				return 1
+			}
+
+			moved++
+			c.Ui.Output(fmt.Sprintf("%s %q to %q", prefix, addrFrom.String(), addrTo.String()))
+			if !dryRun {
+				ssFrom.RemoveModule(addrFrom)
+
+				// Update the address before adding it to the state.
+				ms.Addr = addrTo
+				stateTo.Modules[addrTo.String()] = ms
+			}
+
+		case addrs.AbsResource:
+			addrTo, ok := destAddr.(addrs.AbsResource)
+			if !ok {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					msgInvalidTarget,
+					fmt.Sprintf("Cannot move %s to %s: the source is a whole resource (not a resource instance) so the target must also be a whole resource.", addrFrom, destAddr),
+				))
+				c.showDiagnostics(diags)
+				return 1
+			}
+			diags = diags.Append(c.validateResourceMove(addrFrom, addrTo))
+
+			if stateTo.Resource(addrTo) != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					msgInvalidTarget,
+					fmt.Sprintf("Cannot move to %s: there is already a resource at that address in the current state.", addrTo),
+				))
+			}
+
+			rs := ssFrom.Resource(addrFrom)
+			if rs == nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					msgInvalidSource,
+					fmt.Sprintf("The current state does not contain %s.", addrFrom),
+				))
+			}
+
+			if diags.HasErrors() {
+				c.showDiagnostics(diags)
+				return 1
+			}
+
+			moved++
+			c.Ui.Output(fmt.Sprintf("%s %q to %q", prefix, addrFrom.String(), addrTo.String()))
+			if !dryRun {
+				ssFrom.RemoveResource(addrFrom)
+
+				// Update the address before adding it to the state.
+				rs.Addr = addrTo
+				stateTo.EnsureModule(addrTo.Module).Resources[addrTo.Resource.String()] = rs
+			}
+
+		case addrs.AbsResourceInstance:
+			addrTo, ok := destAddr.(addrs.AbsResourceInstance)
+			if !ok {
+				ra, ok := destAddr.(addrs.AbsResource)
+				if !ok {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						msgInvalidTarget,
+						fmt.Sprintf("Cannot move %s to %s: the target must also be a resource instance.", addrFrom, destAddr),
+					))
+					c.showDiagnostics(diags)
+					return 1
+				}
+				addrTo = ra.Instance(addrs.NoKey)
+			}
+
+			diags = diags.Append(c.validateResourceMove(addrFrom.ContainingResource(), addrTo.ContainingResource()))
+
+			if stateTo.Module(addrTo.Module) == nil {
+				// moving something to a mew module, so we need to ensure it exists
+				stateTo.EnsureModule(addrTo.Module)
+			}
+			if stateTo.ResourceInstance(addrTo) != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					msgInvalidTarget,
+					fmt.Sprintf("Cannot move to %s: there is already a resource instance at that address in the current state.", addrTo),
+				))
+			}
+
+			is := ssFrom.ResourceInstance(addrFrom)
+			if is == nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					msgInvalidSource,
+					fmt.Sprintf("The current state does not contain %s.", addrFrom),
+				))
+			}
+
+			if diags.HasErrors() {
+				c.showDiagnostics(diags)
+				return 1
+			}
+
+			moved++
+			c.Ui.Output(fmt.Sprintf("%s %q to %q", prefix, addrFrom.String(), args[1]))
+			if !dryRun {
+				fromResourceAddr := addrFrom.ContainingResource()
+				fromResource := ssFrom.Resource(fromResourceAddr)
+				fromProviderAddr := fromResource.ProviderConfig
+				ssFrom.ForgetResourceInstanceAll(addrFrom)
+				ssFrom.RemoveResourceIfEmpty(fromResourceAddr)
+
+				rs := stateTo.Resource(addrTo.ContainingResource())
+				if rs == nil {
+					// If we're moving to an address without an index then that
+					// suggests the user's intent is to establish both the
+					// resource and the instance at the same time (since the
+					// address covers both). If there's an index in the
+					// target then allow creating the new instance here.
+					resourceAddr := addrTo.ContainingResource()
+					stateTo.SyncWrapper().SetResourceProvider(
+						resourceAddr,
+						fromProviderAddr, // in this case, we bring the provider along as if we were moving the whole resource
+					)
+					rs = stateTo.Resource(resourceAddr)
+				}
+
+				rs.Instances[addrTo.Resource.Key] = is
+			}
+		default:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				msgInvalidSource,
+				fmt.Sprintf("Cannot move %s: Terraform doesn't know how to move this object.", rawAddrFrom),
+			))
+		}
+
+		// Look for any dependencies that may be effected and
+		// remove them to ensure they are recreated in full.
+		for _, mod := range stateTo.Modules {
+			for _, res := range mod.Resources {
+				for _, ins := range res.Instances {
+					if ins.Current == nil {
+						continue
+					}
+
+					for _, dep := range ins.Current.Dependencies {
+						// check both directions here, since we may be moving
+						// an instance which is in a resource, or a module
+						// which can contain a resource.
+						if dep.TargetContains(rawAddrFrom) || rawAddrFrom.TargetContains(dep) {
+							ins.Current.Dependencies = nil
+							break
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if dryRun {
+		if moved == 0 {
+			c.Ui.Output("Would have moved nothing.")
+		}
+		return 0 // This is as far as we go in dry-run mode
+	}
+
+	b, backendDiags := c.Backend(nil)
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Get schemas, if possible, before writing state
+	var schemas *terraform.Schemas
+	if isCloudMode(b) {
+		var schemaDiags tfdiags.Diagnostics
+		schemas, schemaDiags = c.MaybeGetSchemas(stateTo, nil)
+		diags = diags.Append(schemaDiags)
+	}
+
+	// Write the new state
+	if err := stateToMgr.WriteState(stateTo); err != nil {
+		c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
+		return 1
+	}
+	if err := stateToMgr.PersistState(schemas); err != nil {
+		c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
+		return 1
+	}
+
+	// Write the old state if it is different
+	if stateTo != stateFrom {
+		if err := stateFromMgr.WriteState(stateFrom); err != nil {
+			c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
+			return 1
+		}
+		if err := stateFromMgr.PersistState(schemas); err != nil {
+			c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
+			return 1
+		}
+	}
+
+	c.showDiagnostics(diags)
+
+	if moved == 0 {
+		c.Ui.Output("No matching objects found.")
+	} else {
+		c.Ui.Output(fmt.Sprintf("Successfully moved %d object(s).", moved))
+	}
+	return 0
+}
+
+// sourceObjectAddrs takes a single source object address and expands it to
+// potentially multiple objects that need to be handled within it.
+//
+// In particular, this handles the case where a module is requested directly:
+// if it has any child modules, then they must also be moved. It also resolves
+// the ambiguity that an index-less resource address could either be a resource
+// address or a resource instance address, by making a decision about which
+// is intended based on the current state of the resource in question.
+func (c *StateMvCommand) sourceObjectAddrs(state *states.State, matched addrs.Targetable) []addrs.Targetable {
+	var ret []addrs.Targetable
+
+	switch addr := matched.(type) {
+	case addrs.ModuleInstance:
+		for _, mod := range state.Modules {
+			if len(mod.Addr) < len(addr) {
+				continue // can't possibly be our selection or a child of it
+			}
+			if !mod.Addr[:len(addr)].Equal(addr) {
+				continue
+			}
+			ret = append(ret, mod.Addr)
+		}
+	case addrs.AbsResource:
+		// If this refers to a resource without "count" or "for_each" set then
+		// we'll assume the user intended it to be a resource instance
+		// address instead, to allow for requests like this:
+		//   terraform state mv aws_instance.foo aws_instance.bar[1]
+		// That wouldn't be allowed if aws_instance.foo had multiple instances
+		// since we can't move multiple instances into one.
+		if rs := state.Resource(addr); rs != nil {
+			if _, ok := rs.Instances[addrs.NoKey]; ok {
+				ret = append(ret, addr.Instance(addrs.NoKey))
+			} else {
+				ret = append(ret, addr)
+			}
+		}
+	default:
+		ret = append(ret, matched)
+	}
+
+	return ret
+}
+
+func (c *StateMvCommand) validateResourceMove(addrFrom, addrTo addrs.AbsResource) tfdiags.Diagnostics {
+	const msgInvalidRequest = "Invalid state move request"
+
+	var diags tfdiags.Diagnostics
+	if addrFrom.Resource.Mode != addrTo.Resource.Mode {
+		switch addrFrom.Resource.Mode {
+		case addrs.ManagedResourceMode:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				msgInvalidRequest,
+				fmt.Sprintf("Cannot move %s to %s: a managed resource can be moved only to another managed resource address.", addrFrom, addrTo),
+			))
+		case addrs.DataResourceMode:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				msgInvalidRequest,
+				fmt.Sprintf("Cannot move %s to %s: a data resource can be moved only to another data resource address.", addrFrom, addrTo),
+			))
+		default:
+			// In case a new mode is added in future, this unhelpful error is better than nothing.
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				msgInvalidRequest,
+				fmt.Sprintf("Cannot move %s to %s: cannot change resource mode.", addrFrom, addrTo),
+			))
+		}
+	}
+	if addrFrom.Resource.Type != addrTo.Resource.Type {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			msgInvalidRequest,
+			fmt.Sprintf("Cannot move %s to %s: resource types don't match.", addrFrom, addrTo),
+		))
+	}
+	return diags
+}
+
+func (c *StateMvCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] state mv [options] SOURCE DESTINATION
+
+ This command will move an item matched by the address given to the
+ destination address. This command can also move to a destination address
+ in a completely different state file.
+
+ This can be used for simple resource renaming, moving items to and from
+ a module, moving entire modules, and more. And because this command can also
+ move data to a completely new state, it can also be used for refactoring
+ one configuration into multiple separately managed Terraform configurations.
+
+ This command will output a backup copy of the state prior to saving any
+ changes. The backup cannot be disabled. Due to the destructive nature
+ of this command, backups are required.
+
+ If you're moving an item to a different state file, a backup will be created
+ for each state file.
+
+Options:
+
+  -dry-run                If set, prints out what would've been moved but doesn't
+                          actually move anything.
+
+  -lock=false             Don't hold a state lock during the operation. This is
+                          dangerous if others might concurrently run commands
+                          against the same workspace.
+
+  -lock-timeout=0s        Duration to retry a state lock.
+
+  -ignore-remote-version  A rare option used for the remote backend only. See
+                          the remote backend documentation for more information.
+
+  -state, state-out, and -backup are legacy options supported for the local
+  backend only. For more information, see the local backend's documentation.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *StateMvCommand) Synopsis() string {
+	return "Move an item in the state"
+}
+
+const errStateMv = `Error moving state: %s
+
+Please ensure your addresses and state paths are valid. No
+state was persisted. Your existing states are untouched.`
diff --git a/v1.5.7/internal/command/state_mv_test.go b/v1.5.7/internal/command/state_mv_test.go
new file mode 100644
index 0000000..72cbbbb
--- /dev/null
+++ b/v1.5.7/internal/command/state_mv_test.go
@@ -0,0 +1,2131 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/mitchellh/cli"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestStateMv(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "baz",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON:    []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:       states.ObjectReady,
+				Dependencies: []addrs.ConfigResource{mustResourceAddr("test_instance.foo")},
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+		"test_instance.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("return code: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, statePath, testStateMvOutput)
+
+	// Test we have backups
+	backups := testStateBackups(t, filepath.Dir(statePath))
+	if len(backups) != 1 {
+		t.Fatalf("bad: %#v", backups)
+	}
+	testStateOutput(t, backups[0], testStateMvOutputOriginal)
+
+	// Change the single instance to a counted instance
+	args = []string{
+		"-state", statePath,
+		"test_instance.bar",
+		"test_instance.bar[0]",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("return code: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// extract the resource and verify the mode
+	s := testStateRead(t, statePath)
+	addr, diags := addrs.ParseAbsResourceStr("test_instance.bar")
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+	for key := range s.Resource(addr).Instances {
+		if _, ok := key.(addrs.IntKey); !ok {
+			t.Fatalf("expected each mode List, got key %q", key)
+		}
+	}
+
+	// change from list to map
+	args = []string{
+		"-state", statePath,
+		"test_instance.bar[0]",
+		"test_instance.bar[\"baz\"]",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("return code: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// extract the resource and verify the mode
+	s = testStateRead(t, statePath)
+	addr, diags = addrs.ParseAbsResourceStr("test_instance.bar")
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+	for key := range s.Resource(addr).Instances {
+		if _, ok := key.(addrs.StringKey); !ok {
+			t.Fatalf("expected each mode map, found key %q", key)
+		}
+	}
+
+	// change from from map back to single
+	args = []string{
+		"-state", statePath,
+		"test_instance.bar[\"baz\"]",
+		"test_instance.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("return code: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// extract the resource and verify the mode
+	s = testStateRead(t, statePath)
+	addr, diags = addrs.ParseAbsResourceStr("test_instance.bar")
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+	for key := range s.Resource(addr).Instances {
+		if key != addrs.NoKey {
+			t.Fatalf("expected no each mode, found key %q", key)
+		}
+	}
+
+}
+
+func TestStateMv_backupAndBackupOutOptionsWithNonLocalBackend(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	t.Run("backup option specified", func(t *testing.T) {
+		td := t.TempDir()
+		testCopyDir(t, testFixturePath("init-backend-http"), td)
+		defer testChdir(t, td)()
+
+		backupPath := filepath.Join(td, "backup")
+
+		// Set up our backend state using mock state
+		dataState, srv := testBackendState(t, state, 200)
+		defer srv.Close()
+		testStateFileRemote(t, dataState)
+
+		p := testProvider()
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &StateMvCommand{
+			StateMeta{
+				Meta: Meta{
+					testingOverrides: metaOverridesForProvider(p),
+					Ui:               ui,
+					View:             view,
+				},
+			},
+		}
+
+		args := []string{
+			"-backup", backupPath,
+			"test_instance.foo",
+			"test_instance.bar",
+		}
+		if code := c.Run(args); code == 0 {
+			t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String())
+		}
+
+		gotErr := ui.ErrorWriter.String()
+		wantErr := `
+Error: Invalid command line options: -backup
+
+Command line options -backup and -backup-out are legacy options that operate
+on a local state file only. You must specify a local state file with the
+-state option or switch to the local backend.
+
+`
+		if gotErr != wantErr {
+			t.Fatalf("expected error\ngot:%s\n\nwant:%s", gotErr, wantErr)
+		}
+	})
+
+	t.Run("backup-out option specified", func(t *testing.T) {
+		td := t.TempDir()
+		testCopyDir(t, testFixturePath("init-backend-http"), td)
+		defer testChdir(t, td)()
+
+		backupOutPath := filepath.Join(td, "backup-out")
+
+		// Set up our backend state using mock state
+		dataState, srv := testBackendState(t, state, 200)
+		defer srv.Close()
+		testStateFileRemote(t, dataState)
+
+		p := testProvider()
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &StateMvCommand{
+			StateMeta{
+				Meta: Meta{
+					testingOverrides: metaOverridesForProvider(p),
+					Ui:               ui,
+					View:             view,
+				},
+			},
+		}
+
+		args := []string{
+			"-backup-out", backupOutPath,
+			"test_instance.foo",
+			"test_instance.bar",
+		}
+		if code := c.Run(args); code == 0 {
+			t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String())
+		}
+
+		gotErr := ui.ErrorWriter.String()
+		wantErr := `
+Error: Invalid command line options: -backup-out
+
+Command line options -backup and -backup-out are legacy options that operate
+on a local state file only. You must specify a local state file with the
+-state option or switch to the local backend.
+
+`
+		if gotErr != wantErr {
+			t.Fatalf("expected error\ngot:%s\n\nwant:%s", gotErr, wantErr)
+		}
+	})
+
+	t.Run("backup and backup-out options specified", func(t *testing.T) {
+		td := t.TempDir()
+		testCopyDir(t, testFixturePath("init-backend-http"), td)
+		defer testChdir(t, td)()
+
+		backupPath := filepath.Join(td, "backup")
+		backupOutPath := filepath.Join(td, "backup-out")
+
+		// Set up our backend state using mock state
+		dataState, srv := testBackendState(t, state, 200)
+		defer srv.Close()
+		testStateFileRemote(t, dataState)
+
+		p := testProvider()
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &StateMvCommand{
+			StateMeta{
+				Meta: Meta{
+					testingOverrides: metaOverridesForProvider(p),
+					Ui:               ui,
+					View:             view,
+				},
+			},
+		}
+
+		args := []string{
+			"-backup", backupPath,
+			"-backup-out", backupOutPath,
+			"test_instance.foo",
+			"test_instance.bar",
+		}
+		if code := c.Run(args); code == 0 {
+			t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String())
+		}
+
+		gotErr := ui.ErrorWriter.String()
+		wantErr := `
+Error: Invalid command line options: -backup, -backup-out
+
+Command line options -backup and -backup-out are legacy options that operate
+on a local state file only. You must specify a local state file with the
+-state option or switch to the local backend.
+
+`
+		if gotErr != wantErr {
+			t.Fatalf("expected error\ngot:%s\n\nwant:%s", gotErr, wantErr)
+		}
+	})
+
+	t.Run("backup option specified with state option", func(t *testing.T) {
+		td := t.TempDir()
+		testCopyDir(t, testFixturePath("init-backend-http"), td)
+		defer testChdir(t, td)()
+
+		statePath := testStateFile(t, state)
+		backupPath := filepath.Join(td, "backup")
+
+		// Set up our backend state using mock state
+		dataState, srv := testBackendState(t, state, 200)
+		defer srv.Close()
+		testStateFileRemote(t, dataState)
+
+		p := testProvider()
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &StateMvCommand{
+			StateMeta{
+				Meta: Meta{
+					testingOverrides: metaOverridesForProvider(p),
+					Ui:               ui,
+					View:             view,
+				},
+			},
+		}
+
+		args := []string{
+			"-state", statePath,
+			"-backup", backupPath,
+			"test_instance.foo",
+			"test_instance.bar",
+		}
+		if code := c.Run(args); code != 0 {
+			t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+		}
+
+		// Test it is correct
+		testStateOutput(t, statePath, testStateMvBackupAndBackupOutOptionsWithNonLocalBackendOutput)
+	})
+
+	t.Run("backup-out option specified with state option", func(t *testing.T) {
+		td := t.TempDir()
+		testCopyDir(t, testFixturePath("init-backend-http"), td)
+		defer testChdir(t, td)()
+
+		statePath := testStateFile(t, state)
+		backupOutPath := filepath.Join(td, "backup-out")
+
+		// Set up our backend state using mock state
+		dataState, srv := testBackendState(t, state, 200)
+		defer srv.Close()
+		testStateFileRemote(t, dataState)
+
+		p := testProvider()
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &StateMvCommand{
+			StateMeta{
+				Meta: Meta{
+					testingOverrides: metaOverridesForProvider(p),
+					Ui:               ui,
+					View:             view,
+				},
+			},
+		}
+
+		args := []string{
+			"-state", statePath,
+			"-backup-out", backupOutPath,
+			"test_instance.foo",
+			"test_instance.bar",
+		}
+		if code := c.Run(args); code != 0 {
+			t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+		}
+
+		// Test it is correct
+		testStateOutput(t, statePath, testStateMvBackupAndBackupOutOptionsWithNonLocalBackendOutput)
+	})
+}
+
+func TestStateMv_resourceToInstance(t *testing.T) {
+	// A single resource (no count defined)
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "baz",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON:    []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:       states.ObjectReady,
+				Dependencies: []addrs.ConfigResource{mustResourceAddr("test_instance.foo")},
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceProvider(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "bar",
+			}.Absolute(addrs.RootModuleInstance),
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+		"test_instance.bar[0]",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, statePath, `
+test_instance.bar.0:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.baz:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`)
+
+	// Test we have backups
+	backups := testStateBackups(t, filepath.Dir(statePath))
+	if len(backups) != 1 {
+		t.Fatalf("bad: %#v", backups)
+	}
+	testStateOutput(t, backups[0], testStateMvOutputOriginal)
+}
+
+func TestStateMv_resourceToInstanceErr(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceProvider(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "bar",
+			}.Absolute(addrs.RootModuleInstance),
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+		"test_instance.bar[0]",
+	}
+
+	if code := c.Run(args); code == 0 {
+		t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String())
+	}
+
+	expectedErr := `
+Error: Invalid target address
+
+Cannot move test_instance.foo to test_instance.bar[0]: the source is a whole
+resource (not a resource instance) so the target must also be a whole
+resource.
+
+`
+	errOutput := ui.ErrorWriter.String()
+	if errOutput != expectedErr {
+		t.Errorf("wrong output\n%s", cmp.Diff(errOutput, expectedErr))
+	}
+}
+
+func TestStateMv_resourceToInstanceErrInAutomation(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceProvider(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "bar",
+			}.Absolute(addrs.RootModuleInstance),
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides:    metaOverridesForProvider(p),
+				Ui:                  ui,
+				View:                view,
+				RunningInAutomation: true,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+		"test_instance.bar[0]",
+	}
+
+	if code := c.Run(args); code == 0 {
+		t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String())
+	}
+
+	expectedErr := `
+Error: Invalid target address
+
+Cannot move test_instance.foo to test_instance.bar[0]: the source is a whole
+resource (not a resource instance) so the target must also be a whole
+resource.
+
+`
+	errOutput := ui.ErrorWriter.String()
+	if errOutput != expectedErr {
+		t.Errorf("Unexpected diff.\ngot:\n%s\nwant:\n%s\n", errOutput, expectedErr)
+		t.Errorf("%s", cmp.Diff(errOutput, expectedErr))
+	}
+}
+
+func TestStateMv_instanceToResource(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "baz",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo[0]",
+		"test_instance.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, statePath, `
+test_instance.bar:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.baz:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`)
+
+	// Test we have backups
+	backups := testStateBackups(t, filepath.Dir(statePath))
+	if len(backups) != 1 {
+		t.Fatalf("bad: %#v", backups)
+	}
+	testStateOutput(t, backups[0], `
+test_instance.baz:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.foo.0:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`)
+}
+
+func TestStateMv_instanceToNewResource(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo[0]",
+		"test_instance.bar[\"new\"]",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, statePath, `
+test_instance.bar["new"]:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`)
+
+	// now move the instance to a new resource in a new module
+	args = []string{
+		"-state", statePath,
+		"test_instance.bar[\"new\"]",
+		"module.test.test_instance.baz[\"new\"]",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, statePath, `
+<no state>
+module.test:
+  test_instance.baz["new"]:
+    ID = bar
+    provider = provider["registry.terraform.io/hashicorp/test"]
+    bar = value
+    foo = value
+`)
+}
+
+func TestStateMv_differentResourceTypes(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+		"test_network.bar",
+	}
+	if code := c.Run(args); code == 0 {
+		t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String())
+	}
+
+	gotErr := ui.ErrorWriter.String()
+	wantErr := `
+Error: Invalid state move request
+
+Cannot move test_instance.foo to test_network.bar: resource types don't
+match.
+
+`
+	if gotErr != wantErr {
+		t.Fatalf("expected initialization error\ngot:\n%s\n\nwant:%s", gotErr, wantErr)
+	}
+}
+
+// don't modify backend state is we supply a -state flag
+func TestStateMv_explicitWithBackend(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("init-backend"), td)
+	defer testChdir(t, td)()
+
+	backupPath := filepath.Join(td, "backup")
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "baz",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	// init our backend
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	ic := &InitCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{}
+	if code := ic.Run(args); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	// only modify statePath
+	p := testProvider()
+	ui = new(cli.MockUi)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args = []string{
+		"-backup", backupPath,
+		"-state", statePath,
+		"test_instance.foo",
+		"test_instance.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, statePath, testStateMvOutput)
+}
+
+func TestStateMv_backupExplicit(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "baz",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON:    []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:       states.ObjectReady,
+				Dependencies: []addrs.ConfigResource{mustResourceAddr("test_instance.foo")},
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+	backupPath := statePath + ".backup.test"
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-backup", backupPath,
+		"-state", statePath,
+		"test_instance.foo",
+		"test_instance.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, statePath, testStateMvOutput)
+
+	// Test backup
+	testStateOutput(t, backupPath, testStateMvOutputOriginal)
+}
+
+func TestStateMv_stateOutNew(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+	stateOutPath := statePath + ".out"
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-state-out", stateOutPath,
+		"test_instance.foo",
+		"test_instance.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, stateOutPath, testStateMvOutput_stateOut)
+	testStateOutput(t, statePath, testStateMvOutput_stateOutSrc)
+
+	// Test we have backups
+	backups := testStateBackups(t, filepath.Dir(statePath))
+	if len(backups) != 1 {
+		t.Fatalf("bad: %#v", backups)
+	}
+	testStateOutput(t, backups[0], testStateMvOutput_stateOutOriginal)
+}
+
+func TestStateMv_stateOutExisting(t *testing.T) {
+	stateSrc := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, stateSrc)
+
+	stateDst := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "qux",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	stateOutPath := testStateFile(t, stateDst)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-state-out", stateOutPath,
+		"test_instance.foo",
+		"test_instance.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, stateOutPath, testStateMvExisting_stateDst)
+	testStateOutput(t, statePath, testStateMvExisting_stateSrc)
+
+	// Test we have backups
+	backups := testStateBackups(t, filepath.Dir(statePath))
+	if len(backups) != 1 {
+		t.Fatalf("bad: %#v", backups)
+	}
+	testStateOutput(t, backups[0], testStateMvExisting_stateSrcOriginal)
+
+	backups = testStateBackups(t, filepath.Dir(stateOutPath))
+	if len(backups) != 1 {
+		t.Fatalf("bad: %#v", backups)
+	}
+	testStateOutput(t, backups[0], testStateMvExisting_stateDstOriginal)
+}
+
+func TestStateMv_noState(t *testing.T) {
+	testCwd(t)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{"from", "to"}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+}
+
+func TestStateMv_stateOutNew_count(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.IntKey(1)).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "bar",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+	stateOutPath := statePath + ".out"
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-state-out", stateOutPath,
+		"test_instance.foo",
+		"test_instance.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, stateOutPath, testStateMvCount_stateOut)
+	testStateOutput(t, statePath, testStateMvCount_stateOutSrc)
+
+	// Test we have backups
+	backups := testStateBackups(t, filepath.Dir(statePath))
+	if len(backups) != 1 {
+		t.Fatalf("bad: %#v", backups)
+	}
+	testStateOutput(t, backups[0], testStateMvCount_stateOutOriginal)
+}
+
+// Modules with more than 10 resources were sorted lexically, causing the
+// indexes in the new location to change.
+func TestStateMv_stateOutNew_largeCount(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		// test_instance.foo has 11 instances, all the same except for their ids
+		for i := 0; i < 11; i++ {
+			s.SetResourceInstanceCurrent(
+				addrs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "test_instance",
+					Name: "foo",
+				}.Instance(addrs.IntKey(i)).Absolute(addrs.RootModuleInstance),
+				&states.ResourceInstanceObjectSrc{
+					AttrsJSON: []byte(fmt.Sprintf(`{"id":"foo%d","foo":"value","bar":"value"}`, i)),
+					Status:    states.ObjectReady,
+				},
+				addrs.AbsProviderConfig{
+					Provider: addrs.NewDefaultProvider("test"),
+					Module:   addrs.RootModule,
+				},
+			)
+		}
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "bar",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+	stateOutPath := statePath + ".out"
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-state-out", stateOutPath,
+		"test_instance.foo",
+		"test_instance.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, stateOutPath, testStateMvLargeCount_stateOut)
+	testStateOutput(t, statePath, testStateMvLargeCount_stateOutSrc)
+
+	// Test we have backups
+	backups := testStateBackups(t, filepath.Dir(statePath))
+	if len(backups) != 1 {
+		t.Fatalf("bad: %#v", backups)
+	}
+	testStateOutput(t, backups[0], testStateMvLargeCount_stateOutOriginal)
+}
+
+func TestStateMv_stateOutNew_nestedModule(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("foo", addrs.NoKey).Child("child1", addrs.NoKey)),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("foo", addrs.NoKey).Child("child2", addrs.NoKey)),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	statePath := testStateFile(t, state)
+	stateOutPath := statePath + ".out"
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-state-out", stateOutPath,
+		"module.foo",
+		"module.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, stateOutPath, testStateMvNestedModule_stateOut)
+	testStateOutput(t, statePath, testStateMvNestedModule_stateOutSrc)
+
+	// Test we have backups
+	backups := testStateBackups(t, filepath.Dir(statePath))
+	if len(backups) != 1 {
+		t.Fatalf("bad: %#v", backups)
+	}
+	testStateOutput(t, backups[0], testStateMvNestedModule_stateOutOriginal)
+}
+
+func TestStateMv_toNewModule(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "bar",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	statePath := testStateFile(t, state)
+	stateOutPath1 := statePath + ".out1"
+	stateOutPath2 := statePath + ".out2"
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"-state-out", stateOutPath1,
+		"test_instance.bar",
+		"module.bar.test_instance.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, stateOutPath1, testStateMvNewModule_stateOut)
+	testStateOutput(t, statePath, testStateMvNestedModule_stateOutSrc)
+
+	// Test we have backups
+	backups := testStateBackups(t, filepath.Dir(statePath))
+	if len(backups) != 1 {
+		t.Fatalf("bad: %#v", backups)
+	}
+	testStateOutput(t, backups[0], testStateMvNewModule_stateOutOriginal)
+
+	// now verify we can move the module itself
+	args = []string{
+		"-state", stateOutPath1,
+		"-state-out", stateOutPath2,
+		"module.bar",
+		"module.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+	testStateOutput(t, stateOutPath2, testStateMvModuleNewModule_stateOut)
+}
+
+func TestStateMv_withinBackend(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-unchanged"), td)
+	defer testChdir(t, td)()
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "baz",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON:    []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:       states.ObjectReady,
+				Dependencies: []addrs.ConfigResource{mustResourceAddr("test_instance.foo")},
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	// the local backend state file is "foo"
+	statePath := "local-state.tfstate"
+	backupPath := "local-state.backup"
+
+	f, err := os.Create(statePath)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+
+	if err := writeStateForTesting(state, f); err != nil {
+		t.Fatal(err)
+	}
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-backup", backupPath,
+		"test_instance.foo",
+		"test_instance.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	testStateOutput(t, statePath, testStateMvOutput)
+	testStateOutput(t, backupPath, testStateMvOutputOriginal)
+}
+
+func TestStateMv_fromBackendToLocal(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-unchanged"), td)
+	defer testChdir(t, td)()
+
+	state := states.NewState()
+	state.Module(addrs.RootModuleInstance).SetResourceInstanceCurrent(
+		mustResourceAddr("test_instance.foo").Resource.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+			Status:    states.ObjectReady,
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	state.Module(addrs.RootModuleInstance).SetResourceInstanceCurrent(
+		mustResourceAddr("test_instance.baz").Resource.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+			Status:    states.ObjectReady,
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	// the local backend state file is "foo"
+	statePath := "local-state.tfstate"
+
+	// real "local" state file
+	statePathOut := "real-local.tfstate"
+
+	f, err := os.Create(statePath)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+
+	if err := writeStateForTesting(state, f); err != nil {
+		t.Fatal(err)
+	}
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state-out", statePathOut,
+		"test_instance.foo",
+		"test_instance.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	testStateOutput(t, statePathOut, testStateMvCount_stateOutSrc)
+
+	// the backend state should be left with only baz
+	testStateOutput(t, statePath, testStateMvOriginal_backend)
+}
+
+// This test covers moving the only resource in a module to a new address in
+// that module, which triggers the maybePruneModule functionality. This caused
+// a panic report: https://github.com/hashicorp/terraform/issues/25520
+func TestStateMv_onlyResourceInModule(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance.Child("foo", addrs.NoKey)),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	statePath := testStateFile(t, state)
+	testStateOutput(t, statePath, testStateMvOnlyResourceInModule_original)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"module.foo.test_instance.foo",
+		"module.foo.test_instance.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, statePath, testStateMvOnlyResourceInModule_output)
+
+	// Test we have backups
+	backups := testStateBackups(t, filepath.Dir(statePath))
+	if len(backups) != 1 {
+		t.Fatalf("bad: %#v", backups)
+	}
+	testStateOutput(t, backups[0], testStateMvOnlyResourceInModule_original)
+}
+
+func TestStateMvHelp(t *testing.T) {
+	c := &StateMvCommand{}
+	if strings.ContainsRune(c.Help(), '\t') {
+		t.Fatal("help text contains tab character, which will result in poor formatting")
+	}
+}
+
+func TestStateMvInvalidSourceAddress(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"foo.bar1",
+		"foo.bar2",
+	}
+	code := c.Run(args)
+	if code != 1 {
+		t.Fatalf("expected error code 1, got:\n%d", code)
+	}
+}
+
+func TestStateMv_checkRequiredVersion(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("command-check-required-version"), td)
+	defer testChdir(t, td)()
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "baz",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON:    []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:       states.ObjectReady,
+				Dependencies: []addrs.ConfigResource{mustResourceAddr("test_instance.foo")},
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateMvCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+		"test_instance.bar",
+	}
+
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
+	}
+
+	// State is unchanged
+	testStateOutput(t, statePath, testStateMvOutputOriginal)
+
+	// Required version diags are correct
+	errStr := ui.ErrorWriter.String()
+	if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) {
+		t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr)
+	}
+	if strings.Contains(errStr, `required_version = ">= 0.13.0"`) {
+		t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr)
+	}
+}
+
+const testStateMvOutputOriginal = `
+test_instance.baz:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+
+  Dependencies:
+    test_instance.foo
+test_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
+
+const testStateMvOutput = `
+test_instance.bar:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.baz:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
+
+const testStateMvBackupAndBackupOutOptionsWithNonLocalBackendOutput = `
+test_instance.bar:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
+
+const testStateMvCount_stateOut = `
+test_instance.bar.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.bar.1:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
+
+const testStateMvCount_stateOutSrc = `
+test_instance.bar:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
+
+const testStateMvCount_stateOutOriginal = `
+test_instance.bar:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.foo.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.foo.1:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
+
+const testStateMvLargeCount_stateOut = `
+test_instance.bar.0:
+  ID = foo0
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.bar.1:
+  ID = foo1
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.bar.2:
+  ID = foo2
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.bar.3:
+  ID = foo3
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.bar.4:
+  ID = foo4
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.bar.5:
+  ID = foo5
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.bar.6:
+  ID = foo6
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.bar.7:
+  ID = foo7
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.bar.8:
+  ID = foo8
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.bar.9:
+  ID = foo9
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.bar.10:
+  ID = foo10
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
+
+const testStateMvLargeCount_stateOutSrc = `
+test_instance.bar:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
+
+const testStateMvLargeCount_stateOutOriginal = `
+test_instance.bar:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.foo.0:
+  ID = foo0
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.foo.1:
+  ID = foo1
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.foo.2:
+  ID = foo2
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.foo.3:
+  ID = foo3
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.foo.4:
+  ID = foo4
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.foo.5:
+  ID = foo5
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.foo.6:
+  ID = foo6
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.foo.7:
+  ID = foo7
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.foo.8:
+  ID = foo8
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.foo.9:
+  ID = foo9
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.foo.10:
+  ID = foo10
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
+
+const testStateMvNestedModule_stateOut = `
+<no state>
+module.bar.child1:
+  test_instance.foo:
+    ID = bar
+    provider = provider["registry.terraform.io/hashicorp/test"]
+    bar = value
+    foo = value
+module.bar.child2:
+  test_instance.foo:
+    ID = bar
+    provider = provider["registry.terraform.io/hashicorp/test"]
+    bar = value
+    foo = value
+`
+
+const testStateMvNewModule_stateOut = `
+<no state>
+module.bar:
+  test_instance.bar:
+    ID = bar
+    provider = provider["registry.terraform.io/hashicorp/test"]
+    bar = value
+    foo = value
+`
+
+const testStateMvModuleNewModule_stateOut = `
+<no state>
+module.foo:
+  test_instance.bar:
+    ID = bar
+    provider = provider["registry.terraform.io/hashicorp/test"]
+    bar = value
+    foo = value
+`
+
+const testStateMvNewModule_stateOutOriginal = `
+test_instance.bar:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
+
+const testStateMvNestedModule_stateOutSrc = `
+<no state>
+`
+
+const testStateMvNestedModule_stateOutOriginal = `
+<no state>
+module.foo.child1:
+  test_instance.foo:
+    ID = bar
+    provider = provider["registry.terraform.io/hashicorp/test"]
+    bar = value
+    foo = value
+module.foo.child2:
+  test_instance.foo:
+    ID = bar
+    provider = provider["registry.terraform.io/hashicorp/test"]
+    bar = value
+    foo = value
+`
+
+const testStateMvOutput_stateOut = `
+test_instance.bar:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
+
+const testStateMvOutput_stateOutSrc = `
+<no state>
+`
+
+const testStateMvOutput_stateOutOriginal = `
+test_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
+
+const testStateMvExisting_stateSrc = `
+<no state>
+`
+
+const testStateMvExisting_stateDst = `
+test_instance.bar:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.qux:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+`
+
+const testStateMvExisting_stateSrcOriginal = `
+test_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
+
+const testStateMvExisting_stateDstOriginal = `
+test_instance.qux:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+`
+
+const testStateMvOriginal_backend = `
+test_instance.baz:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
+
+const testStateMvOnlyResourceInModule_original = `
+<no state>
+module.foo:
+  test_instance.foo.0:
+    ID = bar
+    provider = provider["registry.terraform.io/hashicorp/test"]
+    bar = value
+    foo = value
+`
+
+const testStateMvOnlyResourceInModule_output = `
+<no state>
+module.foo:
+  test_instance.bar.0:
+    ID = bar
+    provider = provider["registry.terraform.io/hashicorp/test"]
+    bar = value
+    foo = value
+`
diff --git a/v1.5.7/internal/command/state_pull.go b/v1.5.7/internal/command/state_pull.go
new file mode 100644
index 0000000..1f9a6df
--- /dev/null
+++ b/v1.5.7/internal/command/state_pull.go
@@ -0,0 +1,97 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+// StatePullCommand is a Command implementation that shows a single resource.
+type StatePullCommand struct {
+	Meta
+	StateMeta
+}
+
+func (c *StatePullCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	cmdFlags := c.Meta.defaultFlagSet("state pull")
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	if diags := c.Meta.checkRequiredVersion(); diags != nil {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(nil)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(backendDiags)
+		return 1
+	}
+
+	// This is a read-only command
+	c.ignoreRemoteVersionConflict(b)
+
+	// Get the state manager for the current workspace
+	env, err := c.Workspace()
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err))
+		return 1
+	}
+	stateMgr, err := b.StateMgr(env)
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
+		return 1
+	}
+	if err := stateMgr.RefreshState(); err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to refresh state: %s", err))
+		return 1
+	}
+
+	// Get a statefile object representing the latest snapshot
+	stateFile := statemgr.Export(stateMgr)
+
+	if stateFile != nil { // we produce no output if the statefile is nil
+		var buf bytes.Buffer
+		err = statefile.Write(stateFile, &buf)
+		if err != nil {
+			c.Ui.Error(fmt.Sprintf("Failed to write state: %s", err))
+			return 1
+		}
+
+		c.Ui.Output(buf.String())
+	}
+
+	return 0
+}
+
+func (c *StatePullCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] state pull [options]
+
+  Pull the state from its location, upgrade the local copy, and output it
+  to stdout.
+
+  This command "pulls" the current state and outputs it to stdout.
+  As part of this process, Terraform will upgrade the state format of the
+  local copy to the current version.
+
+  The primary use of this is for state stored remotely. This command
+  will still work with local state but is less useful for this.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *StatePullCommand) Synopsis() string {
+	return "Pull current state and output to stdout"
+}
diff --git a/v1.5.7/internal/command/state_pull_test.go b/v1.5.7/internal/command/state_pull_test.go
new file mode 100644
index 0000000..319f38a
--- /dev/null
+++ b/v1.5.7/internal/command/state_pull_test.go
@@ -0,0 +1,97 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"io/ioutil"
+	"strings"
+	"testing"
+
+	"github.com/mitchellh/cli"
+)
+
+func TestStatePull(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("state-pull-backend"), td)
+	defer testChdir(t, td)()
+
+	expected, err := ioutil.ReadFile("local-state.tfstate")
+	if err != nil {
+		t.Fatalf("error reading state: %v", err)
+	}
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	c := &StatePullCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	actual := ui.OutputWriter.Bytes()
+	if bytes.Equal(actual, expected) {
+		t.Fatalf("expected:\n%s\n\nto include: %q", actual, expected)
+	}
+}
+
+func TestStatePull_noState(t *testing.T) {
+	testCwd(t)
+
+	p := testProvider()
+	ui := cli.NewMockUi()
+	c := &StatePullCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	actual := ui.OutputWriter.String()
+	if actual != "" {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+func TestStatePull_checkRequiredVersion(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("command-check-required-version"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	ui := cli.NewMockUi()
+	c := &StatePullCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+		},
+	}
+
+	args := []string{}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
+	}
+
+	// Required version diags are correct
+	errStr := ui.ErrorWriter.String()
+	if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) {
+		t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr)
+	}
+	if strings.Contains(errStr, `required_version = ">= 0.13.0"`) {
+		t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr)
+	}
+}
diff --git a/v1.5.7/internal/command/state_push.go b/v1.5.7/internal/command/state_push.go
new file mode 100644
index 0000000..7a9e3cc
--- /dev/null
+++ b/v1.5.7/internal/command/state_push.go
@@ -0,0 +1,190 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/mitchellh/cli"
+)
+
+// StatePushCommand is a Command implementation that shows a single resource.
+type StatePushCommand struct {
+	Meta
+	StateMeta
+}
+
+func (c *StatePushCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	var flagForce bool
+	cmdFlags := c.Meta.ignoreRemoteVersionFlagSet("state push")
+	cmdFlags.BoolVar(&flagForce, "force", false, "")
+	cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
+	cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+	args = cmdFlags.Args()
+
+	if len(args) != 1 {
+		c.Ui.Error("Exactly one argument expected.\n")
+		return cli.RunResultHelp
+	}
+
+	if diags := c.Meta.checkRequiredVersion(); diags != nil {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Determine our reader for the input state. This is the filepath
+	// or stdin if "-" is given.
+	var r io.Reader = os.Stdin
+	if args[0] != "-" {
+		f, err := os.Open(args[0])
+		if err != nil {
+			c.Ui.Error(err.Error())
+			return 1
+		}
+
+		// Note: we don't need to defer a Close here because we do a close
+		// automatically below directly after the read.
+
+		r = f
+	}
+
+	// Read the state
+	srcStateFile, err := statefile.Read(r)
+	if c, ok := r.(io.Closer); ok {
+		// Close the reader if possible right now since we're done with it.
+		c.Close()
+	}
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Error reading source state %q: %s", args[0], err))
+		return 1
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(nil)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(backendDiags)
+		return 1
+	}
+
+	// Determine the workspace name
+	workspace, err := c.Workspace()
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err))
+		return 1
+	}
+
+	// Check remote Terraform version is compatible
+	remoteVersionDiags := c.remoteVersionCheck(b, workspace)
+	c.showDiagnostics(remoteVersionDiags)
+	if remoteVersionDiags.HasErrors() {
+		return 1
+	}
+
+	// Get the state manager for the currently-selected workspace
+	stateMgr, err := b.StateMgr(workspace)
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to load destination state: %s", err))
+		return 1
+	}
+
+	if c.stateLock {
+		stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
+		if diags := stateLocker.Lock(stateMgr, "state-push"); diags.HasErrors() {
+			c.showDiagnostics(diags)
+			return 1
+		}
+		defer func() {
+			if diags := stateLocker.Unlock(); diags.HasErrors() {
+				c.showDiagnostics(diags)
+			}
+		}()
+	}
+
+	if err := stateMgr.RefreshState(); err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to refresh destination state: %s", err))
+		return 1
+	}
+
+	if srcStateFile == nil {
+		// We'll push a new empty state instead
+		srcStateFile = statemgr.NewStateFile()
+	}
+
+	// Import it, forcing through the lineage/serial if requested and possible.
+	if err := statemgr.Import(srcStateFile, stateMgr, flagForce); err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to write state: %s", err))
+		return 1
+	}
+
+	// Get schemas, if possible, before writing state
+	var schemas *terraform.Schemas
+	var diags tfdiags.Diagnostics
+	if isCloudMode(b) {
+		schemas, diags = c.MaybeGetSchemas(srcStateFile.State, nil)
+	}
+
+	if err := stateMgr.WriteState(srcStateFile.State); err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to write state: %s", err))
+		return 1
+	}
+	if err := stateMgr.PersistState(schemas); err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to persist state: %s", err))
+		return 1
+	}
+
+	c.showDiagnostics(diags)
+	return 0
+}
+
+func (c *StatePushCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] state push [options] PATH
+
+  Update remote state from a local state file at PATH.
+
+  This command "pushes" a local state and overwrites remote state
+  with a local state file. The command will protect you against writing
+  an older serial or a different state file lineage unless you specify the
+  "-force" flag.
+
+  This command works with local state (it will overwrite the local
+  state), but is less useful for this use case.
+
+  If PATH is "-", then this command will read the state to push from stdin.
+  Data from stdin is not streamed to the backend: it is loaded completely
+  (until pipe close), verified, and then pushed.
+
+Options:
+
+  -force              Write the state even if lineages don't match or the
+                      remote serial is higher.
+
+  -lock=false         Don't hold a state lock during the operation. This is
+                      dangerous if others might concurrently run commands
+                      against the same workspace.
+
+  -lock-timeout=0s    Duration to retry a state lock.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *StatePushCommand) Synopsis() string {
+	return "Update remote state from a local state file"
+}
diff --git a/v1.5.7/internal/command/state_push_test.go b/v1.5.7/internal/command/state_push_test.go
new file mode 100644
index 0000000..90e7326
--- /dev/null
+++ b/v1.5.7/internal/command/state_push_test.go
@@ -0,0 +1,319 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/backend/remote-state/inmem"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/mitchellh/cli"
+)
+
+func TestStatePush_empty(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("state-push-good"), td)
+	defer testChdir(t, td)()
+
+	expected := testStateRead(t, "replace.tfstate")
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StatePushCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"replace.tfstate"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	actual := testStateRead(t, "local-state.tfstate")
+	if !actual.Equal(expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestStatePush_lockedState(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("state-push-good"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StatePushCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	unlock, err := testLockState(t, testDataDir, "local-state.tfstate")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer unlock()
+
+	args := []string{"replace.tfstate"}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad: %d", code)
+	}
+	if !strings.Contains(ui.ErrorWriter.String(), "Error acquiring the state lock") {
+		t.Fatalf("expected a lock error, got: %s", ui.ErrorWriter.String())
+	}
+}
+
+func TestStatePush_replaceMatch(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("state-push-replace-match"), td)
+	defer testChdir(t, td)()
+
+	expected := testStateRead(t, "replace.tfstate")
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StatePushCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"replace.tfstate"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	actual := testStateRead(t, "local-state.tfstate")
+	if !actual.Equal(expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestStatePush_replaceMatchStdin(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("state-push-replace-match"), td)
+	defer testChdir(t, td)()
+
+	expected := testStateRead(t, "replace.tfstate")
+
+	// Set up the replacement to come from stdin
+	var buf bytes.Buffer
+	if err := writeStateForTesting(expected, &buf); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer testStdinPipe(t, &buf)()
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StatePushCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"-force", "-"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	actual := testStateRead(t, "local-state.tfstate")
+	if !actual.Equal(expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestStatePush_lineageMismatch(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("state-push-bad-lineage"), td)
+	defer testChdir(t, td)()
+
+	expected := testStateRead(t, "local-state.tfstate")
+
+	p := testProvider()
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	c := &StatePushCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"replace.tfstate"}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	actual := testStateRead(t, "local-state.tfstate")
+	if !actual.Equal(expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestStatePush_serialNewer(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("state-push-serial-newer"), td)
+	defer testChdir(t, td)()
+
+	expected := testStateRead(t, "local-state.tfstate")
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StatePushCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"replace.tfstate"}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad: %d", code)
+	}
+
+	actual := testStateRead(t, "local-state.tfstate")
+	if !actual.Equal(expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestStatePush_serialOlder(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("state-push-serial-older"), td)
+	defer testChdir(t, td)()
+
+	expected := testStateRead(t, "replace.tfstate")
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StatePushCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"replace.tfstate"}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	actual := testStateRead(t, "local-state.tfstate")
+	if !actual.Equal(expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestStatePush_forceRemoteState(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("inmem-backend"), td)
+	defer testChdir(t, td)()
+	defer inmem.Reset()
+
+	s := states.NewState()
+	statePath := testStateFile(t, s)
+
+	// init the backend
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	initCmd := &InitCommand{
+		Meta: Meta{Ui: ui, View: view},
+	}
+	if code := initCmd.Run([]string{}); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	// create a new workspace
+	ui = new(cli.MockUi)
+	newCmd := &WorkspaceNewCommand{
+		Meta: Meta{Ui: ui, View: view},
+	}
+	if code := newCmd.Run([]string{"test"}); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
+	}
+
+	// put a dummy state in place, so we have something to force
+	b := backend.TestBackendConfig(t, inmem.New(), nil)
+	sMgr, err := b.StateMgr("test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := sMgr.WriteState(states.NewState()); err != nil {
+		t.Fatal(err)
+	}
+	if err := sMgr.PersistState(nil); err != nil {
+		t.Fatal(err)
+	}
+
+	// push our local state to that new workspace
+	ui = new(cli.MockUi)
+	c := &StatePushCommand{
+		Meta: Meta{Ui: ui, View: view},
+	}
+
+	args := []string{"-force", statePath}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+}
+
+func TestStatePush_checkRequiredVersion(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("command-check-required-version"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	c := &StatePushCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"replace.tfstate"}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
+	}
+
+	// Required version diags are correct
+	errStr := ui.ErrorWriter.String()
+	if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) {
+		t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr)
+	}
+	if strings.Contains(errStr, `required_version = ">= 0.13.0"`) {
+		t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr)
+	}
+}
diff --git a/v1.5.7/internal/command/state_replace_provider.go b/v1.5.7/internal/command/state_replace_provider.go
new file mode 100644
index 0000000..f30d988
--- /dev/null
+++ b/v1.5.7/internal/command/state_replace_provider.go
@@ -0,0 +1,225 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/mitchellh/cli"
+)
+
+// StateReplaceProviderCommand is a Command implementation that allows users
+// to change the provider associated with existing resources. This is only
+// likely to be useful if a provider is forked or changes its fully-qualified
+// name.
+
+type StateReplaceProviderCommand struct {
+	StateMeta
+}
+
+func (c *StateReplaceProviderCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+
+	var autoApprove bool
+	cmdFlags := c.Meta.ignoreRemoteVersionFlagSet("state replace-provider")
+	cmdFlags.BoolVar(&autoApprove, "auto-approve", false, "skip interactive approval of replacements")
+	cmdFlags.StringVar(&c.backupPath, "backup", "-", "backup")
+	cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock states")
+	cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
+	cmdFlags.StringVar(&c.statePath, "state", "", "path")
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return cli.RunResultHelp
+	}
+	args = cmdFlags.Args()
+	if len(args) != 2 {
+		c.Ui.Error("Exactly two arguments expected.\n")
+		return cli.RunResultHelp
+	}
+
+	if diags := c.Meta.checkRequiredVersion(); diags != nil {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	// Parse from/to arguments into providers
+	from, fromDiags := addrs.ParseProviderSourceString(args[0])
+	if fromDiags.HasErrors() {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			fmt.Sprintf(`Invalid "from" provider %q`, args[0]),
+			fromDiags.Err().Error(),
+		))
+	}
+	to, toDiags := addrs.ParseProviderSourceString(args[1])
+	if toDiags.HasErrors() {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			fmt.Sprintf(`Invalid "to" provider %q`, args[1]),
+			toDiags.Err().Error(),
+		))
+	}
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Initialize the state manager as configured
+	stateMgr, err := c.State()
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
+		return 1
+	}
+
+	// Acquire lock if requested
+	if c.stateLock {
+		stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
+		if diags := stateLocker.Lock(stateMgr, "state-replace-provider"); diags.HasErrors() {
+			c.showDiagnostics(diags)
+			return 1
+		}
+		defer func() {
+			if diags := stateLocker.Unlock(); diags.HasErrors() {
+				c.showDiagnostics(diags)
+			}
+		}()
+	}
+
+	// Refresh and load state
+	if err := stateMgr.RefreshState(); err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to refresh source state: %s", err))
+		return 1
+	}
+
+	state := stateMgr.State()
+	if state == nil {
+		c.Ui.Error(errStateNotFound)
+		return 1
+	}
+
+	// Fetch all resources from the state
+	resources, diags := c.lookupAllResources(state)
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	var willReplace []*states.Resource
+
+	// Update all matching resources with new provider
+	for _, resource := range resources {
+		if resource.ProviderConfig.Provider.Equals(from) {
+			willReplace = append(willReplace, resource)
+		}
+	}
+	c.showDiagnostics(diags)
+
+	if len(willReplace) == 0 {
+		c.Ui.Output("No matching resources found.")
+		return 0
+	}
+
+	// Explain the changes
+	colorize := c.Colorize()
+	c.Ui.Output("Terraform will perform the following actions:\n")
+	c.Ui.Output(colorize.Color("  [yellow]~[reset] Updating provider:"))
+	c.Ui.Output(colorize.Color(fmt.Sprintf("    [red]-[reset] %s", from)))
+	c.Ui.Output(colorize.Color(fmt.Sprintf("    [green]+[reset] %s\n", to)))
+
+	c.Ui.Output(colorize.Color(fmt.Sprintf("[bold]Changing[reset] %d resources:\n", len(willReplace))))
+	for _, resource := range willReplace {
+		c.Ui.Output(colorize.Color(fmt.Sprintf("  %s", resource.Addr)))
+	}
+
+	// Confirm
+	if !autoApprove {
+		c.Ui.Output(colorize.Color(
+			"\n[bold]Do you want to make these changes?[reset]\n" +
+				"Only 'yes' will be accepted to continue.\n",
+		))
+		v, err := c.Ui.Ask("Enter a value:")
+		if err != nil {
+			c.Ui.Error(fmt.Sprintf("Error asking for approval: %s", err))
+			return 1
+		}
+		if v != "yes" {
+			c.Ui.Output("Cancelled replacing providers.")
+			return 0
+		}
+	}
+
+	// Update the provider for each resource
+	for _, resource := range willReplace {
+		resource.ProviderConfig.Provider = to
+	}
+
+	b, backendDiags := c.Backend(nil)
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Get schemas, if possible, before writing state
+	var schemas *terraform.Schemas
+	if isCloudMode(b) {
+		var schemaDiags tfdiags.Diagnostics
+		schemas, schemaDiags = c.MaybeGetSchemas(state, nil)
+		diags = diags.Append(schemaDiags)
+	}
+
+	// Write the updated state
+	if err := stateMgr.WriteState(state); err != nil {
+		c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
+		return 1
+	}
+	if err := stateMgr.PersistState(schemas); err != nil {
+		c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
+		return 1
+	}
+
+	c.showDiagnostics(diags)
+	c.Ui.Output(fmt.Sprintf("\nSuccessfully replaced provider for %d resources.", len(willReplace)))
+	return 0
+}
+
+func (c *StateReplaceProviderCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] state replace-provider [options] FROM_PROVIDER_FQN TO_PROVIDER_FQN
+
+  Replace provider for resources in the Terraform state.
+
+Options:
+
+  -auto-approve           Skip interactive approval.
+
+  -lock=false             Don't hold a state lock during the operation. This is
+                          dangerous if others might concurrently run commands
+                          against the same workspace.
+
+  -lock-timeout=0s        Duration to retry a state lock.
+
+  -ignore-remote-version  A rare option used for the remote backend only. See
+                          the remote backend documentation for more information.
+
+  -state, state-out, and -backup are legacy options supported for the local
+  backend only. For more information, see the local backend's documentation.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *StateReplaceProviderCommand) Synopsis() string {
+	return "Replace provider in the state"
+}
diff --git a/v1.5.7/internal/command/state_replace_provider_test.go b/v1.5.7/internal/command/state_replace_provider_test.go
new file mode 100644
index 0000000..d80bc85
--- /dev/null
+++ b/v1.5.7/internal/command/state_replace_provider_test.go
@@ -0,0 +1,425 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/mitchellh/cli"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestStateReplaceProvider(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "alpha",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"alpha","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "beta",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"beta","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "azurerm_virtual_machine",
+				Name: "gamma",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"gamma","baz":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewLegacyProvider("azurerm"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	t.Run("happy path", func(t *testing.T) {
+		statePath := testStateFile(t, state)
+
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &StateReplaceProviderCommand{
+			StateMeta{
+				Meta: Meta{
+					Ui:   ui,
+					View: view,
+				},
+			},
+		}
+
+		inputBuf := &bytes.Buffer{}
+		ui.InputReader = inputBuf
+		inputBuf.WriteString("yes\n")
+
+		args := []string{
+			"-state", statePath,
+			"hashicorp/aws",
+			"acmecorp/aws",
+		}
+		if code := c.Run(args); code != 0 {
+			t.Fatalf("return code: %d\n\n%s", code, ui.ErrorWriter.String())
+		}
+
+		testStateOutput(t, statePath, testStateReplaceProviderOutput)
+
+		backups := testStateBackups(t, filepath.Dir(statePath))
+		if len(backups) != 1 {
+			t.Fatalf("unexpected backups: %#v", backups)
+		}
+		testStateOutput(t, backups[0], testStateReplaceProviderOutputOriginal)
+	})
+
+	t.Run("auto approve", func(t *testing.T) {
+		statePath := testStateFile(t, state)
+
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &StateReplaceProviderCommand{
+			StateMeta{
+				Meta: Meta{
+					Ui:   ui,
+					View: view,
+				},
+			},
+		}
+
+		inputBuf := &bytes.Buffer{}
+		ui.InputReader = inputBuf
+
+		args := []string{
+			"-state", statePath,
+			"-auto-approve",
+			"hashicorp/aws",
+			"acmecorp/aws",
+		}
+		if code := c.Run(args); code != 0 {
+			t.Fatalf("return code: %d\n\n%s", code, ui.ErrorWriter.String())
+		}
+
+		testStateOutput(t, statePath, testStateReplaceProviderOutput)
+
+		backups := testStateBackups(t, filepath.Dir(statePath))
+		if len(backups) != 1 {
+			t.Fatalf("unexpected backups: %#v", backups)
+		}
+		testStateOutput(t, backups[0], testStateReplaceProviderOutputOriginal)
+	})
+
+	t.Run("cancel at approval step", func(t *testing.T) {
+		statePath := testStateFile(t, state)
+
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &StateReplaceProviderCommand{
+			StateMeta{
+				Meta: Meta{
+					Ui:   ui,
+					View: view,
+				},
+			},
+		}
+
+		inputBuf := &bytes.Buffer{}
+		ui.InputReader = inputBuf
+		inputBuf.WriteString("no\n")
+
+		args := []string{
+			"-state", statePath,
+			"hashicorp/aws",
+			"acmecorp/aws",
+		}
+		if code := c.Run(args); code != 0 {
+			t.Fatalf("return code: %d\n\n%s", code, ui.ErrorWriter.String())
+		}
+
+		testStateOutput(t, statePath, testStateReplaceProviderOutputOriginal)
+
+		backups := testStateBackups(t, filepath.Dir(statePath))
+		if len(backups) != 0 {
+			t.Fatalf("unexpected backups: %#v", backups)
+		}
+	})
+
+	t.Run("no matching provider found", func(t *testing.T) {
+		statePath := testStateFile(t, state)
+
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &StateReplaceProviderCommand{
+			StateMeta{
+				Meta: Meta{
+					Ui:   ui,
+					View: view,
+				},
+			},
+		}
+
+		args := []string{
+			"-state", statePath,
+			"hashicorp/google",
+			"acmecorp/google",
+		}
+		if code := c.Run(args); code != 0 {
+			t.Fatalf("return code: %d\n\n%s", code, ui.ErrorWriter.String())
+		}
+
+		testStateOutput(t, statePath, testStateReplaceProviderOutputOriginal)
+
+		backups := testStateBackups(t, filepath.Dir(statePath))
+		if len(backups) != 0 {
+			t.Fatalf("unexpected backups: %#v", backups)
+		}
+	})
+
+	t.Run("invalid flags", func(t *testing.T) {
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &StateReplaceProviderCommand{
+			StateMeta{
+				Meta: Meta{
+					Ui:   ui,
+					View: view,
+				},
+			},
+		}
+
+		args := []string{
+			"-invalid",
+			"hashicorp/google",
+			"acmecorp/google",
+		}
+		if code := c.Run(args); code == 0 {
+			t.Fatalf("successful exit; want error")
+		}
+
+		if got, want := ui.ErrorWriter.String(), "Error parsing command-line flags"; !strings.Contains(got, want) {
+			t.Fatalf("missing expected error message\nwant: %s\nfull output:\n%s", want, got)
+		}
+	})
+
+	t.Run("wrong number of arguments", func(t *testing.T) {
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &StateReplaceProviderCommand{
+			StateMeta{
+				Meta: Meta{
+					Ui:   ui,
+					View: view,
+				},
+			},
+		}
+
+		args := []string{"a", "b", "c", "d"}
+		if code := c.Run(args); code == 0 {
+			t.Fatalf("successful exit; want error")
+		}
+
+		if got, want := ui.ErrorWriter.String(), "Exactly two arguments expected"; !strings.Contains(got, want) {
+			t.Fatalf("missing expected error message\nwant: %s\nfull output:\n%s", want, got)
+		}
+	})
+
+	t.Run("invalid provider strings", func(t *testing.T) {
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		c := &StateReplaceProviderCommand{
+			StateMeta{
+				Meta: Meta{
+					Ui:   ui,
+					View: view,
+				},
+			},
+		}
+
+		args := []string{
+			"hashicorp/google_cloud",
+			"-/-/google",
+		}
+		if code := c.Run(args); code == 0 {
+			t.Fatalf("successful exit; want error")
+		}
+
+		got := ui.ErrorWriter.String()
+		msgs := []string{
+			`Invalid "from" provider "hashicorp/google_cloud"`,
+			"Invalid provider type",
+			`Invalid "to" provider "-/-/google"`,
+			"Invalid provider source hostname",
+		}
+		for _, msg := range msgs {
+			if !strings.Contains(got, msg) {
+				t.Errorf("missing expected error message\nwant: %s\nfull output:\n%s", msg, got)
+			}
+		}
+	})
+}
+
+func TestStateReplaceProvider_docs(t *testing.T) {
+	c := &StateReplaceProviderCommand{}
+
+	if got, want := c.Help(), "Usage: terraform [global options] state replace-provider"; !strings.Contains(got, want) {
+		t.Fatalf("unexpected help text\nwant: %s\nfull output:\n%s", want, got)
+	}
+
+	if got, want := c.Synopsis(), "Replace provider in the state"; got != want {
+		t.Fatalf("unexpected synopsis\nwant: %s\nfull output:\n%s", want, got)
+	}
+}
+
+func TestStateReplaceProvider_checkRequiredVersion(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("command-check-required-version"), td)
+	defer testChdir(t, td)()
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "alpha",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"alpha","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "beta",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"beta","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "azurerm_virtual_machine",
+				Name: "gamma",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"gamma","baz":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewLegacyProvider("azurerm"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	statePath := testStateFile(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateReplaceProviderCommand{
+		StateMeta{
+			Meta: Meta{
+				Ui:   ui,
+				View: view,
+			},
+		},
+	}
+
+	inputBuf := &bytes.Buffer{}
+	ui.InputReader = inputBuf
+	inputBuf.WriteString("yes\n")
+
+	args := []string{
+		"-state", statePath,
+		"hashicorp/aws",
+		"acmecorp/aws",
+	}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
+	}
+
+	// State is unchanged
+	testStateOutput(t, statePath, testStateReplaceProviderOutputOriginal)
+
+	// Required version diags are correct
+	errStr := ui.ErrorWriter.String()
+	if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) {
+		t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr)
+	}
+	if strings.Contains(errStr, `required_version = ">= 0.13.0"`) {
+		t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr)
+	}
+}
+
+const testStateReplaceProviderOutputOriginal = `
+aws_instance.alpha:
+  ID = alpha
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  bar = value
+  foo = value
+aws_instance.beta:
+  ID = beta
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  bar = value
+  foo = value
+azurerm_virtual_machine.gamma:
+  ID = gamma
+  provider = provider["registry.terraform.io/-/azurerm"]
+  baz = value
+`
+
+const testStateReplaceProviderOutput = `
+aws_instance.alpha:
+  ID = alpha
+  provider = provider["registry.terraform.io/acmecorp/aws"]
+  bar = value
+  foo = value
+aws_instance.beta:
+  ID = beta
+  provider = provider["registry.terraform.io/acmecorp/aws"]
+  bar = value
+  foo = value
+azurerm_virtual_machine.gamma:
+  ID = gamma
+  provider = provider["registry.terraform.io/-/azurerm"]
+  baz = value
+`
diff --git a/v1.5.7/internal/command/state_rm.go b/v1.5.7/internal/command/state_rm.go
new file mode 100644
index 0000000..c2818e3
--- /dev/null
+++ b/v1.5.7/internal/command/state_rm.go
@@ -0,0 +1,209 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/mitchellh/cli"
+)
+
+// StateRmCommand is a Command implementation that shows a single resource.
+type StateRmCommand struct {
+	StateMeta
+}
+
+func (c *StateRmCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	var dryRun bool
+	cmdFlags := c.Meta.ignoreRemoteVersionFlagSet("state rm")
+	cmdFlags.BoolVar(&dryRun, "dry-run", false, "dry run")
+	cmdFlags.StringVar(&c.backupPath, "backup", "-", "backup")
+	cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
+	cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
+	cmdFlags.StringVar(&c.statePath, "state", "", "path")
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	args = cmdFlags.Args()
+	if len(args) < 1 {
+		c.Ui.Error("At least one address is required.\n")
+		return cli.RunResultHelp
+	}
+
+	if diags := c.Meta.checkRequiredVersion(); diags != nil {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Get the state
+	stateMgr, err := c.State()
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
+		return 1
+	}
+
+	if c.stateLock {
+		stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
+		if diags := stateLocker.Lock(stateMgr, "state-rm"); diags.HasErrors() {
+			c.showDiagnostics(diags)
+			return 1
+		}
+		defer func() {
+			if diags := stateLocker.Unlock(); diags.HasErrors() {
+				c.showDiagnostics(diags)
+			}
+		}()
+	}
+
+	if err := stateMgr.RefreshState(); err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to refresh state: %s", err))
+		return 1
+	}
+
+	state := stateMgr.State()
+	if state == nil {
+		c.Ui.Error(errStateNotFound)
+		return 1
+	}
+
+	// This command primarily works with resource instances, though it will
+	// also clean up any modules and resources left empty by actions it takes.
+	var addrs []addrs.AbsResourceInstance
+	var diags tfdiags.Diagnostics
+	for _, addrStr := range args {
+		moreAddrs, moreDiags := c.lookupResourceInstanceAddr(state, true, addrStr)
+		addrs = append(addrs, moreAddrs...)
+		diags = diags.Append(moreDiags)
+	}
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	prefix := "Removed "
+	if dryRun {
+		prefix = "Would remove "
+	}
+
+	var isCount int
+	ss := state.SyncWrapper()
+	for _, addr := range addrs {
+		isCount++
+		c.Ui.Output(prefix + addr.String())
+		if !dryRun {
+			ss.ForgetResourceInstanceAll(addr)
+			ss.RemoveResourceIfEmpty(addr.ContainingResource())
+		}
+	}
+
+	if dryRun {
+		if isCount == 0 {
+			c.Ui.Output("Would have removed nothing.")
+		}
+		return 0 // This is as far as we go in dry-run mode
+	}
+
+	b, backendDiags := c.Backend(nil)
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Get schemas, if possible, before writing state
+	var schemas *terraform.Schemas
+	if isCloudMode(b) {
+		var schemaDiags tfdiags.Diagnostics
+		schemas, schemaDiags = c.MaybeGetSchemas(state, nil)
+		diags = diags.Append(schemaDiags)
+	}
+
+	if err := stateMgr.WriteState(state); err != nil {
+		c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
+		return 1
+	}
+	if err := stateMgr.PersistState(schemas); err != nil {
+		c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
+		return 1
+	}
+
+	if len(diags) > 0 && isCount != 0 {
+		c.showDiagnostics(diags)
+	}
+
+	if isCount == 0 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid target address",
+			"No matching objects found. To view the available instances, use \"terraform state list\". Please modify the address to reference a specific instance.",
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	c.Ui.Output(fmt.Sprintf("Successfully removed %d resource instance(s).", isCount))
+	return 0
+}
+
+func (c *StateRmCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] state rm [options] ADDRESS...
+
+  Remove one or more items from the Terraform state, causing Terraform to
+  "forget" those items without first destroying them in the remote system.
+
+  This command removes one or more resource instances from the Terraform state
+  based on the addresses given. You can view and list the available instances
+  with "terraform state list".
+
+  If you give the address of an entire module then all of the instances in
+  that module and any of its child modules will be removed from the state.
+
+  If you give the address of a resource that has "count" or "for_each" set,
+  all of the instances of that resource will be removed from the state.
+
+Options:
+
+  -dry-run                If set, prints out what would've been removed but
+                          doesn't actually remove anything.
+
+  -backup=PATH            Path where Terraform should write the backup
+                          state.
+
+  -lock=false             Don't hold a state lock during the operation. This is
+                          dangerous if others might concurrently run commands
+                          against the same workspace.
+
+  -lock-timeout=0s        Duration to retry a state lock.
+
+  -state=PATH             Path to the state file to update. Defaults to the
+                          current workspace state.
+
+  -ignore-remote-version  Continue even if remote and local Terraform versions
+                          are incompatible. This may result in an unusable
+                          workspace, and should be used with extreme caution.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *StateRmCommand) Synopsis() string {
+	return "Remove instances from the state"
+}
+
+const errStateRmPersist = `Error saving the state: %s
+
+The state was not saved. No items were removed from the persisted
+state. No backup was created since no modification occurred. Please
+resolve the issue above and try again.`
diff --git a/v1.5.7/internal/command/state_rm_test.go b/v1.5.7/internal/command/state_rm_test.go
new file mode 100644
index 0000000..fd0b117
--- /dev/null
+++ b/v1.5.7/internal/command/state_rm_test.go
@@ -0,0 +1,582 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/mitchellh/cli"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestStateRm(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "bar",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateRmCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, statePath, testStateRmOutput)
+
+	// Test we have backups
+	backups := testStateBackups(t, filepath.Dir(statePath))
+	if len(backups) != 1 {
+		t.Fatalf("bad: %#v", backups)
+	}
+	testStateOutput(t, backups[0], testStateRmOutputOriginal)
+}
+
+func TestStateRmNotChildModule(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		// This second instance has the same local address as the first but
+		// is in a child module. Older versions of Terraform would incorrectly
+		// remove this one too, since they failed to check the module address.
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey)),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateRmCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, statePath, `
+<no state>
+module.child:
+  test_instance.foo:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/test"]
+    bar = value
+    foo = value
+`)
+
+	// Test we have backups
+	backups := testStateBackups(t, filepath.Dir(statePath))
+	if len(backups) != 1 {
+		t.Fatalf("bad: %#v", backups)
+	}
+	testStateOutput(t, backups[0], `
+test_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+
+module.child:
+  test_instance.foo:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/test"]
+    bar = value
+    foo = value
+`)
+}
+
+func TestStateRmNoArgs(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "bar",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateRmCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+	}
+	if code := c.Run(args); code == 0 {
+		t.Errorf("expected non-zero exit code, got: %d", code)
+	}
+
+	if msg := ui.ErrorWriter.String(); !strings.Contains(msg, "At least one address") {
+		t.Errorf("not the error we were looking for:\n%s", msg)
+	}
+
+}
+
+func TestStateRmNonExist(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "bar",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateRmCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.baz", // doesn't exist in the state constructed above
+	}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("expected exit status %d, got: %d", 1, code)
+	}
+}
+
+func TestStateRm_backupExplicit(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "bar",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+	backupPath := statePath + ".backup.test"
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateRmCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-backup", backupPath,
+		"-state", statePath,
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, statePath, testStateRmOutput)
+
+	// Test backup
+	testStateOutput(t, backupPath, testStateRmOutputOriginal)
+}
+
+func TestStateRm_noState(t *testing.T) {
+	testCwd(t)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateRmCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{"foo"}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+}
+
+func TestStateRm_needsInit(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-change"), td)
+	defer testChdir(t, td)()
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateRmCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{"foo"}
+	if code := c.Run(args); code == 0 {
+		t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String())
+	}
+
+	if !strings.Contains(ui.ErrorWriter.String(), "Backend initialization") {
+		t.Fatalf("expected initialization error, got:\n%s", ui.ErrorWriter.String())
+	}
+}
+
+func TestStateRm_backendState(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-unchanged"), td)
+	defer testChdir(t, td)()
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "bar",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	statePath := "local-state.tfstate"
+	backupPath := "local-state.backup"
+
+	f, err := os.Create(statePath)
+	if err != nil {
+		t.Fatalf("failed to create state file %s: %s", statePath, err)
+	}
+	defer f.Close()
+
+	err = writeStateForTesting(state, f)
+	if err != nil {
+		t.Fatalf("failed to write state to file %s: %s", statePath, err)
+	}
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateRmCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-backup", backupPath,
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Test it is correct
+	testStateOutput(t, statePath, testStateRmOutput)
+
+	// Test backup
+	testStateOutput(t, backupPath, testStateRmOutputOriginal)
+}
+
+func TestStateRm_checkRequiredVersion(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("command-check-required-version"), td)
+	defer testChdir(t, td)()
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "bar",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &StateRmCommand{
+		StateMeta{
+			Meta: Meta{
+				testingOverrides: metaOverridesForProvider(p),
+				Ui:               ui,
+				View:             view,
+			},
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
+	}
+
+	// State is unchanged
+	testStateOutput(t, statePath, testStateRmOutputOriginal)
+
+	// Required version diags are correct
+	errStr := ui.ErrorWriter.String()
+	if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) {
+		t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr)
+	}
+	if strings.Contains(errStr, `required_version = ">= 0.13.0"`) {
+		t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr)
+	}
+}
+
+const testStateRmOutputOriginal = `
+test_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+test_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
+
+const testStateRmOutput = `
+test_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  bar = value
+  foo = value
+`
diff --git a/v1.5.7/internal/command/state_show.go b/v1.5.7/internal/command/state_show.go
new file mode 100644
index 0000000..53f64ab
--- /dev/null
+++ b/v1.5.7/internal/command/state_show.go
@@ -0,0 +1,204 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"os"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/jsonformat"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/command/jsonstate"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/mitchellh/cli"
+)
+
+// StateShowCommand is a Command implementation that shows a single resource.
+type StateShowCommand struct {
+	Meta
+	StateMeta
+}
+
+func (c *StateShowCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	cmdFlags := c.Meta.defaultFlagSet("state show")
+	cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path")
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Streams.Eprintf("Error parsing command-line flags: %s\n", err.Error())
+		return 1
+	}
+	args = cmdFlags.Args()
+	if len(args) != 1 {
+		c.Streams.Eprint("Exactly one argument expected.\n")
+		return cli.RunResultHelp
+	}
+
+	// Check for user-supplied plugin path
+	var err error
+	if c.pluginPath, err = c.loadPluginPath(); err != nil {
+		c.Streams.Eprintf("Error loading plugin path: %\n", err)
+		return 1
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(nil)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(backendDiags)
+		return 1
+	}
+
+	// We require a local backend
+	local, ok := b.(backend.Local)
+	if !ok {
+		c.Streams.Eprint(ErrUnsupportedLocalOp)
+		return 1
+	}
+
+	// This is a read-only command
+	c.ignoreRemoteVersionConflict(b)
+
+	// Check if the address can be parsed
+	addr, addrDiags := addrs.ParseAbsResourceInstanceStr(args[0])
+	if addrDiags.HasErrors() {
+		c.Streams.Eprintln(fmt.Sprintf(errParsingAddress, args[0]))
+		return 1
+	}
+
+	// We expect the config dir to always be the cwd
+	cwd, err := os.Getwd()
+	if err != nil {
+		c.Streams.Eprintf("Error getting cwd: %s\n", err)
+		return 1
+	}
+
+	// Build the operation (required to get the schemas)
+	opReq := c.Operation(b, arguments.ViewHuman)
+	opReq.AllowUnsetVariables = true
+	opReq.ConfigDir = cwd
+
+	opReq.ConfigLoader, err = c.initConfigLoader()
+	if err != nil {
+		c.Streams.Eprintf("Error initializing config loader: %s\n", err)
+		return 1
+	}
+
+	// Get the context (required to get the schemas)
+	lr, _, ctxDiags := local.LocalRun(opReq)
+	if ctxDiags.HasErrors() {
+		c.View.Diagnostics(ctxDiags)
+		return 1
+	}
+
+	// Get the schemas from the context
+	schemas, diags := lr.Core.Schemas(lr.Config, lr.InputState)
+	if diags.HasErrors() {
+		c.View.Diagnostics(diags)
+		return 1
+	}
+
+	// Get the state
+	env, err := c.Workspace()
+	if err != nil {
+		c.Streams.Eprintf("Error selecting workspace: %s\n", err)
+		return 1
+	}
+	stateMgr, err := b.StateMgr(env)
+	if err != nil {
+		c.Streams.Eprintln(fmt.Sprintf(errStateLoadingState, err))
+		return 1
+	}
+	if err := stateMgr.RefreshState(); err != nil {
+		c.Streams.Eprintf("Failed to refresh state: %s\n", err)
+		return 1
+	}
+
+	state := stateMgr.State()
+	if state == nil {
+		c.Streams.Eprintln(errStateNotFound)
+		return 1
+	}
+
+	is := state.ResourceInstance(addr)
+	if !is.HasCurrent() {
+		c.Streams.Eprintln(errNoInstanceFound)
+		return 1
+	}
+
+	// check if the resource has a configured provider, otherwise this will use the default provider
+	rs := state.Resource(addr.ContainingResource())
+	absPc := addrs.AbsProviderConfig{
+		Provider: rs.ProviderConfig.Provider,
+		Alias:    rs.ProviderConfig.Alias,
+		Module:   addrs.RootModule,
+	}
+	singleInstance := states.NewState()
+	singleInstance.EnsureModule(addr.Module).SetResourceInstanceCurrent(
+		addr.Resource,
+		is.Current,
+		absPc,
+	)
+
+	root, outputs, err := jsonstate.MarshalForRenderer(statefile.New(singleInstance, "", 0), schemas)
+	if err != nil {
+		c.Streams.Eprintf("Failed to marshal state to json: %s", err)
+	}
+
+	jstate := jsonformat.State{
+		StateFormatVersion:    jsonstate.FormatVersion,
+		ProviderFormatVersion: jsonprovider.FormatVersion,
+		RootModule:            root,
+		RootModuleOutputs:     outputs,
+		ProviderSchemas:       jsonprovider.MarshalForRenderer(schemas),
+	}
+
+	renderer := jsonformat.Renderer{
+		Streams:             c.Streams,
+		Colorize:            c.Colorize(),
+		RunningInAutomation: c.RunningInAutomation,
+	}
+
+	renderer.RenderHumanState(jstate)
+	return 0
+}
+
+func (c *StateShowCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] state show [options] ADDRESS
+
+  Shows the attributes of a resource in the Terraform state.
+
+  This command shows the attributes of a single resource in the Terraform
+  state. The address argument must be used to specify a single resource.
+  You can view the list of available resources with "terraform state list".
+
+Options:
+
+  -state=statefile    Path to a Terraform state file to use to look
+                      up Terraform-managed resources. By default it will
+                      use the state "terraform.tfstate" if it exists.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *StateShowCommand) Synopsis() string {
+	return "Show a resource in the state"
+}
+
+const errNoInstanceFound = `No instance found for the given address!
+
+This command requires that the address references one specific instance.
+To view the available instances, use "terraform state list". Please modify 
+the address to reference a specific instance.`
+
+const errParsingAddress = `Error parsing instance address: %s
+
+This command requires that the address references one specific instance.
+To view the available instances, use "terraform state list". Please modify 
+the address to reference a specific instance.`
diff --git a/v1.5.7/internal/command/state_show_test.go b/v1.5.7/internal/command/state_show_test.go
new file mode 100644
index 0000000..3d599cc
--- /dev/null
+++ b/v1.5.7/internal/command/state_show_test.go
@@ -0,0 +1,278 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestStateShow(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":  {Type: cty.String, Optional: true, Computed: true},
+						"foo": {Type: cty.String, Optional: true},
+						"bar": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	streams, done := terminal.StreamsForTesting(t)
+	c := &StateShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Streams:          streams,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// Test that outputs were displayed
+	expected := strings.TrimSpace(testStateShowOutput) + "\n"
+	actual := output.Stdout()
+	if actual != expected {
+		t.Fatalf("Expected:\n%q\n\nTo equal:\n%q", actual, expected)
+	}
+}
+
+func TestStateShow_multi(t *testing.T) {
+	submod, _ := addrs.ParseModuleInstanceStr("module.sub")
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(submod),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   submod.Module(),
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":  {Type: cty.String, Optional: true, Computed: true},
+						"foo": {Type: cty.String, Optional: true},
+						"bar": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	streams, done := terminal.StreamsForTesting(t)
+	c := &StateShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Streams:          streams,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// Test that outputs were displayed
+	expected := strings.TrimSpace(testStateShowOutput) + "\n"
+	actual := output.Stdout()
+	if actual != expected {
+		t.Fatalf("Expected:\n%q\n\nTo equal:\n%q", actual, expected)
+	}
+}
+
+func TestStateShow_noState(t *testing.T) {
+	testCwd(t)
+
+	p := testProvider()
+	streams, done := terminal.StreamsForTesting(t)
+	c := &StateShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Streams:          streams,
+		},
+	}
+
+	args := []string{
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad: %d", code)
+	}
+	output := done(t)
+	if !strings.Contains(output.Stderr(), "No state file was found!") {
+		t.Fatalf("expected a no state file error, got: %s", output.Stderr())
+	}
+}
+
+func TestStateShow_emptyState(t *testing.T) {
+	state := states.NewState()
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	streams, done := terminal.StreamsForTesting(t)
+	c := &StateShowCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Streams:          streams,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad: %d", code)
+	}
+	output := done(t)
+	if !strings.Contains(output.Stderr(), "No instance found for the given address!") {
+		t.Fatalf("expected a no instance found error, got: %s", output.Stderr())
+	}
+}
+
+func TestStateShow_configured_provider(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test-beta"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":  {Type: cty.String, Optional: true, Computed: true},
+						"foo": {Type: cty.String, Optional: true},
+						"bar": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	streams, done := terminal.StreamsForTesting(t)
+	c := &StateShowCommand{
+		Meta: Meta{
+			testingOverrides: &testingOverrides{
+				Providers: map[addrs.Provider]providers.Factory{
+					addrs.NewDefaultProvider("test-beta"): providers.FactoryFixed(p),
+				},
+			},
+			Streams: streams,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+	}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
+	}
+
+	// Test that outputs were displayed
+	expected := strings.TrimSpace(testStateShowOutput) + "\n"
+	actual := output.Stdout()
+	if actual != expected {
+		t.Fatalf("Expected:\n%q\n\nTo equal:\n%q", actual, expected)
+	}
+}
+
+const testStateShowOutput = `
+# test_instance.foo:
+resource "test_instance" "foo" {
+    bar = "value"
+    foo = "value"
+    id  = "bar"
+}
+`
diff --git a/v1.5.7/internal/command/state_test.go b/v1.5.7/internal/command/state_test.go
new file mode 100644
index 0000000..fbdf397
--- /dev/null
+++ b/v1.5.7/internal/command/state_test.go
@@ -0,0 +1,43 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"path/filepath"
+	"regexp"
+	"sort"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+// testStateBackups returns the list of backups in order of creation
+// (oldest first) in the given directory.
+func testStateBackups(t *testing.T, dir string) []string {
+	// Find all the backups
+	list, err := filepath.Glob(filepath.Join(dir, "*"+DefaultBackupExtension))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Sort them which will put them naturally in the right order
+	sort.Strings(list)
+
+	return list
+}
+
+func TestStateDefaultBackupExtension(t *testing.T) {
+	testCwd(t)
+
+	s, err := (&StateMeta{}).State()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	backupPath := s.(*statemgr.Filesystem).BackupPath()
+	match := regexp.MustCompile(`terraform\.tfstate\.\d+\.backup$`).MatchString
+	if !match(backupPath) {
+		t.Fatal("Bad backup path:", backupPath)
+	}
+}
diff --git a/v1.5.7/internal/command/taint.go b/v1.5.7/internal/command/taint.go
new file mode 100644
index 0000000..7a4213f
--- /dev/null
+++ b/v1.5.7/internal/command/taint.go
@@ -0,0 +1,253 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// TaintCommand is a cli.Command implementation that manually taints
+// a resource, marking it for recreation.
+type TaintCommand struct {
+	Meta
+}
+
+func (c *TaintCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	var allowMissing bool
+	cmdFlags := c.Meta.ignoreRemoteVersionFlagSet("taint")
+	cmdFlags.BoolVar(&allowMissing, "allow-missing", false, "allow missing")
+	cmdFlags.StringVar(&c.Meta.backupPath, "backup", "", "path")
+	cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
+	cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
+	cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path")
+	cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	// Require the one argument for the resource to taint
+	args = cmdFlags.Args()
+	if len(args) != 1 {
+		c.Ui.Error("The taint command expects exactly one argument.")
+		cmdFlags.Usage()
+		return 1
+	}
+
+	addr, addrDiags := addrs.ParseAbsResourceInstanceStr(args[0])
+	diags = diags.Append(addrDiags)
+	if addrDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	if addr.Resource.Resource.Mode != addrs.ManagedResourceMode {
+		c.Ui.Error(fmt.Sprintf("Resource instance %s cannot be tainted", addr))
+		return 1
+	}
+
+	if diags := c.Meta.checkRequiredVersion(); diags != nil {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(nil)
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Determine the workspace name
+	workspace, err := c.Workspace()
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err))
+		return 1
+	}
+
+	// Check remote Terraform version is compatible
+	remoteVersionDiags := c.remoteVersionCheck(b, workspace)
+	diags = diags.Append(remoteVersionDiags)
+	c.showDiagnostics(diags)
+	if diags.HasErrors() {
+		return 1
+	}
+
+	// Get the state
+	stateMgr, err := b.StateMgr(workspace)
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
+		return 1
+	}
+
+	if c.stateLock {
+		stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
+		if diags := stateLocker.Lock(stateMgr, "taint"); diags.HasErrors() {
+			c.showDiagnostics(diags)
+			return 1
+		}
+		defer func() {
+			if diags := stateLocker.Unlock(); diags.HasErrors() {
+				c.showDiagnostics(diags)
+			}
+		}()
+	}
+
+	if err := stateMgr.RefreshState(); err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
+		return 1
+	}
+
+	// Get the actual state structure
+	state := stateMgr.State()
+	if state.Empty() {
+		if allowMissing {
+			return c.allowMissingExit(addr)
+		}
+
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"No such resource instance",
+			"The state currently contains no resource instances whatsoever. This may occur if the configuration has never been applied or if it has recently been destroyed.",
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Get schemas, if possible, before writing state
+	var schemas *terraform.Schemas
+	if isCloudMode(b) {
+		var schemaDiags tfdiags.Diagnostics
+		schemas, schemaDiags = c.MaybeGetSchemas(state, nil)
+		diags = diags.Append(schemaDiags)
+	}
+
+	ss := state.SyncWrapper()
+
+	// Get the resource and instance we're going to taint
+	rs := ss.Resource(addr.ContainingResource())
+	is := ss.ResourceInstance(addr)
+	if is == nil {
+		if allowMissing {
+			return c.allowMissingExit(addr)
+		}
+
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"No such resource instance",
+			fmt.Sprintf("There is no resource instance in the state with the address %s. If the resource configuration has just been added, you must run \"terraform apply\" once to create the corresponding instance(s) before they can be tainted.", addr),
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	obj := is.Current
+	if obj == nil {
+		if len(is.Deposed) != 0 {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"No such resource instance",
+				fmt.Sprintf("Resource instance %s is currently part-way through a create_before_destroy replacement action. Run \"terraform apply\" to complete its replacement before tainting it.", addr),
+			))
+		} else {
+			// Don't know why we're here, but we'll produce a generic error message anyway.
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"No such resource instance",
+				fmt.Sprintf("Resource instance %s does not currently have a remote object associated with it, so it cannot be tainted.", addr),
+			))
+		}
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	obj.Status = states.ObjectTainted
+	ss.SetResourceInstanceCurrent(addr, obj, rs.ProviderConfig)
+
+	if err := stateMgr.WriteState(state); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
+		return 1
+	}
+	if err := stateMgr.PersistState(schemas); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
+		return 1
+	}
+
+	c.showDiagnostics(diags)
+	c.Ui.Output(fmt.Sprintf("Resource instance %s has been marked as tainted.", addr))
+	return 0
+}
+
+func (c *TaintCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] taint [options] <address>
+
+  Terraform uses the term "tainted" to describe a resource instance
+  which may not be fully functional, either because its creation
+  partially failed or because you've manually marked it as such using
+  this command.
+
+  This will not modify your infrastructure directly, but subsequent
+  Terraform plans will include actions to destroy the remote object
+  and create a new object to replace it.
+
+  You can remove the "taint" state from a resource instance using
+  the "terraform untaint" command.
+
+  The address is in the usual resource address syntax, such as:
+    aws_instance.foo
+    aws_instance.bar[1]
+    module.foo.module.bar.aws_instance.baz
+
+  Use your shell's quoting or escaping syntax to ensure that the
+  address will reach Terraform correctly, without any special
+  interpretation.
+
+Options:
+
+  -allow-missing          If specified, the command will succeed (exit code 0)
+                          even if the resource is missing.
+
+  -lock=false             Don't hold a state lock during the operation. This is
+                          dangerous if others might concurrently run commands
+                          against the same workspace.
+
+  -lock-timeout=0s        Duration to retry a state lock.
+
+  -ignore-remote-version  A rare option used for the remote backend only. See
+                          the remote backend documentation for more information.
+
+  -state, state-out, and -backup are legacy options supported for the local
+  backend only. For more information, see the local backend's documentation.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *TaintCommand) Synopsis() string {
+	return "Mark a resource instance as not fully functional"
+}
+
+func (c *TaintCommand) allowMissingExit(name addrs.AbsResourceInstance) int {
+	c.showDiagnostics(tfdiags.Sourceless(
+		tfdiags.Warning,
+		"No such resource instance",
+		fmt.Sprintf("Resource instance %s was not found, but this is not an error because -allow-missing was set.", name),
+	))
+	return 0
+}
diff --git a/v1.5.7/internal/command/taint_test.go b/v1.5.7/internal/command/taint_test.go
new file mode 100644
index 0000000..1978e3a
--- /dev/null
+++ b/v1.5.7/internal/command/taint_test.go
@@ -0,0 +1,567 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"os"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/mitchellh/cli"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestTaint(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &TaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	testStateOutput(t, statePath, testTaintStr)
+}
+
+func TestTaint_lockedState(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	unlock, err := testLockState(t, testDataDir, statePath)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer unlock()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &TaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code == 0 {
+		t.Fatal("expected error")
+	}
+
+	output := ui.ErrorWriter.String()
+	if !strings.Contains(output, "lock") {
+		t.Fatal("command output does not look like a lock error:", output)
+	}
+}
+
+func TestTaint_backup(t *testing.T) {
+	// Get a temp cwd
+	testCwd(t)
+
+	// Write the temp state
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	testStateFileDefault(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &TaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	testStateOutput(t, DefaultStateFilename+".backup", testTaintDefaultStr)
+	testStateOutput(t, DefaultStateFilename, testTaintStr)
+}
+
+func TestTaint_backupDisable(t *testing.T) {
+	// Get a temp cwd
+	testCwd(t)
+
+	// Write the temp state
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	testStateFileDefault(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &TaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-backup", "-",
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	if _, err := os.Stat(DefaultStateFilename + ".backup"); err == nil {
+		t.Fatal("backup path should not exist")
+	}
+
+	testStateOutput(t, DefaultStateFilename, testTaintStr)
+}
+
+func TestTaint_badState(t *testing.T) {
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &TaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-state", "i-should-not-exist-ever",
+		"foo",
+	}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+}
+
+func TestTaint_defaultState(t *testing.T) {
+	// Get a temp cwd
+	testCwd(t)
+
+	// Write the temp state
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	testStateFileDefault(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &TaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	testStateOutput(t, DefaultStateFilename, testTaintStr)
+}
+
+func TestTaint_defaultWorkspaceState(t *testing.T) {
+	// Get a temp cwd
+	testCwd(t)
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	testWorkspace := "development"
+	path := testStateFileWorkspaceDefault(t, testWorkspace, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	meta := Meta{Ui: ui, View: view}
+	meta.SetWorkspace(testWorkspace)
+	c := &TaintCommand{
+		Meta: meta,
+	}
+
+	args := []string{
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	testStateOutput(t, path, testTaintStr)
+}
+
+func TestTaint_missing(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &TaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.bar",
+	}
+	if code := c.Run(args); code == 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.OutputWriter.String())
+	}
+}
+
+func TestTaint_missingAllow(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &TaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-allow-missing",
+		"-state", statePath,
+		"test_instance.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Check for the warning
+	actual := strings.TrimSpace(ui.ErrorWriter.String())
+	expected := strings.TrimSpace(`
+Warning: No such resource instance
+
+Resource instance test_instance.bar was not found, but this is not an error
+because -allow-missing was set.
+
+`)
+	if diff := cmp.Diff(expected, actual); diff != "" {
+		t.Fatalf("wrong output\n%s", diff)
+	}
+}
+
+func TestTaint_stateOut(t *testing.T) {
+	// Get a temp cwd
+	testCwd(t)
+
+	// Write the temp state
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	testStateFileDefault(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &TaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-state-out", "foo",
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	testStateOutput(t, DefaultStateFilename, testTaintDefaultStr)
+	testStateOutput(t, "foo", testTaintStr)
+}
+
+func TestTaint_module(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "blah",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey)),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"blah"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &TaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"module.child.test_instance.blah",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	testStateOutput(t, statePath, testTaintModuleStr)
+}
+
+func TestTaint_checkRequiredVersion(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("command-check-required-version"), td)
+	defer testChdir(t, td)()
+
+	// Write the temp state
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	path := testStateFile(t, state)
+
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	c := &TaintCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{"test_instance.foo"}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
+	}
+
+	// State is unchanged
+	testStateOutput(t, path, testTaintDefaultStr)
+
+	// Required version diags are correct
+	errStr := ui.ErrorWriter.String()
+	if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) {
+		t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr)
+	}
+	if strings.Contains(errStr, `required_version = ">= 0.13.0"`) {
+		t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr)
+	}
+}
+
+const testTaintStr = `
+test_instance.foo: (tainted)
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+`
+
+const testTaintDefaultStr = `
+test_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+`
+
+const testTaintModuleStr = `
+test_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+
+module.child:
+  test_instance.blah: (tainted)
+    ID = blah
+    provider = provider["registry.terraform.io/hashicorp/test"]
+`
diff --git a/v1.5.7/internal/command/test.go b/v1.5.7/internal/command/test.go
new file mode 100644
index 0000000..e95ed4f
--- /dev/null
+++ b/v1.5.7/internal/command/test.go
@@ -0,0 +1,738 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"context"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/format"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/moduletest"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providercache"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// TestCommand is the implementation of "terraform test".
+type TestCommand struct {
+	Meta
+}
+
+func (c *TestCommand) Run(rawArgs []string) int {
+	// Parse and apply global view arguments
+	common, rawArgs := arguments.ParseView(rawArgs)
+	c.View.Configure(common)
+
+	args, diags := arguments.ParseTest(rawArgs)
+	view := views.NewTest(c.View, args.Output)
+	if diags.HasErrors() {
+		view.Diagnostics(diags)
+		return 1
+	}
+
+	diags = diags.Append(tfdiags.Sourceless(
+		tfdiags.Warning,
+		`The "terraform test" command is experimental`,
+		"We'd like to invite adventurous module authors to write integration tests for their modules using this command, but all of the behaviors of this command are currently experimental and may change based on feedback.\n\nFor more information on the testing experiment, including ongoing research goals and avenues for feedback, see:\n    https://www.terraform.io/docs/language/modules/testing-experiment.html",
+	))
+
+	ctx, cancel := c.InterruptibleContext()
+	defer cancel()
+
+	results, moreDiags := c.run(ctx, args)
+	diags = diags.Append(moreDiags)
+
+	initFailed := diags.HasErrors()
+	view.Diagnostics(diags)
+	diags = view.Results(results)
+	resultsFailed := diags.HasErrors()
+	view.Diagnostics(diags) // possible additional errors from saving the results
+
+	var testsFailed bool
+	for _, suite := range results {
+		for _, component := range suite.Components {
+			for _, assertion := range component.Assertions {
+				if !assertion.Outcome.SuiteCanPass() {
+					testsFailed = true
+				}
+			}
+		}
+	}
+
+	// Lots of things can possibly have failed
+	if initFailed || resultsFailed || testsFailed {
+		return 1
+	}
+	return 0
+}
+
+func (c *TestCommand) run(ctx context.Context, args arguments.Test) (results map[string]*moduletest.Suite, diags tfdiags.Diagnostics) {
+	suiteNames, err := c.collectSuiteNames()
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Error while searching for test configurations",
+			fmt.Sprintf("While attempting to scan the 'tests' subdirectory for potential test configurations, Terraform encountered an error: %s.", err),
+		))
+		return nil, diags
+	}
+
+	ret := make(map[string]*moduletest.Suite, len(suiteNames))
+	for _, suiteName := range suiteNames {
+		if ctx.Err() != nil {
+			// If the context has already failed in some way then we'll
+			// halt early and report whatever's already happened.
+			break
+		}
+		suite, moreDiags := c.runSuite(ctx, suiteName)
+		diags = diags.Append(moreDiags)
+		ret[suiteName] = suite
+	}
+
+	return ret, diags
+}
+
+func (c *TestCommand) runSuite(ctx context.Context, suiteName string) (*moduletest.Suite, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	ret := moduletest.Suite{
+		Name:       suiteName,
+		Components: map[string]*moduletest.Component{},
+	}
+
+	// In order to make this initial round of "terraform test" pretty self
+	// contained while it's experimental, it's largely just mimicking what
+	// would happen when running the main Terraform workflow commands, which
+	// comes at the expense of a few irritants that we'll hopefully resolve
+	// in future iterations as the design solidifies:
+	// - We need to install remote modules separately for each of the
+	//   test suites, because we don't have any sense of a shared cache
+	//   of modules that multiple configurations can refer to at once.
+	// - We _do_ have a sense of a cache of remote providers, but it's fixed
+	//   at being specifically a two-level cache (global vs. directory-specific)
+	//   and so we can't easily capture a third level of "all of the test suites
+	//   for this module" that sits between the two. Consequently, we need to
+	//   dynamically choose between creating a directory-specific "global"
+	//   cache or using the user's existing global cache, to avoid any
+	//   situation were we'd be re-downloading the same providers for every
+	//   one of the test suites.
+	// - We need to do something a bit horrid in order to have our test
+	//   provider instance persist between the plan and apply steps, because
+	//   normally that is the exact opposite of what we want.
+	// The above notes are here mainly as an aid to someone who might be
+	// planning a subsequent phase of this R&D effort, to help distinguish
+	// between things we're doing here because they are valuable vs. things
+	// we're doing just to make it work without doing any disruptive
+	// refactoring.
+
+	suiteDirs, moreDiags := c.prepareSuiteDir(ctx, suiteName)
+	diags = diags.Append(moreDiags)
+	if diags.HasErrors() {
+		// Generate a special failure representing the test initialization
+		// having failed, since we therefore won'tbe able to run the actual
+		// tests defined inside.
+		ret.Components["(init)"] = &moduletest.Component{
+			Assertions: map[string]*moduletest.Assertion{
+				"(init)": {
+					Outcome:     moduletest.Error,
+					Description: "terraform init",
+					Message:     "failed to install test suite dependencies",
+					Diagnostics: diags,
+				},
+			},
+		}
+		return &ret, nil
+	}
+
+	// When we run the suite itself, we collect up diagnostics associated
+	// with individual components, so ret.Components may or may not contain
+	// failed/errored components after runTestSuite returns.
+	var finalState *states.State
+	ret.Components, finalState = c.runTestSuite(ctx, suiteDirs)
+
+	// Regardless of the success or failure of the test suite, if there are
+	// any objects left in the state then we'll generate a top-level error
+	// about each one to minimize the chance of the user failing to notice
+	// that there are leftover objects that might continue to cost money
+	// unless manually deleted.
+	for _, ms := range finalState.Modules {
+		for _, rs := range ms.Resources {
+			for instanceKey, is := range rs.Instances {
+				var objs []*states.ResourceInstanceObjectSrc
+				if is.Current != nil {
+					objs = append(objs, is.Current)
+				}
+				for _, obj := range is.Deposed {
+					objs = append(objs, obj)
+				}
+				for _, obj := range objs {
+					// Unfortunately we don't have provider schemas out here
+					// and so we're limited in what we can achieve with these
+					// ResourceInstanceObjectSrc values, but we can try some
+					// heuristicy things to try to give some useful information
+					// in common cases.
+					var k, v string
+					if ty, err := ctyjson.ImpliedType(obj.AttrsJSON); err == nil {
+						if approxV, err := ctyjson.Unmarshal(obj.AttrsJSON, ty); err == nil {
+							k, v = format.ObjectValueIDOrName(approxV)
+						}
+					}
+
+					var detail string
+					if k != "" {
+						// We can be more specific if we were able to infer
+						// an identifying attribute for this object.
+						detail = fmt.Sprintf(
+							"Due to errors during destroy, test suite %q has left behind an object for %s, with the following identity:\n    %s = %q\n\nYou will need to delete this object manually in the remote system, or else it may have an ongoing cost.",
+							suiteName,
+							rs.Addr.Instance(instanceKey),
+							k, v,
+						)
+					} else {
+						// If our heuristics for finding a suitable identifier
+						// failed then unfortunately we must be more vague.
+						// (We can't just print the entire object, because it
+						// might be overly large and it might contain sensitive
+						// values.)
+						detail = fmt.Sprintf(
+							"Due to errors during destroy, test suite %q has left behind an object for %s. You will need to delete this object manually in the remote system, or else it may have an ongoing cost.",
+							suiteName,
+							rs.Addr.Instance(instanceKey),
+						)
+					}
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Failed to clean up after tests",
+						detail,
+					))
+				}
+			}
+		}
+	}
+
+	return &ret, diags
+}
+
+func (c *TestCommand) prepareSuiteDir(ctx context.Context, suiteName string) (testCommandSuiteDirs, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	configDir := filepath.Join("tests", suiteName)
+	log.Printf("[TRACE] terraform test: Prepare directory for suite %q in %s", suiteName, configDir)
+
+	suiteDirs := testCommandSuiteDirs{
+		SuiteName: suiteName,
+		ConfigDir: configDir,
+	}
+
+	// Before we can run a test suite we need to make sure that we have all of
+	// its dependencies available, so the following is essentially an
+	// abbreviated form of what happens during "terraform init", with some
+	// extra trickery in places.
+
+	// First, module installation. This will include linking in the module
+	// under test, but also includes grabbing the dependencies of that module
+	// if it has any.
+	suiteDirs.ModulesDir = filepath.Join(configDir, ".terraform", "modules")
+	os.MkdirAll(suiteDirs.ModulesDir, 0755) // if this fails then we'll ignore it and let InstallModules below fail instead
+	reg := c.registryClient()
+	loader, err := c.initConfigLoader()
+	if err != nil {
+		diags = diags.Append(err)
+		return suiteDirs, diags
+	}
+	moduleInst := initwd.NewModuleInstaller(suiteDirs.ModulesDir, loader, reg)
+	_, moreDiags := moduleInst.InstallModules(ctx, configDir, true, nil)
+	diags = diags.Append(moreDiags)
+	if diags.HasErrors() {
+		return suiteDirs, diags
+	}
+
+	// The installer puts the files in a suitable place on disk, but we
+	// still need to actually load the configuration. We need to do this
+	// with a separate config loader because the Meta.configLoader instance
+	// is intended for interacting with the current working directory, not
+	// with the test suite subdirectories.
+	loader, err = configload.NewLoader(&configload.Config{
+		ModulesDir: suiteDirs.ModulesDir,
+		Services:   c.Services,
+	})
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to create test configuration loader",
+			fmt.Sprintf("Failed to prepare loader for test configuration %s: %s.", configDir, err),
+		))
+		return suiteDirs, diags
+	}
+	cfg, hclDiags := loader.LoadConfig(configDir)
+	diags = diags.Append(hclDiags)
+	if diags.HasErrors() {
+		return suiteDirs, diags
+	}
+	suiteDirs.Config = cfg
+
+	// With the full configuration tree available, we can now install
+	// the necessary providers. We'll use a separate local cache directory
+	// here, because the test configuration might have additional requirements
+	// compared to the module itself.
+	suiteDirs.ProvidersDir = filepath.Join(configDir, ".terraform", "providers")
+	os.MkdirAll(suiteDirs.ProvidersDir, 0755) // if this fails then we'll ignore it and operations below fail instead
+	localCacheDir := providercache.NewDir(suiteDirs.ProvidersDir)
+	providerInst := c.providerInstaller().Clone(localCacheDir)
+	if !providerInst.HasGlobalCacheDir() {
+		// If the user already configured a global cache directory then we'll
+		// just use it for caching the test providers too, because then we
+		// can potentially reuse cache entries they already have. However,
+		// if they didn't configure one then we'll still establish one locally
+		// in the working directory, which we'll then share across all tests
+		// to avoid downloading the same providers repeatedly.
+		cachePath := filepath.Join(c.DataDir(), "testing-providers") // note this is _not_ under the suite dir
+		err := os.MkdirAll(cachePath, 0755)
+		// If we were unable to create the directory for any reason then we'll
+		// just proceed without a cache, at the expense of repeated downloads.
+		// (With that said, later installing might end up failing for the
+		// same reason anyway...)
+		if err == nil || os.IsExist(err) {
+			cacheDir := providercache.NewDir(cachePath)
+			providerInst.SetGlobalCacheDir(cacheDir)
+		}
+	}
+	reqs, hclDiags := cfg.ProviderRequirements()
+	diags = diags.Append(hclDiags)
+	if diags.HasErrors() {
+		return suiteDirs, diags
+	}
+
+	// For test suites we only retain the "locks" in memory for the duration
+	// for one run, just to make sure that we use the same providers when we
+	// eventually run the test suite.
+	locks := depsfile.NewLocks()
+	evts := &providercache.InstallerEvents{
+		QueryPackagesFailure: func(provider addrs.Provider, err error) {
+			if err != nil && addrs.IsDefaultProvider(provider) && provider.Type == "test" {
+				// This is some additional context for the failure error
+				// we'll generate afterwards. Not the most ideal UX but
+				// good enough for this prototype implementation, to help
+				// hint about the special builtin provider we use here.
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Warning,
+					"Probably-unintended reference to \"hashicorp/test\" provider",
+					"For the purposes of this experimental implementation of module test suites, you must use the built-in test provider terraform.io/builtin/test, which requires an explicit required_providers declaration.",
+				))
+			}
+		},
+	}
+	ctx = evts.OnContext(ctx)
+	locks, err = providerInst.EnsureProviderVersions(ctx, locks, reqs, providercache.InstallUpgrades)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to install required providers",
+			fmt.Sprintf("Couldn't install necessary providers for test configuration %s: %s.", configDir, err),
+		))
+		return suiteDirs, diags
+	}
+	suiteDirs.ProviderLocks = locks
+	suiteDirs.ProviderCache = localCacheDir
+
+	return suiteDirs, diags
+}
+
+func (c *TestCommand) runTestSuite(ctx context.Context, suiteDirs testCommandSuiteDirs) (map[string]*moduletest.Component, *states.State) {
+	log.Printf("[TRACE] terraform test: Run test suite %q", suiteDirs.SuiteName)
+
+	ret := make(map[string]*moduletest.Component)
+
+	// To collect test results we'll use an instance of the special "test"
+	// provider, which records the intention to make a test assertion during
+	// planning and then hopefully updates that to an actual assertion result
+	// during apply, unless an apply error causes the graph walk to exit early.
+	// For this to work correctly, we must ensure we're using the same provider
+	// instance for both plan and apply.
+	testProvider := moduletest.NewProvider()
+
+	// synthError is a helper to return early with a synthetic failing
+	// component, for problems that prevent us from even discovering what an
+	// appropriate component and assertion name might be.
+	state := states.NewState()
+	synthError := func(name string, desc string, msg string, diags tfdiags.Diagnostics) (map[string]*moduletest.Component, *states.State) {
+		key := "(" + name + ")" // parens ensure this can't conflict with an actual component/assertion key
+		ret[key] = &moduletest.Component{
+			Assertions: map[string]*moduletest.Assertion{
+				key: {
+					Outcome:     moduletest.Error,
+					Description: desc,
+					Message:     msg,
+					Diagnostics: diags,
+				},
+			},
+		}
+		return ret, state
+	}
+
+	// NOTE: This function intentionally deviates from the usual pattern of
+	// gradually appending more diagnostics to the same diags, because
+	// here we're associating each set of diagnostics with the specific
+	// operation it belongs to.
+
+	providerFactories, diags := c.testSuiteProviders(suiteDirs, testProvider)
+	if diags.HasErrors() {
+		// It should be unusual to get in here, because testSuiteProviders
+		// should rely only on things guaranteed by prepareSuiteDir, but
+		// since we're doing external I/O here there is always the risk that
+		// the filesystem changes or fails between setting up and using the
+		// providers.
+		return synthError(
+			"init",
+			"terraform init",
+			"failed to resolve the required providers",
+			diags,
+		)
+	}
+
+	plan, diags := c.testSuitePlan(ctx, suiteDirs, providerFactories)
+	if diags.HasErrors() {
+		// It should be unusual to get in here, because testSuitePlan
+		// should rely only on things guaranteed by prepareSuiteDir, but
+		// since we're doing external I/O here there is always the risk that
+		// the filesystem changes or fails between setting up and using the
+		// providers.
+		return synthError(
+			"plan",
+			"terraform plan",
+			"failed to create a plan",
+			diags,
+		)
+	}
+
+	// Now we'll apply the plan. Once we try to apply, we might've created
+	// real remote objects, and so we must try to run destroy even if the
+	// apply returns errors, and we must return whatever state we end up
+	// with so the caller can generate additional loud errors if anything
+	// is left in it.
+
+	state, diags = c.testSuiteApply(ctx, plan, suiteDirs, providerFactories)
+	if diags.HasErrors() {
+		// We don't return here, unlike the others above, because we want to
+		// continue to the destroy below even if there are apply errors.
+		synthError(
+			"apply",
+			"terraform apply",
+			"failed to apply the created plan",
+			diags,
+		)
+	}
+
+	// By the time we get here, the test provider will have gathered up all
+	// of the planned assertions and the final results for any assertions that
+	// were not blocked by an error. This also resets the provider so that
+	// the destroy operation below won't get tripped up on stale results.
+	ret = testProvider.Reset()
+
+	state, diags = c.testSuiteDestroy(ctx, state, suiteDirs, providerFactories)
+	if diags.HasErrors() {
+		synthError(
+			"destroy",
+			"terraform destroy",
+			"failed to destroy objects created during test (NOTE: leftover remote objects may still exist)",
+			diags,
+		)
+	}
+
+	return ret, state
+}
+
+func (c *TestCommand) testSuiteProviders(suiteDirs testCommandSuiteDirs, testProvider *moduletest.Provider) (map[addrs.Provider]providers.Factory, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	ret := make(map[addrs.Provider]providers.Factory)
+
+	// We can safely use the internal providers returned by Meta here because
+	// the built-in provider versions can never vary based on the configuration
+	// and thus we don't need to worry about potential version differences
+	// between main module and test suite modules.
+	for name, factory := range c.internalProviders() {
+		ret[addrs.NewBuiltInProvider(name)] = factory
+	}
+
+	// For the remaining non-builtin providers, we'll just take whatever we
+	// recorded earlier in the in-memory-only "lock file". All of these should
+	// typically still be available because we would've only just installed
+	// them, but this could fail if e.g. the filesystem has been somehow
+	// damaged in the meantime.
+	for provider, lock := range suiteDirs.ProviderLocks.AllProviders() {
+		version := lock.Version()
+		cached := suiteDirs.ProviderCache.ProviderVersion(provider, version)
+		if cached == nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Required provider not found",
+				fmt.Sprintf("Although installation previously succeeded for %s v%s, it no longer seems to be present in the cache directory.", provider.ForDisplay(), version.String()),
+			))
+			continue // potentially collect up multiple errors
+		}
+
+		// NOTE: We don't consider the checksums for test suite dependencies,
+		// because we're creating a fresh "lock file" each time we run anyway
+		// and so they wouldn't actually guarantee anything useful.
+
+		ret[provider] = providerFactory(cached)
+	}
+
+	// We'll replace the test provider instance with the one our caller
+	// provided, so it'll be able to interrogate the test results directly.
+	ret[addrs.NewBuiltInProvider("test")] = func() (providers.Interface, error) {
+		return testProvider, nil
+	}
+
+	return ret, diags
+}
+
+type testSuiteRunContext struct {
+	Core *terraform.Context
+
+	PlanMode   plans.Mode
+	Config     *configs.Config
+	InputState *states.State
+	Changes    *plans.Changes
+}
+
+func (c *TestCommand) testSuiteContext(suiteDirs testCommandSuiteDirs, providerFactories map[addrs.Provider]providers.Factory, state *states.State, plan *plans.Plan, destroy bool) (*testSuiteRunContext, tfdiags.Diagnostics) {
+	var changes *plans.Changes
+	if plan != nil {
+		changes = plan.Changes
+	}
+
+	planMode := plans.NormalMode
+	if destroy {
+		planMode = plans.DestroyMode
+	}
+
+	tfCtx, diags := terraform.NewContext(&terraform.ContextOpts{
+		Providers: providerFactories,
+
+		// We just use the provisioners from the main Meta here, because
+		// unlike providers provisioner plugins are not automatically
+		// installable anyway, and so we'll need to hunt for them in the same
+		// legacy way that normal Terraform operations do.
+		Provisioners: c.provisionerFactories(),
+
+		Meta: &terraform.ContextMeta{
+			Env: "test_" + suiteDirs.SuiteName,
+		},
+	})
+	if diags.HasErrors() {
+		return nil, diags
+	}
+	return &testSuiteRunContext{
+		Core: tfCtx,
+
+		PlanMode:   planMode,
+		Config:     suiteDirs.Config,
+		InputState: state,
+		Changes:    changes,
+	}, diags
+}
+
+func (c *TestCommand) testSuitePlan(ctx context.Context, suiteDirs testCommandSuiteDirs, providerFactories map[addrs.Provider]providers.Factory) (*plans.Plan, tfdiags.Diagnostics) {
+	log.Printf("[TRACE] terraform test: create plan for suite %q", suiteDirs.SuiteName)
+	runCtx, diags := c.testSuiteContext(suiteDirs, providerFactories, nil, nil, false)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	// We'll also validate as part of planning, to ensure that the test
+	// configuration would pass "terraform validate". This is actually
+	// largely redundant with the runCtx.Core.Plan call below, but was
+	// included here originally because Plan did _originally_ assume that
+	// an earlier Validate had already passed, but now does its own
+	// validation work as (mostly) a superset of validate.
+	moreDiags := runCtx.Core.Validate(runCtx.Config)
+	diags = diags.Append(moreDiags)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	plan, moreDiags := runCtx.Core.Plan(
+		runCtx.Config, runCtx.InputState, &terraform.PlanOpts{Mode: runCtx.PlanMode},
+	)
+	diags = diags.Append(moreDiags)
+	return plan, diags
+}
+
+func (c *TestCommand) testSuiteApply(ctx context.Context, plan *plans.Plan, suiteDirs testCommandSuiteDirs, providerFactories map[addrs.Provider]providers.Factory) (*states.State, tfdiags.Diagnostics) {
+	log.Printf("[TRACE] terraform test: apply plan for suite %q", suiteDirs.SuiteName)
+	runCtx, diags := c.testSuiteContext(suiteDirs, providerFactories, nil, plan, false)
+	if diags.HasErrors() {
+		// To make things easier on the caller, we'll return a valid empty
+		// state even in this case.
+		return states.NewState(), diags
+	}
+
+	state, moreDiags := runCtx.Core.Apply(plan, runCtx.Config)
+	diags = diags.Append(moreDiags)
+	return state, diags
+}
+
+func (c *TestCommand) testSuiteDestroy(ctx context.Context, state *states.State, suiteDirs testCommandSuiteDirs, providerFactories map[addrs.Provider]providers.Factory) (*states.State, tfdiags.Diagnostics) {
+	log.Printf("[TRACE] terraform test: plan to destroy any existing objects for suite %q", suiteDirs.SuiteName)
+	runCtx, diags := c.testSuiteContext(suiteDirs, providerFactories, state, nil, true)
+	if diags.HasErrors() {
+		return state, diags
+	}
+
+	plan, moreDiags := runCtx.Core.Plan(
+		runCtx.Config, runCtx.InputState, &terraform.PlanOpts{Mode: runCtx.PlanMode},
+	)
+	diags = diags.Append(moreDiags)
+	if diags.HasErrors() {
+		return state, diags
+	}
+
+	log.Printf("[TRACE] terraform test: apply the plan to destroy any existing objects for suite %q", suiteDirs.SuiteName)
+	runCtx, moreDiags = c.testSuiteContext(suiteDirs, providerFactories, state, plan, true)
+	diags = diags.Append(moreDiags)
+	if diags.HasErrors() {
+		return state, diags
+	}
+
+	state, moreDiags = runCtx.Core.Apply(plan, runCtx.Config)
+	diags = diags.Append(moreDiags)
+	return state, diags
+}
+
+func (c *TestCommand) collectSuiteNames() ([]string, error) {
+	items, err := ioutil.ReadDir("tests")
+	if err != nil {
+		if os.IsNotExist(err) {
+			return nil, nil
+		}
+		return nil, err
+	}
+
+	ret := make([]string, 0, len(items))
+	for _, item := range items {
+		if !item.IsDir() {
+			continue
+		}
+		name := item.Name()
+		suitePath := filepath.Join("tests", name)
+		tfFiles, err := filepath.Glob(filepath.Join(suitePath, "*.tf"))
+		if err != nil {
+			// We'll just ignore it and treat it like a dir with no .tf files
+			tfFiles = nil
+		}
+		tfJSONFiles, err := filepath.Glob(filepath.Join(suitePath, "*.tf.json"))
+		if err != nil {
+			// We'll just ignore it and treat it like a dir with no .tf.json files
+			tfJSONFiles = nil
+		}
+		if (len(tfFiles) + len(tfJSONFiles)) == 0 {
+			// Not a test suite, then.
+			continue
+		}
+		ret = append(ret, name)
+	}
+
+	return ret, nil
+}
+
+func (c *TestCommand) Help() string {
+	helpText := `
+Usage: terraform test [options]
+
+  This is an experimental command to help with automated integration
+  testing of shared modules. The usage and behavior of this command is
+  likely to change in breaking ways in subsequent releases, as we
+  are currently using this command primarily for research purposes.
+
+  In its current experimental form, "test" will look under the current
+  working directory for a subdirectory called "tests", and then within
+  that directory search for one or more subdirectories that contain
+  ".tf" or ".tf.json" files. For any that it finds, it will perform
+  Terraform operations similar to the following sequence of commands
+  in each of those directories:
+      terraform validate
+      terraform apply
+      terraform destroy
+
+  The test configurations should not declare any input variables and
+  should at least contain a call to the module being tested, which
+  will always be available at the path ../.. due to the expected
+  filesystem layout.
+
+  The tests are considered to be successful if all of the above steps
+  succeed.
+
+  Test configurations may optionally include uses of the special
+  built-in test provider terraform.io/builtin/test, which allows
+  writing explicit test assertions which must also all pass in order
+  for the test run to be considered successful.
+
+  This initial implementation is intended as a minimally-viable
+  product to use for further research and experimentation, and in
+  particular it currently lacks the following capabilities that we
+  expect to consider in later iterations, based on feedback:
+    - Testing of subsequent updates to existing infrastructure,
+      where currently it only supports initial creation and
+      then destruction.
+    - Testing top-level modules that are intended to be used for
+      "real" environments, which typically have hard-coded values
+      that don't permit creating a separate "copy" for testing.
+    - Some sort of support for unit test runs that don't interact
+      with remote systems at all, e.g. for use in checking pull
+      requests from untrusted contributors.
+
+  In the meantime, we'd like to hear feedback from module authors
+  who have tried writing some experimental tests for their modules
+  about what sorts of tests you were able to write, what sorts of
+  tests you weren't able to write, and any tests that you were
+  able to write but that were difficult to model in some way.
+
+Options:
+
+  -compact-warnings  Use a more compact representation for warnings, if
+                     this command produces only warnings and no errors.
+
+  -junit-xml=FILE    In addition to the usual output, also write test
+                     results to the given file path in JUnit XML format.
+                     This format is commonly supported by CI systems, and
+                     they typically expect to be given a filename to search
+                     for in the test workspace after the test run finishes.
+
+  -no-color          Don't include virtual terminal formatting sequences in
+                     the output.
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *TestCommand) Synopsis() string {
+	return "Experimental support for module integration testing"
+}
+
+type testCommandSuiteDirs struct {
+	SuiteName string
+
+	ConfigDir    string
+	ModulesDir   string
+	ProvidersDir string
+
+	Config        *configs.Config
+	ProviderCache *providercache.Dir
+	ProviderLocks *depsfile.Locks
+}
diff --git a/v1.5.7/internal/command/test_test.go b/v1.5.7/internal/command/test_test.go
new file mode 100644
index 0000000..85b27ac
--- /dev/null
+++ b/v1.5.7/internal/command/test_test.go
@@ -0,0 +1,166 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"io/ioutil"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/terminal"
+)
+
+// These are the main tests for the "terraform test" command.
+func TestTest(t *testing.T) {
+	t.Run("passes", func(t *testing.T) {
+		td := t.TempDir()
+		testCopyDir(t, testFixturePath("test-passes"), td)
+		defer testChdir(t, td)()
+
+		streams, close := terminal.StreamsForTesting(t)
+		cmd := &TestCommand{
+			Meta: Meta{
+				Streams: streams,
+				View:    views.NewView(streams),
+			},
+		}
+		exitStatus := cmd.Run([]string{"-junit-xml=junit.xml", "-no-color"})
+		outp := close(t)
+		if got, want := exitStatus, 0; got != want {
+			t.Fatalf("wrong exit status %d; want %d\nstderr:\n%s", got, want, outp.Stderr())
+		}
+
+		gotStdout := strings.TrimSpace(outp.Stdout())
+		wantStdout := strings.TrimSpace(`
+Warning: The "terraform test" command is experimental
+
+We'd like to invite adventurous module authors to write integration tests for
+their modules using this command, but all of the behaviors of this command
+are currently experimental and may change based on feedback.
+
+For more information on the testing experiment, including ongoing research
+goals and avenues for feedback, see:
+    https://www.terraform.io/docs/language/modules/testing-experiment.html
+`)
+		if diff := cmp.Diff(wantStdout, gotStdout); diff != "" {
+			t.Errorf("wrong stdout\n%s", diff)
+		}
+
+		gotStderr := strings.TrimSpace(outp.Stderr())
+		wantStderr := strings.TrimSpace(`
+Success! All of the test assertions passed.
+`)
+		if diff := cmp.Diff(wantStderr, gotStderr); diff != "" {
+			t.Errorf("wrong stderr\n%s", diff)
+		}
+
+		gotXMLSrc, err := ioutil.ReadFile("junit.xml")
+		if err != nil {
+			t.Fatal(err)
+		}
+		gotXML := string(bytes.TrimSpace(gotXMLSrc))
+		wantXML := strings.TrimSpace(`
+<testsuites>
+  <errors>0</errors>
+  <failures>0</failures>
+  <tests>1</tests>
+  <testsuite>
+    <name>hello</name>
+    <tests>1</tests>
+    <skipped>0</skipped>
+    <errors>0</errors>
+    <failures>0</failures>
+    <testcase>
+      <name>output</name>
+      <classname>foo</classname>
+    </testcase>
+  </testsuite>
+</testsuites>
+`)
+		if diff := cmp.Diff(wantXML, gotXML); diff != "" {
+			t.Errorf("wrong JUnit XML\n%s", diff)
+		}
+	})
+	t.Run("fails", func(t *testing.T) {
+		td := t.TempDir()
+		testCopyDir(t, testFixturePath("test-fails"), td)
+		defer testChdir(t, td)()
+
+		streams, close := terminal.StreamsForTesting(t)
+		cmd := &TestCommand{
+			Meta: Meta{
+				Streams: streams,
+				View:    views.NewView(streams),
+			},
+		}
+		exitStatus := cmd.Run([]string{"-junit-xml=junit.xml", "-no-color"})
+		outp := close(t)
+		if got, want := exitStatus, 1; got != want {
+			t.Fatalf("wrong exit status %d; want %d\nstderr:\n%s", got, want, outp.Stderr())
+		}
+
+		gotStdout := strings.TrimSpace(outp.Stdout())
+		wantStdout := strings.TrimSpace(`
+Warning: The "terraform test" command is experimental
+
+We'd like to invite adventurous module authors to write integration tests for
+their modules using this command, but all of the behaviors of this command
+are currently experimental and may change based on feedback.
+
+For more information on the testing experiment, including ongoing research
+goals and avenues for feedback, see:
+    https://www.terraform.io/docs/language/modules/testing-experiment.html
+`)
+		if diff := cmp.Diff(wantStdout, gotStdout); diff != "" {
+			t.Errorf("wrong stdout\n%s", diff)
+		}
+
+		gotStderr := strings.TrimSpace(outp.Stderr())
+		wantStderr := strings.TrimSpace(`
+─── Failed: hello.foo.output (output "foo" value) ───────────────────────────
+wrong value
+    got:  "foo value boop"
+    want: "foo not boop"
+
+─────────────────────────────────────────────────────────────────────────────
+`)
+		if diff := cmp.Diff(wantStderr, gotStderr); diff != "" {
+			t.Errorf("wrong stderr\n%s", diff)
+		}
+
+		gotXMLSrc, err := ioutil.ReadFile("junit.xml")
+		if err != nil {
+			t.Fatal(err)
+		}
+		gotXML := string(bytes.TrimSpace(gotXMLSrc))
+		wantXML := strings.TrimSpace(`
+<testsuites>
+  <errors>0</errors>
+  <failures>1</failures>
+  <tests>1</tests>
+  <testsuite>
+    <name>hello</name>
+    <tests>1</tests>
+    <skipped>0</skipped>
+    <errors>0</errors>
+    <failures>1</failures>
+    <testcase>
+      <name>output</name>
+      <classname>foo</classname>
+      <failure>
+        <message>wrong value&#xA;    got:  &#34;foo value boop&#34;&#xA;    want: &#34;foo not boop&#34;&#xA;</message>
+      </failure>
+    </testcase>
+  </testsuite>
+</testsuites>
+`)
+		if diff := cmp.Diff(wantXML, gotXML); diff != "" {
+			t.Errorf("wrong JUnit XML\n%s", diff)
+		}
+	})
+
+}
diff --git a/v1.5.7/internal/command/testdata/apply-config-invalid/main.tf b/v1.5.7/internal/command/testdata/apply-config-invalid/main.tf
new file mode 100644
index 0000000..81ea8d1
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/apply-config-invalid/main.tf
@@ -0,0 +1,3 @@
+resource "test_instance" "foo" {
+    ami = "${var.nope}"
+}
diff --git a/v1.5.7/internal/command/testdata/apply-destroy-targeted/main.tf b/v1.5.7/internal/command/testdata/apply-destroy-targeted/main.tf
new file mode 100644
index 0000000..0f249b3
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/apply-destroy-targeted/main.tf
@@ -0,0 +1,7 @@
+resource "test_instance" "foo" {
+  count = 3
+}
+
+resource "test_load_balancer" "foo" {
+  instances = test_instance.foo.*.id
+}
diff --git a/v1.5.7/internal/command/testdata/apply-error/main.tf b/v1.5.7/internal/command/testdata/apply-error/main.tf
new file mode 100644
index 0000000..a6d6cc0
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/apply-error/main.tf
@@ -0,0 +1,7 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+}
+
+resource "test_instance" "bar" {
+    error = "true"
+}
diff --git a/v1.5.7/internal/command/testdata/apply-input-partial/main.tf b/v1.5.7/internal/command/testdata/apply-input-partial/main.tf
new file mode 100644
index 0000000..85ada15
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/apply-input-partial/main.tf
@@ -0,0 +1,9 @@
+variable "foo" {}
+variable "bar" {}
+
+output "foo" {
+  value = "${var.foo}"
+}
+output "bar" {
+  value = "${var.bar}"
+}
diff --git a/v1.5.7/internal/command/testdata/apply-input/main.tf b/v1.5.7/internal/command/testdata/apply-input/main.tf
new file mode 100644
index 0000000..b7f2958
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/apply-input/main.tf
@@ -0,0 +1,5 @@
+variable "foo" {}
+
+output "result" {
+  value = var.foo
+}
diff --git a/v1.5.7/internal/command/testdata/apply-plan-no-module/main.tf b/v1.5.7/internal/command/testdata/apply-plan-no-module/main.tf
new file mode 100644
index 0000000..deea30d
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/apply-plan-no-module/main.tf
@@ -0,0 +1,7 @@
+resource "test_instance" "tmpl" {
+  foo = "${file("${path.module}/template.txt")}"
+}
+
+output "template" {
+	value = "${test_instance.tmpl.foo}"
+}
diff --git a/v1.5.7/internal/command/testdata/apply-replace/main.tf b/v1.5.7/internal/command/testdata/apply-replace/main.tf
new file mode 100644
index 0000000..efc6729
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/apply-replace/main.tf
@@ -0,0 +1,2 @@
+resource "test_instance" "a" {
+}
diff --git a/v1.5.7/internal/command/testdata/apply-sensitive-output/main.tf b/v1.5.7/internal/command/testdata/apply-sensitive-output/main.tf
new file mode 100644
index 0000000..87994ae
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/apply-sensitive-output/main.tf
@@ -0,0 +1,12 @@
+variable "input" {
+  default = "Hello world"
+}
+
+output "notsensitive" {
+  value = "${var.input}"
+}
+
+output "sensitive" {
+  sensitive = true
+  value = "${var.input}"
+}
diff --git a/v1.5.7/internal/command/testdata/apply-shutdown/main.tf b/v1.5.7/internal/command/testdata/apply-shutdown/main.tf
new file mode 100644
index 0000000..5fc9660
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/apply-shutdown/main.tf
@@ -0,0 +1,7 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+}
+
+resource "test_instance" "bar" {
+    ami = "${test_instance.foo.ami}"
+}
diff --git a/v1.5.7/internal/command/testdata/apply-targeted/main.tf b/v1.5.7/internal/command/testdata/apply-targeted/main.tf
new file mode 100644
index 0000000..1b6c424
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/apply-targeted/main.tf
@@ -0,0 +1,9 @@
+resource "test_instance" "foo" {
+  count = 2
+}
+
+resource "test_instance" "bar" {
+}
+
+resource "test_instance" "baz" {
+}
diff --git a/v1.5.7/internal/command/testdata/apply-terraform-env/main.tf b/v1.5.7/internal/command/testdata/apply-terraform-env/main.tf
new file mode 100644
index 0000000..3866960
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/apply-terraform-env/main.tf
@@ -0,0 +1,3 @@
+output "output" {
+  value = terraform.workspace
+}
diff --git a/v1.5.7/internal/command/testdata/apply-vars/main.tf b/v1.5.7/internal/command/testdata/apply-vars/main.tf
new file mode 100644
index 0000000..1d6da85
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/apply-vars/main.tf
@@ -0,0 +1,5 @@
+variable "foo" {}
+
+resource "test_instance" "foo" {
+    value = var.foo
+}
diff --git a/v1.5.7/internal/command/testdata/apply/main.tf b/v1.5.7/internal/command/testdata/apply/main.tf
new file mode 100644
index 0000000..1b10129
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/apply/main.tf
@@ -0,0 +1,3 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+}
diff --git a/v1.5.7/internal/command/testdata/apply/output.jsonlog b/v1.5.7/internal/command/testdata/apply/output.jsonlog
new file mode 100644
index 0000000..64cf5cc
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/apply/output.jsonlog
@@ -0,0 +1,7 @@
+{"@level":"info","@message":"Terraform 0.15.0-dev","@module":"terraform.ui","terraform":"0.15.0-dev","type":"version","ui":"0.1.0"}
+{"@level":"info","@message":"test_instance.foo: Plan to create","@module":"terraform.ui","change":{"resource":{"addr":"test_instance.foo","module":"","resource":"test_instance.foo","implied_provider":"test","resource_type":"test_instance","resource_name":"foo","resource_key":null},"action":"create"},"type":"planned_change"}
+{"@level":"info","@message":"Plan: 1 to add, 0 to change, 0 to destroy.","@module":"terraform.ui","changes":{"add":1,"import":0,"change":0,"remove":0,"operation":"plan"},"type":"change_summary"}
+{"@level":"info","@message":"test_instance.foo: Creating...","@module":"terraform.ui","hook":{"resource":{"addr":"test_instance.foo","module":"","resource":"test_instance.foo","implied_provider":"test","resource_type":"test_instance","resource_name":"foo","resource_key":null},"action":"create"},"type":"apply_start"}
+{"@level":"info","@message":"test_instance.foo: Creation complete after 0s","@module":"terraform.ui","hook":{"resource":{"addr":"test_instance.foo","module":"","resource":"test_instance.foo","implied_provider":"test","resource_type":"test_instance","resource_name":"foo","resource_key":null},"action":"create","elapsed_seconds":0},"type":"apply_complete"}
+{"@level":"info","@message":"Apply complete! Resources: 1 added, 0 changed, 0 destroyed.","@module":"terraform.ui","changes":{"add":1,"import":0,"change":0,"remove":0,"operation":"apply"},"type":"change_summary"}
+{"@level":"info","@message":"Outputs: 0","@module":"terraform.ui","outputs":{},"type":"outputs"}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-default-to-single/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-change-multi-default-to-single/.terraform/terraform.tfstate
new file mode 100644
index 0000000..073bd7a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-default-to-single/.terraform/terraform.tfstate
@@ -0,0 +1,22 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-default-to-single/local-state.tfstate b/v1.5.7/internal/command/testdata/backend-change-multi-default-to-single/local-state.tfstate
new file mode 100644
index 0000000..60c275e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-default-to-single/local-state.tfstate
@@ -0,0 +1,12 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "backend-change",
+    "outputs": {
+        "foo": {
+            "type": "string",
+            "value": "bar"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-default-to-single/main.tf b/v1.5.7/internal/command/testdata/backend-change-multi-default-to-single/main.tf
new file mode 100644
index 0000000..2f67c6f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-default-to-single/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local-single" {
+        path = "local-state-2.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-multi/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-change-multi-to-multi/.terraform/terraform.tfstate
new file mode 100644
index 0000000..073bd7a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-multi/.terraform/terraform.tfstate
@@ -0,0 +1,22 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-multi/local-state.tfstate b/v1.5.7/internal/command/testdata/backend-change-multi-to-multi/local-state.tfstate
new file mode 100644
index 0000000..60c275e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-multi/local-state.tfstate
@@ -0,0 +1,12 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "backend-change",
+    "outputs": {
+        "foo": {
+            "type": "string",
+            "value": "bar"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-multi/main.tf b/v1.5.7/internal/command/testdata/backend-change-multi-to-multi/main.tf
new file mode 100644
index 0000000..c8d630d
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-multi/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        workspace_dir = "envdir-new"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-multi/terraform.tfstate.d/env2/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-change-multi-to-multi/terraform.tfstate.d/env2/terraform.tfstate
new file mode 100644
index 0000000..2847289
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-multi/terraform.tfstate.d/env2/terraform.tfstate
@@ -0,0 +1,12 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "backend-change-env2",
+    "outputs": {
+        "foo": {
+            "type": "string",
+            "value": "bar"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-with-default/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-with-default/.terraform/terraform.tfstate
new file mode 100644
index 0000000..073bd7a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-with-default/.terraform/terraform.tfstate
@@ -0,0 +1,22 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-with-default/local-state.tfstate b/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-with-default/local-state.tfstate
new file mode 100644
index 0000000..d42eb03
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-with-default/local-state.tfstate
@@ -0,0 +1,12 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "backend-change-env1",
+    "outputs": {
+        "foo": {
+            "type": "string",
+            "value": "bar"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-with-default/main.tf b/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-with-default/main.tf
new file mode 100644
index 0000000..6328a4f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-with-default/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local-no-default" {
+        workspace_dir = "envdir-new"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-with-default/terraform.tfstate.d/env2/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-with-default/terraform.tfstate.d/env2/terraform.tfstate
new file mode 100644
index 0000000..2847289
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-with-default/terraform.tfstate.d/env2/terraform.tfstate
@@ -0,0 +1,12 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "backend-change-env2",
+    "outputs": {
+        "foo": {
+            "type": "string",
+            "value": "bar"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-without-default/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-without-default/.terraform/terraform.tfstate
new file mode 100644
index 0000000..073bd7a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-without-default/.terraform/terraform.tfstate
@@ -0,0 +1,22 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-without-default/main.tf b/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-without-default/main.tf
new file mode 100644
index 0000000..6328a4f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-without-default/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local-no-default" {
+        workspace_dir = "envdir-new"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-without-default/terraform.tfstate.d/env2/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-without-default/terraform.tfstate.d/env2/terraform.tfstate
new file mode 100644
index 0000000..2847289
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-no-default-without-default/terraform.tfstate.d/env2/terraform.tfstate
@@ -0,0 +1,12 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "backend-change-env2",
+    "outputs": {
+        "foo": {
+            "type": "string",
+            "value": "bar"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-single/.terraform/environment b/v1.5.7/internal/command/testdata/backend-change-multi-to-single/.terraform/environment
new file mode 100644
index 0000000..e5e6010
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-single/.terraform/environment
@@ -0,0 +1 @@
+env1
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-single/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-change-multi-to-single/.terraform/terraform.tfstate
new file mode 100644
index 0000000..073bd7a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-single/.terraform/terraform.tfstate
@@ -0,0 +1,22 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-single/main.tf b/v1.5.7/internal/command/testdata/backend-change-multi-to-single/main.tf
new file mode 100644
index 0000000..2f67c6f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-single/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local-single" {
+        path = "local-state-2.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-single/terraform.tfstate.d/env1/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-change-multi-to-single/terraform.tfstate.d/env1/terraform.tfstate
new file mode 100644
index 0000000..60c275e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-single/terraform.tfstate.d/env1/terraform.tfstate
@@ -0,0 +1,12 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "backend-change",
+    "outputs": {
+        "foo": {
+            "type": "string",
+            "value": "bar"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-multi-to-single/terraform.tfstate.d/env2/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-change-multi-to-single/terraform.tfstate.d/env2/terraform.tfstate
new file mode 100644
index 0000000..2847289
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-multi-to-single/terraform.tfstate.d/env2/terraform.tfstate
@@ -0,0 +1,12 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "backend-change-env2",
+    "outputs": {
+        "foo": {
+            "type": "string",
+            "value": "bar"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-single-to-single/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-change-single-to-single/.terraform/terraform.tfstate
new file mode 100644
index 0000000..be6ed26
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-single-to-single/.terraform/terraform.tfstate
@@ -0,0 +1,22 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local-single",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-single-to-single/local-state.tfstate b/v1.5.7/internal/command/testdata/backend-change-single-to-single/local-state.tfstate
new file mode 100644
index 0000000..60c275e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-single-to-single/local-state.tfstate
@@ -0,0 +1,12 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "backend-change",
+    "outputs": {
+        "foo": {
+            "type": "string",
+            "value": "bar"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change-single-to-single/main.tf b/v1.5.7/internal/command/testdata/backend-change-single-to-single/main.tf
new file mode 100644
index 0000000..2f67c6f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change-single-to-single/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local-single" {
+        path = "local-state-2.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-change/.terraform/terraform.tfstate
new file mode 100644
index 0000000..073bd7a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change/.terraform/terraform.tfstate
@@ -0,0 +1,22 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change/local-state.tfstate b/v1.5.7/internal/command/testdata/backend-change/local-state.tfstate
new file mode 100644
index 0000000..60c275e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change/local-state.tfstate
@@ -0,0 +1,12 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "backend-change",
+    "outputs": {
+        "foo": {
+            "type": "string",
+            "value": "bar"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-change/main.tf b/v1.5.7/internal/command/testdata/backend-change/main.tf
new file mode 100644
index 0000000..0277003
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-change/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state-2.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-changed-with-legacy/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-changed-with-legacy/.terraform/terraform.tfstate
new file mode 100644
index 0000000..1e8c0a1
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-changed-with-legacy/.terraform/terraform.tfstate
@@ -0,0 +1,28 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "remote": {
+        "type": "local",
+        "config": {
+            "path": "local-state-old.tfstate"
+        }
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/backend-changed-with-legacy/local-state-old.tfstate b/v1.5.7/internal/command/testdata/backend-changed-with-legacy/local-state-old.tfstate
new file mode 100644
index 0000000..e8cb7d8
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-changed-with-legacy/local-state-old.tfstate
@@ -0,0 +1,6 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "legacy"
+}
diff --git a/v1.5.7/internal/command/testdata/backend-changed-with-legacy/local-state.tfstate b/v1.5.7/internal/command/testdata/backend-changed-with-legacy/local-state.tfstate
new file mode 100644
index 0000000..a3b08ca
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-changed-with-legacy/local-state.tfstate
@@ -0,0 +1,6 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "configured"
+}
diff --git a/v1.5.7/internal/command/testdata/backend-changed-with-legacy/main.tf b/v1.5.7/internal/command/testdata/backend-changed-with-legacy/main.tf
new file mode 100644
index 0000000..0277003
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-changed-with-legacy/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state-2.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-from-state/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-from-state/terraform.tfstate
new file mode 100644
index 0000000..091ecc1
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-from-state/terraform.tfstate
@@ -0,0 +1,10 @@
+{
+    "version": 3,
+    "terraform_version": "0.12.0",
+    "serial": 7,
+    "lineage": "configured",
+    "backend": {
+        "type": "inmem",
+        "config": {}
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-inmem-locked/main.tf b/v1.5.7/internal/command/testdata/backend-inmem-locked/main.tf
new file mode 100644
index 0000000..9fb065d
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-inmem-locked/main.tf
@@ -0,0 +1,5 @@
+terraform {
+	backend "inmem" {
+		lock_id = "2b6a6738-5dd5-50d6-c0ae-f6352977666b"
+	}
+}
diff --git a/v1.5.7/internal/command/testdata/backend-new-interp/main.tf b/v1.5.7/internal/command/testdata/backend-new-interp/main.tf
new file mode 100644
index 0000000..136d0f3
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-new-interp/main.tf
@@ -0,0 +1,7 @@
+variable "foo" { default = "bar" }
+
+terraform {
+    backend "local" {
+        path = "${var.foo}"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-new-legacy/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-new-legacy/.terraform/terraform.tfstate
new file mode 100644
index 0000000..481edc6
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-new-legacy/.terraform/terraform.tfstate
@@ -0,0 +1,21 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "remote": {
+        "type": "local",
+        "config": {
+            "path": "local-state-old.tfstate"
+        }
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/backend-new-legacy/local-state-old.tfstate b/v1.5.7/internal/command/testdata/backend-new-legacy/local-state-old.tfstate
new file mode 100644
index 0000000..5f491bc
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-new-legacy/local-state-old.tfstate
@@ -0,0 +1,12 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "backend-new-legacy",
+    "remote": {
+        "type": "local",
+        "config": {
+            "path": "local-state-old.tfstate"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-new-legacy/main.tf b/v1.5.7/internal/command/testdata/backend-new-legacy/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-new-legacy/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-new-migrate-existing/local-state.tfstate b/v1.5.7/internal/command/testdata/backend-new-migrate-existing/local-state.tfstate
new file mode 100644
index 0000000..d9c0d27
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-new-migrate-existing/local-state.tfstate
@@ -0,0 +1,6 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 8,
+    "lineage": "remote"
+}
diff --git a/v1.5.7/internal/command/testdata/backend-new-migrate-existing/main.tf b/v1.5.7/internal/command/testdata/backend-new-migrate-existing/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-new-migrate-existing/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-new-migrate-existing/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-new-migrate-existing/terraform.tfstate
new file mode 100644
index 0000000..f90be0a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-new-migrate-existing/terraform.tfstate
@@ -0,0 +1,12 @@
+{
+    "version": 4,
+    "terraform_version": "0.8.2",
+    "serial": 8,
+    "lineage": "local",
+    "outputs": {
+        "foo": {
+            "type": "string",
+            "value": "bar"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-new-migrate/main.tf b/v1.5.7/internal/command/testdata/backend-new-migrate/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-new-migrate/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-new-migrate/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-new-migrate/terraform.tfstate
new file mode 100644
index 0000000..fe645de
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-new-migrate/terraform.tfstate
@@ -0,0 +1,12 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 8,
+    "lineage": "backend-new-migrate",
+    "outputs": {
+        "foo": {
+            "type": "string",
+            "value": "bar"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-new/main.tf b/v1.5.7/internal/command/testdata/backend-new/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-new/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-plan-backend-empty-config/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-plan-backend-empty-config/.terraform/terraform.tfstate
new file mode 100644
index 0000000..073bd7a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-backend-empty-config/.terraform/terraform.tfstate
@@ -0,0 +1,22 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/backend-plan-backend-empty-config/local-state.tfstate b/v1.5.7/internal/command/testdata/backend-plan-backend-empty-config/local-state.tfstate
new file mode 100644
index 0000000..8f4112c
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-backend-empty-config/local-state.tfstate
@@ -0,0 +1,5 @@
+{
+    "version": 4,
+    "serial": 0,
+    "lineage": "hello"
+}
diff --git a/v1.5.7/internal/command/testdata/backend-plan-backend-empty-config/main.tf b/v1.5.7/internal/command/testdata/backend-plan-backend-empty-config/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-backend-empty-config/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-plan-backend-empty/readme.txt b/v1.5.7/internal/command/testdata/backend-plan-backend-empty/readme.txt
new file mode 100644
index 0000000..e2d6fa2
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-backend-empty/readme.txt
@@ -0,0 +1 @@
+This directory is empty on purpose.
diff --git a/v1.5.7/internal/command/testdata/backend-plan-backend-match/local-state.tfstate b/v1.5.7/internal/command/testdata/backend-plan-backend-match/local-state.tfstate
new file mode 100644
index 0000000..8f4112c
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-backend-match/local-state.tfstate
@@ -0,0 +1,5 @@
+{
+    "version": 4,
+    "serial": 0,
+    "lineage": "hello"
+}
diff --git a/v1.5.7/internal/command/testdata/backend-plan-backend-match/readme.txt b/v1.5.7/internal/command/testdata/backend-plan-backend-match/readme.txt
new file mode 100644
index 0000000..b381753
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-backend-match/readme.txt
@@ -0,0 +1 @@
+This directory has no configuration on purpose.
diff --git a/v1.5.7/internal/command/testdata/backend-plan-backend-mismatch/local-state.tfstate b/v1.5.7/internal/command/testdata/backend-plan-backend-mismatch/local-state.tfstate
new file mode 100644
index 0000000..3ea7358
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-backend-mismatch/local-state.tfstate
@@ -0,0 +1,5 @@
+{
+    "version": 4,
+    "serial": 0,
+    "lineage": "different"
+}
diff --git a/v1.5.7/internal/command/testdata/backend-plan-legacy-data/local-state.tfstate b/v1.5.7/internal/command/testdata/backend-plan-legacy-data/local-state.tfstate
new file mode 100644
index 0000000..8f4112c
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-legacy-data/local-state.tfstate
@@ -0,0 +1,5 @@
+{
+    "version": 4,
+    "serial": 0,
+    "lineage": "hello"
+}
diff --git a/v1.5.7/internal/command/testdata/backend-plan-legacy-data/main.tf b/v1.5.7/internal/command/testdata/backend-plan-legacy-data/main.tf
new file mode 100644
index 0000000..b7db254
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-legacy-data/main.tf
@@ -0,0 +1 @@
+# Empty
diff --git a/v1.5.7/internal/command/testdata/backend-plan-legacy-data/state.tfstate b/v1.5.7/internal/command/testdata/backend-plan-legacy-data/state.tfstate
new file mode 100644
index 0000000..b5e5193
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-legacy-data/state.tfstate
@@ -0,0 +1,11 @@
+{
+    "version": 4,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "remote": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-plan-legacy/readme.txt b/v1.5.7/internal/command/testdata/backend-plan-legacy/readme.txt
new file mode 100644
index 0000000..08c2a35
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-legacy/readme.txt
@@ -0,0 +1 @@
+No configs on purpose
diff --git a/v1.5.7/internal/command/testdata/backend-plan-local-match/main.tf b/v1.5.7/internal/command/testdata/backend-plan-local-match/main.tf
new file mode 100644
index 0000000..b7db254
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-local-match/main.tf
@@ -0,0 +1 @@
+# Empty
diff --git a/v1.5.7/internal/command/testdata/backend-plan-local-match/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-plan-local-match/terraform.tfstate
new file mode 100644
index 0000000..55a5b74
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-local-match/terraform.tfstate
@@ -0,0 +1,6 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "hello"
+}
diff --git a/v1.5.7/internal/command/testdata/backend-plan-local-mismatch-lineage/main.tf b/v1.5.7/internal/command/testdata/backend-plan-local-mismatch-lineage/main.tf
new file mode 100644
index 0000000..b7db254
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-local-mismatch-lineage/main.tf
@@ -0,0 +1 @@
+# Empty
diff --git a/v1.5.7/internal/command/testdata/backend-plan-local-mismatch-lineage/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-plan-local-mismatch-lineage/terraform.tfstate
new file mode 100644
index 0000000..55a5b74
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-local-mismatch-lineage/terraform.tfstate
@@ -0,0 +1,6 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "hello"
+}
diff --git a/v1.5.7/internal/command/testdata/backend-plan-local-newer/main.tf b/v1.5.7/internal/command/testdata/backend-plan-local-newer/main.tf
new file mode 100644
index 0000000..b7db254
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-local-newer/main.tf
@@ -0,0 +1 @@
+# Empty
diff --git a/v1.5.7/internal/command/testdata/backend-plan-local-newer/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-plan-local-newer/terraform.tfstate
new file mode 100644
index 0000000..e7ff8f6
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-local-newer/terraform.tfstate
@@ -0,0 +1,6 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 10,
+    "lineage": "hello"
+}
diff --git a/v1.5.7/internal/command/testdata/backend-plan-local/main.tf b/v1.5.7/internal/command/testdata/backend-plan-local/main.tf
new file mode 100644
index 0000000..fec5601
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-plan-local/main.tf
@@ -0,0 +1 @@
+# Hello
diff --git a/v1.5.7/internal/command/testdata/backend-unchanged-with-legacy/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-unchanged-with-legacy/.terraform/terraform.tfstate
new file mode 100644
index 0000000..1e8c0a1
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-unchanged-with-legacy/.terraform/terraform.tfstate
@@ -0,0 +1,28 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "remote": {
+        "type": "local",
+        "config": {
+            "path": "local-state-old.tfstate"
+        }
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/backend-unchanged-with-legacy/local-state-old.tfstate b/v1.5.7/internal/command/testdata/backend-unchanged-with-legacy/local-state-old.tfstate
new file mode 100644
index 0000000..59c7336
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-unchanged-with-legacy/local-state-old.tfstate
@@ -0,0 +1,6 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "backend-unchanged-with-legacy"
+}
diff --git a/v1.5.7/internal/command/testdata/backend-unchanged-with-legacy/local-state.tfstate b/v1.5.7/internal/command/testdata/backend-unchanged-with-legacy/local-state.tfstate
new file mode 100644
index 0000000..a3b08ca
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-unchanged-with-legacy/local-state.tfstate
@@ -0,0 +1,6 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "configured"
+}
diff --git a/v1.5.7/internal/command/testdata/backend-unchanged-with-legacy/main.tf b/v1.5.7/internal/command/testdata/backend-unchanged-with-legacy/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-unchanged-with-legacy/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-unchanged/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-unchanged/.terraform/terraform.tfstate
new file mode 100644
index 0000000..122adb8
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-unchanged/.terraform/terraform.tfstate
@@ -0,0 +1,23 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate",
+            "workspace_dir": null
+        },
+        "hash": 4282859327
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/backend-unchanged/local-state.tfstate b/v1.5.7/internal/command/testdata/backend-unchanged/local-state.tfstate
new file mode 100644
index 0000000..3e61bf4
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-unchanged/local-state.tfstate
@@ -0,0 +1,6 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "configuredUnchanged"
+}
diff --git a/v1.5.7/internal/command/testdata/backend-unchanged/main.tf b/v1.5.7/internal/command/testdata/backend-unchanged/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-unchanged/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-unset-with-legacy/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-unset-with-legacy/.terraform/terraform.tfstate
new file mode 100644
index 0000000..1e8c0a1
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-unset-with-legacy/.terraform/terraform.tfstate
@@ -0,0 +1,28 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "remote": {
+        "type": "local",
+        "config": {
+            "path": "local-state-old.tfstate"
+        }
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/backend-unset-with-legacy/local-state-old.tfstate b/v1.5.7/internal/command/testdata/backend-unset-with-legacy/local-state-old.tfstate
new file mode 100644
index 0000000..e8cb7d8
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-unset-with-legacy/local-state-old.tfstate
@@ -0,0 +1,6 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "legacy"
+}
diff --git a/v1.5.7/internal/command/testdata/backend-unset-with-legacy/local-state.tfstate b/v1.5.7/internal/command/testdata/backend-unset-with-legacy/local-state.tfstate
new file mode 100644
index 0000000..1ea457c
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-unset-with-legacy/local-state.tfstate
@@ -0,0 +1,6 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "backend"
+}
diff --git a/v1.5.7/internal/command/testdata/backend-unset-with-legacy/main.tf b/v1.5.7/internal/command/testdata/backend-unset-with-legacy/main.tf
new file mode 100644
index 0000000..0422cd4
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-unset-with-legacy/main.tf
@@ -0,0 +1 @@
+# Empty, we're unsetting
diff --git a/v1.5.7/internal/command/testdata/backend-unset/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/backend-unset/.terraform/terraform.tfstate
new file mode 100644
index 0000000..073bd7a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-unset/.terraform/terraform.tfstate
@@ -0,0 +1,22 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/backend-unset/local-state.tfstate b/v1.5.7/internal/command/testdata/backend-unset/local-state.tfstate
new file mode 100644
index 0000000..45964a3
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-unset/local-state.tfstate
@@ -0,0 +1,12 @@
+{
+    "version": 4,
+    "terraform_version": "0.14.0",
+    "serial": 7,
+    "lineage": "configuredUnset",
+    "outputs": {
+        "foo": {
+            "type": "string",
+            "value": "bar"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/backend-unset/main.tf b/v1.5.7/internal/command/testdata/backend-unset/main.tf
new file mode 100644
index 0000000..3571c40
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/backend-unset/main.tf
@@ -0,0 +1 @@
+# Empty, unset!
diff --git a/v1.5.7/internal/command/testdata/command-check-required-version/main.tf b/v1.5.7/internal/command/testdata/command-check-required-version/main.tf
new file mode 100644
index 0000000..f3f71a6
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/command-check-required-version/main.tf
@@ -0,0 +1,7 @@
+terraform {
+  required_version = "~> 0.9.0"
+}
+
+terraform {
+  required_version = ">= 0.13.0"
+}
diff --git a/v1.5.7/internal/command/testdata/empty-file b/v1.5.7/internal/command/testdata/empty-file
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/empty-file
diff --git a/v1.5.7/internal/command/testdata/empty/README b/v1.5.7/internal/command/testdata/empty/README
new file mode 100644
index 0000000..8f55f30
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/empty/README
@@ -0,0 +1,2 @@
+This directory is intentionally empty, for testing any specialized error
+messages that deal with empty configuration directories.
diff --git a/v1.5.7/internal/command/testdata/fmt/general_in.tf b/v1.5.7/internal/command/testdata/fmt/general_in.tf
new file mode 100644
index 0000000..94db189
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/fmt/general_in.tf
@@ -0,0 +1,53 @@
+# This test case is intended to cover many of the main formatting
+# rules of "terraform fmt" at once. It's fine to add new stuff in
+# here, but you can also add other _in.tf/_out.tf pairs in the
+# same directory if you want to test something complicated that,
+# for example, requires specific nested context.
+#
+# The input file of this test intentionally has strange whitespace
+# alignment, because the goal is to see the fmt command fix it.
+# If you're applying batch formatting to all .tf files in the
+# repository (or similar), be sure to skip this one to avoid
+# invalidating the test.
+
+terraform {
+required_providers {
+foo = { version = "1.0.0" }
+barbaz = {
+            version = "2.0.0"
+}
+}
+}
+
+variable instance_type {
+
+}
+
+resource foo_instance foo {
+  instance_type = "${var.instance_type}"
+}
+
+resource foo_instance "bar" {
+    instance_type = "${var.instance_type}-2"
+}
+
+resource "foo_instance" /* ... */ "baz" {
+  instance_type = "${var.instance_type}${var.instance_type}"
+
+  beep boop {}
+  beep blep {
+    thingy = "${var.instance_type}"
+  }
+}
+
+  provider "" {
+}
+
+locals {
+  name = "${contains(["foo"], var.my_var) ? "${var.my_var}-bar" :
+    contains(["baz"], var.my_var) ? "baz-${var.my_var}" :
+  file("ERROR: unsupported type ${var.my_var}")}"
+  wrapped = "${(var.my_var == null ? 1 :
+    var.your_var == null ? 2 :
+  3)}"
+}
diff --git a/v1.5.7/internal/command/testdata/fmt/general_out.tf b/v1.5.7/internal/command/testdata/fmt/general_out.tf
new file mode 100644
index 0000000..1fe6b5b
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/fmt/general_out.tf
@@ -0,0 +1,53 @@
+# This test case is intended to cover many of the main formatting
+# rules of "terraform fmt" at once. It's fine to add new stuff in
+# here, but you can also add other _in.tf/_out.tf pairs in the
+# same directory if you want to test something complicated that,
+# for example, requires specific nested context.
+#
+# The input file of this test intentionally has strange whitespace
+# alignment, because the goal is to see the fmt command fix it.
+# If you're applying batch formatting to all .tf files in the
+# repository (or similar), be sure to skip this one to avoid
+# invalidating the test.
+
+terraform {
+  required_providers {
+    foo = { version = "1.0.0" }
+    barbaz = {
+      version = "2.0.0"
+    }
+  }
+}
+
+variable "instance_type" {
+
+}
+
+resource "foo_instance" "foo" {
+  instance_type = var.instance_type
+}
+
+resource "foo_instance" "bar" {
+  instance_type = "${var.instance_type}-2"
+}
+
+resource "foo_instance" "baz" {
+  instance_type = "${var.instance_type}${var.instance_type}"
+
+  beep "boop" {}
+  beep "blep" {
+    thingy = var.instance_type
+  }
+}
+
+provider "" {
+}
+
+locals {
+  name = (contains(["foo"], var.my_var) ? "${var.my_var}-bar" :
+    contains(["baz"], var.my_var) ? "baz-${var.my_var}" :
+  file("ERROR: unsupported type ${var.my_var}"))
+  wrapped = (var.my_var == null ? 1 :
+    var.your_var == null ? 2 :
+  3)
+}
diff --git a/v1.5.7/internal/command/testdata/fmt/variable_type_in.tf b/v1.5.7/internal/command/testdata/fmt/variable_type_in.tf
new file mode 100644
index 0000000..3d67812
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/fmt/variable_type_in.tf
@@ -0,0 +1,57 @@
+variable "a" {
+  type = string
+}
+
+variable "b" {
+  type = list
+}
+
+variable "c" {
+  type = map
+}
+
+variable "d" {
+  type = set
+}
+
+variable "e" {
+  type = "string"
+}
+
+variable "f" {
+  type = "list"
+}
+
+variable "g" {
+  type = "map"
+}
+
+variable "h" {
+  type = object({})
+}
+
+variable "i" {
+  type = object({
+    foo = string
+  })
+}
+
+variable "j" {
+  type = tuple([])
+}
+
+variable "k" {
+  type = tuple([number])
+}
+
+variable "l" {
+  type = list(string)
+}
+
+variable "m" {
+  type = list(
+    object({
+      foo = bool
+    })
+  )
+}
diff --git a/v1.5.7/internal/command/testdata/fmt/variable_type_out.tf b/v1.5.7/internal/command/testdata/fmt/variable_type_out.tf
new file mode 100644
index 0000000..f4f2df2
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/fmt/variable_type_out.tf
@@ -0,0 +1,57 @@
+variable "a" {
+  type = string
+}
+
+variable "b" {
+  type = list(any)
+}
+
+variable "c" {
+  type = map(any)
+}
+
+variable "d" {
+  type = set(any)
+}
+
+variable "e" {
+  type = string
+}
+
+variable "f" {
+  type = list(string)
+}
+
+variable "g" {
+  type = map(string)
+}
+
+variable "h" {
+  type = object({})
+}
+
+variable "i" {
+  type = object({
+    foo = string
+  })
+}
+
+variable "j" {
+  type = tuple([])
+}
+
+variable "k" {
+  type = tuple([number])
+}
+
+variable "l" {
+  type = list(string)
+}
+
+variable "m" {
+  type = list(
+    object({
+      foo = bool
+    })
+  )
+}
diff --git a/v1.5.7/internal/command/testdata/get/foo/main.tf b/v1.5.7/internal/command/testdata/get/foo/main.tf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/get/foo/main.tf
diff --git a/v1.5.7/internal/command/testdata/get/main.tf b/v1.5.7/internal/command/testdata/get/main.tf
new file mode 100644
index 0000000..0ce1c38
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/get/main.tf
@@ -0,0 +1,3 @@
+module "foo" {
+    source = "./foo"
+}
diff --git a/v1.5.7/internal/command/testdata/graph/main.tf b/v1.5.7/internal/command/testdata/graph/main.tf
new file mode 100644
index 0000000..1b10129
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/graph/main.tf
@@ -0,0 +1,3 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+}
diff --git a/v1.5.7/internal/command/testdata/import-missing-resource-config/main.tf b/v1.5.7/internal/command/testdata/import-missing-resource-config/main.tf
new file mode 100644
index 0000000..d644bad
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-missing-resource-config/main.tf
@@ -0,0 +1,5 @@
+provider "test" {
+
+}
+
+# No resource block present, so import fails
diff --git a/v1.5.7/internal/command/testdata/import-module-input-variable/child/main.tf b/v1.5.7/internal/command/testdata/import-module-input-variable/child/main.tf
new file mode 100644
index 0000000..6327b7c
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-module-input-variable/child/main.tf
@@ -0,0 +1,11 @@
+variable "foo" {
+  default = {}
+}
+
+locals {
+  baz = var.foo.bar.baz
+}
+
+resource "test_instance" "foo" {
+    foo = local.baz
+}
diff --git a/v1.5.7/internal/command/testdata/import-module-input-variable/main.tf b/v1.5.7/internal/command/testdata/import-module-input-variable/main.tf
new file mode 100644
index 0000000..13334c1
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-module-input-variable/main.tf
@@ -0,0 +1,8 @@
+variable "foo" {
+  default = {}
+}
+
+module "child" {
+    source = "./child"
+    foo = var.foo
+}
diff --git a/v1.5.7/internal/command/testdata/import-module-input-variable/terraform.tfvars b/v1.5.7/internal/command/testdata/import-module-input-variable/terraform.tfvars
new file mode 100644
index 0000000..39ab5cb
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-module-input-variable/terraform.tfvars
@@ -0,0 +1 @@
+foo = { bar = { baz = true } }
diff --git a/v1.5.7/internal/command/testdata/import-module-var-file/child/main.tf b/v1.5.7/internal/command/testdata/import-module-var-file/child/main.tf
new file mode 100644
index 0000000..6a4ae0d
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-module-var-file/child/main.tf
@@ -0,0 +1,5 @@
+variable "foo" {}
+
+resource "test_instance" "foo" {
+    foo = var.foo
+}
diff --git a/v1.5.7/internal/command/testdata/import-module-var-file/main.tf b/v1.5.7/internal/command/testdata/import-module-var-file/main.tf
new file mode 100644
index 0000000..222348f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-module-var-file/main.tf
@@ -0,0 +1,6 @@
+variable "foo" {}
+
+module "child" {
+    source = "./child"
+    foo = var.foo
+}
diff --git a/v1.5.7/internal/command/testdata/import-module-var-file/terraform.tfvars b/v1.5.7/internal/command/testdata/import-module-var-file/terraform.tfvars
new file mode 100644
index 0000000..5abc475
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-module-var-file/terraform.tfvars
@@ -0,0 +1 @@
+foo = "bar"
diff --git a/v1.5.7/internal/command/testdata/import-provider-aliased/main.tf b/v1.5.7/internal/command/testdata/import-provider-aliased/main.tf
new file mode 100644
index 0000000..9ef6de2
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-provider-aliased/main.tf
@@ -0,0 +1,8 @@
+provider "test" {
+    foo = "bar"
+
+    alias = "alias"
+}
+
+resource "test_instance" "foo" {
+}
diff --git a/v1.5.7/internal/command/testdata/import-provider-datasource/main.tf b/v1.5.7/internal/command/testdata/import-provider-datasource/main.tf
new file mode 100644
index 0000000..3b9fa3a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-provider-datasource/main.tf
@@ -0,0 +1,13 @@
+provider "test" {
+  foo = data.test_data.key.id
+}
+
+provider "test" {
+  alias = "credentials"
+}
+
+data "test_data" "key" {
+  provider = test.credentials
+}
+
+resource "test_instance" "foo" {}
diff --git a/v1.5.7/internal/command/testdata/import-provider-implicit/main.tf b/v1.5.7/internal/command/testdata/import-provider-implicit/main.tf
new file mode 100644
index 0000000..02ffc5b
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-provider-implicit/main.tf
@@ -0,0 +1,4 @@
+# Declaring this resource implies that we depend on the
+# "test" provider, making it available for import.
+resource "test_instance" "foo" {
+}
diff --git a/v1.5.7/internal/command/testdata/import-provider-invalid/main.tf b/v1.5.7/internal/command/testdata/import-provider-invalid/main.tf
new file mode 100644
index 0000000..c156850
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-provider-invalid/main.tf
@@ -0,0 +1,15 @@
+terraform {
+	backend "local" {
+		path = "imported.tfstate"
+	}
+}
+
+provider "test" {
+    foo = "bar"
+}
+
+resource "test_instance" "foo" {
+}
+
+resource "unknown_instance" "baz" {
+}
diff --git a/v1.5.7/internal/command/testdata/import-provider-remote-state/main.tf b/v1.5.7/internal/command/testdata/import-provider-remote-state/main.tf
new file mode 100644
index 0000000..23ebfb4
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-provider-remote-state/main.tf
@@ -0,0 +1,12 @@
+terraform {
+	backend "local" {
+		path = "imported.tfstate"
+	}
+}
+
+provider "test" {
+    foo = "bar"
+}
+
+resource "test_instance" "foo" {
+}
diff --git a/v1.5.7/internal/command/testdata/import-provider-var-default/main.tf b/v1.5.7/internal/command/testdata/import-provider-var-default/main.tf
new file mode 100644
index 0000000..c63b4c0
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-provider-var-default/main.tf
@@ -0,0 +1,8 @@
+variable "foo" {}
+
+provider "test" {
+    foo = "${var.foo}"
+}
+
+resource "test_instance" "foo" {
+}
diff --git a/v1.5.7/internal/command/testdata/import-provider-var-default/terraform.tfvars b/v1.5.7/internal/command/testdata/import-provider-var-default/terraform.tfvars
new file mode 100644
index 0000000..5abc475
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-provider-var-default/terraform.tfvars
@@ -0,0 +1 @@
+foo = "bar"
diff --git a/v1.5.7/internal/command/testdata/import-provider-var-file/blah.tfvars b/v1.5.7/internal/command/testdata/import-provider-var-file/blah.tfvars
new file mode 100644
index 0000000..5abc475
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-provider-var-file/blah.tfvars
@@ -0,0 +1 @@
+foo = "bar"
diff --git a/v1.5.7/internal/command/testdata/import-provider-var-file/main.tf b/v1.5.7/internal/command/testdata/import-provider-var-file/main.tf
new file mode 100644
index 0000000..c63b4c0
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-provider-var-file/main.tf
@@ -0,0 +1,8 @@
+variable "foo" {}
+
+provider "test" {
+    foo = "${var.foo}"
+}
+
+resource "test_instance" "foo" {
+}
diff --git a/v1.5.7/internal/command/testdata/import-provider-var/main.tf b/v1.5.7/internal/command/testdata/import-provider-var/main.tf
new file mode 100644
index 0000000..c63b4c0
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-provider-var/main.tf
@@ -0,0 +1,8 @@
+variable "foo" {}
+
+provider "test" {
+    foo = "${var.foo}"
+}
+
+resource "test_instance" "foo" {
+}
diff --git a/v1.5.7/internal/command/testdata/import-provider/main.tf b/v1.5.7/internal/command/testdata/import-provider/main.tf
new file mode 100644
index 0000000..943e8b3
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/import-provider/main.tf
@@ -0,0 +1,6 @@
+provider "test" {
+    foo = "bar"
+}
+
+resource "test_instance" "foo" {
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-config-file-change-migrate-existing/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/init-backend-config-file-change-migrate-existing/.terraform/terraform.tfstate
new file mode 100644
index 0000000..073bd7a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-config-file-change-migrate-existing/.terraform/terraform.tfstate
@@ -0,0 +1,22 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-config-file-change-migrate-existing/input.config b/v1.5.7/internal/command/testdata/init-backend-config-file-change-migrate-existing/input.config
new file mode 100644
index 0000000..6cd14f4
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-config-file-change-migrate-existing/input.config
@@ -0,0 +1 @@
+path = "hello"
diff --git a/v1.5.7/internal/command/testdata/init-backend-config-file-change-migrate-existing/local-state.tfstate b/v1.5.7/internal/command/testdata/init-backend-config-file-change-migrate-existing/local-state.tfstate
new file mode 100644
index 0000000..ce8d954
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-config-file-change-migrate-existing/local-state.tfstate
@@ -0,0 +1,21 @@
+{
+    "version": 3,
+    "terraform_version": "0.8.2",
+    "serial": 8,
+    "lineage": "local",
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {
+                "foo": {
+                    "type": "string",
+                    "value": "bar"
+                }
+            },
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-config-file-change-migrate-existing/main.tf b/v1.5.7/internal/command/testdata/init-backend-config-file-change-migrate-existing/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-config-file-change-migrate-existing/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-config-file-change/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/init-backend-config-file-change/.terraform/terraform.tfstate
new file mode 100644
index 0000000..073bd7a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-config-file-change/.terraform/terraform.tfstate
@@ -0,0 +1,22 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-config-file-change/input.config b/v1.5.7/internal/command/testdata/init-backend-config-file-change/input.config
new file mode 100644
index 0000000..6cd14f4
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-config-file-change/input.config
@@ -0,0 +1 @@
+path = "hello"
diff --git a/v1.5.7/internal/command/testdata/init-backend-config-file-change/main.tf b/v1.5.7/internal/command/testdata/init-backend-config-file-change/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-config-file-change/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-config-file/backend.config b/v1.5.7/internal/command/testdata/init-backend-config-file/backend.config
new file mode 100644
index 0000000..c3d7524
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-config-file/backend.config
@@ -0,0 +1,7 @@
+// the -backend-config flag on init cannot be used to point to a "full" backend
+// block
+terraform {
+    backend "local" {
+        path = "hello"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-config-file/input.config b/v1.5.7/internal/command/testdata/init-backend-config-file/input.config
new file mode 100644
index 0000000..6cd14f4
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-config-file/input.config
@@ -0,0 +1 @@
+path = "hello"
diff --git a/v1.5.7/internal/command/testdata/init-backend-config-file/invalid.config b/v1.5.7/internal/command/testdata/init-backend-config-file/invalid.config
new file mode 100644
index 0000000..39f97f5
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-config-file/invalid.config
@@ -0,0 +1,2 @@
+path = "hello"
+foo  = "bar"
diff --git a/v1.5.7/internal/command/testdata/init-backend-config-file/main.tf b/v1.5.7/internal/command/testdata/init-backend-config-file/main.tf
new file mode 100644
index 0000000..c08b42f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-config-file/main.tf
@@ -0,0 +1,3 @@
+terraform {
+    backend "local" {}
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-config-kv/main.tf b/v1.5.7/internal/command/testdata/init-backend-config-kv/main.tf
new file mode 100644
index 0000000..c08b42f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-config-kv/main.tf
@@ -0,0 +1,3 @@
+terraform {
+    backend "local" {}
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-empty/main.tf b/v1.5.7/internal/command/testdata/init-backend-empty/main.tf
new file mode 100644
index 0000000..7f62e0e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-empty/main.tf
@@ -0,0 +1,4 @@
+terraform {
+    backend "local" {
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-http/main.tf b/v1.5.7/internal/command/testdata/init-backend-http/main.tf
new file mode 100644
index 0000000..4ca44e9
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-http/main.tf
@@ -0,0 +1,4 @@
+terraform {
+  backend "http" {
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-migrate-while-locked/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/init-backend-migrate-while-locked/.terraform/terraform.tfstate
new file mode 100644
index 0000000..073bd7a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-migrate-while-locked/.terraform/terraform.tfstate
@@ -0,0 +1,22 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-migrate-while-locked/input.config b/v1.5.7/internal/command/testdata/init-backend-migrate-while-locked/input.config
new file mode 100644
index 0000000..6cd14f4
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-migrate-while-locked/input.config
@@ -0,0 +1 @@
+path = "hello"
diff --git a/v1.5.7/internal/command/testdata/init-backend-migrate-while-locked/main.tf b/v1.5.7/internal/command/testdata/init-backend-migrate-while-locked/main.tf
new file mode 100644
index 0000000..bea8e78
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-migrate-while-locked/main.tf
@@ -0,0 +1,5 @@
+terraform {
+  backend "local" {
+    path = "local-state.tfstate"
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/environment b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/environment
new file mode 100644
index 0000000..5716ca5
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/environment
@@ -0,0 +1 @@
+bar
diff --git a/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/terraform.tfstate
new file mode 100644
index 0000000..19a90cc
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/terraform.tfstate
@@ -0,0 +1,23 @@
+{
+    "version": 3,
+    "serial": 2,
+    "lineage": "2f3864a6-1d3e-1999-0f84-36cdb61179d3",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": null,
+            "workspace_dir": null
+        },
+        "hash": 666019178
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/main.tf b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/main.tf
new file mode 100644
index 0000000..da6f209
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/main.tf
@@ -0,0 +1,7 @@
+terraform {
+    backend "local" {}
+}
+
+output "foo" {
+  value = "bar"
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate
new file mode 100644
index 0000000..47de0a4
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate
@@ -0,0 +1,13 @@
+{
+  "version": 4,
+  "terraform_version": "1.1.0",
+  "serial": 1,
+  "lineage": "cc4bb587-aa35-87ad-b3b7-7abdb574f2a1",
+  "outputs": {
+    "foo": {
+      "value": "bar",
+      "type": "string"
+    }
+  },
+  "resources": []
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate.d/foo/terraform.tfstate b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate.d/foo/terraform.tfstate
new file mode 100644
index 0000000..70021d0
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate.d/foo/terraform.tfstate
@@ -0,0 +1,13 @@
+{
+  "version": 4,
+  "terraform_version": "1.1.0",
+  "serial": 1,
+  "lineage": "8ad3c77d-51aa-d90a-4f12-176f538b6e8b",
+  "outputs": {
+    "foo": {
+      "value": "bar",
+      "type": "string"
+    }
+  },
+  "resources": []
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/environment b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/environment
new file mode 100644
index 0000000..5716ca5
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/environment
@@ -0,0 +1 @@
+bar
diff --git a/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/terraform.tfstate
new file mode 100644
index 0000000..19a90cc
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/terraform.tfstate
@@ -0,0 +1,23 @@
+{
+    "version": 3,
+    "serial": 2,
+    "lineage": "2f3864a6-1d3e-1999-0f84-36cdb61179d3",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": null,
+            "workspace_dir": null
+        },
+        "hash": 666019178
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-single/main.tf b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-single/main.tf
new file mode 100644
index 0000000..da6f209
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-single/main.tf
@@ -0,0 +1,7 @@
+terraform {
+    backend "local" {}
+}
+
+output "foo" {
+  value = "bar"
+}
diff --git a/v1.5.7/internal/command/testdata/init-backend/main.tf b/v1.5.7/internal/command/testdata/init-backend/main.tf
new file mode 100644
index 0000000..a6bafda
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-backend/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "foo"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/init-check-required-version-first-module/main.tf b/v1.5.7/internal/command/testdata/init-check-required-version-first-module/main.tf
new file mode 100644
index 0000000..ba84684
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-check-required-version-first-module/main.tf
@@ -0,0 +1,3 @@
+module "mod" {
+  source = "./mod"
+}
diff --git a/v1.5.7/internal/command/testdata/init-check-required-version-first-module/mod/main.tf b/v1.5.7/internal/command/testdata/init-check-required-version-first-module/mod/main.tf
new file mode 100644
index 0000000..ab311d0
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-check-required-version-first-module/mod/main.tf
@@ -0,0 +1,17 @@
+terraform {
+  required_version = ">200.0.0"
+
+  bad {
+    block = "false"
+  }
+
+  required_providers {
+    bang = {
+      oops = "boom"
+    }
+  }
+}
+
+nope {
+  boom {}
+}
diff --git a/v1.5.7/internal/command/testdata/init-check-required-version-first/main.tf b/v1.5.7/internal/command/testdata/init-check-required-version-first/main.tf
new file mode 100644
index 0000000..ab311d0
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-check-required-version-first/main.tf
@@ -0,0 +1,17 @@
+terraform {
+  required_version = ">200.0.0"
+
+  bad {
+    block = "false"
+  }
+
+  required_providers {
+    bang = {
+      oops = "boom"
+    }
+  }
+}
+
+nope {
+  boom {}
+}
diff --git a/v1.5.7/internal/command/testdata/init-check-required-version/main.tf b/v1.5.7/internal/command/testdata/init-check-required-version/main.tf
new file mode 100644
index 0000000..00725e8
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-check-required-version/main.tf
@@ -0,0 +1,7 @@
+terraform {
+    required_version = "~> 0.9.0"
+}
+
+terraform {
+    required_version = ">= 0.13.0"
+}
diff --git a/v1.5.7/internal/command/testdata/init-cloud-simple/init-cloud-simple.tf b/v1.5.7/internal/command/testdata/init-cloud-simple/init-cloud-simple.tf
new file mode 100644
index 0000000..2493abe
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-cloud-simple/init-cloud-simple.tf
@@ -0,0 +1,13 @@
+# This is a simple configuration with Terraform Cloud mode minimally
+# activated, but it's suitable only for testing things that we can exercise
+# without actually accessing Terraform Cloud, such as checking of invalid
+# command-line options to "terraform init".
+
+terraform {
+  cloud {
+    organization = "PLACEHOLDER"
+    workspaces {
+        name = "PLACEHOLDER"
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/init-get-provider-detected-legacy/.terraform/modules/dicerolls/terraform-random-bar-1.0.0/main.tf b/v1.5.7/internal/command/testdata/init-get-provider-detected-legacy/.terraform/modules/dicerolls/terraform-random-bar-1.0.0/main.tf
new file mode 100644
index 0000000..ae4c998
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-get-provider-detected-legacy/.terraform/modules/dicerolls/terraform-random-bar-1.0.0/main.tf
@@ -0,0 +1,7 @@
+// This will try to install hashicorp/baz, fail, and then suggest
+// terraform-providers/baz
+provider baz {}
+
+output "d6" {
+  value = 4 // chosen by fair dice roll, guaranteed to be random
+}
diff --git a/v1.5.7/internal/command/testdata/init-get-provider-detected-legacy/.terraform/modules/modules.json b/v1.5.7/internal/command/testdata/init-get-provider-detected-legacy/.terraform/modules/modules.json
new file mode 100644
index 0000000..8ee9881
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-get-provider-detected-legacy/.terraform/modules/modules.json
@@ -0,0 +1 @@
+{"Modules":[{"Key":"dicerolls","Source":"acme/bar/random","Version":"1.0.0","Dir":".terraform/modules/dicerolls/terraform-random-bar-1.0.0"},{"Key":"","Source":"","Dir":"."}]}
diff --git a/v1.5.7/internal/command/testdata/init-get-provider-detected-legacy/child/main.tf b/v1.5.7/internal/command/testdata/init-get-provider-detected-legacy/child/main.tf
new file mode 100644
index 0000000..6c8b883
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-get-provider-detected-legacy/child/main.tf
@@ -0,0 +1,3 @@
+// This will try to install hashicorp/baz, fail, and then suggest
+// terraform-providers/baz
+provider baz {}
diff --git a/v1.5.7/internal/command/testdata/init-get-provider-detected-legacy/main.tf b/v1.5.7/internal/command/testdata/init-get-provider-detected-legacy/main.tf
new file mode 100644
index 0000000..4ba7ef4
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-get-provider-detected-legacy/main.tf
@@ -0,0 +1,18 @@
+// This should result in installing hashicorp/foo
+provider foo {}
+
+// This will try to install hashicorp/baz, fail, and then suggest
+// terraform-providers/baz
+provider baz {}
+
+// This will try to install hashicrop/frob, fail, find no suggestions, and
+// result in an error
+provider frob {}
+
+module "some-baz-stuff" {
+  source = "./child"
+}
+
+module "dicerolls" {
+  source = "acme/bar/random"
+}
diff --git a/v1.5.7/internal/command/testdata/init-get-provider-invalid-package/main.tf b/v1.5.7/internal/command/testdata/init-get-provider-invalid-package/main.tf
new file mode 100644
index 0000000..5f93ef7
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-get-provider-invalid-package/main.tf
@@ -0,0 +1,8 @@
+terraform {
+  required_providers {
+    package = {
+      source  = "invalid/package"
+      version = "1.0.0"
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/init-get-provider-legacy-from-state/main.tf b/v1.5.7/internal/command/testdata/init-get-provider-legacy-from-state/main.tf
new file mode 100644
index 0000000..3665181
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-get-provider-legacy-from-state/main.tf
@@ -0,0 +1,12 @@
+terraform {
+  required_providers {
+    alpha = {
+      source  = "acme/alpha"
+      version = "1.2.3"
+    }
+  }
+}
+
+resource "alpha_resource" "a" {
+  index = 1
+}
diff --git a/v1.5.7/internal/command/testdata/init-get-provider-legacy-from-state/terraform.tfstate b/v1.5.7/internal/command/testdata/init-get-provider-legacy-from-state/terraform.tfstate
new file mode 100644
index 0000000..33b2fb0
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-get-provider-legacy-from-state/terraform.tfstate
@@ -0,0 +1,25 @@
+{
+  "version": 4,
+  "terraform_version": "0.12.28",
+  "serial": 1,
+  "lineage": "481bf512-f245-4c60-42dc-7005f4fa9181",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "alpha_resource",
+      "name": "a",
+      "provider": "provider.alpha",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "a",
+            "index": 1
+          },
+          "private": "bnVsbA=="
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/init-get-provider-source/main.tf b/v1.5.7/internal/command/testdata/init-get-provider-source/main.tf
new file mode 100644
index 0000000..a434a97
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-get-provider-source/main.tf
@@ -0,0 +1,21 @@
+provider alpha {
+  version = "1.2.3"
+}
+
+resource beta_resource b {}
+resource gamma_resource g {}
+
+terraform {
+  required_providers {
+    alpha = {
+      source = "acme/alpha"
+    }
+    beta = {
+      source = "registry.example.com/acme/beta"
+    }
+  }
+}
+
+provider beta {
+  region = "foo"
+}
diff --git a/v1.5.7/internal/command/testdata/init-get-providers/main.tf b/v1.5.7/internal/command/testdata/init-get-providers/main.tf
new file mode 100644
index 0000000..aa288ac
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-get-providers/main.tf
@@ -0,0 +1,14 @@
+provider "exact" {
+  version = "1.2.3"
+}
+
+provider "greater-than" {
+  version = ">= 2.3.3"
+}
+
+provider "between" {
+  # The second constraint here intentionally has
+  # no space after the < operator to make sure
+  # that we can parse that form too.
+  version = "> 1.0.0 , <3.0.0"
+}
diff --git a/v1.5.7/internal/command/testdata/init-get/foo/main.tf b/v1.5.7/internal/command/testdata/init-get/foo/main.tf
new file mode 100644
index 0000000..b7db254
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-get/foo/main.tf
@@ -0,0 +1 @@
+# Empty
diff --git a/v1.5.7/internal/command/testdata/init-get/main.tf b/v1.5.7/internal/command/testdata/init-get/main.tf
new file mode 100644
index 0000000..0ce1c38
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-get/main.tf
@@ -0,0 +1,3 @@
+module "foo" {
+    source = "./foo"
+}
diff --git a/v1.5.7/internal/command/testdata/init-internal-invalid/main.tf b/v1.5.7/internal/command/testdata/init-internal-invalid/main.tf
new file mode 100644
index 0000000..109242b
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-internal-invalid/main.tf
@@ -0,0 +1,10 @@
+terraform {
+  required_providers {
+    nonexist = {
+      source = "terraform.io/builtin/nonexist"
+    }
+    terraform = {
+      version = "1.2.0"
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/init-internal/main.tf b/v1.5.7/internal/command/testdata/init-internal/main.tf
new file mode 100644
index 0000000..962d711
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-internal/main.tf
@@ -0,0 +1 @@
+provider "terraform" {}
diff --git a/v1.5.7/internal/command/testdata/init-legacy-provider-cache/.terraform/plugins/example.com/test/b/1.1.0/os_arch/terraform-provider-b b/v1.5.7/internal/command/testdata/init-legacy-provider-cache/.terraform/plugins/example.com/test/b/1.1.0/os_arch/terraform-provider-b
new file mode 100644
index 0000000..7e9920e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-legacy-provider-cache/.terraform/plugins/example.com/test/b/1.1.0/os_arch/terraform-provider-b
@@ -0,0 +1,2 @@
+# This is not a real provider executable. It's just here to be discovered
+# during installation and produce a warning about it being in the wrong place.
diff --git a/v1.5.7/internal/command/testdata/init-legacy-provider-cache/.terraform/plugins/registry.terraform.io/hashicorp/c/2.0.0/os_arch/terraform-provider-c b/v1.5.7/internal/command/testdata/init-legacy-provider-cache/.terraform/plugins/registry.terraform.io/hashicorp/c/2.0.0/os_arch/terraform-provider-c
new file mode 100644
index 0000000..7e9920e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-legacy-provider-cache/.terraform/plugins/registry.terraform.io/hashicorp/c/2.0.0/os_arch/terraform-provider-c
@@ -0,0 +1,2 @@
+# This is not a real provider executable. It's just here to be discovered
+# during installation and produce a warning about it being in the wrong place.
diff --git a/v1.5.7/internal/command/testdata/init-legacy-provider-cache/versions.tf b/v1.5.7/internal/command/testdata/init-legacy-provider-cache/versions.tf
new file mode 100644
index 0000000..7829b08
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-legacy-provider-cache/versions.tf
@@ -0,0 +1,21 @@
+terraform {
+  required_providers {
+    a = {
+      # This one is just not available at all
+      source = "example.com/test/a"
+    }
+    b = {
+      # This one is unavailable but happens to be cached in the legacy
+      # cache directory, under .terraform/plugins
+      source = "example.com/test/b"
+    }
+    c = {
+      # This one is also cached in the legacy cache directory, but it's
+      # an official provider so init will assume it got there via normal
+      # automatic installation and not generate a warning about it.
+      # This one is also not available at all, but it's an official
+      # provider so we don't expect to see a warning about it.
+      source = "hashicorp/c"
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/init-legacy-rc/main.tf b/v1.5.7/internal/command/testdata/init-legacy-rc/main.tf
new file mode 100644
index 0000000..4b04a89
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-legacy-rc/main.tf
@@ -0,0 +1 @@
+provider "legacy" {}
diff --git a/v1.5.7/internal/command/testdata/init-provider-lock-file-readonly-add/main.tf b/v1.5.7/internal/command/testdata/init-provider-lock-file-readonly-add/main.tf
new file mode 100644
index 0000000..a706a53
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-provider-lock-file-readonly-add/main.tf
@@ -0,0 +1,10 @@
+terraform {
+  required_providers {
+    test = {
+      version = "1.2.3"
+    }
+    foo = {
+      version = "1.0.0"
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/init-provider-lock-file/main.tf b/v1.5.7/internal/command/testdata/init-provider-lock-file/main.tf
new file mode 100644
index 0000000..7eed7c5
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-provider-lock-file/main.tf
@@ -0,0 +1,3 @@
+provider "test" {
+	version = "1.2.3"
+}
diff --git a/v1.5.7/internal/command/testdata/init-provider-now-unused/main.tf b/v1.5.7/internal/command/testdata/init-provider-now-unused/main.tf
new file mode 100644
index 0000000..e1f1ec1
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-provider-now-unused/main.tf
@@ -0,0 +1,3 @@
+# Intentionally blank, but intended to be used in a test case which
+# uses an input lock file which already had an entry for the hashicorp/test
+# provider, and should therefore detect it as no longer used.
diff --git a/v1.5.7/internal/command/testdata/init-providers-lock/main.tf b/v1.5.7/internal/command/testdata/init-providers-lock/main.tf
new file mode 100644
index 0000000..7eed7c5
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-providers-lock/main.tf
@@ -0,0 +1,3 @@
+provider "test" {
+	version = "1.2.3"
+}
diff --git a/v1.5.7/internal/command/testdata/init-registry-module/main.tf b/v1.5.7/internal/command/testdata/init-registry-module/main.tf
new file mode 100644
index 0000000..cc388d7
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-registry-module/main.tf
@@ -0,0 +1,4 @@
+module "foo" {
+  source = "registry.does.not.exist/example_corp/foo/bar"
+  version = "0.1.0"
+}
diff --git a/v1.5.7/internal/command/testdata/init-required-providers/main.tf b/v1.5.7/internal/command/testdata/init-required-providers/main.tf
new file mode 100644
index 0000000..20dac12
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-required-providers/main.tf
@@ -0,0 +1,11 @@
+terraform {
+  required_providers {
+    test = "1.2.3"
+    source = {
+      version = "1.2.3"
+    }
+    test-beta = {
+      version = "1.2.4"
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/init-syntax-invalid-backend-attribute-invalid/main.tf b/v1.5.7/internal/command/testdata/init-syntax-invalid-backend-attribute-invalid/main.tf
new file mode 100644
index 0000000..8e50cf0
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-syntax-invalid-backend-attribute-invalid/main.tf
@@ -0,0 +1,10 @@
+
+terraform {
+  backend "local" {
+    path = $invalid
+  }
+}
+
+variable "input" {
+  type = string
+}
diff --git a/v1.5.7/internal/command/testdata/init-syntax-invalid-backend-invalid/main.tf b/v1.5.7/internal/command/testdata/init-syntax-invalid-backend-invalid/main.tf
new file mode 100644
index 0000000..4fb3f33
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-syntax-invalid-backend-invalid/main.tf
@@ -0,0 +1,7 @@
+terraform {
+  backend "nonexistent" {}
+}
+
+bad_block {
+}
+
diff --git a/v1.5.7/internal/command/testdata/init-syntax-invalid-no-backend/main.tf b/v1.5.7/internal/command/testdata/init-syntax-invalid-no-backend/main.tf
new file mode 100644
index 0000000..5f1451d
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-syntax-invalid-no-backend/main.tf
@@ -0,0 +1,3 @@
+bad_block {
+}
+
diff --git a/v1.5.7/internal/command/testdata/init-syntax-invalid-with-backend/main.tf b/v1.5.7/internal/command/testdata/init-syntax-invalid-with-backend/main.tf
new file mode 100644
index 0000000..2ea4406
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init-syntax-invalid-with-backend/main.tf
@@ -0,0 +1,7 @@
+terraform {
+  backend "local" {}
+}
+
+bad_block {
+}
+
diff --git a/v1.5.7/internal/command/testdata/init/hello.tf b/v1.5.7/internal/command/testdata/init/hello.tf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/init/hello.tf
diff --git a/v1.5.7/internal/command/testdata/inmem-backend/main.tf b/v1.5.7/internal/command/testdata/inmem-backend/main.tf
new file mode 100644
index 0000000..df9309a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/inmem-backend/main.tf
@@ -0,0 +1,3 @@
+terraform {
+  backend "inmem" {}
+}
diff --git a/v1.5.7/internal/command/testdata/login-oauth-server/main.go b/v1.5.7/internal/command/testdata/login-oauth-server/main.go
new file mode 100644
index 0000000..105936c
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/login-oauth-server/main.go
@@ -0,0 +1,72 @@
+//go:build ignore
+// +build ignore
+
+// This file is a helper for those doing _manual_ testing of "terraform login"
+// and/or "terraform logout" and want to start up a test OAuth server in a
+// separate process for convenience:
+//
+//    go run ./command/testdata/login-oauth-server/main.go :8080
+//
+// This is _not_ the main way to use this oauthserver package. For automated
+// test code, import it as a normal Go package instead:
+//
+//     import oauthserver "github.com/hashicorp/terraform/internal/command/testdata/login-oauth-server"
+
+package main
+
+import (
+	"fmt"
+	"net"
+	"net/http"
+	"os"
+
+	oauthserver "github.com/hashicorp/terraform/internal/command/testdata/login-oauth-server"
+)
+
+func main() {
+	if len(os.Args) < 2 {
+		fmt.Fprintln(os.Stderr, "Usage: go run ./command/testdata/login-oauth-server/main.go <listen-address>")
+		os.Exit(1)
+	}
+
+	host, port, err := net.SplitHostPort(os.Args[1])
+	if err != nil {
+		fmt.Fprintln(os.Stderr, "Invalid address: %s", err)
+		os.Exit(1)
+	}
+
+	if host == "" {
+		host = "127.0.0.1"
+	}
+	addr := fmt.Sprintf("%s:%s", host, port)
+
+	fmt.Printf("Will listen on %s...\n", addr)
+	fmt.Printf(
+		configExampleFmt,
+		fmt.Sprintf("http://%s:%s/authz", host, port),
+		fmt.Sprintf("http://%s:%s/token", host, port),
+		fmt.Sprintf("http://%s:%s/revoke", host, port),
+	)
+
+	server := &http.Server{
+		Addr:    addr,
+		Handler: oauthserver.Handler,
+	}
+	err = server.ListenAndServe()
+	fmt.Fprintln(os.Stderr, err.Error())
+}
+
+const configExampleFmt = `
+host "login-test.example.com" {
+  services = {
+    "login.v1" = {
+      authz       = %q
+      token       = %q
+      client      = "placeholder"
+      grant_types = ["code", "password"]
+    }
+    "logout.v1" = %q
+  }
+}
+
+`
diff --git a/v1.5.7/internal/command/testdata/login-oauth-server/oauthserver.go b/v1.5.7/internal/command/testdata/login-oauth-server/oauthserver.go
new file mode 100644
index 0000000..5454a1d
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/login-oauth-server/oauthserver.go
@@ -0,0 +1,179 @@
+// Package oauthserver is a very simplistic OAuth server used only for
+// the testing of the "terraform login" and "terraform logout" commands.
+package oauthserver
+
+import (
+	"crypto/sha256"
+	"encoding/base64"
+	"fmt"
+	"html"
+	"log"
+	"net/http"
+	"net/url"
+	"strings"
+)
+
+// Handler is an implementation of net/http.Handler that provides a stub
+// OAuth server implementation with the following endpoints:
+//
+//     /authz  - authorization endpoint
+//     /token  - token endpoint
+//     /revoke - token revocation (logout) endpoint
+//
+// The authorization endpoint returns HTML per normal OAuth conventions, but
+// it also includes an HTTP header X-Redirect-To giving the same URL that the
+// link in the HTML indicates, allowing a non-browser user-agent to traverse
+// this robotically in automated tests.
+var Handler http.Handler
+
+type handler struct{}
+
+func (h handler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
+	switch req.URL.Path {
+	case "/authz":
+		h.serveAuthz(resp, req)
+	case "/token":
+		h.serveToken(resp, req)
+	case "/revoke":
+		h.serveRevoke(resp, req)
+	default:
+		resp.WriteHeader(404)
+	}
+}
+
+func (h handler) serveAuthz(resp http.ResponseWriter, req *http.Request) {
+	args := req.URL.Query()
+	if rt := args.Get("response_type"); rt != "code" {
+		resp.WriteHeader(400)
+		resp.Write([]byte("wrong response_type"))
+		log.Printf("/authz: incorrect response type %q", rt)
+		return
+	}
+	redirectURL, err := url.Parse(args.Get("redirect_uri"))
+	if err != nil {
+		resp.WriteHeader(400)
+		resp.Write([]byte(fmt.Sprintf("invalid redirect_uri %s: %s", args.Get("redirect_uri"), err)))
+		return
+	}
+
+	state := args.Get("state")
+	challenge := args.Get("code_challenge")
+	challengeMethod := args.Get("code_challenge_method")
+	if challengeMethod == "" {
+		challengeMethod = "plain"
+	}
+
+	// NOTE: This is not a suitable implementation for a real OAuth server
+	// because the code challenge is providing no security whatsoever. This
+	// is just a simple implementation for this stub server.
+	code := fmt.Sprintf("%s:%s", challengeMethod, challenge)
+
+	redirectQuery := redirectURL.Query()
+	redirectQuery.Set("code", code)
+	if state != "" {
+		redirectQuery.Set("state", state)
+	}
+	redirectURL.RawQuery = redirectQuery.Encode()
+
+	respBody := fmt.Sprintf(`<a href="%s">Log In and Consent</a>`, html.EscapeString(redirectURL.String()))
+	resp.Header().Set("Content-Type", "text/html")
+	resp.Header().Set("Content-Length", fmt.Sprintf("%d", len(respBody)))
+	resp.Header().Set("X-Redirect-To", redirectURL.String()) // For robotic clients, using webbrowser.MockLauncher
+	resp.WriteHeader(200)
+	resp.Write([]byte(respBody))
+}
+
+func (h handler) serveToken(resp http.ResponseWriter, req *http.Request) {
+	if req.Method != "POST" {
+		resp.WriteHeader(405)
+		log.Printf("/token: unsupported request method %q", req.Method)
+		return
+	}
+
+	if err := req.ParseForm(); err != nil {
+		resp.WriteHeader(500)
+		log.Printf("/token: error parsing body: %s", err)
+		return
+	}
+
+	grantType := req.Form.Get("grant_type")
+	log.Printf("/token: grant_type is %q", grantType)
+	switch grantType {
+
+	case "authorization_code":
+		code := req.Form.Get("code")
+		codeParts := strings.SplitN(code, ":", 2)
+		if len(codeParts) != 2 {
+			log.Printf("/token: invalid code %q", code)
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(400)
+			resp.Write([]byte(`{"error":"invalid_grant"}`))
+			return
+		}
+
+		codeVerifier := req.Form.Get("code_verifier")
+
+		switch codeParts[0] {
+		case "plain":
+			if codeParts[1] != codeVerifier {
+				log.Printf("/token: incorrect code verifier %q; want %q", codeParts[1], codeVerifier)
+				resp.Header().Set("Content-Type", "application/json")
+				resp.WriteHeader(400)
+				resp.Write([]byte(`{"error":"invalid_grant"}`))
+				return
+			}
+		case "S256":
+			h := sha256.New()
+			h.Write([]byte(codeVerifier))
+			encVerifier := base64.RawURLEncoding.EncodeToString(h.Sum(nil))
+			if codeParts[1] != encVerifier {
+				log.Printf("/token: incorrect code verifier %q; want %q", codeParts[1], encVerifier)
+				resp.Header().Set("Content-Type", "application/json")
+				resp.WriteHeader(400)
+				resp.Write([]byte(`{"error":"invalid_grant"}`))
+				return
+			}
+		default:
+			log.Printf("/token: unsupported challenge method %q", codeParts[0])
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(400)
+			resp.Write([]byte(`{"error":"invalid_grant"}`))
+			return
+		}
+
+		resp.Header().Set("Content-Type", "application/json")
+		resp.WriteHeader(200)
+		resp.Write([]byte(`{"access_token":"good-token","token_type":"bearer"}`))
+		log.Println("/token: successful request")
+
+	case "password":
+		username := req.Form.Get("username")
+		password := req.Form.Get("password")
+
+		if username == "wrong" || password == "wrong" {
+			// These special "credentials" allow testing for the error case.
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(400)
+			resp.Write([]byte(`{"error":"invalid_grant"}`))
+			log.Println("/token: 'wrong' credentials")
+			return
+		}
+
+		resp.Header().Set("Content-Type", "application/json")
+		resp.WriteHeader(200)
+		resp.Write([]byte(`{"access_token":"good-token","token_type":"bearer"}`))
+		log.Println("/token: successful request")
+
+	default:
+		resp.WriteHeader(400)
+		log.Printf("/token: unsupported grant type %q", grantType)
+	}
+}
+
+func (h handler) serveRevoke(resp http.ResponseWriter, req *http.Request) {
+	resp.WriteHeader(404)
+}
+
+func init() {
+	Handler = handler{}
+}
diff --git a/v1.5.7/internal/command/testdata/login-tfe-server/tfeserver.go b/v1.5.7/internal/command/testdata/login-tfe-server/tfeserver.go
new file mode 100644
index 0000000..111c071
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/login-tfe-server/tfeserver.go
@@ -0,0 +1,62 @@
+// Package tfeserver is a test stub implementing a subset of the TFE API used
+// only for the testing of the "terraform login" command.
+package tfeserver
+
+import (
+	"fmt"
+	"net/http"
+	"strings"
+)
+
+const (
+	goodToken      = "good-token"
+	accountDetails = `{"data":{"id":"user-abc123","type":"users","attributes":{"username":"testuser","email":"testuser@example.com"}}}`
+	MOTD           = `{"msg":"Welcome to Terraform Cloud!"}`
+)
+
+// Handler is an implementation of net/http.Handler that provides a stub
+// TFE API server implementation with the following endpoints:
+//
+//     /ping            - API existence endpoint
+//     /account/details - current user endpoint
+var Handler http.Handler
+
+type handler struct{}
+
+func (h handler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
+	resp.Header().Set("Content-Type", "application/vnd.api+json")
+	switch req.URL.Path {
+	case "/api/v2/ping":
+		h.servePing(resp, req)
+	case "/api/v2/account/details":
+		h.serveAccountDetails(resp, req)
+	case "/api/terraform/motd":
+		h.serveMOTD(resp, req)
+	default:
+		fmt.Printf("404 when fetching %s\n", req.URL.String())
+		http.Error(resp, `{"errors":[{"status":"404","title":"not found"}]}`, http.StatusNotFound)
+	}
+}
+
+func (h handler) servePing(resp http.ResponseWriter, req *http.Request) {
+	resp.WriteHeader(http.StatusNoContent)
+}
+
+func (h handler) serveAccountDetails(resp http.ResponseWriter, req *http.Request) {
+	if !strings.Contains(req.Header.Get("Authorization"), goodToken) {
+		http.Error(resp, `{"errors":[{"status":"401","title":"unauthorized"}]}`, http.StatusUnauthorized)
+		return
+	}
+
+	resp.WriteHeader(http.StatusOK)
+	resp.Write([]byte(accountDetails))
+}
+
+func (h handler) serveMOTD(resp http.ResponseWriter, req *http.Request) {
+	resp.WriteHeader(http.StatusOK)
+	resp.Write([]byte(MOTD))
+}
+
+func init() {
+	Handler = handler{}
+}
diff --git a/v1.5.7/internal/command/testdata/modules/.terraform/modules/modules.json b/v1.5.7/internal/command/testdata/modules/.terraform/modules/modules.json
new file mode 100644
index 0000000..b812559
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/modules/.terraform/modules/modules.json
@@ -0,0 +1 @@
+{"Modules":[{"Key":"","Source":"","Dir":"."},{"Key":"child","Source":"./child","Dir":"child"},{"Key":"count_child","Source":"./child","Dir":"child"}]}
\ No newline at end of file
diff --git a/v1.5.7/internal/command/testdata/modules/child/main.tf b/v1.5.7/internal/command/testdata/modules/child/main.tf
new file mode 100644
index 0000000..f059e25
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/modules/child/main.tf
@@ -0,0 +1,5 @@
+resource "test_instance" "test" {
+}
+output "myoutput" {
+  value = "bar"
+}
diff --git a/v1.5.7/internal/command/testdata/modules/main.tf b/v1.5.7/internal/command/testdata/modules/main.tf
new file mode 100644
index 0000000..4802b56
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/modules/main.tf
@@ -0,0 +1,11 @@
+locals {
+  foo = 3
+}
+
+module "child" {
+  source = "./child"
+}
+module "count_child" {
+  count = 1
+  source = "./child"
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/command/testdata/modules/terraform.tfstate b/v1.5.7/internal/command/testdata/modules/terraform.tfstate
new file mode 100644
index 0000000..36ff20d
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/modules/terraform.tfstate
@@ -0,0 +1,23 @@
+{
+    "version": 4,
+    "terraform_version": "0.13.0",
+    "serial": 7,
+    "lineage": "9cb740e3-d64d-e53e-a8e4-99b9bcacf24b",
+    "outputs": {},
+    "resources": [
+      {
+        "module": "module.child",
+        "mode": "managed",
+        "type": "test_instance",
+        "name": "test",
+        "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+        "instances": [
+          {
+            "schema_version": 0,
+            "attributes": {}
+          }
+        ]
+      }
+    ]
+  }
+  
\ No newline at end of file
diff --git a/v1.5.7/internal/command/testdata/parallelism/main.tf b/v1.5.7/internal/command/testdata/parallelism/main.tf
new file mode 100644
index 0000000..6032c62
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/parallelism/main.tf
@@ -0,0 +1,10 @@
+resource "test0_instance" "foo" {}
+resource "test1_instance" "foo" {}
+resource "test2_instance" "foo" {}
+resource "test3_instance" "foo" {}
+resource "test4_instance" "foo" {}
+resource "test5_instance" "foo" {}
+resource "test6_instance" "foo" {}
+resource "test7_instance" "foo" {}
+resource "test8_instance" "foo" {}
+resource "test9_instance" "foo" {}
diff --git a/v1.5.7/internal/command/testdata/plan-emptydiff/main.tf b/v1.5.7/internal/command/testdata/plan-emptydiff/main.tf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/plan-emptydiff/main.tf
diff --git a/v1.5.7/internal/command/testdata/plan-fail-condition/main.tf b/v1.5.7/internal/command/testdata/plan-fail-condition/main.tf
new file mode 100644
index 0000000..5cee0ff
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/plan-fail-condition/main.tf
@@ -0,0 +1,15 @@
+locals {
+  ami = "bar"
+}
+
+resource "test_instance" "foo" {
+  ami = local.ami
+
+  lifecycle {
+    precondition {
+      // failing condition
+      condition = local.ami != "bar"
+      error_message = "ami is bar"
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/plan-import-config-gen/generated.tf.expected b/v1.5.7/internal/command/testdata/plan-import-config-gen/generated.tf.expected
new file mode 100644
index 0000000..c864b2a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/plan-import-config-gen/generated.tf.expected
@@ -0,0 +1,7 @@
+# __generated__ by Terraform
+# Please review these resources and move them into your main configuration files.
+
+# __generated__ by Terraform from "bar"
+resource "test_instance" "foo" {
+  ami = null
+}
diff --git a/v1.5.7/internal/command/testdata/plan-import-config-gen/main.tf b/v1.5.7/internal/command/testdata/plan-import-config-gen/main.tf
new file mode 100644
index 0000000..ea89e71
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/plan-import-config-gen/main.tf
@@ -0,0 +1,4 @@
+import {
+  id = "bar"
+  to = test_instance.foo
+}
diff --git a/v1.5.7/internal/command/testdata/plan-invalid/main.tf b/v1.5.7/internal/command/testdata/plan-invalid/main.tf
new file mode 100644
index 0000000..a81c80e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/plan-invalid/main.tf
@@ -0,0 +1,10 @@
+resource "test_instance" "foo" {
+  count = 5
+}
+
+resource "test_instance" "bar" {
+  # This is invalid because timestamp() returns an unknown value during plan,
+  # but the "count" argument in particular must always be known during plan
+  # so we can predict how many instances we will operate on.
+  count = timestamp()
+}
diff --git a/v1.5.7/internal/command/testdata/plan-out-backend-legacy/main.tf b/v1.5.7/internal/command/testdata/plan-out-backend-legacy/main.tf
new file mode 100644
index 0000000..1b10129
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/plan-out-backend-legacy/main.tf
@@ -0,0 +1,3 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+}
diff --git a/v1.5.7/internal/command/testdata/plan-out-backend/main.tf b/v1.5.7/internal/command/testdata/plan-out-backend/main.tf
new file mode 100644
index 0000000..38ba171
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/plan-out-backend/main.tf
@@ -0,0 +1,8 @@
+terraform {
+  backend "http" {
+  }
+}
+
+resource "test_instance" "foo" {
+  ami = "bar"
+}
diff --git a/v1.5.7/internal/command/testdata/plan-provider-input/main.tf b/v1.5.7/internal/command/testdata/plan-provider-input/main.tf
new file mode 100644
index 0000000..4211ba3
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/plan-provider-input/main.tf
@@ -0,0 +1,20 @@
+variable "users" {
+    default = {
+        one = "onepw"
+        two = "twopw"
+    }
+}
+
+provider "test" {
+    url = "example.com"
+    
+    dynamic "auth" {
+        for_each = var.users
+        content {
+            user     = auth.key
+            password = auth.value
+        }
+    }
+}
+
+resource "test_instance" "test" {}
\ No newline at end of file
diff --git a/v1.5.7/internal/command/testdata/plan-replace/main.tf b/v1.5.7/internal/command/testdata/plan-replace/main.tf
new file mode 100644
index 0000000..efc6729
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/plan-replace/main.tf
@@ -0,0 +1,2 @@
+resource "test_instance" "a" {
+}
diff --git a/v1.5.7/internal/command/testdata/plan-vars/main.tf b/v1.5.7/internal/command/testdata/plan-vars/main.tf
new file mode 100644
index 0000000..005abad
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/plan-vars/main.tf
@@ -0,0 +1,5 @@
+variable "foo" {}
+
+resource "test_instance" "foo" {
+    value = "${var.foo}"
+}
diff --git a/v1.5.7/internal/command/testdata/plan/main.tf b/v1.5.7/internal/command/testdata/plan/main.tf
new file mode 100644
index 0000000..7b30915
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/plan/main.tf
@@ -0,0 +1,13 @@
+resource "test_instance" "foo" {
+  ami = "bar"
+
+  # This is here because at some point it caused a test failure
+  network_interface {
+    device_index = 0
+    description  = "Main network interface"
+  }
+}
+
+data "test_data_source" "a" {
+  id = "zzzzz"
+}
diff --git a/v1.5.7/internal/command/testdata/plan/output.jsonlog b/v1.5.7/internal/command/testdata/plan/output.jsonlog
new file mode 100644
index 0000000..7f42c6e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/plan/output.jsonlog
@@ -0,0 +1,5 @@
+{"@level":"info","@message":"Terraform 1.3.0-dev","@module":"terraform.ui","terraform":"1.3.0-dev","type":"version","ui":"1.0"}
+{"@level":"info","@message":"data.test_data_source.a: Refreshing...","@module":"terraform.ui","hook":{"resource":{"addr":"data.test_data_source.a","module":"","resource":"data.test_data_source.a","implied_provider":"test","resource_type":"test_data_source","resource_name":"a","resource_key":null},"action":"read"},"type":"apply_start"}
+{"@level":"info","@message":"data.test_data_source.a: Refresh complete after 0s [id=zzzzz]","@module":"terraform.ui","hook":{"resource":{"addr":"data.test_data_source.a","module":"","resource":"data.test_data_source.a","implied_provider":"test","resource_type":"test_data_source","resource_name":"a","resource_key":null},"action":"read","id_key":"id","id_value":"zzzzz","elapsed_seconds":0},"type":"apply_complete"}
+{"@level":"info","@message":"test_instance.foo: Plan to create","@module":"terraform.ui","change":{"resource":{"addr":"test_instance.foo","module":"","resource":"test_instance.foo","implied_provider":"test","resource_type":"test_instance","resource_name":"foo","resource_key":null},"action":"create"},"type":"planned_change"}
+{"@level":"info","@message":"Plan: 1 to add, 0 to change, 0 to destroy.","@module":"terraform.ui","changes":{"add":1,"import":0,"change":0,"remove":0,"operation":"plan"},"type":"change_summary"}
diff --git a/v1.5.7/internal/command/testdata/providers-lock/append/.terraform.lock.hcl b/v1.5.7/internal/command/testdata/providers-lock/append/.terraform.lock.hcl
new file mode 100644
index 0000000..1f711f0
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers-lock/append/.terraform.lock.hcl
@@ -0,0 +1,9 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/test" {
+  version = "1.0.0"
+  hashes = [
+    "h1:invalid",
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/providers-lock/append/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test b/v1.5.7/internal/command/testdata/providers-lock/append/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers-lock/append/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test
diff --git a/v1.5.7/internal/command/testdata/providers-lock/append/main.tf b/v1.5.7/internal/command/testdata/providers-lock/append/main.tf
new file mode 100644
index 0000000..d3de379
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers-lock/append/main.tf
@@ -0,0 +1,7 @@
+terraform {
+    required_providers {
+        test = {
+            source = "hashicorp/test"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/providers-lock/basic/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test b/v1.5.7/internal/command/testdata/providers-lock/basic/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers-lock/basic/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test
diff --git a/v1.5.7/internal/command/testdata/providers-lock/basic/main.tf b/v1.5.7/internal/command/testdata/providers-lock/basic/main.tf
new file mode 100644
index 0000000..41b211f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers-lock/basic/main.tf
@@ -0,0 +1,7 @@
+terraform {
+    required_providers {
+        test = {
+            source = "hashicorp/test"
+        }
+    }
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/command/testdata/providers-schema/basic/output.json b/v1.5.7/internal/command/testdata/providers-schema/basic/output.json
new file mode 100644
index 0000000..dfac55b
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers-schema/basic/output.json
@@ -0,0 +1,60 @@
+{
+    "format_version": "1.0",
+    "provider_schemas": {
+        "registry.terraform.io/hashicorp/test": {
+            "provider": {
+                "version": 0,
+                "block": {
+                    "attributes": {
+                        "region": {
+                            "description_kind": "plain",
+                            "optional": true,
+                            "type": "string"
+                        }
+                    },
+                    "description_kind": "plain"
+                }
+            },
+            "resource_schemas": {
+                "test_instance": {
+                    "version": 0,
+                    "block": {
+                        "attributes": {
+                            "ami": {
+                                "type": "string",
+                                "optional": true,
+                                "description_kind": "plain"
+                            },
+                            "id": {
+                                "type": "string",
+                                "optional": true,
+                                "computed": true,
+                                "description_kind": "plain"
+                            },
+                            "volumes": {
+                                "nested_type": {
+                                    "nesting_mode": "list",
+                                    "attributes": {
+                                        "size": {
+                                            "type": "string",
+                                            "required": true,
+                                            "description_kind": "plain"
+                                        },
+                                        "mount_point": {
+                                            "type": "string",
+                                            "required": true,
+                                            "description_kind": "plain"
+                                        }
+                                    }
+                                },
+                                "description_kind": "plain",
+                                "optional": true
+                            }
+                        },
+                        "description_kind": "plain"
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/providers-schema/basic/provider.tf b/v1.5.7/internal/command/testdata/providers-schema/basic/provider.tf
new file mode 100644
index 0000000..06e5111
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers-schema/basic/provider.tf
@@ -0,0 +1,3 @@
+provider "test" {
+
+}
diff --git a/v1.5.7/internal/command/testdata/providers-schema/empty/main.tf b/v1.5.7/internal/command/testdata/providers-schema/empty/main.tf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers-schema/empty/main.tf
diff --git a/v1.5.7/internal/command/testdata/providers-schema/empty/output.json b/v1.5.7/internal/command/testdata/providers-schema/empty/output.json
new file mode 100644
index 0000000..381450c
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers-schema/empty/output.json
@@ -0,0 +1,3 @@
+{
+    "format_version": "1.0"
+}
diff --git a/v1.5.7/internal/command/testdata/providers-schema/required/output.json b/v1.5.7/internal/command/testdata/providers-schema/required/output.json
new file mode 100644
index 0000000..dfac55b
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers-schema/required/output.json
@@ -0,0 +1,60 @@
+{
+    "format_version": "1.0",
+    "provider_schemas": {
+        "registry.terraform.io/hashicorp/test": {
+            "provider": {
+                "version": 0,
+                "block": {
+                    "attributes": {
+                        "region": {
+                            "description_kind": "plain",
+                            "optional": true,
+                            "type": "string"
+                        }
+                    },
+                    "description_kind": "plain"
+                }
+            },
+            "resource_schemas": {
+                "test_instance": {
+                    "version": 0,
+                    "block": {
+                        "attributes": {
+                            "ami": {
+                                "type": "string",
+                                "optional": true,
+                                "description_kind": "plain"
+                            },
+                            "id": {
+                                "type": "string",
+                                "optional": true,
+                                "computed": true,
+                                "description_kind": "plain"
+                            },
+                            "volumes": {
+                                "nested_type": {
+                                    "nesting_mode": "list",
+                                    "attributes": {
+                                        "size": {
+                                            "type": "string",
+                                            "required": true,
+                                            "description_kind": "plain"
+                                        },
+                                        "mount_point": {
+                                            "type": "string",
+                                            "required": true,
+                                            "description_kind": "plain"
+                                        }
+                                    }
+                                },
+                                "description_kind": "plain",
+                                "optional": true
+                            }
+                        },
+                        "description_kind": "plain"
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/providers-schema/required/provider.tf b/v1.5.7/internal/command/testdata/providers-schema/required/provider.tf
new file mode 100644
index 0000000..a6475e1
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers-schema/required/provider.tf
@@ -0,0 +1,7 @@
+terraform {
+  required_providers {
+    test = {
+      source = "hashicorp/test"
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/providers/basic/main.tf b/v1.5.7/internal/command/testdata/providers/basic/main.tf
new file mode 100644
index 0000000..d22a2b5
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers/basic/main.tf
@@ -0,0 +1,11 @@
+provider "foo" {
+
+}
+
+resource "bar_instance" "test" {
+
+}
+
+provider "baz" {
+  version = "1.2.0"
+}
diff --git a/v1.5.7/internal/command/testdata/providers/modules/child/main.tf b/v1.5.7/internal/command/testdata/providers/modules/child/main.tf
new file mode 100644
index 0000000..e5bd702
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers/modules/child/main.tf
@@ -0,0 +1 @@
+resource "baz_resource" "baz" {}
diff --git a/v1.5.7/internal/command/testdata/providers/modules/main.tf b/v1.5.7/internal/command/testdata/providers/modules/main.tf
new file mode 100644
index 0000000..37e1793
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers/modules/main.tf
@@ -0,0 +1,15 @@
+terraform {
+  required_providers {
+    foo = {
+      version = "1.0"
+    }
+  }
+}
+
+provider "bar" {
+  version = "2.0.0"
+}
+
+module "kiddo" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/command/testdata/providers/state/main.tf b/v1.5.7/internal/command/testdata/providers/state/main.tf
new file mode 100644
index 0000000..b34c855
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers/state/main.tf
@@ -0,0 +1,11 @@
+terraform {
+  required_providers {
+    foo = {
+      version = "1.0"
+    }
+  }
+}
+
+provider "bar" {
+  version = "2.0.0"
+}
diff --git a/v1.5.7/internal/command/testdata/providers/state/terraform.tfstate b/v1.5.7/internal/command/testdata/providers/state/terraform.tfstate
new file mode 100644
index 0000000..7e58182
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/providers/state/terraform.tfstate
@@ -0,0 +1,24 @@
+{
+    "version": 4,
+    "terraform_version": "0.13.0",
+    "serial": 1,
+    "lineage": "00bfda35-ad61-ec8d-c013-14b0320bc416",
+    "outputs": {},
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "baz_instance",
+            "name": "example",
+            "provider": "provider[\"registry.terraform.io/hashicorp/baz\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes": {
+                        "id": "621124146446964903"
+                    },
+                    "private": "bnVsbA=="
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/push-backend-new/main.tf b/v1.5.7/internal/command/testdata/push-backend-new/main.tf
new file mode 100644
index 0000000..68a49b4
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/push-backend-new/main.tf
@@ -0,0 +1,5 @@
+terraform {
+  backend "inmem" {}
+}
+
+atlas { name = "hello" }
diff --git a/v1.5.7/internal/command/testdata/push-input-partial/main.tf b/v1.5.7/internal/command/testdata/push-input-partial/main.tf
new file mode 100644
index 0000000..8285c1a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/push-input-partial/main.tf
@@ -0,0 +1,8 @@
+variable "foo" {}
+variable "bar" {}
+
+resource "test_instance" "foo" {}
+
+atlas {
+    name = "foo"
+}
diff --git a/v1.5.7/internal/command/testdata/push-input/main.tf b/v1.5.7/internal/command/testdata/push-input/main.tf
new file mode 100644
index 0000000..3bd930c
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/push-input/main.tf
@@ -0,0 +1,7 @@
+variable "foo" {}
+
+resource "test_instance" "foo" {}
+
+atlas {
+    name = "foo"
+}
diff --git a/v1.5.7/internal/command/testdata/push-no-remote/main.tf b/v1.5.7/internal/command/testdata/push-no-remote/main.tf
new file mode 100644
index 0000000..2651626
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/push-no-remote/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "foo" {}
+
+atlas {
+    name = "foo"
+}
diff --git a/v1.5.7/internal/command/testdata/push-no-upload/child/main.tf b/v1.5.7/internal/command/testdata/push-no-upload/child/main.tf
new file mode 100644
index 0000000..b7db254
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/push-no-upload/child/main.tf
@@ -0,0 +1 @@
+# Empty
diff --git a/v1.5.7/internal/command/testdata/push-no-upload/main.tf b/v1.5.7/internal/command/testdata/push-no-upload/main.tf
new file mode 100644
index 0000000..c70c8b6
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/push-no-upload/main.tf
@@ -0,0 +1 @@
+module "example" { source = "./child" }
diff --git a/v1.5.7/internal/command/testdata/push-tfvars/main.tf b/v1.5.7/internal/command/testdata/push-tfvars/main.tf
new file mode 100644
index 0000000..2699d50
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/push-tfvars/main.tf
@@ -0,0 +1,22 @@
+variable "foo" {}
+
+variable "bar" {}
+
+variable "baz" {
+  type = "map"
+
+  default = {
+    "A"    = "a"
+  }
+}
+
+variable "fob" {
+  type    = "list"
+  default = ["a", "quotes \"in\" quotes"]
+}
+
+resource "test_instance" "foo" {}
+
+atlas {
+  name = "foo"
+}
diff --git a/v1.5.7/internal/command/testdata/push-tfvars/terraform.tfvars b/v1.5.7/internal/command/testdata/push-tfvars/terraform.tfvars
new file mode 100644
index 0000000..92292f0
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/push-tfvars/terraform.tfvars
@@ -0,0 +1,2 @@
+foo = "bar"
+bar = "foo"
diff --git a/v1.5.7/internal/command/testdata/push/main.tf b/v1.5.7/internal/command/testdata/push/main.tf
new file mode 100644
index 0000000..28f267c
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/push/main.tf
@@ -0,0 +1,5 @@
+resource "test_instance" "foo" {}
+
+atlas {
+    name = "foo"
+}
diff --git a/v1.5.7/internal/command/testdata/refresh-empty/main.tf b/v1.5.7/internal/command/testdata/refresh-empty/main.tf
new file mode 100644
index 0000000..fec5601
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/refresh-empty/main.tf
@@ -0,0 +1 @@
+# Hello
diff --git a/v1.5.7/internal/command/testdata/refresh-output/main.tf b/v1.5.7/internal/command/testdata/refresh-output/main.tf
new file mode 100644
index 0000000..d7efff6
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/refresh-output/main.tf
@@ -0,0 +1,7 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+}
+
+output "endpoint" {
+  value = "foo.example.com"
+}
diff --git a/v1.5.7/internal/command/testdata/refresh-targeted/main.tf b/v1.5.7/internal/command/testdata/refresh-targeted/main.tf
new file mode 100644
index 0000000..734f585
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/refresh-targeted/main.tf
@@ -0,0 +1,7 @@
+resource "test_instance" "foo" {
+  id = "foo"
+}
+
+resource "test_instance" "bar" {
+  id = "bar"
+}
diff --git a/v1.5.7/internal/command/testdata/refresh-unset-var/main.tf b/v1.5.7/internal/command/testdata/refresh-unset-var/main.tf
new file mode 100644
index 0000000..446cf70
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/refresh-unset-var/main.tf
@@ -0,0 +1,7 @@
+variable "should_ask" {}
+
+provider "test" {}
+
+resource "test_instance" "foo" {
+  ami = "${var.should_ask}"
+}
diff --git a/v1.5.7/internal/command/testdata/refresh-var/main.tf b/v1.5.7/internal/command/testdata/refresh-var/main.tf
new file mode 100644
index 0000000..af73b1c
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/refresh-var/main.tf
@@ -0,0 +1,7 @@
+variable "foo" {}
+
+provider "test" {
+    value = "${var.foo}"
+}
+
+resource "test_instance" "foo" {}
diff --git a/v1.5.7/internal/command/testdata/refresh/main.tf b/v1.5.7/internal/command/testdata/refresh/main.tf
new file mode 100644
index 0000000..1b10129
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/refresh/main.tf
@@ -0,0 +1,3 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+}
diff --git a/v1.5.7/internal/command/testdata/show-corrupt-statefile/terraform.tfstate b/v1.5.7/internal/command/testdata/show-corrupt-statefile/terraform.tfstate
new file mode 100644
index 0000000..9977a28
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-corrupt-statefile/terraform.tfstate
@@ -0,0 +1 @@
+invalid
diff --git a/v1.5.7/internal/command/testdata/show-json-sensitive/main.tf b/v1.5.7/internal/command/testdata/show-json-sensitive/main.tf
new file mode 100644
index 0000000..a980e4d
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json-sensitive/main.tf
@@ -0,0 +1,21 @@
+provider "test" {
+  region = "somewhere"
+}
+
+variable "test_var" {
+  default   = "bar"
+  sensitive = true
+}
+
+resource "test_instance" "test" {
+  // this variable is sensitive
+  ami = var.test_var
+  // the password attribute is sensitive in the showFixtureSensitiveProvider schema.
+  password = "secret"
+  count    = 3
+}
+
+output "test" {
+  value     = var.test_var
+  sensitive = true
+}
diff --git a/v1.5.7/internal/command/testdata/show-json-sensitive/output.json b/v1.5.7/internal/command/testdata/show-json-sensitive/output.json
new file mode 100644
index 0000000..156b12f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json-sensitive/output.json
@@ -0,0 +1,217 @@
+{
+    "format_version": "1.0",
+    "variables": {
+        "test_var": {
+            "value": "bar"
+        }
+    },
+    "planned_values": {
+        "outputs": {
+            "test": {
+                "sensitive": true,
+                "type": "string",
+                "value": "bar"
+            }
+        },
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.test[0]",
+                    "index": 0,
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar",
+                        "password": "secret"
+                    },
+                    "sensitive_values": {
+                        "ami": true
+                    }
+                },
+                {
+                    "address": "test_instance.test[1]",
+                    "index": 1,
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar",
+                        "password": "secret"
+                    },
+                    "sensitive_values": {
+                        "ami": true
+                    }
+                },
+                {
+                    "address": "test_instance.test[2]",
+                    "index": 2,
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar",
+                        "password": "secret"
+                    },
+                    "sensitive_values": {
+                        "ami": true
+                    }
+                }
+            ]
+        }
+    },
+    "prior_state": {
+        "format_version": "1.0",
+        "values": {
+            "outputs": {
+                "test": {
+                    "sensitive": true,
+                    "type": "string",
+                    "value": "bar"
+                }
+            },
+            "root_module": {}
+        }
+    },
+    "resource_changes": [
+        {
+            "address": "test_instance.test[0]",
+            "index": 0,
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after_unknown": {
+                    "id": true
+                },
+                "after": {
+                    "ami": "bar",
+                    "password": "secret"
+                },
+                "after_sensitive": {"ami": true, "password": true},
+                "before_sensitive": false
+            }
+        },
+        {
+            "address": "test_instance.test[1]",
+            "index": 1,
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after_unknown": {
+                    "id": true
+                },
+                "after": {
+                    "ami": "bar",
+                    "password": "secret"
+                },
+                "after_sensitive": {"ami": true, "password": true},
+                "before_sensitive": false
+            }
+        },
+        {
+            "address": "test_instance.test[2]",
+            "index": 2,
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after_unknown": {
+                    "id": true
+                },
+                "after": {
+                    "ami": "bar",
+                    "password": "secret"
+                },
+                "after_sensitive": {"ami": true, "password": true},
+                "before_sensitive": false
+            }
+        }
+    ],
+    "output_changes": {
+        "test": {
+            "actions": [
+                "create"
+            ],
+            "before": null,
+            "after": "bar",
+            "after_unknown": false,
+            "before_sensitive": true,
+            "after_sensitive": true
+        }
+    },
+    "configuration": {
+        "provider_config": {
+            "test": {
+                "name": "test",
+                "full_name": "registry.terraform.io/hashicorp/test",
+                "expressions": {
+                    "region": {
+                        "constant_value": "somewhere"
+                    }
+                }
+            }
+        },
+        "root_module": {
+            "outputs": {
+                "test": {
+                    "expression": {
+                        "references": [
+                            "var.test_var"
+                        ]
+                    },
+                    "sensitive": true
+                }
+            },
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_config_key": "test",
+                    "schema_version": 0,
+                    "expressions": {
+                        "ami": {
+                            "references": [
+                                "var.test_var"
+                            ]
+                        },
+                        "password": {"constant_value": "secret"}
+                    },
+                    "count_expression": {
+                        "constant_value": 3
+                    }
+                }
+            ],
+            "variables": {
+                "test_var": {
+                    "default": "bar",
+                    "sensitive": true
+                }
+            }
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json-state/basic/output.json b/v1.5.7/internal/command/testdata/show-json-state/basic/output.json
new file mode 100644
index 0000000..229fa00
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json-state/basic/output.json
@@ -0,0 +1,38 @@
+{
+    "format_version": "1.0",
+    "terraform_version": "0.12.0",
+    "values": {
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.example[0]",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "example",
+                    "index": 0,
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": null,
+                        "id": "621124146446964903"
+                    },
+                    "sensitive_values": {}
+                },
+                {
+                    "address": "test_instance.example[1]",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "example",
+                    "index": 1,
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": null,
+                        "id": "4330206298367988603"
+                    },
+                    "sensitive_values": {}
+                }
+            ]
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json-state/basic/terraform.tfstate b/v1.5.7/internal/command/testdata/show-json-state/basic/terraform.tfstate
new file mode 100644
index 0000000..046c196
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json-state/basic/terraform.tfstate
@@ -0,0 +1,34 @@
+{
+    "version": 4,
+    "terraform_version": "0.12.0",
+    "serial": 1,
+    "lineage": "00bfda35-ad61-ec8d-c013-14b0320bc416",
+    "outputs": {},
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "example",
+            "each": "list",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "index_key": 0,
+                    "schema_version": 0,
+                    "attributes": {
+                        "id": "621124146446964903"
+                    },
+                    "private": "bnVsbA=="
+                },
+                {
+                    "index_key": 1,
+                    "schema_version": 0,
+                    "attributes": {
+                        "id": "4330206298367988603"
+                    },
+                    "private": "bnVsbA=="
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/show-json-state/empty/output.json b/v1.5.7/internal/command/testdata/show-json-state/empty/output.json
new file mode 100644
index 0000000..381450c
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json-state/empty/output.json
@@ -0,0 +1,3 @@
+{
+    "format_version": "1.0"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json-state/empty/terraform.tfstate b/v1.5.7/internal/command/testdata/show-json-state/empty/terraform.tfstate
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json-state/empty/terraform.tfstate
diff --git a/v1.5.7/internal/command/testdata/show-json-state/modules/bar/main.tf b/v1.5.7/internal/command/testdata/show-json-state/modules/bar/main.tf
new file mode 100644
index 0000000..5d1788a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json-state/modules/bar/main.tf
@@ -0,0 +1,11 @@
+variable "test_var" {
+  default = "bar-var"
+}
+
+output "test" {
+  value = var.test_var
+}
+
+resource "test_instance" "test" {
+  ami = var.test_var
+}
diff --git a/v1.5.7/internal/command/testdata/show-json-state/modules/foo/main.tf b/v1.5.7/internal/command/testdata/show-json-state/modules/foo/main.tf
new file mode 100644
index 0000000..d1ae792
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json-state/modules/foo/main.tf
@@ -0,0 +1,14 @@
+variable "test_var" {
+  default = "foo-var"
+}
+
+resource "test_instance" "test" {
+  ami   = var.test_var
+  count = 1
+}
+
+output "test" {
+  value = var.test_var
+}
+
+provider "test" {}
diff --git a/v1.5.7/internal/command/testdata/show-json-state/modules/main.tf b/v1.5.7/internal/command/testdata/show-json-state/modules/main.tf
new file mode 100644
index 0000000..d1cabad
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json-state/modules/main.tf
@@ -0,0 +1,13 @@
+module "module_test_foo" {
+  source   = "./foo"
+  test_var = "baz"
+}
+
+module "module_test_bar" {
+  source = "./bar"
+}
+
+output "test" {
+  value      = module.module_test_foo.test
+  depends_on = [module.module_test_foo]
+}
diff --git a/v1.5.7/internal/command/testdata/show-json-state/modules/output.json b/v1.5.7/internal/command/testdata/show-json-state/modules/output.json
new file mode 100644
index 0000000..7dcea2f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json-state/modules/output.json
@@ -0,0 +1,54 @@
+{
+    "format_version": "1.0",
+    "terraform_version": "0.12.0",
+    "values": {
+        "outputs": {
+            "test": {
+                "sensitive": false,
+                "type": "string",
+                "value": "baz"
+            }
+        },
+        "root_module": {
+            "child_modules": [
+                {
+                    "resources": [
+                        {
+                            "address": "module.module_test_bar.test_instance.example",
+                            "mode": "managed",
+                            "type": "test_instance",
+                            "name": "example",
+                            "provider_name": "registry.terraform.io/hashicorp/test",
+                            "schema_version": 0,
+                            "values": {
+                                "ami": "bar-var",
+                                "id": null
+                            },
+                            "sensitive_values": {}
+                        }
+                    ],
+                    "address": "module.module_test_bar"
+                },
+                {
+                    "resources": [
+                        {
+                            "address": "module.module_test_foo.test_instance.example[0]",
+                            "mode": "managed",
+                            "type": "test_instance",
+                            "name": "example",
+                            "index": 0,
+                            "provider_name": "registry.terraform.io/hashicorp/test",
+                            "schema_version": 0,
+                            "values": {
+                                "ami": "foo-var",
+                                "id": null
+                            },
+                            "sensitive_values": {}
+                        }
+                    ],
+                    "address": "module.module_test_foo"
+                }
+            ]
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json-state/modules/terraform.tfstate b/v1.5.7/internal/command/testdata/show-json-state/modules/terraform.tfstate
new file mode 100644
index 0000000..88f52a6
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json-state/modules/terraform.tfstate
@@ -0,0 +1,48 @@
+{
+    "version": 4,
+    "terraform_version": "0.12.0",
+    "serial": 8,
+    "lineage": "00bfda35-ad61-ec8d-c013-14b0320bc416",
+    "outputs": {
+        "test": {
+            "value": "baz",
+            "type": "string"
+        }
+    },
+    "resources": [
+        {
+            "module": "module.module_test_foo",
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "example",
+            "each": "list",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "index_key": 0,
+                    "schema_version": 0,
+                    "attributes": {
+                        "ami": "foo-var"
+                    },
+                    "private": "bnVsbA=="
+                }
+            ]
+        },
+        {
+            "module": "module.module_test_bar",
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "example",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes": {
+                        "ami": "bar-var"
+                    },
+                    "private": "bnVsbA=="
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/show-json-state/no-state/output.json b/v1.5.7/internal/command/testdata/show-json-state/no-state/output.json
new file mode 100644
index 0000000..381450c
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json-state/no-state/output.json
@@ -0,0 +1,3 @@
+{
+    "format_version": "1.0"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json-state/sensitive-variables/output.json b/v1.5.7/internal/command/testdata/show-json-state/sensitive-variables/output.json
new file mode 100644
index 0000000..60503cd
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json-state/sensitive-variables/output.json
@@ -0,0 +1,25 @@
+{
+    "format_version": "1.0",
+    "terraform_version": "0.14.0",
+    "values": {
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "id": "621124146446964903",
+                        "ami": "abc"
+                    },
+                    "sensitive_values": {
+                        "ami": true
+                    }
+                }
+            ]
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json-state/sensitive-variables/terraform.tfstate b/v1.5.7/internal/command/testdata/show-json-state/sensitive-variables/terraform.tfstate
new file mode 100644
index 0000000..5571245
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json-state/sensitive-variables/terraform.tfstate
@@ -0,0 +1,33 @@
+{
+  "version": 4,
+  "terraform_version": "0.14.0",
+  "serial": 1,
+  "lineage": "d7a6880b-6875-288f-13a9-696a65c73036",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test",
+      "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "621124146446964903",
+            "ami": "abc"
+          },
+          "sensitive_attributes": [
+            [
+              {
+                "type": "get_attr",
+                "value": "ami"
+              }
+            ]
+          ],
+          "private": "bnVsbA=="
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/basic-create/main.tf b/v1.5.7/internal/command/testdata/show-json/basic-create/main.tf
new file mode 100644
index 0000000..2f41f53
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/basic-create/main.tf
@@ -0,0 +1,16 @@
+provider "test" {
+  region = "somewhere"
+}
+
+variable "test_var" {
+  default = "bar"
+}
+
+resource "test_instance" "test" {
+  ami   = var.test_var
+  count = 3
+}
+
+output "test" {
+  value = var.test_var
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/basic-create/output.json b/v1.5.7/internal/command/testdata/show-json/basic-create/output.json
new file mode 100644
index 0000000..ed348c3
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/basic-create/output.json
@@ -0,0 +1,202 @@
+{
+    "format_version": "1.0",
+    "variables": {
+        "test_var": {
+            "value": "bar"
+        }
+    },
+    "planned_values": {
+        "outputs": {
+            "test": {
+                "sensitive": false,
+                "type": "string",
+                "value": "bar"
+            }
+        },
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.test[0]",
+                    "index": 0,
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar"
+                    },
+                    "sensitive_values": {}
+                },
+                {
+                    "address": "test_instance.test[1]",
+                    "index": 1,
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar"
+                    },
+                    "sensitive_values": {}
+                },
+                {
+                    "address": "test_instance.test[2]",
+                    "index": 2,
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar"
+                    },
+                    "sensitive_values": {}
+                }
+            ]
+        }
+    },
+    "prior_state": {
+        "format_version": "1.0",
+        "values": {
+            "outputs": {
+                "test": {
+                    "sensitive": false,
+                    "type": "string",
+                    "value": "bar"
+                }
+            },
+            "root_module": {}
+        }
+    },
+    "resource_changes": [
+        {
+            "address": "test_instance.test[0]",
+            "index": 0,
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after_unknown": {
+                    "id": true
+                },
+                "after": {
+                    "ami": "bar"
+                },
+                "after_sensitive": {},
+                "before_sensitive": false
+            }
+        },
+        {
+            "address": "test_instance.test[1]",
+            "index": 1,
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after_unknown": {
+                    "id": true
+                },
+                "after": {
+                    "ami": "bar"
+                },
+                "after_sensitive": {},
+                "before_sensitive": false
+            }
+        },
+        {
+            "address": "test_instance.test[2]",
+            "index": 2,
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after_unknown": {
+                    "id": true
+                },
+                "after": {
+                    "ami": "bar"
+                },
+                "after_sensitive": {},
+                "before_sensitive": false
+            }
+        }
+    ],
+    "output_changes": {
+        "test": {
+            "actions": [
+                "create"
+            ],
+            "before": null,
+            "after": "bar",
+            "after_unknown": false,
+            "before_sensitive": false,
+            "after_sensitive": false
+        }
+    },
+    "configuration": {
+        "provider_config": {
+            "test": {
+                "name": "test",
+                "full_name": "registry.terraform.io/hashicorp/test",
+                "expressions": {
+                    "region": {
+                        "constant_value": "somewhere"
+                    }
+                }
+            }
+        },
+        "root_module": {
+            "outputs": {
+                "test": {
+                    "expression": {
+                        "references": [
+                            "var.test_var"
+                        ]
+                    }
+                }
+            },
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_config_key": "test",
+                    "schema_version": 0,
+                    "expressions": {
+                        "ami": {
+                            "references": [
+                                "var.test_var"
+                            ]
+                        }
+                    },
+                    "count_expression": {
+                        "constant_value": 3
+                    }
+                }
+            ],
+            "variables": {
+                "test_var": {
+                    "default": "bar"
+                }
+            }
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/basic-delete/main.tf b/v1.5.7/internal/command/testdata/show-json/basic-delete/main.tf
new file mode 100644
index 0000000..52fea37
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/basic-delete/main.tf
@@ -0,0 +1,10 @@
+variable "test_var" {
+    default = "bar"
+}
+resource "test_instance" "test" {
+    ami = var.test_var
+}
+
+output "test" {
+    value = var.test_var
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/command/testdata/show-json/basic-delete/output.json b/v1.5.7/internal/command/testdata/show-json/basic-delete/output.json
new file mode 100644
index 0000000..e24ff07
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/basic-delete/output.json
@@ -0,0 +1,175 @@
+{
+    "format_version": "1.0",
+    "variables": {
+        "test_var": {
+            "value": "bar"
+        }
+    },
+    "planned_values": {
+        "outputs": {
+            "test": {
+                "sensitive": false,
+                "type": "string",
+                "value": "bar"
+            }
+        },
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar",
+                        "id": "placeholder"
+                    },
+                    "sensitive_values": {}
+                }
+            ]
+        }
+    },
+    "resource_changes": [
+        {
+            "address": "test_instance.test",
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "update"
+                ],
+                "before": {
+                    "ami": "foo",
+                    "id": "placeholder"
+                },
+                "after": {
+                    "ami": "bar",
+                    "id": "placeholder"
+                },
+                "after_unknown": {},
+                "after_sensitive": {},
+                "before_sensitive": {}
+            }
+        },
+        {
+            "address": "test_instance.test-delete",
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test-delete",
+            "action_reason": "delete_because_no_resource_config",
+            "change": {
+                "actions": [
+                    "delete"
+                ],
+                "before": {
+                    "ami": "foo",
+                    "id": "placeholder"
+                },
+                "after": null,
+                "after_unknown": {},
+                "after_sensitive": false,
+                "before_sensitive": {}
+            }
+        }
+    ],
+    "output_changes": {
+        "test": {
+            "actions": [
+                "create"
+            ],
+            "before": null,
+            "after": "bar",
+            "after_unknown": false,
+            "before_sensitive": false,
+            "after_sensitive": false
+        }
+    },
+    "prior_state": {
+        "format_version": "1.0",
+        "values": {
+            "outputs": {
+                "test": {
+                    "sensitive": false,
+                    "type": "string",
+                    "value": "bar"
+                }
+            },
+            "root_module": {
+                "resources": [
+                    {
+                        "address": "test_instance.test",
+                        "schema_version": 0,
+                        "mode": "managed",
+                        "type": "test_instance",
+                        "name": "test",
+                        "provider_name": "registry.terraform.io/hashicorp/test",
+                        "values": {
+                            "ami": "foo",
+                            "id": "placeholder"
+                        },
+                        "sensitive_values": {}
+                    },
+                    {
+                        "address": "test_instance.test-delete",
+                        "schema_version": 0,
+                        "mode": "managed",
+                        "type": "test_instance",
+                        "name": "test-delete",
+                        "provider_name": "registry.terraform.io/hashicorp/test",
+                        "values": {
+                            "ami": "foo",
+                            "id": "placeholder"
+                        },
+                        "sensitive_values": {}
+                    }
+                ]
+            }
+        }
+    },
+    "configuration": {
+        "provider_config": {
+            "test": {
+                "name": "test",
+                "full_name": "registry.terraform.io/hashicorp/test"
+            }
+        },
+        "root_module": {
+            "outputs": {
+                "test": {
+                    "expression": {
+                        "references": [
+                            "var.test_var"
+                        ]
+                    }
+                }
+            },
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_config_key": "test",
+                    "schema_version": 0,
+                    "expressions": {
+                        "ami": {
+                            "references": [
+                                "var.test_var"
+                            ]
+                        }
+                    }
+                }
+            ],
+            "variables": {
+                "test_var": {
+                    "default": "bar"
+                }
+            }
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/basic-delete/terraform.tfstate b/v1.5.7/internal/command/testdata/show-json/basic-delete/terraform.tfstate
new file mode 100644
index 0000000..ac865b8
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/basic-delete/terraform.tfstate
@@ -0,0 +1,39 @@
+{
+  "version": 4,
+  "terraform_version": "0.12.0",
+  "serial": 7,
+  "lineage": "configuredUnchanged",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test",
+      "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "ami": "foo",
+            "id": "placeholder"
+          }
+        }
+      ]
+    },
+    {
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test-delete",
+      "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "ami": "foo",
+            "id": "placeholder"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/basic-update/main.tf b/v1.5.7/internal/command/testdata/show-json/basic-update/main.tf
new file mode 100644
index 0000000..52fea37
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/basic-update/main.tf
@@ -0,0 +1,10 @@
+variable "test_var" {
+    default = "bar"
+}
+resource "test_instance" "test" {
+    ami = var.test_var
+}
+
+output "test" {
+    value = var.test_var
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/command/testdata/show-json/basic-update/output.json b/v1.5.7/internal/command/testdata/show-json/basic-update/output.json
new file mode 100644
index 0000000..05927e4
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/basic-update/output.json
@@ -0,0 +1,141 @@
+{
+    "format_version": "1.0",
+    "variables": {
+        "test_var": {
+            "value": "bar"
+        }
+    },
+    "planned_values": {
+        "outputs": {
+            "test": {
+                "sensitive": false,
+                "type": "string",
+                "value": "bar"
+            }
+        },
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar",
+                        "id": "placeholder"
+                    },
+                    "sensitive_values": {}
+                }
+            ]
+        }
+    },
+    "resource_changes": [
+        {
+            "address": "test_instance.test",
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "no-op"
+                ],
+                "before": {
+                    "ami": "bar",
+                    "id": "placeholder"
+                },
+                "after": {
+                    "ami": "bar",
+                    "id": "placeholder"
+                },
+                "after_unknown": {},
+                "after_sensitive": {},
+                "before_sensitive": {}
+            }
+        }
+    ],
+    "output_changes": {
+        "test": {
+            "actions": [
+                "no-op"
+            ],
+            "before": "bar",
+            "after": "bar",
+            "after_unknown": false,
+            "before_sensitive": false,
+            "after_sensitive": false
+        }
+    },
+    "prior_state": {
+        "format_version": "1.0",
+        "values": {
+            "outputs": {
+                "test": {
+                    "sensitive": false,
+                    "type": "string",
+                    "value": "bar"
+                }
+            },
+            "root_module": {
+                "resources": [
+                    {
+                        "address": "test_instance.test",
+                        "mode": "managed",
+                        "type": "test_instance",
+                        "name": "test",
+                        "schema_version": 0,
+                        "provider_name": "registry.terraform.io/hashicorp/test",
+                        "values": {
+                            "ami": "bar",
+                            "id": "placeholder"
+                        },
+                        "sensitive_values": {}
+                    }
+                ]
+            }
+        }
+    },
+    "configuration": {
+        "provider_config": {
+            "test": {
+                "name": "test",
+                "full_name": "registry.terraform.io/hashicorp/test"
+            }
+        },
+        "root_module": {
+            "outputs": {
+                "test": {
+                    "expression": {
+                        "references": [
+                            "var.test_var"
+                        ]
+                    }
+                }
+            },
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_config_key": "test",
+                    "schema_version": 0,
+                    "expressions": {
+                        "ami": {
+                            "references": [
+                                "var.test_var"
+                            ]
+                        }
+                    }
+                }
+            ],
+            "variables": {
+                "test_var": {
+                    "default": "bar"
+                }
+            }
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/basic-update/terraform.tfstate b/v1.5.7/internal/command/testdata/show-json/basic-update/terraform.tfstate
new file mode 100644
index 0000000..bc691ae
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/basic-update/terraform.tfstate
@@ -0,0 +1,29 @@
+{
+    "version": 4,
+    "terraform_version": "0.12.0",
+    "serial": 7,
+    "lineage": "configuredUnchanged",
+    "outputs": {
+        "test": {
+            "value": "bar",
+            "type": "string"
+        }
+    },
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "test",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes": {
+                        "ami": "bar",
+                        "id": "placeholder"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/conditions/for-refresh.tfstate b/v1.5.7/internal/command/testdata/show-json/conditions/for-refresh.tfstate
new file mode 100644
index 0000000..1b0b101
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/conditions/for-refresh.tfstate
@@ -0,0 +1,39 @@
+{
+    "version": 4,
+    "terraform_version": "1.2.0-dev",
+    "serial": 1,
+    "lineage": "no",
+    "outputs": {},
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "foo",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes": {
+                        "ami": "ami-test",
+                        "id": "placeholder"
+                    }
+                }
+            ]
+        },
+        {
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "bar",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes": {
+                        "ami": "ami-test",
+                        "id": "placeheld"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/conditions/main.tf b/v1.5.7/internal/command/testdata/show-json/conditions/main.tf
new file mode 100644
index 0000000..f63dca9
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/conditions/main.tf
@@ -0,0 +1,40 @@
+variable "ami" {
+  type    = string
+  default = "ami-test"
+}
+
+variable "id_minimum_length" {
+  type    = number
+  default = 10
+}
+
+resource "test_instance" "foo" {
+  ami = var.ami
+
+  lifecycle {
+    precondition {
+      condition     = can(regex("^ami-", var.ami))
+      error_message = "Invalid AMI ID: must start with \"ami-\"."
+    }
+  }
+}
+
+resource "test_instance" "bar" {
+  ami = "ami-boop"
+
+  lifecycle {
+    postcondition {
+      condition     = length(self.id) >= var.id_minimum_length
+      error_message = "Resource ID is unacceptably short (${length(self.id)} characters)."
+    }
+  }
+}
+
+output "foo_id" {
+  value = test_instance.foo.id
+
+  precondition {
+    condition     = test_instance.foo.ami != "ami-bad"
+    error_message = "Foo has a bad AMI again!"
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/conditions/output-refresh-only.json b/v1.5.7/internal/command/testdata/show-json/conditions/output-refresh-only.json
new file mode 100644
index 0000000..7b1845f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/conditions/output-refresh-only.json
@@ -0,0 +1,171 @@
+{
+  "format_version": "1.1",
+  "terraform_version": "1.2.0-dev",
+  "variables": {
+    "ami": {
+      "value": "bad-ami"
+    },
+    "id_minimum_length": {
+      "value": 10
+    }
+  },
+  "planned_values": {
+    "outputs": {
+      "foo_id": {
+        "sensitive": false,
+        "type": "string",
+        "value": "placeholder"
+      }
+    },
+    "root_module": {}
+  },
+  "output_changes": {
+    "foo_id": {
+      "actions": [
+        "create"
+      ],
+      "before": null,
+      "after": "placeholder",
+      "after_unknown": false,
+      "before_sensitive": false,
+      "after_sensitive": false
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "terraform_version": "1.1.0",
+    "values": {
+      "outputs": {
+        "foo_id": {
+          "sensitive": false,
+          "type": "string",
+          "value": "placeholder"
+        }
+      },
+      "root_module": {
+        "resources": [
+          {
+            "address": "test_instance.bar",
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "bar",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "schema_version": 0,
+            "values": {
+              "ami": "ami-test",
+              "id": "placeheld",
+              "password": null
+            },
+            "sensitive_values": {
+              "password": true
+            }
+          },
+          {
+            "address": "test_instance.foo",
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "foo",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "schema_version": 0,
+            "values": {
+              "ami": "ami-test",
+              "id": "placeholder",
+              "password": null
+            },
+            "sensitive_values": {
+              "password": true
+            }
+          }
+        ]
+      }
+    }
+  },
+  "configuration": {
+    "provider_config": {
+      "test": {
+        "name": "test",
+        "full_name": "registry.terraform.io/hashicorp/test"
+      }
+    },
+    "root_module": {
+      "outputs": {
+        "foo_id": {
+          "expression": {
+            "references": [
+              "test_instance.foo.id",
+              "test_instance.foo"
+            ]
+          }
+        }
+      },
+      "resources": [
+        {
+          "address": "test_instance.bar",
+          "mode": "managed",
+          "type": "test_instance",
+          "name": "bar",
+          "provider_config_key": "test",
+          "expressions": {
+            "ami": {
+              "constant_value": "ami-boop"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "test_instance.foo",
+          "mode": "managed",
+          "type": "test_instance",
+          "name": "foo",
+          "provider_config_key": "test",
+          "expressions": {
+            "ami": {
+              "references": [
+                "var.ami"
+              ]
+            }
+          },
+          "schema_version": 0
+        }
+      ],
+      "variables": {
+        "ami": {
+          "default": "ami-test"
+        },
+        "id_minimum_length": {
+          "default": 10
+        }
+      }
+    }
+  },
+  "relevant_attributes": [
+    {
+      "resource": "test_instance.foo",
+      "attribute": [
+        "id"
+      ]
+    }
+  ],
+  "condition_results": [
+    {
+      "address": "output.foo_id",
+      "condition_type": "OutputPrecondition",
+      "result": true,
+      "unknown": false
+    },
+    {
+      "address": "test_instance.bar",
+      "condition_type": "ResourcePostcondition",
+      "result": false,
+      "unknown": false,
+      "error_message": "Resource ID is unacceptably short (9 characters)."
+    },
+    {
+      "address": "test_instance.foo",
+      "condition_type": "ResourcePrecondition",
+      "result": false,
+      "unknown": false,
+      "error_message": "Invalid AMI ID: must start with \"ami-\"."
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/conditions/output.json b/v1.5.7/internal/command/testdata/show-json/conditions/output.json
new file mode 100644
index 0000000..1d13887
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/conditions/output.json
@@ -0,0 +1,188 @@
+{
+  "format_version": "1.1",
+  "terraform_version": "1.2.0-dev",
+  "variables": {
+    "ami": {
+      "value": "ami-test"
+    },
+    "id_minimum_length": {
+      "value": 10
+    }
+  },
+  "planned_values": {
+    "outputs": {
+      "foo_id": {
+        "sensitive": false
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "test_instance.bar",
+          "mode": "managed",
+          "type": "test_instance",
+          "name": "bar",
+          "provider_name": "registry.terraform.io/hashicorp/test",
+          "schema_version": 0,
+          "values": {
+            "ami": "ami-boop"
+          },
+          "sensitive_values": {}
+        },
+        {
+          "address": "test_instance.foo",
+          "mode": "managed",
+          "type": "test_instance",
+          "name": "foo",
+          "provider_name": "registry.terraform.io/hashicorp/test",
+          "schema_version": 0,
+          "values": {
+            "ami": "ami-test"
+          },
+          "sensitive_values": {}
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "test_instance.bar",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "bar",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "ami-boop"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "test_instance.foo",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "foo",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "ami-test"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    }
+  ],
+  "output_changes": {
+    "foo_id": {
+      "actions": [
+        "create"
+      ],
+      "before": null,
+      "after_unknown": true,
+      "before_sensitive": false,
+      "after_sensitive": false
+    }
+  },
+  "configuration": {
+    "provider_config": {
+      "test": {
+        "name": "test",
+        "full_name": "registry.terraform.io/hashicorp/test"
+      }
+    },
+    "root_module": {
+      "outputs": {
+        "foo_id": {
+          "expression": {
+            "references": [
+              "test_instance.foo.id",
+              "test_instance.foo"
+            ]
+          }
+        }
+      },
+      "resources": [
+        {
+          "address": "test_instance.bar",
+          "mode": "managed",
+          "type": "test_instance",
+          "name": "bar",
+          "provider_config_key": "test",
+          "expressions": {
+            "ami": {
+              "constant_value": "ami-boop"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "test_instance.foo",
+          "mode": "managed",
+          "type": "test_instance",
+          "name": "foo",
+          "provider_config_key": "test",
+          "expressions": {
+            "ami": {
+              "references": [
+                "var.ami"
+              ]
+            }
+          },
+          "schema_version": 0
+        }
+      ],
+      "variables": {
+        "ami": {
+          "default": "ami-test"
+        },
+        "id_minimum_length": {
+          "default": 10
+        }
+      }
+    }
+  },
+  "relevant_attributes": [
+    {
+      "resource": "test_instance.foo",
+      "attribute": [
+        "id"
+      ]
+    }
+  ],
+  "condition_results": [
+    {
+      "address": "output.foo_id",
+      "condition_type": "OutputPrecondition",
+      "result": true,
+      "unknown": false
+    },
+    {
+      "address": "test_instance.bar",
+      "condition_type": "ResourcePostcondition",
+      "result": false,
+      "unknown": true
+    },
+    {
+      "address": "test_instance.foo",
+      "condition_type": "ResourcePrecondition",
+      "result": true,
+      "unknown": false
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/drift/main.tf b/v1.5.7/internal/command/testdata/show-json/drift/main.tf
new file mode 100644
index 0000000..18995de
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/drift/main.tf
@@ -0,0 +1,13 @@
+# In state with `ami = "foo"`, so this should be a regular update. The provider
+# should not detect changes on refresh.
+resource "test_instance" "no_refresh" {
+  ami = "bar"
+}
+
+# In state with `ami = "refresh-me"`, but the provider will return
+# `"refreshed"` after the refresh phase. The plan should show the drift
+# (`"refresh-me"` to `"refreshed"`) and plan the update (`"refreshed"` to
+# `"baz"`).
+resource "test_instance" "should_refresh" {
+  ami = "baz"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/drift/output.json b/v1.5.7/internal/command/testdata/show-json/drift/output.json
new file mode 100644
index 0000000..08029bf
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/drift/output.json
@@ -0,0 +1,181 @@
+{
+    "format_version": "1.0",
+    "planned_values": {
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.no_refresh",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "no_refresh",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar",
+                        "id": "placeholder"
+                    },
+                    "sensitive_values": {}
+                },
+                {
+                    "address": "test_instance.should_refresh",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "should_refresh",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "baz",
+                        "id": "placeholder"
+                    },
+                    "sensitive_values": {}
+                }
+            ]
+        }
+    },
+    "resource_drift": [
+        {
+            "address": "test_instance.should_refresh",
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "should_refresh",
+            "change": {
+                "actions": [
+                    "update"
+                ],
+                "before": {
+                    "ami": "refresh-me",
+                    "id": "placeholder"
+                },
+                "after": {
+                    "ami": "refreshed",
+                    "id": "placeholder"
+                },
+                "after_sensitive": {},
+                "after_unknown": {},
+                "before_sensitive": {}
+            }
+        }
+    ],
+    "resource_changes": [
+        {
+            "address": "test_instance.no_refresh",
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "no_refresh",
+            "change": {
+                "actions": [
+                    "update"
+                ],
+                "before": {
+                    "ami": "foo",
+                    "id": "placeholder"
+                },
+                "after": {
+                    "ami": "bar",
+                    "id": "placeholder"
+                },
+                "after_unknown": {},
+                "after_sensitive": {},
+                "before_sensitive": {}
+            }
+        },
+        {
+            "address": "test_instance.should_refresh",
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "should_refresh",
+            "change": {
+                "actions": [
+                    "update"
+                ],
+                "before": {
+                    "ami": "refreshed",
+                    "id": "placeholder"
+                },
+                "after": {
+                    "ami": "baz",
+                    "id": "placeholder"
+                },
+                "after_unknown": {},
+                "after_sensitive": {},
+                "before_sensitive": {}
+            }
+        }
+    ],
+    "prior_state": {
+        "format_version": "1.0",
+        "values": {
+            "root_module": {
+                "resources": [
+                    {
+                        "address": "test_instance.no_refresh",
+                        "mode": "managed",
+                        "type": "test_instance",
+                        "name": "no_refresh",
+                        "schema_version": 0,
+                        "provider_name": "registry.terraform.io/hashicorp/test",
+                        "values": {
+                            "ami": "foo",
+                            "id": "placeholder"
+                        },
+                        "sensitive_values": {}
+                    },
+                    {
+                        "address": "test_instance.should_refresh",
+                        "mode": "managed",
+                        "type": "test_instance",
+                        "name": "should_refresh",
+                        "schema_version": 0,
+                        "provider_name": "registry.terraform.io/hashicorp/test",
+                        "values": {
+                            "ami": "refreshed",
+                            "id": "placeholder"
+                        },
+                        "sensitive_values": {}
+                    }
+                ]
+            }
+        }
+    },
+    "configuration": {
+        "provider_config": {
+            "test": {
+                "name": "test",
+                "full_name": "registry.terraform.io/hashicorp/test"
+            }
+        },
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.no_refresh",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "no_refresh",
+                    "provider_config_key": "test",
+                    "schema_version": 0,
+                    "expressions": {
+                        "ami": {
+                            "constant_value": "bar"
+                        }
+                    }
+                },
+                {
+                    "address": "test_instance.should_refresh",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "should_refresh",
+                    "provider_config_key": "test",
+                    "schema_version": 0,
+                    "expressions": {
+                        "ami": {
+                            "constant_value": "baz"
+                        }
+                    }
+                }
+            ]
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/drift/terraform.tfstate b/v1.5.7/internal/command/testdata/show-json/drift/terraform.tfstate
new file mode 100644
index 0000000..02b8944
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/drift/terraform.tfstate
@@ -0,0 +1,38 @@
+{
+    "version": 4,
+    "terraform_version": "0.12.0",
+    "serial": 7,
+    "lineage": "configuredUnchanged",
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "no_refresh",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes": {
+                        "ami": "foo",
+                        "id": "placeholder"
+                    }
+                }
+            ]
+        },
+        {
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "should_refresh",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes": {
+                        "ami": "refresh-me",
+                        "id": "placeholder"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/module-depends-on/foo/main.tf b/v1.5.7/internal/command/testdata/show-json/module-depends-on/foo/main.tf
new file mode 100644
index 0000000..50e1c12
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/module-depends-on/foo/main.tf
@@ -0,0 +1,3 @@
+variable "test_var" {
+  default = "foo-var"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/module-depends-on/main.tf b/v1.5.7/internal/command/testdata/show-json/module-depends-on/main.tf
new file mode 100644
index 0000000..f718514
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/module-depends-on/main.tf
@@ -0,0 +1,11 @@
+module "foo" {
+    source = "./foo"
+
+    depends_on = [
+        test_instance.test
+    ]
+}
+
+resource "test_instance" "test" {
+    ami   = "foo-bar"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/module-depends-on/output.json b/v1.5.7/internal/command/testdata/show-json/module-depends-on/output.json
new file mode 100644
index 0000000..c76c762
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/module-depends-on/output.json
@@ -0,0 +1,85 @@
+{
+    "format_version": "1.0",
+    "terraform_version": "0.13.1-dev",
+    "planned_values": {
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "foo-bar"
+                    },
+                    "sensitive_values": {}
+                }
+            ]
+        }
+    },
+    "resource_changes": [
+        {
+            "address": "test_instance.test",
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "test",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after": {
+                    "ami": "foo-bar"
+                },
+                "after_unknown": {
+                    "id": true
+                },
+                "after_sensitive": {},
+                "before_sensitive": false
+            }
+        }
+    ],
+    "configuration": {
+        "provider_config": {
+            "test": {
+                "name": "test",
+                "full_name": "registry.terraform.io/hashicorp/test"
+            }
+        },
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_config_key": "test",
+                    "expressions": {
+                        "ami": {
+                            "constant_value": "foo-bar"
+                        }
+                    },
+                    "schema_version": 0
+                }
+            ],
+            "module_calls": {
+                "foo": {
+                    "depends_on": [
+                        "test_instance.test"
+                    ],
+                    "source": "./foo",
+                    "module": {
+                        "variables": {
+                            "test_var": {
+                                "default": "foo-var"
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/modules/bar/main.tf b/v1.5.7/internal/command/testdata/show-json/modules/bar/main.tf
new file mode 100644
index 0000000..5d1788a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/modules/bar/main.tf
@@ -0,0 +1,11 @@
+variable "test_var" {
+  default = "bar-var"
+}
+
+output "test" {
+  value = var.test_var
+}
+
+resource "test_instance" "test" {
+  ami = var.test_var
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/modules/foo/main.tf b/v1.5.7/internal/command/testdata/show-json/modules/foo/main.tf
new file mode 100644
index 0000000..2694ca8
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/modules/foo/main.tf
@@ -0,0 +1,13 @@
+variable "test_var" {
+  default = "foo-var"
+}
+resource "test_instance" "test" {
+  ami   = var.test_var
+  count = 3
+}
+
+output "test" {
+  value = var.test_var
+}
+
+provider "test" {}
diff --git a/v1.5.7/internal/command/testdata/show-json/modules/main.tf b/v1.5.7/internal/command/testdata/show-json/modules/main.tf
new file mode 100644
index 0000000..d1cabad
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/modules/main.tf
@@ -0,0 +1,13 @@
+module "module_test_foo" {
+  source   = "./foo"
+  test_var = "baz"
+}
+
+module "module_test_bar" {
+  source = "./bar"
+}
+
+output "test" {
+  value      = module.module_test_foo.test
+  depends_on = [module.module_test_foo]
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/modules/output.json b/v1.5.7/internal/command/testdata/show-json/modules/output.json
new file mode 100644
index 0000000..ceb9c1c
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/modules/output.json
@@ -0,0 +1,306 @@
+{
+    "format_version": "1.0",
+    "planned_values": {
+        "outputs": {
+            "test": {
+                "sensitive": false,
+                "type": "string",
+                "value": "baz"
+            }
+        },
+        "root_module": {
+            "child_modules": [
+                {
+                    "resources": [
+                        {
+                            "address": "module.module_test_bar.test_instance.test",
+                            "mode": "managed",
+                            "type": "test_instance",
+                            "name": "test",
+                            "provider_name": "registry.terraform.io/hashicorp/test",
+                            "schema_version": 0,
+                            "values": {
+                                "ami": "bar-var"
+                            },
+                            "sensitive_values": {}
+                        }
+                    ],
+                    "address": "module.module_test_bar"
+                },
+                {
+                    "resources": [
+                        {
+                            "address": "module.module_test_foo.test_instance.test[0]",
+                            "mode": "managed",
+                            "type": "test_instance",
+                            "name": "test",
+                            "index": 0,
+                            "provider_name": "registry.terraform.io/hashicorp/test",
+                            "schema_version": 0,
+                            "values": {
+                                "ami": "baz"
+                            },
+                            "sensitive_values": {}
+                        },
+                        {
+                            "address": "module.module_test_foo.test_instance.test[1]",
+                            "mode": "managed",
+                            "type": "test_instance",
+                            "name": "test",
+                            "index": 1,
+                            "provider_name": "registry.terraform.io/hashicorp/test",
+                            "schema_version": 0,
+                            "values": {
+                                "ami": "baz"
+                            },
+                            "sensitive_values": {}
+                        },
+                        {
+                            "address": "module.module_test_foo.test_instance.test[2]",
+                            "mode": "managed",
+                            "type": "test_instance",
+                            "name": "test",
+                            "index": 2,
+                            "provider_name": "registry.terraform.io/hashicorp/test",
+                            "schema_version": 0,
+                            "values": {
+                                "ami": "baz"
+                            },
+                            "sensitive_values": {}
+                        }
+                    ],
+                    "address": "module.module_test_foo"
+                }
+            ]
+        }
+    },
+    "prior_state": {
+        "format_version": "1.0",
+        "values": {
+            "outputs": {
+                "test": {
+                    "sensitive": false,
+                    "type": "string",
+                    "value": "baz"
+                }
+            },
+            "root_module": {}
+        }
+    },
+    "resource_changes": [
+        {
+            "address": "module.module_test_bar.test_instance.test",
+            "module_address": "module.module_test_bar",
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "test",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after": {
+                    "ami": "bar-var"
+                },
+                "after_unknown": {
+                    "id": true
+                },
+                "after_sensitive": {},
+                "before_sensitive": false
+            }
+        },
+        {
+            "address": "module.module_test_foo.test_instance.test[0]",
+            "module_address": "module.module_test_foo",
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "index": 0,
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after": {
+                    "ami": "baz"
+                },
+                "after_unknown": {
+                    "id": true
+                },
+                "after_sensitive": {},
+                "before_sensitive": false
+            }
+        },
+        {
+            "address": "module.module_test_foo.test_instance.test[1]",
+            "module_address": "module.module_test_foo",
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "index": 1,
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after": {
+                    "ami": "baz"
+                },
+                "after_unknown": {
+                    "id": true
+                },
+                "after_sensitive": {},
+                "before_sensitive": false
+            }
+        },
+        {
+            "address": "module.module_test_foo.test_instance.test[2]",
+            "module_address": "module.module_test_foo",
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "index": 2,
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after": {
+                    "ami": "baz"
+                },
+                "after_unknown": {
+                    "id": true
+                },
+                "after_sensitive": {},
+                "before_sensitive": false
+            }
+        }
+    ],
+    "output_changes": {
+        "test": {
+            "actions": [
+                "create"
+            ],
+            "before": null,
+            "after": "baz",
+            "after_unknown": false,
+            "before_sensitive": false,
+            "after_sensitive": false
+        }
+    },
+    "configuration": {
+        "root_module": {
+            "outputs": {
+                "test": {
+                    "expression": {
+                        "references": [
+                            "module.module_test_foo.test",
+                            "module.module_test_foo"
+                        ]
+                    },
+                    "depends_on": [
+                        "module.module_test_foo"
+                    ]
+                }
+            },
+            "module_calls": {
+                "module_test_bar": {
+                    "source": "./bar",
+                    "module": {
+                        "outputs": {
+                            "test": {
+                                "expression": {
+                                    "references": [
+                                        "var.test_var"
+                                    ]
+                                }
+                            }
+                        },
+                        "resources": [
+                            {
+                                "address": "test_instance.test",
+                                "mode": "managed",
+                                "type": "test_instance",
+                                "name": "test",
+                                "provider_config_key": "module.module_test_bar:test",
+                                "expressions": {
+                                    "ami": {
+                                        "references": [
+                                            "var.test_var"
+                                        ]
+                                    }
+                                },
+                                "schema_version": 0
+                            }
+                        ],
+                        "variables": {
+                            "test_var": {
+                                "default": "bar-var"
+                            }
+                        }
+                    }
+                },
+                "module_test_foo": {
+                    "source": "./foo",
+                    "expressions": {
+                        "test_var": {
+                            "constant_value": "baz"
+                        }
+                    },
+                    "module": {
+                        "outputs": {
+                            "test": {
+                                "expression": {
+                                    "references": [
+                                        "var.test_var"
+                                    ]
+                                }
+                            }
+                        },
+                        "resources": [
+                            {
+                                "address": "test_instance.test",
+                                "mode": "managed",
+                                "type": "test_instance",
+                                "name": "test",
+                                "provider_config_key": "module.module_test_foo:test",
+                                "expressions": {
+                                    "ami": {
+                                        "references": [
+                                            "var.test_var"
+                                        ]
+                                    }
+                                },
+                                "schema_version": 0,
+                                "count_expression": {
+                                    "constant_value": 3
+                                }
+                            }
+                        ],
+                        "variables": {
+                            "test_var": {
+                                "default": "foo-var"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "provider_config": {
+            "module.module_test_foo:test": {
+                "module_address": "module.module_test_foo",
+                "name": "test",
+                "full_name": "registry.terraform.io/hashicorp/test"
+            },
+            "module.module_test_bar:test": {
+                "module_address": "module.module_test_bar",
+                "name": "test",
+                "full_name": "registry.terraform.io/hashicorp/test"
+            }
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/moved-drift/main.tf b/v1.5.7/internal/command/testdata/show-json/moved-drift/main.tf
new file mode 100644
index 0000000..9f93a10
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/moved-drift/main.tf
@@ -0,0 +1,18 @@
+# In state with `ami = "foo"`, so this should be a regular update. The provider
+# should not detect changes on refresh.
+resource "test_instance" "no_refresh" {
+  ami = "bar"
+}
+
+# In state with `ami = "refresh-me"`, but the provider will return
+# `"refreshed"` after the refresh phase. The plan should show the drift
+# (`"refresh-me"` to `"refreshed"`) and plan the update (`"refreshed"` to
+# `"baz"`).
+resource "test_instance" "should_refresh_with_move" {
+  ami = "baz"
+}
+
+moved {
+  from = test_instance.should_refresh
+  to   = test_instance.should_refresh_with_move
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/moved-drift/output.json b/v1.5.7/internal/command/testdata/show-json/moved-drift/output.json
new file mode 100644
index 0000000..db3ac21
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/moved-drift/output.json
@@ -0,0 +1,183 @@
+{
+    "format_version": "1.0",
+    "planned_values": {
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.no_refresh",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "no_refresh",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar",
+                        "id": "placeholder"
+                    },
+                    "sensitive_values": {}
+                },
+                {
+                    "address": "test_instance.should_refresh_with_move",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "should_refresh_with_move",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "baz",
+                        "id": "placeholder"
+                    },
+                    "sensitive_values": {}
+                }
+            ]
+        }
+    },
+    "resource_drift": [
+        {
+            "address": "test_instance.should_refresh_with_move",
+            "mode": "managed",
+            "type": "test_instance",
+            "previous_address": "test_instance.should_refresh",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "should_refresh_with_move",
+            "change": {
+                "actions": [
+                    "update"
+                ],
+                "before": {
+                    "ami": "refresh-me",
+                    "id": "placeholder"
+                },
+                "after": {
+                    "ami": "refreshed",
+                    "id": "placeholder"
+                },
+                "after_sensitive": {},
+                "after_unknown": {},
+                "before_sensitive": {}
+            }
+        }
+    ],
+    "resource_changes": [
+        {
+            "address": "test_instance.no_refresh",
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "no_refresh",
+            "change": {
+                "actions": [
+                    "update"
+                ],
+                "before": {
+                    "ami": "foo",
+                    "id": "placeholder"
+                },
+                "after": {
+                    "ami": "bar",
+                    "id": "placeholder"
+                },
+                "after_unknown": {},
+                "after_sensitive": {},
+                "before_sensitive": {}
+            }
+        },
+        {
+            "address": "test_instance.should_refresh_with_move",
+            "mode": "managed",
+            "type": "test_instance",
+            "previous_address": "test_instance.should_refresh",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "should_refresh_with_move",
+            "change": {
+                "actions": [
+                    "update"
+                ],
+                "before": {
+                    "ami": "refreshed",
+                    "id": "placeholder"
+                },
+                "after": {
+                    "ami": "baz",
+                    "id": "placeholder"
+                },
+                "after_unknown": {},
+                "after_sensitive": {},
+                "before_sensitive": {}
+            }
+        }
+    ],
+    "prior_state": {
+        "format_version": "1.0",
+        "values": {
+            "root_module": {
+                "resources": [
+                    {
+                        "address": "test_instance.no_refresh",
+                        "mode": "managed",
+                        "type": "test_instance",
+                        "name": "no_refresh",
+                        "schema_version": 0,
+                        "provider_name": "registry.terraform.io/hashicorp/test",
+                        "values": {
+                            "ami": "foo",
+                            "id": "placeholder"
+                        },
+                        "sensitive_values": {}
+                    },
+                    {
+                        "address": "test_instance.should_refresh_with_move",
+                        "mode": "managed",
+                        "type": "test_instance",
+                        "name": "should_refresh_with_move",
+                        "schema_version": 0,
+                        "provider_name": "registry.terraform.io/hashicorp/test",
+                        "values": {
+                            "ami": "refreshed",
+                            "id": "placeholder"
+                        },
+                        "sensitive_values": {}
+                    }
+                ]
+            }
+        }
+    },
+    "configuration": {
+        "provider_config": {
+            "test": {
+                "name": "test",
+                "full_name": "registry.terraform.io/hashicorp/test"
+            }
+        },
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.no_refresh",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "no_refresh",
+                    "provider_config_key": "test",
+                    "schema_version": 0,
+                    "expressions": {
+                        "ami": {
+                            "constant_value": "bar"
+                        }
+                    }
+                },
+                {
+                    "address": "test_instance.should_refresh_with_move",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "should_refresh_with_move",
+                    "provider_config_key": "test",
+                    "schema_version": 0,
+                    "expressions": {
+                        "ami": {
+                            "constant_value": "baz"
+                        }
+                    }
+                }
+            ]
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/moved-drift/terraform.tfstate b/v1.5.7/internal/command/testdata/show-json/moved-drift/terraform.tfstate
new file mode 100644
index 0000000..02b8944
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/moved-drift/terraform.tfstate
@@ -0,0 +1,38 @@
+{
+    "version": 4,
+    "terraform_version": "0.12.0",
+    "serial": 7,
+    "lineage": "configuredUnchanged",
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "no_refresh",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes": {
+                        "ami": "foo",
+                        "id": "placeholder"
+                    }
+                }
+            ]
+        },
+        {
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "should_refresh",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes": {
+                        "ami": "refresh-me",
+                        "id": "placeholder"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/moved/main.tf b/v1.5.7/internal/command/testdata/show-json/moved/main.tf
new file mode 100644
index 0000000..0f11c2c
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/moved/main.tf
@@ -0,0 +1,8 @@
+resource "test_instance" "baz" {
+  ami = "baz"
+}
+
+moved {
+  from = test_instance.foo
+  to   = test_instance.baz
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/moved/output.json b/v1.5.7/internal/command/testdata/show-json/moved/output.json
new file mode 100644
index 0000000..d8b9f2a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/moved/output.json
@@ -0,0 +1,95 @@
+{
+    "format_version": "1.0",
+    "planned_values": {
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.baz",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "baz",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "baz",
+                        "id": "placeholder"
+                    },
+                    "sensitive_values": {}
+                }
+            ]
+        }
+    },
+    "resource_changes": [
+        {
+            "address": "test_instance.baz",
+            "mode": "managed",
+            "type": "test_instance",
+            "previous_address": "test_instance.foo",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "baz",
+            "change": {
+                "actions": [
+                    "update"
+                ],
+                "before": {
+                    "ami": "foo",
+                    "id": "placeholder"
+                },
+                "after": {
+                    "ami": "baz",
+                    "id": "placeholder"
+                },
+                "after_unknown": {},
+                "after_sensitive": {},
+                "before_sensitive": {}
+            }
+        }
+    ],
+    "prior_state": {
+        "format_version": "1.0",
+        "values": {
+            "root_module": {
+                "resources": [
+                    {
+                        "address": "test_instance.baz",
+                        "mode": "managed",
+                        "type": "test_instance",
+                        "name": "baz",
+                        "schema_version": 0,
+                        "provider_name": "registry.terraform.io/hashicorp/test",
+                        "values": {
+                            "ami": "foo",
+                            "id": "placeholder"
+                        },
+                        "sensitive_values": {}
+                    }
+                ]
+            }
+        }
+    },
+    "configuration": {
+        "provider_config": {
+            "test": {
+                "name": "test",
+                "full_name": "registry.terraform.io/hashicorp/test"
+            }
+        },
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.baz",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "baz",
+                    "provider_config_key": "test",
+                    "schema_version": 0,
+                    "expressions": {
+                        "ami": {
+                            "constant_value": "baz"
+                        }
+                    }
+                }
+            ]
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/moved/terraform.tfstate b/v1.5.7/internal/command/testdata/show-json/moved/terraform.tfstate
new file mode 100644
index 0000000..b4e5718
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/moved/terraform.tfstate
@@ -0,0 +1,23 @@
+{
+    "version": 4,
+    "terraform_version": "0.12.0",
+    "serial": 7,
+    "lineage": "configuredUnchanged",
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "foo",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes": {
+                        "ami": "foo",
+                        "id": "placeholder"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/multi-resource-update/main.tf b/v1.5.7/internal/command/testdata/show-json/multi-resource-update/main.tf
new file mode 100644
index 0000000..3ead9dd
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/multi-resource-update/main.tf
@@ -0,0 +1,13 @@
+variable "test_var" {
+  default = "bar"
+}
+
+// There is a single instance in state. The plan will add a resource.
+resource "test_instance" "test" {
+  ami   = var.test_var
+  count = 2
+}
+
+output "test" {
+  value = var.test_var
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/multi-resource-update/output.json b/v1.5.7/internal/command/testdata/show-json/multi-resource-update/output.json
new file mode 100644
index 0000000..3158137
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/multi-resource-update/output.json
@@ -0,0 +1,185 @@
+{
+    "format_version": "1.0",
+    "terraform_version": "0.13.0",
+    "variables": {
+        "test_var": {
+            "value": "bar"
+        }
+    },
+    "planned_values": {
+        "outputs": {
+            "test": {
+                "sensitive": false,
+                "type": "string",
+                "value": "bar"
+            }
+        },
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.test[0]",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "index": 0,
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar",
+                        "id": "placeholder"
+                    },
+                    "sensitive_values": {}
+                },
+                {
+                    "address": "test_instance.test[1]",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "index": 1,
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar"
+                    },
+                    "sensitive_values": {}
+                }
+            ]
+        }
+    },
+    "resource_changes": [
+        {
+            "address": "test_instance.test[0]",
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "test",
+            "index": 0,
+            "previous_address": "test_instance.test",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "change": {
+                "actions": [
+                    "no-op"
+                ],
+                "before": {
+                    "ami": "bar",
+                    "id": "placeholder"
+                },
+                "after": {
+                    "ami": "bar",
+                    "id": "placeholder"
+                },
+                "after_unknown": {},
+                "after_sensitive": {},
+                "before_sensitive": {}
+            }
+        },
+        {
+            "address": "test_instance.test[1]",
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "test",
+            "index": 1,
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after": {
+                    "ami": "bar"
+                },
+                "after_unknown": {
+                    "id": true
+                },
+                "after_sensitive": {},
+                "before_sensitive": false
+            }
+        }
+    ],
+    "output_changes": {
+        "test": {
+            "actions": [
+                "no-op"
+            ],
+            "before": "bar",
+            "after": "bar",
+            "after_unknown": false,
+            "before_sensitive": false,
+            "after_sensitive": false
+        }
+    },
+    "prior_state": {
+        "format_version": "1.0",
+        "terraform_version": "0.13.0",
+        "values": {
+            "outputs": {
+                "test": {
+                    "sensitive": false,
+                    "type": "string",
+                    "value": "bar"
+                }
+            },
+            "root_module": {
+                "resources": [
+                    {
+                        "address": "test_instance.test[0]",
+                        "mode": "managed",
+                        "type": "test_instance",
+                        "name": "test",
+                        "index": 0,
+                        "provider_name": "registry.terraform.io/hashicorp/test",
+                        "schema_version": 0,
+                        "values": {
+                            "ami": "bar",
+                            "id": "placeholder"
+                        },
+                        "sensitive_values": {}
+                    }
+                ]
+            }
+        }
+    },
+    "configuration": {
+        "provider_config": {
+            "test": {
+                "name": "test",
+                "full_name": "registry.terraform.io/hashicorp/test"
+            }
+        },
+        "root_module": {
+            "outputs": {
+                "test": {
+                    "expression": {
+                        "references": [
+                            "var.test_var"
+                        ]
+                    }
+                }
+            },
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_config_key": "test",
+                    "expressions": {
+                        "ami": {
+                            "references": [
+                                "var.test_var"
+                            ]
+                        }
+                    },
+                    "schema_version": 0,
+                    "count_expression": {
+                        "constant_value": 2
+                    }
+                }
+            ],
+            "variables": {
+                "test_var": {
+                    "default": "bar"
+                }
+            }
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/multi-resource-update/terraform.tfstate b/v1.5.7/internal/command/testdata/show-json/multi-resource-update/terraform.tfstate
new file mode 100644
index 0000000..bc691ae
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/multi-resource-update/terraform.tfstate
@@ -0,0 +1,29 @@
+{
+    "version": 4,
+    "terraform_version": "0.12.0",
+    "serial": 7,
+    "lineage": "configuredUnchanged",
+    "outputs": {
+        "test": {
+            "value": "bar",
+            "type": "string"
+        }
+    },
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "test",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes": {
+                        "ami": "bar",
+                        "id": "placeholder"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/nested-module-error/main.tf b/v1.5.7/internal/command/testdata/show-json/nested-module-error/main.tf
new file mode 100644
index 0000000..ef0bad2
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/nested-module-error/main.tf
@@ -0,0 +1,3 @@
+module "my_module" {
+  source = "./modules"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/nested-module-error/modules/main.tf b/v1.5.7/internal/command/testdata/show-json/nested-module-error/modules/main.tf
new file mode 100644
index 0000000..990155e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/nested-module-error/modules/main.tf
@@ -0,0 +1,3 @@
+module "more" {
+  source = "./more-modules"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/nested-module-error/modules/more-modules/main.tf b/v1.5.7/internal/command/testdata/show-json/nested-module-error/modules/more-modules/main.tf
new file mode 100644
index 0000000..488a271
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/nested-module-error/modules/more-modules/main.tf
@@ -0,0 +1,4 @@
+variable "misspelled" {
+  default     = "ehllo"
+  descriptoni = "I am a misspelled attribute"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/nested-modules/main.tf b/v1.5.7/internal/command/testdata/show-json/nested-modules/main.tf
new file mode 100644
index 0000000..ef0bad2
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/nested-modules/main.tf
@@ -0,0 +1,3 @@
+module "my_module" {
+  source = "./modules"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/nested-modules/modules/main.tf b/v1.5.7/internal/command/testdata/show-json/nested-modules/modules/main.tf
new file mode 100644
index 0000000..990155e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/nested-modules/modules/main.tf
@@ -0,0 +1,3 @@
+module "more" {
+  source = "./more-modules"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/nested-modules/modules/more-modules/main.tf b/v1.5.7/internal/command/testdata/show-json/nested-modules/modules/more-modules/main.tf
new file mode 100644
index 0000000..2e5273a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/nested-modules/modules/more-modules/main.tf
@@ -0,0 +1,7 @@
+variable "test_var" {
+  default = "bar-var"
+}
+
+resource "test_instance" "test" {
+  ami = var.test_var
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/nested-modules/output.json b/v1.5.7/internal/command/testdata/show-json/nested-modules/output.json
new file mode 100644
index 0000000..cf1ab97
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/nested-modules/output.json
@@ -0,0 +1,98 @@
+{
+  "format_version": "1.0",
+  "planned_values": {
+    "root_module": {
+      "child_modules": [
+        {
+          "address": "module.my_module",
+          "child_modules": [
+            {
+              "resources": [
+                {
+                  "address": "module.my_module.module.more.test_instance.test",
+                  "mode": "managed",
+                  "type": "test_instance",
+                  "name": "test",
+                  "provider_name": "registry.terraform.io/hashicorp/test",
+                  "schema_version": 0,
+                  "values": {
+                    "ami": "bar-var"
+                  },
+                  "sensitive_values": {}
+                }
+              ],
+              "address": "module.my_module.module.more"
+            }
+          ]
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "module.my_module.module.more.test_instance.test",
+      "module_address": "module.my_module.module.more",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": ["create"],
+        "before": null,
+        "after": {
+          "ami": "bar-var"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "after_sensitive": {},
+        "before_sensitive": false
+      }
+    }
+  ],
+  "configuration": {
+    "provider_config": {
+      "module.my_module.module.more:test": {
+        "module_address": "module.my_module.module.more",
+        "name": "test",
+        "full_name": "registry.terraform.io/hashicorp/test"
+      }
+    },
+    "root_module": {
+      "module_calls": {
+        "my_module": {
+          "source": "./modules",
+          "module": {
+            "module_calls": {
+              "more": {
+                "source": "./more-modules",
+                "module": {
+                  "resources": [
+                    {
+                      "address": "test_instance.test",
+                      "mode": "managed",
+                      "type": "test_instance",
+                      "name": "test",
+                      "provider_config_key": "module.my_module.module.more:test",
+                      "expressions": {
+                        "ami": {
+                          "references": ["var.test_var"]
+                        }
+                      },
+                      "schema_version": 0
+                    }
+                  ],
+                  "variables": {
+                    "test_var": {
+                      "default": "bar-var"
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-aliasing-conflict/child/main.tf b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-conflict/child/main.tf
new file mode 100644
index 0000000..2479df3
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-conflict/child/main.tf
@@ -0,0 +1,11 @@
+terraform {
+  required_providers {
+    test = {
+      source = "hashicorp2/test"
+    }
+  }
+}
+
+resource "test_instance" "test" {
+  ami = "bar"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-aliasing-conflict/main.tf b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-conflict/main.tf
new file mode 100644
index 0000000..2d8bc0b
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-conflict/main.tf
@@ -0,0 +1,11 @@
+provider "test" {
+  region = "somewhere"
+}
+
+resource "test_instance" "test" {
+  ami = "foo"
+}
+
+module "child" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-aliasing-conflict/output.json b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-conflict/output.json
new file mode 100644
index 0000000..b95a96f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-conflict/output.json
@@ -0,0 +1,143 @@
+{
+  "format_version": "1.0",
+  "terraform_version": "1.1.0-dev",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "test_instance.test",
+          "mode": "managed",
+          "type": "test_instance",
+          "name": "test",
+          "provider_name": "registry.terraform.io/hashicorp/test",
+          "schema_version": 0,
+          "values": {
+            "ami": "foo"
+          },
+          "sensitive_values": {}
+        }
+      ],
+      "child_modules": [
+        {
+          "resources": [
+            {
+              "address": "module.child.test_instance.test",
+              "mode": "managed",
+              "type": "test_instance",
+              "name": "test",
+              "provider_name": "registry.terraform.io/hashicorp2/test",
+              "schema_version": 0,
+              "values": {
+                "ami": "bar"
+              },
+              "sensitive_values": {}
+            }
+          ],
+          "address": "module.child"
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "test_instance.test",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "foo"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "module.child.test_instance.test",
+      "module_address": "module.child",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test",
+      "provider_name": "registry.terraform.io/hashicorp2/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "bar"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    }
+  ],
+  "configuration": {
+    "provider_config": {
+      "test": {
+        "name": "test",
+        "full_name": "registry.terraform.io/hashicorp/test",
+        "expressions": {
+          "region": {
+            "constant_value": "somewhere"
+          }
+        }
+      },
+      "module.child:test": {
+        "module_address": "module.child",
+        "name": "test",
+        "full_name": "registry.terraform.io/hashicorp2/test"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "test_instance.test",
+          "mode": "managed",
+          "type": "test_instance",
+          "name": "test",
+          "provider_config_key": "test",
+          "expressions": {
+            "ami": {
+              "constant_value": "foo"
+            }
+          },
+          "schema_version": 0
+        }
+      ],
+      "module_calls": {
+        "child": {
+          "source": "./child",
+          "module": {
+            "resources": [
+              {
+                "address": "test_instance.test",
+                "mode": "managed",
+                "type": "test_instance",
+                "name": "test",
+                "provider_config_key": "module.child:test",
+                "expressions": {
+                  "ami": {
+                    "constant_value": "bar"
+                  }
+                },
+                "schema_version": 0
+              }
+            ]
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-aliasing-default/child/main.tf b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-default/child/main.tf
new file mode 100644
index 0000000..b865e3e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-default/child/main.tf
@@ -0,0 +1,20 @@
+terraform {
+  required_providers {
+    test = {
+      source = "hashicorp/test"
+    }
+  }
+}
+
+resource "test_instance" "test" {
+  ami = "bar"
+}
+
+module "with_requirement" {
+  source     = "./nested"
+  depends_on = [module.no_requirements]
+}
+
+module "no_requirements" {
+  source = "./nested-no-requirements"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-aliasing-default/child/nested-no-requirements/main.tf b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-default/child/nested-no-requirements/main.tf
new file mode 100644
index 0000000..2078186
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-default/child/nested-no-requirements/main.tf
@@ -0,0 +1,3 @@
+resource "test_instance" "test" {
+  ami = "qux"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-aliasing-default/child/nested/main.tf b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-default/child/nested/main.tf
new file mode 100644
index 0000000..1590c5c
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-default/child/nested/main.tf
@@ -0,0 +1,11 @@
+terraform {
+  required_providers {
+    test = {
+      source = "hashicorp/test"
+    }
+  }
+}
+
+resource "test_instance" "test" {
+  ami = "baz"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-aliasing-default/main.tf b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-default/main.tf
new file mode 100644
index 0000000..f5e63f0
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-default/main.tf
@@ -0,0 +1,19 @@
+provider "test" {
+  region = "somewhere"
+}
+
+provider "test" {
+  alias  = "backup"
+  region = "elsewhere"
+}
+
+resource "test_instance" "test" {
+  ami = "foo"
+}
+
+module "child" {
+  source = "./child"
+  providers = {
+    test = test.backup
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-aliasing-default/output.json b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-default/output.json
new file mode 100644
index 0000000..916d78b
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-aliasing-default/output.json
@@ -0,0 +1,271 @@
+{
+  "format_version": "1.0",
+  "terraform_version": "1.1.0-dev",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "test_instance.test",
+          "mode": "managed",
+          "type": "test_instance",
+          "name": "test",
+          "provider_name": "registry.terraform.io/hashicorp/test",
+          "schema_version": 0,
+          "values": {
+            "ami": "foo"
+          },
+          "sensitive_values": {}
+        }
+      ],
+      "child_modules": [
+        {
+          "resources": [
+            {
+              "address": "module.child.test_instance.test",
+              "mode": "managed",
+              "type": "test_instance",
+              "name": "test",
+              "provider_name": "registry.terraform.io/hashicorp/test",
+              "schema_version": 0,
+              "values": {
+                "ami": "bar"
+              },
+              "sensitive_values": {}
+            }
+          ],
+          "address": "module.child",
+          "child_modules": [
+            {
+              "resources": [
+                {
+                  "address": "module.child.module.no_requirements.test_instance.test",
+                  "mode": "managed",
+                  "type": "test_instance",
+                  "name": "test",
+                  "provider_name": "registry.terraform.io/hashicorp/test",
+                  "schema_version": 0,
+                  "values": {
+                    "ami": "qux"
+                  },
+                  "sensitive_values": {}
+                }
+              ],
+              "address": "module.child.module.no_requirements"
+            },
+            {
+              "resources": [
+                {
+                  "address": "module.child.module.with_requirement.test_instance.test",
+                  "mode": "managed",
+                  "type": "test_instance",
+                  "name": "test",
+                  "provider_name": "registry.terraform.io/hashicorp/test",
+                  "schema_version": 0,
+                  "values": {
+                    "ami": "baz"
+                  },
+                  "sensitive_values": {}
+                }
+              ],
+              "address": "module.child.module.with_requirement"
+            }
+          ]
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "test_instance.test",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "foo"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "module.child.test_instance.test",
+      "module_address": "module.child",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "bar"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "module.child.module.no_requirements.test_instance.test",
+      "module_address": "module.child.module.no_requirements",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "qux"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "module.child.module.with_requirement.test_instance.test",
+      "module_address": "module.child.module.with_requirement",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "baz"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    }
+  ],
+  "configuration": {
+    "provider_config": {
+      "test": {
+        "name": "test",
+        "full_name": "registry.terraform.io/hashicorp/test",
+        "expressions": {
+          "region": {
+            "constant_value": "somewhere"
+          }
+        }
+      },
+      "test.backup": {
+        "name": "test",
+        "full_name": "registry.terraform.io/hashicorp/test",
+        "alias": "backup",
+        "expressions": {
+          "region": {
+            "constant_value": "elsewhere"
+          }
+        }
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "test_instance.test",
+          "mode": "managed",
+          "type": "test_instance",
+          "name": "test",
+          "provider_config_key": "test",
+          "expressions": {
+            "ami": {
+              "constant_value": "foo"
+            }
+          },
+          "schema_version": 0
+        }
+      ],
+      "module_calls": {
+        "child": {
+          "source": "./child",
+          "module": {
+            "resources": [
+              {
+                "address": "test_instance.test",
+                "mode": "managed",
+                "type": "test_instance",
+                "name": "test",
+                "provider_config_key": "test.backup",
+                "expressions": {
+                  "ami": {
+                    "constant_value": "bar"
+                  }
+                },
+                "schema_version": 0
+              }
+            ],
+            "module_calls": {
+              "no_requirements": {
+                "source": "./nested-no-requirements",
+                "module": {
+                  "resources": [
+                    {
+                      "address": "test_instance.test",
+                      "mode": "managed",
+                      "type": "test_instance",
+                      "name": "test",
+                      "provider_config_key": "test.backup",
+                      "expressions": {
+                        "ami": {
+                          "constant_value": "qux"
+                        }
+                      },
+                      "schema_version": 0
+                    }
+                  ]
+                }
+              },
+              "with_requirement": {
+                "source": "./nested",
+                "depends_on": ["module.no_requirements"],
+                "module": {
+                  "resources": [
+                    {
+                      "address": "test_instance.test",
+                      "mode": "managed",
+                      "type": "test_instance",
+                      "name": "test",
+                      "provider_config_key": "test.backup",
+                      "expressions": {
+                        "ami": {
+                          "constant_value": "baz"
+                        }
+                      },
+                      "schema_version": 0
+                    }
+                  ]
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-aliasing/child/main.tf b/v1.5.7/internal/command/testdata/show-json/provider-aliasing/child/main.tf
new file mode 100644
index 0000000..4255575
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-aliasing/child/main.tf
@@ -0,0 +1,26 @@
+terraform {
+  required_providers {
+    test = {
+      source                = "hashicorp/test"
+      configuration_aliases = [test, test.second]
+    }
+  }
+}
+
+resource "test_instance" "test_primary" {
+  ami      = "primary"
+  provider = test
+}
+
+resource "test_instance" "test_secondary" {
+  ami      = "secondary"
+  provider = test.second
+}
+
+module "grandchild" {
+  source = "./nested"
+  providers = {
+    test     = test
+    test.alt = test.second
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-aliasing/child/nested/main.tf b/v1.5.7/internal/command/testdata/show-json/provider-aliasing/child/nested/main.tf
new file mode 100644
index 0000000..ff1fe9a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-aliasing/child/nested/main.tf
@@ -0,0 +1,18 @@
+terraform {
+  required_providers {
+    test = {
+      source                = "hashicorp/test"
+      configuration_aliases = [test, test.alt]
+    }
+  }
+}
+
+resource "test_instance" "test_main" {
+  ami      = "main"
+  provider = test
+}
+
+resource "test_instance" "test_alternate" {
+  ami      = "secondary"
+  provider = test.alt
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-aliasing/main.tf b/v1.5.7/internal/command/testdata/show-json/provider-aliasing/main.tf
new file mode 100644
index 0000000..7f6b0a3
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-aliasing/main.tf
@@ -0,0 +1,34 @@
+provider "test" {
+  region = "somewhere"
+}
+
+provider "test" {
+  alias  = "backup"
+  region = "elsewhere"
+}
+
+resource "test_instance" "test" {
+  ami      = "foo"
+  provider = test
+}
+
+resource "test_instance" "test_backup" {
+  ami      = "foo-backup"
+  provider = test.backup
+}
+
+module "child" {
+  source = "./child"
+  providers = {
+    test        = test
+    test.second = test.backup
+  }
+}
+
+module "sibling" {
+  source = "./child"
+  providers = {
+    test        = test
+    test.second = test
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-aliasing/output.json b/v1.5.7/internal/command/testdata/show-json/provider-aliasing/output.json
new file mode 100755
index 0000000..6dc3b74
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-aliasing/output.json
@@ -0,0 +1,567 @@
+{
+  "format_version": "1.0",
+  "terraform_version": "1.1.0-dev",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "test_instance.test",
+          "mode": "managed",
+          "type": "test_instance",
+          "name": "test",
+          "provider_name": "registry.terraform.io/hashicorp/test",
+          "schema_version": 0,
+          "values": {
+            "ami": "foo"
+          },
+          "sensitive_values": {}
+        },
+        {
+          "address": "test_instance.test_backup",
+          "mode": "managed",
+          "type": "test_instance",
+          "name": "test_backup",
+          "provider_name": "registry.terraform.io/hashicorp/test",
+          "schema_version": 0,
+          "values": {
+            "ami": "foo-backup"
+          },
+          "sensitive_values": {}
+        }
+      ],
+      "child_modules": [
+        {
+          "resources": [
+            {
+              "address": "module.child.test_instance.test_primary",
+              "mode": "managed",
+              "type": "test_instance",
+              "name": "test_primary",
+              "provider_name": "registry.terraform.io/hashicorp/test",
+              "schema_version": 0,
+              "values": {
+                "ami": "primary"
+              },
+              "sensitive_values": {}
+            },
+            {
+              "address": "module.child.test_instance.test_secondary",
+              "mode": "managed",
+              "type": "test_instance",
+              "name": "test_secondary",
+              "provider_name": "registry.terraform.io/hashicorp/test",
+              "schema_version": 0,
+              "values": {
+                "ami": "secondary"
+              },
+              "sensitive_values": {}
+            }
+          ],
+          "address": "module.child",
+          "child_modules": [
+            {
+              "resources": [
+                {
+                  "address": "module.child.module.grandchild.test_instance.test_alternate",
+                  "mode": "managed",
+                  "type": "test_instance",
+                  "name": "test_alternate",
+                  "provider_name": "registry.terraform.io/hashicorp/test",
+                  "schema_version": 0,
+                  "values": {
+                    "ami": "secondary"
+                  },
+                  "sensitive_values": {}
+                },
+                {
+                  "address": "module.child.module.grandchild.test_instance.test_main",
+                  "mode": "managed",
+                  "type": "test_instance",
+                  "name": "test_main",
+                  "provider_name": "registry.terraform.io/hashicorp/test",
+                  "schema_version": 0,
+                  "values": {
+                    "ami": "main"
+                  },
+                  "sensitive_values": {}
+                }
+              ],
+              "address": "module.child.module.grandchild"
+            }
+          ]
+        },
+        {
+          "resources": [
+            {
+              "address": "module.sibling.test_instance.test_primary",
+              "mode": "managed",
+              "type": "test_instance",
+              "name": "test_primary",
+              "provider_name": "registry.terraform.io/hashicorp/test",
+              "schema_version": 0,
+              "values": {
+                "ami": "primary"
+              },
+              "sensitive_values": {}
+            },
+            {
+              "address": "module.sibling.test_instance.test_secondary",
+              "mode": "managed",
+              "type": "test_instance",
+              "name": "test_secondary",
+              "provider_name": "registry.terraform.io/hashicorp/test",
+              "schema_version": 0,
+              "values": {
+                "ami": "secondary"
+              },
+              "sensitive_values": {}
+            }
+          ],
+          "address": "module.sibling",
+          "child_modules": [
+            {
+              "resources": [
+                {
+                  "address": "module.sibling.module.grandchild.test_instance.test_alternate",
+                  "mode": "managed",
+                  "type": "test_instance",
+                  "name": "test_alternate",
+                  "provider_name": "registry.terraform.io/hashicorp/test",
+                  "schema_version": 0,
+                  "values": {
+                    "ami": "secondary"
+                  },
+                  "sensitive_values": {}
+                },
+                {
+                  "address": "module.sibling.module.grandchild.test_instance.test_main",
+                  "mode": "managed",
+                  "type": "test_instance",
+                  "name": "test_main",
+                  "provider_name": "registry.terraform.io/hashicorp/test",
+                  "schema_version": 0,
+                  "values": {
+                    "ami": "main"
+                  },
+                  "sensitive_values": {}
+                }
+              ],
+              "address": "module.sibling.module.grandchild"
+            }
+          ]
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "test_instance.test",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "foo"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "test_instance.test_backup",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test_backup",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "foo-backup"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "module.child.test_instance.test_primary",
+      "module_address": "module.child",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test_primary",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "primary"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "module.child.test_instance.test_secondary",
+      "module_address": "module.child",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test_secondary",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "secondary"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "module.sibling.test_instance.test_primary",
+      "module_address": "module.sibling",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test_primary",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "primary"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "module.sibling.test_instance.test_secondary",
+      "module_address": "module.sibling",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test_secondary",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "secondary"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "module.child.module.grandchild.test_instance.test_alternate",
+      "module_address": "module.child.module.grandchild",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test_alternate",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "secondary"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "module.child.module.grandchild.test_instance.test_main",
+      "module_address": "module.child.module.grandchild",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test_main",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "main"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "module.sibling.module.grandchild.test_instance.test_alternate",
+      "module_address": "module.sibling.module.grandchild",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test_alternate",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "secondary"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "module.sibling.module.grandchild.test_instance.test_main",
+      "module_address": "module.sibling.module.grandchild",
+      "mode": "managed",
+      "type": "test_instance",
+      "name": "test_main",
+      "provider_name": "registry.terraform.io/hashicorp/test",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "ami": "main"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    }
+  ],
+  "configuration": {
+    "provider_config": {
+      "test": {
+        "name": "test",
+        "full_name": "registry.terraform.io/hashicorp/test",
+        "expressions": {
+          "region": {
+            "constant_value": "somewhere"
+          }
+        }
+      },
+      "test.backup": {
+        "name": "test",
+        "full_name": "registry.terraform.io/hashicorp/test",
+        "alias": "backup",
+        "expressions": {
+          "region": {
+            "constant_value": "elsewhere"
+          }
+        }
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "test_instance.test",
+          "mode": "managed",
+          "type": "test_instance",
+          "name": "test",
+          "provider_config_key": "test",
+          "expressions": {
+            "ami": {
+              "constant_value": "foo"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "test_instance.test_backup",
+          "mode": "managed",
+          "type": "test_instance",
+          "name": "test_backup",
+          "provider_config_key": "test.backup",
+          "expressions": {
+            "ami": {
+              "constant_value": "foo-backup"
+            }
+          },
+          "schema_version": 0
+        }
+      ],
+      "module_calls": {
+        "child": {
+          "source": "./child",
+          "module": {
+            "resources": [
+              {
+                "address": "test_instance.test_primary",
+                "mode": "managed",
+                "type": "test_instance",
+                "name": "test_primary",
+                "provider_config_key": "test",
+                "expressions": {
+                  "ami": {
+                    "constant_value": "primary"
+                  }
+                },
+                "schema_version": 0
+              },
+              {
+                "address": "test_instance.test_secondary",
+                "mode": "managed",
+                "type": "test_instance",
+                "name": "test_secondary",
+                "provider_config_key": "test.backup",
+                "expressions": {
+                  "ami": {
+                    "constant_value": "secondary"
+                  }
+                },
+                "schema_version": 0
+              }
+            ],
+            "module_calls": {
+              "grandchild": {
+                "source": "./nested",
+                "module": {
+                  "resources": [
+                    {
+                      "address": "test_instance.test_alternate",
+                      "mode": "managed",
+                      "type": "test_instance",
+                      "name": "test_alternate",
+                      "provider_config_key": "test.backup",
+                      "expressions": {
+                        "ami": {
+                          "constant_value": "secondary"
+                        }
+                      },
+                      "schema_version": 0
+                    },
+                    {
+                      "address": "test_instance.test_main",
+                      "mode": "managed",
+                      "type": "test_instance",
+                      "name": "test_main",
+                      "provider_config_key": "test",
+                      "expressions": {
+                        "ami": {
+                          "constant_value": "main"
+                        }
+                      },
+                      "schema_version": 0
+                    }
+                  ]
+                }
+              }
+            }
+          }
+        },
+        "sibling": {
+          "source": "./child",
+          "module": {
+            "resources": [
+              {
+                "address": "test_instance.test_primary",
+                "mode": "managed",
+                "type": "test_instance",
+                "name": "test_primary",
+                "provider_config_key": "test",
+                "expressions": {
+                  "ami": {
+                    "constant_value": "primary"
+                  }
+                },
+                "schema_version": 0
+              },
+              {
+                "address": "test_instance.test_secondary",
+                "mode": "managed",
+                "type": "test_instance",
+                "name": "test_secondary",
+                "provider_config_key": "test",
+                "expressions": {
+                  "ami": {
+                    "constant_value": "secondary"
+                  }
+                },
+                "schema_version": 0
+              }
+            ],
+            "module_calls": {
+              "grandchild": {
+                "source": "./nested",
+                "module": {
+                  "resources": [
+                    {
+                      "address": "test_instance.test_alternate",
+                      "mode": "managed",
+                      "type": "test_instance",
+                      "name": "test_alternate",
+                      "provider_config_key": "test",
+                      "expressions": {
+                        "ami": {
+                          "constant_value": "secondary"
+                        }
+                      },
+                      "schema_version": 0
+                    },
+                    {
+                      "address": "test_instance.test_main",
+                      "mode": "managed",
+                      "type": "test_instance",
+                      "name": "test_main",
+                      "provider_config_key": "test",
+                      "expressions": {
+                        "ami": {
+                          "constant_value": "main"
+                        }
+                      },
+                      "schema_version": 0
+                    }
+                  ]
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-version-no-config/main.tf b/v1.5.7/internal/command/testdata/show-json/provider-version-no-config/main.tf
new file mode 100644
index 0000000..c5df9bf
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-version-no-config/main.tf
@@ -0,0 +1,21 @@
+terraform {
+  required_providers {
+    test = {
+      source = "hashicorp/test"
+      version = ">= 1.2.3"
+    }
+  }
+}
+
+variable "test_var" {
+  default = "bar"
+}
+
+resource "test_instance" "test" {
+  ami   = var.test_var
+  count = 3
+}
+
+output "test" {
+  value = var.test_var
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-version-no-config/output.json b/v1.5.7/internal/command/testdata/show-json/provider-version-no-config/output.json
new file mode 100644
index 0000000..aae0cac
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-version-no-config/output.json
@@ -0,0 +1,198 @@
+{
+    "format_version": "1.0",
+    "variables": {
+        "test_var": {
+            "value": "bar"
+        }
+    },
+    "planned_values": {
+        "outputs": {
+            "test": {
+                "sensitive": false,
+                "type": "string",
+                "value": "bar"
+            }
+        },
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.test[0]",
+                    "index": 0,
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar"
+                    },
+                    "sensitive_values": {}
+                },
+                {
+                    "address": "test_instance.test[1]",
+                    "index": 1,
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar"
+                    },
+                    "sensitive_values": {}
+                },
+                {
+                    "address": "test_instance.test[2]",
+                    "index": 2,
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar"
+                    },
+                    "sensitive_values": {}
+                }
+            ]
+        }
+    },
+    "prior_state": {
+        "format_version": "1.0",
+        "values": {
+            "outputs": {
+                "test": {
+                    "sensitive": false,
+                    "type": "string",
+                    "value": "bar"
+                }
+            },
+            "root_module": {}
+        }
+    },
+    "resource_changes": [
+        {
+            "address": "test_instance.test[0]",
+            "index": 0,
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after_unknown": {
+                    "id": true
+                },
+                "after": {
+                    "ami": "bar"
+                },
+                "after_sensitive": {},
+                "before_sensitive": false
+            }
+        },
+        {
+            "address": "test_instance.test[1]",
+            "index": 1,
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after_unknown": {
+                    "id": true
+                },
+                "after": {
+                    "ami": "bar"
+                },
+                "after_sensitive": {},
+                "before_sensitive": false
+            }
+        },
+        {
+            "address": "test_instance.test[2]",
+            "index": 2,
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after_unknown": {
+                    "id": true
+                },
+                "after": {
+                    "ami": "bar"
+                },
+                "after_sensitive": {},
+                "before_sensitive": false
+            }
+        }
+    ],
+    "output_changes": {
+        "test": {
+            "actions": [
+                "create"
+            ],
+            "before": null,
+            "after": "bar",
+            "after_unknown": false,
+            "before_sensitive": false,
+            "after_sensitive": false
+        }
+    },
+    "configuration": {
+        "provider_config": {
+            "test": {
+                "name": "test",
+                "full_name": "registry.terraform.io/hashicorp/test",
+                "version_constraint": ">= 1.2.3"
+            }
+        },
+        "root_module": {
+            "outputs": {
+                "test": {
+                    "expression": {
+                        "references": [
+                            "var.test_var"
+                        ]
+                    }
+                }
+            },
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_config_key": "test",
+                    "schema_version": 0,
+                    "expressions": {
+                        "ami": {
+                            "references": [
+                                "var.test_var"
+                            ]
+                        }
+                    },
+                    "count_expression": {
+                        "constant_value": 3
+                    }
+                }
+            ],
+            "variables": {
+                "test_var": {
+                    "default": "bar"
+                }
+            }
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-version/main.tf b/v1.5.7/internal/command/testdata/show-json/provider-version/main.tf
new file mode 100644
index 0000000..b6d3cb9
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-version/main.tf
@@ -0,0 +1,26 @@
+terraform {
+  required_providers {
+    test = {
+      source = "hashicorp/test"
+      version = ">= 1.2.3"
+    }
+  }
+}
+
+provider "test" {
+  region = "somewhere"
+  version = "1.2.3"
+}
+
+variable "test_var" {
+  default = "bar"
+}
+
+resource "test_instance" "test" {
+  ami   = var.test_var
+  count = 3
+}
+
+output "test" {
+  value = var.test_var
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/provider-version/output.json b/v1.5.7/internal/command/testdata/show-json/provider-version/output.json
new file mode 100644
index 0000000..111ece4
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/provider-version/output.json
@@ -0,0 +1,203 @@
+{
+    "format_version": "1.0",
+    "variables": {
+        "test_var": {
+            "value": "bar"
+        }
+    },
+    "planned_values": {
+        "outputs": {
+            "test": {
+                "sensitive": false,
+                "type": "string",
+                "value": "bar"
+            }
+        },
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.test[0]",
+                    "index": 0,
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar"
+                    },
+                    "sensitive_values": {}
+                },
+                {
+                    "address": "test_instance.test[1]",
+                    "index": 1,
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar"
+                    },
+                    "sensitive_values": {}
+                },
+                {
+                    "address": "test_instance.test[2]",
+                    "index": 2,
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "bar"
+                    },
+                    "sensitive_values": {}
+                }
+            ]
+        }
+    },
+    "prior_state": {
+        "format_version": "1.0",
+        "values": {
+            "outputs": {
+                "test": {
+                    "sensitive": false,
+                    "type": "string",
+                    "value": "bar"
+                }
+            },
+            "root_module": {}
+        }
+    },
+    "resource_changes": [
+        {
+            "address": "test_instance.test[0]",
+            "index": 0,
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after_unknown": {
+                    "id": true
+                },
+                "after": {
+                    "ami": "bar"
+                },
+                "after_sensitive": {},
+                "before_sensitive": false
+            }
+        },
+        {
+            "address": "test_instance.test[1]",
+            "index": 1,
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after_unknown": {
+                    "id": true
+                },
+                "after": {
+                    "ami": "bar"
+                },
+                "after_sensitive": {},
+                "before_sensitive": false
+            }
+        },
+        {
+            "address": "test_instance.test[2]",
+            "index": 2,
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after_unknown": {
+                    "id": true
+                },
+                "after": {
+                    "ami": "bar"
+                },
+                "after_sensitive": {},
+                "before_sensitive": false
+            }
+        }
+    ],
+    "output_changes": {
+        "test": {
+            "actions": [
+                "create"
+            ],
+            "before": null,
+            "after": "bar",
+            "after_unknown": false,
+            "before_sensitive": false,
+            "after_sensitive": false
+        }
+    },
+    "configuration": {
+        "provider_config": {
+            "test": {
+                "name": "test",
+                "full_name": "registry.terraform.io/hashicorp/test",
+                "expressions": {
+                    "region": {
+                        "constant_value": "somewhere"
+                    }
+                },
+                "version_constraint": ">= 1.2.3, 1.2.3"
+            }
+        },
+        "root_module": {
+            "outputs": {
+                "test": {
+                    "expression": {
+                        "references": [
+                            "var.test_var"
+                        ]
+                    }
+                }
+            },
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_config_key": "test",
+                    "schema_version": 0,
+                    "expressions": {
+                        "ami": {
+                            "references": [
+                                "var.test_var"
+                            ]
+                        }
+                    },
+                    "count_expression": {
+                        "constant_value": 3
+                    }
+                }
+            ],
+            "variables": {
+                "test_var": {
+                    "default": "bar"
+                }
+            }
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/requires-replace/main.tf b/v1.5.7/internal/command/testdata/show-json/requires-replace/main.tf
new file mode 100644
index 0000000..6be6611
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/requires-replace/main.tf
@@ -0,0 +1,3 @@
+resource "test_instance" "test" {
+    ami = "force-replace"
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/requires-replace/output.json b/v1.5.7/internal/command/testdata/show-json/requires-replace/output.json
new file mode 100644
index 0000000..1eb37ea
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/requires-replace/output.json
@@ -0,0 +1,97 @@
+{
+    "format_version": "1.0",
+    "planned_values": {
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "force-replace"
+                    },
+                    "sensitive_values": {}
+                }
+            ]
+        }
+    },
+    "resource_changes": [
+        {
+            "address": "test_instance.test",
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "delete",
+                    "create"
+                ],
+                "before": {
+                    "ami": "bar",
+                    "id": "placeholder"
+                },
+                "after": {
+                    "ami": "force-replace"
+                },
+                "after_unknown": {
+                    "id": true
+                },
+                "after_sensitive": {},
+                "before_sensitive": {},
+                "replace_paths": [["ami"]]
+            },
+            "action_reason": "replace_because_cannot_update"
+        }
+    ],
+    "prior_state": {
+        "format_version": "1.0",
+        "values": {
+            "root_module": {
+                "resources": [
+                    {
+                        "address": "test_instance.test",
+                        "mode": "managed",
+                        "type": "test_instance",
+                        "name": "test",
+                        "schema_version": 0,
+                        "provider_name": "registry.terraform.io/hashicorp/test",
+                        "values": {
+                            "ami": "bar",
+                            "id": "placeholder"
+                        },
+                        "sensitive_values": {}
+                    }
+                ]
+            }
+        }
+    },
+    "configuration": {
+        "provider_config": {
+            "test": {
+                "name": "test",
+                "full_name": "registry.terraform.io/hashicorp/test"
+            }
+        },
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_config_key": "test",
+                    "schema_version": 0,
+                    "expressions": {
+                        "ami": {
+                            "constant_value": "force-replace"
+                        }
+                    }
+                }
+            ]
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/requires-replace/terraform.tfstate b/v1.5.7/internal/command/testdata/show-json/requires-replace/terraform.tfstate
new file mode 100644
index 0000000..b57f60f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/requires-replace/terraform.tfstate
@@ -0,0 +1,24 @@
+{
+    "version": 4,
+    "terraform_version": "0.12.0",
+    "serial": 7,
+    "lineage": "configuredUnchanged",
+    "outputs": {},
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "test",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes": {
+                        "ami": "bar",
+                        "id": "placeholder"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/sensitive-values/main.tf b/v1.5.7/internal/command/testdata/show-json/sensitive-values/main.tf
new file mode 100644
index 0000000..3f8ba82
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/sensitive-values/main.tf
@@ -0,0 +1,13 @@
+variable "test_var" {
+  default = "boop"
+  sensitive = true
+}
+
+resource "test_instance" "test" {
+  ami = var.test_var
+}
+
+output "test" {
+  value = test_instance.test.ami
+  sensitive = true
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/sensitive-values/output.json b/v1.5.7/internal/command/testdata/show-json/sensitive-values/output.json
new file mode 100644
index 0000000..fcdc976
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/sensitive-values/output.json
@@ -0,0 +1,129 @@
+{
+    "format_version": "1.0",
+    "variables": {
+        "test_var": {
+            "value": "boop"
+        }
+    },
+    "planned_values": {
+        "outputs": {
+            "test": {
+                "sensitive": true,
+                "type": "string",
+                "value": "boop"
+            }
+        },
+        "root_module": {
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_name": "registry.terraform.io/hashicorp/test",
+                    "schema_version": 0,
+                    "values": {
+                        "ami": "boop"
+                    },
+                    "sensitive_values": {
+                        "ami": true
+                    }
+                }
+            ]
+        }
+    },
+    "resource_changes": [
+        {
+            "address": "test_instance.test",
+            "mode": "managed",
+            "type": "test_instance",
+            "provider_name": "registry.terraform.io/hashicorp/test",
+            "name": "test",
+            "change": {
+                "actions": [
+                    "create"
+                ],
+                "before": null,
+                "after": {
+                    "ami": "boop"
+                },
+                "after_unknown": {
+                    "id": true
+                },
+                "after_sensitive": {
+                  "ami": true
+                },
+                "before_sensitive": false
+            }
+        }
+    ],
+    "output_changes": {
+        "test": {
+            "actions": [
+                "create"
+            ],
+            "before": null,
+            "after": "boop",
+            "after_unknown": false,
+            "before_sensitive": true,
+            "after_sensitive": true
+        }
+    },
+    "prior_state": {
+        "format_version": "1.0",
+        "values": {
+            "outputs": {
+                "test": {
+                    "sensitive": true,
+                    "type": "string",
+                    "value": "boop"
+                }
+            },
+            "root_module": {}
+        }
+    },
+    "configuration": {
+        "provider_config": {
+            "test": {
+                "name": "test",
+                "full_name": "registry.terraform.io/hashicorp/test"
+            }
+        },
+        "root_module": {
+            "outputs": {
+                "test": {
+                    "expression": {
+                        "references": [
+                            "test_instance.test.ami",
+                            "test_instance.test"
+                        ]
+                    },
+                    "sensitive": true
+                }
+            },
+            "resources": [
+                {
+                    "address": "test_instance.test",
+                    "mode": "managed",
+                    "type": "test_instance",
+                    "name": "test",
+                    "provider_config_key": "test",
+                    "schema_version": 0,
+                    "expressions": {
+                        "ami": {
+                            "references": [
+                                "var.test_var"
+                            ]
+                        }
+                    }
+                }
+            ],
+            "variables": {
+                "test_var": {
+                    "default": "boop",
+                    "sensitive": true
+                }
+            }
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/unknown-output/main.tf b/v1.5.7/internal/command/testdata/show-json/unknown-output/main.tf
new file mode 100644
index 0000000..d97891e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/unknown-output/main.tf
@@ -0,0 +1,19 @@
+output "foo" {
+  value = "hello"
+}
+
+output "bar" {
+  value = tolist([
+    "hello",
+    timestamp(),
+    "world",
+  ])
+}
+
+output "baz" {
+  value = {
+    greeting: "hello",
+    time: timestamp(),
+    subject: "world",
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/show-json/unknown-output/output.json b/v1.5.7/internal/command/testdata/show-json/unknown-output/output.json
new file mode 100644
index 0000000..8a52b8d
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show-json/unknown-output/output.json
@@ -0,0 +1,96 @@
+{
+  "format_version": "1.1",
+  "terraform_version": "1.3.0-dev",
+  "planned_values": {
+    "outputs": {
+      "bar": {
+        "sensitive": false
+      },
+      "baz": {
+        "sensitive": false
+      },
+      "foo": {
+        "sensitive": false,
+        "type": "string",
+        "value": "hello"
+      }
+    },
+    "root_module": {}
+  },
+  "output_changes": {
+    "bar": {
+      "actions": [
+        "create"
+      ],
+      "before": null,
+      "after": [
+        "hello",
+        null,
+        "world"
+      ],
+      "after_unknown": [
+        false,
+        true,
+        false
+      ],
+      "before_sensitive": false,
+      "after_sensitive": false
+    },
+    "baz": {
+      "actions": [
+        "create"
+      ],
+      "before": null,
+      "after": {
+        "greeting": "hello",
+        "subject": "world"
+      },
+      "after_unknown": {
+        "time": true
+      },
+      "before_sensitive": false,
+      "after_sensitive": false
+    },
+    "foo": {
+      "actions": [
+        "create"
+      ],
+      "before": null,
+      "after": "hello",
+      "after_unknown": false,
+      "before_sensitive": false,
+      "after_sensitive": false
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "terraform_version": "1.3.0",
+    "values": {
+      "outputs": {
+        "foo": {
+          "sensitive": false,
+          "value": "hello",
+          "type": "string"
+        }
+      },
+      "root_module": {}
+    }
+  },
+  "configuration": {
+    "root_module": {
+      "outputs": {
+        "bar": {
+          "expression": {}
+        },
+        "baz": {
+          "expression": {}
+        },
+        "foo": {
+          "expression": {
+            "constant_value": "hello"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/show/main.tf b/v1.5.7/internal/command/testdata/show/main.tf
new file mode 100644
index 0000000..1b10129
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/show/main.tf
@@ -0,0 +1,3 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+}
diff --git a/v1.5.7/internal/command/testdata/state-list-backend-custom/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/state-list-backend-custom/.terraform/terraform.tfstate
new file mode 100644
index 0000000..122adb8
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-list-backend-custom/.terraform/terraform.tfstate
@@ -0,0 +1,23 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate",
+            "workspace_dir": null
+        },
+        "hash": 4282859327
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-list-backend-custom/local-state.tfstate b/v1.5.7/internal/command/testdata/state-list-backend-custom/local-state.tfstate
new file mode 100644
index 0000000..f357c30
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-list-backend-custom/local-state.tfstate
@@ -0,0 +1,24 @@
+{
+  "version": 4,
+  "terraform_version": "0.12.0",
+  "serial": 7,
+  "lineage": "configuredUnchanged",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "a",
+      "provider": "provider[\"registry.terraform.io/-/null\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "8521602373864259745",
+            "triggers": null
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-list-backend-custom/main.tf b/v1.5.7/internal/command/testdata/state-list-backend-custom/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-list-backend-custom/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/state-list-backend-default/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/state-list-backend-default/.terraform/terraform.tfstate
new file mode 100644
index 0000000..44ed4f6
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-list-backend-default/.terraform/terraform.tfstate
@@ -0,0 +1,23 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": null,
+            "workspace_dir": null
+        },
+        "hash": 666019178
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-list-backend-default/main.tf b/v1.5.7/internal/command/testdata/state-list-backend-default/main.tf
new file mode 100644
index 0000000..7f62e0e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-list-backend-default/main.tf
@@ -0,0 +1,4 @@
+terraform {
+    backend "local" {
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/state-list-backend-default/terraform.tfstate b/v1.5.7/internal/command/testdata/state-list-backend-default/terraform.tfstate
new file mode 100644
index 0000000..f357c30
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-list-backend-default/terraform.tfstate
@@ -0,0 +1,24 @@
+{
+  "version": 4,
+  "terraform_version": "0.12.0",
+  "serial": 7,
+  "lineage": "configuredUnchanged",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "a",
+      "provider": "provider[\"registry.terraform.io/-/null\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "8521602373864259745",
+            "triggers": null
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-list-nested-modules/terraform.tfstate b/v1.5.7/internal/command/testdata/state-list-nested-modules/terraform.tfstate
new file mode 100644
index 0000000..3e4689a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-list-nested-modules/terraform.tfstate
@@ -0,0 +1,91 @@
+{
+    "version": 4,
+    "terraform_version": "0.15.0",
+    "serial": 8,
+    "lineage": "00bfda35-ad61-ec8d-c013-14b0320bc416",
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "root",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "attributes": {
+                        "id": "root"
+                    }
+                }
+            ]
+        },
+        {
+            "module": "module.nest",
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "nest",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "attributes": {
+                        "ami": "nested"
+                    }
+                }
+            ]
+        },
+        {
+            "module": "module.nest.module.subnest",
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "subnest",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "attributes": {
+                        "id": "subnested"
+                    }
+                }
+            ]
+        },
+        {
+            "module": "module.nonexist.module.child",
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "child",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "attributes": {
+                        "id": "child"
+                    }
+                }
+            ]
+        },
+        {
+            "module": "module.count[0]",
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "count",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "attributes": {
+                        "id": "zero"
+                    }
+                }
+            ]
+        },
+        {
+            "module": "module.count[1]",
+            "mode": "managed",
+            "type": "test_instance",
+            "name": "count",
+            "provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
+            "instances": [
+                {
+                    "attributes": {
+                        "id": "one"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-pull-backend/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/state-pull-backend/.terraform/terraform.tfstate
new file mode 100644
index 0000000..122adb8
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-pull-backend/.terraform/terraform.tfstate
@@ -0,0 +1,23 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate",
+            "workspace_dir": null
+        },
+        "hash": 4282859327
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-pull-backend/local-state.tfstate b/v1.5.7/internal/command/testdata/state-pull-backend/local-state.tfstate
new file mode 100644
index 0000000..db3d0b7
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-pull-backend/local-state.tfstate
@@ -0,0 +1,24 @@
+{
+  "version": 4,
+  "terraform_version": "0.12.0",
+  "serial": 7,
+  "lineage": "configuredUnchanged",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "a",
+      "provider": "provider.null",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "8521602373864259745",
+            "triggers": null
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-pull-backend/main.tf b/v1.5.7/internal/command/testdata/state-pull-backend/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-pull-backend/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-bad-lineage/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/state-push-bad-lineage/.terraform/terraform.tfstate
new file mode 100644
index 0000000..073bd7a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-bad-lineage/.terraform/terraform.tfstate
@@ -0,0 +1,22 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate"
+        },
+        "hash": 9073424445967744180
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-bad-lineage/local-state.tfstate b/v1.5.7/internal/command/testdata/state-push-bad-lineage/local-state.tfstate
new file mode 100644
index 0000000..d4317e7
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-bad-lineage/local-state.tfstate
@@ -0,0 +1,11 @@
+{
+    "version": 4,
+    "serial": 1,
+    "lineage": "mismatch",
+    "outputs": {
+        "foo": {
+            "type": "string",
+            "value": "bar"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-bad-lineage/main.tf b/v1.5.7/internal/command/testdata/state-push-bad-lineage/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-bad-lineage/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-bad-lineage/replace.tfstate b/v1.5.7/internal/command/testdata/state-push-bad-lineage/replace.tfstate
new file mode 100644
index 0000000..670f0cc
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-bad-lineage/replace.tfstate
@@ -0,0 +1,11 @@
+{
+    "version": 4,
+    "serial": 2,
+    "lineage": "hello",
+    "outputs": {
+        "foo": {
+            "type": "string",
+            "value": "baz"
+        }
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-good/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/state-push-good/.terraform/terraform.tfstate
new file mode 100644
index 0000000..122adb8
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-good/.terraform/terraform.tfstate
@@ -0,0 +1,23 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate",
+            "workspace_dir": null
+        },
+        "hash": 4282859327
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-good/main.tf b/v1.5.7/internal/command/testdata/state-push-good/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-good/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-good/replace.tfstate b/v1.5.7/internal/command/testdata/state-push-good/replace.tfstate
new file mode 100644
index 0000000..9921bc0
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-good/replace.tfstate
@@ -0,0 +1,23 @@
+{
+  "version": 4,
+  "serial": 0,
+  "lineage": "hello",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "b",
+      "provider": "provider.null",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "9051675049789185374",
+            "triggers": null
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-replace-match/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/state-push-replace-match/.terraform/terraform.tfstate
new file mode 100644
index 0000000..122adb8
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-replace-match/.terraform/terraform.tfstate
@@ -0,0 +1,23 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate",
+            "workspace_dir": null
+        },
+        "hash": 4282859327
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-replace-match/local-state.tfstate b/v1.5.7/internal/command/testdata/state-push-replace-match/local-state.tfstate
new file mode 100644
index 0000000..b4cf81f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-replace-match/local-state.tfstate
@@ -0,0 +1,23 @@
+{
+  "version": 4,
+  "serial": 1,
+  "lineage": "hello",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "a",
+      "provider": "provider.null",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "8521602373864259745",
+            "triggers": null
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-replace-match/main.tf b/v1.5.7/internal/command/testdata/state-push-replace-match/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-replace-match/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-replace-match/replace.tfstate b/v1.5.7/internal/command/testdata/state-push-replace-match/replace.tfstate
new file mode 100644
index 0000000..a5789c5
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-replace-match/replace.tfstate
@@ -0,0 +1,23 @@
+{
+  "version": 4,
+  "serial": 2,
+  "lineage": "hello",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "b",
+      "provider": "provider.null",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "9051675049789185374",
+            "triggers": null
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-serial-newer/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/state-push-serial-newer/.terraform/terraform.tfstate
new file mode 100644
index 0000000..122adb8
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-serial-newer/.terraform/terraform.tfstate
@@ -0,0 +1,23 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate",
+            "workspace_dir": null
+        },
+        "hash": 4282859327
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-serial-newer/local-state.tfstate b/v1.5.7/internal/command/testdata/state-push-serial-newer/local-state.tfstate
new file mode 100644
index 0000000..012c885
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-serial-newer/local-state.tfstate
@@ -0,0 +1,23 @@
+{
+  "version": 4,
+  "serial": 3,
+  "lineage": "hello",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "a",
+      "provider": "provider[\"registry.terraform.io/-/null\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "8521602373864259745",
+            "triggers": null
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-serial-newer/main.tf b/v1.5.7/internal/command/testdata/state-push-serial-newer/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-serial-newer/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-serial-newer/replace.tfstate b/v1.5.7/internal/command/testdata/state-push-serial-newer/replace.tfstate
new file mode 100644
index 0000000..ad94a1f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-serial-newer/replace.tfstate
@@ -0,0 +1,23 @@
+{
+  "version": 4,
+  "serial": 2,
+  "lineage": "hello",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "b",
+      "provider": "provider[\"registry.terraform.io/-/null\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "9051675049789185374",
+            "triggers": null
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-serial-older/.terraform/terraform.tfstate b/v1.5.7/internal/command/testdata/state-push-serial-older/.terraform/terraform.tfstate
new file mode 100644
index 0000000..122adb8
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-serial-older/.terraform/terraform.tfstate
@@ -0,0 +1,23 @@
+{
+    "version": 3,
+    "serial": 0,
+    "lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
+    "backend": {
+        "type": "local",
+        "config": {
+            "path": "local-state.tfstate",
+            "workspace_dir": null
+        },
+        "hash": 4282859327
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {},
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-serial-older/local-state.tfstate b/v1.5.7/internal/command/testdata/state-push-serial-older/local-state.tfstate
new file mode 100644
index 0000000..b4cf81f
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-serial-older/local-state.tfstate
@@ -0,0 +1,23 @@
+{
+  "version": 4,
+  "serial": 1,
+  "lineage": "hello",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "a",
+      "provider": "provider.null",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "8521602373864259745",
+            "triggers": null
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-serial-older/main.tf b/v1.5.7/internal/command/testdata/state-push-serial-older/main.tf
new file mode 100644
index 0000000..ca1bd39
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-serial-older/main.tf
@@ -0,0 +1,5 @@
+terraform {
+    backend "local" {
+        path = "local-state.tfstate"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/state-push-serial-older/replace.tfstate b/v1.5.7/internal/command/testdata/state-push-serial-older/replace.tfstate
new file mode 100644
index 0000000..a5789c5
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/state-push-serial-older/replace.tfstate
@@ -0,0 +1,23 @@
+{
+  "version": 4,
+  "serial": 2,
+  "lineage": "hello",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "b",
+      "provider": "provider.null",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "9051675049789185374",
+            "triggers": null
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/statelocker.go b/v1.5.7/internal/command/testdata/statelocker.go
new file mode 100644
index 0000000..a317086
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/statelocker.go
@@ -0,0 +1,54 @@
+// statelocker use used for testing command with a locked state.
+// This will lock the state file at a given path, then wait for a sigal. On
+// SIGINT and SIGTERM the state will be Unlocked before exit.
+package main
+
+import (
+	"io"
+	"log"
+	"os"
+	"os/signal"
+	"syscall"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+func main() {
+	if len(os.Args) != 2 {
+		log.Fatal(os.Args[0], "statefile")
+	}
+
+	s := &clistate.LocalState{
+		Path: os.Args[1],
+	}
+
+	info := statemgr.NewLockInfo()
+	info.Operation = "test"
+	info.Info = "state locker"
+
+	lockID, err := s.Lock(info)
+	if err != nil {
+		io.WriteString(os.Stderr, err.Error())
+		return
+	}
+
+	// signal to the caller that we're locked
+	io.WriteString(os.Stdout, "LOCKID "+lockID)
+
+	defer func() {
+		if err := s.Unlock(lockID); err != nil {
+			io.WriteString(os.Stderr, err.Error())
+		}
+	}()
+
+	c := make(chan os.Signal, 1)
+	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
+
+	// timeout after 10 second in case we don't get cleaned up by the test
+	select {
+	case <-time.After(10 * time.Second):
+	case <-c:
+	}
+}
diff --git a/v1.5.7/internal/command/testdata/test-fails/test-fails.tf b/v1.5.7/internal/command/testdata/test-fails/test-fails.tf
new file mode 100644
index 0000000..d618fb9
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/test-fails/test-fails.tf
@@ -0,0 +1,7 @@
+variable "input" {
+  type = string
+}
+
+output "foo" {
+  value = "foo value ${var.input}"
+}
diff --git a/v1.5.7/internal/command/testdata/test-fails/tests/hello/hello.tf b/v1.5.7/internal/command/testdata/test-fails/tests/hello/hello.tf
new file mode 100644
index 0000000..6fbf8ee
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/test-fails/tests/hello/hello.tf
@@ -0,0 +1,23 @@
+terraform {
+  required_providers {
+    test = {
+      source = "terraform.io/builtin/test"
+    }
+  }
+}
+
+module "main" {
+  source = "../.."
+
+  input = "boop"
+}
+
+resource "test_assertions" "foo" {
+  component = "foo"
+
+  equal "output" {
+    description = "output \"foo\" value"
+    got         = module.main.foo
+    want        = "foo not boop"
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/test-passes/test-passes.tf b/v1.5.7/internal/command/testdata/test-passes/test-passes.tf
new file mode 100644
index 0000000..d618fb9
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/test-passes/test-passes.tf
@@ -0,0 +1,7 @@
+variable "input" {
+  type = string
+}
+
+output "foo" {
+  value = "foo value ${var.input}"
+}
diff --git a/v1.5.7/internal/command/testdata/test-passes/tests/hello/hello.tf b/v1.5.7/internal/command/testdata/test-passes/tests/hello/hello.tf
new file mode 100644
index 0000000..2129f43
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/test-passes/tests/hello/hello.tf
@@ -0,0 +1,23 @@
+terraform {
+  required_providers {
+    test = {
+      source = "terraform.io/builtin/test"
+    }
+  }
+}
+
+module "main" {
+  source = "../.."
+
+  input = "boop"
+}
+
+resource "test_assertions" "foo" {
+  component = "foo"
+
+  equal "output" {
+    description = "output \"foo\" value"
+    got         = module.main.foo
+    want        = "foo value boop"
+  }
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/duplicate_import_targets/main.tf b/v1.5.7/internal/command/testdata/validate-invalid/duplicate_import_targets/main.tf
new file mode 100644
index 0000000..3c663bd
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/duplicate_import_targets/main.tf
@@ -0,0 +1,12 @@
+resource "aws_instance" "web" {
+}
+
+import {
+  to = aws_instance.web
+  id = "test"
+}
+
+import {
+  to = aws_instance.web
+  id = "test2"
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/duplicate_import_targets/output.json b/v1.5.7/internal/command/testdata/validate-invalid/duplicate_import_targets/output.json
new file mode 100644
index 0000000..bad183b
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/duplicate_import_targets/output.json
@@ -0,0 +1,34 @@
+{
+  "format_version": "1.0",
+  "valid": false,
+  "error_count": 1,
+  "warning_count": 0,
+  "diagnostics": [
+    {
+      "severity": "error",
+      "summary": "Duplicate import configuration for \"aws_instance.web\"",
+      "detail": "An import block for the resource \"aws_instance.web\" was already declared at testdata/validate-invalid/duplicate_import_targets/main.tf:4,1-7. A resource can have only one import block.",
+      "range": {
+        "filename": "testdata/validate-invalid/duplicate_import_targets/main.tf",
+        "start": {
+          "line": 9,
+          "column": 1,
+          "byte": 85
+        },
+        "end": {
+          "line": 9,
+          "column": 7,
+          "byte": 91
+        }
+      },
+      "snippet": {
+        "context": null,
+        "code": "import {",
+        "start_line": 9,
+        "highlight_start_offset": 0,
+        "highlight_end_offset": 6,
+        "values": []
+      }
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/incorrectmodulename/main.tf b/v1.5.7/internal/command/testdata/validate-invalid/incorrectmodulename/main.tf
new file mode 100644
index 0000000..4550940
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/incorrectmodulename/main.tf
@@ -0,0 +1,6 @@
+module "super#module" {
+}
+
+module "super" {
+  source = var.modulename
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/incorrectmodulename/output.json b/v1.5.7/internal/command/testdata/validate-invalid/incorrectmodulename/output.json
new file mode 100644
index 0000000..f144313
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/incorrectmodulename/output.json
@@ -0,0 +1,112 @@
+{
+  "format_version": "1.0",
+  "valid": false,
+  "error_count": 4,
+  "warning_count": 0,
+  "diagnostics": [
+    {
+      "severity": "error",
+      "summary": "Missing required argument",
+      "detail": "The argument \"source\" is required, but no definition was found.",
+      "range": {
+        "filename": "testdata/validate-invalid/incorrectmodulename/main.tf",
+        "start": {
+          "line": 1,
+          "column": 23,
+          "byte": 22
+        },
+        "end": {
+          "line": 1,
+          "column": 24,
+          "byte": 23
+        }
+      },
+      "snippet": {
+        "context": "module \"super#module\"",
+        "code": "module \"super#module\" {",
+        "start_line": 1,
+        "highlight_start_offset": 22,
+        "highlight_end_offset": 23,
+        "values": []
+      }
+    },
+    {
+      "severity": "error",
+      "summary": "Invalid module instance name",
+      "detail": "A name must start with a letter or underscore and may contain only letters, digits, underscores, and dashes.",
+      "range": {
+        "filename": "testdata/validate-invalid/incorrectmodulename/main.tf",
+        "start": {
+          "line": 1,
+          "column": 8,
+          "byte": 7
+        },
+        "end": {
+          "line": 1,
+          "column": 22,
+          "byte": 21
+        }
+      },
+      "snippet": {
+        "context": "module \"super#module\"",
+        "code": "module \"super#module\" {",
+        "start_line": 1,
+        "highlight_start_offset": 7,
+        "highlight_end_offset": 21,
+        "values": []
+      }
+    },
+    {
+      "severity": "error",
+      "summary": "Variables not allowed",
+      "detail": "Variables may not be used here.",
+      "range": {
+        "filename": "testdata/validate-invalid/incorrectmodulename/main.tf",
+        "start": {
+          "line": 5,
+          "column": 12,
+          "byte": 55
+        },
+        "end": {
+          "line": 5,
+          "column": 15,
+          "byte": 58
+        }
+      },
+      "snippet": {
+        "context": "module \"super\"",
+        "code": "  source = var.modulename",
+        "start_line": 5,
+        "highlight_start_offset": 11,
+        "highlight_end_offset": 14,
+        "values": []
+      }
+    },
+    {
+      "severity": "error",
+      "summary": "Unsuitable value type",
+      "detail": "Unsuitable value: value must be known",
+      "range": {
+        "filename": "testdata/validate-invalid/incorrectmodulename/main.tf",
+        "start": {
+          "line": 5,
+          "column": 12,
+          "byte": 55
+        },
+        "end": {
+          "line": 5,
+          "column": 26,
+          "byte": 69
+        }
+      },
+      "snippet": {
+        "context": "module \"super\"",
+        "code": "  source = var.modulename",
+        "start_line": 5,
+        "highlight_start_offset": 11,
+        "highlight_end_offset": 25,
+        "values": []
+      }
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/interpolation/main.tf b/v1.5.7/internal/command/testdata/validate-invalid/interpolation/main.tf
new file mode 100644
index 0000000..bbb8e69
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/interpolation/main.tf
@@ -0,0 +1,11 @@
+variable "otherresourcename" {
+  default = "aws_instance.web1"
+}
+
+variable "vairable_with_interpolation" {
+  default = "${var.otherresourcename}"
+}
+
+resource "aws_instance" "web" {
+  depends_on = ["${var.otherresourcename}}"]
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/interpolation/output.json b/v1.5.7/internal/command/testdata/validate-invalid/interpolation/output.json
new file mode 100644
index 0000000..2843b19
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/interpolation/output.json
@@ -0,0 +1,60 @@
+{
+  "format_version": "1.0",
+  "valid": false,
+  "error_count": 2,
+  "warning_count": 0,
+  "diagnostics": [
+    {
+      "severity": "error",
+      "summary": "Variables not allowed",
+      "detail": "Variables may not be used here.",
+      "range": {
+        "filename": "testdata/validate-invalid/interpolation/main.tf",
+        "start": {
+          "line": 6,
+          "column": 16,
+          "byte": 122
+        },
+        "end": {
+          "line": 6,
+          "column": 19,
+          "byte": 125
+        }
+      },
+      "snippet": {
+        "context": "variable \"vairable_with_interpolation\"",
+        "code": "  default = \"${var.otherresourcename}\"",
+        "start_line": 6,
+        "highlight_start_offset": 15,
+        "highlight_end_offset": 18,
+        "values": []
+      }
+    },
+    {
+      "severity": "error",
+      "summary": "Invalid expression",
+      "detail": "A single static variable reference is required: only attribute access and indexing with constant keys. No calculations, function calls, template expressions, etc are allowed here.",
+      "range": {
+        "filename": "testdata/validate-invalid/interpolation/main.tf",
+        "start": {
+          "line": 10,
+          "column": 17,
+          "byte": 197
+        },
+        "end": {
+          "line": 10,
+          "column": 44,
+          "byte": 224
+        }
+      },
+      "snippet": {
+        "context": "resource \"aws_instance\" \"web\"",
+        "code": "  depends_on = [\"${var.otherresourcename}}\"]",
+        "start_line": 10,
+        "highlight_start_offset": 16,
+        "highlight_end_offset": 43,
+        "values": []
+      }
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/main.tf b/v1.5.7/internal/command/testdata/validate-invalid/main.tf
new file mode 100644
index 0000000..b1d6334
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/main.tf
@@ -0,0 +1,8 @@
+resorce "test_instance" "foo" { # Intentional typo to test error reporting
+    ami = "bar"
+
+    network_interface {
+      device_index = 0
+      description = "Main network interface"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/missing_defined_var/main.tf b/v1.5.7/internal/command/testdata/validate-invalid/missing_defined_var/main.tf
new file mode 100644
index 0000000..b3e1221
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/missing_defined_var/main.tf
@@ -0,0 +1,10 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+
+    network_interface {
+      device_index = 0
+      description = "Main network interface ${var.name}"
+    }
+}
+
+variable "name" {}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/missing_defined_var/output.json b/v1.5.7/internal/command/testdata/validate-invalid/missing_defined_var/output.json
new file mode 100644
index 0000000..40258a9
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/missing_defined_var/output.json
@@ -0,0 +1,7 @@
+{
+  "format_version": "1.0",
+  "valid": true,
+  "error_count": 0,
+  "warning_count": 0,
+  "diagnostics": []
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/missing_quote/main.tf b/v1.5.7/internal/command/testdata/validate-invalid/missing_quote/main.tf
new file mode 100644
index 0000000..c8e0785
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/missing_quote/main.tf
@@ -0,0 +1,9 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+
+    network_interface {
+      device_index = 0
+      name = test
+      description = "Main network interface"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/missing_quote/output.json b/v1.5.7/internal/command/testdata/validate-invalid/missing_quote/output.json
new file mode 100644
index 0000000..87aeca8
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/missing_quote/output.json
@@ -0,0 +1,34 @@
+{
+  "format_version": "1.0",
+  "valid": false,
+  "error_count": 1,
+  "warning_count": 0,
+  "diagnostics": [
+    {
+      "severity": "error",
+      "summary": "Invalid reference",
+      "detail": "A reference to a resource type must be followed by at least one attribute access, specifying the resource name.",
+      "range": {
+        "filename": "testdata/validate-invalid/missing_quote/main.tf",
+        "start": {
+          "line": 6,
+          "column": 14,
+          "byte": 110
+        },
+        "end": {
+          "line": 6,
+          "column": 18,
+          "byte": 114
+        }
+      },
+      "snippet": {
+        "context": "resource \"test_instance\" \"foo\"",
+        "code": "      name = test",
+        "start_line": 6,
+        "highlight_start_offset": 13,
+        "highlight_end_offset": 17,
+        "values": []
+      }
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/missing_var/main.tf b/v1.5.7/internal/command/testdata/validate-invalid/missing_var/main.tf
new file mode 100644
index 0000000..37a7755
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/missing_var/main.tf
@@ -0,0 +1,8 @@
+resource "test_instance" "foo" {
+    ami = "bar"
+
+    network_interface {
+      device_index = 0
+      description = var.description
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/missing_var/output.json b/v1.5.7/internal/command/testdata/validate-invalid/missing_var/output.json
new file mode 100644
index 0000000..6f0b9d5
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/missing_var/output.json
@@ -0,0 +1,34 @@
+{
+  "format_version": "1.0",
+  "valid": false,
+  "error_count": 1,
+  "warning_count": 0,
+  "diagnostics": [
+    {
+      "severity": "error",
+      "summary": "Reference to undeclared input variable",
+      "detail": "An input variable with the name \"description\" has not been declared. This variable can be declared with a variable \"description\" {} block.",
+      "range": {
+        "filename": "testdata/validate-invalid/missing_var/main.tf",
+        "start": {
+          "line": 6,
+          "column": 21,
+          "byte": 117
+        },
+        "end": {
+          "line": 6,
+          "column": 36,
+          "byte": 132
+        }
+      },
+      "snippet": {
+        "context": "resource \"test_instance\" \"foo\"",
+        "code": "      description = var.description",
+        "start_line": 6,
+        "highlight_start_offset": 20,
+        "highlight_end_offset": 35,
+        "values": []
+      }
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/multiple_modules/main.tf b/v1.5.7/internal/command/testdata/validate-invalid/multiple_modules/main.tf
new file mode 100644
index 0000000..28b339e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/multiple_modules/main.tf
@@ -0,0 +1,7 @@
+module "multi_module" {
+  source = "./foo"
+}
+
+module "multi_module" {
+  source = "./foo"
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/multiple_modules/output.json b/v1.5.7/internal/command/testdata/validate-invalid/multiple_modules/output.json
new file mode 100644
index 0000000..1aeaf92
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/multiple_modules/output.json
@@ -0,0 +1,34 @@
+{
+  "format_version": "1.0",
+  "valid": false,
+  "error_count": 1,
+  "warning_count": 0,
+  "diagnostics": [
+    {
+      "severity": "error",
+      "summary": "Duplicate module call",
+      "detail": "A module call named \"multi_module\" was already defined at testdata/validate-invalid/multiple_modules/main.tf:1,1-22. Module calls must have unique names within a module.",
+      "range": {
+        "filename": "testdata/validate-invalid/multiple_modules/main.tf",
+        "start": {
+          "line": 5,
+          "column": 1,
+          "byte": 46
+        },
+        "end": {
+          "line": 5,
+          "column": 22,
+          "byte": 67
+        }
+      },
+      "snippet": {
+        "context": null,
+        "code": "module \"multi_module\" {",
+        "start_line": 5,
+        "highlight_start_offset": 0,
+        "highlight_end_offset": 21,
+        "values": []
+      }
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/multiple_providers/main.tf b/v1.5.7/internal/command/testdata/validate-invalid/multiple_providers/main.tf
new file mode 100644
index 0000000..e1df9c9
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/multiple_providers/main.tf
@@ -0,0 +1,11 @@
+provider "aws" {
+  access_key = "123"
+  secret_key = "233"
+  region = "us-east-1"
+}
+
+provider "aws" {
+  access_key = "123"
+  secret_key = "233"
+  region = "us-east-1"
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/multiple_providers/output.json b/v1.5.7/internal/command/testdata/validate-invalid/multiple_providers/output.json
new file mode 100644
index 0000000..309cf0e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/multiple_providers/output.json
@@ -0,0 +1,34 @@
+{
+  "format_version": "1.0",
+  "valid": false,
+  "error_count": 1,
+  "warning_count": 0,
+  "diagnostics": [
+    {
+      "severity": "error",
+      "summary": "Duplicate provider configuration",
+      "detail": "A default (non-aliased) provider configuration for \"aws\" was already given at testdata/validate-invalid/multiple_providers/main.tf:1,1-15. If multiple configurations are required, set the \"alias\" argument for alternative configurations.",
+      "range": {
+        "filename": "testdata/validate-invalid/multiple_providers/main.tf",
+        "start": {
+          "line": 7,
+          "column": 1,
+          "byte": 85
+        },
+        "end": {
+          "line": 7,
+          "column": 15,
+          "byte": 99
+        }
+      },
+      "snippet": {
+        "context": null,
+        "code": "provider \"aws\" {",
+        "start_line": 7,
+        "highlight_start_offset": 0,
+        "highlight_end_offset": 14,
+        "values": []
+      }
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/multiple_resources/main.tf b/v1.5.7/internal/command/testdata/validate-invalid/multiple_resources/main.tf
new file mode 100644
index 0000000..7866b48
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/multiple_resources/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "web" {
+}
+
+resource "aws_instance" "web" {
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/multiple_resources/output.json b/v1.5.7/internal/command/testdata/validate-invalid/multiple_resources/output.json
new file mode 100644
index 0000000..ded584e
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/multiple_resources/output.json
@@ -0,0 +1,34 @@
+{
+  "format_version": "1.0",
+  "valid": false,
+  "error_count": 1,
+  "warning_count": 0,
+  "diagnostics": [
+    {
+      "severity": "error",
+      "summary": "Duplicate resource \"aws_instance\" configuration",
+      "detail": "A aws_instance resource named \"web\" was already declared at testdata/validate-invalid/multiple_resources/main.tf:1,1-30. Resource names must be unique per type in each module.",
+      "range": {
+        "filename": "testdata/validate-invalid/multiple_resources/main.tf",
+        "start": {
+          "line": 4,
+          "column": 1,
+          "byte": 35
+        },
+        "end": {
+          "line": 4,
+          "column": 30,
+          "byte": 64
+        }
+      },
+      "snippet": {
+        "context": null,
+        "code": "resource \"aws_instance\" \"web\" {",
+        "start_line": 4,
+        "highlight_start_offset": 0,
+        "highlight_end_offset": 29,
+        "values": []
+      }
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/output.json b/v1.5.7/internal/command/testdata/validate-invalid/output.json
new file mode 100644
index 0000000..7325485
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/output.json
@@ -0,0 +1,34 @@
+{
+  "format_version": "1.0",
+  "valid": false,
+  "error_count": 1,
+  "warning_count": 0,
+  "diagnostics": [
+    {
+      "severity": "error",
+      "summary": "Unsupported block type",
+      "detail": "Blocks of type \"resorce\" are not expected here. Did you mean \"resource\"?",
+      "range": {
+        "filename": "testdata/validate-invalid/main.tf",
+        "start": {
+          "line": 1,
+          "column": 1,
+          "byte": 0
+        },
+        "end": {
+          "line": 1,
+          "column": 8,
+          "byte": 7
+        }
+      },
+      "snippet": {
+        "context": null,
+        "code": "resorce \"test_instance\" \"foo\" { # Intentional typo to test error reporting",
+        "start_line": 1,
+        "highlight_start_offset": 0,
+        "highlight_end_offset": 7,
+        "values": []
+      }
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/outputs/main.tf b/v1.5.7/internal/command/testdata/validate-invalid/outputs/main.tf
new file mode 100644
index 0000000..fa35d2a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/outputs/main.tf
@@ -0,0 +1,3 @@
+output "myvalue" {
+  values = "Some value"
+}
diff --git a/v1.5.7/internal/command/testdata/validate-invalid/outputs/output.json b/v1.5.7/internal/command/testdata/validate-invalid/outputs/output.json
new file mode 100644
index 0000000..f774b45
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-invalid/outputs/output.json
@@ -0,0 +1,60 @@
+{
+  "format_version": "1.0",
+  "valid": false,
+  "error_count": 2,
+  "warning_count": 0,
+  "diagnostics": [
+    {
+      "severity": "error",
+      "summary": "Missing required argument",
+      "detail": "The argument \"value\" is required, but no definition was found.",
+      "range": {
+        "filename": "testdata/validate-invalid/outputs/main.tf",
+        "start": {
+          "line": 1,
+          "column": 18,
+          "byte": 17
+        },
+        "end": {
+          "line": 1,
+          "column": 19,
+          "byte": 18
+        }
+      },
+      "snippet": {
+        "context": "output \"myvalue\"",
+        "code": "output \"myvalue\" {",
+        "start_line": 1,
+        "highlight_start_offset": 17,
+        "highlight_end_offset": 18,
+        "values": []
+      }
+    },
+    {
+      "severity": "error",
+      "summary": "Unsupported argument",
+      "detail": "An argument named \"values\" is not expected here. Did you mean \"value\"?",
+      "range": {
+        "filename": "testdata/validate-invalid/outputs/main.tf",
+        "start": {
+          "line": 2,
+          "column": 3,
+          "byte": 21
+        },
+        "end": {
+          "line": 2,
+          "column": 9,
+          "byte": 27
+        }
+      },
+      "snippet": {
+        "context": "output \"myvalue\"",
+        "code": "  values = \"Some value\"",
+        "start_line": 2,
+        "highlight_start_offset": 2,
+        "highlight_end_offset": 8,
+        "values": []
+      }
+    }
+  ]
+}
diff --git a/v1.5.7/internal/command/testdata/validate-valid/main.tf b/v1.5.7/internal/command/testdata/validate-valid/main.tf
new file mode 100644
index 0000000..2dcb1ec
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-valid/main.tf
@@ -0,0 +1,14 @@
+variable "var_with_escaped_interp" {
+  # This is here because in the past it failed. See Github #13001
+  default = "foo-$${bar.baz}"
+}
+
+resource "test_instance" "foo" {
+    ami = "bar"
+
+    # This is here because at some point it caused a test failure
+    network_interface {
+      device_index = 0
+      description = "Main network interface"
+    }
+}
diff --git a/v1.5.7/internal/command/testdata/validate-valid/output.json b/v1.5.7/internal/command/testdata/validate-valid/output.json
new file mode 100644
index 0000000..40258a9
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-valid/output.json
@@ -0,0 +1,7 @@
+{
+  "format_version": "1.0",
+  "valid": true,
+  "error_count": 0,
+  "warning_count": 0,
+  "diagnostics": []
+}
diff --git a/v1.5.7/internal/command/testdata/validate-valid/with-tfvars-file/main.tf b/v1.5.7/internal/command/testdata/validate-valid/with-tfvars-file/main.tf
new file mode 100644
index 0000000..b318fbf
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-valid/with-tfvars-file/main.tf
@@ -0,0 +1,4 @@
+variable "var_without_default" {
+  type = string
+}
+
diff --git a/v1.5.7/internal/command/testdata/validate-valid/with-tfvars-file/terraform.tfvars b/v1.5.7/internal/command/testdata/validate-valid/with-tfvars-file/terraform.tfvars
new file mode 100644
index 0000000..5b6bd87
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/validate-valid/with-tfvars-file/terraform.tfvars
@@ -0,0 +1 @@
+var_without_default = "foo"
diff --git a/v1.5.7/internal/command/testdata/variables/main.tf b/v1.5.7/internal/command/testdata/variables/main.tf
new file mode 100644
index 0000000..84a3f9a
--- /dev/null
+++ b/v1.5.7/internal/command/testdata/variables/main.tf
@@ -0,0 +1,16 @@
+variable "foo" {
+    default = "bar"
+}
+
+variable "snack" {
+    default = "popcorn"
+}
+
+variable "secret_snack" {
+    default   = "seaweed snacks"
+    sensitive = true
+}
+
+locals {
+    snack_bar = [var.snack, var.secret_snack]
+}
diff --git a/v1.5.7/internal/command/ui_input.go b/v1.5.7/internal/command/ui_input.go
new file mode 100644
index 0000000..094f347
--- /dev/null
+++ b/v1.5.7/internal/command/ui_input.go
@@ -0,0 +1,194 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bufio"
+	"bytes"
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"os/signal"
+	"strings"
+	"sync"
+	"sync/atomic"
+	"unicode"
+
+	"github.com/bgentry/speakeasy"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/mattn/go-isatty"
+	"github.com/mitchellh/colorstring"
+)
+
+var defaultInputReader io.Reader
+var defaultInputWriter io.Writer
+var testInputResponse []string
+var testInputResponseMap map[string]string
+
+// UIInput is an implementation of terraform.UIInput that asks the CLI
+// for input stdin.
+type UIInput struct {
+	// Colorize will color the output.
+	Colorize *colorstring.Colorize
+
+	// Reader and Writer for IO. If these aren't set, they will default to
+	// Stdin and Stdout respectively.
+	Reader io.Reader
+	Writer io.Writer
+
+	listening int32
+	result    chan string
+	err       chan string
+
+	interrupted bool
+	l           sync.Mutex
+	once        sync.Once
+}
+
+func (i *UIInput) Input(ctx context.Context, opts *terraform.InputOpts) (string, error) {
+	i.once.Do(i.init)
+
+	r := i.Reader
+	w := i.Writer
+	if r == nil {
+		r = defaultInputReader
+	}
+	if w == nil {
+		w = defaultInputWriter
+	}
+	if r == nil {
+		r = os.Stdin
+	}
+	if w == nil {
+		w = os.Stdout
+	}
+
+	// Make sure we only ask for input once at a time. Terraform
+	// should enforce this, but it doesn't hurt to verify.
+	i.l.Lock()
+	defer i.l.Unlock()
+
+	// If we're interrupted, then don't ask for input
+	if i.interrupted {
+		return "", errors.New("interrupted")
+	}
+
+	// If we have test results, return those. testInputResponse is the
+	// "old" way of doing it and we should remove that.
+	if testInputResponse != nil {
+		v := testInputResponse[0]
+		testInputResponse = testInputResponse[1:]
+		return v, nil
+	}
+
+	// testInputResponseMap is the new way for test responses, based on
+	// the query ID.
+	if testInputResponseMap != nil {
+		v, ok := testInputResponseMap[opts.Id]
+		if !ok {
+			return "", fmt.Errorf("unexpected input request in test: %s", opts.Id)
+		}
+
+		delete(testInputResponseMap, opts.Id)
+		return v, nil
+	}
+
+	log.Printf("[DEBUG] command: asking for input: %q", opts.Query)
+
+	// Listen for interrupts so we can cancel the input ask
+	sigCh := make(chan os.Signal, 1)
+	signal.Notify(sigCh, os.Interrupt)
+	defer signal.Stop(sigCh)
+
+	// Build the output format for asking
+	var buf bytes.Buffer
+	buf.WriteString("[reset]")
+	buf.WriteString(fmt.Sprintf("[bold]%s[reset]\n", opts.Query))
+	if opts.Description != "" {
+		s := bufio.NewScanner(strings.NewReader(opts.Description))
+		for s.Scan() {
+			buf.WriteString(fmt.Sprintf("  %s\n", s.Text()))
+		}
+		buf.WriteString("\n")
+	}
+	if opts.Default != "" {
+		buf.WriteString("  [bold]Default:[reset] ")
+		buf.WriteString(opts.Default)
+		buf.WriteString("\n")
+	}
+	buf.WriteString("  [bold]Enter a value:[reset] ")
+
+	// Ask the user for their input
+	if _, err := fmt.Fprint(w, i.Colorize.Color(buf.String())); err != nil {
+		return "", err
+	}
+
+	// Listen for the input in a goroutine. This will allow us to
+	// interrupt this if we are interrupted (SIGINT).
+	go func() {
+		if !atomic.CompareAndSwapInt32(&i.listening, 0, 1) {
+			return // We are already listening for input.
+		}
+		defer atomic.CompareAndSwapInt32(&i.listening, 1, 0)
+
+		var line string
+		var err error
+		if opts.Secret && isatty.IsTerminal(os.Stdin.Fd()) {
+			line, err = speakeasy.Ask("")
+		} else {
+			buf := bufio.NewReader(r)
+			line, err = buf.ReadString('\n')
+		}
+		if err != nil {
+			log.Printf("[ERR] UIInput scan err: %s", err)
+			i.err <- string(err.Error())
+		} else {
+			i.result <- strings.TrimRightFunc(line, unicode.IsSpace)
+		}
+	}()
+
+	select {
+	case err := <-i.err:
+		return "", errors.New(err)
+
+	case line := <-i.result:
+		fmt.Fprint(w, "\n")
+
+		if line == "" {
+			line = opts.Default
+		}
+
+		return line, nil
+	case <-ctx.Done():
+		// Print a newline so that any further output starts properly
+		// on a new line.
+		fmt.Fprintln(w)
+
+		return "", ctx.Err()
+	case <-sigCh:
+		// Print a newline so that any further output starts properly
+		// on a new line.
+		fmt.Fprintln(w)
+
+		// Mark that we were interrupted so future Ask calls fail.
+		i.interrupted = true
+
+		return "", errors.New("interrupted")
+	}
+}
+
+func (i *UIInput) init() {
+	i.result = make(chan string)
+	i.err = make(chan string)
+
+	if i.Colorize == nil {
+		i.Colorize = &colorstring.Colorize{
+			Colors:  colorstring.DefaultColors,
+			Disable: true,
+		}
+	}
+}
diff --git a/v1.5.7/internal/command/ui_input_test.go b/v1.5.7/internal/command/ui_input_test.go
new file mode 100644
index 0000000..9172de8
--- /dev/null
+++ b/v1.5.7/internal/command/ui_input_test.go
@@ -0,0 +1,122 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"io"
+	"sync/atomic"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+func TestUIInput_impl(t *testing.T) {
+	var _ terraform.UIInput = new(UIInput)
+}
+
+func TestUIInputInput(t *testing.T) {
+	i := &UIInput{
+		Reader: bytes.NewBufferString("foo\n"),
+		Writer: bytes.NewBuffer(nil),
+	}
+
+	v, err := i.Input(context.Background(), &terraform.InputOpts{})
+	if err != nil {
+		t.Fatalf("unexpected error: %v", err)
+	}
+
+	if v != "foo" {
+		t.Fatalf("unexpected input: %s", v)
+	}
+}
+
+func TestUIInputInput_canceled(t *testing.T) {
+	r, w := io.Pipe()
+	i := &UIInput{
+		Reader: r,
+		Writer: bytes.NewBuffer(nil),
+	}
+
+	// Make a context that can be canceled.
+	ctx, cancel := context.WithCancel(context.Background())
+
+	go func() {
+		// Cancel the context after 2 seconds.
+		time.Sleep(2 * time.Second)
+		cancel()
+	}()
+
+	// Get input until the context is canceled.
+	v, err := i.Input(ctx, &terraform.InputOpts{})
+	if err != context.Canceled {
+		t.Fatalf("expected a context.Canceled error, got: %v", err)
+	}
+
+	// As the context was canceled v should be empty.
+	if v != "" {
+		t.Fatalf("unexpected input: %s", v)
+	}
+
+	// As the context was canceled we should still be listening.
+	listening := atomic.LoadInt32(&i.listening)
+	if listening != 1 {
+		t.Fatalf("expected listening to be 1, got: %d", listening)
+	}
+
+	go func() {
+		// Fake input is given after 1 second.
+		time.Sleep(time.Second)
+		fmt.Fprint(w, "foo\n")
+		w.Close()
+	}()
+
+	v, err = i.Input(context.Background(), &terraform.InputOpts{})
+	if err != nil {
+		t.Fatalf("unexpected error: %v", err)
+	}
+
+	if v != "foo" {
+		t.Fatalf("unexpected input: %s", v)
+	}
+}
+
+func TestUIInputInput_spaces(t *testing.T) {
+	i := &UIInput{
+		Reader: bytes.NewBufferString("foo bar\n"),
+		Writer: bytes.NewBuffer(nil),
+	}
+
+	v, err := i.Input(context.Background(), &terraform.InputOpts{})
+	if err != nil {
+		t.Fatalf("unexpected error: %v", err)
+	}
+
+	if v != "foo bar" {
+		t.Fatalf("unexpected input: %s", v)
+	}
+}
+
+func TestUIInputInput_Error(t *testing.T) {
+	i := &UIInput{
+		Reader: bytes.NewBuffer(nil),
+		Writer: bytes.NewBuffer(nil),
+	}
+
+	v, err := i.Input(context.Background(), &terraform.InputOpts{})
+	if err == nil {
+		t.Fatalf("Error is not 'nil'")
+	}
+
+	if err.Error() != "EOF" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+
+	if v != "" {
+		t.Fatalf("input must be empty")
+	}
+}
diff --git a/v1.5.7/internal/command/unlock.go b/v1.5.7/internal/command/unlock.go
new file mode 100644
index 0000000..49c8071
--- /dev/null
+++ b/v1.5.7/internal/command/unlock.go
@@ -0,0 +1,147 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"context"
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/mitchellh/cli"
+)
+
+// UnlockCommand is a cli.Command implementation that manually unlocks
+// the state.
+type UnlockCommand struct {
+	Meta
+}
+
+func (c *UnlockCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	var force bool
+	cmdFlags := c.Meta.defaultFlagSet("force-unlock")
+	cmdFlags.BoolVar(&force, "force", false, "force")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	args = cmdFlags.Args()
+	if len(args) != 1 {
+		c.Ui.Error("Expected a single argument: LOCK_ID")
+		return cli.RunResultHelp
+	}
+
+	lockID := args[0]
+	args = args[1:]
+
+	// assume everything is initialized. The user can manually init if this is
+	// required.
+	configPath, err := ModulePath(args)
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	backendConfig, backendDiags := c.loadBackendConfig(configPath)
+	diags = diags.Append(backendDiags)
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(&BackendOpts{
+		Config: backendConfig,
+	})
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	env, err := c.Workspace()
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err))
+		return 1
+	}
+	stateMgr, err := b.StateMgr(env)
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
+		return 1
+	}
+
+	_, isLocal := stateMgr.(*statemgr.Filesystem)
+
+	if !force {
+		// Forcing this doesn't do anything, but doesn't break anything either,
+		// and allows us to run the basic command test too.
+		if isLocal {
+			c.Ui.Error("Local state cannot be unlocked by another process")
+			return 1
+		}
+
+		desc := "Terraform will remove the lock on the remote state.\n" +
+			"This will allow local Terraform commands to modify this state, even though it\n" +
+			"may still be in use. Only 'yes' will be accepted to confirm."
+
+		v, err := c.UIInput().Input(context.Background(), &terraform.InputOpts{
+			Id:          "force-unlock",
+			Query:       "Do you really want to force-unlock?",
+			Description: desc,
+		})
+		if err != nil {
+			c.Ui.Error(fmt.Sprintf("Error asking for confirmation: %s", err))
+			return 1
+		}
+		if v != "yes" {
+			c.Ui.Output("force-unlock cancelled.")
+			return 1
+		}
+	}
+
+	if err := stateMgr.Unlock(lockID); err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to unlock state: %s", err))
+		return 1
+	}
+
+	c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputUnlockSuccess)))
+	return 0
+}
+
+func (c *UnlockCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] force-unlock LOCK_ID
+
+  Manually unlock the state for the defined configuration.
+
+  This will not modify your infrastructure. This command removes the lock on the
+  state for the current workspace. The behavior of this lock is dependent
+  on the backend being used. Local state files cannot be unlocked by another
+  process.
+
+Options:
+
+  -force                 Don't ask for input for unlock confirmation.
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *UnlockCommand) Synopsis() string {
+	return "Release a stuck lock on the current workspace"
+}
+
+const outputUnlockSuccess = `
+[reset][bold][green]Terraform state has been successfully unlocked![reset][green]
+
+The state has been unlocked, and Terraform commands should now be able to
+obtain a new lock on the remote state.
+`
diff --git a/v1.5.7/internal/command/unlock_test.go b/v1.5.7/internal/command/unlock_test.go
new file mode 100644
index 0000000..7123053
--- /dev/null
+++ b/v1.5.7/internal/command/unlock_test.go
@@ -0,0 +1,121 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"os"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/backend/remote-state/inmem"
+	"github.com/mitchellh/cli"
+
+	legacy "github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+// Since we can't unlock a local state file, just test that calling unlock
+// doesn't fail.
+func TestUnlock(t *testing.T) {
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	// Write the legacy state
+	statePath := DefaultStateFilename
+	{
+		f, err := os.Create(statePath)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		err = legacy.WriteState(legacy.NewState(), f)
+		f.Close()
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	p := testProvider()
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &UnlockCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			Ui:               ui,
+			View:             view,
+		},
+	}
+
+	args := []string{
+		"-force",
+		"LOCK_ID",
+	}
+
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad: %d\n%s\n%s", code, ui.OutputWriter.String(), ui.ErrorWriter.String())
+	}
+
+	// make sure we don't crash with arguments in the wrong order
+	args = []string{
+		"LOCK_ID",
+		"-force",
+	}
+
+	if code := c.Run(args); code != cli.RunResultHelp {
+		t.Fatalf("bad: %d\n%s\n%s", code, ui.OutputWriter.String(), ui.ErrorWriter.String())
+	}
+}
+
+// Newly configured backend
+func TestUnlock_inmemBackend(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("backend-inmem-locked"), td)
+	defer testChdir(t, td)()
+	defer inmem.Reset()
+
+	// init backend
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	ci := &InitCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+	if code := ci.Run(nil); code != 0 {
+		t.Fatalf("bad: %d\n%s", code, ui.ErrorWriter)
+	}
+
+	ui = new(cli.MockUi)
+	c := &UnlockCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	// run with the incorrect lock ID
+	args := []string{
+		"-force",
+		"LOCK_ID",
+	}
+
+	if code := c.Run(args); code == 0 {
+		t.Fatalf("bad: %d\n%s\n%s", code, ui.OutputWriter.String(), ui.ErrorWriter.String())
+	}
+
+	ui = new(cli.MockUi)
+	c = &UnlockCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	// lockID set in the test fixture
+	args[1] = "2b6a6738-5dd5-50d6-c0ae-f6352977666b"
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n%s\n%s", code, ui.OutputWriter.String(), ui.ErrorWriter.String())
+	}
+
+}
diff --git a/v1.5.7/internal/command/untaint.go b/v1.5.7/internal/command/untaint.go
new file mode 100644
index 0000000..36f0650
--- /dev/null
+++ b/v1.5.7/internal/command/untaint.go
@@ -0,0 +1,244 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// UntaintCommand is a cli.Command implementation that manually untaints
+// a resource, marking it as primary and ready for service.
+type UntaintCommand struct {
+	Meta
+}
+
+func (c *UntaintCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	var allowMissing bool
+	cmdFlags := c.Meta.ignoreRemoteVersionFlagSet("untaint")
+	cmdFlags.BoolVar(&allowMissing, "allow-missing", false, "allow missing")
+	cmdFlags.StringVar(&c.Meta.backupPath, "backup", "", "path")
+	cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
+	cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
+	cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path")
+	cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	// Require the one argument for the resource to untaint
+	args = cmdFlags.Args()
+	if len(args) != 1 {
+		c.Ui.Error("The untaint command expects exactly one argument.")
+		cmdFlags.Usage()
+		return 1
+	}
+
+	addr, addrDiags := addrs.ParseAbsResourceInstanceStr(args[0])
+	diags = diags.Append(addrDiags)
+	if addrDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(nil)
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Determine the workspace name
+	workspace, err := c.Workspace()
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err))
+		return 1
+	}
+
+	// Check remote Terraform version is compatible
+	remoteVersionDiags := c.remoteVersionCheck(b, workspace)
+	diags = diags.Append(remoteVersionDiags)
+	c.showDiagnostics(diags)
+	if diags.HasErrors() {
+		return 1
+	}
+
+	// Get the state
+	stateMgr, err := b.StateMgr(workspace)
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
+		return 1
+	}
+
+	if c.stateLock {
+		stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
+		if diags := stateLocker.Lock(stateMgr, "untaint"); diags.HasErrors() {
+			c.showDiagnostics(diags)
+			return 1
+		}
+		defer func() {
+			if diags := stateLocker.Unlock(); diags.HasErrors() {
+				c.showDiagnostics(diags)
+			}
+		}()
+	}
+
+	if err := stateMgr.RefreshState(); err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
+		return 1
+	}
+
+	// Get the actual state structure
+	state := stateMgr.State()
+	if state.Empty() {
+		if allowMissing {
+			return c.allowMissingExit(addr)
+		}
+
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"No such resource instance",
+			"The state currently contains no resource instances whatsoever. This may occur if the configuration has never been applied or if it has recently been destroyed.",
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	ss := state.SyncWrapper()
+
+	// Get the resource and instance we're going to taint
+	rs := ss.Resource(addr.ContainingResource())
+	is := ss.ResourceInstance(addr)
+	if is == nil {
+		if allowMissing {
+			return c.allowMissingExit(addr)
+		}
+
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"No such resource instance",
+			fmt.Sprintf("There is no resource instance in the state with the address %s. If the resource configuration has just been added, you must run \"terraform apply\" once to create the corresponding instance(s) before they can be tainted.", addr),
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	obj := is.Current
+	if obj == nil {
+		if len(is.Deposed) != 0 {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"No such resource instance",
+				fmt.Sprintf("Resource instance %s is currently part-way through a create_before_destroy replacement action. Run \"terraform apply\" to complete its replacement before tainting it.", addr),
+			))
+		} else {
+			// Don't know why we're here, but we'll produce a generic error message anyway.
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"No such resource instance",
+				fmt.Sprintf("Resource instance %s does not currently have a remote object associated with it, so it cannot be tainted.", addr),
+			))
+		}
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	if obj.Status != states.ObjectTainted {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Resource instance is not tainted",
+			fmt.Sprintf("Resource instance %s is not currently tainted, and so it cannot be untainted.", addr),
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Get schemas, if possible, before writing state
+	var schemas *terraform.Schemas
+	if isCloudMode(b) {
+		var schemaDiags tfdiags.Diagnostics
+		schemas, schemaDiags = c.MaybeGetSchemas(state, nil)
+		diags = diags.Append(schemaDiags)
+	}
+
+	obj.Status = states.ObjectReady
+	ss.SetResourceInstanceCurrent(addr, obj, rs.ProviderConfig)
+
+	if err := stateMgr.WriteState(state); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
+		return 1
+	}
+	if err := stateMgr.PersistState(schemas); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
+		return 1
+	}
+
+	c.showDiagnostics(diags)
+	c.Ui.Output(fmt.Sprintf("Resource instance %s has been successfully untainted.", addr))
+	return 0
+}
+
+func (c *UntaintCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] untaint [options] name
+
+  Terraform uses the term "tainted" to describe a resource instance
+  which may not be fully functional, either because its creation
+  partially failed or because you've manually marked it as such using
+  the "terraform taint" command.
+
+  This command removes that state from a resource instance, causing
+  Terraform to see it as fully-functional and not in need of
+  replacement.
+
+  This will not modify your infrastructure directly. It only avoids
+  Terraform planning to replace a tainted instance in a future operation.
+
+Options:
+
+  -allow-missing          If specified, the command will succeed (exit code 0)
+                          even if the resource is missing.
+
+  -lock=false             Don't hold a state lock during the operation. This is
+                          dangerous if others might concurrently run commands
+                          against the same workspace.
+
+  -lock-timeout=0s        Duration to retry a state lock.
+
+  -ignore-remote-version  A rare option used for the remote backend only. See
+                          the remote backend documentation for more information.
+
+  -state, state-out, and -backup are legacy options supported for the local
+  backend only. For more information, see the local backend's documentation.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *UntaintCommand) Synopsis() string {
+	return "Remove the 'tainted' state from a resource instance"
+}
+
+func (c *UntaintCommand) allowMissingExit(name addrs.AbsResourceInstance) int {
+	c.showDiagnostics(tfdiags.Sourceless(
+		tfdiags.Warning,
+		"No such resource instance",
+		fmt.Sprintf("Resource instance %s was not found, but this is not an error because -allow-missing was set.", name),
+	))
+	return 0
+}
diff --git a/v1.5.7/internal/command/untaint_test.go b/v1.5.7/internal/command/untaint_test.go
new file mode 100644
index 0000000..25d3893
--- /dev/null
+++ b/v1.5.7/internal/command/untaint_test.go
@@ -0,0 +1,535 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"os"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/mitchellh/cli"
+)
+
+func TestUntaint(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectTainted,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &UntaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	expected := strings.TrimSpace(`
+test_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+	`)
+	testStateOutput(t, statePath, expected)
+}
+
+func TestUntaint_lockedState(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectTainted,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+	unlock, err := testLockState(t, testDataDir, statePath)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer unlock()
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &UntaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code == 0 {
+		t.Fatal("expected error")
+	}
+
+	output := ui.ErrorWriter.String()
+	if !strings.Contains(output, "lock") {
+		t.Fatal("command output does not look like a lock error:", output)
+	}
+}
+
+func TestUntaint_backup(t *testing.T) {
+	// Get a temp cwd
+	testCwd(t)
+
+	// Write the temp state
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectTainted,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	testStateFileDefault(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &UntaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Backup is still tainted
+	testStateOutput(t, DefaultStateFilename+".backup", strings.TrimSpace(`
+test_instance.foo: (tainted)
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+	`))
+
+	// State is untainted
+	testStateOutput(t, DefaultStateFilename, strings.TrimSpace(`
+test_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+	`))
+}
+
+func TestUntaint_backupDisable(t *testing.T) {
+	// Get a temp cwd
+	testCwd(t)
+
+	// Write the temp state
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectTainted,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	testStateFileDefault(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &UntaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-backup", "-",
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	if _, err := os.Stat(DefaultStateFilename + ".backup"); err == nil {
+		t.Fatal("backup path should not exist")
+	}
+
+	testStateOutput(t, DefaultStateFilename, strings.TrimSpace(`
+test_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+	`))
+}
+
+func TestUntaint_badState(t *testing.T) {
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &UntaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-state", "i-should-not-exist-ever",
+		"foo",
+	}
+	if code := c.Run(args); code != 1 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+}
+
+func TestUntaint_defaultState(t *testing.T) {
+	// Get a temp cwd
+	testCwd(t)
+
+	// Write the temp state
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectTainted,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	testStateFileDefault(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &UntaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	testStateOutput(t, DefaultStateFilename, strings.TrimSpace(`
+test_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+	`))
+}
+
+func TestUntaint_defaultWorkspaceState(t *testing.T) {
+	// Get a temp cwd
+	testCwd(t)
+
+	// Write the temp state
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectTainted,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	testWorkspace := "development"
+	path := testStateFileWorkspaceDefault(t, testWorkspace, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	meta := Meta{Ui: ui, View: view}
+	meta.SetWorkspace(testWorkspace)
+	c := &UntaintCommand{
+		Meta: meta,
+	}
+
+	args := []string{
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	testStateOutput(t, path, strings.TrimSpace(`
+test_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+	`))
+}
+
+func TestUntaint_missing(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectTainted,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &UntaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"test_instance.bar",
+	}
+	if code := c.Run(args); code == 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.OutputWriter.String())
+	}
+}
+
+func TestUntaint_missingAllow(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectTainted,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &UntaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-allow-missing",
+		"-state", statePath,
+		"test_instance.bar",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	// Check for the warning
+	actual := strings.TrimSpace(ui.ErrorWriter.String())
+	expected := strings.TrimSpace(`
+Warning: No such resource instance
+
+Resource instance test_instance.bar was not found, but this is not an error
+because -allow-missing was set.
+
+`)
+	if diff := cmp.Diff(expected, actual); diff != "" {
+		t.Fatalf("wrong output\n%s", diff)
+	}
+}
+
+func TestUntaint_stateOut(t *testing.T) {
+	// Get a temp cwd
+	testCwd(t)
+
+	// Write the temp state
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectTainted,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	testStateFileDefault(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &UntaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-state-out", "foo",
+		"test_instance.foo",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	testStateOutput(t, DefaultStateFilename, strings.TrimSpace(`
+test_instance.foo: (tainted)
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+	`))
+	testStateOutput(t, "foo", strings.TrimSpace(`
+test_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+	`))
+}
+
+func TestUntaint_module(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectTainted,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "blah",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey)),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectTainted,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	statePath := testStateFile(t, state)
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	c := &UntaintCommand{
+		Meta: Meta{
+			Ui:   ui,
+			View: view,
+		},
+	}
+
+	args := []string{
+		"-state", statePath,
+		"module.child.test_instance.blah",
+	}
+	if code := c.Run(args); code != 0 {
+		t.Fatalf("command exited with status code %d; want 0\n\n%s", code, ui.ErrorWriter.String())
+	}
+
+	testStateOutput(t, statePath, strings.TrimSpace(`
+test_instance.foo: (tainted)
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/test"]
+
+module.child:
+  test_instance.blah:
+    ID = bar
+    provider = provider["registry.terraform.io/hashicorp/test"]
+	`))
+}
diff --git a/v1.5.7/internal/command/validate.go b/v1.5.7/internal/command/validate.go
new file mode 100644
index 0000000..601d532
--- /dev/null
+++ b/v1.5.7/internal/command/validate.go
@@ -0,0 +1,133 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"path/filepath"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ValidateCommand is a Command implementation that validates the terraform files
+type ValidateCommand struct {
+	Meta
+}
+
+func (c *ValidateCommand) Run(rawArgs []string) int {
+	// Parse and apply global view arguments
+	common, rawArgs := arguments.ParseView(rawArgs)
+	c.View.Configure(common)
+
+	// Parse and validate flags
+	args, diags := arguments.ParseValidate(rawArgs)
+	if diags.HasErrors() {
+		c.View.Diagnostics(diags)
+		c.View.HelpPrompt("validate")
+		return 1
+	}
+
+	view := views.NewValidate(args.ViewType, c.View)
+
+	// After this point, we must only produce JSON output if JSON mode is
+	// enabled, so all errors should be accumulated into diags and we'll
+	// print out a suitable result at the end, depending on the format
+	// selection. All returns from this point on must be tail-calls into
+	// view.Results in order to produce the expected output.
+
+	dir, err := filepath.Abs(args.Path)
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("unable to locate module: %s", err))
+		return view.Results(diags)
+	}
+
+	// Check for user-supplied plugin path
+	if c.pluginPath, err = c.loadPluginPath(); err != nil {
+		diags = diags.Append(fmt.Errorf("error loading plugin path: %s", err))
+		return view.Results(diags)
+	}
+
+	validateDiags := c.validate(dir)
+	diags = diags.Append(validateDiags)
+
+	// Validating with dev overrides in effect means that the result might
+	// not be valid for a stable release, so we'll warn about that in case
+	// the user is trying to use "terraform validate" as a sort of pre-flight
+	// check before submitting a change.
+	diags = diags.Append(c.providerDevOverrideRuntimeWarnings())
+
+	return view.Results(diags)
+}
+
+func (c *ValidateCommand) validate(dir string) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	cfg, cfgDiags := c.loadConfig(dir)
+	diags = diags.Append(cfgDiags)
+
+	if diags.HasErrors() {
+		return diags
+	}
+
+	opts, err := c.contextOpts()
+	if err != nil {
+		diags = diags.Append(err)
+		return diags
+	}
+
+	tfCtx, ctxDiags := terraform.NewContext(opts)
+	diags = diags.Append(ctxDiags)
+	if ctxDiags.HasErrors() {
+		return diags
+	}
+
+	validateDiags := tfCtx.Validate(cfg)
+	diags = diags.Append(validateDiags)
+	return diags
+}
+
+func (c *ValidateCommand) Synopsis() string {
+	return "Check whether the configuration is valid"
+}
+
+func (c *ValidateCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] validate [options]
+
+  Validate the configuration files in a directory, referring only to the
+  configuration and not accessing any remote services such as remote state,
+  provider APIs, etc.
+
+  Validate runs checks that verify whether a configuration is syntactically
+  valid and internally consistent, regardless of any provided variables or
+  existing state. It is thus primarily useful for general verification of
+  reusable modules, including correctness of attribute names and value types.
+
+  It is safe to run this command automatically, for example as a post-save
+  check in a text editor or as a test step for a re-usable module in a CI
+  system.
+
+  Validation requires an initialized working directory with any referenced
+  plugins and modules installed. To initialize a working directory for
+  validation without accessing any configured remote backend, use:
+      terraform init -backend=false
+
+  To verify configuration in the context of a particular run (a particular
+  target workspace, input variable values, etc), use the 'terraform plan'
+  command instead, which includes an implied validation check.
+
+Options:
+
+  -json        Produce output in a machine-readable JSON format, suitable for
+               use in text editor integrations and other automated systems.
+               Always disables color.
+
+  -no-color    If specified, output won't contain any color.
+`
+	return strings.TrimSpace(helpText)
+}
diff --git a/v1.5.7/internal/command/validate_test.go b/v1.5.7/internal/command/validate_test.go
new file mode 100644
index 0000000..7da44bf
--- /dev/null
+++ b/v1.5.7/internal/command/validate_test.go
@@ -0,0 +1,281 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"os"
+	"path"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/terminal"
+)
+
+func setupTest(t *testing.T, fixturepath string, args ...string) (*terminal.TestOutput, int) {
+	view, done := testView(t)
+	p := testProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"ami": {Type: cty.String, Optional: true},
+					},
+					BlockTypes: map[string]*configschema.NestedBlock{
+						"network_interface": {
+							Nesting: configschema.NestingList,
+							Block: configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"device_index": {Type: cty.String, Optional: true},
+									"description":  {Type: cty.String, Optional: true},
+									"name":         {Type: cty.String, Optional: true},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	c := &ValidateCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(p),
+			View:             view,
+		},
+	}
+
+	args = append(args, "-no-color")
+	args = append(args, testFixturePath(fixturepath))
+
+	code := c.Run(args)
+	return done(t), code
+}
+
+func TestValidateCommand(t *testing.T) {
+	if output, code := setupTest(t, "validate-valid"); code != 0 {
+		t.Fatalf("unexpected non-successful exit code %d\n\n%s", code, output.Stderr())
+	}
+}
+
+func TestValidateCommandWithTfvarsFile(t *testing.T) {
+	// Create a temporary working directory that is empty because this test
+	// requires scanning the current working directory by validate command.
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("validate-valid/with-tfvars-file"), td)
+	defer testChdir(t, td)()
+
+	view, done := testView(t)
+	c := &ValidateCommand{
+		Meta: Meta{
+			testingOverrides: metaOverridesForProvider(testProvider()),
+			View:             view,
+		},
+	}
+
+	args := []string{}
+	code := c.Run(args)
+	output := done(t)
+	if code != 0 {
+		t.Fatalf("bad %d\n\n%s", code, output.Stderr())
+	}
+}
+
+func TestValidateFailingCommand(t *testing.T) {
+	if output, code := setupTest(t, "validate-invalid"); code != 1 {
+		t.Fatalf("Should have failed: %d\n\n%s", code, output.Stderr())
+	}
+}
+
+func TestValidateFailingCommandMissingQuote(t *testing.T) {
+	output, code := setupTest(t, "validate-invalid/missing_quote")
+
+	if code != 1 {
+		t.Fatalf("Should have failed: %d\n\n%s", code, output.Stderr())
+	}
+	wantError := "Error: Invalid reference"
+	if !strings.Contains(output.Stderr(), wantError) {
+		t.Fatalf("Missing error string %q\n\n'%s'", wantError, output.Stderr())
+	}
+}
+
+func TestValidateFailingCommandMissingVariable(t *testing.T) {
+	output, code := setupTest(t, "validate-invalid/missing_var")
+	if code != 1 {
+		t.Fatalf("Should have failed: %d\n\n%s", code, output.Stderr())
+	}
+	wantError := "Error: Reference to undeclared input variable"
+	if !strings.Contains(output.Stderr(), wantError) {
+		t.Fatalf("Missing error string %q\n\n'%s'", wantError, output.Stderr())
+	}
+}
+
+func TestSameProviderMutipleTimesShouldFail(t *testing.T) {
+	output, code := setupTest(t, "validate-invalid/multiple_providers")
+	if code != 1 {
+		t.Fatalf("Should have failed: %d\n\n%s", code, output.Stderr())
+	}
+	wantError := "Error: Duplicate provider configuration"
+	if !strings.Contains(output.Stderr(), wantError) {
+		t.Fatalf("Missing error string %q\n\n'%s'", wantError, output.Stderr())
+	}
+}
+
+func TestSameModuleMultipleTimesShouldFail(t *testing.T) {
+	output, code := setupTest(t, "validate-invalid/multiple_modules")
+	if code != 1 {
+		t.Fatalf("Should have failed: %d\n\n%s", code, output.Stderr())
+	}
+	wantError := "Error: Duplicate module call"
+	if !strings.Contains(output.Stderr(), wantError) {
+		t.Fatalf("Missing error string %q\n\n'%s'", wantError, output.Stderr())
+	}
+}
+
+func TestSameResourceMultipleTimesShouldFail(t *testing.T) {
+	output, code := setupTest(t, "validate-invalid/multiple_resources")
+	if code != 1 {
+		t.Fatalf("Should have failed: %d\n\n%s", code, output.Stderr())
+	}
+	wantError := `Error: Duplicate resource "aws_instance" configuration`
+	if !strings.Contains(output.Stderr(), wantError) {
+		t.Fatalf("Missing error string %q\n\n'%s'", wantError, output.Stderr())
+	}
+}
+
+func TestSameImportTargetMultipleTimesShouldFail(t *testing.T) {
+	output, code := setupTest(t, "validate-invalid/duplicate_import_targets")
+	if code != 1 {
+		t.Fatalf("Should have failed: %d\n\n%s", code, output.Stderr())
+	}
+	wantError := `Error: Duplicate import configuration for "aws_instance.web"`
+	if !strings.Contains(output.Stderr(), wantError) {
+		t.Fatalf("Missing error string %q\n\n'%s'", wantError, output.Stderr())
+	}
+}
+
+func TestOutputWithoutValueShouldFail(t *testing.T) {
+	output, code := setupTest(t, "validate-invalid/outputs")
+	if code != 1 {
+		t.Fatalf("Should have failed: %d\n\n%s", code, output.Stderr())
+	}
+	wantError := `The argument "value" is required, but no definition was found.`
+	if !strings.Contains(output.Stderr(), wantError) {
+		t.Fatalf("Missing error string %q\n\n'%s'", wantError, output.Stderr())
+	}
+	wantError = `An argument named "values" is not expected here. Did you mean "value"?`
+	if !strings.Contains(output.Stderr(), wantError) {
+		t.Fatalf("Missing error string %q\n\n'%s'", wantError, output.Stderr())
+	}
+}
+
+func TestModuleWithIncorrectNameShouldFail(t *testing.T) {
+	output, code := setupTest(t, "validate-invalid/incorrectmodulename")
+	if code != 1 {
+		t.Fatalf("Should have failed: %d\n\n%s", code, output.Stderr())
+	}
+
+	wantError := `Error: Invalid module instance name`
+	if !strings.Contains(output.Stderr(), wantError) {
+		t.Fatalf("Missing error string %q\n\n'%s'", wantError, output.Stderr())
+	}
+	wantError = `Error: Variables not allowed`
+	if !strings.Contains(output.Stderr(), wantError) {
+		t.Fatalf("Missing error string %q\n\n'%s'", wantError, output.Stderr())
+	}
+}
+
+func TestWronglyUsedInterpolationShouldFail(t *testing.T) {
+	output, code := setupTest(t, "validate-invalid/interpolation")
+	if code != 1 {
+		t.Fatalf("Should have failed: %d\n\n%s", code, output.Stderr())
+	}
+
+	wantError := `Error: Variables not allowed`
+	if !strings.Contains(output.Stderr(), wantError) {
+		t.Fatalf("Missing error string %q\n\n'%s'", wantError, output.Stderr())
+	}
+	wantError = `A single static variable reference is required`
+	if !strings.Contains(output.Stderr(), wantError) {
+		t.Fatalf("Missing error string %q\n\n'%s'", wantError, output.Stderr())
+	}
+}
+
+func TestMissingDefinedVar(t *testing.T) {
+	output, code := setupTest(t, "validate-invalid/missing_defined_var")
+	// This is allowed because validate tests only that variables are referenced
+	// correctly, not that they all have defined values.
+	if code != 0 {
+		t.Fatalf("Should have passed: %d\n\n%s", code, output.Stderr())
+	}
+}
+
+func TestValidate_json(t *testing.T) {
+	tests := []struct {
+		path  string
+		valid bool
+	}{
+		{"validate-valid", true},
+		{"validate-invalid", false},
+		{"validate-invalid/missing_quote", false},
+		{"validate-invalid/missing_var", false},
+		{"validate-invalid/multiple_providers", false},
+		{"validate-invalid/multiple_modules", false},
+		{"validate-invalid/multiple_resources", false},
+		{"validate-invalid/duplicate_import_targets", false},
+		{"validate-invalid/outputs", false},
+		{"validate-invalid/incorrectmodulename", false},
+		{"validate-invalid/interpolation", false},
+		{"validate-invalid/missing_defined_var", true},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.path, func(t *testing.T) {
+			var want, got map[string]interface{}
+
+			wantFile, err := os.Open(path.Join(testFixturePath(tc.path), "output.json"))
+			if err != nil {
+				t.Fatalf("failed to open output file: %s", err)
+			}
+			defer wantFile.Close()
+			wantBytes, err := ioutil.ReadAll(wantFile)
+			if err != nil {
+				t.Fatalf("failed to read output file: %s", err)
+			}
+			err = json.Unmarshal([]byte(wantBytes), &want)
+			if err != nil {
+				t.Fatalf("failed to unmarshal expected JSON: %s", err)
+			}
+
+			output, code := setupTest(t, tc.path, "-json")
+
+			gotString := output.Stdout()
+			err = json.Unmarshal([]byte(gotString), &got)
+			if err != nil {
+				t.Fatalf("failed to unmarshal actual JSON: %s", err)
+			}
+
+			if !cmp.Equal(got, want) {
+				t.Errorf("wrong output:\n %v\n", cmp.Diff(got, want))
+				t.Errorf("raw output:\n%s\n", gotString)
+			}
+
+			if tc.valid && code != 0 {
+				t.Errorf("wrong exit code: want 0, got %d", code)
+			} else if !tc.valid && code != 1 {
+				t.Errorf("wrong exit code: want 1, got %d", code)
+			}
+
+			if errorOutput := output.Stderr(); errorOutput != "" {
+				t.Errorf("unexpected error output:\n%s", errorOutput)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/version.go b/v1.5.7/internal/command/version.go
new file mode 100644
index 0000000..02d08bc
--- /dev/null
+++ b/v1.5.7/internal/command/version.go
@@ -0,0 +1,175 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+// VersionCommand is a Command implementation prints the version.
+type VersionCommand struct {
+	Meta
+
+	Version           string
+	VersionPrerelease string
+	CheckFunc         VersionCheckFunc
+	Platform          getproviders.Platform
+}
+
+type VersionOutput struct {
+	Version            string            `json:"terraform_version"`
+	Platform           string            `json:"platform"`
+	ProviderSelections map[string]string `json:"provider_selections"`
+	Outdated           bool              `json:"terraform_outdated"`
+}
+
+// VersionCheckFunc is the callback called by the Version command to
+// check if there is a new version of Terraform.
+type VersionCheckFunc func() (VersionCheckInfo, error)
+
+// VersionCheckInfo is the return value for the VersionCheckFunc callback
+// and tells the Version command information about the latest version
+// of Terraform.
+type VersionCheckInfo struct {
+	Outdated bool
+	Latest   string
+	Alerts   []string
+}
+
+func (c *VersionCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] version [options]
+
+  Displays the version of Terraform and all installed plugins
+
+Options:
+
+  -json       Output the version information as a JSON object.
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *VersionCommand) Run(args []string) int {
+	var outdated bool
+	var latest string
+	var versionString bytes.Buffer
+	args = c.Meta.process(args)
+	var jsonOutput bool
+	cmdFlags := c.Meta.defaultFlagSet("version")
+	cmdFlags.BoolVar(&jsonOutput, "json", false, "json")
+	// Enable but ignore the global version flags. In main.go, if any of the
+	// arguments are -v, -version, or --version, this command will be called
+	// with the rest of the arguments, so we need to be able to cope with
+	// those.
+	cmdFlags.Bool("v", true, "version")
+	cmdFlags.Bool("version", true, "version")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	fmt.Fprintf(&versionString, "Terraform v%s", c.Version)
+	if c.VersionPrerelease != "" {
+		fmt.Fprintf(&versionString, "-%s", c.VersionPrerelease)
+	}
+
+	// We'll also attempt to print out the selected plugin versions. We do
+	// this based on the dependency lock file, and so the result might be
+	// empty or incomplete if the user hasn't successfully run "terraform init"
+	// since the most recent change to dependencies.
+	//
+	// Generally-speaking this is a best-effort thing that will give us a good
+	// result in the usual case where the user successfully ran "terraform init"
+	// and then hit a problem running _another_ command.
+	var providerVersions []string
+	var providerLocks map[addrs.Provider]*depsfile.ProviderLock
+	if locks, err := c.lockedDependencies(); err == nil {
+		providerLocks = locks.AllProviders()
+		for providerAddr, lock := range providerLocks {
+			version := lock.Version().String()
+			if version == "0.0.0" {
+				providerVersions = append(providerVersions, fmt.Sprintf("+ provider %s (unversioned)", providerAddr))
+			} else {
+				providerVersions = append(providerVersions, fmt.Sprintf("+ provider %s v%s", providerAddr, version))
+			}
+		}
+	}
+
+	// If we have a version check function, then let's check for
+	// the latest version as well.
+	if c.CheckFunc != nil {
+		// Check the latest version
+		info, err := c.CheckFunc()
+		if err != nil && !jsonOutput {
+			c.Ui.Error(fmt.Sprintf(
+				"\nError checking latest version: %s", err))
+		}
+		if info.Outdated {
+			outdated = true
+			latest = info.Latest
+		}
+	}
+
+	if jsonOutput {
+		selectionsOutput := make(map[string]string)
+		for providerAddr, lock := range providerLocks {
+			version := lock.Version().String()
+			selectionsOutput[providerAddr.String()] = version
+		}
+
+		var versionOutput string
+		if c.VersionPrerelease != "" {
+			versionOutput = c.Version + "-" + c.VersionPrerelease
+		} else {
+			versionOutput = c.Version
+		}
+
+		output := VersionOutput{
+			Version:            versionOutput,
+			Platform:           c.Platform.String(),
+			ProviderSelections: selectionsOutput,
+			Outdated:           outdated,
+		}
+
+		jsonOutput, err := json.MarshalIndent(output, "", "  ")
+		if err != nil {
+			c.Ui.Error(fmt.Sprintf("\nError marshalling JSON: %s", err))
+			return 1
+		}
+		c.Ui.Output(string(jsonOutput))
+		return 0
+	} else {
+		c.Ui.Output(versionString.String())
+		c.Ui.Output(fmt.Sprintf("on %s", c.Platform))
+
+		if len(providerVersions) != 0 {
+			sort.Strings(providerVersions)
+			for _, str := range providerVersions {
+				c.Ui.Output(str)
+			}
+		}
+		if outdated {
+			c.Ui.Output(fmt.Sprintf(
+				"\nYour version of Terraform is out of date! The latest version\n"+
+					"is %s. You can update by downloading from https://www.terraform.io/downloads.html",
+				latest))
+		}
+
+	}
+
+	return 0
+}
+
+func (c *VersionCommand) Synopsis() string {
+	return "Show the current Terraform version"
+}
diff --git a/v1.5.7/internal/command/version_test.go b/v1.5.7/internal/command/version_test.go
new file mode 100644
index 0000000..ebcc601
--- /dev/null
+++ b/v1.5.7/internal/command/version_test.go
@@ -0,0 +1,231 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/mitchellh/cli"
+)
+
+func TestVersionCommand_implements(t *testing.T) {
+	var _ cli.Command = &VersionCommand{}
+}
+
+func TestVersion(t *testing.T) {
+	td := t.TempDir()
+	defer testChdir(t, td)()
+
+	// We'll create a fixed dependency lock file in our working directory
+	// so we can verify that the version command shows the information
+	// from it.
+	locks := depsfile.NewLocks()
+	locks.SetProvider(
+		addrs.NewDefaultProvider("test2"),
+		getproviders.MustParseVersion("1.2.3"),
+		nil,
+		nil,
+	)
+	locks.SetProvider(
+		addrs.NewDefaultProvider("test1"),
+		getproviders.MustParseVersion("7.8.9-beta.2"),
+		nil,
+		nil,
+	)
+
+	ui := cli.NewMockUi()
+	c := &VersionCommand{
+		Meta: Meta{
+			Ui: ui,
+		},
+		Version:           "4.5.6",
+		VersionPrerelease: "foo",
+		Platform:          getproviders.Platform{OS: "aros", Arch: "riscv64"},
+	}
+	if err := c.replaceLockedDependencies(locks); err != nil {
+		t.Fatal(err)
+	}
+	if code := c.Run([]string{}); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	actual := strings.TrimSpace(ui.OutputWriter.String())
+	expected := "Terraform v4.5.6-foo\non aros_riscv64\n+ provider registry.terraform.io/hashicorp/test1 v7.8.9-beta.2\n+ provider registry.terraform.io/hashicorp/test2 v1.2.3"
+	if actual != expected {
+		t.Fatalf("wrong output\ngot:\n%s\nwant:\n%s", actual, expected)
+	}
+
+}
+
+func TestVersion_flags(t *testing.T) {
+	ui := new(cli.MockUi)
+	m := Meta{
+		Ui: ui,
+	}
+
+	// `terraform version`
+	c := &VersionCommand{
+		Meta:              m,
+		Version:           "4.5.6",
+		VersionPrerelease: "foo",
+		Platform:          getproviders.Platform{OS: "aros", Arch: "riscv64"},
+	}
+
+	if code := c.Run([]string{"-v", "-version"}); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	actual := strings.TrimSpace(ui.OutputWriter.String())
+	expected := "Terraform v4.5.6-foo\non aros_riscv64"
+	if actual != expected {
+		t.Fatalf("wrong output\ngot: %#v\nwant: %#v", actual, expected)
+	}
+}
+
+func TestVersion_outdated(t *testing.T) {
+	ui := new(cli.MockUi)
+	m := Meta{
+		Ui: ui,
+	}
+
+	c := &VersionCommand{
+		Meta:      m,
+		Version:   "4.5.6",
+		CheckFunc: mockVersionCheckFunc(true, "4.5.7"),
+		Platform:  getproviders.Platform{OS: "aros", Arch: "riscv64"},
+	}
+
+	if code := c.Run([]string{}); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	actual := strings.TrimSpace(ui.OutputWriter.String())
+	expected := "Terraform v4.5.6\non aros_riscv64\n\nYour version of Terraform is out of date! The latest version\nis 4.5.7. You can update by downloading from https://www.terraform.io/downloads.html"
+	if actual != expected {
+		t.Fatalf("wrong output\ngot: %#v\nwant: %#v", actual, expected)
+	}
+}
+
+func TestVersion_json(t *testing.T) {
+	td := t.TempDir()
+	defer testChdir(t, td)()
+
+	ui := cli.NewMockUi()
+	meta := Meta{
+		Ui: ui,
+	}
+
+	// `terraform version -json` without prerelease
+	c := &VersionCommand{
+		Meta:     meta,
+		Version:  "4.5.6",
+		Platform: getproviders.Platform{OS: "aros", Arch: "riscv64"},
+	}
+	if code := c.Run([]string{"-json"}); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	actual := strings.TrimSpace(ui.OutputWriter.String())
+	expected := strings.TrimSpace(`
+{
+  "terraform_version": "4.5.6",
+  "platform": "aros_riscv64",
+  "provider_selections": {},
+  "terraform_outdated": false
+}
+`)
+	if diff := cmp.Diff(expected, actual); diff != "" {
+		t.Fatalf("wrong output\n%s", diff)
+	}
+
+	// flush the output from the mock ui
+	ui.OutputWriter.Reset()
+
+	// Now we'll create a fixed dependency lock file in our working directory
+	// so we can verify that the version command shows the information
+	// from it.
+	locks := depsfile.NewLocks()
+	locks.SetProvider(
+		addrs.NewDefaultProvider("test2"),
+		getproviders.MustParseVersion("1.2.3"),
+		nil,
+		nil,
+	)
+	locks.SetProvider(
+		addrs.NewDefaultProvider("test1"),
+		getproviders.MustParseVersion("7.8.9-beta.2"),
+		nil,
+		nil,
+	)
+
+	// `terraform version -json` with prerelease and provider dependencies
+	c = &VersionCommand{
+		Meta:              meta,
+		Version:           "4.5.6",
+		VersionPrerelease: "foo",
+		Platform:          getproviders.Platform{OS: "aros", Arch: "riscv64"},
+	}
+	if err := c.replaceLockedDependencies(locks); err != nil {
+		t.Fatal(err)
+	}
+	if code := c.Run([]string{"-json"}); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	actual = strings.TrimSpace(ui.OutputWriter.String())
+	expected = strings.TrimSpace(`
+{
+  "terraform_version": "4.5.6-foo",
+  "platform": "aros_riscv64",
+  "provider_selections": {
+    "registry.terraform.io/hashicorp/test1": "7.8.9-beta.2",
+    "registry.terraform.io/hashicorp/test2": "1.2.3"
+  },
+  "terraform_outdated": false
+}
+`)
+	if diff := cmp.Diff(expected, actual); diff != "" {
+		t.Fatalf("wrong output\n%s", diff)
+	}
+
+}
+
+func TestVersion_jsonoutdated(t *testing.T) {
+	ui := new(cli.MockUi)
+	m := Meta{
+		Ui: ui,
+	}
+
+	c := &VersionCommand{
+		Meta:      m,
+		Version:   "4.5.6",
+		CheckFunc: mockVersionCheckFunc(true, "4.5.7"),
+		Platform:  getproviders.Platform{OS: "aros", Arch: "riscv64"},
+	}
+
+	if code := c.Run([]string{"-json"}); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	actual := strings.TrimSpace(ui.OutputWriter.String())
+	expected := "{\n  \"terraform_version\": \"4.5.6\",\n  \"platform\": \"aros_riscv64\",\n  \"provider_selections\": {},\n  \"terraform_outdated\": true\n}"
+	if actual != expected {
+		t.Fatalf("wrong output\ngot: %#v\nwant: %#v", actual, expected)
+	}
+}
+
+func mockVersionCheckFunc(outdated bool, latest string) VersionCheckFunc {
+	return func() (VersionCheckInfo, error) {
+		return VersionCheckInfo{
+			Outdated: outdated,
+			Latest:   latest,
+			// Alerts is not used by version command
+		}, nil
+	}
+}
diff --git a/v1.5.7/internal/command/views/apply.go b/v1.5.7/internal/command/views/apply.go
new file mode 100644
index 0000000..8a8dbc6
--- /dev/null
+++ b/v1.5.7/internal/command/views/apply.go
@@ -0,0 +1,174 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/format"
+	"github.com/hashicorp/terraform/internal/command/views/json"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// The Apply view is used for the apply command.
+type Apply interface {
+	ResourceCount(stateOutPath string)
+	Outputs(outputValues map[string]*states.OutputValue)
+
+	Operation() Operation
+	Hooks() []terraform.Hook
+
+	Diagnostics(diags tfdiags.Diagnostics)
+	HelpPrompt()
+}
+
+// NewApply returns an initialized Apply implementation for the given ViewType.
+func NewApply(vt arguments.ViewType, destroy bool, view *View) Apply {
+	switch vt {
+	case arguments.ViewJSON:
+		return &ApplyJSON{
+			view:      NewJSONView(view),
+			destroy:   destroy,
+			countHook: &countHook{},
+		}
+	case arguments.ViewHuman:
+		return &ApplyHuman{
+			view:         view,
+			destroy:      destroy,
+			inAutomation: view.RunningInAutomation(),
+			countHook:    &countHook{},
+		}
+	default:
+		panic(fmt.Sprintf("unknown view type %v", vt))
+	}
+}
+
+// The ApplyHuman implementation renders human-readable text logs, suitable for
+// a scrolling terminal.
+type ApplyHuman struct {
+	view *View
+
+	destroy      bool
+	inAutomation bool
+
+	countHook *countHook
+}
+
+var _ Apply = (*ApplyHuman)(nil)
+
+func (v *ApplyHuman) ResourceCount(stateOutPath string) {
+	if v.destroy {
+		v.view.streams.Printf(
+			v.view.colorize.Color("[reset][bold][green]\nDestroy complete! Resources: %d destroyed.\n"),
+			v.countHook.Removed,
+		)
+	} else if v.countHook.Imported > 0 {
+		v.view.streams.Printf(
+			v.view.colorize.Color("[reset][bold][green]\nApply complete! Resources: %d imported, %d added, %d changed, %d destroyed.\n"),
+			v.countHook.Imported,
+			v.countHook.Added,
+			v.countHook.Changed,
+			v.countHook.Removed,
+		)
+	} else {
+		v.view.streams.Printf(
+			v.view.colorize.Color("[reset][bold][green]\nApply complete! Resources: %d added, %d changed, %d destroyed.\n"),
+			v.countHook.Added,
+			v.countHook.Changed,
+			v.countHook.Removed,
+		)
+	}
+	if (v.countHook.Added > 0 || v.countHook.Changed > 0) && stateOutPath != "" {
+		v.view.streams.Printf("\n%s\n\n", format.WordWrap(stateOutPathPostApply, v.view.outputColumns()))
+		v.view.streams.Printf("State path: %s\n", stateOutPath)
+	}
+}
+
+func (v *ApplyHuman) Outputs(outputValues map[string]*states.OutputValue) {
+	if len(outputValues) > 0 {
+		v.view.streams.Print(v.view.colorize.Color("[reset][bold][green]\nOutputs:\n\n"))
+		NewOutput(arguments.ViewHuman, v.view).Output("", outputValues)
+	}
+}
+
+func (v *ApplyHuman) Operation() Operation {
+	return NewOperation(arguments.ViewHuman, v.inAutomation, v.view)
+}
+
+func (v *ApplyHuman) Hooks() []terraform.Hook {
+	return []terraform.Hook{
+		v.countHook,
+		NewUiHook(v.view),
+	}
+}
+
+func (v *ApplyHuman) Diagnostics(diags tfdiags.Diagnostics) {
+	v.view.Diagnostics(diags)
+}
+
+func (v *ApplyHuman) HelpPrompt() {
+	command := "apply"
+	if v.destroy {
+		command = "destroy"
+	}
+	v.view.HelpPrompt(command)
+}
+
+const stateOutPathPostApply = "The state of your infrastructure has been saved to the path below. This state is required to modify and destroy your infrastructure, so keep it safe. To inspect the complete state use the `terraform show` command."
+
+// The ApplyJSON implementation renders streaming JSON logs, suitable for
+// integrating with other software.
+type ApplyJSON struct {
+	view *JSONView
+
+	destroy bool
+
+	countHook *countHook
+}
+
+var _ Apply = (*ApplyJSON)(nil)
+
+func (v *ApplyJSON) ResourceCount(stateOutPath string) {
+	operation := json.OperationApplied
+	if v.destroy {
+		operation = json.OperationDestroyed
+	}
+	v.view.ChangeSummary(&json.ChangeSummary{
+		Add:       v.countHook.Added,
+		Change:    v.countHook.Changed,
+		Remove:    v.countHook.Removed,
+		Import:    v.countHook.Imported,
+		Operation: operation,
+	})
+}
+
+func (v *ApplyJSON) Outputs(outputValues map[string]*states.OutputValue) {
+	outputs, diags := json.OutputsFromMap(outputValues)
+	if diags.HasErrors() {
+		v.Diagnostics(diags)
+	} else {
+		v.view.Outputs(outputs)
+	}
+}
+
+func (v *ApplyJSON) Operation() Operation {
+	return &OperationJSON{view: v.view}
+}
+
+func (v *ApplyJSON) Hooks() []terraform.Hook {
+	return []terraform.Hook{
+		v.countHook,
+		newJSONHook(v.view),
+	}
+}
+
+func (v *ApplyJSON) Diagnostics(diags tfdiags.Diagnostics) {
+	v.view.Diagnostics(diags)
+}
+
+func (v *ApplyJSON) HelpPrompt() {
+}
diff --git a/v1.5.7/internal/command/views/apply_test.go b/v1.5.7/internal/command/views/apply_test.go
new file mode 100644
index 0000000..dfaa46c
--- /dev/null
+++ b/v1.5.7/internal/command/views/apply_test.go
@@ -0,0 +1,270 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// This test is mostly because I am paranoid about having two consecutive
+// boolean arguments.
+func TestApply_new(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	defer done(t)
+	v := NewApply(arguments.ViewHuman, false, NewView(streams).SetRunningInAutomation(true))
+	hv, ok := v.(*ApplyHuman)
+	if !ok {
+		t.Fatalf("unexpected return type %t", v)
+	}
+
+	if hv.destroy != false {
+		t.Fatalf("unexpected destroy value")
+	}
+
+	if hv.inAutomation != true {
+		t.Fatalf("unexpected inAutomation value")
+	}
+}
+
+// Basic test coverage of Outputs, since most of its functionality is tested
+// elsewhere.
+func TestApplyHuman_outputs(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := NewApply(arguments.ViewHuman, false, NewView(streams))
+
+	v.Outputs(map[string]*states.OutputValue{
+		"foo": {Value: cty.StringVal("secret")},
+	})
+
+	got := done(t).Stdout()
+	for _, want := range []string{"Outputs:", `foo = "secret"`} {
+		if !strings.Contains(got, want) {
+			t.Errorf("wrong result\ngot:  %q\nwant: %q", got, want)
+		}
+	}
+}
+
+// Outputs should do nothing if there are no outputs to render.
+func TestApplyHuman_outputsEmpty(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := NewApply(arguments.ViewHuman, false, NewView(streams))
+
+	v.Outputs(map[string]*states.OutputValue{})
+
+	got := done(t).Stdout()
+	if got != "" {
+		t.Errorf("output should be empty, but got: %q", got)
+	}
+}
+
+// Ensure that the correct view type and in-automation settings propagate to the
+// Operation view.
+func TestApplyHuman_operation(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	defer done(t)
+	v := NewApply(arguments.ViewHuman, false, NewView(streams).SetRunningInAutomation(true)).Operation()
+	if hv, ok := v.(*OperationHuman); !ok {
+		t.Fatalf("unexpected return type %t", v)
+	} else if hv.inAutomation != true {
+		t.Fatalf("unexpected inAutomation value on Operation view")
+	}
+}
+
+// This view is used for both apply and destroy commands, so the help output
+// needs to cover both.
+func TestApplyHuman_help(t *testing.T) {
+	testCases := map[string]bool{
+		"apply":   false,
+		"destroy": true,
+	}
+
+	for name, destroy := range testCases {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			v := NewApply(arguments.ViewHuman, destroy, NewView(streams))
+			v.HelpPrompt()
+			got := done(t).Stderr()
+			if !strings.Contains(got, name) {
+				t.Errorf("wrong result\ngot:  %q\nwant: %q", got, name)
+			}
+		})
+	}
+}
+
+// Hooks and ResourceCount are tangled up and easiest to test together.
+func TestApply_resourceCount(t *testing.T) {
+	testCases := map[string]struct {
+		destroy   bool
+		want      string
+		importing bool
+	}{
+		"apply": {
+			false,
+			"Apply complete! Resources: 1 added, 2 changed, 3 destroyed.",
+			false,
+		},
+		"destroy": {
+			true,
+			"Destroy complete! Resources: 3 destroyed.",
+			false,
+		},
+		"import": {
+			false,
+			"Apply complete! Resources: 1 imported, 1 added, 2 changed, 3 destroyed.",
+			true,
+		},
+	}
+
+	// For compatibility reasons, these tests should hold true for both human
+	// and JSON output modes
+	views := []arguments.ViewType{arguments.ViewHuman, arguments.ViewJSON}
+
+	for name, tc := range testCases {
+		for _, viewType := range views {
+			t.Run(fmt.Sprintf("%s (%s view)", name, viewType), func(t *testing.T) {
+				streams, done := terminal.StreamsForTesting(t)
+				v := NewApply(viewType, tc.destroy, NewView(streams))
+				hooks := v.Hooks()
+
+				var count *countHook
+				for _, hook := range hooks {
+					if ch, ok := hook.(*countHook); ok {
+						count = ch
+					}
+				}
+				if count == nil {
+					t.Fatalf("expected Hooks to include a countHook: %#v", hooks)
+				}
+
+				count.Added = 1
+				count.Changed = 2
+				count.Removed = 3
+
+				if tc.importing {
+					count.Imported = 1
+				}
+
+				v.ResourceCount("")
+
+				got := done(t).Stdout()
+				if !strings.Contains(got, tc.want) {
+					t.Errorf("wrong result\ngot:  %q\nwant: %q", got, tc.want)
+				}
+			})
+		}
+	}
+}
+
+func TestApplyHuman_resourceCountStatePath(t *testing.T) {
+	testCases := map[string]struct {
+		added        int
+		changed      int
+		removed      int
+		statePath    string
+		wantContains bool
+	}{
+		"default state path": {
+			added:        1,
+			changed:      2,
+			removed:      3,
+			statePath:    "",
+			wantContains: false,
+		},
+		"only removed": {
+			added:        0,
+			changed:      0,
+			removed:      5,
+			statePath:    "foo.tfstate",
+			wantContains: false,
+		},
+		"added": {
+			added:        5,
+			changed:      0,
+			removed:      0,
+			statePath:    "foo.tfstate",
+			wantContains: true,
+		},
+		"changed": {
+			added:        0,
+			changed:      5,
+			removed:      0,
+			statePath:    "foo.tfstate",
+			wantContains: true,
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			v := NewApply(arguments.ViewHuman, false, NewView(streams))
+			hooks := v.Hooks()
+
+			var count *countHook
+			for _, hook := range hooks {
+				if ch, ok := hook.(*countHook); ok {
+					count = ch
+				}
+			}
+			if count == nil {
+				t.Fatalf("expected Hooks to include a countHook: %#v", hooks)
+			}
+
+			count.Added = tc.added
+			count.Changed = tc.changed
+			count.Removed = tc.removed
+
+			v.ResourceCount(tc.statePath)
+
+			got := done(t).Stdout()
+			want := "State path: " + tc.statePath
+			contains := strings.Contains(got, want)
+			if contains && !tc.wantContains {
+				t.Errorf("wrong result\ngot:  %q\nshould not contain: %q", got, want)
+			} else if !contains && tc.wantContains {
+				t.Errorf("wrong result\ngot:  %q\nshould contain: %q", got, want)
+			}
+		})
+	}
+}
+
+// Basic test coverage of Outputs, since most of its functionality is tested
+// elsewhere.
+func TestApplyJSON_outputs(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := NewApply(arguments.ViewJSON, false, NewView(streams))
+
+	v.Outputs(map[string]*states.OutputValue{
+		"boop_count": {Value: cty.NumberIntVal(92)},
+		"password":   {Value: cty.StringVal("horse-battery").Mark(marks.Sensitive), Sensitive: true},
+	})
+
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": "Outputs: 2",
+			"@module":  "terraform.ui",
+			"type":     "outputs",
+			"outputs": map[string]interface{}{
+				"boop_count": map[string]interface{}{
+					"sensitive": false,
+					"value":     float64(92),
+					"type":      "number",
+				},
+				"password": map[string]interface{}{
+					"sensitive": true,
+					"type":      "string",
+				},
+			},
+		},
+	}
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
diff --git a/v1.5.7/internal/command/views/hook_count.go b/v1.5.7/internal/command/views/hook_count.go
new file mode 100644
index 0000000..2336ee6
--- /dev/null
+++ b/v1.5.7/internal/command/views/hook_count.go
@@ -0,0 +1,119 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"sync"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// countHook is a hook that counts the number of resources
+// added, removed, changed during the course of an apply.
+type countHook struct {
+	Added    int
+	Changed  int
+	Removed  int
+	Imported int
+
+	ToAdd          int
+	ToChange       int
+	ToRemove       int
+	ToRemoveAndAdd int
+
+	pending map[string]plans.Action
+
+	sync.Mutex
+	terraform.NilHook
+}
+
+var _ terraform.Hook = (*countHook)(nil)
+
+func (h *countHook) Reset() {
+	h.Lock()
+	defer h.Unlock()
+
+	h.pending = nil
+	h.Added = 0
+	h.Changed = 0
+	h.Removed = 0
+	h.Imported = 0
+}
+
+func (h *countHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	if h.pending == nil {
+		h.pending = make(map[string]plans.Action)
+	}
+
+	h.pending[addr.String()] = action
+
+	return terraform.HookActionContinue, nil
+}
+
+func (h *countHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (terraform.HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	if h.pending != nil {
+		pendingKey := addr.String()
+		if action, ok := h.pending[pendingKey]; ok {
+			delete(h.pending, pendingKey)
+
+			if err == nil {
+				switch action {
+				case plans.CreateThenDelete, plans.DeleteThenCreate:
+					h.Added++
+					h.Removed++
+				case plans.Create:
+					h.Added++
+				case plans.Delete:
+					h.Removed++
+				case plans.Update:
+					h.Changed++
+				}
+			}
+		}
+	}
+
+	return terraform.HookActionContinue, nil
+}
+
+func (h *countHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	// We don't count anything for data resources
+	if addr.Resource.Resource.Mode == addrs.DataResourceMode {
+		return terraform.HookActionContinue, nil
+	}
+
+	switch action {
+	case plans.CreateThenDelete, plans.DeleteThenCreate:
+		h.ToRemoveAndAdd += 1
+	case plans.Create:
+		h.ToAdd += 1
+	case plans.Delete:
+		h.ToRemove += 1
+	case plans.Update:
+		h.ToChange += 1
+	}
+
+	return terraform.HookActionContinue, nil
+}
+
+func (h *countHook) PostApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (terraform.HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.Imported++
+	return terraform.HookActionContinue, nil
+}
diff --git a/v1.5.7/internal/command/views/hook_count_test.go b/v1.5.7/internal/command/views/hook_count_test.go
new file mode 100644
index 0000000..80fcd41
--- /dev/null
+++ b/v1.5.7/internal/command/views/hook_count_test.go
@@ -0,0 +1,340 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+
+	legacy "github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+func TestCountHook_impl(t *testing.T) {
+	var _ terraform.Hook = new(countHook)
+}
+
+func TestCountHookPostDiff_DestroyDeposed(t *testing.T) {
+	h := new(countHook)
+
+	resources := map[string]*legacy.InstanceDiff{
+		"lorem": &legacy.InstanceDiff{DestroyDeposed: true},
+	}
+
+	for k := range resources {
+		addr := addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: k,
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+		h.PostDiff(addr, states.DeposedKey("deadbeef"), plans.Delete, cty.DynamicVal, cty.DynamicVal)
+	}
+
+	expected := new(countHook)
+	expected.ToAdd = 0
+	expected.ToChange = 0
+	expected.ToRemoveAndAdd = 0
+	expected.ToRemove = 1
+
+	if !reflect.DeepEqual(expected, h) {
+		t.Fatalf("Expected %#v, got %#v instead.", expected, h)
+	}
+}
+
+func TestCountHookPostDiff_DestroyOnly(t *testing.T) {
+	h := new(countHook)
+
+	resources := map[string]*legacy.InstanceDiff{
+		"foo":   &legacy.InstanceDiff{Destroy: true},
+		"bar":   &legacy.InstanceDiff{Destroy: true},
+		"lorem": &legacy.InstanceDiff{Destroy: true},
+		"ipsum": &legacy.InstanceDiff{Destroy: true},
+	}
+
+	for k := range resources {
+		addr := addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: k,
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+		h.PostDiff(addr, states.CurrentGen, plans.Delete, cty.DynamicVal, cty.DynamicVal)
+	}
+
+	expected := new(countHook)
+	expected.ToAdd = 0
+	expected.ToChange = 0
+	expected.ToRemoveAndAdd = 0
+	expected.ToRemove = 4
+
+	if !reflect.DeepEqual(expected, h) {
+		t.Fatalf("Expected %#v, got %#v instead.", expected, h)
+	}
+}
+
+func TestCountHookPostDiff_AddOnly(t *testing.T) {
+	h := new(countHook)
+
+	resources := map[string]*legacy.InstanceDiff{
+		"foo": &legacy.InstanceDiff{
+			Attributes: map[string]*legacy.ResourceAttrDiff{
+				"foo": &legacy.ResourceAttrDiff{RequiresNew: true},
+			},
+		},
+		"bar": &legacy.InstanceDiff{
+			Attributes: map[string]*legacy.ResourceAttrDiff{
+				"foo": &legacy.ResourceAttrDiff{RequiresNew: true},
+			},
+		},
+		"lorem": &legacy.InstanceDiff{
+			Attributes: map[string]*legacy.ResourceAttrDiff{
+				"foo": &legacy.ResourceAttrDiff{RequiresNew: true},
+			},
+		},
+	}
+
+	for k := range resources {
+		addr := addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: k,
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+		h.PostDiff(addr, states.CurrentGen, plans.Create, cty.DynamicVal, cty.DynamicVal)
+	}
+
+	expected := new(countHook)
+	expected.ToAdd = 3
+	expected.ToChange = 0
+	expected.ToRemoveAndAdd = 0
+	expected.ToRemove = 0
+
+	if !reflect.DeepEqual(expected, h) {
+		t.Fatalf("Expected %#v, got %#v instead.", expected, h)
+	}
+}
+
+func TestCountHookPostDiff_ChangeOnly(t *testing.T) {
+	h := new(countHook)
+
+	resources := map[string]*legacy.InstanceDiff{
+		"foo": &legacy.InstanceDiff{
+			Destroy: false,
+			Attributes: map[string]*legacy.ResourceAttrDiff{
+				"foo": &legacy.ResourceAttrDiff{},
+			},
+		},
+		"bar": &legacy.InstanceDiff{
+			Destroy: false,
+			Attributes: map[string]*legacy.ResourceAttrDiff{
+				"foo": &legacy.ResourceAttrDiff{},
+			},
+		},
+		"lorem": &legacy.InstanceDiff{
+			Destroy: false,
+			Attributes: map[string]*legacy.ResourceAttrDiff{
+				"foo": &legacy.ResourceAttrDiff{},
+			},
+		},
+	}
+
+	for k := range resources {
+		addr := addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: k,
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+		h.PostDiff(addr, states.CurrentGen, plans.Update, cty.DynamicVal, cty.DynamicVal)
+	}
+
+	expected := new(countHook)
+	expected.ToAdd = 0
+	expected.ToChange = 3
+	expected.ToRemoveAndAdd = 0
+	expected.ToRemove = 0
+
+	if !reflect.DeepEqual(expected, h) {
+		t.Fatalf("Expected %#v, got %#v instead.", expected, h)
+	}
+}
+
+func TestCountHookPostDiff_Mixed(t *testing.T) {
+	h := new(countHook)
+
+	resources := map[string]plans.Action{
+		"foo":   plans.Delete,
+		"bar":   plans.NoOp,
+		"lorem": plans.Update,
+		"ipsum": plans.Delete,
+	}
+
+	for k, a := range resources {
+		addr := addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: k,
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+		h.PostDiff(addr, states.CurrentGen, a, cty.DynamicVal, cty.DynamicVal)
+	}
+
+	expected := new(countHook)
+	expected.ToAdd = 0
+	expected.ToChange = 1
+	expected.ToRemoveAndAdd = 0
+	expected.ToRemove = 2
+
+	if !reflect.DeepEqual(expected, h) {
+		t.Fatalf("Expected %#v, got %#v instead.",
+			expected, h)
+	}
+}
+
+func TestCountHookPostDiff_NoChange(t *testing.T) {
+	h := new(countHook)
+
+	resources := map[string]*legacy.InstanceDiff{
+		"foo":   &legacy.InstanceDiff{},
+		"bar":   &legacy.InstanceDiff{},
+		"lorem": &legacy.InstanceDiff{},
+		"ipsum": &legacy.InstanceDiff{},
+	}
+
+	for k := range resources {
+		addr := addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: k,
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+		h.PostDiff(addr, states.CurrentGen, plans.NoOp, cty.DynamicVal, cty.DynamicVal)
+	}
+
+	expected := new(countHook)
+	expected.ToAdd = 0
+	expected.ToChange = 0
+	expected.ToRemoveAndAdd = 0
+	expected.ToRemove = 0
+
+	if !reflect.DeepEqual(expected, h) {
+		t.Fatalf("Expected %#v, got %#v instead.",
+			expected, h)
+	}
+}
+
+func TestCountHookPostDiff_DataSource(t *testing.T) {
+	h := new(countHook)
+
+	resources := map[string]plans.Action{
+		"foo":   plans.Delete,
+		"bar":   plans.NoOp,
+		"lorem": plans.Update,
+		"ipsum": plans.Delete,
+	}
+
+	for k, a := range resources {
+		addr := addrs.Resource{
+			Mode: addrs.DataResourceMode,
+			Type: "test_instance",
+			Name: k,
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+		h.PostDiff(addr, states.CurrentGen, a, cty.DynamicVal, cty.DynamicVal)
+	}
+
+	expected := new(countHook)
+	expected.ToAdd = 0
+	expected.ToChange = 0
+	expected.ToRemoveAndAdd = 0
+	expected.ToRemove = 0
+
+	if !reflect.DeepEqual(expected, h) {
+		t.Fatalf("Expected %#v, got %#v instead.",
+			expected, h)
+	}
+}
+
+func TestCountHookApply_ChangeOnly(t *testing.T) {
+	h := new(countHook)
+
+	resources := map[string]*legacy.InstanceDiff{
+		"foo": &legacy.InstanceDiff{
+			Destroy: false,
+			Attributes: map[string]*legacy.ResourceAttrDiff{
+				"foo": &legacy.ResourceAttrDiff{},
+			},
+		},
+		"bar": &legacy.InstanceDiff{
+			Destroy: false,
+			Attributes: map[string]*legacy.ResourceAttrDiff{
+				"foo": &legacy.ResourceAttrDiff{},
+			},
+		},
+		"lorem": &legacy.InstanceDiff{
+			Destroy: false,
+			Attributes: map[string]*legacy.ResourceAttrDiff{
+				"foo": &legacy.ResourceAttrDiff{},
+			},
+		},
+	}
+
+	for k := range resources {
+		addr := addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: k,
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+		h.PreApply(addr, states.CurrentGen, plans.Update, cty.DynamicVal, cty.DynamicVal)
+		h.PostApply(addr, states.CurrentGen, cty.DynamicVal, nil)
+	}
+
+	expected := &countHook{pending: make(map[string]plans.Action)}
+	expected.Added = 0
+	expected.Changed = 3
+	expected.Removed = 0
+
+	if !reflect.DeepEqual(expected, h) {
+		t.Fatalf("Expected:\n%#v\nGot:\n%#v\n", expected, h)
+	}
+}
+
+func TestCountHookApply_DestroyOnly(t *testing.T) {
+	h := new(countHook)
+
+	resources := map[string]*legacy.InstanceDiff{
+		"foo":   &legacy.InstanceDiff{Destroy: true},
+		"bar":   &legacy.InstanceDiff{Destroy: true},
+		"lorem": &legacy.InstanceDiff{Destroy: true},
+		"ipsum": &legacy.InstanceDiff{Destroy: true},
+	}
+
+	for k := range resources {
+		addr := addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: k,
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+		h.PreApply(addr, states.CurrentGen, plans.Delete, cty.DynamicVal, cty.DynamicVal)
+		h.PostApply(addr, states.CurrentGen, cty.DynamicVal, nil)
+	}
+
+	expected := &countHook{pending: make(map[string]plans.Action)}
+	expected.Added = 0
+	expected.Changed = 0
+	expected.Removed = 4
+
+	if !reflect.DeepEqual(expected, h) {
+		t.Fatalf("Expected:\n%#v\nGot:\n%#v\n", expected, h)
+	}
+}
diff --git a/v1.5.7/internal/command/views/hook_json.go b/v1.5.7/internal/command/views/hook_json.go
new file mode 100644
index 0000000..6b3a2ef
--- /dev/null
+++ b/v1.5.7/internal/command/views/hook_json.go
@@ -0,0 +1,168 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"bufio"
+	"strings"
+	"sync"
+	"time"
+	"unicode"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/format"
+	"github.com/hashicorp/terraform/internal/command/views/json"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// How long to wait between sending heartbeat/progress messages
+const heartbeatInterval = 10 * time.Second
+
+func newJSONHook(view *JSONView) *jsonHook {
+	return &jsonHook{
+		view:      view,
+		applying:  make(map[string]applyProgress),
+		timeNow:   time.Now,
+		timeAfter: time.After,
+	}
+}
+
+type jsonHook struct {
+	terraform.NilHook
+
+	view *JSONView
+
+	// Concurrent map of resource addresses to allow the sequence of pre-apply,
+	// progress, and post-apply messages to share data about the resource
+	applying     map[string]applyProgress
+	applyingLock sync.Mutex
+
+	// Mockable functions for testing the progress timer goroutine
+	timeNow   func() time.Time
+	timeAfter func(time.Duration) <-chan time.Time
+}
+
+var _ terraform.Hook = (*jsonHook)(nil)
+
+type applyProgress struct {
+	addr   addrs.AbsResourceInstance
+	action plans.Action
+	start  time.Time
+
+	// done is used for post-apply to stop the progress goroutine
+	done chan struct{}
+
+	// heartbeatDone is used to allow tests to safely wait for the progress
+	// goroutine to finish
+	heartbeatDone chan struct{}
+}
+
+func (h *jsonHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) {
+	if action != plans.NoOp {
+		idKey, idValue := format.ObjectValueIDOrName(priorState)
+		h.view.Hook(json.NewApplyStart(addr, action, idKey, idValue))
+	}
+
+	progress := applyProgress{
+		addr:          addr,
+		action:        action,
+		start:         h.timeNow().Round(time.Second),
+		done:          make(chan struct{}),
+		heartbeatDone: make(chan struct{}),
+	}
+	h.applyingLock.Lock()
+	h.applying[addr.String()] = progress
+	h.applyingLock.Unlock()
+
+	if action != plans.NoOp {
+		go h.applyingHeartbeat(progress)
+	}
+	return terraform.HookActionContinue, nil
+}
+
+func (h *jsonHook) applyingHeartbeat(progress applyProgress) {
+	defer close(progress.heartbeatDone)
+	for {
+		select {
+		case <-progress.done:
+			return
+		case <-h.timeAfter(heartbeatInterval):
+		}
+
+		elapsed := h.timeNow().Round(time.Second).Sub(progress.start)
+		h.view.Hook(json.NewApplyProgress(progress.addr, progress.action, elapsed))
+	}
+}
+
+func (h *jsonHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (terraform.HookAction, error) {
+	key := addr.String()
+	h.applyingLock.Lock()
+	progress := h.applying[key]
+	if progress.done != nil {
+		close(progress.done)
+	}
+	delete(h.applying, key)
+	h.applyingLock.Unlock()
+
+	if progress.action == plans.NoOp {
+		return terraform.HookActionContinue, nil
+	}
+
+	elapsed := h.timeNow().Round(time.Second).Sub(progress.start)
+
+	if err != nil {
+		// Errors are collected and displayed post-apply, so no need to
+		// re-render them here. Instead just signal that this resource failed
+		// to apply.
+		h.view.Hook(json.NewApplyErrored(addr, progress.action, elapsed))
+	} else {
+		idKey, idValue := format.ObjectValueID(newState)
+		h.view.Hook(json.NewApplyComplete(addr, progress.action, idKey, idValue, elapsed))
+	}
+	return terraform.HookActionContinue, nil
+}
+
+func (h *jsonHook) PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string) (terraform.HookAction, error) {
+	h.view.Hook(json.NewProvisionStart(addr, typeName))
+	return terraform.HookActionContinue, nil
+}
+
+func (h *jsonHook) PostProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string, err error) (terraform.HookAction, error) {
+	if err != nil {
+		// Errors are collected and displayed post-apply, so no need to
+		// re-render them here. Instead just signal that this provisioner step
+		// failed.
+		h.view.Hook(json.NewProvisionErrored(addr, typeName))
+	} else {
+		h.view.Hook(json.NewProvisionComplete(addr, typeName))
+	}
+	return terraform.HookActionContinue, nil
+}
+
+func (h *jsonHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, msg string) {
+	s := bufio.NewScanner(strings.NewReader(msg))
+	s.Split(scanLines)
+	for s.Scan() {
+		line := strings.TrimRightFunc(s.Text(), unicode.IsSpace)
+		if line != "" {
+			h.view.Hook(json.NewProvisionProgress(addr, typeName, line))
+		}
+	}
+}
+
+func (h *jsonHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (terraform.HookAction, error) {
+	idKey, idValue := format.ObjectValueID(priorState)
+	h.view.Hook(json.NewRefreshStart(addr, idKey, idValue))
+	return terraform.HookActionContinue, nil
+}
+
+func (h *jsonHook) PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (terraform.HookAction, error) {
+	idKey, idValue := format.ObjectValueID(newState)
+	h.view.Hook(json.NewRefreshComplete(addr, idKey, idValue))
+	return terraform.HookActionContinue, nil
+}
diff --git a/v1.5.7/internal/command/views/hook_json_test.go b/v1.5.7/internal/command/views/hook_json_test.go
new file mode 100644
index 0000000..faabaa3
--- /dev/null
+++ b/v1.5.7/internal/command/views/hook_json_test.go
@@ -0,0 +1,341 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"fmt"
+	"sync"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Test a sequence of hooks associated with creating a resource
+func TestJSONHook_create(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	hook := newJSONHook(NewJSONView(NewView(streams)))
+
+	var nowMu sync.Mutex
+	now := time.Now()
+	hook.timeNow = func() time.Time {
+		nowMu.Lock()
+		defer nowMu.Unlock()
+		return now
+	}
+
+	after := make(chan time.Time, 1)
+	hook.timeAfter = func(time.Duration) <-chan time.Time { return after }
+
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "boop",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+	priorState := cty.NullVal(cty.Object(map[string]cty.Type{
+		"id":  cty.String,
+		"bar": cty.List(cty.String),
+	}))
+	plannedNewState := cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("test"),
+		"bar": cty.ListVal([]cty.Value{
+			cty.StringVal("baz"),
+		}),
+	})
+
+	action, err := hook.PreApply(addr, states.CurrentGen, plans.Create, priorState, plannedNewState)
+	testHookReturnValues(t, action, err)
+
+	action, err = hook.PreProvisionInstanceStep(addr, "local-exec")
+	testHookReturnValues(t, action, err)
+
+	hook.ProvisionOutput(addr, "local-exec", `Executing: ["/bin/sh" "-c" "touch /etc/motd"]`)
+
+	action, err = hook.PostProvisionInstanceStep(addr, "local-exec", nil)
+	testHookReturnValues(t, action, err)
+
+	// Travel 10s into the future, notify the progress goroutine, and sleep
+	// briefly to allow it to execute
+	nowMu.Lock()
+	now = now.Add(10 * time.Second)
+	after <- now
+	nowMu.Unlock()
+	time.Sleep(1 * time.Millisecond)
+
+	// Travel 10s into the future, notify the progress goroutine, and sleep
+	// briefly to allow it to execute
+	nowMu.Lock()
+	now = now.Add(10 * time.Second)
+	after <- now
+	nowMu.Unlock()
+	time.Sleep(1 * time.Millisecond)
+
+	// Travel 2s into the future. We have arrived!
+	nowMu.Lock()
+	now = now.Add(2 * time.Second)
+	nowMu.Unlock()
+
+	action, err = hook.PostApply(addr, states.CurrentGen, plannedNewState, nil)
+	testHookReturnValues(t, action, err)
+
+	// Shut down the progress goroutine if still active
+	hook.applyingLock.Lock()
+	for key, progress := range hook.applying {
+		close(progress.done)
+		<-progress.heartbeatDone
+		delete(hook.applying, key)
+	}
+	hook.applyingLock.Unlock()
+
+	wantResource := map[string]interface{}{
+		"addr":             string("test_instance.boop"),
+		"implied_provider": string("test"),
+		"module":           string(""),
+		"resource":         string("test_instance.boop"),
+		"resource_key":     nil,
+		"resource_name":    string("boop"),
+		"resource_type":    string("test_instance"),
+	}
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": "test_instance.boop: Creating...",
+			"@module":  "terraform.ui",
+			"type":     "apply_start",
+			"hook": map[string]interface{}{
+				"action":   string("create"),
+				"resource": wantResource,
+			},
+		},
+		{
+			"@level":   "info",
+			"@message": "test_instance.boop: Provisioning with 'local-exec'...",
+			"@module":  "terraform.ui",
+			"type":     "provision_start",
+			"hook": map[string]interface{}{
+				"provisioner": "local-exec",
+				"resource":    wantResource,
+			},
+		},
+		{
+			"@level":   "info",
+			"@message": `test_instance.boop: (local-exec): Executing: ["/bin/sh" "-c" "touch /etc/motd"]`,
+			"@module":  "terraform.ui",
+			"type":     "provision_progress",
+			"hook": map[string]interface{}{
+				"output":      `Executing: ["/bin/sh" "-c" "touch /etc/motd"]`,
+				"provisioner": "local-exec",
+				"resource":    wantResource,
+			},
+		},
+		{
+			"@level":   "info",
+			"@message": "test_instance.boop: (local-exec) Provisioning complete",
+			"@module":  "terraform.ui",
+			"type":     "provision_complete",
+			"hook": map[string]interface{}{
+				"provisioner": "local-exec",
+				"resource":    wantResource,
+			},
+		},
+		{
+			"@level":   "info",
+			"@message": "test_instance.boop: Still creating... [10s elapsed]",
+			"@module":  "terraform.ui",
+			"type":     "apply_progress",
+			"hook": map[string]interface{}{
+				"action":          string("create"),
+				"elapsed_seconds": float64(10),
+				"resource":        wantResource,
+			},
+		},
+		{
+			"@level":   "info",
+			"@message": "test_instance.boop: Still creating... [20s elapsed]",
+			"@module":  "terraform.ui",
+			"type":     "apply_progress",
+			"hook": map[string]interface{}{
+				"action":          string("create"),
+				"elapsed_seconds": float64(20),
+				"resource":        wantResource,
+			},
+		},
+		{
+			"@level":   "info",
+			"@message": "test_instance.boop: Creation complete after 22s [id=test]",
+			"@module":  "terraform.ui",
+			"type":     "apply_complete",
+			"hook": map[string]interface{}{
+				"action":          string("create"),
+				"elapsed_seconds": float64(22),
+				"id_key":          "id",
+				"id_value":        "test",
+				"resource":        wantResource,
+			},
+		},
+	}
+
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func TestJSONHook_errors(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	hook := newJSONHook(NewJSONView(NewView(streams)))
+
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "boop",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+	priorState := cty.NullVal(cty.Object(map[string]cty.Type{
+		"id":  cty.String,
+		"bar": cty.List(cty.String),
+	}))
+	plannedNewState := cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("test"),
+		"bar": cty.ListVal([]cty.Value{
+			cty.StringVal("baz"),
+		}),
+	})
+
+	action, err := hook.PreApply(addr, states.CurrentGen, plans.Delete, priorState, plannedNewState)
+	testHookReturnValues(t, action, err)
+
+	provisionError := fmt.Errorf("provisioner didn't want to")
+	action, err = hook.PostProvisionInstanceStep(addr, "local-exec", provisionError)
+	testHookReturnValues(t, action, err)
+
+	applyError := fmt.Errorf("provider was sad")
+	action, err = hook.PostApply(addr, states.CurrentGen, plannedNewState, applyError)
+	testHookReturnValues(t, action, err)
+
+	// Shut down the progress goroutine
+	hook.applyingLock.Lock()
+	for key, progress := range hook.applying {
+		close(progress.done)
+		<-progress.heartbeatDone
+		delete(hook.applying, key)
+	}
+	hook.applyingLock.Unlock()
+
+	wantResource := map[string]interface{}{
+		"addr":             string("test_instance.boop"),
+		"implied_provider": string("test"),
+		"module":           string(""),
+		"resource":         string("test_instance.boop"),
+		"resource_key":     nil,
+		"resource_name":    string("boop"),
+		"resource_type":    string("test_instance"),
+	}
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": "test_instance.boop: Destroying...",
+			"@module":  "terraform.ui",
+			"type":     "apply_start",
+			"hook": map[string]interface{}{
+				"action":   string("delete"),
+				"resource": wantResource,
+			},
+		},
+		{
+			"@level":   "info",
+			"@message": "test_instance.boop: (local-exec) Provisioning errored",
+			"@module":  "terraform.ui",
+			"type":     "provision_errored",
+			"hook": map[string]interface{}{
+				"provisioner": "local-exec",
+				"resource":    wantResource,
+			},
+		},
+		{
+			"@level":   "info",
+			"@message": "test_instance.boop: Destruction errored after 0s",
+			"@module":  "terraform.ui",
+			"type":     "apply_errored",
+			"hook": map[string]interface{}{
+				"action":          string("delete"),
+				"elapsed_seconds": float64(0),
+				"resource":        wantResource,
+			},
+		},
+	}
+
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func TestJSONHook_refresh(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	hook := newJSONHook(NewJSONView(NewView(streams)))
+
+	addr := addrs.Resource{
+		Mode: addrs.DataResourceMode,
+		Type: "test_data_source",
+		Name: "beep",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+	state := cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("honk"),
+		"bar": cty.ListVal([]cty.Value{
+			cty.StringVal("baz"),
+		}),
+	})
+
+	action, err := hook.PreRefresh(addr, states.CurrentGen, state)
+	testHookReturnValues(t, action, err)
+
+	action, err = hook.PostRefresh(addr, states.CurrentGen, state, state)
+	testHookReturnValues(t, action, err)
+
+	wantResource := map[string]interface{}{
+		"addr":             string("data.test_data_source.beep"),
+		"implied_provider": string("test"),
+		"module":           string(""),
+		"resource":         string("data.test_data_source.beep"),
+		"resource_key":     nil,
+		"resource_name":    string("beep"),
+		"resource_type":    string("test_data_source"),
+	}
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": "data.test_data_source.beep: Refreshing state... [id=honk]",
+			"@module":  "terraform.ui",
+			"type":     "refresh_start",
+			"hook": map[string]interface{}{
+				"resource": wantResource,
+				"id_key":   "id",
+				"id_value": "honk",
+			},
+		},
+		{
+			"@level":   "info",
+			"@message": "data.test_data_source.beep: Refresh complete [id=honk]",
+			"@module":  "terraform.ui",
+			"type":     "refresh_complete",
+			"hook": map[string]interface{}{
+				"resource": wantResource,
+				"id_key":   "id",
+				"id_value": "honk",
+			},
+		},
+	}
+
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func testHookReturnValues(t *testing.T, action terraform.HookAction, err error) {
+	t.Helper()
+
+	if err != nil {
+		t.Fatal(err)
+	}
+	if action != terraform.HookActionContinue {
+		t.Fatalf("Expected hook to continue, given: %#v", action)
+	}
+}
diff --git a/v1.5.7/internal/command/views/hook_ui.go b/v1.5.7/internal/command/views/hook_ui.go
new file mode 100644
index 0000000..400718e
--- /dev/null
+++ b/v1.5.7/internal/command/views/hook_ui.go
@@ -0,0 +1,401 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"strings"
+	"sync"
+	"time"
+	"unicode"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/format"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+const defaultPeriodicUiTimer = 10 * time.Second
+const maxIdLen = 80
+
+func NewUiHook(view *View) *UiHook {
+	return &UiHook{
+		view:            view,
+		periodicUiTimer: defaultPeriodicUiTimer,
+		resources:       make(map[string]uiResourceState),
+	}
+}
+
+type UiHook struct {
+	terraform.NilHook
+
+	view     *View
+	viewLock sync.Mutex
+
+	periodicUiTimer time.Duration
+
+	resources     map[string]uiResourceState
+	resourcesLock sync.Mutex
+}
+
+var _ terraform.Hook = (*UiHook)(nil)
+
+// uiResourceState tracks the state of a single resource
+type uiResourceState struct {
+	DispAddr       string
+	IDKey, IDValue string
+	Op             uiResourceOp
+	Start          time.Time
+
+	DoneCh chan struct{} // To be used for cancellation
+
+	done chan struct{} // used to coordinate tests
+}
+
+// uiResourceOp is an enum for operations on a resource
+type uiResourceOp byte
+
+const (
+	uiResourceUnknown uiResourceOp = iota
+	uiResourceCreate
+	uiResourceModify
+	uiResourceDestroy
+	uiResourceRead
+	uiResourceNoOp
+)
+
+func (h *UiHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) {
+	dispAddr := addr.String()
+	if gen != states.CurrentGen {
+		dispAddr = fmt.Sprintf("%s (deposed object %s)", dispAddr, gen)
+	}
+
+	var operation string
+	var op uiResourceOp
+	idKey, idValue := format.ObjectValueIDOrName(priorState)
+	switch action {
+	case plans.Delete:
+		operation = "Destroying..."
+		op = uiResourceDestroy
+	case plans.Create:
+		operation = "Creating..."
+		op = uiResourceCreate
+	case plans.Update:
+		operation = "Modifying..."
+		op = uiResourceModify
+	case plans.Read:
+		operation = "Reading..."
+		op = uiResourceRead
+	case plans.NoOp:
+		op = uiResourceNoOp
+	default:
+		// We don't expect any other actions in here, so anything else is a
+		// bug in the caller but we'll ignore it in order to be robust.
+		h.println(fmt.Sprintf("(Unknown action %s for %s)", action, dispAddr))
+		return terraform.HookActionContinue, nil
+	}
+
+	var stateIdSuffix string
+	if idKey != "" && idValue != "" {
+		stateIdSuffix = fmt.Sprintf(" [%s=%s]", idKey, idValue)
+	} else {
+		// Make sure they are both empty so we can deal with this more
+		// easily in the other hook methods.
+		idKey = ""
+		idValue = ""
+	}
+
+	if operation != "" {
+		h.println(fmt.Sprintf(
+			h.view.colorize.Color("[reset][bold]%s: %s%s[reset]"),
+			dispAddr,
+			operation,
+			stateIdSuffix,
+		))
+	}
+
+	key := addr.String()
+	uiState := uiResourceState{
+		DispAddr: key,
+		IDKey:    idKey,
+		IDValue:  idValue,
+		Op:       op,
+		Start:    time.Now().Round(time.Second),
+		DoneCh:   make(chan struct{}),
+		done:     make(chan struct{}),
+	}
+
+	h.resourcesLock.Lock()
+	h.resources[key] = uiState
+	h.resourcesLock.Unlock()
+
+	// Start goroutine that shows progress
+	if op != uiResourceNoOp {
+		go h.stillApplying(uiState)
+	}
+
+	return terraform.HookActionContinue, nil
+}
+
+func (h *UiHook) stillApplying(state uiResourceState) {
+	defer close(state.done)
+	for {
+		select {
+		case <-state.DoneCh:
+			return
+
+		case <-time.After(h.periodicUiTimer):
+			// Timer up, show status
+		}
+
+		var msg string
+		switch state.Op {
+		case uiResourceModify:
+			msg = "Still modifying..."
+		case uiResourceDestroy:
+			msg = "Still destroying..."
+		case uiResourceCreate:
+			msg = "Still creating..."
+		case uiResourceRead:
+			msg = "Still reading..."
+		case uiResourceUnknown:
+			return
+		}
+
+		idSuffix := ""
+		if state.IDKey != "" {
+			idSuffix = fmt.Sprintf("%s=%s, ", state.IDKey, truncateId(state.IDValue, maxIdLen))
+		}
+
+		h.println(fmt.Sprintf(
+			h.view.colorize.Color("[reset][bold]%s: %s [%s%s elapsed][reset]"),
+			state.DispAddr,
+			msg,
+			idSuffix,
+			time.Now().Round(time.Second).Sub(state.Start),
+		))
+	}
+}
+
+func (h *UiHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, applyerr error) (terraform.HookAction, error) {
+	id := addr.String()
+
+	h.resourcesLock.Lock()
+	state := h.resources[id]
+	if state.DoneCh != nil {
+		close(state.DoneCh)
+	}
+
+	delete(h.resources, id)
+	h.resourcesLock.Unlock()
+
+	var stateIdSuffix string
+	if k, v := format.ObjectValueID(newState); k != "" && v != "" {
+		stateIdSuffix = fmt.Sprintf(" [%s=%s]", k, v)
+	}
+
+	var msg string
+	switch state.Op {
+	case uiResourceModify:
+		msg = "Modifications complete"
+	case uiResourceDestroy:
+		msg = "Destruction complete"
+	case uiResourceCreate:
+		msg = "Creation complete"
+	case uiResourceRead:
+		msg = "Read complete"
+	case uiResourceNoOp:
+		// We don't make any announcements about no-op changes
+		return terraform.HookActionContinue, nil
+	case uiResourceUnknown:
+		return terraform.HookActionContinue, nil
+	}
+
+	if applyerr != nil {
+		// Errors are collected and printed in ApplyCommand, no need to duplicate
+		return terraform.HookActionContinue, nil
+	}
+
+	addrStr := addr.String()
+	if depKey, ok := gen.(states.DeposedKey); ok {
+		addrStr = fmt.Sprintf("%s (deposed object %s)", addrStr, depKey)
+	}
+
+	colorized := fmt.Sprintf(
+		h.view.colorize.Color("[reset][bold]%s: %s after %s%s"),
+		addrStr, msg, time.Now().Round(time.Second).Sub(state.Start), stateIdSuffix)
+
+	h.println(colorized)
+
+	return terraform.HookActionContinue, nil
+}
+
+func (h *UiHook) PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string) (terraform.HookAction, error) {
+	h.println(fmt.Sprintf(
+		h.view.colorize.Color("[reset][bold]%s: Provisioning with '%s'...[reset]"),
+		addr, typeName,
+	))
+	return terraform.HookActionContinue, nil
+}
+
+func (h *UiHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, msg string) {
+	var buf bytes.Buffer
+
+	prefix := fmt.Sprintf(
+		h.view.colorize.Color("[reset][bold]%s (%s):[reset] "),
+		addr, typeName,
+	)
+	s := bufio.NewScanner(strings.NewReader(msg))
+	s.Split(scanLines)
+	for s.Scan() {
+		line := strings.TrimRightFunc(s.Text(), unicode.IsSpace)
+		if line != "" {
+			buf.WriteString(fmt.Sprintf("%s%s\n", prefix, line))
+		}
+	}
+
+	h.println(strings.TrimSpace(buf.String()))
+}
+
+func (h *UiHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (terraform.HookAction, error) {
+	var stateIdSuffix string
+	if k, v := format.ObjectValueID(priorState); k != "" && v != "" {
+		stateIdSuffix = fmt.Sprintf(" [%s=%s]", k, v)
+	}
+
+	addrStr := addr.String()
+	if depKey, ok := gen.(states.DeposedKey); ok {
+		addrStr = fmt.Sprintf("%s (deposed object %s)", addrStr, depKey)
+	}
+
+	h.println(fmt.Sprintf(
+		h.view.colorize.Color("[reset][bold]%s: Refreshing state...%s"),
+		addrStr, stateIdSuffix))
+	return terraform.HookActionContinue, nil
+}
+
+func (h *UiHook) PreImportState(addr addrs.AbsResourceInstance, importID string) (terraform.HookAction, error) {
+	h.println(fmt.Sprintf(
+		h.view.colorize.Color("[reset][bold]%s: Importing from ID %q..."),
+		addr, importID,
+	))
+	return terraform.HookActionContinue, nil
+}
+
+func (h *UiHook) PostImportState(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (terraform.HookAction, error) {
+	h.println(fmt.Sprintf(
+		h.view.colorize.Color("[reset][bold][green]%s: Import prepared!"),
+		addr,
+	))
+	for _, s := range imported {
+		h.println(fmt.Sprintf(
+			h.view.colorize.Color("[reset][green]  Prepared %s for import"),
+			s.TypeName,
+		))
+	}
+
+	return terraform.HookActionContinue, nil
+}
+
+func (h *UiHook) PrePlanImport(addr addrs.AbsResourceInstance, importID string) (terraform.HookAction, error) {
+	h.println(fmt.Sprintf(
+		h.view.colorize.Color("[reset][bold]%s: Preparing import... [id=%s]"),
+		addr, importID,
+	))
+
+	return terraform.HookActionContinue, nil
+}
+
+func (h *UiHook) PreApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (terraform.HookAction, error) {
+	h.println(fmt.Sprintf(
+		h.view.colorize.Color("[reset][bold]%s: Importing... [id=%s]"),
+		addr, importing.ID,
+	))
+
+	return terraform.HookActionContinue, nil
+}
+
+func (h *UiHook) PostApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (terraform.HookAction, error) {
+	h.println(fmt.Sprintf(
+		h.view.colorize.Color("[reset][bold]%s: Import complete [id=%s]"),
+		addr, importing.ID,
+	))
+
+	return terraform.HookActionContinue, nil
+}
+
+// Wrap calls to the view so that concurrent calls do not interleave println.
+func (h *UiHook) println(s string) {
+	h.viewLock.Lock()
+	defer h.viewLock.Unlock()
+	h.view.streams.Println(s)
+}
+
+// scanLines is basically copied from the Go standard library except
+// we've modified it to also fine `\r`.
+func scanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
+	if atEOF && len(data) == 0 {
+		return 0, nil, nil
+	}
+	if i := bytes.IndexByte(data, '\n'); i >= 0 {
+		// We have a full newline-terminated line.
+		return i + 1, dropCR(data[0:i]), nil
+	}
+	if i := bytes.IndexByte(data, '\r'); i >= 0 {
+		// We have a full carriage-return-terminated line.
+		return i + 1, dropCR(data[0:i]), nil
+	}
+	// If we're at EOF, we have a final, non-terminated line. Return it.
+	if atEOF {
+		return len(data), dropCR(data), nil
+	}
+	// Request more data.
+	return 0, nil, nil
+}
+
+// dropCR drops a terminal \r from the data.
+func dropCR(data []byte) []byte {
+	if len(data) > 0 && data[len(data)-1] == '\r' {
+		return data[0 : len(data)-1]
+	}
+	return data
+}
+
+func truncateId(id string, maxLen int) string {
+	// Note that the id may contain multibyte characters.
+	// We need to truncate it to maxLen characters, not maxLen bytes.
+	rid := []rune(id)
+	totalLength := len(rid)
+	if totalLength <= maxLen {
+		return id
+	}
+	if maxLen < 5 {
+		// We don't shorten to less than 5 chars
+		// as that would be pointless with ... (3 chars)
+		maxLen = 5
+	}
+
+	dots := []rune("...")
+	partLen := maxLen / 2
+
+	leftIdx := partLen - 1
+	leftPart := rid[0:leftIdx]
+
+	rightIdx := totalLength - partLen - 1
+
+	overlap := maxLen - (partLen*2 + len(dots))
+	if overlap < 0 {
+		rightIdx -= overlap
+	}
+
+	rightPart := rid[rightIdx:]
+
+	return string(leftPart) + string(dots) + string(rightPart)
+}
diff --git a/v1.5.7/internal/command/views/hook_ui_test.go b/v1.5.7/internal/command/views/hook_ui_test.go
new file mode 100644
index 0000000..ac1b5a1
--- /dev/null
+++ b/v1.5.7/internal/command/views/hook_ui_test.go
@@ -0,0 +1,661 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"fmt"
+	"regexp"
+	"testing"
+	"time"
+
+	"strings"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// Test the PreApply hook for creating a new resource
+func TestUiHookPreApply_create(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	view := NewView(streams)
+	h := NewUiHook(view)
+	h.resources = map[string]uiResourceState{
+		"test_instance.foo": {
+			Op:    uiResourceCreate,
+			Start: time.Now(),
+		},
+	}
+
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	priorState := cty.NullVal(cty.Object(map[string]cty.Type{
+		"id":  cty.String,
+		"bar": cty.List(cty.String),
+	}))
+	plannedNewState := cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("test"),
+		"bar": cty.ListVal([]cty.Value{
+			cty.StringVal("baz"),
+		}),
+	})
+
+	action, err := h.PreApply(addr, states.CurrentGen, plans.Create, priorState, plannedNewState)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if action != terraform.HookActionContinue {
+		t.Fatalf("Expected hook to continue, given: %#v", action)
+	}
+
+	// stop the background writer
+	uiState := h.resources[addr.String()]
+	close(uiState.DoneCh)
+	<-uiState.done
+
+	expectedOutput := "test_instance.foo: Creating...\n"
+	result := done(t)
+	output := result.Stdout()
+	if output != expectedOutput {
+		t.Fatalf("Output didn't match.\nExpected: %q\nGiven: %q", expectedOutput, output)
+	}
+
+	expectedErrOutput := ""
+	errOutput := result.Stderr()
+	if errOutput != expectedErrOutput {
+		t.Fatalf("Error output didn't match.\nExpected: %q\nGiven: %q", expectedErrOutput, errOutput)
+	}
+}
+
+// Test the PreApply hook's use of a periodic timer to display "still working"
+// log lines
+func TestUiHookPreApply_periodicTimer(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	view := NewView(streams)
+	h := NewUiHook(view)
+	h.periodicUiTimer = 1 * time.Second
+	h.resources = map[string]uiResourceState{
+		"test_instance.foo": {
+			Op:    uiResourceModify,
+			Start: time.Now(),
+		},
+	}
+
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	priorState := cty.ObjectVal(map[string]cty.Value{
+		"id":  cty.StringVal("test"),
+		"bar": cty.ListValEmpty(cty.String),
+	})
+	plannedNewState := cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("test"),
+		"bar": cty.ListVal([]cty.Value{
+			cty.StringVal("baz"),
+		}),
+	})
+
+	action, err := h.PreApply(addr, states.CurrentGen, plans.Update, priorState, plannedNewState)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if action != terraform.HookActionContinue {
+		t.Fatalf("Expected hook to continue, given: %#v", action)
+	}
+
+	time.Sleep(3100 * time.Millisecond)
+
+	// stop the background writer
+	uiState := h.resources[addr.String()]
+	close(uiState.DoneCh)
+	<-uiState.done
+
+	expectedOutput := `test_instance.foo: Modifying... [id=test]
+test_instance.foo: Still modifying... [id=test, 1s elapsed]
+test_instance.foo: Still modifying... [id=test, 2s elapsed]
+test_instance.foo: Still modifying... [id=test, 3s elapsed]
+`
+	result := done(t)
+	output := result.Stdout()
+	if output != expectedOutput {
+		t.Fatalf("Output didn't match.\nExpected: %q\nGiven: %q", expectedOutput, output)
+	}
+
+	expectedErrOutput := ""
+	errOutput := result.Stderr()
+	if errOutput != expectedErrOutput {
+		t.Fatalf("Error output didn't match.\nExpected: %q\nGiven: %q", expectedErrOutput, errOutput)
+	}
+}
+
+// Test the PreApply hook's destroy path, including passing a deposed key as
+// the gen argument.
+func TestUiHookPreApply_destroy(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	view := NewView(streams)
+	h := NewUiHook(view)
+	h.resources = map[string]uiResourceState{
+		"test_instance.foo": {
+			Op:    uiResourceDestroy,
+			Start: time.Now(),
+		},
+	}
+
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	priorState := cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("abc123"),
+		"verbs": cty.ListVal([]cty.Value{
+			cty.StringVal("boop"),
+		}),
+	})
+	plannedNewState := cty.NullVal(cty.Object(map[string]cty.Type{
+		"id":    cty.String,
+		"verbs": cty.List(cty.String),
+	}))
+
+	key := states.NewDeposedKey()
+	action, err := h.PreApply(addr, key, plans.Delete, priorState, plannedNewState)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if action != terraform.HookActionContinue {
+		t.Fatalf("Expected hook to continue, given: %#v", action)
+	}
+
+	// stop the background writer
+	uiState := h.resources[addr.String()]
+	close(uiState.DoneCh)
+	<-uiState.done
+
+	result := done(t)
+	expectedOutput := fmt.Sprintf("test_instance.foo (deposed object %s): Destroying... [id=abc123]\n", key)
+	output := result.Stdout()
+	if output != expectedOutput {
+		t.Fatalf("Output didn't match.\nExpected: %q\nGiven: %q", expectedOutput, output)
+	}
+
+	expectedErrOutput := ""
+	errOutput := result.Stderr()
+	if errOutput != expectedErrOutput {
+		t.Fatalf("Error output didn't match.\nExpected: %q\nGiven: %q", expectedErrOutput, errOutput)
+	}
+}
+
+// Verify that colorize is called on format strings, not user input, by adding
+// valid color codes as resource names and IDs.
+func TestUiHookPostApply_colorInterpolation(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	view := NewView(streams)
+	view.Configure(&arguments.View{NoColor: false})
+	h := NewUiHook(view)
+	h.resources = map[string]uiResourceState{
+		"test_instance.foo[\"[red]\"]": {
+			Op:    uiResourceCreate,
+			Start: time.Now(),
+		},
+	}
+
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "foo",
+	}.Instance(addrs.StringKey("[red]")).Absolute(addrs.RootModuleInstance)
+
+	newState := cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("[blue]"),
+	})
+
+	action, err := h.PostApply(addr, states.CurrentGen, newState, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if action != terraform.HookActionContinue {
+		t.Fatalf("Expected hook to continue, given: %#v", action)
+	}
+	result := done(t)
+
+	reset := "\x1b[0m"
+	bold := "\x1b[1m"
+	wantPrefix := reset + bold + `test_instance.foo["[red]"]: Creation complete after`
+	wantSuffix := "[id=[blue]]" + reset + "\n"
+	output := result.Stdout()
+
+	if !strings.HasPrefix(output, wantPrefix) {
+		t.Fatalf("wrong output prefix\n got: %#v\nwant: %#v", output, wantPrefix)
+	}
+
+	if !strings.HasSuffix(output, wantSuffix) {
+		t.Fatalf("wrong output suffix\n got: %#v\nwant: %#v", output, wantSuffix)
+	}
+
+	expectedErrOutput := ""
+	errOutput := result.Stderr()
+	if errOutput != expectedErrOutput {
+		t.Fatalf("Error output didn't match.\nExpected: %q\nGiven: %q", expectedErrOutput, errOutput)
+	}
+}
+
+// Test that the PostApply hook renders a total time.
+func TestUiHookPostApply_emptyState(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	view := NewView(streams)
+	h := NewUiHook(view)
+	h.resources = map[string]uiResourceState{
+		"data.google_compute_zones.available": {
+			Op:    uiResourceDestroy,
+			Start: time.Now(),
+		},
+	}
+
+	addr := addrs.Resource{
+		Mode: addrs.DataResourceMode,
+		Type: "google_compute_zones",
+		Name: "available",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	newState := cty.NullVal(cty.Object(map[string]cty.Type{
+		"id":    cty.String,
+		"names": cty.List(cty.String),
+	}))
+
+	action, err := h.PostApply(addr, states.CurrentGen, newState, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if action != terraform.HookActionContinue {
+		t.Fatalf("Expected hook to continue, given: %#v", action)
+	}
+	result := done(t)
+
+	expectedRegexp := "^data.google_compute_zones.available: Destruction complete after -?[a-z0-9µ.]+\n$"
+	output := result.Stdout()
+	if matched, _ := regexp.MatchString(expectedRegexp, output); !matched {
+		t.Fatalf("Output didn't match regexp.\nExpected: %q\nGiven: %q", expectedRegexp, output)
+	}
+
+	expectedErrOutput := ""
+	errOutput := result.Stderr()
+	if errOutput != expectedErrOutput {
+		t.Fatalf("Error output didn't match.\nExpected: %q\nGiven: %q", expectedErrOutput, errOutput)
+	}
+}
+
+func TestPreProvisionInstanceStep(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	view := NewView(streams)
+	h := NewUiHook(view)
+
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	action, err := h.PreProvisionInstanceStep(addr, "local-exec")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if action != terraform.HookActionContinue {
+		t.Fatalf("Expected hook to continue, given: %#v", action)
+	}
+	result := done(t)
+
+	if got, want := result.Stdout(), "test_instance.foo: Provisioning with 'local-exec'...\n"; got != want {
+		t.Fatalf("unexpected output\n got: %q\nwant: %q", got, want)
+	}
+}
+
+// Test ProvisionOutput, including lots of edge cases for the output
+// whitespace/line ending logic.
+func TestProvisionOutput(t *testing.T) {
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	testCases := map[string]struct {
+		provisioner string
+		input       string
+		wantOutput  string
+	}{
+		"single line": {
+			"local-exec",
+			"foo\n",
+			"test_instance.foo (local-exec): foo\n",
+		},
+		"multiple lines": {
+			"x",
+			`foo
+bar
+baz
+`,
+			`test_instance.foo (x): foo
+test_instance.foo (x): bar
+test_instance.foo (x): baz
+`,
+		},
+		"trailing whitespace": {
+			"x",
+			"foo                  \nbar\n",
+			"test_instance.foo (x): foo\ntest_instance.foo (x): bar\n",
+		},
+		"blank lines": {
+			"x",
+			"foo\n\nbar\n\n\nbaz\n",
+			`test_instance.foo (x): foo
+test_instance.foo (x): bar
+test_instance.foo (x): baz
+`,
+		},
+		"no final newline": {
+			"x",
+			`foo
+bar`,
+			`test_instance.foo (x): foo
+test_instance.foo (x): bar
+`,
+		},
+		"CR, no LF": {
+			"MacOS 9?",
+			"foo\rbar\r",
+			`test_instance.foo (MacOS 9?): foo
+test_instance.foo (MacOS 9?): bar
+`,
+		},
+		"CRLF": {
+			"winrm",
+			"foo\r\nbar\r\n",
+			`test_instance.foo (winrm): foo
+test_instance.foo (winrm): bar
+`,
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			view := NewView(streams)
+			h := NewUiHook(view)
+
+			h.ProvisionOutput(addr, tc.provisioner, tc.input)
+			result := done(t)
+
+			if got := result.Stdout(); got != tc.wantOutput {
+				t.Fatalf("unexpected output\n got: %q\nwant: %q", got, tc.wantOutput)
+			}
+		})
+	}
+}
+
+// Test the PreRefresh hook in the normal path where the resource exists with
+// an ID key and value in the state.
+func TestPreRefresh(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	view := NewView(streams)
+	h := NewUiHook(view)
+
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	priorState := cty.ObjectVal(map[string]cty.Value{
+		"id":  cty.StringVal("test"),
+		"bar": cty.ListValEmpty(cty.String),
+	})
+
+	action, err := h.PreRefresh(addr, states.CurrentGen, priorState)
+
+	if err != nil {
+		t.Fatal(err)
+	}
+	if action != terraform.HookActionContinue {
+		t.Fatalf("Expected hook to continue, given: %#v", action)
+	}
+	result := done(t)
+
+	if got, want := result.Stdout(), "test_instance.foo: Refreshing state... [id=test]\n"; got != want {
+		t.Fatalf("unexpected output\n got: %q\nwant: %q", got, want)
+	}
+}
+
+// Test that PreRefresh still works if no ID key and value can be determined
+// from state.
+func TestPreRefresh_noID(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	view := NewView(streams)
+	h := NewUiHook(view)
+
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	priorState := cty.ObjectVal(map[string]cty.Value{
+		"bar": cty.ListValEmpty(cty.String),
+	})
+
+	action, err := h.PreRefresh(addr, states.CurrentGen, priorState)
+
+	if err != nil {
+		t.Fatal(err)
+	}
+	if action != terraform.HookActionContinue {
+		t.Fatalf("Expected hook to continue, given: %#v", action)
+	}
+	result := done(t)
+
+	if got, want := result.Stdout(), "test_instance.foo: Refreshing state...\n"; got != want {
+		t.Fatalf("unexpected output\n got: %q\nwant: %q", got, want)
+	}
+}
+
+// Test the very simple PreImportState hook.
+func TestPreImportState(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	view := NewView(streams)
+	h := NewUiHook(view)
+
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	action, err := h.PreImportState(addr, "test")
+
+	if err != nil {
+		t.Fatal(err)
+	}
+	if action != terraform.HookActionContinue {
+		t.Fatalf("Expected hook to continue, given: %#v", action)
+	}
+	result := done(t)
+
+	if got, want := result.Stdout(), "test_instance.foo: Importing from ID \"test\"...\n"; got != want {
+		t.Fatalf("unexpected output\n got: %q\nwant: %q", got, want)
+	}
+}
+
+// Test the PostImportState UI hook. Again, this hook behaviour seems odd to
+// me (see below), so please don't consider these tests as justification for
+// keeping this behaviour.
+func TestPostImportState(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	view := NewView(streams)
+	h := NewUiHook(view)
+
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	// The "Prepared [...] for import" lines display the type name of each of
+	// the imported resources passed to the hook. I'm not sure how it's
+	// possible for an import to result in a different resource type name than
+	// the target address, but the hook works like this so we're covering it.
+	imported := []providers.ImportedResource{
+		{
+			TypeName: "test_some_instance",
+			State: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("test"),
+			}),
+		},
+		{
+			TypeName: "test_other_instance",
+			State: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("test"),
+			}),
+		},
+	}
+
+	action, err := h.PostImportState(addr, imported)
+
+	if err != nil {
+		t.Fatal(err)
+	}
+	if action != terraform.HookActionContinue {
+		t.Fatalf("Expected hook to continue, given: %#v", action)
+	}
+	result := done(t)
+
+	want := `test_instance.foo: Import prepared!
+  Prepared test_some_instance for import
+  Prepared test_other_instance for import
+`
+	if got := result.Stdout(); got != want {
+		t.Fatalf("unexpected output\n got: %q\nwant: %q", got, want)
+	}
+}
+
+func TestTruncateId(t *testing.T) {
+	testCases := []struct {
+		Input    string
+		Expected string
+		MaxLen   int
+	}{
+		{
+			Input:    "Hello world",
+			Expected: "H...d",
+			MaxLen:   3,
+		},
+		{
+			Input:    "Hello world",
+			Expected: "H...d",
+			MaxLen:   5,
+		},
+		{
+			Input:    "Hello world",
+			Expected: "He...d",
+			MaxLen:   6,
+		},
+		{
+			Input:    "Hello world",
+			Expected: "He...ld",
+			MaxLen:   7,
+		},
+		{
+			Input:    "Hello world",
+			Expected: "Hel...ld",
+			MaxLen:   8,
+		},
+		{
+			Input:    "Hello world",
+			Expected: "Hel...rld",
+			MaxLen:   9,
+		},
+		{
+			Input:    "Hello world",
+			Expected: "Hell...rld",
+			MaxLen:   10,
+		},
+		{
+			Input:    "Hello world",
+			Expected: "Hello world",
+			MaxLen:   11,
+		},
+		{
+			Input:    "Hello world",
+			Expected: "Hello world",
+			MaxLen:   12,
+		},
+		{
+			Input:    "あいうえおかきくけこさ",
+			Expected: "あ...さ",
+			MaxLen:   3,
+		},
+		{
+			Input:    "あいうえおかきくけこさ",
+			Expected: "あ...さ",
+			MaxLen:   5,
+		},
+		{
+			Input:    "あいうえおかきくけこさ",
+			Expected: "あい...さ",
+			MaxLen:   6,
+		},
+		{
+			Input:    "あいうえおかきくけこさ",
+			Expected: "あい...こさ",
+			MaxLen:   7,
+		},
+		{
+			Input:    "あいうえおかきくけこさ",
+			Expected: "あいう...こさ",
+			MaxLen:   8,
+		},
+		{
+			Input:    "あいうえおかきくけこさ",
+			Expected: "あいう...けこさ",
+			MaxLen:   9,
+		},
+		{
+			Input:    "あいうえおかきくけこさ",
+			Expected: "あいうえ...けこさ",
+			MaxLen:   10,
+		},
+		{
+			Input:    "あいうえおかきくけこさ",
+			Expected: "あいうえおかきくけこさ",
+			MaxLen:   11,
+		},
+		{
+			Input:    "あいうえおかきくけこさ",
+			Expected: "あいうえおかきくけこさ",
+			MaxLen:   12,
+		},
+	}
+	for i, tc := range testCases {
+		testName := fmt.Sprintf("%d", i)
+		t.Run(testName, func(t *testing.T) {
+			out := truncateId(tc.Input, tc.MaxLen)
+			if out != tc.Expected {
+				t.Fatalf("Expected %q to be shortened to %d as %q (given: %q)",
+					tc.Input, tc.MaxLen, tc.Expected, out)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/views/json/change.go b/v1.5.7/internal/command/views/json/change.go
new file mode 100644
index 0000000..3fd5f49
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/change.go
@@ -0,0 +1,151 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package json
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+func NewResourceInstanceChange(change *plans.ResourceInstanceChangeSrc) *ResourceInstanceChange {
+	c := &ResourceInstanceChange{
+		Resource:        newResourceAddr(change.Addr),
+		Action:          changeAction(change.Action),
+		Reason:          changeReason(change.ActionReason),
+		GeneratedConfig: change.GeneratedConfig,
+	}
+
+	// The order here matters, we want the moved action to take precedence over
+	// the import action. We're basically taking "the most recent action" as the
+	// primary action in the streamed logs. That is to say, that if a resource
+	// is imported and then moved in a single operation then the change for that
+	// resource will be reported as ActionMove while the Importing flag will
+	// still be set to true.
+	//
+	// Since both the moved and imported actions only overwrite a NoOp this
+	// behaviour is consistent across the other actions as well. Something that
+	// is imported and then updated, or moved and then updated, will have the
+	// ActionUpdate as the recognised action for the change.
+
+	if !change.Addr.Equal(change.PrevRunAddr) {
+		if c.Action == ActionNoOp {
+			c.Action = ActionMove
+		}
+		pr := newResourceAddr(change.PrevRunAddr)
+		c.PreviousResource = &pr
+	}
+	if change.Importing != nil {
+		if c.Action == ActionNoOp {
+			c.Action = ActionImport
+		}
+		c.Importing = &Importing{ID: change.Importing.ID}
+	}
+
+	return c
+}
+
+type ResourceInstanceChange struct {
+	Resource         ResourceAddr  `json:"resource"`
+	PreviousResource *ResourceAddr `json:"previous_resource,omitempty"`
+	Action           ChangeAction  `json:"action"`
+	Reason           ChangeReason  `json:"reason,omitempty"`
+	Importing        *Importing    `json:"importing,omitempty"`
+	GeneratedConfig  string        `json:"generated_config,omitempty"`
+}
+
+func (c *ResourceInstanceChange) String() string {
+	return fmt.Sprintf("%s: Plan to %s", c.Resource.Addr, c.Action)
+}
+
+type ChangeAction string
+
+const (
+	ActionNoOp    ChangeAction = "noop"
+	ActionMove    ChangeAction = "move"
+	ActionCreate  ChangeAction = "create"
+	ActionRead    ChangeAction = "read"
+	ActionUpdate  ChangeAction = "update"
+	ActionReplace ChangeAction = "replace"
+	ActionDelete  ChangeAction = "delete"
+	ActionImport  ChangeAction = "import"
+)
+
+func changeAction(action plans.Action) ChangeAction {
+	switch action {
+	case plans.NoOp:
+		return ActionNoOp
+	case plans.Create:
+		return ActionCreate
+	case plans.Read:
+		return ActionRead
+	case plans.Update:
+		return ActionUpdate
+	case plans.DeleteThenCreate, plans.CreateThenDelete:
+		return ActionReplace
+	case plans.Delete:
+		return ActionDelete
+	default:
+		return ActionNoOp
+	}
+}
+
+type ChangeReason string
+
+const (
+	ReasonNone               ChangeReason = ""
+	ReasonTainted            ChangeReason = "tainted"
+	ReasonRequested          ChangeReason = "requested"
+	ReasonReplaceTriggeredBy ChangeReason = "replace_triggered_by"
+	ReasonCannotUpdate       ChangeReason = "cannot_update"
+	ReasonUnknown            ChangeReason = "unknown"
+
+	ReasonDeleteBecauseNoResourceConfig ChangeReason = "delete_because_no_resource_config"
+	ReasonDeleteBecauseWrongRepetition  ChangeReason = "delete_because_wrong_repetition"
+	ReasonDeleteBecauseCountIndex       ChangeReason = "delete_because_count_index"
+	ReasonDeleteBecauseEachKey          ChangeReason = "delete_because_each_key"
+	ReasonDeleteBecauseNoModule         ChangeReason = "delete_because_no_module"
+	ReasonDeleteBecauseNoMoveTarget     ChangeReason = "delete_because_no_move_target"
+	ReasonReadBecauseConfigUnknown      ChangeReason = "read_because_config_unknown"
+	ReasonReadBecauseDependencyPending  ChangeReason = "read_because_dependency_pending"
+	ReasonReadBecauseCheckNested        ChangeReason = "read_because_check_nested"
+)
+
+func changeReason(reason plans.ResourceInstanceChangeActionReason) ChangeReason {
+	switch reason {
+	case plans.ResourceInstanceChangeNoReason:
+		return ReasonNone
+	case plans.ResourceInstanceReplaceBecauseTainted:
+		return ReasonTainted
+	case plans.ResourceInstanceReplaceByRequest:
+		return ReasonRequested
+	case plans.ResourceInstanceReplaceBecauseCannotUpdate:
+		return ReasonCannotUpdate
+	case plans.ResourceInstanceReplaceByTriggers:
+		return ReasonReplaceTriggeredBy
+	case plans.ResourceInstanceDeleteBecauseNoResourceConfig:
+		return ReasonDeleteBecauseNoResourceConfig
+	case plans.ResourceInstanceDeleteBecauseWrongRepetition:
+		return ReasonDeleteBecauseWrongRepetition
+	case plans.ResourceInstanceDeleteBecauseCountIndex:
+		return ReasonDeleteBecauseCountIndex
+	case plans.ResourceInstanceDeleteBecauseEachKey:
+		return ReasonDeleteBecauseEachKey
+	case plans.ResourceInstanceDeleteBecauseNoModule:
+		return ReasonDeleteBecauseNoModule
+	case plans.ResourceInstanceReadBecauseConfigUnknown:
+		return ReasonReadBecauseConfigUnknown
+	case plans.ResourceInstanceDeleteBecauseNoMoveTarget:
+		return ReasonDeleteBecauseNoMoveTarget
+	case plans.ResourceInstanceReadBecauseDependencyPending:
+		return ReasonReadBecauseDependencyPending
+	case plans.ResourceInstanceReadBecauseCheckNested:
+		return ReasonReadBecauseCheckNested
+	default:
+		// This should never happen, but there's no good way to guarantee
+		// exhaustive handling of the enum, so a generic fall back is better
+		// than a misleading result or a panic
+		return ReasonUnknown
+	}
+}
diff --git a/v1.5.7/internal/command/views/json/change_summary.go b/v1.5.7/internal/command/views/json/change_summary.go
new file mode 100644
index 0000000..3915c5c
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/change_summary.go
@@ -0,0 +1,44 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package json
+
+import "fmt"
+
+type Operation string
+
+const (
+	OperationApplied   Operation = "apply"
+	OperationDestroyed Operation = "destroy"
+	OperationPlanned   Operation = "plan"
+)
+
+type ChangeSummary struct {
+	Add       int       `json:"add"`
+	Change    int       `json:"change"`
+	Import    int       `json:"import"`
+	Remove    int       `json:"remove"`
+	Operation Operation `json:"operation"`
+}
+
+// The summary strings for apply and plan are accidentally a public interface
+// used by Terraform Cloud and Terraform Enterprise, so the exact formats of
+// these strings are important.
+func (cs *ChangeSummary) String() string {
+	switch cs.Operation {
+	case OperationApplied:
+		if cs.Import > 0 {
+			return fmt.Sprintf("Apply complete! Resources: %d imported, %d added, %d changed, %d destroyed.", cs.Import, cs.Add, cs.Change, cs.Remove)
+		}
+		return fmt.Sprintf("Apply complete! Resources: %d added, %d changed, %d destroyed.", cs.Add, cs.Change, cs.Remove)
+	case OperationDestroyed:
+		return fmt.Sprintf("Destroy complete! Resources: %d destroyed.", cs.Remove)
+	case OperationPlanned:
+		if cs.Import > 0 {
+			return fmt.Sprintf("Plan: %d to import, %d to add, %d to change, %d to destroy.", cs.Import, cs.Add, cs.Change, cs.Remove)
+		}
+		return fmt.Sprintf("Plan: %d to add, %d to change, %d to destroy.", cs.Add, cs.Change, cs.Remove)
+	default:
+		return fmt.Sprintf("%s: %d add, %d change, %d destroy", cs.Operation, cs.Add, cs.Change, cs.Remove)
+	}
+}
diff --git a/v1.5.7/internal/command/views/json/diagnostic.go b/v1.5.7/internal/command/views/json/diagnostic.go
new file mode 100644
index 0000000..ea7a409
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/diagnostic.go
@@ -0,0 +1,493 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package json
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcled"
+	"github.com/hashicorp/hcl/v2/hclparse"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// These severities map to the tfdiags.Severity values, plus an explicit
+// unknown in case that enum grows without us noticing here.
+const (
+	DiagnosticSeverityUnknown = "unknown"
+	DiagnosticSeverityError   = "error"
+	DiagnosticSeverityWarning = "warning"
+)
+
+// Diagnostic represents any tfdiags.Diagnostic value. The simplest form has
+// just a severity, single line summary, and optional detail. If there is more
+// information about the source of the diagnostic, this is represented in the
+// range field.
+type Diagnostic struct {
+	Severity string             `json:"severity"`
+	Summary  string             `json:"summary"`
+	Detail   string             `json:"detail"`
+	Address  string             `json:"address,omitempty"`
+	Range    *DiagnosticRange   `json:"range,omitempty"`
+	Snippet  *DiagnosticSnippet `json:"snippet,omitempty"`
+}
+
+// Pos represents a position in the source code.
+type Pos struct {
+	// Line is a one-based count for the line in the indicated file.
+	Line int `json:"line"`
+
+	// Column is a one-based count of Unicode characters from the start of the line.
+	Column int `json:"column"`
+
+	// Byte is a zero-based offset into the indicated file.
+	Byte int `json:"byte"`
+}
+
+// DiagnosticRange represents the filename and position of the diagnostic
+// subject. This defines the range of the source to be highlighted in the
+// output. Note that the snippet may include additional surrounding source code
+// if the diagnostic has a context range.
+//
+// The Start position is inclusive, and the End position is exclusive. Exact
+// positions are intended for highlighting for human interpretation only and
+// are subject to change.
+type DiagnosticRange struct {
+	Filename string `json:"filename"`
+	Start    Pos    `json:"start"`
+	End      Pos    `json:"end"`
+}
+
+// DiagnosticSnippet represents source code information about the diagnostic.
+// It is possible for a diagnostic to have a source (and therefore a range) but
+// no source code can be found. In this case, the range field will be present and
+// the snippet field will not.
+type DiagnosticSnippet struct {
+	// Context is derived from HCL's hcled.ContextString output. This gives a
+	// high-level summary of the root context of the diagnostic: for example,
+	// the resource block in which an expression causes an error.
+	Context *string `json:"context"`
+
+	// Code is a possibly-multi-line string of Terraform configuration, which
+	// includes both the diagnostic source and any relevant context as defined
+	// by the diagnostic.
+	Code string `json:"code"`
+
+	// StartLine is the line number in the source file for the first line of
+	// the snippet code block. This is not necessarily the same as the value of
+	// Range.Start.Line, as it is possible to have zero or more lines of
+	// context source code before the diagnostic range starts.
+	StartLine int `json:"start_line"`
+
+	// HighlightStartOffset is the character offset into Code at which the
+	// diagnostic source range starts, which ought to be highlighted as such by
+	// the consumer of this data.
+	HighlightStartOffset int `json:"highlight_start_offset"`
+
+	// HighlightEndOffset is the character offset into Code at which the
+	// diagnostic source range ends.
+	HighlightEndOffset int `json:"highlight_end_offset"`
+
+	// Values is a sorted slice of expression values which may be useful in
+	// understanding the source of an error in a complex expression.
+	Values []DiagnosticExpressionValue `json:"values"`
+
+	// FunctionCall is information about a function call whose failure is
+	// being reported by this diagnostic, if any.
+	FunctionCall *DiagnosticFunctionCall `json:"function_call,omitempty"`
+}
+
+// DiagnosticExpressionValue represents an HCL traversal string (e.g.
+// "var.foo") and a statement about its value while the expression was
+// evaluated (e.g. "is a string", "will be known only after apply"). These are
+// intended to help the consumer diagnose why an expression caused a diagnostic
+// to be emitted.
+type DiagnosticExpressionValue struct {
+	Traversal string `json:"traversal"`
+	Statement string `json:"statement"`
+}
+
+// DiagnosticFunctionCall represents a function call whose information is
+// being included as part of a diagnostic snippet.
+type DiagnosticFunctionCall struct {
+	// CalledAs is the full name that was used to call this function,
+	// potentially including namespace prefixes if the function does not belong
+	// to the default function namespace.
+	CalledAs string `json:"called_as"`
+
+	// Signature is a description of the signature of the function that was
+	// called, if any. Might be omitted if we're reporting that a call failed
+	// because the given function name isn't known, for example.
+	Signature *Function `json:"signature,omitempty"`
+}
+
+// NewDiagnostic takes a tfdiags.Diagnostic and a map of configuration sources,
+// and returns a Diagnostic struct.
+func NewDiagnostic(diag tfdiags.Diagnostic, sources map[string][]byte) *Diagnostic {
+	var sev string
+	switch diag.Severity() {
+	case tfdiags.Error:
+		sev = DiagnosticSeverityError
+	case tfdiags.Warning:
+		sev = DiagnosticSeverityWarning
+	default:
+		sev = DiagnosticSeverityUnknown
+	}
+
+	desc := diag.Description()
+
+	diagnostic := &Diagnostic{
+		Severity: sev,
+		Summary:  desc.Summary,
+		Detail:   desc.Detail,
+		Address:  desc.Address,
+	}
+
+	sourceRefs := diag.Source()
+	if sourceRefs.Subject != nil {
+		// We'll borrow HCL's range implementation here, because it has some
+		// handy features to help us produce a nice source code snippet.
+		highlightRange := sourceRefs.Subject.ToHCL()
+
+		// Some diagnostic sources fail to set the end of the subject range.
+		if highlightRange.End == (hcl.Pos{}) {
+			highlightRange.End = highlightRange.Start
+		}
+
+		snippetRange := highlightRange
+		if sourceRefs.Context != nil {
+			snippetRange = sourceRefs.Context.ToHCL()
+		}
+
+		// Make sure the snippet includes the highlight. This should be true
+		// for any reasonable diagnostic, but we'll make sure.
+		snippetRange = hcl.RangeOver(snippetRange, highlightRange)
+
+		// Empty ranges result in odd diagnostic output, so extend the end to
+		// ensure there's at least one byte in the snippet or highlight.
+		if snippetRange.Empty() {
+			snippetRange.End.Byte++
+			snippetRange.End.Column++
+		}
+		if highlightRange.Empty() {
+			highlightRange.End.Byte++
+			highlightRange.End.Column++
+		}
+
+		diagnostic.Range = &DiagnosticRange{
+			Filename: highlightRange.Filename,
+			Start: Pos{
+				Line:   highlightRange.Start.Line,
+				Column: highlightRange.Start.Column,
+				Byte:   highlightRange.Start.Byte,
+			},
+			End: Pos{
+				Line:   highlightRange.End.Line,
+				Column: highlightRange.End.Column,
+				Byte:   highlightRange.End.Byte,
+			},
+		}
+
+		var src []byte
+		if sources != nil {
+			src = sources[highlightRange.Filename]
+		}
+
+		// If we have a source file for the diagnostic, we can emit a code
+		// snippet.
+		if src != nil {
+			diagnostic.Snippet = &DiagnosticSnippet{
+				StartLine: snippetRange.Start.Line,
+
+				// Ensure that the default Values struct is an empty array, as this
+				// makes consuming the JSON structure easier in most languages.
+				Values: []DiagnosticExpressionValue{},
+			}
+
+			file, offset := parseRange(src, highlightRange)
+
+			// Some diagnostics may have a useful top-level context to add to
+			// the code snippet output.
+			contextStr := hcled.ContextString(file, offset-1)
+			if contextStr != "" {
+				diagnostic.Snippet.Context = &contextStr
+			}
+
+			// Build the string of the code snippet, tracking at which byte of
+			// the file the snippet starts.
+			var codeStartByte int
+			sc := hcl.NewRangeScanner(src, highlightRange.Filename, bufio.ScanLines)
+			var code strings.Builder
+			for sc.Scan() {
+				lineRange := sc.Range()
+				if lineRange.Overlaps(snippetRange) {
+					if codeStartByte == 0 && code.Len() == 0 {
+						codeStartByte = lineRange.Start.Byte
+					}
+					code.Write(lineRange.SliceBytes(src))
+					code.WriteRune('\n')
+				}
+			}
+			codeStr := strings.TrimSuffix(code.String(), "\n")
+			diagnostic.Snippet.Code = codeStr
+
+			// Calculate the start and end byte of the highlight range relative
+			// to the code snippet string.
+			start := highlightRange.Start.Byte - codeStartByte
+			end := start + (highlightRange.End.Byte - highlightRange.Start.Byte)
+
+			// We can end up with some quirky results here in edge cases like
+			// when a source range starts or ends at a newline character,
+			// so we'll cap the results at the bounds of the highlight range
+			// so that consumers of this data don't need to contend with
+			// out-of-bounds errors themselves.
+			if start < 0 {
+				start = 0
+			} else if start > len(codeStr) {
+				start = len(codeStr)
+			}
+			if end < 0 {
+				end = 0
+			} else if end > len(codeStr) {
+				end = len(codeStr)
+			}
+
+			diagnostic.Snippet.HighlightStartOffset = start
+			diagnostic.Snippet.HighlightEndOffset = end
+
+			if fromExpr := diag.FromExpr(); fromExpr != nil {
+				// We may also be able to generate information about the dynamic
+				// values of relevant variables at the point of evaluation, then.
+				// This is particularly useful for expressions that get evaluated
+				// multiple times with different values, such as blocks using
+				// "count" and "for_each", or within "for" expressions.
+				expr := fromExpr.Expression
+				ctx := fromExpr.EvalContext
+				vars := expr.Variables()
+				values := make([]DiagnosticExpressionValue, 0, len(vars))
+				seen := make(map[string]struct{}, len(vars))
+				includeUnknown := tfdiags.DiagnosticCausedByUnknown(diag)
+				includeSensitive := tfdiags.DiagnosticCausedBySensitive(diag)
+			Traversals:
+				for _, traversal := range vars {
+					for len(traversal) > 1 {
+						val, diags := traversal.TraverseAbs(ctx)
+						if diags.HasErrors() {
+							// Skip anything that generates errors, since we probably
+							// already have the same error in our diagnostics set
+							// already.
+							traversal = traversal[:len(traversal)-1]
+							continue
+						}
+
+						traversalStr := traversalStr(traversal)
+						if _, exists := seen[traversalStr]; exists {
+							continue Traversals // don't show duplicates when the same variable is referenced multiple times
+						}
+						value := DiagnosticExpressionValue{
+							Traversal: traversalStr,
+						}
+						switch {
+						case val.HasMark(marks.Sensitive):
+							// We only mention a sensitive value if the diagnostic
+							// we're rendering is explicitly marked as being
+							// caused by sensitive values, because otherwise
+							// readers tend to be misled into thinking the error
+							// is caused by the sensitive value even when it isn't.
+							if !includeSensitive {
+								continue Traversals
+							}
+							// Even when we do mention one, we keep it vague
+							// in order to minimize the chance of giving away
+							// whatever was sensitive about it.
+							value.Statement = "has a sensitive value"
+						case !val.IsKnown():
+							// We'll avoid saying anything about unknown or
+							// "known after apply" unless the diagnostic is
+							// explicitly marked as being caused by unknown
+							// values, because otherwise readers tend to be
+							// misled into thinking the error is caused by the
+							// unknown value even when it isn't.
+							if ty := val.Type(); ty != cty.DynamicPseudoType {
+								if includeUnknown {
+									value.Statement = fmt.Sprintf("is a %s, known only after apply", ty.FriendlyName())
+								} else {
+									value.Statement = fmt.Sprintf("is a %s", ty.FriendlyName())
+								}
+							} else {
+								if !includeUnknown {
+									continue Traversals
+								}
+								value.Statement = "will be known only after apply"
+							}
+						default:
+							value.Statement = fmt.Sprintf("is %s", compactValueStr(val))
+						}
+						values = append(values, value)
+						seen[traversalStr] = struct{}{}
+					}
+				}
+				sort.Slice(values, func(i, j int) bool {
+					return values[i].Traversal < values[j].Traversal
+				})
+				diagnostic.Snippet.Values = values
+
+				if callInfo := tfdiags.ExtraInfo[hclsyntax.FunctionCallDiagExtra](diag); callInfo != nil && callInfo.CalledFunctionName() != "" {
+					calledAs := callInfo.CalledFunctionName()
+					baseName := calledAs
+					if idx := strings.LastIndex(baseName, "::"); idx >= 0 {
+						baseName = baseName[idx+2:]
+					}
+					callInfo := &DiagnosticFunctionCall{
+						CalledAs: calledAs,
+					}
+					if f, ok := ctx.Functions[calledAs]; ok {
+						callInfo.Signature = DescribeFunction(baseName, f)
+					}
+					diagnostic.Snippet.FunctionCall = callInfo
+				}
+
+			}
+
+		}
+	}
+
+	return diagnostic
+}
+
+func parseRange(src []byte, rng hcl.Range) (*hcl.File, int) {
+	filename := rng.Filename
+	offset := rng.Start.Byte
+
+	// We need to re-parse here to get a *hcl.File we can interrogate. This
+	// is not awesome since we presumably already parsed the file earlier too,
+	// but this re-parsing is architecturally simpler than retaining all of
+	// the hcl.File objects and we only do this in the case of an error anyway
+	// so the overhead here is not a big problem.
+	parser := hclparse.NewParser()
+	var file *hcl.File
+
+	// Ignore diagnostics here as there is nothing we can do with them.
+	if strings.HasSuffix(filename, ".json") {
+		file, _ = parser.ParseJSON(src, filename)
+	} else {
+		file, _ = parser.ParseHCL(src, filename)
+	}
+
+	return file, offset
+}
+
+// compactValueStr produces a compact, single-line summary of a given value
+// that is suitable for display in the UI.
+//
+// For primitives it returns a full representation, while for more complex
+// types it instead summarizes the type, size, etc to produce something
+// that is hopefully still somewhat useful but not as verbose as a rendering
+// of the entire data structure.
+func compactValueStr(val cty.Value) string {
+	// This is a specialized subset of value rendering tailored to producing
+	// helpful but concise messages in diagnostics. It is not comprehensive
+	// nor intended to be used for other purposes.
+
+	if val.HasMark(marks.Sensitive) {
+		// We check this in here just to make sure, but note that the caller
+		// of compactValueStr ought to have already checked this and skipped
+		// calling into compactValueStr anyway, so this shouldn't actually
+		// be reachable.
+		return "(sensitive value)"
+	}
+
+	// WARNING: We've only checked that the value isn't sensitive _shallowly_
+	// here, and so we must never show any element values from complex types
+	// in here. However, it's fine to show map keys and attribute names because
+	// those are never sensitive in isolation: the entire value would be
+	// sensitive in that case.
+
+	ty := val.Type()
+	switch {
+	case val.IsNull():
+		return "null"
+	case !val.IsKnown():
+		// Should never happen here because we should filter before we get
+		// in here, but we'll do something reasonable rather than panic.
+		return "(not yet known)"
+	case ty == cty.Bool:
+		if val.True() {
+			return "true"
+		}
+		return "false"
+	case ty == cty.Number:
+		bf := val.AsBigFloat()
+		return bf.Text('g', 10)
+	case ty == cty.String:
+		// Go string syntax is not exactly the same as HCL native string syntax,
+		// but we'll accept the minor edge-cases where this is different here
+		// for now, just to get something reasonable here.
+		return fmt.Sprintf("%q", val.AsString())
+	case ty.IsCollectionType() || ty.IsTupleType():
+		l := val.LengthInt()
+		switch l {
+		case 0:
+			return "empty " + ty.FriendlyName()
+		case 1:
+			return ty.FriendlyName() + " with 1 element"
+		default:
+			return fmt.Sprintf("%s with %d elements", ty.FriendlyName(), l)
+		}
+	case ty.IsObjectType():
+		atys := ty.AttributeTypes()
+		l := len(atys)
+		switch l {
+		case 0:
+			return "object with no attributes"
+		case 1:
+			var name string
+			for k := range atys {
+				name = k
+			}
+			return fmt.Sprintf("object with 1 attribute %q", name)
+		default:
+			return fmt.Sprintf("object with %d attributes", l)
+		}
+	default:
+		return ty.FriendlyName()
+	}
+}
+
+// traversalStr produces a representation of an HCL traversal that is compact,
+// resembles HCL native syntax, and is suitable for display in the UI.
+func traversalStr(traversal hcl.Traversal) string {
+	// This is a specialized subset of traversal rendering tailored to
+	// producing helpful contextual messages in diagnostics. It is not
+	// comprehensive nor intended to be used for other purposes.
+
+	var buf bytes.Buffer
+	for _, step := range traversal {
+		switch tStep := step.(type) {
+		case hcl.TraverseRoot:
+			buf.WriteString(tStep.Name)
+		case hcl.TraverseAttr:
+			buf.WriteByte('.')
+			buf.WriteString(tStep.Name)
+		case hcl.TraverseIndex:
+			buf.WriteByte('[')
+			if keyTy := tStep.Key.Type(); keyTy.IsPrimitiveType() {
+				buf.WriteString(compactValueStr(tStep.Key))
+			} else {
+				// We'll just use a placeholder for more complex values,
+				// since otherwise our result could grow ridiculously long.
+				buf.WriteString("...")
+			}
+			buf.WriteByte(']')
+		}
+	}
+	return buf.String()
+}
diff --git a/v1.5.7/internal/command/views/json/diagnostic_test.go b/v1.5.7/internal/command/views/json/diagnostic_test.go
new file mode 100644
index 0000000..1524bdf
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/diagnostic_test.go
@@ -0,0 +1,954 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package json
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcltest"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestNewDiagnostic(t *testing.T) {
+	// Common HCL for diags with source ranges. This does not have any real
+	// semantic errors, but we can synthesize fake HCL errors which will
+	// exercise the diagnostic rendering code using this
+	sources := map[string][]byte{
+		"test.tf": []byte(`resource "test_resource" "test" {
+  foo = var.boop["hello!"]
+  bar = {
+    baz = maybe
+  }
+}
+`),
+		"short.tf":       []byte("bad source code"),
+		"odd-comment.tf": []byte("foo\n\n#\n"),
+		"values.tf": []byte(`[
+  var.a,
+  var.b,
+  var.c,
+  var.d,
+  var.e,
+  var.f,
+  var.g,
+  var.h,
+  var.i,
+  var.j,
+  var.k,
+]
+`),
+	}
+	testCases := map[string]struct {
+		diag interface{} // allow various kinds of diags
+		want *Diagnostic
+	}{
+		"sourceless warning": {
+			tfdiags.Sourceless(
+				tfdiags.Warning,
+				"Oh no",
+				"Something is broken",
+			),
+			&Diagnostic{
+				Severity: "warning",
+				Summary:  "Oh no",
+				Detail:   "Something is broken",
+			},
+		},
+		"error with source code unavailable": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Bad news",
+				Detail:   "It went wrong",
+				Subject: &hcl.Range{
+					Filename: "modules/oops/missing.tf",
+					Start:    hcl.Pos{Line: 1, Column: 6, Byte: 5},
+					End:      hcl.Pos{Line: 2, Column: 12, Byte: 33},
+				},
+			},
+			&Diagnostic{
+				Severity: "error",
+				Summary:  "Bad news",
+				Detail:   "It went wrong",
+				Range: &DiagnosticRange{
+					Filename: "modules/oops/missing.tf",
+					Start: Pos{
+						Line:   1,
+						Column: 6,
+						Byte:   5,
+					},
+					End: Pos{
+						Line:   2,
+						Column: 12,
+						Byte:   33,
+					},
+				},
+			},
+		},
+		"error with source code subject": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Tiny explosion",
+				Detail:   "Unexpected detonation while parsing",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 10, Byte: 9},
+					End:      hcl.Pos{Line: 1, Column: 25, Byte: 24},
+				},
+			},
+			&Diagnostic{
+				Severity: "error",
+				Summary:  "Tiny explosion",
+				Detail:   "Unexpected detonation while parsing",
+				Range: &DiagnosticRange{
+					Filename: "test.tf",
+					Start: Pos{
+						Line:   1,
+						Column: 10,
+						Byte:   9,
+					},
+					End: Pos{
+						Line:   1,
+						Column: 25,
+						Byte:   24,
+					},
+				},
+				Snippet: &DiagnosticSnippet{
+					Context:              strPtr(`resource "test_resource" "test"`),
+					Code:                 `resource "test_resource" "test" {`,
+					StartLine:            1,
+					HighlightStartOffset: 9,
+					HighlightEndOffset:   24,
+					Values:               []DiagnosticExpressionValue{},
+				},
+			},
+		},
+		"error with source code subject but no context": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Nonsense input",
+				Detail:   "What you wrote makes no sense",
+				Subject: &hcl.Range{
+					Filename: "short.tf",
+					Start:    hcl.Pos{Line: 1, Column: 5, Byte: 4},
+					End:      hcl.Pos{Line: 1, Column: 10, Byte: 9},
+				},
+			},
+			&Diagnostic{
+				Severity: "error",
+				Summary:  "Nonsense input",
+				Detail:   "What you wrote makes no sense",
+				Range: &DiagnosticRange{
+					Filename: "short.tf",
+					Start: Pos{
+						Line:   1,
+						Column: 5,
+						Byte:   4,
+					},
+					End: Pos{
+						Line:   1,
+						Column: 10,
+						Byte:   9,
+					},
+				},
+				Snippet: &DiagnosticSnippet{
+					Context:              nil,
+					Code:                 (`bad source code`),
+					StartLine:            (1),
+					HighlightStartOffset: (4),
+					HighlightEndOffset:   (9),
+					Values:               []DiagnosticExpressionValue{},
+				},
+			},
+		},
+		"error with multi-line snippet": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "In this house we respect booleans",
+				Detail:   "True or false, there is no maybe",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 4, Column: 11, Byte: 81},
+					End:      hcl.Pos{Line: 4, Column: 16, Byte: 86},
+				},
+				Context: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 3, Column: 3, Byte: 63},
+					End:      hcl.Pos{Line: 5, Column: 4, Byte: 90},
+				},
+			},
+			&Diagnostic{
+				Severity: "error",
+				Summary:  "In this house we respect booleans",
+				Detail:   "True or false, there is no maybe",
+				Range: &DiagnosticRange{
+					Filename: "test.tf",
+					Start: Pos{
+						Line:   4,
+						Column: 11,
+						Byte:   81,
+					},
+					End: Pos{
+						Line:   4,
+						Column: 16,
+						Byte:   86,
+					},
+				},
+				Snippet: &DiagnosticSnippet{
+					Context:              strPtr(`resource "test_resource" "test"`),
+					Code:                 "  bar = {\n    baz = maybe\n  }",
+					StartLine:            3,
+					HighlightStartOffset: 20,
+					HighlightEndOffset:   25,
+					Values:               []DiagnosticExpressionValue{},
+				},
+			},
+		},
+		"error with empty highlight range at end of source code": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "You forgot something",
+				Detail:   "Please finish your thought",
+				Subject: &hcl.Range{
+					Filename: "short.tf",
+					Start:    hcl.Pos{Line: 1, Column: 16, Byte: 15},
+					End:      hcl.Pos{Line: 1, Column: 16, Byte: 15},
+				},
+			},
+			&Diagnostic{
+				Severity: "error",
+				Summary:  "You forgot something",
+				Detail:   "Please finish your thought",
+				Range: &DiagnosticRange{
+					Filename: "short.tf",
+					Start: Pos{
+						Line:   1,
+						Column: 16,
+						Byte:   15,
+					},
+					End: Pos{
+						Line:   1,
+						Column: 17,
+						Byte:   16,
+					},
+				},
+				Snippet: &DiagnosticSnippet{
+					Code:                 ("bad source code"),
+					StartLine:            (1),
+					HighlightStartOffset: (15),
+					HighlightEndOffset:   (15),
+					Values:               []DiagnosticExpressionValue{},
+				},
+			},
+		},
+		"error with unset highlight end position": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "There is no end",
+				Detail:   "But there is a beginning",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 1, Column: 16, Byte: 15},
+					End:      hcl.Pos{Line: 0, Column: 0, Byte: 0},
+				},
+			},
+			&Diagnostic{
+				Severity: "error",
+				Summary:  "There is no end",
+				Detail:   "But there is a beginning",
+				Range: &DiagnosticRange{
+					Filename: "test.tf",
+					Start: Pos{
+						Line:   1,
+						Column: 16,
+						Byte:   15,
+					},
+					End: Pos{
+						Line:   1,
+						Column: 17,
+						Byte:   16,
+					},
+				},
+				Snippet: &DiagnosticSnippet{
+					Context:              strPtr(`resource "test_resource" "test"`),
+					Code:                 `resource "test_resource" "test" {`,
+					StartLine:            1,
+					HighlightStartOffset: 15,
+					HighlightEndOffset:   16,
+					Values:               []DiagnosticExpressionValue{},
+				},
+			},
+		},
+		"error whose range starts at a newline": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid newline",
+				Detail:   "How awkward!",
+				Subject: &hcl.Range{
+					Filename: "odd-comment.tf",
+					Start:    hcl.Pos{Line: 2, Column: 5, Byte: 4},
+					End:      hcl.Pos{Line: 3, Column: 1, Byte: 6},
+				},
+			},
+			&Diagnostic{
+				Severity: "error",
+				Summary:  "Invalid newline",
+				Detail:   "How awkward!",
+				Range: &DiagnosticRange{
+					Filename: "odd-comment.tf",
+					Start: Pos{
+						Line:   2,
+						Column: 5,
+						Byte:   4,
+					},
+					End: Pos{
+						Line:   3,
+						Column: 1,
+						Byte:   6,
+					},
+				},
+				Snippet: &DiagnosticSnippet{
+					Code:      `#`,
+					StartLine: 2,
+					Values:    []DiagnosticExpressionValue{},
+
+					// Due to the range starting at a newline on a blank
+					// line, we end up stripping off the initial newline
+					// to produce only a one-line snippet. That would
+					// therefore cause the start offset to naturally be
+					// -1, just before the Code we returned, but then we
+					// force it to zero so that the result will still be
+					// in range for a byte-oriented slice of Code.
+					HighlightStartOffset: 0,
+					HighlightEndOffset:   1,
+				},
+			},
+		},
+		"error with source code subject and known expression": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Wrong noises",
+				Detail:   "Biological sounds are not allowed",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 2, Column: 9, Byte: 42},
+					End:      hcl.Pos{Line: 2, Column: 26, Byte: 59},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "var"},
+					hcl.TraverseAttr{Name: "boop"},
+					hcl.TraverseIndex{Key: cty.StringVal("hello!")},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"var": cty.ObjectVal(map[string]cty.Value{
+							"boop": cty.MapVal(map[string]cty.Value{
+								"hello!": cty.StringVal("bleurgh"),
+							}),
+						}),
+					},
+				},
+			},
+			&Diagnostic{
+				Severity: "error",
+				Summary:  "Wrong noises",
+				Detail:   "Biological sounds are not allowed",
+				Range: &DiagnosticRange{
+					Filename: "test.tf",
+					Start: Pos{
+						Line:   2,
+						Column: 9,
+						Byte:   42,
+					},
+					End: Pos{
+						Line:   2,
+						Column: 26,
+						Byte:   59,
+					},
+				},
+				Snippet: &DiagnosticSnippet{
+					Context:              strPtr(`resource "test_resource" "test"`),
+					Code:                 (`  foo = var.boop["hello!"]`),
+					StartLine:            (2),
+					HighlightStartOffset: (8),
+					HighlightEndOffset:   (25),
+					Values: []DiagnosticExpressionValue{
+						{
+							Traversal: `var.boop["hello!"]`,
+							Statement: `is "bleurgh"`,
+						},
+					},
+				},
+			},
+		},
+		"error with source code subject and expression referring to sensitive value": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Wrong noises",
+				Detail:   "Biological sounds are not allowed",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 2, Column: 9, Byte: 42},
+					End:      hcl.Pos{Line: 2, Column: 26, Byte: 59},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "var"},
+					hcl.TraverseAttr{Name: "boop"},
+					hcl.TraverseIndex{Key: cty.StringVal("hello!")},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"var": cty.ObjectVal(map[string]cty.Value{
+							"boop": cty.MapVal(map[string]cty.Value{
+								"hello!": cty.StringVal("bleurgh").Mark(marks.Sensitive),
+							}),
+						}),
+					},
+				},
+				Extra: diagnosticCausedBySensitive(true),
+			},
+			&Diagnostic{
+				Severity: "error",
+				Summary:  "Wrong noises",
+				Detail:   "Biological sounds are not allowed",
+				Range: &DiagnosticRange{
+					Filename: "test.tf",
+					Start: Pos{
+						Line:   2,
+						Column: 9,
+						Byte:   42,
+					},
+					End: Pos{
+						Line:   2,
+						Column: 26,
+						Byte:   59,
+					},
+				},
+				Snippet: &DiagnosticSnippet{
+					Context:              strPtr(`resource "test_resource" "test"`),
+					Code:                 (`  foo = var.boop["hello!"]`),
+					StartLine:            (2),
+					HighlightStartOffset: (8),
+					HighlightEndOffset:   (25),
+					Values: []DiagnosticExpressionValue{
+						{
+							Traversal: `var.boop["hello!"]`,
+							Statement: `has a sensitive value`,
+						},
+					},
+				},
+			},
+		},
+		"error with source code subject and expression referring to sensitive value when not caused by sensitive values": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Wrong noises",
+				Detail:   "Biological sounds are not allowed",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 2, Column: 9, Byte: 42},
+					End:      hcl.Pos{Line: 2, Column: 26, Byte: 59},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "var"},
+					hcl.TraverseAttr{Name: "boop"},
+					hcl.TraverseIndex{Key: cty.StringVal("hello!")},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"var": cty.ObjectVal(map[string]cty.Value{
+							"boop": cty.MapVal(map[string]cty.Value{
+								"hello!": cty.StringVal("bleurgh").Mark(marks.Sensitive),
+							}),
+						}),
+					},
+				},
+			},
+			&Diagnostic{
+				Severity: "error",
+				Summary:  "Wrong noises",
+				Detail:   "Biological sounds are not allowed",
+				Range: &DiagnosticRange{
+					Filename: "test.tf",
+					Start: Pos{
+						Line:   2,
+						Column: 9,
+						Byte:   42,
+					},
+					End: Pos{
+						Line:   2,
+						Column: 26,
+						Byte:   59,
+					},
+				},
+				Snippet: &DiagnosticSnippet{
+					Context:              strPtr(`resource "test_resource" "test"`),
+					Code:                 (`  foo = var.boop["hello!"]`),
+					StartLine:            (2),
+					HighlightStartOffset: (8),
+					HighlightEndOffset:   (25),
+					Values:               []DiagnosticExpressionValue{
+						// The sensitive value is filtered out because this is
+						// not a sensitive-value-related diagnostic message.
+					},
+				},
+			},
+		},
+		"error with source code subject and expression referring to a collection containing a sensitive value": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Wrong noises",
+				Detail:   "Biological sounds are not allowed",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 2, Column: 9, Byte: 42},
+					End:      hcl.Pos{Line: 2, Column: 26, Byte: 59},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "var"},
+					hcl.TraverseAttr{Name: "boop"},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"var": cty.ObjectVal(map[string]cty.Value{
+							"boop": cty.MapVal(map[string]cty.Value{
+								"hello!": cty.StringVal("bleurgh").Mark(marks.Sensitive),
+							}),
+						}),
+					},
+				},
+			},
+			&Diagnostic{
+				Severity: "error",
+				Summary:  "Wrong noises",
+				Detail:   "Biological sounds are not allowed",
+				Range: &DiagnosticRange{
+					Filename: "test.tf",
+					Start: Pos{
+						Line:   2,
+						Column: 9,
+						Byte:   42,
+					},
+					End: Pos{
+						Line:   2,
+						Column: 26,
+						Byte:   59,
+					},
+				},
+				Snippet: &DiagnosticSnippet{
+					Context:              strPtr(`resource "test_resource" "test"`),
+					Code:                 (`  foo = var.boop["hello!"]`),
+					StartLine:            (2),
+					HighlightStartOffset: (8),
+					HighlightEndOffset:   (25),
+					Values: []DiagnosticExpressionValue{
+						{
+							Traversal: `var.boop`,
+							Statement: `is map of string with 1 element`,
+						},
+					},
+				},
+			},
+		},
+		"error with source code subject and unknown string expression": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Wrong noises",
+				Detail:   "Biological sounds are not allowed",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 2, Column: 9, Byte: 42},
+					End:      hcl.Pos{Line: 2, Column: 26, Byte: 59},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "var"},
+					hcl.TraverseAttr{Name: "boop"},
+					hcl.TraverseIndex{Key: cty.StringVal("hello!")},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"var": cty.ObjectVal(map[string]cty.Value{
+							"boop": cty.MapVal(map[string]cty.Value{
+								"hello!": cty.UnknownVal(cty.String),
+							}),
+						}),
+					},
+				},
+				Extra: diagnosticCausedByUnknown(true),
+			},
+			&Diagnostic{
+				Severity: "error",
+				Summary:  "Wrong noises",
+				Detail:   "Biological sounds are not allowed",
+				Range: &DiagnosticRange{
+					Filename: "test.tf",
+					Start: Pos{
+						Line:   2,
+						Column: 9,
+						Byte:   42,
+					},
+					End: Pos{
+						Line:   2,
+						Column: 26,
+						Byte:   59,
+					},
+				},
+				Snippet: &DiagnosticSnippet{
+					Context:              strPtr(`resource "test_resource" "test"`),
+					Code:                 (`  foo = var.boop["hello!"]`),
+					StartLine:            (2),
+					HighlightStartOffset: (8),
+					HighlightEndOffset:   (25),
+					Values: []DiagnosticExpressionValue{
+						{
+							Traversal: `var.boop["hello!"]`,
+							Statement: `is a string, known only after apply`,
+						},
+					},
+				},
+			},
+		},
+		"error with source code subject and unknown expression of unknown type": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Wrong noises",
+				Detail:   "Biological sounds are not allowed",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 2, Column: 9, Byte: 42},
+					End:      hcl.Pos{Line: 2, Column: 26, Byte: 59},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "var"},
+					hcl.TraverseAttr{Name: "boop"},
+					hcl.TraverseIndex{Key: cty.StringVal("hello!")},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"var": cty.ObjectVal(map[string]cty.Value{
+							"boop": cty.MapVal(map[string]cty.Value{
+								"hello!": cty.UnknownVal(cty.DynamicPseudoType),
+							}),
+						}),
+					},
+				},
+				Extra: diagnosticCausedByUnknown(true),
+			},
+			&Diagnostic{
+				Severity: "error",
+				Summary:  "Wrong noises",
+				Detail:   "Biological sounds are not allowed",
+				Range: &DiagnosticRange{
+					Filename: "test.tf",
+					Start: Pos{
+						Line:   2,
+						Column: 9,
+						Byte:   42,
+					},
+					End: Pos{
+						Line:   2,
+						Column: 26,
+						Byte:   59,
+					},
+				},
+				Snippet: &DiagnosticSnippet{
+					Context:              strPtr(`resource "test_resource" "test"`),
+					Code:                 (`  foo = var.boop["hello!"]`),
+					StartLine:            (2),
+					HighlightStartOffset: (8),
+					HighlightEndOffset:   (25),
+					Values: []DiagnosticExpressionValue{
+						{
+							Traversal: `var.boop["hello!"]`,
+							Statement: `will be known only after apply`,
+						},
+					},
+				},
+			},
+		},
+		"error with source code subject and unknown expression of unknown type when not caused by unknown values": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Wrong noises",
+				Detail:   "Biological sounds are not allowed",
+				Subject: &hcl.Range{
+					Filename: "test.tf",
+					Start:    hcl.Pos{Line: 2, Column: 9, Byte: 42},
+					End:      hcl.Pos{Line: 2, Column: 26, Byte: 59},
+				},
+				Expression: hcltest.MockExprTraversal(hcl.Traversal{
+					hcl.TraverseRoot{Name: "var"},
+					hcl.TraverseAttr{Name: "boop"},
+					hcl.TraverseIndex{Key: cty.StringVal("hello!")},
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"var": cty.ObjectVal(map[string]cty.Value{
+							"boop": cty.MapVal(map[string]cty.Value{
+								"hello!": cty.UnknownVal(cty.DynamicPseudoType),
+							}),
+						}),
+					},
+				},
+			},
+			&Diagnostic{
+				Severity: "error",
+				Summary:  "Wrong noises",
+				Detail:   "Biological sounds are not allowed",
+				Range: &DiagnosticRange{
+					Filename: "test.tf",
+					Start: Pos{
+						Line:   2,
+						Column: 9,
+						Byte:   42,
+					},
+					End: Pos{
+						Line:   2,
+						Column: 26,
+						Byte:   59,
+					},
+				},
+				Snippet: &DiagnosticSnippet{
+					Context:              strPtr(`resource "test_resource" "test"`),
+					Code:                 (`  foo = var.boop["hello!"]`),
+					StartLine:            (2),
+					HighlightStartOffset: (8),
+					HighlightEndOffset:   (25),
+					Values:               []DiagnosticExpressionValue{
+						// The unknown value is filtered out because this is
+						// not an unknown-value-related diagnostic message.
+					},
+				},
+			},
+		},
+		"error with source code subject with multiple expression values": {
+			&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Catastrophic failure",
+				Detail:   "Basically, everything went wrong",
+				Subject: &hcl.Range{
+					Filename: "values.tf",
+					Start:    hcl.Pos{Line: 1, Column: 1, Byte: 0},
+					End:      hcl.Pos{Line: 13, Column: 2, Byte: 102},
+				},
+				Expression: hcltest.MockExprList([]hcl.Expression{
+					hcltest.MockExprTraversalSrc("var.a"),
+					hcltest.MockExprTraversalSrc("var.b"),
+					hcltest.MockExprTraversalSrc("var.c"),
+					hcltest.MockExprTraversalSrc("var.d"),
+					hcltest.MockExprTraversalSrc("var.e"),
+					hcltest.MockExprTraversalSrc("var.f"),
+					hcltest.MockExprTraversalSrc("var.g"),
+					hcltest.MockExprTraversalSrc("var.h"),
+					hcltest.MockExprTraversalSrc("var.i"),
+					hcltest.MockExprTraversalSrc("var.j"),
+					hcltest.MockExprTraversalSrc("var.k"),
+				}),
+				EvalContext: &hcl.EvalContext{
+					Variables: map[string]cty.Value{
+						"var": cty.ObjectVal(map[string]cty.Value{
+							"a": cty.True,
+							"b": cty.NumberFloatVal(123.45),
+							"c": cty.NullVal(cty.String),
+							"d": cty.StringVal("secret").Mark(marks.Sensitive),
+							"e": cty.False,
+							"f": cty.ListValEmpty(cty.String),
+							"g": cty.MapVal(map[string]cty.Value{
+								"boop": cty.StringVal("beep"),
+							}),
+							"h": cty.ListVal([]cty.Value{
+								cty.StringVal("boop"),
+								cty.StringVal("beep"),
+								cty.StringVal("blorp"),
+							}),
+							"i": cty.EmptyObjectVal,
+							"j": cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.StringVal("bar"),
+							}),
+							"k": cty.ObjectVal(map[string]cty.Value{
+								"a": cty.True,
+								"b": cty.False,
+							}),
+						}),
+					},
+				},
+				Extra: diagnosticCausedBySensitive(true),
+			},
+			&Diagnostic{
+				Severity: "error",
+				Summary:  "Catastrophic failure",
+				Detail:   "Basically, everything went wrong",
+				Range: &DiagnosticRange{
+					Filename: "values.tf",
+					Start: Pos{
+						Line:   1,
+						Column: 1,
+						Byte:   0,
+					},
+					End: Pos{
+						Line:   13,
+						Column: 2,
+						Byte:   102,
+					},
+				},
+				Snippet: &DiagnosticSnippet{
+					Code: `[
+  var.a,
+  var.b,
+  var.c,
+  var.d,
+  var.e,
+  var.f,
+  var.g,
+  var.h,
+  var.i,
+  var.j,
+  var.k,
+]`,
+					StartLine:            (1),
+					HighlightStartOffset: (0),
+					HighlightEndOffset:   (102),
+					Values: []DiagnosticExpressionValue{
+						{
+							Traversal: `var.a`,
+							Statement: `is true`,
+						},
+						{
+							Traversal: `var.b`,
+							Statement: `is 123.45`,
+						},
+						{
+							Traversal: `var.c`,
+							Statement: `is null`,
+						},
+						{
+							Traversal: `var.d`,
+							Statement: `has a sensitive value`,
+						},
+						{
+							Traversal: `var.e`,
+							Statement: `is false`,
+						},
+						{
+							Traversal: `var.f`,
+							Statement: `is empty list of string`,
+						},
+						{
+							Traversal: `var.g`,
+							Statement: `is map of string with 1 element`,
+						},
+						{
+							Traversal: `var.h`,
+							Statement: `is list of string with 3 elements`,
+						},
+						{
+							Traversal: `var.i`,
+							Statement: `is object with no attributes`,
+						},
+						{
+							Traversal: `var.j`,
+							Statement: `is object with 1 attribute "foo"`,
+						},
+						{
+							Traversal: `var.k`,
+							Statement: `is object with 2 attributes`,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			// Convert the diag into a tfdiags.Diagnostic
+			var diags tfdiags.Diagnostics
+			diags = diags.Append(tc.diag)
+
+			got := NewDiagnostic(diags[0], sources)
+			if !cmp.Equal(tc.want, got) {
+				t.Fatalf("wrong result\n:%s", cmp.Diff(tc.want, got))
+			}
+		})
+
+		t.Run(fmt.Sprintf("golden test for %s", name), func(t *testing.T) {
+			// Convert the diag into a tfdiags.Diagnostic
+			var diags tfdiags.Diagnostics
+			diags = diags.Append(tc.diag)
+
+			got := NewDiagnostic(diags[0], sources)
+
+			// Render the diagnostic to indented JSON
+			gotBytes, err := json.MarshalIndent(got, "", "  ")
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			// Compare against the golden reference
+			filename := path.Join(
+				"testdata",
+				"diagnostic",
+				fmt.Sprintf("%s.json", strings.ReplaceAll(name, " ", "-")),
+			)
+
+			// Generate golden reference by uncommenting the next two lines:
+			// gotBytes = append(gotBytes, '\n')
+			// os.WriteFile(filename, gotBytes, 0644)
+
+			wantFile, err := os.Open(filename)
+			if err != nil {
+				t.Fatalf("failed to open golden file: %s", err)
+			}
+			defer wantFile.Close()
+			wantBytes, err := ioutil.ReadAll(wantFile)
+			if err != nil {
+				t.Fatalf("failed to read output file: %s", err)
+			}
+
+			// Don't care about leading or trailing whitespace
+			gotString := strings.TrimSpace(string(gotBytes))
+			wantString := strings.TrimSpace(string(wantBytes))
+
+			if !cmp.Equal(wantString, gotString) {
+				t.Fatalf("wrong result\n:%s", cmp.Diff(wantString, gotString))
+			}
+		})
+	}
+}
+
+// Helper function to make constructing literal Diagnostics easier. There
+// are fields which are pointer-to-string to ensure that the rendered JSON
+// results in `null` for an empty value, rather than `""`.
+func strPtr(s string) *string { return &s }
+
+// diagnosticCausedByUnknown is a testing helper for exercising our logic
+// for selectively showing unknown values alongside our source snippets for
+// diagnostics that are explicitly marked as being caused by unknown values.
+type diagnosticCausedByUnknown bool
+
+var _ tfdiags.DiagnosticExtraBecauseUnknown = diagnosticCausedByUnknown(true)
+
+func (e diagnosticCausedByUnknown) DiagnosticCausedByUnknown() bool {
+	return bool(e)
+}
+
+// diagnosticCausedBySensitive is a testing helper for exercising our logic
+// for selectively showing sensitive values alongside our source snippets for
+// diagnostics that are explicitly marked as being caused by sensitive values.
+type diagnosticCausedBySensitive bool
+
+var _ tfdiags.DiagnosticExtraBecauseSensitive = diagnosticCausedBySensitive(true)
+
+func (e diagnosticCausedBySensitive) DiagnosticCausedBySensitive() bool {
+	return bool(e)
+}
diff --git a/v1.5.7/internal/command/views/json/function.go b/v1.5.7/internal/command/views/json/function.go
new file mode 100644
index 0000000..7875304
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/function.go
@@ -0,0 +1,115 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package json
+
+import (
+	"encoding/json"
+
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+)
+
+// Function is a description of the JSON representation of the signature of
+// a function callable from the Terraform language.
+type Function struct {
+	// Name is the leaf name of the function, without any namespace prefix.
+	Name string `json:"name"`
+
+	Params        []FunctionParam `json:"params"`
+	VariadicParam *FunctionParam  `json:"variadic_param,omitempty"`
+
+	// ReturnType is type constraint which is a static approximation of the
+	// possibly-dynamic return type of the function.
+	ReturnType json.RawMessage `json:"return_type"`
+
+	Description     string `json:"description,omitempty"`
+	DescriptionKind string `json:"description_kind,omitempty"`
+}
+
+// FunctionParam represents a single parameter to a function, as represented
+// by type Function.
+type FunctionParam struct {
+	// Name is a name for the function which is used primarily for
+	// documentation purposes, because function arguments are positional
+	// and therefore don't appear directly in configuration source code.
+	Name string `json:"name"`
+
+	// Type is a type constraint which is a static approximation of the
+	// possibly-dynamic type of the parameter. Particular functions may
+	// have additional requirements that a type constraint alone cannot
+	// represent.
+	Type json.RawMessage `json:"type"`
+
+	// Maybe some of the other fields in function.Parameter would be
+	// interesting to describe here too, but we'll wait to see if there
+	// is a use-case first.
+
+	Description     string `json:"description,omitempty"`
+	DescriptionKind string `json:"description_kind,omitempty"`
+}
+
+// DescribeFunction returns a description of the signature of the given cty
+// function, as a pointer to this package's serializable type Function.
+func DescribeFunction(name string, f function.Function) *Function {
+	ret := &Function{
+		Name: name,
+	}
+
+	params := f.Params()
+	ret.Params = make([]FunctionParam, len(params))
+	typeCheckArgs := make([]cty.Type, len(params), len(params)+1)
+	for i, param := range params {
+		ret.Params[i] = describeFunctionParam(&param)
+		typeCheckArgs[i] = param.Type
+	}
+	if varParam := f.VarParam(); varParam != nil {
+		descParam := describeFunctionParam(varParam)
+		ret.VariadicParam = &descParam
+		typeCheckArgs = append(typeCheckArgs, varParam.Type)
+	}
+
+	retType, err := f.ReturnType(typeCheckArgs)
+	if err != nil {
+		// Getting an error when type-checking with exactly the type constraints
+		// the function called for is weird, so we'll just treat it as if it
+		// has a dynamic return type instead, for our purposes here.
+		// One reason this can happen is for a function which has a variadic
+		// parameter but has logic inside it which considers it invalid to
+		// specify exactly one argument for that parameter (since that's what
+		// we did in typeCheckArgs as an approximation of a valid call above.)
+		retType = cty.DynamicPseudoType
+	}
+
+	if raw, err := retType.MarshalJSON(); err != nil {
+		// Again, we'll treat any errors as if the function is dynamically
+		// typed because it would be weird to get here.
+		ret.ReturnType = json.RawMessage(`"dynamic"`)
+	} else {
+		ret.ReturnType = json.RawMessage(raw)
+	}
+
+	// We don't currently have any sense of descriptions for functions and
+	// their parameters, so we'll just leave those fields unpopulated for now.
+
+	return ret
+}
+
+func describeFunctionParam(p *function.Parameter) FunctionParam {
+	ret := FunctionParam{
+		Name: p.Name,
+	}
+
+	if raw, err := p.Type.MarshalJSON(); err != nil {
+		// We'll treat any errors as if the function is dynamically
+		// typed because it would be weird to get here.
+		ret.Type = json.RawMessage(`"dynamic"`)
+	} else {
+		ret.Type = json.RawMessage(raw)
+	}
+
+	// We don't currently have any sense of descriptions for functions and
+	// their parameters, so we'll just leave those fields unpopulated for now.
+
+	return ret
+}
diff --git a/v1.5.7/internal/command/views/json/function_test.go b/v1.5.7/internal/command/views/json/function_test.go
new file mode 100644
index 0000000..a9cdeec
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/function_test.go
@@ -0,0 +1,95 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package json
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty/function"
+	"github.com/zclconf/go-cty/cty/function/stdlib"
+)
+
+func TestDescribeFunction(t *testing.T) {
+	// NOTE: This test case is referring to some real functions in other
+	// packages. and so if those functions change signature later it will
+	// probably make some cases here fail. If that is the cause of the failure,
+	// it's fine to update the test here to match rather than to revert the
+	// change to the function signature, as long as the change to the
+	// function signature is otherwise within the bounds of our compatibility
+	// promises.
+
+	tests := map[string]struct {
+		Function function.Function
+		Want     *Function
+	}{
+		"upper": {
+			Function: stdlib.UpperFunc,
+			Want: &Function{
+				Name: "upper",
+				Params: []FunctionParam{
+					{
+						Name: "str",
+						Type: json.RawMessage(`"string"`),
+					},
+				},
+				ReturnType: json.RawMessage(`"string"`),
+			},
+		},
+		"coalesce": {
+			Function: stdlib.CoalesceFunc,
+			Want: &Function{
+				Name:   "coalesce",
+				Params: []FunctionParam{},
+				VariadicParam: &FunctionParam{
+					Name: "vals",
+					Type: json.RawMessage(`"dynamic"`),
+				},
+				ReturnType: json.RawMessage(`"dynamic"`),
+			},
+		},
+		"join": {
+			Function: stdlib.JoinFunc,
+			Want: &Function{
+				Name: "join",
+				Params: []FunctionParam{
+					{
+						Name: "separator",
+						Type: json.RawMessage(`"string"`),
+					},
+				},
+				VariadicParam: &FunctionParam{
+					Name: "lists",
+					Type: json.RawMessage(`["list","string"]`),
+				},
+				ReturnType: json.RawMessage(`"string"`),
+			},
+		},
+		"jsonencode": {
+			Function: stdlib.JSONEncodeFunc,
+			Want: &Function{
+				Name: "jsonencode",
+				Params: []FunctionParam{
+					{
+						Name: "val",
+						Type: json.RawMessage(`"dynamic"`),
+					},
+				},
+				ReturnType: json.RawMessage(`"string"`),
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got := DescribeFunction(name, test.Function)
+			want := test.Want
+
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/views/json/hook.go b/v1.5.7/internal/command/views/json/hook.go
new file mode 100644
index 0000000..40adcbc
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/hook.go
@@ -0,0 +1,379 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package json
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+type Hook interface {
+	HookType() MessageType
+	String() string
+}
+
+// ApplyStart: triggered by PreApply hook
+type applyStart struct {
+	Resource   ResourceAddr `json:"resource"`
+	Action     ChangeAction `json:"action"`
+	IDKey      string       `json:"id_key,omitempty"`
+	IDValue    string       `json:"id_value,omitempty"`
+	actionVerb string
+}
+
+var _ Hook = (*applyStart)(nil)
+
+func (h *applyStart) HookType() MessageType {
+	return MessageApplyStart
+}
+
+func (h *applyStart) String() string {
+	var id string
+	if h.IDKey != "" && h.IDValue != "" {
+		id = fmt.Sprintf(" [%s=%s]", h.IDKey, h.IDValue)
+	}
+	return fmt.Sprintf("%s: %s...%s", h.Resource.Addr, h.actionVerb, id)
+}
+
+func NewApplyStart(addr addrs.AbsResourceInstance, action plans.Action, idKey string, idValue string) Hook {
+	hook := &applyStart{
+		Resource:   newResourceAddr(addr),
+		Action:     changeAction(action),
+		IDKey:      idKey,
+		IDValue:    idValue,
+		actionVerb: startActionVerb(action),
+	}
+
+	return hook
+}
+
+// ApplyProgress: currently triggered by a timer started on PreApply. In
+// future, this might also be triggered by provider progress reporting.
+type applyProgress struct {
+	Resource   ResourceAddr `json:"resource"`
+	Action     ChangeAction `json:"action"`
+	Elapsed    float64      `json:"elapsed_seconds"`
+	actionVerb string
+	elapsed    time.Duration
+}
+
+var _ Hook = (*applyProgress)(nil)
+
+func (h *applyProgress) HookType() MessageType {
+	return MessageApplyProgress
+}
+
+func (h *applyProgress) String() string {
+	return fmt.Sprintf("%s: Still %s... [%s elapsed]", h.Resource.Addr, h.actionVerb, h.elapsed)
+}
+
+func NewApplyProgress(addr addrs.AbsResourceInstance, action plans.Action, elapsed time.Duration) Hook {
+	return &applyProgress{
+		Resource:   newResourceAddr(addr),
+		Action:     changeAction(action),
+		Elapsed:    elapsed.Seconds(),
+		actionVerb: progressActionVerb(action),
+		elapsed:    elapsed,
+	}
+}
+
+// ApplyComplete: triggered by PostApply hook
+type applyComplete struct {
+	Resource   ResourceAddr `json:"resource"`
+	Action     ChangeAction `json:"action"`
+	IDKey      string       `json:"id_key,omitempty"`
+	IDValue    string       `json:"id_value,omitempty"`
+	Elapsed    float64      `json:"elapsed_seconds"`
+	actionNoun string
+	elapsed    time.Duration
+}
+
+var _ Hook = (*applyComplete)(nil)
+
+func (h *applyComplete) HookType() MessageType {
+	return MessageApplyComplete
+}
+
+func (h *applyComplete) String() string {
+	var id string
+	if h.IDKey != "" && h.IDValue != "" {
+		id = fmt.Sprintf(" [%s=%s]", h.IDKey, h.IDValue)
+	}
+	return fmt.Sprintf("%s: %s complete after %s%s", h.Resource.Addr, h.actionNoun, h.elapsed, id)
+}
+
+func NewApplyComplete(addr addrs.AbsResourceInstance, action plans.Action, idKey, idValue string, elapsed time.Duration) Hook {
+	return &applyComplete{
+		Resource:   newResourceAddr(addr),
+		Action:     changeAction(action),
+		IDKey:      idKey,
+		IDValue:    idValue,
+		Elapsed:    elapsed.Seconds(),
+		actionNoun: actionNoun(action),
+		elapsed:    elapsed,
+	}
+}
+
+// ApplyErrored: triggered by PostApply hook on failure. This will be followed
+// by diagnostics when the apply finishes.
+type applyErrored struct {
+	Resource   ResourceAddr `json:"resource"`
+	Action     ChangeAction `json:"action"`
+	Elapsed    float64      `json:"elapsed_seconds"`
+	actionNoun string
+	elapsed    time.Duration
+}
+
+var _ Hook = (*applyErrored)(nil)
+
+func (h *applyErrored) HookType() MessageType {
+	return MessageApplyErrored
+}
+
+func (h *applyErrored) String() string {
+	return fmt.Sprintf("%s: %s errored after %s", h.Resource.Addr, h.actionNoun, h.elapsed)
+}
+
+func NewApplyErrored(addr addrs.AbsResourceInstance, action plans.Action, elapsed time.Duration) Hook {
+	return &applyErrored{
+		Resource:   newResourceAddr(addr),
+		Action:     changeAction(action),
+		Elapsed:    elapsed.Seconds(),
+		actionNoun: actionNoun(action),
+		elapsed:    elapsed,
+	}
+}
+
+// ProvisionStart: triggered by PreProvisionInstanceStep hook
+type provisionStart struct {
+	Resource    ResourceAddr `json:"resource"`
+	Provisioner string       `json:"provisioner"`
+}
+
+var _ Hook = (*provisionStart)(nil)
+
+func (h *provisionStart) HookType() MessageType {
+	return MessageProvisionStart
+}
+
+func (h *provisionStart) String() string {
+	return fmt.Sprintf("%s: Provisioning with '%s'...", h.Resource.Addr, h.Provisioner)
+}
+
+func NewProvisionStart(addr addrs.AbsResourceInstance, provisioner string) Hook {
+	return &provisionStart{
+		Resource:    newResourceAddr(addr),
+		Provisioner: provisioner,
+	}
+}
+
+// ProvisionProgress: triggered by ProvisionOutput hook
+type provisionProgress struct {
+	Resource    ResourceAddr `json:"resource"`
+	Provisioner string       `json:"provisioner"`
+	Output      string       `json:"output"`
+}
+
+var _ Hook = (*provisionProgress)(nil)
+
+func (h *provisionProgress) HookType() MessageType {
+	return MessageProvisionProgress
+}
+
+func (h *provisionProgress) String() string {
+	return fmt.Sprintf("%s: (%s): %s", h.Resource.Addr, h.Provisioner, h.Output)
+}
+
+func NewProvisionProgress(addr addrs.AbsResourceInstance, provisioner string, output string) Hook {
+	return &provisionProgress{
+		Resource:    newResourceAddr(addr),
+		Provisioner: provisioner,
+		Output:      output,
+	}
+}
+
+// ProvisionComplete: triggered by PostProvisionInstanceStep hook
+type provisionComplete struct {
+	Resource    ResourceAddr `json:"resource"`
+	Provisioner string       `json:"provisioner"`
+}
+
+var _ Hook = (*provisionComplete)(nil)
+
+func (h *provisionComplete) HookType() MessageType {
+	return MessageProvisionComplete
+}
+
+func (h *provisionComplete) String() string {
+	return fmt.Sprintf("%s: (%s) Provisioning complete", h.Resource.Addr, h.Provisioner)
+}
+
+func NewProvisionComplete(addr addrs.AbsResourceInstance, provisioner string) Hook {
+	return &provisionComplete{
+		Resource:    newResourceAddr(addr),
+		Provisioner: provisioner,
+	}
+}
+
+// ProvisionErrored: triggered by PostProvisionInstanceStep hook on failure.
+// This will be followed by diagnostics when the apply finishes.
+type provisionErrored struct {
+	Resource    ResourceAddr `json:"resource"`
+	Provisioner string       `json:"provisioner"`
+}
+
+var _ Hook = (*provisionErrored)(nil)
+
+func (h *provisionErrored) HookType() MessageType {
+	return MessageProvisionErrored
+}
+
+func (h *provisionErrored) String() string {
+	return fmt.Sprintf("%s: (%s) Provisioning errored", h.Resource.Addr, h.Provisioner)
+}
+
+func NewProvisionErrored(addr addrs.AbsResourceInstance, provisioner string) Hook {
+	return &provisionErrored{
+		Resource:    newResourceAddr(addr),
+		Provisioner: provisioner,
+	}
+}
+
+// RefreshStart: triggered by PreRefresh hook
+type refreshStart struct {
+	Resource ResourceAddr `json:"resource"`
+	IDKey    string       `json:"id_key,omitempty"`
+	IDValue  string       `json:"id_value,omitempty"`
+}
+
+var _ Hook = (*refreshStart)(nil)
+
+func (h *refreshStart) HookType() MessageType {
+	return MessageRefreshStart
+}
+
+func (h *refreshStart) String() string {
+	var id string
+	if h.IDKey != "" && h.IDValue != "" {
+		id = fmt.Sprintf(" [%s=%s]", h.IDKey, h.IDValue)
+	}
+	return fmt.Sprintf("%s: Refreshing state...%s", h.Resource.Addr, id)
+}
+
+func NewRefreshStart(addr addrs.AbsResourceInstance, idKey, idValue string) Hook {
+	return &refreshStart{
+		Resource: newResourceAddr(addr),
+		IDKey:    idKey,
+		IDValue:  idValue,
+	}
+}
+
+// RefreshComplete: triggered by PostRefresh hook
+type refreshComplete struct {
+	Resource ResourceAddr `json:"resource"`
+	IDKey    string       `json:"id_key,omitempty"`
+	IDValue  string       `json:"id_value,omitempty"`
+}
+
+var _ Hook = (*refreshComplete)(nil)
+
+func (h *refreshComplete) HookType() MessageType {
+	return MessageRefreshComplete
+}
+
+func (h *refreshComplete) String() string {
+	var id string
+	if h.IDKey != "" && h.IDValue != "" {
+		id = fmt.Sprintf(" [%s=%s]", h.IDKey, h.IDValue)
+	}
+	return fmt.Sprintf("%s: Refresh complete%s", h.Resource.Addr, id)
+}
+
+func NewRefreshComplete(addr addrs.AbsResourceInstance, idKey, idValue string) Hook {
+	return &refreshComplete{
+		Resource: newResourceAddr(addr),
+		IDKey:    idKey,
+		IDValue:  idValue,
+	}
+}
+
+// Convert the subset of plans.Action values we expect to receive into a
+// present-tense verb for the applyStart hook message.
+func startActionVerb(action plans.Action) string {
+	switch action {
+	case plans.Create:
+		return "Creating"
+	case plans.Update:
+		return "Modifying"
+	case plans.Delete:
+		return "Destroying"
+	case plans.Read:
+		return "Refreshing"
+	case plans.CreateThenDelete, plans.DeleteThenCreate:
+		// This is not currently possible to reach, as we receive separate
+		// passes for create and delete
+		return "Replacing"
+	case plans.NoOp:
+		// This should never be possible: a no-op planned change should not
+		// be applied. We'll fall back to "Applying".
+		fallthrough
+	default:
+		return "Applying"
+	}
+}
+
+// Convert the subset of plans.Action values we expect to receive into a
+// present-tense verb for the applyProgress hook message. This will be
+// prefixed with "Still ", so it is lower-case.
+func progressActionVerb(action plans.Action) string {
+	switch action {
+	case plans.Create:
+		return "creating"
+	case plans.Update:
+		return "modifying"
+	case plans.Delete:
+		return "destroying"
+	case plans.Read:
+		return "refreshing"
+	case plans.CreateThenDelete, plans.DeleteThenCreate:
+		// This is not currently possible to reach, as we receive separate
+		// passes for create and delete
+		return "replacing"
+	case plans.NoOp:
+		// This should never be possible: a no-op planned change should not
+		// be applied. We'll fall back to "applying".
+		fallthrough
+	default:
+		return "applying"
+	}
+}
+
+// Convert the subset of plans.Action values we expect to receive into a
+// noun for the applyComplete and applyErrored hook messages. This will be
+// combined into a phrase like "Creation complete after 1m4s".
+func actionNoun(action plans.Action) string {
+	switch action {
+	case plans.Create:
+		return "Creation"
+	case plans.Update:
+		return "Modifications"
+	case plans.Delete:
+		return "Destruction"
+	case plans.Read:
+		return "Refresh"
+	case plans.CreateThenDelete, plans.DeleteThenCreate:
+		// This is not currently possible to reach, as we receive separate
+		// passes for create and delete
+		return "Replacement"
+	case plans.NoOp:
+		// This should never be possible: a no-op planned change should not
+		// be applied. We'll fall back to "Apply".
+		fallthrough
+	default:
+		return "Apply"
+	}
+}
diff --git a/v1.5.7/internal/command/views/json/importing.go b/v1.5.7/internal/command/views/json/importing.go
new file mode 100644
index 0000000..b79709b
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/importing.go
@@ -0,0 +1,16 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package json
+
+// Importing contains metadata about a resource change that includes an import
+// action.
+//
+// Every field in here should be treated as optional as future versions do not
+// make a guarantee that they will retain the format of this change.
+//
+// Consumers should be capable of rendering/parsing the Importing struct even
+// if it does not have the ID field set.
+type Importing struct {
+	ID string `json:"id,omitempty"`
+}
diff --git a/v1.5.7/internal/command/views/json/message_types.go b/v1.5.7/internal/command/views/json/message_types.go
new file mode 100644
index 0000000..45bf453
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/message_types.go
@@ -0,0 +1,31 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package json
+
+type MessageType string
+
+const (
+	// Generic messages
+	MessageVersion    MessageType = "version"
+	MessageLog        MessageType = "log"
+	MessageDiagnostic MessageType = "diagnostic"
+
+	// Operation results
+	MessageResourceDrift MessageType = "resource_drift"
+	MessagePlannedChange MessageType = "planned_change"
+	MessageChangeSummary MessageType = "change_summary"
+	MessageOutputs       MessageType = "outputs"
+
+	// Hook-driven messages
+	MessageApplyStart        MessageType = "apply_start"
+	MessageApplyProgress     MessageType = "apply_progress"
+	MessageApplyComplete     MessageType = "apply_complete"
+	MessageApplyErrored      MessageType = "apply_errored"
+	MessageProvisionStart    MessageType = "provision_start"
+	MessageProvisionProgress MessageType = "provision_progress"
+	MessageProvisionComplete MessageType = "provision_complete"
+	MessageProvisionErrored  MessageType = "provision_errored"
+	MessageRefreshStart      MessageType = "refresh_start"
+	MessageRefreshComplete   MessageType = "refresh_complete"
+)
diff --git a/v1.5.7/internal/command/views/json/output.go b/v1.5.7/internal/command/views/json/output.go
new file mode 100644
index 0000000..3e87c67
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/output.go
@@ -0,0 +1,78 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package json
+
+import (
+	"encoding/json"
+	"fmt"
+
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+type Output struct {
+	Sensitive bool            `json:"sensitive"`
+	Type      json.RawMessage `json:"type,omitempty"`
+	Value     json.RawMessage `json:"value,omitempty"`
+	Action    ChangeAction    `json:"action,omitempty"`
+}
+
+type Outputs map[string]Output
+
+func OutputsFromMap(outputValues map[string]*states.OutputValue) (Outputs, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	outputs := make(map[string]Output, len(outputValues))
+
+	for name, ov := range outputValues {
+		unmarked, _ := ov.Value.UnmarkDeep()
+		value, err := ctyjson.Marshal(unmarked, unmarked.Type())
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				fmt.Sprintf("Error serializing output %q", name),
+				fmt.Sprintf("Error: %s", err),
+			))
+			return nil, diags
+		}
+		valueType, err := ctyjson.MarshalType(unmarked.Type())
+		if err != nil {
+			diags = diags.Append(err)
+			return nil, diags
+		}
+
+		var redactedValue json.RawMessage
+		if !ov.Sensitive {
+			redactedValue = json.RawMessage(value)
+		}
+
+		outputs[name] = Output{
+			Sensitive: ov.Sensitive,
+			Type:      json.RawMessage(valueType),
+			Value:     redactedValue,
+		}
+	}
+
+	return outputs, nil
+}
+
+func OutputsFromChanges(changes []*plans.OutputChangeSrc) Outputs {
+	outputs := make(map[string]Output, len(changes))
+
+	for _, change := range changes {
+		outputs[change.Addr.OutputValue.Name] = Output{
+			Sensitive: change.Sensitive,
+			Action:    changeAction(change.Action),
+		}
+	}
+
+	return outputs
+}
+
+func (o Outputs) String() string {
+	return fmt.Sprintf("Outputs: %d", len(o))
+}
diff --git a/v1.5.7/internal/command/views/json/output_test.go b/v1.5.7/internal/command/views/json/output_test.go
new file mode 100644
index 0000000..057adb5
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/output_test.go
@@ -0,0 +1,183 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package json
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestOutputsFromMap(t *testing.T) {
+	got, diags := OutputsFromMap(map[string]*states.OutputValue{
+		// Normal non-sensitive output
+		"boop": {
+			Value: cty.NumberIntVal(1234),
+		},
+		// Sensitive string output
+		"beep": {
+			Value:     cty.StringVal("horse-battery").Mark(marks.Sensitive),
+			Sensitive: true,
+		},
+		// Sensitive object output which is marked at the leaf
+		"blorp": {
+			Value: cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ObjectVal(map[string]cty.Value{
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("oh, hi").Mark(marks.Sensitive),
+					}),
+				}),
+			}),
+			Sensitive: true,
+		},
+		// Null value
+		"honk": {
+			Value: cty.NullVal(cty.Map(cty.Bool)),
+		},
+	})
+	if len(diags) > 0 {
+		t.Fatal(diags.Err())
+	}
+
+	want := Outputs{
+		"boop": {
+			Sensitive: false,
+			Type:      json.RawMessage(`"number"`),
+			Value:     json.RawMessage(`1234`),
+		},
+		"beep": {
+			Sensitive: true,
+			Type:      json.RawMessage(`"string"`),
+		},
+		"blorp": {
+			Sensitive: true,
+			Type:      json.RawMessage(`["object",{"a":["object",{"b":["object",{"c":"string"}]}]}]`),
+		},
+		"honk": {
+			Sensitive: false,
+			Type:      json.RawMessage(`["map","bool"]`),
+			Value:     json.RawMessage(`null`),
+		},
+	}
+
+	if !cmp.Equal(want, got) {
+		t.Fatalf("unexpected result\n%s", cmp.Diff(want, got))
+	}
+}
+
+func TestOutputsFromChanges(t *testing.T) {
+	root := addrs.RootModuleInstance
+	num, err := plans.NewDynamicValue(cty.NumberIntVal(1234), cty.Number)
+	if err != nil {
+		t.Fatalf("unexpected error creating dynamic value: %v", err)
+	}
+	str, err := plans.NewDynamicValue(cty.StringVal("1234"), cty.String)
+	if err != nil {
+		t.Fatalf("unexpected error creating dynamic value: %v", err)
+	}
+
+	got := OutputsFromChanges([]*plans.OutputChangeSrc{
+		// Unchanged output "boop", value 1234
+		{
+			Addr: root.OutputValue("boop"),
+			ChangeSrc: plans.ChangeSrc{
+				Action: plans.NoOp,
+				Before: num,
+				After:  num,
+			},
+			Sensitive: false,
+		},
+		// New output "beep", value 1234
+		{
+			Addr: root.OutputValue("beep"),
+			ChangeSrc: plans.ChangeSrc{
+				Action: plans.Create,
+				Before: nil,
+				After:  num,
+			},
+			Sensitive: false,
+		},
+		// Deleted output "blorp", prior value 1234
+		{
+			Addr: root.OutputValue("blorp"),
+			ChangeSrc: plans.ChangeSrc{
+				Action: plans.Delete,
+				Before: num,
+				After:  nil,
+			},
+			Sensitive: false,
+		},
+		// Updated output "honk", prior value 1234, new value "1234"
+		{
+			Addr: root.OutputValue("honk"),
+			ChangeSrc: plans.ChangeSrc{
+				Action: plans.Update,
+				Before: num,
+				After:  str,
+			},
+			Sensitive: false,
+		},
+		// New sensitive output "secret", value "1234"
+		{
+			Addr: root.OutputValue("secret"),
+			ChangeSrc: plans.ChangeSrc{
+				Action: plans.Create,
+				Before: nil,
+				After:  str,
+			},
+			Sensitive: true,
+		},
+	})
+
+	want := Outputs{
+		"boop": {
+			Action:    "noop",
+			Sensitive: false,
+		},
+		"beep": {
+			Action:    "create",
+			Sensitive: false,
+		},
+		"blorp": {
+			Action:    "delete",
+			Sensitive: false,
+		},
+		"honk": {
+			Action:    "update",
+			Sensitive: false,
+		},
+		"secret": {
+			Action:    "create",
+			Sensitive: true,
+		},
+	}
+
+	if !cmp.Equal(want, got) {
+		t.Fatalf("unexpected result\n%s", cmp.Diff(want, got))
+	}
+}
+
+func TestOutputs_String(t *testing.T) {
+	outputs := Outputs{
+		"boop": {
+			Sensitive: false,
+			Type:      json.RawMessage(`"number"`),
+			Value:     json.RawMessage(`1234`),
+		},
+		"beep": {
+			Sensitive: true,
+			Type:      json.RawMessage(`"string"`),
+			Value:     json.RawMessage(`"horse-battery"`),
+		},
+	}
+	if got, want := outputs.String(), "Outputs: 2"; got != want {
+		t.Fatalf("unexpected value\n got: %q\nwant: %q", got, want)
+	}
+}
diff --git a/v1.5.7/internal/command/views/json/resource_addr.go b/v1.5.7/internal/command/views/json/resource_addr.go
new file mode 100644
index 0000000..f5a3ca7
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/resource_addr.go
@@ -0,0 +1,37 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package json
+
+import (
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+type ResourceAddr struct {
+	Addr            string                  `json:"addr"`
+	Module          string                  `json:"module"`
+	Resource        string                  `json:"resource"`
+	ImpliedProvider string                  `json:"implied_provider"`
+	ResourceType    string                  `json:"resource_type"`
+	ResourceName    string                  `json:"resource_name"`
+	ResourceKey     ctyjson.SimpleJSONValue `json:"resource_key"`
+}
+
+func newResourceAddr(addr addrs.AbsResourceInstance) ResourceAddr {
+	resourceKey := ctyjson.SimpleJSONValue{Value: cty.NilVal}
+	if addr.Resource.Key != nil {
+		resourceKey.Value = addr.Resource.Key.Value()
+	}
+	return ResourceAddr{
+		Addr:            addr.String(),
+		Module:          addr.Module.String(),
+		Resource:        addr.Resource.String(),
+		ImpliedProvider: addr.Resource.Resource.ImpliedProvider(),
+		ResourceType:    addr.Resource.Resource.Type,
+		ResourceName:    addr.Resource.Resource.Name,
+		ResourceKey:     resourceKey,
+	}
+}
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/error-whose-range-starts-at-a-newline.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-whose-range-starts-at-a-newline.json
new file mode 100644
index 0000000..27c9d11
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-whose-range-starts-at-a-newline.json
@@ -0,0 +1,26 @@
+{
+  "severity": "error",
+  "summary": "Invalid newline",
+  "detail": "How awkward!",
+  "range": {
+    "filename": "odd-comment.tf",
+    "start": {
+      "line": 2,
+      "column": 5,
+      "byte": 4
+    },
+    "end": {
+      "line": 3,
+      "column": 1,
+      "byte": 6
+    }
+  },
+  "snippet": {
+    "context": null,
+    "code": "#",
+    "start_line": 2,
+    "highlight_start_offset": 0,
+    "highlight_end_offset": 1,
+    "values": []
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-empty-highlight-range-at-end-of-source-code.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-empty-highlight-range-at-end-of-source-code.json
new file mode 100644
index 0000000..e8cd009
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-empty-highlight-range-at-end-of-source-code.json
@@ -0,0 +1,26 @@
+{
+  "severity": "error",
+  "summary": "You forgot something",
+  "detail": "Please finish your thought",
+  "range": {
+    "filename": "short.tf",
+    "start": {
+      "line": 1,
+      "column": 16,
+      "byte": 15
+    },
+    "end": {
+      "line": 1,
+      "column": 17,
+      "byte": 16
+    }
+  },
+  "snippet": {
+    "context": null,
+    "code": "bad source code",
+    "start_line": 1,
+    "highlight_start_offset": 15,
+    "highlight_end_offset": 15,
+    "values": []
+  }
+}
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-multi-line-snippet.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-multi-line-snippet.json
new file mode 100644
index 0000000..5acb67d
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-multi-line-snippet.json
@@ -0,0 +1,26 @@
+{
+  "severity": "error",
+  "summary": "In this house we respect booleans",
+  "detail": "True or false, there is no maybe",
+  "range": {
+    "filename": "test.tf",
+    "start": {
+      "line": 4,
+      "column": 11,
+      "byte": 81
+    },
+    "end": {
+      "line": 4,
+      "column": 16,
+      "byte": 86
+    }
+  },
+  "snippet": {
+    "context": "resource \"test_resource\" \"test\"",
+    "code": "  bar = {\n    baz = maybe\n  }",
+    "start_line": 3,
+    "highlight_start_offset": 20,
+    "highlight_end_offset": 25,
+    "values": []
+  }
+}
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-a-collection-containing-a-sensitive-value.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-a-collection-containing-a-sensitive-value.json
new file mode 100644
index 0000000..e6599fa
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-a-collection-containing-a-sensitive-value.json
@@ -0,0 +1,31 @@
+{
+  "severity": "error",
+  "summary": "Wrong noises",
+  "detail": "Biological sounds are not allowed",
+  "range": {
+    "filename": "test.tf",
+    "start": {
+      "line": 2,
+      "column": 9,
+      "byte": 42
+    },
+    "end": {
+      "line": 2,
+      "column": 26,
+      "byte": 59
+    }
+  },
+  "snippet": {
+    "context": "resource \"test_resource\" \"test\"",
+    "code": "  foo = var.boop[\"hello!\"]",
+    "start_line": 2,
+    "highlight_start_offset": 8,
+    "highlight_end_offset": 25,
+    "values": [
+      {
+        "traversal": "var.boop",
+        "statement": "is map of string with 1 element"
+      }
+    ]
+  }
+}
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value-when-not-caused-by-sensitive-values.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value-when-not-caused-by-sensitive-values.json
new file mode 100644
index 0000000..8d3625d
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value-when-not-caused-by-sensitive-values.json
@@ -0,0 +1,26 @@
+{
+  "severity": "error",
+  "summary": "Wrong noises",
+  "detail": "Biological sounds are not allowed",
+  "range": {
+    "filename": "test.tf",
+    "start": {
+      "line": 2,
+      "column": 9,
+      "byte": 42
+    },
+    "end": {
+      "line": 2,
+      "column": 26,
+      "byte": 59
+    }
+  },
+  "snippet": {
+    "context": "resource \"test_resource\" \"test\"",
+    "code": "  foo = var.boop[\"hello!\"]",
+    "start_line": 2,
+    "highlight_start_offset": 8,
+    "highlight_end_offset": 25,
+    "values": []
+  }
+}
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value.json
new file mode 100644
index 0000000..abffcdb
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value.json
@@ -0,0 +1,31 @@
+{
+  "severity": "error",
+  "summary": "Wrong noises",
+  "detail": "Biological sounds are not allowed",
+  "range": {
+    "filename": "test.tf",
+    "start": {
+      "line": 2,
+      "column": 9,
+      "byte": 42
+    },
+    "end": {
+      "line": 2,
+      "column": 26,
+      "byte": 59
+    }
+  },
+  "snippet": {
+    "context": "resource \"test_resource\" \"test\"",
+    "code": "  foo = var.boop[\"hello!\"]",
+    "start_line": 2,
+    "highlight_start_offset": 8,
+    "highlight_end_offset": 25,
+    "values": [
+      {
+        "traversal": "var.boop[\"hello!\"]",
+        "statement": "has a sensitive value"
+      }
+    ]
+  }
+}
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-known-expression.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-known-expression.json
new file mode 100644
index 0000000..dde961c
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-known-expression.json
@@ -0,0 +1,31 @@
+{
+  "severity": "error",
+  "summary": "Wrong noises",
+  "detail": "Biological sounds are not allowed",
+  "range": {
+    "filename": "test.tf",
+    "start": {
+      "line": 2,
+      "column": 9,
+      "byte": 42
+    },
+    "end": {
+      "line": 2,
+      "column": 26,
+      "byte": 59
+    }
+  },
+  "snippet": {
+    "context": "resource \"test_resource\" \"test\"",
+    "code": "  foo = var.boop[\"hello!\"]",
+    "start_line": 2,
+    "highlight_start_offset": 8,
+    "highlight_end_offset": 25,
+    "values": [
+      {
+        "traversal": "var.boop[\"hello!\"]",
+        "statement": "is \"bleurgh\""
+      }
+    ]
+  }
+}
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type-when-not-caused-by-unknown-values.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type-when-not-caused-by-unknown-values.json
new file mode 100644
index 0000000..8d3625d
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type-when-not-caused-by-unknown-values.json
@@ -0,0 +1,26 @@
+{
+  "severity": "error",
+  "summary": "Wrong noises",
+  "detail": "Biological sounds are not allowed",
+  "range": {
+    "filename": "test.tf",
+    "start": {
+      "line": 2,
+      "column": 9,
+      "byte": 42
+    },
+    "end": {
+      "line": 2,
+      "column": 26,
+      "byte": 59
+    }
+  },
+  "snippet": {
+    "context": "resource \"test_resource\" \"test\"",
+    "code": "  foo = var.boop[\"hello!\"]",
+    "start_line": 2,
+    "highlight_start_offset": 8,
+    "highlight_end_offset": 25,
+    "values": []
+  }
+}
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type.json
new file mode 100644
index 0000000..d8aa3c4
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type.json
@@ -0,0 +1,31 @@
+{
+  "severity": "error",
+  "summary": "Wrong noises",
+  "detail": "Biological sounds are not allowed",
+  "range": {
+    "filename": "test.tf",
+    "start": {
+      "line": 2,
+      "column": 9,
+      "byte": 42
+    },
+    "end": {
+      "line": 2,
+      "column": 26,
+      "byte": 59
+    }
+  },
+  "snippet": {
+    "context": "resource \"test_resource\" \"test\"",
+    "code": "  foo = var.boop[\"hello!\"]",
+    "start_line": 2,
+    "highlight_start_offset": 8,
+    "highlight_end_offset": 25,
+    "values": [
+      {
+        "traversal": "var.boop[\"hello!\"]",
+        "statement": "will be known only after apply"
+      }
+    ]
+  }
+}
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-string-expression.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-string-expression.json
new file mode 100644
index 0000000..8255af8
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-string-expression.json
@@ -0,0 +1,31 @@
+{
+  "severity": "error",
+  "summary": "Wrong noises",
+  "detail": "Biological sounds are not allowed",
+  "range": {
+    "filename": "test.tf",
+    "start": {
+      "line": 2,
+      "column": 9,
+      "byte": 42
+    },
+    "end": {
+      "line": 2,
+      "column": 26,
+      "byte": 59
+    }
+  },
+  "snippet": {
+    "context": "resource \"test_resource\" \"test\"",
+    "code": "  foo = var.boop[\"hello!\"]",
+    "start_line": 2,
+    "highlight_start_offset": 8,
+    "highlight_end_offset": 25,
+    "values": [
+      {
+        "traversal": "var.boop[\"hello!\"]",
+        "statement": "is a string, known only after apply"
+      }
+    ]
+  }
+}
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-but-no-context.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-but-no-context.json
new file mode 100644
index 0000000..9cfafbc
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-but-no-context.json
@@ -0,0 +1,26 @@
+{
+  "severity": "error",
+  "summary": "Nonsense input",
+  "detail": "What you wrote makes no sense",
+  "range": {
+    "filename": "short.tf",
+    "start": {
+      "line": 1,
+      "column": 5,
+      "byte": 4
+    },
+    "end": {
+      "line": 1,
+      "column": 10,
+      "byte": 9
+    }
+  },
+  "snippet": {
+    "context": null,
+    "code": "bad source code",
+    "start_line": 1,
+    "highlight_start_offset": 4,
+    "highlight_end_offset": 9,
+    "values": []
+  }
+}
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-with-multiple-expression-values.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-with-multiple-expression-values.json
new file mode 100644
index 0000000..b88e490
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-with-multiple-expression-values.json
@@ -0,0 +1,71 @@
+{
+  "severity": "error",
+  "summary": "Catastrophic failure",
+  "detail": "Basically, everything went wrong",
+  "range": {
+    "filename": "values.tf",
+    "start": {
+      "line": 1,
+      "column": 1,
+      "byte": 0
+    },
+    "end": {
+      "line": 13,
+      "column": 2,
+      "byte": 102
+    }
+  },
+  "snippet": {
+    "context": null,
+    "code": "[\n  var.a,\n  var.b,\n  var.c,\n  var.d,\n  var.e,\n  var.f,\n  var.g,\n  var.h,\n  var.i,\n  var.j,\n  var.k,\n]",
+    "start_line": 1,
+    "highlight_start_offset": 0,
+    "highlight_end_offset": 102,
+    "values": [
+      {
+        "traversal": "var.a",
+        "statement": "is true"
+      },
+      {
+        "traversal": "var.b",
+        "statement": "is 123.45"
+      },
+      {
+        "traversal": "var.c",
+        "statement": "is null"
+      },
+      {
+        "traversal": "var.d",
+        "statement": "has a sensitive value"
+      },
+      {
+        "traversal": "var.e",
+        "statement": "is false"
+      },
+      {
+        "traversal": "var.f",
+        "statement": "is empty list of string"
+      },
+      {
+        "traversal": "var.g",
+        "statement": "is map of string with 1 element"
+      },
+      {
+        "traversal": "var.h",
+        "statement": "is list of string with 3 elements"
+      },
+      {
+        "traversal": "var.i",
+        "statement": "is object with no attributes"
+      },
+      {
+        "traversal": "var.j",
+        "statement": "is object with 1 attribute \"foo\""
+      },
+      {
+        "traversal": "var.k",
+        "statement": "is object with 2 attributes"
+      }
+    ]
+  }
+}
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject.json
new file mode 100644
index 0000000..762d811
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject.json
@@ -0,0 +1,26 @@
+{
+  "severity": "error",
+  "summary": "Tiny explosion",
+  "detail": "Unexpected detonation while parsing",
+  "range": {
+    "filename": "test.tf",
+    "start": {
+      "line": 1,
+      "column": 10,
+      "byte": 9
+    },
+    "end": {
+      "line": 1,
+      "column": 25,
+      "byte": 24
+    }
+  },
+  "snippet": {
+    "context": "resource \"test_resource\" \"test\"",
+    "code": "resource \"test_resource\" \"test\" {",
+    "start_line": 1,
+    "highlight_start_offset": 9,
+    "highlight_end_offset": 24,
+    "values": []
+  }
+}
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-unavailable.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-unavailable.json
new file mode 100644
index 0000000..2646f47
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-source-code-unavailable.json
@@ -0,0 +1,18 @@
+{
+  "severity": "error",
+  "summary": "Bad news",
+  "detail": "It went wrong",
+  "range": {
+    "filename": "modules/oops/missing.tf",
+    "start": {
+      "line": 1,
+      "column": 6,
+      "byte": 5
+    },
+    "end": {
+      "line": 2,
+      "column": 12,
+      "byte": 33
+    }
+  }
+}
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-unset-highlight-end-position.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-unset-highlight-end-position.json
new file mode 100644
index 0000000..1f7351f
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/error-with-unset-highlight-end-position.json
@@ -0,0 +1,26 @@
+{
+  "severity": "error",
+  "summary": "There is no end",
+  "detail": "But there is a beginning",
+  "range": {
+    "filename": "test.tf",
+    "start": {
+      "line": 1,
+      "column": 16,
+      "byte": 15
+    },
+    "end": {
+      "line": 1,
+      "column": 17,
+      "byte": 16
+    }
+  },
+  "snippet": {
+    "context": "resource \"test_resource\" \"test\"",
+    "code": "resource \"test_resource\" \"test\" {",
+    "start_line": 1,
+    "highlight_start_offset": 15,
+    "highlight_end_offset": 16,
+    "values": []
+  }
+}
diff --git a/v1.5.7/internal/command/views/json/testdata/diagnostic/sourceless-warning.json b/v1.5.7/internal/command/views/json/testdata/diagnostic/sourceless-warning.json
new file mode 100644
index 0000000..56e1718
--- /dev/null
+++ b/v1.5.7/internal/command/views/json/testdata/diagnostic/sourceless-warning.json
@@ -0,0 +1,5 @@
+{
+  "severity": "warning",
+  "summary": "Oh no",
+  "detail": "Something is broken"
+}
diff --git a/v1.5.7/internal/command/views/json_view.go b/v1.5.7/internal/command/views/json_view.go
new file mode 100644
index 0000000..1ae74f5
--- /dev/null
+++ b/v1.5.7/internal/command/views/json_view.go
@@ -0,0 +1,131 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	encJson "encoding/json"
+	"fmt"
+
+	"github.com/hashicorp/go-hclog"
+	"github.com/hashicorp/terraform/internal/command/views/json"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+// This version describes the schema of JSON UI messages. This version must be
+// updated after making any changes to this view, the jsonHook, or any of the
+// command/views/json package.
+const JSON_UI_VERSION = "1.1"
+
+func NewJSONView(view *View) *JSONView {
+	log := hclog.New(&hclog.LoggerOptions{
+		Name:       "terraform.ui",
+		Output:     view.streams.Stdout.File,
+		JSONFormat: true,
+	})
+	jv := &JSONView{
+		log:  log,
+		view: view,
+	}
+	jv.Version()
+	return jv
+}
+
+type JSONView struct {
+	// hclog is used for all output in JSON UI mode. The logger has an internal
+	// mutex to ensure that messages are not interleaved.
+	log hclog.Logger
+
+	// We hold a reference to the view entirely to allow us to access the
+	// ConfigSources function pointer, in order to render source snippets into
+	// diagnostics. This is even more unfortunate than the same reference in the
+	// view.
+	//
+	// Do not be tempted to dereference the configSource value upon logger init,
+	// as it will likely be updated later.
+	view *View
+}
+
+func (v *JSONView) Version() {
+	version := tfversion.String()
+	v.log.Info(
+		fmt.Sprintf("Terraform %s", version),
+		"type", json.MessageVersion,
+		"terraform", version,
+		"ui", JSON_UI_VERSION,
+	)
+}
+
+func (v *JSONView) Log(message string) {
+	v.log.Info(message, "type", json.MessageLog)
+}
+
+func (v *JSONView) StateDump(state string) {
+	v.log.Info(
+		"Emergency state dump",
+		"type", json.MessageLog,
+		"state", encJson.RawMessage(state),
+	)
+}
+
+func (v *JSONView) Diagnostics(diags tfdiags.Diagnostics) {
+	sources := v.view.configSources()
+	for _, diag := range diags {
+		diagnostic := json.NewDiagnostic(diag, sources)
+		switch diag.Severity() {
+		case tfdiags.Warning:
+			v.log.Warn(
+				fmt.Sprintf("Warning: %s", diag.Description().Summary),
+				"type", json.MessageDiagnostic,
+				"diagnostic", diagnostic,
+			)
+		default:
+			v.log.Error(
+				fmt.Sprintf("Error: %s", diag.Description().Summary),
+				"type", json.MessageDiagnostic,
+				"diagnostic", diagnostic,
+			)
+		}
+	}
+}
+
+func (v *JSONView) PlannedChange(c *json.ResourceInstanceChange) {
+	v.log.Info(
+		c.String(),
+		"type", json.MessagePlannedChange,
+		"change", c,
+	)
+}
+
+func (v *JSONView) ResourceDrift(c *json.ResourceInstanceChange) {
+	v.log.Info(
+		fmt.Sprintf("%s: Drift detected (%s)", c.Resource.Addr, c.Action),
+		"type", json.MessageResourceDrift,
+		"change", c,
+	)
+}
+
+func (v *JSONView) ChangeSummary(cs *json.ChangeSummary) {
+	v.log.Info(
+		cs.String(),
+		"type", json.MessageChangeSummary,
+		"changes", cs,
+	)
+}
+
+func (v *JSONView) Hook(h json.Hook) {
+	v.log.Info(
+		h.String(),
+		"type", h.HookType(),
+		"hook", h,
+	)
+}
+
+func (v *JSONView) Outputs(outputs json.Outputs) {
+	v.log.Info(
+		outputs.String(),
+		"type", json.MessageOutputs,
+		"outputs", outputs,
+	)
+}
diff --git a/v1.5.7/internal/command/views/json_view_test.go b/v1.5.7/internal/command/views/json_view_test.go
new file mode 100644
index 0000000..61a6a38
--- /dev/null
+++ b/v1.5.7/internal/command/views/json_view_test.go
@@ -0,0 +1,387 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"encoding/json"
+	"fmt"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+	viewsjson "github.com/hashicorp/terraform/internal/command/views/json"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+// Calling NewJSONView should also always output a version message, which is a
+// convenient way to test that NewJSONView works.
+func TestNewJSONView(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	NewJSONView(NewView(streams))
+
+	version := tfversion.String()
+	want := []map[string]interface{}{
+		{
+			"@level":    "info",
+			"@message":  fmt.Sprintf("Terraform %s", version),
+			"@module":   "terraform.ui",
+			"type":      "version",
+			"terraform": version,
+			"ui":        JSON_UI_VERSION,
+		},
+	}
+
+	testJSONViewOutputEqualsFull(t, done(t).Stdout(), want)
+}
+
+func TestJSONView_Log(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	jv := NewJSONView(NewView(streams))
+
+	jv.Log("hello, world")
+
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": "hello, world",
+			"@module":  "terraform.ui",
+			"type":     "log",
+		},
+	}
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+// This test covers only the basics of JSON diagnostic rendering, as more
+// complex diagnostics are tested elsewhere.
+func TestJSONView_Diagnostics(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	jv := NewJSONView(NewView(streams))
+
+	var diags tfdiags.Diagnostics
+	diags = diags.Append(tfdiags.Sourceless(
+		tfdiags.Warning,
+		`Improper use of "less"`,
+		`You probably mean "10 buckets or fewer"`,
+	))
+	diags = diags.Append(tfdiags.Sourceless(
+		tfdiags.Error,
+		"Unusually stripey cat detected",
+		"Are you sure this random_pet isn't a cheetah?",
+	))
+
+	jv.Diagnostics(diags)
+
+	want := []map[string]interface{}{
+		{
+			"@level":   "warn",
+			"@message": `Warning: Improper use of "less"`,
+			"@module":  "terraform.ui",
+			"type":     "diagnostic",
+			"diagnostic": map[string]interface{}{
+				"severity": "warning",
+				"summary":  `Improper use of "less"`,
+				"detail":   `You probably mean "10 buckets or fewer"`,
+			},
+		},
+		{
+			"@level":   "error",
+			"@message": "Error: Unusually stripey cat detected",
+			"@module":  "terraform.ui",
+			"type":     "diagnostic",
+			"diagnostic": map[string]interface{}{
+				"severity": "error",
+				"summary":  "Unusually stripey cat detected",
+				"detail":   "Are you sure this random_pet isn't a cheetah?",
+			},
+		},
+	}
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func TestJSONView_PlannedChange(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	jv := NewJSONView(NewView(streams))
+
+	foo, diags := addrs.ParseModuleInstanceStr("module.foo")
+	if len(diags) > 0 {
+		t.Fatal(diags.Err())
+	}
+	managed := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_instance", Name: "bar"}
+	cs := &plans.ResourceInstanceChangeSrc{
+		Addr:        managed.Instance(addrs.StringKey("boop")).Absolute(foo),
+		PrevRunAddr: managed.Instance(addrs.StringKey("boop")).Absolute(foo),
+		ChangeSrc: plans.ChangeSrc{
+			Action: plans.Create,
+		},
+	}
+	jv.PlannedChange(viewsjson.NewResourceInstanceChange(cs))
+
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": `module.foo.test_instance.bar["boop"]: Plan to create`,
+			"@module":  "terraform.ui",
+			"type":     "planned_change",
+			"change": map[string]interface{}{
+				"action": "create",
+				"resource": map[string]interface{}{
+					"addr":             `module.foo.test_instance.bar["boop"]`,
+					"implied_provider": "test",
+					"module":           "module.foo",
+					"resource":         `test_instance.bar["boop"]`,
+					"resource_key":     "boop",
+					"resource_name":    "bar",
+					"resource_type":    "test_instance",
+				},
+			},
+		},
+	}
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func TestJSONView_ResourceDrift(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	jv := NewJSONView(NewView(streams))
+
+	foo, diags := addrs.ParseModuleInstanceStr("module.foo")
+	if len(diags) > 0 {
+		t.Fatal(diags.Err())
+	}
+	managed := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_instance", Name: "bar"}
+	cs := &plans.ResourceInstanceChangeSrc{
+		Addr:        managed.Instance(addrs.StringKey("boop")).Absolute(foo),
+		PrevRunAddr: managed.Instance(addrs.StringKey("boop")).Absolute(foo),
+		ChangeSrc: plans.ChangeSrc{
+			Action: plans.Update,
+		},
+	}
+	jv.ResourceDrift(viewsjson.NewResourceInstanceChange(cs))
+
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": `module.foo.test_instance.bar["boop"]: Drift detected (update)`,
+			"@module":  "terraform.ui",
+			"type":     "resource_drift",
+			"change": map[string]interface{}{
+				"action": "update",
+				"resource": map[string]interface{}{
+					"addr":             `module.foo.test_instance.bar["boop"]`,
+					"implied_provider": "test",
+					"module":           "module.foo",
+					"resource":         `test_instance.bar["boop"]`,
+					"resource_key":     "boop",
+					"resource_name":    "bar",
+					"resource_type":    "test_instance",
+				},
+			},
+		},
+	}
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func TestJSONView_ChangeSummary(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	jv := NewJSONView(NewView(streams))
+
+	jv.ChangeSummary(&viewsjson.ChangeSummary{
+		Add:       1,
+		Change:    2,
+		Remove:    3,
+		Operation: viewsjson.OperationApplied,
+	})
+
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": "Apply complete! Resources: 1 added, 2 changed, 3 destroyed.",
+			"@module":  "terraform.ui",
+			"type":     "change_summary",
+			"changes": map[string]interface{}{
+				"add":       float64(1),
+				"import":    float64(0),
+				"change":    float64(2),
+				"remove":    float64(3),
+				"operation": "apply",
+			},
+		},
+	}
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func TestJSONView_ChangeSummaryWithImport(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	jv := NewJSONView(NewView(streams))
+
+	jv.ChangeSummary(&viewsjson.ChangeSummary{
+		Add:       1,
+		Change:    2,
+		Remove:    3,
+		Import:    1,
+		Operation: viewsjson.OperationApplied,
+	})
+
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": "Apply complete! Resources: 1 imported, 1 added, 2 changed, 3 destroyed.",
+			"@module":  "terraform.ui",
+			"type":     "change_summary",
+			"changes": map[string]interface{}{
+				"add":       float64(1),
+				"change":    float64(2),
+				"remove":    float64(3),
+				"import":    float64(1),
+				"operation": "apply",
+			},
+		},
+	}
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func TestJSONView_Hook(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	jv := NewJSONView(NewView(streams))
+
+	foo, diags := addrs.ParseModuleInstanceStr("module.foo")
+	if len(diags) > 0 {
+		t.Fatal(diags.Err())
+	}
+	managed := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_instance", Name: "bar"}
+	addr := managed.Instance(addrs.StringKey("boop")).Absolute(foo)
+	hook := viewsjson.NewApplyComplete(addr, plans.Create, "id", "boop-beep", 34*time.Second)
+
+	jv.Hook(hook)
+
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": `module.foo.test_instance.bar["boop"]: Creation complete after 34s [id=boop-beep]`,
+			"@module":  "terraform.ui",
+			"type":     "apply_complete",
+			"hook": map[string]interface{}{
+				"resource": map[string]interface{}{
+					"addr":             `module.foo.test_instance.bar["boop"]`,
+					"implied_provider": "test",
+					"module":           "module.foo",
+					"resource":         `test_instance.bar["boop"]`,
+					"resource_key":     "boop",
+					"resource_name":    "bar",
+					"resource_type":    "test_instance",
+				},
+				"action":          "create",
+				"id_key":          "id",
+				"id_value":        "boop-beep",
+				"elapsed_seconds": float64(34),
+			},
+		},
+	}
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func TestJSONView_Outputs(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	jv := NewJSONView(NewView(streams))
+
+	jv.Outputs(viewsjson.Outputs{
+		"boop_count": {
+			Sensitive: false,
+			Value:     json.RawMessage(`92`),
+			Type:      json.RawMessage(`"number"`),
+		},
+		"password": {
+			Sensitive: true,
+			Value:     json.RawMessage(`"horse-battery"`),
+			Type:      json.RawMessage(`"string"`),
+		},
+	})
+
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": "Outputs: 2",
+			"@module":  "terraform.ui",
+			"type":     "outputs",
+			"outputs": map[string]interface{}{
+				"boop_count": map[string]interface{}{
+					"sensitive": false,
+					"value":     float64(92),
+					"type":      "number",
+				},
+				"password": map[string]interface{}{
+					"sensitive": true,
+					"value":     "horse-battery",
+					"type":      "string",
+				},
+			},
+		},
+	}
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+// This helper function tests a possibly multi-line JSONView output string
+// against a slice of structs representing the desired log messages. It
+// verifies that the output of JSONView is in JSON log format, one message per
+// line.
+func testJSONViewOutputEqualsFull(t *testing.T, output string, want []map[string]interface{}) {
+	t.Helper()
+
+	// Remove final trailing newline
+	output = strings.TrimSuffix(output, "\n")
+
+	// Split log into lines, each of which should be a JSON log message
+	gotLines := strings.Split(output, "\n")
+
+	if len(gotLines) != len(want) {
+		t.Errorf("unexpected number of messages. got %d, want %d", len(gotLines), len(want))
+	}
+
+	// Unmarshal each line and compare to the expected value
+	for i := range gotLines {
+		var gotStruct map[string]interface{}
+		if i >= len(want) {
+			t.Error("reached end of want messages too soon")
+			break
+		}
+		wantStruct := want[i]
+
+		if err := json.Unmarshal([]byte(gotLines[i]), &gotStruct); err != nil {
+			t.Fatal(err)
+		}
+
+		if timestamp, ok := gotStruct["@timestamp"]; !ok {
+			t.Errorf("message has no timestamp: %#v", gotStruct)
+		} else {
+			// Remove the timestamp value from the struct to allow comparison
+			delete(gotStruct, "@timestamp")
+
+			// Verify the timestamp format
+			if _, err := time.Parse("2006-01-02T15:04:05.000000Z07:00", timestamp.(string)); err != nil {
+				t.Errorf("error parsing timestamp on line %d: %s", i, err)
+			}
+		}
+
+		if !cmp.Equal(wantStruct, gotStruct) {
+			t.Errorf("unexpected output on line %d:\n%s", i, cmp.Diff(wantStruct, gotStruct))
+		}
+	}
+}
+
+// testJSONViewOutputEquals skips the first line of output, since it ought to
+// be a version message that we don't care about for most of our tests.
+func testJSONViewOutputEquals(t *testing.T, output string, want []map[string]interface{}) {
+	t.Helper()
+
+	// Remove up to the first newline
+	index := strings.Index(output, "\n")
+	if index >= 0 {
+		output = output[index+1:]
+	}
+	testJSONViewOutputEqualsFull(t, output, want)
+}
diff --git a/v1.5.7/internal/command/views/operation.go b/v1.5.7/internal/command/views/operation.go
new file mode 100644
index 0000000..d5b5566
--- /dev/null
+++ b/v1.5.7/internal/command/views/operation.go
@@ -0,0 +1,307 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"bytes"
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/format"
+	"github.com/hashicorp/terraform/internal/command/jsonformat"
+	"github.com/hashicorp/terraform/internal/command/jsonplan"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/command/views/json"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+type Operation interface {
+	Interrupted()
+	FatalInterrupt()
+	Stopping()
+	Cancelled(planMode plans.Mode)
+
+	EmergencyDumpState(stateFile *statefile.File) error
+
+	PlannedChange(change *plans.ResourceInstanceChangeSrc)
+	Plan(plan *plans.Plan, schemas *terraform.Schemas)
+	PlanNextStep(planPath string, genConfigPath string)
+
+	Diagnostics(diags tfdiags.Diagnostics)
+}
+
+func NewOperation(vt arguments.ViewType, inAutomation bool, view *View) Operation {
+	switch vt {
+	case arguments.ViewHuman:
+		return &OperationHuman{view: view, inAutomation: inAutomation}
+	default:
+		panic(fmt.Sprintf("unknown view type %v", vt))
+	}
+}
+
+type OperationHuman struct {
+	view *View
+
+	// inAutomation indicates that commands are being run by an
+	// automated system rather than directly at a command prompt.
+	//
+	// This is a hint not to produce messages that expect that a user can
+	// run a follow-up command, perhaps because Terraform is running in
+	// some sort of workflow automation tool that abstracts away the
+	// exact commands that are being run.
+	inAutomation bool
+}
+
+var _ Operation = (*OperationHuman)(nil)
+
+func (v *OperationHuman) Interrupted() {
+	v.view.streams.Println(format.WordWrap(interrupted, v.view.outputColumns()))
+}
+
+func (v *OperationHuman) FatalInterrupt() {
+	v.view.streams.Eprintln(format.WordWrap(fatalInterrupt, v.view.errorColumns()))
+}
+
+func (v *OperationHuman) Stopping() {
+	v.view.streams.Println("Stopping operation...")
+}
+
+func (v *OperationHuman) Cancelled(planMode plans.Mode) {
+	switch planMode {
+	case plans.DestroyMode:
+		v.view.streams.Println("Destroy cancelled.")
+	default:
+		v.view.streams.Println("Apply cancelled.")
+	}
+}
+
+func (v *OperationHuman) EmergencyDumpState(stateFile *statefile.File) error {
+	stateBuf := new(bytes.Buffer)
+	jsonErr := statefile.Write(stateFile, stateBuf)
+	if jsonErr != nil {
+		return jsonErr
+	}
+	v.view.streams.Eprintln(stateBuf)
+	return nil
+}
+
+func (v *OperationHuman) Plan(plan *plans.Plan, schemas *terraform.Schemas) {
+	outputs, changed, drift, attrs, err := jsonplan.MarshalForRenderer(plan, schemas)
+	if err != nil {
+		v.view.streams.Eprintf("Failed to marshal plan to json: %s", err)
+		return
+	}
+
+	renderer := jsonformat.Renderer{
+		Colorize:            v.view.colorize,
+		Streams:             v.view.streams,
+		RunningInAutomation: v.inAutomation,
+	}
+
+	jplan := jsonformat.Plan{
+		PlanFormatVersion:     jsonplan.FormatVersion,
+		ProviderFormatVersion: jsonprovider.FormatVersion,
+		OutputChanges:         outputs,
+		ResourceChanges:       changed,
+		ResourceDrift:         drift,
+		ProviderSchemas:       jsonprovider.MarshalForRenderer(schemas),
+		RelevantAttributes:    attrs,
+	}
+
+	// Side load some data that we can't extract from the JSON plan.
+	var opts []jsonformat.PlanRendererOpt
+	if !plan.CanApply() {
+		opts = append(opts, jsonformat.CanNotApply)
+	}
+	if plan.Errored {
+		opts = append(opts, jsonformat.Errored)
+	}
+
+	renderer.RenderHumanPlan(jplan, plan.UIMode, opts...)
+}
+
+func (v *OperationHuman) PlannedChange(change *plans.ResourceInstanceChangeSrc) {
+	// PlannedChange is primarily for machine-readable output in order to
+	// get a per-resource-instance change description. We don't use it
+	// with OperationHuman because the output of Plan already includes the
+	// change details for all resource instances.
+}
+
+// PlanNextStep gives the user some next-steps, unless we're running in an
+// automation tool which is presumed to provide its own UI for further actions.
+func (v *OperationHuman) PlanNextStep(planPath string, genConfigPath string) {
+	if v.inAutomation {
+		return
+	}
+	v.view.outputHorizRule()
+
+	if genConfigPath != "" {
+		v.view.streams.Printf(
+			format.WordWrap(
+				"\n"+strings.TrimSpace(fmt.Sprintf(planHeaderGenConfig, genConfigPath)),
+				v.view.outputColumns(),
+			) + "\n")
+	}
+
+	if planPath == "" {
+		v.view.streams.Print(
+			format.WordWrap(
+				"\n"+strings.TrimSpace(planHeaderNoOutput),
+				v.view.outputColumns(),
+			) + "\n",
+		)
+	} else {
+		v.view.streams.Printf(
+			format.WordWrap(
+				"\n"+strings.TrimSpace(fmt.Sprintf(planHeaderYesOutput, planPath, planPath)),
+				v.view.outputColumns(),
+			) + "\n",
+		)
+	}
+}
+
+func (v *OperationHuman) Diagnostics(diags tfdiags.Diagnostics) {
+	v.view.Diagnostics(diags)
+}
+
+type OperationJSON struct {
+	view *JSONView
+}
+
+var _ Operation = (*OperationJSON)(nil)
+
+func (v *OperationJSON) Interrupted() {
+	v.view.Log(interrupted)
+}
+
+func (v *OperationJSON) FatalInterrupt() {
+	v.view.Log(fatalInterrupt)
+}
+
+func (v *OperationJSON) Stopping() {
+	v.view.Log("Stopping operation...")
+}
+
+func (v *OperationJSON) Cancelled(planMode plans.Mode) {
+	switch planMode {
+	case plans.DestroyMode:
+		v.view.Log("Destroy cancelled")
+	default:
+		v.view.Log("Apply cancelled")
+	}
+}
+
+func (v *OperationJSON) EmergencyDumpState(stateFile *statefile.File) error {
+	stateBuf := new(bytes.Buffer)
+	jsonErr := statefile.Write(stateFile, stateBuf)
+	if jsonErr != nil {
+		return jsonErr
+	}
+	v.view.StateDump(stateBuf.String())
+	return nil
+}
+
+// Log a change summary and a series of "planned" messages for the changes in
+// the plan.
+func (v *OperationJSON) Plan(plan *plans.Plan, schemas *terraform.Schemas) {
+	for _, dr := range plan.DriftedResources {
+		// In refresh-only mode, we output all resources marked as drifted,
+		// including those which have moved without other changes. In other plan
+		// modes, move-only changes will be included in the planned changes, so
+		// we skip them here.
+		if dr.Action != plans.NoOp || plan.UIMode == plans.RefreshOnlyMode {
+			v.view.ResourceDrift(json.NewResourceInstanceChange(dr))
+		}
+	}
+
+	cs := &json.ChangeSummary{
+		Operation: json.OperationPlanned,
+	}
+	for _, change := range plan.Changes.Resources {
+		if change.Action == plans.Delete && change.Addr.Resource.Resource.Mode == addrs.DataResourceMode {
+			// Avoid rendering data sources on deletion
+			continue
+		}
+
+		if change.Importing != nil {
+			cs.Import++
+		}
+
+		switch change.Action {
+		case plans.Create:
+			cs.Add++
+		case plans.Delete:
+			cs.Remove++
+		case plans.Update:
+			cs.Change++
+		case plans.CreateThenDelete, plans.DeleteThenCreate:
+			cs.Add++
+			cs.Remove++
+		}
+
+		if change.Action != plans.NoOp || !change.Addr.Equal(change.PrevRunAddr) || change.Importing != nil {
+			v.view.PlannedChange(json.NewResourceInstanceChange(change))
+		}
+	}
+
+	v.view.ChangeSummary(cs)
+
+	var rootModuleOutputs []*plans.OutputChangeSrc
+	for _, output := range plan.Changes.Outputs {
+		if !output.Addr.Module.IsRoot() {
+			continue
+		}
+		rootModuleOutputs = append(rootModuleOutputs, output)
+	}
+	if len(rootModuleOutputs) > 0 {
+		v.view.Outputs(json.OutputsFromChanges(rootModuleOutputs))
+	}
+}
+
+func (v *OperationJSON) PlannedChange(change *plans.ResourceInstanceChangeSrc) {
+	if change.Action == plans.Delete && change.Addr.Resource.Resource.Mode == addrs.DataResourceMode {
+		// Avoid rendering data sources on deletion
+		return
+	}
+	v.view.PlannedChange(json.NewResourceInstanceChange(change))
+}
+
+// PlanNextStep does nothing for the JSON view as it is a hook for user-facing
+// output only applicable to human-readable UI.
+func (v *OperationJSON) PlanNextStep(planPath string, genConfigPath string) {
+}
+
+func (v *OperationJSON) Diagnostics(diags tfdiags.Diagnostics) {
+	v.view.Diagnostics(diags)
+}
+
+const fatalInterrupt = `
+Two interrupts received. Exiting immediately. Note that data loss may have occurred.
+`
+
+const interrupted = `
+Interrupt received.
+Please wait for Terraform to exit or data loss may occur.
+Gracefully shutting down...
+`
+
+const planHeaderNoOutput = `
+Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
+`
+
+const planHeaderYesOutput = `
+Saved the plan to: %s
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply %q
+`
+
+const planHeaderGenConfig = `
+Terraform has generated configuration and written it to %s. Please review the configuration and edit it as necessary before adding it to version control.
+`
diff --git a/v1.5.7/internal/command/views/operation_test.go b/v1.5.7/internal/command/views/operation_test.go
new file mode 100644
index 0000000..0fe23f5
--- /dev/null
+++ b/v1.5.7/internal/command/views/operation_test.go
@@ -0,0 +1,1329 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"bytes"
+	"encoding/json"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/lang/globalref"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestOperation_stopping(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := NewOperation(arguments.ViewHuman, false, NewView(streams))
+
+	v.Stopping()
+
+	if got, want := done(t).Stdout(), "Stopping operation...\n"; got != want {
+		t.Errorf("wrong result\ngot:  %q\nwant: %q", got, want)
+	}
+}
+
+func TestOperation_cancelled(t *testing.T) {
+	testCases := map[string]struct {
+		planMode plans.Mode
+		want     string
+	}{
+		"apply": {
+			planMode: plans.NormalMode,
+			want:     "Apply cancelled.\n",
+		},
+		"destroy": {
+			planMode: plans.DestroyMode,
+			want:     "Destroy cancelled.\n",
+		},
+	}
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			v := NewOperation(arguments.ViewHuman, false, NewView(streams))
+
+			v.Cancelled(tc.planMode)
+
+			if got, want := done(t).Stdout(), tc.want; got != want {
+				t.Errorf("wrong result\ngot:  %q\nwant: %q", got, want)
+			}
+		})
+	}
+}
+
+func TestOperation_emergencyDumpState(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := NewOperation(arguments.ViewHuman, false, NewView(streams))
+
+	stateFile := statefile.New(nil, "foo", 1)
+
+	err := v.EmergencyDumpState(stateFile)
+	if err != nil {
+		t.Fatalf("unexpected error dumping state: %s", err)
+	}
+
+	// Check that the result (on stderr) looks like JSON state
+	raw := done(t).Stderr()
+	var state map[string]interface{}
+	if err := json.Unmarshal([]byte(raw), &state); err != nil {
+		t.Fatalf("unexpected error parsing dumped state: %s\nraw:\n%s", err, raw)
+	}
+}
+
+func TestOperation_planNoChanges(t *testing.T) {
+
+	tests := map[string]struct {
+		plan     func(schemas *terraform.Schemas) *plans.Plan
+		wantText string
+	}{
+		"nothing at all in normal mode": {
+			func(schemas *terraform.Schemas) *plans.Plan {
+				return &plans.Plan{
+					UIMode:  plans.NormalMode,
+					Changes: plans.NewChanges(),
+				}
+			},
+			"no differences, so no changes are needed.",
+		},
+		"nothing at all in refresh-only mode": {
+			func(schemas *terraform.Schemas) *plans.Plan {
+				return &plans.Plan{
+					UIMode:  plans.RefreshOnlyMode,
+					Changes: plans.NewChanges(),
+				}
+			},
+			"Terraform has checked that the real remote objects still match",
+		},
+		"nothing at all in destroy mode": {
+			func(schemas *terraform.Schemas) *plans.Plan {
+				return &plans.Plan{
+					UIMode:  plans.DestroyMode,
+					Changes: plans.NewChanges(),
+				}
+			},
+			"No objects need to be destroyed.",
+		},
+		"no drift detected in normal noop": {
+			func(schemas *terraform.Schemas) *plans.Plan {
+				addr := addrs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "test_resource",
+					Name: "somewhere",
+				}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+				schema, _ := schemas.ResourceTypeConfig(
+					addrs.NewDefaultProvider("test"),
+					addr.Resource.Resource.Mode,
+					addr.Resource.Resource.Type,
+				)
+				ty := schema.ImpliedType()
+				rc := &plans.ResourceInstanceChange{
+					Addr:        addr,
+					PrevRunAddr: addr,
+					ProviderAddr: addrs.RootModuleInstance.ProviderConfigDefault(
+						addrs.NewDefaultProvider("test"),
+					),
+					Change: plans.Change{
+						Action: plans.Update,
+						Before: cty.NullVal(ty),
+						After: cty.ObjectVal(map[string]cty.Value{
+							"id":  cty.StringVal("1234"),
+							"foo": cty.StringVal("bar"),
+						}),
+					},
+				}
+				rcs, err := rc.Encode(ty)
+				if err != nil {
+					panic(err)
+				}
+				drs := []*plans.ResourceInstanceChangeSrc{rcs}
+				return &plans.Plan{
+					UIMode:           plans.NormalMode,
+					Changes:          plans.NewChanges(),
+					DriftedResources: drs,
+				}
+			},
+			"No changes",
+		},
+		"drift detected in normal mode": {
+			func(schemas *terraform.Schemas) *plans.Plan {
+				addr := addrs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "test_resource",
+					Name: "somewhere",
+				}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+				schema, _ := schemas.ResourceTypeConfig(
+					addrs.NewDefaultProvider("test"),
+					addr.Resource.Resource.Mode,
+					addr.Resource.Resource.Type,
+				)
+				ty := schema.ImpliedType()
+				rc := &plans.ResourceInstanceChange{
+					Addr:        addr,
+					PrevRunAddr: addr,
+					ProviderAddr: addrs.RootModuleInstance.ProviderConfigDefault(
+						addrs.NewDefaultProvider("test"),
+					),
+					Change: plans.Change{
+						Action: plans.Update,
+						Before: cty.NullVal(ty),
+						After: cty.ObjectVal(map[string]cty.Value{
+							"id":  cty.StringVal("1234"),
+							"foo": cty.StringVal("bar"),
+						}),
+					},
+				}
+				rcs, err := rc.Encode(ty)
+				if err != nil {
+					panic(err)
+				}
+				drs := []*plans.ResourceInstanceChangeSrc{rcs}
+				changes := plans.NewChanges()
+				changes.Resources = drs
+				return &plans.Plan{
+					UIMode:           plans.NormalMode,
+					Changes:          changes,
+					DriftedResources: drs,
+					RelevantAttributes: []globalref.ResourceAttr{{
+						Resource: addr,
+						Attr:     cty.GetAttrPath("id"),
+					}},
+				}
+			},
+			"Objects have changed outside of Terraform",
+		},
+		"drift detected in refresh-only mode": {
+			func(schemas *terraform.Schemas) *plans.Plan {
+				addr := addrs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "test_resource",
+					Name: "somewhere",
+				}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+				schema, _ := schemas.ResourceTypeConfig(
+					addrs.NewDefaultProvider("test"),
+					addr.Resource.Resource.Mode,
+					addr.Resource.Resource.Type,
+				)
+				ty := schema.ImpliedType()
+				rc := &plans.ResourceInstanceChange{
+					Addr:        addr,
+					PrevRunAddr: addr,
+					ProviderAddr: addrs.RootModuleInstance.ProviderConfigDefault(
+						addrs.NewDefaultProvider("test"),
+					),
+					Change: plans.Change{
+						Action: plans.Update,
+						Before: cty.NullVal(ty),
+						After: cty.ObjectVal(map[string]cty.Value{
+							"id":  cty.StringVal("1234"),
+							"foo": cty.StringVal("bar"),
+						}),
+					},
+				}
+				rcs, err := rc.Encode(ty)
+				if err != nil {
+					panic(err)
+				}
+				drs := []*plans.ResourceInstanceChangeSrc{rcs}
+				return &plans.Plan{
+					UIMode:           plans.RefreshOnlyMode,
+					Changes:          plans.NewChanges(),
+					DriftedResources: drs,
+				}
+			},
+			"If you were expecting these changes then you can apply this plan",
+		},
+		"move-only changes in refresh-only mode": {
+			func(schemas *terraform.Schemas) *plans.Plan {
+				addr := addrs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "test_resource",
+					Name: "somewhere",
+				}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+				addrPrev := addrs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "test_resource",
+					Name: "anywhere",
+				}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+				schema, _ := schemas.ResourceTypeConfig(
+					addrs.NewDefaultProvider("test"),
+					addr.Resource.Resource.Mode,
+					addr.Resource.Resource.Type,
+				)
+				ty := schema.ImpliedType()
+				rc := &plans.ResourceInstanceChange{
+					Addr:        addr,
+					PrevRunAddr: addrPrev,
+					ProviderAddr: addrs.RootModuleInstance.ProviderConfigDefault(
+						addrs.NewDefaultProvider("test"),
+					),
+					Change: plans.Change{
+						Action: plans.NoOp,
+						Before: cty.ObjectVal(map[string]cty.Value{
+							"id":  cty.StringVal("1234"),
+							"foo": cty.StringVal("bar"),
+						}),
+						After: cty.ObjectVal(map[string]cty.Value{
+							"id":  cty.StringVal("1234"),
+							"foo": cty.StringVal("bar"),
+						}),
+					},
+				}
+				rcs, err := rc.Encode(ty)
+				if err != nil {
+					panic(err)
+				}
+				drs := []*plans.ResourceInstanceChangeSrc{rcs}
+				return &plans.Plan{
+					UIMode:           plans.RefreshOnlyMode,
+					Changes:          plans.NewChanges(),
+					DriftedResources: drs,
+				}
+			},
+			"test_resource.anywhere has moved to test_resource.somewhere",
+		},
+		"drift detected in destroy mode": {
+			func(schemas *terraform.Schemas) *plans.Plan {
+				return &plans.Plan{
+					UIMode:  plans.DestroyMode,
+					Changes: plans.NewChanges(),
+					PrevRunState: states.BuildState(func(state *states.SyncState) {
+						state.SetResourceInstanceCurrent(
+							addrs.Resource{
+								Mode: addrs.ManagedResourceMode,
+								Type: "test_resource",
+								Name: "somewhere",
+							}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+							&states.ResourceInstanceObjectSrc{
+								Status:    states.ObjectReady,
+								AttrsJSON: []byte(`{}`),
+							},
+							addrs.RootModuleInstance.ProviderConfigDefault(addrs.NewDefaultProvider("test")),
+						)
+					}),
+					PriorState: states.NewState(),
+				}
+			},
+			"No objects need to be destroyed.",
+		},
+	}
+
+	schemas := testSchemas()
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			v := NewOperation(arguments.ViewHuman, false, NewView(streams))
+			plan := test.plan(schemas)
+			v.Plan(plan, schemas)
+			got := done(t).Stdout()
+			if want := test.wantText; want != "" && !strings.Contains(got, want) {
+				t.Errorf("missing expected message\ngot:\n%s\n\nwant substring: %s", got, want)
+			}
+		})
+	}
+}
+
+func TestOperation_plan(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := NewOperation(arguments.ViewHuman, true, NewView(streams))
+
+	plan := testPlan(t)
+	schemas := testSchemas()
+	v.Plan(plan, schemas)
+
+	want := `
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  # test_resource.foo will be created
+  + resource "test_resource" "foo" {
+      + foo = "bar"
+      + id  = (known after apply)
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+`
+
+	if got := done(t).Stdout(); got != want {
+		t.Errorf("unexpected output\ngot:\n%s\nwant:\n%s", got, want)
+	}
+}
+
+func TestOperation_planWithDatasource(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := NewOperation(arguments.ViewHuman, true, NewView(streams))
+
+	plan := testPlanWithDatasource(t)
+	schemas := testSchemas()
+	v.Plan(plan, schemas)
+
+	want := `
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+ <= read (data resources)
+
+Terraform will perform the following actions:
+
+  # data.test_data_source.bar will be read during apply
+ <= data "test_data_source" "bar" {
+      + bar = "foo"
+      + id  = "C6743020-40BD-4591-81E6-CD08494341D3"
+    }
+
+  # test_resource.foo will be created
+  + resource "test_resource" "foo" {
+      + foo = "bar"
+      + id  = (known after apply)
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+`
+
+	if got := done(t).Stdout(); got != want {
+		t.Errorf("unexpected output\ngot:\n%s\nwant:\n%s", got, want)
+	}
+}
+
+func TestOperation_planWithDatasourceAndDrift(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := NewOperation(arguments.ViewHuman, true, NewView(streams))
+
+	plan := testPlanWithDatasource(t)
+	schemas := testSchemas()
+	v.Plan(plan, schemas)
+
+	want := `
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+ <= read (data resources)
+
+Terraform will perform the following actions:
+
+  # data.test_data_source.bar will be read during apply
+ <= data "test_data_source" "bar" {
+      + bar = "foo"
+      + id  = "C6743020-40BD-4591-81E6-CD08494341D3"
+    }
+
+  # test_resource.foo will be created
+  + resource "test_resource" "foo" {
+      + foo = "bar"
+      + id  = (known after apply)
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+`
+
+	if got := done(t).Stdout(); got != want {
+		t.Errorf("unexpected output\ngot:\n%s\nwant:\n%s", got, want)
+	}
+}
+
+func TestOperation_planNextStep(t *testing.T) {
+	testCases := map[string]struct {
+		path string
+		want string
+	}{
+		"no state path": {
+			path: "",
+			want: "You didn't use the -out option",
+		},
+		"state path": {
+			path: "good plan.tfplan",
+			want: `terraform apply "good plan.tfplan"`,
+		},
+	}
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			v := NewOperation(arguments.ViewHuman, false, NewView(streams))
+
+			v.PlanNextStep(tc.path, "")
+
+			if got := done(t).Stdout(); !strings.Contains(got, tc.want) {
+				t.Errorf("wrong result\ngot:  %q\nwant: %q", got, tc.want)
+			}
+		})
+	}
+}
+
+// The in-automation state is on the view itself, so testing it separately is
+// clearer.
+func TestOperation_planNextStepInAutomation(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := NewOperation(arguments.ViewHuman, true, NewView(streams))
+
+	v.PlanNextStep("", "")
+
+	if got := done(t).Stdout(); got != "" {
+		t.Errorf("unexpected output\ngot: %q", got)
+	}
+}
+
+// Test all the trivial OperationJSON methods together. Y'know, for brevity.
+// This test is not a realistic stream of messages.
+func TestOperationJSON_logs(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := &OperationJSON{view: NewJSONView(NewView(streams))}
+
+	v.Cancelled(plans.NormalMode)
+	v.Cancelled(plans.DestroyMode)
+	v.Stopping()
+	v.Interrupted()
+	v.FatalInterrupt()
+
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": "Apply cancelled",
+			"@module":  "terraform.ui",
+			"type":     "log",
+		},
+		{
+			"@level":   "info",
+			"@message": "Destroy cancelled",
+			"@module":  "terraform.ui",
+			"type":     "log",
+		},
+		{
+			"@level":   "info",
+			"@message": "Stopping operation...",
+			"@module":  "terraform.ui",
+			"type":     "log",
+		},
+		{
+			"@level":   "info",
+			"@message": interrupted,
+			"@module":  "terraform.ui",
+			"type":     "log",
+		},
+		{
+			"@level":   "info",
+			"@message": fatalInterrupt,
+			"@module":  "terraform.ui",
+			"type":     "log",
+		},
+	}
+
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+// This is a fairly circular test, but it's such a rarely executed code path
+// that I think it's probably still worth having. We're not testing against
+// a fixed state JSON output because this test ought not fail just because
+// we upgrade state format in the future.
+func TestOperationJSON_emergencyDumpState(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := &OperationJSON{view: NewJSONView(NewView(streams))}
+
+	stateFile := statefile.New(nil, "foo", 1)
+	stateBuf := new(bytes.Buffer)
+	err := statefile.Write(stateFile, stateBuf)
+	if err != nil {
+		t.Fatal(err)
+	}
+	var stateJSON map[string]interface{}
+	err = json.Unmarshal(stateBuf.Bytes(), &stateJSON)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = v.EmergencyDumpState(stateFile)
+	if err != nil {
+		t.Fatalf("unexpected error dumping state: %s", err)
+	}
+
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": "Emergency state dump",
+			"@module":  "terraform.ui",
+			"type":     "log",
+			"state":    stateJSON,
+		},
+	}
+
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func TestOperationJSON_planNoChanges(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := &OperationJSON{view: NewJSONView(NewView(streams))}
+
+	plan := &plans.Plan{
+		Changes: plans.NewChanges(),
+	}
+	v.Plan(plan, nil)
+
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": "Plan: 0 to add, 0 to change, 0 to destroy.",
+			"@module":  "terraform.ui",
+			"type":     "change_summary",
+			"changes": map[string]interface{}{
+				"operation": "plan",
+				"add":       float64(0),
+				"import":    float64(0),
+				"change":    float64(0),
+				"remove":    float64(0),
+			},
+		},
+	}
+
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func TestOperationJSON_plan(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := &OperationJSON{view: NewJSONView(NewView(streams))}
+
+	root := addrs.RootModuleInstance
+	vpc, diags := addrs.ParseModuleInstanceStr("module.vpc")
+	if len(diags) > 0 {
+		t.Fatal(diags.Err())
+	}
+	boop := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "boop"}
+	beep := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "beep"}
+	derp := addrs.Resource{Mode: addrs.DataResourceMode, Type: "test_source", Name: "derp"}
+
+	plan := &plans.Plan{
+		Changes: &plans.Changes{
+			Resources: []*plans.ResourceInstanceChangeSrc{
+				{
+					Addr:        boop.Instance(addrs.IntKey(0)).Absolute(root),
+					PrevRunAddr: boop.Instance(addrs.IntKey(0)).Absolute(root),
+					ChangeSrc:   plans.ChangeSrc{Action: plans.CreateThenDelete},
+				},
+				{
+					Addr:        boop.Instance(addrs.IntKey(1)).Absolute(root),
+					PrevRunAddr: boop.Instance(addrs.IntKey(1)).Absolute(root),
+					ChangeSrc:   plans.ChangeSrc{Action: plans.Create},
+				},
+				{
+					Addr:        boop.Instance(addrs.IntKey(0)).Absolute(vpc),
+					PrevRunAddr: boop.Instance(addrs.IntKey(0)).Absolute(vpc),
+					ChangeSrc:   plans.ChangeSrc{Action: plans.Delete},
+				},
+				{
+					Addr:        beep.Instance(addrs.NoKey).Absolute(root),
+					PrevRunAddr: beep.Instance(addrs.NoKey).Absolute(root),
+					ChangeSrc:   plans.ChangeSrc{Action: plans.DeleteThenCreate},
+				},
+				{
+					Addr:        beep.Instance(addrs.NoKey).Absolute(vpc),
+					PrevRunAddr: beep.Instance(addrs.NoKey).Absolute(vpc),
+					ChangeSrc:   plans.ChangeSrc{Action: plans.Update},
+				},
+				// Data source deletion should not show up in the logs
+				{
+					Addr:        derp.Instance(addrs.NoKey).Absolute(root),
+					PrevRunAddr: derp.Instance(addrs.NoKey).Absolute(root),
+					ChangeSrc:   plans.ChangeSrc{Action: plans.Delete},
+				},
+			},
+		},
+	}
+	v.Plan(plan, testSchemas())
+
+	want := []map[string]interface{}{
+		// Create-then-delete should result in replace
+		{
+			"@level":   "info",
+			"@message": "test_resource.boop[0]: Plan to replace",
+			"@module":  "terraform.ui",
+			"type":     "planned_change",
+			"change": map[string]interface{}{
+				"action": "replace",
+				"resource": map[string]interface{}{
+					"addr":             `test_resource.boop[0]`,
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         `test_resource.boop[0]`,
+					"resource_key":     float64(0),
+					"resource_name":    "boop",
+					"resource_type":    "test_resource",
+				},
+			},
+		},
+		// Simple create
+		{
+			"@level":   "info",
+			"@message": "test_resource.boop[1]: Plan to create",
+			"@module":  "terraform.ui",
+			"type":     "planned_change",
+			"change": map[string]interface{}{
+				"action": "create",
+				"resource": map[string]interface{}{
+					"addr":             `test_resource.boop[1]`,
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         `test_resource.boop[1]`,
+					"resource_key":     float64(1),
+					"resource_name":    "boop",
+					"resource_type":    "test_resource",
+				},
+			},
+		},
+		// Simple delete
+		{
+			"@level":   "info",
+			"@message": "module.vpc.test_resource.boop[0]: Plan to delete",
+			"@module":  "terraform.ui",
+			"type":     "planned_change",
+			"change": map[string]interface{}{
+				"action": "delete",
+				"resource": map[string]interface{}{
+					"addr":             `module.vpc.test_resource.boop[0]`,
+					"implied_provider": "test",
+					"module":           "module.vpc",
+					"resource":         `test_resource.boop[0]`,
+					"resource_key":     float64(0),
+					"resource_name":    "boop",
+					"resource_type":    "test_resource",
+				},
+			},
+		},
+		// Delete-then-create is also a replace
+		{
+			"@level":   "info",
+			"@message": "test_resource.beep: Plan to replace",
+			"@module":  "terraform.ui",
+			"type":     "planned_change",
+			"change": map[string]interface{}{
+				"action": "replace",
+				"resource": map[string]interface{}{
+					"addr":             `test_resource.beep`,
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         `test_resource.beep`,
+					"resource_key":     nil,
+					"resource_name":    "beep",
+					"resource_type":    "test_resource",
+				},
+			},
+		},
+		// Simple update
+		{
+			"@level":   "info",
+			"@message": "module.vpc.test_resource.beep: Plan to update",
+			"@module":  "terraform.ui",
+			"type":     "planned_change",
+			"change": map[string]interface{}{
+				"action": "update",
+				"resource": map[string]interface{}{
+					"addr":             `module.vpc.test_resource.beep`,
+					"implied_provider": "test",
+					"module":           "module.vpc",
+					"resource":         `test_resource.beep`,
+					"resource_key":     nil,
+					"resource_name":    "beep",
+					"resource_type":    "test_resource",
+				},
+			},
+		},
+		// These counts are 3 add/1 change/3 destroy because the replace
+		// changes result in both add and destroy counts.
+		{
+			"@level":   "info",
+			"@message": "Plan: 3 to add, 1 to change, 3 to destroy.",
+			"@module":  "terraform.ui",
+			"type":     "change_summary",
+			"changes": map[string]interface{}{
+				"operation": "plan",
+				"add":       float64(3),
+				"import":    float64(0),
+				"change":    float64(1),
+				"remove":    float64(3),
+			},
+		},
+	}
+
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func TestOperationJSON_planWithImport(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := &OperationJSON{view: NewJSONView(NewView(streams))}
+
+	root := addrs.RootModuleInstance
+	vpc, diags := addrs.ParseModuleInstanceStr("module.vpc")
+	if len(diags) > 0 {
+		t.Fatal(diags.Err())
+	}
+	boop := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "boop"}
+	beep := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "beep"}
+
+	plan := &plans.Plan{
+		Changes: &plans.Changes{
+			Resources: []*plans.ResourceInstanceChangeSrc{
+				{
+					Addr:        boop.Instance(addrs.IntKey(0)).Absolute(vpc),
+					PrevRunAddr: boop.Instance(addrs.IntKey(0)).Absolute(vpc),
+					ChangeSrc:   plans.ChangeSrc{Action: plans.NoOp, Importing: &plans.ImportingSrc{ID: "DECD6D77"}},
+				},
+				{
+					Addr:        boop.Instance(addrs.IntKey(1)).Absolute(vpc),
+					PrevRunAddr: boop.Instance(addrs.IntKey(1)).Absolute(vpc),
+					ChangeSrc:   plans.ChangeSrc{Action: plans.Delete, Importing: &plans.ImportingSrc{ID: "DECD6D77"}},
+				},
+				{
+					Addr:        boop.Instance(addrs.IntKey(0)).Absolute(root),
+					PrevRunAddr: boop.Instance(addrs.IntKey(0)).Absolute(root),
+					ChangeSrc:   plans.ChangeSrc{Action: plans.CreateThenDelete, Importing: &plans.ImportingSrc{ID: "DECD6D77"}},
+				},
+				{
+					Addr:        beep.Instance(addrs.NoKey).Absolute(root),
+					PrevRunAddr: beep.Instance(addrs.NoKey).Absolute(root),
+					ChangeSrc:   plans.ChangeSrc{Action: plans.Update, Importing: &plans.ImportingSrc{ID: "DECD6D77"}},
+				},
+			},
+		},
+	}
+	v.Plan(plan, testSchemas())
+
+	want := []map[string]interface{}{
+		// Simple import
+		{
+			"@level":   "info",
+			"@message": "module.vpc.test_resource.boop[0]: Plan to import",
+			"@module":  "terraform.ui",
+			"type":     "planned_change",
+			"change": map[string]interface{}{
+				"action": "import",
+				"resource": map[string]interface{}{
+					"addr":             `module.vpc.test_resource.boop[0]`,
+					"implied_provider": "test",
+					"module":           "module.vpc",
+					"resource":         `test_resource.boop[0]`,
+					"resource_key":     float64(0),
+					"resource_name":    "boop",
+					"resource_type":    "test_resource",
+				},
+				"importing": map[string]interface{}{
+					"id": "DECD6D77",
+				},
+			},
+		},
+		// Delete after importing
+		{
+			"@level":   "info",
+			"@message": "module.vpc.test_resource.boop[1]: Plan to delete",
+			"@module":  "terraform.ui",
+			"type":     "planned_change",
+			"change": map[string]interface{}{
+				"action": "delete",
+				"resource": map[string]interface{}{
+					"addr":             `module.vpc.test_resource.boop[1]`,
+					"implied_provider": "test",
+					"module":           "module.vpc",
+					"resource":         `test_resource.boop[1]`,
+					"resource_key":     float64(1),
+					"resource_name":    "boop",
+					"resource_type":    "test_resource",
+				},
+				"importing": map[string]interface{}{
+					"id": "DECD6D77",
+				},
+			},
+		},
+		// Create-then-delete after importing.
+		{
+			"@level":   "info",
+			"@message": "test_resource.boop[0]: Plan to replace",
+			"@module":  "terraform.ui",
+			"type":     "planned_change",
+			"change": map[string]interface{}{
+				"action": "replace",
+				"resource": map[string]interface{}{
+					"addr":             `test_resource.boop[0]`,
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         `test_resource.boop[0]`,
+					"resource_key":     float64(0),
+					"resource_name":    "boop",
+					"resource_type":    "test_resource",
+				},
+				"importing": map[string]interface{}{
+					"id": "DECD6D77",
+				},
+			},
+		},
+		// Update after importing
+		{
+			"@level":   "info",
+			"@message": "test_resource.beep: Plan to update",
+			"@module":  "terraform.ui",
+			"type":     "planned_change",
+			"change": map[string]interface{}{
+				"action": "update",
+				"resource": map[string]interface{}{
+					"addr":             `test_resource.beep`,
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         `test_resource.beep`,
+					"resource_key":     nil,
+					"resource_name":    "beep",
+					"resource_type":    "test_resource",
+				},
+				"importing": map[string]interface{}{
+					"id": "DECD6D77",
+				},
+			},
+		},
+		{
+			"@level":   "info",
+			"@message": "Plan: 4 to import, 1 to add, 1 to change, 2 to destroy.",
+			"@module":  "terraform.ui",
+			"type":     "change_summary",
+			"changes": map[string]interface{}{
+				"operation": "plan",
+				"add":       float64(1),
+				"import":    float64(4),
+				"change":    float64(1),
+				"remove":    float64(2),
+			},
+		},
+	}
+
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func TestOperationJSON_planDriftWithMove(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := &OperationJSON{view: NewJSONView(NewView(streams))}
+
+	root := addrs.RootModuleInstance
+	boop := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "boop"}
+	beep := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "beep"}
+	blep := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "blep"}
+	honk := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "honk"}
+
+	plan := &plans.Plan{
+		UIMode: plans.NormalMode,
+		Changes: &plans.Changes{
+			Resources: []*plans.ResourceInstanceChangeSrc{
+				{
+					Addr:        honk.Instance(addrs.StringKey("bonk")).Absolute(root),
+					PrevRunAddr: honk.Instance(addrs.IntKey(0)).Absolute(root),
+					ChangeSrc:   plans.ChangeSrc{Action: plans.NoOp},
+				},
+			},
+		},
+		DriftedResources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr:        beep.Instance(addrs.NoKey).Absolute(root),
+				PrevRunAddr: beep.Instance(addrs.NoKey).Absolute(root),
+				ChangeSrc:   plans.ChangeSrc{Action: plans.Delete},
+			},
+			{
+				Addr:        boop.Instance(addrs.NoKey).Absolute(root),
+				PrevRunAddr: blep.Instance(addrs.NoKey).Absolute(root),
+				ChangeSrc:   plans.ChangeSrc{Action: plans.Update},
+			},
+			// Move-only resource drift should not be present in normal mode plans
+			{
+				Addr:        honk.Instance(addrs.StringKey("bonk")).Absolute(root),
+				PrevRunAddr: honk.Instance(addrs.IntKey(0)).Absolute(root),
+				ChangeSrc:   plans.ChangeSrc{Action: plans.NoOp},
+			},
+		},
+	}
+	v.Plan(plan, testSchemas())
+
+	want := []map[string]interface{}{
+		// Drift detected: delete
+		{
+			"@level":   "info",
+			"@message": "test_resource.beep: Drift detected (delete)",
+			"@module":  "terraform.ui",
+			"type":     "resource_drift",
+			"change": map[string]interface{}{
+				"action": "delete",
+				"resource": map[string]interface{}{
+					"addr":             "test_resource.beep",
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         "test_resource.beep",
+					"resource_key":     nil,
+					"resource_name":    "beep",
+					"resource_type":    "test_resource",
+				},
+			},
+		},
+		// Drift detected: update with move
+		{
+			"@level":   "info",
+			"@message": "test_resource.boop: Drift detected (update)",
+			"@module":  "terraform.ui",
+			"type":     "resource_drift",
+			"change": map[string]interface{}{
+				"action": "update",
+				"resource": map[string]interface{}{
+					"addr":             "test_resource.boop",
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         "test_resource.boop",
+					"resource_key":     nil,
+					"resource_name":    "boop",
+					"resource_type":    "test_resource",
+				},
+				"previous_resource": map[string]interface{}{
+					"addr":             "test_resource.blep",
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         "test_resource.blep",
+					"resource_key":     nil,
+					"resource_name":    "blep",
+					"resource_type":    "test_resource",
+				},
+			},
+		},
+		// Move-only change
+		{
+			"@level":   "info",
+			"@message": `test_resource.honk["bonk"]: Plan to move`,
+			"@module":  "terraform.ui",
+			"type":     "planned_change",
+			"change": map[string]interface{}{
+				"action": "move",
+				"resource": map[string]interface{}{
+					"addr":             `test_resource.honk["bonk"]`,
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         `test_resource.honk["bonk"]`,
+					"resource_key":     "bonk",
+					"resource_name":    "honk",
+					"resource_type":    "test_resource",
+				},
+				"previous_resource": map[string]interface{}{
+					"addr":             `test_resource.honk[0]`,
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         `test_resource.honk[0]`,
+					"resource_key":     float64(0),
+					"resource_name":    "honk",
+					"resource_type":    "test_resource",
+				},
+			},
+		},
+		// No changes
+		{
+			"@level":   "info",
+			"@message": "Plan: 0 to add, 0 to change, 0 to destroy.",
+			"@module":  "terraform.ui",
+			"type":     "change_summary",
+			"changes": map[string]interface{}{
+				"operation": "plan",
+				"add":       float64(0),
+				"import":    float64(0),
+				"change":    float64(0),
+				"remove":    float64(0),
+			},
+		},
+	}
+
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func TestOperationJSON_planDriftWithMoveRefreshOnly(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := &OperationJSON{view: NewJSONView(NewView(streams))}
+
+	root := addrs.RootModuleInstance
+	boop := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "boop"}
+	beep := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "beep"}
+	blep := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "blep"}
+	honk := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "honk"}
+
+	plan := &plans.Plan{
+		UIMode: plans.RefreshOnlyMode,
+		Changes: &plans.Changes{
+			Resources: []*plans.ResourceInstanceChangeSrc{},
+		},
+		DriftedResources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr:        beep.Instance(addrs.NoKey).Absolute(root),
+				PrevRunAddr: beep.Instance(addrs.NoKey).Absolute(root),
+				ChangeSrc:   plans.ChangeSrc{Action: plans.Delete},
+			},
+			{
+				Addr:        boop.Instance(addrs.NoKey).Absolute(root),
+				PrevRunAddr: blep.Instance(addrs.NoKey).Absolute(root),
+				ChangeSrc:   plans.ChangeSrc{Action: plans.Update},
+			},
+			// Move-only resource drift should be present in refresh-only plans
+			{
+				Addr:        honk.Instance(addrs.StringKey("bonk")).Absolute(root),
+				PrevRunAddr: honk.Instance(addrs.IntKey(0)).Absolute(root),
+				ChangeSrc:   plans.ChangeSrc{Action: plans.NoOp},
+			},
+		},
+	}
+	v.Plan(plan, testSchemas())
+
+	want := []map[string]interface{}{
+		// Drift detected: delete
+		{
+			"@level":   "info",
+			"@message": "test_resource.beep: Drift detected (delete)",
+			"@module":  "terraform.ui",
+			"type":     "resource_drift",
+			"change": map[string]interface{}{
+				"action": "delete",
+				"resource": map[string]interface{}{
+					"addr":             "test_resource.beep",
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         "test_resource.beep",
+					"resource_key":     nil,
+					"resource_name":    "beep",
+					"resource_type":    "test_resource",
+				},
+			},
+		},
+		// Drift detected: update
+		{
+			"@level":   "info",
+			"@message": "test_resource.boop: Drift detected (update)",
+			"@module":  "terraform.ui",
+			"type":     "resource_drift",
+			"change": map[string]interface{}{
+				"action": "update",
+				"resource": map[string]interface{}{
+					"addr":             "test_resource.boop",
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         "test_resource.boop",
+					"resource_key":     nil,
+					"resource_name":    "boop",
+					"resource_type":    "test_resource",
+				},
+				"previous_resource": map[string]interface{}{
+					"addr":             "test_resource.blep",
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         "test_resource.blep",
+					"resource_key":     nil,
+					"resource_name":    "blep",
+					"resource_type":    "test_resource",
+				},
+			},
+		},
+		// Drift detected: Move-only change
+		{
+			"@level":   "info",
+			"@message": `test_resource.honk["bonk"]: Drift detected (move)`,
+			"@module":  "terraform.ui",
+			"type":     "resource_drift",
+			"change": map[string]interface{}{
+				"action": "move",
+				"resource": map[string]interface{}{
+					"addr":             `test_resource.honk["bonk"]`,
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         `test_resource.honk["bonk"]`,
+					"resource_key":     "bonk",
+					"resource_name":    "honk",
+					"resource_type":    "test_resource",
+				},
+				"previous_resource": map[string]interface{}{
+					"addr":             `test_resource.honk[0]`,
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         `test_resource.honk[0]`,
+					"resource_key":     float64(0),
+					"resource_name":    "honk",
+					"resource_type":    "test_resource",
+				},
+			},
+		},
+		// No changes
+		{
+			"@level":   "info",
+			"@message": "Plan: 0 to add, 0 to change, 0 to destroy.",
+			"@module":  "terraform.ui",
+			"type":     "change_summary",
+			"changes": map[string]interface{}{
+				"operation": "plan",
+				"add":       float64(0),
+				"import":    float64(0),
+				"change":    float64(0),
+				"remove":    float64(0),
+			},
+		},
+	}
+
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func TestOperationJSON_planOutputChanges(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := &OperationJSON{view: NewJSONView(NewView(streams))}
+
+	root := addrs.RootModuleInstance
+
+	plan := &plans.Plan{
+		Changes: &plans.Changes{
+			Resources: []*plans.ResourceInstanceChangeSrc{},
+			Outputs: []*plans.OutputChangeSrc{
+				{
+					Addr: root.OutputValue("boop"),
+					ChangeSrc: plans.ChangeSrc{
+						Action: plans.NoOp,
+					},
+				},
+				{
+					Addr: root.OutputValue("beep"),
+					ChangeSrc: plans.ChangeSrc{
+						Action: plans.Create,
+					},
+				},
+				{
+					Addr: root.OutputValue("bonk"),
+					ChangeSrc: plans.ChangeSrc{
+						Action: plans.Delete,
+					},
+				},
+				{
+					Addr: root.OutputValue("honk"),
+					ChangeSrc: plans.ChangeSrc{
+						Action: plans.Update,
+					},
+					Sensitive: true,
+				},
+			},
+		},
+	}
+	v.Plan(plan, testSchemas())
+
+	want := []map[string]interface{}{
+		// No resource changes
+		{
+			"@level":   "info",
+			"@message": "Plan: 0 to add, 0 to change, 0 to destroy.",
+			"@module":  "terraform.ui",
+			"type":     "change_summary",
+			"changes": map[string]interface{}{
+				"operation": "plan",
+				"add":       float64(0),
+				"import":    float64(0),
+				"change":    float64(0),
+				"remove":    float64(0),
+			},
+		},
+		// Output changes
+		{
+			"@level":   "info",
+			"@message": "Outputs: 4",
+			"@module":  "terraform.ui",
+			"type":     "outputs",
+			"outputs": map[string]interface{}{
+				"boop": map[string]interface{}{
+					"action":    "noop",
+					"sensitive": false,
+				},
+				"beep": map[string]interface{}{
+					"action":    "create",
+					"sensitive": false,
+				},
+				"bonk": map[string]interface{}{
+					"action":    "delete",
+					"sensitive": false,
+				},
+				"honk": map[string]interface{}{
+					"action":    "update",
+					"sensitive": true,
+				},
+			},
+		},
+	}
+
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
+
+func TestOperationJSON_plannedChange(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := &OperationJSON{view: NewJSONView(NewView(streams))}
+
+	root := addrs.RootModuleInstance
+	boop := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_instance", Name: "boop"}
+	derp := addrs.Resource{Mode: addrs.DataResourceMode, Type: "test_source", Name: "derp"}
+
+	// Replace requested by user
+	v.PlannedChange(&plans.ResourceInstanceChangeSrc{
+		Addr:         boop.Instance(addrs.IntKey(0)).Absolute(root),
+		PrevRunAddr:  boop.Instance(addrs.IntKey(0)).Absolute(root),
+		ChangeSrc:    plans.ChangeSrc{Action: plans.DeleteThenCreate},
+		ActionReason: plans.ResourceInstanceReplaceByRequest,
+	})
+
+	// Simple create
+	v.PlannedChange(&plans.ResourceInstanceChangeSrc{
+		Addr:        boop.Instance(addrs.IntKey(1)).Absolute(root),
+		PrevRunAddr: boop.Instance(addrs.IntKey(1)).Absolute(root),
+		ChangeSrc:   plans.ChangeSrc{Action: plans.Create},
+	})
+
+	// Data source deletion
+	v.PlannedChange(&plans.ResourceInstanceChangeSrc{
+		Addr:        derp.Instance(addrs.NoKey).Absolute(root),
+		PrevRunAddr: derp.Instance(addrs.NoKey).Absolute(root),
+		ChangeSrc:   plans.ChangeSrc{Action: plans.Delete},
+	})
+
+	// Expect only two messages, as the data source deletion should be a no-op
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": "test_instance.boop[0]: Plan to replace",
+			"@module":  "terraform.ui",
+			"type":     "planned_change",
+			"change": map[string]interface{}{
+				"action": "replace",
+				"reason": "requested",
+				"resource": map[string]interface{}{
+					"addr":             `test_instance.boop[0]`,
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         `test_instance.boop[0]`,
+					"resource_key":     float64(0),
+					"resource_name":    "boop",
+					"resource_type":    "test_instance",
+				},
+			},
+		},
+		{
+			"@level":   "info",
+			"@message": "test_instance.boop[1]: Plan to create",
+			"@module":  "terraform.ui",
+			"type":     "planned_change",
+			"change": map[string]interface{}{
+				"action": "create",
+				"resource": map[string]interface{}{
+					"addr":             `test_instance.boop[1]`,
+					"implied_provider": "test",
+					"module":           "",
+					"resource":         `test_instance.boop[1]`,
+					"resource_key":     float64(1),
+					"resource_name":    "boop",
+					"resource_type":    "test_instance",
+				},
+			},
+		},
+	}
+
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
diff --git a/v1.5.7/internal/command/views/output.go b/v1.5.7/internal/command/views/output.go
new file mode 100644
index 0000000..8882f13
--- /dev/null
+++ b/v1.5.7/internal/command/views/output.go
@@ -0,0 +1,288 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"sort"
+	"strings"
+
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/convert"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/repl"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// The Output view renders either one or all outputs, depending on whether or
+// not the name argument is empty.
+type Output interface {
+	Output(name string, outputs map[string]*states.OutputValue) tfdiags.Diagnostics
+	Diagnostics(diags tfdiags.Diagnostics)
+}
+
+// NewOutput returns an initialized Output implementation for the given ViewType.
+func NewOutput(vt arguments.ViewType, view *View) Output {
+	switch vt {
+	case arguments.ViewJSON:
+		return &OutputJSON{view: view}
+	case arguments.ViewRaw:
+		return &OutputRaw{view: view}
+	case arguments.ViewHuman:
+		return &OutputHuman{view: view}
+	default:
+		panic(fmt.Sprintf("unknown view type %v", vt))
+	}
+}
+
+// The OutputHuman implementation renders outputs in a format equivalent to HCL
+// source. This uses the same formatting logic as in the console REPL.
+type OutputHuman struct {
+	view *View
+}
+
+var _ Output = (*OutputHuman)(nil)
+
+func (v *OutputHuman) Output(name string, outputs map[string]*states.OutputValue) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	if len(outputs) == 0 {
+		diags = diags.Append(noOutputsWarning())
+		return diags
+	}
+
+	if name != "" {
+		output, ok := outputs[name]
+		if !ok {
+			diags = diags.Append(missingOutputError(name))
+			return diags
+		}
+		result := repl.FormatValue(output.Value, 0)
+		v.view.streams.Println(result)
+		return nil
+	}
+
+	outputBuf := new(bytes.Buffer)
+	if len(outputs) > 0 {
+		// Output the outputs in alphabetical order
+		keyLen := 0
+		ks := make([]string, 0, len(outputs))
+		for key := range outputs {
+			ks = append(ks, key)
+			if len(key) > keyLen {
+				keyLen = len(key)
+			}
+		}
+		sort.Strings(ks)
+
+		for _, k := range ks {
+			v := outputs[k]
+			if v.Sensitive {
+				outputBuf.WriteString(fmt.Sprintf("%s = <sensitive>\n", k))
+				continue
+			}
+
+			result := repl.FormatValue(v.Value, 0)
+			outputBuf.WriteString(fmt.Sprintf("%s = %s\n", k, result))
+		}
+	}
+
+	v.view.streams.Println(strings.TrimSpace(outputBuf.String()))
+
+	return nil
+}
+
+func (v *OutputHuman) Diagnostics(diags tfdiags.Diagnostics) {
+	v.view.Diagnostics(diags)
+}
+
+// The OutputRaw implementation renders single string, number, or boolean
+// output values directly and without quotes or other formatting. This is
+// intended for use in shell scripting or other environments where the exact
+// type of an output value is not important.
+type OutputRaw struct {
+	view *View
+}
+
+var _ Output = (*OutputRaw)(nil)
+
+func (v *OutputRaw) Output(name string, outputs map[string]*states.OutputValue) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	if len(outputs) == 0 {
+		diags = diags.Append(noOutputsWarning())
+		return diags
+	}
+
+	if name == "" {
+		diags = diags.Append(fmt.Errorf("Raw output format is only supported for single outputs"))
+		return diags
+	}
+
+	output, ok := outputs[name]
+	if !ok {
+		diags = diags.Append(missingOutputError(name))
+		return diags
+	}
+
+	strV, err := convert.Convert(output.Value, cty.String)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Unsupported value for raw output",
+			fmt.Sprintf(
+				"The -raw option only supports strings, numbers, and boolean values, but output value %q is %s.\n\nUse the -json option for machine-readable representations of output values that have complex types.",
+				name, output.Value.Type().FriendlyName(),
+			),
+		))
+		return diags
+	}
+	if strV.IsNull() {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Unsupported value for raw output",
+			fmt.Sprintf(
+				"The value for output value %q is null, so -raw mode cannot print it.",
+				name,
+			),
+		))
+		return diags
+	}
+	if !strV.IsKnown() {
+		// Since we're working with values from the state it would be very
+		// odd to end up in here, but we'll handle it anyway to avoid a
+		// panic in case our rules somehow change in future.
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Unsupported value for raw output",
+			fmt.Sprintf(
+				"The value for output value %q won't be known until after a successful terraform apply, so -raw mode cannot print it.",
+				name,
+			),
+		))
+		return diags
+	}
+	// If we get out here then we should have a valid string to print.
+	// We're writing it using Print here so that a shell caller will get
+	// exactly the value and no extra whitespace (including trailing newline).
+	v.view.streams.Print(strV.AsString())
+	return nil
+}
+
+func (v *OutputRaw) Diagnostics(diags tfdiags.Diagnostics) {
+	v.view.Diagnostics(diags)
+}
+
+// The OutputJSON implementation renders outputs as JSON values. When rendering
+// a single output, only the value is displayed. When rendering all outputs,
+// the result is a JSON object with keys matching the output names and object
+// values including type and sensitivity metadata.
+type OutputJSON struct {
+	view *View
+}
+
+var _ Output = (*OutputJSON)(nil)
+
+func (v *OutputJSON) Output(name string, outputs map[string]*states.OutputValue) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	if name != "" {
+		output, ok := outputs[name]
+		if !ok {
+			diags = diags.Append(missingOutputError(name))
+			return diags
+		}
+		value := output.Value
+
+		jsonOutput, err := ctyjson.Marshal(value, value.Type())
+		if err != nil {
+			diags = diags.Append(err)
+			return diags
+		}
+
+		v.view.streams.Println(string(jsonOutput))
+
+		return nil
+	}
+
+	// Due to a historical accident, the switch from state version 2 to
+	// 3 caused our JSON output here to be the full metadata about the
+	// outputs rather than just the output values themselves as we'd
+	// show in the single value case. We must now maintain that behavior
+	// for compatibility, so this is an emulation of the JSON
+	// serialization of outputs used in state format version 3.
+	type OutputMeta struct {
+		Sensitive bool            `json:"sensitive"`
+		Type      json.RawMessage `json:"type"`
+		Value     json.RawMessage `json:"value"`
+	}
+	outputMetas := map[string]OutputMeta{}
+
+	for n, os := range outputs {
+		jsonVal, err := ctyjson.Marshal(os.Value, os.Value.Type())
+		if err != nil {
+			diags = diags.Append(err)
+			return diags
+		}
+		jsonType, err := ctyjson.MarshalType(os.Value.Type())
+		if err != nil {
+			diags = diags.Append(err)
+			return diags
+		}
+		outputMetas[n] = OutputMeta{
+			Sensitive: os.Sensitive,
+			Type:      json.RawMessage(jsonType),
+			Value:     json.RawMessage(jsonVal),
+		}
+	}
+
+	jsonOutputs, err := json.MarshalIndent(outputMetas, "", "  ")
+	if err != nil {
+		diags = diags.Append(err)
+		return diags
+	}
+
+	v.view.streams.Println(string(jsonOutputs))
+
+	return nil
+}
+
+func (v *OutputJSON) Diagnostics(diags tfdiags.Diagnostics) {
+	v.view.Diagnostics(diags)
+}
+
+// For text and raw output modes, an empty map of outputs is considered a
+// separate and higher priority failure mode than an output not being present
+// in a non-empty map. This warning diagnostic explains how this might have
+// happened.
+func noOutputsWarning() tfdiags.Diagnostic {
+	return tfdiags.Sourceless(
+		tfdiags.Warning,
+		"No outputs found",
+		"The state file either has no outputs defined, or all the defined "+
+			"outputs are empty. Please define an output in your configuration "+
+			"with the `output` keyword and run `terraform refresh` for it to "+
+			"become available. If you are using interpolation, please verify "+
+			"the interpolated value is not empty. You can use the "+
+			"`terraform console` command to assist.",
+	)
+}
+
+// Attempting to display a missing output results in this failure, which
+// includes suggestions on how to rectify the problem.
+func missingOutputError(name string) tfdiags.Diagnostic {
+	return tfdiags.Sourceless(
+		tfdiags.Error,
+		fmt.Sprintf("Output %q not found", name),
+		"The output variable requested could not be found in the state "+
+			"file. If you recently added this to your configuration, be "+
+			"sure to run `terraform apply`, since the state won't be updated "+
+			"with new output variables until that command is run.",
+	)
+}
diff --git a/v1.5.7/internal/command/views/output_test.go b/v1.5.7/internal/command/views/output_test.go
new file mode 100644
index 0000000..65b76af
--- /dev/null
+++ b/v1.5.7/internal/command/views/output_test.go
@@ -0,0 +1,366 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Test various single output values for human-readable UI. Note that since
+// OutputHuman defers to repl.FormatValue to render a single value, most of the
+// test coverage should be in that package.
+func TestOutputHuman_single(t *testing.T) {
+	testCases := map[string]struct {
+		value   cty.Value
+		want    string
+		wantErr bool
+	}{
+		"string": {
+			value: cty.StringVal("hello"),
+			want:  "\"hello\"\n",
+		},
+		"list of maps": {
+			value: cty.ListVal([]cty.Value{
+				cty.MapVal(map[string]cty.Value{
+					"key":  cty.StringVal("value"),
+					"key2": cty.StringVal("value2"),
+				}),
+				cty.MapVal(map[string]cty.Value{
+					"key": cty.StringVal("value"),
+				}),
+			}),
+			want: `tolist([
+  tomap({
+    "key" = "value"
+    "key2" = "value2"
+  }),
+  tomap({
+    "key" = "value"
+  }),
+])
+`,
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			v := NewOutput(arguments.ViewHuman, NewView(streams))
+
+			outputs := map[string]*states.OutputValue{
+				"foo": {Value: tc.value},
+			}
+			diags := v.Output("foo", outputs)
+
+			if diags.HasErrors() {
+				if !tc.wantErr {
+					t.Fatalf("unexpected diagnostics: %s", diags)
+				}
+			} else if tc.wantErr {
+				t.Fatalf("succeeded, but want error")
+			}
+
+			if got, want := done(t).Stdout(), tc.want; got != want {
+				t.Errorf("wrong result\ngot:  %q\nwant: %q", got, want)
+			}
+		})
+	}
+}
+
+// Sensitive output values are rendered to the console intentionally when
+// requesting a single output.
+func TestOutput_sensitive(t *testing.T) {
+	testCases := map[string]arguments.ViewType{
+		"human": arguments.ViewHuman,
+		"json":  arguments.ViewJSON,
+		"raw":   arguments.ViewRaw,
+	}
+	for name, vt := range testCases {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			v := NewOutput(vt, NewView(streams))
+
+			outputs := map[string]*states.OutputValue{
+				"foo": {
+					Value:     cty.StringVal("secret"),
+					Sensitive: true,
+				},
+			}
+			diags := v.Output("foo", outputs)
+
+			if diags.HasErrors() {
+				t.Fatalf("unexpected diagnostics: %s", diags)
+			}
+
+			// Test for substring match here because we don't care about exact
+			// output format in this test, just the presence of the sensitive
+			// value.
+			if got, want := done(t).Stdout(), "secret"; !strings.Contains(got, want) {
+				t.Errorf("wrong result\ngot:  %q\nwant: %q", got, want)
+			}
+		})
+	}
+}
+
+// Showing all outputs is supported by human and JSON output format.
+func TestOutput_all(t *testing.T) {
+	outputs := map[string]*states.OutputValue{
+		"foo": {
+			Value:     cty.StringVal("secret"),
+			Sensitive: true,
+		},
+		"bar": {
+			Value: cty.ListVal([]cty.Value{cty.True, cty.False, cty.True}),
+		},
+		"baz": {
+			Value: cty.ObjectVal(map[string]cty.Value{
+				"boop": cty.NumberIntVal(5),
+				"beep": cty.StringVal("true"),
+			}),
+		},
+	}
+
+	testCases := map[string]struct {
+		vt   arguments.ViewType
+		want string
+	}{
+		"human": {
+			arguments.ViewHuman,
+			`bar = tolist([
+  true,
+  false,
+  true,
+])
+baz = {
+  "beep" = "true"
+  "boop" = 5
+}
+foo = <sensitive>
+`,
+		},
+		"json": {
+			arguments.ViewJSON,
+			`{
+  "bar": {
+    "sensitive": false,
+    "type": [
+      "list",
+      "bool"
+    ],
+    "value": [
+      true,
+      false,
+      true
+    ]
+  },
+  "baz": {
+    "sensitive": false,
+    "type": [
+      "object",
+      {
+        "beep": "string",
+        "boop": "number"
+      }
+    ],
+    "value": {
+      "beep": "true",
+      "boop": 5
+    }
+  },
+  "foo": {
+    "sensitive": true,
+    "type": "string",
+    "value": "secret"
+  }
+}
+`,
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			v := NewOutput(tc.vt, NewView(streams))
+			diags := v.Output("", outputs)
+
+			if diags.HasErrors() {
+				t.Fatalf("unexpected diagnostics: %s", diags)
+			}
+
+			if got := done(t).Stdout(); got != tc.want {
+				t.Errorf("wrong result\ngot:  %q\nwant: %q", got, tc.want)
+			}
+		})
+	}
+}
+
+// JSON output format supports empty outputs by rendering an empty object
+// without diagnostics.
+func TestOutputJSON_empty(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := NewOutput(arguments.ViewJSON, NewView(streams))
+
+	diags := v.Output("", map[string]*states.OutputValue{})
+
+	if diags.HasErrors() {
+		t.Fatalf("unexpected diagnostics: %s", diags)
+	}
+
+	if got, want := done(t).Stdout(), "{}\n"; got != want {
+		t.Errorf("wrong result\ngot:  %q\nwant: %q", got, want)
+	}
+}
+
+// Human and raw formats render a warning if there are no outputs.
+func TestOutput_emptyWarning(t *testing.T) {
+	testCases := map[string]arguments.ViewType{
+		"human": arguments.ViewHuman,
+		"raw":   arguments.ViewRaw,
+	}
+
+	for name, vt := range testCases {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			v := NewOutput(vt, NewView(streams))
+
+			diags := v.Output("", map[string]*states.OutputValue{})
+
+			if got, want := done(t).Stdout(), ""; got != want {
+				t.Errorf("wrong result\ngot:  %q\nwant: %q", got, want)
+			}
+
+			if len(diags) != 1 {
+				t.Fatalf("expected 1 diagnostic, got %d", len(diags))
+			}
+
+			if diags.HasErrors() {
+				t.Fatalf("unexpected error diagnostics: %s", diags)
+			}
+
+			if got, want := diags[0].Description().Summary, "No outputs found"; got != want {
+				t.Errorf("unexpected diagnostics: %s", diags)
+			}
+		})
+	}
+}
+
+// Raw output is a simple unquoted output format designed for shell scripts,
+// which relies on the cty.AsString() implementation. This test covers
+// formatting for supported value types.
+func TestOutputRaw(t *testing.T) {
+	values := map[string]cty.Value{
+		"str":      cty.StringVal("bar"),
+		"multistr": cty.StringVal("bar\nbaz"),
+		"num":      cty.NumberIntVal(2),
+		"bool":     cty.True,
+		"obj":      cty.EmptyObjectVal,
+		"null":     cty.NullVal(cty.String),
+		"unknown":  cty.UnknownVal(cty.String),
+	}
+
+	tests := map[string]struct {
+		WantOutput string
+		WantErr    bool
+	}{
+		"str":      {WantOutput: "bar"},
+		"multistr": {WantOutput: "bar\nbaz"},
+		"num":      {WantOutput: "2"},
+		"bool":     {WantOutput: "true"},
+		"obj":      {WantErr: true},
+		"null":     {WantErr: true},
+		"unknown":  {WantErr: true},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			v := NewOutput(arguments.ViewRaw, NewView(streams))
+
+			value := values[name]
+			outputs := map[string]*states.OutputValue{
+				name: {Value: value},
+			}
+			diags := v.Output(name, outputs)
+
+			if diags.HasErrors() {
+				if !test.WantErr {
+					t.Fatalf("unexpected diagnostics: %s", diags)
+				}
+			} else if test.WantErr {
+				t.Fatalf("succeeded, but want error")
+			}
+
+			if got, want := done(t).Stdout(), test.WantOutput; got != want {
+				t.Errorf("wrong result\ngot:  %q\nwant: %q", got, want)
+			}
+		})
+	}
+}
+
+// Raw cannot render all outputs.
+func TestOutputRaw_all(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := NewOutput(arguments.ViewRaw, NewView(streams))
+
+	outputs := map[string]*states.OutputValue{
+		"foo": {Value: cty.StringVal("secret")},
+		"bar": {Value: cty.True},
+	}
+	diags := v.Output("", outputs)
+
+	if got, want := done(t).Stdout(), ""; got != want {
+		t.Errorf("wrong result\ngot:  %q\nwant: %q", got, want)
+	}
+
+	if !diags.HasErrors() {
+		t.Fatalf("expected diagnostics, got %s", diags)
+	}
+
+	if got, want := diags.Err().Error(), "Raw output format is only supported for single outputs"; got != want {
+		t.Errorf("unexpected diagnostics: %s", diags)
+	}
+}
+
+// All outputs render an error if a specific output is requested which is
+// missing from the map of outputs.
+func TestOutput_missing(t *testing.T) {
+	testCases := map[string]arguments.ViewType{
+		"human": arguments.ViewHuman,
+		"json":  arguments.ViewJSON,
+		"raw":   arguments.ViewRaw,
+	}
+
+	for name, vt := range testCases {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			v := NewOutput(vt, NewView(streams))
+
+			diags := v.Output("foo", map[string]*states.OutputValue{
+				"bar": {Value: cty.StringVal("boop")},
+			})
+
+			if len(diags) != 1 {
+				t.Fatalf("expected 1 diagnostic, got %d", len(diags))
+			}
+
+			if !diags.HasErrors() {
+				t.Fatalf("expected error diagnostics, got %s", diags)
+			}
+
+			if got, want := diags[0].Description().Summary, `Output "foo" not found`; got != want {
+				t.Errorf("unexpected diagnostics: %s", diags)
+			}
+
+			if got, want := done(t).Stdout(), ""; got != want {
+				t.Errorf("wrong result\ngot:  %q\nwant: %q", got, want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/views/plan.go b/v1.5.7/internal/command/views/plan.go
new file mode 100644
index 0000000..ab1f766
--- /dev/null
+++ b/v1.5.7/internal/command/views/plan.go
@@ -0,0 +1,91 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// The Plan view is used for the plan command.
+type Plan interface {
+	Operation() Operation
+	Hooks() []terraform.Hook
+
+	Diagnostics(diags tfdiags.Diagnostics)
+	HelpPrompt()
+}
+
+// NewPlan returns an initialized Plan implementation for the given ViewType.
+func NewPlan(vt arguments.ViewType, view *View) Plan {
+	switch vt {
+	case arguments.ViewJSON:
+		return &PlanJSON{
+			view: NewJSONView(view),
+		}
+	case arguments.ViewHuman:
+		return &PlanHuman{
+			view:         view,
+			inAutomation: view.RunningInAutomation(),
+		}
+	default:
+		panic(fmt.Sprintf("unknown view type %v", vt))
+	}
+}
+
+// The PlanHuman implementation renders human-readable text logs, suitable for
+// a scrolling terminal.
+type PlanHuman struct {
+	view *View
+
+	inAutomation bool
+}
+
+var _ Plan = (*PlanHuman)(nil)
+
+func (v *PlanHuman) Operation() Operation {
+	return NewOperation(arguments.ViewHuman, v.inAutomation, v.view)
+}
+
+func (v *PlanHuman) Hooks() []terraform.Hook {
+	return []terraform.Hook{
+		NewUiHook(v.view),
+	}
+}
+
+func (v *PlanHuman) Diagnostics(diags tfdiags.Diagnostics) {
+	v.view.Diagnostics(diags)
+}
+
+func (v *PlanHuman) HelpPrompt() {
+	v.view.HelpPrompt("plan")
+}
+
+// The PlanJSON implementation renders streaming JSON logs, suitable for
+// integrating with other software.
+type PlanJSON struct {
+	view *JSONView
+}
+
+var _ Plan = (*PlanJSON)(nil)
+
+func (v *PlanJSON) Operation() Operation {
+	return &OperationJSON{view: v.view}
+}
+
+func (v *PlanJSON) Hooks() []terraform.Hook {
+	return []terraform.Hook{
+		newJSONHook(v.view),
+	}
+}
+
+func (v *PlanJSON) Diagnostics(diags tfdiags.Diagnostics) {
+	v.view.Diagnostics(diags)
+}
+
+func (v *PlanJSON) HelpPrompt() {
+}
diff --git a/v1.5.7/internal/command/views/plan_test.go b/v1.5.7/internal/command/views/plan_test.go
new file mode 100644
index 0000000..0011f6b
--- /dev/null
+++ b/v1.5.7/internal/command/views/plan_test.go
@@ -0,0 +1,179 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Ensure that the correct view type and in-automation settings propagate to the
+// Operation view.
+func TestPlanHuman_operation(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	defer done(t)
+	v := NewPlan(arguments.ViewHuman, NewView(streams).SetRunningInAutomation(true)).Operation()
+	if hv, ok := v.(*OperationHuman); !ok {
+		t.Fatalf("unexpected return type %t", v)
+	} else if hv.inAutomation != true {
+		t.Fatalf("unexpected inAutomation value on Operation view")
+	}
+}
+
+// Verify that Hooks includes a UI hook
+func TestPlanHuman_hooks(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	defer done(t)
+	v := NewPlan(arguments.ViewHuman, NewView(streams).SetRunningInAutomation((true)))
+	hooks := v.Hooks()
+
+	var uiHook *UiHook
+	for _, hook := range hooks {
+		if ch, ok := hook.(*UiHook); ok {
+			uiHook = ch
+		}
+	}
+	if uiHook == nil {
+		t.Fatalf("expected Hooks to include a UiHook: %#v", hooks)
+	}
+}
+
+// Helper functions to build a trivial test plan, to exercise the plan
+// renderer.
+func testPlan(t *testing.T) *plans.Plan {
+	t.Helper()
+
+	plannedVal := cty.ObjectVal(map[string]cty.Value{
+		"id":  cty.UnknownVal(cty.String),
+		"foo": cty.StringVal("bar"),
+	})
+	priorValRaw, err := plans.NewDynamicValue(cty.NullVal(plannedVal.Type()), plannedVal.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	plannedValRaw, err := plans.NewDynamicValue(plannedVal, plannedVal.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	changes := plans.NewChanges()
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_resource",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	changes.SyncWrapper().AppendResourceInstanceChange(&plans.ResourceInstanceChangeSrc{
+		Addr:        addr,
+		PrevRunAddr: addr,
+		ProviderAddr: addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+		ChangeSrc: plans.ChangeSrc{
+			Action: plans.Create,
+			Before: priorValRaw,
+			After:  plannedValRaw,
+		},
+	})
+
+	return &plans.Plan{
+		Changes: changes,
+	}
+}
+
+func testPlanWithDatasource(t *testing.T) *plans.Plan {
+	plan := testPlan(t)
+
+	addr := addrs.Resource{
+		Mode: addrs.DataResourceMode,
+		Type: "test_data_source",
+		Name: "bar",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	dataVal := cty.ObjectVal(map[string]cty.Value{
+		"id":  cty.StringVal("C6743020-40BD-4591-81E6-CD08494341D3"),
+		"bar": cty.StringVal("foo"),
+	})
+	priorValRaw, err := plans.NewDynamicValue(cty.NullVal(dataVal.Type()), dataVal.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+	plannedValRaw, err := plans.NewDynamicValue(dataVal, dataVal.Type())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	plan.Changes.SyncWrapper().AppendResourceInstanceChange(&plans.ResourceInstanceChangeSrc{
+		Addr:        addr,
+		PrevRunAddr: addr,
+		ProviderAddr: addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+		ChangeSrc: plans.ChangeSrc{
+			Action: plans.Read,
+			Before: priorValRaw,
+			After:  plannedValRaw,
+		},
+	})
+
+	return plan
+}
+
+func testSchemas() *terraform.Schemas {
+	provider := testProvider()
+	return &terraform.Schemas{
+		Providers: map[addrs.Provider]*terraform.ProviderSchema{
+			addrs.NewDefaultProvider("test"): provider.ProviderSchema(),
+		},
+	}
+}
+
+func testProvider() *terraform.MockProvider {
+	p := new(terraform.MockProvider)
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		return providers.ReadResourceResponse{NewState: req.PriorState}
+	}
+
+	p.GetProviderSchemaResponse = testProviderSchema()
+
+	return p
+}
+
+func testProviderSchema() *providers.GetProviderSchemaResponse {
+	return &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_resource": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":  {Type: cty.String, Computed: true},
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+		DataSources: map[string]providers.Schema{
+			"test_data_source": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":  {Type: cty.String, Required: true},
+						"bar": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+}
diff --git a/v1.5.7/internal/command/views/refresh.go b/v1.5.7/internal/command/views/refresh.go
new file mode 100644
index 0000000..230a48c
--- /dev/null
+++ b/v1.5.7/internal/command/views/refresh.go
@@ -0,0 +1,115 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/views/json"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// The Refresh view is used for the refresh command.
+type Refresh interface {
+	Outputs(outputValues map[string]*states.OutputValue)
+
+	Operation() Operation
+	Hooks() []terraform.Hook
+
+	Diagnostics(diags tfdiags.Diagnostics)
+	HelpPrompt()
+}
+
+// NewRefresh returns an initialized Refresh implementation for the given ViewType.
+func NewRefresh(vt arguments.ViewType, view *View) Refresh {
+	switch vt {
+	case arguments.ViewJSON:
+		return &RefreshJSON{
+			view: NewJSONView(view),
+		}
+	case arguments.ViewHuman:
+		return &RefreshHuman{
+			view:         view,
+			inAutomation: view.RunningInAutomation(),
+			countHook:    &countHook{},
+		}
+	default:
+		panic(fmt.Sprintf("unknown view type %v", vt))
+	}
+}
+
+// The RefreshHuman implementation renders human-readable text logs, suitable for
+// a scrolling terminal.
+type RefreshHuman struct {
+	view *View
+
+	inAutomation bool
+
+	countHook *countHook
+}
+
+var _ Refresh = (*RefreshHuman)(nil)
+
+func (v *RefreshHuman) Outputs(outputValues map[string]*states.OutputValue) {
+	if len(outputValues) > 0 {
+		v.view.streams.Print(v.view.colorize.Color("[reset][bold][green]\nOutputs:\n\n"))
+		NewOutput(arguments.ViewHuman, v.view).Output("", outputValues)
+	}
+}
+
+func (v *RefreshHuman) Operation() Operation {
+	return NewOperation(arguments.ViewHuman, v.inAutomation, v.view)
+}
+
+func (v *RefreshHuman) Hooks() []terraform.Hook {
+	return []terraform.Hook{
+		v.countHook,
+		NewUiHook(v.view),
+	}
+}
+
+func (v *RefreshHuman) Diagnostics(diags tfdiags.Diagnostics) {
+	v.view.Diagnostics(diags)
+}
+
+func (v *RefreshHuman) HelpPrompt() {
+	v.view.HelpPrompt("refresh")
+}
+
+// The RefreshJSON implementation renders streaming JSON logs, suitable for
+// integrating with other software.
+type RefreshJSON struct {
+	view *JSONView
+}
+
+var _ Refresh = (*RefreshJSON)(nil)
+
+func (v *RefreshJSON) Outputs(outputValues map[string]*states.OutputValue) {
+	outputs, diags := json.OutputsFromMap(outputValues)
+	if diags.HasErrors() {
+		v.Diagnostics(diags)
+	} else {
+		v.view.Outputs(outputs)
+	}
+}
+
+func (v *RefreshJSON) Operation() Operation {
+	return &OperationJSON{view: v.view}
+}
+
+func (v *RefreshJSON) Hooks() []terraform.Hook {
+	return []terraform.Hook{
+		newJSONHook(v.view),
+	}
+}
+
+func (v *RefreshJSON) Diagnostics(diags tfdiags.Diagnostics) {
+	v.view.Diagnostics(diags)
+}
+
+func (v *RefreshJSON) HelpPrompt() {
+}
diff --git a/v1.5.7/internal/command/views/refresh_test.go b/v1.5.7/internal/command/views/refresh_test.go
new file mode 100644
index 0000000..355324e
--- /dev/null
+++ b/v1.5.7/internal/command/views/refresh_test.go
@@ -0,0 +1,110 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Ensure that the correct view type and in-automation settings propagate to the
+// Operation view.
+func TestRefreshHuman_operation(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	defer done(t)
+	v := NewRefresh(arguments.ViewHuman, NewView(streams).SetRunningInAutomation(true)).Operation()
+	if hv, ok := v.(*OperationHuman); !ok {
+		t.Fatalf("unexpected return type %t", v)
+	} else if hv.inAutomation != true {
+		t.Fatalf("unexpected inAutomation value on Operation view")
+	}
+}
+
+// Verify that Hooks includes a UI hook
+func TestRefreshHuman_hooks(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	defer done(t)
+	v := NewRefresh(arguments.ViewHuman, NewView(streams).SetRunningInAutomation(true))
+	hooks := v.Hooks()
+
+	var uiHook *UiHook
+	for _, hook := range hooks {
+		if ch, ok := hook.(*UiHook); ok {
+			uiHook = ch
+		}
+	}
+	if uiHook == nil {
+		t.Fatalf("expected Hooks to include a UiHook: %#v", hooks)
+	}
+}
+
+// Basic test coverage of Outputs, since most of its functionality is tested
+// elsewhere.
+func TestRefreshHuman_outputs(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := NewRefresh(arguments.ViewHuman, NewView(streams))
+
+	v.Outputs(map[string]*states.OutputValue{
+		"foo": {Value: cty.StringVal("secret")},
+	})
+
+	got := done(t).Stdout()
+	for _, want := range []string{"Outputs:", `foo = "secret"`} {
+		if !strings.Contains(got, want) {
+			t.Errorf("wrong result\ngot:  %q\nwant: %q", got, want)
+		}
+	}
+}
+
+// Outputs should do nothing if there are no outputs to render.
+func TestRefreshHuman_outputsEmpty(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := NewRefresh(arguments.ViewHuman, NewView(streams))
+
+	v.Outputs(map[string]*states.OutputValue{})
+
+	got := done(t).Stdout()
+	if got != "" {
+		t.Errorf("output should be empty, but got: %q", got)
+	}
+}
+
+// Basic test coverage of Outputs, since most of its functionality is tested
+// elsewhere.
+func TestRefreshJSON_outputs(t *testing.T) {
+	streams, done := terminal.StreamsForTesting(t)
+	v := NewRefresh(arguments.ViewJSON, NewView(streams))
+
+	v.Outputs(map[string]*states.OutputValue{
+		"boop_count": {Value: cty.NumberIntVal(92)},
+		"password":   {Value: cty.StringVal("horse-battery").Mark(marks.Sensitive), Sensitive: true},
+	})
+
+	want := []map[string]interface{}{
+		{
+			"@level":   "info",
+			"@message": "Outputs: 2",
+			"@module":  "terraform.ui",
+			"type":     "outputs",
+			"outputs": map[string]interface{}{
+				"boop_count": map[string]interface{}{
+					"sensitive": false,
+					"value":     float64(92),
+					"type":      "number",
+				},
+				"password": map[string]interface{}{
+					"sensitive": true,
+					"type":      "string",
+				},
+			},
+		},
+	}
+	testJSONViewOutputEquals(t, done(t).Stdout(), want)
+}
diff --git a/v1.5.7/internal/command/views/show.go b/v1.5.7/internal/command/views/show.go
new file mode 100644
index 0000000..23f8737
--- /dev/null
+++ b/v1.5.7/internal/command/views/show.go
@@ -0,0 +1,141 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/jsonformat"
+	"github.com/hashicorp/terraform/internal/command/jsonplan"
+	"github.com/hashicorp/terraform/internal/command/jsonprovider"
+	"github.com/hashicorp/terraform/internal/command/jsonstate"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+type Show interface {
+	// Display renders the plan, if it is available. If plan is nil, it renders the statefile.
+	Display(config *configs.Config, plan *plans.Plan, stateFile *statefile.File, schemas *terraform.Schemas) int
+
+	// Diagnostics renders early diagnostics, resulting from argument parsing.
+	Diagnostics(diags tfdiags.Diagnostics)
+}
+
+func NewShow(vt arguments.ViewType, view *View) Show {
+	switch vt {
+	case arguments.ViewJSON:
+		return &ShowJSON{view: view}
+	case arguments.ViewHuman:
+		return &ShowHuman{view: view}
+	default:
+		panic(fmt.Sprintf("unknown view type %v", vt))
+	}
+}
+
+type ShowHuman struct {
+	view *View
+}
+
+var _ Show = (*ShowHuman)(nil)
+
+func (v *ShowHuman) Display(config *configs.Config, plan *plans.Plan, stateFile *statefile.File, schemas *terraform.Schemas) int {
+	renderer := jsonformat.Renderer{
+		Colorize:            v.view.colorize,
+		Streams:             v.view.streams,
+		RunningInAutomation: v.view.runningInAutomation,
+	}
+
+	if plan != nil {
+		outputs, changed, drift, attrs, err := jsonplan.MarshalForRenderer(plan, schemas)
+		if err != nil {
+			v.view.streams.Eprintf("Failed to marshal plan to json: %s", err)
+			return 1
+		}
+
+		jplan := jsonformat.Plan{
+			PlanFormatVersion:     jsonplan.FormatVersion,
+			ProviderFormatVersion: jsonprovider.FormatVersion,
+			OutputChanges:         outputs,
+			ResourceChanges:       changed,
+			ResourceDrift:         drift,
+			ProviderSchemas:       jsonprovider.MarshalForRenderer(schemas),
+			RelevantAttributes:    attrs,
+		}
+
+		var opts []jsonformat.PlanRendererOpt
+		if !plan.CanApply() {
+			opts = append(opts, jsonformat.CanNotApply)
+		}
+		if plan.Errored {
+			opts = append(opts, jsonformat.Errored)
+		}
+
+		renderer.RenderHumanPlan(jplan, plan.UIMode, opts...)
+	} else {
+		if stateFile == nil {
+			v.view.streams.Println("No state.")
+			return 0
+		}
+
+		root, outputs, err := jsonstate.MarshalForRenderer(stateFile, schemas)
+		if err != nil {
+			v.view.streams.Eprintf("Failed to marshal state to json: %s", err)
+			return 1
+		}
+
+		jstate := jsonformat.State{
+			StateFormatVersion:    jsonstate.FormatVersion,
+			ProviderFormatVersion: jsonprovider.FormatVersion,
+			RootModule:            root,
+			RootModuleOutputs:     outputs,
+			ProviderSchemas:       jsonprovider.MarshalForRenderer(schemas),
+		}
+
+		renderer.RenderHumanState(jstate)
+	}
+	return 0
+}
+
+func (v *ShowHuman) Diagnostics(diags tfdiags.Diagnostics) {
+	v.view.Diagnostics(diags)
+}
+
+type ShowJSON struct {
+	view *View
+}
+
+var _ Show = (*ShowJSON)(nil)
+
+func (v *ShowJSON) Display(config *configs.Config, plan *plans.Plan, stateFile *statefile.File, schemas *terraform.Schemas) int {
+	if plan != nil {
+		jsonPlan, err := jsonplan.Marshal(config, plan, stateFile, schemas)
+
+		if err != nil {
+			v.view.streams.Eprintf("Failed to marshal plan to json: %s", err)
+			return 1
+		}
+		v.view.streams.Println(string(jsonPlan))
+	} else {
+		// It is possible that there is neither state nor a plan.
+		// That's ok, we'll just return an empty object.
+		jsonState, err := jsonstate.Marshal(stateFile, schemas)
+		if err != nil {
+			v.view.streams.Eprintf("Failed to marshal state to json: %s", err)
+			return 1
+		}
+		v.view.streams.Println(string(jsonState))
+	}
+	return 0
+}
+
+// Diagnostics should only be called if show cannot be executed.
+// In this case, we choose to render human-readable diagnostic output,
+// primarily for backwards compatibility.
+func (v *ShowJSON) Diagnostics(diags tfdiags.Diagnostics) {
+	v.view.Diagnostics(diags)
+}
diff --git a/v1.5.7/internal/command/views/show_test.go b/v1.5.7/internal/command/views/show_test.go
new file mode 100644
index 0000000..2101b82
--- /dev/null
+++ b/v1.5.7/internal/command/views/show_test.go
@@ -0,0 +1,187 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"encoding/json"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/terraform"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestShowHuman(t *testing.T) {
+	testCases := map[string]struct {
+		plan       *plans.Plan
+		stateFile  *statefile.File
+		schemas    *terraform.Schemas
+		wantExact  bool
+		wantString string
+	}{
+		"plan file": {
+			testPlan(t),
+			nil,
+			testSchemas(),
+			false,
+			"# test_resource.foo will be created",
+		},
+		"statefile": {
+			nil,
+			&statefile.File{
+				Serial:  0,
+				Lineage: "fake-for-testing",
+				State:   testState(),
+			},
+			testSchemas(),
+			false,
+			"# test_resource.foo:",
+		},
+		"empty statefile": {
+			nil,
+			&statefile.File{
+				Serial:  0,
+				Lineage: "fake-for-testing",
+				State:   states.NewState(),
+			},
+			testSchemas(),
+			true,
+			"The state file is empty. No resources are represented.\n",
+		},
+		"nothing": {
+			nil,
+			nil,
+			nil,
+			true,
+			"No state.\n",
+		},
+	}
+	for name, testCase := range testCases {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			view := NewView(streams)
+			view.Configure(&arguments.View{NoColor: true})
+			v := NewShow(arguments.ViewHuman, view)
+
+			code := v.Display(nil, testCase.plan, testCase.stateFile, testCase.schemas)
+			if code != 0 {
+				t.Errorf("expected 0 return code, got %d", code)
+			}
+
+			output := done(t)
+			got := output.Stdout()
+			want := testCase.wantString
+			if (testCase.wantExact && got != want) || (!testCase.wantExact && !strings.Contains(got, want)) {
+				t.Fatalf("unexpected output\ngot: %s\nwant: %s", got, want)
+			}
+		})
+	}
+}
+
+func TestShowJSON(t *testing.T) {
+	testCases := map[string]struct {
+		plan      *plans.Plan
+		stateFile *statefile.File
+	}{
+		"plan file": {
+			testPlan(t),
+			nil,
+		},
+		"statefile": {
+			nil,
+			&statefile.File{
+				Serial:  0,
+				Lineage: "fake-for-testing",
+				State:   testState(),
+			},
+		},
+		"empty statefile": {
+			nil,
+			&statefile.File{
+				Serial:  0,
+				Lineage: "fake-for-testing",
+				State:   states.NewState(),
+			},
+		},
+		"nothing": {
+			nil,
+			nil,
+		},
+	}
+
+	config, _, configCleanup := initwd.MustLoadConfigForTests(t, "./testdata/show")
+	defer configCleanup()
+
+	for name, testCase := range testCases {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			view := NewView(streams)
+			view.Configure(&arguments.View{NoColor: true})
+			v := NewShow(arguments.ViewJSON, view)
+
+			schemas := &terraform.Schemas{
+				Providers: map[addrs.Provider]*terraform.ProviderSchema{
+					addrs.NewDefaultProvider("test"): {
+						ResourceTypes: map[string]*configschema.Block{
+							"test_resource": {
+								Attributes: map[string]*configschema.Attribute{
+									"id":  {Type: cty.String, Optional: true, Computed: true},
+									"foo": {Type: cty.String, Optional: true},
+								},
+							},
+						},
+					},
+				},
+			}
+
+			code := v.Display(config, testCase.plan, testCase.stateFile, schemas)
+
+			if code != 0 {
+				t.Errorf("expected 0 return code, got %d", code)
+			}
+
+			// Make sure the result looks like JSON; we comprehensively test
+			// the structure of this output in the command package tests.
+			var result map[string]interface{}
+			got := done(t).All()
+			t.Logf("output: %s", got)
+			if err := json.Unmarshal([]byte(got), &result); err != nil {
+				t.Fatal(err)
+			}
+		})
+	}
+}
+
+// testState returns a test State structure.
+func testState() *states.State {
+	return states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_resource",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar","foo":"value"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		// DeepCopy is used here to ensure our synthetic state matches exactly
+		// with a state that will have been copied during the command
+		// operation, and all fields have been copied correctly.
+	}).DeepCopy()
+}
diff --git a/v1.5.7/internal/command/views/state_locker.go b/v1.5.7/internal/command/views/state_locker.go
new file mode 100644
index 0000000..a1af054
--- /dev/null
+++ b/v1.5.7/internal/command/views/state_locker.go
@@ -0,0 +1,82 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"encoding/json"
+	"fmt"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+)
+
+// The StateLocker view is used to display locking/unlocking status messages
+// if the state lock process takes longer than expected.
+type StateLocker interface {
+	Locking()
+	Unlocking()
+}
+
+// NewStateLocker returns an initialized StateLocker implementation for the given ViewType.
+func NewStateLocker(vt arguments.ViewType, view *View) StateLocker {
+	switch vt {
+	case arguments.ViewHuman:
+		return &StateLockerHuman{view: view}
+	case arguments.ViewJSON:
+		return &StateLockerJSON{view: view}
+	default:
+		panic(fmt.Sprintf("unknown view type %v", vt))
+	}
+}
+
+// StateLockerHuman is an implementation of StateLocker which prints status to
+// a terminal.
+type StateLockerHuman struct {
+	view *View
+}
+
+var _ StateLocker = (*StateLockerHuman)(nil)
+var _ StateLocker = (*StateLockerJSON)(nil)
+
+func (v *StateLockerHuman) Locking() {
+	v.view.streams.Println("Acquiring state lock. This may take a few moments...")
+}
+
+func (v *StateLockerHuman) Unlocking() {
+	v.view.streams.Println("Releasing state lock. This may take a few moments...")
+}
+
+// StateLockerJSON is an implementation of StateLocker which prints the state lock status
+// to a terminal in machine-readable JSON form.
+type StateLockerJSON struct {
+	view *View
+}
+
+func (v *StateLockerJSON) Locking() {
+	current_timestamp := time.Now().Format(time.RFC3339)
+
+	json_data := map[string]string{
+		"@level":     "info",
+		"@message":   "Acquiring state lock. This may take a few moments...",
+		"@module":    "terraform.ui",
+		"@timestamp": current_timestamp,
+		"type":       "state_lock_acquire"}
+
+	lock_info_message, _ := json.Marshal(json_data)
+	v.view.streams.Println(string(lock_info_message))
+}
+
+func (v *StateLockerJSON) Unlocking() {
+	current_timestamp := time.Now().Format(time.RFC3339)
+
+	json_data := map[string]string{
+		"@level":     "info",
+		"@message":   "Releasing state lock. This may take a few moments...",
+		"@module":    "terraform.ui",
+		"@timestamp": current_timestamp,
+		"type":       "state_lock_release"}
+
+	lock_info_message, _ := json.Marshal(json_data)
+	v.view.streams.Println(string(lock_info_message))
+}
diff --git a/v1.5.7/internal/command/views/test.go b/v1.5.7/internal/command/views/test.go
new file mode 100644
index 0000000..06a9752
--- /dev/null
+++ b/v1.5.7/internal/command/views/test.go
@@ -0,0 +1,376 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"encoding/xml"
+	"fmt"
+	"io/ioutil"
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/format"
+	"github.com/hashicorp/terraform/internal/moduletest"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/mitchellh/colorstring"
+)
+
+// Test is the view interface for the "terraform test" command.
+type Test interface {
+	// Results presents the given test results.
+	Results(map[string]*moduletest.Suite) tfdiags.Diagnostics
+
+	// Diagnostics is for reporting warnings or errors that occurred with the
+	// mechanics of running tests. For this command in particular, some
+	// errors are considered to be test failures rather than mechanism failures,
+	// and so those will be reported via Results rather than via Diagnostics.
+	Diagnostics(tfdiags.Diagnostics)
+}
+
+// NewTest returns an implementation of Test configured to respect the
+// settings described in the given arguments.
+func NewTest(base *View, args arguments.TestOutput) Test {
+	return &testHuman{
+		streams:         base.streams,
+		showDiagnostics: base.Diagnostics,
+		colorize:        base.colorize,
+		junitXMLFile:    args.JUnitXMLFile,
+	}
+}
+
+type testHuman struct {
+	// This is the subset of functionality we need from the base view.
+	streams         *terminal.Streams
+	showDiagnostics func(diags tfdiags.Diagnostics)
+	colorize        *colorstring.Colorize
+
+	// If junitXMLFile is not empty then results will be written to
+	// the given file path in addition to the usual output.
+	junitXMLFile string
+}
+
+func (v *testHuman) Results(results map[string]*moduletest.Suite) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	// FIXME: Due to how this prototype command evolved concurrently with
+	// establishing the idea of command views, the handling of JUnit output
+	// as part of the "human" view rather than as a separate view in its
+	// own right is a little odd and awkward. We should refactor this
+	// prior to making "terraform test" a real supported command to make
+	// it be structured more like the other commands that use the views
+	// package.
+
+	v.humanResults(results)
+
+	if v.junitXMLFile != "" {
+		moreDiags := v.junitXMLResults(results, v.junitXMLFile)
+		diags = diags.Append(moreDiags)
+	}
+
+	return diags
+}
+
+func (v *testHuman) Diagnostics(diags tfdiags.Diagnostics) {
+	if len(diags) == 0 {
+		return
+	}
+	v.showDiagnostics(diags)
+}
+
+func (v *testHuman) humanResults(results map[string]*moduletest.Suite) {
+	failCount := 0
+	width := v.streams.Stderr.Columns()
+
+	suiteNames := make([]string, 0, len(results))
+	for suiteName := range results {
+		suiteNames = append(suiteNames, suiteName)
+	}
+	sort.Strings(suiteNames)
+	for _, suiteName := range suiteNames {
+		suite := results[suiteName]
+
+		componentNames := make([]string, 0, len(suite.Components))
+		for componentName := range suite.Components {
+			componentNames = append(componentNames, componentName)
+		}
+		for _, componentName := range componentNames {
+			component := suite.Components[componentName]
+
+			assertionNames := make([]string, 0, len(component.Assertions))
+			for assertionName := range component.Assertions {
+				assertionNames = append(assertionNames, assertionName)
+			}
+			sort.Strings(assertionNames)
+
+			for _, assertionName := range assertionNames {
+				assertion := component.Assertions[assertionName]
+
+				fullName := fmt.Sprintf("%s.%s.%s", suiteName, componentName, assertionName)
+				if strings.HasPrefix(componentName, "(") {
+					// parenthesis-prefixed components are placeholders that
+					// the test harness generates to represent problems that
+					// prevented checking any assertions at all, so we'll
+					// just hide them and show the suite name.
+					fullName = suiteName
+				}
+				headingExtra := fmt.Sprintf("%s (%s)", fullName, assertion.Description)
+
+				switch assertion.Outcome {
+				case moduletest.Failed:
+					// Failed means that the assertion was successfully
+					// excecuted but that the assertion condition didn't hold.
+					v.eprintRuleHeading("yellow", "Failed", headingExtra)
+
+				case moduletest.Error:
+					// Error means that the system encountered an unexpected
+					// error when trying to evaluate the assertion.
+					v.eprintRuleHeading("red", "Error", headingExtra)
+
+				default:
+					// We don't do anything for moduletest.Passed or
+					// moduletest.Skipped. Perhaps in future we'll offer a
+					// -verbose option to include information about those.
+					continue
+				}
+				failCount++
+
+				if len(assertion.Message) > 0 {
+					dispMsg := format.WordWrap(assertion.Message, width)
+					v.streams.Eprintln(dispMsg)
+				}
+				if len(assertion.Diagnostics) > 0 {
+					// We'll do our own writing of the diagnostics in this
+					// case, rather than using v.Diagnostics, because we
+					// specifically want all of these diagnostics to go to
+					// Stderr along with all of the other output we've
+					// generated.
+					for _, diag := range assertion.Diagnostics {
+						diagStr := format.Diagnostic(diag, nil, v.colorize, width)
+						v.streams.Eprint(diagStr)
+					}
+				}
+			}
+		}
+	}
+
+	if failCount > 0 {
+		// If we've printed at least one failure then we'll have printed at
+		// least one horizontal rule across the terminal, and so we'll balance
+		// that with another horizontal rule.
+		if width > 1 {
+			rule := strings.Repeat("─", width-1)
+			v.streams.Eprintln(v.colorize.Color("[dark_gray]" + rule))
+		}
+	}
+
+	if failCount == 0 {
+		if len(results) > 0 {
+			// This is not actually an error, but it's convenient if all of our
+			// result output goes to the same stream for when this is running in
+			// automation that might be gathering this output via a pipe.
+			v.streams.Eprint(v.colorize.Color("[bold][green]Success![reset] All of the test assertions passed.\n\n"))
+		} else {
+			v.streams.Eprint(v.colorize.Color("[bold][yellow]No tests defined.[reset] This module doesn't have any test suites to run.\n\n"))
+		}
+	}
+
+	// Try to flush any buffering that might be happening. (This isn't always
+	// successful, depending on what sort of fd Stderr is connected to.)
+	v.streams.Stderr.File.Sync()
+}
+
+func (v *testHuman) junitXMLResults(results map[string]*moduletest.Suite, filename string) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	// "JUnit XML" is a file format that has become a de-facto standard for
+	// test reporting tools but that is not formally specified anywhere, and
+	// so each producer and consumer implementation unfortunately tends to
+	// differ in certain ways from others.
+	// With that in mind, this is a best effort sort of thing aimed at being
+	// broadly compatible with various consumers, but it's likely that
+	// some consumers will present these results better than others.
+	// This implementation is based mainly on the pseudo-specification of the
+	// format curated here, based on the Jenkins parser implementation:
+	//    https://llg.cubic.org/docs/junit/
+
+	// An "Outcome" represents one of the various XML elements allowed inside
+	// a testcase element to indicate the test outcome.
+	type Outcome struct {
+		Message string `xml:"message,omitempty"`
+	}
+
+	// TestCase represents an individual test case as part of a suite. Note
+	// that a JUnit XML incorporates both the "component" and "assertion"
+	// levels of our model: we pretend that component is a class name and
+	// assertion is a method name in order to match with the Java-flavored
+	// expectations of JUnit XML, which are hopefully close enough to get
+	// a test result rendering that's useful to humans.
+	type TestCase struct {
+		AssertionName string `xml:"name"`
+		ComponentName string `xml:"classname"`
+
+		// These fields represent the different outcomes of a TestCase. Only one
+		// of these should be populated in each TestCase; this awkward
+		// structure is just to make this play nicely with encoding/xml's
+		// expecatations.
+		Skipped *Outcome `xml:"skipped,omitempty"`
+		Error   *Outcome `xml:"error,omitempty"`
+		Failure *Outcome `xml:"failure,omitempty"`
+
+		Stderr string `xml:"system-out,omitempty"`
+	}
+
+	// TestSuite represents an individual test suite, of potentially many
+	// in a JUnit XML document.
+	type TestSuite struct {
+		Name         string      `xml:"name"`
+		TotalCount   int         `xml:"tests"`
+		SkippedCount int         `xml:"skipped"`
+		ErrorCount   int         `xml:"errors"`
+		FailureCount int         `xml:"failures"`
+		Cases        []*TestCase `xml:"testcase"`
+	}
+
+	// TestSuites represents the root element of the XML document.
+	type TestSuites struct {
+		XMLName      struct{}     `xml:"testsuites"`
+		ErrorCount   int          `xml:"errors"`
+		FailureCount int          `xml:"failures"`
+		TotalCount   int          `xml:"tests"`
+		Suites       []*TestSuite `xml:"testsuite"`
+	}
+
+	xmlSuites := TestSuites{}
+	suiteNames := make([]string, 0, len(results))
+	for suiteName := range results {
+		suiteNames = append(suiteNames, suiteName)
+	}
+	sort.Strings(suiteNames)
+	for _, suiteName := range suiteNames {
+		suite := results[suiteName]
+
+		xmlSuite := &TestSuite{
+			Name: suiteName,
+		}
+		xmlSuites.Suites = append(xmlSuites.Suites, xmlSuite)
+
+		componentNames := make([]string, 0, len(suite.Components))
+		for componentName := range suite.Components {
+			componentNames = append(componentNames, componentName)
+		}
+		for _, componentName := range componentNames {
+			component := suite.Components[componentName]
+
+			assertionNames := make([]string, 0, len(component.Assertions))
+			for assertionName := range component.Assertions {
+				assertionNames = append(assertionNames, assertionName)
+			}
+			sort.Strings(assertionNames)
+
+			for _, assertionName := range assertionNames {
+				assertion := component.Assertions[assertionName]
+				xmlSuites.TotalCount++
+				xmlSuite.TotalCount++
+
+				xmlCase := &TestCase{
+					ComponentName: componentName,
+					AssertionName: assertionName,
+				}
+				xmlSuite.Cases = append(xmlSuite.Cases, xmlCase)
+
+				switch assertion.Outcome {
+				case moduletest.Pending:
+					// We represent "pending" cases -- cases blocked by
+					// upstream errors -- as if they were "skipped" in JUnit
+					// terms, because we didn't actually check them and so
+					// can't say whether they succeeded or not.
+					xmlSuite.SkippedCount++
+					xmlCase.Skipped = &Outcome{
+						Message: assertion.Message,
+					}
+				case moduletest.Failed:
+					xmlSuites.FailureCount++
+					xmlSuite.FailureCount++
+					xmlCase.Failure = &Outcome{
+						Message: assertion.Message,
+					}
+				case moduletest.Error:
+					xmlSuites.ErrorCount++
+					xmlSuite.ErrorCount++
+					xmlCase.Error = &Outcome{
+						Message: assertion.Message,
+					}
+
+					// We'll also include the diagnostics in the "stderr"
+					// portion of the output, so they'll hopefully be visible
+					// in a test log viewer in JUnit-XML-Consuming CI systems.
+					var buf strings.Builder
+					for _, diag := range assertion.Diagnostics {
+						diagStr := format.DiagnosticPlain(diag, nil, 68)
+						buf.WriteString(diagStr)
+					}
+					xmlCase.Stderr = buf.String()
+				}
+
+			}
+		}
+	}
+
+	xmlOut, err := xml.MarshalIndent(&xmlSuites, "", "  ")
+	if err != nil {
+		// If marshalling fails then that's a bug in the code above,
+		// because we should always be producing a value that is
+		// accepted by encoding/xml.
+		panic(fmt.Sprintf("invalid values to marshal as JUnit XML: %s", err))
+	}
+
+	err = ioutil.WriteFile(filename, xmlOut, 0644)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to write JUnit XML file",
+			fmt.Sprintf(
+				"Could not create %s to record the test results in JUnit XML format: %s.",
+				filename,
+				err,
+			),
+		))
+	}
+
+	return diags
+}
+
+func (v *testHuman) eprintRuleHeading(color, prefix, extra string) {
+	const lineCell string = "─"
+	textLen := len(prefix) + len(": ") + len(extra)
+	spacingLen := 2
+	leftLineLen := 3
+
+	rightLineLen := 0
+	width := v.streams.Stderr.Columns()
+	if (textLen + spacingLen + leftLineLen) < (width - 1) {
+		// (we allow an extra column at the end because some terminals can't
+		// print in the final column without wrapping to the next line)
+		rightLineLen = width - (textLen + spacingLen + leftLineLen) - 1
+	}
+
+	colorCode := "[" + color + "]"
+
+	// We'll prepare what we're going to print in memory first, so that we can
+	// send it all to stderr in one write in case other programs are also
+	// concurrently trying to write to the terminal for some reason.
+	var buf strings.Builder
+	buf.WriteString(v.colorize.Color(colorCode + strings.Repeat(lineCell, leftLineLen)))
+	buf.WriteByte(' ')
+	buf.WriteString(v.colorize.Color("[bold]" + colorCode + prefix + ":"))
+	buf.WriteByte(' ')
+	buf.WriteString(extra)
+	if rightLineLen > 0 {
+		buf.WriteByte(' ')
+		buf.WriteString(v.colorize.Color(colorCode + strings.Repeat(lineCell, rightLineLen)))
+	}
+	v.streams.Eprintln(buf.String())
+}
diff --git a/v1.5.7/internal/command/views/test_test.go b/v1.5.7/internal/command/views/test_test.go
new file mode 100644
index 0000000..76baef7
--- /dev/null
+++ b/v1.5.7/internal/command/views/test_test.go
@@ -0,0 +1,35 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/moduletest"
+	"github.com/hashicorp/terraform/internal/terminal"
+)
+
+func TestTest(t *testing.T) {
+	streams, close := terminal.StreamsForTesting(t)
+	baseView := NewView(streams)
+	view := NewTest(baseView, arguments.TestOutput{
+		JUnitXMLFile: "",
+	})
+
+	results := map[string]*moduletest.Suite{}
+	view.Results(results)
+
+	output := close(t)
+	gotOutput := strings.TrimSpace(output.All())
+	wantOutput := `No tests defined. This module doesn't have any test suites to run.`
+	if gotOutput != wantOutput {
+		t.Errorf("wrong output\ngot:\n%s\nwant:\n%s", gotOutput, wantOutput)
+	}
+
+	// TODO: Test more at this layer. For now, the main UI output tests for
+	// the "terraform test" command are in the command package as part of
+	// the overall command tests.
+}
diff --git a/v1.5.7/internal/command/views/testdata/show/main.tf b/v1.5.7/internal/command/views/testdata/show/main.tf
new file mode 100644
index 0000000..e1cca23
--- /dev/null
+++ b/v1.5.7/internal/command/views/testdata/show/main.tf
@@ -0,0 +1,3 @@
+resource "test_resource" "foo" {
+    foo = "value"
+}
diff --git a/v1.5.7/internal/command/views/validate.go b/v1.5.7/internal/command/views/validate.go
new file mode 100644
index 0000000..517287f
--- /dev/null
+++ b/v1.5.7/internal/command/views/validate.go
@@ -0,0 +1,141 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/format"
+	viewsjson "github.com/hashicorp/terraform/internal/command/views/json"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// The Validate is used for the validate command.
+type Validate interface {
+	// Results renders the diagnostics returned from a validation walk, and
+	// returns a CLI exit code: 0 if there are no errors, 1 otherwise
+	Results(diags tfdiags.Diagnostics) int
+
+	// Diagnostics renders early diagnostics, resulting from argument parsing.
+	Diagnostics(diags tfdiags.Diagnostics)
+}
+
+// NewValidate returns an initialized Validate implementation for the given ViewType.
+func NewValidate(vt arguments.ViewType, view *View) Validate {
+	switch vt {
+	case arguments.ViewJSON:
+		return &ValidateJSON{view: view}
+	case arguments.ViewHuman:
+		return &ValidateHuman{view: view}
+	default:
+		panic(fmt.Sprintf("unknown view type %v", vt))
+	}
+}
+
+// The ValidateHuman implementation renders diagnostics in a human-readable form,
+// along with a success/failure message if Terraform is able to execute the
+// validation walk.
+type ValidateHuman struct {
+	view *View
+}
+
+var _ Validate = (*ValidateHuman)(nil)
+
+func (v *ValidateHuman) Results(diags tfdiags.Diagnostics) int {
+	columns := v.view.outputColumns()
+
+	if len(diags) == 0 {
+		v.view.streams.Println(format.WordWrap(v.view.colorize.Color(validateSuccess), columns))
+	} else {
+		v.Diagnostics(diags)
+
+		if !diags.HasErrors() {
+			v.view.streams.Println(format.WordWrap(v.view.colorize.Color(validateWarnings), columns))
+		}
+	}
+
+	if diags.HasErrors() {
+		return 1
+	}
+	return 0
+}
+
+const validateSuccess = "[green][bold]Success![reset] The configuration is valid.\n"
+
+const validateWarnings = "[green][bold]Success![reset] The configuration is valid, but there were some validation warnings as shown above.\n"
+
+func (v *ValidateHuman) Diagnostics(diags tfdiags.Diagnostics) {
+	v.view.Diagnostics(diags)
+}
+
+// The ValidateJSON implementation renders validation results as a JSON object.
+// This object includes top-level fields summarizing the result, and an array
+// of JSON diagnostic objects.
+type ValidateJSON struct {
+	view *View
+}
+
+var _ Validate = (*ValidateJSON)(nil)
+
+func (v *ValidateJSON) Results(diags tfdiags.Diagnostics) int {
+	// FormatVersion represents the version of the json format and will be
+	// incremented for any change to this format that requires changes to a
+	// consuming parser.
+	const FormatVersion = "1.0"
+
+	type Output struct {
+		FormatVersion string `json:"format_version"`
+
+		// We include some summary information that is actually redundant
+		// with the detailed diagnostics, but avoids the need for callers
+		// to re-implement our logic for deciding these.
+		Valid        bool                    `json:"valid"`
+		ErrorCount   int                     `json:"error_count"`
+		WarningCount int                     `json:"warning_count"`
+		Diagnostics  []*viewsjson.Diagnostic `json:"diagnostics"`
+	}
+
+	output := Output{
+		FormatVersion: FormatVersion,
+		Valid:         true, // until proven otherwise
+	}
+	configSources := v.view.configSources()
+	for _, diag := range diags {
+		output.Diagnostics = append(output.Diagnostics, viewsjson.NewDiagnostic(diag, configSources))
+
+		switch diag.Severity() {
+		case tfdiags.Error:
+			output.ErrorCount++
+			output.Valid = false
+		case tfdiags.Warning:
+			output.WarningCount++
+		}
+	}
+	if output.Diagnostics == nil {
+		// Make sure this always appears as an array in our output, since
+		// this is easier to consume for dynamically-typed languages.
+		output.Diagnostics = []*viewsjson.Diagnostic{}
+	}
+
+	j, err := json.MarshalIndent(&output, "", "  ")
+	if err != nil {
+		// Should never happen because we fully-control the input here
+		panic(err)
+	}
+	v.view.streams.Println(string(j))
+
+	if diags.HasErrors() {
+		return 1
+	}
+	return 0
+}
+
+// Diagnostics should only be called if the validation walk cannot be executed.
+// In this case, we choose to render human-readable diagnostic output,
+// primarily for backwards compatibility.
+func (v *ValidateJSON) Diagnostics(diags tfdiags.Diagnostics) {
+	v.view.Diagnostics(diags)
+}
diff --git a/v1.5.7/internal/command/views/validate_test.go b/v1.5.7/internal/command/views/validate_test.go
new file mode 100644
index 0000000..4ab1c61
--- /dev/null
+++ b/v1.5.7/internal/command/views/validate_test.go
@@ -0,0 +1,136 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"encoding/json"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestValidateHuman(t *testing.T) {
+	testCases := map[string]struct {
+		diag          tfdiags.Diagnostic
+		wantSuccess   bool
+		wantSubstring string
+	}{
+		"success": {
+			nil,
+			true,
+			"The configuration is valid.",
+		},
+		"warning": {
+			tfdiags.Sourceless(
+				tfdiags.Warning,
+				"Your shoelaces are untied",
+				"Watch out, or you'll trip!",
+			),
+			true,
+			"The configuration is valid, but there were some validation warnings",
+		},
+		"error": {
+			tfdiags.Sourceless(
+				tfdiags.Error,
+				"Configuration is missing random_pet",
+				"Every configuration should have a random_pet.",
+			),
+			false,
+			"Error: Configuration is missing random_pet",
+		},
+	}
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			view := NewView(streams)
+			view.Configure(&arguments.View{NoColor: true})
+			v := NewValidate(arguments.ViewHuman, view)
+
+			var diags tfdiags.Diagnostics
+
+			if tc.diag != nil {
+				diags = diags.Append(tc.diag)
+			}
+
+			ret := v.Results(diags)
+
+			if tc.wantSuccess && ret != 0 {
+				t.Errorf("expected 0 return code, got %d", ret)
+			} else if !tc.wantSuccess && ret != 1 {
+				t.Errorf("expected 1 return code, got %d", ret)
+			}
+
+			got := done(t).All()
+			if strings.Contains(got, "Success!") != tc.wantSuccess {
+				t.Errorf("unexpected output:\n%s", got)
+			}
+			if !strings.Contains(got, tc.wantSubstring) {
+				t.Errorf("expected output to include %q, but was:\n%s", tc.wantSubstring, got)
+			}
+		})
+	}
+}
+
+func TestValidateJSON(t *testing.T) {
+	testCases := map[string]struct {
+		diag        tfdiags.Diagnostic
+		wantSuccess bool
+	}{
+		"success": {
+			nil,
+			true,
+		},
+		"warning": {
+			tfdiags.Sourceless(
+				tfdiags.Warning,
+				"Your shoelaces are untied",
+				"Watch out, or you'll trip!",
+			),
+			true,
+		},
+		"error": {
+			tfdiags.Sourceless(
+				tfdiags.Error,
+				"Configuration is missing random_pet",
+				"Every configuration should have a random_pet.",
+			),
+			false,
+		},
+	}
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			streams, done := terminal.StreamsForTesting(t)
+			view := NewView(streams)
+			view.Configure(&arguments.View{NoColor: true})
+			v := NewValidate(arguments.ViewJSON, view)
+
+			var diags tfdiags.Diagnostics
+
+			if tc.diag != nil {
+				diags = diags.Append(tc.diag)
+			}
+
+			ret := v.Results(diags)
+
+			if tc.wantSuccess && ret != 0 {
+				t.Errorf("expected 0 return code, got %d", ret)
+			} else if !tc.wantSuccess && ret != 1 {
+				t.Errorf("expected 1 return code, got %d", ret)
+			}
+
+			got := done(t).All()
+
+			// Make sure the result looks like JSON; we comprehensively test
+			// the structure of this output in the command package tests.
+			var result map[string]interface{}
+
+			if err := json.Unmarshal([]byte(got), &result); err != nil {
+				t.Fatal(err)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/command/views/view.go b/v1.5.7/internal/command/views/view.go
new file mode 100644
index 0000000..f82b67f
--- /dev/null
+++ b/v1.5.7/internal/command/views/view.go
@@ -0,0 +1,165 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package views
+
+import (
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/format"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/mitchellh/colorstring"
+)
+
+// View is the base layer for command views, encapsulating a set of I/O
+// streams, a colorize implementation, and implementing a human friendly view
+// for diagnostics.
+type View struct {
+	streams  *terminal.Streams
+	colorize *colorstring.Colorize
+
+	compactWarnings bool
+
+	// When this is true it's a hint that Terraform is being run indirectly
+	// via a wrapper script or other automation and so we may wish to replace
+	// direct examples of commands to run with more conceptual directions.
+	// However, we only do this on a best-effort basis, typically prioritizing
+	// the messages that users are most likely to see.
+	runningInAutomation bool
+
+	// This unfortunate wart is required to enable rendering of diagnostics which
+	// have associated source code in the configuration. This function pointer
+	// will be dereferenced as late as possible when rendering diagnostics in
+	// order to access the config loader cache.
+	configSources func() map[string][]byte
+}
+
+// Initialize a View with the given streams, a disabled colorize object, and a
+// no-op configSources callback.
+func NewView(streams *terminal.Streams) *View {
+	return &View{
+		streams: streams,
+		colorize: &colorstring.Colorize{
+			Colors:  colorstring.DefaultColors,
+			Disable: true,
+			Reset:   true,
+		},
+		configSources: func() map[string][]byte { return nil },
+	}
+}
+
+// SetRunningInAutomation modifies the view's "running in automation" flag,
+// which causes some slight adjustments to certain messages that would normally
+// suggest specific Terraform commands to run, to make more conceptual gestures
+// instead for situations where the user isn't running Terraform directly.
+//
+// For convenient use during initialization (in conjunction with NewView),
+// SetRunningInAutomation returns the reciever after modifying it.
+func (v *View) SetRunningInAutomation(new bool) *View {
+	v.runningInAutomation = new
+	return v
+}
+
+func (v *View) RunningInAutomation() bool {
+	return v.runningInAutomation
+}
+
+// Configure applies the global view configuration flags.
+func (v *View) Configure(view *arguments.View) {
+	v.colorize.Disable = view.NoColor
+	v.compactWarnings = view.CompactWarnings
+}
+
+// SetConfigSources overrides the default no-op callback with a new function
+// pointer, and should be called when the config loader is initialized.
+func (v *View) SetConfigSources(cb func() map[string][]byte) {
+	v.configSources = cb
+}
+
+// Diagnostics renders a set of warnings and errors in human-readable form.
+// Warnings are printed to stdout, and errors to stderr.
+func (v *View) Diagnostics(diags tfdiags.Diagnostics) {
+	diags.Sort()
+
+	if len(diags) == 0 {
+		return
+	}
+
+	diags = diags.ConsolidateWarnings(1)
+
+	// Since warning messages are generally competing
+	if v.compactWarnings {
+		// If the user selected compact warnings and all of the diagnostics are
+		// warnings then we'll use a more compact representation of the warnings
+		// that only includes their summaries.
+		// We show full warnings if there are also errors, because a warning
+		// can sometimes serve as good context for a subsequent error.
+		useCompact := true
+		for _, diag := range diags {
+			if diag.Severity() != tfdiags.Warning {
+				useCompact = false
+				break
+			}
+		}
+		if useCompact {
+			msg := format.DiagnosticWarningsCompact(diags, v.colorize)
+			msg = "\n" + msg + "\nTo see the full warning notes, run Terraform without -compact-warnings.\n"
+			v.streams.Print(msg)
+			return
+		}
+	}
+
+	for _, diag := range diags {
+		var msg string
+		if v.colorize.Disable {
+			msg = format.DiagnosticPlain(diag, v.configSources(), v.streams.Stderr.Columns())
+		} else {
+			msg = format.Diagnostic(diag, v.configSources(), v.colorize, v.streams.Stderr.Columns())
+		}
+
+		if diag.Severity() == tfdiags.Error {
+			v.streams.Eprint(msg)
+		} else {
+			v.streams.Print(msg)
+		}
+	}
+}
+
+// HelpPrompt is intended to be called from commands which fail to parse all
+// of their CLI arguments successfully. It refers users to the full help output
+// rather than rendering it directly, which can be overwhelming and confusing.
+func (v *View) HelpPrompt(command string) {
+	v.streams.Eprintf(helpPrompt, command)
+}
+
+const helpPrompt = `
+For more help on using this command, run:
+  terraform %s -help
+`
+
+// outputColumns returns the number of text character cells any non-error
+// output should be wrapped to.
+//
+// This is the number of columns to use if you are calling v.streams.Print or
+// related functions.
+func (v *View) outputColumns() int {
+	return v.streams.Stdout.Columns()
+}
+
+// errorColumns returns the number of text character cells any error
+// output should be wrapped to.
+//
+// This is the number of columns to use if you are calling v.streams.Eprint
+// or related functions.
+func (v *View) errorColumns() int {
+	return v.streams.Stderr.Columns()
+}
+
+// outputHorizRule will call v.streams.Println with enough horizontal line
+// characters to fill an entire row of output.
+//
+// If UI color is enabled, the rule will get a dark grey coloring to try to
+// visually de-emphasize it.
+func (v *View) outputHorizRule() {
+	v.streams.Println(format.HorizontalRule(v.colorize, v.outputColumns()))
+}
diff --git a/v1.5.7/internal/command/webbrowser/mock.go b/v1.5.7/internal/command/webbrowser/mock.go
new file mode 100644
index 0000000..1245cbe
--- /dev/null
+++ b/v1.5.7/internal/command/webbrowser/mock.go
@@ -0,0 +1,155 @@
+package webbrowser
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"net/http"
+	"net/url"
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/httpclient"
+)
+
+// NewMockLauncher creates and returns a mock implementation of Launcher,
+// with some special behavior designed for use in unit tests.
+//
+// See the documentation of MockLauncher itself for more information.
+func NewMockLauncher(ctx context.Context) *MockLauncher {
+	client := httpclient.New()
+	return &MockLauncher{
+		Client:  client,
+		Context: ctx,
+	}
+}
+
+// MockLauncher is a mock implementation of Launcher that has some special
+// behavior designed for use in unit tests.
+//
+// When OpenURL is called, MockLauncher will make an HTTP request to the given
+// URL rather than interacting with a "real" browser.
+//
+// In normal situations it will then return with no further action, but if
+// the response to the given URL is either a standard HTTP redirect response
+// or includes the custom HTTP header X-Redirect-To then MockLauncher will
+// send a follow-up request to that target URL, and continue in this manner
+// until it reaches a URL that is not a redirect. (The X-Redirect-To header
+// is there so that a server can potentially offer a normal HTML page to
+// an actual browser while also giving a next-hop hint for MockLauncher.)
+//
+// Since MockLauncher is not a full programmable user-agent implementation
+// it can't be used for testing of real-world web applications, but it can
+// be used for testing against specialized test servers that are written
+// with MockLauncher in mind and know how to drive the request flow through
+// whatever steps are required to complete the desired test.
+//
+// All of the actions taken by MockLauncher happen asynchronously in the
+// background, to simulate the concurrency of a separate web browser.
+// Test code using MockLauncher should provide a context which is cancelled
+// when the test completes, to help avoid leaking MockLaunchers.
+type MockLauncher struct {
+	// Client is the HTTP client that MockLauncher will use to make requests.
+	// By default (if you use NewMockLauncher) this is a new client created
+	// via httpclient.New, but callers may override it if they need customized
+	// behavior for a particular test.
+	//
+	// Do not use a client that is shared with any other subsystem, because
+	// MockLauncher will customize the settings of the given client.
+	Client *http.Client
+
+	// Context can be cancelled in order to abort an OpenURL call before it
+	// would naturally complete.
+	Context context.Context
+
+	// Responses is a log of all of the responses recieved from the launcher's
+	// requests, in the order requested.
+	Responses []*http.Response
+
+	// done is a waitgroup used internally to signal when the async work is
+	// complete, in order to make this mock more convenient to use in tests.
+	done sync.WaitGroup
+}
+
+var _ Launcher = (*MockLauncher)(nil)
+
+// OpenURL is the mock implementation of Launcher, which has the special
+// behavior described for type MockLauncher.
+func (l *MockLauncher) OpenURL(u string) error {
+	// We run our operation in the background because it's supposed to be
+	// behaving like a web browser running in a separate process.
+	log.Printf("[TRACE] webbrowser.MockLauncher: OpenURL(%q) starting in the background", u)
+	l.done.Add(1)
+	go func() {
+		err := l.openURL(u)
+		if err != nil {
+			// Can't really do anything with this asynchronously, so we'll
+			// just log it so that someone debugging will be able to see it.
+			log.Printf("[ERROR] webbrowser.MockLauncher: OpenURL(%q): %s", u, err)
+		} else {
+			log.Printf("[TRACE] webbrowser.MockLauncher: OpenURL(%q) has concluded", u)
+		}
+		l.done.Done()
+	}()
+	return nil
+}
+
+func (l *MockLauncher) openURL(u string) error {
+	// We need to disable automatic redirect following so that we can implement
+	// it ourselves below, and thus be able to see the redirects in our
+	// responses log.
+	l.Client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
+		return http.ErrUseLastResponse
+	}
+
+	// We'll keep looping as long as the server keeps giving us new URLs to
+	// request.
+	for u != "" {
+		log.Printf("[DEBUG] webbrowser.MockLauncher: requesting %s", u)
+		req, err := http.NewRequest("GET", u, nil)
+		if err != nil {
+			return fmt.Errorf("failed to construct HTTP request for %s: %s", u, err)
+		}
+		resp, err := l.Client.Do(req)
+		if err != nil {
+			log.Printf("[DEBUG] webbrowser.MockLauncher: request failed: %s", err)
+			return fmt.Errorf("error requesting %s: %s", u, err)
+		}
+		l.Responses = append(l.Responses, resp)
+		if resp.StatusCode >= 400 {
+			log.Printf("[DEBUG] webbrowser.MockLauncher: request failed: %s", resp.Status)
+			return fmt.Errorf("error requesting %s: %s", u, resp.Status)
+		}
+		log.Printf("[DEBUG] webbrowser.MockLauncher: request succeeded: %s", resp.Status)
+
+		u = "" // unless it's a redirect, we'll stop after this
+		if location := resp.Header.Get("Location"); location != "" {
+			u = location
+		} else if redirectTo := resp.Header.Get("X-Redirect-To"); redirectTo != "" {
+			u = redirectTo
+		}
+
+		if u != "" {
+			// HTTP technically doesn't permit relative URLs in Location, but
+			// browsers tolerate it and so real-world servers do it, and thus
+			// we'll allow it here too.
+			oldURL := resp.Request.URL
+			givenURL, err := url.Parse(u)
+			if err != nil {
+				return fmt.Errorf("invalid redirect URL %s: %s", u, err)
+			}
+			u = oldURL.ResolveReference(givenURL).String()
+			log.Printf("[DEBUG] webbrowser.MockLauncher: redirected to %s", u)
+		}
+	}
+
+	log.Printf("[DEBUG] webbrowser.MockLauncher: all done")
+	return nil
+}
+
+// Wait blocks until the MockLauncher has finished its asynchronous work of
+// making HTTP requests and following redirects, at which point it will have
+// reached a request that didn't redirect anywhere and stopped iterating.
+func (l *MockLauncher) Wait() {
+	log.Printf("[TRACE] webbrowser.MockLauncher: Wait() for current work to complete")
+	l.done.Wait()
+}
diff --git a/v1.5.7/internal/command/webbrowser/mock_test.go b/v1.5.7/internal/command/webbrowser/mock_test.go
new file mode 100644
index 0000000..610f83d
--- /dev/null
+++ b/v1.5.7/internal/command/webbrowser/mock_test.go
@@ -0,0 +1,95 @@
+package webbrowser
+
+import (
+	"context"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+)
+
+func TestMockLauncher(t *testing.T) {
+	s := httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
+		resp.Header().Set("Content-Length", "0")
+		switch req.URL.Path {
+		case "/standard-redirect-source":
+			resp.Header().Set("Location", "/standard-redirect-target")
+			resp.WriteHeader(302)
+		case "/custom-redirect-source":
+			resp.Header().Set("X-Redirect-To", "/custom-redirect-target")
+			resp.WriteHeader(200)
+		case "/error":
+			resp.WriteHeader(500)
+		default:
+			resp.WriteHeader(200)
+		}
+	}))
+	defer s.Close()
+
+	t.Run("no redirects", func(t *testing.T) {
+		l := NewMockLauncher(context.Background())
+		err := l.OpenURL(s.URL)
+		if err != nil {
+			t.Fatal(err)
+		}
+		l.Wait() // Let the async work complete
+		if got, want := len(l.Responses), 1; got != want {
+			t.Fatalf("wrong number of responses %d; want %d", got, want)
+		}
+		if got, want := l.Responses[0].Request.URL.Path, ""; got != want {
+			t.Fatalf("wrong request URL %q; want %q", got, want)
+		}
+	})
+	t.Run("error", func(t *testing.T) {
+		l := NewMockLauncher(context.Background())
+		err := l.OpenURL(s.URL + "/error")
+		if err != nil {
+			// Th is kind of error is supposed to happen asynchronously, so we
+			// should not see it here.
+			t.Fatal(err)
+		}
+		l.Wait() // Let the async work complete
+		if got, want := len(l.Responses), 1; got != want {
+			t.Fatalf("wrong number of responses %d; want %d", got, want)
+		}
+		if got, want := l.Responses[0].Request.URL.Path, "/error"; got != want {
+			t.Fatalf("wrong request URL %q; want %q", got, want)
+		}
+		if got, want := l.Responses[0].StatusCode, 500; got != want {
+			t.Fatalf("wrong response status %d; want %d", got, want)
+		}
+	})
+	t.Run("standard redirect", func(t *testing.T) {
+		l := NewMockLauncher(context.Background())
+		err := l.OpenURL(s.URL + "/standard-redirect-source")
+		if err != nil {
+			t.Fatal(err)
+		}
+		l.Wait() // Let the async work complete
+		if got, want := len(l.Responses), 2; got != want {
+			t.Fatalf("wrong number of responses %d; want %d", got, want)
+		}
+		if got, want := l.Responses[0].Request.URL.Path, "/standard-redirect-source"; got != want {
+			t.Fatalf("wrong request 0 URL %q; want %q", got, want)
+		}
+		if got, want := l.Responses[1].Request.URL.Path, "/standard-redirect-target"; got != want {
+			t.Fatalf("wrong request 1 URL %q; want %q", got, want)
+		}
+	})
+	t.Run("custom redirect", func(t *testing.T) {
+		l := NewMockLauncher(context.Background())
+		err := l.OpenURL(s.URL + "/custom-redirect-source")
+		if err != nil {
+			t.Fatal(err)
+		}
+		l.Wait() // Let the async work complete
+		if got, want := len(l.Responses), 2; got != want {
+			t.Fatalf("wrong number of responses %d; want %d", got, want)
+		}
+		if got, want := l.Responses[0].Request.URL.Path, "/custom-redirect-source"; got != want {
+			t.Fatalf("wrong request 0 URL %q; want %q", got, want)
+		}
+		if got, want := l.Responses[1].Request.URL.Path, "/custom-redirect-target"; got != want {
+			t.Fatalf("wrong request 1 URL %q; want %q", got, want)
+		}
+	})
+}
diff --git a/v1.5.7/internal/command/webbrowser/native.go b/v1.5.7/internal/command/webbrowser/native.go
new file mode 100644
index 0000000..9ec40b4
--- /dev/null
+++ b/v1.5.7/internal/command/webbrowser/native.go
@@ -0,0 +1,21 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package webbrowser
+
+import (
+	"github.com/pkg/browser"
+)
+
+// NewNativeLauncher creates and returns a Launcher that will attempt to interact
+// with the browser-launching mechanisms of the operating system where the
+// program is currently running.
+func NewNativeLauncher() Launcher {
+	return nativeLauncher{}
+}
+
+type nativeLauncher struct{}
+
+func (l nativeLauncher) OpenURL(url string) error {
+	return browser.OpenURL(url)
+}
diff --git a/v1.5.7/internal/command/webbrowser/webbrowser.go b/v1.5.7/internal/command/webbrowser/webbrowser.go
new file mode 100644
index 0000000..46d373d
--- /dev/null
+++ b/v1.5.7/internal/command/webbrowser/webbrowser.go
@@ -0,0 +1,22 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package webbrowser
+
+// Launcher is an object that knows how to open a given URL in a new tab in
+// some suitable browser on the current system.
+//
+// Launching of browsers is a very target-platform-sensitive activity, so
+// this interface serves as an abstraction over many possible implementations
+// which can be selected based on what is appropriate for a specific situation.
+type Launcher interface {
+	// OpenURL opens the given URL in a web browser.
+	//
+	// Depending on the circumstances and on the target platform, this may or
+	// may not cause the browser to take input focus. Because of this
+	// uncertainty, any caller of this method must be sure to include some
+	// language in its UI output to let the user know that a browser tab has
+	// opened somewhere, so that they can go and find it if the focus didn't
+	// switch automatically.
+	OpenURL(url string) error
+}
diff --git a/v1.5.7/internal/command/workdir/dir.go b/v1.5.7/internal/command/workdir/dir.go
new file mode 100644
index 0000000..b4fc62c
--- /dev/null
+++ b/v1.5.7/internal/command/workdir/dir.go
@@ -0,0 +1,152 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package workdir
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+)
+
+// Dir represents a single Terraform working directory.
+//
+// "Working directory" is unfortunately a slight misnomer, because non-default
+// options can potentially stretch the definition such that multiple working
+// directories end up appearing to share a data directory, or other similar
+// anomolies, but we continue to use this terminology both for historical
+// reasons and because it reflects the common case without any special
+// overrides.
+//
+// The naming convention for methods on this type is that methods whose names
+// begin with "Override" affect only characteristics of the particular object
+// they're called on, changing where it looks for data, while methods whose
+// names begin with "Set" will write settings to disk such that other instances
+// referring to the same directories will also see them. Given that, the
+// "Override" methods should be used only during the initialization steps
+// for a Dir object, typically only inside "package main", so that all
+// subsequent work elsewhere will access consistent locations on disk.
+//
+// We're gradually transitioning to using this type to manage working directory
+// settings, and so not everything in the working directory "data dir" is
+// encapsulated here yet, but hopefully we'll gradually migrate all of those
+// settings here over time. The working directory state not yet managed in here
+// is typically managed directly in the "command" package, either directly
+// inside commands or in methods of the giant command.Meta type.
+type Dir struct {
+	// mainDir is the path to the directory that we present as the
+	// "working directory" in the user model, which is typically the
+	// current working directory when running Terraform CLI, or the
+	// directory explicitly chosen by the user using the -chdir=...
+	// global option.
+	mainDir string
+
+	// originalDir is the path to the working directory that was
+	// selected when creating the Terraform CLI process, regardless of
+	// -chdir=... being set. This is only for very limited purposes
+	// related to backward compatibility; most functionality should
+	// use mainDir instead.
+	originalDir string
+
+	// dataDir is the path to the directory where we will store our
+	// working directory settings and artifacts. This is typically a
+	// directory named ".terraform" within mainDir, but users may
+	// override it.
+	dataDir string
+}
+
+// NewDir constructs a new working directory, anchored at the given path.
+//
+// In normal use, mainPath should be "." to reflect the current working
+// directory, with "package main" having switched the process's current
+// working directory if necessary prior to calling this function. However,
+// unusual situations in tests may set mainPath to a temporary directory, or
+// similar.
+//
+// WARNING: Although the logic in this package is intended to work regardless
+// of whether mainPath is actually the current working directory, we're
+// currently in a transitional state where this package shares responsibility
+// for the working directory with various command.Meta methods, and those
+// often assume that the main path of the working directory will always be
+// ".". If you're writing test code that spans across both areas of
+// responsibility then you must ensure that the test temporarily changes the
+// test process's working directory to the directory returned by RootModuleDir
+// before using the result inside a command.Meta.
+func NewDir(mainPath string) *Dir {
+	mainPath = filepath.Clean(mainPath)
+	return &Dir{
+		mainDir:     mainPath,
+		originalDir: mainPath,
+		dataDir:     filepath.Join(mainPath, ".terraform"),
+	}
+}
+
+// OverrideOriginalWorkingDir records a different path as the
+// "original working directory" for the reciever.
+//
+// Use this only to record the original working directory when Terraform is run
+// with the -chdir=... global option. In that case, the directory given in
+// -chdir=... is the "main path" to pass in to NewDir, while the original
+// working directory should be sent to this method.
+func (d *Dir) OverrideOriginalWorkingDir(originalPath string) {
+	d.originalDir = filepath.Clean(originalPath)
+}
+
+// OverrideDataDir chooses a specific alternative directory to read and write
+// the persistent working directory settings.
+//
+// "package main" can call this if it detects that the user has overridden
+// the default location by setting the relevant environment variable. Don't
+// call this when that environment variable isn't set, in order to preserve
+// the default setting of a dot-prefixed directory directly inside the main
+// working directory.
+func (d *Dir) OverrideDataDir(dataDir string) {
+	d.dataDir = filepath.Clean(dataDir)
+}
+
+// RootModuleDir returns the directory where we expect to find the root module
+// configuration for this working directory.
+func (d *Dir) RootModuleDir() string {
+	// The root module configuration is just directly inside the main directory.
+	return d.mainDir
+}
+
+// OriginalWorkingDir returns the true, operating-system-originated working
+// directory that the current Terraform process was launched from.
+//
+// This is usually the same as the main working directory, but differs in the
+// special case where the user ran Terraform with the global -chdir=...
+// option. This is here only for a few backward compatibility affordances
+// from before we had the -chdir=... option, so should typically not be used
+// for anything new.
+func (d *Dir) OriginalWorkingDir() string {
+	return d.originalDir
+}
+
+// DataDir returns the base path where the reciever keeps all of the settings
+// and artifacts that must persist between consecutive commands in a single
+// session.
+//
+// This is exported only to allow the legacy behaviors in command.Meta to
+// continue accessing this directory directly. Over time we should replace
+// all of those direct accesses with methods on this type, and then remove
+// this method. Avoid using this method for new use-cases.
+func (d *Dir) DataDir() string {
+	return d.dataDir
+}
+
+// ensureDataDir creates the data directory and all of the necessary parent
+// directories that lead to it, if they don't already exist.
+//
+// For directories that already exist ensureDataDir will preserve their
+// permissions, while it'll create any new directories to be owned by the user
+// running Terraform, readable and writable by that user, and readable by
+// all other users, or some approximation of that on non-Unix platforms which
+// have a different permissions model.
+func (d *Dir) ensureDataDir() error {
+	err := os.MkdirAll(d.dataDir, 0755)
+	if err != nil {
+		return fmt.Errorf("failed to prepare working directory: %w", err)
+	}
+	return nil
+}
diff --git a/v1.5.7/internal/command/workdir/doc.go b/v1.5.7/internal/command/workdir/doc.go
new file mode 100644
index 0000000..9d08231
--- /dev/null
+++ b/v1.5.7/internal/command/workdir/doc.go
@@ -0,0 +1,19 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package workdir models the various local artifacts and state we keep inside
+// a Terraform "working directory".
+//
+// The working directory artifacts and settings are typically initialized or
+// modified by "terraform init", after which they persist for use by other
+// commands in the same directory, but are not visible to commands run in
+// other working directories or on other computers.
+//
+// Although "terraform init" is the main command which modifies a workdir,
+// other commands do sometimes make more focused modifications for settings
+// which can typically change multiple times during a session, such as the
+// currently-selected workspace name. Any command which modifies the working
+// directory settings must discard and reload any objects which derived from
+// those settings, because otherwise the existing objects will often continue
+// to follow the settings that were present when they were created.
+package workdir
diff --git a/v1.5.7/internal/command/workdir/normalize_path.go b/v1.5.7/internal/command/workdir/normalize_path.go
new file mode 100644
index 0000000..601897b
--- /dev/null
+++ b/v1.5.7/internal/command/workdir/normalize_path.go
@@ -0,0 +1,55 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package workdir
+
+import (
+	"path/filepath"
+)
+
+// NormalizePath attempts to transform the given path so that it's relative
+// to the working directory, which is our preferred way to present and store
+// paths to files and directories within a configuration so that they can
+// be portable to operations in other working directories.
+//
+// It isn't always possible to produce a relative path. For example, on Windows
+// the given path might be on a different volume (e.g. drive letter or network
+// share) than the working directory.
+//
+// Note that the result will be relative to the main directory of the receiver,
+// which should always be the actual process working directory in normal code,
+// but might be some other temporary working directory when in test code.
+// If you need to access the file or directory that the result refers to with
+// functions that aren't aware of our base directory, you can use something
+// like the following, which again should be needed only in test code which
+// might need to inspect the filesystem in order to make assertions:
+//
+//	filepath.Join(d.RootModuleDir(), normalizePathResult)
+//
+// The above is suitable only for situations where the given path is known
+// to be beneath the working directory, which is the typical situation for
+// temporary working directories created for automated tests.
+func (d *Dir) NormalizePath(given string) string {
+	// We need an absolute version of d.mainDir in order for our "Rel"
+	// result to be reliable.
+	absMain, err := filepath.Abs(d.mainDir)
+	if err != nil {
+		// Weird, but okay...
+		return filepath.Clean(given)
+	}
+
+	if !filepath.IsAbs(given) {
+		given = filepath.Join(absMain, given)
+	}
+
+	ret, err := filepath.Rel(absMain, given)
+	if err != nil {
+		// It's not always possible to find a relative path. For example,
+		// the given path might be on an entirely separate volume
+		// (e.g. drive letter or network share) on a Windows system, which
+		// always requires an absolute path.
+		return filepath.Clean(given)
+	}
+
+	return ret
+}
diff --git a/v1.5.7/internal/command/workdir/plugin_dirs.go b/v1.5.7/internal/command/workdir/plugin_dirs.go
new file mode 100644
index 0000000..c7caab1
--- /dev/null
+++ b/v1.5.7/internal/command/workdir/plugin_dirs.go
@@ -0,0 +1,86 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package workdir
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+)
+
+const PluginPathFilename = "plugin_path"
+
+// ProviderLocalCacheDir returns the directory we'll use as the
+// working-directory-specific local cache of providers.
+//
+// The provider installer's job is to make sure that all providers needed for
+// a particular working directory are available in this cache directory. No
+// other component may write here, and in particular a Dir object itself
+// never reads or writes into this directory, instead just delegating all of
+// that responsibility to other components.
+//
+// Typically, the caller will ultimately pass the result of this method either
+// directly or indirectly into providercache.NewDir, to get an object
+// responsible for managing the contents.
+func (d *Dir) ProviderLocalCacheDir() string {
+	return filepath.Join(d.dataDir, "providers")
+}
+
+// ForcedPluginDirs returns a list of directories to use to find plugins,
+// instead of the default locations.
+//
+// Returns an zero-length list and no error in the normal case where there
+// are no overridden search directories. If ForcedPluginDirs returns a
+// non-empty list with no errors then the result totally replaces the default
+// search directories.
+func (d *Dir) ForcedPluginDirs() ([]string, error) {
+	raw, err := ioutil.ReadFile(filepath.Join(d.dataDir, PluginPathFilename))
+	if os.IsNotExist(err) {
+		return nil, nil
+	}
+
+	if err != nil {
+		return nil, err
+	}
+
+	var pluginPath []string
+	if err := json.Unmarshal(raw, &pluginPath); err != nil {
+		return nil, err
+	}
+	return pluginPath, nil
+}
+
+// SetForcedPluginDirs records an overridden list of directories to search
+// to find plugins, instead of the default locations. See ForcePluginDirs
+// for more information.
+//
+// Pass a zero-length list to deactivate forced plugin directories altogether,
+// thus allowing the working directory to return to using the default
+// search directories.
+func (d *Dir) SetForcedPluginDirs(dirs []string) error {
+
+	filePath := filepath.Join(d.dataDir, PluginPathFilename)
+	switch {
+	case len(dirs) == 0:
+		err := os.Remove(filePath)
+		if !os.IsNotExist(err) {
+			return err
+		}
+		return nil
+	default:
+		// We'll ignore errors from this one, because if we fail to create
+		// the directory then we'll fail to create the file below too,
+		// and that subsequent error will more directly reflect what we
+		// are trying to do here.
+		d.ensureDataDir()
+
+		raw, err := json.MarshalIndent(dirs, "", "  ")
+		if err != nil {
+			return err
+		}
+
+		return ioutil.WriteFile(filePath, raw, 0644)
+	}
+}
diff --git a/v1.5.7/internal/command/workdir/plugin_dirs_test.go b/v1.5.7/internal/command/workdir/plugin_dirs_test.go
new file mode 100644
index 0000000..d96f733
--- /dev/null
+++ b/v1.5.7/internal/command/workdir/plugin_dirs_test.go
@@ -0,0 +1,58 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package workdir
+
+import (
+	"path/filepath"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+)
+
+func TestDirForcedPluginDirs(t *testing.T) {
+	tmpDir := t.TempDir()
+
+	dir := NewDir(tmpDir)
+	// We'll use the default convention of a data dir nested inside the
+	// working directory, so we don't need to override anything on "dir".
+
+	want := []string(nil)
+	got, err := dir.ForcedPluginDirs()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Errorf("wrong initial settings\n%s", diff)
+	}
+
+	fakeDir1 := filepath.Join(tmpDir, "boop1")
+	fakeDir2 := filepath.Join(tmpDir, "boop2")
+	err = dir.SetForcedPluginDirs([]string{fakeDir1, fakeDir2})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	want = []string{fakeDir1, fakeDir2}
+	got, err = dir.ForcedPluginDirs()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Errorf("wrong updated settings\n%s", diff)
+	}
+
+	err = dir.SetForcedPluginDirs(nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	want = nil
+	got, err = dir.ForcedPluginDirs()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Errorf("wrong final settings, after reverting back to defaults\n%s", diff)
+	}
+}
diff --git a/v1.5.7/internal/command/workspace_command.go b/v1.5.7/internal/command/workspace_command.go
new file mode 100644
index 0000000..e348c0b
--- /dev/null
+++ b/v1.5.7/internal/command/workspace_command.go
@@ -0,0 +1,128 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"net/url"
+	"strings"
+
+	"github.com/mitchellh/cli"
+)
+
+// WorkspaceCommand is a Command Implementation that manipulates workspaces,
+// which allow multiple distinct states and variables from a single config.
+type WorkspaceCommand struct {
+	Meta
+	LegacyName bool
+}
+
+func (c *WorkspaceCommand) Run(args []string) int {
+	c.Meta.process(args)
+	envCommandShowWarning(c.Ui, c.LegacyName)
+
+	cmdFlags := c.Meta.extendedFlagSet("workspace")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+
+	return cli.RunResultHelp
+}
+
+func (c *WorkspaceCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] workspace
+
+  new, list, show, select and delete Terraform workspaces.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *WorkspaceCommand) Synopsis() string {
+	return "Workspace management"
+}
+
+// validWorkspaceName returns true is this name is valid to use as a workspace name.
+// Since most named states are accessed via a filesystem path or URL, check if
+// escaping the name would be required.
+func validWorkspaceName(name string) bool {
+	return name == url.PathEscape(name)
+}
+
+func envCommandShowWarning(ui cli.Ui, show bool) {
+	if !show {
+		return
+	}
+
+	ui.Warn(`Warning: the "terraform env" family of commands is deprecated.
+
+"Workspace" is now the preferred term for what earlier Terraform versions
+called "environment", to reduce ambiguity caused by the latter term colliding
+with other concepts.
+
+The "terraform workspace" commands should be used instead. "terraform env"
+will be removed in a future Terraform version.
+`)
+}
+
+const (
+	envExists = `Workspace %q already exists`
+
+	envDoesNotExist = `
+Workspace %q doesn't exist.
+
+You can create this workspace with the "new" subcommand 
+or include the "-or-create" flag with the "select" subcommand.`
+
+	envChanged = `[reset][green]Switched to workspace %q.`
+
+	envCreated = `
+[reset][green][bold]Created and switched to workspace %q![reset][green]
+
+You're now on a new, empty workspace. Workspaces isolate their state,
+so if you run "terraform plan" Terraform will not see any existing state
+for this configuration.
+`
+
+	envDeleted = `[reset][green]Deleted workspace %q!`
+
+	envWarnNotEmpty = `[reset][yellow]WARNING: %q was non-empty.
+The resources managed by the deleted workspace may still exist,
+but are no longer manageable by Terraform since the state has
+been deleted.
+`
+
+	envDelCurrent = `
+Workspace %[1]q is your active workspace.
+
+You cannot delete the currently active workspace. Please switch
+to another workspace and try again.
+`
+
+	envInvalidName = `
+The workspace name %q is not allowed. The name must contain only URL safe
+characters, and no path separators.
+`
+
+	envIsOverriddenNote = `
+
+The active workspace is being overridden using the TF_WORKSPACE environment
+variable.
+`
+
+	envIsOverriddenSelectError = `
+The selected workspace is currently overridden using the TF_WORKSPACE
+environment variable.
+
+To select a new workspace, either update this environment variable or unset
+it and then run this command again.
+`
+
+	envIsOverriddenNewError = `
+The workspace is currently overridden using the TF_WORKSPACE environment
+variable. You cannot create a new workspace when using this setting.
+
+To create a new workspace, either unset this environment variable or update it
+to match the workspace name you are trying to create, and then run this command
+again.
+`
+)
diff --git a/v1.5.7/internal/command/workspace_command_test.go b/v1.5.7/internal/command/workspace_command_test.go
new file mode 100644
index 0000000..c5bde96
--- /dev/null
+++ b/v1.5.7/internal/command/workspace_command_test.go
@@ -0,0 +1,468 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/backend"
+	"github.com/hashicorp/terraform/internal/backend/local"
+	"github.com/hashicorp/terraform/internal/backend/remote-state/inmem"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/mitchellh/cli"
+
+	legacy "github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+func TestWorkspace_createAndChange(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	newCmd := &WorkspaceNewCommand{}
+
+	current, _ := newCmd.Workspace()
+	if current != backend.DefaultStateName {
+		t.Fatal("current workspace should be 'default'")
+	}
+
+	args := []string{"test"}
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	newCmd.Meta = Meta{Ui: ui, View: view}
+	if code := newCmd.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
+	}
+
+	current, _ = newCmd.Workspace()
+	if current != "test" {
+		t.Fatalf("current workspace should be 'test', got %q", current)
+	}
+
+	selCmd := &WorkspaceSelectCommand{}
+	args = []string{backend.DefaultStateName}
+	ui = new(cli.MockUi)
+	selCmd.Meta = Meta{Ui: ui, View: view}
+	if code := selCmd.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
+	}
+
+	current, _ = newCmd.Workspace()
+	if current != backend.DefaultStateName {
+		t.Fatal("current workspace should be 'default'")
+	}
+
+}
+
+// Create some workspaces and test the list output.
+// This also ensures we switch to the correct env after each call
+func TestWorkspace_createAndList(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	// make sure a vars file doesn't interfere
+	err := ioutil.WriteFile(
+		DefaultVarsFilename,
+		[]byte(`foo = "bar"`),
+		0644,
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	envs := []string{"test_a", "test_b", "test_c"}
+
+	// create multiple workspaces
+	for _, env := range envs {
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		newCmd := &WorkspaceNewCommand{
+			Meta: Meta{Ui: ui, View: view},
+		}
+		if code := newCmd.Run([]string{env}); code != 0 {
+			t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
+		}
+	}
+
+	listCmd := &WorkspaceListCommand{}
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	listCmd.Meta = Meta{Ui: ui, View: view}
+
+	if code := listCmd.Run(nil); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
+	}
+
+	actual := strings.TrimSpace(ui.OutputWriter.String())
+	expected := "default\n  test_a\n  test_b\n* test_c"
+
+	if actual != expected {
+		t.Fatalf("\nexpected: %q\nactual:  %q", expected, actual)
+	}
+}
+
+// Create some workspaces and test the show output.
+func TestWorkspace_createAndShow(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	// make sure a vars file doesn't interfere
+	err := ioutil.WriteFile(
+		DefaultVarsFilename,
+		[]byte(`foo = "bar"`),
+		0644,
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// make sure current workspace show outputs "default"
+	showCmd := &WorkspaceShowCommand{}
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	showCmd.Meta = Meta{Ui: ui, View: view}
+
+	if code := showCmd.Run(nil); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
+	}
+
+	actual := strings.TrimSpace(ui.OutputWriter.String())
+	expected := "default"
+
+	if actual != expected {
+		t.Fatalf("\nexpected: %q\nactual:  %q", expected, actual)
+	}
+
+	newCmd := &WorkspaceNewCommand{}
+
+	env := []string{"test_a"}
+
+	// create test_a workspace
+	ui = new(cli.MockUi)
+	newCmd.Meta = Meta{Ui: ui, View: view}
+	if code := newCmd.Run(env); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
+	}
+
+	selCmd := &WorkspaceSelectCommand{}
+	ui = new(cli.MockUi)
+	selCmd.Meta = Meta{Ui: ui, View: view}
+	if code := selCmd.Run(env); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
+	}
+
+	showCmd = &WorkspaceShowCommand{}
+	ui = new(cli.MockUi)
+	showCmd.Meta = Meta{Ui: ui, View: view}
+
+	if code := showCmd.Run(nil); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
+	}
+
+	actual = strings.TrimSpace(ui.OutputWriter.String())
+	expected = "test_a"
+
+	if actual != expected {
+		t.Fatalf("\nexpected: %q\nactual:  %q", expected, actual)
+	}
+}
+
+// Don't allow names that aren't URL safe
+func TestWorkspace_createInvalid(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	envs := []string{"test_a*", "test_b/foo", "../../../test_c", "好_d"}
+
+	// create multiple workspaces
+	for _, env := range envs {
+		ui := new(cli.MockUi)
+		view, _ := testView(t)
+		newCmd := &WorkspaceNewCommand{
+			Meta: Meta{Ui: ui, View: view},
+		}
+		if code := newCmd.Run([]string{env}); code == 0 {
+			t.Fatalf("expected failure: \n%s", ui.OutputWriter)
+		}
+	}
+
+	// list workspaces to make sure none were created
+	listCmd := &WorkspaceListCommand{}
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	listCmd.Meta = Meta{Ui: ui, View: view}
+
+	if code := listCmd.Run(nil); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
+	}
+
+	actual := strings.TrimSpace(ui.OutputWriter.String())
+	expected := "* default"
+
+	if actual != expected {
+		t.Fatalf("\nexpected: %q\nactual:  %q", expected, actual)
+	}
+}
+
+func TestWorkspace_createWithState(t *testing.T) {
+	td := t.TempDir()
+	testCopyDir(t, testFixturePath("inmem-backend"), td)
+	defer testChdir(t, td)()
+	defer inmem.Reset()
+
+	// init the backend
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	initCmd := &InitCommand{
+		Meta: Meta{Ui: ui, View: view},
+	}
+	if code := initCmd.Run([]string{}); code != 0 {
+		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
+	}
+
+	originalState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"bar"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	err := statemgr.NewFilesystem("test.tfstate").WriteState(originalState)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	workspace := "test_workspace"
+
+	args := []string{"-state", "test.tfstate", workspace}
+	ui = new(cli.MockUi)
+	newCmd := &WorkspaceNewCommand{
+		Meta: Meta{Ui: ui, View: view},
+	}
+	if code := newCmd.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
+	}
+
+	newPath := filepath.Join(local.DefaultWorkspaceDir, "test", DefaultStateFilename)
+	envState := statemgr.NewFilesystem(newPath)
+	err = envState.RefreshState()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	b := backend.TestBackendConfig(t, inmem.New(), nil)
+	sMgr, err := b.StateMgr(workspace)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	newState := sMgr.State()
+
+	if got, want := newState.String(), originalState.String(); got != want {
+		t.Fatalf("states not equal\ngot: %s\nwant: %s", got, want)
+	}
+}
+
+func TestWorkspace_delete(t *testing.T) {
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	// create the workspace directories
+	if err := os.MkdirAll(filepath.Join(local.DefaultWorkspaceDir, "test"), 0755); err != nil {
+		t.Fatal(err)
+	}
+
+	// create the workspace file
+	if err := os.MkdirAll(DefaultDataDir, 0755); err != nil {
+		t.Fatal(err)
+	}
+	if err := ioutil.WriteFile(filepath.Join(DefaultDataDir, local.DefaultWorkspaceFile), []byte("test"), 0644); err != nil {
+		t.Fatal(err)
+	}
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	delCmd := &WorkspaceDeleteCommand{
+		Meta: Meta{Ui: ui, View: view},
+	}
+
+	current, _ := delCmd.Workspace()
+	if current != "test" {
+		t.Fatal("wrong workspace:", current)
+	}
+
+	// we can't delete our current workspace
+	args := []string{"test"}
+	if code := delCmd.Run(args); code == 0 {
+		t.Fatal("expected error deleting current workspace")
+	}
+
+	// change back to default
+	if err := delCmd.SetWorkspace(backend.DefaultStateName); err != nil {
+		t.Fatal(err)
+	}
+
+	// try the delete again
+	ui = new(cli.MockUi)
+	delCmd.Meta.Ui = ui
+	if code := delCmd.Run(args); code != 0 {
+		t.Fatalf("error deleting workspace: %s", ui.ErrorWriter)
+	}
+
+	current, _ = delCmd.Workspace()
+	if current != backend.DefaultStateName {
+		t.Fatalf("wrong workspace: %q", current)
+	}
+}
+
+func TestWorkspace_deleteInvalid(t *testing.T) {
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	// choose an invalid workspace name
+	workspace := "test workspace"
+	path := filepath.Join(local.DefaultWorkspaceDir, workspace)
+
+	// create the workspace directories
+	if err := os.MkdirAll(path, 0755); err != nil {
+		t.Fatal(err)
+	}
+
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	delCmd := &WorkspaceDeleteCommand{
+		Meta: Meta{Ui: ui, View: view},
+	}
+
+	// delete the workspace
+	if code := delCmd.Run([]string{workspace}); code != 0 {
+		t.Fatalf("error deleting workspace: %s", ui.ErrorWriter)
+	}
+
+	if _, err := os.Stat(path); err == nil {
+		t.Fatalf("should have deleted workspace, but %s still exists", path)
+	} else if !os.IsNotExist(err) {
+		t.Fatalf("unexpected error for workspace path: %s", err)
+	}
+}
+
+func TestWorkspace_deleteWithState(t *testing.T) {
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	// create the workspace directories
+	if err := os.MkdirAll(filepath.Join(local.DefaultWorkspaceDir, "test"), 0755); err != nil {
+		t.Fatal(err)
+	}
+
+	// create a non-empty state
+	originalState := &legacy.State{
+		Modules: []*legacy.ModuleState{
+			{
+				Path: []string{"root"},
+				Resources: map[string]*legacy.ResourceState{
+					"test_instance.foo": {
+						Type: "test_instance",
+						Primary: &legacy.InstanceState{
+							ID: "bar",
+						},
+					},
+				},
+			},
+		},
+	}
+
+	f, err := os.Create(filepath.Join(local.DefaultWorkspaceDir, "test", "terraform.tfstate"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+	if err := legacy.WriteState(originalState, f); err != nil {
+		t.Fatal(err)
+	}
+
+	ui := cli.NewMockUi()
+	view, _ := testView(t)
+	delCmd := &WorkspaceDeleteCommand{
+		Meta: Meta{Ui: ui, View: view},
+	}
+	args := []string{"test"}
+	if code := delCmd.Run(args); code == 0 {
+		t.Fatalf("expected failure without -force.\noutput: %s", ui.OutputWriter)
+	}
+	gotStderr := ui.ErrorWriter.String()
+	if want, got := `Workspace "test" is currently tracking the following resource instances`, gotStderr; !strings.Contains(got, want) {
+		t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, got)
+	}
+	if want, got := `- test_instance.foo`, gotStderr; !strings.Contains(got, want) {
+		t.Errorf("error message doesn't mention the remaining instance\nwant substring: %s\ngot:\n%s", want, got)
+	}
+
+	ui = new(cli.MockUi)
+	delCmd.Meta.Ui = ui
+
+	args = []string{"-force", "test"}
+	if code := delCmd.Run(args); code != 0 {
+		t.Fatalf("failure: %s", ui.ErrorWriter)
+	}
+
+	if _, err := os.Stat(filepath.Join(local.DefaultWorkspaceDir, "test")); !os.IsNotExist(err) {
+		t.Fatal("env 'test' still exists!")
+	}
+}
+
+func TestWorkspace_selectWithOrCreate(t *testing.T) {
+	// Create a temporary working directory that is empty
+	td := t.TempDir()
+	os.MkdirAll(td, 0755)
+	defer testChdir(t, td)()
+
+	selectCmd := &WorkspaceSelectCommand{}
+
+	current, _ := selectCmd.Workspace()
+	if current != backend.DefaultStateName {
+		t.Fatal("current workspace should be 'default'")
+	}
+
+	args := []string{"-or-create", "test"}
+	ui := new(cli.MockUi)
+	view, _ := testView(t)
+	selectCmd.Meta = Meta{Ui: ui, View: view}
+	if code := selectCmd.Run(args); code != 0 {
+		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
+	}
+
+	current, _ = selectCmd.Workspace()
+	if current != "test" {
+		t.Fatalf("current workspace should be 'test', got %q", current)
+	}
+
+}
diff --git a/v1.5.7/internal/command/workspace_delete.go b/v1.5.7/internal/command/workspace_delete.go
new file mode 100644
index 0000000..a62bd2b
--- /dev/null
+++ b/v1.5.7/internal/command/workspace_delete.go
@@ -0,0 +1,232 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/mitchellh/cli"
+	"github.com/posener/complete"
+)
+
+type WorkspaceDeleteCommand struct {
+	Meta
+	LegacyName bool
+}
+
+func (c *WorkspaceDeleteCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	envCommandShowWarning(c.Ui, c.LegacyName)
+
+	var force bool
+	var stateLock bool
+	var stateLockTimeout time.Duration
+	cmdFlags := c.Meta.defaultFlagSet("workspace delete")
+	cmdFlags.BoolVar(&force, "force", false, "force removal of a non-empty workspace")
+	cmdFlags.BoolVar(&stateLock, "lock", true, "lock state")
+	cmdFlags.DurationVar(&stateLockTimeout, "lock-timeout", 0, "lock timeout")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	args = cmdFlags.Args()
+	if len(args) != 1 {
+		c.Ui.Error("Expected a single argument: NAME.\n")
+		return cli.RunResultHelp
+	}
+
+	configPath, err := ModulePath(args[1:])
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	backendConfig, backendDiags := c.loadBackendConfig(configPath)
+	diags = diags.Append(backendDiags)
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(&BackendOpts{
+		Config: backendConfig,
+	})
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// This command will not write state
+	c.ignoreRemoteVersionConflict(b)
+
+	workspaces, err := b.Workspaces()
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	workspace := args[0]
+	exists := false
+	for _, ws := range workspaces {
+		if workspace == ws {
+			exists = true
+			break
+		}
+	}
+
+	if !exists {
+		c.Ui.Error(fmt.Sprintf(strings.TrimSpace(envDoesNotExist), workspace))
+		return 1
+	}
+
+	currentWorkspace, err := c.Workspace()
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err))
+		return 1
+	}
+	if workspace == currentWorkspace {
+		c.Ui.Error(fmt.Sprintf(strings.TrimSpace(envDelCurrent), workspace))
+		return 1
+	}
+
+	// we need the actual state to see if it's empty
+	stateMgr, err := b.StateMgr(workspace)
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	var stateLocker clistate.Locker
+	if stateLock {
+		stateLocker = clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
+		if diags := stateLocker.Lock(stateMgr, "state-replace-provider"); diags.HasErrors() {
+			c.showDiagnostics(diags)
+			return 1
+		}
+	} else {
+		stateLocker = clistate.NewNoopLocker()
+	}
+
+	if err := stateMgr.RefreshState(); err != nil {
+		// We need to release the lock before exit
+		stateLocker.Unlock()
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	hasResources := stateMgr.State().HasManagedResourceInstanceObjects()
+
+	if hasResources && !force {
+		// We'll collect a list of what's being managed here as extra context
+		// for the message.
+		var buf strings.Builder
+		for _, obj := range stateMgr.State().AllResourceInstanceObjectAddrs() {
+			if obj.DeposedKey == states.NotDeposed {
+				fmt.Fprintf(&buf, "\n  - %s", obj.Instance.String())
+			} else {
+				fmt.Fprintf(&buf, "\n  - %s (deposed object %s)", obj.Instance.String(), obj.DeposedKey)
+			}
+		}
+
+		// We need to release the lock before exit
+		stateLocker.Unlock()
+
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Workspace is not empty",
+			fmt.Sprintf(
+				"Workspace %q is currently tracking the following resource instances:%s\n\nDeleting this workspace would cause Terraform to lose track of any associated remote objects, which would then require you to delete them manually outside of Terraform. You should destroy these objects with Terraform before deleting the workspace.\n\nIf you want to delete this workspace anyway, and have Terraform forget about these managed objects, use the -force option to disable this safety check.",
+				workspace, buf.String(),
+			),
+		))
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// We need to release the lock just before deleting the state, in case
+	// the backend can't remove the resource while holding the lock. This
+	// is currently true for Windows local files.
+	//
+	// TODO: While there is little safety in locking while deleting the
+	// state, it might be nice to be able to coordinate processes around
+	// state deletion, i.e. in a CI environment. Adding Delete() as a
+	// required method of States would allow the removal of the resource to
+	// be delegated from the Backend to the State itself.
+	stateLocker.Unlock()
+
+	err = b.DeleteWorkspace(workspace, force)
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	c.Ui.Output(
+		c.Colorize().Color(
+			fmt.Sprintf(envDeleted, workspace),
+		),
+	)
+
+	if hasResources {
+		c.Ui.Output(
+			c.Colorize().Color(
+				fmt.Sprintf(envWarnNotEmpty, workspace),
+			),
+		)
+	}
+
+	return 0
+}
+
+func (c *WorkspaceDeleteCommand) AutocompleteArgs() complete.Predictor {
+	return completePredictSequence{
+		c.completePredictWorkspaceName(),
+		complete.PredictDirs(""),
+	}
+}
+
+func (c *WorkspaceDeleteCommand) AutocompleteFlags() complete.Flags {
+	return complete.Flags{
+		"-force": complete.PredictNothing,
+	}
+}
+
+func (c *WorkspaceDeleteCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] workspace delete [OPTIONS] NAME
+
+  Delete a Terraform workspace
+
+
+Options:
+
+  -force             Remove a workspace even if it is managing resources.
+                     Terraform can no longer track or manage the workspace's
+                     infrastructure.
+
+  -lock=false        Don't hold a state lock during the operation. This is
+                     dangerous if others might concurrently run commands
+                     against the same workspace.
+
+  -lock-timeout=0s   Duration to retry a state lock.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *WorkspaceDeleteCommand) Synopsis() string {
+	return "Delete a workspace"
+}
diff --git a/v1.5.7/internal/command/workspace_list.go b/v1.5.7/internal/command/workspace_list.go
new file mode 100644
index 0000000..5d4cfd6
--- /dev/null
+++ b/v1.5.7/internal/command/workspace_list.go
@@ -0,0 +1,107 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"bytes"
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/posener/complete"
+)
+
+type WorkspaceListCommand struct {
+	Meta
+	LegacyName bool
+}
+
+func (c *WorkspaceListCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	envCommandShowWarning(c.Ui, c.LegacyName)
+
+	cmdFlags := c.Meta.defaultFlagSet("workspace list")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	args = cmdFlags.Args()
+	configPath, err := ModulePath(args)
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	backendConfig, backendDiags := c.loadBackendConfig(configPath)
+	diags = diags.Append(backendDiags)
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(&BackendOpts{
+		Config: backendConfig,
+	})
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// This command will not write state
+	c.ignoreRemoteVersionConflict(b)
+
+	states, err := b.Workspaces()
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	env, isOverridden := c.WorkspaceOverridden()
+
+	var out bytes.Buffer
+	for _, s := range states {
+		if s == env {
+			out.WriteString("* ")
+		} else {
+			out.WriteString("  ")
+		}
+		out.WriteString(s + "\n")
+	}
+
+	c.Ui.Output(out.String())
+
+	if isOverridden {
+		c.Ui.Output(envIsOverriddenNote)
+	}
+
+	return 0
+}
+
+func (c *WorkspaceListCommand) AutocompleteArgs() complete.Predictor {
+	return complete.PredictDirs("")
+}
+
+func (c *WorkspaceListCommand) AutocompleteFlags() complete.Flags {
+	return nil
+}
+
+func (c *WorkspaceListCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] workspace list
+
+  List Terraform workspaces.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *WorkspaceListCommand) Synopsis() string {
+	return "List Workspaces"
+}
diff --git a/v1.5.7/internal/command/workspace_new.go b/v1.5.7/internal/command/workspace_new.go
new file mode 100644
index 0000000..161bd10
--- /dev/null
+++ b/v1.5.7/internal/command/workspace_new.go
@@ -0,0 +1,206 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"os"
+	"strings"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/command/arguments"
+	"github.com/hashicorp/terraform/internal/command/clistate"
+	"github.com/hashicorp/terraform/internal/command/views"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/mitchellh/cli"
+	"github.com/posener/complete"
+)
+
+type WorkspaceNewCommand struct {
+	Meta
+	LegacyName bool
+}
+
+func (c *WorkspaceNewCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	envCommandShowWarning(c.Ui, c.LegacyName)
+
+	var stateLock bool
+	var stateLockTimeout time.Duration
+	var statePath string
+	cmdFlags := c.Meta.defaultFlagSet("workspace new")
+	cmdFlags.BoolVar(&stateLock, "lock", true, "lock state")
+	cmdFlags.DurationVar(&stateLockTimeout, "lock-timeout", 0, "lock timeout")
+	cmdFlags.StringVar(&statePath, "state", "", "terraform state file")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	args = cmdFlags.Args()
+	if len(args) != 1 {
+		c.Ui.Error("Expected a single argument: NAME.\n")
+		return cli.RunResultHelp
+	}
+
+	workspace := args[0]
+
+	if !validWorkspaceName(workspace) {
+		c.Ui.Error(fmt.Sprintf(envInvalidName, workspace))
+		return 1
+	}
+
+	// You can't ask to create a workspace when you're overriding the
+	// workspace name to be something different.
+	if current, isOverridden := c.WorkspaceOverridden(); current != workspace && isOverridden {
+		c.Ui.Error(envIsOverriddenNewError)
+		return 1
+	}
+
+	configPath, err := ModulePath(args[1:])
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	backendConfig, backendDiags := c.loadBackendConfig(configPath)
+	diags = diags.Append(backendDiags)
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(&BackendOpts{
+		Config: backendConfig,
+	})
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	// This command will not write state
+	c.ignoreRemoteVersionConflict(b)
+
+	workspaces, err := b.Workspaces()
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to get configured named states: %s", err))
+		return 1
+	}
+	for _, ws := range workspaces {
+		if workspace == ws {
+			c.Ui.Error(fmt.Sprintf(envExists, workspace))
+			return 1
+		}
+	}
+
+	_, err = b.StateMgr(workspace)
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	// now set the current workspace locally
+	if err := c.SetWorkspace(workspace); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error selecting new workspace: %s", err))
+		return 1
+	}
+
+	c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
+		strings.TrimSpace(envCreated), workspace)))
+
+	if statePath == "" {
+		// if we're not loading a state, then we're done
+		return 0
+	}
+
+	// load the new Backend state
+	stateMgr, err := b.StateMgr(workspace)
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	if stateLock {
+		stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
+		if diags := stateLocker.Lock(stateMgr, "workspace-new"); diags.HasErrors() {
+			c.showDiagnostics(diags)
+			return 1
+		}
+		defer func() {
+			if diags := stateLocker.Unlock(); diags.HasErrors() {
+				c.showDiagnostics(diags)
+			}
+		}()
+	}
+
+	// read the existing state file
+	f, err := os.Open(statePath)
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	stateFile, err := statefile.Read(f)
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	// save the existing state in the new Backend.
+	err = stateMgr.WriteState(stateFile.State)
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+	err = stateMgr.PersistState(nil)
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	return 0
+}
+
+func (c *WorkspaceNewCommand) AutocompleteArgs() complete.Predictor {
+	return completePredictSequence{
+		complete.PredictAnything,
+		complete.PredictDirs(""),
+	}
+}
+
+func (c *WorkspaceNewCommand) AutocompleteFlags() complete.Flags {
+	return complete.Flags{
+		"-state": complete.PredictFiles("*.tfstate"),
+	}
+}
+
+func (c *WorkspaceNewCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] workspace new [OPTIONS] NAME
+
+  Create a new Terraform workspace.
+
+Options:
+
+    -lock=false         Don't hold a state lock during the operation. This is
+                        dangerous if others might concurrently run commands
+                        against the same workspace.
+
+    -lock-timeout=0s    Duration to retry a state lock.
+
+    -state=path         Copy an existing state file into the new workspace.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *WorkspaceNewCommand) Synopsis() string {
+	return "Create a new workspace"
+}
diff --git a/v1.5.7/internal/command/workspace_select.go b/v1.5.7/internal/command/workspace_select.go
new file mode 100644
index 0000000..52d75ae
--- /dev/null
+++ b/v1.5.7/internal/command/workspace_select.go
@@ -0,0 +1,166 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/mitchellh/cli"
+	"github.com/posener/complete"
+)
+
+type WorkspaceSelectCommand struct {
+	Meta
+	LegacyName bool
+}
+
+func (c *WorkspaceSelectCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	envCommandShowWarning(c.Ui, c.LegacyName)
+
+	var orCreate bool
+	cmdFlags := c.Meta.defaultFlagSet("workspace select")
+	cmdFlags.BoolVar(&orCreate, "or-create", false, "create workspace if it does not exist")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	args = cmdFlags.Args()
+	if len(args) != 1 {
+		c.Ui.Error("Expected a single argument: NAME.\n")
+		return cli.RunResultHelp
+	}
+
+	configPath, err := ModulePath(args[1:])
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	var diags tfdiags.Diagnostics
+
+	backendConfig, backendDiags := c.loadBackendConfig(configPath)
+	diags = diags.Append(backendDiags)
+	if diags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	current, isOverridden := c.WorkspaceOverridden()
+	if isOverridden {
+		c.Ui.Error(envIsOverriddenSelectError)
+		return 1
+	}
+
+	// Load the backend
+	b, backendDiags := c.Backend(&BackendOpts{
+		Config: backendConfig,
+	})
+	diags = diags.Append(backendDiags)
+	if backendDiags.HasErrors() {
+		c.showDiagnostics(diags)
+		return 1
+	}
+
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Failed to load backend: %s", err))
+		return 1
+	}
+
+	// This command will not write state
+	c.ignoreRemoteVersionConflict(b)
+
+	name := args[0]
+	if !validWorkspaceName(name) {
+		c.Ui.Error(fmt.Sprintf(envInvalidName, name))
+		return 1
+	}
+
+	states, err := b.Workspaces()
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	if name == current {
+		// already using this workspace
+		return 0
+	}
+
+	found := false
+	for _, s := range states {
+		if name == s {
+			found = true
+			break
+		}
+	}
+
+	var newState bool
+
+	if !found {
+		if orCreate {
+			_, err = b.StateMgr(name)
+			if err != nil {
+				c.Ui.Error(err.Error())
+				return 1
+			}
+			newState = true
+		} else {
+			c.Ui.Error(fmt.Sprintf(envDoesNotExist, name))
+			return 1
+		}
+	}
+
+	err = c.SetWorkspace(name)
+	if err != nil {
+		c.Ui.Error(err.Error())
+		return 1
+	}
+
+	if newState {
+		c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
+			strings.TrimSpace(envCreated), name)))
+	} else {
+		c.Ui.Output(
+			c.Colorize().Color(
+				fmt.Sprintf(envChanged, name),
+			),
+		)
+	}
+
+	return 0
+}
+
+func (c *WorkspaceSelectCommand) AutocompleteArgs() complete.Predictor {
+	return completePredictSequence{
+		c.completePredictWorkspaceName(),
+		complete.PredictDirs(""),
+	}
+}
+
+func (c *WorkspaceSelectCommand) AutocompleteFlags() complete.Flags {
+	return nil
+}
+
+func (c *WorkspaceSelectCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] workspace select NAME
+
+  Select a different Terraform workspace.
+
+Options:
+
+    -or-create=false    Create the Terraform workspace if it doesn't exist.
+
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *WorkspaceSelectCommand) Synopsis() string {
+	return "Select a workspace"
+}
diff --git a/v1.5.7/internal/command/workspace_show.go b/v1.5.7/internal/command/workspace_show.go
new file mode 100644
index 0000000..90e21ca
--- /dev/null
+++ b/v1.5.7/internal/command/workspace_show.go
@@ -0,0 +1,55 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package command
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/posener/complete"
+)
+
+type WorkspaceShowCommand struct {
+	Meta
+}
+
+func (c *WorkspaceShowCommand) Run(args []string) int {
+	args = c.Meta.process(args)
+	cmdFlags := c.Meta.extendedFlagSet("workspace show")
+	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
+	if err := cmdFlags.Parse(args); err != nil {
+		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
+		return 1
+	}
+
+	workspace, err := c.Workspace()
+	if err != nil {
+		c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err))
+		return 1
+	}
+	c.Ui.Output(workspace)
+
+	return 0
+}
+
+func (c *WorkspaceShowCommand) AutocompleteArgs() complete.Predictor {
+	return complete.PredictNothing
+}
+
+func (c *WorkspaceShowCommand) AutocompleteFlags() complete.Flags {
+	return nil
+}
+
+func (c *WorkspaceShowCommand) Help() string {
+	helpText := `
+Usage: terraform [global options] workspace show
+
+  Show the name of the current workspace.
+`
+	return strings.TrimSpace(helpText)
+}
+
+func (c *WorkspaceShowCommand) Synopsis() string {
+	return "Show the name of the current workspace"
+}
diff --git a/v1.5.7/internal/communicator/communicator.go b/v1.5.7/internal/communicator/communicator.go
new file mode 100644
index 0000000..a735a24
--- /dev/null
+++ b/v1.5.7/internal/communicator/communicator.go
@@ -0,0 +1,173 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package communicator
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"log"
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/communicator/remote"
+	"github.com/hashicorp/terraform/internal/communicator/shared"
+	"github.com/hashicorp/terraform/internal/communicator/ssh"
+	"github.com/hashicorp/terraform/internal/communicator/winrm"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Communicator is an interface that must be implemented by all communicators
+// used for any of the provisioners
+type Communicator interface {
+	// Connect is used to set up the connection
+	Connect(provisioners.UIOutput) error
+
+	// Disconnect is used to terminate the connection
+	Disconnect() error
+
+	// Timeout returns the configured connection timeout
+	Timeout() time.Duration
+
+	// ScriptPath returns the configured script path
+	ScriptPath() string
+
+	// Start executes a remote command in a new session
+	Start(*remote.Cmd) error
+
+	// Upload is used to upload a single file
+	Upload(string, io.Reader) error
+
+	// UploadScript is used to upload a file as an executable script
+	UploadScript(string, io.Reader) error
+
+	// UploadDir is used to upload a directory
+	UploadDir(string, string) error
+}
+
+// New returns a configured Communicator or an error if the connection type is not supported
+func New(v cty.Value) (Communicator, error) {
+	v, err := shared.ConnectionBlockSupersetSchema.CoerceValue(v)
+	if err != nil {
+		return nil, err
+	}
+
+	typeVal := v.GetAttr("type")
+	connType := ""
+	if !typeVal.IsNull() {
+		connType = typeVal.AsString()
+	}
+
+	switch connType {
+	case "ssh", "": // The default connection type is ssh, so if connType is empty use ssh
+		return ssh.New(v)
+	case "winrm":
+		return winrm.New(v)
+	default:
+		return nil, fmt.Errorf("connection type '%s' not supported", connType)
+	}
+}
+
+// maxBackoffDelay is the maximum delay between retry attempts
+var maxBackoffDelay = 20 * time.Second
+var initialBackoffDelay = time.Second
+
+// in practice we want to abort the retry asap, but for tests we need to
+// synchronize the return.
+var retryTestWg *sync.WaitGroup
+
+// Fatal is an interface that error values can return to halt Retry
+type Fatal interface {
+	FatalError() error
+}
+
+// Retry retries the function f until it returns a nil error, a Fatal error, or
+// the context expires.
+func Retry(ctx context.Context, f func() error) error {
+	// container for atomic error value
+	type errWrap struct {
+		E error
+	}
+
+	// Try the function in a goroutine
+	var errVal atomic.Value
+	doneCh := make(chan struct{})
+	go func() {
+		if retryTestWg != nil {
+			defer retryTestWg.Done()
+		}
+
+		defer close(doneCh)
+
+		delay := time.Duration(0)
+		for {
+			// If our context ended, we want to exit right away.
+			select {
+			case <-ctx.Done():
+				return
+			case <-time.After(delay):
+			}
+
+			// Try the function call
+			err := f()
+
+			// return if we have no error, or a FatalError
+			done := false
+			switch e := err.(type) {
+			case nil:
+				done = true
+			case Fatal:
+				err = e.FatalError()
+				done = true
+			}
+
+			errVal.Store(errWrap{err})
+
+			if done {
+				return
+			}
+
+			log.Printf("[WARN] retryable error: %v", err)
+
+			delay *= 2
+
+			if delay == 0 {
+				delay = initialBackoffDelay
+			}
+
+			if delay > maxBackoffDelay {
+				delay = maxBackoffDelay
+			}
+
+			log.Printf("[INFO] sleeping for %s", delay)
+		}
+	}()
+
+	// Wait for completion
+	select {
+	case <-ctx.Done():
+	case <-doneCh:
+	}
+
+	var lastErr error
+	// Check if we got an error executing
+	if ev, ok := errVal.Load().(errWrap); ok {
+		lastErr = ev.E
+	}
+
+	// Check if we have a context error to check if we're interrupted or timeout
+	switch ctx.Err() {
+	case context.Canceled:
+		return fmt.Errorf("interrupted - last error: %v", lastErr)
+	case context.DeadlineExceeded:
+		return fmt.Errorf("timeout - last error: %v", lastErr)
+	}
+
+	if lastErr != nil {
+		return lastErr
+	}
+	return nil
+}
diff --git a/v1.5.7/internal/communicator/communicator_mock.go b/v1.5.7/internal/communicator/communicator_mock.go
new file mode 100644
index 0000000..aa33781
--- /dev/null
+++ b/v1.5.7/internal/communicator/communicator_mock.go
@@ -0,0 +1,109 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package communicator
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"strings"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/communicator/remote"
+	"github.com/hashicorp/terraform/internal/provisioners"
+)
+
+// MockCommunicator is an implementation of Communicator that can be used for tests.
+type MockCommunicator struct {
+	RemoteScriptPath string
+	Commands         map[string]bool
+	Uploads          map[string]string
+	UploadScripts    map[string]string
+	UploadDirs       map[string]string
+	CommandFunc      func(*remote.Cmd) error
+	DisconnectFunc   func() error
+	ConnTimeout      time.Duration
+}
+
+// Connect implementation of communicator.Communicator interface
+func (c *MockCommunicator) Connect(o provisioners.UIOutput) error {
+	return nil
+}
+
+// Disconnect implementation of communicator.Communicator interface
+func (c *MockCommunicator) Disconnect() error {
+	if c.DisconnectFunc != nil {
+		return c.DisconnectFunc()
+	}
+	return nil
+}
+
+// Timeout implementation of communicator.Communicator interface
+func (c *MockCommunicator) Timeout() time.Duration {
+	if c.ConnTimeout != 0 {
+		return c.ConnTimeout
+	}
+	return time.Duration(5 * time.Second)
+}
+
+// ScriptPath implementation of communicator.Communicator interface
+func (c *MockCommunicator) ScriptPath() string {
+	return c.RemoteScriptPath
+}
+
+// Start implementation of communicator.Communicator interface
+func (c *MockCommunicator) Start(r *remote.Cmd) error {
+	r.Init()
+
+	if c.CommandFunc != nil {
+		return c.CommandFunc(r)
+	}
+
+	if !c.Commands[r.Command] {
+		return fmt.Errorf("Command not found!")
+	}
+
+	r.SetExitStatus(0, nil)
+
+	return nil
+}
+
+// Upload implementation of communicator.Communicator interface
+func (c *MockCommunicator) Upload(path string, input io.Reader) error {
+	f, ok := c.Uploads[path]
+	if !ok {
+		return fmt.Errorf("Path %q not found!", path)
+	}
+
+	var buf bytes.Buffer
+	buf.ReadFrom(input)
+	content := strings.TrimSpace(buf.String())
+
+	f = strings.TrimSpace(f)
+	if f != content {
+		return fmt.Errorf("expected: %q\n\ngot: %q\n", f, content)
+	}
+
+	return nil
+}
+
+// UploadScript implementation of communicator.Communicator interface
+func (c *MockCommunicator) UploadScript(path string, input io.Reader) error {
+	c.Uploads = c.UploadScripts
+	return c.Upload(path, input)
+}
+
+// UploadDir implementation of communicator.Communicator interface
+func (c *MockCommunicator) UploadDir(dst string, src string) error {
+	v, ok := c.UploadDirs[src]
+	if !ok {
+		return fmt.Errorf("Directory not found!")
+	}
+
+	if v != dst {
+		return fmt.Errorf("expected: %q\n\ngot: %q\n", v, dst)
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/communicator/communicator_test.go b/v1.5.7/internal/communicator/communicator_test.go
new file mode 100644
index 0000000..2986dc2
--- /dev/null
+++ b/v1.5.7/internal/communicator/communicator_test.go
@@ -0,0 +1,106 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package communicator
+
+import (
+	"context"
+	"errors"
+	"io"
+	"net"
+	"sync"
+	"testing"
+	"time"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestCommunicator_new(t *testing.T) {
+	cfg := map[string]cty.Value{
+		"type": cty.StringVal("telnet"),
+		"host": cty.StringVal("127.0.0.1"),
+	}
+
+	if _, err := New(cty.ObjectVal(cfg)); err == nil {
+		t.Fatalf("expected error with telnet")
+	}
+
+	cfg["type"] = cty.StringVal("ssh")
+	if _, err := New(cty.ObjectVal(cfg)); err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	cfg["type"] = cty.StringVal("winrm")
+	if _, err := New(cty.ObjectVal(cfg)); err != nil {
+		t.Fatalf("err: %v", err)
+	}
+}
+func TestRetryFunc(t *testing.T) {
+	origMax := maxBackoffDelay
+	maxBackoffDelay = time.Second
+	origStart := initialBackoffDelay
+	initialBackoffDelay = 10 * time.Millisecond
+
+	defer func() {
+		maxBackoffDelay = origMax
+		initialBackoffDelay = origStart
+	}()
+
+	// succeed on the third try
+	errs := []error{io.EOF, &net.OpError{Err: errors.New("ERROR")}, nil}
+	count := 0
+
+	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+	defer cancel()
+
+	err := Retry(ctx, func() error {
+		if count >= len(errs) {
+			return errors.New("failed to stop after nil error")
+		}
+
+		err := errs[count]
+		count++
+
+		return err
+	})
+
+	if count != 3 {
+		t.Fatal("retry func should have been called 3 times")
+	}
+
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestRetryFuncBackoff(t *testing.T) {
+	origMax := maxBackoffDelay
+	maxBackoffDelay = time.Second
+	origStart := initialBackoffDelay
+	initialBackoffDelay = 100 * time.Millisecond
+
+	retryTestWg = &sync.WaitGroup{}
+	retryTestWg.Add(1)
+
+	defer func() {
+		maxBackoffDelay = origMax
+		initialBackoffDelay = origStart
+		retryTestWg = nil
+	}()
+
+	count := 0
+
+	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+	defer cancel()
+
+	Retry(ctx, func() error {
+		count++
+		return io.EOF
+	})
+	cancel()
+	retryTestWg.Wait()
+
+	if count > 4 {
+		t.Fatalf("retry func failed to backoff. called %d times", count)
+	}
+}
diff --git a/v1.5.7/internal/communicator/remote/command.go b/v1.5.7/internal/communicator/remote/command.go
new file mode 100644
index 0000000..52fb045
--- /dev/null
+++ b/v1.5.7/internal/communicator/remote/command.go
@@ -0,0 +1,99 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"fmt"
+	"io"
+	"sync"
+)
+
+// Cmd represents a remote command being prepared or run.
+type Cmd struct {
+	// Command is the command to run remotely. This is executed as if
+	// it were a shell command, so you are expected to do any shell escaping
+	// necessary.
+	Command string
+
+	// Stdin specifies the process's standard input. If Stdin is
+	// nil, the process reads from an empty bytes.Buffer.
+	Stdin io.Reader
+
+	// Stdout and Stderr represent the process's standard output and
+	// error.
+	//
+	// If either is nil, it will be set to ioutil.Discard.
+	Stdout io.Writer
+	Stderr io.Writer
+
+	// Once Wait returns, his will contain the exit code of the process.
+	exitStatus int
+
+	// Internal fields
+	exitCh chan struct{}
+
+	// err is used to store any error reported by the Communicator during
+	// execution.
+	err error
+
+	// This thing is a mutex, lock when making modifications concurrently
+	sync.Mutex
+}
+
+// Init must be called by the Communicator before executing the command.
+func (c *Cmd) Init() {
+	c.Lock()
+	defer c.Unlock()
+
+	c.exitCh = make(chan struct{})
+}
+
+// SetExitStatus stores the exit status of the remote command as well as any
+// communicator related error. SetExitStatus then unblocks any pending calls
+// to Wait.
+// This should only be called by communicators executing the remote.Cmd.
+func (c *Cmd) SetExitStatus(status int, err error) {
+	c.Lock()
+	defer c.Unlock()
+
+	c.exitStatus = status
+	c.err = err
+
+	close(c.exitCh)
+}
+
+// Wait waits for the remote command to complete.
+// Wait may return an error from the communicator, or an ExitError if the
+// process exits with a non-zero exit status.
+func (c *Cmd) Wait() error {
+	<-c.exitCh
+
+	c.Lock()
+	defer c.Unlock()
+
+	if c.err != nil || c.exitStatus != 0 {
+		return &ExitError{
+			Command:    c.Command,
+			ExitStatus: c.exitStatus,
+			Err:        c.err,
+		}
+	}
+
+	return nil
+}
+
+// ExitError is returned by Wait to indicate and error executing the remote
+// command, or a non-zero exit status.
+type ExitError struct {
+	Command    string
+	ExitStatus int
+	Err        error
+}
+
+func (e *ExitError) Error() string {
+	if e.Err != nil {
+		return fmt.Sprintf("error executing %q: %v", e.Command, e.Err)
+	}
+	return fmt.Sprintf("%q exit status: %d", e.Command, e.ExitStatus)
+}
diff --git a/v1.5.7/internal/communicator/remote/command_test.go b/v1.5.7/internal/communicator/remote/command_test.go
new file mode 100644
index 0000000..60794e8
--- /dev/null
+++ b/v1.5.7/internal/communicator/remote/command_test.go
@@ -0,0 +1,4 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
diff --git a/v1.5.7/internal/communicator/shared/shared.go b/v1.5.7/internal/communicator/shared/shared.go
new file mode 100644
index 0000000..a081ff3
--- /dev/null
+++ b/v1.5.7/internal/communicator/shared/shared.go
@@ -0,0 +1,156 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package shared
+
+import (
+	"fmt"
+	"net"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// ConnectionBlockSupersetSchema is a schema representing the superset of all
+// possible arguments for "connection" blocks across all supported connection
+// types.
+//
+// This currently lives here because we've not yet updated our communicator
+// subsystem to be aware of schema itself. Once that is done, we can remove
+// this and use a type-specific schema from the communicator to validate
+// exactly what is expected for a given connection type.
+var ConnectionBlockSupersetSchema = &configschema.Block{
+	Attributes: map[string]*configschema.Attribute{
+		// Common attributes for both connection types
+		"host": {
+			Type:     cty.String,
+			Required: true,
+		},
+		"type": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"user": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"password": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"port": {
+			Type:     cty.Number,
+			Optional: true,
+		},
+		"timeout": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"script_path": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		// For type=ssh only (enforced in ssh communicator)
+		"target_platform": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"private_key": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"certificate": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"host_key": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"agent": {
+			Type:     cty.Bool,
+			Optional: true,
+		},
+		"agent_identity": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"proxy_scheme": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"proxy_host": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"proxy_port": {
+			Type:     cty.Number,
+			Optional: true,
+		},
+		"proxy_user_name": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"proxy_user_password": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"bastion_host": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"bastion_host_key": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"bastion_port": {
+			Type:     cty.Number,
+			Optional: true,
+		},
+		"bastion_user": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"bastion_password": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"bastion_private_key": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"bastion_certificate": {
+			Type:     cty.String,
+			Optional: true,
+		},
+
+		// For type=winrm only (enforced in winrm communicator)
+		"https": {
+			Type:     cty.Bool,
+			Optional: true,
+		},
+		"insecure": {
+			Type:     cty.Bool,
+			Optional: true,
+		},
+		"cacert": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"use_ntlm": {
+			Type:     cty.Bool,
+			Optional: true,
+		},
+	},
+}
+
+// IpFormat formats the IP correctly, so we don't provide IPv6 address in an IPv4 format during node communication. We return the ip parameter as is if it's an IPv4 address or a hostname.
+func IpFormat(ip string) string {
+	ipObj := net.ParseIP(ip)
+	// Return the ip/host as is if it's either a hostname or an IPv4 address.
+	if ipObj == nil || ipObj.To4() != nil {
+		return ip
+	}
+
+	return fmt.Sprintf("[%s]", ip)
+}
diff --git a/v1.5.7/internal/communicator/shared/shared_test.go b/v1.5.7/internal/communicator/shared/shared_test.go
new file mode 100644
index 0000000..de9ddb7
--- /dev/null
+++ b/v1.5.7/internal/communicator/shared/shared_test.go
@@ -0,0 +1,29 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package shared
+
+import (
+	"testing"
+)
+
+func TestIpFormatting_Ipv4(t *testing.T) {
+	formatted := IpFormat("127.0.0.1")
+	if formatted != "127.0.0.1" {
+		t.Fatal("expected", "127.0.0.1", "got", formatted)
+	}
+}
+
+func TestIpFormatting_Hostname(t *testing.T) {
+	formatted := IpFormat("example.com")
+	if formatted != "example.com" {
+		t.Fatal("expected", "example.com", "got", formatted)
+	}
+}
+
+func TestIpFormatting_Ipv6(t *testing.T) {
+	formatted := IpFormat("::1")
+	if formatted != "[::1]" {
+		t.Fatal("expected", "[::1]", "got", formatted)
+	}
+}
diff --git a/v1.5.7/internal/communicator/ssh/communicator.go b/v1.5.7/internal/communicator/ssh/communicator.go
new file mode 100644
index 0000000..2adbdc4
--- /dev/null
+++ b/v1.5.7/internal/communicator/ssh/communicator.go
@@ -0,0 +1,899 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package ssh
+
+import (
+	"bufio"
+	"bytes"
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"math/rand"
+	"net"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/apparentlymart/go-shquot/shquot"
+	"github.com/hashicorp/terraform/internal/communicator/remote"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/zclconf/go-cty/cty"
+	"golang.org/x/crypto/ssh"
+	"golang.org/x/crypto/ssh/agent"
+
+	_ "github.com/hashicorp/terraform/internal/logging"
+)
+
+const (
+	// DefaultShebang is added at the top of a SSH script file
+	DefaultShebang = "#!/bin/sh\n"
+)
+
+var (
+	// randShared is a global random generator object that is shared.  This must be
+	// shared since it is seeded by the current time and creating multiple can
+	// result in the same values. By using a shared RNG we assure different numbers
+	// per call.
+	randLock   sync.Mutex
+	randShared *rand.Rand
+
+	// enable ssh keeplive probes by default
+	keepAliveInterval = 2 * time.Second
+
+	// max time to wait for for a KeepAlive response before considering the
+	// connection to be dead.
+	maxKeepAliveDelay = 120 * time.Second
+)
+
+// Communicator represents the SSH communicator
+type Communicator struct {
+	connInfo        *connectionInfo
+	client          *ssh.Client
+	config          *sshConfig
+	conn            net.Conn
+	cancelKeepAlive context.CancelFunc
+
+	lock sync.Mutex
+}
+
+type sshConfig struct {
+	// The configuration of the Go SSH connection
+	config *ssh.ClientConfig
+
+	// connection returns a new connection. The current connection
+	// in use will be closed as part of the Close method, or in the
+	// case an error occurs.
+	connection func() (net.Conn, error)
+
+	// noPty, if true, will not request a pty from the remote end.
+	noPty bool
+
+	// sshAgent is a struct surrounding the agent.Agent client and the net.Conn
+	// to the SSH Agent. It is nil if no SSH agent is configured
+	sshAgent *sshAgent
+}
+
+type fatalError struct {
+	error
+}
+
+func (e fatalError) FatalError() error {
+	return e.error
+}
+
+// New creates a new communicator implementation over SSH.
+func New(v cty.Value) (*Communicator, error) {
+	connInfo, err := parseConnectionInfo(v)
+	if err != nil {
+		return nil, err
+	}
+
+	config, err := prepareSSHConfig(connInfo)
+	if err != nil {
+		return nil, err
+	}
+
+	// Set up the random number generator once. The seed value is the
+	// time multiplied by the PID. This can overflow the int64 but that
+	// is okay. We multiply by the PID in case we have multiple processes
+	// grabbing this at the same time. This is possible with Terraform and
+	// if we communicate to the same host at the same instance, we could
+	// overwrite the same files. Multiplying by the PID prevents this.
+	randLock.Lock()
+	defer randLock.Unlock()
+	if randShared == nil {
+		randShared = rand.New(rand.NewSource(
+			time.Now().UnixNano() * int64(os.Getpid())))
+	}
+
+	comm := &Communicator{
+		connInfo: connInfo,
+		config:   config,
+	}
+
+	return comm, nil
+}
+
+// Connect implementation of communicator.Communicator interface
+func (c *Communicator) Connect(o provisioners.UIOutput) (err error) {
+	// Grab a lock so we can modify our internal attributes
+	c.lock.Lock()
+	defer c.lock.Unlock()
+
+	if c.conn != nil {
+		c.conn.Close()
+	}
+
+	// Set the conn and client to nil since we'll recreate it
+	c.conn = nil
+	c.client = nil
+
+	if o != nil {
+		o.Output(fmt.Sprintf(
+			"Connecting to remote host via SSH...\n"+
+				"  Host: %s\n"+
+				"  User: %s\n"+
+				"  Password: %t\n"+
+				"  Private key: %t\n"+
+				"  Certificate: %t\n"+
+				"  SSH Agent: %t\n"+
+				"  Checking Host Key: %t\n"+
+				"  Target Platform: %s\n",
+			c.connInfo.Host, c.connInfo.User,
+			c.connInfo.Password != "",
+			c.connInfo.PrivateKey != "",
+			c.connInfo.Certificate != "",
+			c.connInfo.Agent,
+			c.connInfo.HostKey != "",
+			c.connInfo.TargetPlatform,
+		))
+
+		if c.connInfo.BastionHost != "" {
+			o.Output(fmt.Sprintf(
+				"Using configured bastion host...\n"+
+					"  Host: %s\n"+
+					"  User: %s\n"+
+					"  Password: %t\n"+
+					"  Private key: %t\n"+
+					"  Certificate: %t\n"+
+					"  SSH Agent: %t\n"+
+					"  Checking Host Key: %t",
+				c.connInfo.BastionHost, c.connInfo.BastionUser,
+				c.connInfo.BastionPassword != "",
+				c.connInfo.BastionPrivateKey != "",
+				c.connInfo.BastionCertificate != "",
+				c.connInfo.Agent,
+				c.connInfo.BastionHostKey != "",
+			))
+		}
+
+		if c.connInfo.ProxyHost != "" {
+			o.Output(fmt.Sprintf(
+				"Using configured proxy host...\n"+
+					"  ProxyHost: %s\n"+
+					"  ProxyPort: %d\n"+
+					"  ProxyUserName: %s\n"+
+					"  ProxyUserPassword: %t",
+				c.connInfo.ProxyHost,
+				c.connInfo.ProxyPort,
+				c.connInfo.ProxyUserName,
+				c.connInfo.ProxyUserPassword != "",
+			))
+		}
+	}
+
+	hostAndPort := fmt.Sprintf("%s:%d", c.connInfo.Host, c.connInfo.Port)
+	log.Printf("[DEBUG] Connecting to %s for SSH", hostAndPort)
+	c.conn, err = c.config.connection()
+	if err != nil {
+		// Explicitly set this to the REAL nil. Connection() can return
+		// a nil implementation of net.Conn which will make the
+		// "if c.conn == nil" check fail above. Read here for more information
+		// on this psychotic language feature:
+		//
+		// http://golang.org/doc/faq#nil_error
+		c.conn = nil
+
+		log.Printf("[ERROR] connection error: %s", err)
+		return err
+	}
+
+	log.Printf("[DEBUG] Connection established. Handshaking for user %v", c.connInfo.User)
+	sshConn, sshChan, req, err := ssh.NewClientConn(c.conn, hostAndPort, c.config.config)
+	if err != nil {
+		err = fmt.Errorf("SSH authentication failed (%s@%s): %w", c.connInfo.User, hostAndPort, err)
+
+		// While in theory this should be a fatal error, some hosts may start
+		// the ssh service before it is properly configured, or before user
+		// authentication data is available.
+		// Log the error, and allow the provisioner to retry.
+		log.Printf("[WARN] %s", err)
+		return err
+	}
+
+	c.client = ssh.NewClient(sshConn, sshChan, req)
+
+	if c.config.sshAgent != nil {
+		log.Printf("[DEBUG] Telling SSH config to forward to agent")
+		if err := c.config.sshAgent.ForwardToAgent(c.client); err != nil {
+			return fatalError{err}
+		}
+
+		log.Printf("[DEBUG] Setting up a session to request agent forwarding")
+		session, err := c.client.NewSession()
+		if err != nil {
+			return err
+		}
+		defer session.Close()
+
+		err = agent.RequestAgentForwarding(session)
+
+		if err == nil {
+			log.Printf("[INFO] agent forwarding enabled")
+		} else {
+			log.Printf("[WARN] error forwarding agent: %s", err)
+		}
+	}
+
+	if err != nil {
+		return err
+	}
+
+	if o != nil {
+		o.Output("Connected!")
+	}
+
+	ctx, cancelKeepAlive := context.WithCancel(context.TODO())
+	c.cancelKeepAlive = cancelKeepAlive
+
+	// Start a keepalive goroutine to help maintain the connection for
+	// long-running commands.
+	log.Printf("[DEBUG] starting ssh KeepAlives")
+
+	// We want a local copy of the ssh client pointer, so that a reconnect
+	// doesn't race with the running keep-alive loop.
+	sshClient := c.client
+	go func() {
+		defer cancelKeepAlive()
+		// Along with the KeepAlives generating packets to keep the tcp
+		// connection open, we will use the replies to verify liveness of the
+		// connection. This will prevent dead connections from blocking the
+		// provisioner indefinitely.
+		respCh := make(chan error, 1)
+
+		go func() {
+			t := time.NewTicker(keepAliveInterval)
+			defer t.Stop()
+			for {
+				select {
+				case <-t.C:
+					_, _, err := sshClient.SendRequest("keepalive@terraform.io", true, nil)
+					respCh <- err
+				case <-ctx.Done():
+					return
+				}
+			}
+		}()
+
+		after := time.NewTimer(maxKeepAliveDelay)
+		defer after.Stop()
+
+		for {
+			select {
+			case err := <-respCh:
+				if err != nil {
+					log.Printf("[ERROR] ssh keepalive: %s", err)
+					sshConn.Close()
+					return
+				}
+			case <-after.C:
+				// abort after too many missed keepalives
+				log.Println("[ERROR] no reply from ssh server")
+				sshConn.Close()
+				return
+			case <-ctx.Done():
+				return
+			}
+			if !after.Stop() {
+				<-after.C
+			}
+			after.Reset(maxKeepAliveDelay)
+		}
+	}()
+
+	return nil
+}
+
+// Disconnect implementation of communicator.Communicator interface
+func (c *Communicator) Disconnect() error {
+	c.lock.Lock()
+	defer c.lock.Unlock()
+
+	if c.cancelKeepAlive != nil {
+		c.cancelKeepAlive()
+	}
+
+	if c.config.sshAgent != nil {
+		if err := c.config.sshAgent.Close(); err != nil {
+			return err
+		}
+	}
+
+	if c.conn != nil {
+		conn := c.conn
+		c.conn = nil
+		return conn.Close()
+	}
+
+	return nil
+}
+
+// Timeout implementation of communicator.Communicator interface
+func (c *Communicator) Timeout() time.Duration {
+	return c.connInfo.TimeoutVal
+}
+
+// ScriptPath implementation of communicator.Communicator interface
+func (c *Communicator) ScriptPath() string {
+	randLock.Lock()
+	defer randLock.Unlock()
+
+	return strings.Replace(
+		c.connInfo.ScriptPath, "%RAND%",
+		strconv.FormatInt(int64(randShared.Int31()), 10), -1)
+}
+
+// Start implementation of communicator.Communicator interface
+func (c *Communicator) Start(cmd *remote.Cmd) error {
+	cmd.Init()
+
+	session, err := c.newSession()
+	if err != nil {
+		return err
+	}
+
+	// Set up our session
+	session.Stdin = cmd.Stdin
+	session.Stdout = cmd.Stdout
+	session.Stderr = cmd.Stderr
+
+	if !c.config.noPty && c.connInfo.TargetPlatform != TargetPlatformWindows {
+		// Request a PTY
+		termModes := ssh.TerminalModes{
+			ssh.ECHO:          0,     // do not echo
+			ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
+			ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
+		}
+
+		if err := session.RequestPty("xterm", 80, 40, termModes); err != nil {
+			return err
+		}
+	}
+
+	log.Printf("[DEBUG] starting remote command: %s", cmd.Command)
+	err = session.Start(strings.TrimSpace(cmd.Command) + "\n")
+	if err != nil {
+		return err
+	}
+
+	// Start a goroutine to wait for the session to end and set the
+	// exit boolean and status.
+	go func() {
+		defer session.Close()
+
+		err := session.Wait()
+		exitStatus := 0
+		if err != nil {
+			exitErr, ok := err.(*ssh.ExitError)
+			if ok {
+				exitStatus = exitErr.ExitStatus()
+			}
+		}
+
+		cmd.SetExitStatus(exitStatus, err)
+		log.Printf("[DEBUG] remote command exited with '%d': %s", exitStatus, cmd.Command)
+	}()
+
+	return nil
+}
+
+// Upload implementation of communicator.Communicator interface
+func (c *Communicator) Upload(path string, input io.Reader) error {
+	// The target directory and file for talking the SCP protocol
+	targetDir := filepath.Dir(path)
+	targetFile := filepath.Base(path)
+
+	// On windows, filepath.Dir uses backslash separators (ie. "\tmp").
+	// This does not work when the target host is unix.  Switch to forward slash
+	// which works for unix and windows
+	targetDir = filepath.ToSlash(targetDir)
+
+	// Skip copying if we can get the file size directly from common io.Readers
+	size := int64(0)
+
+	switch src := input.(type) {
+	case *os.File:
+		fi, err := src.Stat()
+		if err == nil {
+			size = fi.Size()
+		}
+	case *bytes.Buffer:
+		size = int64(src.Len())
+	case *bytes.Reader:
+		size = int64(src.Len())
+	case *strings.Reader:
+		size = int64(src.Len())
+	}
+
+	scpFunc := func(w io.Writer, stdoutR *bufio.Reader) error {
+		return scpUploadFile(targetFile, input, w, stdoutR, size)
+	}
+
+	cmd, err := quoteShell([]string{"scp", "-vt", targetDir}, c.connInfo.TargetPlatform)
+	if err != nil {
+		return err
+	}
+	return c.scpSession(cmd, scpFunc)
+}
+
+// UploadScript implementation of communicator.Communicator interface
+func (c *Communicator) UploadScript(path string, input io.Reader) error {
+	reader := bufio.NewReader(input)
+	prefix, err := reader.Peek(2)
+	if err != nil {
+		return fmt.Errorf("Error reading script: %s", err)
+	}
+	var script bytes.Buffer
+
+	if string(prefix) != "#!" && c.connInfo.TargetPlatform != TargetPlatformWindows {
+		script.WriteString(DefaultShebang)
+	}
+	script.ReadFrom(reader)
+
+	if err := c.Upload(path, &script); err != nil {
+		return err
+	}
+	if c.connInfo.TargetPlatform != TargetPlatformWindows {
+		var stdout, stderr bytes.Buffer
+		cmd := &remote.Cmd{
+			Command: fmt.Sprintf("chmod 0777 %s", path),
+			Stdout:  &stdout,
+			Stderr:  &stderr,
+		}
+		if err := c.Start(cmd); err != nil {
+			return fmt.Errorf(
+				"Error chmodding script file to 0777 in remote "+
+					"machine: %s", err)
+		}
+
+		if err := cmd.Wait(); err != nil {
+			return fmt.Errorf(
+				"Error chmodding script file to 0777 in remote "+
+					"machine %v: %s %s", err, stdout.String(), stderr.String())
+		}
+	}
+	return nil
+}
+
+// UploadDir implementation of communicator.Communicator interface
+func (c *Communicator) UploadDir(dst string, src string) error {
+	log.Printf("[DEBUG] Uploading dir '%s' to '%s'", src, dst)
+	scpFunc := func(w io.Writer, r *bufio.Reader) error {
+		uploadEntries := func() error {
+			f, err := os.Open(src)
+			if err != nil {
+				return err
+			}
+			defer f.Close()
+
+			entries, err := f.Readdir(-1)
+			if err != nil {
+				return err
+			}
+
+			return scpUploadDir(src, entries, w, r)
+		}
+
+		if src[len(src)-1] != '/' {
+			log.Printf("[DEBUG] No trailing slash, creating the source directory name")
+			return scpUploadDirProtocol(filepath.Base(src), w, r, uploadEntries)
+		}
+		// Trailing slash, so only upload the contents
+		return uploadEntries()
+	}
+
+	cmd, err := quoteShell([]string{"scp", "-rvt", dst}, c.connInfo.TargetPlatform)
+	if err != nil {
+		return err
+	}
+	return c.scpSession(cmd, scpFunc)
+}
+
+func (c *Communicator) newSession() (session *ssh.Session, err error) {
+	log.Println("[DEBUG] opening new ssh session")
+	if c.client == nil {
+		err = errors.New("ssh client is not connected")
+	} else {
+		session, err = c.client.NewSession()
+	}
+
+	if err != nil {
+		log.Printf("[WARN] ssh session open error: '%s', attempting reconnect", err)
+		if err := c.Connect(nil); err != nil {
+			return nil, err
+		}
+
+		return c.client.NewSession()
+	}
+
+	return session, nil
+}
+
+func (c *Communicator) scpSession(scpCommand string, f func(io.Writer, *bufio.Reader) error) error {
+	session, err := c.newSession()
+	if err != nil {
+		return err
+	}
+	defer session.Close()
+
+	// Get a pipe to stdin so that we can send data down
+	stdinW, err := session.StdinPipe()
+	if err != nil {
+		return err
+	}
+
+	// We only want to close once, so we nil w after we close it,
+	// and only close in the defer if it hasn't been closed already.
+	defer func() {
+		if stdinW != nil {
+			stdinW.Close()
+		}
+	}()
+
+	// Get a pipe to stdout so that we can get responses back
+	stdoutPipe, err := session.StdoutPipe()
+	if err != nil {
+		return err
+	}
+	stdoutR := bufio.NewReader(stdoutPipe)
+
+	// Set stderr to a bytes buffer
+	stderr := new(bytes.Buffer)
+	session.Stderr = stderr
+
+	// Start the sink mode on the other side
+	// TODO(mitchellh): There are probably issues with shell escaping the path
+	log.Println("[DEBUG] Starting remote scp process: ", scpCommand)
+	if err := session.Start(scpCommand); err != nil {
+		return err
+	}
+
+	// Call our callback that executes in the context of SCP. We ignore
+	// EOF errors if they occur because it usually means that SCP prematurely
+	// ended on the other side.
+	log.Println("[DEBUG] Started SCP session, beginning transfers...")
+	if err := f(stdinW, stdoutR); err != nil && err != io.EOF {
+		return err
+	}
+
+	// Close the stdin, which sends an EOF, and then set w to nil so that
+	// our defer func doesn't close it again since that is unsafe with
+	// the Go SSH package.
+	log.Println("[DEBUG] SCP session complete, closing stdin pipe.")
+	stdinW.Close()
+	stdinW = nil
+
+	// Wait for the SCP connection to close, meaning it has consumed all
+	// our data and has completed. Or has errored.
+	log.Println("[DEBUG] Waiting for SSH session to complete.")
+	err = session.Wait()
+
+	// log any stderr before exiting on an error
+	scpErr := stderr.String()
+	if len(scpErr) > 0 {
+		log.Printf("[ERROR] scp stderr: %q", stderr)
+	}
+
+	if err != nil {
+		if exitErr, ok := err.(*ssh.ExitError); ok {
+			// Otherwise, we have an ExitErorr, meaning we can just read
+			// the exit status
+			log.Printf("[ERROR] %s", exitErr)
+
+			// If we exited with status 127, it means SCP isn't available.
+			// Return a more descriptive error for that.
+			if exitErr.ExitStatus() == 127 {
+				return errors.New(
+					"SCP failed to start. This usually means that SCP is not\n" +
+						"properly installed on the remote system.")
+			}
+		}
+
+		return err
+	}
+
+	return nil
+}
+
+// checkSCPStatus checks that a prior command sent to SCP completed
+// successfully. If it did not complete successfully, an error will
+// be returned.
+func checkSCPStatus(r *bufio.Reader) error {
+	code, err := r.ReadByte()
+	if err != nil {
+		return err
+	}
+
+	if code != 0 {
+		// Treat any non-zero (really 1 and 2) as fatal errors
+		message, _, err := r.ReadLine()
+		if err != nil {
+			return fmt.Errorf("Error reading error message: %s", err)
+		}
+
+		return errors.New(string(message))
+	}
+
+	return nil
+}
+
+var testUploadSizeHook func(size int64)
+
+func scpUploadFile(dst string, src io.Reader, w io.Writer, r *bufio.Reader, size int64) error {
+	if testUploadSizeHook != nil {
+		testUploadSizeHook(size)
+	}
+
+	if size == 0 {
+		// Create a temporary file where we can copy the contents of the src
+		// so that we can determine the length, since SCP is length-prefixed.
+		tf, err := ioutil.TempFile("", "terraform-upload")
+		if err != nil {
+			return fmt.Errorf("Error creating temporary file for upload: %s", err)
+		}
+		defer os.Remove(tf.Name())
+		defer tf.Close()
+
+		log.Println("[DEBUG] Copying input data into temporary file so we can read the length")
+		if _, err := io.Copy(tf, src); err != nil {
+			return err
+		}
+
+		// Sync the file so that the contents are definitely on disk, then
+		// read the length of it.
+		if err := tf.Sync(); err != nil {
+			return fmt.Errorf("Error creating temporary file for upload: %s", err)
+		}
+
+		// Seek the file to the beginning so we can re-read all of it
+		if _, err := tf.Seek(0, 0); err != nil {
+			return fmt.Errorf("Error creating temporary file for upload: %s", err)
+		}
+
+		fi, err := tf.Stat()
+		if err != nil {
+			return fmt.Errorf("Error creating temporary file for upload: %s", err)
+		}
+
+		src = tf
+		size = fi.Size()
+	}
+
+	// Start the protocol
+	log.Println("[DEBUG] Beginning file upload...")
+	fmt.Fprintln(w, "C0644", size, dst)
+	if err := checkSCPStatus(r); err != nil {
+		return err
+	}
+
+	if _, err := io.Copy(w, src); err != nil {
+		return err
+	}
+
+	fmt.Fprint(w, "\x00")
+	if err := checkSCPStatus(r); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func scpUploadDirProtocol(name string, w io.Writer, r *bufio.Reader, f func() error) error {
+	log.Printf("[DEBUG] SCP: starting directory upload: %s", name)
+	fmt.Fprintln(w, "D0755 0", name)
+	err := checkSCPStatus(r)
+	if err != nil {
+		return err
+	}
+
+	if err := f(); err != nil {
+		return err
+	}
+
+	fmt.Fprintln(w, "E")
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func scpUploadDir(root string, fs []os.FileInfo, w io.Writer, r *bufio.Reader) error {
+	for _, fi := range fs {
+		realPath := filepath.Join(root, fi.Name())
+
+		// Track if this is actually a symlink to a directory. If it is
+		// a symlink to a file we don't do any special behavior because uploading
+		// a file just works. If it is a directory, we need to know so we
+		// treat it as such.
+		isSymlinkToDir := false
+		if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
+			symPath, err := filepath.EvalSymlinks(realPath)
+			if err != nil {
+				return err
+			}
+
+			symFi, err := os.Lstat(symPath)
+			if err != nil {
+				return err
+			}
+
+			isSymlinkToDir = symFi.IsDir()
+		}
+
+		if !fi.IsDir() && !isSymlinkToDir {
+			// It is a regular file (or symlink to a file), just upload it
+			f, err := os.Open(realPath)
+			if err != nil {
+				return err
+			}
+
+			err = func() error {
+				defer f.Close()
+				return scpUploadFile(fi.Name(), f, w, r, fi.Size())
+			}()
+
+			if err != nil {
+				return err
+			}
+
+			continue
+		}
+
+		// It is a directory, recursively upload
+		err := scpUploadDirProtocol(fi.Name(), w, r, func() error {
+			f, err := os.Open(realPath)
+			if err != nil {
+				return err
+			}
+			defer f.Close()
+
+			entries, err := f.Readdir(-1)
+			if err != nil {
+				return err
+			}
+
+			return scpUploadDir(realPath, entries, w, r)
+		})
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// ConnectFunc is a convenience method for returning a function
+// that just uses net.Dial to communicate with the remote end that
+// is suitable for use with the SSH communicator configuration.
+func ConnectFunc(network, addr string, p *proxyInfo) func() (net.Conn, error) {
+	return func() (net.Conn, error) {
+		var c net.Conn
+		var err error
+
+		// Wrap connection to host if proxy server is configured
+		if p != nil {
+			RegisterDialerType()
+			c, err = newHttpProxyConn(p, addr)
+		} else {
+			c, err = net.DialTimeout(network, addr, 15*time.Second)
+		}
+
+		if err != nil {
+			return nil, err
+		}
+
+		if tcpConn, ok := c.(*net.TCPConn); ok {
+			tcpConn.SetKeepAlive(true)
+		}
+
+		return c, nil
+	}
+}
+
+// BastionConnectFunc is a convenience method for returning a function
+// that connects to a host over a bastion connection.
+func BastionConnectFunc(
+	bProto string,
+	bAddr string,
+	bConf *ssh.ClientConfig,
+	proto string,
+	addr string,
+	p *proxyInfo) func() (net.Conn, error) {
+	return func() (net.Conn, error) {
+		log.Printf("[DEBUG] Connecting to bastion: %s", bAddr)
+		var bastion *ssh.Client
+		var err error
+
+		// Wrap connection to bastion server if proxy server is configured
+		if p != nil {
+			var pConn net.Conn
+			var bConn ssh.Conn
+			var bChans <-chan ssh.NewChannel
+			var bReq <-chan *ssh.Request
+
+			RegisterDialerType()
+			pConn, err = newHttpProxyConn(p, bAddr)
+
+			if err != nil {
+				return nil, fmt.Errorf("Error connecting to proxy: %s", err)
+			}
+
+			bConn, bChans, bReq, err = ssh.NewClientConn(pConn, bAddr, bConf)
+
+			if err != nil {
+				return nil, fmt.Errorf("Error creating new client connection via proxy: %s", err)
+			}
+
+			bastion = ssh.NewClient(bConn, bChans, bReq)
+		} else {
+			bastion, err = ssh.Dial(bProto, bAddr, bConf)
+		}
+
+		if err != nil {
+			return nil, fmt.Errorf("Error connecting to bastion: %s", err)
+		}
+
+		log.Printf("[DEBUG] Connecting via bastion (%s) to host: %s", bAddr, addr)
+		conn, err := bastion.Dial(proto, addr)
+		if err != nil {
+			bastion.Close()
+			return nil, err
+		}
+
+		// Wrap it up so we close both things properly
+		return &bastionConn{
+			Conn:    conn,
+			Bastion: bastion,
+		}, nil
+	}
+}
+
+type bastionConn struct {
+	net.Conn
+	Bastion *ssh.Client
+}
+
+func (c *bastionConn) Close() error {
+	c.Conn.Close()
+	return c.Bastion.Close()
+}
+
+func quoteShell(args []string, targetPlatform string) (string, error) {
+	if targetPlatform == TargetPlatformUnix {
+		return shquot.POSIXShell(args), nil
+	}
+	if targetPlatform == TargetPlatformWindows {
+		return shquot.WindowsArgv(args), nil
+	}
+
+	return "", fmt.Errorf("Cannot quote shell command, target platform unknown: %s", targetPlatform)
+
+}
diff --git a/v1.5.7/internal/communicator/ssh/communicator_test.go b/v1.5.7/internal/communicator/ssh/communicator_test.go
new file mode 100644
index 0000000..eaf98ce
--- /dev/null
+++ b/v1.5.7/internal/communicator/ssh/communicator_test.go
@@ -0,0 +1,762 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build !race
+// +build !race
+
+package ssh
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/base64"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"math/rand"
+	"net"
+	"os"
+	"path/filepath"
+	"regexp"
+	"strconv"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/communicator/remote"
+	"github.com/zclconf/go-cty/cty"
+	"golang.org/x/crypto/ssh"
+)
+
+// private key for mock server
+const testServerPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA19lGVsTqIT5iiNYRgnoY1CwkbETW5cq+Rzk5v/kTlf31XpSU
+70HVWkbTERECjaYdXM2gGcbb+sxpq6GtXf1M3kVomycqhxwhPv4Cr6Xp4WT/jkFx
+9z+FFzpeodGJWjOH6L2H5uX1Cvr9EDdQp9t9/J32/qBFntY8GwoUI/y/1MSTmMiF
+tupdMODN064vd3gyMKTwrlQ8tZM6aYuyOPsutLlUY7M5x5FwMDYvnPDSeyT/Iw0z
+s3B+NCyqeeMd2T7YzQFnRATj0M7rM5LoSs7DVqVriOEABssFyLj31PboaoLhOKgc
+qoM9khkNzr7FHVvi+DhYM2jD0DwvqZLN6NmnLwIDAQABAoIBAQCGVj+kuSFOV1lT
++IclQYA6bM6uY5mroqcSBNegVxCNhWU03BxlW//BE9tA/+kq53vWylMeN9mpGZea
+riEMIh25KFGWXqXlOOioH8bkMsqA8S7sBmc7jljyv+0toQ9vCCtJ+sueNPhxQQxH
+D2YvUjfzBQ04I9+wn30BByDJ1QA/FoPsunxIOUCcRBE/7jxuLYcpR+JvEF68yYIh
+atXRld4W4in7T65YDR8jK1Uj9XAcNeDYNpT/M6oFLx1aPIlkG86aCWRO19S1jLPT
+b1ZAKHHxPMCVkSYW0RqvIgLXQOR62D0Zne6/2wtzJkk5UCjkSQ2z7ZzJpMkWgDgN
+ifCULFPBAoGBAPoMZ5q1w+zB+knXUD33n1J+niN6TZHJulpf2w5zsW+m2K6Zn62M
+MXndXlVAHtk6p02q9kxHdgov34Uo8VpuNjbS1+abGFTI8NZgFo+bsDxJdItemwC4
+KJ7L1iz39hRN/ZylMRLz5uTYRGddCkeIHhiG2h7zohH/MaYzUacXEEy3AoGBANz8
+e/msleB+iXC0cXKwds26N4hyMdAFE5qAqJXvV3S2W8JZnmU+sS7vPAWMYPlERPk1
+D8Q2eXqdPIkAWBhrx4RxD7rNc5qFNcQWEhCIxC9fccluH1y5g2M+4jpMX2CT8Uv+
+3z+NoJ5uDTXZTnLCfoZzgZ4nCZVZ+6iU5U1+YXFJAoGBANLPpIV920n/nJmmquMj
+orI1R/QXR9Cy56cMC65agezlGOfTYxk5Cfl5Ve+/2IJCfgzwJyjWUsFx7RviEeGw
+64o7JoUom1HX+5xxdHPsyZ96OoTJ5RqtKKoApnhRMamau0fWydH1yeOEJd+TRHhc
+XStGfhz8QNa1dVFvENczja1vAoGABGWhsd4VPVpHMc7lUvrf4kgKQtTC2PjA4xoc
+QJ96hf/642sVE76jl+N6tkGMzGjnVm4P2j+bOy1VvwQavKGoXqJBRd5Apppv727g
+/SM7hBXKFc/zH80xKBBgP/i1DR7kdjakCoeu4ngeGywvu2jTS6mQsqzkK+yWbUxJ
+I7mYBsECgYB/KNXlTEpXtz/kwWCHFSYA8U74l7zZbVD8ul0e56JDK+lLcJ0tJffk
+gqnBycHj6AhEycjda75cs+0zybZvN4x65KZHOGW/O/7OAWEcZP5TPb3zf9ned3Hl
+NsZoFj52ponUM6+99A2CmezFCN16c4mbA//luWF+k3VVqR6BpkrhKw==
+-----END RSA PRIVATE KEY-----`
+
+// this cert was signed by the key from testCAPublicKey
+const testServerHostCert = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgvQ3Bs1ex7277b9q6I0fNaWsVEC16f+LcT8RLPSVMEVMAAAADAQABAAABAQDX2UZWxOohPmKI1hGCehjULCRsRNblyr5HOTm/+ROV/fVelJTvQdVaRtMREQKNph1czaAZxtv6zGmroa1d/UzeRWibJyqHHCE+/gKvpenhZP+OQXH3P4UXOl6h0YlaM4fovYfm5fUK+v0QN1Cn2338nfb+oEWe1jwbChQj/L/UxJOYyIW26l0w4M3Tri93eDIwpPCuVDy1kzppi7I4+y60uVRjsznHkXAwNi+c8NJ7JP8jDTOzcH40LKp54x3ZPtjNAWdEBOPQzuszkuhKzsNWpWuI4QAGywXIuPfU9uhqguE4qByqgz2SGQ3OvsUdW+L4OFgzaMPQPC+pks3o2acvAAAAAAAAAAAAAAACAAAAB2NhLXRlc3QAAAANAAAACTEyNy4wLjAuMQAAAABag0jkAAAAAHDcHtAAAAAAAAAAAAAAAAAAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQCrozyZIhdEvalCn+eSzHH94cO9ykiywA13ntWI7mJcHBwYTeCYWG8E9zGXyp2iDOjCGudM0Tdt8o0OofKChk9Z/qiUN0G8y1kmaXBlBM3qA5R9NPpvMYMNkYLfX6ivtZCnqrsbzaoqN2Oc/7H2StHzJWh/XCGu9otQZA6vdv1oSmAsZOjw/xIGaGQqDUaLq21J280PP1qSbdJHf76iSHE+TWe3YpqV946JWM5tCh0DykZ10VznvxYpUjzhr07IN3tVKxOXbPnnU7lX6IaLIWgfzLqwSyheeux05c3JLF9iF4sFu8ou4hwQz1iuUTU1jxgwZP0w/bkXgFFs0949lW81AAABDwAAAAdzc2gtcnNhAAABAEyoiVkZ5z79nh3WSU5mU2U7e2BItnnEqsJIm9EN+35uG0yORSXmQoaa9mtli7G3r79tyqEJd/C95EdNvU/9TjaoDcbH8OHP+Ue9XSfUzBuQ6bGSXe6mlZlO7QJ1cIyWphFP3MkrweDSiJ+SpeXzLzZkiJ7zKv5czhBEyG/MujFgvikotL+eUNG42y2cgsesXSjENSBS3l11q55a+RM2QKt3W32im8CsSxrH6Mz6p4JXQNgsVvZRknLxNlWXULFB2HLTunPKzJNMTf6xZf66oivSBAXVIdNKhlVpAQ3dT/dW5K6J4aQF/hjWByyLprFwZ16cPDqvtalnTCpbRYelNbw=`
+
+const testCAPublicKey = `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrozyZIhdEvalCn+eSzHH94cO9ykiywA13ntWI7mJcHBwYTeCYWG8E9zGXyp2iDOjCGudM0Tdt8o0OofKChk9Z/qiUN0G8y1kmaXBlBM3qA5R9NPpvMYMNkYLfX6ivtZCnqrsbzaoqN2Oc/7H2StHzJWh/XCGu9otQZA6vdv1oSmAsZOjw/xIGaGQqDUaLq21J280PP1qSbdJHf76iSHE+TWe3YpqV946JWM5tCh0DykZ10VznvxYpUjzhr07IN3tVKxOXbPnnU7lX6IaLIWgfzLqwSyheeux05c3JLF9iF4sFu8ou4hwQz1iuUTU1jxgwZP0w/bkXgFFs0949lW81`
+
+func newMockLineServer(t *testing.T, signer ssh.Signer, pubKey string) string {
+	serverConfig := &ssh.ServerConfig{
+		PasswordCallback:  acceptUserPass("user", "pass"),
+		PublicKeyCallback: acceptPublicKey(pubKey),
+	}
+
+	var err error
+	if signer == nil {
+		signer, err = ssh.ParsePrivateKey([]byte(testServerPrivateKey))
+		if err != nil {
+			t.Fatalf("unable to parse private key: %s", err)
+		}
+	}
+	serverConfig.AddHostKey(signer)
+
+	l, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("Unable to listen for connection: %s", err)
+	}
+
+	go func() {
+		defer l.Close()
+		c, err := l.Accept()
+		if err != nil {
+			t.Errorf("Unable to accept incoming connection: %s", err)
+		}
+		defer c.Close()
+		conn, chans, _, err := ssh.NewServerConn(c, serverConfig)
+		if err != nil {
+			t.Logf("Handshaking error: %v", err)
+		}
+		t.Log("Accepted SSH connection")
+
+		for newChannel := range chans {
+			channel, requests, err := newChannel.Accept()
+			if err != nil {
+				t.Errorf("Unable to accept channel.")
+			}
+			t.Log("Accepted channel")
+
+			go func(in <-chan *ssh.Request) {
+				defer channel.Close()
+				for req := range in {
+					// since this channel's requests are serviced serially,
+					// this will block keepalive probes, and can simulate a
+					// hung connection.
+					if bytes.Contains(req.Payload, []byte("sleep")) {
+						time.Sleep(time.Second)
+					}
+
+					if req.WantReply {
+						req.Reply(true, nil)
+					}
+				}
+			}(requests)
+		}
+		conn.Close()
+	}()
+
+	return l.Addr().String()
+}
+
+func TestNew_Invalid(t *testing.T) {
+	address := newMockLineServer(t, nil, testClientPublicKey)
+	parts := strings.Split(address, ":")
+
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":     cty.StringVal("ssh"),
+		"user":     cty.StringVal("user"),
+		"password": cty.StringVal("i-am-invalid"),
+		"host":     cty.StringVal(parts[0]),
+		"port":     cty.StringVal(parts[1]),
+		"timeout":  cty.StringVal("30s"),
+	})
+
+	c, err := New(v)
+	if err != nil {
+		t.Fatalf("error creating communicator: %s", err)
+	}
+
+	err = c.Connect(nil)
+	if err == nil {
+		t.Fatal("should have had an error connecting")
+	}
+}
+
+func TestNew_InvalidHost(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":     cty.StringVal("ssh"),
+		"user":     cty.StringVal("user"),
+		"password": cty.StringVal("i-am-invalid"),
+		"port":     cty.StringVal("22"),
+		"timeout":  cty.StringVal("30s"),
+	})
+
+	_, err := New(v)
+	if err == nil {
+		t.Fatal("should have had an error creating communicator")
+	}
+}
+
+func TestStart(t *testing.T) {
+	address := newMockLineServer(t, nil, testClientPublicKey)
+	parts := strings.Split(address, ":")
+
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":     cty.StringVal("ssh"),
+		"user":     cty.StringVal("user"),
+		"password": cty.StringVal("pass"),
+		"host":     cty.StringVal(parts[0]),
+		"port":     cty.StringVal(parts[1]),
+		"timeout":  cty.StringVal("30s"),
+	})
+
+	c, err := New(v)
+	if err != nil {
+		t.Fatalf("error creating communicator: %s", err)
+	}
+
+	var cmd remote.Cmd
+	stdout := new(bytes.Buffer)
+	cmd.Command = "echo foo"
+	cmd.Stdout = stdout
+
+	err = c.Start(&cmd)
+	if err != nil {
+		t.Fatalf("error executing remote command: %s", err)
+	}
+}
+
+// TestKeepAlives verifies that the keepalive messages don't interfere with
+// normal operation of the client.
+func TestKeepAlives(t *testing.T) {
+	ivl := keepAliveInterval
+	keepAliveInterval = 250 * time.Millisecond
+	defer func() { keepAliveInterval = ivl }()
+
+	address := newMockLineServer(t, nil, testClientPublicKey)
+	parts := strings.Split(address, ":")
+
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":     cty.StringVal("ssh"),
+		"user":     cty.StringVal("user"),
+		"password": cty.StringVal("pass"),
+		"host":     cty.StringVal(parts[0]),
+		"port":     cty.StringVal(parts[1]),
+	})
+
+	c, err := New(v)
+	if err != nil {
+		t.Fatalf("error creating communicator: %s", err)
+	}
+
+	if err := c.Connect(nil); err != nil {
+		t.Fatal(err)
+	}
+
+	var cmd remote.Cmd
+	stdout := new(bytes.Buffer)
+	cmd.Command = "sleep"
+	cmd.Stdout = stdout
+
+	// wait a bit before executing the command, so that at least 1 keepalive is sent
+	time.Sleep(500 * time.Millisecond)
+
+	err = c.Start(&cmd)
+	if err != nil {
+		t.Fatalf("error executing remote command: %s", err)
+	}
+}
+
+// TestDeadConnection verifies that failed keepalive messages will eventually
+// kill the connection.
+func TestFailedKeepAlives(t *testing.T) {
+	ivl := keepAliveInterval
+	del := maxKeepAliveDelay
+	maxKeepAliveDelay = 500 * time.Millisecond
+	keepAliveInterval = 250 * time.Millisecond
+	defer func() {
+		keepAliveInterval = ivl
+		maxKeepAliveDelay = del
+	}()
+
+	address := newMockLineServer(t, nil, testClientPublicKey)
+	parts := strings.Split(address, ":")
+
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":     cty.StringVal("ssh"),
+		"user":     cty.StringVal("user"),
+		"password": cty.StringVal("pass"),
+		"host":     cty.StringVal(parts[0]),
+		"port":     cty.StringVal(parts[1]),
+		"timeout":  cty.StringVal("30s"),
+	})
+
+	c, err := New(v)
+	if err != nil {
+		t.Fatalf("error creating communicator: %s", err)
+	}
+
+	if err := c.Connect(nil); err != nil {
+		t.Fatal(err)
+	}
+	var cmd remote.Cmd
+	stdout := new(bytes.Buffer)
+	cmd.Command = "sleep"
+	cmd.Stdout = stdout
+
+	err = c.Start(&cmd)
+	if err == nil {
+		t.Fatal("expected connection error")
+	}
+}
+
+func TestLostConnection(t *testing.T) {
+	address := newMockLineServer(t, nil, testClientPublicKey)
+	parts := strings.Split(address, ":")
+
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":     cty.StringVal("ssh"),
+		"user":     cty.StringVal("user"),
+		"password": cty.StringVal("pass"),
+		"host":     cty.StringVal(parts[0]),
+		"port":     cty.StringVal(parts[1]),
+		"timeout":  cty.StringVal("30s"),
+	})
+
+	c, err := New(v)
+	if err != nil {
+		t.Fatalf("error creating communicator: %s", err)
+	}
+
+	var cmd remote.Cmd
+	stdout := new(bytes.Buffer)
+	cmd.Command = "echo foo"
+	cmd.Stdout = stdout
+
+	err = c.Start(&cmd)
+	if err != nil {
+		t.Fatalf("error executing remote command: %s", err)
+	}
+
+	// The test server can't execute anything, so Wait will block, unless
+	// there's an error.  Disconnect the communicator transport, to cause the
+	// command to fail.
+	go func() {
+		time.Sleep(100 * time.Millisecond)
+		c.Disconnect()
+	}()
+
+	err = cmd.Wait()
+	if err == nil {
+		t.Fatal("expected communicator error")
+	}
+}
+
+func TestHostKey(t *testing.T) {
+	// get the server's public key
+	signer, err := ssh.ParsePrivateKey([]byte(testServerPrivateKey))
+	if err != nil {
+		t.Fatalf("unable to parse private key: %v", err)
+	}
+	pubKey := fmt.Sprintf("ssh-rsa %s", base64.StdEncoding.EncodeToString(signer.PublicKey().Marshal()))
+
+	address := newMockLineServer(t, nil, testClientPublicKey)
+	host, p, _ := net.SplitHostPort(address)
+	port, _ := strconv.Atoi(p)
+
+	connInfo := &connectionInfo{
+		User:     "user",
+		Password: "pass",
+		Host:     host,
+		HostKey:  pubKey,
+		Port:     uint16(port),
+		Timeout:  "30s",
+	}
+
+	cfg, err := prepareSSHConfig(connInfo)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	c := &Communicator{
+		connInfo: connInfo,
+		config:   cfg,
+	}
+
+	var cmd remote.Cmd
+	stdout := new(bytes.Buffer)
+	cmd.Command = "echo foo"
+	cmd.Stdout = stdout
+
+	if err := c.Start(&cmd); err != nil {
+		t.Fatal(err)
+	}
+	if err := c.Disconnect(); err != nil {
+		t.Fatal(err)
+	}
+
+	// now check with the wrong HostKey
+	address = newMockLineServer(t, nil, testClientPublicKey)
+	_, p, _ = net.SplitHostPort(address)
+	port, _ = strconv.Atoi(p)
+
+	connInfo.HostKey = testClientPublicKey
+	connInfo.Port = uint16(port)
+
+	cfg, err = prepareSSHConfig(connInfo)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	c = &Communicator{
+		connInfo: connInfo,
+		config:   cfg,
+	}
+
+	err = c.Start(&cmd)
+	if err == nil || !strings.Contains(err.Error(), "mismatch") {
+		t.Fatalf("expected host key mismatch, got error:%v", err)
+	}
+}
+
+func TestHostCert(t *testing.T) {
+	pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(testServerHostCert))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	signer, err := ssh.ParsePrivateKey([]byte(testServerPrivateKey))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	signer, err = ssh.NewCertSigner(pk.(*ssh.Certificate), signer)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	address := newMockLineServer(t, signer, testClientPublicKey)
+	host, p, _ := net.SplitHostPort(address)
+	port, _ := strconv.Atoi(p)
+
+	connInfo := &connectionInfo{
+		User:     "user",
+		Password: "pass",
+		Host:     host,
+		HostKey:  testCAPublicKey,
+		Port:     uint16(port),
+		Timeout:  "30s",
+	}
+
+	cfg, err := prepareSSHConfig(connInfo)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	c := &Communicator{
+		connInfo: connInfo,
+		config:   cfg,
+	}
+
+	var cmd remote.Cmd
+	stdout := new(bytes.Buffer)
+	cmd.Command = "echo foo"
+	cmd.Stdout = stdout
+
+	if err := c.Start(&cmd); err != nil {
+		t.Fatal(err)
+	}
+	if err := c.Disconnect(); err != nil {
+		t.Fatal(err)
+	}
+
+	// now check with the wrong HostKey
+	address = newMockLineServer(t, signer, testClientPublicKey)
+	_, p, _ = net.SplitHostPort(address)
+	port, _ = strconv.Atoi(p)
+
+	connInfo.HostKey = testClientPublicKey
+	connInfo.Port = uint16(port)
+
+	cfg, err = prepareSSHConfig(connInfo)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	c = &Communicator{
+		connInfo: connInfo,
+		config:   cfg,
+	}
+
+	err = c.Start(&cmd)
+	if err == nil || !strings.Contains(err.Error(), "authorities") {
+		t.Fatalf("expected host key mismatch, got error:%v", err)
+	}
+}
+
+const SERVER_PEM = `-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA8CkDr7uxCFt6lQUVwS8NyPO+fQNxORoGnMnN/XhVJZvpqyKR
+Uji9R0d8D66bYxUUsabXjP2y4HTVzbZtnvXFZZshk0cOtJjjekpYJaLK2esPR/iX
+wvSltNkrDQDPN/RmgEEMIevW8AgrPsqrnybFHxTpd7rEUHXBOe4nMNRIg3XHykB6
+jZk8q5bBPUe3I/f0DK5TJEBpTc6dO3P/j93u55VUqr39/SPRHnld2mCw+c8v6UOh
+sssO/DIZFPScD3DYqsk2N+/nz9zXfcOTdWGhawgxuIo1DTokrNQbG3pDrLqcWgqj
+13vqJFCmRA0O2CQIwJePd6+Np/XO3Uh/KL6FlQIDAQABAoIBAQCmvQMXNmvCDqk7
+30zsVDvw4fHGH+azK3Od1aqTqcEMHISOUbCtckFPxLzIsoSltRQqB1kuRVG07skm
+Stsu+xny4lLcSwBVuLRuykEK2EyYIc/5Owo6y9pkhkaSf5ZfFes4bnD6+B/BhRpp
+PRMMq0E+xCkX/G6iIi9mhgdlqm0x/vKtjzQeeshw9+gRcRLUpX+UeKFKXMXcDayx
+qekr1bAaQKNBhTK+CbZjcqzG4f+BXVGRTZ9nsPAV+yTnWUCU0TghwPmtthHbebqa
+9hlkum7qik/bQj/tjJ8/b0vTfHQSVxhtPG/ZV2Tn9ZuL/vrkYqeyMU8XkJ/uaEvH
+WPyOcB4BAoGBAP5o5JSEtPog+U3JFrLNSRjz5ofZNVkJzice+0XyqlzJDHhX5tF8
+mriYQZLLXYhckBm4IdkhTn/dVbXNQTzyy2WVuO5nU8bkCMvGL9CGpW4YGqwGf7NX
+e4H3emtRjLv8VZpUHe/RUUDhmYvMSt1qmXuskfpROuGfLhQBUd6A4J+BAoGBAPGp
+UcMKjrxZ5qjYU6DLgS+xeca4Eu70HgdbSQbRo45WubXjyXvTRFij36DrpxJWf1D7
+lIsyBifoTra/lAuC1NQXGYWjTCdk2ey8Ll5qOgiXvE6lINHABr+U/Z90/g6LuML2
+VzaZbq/QLcT3yVsdyTogKckzCaKsCpusyHE1CXAVAoGAd6kMglKc8N0bhZukgnsN
++5+UeacPcY6sGTh4RWErAjNKGzx1A2lROKvcg9gFaULoQECcIw2IZ5nKW5VsLueg
+BWrTrcaJ4A2XmYjhKnp6SvspaGoyHD90hx/Iw7t6r1yzQsB3yDmytwqldtyjBdvC
+zynPC2azhDWjraMlR7tka4ECgYAxwvLiHa9sm3qCtCDsUFtmrb3srITBjaUNUL/F
+1q8+JR+Sk7gudj9xnTT0VvINNaB71YIt83wPBagHu4VJpYQbtDH+MbUBu6OgOtO1
+f1w53rzY2OncJxV8p7pd9mJGLoE6LC2jQY7oRw7Vq0xcJdME1BCmrIrEY3a/vaF8
+pjYuTQKBgQCIOH23Xita8KmhH0NdlWxZfcQt1j3AnOcKe6UyN4BsF8hqS7eTA52s
+WjG5X2IBl7gs1eMM1qkqR8npS9nwfO/pBmZPwjiZoilypXxWj+c+P3vwre2yija4
+bXgFVj4KFBwhr1+8KcobxC0SAPEouMvSkxzjjw+gnebozUtPlud9jA==
+-----END RSA PRIVATE KEY-----
+`
+const CLIENT_CERT_SIGNED_BY_SERVER = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgbMDNUn4M2TtzrSH7MOT2QsvLzZWjehJ5TYrBOp9p+lwAAAADAQABAAABAQCyu57E7zIWRyEWuaiOiikOSZKFjbwLkpE9fboFfLLsNUJj4zw+5bZUJtzWK8roPjgL8s1oPncro5wuTtI2Nu4fkpeFK0Hb33o6Eyksuj4Om4+6Uemn1QEcb0bZqK8Zyg9Dg9deP7LeE0v78b5/jZafFgwxv+/sMhM0PRD34NCDYcYmkkHlvQtQWFAdbPXCgghObedZyYdoqZVuhTsiPMWtQS/cc9M4tv6mPOuQlhZt3R/Oh/kwUyu45oGRb5bhO4JicozFS3oeClpU+UMbgslkzApJqxZBWN7+PDFSZhKk2GslyeyP4sH3E30Z00yVi/lQYgmQsB+Hg6ClemNQMNu/AAAAAAAAAAAAAAACAAAABHVzZXIAAAAIAAAABHVzZXIAAAAAWzBjXAAAAAB/POfPAAAAAAAAAAAAAAAAAAABFwAAAAdzc2gtcnNhAAAAAwEAAQAAAQEA8CkDr7uxCFt6lQUVwS8NyPO+fQNxORoGnMnN/XhVJZvpqyKRUji9R0d8D66bYxUUsabXjP2y4HTVzbZtnvXFZZshk0cOtJjjekpYJaLK2esPR/iXwvSltNkrDQDPN/RmgEEMIevW8AgrPsqrnybFHxTpd7rEUHXBOe4nMNRIg3XHykB6jZk8q5bBPUe3I/f0DK5TJEBpTc6dO3P/j93u55VUqr39/SPRHnld2mCw+c8v6UOhsssO/DIZFPScD3DYqsk2N+/nz9zXfcOTdWGhawgxuIo1DTokrNQbG3pDrLqcWgqj13vqJFCmRA0O2CQIwJePd6+Np/XO3Uh/KL6FlQAAAQ8AAAAHc3NoLXJzYQAAAQC6sKEQHyl954BQn2BXuTgOB3NkENBxN7SD8ZaS8PNkDESytLjSIqrzoE6m7xuzprA+G23XRrCY/um3UvM7+7+zbwig2NIBbGbp3QFliQHegQKW6hTZP09jAQZk5jRrrEr/QT/s+gtHPmjxJK7XOQYxhInDKj+aJg62ExcwpQlP/0ATKNOIkdzTzzq916p0UOnnVaaPMKibh5Lv69GafIhKJRZSuuLN9fvs1G1RuUbxn/BNSeoRCr54L++Ztg09fJxunoyELs8mwgzCgB3pdZoUR2Z6ak05W4mvH3lkSz2BKUrlwxI6mterxhJy1GuN1K/zBG0gEMl2UTLajGK3qKM8 itbitloaner@MacBook-Pro-4.fios-router.home`
+const CLIENT_PEM = `-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAsruexO8yFkchFrmojoopDkmShY28C5KRPX26BXyy7DVCY+M8
+PuW2VCbc1ivK6D44C/LNaD53K6OcLk7SNjbuH5KXhStB2996OhMpLLo+DpuPulHp
+p9UBHG9G2aivGcoPQ4PXXj+y3hNL+/G+f42WnxYMMb/v7DITND0Q9+DQg2HGJpJB
+5b0LUFhQHWz1woIITm3nWcmHaKmVboU7IjzFrUEv3HPTOLb+pjzrkJYWbd0fzof5
+MFMruOaBkW+W4TuCYnKMxUt6HgpaVPlDG4LJZMwKSasWQVje/jwxUmYSpNhrJcns
+j+LB9xN9GdNMlYv5UGIJkLAfh4OgpXpjUDDbvwIDAQABAoIBAEu2ctFVyk/pnbi0
+uRR4rl+hBvKQUeJNGj2ELvL4Ggs5nIAX2IOEZ7JKLC6FqpSrFq7pEd5g57aSvixX
+s3DH4CN7w7fj1ShBCNPlHgIWewdRGpeA74vrDWdwNAEsFdDE6aZeCTOhpDGy1vNJ
+OrtpzS5i9pN0jTvvEneEjtWSZIHiiVlN+0hsFaiwZ6KXON+sDccZPmnP6Fzwj5Rc
+WS0dKSwnxnx0otWgwWFs8nr306nSeMsNmQkHsS9lz4DEVpp9owdzrX1JmbQvNYAV
+ohmB3ET4JYFgerqPXJfed9poueGuWCP6MYhsjNeHN35QhofxdO5/0i3JlZfqwZei
+tNq/0oECgYEA6SqjRqDiIp3ajwyB7Wf0cIQG/P6JZDyN1jl//htgniliIH5UP1Tm
+uAMG5MincV6X9lOyXyh6Yofu5+NR0yt9SqbDZVJ3ZCxKTun7pxJvQFd7wl5bMkiJ
+qVfS08k6gQHHDoO+eel+DtpIfWc+e3tvX0aihSU0GZEMqDXYkkphLGECgYEAxDxb
++JwJ3N5UEjjkuvFBpuJnmjIaN9HvQkTv3inlx1gLE4iWBZXXsu4aWF8MCUeAAZyP
+42hQDSkCYX/A22tYCEn/jfrU6A+6rkWBTjdUlYLvlSkhosSnO+117WEItb5cUE95
+hF4UY7LNs1AsDkV4WE87f/EjpxSwUAjB2Lfd/B8CgYAJ/JiHsuZcozQ0Qk3iVDyF
+ATKnbWOHFozgqw/PW27U92LLj32eRM2o/gAylmGNmoaZt1YBe2NaiwXxiqv7hnZU
+VzYxRcn1UWxRWvY7Xq/DKrwTRCVVzwOObEOMbKcD1YaoGX50DEso6bKHJH/pnAzW
+INlfKIvFuI+5OK0w/tyQoQKBgQCf/jpaOxaLfrV62eobRQJrByLDBGB97GsvU7di
+IjTWz8DQH0d5rE7d8uWF8ZCFrEcAiV6DYZQK9smbJqbd/uoacAKtBro5rkFdPwwK
+8m/DKqsdqRhkdgOHh7bjYH7Sdy8ax4Fi27WyB6FQtmgFBrz0+zyetsODwQlzZ4Bs
+qpSRrwKBgQC0vWHrY5aGIdF+b8EpP0/SSLLALpMySHyWhDyxYcPqdhszYbjDcavv
+xrrLXNUD2duBHKPVYE+7uVoDkpZXLUQ4x8argo/IwQM6Kh2ma1y83TYMT6XhL1+B
+5UPcl6RXZBCkiU7nFIG6/0XKFqVWc3fU8e09X+iJwXIJ5Jatywtg+g==
+-----END RSA PRIVATE KEY-----
+`
+
+func TestCertificateBasedAuth(t *testing.T) {
+	signer, err := ssh.ParsePrivateKey([]byte(SERVER_PEM))
+	if err != nil {
+		t.Fatalf("unable to parse private key: %v", err)
+	}
+	address := newMockLineServer(t, signer, CLIENT_CERT_SIGNED_BY_SERVER)
+	host, p, _ := net.SplitHostPort(address)
+	port, _ := strconv.Atoi(p)
+
+	connInfo := &connectionInfo{
+		User:        "user",
+		Host:        host,
+		PrivateKey:  CLIENT_PEM,
+		Certificate: CLIENT_CERT_SIGNED_BY_SERVER,
+		Port:        uint16(port),
+		Timeout:     "30s",
+	}
+
+	cfg, err := prepareSSHConfig(connInfo)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	c := &Communicator{
+		connInfo: connInfo,
+		config:   cfg,
+	}
+
+	var cmd remote.Cmd
+	stdout := new(bytes.Buffer)
+	cmd.Command = "echo foo"
+	cmd.Stdout = stdout
+
+	if err := c.Start(&cmd); err != nil {
+		t.Fatal(err)
+	}
+	if err := c.Disconnect(); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestAccUploadFile(t *testing.T) {
+	// use the local ssh server and scp binary to check uploads
+	if ok := os.Getenv("SSH_UPLOAD_TEST"); ok == "" {
+		t.Log("Skipping Upload Acceptance without SSH_UPLOAD_TEST set")
+		t.Skip()
+	}
+
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":    cty.StringVal("ssh"),
+		"user":    cty.StringVal(os.Getenv("USER")),
+		"host":    cty.StringVal("127.0.0.1"),
+		"port":    cty.StringVal("22"),
+		"timeout": cty.StringVal("30s"),
+	})
+
+	c, err := New(v)
+	if err != nil {
+		t.Fatalf("error creating communicator: %s", err)
+	}
+
+	tmpDir := t.TempDir()
+	source, err := os.CreateTemp(tmpDir, "tempfile.in")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	content := "this is the file content"
+	if _, err := source.WriteString(content); err != nil {
+		t.Fatal(err)
+	}
+	source.Seek(0, io.SeekStart)
+
+	tmpFile := filepath.Join(tmpDir, "tempFile.out")
+
+	testUploadSizeHook = func(size int64) {
+		if size != int64(len(content)) {
+			t.Errorf("expected %d bytes, got %d\n", len(content), size)
+		}
+	}
+	defer func() {
+		testUploadSizeHook = nil
+	}()
+
+	err = c.Upload(tmpFile, source)
+	if err != nil {
+		t.Fatalf("error uploading file: %s", err)
+	}
+
+	data, err := ioutil.ReadFile(tmpFile)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if string(data) != content {
+		t.Fatalf("bad: %s", data)
+	}
+}
+
+func TestAccHugeUploadFile(t *testing.T) {
+	// use the local ssh server and scp binary to check uploads
+	if ok := os.Getenv("SSH_UPLOAD_TEST"); ok == "" {
+		t.Log("Skipping Upload Acceptance without SSH_UPLOAD_TEST set")
+		t.Skip()
+	}
+
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":    cty.StringVal("ssh"),
+		"host":    cty.StringVal("127.0.0.1"),
+		"user":    cty.StringVal(os.Getenv("USER")),
+		"port":    cty.StringVal("22"),
+		"timeout": cty.StringVal("30s"),
+	})
+
+	c, err := New(v)
+	if err != nil {
+		t.Fatalf("error creating communicator: %s", err)
+	}
+
+	// copy 4GB of data, random to prevent compression.
+	size := int64(1 << 32)
+	source := io.LimitReader(rand.New(rand.NewSource(0)), size)
+
+	dest, err := ioutil.TempFile("", "communicator")
+	if err != nil {
+		t.Fatal(err)
+	}
+	destName := dest.Name()
+	dest.Close()
+	defer os.Remove(destName)
+
+	t.Log("Uploading to", destName)
+
+	// bypass the Upload method so we can directly supply the file size
+	// preventing the extra copy of the huge file.
+	targetDir := filepath.Dir(destName)
+	targetFile := filepath.Base(destName)
+
+	scpFunc := func(w io.Writer, stdoutR *bufio.Reader) error {
+		return scpUploadFile(targetFile, source, w, stdoutR, size)
+	}
+
+	cmd, err := quoteShell([]string{"scp", "-vt", targetDir}, c.connInfo.TargetPlatform)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = c.scpSession(cmd, scpFunc)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// check the final file size
+	fs, err := os.Stat(destName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if fs.Size() != size {
+		t.Fatalf("expected file size of %d, got %d", size, fs.Size())
+	}
+}
+
+func TestScriptPath(t *testing.T) {
+	cases := []struct {
+		Input   string
+		Pattern string
+	}{
+		{
+			"/tmp/script.sh",
+			`^/tmp/script\.sh$`,
+		},
+		{
+			"/tmp/script_%RAND%.sh",
+			`^/tmp/script_(\d+)\.sh$`,
+		},
+	}
+
+	for _, tc := range cases {
+		v := cty.ObjectVal(map[string]cty.Value{
+			"type":        cty.StringVal("ssh"),
+			"host":        cty.StringVal("127.0.0.1"),
+			"script_path": cty.StringVal(tc.Input),
+		})
+
+		comm, err := New(v)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		output := comm.ScriptPath()
+
+		match, err := regexp.Match(tc.Pattern, []byte(output))
+		if err != nil {
+			t.Fatalf("bad: %s\n\nerr: %s", tc.Input, err)
+		}
+		if !match {
+			t.Fatalf("bad: %s\n\n%s", tc.Input, output)
+		}
+	}
+}
+
+func TestScriptPath_randSeed(t *testing.T) {
+	// Pre GH-4186 fix, this value was the deterministic start the pseudorandom
+	// chain of unseeded math/rand values for Int31().
+	staticSeedPath := "/tmp/terraform_1298498081.sh"
+	c, err := New(cty.ObjectVal(map[string]cty.Value{
+		"type": cty.StringVal("ssh"),
+		"host": cty.StringVal("127.0.0.1"),
+	}))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	path := c.ScriptPath()
+	if path == staticSeedPath {
+		t.Fatalf("rand not seeded! got: %s", path)
+	}
+}
+
+var testClientPublicKey = `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDE6A1c4n+OtEPEFlNKTZf2i03L3NylSYmvmJ8OLmzLuPZmJBJt4G3VZ/60s1aKzwLKrTq20S+ONG4zvnK5zIPoauoNNdUJKbg944hB4OE+HDbrBhk7SH+YWCsCILBoSXwAVdUEic6FWf/SeqBSmTBySHvpuNOw16J+SK6Ardx8k64F2tRkZuC6AmOZijgKa/sQKjWAIVPk34ECM6OLfPc3kKUEfkdpYLvuMfuRMfSTlxn5lFC0b0SovK9aWfNMBH9iXLQkieQ5rXoyzUC7mwgnASgl8cqw1UrToiUuhvneduXBhbQfmC/Upv+tL6dSSk+0DlgVKEHuJmc8s8+/qpdL`
+
+func acceptUserPass(goodUser, goodPass string) func(ssh.ConnMetadata, []byte) (*ssh.Permissions, error) {
+	return func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
+		if c.User() == goodUser && string(pass) == goodPass {
+			return nil, nil
+		}
+		return nil, fmt.Errorf("password rejected for %q", c.User())
+	}
+}
+
+func acceptPublicKey(keystr string) func(ssh.ConnMetadata, ssh.PublicKey) (*ssh.Permissions, error) {
+	return func(_ ssh.ConnMetadata, inkey ssh.PublicKey) (*ssh.Permissions, error) {
+		goodkey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(keystr))
+		if err != nil {
+			return nil, fmt.Errorf("error parsing key: %v", err)
+		}
+
+		if bytes.Equal(inkey.Marshal(), goodkey.Marshal()) {
+			return nil, nil
+		}
+
+		return nil, fmt.Errorf("public key rejected")
+	}
+}
diff --git a/v1.5.7/internal/communicator/ssh/http_proxy.go b/v1.5.7/internal/communicator/ssh/http_proxy.go
new file mode 100644
index 0000000..1aaaa3f
--- /dev/null
+++ b/v1.5.7/internal/communicator/ssh/http_proxy.go
@@ -0,0 +1,155 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package ssh
+
+import (
+	"bufio"
+	"fmt"
+	"net"
+	"net/http"
+	"net/url"
+	"time"
+
+	"golang.org/x/net/proxy"
+)
+
+// Dialer implements for SSH over HTTP Proxy.
+type proxyDialer struct {
+	proxy proxyInfo
+	// forwarding Dialer
+	forward proxy.Dialer
+}
+
+type proxyInfo struct {
+	// HTTP Proxy host or host:port
+	host string
+	// HTTP Proxy scheme
+	scheme string
+	// An immutable encapsulation of username and password details for a URL
+	userInfo *url.Userinfo
+}
+
+func newProxyInfo(host, scheme, username, password string) *proxyInfo {
+	p := &proxyInfo{
+		host:   host,
+		scheme: scheme,
+	}
+
+	p.userInfo = url.UserPassword(username, password)
+
+	if p.scheme == "" {
+		p.scheme = "http"
+	}
+
+	return p
+}
+
+func (p *proxyInfo) url() *url.URL {
+	return &url.URL{
+		Scheme: p.scheme,
+		User:   p.userInfo,
+		Host:   p.host,
+	}
+}
+
+func (p *proxyDialer) Dial(network, addr string) (net.Conn, error) {
+	// Dial the proxy host
+	c, err := p.forward.Dial(network, p.proxy.host)
+
+	if err != nil {
+		return nil, err
+	}
+
+	err = c.SetDeadline(time.Now().Add(15 * time.Second))
+	if err != nil {
+		return nil, err
+	}
+
+	// Generate request URL to host accessed through the proxy
+	reqUrl := &url.URL{
+		Scheme: "",
+		Host:   addr,
+	}
+
+	// Create a request object using the CONNECT method to instruct the proxy server to tunnel a protocol other than HTTP.
+	req, err := http.NewRequest("CONNECT", reqUrl.String(), nil)
+	if err != nil {
+		c.Close()
+		return nil, err
+	}
+
+	// If http proxy requires authentication, configure settings for basic authentication.
+	if p.proxy.userInfo.String() != "" {
+		username := p.proxy.userInfo.Username()
+		password, _ := p.proxy.userInfo.Password()
+		req.SetBasicAuth(username, password)
+		req.Header.Add("Proxy-Authorization", req.Header.Get("Authorization"))
+	}
+
+	// Do not close the connection after sending this request and reading its response.
+	req.Close = false
+
+	// Writes the request in the form expected by an HTTP proxy.
+	err = req.Write(c)
+	if err != nil {
+		c.Close()
+		return nil, err
+	}
+
+	res, err := http.ReadResponse(bufio.NewReader(c), req)
+
+	if err != nil {
+		res.Body.Close()
+		c.Close()
+		return nil, err
+	}
+
+	res.Body.Close()
+
+	if res.StatusCode != http.StatusOK {
+		c.Close()
+		return nil, fmt.Errorf("Connection Error: StatusCode: %d", res.StatusCode)
+	}
+
+	return c, nil
+}
+
+// NewHttpProxyDialer generate Http Proxy Dialer
+func newHttpProxyDialer(u *url.URL, forward proxy.Dialer) (proxy.Dialer, error) {
+	var proxyUserName, proxyPassword string
+	if u.User != nil {
+		proxyUserName = u.User.Username()
+		proxyPassword, _ = u.User.Password()
+	}
+
+	pd := &proxyDialer{
+		proxy:   *newProxyInfo(u.Host, u.Scheme, proxyUserName, proxyPassword),
+		forward: forward,
+	}
+
+	return pd, nil
+}
+
+// RegisterDialerType register schemes used by `proxy.FromURL`
+func RegisterDialerType() {
+	proxy.RegisterDialerType("http", newHttpProxyDialer)
+	proxy.RegisterDialerType("https", newHttpProxyDialer)
+}
+
+// NewHttpProxyConn create a connection to connect through the proxy server.
+func newHttpProxyConn(p *proxyInfo, targetAddr string) (net.Conn, error) {
+	pd, err := proxy.FromURL(p.url(), proxy.Direct)
+
+	if err != nil {
+		return nil, err
+	}
+
+	proxyConn, err := pd.Dial("tcp", targetAddr)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return proxyConn, err
+}
diff --git a/v1.5.7/internal/communicator/ssh/password.go b/v1.5.7/internal/communicator/ssh/password.go
new file mode 100644
index 0000000..fee2416
--- /dev/null
+++ b/v1.5.7/internal/communicator/ssh/password.go
@@ -0,0 +1,31 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package ssh
+
+import (
+	"log"
+
+	"golang.org/x/crypto/ssh"
+)
+
+// An implementation of ssh.KeyboardInteractiveChallenge that simply sends
+// back the password for all questions. The questions are logged.
+func PasswordKeyboardInteractive(password string) ssh.KeyboardInteractiveChallenge {
+	return func(user, instruction string, questions []string, echos []bool) ([]string, error) {
+		log.Printf("Keyboard interactive challenge: ")
+		log.Printf("-- User: %s", user)
+		log.Printf("-- Instructions: %s", instruction)
+		for i, question := range questions {
+			log.Printf("-- Question %d: %s", i+1, question)
+		}
+
+		// Just send the password back for all questions
+		answers := make([]string, len(questions))
+		for i := range answers {
+			answers[i] = string(password)
+		}
+
+		return answers, nil
+	}
+}
diff --git a/v1.5.7/internal/communicator/ssh/password_test.go b/v1.5.7/internal/communicator/ssh/password_test.go
new file mode 100644
index 0000000..fa0640b
--- /dev/null
+++ b/v1.5.7/internal/communicator/ssh/password_test.go
@@ -0,0 +1,21 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package ssh
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestPasswordKeybardInteractive_Challenge(t *testing.T) {
+	p := PasswordKeyboardInteractive("foo")
+	result, err := p("foo", "bar", []string{"one", "two"}, nil)
+	if err != nil {
+		t.Fatalf("err not nil: %s", err)
+	}
+
+	if !reflect.DeepEqual(result, []string{"foo", "foo"}) {
+		t.Fatalf("invalid password: %#v", result)
+	}
+}
diff --git a/v1.5.7/internal/communicator/ssh/provisioner.go b/v1.5.7/internal/communicator/ssh/provisioner.go
new file mode 100644
index 0000000..3f0e22f
--- /dev/null
+++ b/v1.5.7/internal/communicator/ssh/provisioner.go
@@ -0,0 +1,596 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package ssh
+
+import (
+	"bytes"
+	"encoding/pem"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/communicator/shared"
+	sshagent "github.com/xanzy/ssh-agent"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/gocty"
+	"golang.org/x/crypto/ssh"
+	"golang.org/x/crypto/ssh/agent"
+	"golang.org/x/crypto/ssh/knownhosts"
+)
+
+const (
+	// DefaultUser is used if there is no user given
+	DefaultUser = "root"
+
+	// DefaultPort is used if there is no port given
+	DefaultPort = 22
+
+	// DefaultUnixScriptPath is used as the path to copy the file to
+	// for remote execution on unix if not provided otherwise.
+	DefaultUnixScriptPath = "/tmp/terraform_%RAND%.sh"
+	// DefaultWindowsScriptPath is used as the path to copy the file to
+	// for remote execution on windows if not provided otherwise.
+	DefaultWindowsScriptPath = "C:/windows/temp/terraform_%RAND%.cmd"
+
+	// DefaultTimeout is used if there is no timeout given
+	DefaultTimeout = 5 * time.Minute
+
+	// TargetPlatformUnix used for cleaner code, and is used if no target platform has been specified
+	TargetPlatformUnix = "unix"
+	//TargetPlatformWindows used for cleaner code
+	TargetPlatformWindows = "windows"
+)
+
+// connectionInfo is decoded from the ConnInfo of the resource. These are the
+// only keys we look at. If a PrivateKey is given, that is used instead
+// of a password.
+type connectionInfo struct {
+	User           string
+	Password       string
+	PrivateKey     string
+	Certificate    string
+	Host           string
+	HostKey        string
+	Port           uint16
+	Agent          bool
+	ScriptPath     string
+	TargetPlatform string
+	Timeout        string
+	TimeoutVal     time.Duration
+
+	ProxyScheme       string
+	ProxyHost         string
+	ProxyPort         uint16
+	ProxyUserName     string
+	ProxyUserPassword string
+
+	BastionUser        string
+	BastionPassword    string
+	BastionPrivateKey  string
+	BastionCertificate string
+	BastionHost        string
+	BastionHostKey     string
+	BastionPort        uint16
+
+	AgentIdentity string
+}
+
+// decodeConnInfo decodes the given cty.Value using the same behavior as the
+// lgeacy mapstructure decoder in order to preserve as much of the existing
+// logic as possible for compatibility.
+func decodeConnInfo(v cty.Value) (*connectionInfo, error) {
+	connInfo := &connectionInfo{}
+	if v.IsNull() {
+		return connInfo, nil
+	}
+
+	for k, v := range v.AsValueMap() {
+		if v.IsNull() {
+			continue
+		}
+
+		switch k {
+		case "user":
+			connInfo.User = v.AsString()
+		case "password":
+			connInfo.Password = v.AsString()
+		case "private_key":
+			connInfo.PrivateKey = v.AsString()
+		case "certificate":
+			connInfo.Certificate = v.AsString()
+		case "host":
+			connInfo.Host = v.AsString()
+		case "host_key":
+			connInfo.HostKey = v.AsString()
+		case "port":
+			if err := gocty.FromCtyValue(v, &connInfo.Port); err != nil {
+				return nil, err
+			}
+		case "agent":
+			connInfo.Agent = v.True()
+		case "script_path":
+			connInfo.ScriptPath = v.AsString()
+		case "target_platform":
+			connInfo.TargetPlatform = v.AsString()
+		case "timeout":
+			connInfo.Timeout = v.AsString()
+		case "proxy_scheme":
+			connInfo.ProxyScheme = v.AsString()
+		case "proxy_host":
+			connInfo.ProxyHost = v.AsString()
+		case "proxy_port":
+			if err := gocty.FromCtyValue(v, &connInfo.ProxyPort); err != nil {
+				return nil, err
+			}
+		case "proxy_user_name":
+			connInfo.ProxyUserName = v.AsString()
+		case "proxy_user_password":
+			connInfo.ProxyUserPassword = v.AsString()
+		case "bastion_user":
+			connInfo.BastionUser = v.AsString()
+		case "bastion_password":
+			connInfo.BastionPassword = v.AsString()
+		case "bastion_private_key":
+			connInfo.BastionPrivateKey = v.AsString()
+		case "bastion_certificate":
+			connInfo.BastionCertificate = v.AsString()
+		case "bastion_host":
+			connInfo.BastionHost = v.AsString()
+		case "bastion_host_key":
+			connInfo.BastionHostKey = v.AsString()
+		case "bastion_port":
+			if err := gocty.FromCtyValue(v, &connInfo.BastionPort); err != nil {
+				return nil, err
+			}
+		case "agent_identity":
+			connInfo.AgentIdentity = v.AsString()
+		}
+	}
+	return connInfo, nil
+}
+
+// parseConnectionInfo is used to convert the raw configuration into the
+// *connectionInfo struct.
+func parseConnectionInfo(v cty.Value) (*connectionInfo, error) {
+	v, err := shared.ConnectionBlockSupersetSchema.CoerceValue(v)
+	if err != nil {
+		return nil, err
+	}
+
+	connInfo, err := decodeConnInfo(v)
+	if err != nil {
+		return nil, err
+	}
+
+	// To default Agent to true, we need to check the raw string, since the
+	// decoded boolean can't represent "absence of config".
+	//
+	// And if SSH_AUTH_SOCK is not set, there's no agent to connect to, so we
+	// shouldn't try.
+	agent := v.GetAttr("agent")
+	if agent.IsNull() && os.Getenv("SSH_AUTH_SOCK") != "" {
+		connInfo.Agent = true
+	}
+
+	if connInfo.User == "" {
+		connInfo.User = DefaultUser
+	}
+
+	// Check if host is empty.
+	// Otherwise return error.
+	if connInfo.Host == "" {
+		return nil, fmt.Errorf("host for provisioner cannot be empty")
+	}
+
+	// Format the host if needed.
+	// Needed for IPv6 support.
+	connInfo.Host = shared.IpFormat(connInfo.Host)
+
+	if connInfo.Port == 0 {
+		connInfo.Port = DefaultPort
+	}
+	// Set default targetPlatform to unix if it's empty
+	if connInfo.TargetPlatform == "" {
+		connInfo.TargetPlatform = TargetPlatformUnix
+	} else if connInfo.TargetPlatform != TargetPlatformUnix && connInfo.TargetPlatform != TargetPlatformWindows {
+		return nil, fmt.Errorf("target_platform for provisioner has to be either %s or %s", TargetPlatformUnix, TargetPlatformWindows)
+	}
+	// Choose an appropriate default script path based on the target platform. There is no single
+	// suitable default script path which works on both UNIX and Windows targets.
+	if connInfo.ScriptPath == "" && connInfo.TargetPlatform == TargetPlatformUnix {
+		connInfo.ScriptPath = DefaultUnixScriptPath
+	}
+	if connInfo.ScriptPath == "" && connInfo.TargetPlatform == TargetPlatformWindows {
+		connInfo.ScriptPath = DefaultWindowsScriptPath
+	}
+	if connInfo.Timeout != "" {
+		connInfo.TimeoutVal = safeDuration(connInfo.Timeout, DefaultTimeout)
+	} else {
+		connInfo.TimeoutVal = DefaultTimeout
+	}
+
+	// Default all bastion config attrs to their non-bastion counterparts
+	if connInfo.BastionHost != "" {
+		// Format the bastion host if needed.
+		// Needed for IPv6 support.
+		connInfo.BastionHost = shared.IpFormat(connInfo.BastionHost)
+
+		if connInfo.BastionUser == "" {
+			connInfo.BastionUser = connInfo.User
+		}
+		if connInfo.BastionPassword == "" {
+			connInfo.BastionPassword = connInfo.Password
+		}
+		if connInfo.BastionPrivateKey == "" {
+			connInfo.BastionPrivateKey = connInfo.PrivateKey
+		}
+		if connInfo.BastionCertificate == "" {
+			connInfo.BastionCertificate = connInfo.Certificate
+		}
+		if connInfo.BastionPort == 0 {
+			connInfo.BastionPort = connInfo.Port
+		}
+	}
+
+	return connInfo, nil
+}
+
+// safeDuration returns either the parsed duration or a default value
+func safeDuration(dur string, defaultDur time.Duration) time.Duration {
+	d, err := time.ParseDuration(dur)
+	if err != nil {
+		log.Printf("Invalid duration '%s', using default of %s", dur, defaultDur)
+		return defaultDur
+	}
+	return d
+}
+
+// prepareSSHConfig is used to turn the *ConnectionInfo provided into a
+// usable *SSHConfig for client initialization.
+func prepareSSHConfig(connInfo *connectionInfo) (*sshConfig, error) {
+	sshAgent, err := connectToAgent(connInfo)
+	if err != nil {
+		return nil, err
+	}
+
+	host := fmt.Sprintf("%s:%d", connInfo.Host, connInfo.Port)
+
+	sshConf, err := buildSSHClientConfig(sshClientConfigOpts{
+		user:        connInfo.User,
+		host:        host,
+		privateKey:  connInfo.PrivateKey,
+		password:    connInfo.Password,
+		hostKey:     connInfo.HostKey,
+		certificate: connInfo.Certificate,
+		sshAgent:    sshAgent,
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	var p *proxyInfo
+
+	if connInfo.ProxyHost != "" {
+		p = newProxyInfo(
+			fmt.Sprintf("%s:%d", connInfo.ProxyHost, connInfo.ProxyPort),
+			connInfo.ProxyScheme,
+			connInfo.ProxyUserName,
+			connInfo.ProxyUserPassword,
+		)
+	}
+
+	connectFunc := ConnectFunc("tcp", host, p)
+
+	var bastionConf *ssh.ClientConfig
+	if connInfo.BastionHost != "" {
+		bastionHost := fmt.Sprintf("%s:%d", connInfo.BastionHost, connInfo.BastionPort)
+
+		bastionConf, err = buildSSHClientConfig(sshClientConfigOpts{
+			user:        connInfo.BastionUser,
+			host:        bastionHost,
+			privateKey:  connInfo.BastionPrivateKey,
+			password:    connInfo.BastionPassword,
+			hostKey:     connInfo.HostKey,
+			certificate: connInfo.BastionCertificate,
+			sshAgent:    sshAgent,
+		})
+		if err != nil {
+			return nil, err
+		}
+
+		connectFunc = BastionConnectFunc("tcp", bastionHost, bastionConf, "tcp", host, p)
+	}
+
+	config := &sshConfig{
+		config:     sshConf,
+		connection: connectFunc,
+		sshAgent:   sshAgent,
+	}
+	return config, nil
+}
+
+type sshClientConfigOpts struct {
+	privateKey  string
+	password    string
+	sshAgent    *sshAgent
+	certificate string
+	user        string
+	host        string
+	hostKey     string
+}
+
+func buildSSHClientConfig(opts sshClientConfigOpts) (*ssh.ClientConfig, error) {
+	hkCallback := ssh.InsecureIgnoreHostKey()
+
+	if opts.hostKey != "" {
+		// The knownhosts package only takes paths to files, but terraform
+		// generally wants to handle config data in-memory. Rather than making
+		// the known_hosts file an exception, write out the data to a temporary
+		// file to create the HostKeyCallback.
+		tf, err := ioutil.TempFile("", "tf-known_hosts")
+		if err != nil {
+			return nil, fmt.Errorf("failed to create temp known_hosts file: %s", err)
+		}
+		defer tf.Close()
+		defer os.RemoveAll(tf.Name())
+
+		// we mark this as a CA as well, but the host key fallback will still
+		// use it as a direct match if the remote host doesn't return a
+		// certificate.
+		if _, err := tf.WriteString(fmt.Sprintf("@cert-authority %s %s\n", opts.host, opts.hostKey)); err != nil {
+			return nil, fmt.Errorf("failed to write temp known_hosts file: %s", err)
+		}
+		tf.Sync()
+
+		hkCallback, err = knownhosts.New(tf.Name())
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	conf := &ssh.ClientConfig{
+		HostKeyCallback: hkCallback,
+		User:            opts.user,
+	}
+
+	if opts.privateKey != "" {
+		if opts.certificate != "" {
+			log.Println("using client certificate for authentication")
+
+			certSigner, err := signCertWithPrivateKey(opts.privateKey, opts.certificate)
+			if err != nil {
+				return nil, err
+			}
+			conf.Auth = append(conf.Auth, certSigner)
+		} else {
+			log.Println("using private key for authentication")
+
+			pubKeyAuth, err := readPrivateKey(opts.privateKey)
+			if err != nil {
+				return nil, err
+			}
+			conf.Auth = append(conf.Auth, pubKeyAuth)
+		}
+	}
+
+	if opts.password != "" {
+		conf.Auth = append(conf.Auth, ssh.Password(opts.password))
+		conf.Auth = append(conf.Auth, ssh.KeyboardInteractive(
+			PasswordKeyboardInteractive(opts.password)))
+	}
+
+	if opts.sshAgent != nil {
+		conf.Auth = append(conf.Auth, opts.sshAgent.Auth())
+	}
+
+	return conf, nil
+}
+
+// Create a Cert Signer and return ssh.AuthMethod
+func signCertWithPrivateKey(pk string, certificate string) (ssh.AuthMethod, error) {
+	rawPk, err := ssh.ParseRawPrivateKey([]byte(pk))
+	if err != nil {
+		return nil, fmt.Errorf("failed to parse private key %q: %s", pk, err)
+	}
+
+	pcert, _, _, _, err := ssh.ParseAuthorizedKey([]byte(certificate))
+	if err != nil {
+		return nil, fmt.Errorf("failed to parse certificate %q: %s", certificate, err)
+	}
+
+	usigner, err := ssh.NewSignerFromKey(rawPk)
+	if err != nil {
+		return nil, fmt.Errorf("failed to create signer from raw private key %q: %s", rawPk, err)
+	}
+
+	ucertSigner, err := ssh.NewCertSigner(pcert.(*ssh.Certificate), usigner)
+	if err != nil {
+		return nil, fmt.Errorf("failed to create cert signer %q: %s", usigner, err)
+	}
+
+	return ssh.PublicKeys(ucertSigner), nil
+}
+
+func readPrivateKey(pk string) (ssh.AuthMethod, error) {
+	// We parse the private key on our own first so that we can
+	// show a nicer error if the private key has a password.
+	block, _ := pem.Decode([]byte(pk))
+	if block == nil {
+		return nil, errors.New("Failed to read ssh private key: no key found")
+	}
+	if block.Headers["Proc-Type"] == "4,ENCRYPTED" {
+		return nil, errors.New(
+			"Failed to read ssh private key: password protected keys are\n" +
+				"not supported. Please decrypt the key prior to use.")
+	}
+
+	signer, err := ssh.ParsePrivateKey([]byte(pk))
+	if err != nil {
+		return nil, fmt.Errorf("Failed to parse ssh private key: %s", err)
+	}
+
+	return ssh.PublicKeys(signer), nil
+}
+
+func connectToAgent(connInfo *connectionInfo) (*sshAgent, error) {
+	if !connInfo.Agent {
+		// No agent configured
+		return nil, nil
+	}
+
+	agent, conn, err := sshagent.New()
+	if err != nil {
+		return nil, err
+	}
+
+	// connection close is handled over in Communicator
+	return &sshAgent{
+		agent: agent,
+		conn:  conn,
+		id:    connInfo.AgentIdentity,
+	}, nil
+
+}
+
+// A tiny wrapper around an agent.Agent to expose the ability to close its
+// associated connection on request.
+type sshAgent struct {
+	agent agent.Agent
+	conn  net.Conn
+	id    string
+}
+
+func (a *sshAgent) Close() error {
+	if a.conn == nil {
+		return nil
+	}
+
+	return a.conn.Close()
+}
+
+// make an attempt to either read the identity file or find a corresponding
+// public key file using the typical openssh naming convention.
+// This returns the public key in wire format, or nil when a key is not found.
+func findIDPublicKey(id string) []byte {
+	for _, d := range idKeyData(id) {
+		signer, err := ssh.ParsePrivateKey(d)
+		if err == nil {
+			log.Println("[DEBUG] parsed id private key")
+			pk := signer.PublicKey()
+			return pk.Marshal()
+		}
+
+		// try it as a publicKey
+		pk, err := ssh.ParsePublicKey(d)
+		if err == nil {
+			log.Println("[DEBUG] parsed id public key")
+			return pk.Marshal()
+		}
+
+		// finally try it as an authorized key
+		pk, _, _, _, err = ssh.ParseAuthorizedKey(d)
+		if err == nil {
+			log.Println("[DEBUG] parsed id authorized key")
+			return pk.Marshal()
+		}
+	}
+
+	return nil
+}
+
+// Try to read an id file using the id as the file path. Also read the .pub
+// file if it exists, as the id file may be encrypted. Return only the file
+// data read. We don't need to know what data came from which path, as we will
+// try parsing each as a private key, a public key and an authorized key
+// regardless.
+func idKeyData(id string) [][]byte {
+	idPath, err := filepath.Abs(id)
+	if err != nil {
+		return nil
+	}
+
+	var fileData [][]byte
+
+	paths := []string{idPath}
+
+	if !strings.HasSuffix(idPath, ".pub") {
+		paths = append(paths, idPath+".pub")
+	}
+
+	for _, p := range paths {
+		d, err := ioutil.ReadFile(p)
+		if err != nil {
+			log.Printf("[DEBUG] error reading %q: %s", p, err)
+			continue
+		}
+		log.Printf("[DEBUG] found identity data at %q", p)
+		fileData = append(fileData, d)
+	}
+
+	return fileData
+}
+
+// sortSigners moves a signer with an agent comment field matching the
+// agent_identity to the head of the list when attempting authentication. This
+// helps when there are more keys loaded in an agent than the host will allow
+// attempts.
+func (s *sshAgent) sortSigners(signers []ssh.Signer) {
+	if s.id == "" || len(signers) < 2 {
+		return
+	}
+
+	// if we can locate the public key, either by extracting it from the id or
+	// locating the .pub file, then we can more easily determine an exact match
+	idPk := findIDPublicKey(s.id)
+
+	// if we have a signer with a connect field that matches the id, send that
+	// first, otherwise put close matches at the front of the list.
+	head := 0
+	for i := range signers {
+		pk := signers[i].PublicKey()
+		k, ok := pk.(*agent.Key)
+		if !ok {
+			continue
+		}
+
+		// check for an exact match first
+		if bytes.Equal(pk.Marshal(), idPk) || s.id == k.Comment {
+			signers[0], signers[i] = signers[i], signers[0]
+			break
+		}
+
+		// no exact match yet, move it to the front if it's close. The agent
+		// may have loaded as a full filepath, while the config refers to it by
+		// filename only.
+		if strings.HasSuffix(k.Comment, s.id) {
+			signers[head], signers[i] = signers[i], signers[head]
+			head++
+			continue
+		}
+	}
+}
+
+func (s *sshAgent) Signers() ([]ssh.Signer, error) {
+	signers, err := s.agent.Signers()
+	if err != nil {
+		return nil, err
+	}
+
+	s.sortSigners(signers)
+	return signers, nil
+}
+
+func (a *sshAgent) Auth() ssh.AuthMethod {
+	return ssh.PublicKeysCallback(a.Signers)
+}
+
+func (a *sshAgent) ForwardToAgent(client *ssh.Client) error {
+	return agent.ForwardToAgent(client, a.agent)
+}
diff --git a/v1.5.7/internal/communicator/ssh/provisioner_test.go b/v1.5.7/internal/communicator/ssh/provisioner_test.go
new file mode 100644
index 0000000..f6183c2
--- /dev/null
+++ b/v1.5.7/internal/communicator/ssh/provisioner_test.go
@@ -0,0 +1,229 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package ssh
+
+import (
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestProvisioner_connInfo(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":         cty.StringVal("ssh"),
+		"user":         cty.StringVal("root"),
+		"password":     cty.StringVal("supersecret"),
+		"private_key":  cty.StringVal("someprivatekeycontents"),
+		"certificate":  cty.StringVal("somecertificate"),
+		"host":         cty.StringVal("127.0.0.1"),
+		"port":         cty.StringVal("22"),
+		"timeout":      cty.StringVal("30s"),
+		"bastion_host": cty.StringVal("127.0.1.1"),
+		"bastion_port": cty.NumberIntVal(20022),
+	})
+
+	conf, err := parseConnectionInfo(v)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if conf.User != "root" {
+		t.Fatalf("bad: %v", conf)
+	}
+	if conf.Password != "supersecret" {
+		t.Fatalf("bad: %v", conf)
+	}
+	if conf.PrivateKey != "someprivatekeycontents" {
+		t.Fatalf("bad: %v", conf)
+	}
+	if conf.Certificate != "somecertificate" {
+		t.Fatalf("bad: %v", conf)
+	}
+	if conf.Host != "127.0.0.1" {
+		t.Fatalf("bad: %v", conf)
+	}
+	if conf.Port != 22 {
+		t.Fatalf("bad: %v", conf)
+	}
+	if conf.Timeout != "30s" {
+		t.Fatalf("bad: %v", conf)
+	}
+	if conf.ScriptPath != DefaultUnixScriptPath {
+		t.Fatalf("bad: %v", conf)
+	}
+	if conf.TargetPlatform != TargetPlatformUnix {
+		t.Fatalf("bad: %v", conf)
+	}
+	if conf.BastionHost != "127.0.1.1" {
+		t.Fatalf("bad: %v", conf)
+	}
+	if conf.BastionPort != 20022 {
+		t.Fatalf("bad: %v", conf)
+	}
+	if conf.BastionUser != "root" {
+		t.Fatalf("bad: %v", conf)
+	}
+	if conf.BastionPassword != "supersecret" {
+		t.Fatalf("bad: %v", conf)
+	}
+	if conf.BastionPrivateKey != "someprivatekeycontents" {
+		t.Fatalf("bad: %v", conf)
+	}
+}
+
+func TestProvisioner_connInfoIpv6(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":         cty.StringVal("ssh"),
+		"user":         cty.StringVal("root"),
+		"password":     cty.StringVal("supersecret"),
+		"private_key":  cty.StringVal("someprivatekeycontents"),
+		"host":         cty.StringVal("::1"),
+		"port":         cty.StringVal("22"),
+		"timeout":      cty.StringVal("30s"),
+		"bastion_host": cty.StringVal("::1"),
+	})
+
+	conf, err := parseConnectionInfo(v)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if conf.Host != "[::1]" {
+		t.Fatalf("bad: %v", conf)
+	}
+
+	if conf.BastionHost != "[::1]" {
+		t.Fatalf("bad %v", conf)
+	}
+}
+
+func TestProvisioner_connInfoHostname(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":         cty.StringVal("ssh"),
+		"user":         cty.StringVal("root"),
+		"password":     cty.StringVal("supersecret"),
+		"private_key":  cty.StringVal("someprivatekeycontents"),
+		"host":         cty.StringVal("example.com"),
+		"port":         cty.StringVal("22"),
+		"timeout":      cty.StringVal("30s"),
+		"bastion_host": cty.StringVal("example.com"),
+	})
+
+	conf, err := parseConnectionInfo(v)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if conf.Host != "example.com" {
+		t.Fatalf("bad: %v", conf)
+	}
+
+	if conf.BastionHost != "example.com" {
+		t.Fatalf("bad %v", conf)
+	}
+}
+
+func TestProvisioner_connInfoEmptyHostname(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":        cty.StringVal("ssh"),
+		"user":        cty.StringVal("root"),
+		"password":    cty.StringVal("supersecret"),
+		"private_key": cty.StringVal("someprivatekeycontents"),
+		"port":        cty.StringVal("22"),
+		"timeout":     cty.StringVal("30s"),
+	})
+
+	_, err := parseConnectionInfo(v)
+	if err == nil {
+		t.Fatalf("bad: should not allow empty host")
+	}
+}
+
+func TestProvisioner_connInfoProxy(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":                cty.StringVal("ssh"),
+		"user":                cty.StringVal("root"),
+		"password":            cty.StringVal("supersecret"),
+		"private_key":         cty.StringVal("someprivatekeycontents"),
+		"host":                cty.StringVal("example.com"),
+		"port":                cty.StringVal("22"),
+		"timeout":             cty.StringVal("30s"),
+		"proxy_scheme":        cty.StringVal("http"),
+		"proxy_host":          cty.StringVal("proxy.example.com"),
+		"proxy_port":          cty.StringVal("80"),
+		"proxy_user_name":     cty.StringVal("proxyuser"),
+		"proxy_user_password": cty.StringVal("proxyuser_password"),
+	})
+
+	conf, err := parseConnectionInfo(v)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if conf.Host != "example.com" {
+		t.Fatalf("bad: %v", conf)
+	}
+
+	if conf.ProxyScheme != "http" {
+		t.Fatalf("bad: %v", conf)
+	}
+
+	if conf.ProxyHost != "proxy.example.com" {
+		t.Fatalf("bad: %v", conf)
+	}
+
+	if conf.ProxyPort != 80 {
+		t.Fatalf("bad: %v", conf)
+	}
+
+	if conf.ProxyUserName != "proxyuser" {
+		t.Fatalf("bad: %v", conf)
+	}
+
+	if conf.ProxyUserPassword != "proxyuser_password" {
+		t.Fatalf("bad: %v", conf)
+	}
+}
+
+func TestProvisioner_stringBastionPort(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":         cty.StringVal("ssh"),
+		"user":         cty.StringVal("root"),
+		"password":     cty.StringVal("supersecret"),
+		"private_key":  cty.StringVal("someprivatekeycontents"),
+		"host":         cty.StringVal("example.com"),
+		"port":         cty.StringVal("22"),
+		"timeout":      cty.StringVal("30s"),
+		"bastion_host": cty.StringVal("example.com"),
+		"bastion_port": cty.StringVal("12345"),
+	})
+
+	conf, err := parseConnectionInfo(v)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if conf.BastionPort != 12345 {
+		t.Fatalf("bad %v", conf)
+	}
+}
+
+func TestProvisioner_invalidPortNumber(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":        cty.StringVal("ssh"),
+		"user":        cty.StringVal("root"),
+		"password":    cty.StringVal("supersecret"),
+		"private_key": cty.StringVal("someprivatekeycontents"),
+		"host":        cty.StringVal("example.com"),
+		"port":        cty.NumberIntVal(123456789),
+	})
+
+	_, err := parseConnectionInfo(v)
+	if err == nil {
+		t.Fatalf("bad: should not allow invalid port number")
+	}
+	if got, want := err.Error(), "value must be a whole number, between 0 and 65535 inclusive"; got != want {
+		t.Errorf("unexpected error\n got: %s\nwant: %s", got, want)
+	}
+}
diff --git a/v1.5.7/internal/communicator/ssh/ssh_test.go b/v1.5.7/internal/communicator/ssh/ssh_test.go
new file mode 100644
index 0000000..be7df89
--- /dev/null
+++ b/v1.5.7/internal/communicator/ssh/ssh_test.go
@@ -0,0 +1,104 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package ssh
+
+import (
+	"bytes"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/pem"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"testing"
+
+	"golang.org/x/crypto/ssh"
+)
+
+// verify that we can locate public key data
+func TestFindKeyData(t *testing.T) {
+	// set up a test directory
+	td := t.TempDir()
+	cwd, err := os.Getwd()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := os.Chdir(td); err != nil {
+		t.Fatal(err)
+	}
+	defer os.Chdir(cwd)
+
+	id := "provisioner_id"
+
+	pub := generateSSHKey(t, id)
+	pubData := pub.Marshal()
+
+	// backup the pub file, and replace it with a broken file to ensure we
+	// extract the public key from the private key.
+	if err := os.Rename(id+".pub", "saved.pub"); err != nil {
+		t.Fatal(err)
+	}
+	if err := ioutil.WriteFile(id+".pub", []byte("not a public key"), 0600); err != nil {
+		t.Fatal(err)
+	}
+
+	foundData := findIDPublicKey(id)
+	if !bytes.Equal(foundData, pubData) {
+		t.Fatalf("public key %q does not match", foundData)
+	}
+
+	// move the pub file back, and break the private key file to simulate an
+	// encrypted private key
+	if err := os.Rename("saved.pub", id+".pub"); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := ioutil.WriteFile(id, []byte("encrypted private key"), 0600); err != nil {
+		t.Fatal(err)
+	}
+
+	foundData = findIDPublicKey(id)
+	if !bytes.Equal(foundData, pubData) {
+		t.Fatalf("public key %q does not match", foundData)
+	}
+
+	// check the file by path too
+	foundData = findIDPublicKey(filepath.Join(".", id))
+	if !bytes.Equal(foundData, pubData) {
+		t.Fatalf("public key %q does not match", foundData)
+	}
+}
+
+func generateSSHKey(t *testing.T, idFile string) ssh.PublicKey {
+	t.Helper()
+
+	priv, err := rsa.GenerateKey(rand.Reader, 2048)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	privFile, err := os.OpenFile(idFile, os.O_RDWR|os.O_CREATE, 0600)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer privFile.Close()
+	privPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}
+	if err := pem.Encode(privFile, privPEM); err != nil {
+		t.Fatal(err)
+	}
+
+	// generate and write public key
+	pub, err := ssh.NewPublicKey(&priv.PublicKey)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = ioutil.WriteFile(idFile+".pub", ssh.MarshalAuthorizedKey(pub), 0600)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	return pub
+}
diff --git a/v1.5.7/internal/communicator/winrm/communicator.go b/v1.5.7/internal/communicator/winrm/communicator.go
new file mode 100644
index 0000000..bf54bc6
--- /dev/null
+++ b/v1.5.7/internal/communicator/winrm/communicator.go
@@ -0,0 +1,205 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package winrm
+
+import (
+	"fmt"
+	"io"
+	"log"
+	"math/rand"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/communicator/remote"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/masterzen/winrm"
+	"github.com/packer-community/winrmcp/winrmcp"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Communicator represents the WinRM communicator
+type Communicator struct {
+	connInfo *connectionInfo
+	client   *winrm.Client
+	endpoint *winrm.Endpoint
+	rand     *rand.Rand
+}
+
+// New creates a new communicator implementation over WinRM.
+func New(v cty.Value) (*Communicator, error) {
+	connInfo, err := parseConnectionInfo(v)
+	if err != nil {
+		return nil, err
+	}
+
+	endpoint := &winrm.Endpoint{
+		Host:     connInfo.Host,
+		Port:     int(connInfo.Port),
+		HTTPS:    connInfo.HTTPS,
+		Insecure: connInfo.Insecure,
+		Timeout:  connInfo.TimeoutVal,
+	}
+	if len(connInfo.CACert) > 0 {
+		endpoint.CACert = []byte(connInfo.CACert)
+	}
+
+	comm := &Communicator{
+		connInfo: connInfo,
+		endpoint: endpoint,
+		// Seed our own rand source so that script paths are not deterministic
+		rand: rand.New(rand.NewSource(time.Now().UnixNano())),
+	}
+
+	return comm, nil
+}
+
+// Connect implementation of communicator.Communicator interface
+func (c *Communicator) Connect(o provisioners.UIOutput) error {
+	// Set the client to nil since we'll (re)create it
+	c.client = nil
+
+	params := winrm.DefaultParameters
+	params.Timeout = formatDuration(c.Timeout())
+	if c.connInfo.NTLM {
+		params.TransportDecorator = func() winrm.Transporter { return &winrm.ClientNTLM{} }
+	}
+
+	client, err := winrm.NewClientWithParameters(
+		c.endpoint, c.connInfo.User, c.connInfo.Password, params)
+	if err != nil {
+		return err
+	}
+
+	if o != nil {
+		o.Output(fmt.Sprintf(
+			"Connecting to remote host via WinRM...\n"+
+				"  Host: %s\n"+
+				"  Port: %d\n"+
+				"  User: %s\n"+
+				"  Password: %t\n"+
+				"  HTTPS: %t\n"+
+				"  Insecure: %t\n"+
+				"  NTLM: %t\n"+
+				"  CACert: %t",
+			c.connInfo.Host,
+			c.connInfo.Port,
+			c.connInfo.User,
+			c.connInfo.Password != "",
+			c.connInfo.HTTPS,
+			c.connInfo.Insecure,
+			c.connInfo.NTLM,
+			c.connInfo.CACert != "",
+		))
+	}
+
+	log.Printf("[DEBUG] connecting to remote shell using WinRM")
+	shell, err := client.CreateShell()
+	if err != nil {
+		log.Printf("[ERROR] error creating shell: %s", err)
+		return err
+	}
+
+	err = shell.Close()
+	if err != nil {
+		log.Printf("[ERROR] error closing shell: %s", err)
+		return err
+	}
+
+	if o != nil {
+		o.Output("Connected!")
+	}
+
+	c.client = client
+
+	return nil
+}
+
+// Disconnect implementation of communicator.Communicator interface
+func (c *Communicator) Disconnect() error {
+	c.client = nil
+	return nil
+}
+
+// Timeout implementation of communicator.Communicator interface
+func (c *Communicator) Timeout() time.Duration {
+	return c.connInfo.TimeoutVal
+}
+
+// ScriptPath implementation of communicator.Communicator interface
+func (c *Communicator) ScriptPath() string {
+	return strings.Replace(
+		c.connInfo.ScriptPath, "%RAND%",
+		strconv.FormatInt(int64(c.rand.Int31()), 10), -1)
+}
+
+// Start implementation of communicator.Communicator interface
+func (c *Communicator) Start(rc *remote.Cmd) error {
+	rc.Init()
+	log.Printf("[DEBUG] starting remote command: %s", rc.Command)
+
+	// TODO: make sure communicators always connect first, so we can get output
+	// from the connection.
+	if c.client == nil {
+		log.Println("[WARN] winrm client not connected, attempting to connect")
+		if err := c.Connect(nil); err != nil {
+			return err
+		}
+	}
+
+	status, err := c.client.Run(rc.Command, rc.Stdout, rc.Stderr)
+	rc.SetExitStatus(status, err)
+
+	return nil
+}
+
+// Upload implementation of communicator.Communicator interface
+func (c *Communicator) Upload(path string, input io.Reader) error {
+	wcp, err := c.newCopyClient()
+	if err != nil {
+		return err
+	}
+	log.Printf("[DEBUG] Uploading file to '%s'", path)
+	return wcp.Write(path, input)
+}
+
+// UploadScript implementation of communicator.Communicator interface
+func (c *Communicator) UploadScript(path string, input io.Reader) error {
+	return c.Upload(path, input)
+}
+
+// UploadDir implementation of communicator.Communicator interface
+func (c *Communicator) UploadDir(dst string, src string) error {
+	log.Printf("[DEBUG] Uploading dir '%s' to '%s'", src, dst)
+	wcp, err := c.newCopyClient()
+	if err != nil {
+		return err
+	}
+	return wcp.Copy(src, dst)
+}
+
+func (c *Communicator) newCopyClient() (*winrmcp.Winrmcp, error) {
+	addr := fmt.Sprintf("%s:%d", c.endpoint.Host, c.endpoint.Port)
+
+	config := winrmcp.Config{
+		Auth: winrmcp.Auth{
+			User:     c.connInfo.User,
+			Password: c.connInfo.Password,
+		},
+		Https:                 c.connInfo.HTTPS,
+		Insecure:              c.connInfo.Insecure,
+		OperationTimeout:      c.Timeout(),
+		MaxOperationsPerShell: 15, // lowest common denominator
+	}
+
+	if c.connInfo.NTLM {
+		config.TransportDecorator = func() winrm.Transporter { return &winrm.ClientNTLM{} }
+	}
+
+	if c.connInfo.CACert != "" {
+		config.CACertBytes = []byte(c.connInfo.CACert)
+	}
+
+	return winrmcp.New(addr, &config)
+}
diff --git a/v1.5.7/internal/communicator/winrm/communicator_test.go b/v1.5.7/internal/communicator/winrm/communicator_test.go
new file mode 100644
index 0000000..0f4f282
--- /dev/null
+++ b/v1.5.7/internal/communicator/winrm/communicator_test.go
@@ -0,0 +1,221 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package winrm
+
+import (
+	"bytes"
+	"io"
+	"regexp"
+	"strconv"
+	"testing"
+
+	"github.com/dylanmei/winrmtest"
+	"github.com/hashicorp/terraform/internal/communicator/remote"
+	"github.com/hashicorp/terraform/internal/communicator/shared"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func newMockWinRMServer(t *testing.T) *winrmtest.Remote {
+	wrm := winrmtest.NewRemote()
+
+	wrm.CommandFunc(
+		winrmtest.MatchText("echo foo"),
+		func(out, err io.Writer) int {
+			out.Write([]byte("foo"))
+			return 0
+		})
+
+	wrm.CommandFunc(
+		winrmtest.MatchPattern(`^echo c29tZXRoaW5n >> ".*"$`),
+		func(out, err io.Writer) int {
+			return 0
+		})
+
+	wrm.CommandFunc(
+		winrmtest.MatchPattern(`^powershell.exe -EncodedCommand .*$`),
+		func(out, err io.Writer) int {
+			return 0
+		})
+
+	wrm.CommandFunc(
+		winrmtest.MatchText("powershell"),
+		func(out, err io.Writer) int {
+			return 0
+		})
+
+	return wrm
+}
+
+func TestStart(t *testing.T) {
+	wrm := newMockWinRMServer(t)
+	defer wrm.Close()
+
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":     cty.StringVal("winrm"),
+		"user":     cty.StringVal("user"),
+		"password": cty.StringVal("pass"),
+		"host":     cty.StringVal(wrm.Host),
+		"port":     cty.StringVal(strconv.Itoa(wrm.Port)),
+		"timeout":  cty.StringVal("30s"),
+	})
+
+	c, err := New(v)
+	if err != nil {
+		t.Fatalf("error creating communicator: %s", err)
+	}
+
+	var cmd remote.Cmd
+	stdout := new(bytes.Buffer)
+	cmd.Command = "echo foo"
+	cmd.Stdout = stdout
+
+	err = c.Start(&cmd)
+	if err != nil {
+		t.Fatalf("error executing remote command: %s", err)
+	}
+	cmd.Wait()
+
+	if stdout.String() != "foo" {
+		t.Fatalf("bad command response: expected %q, got %q", "foo", stdout.String())
+	}
+}
+
+func TestUpload(t *testing.T) {
+	wrm := newMockWinRMServer(t)
+	defer wrm.Close()
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":     cty.StringVal("winrm"),
+		"user":     cty.StringVal("user"),
+		"password": cty.StringVal("pass"),
+		"host":     cty.StringVal(wrm.Host),
+		"port":     cty.StringVal(strconv.Itoa(wrm.Port)),
+		"timeout":  cty.StringVal("30s"),
+	})
+
+	c, err := New(v)
+	if err != nil {
+		t.Fatalf("error creating communicator: %s", err)
+	}
+
+	err = c.Connect(nil)
+	if err != nil {
+		t.Fatalf("error connecting communicator: %s", err)
+	}
+	defer c.Disconnect()
+
+	err = c.Upload("C:/Temp/terraform.cmd", bytes.NewReader([]byte("something")))
+	if err != nil {
+		t.Fatalf("error uploading file: %s", err)
+	}
+}
+
+func TestScriptPath(t *testing.T) {
+	cases := []struct {
+		Input   string
+		Pattern string
+	}{
+		{
+			"/tmp/script.sh",
+			`^/tmp/script\.sh$`,
+		},
+		{
+			"/tmp/script_%RAND%.sh",
+			`^/tmp/script_(\d+)\.sh$`,
+		},
+	}
+
+	for _, tc := range cases {
+		v := cty.ObjectVal(map[string]cty.Value{
+			"host":        cty.StringVal(""),
+			"type":        cty.StringVal("winrm"),
+			"script_path": cty.StringVal(tc.Input),
+		})
+
+		comm, err := New(v)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		output := comm.ScriptPath()
+
+		match, err := regexp.Match(tc.Pattern, []byte(output))
+		if err != nil {
+			t.Fatalf("bad: %s\n\nerr: %s", tc.Input, err)
+		}
+		if !match {
+			t.Fatalf("bad: %s\n\n%s", tc.Input, output)
+		}
+	}
+}
+
+func TestNoTransportDecorator(t *testing.T) {
+	wrm := newMockWinRMServer(t)
+	defer wrm.Close()
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":     cty.StringVal("winrm"),
+		"user":     cty.StringVal("user"),
+		"password": cty.StringVal("pass"),
+		"host":     cty.StringVal(wrm.Host),
+		"port":     cty.StringVal(strconv.Itoa(wrm.Port)),
+		"timeout":  cty.StringVal("30s"),
+	})
+
+	c, err := New(v)
+	if err != nil {
+		t.Fatalf("error creating communicator: %s", err)
+	}
+
+	err = c.Connect(nil)
+	if err != nil {
+		t.Fatalf("error connecting communicator: %s", err)
+	}
+	defer c.Disconnect()
+
+	if c.client.TransportDecorator != nil {
+		t.Fatal("bad TransportDecorator: expected nil, got non-nil")
+	}
+}
+
+func TestTransportDecorator(t *testing.T) {
+	wrm := newMockWinRMServer(t)
+	defer wrm.Close()
+
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":     cty.StringVal("winrm"),
+		"user":     cty.StringVal("user"),
+		"password": cty.StringVal("pass"),
+		"host":     cty.StringVal(wrm.Host),
+		"port":     cty.StringVal(strconv.Itoa(wrm.Port)),
+		"use_ntlm": cty.StringVal("true"),
+		"timeout":  cty.StringVal("30s"),
+	})
+
+	c, err := New(v)
+	if err != nil {
+		t.Fatalf("error creating communicator: %s", err)
+	}
+
+	err = c.Connect(nil)
+	if err != nil {
+		t.Fatalf("error connecting communicator: %s", err)
+	}
+	defer c.Disconnect()
+
+	if c.client.TransportDecorator == nil {
+		t.Fatal("bad TransportDecorator: expected non-nil, got nil")
+	}
+}
+
+func TestScriptPath_randSeed(t *testing.T) {
+	// Pre GH-4186 fix, this value was the deterministic start the pseudorandom
+	// chain of unseeded math/rand values for Int31().
+	staticSeedPath := "C:/Temp/terraform_1298498081.cmd"
+	c, err := New(cty.NullVal(shared.ConnectionBlockSupersetSchema.ImpliedType()))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	path := c.ScriptPath()
+	if path == staticSeedPath {
+		t.Fatalf("rand not seeded! got: %s", path)
+	}
+}
diff --git a/v1.5.7/internal/communicator/winrm/provisioner.go b/v1.5.7/internal/communicator/winrm/provisioner.go
new file mode 100644
index 0000000..a02cb3c
--- /dev/null
+++ b/v1.5.7/internal/communicator/winrm/provisioner.go
@@ -0,0 +1,172 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package winrm
+
+import (
+	"fmt"
+	"log"
+	"path/filepath"
+	"strings"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/communicator/shared"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/gocty"
+)
+
+const (
+	// DefaultUser is used if there is no user given
+	DefaultUser = "Administrator"
+
+	// DefaultPort is used if there is no port given
+	DefaultPort = 5985
+
+	// DefaultHTTPSPort is used if there is no port given and HTTPS is true
+	DefaultHTTPSPort = 5986
+
+	// DefaultScriptPath is used as the path to copy the file to
+	// for remote execution if not provided otherwise.
+	DefaultScriptPath = "C:/Temp/terraform_%RAND%.cmd"
+
+	// DefaultTimeout is used if there is no timeout given
+	DefaultTimeout = 5 * time.Minute
+)
+
+// connectionInfo is decoded from the ConnInfo of the resource. These are the
+// only keys we look at. If a KeyFile is given, that is used instead
+// of a password.
+type connectionInfo struct {
+	User       string
+	Password   string
+	Host       string
+	Port       uint16
+	HTTPS      bool
+	Insecure   bool
+	NTLM       bool   `mapstructure:"use_ntlm"`
+	CACert     string `mapstructure:"cacert"`
+	Timeout    string
+	ScriptPath string        `mapstructure:"script_path"`
+	TimeoutVal time.Duration `mapstructure:"-"`
+}
+
+// decodeConnInfo decodes the given cty.Value using the same behavior as the
+// lgeacy mapstructure decoder in order to preserve as much of the existing
+// logic as possible for compatibility.
+func decodeConnInfo(v cty.Value) (*connectionInfo, error) {
+	connInfo := &connectionInfo{}
+	if v.IsNull() {
+		return connInfo, nil
+	}
+
+	for k, v := range v.AsValueMap() {
+		if v.IsNull() {
+			continue
+		}
+
+		switch k {
+		case "user":
+			connInfo.User = v.AsString()
+		case "password":
+			connInfo.Password = v.AsString()
+		case "host":
+			connInfo.Host = v.AsString()
+		case "port":
+			if err := gocty.FromCtyValue(v, &connInfo.Port); err != nil {
+				return nil, err
+			}
+		case "https":
+			connInfo.HTTPS = v.True()
+		case "insecure":
+			connInfo.Insecure = v.True()
+		case "use_ntlm":
+			connInfo.NTLM = v.True()
+		case "cacert":
+			connInfo.CACert = v.AsString()
+		case "script_path":
+			connInfo.ScriptPath = v.AsString()
+		case "timeout":
+			connInfo.Timeout = v.AsString()
+		}
+	}
+	return connInfo, nil
+}
+
+// parseConnectionInfo is used to convert the ConnInfo of the InstanceState into
+// a ConnectionInfo struct
+func parseConnectionInfo(v cty.Value) (*connectionInfo, error) {
+	v, err := shared.ConnectionBlockSupersetSchema.CoerceValue(v)
+	if err != nil {
+		return nil, err
+	}
+
+	connInfo, err := decodeConnInfo(v)
+	if err != nil {
+		return nil, err
+	}
+	// Check on script paths which point to the default Windows TEMP folder because files
+	// which are put in there very early in the boot process could get cleaned/deleted
+	// before you had the change to execute them.
+	//
+	// TODO (SvH) Needs some more debugging to fully understand the exact sequence of events
+	// causing this...
+	if strings.HasPrefix(filepath.ToSlash(connInfo.ScriptPath), "C:/Windows/Temp") {
+		return nil, fmt.Errorf(
+			`Using the C:\Windows\Temp folder is not supported. Please use a different 'script_path'.`)
+	}
+
+	if connInfo.User == "" {
+		connInfo.User = DefaultUser
+	}
+
+	// Format the host if needed.
+	// Needed for IPv6 support.
+	connInfo.Host = shared.IpFormat(connInfo.Host)
+
+	if connInfo.Port == 0 {
+		if connInfo.HTTPS {
+			connInfo.Port = DefaultHTTPSPort
+		} else {
+			connInfo.Port = DefaultPort
+		}
+	}
+	if connInfo.ScriptPath == "" {
+		connInfo.ScriptPath = DefaultScriptPath
+	}
+	if connInfo.Timeout != "" {
+		connInfo.TimeoutVal = safeDuration(connInfo.Timeout, DefaultTimeout)
+	} else {
+		connInfo.TimeoutVal = DefaultTimeout
+	}
+
+	return connInfo, nil
+}
+
+// safeDuration returns either the parsed duration or a default value
+func safeDuration(dur string, defaultDur time.Duration) time.Duration {
+	d, err := time.ParseDuration(dur)
+	if err != nil {
+		log.Printf("Invalid duration '%s', using default of %s", dur, defaultDur)
+		return defaultDur
+	}
+	return d
+}
+
+func formatDuration(duration time.Duration) string {
+	h := int(duration.Hours())
+	m := int(duration.Minutes()) - h*60
+	s := int(duration.Seconds()) - (h*3600 + m*60)
+
+	res := "PT"
+	if h > 0 {
+		res = fmt.Sprintf("%s%dH", res, h)
+	}
+	if m > 0 {
+		res = fmt.Sprintf("%s%dM", res, m)
+	}
+	if s > 0 {
+		res = fmt.Sprintf("%s%dS", res, s)
+	}
+
+	return res
+}
diff --git a/v1.5.7/internal/communicator/winrm/provisioner_test.go b/v1.5.7/internal/communicator/winrm/provisioner_test.go
new file mode 100644
index 0000000..cd253d3
--- /dev/null
+++ b/v1.5.7/internal/communicator/winrm/provisioner_test.go
@@ -0,0 +1,260 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package winrm
+
+import (
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestProvisioner_defaultHTTPSPort(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":     cty.StringVal("winrm"),
+		"user":     cty.StringVal("Administrator"),
+		"password": cty.StringVal("supersecret"),
+		"host":     cty.StringVal("127.0.0.1"),
+		"https":    cty.True,
+	})
+
+	conf, err := parseConnectionInfo(v)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+	if conf.Port != 5986 {
+		t.Fatalf("expected: %v: got: %v", 5986, conf)
+	}
+	if conf.HTTPS != true {
+		t.Fatalf("expected: %v: got: %v", true, conf)
+	}
+}
+
+func TestProvisioner_connInfo(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":     cty.StringVal("winrm"),
+		"user":     cty.StringVal("Administrator"),
+		"password": cty.StringVal("supersecret"),
+		"host":     cty.StringVal("127.0.0.1"),
+		"port":     cty.StringVal("5985"),
+		"https":    cty.True,
+		"use_ntlm": cty.True,
+		"timeout":  cty.StringVal("30s"),
+	})
+
+	conf, err := parseConnectionInfo(v)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if conf.User != "Administrator" {
+		t.Fatalf("expected: %v: got: %v", "Administrator", conf)
+	}
+	if conf.Password != "supersecret" {
+		t.Fatalf("expected: %v: got: %v", "supersecret", conf)
+	}
+	if conf.Host != "127.0.0.1" {
+		t.Fatalf("expected: %v: got: %v", "127.0.0.1", conf)
+	}
+	if conf.Port != 5985 {
+		t.Fatalf("expected: %v: got: %v", 5985, conf)
+	}
+	if conf.HTTPS != true {
+		t.Fatalf("expected: %v: got: %v", true, conf)
+	}
+	if conf.NTLM != true {
+		t.Fatalf("expected: %v: got: %v", true, conf)
+	}
+	if conf.Timeout != "30s" {
+		t.Fatalf("expected: %v: got: %v", "30s", conf)
+	}
+	if conf.ScriptPath != DefaultScriptPath {
+		t.Fatalf("expected: %v: got: %v", DefaultScriptPath, conf)
+	}
+}
+
+func TestProvisioner_connInfoCACert(t *testing.T) {
+	caCert := `
+-----BEGIN CERTIFICATE-----
+MIIDBjCCAe4CCQCGWwBmOiHQdTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTE2MDYyMTE2MzM0MVoXDTE3MDYyMTE2MzM0MVowRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AL+LFlsCJG5txZp4yuu+lQnuUrgBXRG+irQqcTXlV91Bp5hpmRIyhnGCtWxxDBUL
+xrh4WN3VV/0jDzKT976oLgOy3hj56Cdqf+JlZ1qgMN5bHB3mm3aVWnrnsLbBsfwZ
+SEbk3Kht/cE1nK2toNVW+rznS3m+eoV3Zn/DUNwGlZr42hGNs6ETn2jURY78ETqR
+mW47xvjf86eIo7vULHJaY6xyarPqkL8DZazOmvY06hUGvGwGBny7gugfXqDG+I8n
+cPBsGJGSAmHmVV8o0RCB9UjY+TvSMQRpEDoVlvyrGuglsD8to/4+7UcsuDGlRYN6
+jmIOC37mOi/jwRfWL1YUa4MCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAPDxTH0oQ
+JjKXoJgkmQxurB81RfnK/NrswJVzWbOv6ejcbhwh+/ZgJTMc15BrYcxU6vUW1V/i
+Z7APU0qJ0icECACML+a2fRI7YdLCTiPIOmY66HY8MZHAn3dGjU5TeiUflC0n0zkP
+mxKJe43kcYLNDItbfvUDo/GoxTXrC3EFVZyU0RhFzoVJdODlTHXMVFCzcbQEBrBJ
+xKdShCEc8nFMneZcGFeEU488ntZoWzzms8/QpYrKa5S0Sd7umEU2Kwu4HTkvUFg/
+CqDUFjhydXxYRsxXBBrEiLOE5BdtJR1sH/QHxIJe23C9iHI2nS1NbLziNEApLwC4
+GnSud83VUo9G9w==
+-----END CERTIFICATE-----
+`
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":     cty.StringVal("winrm"),
+		"user":     cty.StringVal("Administrator"),
+		"password": cty.StringVal("supersecret"),
+		"host":     cty.StringVal("127.0.0.1"),
+		"port":     cty.StringVal("5985"),
+		"https":    cty.True,
+		"timeout":  cty.StringVal("30s"),
+		"cacert":   cty.StringVal(caCert),
+	})
+
+	conf, err := parseConnectionInfo(v)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if conf.User != "Administrator" {
+		t.Fatalf("expected: %v: got: %v", "Administrator", conf)
+	}
+	if conf.Password != "supersecret" {
+		t.Fatalf("expected: %v: got: %v", "supersecret", conf)
+	}
+	if conf.Host != "127.0.0.1" {
+		t.Fatalf("expected: %v: got: %v", "127.0.0.1", conf)
+	}
+	if conf.Port != 5985 {
+		t.Fatalf("expected: %v: got: %v", 5985, conf)
+	}
+	if conf.HTTPS != true {
+		t.Fatalf("expected: %v: got: %v", true, conf)
+	}
+	if conf.Timeout != "30s" {
+		t.Fatalf("expected: %v: got: %v", "30s", conf)
+	}
+	if conf.ScriptPath != DefaultScriptPath {
+		t.Fatalf("expected: %v: got: %v", DefaultScriptPath, conf)
+	}
+	if conf.CACert != caCert {
+		t.Fatalf("expected: %v: got: %v", caCert, conf.CACert)
+	}
+}
+
+func TestProvisioner_connInfoIpv6(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":     cty.StringVal("winrm"),
+		"user":     cty.StringVal("Administrator"),
+		"password": cty.StringVal("supersecret"),
+		"host":     cty.StringVal("::1"),
+		"port":     cty.StringVal("5985"),
+		"https":    cty.True,
+		"timeout":  cty.StringVal("30s"),
+	})
+
+	conf, err := parseConnectionInfo(v)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if conf.User != "Administrator" {
+		t.Fatalf("expected: %v: got: %v", "Administrator", conf)
+	}
+	if conf.Password != "supersecret" {
+		t.Fatalf("expected: %v: got: %v", "supersecret", conf)
+	}
+	if conf.Host != "[::1]" {
+		t.Fatalf("expected: %v: got: %v", "[::1]", conf)
+	}
+	if conf.Port != 5985 {
+		t.Fatalf("expected: %v: got: %v", 5985, conf)
+	}
+	if conf.HTTPS != true {
+		t.Fatalf("expected: %v: got: %v", true, conf)
+	}
+	if conf.Timeout != "30s" {
+		t.Fatalf("expected: %v: got: %v", "30s", conf)
+	}
+	if conf.ScriptPath != DefaultScriptPath {
+		t.Fatalf("expected: %v: got: %v", DefaultScriptPath, conf)
+	}
+}
+
+func TestProvisioner_connInfoHostname(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"type":     cty.StringVal("winrm"),
+		"user":     cty.StringVal("Administrator"),
+		"password": cty.StringVal("supersecret"),
+		"host":     cty.StringVal("example.com"),
+		"port":     cty.StringVal("5985"),
+		"https":    cty.True,
+		"timeout":  cty.StringVal("30s"),
+	})
+
+	conf, err := parseConnectionInfo(v)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if conf.User != "Administrator" {
+		t.Fatalf("expected: %v: got: %v", "Administrator", conf)
+	}
+	if conf.Password != "supersecret" {
+		t.Fatalf("expected: %v: got: %v", "supersecret", conf)
+	}
+	if conf.Host != "example.com" {
+		t.Fatalf("expected: %v: got: %v", "example.com", conf)
+	}
+	if conf.Port != 5985 {
+		t.Fatalf("expected: %v: got: %v", 5985, conf)
+	}
+	if conf.HTTPS != true {
+		t.Fatalf("expected: %v: got: %v", true, conf)
+	}
+	if conf.Timeout != "30s" {
+		t.Fatalf("expected: %v: got: %v", "30s", conf)
+	}
+	if conf.ScriptPath != DefaultScriptPath {
+		t.Fatalf("expected: %v: got: %v", DefaultScriptPath, conf)
+	}
+}
+
+func TestProvisioner_formatDuration(t *testing.T) {
+	cases := map[string]struct {
+		Config map[string]cty.Value
+		Result string
+	}{
+		"testSeconds": {
+			Config: map[string]cty.Value{
+				"timeout": cty.StringVal("90s"),
+			},
+
+			Result: "PT1M30S",
+		},
+		"testMinutes": {
+			Config: map[string]cty.Value{
+				"timeout": cty.StringVal("5m"),
+			},
+
+			Result: "PT5M",
+		},
+		"testHours": {
+			Config: map[string]cty.Value{
+				"timeout": cty.StringVal("1h"),
+			},
+
+			Result: "PT1H",
+		},
+	}
+
+	for name, tc := range cases {
+		// host is required in the schema
+		tc.Config["host"] = cty.StringVal("")
+
+		conf, err := parseConnectionInfo(cty.ObjectVal(tc.Config))
+		if err != nil {
+			t.Fatalf("err: %v", err)
+		}
+
+		result := formatDuration(conf.TimeoutVal)
+		if result != tc.Result {
+			t.Fatalf("%s: expected: %s got: %s", name, tc.Result, result)
+		}
+	}
+}
diff --git a/v1.5.7/internal/configs/backend.go b/v1.5.7/internal/configs/backend.go
new file mode 100644
index 0000000..f8015a0
--- /dev/null
+++ b/v1.5.7/internal/configs/backend.go
@@ -0,0 +1,58 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcldec"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Backend represents a "backend" block inside a "terraform" block in a module
+// or file.
+type Backend struct {
+	Type   string
+	Config hcl.Body
+
+	TypeRange hcl.Range
+	DeclRange hcl.Range
+}
+
+func decodeBackendBlock(block *hcl.Block) (*Backend, hcl.Diagnostics) {
+	return &Backend{
+		Type:      block.Labels[0],
+		TypeRange: block.LabelRanges[0],
+		Config:    block.Body,
+		DeclRange: block.DefRange,
+	}, nil
+}
+
+// Hash produces a hash value for the reciever that covers the type and the
+// portions of the config that conform to the given schema.
+//
+// If the config does not conform to the schema then the result is not
+// meaningful for comparison since it will be based on an incomplete result.
+//
+// As an exception, required attributes in the schema are treated as optional
+// for the purpose of hashing, so that an incomplete configuration can still
+// be hashed. Other errors, such as extraneous attributes, have no such special
+// case.
+func (b *Backend) Hash(schema *configschema.Block) int {
+	// Don't fail if required attributes are not set. Instead, we'll just
+	// hash them as nulls.
+	schema = schema.NoneRequired()
+	spec := schema.DecoderSpec()
+	val, _ := hcldec.Decode(b.Config, spec, nil)
+	if val == cty.NilVal {
+		val = cty.UnknownVal(schema.ImpliedType())
+	}
+
+	toHash := cty.TupleVal([]cty.Value{
+		cty.StringVal(b.Type),
+		val,
+	})
+
+	return toHash.Hash()
+}
diff --git a/v1.5.7/internal/configs/checks.go b/v1.5.7/internal/configs/checks.go
new file mode 100644
index 0000000..9bb4741
--- /dev/null
+++ b/v1.5.7/internal/configs/checks.go
@@ -0,0 +1,260 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/lang"
+)
+
+// CheckRule represents a configuration-defined validation rule, precondition,
+// or postcondition. Blocks of this sort can appear in a few different places
+// in configuration, including "validation" blocks for variables,
+// and "precondition" and "postcondition" blocks for resources.
+type CheckRule struct {
+	// Condition is an expression that must evaluate to true if the condition
+	// holds or false if it does not. If the expression produces an error then
+	// that's considered to be a bug in the module defining the check.
+	//
+	// The available variables in a condition expression vary depending on what
+	// a check is attached to. For example, validation rules attached to
+	// input variables can only refer to the variable that is being validated.
+	Condition hcl.Expression
+
+	// ErrorMessage should be one or more full sentences, which should be in
+	// English for consistency with the rest of the error message output but
+	// can in practice be in any language. The message should describe what is
+	// required for the condition to return true in a way that would make sense
+	// to a caller of the module.
+	//
+	// The error message expression has the same variables available for
+	// interpolation as the corresponding condition.
+	ErrorMessage hcl.Expression
+
+	DeclRange hcl.Range
+}
+
+// validateSelfReferences looks for references in the check rule matching the
+// specified resource address, returning error diagnostics if such a reference
+// is found.
+func (cr *CheckRule) validateSelfReferences(checkType string, addr addrs.Resource) hcl.Diagnostics {
+	var diags hcl.Diagnostics
+	exprs := []hcl.Expression{
+		cr.Condition,
+		cr.ErrorMessage,
+	}
+	for _, expr := range exprs {
+		if expr == nil {
+			continue
+		}
+		refs, _ := lang.References(expr.Variables())
+		for _, ref := range refs {
+			var refAddr addrs.Resource
+
+			switch rs := ref.Subject.(type) {
+			case addrs.Resource:
+				refAddr = rs
+			case addrs.ResourceInstance:
+				refAddr = rs.Resource
+			default:
+				continue
+			}
+
+			if refAddr.Equal(addr) {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  fmt.Sprintf("Invalid reference in %s", checkType),
+					Detail:   fmt.Sprintf("Configuration for %s may not refer to itself.", addr.String()),
+					Subject:  expr.Range().Ptr(),
+				})
+				break
+			}
+		}
+	}
+	return diags
+}
+
+// decodeCheckRuleBlock decodes the contents of the given block as a check rule.
+//
+// Unlike most of our "decode..." functions, this one can be applied to blocks
+// of various types as long as their body structures are "check-shaped". The
+// function takes the containing block only because some error messages will
+// refer to its location, and the returned object's DeclRange will be the
+// block's header.
+func decodeCheckRuleBlock(block *hcl.Block, override bool) (*CheckRule, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+	cr := &CheckRule{
+		DeclRange: block.DefRange,
+	}
+
+	if override {
+		// For now we'll just forbid overriding check blocks, to simplify
+		// the initial design. If we can find a clear use-case for overriding
+		// checks in override files and there's a way to define it that
+		// isn't confusing then we could relax this.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  fmt.Sprintf("Can't override %s blocks", block.Type),
+			Detail:   fmt.Sprintf("Override files cannot override %q blocks.", block.Type),
+			Subject:  cr.DeclRange.Ptr(),
+		})
+		return cr, diags
+	}
+
+	content, moreDiags := block.Body.Content(checkRuleBlockSchema)
+	diags = append(diags, moreDiags...)
+
+	if attr, exists := content.Attributes["condition"]; exists {
+		cr.Condition = attr.Expr
+
+		if len(cr.Condition.Variables()) == 0 {
+			// A condition expression that doesn't refer to any variable is
+			// pointless, because its result would always be a constant.
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  fmt.Sprintf("Invalid %s expression", block.Type),
+				Detail:   "The condition expression must refer to at least one object from elsewhere in the configuration, or else its result would not be checking anything.",
+				Subject:  cr.Condition.Range().Ptr(),
+			})
+		}
+	}
+
+	if attr, exists := content.Attributes["error_message"]; exists {
+		cr.ErrorMessage = attr.Expr
+	}
+
+	return cr, diags
+}
+
+var checkRuleBlockSchema = &hcl.BodySchema{
+	Attributes: []hcl.AttributeSchema{
+		{
+			Name:     "condition",
+			Required: true,
+		},
+		{
+			Name:     "error_message",
+			Required: true,
+		},
+	},
+}
+
+// Check represents a configuration defined check block.
+//
+// A check block contains 0-1 data blocks, and 0-n assert blocks. The check
+// block will load the data block, and execute the assert blocks as check rules
+// during the plan and apply Terraform operations.
+type Check struct {
+	Name string
+
+	DataResource *Resource
+	Asserts      []*CheckRule
+
+	DeclRange hcl.Range
+}
+
+func (c Check) Addr() addrs.Check {
+	return addrs.Check{
+		Name: c.Name,
+	}
+}
+
+func (c Check) Accessible(addr addrs.Referenceable) bool {
+	if check, ok := addr.(addrs.Check); ok {
+		return check.Equal(c.Addr())
+	}
+	return false
+}
+
+func decodeCheckBlock(block *hcl.Block, override bool) (*Check, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+
+	check := &Check{
+		Name:      block.Labels[0],
+		DeclRange: block.DefRange,
+	}
+
+	if override {
+		// For now we'll just forbid overriding check blocks, to simplify
+		// the initial design. If we can find a clear use-case for overriding
+		// checks in override files and there's a way to define it that
+		// isn't confusing then we could relax this.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Can't override check blocks",
+			Detail:   "Override files cannot override check blocks.",
+			Subject:  check.DeclRange.Ptr(),
+		})
+		return check, diags
+	}
+
+	content, moreDiags := block.Body.Content(checkBlockSchema)
+	diags = append(diags, moreDiags...)
+
+	if !hclsyntax.ValidIdentifier(check.Name) {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid check block name",
+			Detail:   badIdentifierDetail,
+			Subject:  &block.LabelRanges[0],
+		})
+	}
+
+	for _, block := range content.Blocks {
+		switch block.Type {
+		case "data":
+
+			if check.DataResource != nil {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Multiple data resource blocks",
+					Detail:   fmt.Sprintf("This check block already has a data resource defined at %s.", check.DataResource.DeclRange.Ptr()),
+					Subject:  block.DefRange.Ptr(),
+				})
+				continue
+			}
+
+			data, moreDiags := decodeDataBlock(block, override, true)
+			diags = append(diags, moreDiags...)
+			if !moreDiags.HasErrors() {
+				// Connect this data block back up to this check block.
+				data.Container = check
+
+				// Finally, save the data block.
+				check.DataResource = data
+			}
+		case "assert":
+			assert, moreDiags := decodeCheckRuleBlock(block, override)
+			diags = append(diags, moreDiags...)
+			if !moreDiags.HasErrors() {
+				check.Asserts = append(check.Asserts, assert)
+			}
+		default:
+			panic(fmt.Sprintf("unhandled check nested block %q", block.Type))
+		}
+	}
+
+	if len(check.Asserts) == 0 {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Zero assert blocks",
+			Detail:   "Check blocks must have at least one assert block.",
+			Subject:  check.DeclRange.Ptr(),
+		})
+	}
+
+	return check, diags
+}
+
+var checkBlockSchema = &hcl.BodySchema{
+	Blocks: []hcl.BlockHeaderSchema{
+		{Type: "data", LabelNames: []string{"type", "name"}},
+		{Type: "assert"},
+	},
+}
diff --git a/v1.5.7/internal/configs/cloud.go b/v1.5.7/internal/configs/cloud.go
new file mode 100644
index 0000000..3b0154a
--- /dev/null
+++ b/v1.5.7/internal/configs/cloud.go
@@ -0,0 +1,30 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"github.com/hashicorp/hcl/v2"
+)
+
+// Cloud represents a "cloud" block inside a "terraform" block in a module
+// or file.
+type CloudConfig struct {
+	Config hcl.Body
+
+	DeclRange hcl.Range
+}
+
+func decodeCloudBlock(block *hcl.Block) (*CloudConfig, hcl.Diagnostics) {
+	return &CloudConfig{
+		Config:    block.Body,
+		DeclRange: block.DefRange,
+	}, nil
+}
+
+func (c *CloudConfig) ToBackendConfig() Backend {
+	return Backend{
+		Type:   "cloud",
+		Config: c.Config,
+	}
+}
diff --git a/v1.5.7/internal/configs/compat_shim.go b/v1.5.7/internal/configs/compat_shim.go
new file mode 100644
index 0000000..bf54265
--- /dev/null
+++ b/v1.5.7/internal/configs/compat_shim.go
@@ -0,0 +1,112 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// -------------------------------------------------------------------------
+// Functions in this file are compatibility shims intended to ease conversion
+// from the old configuration loader. Any use of these functions that makes
+// a change should generate a deprecation warning explaining to the user how
+// to update their code for new patterns.
+//
+// Shims are particularly important for any patterns that have been widely
+// documented in books, tutorials, etc. Users will still be starting from
+// these examples and we want to help them adopt the latest patterns rather
+// than leave them stranded.
+// -------------------------------------------------------------------------
+
+// shimTraversalInString takes any arbitrary expression and checks if it is
+// a quoted string in the native syntax. If it _is_, then it is parsed as a
+// traversal and re-wrapped into a synthetic traversal expression and a
+// warning is generated. Otherwise, the given expression is just returned
+// verbatim.
+//
+// This function has no effect on expressions from the JSON syntax, since
+// traversals in strings are the required pattern in that syntax.
+//
+// If wantKeyword is set, the generated warning diagnostic will talk about
+// keywords rather than references. The behavior is otherwise unchanged, and
+// the caller remains responsible for checking that the result is indeed
+// a keyword, e.g. using hcl.ExprAsKeyword.
+func shimTraversalInString(expr hcl.Expression, wantKeyword bool) (hcl.Expression, hcl.Diagnostics) {
+	// ObjectConsKeyExpr is a special wrapper type used for keys on object
+	// constructors to deal with the fact that naked identifiers are normally
+	// handled as "bareword" strings rather than as variable references. Since
+	// we know we're interpreting as a traversal anyway (and thus it won't
+	// matter whether it's a string or an identifier) we can safely just unwrap
+	// here and then process whatever we find inside as normal.
+	if ocke, ok := expr.(*hclsyntax.ObjectConsKeyExpr); ok {
+		expr = ocke.Wrapped
+	}
+
+	if !exprIsNativeQuotedString(expr) {
+		return expr, nil
+	}
+
+	strVal, diags := expr.Value(nil)
+	if diags.HasErrors() || strVal.IsNull() || !strVal.IsKnown() {
+		// Since we're not even able to attempt a shim here, we'll discard
+		// the diagnostics we saw so far and let the caller's own error
+		// handling take care of reporting the invalid expression.
+		return expr, nil
+	}
+
+	// The position handling here isn't _quite_ right because it won't
+	// take into account any escape sequences in the literal string, but
+	// it should be close enough for any error reporting to make sense.
+	srcRange := expr.Range()
+	startPos := srcRange.Start // copy
+	startPos.Column++          // skip initial quote
+	startPos.Byte++            // skip initial quote
+
+	traversal, tDiags := hclsyntax.ParseTraversalAbs(
+		[]byte(strVal.AsString()),
+		srcRange.Filename,
+		startPos,
+	)
+	diags = append(diags, tDiags...)
+
+	if wantKeyword {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagWarning,
+			Summary:  "Quoted keywords are deprecated",
+			Detail:   "In this context, keywords are expected literally rather than in quotes. Terraform 0.11 and earlier required quotes, but quoted keywords are now deprecated and will be removed in a future version of Terraform. Remove the quotes surrounding this keyword to silence this warning.",
+			Subject:  &srcRange,
+		})
+	} else {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagWarning,
+			Summary:  "Quoted references are deprecated",
+			Detail:   "In this context, references are expected literally rather than in quotes. Terraform 0.11 and earlier required quotes, but quoted references are now deprecated and will be removed in a future version of Terraform. Remove the quotes surrounding this reference to silence this warning.",
+			Subject:  &srcRange,
+		})
+	}
+
+	return &hclsyntax.ScopeTraversalExpr{
+		Traversal: traversal,
+		SrcRange:  srcRange,
+	}, diags
+}
+
+// shimIsIgnoreChangesStar returns true if the given expression seems to be
+// a string literal whose value is "*". This is used to support a legacy
+// form of ignore_changes = all .
+//
+// This function does not itself emit any diagnostics, so it's the caller's
+// responsibility to emit a warning diagnostic when this function returns true.
+func shimIsIgnoreChangesStar(expr hcl.Expression) bool {
+	val, valDiags := expr.Value(nil)
+	if valDiags.HasErrors() {
+		return false
+	}
+	if val.Type() != cty.String || val.IsNull() || !val.IsKnown() {
+		return false
+	}
+	return val.AsString() == "*"
+}
diff --git a/v1.5.7/internal/configs/config.go b/v1.5.7/internal/configs/config.go
new file mode 100644
index 0000000..bae01bd
--- /dev/null
+++ b/v1.5.7/internal/configs/config.go
@@ -0,0 +1,663 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+	"log"
+	"sort"
+
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+// A Config is a node in the tree of modules within a configuration.
+//
+// The module tree is constructed by following ModuleCall instances recursively
+// through the root module transitively into descendent modules.
+//
+// A module tree described in *this* package represents the static tree
+// represented by configuration. During evaluation a static ModuleNode may
+// expand into zero or more module instances depending on the use of count and
+// for_each configuration attributes within each call.
+type Config struct {
+	// RootModule points to the Config for the root module within the same
+	// module tree as this module. If this module _is_ the root module then
+	// this is self-referential.
+	Root *Config
+
+	// ParentModule points to the Config for the module that directly calls
+	// this module. If this is the root module then this field is nil.
+	Parent *Config
+
+	// Path is a sequence of module logical names that traverse from the root
+	// module to this config. Path is empty for the root module.
+	//
+	// This should only be used to display paths to the end-user in rare cases
+	// where we are talking about the static module tree, before module calls
+	// have been resolved. In most cases, an addrs.ModuleInstance describing
+	// a node in the dynamic module tree is better, since it will then include
+	// any keys resulting from evaluating "count" and "for_each" arguments.
+	Path addrs.Module
+
+	// ChildModules points to the Config for each of the direct child modules
+	// called from this module. The keys in this map match the keys in
+	// Module.ModuleCalls.
+	Children map[string]*Config
+
+	// Module points to the object describing the configuration for the
+	// various elements (variables, resources, etc) defined by this module.
+	Module *Module
+
+	// CallRange is the source range for the header of the module block that
+	// requested this module.
+	//
+	// This field is meaningless for the root module, where its contents are undefined.
+	CallRange hcl.Range
+
+	// SourceAddr is the source address that the referenced module was requested
+	// from, as specified in configuration. SourceAddrRaw is the same
+	// information, but as the raw string the user originally entered.
+	//
+	// These fields are meaningless for the root module, where their contents are undefined.
+	SourceAddr    addrs.ModuleSource
+	SourceAddrRaw string
+
+	// SourceAddrRange is the location in the configuration source where the
+	// SourceAddr value was set, for use in diagnostic messages.
+	//
+	// This field is meaningless for the root module, where its contents are undefined.
+	SourceAddrRange hcl.Range
+
+	// Version is the specific version that was selected for this module,
+	// based on version constraints given in configuration.
+	//
+	// This field is nil if the module was loaded from a non-registry source,
+	// since versions are not supported for other sources.
+	//
+	// This field is meaningless for the root module, where it will always
+	// be nil.
+	Version *version.Version
+}
+
+// ModuleRequirements represents the provider requirements for an individual
+// module, along with references to any child modules. This is used to
+// determine which modules require which providers.
+type ModuleRequirements struct {
+	Name         string
+	SourceAddr   addrs.ModuleSource
+	SourceDir    string
+	Requirements getproviders.Requirements
+	Children     map[string]*ModuleRequirements
+}
+
+// NewEmptyConfig constructs a single-node configuration tree with an empty
+// root module. This is generally a pretty useless thing to do, so most callers
+// should instead use BuildConfig.
+func NewEmptyConfig() *Config {
+	ret := &Config{}
+	ret.Root = ret
+	ret.Children = make(map[string]*Config)
+	ret.Module = &Module{}
+	return ret
+}
+
+// Depth returns the number of "hops" the receiver is from the root of its
+// module tree, with the root module having a depth of zero.
+func (c *Config) Depth() int {
+	ret := 0
+	this := c
+	for this.Parent != nil {
+		ret++
+		this = this.Parent
+	}
+	return ret
+}
+
+// DeepEach calls the given function once for each module in the tree, starting
+// with the receiver.
+//
+// A parent is always called before its children and children of a particular
+// node are visited in lexicographic order by their names.
+func (c *Config) DeepEach(cb func(c *Config)) {
+	cb(c)
+
+	names := make([]string, 0, len(c.Children))
+	for name := range c.Children {
+		names = append(names, name)
+	}
+
+	for _, name := range names {
+		c.Children[name].DeepEach(cb)
+	}
+}
+
+// AllModules returns a slice of all the receiver and all of its descendent
+// nodes in the module tree, in the same order they would be visited by
+// DeepEach.
+func (c *Config) AllModules() []*Config {
+	var ret []*Config
+	c.DeepEach(func(c *Config) {
+		ret = append(ret, c)
+	})
+	return ret
+}
+
+// Descendent returns the descendent config that has the given path beneath
+// the receiver, or nil if there is no such module.
+//
+// The path traverses the static module tree, prior to any expansion to handle
+// count and for_each arguments.
+//
+// An empty path will just return the receiver, and is therefore pointless.
+func (c *Config) Descendent(path addrs.Module) *Config {
+	current := c
+	for _, name := range path {
+		current = current.Children[name]
+		if current == nil {
+			return nil
+		}
+	}
+	return current
+}
+
+// DescendentForInstance is like Descendent except that it accepts a path
+// to a particular module instance in the dynamic module graph, returning
+// the node from the static module graph that corresponds to it.
+//
+// All instances created by a particular module call share the same
+// configuration, so the keys within the given path are disregarded.
+func (c *Config) DescendentForInstance(path addrs.ModuleInstance) *Config {
+	current := c
+	for _, step := range path {
+		current = current.Children[step.Name]
+		if current == nil {
+			return nil
+		}
+	}
+	return current
+}
+
+// EntersNewPackage returns true if this call is to an external module, either
+// directly via a remote source address or indirectly via a registry source
+// address.
+//
+// Other behaviors in Terraform may treat package crossings as a special
+// situation, because that indicates that the caller and callee can change
+// independently of one another and thus we should disallow using any features
+// where the caller assumes anything about the callee other than its input
+// variables, required provider configurations, and output values.
+//
+// It's not meaningful to ask if the Config representing the root module enters
+// a new package because the root module is always outside of all module
+// packages, and so this function will arbitrarily return false in that case.
+func (c *Config) EntersNewPackage() bool {
+	return moduleSourceAddrEntersNewPackage(c.SourceAddr)
+}
+
+// VerifyDependencySelections checks whether the given locked dependencies
+// are acceptable for all of the version constraints reported in the
+// configuration tree represented by the reciever.
+//
+// This function will errors only if any of the locked dependencies are out of
+// range for corresponding constraints in the configuration. If there are
+// multiple inconsistencies then it will attempt to describe as many of them
+// as possible, rather than stopping at the first problem.
+//
+// It's typically the responsibility of "terraform init" to change the locked
+// dependencies to conform with the configuration, and so
+// VerifyDependencySelections is intended for other commands to check whether
+// it did so correctly and to catch if anything has changed in configuration
+// since the last "terraform init" which requires re-initialization. However,
+// it's up to the caller to decide how to advise users recover from these
+// errors, because the advise can vary depending on what operation the user
+// is attempting.
+func (c *Config) VerifyDependencySelections(depLocks *depsfile.Locks) []error {
+	var errs []error
+
+	reqs, diags := c.ProviderRequirements()
+	if diags.HasErrors() {
+		// It should be very unusual to get here, but unfortunately we can
+		// end up here in some edge cases where the config loader doesn't
+		// process version constraint strings in exactly the same way as
+		// the requirements resolver. (See the addProviderRequirements method
+		// for more information.)
+		errs = append(errs, fmt.Errorf("failed to determine the configuration's provider requirements: %s", diags.Error()))
+	}
+
+	for providerAddr, constraints := range reqs {
+		if !depsfile.ProviderIsLockable(providerAddr) {
+			continue // disregard builtin providers, and such
+		}
+		if depLocks != nil && depLocks.ProviderIsOverridden(providerAddr) {
+			// The "overridden" case is for unusual special situations like
+			// dev overrides, so we'll explicitly note it in the logs just in
+			// case we see bug reports with these active and it helps us
+			// understand why we ended up using the "wrong" plugin.
+			log.Printf("[DEBUG] Config.VerifyDependencySelections: skipping %s because it's overridden by a special configuration setting", providerAddr)
+			continue
+		}
+
+		var lock *depsfile.ProviderLock
+		if depLocks != nil { // Should always be true in main code, but unfortunately sometimes not true in old tests that don't fill out arguments completely
+			lock = depLocks.Provider(providerAddr)
+		}
+		if lock == nil {
+			log.Printf("[TRACE] Config.VerifyDependencySelections: provider %s has no lock file entry to satisfy %q", providerAddr, getproviders.VersionConstraintsString(constraints))
+			errs = append(errs, fmt.Errorf("provider %s: required by this configuration but no version is selected", providerAddr))
+			continue
+		}
+
+		selectedVersion := lock.Version()
+		allowedVersions := getproviders.MeetingConstraints(constraints)
+		log.Printf("[TRACE] Config.VerifyDependencySelections: provider %s has %s to satisfy %q", providerAddr, selectedVersion.String(), getproviders.VersionConstraintsString(constraints))
+		if !allowedVersions.Has(selectedVersion) {
+			// The most likely cause of this is that the author of a module
+			// has changed its constraints, but this could also happen in
+			// some other unusual situations, such as the user directly
+			// editing the lock file to record something invalid. We'll
+			// distinguish those cases here in order to avoid the more
+			// specific error message potentially being a red herring in
+			// the edge-cases.
+			currentConstraints := getproviders.VersionConstraintsString(constraints)
+			lockedConstraints := getproviders.VersionConstraintsString(lock.VersionConstraints())
+			switch {
+			case currentConstraints != lockedConstraints:
+				errs = append(errs, fmt.Errorf("provider %s: locked version selection %s doesn't match the updated version constraints %q", providerAddr, selectedVersion.String(), currentConstraints))
+			default:
+				errs = append(errs, fmt.Errorf("provider %s: version constraints %q don't match the locked version selection %s", providerAddr, currentConstraints, selectedVersion.String()))
+			}
+		}
+	}
+
+	// Return multiple errors in an arbitrary-but-deterministic order.
+	sort.Slice(errs, func(i, j int) bool {
+		return errs[i].Error() < errs[j].Error()
+	})
+
+	return errs
+}
+
+// ProviderRequirements searches the full tree of modules under the receiver
+// for both explicit and implicit dependencies on providers.
+//
+// The result is a full manifest of all of the providers that must be available
+// in order to work with the receiving configuration.
+//
+// If the returned diagnostics includes errors then the resulting Requirements
+// may be incomplete.
+func (c *Config) ProviderRequirements() (getproviders.Requirements, hcl.Diagnostics) {
+	reqs := make(getproviders.Requirements)
+	diags := c.addProviderRequirements(reqs, true)
+
+	return reqs, diags
+}
+
+// ProviderRequirementsShallow searches only the direct receiver for explicit
+// and implicit dependencies on providers. Descendant modules are ignored.
+//
+// If the returned diagnostics includes errors then the resulting Requirements
+// may be incomplete.
+func (c *Config) ProviderRequirementsShallow() (getproviders.Requirements, hcl.Diagnostics) {
+	reqs := make(getproviders.Requirements)
+	diags := c.addProviderRequirements(reqs, false)
+
+	return reqs, diags
+}
+
+// ProviderRequirementsByModule searches the full tree of modules under the
+// receiver for both explicit and implicit dependencies on providers,
+// constructing a tree where the requirements are broken out by module.
+//
+// If the returned diagnostics includes errors then the resulting Requirements
+// may be incomplete.
+func (c *Config) ProviderRequirementsByModule() (*ModuleRequirements, hcl.Diagnostics) {
+	reqs := make(getproviders.Requirements)
+	diags := c.addProviderRequirements(reqs, false)
+
+	children := make(map[string]*ModuleRequirements)
+	for name, child := range c.Children {
+		childReqs, childDiags := child.ProviderRequirementsByModule()
+		childReqs.Name = name
+		children[name] = childReqs
+		diags = append(diags, childDiags...)
+	}
+
+	ret := &ModuleRequirements{
+		SourceAddr:   c.SourceAddr,
+		SourceDir:    c.Module.SourceDir,
+		Requirements: reqs,
+		Children:     children,
+	}
+
+	return ret, diags
+}
+
+// addProviderRequirements is the main part of the ProviderRequirements
+// implementation, gradually mutating a shared requirements object to
+// eventually return. If the recurse argument is true, the requirements will
+// include all descendant modules; otherwise, only the specified module.
+func (c *Config) addProviderRequirements(reqs getproviders.Requirements, recurse bool) hcl.Diagnostics {
+	var diags hcl.Diagnostics
+
+	// First we'll deal with the requirements directly in _our_ module...
+	if c.Module.ProviderRequirements != nil {
+		for _, providerReqs := range c.Module.ProviderRequirements.RequiredProviders {
+			fqn := providerReqs.Type
+			if _, ok := reqs[fqn]; !ok {
+				// We'll at least have an unconstrained dependency then, but might
+				// add to this in the loop below.
+				reqs[fqn] = nil
+			}
+			// The model of version constraints in this package is still the
+			// old one using a different upstream module to represent versions,
+			// so we'll need to shim that out here for now. The two parsers
+			// don't exactly agree in practice 🙄 so this might produce new errors.
+			// TODO: Use the new parser throughout this package so we can get the
+			// better error messages it produces in more situations.
+			constraints, err := getproviders.ParseVersionConstraints(providerReqs.Requirement.Required.String())
+			if err != nil {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid version constraint",
+					// The errors returned by ParseVersionConstraint already include
+					// the section of input that was incorrect, so we don't need to
+					// include that here.
+					Detail:  fmt.Sprintf("Incorrect version constraint syntax: %s.", err.Error()),
+					Subject: providerReqs.Requirement.DeclRange.Ptr(),
+				})
+			}
+			reqs[fqn] = append(reqs[fqn], constraints...)
+		}
+	}
+
+	// Each resource in the configuration creates an *implicit* provider
+	// dependency, though we'll only record it if there isn't already
+	// an explicit dependency on the same provider.
+	for _, rc := range c.Module.ManagedResources {
+		fqn := rc.Provider
+		if _, exists := reqs[fqn]; exists {
+			// Explicit dependency already present
+			continue
+		}
+		reqs[fqn] = nil
+	}
+	for _, rc := range c.Module.DataResources {
+		fqn := rc.Provider
+		if _, exists := reqs[fqn]; exists {
+			// Explicit dependency already present
+			continue
+		}
+		reqs[fqn] = nil
+	}
+	for _, i := range c.Module.Import {
+		implied, err := addrs.ParseProviderPart(i.To.Resource.Resource.ImpliedProvider())
+		if err == nil {
+			provider := c.Module.ImpliedProviderForUnqualifiedType(implied)
+			if _, exists := reqs[provider]; exists {
+				// Explicit dependency already present
+				continue
+			}
+			reqs[provider] = nil
+		}
+		// We don't return a diagnostic here, because the invalid address will
+		// have been caught elsewhere.
+	}
+
+	// Import blocks that are generating config may also have a custom provider
+	// meta argument. Like the provider meta argument used in resource blocks,
+	// we use this opportunity to load any implicit providers.
+	//
+	// We'll also use this to validate that import blocks and targeted resource
+	// blocks agree on which provider they should be using. If they don't agree,
+	// this will be because the user has written explicit provider arguments
+	// that don't agree and we'll get them to fix it.
+	for _, i := range c.Module.Import {
+		if len(i.To.Module) > 0 {
+			// All provider information for imports into modules should come
+			// from the module block, so we don't need to load anything for
+			// import targets within modules.
+			continue
+		}
+
+		if target, exists := c.Module.ManagedResources[i.To.String()]; exists {
+			// This means the information about the provider for this import
+			// should come from the resource block itself and not the import
+			// block.
+			//
+			// In general, we say that you shouldn't set the provider attribute
+			// on import blocks in this case. But to make config generation
+			// easier, we will say that if it is set in both places and it's the
+			// same then that is okay.
+
+			if i.ProviderConfigRef != nil {
+				if target.ProviderConfigRef == nil {
+					// This means we have a provider specified in the import
+					// block and not in the resource block. This isn't the right
+					// way round so let's consider this a failure.
+					diags = append(diags, &hcl.Diagnostic{
+						Severity: hcl.DiagError,
+						Summary:  "Invalid import provider argument",
+						Detail:   "The provider argument can only be specified in import blocks that will generate configuration.\n\nUse the provider argument in the target resource block to configure the provider for a resource with explicit provider configuration.",
+						Subject:  i.ProviderDeclRange.Ptr(),
+					})
+					continue
+				}
+
+				if i.ProviderConfigRef.Name != target.ProviderConfigRef.Name || i.ProviderConfigRef.Alias != target.ProviderConfigRef.Alias {
+					// This means we have a provider specified in both the
+					// import block and the resource block, and they disagree.
+					// This is bad as Terraform now has different instructions
+					// about which provider to use.
+					//
+					// The general guidance is that only the resource should be
+					// specifying the provider as the import block provider
+					// attribute is just for generating config. So, let's just
+					// tell the user to only set the provider argument in the
+					// resource.
+					diags = append(diags, &hcl.Diagnostic{
+						Severity: hcl.DiagError,
+						Summary:  "Invalid import provider argument",
+						Detail:   "The provider argument can only be specified in import blocks that will generate configuration.\n\nUse the provider argument in the target resource block to configure the provider for a resource with explicit provider configuration.",
+						Subject:  i.ProviderDeclRange.Ptr(),
+					})
+					continue
+				}
+			}
+
+			// All the provider information should come from the target resource
+			// which has already been processed, so skip the rest of this
+			// processing.
+			continue
+		}
+
+		// Otherwise we are generating config for the resource being imported,
+		// so all the provider information must come from this import block.
+		fqn := i.Provider
+		if _, exists := reqs[fqn]; exists {
+			// Explicit dependency already present
+			continue
+		}
+		reqs[fqn] = nil
+	}
+
+	// "provider" block can also contain version constraints
+	for _, provider := range c.Module.ProviderConfigs {
+		fqn := c.Module.ProviderForLocalConfig(addrs.LocalProviderConfig{LocalName: provider.Name})
+		if _, ok := reqs[fqn]; !ok {
+			// We'll at least have an unconstrained dependency then, but might
+			// add to this in the loop below.
+			reqs[fqn] = nil
+		}
+		if provider.Version.Required != nil {
+			// The model of version constraints in this package is still the
+			// old one using a different upstream module to represent versions,
+			// so we'll need to shim that out here for now. The two parsers
+			// don't exactly agree in practice 🙄 so this might produce new errors.
+			// TODO: Use the new parser throughout this package so we can get the
+			// better error messages it produces in more situations.
+			constraints, err := getproviders.ParseVersionConstraints(provider.Version.Required.String())
+			if err != nil {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid version constraint",
+					// The errors returned by ParseVersionConstraint already include
+					// the section of input that was incorrect, so we don't need to
+					// include that here.
+					Detail:  fmt.Sprintf("Incorrect version constraint syntax: %s.", err.Error()),
+					Subject: provider.Version.DeclRange.Ptr(),
+				})
+			}
+			reqs[fqn] = append(reqs[fqn], constraints...)
+		}
+	}
+
+	if recurse {
+		for _, childConfig := range c.Children {
+			moreDiags := childConfig.addProviderRequirements(reqs, true)
+			diags = append(diags, moreDiags...)
+		}
+	}
+
+	return diags
+}
+
+// resolveProviderTypes walks through the providers in the module and ensures
+// the true types are assigned based on the provider requirements for the
+// module.
+func (c *Config) resolveProviderTypes() {
+	for _, child := range c.Children {
+		child.resolveProviderTypes()
+	}
+
+	// collect the required_providers, and then add any missing default providers
+	providers := map[string]addrs.Provider{}
+	for name, p := range c.Module.ProviderRequirements.RequiredProviders {
+		providers[name] = p.Type
+	}
+
+	// ensure all provider configs know their correct type
+	for _, p := range c.Module.ProviderConfigs {
+		addr, required := providers[p.Name]
+		if required {
+			p.providerType = addr
+		} else {
+			addr := addrs.NewDefaultProvider(p.Name)
+			p.providerType = addr
+			providers[p.Name] = addr
+		}
+	}
+
+	// connect module call providers to the correct type
+	for _, mod := range c.Module.ModuleCalls {
+		for _, p := range mod.Providers {
+			if addr, known := providers[p.InParent.Name]; known {
+				p.InParent.providerType = addr
+			}
+		}
+	}
+
+	// fill in parent module calls too
+	if c.Parent != nil {
+		for _, mod := range c.Parent.Module.ModuleCalls {
+			for _, p := range mod.Providers {
+				if addr, known := providers[p.InChild.Name]; known {
+					p.InChild.providerType = addr
+				}
+			}
+		}
+	}
+}
+
+// ProviderTypes returns the FQNs of each distinct provider type referenced
+// in the receiving configuration.
+//
+// This is a helper for easily determining which provider types are required
+// to fully interpret the configuration, though it does not include version
+// information and so callers are expected to have already dealt with
+// provider version selection in an earlier step and have identified suitable
+// versions for each provider.
+func (c *Config) ProviderTypes() []addrs.Provider {
+	// Ignore diagnostics here because they relate to version constraints
+	reqs, _ := c.ProviderRequirements()
+
+	ret := make([]addrs.Provider, 0, len(reqs))
+	for k := range reqs {
+		ret = append(ret, k)
+	}
+	sort.Slice(ret, func(i, j int) bool {
+		return ret[i].String() < ret[j].String()
+	})
+	return ret
+}
+
+// ResolveAbsProviderAddr returns the AbsProviderConfig represented by the given
+// ProviderConfig address, which must not be nil or this method will panic.
+//
+// If the given address is already an AbsProviderConfig then this method returns
+// it verbatim, and will always succeed. If it's a LocalProviderConfig then
+// it will consult the local-to-FQN mapping table for the given module
+// to find the absolute address corresponding to the given local one.
+//
+// The module address to resolve local addresses in must be given in the second
+// argument, and must refer to a module that exists under the receiver or
+// else this method will panic.
+func (c *Config) ResolveAbsProviderAddr(addr addrs.ProviderConfig, inModule addrs.Module) addrs.AbsProviderConfig {
+	switch addr := addr.(type) {
+
+	case addrs.AbsProviderConfig:
+		return addr
+
+	case addrs.LocalProviderConfig:
+		// Find the descendent Config that contains the module that this
+		// local config belongs to.
+		mc := c.Descendent(inModule)
+		if mc == nil {
+			panic(fmt.Sprintf("ResolveAbsProviderAddr with non-existent module %s", inModule.String()))
+		}
+
+		var provider addrs.Provider
+		if providerReq, exists := c.Module.ProviderRequirements.RequiredProviders[addr.LocalName]; exists {
+			provider = providerReq.Type
+		} else {
+			provider = addrs.ImpliedProviderForUnqualifiedType(addr.LocalName)
+		}
+
+		return addrs.AbsProviderConfig{
+			Module:   inModule,
+			Provider: provider,
+			Alias:    addr.Alias,
+		}
+
+	default:
+		panic(fmt.Sprintf("cannot ResolveAbsProviderAddr(%v, ...)", addr))
+	}
+
+}
+
+// ProviderForConfigAddr returns the FQN for a given addrs.ProviderConfig, first
+// by checking for the provider in module.ProviderRequirements and falling
+// back to addrs.NewDefaultProvider if it is not found.
+func (c *Config) ProviderForConfigAddr(addr addrs.LocalProviderConfig) addrs.Provider {
+	if provider, exists := c.Module.ProviderRequirements.RequiredProviders[addr.LocalName]; exists {
+		return provider.Type
+	}
+	return c.ResolveAbsProviderAddr(addr, addrs.RootModule).Provider
+}
+
+func (c *Config) CheckCoreVersionRequirements() hcl.Diagnostics {
+	var diags hcl.Diagnostics
+
+	diags = diags.Extend(c.Module.CheckCoreVersionRequirements(c.Path, c.SourceAddr))
+
+	for _, c := range c.Children {
+		childDiags := c.CheckCoreVersionRequirements()
+		diags = diags.Extend(childDiags)
+	}
+
+	return diags
+}
diff --git a/v1.5.7/internal/configs/config_build.go b/v1.5.7/internal/configs/config_build.go
new file mode 100644
index 0000000..78a0cf9
--- /dev/null
+++ b/v1.5.7/internal/configs/config_build.go
@@ -0,0 +1,213 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+	"sort"
+
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// BuildConfig constructs a Config from a root module by loading all of its
+// descendent modules via the given ModuleWalker.
+//
+// The result is a module tree that has so far only had basic module- and
+// file-level invariants validated. If the returned diagnostics contains errors,
+// the returned module tree may be incomplete but can still be used carefully
+// for static analysis.
+func BuildConfig(root *Module, walker ModuleWalker) (*Config, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+	cfg := &Config{
+		Module: root,
+	}
+	cfg.Root = cfg // Root module is self-referential.
+	cfg.Children, diags = buildChildModules(cfg, walker)
+
+	// Skip provider resolution if there are any errors, since the provider
+	// configurations themselves may not be valid.
+	if !diags.HasErrors() {
+		// Now that the config is built, we can connect the provider names to all
+		// the known types for validation.
+		cfg.resolveProviderTypes()
+	}
+
+	diags = append(diags, validateProviderConfigs(nil, cfg, nil)...)
+
+	return cfg, diags
+}
+
+func buildChildModules(parent *Config, walker ModuleWalker) (map[string]*Config, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+	ret := map[string]*Config{}
+
+	calls := parent.Module.ModuleCalls
+
+	// We'll sort the calls by their local names so that they'll appear in a
+	// predictable order in any logging that's produced during the walk.
+	callNames := make([]string, 0, len(calls))
+	for k := range calls {
+		callNames = append(callNames, k)
+	}
+	sort.Strings(callNames)
+
+	for _, callName := range callNames {
+		call := calls[callName]
+		path := make([]string, len(parent.Path)+1)
+		copy(path, parent.Path)
+		path[len(path)-1] = call.Name
+
+		req := ModuleRequest{
+			Name:              call.Name,
+			Path:              path,
+			SourceAddr:        call.SourceAddr,
+			SourceAddrRange:   call.SourceAddrRange,
+			VersionConstraint: call.Version,
+			Parent:            parent,
+			CallRange:         call.DeclRange,
+		}
+
+		mod, ver, modDiags := walker.LoadModule(&req)
+		diags = append(diags, modDiags...)
+		if mod == nil {
+			// nil can be returned if the source address was invalid and so
+			// nothing could be loaded whatsoever. LoadModule should've
+			// returned at least one error diagnostic in that case.
+			continue
+		}
+
+		child := &Config{
+			Parent:          parent,
+			Root:            parent.Root,
+			Path:            path,
+			Module:          mod,
+			CallRange:       call.DeclRange,
+			SourceAddr:      call.SourceAddr,
+			SourceAddrRange: call.SourceAddrRange,
+			Version:         ver,
+		}
+
+		child.Children, modDiags = buildChildModules(child, walker)
+		diags = append(diags, modDiags...)
+
+		if mod.Backend != nil {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagWarning,
+				Summary:  "Backend configuration ignored",
+				Detail:   "Any selected backend applies to the entire configuration, so Terraform expects provider configurations only in the root module.\n\nThis is a warning rather than an error because it's sometimes convenient to temporarily call a root module as a child module for testing purposes, but this backend configuration block will have no effect.",
+				Subject:  mod.Backend.DeclRange.Ptr(),
+			})
+		}
+
+		if len(mod.Import) > 0 {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid import configuration",
+				Detail:   fmt.Sprintf("An import block was detected in %q. Import blocks are only allowed in the root module.", child.Path),
+				Subject:  mod.Import[0].DeclRange.Ptr(),
+			})
+		}
+
+		ret[call.Name] = child
+	}
+
+	return ret, diags
+}
+
+// A ModuleWalker knows how to find and load a child module given details about
+// the module to be loaded and a reference to its partially-loaded parent
+// Config.
+type ModuleWalker interface {
+	// LoadModule finds and loads a requested child module.
+	//
+	// If errors are detected during loading, implementations should return them
+	// in the diagnostics object. If the diagnostics object contains any errors
+	// then the caller will tolerate the returned module being nil or incomplete.
+	// If no errors are returned, it should be non-nil and complete.
+	//
+	// Full validation need not have been performed but an implementation should
+	// ensure that the basic file- and module-validations performed by the
+	// LoadConfigDir function (valid syntax, no namespace collisions, etc) have
+	// been performed before returning a module.
+	LoadModule(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics)
+}
+
+// ModuleWalkerFunc is an implementation of ModuleWalker that directly wraps
+// a callback function, for more convenient use of that interface.
+type ModuleWalkerFunc func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics)
+
+// LoadModule implements ModuleWalker.
+func (f ModuleWalkerFunc) LoadModule(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
+	return f(req)
+}
+
+// ModuleRequest is used with the ModuleWalker interface to describe a child
+// module that must be loaded.
+type ModuleRequest struct {
+	// Name is the "logical name" of the module call within configuration.
+	// This is provided in case the name is used as part of a storage key
+	// for the module, but implementations must otherwise treat it as an
+	// opaque string. It is guaranteed to have already been validated as an
+	// HCL identifier and UTF-8 encoded.
+	Name string
+
+	// Path is a list of logical names that traverse from the root module to
+	// this module. This can be used, for example, to form a lookup key for
+	// each distinct module call in a configuration, allowing for multiple
+	// calls with the same name at different points in the tree.
+	Path addrs.Module
+
+	// SourceAddr is the source address string provided by the user in
+	// configuration.
+	SourceAddr addrs.ModuleSource
+
+	// SourceAddrRange is the source range for the SourceAddr value as it
+	// was provided in configuration. This can and should be used to generate
+	// diagnostics about the source address having invalid syntax, referring
+	// to a non-existent object, etc.
+	SourceAddrRange hcl.Range
+
+	// VersionConstraint is the version constraint applied to the module in
+	// configuration. This data structure includes the source range for
+	// the constraint, which can and should be used to generate diagnostics
+	// about constraint-related issues, such as constraints that eliminate all
+	// available versions of a module whose source is otherwise valid.
+	VersionConstraint VersionConstraint
+
+	// Parent is the partially-constructed module tree node that the loaded
+	// module will be added to. Callers may refer to any field of this
+	// structure except Children, which is still under construction when
+	// ModuleRequest objects are created and thus has undefined content.
+	// The main reason this is provided is so that full module paths can
+	// be constructed for uniqueness.
+	Parent *Config
+
+	// CallRange is the source range for the header of the "module" block
+	// in configuration that prompted this request. This can be used as the
+	// subject of an error diagnostic that relates to the module call itself,
+	// rather than to either its source address or its version number.
+	CallRange hcl.Range
+}
+
+// DisabledModuleWalker is a ModuleWalker that doesn't support
+// child modules at all, and so will return an error if asked to load one.
+//
+// This is provided primarily for testing. There is no good reason to use this
+// in the main application.
+var DisabledModuleWalker ModuleWalker
+
+func init() {
+	DisabledModuleWalker = ModuleWalkerFunc(func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
+		return nil, nil, hcl.Diagnostics{
+			{
+				Severity: hcl.DiagError,
+				Summary:  "Child modules are not supported",
+				Detail:   "Child module calls are not allowed in this context.",
+				Subject:  &req.CallRange,
+			},
+		}
+	})
+}
diff --git a/v1.5.7/internal/configs/config_build_test.go b/v1.5.7/internal/configs/config_build_test.go
new file mode 100644
index 0000000..cee7c09
--- /dev/null
+++ b/v1.5.7/internal/configs/config_build_test.go
@@ -0,0 +1,284 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+	"io/ioutil"
+	"path/filepath"
+	"reflect"
+	"sort"
+	"strings"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/hcl/v2"
+)
+
+func TestBuildConfig(t *testing.T) {
+	parser := NewParser(nil)
+	mod, diags := parser.LoadConfigDir("testdata/config-build")
+	assertNoDiagnostics(t, diags)
+	if mod == nil {
+		t.Fatal("got nil root module; want non-nil")
+	}
+
+	versionI := 0
+	cfg, diags := BuildConfig(mod, ModuleWalkerFunc(
+		func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
+			// For the sake of this test we're going to just treat our
+			// SourceAddr as a path relative to our fixture directory.
+			// A "real" implementation of ModuleWalker should accept the
+			// various different source address syntaxes Terraform supports.
+			sourcePath := filepath.Join("testdata/config-build", req.SourceAddr.String())
+
+			mod, diags := parser.LoadConfigDir(sourcePath)
+			version, _ := version.NewVersion(fmt.Sprintf("1.0.%d", versionI))
+			versionI++
+			return mod, version, diags
+		},
+	))
+	assertNoDiagnostics(t, diags)
+	if cfg == nil {
+		t.Fatal("got nil config; want non-nil")
+	}
+
+	var got []string
+	cfg.DeepEach(func(c *Config) {
+		got = append(got, fmt.Sprintf("%s %s", strings.Join(c.Path, "."), c.Version))
+	})
+	sort.Strings(got)
+	want := []string{
+		" <nil>",
+		"child_a 1.0.0",
+		"child_a.child_c 1.0.1",
+		"child_b 1.0.2",
+		"child_b.child_c 1.0.3",
+	}
+
+	if !reflect.DeepEqual(got, want) {
+		t.Fatalf("wrong result\ngot: %swant: %s", spew.Sdump(got), spew.Sdump(want))
+	}
+
+	if _, exists := cfg.Children["child_a"].Children["child_c"].Module.Outputs["hello"]; !exists {
+		t.Fatalf("missing output 'hello' in child_a.child_c")
+	}
+	if _, exists := cfg.Children["child_b"].Children["child_c"].Module.Outputs["hello"]; !exists {
+		t.Fatalf("missing output 'hello' in child_b.child_c")
+	}
+	if cfg.Children["child_a"].Children["child_c"].Module == cfg.Children["child_b"].Children["child_c"].Module {
+		t.Fatalf("child_a.child_c is same object as child_b.child_c; should not be")
+	}
+}
+
+func TestBuildConfigDiags(t *testing.T) {
+	parser := NewParser(nil)
+	mod, diags := parser.LoadConfigDir("testdata/nested-errors")
+	assertNoDiagnostics(t, diags)
+	if mod == nil {
+		t.Fatal("got nil root module; want non-nil")
+	}
+
+	versionI := 0
+	cfg, diags := BuildConfig(mod, ModuleWalkerFunc(
+		func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
+			// For the sake of this test we're going to just treat our
+			// SourceAddr as a path relative to our fixture directory.
+			// A "real" implementation of ModuleWalker should accept the
+			// various different source address syntaxes Terraform supports.
+			sourcePath := filepath.Join("testdata/nested-errors", req.SourceAddr.String())
+
+			mod, diags := parser.LoadConfigDir(sourcePath)
+			version, _ := version.NewVersion(fmt.Sprintf("1.0.%d", versionI))
+			versionI++
+			return mod, version, diags
+		},
+	))
+
+	wantDiag := `testdata/nested-errors/child_c/child_c.tf:5,1-8: ` +
+		`Unsupported block type; Blocks of type "invalid" are not expected here.`
+	assertExactDiagnostics(t, diags, []string{wantDiag})
+
+	// we should still have module structure loaded
+	var got []string
+	cfg.DeepEach(func(c *Config) {
+		got = append(got, fmt.Sprintf("%s %s", strings.Join(c.Path, "."), c.Version))
+	})
+	sort.Strings(got)
+	want := []string{
+		" <nil>",
+		"child_a 1.0.0",
+		"child_a.child_c 1.0.1",
+	}
+
+	if !reflect.DeepEqual(got, want) {
+		t.Fatalf("wrong result\ngot: %swant: %s", spew.Sdump(got), spew.Sdump(want))
+	}
+}
+
+func TestBuildConfigChildModuleBackend(t *testing.T) {
+	parser := NewParser(nil)
+	mod, diags := parser.LoadConfigDir("testdata/nested-backend-warning")
+	assertNoDiagnostics(t, diags)
+	if mod == nil {
+		t.Fatal("got nil root module; want non-nil")
+	}
+
+	cfg, diags := BuildConfig(mod, ModuleWalkerFunc(
+		func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
+			// For the sake of this test we're going to just treat our
+			// SourceAddr as a path relative to our fixture directory.
+			// A "real" implementation of ModuleWalker should accept the
+			// various different source address syntaxes Terraform supports.
+			sourcePath := filepath.Join("testdata/nested-backend-warning", req.SourceAddr.String())
+
+			mod, diags := parser.LoadConfigDir(sourcePath)
+			version, _ := version.NewVersion("1.0.0")
+			return mod, version, diags
+		},
+	))
+
+	assertDiagnosticSummary(t, diags, "Backend configuration ignored")
+
+	// we should still have module structure loaded
+	var got []string
+	cfg.DeepEach(func(c *Config) {
+		got = append(got, fmt.Sprintf("%s %s", strings.Join(c.Path, "."), c.Version))
+	})
+	sort.Strings(got)
+	want := []string{
+		" <nil>",
+		"child 1.0.0",
+	}
+
+	if !reflect.DeepEqual(got, want) {
+		t.Fatalf("wrong result\ngot: %swant: %s", spew.Sdump(got), spew.Sdump(want))
+	}
+}
+
+func TestBuildConfigInvalidModules(t *testing.T) {
+	testDir := "testdata/config-diagnostics"
+	dirs, err := ioutil.ReadDir(testDir)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, info := range dirs {
+		name := info.Name()
+		t.Run(name, func(t *testing.T) {
+			parser := NewParser(nil)
+			path := filepath.Join(testDir, name)
+
+			mod, diags := parser.LoadConfigDir(path)
+			if diags.HasErrors() {
+				// these tests should only trigger errors that are caught in
+				// the config loader.
+				t.Errorf("error loading config dir")
+				for _, diag := range diags {
+					t.Logf("- %s", diag)
+				}
+			}
+
+			readDiags := func(data []byte, _ error) []string {
+				var expected []string
+				for _, s := range strings.Split(string(data), "\n") {
+					msg := strings.TrimSpace(s)
+					msg = strings.ReplaceAll(msg, `\n`, "\n")
+					if msg != "" {
+						expected = append(expected, msg)
+					}
+				}
+				return expected
+			}
+
+			// Load expected errors and warnings.
+			// Each line in the file is matched as a substring against the
+			// diagnostic outputs.
+			// Capturing part of the path and source range in the message lets
+			// us also ensure the diagnostic is being attributed to the
+			// expected location in the source, but is not required.
+			// The literal characters `\n` are replaced with newlines, but
+			// otherwise the string is unchanged.
+			expectedErrs := readDiags(ioutil.ReadFile(filepath.Join(testDir, name, "errors")))
+			expectedWarnings := readDiags(ioutil.ReadFile(filepath.Join(testDir, name, "warnings")))
+
+			_, buildDiags := BuildConfig(mod, ModuleWalkerFunc(
+				func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
+					// for simplicity, these tests will treat all source
+					// addresses as relative to the root module
+					sourcePath := filepath.Join(path, req.SourceAddr.String())
+					mod, diags := parser.LoadConfigDir(sourcePath)
+					version, _ := version.NewVersion("1.0.0")
+					return mod, version, diags
+				},
+			))
+
+			// we can make this less repetitive later if we want
+			for _, msg := range expectedErrs {
+				found := false
+				for _, diag := range buildDiags {
+					if diag.Severity == hcl.DiagError && strings.Contains(diag.Error(), msg) {
+						found = true
+						break
+					}
+				}
+
+				if !found {
+					t.Errorf("Expected error diagnostic containing:\n    %s", msg)
+				}
+			}
+
+			for _, diag := range buildDiags {
+				if diag.Severity != hcl.DiagError {
+					continue
+				}
+				found := false
+				for _, msg := range expectedErrs {
+					if strings.Contains(diag.Error(), msg) {
+						found = true
+						break
+					}
+				}
+
+				if !found {
+					t.Errorf("Unexpected error:\n    %s", diag)
+				}
+			}
+
+			for _, msg := range expectedWarnings {
+				found := false
+				for _, diag := range buildDiags {
+					if diag.Severity == hcl.DiagWarning && strings.Contains(diag.Error(), msg) {
+						found = true
+						break
+					}
+				}
+
+				if !found {
+					t.Errorf("Expected warning diagnostic containing:\n    %s", msg)
+				}
+			}
+
+			for _, diag := range buildDiags {
+				if diag.Severity != hcl.DiagWarning {
+					continue
+				}
+				found := false
+				for _, msg := range expectedWarnings {
+					if strings.Contains(diag.Error(), msg) {
+						found = true
+						break
+					}
+				}
+
+				if !found {
+					t.Errorf("Unexpected warning:\n    %s", diag)
+				}
+			}
+
+		})
+	}
+}
diff --git a/v1.5.7/internal/configs/config_test.go b/v1.5.7/internal/configs/config_test.go
new file mode 100644
index 0000000..699e199
--- /dev/null
+++ b/v1.5.7/internal/configs/config_test.go
@@ -0,0 +1,468 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"os"
+	"testing"
+
+	"github.com/go-test/deep"
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/zclconf/go-cty/cty"
+
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+func TestConfigProviderTypes(t *testing.T) {
+	// nil cfg should return an empty map
+	got := NewEmptyConfig().ProviderTypes()
+	if len(got) != 0 {
+		t.Fatal("expected empty result from empty config")
+	}
+
+	cfg, diags := testModuleConfigFromFile("testdata/valid-files/providers-explicit-implied.tf")
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	got = cfg.ProviderTypes()
+	want := []addrs.Provider{
+		addrs.NewDefaultProvider("aws"),
+		addrs.NewDefaultProvider("local"),
+		addrs.NewDefaultProvider("null"),
+		addrs.NewDefaultProvider("template"),
+		addrs.NewDefaultProvider("test"),
+	}
+	for _, problem := range deep.Equal(got, want) {
+		t.Error(problem)
+	}
+}
+
+func TestConfigProviderTypes_nested(t *testing.T) {
+	// basic test with a nil config
+	c := NewEmptyConfig()
+	got := c.ProviderTypes()
+	if len(got) != 0 {
+		t.Fatalf("wrong result!\ngot: %#v\nwant: nil\n", got)
+	}
+
+	// config with two provider sources, and one implicit (default) provider
+	cfg, diags := testNestedModuleConfigFromDir(t, "testdata/valid-modules/nested-providers-fqns")
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	got = cfg.ProviderTypes()
+	want := []addrs.Provider{
+		addrs.NewProvider(addrs.DefaultProviderRegistryHost, "bar", "test"),
+		addrs.NewProvider(addrs.DefaultProviderRegistryHost, "foo", "test"),
+		addrs.NewDefaultProvider("test"),
+	}
+
+	for _, problem := range deep.Equal(got, want) {
+		t.Error(problem)
+	}
+}
+
+func TestConfigResolveAbsProviderAddr(t *testing.T) {
+	cfg, diags := testModuleConfigFromDir("testdata/providers-explicit-fqn")
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	t.Run("already absolute", func(t *testing.T) {
+		addr := addrs.AbsProviderConfig{
+			Module:   addrs.RootModule,
+			Provider: addrs.NewDefaultProvider("test"),
+			Alias:    "boop",
+		}
+		got := cfg.ResolveAbsProviderAddr(addr, addrs.RootModule)
+		if got, want := got.String(), addr.String(); got != want {
+			t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run("local, implied mapping", func(t *testing.T) {
+		addr := addrs.LocalProviderConfig{
+			LocalName: "implied",
+			Alias:     "boop",
+		}
+		got := cfg.ResolveAbsProviderAddr(addr, addrs.RootModule)
+		want := addrs.AbsProviderConfig{
+			Module:   addrs.RootModule,
+			Provider: addrs.NewDefaultProvider("implied"),
+			Alias:    "boop",
+		}
+		if got, want := got.String(), want.String(); got != want {
+			t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run("local, explicit mapping", func(t *testing.T) {
+		addr := addrs.LocalProviderConfig{
+			LocalName: "foo-test", // this is explicitly set in the config
+			Alias:     "boop",
+		}
+		got := cfg.ResolveAbsProviderAddr(addr, addrs.RootModule)
+		want := addrs.AbsProviderConfig{
+			Module:   addrs.RootModule,
+			Provider: addrs.NewProvider(addrs.DefaultProviderRegistryHost, "foo", "test"),
+			Alias:    "boop",
+		}
+		if got, want := got.String(), want.String(); got != want {
+			t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+}
+
+func TestConfigProviderRequirements(t *testing.T) {
+	cfg, diags := testNestedModuleConfigFromDir(t, "testdata/provider-reqs")
+	// TODO: Version Constraint Deprecation.
+	// Once we've removed the version argument from provider configuration
+	// blocks, this can go back to expected 0 diagnostics.
+	// assertNoDiagnostics(t, diags)
+	assertDiagnosticCount(t, diags, 1)
+	assertDiagnosticSummary(t, diags, "Version constraints inside provider configuration blocks are deprecated")
+
+	tlsProvider := addrs.NewProvider(
+		addrs.DefaultProviderRegistryHost,
+		"hashicorp", "tls",
+	)
+	happycloudProvider := addrs.NewProvider(
+		svchost.Hostname("tf.example.com"),
+		"awesomecorp", "happycloud",
+	)
+	nullProvider := addrs.NewDefaultProvider("null")
+	randomProvider := addrs.NewDefaultProvider("random")
+	impliedProvider := addrs.NewDefaultProvider("implied")
+	terraformProvider := addrs.NewBuiltInProvider("terraform")
+	configuredProvider := addrs.NewDefaultProvider("configured")
+	grandchildProvider := addrs.NewDefaultProvider("grandchild")
+
+	got, diags := cfg.ProviderRequirements()
+	assertNoDiagnostics(t, diags)
+	want := getproviders.Requirements{
+		// the nullProvider constraints from the two modules are merged
+		nullProvider:       getproviders.MustParseVersionConstraints("~> 2.0.0, 2.0.1"),
+		randomProvider:     getproviders.MustParseVersionConstraints("~> 1.2.0"),
+		tlsProvider:        getproviders.MustParseVersionConstraints("~> 3.0"),
+		configuredProvider: getproviders.MustParseVersionConstraints("~> 1.4"),
+		impliedProvider:    nil,
+		happycloudProvider: nil,
+		terraformProvider:  nil,
+		grandchildProvider: nil,
+	}
+
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Errorf("wrong result\n%s", diff)
+	}
+}
+
+func TestConfigProviderRequirementsDuplicate(t *testing.T) {
+	_, diags := testNestedModuleConfigFromDir(t, "testdata/duplicate-local-name")
+	assertDiagnosticCount(t, diags, 3)
+	assertDiagnosticSummary(t, diags, "Duplicate required provider")
+}
+
+func TestConfigProviderRequirementsShallow(t *testing.T) {
+	cfg, diags := testNestedModuleConfigFromDir(t, "testdata/provider-reqs")
+	// TODO: Version Constraint Deprecation.
+	// Once we've removed the version argument from provider configuration
+	// blocks, this can go back to expected 0 diagnostics.
+	// assertNoDiagnostics(t, diags)
+	assertDiagnosticCount(t, diags, 1)
+	assertDiagnosticSummary(t, diags, "Version constraints inside provider configuration blocks are deprecated")
+
+	tlsProvider := addrs.NewProvider(
+		addrs.DefaultProviderRegistryHost,
+		"hashicorp", "tls",
+	)
+	nullProvider := addrs.NewDefaultProvider("null")
+	randomProvider := addrs.NewDefaultProvider("random")
+	impliedProvider := addrs.NewDefaultProvider("implied")
+	terraformProvider := addrs.NewBuiltInProvider("terraform")
+	configuredProvider := addrs.NewDefaultProvider("configured")
+
+	got, diags := cfg.ProviderRequirementsShallow()
+	assertNoDiagnostics(t, diags)
+	want := getproviders.Requirements{
+		// the nullProvider constraint is only from the root module
+		nullProvider:       getproviders.MustParseVersionConstraints("~> 2.0.0"),
+		randomProvider:     getproviders.MustParseVersionConstraints("~> 1.2.0"),
+		tlsProvider:        getproviders.MustParseVersionConstraints("~> 3.0"),
+		configuredProvider: getproviders.MustParseVersionConstraints("~> 1.4"),
+		impliedProvider:    nil,
+		terraformProvider:  nil,
+	}
+
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Errorf("wrong result\n%s", diff)
+	}
+}
+
+func TestConfigProviderRequirementsByModule(t *testing.T) {
+	cfg, diags := testNestedModuleConfigFromDir(t, "testdata/provider-reqs")
+	// TODO: Version Constraint Deprecation.
+	// Once we've removed the version argument from provider configuration
+	// blocks, this can go back to expected 0 diagnostics.
+	// assertNoDiagnostics(t, diags)
+	assertDiagnosticCount(t, diags, 1)
+	assertDiagnosticSummary(t, diags, "Version constraints inside provider configuration blocks are deprecated")
+
+	tlsProvider := addrs.NewProvider(
+		addrs.DefaultProviderRegistryHost,
+		"hashicorp", "tls",
+	)
+	happycloudProvider := addrs.NewProvider(
+		svchost.Hostname("tf.example.com"),
+		"awesomecorp", "happycloud",
+	)
+	nullProvider := addrs.NewDefaultProvider("null")
+	randomProvider := addrs.NewDefaultProvider("random")
+	impliedProvider := addrs.NewDefaultProvider("implied")
+	terraformProvider := addrs.NewBuiltInProvider("terraform")
+	configuredProvider := addrs.NewDefaultProvider("configured")
+	grandchildProvider := addrs.NewDefaultProvider("grandchild")
+
+	got, diags := cfg.ProviderRequirementsByModule()
+	assertNoDiagnostics(t, diags)
+	want := &ModuleRequirements{
+		Name:       "",
+		SourceAddr: nil,
+		SourceDir:  "testdata/provider-reqs",
+		Requirements: getproviders.Requirements{
+			// Only the root module's version is present here
+			nullProvider:       getproviders.MustParseVersionConstraints("~> 2.0.0"),
+			randomProvider:     getproviders.MustParseVersionConstraints("~> 1.2.0"),
+			tlsProvider:        getproviders.MustParseVersionConstraints("~> 3.0"),
+			configuredProvider: getproviders.MustParseVersionConstraints("~> 1.4"),
+			impliedProvider:    nil,
+			terraformProvider:  nil,
+		},
+		Children: map[string]*ModuleRequirements{
+			"kinder": {
+				Name:       "kinder",
+				SourceAddr: addrs.ModuleSourceLocal("./child"),
+				SourceDir:  "testdata/provider-reqs/child",
+				Requirements: getproviders.Requirements{
+					nullProvider:       getproviders.MustParseVersionConstraints("= 2.0.1"),
+					happycloudProvider: nil,
+				},
+				Children: map[string]*ModuleRequirements{
+					"nested": {
+						Name:       "nested",
+						SourceAddr: addrs.ModuleSourceLocal("./grandchild"),
+						SourceDir:  "testdata/provider-reqs/child/grandchild",
+						Requirements: getproviders.Requirements{
+							grandchildProvider: nil,
+						},
+						Children: map[string]*ModuleRequirements{},
+					},
+				},
+			},
+		},
+	}
+
+	ignore := cmpopts.IgnoreUnexported(version.Constraint{}, cty.Value{}, hclsyntax.Body{})
+	if diff := cmp.Diff(want, got, ignore); diff != "" {
+		t.Errorf("wrong result\n%s", diff)
+	}
+}
+
+func TestVerifyDependencySelections(t *testing.T) {
+	cfg, diags := testNestedModuleConfigFromDir(t, "testdata/provider-reqs")
+	// TODO: Version Constraint Deprecation.
+	// Once we've removed the version argument from provider configuration
+	// blocks, this can go back to expected 0 diagnostics.
+	// assertNoDiagnostics(t, diags)
+	assertDiagnosticCount(t, diags, 1)
+	assertDiagnosticSummary(t, diags, "Version constraints inside provider configuration blocks are deprecated")
+
+	tlsProvider := addrs.NewProvider(
+		addrs.DefaultProviderRegistryHost,
+		"hashicorp", "tls",
+	)
+	happycloudProvider := addrs.NewProvider(
+		svchost.Hostname("tf.example.com"),
+		"awesomecorp", "happycloud",
+	)
+	nullProvider := addrs.NewDefaultProvider("null")
+	randomProvider := addrs.NewDefaultProvider("random")
+	impliedProvider := addrs.NewDefaultProvider("implied")
+	configuredProvider := addrs.NewDefaultProvider("configured")
+	grandchildProvider := addrs.NewDefaultProvider("grandchild")
+
+	tests := map[string]struct {
+		PrepareLocks func(*depsfile.Locks)
+		WantErrs     []string
+	}{
+		"empty locks": {
+			func(*depsfile.Locks) {
+				// Intentionally blank
+			},
+			[]string{
+				`provider registry.terraform.io/hashicorp/configured: required by this configuration but no version is selected`,
+				`provider registry.terraform.io/hashicorp/grandchild: required by this configuration but no version is selected`,
+				`provider registry.terraform.io/hashicorp/implied: required by this configuration but no version is selected`,
+				`provider registry.terraform.io/hashicorp/null: required by this configuration but no version is selected`,
+				`provider registry.terraform.io/hashicorp/random: required by this configuration but no version is selected`,
+				`provider registry.terraform.io/hashicorp/tls: required by this configuration but no version is selected`,
+				`provider tf.example.com/awesomecorp/happycloud: required by this configuration but no version is selected`,
+			},
+		},
+		"suitable locks": {
+			func(locks *depsfile.Locks) {
+				locks.SetProvider(configuredProvider, getproviders.MustParseVersion("1.4.0"), nil, nil)
+				locks.SetProvider(grandchildProvider, getproviders.MustParseVersion("0.1.0"), nil, nil)
+				locks.SetProvider(impliedProvider, getproviders.MustParseVersion("0.2.0"), nil, nil)
+				locks.SetProvider(nullProvider, getproviders.MustParseVersion("2.0.1"), nil, nil)
+				locks.SetProvider(randomProvider, getproviders.MustParseVersion("1.2.2"), nil, nil)
+				locks.SetProvider(tlsProvider, getproviders.MustParseVersion("3.0.1"), nil, nil)
+				locks.SetProvider(happycloudProvider, getproviders.MustParseVersion("0.0.1"), nil, nil)
+			},
+			nil,
+		},
+		"null provider constraints changed": {
+			func(locks *depsfile.Locks) {
+				locks.SetProvider(configuredProvider, getproviders.MustParseVersion("1.4.0"), nil, nil)
+				locks.SetProvider(grandchildProvider, getproviders.MustParseVersion("0.1.0"), nil, nil)
+				locks.SetProvider(impliedProvider, getproviders.MustParseVersion("0.2.0"), nil, nil)
+				locks.SetProvider(nullProvider, getproviders.MustParseVersion("3.0.0"), nil, nil)
+				locks.SetProvider(randomProvider, getproviders.MustParseVersion("1.2.2"), nil, nil)
+				locks.SetProvider(tlsProvider, getproviders.MustParseVersion("3.0.1"), nil, nil)
+				locks.SetProvider(happycloudProvider, getproviders.MustParseVersion("0.0.1"), nil, nil)
+			},
+			[]string{
+				`provider registry.terraform.io/hashicorp/null: locked version selection 3.0.0 doesn't match the updated version constraints "~> 2.0.0, 2.0.1"`,
+			},
+		},
+		"null provider lock changed": {
+			func(locks *depsfile.Locks) {
+				// In this case, we set the lock file version constraints to
+				// match the configuration, and so our error message changes
+				// to not assume the configuration changed anymore.
+				locks.SetProvider(nullProvider, getproviders.MustParseVersion("3.0.0"), getproviders.MustParseVersionConstraints("~> 2.0.0, 2.0.1"), nil)
+
+				locks.SetProvider(configuredProvider, getproviders.MustParseVersion("1.4.0"), nil, nil)
+				locks.SetProvider(grandchildProvider, getproviders.MustParseVersion("0.1.0"), nil, nil)
+				locks.SetProvider(impliedProvider, getproviders.MustParseVersion("0.2.0"), nil, nil)
+				locks.SetProvider(randomProvider, getproviders.MustParseVersion("1.2.2"), nil, nil)
+				locks.SetProvider(tlsProvider, getproviders.MustParseVersion("3.0.1"), nil, nil)
+				locks.SetProvider(happycloudProvider, getproviders.MustParseVersion("0.0.1"), nil, nil)
+			},
+			[]string{
+				`provider registry.terraform.io/hashicorp/null: version constraints "~> 2.0.0, 2.0.1" don't match the locked version selection 3.0.0`,
+			},
+		},
+		"overridden provider": {
+			func(locks *depsfile.Locks) {
+				locks.SetProviderOverridden(happycloudProvider)
+			},
+			[]string{
+				// We still catch all of the other ones, because only happycloud was overridden
+				`provider registry.terraform.io/hashicorp/configured: required by this configuration but no version is selected`,
+				`provider registry.terraform.io/hashicorp/grandchild: required by this configuration but no version is selected`,
+				`provider registry.terraform.io/hashicorp/implied: required by this configuration but no version is selected`,
+				`provider registry.terraform.io/hashicorp/null: required by this configuration but no version is selected`,
+				`provider registry.terraform.io/hashicorp/random: required by this configuration but no version is selected`,
+				`provider registry.terraform.io/hashicorp/tls: required by this configuration but no version is selected`,
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			depLocks := depsfile.NewLocks()
+			test.PrepareLocks(depLocks)
+			gotErrs := cfg.VerifyDependencySelections(depLocks)
+
+			var gotErrsStr []string
+			if gotErrs != nil {
+				gotErrsStr = make([]string, len(gotErrs))
+				for i, err := range gotErrs {
+					gotErrsStr[i] = err.Error()
+				}
+			}
+
+			if diff := cmp.Diff(test.WantErrs, gotErrsStr); diff != "" {
+				t.Errorf("wrong errors\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestConfigProviderForConfigAddr(t *testing.T) {
+	cfg, diags := testModuleConfigFromDir("testdata/valid-modules/providers-fqns")
+	assertNoDiagnostics(t, diags)
+
+	got := cfg.ProviderForConfigAddr(addrs.NewDefaultLocalProviderConfig("foo-test"))
+	want := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "foo", "test")
+	if !got.Equals(want) {
+		t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+	}
+
+	// now check a provider that isn't in the configuration. It should return a DefaultProvider.
+	got = cfg.ProviderForConfigAddr(addrs.NewDefaultLocalProviderConfig("bar-test"))
+	want = addrs.NewDefaultProvider("bar-test")
+	if !got.Equals(want) {
+		t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+	}
+}
+
+func TestConfigAddProviderRequirements(t *testing.T) {
+	cfg, diags := testModuleConfigFromFile("testdata/valid-files/providers-explicit-implied.tf")
+	assertNoDiagnostics(t, diags)
+
+	reqs := getproviders.Requirements{
+		addrs.NewDefaultProvider("null"): nil,
+	}
+	diags = cfg.addProviderRequirements(reqs, true)
+	assertNoDiagnostics(t, diags)
+}
+
+func TestConfigImportProviderClashesWithModules(t *testing.T) {
+	src, err := os.ReadFile("testdata/invalid-import-files/import-and-module-clash.tf")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	parser := testParser(map[string]string{
+		"main.tf": string(src),
+	})
+
+	_, diags := parser.LoadConfigFile("main.tf")
+	assertExactDiagnostics(t, diags, []string{
+		`main.tf:9,3-19: Invalid import provider argument; The provider argument can only be specified in import blocks that will generate configuration.
+
+Use the providers argument within the module block to configure providers for all resources within a module, including imported resources.`,
+	})
+}
+
+func TestConfigImportProviderClashesWithResources(t *testing.T) {
+	cfg, diags := testModuleConfigFromFile("testdata/invalid-import-files/import-and-resource-clash.tf")
+	assertNoDiagnostics(t, diags)
+
+	diags = cfg.addProviderRequirements(getproviders.Requirements{}, true)
+	assertExactDiagnostics(t, diags, []string{
+		`testdata/invalid-import-files/import-and-resource-clash.tf:9,3-19: Invalid import provider argument; The provider argument can only be specified in import blocks that will generate configuration.
+
+Use the provider argument in the target resource block to configure the provider for a resource with explicit provider configuration.`,
+	})
+}
+
+func TestConfigImportProviderWithNoResourceProvider(t *testing.T) {
+	cfg, diags := testModuleConfigFromFile("testdata/invalid-import-files/import-and-no-resource.tf")
+	assertNoDiagnostics(t, diags)
+
+	diags = cfg.addProviderRequirements(getproviders.Requirements{}, true)
+	assertExactDiagnostics(t, diags, []string{
+		`testdata/invalid-import-files/import-and-no-resource.tf:5,3-19: Invalid import provider argument; The provider argument can only be specified in import blocks that will generate configuration.
+
+Use the provider argument in the target resource block to configure the provider for a resource with explicit provider configuration.`,
+	})
+}
diff --git a/v1.5.7/internal/configs/configload/copy_dir.go b/v1.5.7/internal/configs/configload/copy_dir.go
new file mode 100644
index 0000000..b351f71
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/copy_dir.go
@@ -0,0 +1,118 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configload
+
+import (
+	"io"
+	"os"
+	"path/filepath"
+)
+
+// copyDir copies the src directory contents into dst. Both directories
+// should already exist.
+func copyDir(dst, src string) error {
+	src, err := filepath.EvalSymlinks(src)
+	if err != nil {
+		return err
+	}
+
+	walkFn := func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+
+		if path == src {
+			return nil
+		}
+
+		// The "path" has the src prefixed to it. We need to join our
+		// destination with the path without the src on it.
+		dstPath := filepath.Join(dst, path[len(src):])
+
+		// we don't want to try and copy the same file over itself.
+		if eq, err := sameFile(path, dstPath); eq {
+			return nil
+		} else if err != nil {
+			return err
+		}
+
+		// If we have a directory, make that subdirectory, then continue
+		// the walk.
+		if info.IsDir() {
+			if path == filepath.Join(src, dst) {
+				// dst is in src; don't walk it.
+				return nil
+			}
+
+			if err := os.MkdirAll(dstPath, 0755); err != nil {
+				return err
+			}
+
+			return nil
+		}
+
+		// If the current path is a symlink, recreate the symlink relative to
+		// the dst directory
+		if info.Mode()&os.ModeSymlink == os.ModeSymlink {
+			target, err := os.Readlink(path)
+			if err != nil {
+				return err
+			}
+
+			return os.Symlink(target, dstPath)
+		}
+
+		// If we have a file, copy the contents.
+		srcF, err := os.Open(path)
+		if err != nil {
+			return err
+		}
+		defer srcF.Close()
+
+		dstF, err := os.Create(dstPath)
+		if err != nil {
+			return err
+		}
+		defer dstF.Close()
+
+		if _, err := io.Copy(dstF, srcF); err != nil {
+			return err
+		}
+
+		// Chmod it
+		return os.Chmod(dstPath, info.Mode())
+	}
+
+	return filepath.Walk(src, walkFn)
+}
+
+// sameFile tried to determine if to paths are the same file.
+// If the paths don't match, we lookup the inode on supported systems.
+func sameFile(a, b string) (bool, error) {
+	if a == b {
+		return true, nil
+	}
+
+	aIno, err := inode(a)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return false, nil
+		}
+		return false, err
+	}
+
+	bIno, err := inode(b)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return false, nil
+		}
+		return false, err
+	}
+
+	if aIno > 0 && aIno == bIno {
+		return true, nil
+	}
+
+	return false, nil
+}
diff --git a/v1.5.7/internal/configs/configload/copy_dir_test.go b/v1.5.7/internal/configs/configload/copy_dir_test.go
new file mode 100644
index 0000000..689a78e
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/copy_dir_test.go
@@ -0,0 +1,102 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configload
+
+import (
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"testing"
+)
+
+// TestCopyDir_symlinks sets up a directory with two submodules,
+// one being a symlink to the other
+//
+// The resultant file structure is as follows:
+// 	├── modules
+//  │   ├── symlink-module -> test-module
+//  │   └── test-module
+//  │       └── main.tf
+//  └── target
+//     ├── symlink-module -> test-module
+//     └── test-module
+//         └── main.tf
+
+func TestCopyDir_symlinks(t *testing.T) {
+	tmpdir := t.TempDir()
+
+	moduleDir := filepath.Join(tmpdir, "modules")
+	err := os.Mkdir(moduleDir, os.ModePerm)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	subModuleDir := filepath.Join(moduleDir, "test-module")
+	err = os.Mkdir(subModuleDir, os.ModePerm)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = ioutil.WriteFile(filepath.Join(subModuleDir, "main.tf"), []byte("hello"), 0644)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = os.Symlink("test-module", filepath.Join(moduleDir, "symlink-module"))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	targetDir := filepath.Join(tmpdir, "target")
+	os.Mkdir(targetDir, os.ModePerm)
+
+	err = copyDir(targetDir, moduleDir)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err = os.Lstat(filepath.Join(targetDir, "test-module", "main.tf")); os.IsNotExist(err) {
+		t.Fatal("target test-module/main.tf was not created")
+	}
+
+	if _, err = os.Lstat(filepath.Join(targetDir, "symlink-module", "main.tf")); os.IsNotExist(err) {
+		t.Fatal("target symlink-module/main.tf was not created")
+	}
+}
+
+func TestCopyDir_symlink_file(t *testing.T) {
+	tmpdir := t.TempDir()
+
+	moduleDir := filepath.Join(tmpdir, "modules")
+	err := os.Mkdir(moduleDir, os.ModePerm)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = ioutil.WriteFile(filepath.Join(moduleDir, "main.tf"), []byte("hello"), 0644)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = os.Symlink("main.tf", filepath.Join(moduleDir, "symlink.tf"))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	targetDir := filepath.Join(tmpdir, "target")
+	os.Mkdir(targetDir, os.ModePerm)
+
+	err = copyDir(targetDir, moduleDir)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err = os.Lstat(filepath.Join(targetDir, "main.tf")); os.IsNotExist(err) {
+		t.Fatal("target/main.tf was not created")
+	}
+
+	if _, err = os.Lstat(filepath.Join(targetDir, "symlink.tf")); os.IsNotExist(err) {
+		t.Fatal("target/symlink.tf was not created")
+	}
+}
diff --git a/v1.5.7/internal/configs/configload/doc.go b/v1.5.7/internal/configs/configload/doc.go
new file mode 100644
index 0000000..a3ac60e
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/doc.go
@@ -0,0 +1,7 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package configload knows how to install modules into the .terraform/modules
+// directory and to load modules from those installed locations. It is used
+// in conjunction with the LoadConfig function in the parent package.
+package configload
diff --git a/v1.5.7/internal/configs/configload/inode.go b/v1.5.7/internal/configs/configload/inode.go
new file mode 100644
index 0000000..95bae2b
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/inode.go
@@ -0,0 +1,25 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build linux || darwin || openbsd || netbsd || solaris || dragonfly
+// +build linux darwin openbsd netbsd solaris dragonfly
+
+package configload
+
+import (
+	"fmt"
+	"os"
+	"syscall"
+)
+
+// lookup the inode of a file on posix systems
+func inode(path string) (uint64, error) {
+	stat, err := os.Stat(path)
+	if err != nil {
+		return 0, err
+	}
+	if st, ok := stat.Sys().(*syscall.Stat_t); ok {
+		return st.Ino, nil
+	}
+	return 0, fmt.Errorf("could not determine file inode")
+}
diff --git a/v1.5.7/internal/configs/configload/inode_freebsd.go b/v1.5.7/internal/configs/configload/inode_freebsd.go
new file mode 100644
index 0000000..d7f1051
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/inode_freebsd.go
@@ -0,0 +1,25 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build freebsd
+// +build freebsd
+
+package configload
+
+import (
+	"fmt"
+	"os"
+	"syscall"
+)
+
+// lookup the inode of a file on posix systems
+func inode(path string) (uint64, error) {
+	stat, err := os.Stat(path)
+	if err != nil {
+		return 0, err
+	}
+	if st, ok := stat.Sys().(*syscall.Stat_t); ok {
+		return uint64(st.Ino), nil
+	}
+	return 0, fmt.Errorf("could not determine file inode")
+}
diff --git a/v1.5.7/internal/configs/configload/inode_windows.go b/v1.5.7/internal/configs/configload/inode_windows.go
new file mode 100644
index 0000000..c424fb0
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/inode_windows.go
@@ -0,0 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build windows
+// +build windows
+
+package configload
+
+// no syscall.Stat_t on windows, return 0 for inodes
+func inode(path string) (uint64, error) {
+	return 0, nil
+}
diff --git a/v1.5.7/internal/configs/configload/loader.go b/v1.5.7/internal/configs/configload/loader.go
new file mode 100644
index 0000000..22e833d
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/loader.go
@@ -0,0 +1,166 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configload
+
+import (
+	"fmt"
+	"path/filepath"
+
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/registry"
+	"github.com/spf13/afero"
+)
+
+// A Loader instance is the main entry-point for loading configurations via
+// this package.
+//
+// It extends the general config-loading functionality in the parent package
+// "configs" to support installation of modules from remote sources and
+// loading full configurations using modules that were previously installed.
+type Loader struct {
+	// parser is used to read configuration
+	parser *configs.Parser
+
+	// modules is used to install and locate descendent modules that are
+	// referenced (directly or indirectly) from the root module.
+	modules moduleMgr
+}
+
+// Config is used with NewLoader to specify configuration arguments for the
+// loader.
+type Config struct {
+	// ModulesDir is a path to a directory where descendent modules are
+	// (or should be) installed. (This is usually the
+	// .terraform/modules directory, in the common case where this package
+	// is being loaded from the main Terraform CLI package.)
+	ModulesDir string
+
+	// Services is the service discovery client to use when locating remote
+	// module registry endpoints. If this is nil then registry sources are
+	// not supported, which should be true only in specialized circumstances
+	// such as in tests.
+	Services *disco.Disco
+}
+
+// NewLoader creates and returns a loader that reads configuration from the
+// real OS filesystem.
+//
+// The loader has some internal state about the modules that are currently
+// installed, which is read from disk as part of this function. If that
+// manifest cannot be read then an error will be returned.
+func NewLoader(config *Config) (*Loader, error) {
+	fs := afero.NewOsFs()
+	parser := configs.NewParser(fs)
+	reg := registry.NewClient(config.Services, nil)
+
+	ret := &Loader{
+		parser: parser,
+		modules: moduleMgr{
+			FS:         afero.Afero{Fs: fs},
+			CanInstall: true,
+			Dir:        config.ModulesDir,
+			Services:   config.Services,
+			Registry:   reg,
+		},
+	}
+
+	err := ret.modules.readModuleManifestSnapshot()
+	if err != nil {
+		return nil, fmt.Errorf("failed to read module manifest: %s", err)
+	}
+
+	return ret, nil
+}
+
+// ModulesDir returns the path to the directory where the loader will look for
+// the local cache of remote module packages.
+func (l *Loader) ModulesDir() string {
+	return l.modules.Dir
+}
+
+// RefreshModules updates the in-memory cache of the module manifest from the
+// module manifest file on disk. This is not necessary in normal use because
+// module installation and configuration loading are separate steps, but it
+// can be useful in tests where module installation is done as a part of
+// configuration loading by a helper function.
+//
+// Call this function after any module installation where an existing loader
+// is already alive and may be used again later.
+//
+// An error is returned if the manifest file cannot be read.
+func (l *Loader) RefreshModules() error {
+	if l == nil {
+		// Nothing to do, then.
+		return nil
+	}
+	return l.modules.readModuleManifestSnapshot()
+}
+
+// Parser returns the underlying parser for this loader.
+//
+// This is useful for loading other sorts of files than the module directories
+// that a loader deals with, since then they will share the source code cache
+// for this loader and can thus be shown as snippets in diagnostic messages.
+func (l *Loader) Parser() *configs.Parser {
+	return l.parser
+}
+
+// Sources returns the source code cache for the underlying parser of this
+// loader. This is a shorthand for l.Parser().Sources().
+func (l *Loader) Sources() map[string][]byte {
+	return l.parser.Sources()
+}
+
+// IsConfigDir returns true if and only if the given directory contains at
+// least one Terraform configuration file. This is a wrapper around calling
+// the same method name on the loader's parser.
+func (l *Loader) IsConfigDir(path string) bool {
+	return l.parser.IsConfigDir(path)
+}
+
+// ImportSources writes into the receiver's source code map the given source
+// code buffers.
+//
+// This is useful in the situation where an ancillary loader is created for
+// some reason (e.g. loading config from a plan file) but the cached source
+// code from that loader must be imported into the "main" loader in order
+// to return source code snapshots in diagnostic messages.
+//
+//	loader.ImportSources(otherLoader.Sources())
+func (l *Loader) ImportSources(sources map[string][]byte) {
+	p := l.Parser()
+	for name, src := range sources {
+		p.ForceFileSource(name, src)
+	}
+}
+
+// ImportSourcesFromSnapshot writes into the receiver's source code the
+// source files from the given snapshot.
+//
+// This is similar to ImportSources but knows how to unpack and flatten a
+// snapshot data structure to get the corresponding flat source file map.
+func (l *Loader) ImportSourcesFromSnapshot(snap *Snapshot) {
+	p := l.Parser()
+	for _, m := range snap.Modules {
+		baseDir := m.Dir
+		for fn, src := range m.Files {
+			fullPath := filepath.Join(baseDir, fn)
+			p.ForceFileSource(fullPath, src)
+		}
+	}
+}
+
+// AllowLanguageExperiments specifies whether subsequent LoadConfig (and
+// similar) calls will allow opting in to experimental language features.
+//
+// If this method is never called for a particular loader, the default behavior
+// is to disallow language experiments.
+//
+// Main code should set this only for alpha or development builds. Test code
+// is responsible for deciding for itself whether and how to call this
+// method.
+func (l *Loader) AllowLanguageExperiments(allowed bool) {
+	l.parser.AllowLanguageExperiments(allowed)
+}
diff --git a/v1.5.7/internal/configs/configload/loader_load.go b/v1.5.7/internal/configs/configload/loader_load.go
new file mode 100644
index 0000000..1dd4c95
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/loader_load.go
@@ -0,0 +1,116 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configload
+
+import (
+	"fmt"
+
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/configs"
+)
+
+// LoadConfig reads the Terraform module in the given directory and uses it as the
+// root module to build the static module tree that represents a configuration,
+// assuming that all required descendent modules have already been installed.
+//
+// If error diagnostics are returned, the returned configuration may be either
+// nil or incomplete. In the latter case, cautious static analysis is possible
+// in spite of the errors.
+//
+// LoadConfig performs the basic syntax and uniqueness validations that are
+// required to process the individual modules
+func (l *Loader) LoadConfig(rootDir string) (*configs.Config, hcl.Diagnostics) {
+	rootMod, diags := l.parser.LoadConfigDir(rootDir)
+	if rootMod == nil || diags.HasErrors() {
+		// Ensure we return any parsed modules here so that required_version
+		// constraints can be verified even when encountering errors.
+		cfg := &configs.Config{
+			Module: rootMod,
+		}
+
+		return cfg, diags
+	}
+
+	cfg, cDiags := configs.BuildConfig(rootMod, configs.ModuleWalkerFunc(l.moduleWalkerLoad))
+	diags = append(diags, cDiags...)
+
+	return cfg, diags
+}
+
+// moduleWalkerLoad is a configs.ModuleWalkerFunc for loading modules that
+// are presumed to have already been installed.
+func (l *Loader) moduleWalkerLoad(req *configs.ModuleRequest) (*configs.Module, *version.Version, hcl.Diagnostics) {
+	// Since we're just loading here, we expect that all referenced modules
+	// will be already installed and described in our manifest. However, we
+	// do verify that the manifest and the configuration are in agreement
+	// so that we can prompt the user to run "terraform init" if not.
+
+	key := l.modules.manifest.ModuleKey(req.Path)
+	record, exists := l.modules.manifest[key]
+
+	if !exists {
+		return nil, nil, hcl.Diagnostics{
+			{
+				Severity: hcl.DiagError,
+				Summary:  "Module not installed",
+				Detail:   "This module is not yet installed. Run \"terraform init\" to install all modules required by this configuration.",
+				Subject:  &req.CallRange,
+			},
+		}
+	}
+
+	var diags hcl.Diagnostics
+
+	// Check for inconsistencies between manifest and config.
+
+	// We ignore a nil SourceAddr here, which represents a failure during
+	// configuration parsing, and will be reported in a diagnostic elsewhere.
+	if req.SourceAddr != nil && req.SourceAddr.String() != record.SourceAddr {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Module source has changed",
+			Detail:   "The source address was changed since this module was installed. Run \"terraform init\" to install all modules required by this configuration.",
+			Subject:  &req.SourceAddrRange,
+		})
+	}
+	if len(req.VersionConstraint.Required) > 0 && record.Version == nil {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Module version requirements have changed",
+			Detail:   "The version requirements have changed since this module was installed and the installed version is no longer acceptable. Run \"terraform init\" to install all modules required by this configuration.",
+			Subject:  &req.SourceAddrRange,
+		})
+	}
+	if record.Version != nil && !req.VersionConstraint.Required.Check(record.Version) {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Module version requirements have changed",
+			Detail: fmt.Sprintf(
+				"The version requirements have changed since this module was installed and the installed version (%s) is no longer acceptable. Run \"terraform init\" to install all modules required by this configuration.",
+				record.Version,
+			),
+			Subject: &req.SourceAddrRange,
+		})
+	}
+
+	mod, mDiags := l.parser.LoadConfigDir(record.Dir)
+	diags = append(diags, mDiags...)
+	if mod == nil {
+		// nil specifically indicates that the directory does not exist or
+		// cannot be read, so in this case we'll discard any generic diagnostics
+		// returned from LoadConfigDir and produce our own context-sensitive
+		// error message.
+		return nil, nil, hcl.Diagnostics{
+			{
+				Severity: hcl.DiagError,
+				Summary:  "Module not installed",
+				Detail:   fmt.Sprintf("This module's local cache directory %s could not be read. Run \"terraform init\" to install all modules required by this configuration.", record.Dir),
+				Subject:  &req.CallRange,
+			},
+		}
+	}
+
+	return mod, record.Version, diags
+}
diff --git a/v1.5.7/internal/configs/configload/loader_load_test.go b/v1.5.7/internal/configs/configload/loader_load_test.go
new file mode 100644
index 0000000..5e68fbd
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/loader_load_test.go
@@ -0,0 +1,210 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configload
+
+import (
+	"path/filepath"
+	"reflect"
+	"sort"
+	"strings"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs"
+)
+
+func TestLoaderLoadConfig_okay(t *testing.T) {
+	fixtureDir := filepath.Clean("testdata/already-installed")
+	loader, err := NewLoader(&Config{
+		ModulesDir: filepath.Join(fixtureDir, ".terraform/modules"),
+	})
+	if err != nil {
+		t.Fatalf("unexpected error from NewLoader: %s", err)
+	}
+
+	cfg, diags := loader.LoadConfig(fixtureDir)
+	assertNoDiagnostics(t, diags)
+	if cfg == nil {
+		t.Fatalf("config is nil; want non-nil")
+	}
+
+	var gotPaths []string
+	cfg.DeepEach(func(c *configs.Config) {
+		gotPaths = append(gotPaths, strings.Join(c.Path, "."))
+	})
+	sort.Strings(gotPaths)
+	wantPaths := []string{
+		"", // root module
+		"child_a",
+		"child_a.child_c",
+		"child_b",
+		"child_b.child_d",
+	}
+
+	if !reflect.DeepEqual(gotPaths, wantPaths) {
+		t.Fatalf("wrong module paths\ngot: %swant %s", spew.Sdump(gotPaths), spew.Sdump(wantPaths))
+	}
+
+	t.Run("child_a.child_c output", func(t *testing.T) {
+		output := cfg.Children["child_a"].Children["child_c"].Module.Outputs["hello"]
+		got, diags := output.Expr.Value(nil)
+		assertNoDiagnostics(t, diags)
+		assertResultCtyEqual(t, got, cty.StringVal("Hello from child_c"))
+	})
+	t.Run("child_b.child_d output", func(t *testing.T) {
+		output := cfg.Children["child_b"].Children["child_d"].Module.Outputs["hello"]
+		got, diags := output.Expr.Value(nil)
+		assertNoDiagnostics(t, diags)
+		assertResultCtyEqual(t, got, cty.StringVal("Hello from child_d"))
+	})
+}
+
+func TestLoaderLoadConfig_addVersion(t *testing.T) {
+	// This test is for what happens when there is a version constraint added
+	// to a module that previously didn't have one.
+	fixtureDir := filepath.Clean("testdata/add-version-constraint")
+	loader, err := NewLoader(&Config{
+		ModulesDir: filepath.Join(fixtureDir, ".terraform/modules"),
+	})
+	if err != nil {
+		t.Fatalf("unexpected error from NewLoader: %s", err)
+	}
+
+	_, diags := loader.LoadConfig(fixtureDir)
+	if !diags.HasErrors() {
+		t.Fatalf("success; want error")
+	}
+	got := diags.Error()
+	want := "Module version requirements have changed"
+	if !strings.Contains(got, want) {
+		t.Fatalf("wrong error\ngot:\n%s\n\nwant: containing %q", got, want)
+	}
+}
+
+func TestLoaderLoadConfig_loadDiags(t *testing.T) {
+	// building a config which didn't load correctly may cause configs to panic
+	fixtureDir := filepath.Clean("testdata/invalid-names")
+	loader, err := NewLoader(&Config{
+		ModulesDir: filepath.Join(fixtureDir, ".terraform/modules"),
+	})
+	if err != nil {
+		t.Fatalf("unexpected error from NewLoader: %s", err)
+	}
+
+	cfg, diags := loader.LoadConfig(fixtureDir)
+	if !diags.HasErrors() {
+		t.Fatal("success; want error")
+	}
+
+	if cfg == nil {
+		t.Fatal("partial config not returned with diagnostics")
+	}
+
+	if cfg.Module == nil {
+		t.Fatal("expected config module")
+	}
+}
+
+func TestLoaderLoadConfig_loadDiagsFromSubmodules(t *testing.T) {
+	// building a config which didn't load correctly may cause configs to panic
+	fixtureDir := filepath.Clean("testdata/invalid-names-in-submodules")
+	loader, err := NewLoader(&Config{
+		ModulesDir: filepath.Join(fixtureDir, ".terraform/modules"),
+	})
+	if err != nil {
+		t.Fatalf("unexpected error from NewLoader: %s", err)
+	}
+
+	cfg, diags := loader.LoadConfig(fixtureDir)
+	if !diags.HasErrors() {
+		t.Fatalf("loading succeeded; want an error")
+	}
+	if got, want := diags.Error(), " Invalid provider local name"; !strings.Contains(got, want) {
+		t.Errorf("missing expected error\nwant substring: %s\ngot: %s", want, got)
+	}
+
+	if cfg == nil {
+		t.Fatal("partial config not returned with diagnostics")
+	}
+
+	if cfg.Module == nil {
+		t.Fatal("expected config module")
+	}
+}
+
+func TestLoaderLoadConfig_childProviderGrandchildCount(t *testing.T) {
+	// This test is focused on the specific situation where:
+	// - A child module contains a nested provider block, which is no longer
+	//   recommended but supported for backward-compatibility.
+	// - A child of that child does _not_ contain a nested provider block,
+	//   and is called with "count" (would also apply to "for_each" and
+	//   "depends_on").
+	// It isn't valid to use "count" with a module that _itself_ contains
+	// a provider configuration, but it _is_ valid for a module with a
+	// provider configuration to call another module with count. We previously
+	// botched this rule and so this is a regression test to cover the
+	// solution to that mistake:
+	//     https://github.com/hashicorp/terraform/issues/31081
+
+	// Since this test is based on success rather than failure and it's
+	// covering a relatively large set of code where only a small part
+	// contributes to the test, we'll make sure to test both the success and
+	// failure cases here so that we'll have a better chance of noticing if a
+	// future change makes this succeed only because we've reorganized the code
+	// so that the check isn't happening at all anymore.
+	//
+	// If the "not okay" subtest fails, you should also be skeptical about
+	// whether the "okay" subtest is still valid, even if it happens to
+	// still be passing.
+	t.Run("okay", func(t *testing.T) {
+		fixtureDir := filepath.Clean("testdata/child-provider-grandchild-count")
+		loader, err := NewLoader(&Config{
+			ModulesDir: filepath.Join(fixtureDir, ".terraform/modules"),
+		})
+		if err != nil {
+			t.Fatalf("unexpected error from NewLoader: %s", err)
+		}
+
+		cfg, diags := loader.LoadConfig(fixtureDir)
+		assertNoDiagnostics(t, diags)
+		if cfg == nil {
+			t.Fatalf("config is nil; want non-nil")
+		}
+
+		var gotPaths []string
+		cfg.DeepEach(func(c *configs.Config) {
+			gotPaths = append(gotPaths, strings.Join(c.Path, "."))
+		})
+		sort.Strings(gotPaths)
+		wantPaths := []string{
+			"", // root module
+			"child",
+			"child.grandchild",
+		}
+
+		if !reflect.DeepEqual(gotPaths, wantPaths) {
+			t.Fatalf("wrong module paths\ngot: %swant %s", spew.Sdump(gotPaths), spew.Sdump(wantPaths))
+		}
+	})
+	t.Run("not okay", func(t *testing.T) {
+		fixtureDir := filepath.Clean("testdata/child-provider-child-count")
+		loader, err := NewLoader(&Config{
+			ModulesDir: filepath.Join(fixtureDir, ".terraform/modules"),
+		})
+		if err != nil {
+			t.Fatalf("unexpected error from NewLoader: %s", err)
+		}
+
+		_, diags := loader.LoadConfig(fixtureDir)
+		if !diags.HasErrors() {
+			t.Fatalf("loading succeeded; want an error")
+		}
+		if got, want := diags.Error(), "Module is incompatible with count, for_each, and depends_on"; !strings.Contains(got, want) {
+			t.Errorf("missing expected error\nwant substring: %s\ngot: %s", want, got)
+		}
+	})
+
+}
diff --git a/v1.5.7/internal/configs/configload/loader_snapshot.go b/v1.5.7/internal/configs/configload/loader_snapshot.go
new file mode 100644
index 0000000..e4eb4ba
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/loader_snapshot.go
@@ -0,0 +1,507 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configload
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"path/filepath"
+	"sort"
+	"time"
+
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/modsdir"
+	"github.com/spf13/afero"
+)
+
+// LoadConfigWithSnapshot is a variant of LoadConfig that also simultaneously
+// creates an in-memory snapshot of the configuration files used, which can
+// be later used to create a loader that may read only from this snapshot.
+func (l *Loader) LoadConfigWithSnapshot(rootDir string) (*configs.Config, *Snapshot, hcl.Diagnostics) {
+	rootMod, diags := l.parser.LoadConfigDir(rootDir)
+	if rootMod == nil {
+		return nil, nil, diags
+	}
+
+	snap := &Snapshot{
+		Modules: map[string]*SnapshotModule{},
+	}
+	walker := l.makeModuleWalkerSnapshot(snap)
+	cfg, cDiags := configs.BuildConfig(rootMod, walker)
+	diags = append(diags, cDiags...)
+
+	addDiags := l.addModuleToSnapshot(snap, "", rootDir, "", nil)
+	diags = append(diags, addDiags...)
+
+	return cfg, snap, diags
+}
+
+// NewLoaderFromSnapshot creates a Loader that reads files only from the
+// given snapshot.
+//
+// A snapshot-based loader cannot install modules, so calling InstallModules
+// on the return value will cause a panic.
+//
+// A snapshot-based loader also has access only to configuration files. Its
+// underlying parser does not have access to other files in the native
+// filesystem, such as values files. For those, either use a normal loader
+// (created by NewLoader) or use the configs.Parser API directly.
+func NewLoaderFromSnapshot(snap *Snapshot) *Loader {
+	fs := snapshotFS{snap}
+	parser := configs.NewParser(fs)
+
+	ret := &Loader{
+		parser: parser,
+		modules: moduleMgr{
+			FS:         afero.Afero{Fs: fs},
+			CanInstall: false,
+			manifest:   snap.moduleManifest(),
+		},
+	}
+
+	return ret
+}
+
+// Snapshot is an in-memory representation of the source files from a
+// configuration, which can be used as an alternative configurations source
+// for a loader with NewLoaderFromSnapshot.
+//
+// The primary purpose of a Snapshot is to build the configuration portion
+// of a plan file (see ../../plans/planfile) so that it can later be reloaded
+// and used to recover the exact configuration that the plan was built from.
+type Snapshot struct {
+	// Modules is a map from opaque module keys (suitable for use as directory
+	// names on all supported operating systems) to the snapshot information
+	// about each module.
+	Modules map[string]*SnapshotModule
+}
+
+// NewEmptySnapshot constructs and returns a snapshot containing only an empty
+// root module. This is not useful for anything except placeholders in tests.
+func NewEmptySnapshot() *Snapshot {
+	return &Snapshot{
+		Modules: map[string]*SnapshotModule{
+			"": &SnapshotModule{
+				Files: map[string][]byte{},
+			},
+		},
+	}
+}
+
+// SnapshotModule represents a single module within a Snapshot.
+type SnapshotModule struct {
+	// Dir is the path, relative to the root directory given when the
+	// snapshot was created, where the module appears in the snapshot's
+	// virtual filesystem.
+	Dir string
+
+	// Files is a map from each configuration file filename for the
+	// module to a raw byte representation of the source file contents.
+	Files map[string][]byte
+
+	// SourceAddr is the source address given for this module in configuration.
+	SourceAddr string `json:"Source"`
+
+	// Version is the version of the module that is installed, or nil if
+	// the module is installed from a source that does not support versions.
+	Version *version.Version `json:"-"`
+}
+
+// moduleManifest constructs a module manifest based on the contents of
+// the receiving snapshot.
+func (s *Snapshot) moduleManifest() modsdir.Manifest {
+	ret := make(modsdir.Manifest)
+
+	for k, modSnap := range s.Modules {
+		ret[k] = modsdir.Record{
+			Key:        k,
+			Dir:        modSnap.Dir,
+			SourceAddr: modSnap.SourceAddr,
+			Version:    modSnap.Version,
+		}
+	}
+
+	return ret
+}
+
+// makeModuleWalkerSnapshot creates a configs.ModuleWalker that will exhibit
+// the same lookup behaviors as l.moduleWalkerLoad but will additionally write
+// source files from the referenced modules into the given snapshot.
+func (l *Loader) makeModuleWalkerSnapshot(snap *Snapshot) configs.ModuleWalker {
+	return configs.ModuleWalkerFunc(
+		func(req *configs.ModuleRequest) (*configs.Module, *version.Version, hcl.Diagnostics) {
+			mod, v, diags := l.moduleWalkerLoad(req)
+			if diags.HasErrors() {
+				return mod, v, diags
+			}
+
+			key := l.modules.manifest.ModuleKey(req.Path)
+			record, exists := l.modules.manifest[key]
+
+			if !exists {
+				// Should never happen, since otherwise moduleWalkerLoader would've
+				// returned an error and we would've returned already.
+				panic(fmt.Sprintf("module %s is not present in manifest", key))
+			}
+
+			addDiags := l.addModuleToSnapshot(snap, key, record.Dir, record.SourceAddr, record.Version)
+			diags = append(diags, addDiags...)
+
+			return mod, v, diags
+		},
+	)
+}
+
+func (l *Loader) addModuleToSnapshot(snap *Snapshot, key string, dir string, sourceAddr string, v *version.Version) hcl.Diagnostics {
+	var diags hcl.Diagnostics
+
+	primaryFiles, overrideFiles, moreDiags := l.parser.ConfigDirFiles(dir)
+	if moreDiags.HasErrors() {
+		// Any diagnostics we get here should be already present
+		// in diags, so it's weird if we get here but we'll allow it
+		// and return a general error message in that case.
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Failed to read directory for module",
+			Detail:   fmt.Sprintf("The source directory %s could not be read", dir),
+		})
+		return diags
+	}
+
+	snapMod := &SnapshotModule{
+		Dir:        dir,
+		Files:      map[string][]byte{},
+		SourceAddr: sourceAddr,
+		Version:    v,
+	}
+
+	files := make([]string, 0, len(primaryFiles)+len(overrideFiles))
+	files = append(files, primaryFiles...)
+	files = append(files, overrideFiles...)
+	sources := l.Sources() // should be populated with all the files we need by now
+	for _, filePath := range files {
+		filename := filepath.Base(filePath)
+		src, exists := sources[filePath]
+		if !exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Missing source file for snapshot",
+				Detail:   fmt.Sprintf("The source code for file %s could not be found to produce a configuration snapshot.", filePath),
+			})
+			continue
+		}
+		snapMod.Files[filepath.Clean(filename)] = src
+	}
+
+	snap.Modules[key] = snapMod
+
+	return diags
+}
+
+// snapshotFS is an implementation of afero.Fs that reads from a snapshot.
+//
+// This is not intended as a general-purpose filesystem implementation. Instead,
+// it just supports the minimal functionality required to support the
+// configuration loader and parser as an implementation detail of creating
+// a loader from a snapshot.
+type snapshotFS struct {
+	snap *Snapshot
+}
+
+var _ afero.Fs = snapshotFS{}
+
+func (fs snapshotFS) Create(name string) (afero.File, error) {
+	return nil, fmt.Errorf("cannot create file inside configuration snapshot")
+}
+
+func (fs snapshotFS) Mkdir(name string, perm os.FileMode) error {
+	return fmt.Errorf("cannot create directory inside configuration snapshot")
+}
+
+func (fs snapshotFS) MkdirAll(name string, perm os.FileMode) error {
+	return fmt.Errorf("cannot create directories inside configuration snapshot")
+}
+
+func (fs snapshotFS) Open(name string) (afero.File, error) {
+
+	// Our "filesystem" is sparsely populated only with the directories
+	// mentioned by modules in our snapshot, so the high-level process
+	// for opening a file is:
+	// - Find the module snapshot corresponding to the containing directory
+	// - Find the file within that snapshot
+	// - Wrap the resulting byte slice in a snapshotFile to return
+	//
+	// The other possibility handled here is if the given name is for the
+	// module directory itself, in which case we'll return a snapshotDir
+	// instead.
+	//
+	// This function doesn't try to be incredibly robust in supporting
+	// different permutations of paths, etc because in practice we only
+	// need to support the path forms that our own loader and parser will
+	// generate.
+
+	dir := filepath.Dir(name)
+	fn := filepath.Base(name)
+	directDir := filepath.Clean(name)
+
+	// First we'll check to see if this is an exact path for a module directory.
+	// We need to do this first (rather than as part of the next loop below)
+	// because a module in a child directory of another module can otherwise
+	// appear to be a file in that parent directory.
+	for _, candidate := range fs.snap.Modules {
+		modDir := filepath.Clean(candidate.Dir)
+		if modDir == directDir {
+			// We've matched the module directory itself
+			filenames := make([]string, 0, len(candidate.Files))
+			for n := range candidate.Files {
+				filenames = append(filenames, n)
+			}
+			sort.Strings(filenames)
+			return &snapshotDir{
+				filenames: filenames,
+			}, nil
+		}
+	}
+
+	// If we get here then the given path isn't a module directory exactly, so
+	// we'll treat it as a file path and try to find a module directory it
+	// could be located in.
+	var modSnap *SnapshotModule
+	for _, candidate := range fs.snap.Modules {
+		modDir := filepath.Clean(candidate.Dir)
+		if modDir == dir {
+			modSnap = candidate
+			break
+		}
+	}
+	if modSnap == nil {
+		return nil, os.ErrNotExist
+	}
+
+	src, exists := modSnap.Files[fn]
+	if !exists {
+		return nil, os.ErrNotExist
+	}
+
+	return &snapshotFile{
+		src: src,
+	}, nil
+}
+
+func (fs snapshotFS) OpenFile(name string, flag int, perm os.FileMode) (afero.File, error) {
+	return fs.Open(name)
+}
+
+func (fs snapshotFS) Remove(name string) error {
+	return fmt.Errorf("cannot remove file inside configuration snapshot")
+}
+
+func (fs snapshotFS) RemoveAll(path string) error {
+	return fmt.Errorf("cannot remove files inside configuration snapshot")
+}
+
+func (fs snapshotFS) Rename(old, new string) error {
+	return fmt.Errorf("cannot rename file inside configuration snapshot")
+}
+
+func (fs snapshotFS) Stat(name string) (os.FileInfo, error) {
+	f, err := fs.Open(name)
+	if err != nil {
+		return nil, err
+	}
+	_, isDir := f.(*snapshotDir)
+	return snapshotFileInfo{
+		name:  filepath.Base(name),
+		isDir: isDir,
+	}, nil
+}
+
+func (fs snapshotFS) Name() string {
+	return "ConfigSnapshotFS"
+}
+
+func (fs snapshotFS) Chmod(name string, mode os.FileMode) error {
+	return fmt.Errorf("cannot set file mode inside configuration snapshot")
+}
+
+func (fs snapshotFS) Chtimes(name string, atime, mtime time.Time) error {
+	return fmt.Errorf("cannot set file times inside configuration snapshot")
+}
+
+type snapshotFile struct {
+	snapshotFileStub
+	src []byte
+	at  int64
+}
+
+var _ afero.File = (*snapshotFile)(nil)
+
+func (f *snapshotFile) Read(p []byte) (n int, err error) {
+	if len(p) > 0 && f.at == int64(len(f.src)) {
+		return 0, io.EOF
+	}
+	if f.at > int64(len(f.src)) {
+		return 0, io.ErrUnexpectedEOF
+	}
+	if int64(len(f.src))-f.at >= int64(len(p)) {
+		n = len(p)
+	} else {
+		n = int(int64(len(f.src)) - f.at)
+	}
+	copy(p, f.src[f.at:f.at+int64(n)])
+	f.at += int64(n)
+	return
+}
+
+func (f *snapshotFile) ReadAt(p []byte, off int64) (n int, err error) {
+	f.at = off
+	return f.Read(p)
+}
+
+func (f *snapshotFile) Seek(offset int64, whence int) (int64, error) {
+	switch whence {
+	case 0:
+		f.at = offset
+	case 1:
+		f.at += offset
+	case 2:
+		f.at = int64(len(f.src)) + offset
+	}
+	return f.at, nil
+}
+
+type snapshotDir struct {
+	snapshotFileStub
+	filenames []string
+	at        int
+}
+
+var _ afero.File = (*snapshotDir)(nil)
+
+func (f *snapshotDir) Readdir(count int) ([]os.FileInfo, error) {
+	names, err := f.Readdirnames(count)
+	if err != nil {
+		return nil, err
+	}
+	ret := make([]os.FileInfo, len(names))
+	for i, name := range names {
+		ret[i] = snapshotFileInfo{
+			name:  name,
+			isDir: false,
+		}
+	}
+	return ret, nil
+}
+
+func (f *snapshotDir) Readdirnames(count int) ([]string, error) {
+	var outLen int
+	names := f.filenames[f.at:]
+	if count > 0 {
+		if len(names) < count {
+			outLen = len(names)
+		} else {
+			outLen = count
+		}
+		if len(names) == 0 {
+			return nil, io.EOF
+		}
+	} else {
+		outLen = len(names)
+	}
+	f.at += outLen
+
+	return names[:outLen], nil
+}
+
+// snapshotFileInfo is a minimal implementation of os.FileInfo to support our
+// virtual filesystem from snapshots.
+type snapshotFileInfo struct {
+	name  string
+	isDir bool
+}
+
+var _ os.FileInfo = snapshotFileInfo{}
+
+func (fi snapshotFileInfo) Name() string {
+	return fi.name
+}
+
+func (fi snapshotFileInfo) Size() int64 {
+	// In practice, our parser and loader never call Size
+	return -1
+}
+
+func (fi snapshotFileInfo) Mode() os.FileMode {
+	return os.ModePerm
+}
+
+func (fi snapshotFileInfo) ModTime() time.Time {
+	return time.Now()
+}
+
+func (fi snapshotFileInfo) IsDir() bool {
+	return fi.isDir
+}
+
+func (fi snapshotFileInfo) Sys() interface{} {
+	return nil
+}
+
+type snapshotFileStub struct{}
+
+func (f snapshotFileStub) Close() error {
+	return nil
+}
+
+func (f snapshotFileStub) Read(p []byte) (n int, err error) {
+	return 0, fmt.Errorf("cannot read")
+}
+
+func (f snapshotFileStub) ReadAt(p []byte, off int64) (n int, err error) {
+	return 0, fmt.Errorf("cannot read")
+}
+
+func (f snapshotFileStub) Seek(offset int64, whence int) (int64, error) {
+	return 0, fmt.Errorf("cannot seek")
+}
+
+func (f snapshotFileStub) Write(p []byte) (n int, err error) {
+	return f.WriteAt(p, 0)
+}
+
+func (f snapshotFileStub) WriteAt(p []byte, off int64) (n int, err error) {
+	return 0, fmt.Errorf("cannot write to file in snapshot")
+}
+
+func (f snapshotFileStub) WriteString(s string) (n int, err error) {
+	return 0, fmt.Errorf("cannot write to file in snapshot")
+}
+
+func (f snapshotFileStub) Name() string {
+	// in practice, the loader and parser never use this
+	return "<unimplemented>"
+}
+
+func (f snapshotFileStub) Readdir(count int) ([]os.FileInfo, error) {
+	return nil, fmt.Errorf("cannot use Readdir on a file")
+}
+
+func (f snapshotFileStub) Readdirnames(count int) ([]string, error) {
+	return nil, fmt.Errorf("cannot use Readdir on a file")
+}
+
+func (f snapshotFileStub) Stat() (os.FileInfo, error) {
+	return nil, fmt.Errorf("cannot stat")
+}
+
+func (f snapshotFileStub) Sync() error {
+	return nil
+}
+
+func (f snapshotFileStub) Truncate(size int64) error {
+	return fmt.Errorf("cannot write to file in snapshot")
+}
diff --git a/v1.5.7/internal/configs/configload/loader_snapshot_test.go b/v1.5.7/internal/configs/configload/loader_snapshot_test.go
new file mode 100644
index 0000000..d8f597e
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/loader_snapshot_test.go
@@ -0,0 +1,145 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configload
+
+import (
+	"os"
+	"path/filepath"
+	"reflect"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/go-test/deep"
+)
+
+func TestLoadConfigWithSnapshot(t *testing.T) {
+	fixtureDir := filepath.Clean("testdata/already-installed")
+	loader, err := NewLoader(&Config{
+		ModulesDir: filepath.Join(fixtureDir, ".terraform/modules"),
+	})
+	if err != nil {
+		t.Fatalf("unexpected error from NewLoader: %s", err)
+	}
+
+	_, got, diags := loader.LoadConfigWithSnapshot(fixtureDir)
+	assertNoDiagnostics(t, diags)
+	if got == nil {
+		t.Fatalf("snapshot is nil; want non-nil")
+	}
+
+	t.Log(spew.Sdump(got))
+
+	{
+		gotModuleDirs := map[string]string{}
+		for k, m := range got.Modules {
+			gotModuleDirs[k] = m.Dir
+		}
+		wantModuleDirs := map[string]string{
+			"":                "testdata/already-installed",
+			"child_a":         "testdata/already-installed/.terraform/modules/child_a",
+			"child_a.child_c": "testdata/already-installed/.terraform/modules/child_a/child_c",
+			"child_b":         "testdata/already-installed/.terraform/modules/child_b",
+			"child_b.child_d": "testdata/already-installed/.terraform/modules/child_b.child_d",
+		}
+
+		problems := deep.Equal(wantModuleDirs, gotModuleDirs)
+		for _, problem := range problems {
+			t.Errorf(problem)
+		}
+		if len(problems) > 0 {
+			return
+		}
+	}
+
+	gotRoot := got.Modules[""]
+	wantRoot := &SnapshotModule{
+		Dir: "testdata/already-installed",
+		Files: map[string][]byte{
+			"root.tf": []byte(`
+module "child_a" {
+  source  = "example.com/foo/bar_a/baz"
+  version = ">= 1.0.0"
+}
+
+module "child_b" {
+  source = "example.com/foo/bar_b/baz"
+  version = ">= 1.0.0"
+}
+`),
+		},
+	}
+	if !reflect.DeepEqual(gotRoot, wantRoot) {
+		t.Errorf("wrong root module snapshot\ngot: %swant: %s", spew.Sdump(gotRoot), spew.Sdump(wantRoot))
+	}
+
+}
+
+func TestLoadConfigWithSnapshot_invalidSource(t *testing.T) {
+	fixtureDir := filepath.Clean("testdata/already-installed-now-invalid")
+
+	old, _ := os.Getwd()
+	os.Chdir(fixtureDir)
+	defer os.Chdir(old)
+
+	loader, err := NewLoader(&Config{
+		ModulesDir: ".terraform/modules",
+	})
+	if err != nil {
+		t.Fatalf("unexpected error from NewLoader: %s", err)
+	}
+
+	_, _, diags := loader.LoadConfigWithSnapshot(".")
+	if !diags.HasErrors() {
+		t.Error("LoadConfigWithSnapshot succeeded; want errors")
+	}
+}
+
+func TestSnapshotRoundtrip(t *testing.T) {
+	fixtureDir := filepath.Clean("testdata/already-installed")
+	loader, err := NewLoader(&Config{
+		ModulesDir: filepath.Join(fixtureDir, ".terraform/modules"),
+	})
+	if err != nil {
+		t.Fatalf("unexpected error from NewLoader: %s", err)
+	}
+
+	_, snap, diags := loader.LoadConfigWithSnapshot(fixtureDir)
+	assertNoDiagnostics(t, diags)
+	if snap == nil {
+		t.Fatalf("snapshot is nil; want non-nil")
+	}
+
+	snapLoader := NewLoaderFromSnapshot(snap)
+	if loader == nil {
+		t.Fatalf("loader is nil; want non-nil")
+	}
+
+	config, diags := snapLoader.LoadConfig(fixtureDir)
+	assertNoDiagnostics(t, diags)
+	if config == nil {
+		t.Fatalf("config is nil; want non-nil")
+	}
+	if config.Module == nil {
+		t.Fatalf("config has no root module")
+	}
+	if got, want := config.Module.SourceDir, "testdata/already-installed"; got != want {
+		t.Errorf("wrong root module sourcedir %q; want %q", got, want)
+	}
+	if got, want := len(config.Module.ModuleCalls), 2; got != want {
+		t.Errorf("wrong number of module calls in root module %d; want %d", got, want)
+	}
+	childA := config.Children["child_a"]
+	if childA == nil {
+		t.Fatalf("child_a config is nil; want non-nil")
+	}
+	if childA.Module == nil {
+		t.Fatalf("child_a config has no module")
+	}
+	if got, want := childA.Module.SourceDir, "testdata/already-installed/.terraform/modules/child_a"; got != want {
+		t.Errorf("wrong child_a sourcedir %q; want %q", got, want)
+	}
+	if got, want := len(childA.Module.ModuleCalls), 1; got != want {
+		t.Errorf("wrong number of module calls in child_a %d; want %d", got, want)
+	}
+}
diff --git a/v1.5.7/internal/configs/configload/loader_test.go b/v1.5.7/internal/configs/configload/loader_test.go
new file mode 100644
index 0000000..36864d5
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/loader_test.go
@@ -0,0 +1,36 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configload
+
+import (
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func assertNoDiagnostics(t *testing.T, diags hcl.Diagnostics) bool {
+	t.Helper()
+	return assertDiagnosticCount(t, diags, 0)
+}
+
+func assertDiagnosticCount(t *testing.T, diags hcl.Diagnostics, want int) bool {
+	t.Helper()
+	if len(diags) != want {
+		t.Errorf("wrong number of diagnostics %d; want %d", len(diags), want)
+		for _, diag := range diags {
+			t.Logf("- %s", diag)
+		}
+		return true
+	}
+	return false
+}
+func assertResultCtyEqual(t *testing.T, got, want cty.Value) bool {
+	t.Helper()
+	if !got.RawEquals(want) {
+		t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, want)
+		return true
+	}
+	return false
+}
diff --git a/v1.5.7/internal/configs/configload/module_mgr.go b/v1.5.7/internal/configs/configload/module_mgr.go
new file mode 100644
index 0000000..a309bca
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/module_mgr.go
@@ -0,0 +1,65 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configload
+
+import (
+	"os"
+	"path/filepath"
+
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/modsdir"
+	"github.com/hashicorp/terraform/internal/registry"
+	"github.com/spf13/afero"
+)
+
+type moduleMgr struct {
+	FS afero.Afero
+
+	// CanInstall is true for a module manager that can support installation.
+	//
+	// This must be set only if FS is an afero.OsFs, because the installer
+	// (which uses go-getter) is not aware of the virtual filesystem
+	// abstraction and will always write into the "real" filesystem.
+	CanInstall bool
+
+	// Dir is the path where descendent modules are (or will be) installed.
+	Dir string
+
+	// Services is a service discovery client that will be used to find
+	// remote module registry endpoints. This object may be pre-loaded with
+	// cached discovery information.
+	Services *disco.Disco
+
+	// Registry is a client for the module registry protocol, which is used
+	// when a module is requested from a registry source.
+	Registry *registry.Client
+
+	// manifest tracks the currently-installed modules for this manager.
+	//
+	// The loader may read this. Only the installer may write to it, and
+	// after a set of updates are completed the installer must call
+	// writeModuleManifestSnapshot to persist a snapshot of the manifest
+	// to disk for use on subsequent runs.
+	manifest modsdir.Manifest
+}
+
+func (m *moduleMgr) manifestSnapshotPath() string {
+	return filepath.Join(m.Dir, modsdir.ManifestSnapshotFilename)
+}
+
+// readModuleManifestSnapshot loads a manifest snapshot from the filesystem.
+func (m *moduleMgr) readModuleManifestSnapshot() error {
+	r, err := m.FS.Open(m.manifestSnapshotPath())
+	if err != nil {
+		if os.IsNotExist(err) {
+			// We'll treat a missing file as an empty manifest
+			m.manifest = make(modsdir.Manifest)
+			return nil
+		}
+		return err
+	}
+
+	m.manifest, err = modsdir.ReadManifestSnapshot(r)
+	return err
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/add-version-constraint/.terraform/modules/child/empty.tf b/v1.5.7/internal/configs/configload/testdata/add-version-constraint/.terraform/modules/child/empty.tf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/add-version-constraint/.terraform/modules/child/empty.tf
diff --git a/v1.5.7/internal/configs/configload/testdata/add-version-constraint/.terraform/modules/modules.json b/v1.5.7/internal/configs/configload/testdata/add-version-constraint/.terraform/modules/modules.json
new file mode 100644
index 0000000..c02f400
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/add-version-constraint/.terraform/modules/modules.json
@@ -0,0 +1,14 @@
+{
+    "Modules": [
+        {
+            "Key": "",
+            "Source": "",
+            "Dir": "testdata/add-version-constraint"
+        },
+        {
+            "Key": "child",
+            "Source": "hashicorp/module-installer-acctest/aws",
+            "Dir": "testdata/add-version-constraint/.terraform/modules/child"
+        }
+    ]
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/add-version-constraint/add-version-constraint.tf b/v1.5.7/internal/configs/configload/testdata/add-version-constraint/add-version-constraint.tf
new file mode 100644
index 0000000..2d407a4
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/add-version-constraint/add-version-constraint.tf
@@ -0,0 +1,10 @@
+# This fixture depends on a registry module, which indirectly refers to the
+# following github repository:
+#
+# However, the test that uses it is testing for an error, so in practice the
+# registry does not need to be accessed when this test is successful.
+
+module "child" {
+  source  = "hashicorp/module-installer-acctest/aws"
+  version = "0.0.1"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/already-installed-now-invalid/.terraform/modules/modules.json b/v1.5.7/internal/configs/configload/testdata/already-installed-now-invalid/.terraform/modules/modules.json
new file mode 100644
index 0000000..32a4ace
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/already-installed-now-invalid/.terraform/modules/modules.json
@@ -0,0 +1 @@
+{"Modules":[{"Key":"","Source":"","Dir":"."},{"Key":"foo","Source":"./foo","Dir":"foo"},{"Key":"foo.bar","Source":"./bar","Dir":"foo/bar"}]}
\ No newline at end of file
diff --git a/v1.5.7/internal/configs/configload/testdata/already-installed-now-invalid/foo/bar/main.tf b/v1.5.7/internal/configs/configload/testdata/already-installed-now-invalid/foo/bar/main.tf
new file mode 100644
index 0000000..48b5e2e
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/already-installed-now-invalid/foo/bar/main.tf
@@ -0,0 +1,3 @@
+output "hello" {
+  value = "Hello from foo/bar"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/already-installed-now-invalid/foo/main.tf b/v1.5.7/internal/configs/configload/testdata/already-installed-now-invalid/foo/main.tf
new file mode 100644
index 0000000..9fba572
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/already-installed-now-invalid/foo/main.tf
@@ -0,0 +1,3 @@
+module "bar" {
+  source = "${path.module}/bar"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/already-installed-now-invalid/root.tf b/v1.5.7/internal/configs/configload/testdata/already-installed-now-invalid/root.tf
new file mode 100644
index 0000000..020494e
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/already-installed-now-invalid/root.tf
@@ -0,0 +1,3 @@
+module "foo" {
+  source  = "./foo"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/already-installed/.terraform/modules/child_a/child_a.tf b/v1.5.7/internal/configs/configload/testdata/already-installed/.terraform/modules/child_a/child_a.tf
new file mode 100644
index 0000000..2f4d0f1
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/already-installed/.terraform/modules/child_a/child_a.tf
@@ -0,0 +1,4 @@
+
+module "child_c" {
+  source  = "./child_c"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/already-installed/.terraform/modules/child_a/child_c/child_c.tf b/v1.5.7/internal/configs/configload/testdata/already-installed/.terraform/modules/child_a/child_c/child_c.tf
new file mode 100644
index 0000000..785d98d
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/already-installed/.terraform/modules/child_a/child_c/child_c.tf
@@ -0,0 +1,4 @@
+
+output "hello" {
+  value = "Hello from child_c"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/already-installed/.terraform/modules/child_b.child_d/child_d.tf b/v1.5.7/internal/configs/configload/testdata/already-installed/.terraform/modules/child_b.child_d/child_d.tf
new file mode 100644
index 0000000..145576a
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/already-installed/.terraform/modules/child_b.child_d/child_d.tf
@@ -0,0 +1,4 @@
+
+output "hello" {
+  value = "Hello from child_d"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/already-installed/.terraform/modules/child_b/child_b.tf b/v1.5.7/internal/configs/configload/testdata/already-installed/.terraform/modules/child_b/child_b.tf
new file mode 100644
index 0000000..4a1b247
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/already-installed/.terraform/modules/child_b/child_b.tf
@@ -0,0 +1,5 @@
+
+module "child_d" {
+  source  = "example.com/foo/bar_d/baz"
+  # Intentionally no version here
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/already-installed/.terraform/modules/modules.json b/v1.5.7/internal/configs/configload/testdata/already-installed/.terraform/modules/modules.json
new file mode 100644
index 0000000..4343986
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/already-installed/.terraform/modules/modules.json
@@ -0,0 +1 @@
+{"Modules":[{"Key":"","Source":"","Dir":"testdata/already-installed"},{"Key":"child_a","Source":"example.com/foo/bar_a/baz","Version":"1.0.1","Dir":"testdata/already-installed/.terraform/modules/child_a"},{"Key":"child_b","Source":"example.com/foo/bar_b/baz","Version":"1.0.0","Dir":"testdata/already-installed/.terraform/modules/child_b"},{"Key":"child_a.child_c","Source":"./child_c","Dir":"testdata/already-installed/.terraform/modules/child_a/child_c"},{"Key":"child_b.child_d","Source":"example.com/foo/bar_d/baz","Version":"1.2.0","Dir":"testdata/already-installed/.terraform/modules/child_b.child_d"}]}
\ No newline at end of file
diff --git a/v1.5.7/internal/configs/configload/testdata/already-installed/root.tf b/v1.5.7/internal/configs/configload/testdata/already-installed/root.tf
new file mode 100644
index 0000000..8a44739
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/already-installed/root.tf
@@ -0,0 +1,10 @@
+
+module "child_a" {
+  source  = "example.com/foo/bar_a/baz"
+  version = ">= 1.0.0"
+}
+
+module "child_b" {
+  source = "example.com/foo/bar_b/baz"
+  version = ">= 1.0.0"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/child-provider-child-count/.terraform/modules/modules.json b/v1.5.7/internal/configs/configload/testdata/child-provider-child-count/.terraform/modules/modules.json
new file mode 100644
index 0000000..3a80b67
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/child-provider-child-count/.terraform/modules/modules.json
@@ -0,0 +1,19 @@
+{
+    "Modules": [
+        {
+            "Key": "",
+            "Source": "",
+            "Dir": "."
+        },
+        {
+            "Key": "child",
+            "Source": "./child",
+            "Dir": "testdata/child-provider-child-count/child"
+        },
+        {
+            "Key": "child.grandchild",
+            "Source": "../grandchild",
+            "Dir": "testdata/child-provider-child-count/grandchild"
+        }
+    ]
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/child-provider-child-count/child-provider-child-count.tf b/v1.5.7/internal/configs/configload/testdata/child-provider-child-count/child-provider-child-count.tf
new file mode 100644
index 0000000..5b39941
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/child-provider-child-count/child-provider-child-count.tf
@@ -0,0 +1,4 @@
+module "child" {
+  source = "./child"
+  count  = 1
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/child-provider-child-count/child/child-provider-child-count-child.tf b/v1.5.7/internal/configs/configload/testdata/child-provider-child-count/child/child-provider-child-count-child.tf
new file mode 100644
index 0000000..524742c
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/child-provider-child-count/child/child-provider-child-count-child.tf
@@ -0,0 +1,7 @@
+provider "boop" {
+    blah = true
+}
+
+module "grandchild" {
+    source = "../grandchild"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/child-provider-child-count/grandchild/child-provider-child-count-grandchild.tf b/v1.5.7/internal/configs/configload/testdata/child-provider-child-count/grandchild/child-provider-child-count-grandchild.tf
new file mode 100644
index 0000000..ccd9dce
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/child-provider-child-count/grandchild/child-provider-child-count-grandchild.tf
@@ -0,0 +1 @@
+# Intentionally blank
diff --git a/v1.5.7/internal/configs/configload/testdata/child-provider-grandchild-count/.terraform/modules/modules.json b/v1.5.7/internal/configs/configload/testdata/child-provider-grandchild-count/.terraform/modules/modules.json
new file mode 100644
index 0000000..a9239e3
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/child-provider-grandchild-count/.terraform/modules/modules.json
@@ -0,0 +1,19 @@
+{
+    "Modules": [
+        {
+            "Key": "",
+            "Source": "",
+            "Dir": "."
+        },
+        {
+            "Key": "child",
+            "Source": "./child",
+            "Dir": "testdata/child-provider-grandchild-count/child"
+        },
+        {
+            "Key": "child.grandchild",
+            "Source": "../grandchild",
+            "Dir": "testdata/child-provider-grandchild-count/grandchild"
+        }
+    ]
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/child-provider-grandchild-count/child-provider-grandchild-count.tf b/v1.5.7/internal/configs/configload/testdata/child-provider-grandchild-count/child-provider-grandchild-count.tf
new file mode 100644
index 0000000..1f95749
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/child-provider-grandchild-count/child-provider-grandchild-count.tf
@@ -0,0 +1,3 @@
+module "child" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/child-provider-grandchild-count/child/child-provider-grandchild-count-child.tf b/v1.5.7/internal/configs/configload/testdata/child-provider-grandchild-count/child/child-provider-grandchild-count-child.tf
new file mode 100644
index 0000000..8d3fe10
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/child-provider-grandchild-count/child/child-provider-grandchild-count-child.tf
@@ -0,0 +1,12 @@
+provider "boop" {
+    blah = true
+}
+
+module "grandchild" {
+    source = "../grandchild"
+
+    # grandchild's caller (this file) has a legacy nested provider block, but
+    # grandchild itself does not and so it's valid to use "count" here even
+    # though it wouldn't be valid to call "child" (this file) with "count".
+    count = 2
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/child-provider-grandchild-count/grandchild/child-provider-grandchild-count-grandchild.tf b/v1.5.7/internal/configs/configload/testdata/child-provider-grandchild-count/grandchild/child-provider-grandchild-count-grandchild.tf
new file mode 100644
index 0000000..ccd9dce
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/child-provider-grandchild-count/grandchild/child-provider-grandchild-count-grandchild.tf
@@ -0,0 +1 @@
+# Intentionally blank
diff --git a/v1.5.7/internal/configs/configload/testdata/empty/.gitignore b/v1.5.7/internal/configs/configload/testdata/empty/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/empty/.gitignore
diff --git a/v1.5.7/internal/configs/configload/testdata/go-getter-modules/.gitignore b/v1.5.7/internal/configs/configload/testdata/go-getter-modules/.gitignore
new file mode 100644
index 0000000..6e0db03
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/go-getter-modules/.gitignore
@@ -0,0 +1 @@
+.terraform/*
diff --git a/v1.5.7/internal/configs/configload/testdata/go-getter-modules/root.tf b/v1.5.7/internal/configs/configload/testdata/go-getter-modules/root.tf
new file mode 100644
index 0000000..9b174a7
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/go-getter-modules/root.tf
@@ -0,0 +1,21 @@
+# This fixture depends on a github repo at:
+#     https://github.com/hashicorp/terraform-aws-module-installer-acctest
+# ...and expects its v0.0.1 tag to be pointing at the following commit:
+#     d676ab2559d4e0621d59e3c3c4cbb33958ac4608
+
+variable "v" {
+  description = "in local caller for go-getter-modules"
+  default     = ""
+}
+
+module "acctest_root" {
+  source = "github.com/hashicorp/terraform-aws-module-installer-acctest?ref=v0.0.1"
+}
+
+module "acctest_child_a" {
+  source = "github.com/hashicorp/terraform-aws-module-installer-acctest//modules/child_a?ref=v0.0.1"
+}
+
+module "acctest_child_b" {
+  source = "github.com/hashicorp/terraform-aws-module-installer-acctest//modules/child_b?ref=v0.0.1"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/invalid-names-in-submodules/.terraform/modules/modules.json b/v1.5.7/internal/configs/configload/testdata/invalid-names-in-submodules/.terraform/modules/modules.json
new file mode 100644
index 0000000..c55c1cf
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/invalid-names-in-submodules/.terraform/modules/modules.json
@@ -0,0 +1,14 @@
+{
+	"Modules": [
+		{
+			"Key": "test",
+			"Source": "./sub",
+			"Dir": "testdata/invalid-names-in-submodules/sub"
+		},
+		{
+			"Key": "",
+			"Source": "",
+			"Dir": "."
+		}
+	]
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/configs/configload/testdata/invalid-names-in-submodules/main.tf b/v1.5.7/internal/configs/configload/testdata/invalid-names-in-submodules/main.tf
new file mode 100644
index 0000000..3fbc8c6
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/invalid-names-in-submodules/main.tf
@@ -0,0 +1,3 @@
+module "test" {
+	source = "./sub"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/invalid-names-in-submodules/sub/main.tf b/v1.5.7/internal/configs/configload/testdata/invalid-names-in-submodules/sub/main.tf
new file mode 100644
index 0000000..aacab2c
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/invalid-names-in-submodules/sub/main.tf
@@ -0,0 +1,7 @@
+resource "aws-_foo" "test" {
+
+}
+
+data "aws-_bar" "test" {
+
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/invalid-names/main.tf b/v1.5.7/internal/configs/configload/testdata/invalid-names/main.tf
new file mode 100644
index 0000000..d4eee4c
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/invalid-names/main.tf
@@ -0,0 +1,3 @@
+provider "42_bad!" {
+  invalid_provider_name = "yes"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/local-modules/child_a/child_a.tf b/v1.5.7/internal/configs/configload/testdata/local-modules/child_a/child_a.tf
new file mode 100644
index 0000000..68ebb8e
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/local-modules/child_a/child_a.tf
@@ -0,0 +1,9 @@
+
+variable "v" {
+  description = "in child_a module"
+  default     = ""
+}
+
+module "child_b" {
+  source = "./child_b"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/local-modules/child_a/child_b/child_b.tf b/v1.5.7/internal/configs/configload/testdata/local-modules/child_a/child_b/child_b.tf
new file mode 100644
index 0000000..e2e2209
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/local-modules/child_a/child_b/child_b.tf
@@ -0,0 +1,9 @@
+
+variable "v" {
+  description = "in child_b module"
+  default     = ""
+}
+
+output "hello" {
+  value = "Hello from child_b!"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/local-modules/root.tf b/v1.5.7/internal/configs/configload/testdata/local-modules/root.tf
new file mode 100644
index 0000000..3b4c641
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/local-modules/root.tf
@@ -0,0 +1,9 @@
+
+variable "v" {
+  description = "in root module"
+  default     = ""
+}
+
+module "child_a" {
+  source = "./child_a"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/module-depends-on/.terraform/modules/modules.json b/v1.5.7/internal/configs/configload/testdata/module-depends-on/.terraform/modules/modules.json
new file mode 100644
index 0000000..28f8130
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/module-depends-on/.terraform/modules/modules.json
@@ -0,0 +1,24 @@
+{
+    "Modules": [
+        {
+            "Key": "",
+            "Source": "",
+            "Dir": "testdata/expand-modules/nested-provider"
+        },
+        {
+            "Key": "child",
+            "Source": "./child",
+            "Dir": "testdata/expand-modules/nested-provider/child"
+        },
+        {
+            "Key": "child2",
+            "Source": "./child2",
+            "Dir": "testdata/expand-modules/nested-provider/child2"
+        },
+        {
+            "Key": "child.child2",
+            "Source": "../child2",
+            "Dir": "testdata/expand-modules/nested-provider/child2"
+        }
+    ]
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/module-depends-on/child/main.tf b/v1.5.7/internal/configs/configload/testdata/module-depends-on/child/main.tf
new file mode 100644
index 0000000..f6b74b7
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/module-depends-on/child/main.tf
@@ -0,0 +1,3 @@
+module "child2" {
+  source = "../child2"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/module-depends-on/child2/main.tf b/v1.5.7/internal/configs/configload/testdata/module-depends-on/child2/main.tf
new file mode 100644
index 0000000..bea1f0c
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/module-depends-on/child2/main.tf
@@ -0,0 +1,6 @@
+provider "aws" {
+}
+
+output "my_output" {
+  value = "my output"
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/module-depends-on/root.tf b/v1.5.7/internal/configs/configload/testdata/module-depends-on/root.tf
new file mode 100644
index 0000000..b14d24c
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/module-depends-on/root.tf
@@ -0,0 +1,7 @@
+module "child" {
+  source = "./child"
+  depends_on = [test_resource.a]
+}
+
+resource "test_resource" "a" {
+}
diff --git a/v1.5.7/internal/configs/configload/testdata/registry-modules/.gitignore b/v1.5.7/internal/configs/configload/testdata/registry-modules/.gitignore
new file mode 100644
index 0000000..6e0db03
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/registry-modules/.gitignore
@@ -0,0 +1 @@
+.terraform/*
diff --git a/v1.5.7/internal/configs/configload/testdata/registry-modules/root.tf b/v1.5.7/internal/configs/configload/testdata/registry-modules/root.tf
new file mode 100644
index 0000000..4b5ad1f
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testdata/registry-modules/root.tf
@@ -0,0 +1,33 @@
+# This fixture indirectly depends on a github repo at:
+#     https://github.com/hashicorp/terraform-aws-module-installer-acctest
+# ...and expects its v0.0.1 tag to be pointing at the following commit:
+#     d676ab2559d4e0621d59e3c3c4cbb33958ac4608
+#
+# This repository is accessed indirectly via:
+#     https://registry.terraform.io/modules/hashicorp/module-installer-acctest/aws/0.0.1
+#
+# Since the tag's id is included in a downloaded archive, it is expected to
+# have the following id:
+#     853d03855b3290a3ca491d4c3a7684572dd42237
+# (this particular assumption is encoded in the tests that use this fixture)
+
+
+variable "v" {
+  description = "in local caller for registry-modules"
+  default     = ""
+}
+
+module "acctest_root" {
+  source  = "hashicorp/module-installer-acctest/aws"
+  version = "0.0.1"
+}
+
+module "acctest_child_a" {
+  source  = "hashicorp/module-installer-acctest/aws//modules/child_a"
+  version = "0.0.1"
+}
+
+module "acctest_child_b" {
+  source  = "hashicorp/module-installer-acctest/aws//modules/child_b"
+  version = "0.0.1"
+}
diff --git a/v1.5.7/internal/configs/configload/testing.go b/v1.5.7/internal/configs/configload/testing.go
new file mode 100644
index 0000000..a0a6d51
--- /dev/null
+++ b/v1.5.7/internal/configs/configload/testing.go
@@ -0,0 +1,46 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configload
+
+import (
+	"io/ioutil"
+	"os"
+	"testing"
+)
+
+// NewLoaderForTests is a variant of NewLoader that is intended to be more
+// convenient for unit tests.
+//
+// The loader's modules directory is a separate temporary directory created
+// for each call. Along with the created loader, this function returns a
+// cleanup function that should be called before the test completes in order
+// to remove that temporary directory.
+//
+// In the case of any errors, t.Fatal (or similar) will be called to halt
+// execution of the test, so the calling test does not need to handle errors
+// itself.
+func NewLoaderForTests(t *testing.T) (*Loader, func()) {
+	t.Helper()
+
+	modulesDir, err := ioutil.TempDir("", "tf-configs")
+	if err != nil {
+		t.Fatalf("failed to create temporary modules dir: %s", err)
+		return nil, func() {}
+	}
+
+	cleanup := func() {
+		os.RemoveAll(modulesDir)
+	}
+
+	loader, err := NewLoader(&Config{
+		ModulesDir: modulesDir,
+	})
+	if err != nil {
+		cleanup()
+		t.Fatalf("failed to create config loader: %s", err)
+		return nil, func() {}
+	}
+
+	return loader, cleanup
+}
diff --git a/v1.5.7/internal/configs/configschema/coerce_value.go b/v1.5.7/internal/configs/configschema/coerce_value.go
new file mode 100644
index 0000000..d720589
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/coerce_value.go
@@ -0,0 +1,251 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"fmt"
+
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/convert"
+)
+
+// CoerceValue attempts to force the given value to conform to the type
+// implied by the receiever.
+//
+// This is useful in situations where a configuration must be derived from
+// an already-decoded value. It is always better to decode directly from
+// configuration where possible since then source location information is
+// still available to produce diagnostics, but in special situations this
+// function allows a compatible result to be obtained even if the
+// configuration objects are not available.
+//
+// If the given value cannot be converted to conform to the receiving schema
+// then an error is returned describing one of possibly many problems. This
+// error may be a cty.PathError indicating a position within the nested
+// data structure where the problem applies.
+func (b *Block) CoerceValue(in cty.Value) (cty.Value, error) {
+	var path cty.Path
+	return b.coerceValue(in, path)
+}
+
+func (b *Block) coerceValue(in cty.Value, path cty.Path) (cty.Value, error) {
+	convType := b.specType()
+	impliedType := convType.WithoutOptionalAttributesDeep()
+
+	switch {
+	case in.IsNull():
+		return cty.NullVal(impliedType), nil
+	case !in.IsKnown():
+		return cty.UnknownVal(impliedType), nil
+	}
+
+	ty := in.Type()
+	if !ty.IsObjectType() {
+		return cty.UnknownVal(impliedType), path.NewErrorf("an object is required")
+	}
+
+	for name := range ty.AttributeTypes() {
+		if _, defined := b.Attributes[name]; defined {
+			continue
+		}
+		if _, defined := b.BlockTypes[name]; defined {
+			continue
+		}
+		return cty.UnknownVal(impliedType), path.NewErrorf("unexpected attribute %q", name)
+	}
+
+	attrs := make(map[string]cty.Value)
+
+	for name, attrS := range b.Attributes {
+		attrType := impliedType.AttributeType(name)
+		attrConvType := convType.AttributeType(name)
+
+		var val cty.Value
+		switch {
+		case ty.HasAttribute(name):
+			val = in.GetAttr(name)
+		case attrS.Computed || attrS.Optional:
+			val = cty.NullVal(attrType)
+		default:
+			return cty.UnknownVal(impliedType), path.NewErrorf("attribute %q is required", name)
+		}
+
+		val, err := convert.Convert(val, attrConvType)
+		if err != nil {
+			return cty.UnknownVal(impliedType), append(path, cty.GetAttrStep{Name: name}).NewError(err)
+		}
+		attrs[name] = val
+	}
+
+	for typeName, blockS := range b.BlockTypes {
+		switch blockS.Nesting {
+
+		case NestingSingle, NestingGroup:
+			switch {
+			case ty.HasAttribute(typeName):
+				var err error
+				val := in.GetAttr(typeName)
+				attrs[typeName], err = blockS.coerceValue(val, append(path, cty.GetAttrStep{Name: typeName}))
+				if err != nil {
+					return cty.UnknownVal(impliedType), err
+				}
+			default:
+				attrs[typeName] = blockS.EmptyValue()
+			}
+
+		case NestingList:
+			switch {
+			case ty.HasAttribute(typeName):
+				coll := in.GetAttr(typeName)
+
+				switch {
+				case coll.IsNull():
+					attrs[typeName] = cty.NullVal(cty.List(blockS.ImpliedType()))
+					continue
+				case !coll.IsKnown():
+					attrs[typeName] = cty.UnknownVal(cty.List(blockS.ImpliedType()))
+					continue
+				}
+
+				if !coll.CanIterateElements() {
+					return cty.UnknownVal(impliedType), path.NewErrorf("must be a list")
+				}
+				l := coll.LengthInt()
+
+				if l == 0 {
+					attrs[typeName] = cty.ListValEmpty(blockS.ImpliedType())
+					continue
+				}
+				elems := make([]cty.Value, 0, l)
+				{
+					path = append(path, cty.GetAttrStep{Name: typeName})
+					for it := coll.ElementIterator(); it.Next(); {
+						var err error
+						idx, val := it.Element()
+						val, err = blockS.coerceValue(val, append(path, cty.IndexStep{Key: idx}))
+						if err != nil {
+							return cty.UnknownVal(impliedType), err
+						}
+						elems = append(elems, val)
+					}
+				}
+				attrs[typeName] = cty.ListVal(elems)
+			default:
+				attrs[typeName] = cty.ListValEmpty(blockS.ImpliedType())
+			}
+
+		case NestingSet:
+			switch {
+			case ty.HasAttribute(typeName):
+				coll := in.GetAttr(typeName)
+
+				switch {
+				case coll.IsNull():
+					attrs[typeName] = cty.NullVal(cty.Set(blockS.ImpliedType()))
+					continue
+				case !coll.IsKnown():
+					attrs[typeName] = cty.UnknownVal(cty.Set(blockS.ImpliedType()))
+					continue
+				}
+
+				if !coll.CanIterateElements() {
+					return cty.UnknownVal(impliedType), path.NewErrorf("must be a set")
+				}
+				l := coll.LengthInt()
+
+				if l == 0 {
+					attrs[typeName] = cty.SetValEmpty(blockS.ImpliedType())
+					continue
+				}
+				elems := make([]cty.Value, 0, l)
+				{
+					path = append(path, cty.GetAttrStep{Name: typeName})
+					for it := coll.ElementIterator(); it.Next(); {
+						var err error
+						idx, val := it.Element()
+						val, err = blockS.coerceValue(val, append(path, cty.IndexStep{Key: idx}))
+						if err != nil {
+							return cty.UnknownVal(impliedType), err
+						}
+						elems = append(elems, val)
+					}
+				}
+				attrs[typeName] = cty.SetVal(elems)
+			default:
+				attrs[typeName] = cty.SetValEmpty(blockS.ImpliedType())
+			}
+
+		case NestingMap:
+			switch {
+			case ty.HasAttribute(typeName):
+				coll := in.GetAttr(typeName)
+
+				switch {
+				case coll.IsNull():
+					attrs[typeName] = cty.NullVal(cty.Map(blockS.ImpliedType()))
+					continue
+				case !coll.IsKnown():
+					attrs[typeName] = cty.UnknownVal(cty.Map(blockS.ImpliedType()))
+					continue
+				}
+
+				if !coll.CanIterateElements() {
+					return cty.UnknownVal(impliedType), path.NewErrorf("must be a map")
+				}
+				l := coll.LengthInt()
+				if l == 0 {
+					attrs[typeName] = cty.MapValEmpty(blockS.ImpliedType())
+					continue
+				}
+				elems := make(map[string]cty.Value)
+				{
+					path = append(path, cty.GetAttrStep{Name: typeName})
+					for it := coll.ElementIterator(); it.Next(); {
+						var err error
+						key, val := it.Element()
+						if key.Type() != cty.String || key.IsNull() || !key.IsKnown() {
+							return cty.UnknownVal(impliedType), path.NewErrorf("must be a map")
+						}
+						val, err = blockS.coerceValue(val, append(path, cty.IndexStep{Key: key}))
+						if err != nil {
+							return cty.UnknownVal(impliedType), err
+						}
+						elems[key.AsString()] = val
+					}
+				}
+
+				// If the attribute values here contain any DynamicPseudoTypes,
+				// the concrete type must be an object.
+				useObject := false
+				switch {
+				case coll.Type().IsObjectType():
+					useObject = true
+				default:
+					// It's possible that we were given a map, and need to coerce it to an object
+					ety := coll.Type().ElementType()
+					for _, v := range elems {
+						if !v.Type().Equals(ety) {
+							useObject = true
+							break
+						}
+					}
+				}
+
+				if useObject {
+					attrs[typeName] = cty.ObjectVal(elems)
+				} else {
+					attrs[typeName] = cty.MapVal(elems)
+				}
+			default:
+				attrs[typeName] = cty.MapValEmpty(blockS.ImpliedType())
+			}
+
+		default:
+			// should never happen because above is exhaustive
+			panic(fmt.Errorf("unsupported nesting mode %#v", blockS.Nesting))
+		}
+	}
+
+	return cty.ObjectVal(attrs), nil
+}
diff --git a/v1.5.7/internal/configs/configschema/coerce_value_test.go b/v1.5.7/internal/configs/configschema/coerce_value_test.go
new file mode 100644
index 0000000..25b2b1c
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/coerce_value_test.go
@@ -0,0 +1,628 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestCoerceValue(t *testing.T) {
+	tests := map[string]struct {
+		Schema    *Block
+		Input     cty.Value
+		WantValue cty.Value
+		WantErr   string
+	}{
+		"empty schema and value": {
+			&Block{},
+			cty.EmptyObjectVal,
+			cty.EmptyObjectVal,
+			``,
+		},
+		"attribute present": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.True,
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("true"),
+			}),
+			``,
+		},
+		"single block present": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block:   Block{},
+						Nesting: NestingSingle,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.EmptyObjectVal,
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.EmptyObjectVal,
+			}),
+			``,
+		},
+		"single block wrong type": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block:   Block{},
+						Nesting: NestingSingle,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.True,
+			}),
+			cty.DynamicVal,
+			`.foo: an object is required`,
+		},
+		"list block with one item": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block:   Block{},
+						Nesting: NestingList,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{cty.EmptyObjectVal}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{cty.EmptyObjectVal}),
+			}),
+			``,
+		},
+		"set block with one item": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block:   Block{},
+						Nesting: NestingSet,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{cty.EmptyObjectVal}), // can implicitly convert to set
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{cty.EmptyObjectVal}),
+			}),
+			``,
+		},
+		"map block with one item": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block:   Block{},
+						Nesting: NestingMap,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.MapVal(map[string]cty.Value{"foo": cty.EmptyObjectVal}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.MapVal(map[string]cty.Value{"foo": cty.EmptyObjectVal}),
+			}),
+			``,
+		},
+		"list block with one item having an attribute": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"bar": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+						Nesting: NestingList,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+					"bar": cty.StringVal("hello"),
+				})}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+					"bar": cty.StringVal("hello"),
+				})}),
+			}),
+			``,
+		},
+		"list block with one item having a missing attribute": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"bar": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+						Nesting: NestingList,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{cty.EmptyObjectVal}),
+			}),
+			cty.DynamicVal,
+			`.foo[0]: attribute "bar" is required`,
+		},
+		"list block with one item having an extraneous attribute": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block:   Block{},
+						Nesting: NestingList,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+					"bar": cty.StringVal("hello"),
+				})}),
+			}),
+			cty.DynamicVal,
+			`.foo[0]: unexpected attribute "bar"`,
+		},
+		"missing optional attribute": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			cty.EmptyObjectVal,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(cty.String),
+			}),
+			``,
+		},
+		"missing optional single block": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block:   Block{},
+						Nesting: NestingSingle,
+					},
+				},
+			},
+			cty.EmptyObjectVal,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(cty.EmptyObject),
+			}),
+			``,
+		},
+		"missing optional list block": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block:   Block{},
+						Nesting: NestingList,
+					},
+				},
+			},
+			cty.EmptyObjectVal,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListValEmpty(cty.EmptyObject),
+			}),
+			``,
+		},
+		"missing optional set block": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block:   Block{},
+						Nesting: NestingSet,
+					},
+				},
+			},
+			cty.EmptyObjectVal,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetValEmpty(cty.EmptyObject),
+			}),
+			``,
+		},
+		"missing optional map block": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block:   Block{},
+						Nesting: NestingMap,
+					},
+				},
+			},
+			cty.EmptyObjectVal,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.MapValEmpty(cty.EmptyObject),
+			}),
+			``,
+		},
+		"missing required attribute": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+			},
+			cty.EmptyObjectVal,
+			cty.DynamicVal,
+			`attribute "foo" is required`,
+		},
+		"missing required single block": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block:    Block{},
+						Nesting:  NestingSingle,
+						MinItems: 1,
+						MaxItems: 1,
+					},
+				},
+			},
+			cty.EmptyObjectVal,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(cty.EmptyObject),
+			}),
+			``,
+		},
+		"unknown nested list": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"attr": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block:    Block{},
+						Nesting:  NestingList,
+						MinItems: 2,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"attr": cty.StringVal("test"),
+				"foo":  cty.UnknownVal(cty.EmptyObject),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"attr": cty.StringVal("test"),
+				"foo":  cty.UnknownVal(cty.List(cty.EmptyObject)),
+			}),
+			"",
+		},
+		"unknowns in nested list": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"attr": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+						Nesting:  NestingList,
+						MinItems: 2,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"attr": cty.UnknownVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"attr": cty.UnknownVal(cty.String),
+					}),
+				}),
+			}),
+			"",
+		},
+		"unknown nested set": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"attr": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block:    Block{},
+						Nesting:  NestingSet,
+						MinItems: 1,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"attr": cty.StringVal("test"),
+				"foo":  cty.UnknownVal(cty.EmptyObject),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"attr": cty.StringVal("test"),
+				"foo":  cty.UnknownVal(cty.Set(cty.EmptyObject)),
+			}),
+			"",
+		},
+		"unknown nested map": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"attr": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Block:    Block{},
+						Nesting:  NestingMap,
+						MinItems: 1,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"attr": cty.StringVal("test"),
+				"foo":  cty.UnknownVal(cty.Map(cty.String)),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"attr": cty.StringVal("test"),
+				"foo":  cty.UnknownVal(cty.Map(cty.EmptyObject)),
+			}),
+			"",
+		},
+		"extraneous attribute": {
+			&Block{},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+			}),
+			cty.DynamicVal,
+			`unexpected attribute "foo"`,
+		},
+		"wrong attribute type": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						Type:     cty.Number,
+						Required: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.False,
+			}),
+			cty.DynamicVal,
+			`.foo: number required`,
+		},
+		"unset computed value": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(cty.String),
+			}),
+			``,
+		},
+		"dynamic value attributes": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Nesting: NestingMap,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"bar": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+								"baz": {
+									Type:     cty.DynamicPseudoType,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ObjectVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("beep"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("boop"),
+						"baz": cty.NumberIntVal(8),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ObjectVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("beep"),
+						"baz": cty.NullVal(cty.DynamicPseudoType),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("boop"),
+						"baz": cty.NumberIntVal(8),
+					}),
+				}),
+			}),
+			``,
+		},
+		"dynamic attributes in map": {
+			// Convert a block represented as a map to an object if a
+			// DynamicPseudoType causes the element types to mismatch.
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Nesting: NestingMap,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"bar": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+								"baz": {
+									Type:     cty.DynamicPseudoType,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("beep"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("boop"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ObjectVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("beep"),
+						"baz": cty.NullVal(cty.DynamicPseudoType),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("boop"),
+						"baz": cty.NullVal(cty.DynamicPseudoType),
+					}),
+				}),
+			}),
+			``,
+		},
+		"nested types": {
+			// handle NestedTypes
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						NestedType: &Object{
+							Nesting: NestingList,
+							Attributes: map[string]*Attribute{
+								"bar": {
+									Type:     cty.String,
+									Required: true,
+								},
+								"baz": {
+									Type:     cty.Map(cty.String),
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+					"fob": {
+						NestedType: &Object{
+							Nesting: NestingSet,
+							Attributes: map[string]*Attribute{
+								"bar": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("beep"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("boop"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("beep"),
+						"baz": cty.NullVal(cty.Map(cty.String)),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("boop"),
+						"baz": cty.NullVal(cty.Map(cty.String)),
+					}),
+				}),
+				"fob": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{
+					"bar": cty.String,
+				}))),
+			}),
+			``,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			gotValue, gotErrObj := test.Schema.CoerceValue(test.Input)
+
+			if gotErrObj == nil {
+				if test.WantErr != "" {
+					t.Fatalf("coersion succeeded; want error: %q", test.WantErr)
+				}
+			} else {
+				gotErr := tfdiags.FormatError(gotErrObj)
+				if gotErr != test.WantErr {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", gotErr, test.WantErr)
+				}
+				return
+			}
+
+			if !gotValue.RawEquals(test.WantValue) {
+				t.Errorf("wrong result\ninput: %#v\ngot:   %#v\nwant:  %#v", test.Input, gotValue, test.WantValue)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/configs/configschema/decoder_spec.go b/v1.5.7/internal/configs/configschema/decoder_spec.go
new file mode 100644
index 0000000..dc4a973
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/decoder_spec.go
@@ -0,0 +1,226 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"runtime"
+	"sync"
+	"unsafe"
+
+	"github.com/hashicorp/hcl/v2/hcldec"
+	"github.com/zclconf/go-cty/cty"
+)
+
+var mapLabelNames = []string{"key"}
+
+// specCache is a global cache of all the generated hcldec.Spec values for
+// Blocks. This cache is used by the Block.DecoderSpec method to memoize calls
+// and prevent unnecessary regeneration of the spec, especially when they are
+// large and deeply nested.
+// Caching these externally rather than within the struct is required because
+// Blocks are used by value and copied when working with NestedBlocks, and the
+// copying of the value prevents any safe synchronisation of the struct itself.
+//
+// While we are using the *Block pointer as the cache key, and the Block
+// contents are mutable, once a Block is created it is treated as immutable for
+// the duration of its life. Because a Block is a representation of a logical
+// schema, which cannot change while it's being used, any modifications to the
+// schema during execution would be an error.
+type specCache struct {
+	sync.Mutex
+	specs map[uintptr]hcldec.Spec
+}
+
+var decoderSpecCache = specCache{
+	specs: map[uintptr]hcldec.Spec{},
+}
+
+// get returns the Spec associated with eth given Block, or nil if non is
+// found.
+func (s *specCache) get(b *Block) hcldec.Spec {
+	s.Lock()
+	defer s.Unlock()
+	k := uintptr(unsafe.Pointer(b))
+	return s.specs[k]
+}
+
+// set stores the given Spec as being the result of b.DecoderSpec().
+func (s *specCache) set(b *Block, spec hcldec.Spec) {
+	s.Lock()
+	defer s.Unlock()
+
+	// the uintptr value gets us a unique identifier for each block, without
+	// tying this to the block value itself.
+	k := uintptr(unsafe.Pointer(b))
+	if _, ok := s.specs[k]; ok {
+		return
+	}
+
+	s.specs[k] = spec
+
+	// This must use a finalizer tied to the Block, otherwise we'll continue to
+	// build up Spec values as the Blocks are recycled.
+	runtime.SetFinalizer(b, s.delete)
+}
+
+// delete removes the spec associated with the given Block.
+func (s *specCache) delete(b *Block) {
+	s.Lock()
+	defer s.Unlock()
+
+	k := uintptr(unsafe.Pointer(b))
+	delete(s.specs, k)
+}
+
+// DecoderSpec returns a hcldec.Spec that can be used to decode a HCL Body
+// using the facilities in the hcldec package.
+//
+// The returned specification is guaranteed to return a value of the same type
+// returned by method ImpliedType, but it may contain null values if any of the
+// block attributes are defined as optional and/or computed respectively.
+func (b *Block) DecoderSpec() hcldec.Spec {
+	ret := hcldec.ObjectSpec{}
+	if b == nil {
+		return ret
+	}
+
+	if spec := decoderSpecCache.get(b); spec != nil {
+		return spec
+	}
+
+	for name, attrS := range b.Attributes {
+		ret[name] = attrS.decoderSpec(name)
+	}
+
+	for name, blockS := range b.BlockTypes {
+		if _, exists := ret[name]; exists {
+			// This indicates an invalid schema, since it's not valid to define
+			// both an attribute and a block type of the same name. We assume
+			// that the provider has already used something like
+			// InternalValidate to validate their schema.
+			continue
+		}
+
+		childSpec := blockS.Block.DecoderSpec()
+
+		switch blockS.Nesting {
+		case NestingSingle, NestingGroup:
+			ret[name] = &hcldec.BlockSpec{
+				TypeName: name,
+				Nested:   childSpec,
+				Required: blockS.MinItems == 1,
+			}
+			if blockS.Nesting == NestingGroup {
+				ret[name] = &hcldec.DefaultSpec{
+					Primary: ret[name],
+					Default: &hcldec.LiteralSpec{
+						Value: blockS.EmptyValue(),
+					},
+				}
+			}
+		case NestingList:
+			// We prefer to use a list where possible, since it makes our
+			// implied type more complete, but if there are any
+			// dynamically-typed attributes inside we must use a tuple
+			// instead, at the expense of our type then not being predictable.
+			if blockS.Block.specType().HasDynamicTypes() {
+				ret[name] = &hcldec.BlockTupleSpec{
+					TypeName: name,
+					Nested:   childSpec,
+					MinItems: blockS.MinItems,
+					MaxItems: blockS.MaxItems,
+				}
+			} else {
+				ret[name] = &hcldec.BlockListSpec{
+					TypeName: name,
+					Nested:   childSpec,
+					MinItems: blockS.MinItems,
+					MaxItems: blockS.MaxItems,
+				}
+			}
+		case NestingSet:
+			// We forbid dynamically-typed attributes inside NestingSet in
+			// InternalValidate, so we don't do anything special to handle that
+			// here. (There is no set analog to tuple and object types, because
+			// cty's set implementation depends on knowing the static type in
+			// order to properly compute its internal hashes.)  We assume that
+			// the provider has already used something like InternalValidate to
+			// validate their schema.
+			ret[name] = &hcldec.BlockSetSpec{
+				TypeName: name,
+				Nested:   childSpec,
+				MinItems: blockS.MinItems,
+				MaxItems: blockS.MaxItems,
+			}
+		case NestingMap:
+			// We prefer to use a list where possible, since it makes our
+			// implied type more complete, but if there are any
+			// dynamically-typed attributes inside we must use a tuple
+			// instead, at the expense of our type then not being predictable.
+			if blockS.Block.specType().HasDynamicTypes() {
+				ret[name] = &hcldec.BlockObjectSpec{
+					TypeName:   name,
+					Nested:     childSpec,
+					LabelNames: mapLabelNames,
+				}
+			} else {
+				ret[name] = &hcldec.BlockMapSpec{
+					TypeName:   name,
+					Nested:     childSpec,
+					LabelNames: mapLabelNames,
+				}
+			}
+		default:
+			// Invalid nesting type is just ignored. It's checked by
+			// InternalValidate.  We assume that the provider has already used
+			// something like InternalValidate to validate their schema.
+			continue
+		}
+	}
+
+	decoderSpecCache.set(b, ret)
+	return ret
+}
+
+func (a *Attribute) decoderSpec(name string) hcldec.Spec {
+	ret := &hcldec.AttrSpec{Name: name}
+	if a == nil {
+		return ret
+	}
+
+	if a.NestedType != nil {
+		if a.Type != cty.NilType {
+			panic("Invalid attribute schema: NestedType and Type cannot both be set. This is a bug in the provider.")
+		}
+
+		ty := a.NestedType.specType()
+		ret.Type = ty
+		ret.Required = a.Required
+		return ret
+	}
+
+	ret.Type = a.Type
+	ret.Required = a.Required
+	return ret
+}
+
+// listOptionalAttrsFromObject is a helper function which does *not* recurse
+// into NestedType Attributes, because the optional types for each of those will
+// belong to their own cty.Object definitions. It is used in other functions
+// which themselves handle that recursion.
+func listOptionalAttrsFromObject(o *Object) []string {
+	ret := make([]string, 0)
+
+	// This is unlikely to happen outside of tests.
+	if o == nil {
+		return ret
+	}
+
+	for name, attr := range o.Attributes {
+		if attr.Optional || attr.Computed {
+			ret = append(ret, name)
+		}
+	}
+	return ret
+}
diff --git a/v1.5.7/internal/configs/configschema/decoder_spec_test.go b/v1.5.7/internal/configs/configschema/decoder_spec_test.go
new file mode 100644
index 0000000..dc76033
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/decoder_spec_test.go
@@ -0,0 +1,932 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"sort"
+	"testing"
+
+	"github.com/apparentlymart/go-dump/dump"
+	"github.com/davecgh/go-spew/spew"
+	"github.com/google/go-cmp/cmp"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcldec"
+	"github.com/hashicorp/hcl/v2/hcltest"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestBlockDecoderSpec(t *testing.T) {
+	tests := map[string]struct {
+		Schema    *Block
+		TestBody  hcl.Body
+		Want      cty.Value
+		DiagCount int
+	}{
+		"empty": {
+			&Block{},
+			hcl.EmptyBody(),
+			cty.EmptyObjectVal,
+			0,
+		},
+		"nil": {
+			nil,
+			hcl.EmptyBody(),
+			cty.EmptyObjectVal,
+			0,
+		},
+		"attributes": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"optional": {
+						Type:     cty.Number,
+						Optional: true,
+					},
+					"required": {
+						Type:     cty.String,
+						Required: true,
+					},
+					"computed": {
+						Type:     cty.List(cty.Bool),
+						Computed: true,
+					},
+					"optional_computed": {
+						Type:     cty.Map(cty.Bool),
+						Optional: true,
+						Computed: true,
+					},
+					"optional_computed_overridden": {
+						Type:     cty.Bool,
+						Optional: true,
+						Computed: true,
+					},
+					"optional_computed_unknown": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+				},
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"required": {
+						Name: "required",
+						Expr: hcltest.MockExprLiteral(cty.NumberIntVal(5)),
+					},
+					"optional_computed_overridden": {
+						Name: "optional_computed_overridden",
+						Expr: hcltest.MockExprLiteral(cty.True),
+					},
+					"optional_computed_unknown": {
+						Name: "optional_computed_overridden",
+						Expr: hcltest.MockExprLiteral(cty.UnknownVal(cty.String)),
+					},
+				},
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"optional":                     cty.NullVal(cty.Number),
+				"required":                     cty.StringVal("5"), // converted from number to string
+				"computed":                     cty.NullVal(cty.List(cty.Bool)),
+				"optional_computed":            cty.NullVal(cty.Map(cty.Bool)),
+				"optional_computed_overridden": cty.True,
+				"optional_computed_unknown":    cty.UnknownVal(cty.String),
+			}),
+			0,
+		},
+		"dynamically-typed attribute": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						Type:     cty.DynamicPseudoType, // any type is permitted
+						Required: true,
+					},
+				},
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"foo": {
+						Name: "foo",
+						Expr: hcltest.MockExprLiteral(cty.True),
+					},
+				},
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.True,
+			}),
+			0,
+		},
+		"dynamically-typed attribute omitted": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						Type:     cty.DynamicPseudoType, // any type is permitted
+						Optional: true,
+					},
+				},
+			},
+			hcltest.MockBody(&hcl.BodyContent{}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(cty.DynamicPseudoType),
+			}),
+			0,
+		},
+		"required attribute omitted": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						Type:     cty.Bool,
+						Required: true,
+					},
+				},
+			},
+			hcltest.MockBody(&hcl.BodyContent{}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(cty.Bool),
+			}),
+			1, // missing required attribute
+		},
+		"wrong attribute type": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"optional": {
+						Type:     cty.Number,
+						Optional: true,
+					},
+				},
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"optional": {
+						Name: "optional",
+						Expr: hcltest.MockExprLiteral(cty.True),
+					},
+				},
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"optional": cty.UnknownVal(cty.Number),
+			}),
+			1, // incorrect type; number required
+		},
+		"blocks": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"single": {
+						Nesting: NestingSingle,
+						Block:   Block{},
+					},
+					"list": {
+						Nesting: NestingList,
+						Block:   Block{},
+					},
+					"set": {
+						Nesting: NestingSet,
+						Block:   Block{},
+					},
+					"map": {
+						Nesting: NestingMap,
+						Block:   Block{},
+					},
+				},
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Blocks: hcl.Blocks{
+					&hcl.Block{
+						Type: "list",
+						Body: hcl.EmptyBody(),
+					},
+					&hcl.Block{
+						Type: "single",
+						Body: hcl.EmptyBody(),
+					},
+					&hcl.Block{
+						Type: "list",
+						Body: hcl.EmptyBody(),
+					},
+					&hcl.Block{
+						Type: "set",
+						Body: hcl.EmptyBody(),
+					},
+					&hcl.Block{
+						Type:        "map",
+						Labels:      []string{"foo"},
+						LabelRanges: []hcl.Range{hcl.Range{}},
+						Body:        hcl.EmptyBody(),
+					},
+					&hcl.Block{
+						Type:        "map",
+						Labels:      []string{"bar"},
+						LabelRanges: []hcl.Range{hcl.Range{}},
+						Body:        hcl.EmptyBody(),
+					},
+					&hcl.Block{
+						Type: "set",
+						Body: hcl.EmptyBody(),
+					},
+				},
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"single": cty.EmptyObjectVal,
+				"list": cty.ListVal([]cty.Value{
+					cty.EmptyObjectVal,
+					cty.EmptyObjectVal,
+				}),
+				"set": cty.SetVal([]cty.Value{
+					cty.EmptyObjectVal,
+					cty.EmptyObjectVal,
+				}),
+				"map": cty.MapVal(map[string]cty.Value{
+					"foo": cty.EmptyObjectVal,
+					"bar": cty.EmptyObjectVal,
+				}),
+			}),
+			0,
+		},
+		"blocks with dynamically-typed attributes": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"single": {
+						Nesting: NestingSingle,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"a": {
+									Type:     cty.DynamicPseudoType,
+									Optional: true,
+								},
+							},
+						},
+					},
+					"list": {
+						Nesting: NestingList,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"a": {
+									Type:     cty.DynamicPseudoType,
+									Optional: true,
+								},
+							},
+						},
+					},
+					"map": {
+						Nesting: NestingMap,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"a": {
+									Type:     cty.DynamicPseudoType,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Blocks: hcl.Blocks{
+					&hcl.Block{
+						Type: "list",
+						Body: hcl.EmptyBody(),
+					},
+					&hcl.Block{
+						Type: "single",
+						Body: hcl.EmptyBody(),
+					},
+					&hcl.Block{
+						Type: "list",
+						Body: hcl.EmptyBody(),
+					},
+					&hcl.Block{
+						Type:        "map",
+						Labels:      []string{"foo"},
+						LabelRanges: []hcl.Range{hcl.Range{}},
+						Body:        hcl.EmptyBody(),
+					},
+					&hcl.Block{
+						Type:        "map",
+						Labels:      []string{"bar"},
+						LabelRanges: []hcl.Range{hcl.Range{}},
+						Body:        hcl.EmptyBody(),
+					},
+				},
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"single": cty.ObjectVal(map[string]cty.Value{
+					"a": cty.NullVal(cty.DynamicPseudoType),
+				}),
+				"list": cty.TupleVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"a": cty.NullVal(cty.DynamicPseudoType),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"a": cty.NullVal(cty.DynamicPseudoType),
+					}),
+				}),
+				"map": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.ObjectVal(map[string]cty.Value{
+						"a": cty.NullVal(cty.DynamicPseudoType),
+					}),
+					"bar": cty.ObjectVal(map[string]cty.Value{
+						"a": cty.NullVal(cty.DynamicPseudoType),
+					}),
+				}),
+			}),
+			0,
+		},
+		"too many list items": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Nesting:  NestingList,
+						Block:    Block{},
+						MaxItems: 1,
+					},
+				},
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Blocks: hcl.Blocks{
+					&hcl.Block{
+						Type: "foo",
+						Body: hcl.EmptyBody(),
+					},
+					&hcl.Block{
+						Type: "foo",
+						Body: unknownBody{hcl.EmptyBody()},
+					},
+				},
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.UnknownVal(cty.List(cty.EmptyObject)),
+			}),
+			0, // max items cannot be validated during decode
+		},
+		// dynamic blocks may fulfill MinItems, but there is only one block to
+		// decode.
+		"required MinItems": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Nesting:  NestingList,
+						Block:    Block{},
+						MinItems: 2,
+					},
+				},
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Blocks: hcl.Blocks{
+					&hcl.Block{
+						Type: "foo",
+						Body: unknownBody{hcl.EmptyBody()},
+					},
+				},
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.UnknownVal(cty.List(cty.EmptyObject)),
+			}),
+			0,
+		},
+		"extraneous attribute": {
+			&Block{},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"extra": {
+						Name: "extra",
+						Expr: hcltest.MockExprLiteral(cty.StringVal("hello")),
+					},
+				},
+			}),
+			cty.EmptyObjectVal,
+			1, // extraneous attribute
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			spec := test.Schema.DecoderSpec()
+
+			got, diags := hcldec.Decode(test.TestBody, spec, nil)
+			if len(diags) != test.DiagCount {
+				t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.DiagCount)
+				for _, diag := range diags {
+					t.Logf("- %s", diag.Error())
+				}
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Logf("[INFO] implied schema is %s", spew.Sdump(hcldec.ImpliedSchema(spec)))
+				t.Errorf("wrong result\ngot:  %s\nwant: %s", dump.Value(got), dump.Value(test.Want))
+			}
+
+			// Double-check that we're producing consistent results for DecoderSpec
+			// and ImpliedType.
+			impliedType := test.Schema.ImpliedType()
+			if errs := got.Type().TestConformance(impliedType); len(errs) != 0 {
+				t.Errorf("result does not conform to the schema's implied type")
+				for _, err := range errs {
+					t.Logf("- %s", err.Error())
+				}
+			}
+		})
+	}
+}
+
+// this satisfies hcldec.UnknownBody to simulate a dynamic block with an
+// unknown number of values.
+type unknownBody struct {
+	hcl.Body
+}
+
+func (b unknownBody) Unknown() bool {
+	return true
+}
+
+func TestAttributeDecoderSpec(t *testing.T) {
+	tests := map[string]struct {
+		Schema    *Attribute
+		TestBody  hcl.Body
+		Want      cty.Value
+		DiagCount int
+	}{
+		"empty": {
+			&Attribute{},
+			hcl.EmptyBody(),
+			cty.NilVal,
+			0,
+		},
+		"nil": {
+			nil,
+			hcl.EmptyBody(),
+			cty.NilVal,
+			0,
+		},
+		"optional string (null)": {
+			&Attribute{
+				Type:     cty.String,
+				Optional: true,
+			},
+			hcltest.MockBody(&hcl.BodyContent{}),
+			cty.NullVal(cty.String),
+			0,
+		},
+		"optional string": {
+			&Attribute{
+				Type:     cty.String,
+				Optional: true,
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"attr": {
+						Name: "attr",
+						Expr: hcltest.MockExprLiteral(cty.StringVal("bar")),
+					},
+				},
+			}),
+			cty.StringVal("bar"),
+			0,
+		},
+		"NestedType with required string": {
+			&Attribute{
+				NestedType: &Object{
+					Nesting: NestingSingle,
+					Attributes: map[string]*Attribute{
+						"foo": {
+							Type:     cty.String,
+							Required: true,
+						},
+					},
+				},
+				Optional: true,
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"attr": {
+						Name: "attr",
+						Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
+							"foo": cty.StringVal("bar"),
+						})),
+					},
+				},
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+			}),
+			0,
+		},
+		"NestedType with optional attributes": {
+			&Attribute{
+				NestedType: &Object{
+					Nesting: NestingSingle,
+					Attributes: map[string]*Attribute{
+						"foo": {
+							Type:     cty.String,
+							Optional: true,
+						},
+						"bar": {
+							Type:     cty.String,
+							Optional: true,
+						},
+					},
+				},
+				Optional: true,
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"attr": {
+						Name: "attr",
+						Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
+							"foo": cty.StringVal("bar"),
+						})),
+					},
+				},
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+				"bar": cty.NullVal(cty.String),
+			}),
+			0,
+		},
+		"NestedType with missing required string": {
+			&Attribute{
+				NestedType: &Object{
+					Nesting: NestingSingle,
+					Attributes: map[string]*Attribute{
+						"foo": {
+							Type:     cty.String,
+							Required: true,
+						},
+					},
+				},
+				Optional: true,
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"attr": {
+						Name: "attr",
+						Expr: hcltest.MockExprLiteral(cty.EmptyObjectVal),
+					},
+				},
+			}),
+			cty.UnknownVal(cty.Object(map[string]cty.Type{
+				"foo": cty.String,
+			})),
+			1,
+		},
+		// NestedModes
+		"NestedType NestingModeList valid": {
+			&Attribute{
+				NestedType: &Object{
+					Nesting: NestingList,
+					Attributes: map[string]*Attribute{
+						"foo": {
+							Type:     cty.String,
+							Required: true,
+						},
+					},
+				},
+				Optional: true,
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"attr": {
+						Name: "attr",
+						Expr: hcltest.MockExprLiteral(cty.ListVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.StringVal("bar"),
+							}),
+							cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.StringVal("baz"),
+							}),
+						})),
+					},
+				},
+			}),
+			cty.ListVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("bar")}),
+				cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("baz")}),
+			}),
+			0,
+		},
+		"NestedType NestingModeList invalid": {
+			&Attribute{
+				NestedType: &Object{
+					Nesting: NestingList,
+					Attributes: map[string]*Attribute{
+						"foo": {
+							Type:     cty.String,
+							Required: true,
+						},
+					},
+				},
+				Optional: true,
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"attr": {
+						Name: "attr",
+						Expr: hcltest.MockExprLiteral(cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+							// "foo" should be a string, not a list
+							"foo": cty.ListVal([]cty.Value{cty.StringVal("bar"), cty.StringVal("baz")}),
+						})})),
+					},
+				},
+			}),
+			cty.UnknownVal(cty.List(cty.Object(map[string]cty.Type{"foo": cty.String}))),
+			1,
+		},
+		"NestedType NestingModeSet valid": {
+			&Attribute{
+				NestedType: &Object{
+					Nesting: NestingSet,
+					Attributes: map[string]*Attribute{
+						"foo": {
+							Type:     cty.String,
+							Required: true,
+						},
+					},
+				},
+				Optional: true,
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"attr": {
+						Name: "attr",
+						Expr: hcltest.MockExprLiteral(cty.SetVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.StringVal("bar"),
+							}),
+							cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.StringVal("baz"),
+							}),
+						})),
+					},
+				},
+			}),
+			cty.SetVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("bar")}),
+				cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("baz")}),
+			}),
+			0,
+		},
+		"NestedType NestingModeSet invalid": {
+			&Attribute{
+				NestedType: &Object{
+					Nesting: NestingSet,
+					Attributes: map[string]*Attribute{
+						"foo": {
+							Type:     cty.String,
+							Required: true,
+						},
+					},
+				},
+				Optional: true,
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"attr": {
+						Name: "attr",
+						Expr: hcltest.MockExprLiteral(cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+							// "foo" should be a string, not a list
+							"foo": cty.ListVal([]cty.Value{cty.StringVal("bar"), cty.StringVal("baz")}),
+						})})),
+					},
+				},
+			}),
+			cty.UnknownVal(cty.Set(cty.Object(map[string]cty.Type{"foo": cty.String}))),
+			1,
+		},
+		"NestedType NestingModeMap valid": {
+			&Attribute{
+				NestedType: &Object{
+					Nesting: NestingMap,
+					Attributes: map[string]*Attribute{
+						"foo": {
+							Type:     cty.String,
+							Required: true,
+						},
+					},
+				},
+				Optional: true,
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"attr": {
+						Name: "attr",
+						Expr: hcltest.MockExprLiteral(cty.MapVal(map[string]cty.Value{
+							"one": cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.StringVal("bar"),
+							}),
+							"two": cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.StringVal("baz"),
+							}),
+						})),
+					},
+				},
+			}),
+			cty.MapVal(map[string]cty.Value{
+				"one": cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("bar")}),
+				"two": cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("baz")}),
+			}),
+			0,
+		},
+		"NestedType NestingModeMap invalid": {
+			&Attribute{
+				NestedType: &Object{
+					Nesting: NestingMap,
+					Attributes: map[string]*Attribute{
+						"foo": {
+							Type:     cty.String,
+							Required: true,
+						},
+					},
+				},
+				Optional: true,
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"attr": {
+						Name: "attr",
+						Expr: hcltest.MockExprLiteral(cty.MapVal(map[string]cty.Value{
+							"one": cty.ObjectVal(map[string]cty.Value{
+								// "foo" should be a string, not a list
+								"foo": cty.ListVal([]cty.Value{cty.StringVal("bar"), cty.StringVal("baz")}),
+							}),
+						})),
+					},
+				},
+			}),
+			cty.UnknownVal(cty.Map(cty.Object(map[string]cty.Type{"foo": cty.String}))),
+			1,
+		},
+		"deeply NestedType NestingModeList valid": {
+			&Attribute{
+				NestedType: &Object{
+					Nesting: NestingList,
+					Attributes: map[string]*Attribute{
+						"foo": {
+							NestedType: &Object{
+								Nesting: NestingList,
+								Attributes: map[string]*Attribute{
+									"bar": {
+										Type:     cty.String,
+										Required: true,
+									},
+								},
+							},
+							Required: true,
+						},
+					},
+				},
+				Optional: true,
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"attr": {
+						Name: "attr",
+						Expr: hcltest.MockExprLiteral(cty.ListVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.ListVal([]cty.Value{
+									cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("baz")}),
+									cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("boz")}),
+								}),
+							}),
+							cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.ListVal([]cty.Value{
+									cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("biz")}),
+									cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("buz")}),
+								}),
+							}),
+						})),
+					},
+				},
+			}),
+			cty.ListVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("baz")}),
+					cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("boz")}),
+				})}),
+				cty.ObjectVal(map[string]cty.Value{"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("biz")}),
+					cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("buz")}),
+				})}),
+			}),
+			0,
+		},
+		"deeply NestedType NestingList invalid": {
+			&Attribute{
+				NestedType: &Object{
+					Nesting: NestingList,
+					Attributes: map[string]*Attribute{
+						"foo": {
+							NestedType: &Object{
+								Nesting: NestingList,
+								Attributes: map[string]*Attribute{
+									"bar": {
+										Type:     cty.Number,
+										Required: true,
+									},
+								},
+							},
+							Required: true,
+						},
+					},
+				},
+				Optional: true,
+			},
+			hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"attr": {
+						Name: "attr",
+						Expr: hcltest.MockExprLiteral(cty.ListVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.ListVal([]cty.Value{
+									// bar should be a Number
+									cty.ObjectVal(map[string]cty.Value{"bar": cty.True}),
+									cty.ObjectVal(map[string]cty.Value{"bar": cty.False}),
+								}),
+							}),
+						})),
+					},
+				},
+			}),
+			cty.UnknownVal(cty.List(cty.Object(map[string]cty.Type{
+				"foo": cty.List(cty.Object(map[string]cty.Type{"bar": cty.Number})),
+			}))),
+			1,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			spec := test.Schema.decoderSpec("attr")
+			got, diags := hcldec.Decode(test.TestBody, spec, nil)
+			if len(diags) != test.DiagCount {
+				t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.DiagCount)
+				for _, diag := range diags {
+					t.Logf("- %s", diag.Error())
+				}
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Logf("[INFO] implied schema is %s", spew.Sdump(hcldec.ImpliedSchema(spec)))
+				t.Errorf("wrong result\ngot:  %s\nwant: %s", dump.Value(got), dump.Value(test.Want))
+			}
+		})
+	}
+
+}
+
+// TestAttributeDecodeSpec_panic is a temporary test which verifies that
+// decoderSpec panics when an invalid Attribute schema is encountered. It will
+// be removed when InternalValidate() is extended to validate Attribute specs
+// (and is used). See the #FIXME in decoderSpec.
+func TestAttributeDecoderSpec_panic(t *testing.T) {
+	attrS := &Attribute{
+		Type: cty.Object(map[string]cty.Type{
+			"nested_attribute": cty.String,
+		}),
+		NestedType: &Object{},
+		Optional:   true,
+	}
+
+	defer func() { recover() }()
+	attrS.decoderSpec("attr")
+	t.Errorf("expected panic")
+}
+
+func TestListOptionalAttrsFromObject(t *testing.T) {
+	tests := []struct {
+		input *Object
+		want  []string
+	}{
+		{
+			nil,
+			[]string{},
+		},
+		{
+			&Object{},
+			[]string{},
+		},
+		{
+			&Object{
+				Nesting: NestingSingle,
+				Attributes: map[string]*Attribute{
+					"optional":          {Type: cty.String, Optional: true},
+					"required":          {Type: cty.Number, Required: true},
+					"computed":          {Type: cty.List(cty.Bool), Computed: true},
+					"optional_computed": {Type: cty.Map(cty.Bool), Optional: true, Computed: true},
+				},
+			},
+			[]string{"optional", "computed", "optional_computed"},
+		},
+	}
+
+	for _, test := range tests {
+		got := listOptionalAttrsFromObject(test.input)
+
+		// order is irrelevant
+		sort.Strings(got)
+		sort.Strings(test.want)
+
+		if diff := cmp.Diff(got, test.want); diff != "" {
+			t.Fatalf("wrong result: %s\n", diff)
+		}
+	}
+}
diff --git a/v1.5.7/internal/configs/configschema/doc.go b/v1.5.7/internal/configs/configschema/doc.go
new file mode 100644
index 0000000..d96be9c
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/doc.go
@@ -0,0 +1,17 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package configschema contains types for describing the expected structure
+// of a configuration block whose shape is not known until runtime.
+//
+// For example, this is used to describe the expected contents of a resource
+// configuration block, which is defined by the corresponding provider plugin
+// and thus not compiled into Terraform core.
+//
+// A configschema primarily describes the shape of configuration, but it is
+// also suitable for use with other structures derived from the configuration,
+// such as the cached state of a resource or a resource diff.
+//
+// This package should not be confused with the package helper/schema, which
+// is the higher-level helper library used to implement providers themselves.
+package configschema
diff --git a/v1.5.7/internal/configs/configschema/empty_value.go b/v1.5.7/internal/configs/configschema/empty_value.go
new file mode 100644
index 0000000..a768e14
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/empty_value.go
@@ -0,0 +1,62 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"github.com/zclconf/go-cty/cty"
+)
+
+// EmptyValue returns the "empty value" for the recieving block, which for
+// a block type is a non-null object where all of the attribute values are
+// the empty values of the block's attributes and nested block types.
+//
+// In other words, it returns the value that would be returned if an empty
+// block were decoded against the recieving schema, assuming that no required
+// attribute or block constraints were honored.
+func (b *Block) EmptyValue() cty.Value {
+	vals := make(map[string]cty.Value)
+	for name, attrS := range b.Attributes {
+		vals[name] = attrS.EmptyValue()
+	}
+	for name, blockS := range b.BlockTypes {
+		vals[name] = blockS.EmptyValue()
+	}
+	return cty.ObjectVal(vals)
+}
+
+// EmptyValue returns the "empty value" for the receiving attribute, which is
+// the value that would be returned if there were no definition of the attribute
+// at all, ignoring any required constraint.
+func (a *Attribute) EmptyValue() cty.Value {
+	return cty.NullVal(a.ImpliedType())
+}
+
+// EmptyValue returns the "empty value" for when there are zero nested blocks
+// present of the receiving type.
+func (b *NestedBlock) EmptyValue() cty.Value {
+	switch b.Nesting {
+	case NestingSingle:
+		return cty.NullVal(b.Block.ImpliedType())
+	case NestingGroup:
+		return b.Block.EmptyValue()
+	case NestingList:
+		if ty := b.Block.ImpliedType(); ty.HasDynamicTypes() {
+			return cty.EmptyTupleVal
+		} else {
+			return cty.ListValEmpty(ty)
+		}
+	case NestingMap:
+		if ty := b.Block.ImpliedType(); ty.HasDynamicTypes() {
+			return cty.EmptyObjectVal
+		} else {
+			return cty.MapValEmpty(ty)
+		}
+	case NestingSet:
+		return cty.SetValEmpty(b.Block.ImpliedType())
+	default:
+		// Should never get here because the above is intended to be exhaustive,
+		// but we'll be robust and return a result nonetheless.
+		return cty.NullVal(cty.DynamicPseudoType)
+	}
+}
diff --git a/v1.5.7/internal/configs/configschema/empty_value_test.go b/v1.5.7/internal/configs/configschema/empty_value_test.go
new file mode 100644
index 0000000..ddf81e0
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/empty_value_test.go
@@ -0,0 +1,260 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/apparentlymart/go-dump/dump"
+	"github.com/davecgh/go-spew/spew"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestBlockEmptyValue(t *testing.T) {
+	tests := []struct {
+		Schema *Block
+		Want   cty.Value
+	}{
+		{
+			&Block{},
+			cty.EmptyObjectVal,
+		},
+		{
+			&Block{
+				Attributes: map[string]*Attribute{
+					"str": {Type: cty.String, Required: true},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"str": cty.NullVal(cty.String),
+			}),
+		},
+		{
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"single": {
+						Nesting: NestingSingle,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"str": {Type: cty.String, Required: true},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"single": cty.NullVal(cty.Object(map[string]cty.Type{
+					"str": cty.String,
+				})),
+			}),
+		},
+		{
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"group": {
+						Nesting: NestingGroup,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"str": {Type: cty.String, Required: true},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"group": cty.ObjectVal(map[string]cty.Value{
+					"str": cty.NullVal(cty.String),
+				}),
+			}),
+		},
+		{
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"list": {
+						Nesting: NestingList,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"str": {Type: cty.String, Required: true},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"list": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+					"str": cty.String,
+				})),
+			}),
+		},
+		{
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"list_dynamic": {
+						Nesting: NestingList,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"str": {Type: cty.DynamicPseudoType, Required: true},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"list_dynamic": cty.EmptyTupleVal,
+			}),
+		},
+		{
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"map": {
+						Nesting: NestingMap,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"str": {Type: cty.String, Required: true},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"map": cty.MapValEmpty(cty.Object(map[string]cty.Type{
+					"str": cty.String,
+				})),
+			}),
+		},
+		{
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"map_dynamic": {
+						Nesting: NestingMap,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"str": {Type: cty.DynamicPseudoType, Required: true},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"map_dynamic": cty.EmptyObjectVal,
+			}),
+		},
+		{
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"set": {
+						Nesting: NestingSet,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"str": {Type: cty.String, Required: true},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"set": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"str": cty.String,
+				})),
+			}),
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%#v", test.Schema), func(t *testing.T) {
+			got := test.Schema.EmptyValue()
+			if !test.Want.RawEquals(got) {
+				t.Errorf("wrong result\nschema: %s\ngot: %s\nwant: %s", spew.Sdump(test.Schema), dump.Value(got), dump.Value(test.Want))
+			}
+		})
+	}
+}
+
+// Attribute EmptyValue() is well covered by the Block tests above; these tests
+// focus on the behavior with NestedType field inside an Attribute
+func TestAttributeEmptyValue(t *testing.T) {
+	tests := []struct {
+		Schema *Attribute
+		Want   cty.Value
+	}{
+		{
+			&Attribute{},
+			cty.NilVal,
+		},
+		{
+			&Attribute{
+				Type: cty.String,
+			},
+			cty.NullVal(cty.String),
+		},
+		{
+			&Attribute{
+				NestedType: &Object{
+					Nesting: NestingSingle,
+					Attributes: map[string]*Attribute{
+						"str": {Type: cty.String, Required: true},
+					},
+				},
+			},
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"str": cty.String,
+			})),
+		},
+		{
+			&Attribute{
+				NestedType: &Object{
+					Nesting: NestingList,
+					Attributes: map[string]*Attribute{
+						"str": {Type: cty.String, Required: true},
+					},
+				},
+			},
+			cty.NullVal(cty.List(
+				cty.Object(map[string]cty.Type{
+					"str": cty.String,
+				}),
+			)),
+		},
+		{
+			&Attribute{
+				NestedType: &Object{
+					Nesting: NestingMap,
+					Attributes: map[string]*Attribute{
+						"str": {Type: cty.String, Required: true},
+					},
+				},
+			},
+			cty.NullVal(cty.Map(
+				cty.Object(map[string]cty.Type{
+					"str": cty.String,
+				}),
+			)),
+		},
+		{
+			&Attribute{
+				NestedType: &Object{
+					Nesting: NestingSet,
+					Attributes: map[string]*Attribute{
+						"str": {Type: cty.String, Required: true},
+					},
+				},
+			},
+			cty.NullVal(cty.Set(
+				cty.Object(map[string]cty.Type{
+					"str": cty.String,
+				}),
+			)),
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%#v", test.Schema), func(t *testing.T) {
+			got := test.Schema.EmptyValue()
+			if !test.Want.RawEquals(got) {
+				t.Errorf("wrong result\nschema: %s\ngot: %s\nwant: %s", spew.Sdump(test.Schema), dump.Value(got), dump.Value(test.Want))
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/configs/configschema/filter.go b/v1.5.7/internal/configs/configschema/filter.go
new file mode 100644
index 0000000..bb0f3d8
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/filter.go
@@ -0,0 +1,95 @@
+package configschema
+
+type FilterT[T any] func(string, T) bool
+
+var (
+	FilterReadOnlyAttribute = func(name string, attribute *Attribute) bool {
+		return attribute.Computed && !attribute.Optional
+	}
+
+	FilterHelperSchemaIdAttribute = func(name string, attribute *Attribute) bool {
+		if name == "id" && attribute.Computed && attribute.Optional {
+			return true
+		}
+		return false
+	}
+
+	FilterDeprecatedAttribute = func(name string, attribute *Attribute) bool {
+		return attribute.Deprecated
+	}
+
+	FilterDeprecatedBlock = func(name string, block *NestedBlock) bool {
+		return block.Deprecated
+	}
+)
+
+func FilterOr[T any](filters ...FilterT[T]) FilterT[T] {
+	return func(name string, value T) bool {
+		for _, f := range filters {
+			if f(name, value) {
+				return true
+			}
+		}
+		return false
+	}
+}
+
+func (b *Block) Filter(filterAttribute FilterT[*Attribute], filterBlock FilterT[*NestedBlock]) *Block {
+	ret := &Block{
+		Description:     b.Description,
+		DescriptionKind: b.DescriptionKind,
+		Deprecated:      b.Deprecated,
+	}
+
+	if b.Attributes != nil {
+		ret.Attributes = make(map[string]*Attribute, len(b.Attributes))
+	}
+	for name, attrS := range b.Attributes {
+		if filterAttribute == nil || !filterAttribute(name, attrS) {
+			ret.Attributes[name] = attrS
+		}
+
+		if attrS.NestedType != nil {
+			ret.Attributes[name].NestedType = filterNestedType(attrS.NestedType, filterAttribute)
+		}
+	}
+
+	if b.BlockTypes != nil {
+		ret.BlockTypes = make(map[string]*NestedBlock, len(b.BlockTypes))
+	}
+	for name, blockS := range b.BlockTypes {
+		if filterBlock == nil || !filterBlock(name, blockS) {
+			block := blockS.Filter(filterAttribute, filterBlock)
+			ret.BlockTypes[name] = &NestedBlock{
+				Block:    *block,
+				Nesting:  blockS.Nesting,
+				MinItems: blockS.MinItems,
+				MaxItems: blockS.MaxItems,
+			}
+		}
+	}
+
+	return ret
+}
+
+func filterNestedType(obj *Object, filterAttribute FilterT[*Attribute]) *Object {
+	if obj == nil {
+		return nil
+	}
+
+	ret := &Object{
+		Attributes: map[string]*Attribute{},
+		Nesting:    obj.Nesting,
+	}
+
+	for name, attrS := range obj.Attributes {
+		if filterAttribute == nil || !filterAttribute(name, attrS) {
+			ret.Attributes[name] = attrS
+			if attrS.NestedType != nil {
+				ret.Attributes[name].NestedType = filterNestedType(attrS.NestedType, filterAttribute)
+			}
+		}
+	}
+
+	return ret
+}
diff --git a/v1.5.7/internal/configs/configschema/filter_test.go b/v1.5.7/internal/configs/configschema/filter_test.go
new file mode 100644
index 0000000..29b6115
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/filter_test.go
@@ -0,0 +1,278 @@
+package configschema
+
+import (
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+)
+
+func TestFilter(t *testing.T) {
+	testCases := map[string]struct {
+		schema          *Block
+		filterAttribute FilterT[*Attribute]
+		filterBlock     FilterT[*NestedBlock]
+		want            *Block
+	}{
+		"empty": {
+			schema:          &Block{},
+			filterAttribute: FilterDeprecatedAttribute,
+			filterBlock:     FilterDeprecatedBlock,
+			want:            &Block{},
+		},
+		"noop": {
+			schema: &Block{
+				Attributes: map[string]*Attribute{
+					"string": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+				BlockTypes: map[string]*NestedBlock{
+					"list": {
+						Nesting: NestingList,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"string": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			filterAttribute: nil,
+			filterBlock:     nil,
+			want: &Block{
+				Attributes: map[string]*Attribute{
+					"string": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+				BlockTypes: map[string]*NestedBlock{
+					"list": {
+						Nesting: NestingList,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"string": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		"filter_deprecated": {
+			schema: &Block{
+				Attributes: map[string]*Attribute{
+					"string": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"deprecated_string": {
+						Type:       cty.String,
+						Deprecated: true,
+					},
+					"nested": {
+						NestedType: &Object{
+							Attributes: map[string]*Attribute{
+								"string": {
+									Type: cty.String,
+								},
+								"deprecated_string": {
+									Type:       cty.String,
+									Deprecated: true,
+								},
+							},
+							Nesting: NestingList,
+						},
+					},
+				},
+
+				BlockTypes: map[string]*NestedBlock{
+					"list": {
+						Nesting: NestingList,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"string": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+							Deprecated: true,
+						},
+					},
+				},
+			},
+			filterAttribute: FilterDeprecatedAttribute,
+			filterBlock:     FilterDeprecatedBlock,
+			want: &Block{
+				Attributes: map[string]*Attribute{
+					"string": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"nested": {
+						NestedType: &Object{
+							Attributes: map[string]*Attribute{
+								"string": {
+									Type: cty.String,
+								},
+							},
+							Nesting: NestingList,
+						},
+					},
+				},
+			},
+		},
+		"filter_read_only": {
+			schema: &Block{
+				Attributes: map[string]*Attribute{
+					"string": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"read_only_string": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"nested": {
+						NestedType: &Object{
+							Attributes: map[string]*Attribute{
+								"string": {
+									Type:     cty.String,
+									Optional: true,
+								},
+								"read_only_string": {
+									Type:     cty.String,
+									Computed: true,
+								},
+								"deeply_nested": {
+									NestedType: &Object{
+										Attributes: map[string]*Attribute{
+											"number": {
+												Type:     cty.Number,
+												Required: true,
+											},
+											"read_only_number": {
+												Type:     cty.Number,
+												Computed: true,
+											},
+										},
+										Nesting: NestingList,
+									},
+								},
+							},
+							Nesting: NestingList,
+						},
+					},
+				},
+
+				BlockTypes: map[string]*NestedBlock{
+					"list": {
+						Nesting: NestingList,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"string": {
+									Type:     cty.String,
+									Optional: true,
+								},
+								"read_only_string": {
+									Type:     cty.String,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			filterAttribute: FilterReadOnlyAttribute,
+			filterBlock:     nil,
+			want: &Block{
+				Attributes: map[string]*Attribute{
+					"string": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"nested": {
+						NestedType: &Object{
+							Attributes: map[string]*Attribute{
+								"string": {
+									Type:     cty.String,
+									Optional: true,
+								},
+								"deeply_nested": {
+									NestedType: &Object{
+										Attributes: map[string]*Attribute{
+											"number": {
+												Type:     cty.Number,
+												Required: true,
+											},
+										},
+										Nesting: NestingList,
+									},
+								},
+							},
+							Nesting: NestingList,
+						},
+					},
+				},
+				BlockTypes: map[string]*NestedBlock{
+					"list": {
+						Nesting: NestingList,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"string": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		"filter_optional_computed_id": {
+			schema: &Block{
+				Attributes: map[string]*Attribute{
+					"id": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+					"string": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+				},
+			},
+			filterAttribute: FilterHelperSchemaIdAttribute,
+			filterBlock:     nil,
+			want: &Block{
+				Attributes: map[string]*Attribute{
+					"string": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+				},
+			},
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got := tc.schema.Filter(tc.filterAttribute, tc.filterBlock)
+			if !cmp.Equal(got, tc.want, cmp.Comparer(cty.Type.Equals), cmpopts.EquateEmpty()) {
+				t.Fatal(cmp.Diff(got, tc.want, cmp.Comparer(cty.Type.Equals), cmpopts.EquateEmpty()))
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/configs/configschema/implied_type.go b/v1.5.7/internal/configs/configschema/implied_type.go
new file mode 100644
index 0000000..d673bdf
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/implied_type.go
@@ -0,0 +1,136 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"github.com/hashicorp/hcl/v2/hcldec"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// ImpliedType returns the cty.Type that would result from decoding a
+// configuration block using the receiving block schema.
+//
+// The type returned from Block.ImpliedType differs from the type returned by
+// hcldec.ImpliedType in that there will be no objects with optional
+// attributes, since this value is not to be used for the decoding of
+// configuration.
+//
+// ImpliedType always returns a result, even if the given schema is
+// inconsistent. Code that creates configschema.Block objects should be
+// tested using the InternalValidate method to detect any inconsistencies
+// that would cause this method to fall back on defaults and assumptions.
+func (b *Block) ImpliedType() cty.Type {
+	return b.specType().WithoutOptionalAttributesDeep()
+}
+
+// specType returns the cty.Type used for decoding a configuration
+// block using the receiving block schema. This is the type used internally by
+// hcldec to decode configuration.
+func (b *Block) specType() cty.Type {
+	if b == nil {
+		return cty.EmptyObject
+	}
+
+	return hcldec.ImpliedType(b.DecoderSpec())
+}
+
+// ContainsSensitive returns true if any of the attributes of the receiving
+// block or any of its descendent blocks are marked as sensitive.
+//
+// Blocks themselves cannot be sensitive as a whole -- sensitivity is a
+// per-attribute idea -- but sometimes we want to include a whole object
+// decoded from a block in some UI output, and that is safe to do only if
+// none of the contained attributes are sensitive.
+func (b *Block) ContainsSensitive() bool {
+	for _, attrS := range b.Attributes {
+		if attrS.Sensitive {
+			return true
+		}
+		if attrS.NestedType != nil && attrS.NestedType.ContainsSensitive() {
+			return true
+		}
+	}
+	for _, blockS := range b.BlockTypes {
+		if blockS.ContainsSensitive() {
+			return true
+		}
+	}
+	return false
+}
+
+// ImpliedType returns the cty.Type that would result from decoding a Block's
+// ImpliedType and getting the resulting AttributeType.
+//
+// ImpliedType always returns a result, even if the given schema is
+// inconsistent. Code that creates configschema.Object objects should be tested
+// using the InternalValidate method to detect any inconsistencies that would
+// cause this method to fall back on defaults and assumptions.
+func (a *Attribute) ImpliedType() cty.Type {
+	if a.NestedType != nil {
+		return a.NestedType.specType().WithoutOptionalAttributesDeep()
+	}
+	return a.Type
+}
+
+// ImpliedType returns the cty.Type that would result from decoding a
+// NestedType Attribute using the receiving block schema.
+//
+// ImpliedType always returns a result, even if the given schema is
+// inconsistent. Code that creates configschema.Object objects should be tested
+// using the InternalValidate method to detect any inconsistencies that would
+// cause this method to fall back on defaults and assumptions.
+func (o *Object) ImpliedType() cty.Type {
+	return o.specType().WithoutOptionalAttributesDeep()
+}
+
+// specType returns the cty.Type used for decoding a NestedType Attribute using
+// the receiving block schema.
+func (o *Object) specType() cty.Type {
+	if o == nil {
+		return cty.EmptyObject
+	}
+
+	attrTys := make(map[string]cty.Type, len(o.Attributes))
+	for name, attrS := range o.Attributes {
+		if attrS.NestedType != nil {
+			attrTys[name] = attrS.NestedType.specType()
+		} else {
+			attrTys[name] = attrS.Type
+		}
+	}
+	optAttrs := listOptionalAttrsFromObject(o)
+
+	var ret cty.Type
+	if len(optAttrs) > 0 {
+		ret = cty.ObjectWithOptionalAttrs(attrTys, optAttrs)
+	} else {
+		ret = cty.Object(attrTys)
+	}
+	switch o.Nesting {
+	case NestingSingle:
+		return ret
+	case NestingList:
+		return cty.List(ret)
+	case NestingMap:
+		return cty.Map(ret)
+	case NestingSet:
+		return cty.Set(ret)
+	default: // Should never happen
+		return cty.EmptyObject
+	}
+}
+
+// ContainsSensitive returns true if any of the attributes of the receiving
+// Object are marked as sensitive.
+func (o *Object) ContainsSensitive() bool {
+	for _, attrS := range o.Attributes {
+		if attrS.Sensitive {
+			return true
+		}
+		if attrS.NestedType != nil && attrS.NestedType.ContainsSensitive() {
+			return true
+		}
+	}
+	return false
+}
diff --git a/v1.5.7/internal/configs/configschema/implied_type_test.go b/v1.5.7/internal/configs/configschema/implied_type_test.go
new file mode 100644
index 0000000..a5745d1
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/implied_type_test.go
@@ -0,0 +1,607 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestBlockImpliedType(t *testing.T) {
+	tests := map[string]struct {
+		Schema *Block
+		Want   cty.Type
+	}{
+		"nil": {
+			nil,
+			cty.EmptyObject,
+		},
+		"empty": {
+			&Block{},
+			cty.EmptyObject,
+		},
+		"attributes": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"optional": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"required": {
+						Type:     cty.Number,
+						Required: true,
+					},
+					"computed": {
+						Type:     cty.List(cty.Bool),
+						Computed: true,
+					},
+					"optional_computed": {
+						Type:     cty.Map(cty.Bool),
+						Optional: true,
+						Computed: true,
+					},
+				},
+			},
+			cty.Object(map[string]cty.Type{
+				"optional":          cty.String,
+				"required":          cty.Number,
+				"computed":          cty.List(cty.Bool),
+				"optional_computed": cty.Map(cty.Bool),
+			}),
+		},
+		"blocks": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"single": &NestedBlock{
+						Nesting: NestingSingle,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"foo": {
+									Type:     cty.DynamicPseudoType,
+									Required: true,
+								},
+							},
+						},
+					},
+					"list": &NestedBlock{
+						Nesting: NestingList,
+					},
+					"set": &NestedBlock{
+						Nesting: NestingSet,
+					},
+					"map": &NestedBlock{
+						Nesting: NestingMap,
+					},
+				},
+			},
+			cty.Object(map[string]cty.Type{
+				"single": cty.Object(map[string]cty.Type{
+					"foo": cty.DynamicPseudoType,
+				}),
+				"list": cty.List(cty.EmptyObject),
+				"set":  cty.Set(cty.EmptyObject),
+				"map":  cty.Map(cty.EmptyObject),
+			}),
+		},
+		"deep block nesting": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"single": &NestedBlock{
+						Nesting: NestingSingle,
+						Block: Block{
+							BlockTypes: map[string]*NestedBlock{
+								"list": &NestedBlock{
+									Nesting: NestingList,
+									Block: Block{
+										BlockTypes: map[string]*NestedBlock{
+											"set": &NestedBlock{
+												Nesting: NestingSet,
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.Object(map[string]cty.Type{
+				"single": cty.Object(map[string]cty.Type{
+					"list": cty.List(cty.Object(map[string]cty.Type{
+						"set": cty.Set(cty.EmptyObject),
+					})),
+				}),
+			}),
+		},
+		"nested objects with optional attrs": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"map": {
+						Optional: true,
+						NestedType: &Object{
+							Nesting: NestingMap,
+							Attributes: map[string]*Attribute{
+								"optional":          {Type: cty.String, Optional: true},
+								"required":          {Type: cty.Number, Required: true},
+								"computed":          {Type: cty.List(cty.Bool), Computed: true},
+								"optional_computed": {Type: cty.Map(cty.Bool), Optional: true, Computed: true},
+							},
+						},
+					},
+				},
+			},
+			// The ImpliedType from the type-level block should not contain any
+			// optional attributes.
+			cty.Object(map[string]cty.Type{
+				"map": cty.Map(cty.Object(
+					map[string]cty.Type{
+						"optional":          cty.String,
+						"required":          cty.Number,
+						"computed":          cty.List(cty.Bool),
+						"optional_computed": cty.Map(cty.Bool),
+					},
+				)),
+			}),
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got := test.Schema.ImpliedType()
+			if !got.Equals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestBlockContainsSensitive(t *testing.T) {
+	tests := map[string]struct {
+		Schema *Block
+		Want   bool
+	}{
+		"object contains sensitive": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"sensitive": {Sensitive: true},
+				},
+			},
+			true,
+		},
+		"no sensitive attrs": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"insensitive": {},
+				},
+			},
+			false,
+		},
+		"nested object contains sensitive": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"nested": {
+						NestedType: &Object{
+							Nesting: NestingSingle,
+							Attributes: map[string]*Attribute{
+								"sensitive": {Sensitive: true},
+							},
+						},
+					},
+				},
+			},
+			true,
+		},
+		"nested obj, no sensitive attrs": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"nested": {
+						NestedType: &Object{
+							Nesting: NestingSingle,
+							Attributes: map[string]*Attribute{
+								"public": {},
+							},
+						},
+					},
+				},
+			},
+			false,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got := test.Schema.ContainsSensitive()
+			if got != test.Want {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+
+}
+
+func TestObjectImpliedType(t *testing.T) {
+	tests := map[string]struct {
+		Schema *Object
+		Want   cty.Type
+	}{
+		"nil": {
+			nil,
+			cty.EmptyObject,
+		},
+		"empty": {
+			&Object{},
+			cty.EmptyObject,
+		},
+		"attributes": {
+			&Object{
+				Nesting: NestingSingle,
+				Attributes: map[string]*Attribute{
+					"optional":          {Type: cty.String, Optional: true},
+					"required":          {Type: cty.Number, Required: true},
+					"computed":          {Type: cty.List(cty.Bool), Computed: true},
+					"optional_computed": {Type: cty.Map(cty.Bool), Optional: true, Computed: true},
+				},
+			},
+			cty.Object(
+				map[string]cty.Type{
+					"optional":          cty.String,
+					"required":          cty.Number,
+					"computed":          cty.List(cty.Bool),
+					"optional_computed": cty.Map(cty.Bool),
+				},
+			),
+		},
+		"nested attributes": {
+			&Object{
+				Nesting: NestingSingle,
+				Attributes: map[string]*Attribute{
+					"nested_type": {
+						NestedType: &Object{
+							Nesting: NestingSingle,
+							Attributes: map[string]*Attribute{
+								"optional":          {Type: cty.String, Optional: true},
+								"required":          {Type: cty.Number, Required: true},
+								"computed":          {Type: cty.List(cty.Bool), Computed: true},
+								"optional_computed": {Type: cty.Map(cty.Bool), Optional: true, Computed: true},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.Object(map[string]cty.Type{
+				"nested_type": cty.Object(map[string]cty.Type{
+					"optional":          cty.String,
+					"required":          cty.Number,
+					"computed":          cty.List(cty.Bool),
+					"optional_computed": cty.Map(cty.Bool),
+				}),
+			}),
+		},
+		"nested object-type attributes": {
+			&Object{
+				Nesting: NestingSingle,
+				Attributes: map[string]*Attribute{
+					"nested_type": {
+						NestedType: &Object{
+							Nesting: NestingSingle,
+							Attributes: map[string]*Attribute{
+								"optional":          {Type: cty.String, Optional: true},
+								"required":          {Type: cty.Number, Required: true},
+								"computed":          {Type: cty.List(cty.Bool), Computed: true},
+								"optional_computed": {Type: cty.Map(cty.Bool), Optional: true, Computed: true},
+								"object": {
+									Type: cty.ObjectWithOptionalAttrs(map[string]cty.Type{
+										"optional": cty.String,
+										"required": cty.Number,
+									}, []string{"optional"}),
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.Object(map[string]cty.Type{
+				"nested_type": cty.Object(map[string]cty.Type{
+					"optional":          cty.String,
+					"required":          cty.Number,
+					"computed":          cty.List(cty.Bool),
+					"optional_computed": cty.Map(cty.Bool),
+					"object":            cty.Object(map[string]cty.Type{"optional": cty.String, "required": cty.Number}),
+				}),
+			}),
+		},
+		"NestingList": {
+			&Object{
+				Nesting: NestingList,
+				Attributes: map[string]*Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+			cty.List(cty.Object(map[string]cty.Type{"foo": cty.String})),
+		},
+		"NestingMap": {
+			&Object{
+				Nesting: NestingMap,
+				Attributes: map[string]*Attribute{
+					"foo": {Type: cty.String},
+				},
+			},
+			cty.Map(cty.Object(map[string]cty.Type{"foo": cty.String})),
+		},
+		"NestingSet": {
+			&Object{
+				Nesting: NestingSet,
+				Attributes: map[string]*Attribute{
+					"foo": {Type: cty.String},
+				},
+			},
+			cty.Set(cty.Object(map[string]cty.Type{"foo": cty.String})),
+		},
+		"deeply nested NestingList": {
+			&Object{
+				Nesting: NestingList,
+				Attributes: map[string]*Attribute{
+					"foo": {
+						NestedType: &Object{
+							Nesting: NestingList,
+							Attributes: map[string]*Attribute{
+								"bar": {Type: cty.String},
+							},
+						},
+					},
+				},
+			},
+			cty.List(cty.Object(map[string]cty.Type{"foo": cty.List(cty.Object(map[string]cty.Type{"bar": cty.String}))})),
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got := test.Schema.ImpliedType()
+			if !got.Equals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestObjectContainsSensitive(t *testing.T) {
+	tests := map[string]struct {
+		Schema *Object
+		Want   bool
+	}{
+		"object contains sensitive": {
+			&Object{
+				Attributes: map[string]*Attribute{
+					"sensitive": {Sensitive: true},
+				},
+			},
+			true,
+		},
+		"no sensitive attrs": {
+			&Object{
+				Attributes: map[string]*Attribute{
+					"insensitive": {},
+				},
+			},
+			false,
+		},
+		"nested object contains sensitive": {
+			&Object{
+				Attributes: map[string]*Attribute{
+					"nested": {
+						NestedType: &Object{
+							Nesting: NestingSingle,
+							Attributes: map[string]*Attribute{
+								"sensitive": {Sensitive: true},
+							},
+						},
+					},
+				},
+			},
+			true,
+		},
+		"nested obj, no sensitive attrs": {
+			&Object{
+				Attributes: map[string]*Attribute{
+					"nested": {
+						NestedType: &Object{
+							Nesting: NestingSingle,
+							Attributes: map[string]*Attribute{
+								"public": {},
+							},
+						},
+					},
+				},
+			},
+			false,
+		},
+		"several nested objects, one contains sensitive": {
+			&Object{
+				Attributes: map[string]*Attribute{
+					"alpha": {
+						NestedType: &Object{
+							Nesting: NestingSingle,
+							Attributes: map[string]*Attribute{
+								"nonsensitive": {},
+							},
+						},
+					},
+					"beta": {
+						NestedType: &Object{
+							Nesting: NestingSingle,
+							Attributes: map[string]*Attribute{
+								"sensitive": {Sensitive: true},
+							},
+						},
+					},
+					"gamma": {
+						NestedType: &Object{
+							Nesting: NestingSingle,
+							Attributes: map[string]*Attribute{
+								"nonsensitive": {},
+							},
+						},
+					},
+				},
+			},
+			true,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got := test.Schema.ContainsSensitive()
+			if got != test.Want {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+
+}
+
+// Nested attribute should return optional object attributes for decoding.
+func TestObjectSpecType(t *testing.T) {
+	tests := map[string]struct {
+		Schema *Object
+		Want   cty.Type
+	}{
+		"attributes": {
+			&Object{
+				Nesting: NestingSingle,
+				Attributes: map[string]*Attribute{
+					"optional":          {Type: cty.String, Optional: true},
+					"required":          {Type: cty.Number, Required: true},
+					"computed":          {Type: cty.List(cty.Bool), Computed: true},
+					"optional_computed": {Type: cty.Map(cty.Bool), Optional: true, Computed: true},
+				},
+			},
+			cty.ObjectWithOptionalAttrs(
+				map[string]cty.Type{
+					"optional":          cty.String,
+					"required":          cty.Number,
+					"computed":          cty.List(cty.Bool),
+					"optional_computed": cty.Map(cty.Bool),
+				},
+				[]string{"optional", "computed", "optional_computed"},
+			),
+		},
+		"nested attributes": {
+			&Object{
+				Nesting: NestingSingle,
+				Attributes: map[string]*Attribute{
+					"nested_type": {
+						NestedType: &Object{
+							Nesting: NestingSingle,
+							Attributes: map[string]*Attribute{
+								"optional":          {Type: cty.String, Optional: true},
+								"required":          {Type: cty.Number, Required: true},
+								"computed":          {Type: cty.List(cty.Bool), Computed: true},
+								"optional_computed": {Type: cty.Map(cty.Bool), Optional: true, Computed: true},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectWithOptionalAttrs(map[string]cty.Type{
+				"nested_type": cty.ObjectWithOptionalAttrs(map[string]cty.Type{
+					"optional":          cty.String,
+					"required":          cty.Number,
+					"computed":          cty.List(cty.Bool),
+					"optional_computed": cty.Map(cty.Bool),
+				}, []string{"optional", "computed", "optional_computed"}),
+			}, []string{"nested_type"}),
+		},
+		"nested object-type attributes": {
+			&Object{
+				Nesting: NestingSingle,
+				Attributes: map[string]*Attribute{
+					"nested_type": {
+						NestedType: &Object{
+							Nesting: NestingSingle,
+							Attributes: map[string]*Attribute{
+								"optional":          {Type: cty.String, Optional: true},
+								"required":          {Type: cty.Number, Required: true},
+								"computed":          {Type: cty.List(cty.Bool), Computed: true},
+								"optional_computed": {Type: cty.Map(cty.Bool), Optional: true, Computed: true},
+								"object": {
+									Type: cty.ObjectWithOptionalAttrs(map[string]cty.Type{
+										"optional": cty.String,
+										"required": cty.Number,
+									}, []string{"optional"}),
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectWithOptionalAttrs(map[string]cty.Type{
+				"nested_type": cty.ObjectWithOptionalAttrs(map[string]cty.Type{
+					"optional":          cty.String,
+					"required":          cty.Number,
+					"computed":          cty.List(cty.Bool),
+					"optional_computed": cty.Map(cty.Bool),
+					"object":            cty.ObjectWithOptionalAttrs(map[string]cty.Type{"optional": cty.String, "required": cty.Number}, []string{"optional"}),
+				}, []string{"optional", "computed", "optional_computed"}),
+			}, []string{"nested_type"}),
+		},
+		"NestingList": {
+			&Object{
+				Nesting: NestingList,
+				Attributes: map[string]*Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+			cty.List(cty.ObjectWithOptionalAttrs(map[string]cty.Type{"foo": cty.String}, []string{"foo"})),
+		},
+		"NestingMap": {
+			&Object{
+				Nesting: NestingMap,
+				Attributes: map[string]*Attribute{
+					"foo": {Type: cty.String},
+				},
+			},
+			cty.Map(cty.Object(map[string]cty.Type{"foo": cty.String})),
+		},
+		"NestingSet": {
+			&Object{
+				Nesting: NestingSet,
+				Attributes: map[string]*Attribute{
+					"foo": {Type: cty.String},
+				},
+			},
+			cty.Set(cty.Object(map[string]cty.Type{"foo": cty.String})),
+		},
+		"deeply nested NestingList": {
+			&Object{
+				Nesting: NestingList,
+				Attributes: map[string]*Attribute{
+					"foo": {
+						NestedType: &Object{
+							Nesting: NestingList,
+							Attributes: map[string]*Attribute{
+								"bar": {Type: cty.String},
+							},
+						},
+					},
+				},
+			},
+			cty.List(cty.Object(map[string]cty.Type{"foo": cty.List(cty.Object(map[string]cty.Type{"bar": cty.String}))})),
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got := test.Schema.specType()
+			if !got.Equals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/configs/configschema/internal_validate.go b/v1.5.7/internal/configs/configschema/internal_validate.go
new file mode 100644
index 0000000..d2a4190
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/internal_validate.go
@@ -0,0 +1,162 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"fmt"
+	"regexp"
+
+	"github.com/zclconf/go-cty/cty"
+
+	multierror "github.com/hashicorp/go-multierror"
+)
+
+var validName = regexp.MustCompile(`^[a-z0-9_]+$`)
+
+// InternalValidate returns an error if the receiving block and its child schema
+// definitions have any inconsistencies with the documented rules for valid
+// schema.
+//
+// This can be used within unit tests to detect when a given schema is invalid,
+// and is run when terraform loads provider schemas during NewContext.
+func (b *Block) InternalValidate() error {
+	if b == nil {
+		return fmt.Errorf("top-level block schema is nil")
+	}
+	return b.internalValidate("")
+}
+
+func (b *Block) internalValidate(prefix string) error {
+	var multiErr *multierror.Error
+
+	for name, attrS := range b.Attributes {
+		if attrS == nil {
+			multiErr = multierror.Append(multiErr, fmt.Errorf("%s%s: attribute schema is nil", prefix, name))
+			continue
+		}
+		multiErr = multierror.Append(multiErr, attrS.internalValidate(name, prefix))
+	}
+
+	for name, blockS := range b.BlockTypes {
+		if blockS == nil {
+			multiErr = multierror.Append(multiErr, fmt.Errorf("%s%s: block schema is nil", prefix, name))
+			continue
+		}
+
+		if _, isAttr := b.Attributes[name]; isAttr {
+			multiErr = multierror.Append(multiErr, fmt.Errorf("%s%s: name defined as both attribute and child block type", prefix, name))
+		} else if !validName.MatchString(name) {
+			multiErr = multierror.Append(multiErr, fmt.Errorf("%s%s: name may contain only lowercase letters, digits and underscores", prefix, name))
+		}
+
+		if blockS.MinItems < 0 || blockS.MaxItems < 0 {
+			multiErr = multierror.Append(multiErr, fmt.Errorf("%s%s: MinItems and MaxItems must both be greater than zero", prefix, name))
+		}
+
+		switch blockS.Nesting {
+		case NestingSingle:
+			switch {
+			case blockS.MinItems != blockS.MaxItems:
+				multiErr = multierror.Append(multiErr, fmt.Errorf("%s%s: MinItems and MaxItems must match in NestingSingle mode", prefix, name))
+			case blockS.MinItems < 0 || blockS.MinItems > 1:
+				multiErr = multierror.Append(multiErr, fmt.Errorf("%s%s: MinItems and MaxItems must be set to either 0 or 1 in NestingSingle mode", prefix, name))
+			}
+		case NestingGroup:
+			if blockS.MinItems != 0 || blockS.MaxItems != 0 {
+				multiErr = multierror.Append(multiErr, fmt.Errorf("%s%s: MinItems and MaxItems cannot be used in NestingGroup mode", prefix, name))
+			}
+		case NestingList, NestingSet:
+			if blockS.MinItems > blockS.MaxItems && blockS.MaxItems != 0 {
+				multiErr = multierror.Append(multiErr, fmt.Errorf("%s%s: MinItems must be less than or equal to MaxItems in %s mode", prefix, name, blockS.Nesting))
+			}
+			if blockS.Nesting == NestingSet {
+				ety := blockS.Block.ImpliedType()
+				if ety.HasDynamicTypes() {
+					// This is not permitted because the HCL (cty) set implementation
+					// needs to know the exact type of set elements in order to
+					// properly hash them, and so can't support mixed types.
+					multiErr = multierror.Append(multiErr, fmt.Errorf("%s%s: NestingSet blocks may not contain attributes of cty.DynamicPseudoType", prefix, name))
+				}
+			}
+		case NestingMap:
+			if blockS.MinItems != 0 || blockS.MaxItems != 0 {
+				multiErr = multierror.Append(multiErr, fmt.Errorf("%s%s: MinItems and MaxItems must both be 0 in NestingMap mode", prefix, name))
+			}
+		default:
+			multiErr = multierror.Append(multiErr, fmt.Errorf("%s%s: invalid nesting mode %s", prefix, name, blockS.Nesting))
+		}
+
+		subPrefix := prefix + name + "."
+		multiErr = multierror.Append(multiErr, blockS.Block.internalValidate(subPrefix))
+	}
+
+	return multiErr.ErrorOrNil()
+}
+
+// InternalValidate returns an error if the receiving attribute and its child
+// schema definitions have any inconsistencies with the documented rules for
+// valid schema.
+func (a *Attribute) InternalValidate(name string) error {
+	if a == nil {
+		return fmt.Errorf("attribute schema is nil")
+	}
+	return a.internalValidate(name, "")
+}
+
+func (a *Attribute) internalValidate(name, prefix string) error {
+	var err *multierror.Error
+
+	/* FIXME: this validation breaks certain existing providers and cannot be enforced without coordination.
+	if !validName.MatchString(name) {
+		err = multierror.Append(err, fmt.Errorf("%s%s: name may contain only lowercase letters, digits and underscores", prefix, name))
+	}
+	*/
+	if !a.Optional && !a.Required && !a.Computed {
+		err = multierror.Append(err, fmt.Errorf("%s%s: must set Optional, Required or Computed", prefix, name))
+	}
+	if a.Optional && a.Required {
+		err = multierror.Append(err, fmt.Errorf("%s%s: cannot set both Optional and Required", prefix, name))
+	}
+	if a.Computed && a.Required {
+		err = multierror.Append(err, fmt.Errorf("%s%s: cannot set both Computed and Required", prefix, name))
+	}
+
+	if a.Type == cty.NilType && a.NestedType == nil {
+		err = multierror.Append(err, fmt.Errorf("%s%s: either Type or NestedType must be defined", prefix, name))
+	}
+
+	if a.Type != cty.NilType {
+		if a.NestedType != nil {
+			err = multierror.Append(fmt.Errorf("%s: Type and NestedType cannot both be set", name))
+		}
+	}
+
+	if a.NestedType != nil {
+		switch a.NestedType.Nesting {
+		case NestingSingle, NestingMap:
+			// no validations to perform
+		case NestingList, NestingSet:
+			if a.NestedType.Nesting == NestingSet {
+				ety := a.ImpliedType()
+				if ety.HasDynamicTypes() {
+					// This is not permitted because the HCL (cty) set implementation
+					// needs to know the exact type of set elements in order to
+					// properly hash them, and so can't support mixed types.
+					err = multierror.Append(err, fmt.Errorf("%s%s: NestingSet blocks may not contain attributes of cty.DynamicPseudoType", prefix, name))
+				}
+			}
+		default:
+			err = multierror.Append(err, fmt.Errorf("%s%s: invalid nesting mode %s", prefix, name, a.NestedType.Nesting))
+		}
+		for name, attrS := range a.NestedType.Attributes {
+			if attrS == nil {
+				err = multierror.Append(err, fmt.Errorf("%s%s: attribute schema is nil", prefix, name))
+				continue
+			}
+			err = multierror.Append(err, attrS.internalValidate(name, prefix))
+		}
+	}
+
+	return err.ErrorOrNil()
+}
diff --git a/v1.5.7/internal/configs/configschema/internal_validate_test.go b/v1.5.7/internal/configs/configschema/internal_validate_test.go
new file mode 100644
index 0000000..adb8284
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/internal_validate_test.go
@@ -0,0 +1,306 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+
+	multierror "github.com/hashicorp/go-multierror"
+)
+
+func TestBlockInternalValidate(t *testing.T) {
+	tests := map[string]struct {
+		Block *Block
+		Errs  []string
+	}{
+		"empty": {
+			&Block{},
+			[]string{},
+		},
+		"valid": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						Type:     cty.String,
+						Required: true,
+					},
+					"bar": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"baz": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"baz_maybe": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+				},
+				BlockTypes: map[string]*NestedBlock{
+					"single": {
+						Nesting: NestingSingle,
+						Block:   Block{},
+					},
+					"single_required": {
+						Nesting:  NestingSingle,
+						Block:    Block{},
+						MinItems: 1,
+						MaxItems: 1,
+					},
+					"list": {
+						Nesting: NestingList,
+						Block:   Block{},
+					},
+					"list_required": {
+						Nesting:  NestingList,
+						Block:    Block{},
+						MinItems: 1,
+					},
+					"set": {
+						Nesting: NestingSet,
+						Block:   Block{},
+					},
+					"set_required": {
+						Nesting:  NestingSet,
+						Block:    Block{},
+						MinItems: 1,
+					},
+					"map": {
+						Nesting: NestingMap,
+						Block:   Block{},
+					},
+				},
+			},
+			[]string{},
+		},
+		"attribute with no flags set": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						Type: cty.String,
+					},
+				},
+			},
+			[]string{"foo: must set Optional, Required or Computed"},
+		},
+		"attribute required and optional": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						Type:     cty.String,
+						Required: true,
+						Optional: true,
+					},
+				},
+			},
+			[]string{"foo: cannot set both Optional and Required"},
+		},
+		"attribute required and computed": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						Type:     cty.String,
+						Required: true,
+						Computed: true,
+					},
+				},
+			},
+			[]string{"foo: cannot set both Computed and Required"},
+		},
+		"attribute optional and computed": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+				},
+			},
+			[]string{},
+		},
+		"attribute with missing type": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						Optional: true,
+					},
+				},
+			},
+			[]string{"foo: either Type or NestedType must be defined"},
+		},
+		/* FIXME: This caused errors when applied to existing providers (oci)
+		and cannot be enforced without coordination.
+
+		"attribute with invalid name": {&Block{Attributes:
+		    map[string]*Attribute{"fooBar": {Type:     cty.String, Optional:
+		    true,
+		            },
+		        },
+		    },
+		    []string{"fooBar: name may contain only lowercase letters, digits and underscores"},
+		},
+		*/
+		"attribute with invalid NestedType attribute": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						NestedType: &Object{
+							Nesting: NestingSingle,
+							Attributes: map[string]*Attribute{
+								"foo": {
+									Type:     cty.String,
+									Required: true,
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			[]string{"foo: cannot set both Optional and Required"},
+		},
+		"block type with invalid name": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"fooBar": {
+						Nesting: NestingSingle,
+					},
+				},
+			},
+			[]string{"fooBar: name may contain only lowercase letters, digits and underscores"},
+		},
+		"colliding names": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+				BlockTypes: map[string]*NestedBlock{
+					"foo": {
+						Nesting: NestingSingle,
+					},
+				},
+			},
+			[]string{"foo: name defined as both attribute and child block type"},
+		},
+		"nested block with badness": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"bad": {
+						Nesting: NestingSingle,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"nested_bad": {
+									Type:     cty.String,
+									Required: true,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			[]string{"bad.nested_bad: cannot set both Optional and Required"},
+		},
+		"nested list block with dynamically-typed attribute": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"bad": {
+						Nesting: NestingList,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"nested_bad": {
+									Type:     cty.DynamicPseudoType,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			[]string{},
+		},
+		"nested set block with dynamically-typed attribute": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"bad": {
+						Nesting: NestingSet,
+						Block: Block{
+							Attributes: map[string]*Attribute{
+								"nested_bad": {
+									Type:     cty.DynamicPseudoType,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			[]string{"bad: NestingSet blocks may not contain attributes of cty.DynamicPseudoType"},
+		},
+		"nil": {
+			nil,
+			[]string{"top-level block schema is nil"},
+		},
+		"nil attr": {
+			&Block{
+				Attributes: map[string]*Attribute{
+					"bad": nil,
+				},
+			},
+			[]string{"bad: attribute schema is nil"},
+		},
+		"nil block type": {
+			&Block{
+				BlockTypes: map[string]*NestedBlock{
+					"bad": nil,
+				},
+			},
+			[]string{"bad: block schema is nil"},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			errs := multierrorErrors(test.Block.InternalValidate())
+			if got, want := len(errs), len(test.Errs); got != want {
+				t.Errorf("wrong number of errors %d; want %d", got, want)
+				for _, err := range errs {
+					t.Logf("- %s", err.Error())
+				}
+			} else {
+				if len(errs) > 0 {
+					for i := range errs {
+						if errs[i].Error() != test.Errs[i] {
+							t.Errorf("wrong error: got %s, want %s", errs[i].Error(), test.Errs[i])
+						}
+					}
+				}
+			}
+		})
+	}
+}
+
+func multierrorErrors(err error) []error {
+	// A function like this should really be part of the multierror package...
+
+	if err == nil {
+		return nil
+	}
+
+	switch terr := err.(type) {
+	case *multierror.Error:
+		return terr.Errors
+	default:
+		return []error{err}
+	}
+}
diff --git a/v1.5.7/internal/configs/configschema/marks.go b/v1.5.7/internal/configs/configschema/marks.go
new file mode 100644
index 0000000..f813b17
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/marks.go
@@ -0,0 +1,156 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// copyAndExtendPath returns a copy of a cty.Path with some additional
+// `cty.PathStep`s appended to its end, to simplify creating new child paths.
+func copyAndExtendPath(path cty.Path, nextSteps ...cty.PathStep) cty.Path {
+	newPath := make(cty.Path, len(path), len(path)+len(nextSteps))
+	copy(newPath, path)
+	newPath = append(newPath, nextSteps...)
+	return newPath
+}
+
+// ValueMarks returns a set of path value marks for a given value and path,
+// based on the sensitive flag for each attribute within the schema. Nested
+// blocks are descended (if present in the given value).
+func (b *Block) ValueMarks(val cty.Value, path cty.Path) []cty.PathValueMarks {
+	var pvm []cty.PathValueMarks
+
+	// We can mark attributes as sensitive even if the value is null
+	for name, attrS := range b.Attributes {
+		if attrS.Sensitive {
+			// Create a copy of the path, with this step added, to add to our PathValueMarks slice
+			attrPath := copyAndExtendPath(path, cty.GetAttrStep{Name: name})
+			pvm = append(pvm, cty.PathValueMarks{
+				Path:  attrPath,
+				Marks: cty.NewValueMarks(marks.Sensitive),
+			})
+		}
+	}
+
+	// If the value is null, no other marks are possible
+	if val.IsNull() {
+		return pvm
+	}
+
+	// Extract marks for nested attribute type values
+	for name, attrS := range b.Attributes {
+		// If the attribute has no nested type, or the nested type doesn't
+		// contain any sensitive attributes, skip inspecting it
+		if attrS.NestedType == nil || !attrS.NestedType.ContainsSensitive() {
+			continue
+		}
+
+		// Create a copy of the path, with this step added, to add to our PathValueMarks slice
+		attrPath := copyAndExtendPath(path, cty.GetAttrStep{Name: name})
+
+		pvm = append(pvm, attrS.NestedType.ValueMarks(val.GetAttr(name), attrPath)...)
+	}
+
+	// Extract marks for nested blocks
+	for name, blockS := range b.BlockTypes {
+		// If our block doesn't contain any sensitive attributes, skip inspecting it
+		if !blockS.Block.ContainsSensitive() {
+			continue
+		}
+
+		blockV := val.GetAttr(name)
+		if blockV.IsNull() || !blockV.IsKnown() {
+			continue
+		}
+
+		// Create a copy of the path, with this step added, to add to our PathValueMarks slice
+		blockPath := copyAndExtendPath(path, cty.GetAttrStep{Name: name})
+
+		switch blockS.Nesting {
+		case NestingSingle, NestingGroup:
+			pvm = append(pvm, blockS.Block.ValueMarks(blockV, blockPath)...)
+		case NestingList, NestingMap, NestingSet:
+			for it := blockV.ElementIterator(); it.Next(); {
+				idx, blockEV := it.Element()
+				// Create a copy of the path, with this block instance's index
+				// step added, to add to our PathValueMarks slice
+				blockInstancePath := copyAndExtendPath(blockPath, cty.IndexStep{Key: idx})
+				morePaths := blockS.Block.ValueMarks(blockEV, blockInstancePath)
+				pvm = append(pvm, morePaths...)
+			}
+		default:
+			panic(fmt.Sprintf("unsupported nesting mode %s", blockS.Nesting))
+		}
+	}
+	return pvm
+}
+
+// ValueMarks returns a set of path value marks for a given value and path,
+// based on the sensitive flag for each attribute within the nested attribute.
+// Attributes with nested types are descended (if present in the given value).
+func (o *Object) ValueMarks(val cty.Value, path cty.Path) []cty.PathValueMarks {
+	var pvm []cty.PathValueMarks
+
+	if val.IsNull() || !val.IsKnown() {
+		return pvm
+	}
+
+	for name, attrS := range o.Attributes {
+		// Skip attributes which can never produce sensitive path value marks
+		if !attrS.Sensitive && (attrS.NestedType == nil || !attrS.NestedType.ContainsSensitive()) {
+			continue
+		}
+
+		switch o.Nesting {
+		case NestingSingle, NestingGroup:
+			// Create a path to this attribute
+			attrPath := copyAndExtendPath(path, cty.GetAttrStep{Name: name})
+
+			if attrS.Sensitive {
+				// If the entire attribute is sensitive, mark it so
+				pvm = append(pvm, cty.PathValueMarks{
+					Path:  attrPath,
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				})
+			} else {
+				// The attribute has a nested type which contains sensitive
+				// attributes, so recurse
+				pvm = append(pvm, attrS.NestedType.ValueMarks(val.GetAttr(name), attrPath)...)
+			}
+		case NestingList, NestingMap, NestingSet:
+			// For nested attribute types which have a non-single nesting mode,
+			// we add path value marks for each element of the collection
+			for it := val.ElementIterator(); it.Next(); {
+				idx, attrEV := it.Element()
+				attrV := attrEV.GetAttr(name)
+
+				// Create a path to this element of the attribute's collection. Note
+				// that the path is extended in opposite order to the iteration order
+				// of the loops: index into the collection, then the contained
+				// attribute name. This is because we have one type
+				// representing multiple collection elements.
+				attrPath := copyAndExtendPath(path, cty.IndexStep{Key: idx}, cty.GetAttrStep{Name: name})
+
+				if attrS.Sensitive {
+					// If the entire attribute is sensitive, mark it so
+					pvm = append(pvm, cty.PathValueMarks{
+						Path:  attrPath,
+						Marks: cty.NewValueMarks(marks.Sensitive),
+					})
+				} else {
+					// The attribute has a nested type which contains sensitive
+					// attributes, so recurse
+					pvm = append(pvm, attrS.NestedType.ValueMarks(attrV, attrPath)...)
+				}
+			}
+		default:
+			panic(fmt.Sprintf("unsupported nesting mode %s", attrS.NestedType.Nesting))
+		}
+	}
+	return pvm
+}
diff --git a/v1.5.7/internal/configs/configschema/marks_test.go b/v1.5.7/internal/configs/configschema/marks_test.go
new file mode 100644
index 0000000..c74a298
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/marks_test.go
@@ -0,0 +1,185 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestBlockValueMarks(t *testing.T) {
+	schema := &Block{
+		Attributes: map[string]*Attribute{
+			"unsensitive": {
+				Type:     cty.String,
+				Optional: true,
+			},
+			"sensitive": {
+				Type:      cty.String,
+				Sensitive: true,
+			},
+			"nested": {
+				NestedType: &Object{
+					Attributes: map[string]*Attribute{
+						"boop": {
+							Type: cty.String,
+						},
+						"honk": {
+							Type:      cty.String,
+							Sensitive: true,
+						},
+					},
+					Nesting: NestingList,
+				},
+			},
+		},
+
+		BlockTypes: map[string]*NestedBlock{
+			"list": {
+				Nesting: NestingList,
+				Block: Block{
+					Attributes: map[string]*Attribute{
+						"unsensitive": {
+							Type:     cty.String,
+							Optional: true,
+						},
+						"sensitive": {
+							Type:      cty.String,
+							Sensitive: true,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testCases := map[string]struct {
+		given  cty.Value
+		expect cty.Value
+	}{
+		"unknown object": {
+			cty.UnknownVal(schema.ImpliedType()),
+			cty.UnknownVal(schema.ImpliedType()),
+		},
+		"null object": {
+			cty.NullVal(schema.ImpliedType()),
+			cty.NullVal(schema.ImpliedType()),
+		},
+		"object with unknown attributes and blocks": {
+			cty.ObjectVal(map[string]cty.Value{
+				"sensitive":   cty.UnknownVal(cty.String),
+				"unsensitive": cty.UnknownVal(cty.String),
+				"nested": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"boop": cty.String,
+					"honk": cty.String,
+				}))),
+				"list": cty.UnknownVal(schema.BlockTypes["list"].ImpliedType()),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"sensitive":   cty.UnknownVal(cty.String).Mark(marks.Sensitive),
+				"unsensitive": cty.UnknownVal(cty.String),
+				"nested": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"boop": cty.String,
+					"honk": cty.String,
+				}))),
+				"list": cty.UnknownVal(schema.BlockTypes["list"].ImpliedType()),
+			}),
+		},
+		"object with block value": {
+			cty.ObjectVal(map[string]cty.Value{
+				"sensitive":   cty.NullVal(cty.String),
+				"unsensitive": cty.UnknownVal(cty.String),
+				"nested": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"boop": cty.String,
+					"honk": cty.String,
+				}))),
+				"list": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"sensitive":   cty.UnknownVal(cty.String),
+						"unsensitive": cty.UnknownVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"sensitive":   cty.NullVal(cty.String),
+						"unsensitive": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"sensitive":   cty.NullVal(cty.String).Mark(marks.Sensitive),
+				"unsensitive": cty.UnknownVal(cty.String),
+				"nested": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"boop": cty.String,
+					"honk": cty.String,
+				}))),
+				"list": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"sensitive":   cty.UnknownVal(cty.String).Mark(marks.Sensitive),
+						"unsensitive": cty.UnknownVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"sensitive":   cty.NullVal(cty.String).Mark(marks.Sensitive),
+						"unsensitive": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+		},
+		"object with known values and nested attribute": {
+			cty.ObjectVal(map[string]cty.Value{
+				"sensitive":   cty.StringVal("foo"),
+				"unsensitive": cty.StringVal("bar"),
+				"nested": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"boop": cty.StringVal("foo"),
+						"honk": cty.StringVal("bar"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"boop": cty.NullVal(cty.String),
+						"honk": cty.NullVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"boop": cty.UnknownVal(cty.String),
+						"honk": cty.UnknownVal(cty.String),
+					}),
+				}),
+				"list": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"sensitive":   cty.String,
+					"unsensitive": cty.String,
+				}))),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"sensitive":   cty.StringVal("foo").Mark(marks.Sensitive),
+				"unsensitive": cty.StringVal("bar"),
+				"nested": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"boop": cty.StringVal("foo"),
+						"honk": cty.StringVal("bar").Mark(marks.Sensitive),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"boop": cty.NullVal(cty.String),
+						"honk": cty.NullVal(cty.String).Mark(marks.Sensitive),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"boop": cty.UnknownVal(cty.String),
+						"honk": cty.UnknownVal(cty.String).Mark(marks.Sensitive),
+					}),
+				}),
+				"list": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"sensitive":   cty.String,
+					"unsensitive": cty.String,
+				}))),
+			}),
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got := tc.given.MarkWithPaths(schema.ValueMarks(tc.given, nil))
+			if !got.RawEquals(tc.expect) {
+				t.Fatalf("\nexpected: %#v\ngot:      %#v\n", tc.expect, got)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/configs/configschema/nestingmode_string.go b/v1.5.7/internal/configs/configschema/nestingmode_string.go
new file mode 100644
index 0000000..febe743
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/nestingmode_string.go
@@ -0,0 +1,28 @@
+// Code generated by "stringer -type=NestingMode"; DO NOT EDIT.
+
+package configschema
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[nestingModeInvalid-0]
+	_ = x[NestingSingle-1]
+	_ = x[NestingGroup-2]
+	_ = x[NestingList-3]
+	_ = x[NestingSet-4]
+	_ = x[NestingMap-5]
+}
+
+const _NestingMode_name = "nestingModeInvalidNestingSingleNestingGroupNestingListNestingSetNestingMap"
+
+var _NestingMode_index = [...]uint8{0, 18, 31, 43, 54, 64, 74}
+
+func (i NestingMode) String() string {
+	if i < 0 || i >= NestingMode(len(_NestingMode_index)-1) {
+		return "NestingMode(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _NestingMode_name[_NestingMode_index[i]:_NestingMode_index[i+1]]
+}
diff --git a/v1.5.7/internal/configs/configschema/none_required.go b/v1.5.7/internal/configs/configschema/none_required.go
new file mode 100644
index 0000000..4f48b76
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/none_required.go
@@ -0,0 +1,41 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+// NoneRequired returns a deep copy of the receiver with any required
+// attributes translated to optional.
+func (b *Block) NoneRequired() *Block {
+	ret := &Block{}
+
+	if b.Attributes != nil {
+		ret.Attributes = make(map[string]*Attribute, len(b.Attributes))
+	}
+	for name, attrS := range b.Attributes {
+		ret.Attributes[name] = attrS.forceOptional()
+	}
+
+	if b.BlockTypes != nil {
+		ret.BlockTypes = make(map[string]*NestedBlock, len(b.BlockTypes))
+	}
+	for name, blockS := range b.BlockTypes {
+		ret.BlockTypes[name] = blockS.noneRequired()
+	}
+
+	return ret
+}
+
+func (b *NestedBlock) noneRequired() *NestedBlock {
+	ret := *b
+	ret.Block = *(ret.Block.NoneRequired())
+	ret.MinItems = 0
+	ret.MaxItems = 0
+	return &ret
+}
+
+func (a *Attribute) forceOptional() *Attribute {
+	ret := *a
+	ret.Optional = true
+	ret.Required = false
+	return &ret
+}
diff --git a/v1.5.7/internal/configs/configschema/path.go b/v1.5.7/internal/configs/configschema/path.go
new file mode 100644
index 0000000..69b5aca
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/path.go
@@ -0,0 +1,58 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"github.com/zclconf/go-cty/cty"
+)
+
+// AttributeByPath looks up the Attribute schema which corresponds to the given
+// cty.Path. A nil value is returned if the given path does not correspond to a
+// specific attribute.
+func (b *Block) AttributeByPath(path cty.Path) *Attribute {
+	block := b
+	for i, step := range path {
+		switch step := step.(type) {
+		case cty.GetAttrStep:
+			if attr := block.Attributes[step.Name]; attr != nil {
+				// If the Attribute is defined with a NestedType and there's
+				// more to the path, descend into the NestedType
+				if attr.NestedType != nil && i < len(path)-1 {
+					return attr.NestedType.AttributeByPath(path[i+1:])
+				} else if i < len(path)-1 { // There's more to the path, but not more to this Attribute.
+					return nil
+				}
+				return attr
+			}
+
+			if nestedBlock := block.BlockTypes[step.Name]; nestedBlock != nil {
+				block = &nestedBlock.Block
+				continue
+			}
+
+			return nil
+		}
+	}
+	return nil
+}
+
+// AttributeByPath recurses through a NestedType to look up the Attribute scheme
+// which corresponds to the given cty.Path. A nil value is returned if the given
+// path does not correspond to a specific attribute.
+func (o *Object) AttributeByPath(path cty.Path) *Attribute {
+	for i, step := range path {
+		switch step := step.(type) {
+		case cty.GetAttrStep:
+			if attr := o.Attributes[step.Name]; attr != nil {
+				if attr.NestedType != nil && i < len(path)-1 {
+					return attr.NestedType.AttributeByPath(path[i+1:])
+				} else if i < len(path)-1 { // There's more to the path, but not more to this Attribute.
+					return nil
+				}
+				return attr
+			}
+		}
+	}
+	return nil
+}
diff --git a/v1.5.7/internal/configs/configschema/path_test.go b/v1.5.7/internal/configs/configschema/path_test.go
new file mode 100644
index 0000000..43c0d2d
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/path_test.go
@@ -0,0 +1,232 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestAttributeByPath(t *testing.T) {
+	schema := &Block{
+		Attributes: map[string]*Attribute{
+			"a1": {Description: "a1"},
+			"a2": {Description: "a2"},
+			"a3": {
+				Description: "a3",
+				NestedType: &Object{
+					Nesting: NestingList,
+					Attributes: map[string]*Attribute{
+						"nt1": {Description: "nt1"},
+						"nt2": {
+							Description: "nt2",
+							NestedType: &Object{
+								Nesting: NestingSingle,
+								Attributes: map[string]*Attribute{
+									"deeply_nested": {Description: "deeply_nested"},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		BlockTypes: map[string]*NestedBlock{
+			"b1": {
+				Nesting: NestingList,
+				Block: Block{
+					Attributes: map[string]*Attribute{
+						"a3": {Description: "a3"},
+						"a4": {Description: "a4"},
+					},
+					BlockTypes: map[string]*NestedBlock{
+						"b2": {
+							Nesting: NestingMap,
+							Block: Block{
+								Attributes: map[string]*Attribute{
+									"a5": {Description: "a5"},
+									"a6": {Description: "a6"},
+								},
+							},
+						},
+					},
+				},
+			},
+			"b3": {
+				Nesting: NestingMap,
+				Block: Block{
+					Attributes: map[string]*Attribute{
+						"a7": {Description: "a7"},
+						"a8": {Description: "a8"},
+					},
+					BlockTypes: map[string]*NestedBlock{
+						"b4": {
+							Nesting: NestingSet,
+							Block: Block{
+								Attributes: map[string]*Attribute{
+									"a9":  {Description: "a9"},
+									"a10": {Description: "a10"},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for _, tc := range []struct {
+		path            cty.Path
+		attrDescription string
+		exists          bool
+	}{
+		{
+			cty.GetAttrPath("a2"),
+			"a2",
+			true,
+		},
+		{
+			cty.GetAttrPath("a3").IndexInt(1).GetAttr("nt2"),
+			"nt2",
+			true,
+		},
+		{
+			cty.GetAttrPath("a3").IndexInt(1).GetAttr("b2").IndexString("foo").GetAttr("no"),
+			"missing",
+			false,
+		},
+		{
+			cty.GetAttrPath("b1"),
+			"block",
+			false,
+		},
+		{
+			cty.GetAttrPath("b1").IndexInt(1).GetAttr("a3"),
+			"a3",
+			true,
+		},
+		{
+			cty.GetAttrPath("b1").IndexInt(1).GetAttr("b2").IndexString("foo").GetAttr("a7"),
+			"missing",
+			false,
+		},
+		{
+			cty.GetAttrPath("b1").IndexInt(1).GetAttr("b2").IndexString("foo").GetAttr("a6"),
+			"a6",
+			true,
+		},
+		{
+			cty.GetAttrPath("b3").IndexString("foo").GetAttr("b2").IndexString("foo").GetAttr("a7"),
+			"missing_block",
+			false,
+		},
+		{
+			cty.GetAttrPath("b3").IndexString("foo").GetAttr("a7"),
+			"a7",
+			true,
+		},
+		{
+			// Index steps don't apply to the schema, so the set Index value doesn't matter.
+			cty.GetAttrPath("b3").IndexString("foo").GetAttr("b4").Index(cty.EmptyObjectVal).GetAttr("a9"),
+			"a9",
+			true,
+		},
+	} {
+		t.Run(tc.attrDescription, func(t *testing.T) {
+			attr := schema.AttributeByPath(tc.path)
+			if !tc.exists && attr == nil {
+				return
+			}
+
+			if attr == nil {
+				t.Fatalf("missing attribute from path %#v\n", tc.path)
+			}
+
+			if attr.Description != tc.attrDescription {
+				t.Fatalf("expected Attribute for %q, got %#v\n", tc.attrDescription, attr)
+			}
+		})
+	}
+}
+
+func TestObject_AttributeByPath(t *testing.T) {
+	obj := &Object{
+		Nesting: NestingList,
+		Attributes: map[string]*Attribute{
+			"a1": {Description: "a1"},
+			"a2": {
+				Description: "a2",
+				NestedType: &Object{
+					Nesting: NestingSingle,
+					Attributes: map[string]*Attribute{
+						"n1": {Description: "n1"},
+						"n2": {
+							Description: "n2",
+							NestedType: &Object{
+								Attributes: map[string]*Attribute{
+									"dn1": {Description: "dn1"},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	tests := []struct {
+		path            cty.Path
+		attrDescription string
+		exists          bool
+	}{
+		{
+			cty.GetAttrPath("a2"),
+			"a2",
+			true,
+		},
+		{
+			cty.GetAttrPath("a3"),
+			"missing",
+			false,
+		},
+		{
+			cty.GetAttrPath("a2").IndexString("foo").GetAttr("n1"),
+			"n1",
+			true,
+		},
+		{
+			cty.GetAttrPath("a2").IndexString("foo").GetAttr("n2").IndexInt(11).GetAttr("dn1"),
+			"dn1",
+			true,
+		},
+		{
+			cty.GetAttrPath("a2").IndexString("foo").GetAttr("n2").IndexInt(11).GetAttr("dn1").IndexString("hello").GetAttr("nope"),
+			"missing_nested",
+			false,
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.attrDescription, func(t *testing.T) {
+			attr := obj.AttributeByPath(tc.path)
+			if !tc.exists && attr == nil {
+				return
+			}
+
+			if !tc.exists && attr != nil {
+				t.Fatalf("found Attribute, expected nil from path %#v\n", tc.path)
+			}
+
+			if attr == nil {
+				t.Fatalf("missing attribute from path %#v\n", tc.path)
+			}
+
+			if attr.Description != tc.attrDescription {
+				t.Fatalf("expected Attribute for %q, got %#v\n", tc.attrDescription, attr)
+			}
+		})
+	}
+
+}
diff --git a/v1.5.7/internal/configs/configschema/schema.go b/v1.5.7/internal/configs/configschema/schema.go
new file mode 100644
index 0000000..fc6af58
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/schema.go
@@ -0,0 +1,167 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"github.com/zclconf/go-cty/cty"
+)
+
+type StringKind int
+
+const (
+	StringPlain StringKind = iota
+	StringMarkdown
+)
+
+// Block represents a configuration block.
+//
+// "Block" here is a logical grouping construct, though it happens to map
+// directly onto the physical block syntax of Terraform's native configuration
+// syntax. It may be a more a matter of convention in other syntaxes, such as
+// JSON.
+//
+// When converted to a value, a Block always becomes an instance of an object
+// type derived from its defined attributes and nested blocks
+type Block struct {
+	// Attributes describes any attributes that may appear directly inside
+	// the block.
+	Attributes map[string]*Attribute
+
+	// BlockTypes describes any nested block types that may appear directly
+	// inside the block.
+	BlockTypes map[string]*NestedBlock
+
+	Description     string
+	DescriptionKind StringKind
+
+	Deprecated bool
+}
+
+// Attribute represents a configuration attribute, within a block.
+type Attribute struct {
+	// Type is a type specification that the attribute's value must conform to.
+	// It conflicts with NestedType.
+	Type cty.Type
+
+	// NestedType indicates that the attribute is a NestedBlock-style object.
+	// This field conflicts with Type.
+	NestedType *Object
+
+	// Description is an English-language description of the purpose and
+	// usage of the attribute. A description should be concise and use only
+	// one or two sentences, leaving full definition to longer-form
+	// documentation defined elsewhere.
+	Description     string
+	DescriptionKind StringKind
+
+	// Required, if set to true, specifies that an omitted or null value is
+	// not permitted.
+	Required bool
+
+	// Optional, if set to true, specifies that an omitted or null value is
+	// permitted. This field conflicts with Required.
+	Optional bool
+
+	// Computed, if set to true, specifies that the value comes from the
+	// provider rather than from configuration. If combined with Optional,
+	// then the config may optionally provide an overridden value.
+	Computed bool
+
+	// Sensitive, if set to true, indicates that an attribute may contain
+	// sensitive information.
+	//
+	// At present nothing is done with this information, but callers are
+	// encouraged to set it where appropriate so that it may be used in the
+	// future to help Terraform mask sensitive information. (Terraform
+	// currently achieves this in a limited sense via other mechanisms.)
+	Sensitive bool
+
+	Deprecated bool
+}
+
+// Object represents the embedding of a structural object inside an Attribute.
+type Object struct {
+	// Attributes describes the nested attributes which may appear inside the
+	// Object.
+	Attributes map[string]*Attribute
+
+	// Nesting provides the nesting mode for this Object, which determines how
+	// many instances of the Object are allowed, how many labels it expects, and
+	// how the resulting data will be converted into a data structure.
+	Nesting NestingMode
+}
+
+// NestedBlock represents the embedding of one block within another.
+type NestedBlock struct {
+	// Block is the description of the block that's nested.
+	Block
+
+	// Nesting provides the nesting mode for the child block, which determines
+	// how many instances of the block are allowed, how many labels it expects,
+	// and how the resulting data will be converted into a data structure.
+	Nesting NestingMode
+
+	// MinItems and MaxItems set, for the NestingList and NestingSet nesting
+	// modes, lower and upper limits on the number of child blocks allowed
+	// of the given type. If both are left at zero, no limit is applied.
+	//
+	// As a special case, both values can be set to 1 for NestingSingle in
+	// order to indicate that a particular single block is required.
+	//
+	// These fields are ignored for other nesting modes and must both be left
+	// at zero.
+	MinItems, MaxItems int
+}
+
+// NestingMode is an enumeration of modes for nesting blocks inside other
+// blocks.
+type NestingMode int
+
+// Object represents the embedding of a NestedBl
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=NestingMode
+
+const (
+	nestingModeInvalid NestingMode = iota
+
+	// NestingSingle indicates that only a single instance of a given
+	// block type is permitted, with no labels, and its content should be
+	// provided directly as an object value.
+	NestingSingle
+
+	// NestingGroup is similar to NestingSingle in that it calls for only a
+	// single instance of a given block type with no labels, but it additonally
+	// guarantees that its result will never be null, even if the block is
+	// absent, and instead the nested attributes and blocks will be treated
+	// as absent in that case. (Any required attributes or blocks within the
+	// nested block are not enforced unless the block is explicitly present
+	// in the configuration, so they are all effectively optional when the
+	// block is not present.)
+	//
+	// This is useful for the situation where a remote API has a feature that
+	// is always enabled but has a group of settings related to that feature
+	// that themselves have default values. By using NestingGroup instead of
+	// NestingSingle in that case, generated plans will show the block as
+	// present even when not present in configuration, thus allowing any
+	// default values within to be displayed to the user.
+	NestingGroup
+
+	// NestingList indicates that multiple blocks of the given type are
+	// permitted, with no labels, and that their corresponding objects should
+	// be provided in a list.
+	NestingList
+
+	// NestingSet indicates that multiple blocks of the given type are
+	// permitted, with no labels, and that their corresponding objects should
+	// be provided in a set.
+	NestingSet
+
+	// NestingMap indicates that multiple blocks of the given type are
+	// permitted, each with a single label, and that their corresponding
+	// objects should be provided in a map whose keys are the labels.
+	//
+	// It's an error, therefore, to use the same label value on multiple
+	// blocks.
+	NestingMap
+)
diff --git a/v1.5.7/internal/configs/configschema/validate_traversal.go b/v1.5.7/internal/configs/configschema/validate_traversal.go
new file mode 100644
index 0000000..abce9c2
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/validate_traversal.go
@@ -0,0 +1,196 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"fmt"
+	"sort"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/didyoumean"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// StaticValidateTraversal checks whether the given traversal (which must be
+// relative) refers to a construct in the receiving schema, returning error
+// diagnostics if any problems are found.
+//
+// This method is "optimistic" in that it will not return errors for possible
+// problems that cannot be detected statically. It is possible that a
+// traversal which passed static validation will still fail when evaluated.
+func (b *Block) StaticValidateTraversal(traversal hcl.Traversal) tfdiags.Diagnostics {
+	if !traversal.IsRelative() {
+		panic("StaticValidateTraversal on absolute traversal")
+	}
+	if len(traversal) == 0 {
+		return nil
+	}
+
+	var diags tfdiags.Diagnostics
+
+	next := traversal[0]
+	after := traversal[1:]
+
+	var name string
+	switch step := next.(type) {
+	case hcl.TraverseAttr:
+		name = step.Name
+	case hcl.TraverseIndex:
+		// No other traversal step types are allowed directly at a block.
+		// If it looks like the user was trying to use index syntax to
+		// access an attribute then we'll produce a specialized message.
+		key := step.Key
+		if key.Type() == cty.String && key.IsKnown() && !key.IsNull() {
+			maybeName := key.AsString()
+			if hclsyntax.ValidIdentifier(maybeName) {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  `Invalid index operation`,
+					Detail:   fmt.Sprintf(`Only attribute access is allowed here. Did you mean to access attribute %q using the dot operator?`, maybeName),
+					Subject:  &step.SrcRange,
+				})
+				return diags
+			}
+		}
+		// If it looks like some other kind of index then we'll use a generic error.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Invalid index operation`,
+			Detail:   `Only attribute access is allowed here, using the dot operator.`,
+			Subject:  &step.SrcRange,
+		})
+		return diags
+	default:
+		// No other traversal types should appear in a normal valid traversal,
+		// but we'll handle this with a generic error anyway to be robust.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Invalid operation`,
+			Detail:   `Only attribute access is allowed here, using the dot operator.`,
+			Subject:  next.SourceRange().Ptr(),
+		})
+		return diags
+	}
+
+	if attrS, exists := b.Attributes[name]; exists {
+		// Check for Deprecated status of this attribute.
+		// We currently can't provide the user with any useful guidance because
+		// the deprecation string is not part of the schema, but we can at
+		// least warn them.
+		//
+		// This purposely does not attempt to recurse into nested attribute
+		// types. Because nested attribute values are often not accessed via a
+		// direct traversal to the leaf attributes, we cannot reliably detect
+		// if a nested, deprecated attribute value is actually used from the
+		// traversal alone. More precise detection of deprecated attributes
+		// would require adding metadata like marks to the cty value itself, to
+		// be caught during evaluation.
+		if attrS.Deprecated {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagWarning,
+				Summary:  `Deprecated attribute`,
+				Detail:   fmt.Sprintf(`The attribute %q is deprecated. Refer to the provider documentation for details.`, name),
+				Subject:  next.SourceRange().Ptr(),
+			})
+		}
+
+		// For attribute validation we will just apply the rest of the
+		// traversal to an unknown value of the attribute type and pass
+		// through HCL's own errors, since we don't want to replicate all
+		// of HCL's type checking rules here.
+		val := cty.UnknownVal(attrS.ImpliedType())
+		_, hclDiags := after.TraverseRel(val)
+		return diags.Append(hclDiags)
+	}
+
+	if blockS, exists := b.BlockTypes[name]; exists {
+		moreDiags := blockS.staticValidateTraversal(name, after)
+		diags = diags.Append(moreDiags)
+		return diags
+	}
+
+	// If we get here then the name isn't valid at all. We'll collect up
+	// all of the names that _are_ valid to use as suggestions.
+	var suggestions []string
+	for name := range b.Attributes {
+		suggestions = append(suggestions, name)
+	}
+	for name := range b.BlockTypes {
+		suggestions = append(suggestions, name)
+	}
+	sort.Strings(suggestions)
+	suggestion := didyoumean.NameSuggestion(name, suggestions)
+	if suggestion != "" {
+		suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
+	}
+	diags = diags.Append(&hcl.Diagnostic{
+		Severity: hcl.DiagError,
+		Summary:  `Unsupported attribute`,
+		Detail:   fmt.Sprintf(`This object has no argument, nested block, or exported attribute named %q.%s`, name, suggestion),
+		Subject:  next.SourceRange().Ptr(),
+	})
+
+	return diags
+}
+
+func (b *NestedBlock) staticValidateTraversal(typeName string, traversal hcl.Traversal) tfdiags.Diagnostics {
+	if b.Nesting == NestingSingle || b.Nesting == NestingGroup {
+		// Single blocks are easy: just pass right through.
+		return b.Block.StaticValidateTraversal(traversal)
+	}
+
+	if len(traversal) == 0 {
+		// It's always valid to access a nested block's attribute directly.
+		return nil
+	}
+
+	var diags tfdiags.Diagnostics
+	next := traversal[0]
+	after := traversal[1:]
+
+	switch b.Nesting {
+
+	case NestingSet:
+		// Can't traverse into a set at all, since it does not have any keys
+		// to index with.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Cannot index a set value`,
+			Detail:   fmt.Sprintf(`Block type %q is represented by a set of objects, and set elements do not have addressable keys. To find elements matching specific criteria, use a "for" expression with an "if" clause.`, typeName),
+			Subject:  next.SourceRange().Ptr(),
+		})
+		return diags
+
+	case NestingList:
+		if _, ok := next.(hcl.TraverseIndex); ok {
+			moreDiags := b.Block.StaticValidateTraversal(after)
+			diags = diags.Append(moreDiags)
+		} else {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  `Invalid operation`,
+				Detail:   fmt.Sprintf(`Block type %q is represented by a list of objects, so it must be indexed using a numeric key, like .%s[0].`, typeName, typeName),
+				Subject:  next.SourceRange().Ptr(),
+			})
+		}
+		return diags
+
+	case NestingMap:
+		// Both attribute and index steps are valid for maps, so we'll just
+		// pass through here and let normal evaluation catch an
+		// incorrectly-typed index key later, if present.
+		moreDiags := b.Block.StaticValidateTraversal(after)
+		diags = diags.Append(moreDiags)
+		return diags
+
+	default:
+		// Invalid nesting type is just ignored. It's checked by
+		// InternalValidate. (Note that we handled NestingSingle separately
+		// back at the start of this function.)
+		return nil
+	}
+}
diff --git a/v1.5.7/internal/configs/configschema/validate_traversal_test.go b/v1.5.7/internal/configs/configschema/validate_traversal_test.go
new file mode 100644
index 0000000..1e1cbec
--- /dev/null
+++ b/v1.5.7/internal/configs/configschema/validate_traversal_test.go
@@ -0,0 +1,261 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configschema
+
+import (
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestStaticValidateTraversal(t *testing.T) {
+	attrs := map[string]*Attribute{
+		"str":        {Type: cty.String, Optional: true},
+		"list":       {Type: cty.List(cty.String), Optional: true},
+		"dyn":        {Type: cty.DynamicPseudoType, Optional: true},
+		"deprecated": {Type: cty.String, Computed: true, Deprecated: true},
+		"nested_single": {
+			Optional: true,
+			NestedType: &Object{
+				Nesting: NestingSingle,
+				Attributes: map[string]*Attribute{
+					"optional": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		"nested_list": {
+			Optional: true,
+			NestedType: &Object{
+				Nesting: NestingList,
+				Attributes: map[string]*Attribute{
+					"optional": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		"nested_set": {
+			Optional: true,
+			NestedType: &Object{
+				Nesting: NestingSet,
+				Attributes: map[string]*Attribute{
+					"optional": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		"nested_map": {
+			Optional: true,
+			NestedType: &Object{
+				Nesting: NestingMap,
+				Attributes: map[string]*Attribute{
+					"optional": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	}
+	schema := &Block{
+		Attributes: attrs,
+		BlockTypes: map[string]*NestedBlock{
+			"single_block": {
+				Nesting: NestingSingle,
+				Block: Block{
+					Attributes: attrs,
+				},
+			},
+			"list_block": {
+				Nesting: NestingList,
+				Block: Block{
+					Attributes: attrs,
+				},
+			},
+			"set_block": {
+				Nesting: NestingSet,
+				Block: Block{
+					Attributes: attrs,
+				},
+			},
+			"map_block": {
+				Nesting: NestingMap,
+				Block: Block{
+					Attributes: attrs,
+				},
+			},
+		},
+	}
+
+	tests := []struct {
+		Traversal string
+		WantError string
+	}{
+		{
+			`obj`,
+			``,
+		},
+		{
+			`obj.str`,
+			``,
+		},
+		{
+			`obj.str.nonexist`,
+			`Unsupported attribute: Can't access attributes on a primitive-typed value (string).`,
+		},
+		{
+			`obj.list`,
+			``,
+		},
+		{
+			`obj.list[0]`,
+			``,
+		},
+		{
+			`obj.list.nonexist`,
+			`Unsupported attribute: This value does not have any attributes.`,
+		},
+		{
+			`obj.dyn`,
+			``,
+		},
+		{
+			`obj.dyn.anything_goes`,
+			``,
+		},
+		{
+			`obj.dyn[0]`,
+			``,
+		},
+		{
+			`obj.nonexist`,
+			`Unsupported attribute: This object has no argument, nested block, or exported attribute named "nonexist".`,
+		},
+		{
+			`obj[1]`,
+			`Invalid index operation: Only attribute access is allowed here, using the dot operator.`,
+		},
+		{
+			`obj["str"]`, // we require attribute access for the first step to avoid ambiguity with resource instance indices
+			`Invalid index operation: Only attribute access is allowed here. Did you mean to access attribute "str" using the dot operator?`,
+		},
+		{
+			`obj.atr`,
+			`Unsupported attribute: This object has no argument, nested block, or exported attribute named "atr". Did you mean "str"?`,
+		},
+		{
+			`obj.single_block`,
+			``,
+		},
+		{
+			`obj.single_block.str`,
+			``,
+		},
+		{
+			`obj.single_block.nonexist`,
+			`Unsupported attribute: This object has no argument, nested block, or exported attribute named "nonexist".`,
+		},
+		{
+			`obj.list_block`,
+			``,
+		},
+		{
+			`obj.list_block[0]`,
+			``,
+		},
+		{
+			`obj.list_block[0].str`,
+			``,
+		},
+		{
+			`obj.list_block[0].nonexist`,
+			`Unsupported attribute: This object has no argument, nested block, or exported attribute named "nonexist".`,
+		},
+		{
+			`obj.list_block.str`,
+			`Invalid operation: Block type "list_block" is represented by a list of objects, so it must be indexed using a numeric key, like .list_block[0].`,
+		},
+		{
+			`obj.set_block`,
+			``,
+		},
+		{
+			`obj.set_block[0]`,
+			`Cannot index a set value: Block type "set_block" is represented by a set of objects, and set elements do not have addressable keys. To find elements matching specific criteria, use a "for" expression with an "if" clause.`,
+		},
+		{
+			`obj.set_block.str`,
+			`Cannot index a set value: Block type "set_block" is represented by a set of objects, and set elements do not have addressable keys. To find elements matching specific criteria, use a "for" expression with an "if" clause.`,
+		},
+		{
+			`obj.map_block`,
+			``,
+		},
+		{
+			`obj.map_block.anything`,
+			``,
+		},
+		{
+			`obj.map_block["anything"]`,
+			``,
+		},
+		{
+			`obj.map_block.anything.str`,
+			``,
+		},
+		{
+			`obj.map_block["anything"].str`,
+			``,
+		},
+		{
+			`obj.map_block.anything.nonexist`,
+			`Unsupported attribute: This object has no argument, nested block, or exported attribute named "nonexist".`,
+		},
+		{
+			`obj.nested_single.optional`,
+			``,
+		},
+		{
+			`obj.nested_list[0].optional`,
+			``,
+		},
+		{
+			`obj.nested_set[0].optional`,
+			`Invalid index: Elements of a set are identified only by their value and don't have any separate index or key to select with, so it's only possible to perform operations across all elements of the set.`,
+		},
+		{
+			`obj.nested_map["key"].optional`,
+			``,
+		},
+		{
+			`obj.deprecated`,
+			`Deprecated attribute: The attribute "deprecated" is deprecated. Refer to the provider documentation for details.`,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Traversal, func(t *testing.T) {
+			traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(test.Traversal), "", hcl.Pos{Line: 1, Column: 1})
+			for _, diag := range parseDiags {
+				t.Error(diag.Error())
+			}
+
+			// We trim the "obj." portion from the front since StaticValidateTraversal
+			// only works with relative traversals.
+			traversal = traversal[1:]
+
+			diags := schema.StaticValidateTraversal(traversal)
+			if test.WantError == "" {
+				if diags.HasErrors() {
+					t.Errorf("unexpected error: %s", diags.Err().Error())
+				}
+			} else {
+				err := diags.ErrWithWarnings()
+				if err != nil {
+					if got := err.Error(); got != test.WantError {
+						t.Errorf("wrong error\ngot:  %s\nwant: %s", got, test.WantError)
+					}
+				} else {
+					t.Errorf("wrong error\ngot:  <no error>\nwant: %s", test.WantError)
+				}
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/configs/container.go b/v1.5.7/internal/configs/container.go
new file mode 100644
index 0000000..fd58c70
--- /dev/null
+++ b/v1.5.7/internal/configs/container.go
@@ -0,0 +1,19 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import "github.com/hashicorp/terraform/internal/addrs"
+
+// Container provides an interface for scoped resources.
+//
+// Any resources contained within a Container should not be accessible from
+// outside the container.
+type Container interface {
+	// Accessible should return true if the resource specified by addr can
+	// reference other items within this Container.
+	//
+	// Typically, that means that addr will either be the container itself or
+	// something within the container.
+	Accessible(addr addrs.Referenceable) bool
+}
diff --git a/v1.5.7/internal/configs/depends_on.go b/v1.5.7/internal/configs/depends_on.go
new file mode 100644
index 0000000..f70cac5
--- /dev/null
+++ b/v1.5.7/internal/configs/depends_on.go
@@ -0,0 +1,26 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"github.com/hashicorp/hcl/v2"
+)
+
+func decodeDependsOn(attr *hcl.Attribute) ([]hcl.Traversal, hcl.Diagnostics) {
+	var ret []hcl.Traversal
+	exprs, diags := hcl.ExprList(attr.Expr)
+
+	for _, expr := range exprs {
+		expr, shimDiags := shimTraversalInString(expr, false)
+		diags = append(diags, shimDiags...)
+
+		traversal, travDiags := hcl.AbsTraversalForExpr(expr)
+		diags = append(diags, travDiags...)
+		if len(traversal) != 0 {
+			ret = append(ret, traversal)
+		}
+	}
+
+	return ret, diags
+}
diff --git a/v1.5.7/internal/configs/doc.go b/v1.5.7/internal/configs/doc.go
new file mode 100644
index 0000000..3dadfb0
--- /dev/null
+++ b/v1.5.7/internal/configs/doc.go
@@ -0,0 +1,22 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package configs contains types that represent Terraform configurations and
+// the different elements thereof.
+//
+// The functionality in this package can be used for some static analyses of
+// Terraform configurations, but this package generally exposes representations
+// of the configuration source code rather than the result of evaluating these
+// objects. The sibling package "lang" deals with evaluation of structures
+// and expressions in the configuration.
+//
+// Due to its close relationship with HCL, this package makes frequent use
+// of types from the HCL API, including raw HCL diagnostic messages. Such
+// diagnostics can be converted into Terraform-flavored diagnostics, if needed,
+// using functions in the sibling package tfdiags.
+//
+// The Parser type is the main entry-point into this package. The LoadConfigDir
+// method can be used to load a single module directory, and then a full
+// configuration (including any descendent modules) can be produced using
+// the top-level BuildConfig method.
+package configs
diff --git a/v1.5.7/internal/configs/escaping_blocks_test.go b/v1.5.7/internal/configs/escaping_blocks_test.go
new file mode 100644
index 0000000..ca4d521
--- /dev/null
+++ b/v1.5.7/internal/configs/escaping_blocks_test.go
@@ -0,0 +1,311 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// "Escaping Blocks" are a special mechanism we have inside our block types
+// that accept a mixture of meta-arguments and externally-defined arguments,
+// which allow an author to force particular argument names to be interpreted
+// as externally-defined even if they have the same name as a meta-argument.
+//
+// An escaping block is a block with the special type name "_" (just an
+// underscore), and is allowed at the top-level of any resource, data, or
+// module block. It intentionally has a rather "odd" look so that it stands
+// out as something special and rare.
+//
+// This is not something we expect to see used a lot, but it's an important
+// part of our strategy to evolve the Terraform language in future using
+// editions, so that later editions can define new meta-arguments without
+// blocking access to externally-defined arguments of the same name.
+//
+// We should still define new meta-arguments with care to avoid squatting on
+// commonly-used names, but we can't see all modules and all providers in
+// the world and so this is an escape hatch for edge cases. Module migration
+// tools for future editions that define new meta-arguments should detect
+// collisions and automatically migrate existing arguments into an escaping
+// block.
+
+func TestEscapingBlockResource(t *testing.T) {
+	// (this also tests escaping blocks in provisioner blocks, because
+	// they only appear nested inside resource blocks.)
+
+	parser := NewParser(nil)
+	mod, diags := parser.LoadConfigDir("testdata/escaping-blocks/resource")
+	assertNoDiagnostics(t, diags)
+	if mod == nil {
+		t.Fatal("got nil root module; want non-nil")
+	}
+
+	rc := mod.ManagedResources["foo.bar"]
+	if rc == nil {
+		t.Fatal("no managed resource named foo.bar")
+	}
+
+	t.Run("resource body", func(t *testing.T) {
+		if got := rc.Count; got == nil {
+			t.Errorf("count not set; want count = 2")
+		} else {
+			got, diags := got.Value(nil)
+			assertNoDiagnostics(t, diags)
+			if want := cty.NumberIntVal(2); !want.RawEquals(got) {
+				t.Errorf("wrong count\ngot:  %#v\nwant: %#v", got, want)
+			}
+		}
+		if got, want := rc.ForEach, hcl.Expression(nil); got != want {
+			// Shouldn't have any count because our test fixture only has
+			// for_each in the escaping block.
+			t.Errorf("wrong for_each\ngot:  %#v\nwant: %#v", got, want)
+		}
+
+		schema := &hcl.BodySchema{
+			Attributes: []hcl.AttributeSchema{
+				{Name: "normal", Required: true},
+				{Name: "count", Required: true},
+				{Name: "for_each", Required: true},
+			},
+			Blocks: []hcl.BlockHeaderSchema{
+				{Type: "normal_block"},
+				{Type: "lifecycle"},
+				{Type: "_"},
+			},
+		}
+		content, diags := rc.Config.Content(schema)
+		assertNoDiagnostics(t, diags)
+
+		normalVal, diags := content.Attributes["normal"].Expr.Value(nil)
+		assertNoDiagnostics(t, diags)
+		if got, want := normalVal, cty.StringVal("yes"); !want.RawEquals(got) {
+			t.Errorf("wrong value for 'normal'\ngot:  %#v\nwant: %#v", got, want)
+		}
+
+		countVal, diags := content.Attributes["count"].Expr.Value(nil)
+		assertNoDiagnostics(t, diags)
+		if got, want := countVal, cty.StringVal("not actually count"); !want.RawEquals(got) {
+			t.Errorf("wrong value for 'count'\ngot:  %#v\nwant: %#v", got, want)
+		}
+
+		var gotBlockTypes []string
+		for _, block := range content.Blocks {
+			gotBlockTypes = append(gotBlockTypes, block.Type)
+		}
+		wantBlockTypes := []string{"normal_block", "lifecycle", "_"}
+		if diff := cmp.Diff(gotBlockTypes, wantBlockTypes); diff != "" {
+			t.Errorf("wrong block types\n%s", diff)
+		}
+	})
+	t.Run("provisioner body", func(t *testing.T) {
+		if got, want := len(rc.Managed.Provisioners), 1; got != want {
+			t.Fatalf("wrong number of provisioners %d; want %d", got, want)
+		}
+		pc := rc.Managed.Provisioners[0]
+
+		schema := &hcl.BodySchema{
+			Attributes: []hcl.AttributeSchema{
+				{Name: "when", Required: true},
+				{Name: "normal", Required: true},
+			},
+			Blocks: []hcl.BlockHeaderSchema{
+				{Type: "normal_block"},
+				{Type: "lifecycle"},
+				{Type: "_"},
+			},
+		}
+		content, diags := pc.Config.Content(schema)
+		assertNoDiagnostics(t, diags)
+
+		normalVal, diags := content.Attributes["normal"].Expr.Value(nil)
+		assertNoDiagnostics(t, diags)
+		if got, want := normalVal, cty.StringVal("yep"); !want.RawEquals(got) {
+			t.Errorf("wrong value for 'normal'\ngot:  %#v\nwant: %#v", got, want)
+		}
+		whenVal, diags := content.Attributes["when"].Expr.Value(nil)
+		assertNoDiagnostics(t, diags)
+		if got, want := whenVal, cty.StringVal("hell freezes over"); !want.RawEquals(got) {
+			t.Errorf("wrong value for 'normal'\ngot:  %#v\nwant: %#v", got, want)
+		}
+	})
+}
+
+func TestEscapingBlockData(t *testing.T) {
+	parser := NewParser(nil)
+	mod, diags := parser.LoadConfigDir("testdata/escaping-blocks/data")
+	assertNoDiagnostics(t, diags)
+	if mod == nil {
+		t.Fatal("got nil root module; want non-nil")
+	}
+
+	rc := mod.DataResources["data.foo.bar"]
+	if rc == nil {
+		t.Fatal("no data resource named data.foo.bar")
+	}
+
+	if got := rc.Count; got == nil {
+		t.Errorf("count not set; want count = 2")
+	} else {
+		got, diags := got.Value(nil)
+		assertNoDiagnostics(t, diags)
+		if want := cty.NumberIntVal(2); !want.RawEquals(got) {
+			t.Errorf("wrong count\ngot:  %#v\nwant: %#v", got, want)
+		}
+	}
+	if got, want := rc.ForEach, hcl.Expression(nil); got != want {
+		// Shouldn't have any count because our test fixture only has
+		// for_each in the escaping block.
+		t.Errorf("wrong for_each\ngot:  %#v\nwant: %#v", got, want)
+	}
+
+	schema := &hcl.BodySchema{
+		Attributes: []hcl.AttributeSchema{
+			{Name: "normal", Required: true},
+			{Name: "count", Required: true},
+			{Name: "for_each", Required: true},
+		},
+		Blocks: []hcl.BlockHeaderSchema{
+			{Type: "normal_block"},
+			{Type: "lifecycle"},
+			{Type: "_"},
+		},
+	}
+	content, diags := rc.Config.Content(schema)
+	assertNoDiagnostics(t, diags)
+
+	normalVal, diags := content.Attributes["normal"].Expr.Value(nil)
+	assertNoDiagnostics(t, diags)
+	if got, want := normalVal, cty.StringVal("yes"); !want.RawEquals(got) {
+		t.Errorf("wrong value for 'normal'\ngot:  %#v\nwant: %#v", got, want)
+	}
+
+	countVal, diags := content.Attributes["count"].Expr.Value(nil)
+	assertNoDiagnostics(t, diags)
+	if got, want := countVal, cty.StringVal("not actually count"); !want.RawEquals(got) {
+		t.Errorf("wrong value for 'count'\ngot:  %#v\nwant: %#v", got, want)
+	}
+
+	var gotBlockTypes []string
+	for _, block := range content.Blocks {
+		gotBlockTypes = append(gotBlockTypes, block.Type)
+	}
+	wantBlockTypes := []string{"normal_block", "lifecycle", "_"}
+	if diff := cmp.Diff(gotBlockTypes, wantBlockTypes); diff != "" {
+		t.Errorf("wrong block types\n%s", diff)
+	}
+
+}
+
+func TestEscapingBlockModule(t *testing.T) {
+	parser := NewParser(nil)
+	mod, diags := parser.LoadConfigDir("testdata/escaping-blocks/module")
+	assertNoDiagnostics(t, diags)
+	if mod == nil {
+		t.Fatal("got nil root module; want non-nil")
+	}
+
+	mc := mod.ModuleCalls["foo"]
+	if mc == nil {
+		t.Fatal("no module call named foo")
+	}
+
+	if got := mc.Count; got == nil {
+		t.Errorf("count not set; want count = 2")
+	} else {
+		got, diags := got.Value(nil)
+		assertNoDiagnostics(t, diags)
+		if want := cty.NumberIntVal(2); !want.RawEquals(got) {
+			t.Errorf("wrong count\ngot:  %#v\nwant: %#v", got, want)
+		}
+	}
+	if got, want := mc.ForEach, hcl.Expression(nil); got != want {
+		// Shouldn't have any count because our test fixture only has
+		// for_each in the escaping block.
+		t.Errorf("wrong for_each\ngot:  %#v\nwant: %#v", got, want)
+	}
+
+	schema := &hcl.BodySchema{
+		Attributes: []hcl.AttributeSchema{
+			{Name: "normal", Required: true},
+			{Name: "count", Required: true},
+			{Name: "for_each", Required: true},
+		},
+		Blocks: []hcl.BlockHeaderSchema{
+			{Type: "normal_block"},
+			{Type: "lifecycle"},
+			{Type: "_"},
+		},
+	}
+	content, diags := mc.Config.Content(schema)
+	assertNoDiagnostics(t, diags)
+
+	normalVal, diags := content.Attributes["normal"].Expr.Value(nil)
+	assertNoDiagnostics(t, diags)
+	if got, want := normalVal, cty.StringVal("yes"); !want.RawEquals(got) {
+		t.Errorf("wrong value for 'normal'\ngot:  %#v\nwant: %#v", got, want)
+	}
+
+	countVal, diags := content.Attributes["count"].Expr.Value(nil)
+	assertNoDiagnostics(t, diags)
+	if got, want := countVal, cty.StringVal("not actually count"); !want.RawEquals(got) {
+		t.Errorf("wrong value for 'count'\ngot:  %#v\nwant: %#v", got, want)
+	}
+
+	var gotBlockTypes []string
+	for _, block := range content.Blocks {
+		gotBlockTypes = append(gotBlockTypes, block.Type)
+	}
+	wantBlockTypes := []string{"normal_block", "lifecycle", "_"}
+	if diff := cmp.Diff(gotBlockTypes, wantBlockTypes); diff != "" {
+		t.Errorf("wrong block types\n%s", diff)
+	}
+
+}
+
+func TestEscapingBlockProvider(t *testing.T) {
+	parser := NewParser(nil)
+	mod, diags := parser.LoadConfigDir("testdata/escaping-blocks/provider")
+	assertNoDiagnostics(t, diags)
+	if mod == nil {
+		t.Fatal("got nil root module; want non-nil")
+	}
+
+	pc := mod.ProviderConfigs["foo.bar"]
+	if pc == nil {
+		t.Fatal("no provider configuration named foo.bar")
+	}
+
+	if got, want := pc.Alias, "bar"; got != want {
+		t.Errorf("wrong alias\ngot:  %#v\nwant: %#v", got, want)
+	}
+
+	schema := &hcl.BodySchema{
+		Attributes: []hcl.AttributeSchema{
+			{Name: "normal", Required: true},
+			{Name: "alias", Required: true},
+			{Name: "version", Required: true},
+		},
+	}
+	content, diags := pc.Config.Content(schema)
+	assertNoDiagnostics(t, diags)
+
+	normalVal, diags := content.Attributes["normal"].Expr.Value(nil)
+	assertNoDiagnostics(t, diags)
+	if got, want := normalVal, cty.StringVal("yes"); !want.RawEquals(got) {
+		t.Errorf("wrong value for 'normal'\ngot:  %#v\nwant: %#v", got, want)
+	}
+	aliasVal, diags := content.Attributes["alias"].Expr.Value(nil)
+	assertNoDiagnostics(t, diags)
+	if got, want := aliasVal, cty.StringVal("not actually alias"); !want.RawEquals(got) {
+		t.Errorf("wrong value for 'alias'\ngot:  %#v\nwant: %#v", got, want)
+	}
+	versionVal, diags := content.Attributes["version"].Expr.Value(nil)
+	assertNoDiagnostics(t, diags)
+	if got, want := versionVal, cty.StringVal("not actually version"); !want.RawEquals(got) {
+		t.Errorf("wrong value for 'version'\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
diff --git a/v1.5.7/internal/configs/experiments.go b/v1.5.7/internal/configs/experiments.go
new file mode 100644
index 0000000..1d40750
--- /dev/null
+++ b/v1.5.7/internal/configs/experiments.go
@@ -0,0 +1,239 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/experiments"
+	"github.com/hashicorp/terraform/version"
+)
+
+// When developing UI for experimental features, you can temporarily disable
+// the experiment warning by setting this package-level variable to a non-empty
+// value using a link-time flag:
+//
+// go install -ldflags="-X 'github.com/hashicorp/terraform/internal/configs.disableExperimentWarnings=yes'"
+//
+// This functionality is for development purposes only and is not a feature we
+// are committing to supporting for end users.
+var disableExperimentWarnings = ""
+
+// sniffActiveExperiments does minimal parsing of the given body for
+// "terraform" blocks with "experiments" attributes, returning the
+// experiments found.
+//
+// This is separate from other processing so that we can be sure that all of
+// the experiments are known before we process the result of the module config,
+// and thus we can take into account which experiments are active when deciding
+// how to decode.
+func sniffActiveExperiments(body hcl.Body, allowed bool) (experiments.Set, hcl.Diagnostics) {
+	rootContent, _, diags := body.PartialContent(configFileTerraformBlockSniffRootSchema)
+
+	ret := experiments.NewSet()
+
+	for _, block := range rootContent.Blocks {
+		content, _, blockDiags := block.Body.PartialContent(configFileExperimentsSniffBlockSchema)
+		diags = append(diags, blockDiags...)
+
+		if attr, exists := content.Attributes["language"]; exists {
+			// We don't yet have a sense of selecting an edition of the
+			// language, but we're reserving this syntax for now so that
+			// if and when we do this later older versions of Terraform
+			// will emit a more helpful error message than just saying
+			// this attribute doesn't exist. Handling this as part of
+			// experiments is a bit odd for now but justified by the
+			// fact that a future fuller implementation of switchable
+			// languages would be likely use a similar implementation
+			// strategy as experiments, and thus would lead to this
+			// function being refactored to deal with both concerns at
+			// once. We'll see, though!
+			kw := hcl.ExprAsKeyword(attr.Expr)
+			currentVersion := version.SemVer.String()
+			const firstEdition = "TF2021"
+			switch {
+			case kw == "": // (the expression wasn't a keyword at all)
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid language edition",
+					Detail: fmt.Sprintf(
+						"The language argument expects a bare language edition keyword. Terraform %s supports only language edition %s, which is the default.",
+						currentVersion, firstEdition,
+					),
+					Subject: attr.Expr.Range().Ptr(),
+				})
+			case kw != firstEdition:
+				rel := "different"
+				if kw > firstEdition { // would be weird for this not to be true, but it's user input so anything goes
+					rel = "newer"
+				}
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Unsupported language edition",
+					Detail: fmt.Sprintf(
+						"Terraform v%s only supports language edition %s. This module requires a %s version of Terraform CLI.",
+						currentVersion, firstEdition, rel,
+					),
+					Subject: attr.Expr.Range().Ptr(),
+				})
+			}
+		}
+
+		attr, exists := content.Attributes["experiments"]
+		if !exists {
+			continue
+		}
+
+		exps, expDiags := decodeExperimentsAttr(attr)
+
+		// Because we concluded this particular experiment in the same
+		// release as we made experiments alpha-releases-only, we need to
+		// treat it as special to avoid masking the "experiment has concluded"
+		// error with the more general "experiments are not available at all"
+		// error. Note that this experiment is marked as concluded so this
+		// only "allows" showing the different error message that it is
+		// concluded, and does not allow actually using the experiment outside
+		// of an alpha.
+		// NOTE: We should be able to remove this special exception a release
+		// or two after v1.3 when folks have had a chance to notice that the
+		// experiment has concluded and update their modules accordingly.
+		// When we do so, we might also consider changing decodeExperimentsAttr
+		// to _not_ include concluded experiments in the returned set, since
+		// we're doing that right now only to make this condition work.
+		if exps.Has(experiments.ModuleVariableOptionalAttrs) && len(exps) == 1 {
+			allowed = true
+		}
+
+		if allowed {
+			diags = append(diags, expDiags...)
+			if !expDiags.HasErrors() {
+				ret = experiments.SetUnion(ret, exps)
+			}
+		} else {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Module uses experimental features",
+				Detail:   "Experimental features are intended only for gathering early feedback on new language designs, and so are available only in alpha releases of Terraform.",
+				Subject:  attr.NameRange.Ptr(),
+			})
+		}
+	}
+
+	return ret, diags
+}
+
+func decodeExperimentsAttr(attr *hcl.Attribute) (experiments.Set, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+
+	exprs, moreDiags := hcl.ExprList(attr.Expr)
+	diags = append(diags, moreDiags...)
+	if moreDiags.HasErrors() {
+		return nil, diags
+	}
+
+	var ret = experiments.NewSet()
+	for _, expr := range exprs {
+		kw := hcl.ExprAsKeyword(expr)
+		if kw == "" {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid experiment keyword",
+				Detail:   "Elements of \"experiments\" must all be keywords representing active experiments.",
+				Subject:  expr.Range().Ptr(),
+			})
+			continue
+		}
+
+		exp, err := experiments.GetCurrent(kw)
+		switch err := err.(type) {
+		case experiments.UnavailableError:
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Unknown experiment keyword",
+				Detail:   fmt.Sprintf("There is no current experiment with the keyword %q.", kw),
+				Subject:  expr.Range().Ptr(),
+			})
+		case experiments.ConcludedError:
+			// As a special case we still include the optional attributes
+			// experiment if it's present, because our caller treats that
+			// as special. See the comment in sniffActiveExperiments for
+			// more information, and remove this special case here one the
+			// special case up there is also removed.
+			if kw == "module_variable_optional_attrs" {
+				ret.Add(experiments.ModuleVariableOptionalAttrs)
+			}
+
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Experiment has concluded",
+				Detail:   fmt.Sprintf("Experiment %q is no longer available. %s", kw, err.Message),
+				Subject:  expr.Range().Ptr(),
+			})
+		case nil:
+			// No error at all means it's valid and current.
+			ret.Add(exp)
+
+			if disableExperimentWarnings == "" {
+				// However, experimental features are subject to breaking changes
+				// in future releases, so we'll warn about them to help make sure
+				// folks aren't inadvertently using them in places where that'd be
+				// inappropriate, particularly if the experiment is active in a
+				// shared module they depend on.
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagWarning,
+					Summary:  fmt.Sprintf("Experimental feature %q is active", exp.Keyword()),
+					Detail:   "Experimental features are available only in alpha releases of Terraform and are subject to breaking changes or total removal in later versions, based on feedback. We recommend against using experimental features in production.\n\nIf you have feedback on the design of this feature, please open a GitHub issue to discuss it.",
+					Subject:  expr.Range().Ptr(),
+				})
+			}
+
+		default:
+			// This should never happen, because GetCurrent is not documented
+			// to return any other error type, but we'll handle it to be robust.
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid experiment keyword",
+				Detail:   fmt.Sprintf("Could not parse %q as an experiment keyword: %s.", kw, err.Error()),
+				Subject:  expr.Range().Ptr(),
+			})
+		}
+	}
+	return ret, diags
+}
+
+func checkModuleExperiments(m *Module) hcl.Diagnostics {
+	var diags hcl.Diagnostics
+
+	// When we have current experiments, this is a good place to check that
+	// the features in question can only be used when the experiments are
+	// active. Return error diagnostics if a feature is being used without
+	// opting in to the feature. For example:
+	/*
+		if !m.ActiveExperiments.Has(experiments.ResourceForEach) {
+			for _, rc := range m.ManagedResources {
+				if rc.ForEach != nil {
+					diags = append(diags, &hcl.Diagnostic{
+						Severity: hcl.DiagError,
+						Summary:  "Resource for_each is experimental",
+						Detail:   "This feature is currently an opt-in experiment, subject to change in future releases based on feedback.\n\nActivate the feature for this module by adding resource_for_each to the list of active experiments.",
+						Subject:  rc.ForEach.Range().Ptr(),
+					})
+				}
+			}
+			for _, rc := range m.DataResources {
+				if rc.ForEach != nil {
+					diags = append(diags, &hcl.Diagnostic{
+						Severity: hcl.DiagError,
+						Summary:  "Resource for_each is experimental",
+						Detail:   "This feature is currently an opt-in experiment, subject to change in future releases based on feedback.\n\nActivate the feature for this module by adding resource_for_each to the list of active experiments.",
+						Subject:  rc.ForEach.Range().Ptr(),
+					})
+				}
+			}
+		}
+	*/
+
+	return diags
+}
diff --git a/v1.5.7/internal/configs/experiments_test.go b/v1.5.7/internal/configs/experiments_test.go
new file mode 100644
index 0000000..0d774aa
--- /dev/null
+++ b/v1.5.7/internal/configs/experiments_test.go
@@ -0,0 +1,142 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/hcl/v2"
+
+	"github.com/hashicorp/terraform/internal/experiments"
+)
+
+func TestExperimentsConfig(t *testing.T) {
+	// The experiment registrations are global, so we need to do some special
+	// patching in order to get a predictable set for our tests.
+	current := experiments.Experiment("current")
+	concluded := experiments.Experiment("concluded")
+	currentExperiments := experiments.NewSet(current)
+	concludedExperiments := map[experiments.Experiment]string{
+		concluded: "Reticulate your splines.",
+	}
+	defer experiments.OverrideForTesting(t, currentExperiments, concludedExperiments)()
+
+	t.Run("current", func(t *testing.T) {
+		parser := NewParser(nil)
+		parser.AllowLanguageExperiments(true)
+		mod, diags := parser.LoadConfigDir("testdata/experiments/current")
+		if got, want := len(diags), 1; got != want {
+			t.Fatalf("wrong number of diagnostics %d; want %d", got, want)
+		}
+		got := diags[0]
+		want := &hcl.Diagnostic{
+			Severity: hcl.DiagWarning,
+			Summary:  `Experimental feature "current" is active`,
+			Detail:   "Experimental features are available only in alpha releases of Terraform and are subject to breaking changes or total removal in later versions, based on feedback. We recommend against using experimental features in production.\n\nIf you have feedback on the design of this feature, please open a GitHub issue to discuss it.",
+			Subject: &hcl.Range{
+				Filename: "testdata/experiments/current/current_experiment.tf",
+				Start:    hcl.Pos{Line: 2, Column: 18, Byte: 29},
+				End:      hcl.Pos{Line: 2, Column: 25, Byte: 36},
+			},
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong warning\n%s", diff)
+		}
+		if got, want := len(mod.ActiveExperiments), 1; got != want {
+			t.Errorf("wrong number of experiments %d; want %d", got, want)
+		}
+		if !mod.ActiveExperiments.Has(current) {
+			t.Errorf("module does not indicate current experiment as active")
+		}
+	})
+	t.Run("concluded", func(t *testing.T) {
+		parser := NewParser(nil)
+		parser.AllowLanguageExperiments(true)
+		_, diags := parser.LoadConfigDir("testdata/experiments/concluded")
+		if got, want := len(diags), 1; got != want {
+			t.Fatalf("wrong number of diagnostics %d; want %d", got, want)
+		}
+		got := diags[0]
+		want := &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Experiment has concluded`,
+			Detail:   `Experiment "concluded" is no longer available. Reticulate your splines.`,
+			Subject: &hcl.Range{
+				Filename: "testdata/experiments/concluded/concluded_experiment.tf",
+				Start:    hcl.Pos{Line: 2, Column: 18, Byte: 29},
+				End:      hcl.Pos{Line: 2, Column: 27, Byte: 38},
+			},
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong error\n%s", diff)
+		}
+	})
+	t.Run("concluded", func(t *testing.T) {
+		parser := NewParser(nil)
+		parser.AllowLanguageExperiments(true)
+		_, diags := parser.LoadConfigDir("testdata/experiments/unknown")
+		if got, want := len(diags), 1; got != want {
+			t.Fatalf("wrong number of diagnostics %d; want %d", got, want)
+		}
+		got := diags[0]
+		want := &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Unknown experiment keyword`,
+			Detail:   `There is no current experiment with the keyword "unknown".`,
+			Subject: &hcl.Range{
+				Filename: "testdata/experiments/unknown/unknown_experiment.tf",
+				Start:    hcl.Pos{Line: 2, Column: 18, Byte: 29},
+				End:      hcl.Pos{Line: 2, Column: 25, Byte: 36},
+			},
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong error\n%s", diff)
+		}
+	})
+	t.Run("invalid", func(t *testing.T) {
+		parser := NewParser(nil)
+		parser.AllowLanguageExperiments(true)
+		_, diags := parser.LoadConfigDir("testdata/experiments/invalid")
+		if got, want := len(diags), 1; got != want {
+			t.Fatalf("wrong number of diagnostics %d; want %d", got, want)
+		}
+		got := diags[0]
+		want := &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Invalid expression`,
+			Detail:   `A static list expression is required.`,
+			Subject: &hcl.Range{
+				Filename: "testdata/experiments/invalid/invalid_experiments.tf",
+				Start:    hcl.Pos{Line: 2, Column: 17, Byte: 28},
+				End:      hcl.Pos{Line: 2, Column: 24, Byte: 35},
+			},
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong error\n%s", diff)
+		}
+	})
+	t.Run("disallowed", func(t *testing.T) {
+		parser := NewParser(nil)
+		parser.AllowLanguageExperiments(false) // The default situation for release builds
+		_, diags := parser.LoadConfigDir("testdata/experiments/current")
+		if got, want := len(diags), 1; got != want {
+			t.Fatalf("wrong number of diagnostics %d; want %d", got, want)
+		}
+		got := diags[0]
+		want := &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Module uses experimental features`,
+			Detail:   `Experimental features are intended only for gathering early feedback on new language designs, and so are available only in alpha releases of Terraform.`,
+			Subject: &hcl.Range{
+				Filename: "testdata/experiments/current/current_experiment.tf",
+				Start:    hcl.Pos{Line: 2, Column: 3, Byte: 14},
+				End:      hcl.Pos{Line: 2, Column: 14, Byte: 25},
+			},
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong error\n%s", diff)
+		}
+	})
+}
diff --git a/v1.5.7/internal/configs/hcl2shim/flatmap.go b/v1.5.7/internal/configs/hcl2shim/flatmap.go
new file mode 100644
index 0000000..9ae50d1
--- /dev/null
+++ b/v1.5.7/internal/configs/hcl2shim/flatmap.go
@@ -0,0 +1,427 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package hcl2shim
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/zclconf/go-cty/cty/convert"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+// FlatmapValueFromHCL2 converts a value from HCL2 (really, from the cty dynamic
+// types library that HCL2 uses) to a map compatible with what would be
+// produced by the "flatmap" package.
+//
+// The type of the given value informs the structure of the resulting map.
+// The value must be of an object type or this function will panic.
+//
+// Flatmap values can only represent maps when they are of primitive types,
+// so the given value must not have any maps of complex types or the result
+// is undefined.
+func FlatmapValueFromHCL2(v cty.Value) map[string]string {
+	if v.IsNull() {
+		return nil
+	}
+
+	if !v.Type().IsObjectType() {
+		panic(fmt.Sprintf("HCL2ValueFromFlatmap called on %#v", v.Type()))
+	}
+
+	m := make(map[string]string)
+	flatmapValueFromHCL2Map(m, "", v)
+	return m
+}
+
+func flatmapValueFromHCL2Value(m map[string]string, key string, val cty.Value) {
+	ty := val.Type()
+	switch {
+	case ty.IsPrimitiveType() || ty == cty.DynamicPseudoType:
+		flatmapValueFromHCL2Primitive(m, key, val)
+	case ty.IsObjectType() || ty.IsMapType():
+		flatmapValueFromHCL2Map(m, key+".", val)
+	case ty.IsTupleType() || ty.IsListType() || ty.IsSetType():
+		flatmapValueFromHCL2Seq(m, key+".", val)
+	default:
+		panic(fmt.Sprintf("cannot encode %s to flatmap", ty.FriendlyName()))
+	}
+}
+
+func flatmapValueFromHCL2Primitive(m map[string]string, key string, val cty.Value) {
+	if !val.IsKnown() {
+		m[key] = UnknownVariableValue
+		return
+	}
+	if val.IsNull() {
+		// Omit entirely
+		return
+	}
+
+	var err error
+	val, err = convert.Convert(val, cty.String)
+	if err != nil {
+		// Should not be possible, since all primitive types can convert to string.
+		panic(fmt.Sprintf("invalid primitive encoding to flatmap: %s", err))
+	}
+	m[key] = val.AsString()
+}
+
+func flatmapValueFromHCL2Map(m map[string]string, prefix string, val cty.Value) {
+	if val.IsNull() {
+		// Omit entirely
+		return
+	}
+	if !val.IsKnown() {
+		switch {
+		case val.Type().IsObjectType():
+			// Whole objects can't be unknown in flatmap, so instead we'll
+			// just write all of the attribute values out as unknown.
+			for name, aty := range val.Type().AttributeTypes() {
+				flatmapValueFromHCL2Value(m, prefix+name, cty.UnknownVal(aty))
+			}
+		default:
+			m[prefix+"%"] = UnknownVariableValue
+		}
+		return
+	}
+
+	len := 0
+	for it := val.ElementIterator(); it.Next(); {
+		ak, av := it.Element()
+		name := ak.AsString()
+		flatmapValueFromHCL2Value(m, prefix+name, av)
+		len++
+	}
+	if !val.Type().IsObjectType() { // objects don't have an explicit count included, since their attribute count is fixed
+		m[prefix+"%"] = strconv.Itoa(len)
+	}
+}
+
+func flatmapValueFromHCL2Seq(m map[string]string, prefix string, val cty.Value) {
+	if val.IsNull() {
+		// Omit entirely
+		return
+	}
+	if !val.IsKnown() {
+		m[prefix+"#"] = UnknownVariableValue
+		return
+	}
+
+	// For sets this won't actually generate exactly what helper/schema would've
+	// generated, because we don't have access to the set key function it
+	// would've used. However, in practice it doesn't actually matter what the
+	// keys are as long as they are unique, so we'll just generate sequential
+	// indexes for them as if it were a list.
+	//
+	// An important implication of this, however, is that the set ordering will
+	// not be consistent across mutations and so different keys may be assigned
+	// to the same value when round-tripping. Since this shim is intended to
+	// be short-lived and not used for round-tripping, we accept this.
+	i := 0
+	for it := val.ElementIterator(); it.Next(); {
+		_, av := it.Element()
+		key := prefix + strconv.Itoa(i)
+		flatmapValueFromHCL2Value(m, key, av)
+		i++
+	}
+	m[prefix+"#"] = strconv.Itoa(i)
+}
+
+// HCL2ValueFromFlatmap converts a map compatible with what would be produced
+// by the "flatmap" package to a HCL2 (really, the cty dynamic types library
+// that HCL2 uses) object type.
+//
+// The intended result type must be provided in order to guide how the
+// map contents are decoded. This must be an object type or this function
+// will panic.
+//
+// Flatmap values can only represent maps when they are of primitive types,
+// so the given type must not have any maps of complex types or the result
+// is undefined.
+//
+// The result may contain null values if the given map does not contain keys
+// for all of the different key paths implied by the given type.
+func HCL2ValueFromFlatmap(m map[string]string, ty cty.Type) (cty.Value, error) {
+	if m == nil {
+		return cty.NullVal(ty), nil
+	}
+	if !ty.IsObjectType() {
+		panic(fmt.Sprintf("HCL2ValueFromFlatmap called on %#v", ty))
+	}
+
+	return hcl2ValueFromFlatmapObject(m, "", ty.AttributeTypes())
+}
+
+func hcl2ValueFromFlatmapValue(m map[string]string, key string, ty cty.Type) (cty.Value, error) {
+	var val cty.Value
+	var err error
+	switch {
+	case ty.IsPrimitiveType():
+		val, err = hcl2ValueFromFlatmapPrimitive(m, key, ty)
+	case ty.IsObjectType():
+		val, err = hcl2ValueFromFlatmapObject(m, key+".", ty.AttributeTypes())
+	case ty.IsTupleType():
+		val, err = hcl2ValueFromFlatmapTuple(m, key+".", ty.TupleElementTypes())
+	case ty.IsMapType():
+		val, err = hcl2ValueFromFlatmapMap(m, key+".", ty)
+	case ty.IsListType():
+		val, err = hcl2ValueFromFlatmapList(m, key+".", ty)
+	case ty.IsSetType():
+		val, err = hcl2ValueFromFlatmapSet(m, key+".", ty)
+	default:
+		err = fmt.Errorf("cannot decode %s from flatmap", ty.FriendlyName())
+	}
+
+	if err != nil {
+		return cty.DynamicVal, err
+	}
+	return val, nil
+}
+
+func hcl2ValueFromFlatmapPrimitive(m map[string]string, key string, ty cty.Type) (cty.Value, error) {
+	rawVal, exists := m[key]
+	if !exists {
+		return cty.NullVal(ty), nil
+	}
+	if rawVal == UnknownVariableValue {
+		return cty.UnknownVal(ty), nil
+	}
+
+	var err error
+	val := cty.StringVal(rawVal)
+	val, err = convert.Convert(val, ty)
+	if err != nil {
+		// This should never happen for _valid_ input, but flatmap data might
+		// be tampered with by the user and become invalid.
+		return cty.DynamicVal, fmt.Errorf("invalid value for %q in state: %s", key, err)
+	}
+
+	return val, nil
+}
+
+func hcl2ValueFromFlatmapObject(m map[string]string, prefix string, atys map[string]cty.Type) (cty.Value, error) {
+	vals := make(map[string]cty.Value)
+	for name, aty := range atys {
+		val, err := hcl2ValueFromFlatmapValue(m, prefix+name, aty)
+		if err != nil {
+			return cty.DynamicVal, err
+		}
+		vals[name] = val
+	}
+	return cty.ObjectVal(vals), nil
+}
+
+func hcl2ValueFromFlatmapTuple(m map[string]string, prefix string, etys []cty.Type) (cty.Value, error) {
+	var vals []cty.Value
+
+	// if the container is unknown, there is no count string
+	listName := strings.TrimRight(prefix, ".")
+	if m[listName] == UnknownVariableValue {
+		return cty.UnknownVal(cty.Tuple(etys)), nil
+	}
+
+	countStr, exists := m[prefix+"#"]
+	if !exists {
+		return cty.NullVal(cty.Tuple(etys)), nil
+	}
+	if countStr == UnknownVariableValue {
+		return cty.UnknownVal(cty.Tuple(etys)), nil
+	}
+
+	count, err := strconv.Atoi(countStr)
+	if err != nil {
+		return cty.DynamicVal, fmt.Errorf("invalid count value for %q in state: %s", prefix, err)
+	}
+	if count != len(etys) {
+		return cty.DynamicVal, fmt.Errorf("wrong number of values for %q in state: got %d, but need %d", prefix, count, len(etys))
+	}
+
+	vals = make([]cty.Value, len(etys))
+	for i, ety := range etys {
+		key := prefix + strconv.Itoa(i)
+		val, err := hcl2ValueFromFlatmapValue(m, key, ety)
+		if err != nil {
+			return cty.DynamicVal, err
+		}
+		vals[i] = val
+	}
+	return cty.TupleVal(vals), nil
+}
+
+func hcl2ValueFromFlatmapMap(m map[string]string, prefix string, ty cty.Type) (cty.Value, error) {
+	vals := make(map[string]cty.Value)
+	ety := ty.ElementType()
+
+	// if the container is unknown, there is no count string
+	listName := strings.TrimRight(prefix, ".")
+	if m[listName] == UnknownVariableValue {
+		return cty.UnknownVal(ty), nil
+	}
+
+	// We actually don't really care about the "count" of a map for our
+	// purposes here, but we do need to check if it _exists_ in order to
+	// recognize the difference between null (not set at all) and empty.
+	if strCount, exists := m[prefix+"%"]; !exists {
+		return cty.NullVal(ty), nil
+	} else if strCount == UnknownVariableValue {
+		return cty.UnknownVal(ty), nil
+	}
+
+	for fullKey := range m {
+		if !strings.HasPrefix(fullKey, prefix) {
+			continue
+		}
+
+		// The flatmap format doesn't allow us to distinguish between keys
+		// that contain periods and nested objects, so by convention a
+		// map is only ever of primitive type in flatmap, and we just assume
+		// that the remainder of the raw key (dots and all) is the key we
+		// want in the result value.
+		key := fullKey[len(prefix):]
+		if key == "%" {
+			// Ignore the "count" key
+			continue
+		}
+
+		val, err := hcl2ValueFromFlatmapValue(m, fullKey, ety)
+		if err != nil {
+			return cty.DynamicVal, err
+		}
+		vals[key] = val
+	}
+
+	if len(vals) == 0 {
+		return cty.MapValEmpty(ety), nil
+	}
+	return cty.MapVal(vals), nil
+}
+
+func hcl2ValueFromFlatmapList(m map[string]string, prefix string, ty cty.Type) (cty.Value, error) {
+	var vals []cty.Value
+
+	// if the container is unknown, there is no count string
+	listName := strings.TrimRight(prefix, ".")
+	if m[listName] == UnknownVariableValue {
+		return cty.UnknownVal(ty), nil
+	}
+
+	countStr, exists := m[prefix+"#"]
+	if !exists {
+		return cty.NullVal(ty), nil
+	}
+	if countStr == UnknownVariableValue {
+		return cty.UnknownVal(ty), nil
+	}
+
+	count, err := strconv.Atoi(countStr)
+	if err != nil {
+		return cty.DynamicVal, fmt.Errorf("invalid count value for %q in state: %s", prefix, err)
+	}
+
+	ety := ty.ElementType()
+	if count == 0 {
+		return cty.ListValEmpty(ety), nil
+	}
+
+	vals = make([]cty.Value, count)
+	for i := 0; i < count; i++ {
+		key := prefix + strconv.Itoa(i)
+		val, err := hcl2ValueFromFlatmapValue(m, key, ety)
+		if err != nil {
+			return cty.DynamicVal, err
+		}
+		vals[i] = val
+	}
+
+	return cty.ListVal(vals), nil
+}
+
+func hcl2ValueFromFlatmapSet(m map[string]string, prefix string, ty cty.Type) (cty.Value, error) {
+	var vals []cty.Value
+	ety := ty.ElementType()
+
+	// if the container is unknown, there is no count string
+	listName := strings.TrimRight(prefix, ".")
+	if m[listName] == UnknownVariableValue {
+		return cty.UnknownVal(ty), nil
+	}
+
+	strCount, exists := m[prefix+"#"]
+	if !exists {
+		return cty.NullVal(ty), nil
+	} else if strCount == UnknownVariableValue {
+		return cty.UnknownVal(ty), nil
+	}
+
+	// Keep track of keys we've seen, se we don't add the same set value
+	// multiple times. The cty.Set will normally de-duplicate values, but we may
+	// have unknown values that would not show as equivalent.
+	seen := map[string]bool{}
+
+	for fullKey := range m {
+		if !strings.HasPrefix(fullKey, prefix) {
+			continue
+		}
+		subKey := fullKey[len(prefix):]
+		if subKey == "#" {
+			// Ignore the "count" key
+			continue
+		}
+		key := fullKey
+		if dot := strings.IndexByte(subKey, '.'); dot != -1 {
+			key = fullKey[:dot+len(prefix)]
+		}
+
+		if seen[key] {
+			continue
+		}
+
+		seen[key] = true
+
+		// The flatmap format doesn't allow us to distinguish between keys
+		// that contain periods and nested objects, so by convention a
+		// map is only ever of primitive type in flatmap, and we just assume
+		// that the remainder of the raw key (dots and all) is the key we
+		// want in the result value.
+
+		val, err := hcl2ValueFromFlatmapValue(m, key, ety)
+		if err != nil {
+			return cty.DynamicVal, err
+		}
+		vals = append(vals, val)
+	}
+
+	if len(vals) == 0 && strCount == "1" {
+		// An empty set wouldn't be represented in the flatmap, so this must be
+		// a single empty object since the count is actually 1.
+		// Add an appropriately typed null value to the set.
+		var val cty.Value
+		switch {
+		case ety.IsMapType():
+			val = cty.MapValEmpty(ety)
+		case ety.IsListType():
+			val = cty.ListValEmpty(ety)
+		case ety.IsSetType():
+			val = cty.SetValEmpty(ety)
+		case ety.IsObjectType():
+			// TODO: cty.ObjectValEmpty
+			objectMap := map[string]cty.Value{}
+			for attr, ty := range ety.AttributeTypes() {
+				objectMap[attr] = cty.NullVal(ty)
+			}
+			val = cty.ObjectVal(objectMap)
+		default:
+			val = cty.NullVal(ety)
+		}
+		vals = append(vals, val)
+
+	} else if len(vals) == 0 {
+		return cty.SetValEmpty(ety), nil
+	}
+
+	return cty.SetVal(vals), nil
+}
diff --git a/v1.5.7/internal/configs/hcl2shim/flatmap_test.go b/v1.5.7/internal/configs/hcl2shim/flatmap_test.go
new file mode 100644
index 0000000..c16be54
--- /dev/null
+++ b/v1.5.7/internal/configs/hcl2shim/flatmap_test.go
@@ -0,0 +1,755 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package hcl2shim
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/go-test/deep"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestFlatmapValueFromHCL2(t *testing.T) {
+	tests := []struct {
+		Value cty.Value
+		Want  map[string]string
+	}{
+		{
+			cty.EmptyObjectVal,
+			map[string]string{},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("hello"),
+			}),
+			map[string]string{
+				"foo": "hello",
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.UnknownVal(cty.Bool),
+			}),
+			map[string]string{
+				"foo": UnknownVariableValue,
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NumberIntVal(12),
+			}),
+			map[string]string{
+				"foo": "12",
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.True,
+				"bar": cty.False,
+			}),
+			map[string]string{
+				"foo": "true",
+				"bar": "false",
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("hello"),
+				"bar": cty.StringVal("world"),
+				"baz": cty.StringVal("whelp"),
+			}),
+			map[string]string{
+				"foo": "hello",
+				"bar": "world",
+				"baz": "whelp",
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListValEmpty(cty.String),
+			}),
+			map[string]string{
+				"foo.#": "0",
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.UnknownVal(cty.List(cty.String)),
+			}),
+			map[string]string{
+				"foo.#": UnknownVariableValue,
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.StringVal("hello"),
+				}),
+			}),
+			map[string]string{
+				"foo.#": "1",
+				"foo.0": "hello",
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.StringVal("hello"),
+					cty.StringVal("world"),
+				}),
+			}),
+			map[string]string{
+				"foo.#": "2",
+				"foo.0": "hello",
+				"foo.1": "world",
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.MapVal(map[string]cty.Value{
+					"hello":       cty.NumberIntVal(12),
+					"hello.world": cty.NumberIntVal(10),
+				}),
+			}),
+			map[string]string{
+				"foo.%":           "2",
+				"foo.hello":       "12",
+				"foo.hello.world": "10",
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.UnknownVal(cty.Map(cty.String)),
+			}),
+			map[string]string{
+				"foo.%": UnknownVariableValue,
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.MapVal(map[string]cty.Value{
+					"hello":       cty.NumberIntVal(12),
+					"hello.world": cty.NumberIntVal(10),
+				}),
+			}),
+			map[string]string{
+				"foo.%":           "2",
+				"foo.hello":       "12",
+				"foo.hello.world": "10",
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.StringVal("hello"),
+					cty.StringVal("world"),
+				}),
+			}),
+			map[string]string{
+				"foo.#": "2",
+				"foo.0": "hello",
+				"foo.1": "world",
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.UnknownVal(cty.Set(cty.Number)),
+			}),
+			map[string]string{
+				"foo.#": UnknownVariableValue,
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("hello"),
+						"baz": cty.StringVal("world"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bloo"),
+						"baz": cty.StringVal("blaa"),
+					}),
+				}),
+			}),
+			map[string]string{
+				"foo.#":     "2",
+				"foo.0.bar": "hello",
+				"foo.0.baz": "world",
+				"foo.1.bar": "bloo",
+				"foo.1.baz": "blaa",
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("hello"),
+						"baz": cty.ListVal([]cty.Value{
+							cty.True,
+							cty.True,
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bloo"),
+						"baz": cty.ListVal([]cty.Value{
+							cty.False,
+							cty.True,
+						}),
+					}),
+				}),
+			}),
+			map[string]string{
+				"foo.#":       "2",
+				"foo.0.bar":   "hello",
+				"foo.0.baz.#": "2",
+				"foo.0.baz.0": "true",
+				"foo.0.baz.1": "true",
+				"foo.1.bar":   "bloo",
+				"foo.1.baz.#": "2",
+				"foo.1.baz.0": "false",
+				"foo.1.baz.1": "true",
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.UnknownVal(cty.Object(map[string]cty.Type{
+						"bar": cty.String,
+						"baz": cty.List(cty.Bool),
+						"bap": cty.Map(cty.Number),
+					})),
+				}),
+			}),
+			map[string]string{
+				"foo.#":       "1",
+				"foo.0.bar":   UnknownVariableValue,
+				"foo.0.baz.#": UnknownVariableValue,
+				"foo.0.bap.%": UnknownVariableValue,
+			},
+		},
+		{
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"foo": cty.Set(cty.Object(map[string]cty.Type{
+					"bar": cty.String,
+				})),
+			})),
+			nil,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Value.GoString(), func(t *testing.T) {
+			got := FlatmapValueFromHCL2(test.Value)
+
+			for _, problem := range deep.Equal(got, test.Want) {
+				t.Error(problem)
+			}
+		})
+	}
+}
+
+func TestFlatmapValueFromHCL2FromFlatmap(t *testing.T) {
+	tests := []struct {
+		Name string
+		Map  map[string]string
+		Type cty.Type
+	}{
+		{
+			"empty flatmap with collections",
+			map[string]string{},
+			cty.Object(map[string]cty.Type{
+				"foo": cty.Map(cty.String),
+				"bar": cty.Set(cty.String),
+			}),
+		},
+		{
+			"nil flatmap with collections",
+			nil,
+			cty.Object(map[string]cty.Type{
+				"foo": cty.Map(cty.String),
+				"bar": cty.Set(cty.String),
+			}),
+		},
+		{
+			"empty flatmap with nested collections",
+			map[string]string{},
+			cty.Object(map[string]cty.Type{
+				"foo": cty.Object(
+					map[string]cty.Type{
+						"baz": cty.Map(cty.String),
+					},
+				),
+				"bar": cty.Set(cty.String),
+			}),
+		},
+		{
+			"partial flatmap with nested collections",
+			map[string]string{
+				"foo.baz.%":   "1",
+				"foo.baz.key": "val",
+			},
+			cty.Object(map[string]cty.Type{
+				"foo": cty.Object(
+					map[string]cty.Type{
+						"baz": cty.Map(cty.String),
+						"biz": cty.Map(cty.String),
+					},
+				),
+				"bar": cty.Set(cty.String),
+			}),
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Name, func(t *testing.T) {
+			val, err := HCL2ValueFromFlatmap(test.Map, test.Type)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			got := FlatmapValueFromHCL2(val)
+
+			for _, problem := range deep.Equal(got, test.Map) {
+				t.Error(problem)
+			}
+		})
+	}
+}
+func TestHCL2ValueFromFlatmap(t *testing.T) {
+	tests := []struct {
+		Flatmap map[string]string
+		Type    cty.Type
+		Want    cty.Value
+		WantErr string
+	}{
+		{
+			Flatmap: map[string]string{},
+			Type:    cty.EmptyObject,
+			Want:    cty.EmptyObjectVal,
+		},
+		{
+			Flatmap: map[string]string{
+				"ignored": "foo",
+			},
+			Type: cty.EmptyObject,
+			Want: cty.EmptyObjectVal,
+		},
+		{
+			Flatmap: map[string]string{
+				"foo": "blah",
+				"bar": "true",
+				"baz": "12.5",
+				"unk": UnknownVariableValue,
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.String,
+				"bar": cty.Bool,
+				"baz": cty.Number,
+				"unk": cty.Bool,
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("blah"),
+				"bar": cty.True,
+				"baz": cty.NumberFloatVal(12.5),
+				"unk": cty.UnknownVal(cty.Bool),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.#": "0",
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.List(cty.String),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListValEmpty(cty.String),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.#": UnknownVariableValue,
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.List(cty.String),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.UnknownVal(cty.List(cty.String)),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.#": "1",
+				"foo.0": "hello",
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.List(cty.String),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.StringVal("hello"),
+				}),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.#": "2",
+				"foo.0": "true",
+				"foo.1": "false",
+				"foo.2": "ignored", // (because the count is 2, so this is out of range)
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.List(cty.Bool),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.True,
+					cty.False,
+				}),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.#": "2",
+				"foo.0": "hello",
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Tuple([]cty.Type{
+					cty.String,
+					cty.Bool,
+				}),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.TupleVal([]cty.Value{
+					cty.StringVal("hello"),
+					cty.NullVal(cty.Bool),
+				}),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.#": UnknownVariableValue,
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Tuple([]cty.Type{
+					cty.String,
+					cty.Bool,
+				}),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.UnknownVal(cty.Tuple([]cty.Type{
+					cty.String,
+					cty.Bool,
+				})),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.#": "0",
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Set(cty.String),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetValEmpty(cty.String),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.#": UnknownVariableValue,
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Set(cty.String),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.UnknownVal(cty.Set(cty.String)),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.#":        "1",
+				"foo.24534534": "hello",
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Set(cty.String),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.StringVal("hello"),
+				}),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.#":        "1",
+				"foo.24534534": "true",
+				"foo.95645644": "true",
+				"foo.34533452": "false",
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Set(cty.Bool),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.True,
+					cty.False,
+				}),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.%": "0",
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Map(cty.String),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.MapValEmpty(cty.String),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.%":       "2",
+				"foo.baz":     "true",
+				"foo.bar.baz": "false",
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Map(cty.Bool),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.MapVal(map[string]cty.Value{
+					"baz":     cty.True,
+					"bar.baz": cty.False,
+				}),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.%": UnknownVariableValue,
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Map(cty.Bool),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.UnknownVal(cty.Map(cty.Bool)),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.#":     "2",
+				"foo.0.bar": "hello",
+				"foo.0.baz": "1",
+				"foo.1.bar": "world",
+				"foo.1.baz": "false",
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.List(cty.Object(map[string]cty.Type{
+					"bar": cty.String,
+					"baz": cty.Bool,
+				})),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("hello"),
+						"baz": cty.True,
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("world"),
+						"baz": cty.False,
+					}),
+				}),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.#":            "2",
+				"foo.34534534.bar": "hello",
+				"foo.34534534.baz": "1",
+				"foo.93453345.bar": "world",
+				"foo.93453345.baz": "false",
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Set(cty.Object(map[string]cty.Type{
+					"bar": cty.String,
+					"baz": cty.Bool,
+				})),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("hello"),
+						"baz": cty.True,
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("world"),
+						"baz": cty.False,
+					}),
+				}),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.#": "not-valid",
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.List(cty.String),
+			}),
+			WantErr: `invalid count value for "foo." in state: strconv.Atoi: parsing "not-valid": invalid syntax`,
+		},
+		{
+			Flatmap: nil,
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Set(cty.Object(map[string]cty.Type{
+					"bar": cty.String,
+				})),
+			}),
+			Want: cty.NullVal(cty.Object(map[string]cty.Type{
+				"foo": cty.Set(cty.Object(map[string]cty.Type{
+					"bar": cty.String,
+				})),
+			})),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.#":   "2",
+				"foo.0.%": "2",
+				"foo.0.a": "a",
+				"foo.0.b": "b",
+				"foo.1.%": "1",
+				"foo.1.a": "a",
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.List(cty.Map(cty.String)),
+			}),
+
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.MapVal(map[string]cty.Value{
+						"a": cty.StringVal("a"),
+						"b": cty.StringVal("b"),
+					}),
+					cty.MapVal(map[string]cty.Value{
+						"a": cty.StringVal("a"),
+					}),
+				}),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"single.#":                 "1",
+				"single.~1.value":          "a",
+				"single.~1.optional":       UnknownVariableValue,
+				"two.#":                    "2",
+				"two.~2381914684.value":    "a",
+				"two.~2381914684.optional": UnknownVariableValue,
+				"two.~2798940671.value":    "b",
+				"two.~2798940671.optional": UnknownVariableValue,
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"single": cty.Set(
+					cty.Object(map[string]cty.Type{
+						"value":    cty.String,
+						"optional": cty.String,
+					}),
+				),
+				"two": cty.Set(
+					cty.Object(map[string]cty.Type{
+						"optional": cty.String,
+						"value":    cty.String,
+					}),
+				),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"single": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"value":    cty.StringVal("a"),
+						"optional": cty.UnknownVal(cty.String),
+					}),
+				}),
+				"two": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"value":    cty.StringVal("a"),
+						"optional": cty.UnknownVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"value":    cty.StringVal("b"),
+						"optional": cty.UnknownVal(cty.String),
+					}),
+				}),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"foo.#": "1",
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Set(cty.Object(map[string]cty.Type{
+					"bar": cty.String,
+				})),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+		},
+		{
+			Flatmap: map[string]string{
+				"multi.#":                "1",
+				"multi.2.set.#":          "1",
+				"multi.2.set.3.required": "val",
+			},
+			Type: cty.Object(map[string]cty.Type{
+				"multi": cty.Set(cty.Object(map[string]cty.Type{
+					"set": cty.Set(cty.Object(map[string]cty.Type{
+						"required": cty.String,
+					})),
+				})),
+			}),
+			Want: cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"set": cty.SetVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"required": cty.StringVal("val"),
+							}),
+						}),
+					}),
+				}),
+			}),
+		},
+	}
+
+	for i, test := range tests {
+		t.Run(fmt.Sprintf("%d %#v as %#v", i, test.Flatmap, test.Type), func(t *testing.T) {
+			got, err := HCL2ValueFromFlatmap(test.Flatmap, test.Type)
+
+			if test.WantErr != "" {
+				if err == nil {
+					t.Fatalf("succeeded; want error: %s", test.WantErr)
+				}
+				if got, want := err.Error(), test.WantErr; got != want {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				if got == cty.NilVal {
+					t.Fatalf("result is cty.NilVal; want valid placeholder value")
+				}
+				return
+			} else {
+				if err != nil {
+					t.Fatalf("unexpected error: %s", err.Error())
+				}
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/configs/hcl2shim/paths.go b/v1.5.7/internal/configs/hcl2shim/paths.go
new file mode 100644
index 0000000..3ae21bb
--- /dev/null
+++ b/v1.5.7/internal/configs/hcl2shim/paths.go
@@ -0,0 +1,279 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package hcl2shim
+
+import (
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+// RequiresReplace takes a list of flatmapped paths from a
+// InstanceDiff.Attributes along with the corresponding cty.Type, and returns
+// the list of the cty.Paths that are flagged as causing the resource
+// replacement (RequiresNew).
+// This will filter out redundant paths, paths that refer to flatmapped indexes
+// (e.g. "#", "%"), and will return any changes within a set as the path to the
+// set itself.
+func RequiresReplace(attrs []string, ty cty.Type) ([]cty.Path, error) {
+	var paths []cty.Path
+
+	for _, attr := range attrs {
+		p, err := requiresReplacePath(attr, ty)
+		if err != nil {
+			return nil, err
+		}
+
+		paths = append(paths, p)
+	}
+
+	// now trim off any trailing paths that aren't GetAttrSteps, since only an
+	// attribute itself can require replacement
+	paths = trimPaths(paths)
+
+	// There may be redundant paths due to set elements or index attributes
+	// Do some ugly n^2 filtering, but these are always fairly small sets.
+	for i := 0; i < len(paths)-1; i++ {
+		for j := i + 1; j < len(paths); j++ {
+			if reflect.DeepEqual(paths[i], paths[j]) {
+				// swap the tail and slice it off
+				paths[j], paths[len(paths)-1] = paths[len(paths)-1], paths[j]
+				paths = paths[:len(paths)-1]
+				j--
+			}
+		}
+	}
+
+	return paths, nil
+}
+
+// trimPaths removes any trailing steps that aren't of type GetAttrSet, since
+// only an attribute itself can require replacement
+func trimPaths(paths []cty.Path) []cty.Path {
+	var trimmed []cty.Path
+	for _, path := range paths {
+		path = trimPath(path)
+		if len(path) > 0 {
+			trimmed = append(trimmed, path)
+		}
+	}
+	return trimmed
+}
+
+func trimPath(path cty.Path) cty.Path {
+	for len(path) > 0 {
+		_, isGetAttr := path[len(path)-1].(cty.GetAttrStep)
+		if isGetAttr {
+			break
+		}
+		path = path[:len(path)-1]
+	}
+	return path
+}
+
+// requiresReplacePath takes a key from a flatmap along with the cty.Type
+// describing the structure, and returns the cty.Path that would be used to
+// reference the nested value in the data structure.
+// This is used specifically to record the RequiresReplace attributes from a
+// ResourceInstanceDiff.
+func requiresReplacePath(k string, ty cty.Type) (cty.Path, error) {
+	if k == "" {
+		return nil, nil
+	}
+	if !ty.IsObjectType() {
+		panic(fmt.Sprintf("requires replace path on non-object type: %#v", ty))
+	}
+
+	path, err := pathFromFlatmapKeyObject(k, ty.AttributeTypes())
+	if err != nil {
+		return path, fmt.Errorf("[%s] %s", k, err)
+	}
+	return path, nil
+}
+
+func pathSplit(p string) (string, string) {
+	parts := strings.SplitN(p, ".", 2)
+	head := parts[0]
+	rest := ""
+	if len(parts) > 1 {
+		rest = parts[1]
+	}
+	return head, rest
+}
+
+func pathFromFlatmapKeyObject(key string, atys map[string]cty.Type) (cty.Path, error) {
+	k, rest := pathSplit(key)
+
+	path := cty.Path{cty.GetAttrStep{Name: k}}
+
+	ty, ok := atys[k]
+	if !ok {
+		return path, fmt.Errorf("attribute %q not found", k)
+	}
+
+	if rest == "" {
+		return path, nil
+	}
+
+	p, err := pathFromFlatmapKeyValue(rest, ty)
+	if err != nil {
+		return path, err
+	}
+
+	return append(path, p...), nil
+}
+
+func pathFromFlatmapKeyValue(key string, ty cty.Type) (cty.Path, error) {
+	var path cty.Path
+	var err error
+
+	switch {
+	case ty.IsPrimitiveType():
+		err = fmt.Errorf("invalid step %q with type %#v", key, ty)
+	case ty.IsObjectType():
+		path, err = pathFromFlatmapKeyObject(key, ty.AttributeTypes())
+	case ty.IsTupleType():
+		path, err = pathFromFlatmapKeyTuple(key, ty.TupleElementTypes())
+	case ty.IsMapType():
+		path, err = pathFromFlatmapKeyMap(key, ty)
+	case ty.IsListType():
+		path, err = pathFromFlatmapKeyList(key, ty)
+	case ty.IsSetType():
+		path, err = pathFromFlatmapKeySet(key, ty)
+	default:
+		err = fmt.Errorf("unrecognized type: %s", ty.FriendlyName())
+	}
+
+	if err != nil {
+		return path, err
+	}
+
+	return path, nil
+}
+
+func pathFromFlatmapKeyTuple(key string, etys []cty.Type) (cty.Path, error) {
+	var path cty.Path
+	var err error
+
+	k, rest := pathSplit(key)
+
+	// we don't need to convert the index keys to paths
+	if k == "#" {
+		return path, nil
+	}
+
+	idx, err := strconv.Atoi(k)
+	if err != nil {
+		return path, err
+	}
+
+	path = cty.Path{cty.IndexStep{Key: cty.NumberIntVal(int64(idx))}}
+
+	if idx >= len(etys) {
+		return path, fmt.Errorf("index %s out of range in %#v", key, etys)
+	}
+
+	if rest == "" {
+		return path, nil
+	}
+
+	ty := etys[idx]
+
+	p, err := pathFromFlatmapKeyValue(rest, ty.ElementType())
+	if err != nil {
+		return path, err
+	}
+
+	return append(path, p...), nil
+}
+
+func pathFromFlatmapKeyMap(key string, ty cty.Type) (cty.Path, error) {
+	var path cty.Path
+	var err error
+
+	k, rest := key, ""
+	if !ty.ElementType().IsPrimitiveType() {
+		k, rest = pathSplit(key)
+	}
+
+	// we don't need to convert the index keys to paths
+	if k == "%" {
+		return path, nil
+	}
+
+	path = cty.Path{cty.IndexStep{Key: cty.StringVal(k)}}
+
+	if rest == "" {
+		return path, nil
+	}
+
+	p, err := pathFromFlatmapKeyValue(rest, ty.ElementType())
+	if err != nil {
+		return path, err
+	}
+
+	return append(path, p...), nil
+}
+
+func pathFromFlatmapKeyList(key string, ty cty.Type) (cty.Path, error) {
+	var path cty.Path
+	var err error
+
+	k, rest := pathSplit(key)
+
+	// we don't need to convert the index keys to paths
+	if key == "#" {
+		return path, nil
+	}
+
+	idx, err := strconv.Atoi(k)
+	if err != nil {
+		return path, err
+	}
+
+	path = cty.Path{cty.IndexStep{Key: cty.NumberIntVal(int64(idx))}}
+
+	if rest == "" {
+		return path, nil
+	}
+
+	p, err := pathFromFlatmapKeyValue(rest, ty.ElementType())
+	if err != nil {
+		return path, err
+	}
+
+	return append(path, p...), nil
+}
+
+func pathFromFlatmapKeySet(key string, ty cty.Type) (cty.Path, error) {
+	// once we hit a set, we can't return consistent paths, so just mark the
+	// set as a whole changed.
+	return nil, nil
+}
+
+// FlatmapKeyFromPath returns the flatmap equivalent of the given cty.Path for
+// use in generating legacy style diffs.
+func FlatmapKeyFromPath(path cty.Path) string {
+	var parts []string
+
+	for _, step := range path {
+		switch step := step.(type) {
+		case cty.GetAttrStep:
+			parts = append(parts, step.Name)
+		case cty.IndexStep:
+			switch ty := step.Key.Type(); {
+			case ty == cty.String:
+				parts = append(parts, step.Key.AsString())
+			case ty == cty.Number:
+				i, _ := step.Key.AsBigFloat().Int64()
+				parts = append(parts, strconv.Itoa(int(i)))
+			}
+		}
+	}
+
+	return strings.Join(parts, ".")
+}
diff --git a/v1.5.7/internal/configs/hcl2shim/paths_test.go b/v1.5.7/internal/configs/hcl2shim/paths_test.go
new file mode 100644
index 0000000..00fb987
--- /dev/null
+++ b/v1.5.7/internal/configs/hcl2shim/paths_test.go
@@ -0,0 +1,411 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package hcl2shim
+
+import (
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp/cmpopts"
+
+	"github.com/google/go-cmp/cmp"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+var (
+	ignoreUnexported = cmpopts.IgnoreUnexported(cty.GetAttrStep{}, cty.IndexStep{})
+	valueComparer    = cmp.Comparer(cty.Value.RawEquals)
+)
+
+func TestPathFromFlatmap(t *testing.T) {
+	tests := []struct {
+		Flatmap string
+		Type    cty.Type
+		Want    cty.Path
+		WantErr string
+	}{
+		{
+			Flatmap: "",
+			Type:    cty.EmptyObject,
+			Want:    nil,
+		},
+		{
+			Flatmap: "attr",
+			Type:    cty.EmptyObject,
+			Want:    nil,
+			WantErr: `attribute "attr" not found`,
+		},
+		{
+			Flatmap: "foo",
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.String,
+			}),
+			Want: cty.Path{
+				cty.GetAttrStep{Name: "foo"},
+			},
+		},
+		{
+			Flatmap: "foo.#",
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.List(cty.String),
+			}),
+			Want: cty.Path{
+				cty.GetAttrStep{Name: "foo"},
+			},
+		},
+		{
+			Flatmap: "foo.1",
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.List(cty.String),
+			}),
+			Want: cty.Path{
+				cty.GetAttrStep{Name: "foo"},
+				cty.IndexStep{Key: cty.NumberIntVal(1)},
+			},
+		},
+		{
+			Flatmap: "foo.1",
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Tuple([]cty.Type{
+					cty.String,
+					cty.Bool,
+				}),
+			}),
+			Want: cty.Path{
+				cty.GetAttrStep{Name: "foo"},
+				cty.IndexStep{Key: cty.NumberIntVal(1)},
+			},
+		},
+		{
+			// a set index returns the set itself, since this being applied to
+			// a diff and the set is changing.
+			Flatmap: "foo.24534534",
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Set(cty.String),
+			}),
+			Want: cty.Path{
+				cty.GetAttrStep{Name: "foo"},
+			},
+		},
+		{
+			Flatmap: "foo.%",
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Map(cty.String),
+			}),
+			Want: cty.Path{
+				cty.GetAttrStep{Name: "foo"},
+			},
+		},
+		{
+			Flatmap: "foo.baz",
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Map(cty.Bool),
+			}),
+			Want: cty.Path{
+				cty.GetAttrStep{Name: "foo"},
+				cty.IndexStep{Key: cty.StringVal("baz")},
+			},
+		},
+		{
+			Flatmap: "foo.bar.baz",
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Map(
+					cty.Map(cty.Bool),
+				),
+			}),
+			Want: cty.Path{
+				cty.GetAttrStep{Name: "foo"},
+				cty.IndexStep{Key: cty.StringVal("bar")},
+				cty.IndexStep{Key: cty.StringVal("baz")},
+			},
+		},
+		{
+			Flatmap: "foo.bar.baz",
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Map(
+					cty.Object(map[string]cty.Type{
+						"baz": cty.String,
+					}),
+				),
+			}),
+			Want: cty.Path{
+				cty.GetAttrStep{Name: "foo"},
+				cty.IndexStep{Key: cty.StringVal("bar")},
+				cty.GetAttrStep{Name: "baz"},
+			},
+		},
+		{
+			Flatmap: "foo.0.bar",
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.List(cty.Object(map[string]cty.Type{
+					"bar": cty.String,
+					"baz": cty.Bool,
+				})),
+			}),
+			Want: cty.Path{
+				cty.GetAttrStep{Name: "foo"},
+				cty.IndexStep{Key: cty.NumberIntVal(0)},
+				cty.GetAttrStep{Name: "bar"},
+			},
+		},
+		{
+			Flatmap: "foo.34534534.baz",
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Set(cty.Object(map[string]cty.Type{
+					"bar": cty.String,
+					"baz": cty.Bool,
+				})),
+			}),
+			Want: cty.Path{
+				cty.GetAttrStep{Name: "foo"},
+			},
+		},
+		{
+			Flatmap: "foo.bar.bang",
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.String,
+			}),
+			WantErr: `invalid step "bar.bang"`,
+		},
+		{
+			// there should not be any attribute names with dots
+			Flatmap: "foo.bar.bang",
+			Type: cty.Object(map[string]cty.Type{
+				"foo.bar": cty.Map(cty.String),
+			}),
+			WantErr: `attribute "foo" not found`,
+		},
+		{
+			// We can only handle key names with dots if the map elements are a
+			// primitive type.
+			Flatmap: "foo.bar.bop",
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Map(cty.String),
+			}),
+			Want: cty.Path{
+				cty.GetAttrStep{Name: "foo"},
+				cty.IndexStep{Key: cty.StringVal("bar.bop")},
+			},
+		},
+		{
+			Flatmap: "foo.bar.0.baz",
+			Type: cty.Object(map[string]cty.Type{
+				"foo": cty.Map(
+					cty.List(
+						cty.Map(cty.String),
+					),
+				),
+			}),
+			Want: cty.Path{
+				cty.GetAttrStep{Name: "foo"},
+				cty.IndexStep{Key: cty.StringVal("bar")},
+				cty.IndexStep{Key: cty.NumberIntVal(0)},
+				cty.IndexStep{Key: cty.StringVal("baz")},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%s as %#v", test.Flatmap, test.Type), func(t *testing.T) {
+			got, err := requiresReplacePath(test.Flatmap, test.Type)
+
+			if test.WantErr != "" {
+				if err == nil {
+					t.Fatalf("succeeded; want error: %s", test.WantErr)
+				}
+				if got, want := err.Error(), test.WantErr; !strings.Contains(got, want) {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			} else {
+				if err != nil {
+					t.Fatalf("unexpected error: %s", err.Error())
+				}
+			}
+
+			if !reflect.DeepEqual(got, test.Want) {
+				t.Fatalf("incorrect path\ngot:  %#v\nwant: %#v\n", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestRequiresReplace(t *testing.T) {
+	for _, tc := range []struct {
+		name     string
+		attrs    []string
+		expected []cty.Path
+		ty       cty.Type
+	}{
+		{
+			name: "basic",
+			attrs: []string{
+				"foo",
+			},
+			ty: cty.Object(map[string]cty.Type{
+				"foo": cty.String,
+			}),
+			expected: []cty.Path{
+				cty.Path{cty.GetAttrStep{Name: "foo"}},
+			},
+		},
+		{
+			name: "two",
+			attrs: []string{
+				"foo",
+				"bar",
+			},
+			ty: cty.Object(map[string]cty.Type{
+				"foo": cty.String,
+				"bar": cty.String,
+			}),
+			expected: []cty.Path{
+				cty.Path{cty.GetAttrStep{Name: "foo"}},
+				cty.Path{cty.GetAttrStep{Name: "bar"}},
+			},
+		},
+		{
+			name: "nested object",
+			attrs: []string{
+				"foo.bar",
+			},
+			ty: cty.Object(map[string]cty.Type{
+				"foo": cty.Object(map[string]cty.Type{
+					"bar": cty.String,
+				}),
+			}),
+			expected: []cty.Path{
+				cty.Path{cty.GetAttrStep{Name: "foo"}, cty.GetAttrStep{Name: "bar"}},
+			},
+		},
+		{
+			name: "nested objects",
+			attrs: []string{
+				"foo.bar.baz",
+			},
+			ty: cty.Object(map[string]cty.Type{
+				"foo": cty.Object(map[string]cty.Type{
+					"bar": cty.Object(map[string]cty.Type{
+						"baz": cty.String,
+					}),
+				}),
+			}),
+			expected: []cty.Path{
+				cty.Path{cty.GetAttrStep{Name: "foo"}, cty.GetAttrStep{Name: "bar"}, cty.GetAttrStep{Name: "baz"}},
+			},
+		},
+		{
+			name: "nested map",
+			attrs: []string{
+				"foo.%",
+				"foo.bar",
+			},
+			ty: cty.Object(map[string]cty.Type{
+				"foo": cty.Map(cty.String),
+			}),
+			expected: []cty.Path{
+				cty.Path{cty.GetAttrStep{Name: "foo"}},
+			},
+		},
+		{
+			name: "nested list",
+			attrs: []string{
+				"foo.#",
+				"foo.1",
+			},
+			ty: cty.Object(map[string]cty.Type{
+				"foo": cty.Map(cty.String),
+			}),
+			expected: []cty.Path{
+				cty.Path{cty.GetAttrStep{Name: "foo"}},
+			},
+		},
+		{
+			name: "object in map",
+			attrs: []string{
+				"foo.bar.baz",
+			},
+			ty: cty.Object(map[string]cty.Type{
+				"foo": cty.Map(cty.Object(
+					map[string]cty.Type{
+						"baz": cty.String,
+					},
+				)),
+			}),
+			expected: []cty.Path{
+				cty.Path{cty.GetAttrStep{Name: "foo"}, cty.IndexStep{Key: cty.StringVal("bar")}, cty.GetAttrStep{Name: "baz"}},
+			},
+		},
+		{
+			name: "object in list",
+			attrs: []string{
+				"foo.1.baz",
+			},
+			ty: cty.Object(map[string]cty.Type{
+				"foo": cty.List(cty.Object(
+					map[string]cty.Type{
+						"baz": cty.String,
+					},
+				)),
+			}),
+			expected: []cty.Path{
+				cty.Path{cty.GetAttrStep{Name: "foo"}, cty.IndexStep{Key: cty.NumberIntVal(1)}, cty.GetAttrStep{Name: "baz"}},
+			},
+		},
+	} {
+		t.Run(tc.name, func(t *testing.T) {
+			rp, err := RequiresReplace(tc.attrs, tc.ty)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if !cmp.Equal(tc.expected, rp, ignoreUnexported, valueComparer) {
+				t.Fatalf("\nexpected: %#v\ngot: %#v\n", tc.expected, rp)
+			}
+		})
+
+	}
+}
+
+func TestFlatmapKeyFromPath(t *testing.T) {
+	for i, tc := range []struct {
+		path cty.Path
+		attr string
+	}{
+		{
+			path: cty.Path{
+				cty.GetAttrStep{Name: "force_new"},
+			},
+			attr: "force_new",
+		},
+		{
+			path: cty.Path{
+				cty.GetAttrStep{Name: "attr"},
+				cty.IndexStep{Key: cty.NumberIntVal(0)},
+				cty.GetAttrStep{Name: "force_new"},
+			},
+			attr: "attr.0.force_new",
+		},
+		{
+			path: cty.Path{
+				cty.GetAttrStep{Name: "attr"},
+				cty.IndexStep{Key: cty.StringVal("key")},
+				cty.GetAttrStep{Name: "obj_attr"},
+				cty.IndexStep{Key: cty.NumberIntVal(0)},
+				cty.GetAttrStep{Name: "force_new"},
+			},
+			attr: "attr.key.obj_attr.0.force_new",
+		},
+	} {
+		t.Run(strconv.Itoa(i), func(t *testing.T) {
+			attr := FlatmapKeyFromPath(tc.path)
+			if attr != tc.attr {
+				t.Fatalf("expected:%q got:%q", tc.attr, attr)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/configs/hcl2shim/single_attr_body.go b/v1.5.7/internal/configs/hcl2shim/single_attr_body.go
new file mode 100644
index 0000000..c025fa7
--- /dev/null
+++ b/v1.5.7/internal/configs/hcl2shim/single_attr_body.go
@@ -0,0 +1,88 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package hcl2shim
+
+import (
+	"fmt"
+
+	hcl2 "github.com/hashicorp/hcl/v2"
+)
+
+// SingleAttrBody is a weird implementation of hcl2.Body that acts as if
+// it has a single attribute whose value is the given expression.
+//
+// This is used to shim Resource.RawCount and Output.RawConfig to behave
+// more like they do in the old HCL loader.
+type SingleAttrBody struct {
+	Name string
+	Expr hcl2.Expression
+}
+
+var _ hcl2.Body = SingleAttrBody{}
+
+func (b SingleAttrBody) Content(schema *hcl2.BodySchema) (*hcl2.BodyContent, hcl2.Diagnostics) {
+	content, all, diags := b.content(schema)
+	if !all {
+		// This should never happen because this body implementation should only
+		// be used by code that is aware that it's using a single-attr body.
+		diags = append(diags, &hcl2.Diagnostic{
+			Severity: hcl2.DiagError,
+			Summary:  "Invalid attribute",
+			Detail:   fmt.Sprintf("The correct attribute name is %q.", b.Name),
+			Subject:  b.Expr.Range().Ptr(),
+		})
+	}
+	return content, diags
+}
+
+func (b SingleAttrBody) PartialContent(schema *hcl2.BodySchema) (*hcl2.BodyContent, hcl2.Body, hcl2.Diagnostics) {
+	content, all, diags := b.content(schema)
+	var remain hcl2.Body
+	if all {
+		// If the request matched the one attribute we represent, then the
+		// remaining body is empty.
+		remain = hcl2.EmptyBody()
+	} else {
+		remain = b
+	}
+	return content, remain, diags
+}
+
+func (b SingleAttrBody) content(schema *hcl2.BodySchema) (*hcl2.BodyContent, bool, hcl2.Diagnostics) {
+	ret := &hcl2.BodyContent{}
+	all := false
+	var diags hcl2.Diagnostics
+
+	for _, attrS := range schema.Attributes {
+		if attrS.Name == b.Name {
+			attrs, _ := b.JustAttributes()
+			ret.Attributes = attrs
+			all = true
+		} else if attrS.Required {
+			diags = append(diags, &hcl2.Diagnostic{
+				Severity: hcl2.DiagError,
+				Summary:  "Missing attribute",
+				Detail:   fmt.Sprintf("The attribute %q is required.", attrS.Name),
+				Subject:  b.Expr.Range().Ptr(),
+			})
+		}
+	}
+
+	return ret, all, diags
+}
+
+func (b SingleAttrBody) JustAttributes() (hcl2.Attributes, hcl2.Diagnostics) {
+	return hcl2.Attributes{
+		b.Name: {
+			Expr:      b.Expr,
+			Name:      b.Name,
+			NameRange: b.Expr.Range(),
+			Range:     b.Expr.Range(),
+		},
+	}, nil
+}
+
+func (b SingleAttrBody) MissingItemRange() hcl2.Range {
+	return b.Expr.Range()
+}
diff --git a/v1.5.7/internal/configs/hcl2shim/values.go b/v1.5.7/internal/configs/hcl2shim/values.go
new file mode 100644
index 0000000..9430a65
--- /dev/null
+++ b/v1.5.7/internal/configs/hcl2shim/values.go
@@ -0,0 +1,233 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package hcl2shim
+
+import (
+	"fmt"
+	"math/big"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+// UnknownVariableValue is a sentinel value that can be used
+// to denote that the value of a variable is unknown at this time.
+// RawConfig uses this information to build up data about
+// unknown keys.
+const UnknownVariableValue = "74D93920-ED26-11E3-AC10-0800200C9A66"
+
+// ConfigValueFromHCL2Block is like ConfigValueFromHCL2 but it works only for
+// known object values and uses the provided block schema to perform some
+// additional normalization to better mimic the shape of value that the old
+// HCL1/HIL-based codepaths would've produced.
+//
+// In particular, it discards the collections that we use to represent nested
+// blocks (other than NestingSingle) if they are empty, which better mimics
+// the HCL1 behavior because HCL1 had no knowledge of the schema and so didn't
+// know that an unspecified block _could_ exist.
+//
+// The given object value must conform to the schema's implied type or this
+// function will panic or produce incorrect results.
+//
+// This is primarily useful for the final transition from new-style values to
+// terraform.ResourceConfig before calling to a legacy provider, since
+// helper/schema (the old provider SDK) is particularly sensitive to these
+// subtle differences within its validation code.
+func ConfigValueFromHCL2Block(v cty.Value, schema *configschema.Block) map[string]interface{} {
+	if v.IsNull() {
+		return nil
+	}
+	if !v.IsKnown() {
+		panic("ConfigValueFromHCL2Block used with unknown value")
+	}
+	if !v.Type().IsObjectType() {
+		panic(fmt.Sprintf("ConfigValueFromHCL2Block used with non-object value %#v", v))
+	}
+
+	atys := v.Type().AttributeTypes()
+	ret := make(map[string]interface{})
+
+	for name := range schema.Attributes {
+		if _, exists := atys[name]; !exists {
+			continue
+		}
+
+		av := v.GetAttr(name)
+		if av.IsNull() {
+			// Skip nulls altogether, to better mimic how HCL1 would behave
+			continue
+		}
+		ret[name] = ConfigValueFromHCL2(av)
+	}
+
+	for name, blockS := range schema.BlockTypes {
+		if _, exists := atys[name]; !exists {
+			continue
+		}
+		bv := v.GetAttr(name)
+		if !bv.IsKnown() {
+			ret[name] = UnknownVariableValue
+			continue
+		}
+		if bv.IsNull() {
+			continue
+		}
+
+		switch blockS.Nesting {
+
+		case configschema.NestingSingle, configschema.NestingGroup:
+			ret[name] = ConfigValueFromHCL2Block(bv, &blockS.Block)
+
+		case configschema.NestingList, configschema.NestingSet:
+			l := bv.LengthInt()
+			if l == 0 {
+				// skip empty collections to better mimic how HCL1 would behave
+				continue
+			}
+
+			elems := make([]interface{}, 0, l)
+			for it := bv.ElementIterator(); it.Next(); {
+				_, ev := it.Element()
+				if !ev.IsKnown() {
+					elems = append(elems, UnknownVariableValue)
+					continue
+				}
+				elems = append(elems, ConfigValueFromHCL2Block(ev, &blockS.Block))
+			}
+			ret[name] = elems
+
+		case configschema.NestingMap:
+			if bv.LengthInt() == 0 {
+				// skip empty collections to better mimic how HCL1 would behave
+				continue
+			}
+
+			elems := make(map[string]interface{})
+			for it := bv.ElementIterator(); it.Next(); {
+				ek, ev := it.Element()
+				if !ev.IsKnown() {
+					elems[ek.AsString()] = UnknownVariableValue
+					continue
+				}
+				elems[ek.AsString()] = ConfigValueFromHCL2Block(ev, &blockS.Block)
+			}
+			ret[name] = elems
+		}
+	}
+
+	return ret
+}
+
+// ConfigValueFromHCL2 converts a value from HCL2 (really, from the cty dynamic
+// types library that HCL2 uses) to a value type that matches what would've
+// been produced from the HCL-based interpolator for an equivalent structure.
+//
+// This function will transform a cty null value into a Go nil value, which
+// isn't a possible outcome of the HCL/HIL-based decoder and so callers may
+// need to detect and reject any null values.
+func ConfigValueFromHCL2(v cty.Value) interface{} {
+	if !v.IsKnown() {
+		return UnknownVariableValue
+	}
+	if v.IsNull() {
+		return nil
+	}
+
+	switch v.Type() {
+	case cty.Bool:
+		return v.True() // like HCL.BOOL
+	case cty.String:
+		return v.AsString() // like HCL token.STRING or token.HEREDOC
+	case cty.Number:
+		// We can't match HCL _exactly_ here because it distinguishes between
+		// int and float values, but we'll get as close as we can by using
+		// an int if the number is exactly representable, and a float if not.
+		// The conversion to float will force precision to that of a float64,
+		// which is potentially losing information from the specific number
+		// given, but no worse than what HCL would've done in its own conversion
+		// to float.
+
+		f := v.AsBigFloat()
+		if i, acc := f.Int64(); acc == big.Exact {
+			// if we're on a 32-bit system and the number is too big for 32-bit
+			// int then we'll fall through here and use a float64.
+			const MaxInt = int(^uint(0) >> 1)
+			const MinInt = -MaxInt - 1
+			if i <= int64(MaxInt) && i >= int64(MinInt) {
+				return int(i) // Like HCL token.NUMBER
+			}
+		}
+
+		f64, _ := f.Float64()
+		return f64 // like HCL token.FLOAT
+	}
+
+	if v.Type().IsListType() || v.Type().IsSetType() || v.Type().IsTupleType() {
+		l := make([]interface{}, 0, v.LengthInt())
+		it := v.ElementIterator()
+		for it.Next() {
+			_, ev := it.Element()
+			l = append(l, ConfigValueFromHCL2(ev))
+		}
+		return l
+	}
+
+	if v.Type().IsMapType() || v.Type().IsObjectType() {
+		l := make(map[string]interface{})
+		it := v.ElementIterator()
+		for it.Next() {
+			ek, ev := it.Element()
+			cv := ConfigValueFromHCL2(ev)
+			if cv != nil {
+				l[ek.AsString()] = cv
+			}
+		}
+		return l
+	}
+
+	// If we fall out here then we have some weird type that we haven't
+	// accounted for. This should never happen unless the caller is using
+	// capsule types, and we don't currently have any such types defined.
+	panic(fmt.Errorf("can't convert %#v to config value", v))
+}
+
+// HCL2ValueFromConfigValue is the opposite of configValueFromHCL2: it takes
+// a value as would be returned from the old interpolator and turns it into
+// a cty.Value so it can be used within, for example, an HCL2 EvalContext.
+func HCL2ValueFromConfigValue(v interface{}) cty.Value {
+	if v == nil {
+		return cty.NullVal(cty.DynamicPseudoType)
+	}
+	if v == UnknownVariableValue {
+		return cty.DynamicVal
+	}
+
+	switch tv := v.(type) {
+	case bool:
+		return cty.BoolVal(tv)
+	case string:
+		return cty.StringVal(tv)
+	case int:
+		return cty.NumberIntVal(int64(tv))
+	case float64:
+		return cty.NumberFloatVal(tv)
+	case []interface{}:
+		vals := make([]cty.Value, len(tv))
+		for i, ev := range tv {
+			vals[i] = HCL2ValueFromConfigValue(ev)
+		}
+		return cty.TupleVal(vals)
+	case map[string]interface{}:
+		vals := map[string]cty.Value{}
+		for k, ev := range tv {
+			vals[k] = HCL2ValueFromConfigValue(ev)
+		}
+		return cty.ObjectVal(vals)
+	default:
+		// HCL/HIL should never generate anything that isn't caught by
+		// the above, so if we get here something has gone very wrong.
+		panic(fmt.Errorf("can't convert %#v to cty.Value", v))
+	}
+}
diff --git a/v1.5.7/internal/configs/hcl2shim/values_equiv.go b/v1.5.7/internal/configs/hcl2shim/values_equiv.go
new file mode 100644
index 0000000..cf5b269
--- /dev/null
+++ b/v1.5.7/internal/configs/hcl2shim/values_equiv.go
@@ -0,0 +1,217 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package hcl2shim
+
+import (
+	"github.com/zclconf/go-cty/cty"
+)
+
+// ValuesSDKEquivalent returns true if both of the given values seem equivalent
+// as far as the legacy SDK diffing code would be concerned.
+//
+// Since SDK diffing is a fuzzy, inexact operation, this function is also
+// fuzzy and inexact. It will err on the side of returning false if it
+// encounters an ambiguous situation. Ambiguity is most common in the presence
+// of sets because in practice it is impossible to exactly correlate
+// nonequal-but-equivalent set elements because they have no identity separate
+// from their value.
+//
+// This must be used _only_ for comparing values for equivalence within the
+// SDK planning code. It is only meaningful to compare the "prior state"
+// provided by Terraform Core with the "planned new state" produced by the
+// legacy SDK code via shims. In particular it is not valid to use this
+// function with their the config value or the "proposed new state" value
+// because they contain only the subset of data that Terraform Core itself is
+// able to determine.
+func ValuesSDKEquivalent(a, b cty.Value) bool {
+	if a == cty.NilVal || b == cty.NilVal {
+		// We don't generally expect nils to appear, but we'll allow them
+		// for robustness since the data structures produced by legacy SDK code
+		// can sometimes be non-ideal.
+		return a == b // equivalent if they are _both_ nil
+	}
+	if a.RawEquals(b) {
+		// Easy case. We use RawEquals because we want two unknowns to be
+		// considered equal here, whereas "Equals" would return unknown.
+		return true
+	}
+	if !a.IsKnown() || !b.IsKnown() {
+		// Two unknown values are equivalent regardless of type. A known is
+		// never equivalent to an unknown.
+		return a.IsKnown() == b.IsKnown()
+	}
+	if aZero, bZero := valuesSDKEquivalentIsNullOrZero(a), valuesSDKEquivalentIsNullOrZero(b); aZero || bZero {
+		// Two null/zero values are equivalent regardless of type. A non-zero is
+		// never equivalent to a zero.
+		return aZero == bZero
+	}
+
+	// If we get down here then we are guaranteed that both a and b are known,
+	// non-null values.
+
+	aTy := a.Type()
+	bTy := b.Type()
+	switch {
+	case aTy.IsSetType() && bTy.IsSetType():
+		return valuesSDKEquivalentSets(a, b)
+	case aTy.IsListType() && bTy.IsListType():
+		return valuesSDKEquivalentSequences(a, b)
+	case aTy.IsTupleType() && bTy.IsTupleType():
+		return valuesSDKEquivalentSequences(a, b)
+	case aTy.IsMapType() && bTy.IsMapType():
+		return valuesSDKEquivalentMappings(a, b)
+	case aTy.IsObjectType() && bTy.IsObjectType():
+		return valuesSDKEquivalentMappings(a, b)
+	case aTy == cty.Number && bTy == cty.Number:
+		return valuesSDKEquivalentNumbers(a, b)
+	default:
+		// We've now covered all the interesting cases, so anything that falls
+		// down here cannot be equivalent.
+		return false
+	}
+}
+
+// valuesSDKEquivalentIsNullOrZero returns true if the given value is either
+// null or is the "zero value" (in the SDK/Go sense) for its type.
+func valuesSDKEquivalentIsNullOrZero(v cty.Value) bool {
+	if v == cty.NilVal {
+		return true
+	}
+
+	ty := v.Type()
+	switch {
+	case !v.IsKnown():
+		return false
+	case v.IsNull():
+		return true
+
+	// After this point, v is always known and non-null
+	case ty.IsListType() || ty.IsSetType() || ty.IsMapType() || ty.IsObjectType() || ty.IsTupleType():
+		return v.LengthInt() == 0
+	case ty == cty.String:
+		return v.RawEquals(cty.StringVal(""))
+	case ty == cty.Number:
+		return v.RawEquals(cty.Zero)
+	case ty == cty.Bool:
+		return v.RawEquals(cty.False)
+	default:
+		// The above is exhaustive, but for robustness we'll consider anything
+		// else to _not_ be zero unless it is null.
+		return false
+	}
+}
+
+// valuesSDKEquivalentSets returns true only if each of the elements in a can
+// be correlated with at least one equivalent element in b and vice-versa.
+// This is a fuzzy operation that prefers to signal non-equivalence if it cannot
+// be certain that all elements are accounted for.
+func valuesSDKEquivalentSets(a, b cty.Value) bool {
+	if aLen, bLen := a.LengthInt(), b.LengthInt(); aLen != bLen {
+		return false
+	}
+
+	// Our methodology here is a little tricky, to deal with the fact that
+	// it's impossible to directly correlate two non-equal set elements because
+	// they don't have identities separate from their values.
+	// The approach is to count the number of equivalent elements each element
+	// of a has in b and vice-versa, and then return true only if each element
+	// in both sets has at least one equivalent.
+	as := a.AsValueSlice()
+	bs := b.AsValueSlice()
+	aeqs := make([]bool, len(as))
+	beqs := make([]bool, len(bs))
+	for ai, av := range as {
+		for bi, bv := range bs {
+			if ValuesSDKEquivalent(av, bv) {
+				aeqs[ai] = true
+				beqs[bi] = true
+			}
+		}
+	}
+
+	for _, eq := range aeqs {
+		if !eq {
+			return false
+		}
+	}
+	for _, eq := range beqs {
+		if !eq {
+			return false
+		}
+	}
+	return true
+}
+
+// valuesSDKEquivalentSequences decides equivalence for two sequence values
+// (lists or tuples).
+func valuesSDKEquivalentSequences(a, b cty.Value) bool {
+	as := a.AsValueSlice()
+	bs := b.AsValueSlice()
+	if len(as) != len(bs) {
+		return false
+	}
+
+	for i := range as {
+		if !ValuesSDKEquivalent(as[i], bs[i]) {
+			return false
+		}
+	}
+	return true
+}
+
+// valuesSDKEquivalentMappings decides equivalence for two mapping values
+// (maps or objects).
+func valuesSDKEquivalentMappings(a, b cty.Value) bool {
+	as := a.AsValueMap()
+	bs := b.AsValueMap()
+	if len(as) != len(bs) {
+		return false
+	}
+
+	for k, av := range as {
+		bv, ok := bs[k]
+		if !ok {
+			return false
+		}
+		if !ValuesSDKEquivalent(av, bv) {
+			return false
+		}
+	}
+	return true
+}
+
+// valuesSDKEquivalentNumbers decides equivalence for two number values based
+// on the fact that the SDK uses int and float64 representations while
+// cty (and thus Terraform Core) uses big.Float, and so we expect to lose
+// precision in the round-trip.
+//
+// This does _not_ attempt to allow for an epsilon difference that may be
+// caused by accumulated innacuracy in a float calculation, under the
+// expectation that providers generally do not actually do compuations on
+// floats and instead just pass string representations of them on verbatim
+// to remote APIs. A remote API _itself_ may introduce inaccuracy, but that's
+// a problem for the provider itself to deal with, based on its knowledge of
+// the remote system, e.g. using DiffSuppressFunc.
+func valuesSDKEquivalentNumbers(a, b cty.Value) bool {
+	if a.RawEquals(b) {
+		return true // easy
+	}
+
+	af := a.AsBigFloat()
+	bf := b.AsBigFloat()
+
+	if af.IsInt() != bf.IsInt() {
+		return false
+	}
+	if af.IsInt() && bf.IsInt() {
+		return false // a.RawEquals(b) test above is good enough for integers
+	}
+
+	// The SDK supports only int and float64, so if it's not an integer
+	// we know that only a float64-level of precision can possibly be
+	// significant.
+	af64, _ := af.Float64()
+	bf64, _ := bf.Float64()
+	return af64 == bf64
+}
diff --git a/v1.5.7/internal/configs/hcl2shim/values_equiv_test.go b/v1.5.7/internal/configs/hcl2shim/values_equiv_test.go
new file mode 100644
index 0000000..65663f4
--- /dev/null
+++ b/v1.5.7/internal/configs/hcl2shim/values_equiv_test.go
@@ -0,0 +1,432 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package hcl2shim
+
+import (
+	"fmt"
+	"math/big"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestValuesSDKEquivalent(t *testing.T) {
+	piBig, _, err := big.ParseFloat("3.14159265358979323846264338327950288419716939937510582097494459", 10, 512, big.ToZero)
+	if err != nil {
+		t.Fatal(err)
+	}
+	pi64, _ := piBig.Float64()
+
+	tests := []struct {
+		A, B cty.Value
+		Want bool
+	}{
+		// Strings
+		{
+			cty.StringVal("hello"),
+			cty.StringVal("hello"),
+			true,
+		},
+		{
+			cty.StringVal("hello"),
+			cty.StringVal("world"),
+			false,
+		},
+		{
+			cty.StringVal("hello"),
+			cty.StringVal(""),
+			false,
+		},
+		{
+			cty.NullVal(cty.String),
+			cty.StringVal(""),
+			true,
+		},
+
+		// Numbers
+		{
+			cty.NumberIntVal(1),
+			cty.NumberIntVal(1),
+			true,
+		},
+		{
+			cty.NumberIntVal(1),
+			cty.NumberIntVal(2),
+			false,
+		},
+		{
+			cty.NumberIntVal(1),
+			cty.Zero,
+			false,
+		},
+		{
+			cty.NullVal(cty.Number),
+			cty.Zero,
+			true,
+		},
+		{
+			cty.NumberVal(piBig),
+			cty.Zero,
+			false,
+		},
+		{
+			cty.NumberFloatVal(pi64),
+			cty.Zero,
+			false,
+		},
+		{
+			cty.NumberFloatVal(pi64),
+			cty.NumberVal(piBig),
+			true,
+		},
+
+		// Bools
+		{
+			cty.True,
+			cty.True,
+			true,
+		},
+		{
+			cty.True,
+			cty.False,
+			false,
+		},
+		{
+			cty.NullVal(cty.Bool),
+			cty.False,
+			true,
+		},
+
+		// Mixed primitives
+		{
+			cty.StringVal("hello"),
+			cty.False,
+			false,
+		},
+		{
+			cty.StringVal(""),
+			cty.False,
+			true,
+		},
+		{
+			cty.NumberIntVal(0),
+			cty.False,
+			true,
+		},
+		{
+			cty.StringVal(""),
+			cty.NumberIntVal(0),
+			true,
+		},
+		{
+			cty.NullVal(cty.Bool),
+			cty.NullVal(cty.Number),
+			true,
+		},
+		{
+			cty.StringVal(""),
+			cty.NullVal(cty.Number),
+			true,
+		},
+
+		// Lists
+		{
+			cty.ListValEmpty(cty.String),
+			cty.ListValEmpty(cty.String),
+			true,
+		},
+		{
+			cty.ListValEmpty(cty.String),
+			cty.NullVal(cty.List(cty.String)),
+			true,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
+			cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("hello")}),
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
+			cty.ListValEmpty(cty.String),
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
+			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
+			true,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
+			cty.ListVal([]cty.Value{cty.StringVal("world")}),
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.NullVal(cty.String)}),
+			cty.ListVal([]cty.Value{cty.StringVal("")}),
+			true,
+		},
+
+		// Tuples
+		{
+			cty.EmptyTupleVal,
+			cty.EmptyTupleVal,
+			true,
+		},
+		{
+			cty.EmptyTupleVal,
+			cty.NullVal(cty.EmptyTuple),
+			true,
+		},
+		{
+			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
+			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("hello")}),
+			false,
+		},
+		{
+			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
+			cty.EmptyTupleVal,
+			false,
+		},
+		{
+			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
+			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
+			true,
+		},
+		{
+			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
+			cty.TupleVal([]cty.Value{cty.StringVal("world")}),
+			false,
+		},
+		{
+			cty.TupleVal([]cty.Value{cty.NullVal(cty.String)}),
+			cty.TupleVal([]cty.Value{cty.StringVal("")}),
+			true,
+		},
+
+		// Sets
+		{
+			cty.SetValEmpty(cty.String),
+			cty.SetValEmpty(cty.String),
+			true,
+		},
+		{
+			cty.SetValEmpty(cty.String),
+			cty.NullVal(cty.Set(cty.String)),
+			true,
+		},
+		{
+			cty.SetVal([]cty.Value{cty.StringVal("hello")}),
+			cty.SetValEmpty(cty.String),
+			false,
+		},
+		{
+			cty.SetVal([]cty.Value{cty.StringVal("hello")}),
+			cty.SetVal([]cty.Value{cty.StringVal("hello")}),
+			true,
+		},
+		{
+			cty.SetVal([]cty.Value{cty.StringVal("hello")}),
+			cty.SetVal([]cty.Value{cty.StringVal("world")}),
+			false,
+		},
+		{
+			cty.SetVal([]cty.Value{cty.NullVal(cty.String)}),
+			cty.SetVal([]cty.Value{cty.StringVal("")}),
+			true,
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.NullVal(cty.String),
+				cty.StringVal(""),
+			}),
+			cty.SetVal([]cty.Value{
+				cty.NullVal(cty.String),
+			}),
+			false, // because the element count is different
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.StringVal(""),
+					"b": cty.StringVal(""),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.NullVal(cty.String),
+					"b": cty.StringVal(""),
+				}),
+			}),
+			cty.SetVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.StringVal(""),
+					"b": cty.StringVal(""),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.StringVal(""),
+					"b": cty.NullVal(cty.String),
+				}),
+			}),
+			true,
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.StringVal("boop"),
+					"b": cty.StringVal(""),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.NullVal(cty.String),
+					"b": cty.StringVal(""),
+				}),
+			}),
+			cty.SetVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.StringVal("beep"),
+					"b": cty.StringVal(""),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.StringVal(""),
+					"b": cty.NullVal(cty.String),
+				}),
+			}),
+			false,
+		},
+		{
+			cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+				"list": cty.ListValEmpty(cty.String),
+				"list_block": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"unused": cty.StringVal(""),
+					}),
+				}),
+			})}),
+			cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+				"list": cty.ListValEmpty(cty.String),
+				"list_block": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"unused": cty.NullVal(cty.String),
+					}),
+				}),
+			})}),
+			true,
+		},
+
+		// Maps
+		{
+			cty.MapValEmpty(cty.String),
+			cty.MapValEmpty(cty.String),
+			true,
+		},
+		{
+			cty.MapValEmpty(cty.String),
+			cty.NullVal(cty.Map(cty.String)),
+			true,
+		},
+		{
+			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
+			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("hello"), "hey": cty.StringVal("hello")}),
+			false,
+		},
+		{
+			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
+			cty.MapValEmpty(cty.String),
+			false,
+		},
+		{
+			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
+			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
+			true,
+		},
+		{
+			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
+			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("world")}),
+			false,
+		},
+		{
+			cty.MapVal(map[string]cty.Value{"hi": cty.NullVal(cty.String)}),
+			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("")}),
+			true,
+		},
+
+		// Objects
+		{
+			cty.EmptyObjectVal,
+			cty.EmptyObjectVal,
+			true,
+		},
+		{
+			cty.EmptyObjectVal,
+			cty.NullVal(cty.EmptyObject),
+			true,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
+			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("hello"), "hey": cty.StringVal("hello")}),
+			false,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
+			cty.EmptyObjectVal,
+			false,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
+			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
+			true,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
+			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("world")}),
+			false,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{"hi": cty.NullVal(cty.String)}),
+			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("")}),
+			true,
+		},
+
+		// Unknown values
+		{
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			true,
+		},
+		{
+			cty.StringVal("hello"),
+			cty.UnknownVal(cty.String),
+			false,
+		},
+		{
+			cty.StringVal(""),
+			cty.UnknownVal(cty.String),
+			false,
+		},
+		{
+			cty.NullVal(cty.String),
+			cty.UnknownVal(cty.String),
+			false,
+		},
+	}
+
+	run := func(t *testing.T, a, b cty.Value, want bool) {
+		got := ValuesSDKEquivalent(a, b)
+
+		if got != want {
+			t.Errorf("wrong result\nfor: %#v ≈ %#v\ngot %#v, but want %#v", a, b, got, want)
+		}
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%#v ≈ %#v", test.A, test.B), func(t *testing.T) {
+			run(t, test.A, test.B, test.Want)
+		})
+		// This function is symmetrical, so we'll also test in reverse so
+		// we don't need to manually copy all of the test cases. (But this does
+		// mean that one failure normally becomes two, of course!)
+		if !test.A.RawEquals(test.B) {
+			t.Run(fmt.Sprintf("%#v ≈ %#v", test.B, test.A), func(t *testing.T) {
+				run(t, test.B, test.A, test.Want)
+			})
+		}
+	}
+}
diff --git a/v1.5.7/internal/configs/hcl2shim/values_test.go b/v1.5.7/internal/configs/hcl2shim/values_test.go
new file mode 100644
index 0000000..5ca285c
--- /dev/null
+++ b/v1.5.7/internal/configs/hcl2shim/values_test.go
@@ -0,0 +1,418 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package hcl2shim
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestConfigValueFromHCL2Block(t *testing.T) {
+	tests := []struct {
+		Input  cty.Value
+		Schema *configschema.Block
+		Want   map[string]interface{}
+	}{
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("Ermintrude"),
+				"age":  cty.NumberIntVal(19),
+				"address": cty.ObjectVal(map[string]cty.Value{
+					"street": cty.ListVal([]cty.Value{cty.StringVal("421 Shoreham Loop")}),
+					"city":   cty.StringVal("Fridgewater"),
+					"state":  cty.StringVal("MA"),
+					"zip":    cty.StringVal("91037"),
+				}),
+			}),
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"name": {Type: cty.String, Optional: true},
+					"age":  {Type: cty.Number, Optional: true},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"address": {
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"street": {Type: cty.List(cty.String), Optional: true},
+								"city":   {Type: cty.String, Optional: true},
+								"state":  {Type: cty.String, Optional: true},
+								"zip":    {Type: cty.String, Optional: true},
+							},
+						},
+					},
+				},
+			},
+			map[string]interface{}{
+				"name": "Ermintrude",
+				"age":  int(19),
+				"address": map[string]interface{}{
+					"street": []interface{}{"421 Shoreham Loop"},
+					"city":   "Fridgewater",
+					"state":  "MA",
+					"zip":    "91037",
+				},
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("Ermintrude"),
+				"age":  cty.NumberIntVal(19),
+				"address": cty.NullVal(cty.Object(map[string]cty.Type{
+					"street": cty.List(cty.String),
+					"city":   cty.String,
+					"state":  cty.String,
+					"zip":    cty.String,
+				})),
+			}),
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"name": {Type: cty.String, Optional: true},
+					"age":  {Type: cty.Number, Optional: true},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"address": {
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"street": {Type: cty.List(cty.String), Optional: true},
+								"city":   {Type: cty.String, Optional: true},
+								"state":  {Type: cty.String, Optional: true},
+								"zip":    {Type: cty.String, Optional: true},
+							},
+						},
+					},
+				},
+			},
+			map[string]interface{}{
+				"name": "Ermintrude",
+				"age":  int(19),
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("Ermintrude"),
+				"age":  cty.NumberIntVal(19),
+				"address": cty.ObjectVal(map[string]cty.Value{
+					"street": cty.ListVal([]cty.Value{cty.StringVal("421 Shoreham Loop")}),
+					"city":   cty.StringVal("Fridgewater"),
+					"state":  cty.StringVal("MA"),
+					"zip":    cty.NullVal(cty.String), // should be omitted altogether in result
+				}),
+			}),
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"name": {Type: cty.String, Optional: true},
+					"age":  {Type: cty.Number, Optional: true},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"address": {
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"street": {Type: cty.List(cty.String), Optional: true},
+								"city":   {Type: cty.String, Optional: true},
+								"state":  {Type: cty.String, Optional: true},
+								"zip":    {Type: cty.String, Optional: true},
+							},
+						},
+					},
+				},
+			},
+			map[string]interface{}{
+				"name": "Ermintrude",
+				"age":  int(19),
+				"address": map[string]interface{}{
+					"street": []interface{}{"421 Shoreham Loop"},
+					"city":   "Fridgewater",
+					"state":  "MA",
+				},
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"address": cty.ListVal([]cty.Value{cty.EmptyObjectVal}),
+			}),
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"address": {
+						Nesting: configschema.NestingList,
+						Block:   configschema.Block{},
+					},
+				},
+			},
+			map[string]interface{}{
+				"address": []interface{}{
+					map[string]interface{}{},
+				},
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"address": cty.ListValEmpty(cty.EmptyObject), // should be omitted altogether in result
+			}),
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"address": {
+						Nesting: configschema.NestingList,
+						Block:   configschema.Block{},
+					},
+				},
+			},
+			map[string]interface{}{},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"address": cty.SetVal([]cty.Value{cty.EmptyObjectVal}),
+			}),
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"address": {
+						Nesting: configschema.NestingSet,
+						Block:   configschema.Block{},
+					},
+				},
+			},
+			map[string]interface{}{
+				"address": []interface{}{
+					map[string]interface{}{},
+				},
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"address": cty.SetValEmpty(cty.EmptyObject),
+			}),
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"address": {
+						Nesting: configschema.NestingSet,
+						Block:   configschema.Block{},
+					},
+				},
+			},
+			map[string]interface{}{},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"address": cty.MapVal(map[string]cty.Value{"foo": cty.EmptyObjectVal}),
+			}),
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"address": {
+						Nesting: configschema.NestingMap,
+						Block:   configschema.Block{},
+					},
+				},
+			},
+			map[string]interface{}{
+				"address": map[string]interface{}{
+					"foo": map[string]interface{}{},
+				},
+			},
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"address": cty.MapValEmpty(cty.EmptyObject),
+			}),
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"address": {
+						Nesting: configschema.NestingMap,
+						Block:   configschema.Block{},
+					},
+				},
+			},
+			map[string]interface{}{},
+		},
+		{
+			cty.NullVal(cty.EmptyObject),
+			&configschema.Block{},
+			nil,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%#v", test.Input), func(t *testing.T) {
+			got := ConfigValueFromHCL2Block(test.Input, test.Schema)
+			if !reflect.DeepEqual(got, test.Want) {
+				t.Errorf("wrong result\ninput: %#v\ngot:   %#v\nwant:  %#v", test.Input, got, test.Want)
+			}
+		})
+	}
+}
+
+func TestConfigValueFromHCL2(t *testing.T) {
+	tests := []struct {
+		Input cty.Value
+		Want  interface{}
+	}{
+		{
+			cty.True,
+			true,
+		},
+		{
+			cty.False,
+			false,
+		},
+		{
+			cty.NumberIntVal(12),
+			int(12),
+		},
+		{
+			cty.NumberFloatVal(12.5),
+			float64(12.5),
+		},
+		{
+			cty.StringVal("hello world"),
+			"hello world",
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("Ermintrude"),
+				"age":  cty.NumberIntVal(19),
+				"address": cty.ObjectVal(map[string]cty.Value{
+					"street": cty.ListVal([]cty.Value{cty.StringVal("421 Shoreham Loop")}),
+					"city":   cty.StringVal("Fridgewater"),
+					"state":  cty.StringVal("MA"),
+					"zip":    cty.StringVal("91037"),
+				}),
+			}),
+			map[string]interface{}{
+				"name": "Ermintrude",
+				"age":  int(19),
+				"address": map[string]interface{}{
+					"street": []interface{}{"421 Shoreham Loop"},
+					"city":   "Fridgewater",
+					"state":  "MA",
+					"zip":    "91037",
+				},
+			},
+		},
+		{
+			cty.MapVal(map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+				"bar": cty.StringVal("baz"),
+			}),
+			map[string]interface{}{
+				"foo": "bar",
+				"bar": "baz",
+			},
+		},
+		{
+			cty.TupleVal([]cty.Value{
+				cty.StringVal("foo"),
+				cty.True,
+			}),
+			[]interface{}{
+				"foo",
+				true,
+			},
+		},
+		{
+			cty.NullVal(cty.String),
+			nil,
+		},
+		{
+			cty.UnknownVal(cty.String),
+			UnknownVariableValue,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%#v", test.Input), func(t *testing.T) {
+			got := ConfigValueFromHCL2(test.Input)
+			if !reflect.DeepEqual(got, test.Want) {
+				t.Errorf("wrong result\ninput: %#v\ngot:   %#v\nwant:  %#v", test.Input, got, test.Want)
+			}
+		})
+	}
+}
+
+func TestHCL2ValueFromConfigValue(t *testing.T) {
+	tests := []struct {
+		Input interface{}
+		Want  cty.Value
+	}{
+		{
+			nil,
+			cty.NullVal(cty.DynamicPseudoType),
+		},
+		{
+			UnknownVariableValue,
+			cty.DynamicVal,
+		},
+		{
+			true,
+			cty.True,
+		},
+		{
+			false,
+			cty.False,
+		},
+		{
+			int(12),
+			cty.NumberIntVal(12),
+		},
+		{
+			int(0),
+			cty.Zero,
+		},
+		{
+			float64(12.5),
+			cty.NumberFloatVal(12.5),
+		},
+		{
+			"hello world",
+			cty.StringVal("hello world"),
+		},
+		{
+			"O\u0308",               // decomposed letter + diacritic
+			cty.StringVal("\u00D6"), // NFC-normalized on entry into cty
+		},
+		{
+			[]interface{}{},
+			cty.EmptyTupleVal,
+		},
+		{
+			[]interface{}(nil),
+			cty.EmptyTupleVal,
+		},
+		{
+			[]interface{}{"hello", "world"},
+			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world")}),
+		},
+		{
+			map[string]interface{}{},
+			cty.EmptyObjectVal,
+		},
+		{
+			map[string]interface{}(nil),
+			cty.EmptyObjectVal,
+		},
+		{
+			map[string]interface{}{
+				"foo": "bar",
+				"bar": "baz",
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+				"bar": cty.StringVal("baz"),
+			}),
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%#v", test.Input), func(t *testing.T) {
+			got := HCL2ValueFromConfigValue(test.Input)
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ninput: %#v\ngot:   %#v\nwant:  %#v", test.Input, got, test.Want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/configs/import.go b/v1.5.7/internal/configs/import.go
new file mode 100644
index 0000000..5771f8d
--- /dev/null
+++ b/v1.5.7/internal/configs/import.go
@@ -0,0 +1,81 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/gohcl"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+type Import struct {
+	ID string
+	To addrs.AbsResourceInstance
+
+	ProviderConfigRef *ProviderConfigRef
+	Provider          addrs.Provider
+
+	DeclRange         hcl.Range
+	ProviderDeclRange hcl.Range
+}
+
+func decodeImportBlock(block *hcl.Block) (*Import, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+	imp := &Import{
+		DeclRange: block.DefRange,
+	}
+
+	content, moreDiags := block.Body.Content(importBlockSchema)
+	diags = append(diags, moreDiags...)
+
+	if attr, exists := content.Attributes["id"]; exists {
+		attrDiags := gohcl.DecodeExpression(attr.Expr, nil, &imp.ID)
+		diags = append(diags, attrDiags...)
+
+	}
+
+	if attr, exists := content.Attributes["to"]; exists {
+		traversal, traversalDiags := hcl.AbsTraversalForExpr(attr.Expr)
+		diags = append(diags, traversalDiags...)
+		if !traversalDiags.HasErrors() {
+			to, toDiags := addrs.ParseAbsResourceInstance(traversal)
+			diags = append(diags, toDiags.ToHCL()...)
+			imp.To = to
+		}
+	}
+
+	if attr, exists := content.Attributes["provider"]; exists {
+		if len(imp.To.Module) > 0 {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid import provider argument",
+				Detail:   "The provider argument can only be specified in import blocks that will generate configuration.\n\nUse the providers argument within the module block to configure providers for all resources within a module, including imported resources.",
+				Subject:  attr.Range.Ptr(),
+			})
+		}
+
+		var providerDiags hcl.Diagnostics
+		imp.ProviderConfigRef, providerDiags = decodeProviderConfigRef(attr.Expr, "provider")
+		imp.ProviderDeclRange = attr.Range
+		diags = append(diags, providerDiags...)
+	}
+
+	return imp, diags
+}
+
+var importBlockSchema = &hcl.BodySchema{
+	Attributes: []hcl.AttributeSchema{
+		{
+			Name: "provider",
+		},
+		{
+			Name:     "id",
+			Required: true,
+		},
+		{
+			Name:     "to",
+			Required: true,
+		},
+	},
+}
diff --git a/v1.5.7/internal/configs/import_test.go b/v1.5.7/internal/configs/import_test.go
new file mode 100644
index 0000000..2b3bd6f
--- /dev/null
+++ b/v1.5.7/internal/configs/import_test.go
@@ -0,0 +1,176 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcltest"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestImportBlock_decode(t *testing.T) {
+	blockRange := hcl.Range{
+		Filename: "mock.tf",
+		Start:    hcl.Pos{Line: 3, Column: 12, Byte: 27},
+		End:      hcl.Pos{Line: 3, Column: 19, Byte: 34},
+	}
+
+	foo_str_expr := hcltest.MockExprLiteral(cty.StringVal("foo"))
+	bar_expr := hcltest.MockExprTraversalSrc("test_instance.bar")
+
+	bar_index_expr := hcltest.MockExprTraversalSrc("test_instance.bar[\"one\"]")
+
+	mod_bar_expr := hcltest.MockExprTraversalSrc("module.bar.test_instance.bar")
+
+	tests := map[string]struct {
+		input *hcl.Block
+		want  *Import
+		err   string
+	}{
+		"success": {
+			&hcl.Block{
+				Type: "import",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"id": {
+							Name: "id",
+							Expr: foo_str_expr,
+						},
+						"to": {
+							Name: "to",
+							Expr: bar_expr,
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			&Import{
+				To:        mustAbsResourceInstanceAddr("test_instance.bar"),
+				ID:        "foo",
+				DeclRange: blockRange,
+			},
+			``,
+		},
+		"indexed resources": {
+			&hcl.Block{
+				Type: "import",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"id": {
+							Name: "id",
+							Expr: foo_str_expr,
+						},
+						"to": {
+							Name: "to",
+							Expr: bar_index_expr,
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			&Import{
+				To:        mustAbsResourceInstanceAddr("test_instance.bar[\"one\"]"),
+				ID:        "foo",
+				DeclRange: blockRange,
+			},
+			``,
+		},
+		"resource inside module": {
+			&hcl.Block{
+				Type: "import",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"id": {
+							Name: "id",
+							Expr: foo_str_expr,
+						},
+						"to": {
+							Name: "to",
+							Expr: mod_bar_expr,
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			&Import{
+				To:        mustAbsResourceInstanceAddr("module.bar.test_instance.bar"),
+				ID:        "foo",
+				DeclRange: blockRange,
+			},
+			``,
+		},
+		"error: missing id argument": {
+			&hcl.Block{
+				Type: "import",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"to": {
+							Name: "to",
+							Expr: bar_expr,
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			&Import{
+				To:        mustAbsResourceInstanceAddr("test_instance.bar"),
+				DeclRange: blockRange,
+			},
+			"Missing required argument",
+		},
+		"error: missing to argument": {
+			&hcl.Block{
+				Type: "import",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"id": {
+							Name: "id",
+							Expr: foo_str_expr,
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			&Import{
+				ID:        "foo",
+				DeclRange: blockRange,
+			},
+			"Missing required argument",
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got, diags := decodeImportBlock(test.input)
+
+			if diags.HasErrors() {
+				if test.err == "" {
+					t.Fatalf("unexpected error: %s", diags.Errs())
+				}
+				if gotErr := diags[0].Summary; gotErr != test.err {
+					t.Errorf("wrong error, got %q, want %q", gotErr, test.err)
+				}
+			} else if test.err != "" {
+				t.Fatal("expected error")
+			}
+
+			if !cmp.Equal(got, test.want, cmp.AllowUnexported(addrs.MoveEndpoint{})) {
+				t.Fatalf("wrong result: %s", cmp.Diff(got, test.want))
+			}
+		})
+	}
+}
+
+func mustAbsResourceInstanceAddr(str string) addrs.AbsResourceInstance {
+	addr, diags := addrs.ParseAbsResourceInstanceStr(str)
+	if diags.HasErrors() {
+		panic(fmt.Sprintf("invalid absolute resource instance address: %s", diags.Err()))
+	}
+	return addr
+}
diff --git a/v1.5.7/internal/configs/module.go b/v1.5.7/internal/configs/module.go
new file mode 100644
index 0000000..47bc331
--- /dev/null
+++ b/v1.5.7/internal/configs/module.go
@@ -0,0 +1,747 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/experiments"
+
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+// Module is a container for a set of configuration constructs that are
+// evaluated within a common namespace.
+type Module struct {
+	// SourceDir is the filesystem directory that the module was loaded from.
+	//
+	// This is populated automatically only for configurations loaded with
+	// LoadConfigDir. If the parser is using a virtual filesystem then the
+	// path here will be in terms of that virtual filesystem.
+
+	// Any other caller that constructs a module directly with NewModule may
+	// assign a suitable value to this attribute before using it for other
+	// purposes. It should be treated as immutable by all consumers of Module
+	// values.
+	SourceDir string
+
+	CoreVersionConstraints []VersionConstraint
+
+	ActiveExperiments experiments.Set
+
+	Backend              *Backend
+	CloudConfig          *CloudConfig
+	ProviderConfigs      map[string]*Provider
+	ProviderRequirements *RequiredProviders
+	ProviderLocalNames   map[addrs.Provider]string
+	ProviderMetas        map[addrs.Provider]*ProviderMeta
+
+	Variables map[string]*Variable
+	Locals    map[string]*Local
+	Outputs   map[string]*Output
+
+	ModuleCalls map[string]*ModuleCall
+
+	ManagedResources map[string]*Resource
+	DataResources    map[string]*Resource
+
+	Moved  []*Moved
+	Import []*Import
+
+	Checks map[string]*Check
+}
+
+// File describes the contents of a single configuration file.
+//
+// Individual files are not usually used alone, but rather combined together
+// with other files (conventionally, those in the same directory) to produce
+// a *Module, using NewModule.
+//
+// At the level of an individual file we represent directly the structural
+// elements present in the file, without any attempt to detect conflicting
+// declarations. A File object can therefore be used for some basic static
+// analysis of individual elements, but must be built into a Module to detect
+// duplicate declarations.
+type File struct {
+	CoreVersionConstraints []VersionConstraint
+
+	ActiveExperiments experiments.Set
+
+	Backends          []*Backend
+	CloudConfigs      []*CloudConfig
+	ProviderConfigs   []*Provider
+	ProviderMetas     []*ProviderMeta
+	RequiredProviders []*RequiredProviders
+
+	Variables []*Variable
+	Locals    []*Local
+	Outputs   []*Output
+
+	ModuleCalls []*ModuleCall
+
+	ManagedResources []*Resource
+	DataResources    []*Resource
+
+	Moved  []*Moved
+	Import []*Import
+
+	Checks []*Check
+}
+
+// NewModule takes a list of primary files and a list of override files and
+// produces a *Module by combining the files together.
+//
+// If there are any conflicting declarations in the given files -- for example,
+// if the same variable name is defined twice -- then the resulting module
+// will be incomplete and error diagnostics will be returned. Careful static
+// analysis of the returned Module is still possible in this case, but the
+// module will probably not be semantically valid.
+func NewModule(primaryFiles, overrideFiles []*File) (*Module, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+	mod := &Module{
+		ProviderConfigs:    map[string]*Provider{},
+		ProviderLocalNames: map[addrs.Provider]string{},
+		Variables:          map[string]*Variable{},
+		Locals:             map[string]*Local{},
+		Outputs:            map[string]*Output{},
+		ModuleCalls:        map[string]*ModuleCall{},
+		ManagedResources:   map[string]*Resource{},
+		DataResources:      map[string]*Resource{},
+		Checks:             map[string]*Check{},
+		ProviderMetas:      map[addrs.Provider]*ProviderMeta{},
+	}
+
+	// Process the required_providers blocks first, to ensure that all
+	// resources have access to the correct provider FQNs
+	for _, file := range primaryFiles {
+		for _, r := range file.RequiredProviders {
+			if mod.ProviderRequirements != nil {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Duplicate required providers configuration",
+					Detail:   fmt.Sprintf("A module may have only one required providers configuration. The required providers were previously configured at %s.", mod.ProviderRequirements.DeclRange),
+					Subject:  &r.DeclRange,
+				})
+				continue
+			}
+			mod.ProviderRequirements = r
+		}
+	}
+
+	// If no required_providers block is configured, create a useful empty
+	// state to reduce nil checks elsewhere
+	if mod.ProviderRequirements == nil {
+		mod.ProviderRequirements = &RequiredProviders{
+			RequiredProviders: make(map[string]*RequiredProvider),
+		}
+	}
+
+	// Any required_providers blocks in override files replace the entire
+	// block for each provider
+	for _, file := range overrideFiles {
+		for _, override := range file.RequiredProviders {
+			for name, rp := range override.RequiredProviders {
+				mod.ProviderRequirements.RequiredProviders[name] = rp
+			}
+		}
+	}
+
+	for _, file := range primaryFiles {
+		fileDiags := mod.appendFile(file)
+		diags = append(diags, fileDiags...)
+	}
+
+	for _, file := range overrideFiles {
+		fileDiags := mod.mergeFile(file)
+		diags = append(diags, fileDiags...)
+	}
+
+	diags = append(diags, checkModuleExperiments(mod)...)
+
+	// Generate the FQN -> LocalProviderName map
+	mod.gatherProviderLocalNames()
+
+	return mod, diags
+}
+
+// ResourceByAddr returns the configuration for the resource with the given
+// address, or nil if there is no such resource.
+func (m *Module) ResourceByAddr(addr addrs.Resource) *Resource {
+	key := addr.String()
+	switch addr.Mode {
+	case addrs.ManagedResourceMode:
+		return m.ManagedResources[key]
+	case addrs.DataResourceMode:
+		return m.DataResources[key]
+	default:
+		return nil
+	}
+}
+
+func (m *Module) appendFile(file *File) hcl.Diagnostics {
+	var diags hcl.Diagnostics
+
+	// If there are any conflicting requirements then we'll catch them
+	// when we actually check these constraints.
+	m.CoreVersionConstraints = append(m.CoreVersionConstraints, file.CoreVersionConstraints...)
+
+	m.ActiveExperiments = experiments.SetUnion(m.ActiveExperiments, file.ActiveExperiments)
+
+	for _, b := range file.Backends {
+		if m.Backend != nil {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Duplicate backend configuration",
+				Detail:   fmt.Sprintf("A module may have only one backend configuration. The backend was previously configured at %s.", m.Backend.DeclRange),
+				Subject:  &b.DeclRange,
+			})
+			continue
+		}
+		m.Backend = b
+	}
+
+	for _, c := range file.CloudConfigs {
+		if m.CloudConfig != nil {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Duplicate Terraform Cloud configurations",
+				Detail:   fmt.Sprintf("A module may have only one 'cloud' block configuring Terraform Cloud. Terraform Cloud was previously configured at %s.", m.CloudConfig.DeclRange),
+				Subject:  &c.DeclRange,
+			})
+			continue
+		}
+
+		m.CloudConfig = c
+	}
+
+	if m.Backend != nil && m.CloudConfig != nil {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Both a backend and Terraform Cloud configuration are present",
+			Detail:   fmt.Sprintf("A module may declare either one 'cloud' block configuring Terraform Cloud OR one 'backend' block configuring a state backend. Terraform Cloud is configured at %s; a backend is configured at %s. Remove the backend block to configure Terraform Cloud.", m.CloudConfig.DeclRange, m.Backend.DeclRange),
+			Subject:  &m.Backend.DeclRange,
+		})
+	}
+
+	for _, pc := range file.ProviderConfigs {
+		key := pc.moduleUniqueKey()
+		if existing, exists := m.ProviderConfigs[key]; exists {
+			if existing.Alias == "" {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Duplicate provider configuration",
+					Detail:   fmt.Sprintf("A default (non-aliased) provider configuration for %q was already given at %s. If multiple configurations are required, set the \"alias\" argument for alternative configurations.", existing.Name, existing.DeclRange),
+					Subject:  &pc.DeclRange,
+				})
+			} else {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Duplicate provider configuration",
+					Detail:   fmt.Sprintf("A provider configuration for %q with alias %q was already given at %s. Each configuration for the same provider must have a distinct alias.", existing.Name, existing.Alias, existing.DeclRange),
+					Subject:  &pc.DeclRange,
+				})
+			}
+			continue
+		}
+		m.ProviderConfigs[key] = pc
+	}
+
+	for _, pm := range file.ProviderMetas {
+		provider := m.ProviderForLocalConfig(addrs.LocalProviderConfig{LocalName: pm.Provider})
+		if existing, exists := m.ProviderMetas[provider]; exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Duplicate provider_meta block",
+				Detail:   fmt.Sprintf("A provider_meta block for provider %q was already declared at %s. Providers may only have one provider_meta block per module.", existing.Provider, existing.DeclRange),
+				Subject:  &pm.DeclRange,
+			})
+		}
+		m.ProviderMetas[provider] = pm
+	}
+
+	for _, v := range file.Variables {
+		if existing, exists := m.Variables[v.Name]; exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Duplicate variable declaration",
+				Detail:   fmt.Sprintf("A variable named %q was already declared at %s. Variable names must be unique within a module.", existing.Name, existing.DeclRange),
+				Subject:  &v.DeclRange,
+			})
+		}
+		m.Variables[v.Name] = v
+	}
+
+	for _, l := range file.Locals {
+		if existing, exists := m.Locals[l.Name]; exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Duplicate local value definition",
+				Detail:   fmt.Sprintf("A local value named %q was already defined at %s. Local value names must be unique within a module.", existing.Name, existing.DeclRange),
+				Subject:  &l.DeclRange,
+			})
+		}
+		m.Locals[l.Name] = l
+	}
+
+	for _, o := range file.Outputs {
+		if existing, exists := m.Outputs[o.Name]; exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Duplicate output definition",
+				Detail:   fmt.Sprintf("An output named %q was already defined at %s. Output names must be unique within a module.", existing.Name, existing.DeclRange),
+				Subject:  &o.DeclRange,
+			})
+		}
+		m.Outputs[o.Name] = o
+	}
+
+	for _, mc := range file.ModuleCalls {
+		if existing, exists := m.ModuleCalls[mc.Name]; exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Duplicate module call",
+				Detail:   fmt.Sprintf("A module call named %q was already defined at %s. Module calls must have unique names within a module.", existing.Name, existing.DeclRange),
+				Subject:  &mc.DeclRange,
+			})
+		}
+		m.ModuleCalls[mc.Name] = mc
+	}
+
+	for _, r := range file.ManagedResources {
+		key := r.moduleUniqueKey()
+		if existing, exists := m.ManagedResources[key]; exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  fmt.Sprintf("Duplicate resource %q configuration", existing.Type),
+				Detail:   fmt.Sprintf("A %s resource named %q was already declared at %s. Resource names must be unique per type in each module.", existing.Type, existing.Name, existing.DeclRange),
+				Subject:  &r.DeclRange,
+			})
+			continue
+		}
+		m.ManagedResources[key] = r
+
+		// set the provider FQN for the resource
+		if r.ProviderConfigRef != nil {
+			r.Provider = m.ProviderForLocalConfig(r.ProviderConfigAddr())
+		} else {
+			// an invalid resource name (for e.g. "null resource" instead of
+			// "null_resource") can cause a panic down the line in addrs:
+			// https://github.com/hashicorp/terraform/issues/25560
+			implied, err := addrs.ParseProviderPart(r.Addr().ImpliedProvider())
+			if err == nil {
+				r.Provider = m.ImpliedProviderForUnqualifiedType(implied)
+			}
+			// We don't return a diagnostic because the invalid resource name
+			// will already have been caught.
+		}
+	}
+
+	// Data sources can either be defined at the module root level, or within a
+	// single check block. We'll merge the data sources from both into the
+	// single module level DataResources map.
+	for _, r := range file.DataResources {
+		key := r.moduleUniqueKey()
+		if existing, exists := m.DataResources[key]; exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  fmt.Sprintf("Duplicate data %q configuration", existing.Type),
+				Detail:   fmt.Sprintf("A %s data resource named %q was already declared at %s. Resource names must be unique per type in each module.", existing.Type, existing.Name, existing.DeclRange),
+				Subject:  &r.DeclRange,
+			})
+			continue
+		}
+		m.DataResources[key] = r
+	}
+
+	for _, c := range file.Checks {
+		if c.DataResource != nil {
+			key := c.DataResource.moduleUniqueKey()
+			if existing, exists := m.DataResources[key]; exists {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  fmt.Sprintf("Duplicate data %q configuration", existing.Type),
+					Detail:   fmt.Sprintf("A %s data resource named %q was already declared at %s. Resource names must be unique per type in each module, including within check blocks.", existing.Type, existing.Name, existing.DeclRange),
+					Subject:  &c.DataResource.DeclRange,
+				})
+				continue
+			}
+			m.DataResources[key] = c.DataResource
+		}
+
+		if existing, exists := m.Checks[c.Name]; exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  fmt.Sprintf("Duplicate check %q configuration", existing.Name),
+				Detail:   fmt.Sprintf("A check block named %q was already declared at %s. Check blocks must be unique within each module.", existing.Name, existing.DeclRange),
+				Subject:  &c.DeclRange,
+			})
+			continue
+		}
+		m.Checks[c.Name] = c
+	}
+
+	// Handle the provider associations for all data resources together.
+	for _, r := range m.DataResources {
+		// set the provider FQN for the resource
+		if r.ProviderConfigRef != nil {
+			r.Provider = m.ProviderForLocalConfig(r.ProviderConfigAddr())
+		} else {
+			// an invalid data source name (for e.g. "null resource" instead of
+			// "null_resource") can cause a panic down the line in addrs:
+			// https://github.com/hashicorp/terraform/issues/25560
+			implied, err := addrs.ParseProviderPart(r.Addr().ImpliedProvider())
+			if err == nil {
+				r.Provider = m.ImpliedProviderForUnqualifiedType(implied)
+			}
+			// We don't return a diagnostic because the invalid resource name
+			// will already have been caught.
+		}
+	}
+
+	// "Moved" blocks just append, because they are all independent of one
+	// another at this level. (We handle any references between them at
+	// runtime.)
+	m.Moved = append(m.Moved, file.Moved...)
+
+	for _, i := range file.Import {
+		for _, mi := range m.Import {
+			if i.To.Equal(mi.To) {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  fmt.Sprintf("Duplicate import configuration for %q", i.To),
+					Detail:   fmt.Sprintf("An import block for the resource %q was already declared at %s. A resource can have only one import block.", i.To, mi.DeclRange),
+					Subject:  &i.DeclRange,
+				})
+				continue
+			}
+		}
+
+		if i.ProviderConfigRef != nil {
+			i.Provider = m.ProviderForLocalConfig(addrs.LocalProviderConfig{
+				LocalName: i.ProviderConfigRef.Name,
+				Alias:     i.ProviderConfigRef.Alias,
+			})
+		} else {
+			implied, err := addrs.ParseProviderPart(i.To.Resource.Resource.ImpliedProvider())
+			if err == nil {
+				i.Provider = m.ImpliedProviderForUnqualifiedType(implied)
+			}
+			// We don't return a diagnostic because the invalid resource name
+			// will already have been caught.
+		}
+
+		// It is invalid for any import block to have a "to" argument matching
+		// any moved block's "from" argument.
+		for _, mb := range m.Moved {
+			// Comparing string serialisations is good enough here, because we
+			// only care about equality in the case that both addresses are
+			// AbsResourceInstances.
+			if mb.From.String() == i.To.String() {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Cannot import to a move source",
+					Detail:   "An import block for ID %q targets resource address %s, but this address appears in the \"from\" argument of a moved block, which is invalid. Please change the import target to a different address, such as the move target.",
+					Subject:  &i.DeclRange,
+				})
+			}
+		}
+
+		m.Import = append(m.Import, i)
+	}
+
+	return diags
+}
+
+func (m *Module) mergeFile(file *File) hcl.Diagnostics {
+	var diags hcl.Diagnostics
+
+	if len(file.CoreVersionConstraints) != 0 {
+		// This is a bit of a strange case for overriding since we normally
+		// would union together across multiple files anyway, but we'll
+		// allow it and have each override file clobber any existing list.
+		m.CoreVersionConstraints = nil
+		m.CoreVersionConstraints = append(m.CoreVersionConstraints, file.CoreVersionConstraints...)
+	}
+
+	if len(file.Backends) != 0 {
+		switch len(file.Backends) {
+		case 1:
+			m.CloudConfig = nil // A backend block is mutually exclusive with a cloud one, and overwrites any cloud config
+			m.Backend = file.Backends[0]
+		default:
+			// An override file with multiple backends is still invalid, even
+			// though it can override backends from _other_ files.
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Duplicate backend configuration",
+				Detail:   fmt.Sprintf("Each override file may have only one backend configuration. A backend was previously configured at %s.", file.Backends[0].DeclRange),
+				Subject:  &file.Backends[1].DeclRange,
+			})
+		}
+	}
+
+	if len(file.CloudConfigs) != 0 {
+		switch len(file.CloudConfigs) {
+		case 1:
+			m.Backend = nil // A cloud block is mutually exclusive with a backend one, and overwrites any backend
+			m.CloudConfig = file.CloudConfigs[0]
+		default:
+			// An override file with multiple cloud blocks is still invalid, even
+			// though it can override cloud/backend blocks from _other_ files.
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Duplicate Terraform Cloud configurations",
+				Detail:   fmt.Sprintf("A module may have only one 'cloud' block configuring Terraform Cloud. Terraform Cloud was previously configured at %s.", file.CloudConfigs[0].DeclRange),
+				Subject:  &file.CloudConfigs[1].DeclRange,
+			})
+		}
+	}
+
+	for _, pc := range file.ProviderConfigs {
+		key := pc.moduleUniqueKey()
+		existing, exists := m.ProviderConfigs[key]
+		if pc.Alias == "" {
+			// We allow overriding a non-existing _default_ provider configuration
+			// because the user model is that an absent provider configuration
+			// implies an empty provider configuration, which is what the user
+			// is therefore overriding here.
+			if exists {
+				mergeDiags := existing.merge(pc)
+				diags = append(diags, mergeDiags...)
+			} else {
+				m.ProviderConfigs[key] = pc
+			}
+		} else {
+			// For aliased providers, there must be a base configuration to
+			// override. This allows us to detect and report alias typos
+			// that might otherwise cause the override to not apply.
+			if !exists {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Missing base provider configuration for override",
+					Detail:   fmt.Sprintf("There is no %s provider configuration with the alias %q. An override file can only override an aliased provider configuration that was already defined in a primary configuration file.", pc.Name, pc.Alias),
+					Subject:  &pc.DeclRange,
+				})
+				continue
+			}
+			mergeDiags := existing.merge(pc)
+			diags = append(diags, mergeDiags...)
+		}
+	}
+
+	for _, v := range file.Variables {
+		existing, exists := m.Variables[v.Name]
+		if !exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Missing base variable declaration to override",
+				Detail:   fmt.Sprintf("There is no variable named %q. An override file can only override a variable that was already declared in a primary configuration file.", v.Name),
+				Subject:  &v.DeclRange,
+			})
+			continue
+		}
+		mergeDiags := existing.merge(v)
+		diags = append(diags, mergeDiags...)
+	}
+
+	for _, l := range file.Locals {
+		existing, exists := m.Locals[l.Name]
+		if !exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Missing base local value definition to override",
+				Detail:   fmt.Sprintf("There is no local value named %q. An override file can only override a local value that was already defined in a primary configuration file.", l.Name),
+				Subject:  &l.DeclRange,
+			})
+			continue
+		}
+		mergeDiags := existing.merge(l)
+		diags = append(diags, mergeDiags...)
+	}
+
+	for _, o := range file.Outputs {
+		existing, exists := m.Outputs[o.Name]
+		if !exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Missing base output definition to override",
+				Detail:   fmt.Sprintf("There is no output named %q. An override file can only override an output that was already defined in a primary configuration file.", o.Name),
+				Subject:  &o.DeclRange,
+			})
+			continue
+		}
+		mergeDiags := existing.merge(o)
+		diags = append(diags, mergeDiags...)
+	}
+
+	for _, mc := range file.ModuleCalls {
+		existing, exists := m.ModuleCalls[mc.Name]
+		if !exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Missing module call to override",
+				Detail:   fmt.Sprintf("There is no module call named %q. An override file can only override a module call that was defined in a primary configuration file.", mc.Name),
+				Subject:  &mc.DeclRange,
+			})
+			continue
+		}
+		mergeDiags := existing.merge(mc)
+		diags = append(diags, mergeDiags...)
+	}
+
+	for _, r := range file.ManagedResources {
+		key := r.moduleUniqueKey()
+		existing, exists := m.ManagedResources[key]
+		if !exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Missing resource to override",
+				Detail:   fmt.Sprintf("There is no %s resource named %q. An override file can only override a resource block defined in a primary configuration file.", r.Type, r.Name),
+				Subject:  &r.DeclRange,
+			})
+			continue
+		}
+		mergeDiags := existing.merge(r, m.ProviderRequirements.RequiredProviders)
+		diags = append(diags, mergeDiags...)
+	}
+
+	for _, r := range file.DataResources {
+		key := r.moduleUniqueKey()
+		existing, exists := m.DataResources[key]
+		if !exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Missing data resource to override",
+				Detail:   fmt.Sprintf("There is no %s data resource named %q. An override file can only override a data block defined in a primary configuration file.", r.Type, r.Name),
+				Subject:  &r.DeclRange,
+			})
+			continue
+		}
+		mergeDiags := existing.merge(r, m.ProviderRequirements.RequiredProviders)
+		diags = append(diags, mergeDiags...)
+	}
+
+	for _, m := range file.Moved {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Cannot override 'moved' blocks",
+			Detail:   "Records of moved objects can appear only in normal files, not in override files.",
+			Subject:  m.DeclRange.Ptr(),
+		})
+	}
+
+	for _, m := range file.Import {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Cannot override 'import' blocks",
+			Detail:   "Import blocks can appear only in normal files, not in override files.",
+			Subject:  m.DeclRange.Ptr(),
+		})
+	}
+
+	return diags
+}
+
+// gatherProviderLocalNames is a helper function that populatesA a map of
+// provider FQNs -> provider local names. This information is useful for
+// user-facing output, which should include both the FQN and LocalName. It must
+// only be populated after the module has been parsed.
+func (m *Module) gatherProviderLocalNames() {
+	providers := make(map[addrs.Provider]string)
+	for k, v := range m.ProviderRequirements.RequiredProviders {
+		providers[v.Type] = k
+	}
+	m.ProviderLocalNames = providers
+}
+
+// LocalNameForProvider returns the module-specific user-supplied local name for
+// a given provider FQN, or the default local name if none was supplied.
+func (m *Module) LocalNameForProvider(p addrs.Provider) string {
+	if existing, exists := m.ProviderLocalNames[p]; exists {
+		return existing
+	} else {
+		// If there isn't a map entry, fall back to the default:
+		// Type = LocalName
+		return p.Type
+	}
+}
+
+// ProviderForLocalConfig returns the provider FQN for a given
+// LocalProviderConfig, based on its local name.
+func (m *Module) ProviderForLocalConfig(pc addrs.LocalProviderConfig) addrs.Provider {
+	return m.ImpliedProviderForUnqualifiedType(pc.LocalName)
+}
+
+// ImpliedProviderForUnqualifiedType returns the provider FQN for a given type,
+// first by looking up the type in the provider requirements map, and falling
+// back to an implied default provider.
+//
+// The intended behaviour is that configuring a provider with local name "foo"
+// in a required_providers block will result in resources with type "foo" using
+// that provider.
+func (m *Module) ImpliedProviderForUnqualifiedType(pType string) addrs.Provider {
+	if provider, exists := m.ProviderRequirements.RequiredProviders[pType]; exists {
+		return provider.Type
+	}
+	return addrs.ImpliedProviderForUnqualifiedType(pType)
+}
+
+func (m *Module) CheckCoreVersionRequirements(path addrs.Module, sourceAddr addrs.ModuleSource) hcl.Diagnostics {
+	var diags hcl.Diagnostics
+
+	for _, constraint := range m.CoreVersionConstraints {
+		// Before checking if the constraints are met, check that we are not using any prerelease fields as these
+		// are not currently supported.
+		var prereleaseDiags hcl.Diagnostics
+		for _, required := range constraint.Required {
+			if required.Prerelease() {
+				prereleaseDiags = prereleaseDiags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid required_version constraint",
+					Detail: fmt.Sprintf(
+						"Prerelease version constraints are not supported: %s. Remove the prerelease information from the constraint. Prerelease versions of terraform will match constraints using their version core only.",
+						required.String()),
+					Subject: constraint.DeclRange.Ptr(),
+				})
+			}
+		}
+
+		if len(prereleaseDiags) > 0 {
+			// There were some prerelease fields in the constraints. Don't check the constraints as they will
+			// fail, and populate the diagnostics for these constraints with the prerelease diagnostics.
+			diags = diags.Extend(prereleaseDiags)
+			continue
+		}
+
+		if !constraint.Required.Check(tfversion.SemVer) {
+			switch {
+			case len(path) == 0:
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Unsupported Terraform Core version",
+					Detail: fmt.Sprintf(
+						"This configuration does not support Terraform version %s. To proceed, either choose another supported Terraform version or update this version constraint. Version constraints are normally set for good reason, so updating the constraint may lead to other errors or unexpected behavior.",
+						tfversion.String(),
+					),
+					Subject: constraint.DeclRange.Ptr(),
+				})
+			default:
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Unsupported Terraform Core version",
+					Detail: fmt.Sprintf(
+						"Module %s (from %s) does not support Terraform version %s. To proceed, either choose another supported Terraform version or update this version constraint. Version constraints are normally set for good reason, so updating the constraint may lead to other errors or unexpected behavior.",
+						path, sourceAddr, tfversion.String(),
+					),
+					Subject: constraint.DeclRange.Ptr(),
+				})
+			}
+		}
+	}
+
+	return diags
+}
diff --git a/v1.5.7/internal/configs/module_call.go b/v1.5.7/internal/configs/module_call.go
new file mode 100644
index 0000000..fd115fa
--- /dev/null
+++ b/v1.5.7/internal/configs/module_call.go
@@ -0,0 +1,303 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/gohcl"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/getmodules"
+)
+
+// ModuleCall represents a "module" block in a module or file.
+type ModuleCall struct {
+	Name string
+
+	SourceAddr      addrs.ModuleSource
+	SourceAddrRaw   string
+	SourceAddrRange hcl.Range
+	SourceSet       bool
+
+	Config hcl.Body
+
+	Version VersionConstraint
+
+	Count   hcl.Expression
+	ForEach hcl.Expression
+
+	Providers []PassedProviderConfig
+
+	DependsOn []hcl.Traversal
+
+	DeclRange hcl.Range
+}
+
+func decodeModuleBlock(block *hcl.Block, override bool) (*ModuleCall, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+
+	mc := &ModuleCall{
+		Name:      block.Labels[0],
+		DeclRange: block.DefRange,
+	}
+
+	schema := moduleBlockSchema
+	if override {
+		schema = schemaForOverrides(schema)
+	}
+
+	content, remain, moreDiags := block.Body.PartialContent(schema)
+	diags = append(diags, moreDiags...)
+	mc.Config = remain
+
+	if !hclsyntax.ValidIdentifier(mc.Name) {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid module instance name",
+			Detail:   badIdentifierDetail,
+			Subject:  &block.LabelRanges[0],
+		})
+	}
+
+	haveVersionArg := false
+	if attr, exists := content.Attributes["version"]; exists {
+		var versionDiags hcl.Diagnostics
+		mc.Version, versionDiags = decodeVersionConstraint(attr)
+		diags = append(diags, versionDiags...)
+		haveVersionArg = true
+	}
+
+	if attr, exists := content.Attributes["source"]; exists {
+		mc.SourceSet = true
+		mc.SourceAddrRange = attr.Expr.Range()
+		valDiags := gohcl.DecodeExpression(attr.Expr, nil, &mc.SourceAddrRaw)
+		diags = append(diags, valDiags...)
+		if !valDiags.HasErrors() {
+			var addr addrs.ModuleSource
+			var err error
+			if haveVersionArg {
+				addr, err = addrs.ParseModuleSourceRegistry(mc.SourceAddrRaw)
+			} else {
+				addr, err = addrs.ParseModuleSource(mc.SourceAddrRaw)
+			}
+			mc.SourceAddr = addr
+			if err != nil {
+				// NOTE: We leave mc.SourceAddr as nil for any situation where the
+				// source attribute is invalid, so any code which tries to carefully
+				// use the partial result of a failed config decode must be
+				// resilient to that.
+				mc.SourceAddr = nil
+
+				// NOTE: In practice it's actually very unlikely to end up here,
+				// because our source address parser can turn just about any string
+				// into some sort of remote package address, and so for most errors
+				// we'll detect them only during module installation. There are
+				// still a _few_ purely-syntax errors we can catch at parsing time,
+				// though, mostly related to remote package sub-paths and local
+				// paths.
+				switch err := err.(type) {
+				case *getmodules.MaybeRelativePathErr:
+					diags = append(diags, &hcl.Diagnostic{
+						Severity: hcl.DiagError,
+						Summary:  "Invalid module source address",
+						Detail: fmt.Sprintf(
+							"Terraform failed to determine your intended installation method for remote module package %q.\n\nIf you intended this as a path relative to the current module, use \"./%s\" instead. The \"./\" prefix indicates that the address is a relative filesystem path.",
+							err.Addr, err.Addr,
+						),
+						Subject: mc.SourceAddrRange.Ptr(),
+					})
+				default:
+					if haveVersionArg {
+						// In this case we'll include some extra context that
+						// we assumed a registry source address due to the
+						// version argument.
+						diags = append(diags, &hcl.Diagnostic{
+							Severity: hcl.DiagError,
+							Summary:  "Invalid registry module source address",
+							Detail:   fmt.Sprintf("Failed to parse module registry address: %s.\n\nTerraform assumed that you intended a module registry source address because you also set the argument \"version\", which applies only to registry modules.", err),
+							Subject:  mc.SourceAddrRange.Ptr(),
+						})
+					} else {
+						diags = append(diags, &hcl.Diagnostic{
+							Severity: hcl.DiagError,
+							Summary:  "Invalid module source address",
+							Detail:   fmt.Sprintf("Failed to parse module source address: %s.", err),
+							Subject:  mc.SourceAddrRange.Ptr(),
+						})
+					}
+				}
+			}
+		}
+	}
+
+	if attr, exists := content.Attributes["count"]; exists {
+		mc.Count = attr.Expr
+	}
+
+	if attr, exists := content.Attributes["for_each"]; exists {
+		if mc.Count != nil {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  `Invalid combination of "count" and "for_each"`,
+				Detail:   `The "count" and "for_each" meta-arguments are mutually-exclusive, only one should be used to be explicit about the number of resources to be created.`,
+				Subject:  &attr.NameRange,
+			})
+		}
+
+		mc.ForEach = attr.Expr
+	}
+
+	if attr, exists := content.Attributes["depends_on"]; exists {
+		deps, depsDiags := decodeDependsOn(attr)
+		diags = append(diags, depsDiags...)
+		mc.DependsOn = append(mc.DependsOn, deps...)
+	}
+
+	if attr, exists := content.Attributes["providers"]; exists {
+		seen := make(map[string]hcl.Range)
+		pairs, pDiags := hcl.ExprMap(attr.Expr)
+		diags = append(diags, pDiags...)
+		for _, pair := range pairs {
+			key, keyDiags := decodeProviderConfigRef(pair.Key, "providers")
+			diags = append(diags, keyDiags...)
+			value, valueDiags := decodeProviderConfigRef(pair.Value, "providers")
+			diags = append(diags, valueDiags...)
+			if keyDiags.HasErrors() || valueDiags.HasErrors() {
+				continue
+			}
+
+			matchKey := key.String()
+			if prev, exists := seen[matchKey]; exists {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Duplicate provider address",
+					Detail:   fmt.Sprintf("A provider configuration was already passed to %s at %s. Each child provider configuration can be assigned only once.", matchKey, prev),
+					Subject:  pair.Value.Range().Ptr(),
+				})
+				continue
+			}
+
+			rng := hcl.RangeBetween(pair.Key.Range(), pair.Value.Range())
+			seen[matchKey] = rng
+			mc.Providers = append(mc.Providers, PassedProviderConfig{
+				InChild:  key,
+				InParent: value,
+			})
+		}
+	}
+
+	var seenEscapeBlock *hcl.Block
+	for _, block := range content.Blocks {
+		switch block.Type {
+		case "_":
+			if seenEscapeBlock != nil {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Duplicate escaping block",
+					Detail: fmt.Sprintf(
+						"The special block type \"_\" can be used to force particular arguments to be interpreted as module input variables rather than as meta-arguments, but each module block can have only one such block. The first escaping block was at %s.",
+						seenEscapeBlock.DefRange,
+					),
+					Subject: &block.DefRange,
+				})
+				continue
+			}
+			seenEscapeBlock = block
+
+			// When there's an escaping block its content merges with the
+			// existing config we extracted earlier, so later decoding
+			// will see a blend of both.
+			mc.Config = hcl.MergeBodies([]hcl.Body{mc.Config, block.Body})
+
+		default:
+			// All of the other block types in our schema are reserved.
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Reserved block type name in module block",
+				Detail:   fmt.Sprintf("The block type name %q is reserved for use by Terraform in a future version.", block.Type),
+				Subject:  &block.TypeRange,
+			})
+		}
+	}
+
+	return mc, diags
+}
+
+// EntersNewPackage returns true if this call is to an external module, either
+// directly via a remote source address or indirectly via a registry source
+// address.
+//
+// Other behaviors in Terraform may treat package crossings as a special
+// situation, because that indicates that the caller and callee can change
+// independently of one another and thus we should disallow using any features
+// where the caller assumes anything about the callee other than its input
+// variables, required provider configurations, and output values.
+func (mc *ModuleCall) EntersNewPackage() bool {
+	return moduleSourceAddrEntersNewPackage(mc.SourceAddr)
+}
+
+// PassedProviderConfig represents a provider config explicitly passed down to
+// a child module, possibly giving it a new local address in the process.
+type PassedProviderConfig struct {
+	InChild  *ProviderConfigRef
+	InParent *ProviderConfigRef
+}
+
+var moduleBlockSchema = &hcl.BodySchema{
+	Attributes: []hcl.AttributeSchema{
+		{
+			Name:     "source",
+			Required: true,
+		},
+		{
+			Name: "version",
+		},
+		{
+			Name: "count",
+		},
+		{
+			Name: "for_each",
+		},
+		{
+			Name: "depends_on",
+		},
+		{
+			Name: "providers",
+		},
+	},
+	Blocks: []hcl.BlockHeaderSchema{
+		{Type: "_"}, // meta-argument escaping block
+
+		// These are all reserved for future use.
+		{Type: "lifecycle"},
+		{Type: "locals"},
+		{Type: "provider", LabelNames: []string{"type"}},
+	},
+}
+
+func moduleSourceAddrEntersNewPackage(addr addrs.ModuleSource) bool {
+	switch addr.(type) {
+	case nil:
+		// There are only two situations where we should get here:
+		// - We've been asked about the source address of the root module,
+		//   which is always nil.
+		// - We've been asked about a ModuleCall that is part of the partial
+		//   result of a failed decode.
+		// The root module exists outside of all module packages, so we'll
+		// just return false for that case. For the error case it doesn't
+		// really matter what we return as long as we don't panic, because
+		// we only make a best-effort to allow careful inspection of objects
+		// representing invalid configuration.
+		return false
+	case addrs.ModuleSourceLocal:
+		// Local source addresses are the only address type that remains within
+		// the same package.
+		return false
+	default:
+		// All other address types enter a new package.
+		return true
+	}
+}
diff --git a/v1.5.7/internal/configs/module_call_test.go b/v1.5.7/internal/configs/module_call_test.go
new file mode 100644
index 0000000..412a090
--- /dev/null
+++ b/v1.5.7/internal/configs/module_call_test.go
@@ -0,0 +1,195 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"io/ioutil"
+	"testing"
+
+	"github.com/go-test/deep"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestLoadModuleCall(t *testing.T) {
+	src, err := ioutil.ReadFile("testdata/invalid-files/module-calls.tf")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	parser := testParser(map[string]string{
+		"module-calls.tf": string(src),
+	})
+
+	file, diags := parser.LoadConfigFile("module-calls.tf")
+	assertExactDiagnostics(t, diags, []string{
+		`module-calls.tf:20,3-11: Invalid combination of "count" and "for_each"; The "count" and "for_each" meta-arguments are mutually-exclusive, only one should be used to be explicit about the number of resources to be created.`,
+	})
+
+	gotModules := file.ModuleCalls
+	wantModules := []*ModuleCall{
+		{
+			Name:          "foo",
+			SourceAddr:    addrs.ModuleSourceLocal("./foo"),
+			SourceAddrRaw: "./foo",
+			SourceSet:     true,
+			SourceAddrRange: hcl.Range{
+				Filename: "module-calls.tf",
+				Start:    hcl.Pos{Line: 3, Column: 12, Byte: 27},
+				End:      hcl.Pos{Line: 3, Column: 19, Byte: 34},
+			},
+			DeclRange: hcl.Range{
+				Filename: "module-calls.tf",
+				Start:    hcl.Pos{Line: 2, Column: 1, Byte: 1},
+				End:      hcl.Pos{Line: 2, Column: 13, Byte: 13},
+			},
+		},
+		{
+			Name: "bar",
+			SourceAddr: addrs.ModuleSourceRegistry{
+				Package: addrs.ModuleRegistryPackage{
+					Host:         addrs.DefaultModuleRegistryHost,
+					Namespace:    "hashicorp",
+					Name:         "bar",
+					TargetSystem: "aws",
+				},
+			},
+			SourceAddrRaw: "hashicorp/bar/aws",
+			SourceSet:     true,
+			SourceAddrRange: hcl.Range{
+				Filename: "module-calls.tf",
+				Start:    hcl.Pos{Line: 8, Column: 12, Byte: 113},
+				End:      hcl.Pos{Line: 8, Column: 31, Byte: 132},
+			},
+			DeclRange: hcl.Range{
+				Filename: "module-calls.tf",
+				Start:    hcl.Pos{Line: 7, Column: 1, Byte: 87},
+				End:      hcl.Pos{Line: 7, Column: 13, Byte: 99},
+			},
+		},
+		{
+			Name: "baz",
+			SourceAddr: addrs.ModuleSourceRemote{
+				Package: addrs.ModulePackage("git::https://example.com/"),
+			},
+			SourceAddrRaw: "git::https://example.com/",
+			SourceSet:     true,
+			SourceAddrRange: hcl.Range{
+				Filename: "module-calls.tf",
+				Start:    hcl.Pos{Line: 15, Column: 12, Byte: 193},
+				End:      hcl.Pos{Line: 15, Column: 39, Byte: 220},
+			},
+			DependsOn: []hcl.Traversal{
+				{
+					hcl.TraverseRoot{
+						Name: "module",
+						SrcRange: hcl.Range{
+							Filename: "module-calls.tf",
+							Start:    hcl.Pos{Line: 23, Column: 5, Byte: 295},
+							End:      hcl.Pos{Line: 23, Column: 11, Byte: 301},
+						},
+					},
+					hcl.TraverseAttr{
+						Name: "bar",
+						SrcRange: hcl.Range{
+							Filename: "module-calls.tf",
+							Start:    hcl.Pos{Line: 23, Column: 11, Byte: 301},
+							End:      hcl.Pos{Line: 23, Column: 15, Byte: 305},
+						},
+					},
+				},
+			},
+			Providers: []PassedProviderConfig{
+				{
+					InChild: &ProviderConfigRef{
+						Name: "aws",
+						NameRange: hcl.Range{
+							Filename: "module-calls.tf",
+							Start:    hcl.Pos{Line: 27, Column: 5, Byte: 332},
+							End:      hcl.Pos{Line: 27, Column: 8, Byte: 335},
+						},
+					},
+					InParent: &ProviderConfigRef{
+						Name: "aws",
+						NameRange: hcl.Range{
+							Filename: "module-calls.tf",
+							Start:    hcl.Pos{Line: 27, Column: 11, Byte: 338},
+							End:      hcl.Pos{Line: 27, Column: 14, Byte: 341},
+						},
+						Alias: "foo",
+						AliasRange: &hcl.Range{
+							Filename: "module-calls.tf",
+							Start:    hcl.Pos{Line: 27, Column: 14, Byte: 341},
+							End:      hcl.Pos{Line: 27, Column: 18, Byte: 345},
+						},
+					},
+				},
+			},
+			DeclRange: hcl.Range{
+				Filename: "module-calls.tf",
+				Start:    hcl.Pos{Line: 14, Column: 1, Byte: 167},
+				End:      hcl.Pos{Line: 14, Column: 13, Byte: 179},
+			},
+		},
+	}
+
+	// We'll hide all of the bodies/exprs since we're treating them as opaque
+	// here anyway... the point of this test is to ensure we handle everything
+	// else properly.
+	for _, m := range gotModules {
+		m.Config = nil
+		m.Count = nil
+		m.ForEach = nil
+	}
+
+	for _, problem := range deep.Equal(gotModules, wantModules) {
+		t.Error(problem)
+	}
+}
+
+func TestModuleSourceAddrEntersNewPackage(t *testing.T) {
+	tests := []struct {
+		Addr string
+		Want bool
+	}{
+		{
+			"./",
+			false,
+		},
+		{
+			"../bork",
+			false,
+		},
+		{
+			"/absolute/path",
+			true,
+		},
+		{
+			"github.com/example/foo",
+			true,
+		},
+		{
+			"hashicorp/subnets/cidr", // registry module
+			true,
+		},
+		{
+			"registry.terraform.io/hashicorp/subnets/cidr", // registry module
+			true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Addr, func(t *testing.T) {
+			addr, err := addrs.ParseModuleSource(test.Addr)
+			if err != nil {
+				t.Fatalf("parsing failed for %q: %s", test.Addr, err)
+			}
+
+			got := moduleSourceAddrEntersNewPackage(addr)
+			if got != test.Want {
+				t.Errorf("wrong result for %q\ngot:  %#v\nwant:  %#v", addr, got, test.Want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/configs/module_merge.go b/v1.5.7/internal/configs/module_merge.go
new file mode 100644
index 0000000..104cc2c
--- /dev/null
+++ b/v1.5.7/internal/configs/module_merge.go
@@ -0,0 +1,274 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/convert"
+)
+
+// The methods in this file are used by Module.mergeFile to apply overrides
+// to our different configuration elements. These methods all follow the
+// pattern of mutating the receiver to incorporate settings from the parameter,
+// returning error diagnostics if any aspect of the parameter cannot be merged
+// into the receiver for some reason.
+//
+// User expectation is that anything _explicitly_ set in the given object
+// should take precedence over the corresponding settings in the receiver,
+// but that anything omitted in the given object should be left unchanged.
+// In some cases it may be reasonable to do a "deep merge" of certain nested
+// features, if it is possible to unambiguously correlate the nested elements
+// and their behaviors are orthogonal to each other.
+
+func (p *Provider) merge(op *Provider) hcl.Diagnostics {
+	var diags hcl.Diagnostics
+
+	if op.Version.Required != nil {
+		p.Version = op.Version
+	}
+
+	p.Config = MergeBodies(p.Config, op.Config)
+
+	return diags
+}
+
+func (v *Variable) merge(ov *Variable) hcl.Diagnostics {
+	var diags hcl.Diagnostics
+
+	if ov.DescriptionSet {
+		v.Description = ov.Description
+		v.DescriptionSet = ov.DescriptionSet
+	}
+	if ov.SensitiveSet {
+		v.Sensitive = ov.Sensitive
+		v.SensitiveSet = ov.SensitiveSet
+	}
+	if ov.Default != cty.NilVal {
+		v.Default = ov.Default
+	}
+	if ov.Type != cty.NilType {
+		v.Type = ov.Type
+		v.ConstraintType = ov.ConstraintType
+	}
+	if ov.ParsingMode != 0 {
+		v.ParsingMode = ov.ParsingMode
+	}
+	if ov.NullableSet {
+		v.Nullable = ov.Nullable
+		v.NullableSet = ov.NullableSet
+	}
+
+	// If the override file overrode type without default or vice-versa then
+	// it may have created an invalid situation, which we'll catch now by
+	// attempting to re-convert the value.
+	//
+	// Note that here we may be re-converting an already-converted base value
+	// from the base config. This will be a no-op if the type was not changed,
+	// but in particular might be user-observable in the edge case where the
+	// literal value in config could've been converted to the overridden type
+	// constraint but the converted value cannot. In practice, this situation
+	// should be rare since most of our conversions are interchangable.
+	if v.Default != cty.NilVal {
+		val, err := convert.Convert(v.Default, v.ConstraintType)
+		if err != nil {
+			// What exactly we'll say in the error message here depends on whether
+			// it was Default or Type that was overridden here.
+			switch {
+			case ov.Type != cty.NilType && ov.Default == cty.NilVal:
+				// If only the type was overridden
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid default value for variable",
+					Detail:   fmt.Sprintf("Overriding this variable's type constraint has made its default value invalid: %s.", err),
+					Subject:  &ov.DeclRange,
+				})
+			case ov.Type == cty.NilType && ov.Default != cty.NilVal:
+				// Only the default was overridden
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid default value for variable",
+					Detail:   fmt.Sprintf("The overridden default value for this variable is not compatible with the variable's type constraint: %s.", err),
+					Subject:  &ov.DeclRange,
+				})
+			default:
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid default value for variable",
+					Detail:   fmt.Sprintf("This variable's default value is not compatible with its type constraint: %s.", err),
+					Subject:  &ov.DeclRange,
+				})
+			}
+		} else {
+			v.Default = val
+		}
+
+		// ensure a null default wasn't merged in when it is not allowed
+		if !v.Nullable && v.Default.IsNull() {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid default value for variable",
+				Detail:   "A null default value is not valid when nullable=false.",
+				Subject:  &ov.DeclRange,
+			})
+		}
+	}
+
+	return diags
+}
+
+func (l *Local) merge(ol *Local) hcl.Diagnostics {
+	var diags hcl.Diagnostics
+
+	// Since a local is just a single expression in configuration, the
+	// override definition entirely replaces the base definition, including
+	// the source range so that we'll send the user to the right place if
+	// there is an error.
+	l.Expr = ol.Expr
+	l.DeclRange = ol.DeclRange
+
+	return diags
+}
+
+func (o *Output) merge(oo *Output) hcl.Diagnostics {
+	var diags hcl.Diagnostics
+
+	if oo.Description != "" {
+		o.Description = oo.Description
+	}
+	if oo.Expr != nil {
+		o.Expr = oo.Expr
+	}
+	if oo.SensitiveSet {
+		o.Sensitive = oo.Sensitive
+		o.SensitiveSet = oo.SensitiveSet
+	}
+
+	// We don't allow depends_on to be overridden because that is likely to
+	// cause confusing misbehavior.
+	if len(oo.DependsOn) != 0 {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Unsupported override",
+			Detail:   "The depends_on argument may not be overridden.",
+			Subject:  oo.DependsOn[0].SourceRange().Ptr(), // the first item is the closest range we have
+		})
+	}
+
+	return diags
+}
+
+func (mc *ModuleCall) merge(omc *ModuleCall) hcl.Diagnostics {
+	var diags hcl.Diagnostics
+
+	if omc.SourceSet {
+		mc.SourceAddr = omc.SourceAddr
+		mc.SourceAddrRaw = omc.SourceAddrRaw
+		mc.SourceAddrRange = omc.SourceAddrRange
+		mc.SourceSet = omc.SourceSet
+	}
+
+	if omc.Count != nil {
+		mc.Count = omc.Count
+	}
+
+	if omc.ForEach != nil {
+		mc.ForEach = omc.ForEach
+	}
+
+	if len(omc.Version.Required) != 0 {
+		mc.Version = omc.Version
+	}
+
+	mc.Config = MergeBodies(mc.Config, omc.Config)
+
+	if len(omc.Providers) != 0 {
+		mc.Providers = omc.Providers
+	}
+
+	// We don't allow depends_on to be overridden because that is likely to
+	// cause confusing misbehavior.
+	if len(omc.DependsOn) != 0 {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Unsupported override",
+			Detail:   "The depends_on argument may not be overridden.",
+			Subject:  omc.DependsOn[0].SourceRange().Ptr(), // the first item is the closest range we have
+		})
+	}
+
+	return diags
+}
+
+func (r *Resource) merge(or *Resource, rps map[string]*RequiredProvider) hcl.Diagnostics {
+	var diags hcl.Diagnostics
+
+	if r.Mode != or.Mode {
+		// This is always a programming error, since managed and data resources
+		// are kept in separate maps in the configuration structures.
+		panic(fmt.Errorf("can't merge %s into %s", or.Mode, r.Mode))
+	}
+
+	if or.Count != nil {
+		r.Count = or.Count
+	}
+	if or.ForEach != nil {
+		r.ForEach = or.ForEach
+	}
+
+	if or.ProviderConfigRef != nil {
+		r.ProviderConfigRef = or.ProviderConfigRef
+		if existing, exists := rps[or.ProviderConfigRef.Name]; exists {
+			r.Provider = existing.Type
+		} else {
+			r.Provider = addrs.ImpliedProviderForUnqualifiedType(r.ProviderConfigRef.Name)
+		}
+	}
+
+	// Provider FQN is set by Terraform during Merge
+
+	if r.Mode == addrs.ManagedResourceMode {
+		// or.Managed is always non-nil for managed resource mode
+
+		if or.Managed.Connection != nil {
+			r.Managed.Connection = or.Managed.Connection
+		}
+		if or.Managed.CreateBeforeDestroySet {
+			r.Managed.CreateBeforeDestroy = or.Managed.CreateBeforeDestroy
+			r.Managed.CreateBeforeDestroySet = or.Managed.CreateBeforeDestroySet
+		}
+		if len(or.Managed.IgnoreChanges) != 0 {
+			r.Managed.IgnoreChanges = or.Managed.IgnoreChanges
+		}
+		if or.Managed.IgnoreAllChanges {
+			r.Managed.IgnoreAllChanges = true
+		}
+		if or.Managed.PreventDestroySet {
+			r.Managed.PreventDestroy = or.Managed.PreventDestroy
+			r.Managed.PreventDestroySet = or.Managed.PreventDestroySet
+		}
+		if len(or.Managed.Provisioners) != 0 {
+			r.Managed.Provisioners = or.Managed.Provisioners
+		}
+	}
+
+	r.Config = MergeBodies(r.Config, or.Config)
+
+	// We don't allow depends_on to be overridden because that is likely to
+	// cause confusing misbehavior.
+	if len(or.DependsOn) != 0 {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Unsupported override",
+			Detail:   "The depends_on argument may not be overridden.",
+			Subject:  or.DependsOn[0].SourceRange().Ptr(), // the first item is the closest range we have
+		})
+	}
+
+	return diags
+}
diff --git a/v1.5.7/internal/configs/module_merge_body.go b/v1.5.7/internal/configs/module_merge_body.go
new file mode 100644
index 0000000..a07905d
--- /dev/null
+++ b/v1.5.7/internal/configs/module_merge_body.go
@@ -0,0 +1,144 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"github.com/hashicorp/hcl/v2"
+)
+
+// MergeBodies creates a new HCL body that contains a combination of the
+// given base and override bodies. Attributes and blocks defined in the
+// override body take precedence over those of the same name defined in
+// the base body.
+//
+// If any block of a particular type appears in "override" then it will
+// replace _all_ of the blocks of the same type in "base" in the new
+// body.
+func MergeBodies(base, override hcl.Body) hcl.Body {
+	return mergeBody{
+		Base:     base,
+		Override: override,
+	}
+}
+
+// mergeBody is a hcl.Body implementation that wraps a pair of other bodies
+// and allows attributes and blocks within the override to take precedence
+// over those defined in the base body.
+//
+// This is used to deal with dynamically-processed bodies in Module.mergeFile.
+// It uses a shallow-only merging strategy where direct attributes defined
+// in Override will override attributes of the same name in Base, while any
+// blocks defined in Override will hide all blocks of the same type in Base.
+//
+// This cannot possibly "do the right thing" in all cases, because we don't
+// have enough information about user intent. However, this behavior is intended
+// to be reasonable for simple overriding use-cases.
+type mergeBody struct {
+	Base     hcl.Body
+	Override hcl.Body
+}
+
+var _ hcl.Body = mergeBody{}
+
+func (b mergeBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+	baseSchema := schemaWithDynamic(schema)
+	overrideSchema := schemaWithDynamic(schemaForOverrides(schema))
+
+	baseContent, _, cDiags := b.Base.PartialContent(baseSchema)
+	diags = append(diags, cDiags...)
+	overrideContent, _, cDiags := b.Override.PartialContent(overrideSchema)
+	diags = append(diags, cDiags...)
+
+	content := b.prepareContent(baseContent, overrideContent)
+
+	return content, diags
+}
+
+func (b mergeBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+	baseSchema := schemaWithDynamic(schema)
+	overrideSchema := schemaWithDynamic(schemaForOverrides(schema))
+
+	baseContent, baseRemain, cDiags := b.Base.PartialContent(baseSchema)
+	diags = append(diags, cDiags...)
+	overrideContent, overrideRemain, cDiags := b.Override.PartialContent(overrideSchema)
+	diags = append(diags, cDiags...)
+
+	content := b.prepareContent(baseContent, overrideContent)
+
+	remain := MergeBodies(baseRemain, overrideRemain)
+
+	return content, remain, diags
+}
+
+func (b mergeBody) prepareContent(base *hcl.BodyContent, override *hcl.BodyContent) *hcl.BodyContent {
+	content := &hcl.BodyContent{
+		Attributes: make(hcl.Attributes),
+	}
+
+	// For attributes we just assign from each map in turn and let the override
+	// map clobber any matching entries from base.
+	for k, a := range base.Attributes {
+		content.Attributes[k] = a
+	}
+	for k, a := range override.Attributes {
+		content.Attributes[k] = a
+	}
+
+	// Things are a little more interesting for blocks because they arrive
+	// as a flat list. Our merging semantics call for us to suppress blocks
+	// from base if at least one block of the same type appears in override.
+	// We explicitly do not try to correlate and deeply merge nested blocks,
+	// since we don't have enough context here to infer user intent.
+
+	overriddenBlockTypes := make(map[string]bool)
+	for _, block := range override.Blocks {
+		if block.Type == "dynamic" {
+			overriddenBlockTypes[block.Labels[0]] = true
+			continue
+		}
+		overriddenBlockTypes[block.Type] = true
+	}
+	for _, block := range base.Blocks {
+		// We skip over dynamic blocks whose type label is an overridden type
+		// but note that below we do still leave them as dynamic blocks in
+		// the result because expanding the dynamic blocks that are left is
+		// done much later during the core graph walks, where we can safely
+		// evaluate the expressions.
+		if block.Type == "dynamic" && overriddenBlockTypes[block.Labels[0]] {
+			continue
+		}
+		if overriddenBlockTypes[block.Type] {
+			continue
+		}
+		content.Blocks = append(content.Blocks, block)
+	}
+	content.Blocks = append(content.Blocks, override.Blocks...)
+
+	return content
+}
+
+func (b mergeBody) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+	ret := make(hcl.Attributes)
+
+	baseAttrs, aDiags := b.Base.JustAttributes()
+	diags = append(diags, aDiags...)
+	overrideAttrs, aDiags := b.Override.JustAttributes()
+	diags = append(diags, aDiags...)
+
+	for k, a := range baseAttrs {
+		ret[k] = a
+	}
+	for k, a := range overrideAttrs {
+		ret[k] = a
+	}
+
+	return ret, diags
+}
+
+func (b mergeBody) MissingItemRange() hcl.Range {
+	return b.Base.MissingItemRange()
+}
diff --git a/v1.5.7/internal/configs/module_merge_test.go b/v1.5.7/internal/configs/module_merge_test.go
new file mode 100644
index 0000000..30f2b65
--- /dev/null
+++ b/v1.5.7/internal/configs/module_merge_test.go
@@ -0,0 +1,355 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/gohcl"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestModuleOverrideVariable(t *testing.T) {
+	mod, diags := testModuleFromDir("testdata/valid-modules/override-variable")
+	assertNoDiagnostics(t, diags)
+	if mod == nil {
+		t.Fatalf("module is nil")
+	}
+
+	got := mod.Variables
+	want := map[string]*Variable{
+		"fully_overridden": {
+			Name:           "fully_overridden",
+			Description:    "b_override description",
+			DescriptionSet: true,
+			Default:        cty.StringVal("b_override"),
+			Nullable:       false,
+			NullableSet:    true,
+			Type:           cty.String,
+			ConstraintType: cty.String,
+			ParsingMode:    VariableParseLiteral,
+			DeclRange: hcl.Range{
+				Filename: "testdata/valid-modules/override-variable/primary.tf",
+				Start: hcl.Pos{
+					Line:   1,
+					Column: 1,
+					Byte:   0,
+				},
+				End: hcl.Pos{
+					Line:   1,
+					Column: 28,
+					Byte:   27,
+				},
+			},
+		},
+		"partially_overridden": {
+			Name:           "partially_overridden",
+			Description:    "base description",
+			DescriptionSet: true,
+			Default:        cty.StringVal("b_override partial"),
+			Nullable:       true,
+			NullableSet:    false,
+			Type:           cty.String,
+			ConstraintType: cty.String,
+			ParsingMode:    VariableParseLiteral,
+			DeclRange: hcl.Range{
+				Filename: "testdata/valid-modules/override-variable/primary.tf",
+				Start: hcl.Pos{
+					Line:   7,
+					Column: 1,
+					Byte:   103,
+				},
+				End: hcl.Pos{
+					Line:   7,
+					Column: 32,
+					Byte:   134,
+				},
+			},
+		},
+	}
+	assertResultDeepEqual(t, got, want)
+}
+
+func TestModuleOverrideModule(t *testing.T) {
+	mod, diags := testModuleFromDir("testdata/valid-modules/override-module")
+	assertNoDiagnostics(t, diags)
+	if mod == nil {
+		t.Fatalf("module is nil")
+	}
+
+	if _, exists := mod.ModuleCalls["example"]; !exists {
+		t.Fatalf("no module 'example'")
+	}
+	if len(mod.ModuleCalls) != 1 {
+		t.Fatalf("wrong number of module calls in result %d; want 1", len(mod.ModuleCalls))
+	}
+
+	got := mod.ModuleCalls["example"]
+	want := &ModuleCall{
+		Name:          "example",
+		SourceAddr:    addrs.ModuleSourceLocal("./example2-a_override"),
+		SourceAddrRaw: "./example2-a_override",
+		SourceAddrRange: hcl.Range{
+			Filename: "testdata/valid-modules/override-module/a_override.tf",
+			Start: hcl.Pos{
+				Line:   3,
+				Column: 12,
+				Byte:   31,
+			},
+			End: hcl.Pos{
+				Line:   3,
+				Column: 35,
+				Byte:   54,
+			},
+		},
+		SourceSet: true,
+		DeclRange: hcl.Range{
+			Filename: "testdata/valid-modules/override-module/primary.tf",
+			Start: hcl.Pos{
+				Line:   2,
+				Column: 1,
+				Byte:   1,
+			},
+			End: hcl.Pos{
+				Line:   2,
+				Column: 17,
+				Byte:   17,
+			},
+		},
+		DependsOn: []hcl.Traversal{
+			{
+				hcl.TraverseRoot{
+					Name: "null_resource",
+					SrcRange: hcl.Range{
+						Filename: "testdata/valid-modules/override-module/primary.tf",
+						Start:    hcl.Pos{Line: 11, Column: 17, Byte: 149},
+						End:      hcl.Pos{Line: 11, Column: 30, Byte: 162},
+					},
+				},
+				hcl.TraverseAttr{
+					Name: "test",
+					SrcRange: hcl.Range{
+						Filename: "testdata/valid-modules/override-module/primary.tf",
+						Start:    hcl.Pos{Line: 11, Column: 30, Byte: 162},
+						End:      hcl.Pos{Line: 11, Column: 35, Byte: 167},
+					},
+				},
+			},
+		},
+		Providers: []PassedProviderConfig{
+			{
+				InChild: &ProviderConfigRef{
+					Name: "test",
+					NameRange: hcl.Range{
+						Filename: "testdata/valid-modules/override-module/b_override.tf",
+						Start:    hcl.Pos{Line: 7, Column: 5, Byte: 97},
+						End:      hcl.Pos{Line: 7, Column: 9, Byte: 101},
+					},
+				},
+				InParent: &ProviderConfigRef{
+					Name: "test",
+					NameRange: hcl.Range{
+						Filename: "testdata/valid-modules/override-module/b_override.tf",
+						Start:    hcl.Pos{Line: 7, Column: 12, Byte: 104},
+						End:      hcl.Pos{Line: 7, Column: 16, Byte: 108},
+					},
+					Alias: "b_override",
+					AliasRange: &hcl.Range{
+						Filename: "testdata/valid-modules/override-module/b_override.tf",
+						Start:    hcl.Pos{Line: 7, Column: 16, Byte: 108},
+						End:      hcl.Pos{Line: 7, Column: 27, Byte: 119},
+					},
+				},
+			},
+		},
+	}
+
+	// We're going to extract and nil out our hcl.Body here because DeepEqual
+	// is not a useful way to assert on that.
+	gotConfig := got.Config
+	got.Config = nil
+
+	assertResultDeepEqual(t, got, want)
+
+	type content struct {
+		Kept  *string `hcl:"kept"`
+		Foo   *string `hcl:"foo"`
+		New   *string `hcl:"new"`
+		Newer *string `hcl:"newer"`
+	}
+	var gotArgs content
+	diags = gohcl.DecodeBody(gotConfig, nil, &gotArgs)
+	assertNoDiagnostics(t, diags)
+
+	wantArgs := content{
+		Kept:  stringPtr("primary kept"),
+		Foo:   stringPtr("a_override foo"),
+		New:   stringPtr("b_override new"),
+		Newer: stringPtr("b_override newer"),
+	}
+
+	assertResultDeepEqual(t, gotArgs, wantArgs)
+}
+
+func TestModuleOverrideDynamic(t *testing.T) {
+	schema := &hcl.BodySchema{
+		Blocks: []hcl.BlockHeaderSchema{
+			{Type: "foo"},
+			{Type: "dynamic", LabelNames: []string{"type"}},
+		},
+	}
+
+	t.Run("base is dynamic", func(t *testing.T) {
+		mod, diags := testModuleFromDir("testdata/valid-modules/override-dynamic-block-base")
+		assertNoDiagnostics(t, diags)
+		if mod == nil {
+			t.Fatalf("module is nil")
+		}
+
+		if _, exists := mod.ManagedResources["test.foo"]; !exists {
+			t.Fatalf("no module 'example'")
+		}
+		if len(mod.ManagedResources) != 1 {
+			t.Fatalf("wrong number of managed resources in result %d; want 1", len(mod.ManagedResources))
+		}
+
+		body := mod.ManagedResources["test.foo"].Config
+		content, diags := body.Content(schema)
+		assertNoDiagnostics(t, diags)
+
+		if len(content.Blocks) != 1 {
+			t.Fatalf("wrong number of blocks in result %d; want 1", len(content.Blocks))
+		}
+		if got, want := content.Blocks[0].Type, "foo"; got != want {
+			t.Fatalf("wrong block type %q; want %q", got, want)
+		}
+	})
+	t.Run("override is dynamic", func(t *testing.T) {
+		mod, diags := testModuleFromDir("testdata/valid-modules/override-dynamic-block-override")
+		assertNoDiagnostics(t, diags)
+		if mod == nil {
+			t.Fatalf("module is nil")
+		}
+
+		if _, exists := mod.ManagedResources["test.foo"]; !exists {
+			t.Fatalf("no module 'example'")
+		}
+		if len(mod.ManagedResources) != 1 {
+			t.Fatalf("wrong number of managed resources in result %d; want 1", len(mod.ManagedResources))
+		}
+
+		body := mod.ManagedResources["test.foo"].Config
+		content, diags := body.Content(schema)
+		assertNoDiagnostics(t, diags)
+
+		if len(content.Blocks) != 1 {
+			t.Fatalf("wrong number of blocks in result %d; want 1", len(content.Blocks))
+		}
+		if got, want := content.Blocks[0].Type, "dynamic"; got != want {
+			t.Fatalf("wrong block type %q; want %q", got, want)
+		}
+		if got, want := content.Blocks[0].Labels[0], "foo"; got != want {
+			t.Fatalf("wrong dynamic block label %q; want %q", got, want)
+		}
+	})
+}
+
+func TestModuleOverrideSensitiveVariable(t *testing.T) {
+	type testCase struct {
+		sensitive    bool
+		sensitiveSet bool
+	}
+	cases := map[string]testCase{
+		"false_true": {
+			sensitive:    true,
+			sensitiveSet: true,
+		},
+		"true_false": {
+			sensitive:    false,
+			sensitiveSet: true,
+		},
+		"false_false_true": {
+			sensitive:    true,
+			sensitiveSet: true,
+		},
+		"true_true_false": {
+			sensitive:    false,
+			sensitiveSet: true,
+		},
+		"false_true_false": {
+			sensitive:    false,
+			sensitiveSet: true,
+		},
+		"true_false_true": {
+			sensitive:    true,
+			sensitiveSet: true,
+		},
+	}
+
+	mod, diags := testModuleFromDir("testdata/valid-modules/override-variable-sensitive")
+
+	assertNoDiagnostics(t, diags)
+
+	if mod == nil {
+		t.Fatalf("module is nil")
+	}
+
+	got := mod.Variables
+
+	for v, want := range cases {
+		t.Run(fmt.Sprintf("variable %s", v), func(t *testing.T) {
+			if got[v].Sensitive != want.sensitive {
+				t.Errorf("wrong result for sensitive\ngot: %t want: %t", got[v].Sensitive, want.sensitive)
+			}
+
+			if got[v].SensitiveSet != want.sensitiveSet {
+				t.Errorf("wrong result for sensitive set\ngot: %t want: %t", got[v].Sensitive, want.sensitive)
+			}
+		})
+	}
+}
+
+func TestModuleOverrideResourceFQNs(t *testing.T) {
+	mod, diags := testModuleFromDir("testdata/valid-modules/override-resource-provider")
+	assertNoDiagnostics(t, diags)
+
+	got := mod.ManagedResources["test_instance.explicit"]
+	wantProvider := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "bar", "test")
+	wantProviderCfg := &ProviderConfigRef{
+		Name: "bar-test",
+		NameRange: hcl.Range{
+			Filename: "testdata/valid-modules/override-resource-provider/a_override.tf",
+			Start:    hcl.Pos{Line: 2, Column: 14, Byte: 51},
+			End:      hcl.Pos{Line: 2, Column: 22, Byte: 59},
+		},
+	}
+
+	if !got.Provider.Equals(wantProvider) {
+		t.Fatalf("wrong provider %s, want %s", got.Provider, wantProvider)
+	}
+	assertResultDeepEqual(t, got.ProviderConfigRef, wantProviderCfg)
+
+	// now verify that a resource with no provider config falls back to default
+	got = mod.ManagedResources["test_instance.default"]
+	wantProvider = addrs.NewDefaultProvider("test")
+	if !got.Provider.Equals(wantProvider) {
+		t.Fatalf("wrong provider %s, want %s", got.Provider, wantProvider)
+	}
+	if got.ProviderConfigRef != nil {
+		t.Fatalf("wrong result: found provider config ref %s, expected nil", got.ProviderConfigRef)
+	}
+}
+
+func TestModuleOverrideIgnoreAllChanges(t *testing.T) {
+	mod, diags := testModuleFromDir("testdata/valid-modules/override-ignore-changes")
+	assertNoDiagnostics(t, diags)
+
+	r := mod.ManagedResources["test_instance.foo"]
+	if !r.Managed.IgnoreAllChanges {
+		t.Fatalf("wrong result: expected r.Managed.IgnoreAllChanges to be true")
+	}
+}
diff --git a/v1.5.7/internal/configs/module_test.go b/v1.5.7/internal/configs/module_test.go
new file mode 100644
index 0000000..47fd8b7
--- /dev/null
+++ b/v1.5.7/internal/configs/module_test.go
@@ -0,0 +1,418 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// TestNewModule_provider_fqns exercises module.gatherProviderLocalNames()
+func TestNewModule_provider_local_name(t *testing.T) {
+	mod, diags := testModuleFromDir("testdata/providers-explicit-fqn")
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	p := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "foo", "test")
+	if name, exists := mod.ProviderLocalNames[p]; !exists {
+		t.Fatal("provider FQN foo/test not found")
+	} else {
+		if name != "foo-test" {
+			t.Fatalf("provider localname mismatch: got %s, want foo-test", name)
+		}
+	}
+
+	// ensure the reverse lookup (fqn to local name) works as well
+	localName := mod.LocalNameForProvider(p)
+	if localName != "foo-test" {
+		t.Fatal("provider local name not found")
+	}
+
+	// if there is not a local name for a provider, it should return the type name
+	localName = mod.LocalNameForProvider(addrs.NewDefaultProvider("nonexist"))
+	if localName != "nonexist" {
+		t.Error("wrong local name returned for a non-local provider")
+	}
+
+	// can also look up the "terraform" provider and see that it sources is
+	// allowed to be overridden, even though there is a builtin provider
+	// called "terraform".
+	p = addrs.NewProvider(addrs.DefaultProviderRegistryHost, "not-builtin", "not-terraform")
+	if name, exists := mod.ProviderLocalNames[p]; !exists {
+		t.Fatal("provider FQN not-builtin/not-terraform not found")
+	} else {
+		if name != "terraform" {
+			t.Fatalf("provider localname mismatch: got %s, want terraform", name)
+		}
+	}
+}
+
+// This test validates the provider FQNs set in each Resource
+func TestNewModule_resource_providers(t *testing.T) {
+	cfg, diags := testNestedModuleConfigFromDir(t, "testdata/valid-modules/nested-providers-fqns")
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	// both the root and child module have two resources, one which should use
+	// the default implied provider and one explicitly using a provider set in
+	// required_providers
+	wantImplicit := addrs.NewDefaultProvider("test")
+	wantFoo := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "foo", "test")
+	wantBar := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "bar", "test")
+
+	// root module
+	if !cfg.Module.ManagedResources["test_instance.explicit"].Provider.Equals(wantFoo) {
+		t.Fatalf("wrong provider for \"test_instance.explicit\"\ngot:  %s\nwant: %s",
+			cfg.Module.ManagedResources["test_instance.explicit"].Provider,
+			wantFoo,
+		)
+	}
+	if !cfg.Module.ManagedResources["test_instance.implicit"].Provider.Equals(wantImplicit) {
+		t.Fatalf("wrong provider for \"test_instance.implicit\"\ngot:  %s\nwant: %s",
+			cfg.Module.ManagedResources["test_instance.implicit"].Provider,
+			wantImplicit,
+		)
+	}
+
+	// a data source
+	if !cfg.Module.DataResources["data.test_resource.explicit"].Provider.Equals(wantFoo) {
+		t.Fatalf("wrong provider for \"module.child.test_instance.explicit\"\ngot:  %s\nwant: %s",
+			cfg.Module.ManagedResources["test_instance.explicit"].Provider,
+			wantBar,
+		)
+	}
+
+	// child module
+	cm := cfg.Children["child"].Module
+	if !cm.ManagedResources["test_instance.explicit"].Provider.Equals(wantBar) {
+		t.Fatalf("wrong provider for \"module.child.test_instance.explicit\"\ngot:  %s\nwant: %s",
+			cfg.Module.ManagedResources["test_instance.explicit"].Provider,
+			wantBar,
+		)
+	}
+	if !cm.ManagedResources["test_instance.implicit"].Provider.Equals(wantImplicit) {
+		t.Fatalf("wrong provider for \"module.child.test_instance.implicit\"\ngot:  %s\nwant: %s",
+			cfg.Module.ManagedResources["test_instance.implicit"].Provider,
+			wantImplicit,
+		)
+	}
+}
+
+func TestProviderForLocalConfig(t *testing.T) {
+	mod, diags := testModuleFromDir("testdata/providers-explicit-fqn")
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+	lc := addrs.LocalProviderConfig{LocalName: "foo-test"}
+	got := mod.ProviderForLocalConfig(lc)
+	want := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "foo", "test")
+	if !got.Equals(want) {
+		t.Fatalf("wrong result! got %#v, want %#v\n", got, want)
+	}
+}
+
+// At most one required_providers block per module is permitted.
+func TestModule_required_providers_multiple(t *testing.T) {
+	_, diags := testModuleFromDir("testdata/invalid-modules/multiple-required-providers")
+	if !diags.HasErrors() {
+		t.Fatal("module should have error diags, but does not")
+	}
+
+	want := `Duplicate required providers configuration`
+	if got := diags.Error(); !strings.Contains(got, want) {
+		t.Fatalf("expected error to contain %q\nerror was:\n%s", want, got)
+	}
+}
+
+// A module may have required_providers configured in files loaded later than
+// resources. These provider settings should still be reflected in the
+// resources' configuration.
+func TestModule_required_providers_after_resource(t *testing.T) {
+	mod, diags := testModuleFromDir("testdata/valid-modules/required-providers-after-resource")
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	want := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "foo", "test")
+
+	req, exists := mod.ProviderRequirements.RequiredProviders["test"]
+	if !exists {
+		t.Fatal("no provider requirements found for \"test\"")
+	}
+	if req.Type != want {
+		t.Errorf("wrong provider addr for \"test\"\ngot:  %s\nwant: %s",
+			req.Type, want,
+		)
+	}
+
+	if got := mod.ManagedResources["test_instance.my-instance"].Provider; !got.Equals(want) {
+		t.Errorf("wrong provider addr for \"test_instance.my-instance\"\ngot:  %s\nwant: %s",
+			got, want,
+		)
+	}
+}
+
+// We support overrides for required_providers blocks, which should replace the
+// entire block for each provider localname, leaving other blocks unaffected.
+// This should also be reflected in any resources in the module using this
+// provider.
+func TestModule_required_provider_overrides(t *testing.T) {
+	mod, diags := testModuleFromDir("testdata/valid-modules/required-providers-overrides")
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	// The foo provider and resource should be unaffected
+	want := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "acme", "foo")
+	req, exists := mod.ProviderRequirements.RequiredProviders["foo"]
+	if !exists {
+		t.Fatal("no provider requirements found for \"foo\"")
+	}
+	if req.Type != want {
+		t.Errorf("wrong provider addr for \"foo\"\ngot:  %s\nwant: %s",
+			req.Type, want,
+		)
+	}
+	if got := mod.ManagedResources["foo_thing.ft"].Provider; !got.Equals(want) {
+		t.Errorf("wrong provider addr for \"foo_thing.ft\"\ngot:  %s\nwant: %s",
+			got, want,
+		)
+	}
+
+	// The bar provider and resource should be using the override config
+	want = addrs.NewProvider(addrs.DefaultProviderRegistryHost, "blorp", "bar")
+	req, exists = mod.ProviderRequirements.RequiredProviders["bar"]
+	if !exists {
+		t.Fatal("no provider requirements found for \"bar\"")
+	}
+	if req.Type != want {
+		t.Errorf("wrong provider addr for \"bar\"\ngot:  %s\nwant: %s",
+			req.Type, want,
+		)
+	}
+	if gotVer, wantVer := req.Requirement.Required.String(), "~>2.0.0"; gotVer != wantVer {
+		t.Errorf("wrong provider version constraint for \"bar\"\ngot:  %s\nwant: %s",
+			gotVer, wantVer,
+		)
+	}
+	if got := mod.ManagedResources["bar_thing.bt"].Provider; !got.Equals(want) {
+		t.Errorf("wrong provider addr for \"bar_thing.bt\"\ngot:  %s\nwant: %s",
+			got, want,
+		)
+	}
+}
+
+// Resources without explicit provider configuration are assigned a provider
+// implied based on the resource type. For example, this resource:
+//
+//	resource "foo_instance" "test" {}
+//
+// ...is assigned to whichever provider has local name "foo" in the current
+// module.
+//
+// To find the correct provider, we first look in the module's provider
+// requirements map for a local name matching the resource type, and fall back
+// to a default provider if none is found. This applies to both managed and
+// data resources.
+func TestModule_implied_provider(t *testing.T) {
+	mod, diags := testModuleFromDir("testdata/valid-modules/implied-providers")
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	// The three providers used in the config resources
+	foo := addrs.NewProvider("registry.acme.corp", "acme", "foo")
+	whatever := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "acme", "something")
+	bar := addrs.NewDefaultProvider("bar")
+
+	// Verify that the registry.acme.corp/acme/foo provider is defined in the
+	// module provider requirements with local name "foo"
+	req, exists := mod.ProviderRequirements.RequiredProviders["foo"]
+	if !exists {
+		t.Fatal("no provider requirements found for \"foo\"")
+	}
+	if req.Type != foo {
+		t.Errorf("wrong provider addr for \"foo\"\ngot:  %s\nwant: %s",
+			req.Type, foo,
+		)
+	}
+
+	// Verify that the acme/something provider is defined in the
+	// module provider requirements with local name "whatever"
+	req, exists = mod.ProviderRequirements.RequiredProviders["whatever"]
+	if !exists {
+		t.Fatal("no provider requirements found for \"foo\"")
+	}
+	if req.Type != whatever {
+		t.Errorf("wrong provider addr for \"whatever\"\ngot:  %s\nwant: %s",
+			req.Type, whatever,
+		)
+	}
+
+	// Check that resources are assigned the correct providers: foo_* resources
+	// should have the custom foo provider, bar_* resources the default bar
+	// provider.
+	tests := []struct {
+		Address  string
+		Provider addrs.Provider
+	}{
+		{"foo_resource.a", foo},
+		{"data.foo_resource.b", foo},
+		{"bar_resource.c", bar},
+		{"data.bar_resource.d", bar},
+		{"whatever_resource.e", whatever},
+		{"data.whatever_resource.f", whatever},
+	}
+	for _, test := range tests {
+		resources := mod.ManagedResources
+		if strings.HasPrefix(test.Address, "data.") {
+			resources = mod.DataResources
+		}
+		resource, exists := resources[test.Address]
+		if !exists {
+			t.Errorf("could not find resource %q in %#v", test.Address, resources)
+			continue
+		}
+		if got := resource.Provider; !got.Equals(test.Provider) {
+			t.Errorf("wrong provider addr for %q\ngot:  %s\nwant: %s",
+				test.Address, got, test.Provider,
+			)
+		}
+	}
+}
+
+func TestImpliedProviderForUnqualifiedType(t *testing.T) {
+	mod, diags := testModuleFromDir("testdata/valid-modules/implied-providers")
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	foo := addrs.NewProvider("registry.acme.corp", "acme", "foo")
+	whatever := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "acme", "something")
+	bar := addrs.NewDefaultProvider("bar")
+	tf := addrs.NewBuiltInProvider("terraform")
+
+	tests := []struct {
+		Type     string
+		Provider addrs.Provider
+	}{
+		{"foo", foo},
+		{"whatever", whatever},
+		{"bar", bar},
+		{"terraform", tf},
+	}
+	for _, test := range tests {
+		got := mod.ImpliedProviderForUnqualifiedType(test.Type)
+		if !got.Equals(test.Provider) {
+			t.Errorf("wrong result for %q: got %#v, want %#v\n", test.Type, got, test.Provider)
+		}
+	}
+}
+
+func TestModule_backend_override(t *testing.T) {
+	mod, diags := testModuleFromDir("testdata/valid-modules/override-backend")
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	gotType := mod.Backend.Type
+	wantType := "bar"
+
+	if gotType != wantType {
+		t.Errorf("wrong result for backend type: got %#v, want %#v\n", gotType, wantType)
+	}
+
+	attrs, _ := mod.Backend.Config.JustAttributes()
+
+	gotAttr, diags := attrs["path"].Expr.Value(nil)
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	wantAttr := cty.StringVal("CHANGED/relative/path/to/terraform.tfstate")
+
+	if !gotAttr.RawEquals(wantAttr) {
+		t.Errorf("wrong result for backend 'path': got %#v, want %#v\n", gotAttr, wantAttr)
+	}
+}
+
+// Unlike most other overrides, backend blocks do not require a base configuration in a primary
+// configuration file, as an omitted backend there implies the local backend.
+func TestModule_backend_override_no_base(t *testing.T) {
+	mod, diags := testModuleFromDir("testdata/valid-modules/override-backend-no-base")
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	if mod.Backend == nil {
+		t.Errorf("expected module Backend not to be nil")
+	}
+}
+
+func TestModule_cloud_override_backend(t *testing.T) {
+	mod, diags := testModuleFromDir("testdata/valid-modules/override-backend-with-cloud")
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	if mod.Backend != nil {
+		t.Errorf("expected module Backend to be nil")
+	}
+
+	if mod.CloudConfig == nil {
+		t.Errorf("expected module CloudConfig not to be nil")
+	}
+}
+
+// Unlike most other overrides, cloud blocks do not require a base configuration in a primary
+// configuration file, as an omitted backend there implies the local backend and cloud blocks
+// override backends.
+func TestModule_cloud_override_no_base(t *testing.T) {
+	mod, diags := testModuleFromDir("testdata/valid-modules/override-cloud-no-base")
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	if mod.CloudConfig == nil {
+		t.Errorf("expected module CloudConfig not to be nil")
+	}
+}
+
+func TestModule_cloud_override(t *testing.T) {
+	mod, diags := testModuleFromDir("testdata/valid-modules/override-cloud")
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	attrs, _ := mod.CloudConfig.Config.JustAttributes()
+
+	gotAttr, diags := attrs["organization"].Expr.Value(nil)
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	wantAttr := cty.StringVal("CHANGED")
+
+	if !gotAttr.RawEquals(wantAttr) {
+		t.Errorf("wrong result for Cloud 'organization': got %#v, want %#v\n", gotAttr, wantAttr)
+	}
+
+	// The override should have completely replaced the cloud block in the primary file, no merging
+	if attrs["should_not_be_present_with_override"] != nil {
+		t.Errorf("expected 'should_not_be_present_with_override' attribute to be nil")
+	}
+}
+
+func TestModule_cloud_duplicate_overrides(t *testing.T) {
+	_, diags := testModuleFromDir("testdata/invalid-modules/override-cloud-duplicates")
+	want := `Duplicate Terraform Cloud configurations`
+	if got := diags.Error(); !strings.Contains(got, want) {
+		t.Fatalf("expected module error to contain %q\nerror was:\n%s", want, got)
+	}
+}
diff --git a/v1.5.7/internal/configs/moved.go b/v1.5.7/internal/configs/moved.go
new file mode 100644
index 0000000..ee8b068
--- /dev/null
+++ b/v1.5.7/internal/configs/moved.go
@@ -0,0 +1,75 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+type Moved struct {
+	From *addrs.MoveEndpoint
+	To   *addrs.MoveEndpoint
+
+	DeclRange hcl.Range
+}
+
+func decodeMovedBlock(block *hcl.Block) (*Moved, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+	moved := &Moved{
+		DeclRange: block.DefRange,
+	}
+
+	content, moreDiags := block.Body.Content(movedBlockSchema)
+	diags = append(diags, moreDiags...)
+
+	if attr, exists := content.Attributes["from"]; exists {
+		from, traversalDiags := hcl.AbsTraversalForExpr(attr.Expr)
+		diags = append(diags, traversalDiags...)
+		if !traversalDiags.HasErrors() {
+			from, fromDiags := addrs.ParseMoveEndpoint(from)
+			diags = append(diags, fromDiags.ToHCL()...)
+			moved.From = from
+		}
+	}
+
+	if attr, exists := content.Attributes["to"]; exists {
+		to, traversalDiags := hcl.AbsTraversalForExpr(attr.Expr)
+		diags = append(diags, traversalDiags...)
+		if !traversalDiags.HasErrors() {
+			to, toDiags := addrs.ParseMoveEndpoint(to)
+			diags = append(diags, toDiags.ToHCL()...)
+			moved.To = to
+		}
+	}
+
+	// we can only move from a module to a module, resource to resource, etc.
+	if !diags.HasErrors() {
+		if !moved.From.MightUnifyWith(moved.To) {
+			// We can catch some obviously-wrong combinations early here,
+			// but we still have other dynamic validation to do at runtime.
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid \"moved\" addresses",
+				Detail:   "The \"from\" and \"to\" addresses must either both refer to resources or both refer to modules.",
+				Subject:  &moved.DeclRange,
+			})
+		}
+	}
+
+	return moved, diags
+}
+
+var movedBlockSchema = &hcl.BodySchema{
+	Attributes: []hcl.AttributeSchema{
+		{
+			Name:     "from",
+			Required: true,
+		},
+		{
+			Name:     "to",
+			Required: true,
+		},
+	},
+}
diff --git a/v1.5.7/internal/configs/moved_test.go b/v1.5.7/internal/configs/moved_test.go
new file mode 100644
index 0000000..4d4998b
--- /dev/null
+++ b/v1.5.7/internal/configs/moved_test.go
@@ -0,0 +1,211 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcltest"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestMovedBlock_decode(t *testing.T) {
+	blockRange := hcl.Range{
+		Filename: "mock.tf",
+		Start:    hcl.Pos{Line: 3, Column: 12, Byte: 27},
+		End:      hcl.Pos{Line: 3, Column: 19, Byte: 34},
+	}
+
+	foo_expr := hcltest.MockExprTraversalSrc("test_instance.foo")
+	bar_expr := hcltest.MockExprTraversalSrc("test_instance.bar")
+
+	foo_index_expr := hcltest.MockExprTraversalSrc("test_instance.foo[1]")
+	bar_index_expr := hcltest.MockExprTraversalSrc("test_instance.bar[\"one\"]")
+
+	mod_foo_expr := hcltest.MockExprTraversalSrc("module.foo")
+	mod_bar_expr := hcltest.MockExprTraversalSrc("module.bar")
+
+	tests := map[string]struct {
+		input *hcl.Block
+		want  *Moved
+		err   string
+	}{
+		"success": {
+			&hcl.Block{
+				Type: "moved",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"from": {
+							Name: "from",
+							Expr: foo_expr,
+						},
+						"to": {
+							Name: "to",
+							Expr: bar_expr,
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			&Moved{
+				From:      mustMoveEndpointFromExpr(foo_expr),
+				To:        mustMoveEndpointFromExpr(bar_expr),
+				DeclRange: blockRange,
+			},
+			``,
+		},
+		"indexed resources": {
+			&hcl.Block{
+				Type: "moved",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"from": {
+							Name: "from",
+							Expr: foo_index_expr,
+						},
+						"to": {
+							Name: "to",
+							Expr: bar_index_expr,
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			&Moved{
+				From:      mustMoveEndpointFromExpr(foo_index_expr),
+				To:        mustMoveEndpointFromExpr(bar_index_expr),
+				DeclRange: blockRange,
+			},
+			``,
+		},
+		"modules": {
+			&hcl.Block{
+				Type: "moved",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"from": {
+							Name: "from",
+							Expr: mod_foo_expr,
+						},
+						"to": {
+							Name: "to",
+							Expr: mod_bar_expr,
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			&Moved{
+				From:      mustMoveEndpointFromExpr(mod_foo_expr),
+				To:        mustMoveEndpointFromExpr(mod_bar_expr),
+				DeclRange: blockRange,
+			},
+			``,
+		},
+		"error: missing argument": {
+			&hcl.Block{
+				Type: "moved",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"from": {
+							Name: "from",
+							Expr: foo_expr,
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			&Moved{
+				From:      mustMoveEndpointFromExpr(foo_expr),
+				DeclRange: blockRange,
+			},
+			"Missing required argument",
+		},
+		"error: type mismatch": {
+			&hcl.Block{
+				Type: "moved",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"to": {
+							Name: "to",
+							Expr: foo_expr,
+						},
+						"from": {
+							Name: "from",
+							Expr: mod_foo_expr,
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			&Moved{
+				To:        mustMoveEndpointFromExpr(foo_expr),
+				From:      mustMoveEndpointFromExpr(mod_foo_expr),
+				DeclRange: blockRange,
+			},
+			"Invalid \"moved\" addresses",
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got, diags := decodeMovedBlock(test.input)
+
+			if diags.HasErrors() {
+				if test.err == "" {
+					t.Fatalf("unexpected error: %s", diags.Errs())
+				}
+				if gotErr := diags[0].Summary; gotErr != test.err {
+					t.Errorf("wrong error, got %q, want %q", gotErr, test.err)
+				}
+			} else if test.err != "" {
+				t.Fatal("expected error")
+			}
+
+			if !cmp.Equal(got, test.want, cmp.AllowUnexported(addrs.MoveEndpoint{})) {
+				t.Fatalf("wrong result: %s", cmp.Diff(got, test.want))
+			}
+		})
+	}
+}
+
+func TestMovedBlock_inModule(t *testing.T) {
+	parser := NewParser(nil)
+	mod, diags := parser.LoadConfigDir("testdata/valid-modules/moved-blocks")
+	if diags.HasErrors() {
+		t.Errorf("unexpected error: %s", diags.Error())
+	}
+
+	var gotPairs [][2]string
+	for _, mc := range mod.Moved {
+		gotPairs = append(gotPairs, [2]string{mc.From.String(), mc.To.String()})
+	}
+	wantPairs := [][2]string{
+		{`test.foo`, `test.bar`},
+		{`test.foo`, `test.bar["bloop"]`},
+		{`module.a`, `module.b`},
+		{`module.a`, `module.a["foo"]`},
+		{`test.foo`, `module.a.test.foo`},
+		{`data.test.foo`, `data.test.bar`},
+	}
+	if diff := cmp.Diff(wantPairs, gotPairs); diff != "" {
+		t.Errorf("wrong addresses\n%s", diff)
+	}
+}
+
+func mustMoveEndpointFromExpr(expr hcl.Expression) *addrs.MoveEndpoint {
+	traversal, hcldiags := hcl.AbsTraversalForExpr(expr)
+	if hcldiags.HasErrors() {
+		panic(hcldiags.Errs())
+	}
+
+	ep, diags := addrs.ParseMoveEndpoint(traversal)
+	if diags.HasErrors() {
+		panic(diags.Err())
+	}
+
+	return ep
+}
diff --git a/v1.5.7/internal/configs/named_values.go b/v1.5.7/internal/configs/named_values.go
new file mode 100644
index 0000000..02891b7
--- /dev/null
+++ b/v1.5.7/internal/configs/named_values.go
@@ -0,0 +1,572 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/ext/typeexpr"
+	"github.com/hashicorp/hcl/v2/gohcl"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/convert"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// A consistent detail message for all "not a valid identifier" diagnostics.
+const badIdentifierDetail = "A name must start with a letter or underscore and may contain only letters, digits, underscores, and dashes."
+
+// Variable represents a "variable" block in a module or file.
+type Variable struct {
+	Name        string
+	Description string
+	Default     cty.Value
+
+	// Type is the concrete type of the variable value.
+	Type cty.Type
+	// ConstraintType is used for decoding and type conversions, and may
+	// contain nested ObjectWithOptionalAttr types.
+	ConstraintType cty.Type
+	TypeDefaults   *typeexpr.Defaults
+
+	ParsingMode VariableParsingMode
+	Validations []*CheckRule
+	Sensitive   bool
+
+	DescriptionSet bool
+	SensitiveSet   bool
+
+	// Nullable indicates that null is a valid value for this variable. Setting
+	// Nullable to false means that the module can expect this variable to
+	// never be null.
+	Nullable    bool
+	NullableSet bool
+
+	DeclRange hcl.Range
+}
+
+func decodeVariableBlock(block *hcl.Block, override bool) (*Variable, hcl.Diagnostics) {
+	v := &Variable{
+		Name:      block.Labels[0],
+		DeclRange: block.DefRange,
+	}
+
+	// Unless we're building an override, we'll set some defaults
+	// which we might override with attributes below. We leave these
+	// as zero-value in the override case so we can recognize whether
+	// or not they are set when we merge.
+	if !override {
+		v.Type = cty.DynamicPseudoType
+		v.ConstraintType = cty.DynamicPseudoType
+		v.ParsingMode = VariableParseLiteral
+	}
+
+	content, diags := block.Body.Content(variableBlockSchema)
+
+	if !hclsyntax.ValidIdentifier(v.Name) {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid variable name",
+			Detail:   badIdentifierDetail,
+			Subject:  &block.LabelRanges[0],
+		})
+	}
+
+	// Don't allow declaration of variables that would conflict with the
+	// reserved attribute and block type names in a "module" block, since
+	// these won't be usable for child modules.
+	for _, attr := range moduleBlockSchema.Attributes {
+		if attr.Name == v.Name {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid variable name",
+				Detail:   fmt.Sprintf("The variable name %q is reserved due to its special meaning inside module blocks.", attr.Name),
+				Subject:  &block.LabelRanges[0],
+			})
+		}
+	}
+	for _, blockS := range moduleBlockSchema.Blocks {
+		if blockS.Type == v.Name {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid variable name",
+				Detail:   fmt.Sprintf("The variable name %q is reserved due to its special meaning inside module blocks.", blockS.Type),
+				Subject:  &block.LabelRanges[0],
+			})
+		}
+	}
+
+	if attr, exists := content.Attributes["description"]; exists {
+		valDiags := gohcl.DecodeExpression(attr.Expr, nil, &v.Description)
+		diags = append(diags, valDiags...)
+		v.DescriptionSet = true
+	}
+
+	if attr, exists := content.Attributes["type"]; exists {
+		ty, tyDefaults, parseMode, tyDiags := decodeVariableType(attr.Expr)
+		diags = append(diags, tyDiags...)
+		v.ConstraintType = ty
+		v.TypeDefaults = tyDefaults
+		v.Type = ty.WithoutOptionalAttributesDeep()
+		v.ParsingMode = parseMode
+	}
+
+	if attr, exists := content.Attributes["sensitive"]; exists {
+		valDiags := gohcl.DecodeExpression(attr.Expr, nil, &v.Sensitive)
+		diags = append(diags, valDiags...)
+		v.SensitiveSet = true
+	}
+
+	if attr, exists := content.Attributes["nullable"]; exists {
+		valDiags := gohcl.DecodeExpression(attr.Expr, nil, &v.Nullable)
+		diags = append(diags, valDiags...)
+		v.NullableSet = true
+	} else {
+		// The current default is true, which is subject to change in a future
+		// language edition.
+		v.Nullable = true
+	}
+
+	if attr, exists := content.Attributes["default"]; exists {
+		val, valDiags := attr.Expr.Value(nil)
+		diags = append(diags, valDiags...)
+
+		// Convert the default to the expected type so we can catch invalid
+		// defaults early and allow later code to assume validity.
+		// Note that this depends on us having already processed any "type"
+		// attribute above.
+		// However, we can't do this if we're in an override file where
+		// the type might not be set; we'll catch that during merge.
+		if v.ConstraintType != cty.NilType {
+			var err error
+			// If the type constraint has defaults, we must apply those
+			// defaults to the variable default value before type conversion,
+			// unless the default value is null. Null is excluded from the
+			// type default application process as a special case, to allow
+			// nullable variables to have a null default value.
+			if v.TypeDefaults != nil && !val.IsNull() {
+				val = v.TypeDefaults.Apply(val)
+			}
+			val, err = convert.Convert(val, v.ConstraintType)
+			if err != nil {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid default value for variable",
+					Detail:   fmt.Sprintf("This default value is not compatible with the variable's type constraint: %s.", err),
+					Subject:  attr.Expr.Range().Ptr(),
+				})
+				val = cty.DynamicVal
+			}
+		}
+
+		if !v.Nullable && val.IsNull() {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid default value for variable",
+				Detail:   "A null default value is not valid when nullable=false.",
+				Subject:  attr.Expr.Range().Ptr(),
+			})
+		}
+
+		v.Default = val
+	}
+
+	for _, block := range content.Blocks {
+		switch block.Type {
+
+		case "validation":
+			vv, moreDiags := decodeVariableValidationBlock(v.Name, block, override)
+			diags = append(diags, moreDiags...)
+			v.Validations = append(v.Validations, vv)
+
+		default:
+			// The above cases should be exhaustive for all block types
+			// defined in variableBlockSchema
+			panic(fmt.Sprintf("unhandled block type %q", block.Type))
+		}
+	}
+
+	return v, diags
+}
+
+func decodeVariableType(expr hcl.Expression) (cty.Type, *typeexpr.Defaults, VariableParsingMode, hcl.Diagnostics) {
+	if exprIsNativeQuotedString(expr) {
+		// If a user provides the pre-0.12 form of variable type argument where
+		// the string values "string", "list" and "map" are accepted, we
+		// provide an error to point the user towards using the type system
+		// correctly has a hint.
+		// Only the native syntax ends up in this codepath; we handle the
+		// JSON syntax (which is, of course, quoted within the type system)
+		// in the normal codepath below.
+		val, diags := expr.Value(nil)
+		if diags.HasErrors() {
+			return cty.DynamicPseudoType, nil, VariableParseHCL, diags
+		}
+		str := val.AsString()
+		switch str {
+		case "string":
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid quoted type constraints",
+				Detail:   "Terraform 0.11 and earlier required type constraints to be given in quotes, but that form is now deprecated and will be removed in a future version of Terraform. Remove the quotes around \"string\".",
+				Subject:  expr.Range().Ptr(),
+			})
+			return cty.DynamicPseudoType, nil, VariableParseLiteral, diags
+		case "list":
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid quoted type constraints",
+				Detail:   "Terraform 0.11 and earlier required type constraints to be given in quotes, but that form is now deprecated and will be removed in a future version of Terraform. Remove the quotes around \"list\" and write list(string) instead to explicitly indicate that the list elements are strings.",
+				Subject:  expr.Range().Ptr(),
+			})
+			return cty.DynamicPseudoType, nil, VariableParseHCL, diags
+		case "map":
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid quoted type constraints",
+				Detail:   "Terraform 0.11 and earlier required type constraints to be given in quotes, but that form is now deprecated and will be removed in a future version of Terraform. Remove the quotes around \"map\" and write map(string) instead to explicitly indicate that the map elements are strings.",
+				Subject:  expr.Range().Ptr(),
+			})
+			return cty.DynamicPseudoType, nil, VariableParseHCL, diags
+		default:
+			return cty.DynamicPseudoType, nil, VariableParseHCL, hcl.Diagnostics{{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid legacy variable type hint",
+				Detail:   `To provide a full type expression, remove the surrounding quotes and give the type expression directly.`,
+				Subject:  expr.Range().Ptr(),
+			}}
+		}
+	}
+
+	// First we'll deal with some shorthand forms that the HCL-level type
+	// expression parser doesn't include. These both emulate pre-0.12 behavior
+	// of allowing a list or map of any element type as long as all of the
+	// elements are consistent. This is the same as list(any) or map(any).
+	switch hcl.ExprAsKeyword(expr) {
+	case "list":
+		return cty.List(cty.DynamicPseudoType), nil, VariableParseHCL, nil
+	case "map":
+		return cty.Map(cty.DynamicPseudoType), nil, VariableParseHCL, nil
+	}
+
+	ty, typeDefaults, diags := typeexpr.TypeConstraintWithDefaults(expr)
+	if diags.HasErrors() {
+		return cty.DynamicPseudoType, nil, VariableParseHCL, diags
+	}
+
+	switch {
+	case ty.IsPrimitiveType():
+		// Primitive types use literal parsing.
+		return ty, typeDefaults, VariableParseLiteral, diags
+	default:
+		// Everything else uses HCL parsing
+		return ty, typeDefaults, VariableParseHCL, diags
+	}
+}
+
+func (v *Variable) Addr() addrs.InputVariable {
+	return addrs.InputVariable{Name: v.Name}
+}
+
+// Required returns true if this variable is required to be set by the caller,
+// or false if there is a default value that will be used when it isn't set.
+func (v *Variable) Required() bool {
+	return v.Default == cty.NilVal
+}
+
+// VariableParsingMode defines how values of a particular variable given by
+// text-only mechanisms (command line arguments and environment variables)
+// should be parsed to produce the final value.
+type VariableParsingMode rune
+
+// VariableParseLiteral is a variable parsing mode that just takes the given
+// string directly as a cty.String value.
+const VariableParseLiteral VariableParsingMode = 'L'
+
+// VariableParseHCL is a variable parsing mode that attempts to parse the given
+// string as an HCL expression and returns the result.
+const VariableParseHCL VariableParsingMode = 'H'
+
+// Parse uses the receiving parsing mode to process the given variable value
+// string, returning the result along with any diagnostics.
+//
+// A VariableParsingMode does not know the expected type of the corresponding
+// variable, so it's the caller's responsibility to attempt to convert the
+// result to the appropriate type and return to the user any diagnostics that
+// conversion may produce.
+//
+// The given name is used to create a synthetic filename in case any diagnostics
+// must be generated about the given string value. This should be the name
+// of the root module variable whose value will be populated from the given
+// string.
+//
+// If the returned diagnostics has errors, the returned value may not be
+// valid.
+func (m VariableParsingMode) Parse(name, value string) (cty.Value, hcl.Diagnostics) {
+	switch m {
+	case VariableParseLiteral:
+		return cty.StringVal(value), nil
+	case VariableParseHCL:
+		fakeFilename := fmt.Sprintf("<value for var.%s>", name)
+		expr, diags := hclsyntax.ParseExpression([]byte(value), fakeFilename, hcl.Pos{Line: 1, Column: 1})
+		if diags.HasErrors() {
+			return cty.DynamicVal, diags
+		}
+		val, valDiags := expr.Value(nil)
+		diags = append(diags, valDiags...)
+		return val, diags
+	default:
+		// Should never happen
+		panic(fmt.Errorf("Parse called on invalid VariableParsingMode %#v", m))
+	}
+}
+
+// decodeVariableValidationBlock is a wrapper around decodeCheckRuleBlock
+// that imposes the additional rule that the condition expression can refer
+// only to an input variable of the given name.
+func decodeVariableValidationBlock(varName string, block *hcl.Block, override bool) (*CheckRule, hcl.Diagnostics) {
+	vv, diags := decodeCheckRuleBlock(block, override)
+	if vv.Condition != nil {
+		// The validation condition can only refer to the variable itself,
+		// to ensure that the variable declaration can't create additional
+		// edges in the dependency graph.
+		goodRefs := 0
+		for _, traversal := range vv.Condition.Variables() {
+			ref, moreDiags := addrs.ParseRef(traversal)
+			if !moreDiags.HasErrors() {
+				if addr, ok := ref.Subject.(addrs.InputVariable); ok {
+					if addr.Name == varName {
+						goodRefs++
+						continue // Reference is valid
+					}
+				}
+			}
+			// If we fall out here then the reference is invalid.
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid reference in variable validation",
+				Detail:   fmt.Sprintf("The condition for variable %q can only refer to the variable itself, using var.%s.", varName, varName),
+				Subject:  traversal.SourceRange().Ptr(),
+			})
+		}
+		if goodRefs < 1 {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid variable validation condition",
+				Detail:   fmt.Sprintf("The condition for variable %q must refer to var.%s in order to test incoming values.", varName, varName),
+				Subject:  vv.Condition.Range().Ptr(),
+			})
+		}
+	}
+
+	if vv.ErrorMessage != nil {
+		// The same applies to the validation error message, except that
+		// references are not required. A string literal is a valid error
+		// message.
+		goodRefs := 0
+		for _, traversal := range vv.ErrorMessage.Variables() {
+			ref, moreDiags := addrs.ParseRef(traversal)
+			if !moreDiags.HasErrors() {
+				if addr, ok := ref.Subject.(addrs.InputVariable); ok {
+					if addr.Name == varName {
+						goodRefs++
+						continue // Reference is valid
+					}
+				}
+			}
+			// If we fall out here then the reference is invalid.
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid reference in variable validation",
+				Detail:   fmt.Sprintf("The error message for variable %q can only refer to the variable itself, using var.%s.", varName, varName),
+				Subject:  traversal.SourceRange().Ptr(),
+			})
+		}
+	}
+
+	return vv, diags
+}
+
+// Output represents an "output" block in a module or file.
+type Output struct {
+	Name        string
+	Description string
+	Expr        hcl.Expression
+	DependsOn   []hcl.Traversal
+	Sensitive   bool
+
+	Preconditions []*CheckRule
+
+	DescriptionSet bool
+	SensitiveSet   bool
+
+	DeclRange hcl.Range
+}
+
+func decodeOutputBlock(block *hcl.Block, override bool) (*Output, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+
+	o := &Output{
+		Name:      block.Labels[0],
+		DeclRange: block.DefRange,
+	}
+
+	schema := outputBlockSchema
+	if override {
+		schema = schemaForOverrides(schema)
+	}
+
+	content, moreDiags := block.Body.Content(schema)
+	diags = append(diags, moreDiags...)
+
+	if !hclsyntax.ValidIdentifier(o.Name) {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid output name",
+			Detail:   badIdentifierDetail,
+			Subject:  &block.LabelRanges[0],
+		})
+	}
+
+	if attr, exists := content.Attributes["description"]; exists {
+		valDiags := gohcl.DecodeExpression(attr.Expr, nil, &o.Description)
+		diags = append(diags, valDiags...)
+		o.DescriptionSet = true
+	}
+
+	if attr, exists := content.Attributes["value"]; exists {
+		o.Expr = attr.Expr
+	}
+
+	if attr, exists := content.Attributes["sensitive"]; exists {
+		valDiags := gohcl.DecodeExpression(attr.Expr, nil, &o.Sensitive)
+		diags = append(diags, valDiags...)
+		o.SensitiveSet = true
+	}
+
+	if attr, exists := content.Attributes["depends_on"]; exists {
+		deps, depsDiags := decodeDependsOn(attr)
+		diags = append(diags, depsDiags...)
+		o.DependsOn = append(o.DependsOn, deps...)
+	}
+
+	for _, block := range content.Blocks {
+		switch block.Type {
+		case "precondition":
+			cr, moreDiags := decodeCheckRuleBlock(block, override)
+			diags = append(diags, moreDiags...)
+			o.Preconditions = append(o.Preconditions, cr)
+		case "postcondition":
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Postconditions are not allowed",
+				Detail:   "Output values can only have preconditions, not postconditions.",
+				Subject:  block.TypeRange.Ptr(),
+			})
+		default:
+			// The cases above should be exhaustive for all block types
+			// defined in the block type schema, so this shouldn't happen.
+			panic(fmt.Sprintf("unexpected lifecycle sub-block type %q", block.Type))
+		}
+	}
+
+	return o, diags
+}
+
+func (o *Output) Addr() addrs.OutputValue {
+	return addrs.OutputValue{Name: o.Name}
+}
+
+// Local represents a single entry from a "locals" block in a module or file.
+// The "locals" block itself is not represented, because it serves only to
+// provide context for us to interpret its contents.
+type Local struct {
+	Name string
+	Expr hcl.Expression
+
+	DeclRange hcl.Range
+}
+
+func decodeLocalsBlock(block *hcl.Block) ([]*Local, hcl.Diagnostics) {
+	attrs, diags := block.Body.JustAttributes()
+	if len(attrs) == 0 {
+		return nil, diags
+	}
+
+	locals := make([]*Local, 0, len(attrs))
+	for name, attr := range attrs {
+		if !hclsyntax.ValidIdentifier(name) {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid local value name",
+				Detail:   badIdentifierDetail,
+				Subject:  &attr.NameRange,
+			})
+		}
+
+		locals = append(locals, &Local{
+			Name:      name,
+			Expr:      attr.Expr,
+			DeclRange: attr.Range,
+		})
+	}
+	return locals, diags
+}
+
+// Addr returns the address of the local value declared by the receiver,
+// relative to its containing module.
+func (l *Local) Addr() addrs.LocalValue {
+	return addrs.LocalValue{
+		Name: l.Name,
+	}
+}
+
+var variableBlockSchema = &hcl.BodySchema{
+	Attributes: []hcl.AttributeSchema{
+		{
+			Name: "description",
+		},
+		{
+			Name: "default",
+		},
+		{
+			Name: "type",
+		},
+		{
+			Name: "sensitive",
+		},
+		{
+			Name: "nullable",
+		},
+	},
+	Blocks: []hcl.BlockHeaderSchema{
+		{
+			Type: "validation",
+		},
+	},
+}
+
+var outputBlockSchema = &hcl.BodySchema{
+	Attributes: []hcl.AttributeSchema{
+		{
+			Name: "description",
+		},
+		{
+			Name:     "value",
+			Required: true,
+		},
+		{
+			Name: "depends_on",
+		},
+		{
+			Name: "sensitive",
+		},
+	},
+	Blocks: []hcl.BlockHeaderSchema{
+		{Type: "precondition"},
+		{Type: "postcondition"},
+	},
+}
diff --git a/v1.5.7/internal/configs/parser.go b/v1.5.7/internal/configs/parser.go
new file mode 100644
index 0000000..17df9b2
--- /dev/null
+++ b/v1.5.7/internal/configs/parser.go
@@ -0,0 +1,123 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclparse"
+	"github.com/spf13/afero"
+)
+
+// Parser is the main interface to read configuration files and other related
+// files from disk.
+//
+// It retains a cache of all files that are loaded so that they can be used
+// to create source code snippets in diagnostics, etc.
+type Parser struct {
+	fs afero.Afero
+	p  *hclparse.Parser
+
+	// allowExperiments controls whether we will allow modules to opt in to
+	// experimental language features. In main code this will be set only
+	// for alpha releases and some development builds. Test code must decide
+	// for itself whether to enable it so that tests can cover both the
+	// allowed and not-allowed situations.
+	allowExperiments bool
+}
+
+// NewParser creates and returns a new Parser that reads files from the given
+// filesystem. If a nil filesystem is passed then the system's "real" filesystem
+// will be used, via afero.OsFs.
+func NewParser(fs afero.Fs) *Parser {
+	if fs == nil {
+		fs = afero.OsFs{}
+	}
+
+	return &Parser{
+		fs: afero.Afero{Fs: fs},
+		p:  hclparse.NewParser(),
+	}
+}
+
+// LoadHCLFile is a low-level method that reads the file at the given path,
+// parses it, and returns the hcl.Body representing its root. In many cases
+// it is better to use one of the other Load*File methods on this type,
+// which additionally decode the root body in some way and return a higher-level
+// construct.
+//
+// If the file cannot be read at all -- e.g. because it does not exist -- then
+// this method will return a nil body and error diagnostics. In this case
+// callers may wish to ignore the provided error diagnostics and produce
+// a more context-sensitive error instead.
+//
+// The file will be parsed using the HCL native syntax unless the filename
+// ends with ".json", in which case the HCL JSON syntax will be used.
+func (p *Parser) LoadHCLFile(path string) (hcl.Body, hcl.Diagnostics) {
+	src, err := p.fs.ReadFile(path)
+
+	if err != nil {
+		return nil, hcl.Diagnostics{
+			{
+				Severity: hcl.DiagError,
+				Summary:  "Failed to read file",
+				Detail:   fmt.Sprintf("The file %q could not be read.", path),
+			},
+		}
+	}
+
+	var file *hcl.File
+	var diags hcl.Diagnostics
+	switch {
+	case strings.HasSuffix(path, ".json"):
+		file, diags = p.p.ParseJSON(src, path)
+	default:
+		file, diags = p.p.ParseHCL(src, path)
+	}
+
+	// If the returned file or body is nil, then we'll return a non-nil empty
+	// body so we'll meet our contract that nil means an error reading the file.
+	if file == nil || file.Body == nil {
+		return hcl.EmptyBody(), diags
+	}
+
+	return file.Body, diags
+}
+
+// Sources returns a map of the cached source buffers for all files that
+// have been loaded through this parser, with source filenames (as requested
+// when each file was opened) as the keys.
+func (p *Parser) Sources() map[string][]byte {
+	return p.p.Sources()
+}
+
+// ForceFileSource artificially adds source code to the cache of file sources,
+// as if it had been loaded from the given filename.
+//
+// This should be used only in special situations where configuration is loaded
+// some other way. Most callers should load configuration via methods of
+// Parser, which will update the sources cache automatically.
+func (p *Parser) ForceFileSource(filename string, src []byte) {
+	// We'll make a synthetic hcl.File here just so we can reuse the
+	// existing cache.
+	p.p.AddFile(filename, &hcl.File{
+		Body:  hcl.EmptyBody(),
+		Bytes: src,
+	})
+}
+
+// AllowLanguageExperiments specifies whether subsequent LoadConfigFile (and
+// similar) calls will allow opting in to experimental language features.
+//
+// If this method is never called for a particular parser, the default behavior
+// is to disallow language experiments.
+//
+// Main code should set this only for alpha or development builds. Test code
+// is responsible for deciding for itself whether and how to call this
+// method.
+func (p *Parser) AllowLanguageExperiments(allowed bool) {
+	p.allowExperiments = allowed
+}
diff --git a/v1.5.7/internal/configs/parser_config.go b/v1.5.7/internal/configs/parser_config.go
new file mode 100644
index 0000000..f1a1c55
--- /dev/null
+++ b/v1.5.7/internal/configs/parser_config.go
@@ -0,0 +1,333 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"github.com/hashicorp/hcl/v2"
+)
+
+// LoadConfigFile reads the file at the given path and parses it as a config
+// file.
+//
+// If the file cannot be read -- for example, if it does not exist -- then
+// a nil *File will be returned along with error diagnostics. Callers may wish
+// to disregard the returned diagnostics in this case and instead generate
+// their own error message(s) with additional context.
+//
+// If the returned diagnostics has errors when a non-nil map is returned
+// then the map may be incomplete but should be valid enough for careful
+// static analysis.
+//
+// This method wraps LoadHCLFile, and so it inherits the syntax selection
+// behaviors documented for that method.
+func (p *Parser) LoadConfigFile(path string) (*File, hcl.Diagnostics) {
+	return p.loadConfigFile(path, false)
+}
+
+// LoadConfigFileOverride is the same as LoadConfigFile except that it relaxes
+// certain required attribute constraints in order to interpret the given
+// file as an overrides file.
+func (p *Parser) LoadConfigFileOverride(path string) (*File, hcl.Diagnostics) {
+	return p.loadConfigFile(path, true)
+}
+
+func (p *Parser) loadConfigFile(path string, override bool) (*File, hcl.Diagnostics) {
+	body, diags := p.LoadHCLFile(path)
+	if body == nil {
+		return nil, diags
+	}
+
+	file := &File{}
+
+	var reqDiags hcl.Diagnostics
+	file.CoreVersionConstraints, reqDiags = sniffCoreVersionRequirements(body)
+	diags = append(diags, reqDiags...)
+
+	// We'll load the experiments first because other decoding logic in the
+	// loop below might depend on these experiments.
+	var expDiags hcl.Diagnostics
+	file.ActiveExperiments, expDiags = sniffActiveExperiments(body, p.allowExperiments)
+	diags = append(diags, expDiags...)
+
+	content, contentDiags := body.Content(configFileSchema)
+	diags = append(diags, contentDiags...)
+
+	for _, block := range content.Blocks {
+		switch block.Type {
+
+		case "terraform":
+			content, contentDiags := block.Body.Content(terraformBlockSchema)
+			diags = append(diags, contentDiags...)
+
+			// We ignore the "terraform_version", "language" and "experiments"
+			// attributes here because sniffCoreVersionRequirements and
+			// sniffActiveExperiments already dealt with those above.
+
+			for _, innerBlock := range content.Blocks {
+				switch innerBlock.Type {
+
+				case "backend":
+					backendCfg, cfgDiags := decodeBackendBlock(innerBlock)
+					diags = append(diags, cfgDiags...)
+					if backendCfg != nil {
+						file.Backends = append(file.Backends, backendCfg)
+					}
+
+				case "cloud":
+					cloudCfg, cfgDiags := decodeCloudBlock(innerBlock)
+					diags = append(diags, cfgDiags...)
+					if cloudCfg != nil {
+						file.CloudConfigs = append(file.CloudConfigs, cloudCfg)
+					}
+
+				case "required_providers":
+					reqs, reqsDiags := decodeRequiredProvidersBlock(innerBlock)
+					diags = append(diags, reqsDiags...)
+					file.RequiredProviders = append(file.RequiredProviders, reqs)
+
+				case "provider_meta":
+					providerCfg, cfgDiags := decodeProviderMetaBlock(innerBlock)
+					diags = append(diags, cfgDiags...)
+					if providerCfg != nil {
+						file.ProviderMetas = append(file.ProviderMetas, providerCfg)
+					}
+
+				default:
+					// Should never happen because the above cases should be exhaustive
+					// for all block type names in our schema.
+					continue
+
+				}
+			}
+
+		case "required_providers":
+			// required_providers should be nested inside a "terraform" block
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid required_providers block",
+				Detail:   "A \"required_providers\" block must be nested inside a \"terraform\" block.",
+				Subject:  block.TypeRange.Ptr(),
+			})
+
+		case "provider":
+			cfg, cfgDiags := decodeProviderBlock(block)
+			diags = append(diags, cfgDiags...)
+			if cfg != nil {
+				file.ProviderConfigs = append(file.ProviderConfigs, cfg)
+			}
+
+		case "variable":
+			cfg, cfgDiags := decodeVariableBlock(block, override)
+			diags = append(diags, cfgDiags...)
+			if cfg != nil {
+				file.Variables = append(file.Variables, cfg)
+			}
+
+		case "locals":
+			defs, defsDiags := decodeLocalsBlock(block)
+			diags = append(diags, defsDiags...)
+			file.Locals = append(file.Locals, defs...)
+
+		case "output":
+			cfg, cfgDiags := decodeOutputBlock(block, override)
+			diags = append(diags, cfgDiags...)
+			if cfg != nil {
+				file.Outputs = append(file.Outputs, cfg)
+			}
+
+		case "module":
+			cfg, cfgDiags := decodeModuleBlock(block, override)
+			diags = append(diags, cfgDiags...)
+			if cfg != nil {
+				file.ModuleCalls = append(file.ModuleCalls, cfg)
+			}
+
+		case "resource":
+			cfg, cfgDiags := decodeResourceBlock(block, override)
+			diags = append(diags, cfgDiags...)
+			if cfg != nil {
+				file.ManagedResources = append(file.ManagedResources, cfg)
+			}
+
+		case "data":
+			cfg, cfgDiags := decodeDataBlock(block, override, false)
+			diags = append(diags, cfgDiags...)
+			if cfg != nil {
+				file.DataResources = append(file.DataResources, cfg)
+			}
+
+		case "moved":
+			cfg, cfgDiags := decodeMovedBlock(block)
+			diags = append(diags, cfgDiags...)
+			if cfg != nil {
+				file.Moved = append(file.Moved, cfg)
+			}
+
+		case "import":
+			cfg, cfgDiags := decodeImportBlock(block)
+			diags = append(diags, cfgDiags...)
+			if cfg != nil {
+				file.Import = append(file.Import, cfg)
+			}
+
+		case "check":
+			cfg, cfgDiags := decodeCheckBlock(block, override)
+			diags = append(diags, cfgDiags...)
+			if cfg != nil {
+				file.Checks = append(file.Checks, cfg)
+			}
+
+		default:
+			// Should never happen because the above cases should be exhaustive
+			// for all block type names in our schema.
+			continue
+
+		}
+	}
+
+	return file, diags
+}
+
+// sniffCoreVersionRequirements does minimal parsing of the given body for
+// "terraform" blocks with "required_version" attributes, returning the
+// requirements found.
+//
+// This is intended to maximize the chance that we'll be able to read the
+// requirements (syntax errors notwithstanding) even if the config file contains
+// constructs that might've been added in future Terraform versions
+//
+// This is a "best effort" sort of method which will return constraints it is
+// able to find, but may return no constraints at all if the given body is
+// so invalid that it cannot be decoded at all.
+func sniffCoreVersionRequirements(body hcl.Body) ([]VersionConstraint, hcl.Diagnostics) {
+	rootContent, _, diags := body.PartialContent(configFileTerraformBlockSniffRootSchema)
+
+	var constraints []VersionConstraint
+
+	for _, block := range rootContent.Blocks {
+		content, _, blockDiags := block.Body.PartialContent(configFileVersionSniffBlockSchema)
+		diags = append(diags, blockDiags...)
+
+		attr, exists := content.Attributes["required_version"]
+		if !exists {
+			continue
+		}
+
+		constraint, constraintDiags := decodeVersionConstraint(attr)
+		diags = append(diags, constraintDiags...)
+		if !constraintDiags.HasErrors() {
+			constraints = append(constraints, constraint)
+		}
+	}
+
+	return constraints, diags
+}
+
+// configFileSchema is the schema for the top-level of a config file. We use
+// the low-level HCL API for this level so we can easily deal with each
+// block type separately with its own decoding logic.
+var configFileSchema = &hcl.BodySchema{
+	Blocks: []hcl.BlockHeaderSchema{
+		{
+			Type: "terraform",
+		},
+		{
+			// This one is not really valid, but we include it here so we
+			// can create a specialized error message hinting the user to
+			// nest it inside a "terraform" block.
+			Type: "required_providers",
+		},
+		{
+			Type:       "provider",
+			LabelNames: []string{"name"},
+		},
+		{
+			Type:       "variable",
+			LabelNames: []string{"name"},
+		},
+		{
+			Type: "locals",
+		},
+		{
+			Type:       "output",
+			LabelNames: []string{"name"},
+		},
+		{
+			Type:       "module",
+			LabelNames: []string{"name"},
+		},
+		{
+			Type:       "resource",
+			LabelNames: []string{"type", "name"},
+		},
+		{
+			Type:       "data",
+			LabelNames: []string{"type", "name"},
+		},
+		{
+			Type: "moved",
+		},
+		{
+			Type: "import",
+		},
+		{
+			Type:       "check",
+			LabelNames: []string{"name"},
+		},
+	},
+}
+
+// terraformBlockSchema is the schema for a top-level "terraform" block in
+// a configuration file.
+var terraformBlockSchema = &hcl.BodySchema{
+	Attributes: []hcl.AttributeSchema{
+		{Name: "required_version"},
+		{Name: "experiments"},
+		{Name: "language"},
+	},
+	Blocks: []hcl.BlockHeaderSchema{
+		{
+			Type:       "backend",
+			LabelNames: []string{"type"},
+		},
+		{
+			Type: "cloud",
+		},
+		{
+			Type: "required_providers",
+		},
+		{
+			Type:       "provider_meta",
+			LabelNames: []string{"provider"},
+		},
+	},
+}
+
+// configFileTerraformBlockSniffRootSchema is a schema for
+// sniffCoreVersionRequirements and sniffActiveExperiments.
+var configFileTerraformBlockSniffRootSchema = &hcl.BodySchema{
+	Blocks: []hcl.BlockHeaderSchema{
+		{
+			Type: "terraform",
+		},
+	},
+}
+
+// configFileVersionSniffBlockSchema is a schema for sniffCoreVersionRequirements
+var configFileVersionSniffBlockSchema = &hcl.BodySchema{
+	Attributes: []hcl.AttributeSchema{
+		{
+			Name: "required_version",
+		},
+	},
+}
+
+// configFileExperimentsSniffBlockSchema is a schema for sniffActiveExperiments,
+// to decode a single attribute from inside a "terraform" block.
+var configFileExperimentsSniffBlockSchema = &hcl.BodySchema{
+	Attributes: []hcl.AttributeSchema{
+		{Name: "experiments"},
+		{Name: "language"},
+	},
+}
diff --git a/v1.5.7/internal/configs/parser_config_dir.go b/v1.5.7/internal/configs/parser_config_dir.go
new file mode 100644
index 0000000..eebc12d
--- /dev/null
+++ b/v1.5.7/internal/configs/parser_config_dir.go
@@ -0,0 +1,166 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+)
+
+// LoadConfigDir reads the .tf and .tf.json files in the given directory
+// as config files (using LoadConfigFile) and then combines these files into
+// a single Module.
+//
+// If this method returns nil, that indicates that the given directory does not
+// exist at all or could not be opened for some reason. Callers may wish to
+// detect this case and ignore the returned diagnostics so that they can
+// produce a more context-aware error message in that case.
+//
+// If this method returns a non-nil module while error diagnostics are returned
+// then the module may be incomplete but can be used carefully for static
+// analysis.
+//
+// This file does not consider a directory with no files to be an error, and
+// will simply return an empty module in that case. Callers should first call
+// Parser.IsConfigDir if they wish to recognize that situation.
+//
+// .tf files are parsed using the HCL native syntax while .tf.json files are
+// parsed using the HCL JSON syntax.
+func (p *Parser) LoadConfigDir(path string) (*Module, hcl.Diagnostics) {
+	primaryPaths, overridePaths, diags := p.dirFiles(path)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	primary, fDiags := p.loadFiles(primaryPaths, false)
+	diags = append(diags, fDiags...)
+	override, fDiags := p.loadFiles(overridePaths, true)
+	diags = append(diags, fDiags...)
+
+	mod, modDiags := NewModule(primary, override)
+	diags = append(diags, modDiags...)
+
+	mod.SourceDir = path
+
+	return mod, diags
+}
+
+// ConfigDirFiles returns lists of the primary and override files configuration
+// files in the given directory.
+//
+// If the given directory does not exist or cannot be read, error diagnostics
+// are returned. If errors are returned, the resulting lists may be incomplete.
+func (p Parser) ConfigDirFiles(dir string) (primary, override []string, diags hcl.Diagnostics) {
+	return p.dirFiles(dir)
+}
+
+// IsConfigDir determines whether the given path refers to a directory that
+// exists and contains at least one Terraform config file (with a .tf or
+// .tf.json extension.)
+func (p *Parser) IsConfigDir(path string) bool {
+	primaryPaths, overridePaths, _ := p.dirFiles(path)
+	return (len(primaryPaths) + len(overridePaths)) > 0
+}
+
+func (p *Parser) loadFiles(paths []string, override bool) ([]*File, hcl.Diagnostics) {
+	var files []*File
+	var diags hcl.Diagnostics
+
+	for _, path := range paths {
+		var f *File
+		var fDiags hcl.Diagnostics
+		if override {
+			f, fDiags = p.LoadConfigFileOverride(path)
+		} else {
+			f, fDiags = p.LoadConfigFile(path)
+		}
+		diags = append(diags, fDiags...)
+		if f != nil {
+			files = append(files, f)
+		}
+	}
+
+	return files, diags
+}
+
+func (p *Parser) dirFiles(dir string) (primary, override []string, diags hcl.Diagnostics) {
+	infos, err := p.fs.ReadDir(dir)
+	if err != nil {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Failed to read module directory",
+			Detail:   fmt.Sprintf("Module directory %s does not exist or cannot be read.", dir),
+		})
+		return
+	}
+
+	for _, info := range infos {
+		if info.IsDir() {
+			// We only care about files
+			continue
+		}
+
+		name := info.Name()
+		ext := fileExt(name)
+		if ext == "" || IsIgnoredFile(name) {
+			continue
+		}
+
+		baseName := name[:len(name)-len(ext)] // strip extension
+		isOverride := baseName == "override" || strings.HasSuffix(baseName, "_override")
+
+		fullPath := filepath.Join(dir, name)
+		if isOverride {
+			override = append(override, fullPath)
+		} else {
+			primary = append(primary, fullPath)
+		}
+	}
+
+	return
+}
+
+// fileExt returns the Terraform configuration extension of the given
+// path, or a blank string if it is not a recognized extension.
+func fileExt(path string) string {
+	if strings.HasSuffix(path, ".tf") {
+		return ".tf"
+	} else if strings.HasSuffix(path, ".tf.json") {
+		return ".tf.json"
+	} else {
+		return ""
+	}
+}
+
+// IsIgnoredFile returns true if the given filename (which must not have a
+// directory path ahead of it) should be ignored as e.g. an editor swap file.
+func IsIgnoredFile(name string) bool {
+	return strings.HasPrefix(name, ".") || // Unix-like hidden files
+		strings.HasSuffix(name, "~") || // vim
+		strings.HasPrefix(name, "#") && strings.HasSuffix(name, "#") // emacs
+}
+
+// IsEmptyDir returns true if the given filesystem path contains no Terraform
+// configuration files.
+//
+// Unlike the methods of the Parser type, this function always consults the
+// real filesystem, and thus it isn't appropriate to use when working with
+// configuration loaded from a plan file.
+func IsEmptyDir(path string) (bool, error) {
+	if _, err := os.Stat(path); err != nil && os.IsNotExist(err) {
+		return true, nil
+	}
+
+	p := NewParser(nil)
+	fs, os, diags := p.dirFiles(path)
+	if diags.HasErrors() {
+		return false, diags
+	}
+
+	return len(fs) == 0 && len(os) == 0, nil
+}
diff --git a/v1.5.7/internal/configs/parser_config_dir_test.go b/v1.5.7/internal/configs/parser_config_dir_test.go
new file mode 100644
index 0000000..f1afcb2
--- /dev/null
+++ b/v1.5.7/internal/configs/parser_config_dir_test.go
@@ -0,0 +1,202 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+	"io/ioutil"
+	"path/filepath"
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+)
+
+// TestParseLoadConfigDirSuccess is a simple test that just verifies that
+// a number of test configuration directories (in testdata/valid-modules)
+// can be parsed without raising any diagnostics.
+//
+// It also re-tests the individual files in testdata/valid-files as if
+// they were single-file modules, to ensure that they can be bundled into
+// modules correctly.
+//
+// This test does not verify that reading these modules produces the correct
+// module element contents. More detailed assertions may be made on some subset
+// of these configuration files in other tests.
+func TestParserLoadConfigDirSuccess(t *testing.T) {
+	dirs, err := ioutil.ReadDir("testdata/valid-modules")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, info := range dirs {
+		name := info.Name()
+		t.Run(name, func(t *testing.T) {
+			parser := NewParser(nil)
+			path := filepath.Join("testdata/valid-modules", name)
+
+			mod, diags := parser.LoadConfigDir(path)
+			if len(diags) != 0 && len(mod.ActiveExperiments) != 0 {
+				// As a special case to reduce churn while we're working
+				// through experimental features, we'll ignore the warning
+				// that an experimental feature is active if the module
+				// intentionally opted in to that feature.
+				// If you want to explicitly test for the feature warning
+				// to be generated, consider using testdata/warning-files
+				// instead.
+				filterDiags := make(hcl.Diagnostics, 0, len(diags))
+				for _, diag := range diags {
+					if diag.Severity != hcl.DiagWarning {
+						continue
+					}
+					match := false
+					for exp := range mod.ActiveExperiments {
+						allowedSummary := fmt.Sprintf("Experimental feature %q is active", exp.Keyword())
+						if diag.Summary == allowedSummary {
+							match = true
+							break
+						}
+					}
+					if !match {
+						filterDiags = append(filterDiags, diag)
+					}
+				}
+				diags = filterDiags
+			}
+			if len(diags) != 0 {
+				t.Errorf("unexpected diagnostics")
+				for _, diag := range diags {
+					t.Logf("- %s", diag)
+				}
+			}
+
+			if mod.SourceDir != path {
+				t.Errorf("wrong SourceDir value %q; want %s", mod.SourceDir, path)
+			}
+		})
+	}
+
+	// The individual files in testdata/valid-files should also work
+	// when loaded as modules.
+	files, err := ioutil.ReadDir("testdata/valid-files")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, info := range files {
+		name := info.Name()
+		t.Run(fmt.Sprintf("%s as module", name), func(t *testing.T) {
+			src, err := ioutil.ReadFile(filepath.Join("testdata/valid-files", name))
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			parser := testParser(map[string]string{
+				"mod/" + name: string(src),
+			})
+
+			_, diags := parser.LoadConfigDir("mod")
+			if diags.HasErrors() {
+				t.Errorf("unexpected error diagnostics")
+				for _, diag := range diags {
+					t.Logf("- %s", diag)
+				}
+			}
+		})
+	}
+
+}
+
+// TestParseLoadConfigDirFailure is a simple test that just verifies that
+// a number of test configuration directories (in testdata/invalid-modules)
+// produce diagnostics when parsed.
+//
+// It also re-tests the individual files in testdata/invalid-files as if
+// they were single-file modules, to ensure that their errors are still
+// detected when loading as part of a module.
+//
+// This test does not verify that reading these modules produces any
+// diagnostics in particular. More detailed assertions may be made on some subset
+// of these configuration files in other tests.
+func TestParserLoadConfigDirFailure(t *testing.T) {
+	dirs, err := ioutil.ReadDir("testdata/invalid-modules")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, info := range dirs {
+		name := info.Name()
+		t.Run(name, func(t *testing.T) {
+			parser := NewParser(nil)
+			path := filepath.Join("testdata/invalid-modules", name)
+
+			_, diags := parser.LoadConfigDir(path)
+			if !diags.HasErrors() {
+				t.Errorf("no errors; want at least one")
+				for _, diag := range diags {
+					t.Logf("- %s", diag)
+				}
+			}
+		})
+	}
+
+	// The individual files in testdata/valid-files should also work
+	// when loaded as modules.
+	files, err := ioutil.ReadDir("testdata/invalid-files")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, info := range files {
+		name := info.Name()
+		t.Run(fmt.Sprintf("%s as module", name), func(t *testing.T) {
+			src, err := ioutil.ReadFile(filepath.Join("testdata/invalid-files", name))
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			parser := testParser(map[string]string{
+				"mod/" + name: string(src),
+			})
+
+			_, diags := parser.LoadConfigDir("mod")
+			if !diags.HasErrors() {
+				t.Errorf("no errors; want at least one")
+				for _, diag := range diags {
+					t.Logf("- %s", diag)
+				}
+			}
+		})
+	}
+
+}
+
+func TestIsEmptyDir(t *testing.T) {
+	val, err := IsEmptyDir(filepath.Join("testdata", "valid-files"))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if val {
+		t.Fatal("should not be empty")
+	}
+}
+
+func TestIsEmptyDir_noExist(t *testing.T) {
+	val, err := IsEmptyDir(filepath.Join("testdata", "nopenopenope"))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if !val {
+		t.Fatal("should be empty")
+	}
+}
+
+func TestIsEmptyDir_noConfigs(t *testing.T) {
+	val, err := IsEmptyDir(filepath.Join("testdata", "dir-empty"))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if !val {
+		t.Fatal("should be empty")
+	}
+}
diff --git a/v1.5.7/internal/configs/parser_config_test.go b/v1.5.7/internal/configs/parser_config_test.go
new file mode 100644
index 0000000..f0c8a34
--- /dev/null
+++ b/v1.5.7/internal/configs/parser_config_test.go
@@ -0,0 +1,288 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"bufio"
+	"bytes"
+	"io/ioutil"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+
+	"github.com/hashicorp/hcl/v2"
+)
+
+// TestParseLoadConfigFileSuccess is a simple test that just verifies that
+// a number of test configuration files (in testdata/valid-files) can
+// be parsed without raising any diagnostics.
+//
+// This test does not verify that reading these files produces the correct
+// file element contents. More detailed assertions may be made on some subset
+// of these configuration files in other tests.
+func TestParserLoadConfigFileSuccess(t *testing.T) {
+	files, err := ioutil.ReadDir("testdata/valid-files")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, info := range files {
+		name := info.Name()
+		t.Run(name, func(t *testing.T) {
+			src, err := ioutil.ReadFile(filepath.Join("testdata/valid-files", name))
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			parser := testParser(map[string]string{
+				name: string(src),
+			})
+
+			_, diags := parser.LoadConfigFile(name)
+			if len(diags) != 0 {
+				t.Errorf("unexpected diagnostics")
+				for _, diag := range diags {
+					t.Logf("- %s", diag)
+				}
+			}
+		})
+	}
+}
+
+// TestParseLoadConfigFileFailure is a simple test that just verifies that
+// a number of test configuration files (in testdata/invalid-files)
+// produce errors as expected.
+//
+// This test does not verify specific error messages, so more detailed
+// assertions should be made on some subset of these configuration files in
+// other tests.
+func TestParserLoadConfigFileFailure(t *testing.T) {
+	files, err := ioutil.ReadDir("testdata/invalid-files")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, info := range files {
+		name := info.Name()
+		t.Run(name, func(t *testing.T) {
+			src, err := ioutil.ReadFile(filepath.Join("testdata/invalid-files", name))
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			parser := testParser(map[string]string{
+				name: string(src),
+			})
+
+			_, diags := parser.LoadConfigFile(name)
+			if !diags.HasErrors() {
+				t.Errorf("LoadConfigFile succeeded; want errors")
+			}
+			for _, diag := range diags {
+				t.Logf("- %s", diag)
+			}
+		})
+	}
+}
+
+// This test uses a subset of the same fixture files as
+// TestParserLoadConfigFileFailure, but additionally verifies that each
+// file produces the expected diagnostic summary.
+func TestParserLoadConfigFileFailureMessages(t *testing.T) {
+	tests := []struct {
+		Filename     string
+		WantSeverity hcl.DiagnosticSeverity
+		WantDiag     string
+	}{
+		{
+			"invalid-files/data-resource-lifecycle.tf",
+			hcl.DiagError,
+			"Invalid data resource lifecycle argument",
+		},
+		{
+			"invalid-files/variable-type-unknown.tf",
+			hcl.DiagError,
+			"Invalid type specification",
+		},
+		{
+			"invalid-files/unexpected-attr.tf",
+			hcl.DiagError,
+			"Unsupported argument",
+		},
+		{
+			"invalid-files/unexpected-block.tf",
+			hcl.DiagError,
+			"Unsupported block type",
+		},
+		{
+			"invalid-files/resource-count-and-for_each.tf",
+			hcl.DiagError,
+			`Invalid combination of "count" and "for_each"`,
+		},
+		{
+			"invalid-files/data-count-and-for_each.tf",
+			hcl.DiagError,
+			`Invalid combination of "count" and "for_each"`,
+		},
+		{
+			"invalid-files/resource-lifecycle-badbool.tf",
+			hcl.DiagError,
+			"Unsuitable value type",
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Filename, func(t *testing.T) {
+			src, err := ioutil.ReadFile(filepath.Join("testdata", test.Filename))
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			parser := testParser(map[string]string{
+				test.Filename: string(src),
+			})
+
+			_, diags := parser.LoadConfigFile(test.Filename)
+			if len(diags) != 1 {
+				t.Errorf("Wrong number of diagnostics %d; want 1", len(diags))
+				for _, diag := range diags {
+					t.Logf("- %s", diag)
+				}
+				return
+			}
+			if diags[0].Severity != test.WantSeverity {
+				t.Errorf("Wrong diagnostic severity %#v; want %#v", diags[0].Severity, test.WantSeverity)
+			}
+			if diags[0].Summary != test.WantDiag {
+				t.Errorf("Wrong diagnostic summary\ngot:  %s\nwant: %s", diags[0].Summary, test.WantDiag)
+			}
+		})
+	}
+}
+
+// TestParseLoadConfigFileWarning is a test that verifies files from
+// testdata/warning-files produce particular warnings.
+//
+// This test does not verify that reading these files produces the correct
+// file element contents in spite of those warnings. More detailed assertions
+// may be made on some subset of these configuration files in other tests.
+func TestParserLoadConfigFileWarning(t *testing.T) {
+	files, err := ioutil.ReadDir("testdata/warning-files")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, info := range files {
+		name := info.Name()
+		t.Run(name, func(t *testing.T) {
+			src, err := ioutil.ReadFile(filepath.Join("testdata/warning-files", name))
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			// First we'll scan the file to see what warnings are expected.
+			// That's declared inside the files themselves by using the
+			// string "WARNING: " somewhere on each line that is expected
+			// to produce a warning, followed by the expected warning summary
+			// text. A single-line comment (with #) is the main way to do that.
+			const marker = "WARNING: "
+			sc := bufio.NewScanner(bytes.NewReader(src))
+			wantWarnings := make(map[int]string)
+			lineNum := 1
+			for sc.Scan() {
+				lineText := sc.Text()
+				if idx := strings.Index(lineText, marker); idx != -1 {
+					summaryText := lineText[idx+len(marker):]
+					wantWarnings[lineNum] = summaryText
+				}
+				lineNum++
+			}
+
+			parser := testParser(map[string]string{
+				name: string(src),
+			})
+
+			_, diags := parser.LoadConfigFile(name)
+			if diags.HasErrors() {
+				t.Errorf("unexpected error diagnostics")
+				for _, diag := range diags {
+					t.Logf("- %s", diag)
+				}
+			}
+
+			gotWarnings := make(map[int]string)
+			for _, diag := range diags {
+				if diag.Severity != hcl.DiagWarning || diag.Subject == nil {
+					continue
+				}
+				gotWarnings[diag.Subject.Start.Line] = diag.Summary
+			}
+
+			if diff := cmp.Diff(wantWarnings, gotWarnings); diff != "" {
+				t.Errorf("wrong warnings\n%s", diff)
+			}
+		})
+	}
+}
+
+// TestParseLoadConfigFileError is a test that verifies files from
+// testdata/warning-files produce particular errors.
+//
+// This test does not verify that reading these files produces the correct
+// file element contents in spite of those errors. More detailed assertions
+// may be made on some subset of these configuration files in other tests.
+func TestParserLoadConfigFileError(t *testing.T) {
+	files, err := ioutil.ReadDir("testdata/error-files")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, info := range files {
+		name := info.Name()
+		t.Run(name, func(t *testing.T) {
+			src, err := ioutil.ReadFile(filepath.Join("testdata/error-files", name))
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			// First we'll scan the file to see what warnings are expected.
+			// That's declared inside the files themselves by using the
+			// string "ERROR: " somewhere on each line that is expected
+			// to produce a warning, followed by the expected warning summary
+			// text. A single-line comment (with #) is the main way to do that.
+			const marker = "ERROR: "
+			sc := bufio.NewScanner(bytes.NewReader(src))
+			wantErrors := make(map[int]string)
+			lineNum := 1
+			for sc.Scan() {
+				lineText := sc.Text()
+				if idx := strings.Index(lineText, marker); idx != -1 {
+					summaryText := lineText[idx+len(marker):]
+					wantErrors[lineNum] = summaryText
+				}
+				lineNum++
+			}
+
+			parser := testParser(map[string]string{
+				name: string(src),
+			})
+
+			_, diags := parser.LoadConfigFile(name)
+
+			gotErrors := make(map[int]string)
+			for _, diag := range diags {
+				if diag.Severity != hcl.DiagError || diag.Subject == nil {
+					continue
+				}
+				gotErrors[diag.Subject.Start.Line] = diag.Summary
+			}
+
+			if diff := cmp.Diff(wantErrors, gotErrors); diff != "" {
+				t.Errorf("wrong errors\n%s", diff)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/configs/parser_test.go b/v1.5.7/internal/configs/parser_test.go
new file mode 100644
index 0000000..6de8c71
--- /dev/null
+++ b/v1.5.7/internal/configs/parser_test.go
@@ -0,0 +1,185 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+	"os"
+	"path"
+	"path/filepath"
+	"reflect"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/spf13/afero"
+)
+
+// testParser returns a parser that reads files from the given map, which
+// is from paths to file contents.
+//
+// Since this function uses only in-memory objects, it should never fail.
+// If any errors are encountered in practice, this function will panic.
+func testParser(files map[string]string) *Parser {
+	fs := afero.Afero{Fs: afero.NewMemMapFs()}
+
+	for filePath, contents := range files {
+		dirPath := path.Dir(filePath)
+		err := fs.MkdirAll(dirPath, os.ModePerm)
+		if err != nil {
+			panic(err)
+		}
+		err = fs.WriteFile(filePath, []byte(contents), os.ModePerm)
+		if err != nil {
+			panic(err)
+		}
+	}
+
+	return NewParser(fs)
+}
+
+// testModuleConfigFrom File reads a single file from the given path as a
+// module and returns its configuration. This is a helper for use in unit tests.
+func testModuleConfigFromFile(filename string) (*Config, hcl.Diagnostics) {
+	parser := NewParser(nil)
+	f, diags := parser.LoadConfigFile(filename)
+	mod, modDiags := NewModule([]*File{f}, nil)
+	diags = append(diags, modDiags...)
+	cfg, moreDiags := BuildConfig(mod, nil)
+	return cfg, append(diags, moreDiags...)
+}
+
+// testModuleFromDir reads configuration from the given directory path as
+// a module and returns it. This is a helper for use in unit tests.
+func testModuleFromDir(path string) (*Module, hcl.Diagnostics) {
+	parser := NewParser(nil)
+	return parser.LoadConfigDir(path)
+}
+
+// testModuleFromDir reads configuration from the given directory path as a
+// module and returns its configuration. This is a helper for use in unit tests.
+func testModuleConfigFromDir(path string) (*Config, hcl.Diagnostics) {
+	parser := NewParser(nil)
+	mod, diags := parser.LoadConfigDir(path)
+	cfg, moreDiags := BuildConfig(mod, nil)
+	return cfg, append(diags, moreDiags...)
+}
+
+// testNestedModuleConfigFromDir reads configuration from the given directory path as
+// a module with (optional) submodules and returns its configuration. This is a
+// helper for use in unit tests.
+func testNestedModuleConfigFromDir(t *testing.T, path string) (*Config, hcl.Diagnostics) {
+	t.Helper()
+
+	parser := NewParser(nil)
+	mod, diags := parser.LoadConfigDir(path)
+	if mod == nil {
+		t.Fatal("got nil root module; want non-nil")
+	}
+
+	versionI := 0
+	cfg, nestedDiags := BuildConfig(mod, ModuleWalkerFunc(
+		func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
+			// For the sake of this test we're going to just treat our
+			// SourceAddr as a path relative to the calling module.
+			// A "real" implementation of ModuleWalker should accept the
+			// various different source address syntaxes Terraform supports.
+
+			// Build a full path by walking up the module tree, prepending each
+			// source address path until we hit the root
+			paths := []string{req.SourceAddr.String()}
+			for config := req.Parent; config != nil && config.Parent != nil; config = config.Parent {
+				paths = append([]string{config.SourceAddr.String()}, paths...)
+			}
+			paths = append([]string{path}, paths...)
+			sourcePath := filepath.Join(paths...)
+
+			mod, diags := parser.LoadConfigDir(sourcePath)
+			version, _ := version.NewVersion(fmt.Sprintf("1.0.%d", versionI))
+			versionI++
+			return mod, version, diags
+		},
+	))
+
+	diags = append(diags, nestedDiags...)
+	return cfg, diags
+}
+
+func assertNoDiagnostics(t *testing.T, diags hcl.Diagnostics) bool {
+	t.Helper()
+	return assertDiagnosticCount(t, diags, 0)
+}
+
+func assertDiagnosticCount(t *testing.T, diags hcl.Diagnostics, want int) bool {
+	t.Helper()
+	if len(diags) != want {
+		t.Errorf("wrong number of diagnostics %d; want %d", len(diags), want)
+		for _, diag := range diags {
+			t.Logf("- %s", diag)
+		}
+		return true
+	}
+	return false
+}
+
+func assertDiagnosticSummary(t *testing.T, diags hcl.Diagnostics, want string) bool {
+	t.Helper()
+
+	for _, diag := range diags {
+		if diag.Summary == want {
+			return false
+		}
+	}
+
+	t.Errorf("missing diagnostic summary %q", want)
+	for _, diag := range diags {
+		t.Logf("- %s", diag)
+	}
+	return true
+}
+
+func assertExactDiagnostics(t *testing.T, diags hcl.Diagnostics, want []string) bool {
+	t.Helper()
+
+	gotDiags := map[string]bool{}
+	wantDiags := map[string]bool{}
+
+	for _, diag := range diags {
+		gotDiags[diag.Error()] = true
+	}
+	for _, msg := range want {
+		wantDiags[msg] = true
+	}
+
+	bad := false
+	for got := range gotDiags {
+		if _, exists := wantDiags[got]; !exists {
+			t.Errorf("unexpected diagnostic: %s", got)
+			bad = true
+		}
+	}
+	for want := range wantDiags {
+		if _, exists := gotDiags[want]; !exists {
+			t.Errorf("missing expected diagnostic: %s", want)
+			bad = true
+		}
+	}
+
+	return bad
+}
+
+func assertResultDeepEqual(t *testing.T, got, want interface{}) bool {
+	t.Helper()
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("wrong result\ngot: %swant: %s", spew.Sdump(got), spew.Sdump(want))
+		return true
+	}
+	return false
+}
+
+func stringPtr(s string) *string {
+	return &s
+}
diff --git a/v1.5.7/internal/configs/parser_values.go b/v1.5.7/internal/configs/parser_values.go
new file mode 100644
index 0000000..cd0f585
--- /dev/null
+++ b/v1.5.7/internal/configs/parser_values.go
@@ -0,0 +1,46 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// LoadValuesFile reads the file at the given path and parses it as a "values
+// file", which is an HCL config file whose top-level attributes are treated
+// as arbitrary key.value pairs.
+//
+// If the file cannot be read -- for example, if it does not exist -- then
+// a nil map will be returned along with error diagnostics. Callers may wish
+// to disregard the returned diagnostics in this case and instead generate
+// their own error message(s) with additional context.
+//
+// If the returned diagnostics has errors when a non-nil map is returned
+// then the map may be incomplete but should be valid enough for careful
+// static analysis.
+//
+// This method wraps LoadHCLFile, and so it inherits the syntax selection
+// behaviors documented for that method.
+func (p *Parser) LoadValuesFile(path string) (map[string]cty.Value, hcl.Diagnostics) {
+	body, diags := p.LoadHCLFile(path)
+	if body == nil {
+		return nil, diags
+	}
+
+	vals := make(map[string]cty.Value)
+	attrs, attrDiags := body.JustAttributes()
+	diags = append(diags, attrDiags...)
+	if attrs == nil {
+		return vals, diags
+	}
+
+	for name, attr := range attrs {
+		val, valDiags := attr.Expr.Value(nil)
+		diags = append(diags, valDiags...)
+		vals[name] = val
+	}
+
+	return vals, diags
+}
diff --git a/v1.5.7/internal/configs/parser_values_test.go b/v1.5.7/internal/configs/parser_values_test.go
new file mode 100644
index 0000000..707d222
--- /dev/null
+++ b/v1.5.7/internal/configs/parser_values_test.go
@@ -0,0 +1,116 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestParserLoadValuesFile(t *testing.T) {
+	tests := map[string]struct {
+		Source    string
+		Want      map[string]cty.Value
+		DiagCount int
+	}{
+		"empty.tfvars": {
+			"",
+			map[string]cty.Value{},
+			0,
+		},
+		"empty.json": {
+			"{}",
+			map[string]cty.Value{},
+			0,
+		},
+		"zerolen.json": {
+			"",
+			map[string]cty.Value{},
+			2, // syntax error and missing root object
+		},
+		"one-number.tfvars": {
+			"foo = 1\n",
+			map[string]cty.Value{
+				"foo": cty.NumberIntVal(1),
+			},
+			0,
+		},
+		"one-number.tfvars.json": {
+			`{"foo": 1}`,
+			map[string]cty.Value{
+				"foo": cty.NumberIntVal(1),
+			},
+			0,
+		},
+		"two-bools.tfvars": {
+			"foo = true\nbar = false\n",
+			map[string]cty.Value{
+				"foo": cty.True,
+				"bar": cty.False,
+			},
+			0,
+		},
+		"two-bools.tfvars.json": {
+			`{"foo": true, "bar": false}`,
+			map[string]cty.Value{
+				"foo": cty.True,
+				"bar": cty.False,
+			},
+			0,
+		},
+		"invalid-syntax.tfvars": {
+			"foo bar baz\n",
+			map[string]cty.Value{},
+			2, // invalid block definition, and unexpected foo block (the latter due to parser recovery behavior)
+		},
+		"block.tfvars": {
+			"foo = true\ninvalid {\n}\n",
+			map[string]cty.Value{
+				"foo": cty.True,
+			},
+			1, // blocks are not allowed
+		},
+		"variables.tfvars": {
+			"baz = true\nfoo = var.baz\n",
+			map[string]cty.Value{
+				"baz": cty.True,
+				"foo": cty.DynamicVal,
+			},
+			1, // variables cannot be referenced here
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			p := testParser(map[string]string{
+				name: test.Source,
+			})
+			got, diags := p.LoadValuesFile(name)
+			if len(diags) != test.DiagCount {
+				t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.DiagCount)
+				for _, diag := range diags {
+					t.Logf("- %s", diag)
+				}
+			}
+
+			if len(got) != len(test.Want) {
+				t.Errorf("wrong number of result keys %d; want %d", len(got), len(test.Want))
+			}
+
+			for name, gotVal := range got {
+				wantVal := test.Want[name]
+				if wantVal == cty.NilVal {
+					t.Errorf("unexpected result key %q", name)
+					continue
+				}
+
+				if !gotVal.RawEquals(wantVal) {
+					t.Errorf("wrong value for %q\ngot:  %#v\nwant: %#v", name, gotVal, wantVal)
+					continue
+				}
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/configs/provider.go b/v1.5.7/internal/configs/provider.go
new file mode 100644
index 0000000..38a5a28
--- /dev/null
+++ b/v1.5.7/internal/configs/provider.go
@@ -0,0 +1,285 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/gohcl"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Provider represents a "provider" block in a module or file. A provider
+// block is a provider configuration, and there can be zero or more
+// configurations for each actual provider.
+type Provider struct {
+	Name       string
+	NameRange  hcl.Range
+	Alias      string
+	AliasRange *hcl.Range // nil if no alias set
+
+	Version VersionConstraint
+
+	Config hcl.Body
+
+	DeclRange hcl.Range
+
+	// TODO: this may not be set in some cases, so it is not yet suitable for
+	// use outside of this package. We currently only use it for internal
+	// validation, but once we verify that this can be set in all cases, we can
+	// export this so providers don't need to be re-resolved.
+	// This same field is also added to the ProviderConfigRef struct.
+	providerType addrs.Provider
+}
+
+func decodeProviderBlock(block *hcl.Block) (*Provider, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+
+	content, config, moreDiags := block.Body.PartialContent(providerBlockSchema)
+	diags = append(diags, moreDiags...)
+
+	// Provider names must be localized. Produce an error with a message
+	// indicating the action the user can take to fix this message if the local
+	// name is not localized.
+	name := block.Labels[0]
+	nameDiags := checkProviderNameNormalized(name, block.DefRange)
+	diags = append(diags, nameDiags...)
+	if nameDiags.HasErrors() {
+		// If the name is invalid then we mustn't produce a result because
+		// downstreams could try to use it as a provider type and then crash.
+		return nil, diags
+	}
+
+	provider := &Provider{
+		Name:      name,
+		NameRange: block.LabelRanges[0],
+		Config:    config,
+		DeclRange: block.DefRange,
+	}
+
+	if attr, exists := content.Attributes["alias"]; exists {
+		valDiags := gohcl.DecodeExpression(attr.Expr, nil, &provider.Alias)
+		diags = append(diags, valDiags...)
+		provider.AliasRange = attr.Expr.Range().Ptr()
+
+		if !hclsyntax.ValidIdentifier(provider.Alias) {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid provider configuration alias",
+				Detail:   fmt.Sprintf("An alias must be a valid name. %s", badIdentifierDetail),
+			})
+		}
+	}
+
+	if attr, exists := content.Attributes["version"]; exists {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagWarning,
+			Summary:  "Version constraints inside provider configuration blocks are deprecated",
+			Detail:   "Terraform 0.13 and earlier allowed provider version constraints inside the provider configuration block, but that is now deprecated and will be removed in a future version of Terraform. To silence this warning, move the provider version constraint into the required_providers block.",
+			Subject:  attr.Expr.Range().Ptr(),
+		})
+		var versionDiags hcl.Diagnostics
+		provider.Version, versionDiags = decodeVersionConstraint(attr)
+		diags = append(diags, versionDiags...)
+	}
+
+	// Reserved attribute names
+	for _, name := range []string{"count", "depends_on", "for_each", "source"} {
+		if attr, exists := content.Attributes[name]; exists {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Reserved argument name in provider block",
+				Detail:   fmt.Sprintf("The provider argument name %q is reserved for use by Terraform in a future version.", name),
+				Subject:  &attr.NameRange,
+			})
+		}
+	}
+
+	var seenEscapeBlock *hcl.Block
+	for _, block := range content.Blocks {
+		switch block.Type {
+		case "_":
+			if seenEscapeBlock != nil {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Duplicate escaping block",
+					Detail: fmt.Sprintf(
+						"The special block type \"_\" can be used to force particular arguments to be interpreted as provider-specific rather than as meta-arguments, but each provider block can have only one such block. The first escaping block was at %s.",
+						seenEscapeBlock.DefRange,
+					),
+					Subject: &block.DefRange,
+				})
+				continue
+			}
+			seenEscapeBlock = block
+
+			// When there's an escaping block its content merges with the
+			// existing config we extracted earlier, so later decoding
+			// will see a blend of both.
+			provider.Config = hcl.MergeBodies([]hcl.Body{provider.Config, block.Body})
+
+		default:
+			// All of the other block types in our schema are reserved for
+			// future expansion.
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Reserved block type name in provider block",
+				Detail:   fmt.Sprintf("The block type name %q is reserved for use by Terraform in a future version.", block.Type),
+				Subject:  &block.TypeRange,
+			})
+		}
+	}
+
+	return provider, diags
+}
+
+// Addr returns the address of the receiving provider configuration, relative
+// to its containing module.
+func (p *Provider) Addr() addrs.LocalProviderConfig {
+	return addrs.LocalProviderConfig{
+		LocalName: p.Name,
+		Alias:     p.Alias,
+	}
+}
+
+func (p *Provider) moduleUniqueKey() string {
+	if p.Alias != "" {
+		return fmt.Sprintf("%s.%s", p.Name, p.Alias)
+	}
+	return p.Name
+}
+
+// ParseProviderConfigCompact parses the given absolute traversal as a relative
+// provider address in compact form. The following are examples of traversals
+// that can be successfully parsed as compact relative provider configuration
+// addresses:
+//
+//   - aws
+//   - aws.foo
+//
+// This function will panic if given a relative traversal.
+//
+// If the returned diagnostics contains errors then the result value is invalid
+// and must not be used.
+func ParseProviderConfigCompact(traversal hcl.Traversal) (addrs.LocalProviderConfig, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	ret := addrs.LocalProviderConfig{
+		LocalName: traversal.RootName(),
+	}
+
+	if len(traversal) < 2 {
+		// Just a type name, then.
+		return ret, diags
+	}
+
+	aliasStep := traversal[1]
+	switch ts := aliasStep.(type) {
+	case hcl.TraverseAttr:
+		ret.Alias = ts.Name
+		return ret, diags
+	default:
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider configuration address",
+			Detail:   "The provider type name must either stand alone or be followed by an alias name separated with a dot.",
+			Subject:  aliasStep.SourceRange().Ptr(),
+		})
+	}
+
+	if len(traversal) > 2 {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider configuration address",
+			Detail:   "Extraneous extra operators after provider configuration address.",
+			Subject:  traversal[2:].SourceRange().Ptr(),
+		})
+	}
+
+	return ret, diags
+}
+
+// ParseProviderConfigCompactStr is a helper wrapper around ParseProviderConfigCompact
+// that takes a string and parses it with the HCL native syntax traversal parser
+// before interpreting it.
+//
+// This should be used only in specialized situations since it will cause the
+// created references to not have any meaningful source location information.
+// If a reference string is coming from a source that should be identified in
+// error messages then the caller should instead parse it directly using a
+// suitable function from the HCL API and pass the traversal itself to
+// ParseProviderConfigCompact.
+//
+// Error diagnostics are returned if either the parsing fails or the analysis
+// of the traversal fails. There is no way for the caller to distinguish the
+// two kinds of diagnostics programmatically. If error diagnostics are returned
+// then the returned address is invalid.
+func ParseProviderConfigCompactStr(str string) (addrs.LocalProviderConfig, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1})
+	diags = diags.Append(parseDiags)
+	if parseDiags.HasErrors() {
+		return addrs.LocalProviderConfig{}, diags
+	}
+
+	addr, addrDiags := ParseProviderConfigCompact(traversal)
+	diags = diags.Append(addrDiags)
+	return addr, diags
+}
+
+var providerBlockSchema = &hcl.BodySchema{
+	Attributes: []hcl.AttributeSchema{
+		{
+			Name: "alias",
+		},
+		{
+			Name: "version",
+		},
+
+		// Attribute names reserved for future expansion.
+		{Name: "count"},
+		{Name: "depends_on"},
+		{Name: "for_each"},
+		{Name: "source"},
+	},
+	Blocks: []hcl.BlockHeaderSchema{
+		{Type: "_"}, // meta-argument escaping block
+
+		// The rest of these are reserved for future expansion.
+		{Type: "lifecycle"},
+		{Type: "locals"},
+	},
+}
+
+// checkProviderNameNormalized verifies that the given string is already
+// normalized and returns an error if not.
+func checkProviderNameNormalized(name string, declrange hcl.Range) hcl.Diagnostics {
+	var diags hcl.Diagnostics
+	// verify that the provider local name is normalized
+	normalized, err := addrs.IsProviderPartNormalized(name)
+	if err != nil {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider local name",
+			Detail:   fmt.Sprintf("%s is an invalid provider local name: %s", name, err),
+			Subject:  &declrange,
+		})
+		return diags
+	}
+	if !normalized {
+		// we would have returned this error already
+		normalizedProvider, _ := addrs.ParseProviderPart(name)
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider local name",
+			Detail:   fmt.Sprintf("Provider names must be normalized. Replace %q with %q to fix this error.", name, normalizedProvider),
+			Subject:  &declrange,
+		})
+	}
+	return diags
+}
diff --git a/v1.5.7/internal/configs/provider_meta.go b/v1.5.7/internal/configs/provider_meta.go
new file mode 100644
index 0000000..066f4e3
--- /dev/null
+++ b/v1.5.7/internal/configs/provider_meta.go
@@ -0,0 +1,40 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import "github.com/hashicorp/hcl/v2"
+
+// ProviderMeta represents a "provider_meta" block inside a "terraform" block
+// in a module or file.
+type ProviderMeta struct {
+	Provider string
+	Config   hcl.Body
+
+	ProviderRange hcl.Range
+	DeclRange     hcl.Range
+}
+
+func decodeProviderMetaBlock(block *hcl.Block) (*ProviderMeta, hcl.Diagnostics) {
+	// provider_meta must be a static map. We can verify this by attempting to
+	// evaluate the values.
+	attrs, diags := block.Body.JustAttributes()
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	for _, attr := range attrs {
+		_, d := attr.Expr.Value(nil)
+		diags = append(diags, d...)
+	}
+
+	// verify that the local name is already localized or produce an error.
+	diags = append(diags, checkProviderNameNormalized(block.Labels[0], block.DefRange)...)
+
+	return &ProviderMeta{
+		Provider:      block.Labels[0],
+		ProviderRange: block.LabelRanges[0],
+		Config:        block.Body,
+		DeclRange:     block.DefRange,
+	}, diags
+}
diff --git a/v1.5.7/internal/configs/provider_requirements.go b/v1.5.7/internal/configs/provider_requirements.go
new file mode 100644
index 0000000..28d4738
--- /dev/null
+++ b/v1.5.7/internal/configs/provider_requirements.go
@@ -0,0 +1,249 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// RequiredProvider represents a declaration of a dependency on a particular
+// provider version or source without actually configuring that provider. This
+// is used in child modules that expect a provider to be passed in from their
+// parent.
+type RequiredProvider struct {
+	Name        string
+	Source      string
+	Type        addrs.Provider
+	Requirement VersionConstraint
+	DeclRange   hcl.Range
+	Aliases     []addrs.LocalProviderConfig
+}
+
+type RequiredProviders struct {
+	RequiredProviders map[string]*RequiredProvider
+	DeclRange         hcl.Range
+}
+
+func decodeRequiredProvidersBlock(block *hcl.Block) (*RequiredProviders, hcl.Diagnostics) {
+	attrs, diags := block.Body.JustAttributes()
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	ret := &RequiredProviders{
+		RequiredProviders: make(map[string]*RequiredProvider),
+		DeclRange:         block.DefRange,
+	}
+
+	for name, attr := range attrs {
+		rp := &RequiredProvider{
+			Name:      name,
+			DeclRange: attr.Expr.Range(),
+		}
+
+		// Look for a single static string, in case we have the legacy version-only
+		// format in the configuration.
+		if expr, err := attr.Expr.Value(nil); err == nil && expr.Type().IsPrimitiveType() {
+			vc, reqDiags := decodeVersionConstraint(attr)
+			diags = append(diags, reqDiags...)
+
+			pType, err := addrs.ParseProviderPart(rp.Name)
+			if err != nil {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid provider name",
+					Detail:   err.Error(),
+					Subject:  attr.Expr.Range().Ptr(),
+				})
+				continue
+			}
+
+			rp.Requirement = vc
+			rp.Type = addrs.ImpliedProviderForUnqualifiedType(pType)
+			ret.RequiredProviders[name] = rp
+
+			continue
+		}
+
+		// verify that the local name is already localized or produce an error.
+		nameDiags := checkProviderNameNormalized(name, attr.Expr.Range())
+		if nameDiags.HasErrors() {
+			diags = append(diags, nameDiags...)
+			continue
+		}
+
+		kvs, mapDiags := hcl.ExprMap(attr.Expr)
+		if mapDiags.HasErrors() {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid required_providers object",
+				Detail:   "required_providers entries must be strings or objects.",
+				Subject:  attr.Expr.Range().Ptr(),
+			})
+			continue
+		}
+
+	LOOP:
+		for _, kv := range kvs {
+			key, keyDiags := kv.Key.Value(nil)
+			if keyDiags.HasErrors() {
+				diags = append(diags, keyDiags...)
+				continue
+			}
+
+			if key.Type() != cty.String {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid Attribute",
+					Detail:   fmt.Sprintf("Invalid attribute value for provider requirement: %#v", key),
+					Subject:  kv.Key.Range().Ptr(),
+				})
+				continue
+			}
+
+			switch key.AsString() {
+			case "version":
+				vc := VersionConstraint{
+					DeclRange: attr.Range,
+				}
+
+				constraint, valDiags := kv.Value.Value(nil)
+				if valDiags.HasErrors() || !constraint.Type().Equals(cty.String) {
+					diags = append(diags, &hcl.Diagnostic{
+						Severity: hcl.DiagError,
+						Summary:  "Invalid version constraint",
+						Detail:   "Version must be specified as a string.",
+						Subject:  kv.Value.Range().Ptr(),
+					})
+					continue
+				}
+
+				constraintStr := constraint.AsString()
+				constraints, err := version.NewConstraint(constraintStr)
+				if err != nil {
+					// NewConstraint doesn't return user-friendly errors, so we'll just
+					// ignore the provided error and produce our own generic one.
+					diags = append(diags, &hcl.Diagnostic{
+						Severity: hcl.DiagError,
+						Summary:  "Invalid version constraint",
+						Detail:   "This string does not use correct version constraint syntax.",
+						Subject:  kv.Value.Range().Ptr(),
+					})
+					continue
+				}
+
+				vc.Required = constraints
+				rp.Requirement = vc
+
+			case "source":
+				source, err := kv.Value.Value(nil)
+				if err != nil || !source.Type().Equals(cty.String) {
+					diags = append(diags, &hcl.Diagnostic{
+						Severity: hcl.DiagError,
+						Summary:  "Invalid source",
+						Detail:   "Source must be specified as a string.",
+						Subject:  kv.Value.Range().Ptr(),
+					})
+					continue
+				}
+
+				fqn, sourceDiags := addrs.ParseProviderSourceString(source.AsString())
+				if sourceDiags.HasErrors() {
+					hclDiags := sourceDiags.ToHCL()
+					// The diagnostics from ParseProviderSourceString don't contain
+					// source location information because it has no context to compute
+					// them from, and so we'll add those in quickly here before we
+					// return.
+					for _, diag := range hclDiags {
+						if diag.Subject == nil {
+							diag.Subject = kv.Value.Range().Ptr()
+						}
+					}
+					diags = append(diags, hclDiags...)
+					continue
+				}
+
+				rp.Source = source.AsString()
+				rp.Type = fqn
+
+			case "configuration_aliases":
+				exprs, listDiags := hcl.ExprList(kv.Value)
+				if listDiags.HasErrors() {
+					diags = append(diags, listDiags...)
+					continue
+				}
+
+				for _, expr := range exprs {
+					traversal, travDiags := hcl.AbsTraversalForExpr(expr)
+					if travDiags.HasErrors() {
+						diags = append(diags, travDiags...)
+						continue
+					}
+
+					addr, cfgDiags := ParseProviderConfigCompact(traversal)
+					if cfgDiags.HasErrors() {
+						diags = append(diags, &hcl.Diagnostic{
+							Severity: hcl.DiagError,
+							Summary:  "Invalid configuration_aliases value",
+							Detail:   `Configuration aliases can only contain references to local provider configuration names in the format of provider.alias`,
+							Subject:  kv.Value.Range().Ptr(),
+						})
+						continue
+					}
+
+					if addr.LocalName != name {
+						diags = append(diags, &hcl.Diagnostic{
+							Severity: hcl.DiagError,
+							Summary:  "Invalid configuration_aliases value",
+							Detail:   fmt.Sprintf(`Configuration aliases must be prefixed with the provider name. Expected %q, but found %q.`, name, addr.LocalName),
+							Subject:  kv.Value.Range().Ptr(),
+						})
+						continue
+					}
+
+					rp.Aliases = append(rp.Aliases, addr)
+				}
+
+			default:
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid required_providers object",
+					Detail:   `required_providers objects can only contain "version", "source" and "configuration_aliases" attributes. To configure a provider, use a "provider" block.`,
+					Subject:  kv.Key.Range().Ptr(),
+				})
+				break LOOP
+			}
+
+		}
+
+		if diags.HasErrors() {
+			continue
+		}
+
+		// We can add the required provider when there are no errors.
+		// If a source was not given, create an implied type.
+		if rp.Type.IsZero() {
+			pType, err := addrs.ParseProviderPart(rp.Name)
+			if err != nil {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid provider name",
+					Detail:   err.Error(),
+					Subject:  attr.Expr.Range().Ptr(),
+				})
+			} else {
+				rp.Type = addrs.ImpliedProviderForUnqualifiedType(pType)
+			}
+		}
+
+		ret.RequiredProviders[rp.Name] = rp
+	}
+
+	return ret, diags
+}
diff --git a/v1.5.7/internal/configs/provider_requirements_test.go b/v1.5.7/internal/configs/provider_requirements_test.go
new file mode 100644
index 0000000..68a8aca
--- /dev/null
+++ b/v1.5.7/internal/configs/provider_requirements_test.go
@@ -0,0 +1,352 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcltest"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/zclconf/go-cty/cty"
+)
+
+var (
+	ignoreUnexported = cmpopts.IgnoreUnexported(version.Constraint{})
+	comparer         = cmp.Comparer(func(x, y RequiredProvider) bool {
+		if x.Name != y.Name {
+			return false
+		}
+		if x.Type != y.Type {
+			return false
+		}
+		if x.Source != y.Source {
+			return false
+		}
+		if x.Requirement.Required.String() != y.Requirement.Required.String() {
+			return false
+		}
+		if x.DeclRange != y.DeclRange {
+			return false
+		}
+		return true
+	})
+	blockRange = hcl.Range{
+		Filename: "mock.tf",
+		Start:    hcl.Pos{Line: 3, Column: 12, Byte: 27},
+		End:      hcl.Pos{Line: 3, Column: 19, Byte: 34},
+	}
+	mockRange = hcl.Range{
+		Filename: "MockExprLiteral",
+	}
+)
+
+func TestDecodeRequiredProvidersBlock(t *testing.T) {
+	tests := map[string]struct {
+		Block *hcl.Block
+		Want  *RequiredProviders
+		Error string
+	}{
+		"legacy": {
+			Block: &hcl.Block{
+				Type: "required_providers",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"default": {
+							Name: "default",
+							Expr: hcltest.MockExprLiteral(cty.StringVal("1.0.0")),
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			Want: &RequiredProviders{
+				RequiredProviders: map[string]*RequiredProvider{
+					"default": {
+						Name:        "default",
+						Type:        addrs.NewDefaultProvider("default"),
+						Requirement: testVC("1.0.0"),
+						DeclRange:   mockRange,
+					},
+				},
+				DeclRange: blockRange,
+			},
+		},
+		"provider source": {
+			Block: &hcl.Block{
+				Type: "required_providers",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"my-test": {
+							Name: "my-test",
+							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
+								"source":  cty.StringVal("mycloud/test"),
+								"version": cty.StringVal("2.0.0"),
+							})),
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			Want: &RequiredProviders{
+				RequiredProviders: map[string]*RequiredProvider{
+					"my-test": {
+						Name:        "my-test",
+						Source:      "mycloud/test",
+						Type:        addrs.NewProvider(addrs.DefaultProviderRegistryHost, "mycloud", "test"),
+						Requirement: testVC("2.0.0"),
+						DeclRange:   mockRange,
+					},
+				},
+				DeclRange: blockRange,
+			},
+		},
+		"mixed": {
+			Block: &hcl.Block{
+				Type: "required_providers",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"legacy": {
+							Name: "legacy",
+							Expr: hcltest.MockExprLiteral(cty.StringVal("1.0.0")),
+						},
+						"my-test": {
+							Name: "my-test",
+							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
+								"source":  cty.StringVal("mycloud/test"),
+								"version": cty.StringVal("2.0.0"),
+							})),
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			Want: &RequiredProviders{
+				RequiredProviders: map[string]*RequiredProvider{
+					"legacy": {
+						Name:        "legacy",
+						Type:        addrs.NewDefaultProvider("legacy"),
+						Requirement: testVC("1.0.0"),
+						DeclRange:   mockRange,
+					},
+					"my-test": {
+						Name:        "my-test",
+						Source:      "mycloud/test",
+						Type:        addrs.NewProvider(addrs.DefaultProviderRegistryHost, "mycloud", "test"),
+						Requirement: testVC("2.0.0"),
+						DeclRange:   mockRange,
+					},
+				},
+				DeclRange: blockRange,
+			},
+		},
+		"version-only block": {
+			Block: &hcl.Block{
+				Type: "required_providers",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"test": {
+							Name: "test",
+							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
+								"version": cty.StringVal("~>2.0.0"),
+							})),
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			Want: &RequiredProviders{
+				RequiredProviders: map[string]*RequiredProvider{
+					"test": {
+						Name:        "test",
+						Type:        addrs.NewDefaultProvider("test"),
+						Requirement: testVC("~>2.0.0"),
+						DeclRange:   mockRange,
+					},
+				},
+				DeclRange: blockRange,
+			},
+		},
+		"invalid source": {
+			Block: &hcl.Block{
+				Type: "required_providers",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"my-test": {
+							Name: "my-test",
+							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
+								"source":  cty.StringVal("some/invalid/provider/source/test"),
+								"version": cty.StringVal("~>2.0.0"),
+							})),
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			Want: &RequiredProviders{
+				RequiredProviders: map[string]*RequiredProvider{},
+				DeclRange:         blockRange,
+			},
+			Error: "Invalid provider source string",
+		},
+		"invalid localname": {
+			Block: &hcl.Block{
+				Type: "required_providers",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"my_test": {
+							Name: "my_test",
+							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
+								"version": cty.StringVal("~>2.0.0"),
+							})),
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			Want: &RequiredProviders{
+				RequiredProviders: map[string]*RequiredProvider{},
+				DeclRange:         blockRange,
+			},
+			Error: "Invalid provider local name",
+		},
+		"invalid localname caps": {
+			Block: &hcl.Block{
+				Type: "required_providers",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"MYTEST": {
+							Name: "MYTEST",
+							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
+								"version": cty.StringVal("~>2.0.0"),
+							})),
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			Want: &RequiredProviders{
+				RequiredProviders: map[string]*RequiredProvider{},
+				DeclRange:         blockRange,
+			},
+			Error: "Invalid provider local name",
+		},
+		"version constraint error": {
+			Block: &hcl.Block{
+				Type: "required_providers",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"my-test": {
+							Name: "my-test",
+							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
+								"source":  cty.StringVal("mycloud/test"),
+								"version": cty.StringVal("invalid"),
+							})),
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			Want: &RequiredProviders{
+				RequiredProviders: map[string]*RequiredProvider{},
+				DeclRange:         blockRange,
+			},
+			Error: "Invalid version constraint",
+		},
+		"invalid required_providers attribute value": {
+			Block: &hcl.Block{
+				Type: "required_providers",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"test": {
+							Name: "test",
+							Expr: hcltest.MockExprLiteral(cty.ListVal([]cty.Value{cty.StringVal("2.0.0")})),
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			Want: &RequiredProviders{
+				RequiredProviders: map[string]*RequiredProvider{},
+				DeclRange:         blockRange,
+			},
+			Error: "Invalid required_providers object",
+		},
+		"invalid source attribute type": {
+			Block: &hcl.Block{
+				Type: "required_providers",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"my-test": {
+							Name: "my-test",
+							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
+								"source": cty.DynamicVal,
+							})),
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			Want: &RequiredProviders{
+				RequiredProviders: map[string]*RequiredProvider{},
+				DeclRange:         blockRange,
+			},
+			Error: "Invalid source",
+		},
+		"additional attributes": {
+			Block: &hcl.Block{
+				Type: "required_providers",
+				Body: hcltest.MockBody(&hcl.BodyContent{
+					Attributes: hcl.Attributes{
+						"my-test": {
+							Name: "my-test",
+							Expr: hcltest.MockExprLiteral(cty.ObjectVal(map[string]cty.Value{
+								"source":  cty.StringVal("mycloud/test"),
+								"version": cty.StringVal("2.0.0"),
+								"invalid": cty.BoolVal(true),
+							})),
+						},
+					},
+				}),
+				DefRange: blockRange,
+			},
+			Want: &RequiredProviders{
+				RequiredProviders: map[string]*RequiredProvider{},
+				DeclRange:         blockRange,
+			},
+			Error: "Invalid required_providers object",
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got, diags := decodeRequiredProvidersBlock(test.Block)
+			if diags.HasErrors() {
+				if test.Error == "" {
+					t.Fatalf("unexpected error: %v", diags)
+				}
+				if gotErr := diags[0].Summary; gotErr != test.Error {
+					t.Errorf("wrong error, got %q, want %q", gotErr, test.Error)
+				}
+			} else if test.Error != "" {
+				t.Fatalf("expected error")
+			}
+
+			if !cmp.Equal(got, test.Want, ignoreUnexported, comparer) {
+				t.Fatalf("wrong result:\n %s", cmp.Diff(got, test.Want, ignoreUnexported, comparer))
+			}
+		})
+	}
+}
+
+func testVC(ver string) VersionConstraint {
+	constraint, _ := version.NewConstraint(ver)
+	return VersionConstraint{
+		Required:  constraint,
+		DeclRange: hcl.Range{},
+	}
+}
diff --git a/v1.5.7/internal/configs/provider_test.go b/v1.5.7/internal/configs/provider_test.go
new file mode 100644
index 0000000..2795022
--- /dev/null
+++ b/v1.5.7/internal/configs/provider_test.go
@@ -0,0 +1,153 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"io/ioutil"
+	"testing"
+
+	"github.com/go-test/deep"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestProviderReservedNames(t *testing.T) {
+	src, err := ioutil.ReadFile("testdata/invalid-files/provider-reserved.tf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	parser := testParser(map[string]string{
+		"config.tf": string(src),
+	})
+	_, diags := parser.LoadConfigFile("config.tf")
+
+	assertExactDiagnostics(t, diags, []string{
+		//TODO: This deprecation warning will be removed in terraform v0.15.
+		`config.tf:4,13-20: Version constraints inside provider configuration blocks are deprecated; Terraform 0.13 and earlier allowed provider version constraints inside the provider configuration block, but that is now deprecated and will be removed in a future version of Terraform. To silence this warning, move the provider version constraint into the required_providers block.`,
+		`config.tf:10,3-8: Reserved argument name in provider block; The provider argument name "count" is reserved for use by Terraform in a future version.`,
+		`config.tf:11,3-13: Reserved argument name in provider block; The provider argument name "depends_on" is reserved for use by Terraform in a future version.`,
+		`config.tf:12,3-11: Reserved argument name in provider block; The provider argument name "for_each" is reserved for use by Terraform in a future version.`,
+		`config.tf:14,3-12: Reserved block type name in provider block; The block type name "lifecycle" is reserved for use by Terraform in a future version.`,
+		`config.tf:15,3-9: Reserved block type name in provider block; The block type name "locals" is reserved for use by Terraform in a future version.`,
+		`config.tf:13,3-9: Reserved argument name in provider block; The provider argument name "source" is reserved for use by Terraform in a future version.`,
+	})
+}
+
+func TestParseProviderConfigCompact(t *testing.T) {
+	tests := []struct {
+		Input    string
+		Want     addrs.LocalProviderConfig
+		WantDiag string
+	}{
+		{
+			`aws`,
+			addrs.LocalProviderConfig{
+				LocalName: "aws",
+			},
+			``,
+		},
+		{
+			`aws.foo`,
+			addrs.LocalProviderConfig{
+				LocalName: "aws",
+				Alias:     "foo",
+			},
+			``,
+		},
+		{
+			`aws["foo"]`,
+			addrs.LocalProviderConfig{},
+			`The provider type name must either stand alone or be followed by an alias name separated with a dot.`,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Input, func(t *testing.T) {
+			traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(test.Input), "", hcl.Pos{})
+			if len(parseDiags) != 0 {
+				t.Errorf("unexpected diagnostics during parse")
+				for _, diag := range parseDiags {
+					t.Logf("- %s", diag)
+				}
+				return
+			}
+
+			got, diags := ParseProviderConfigCompact(traversal)
+
+			if test.WantDiag != "" {
+				if len(diags) != 1 {
+					t.Fatalf("got %d diagnostics; want 1", len(diags))
+				}
+				gotDetail := diags[0].Description().Detail
+				if gotDetail != test.WantDiag {
+					t.Fatalf("wrong diagnostic detail\ngot:  %s\nwant: %s", gotDetail, test.WantDiag)
+				}
+				return
+			} else {
+				if len(diags) != 0 {
+					t.Fatalf("got %d diagnostics; want 0", len(diags))
+				}
+			}
+
+			for _, problem := range deep.Equal(got, test.Want) {
+				t.Error(problem)
+			}
+		})
+	}
+}
+
+func TestParseProviderConfigCompactStr(t *testing.T) {
+	tests := []struct {
+		Input    string
+		Want     addrs.LocalProviderConfig
+		WantDiag string
+	}{
+		{
+			`aws`,
+			addrs.LocalProviderConfig{
+				LocalName: "aws",
+			},
+			``,
+		},
+		{
+			`aws.foo`,
+			addrs.LocalProviderConfig{
+				LocalName: "aws",
+				Alias:     "foo",
+			},
+			``,
+		},
+		{
+			`aws["foo"]`,
+			addrs.LocalProviderConfig{},
+			`The provider type name must either stand alone or be followed by an alias name separated with a dot.`,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Input, func(t *testing.T) {
+			got, diags := ParseProviderConfigCompactStr(test.Input)
+
+			if test.WantDiag != "" {
+				if len(diags) != 1 {
+					t.Fatalf("got %d diagnostics; want 1", len(diags))
+				}
+				gotDetail := diags[0].Description().Detail
+				if gotDetail != test.WantDiag {
+					t.Fatalf("wrong diagnostic detail\ngot:  %s\nwant: %s", gotDetail, test.WantDiag)
+				}
+				return
+			} else {
+				if len(diags) != 0 {
+					t.Fatalf("got %d diagnostics; want 0", len(diags))
+				}
+			}
+
+			for _, problem := range deep.Equal(got, test.Want) {
+				t.Error(problem)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/configs/provider_validation.go b/v1.5.7/internal/configs/provider_validation.go
new file mode 100644
index 0000000..f9a7048
--- /dev/null
+++ b/v1.5.7/internal/configs/provider_validation.go
@@ -0,0 +1,541 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// validateProviderConfigs walks the full configuration tree from the root
+// module outward, static validation rules to the various combinations of
+// provider configuration, required_providers values, and module call providers
+// mappings.
+//
+// To retain compatibility with previous terraform versions, empty "proxy
+// provider blocks" are still allowed within modules, though they will
+// generate warnings when the configuration is loaded. The new validation
+// however will generate an error if a suitable provider configuration is not
+// passed in through the module call.
+//
+// The call argument is the ModuleCall for the provided Config cfg. The
+// noProviderConfigRange argument is passed down the call stack, indicating
+// that the module call, or a parent module call, has used a feature (at the
+// specified source location) that precludes providers from being configured at
+// all within the module.
+func validateProviderConfigs(parentCall *ModuleCall, cfg *Config, noProviderConfigRange *hcl.Range) (diags hcl.Diagnostics) {
+	mod := cfg.Module
+
+	for name, child := range cfg.Children {
+		mc := mod.ModuleCalls[name]
+		childNoProviderConfigRange := noProviderConfigRange
+		// if the module call has any of count, for_each or depends_on,
+		// providers are prohibited from being configured in this module, or
+		// any module beneath this module.
+		switch {
+		case mc.Count != nil:
+			childNoProviderConfigRange = mc.Count.Range().Ptr()
+		case mc.ForEach != nil:
+			childNoProviderConfigRange = mc.ForEach.Range().Ptr()
+		case mc.DependsOn != nil:
+			if len(mc.DependsOn) > 0 {
+				childNoProviderConfigRange = mc.DependsOn[0].SourceRange().Ptr()
+			} else {
+				// Weird! We'll just use the call itself, then.
+				childNoProviderConfigRange = mc.DeclRange.Ptr()
+			}
+		}
+		diags = append(diags, validateProviderConfigs(mc, child, childNoProviderConfigRange)...)
+	}
+
+	// the set of provider configuration names passed into the module, with the
+	// source range of the provider assignment in the module call.
+	passedIn := map[string]PassedProviderConfig{}
+
+	// the set of empty configurations that could be proxy configurations, with
+	// the source range of the empty configuration block.
+	emptyConfigs := map[string]hcl.Range{}
+
+	// the set of provider with a defined configuration, with the source range
+	// of the configuration block declaration.
+	configured := map[string]hcl.Range{}
+
+	// the set of configuration_aliases defined in the required_providers
+	// block, with the fully qualified provider type.
+	configAliases := map[string]addrs.AbsProviderConfig{}
+
+	// the set of provider names defined in the required_providers block, and
+	// their provider types.
+	localNames := map[string]addrs.Provider{}
+
+	for _, pc := range mod.ProviderConfigs {
+		name := providerName(pc.Name, pc.Alias)
+		// Validate the config against an empty schema to see if it's empty.
+		_, pcConfigDiags := pc.Config.Content(&hcl.BodySchema{})
+		if pcConfigDiags.HasErrors() || pc.Version.Required != nil {
+			configured[name] = pc.DeclRange
+		} else {
+			emptyConfigs[name] = pc.DeclRange
+		}
+	}
+
+	if mod.ProviderRequirements != nil {
+		// Track all known local types too to ensure we don't have duplicated
+		// with different local names.
+		localTypes := map[string]bool{}
+
+		// check for duplicate requirements of the same type
+		for _, req := range mod.ProviderRequirements.RequiredProviders {
+			if localTypes[req.Type.String()] {
+				// find the last declaration to give a better error
+				prevDecl := ""
+				for localName, typ := range localNames {
+					if typ.Equals(req.Type) {
+						prevDecl = localName
+					}
+				}
+
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagWarning,
+					Summary:  "Duplicate required provider",
+					Detail: fmt.Sprintf(
+						"Provider %s with the local name %q was previously required as %q. A provider can only be required once within required_providers.",
+						req.Type.ForDisplay(), req.Name, prevDecl,
+					),
+					Subject: &req.DeclRange,
+				})
+			} else if addrs.IsDefaultProvider(req.Type) {
+				// Now check for possible implied duplicates, where a provider
+				// block uses a default namespaced provider, but that provider
+				// was required via a different name.
+				impliedLocalName := req.Type.Type
+				// We have to search through the configs for a match, since the keys contains any aliases.
+				for _, pc := range mod.ProviderConfigs {
+					if pc.Name == impliedLocalName && req.Name != impliedLocalName {
+						diags = append(diags, &hcl.Diagnostic{
+							Severity: hcl.DiagWarning,
+							Summary:  "Duplicate required provider",
+							Detail: fmt.Sprintf(
+								"Provider %s with the local name %q was implicitly required via a configuration block as %q. The provider configuration block name must match the name used in required_providers.",
+								req.Type.ForDisplay(), req.Name, req.Type.Type,
+							),
+							Subject: &req.DeclRange,
+						})
+						break
+					}
+				}
+			}
+
+			localTypes[req.Type.String()] = true
+
+			localNames[req.Name] = req.Type
+			for _, alias := range req.Aliases {
+				addr := addrs.AbsProviderConfig{
+					Module:   cfg.Path,
+					Provider: req.Type,
+					Alias:    alias.Alias,
+				}
+				configAliases[providerName(alias.LocalName, alias.Alias)] = addr
+			}
+		}
+	}
+
+	checkImpliedProviderNames := func(resourceConfigs map[string]*Resource) {
+		// Now that we have all the provider configs and requirements validated,
+		// check for any resources which use an implied localname which doesn't
+		// match that of required_providers
+		for _, r := range resourceConfigs {
+			// We're looking for resources with no specific provider reference
+			if r.ProviderConfigRef != nil {
+				continue
+			}
+
+			localName := r.Addr().ImpliedProvider()
+
+			_, err := addrs.ParseProviderPart(localName)
+			if err != nil {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid provider local name",
+					Detail:   fmt.Sprintf("%q is an invalid implied provider local name: %s", localName, err),
+					Subject:  r.DeclRange.Ptr(),
+				})
+				continue
+			}
+
+			if _, ok := localNames[localName]; ok {
+				// OK, this was listed directly in the required_providers
+				continue
+			}
+
+			defAddr := addrs.ImpliedProviderForUnqualifiedType(localName)
+
+			// Now make sure we don't have the same provider required under a
+			// different name.
+			for prevLocalName, addr := range localNames {
+				if addr.Equals(defAddr) {
+					diags = append(diags, &hcl.Diagnostic{
+						Severity: hcl.DiagWarning,
+						Summary:  "Duplicate required provider",
+						Detail: fmt.Sprintf(
+							"Provider %q was implicitly required via resource %q, but listed in required_providers as %q. Either the local name in required_providers must match the resource name, or the %q provider must be assigned within the resource block.",
+							defAddr, r.Addr(), prevLocalName, prevLocalName,
+						),
+						Subject: &r.DeclRange,
+					})
+				}
+			}
+		}
+	}
+	checkImpliedProviderNames(mod.ManagedResources)
+	checkImpliedProviderNames(mod.DataResources)
+
+	// collect providers passed from the parent
+	if parentCall != nil {
+		for _, passed := range parentCall.Providers {
+			name := providerName(passed.InChild.Name, passed.InChild.Alias)
+			passedIn[name] = passed
+		}
+	}
+
+	parentModuleText := "the root module"
+	moduleText := "the root module"
+	if !cfg.Path.IsRoot() {
+		moduleText = cfg.Path.String()
+		if parent := cfg.Path.Parent(); !parent.IsRoot() {
+			// module address are prefixed with `module.`
+			parentModuleText = parent.String()
+		}
+	}
+
+	// Verify that any module calls only refer to named providers, and that
+	// those providers will have a configuration at runtime. This way we can
+	// direct users where to add the missing configuration, because the runtime
+	// error is only "missing provider X".
+	for _, modCall := range mod.ModuleCalls {
+		for _, passed := range modCall.Providers {
+			// aliased providers are handled more strictly, and are never
+			// inherited, so they are validated within modules further down.
+			// Skip these checks to prevent redundant diagnostics.
+			if passed.InParent.Alias != "" {
+				continue
+			}
+
+			name := passed.InParent.String()
+			_, confOK := configured[name]
+			_, localOK := localNames[name]
+			_, passedOK := passedIn[name]
+
+			// This name was not declared somewhere within in the
+			// configuration. We ignore empty configs, because they will
+			// already produce a warning.
+			if !(confOK || localOK) {
+				defAddr := addrs.NewDefaultProvider(name)
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagWarning,
+					Summary:  "Reference to undefined provider",
+					Detail: fmt.Sprintf(
+						"There is no explicit declaration for local provider name %q in %s, so Terraform is assuming you mean to pass a configuration for provider %q.\n\nTo clarify your intent and silence this warning, add to %s a required_providers entry named %q with source = %q, or a different source address if appropriate.",
+						name, moduleText, defAddr.ForDisplay(),
+						parentModuleText, name, defAddr.ForDisplay(),
+					),
+					Subject: &passed.InParent.NameRange,
+				})
+				continue
+			}
+
+			// Now we may have named this provider within the module, but
+			// there won't be a configuration available at runtime if the
+			// parent module did not pass one in.
+			if !cfg.Path.IsRoot() && !(confOK || passedOK) {
+				defAddr := addrs.NewDefaultProvider(name)
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagWarning,
+					Summary:  "Missing required provider configuration",
+					Detail: fmt.Sprintf(
+						"The configuration for %s expects to inherit a configuration for provider %s with local name %q, but %s doesn't pass a configuration under that name.\n\nTo satisfy this requirement, add an entry for %q to the \"providers\" argument in the module %q block.",
+						moduleText, defAddr.ForDisplay(), name, parentModuleText,
+						name, parentCall.Name,
+					),
+					Subject: parentCall.DeclRange.Ptr(),
+				})
+			}
+		}
+	}
+
+	if cfg.Path.IsRoot() {
+		// nothing else to do in the root module
+		return diags
+	}
+
+	// there cannot be any configurations if no provider config is allowed
+	if len(configured) > 0 && noProviderConfigRange != nil {
+		// We report this from the perspective of the use of count, for_each,
+		// or depends_on rather than from inside the module, because the
+		// recipient of this message is more likely to be the author of the
+		// calling module (trying to use an older module that hasn't been
+		// updated yet) than of the called module.
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Module is incompatible with count, for_each, and depends_on",
+			Detail: fmt.Sprintf(
+				"The module at %s is a legacy module which contains its own local provider configurations, and so calls to it may not use the count, for_each, or depends_on arguments.\n\nIf you also control the module %q, consider updating this module to instead expect provider configurations to be passed by its caller.",
+				cfg.Path, cfg.SourceAddr,
+			),
+			Subject: noProviderConfigRange,
+		})
+	}
+
+	// now check that the user is not attempting to override a config
+	for name := range configured {
+		if passed, ok := passedIn[name]; ok {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Cannot override provider configuration",
+				Detail: fmt.Sprintf(
+					"The configuration of %s has its own local configuration for %s, and so it cannot accept an overridden configuration provided by %s.",
+					moduleText, name, parentModuleText,
+				),
+				Subject: &passed.InChild.NameRange,
+			})
+		}
+	}
+
+	// A declared alias requires either a matching configuration within the
+	// module, or one must be passed in.
+	for name, providerAddr := range configAliases {
+		_, confOk := configured[name]
+		_, passedOk := passedIn[name]
+
+		if confOk || passedOk {
+			continue
+		}
+
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Missing required provider configuration",
+			Detail: fmt.Sprintf(
+				"The child module requires an additional configuration for provider %s, with the local name %q.\n\nRefer to the module's documentation to understand the intended purpose of this additional provider configuration, and then add an entry for %s in the \"providers\" meta-argument in the module block to choose which provider configuration the module should use for that purpose.",
+				providerAddr.Provider.ForDisplay(), name,
+				name,
+			),
+			Subject: &parentCall.DeclRange,
+		})
+	}
+
+	// You cannot pass in a provider that cannot be used
+	for name, passed := range passedIn {
+		childTy := passed.InChild.providerType
+		// get a default type if there was none set
+		if childTy.IsZero() {
+			// This means the child module is only using an inferred
+			// provider type. We allow this but will generate a warning to
+			// declare provider_requirements below.
+			childTy = addrs.NewDefaultProvider(passed.InChild.Name)
+		}
+
+		providerAddr := addrs.AbsProviderConfig{
+			Module:   cfg.Path,
+			Provider: childTy,
+			Alias:    passed.InChild.Alias,
+		}
+
+		localAddr, localName := localNames[name]
+		if localName {
+			providerAddr.Provider = localAddr
+		}
+
+		aliasAddr, configAlias := configAliases[name]
+		if configAlias {
+			providerAddr = aliasAddr
+		}
+
+		_, emptyConfig := emptyConfigs[name]
+
+		if !(localName || configAlias || emptyConfig) {
+
+			// we still allow default configs, so switch to a warning if the incoming provider is a default
+			if addrs.IsDefaultProvider(providerAddr.Provider) {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagWarning,
+					Summary:  "Reference to undefined provider",
+					Detail: fmt.Sprintf(
+						"There is no explicit declaration for local provider name %q in %s, so Terraform is assuming you mean to pass a configuration for %q.\n\nIf you also control the child module, add a required_providers entry named %q with the source address %q.",
+						name, moduleText, providerAddr.Provider.ForDisplay(),
+						name, providerAddr.Provider.ForDisplay(),
+					),
+					Subject: &passed.InChild.NameRange,
+				})
+			} else {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Reference to undefined provider",
+					Detail: fmt.Sprintf(
+						"The child module does not declare any provider requirement with the local name %q.\n\nIf you also control the child module, you can add a required_providers entry named %q with the source address %q to accept this provider configuration.",
+						name, name, providerAddr.Provider.ForDisplay(),
+					),
+					Subject: &passed.InChild.NameRange,
+				})
+			}
+		}
+
+		// The provider being passed in must also be of the correct type.
+		pTy := passed.InParent.providerType
+		if pTy.IsZero() {
+			// While we would like to ensure required_providers exists here,
+			// implied default configuration is still allowed.
+			pTy = addrs.NewDefaultProvider(passed.InParent.Name)
+		}
+
+		// use the full address for a nice diagnostic output
+		parentAddr := addrs.AbsProviderConfig{
+			Module:   cfg.Parent.Path,
+			Provider: pTy,
+			Alias:    passed.InParent.Alias,
+		}
+
+		if cfg.Parent.Module.ProviderRequirements != nil {
+			req, defined := cfg.Parent.Module.ProviderRequirements.RequiredProviders[name]
+			if defined {
+				parentAddr.Provider = req.Type
+			}
+		}
+
+		if !providerAddr.Provider.Equals(parentAddr.Provider) {
+			// If this module declares the same source address for a different
+			// local name then we'll prefer to suggest changing to match
+			// the child module's chosen name, assuming that it was the local
+			// name that was wrong rather than the source address.
+			var otherLocalName string
+			for localName, sourceAddr := range localNames {
+				if sourceAddr.Equals(parentAddr.Provider) {
+					otherLocalName = localName
+					break
+				}
+			}
+
+			const errSummary = "Provider type mismatch"
+			if otherLocalName != "" {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  errSummary,
+					Detail: fmt.Sprintf(
+						"The assigned configuration is for provider %q, but local name %q in %s represents %q.\n\nTo pass this configuration to the child module, use the local name %q instead.",
+						parentAddr.Provider.ForDisplay(), passed.InChild.Name,
+						parentModuleText, providerAddr.Provider.ForDisplay(),
+						otherLocalName,
+					),
+					Subject: &passed.InChild.NameRange,
+				})
+			} else {
+				// If there is no declared requirement for the provider the
+				// caller is trying to pass under any name then we'll instead
+				// report it as an unsuitable configuration to pass into the
+				// child module's provider configuration slot.
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  errSummary,
+					Detail: fmt.Sprintf(
+						"The local name %q in %s represents provider %q, but %q in %s represents %q.\n\nEach provider has its own distinct configuration schema and provider types, so this module's %q can be assigned only a configuration for %s, which is not required by %s.",
+						passed.InParent, parentModuleText, parentAddr.Provider.ForDisplay(),
+						passed.InChild, moduleText, providerAddr.Provider.ForDisplay(),
+						passed.InChild, providerAddr.Provider.ForDisplay(),
+						moduleText,
+					),
+					Subject: passed.InParent.NameRange.Ptr(),
+				})
+			}
+		}
+	}
+
+	// Empty configurations are no longer needed. Since the replacement for
+	// this calls for one entry per provider rather than one entry per
+	// provider _configuration_, we'll first gather them up by provider
+	// and then report a single warning for each, whereby we can show a direct
+	// example of what the replacement should look like.
+	type ProviderReqSuggestion struct {
+		SourceAddr      addrs.Provider
+		SourceRanges    []hcl.Range
+		RequiredConfigs []string
+		AliasCount      int
+	}
+	providerReqSuggestions := make(map[string]*ProviderReqSuggestion)
+	for name, src := range emptyConfigs {
+		providerLocalName := name
+		if idx := strings.IndexByte(providerLocalName, '.'); idx >= 0 {
+			providerLocalName = providerLocalName[:idx]
+		}
+
+		sourceAddr, ok := localNames[name]
+		if !ok {
+			sourceAddr = addrs.NewDefaultProvider(providerLocalName)
+		}
+
+		suggestion := providerReqSuggestions[providerLocalName]
+		if suggestion == nil {
+			providerReqSuggestions[providerLocalName] = &ProviderReqSuggestion{
+				SourceAddr: sourceAddr,
+			}
+			suggestion = providerReqSuggestions[providerLocalName]
+		}
+
+		if providerLocalName != name {
+			// It's an aliased provider config, then.
+			suggestion.AliasCount++
+		}
+
+		suggestion.RequiredConfigs = append(suggestion.RequiredConfigs, name)
+		suggestion.SourceRanges = append(suggestion.SourceRanges, src)
+	}
+	for name, suggestion := range providerReqSuggestions {
+		var buf strings.Builder
+
+		fmt.Fprintf(
+			&buf,
+			"Earlier versions of Terraform used empty provider blocks (\"proxy provider configurations\") for child modules to declare their need to be passed a provider configuration by their callers. That approach was ambiguous and is now deprecated.\n\nIf you control this module, you can migrate to the new declaration syntax by removing all of the empty provider %q blocks and then adding or updating an entry like the following to the required_providers block of %s:\n",
+			name, moduleText,
+		)
+		fmt.Fprintf(&buf, "    %s = {\n", name)
+		fmt.Fprintf(&buf, "      source = %q\n", suggestion.SourceAddr.ForDisplay())
+		if suggestion.AliasCount > 0 {
+			// A lexical sort is fine because all of these strings are
+			// guaranteed to start with the same provider local name, and
+			// so we're only really sorting by the alias part.
+			sort.Strings(suggestion.RequiredConfigs)
+			fmt.Fprintln(&buf, "      configuration_aliases = [")
+			for _, addrStr := range suggestion.RequiredConfigs {
+				fmt.Fprintf(&buf, "        %s,\n", addrStr)
+			}
+			fmt.Fprintln(&buf, "      ]")
+
+		}
+		fmt.Fprint(&buf, "    }")
+
+		// We're arbitrarily going to just take the one source range that
+		// sorts earliest here. Multiple should be rare, so this is only to
+		// ensure that we produce a deterministic result in the edge case.
+		sort.Slice(suggestion.SourceRanges, func(i, j int) bool {
+			return suggestion.SourceRanges[i].String() < suggestion.SourceRanges[j].String()
+		})
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagWarning,
+			Summary:  "Redundant empty provider block",
+			Detail:   buf.String(),
+			Subject:  suggestion.SourceRanges[0].Ptr(),
+		})
+	}
+
+	return diags
+}
+
+func providerName(name, alias string) string {
+	if alias != "" {
+		name = name + "." + alias
+	}
+	return name
+}
diff --git a/v1.5.7/internal/configs/provisioner.go b/v1.5.7/internal/configs/provisioner.go
new file mode 100644
index 0000000..9b0413b
--- /dev/null
+++ b/v1.5.7/internal/configs/provisioner.go
@@ -0,0 +1,240 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+)
+
+// Provisioner represents a "provisioner" block when used within a
+// "resource" block in a module or file.
+type Provisioner struct {
+	Type       string
+	Config     hcl.Body
+	Connection *Connection
+	When       ProvisionerWhen
+	OnFailure  ProvisionerOnFailure
+
+	DeclRange hcl.Range
+	TypeRange hcl.Range
+}
+
+func decodeProvisionerBlock(block *hcl.Block) (*Provisioner, hcl.Diagnostics) {
+	pv := &Provisioner{
+		Type:      block.Labels[0],
+		TypeRange: block.LabelRanges[0],
+		DeclRange: block.DefRange,
+		When:      ProvisionerWhenCreate,
+		OnFailure: ProvisionerOnFailureFail,
+	}
+
+	content, config, diags := block.Body.PartialContent(provisionerBlockSchema)
+	pv.Config = config
+
+	switch pv.Type {
+	case "chef", "habitat", "puppet", "salt-masterless":
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  fmt.Sprintf("The \"%s\" provisioner has been removed", pv.Type),
+			Detail:   fmt.Sprintf("The \"%s\" provisioner was deprecated in Terraform 0.13.4 has been removed from Terraform. Visit https://learn.hashicorp.com/collections/terraform/provision for alternatives to using provisioners that are a better fit for the Terraform workflow.", pv.Type),
+			Subject:  &pv.TypeRange,
+		})
+		return nil, diags
+	}
+
+	if attr, exists := content.Attributes["when"]; exists {
+		expr, shimDiags := shimTraversalInString(attr.Expr, true)
+		diags = append(diags, shimDiags...)
+
+		switch hcl.ExprAsKeyword(expr) {
+		case "create":
+			pv.When = ProvisionerWhenCreate
+		case "destroy":
+			pv.When = ProvisionerWhenDestroy
+		default:
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid \"when\" keyword",
+				Detail:   "The \"when\" argument requires one of the following keywords: create or destroy.",
+				Subject:  expr.Range().Ptr(),
+			})
+		}
+	}
+
+	// destroy provisioners can only refer to self
+	if pv.When == ProvisionerWhenDestroy {
+		diags = append(diags, onlySelfRefs(config)...)
+	}
+
+	if attr, exists := content.Attributes["on_failure"]; exists {
+		expr, shimDiags := shimTraversalInString(attr.Expr, true)
+		diags = append(diags, shimDiags...)
+
+		switch hcl.ExprAsKeyword(expr) {
+		case "continue":
+			pv.OnFailure = ProvisionerOnFailureContinue
+		case "fail":
+			pv.OnFailure = ProvisionerOnFailureFail
+		default:
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid \"on_failure\" keyword",
+				Detail:   "The \"on_failure\" argument requires one of the following keywords: continue or fail.",
+				Subject:  attr.Expr.Range().Ptr(),
+			})
+		}
+	}
+
+	var seenConnection *hcl.Block
+	var seenEscapeBlock *hcl.Block
+	for _, block := range content.Blocks {
+		switch block.Type {
+		case "_":
+			if seenEscapeBlock != nil {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Duplicate escaping block",
+					Detail: fmt.Sprintf(
+						"The special block type \"_\" can be used to force particular arguments to be interpreted as provisioner-typpe-specific rather than as meta-arguments, but each provisioner block can have only one such block. The first escaping block was at %s.",
+						seenEscapeBlock.DefRange,
+					),
+					Subject: &block.DefRange,
+				})
+				continue
+			}
+			seenEscapeBlock = block
+
+			// When there's an escaping block its content merges with the
+			// existing config we extracted earlier, so later decoding
+			// will see a blend of both.
+			pv.Config = hcl.MergeBodies([]hcl.Body{pv.Config, block.Body})
+
+		case "connection":
+			if seenConnection != nil {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Duplicate connection block",
+					Detail:   fmt.Sprintf("This provisioner already has a connection block at %s.", seenConnection.DefRange),
+					Subject:  &block.DefRange,
+				})
+				continue
+			}
+			seenConnection = block
+
+			// destroy provisioners can only refer to self
+			if pv.When == ProvisionerWhenDestroy {
+				diags = append(diags, onlySelfRefs(block.Body)...)
+			}
+
+			pv.Connection = &Connection{
+				Config:    block.Body,
+				DeclRange: block.DefRange,
+			}
+
+		default:
+			// Any other block types are ones we've reserved for future use,
+			// so they get a generic message.
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Reserved block type name in provisioner block",
+				Detail:   fmt.Sprintf("The block type name %q is reserved for use by Terraform in a future version.", block.Type),
+				Subject:  &block.TypeRange,
+			})
+		}
+	}
+
+	return pv, diags
+}
+
+func onlySelfRefs(body hcl.Body) hcl.Diagnostics {
+	var diags hcl.Diagnostics
+
+	// Provisioners currently do not use any blocks in their configuration.
+	// Blocks are likely to remain solely for meta parameters, but in the case
+	// that blocks are supported for provisioners, we will want to extend this
+	// to find variables in nested blocks.
+	attrs, _ := body.JustAttributes()
+	for _, attr := range attrs {
+		for _, v := range attr.Expr.Variables() {
+			valid := false
+			switch v.RootName() {
+			case "self", "path", "terraform":
+				valid = true
+			case "count":
+				// count must use "index"
+				if len(v) == 2 {
+					if t, ok := v[1].(hcl.TraverseAttr); ok && t.Name == "index" {
+						valid = true
+					}
+				}
+
+			case "each":
+				if len(v) == 2 {
+					if t, ok := v[1].(hcl.TraverseAttr); ok && t.Name == "key" {
+						valid = true
+					}
+				}
+			}
+
+			if !valid {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid reference from destroy provisioner",
+					Detail: "Destroy-time provisioners and their connection configurations may only " +
+						"reference attributes of the related resource, via 'self', 'count.index', " +
+						"or 'each.key'.\n\nReferences to other resources during the destroy phase " +
+						"can cause dependency cycles and interact poorly with create_before_destroy.",
+					Subject: attr.Expr.Range().Ptr(),
+				})
+			}
+		}
+	}
+	return diags
+}
+
+// Connection represents a "connection" block when used within either a
+// "resource" or "provisioner" block in a module or file.
+type Connection struct {
+	Config hcl.Body
+
+	DeclRange hcl.Range
+}
+
+// ProvisionerWhen is an enum for valid values for when to run provisioners.
+type ProvisionerWhen int
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type ProvisionerWhen
+
+const (
+	ProvisionerWhenInvalid ProvisionerWhen = iota
+	ProvisionerWhenCreate
+	ProvisionerWhenDestroy
+)
+
+// ProvisionerOnFailure is an enum for valid values for on_failure options
+// for provisioners.
+type ProvisionerOnFailure int
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type ProvisionerOnFailure
+
+const (
+	ProvisionerOnFailureInvalid ProvisionerOnFailure = iota
+	ProvisionerOnFailureContinue
+	ProvisionerOnFailureFail
+)
+
+var provisionerBlockSchema = &hcl.BodySchema{
+	Attributes: []hcl.AttributeSchema{
+		{Name: "when"},
+		{Name: "on_failure"},
+	},
+	Blocks: []hcl.BlockHeaderSchema{
+		{Type: "_"}, // meta-argument escaping block
+
+		{Type: "connection"},
+		{Type: "lifecycle"}, // reserved for future use
+	},
+}
diff --git a/v1.5.7/internal/configs/provisioneronfailure_string.go b/v1.5.7/internal/configs/provisioneronfailure_string.go
new file mode 100644
index 0000000..7ff5a6e
--- /dev/null
+++ b/v1.5.7/internal/configs/provisioneronfailure_string.go
@@ -0,0 +1,25 @@
+// Code generated by "stringer -type ProvisionerOnFailure"; DO NOT EDIT.
+
+package configs
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[ProvisionerOnFailureInvalid-0]
+	_ = x[ProvisionerOnFailureContinue-1]
+	_ = x[ProvisionerOnFailureFail-2]
+}
+
+const _ProvisionerOnFailure_name = "ProvisionerOnFailureInvalidProvisionerOnFailureContinueProvisionerOnFailureFail"
+
+var _ProvisionerOnFailure_index = [...]uint8{0, 27, 55, 79}
+
+func (i ProvisionerOnFailure) String() string {
+	if i < 0 || i >= ProvisionerOnFailure(len(_ProvisionerOnFailure_index)-1) {
+		return "ProvisionerOnFailure(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _ProvisionerOnFailure_name[_ProvisionerOnFailure_index[i]:_ProvisionerOnFailure_index[i+1]]
+}
diff --git a/v1.5.7/internal/configs/provisionerwhen_string.go b/v1.5.7/internal/configs/provisionerwhen_string.go
new file mode 100644
index 0000000..9f21b3a
--- /dev/null
+++ b/v1.5.7/internal/configs/provisionerwhen_string.go
@@ -0,0 +1,25 @@
+// Code generated by "stringer -type ProvisionerWhen"; DO NOT EDIT.
+
+package configs
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[ProvisionerWhenInvalid-0]
+	_ = x[ProvisionerWhenCreate-1]
+	_ = x[ProvisionerWhenDestroy-2]
+}
+
+const _ProvisionerWhen_name = "ProvisionerWhenInvalidProvisionerWhenCreateProvisionerWhenDestroy"
+
+var _ProvisionerWhen_index = [...]uint8{0, 22, 43, 65}
+
+func (i ProvisionerWhen) String() string {
+	if i < 0 || i >= ProvisionerWhen(len(_ProvisionerWhen_index)-1) {
+		return "ProvisionerWhen(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _ProvisionerWhen_name[_ProvisionerWhen_index[i]:_ProvisionerWhen_index[i+1]]
+}
diff --git a/v1.5.7/internal/configs/resource.go b/v1.5.7/internal/configs/resource.go
new file mode 100644
index 0000000..b88d93a
--- /dev/null
+++ b/v1.5.7/internal/configs/resource.go
@@ -0,0 +1,819 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/gohcl"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	hcljson "github.com/hashicorp/hcl/v2/json"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Resource represents a "resource" or "data" block in a module or file.
+type Resource struct {
+	Mode    addrs.ResourceMode
+	Name    string
+	Type    string
+	Config  hcl.Body
+	Count   hcl.Expression
+	ForEach hcl.Expression
+
+	ProviderConfigRef *ProviderConfigRef
+	Provider          addrs.Provider
+
+	Preconditions  []*CheckRule
+	Postconditions []*CheckRule
+
+	DependsOn []hcl.Traversal
+
+	TriggersReplacement []hcl.Expression
+
+	// Managed is populated only for Mode = addrs.ManagedResourceMode,
+	// containing the additional fields that apply to managed resources.
+	// For all other resource modes, this field is nil.
+	Managed *ManagedResource
+
+	// Container links a scoped resource back up to the resources that contains
+	// it. This field is referenced during static analysis to check whether any
+	// references are also made from within the same container.
+	//
+	// If this is nil, then this resource is essentially public.
+	Container Container
+
+	DeclRange hcl.Range
+	TypeRange hcl.Range
+}
+
+// ManagedResource represents a "resource" block in a module or file.
+type ManagedResource struct {
+	Connection   *Connection
+	Provisioners []*Provisioner
+
+	CreateBeforeDestroy bool
+	PreventDestroy      bool
+	IgnoreChanges       []hcl.Traversal
+	IgnoreAllChanges    bool
+
+	CreateBeforeDestroySet bool
+	PreventDestroySet      bool
+}
+
+func (r *Resource) moduleUniqueKey() string {
+	return r.Addr().String()
+}
+
+// Addr returns a resource address for the receiver that is relative to the
+// resource's containing module.
+func (r *Resource) Addr() addrs.Resource {
+	return addrs.Resource{
+		Mode: r.Mode,
+		Type: r.Type,
+		Name: r.Name,
+	}
+}
+
+// ProviderConfigAddr returns the address for the provider configuration that
+// should be used for this resource. This function returns a default provider
+// config addr if an explicit "provider" argument was not provided.
+func (r *Resource) ProviderConfigAddr() addrs.LocalProviderConfig {
+	if r.ProviderConfigRef == nil {
+		// If no specific "provider" argument is given, we want to look up the
+		// provider config where the local name matches the implied provider
+		// from the resource type. This may be different from the resource's
+		// provider type.
+		return addrs.LocalProviderConfig{
+			LocalName: r.Addr().ImpliedProvider(),
+		}
+	}
+
+	return addrs.LocalProviderConfig{
+		LocalName: r.ProviderConfigRef.Name,
+		Alias:     r.ProviderConfigRef.Alias,
+	}
+}
+
+// HasCustomConditions returns true if and only if the resource has at least
+// one author-specified custom condition.
+func (r *Resource) HasCustomConditions() bool {
+	return len(r.Postconditions) != 0 || len(r.Preconditions) != 0
+}
+
+func decodeResourceBlock(block *hcl.Block, override bool) (*Resource, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+	r := &Resource{
+		Mode:      addrs.ManagedResourceMode,
+		Type:      block.Labels[0],
+		Name:      block.Labels[1],
+		DeclRange: block.DefRange,
+		TypeRange: block.LabelRanges[0],
+		Managed:   &ManagedResource{},
+	}
+
+	content, remain, moreDiags := block.Body.PartialContent(ResourceBlockSchema)
+	diags = append(diags, moreDiags...)
+	r.Config = remain
+
+	if !hclsyntax.ValidIdentifier(r.Type) {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid resource type name",
+			Detail:   badIdentifierDetail,
+			Subject:  &block.LabelRanges[0],
+		})
+	}
+	if !hclsyntax.ValidIdentifier(r.Name) {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid resource name",
+			Detail:   badIdentifierDetail,
+			Subject:  &block.LabelRanges[1],
+		})
+	}
+
+	if attr, exists := content.Attributes["count"]; exists {
+		r.Count = attr.Expr
+	}
+
+	if attr, exists := content.Attributes["for_each"]; exists {
+		r.ForEach = attr.Expr
+		// Cannot have count and for_each on the same resource block
+		if r.Count != nil {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  `Invalid combination of "count" and "for_each"`,
+				Detail:   `The "count" and "for_each" meta-arguments are mutually-exclusive, only one should be used to be explicit about the number of resources to be created.`,
+				Subject:  &attr.NameRange,
+			})
+		}
+	}
+
+	if attr, exists := content.Attributes["provider"]; exists {
+		var providerDiags hcl.Diagnostics
+		r.ProviderConfigRef, providerDiags = decodeProviderConfigRef(attr.Expr, "provider")
+		diags = append(diags, providerDiags...)
+	}
+
+	if attr, exists := content.Attributes["depends_on"]; exists {
+		deps, depsDiags := decodeDependsOn(attr)
+		diags = append(diags, depsDiags...)
+		r.DependsOn = append(r.DependsOn, deps...)
+	}
+
+	var seenLifecycle *hcl.Block
+	var seenConnection *hcl.Block
+	var seenEscapeBlock *hcl.Block
+	for _, block := range content.Blocks {
+		switch block.Type {
+		case "lifecycle":
+			if seenLifecycle != nil {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Duplicate lifecycle block",
+					Detail:   fmt.Sprintf("This resource already has a lifecycle block at %s.", seenLifecycle.DefRange),
+					Subject:  &block.DefRange,
+				})
+				continue
+			}
+			seenLifecycle = block
+
+			lcContent, lcDiags := block.Body.Content(resourceLifecycleBlockSchema)
+			diags = append(diags, lcDiags...)
+
+			if attr, exists := lcContent.Attributes["create_before_destroy"]; exists {
+				valDiags := gohcl.DecodeExpression(attr.Expr, nil, &r.Managed.CreateBeforeDestroy)
+				diags = append(diags, valDiags...)
+				r.Managed.CreateBeforeDestroySet = true
+			}
+
+			if attr, exists := lcContent.Attributes["prevent_destroy"]; exists {
+				valDiags := gohcl.DecodeExpression(attr.Expr, nil, &r.Managed.PreventDestroy)
+				diags = append(diags, valDiags...)
+				r.Managed.PreventDestroySet = true
+			}
+
+			if attr, exists := lcContent.Attributes["replace_triggered_by"]; exists {
+				exprs, hclDiags := decodeReplaceTriggeredBy(attr.Expr)
+				diags = diags.Extend(hclDiags)
+
+				r.TriggersReplacement = append(r.TriggersReplacement, exprs...)
+			}
+
+			if attr, exists := lcContent.Attributes["ignore_changes"]; exists {
+
+				// ignore_changes can either be a list of relative traversals
+				// or it can be just the keyword "all" to ignore changes to this
+				// resource entirely.
+				//   ignore_changes = [ami, instance_type]
+				//   ignore_changes = all
+				// We also allow two legacy forms for compatibility with earlier
+				// versions:
+				//   ignore_changes = ["ami", "instance_type"]
+				//   ignore_changes = ["*"]
+
+				kw := hcl.ExprAsKeyword(attr.Expr)
+
+				switch {
+				case kw == "all":
+					r.Managed.IgnoreAllChanges = true
+				default:
+					exprs, listDiags := hcl.ExprList(attr.Expr)
+					diags = append(diags, listDiags...)
+
+					var ignoreAllRange hcl.Range
+
+					for _, expr := range exprs {
+
+						// our expr might be the literal string "*", which
+						// we accept as a deprecated way of saying "all".
+						if shimIsIgnoreChangesStar(expr) {
+							r.Managed.IgnoreAllChanges = true
+							ignoreAllRange = expr.Range()
+							diags = append(diags, &hcl.Diagnostic{
+								Severity: hcl.DiagError,
+								Summary:  "Invalid ignore_changes wildcard",
+								Detail:   "The [\"*\"] form of ignore_changes wildcard is was deprecated and is now invalid. Use \"ignore_changes = all\" to ignore changes to all attributes.",
+								Subject:  attr.Expr.Range().Ptr(),
+							})
+							continue
+						}
+
+						expr, shimDiags := shimTraversalInString(expr, false)
+						diags = append(diags, shimDiags...)
+
+						traversal, travDiags := hcl.RelTraversalForExpr(expr)
+						diags = append(diags, travDiags...)
+						if len(traversal) != 0 {
+							r.Managed.IgnoreChanges = append(r.Managed.IgnoreChanges, traversal)
+						}
+					}
+
+					if r.Managed.IgnoreAllChanges && len(r.Managed.IgnoreChanges) != 0 {
+						diags = append(diags, &hcl.Diagnostic{
+							Severity: hcl.DiagError,
+							Summary:  "Invalid ignore_changes ruleset",
+							Detail:   "Cannot mix wildcard string \"*\" with non-wildcard references.",
+							Subject:  &ignoreAllRange,
+							Context:  attr.Expr.Range().Ptr(),
+						})
+					}
+
+				}
+			}
+
+			for _, block := range lcContent.Blocks {
+				switch block.Type {
+				case "precondition", "postcondition":
+					cr, moreDiags := decodeCheckRuleBlock(block, override)
+					diags = append(diags, moreDiags...)
+
+					moreDiags = cr.validateSelfReferences(block.Type, r.Addr())
+					diags = append(diags, moreDiags...)
+
+					switch block.Type {
+					case "precondition":
+						r.Preconditions = append(r.Preconditions, cr)
+					case "postcondition":
+						r.Postconditions = append(r.Postconditions, cr)
+					}
+				default:
+					// The cases above should be exhaustive for all block types
+					// defined in the lifecycle schema, so this shouldn't happen.
+					panic(fmt.Sprintf("unexpected lifecycle sub-block type %q", block.Type))
+				}
+			}
+
+		case "connection":
+			if seenConnection != nil {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Duplicate connection block",
+					Detail:   fmt.Sprintf("This resource already has a connection block at %s.", seenConnection.DefRange),
+					Subject:  &block.DefRange,
+				})
+				continue
+			}
+			seenConnection = block
+
+			r.Managed.Connection = &Connection{
+				Config:    block.Body,
+				DeclRange: block.DefRange,
+			}
+
+		case "provisioner":
+			pv, pvDiags := decodeProvisionerBlock(block)
+			diags = append(diags, pvDiags...)
+			if pv != nil {
+				r.Managed.Provisioners = append(r.Managed.Provisioners, pv)
+			}
+
+		case "_":
+			if seenEscapeBlock != nil {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Duplicate escaping block",
+					Detail: fmt.Sprintf(
+						"The special block type \"_\" can be used to force particular arguments to be interpreted as resource-type-specific rather than as meta-arguments, but each resource block can have only one such block. The first escaping block was at %s.",
+						seenEscapeBlock.DefRange,
+					),
+					Subject: &block.DefRange,
+				})
+				continue
+			}
+			seenEscapeBlock = block
+
+			// When there's an escaping block its content merges with the
+			// existing config we extracted earlier, so later decoding
+			// will see a blend of both.
+			r.Config = hcl.MergeBodies([]hcl.Body{r.Config, block.Body})
+
+		default:
+			// Any other block types are ones we've reserved for future use,
+			// so they get a generic message.
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Reserved block type name in resource block",
+				Detail:   fmt.Sprintf("The block type name %q is reserved for use by Terraform in a future version.", block.Type),
+				Subject:  &block.TypeRange,
+			})
+		}
+	}
+
+	// Now we can validate the connection block references if there are any destroy provisioners.
+	// TODO: should we eliminate standalone connection blocks?
+	if r.Managed.Connection != nil {
+		for _, p := range r.Managed.Provisioners {
+			if p.When == ProvisionerWhenDestroy {
+				diags = append(diags, onlySelfRefs(r.Managed.Connection.Config)...)
+				break
+			}
+		}
+	}
+
+	return r, diags
+}
+
+func decodeDataBlock(block *hcl.Block, override, nested bool) (*Resource, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+	r := &Resource{
+		Mode:      addrs.DataResourceMode,
+		Type:      block.Labels[0],
+		Name:      block.Labels[1],
+		DeclRange: block.DefRange,
+		TypeRange: block.LabelRanges[0],
+	}
+
+	content, remain, moreDiags := block.Body.PartialContent(dataBlockSchema)
+	diags = append(diags, moreDiags...)
+	r.Config = remain
+
+	if !hclsyntax.ValidIdentifier(r.Type) {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid data source name",
+			Detail:   badIdentifierDetail,
+			Subject:  &block.LabelRanges[0],
+		})
+	}
+	if !hclsyntax.ValidIdentifier(r.Name) {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid data resource name",
+			Detail:   badIdentifierDetail,
+			Subject:  &block.LabelRanges[1],
+		})
+	}
+
+	if attr, exists := content.Attributes["count"]; exists && !nested {
+		r.Count = attr.Expr
+	} else if exists && nested {
+		// We don't allow count attributes in nested data blocks.
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Invalid "count" attribute`,
+			Detail:   `The "count" and "for_each" meta-arguments are not supported within nested data blocks.`,
+			Subject:  &attr.NameRange,
+		})
+	}
+
+	if attr, exists := content.Attributes["for_each"]; exists && !nested {
+		r.ForEach = attr.Expr
+		// Cannot have count and for_each on the same data block
+		if r.Count != nil {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  `Invalid combination of "count" and "for_each"`,
+				Detail:   `The "count" and "for_each" meta-arguments are mutually-exclusive, only one should be used to be explicit about the number of resources to be created.`,
+				Subject:  &attr.NameRange,
+			})
+		}
+	} else if exists && nested {
+		// We don't allow for_each attributes in nested data blocks.
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Invalid "for_each" attribute`,
+			Detail:   `The "count" and "for_each" meta-arguments are not supported within nested data blocks.`,
+			Subject:  &attr.NameRange,
+		})
+	}
+
+	if attr, exists := content.Attributes["provider"]; exists {
+		var providerDiags hcl.Diagnostics
+		r.ProviderConfigRef, providerDiags = decodeProviderConfigRef(attr.Expr, "provider")
+		diags = append(diags, providerDiags...)
+	}
+
+	if attr, exists := content.Attributes["depends_on"]; exists {
+		deps, depsDiags := decodeDependsOn(attr)
+		diags = append(diags, depsDiags...)
+		r.DependsOn = append(r.DependsOn, deps...)
+	}
+
+	var seenEscapeBlock *hcl.Block
+	var seenLifecycle *hcl.Block
+	for _, block := range content.Blocks {
+		switch block.Type {
+
+		case "_":
+			if seenEscapeBlock != nil {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Duplicate escaping block",
+					Detail: fmt.Sprintf(
+						"The special block type \"_\" can be used to force particular arguments to be interpreted as resource-type-specific rather than as meta-arguments, but each data block can have only one such block. The first escaping block was at %s.",
+						seenEscapeBlock.DefRange,
+					),
+					Subject: &block.DefRange,
+				})
+				continue
+			}
+			seenEscapeBlock = block
+
+			// When there's an escaping block its content merges with the
+			// existing config we extracted earlier, so later decoding
+			// will see a blend of both.
+			r.Config = hcl.MergeBodies([]hcl.Body{r.Config, block.Body})
+
+		case "lifecycle":
+			if nested {
+				// We don't allow lifecycle arguments in nested data blocks,
+				// the lifecycle is managed by the parent block.
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid lifecycle block",
+					Detail:   `Nested data blocks do not support "lifecycle" blocks as the lifecycle is managed by the containing block.`,
+					Subject:  block.DefRange.Ptr(),
+				})
+			}
+
+			if seenLifecycle != nil {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Duplicate lifecycle block",
+					Detail:   fmt.Sprintf("This resource already has a lifecycle block at %s.", seenLifecycle.DefRange),
+					Subject:  block.DefRange.Ptr(),
+				})
+				continue
+			}
+			seenLifecycle = block
+
+			lcContent, lcDiags := block.Body.Content(resourceLifecycleBlockSchema)
+			diags = append(diags, lcDiags...)
+
+			// All of the attributes defined for resource lifecycle are for
+			// managed resources only, so we can emit a common error message
+			// for any given attributes that HCL accepted.
+			for name, attr := range lcContent.Attributes {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid data resource lifecycle argument",
+					Detail:   fmt.Sprintf("The lifecycle argument %q is defined only for managed resources (\"resource\" blocks), and is not valid for data resources.", name),
+					Subject:  attr.NameRange.Ptr(),
+				})
+			}
+
+			for _, block := range lcContent.Blocks {
+				switch block.Type {
+				case "precondition", "postcondition":
+					cr, moreDiags := decodeCheckRuleBlock(block, override)
+					diags = append(diags, moreDiags...)
+
+					moreDiags = cr.validateSelfReferences(block.Type, r.Addr())
+					diags = append(diags, moreDiags...)
+
+					switch block.Type {
+					case "precondition":
+						r.Preconditions = append(r.Preconditions, cr)
+					case "postcondition":
+						r.Postconditions = append(r.Postconditions, cr)
+					}
+				default:
+					// The cases above should be exhaustive for all block types
+					// defined in the lifecycle schema, so this shouldn't happen.
+					panic(fmt.Sprintf("unexpected lifecycle sub-block type %q", block.Type))
+				}
+			}
+
+		default:
+			// Any other block types are ones we're reserving for future use,
+			// but don't have any defined meaning today.
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Reserved block type name in data block",
+				Detail:   fmt.Sprintf("The block type name %q is reserved for use by Terraform in a future version.", block.Type),
+				Subject:  block.TypeRange.Ptr(),
+			})
+		}
+	}
+
+	return r, diags
+}
+
+// decodeReplaceTriggeredBy decodes and does basic validation of the
+// replace_triggered_by expressions, ensuring they only contains references to
+// a single resource, and the only extra variables are count.index or each.key.
+func decodeReplaceTriggeredBy(expr hcl.Expression) ([]hcl.Expression, hcl.Diagnostics) {
+	// Since we are manually parsing the replace_triggered_by argument, we
+	// need to specially handle json configs, in which case the values will
+	// be json strings rather than hcl. To simplify parsing however we will
+	// decode the individual list elements, rather than the entire expression.
+	isJSON := hcljson.IsJSONExpression(expr)
+
+	exprs, diags := hcl.ExprList(expr)
+
+	for i, expr := range exprs {
+		if isJSON {
+			// We can abuse the hcl json api and rely on the fact that calling
+			// Value on a json expression with no EvalContext will return the
+			// raw string. We can then parse that as normal hcl syntax, and
+			// continue with the decoding.
+			v, ds := expr.Value(nil)
+			diags = diags.Extend(ds)
+			if diags.HasErrors() {
+				continue
+			}
+
+			expr, ds = hclsyntax.ParseExpression([]byte(v.AsString()), "", expr.Range().Start)
+			diags = diags.Extend(ds)
+			if diags.HasErrors() {
+				continue
+			}
+			// make sure to swap out the expression we're returning too
+			exprs[i] = expr
+		}
+
+		refs, refDiags := lang.ReferencesInExpr(expr)
+		for _, diag := range refDiags {
+			severity := hcl.DiagError
+			if diag.Severity() == tfdiags.Warning {
+				severity = hcl.DiagWarning
+			}
+
+			desc := diag.Description()
+
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: severity,
+				Summary:  desc.Summary,
+				Detail:   desc.Detail,
+				Subject:  expr.Range().Ptr(),
+			})
+		}
+
+		if refDiags.HasErrors() {
+			continue
+		}
+
+		resourceCount := 0
+		for _, ref := range refs {
+			switch sub := ref.Subject.(type) {
+			case addrs.Resource, addrs.ResourceInstance:
+				resourceCount++
+
+			case addrs.ForEachAttr:
+				if sub.Name != "key" {
+					diags = append(diags, &hcl.Diagnostic{
+						Severity: hcl.DiagError,
+						Summary:  "Invalid each reference in replace_triggered_by expression",
+						Detail:   "Only each.key may be used in replace_triggered_by.",
+						Subject:  expr.Range().Ptr(),
+					})
+				}
+			case addrs.CountAttr:
+				if sub.Name != "index" {
+					diags = append(diags, &hcl.Diagnostic{
+						Severity: hcl.DiagError,
+						Summary:  "Invalid count reference in replace_triggered_by expression",
+						Detail:   "Only count.index may be used in replace_triggered_by.",
+						Subject:  expr.Range().Ptr(),
+					})
+				}
+			default:
+				// everything else should be simple traversals
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid reference in replace_triggered_by expression",
+					Detail:   "Only resources, count.index, and each.key may be used in replace_triggered_by.",
+					Subject:  expr.Range().Ptr(),
+				})
+			}
+		}
+
+		switch {
+		case resourceCount == 0:
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid replace_triggered_by expression",
+				Detail:   "Missing resource reference in replace_triggered_by expression.",
+				Subject:  expr.Range().Ptr(),
+			})
+		case resourceCount > 1:
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid replace_triggered_by expression",
+				Detail:   "Multiple resource references in replace_triggered_by expression.",
+				Subject:  expr.Range().Ptr(),
+			})
+		}
+	}
+	return exprs, diags
+}
+
+type ProviderConfigRef struct {
+	Name       string
+	NameRange  hcl.Range
+	Alias      string
+	AliasRange *hcl.Range // nil if alias not set
+
+	// TODO: this may not be set in some cases, so it is not yet suitable for
+	// use outside of this package. We currently only use it for internal
+	// validation, but once we verify that this can be set in all cases, we can
+	// export this so providers don't need to be re-resolved.
+	// This same field is also added to the Provider struct.
+	providerType addrs.Provider
+}
+
+func decodeProviderConfigRef(expr hcl.Expression, argName string) (*ProviderConfigRef, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+
+	var shimDiags hcl.Diagnostics
+	expr, shimDiags = shimTraversalInString(expr, false)
+	diags = append(diags, shimDiags...)
+
+	traversal, travDiags := hcl.AbsTraversalForExpr(expr)
+
+	// AbsTraversalForExpr produces only generic errors, so we'll discard
+	// the errors given and produce our own with extra context. If we didn't
+	// get any errors then we might still have warnings, though.
+	if !travDiags.HasErrors() {
+		diags = append(diags, travDiags...)
+	}
+
+	if len(traversal) < 1 || len(traversal) > 2 {
+		// A provider reference was given as a string literal in the legacy
+		// configuration language and there are lots of examples out there
+		// showing that usage, so we'll sniff for that situation here and
+		// produce a specialized error message for it to help users find
+		// the new correct form.
+		if exprIsNativeQuotedString(expr) {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid provider configuration reference",
+				Detail:   "A provider configuration reference must not be given in quotes.",
+				Subject:  expr.Range().Ptr(),
+			})
+			return nil, diags
+		}
+
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider configuration reference",
+			Detail:   fmt.Sprintf("The %s argument requires a provider type name, optionally followed by a period and then a configuration alias.", argName),
+			Subject:  expr.Range().Ptr(),
+		})
+		return nil, diags
+	}
+
+	// verify that the provider local name is normalized
+	name := traversal.RootName()
+	nameDiags := checkProviderNameNormalized(name, traversal[0].SourceRange())
+	diags = append(diags, nameDiags...)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	ret := &ProviderConfigRef{
+		Name:      name,
+		NameRange: traversal[0].SourceRange(),
+	}
+
+	if len(traversal) > 1 {
+		aliasStep, ok := traversal[1].(hcl.TraverseAttr)
+		if !ok {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid provider configuration reference",
+				Detail:   "Provider name must either stand alone or be followed by a period and then a configuration alias.",
+				Subject:  traversal[1].SourceRange().Ptr(),
+			})
+			return ret, diags
+		}
+
+		ret.Alias = aliasStep.Name
+		ret.AliasRange = aliasStep.SourceRange().Ptr()
+	}
+
+	return ret, diags
+}
+
+// Addr returns the provider config address corresponding to the receiving
+// config reference.
+//
+// This is a trivial conversion, essentially just discarding the source
+// location information and keeping just the addressing information.
+func (r *ProviderConfigRef) Addr() addrs.LocalProviderConfig {
+	return addrs.LocalProviderConfig{
+		LocalName: r.Name,
+		Alias:     r.Alias,
+	}
+}
+
+func (r *ProviderConfigRef) String() string {
+	if r == nil {
+		return "<nil>"
+	}
+	if r.Alias != "" {
+		return fmt.Sprintf("%s.%s", r.Name, r.Alias)
+	}
+	return r.Name
+}
+
+var commonResourceAttributes = []hcl.AttributeSchema{
+	{
+		Name: "count",
+	},
+	{
+		Name: "for_each",
+	},
+	{
+		Name: "provider",
+	},
+	{
+		Name: "depends_on",
+	},
+}
+
+// ResourceBlockSchema is the schema for a resource or data resource type within
+// Terraform.
+//
+// This schema is public as it is required elsewhere in order to validate and
+// use generated config.
+var ResourceBlockSchema = &hcl.BodySchema{
+	Attributes: commonResourceAttributes,
+	Blocks: []hcl.BlockHeaderSchema{
+		{Type: "locals"}, // reserved for future use
+		{Type: "lifecycle"},
+		{Type: "connection"},
+		{Type: "provisioner", LabelNames: []string{"type"}},
+		{Type: "_"}, // meta-argument escaping block
+	},
+}
+
+var dataBlockSchema = &hcl.BodySchema{
+	Attributes: commonResourceAttributes,
+	Blocks: []hcl.BlockHeaderSchema{
+		{Type: "lifecycle"},
+		{Type: "locals"}, // reserved for future use
+		{Type: "_"},      // meta-argument escaping block
+	},
+}
+
+var resourceLifecycleBlockSchema = &hcl.BodySchema{
+	// We tell HCL that these elements are all valid for both "resource"
+	// and "data" lifecycle blocks, but the rules are actually more restrictive
+	// than that. We deal with that after decoding so that we can return
+	// more specific error messages than HCL would typically return itself.
+	Attributes: []hcl.AttributeSchema{
+		{
+			Name: "create_before_destroy",
+		},
+		{
+			Name: "prevent_destroy",
+		},
+		{
+			Name: "ignore_changes",
+		},
+		{
+			Name: "replace_triggered_by",
+		},
+	},
+	Blocks: []hcl.BlockHeaderSchema{
+		{Type: "precondition"},
+		{Type: "postcondition"},
+	},
+}
diff --git a/v1.5.7/internal/configs/synth_body.go b/v1.5.7/internal/configs/synth_body.go
new file mode 100644
index 0000000..da491bf
--- /dev/null
+++ b/v1.5.7/internal/configs/synth_body.go
@@ -0,0 +1,121 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// SynthBody produces a synthetic hcl.Body that behaves as if it had attributes
+// corresponding to the elements given in the values map.
+//
+// This is useful in situations where, for example, values provided on the
+// command line can override values given in configuration, using MergeBodies.
+//
+// The given filename is used in case any diagnostics are returned. Since
+// the created body is synthetic, it is likely that this will not be a "real"
+// filename. For example, if from a command line argument it could be
+// a representation of that argument's name, such as "-var=...".
+func SynthBody(filename string, values map[string]cty.Value) hcl.Body {
+	return synthBody{
+		Filename: filename,
+		Values:   values,
+	}
+}
+
+type synthBody struct {
+	Filename string
+	Values   map[string]cty.Value
+}
+
+func (b synthBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
+	content, remain, diags := b.PartialContent(schema)
+	remainS := remain.(synthBody)
+	for name := range remainS.Values {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Unsupported attribute",
+			Detail:   fmt.Sprintf("An attribute named %q is not expected here.", name),
+			Subject:  b.synthRange().Ptr(),
+		})
+	}
+	return content, diags
+}
+
+func (b synthBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+	content := &hcl.BodyContent{
+		Attributes:       make(hcl.Attributes),
+		MissingItemRange: b.synthRange(),
+	}
+
+	remainValues := make(map[string]cty.Value)
+	for attrName, val := range b.Values {
+		remainValues[attrName] = val
+	}
+
+	for _, attrS := range schema.Attributes {
+		delete(remainValues, attrS.Name)
+		val, defined := b.Values[attrS.Name]
+		if !defined {
+			if attrS.Required {
+				diags = append(diags, &hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Missing required attribute",
+					Detail:   fmt.Sprintf("The attribute %q is required, but no definition was found.", attrS.Name),
+					Subject:  b.synthRange().Ptr(),
+				})
+			}
+			continue
+		}
+		content.Attributes[attrS.Name] = b.synthAttribute(attrS.Name, val)
+	}
+
+	// We just ignore blocks altogether, because this body type never has
+	// nested blocks.
+
+	remain := synthBody{
+		Filename: b.Filename,
+		Values:   remainValues,
+	}
+
+	return content, remain, diags
+}
+
+func (b synthBody) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
+	ret := make(hcl.Attributes)
+	for name, val := range b.Values {
+		ret[name] = b.synthAttribute(name, val)
+	}
+	return ret, nil
+}
+
+func (b synthBody) MissingItemRange() hcl.Range {
+	return b.synthRange()
+}
+
+func (b synthBody) synthAttribute(name string, val cty.Value) *hcl.Attribute {
+	rng := b.synthRange()
+	return &hcl.Attribute{
+		Name: name,
+		Expr: &hclsyntax.LiteralValueExpr{
+			Val:      val,
+			SrcRange: rng,
+		},
+		NameRange: rng,
+		Range:     rng,
+	}
+}
+
+func (b synthBody) synthRange() hcl.Range {
+	return hcl.Range{
+		Filename: b.Filename,
+		Start:    hcl.Pos{Line: 1, Column: 1},
+		End:      hcl.Pos{Line: 1, Column: 1},
+	}
+}
diff --git a/v1.5.7/internal/configs/synth_body_test.go b/v1.5.7/internal/configs/synth_body_test.go
new file mode 100644
index 0000000..dd0db58
--- /dev/null
+++ b/v1.5.7/internal/configs/synth_body_test.go
@@ -0,0 +1,68 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestSynthBodyContent(t *testing.T) {
+	tests := map[string]struct {
+		Values    map[string]cty.Value
+		Schema    *hcl.BodySchema
+		DiagCount int
+	}{
+		"empty": {
+			Values:    map[string]cty.Value{},
+			Schema:    &hcl.BodySchema{},
+			DiagCount: 0,
+		},
+		"missing required attribute": {
+			Values: map[string]cty.Value{},
+			Schema: &hcl.BodySchema{
+				Attributes: []hcl.AttributeSchema{
+					{
+						Name:     "nonexist",
+						Required: true,
+					},
+				},
+			},
+			DiagCount: 1, // missing required attribute
+		},
+		"missing optional attribute": {
+			Values: map[string]cty.Value{},
+			Schema: &hcl.BodySchema{
+				Attributes: []hcl.AttributeSchema{
+					{
+						Name: "nonexist",
+					},
+				},
+			},
+			DiagCount: 0,
+		},
+		"extraneous attribute": {
+			Values: map[string]cty.Value{
+				"foo": cty.StringVal("unwanted"),
+			},
+			Schema:    &hcl.BodySchema{},
+			DiagCount: 1, // unsupported attribute
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			body := SynthBody("synth", test.Values)
+			_, diags := body.Content(test.Schema)
+			if got, want := len(diags), test.DiagCount; got != want {
+				t.Errorf("wrong number of diagnostics %d; want %d", got, want)
+				for _, diag := range diags {
+					t.Logf("- %s", diag)
+				}
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/configs/testdata/config-build/child_a/child_a.tf b/v1.5.7/internal/configs/testdata/config-build/child_a/child_a.tf
new file mode 100644
index 0000000..d3eff0b
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-build/child_a/child_a.tf
@@ -0,0 +1,7 @@
+
+module "child_c" {
+  # In the unit test where this fixture is used, we treat the source strings
+  # as relative paths from the fixture directory rather than as source
+  # addresses as we would in a real module walker.
+  source = "./child_c"
+}
diff --git a/v1.5.7/internal/configs/testdata/config-build/child_b/child_b.tf b/v1.5.7/internal/configs/testdata/config-build/child_b/child_b.tf
new file mode 100644
index 0000000..d3eff0b
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-build/child_b/child_b.tf
@@ -0,0 +1,7 @@
+
+module "child_c" {
+  # In the unit test where this fixture is used, we treat the source strings
+  # as relative paths from the fixture directory rather than as source
+  # addresses as we would in a real module walker.
+  source = "./child_c"
+}
diff --git a/v1.5.7/internal/configs/testdata/config-build/child_c/child_c.tf b/v1.5.7/internal/configs/testdata/config-build/child_c/child_c.tf
new file mode 100644
index 0000000..1602020
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-build/child_c/child_c.tf
@@ -0,0 +1,3 @@
+output "hello" {
+  value = "hello"
+}
diff --git a/v1.5.7/internal/configs/testdata/config-build/root.tf b/v1.5.7/internal/configs/testdata/config-build/root.tf
new file mode 100644
index 0000000..5e23e40
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-build/root.tf
@@ -0,0 +1,9 @@
+
+module "child_a" {
+  source = "./child_a"
+}
+
+module "child_b" {
+  source = "./child_b"
+}
+
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/empty-configs/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/empty-configs/main.tf
new file mode 100644
index 0000000..c0edba2
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/empty-configs/main.tf
@@ -0,0 +1,20 @@
+terraform {
+  required_providers {
+    foo = {
+      source = "hashicorp/foo"
+    }
+    baz = {
+      source = "hashicorp/baz"
+    }
+  }
+}
+
+module "mod" {
+  source = "./mod"
+  providers = {
+    foo = foo
+    foo.bar = foo
+    baz = baz
+    baz.bing = baz
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/empty-configs/mod/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/empty-configs/mod/main.tf
new file mode 100644
index 0000000..50995ca
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/empty-configs/mod/main.tf
@@ -0,0 +1,22 @@
+terraform {
+  required_providers {
+    foo = {
+      source = "hashicorp/foo"
+      configuration_aliases = [ foo.bar ]
+    }
+  }
+}
+
+provider "foo" {
+}
+
+provider "foo" {
+  alias = "bar"
+}
+
+provider "baz" {
+}
+
+provider "baz" {
+  alias = "bing"
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/empty-configs/warnings b/v1.5.7/internal/configs/testdata/config-diagnostics/empty-configs/warnings
new file mode 100644
index 0000000..d2fe48d
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/empty-configs/warnings
@@ -0,0 +1,4 @@
+empty-configs/mod/main.tf:10,1-15: Redundant empty provider block; Earlier versions of Terraform used empty provider blocks ("proxy provider configurations") for child modules to declare their need to be passed a provider configuration by their callers. That approach was ambiguous and is now deprecated.
+If you control this module, you can migrate to the new declaration syntax by removing all of the empty provider "foo" blocks and then adding or updating an entry like the following to the required_providers block of module.mod:
+empty-configs/mod/main.tf:17,1-15: Redundant empty provider block; Earlier versions of Terraform used empty provider blocks ("proxy provider configurations") for child modules to declare their need to be passed a provider configuration by their callers. That approach was ambiguous and is now deprecated.
+If you control this module, you can migrate to the new declaration syntax by removing all of the empty provider "baz" blocks and then adding or updating an entry like the following to the required_providers block of module.mod:
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/import-in-child-module/child/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/import-in-child-module/child/main.tf
new file mode 100644
index 0000000..bb8cb13
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/import-in-child-module/child/main.tf
@@ -0,0 +1,6 @@
+resource "aws_instance" "web" {}
+
+import {
+  to = aws_instance.web
+  id = "test"
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/import-in-child-module/errors b/v1.5.7/internal/configs/testdata/config-diagnostics/import-in-child-module/errors
new file mode 100644
index 0000000..b0a5ac4
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/import-in-child-module/errors
@@ -0,0 +1 @@
+import-in-child-module/child/main.tf:3,1-7: Invalid import configuration; An import block was detected in "module.child". Import blocks are only allowed in the root module.
\ No newline at end of file
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/import-in-child-module/root.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/import-in-child-module/root.tf
new file mode 100644
index 0000000..3133e57
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/import-in-child-module/root.tf
@@ -0,0 +1,10 @@
+resource "aws_instance" "web" {}
+
+import {
+  to = aws_instance.web
+  id = "test"
+}
+
+module "child" {
+  source = "./child"
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/incorrect-type/errors b/v1.5.7/internal/configs/testdata/config-diagnostics/incorrect-type/errors
new file mode 100644
index 0000000..97a31fe
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/incorrect-type/errors
@@ -0,0 +1 @@
+incorrect-type/main.tf:15,11-14: Provider type mismatch; The local name "foo" in the root module represents provider "hashicorp/foo", but "foo" in module.mod represents "example.com/vendor/foo".
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/incorrect-type/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/incorrect-type/main.tf
new file mode 100644
index 0000000..074cc84
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/incorrect-type/main.tf
@@ -0,0 +1,18 @@
+terraform {
+  required_providers {
+    foo = {
+      source = "hashicorp/foo"
+    }
+    baz = {
+      source = "hashicorp/baz"
+    }
+  }
+}
+
+module "mod" {
+  source = "./mod"
+  providers = {
+    foo = foo
+    baz = baz
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/incorrect-type/mod/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/incorrect-type/mod/main.tf
new file mode 100644
index 0000000..14c3239
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/incorrect-type/mod/main.tf
@@ -0,0 +1,14 @@
+terraform {
+  required_providers {
+    foo = {
+      source = "example.com/vendor/foo"
+    }
+  }
+}
+
+resource "foo_resource" "a" {
+}
+
+// implied default provider baz
+resource "baz_resource" "a" {
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/incorrect-type/warnings b/v1.5.7/internal/configs/testdata/config-diagnostics/incorrect-type/warnings
new file mode 100644
index 0000000..1e35e88
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/incorrect-type/warnings
@@ -0,0 +1 @@
+incorrect-type/main.tf:16,5-8: Reference to undefined provider; There is no explicit declaration for local provider name "baz" in module.mod, so Terraform is assuming you mean to pass a configuration for "hashicorp/baz".
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/invalid-provider/errors b/v1.5.7/internal/configs/testdata/config-diagnostics/invalid-provider/errors
new file mode 100644
index 0000000..359d476
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/invalid-provider/errors
@@ -0,0 +1 @@
+main.tf:1,1-20: Invalid provider local name; crash_es is an invalid provider local name
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/invalid-provider/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/invalid-provider/main.tf
new file mode 100644
index 0000000..ba84684
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/invalid-provider/main.tf
@@ -0,0 +1,3 @@
+module "mod" {
+  source = "./mod"
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/invalid-provider/mod/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/invalid-provider/mod/main.tf
new file mode 100644
index 0000000..f50ced1
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/invalid-provider/mod/main.tf
@@ -0,0 +1,2 @@
+provider "crash_es" {
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/nested-provider/child/child2/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/nested-provider/child/child2/main.tf
new file mode 100644
index 0000000..f2695a6
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/nested-provider/child/child2/main.tf
@@ -0,0 +1,7 @@
+provider "aws" {
+  value = "foo"
+}
+
+output "my_output" {
+  value = "my output"
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/nested-provider/child/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/nested-provider/child/main.tf
new file mode 100644
index 0000000..9a725a5
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/nested-provider/child/main.tf
@@ -0,0 +1,4 @@
+module "child2" {
+  // the test fixture treats these sources as relative to the root
+  source = "./child/child2"
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/nested-provider/errors b/v1.5.7/internal/configs/testdata/config-diagnostics/nested-provider/errors
new file mode 100644
index 0000000..df929d8
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/nested-provider/errors
@@ -0,0 +1 @@
+nested-provider/root.tf:2,11-12: Module is incompatible with count, for_each, and depends_on; The module at module.child.module.child2 is a legacy module which contains its own local provider configurations, and so calls to it may not use the count, for_each, or depends_on arguments.
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/nested-provider/root.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/nested-provider/root.tf
new file mode 100644
index 0000000..71b90f6
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/nested-provider/root.tf
@@ -0,0 +1,4 @@
+module "child" {
+  count = 1
+  source = "./child"
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/override-provider/errors b/v1.5.7/internal/configs/testdata/config-diagnostics/override-provider/errors
new file mode 100644
index 0000000..6529dd9
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/override-provider/errors
@@ -0,0 +1 @@
+override-provider/main.tf:17,5-8: Cannot override provider configuration; The configuration of module.mod has its own local configuration for bar, and so it cannot accept an overridden configuration provided by the root module.
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/override-provider/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/override-provider/main.tf
new file mode 100644
index 0000000..30feec1
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/override-provider/main.tf
@@ -0,0 +1,19 @@
+terraform {
+  required_providers {
+    bar = {
+      version = "~>1.0.0"
+    }
+  }
+}
+
+provider "bar" {
+  value = "not ok"
+}
+
+// this module configures its own provider, which cannot be overridden
+module "mod" {
+  source = "./mod"
+  providers = {
+    bar = bar
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/override-provider/mod/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/override-provider/mod/main.tf
new file mode 100644
index 0000000..c0b6169
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/override-provider/mod/main.tf
@@ -0,0 +1,12 @@
+terraform {
+  required_providers {
+    bar = {
+      version = "~>1.0.0"
+    }
+  }
+}
+
+// this configuration cannot be overridden from an outside module
+provider "bar" {
+  value = "ok"
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/pass-inherited-provider/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/pass-inherited-provider/main.tf
new file mode 100644
index 0000000..aa4b7e9
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/pass-inherited-provider/main.tf
@@ -0,0 +1,23 @@
+provider "test" {
+  value = "ok"
+}
+
+module "mod" {
+  source = "./mod"
+}
+
+# FIXME: This test is for an awkward interaction that we've preserved for
+# compatibility with what was arguably a bug in earlier versions: if a
+# child module tries to use an inherited provider configuration explicitly by
+# name then Terraform would historically use the wrong provider configuration.
+#
+# Since we weren't able to address that bug without breaking backward
+# compatibility, instead we emit a warning to prompt the author to be explicit,
+# passing in the configuration they intend to use.
+#
+# This case is particularly awkward because a change in the child module
+# (previously referring to a provider only implicitly, but now naming it
+# explicitly) can cause a required change in _this_ module (the caller),
+# even though the author of the child module would've seen no explicit warning
+# that they were making a breaking change. Hopefully we can improve on this
+# in a future language edition.
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/pass-inherited-provider/mod/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/pass-inherited-provider/mod/main.tf
new file mode 100644
index 0000000..e0d142d
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/pass-inherited-provider/mod/main.tf
@@ -0,0 +1,17 @@
+terraform {
+  required_providers {
+    test = {
+      source = "hashicorp/test"
+    }
+  }
+}
+
+module "mod2" {
+  source = "./mod2"
+
+  // the test provider is named here, but a config must be supplied from the
+  // parent module.
+  providers = {
+    test.foo = test
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/pass-inherited-provider/mod2/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/pass-inherited-provider/mod2/main.tf
new file mode 100644
index 0000000..0b73616
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/pass-inherited-provider/mod2/main.tf
@@ -0,0 +1,12 @@
+terraform {
+  required_providers {
+    test = {
+      source = "hashicorp/test"
+      configuration_aliases = [test.foo]
+    }
+  }
+}
+
+resource "test_resource" "foo" {
+  provider = test.foo
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/pass-inherited-provider/warnings b/v1.5.7/internal/configs/testdata/config-diagnostics/pass-inherited-provider/warnings
new file mode 100644
index 0000000..692e14e
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/pass-inherited-provider/warnings
@@ -0,0 +1 @@
+pass-inherited-provider/main.tf:5,1-13: Missing required provider configuration; The configuration for module.mod expects to inherit a configuration for provider hashicorp/test with local name "test", but the root module doesn't pass a configuration under that name.
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/required-alias/errors b/v1.5.7/internal/configs/testdata/config-diagnostics/required-alias/errors
new file mode 100644
index 0000000..b010244
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/required-alias/errors
@@ -0,0 +1 @@
+required-alias/main.tf:1,1-13: Missing required provider configuration; The child module requires an additional configuration for provider hashicorp/foo, with the local name "foo.bar".
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/required-alias/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/required-alias/main.tf
new file mode 100644
index 0000000..c2cfe60
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/required-alias/main.tf
@@ -0,0 +1,4 @@
+module "mod" {
+  source = "./mod"
+  // missing providers with foo.bar provider config
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/required-alias/mod/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/required-alias/mod/main.tf
new file mode 100644
index 0000000..0f2a521
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/required-alias/mod/main.tf
@@ -0,0 +1,13 @@
+terraform {
+  required_providers {
+    foo = {
+      source = "hashicorp/foo"
+      version = "1.0.0"
+      configuration_aliases = [ foo.bar ]
+    }
+  }
+}
+
+resource "foo_resource" "a" {
+  provider = foo.bar
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/unexpected-provider/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/unexpected-provider/main.tf
new file mode 100644
index 0000000..cd859a7
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/unexpected-provider/main.tf
@@ -0,0 +1,15 @@
+terraform {
+  required_providers {
+    foo = {
+      source = "hashicorp/foo"
+      version = "1.0.0"
+    }
+  }
+}
+
+module "mod" {
+  source = "./mod"
+  providers = {
+    foo = foo
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/unexpected-provider/mod/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/unexpected-provider/mod/main.tf
new file mode 100644
index 0000000..f69bfa8
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/unexpected-provider/mod/main.tf
@@ -0,0 +1,2 @@
+resource "foo_resource" "a" {
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/unexpected-provider/warnings b/v1.5.7/internal/configs/testdata/config-diagnostics/unexpected-provider/warnings
new file mode 100644
index 0000000..82be3b7
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/unexpected-provider/warnings
@@ -0,0 +1 @@
+unexpected-provider/main.tf:13,5-8: Reference to undefined provider; There is no explicit declaration for local provider name "foo" in module.mod, so Terraform is assuming you mean to pass a configuration for "hashicorp/foo".
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/unknown-root-provider/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/unknown-root-provider/main.tf
new file mode 100644
index 0000000..cf60f91
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/unknown-root-provider/main.tf
@@ -0,0 +1,7 @@
+module "mod" {
+  source = "./mod"
+  providers = {
+    // bar may be required by the module, but the name is not defined here
+    bar = bar
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/unknown-root-provider/mod/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/unknown-root-provider/mod/main.tf
new file mode 100644
index 0000000..ea8d032
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/unknown-root-provider/mod/main.tf
@@ -0,0 +1,10 @@
+terraform {
+  required_providers {
+    bar = {
+      version = "~>1.0.0"
+    }
+  }
+}
+
+resource "bar_resource" "x" {
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/unknown-root-provider/warnings b/v1.5.7/internal/configs/testdata/config-diagnostics/unknown-root-provider/warnings
new file mode 100644
index 0000000..4d85a51
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/unknown-root-provider/warnings
@@ -0,0 +1 @@
+unknown-root-provider/main.tf:5,11-14: Reference to undefined provider; There is no explicit declaration for local provider name "bar" in the root module, so Terraform is assuming you mean to pass a configuration for provider "hashicorp/bar".
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/with-depends-on/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/with-depends-on/main.tf
new file mode 100644
index 0000000..49c2dcd
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/with-depends-on/main.tf
@@ -0,0 +1,14 @@
+terraform {
+  required_providers {
+    foo = {
+      source = "hashicorp/foo"
+    }
+  }
+}
+
+module "mod2" {
+  source = "./mod1"
+  providers = {
+    foo = foo
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/with-depends-on/mod1/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/with-depends-on/mod1/main.tf
new file mode 100644
index 0000000..c318484
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/with-depends-on/mod1/main.tf
@@ -0,0 +1,19 @@
+terraform {
+  required_providers {
+    foo = {
+      source = "hashicorp/foo"
+    }
+  }
+}
+
+resource "foo_resource" "a" {
+}
+
+module "mod2" {
+  depends_on = [foo_resource.a]
+  // test fixture source is from root
+  source = "./mod1/mod2"
+  providers = {
+    foo = foo
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/with-depends-on/mod1/mod2/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/with-depends-on/mod1/mod2/main.tf
new file mode 100644
index 0000000..eaa3550
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/with-depends-on/mod1/mod2/main.tf
@@ -0,0 +1,15 @@
+terraform {
+  required_providers {
+    foo = {
+      source = "hashicorp/foo"
+    }
+  }
+}
+
+module "mod3" {
+  // test fixture source is from root
+  source = "./mod1/mod2/mod3"
+  providers = {
+    foo.bar = foo
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/config-diagnostics/with-depends-on/mod1/mod2/mod3/main.tf b/v1.5.7/internal/configs/testdata/config-diagnostics/with-depends-on/mod1/mod2/mod3/main.tf
new file mode 100644
index 0000000..b182712
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/config-diagnostics/with-depends-on/mod1/mod2/mod3/main.tf
@@ -0,0 +1,12 @@
+terraform {
+  required_providers {
+    foo = {
+      source = "hashicorp/foo"
+      configuration_aliases = [ foo.bar ]
+    }
+  }
+}
+
+resource "foo_resource" "a" {
+  providers = foo.bar
+}
diff --git a/v1.5.7/internal/configs/testdata/dir-empty/.gitkeep b/v1.5.7/internal/configs/testdata/dir-empty/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/dir-empty/.gitkeep
diff --git a/v1.5.7/internal/configs/testdata/duplicate-local-name/main.tf b/v1.5.7/internal/configs/testdata/duplicate-local-name/main.tf
new file mode 100644
index 0000000..9bac545
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/duplicate-local-name/main.tf
@@ -0,0 +1,23 @@
+terraform {
+  required_providers {
+    test = {
+      source = "hashicorp/test"
+    }
+    dupe = {
+      source = "hashicorp/test"
+    }
+    other = {
+      source = "hashicorp/default"
+    }
+
+    wrong-name = {
+      source = "hashicorp/foo"
+    }
+  }
+}
+
+provider "default" {
+}
+
+resource "foo_resource" {
+}
diff --git a/v1.5.7/internal/configs/testdata/error-files/destroy-provisioners.tf b/v1.5.7/internal/configs/testdata/error-files/destroy-provisioners.tf
new file mode 100644
index 0000000..4831b53
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/error-files/destroy-provisioners.tf
@@ -0,0 +1,44 @@
+locals {
+  user = "name"
+}
+
+resource "null_resource" "a" {
+  connection {
+    host = self.hostname
+    user = local.user # ERROR: Invalid reference from destroy provisioner
+  }
+
+  provisioner "remote-exec" {
+    when = destroy
+    index = count.index
+    key = each.key
+
+    // path and terraform values are static, and do not create any
+    // dependencies.
+    dir = path.module
+    workspace = terraform.workspace
+  }
+}
+
+resource "null_resource" "b" {
+  connection {
+    host = self.hostname
+    # this is OK since there is no destroy provisioner
+    user = local.user
+  }
+
+  provisioner "remote-exec" {
+  }
+}
+
+resource "null_resource" "b" {
+  provisioner "remote-exec" {
+    when = destroy
+    connection {
+      host = self.hostname
+      user = local.user # ERROR: Invalid reference from destroy provisioner
+    }
+
+    command = "echo ${local.name}" # ERROR: Invalid reference from destroy provisioner
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/error-files/ignore_changes.tf b/v1.5.7/internal/configs/testdata/error-files/ignore_changes.tf
new file mode 100644
index 0000000..061209c
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/error-files/ignore_changes.tf
@@ -0,0 +1,5 @@
+resource "null_resource" "all" {
+  lifecycle {
+    ignore_changes = ["*"] # ERROR: Invalid ignore_changes wildcard
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/error-files/invalid_language_edition.tf b/v1.5.7/internal/configs/testdata/error-files/invalid_language_edition.tf
new file mode 100644
index 0000000..255aefe
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/error-files/invalid_language_edition.tf
@@ -0,0 +1,4 @@
+terraform {
+  # The language argument expects a bare keyword, not a string.
+  language = "TF2021" # ERROR: Invalid language edition
+}
diff --git a/v1.5.7/internal/configs/testdata/error-files/module-invalid-registry-source-with-module.tf b/v1.5.7/internal/configs/testdata/error-files/module-invalid-registry-source-with-module.tf
new file mode 100644
index 0000000..0029be8
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/error-files/module-invalid-registry-source-with-module.tf
@@ -0,0 +1,5 @@
+
+module "test" {
+  source  = "---.com/HashiCorp/Consul/aws" # ERROR: Invalid registry module source address
+  version = "1.0.0" # Makes Terraform assume "source" is a module address
+}
diff --git a/v1.5.7/internal/configs/testdata/error-files/module-local-source-with-version.tf b/v1.5.7/internal/configs/testdata/error-files/module-local-source-with-version.tf
new file mode 100644
index 0000000..f570d65
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/error-files/module-local-source-with-version.tf
@@ -0,0 +1,5 @@
+
+module "test" {
+  source  = "../boop" # ERROR: Invalid registry module source address
+  version = "1.0.0" # Makes Terraform assume "source" is a module address
+}
diff --git a/v1.5.7/internal/configs/testdata/error-files/precondition-postcondition-constant.tf b/v1.5.7/internal/configs/testdata/error-files/precondition-postcondition-constant.tf
new file mode 100644
index 0000000..30f4431
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/error-files/precondition-postcondition-constant.tf
@@ -0,0 +1,34 @@
+resource "test" "test" {
+  lifecycle {
+    precondition {
+      condition     = true # ERROR: Invalid precondition expression
+      error_message = "Must be true."
+    }
+    postcondition {
+      condition     = true # ERROR: Invalid postcondition expression
+      error_message = "Must be true."
+    }
+  }
+}
+
+data "test" "test" {
+  lifecycle {
+    precondition {
+      condition     = true # ERROR: Invalid precondition expression
+      error_message = "Must be true."
+    }
+    postcondition {
+      condition     = true # ERROR: Invalid postcondition expression
+      error_message = "Must be true."
+    }
+  }
+}
+
+output "test" {
+  value = ""
+ 
+  precondition {
+    condition     = true # ERROR: Invalid precondition expression
+    error_message = "Must be true."
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/error-files/precondition-postcondition-selfref.tf b/v1.5.7/internal/configs/testdata/error-files/precondition-postcondition-selfref.tf
new file mode 100644
index 0000000..5f295c1
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/error-files/precondition-postcondition-selfref.tf
@@ -0,0 +1,55 @@
+resource "test" "test" {
+  lifecycle {
+    precondition {
+      condition     = test.test.foo # ERROR: Invalid reference in precondition
+      error_message = "Cannot refer to self."
+    }
+    postcondition {
+      condition     = test.test.foo # ERROR: Invalid reference in postcondition
+      error_message = "Cannot refer to self."
+    }
+  }
+}
+
+data "test" "test" {
+  lifecycle {
+    precondition {
+      condition     = data.test.test.foo # ERROR: Invalid reference in precondition
+      error_message = "Cannot refer to self."
+    }
+    postcondition {
+      condition     = data.test.test.foo # ERROR: Invalid reference in postcondition
+      error_message = "Cannot refer to self."
+    }
+  }
+}
+
+resource "test" "test_counted" {
+  count = 1
+
+  lifecycle {
+    precondition {
+      condition     = test.test_counted[0].foo # ERROR: Invalid reference in precondition
+      error_message = "Cannot refer to self."
+    }
+    postcondition {
+      condition     = test.test_counted[0].foo # ERROR: Invalid reference in postcondition
+      error_message = "Cannot refer to self."
+    }
+  }
+}
+
+data "test" "test_counted" {
+  count = 1
+
+  lifecycle {
+    precondition {
+      condition     = data.test.test_counted[0].foo # ERROR: Invalid reference in precondition
+      error_message = "Cannot refer to self."
+    }
+    postcondition {
+      condition     = data.test.test_counted[0].foo # ERROR: Invalid reference in postcondition
+      error_message = "Cannot refer to self."
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/error-files/provider-source-prefix.tf b/v1.5.7/internal/configs/testdata/error-files/provider-source-prefix.tf
new file mode 100644
index 0000000..9681169
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/error-files/provider-source-prefix.tf
@@ -0,0 +1,10 @@
+terraform {
+  required_providers {
+    usererror = {
+      source = "foo/terraform-provider-foo" # ERROR: Invalid provider type
+    }
+    badname = {
+      source = "foo/terraform-foo" # ERROR: Invalid provider type
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/error-files/required-providers-toplevel.tf b/v1.5.7/internal/configs/testdata/error-files/required-providers-toplevel.tf
new file mode 100644
index 0000000..de1bf12
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/error-files/required-providers-toplevel.tf
@@ -0,0 +1,9 @@
+# A top-level required_providers block is not valid, but we have a specialized
+# error for it to hint the user to move it into a terraform block.
+required_providers { # ERROR: Invalid required_providers block
+}
+
+# This one is valid, and what the user should rewrite the above to be like.
+terraform {
+  required_providers {}
+}
diff --git a/v1.5.7/internal/configs/testdata/error-files/unsupported_language_edition.tf b/v1.5.7/internal/configs/testdata/error-files/unsupported_language_edition.tf
new file mode 100644
index 0000000..0ee616f
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/error-files/unsupported_language_edition.tf
@@ -0,0 +1,6 @@
+terraform {
+  # If a future change in this repository happens to make TF2038 a valid
+  # edition then this will start failing; in that case, change this file to
+  # select a different edition that isn't supported.
+  language = TF2038 # ERROR: Unsupported language edition
+}
diff --git a/v1.5.7/internal/configs/testdata/error-files/variable_type_quoted.tf b/v1.5.7/internal/configs/testdata/error-files/variable_type_quoted.tf
new file mode 100644
index 0000000..2292ce1
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/error-files/variable_type_quoted.tf
@@ -0,0 +1,11 @@
+variable "bad_string" {
+  type = "string" # ERROR: Invalid quoted type constraints
+}
+
+variable "bad_map" {
+  type = "map" # ERROR: Invalid quoted type constraints
+}
+
+variable "bad_list" {
+  type = "list" # ERROR: Invalid quoted type constraints
+}
diff --git a/v1.5.7/internal/configs/testdata/error-files/vendor_provisioners.tf b/v1.5.7/internal/configs/testdata/error-files/vendor_provisioners.tf
new file mode 100644
index 0000000..4d2ec78
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/error-files/vendor_provisioners.tf
@@ -0,0 +1,3 @@
+resource "null_resource" "test" {
+  provisioner "habitat" {} # ERROR: The "habitat" provisioner has been removed
+}
diff --git a/v1.5.7/internal/configs/testdata/escaping-blocks/data/data-escaping-block.tf b/v1.5.7/internal/configs/testdata/escaping-blocks/data/data-escaping-block.tf
new file mode 100644
index 0000000..f7efa72
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/escaping-blocks/data/data-escaping-block.tf
@@ -0,0 +1,35 @@
+
+data "foo" "bar" {
+  count = 2
+
+  normal = "yes"
+
+  normal_block {}
+
+  _ {
+    # This "escaping block" is an escape hatch for when a resource
+    # type declares argument names that collide with meta-argument
+    # names. The examples below are not really realistic because they
+    # are long-standing names that predate the need for escaping,
+    # but we're using them as a proxy for new meta-arguments we might
+    # add in future language editions which might collide with
+    # names defined in pre-existing providers.
+
+    # note that count is set both as a meta-argument above _and_ as
+    # an resource-type-specific argument here, which is valid and
+    # should result in both being populated.
+    count = "not actually count"
+
+    # for_each is only set in here, not as a meta-argument
+    for_each = "not actually for_each"
+
+    lifecycle {
+      # This is a literal lifecycle block, not a meta-argument block
+    }
+
+    _ {
+        # It would be pretty weird for a resource type to define its own
+        # "_" block type, but that's valid to escape in here too.
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/escaping-blocks/module/child/nothing.tf b/v1.5.7/internal/configs/testdata/escaping-blocks/module/child/nothing.tf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/escaping-blocks/module/child/nothing.tf
diff --git a/v1.5.7/internal/configs/testdata/escaping-blocks/module/module-escaping-block.tf b/v1.5.7/internal/configs/testdata/escaping-blocks/module/module-escaping-block.tf
new file mode 100644
index 0000000..8d8a354
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/escaping-blocks/module/module-escaping-block.tf
@@ -0,0 +1,36 @@
+
+module "foo" {
+  source = "./child"
+  count = 2
+
+  normal = "yes"
+
+  normal_block {}
+
+  _ {
+    # This "escaping block" is an escape hatch for when a module
+    # declares input variable names that collide with meta-argument
+    # names. The examples below are not really realistic because they
+    # are long-standing names that predate the need for escaping,
+    # but we're using them as a proxy for new meta-arguments we might
+    # add in future language editions which might collide with
+    # names defined in pre-existing modules.
+
+    # note that count is set both as a meta-argument above _and_ as
+    # an resource-type-specific argument here, which is valid and
+    # should result in both being populated.
+    count = "not actually count"
+
+    # for_each is only set in here, not as a meta-argument
+    for_each = "not actually for_each"
+
+    lifecycle {
+      # This is a literal lifecycle block, not a meta-argument block
+    }
+
+    _ {
+        # It would be pretty weird for a resource type to define its own
+        # "_" block type, but that's valid to escape in here too.
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/escaping-blocks/provider/provider-escaping-block.tf b/v1.5.7/internal/configs/testdata/escaping-blocks/provider/provider-escaping-block.tf
new file mode 100644
index 0000000..65a11b7
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/escaping-blocks/provider/provider-escaping-block.tf
@@ -0,0 +1,23 @@
+
+provider "foo" {
+  alias = "bar"
+
+  normal = "yes"
+
+  _ {
+    # This "escaping block" is an escape hatch for when a provider
+    # declares argument names that collide with meta-argument
+    # names. The examples below are not really realistic because they
+    # are long-standing names that predate the need for escaping,
+    # but we're using them as a proxy for new meta-arguments we might
+    # add in future language editions which might collide with
+    # names defined in pre-existing providers.
+
+    # alias is set both as a meta-argument above _and_
+    # as a provider-type-specific argument
+    alias = "not actually alias"
+
+    # version is only set in here, not as a meta-argument
+    version = "not actually version"
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/escaping-blocks/resource/resource-escaping-block.tf b/v1.5.7/internal/configs/testdata/escaping-blocks/resource/resource-escaping-block.tf
new file mode 100644
index 0000000..4d356d6
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/escaping-blocks/resource/resource-escaping-block.tf
@@ -0,0 +1,43 @@
+
+resource "foo" "bar" {
+  count = 2
+
+  normal = "yes"
+
+  normal_block {}
+
+  _ {
+    # This "escaping block" is an escape hatch for when a resource
+    # type declares argument names that collide with meta-argument
+    # names. The examples below are not really realistic because they
+    # are long-standing names that predate the need for escaping,
+    # but we're using them as a proxy for new meta-arguments we might
+    # add in future language editions which might collide with
+    # names defined in pre-existing providers.
+
+    # note that count is set both as a meta-argument above _and_ as
+    # an resource-type-specific argument here, which is valid and
+    # should result in both being populated.
+    count = "not actually count"
+
+    # for_each is only set in here, not as a meta-argument
+    for_each = "not actually for_each"
+
+    lifecycle {
+      # This is a literal lifecycle block, not a meta-argument block
+    }
+
+    _ {
+        # It would be pretty weird for a resource type to define its own
+        # "_" block type, but that's valid to escape in here too.
+    }
+  }
+
+  provisioner "boop" {
+    when = destroy
+    _ {
+      when = "hell freezes over"
+    }
+    normal = "yep"
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/experiments/concluded/concluded_experiment.tf b/v1.5.7/internal/configs/testdata/experiments/concluded/concluded_experiment.tf
new file mode 100644
index 0000000..3310638
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/experiments/concluded/concluded_experiment.tf
@@ -0,0 +1,3 @@
+terraform {
+  experiments = [concluded]
+}
diff --git a/v1.5.7/internal/configs/testdata/experiments/current/current_experiment.tf b/v1.5.7/internal/configs/testdata/experiments/current/current_experiment.tf
new file mode 100644
index 0000000..d21b660
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/experiments/current/current_experiment.tf
@@ -0,0 +1,3 @@
+terraform {
+  experiments = [current]
+}
diff --git a/v1.5.7/internal/configs/testdata/experiments/invalid/invalid_experiments.tf b/v1.5.7/internal/configs/testdata/experiments/invalid/invalid_experiments.tf
new file mode 100644
index 0000000..d3b242b
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/experiments/invalid/invalid_experiments.tf
@@ -0,0 +1,3 @@
+terraform {
+  experiments = invalid
+}
diff --git a/v1.5.7/internal/configs/testdata/experiments/unknown/unknown_experiment.tf b/v1.5.7/internal/configs/testdata/experiments/unknown/unknown_experiment.tf
new file mode 100644
index 0000000..bbe36ed
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/experiments/unknown/unknown_experiment.tf
@@ -0,0 +1,3 @@
+terraform {
+  experiments = [unknown]
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/data-count-and-for_each.tf b/v1.5.7/internal/configs/testdata/invalid-files/data-count-and-for_each.tf
new file mode 100644
index 0000000..7cc4763
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/data-count-and-for_each.tf
@@ -0,0 +1,4 @@
+data "test" "foo" {
+  count = 2
+  for_each = ["a"]
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/data-invalid-provider-reference.tf b/v1.5.7/internal/configs/testdata/invalid-files/data-invalid-provider-reference.tf
new file mode 100644
index 0000000..aef92fd
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/data-invalid-provider-reference.tf
@@ -0,0 +1,3 @@
+data "test_resource" "t" {
+  provider = my_test
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/data-reserved-locals.tf b/v1.5.7/internal/configs/testdata/invalid-files/data-reserved-locals.tf
new file mode 100644
index 0000000..d6558f8
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/data-reserved-locals.tf
@@ -0,0 +1,3 @@
+data "test" "foo" {
+  locals {}
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/data-resource-lifecycle.tf b/v1.5.7/internal/configs/testdata/invalid-files/data-resource-lifecycle.tf
new file mode 100644
index 0000000..7c1aebe
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/data-resource-lifecycle.tf
@@ -0,0 +1,7 @@
+data "example" "example" {
+  lifecycle {
+    # The lifecycle arguments are not valid for data resources:
+    # only the precondition and postcondition blocks are allowed.
+    ignore_changes = []
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/everything-is-a-plan.tf b/v1.5.7/internal/configs/testdata/invalid-files/everything-is-a-plan.tf
new file mode 100644
index 0000000..e66766b
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/everything-is-a-plan.tf
@@ -0,0 +1,11 @@
+# experiments.EverythingIsAPlan exists but is not registered as an active (or
+# concluded) experiment, so this should fail until the experiment "gate" is
+# removed.
+terraform {
+  experiments = [everything_is_a_plan]
+}
+
+moved {
+    from = test_instance.foo
+    to   = test_instance.bar
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/interp-in-data-label.tf b/v1.5.7/internal/configs/testdata/invalid-files/interp-in-data-label.tf
new file mode 100644
index 0000000..e457650
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/interp-in-data-label.tf
@@ -0,0 +1,2 @@
+data "null_resource" "foo_${interpolations_invalid_here}" {
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/interp-in-rsrc-label.tf b/v1.5.7/internal/configs/testdata/invalid-files/interp-in-rsrc-label.tf
new file mode 100644
index 0000000..e7d310b
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/interp-in-rsrc-label.tf
@@ -0,0 +1,2 @@
+resource "null_resource" "foo_${interpolations_invalid_here}" {
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/json-as-native-syntax.tf b/v1.5.7/internal/configs/testdata/invalid-files/json-as-native-syntax.tf
new file mode 100644
index 0000000..2e28090
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/json-as-native-syntax.tf
@@ -0,0 +1,3 @@
+{
+  "terraform": {}
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/module-calls.tf b/v1.5.7/internal/configs/testdata/invalid-files/module-calls.tf
new file mode 100644
index 0000000..dbf29fe
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/module-calls.tf
@@ -0,0 +1,29 @@
+
+module "foo" {
+  source = "./foo"
+  # this block intentionally left (almost) blank
+}
+
+module "bar" {
+  source = "hashicorp/bar/aws"
+
+  boom = "🎆"
+  yes  = true
+}
+
+module "baz" {
+  source = "git::https://example.com/"
+
+  a = 1
+
+  count = 12
+  for_each = ["a", "b", "c"]
+
+  depends_on = [
+    module.bar,
+  ]
+
+  providers = {
+    aws = aws.foo
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/native-syntax-as-json.tf.json b/v1.5.7/internal/configs/testdata/invalid-files/native-syntax-as-json.tf.json
new file mode 100644
index 0000000..ca88e62
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/native-syntax-as-json.tf.json
@@ -0,0 +1,2 @@
+terraform {
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/precondition-postcondition-badref.tf b/v1.5.7/internal/configs/testdata/invalid-files/precondition-postcondition-badref.tf
new file mode 100644
index 0000000..ff5ff71
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/precondition-postcondition-badref.tf
@@ -0,0 +1,29 @@
+data "example" "example" {
+  foo = 5
+
+  lifecycle {
+    precondition {
+      condition     = data.example.example.foo == 5 # ERROR: Invalid reference in precondition
+      error_message = "Must be five."
+    }
+    postcondition {
+      condition     = self.foo == 5
+      error_message = "Must be five, but is ${data.example.example.foo}." # ERROR: Invalid reference in postcondition
+    }
+  }
+}
+
+resource "example" "example" {
+  foo = 5
+
+  lifecycle {
+    precondition {
+      condition     = example.example.foo == 5 # ERROR: Invalid reference in precondition
+      error_message = "Must be five."
+    }
+    postcondition {
+      condition     = self.foo == 5
+      error_message = "Must be five, but is ${example.example.foo}." # ERROR: Invalid reference in postcondition
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/precondition-postcondition-missing-condition.tf b/v1.5.7/internal/configs/testdata/invalid-files/precondition-postcondition-missing-condition.tf
new file mode 100644
index 0000000..d0a6ab3
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/precondition-postcondition-missing-condition.tf
@@ -0,0 +1,12 @@
+resource "example" "example" {
+  foo = 5
+
+  lifecycle {
+    precondition { # ERROR: Missing required argument
+      error_message = "Can a check block fail without a condition?"
+    }
+    postcondition { # ERROR: Missing required argument
+      error_message = "Do not try to pass the check; only realize that there is no check."
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/provider-localname-normalization.tf b/v1.5.7/internal/configs/testdata/invalid-files/provider-localname-normalization.tf
new file mode 100644
index 0000000..34c6e62
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/provider-localname-normalization.tf
@@ -0,0 +1,20 @@
+terraform {
+  required_providers {
+    test = {
+      source = "mycorp/test"
+    }
+  }
+}
+
+provider "TEST" {
+
+}
+
+resource test_resource "test" {
+  // this resource is (implicitly) provided by "mycorp/test"
+}
+
+resource test_resource "TEST" {
+  // this resource is (explicitly) provided by "hashicorp/test"
+  provider = TEST
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/provider-reserved.tf b/v1.5.7/internal/configs/testdata/invalid-files/provider-reserved.tf
new file mode 100644
index 0000000..559474d
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/provider-reserved.tf
@@ -0,0 +1,16 @@
+provider "test" {
+  # These are okay
+  alias   = "foo"
+  version = "1.0.0"
+
+  # Provider-specific arguments are also okay
+  arbitrary = true
+
+  # These are all reserved and should generate errors.
+  count      = 3
+  depends_on = ["foo.bar"]
+  for_each   = ["a", "b"]
+  source     = "foo.example.com/baz/bar"
+  lifecycle {}
+  locals {}
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/provider-syntax.tf b/v1.5.7/internal/configs/testdata/invalid-files/provider-syntax.tf
new file mode 100644
index 0000000..7cf680f
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/provider-syntax.tf
@@ -0,0 +1,3 @@
+provider "template" {
+  version = 
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/resource-count-and-for_each.tf b/v1.5.7/internal/configs/testdata/invalid-files/resource-count-and-for_each.tf
new file mode 100644
index 0000000..530fef7
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/resource-count-and-for_each.tf
@@ -0,0 +1,4 @@
+resource "test" "foo" {
+  count = 2
+  for_each = ["a"]
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/resource-invalid-provider-reference.tf b/v1.5.7/internal/configs/testdata/invalid-files/resource-invalid-provider-reference.tf
new file mode 100644
index 0000000..6fe675f
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/resource-invalid-provider-reference.tf
@@ -0,0 +1,3 @@
+resource "test_resource" "t" {
+  provider = my_test
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/resource-lifecycle-badbool.tf b/v1.5.7/internal/configs/testdata/invalid-files/resource-lifecycle-badbool.tf
new file mode 100644
index 0000000..fdddb69
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/resource-lifecycle-badbool.tf
@@ -0,0 +1,5 @@
+resource "example" "example" {
+  lifecycle {
+    create_before_destroy = "ABSOLUTELY NOT"
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/resource-name-invalid.tf b/v1.5.7/internal/configs/testdata/invalid-files/resource-name-invalid.tf
new file mode 100644
index 0000000..bfd9fff
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/resource-name-invalid.tf
@@ -0,0 +1,7 @@
+resource "test resource" "test_resource" {
+
+}
+
+data "test resource" "test_resource" {
+
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/resource-reserved-locals.tf b/v1.5.7/internal/configs/testdata/invalid-files/resource-reserved-locals.tf
new file mode 100644
index 0000000..368c21f
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/resource-reserved-locals.tf
@@ -0,0 +1,3 @@
+resource "test" "foo" {
+  locals {}
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/resources-ignorechanges-all-legacymix.tf b/v1.5.7/internal/configs/testdata/invalid-files/resources-ignorechanges-all-legacymix.tf
new file mode 100644
index 0000000..9557379
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/resources-ignorechanges-all-legacymix.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "web" {
+  lifecycle {
+    ignore_changes = ["*", "foo"]
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/triggered-invalid-each.tf b/v1.5.7/internal/configs/testdata/invalid-files/triggered-invalid-each.tf
new file mode 100644
index 0000000..0649ecc
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/triggered-invalid-each.tf
@@ -0,0 +1,7 @@
+resource "test_resource" "a" {
+  for_each = var.input
+  lifecycle {
+    // cannot use each.val
+    replace_triggered_by = [ test_resource.b[each.val] ]
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/triggered-invalid-expression.tf b/v1.5.7/internal/configs/testdata/invalid-files/triggered-invalid-expression.tf
new file mode 100644
index 0000000..8bf8af5
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/triggered-invalid-expression.tf
@@ -0,0 +1,6 @@
+resource "test_resource" "a" {
+  count = 1
+  lifecycle {
+    replace_triggered_by = [ not_a_reference ]
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/unexpected-attr.tf b/v1.5.7/internal/configs/testdata/invalid-files/unexpected-attr.tf
new file mode 100644
index 0000000..5abc475
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/unexpected-attr.tf
@@ -0,0 +1 @@
+foo = "bar"
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/unexpected-block.tf b/v1.5.7/internal/configs/testdata/invalid-files/unexpected-block.tf
new file mode 100644
index 0000000..491173c
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/unexpected-block.tf
@@ -0,0 +1,2 @@
+varyable "whoops" {
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/variable-bad-default.tf b/v1.5.7/internal/configs/testdata/invalid-files/variable-bad-default.tf
new file mode 100644
index 0000000..9da568f
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/variable-bad-default.tf
@@ -0,0 +1,4 @@
+variable "incorrectly_typed_default" {
+    type    = list(string)
+    default = "hello"
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/variable-bad-sensitive.tf b/v1.5.7/internal/configs/testdata/invalid-files/variable-bad-sensitive.tf
new file mode 100644
index 0000000..11156b3
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/variable-bad-sensitive.tf
@@ -0,0 +1,3 @@
+variable "sensitive-value" {
+  sensitive = "123" # must be boolean
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/variable-type-unknown.tf b/v1.5.7/internal/configs/testdata/invalid-files/variable-type-unknown.tf
new file mode 100644
index 0000000..bcbb88d
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/variable-type-unknown.tf
@@ -0,0 +1,3 @@
+variable "bad_type" {
+    type = notatype
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/variable-validation-condition-badref.tf b/v1.5.7/internal/configs/testdata/invalid-files/variable-validation-condition-badref.tf
new file mode 100644
index 0000000..9b9e935
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/variable-validation-condition-badref.tf
@@ -0,0 +1,18 @@
+
+locals {
+  foo = 1
+}
+
+variable "validation" {
+  validation {
+    condition     = local.foo == var.validation # ERROR: Invalid reference in variable validation
+    error_message = "Must be five."
+  }
+}
+
+variable "validation_error_expression" {
+  validation {
+    condition     = var.validation_error_expression != 1
+    error_message = "Cannot equal ${local.foo}." # ERROR: Invalid reference in variable validation
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/variable-validation-condition-noref.tf b/v1.5.7/internal/configs/testdata/invalid-files/variable-validation-condition-noref.tf
new file mode 100644
index 0000000..6eee913
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/variable-validation-condition-noref.tf
@@ -0,0 +1,7 @@
+
+variable "validation" {
+  validation {
+    condition     = true # ERROR: Invalid variable validation condition
+    error_message = "Must be true."
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/version-variable.tf b/v1.5.7/internal/configs/testdata/invalid-files/version-variable.tf
new file mode 100644
index 0000000..7c87105
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/version-variable.tf
@@ -0,0 +1,6 @@
+variable "module_version" { default = "v1.0" }
+
+module "foo" {
+  source  = "./ff"
+  version = var.module_version
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-files/zerolen.tf.json b/v1.5.7/internal/configs/testdata/invalid-files/zerolen.tf.json
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-files/zerolen.tf.json
diff --git a/v1.5.7/internal/configs/testdata/invalid-import-files/import-and-module-clash.tf b/v1.5.7/internal/configs/testdata/invalid-import-files/import-and-module-clash.tf
new file mode 100644
index 0000000..3bd5656
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-import-files/import-and-module-clash.tf
@@ -0,0 +1,12 @@
+
+module "importable_resource" {
+  source = "../valid-modules/importable-resource"
+}
+
+provider "local" {}
+
+import {
+  provider = local
+  id = "foo/bar"
+  to = module.importable_resource.local_file.foo
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-import-files/import-and-no-resource.tf b/v1.5.7/internal/configs/testdata/invalid-import-files/import-and-no-resource.tf
new file mode 100644
index 0000000..0bb2b01
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-import-files/import-and-no-resource.tf
@@ -0,0 +1,10 @@
+
+provider "local" {}
+
+import {
+  provider = local
+  id = "foo/bar"
+  to = local_file.foo_bar
+}
+
+resource "local_file" "foo_bar" {}
diff --git a/v1.5.7/internal/configs/testdata/invalid-import-files/import-and-resource-clash.tf b/v1.5.7/internal/configs/testdata/invalid-import-files/import-and-resource-clash.tf
new file mode 100644
index 0000000..c22b1d1
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-import-files/import-and-resource-clash.tf
@@ -0,0 +1,16 @@
+
+provider "local" {}
+
+provider "local" {
+  alias = "alternate"
+}
+
+import {
+  provider = local
+  id = "foo/bar"
+  to = local_file.foo_bar
+}
+
+resource "local_file" "foo_bar" {
+  provider = local.alternate
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-modules/import-to-moved-from/main.tf b/v1.5.7/internal/configs/testdata/invalid-modules/import-to-moved-from/main.tf
new file mode 100644
index 0000000..f0f1a7a
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-modules/import-to-moved-from/main.tf
@@ -0,0 +1,12 @@
+import {
+  id = "foo/bar"
+  to = local_file.foo_bar
+}
+
+moved {
+  from = local_file.foo_bar
+  to   = local_file.bar_baz
+}
+
+resource "local_file" "bar_baz" {
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-modules/multiple-required-providers/a.tf b/v1.5.7/internal/configs/testdata/invalid-modules/multiple-required-providers/a.tf
new file mode 100644
index 0000000..a607ddd
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-modules/multiple-required-providers/a.tf
@@ -0,0 +1,7 @@
+terraform {
+  required_providers {
+    bar = {
+      version = "~>1.0.0"
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-modules/multiple-required-providers/b.tf b/v1.5.7/internal/configs/testdata/invalid-modules/multiple-required-providers/b.tf
new file mode 100644
index 0000000..7672e92
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-modules/multiple-required-providers/b.tf
@@ -0,0 +1,7 @@
+terraform {
+  required_providers {
+    foo = {
+      version = "~>2.0.0"
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-modules/nullable-with-default-null/main.tf b/v1.5.7/internal/configs/testdata/invalid-modules/nullable-with-default-null/main.tf
new file mode 100644
index 0000000..bf7a58a
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-modules/nullable-with-default-null/main.tf
@@ -0,0 +1,5 @@
+variable "in" {
+  type = number
+  nullable = false
+  default = null
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-modules/override-cloud-duplicates/main.tf b/v1.5.7/internal/configs/testdata/invalid-modules/override-cloud-duplicates/main.tf
new file mode 100644
index 0000000..2de9a58
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-modules/override-cloud-duplicates/main.tf
@@ -0,0 +1,14 @@
+terraform {
+  cloud {
+    organization = "foo"
+    should_not_be_present_with_override = true
+  }
+}
+
+resource "aws_instance" "web" {
+  ami = "ami-1234"
+  security_groups = [
+    "foo",
+    "bar",
+  ]
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-modules/override-cloud-duplicates/override.tf b/v1.5.7/internal/configs/testdata/invalid-modules/override-cloud-duplicates/override.tf
new file mode 100644
index 0000000..17ef011
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-modules/override-cloud-duplicates/override.tf
@@ -0,0 +1,11 @@
+terraform {
+  cloud {
+    organization = "foo"
+  }
+}
+
+terraform {
+  cloud {
+    organization = "bar"
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-modules/override-nonexist-variable/override.tf b/v1.5.7/internal/configs/testdata/invalid-modules/override-nonexist-variable/override.tf
new file mode 100644
index 0000000..720db27
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-modules/override-nonexist-variable/override.tf
@@ -0,0 +1,3 @@
+variable "foo" {
+  description = "overridden"
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-modules/override-variable-causes-bad-default/base.tf b/v1.5.7/internal/configs/testdata/invalid-modules/override-variable-causes-bad-default/base.tf
new file mode 100644
index 0000000..f2d572e
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-modules/override-variable-causes-bad-default/base.tf
@@ -0,0 +1,4 @@
+variable "foo" {
+  type    = list(string)
+  default = ["this is valid"]
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-modules/override-variable-causes-bad-default/override.tf b/v1.5.7/internal/configs/testdata/invalid-modules/override-variable-causes-bad-default/override.tf
new file mode 100644
index 0000000..3c979d9
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-modules/override-variable-causes-bad-default/override.tf
@@ -0,0 +1,5 @@
+variable "foo" {
+  type = string
+  # Since we didn't also override the default, this is now invalid because
+  # the existing default is not compatible with "string".
+}
diff --git a/v1.5.7/internal/configs/testdata/invalid-modules/provider-meta/invalid-interpolation.tf b/v1.5.7/internal/configs/testdata/invalid-modules/provider-meta/invalid-interpolation.tf
new file mode 100644
index 0000000..d8a0d44
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/invalid-modules/provider-meta/invalid-interpolation.tf
@@ -0,0 +1,10 @@
+terraform {
+  provider_meta "my-provider" {
+    hello = var.name
+  }
+}
+
+variable "name" {
+  type = string
+}
+
diff --git a/v1.5.7/internal/configs/testdata/nested-backend-warning/child/child.tf b/v1.5.7/internal/configs/testdata/nested-backend-warning/child/child.tf
new file mode 100644
index 0000000..5a6948e
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/nested-backend-warning/child/child.tf
@@ -0,0 +1,6 @@
+terraform {
+  # Only the root module can declare a backend. Terraform should emit a warning
+  # about this child module backend declaration.
+  backend "ignored" {
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/nested-backend-warning/root.tf b/v1.5.7/internal/configs/testdata/nested-backend-warning/root.tf
new file mode 100644
index 0000000..1f95749
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/nested-backend-warning/root.tf
@@ -0,0 +1,3 @@
+module "child" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/configs/testdata/nested-cloud-warning/child/child.tf b/v1.5.7/internal/configs/testdata/nested-cloud-warning/child/child.tf
new file mode 100644
index 0000000..540b921
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/nested-cloud-warning/child/child.tf
@@ -0,0 +1,6 @@
+terraform {
+  # Only the root module can declare a Cloud configuration. Terraform should emit a warning
+  # about this child module Cloud declaration.
+  cloud {
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/nested-cloud-warning/root.tf b/v1.5.7/internal/configs/testdata/nested-cloud-warning/root.tf
new file mode 100644
index 0000000..1f95749
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/nested-cloud-warning/root.tf
@@ -0,0 +1,3 @@
+module "child" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/configs/testdata/nested-errors/child_a/child_a.tf b/v1.5.7/internal/configs/testdata/nested-errors/child_a/child_a.tf
new file mode 100644
index 0000000..d2fb89f
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/nested-errors/child_a/child_a.tf
@@ -0,0 +1,7 @@
+
+module "child_c" {
+  # Note: this test case has an unrealistic module loader that resolves all
+  # sources as relative to the fixture directory, rather than to the
+  # current module directory as Terraform normally would.
+  source = "./child_c"
+}
diff --git a/v1.5.7/internal/configs/testdata/nested-errors/child_c/child_c.tf b/v1.5.7/internal/configs/testdata/nested-errors/child_c/child_c.tf
new file mode 100644
index 0000000..19ba443
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/nested-errors/child_c/child_c.tf
@@ -0,0 +1,6 @@
+output "hello" {
+  value = "hello"
+}
+
+invalid "block" "type " {
+}
diff --git a/v1.5.7/internal/configs/testdata/nested-errors/root.tf b/v1.5.7/internal/configs/testdata/nested-errors/root.tf
new file mode 100644
index 0000000..d596eb0
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/nested-errors/root.tf
@@ -0,0 +1,3 @@
+module "child_a" {
+  source = "./child_a"
+}
diff --git a/v1.5.7/internal/configs/testdata/provider-reqs/child/grandchild/provider-reqs-grandchild.tf b/v1.5.7/internal/configs/testdata/provider-reqs/child/grandchild/provider-reqs-grandchild.tf
new file mode 100644
index 0000000..5ac9dfa
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/provider-reqs/child/grandchild/provider-reqs-grandchild.tf
@@ -0,0 +1,4 @@
+# There is no provider in required_providers called "grandchild", so this
+# implicitly declares a dependency on "hashicorp/grandchild".
+resource "grandchild_foo" "bar" {
+}
diff --git a/v1.5.7/internal/configs/testdata/provider-reqs/child/provider-reqs-child.tf b/v1.5.7/internal/configs/testdata/provider-reqs/child/provider-reqs-child.tf
new file mode 100644
index 0000000..4ebb659
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/provider-reqs/child/provider-reqs-child.tf
@@ -0,0 +1,15 @@
+terraform {
+  required_providers {
+    cloud = {
+      source = "tf.example.com/awesomecorp/happycloud"
+    }
+    null = {
+      # This should merge with the null provider constraint in the root module
+      version = "2.0.1"
+    }
+  }
+}
+
+module "nested" {
+  source = "./grandchild"
+}
diff --git a/v1.5.7/internal/configs/testdata/provider-reqs/provider-reqs-root.tf b/v1.5.7/internal/configs/testdata/provider-reqs/provider-reqs-root.tf
new file mode 100644
index 0000000..03a5625
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/provider-reqs/provider-reqs-root.tf
@@ -0,0 +1,34 @@
+terraform {
+  required_providers {
+    null = "~> 2.0.0"
+    random = {
+      version = "~> 1.2.0"
+    }
+    tls = {
+      source  = "hashicorp/tls"
+      version = "~> 3.0"
+    }
+  }
+}
+
+# There is no provider in required_providers called "implied", so this
+# implicitly declares a dependency on "hashicorp/implied".
+resource "implied_foo" "bar" {
+}
+
+module "kinder" {
+  source = "./child"
+}
+
+# There is no provider in required_providers called "terraform", but for
+# this name in particular we imply terraform.io/builtin/terraform instead,
+# to avoid selecting the now-unmaintained
+# registry.terraform.io/hashicorp/terraform.
+data "terraform_remote_state" "bar" {
+}
+
+# There is no provider in required_providers called "configured", so the version
+# constraint should come from this configuration block.
+provider "configured" {
+  version = "~> 1.4"
+}
diff --git a/v1.5.7/internal/configs/testdata/providers-explicit-fqn/root.tf b/v1.5.7/internal/configs/testdata/providers-explicit-fqn/root.tf
new file mode 100644
index 0000000..9a8d426
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/providers-explicit-fqn/root.tf
@@ -0,0 +1,11 @@
+
+terraform {
+  required_providers {
+    foo-test = {
+      source = "foo/test"
+    }
+    terraform = {
+      source = "not-builtin/not-terraform"
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/backend.tf b/v1.5.7/internal/configs/testdata/valid-files/backend.tf
new file mode 100644
index 0000000..bd8e0f6
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/backend.tf
@@ -0,0 +1,10 @@
+
+terraform {
+  backend "example" {
+    foo = "bar"
+
+    baz {
+      bar = "foo"
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/cloud.tf b/v1.5.7/internal/configs/testdata/valid-files/cloud.tf
new file mode 100644
index 0000000..91985fc
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/cloud.tf
@@ -0,0 +1,10 @@
+
+terraform {
+  cloud {
+    foo = "bar"
+
+    baz {
+      bar = "foo"
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/data-sources.tf b/v1.5.7/internal/configs/testdata/valid-files/data-sources.tf
new file mode 100644
index 0000000..f14dffd
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/data-sources.tf
@@ -0,0 +1,15 @@
+data "http" "example1" {
+}
+
+data "http" "example2" {
+  url = "http://example.com/"
+
+  request_headers = {
+    "Accept" = "application/json"
+  }
+
+  count = 5
+  depends_on = [
+    data.http.example1,
+  ]
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/empty.tf b/v1.5.7/internal/configs/testdata/valid-files/empty.tf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/empty.tf
diff --git a/v1.5.7/internal/configs/testdata/valid-files/empty.tf.json b/v1.5.7/internal/configs/testdata/valid-files/empty.tf.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/empty.tf.json
@@ -0,0 +1 @@
+{}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/locals.tf b/v1.5.7/internal/configs/testdata/valid-files/locals.tf
new file mode 100644
index 0000000..f2ee4a7
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/locals.tf
@@ -0,0 +1,16 @@
+
+locals {
+  # This block intentionally left blank
+}
+
+locals {
+  foo = "foo"
+  bar = true
+}
+
+locals {
+  baz    = "oink"
+  dunno  = "🤷"
+  rowing = "🚣‍♀️"
+  π      = 3.14159265359
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/locals.tf.json b/v1.5.7/internal/configs/testdata/valid-files/locals.tf.json
new file mode 100644
index 0000000..525f69d
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/locals.tf.json
@@ -0,0 +1,10 @@
+{
+  "locals": {
+    "foo": "foo",
+    "bar": true,
+    "baz": "oink",
+    "dunno": "🤷",
+    "rowing": "🚣‍♀️",
+    "π": 3.14159265359
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/object-optional-attrs.tf b/v1.5.7/internal/configs/testdata/valid-files/object-optional-attrs.tf
new file mode 100644
index 0000000..8b7fda9
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/object-optional-attrs.tf
@@ -0,0 +1,38 @@
+variable "a" {
+  type = object({
+    foo = optional(string)
+    bar = optional(bool, true)
+  })
+}
+
+variable "b" {
+  type = list(
+    object({
+      foo = optional(string)
+    })
+  )
+}
+
+variable "c" {
+  type = set(
+    object({
+      foo = optional(string)
+    })
+  )
+}
+
+variable "d" {
+  type = map(
+    object({
+      foo = optional(string)
+    })
+  )
+}
+
+variable "e" {
+  type = object({
+    foo = string
+    bar = optional(bool, true)
+  })
+  default = null
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/outputs.tf b/v1.5.7/internal/configs/testdata/valid-files/outputs.tf
new file mode 100644
index 0000000..7a80666
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/outputs.tf
@@ -0,0 +1,25 @@
+
+output "foo" {
+  value = "hello"
+}
+
+output "bar" {
+  value = local.bar
+}
+
+output "baz" {
+  value     = "ssshhhhhhh"
+  sensitive = true
+}
+
+output "cheeze_pizza" {
+  description = "Nothing special"
+  value       = "🍕"
+}
+
+output "π" {
+  value = 3.14159265359
+  depends_on = [
+    pizza.cheese,
+  ]
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/preconditions-postconditions.tf b/v1.5.7/internal/configs/testdata/valid-files/preconditions-postconditions.tf
new file mode 100644
index 0000000..6f48840
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/preconditions-postconditions.tf
@@ -0,0 +1,34 @@
+resource "test" "test" {
+  lifecycle {
+    precondition {
+      condition     = path.module != ""
+      error_message = "Must be true."
+    }
+    postcondition {
+      condition     = path.module != ""
+      error_message = "Must be true."
+    }
+  }
+}
+
+data "test" "test" {
+  lifecycle {
+    precondition {
+      condition     = path.module != ""
+      error_message = "Must be true."
+    }
+    postcondition {
+      condition     = path.module != ""
+      error_message = "Must be true."
+    }
+  }
+}
+
+output "test" {
+  value = ""
+
+  precondition {
+    condition     = path.module != ""
+    error_message = "Must be true."
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/provider-configs.tf b/v1.5.7/internal/configs/testdata/valid-files/provider-configs.tf
new file mode 100644
index 0000000..6077d64
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/provider-configs.tf
@@ -0,0 +1,13 @@
+
+provider "foo" {
+}
+
+provider "bar" {
+  other = 12
+}
+
+provider "bar" {
+  other = 13
+
+  alias = "bar"
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/providers-explicit-implied.tf b/v1.5.7/internal/configs/testdata/valid-files/providers-explicit-implied.tf
new file mode 100644
index 0000000..49c063a
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/providers-explicit-implied.tf
@@ -0,0 +1,34 @@
+provider "aws" {
+
+}
+
+provider "template" {
+  alias = "foo"
+}
+
+resource "aws_instance" "foo" {
+
+}
+
+resource "null_resource" "foo" {
+
+}
+
+import {
+  id = "directory/filename"
+  to = local_file.foo
+}
+
+import {
+  provider = template.foo
+  id       = "directory/foo_filename"
+  to       = local_file.bar
+}
+
+terraform {
+  required_providers {
+    test = {
+      source = "hashicorp/test"
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/references.tf.json b/v1.5.7/internal/configs/testdata/valid-files/references.tf.json
new file mode 100644
index 0000000..3fe7e0a
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/references.tf.json
@@ -0,0 +1,11 @@
+{
+  "//": "The purpose of this test file is to show that we can use template syntax unwrapping to provide complex expressions without generating the deprecation warnings we'd expect for native syntax.",
+  "resource": {
+    "null_resource": {
+      "baz": {
+        "//": "This particular use of template syntax is redundant, but we permit it because this is the documented way to use more complex expressions in JSON.",
+        "triggers": "${ {} }"
+      }
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/required-providers.tf b/v1.5.7/internal/configs/testdata/valid-files/required-providers.tf
new file mode 100644
index 0000000..271df4a
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/required-providers.tf
@@ -0,0 +1,7 @@
+
+terraform {
+  required_providers {
+    aws    = "~> 1.0.0"
+    consul = "~> 1.2.0"
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/required-version.tf b/v1.5.7/internal/configs/testdata/valid-files/required-version.tf
new file mode 100644
index 0000000..77c9a35
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/required-version.tf
@@ -0,0 +1,4 @@
+
+terraform {
+  required_version = "~> 0.12.0"
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/resources-ignorechanges-all.tf b/v1.5.7/internal/configs/testdata/valid-files/resources-ignorechanges-all.tf
new file mode 100644
index 0000000..32cd232
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/resources-ignorechanges-all.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "web" {
+  lifecycle {
+    ignore_changes = all
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/resources-ignorechanges-all.tf.json b/v1.5.7/internal/configs/testdata/valid-files/resources-ignorechanges-all.tf.json
new file mode 100644
index 0000000..c220208
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/resources-ignorechanges-all.tf.json
@@ -0,0 +1,11 @@
+{
+  "resource": {
+    "aws_instance": {
+      "web": {
+        "lifecycle": {
+          "ignore_changes": "all"
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/resources.tf b/v1.5.7/internal/configs/testdata/valid-files/resources.tf
new file mode 100644
index 0000000..aab038e
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/resources.tf
@@ -0,0 +1,49 @@
+resource "aws_security_group" "firewall" {
+  lifecycle {
+    create_before_destroy = true
+    prevent_destroy = true
+    ignore_changes = [
+      description,
+    ]
+  }
+
+  connection {
+    host = "127.0.0.1"
+  }
+
+  provisioner "local-exec" {
+    command = "echo hello"
+
+    connection {
+      host = "10.1.2.1"
+    }
+  }
+
+  provisioner "local-exec" {
+    command = "echo hello"
+  }
+}
+
+resource "aws_instance" "web" {
+  count = 2
+  ami = "ami-1234"
+  security_groups = [
+    "foo",
+    "bar",
+  ]
+
+  network_interface {
+    device_index = 0
+    description = "Main network interface"
+  }
+
+  depends_on = [
+    aws_security_group.firewall,
+  ]
+}
+
+resource "aws_instance" "depends" {
+  lifecycle {
+    replace_triggered_by = [ aws_instance.web[1], aws_security_group.firewall.id ]
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/resources.tf.json b/v1.5.7/internal/configs/testdata/valid-files/resources.tf.json
new file mode 100644
index 0000000..627963d
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/resources.tf.json
@@ -0,0 +1,18 @@
+{
+  "resource": {
+    "test_object": {
+      "a": {
+        "count": 1,
+        "test_string": "new"
+      },
+      "b": {
+        "count": 1,
+        "lifecycle": {
+          "replace_triggered_by": [
+            "test_object.a[count.index].test_string"
+          ]
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/valid-language-edition.tf b/v1.5.7/internal/configs/testdata/valid-files/valid-language-edition.tf
new file mode 100644
index 0000000..60f2df3
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/valid-language-edition.tf
@@ -0,0 +1,8 @@
+terraform {
+  # If we drop support for TF2021 in a future Terraform release then this
+  # test will fail. In that case, update this to a newer edition that is
+  # still supported, because the purpose of this test is to verify that
+  # we can successfully decode the language argument, not specifically
+  # that we support TF2021.
+  language = TF2021
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/variable_validation.tf b/v1.5.7/internal/configs/testdata/valid-files/variable_validation.tf
new file mode 100644
index 0000000..20e227e
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/variable_validation.tf
@@ -0,0 +1,22 @@
+variable "validation" {
+  validation {
+    condition     = var.validation == 5
+    error_message = "Must be five."
+  }
+}
+
+variable "validation_function" {
+  type = list(string)
+  validation {
+    condition     = length(var.validation_function) > 0
+    error_message = "Must not be empty."
+  }
+}
+
+variable "validation_error_expression" {
+  type = list(string)
+  validation {
+    condition     = length(var.validation_error_expression) < 10
+    error_message = "Too long (${length(var.validation_error_expression)} is greater than 10)."
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/variables.tf b/v1.5.7/internal/configs/testdata/valid-files/variables.tf
new file mode 100644
index 0000000..16640c9
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/variables.tf
@@ -0,0 +1,44 @@
+
+variable "foo" {
+}
+
+variable "bar" {
+  default = "hello"
+}
+
+variable "baz" {
+  type = list
+}
+
+variable "bar-baz" {
+  default = []
+  type    = list(string)
+}
+
+variable "cheeze_pizza" {
+  description = "Nothing special"
+}
+
+variable "π" {
+  default = 3.14159265359
+}
+
+variable "sensitive_value" {
+  default = {
+    "a" = 1,
+    "b" = 2
+  }
+  sensitive = true
+}
+
+variable "nullable" {
+  type = string
+  nullable = true
+  default = "ok"
+}
+
+variable "nullable_default_null" {
+  type = map(string)
+  nullable = true
+  default = null
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-files/variables.tf.json b/v1.5.7/internal/configs/testdata/valid-files/variables.tf.json
new file mode 100644
index 0000000..4e43eb2
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-files/variables.tf.json
@@ -0,0 +1,28 @@
+{
+  "variable": {
+    "foo": {},
+    "bar": {
+      "default": "hello"
+    },
+    "baz": {
+      "type": "list"
+    },
+    "bar-baz": {
+      "default": [],
+      "type": "list"
+    },
+    "cheese_pizza": {
+      "description": "Nothing special"
+    },
+    "π": {
+      "default": 3.14159265359
+    },
+    "sensitive_value": {
+      "default": {
+        "a": 1,
+        "b": 2
+      },
+      "sensitive": true
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/empty/README b/v1.5.7/internal/configs/testdata/valid-modules/empty/README
new file mode 100644
index 0000000..6d93707
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/empty/README
@@ -0,0 +1,2 @@
+This directory is intentionally empty, to test what happens when we load
+a module that contains no configuration files.
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/implied-providers/providers.tf b/v1.5.7/internal/configs/testdata/valid-modules/implied-providers/providers.tf
new file mode 100644
index 0000000..63b5b14
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/implied-providers/providers.tf
@@ -0,0 +1,21 @@
+terraform {
+  required_providers {
+    // This is an expected "real world" example of a community provider, which
+    // has resources named "foo_*" and will likely be used in configurations
+    // with the local name of "foo".
+    foo = {
+      source = "registry.acme.corp/acme/foo"
+    }
+
+    // However, implied provider lookups are based on local name, not provider
+    // type, and this example clarifies that. Only resources with addresses
+    // starting "whatever_" will be assigned this provider implicitly.
+    //
+    // This is _not_ a recommended usage pattern. The best practice is for
+    // local name and type to be the same, and only use a different local name
+    // if there are provider type collisions.
+    whatever = {
+      source = "acme/something"
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/implied-providers/resources.tf b/v1.5.7/internal/configs/testdata/valid-modules/implied-providers/resources.tf
new file mode 100644
index 0000000..6b4a8af
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/implied-providers/resources.tf
@@ -0,0 +1,12 @@
+// These resources map to the configured "foo" provider"
+resource foo_resource "a" {}
+data foo_resource "b" {}
+
+// These resources map to a default "hashicorp/bar" provider
+resource bar_resource "c" {}
+data bar_resource "d" {}
+
+// These resources map to the configured "whatever" provider, which has FQN
+// "acme/something".
+resource whatever_resource "e" {}
+data whatever_resource "f" {}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/importable-resource/main.tf b/v1.5.7/internal/configs/testdata/valid-modules/importable-resource/main.tf
new file mode 100644
index 0000000..3bd2dcb
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/importable-resource/main.tf
@@ -0,0 +1,2 @@
+
+resource "local_file" "foo" {}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/importable-resource/providers.tf b/v1.5.7/internal/configs/testdata/valid-modules/importable-resource/providers.tf
new file mode 100644
index 0000000..4124dca
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/importable-resource/providers.tf
@@ -0,0 +1,7 @@
+terraform {
+  required_providers {
+    local = {
+      source = "hashicorp/local"
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/moved-blocks/moved-blocks-1.tf b/v1.5.7/internal/configs/testdata/valid-modules/moved-blocks/moved-blocks-1.tf
new file mode 100644
index 0000000..fab882d
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/moved-blocks/moved-blocks-1.tf
@@ -0,0 +1,24 @@
+moved {
+  from = test.foo
+  to   = test.bar
+}
+
+moved {
+  from = test.foo
+  to   = test.bar["bloop"]
+}
+
+moved {
+  from = module.a
+  to   = module.b
+}
+
+moved {
+  from = module.a
+  to   = module.a["foo"]
+}
+
+moved {
+  from = test.foo
+  to   = module.a.test.foo
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/moved-blocks/moved-blocks-2.tf b/v1.5.7/internal/configs/testdata/valid-modules/moved-blocks/moved-blocks-2.tf
new file mode 100644
index 0000000..afc9f5a
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/moved-blocks/moved-blocks-2.tf
@@ -0,0 +1,6 @@
+# One more moved block in a separate file just to make sure the
+# appending of multiple files works properly.
+moved {
+  from = data.test.foo
+  to   = data.test.bar
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/nested-providers-fqns/child/main.tf b/v1.5.7/internal/configs/testdata/valid-modules/nested-providers-fqns/child/main.tf
new file mode 100644
index 0000000..79e449b
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/nested-providers-fqns/child/main.tf
@@ -0,0 +1,25 @@
+terraform {
+  required_providers {
+    bar-test = {
+      source = "bar/test"
+    }
+    foo-test = {
+      source = "foo/test"
+      configuration_aliases = [foo-test.other]
+    }
+  }
+}
+
+resource "test_instance" "explicit" {
+  // explicitly setting provider bar-test
+  provider = bar-test
+}
+
+resource "test_instance" "implicit" {
+  // since the provider type name "test" does not match an entry in
+  // required_providers, the default provider "test" should be used
+}
+
+resource "test_instance" "other" {
+  provider = foo-test.other
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/nested-providers-fqns/main.tf b/v1.5.7/internal/configs/testdata/valid-modules/nested-providers-fqns/main.tf
new file mode 100644
index 0000000..27988f4
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/nested-providers-fqns/main.tf
@@ -0,0 +1,29 @@
+terraform {
+  required_providers {
+    foo-test = {
+      source = "foo/test"
+    }
+  }
+}
+
+provider "foo-test" {}
+
+module "child" {
+  source = "./child"
+  providers = {
+    foo-test.other = foo-test
+  }
+}
+
+resource "test_instance" "explicit" {
+  provider = foo-test
+}
+
+data "test_resource" "explicit" {
+  provider = foo-test
+}
+
+resource "test_instance" "implicit" {
+  // since the provider type name "test" does not match an entry in
+  // required_providers, the default provider "test" should be used
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-backend-no-base/main.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-backend-no-base/main.tf
new file mode 100644
index 0000000..7bb1380
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-backend-no-base/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "web" {
+  ami = "ami-1234"
+  security_groups = [
+    "foo",
+    "bar",
+  ]
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-backend-no-base/override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-backend-no-base/override.tf
new file mode 100644
index 0000000..d57fade
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-backend-no-base/override.tf
@@ -0,0 +1,5 @@
+terraform {
+  backend "bar" {
+    path = "CHANGED/relative/path/to/terraform.tfstate"
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-backend-with-cloud/main.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-backend-with-cloud/main.tf
new file mode 100644
index 0000000..56fb72f
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-backend-with-cloud/main.tf
@@ -0,0 +1,13 @@
+terraform {
+  backend "foo" {
+    path = "relative/path/to/terraform.tfstate"
+  }
+}
+
+resource "aws_instance" "web" {
+  ami = "ami-1234"
+  security_groups = [
+    "foo",
+    "bar",
+  ]
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-backend-with-cloud/override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-backend-with-cloud/override.tf
new file mode 100644
index 0000000..51ae925
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-backend-with-cloud/override.tf
@@ -0,0 +1,5 @@
+terraform {
+  cloud {
+    organization = "foo"
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-backend/main.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-backend/main.tf
new file mode 100644
index 0000000..56fb72f
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-backend/main.tf
@@ -0,0 +1,13 @@
+terraform {
+  backend "foo" {
+    path = "relative/path/to/terraform.tfstate"
+  }
+}
+
+resource "aws_instance" "web" {
+  ami = "ami-1234"
+  security_groups = [
+    "foo",
+    "bar",
+  ]
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-backend/override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-backend/override.tf
new file mode 100644
index 0000000..d57fade
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-backend/override.tf
@@ -0,0 +1,5 @@
+terraform {
+  backend "bar" {
+    path = "CHANGED/relative/path/to/terraform.tfstate"
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-cloud-no-base/main.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-cloud-no-base/main.tf
new file mode 100644
index 0000000..7bb1380
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-cloud-no-base/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "web" {
+  ami = "ami-1234"
+  security_groups = [
+    "foo",
+    "bar",
+  ]
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-cloud-no-base/override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-cloud-no-base/override.tf
new file mode 100644
index 0000000..51ae925
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-cloud-no-base/override.tf
@@ -0,0 +1,5 @@
+terraform {
+  cloud {
+    organization = "foo"
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-cloud/main.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-cloud/main.tf
new file mode 100644
index 0000000..2de9a58
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-cloud/main.tf
@@ -0,0 +1,14 @@
+terraform {
+  cloud {
+    organization = "foo"
+    should_not_be_present_with_override = true
+  }
+}
+
+resource "aws_instance" "web" {
+  ami = "ami-1234"
+  security_groups = [
+    "foo",
+    "bar",
+  ]
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-cloud/override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-cloud/override.tf
new file mode 100644
index 0000000..a4a7752
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-cloud/override.tf
@@ -0,0 +1,5 @@
+terraform {
+  cloud {
+    organization = "CHANGED"
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-dynamic-block-base/a_override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-dynamic-block-base/a_override.tf
new file mode 100644
index 0000000..e168fac
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-dynamic-block-base/a_override.tf
@@ -0,0 +1,6 @@
+
+resource "test" "foo" {
+  foo {
+    from = "override"
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-dynamic-block-base/base.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-dynamic-block-base/base.tf
new file mode 100644
index 0000000..0f3ad4c
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-dynamic-block-base/base.tf
@@ -0,0 +1,9 @@
+
+resource "test" "foo" {
+  dynamic "foo" {
+    for_each = []
+    content {
+      from = "base"
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-dynamic-block-override/a_override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-dynamic-block-override/a_override.tf
new file mode 100644
index 0000000..d37ce79
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-dynamic-block-override/a_override.tf
@@ -0,0 +1,9 @@
+
+resource "test" "foo" {
+  dynamic "foo" {
+    for_each = []
+    content {
+      from = "override"
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-dynamic-block-override/base.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-dynamic-block-override/base.tf
new file mode 100644
index 0000000..3ed55a6
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-dynamic-block-override/base.tf
@@ -0,0 +1,6 @@
+
+resource "test" "foo" {
+  foo {
+    from = "base"
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-ignore-changes/main.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-ignore-changes/main.tf
new file mode 100644
index 0000000..55ae515
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-ignore-changes/main.tf
@@ -0,0 +1,3 @@
+resource "test_instance" "foo" {
+  foo = "bar"
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-ignore-changes/main_override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-ignore-changes/main_override.tf
new file mode 100644
index 0000000..f9cd9a5
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-ignore-changes/main_override.tf
@@ -0,0 +1,6 @@
+resource "test_instance" "foo" {
+  foo = "bar"
+  lifecycle {
+    ignore_changes = all
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-module/a_override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-module/a_override.tf
new file mode 100644
index 0000000..7962845
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-module/a_override.tf
@@ -0,0 +1,11 @@
+
+module "example" {
+  source = "./example2-a_override"
+
+  foo = "a_override foo"
+  new = "a_override new"
+
+  providers = {
+    test = test.a_override
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-module/b_override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-module/b_override.tf
new file mode 100644
index 0000000..b624a8a
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-module/b_override.tf
@@ -0,0 +1,9 @@
+
+module "example" {
+  new   = "b_override new"
+  newer = "b_override newer"
+
+  providers = {
+    test = test.b_override
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-module/primary.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-module/primary.tf
new file mode 100644
index 0000000..01a870d
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-module/primary.tf
@@ -0,0 +1,13 @@
+
+module "example" {
+  source = "./example2"
+
+  kept = "primary kept"
+  foo  = "primary foo"
+
+  providers = {
+    test = test.foo
+  }
+  depends_on = [null_resource.test]
+}
+resource "null_resource" "test" {}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-output-sensitive/override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-output-sensitive/override.tf
new file mode 100644
index 0000000..b965fc1
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-output-sensitive/override.tf
@@ -0,0 +1,3 @@
+output "foo" {
+  sensitive = true
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-output-sensitive/primary.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-output-sensitive/primary.tf
new file mode 100644
index 0000000..13bd3a9
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-output-sensitive/primary.tf
@@ -0,0 +1,3 @@
+output "foo" {
+  value = "Hello World"
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-resource-provider/a_override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-resource-provider/a_override.tf
new file mode 100644
index 0000000..9a7c3f9
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-resource-provider/a_override.tf
@@ -0,0 +1,3 @@
+resource "test_instance" "explicit" {
+  provider = bar-test
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-resource-provider/base.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-resource-provider/base.tf
new file mode 100644
index 0000000..0ea12dd
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-resource-provider/base.tf
@@ -0,0 +1,17 @@
+terraform {
+  required_providers {
+    foo-test = {
+      source = "foo/test"
+    }
+    bar-test = {
+      source = "bar/test"
+    }
+  }
+}
+
+resource "test_instance" "explicit" {
+  provider = foo-test
+}
+
+// the provider for this resource should default to "hashicorp/test"
+resource "test_instance" "default" {}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-variable-sensitive/a_override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-variable-sensitive/a_override.tf
new file mode 100644
index 0000000..f2ece93
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-variable-sensitive/a_override.tf
@@ -0,0 +1,23 @@
+variable "false_true" {
+  sensitive = true
+}
+
+variable "true_false" {
+  sensitive = false
+}
+
+variable "false_false_true" {
+  sensitive = false
+}
+
+variable "true_true_false" {
+  sensitive = true
+}
+
+variable "false_true_false" {
+  sensitive = true
+}
+
+variable "true_false_true" {
+  sensitive = false
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-variable-sensitive/b_override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-variable-sensitive/b_override.tf
new file mode 100644
index 0000000..e58e5b3
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-variable-sensitive/b_override.tf
@@ -0,0 +1,21 @@
+variable "false_true" {
+}
+
+variable "true_false" {
+}
+
+variable "false_false_true" {
+  sensitive = true
+}
+
+variable "true_true_false" {
+  sensitive = false
+}
+
+variable "false_true_false" {
+  sensitive = false
+}
+
+variable "true_false_true" {
+  sensitive = true
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-variable-sensitive/primary.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-variable-sensitive/primary.tf
new file mode 100644
index 0000000..eb79a6e
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-variable-sensitive/primary.tf
@@ -0,0 +1,23 @@
+variable "false_true" {
+  sensitive = false
+}
+
+variable "true_false" {
+  sensitive = true
+}
+
+variable "false_false_true" {
+  sensitive = false
+}
+
+variable "true_true_false" {
+  sensitive = true
+}
+
+variable "false_true_false" {
+  sensitive = false
+}
+
+variable "true_false_true" {
+  sensitive = true
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-variable/a_override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-variable/a_override.tf
new file mode 100644
index 0000000..6ec4d1e
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-variable/a_override.tf
@@ -0,0 +1,9 @@
+variable "fully_overridden" {
+  default = "a_override"
+  description = "a_override description"
+  type = string
+}
+
+variable "partially_overridden" {
+  default = "a_override partial"
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-variable/b_override.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-variable/b_override.tf
new file mode 100644
index 0000000..f09ce53
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-variable/b_override.tf
@@ -0,0 +1,10 @@
+variable "fully_overridden" {
+  nullable = false
+  default = "b_override"
+  description = "b_override description"
+  type = string
+}
+
+variable "partially_overridden" {
+  default = "b_override partial"
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/override-variable/primary.tf b/v1.5.7/internal/configs/testdata/valid-modules/override-variable/primary.tf
new file mode 100644
index 0000000..981b86b
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/override-variable/primary.tf
@@ -0,0 +1,11 @@
+variable "fully_overridden" {
+  default = "base"
+  description = "base description"
+  type = string
+}
+
+variable "partially_overridden" {
+  default = "base"
+  description = "base description"
+  type = string
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/provider-aliases/main.tf b/v1.5.7/internal/configs/testdata/valid-modules/provider-aliases/main.tf
new file mode 100644
index 0000000..dd9fb08
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/provider-aliases/main.tf
@@ -0,0 +1,17 @@
+terraform {
+  required_providers {
+    foo-test = {
+      source = "foo/test"
+      configuration_aliases = [foo-test.a, foo-test.b]
+    }
+  }
+}
+
+resource "test_instance" "explicit" {
+  provider = foo-test.a
+}
+
+data "test_resource" "explicit" {
+  provider = foo-test.b
+}
+
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/provider-meta/main.tf b/v1.5.7/internal/configs/testdata/valid-modules/provider-meta/main.tf
new file mode 100644
index 0000000..073e35b
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/provider-meta/main.tf
@@ -0,0 +1,5 @@
+terraform {
+  provider_meta "my-provider" {
+    hello = "test-module"
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/providers-fqns/main.tf b/v1.5.7/internal/configs/testdata/valid-modules/providers-fqns/main.tf
new file mode 100644
index 0000000..ed92c9a
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/providers-fqns/main.tf
@@ -0,0 +1,9 @@
+terraform {
+  required_providers {
+    foo-test = {
+      source = "foo/test"
+    }
+  }
+}
+
+provider "foo-test" {}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/required-providers-after-resource/main.tf b/v1.5.7/internal/configs/testdata/valid-modules/required-providers-after-resource/main.tf
new file mode 100644
index 0000000..8d40ec4
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/required-providers-after-resource/main.tf
@@ -0,0 +1,3 @@
+resource test_instance "my-instance" {
+  provider = test
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/required-providers-after-resource/providers.tf b/v1.5.7/internal/configs/testdata/valid-modules/required-providers-after-resource/providers.tf
new file mode 100644
index 0000000..687ef1b
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/required-providers-after-resource/providers.tf
@@ -0,0 +1,8 @@
+terraform {
+  required_providers {
+    test = {
+      source = "foo/test"
+      version = "~>1.0.0"
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/required-providers-overrides/bar_provider_override.tf b/v1.5.7/internal/configs/testdata/valid-modules/required-providers-overrides/bar_provider_override.tf
new file mode 100644
index 0000000..b83ef74
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/required-providers-overrides/bar_provider_override.tf
@@ -0,0 +1,9 @@
+terraform {
+  required_providers {
+    bar = {
+      source = "blorp/bar"
+      version = "~>2.0.0"
+    }
+  }
+}
+
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/required-providers-overrides/main.tf b/v1.5.7/internal/configs/testdata/valid-modules/required-providers-overrides/main.tf
new file mode 100644
index 0000000..f7e58f2
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/required-providers-overrides/main.tf
@@ -0,0 +1,7 @@
+resource bar_thing "bt" {
+  provider = bar
+}
+
+resource foo_thing "ft" {
+  provider = foo
+}
diff --git a/v1.5.7/internal/configs/testdata/valid-modules/required-providers-overrides/providers.tf b/v1.5.7/internal/configs/testdata/valid-modules/required-providers-overrides/providers.tf
new file mode 100644
index 0000000..9b1d897
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/valid-modules/required-providers-overrides/providers.tf
@@ -0,0 +1,11 @@
+terraform {
+  required_providers {
+    bar = {
+      source = "acme/bar"
+    }
+
+    foo = {
+      source = "acme/foo"
+    }
+  }
+}
diff --git a/v1.5.7/internal/configs/testdata/warning-files/depends_on.tf b/v1.5.7/internal/configs/testdata/warning-files/depends_on.tf
new file mode 100644
index 0000000..17e1bf3
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/warning-files/depends_on.tf
@@ -0,0 +1,6 @@
+resource "null_resource" "a" {
+}
+
+resource "null_resource" "b" {
+  depends_on = ["null_resource.a"] # WARNING: Quoted references are deprecated
+}
diff --git a/v1.5.7/internal/configs/testdata/warning-files/provider_ref.tf b/v1.5.7/internal/configs/testdata/warning-files/provider_ref.tf
new file mode 100644
index 0000000..6f5525e
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/warning-files/provider_ref.tf
@@ -0,0 +1,7 @@
+provider "null" {
+  alias = "foo"
+}
+
+resource "null_resource" "test" {
+  provider = "null.foo" # WARNING: Quoted references are deprecated
+}
diff --git a/v1.5.7/internal/configs/testdata/warning-files/provisioner_keyword.tf b/v1.5.7/internal/configs/testdata/warning-files/provisioner_keyword.tf
new file mode 100644
index 0000000..61fe72b
--- /dev/null
+++ b/v1.5.7/internal/configs/testdata/warning-files/provisioner_keyword.tf
@@ -0,0 +1,6 @@
+resource "null_resource" "a" {
+  provisioner "local-exec" {
+    when       = "create" # WARNING: Quoted keywords are deprecated
+    on_failure = "fail"   # WARNING: Quoted keywords are deprecated
+  }
+}
diff --git a/v1.5.7/internal/configs/util.go b/v1.5.7/internal/configs/util.go
new file mode 100644
index 0000000..c136c7e
--- /dev/null
+++ b/v1.5.7/internal/configs/util.go
@@ -0,0 +1,66 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+)
+
+// exprIsNativeQuotedString determines whether the given expression looks like
+// it's a quoted string in the HCL native syntax.
+//
+// This should be used sparingly only for situations where our legacy HCL
+// decoding would've expected a keyword or reference in quotes but our new
+// decoding expects the keyword or reference to be provided directly as
+// an identifier-based expression.
+func exprIsNativeQuotedString(expr hcl.Expression) bool {
+	_, ok := expr.(*hclsyntax.TemplateExpr)
+	return ok
+}
+
+// schemaForOverrides takes a *hcl.BodySchema and produces a new one that is
+// equivalent except that any required attributes are forced to not be required.
+//
+// This is useful for dealing with "override" config files, which are allowed
+// to omit things that they don't wish to override from the main configuration.
+//
+// The returned schema may have some pointers in common with the given schema,
+// so neither the given schema nor the returned schema should be modified after
+// using this function in order to avoid confusion.
+//
+// Overrides are rarely used, so it's recommended to just create the override
+// schema on the fly only when it's needed, rather than storing it in a global
+// variable as we tend to do for a primary schema.
+func schemaForOverrides(schema *hcl.BodySchema) *hcl.BodySchema {
+	ret := &hcl.BodySchema{
+		Attributes: make([]hcl.AttributeSchema, len(schema.Attributes)),
+		Blocks:     schema.Blocks,
+	}
+
+	for i, attrS := range schema.Attributes {
+		ret.Attributes[i] = attrS
+		ret.Attributes[i].Required = false
+	}
+
+	return ret
+}
+
+// schemaWithDynamic takes a *hcl.BodySchema and produces a new one that
+// is equivalent except that it accepts an additional block type "dynamic" with
+// a single label, used to recognize usage of the HCL dynamic block extension.
+func schemaWithDynamic(schema *hcl.BodySchema) *hcl.BodySchema {
+	ret := &hcl.BodySchema{
+		Attributes: schema.Attributes,
+		Blocks:     make([]hcl.BlockHeaderSchema, len(schema.Blocks), len(schema.Blocks)+1),
+	}
+
+	copy(ret.Blocks, schema.Blocks)
+	ret.Blocks = append(ret.Blocks, hcl.BlockHeaderSchema{
+		Type:       "dynamic",
+		LabelNames: []string{"type"},
+	})
+
+	return ret
+}
diff --git a/v1.5.7/internal/configs/variable_type_hint.go b/v1.5.7/internal/configs/variable_type_hint.go
new file mode 100644
index 0000000..800619d
--- /dev/null
+++ b/v1.5.7/internal/configs/variable_type_hint.go
@@ -0,0 +1,48 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+// VariableTypeHint is an enumeration used for the Variable.TypeHint field,
+// which is an incompletely-specified type for the variable which is used
+// as a hint for whether a value provided in an ambiguous context (on the
+// command line or in an environment variable) should be taken literally as a
+// string or parsed as an HCL expression to produce a data structure.
+//
+// The type hint is applied to runtime values as well, but since it does not
+// accurately describe a precise type it is not fully-sufficient to infer
+// the dynamic type of a value passed through a variable.
+//
+// These hints use inaccurate terminology for historical reasons. Full details
+// are in the documentation for each constant in this enumeration, but in
+// summary:
+//
+//   - TypeHintString requires a primitive type
+//   - TypeHintList requires a type that could be converted to a tuple
+//   - TypeHintMap requires a type that could be converted to an object
+type VariableTypeHint rune
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type VariableTypeHint
+
+// TypeHintNone indicates the absence of a type hint. Values specified in
+// ambiguous contexts will be treated as literal strings, as if TypeHintString
+// were selected, but no runtime value checks will be applied. This is reasonable
+// type hint for a module that is never intended to be used at the top-level
+// of a configuration, since descendent modules never receive values from
+// ambiguous contexts.
+const TypeHintNone VariableTypeHint = 0
+
+// TypeHintString spec indicates that a value provided in an ambiguous context
+// should be treated as a literal string, and additionally requires that the
+// runtime value for the variable is of a primitive type (string, number, bool).
+const TypeHintString VariableTypeHint = 'S'
+
+// TypeHintList indicates that a value provided in an ambiguous context should
+// be treated as an HCL expression, and additionally requires that the
+// runtime value for the variable is of an tuple, list, or set type.
+const TypeHintList VariableTypeHint = 'L'
+
+// TypeHintMap indicates that a value provided in an ambiguous context should
+// be treated as an HCL expression, and additionally requires that the
+// runtime value for the variable is of an object or map type.
+const TypeHintMap VariableTypeHint = 'M'
diff --git a/v1.5.7/internal/configs/variabletypehint_string.go b/v1.5.7/internal/configs/variabletypehint_string.go
new file mode 100644
index 0000000..2b50428
--- /dev/null
+++ b/v1.5.7/internal/configs/variabletypehint_string.go
@@ -0,0 +1,39 @@
+// Code generated by "stringer -type VariableTypeHint"; DO NOT EDIT.
+
+package configs
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[TypeHintNone-0]
+	_ = x[TypeHintString-83]
+	_ = x[TypeHintList-76]
+	_ = x[TypeHintMap-77]
+}
+
+const (
+	_VariableTypeHint_name_0 = "TypeHintNone"
+	_VariableTypeHint_name_1 = "TypeHintListTypeHintMap"
+	_VariableTypeHint_name_2 = "TypeHintString"
+)
+
+var (
+	_VariableTypeHint_index_1 = [...]uint8{0, 12, 23}
+)
+
+func (i VariableTypeHint) String() string {
+	switch {
+	case i == 0:
+		return _VariableTypeHint_name_0
+	case 76 <= i && i <= 77:
+		i -= 76
+		return _VariableTypeHint_name_1[_VariableTypeHint_index_1[i]:_VariableTypeHint_index_1[i+1]]
+	case i == 83:
+		return _VariableTypeHint_name_2
+	default:
+		return "VariableTypeHint(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/v1.5.7/internal/configs/version_constraint.go b/v1.5.7/internal/configs/version_constraint.go
new file mode 100644
index 0000000..5ae9b68
--- /dev/null
+++ b/v1.5.7/internal/configs/version_constraint.go
@@ -0,0 +1,74 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package configs
+
+import (
+	"fmt"
+
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/convert"
+)
+
+// VersionConstraint represents a version constraint on some resource
+// (e.g. Terraform Core, a provider, a module, ...) that carries with it
+// a source range so that a helpful diagnostic can be printed in the event
+// that a particular constraint does not match.
+type VersionConstraint struct {
+	Required  version.Constraints
+	DeclRange hcl.Range
+}
+
+func decodeVersionConstraint(attr *hcl.Attribute) (VersionConstraint, hcl.Diagnostics) {
+	ret := VersionConstraint{
+		DeclRange: attr.Range,
+	}
+
+	val, diags := attr.Expr.Value(nil)
+	if diags.HasErrors() {
+		return ret, diags
+	}
+	var err error
+	val, err = convert.Convert(val, cty.String)
+	if err != nil {
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid version constraint",
+			Detail:   fmt.Sprintf("A string value is required for %s.", attr.Name),
+			Subject:  attr.Expr.Range().Ptr(),
+		})
+		return ret, diags
+	}
+
+	if val.IsNull() {
+		// A null version constraint is strange, but we'll just treat it
+		// like an empty constraint set.
+		return ret, diags
+	}
+
+	if !val.IsWhollyKnown() {
+		// If there is a syntax error, HCL sets the value of the given attribute
+		// to cty.DynamicVal. A diagnostic for the syntax error will already
+		// bubble up, so we will move forward gracefully here.
+		return ret, diags
+	}
+
+	constraintStr := val.AsString()
+	constraints, err := version.NewConstraint(constraintStr)
+	if err != nil {
+		// NewConstraint doesn't return user-friendly errors, so we'll just
+		// ignore the provided error and produce our own generic one.
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid version constraint",
+			Detail:   "This string does not use correct version constraint syntax.", // Not very actionable :(
+			Subject:  attr.Expr.Range().Ptr(),
+		})
+		return ret, diags
+	}
+
+	ret.Required = constraints
+	return ret, diags
+}
diff --git a/v1.5.7/internal/copy/copy_dir.go b/v1.5.7/internal/copy/copy_dir.go
new file mode 100644
index 0000000..34e6907
--- /dev/null
+++ b/v1.5.7/internal/copy/copy_dir.go
@@ -0,0 +1,149 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package copy
+
+import (
+	"io"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+// CopyDir recursively copies all of the files within the directory given in
+// src to the directory given in dst.
+//
+// Both directories should already exist. If the destination directory is
+// non-empty then the new files will merge in with the old, overwriting any
+// files that have a relative path in common between source and destination.
+//
+// Recursive copying of directories is inevitably a rather opinionated sort of
+// operation, so this function won't be appropriate for all use-cases. Some
+// of the "opinions" it has are described in the following paragraphs:
+//
+// Symlinks in the source directory are recreated with the same target in the
+// destination directory. If the symlink is to a directory itself, that
+// directory is not recursively visited for further copying.
+//
+// File and directory modes are not preserved exactly, but the executable
+// flag is preserved for files on operating systems where it is significant.
+//
+// Any "dot files" it encounters along the way are skipped, even on platforms
+// that do not normally ascribe special meaning to files with names starting
+// with dots.
+//
+// Callers may rely on the above details and other undocumented details of
+// this function, so if you intend to change it be sure to review the callers
+// first and make sure they are compatible with the change you intend to make.
+func CopyDir(dst, src string) error {
+	src, err := filepath.EvalSymlinks(src)
+	if err != nil {
+		return err
+	}
+
+	walkFn := func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+
+		if path == src {
+			return nil
+		}
+
+		if strings.HasPrefix(filepath.Base(path), ".") {
+			// Skip any dot files
+			if info.IsDir() {
+				return filepath.SkipDir
+			} else {
+				return nil
+			}
+		}
+
+		// The "path" has the src prefixed to it. We need to join our
+		// destination with the path without the src on it.
+		dstPath := filepath.Join(dst, path[len(src):])
+
+		// we don't want to try and copy the same file over itself.
+		if eq, err := SameFile(path, dstPath); eq {
+			return nil
+		} else if err != nil {
+			return err
+		}
+
+		// If we have a directory, make that subdirectory, then continue
+		// the walk.
+		if info.IsDir() {
+			if path == filepath.Join(src, dst) {
+				// dst is in src; don't walk it.
+				return nil
+			}
+
+			if err := os.MkdirAll(dstPath, 0755); err != nil {
+				return err
+			}
+
+			return nil
+		}
+
+		// If the current path is a symlink, recreate the symlink relative to
+		// the dst directory
+		if info.Mode()&os.ModeSymlink == os.ModeSymlink {
+			target, err := os.Readlink(path)
+			if err != nil {
+				return err
+			}
+
+			return os.Symlink(target, dstPath)
+		}
+
+		// If we have a file, copy the contents.
+		srcF, err := os.Open(path)
+		if err != nil {
+			return err
+		}
+		defer srcF.Close()
+
+		dstF, err := os.Create(dstPath)
+		if err != nil {
+			return err
+		}
+		defer dstF.Close()
+
+		if _, err := io.Copy(dstF, srcF); err != nil {
+			return err
+		}
+
+		// Chmod it
+		return os.Chmod(dstPath, info.Mode())
+	}
+
+	return filepath.Walk(src, walkFn)
+}
+
+// SameFile returns true if the two given paths refer to the same physical
+// file on disk, using the unique file identifiers from the underlying
+// operating system. For example, on Unix systems this checks whether the
+// two files are on the same device and have the same inode.
+func SameFile(a, b string) (bool, error) {
+	if a == b {
+		return true, nil
+	}
+
+	aInfo, err := os.Lstat(a)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return false, nil
+		}
+		return false, err
+	}
+
+	bInfo, err := os.Lstat(b)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return false, nil
+		}
+		return false, err
+	}
+
+	return os.SameFile(aInfo, bInfo), nil
+}
diff --git a/v1.5.7/internal/copy/copy_dir_test.go b/v1.5.7/internal/copy/copy_dir_test.go
new file mode 100644
index 0000000..655adb7
--- /dev/null
+++ b/v1.5.7/internal/copy/copy_dir_test.go
@@ -0,0 +1,102 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package copy
+
+import (
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"testing"
+)
+
+// TestCopyDir_symlinks sets up a directory with two submodules,
+// one being a symlink to the other
+//
+// The resultant file structure is as follows:
+// 	├── modules
+//  │   ├── symlink-module -> test-module
+//  │   └── test-module
+//  │       └── main.tf
+//  └── target
+//     ├── symlink-module -> test-module
+//     └── test-module
+//         └── main.tf
+
+func TestCopyDir_symlinks(t *testing.T) {
+	tmpdir := t.TempDir()
+
+	moduleDir := filepath.Join(tmpdir, "modules")
+	err := os.Mkdir(moduleDir, os.ModePerm)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	subModuleDir := filepath.Join(moduleDir, "test-module")
+	err = os.Mkdir(subModuleDir, os.ModePerm)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = ioutil.WriteFile(filepath.Join(subModuleDir, "main.tf"), []byte("hello"), 0644)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = os.Symlink("test-module", filepath.Join(moduleDir, "symlink-module"))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	targetDir := filepath.Join(tmpdir, "target")
+	os.Mkdir(targetDir, os.ModePerm)
+
+	err = CopyDir(targetDir, moduleDir)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err = os.Lstat(filepath.Join(targetDir, "test-module", "main.tf")); os.IsNotExist(err) {
+		t.Fatal("target test-module/main.tf was not created")
+	}
+
+	if _, err = os.Lstat(filepath.Join(targetDir, "symlink-module", "main.tf")); os.IsNotExist(err) {
+		t.Fatal("target symlink-module/main.tf was not created")
+	}
+}
+
+func TestCopyDir_symlink_file(t *testing.T) {
+	tmpdir := t.TempDir()
+
+	moduleDir := filepath.Join(tmpdir, "modules")
+	err := os.Mkdir(moduleDir, os.ModePerm)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = ioutil.WriteFile(filepath.Join(moduleDir, "main.tf"), []byte("hello"), 0644)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = os.Symlink("main.tf", filepath.Join(moduleDir, "symlink.tf"))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	targetDir := filepath.Join(tmpdir, "target")
+	os.Mkdir(targetDir, os.ModePerm)
+
+	err = CopyDir(targetDir, moduleDir)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err = os.Lstat(filepath.Join(targetDir, "main.tf")); os.IsNotExist(err) {
+		t.Fatal("target/main.tf was not created")
+	}
+
+	if _, err = os.Lstat(filepath.Join(targetDir, "symlink.tf")); os.IsNotExist(err) {
+		t.Fatal("target/symlink.tf was not created")
+	}
+}
diff --git a/v1.5.7/internal/copy/copy_file.go b/v1.5.7/internal/copy/copy_file.go
new file mode 100644
index 0000000..a3fbb94
--- /dev/null
+++ b/v1.5.7/internal/copy/copy_file.go
@@ -0,0 +1,55 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package copy
+
+import (
+	"io"
+	"os"
+)
+
+// From: https://gist.github.com/m4ng0squ4sh/92462b38df26839a3ca324697c8cba04
+
+// CopyFile copies the contents of the file named src to the file named
+// by dst. The file will be created if it does not already exist. If the
+// destination file exists, all it's contents will be replaced by the contents
+// of the source file. The file mode will be copied from the source and
+// the copied data is synced/flushed to stable storage.
+func CopyFile(src, dst string) (err error) {
+	in, err := os.Open(src)
+	if err != nil {
+		return
+	}
+	defer in.Close()
+
+	out, err := os.Create(dst)
+	if err != nil {
+		return
+	}
+	defer func() {
+		if e := out.Close(); e != nil {
+			err = e
+		}
+	}()
+
+	_, err = io.Copy(out, in)
+	if err != nil {
+		return
+	}
+
+	err = out.Sync()
+	if err != nil {
+		return
+	}
+
+	si, err := os.Stat(src)
+	if err != nil {
+		return
+	}
+	err = os.Chmod(dst, si.Mode())
+	if err != nil {
+		return
+	}
+
+	return
+}
diff --git a/v1.5.7/internal/dag/dag.go b/v1.5.7/internal/dag/dag.go
new file mode 100644
index 0000000..1fedb93
--- /dev/null
+++ b/v1.5.7/internal/dag/dag.go
@@ -0,0 +1,372 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+import (
+	"fmt"
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+
+	"github.com/hashicorp/go-multierror"
+)
+
+// AcyclicGraph is a specialization of Graph that cannot have cycles.
+type AcyclicGraph struct {
+	Graph
+}
+
+// WalkFunc is the callback used for walking the graph.
+type WalkFunc func(Vertex) tfdiags.Diagnostics
+
+// DepthWalkFunc is a walk function that also receives the current depth of the
+// walk as an argument
+type DepthWalkFunc func(Vertex, int) error
+
+func (g *AcyclicGraph) DirectedGraph() Grapher {
+	return g
+}
+
+// Returns a Set that includes every Vertex yielded by walking down from the
+// provided starting Vertex v.
+func (g *AcyclicGraph) Ancestors(v Vertex) (Set, error) {
+	s := make(Set)
+	memoFunc := func(v Vertex, d int) error {
+		s.Add(v)
+		return nil
+	}
+
+	if err := g.DepthFirstWalk(g.downEdgesNoCopy(v), memoFunc); err != nil {
+		return nil, err
+	}
+
+	return s, nil
+}
+
+// Returns a Set that includes every Vertex yielded by walking up from the
+// provided starting Vertex v.
+func (g *AcyclicGraph) Descendents(v Vertex) (Set, error) {
+	s := make(Set)
+	memoFunc := func(v Vertex, d int) error {
+		s.Add(v)
+		return nil
+	}
+
+	if err := g.ReverseDepthFirstWalk(g.upEdgesNoCopy(v), memoFunc); err != nil {
+		return nil, err
+	}
+
+	return s, nil
+}
+
+// Root returns the root of the DAG, or an error.
+//
+// Complexity: O(V)
+func (g *AcyclicGraph) Root() (Vertex, error) {
+	roots := make([]Vertex, 0, 1)
+	for _, v := range g.Vertices() {
+		if g.upEdgesNoCopy(v).Len() == 0 {
+			roots = append(roots, v)
+		}
+	}
+
+	if len(roots) > 1 {
+		// TODO(mitchellh): make this error message a lot better
+		return nil, fmt.Errorf("multiple roots: %#v", roots)
+	}
+
+	if len(roots) == 0 {
+		return nil, fmt.Errorf("no roots found")
+	}
+
+	return roots[0], nil
+}
+
+// TransitiveReduction performs the transitive reduction of graph g in place.
+// The transitive reduction of a graph is a graph with as few edges as
+// possible with the same reachability as the original graph. This means
+// that if there are three nodes A => B => C, and A connects to both
+// B and C, and B connects to C, then the transitive reduction is the
+// same graph with only a single edge between A and B, and a single edge
+// between B and C.
+//
+// The graph must be free of cycles for this operation to behave properly.
+//
+// Complexity: O(V(V+E)), or asymptotically O(VE)
+func (g *AcyclicGraph) TransitiveReduction() {
+	// For each vertex u in graph g, do a DFS starting from each vertex
+	// v such that the edge (u,v) exists (v is a direct descendant of u).
+	//
+	// For each v-prime reachable from v, remove the edge (u, v-prime).
+	for _, u := range g.Vertices() {
+		uTargets := g.downEdgesNoCopy(u)
+
+		g.DepthFirstWalk(g.downEdgesNoCopy(u), func(v Vertex, d int) error {
+			shared := uTargets.Intersection(g.downEdgesNoCopy(v))
+			for _, vPrime := range shared {
+				g.RemoveEdge(BasicEdge(u, vPrime))
+			}
+
+			return nil
+		})
+	}
+}
+
+// Validate validates the DAG. A DAG is valid if it has a single root
+// with no cycles.
+func (g *AcyclicGraph) Validate() error {
+	if _, err := g.Root(); err != nil {
+		return err
+	}
+
+	// Look for cycles of more than 1 component
+	var err error
+	cycles := g.Cycles()
+	if len(cycles) > 0 {
+		for _, cycle := range cycles {
+			cycleStr := make([]string, len(cycle))
+			for j, vertex := range cycle {
+				cycleStr[j] = VertexName(vertex)
+			}
+
+			err = multierror.Append(err, fmt.Errorf(
+				"Cycle: %s", strings.Join(cycleStr, ", ")))
+		}
+	}
+
+	// Look for cycles to self
+	for _, e := range g.Edges() {
+		if e.Source() == e.Target() {
+			err = multierror.Append(err, fmt.Errorf(
+				"Self reference: %s", VertexName(e.Source())))
+		}
+	}
+
+	return err
+}
+
+// Cycles reports any cycles between graph nodes.
+// Self-referencing nodes are not reported, and must be detected separately.
+func (g *AcyclicGraph) Cycles() [][]Vertex {
+	var cycles [][]Vertex
+	for _, cycle := range StronglyConnected(&g.Graph) {
+		if len(cycle) > 1 {
+			cycles = append(cycles, cycle)
+		}
+	}
+	return cycles
+}
+
+// Walk walks the graph, calling your callback as each node is visited.
+// This will walk nodes in parallel if it can. The resulting diagnostics
+// contains problems from all graphs visited, in no particular order.
+func (g *AcyclicGraph) Walk(cb WalkFunc) tfdiags.Diagnostics {
+	w := &Walker{Callback: cb, Reverse: true}
+	w.Update(g)
+	return w.Wait()
+}
+
+// simple convenience helper for converting a dag.Set to a []Vertex
+func AsVertexList(s Set) []Vertex {
+	vertexList := make([]Vertex, 0, len(s))
+	for _, raw := range s {
+		vertexList = append(vertexList, raw.(Vertex))
+	}
+	return vertexList
+}
+
+type vertexAtDepth struct {
+	Vertex Vertex
+	Depth  int
+}
+
+// TopologicalOrder returns a topological sort of the given graph, with source
+// vertices ordered before the targets of their edges. The nodes are not sorted,
+// and any valid order may be returned. This function will panic if it
+// encounters a cycle.
+func (g *AcyclicGraph) TopologicalOrder() []Vertex {
+	return g.topoOrder(upOrder)
+}
+
+// ReverseTopologicalOrder returns a topological sort of the given graph, with
+// target vertices ordered before the sources of their edges. The nodes are not
+// sorted, and any valid order may be returned. This function will panic if it
+// encounters a cycle.
+func (g *AcyclicGraph) ReverseTopologicalOrder() []Vertex {
+	return g.topoOrder(downOrder)
+}
+
+func (g *AcyclicGraph) topoOrder(order walkType) []Vertex {
+	// Use a dfs-based sorting algorithm, similar to that used in
+	// TransitiveReduction.
+	sorted := make([]Vertex, 0, len(g.vertices))
+
+	// tmp track the current working node to check for cycles
+	tmp := map[Vertex]bool{}
+
+	// perm tracks completed nodes to end the recursion
+	perm := map[Vertex]bool{}
+
+	var visit func(v Vertex)
+
+	visit = func(v Vertex) {
+		if perm[v] {
+			return
+		}
+
+		if tmp[v] {
+			panic("cycle found in dag")
+		}
+
+		tmp[v] = true
+		var next Set
+		switch {
+		case order&downOrder != 0:
+			next = g.downEdgesNoCopy(v)
+		case order&upOrder != 0:
+			next = g.upEdgesNoCopy(v)
+		default:
+			panic(fmt.Sprintln("invalid order", order))
+		}
+
+		for _, u := range next {
+			visit(u)
+		}
+
+		tmp[v] = false
+		perm[v] = true
+		sorted = append(sorted, v)
+	}
+
+	for _, v := range g.Vertices() {
+		visit(v)
+	}
+
+	return sorted
+}
+
+type walkType uint64
+
+const (
+	depthFirst walkType = 1 << iota
+	breadthFirst
+	downOrder
+	upOrder
+)
+
+// DepthFirstWalk does a depth-first walk of the graph starting from
+// the vertices in start.
+func (g *AcyclicGraph) DepthFirstWalk(start Set, f DepthWalkFunc) error {
+	return g.walk(depthFirst|downOrder, false, start, f)
+}
+
+// ReverseDepthFirstWalk does a depth-first walk _up_ the graph starting from
+// the vertices in start.
+func (g *AcyclicGraph) ReverseDepthFirstWalk(start Set, f DepthWalkFunc) error {
+	return g.walk(depthFirst|upOrder, false, start, f)
+}
+
+// BreadthFirstWalk does a breadth-first walk of the graph starting from
+// the vertices in start.
+func (g *AcyclicGraph) BreadthFirstWalk(start Set, f DepthWalkFunc) error {
+	return g.walk(breadthFirst|downOrder, false, start, f)
+}
+
+// ReverseBreadthFirstWalk does a breadth-first walk _up_ the graph starting from
+// the vertices in start.
+func (g *AcyclicGraph) ReverseBreadthFirstWalk(start Set, f DepthWalkFunc) error {
+	return g.walk(breadthFirst|upOrder, false, start, f)
+}
+
+// Setting test to true will walk sets of vertices in sorted order for
+// deterministic testing.
+func (g *AcyclicGraph) walk(order walkType, test bool, start Set, f DepthWalkFunc) error {
+	seen := make(map[Vertex]struct{})
+	frontier := make([]vertexAtDepth, 0, len(start))
+	for _, v := range start {
+		frontier = append(frontier, vertexAtDepth{
+			Vertex: v,
+			Depth:  0,
+		})
+	}
+
+	if test {
+		testSortFrontier(frontier)
+	}
+
+	for len(frontier) > 0 {
+		// Pop the current vertex
+		var current vertexAtDepth
+
+		switch {
+		case order&depthFirst != 0:
+			// depth first, the frontier is used like a stack
+			n := len(frontier)
+			current = frontier[n-1]
+			frontier = frontier[:n-1]
+		case order&breadthFirst != 0:
+			// breadth first, the frontier is used like a queue
+			current = frontier[0]
+			frontier = frontier[1:]
+		default:
+			panic(fmt.Sprint("invalid visit order", order))
+		}
+
+		// Check if we've seen this already and return...
+		if _, ok := seen[current.Vertex]; ok {
+			continue
+		}
+		seen[current.Vertex] = struct{}{}
+
+		// Visit the current node
+		if err := f(current.Vertex, current.Depth); err != nil {
+			return err
+		}
+
+		var edges Set
+		switch {
+		case order&downOrder != 0:
+			edges = g.downEdgesNoCopy(current.Vertex)
+		case order&upOrder != 0:
+			edges = g.upEdgesNoCopy(current.Vertex)
+		default:
+			panic(fmt.Sprint("invalid walk order", order))
+		}
+
+		if test {
+			frontier = testAppendNextSorted(frontier, edges, current.Depth+1)
+		} else {
+			frontier = appendNext(frontier, edges, current.Depth+1)
+		}
+	}
+	return nil
+}
+
+func appendNext(frontier []vertexAtDepth, next Set, depth int) []vertexAtDepth {
+	for _, v := range next {
+		frontier = append(frontier, vertexAtDepth{
+			Vertex: v,
+			Depth:  depth,
+		})
+	}
+	return frontier
+}
+
+func testAppendNextSorted(frontier []vertexAtDepth, edges Set, depth int) []vertexAtDepth {
+	var newEdges []vertexAtDepth
+	for _, v := range edges {
+		newEdges = append(newEdges, vertexAtDepth{
+			Vertex: v,
+			Depth:  depth,
+		})
+	}
+	testSortFrontier(newEdges)
+	return append(frontier, newEdges...)
+}
+func testSortFrontier(f []vertexAtDepth) {
+	sort.Slice(f, func(i, j int) bool {
+		return VertexName(f[i].Vertex) < VertexName(f[j].Vertex)
+	})
+}
diff --git a/v1.5.7/internal/dag/dag_test.go b/v1.5.7/internal/dag/dag_test.go
new file mode 100644
index 0000000..aaf7d80
--- /dev/null
+++ b/v1.5.7/internal/dag/dag_test.go
@@ -0,0 +1,585 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+import (
+	"flag"
+	"fmt"
+	"os"
+	"reflect"
+	"strconv"
+	"strings"
+	"sync"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+
+	_ "github.com/hashicorp/terraform/internal/logging"
+)
+
+func TestMain(m *testing.M) {
+	flag.Parse()
+	os.Exit(m.Run())
+}
+
+func TestAcyclicGraphRoot(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(3, 2))
+	g.Connect(BasicEdge(3, 1))
+
+	if root, err := g.Root(); err != nil {
+		t.Fatalf("err: %s", err)
+	} else if root != 3 {
+		t.Fatalf("bad: %#v", root)
+	}
+}
+
+func TestAcyclicGraphRoot_cycle(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(1, 2))
+	g.Connect(BasicEdge(2, 3))
+	g.Connect(BasicEdge(3, 1))
+
+	if _, err := g.Root(); err == nil {
+		t.Fatal("should error")
+	}
+}
+
+func TestAcyclicGraphRoot_multiple(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(3, 2))
+
+	if _, err := g.Root(); err == nil {
+		t.Fatal("should error")
+	}
+}
+
+func TestAyclicGraphTransReduction(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(1, 2))
+	g.Connect(BasicEdge(1, 3))
+	g.Connect(BasicEdge(2, 3))
+	g.TransitiveReduction()
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testGraphTransReductionStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+func TestAyclicGraphTransReduction_more(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Add(4)
+	g.Connect(BasicEdge(1, 2))
+	g.Connect(BasicEdge(1, 3))
+	g.Connect(BasicEdge(1, 4))
+	g.Connect(BasicEdge(2, 3))
+	g.Connect(BasicEdge(2, 4))
+	g.Connect(BasicEdge(3, 4))
+	g.TransitiveReduction()
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testGraphTransReductionMoreStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+func TestAyclicGraphTransReduction_multipleRoots(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Add(4)
+	g.Connect(BasicEdge(1, 2))
+	g.Connect(BasicEdge(1, 3))
+	g.Connect(BasicEdge(1, 4))
+	g.Connect(BasicEdge(2, 3))
+	g.Connect(BasicEdge(2, 4))
+	g.Connect(BasicEdge(3, 4))
+
+	g.Add(5)
+	g.Add(6)
+	g.Add(7)
+	g.Add(8)
+	g.Connect(BasicEdge(5, 6))
+	g.Connect(BasicEdge(5, 7))
+	g.Connect(BasicEdge(5, 8))
+	g.Connect(BasicEdge(6, 7))
+	g.Connect(BasicEdge(6, 8))
+	g.Connect(BasicEdge(7, 8))
+	g.TransitiveReduction()
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testGraphTransReductionMultipleRootsStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+// use this to simulate slow sort operations
+type counter struct {
+	Name  string
+	Calls int64
+}
+
+func (s *counter) String() string {
+	s.Calls++
+	return s.Name
+}
+
+// Make sure we can reduce a sizable, fully-connected graph.
+func TestAyclicGraphTransReduction_fullyConnected(t *testing.T) {
+	var g AcyclicGraph
+
+	const nodeCount = 200
+	nodes := make([]*counter, nodeCount)
+	for i := 0; i < nodeCount; i++ {
+		nodes[i] = &counter{Name: strconv.Itoa(i)}
+	}
+
+	// Add them all to the graph
+	for _, n := range nodes {
+		g.Add(n)
+	}
+
+	// connect them all
+	for i := range nodes {
+		for j := range nodes {
+			if i == j {
+				continue
+			}
+			g.Connect(BasicEdge(nodes[i], nodes[j]))
+		}
+	}
+
+	g.TransitiveReduction()
+
+	vertexNameCalls := int64(0)
+	for _, n := range nodes {
+		vertexNameCalls += n.Calls
+	}
+
+	switch {
+	case vertexNameCalls > 2*nodeCount:
+		// Make calling it more the 2x per node fatal.
+		// If we were sorting this would give us roughly ln(n)(n^3) calls, or
+		// >59000000 calls for 200 vertices.
+		t.Fatalf("VertexName called %d times", vertexNameCalls)
+	case vertexNameCalls > 0:
+		// we don't expect any calls, but a change here isn't necessarily fatal
+		t.Logf("WARNING: VertexName called %d times", vertexNameCalls)
+	}
+}
+
+func TestAcyclicGraphValidate(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(3, 2))
+	g.Connect(BasicEdge(3, 1))
+
+	if err := g.Validate(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+}
+
+func TestAcyclicGraphValidate_cycle(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(3, 2))
+	g.Connect(BasicEdge(3, 1))
+	g.Connect(BasicEdge(1, 2))
+	g.Connect(BasicEdge(2, 1))
+
+	if err := g.Validate(); err == nil {
+		t.Fatal("should error")
+	}
+}
+
+func TestAcyclicGraphValidate_cycleSelf(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Connect(BasicEdge(1, 1))
+
+	if err := g.Validate(); err == nil {
+		t.Fatal("should error")
+	}
+}
+
+func TestAcyclicGraphAncestors(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Add(4)
+	g.Add(5)
+	g.Connect(BasicEdge(0, 1))
+	g.Connect(BasicEdge(1, 2))
+	g.Connect(BasicEdge(2, 3))
+	g.Connect(BasicEdge(3, 4))
+	g.Connect(BasicEdge(4, 5))
+
+	actual, err := g.Ancestors(2)
+	if err != nil {
+		t.Fatalf("err: %#v", err)
+	}
+
+	expected := []Vertex{3, 4, 5}
+
+	if actual.Len() != len(expected) {
+		t.Fatalf("bad length! expected %#v to have len %d", actual, len(expected))
+	}
+
+	for _, e := range expected {
+		if !actual.Include(e) {
+			t.Fatalf("expected: %#v to include: %#v", expected, actual)
+		}
+	}
+}
+
+func TestAcyclicGraphDescendents(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Add(4)
+	g.Add(5)
+	g.Connect(BasicEdge(0, 1))
+	g.Connect(BasicEdge(1, 2))
+	g.Connect(BasicEdge(2, 3))
+	g.Connect(BasicEdge(3, 4))
+	g.Connect(BasicEdge(4, 5))
+
+	actual, err := g.Descendents(2)
+	if err != nil {
+		t.Fatalf("err: %#v", err)
+	}
+
+	expected := []Vertex{0, 1}
+
+	if actual.Len() != len(expected) {
+		t.Fatalf("bad length! expected %#v to have len %d", actual, len(expected))
+	}
+
+	for _, e := range expected {
+		if !actual.Include(e) {
+			t.Fatalf("expected: %#v to include: %#v", expected, actual)
+		}
+	}
+}
+
+func TestAcyclicGraphWalk(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(3, 2))
+	g.Connect(BasicEdge(3, 1))
+
+	var visits []Vertex
+	var lock sync.Mutex
+	err := g.Walk(func(v Vertex) tfdiags.Diagnostics {
+		lock.Lock()
+		defer lock.Unlock()
+		visits = append(visits, v)
+		return nil
+	})
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := [][]Vertex{
+		{1, 2, 3},
+		{2, 1, 3},
+	}
+	for _, e := range expected {
+		if reflect.DeepEqual(visits, e) {
+			return
+		}
+	}
+
+	t.Fatalf("bad: %#v", visits)
+}
+
+func TestAcyclicGraphWalk_error(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Add(4)
+	g.Connect(BasicEdge(4, 3))
+	g.Connect(BasicEdge(3, 2))
+	g.Connect(BasicEdge(2, 1))
+
+	var visits []Vertex
+	var lock sync.Mutex
+	err := g.Walk(func(v Vertex) tfdiags.Diagnostics {
+		lock.Lock()
+		defer lock.Unlock()
+
+		var diags tfdiags.Diagnostics
+
+		if v == 2 {
+			diags = diags.Append(fmt.Errorf("error"))
+			return diags
+		}
+
+		visits = append(visits, v)
+		return diags
+	})
+	if err == nil {
+		t.Fatal("should error")
+	}
+
+	expected := []Vertex{1}
+	if !reflect.DeepEqual(visits, expected) {
+		t.Errorf("wrong visits\ngot:  %#v\nwant: %#v", visits, expected)
+	}
+
+}
+
+func BenchmarkDAG(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		count := 150
+		b.StopTimer()
+		g := &AcyclicGraph{}
+
+		// create 4 layers of fully connected nodes
+		// layer A
+		for i := 0; i < count; i++ {
+			g.Add(fmt.Sprintf("A%d", i))
+		}
+
+		// layer B
+		for i := 0; i < count; i++ {
+			B := fmt.Sprintf("B%d", i)
+			g.Add(B)
+			for j := 0; j < count; j++ {
+				g.Connect(BasicEdge(B, fmt.Sprintf("A%d", j)))
+			}
+		}
+
+		// layer C
+		for i := 0; i < count; i++ {
+			c := fmt.Sprintf("C%d", i)
+			g.Add(c)
+			for j := 0; j < count; j++ {
+				// connect them to previous layers so we have something that requires reduction
+				g.Connect(BasicEdge(c, fmt.Sprintf("A%d", j)))
+				g.Connect(BasicEdge(c, fmt.Sprintf("B%d", j)))
+			}
+		}
+
+		// layer D
+		for i := 0; i < count; i++ {
+			d := fmt.Sprintf("D%d", i)
+			g.Add(d)
+			for j := 0; j < count; j++ {
+				g.Connect(BasicEdge(d, fmt.Sprintf("A%d", j)))
+				g.Connect(BasicEdge(d, fmt.Sprintf("B%d", j)))
+				g.Connect(BasicEdge(d, fmt.Sprintf("C%d", j)))
+			}
+		}
+
+		b.StartTimer()
+		// Find dependencies for every node
+		for _, v := range g.Vertices() {
+			_, err := g.Ancestors(v)
+			if err != nil {
+				b.Fatal(err)
+			}
+		}
+
+		// reduce the final graph
+		g.TransitiveReduction()
+	}
+}
+
+func TestAcyclicGraphWalkOrder(t *testing.T) {
+	/* Sample dependency graph,
+	   all edges pointing downwards.
+	       1    2
+	      / \  /  \
+	     3    4    5
+	    /      \  /
+	   6         7
+	           / | \
+	          8  9  10
+	           \ | /
+	             11
+	*/
+
+	var g AcyclicGraph
+	for i := 1; i <= 11; i++ {
+		g.Add(i)
+	}
+	g.Connect(BasicEdge(1, 3))
+	g.Connect(BasicEdge(1, 4))
+	g.Connect(BasicEdge(2, 4))
+	g.Connect(BasicEdge(2, 5))
+	g.Connect(BasicEdge(3, 6))
+	g.Connect(BasicEdge(4, 7))
+	g.Connect(BasicEdge(5, 7))
+	g.Connect(BasicEdge(7, 8))
+	g.Connect(BasicEdge(7, 9))
+	g.Connect(BasicEdge(7, 10))
+	g.Connect(BasicEdge(8, 11))
+	g.Connect(BasicEdge(9, 11))
+	g.Connect(BasicEdge(10, 11))
+
+	start := make(Set)
+	start.Add(2)
+	start.Add(1)
+	reverse := make(Set)
+	reverse.Add(11)
+	reverse.Add(6)
+
+	t.Run("DepthFirst", func(t *testing.T) {
+		var visits []vertexAtDepth
+		g.walk(depthFirst|downOrder, true, start, func(v Vertex, d int) error {
+			visits = append(visits, vertexAtDepth{v, d})
+			return nil
+
+		})
+		expect := []vertexAtDepth{
+			{2, 0}, {5, 1}, {7, 2}, {9, 3}, {11, 4}, {8, 3}, {10, 3}, {4, 1}, {1, 0}, {3, 1}, {6, 2},
+		}
+		if !reflect.DeepEqual(visits, expect) {
+			t.Errorf("expected visits:\n%v\ngot:\n%v\n", expect, visits)
+		}
+	})
+	t.Run("ReverseDepthFirst", func(t *testing.T) {
+		var visits []vertexAtDepth
+		g.walk(depthFirst|upOrder, true, reverse, func(v Vertex, d int) error {
+			visits = append(visits, vertexAtDepth{v, d})
+			return nil
+
+		})
+		expect := []vertexAtDepth{
+			{6, 0}, {3, 1}, {1, 2}, {11, 0}, {9, 1}, {7, 2}, {5, 3}, {2, 4}, {4, 3}, {8, 1}, {10, 1},
+		}
+		if !reflect.DeepEqual(visits, expect) {
+			t.Errorf("expected visits:\n%v\ngot:\n%v\n", expect, visits)
+		}
+	})
+	t.Run("BreadthFirst", func(t *testing.T) {
+		var visits []vertexAtDepth
+		g.walk(breadthFirst|downOrder, true, start, func(v Vertex, d int) error {
+			visits = append(visits, vertexAtDepth{v, d})
+			return nil
+
+		})
+		expect := []vertexAtDepth{
+			{1, 0}, {2, 0}, {3, 1}, {4, 1}, {5, 1}, {6, 2}, {7, 2}, {10, 3}, {8, 3}, {9, 3}, {11, 4},
+		}
+		if !reflect.DeepEqual(visits, expect) {
+			t.Errorf("expected visits:\n%v\ngot:\n%v\n", expect, visits)
+		}
+	})
+	t.Run("ReverseBreadthFirst", func(t *testing.T) {
+		var visits []vertexAtDepth
+		g.walk(breadthFirst|upOrder, true, reverse, func(v Vertex, d int) error {
+			visits = append(visits, vertexAtDepth{v, d})
+			return nil
+
+		})
+		expect := []vertexAtDepth{
+			{11, 0}, {6, 0}, {10, 1}, {8, 1}, {9, 1}, {3, 1}, {7, 2}, {1, 2}, {4, 3}, {5, 3}, {2, 4},
+		}
+		if !reflect.DeepEqual(visits, expect) {
+			t.Errorf("expected visits:\n%v\ngot:\n%v\n", expect, visits)
+		}
+	})
+
+	t.Run("TopologicalOrder", func(t *testing.T) {
+		order := g.topoOrder(downOrder)
+
+		// Validate the order by checking it against the initial graph. We only
+		// need to verify that each node has it's direct dependencies
+		// satisfied.
+		completed := map[Vertex]bool{}
+		for _, v := range order {
+			deps := g.DownEdges(v)
+			for _, dep := range deps {
+				if !completed[dep] {
+					t.Fatalf("walking node %v, but dependency %v was not yet seen", v, dep)
+				}
+			}
+			completed[v] = true
+		}
+	})
+	t.Run("ReverseTopologicalOrder", func(t *testing.T) {
+		order := g.topoOrder(upOrder)
+
+		// Validate the order by checking it against the initial graph. We only
+		// need to verify that each node has it's direct dependencies
+		// satisfied.
+		completed := map[Vertex]bool{}
+		for _, v := range order {
+			deps := g.UpEdges(v)
+			for _, dep := range deps {
+				if !completed[dep] {
+					t.Fatalf("walking node %v, but dependency %v was not yet seen", v, dep)
+				}
+			}
+			completed[v] = true
+		}
+	})
+}
+
+const testGraphTransReductionStr = `
+1
+  2
+2
+  3
+3
+`
+
+const testGraphTransReductionMoreStr = `
+1
+  2
+2
+  3
+3
+  4
+4
+`
+
+const testGraphTransReductionMultipleRootsStr = `
+1
+  2
+2
+  3
+3
+  4
+4
+5
+  6
+6
+  7
+7
+  8
+8
+`
diff --git a/v1.5.7/internal/dag/dot.go b/v1.5.7/internal/dag/dot.go
new file mode 100644
index 0000000..af4671b
--- /dev/null
+++ b/v1.5.7/internal/dag/dot.go
@@ -0,0 +1,285 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+import (
+	"bytes"
+	"fmt"
+	"sort"
+	"strings"
+)
+
+// DotOpts are the options for generating a dot formatted Graph.
+type DotOpts struct {
+	// Allows some nodes to decide to only show themselves when the user has
+	// requested the "verbose" graph.
+	Verbose bool
+
+	// Highlight Cycles
+	DrawCycles bool
+
+	// How many levels to expand modules as we draw
+	MaxDepth int
+
+	// use this to keep the cluster_ naming convention from the previous dot writer
+	cluster bool
+}
+
+// GraphNodeDotter can be implemented by a node to cause it to be included
+// in the dot graph. The Dot method will be called which is expected to
+// return a representation of this node.
+type GraphNodeDotter interface {
+	// Dot is called to return the dot formatting for the node.
+	// The first parameter is the title of the node.
+	// The second parameter includes user-specified options that affect the dot
+	// graph. See GraphDotOpts below for details.
+	DotNode(string, *DotOpts) *DotNode
+}
+
+// DotNode provides a structure for Vertices to return in order to specify their
+// dot format.
+type DotNode struct {
+	Name  string
+	Attrs map[string]string
+}
+
+// Returns the DOT representation of this Graph.
+func (g *marshalGraph) Dot(opts *DotOpts) []byte {
+	if opts == nil {
+		opts = &DotOpts{
+			DrawCycles: true,
+			MaxDepth:   -1,
+			Verbose:    true,
+		}
+	}
+
+	var w indentWriter
+	w.WriteString("digraph {\n")
+	w.Indent()
+
+	// some dot defaults
+	w.WriteString(`compound = "true"` + "\n")
+	w.WriteString(`newrank = "true"` + "\n")
+
+	// the top level graph is written as the first subgraph
+	w.WriteString(`subgraph "root" {` + "\n")
+	g.writeBody(opts, &w)
+
+	// cluster isn't really used other than for naming purposes in some graphs
+	opts.cluster = opts.MaxDepth != 0
+	maxDepth := opts.MaxDepth
+	if maxDepth == 0 {
+		maxDepth = -1
+	}
+
+	for _, s := range g.Subgraphs {
+		g.writeSubgraph(s, opts, maxDepth, &w)
+	}
+
+	w.Unindent()
+	w.WriteString("}\n")
+	return w.Bytes()
+}
+
+func (v *marshalVertex) dot(g *marshalGraph, opts *DotOpts) []byte {
+	var buf bytes.Buffer
+	graphName := g.Name
+	if graphName == "" {
+		graphName = "root"
+	}
+
+	name := v.Name
+	attrs := v.Attrs
+	if v.graphNodeDotter != nil {
+		node := v.graphNodeDotter.DotNode(name, opts)
+		if node == nil {
+			return []byte{}
+		}
+
+		newAttrs := make(map[string]string)
+		for k, v := range attrs {
+			newAttrs[k] = v
+		}
+		for k, v := range node.Attrs {
+			newAttrs[k] = v
+		}
+
+		name = node.Name
+		attrs = newAttrs
+	}
+
+	buf.WriteString(fmt.Sprintf(`"[%s] %s"`, graphName, name))
+	writeAttrs(&buf, attrs)
+	buf.WriteByte('\n')
+
+	return buf.Bytes()
+}
+
+func (e *marshalEdge) dot(g *marshalGraph) string {
+	var buf bytes.Buffer
+	graphName := g.Name
+	if graphName == "" {
+		graphName = "root"
+	}
+
+	sourceName := g.vertexByID(e.Source).Name
+	targetName := g.vertexByID(e.Target).Name
+	s := fmt.Sprintf(`"[%s] %s" -> "[%s] %s"`, graphName, sourceName, graphName, targetName)
+	buf.WriteString(s)
+	writeAttrs(&buf, e.Attrs)
+
+	return buf.String()
+}
+
+func cycleDot(e *marshalEdge, g *marshalGraph) string {
+	return e.dot(g) + ` [color = "red", penwidth = "2.0"]`
+}
+
+// Write the subgraph body. The is recursive, and the depth argument is used to
+// record the current depth of iteration.
+func (g *marshalGraph) writeSubgraph(sg *marshalGraph, opts *DotOpts, depth int, w *indentWriter) {
+	if depth == 0 {
+		return
+	}
+	depth--
+
+	name := sg.Name
+	if opts.cluster {
+		// we prefix with cluster_ to match the old dot output
+		name = "cluster_" + name
+		sg.Attrs["label"] = sg.Name
+	}
+	w.WriteString(fmt.Sprintf("subgraph %q {\n", name))
+	sg.writeBody(opts, w)
+
+	for _, sg := range sg.Subgraphs {
+		g.writeSubgraph(sg, opts, depth, w)
+	}
+}
+
+func (g *marshalGraph) writeBody(opts *DotOpts, w *indentWriter) {
+	w.Indent()
+
+	for _, as := range attrStrings(g.Attrs) {
+		w.WriteString(as + "\n")
+	}
+
+	// list of Vertices that aren't to be included in the dot output
+	skip := map[string]bool{}
+
+	for _, v := range g.Vertices {
+		if v.graphNodeDotter == nil {
+			skip[v.ID] = true
+			continue
+		}
+
+		w.Write(v.dot(g, opts))
+	}
+
+	var dotEdges []string
+
+	if opts.DrawCycles {
+		for _, c := range g.Cycles {
+			if len(c) < 2 {
+				continue
+			}
+
+			for i, j := 0, 1; i < len(c); i, j = i+1, j+1 {
+				if j >= len(c) {
+					j = 0
+				}
+				src := c[i]
+				tgt := c[j]
+
+				if skip[src.ID] || skip[tgt.ID] {
+					continue
+				}
+
+				e := &marshalEdge{
+					Name:   fmt.Sprintf("%s|%s", src.Name, tgt.Name),
+					Source: src.ID,
+					Target: tgt.ID,
+					Attrs:  make(map[string]string),
+				}
+
+				dotEdges = append(dotEdges, cycleDot(e, g))
+				src = tgt
+			}
+		}
+	}
+
+	for _, e := range g.Edges {
+		dotEdges = append(dotEdges, e.dot(g))
+	}
+
+	// srot these again to match the old output
+	sort.Strings(dotEdges)
+
+	for _, e := range dotEdges {
+		w.WriteString(e + "\n")
+	}
+
+	w.Unindent()
+	w.WriteString("}\n")
+}
+
+func writeAttrs(buf *bytes.Buffer, attrs map[string]string) {
+	if len(attrs) > 0 {
+		buf.WriteString(" [")
+		buf.WriteString(strings.Join(attrStrings(attrs), ", "))
+		buf.WriteString("]")
+	}
+}
+
+func attrStrings(attrs map[string]string) []string {
+	strings := make([]string, 0, len(attrs))
+	for k, v := range attrs {
+		strings = append(strings, fmt.Sprintf("%s = %q", k, v))
+	}
+	sort.Strings(strings)
+	return strings
+}
+
+// Provide a bytes.Buffer like structure, which will indent when starting a
+// newline.
+type indentWriter struct {
+	bytes.Buffer
+	level int
+}
+
+func (w *indentWriter) indent() {
+	newline := []byte("\n")
+	if !bytes.HasSuffix(w.Bytes(), newline) {
+		return
+	}
+	for i := 0; i < w.level; i++ {
+		w.Buffer.WriteString("\t")
+	}
+}
+
+// Indent increases indentation by 1
+func (w *indentWriter) Indent() { w.level++ }
+
+// Unindent decreases indentation by 1
+func (w *indentWriter) Unindent() { w.level-- }
+
+// the following methods intercecpt the byte.Buffer writes and insert the
+// indentation when starting a new line.
+func (w *indentWriter) Write(b []byte) (int, error) {
+	w.indent()
+	return w.Buffer.Write(b)
+}
+
+func (w *indentWriter) WriteString(s string) (int, error) {
+	w.indent()
+	return w.Buffer.WriteString(s)
+}
+func (w *indentWriter) WriteByte(b byte) error {
+	w.indent()
+	return w.Buffer.WriteByte(b)
+}
+func (w *indentWriter) WriteRune(r rune) (int, error) {
+	w.indent()
+	return w.Buffer.WriteRune(r)
+}
diff --git a/v1.5.7/internal/dag/dot_test.go b/v1.5.7/internal/dag/dot_test.go
new file mode 100644
index 0000000..be8fa9f
--- /dev/null
+++ b/v1.5.7/internal/dag/dot_test.go
@@ -0,0 +1,42 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestGraphDot_opts(t *testing.T) {
+	var v testDotVertex
+	var g Graph
+	g.Add(&v)
+
+	opts := &DotOpts{MaxDepth: 42}
+	actual := g.Dot(opts)
+	if len(actual) == 0 {
+		t.Fatal("should not be empty")
+	}
+
+	if !v.DotNodeCalled {
+		t.Fatal("should call DotNode")
+	}
+	if !reflect.DeepEqual(v.DotNodeOpts, opts) {
+		t.Fatalf("bad; %#v", v.DotNodeOpts)
+	}
+}
+
+type testDotVertex struct {
+	DotNodeCalled bool
+	DotNodeTitle  string
+	DotNodeOpts   *DotOpts
+	DotNodeReturn *DotNode
+}
+
+func (v *testDotVertex) DotNode(title string, opts *DotOpts) *DotNode {
+	v.DotNodeCalled = true
+	v.DotNodeTitle = title
+	v.DotNodeOpts = opts
+	return v.DotNodeReturn
+}
diff --git a/v1.5.7/internal/dag/edge.go b/v1.5.7/internal/dag/edge.go
new file mode 100644
index 0000000..2f69aaa
--- /dev/null
+++ b/v1.5.7/internal/dag/edge.go
@@ -0,0 +1,36 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+// Edge represents an edge in the graph, with a source and target vertex.
+type Edge interface {
+	Source() Vertex
+	Target() Vertex
+
+	Hashable
+}
+
+// BasicEdge returns an Edge implementation that simply tracks the source
+// and target given as-is.
+func BasicEdge(source, target Vertex) Edge {
+	return &basicEdge{S: source, T: target}
+}
+
+// basicEdge is a basic implementation of Edge that has the source and
+// target vertex.
+type basicEdge struct {
+	S, T Vertex
+}
+
+func (e *basicEdge) Hashcode() interface{} {
+	return [...]interface{}{e.S, e.T}
+}
+
+func (e *basicEdge) Source() Vertex {
+	return e.S
+}
+
+func (e *basicEdge) Target() Vertex {
+	return e.T
+}
diff --git a/v1.5.7/internal/dag/edge_test.go b/v1.5.7/internal/dag/edge_test.go
new file mode 100644
index 0000000..fec8d83
--- /dev/null
+++ b/v1.5.7/internal/dag/edge_test.go
@@ -0,0 +1,29 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+import (
+	"testing"
+)
+
+func TestBasicEdgeHashcode(t *testing.T) {
+	e1 := BasicEdge(1, 2)
+	e2 := BasicEdge(1, 2)
+	if e1.Hashcode() != e2.Hashcode() {
+		t.Fatalf("bad")
+	}
+}
+
+func TestBasicEdgeHashcode_pointer(t *testing.T) {
+	type test struct {
+		Value string
+	}
+
+	v1, v2 := &test{"foo"}, &test{"bar"}
+	e1 := BasicEdge(v1, v2)
+	e2 := BasicEdge(v1, v2)
+	if e1.Hashcode() != e2.Hashcode() {
+		t.Fatalf("bad")
+	}
+}
diff --git a/v1.5.7/internal/dag/graph.go b/v1.5.7/internal/dag/graph.go
new file mode 100644
index 0000000..37807aa
--- /dev/null
+++ b/v1.5.7/internal/dag/graph.go
@@ -0,0 +1,370 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+import (
+	"bytes"
+	"fmt"
+	"sort"
+)
+
+// Graph is used to represent a dependency graph.
+type Graph struct {
+	vertices  Set
+	edges     Set
+	downEdges map[interface{}]Set
+	upEdges   map[interface{}]Set
+}
+
+// Subgrapher allows a Vertex to be a Graph itself, by returning a Grapher.
+type Subgrapher interface {
+	Subgraph() Grapher
+}
+
+// A Grapher is any type that returns a Grapher, mainly used to identify
+// dag.Graph and dag.AcyclicGraph.  In the case of Graph and AcyclicGraph, they
+// return themselves.
+type Grapher interface {
+	DirectedGraph() Grapher
+}
+
+// Vertex of the graph.
+type Vertex interface{}
+
+// NamedVertex is an optional interface that can be implemented by Vertex
+// to give it a human-friendly name that is used for outputting the graph.
+type NamedVertex interface {
+	Vertex
+	Name() string
+}
+
+func (g *Graph) DirectedGraph() Grapher {
+	return g
+}
+
+// Vertices returns the list of all the vertices in the graph.
+func (g *Graph) Vertices() []Vertex {
+	result := make([]Vertex, 0, len(g.vertices))
+	for _, v := range g.vertices {
+		result = append(result, v.(Vertex))
+	}
+
+	return result
+}
+
+// Edges returns the list of all the edges in the graph.
+func (g *Graph) Edges() []Edge {
+	result := make([]Edge, 0, len(g.edges))
+	for _, v := range g.edges {
+		result = append(result, v.(Edge))
+	}
+
+	return result
+}
+
+// EdgesFrom returns the list of edges from the given source.
+func (g *Graph) EdgesFrom(v Vertex) []Edge {
+	var result []Edge
+	from := hashcode(v)
+	for _, e := range g.Edges() {
+		if hashcode(e.Source()) == from {
+			result = append(result, e)
+		}
+	}
+
+	return result
+}
+
+// EdgesTo returns the list of edges to the given target.
+func (g *Graph) EdgesTo(v Vertex) []Edge {
+	var result []Edge
+	search := hashcode(v)
+	for _, e := range g.Edges() {
+		if hashcode(e.Target()) == search {
+			result = append(result, e)
+		}
+	}
+
+	return result
+}
+
+// HasVertex checks if the given Vertex is present in the graph.
+func (g *Graph) HasVertex(v Vertex) bool {
+	return g.vertices.Include(v)
+}
+
+// HasEdge checks if the given Edge is present in the graph.
+func (g *Graph) HasEdge(e Edge) bool {
+	return g.edges.Include(e)
+}
+
+// Add adds a vertex to the graph. This is safe to call multiple time with
+// the same Vertex.
+func (g *Graph) Add(v Vertex) Vertex {
+	g.init()
+	g.vertices.Add(v)
+	return v
+}
+
+// Remove removes a vertex from the graph. This will also remove any
+// edges with this vertex as a source or target.
+func (g *Graph) Remove(v Vertex) Vertex {
+	// Delete the vertex itself
+	g.vertices.Delete(v)
+
+	// Delete the edges to non-existent things
+	for _, target := range g.downEdgesNoCopy(v) {
+		g.RemoveEdge(BasicEdge(v, target))
+	}
+	for _, source := range g.upEdgesNoCopy(v) {
+		g.RemoveEdge(BasicEdge(source, v))
+	}
+
+	return nil
+}
+
+// Replace replaces the original Vertex with replacement. If the original
+// does not exist within the graph, then false is returned. Otherwise, true
+// is returned.
+func (g *Graph) Replace(original, replacement Vertex) bool {
+	// If we don't have the original, we can't do anything
+	if !g.vertices.Include(original) {
+		return false
+	}
+
+	// If they're the same, then don't do anything
+	if original == replacement {
+		return true
+	}
+
+	// Add our new vertex, then copy all the edges
+	g.Add(replacement)
+	for _, target := range g.downEdgesNoCopy(original) {
+		g.Connect(BasicEdge(replacement, target))
+	}
+	for _, source := range g.upEdgesNoCopy(original) {
+		g.Connect(BasicEdge(source, replacement))
+	}
+
+	// Remove our old vertex, which will also remove all the edges
+	g.Remove(original)
+
+	return true
+}
+
+// RemoveEdge removes an edge from the graph.
+func (g *Graph) RemoveEdge(edge Edge) {
+	g.init()
+
+	// Delete the edge from the set
+	g.edges.Delete(edge)
+
+	// Delete the up/down edges
+	if s, ok := g.downEdges[hashcode(edge.Source())]; ok {
+		s.Delete(edge.Target())
+	}
+	if s, ok := g.upEdges[hashcode(edge.Target())]; ok {
+		s.Delete(edge.Source())
+	}
+}
+
+// UpEdges returns the vertices that are *sources* of edges that target the
+// destination Vertex v.
+func (g *Graph) UpEdges(v Vertex) Set {
+	return g.upEdgesNoCopy(v).Copy()
+}
+
+// DownEdges returns the vertices that are *targets* of edges that originate
+// from the source Vertex v.
+func (g *Graph) DownEdges(v Vertex) Set {
+	return g.downEdgesNoCopy(v).Copy()
+}
+
+// downEdgesNoCopy returns the vertices targeted by edges from the source Vertex
+// v as a Set. This Set is the same as used internally by the Graph to prevent a
+// copy, and must not be modified by the caller.
+func (g *Graph) downEdgesNoCopy(v Vertex) Set {
+	g.init()
+	return g.downEdges[hashcode(v)]
+}
+
+// upEdgesNoCopy returns the vertices that are sources of edges targeting the
+// destination Vertex v as a Set. This Set is the same as used internally by the
+// Graph to prevent a copy, and must not be modified by the caller.
+func (g *Graph) upEdgesNoCopy(v Vertex) Set {
+	g.init()
+	return g.upEdges[hashcode(v)]
+}
+
+// Connect adds an edge with the given source and target. This is safe to
+// call multiple times with the same value. Note that the same value is
+// verified through pointer equality of the vertices, not through the
+// value of the edge itself.
+func (g *Graph) Connect(edge Edge) {
+	g.init()
+
+	source := edge.Source()
+	target := edge.Target()
+	sourceCode := hashcode(source)
+	targetCode := hashcode(target)
+
+	// Do we have this already? If so, don't add it again.
+	if s, ok := g.downEdges[sourceCode]; ok && s.Include(target) {
+		return
+	}
+
+	// Add the edge to the set
+	g.edges.Add(edge)
+
+	// Add the down edge
+	s, ok := g.downEdges[sourceCode]
+	if !ok {
+		s = make(Set)
+		g.downEdges[sourceCode] = s
+	}
+	s.Add(target)
+
+	// Add the up edge
+	s, ok = g.upEdges[targetCode]
+	if !ok {
+		s = make(Set)
+		g.upEdges[targetCode] = s
+	}
+	s.Add(source)
+}
+
+// Subsume imports all of the nodes and edges from the given graph into the
+// reciever, leaving the given graph unchanged.
+//
+// If any of the nodes in the given graph are already present in the reciever
+// then the existing node will be retained and any new edges from the given
+// graph will be connected with it.
+//
+// If the given graph has edges in common with the reciever then they will be
+// ignored, because each pair of nodes can only be connected once.
+func (g *Graph) Subsume(other *Graph) {
+	// We're using Set.Filter just as a "visit each element" here, so we're
+	// not doing anything with the result (which will always be empty).
+	other.vertices.Filter(func(i interface{}) bool {
+		g.Add(i)
+		return false
+	})
+	other.edges.Filter(func(i interface{}) bool {
+		g.Connect(i.(Edge))
+		return false
+	})
+}
+
+// String outputs some human-friendly output for the graph structure.
+func (g *Graph) StringWithNodeTypes() string {
+	var buf bytes.Buffer
+
+	// Build the list of node names and a mapping so that we can more
+	// easily alphabetize the output to remain deterministic.
+	vertices := g.Vertices()
+	names := make([]string, 0, len(vertices))
+	mapping := make(map[string]Vertex, len(vertices))
+	for _, v := range vertices {
+		name := VertexName(v)
+		names = append(names, name)
+		mapping[name] = v
+	}
+	sort.Strings(names)
+
+	// Write each node in order...
+	for _, name := range names {
+		v := mapping[name]
+		targets := g.downEdges[hashcode(v)]
+
+		buf.WriteString(fmt.Sprintf("%s - %T\n", name, v))
+
+		// Alphabetize dependencies
+		deps := make([]string, 0, targets.Len())
+		targetNodes := make(map[string]Vertex)
+		for _, target := range targets {
+			dep := VertexName(target)
+			deps = append(deps, dep)
+			targetNodes[dep] = target
+		}
+		sort.Strings(deps)
+
+		// Write dependencies
+		for _, d := range deps {
+			buf.WriteString(fmt.Sprintf("  %s - %T\n", d, targetNodes[d]))
+		}
+	}
+
+	return buf.String()
+}
+
+// String outputs some human-friendly output for the graph structure.
+func (g *Graph) String() string {
+	var buf bytes.Buffer
+
+	// Build the list of node names and a mapping so that we can more
+	// easily alphabetize the output to remain deterministic.
+	vertices := g.Vertices()
+	names := make([]string, 0, len(vertices))
+	mapping := make(map[string]Vertex, len(vertices))
+	for _, v := range vertices {
+		name := VertexName(v)
+		names = append(names, name)
+		mapping[name] = v
+	}
+	sort.Strings(names)
+
+	// Write each node in order...
+	for _, name := range names {
+		v := mapping[name]
+		targets := g.downEdges[hashcode(v)]
+
+		buf.WriteString(fmt.Sprintf("%s\n", name))
+
+		// Alphabetize dependencies
+		deps := make([]string, 0, targets.Len())
+		for _, target := range targets {
+			deps = append(deps, VertexName(target))
+		}
+		sort.Strings(deps)
+
+		// Write dependencies
+		for _, d := range deps {
+			buf.WriteString(fmt.Sprintf("  %s\n", d))
+		}
+	}
+
+	return buf.String()
+}
+
+func (g *Graph) init() {
+	if g.vertices == nil {
+		g.vertices = make(Set)
+	}
+	if g.edges == nil {
+		g.edges = make(Set)
+	}
+	if g.downEdges == nil {
+		g.downEdges = make(map[interface{}]Set)
+	}
+	if g.upEdges == nil {
+		g.upEdges = make(map[interface{}]Set)
+	}
+}
+
+// Dot returns a dot-formatted representation of the Graph.
+func (g *Graph) Dot(opts *DotOpts) []byte {
+	return newMarshalGraph("", g).Dot(opts)
+}
+
+// VertexName returns the name of a vertex.
+func VertexName(raw Vertex) string {
+	switch v := raw.(type) {
+	case NamedVertex:
+		return v.Name()
+	case fmt.Stringer:
+		return v.String()
+	default:
+		return fmt.Sprintf("%v", v)
+	}
+}
diff --git a/v1.5.7/internal/dag/graph_test.go b/v1.5.7/internal/dag/graph_test.go
new file mode 100644
index 0000000..43d1e9f
--- /dev/null
+++ b/v1.5.7/internal/dag/graph_test.go
@@ -0,0 +1,256 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+)
+
+func TestGraph_empty(t *testing.T) {
+	var g Graph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testGraphEmptyStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+func TestGraph_basic(t *testing.T) {
+	var g Graph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(1, 3))
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testGraphBasicStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+func TestGraph_remove(t *testing.T) {
+	var g Graph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(1, 3))
+	g.Remove(3)
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testGraphRemoveStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+func TestGraph_replace(t *testing.T) {
+	var g Graph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(1, 2))
+	g.Connect(BasicEdge(2, 3))
+	g.Replace(2, 42)
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testGraphReplaceStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+func TestGraph_replaceSelf(t *testing.T) {
+	var g Graph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(1, 2))
+	g.Connect(BasicEdge(2, 3))
+	g.Replace(2, 2)
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testGraphReplaceSelfStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+// This tests that connecting edges works based on custom Hashcode
+// implementations for uniqueness.
+func TestGraph_hashcode(t *testing.T) {
+	var g Graph
+	g.Add(&hashVertex{code: 1})
+	g.Add(&hashVertex{code: 2})
+	g.Add(&hashVertex{code: 3})
+	g.Connect(BasicEdge(
+		&hashVertex{code: 1},
+		&hashVertex{code: 3}))
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testGraphBasicStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+func TestGraphHasVertex(t *testing.T) {
+	var g Graph
+	g.Add(1)
+
+	if !g.HasVertex(1) {
+		t.Fatal("should have 1")
+	}
+	if g.HasVertex(2) {
+		t.Fatal("should not have 2")
+	}
+}
+
+func TestGraphHasEdge(t *testing.T) {
+	var g Graph
+	g.Add(1)
+	g.Add(2)
+	g.Connect(BasicEdge(1, 2))
+
+	if !g.HasEdge(BasicEdge(1, 2)) {
+		t.Fatal("should have 1,2")
+	}
+	if g.HasVertex(BasicEdge(2, 3)) {
+		t.Fatal("should not have 2,3")
+	}
+}
+
+func TestGraphEdgesFrom(t *testing.T) {
+	var g Graph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(1, 3))
+	g.Connect(BasicEdge(2, 3))
+
+	edges := g.EdgesFrom(1)
+
+	expected := make(Set)
+	expected.Add(BasicEdge(1, 3))
+
+	s := make(Set)
+	for _, e := range edges {
+		s.Add(e)
+	}
+
+	if s.Intersection(expected).Len() != expected.Len() {
+		t.Fatalf("bad: %#v", edges)
+	}
+}
+
+func TestGraphEdgesTo(t *testing.T) {
+	var g Graph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(1, 3))
+	g.Connect(BasicEdge(1, 2))
+
+	edges := g.EdgesTo(3)
+
+	expected := make(Set)
+	expected.Add(BasicEdge(1, 3))
+
+	s := make(Set)
+	for _, e := range edges {
+		s.Add(e)
+	}
+
+	if s.Intersection(expected).Len() != expected.Len() {
+		t.Fatalf("bad: %#v", edges)
+	}
+}
+
+func TestGraphUpdownEdges(t *testing.T) {
+	// Verify that we can't inadvertently modify the internal graph sets
+	var g Graph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(1, 2))
+	g.Connect(BasicEdge(2, 3))
+
+	up := g.UpEdges(2)
+	if up.Len() != 1 || !up.Include(1) {
+		t.Fatalf("expected only an up edge of '1', got %#v", up)
+	}
+	// modify the up set
+	up.Add(9)
+
+	orig := g.UpEdges(2)
+	diff := up.Difference(orig)
+	if diff.Len() != 1 || !diff.Include(9) {
+		t.Fatalf("expected a diff of only '9', got %#v", diff)
+	}
+
+	down := g.DownEdges(2)
+	if down.Len() != 1 || !down.Include(3) {
+		t.Fatalf("expected only a down edge of '3', got %#v", down)
+	}
+	// modify the down set
+	down.Add(8)
+
+	orig = g.DownEdges(2)
+	diff = down.Difference(orig)
+	if diff.Len() != 1 || !diff.Include(8) {
+		t.Fatalf("expected a diff of only '8', got %#v", diff)
+	}
+}
+
+type hashVertex struct {
+	code interface{}
+}
+
+func (v *hashVertex) Hashcode() interface{} {
+	return v.code
+}
+
+func (v *hashVertex) Name() string {
+	return fmt.Sprintf("%#v", v.code)
+}
+
+const testGraphBasicStr = `
+1
+  3
+2
+3
+`
+
+const testGraphEmptyStr = `
+1
+2
+3
+`
+
+const testGraphRemoveStr = `
+1
+2
+`
+
+const testGraphReplaceStr = `
+1
+  42
+3
+42
+  3
+`
+
+const testGraphReplaceSelfStr = `
+1
+  2
+2
+  3
+3
+`
diff --git a/v1.5.7/internal/dag/marshal.go b/v1.5.7/internal/dag/marshal.go
new file mode 100644
index 0000000..31d0dc8
--- /dev/null
+++ b/v1.5.7/internal/dag/marshal.go
@@ -0,0 +1,200 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+import (
+	"fmt"
+	"reflect"
+	"sort"
+	"strconv"
+)
+
+// the marshal* structs are for serialization of the graph data.
+type marshalGraph struct {
+	// Type is always "Graph", for identification as a top level object in the
+	// JSON stream.
+	Type string
+
+	// Each marshal structure requires a unique ID so that it can be referenced
+	// by other structures.
+	ID string `json:",omitempty"`
+
+	// Human readable name for this graph.
+	Name string `json:",omitempty"`
+
+	// Arbitrary attributes that can be added to the output.
+	Attrs map[string]string `json:",omitempty"`
+
+	// List of graph vertices, sorted by ID.
+	Vertices []*marshalVertex `json:",omitempty"`
+
+	// List of edges, sorted by Source ID.
+	Edges []*marshalEdge `json:",omitempty"`
+
+	// Any number of subgraphs. A subgraph itself is considered a vertex, and
+	// may be referenced by either end of an edge.
+	Subgraphs []*marshalGraph `json:",omitempty"`
+
+	// Any lists of vertices that are included in cycles.
+	Cycles [][]*marshalVertex `json:",omitempty"`
+}
+
+func (g *marshalGraph) vertexByID(id string) *marshalVertex {
+	for _, v := range g.Vertices {
+		if id == v.ID {
+			return v
+		}
+	}
+	return nil
+}
+
+type marshalVertex struct {
+	// Unique ID, used to reference this vertex from other structures.
+	ID string
+
+	// Human readable name
+	Name string `json:",omitempty"`
+
+	Attrs map[string]string `json:",omitempty"`
+
+	// This is to help transition from the old Dot interfaces. We record if the
+	// node was a GraphNodeDotter here, so we can call it to get attributes.
+	graphNodeDotter GraphNodeDotter
+}
+
+func newMarshalVertex(v Vertex) *marshalVertex {
+	dn, ok := v.(GraphNodeDotter)
+	if !ok {
+		dn = nil
+	}
+
+	// the name will be quoted again later, so we need to ensure it's properly
+	// escaped without quotes.
+	name := strconv.Quote(VertexName(v))
+	name = name[1 : len(name)-1]
+
+	return &marshalVertex{
+		ID:              marshalVertexID(v),
+		Name:            name,
+		Attrs:           make(map[string]string),
+		graphNodeDotter: dn,
+	}
+}
+
+// vertices is a sort.Interface implementation for sorting vertices by ID
+type vertices []*marshalVertex
+
+func (v vertices) Less(i, j int) bool { return v[i].Name < v[j].Name }
+func (v vertices) Len() int           { return len(v) }
+func (v vertices) Swap(i, j int)      { v[i], v[j] = v[j], v[i] }
+
+type marshalEdge struct {
+	// Human readable name
+	Name string
+
+	// Source and Target Vertices by ID
+	Source string
+	Target string
+
+	Attrs map[string]string `json:",omitempty"`
+}
+
+func newMarshalEdge(e Edge) *marshalEdge {
+	return &marshalEdge{
+		Name:   fmt.Sprintf("%s|%s", VertexName(e.Source()), VertexName(e.Target())),
+		Source: marshalVertexID(e.Source()),
+		Target: marshalVertexID(e.Target()),
+		Attrs:  make(map[string]string),
+	}
+}
+
+// edges is a sort.Interface implementation for sorting edges by Source ID
+type edges []*marshalEdge
+
+func (e edges) Less(i, j int) bool { return e[i].Name < e[j].Name }
+func (e edges) Len() int           { return len(e) }
+func (e edges) Swap(i, j int)      { e[i], e[j] = e[j], e[i] }
+
+// build a marshalGraph structure from a *Graph
+func newMarshalGraph(name string, g *Graph) *marshalGraph {
+	mg := &marshalGraph{
+		Type:  "Graph",
+		Name:  name,
+		Attrs: make(map[string]string),
+	}
+
+	for _, v := range g.Vertices() {
+		id := marshalVertexID(v)
+		if sg, ok := marshalSubgrapher(v); ok {
+			smg := newMarshalGraph(VertexName(v), sg)
+			smg.ID = id
+			mg.Subgraphs = append(mg.Subgraphs, smg)
+		}
+
+		mv := newMarshalVertex(v)
+		mg.Vertices = append(mg.Vertices, mv)
+	}
+
+	sort.Sort(vertices(mg.Vertices))
+
+	for _, e := range g.Edges() {
+		mg.Edges = append(mg.Edges, newMarshalEdge(e))
+	}
+
+	sort.Sort(edges(mg.Edges))
+
+	for _, c := range (&AcyclicGraph{*g}).Cycles() {
+		var cycle []*marshalVertex
+		for _, v := range c {
+			mv := newMarshalVertex(v)
+			cycle = append(cycle, mv)
+		}
+		mg.Cycles = append(mg.Cycles, cycle)
+	}
+
+	return mg
+}
+
+// Attempt to return a unique ID for any vertex.
+func marshalVertexID(v Vertex) string {
+	val := reflect.ValueOf(v)
+	switch val.Kind() {
+	case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
+		return strconv.Itoa(int(val.Pointer()))
+	case reflect.Interface:
+		// A vertex shouldn't contain another layer of interface, but handle
+		// this just in case.
+		return fmt.Sprintf("%#v", val.Interface())
+	}
+
+	if v, ok := v.(Hashable); ok {
+		h := v.Hashcode()
+		if h, ok := h.(string); ok {
+			return h
+		}
+	}
+
+	// fallback to a name, which we hope is unique.
+	return VertexName(v)
+
+	// we could try harder by attempting to read the arbitrary value from the
+	// interface, but we shouldn't get here from terraform right now.
+}
+
+// check for a Subgrapher, and return the underlying *Graph.
+func marshalSubgrapher(v Vertex) (*Graph, bool) {
+	sg, ok := v.(Subgrapher)
+	if !ok {
+		return nil, false
+	}
+
+	switch g := sg.Subgraph().DirectedGraph().(type) {
+	case *Graph:
+		return g, true
+	case *AcyclicGraph:
+		return &g.Graph, true
+	}
+
+	return nil, false
+}
diff --git a/v1.5.7/internal/dag/marshal_test.go b/v1.5.7/internal/dag/marshal_test.go
new file mode 100644
index 0000000..fecbe64
--- /dev/null
+++ b/v1.5.7/internal/dag/marshal_test.go
@@ -0,0 +1,104 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+import (
+	"strings"
+	"testing"
+)
+
+func TestGraphDot_empty(t *testing.T) {
+	var g Graph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+
+	actual := strings.TrimSpace(string(g.Dot(nil)))
+	expected := strings.TrimSpace(testGraphDotEmptyStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+func TestGraphDot_basic(t *testing.T) {
+	var g Graph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(1, 3))
+
+	actual := strings.TrimSpace(string(g.Dot(nil)))
+	expected := strings.TrimSpace(testGraphDotBasicStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+func TestGraphDot_quoted(t *testing.T) {
+	var g Graph
+	quoted := `name["with-quotes"]`
+	other := `other`
+	g.Add(quoted)
+	g.Add(other)
+	g.Connect(BasicEdge(quoted, other))
+
+	actual := strings.TrimSpace(string(g.Dot(nil)))
+	expected := strings.TrimSpace(testGraphDotQuotedStr)
+	if actual != expected {
+		t.Fatalf("\ngot:   %q\nwanted %q\n", actual, expected)
+	}
+}
+
+func TestGraphDot_attrs(t *testing.T) {
+	var g Graph
+	g.Add(&testGraphNodeDotter{
+		Result: &DotNode{
+			Name:  "foo",
+			Attrs: map[string]string{"foo": "bar"},
+		},
+	})
+
+	actual := strings.TrimSpace(string(g.Dot(nil)))
+	expected := strings.TrimSpace(testGraphDotAttrsStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+type testGraphNodeDotter struct{ Result *DotNode }
+
+func (n *testGraphNodeDotter) Name() string                      { return n.Result.Name }
+func (n *testGraphNodeDotter) DotNode(string, *DotOpts) *DotNode { return n.Result }
+
+const testGraphDotQuotedStr = `digraph {
+	compound = "true"
+	newrank = "true"
+	subgraph "root" {
+		"[root] name[\"with-quotes\"]" -> "[root] other"
+	}
+}`
+
+const testGraphDotBasicStr = `digraph {
+	compound = "true"
+	newrank = "true"
+	subgraph "root" {
+		"[root] 1" -> "[root] 3"
+	}
+}
+`
+
+const testGraphDotEmptyStr = `digraph {
+	compound = "true"
+	newrank = "true"
+	subgraph "root" {
+	}
+}`
+
+const testGraphDotAttrsStr = `digraph {
+	compound = "true"
+	newrank = "true"
+	subgraph "root" {
+		"[root] foo" [foo = "bar"]
+	}
+}`
diff --git a/v1.5.7/internal/dag/set.go b/v1.5.7/internal/dag/set.go
new file mode 100644
index 0000000..30c0e7d
--- /dev/null
+++ b/v1.5.7/internal/dag/set.go
@@ -0,0 +1,116 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+// Set is a set data structure.
+type Set map[interface{}]interface{}
+
+// Hashable is the interface used by set to get the hash code of a value.
+// If this isn't given, then the value of the item being added to the set
+// itself is used as the comparison value.
+type Hashable interface {
+	Hashcode() interface{}
+}
+
+// hashcode returns the hashcode used for set elements.
+func hashcode(v interface{}) interface{} {
+	if h, ok := v.(Hashable); ok {
+		return h.Hashcode()
+	}
+
+	return v
+}
+
+// Add adds an item to the set
+func (s Set) Add(v interface{}) {
+	s[hashcode(v)] = v
+}
+
+// Delete removes an item from the set.
+func (s Set) Delete(v interface{}) {
+	delete(s, hashcode(v))
+}
+
+// Include returns true/false of whether a value is in the set.
+func (s Set) Include(v interface{}) bool {
+	_, ok := s[hashcode(v)]
+	return ok
+}
+
+// Intersection computes the set intersection with other.
+func (s Set) Intersection(other Set) Set {
+	result := make(Set)
+	if s == nil || other == nil {
+		return result
+	}
+	// Iteration over a smaller set has better performance.
+	if other.Len() < s.Len() {
+		s, other = other, s
+	}
+	for _, v := range s {
+		if other.Include(v) {
+			result.Add(v)
+		}
+	}
+	return result
+}
+
+// Difference returns a set with the elements that s has but
+// other doesn't.
+func (s Set) Difference(other Set) Set {
+	if other == nil || other.Len() == 0 {
+		return s.Copy()
+	}
+
+	result := make(Set)
+	for k, v := range s {
+		if _, ok := other[k]; !ok {
+			result.Add(v)
+		}
+	}
+
+	return result
+}
+
+// Filter returns a set that contains the elements from the receiver
+// where the given callback returns true.
+func (s Set) Filter(cb func(interface{}) bool) Set {
+	result := make(Set)
+
+	for _, v := range s {
+		if cb(v) {
+			result.Add(v)
+		}
+	}
+
+	return result
+}
+
+// Len is the number of items in the set.
+func (s Set) Len() int {
+	return len(s)
+}
+
+// List returns the list of set elements.
+func (s Set) List() []interface{} {
+	if s == nil {
+		return nil
+	}
+
+	r := make([]interface{}, 0, len(s))
+	for _, v := range s {
+		r = append(r, v)
+	}
+
+	return r
+}
+
+// Copy returns a shallow copy of the set.
+func (s Set) Copy() Set {
+	c := make(Set, len(s))
+	for k, v := range s {
+		c[k] = v
+	}
+	return c
+}
diff --git a/v1.5.7/internal/dag/set_test.go b/v1.5.7/internal/dag/set_test.go
new file mode 100644
index 0000000..952d4b8
--- /dev/null
+++ b/v1.5.7/internal/dag/set_test.go
@@ -0,0 +1,161 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestSetDifference(t *testing.T) {
+	cases := []struct {
+		Name     string
+		A, B     []interface{}
+		Expected []interface{}
+	}{
+		{
+			"same",
+			[]interface{}{1, 2, 3},
+			[]interface{}{3, 1, 2},
+			[]interface{}{},
+		},
+
+		{
+			"A has extra elements",
+			[]interface{}{1, 2, 3},
+			[]interface{}{3, 2},
+			[]interface{}{1},
+		},
+
+		{
+			"B has extra elements",
+			[]interface{}{1, 2, 3},
+			[]interface{}{3, 2, 1, 4},
+			[]interface{}{},
+		},
+		{
+			"B is nil",
+			[]interface{}{1, 2, 3},
+			nil,
+			[]interface{}{1, 2, 3},
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			one := make(Set)
+			two := make(Set)
+			expected := make(Set)
+			for _, v := range tc.A {
+				one.Add(v)
+			}
+			for _, v := range tc.B {
+				two.Add(v)
+			}
+			if tc.B == nil {
+				two = nil
+			}
+			for _, v := range tc.Expected {
+				expected.Add(v)
+			}
+
+			actual := one.Difference(two)
+			match := actual.Intersection(expected)
+			if match.Len() != expected.Len() {
+				t.Fatalf("bad: %#v", actual.List())
+			}
+		})
+	}
+}
+
+func TestSetFilter(t *testing.T) {
+	cases := []struct {
+		Input    []interface{}
+		Expected []interface{}
+	}{
+		{
+			[]interface{}{1, 2, 3},
+			[]interface{}{1, 2, 3},
+		},
+
+		{
+			[]interface{}{4, 5, 6},
+			[]interface{}{4},
+		},
+
+		{
+			[]interface{}{7, 8, 9},
+			[]interface{}{},
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%#v", i, tc.Input), func(t *testing.T) {
+			input := make(Set)
+			expected := make(Set)
+			for _, v := range tc.Input {
+				input.Add(v)
+			}
+			for _, v := range tc.Expected {
+				expected.Add(v)
+			}
+
+			actual := input.Filter(func(v interface{}) bool {
+				return v.(int) < 5
+			})
+			match := actual.Intersection(expected)
+			if match.Len() != expected.Len() {
+				t.Fatalf("bad: %#v", actual.List())
+			}
+		})
+	}
+}
+
+func TestSetCopy(t *testing.T) {
+	a := make(Set)
+	a.Add(1)
+	a.Add(2)
+
+	b := a.Copy()
+	b.Add(3)
+
+	diff := b.Difference(a)
+
+	if diff.Len() != 1 {
+		t.Fatalf("expected single diff value, got %#v", diff)
+	}
+
+	if !diff.Include(3) {
+		t.Fatalf("diff does not contain 3, got %#v", diff)
+	}
+
+}
+
+func makeSet(n int) Set {
+	ret := make(Set, n)
+	for i := 0; i < n; i++ {
+		ret.Add(i)
+	}
+	return ret
+}
+
+func BenchmarkSetIntersection_100_100000(b *testing.B) {
+	small := makeSet(100)
+	large := makeSet(100000)
+
+	b.ResetTimer()
+	for n := 0; n < b.N; n++ {
+		small.Intersection(large)
+	}
+}
+
+func BenchmarkSetIntersection_100000_100(b *testing.B) {
+	small := makeSet(100)
+	large := makeSet(100000)
+
+	b.ResetTimer()
+	for n := 0; n < b.N; n++ {
+		large.Intersection(small)
+	}
+}
diff --git a/v1.5.7/internal/dag/tarjan.go b/v1.5.7/internal/dag/tarjan.go
new file mode 100644
index 0000000..cdca54e
--- /dev/null
+++ b/v1.5.7/internal/dag/tarjan.go
@@ -0,0 +1,110 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+// StronglyConnected returns the list of strongly connected components
+// within the Graph g. This information is primarily used by this package
+// for cycle detection, but strongly connected components have widespread
+// use.
+func StronglyConnected(g *Graph) [][]Vertex {
+	vs := g.Vertices()
+	acct := sccAcct{
+		NextIndex:   1,
+		VertexIndex: make(map[Vertex]int, len(vs)),
+	}
+	for _, v := range vs {
+		// Recurse on any non-visited nodes
+		if acct.VertexIndex[v] == 0 {
+			stronglyConnected(&acct, g, v)
+		}
+	}
+	return acct.SCC
+}
+
+func stronglyConnected(acct *sccAcct, g *Graph, v Vertex) int {
+	// Initial vertex visit
+	index := acct.visit(v)
+	minIdx := index
+
+	for _, raw := range g.downEdgesNoCopy(v) {
+		target := raw.(Vertex)
+		targetIdx := acct.VertexIndex[target]
+
+		// Recurse on successor if not yet visited
+		if targetIdx == 0 {
+			minIdx = min(minIdx, stronglyConnected(acct, g, target))
+		} else if acct.inStack(target) {
+			// Check if the vertex is in the stack
+			minIdx = min(minIdx, targetIdx)
+		}
+	}
+
+	// Pop the strongly connected components off the stack if
+	// this is a root vertex
+	if index == minIdx {
+		var scc []Vertex
+		for {
+			v2 := acct.pop()
+			scc = append(scc, v2)
+			if v2 == v {
+				break
+			}
+		}
+
+		acct.SCC = append(acct.SCC, scc)
+	}
+
+	return minIdx
+}
+
+func min(a, b int) int {
+	if a <= b {
+		return a
+	}
+	return b
+}
+
+// sccAcct is used ot pass around accounting information for
+// the StronglyConnectedComponents algorithm
+type sccAcct struct {
+	NextIndex   int
+	VertexIndex map[Vertex]int
+	Stack       []Vertex
+	SCC         [][]Vertex
+}
+
+// visit assigns an index and pushes a vertex onto the stack
+func (s *sccAcct) visit(v Vertex) int {
+	idx := s.NextIndex
+	s.VertexIndex[v] = idx
+	s.NextIndex++
+	s.push(v)
+	return idx
+}
+
+// push adds a vertex to the stack
+func (s *sccAcct) push(n Vertex) {
+	s.Stack = append(s.Stack, n)
+}
+
+// pop removes a vertex from the stack
+func (s *sccAcct) pop() Vertex {
+	n := len(s.Stack)
+	if n == 0 {
+		return nil
+	}
+	vertex := s.Stack[n-1]
+	s.Stack = s.Stack[:n-1]
+	return vertex
+}
+
+// inStack checks if a vertex is in the stack
+func (s *sccAcct) inStack(needle Vertex) bool {
+	for _, n := range s.Stack {
+		if n == needle {
+			return true
+		}
+	}
+	return false
+}
diff --git a/v1.5.7/internal/dag/tarjan_test.go b/v1.5.7/internal/dag/tarjan_test.go
new file mode 100644
index 0000000..1977f2d
--- /dev/null
+++ b/v1.5.7/internal/dag/tarjan_test.go
@@ -0,0 +1,89 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+import (
+	"sort"
+	"strings"
+	"testing"
+)
+
+func TestGraphStronglyConnected(t *testing.T) {
+	var g Graph
+	g.Add(1)
+	g.Add(2)
+	g.Connect(BasicEdge(1, 2))
+	g.Connect(BasicEdge(2, 1))
+
+	actual := strings.TrimSpace(testSCCStr(StronglyConnected(&g)))
+	expected := strings.TrimSpace(testGraphStronglyConnectedStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+func TestGraphStronglyConnected_two(t *testing.T) {
+	var g Graph
+	g.Add(1)
+	g.Add(2)
+	g.Connect(BasicEdge(1, 2))
+	g.Connect(BasicEdge(2, 1))
+	g.Add(3)
+
+	actual := strings.TrimSpace(testSCCStr(StronglyConnected(&g)))
+	expected := strings.TrimSpace(testGraphStronglyConnectedTwoStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+func TestGraphStronglyConnected_three(t *testing.T) {
+	var g Graph
+	g.Add(1)
+	g.Add(2)
+	g.Connect(BasicEdge(1, 2))
+	g.Connect(BasicEdge(2, 1))
+	g.Add(3)
+	g.Add(4)
+	g.Add(5)
+	g.Add(6)
+	g.Connect(BasicEdge(4, 5))
+	g.Connect(BasicEdge(5, 6))
+	g.Connect(BasicEdge(6, 4))
+
+	actual := strings.TrimSpace(testSCCStr(StronglyConnected(&g)))
+	expected := strings.TrimSpace(testGraphStronglyConnectedThreeStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+func testSCCStr(list [][]Vertex) string {
+	var lines []string
+	for _, vs := range list {
+		result := make([]string, len(vs))
+		for i, v := range vs {
+			result[i] = VertexName(v)
+		}
+
+		sort.Strings(result)
+		lines = append(lines, strings.Join(result, ","))
+	}
+
+	sort.Strings(lines)
+	return strings.Join(lines, "\n")
+}
+
+const testGraphStronglyConnectedStr = `1,2`
+
+const testGraphStronglyConnectedTwoStr = `
+1,2
+3
+`
+
+const testGraphStronglyConnectedThreeStr = `
+1,2
+3
+4,5,6
+`
diff --git a/v1.5.7/internal/dag/walk.go b/v1.5.7/internal/dag/walk.go
new file mode 100644
index 0000000..1fa1845
--- /dev/null
+++ b/v1.5.7/internal/dag/walk.go
@@ -0,0 +1,451 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+import (
+	"errors"
+	"log"
+	"sync"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Walker is used to walk every vertex of a graph in parallel.
+//
+// A vertex will only be walked when the dependencies of that vertex have
+// been walked. If two vertices can be walked at the same time, they will be.
+//
+// Update can be called to update the graph. This can be called even during
+// a walk, changing vertices/edges mid-walk. This should be done carefully.
+// If a vertex is removed but has already been executed, the result of that
+// execution (any error) is still returned by Wait. Changing or re-adding
+// a vertex that has already executed has no effect. Changing edges of
+// a vertex that has already executed has no effect.
+//
+// Non-parallelism can be enforced by introducing a lock in your callback
+// function. However, the goroutine overhead of a walk will remain.
+// Walker will create V*2 goroutines (one for each vertex, and dependency
+// waiter for each vertex). In general this should be of no concern unless
+// there are a huge number of vertices.
+//
+// The walk is depth first by default. This can be changed with the Reverse
+// option.
+//
+// A single walker is only valid for one graph walk. After the walk is complete
+// you must construct a new walker to walk again. State for the walk is never
+// deleted in case vertices or edges are changed.
+type Walker struct {
+	// Callback is what is called for each vertex
+	Callback WalkFunc
+
+	// Reverse, if true, causes the source of an edge to depend on a target.
+	// When false (default), the target depends on the source.
+	Reverse bool
+
+	// changeLock must be held to modify any of the fields below. Only Update
+	// should modify these fields. Modifying them outside of Update can cause
+	// serious problems.
+	changeLock sync.Mutex
+	vertices   Set
+	edges      Set
+	vertexMap  map[Vertex]*walkerVertex
+
+	// wait is done when all vertices have executed. It may become "undone"
+	// if new vertices are added.
+	wait sync.WaitGroup
+
+	// diagsMap contains the diagnostics recorded so far for execution,
+	// and upstreamFailed contains all the vertices whose problems were
+	// caused by upstream failures, and thus whose diagnostics should be
+	// excluded from the final set.
+	//
+	// Readers and writers of either map must hold diagsLock.
+	diagsMap       map[Vertex]tfdiags.Diagnostics
+	upstreamFailed map[Vertex]struct{}
+	diagsLock      sync.Mutex
+}
+
+func (w *Walker) init() {
+	if w.vertices == nil {
+		w.vertices = make(Set)
+	}
+	if w.edges == nil {
+		w.edges = make(Set)
+	}
+}
+
+type walkerVertex struct {
+	// These should only be set once on initialization and never written again.
+	// They are not protected by a lock since they don't need to be since
+	// they are write-once.
+
+	// DoneCh is closed when this vertex has completed execution, regardless
+	// of success.
+	//
+	// CancelCh is closed when the vertex should cancel execution. If execution
+	// is already complete (DoneCh is closed), this has no effect. Otherwise,
+	// execution is cancelled as quickly as possible.
+	DoneCh   chan struct{}
+	CancelCh chan struct{}
+
+	// Dependency information. Any changes to any of these fields requires
+	// holding DepsLock.
+	//
+	// DepsCh is sent a single value that denotes whether the upstream deps
+	// were successful (no errors). Any value sent means that the upstream
+	// dependencies are complete. No other values will ever be sent again.
+	//
+	// DepsUpdateCh is closed when there is a new DepsCh set.
+	DepsCh       chan bool
+	DepsUpdateCh chan struct{}
+	DepsLock     sync.Mutex
+
+	// Below is not safe to read/write in parallel. This behavior is
+	// enforced by changes only happening in Update. Nothing else should
+	// ever modify these.
+	deps         map[Vertex]chan struct{}
+	depsCancelCh chan struct{}
+}
+
+// Wait waits for the completion of the walk and returns diagnostics describing
+// any problems that arose. Update should be called to populate the walk with
+// vertices and edges prior to calling this.
+//
+// Wait will return as soon as all currently known vertices are complete.
+// If you plan on calling Update with more vertices in the future, you
+// should not call Wait until after this is done.
+func (w *Walker) Wait() tfdiags.Diagnostics {
+	// Wait for completion
+	w.wait.Wait()
+
+	var diags tfdiags.Diagnostics
+	w.diagsLock.Lock()
+	for v, vDiags := range w.diagsMap {
+		if _, upstream := w.upstreamFailed[v]; upstream {
+			// Ignore diagnostics for nodes that had failed upstreams, since
+			// the downstream diagnostics are likely to be redundant.
+			continue
+		}
+		diags = diags.Append(vDiags)
+	}
+	w.diagsLock.Unlock()
+
+	return diags
+}
+
+// Update updates the currently executing walk with the given graph.
+// This will perform a diff of the vertices and edges and update the walker.
+// Already completed vertices remain completed (including any errors during
+// their execution).
+//
+// This returns immediately once the walker is updated; it does not wait
+// for completion of the walk.
+//
+// Multiple Updates can be called in parallel. Update can be called at any
+// time during a walk.
+func (w *Walker) Update(g *AcyclicGraph) {
+	w.init()
+	v := make(Set)
+	e := make(Set)
+	if g != nil {
+		v, e = g.vertices, g.edges
+	}
+
+	// Grab the change lock so no more updates happen but also so that
+	// no new vertices are executed during this time since we may be
+	// removing them.
+	w.changeLock.Lock()
+	defer w.changeLock.Unlock()
+
+	// Initialize fields
+	if w.vertexMap == nil {
+		w.vertexMap = make(map[Vertex]*walkerVertex)
+	}
+
+	// Calculate all our sets
+	newEdges := e.Difference(w.edges)
+	oldEdges := w.edges.Difference(e)
+	newVerts := v.Difference(w.vertices)
+	oldVerts := w.vertices.Difference(v)
+
+	// Add the new vertices
+	for _, raw := range newVerts {
+		v := raw.(Vertex)
+
+		// Add to the waitgroup so our walk is not done until everything finishes
+		w.wait.Add(1)
+
+		// Add to our own set so we know about it already
+		w.vertices.Add(raw)
+
+		// Initialize the vertex info
+		info := &walkerVertex{
+			DoneCh:   make(chan struct{}),
+			CancelCh: make(chan struct{}),
+			deps:     make(map[Vertex]chan struct{}),
+		}
+
+		// Add it to the map and kick off the walk
+		w.vertexMap[v] = info
+	}
+
+	// Remove the old vertices
+	for _, raw := range oldVerts {
+		v := raw.(Vertex)
+
+		// Get the vertex info so we can cancel it
+		info, ok := w.vertexMap[v]
+		if !ok {
+			// This vertex for some reason was never in our map. This
+			// shouldn't be possible.
+			continue
+		}
+
+		// Cancel the vertex
+		close(info.CancelCh)
+
+		// Delete it out of the map
+		delete(w.vertexMap, v)
+		w.vertices.Delete(raw)
+	}
+
+	// Add the new edges
+	changedDeps := make(Set)
+	for _, raw := range newEdges {
+		edge := raw.(Edge)
+		waiter, dep := w.edgeParts(edge)
+
+		// Get the info for the waiter
+		waiterInfo, ok := w.vertexMap[waiter]
+		if !ok {
+			// Vertex doesn't exist... shouldn't be possible but ignore.
+			continue
+		}
+
+		// Get the info for the dep
+		depInfo, ok := w.vertexMap[dep]
+		if !ok {
+			// Vertex doesn't exist... shouldn't be possible but ignore.
+			continue
+		}
+
+		// Add the dependency to our waiter
+		waiterInfo.deps[dep] = depInfo.DoneCh
+
+		// Record that the deps changed for this waiter
+		changedDeps.Add(waiter)
+		w.edges.Add(raw)
+	}
+
+	// Process removed edges
+	for _, raw := range oldEdges {
+		edge := raw.(Edge)
+		waiter, dep := w.edgeParts(edge)
+
+		// Get the info for the waiter
+		waiterInfo, ok := w.vertexMap[waiter]
+		if !ok {
+			// Vertex doesn't exist... shouldn't be possible but ignore.
+			continue
+		}
+
+		// Delete the dependency from the waiter
+		delete(waiterInfo.deps, dep)
+
+		// Record that the deps changed for this waiter
+		changedDeps.Add(waiter)
+		w.edges.Delete(raw)
+	}
+
+	// For each vertex with changed dependencies, we need to kick off
+	// a new waiter and notify the vertex of the changes.
+	for _, raw := range changedDeps {
+		v := raw.(Vertex)
+		info, ok := w.vertexMap[v]
+		if !ok {
+			// Vertex doesn't exist... shouldn't be possible but ignore.
+			continue
+		}
+
+		// Create a new done channel
+		doneCh := make(chan bool, 1)
+
+		// Create the channel we close for cancellation
+		cancelCh := make(chan struct{})
+
+		// Build a new deps copy
+		deps := make(map[Vertex]<-chan struct{})
+		for k, v := range info.deps {
+			deps[k] = v
+		}
+
+		// Update the update channel
+		info.DepsLock.Lock()
+		if info.DepsUpdateCh != nil {
+			close(info.DepsUpdateCh)
+		}
+		info.DepsCh = doneCh
+		info.DepsUpdateCh = make(chan struct{})
+		info.DepsLock.Unlock()
+
+		// Cancel the older waiter
+		if info.depsCancelCh != nil {
+			close(info.depsCancelCh)
+		}
+		info.depsCancelCh = cancelCh
+
+		// Start the waiter
+		go w.waitDeps(v, deps, doneCh, cancelCh)
+	}
+
+	// Start all the new vertices. We do this at the end so that all
+	// the edge waiters and changes are set up above.
+	for _, raw := range newVerts {
+		v := raw.(Vertex)
+		go w.walkVertex(v, w.vertexMap[v])
+	}
+}
+
+// edgeParts returns the waiter and the dependency, in that order.
+// The waiter is waiting on the dependency.
+func (w *Walker) edgeParts(e Edge) (Vertex, Vertex) {
+	if w.Reverse {
+		return e.Source(), e.Target()
+	}
+
+	return e.Target(), e.Source()
+}
+
+// walkVertex walks a single vertex, waiting for any dependencies before
+// executing the callback.
+func (w *Walker) walkVertex(v Vertex, info *walkerVertex) {
+	// When we're done executing, lower the waitgroup count
+	defer w.wait.Done()
+
+	// When we're done, always close our done channel
+	defer close(info.DoneCh)
+
+	// Wait for our dependencies. We create a [closed] deps channel so
+	// that we can immediately fall through to load our actual DepsCh.
+	var depsSuccess bool
+	var depsUpdateCh chan struct{}
+	depsCh := make(chan bool, 1)
+	depsCh <- true
+	close(depsCh)
+	for {
+		select {
+		case <-info.CancelCh:
+			// Cancel
+			return
+
+		case depsSuccess = <-depsCh:
+			// Deps complete! Mark as nil to trigger completion handling.
+			depsCh = nil
+
+		case <-depsUpdateCh:
+			// New deps, reloop
+		}
+
+		// Check if we have updated dependencies. This can happen if the
+		// dependencies were satisfied exactly prior to an Update occurring.
+		// In that case, we'd like to take into account new dependencies
+		// if possible.
+		info.DepsLock.Lock()
+		if info.DepsCh != nil {
+			depsCh = info.DepsCh
+			info.DepsCh = nil
+		}
+		if info.DepsUpdateCh != nil {
+			depsUpdateCh = info.DepsUpdateCh
+		}
+		info.DepsLock.Unlock()
+
+		// If we still have no deps channel set, then we're done!
+		if depsCh == nil {
+			break
+		}
+	}
+
+	// If we passed dependencies, we just want to check once more that
+	// we're not cancelled, since this can happen just as dependencies pass.
+	select {
+	case <-info.CancelCh:
+		// Cancelled during an update while dependencies completed.
+		return
+	default:
+	}
+
+	// Run our callback or note that our upstream failed
+	var diags tfdiags.Diagnostics
+	var upstreamFailed bool
+	if depsSuccess {
+		diags = w.Callback(v)
+	} else {
+		log.Printf("[TRACE] dag/walk: upstream of %q errored, so skipping", VertexName(v))
+		// This won't be displayed to the user because we'll set upstreamFailed,
+		// but we need to ensure there's at least one error in here so that
+		// the failures will cascade downstream.
+		diags = diags.Append(errors.New("upstream dependencies failed"))
+		upstreamFailed = true
+	}
+
+	// Record the result (we must do this after execution because we mustn't
+	// hold diagsLock while visiting a vertex.)
+	w.diagsLock.Lock()
+	if w.diagsMap == nil {
+		w.diagsMap = make(map[Vertex]tfdiags.Diagnostics)
+	}
+	w.diagsMap[v] = diags
+	if w.upstreamFailed == nil {
+		w.upstreamFailed = make(map[Vertex]struct{})
+	}
+	if upstreamFailed {
+		w.upstreamFailed[v] = struct{}{}
+	}
+	w.diagsLock.Unlock()
+}
+
+func (w *Walker) waitDeps(
+	v Vertex,
+	deps map[Vertex]<-chan struct{},
+	doneCh chan<- bool,
+	cancelCh <-chan struct{}) {
+
+	// For each dependency given to us, wait for it to complete
+	for dep, depCh := range deps {
+	DepSatisfied:
+		for {
+			select {
+			case <-depCh:
+				// Dependency satisfied!
+				break DepSatisfied
+
+			case <-cancelCh:
+				// Wait cancelled. Note that we didn't satisfy dependencies
+				// so that anything waiting on us also doesn't run.
+				doneCh <- false
+				return
+
+			case <-time.After(time.Second * 5):
+				log.Printf("[TRACE] dag/walk: vertex %q is waiting for %q",
+					VertexName(v), VertexName(dep))
+			}
+		}
+	}
+
+	// Dependencies satisfied! We need to check if any errored
+	w.diagsLock.Lock()
+	defer w.diagsLock.Unlock()
+	for dep := range deps {
+		if w.diagsMap[dep].HasErrors() {
+			// One of our dependencies failed, so return false
+			doneCh <- false
+			return
+		}
+	}
+
+	// All dependencies satisfied and successful
+	doneCh <- true
+}
diff --git a/v1.5.7/internal/dag/walk_test.go b/v1.5.7/internal/dag/walk_test.go
new file mode 100644
index 0000000..b29d194
--- /dev/null
+++ b/v1.5.7/internal/dag/walk_test.go
@@ -0,0 +1,301 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package dag
+
+import (
+	"fmt"
+	"reflect"
+	"sync"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestWalker_basic(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Connect(BasicEdge(1, 2))
+
+	// Run it a bunch of times since it is timing dependent
+	for i := 0; i < 50; i++ {
+		var order []interface{}
+		w := &Walker{Callback: walkCbRecord(&order)}
+		w.Update(&g)
+
+		// Wait
+		if err := w.Wait(); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		// Check
+		expected := []interface{}{1, 2}
+		if !reflect.DeepEqual(order, expected) {
+			t.Errorf("wrong order\ngot:  %#v\nwant: %#v", order, expected)
+		}
+	}
+}
+
+func TestWalker_updateNilGraph(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Connect(BasicEdge(1, 2))
+
+	// Run it a bunch of times since it is timing dependent
+	for i := 0; i < 50; i++ {
+		var order []interface{}
+		w := &Walker{Callback: walkCbRecord(&order)}
+		w.Update(&g)
+		w.Update(nil)
+
+		// Wait
+		if err := w.Wait(); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+}
+
+func TestWalker_error(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Add(4)
+	g.Connect(BasicEdge(1, 2))
+	g.Connect(BasicEdge(2, 3))
+	g.Connect(BasicEdge(3, 4))
+
+	// Record function
+	var order []interface{}
+	recordF := walkCbRecord(&order)
+
+	// Build a callback that delays until we close a channel
+	cb := func(v Vertex) tfdiags.Diagnostics {
+		if v == 2 {
+			var diags tfdiags.Diagnostics
+			diags = diags.Append(fmt.Errorf("error"))
+			return diags
+		}
+
+		return recordF(v)
+	}
+
+	w := &Walker{Callback: cb}
+	w.Update(&g)
+
+	// Wait
+	if err := w.Wait(); err == nil {
+		t.Fatal("expect error")
+	}
+
+	// Check
+	expected := []interface{}{1}
+	if !reflect.DeepEqual(order, expected) {
+		t.Errorf("wrong order\ngot:  %#v\nwant: %#v", order, expected)
+	}
+}
+
+func TestWalker_newVertex(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Connect(BasicEdge(1, 2))
+
+	// Record function
+	var order []interface{}
+	recordF := walkCbRecord(&order)
+	done2 := make(chan int)
+
+	// Build a callback that notifies us when 2 has been walked
+	var w *Walker
+	cb := func(v Vertex) tfdiags.Diagnostics {
+		if v == 2 {
+			defer close(done2)
+		}
+		return recordF(v)
+	}
+
+	// Add the initial vertices
+	w = &Walker{Callback: cb}
+	w.Update(&g)
+
+	// if 2 has been visited, the walk is complete so far
+	<-done2
+
+	// Update the graph
+	g.Add(3)
+	w.Update(&g)
+
+	// Update the graph again but with the same vertex
+	g.Add(3)
+	w.Update(&g)
+
+	// Wait
+	if err := w.Wait(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Check
+	expected := []interface{}{1, 2, 3}
+	if !reflect.DeepEqual(order, expected) {
+		t.Errorf("wrong order\ngot:  %#v\nwant: %#v", order, expected)
+	}
+}
+
+func TestWalker_removeVertex(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Connect(BasicEdge(1, 2))
+
+	// Record function
+	var order []interface{}
+	recordF := walkCbRecord(&order)
+
+	var w *Walker
+	cb := func(v Vertex) tfdiags.Diagnostics {
+		if v == 1 {
+			g.Remove(2)
+			w.Update(&g)
+		}
+
+		return recordF(v)
+	}
+
+	// Add the initial vertices
+	w = &Walker{Callback: cb}
+	w.Update(&g)
+
+	// Wait
+	if err := w.Wait(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Check
+	expected := []interface{}{1}
+	if !reflect.DeepEqual(order, expected) {
+		t.Errorf("wrong order\ngot:  %#v\nwant: %#v", order, expected)
+	}
+}
+
+func TestWalker_newEdge(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Connect(BasicEdge(1, 2))
+
+	// Record function
+	var order []interface{}
+	recordF := walkCbRecord(&order)
+
+	var w *Walker
+	cb := func(v Vertex) tfdiags.Diagnostics {
+		// record where we are first, otherwise the Updated vertex may get
+		// walked before the first visit.
+		diags := recordF(v)
+
+		if v == 1 {
+			g.Add(3)
+			g.Connect(BasicEdge(3, 2))
+			w.Update(&g)
+		}
+		return diags
+	}
+
+	// Add the initial vertices
+	w = &Walker{Callback: cb}
+	w.Update(&g)
+
+	// Wait
+	if err := w.Wait(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Check
+	expected := []interface{}{1, 3, 2}
+	if !reflect.DeepEqual(order, expected) {
+		t.Errorf("wrong order\ngot:  %#v\nwant: %#v", order, expected)
+	}
+}
+
+func TestWalker_removeEdge(t *testing.T) {
+	var g AcyclicGraph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(BasicEdge(1, 2))
+	g.Connect(BasicEdge(1, 3))
+	g.Connect(BasicEdge(3, 2))
+
+	// Record function
+	var order []interface{}
+	recordF := walkCbRecord(&order)
+
+	// The way this works is that our original graph forces
+	// the order of 1 => 3 => 2. During the execution of 1, we
+	// remove the edge forcing 3 before 2. Then, during the execution
+	// of 3, we wait on a channel that is only closed by 2, implicitly
+	// forcing 2 before 3 via the callback (and not the graph). If
+	// 2 cannot execute before 3 (edge removal is non-functional), then
+	// this test will timeout.
+	var w *Walker
+	gateCh := make(chan struct{})
+	cb := func(v Vertex) tfdiags.Diagnostics {
+		t.Logf("visit vertex %#v", v)
+		switch v {
+		case 1:
+			g.RemoveEdge(BasicEdge(3, 2))
+			w.Update(&g)
+			t.Logf("removed edge from 3 to 2")
+
+		case 2:
+			// this visit isn't completed until we've recorded it
+			// Once the visit is official, we can then close the gate to
+			// let 3 continue.
+			defer close(gateCh)
+			defer t.Logf("2 unblocked 3")
+
+		case 3:
+			select {
+			case <-gateCh:
+				t.Logf("vertex 3 gate channel is now closed")
+			case <-time.After(500 * time.Millisecond):
+				t.Logf("vertex 3 timed out waiting for the gate channel to close")
+				var diags tfdiags.Diagnostics
+				diags = diags.Append(fmt.Errorf("timeout 3 waiting for 2"))
+				return diags
+			}
+		}
+
+		return recordF(v)
+	}
+
+	// Add the initial vertices
+	w = &Walker{Callback: cb}
+	w.Update(&g)
+
+	// Wait
+	if diags := w.Wait(); diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	// Check
+	expected := []interface{}{1, 2, 3}
+	if !reflect.DeepEqual(order, expected) {
+		t.Errorf("wrong order\ngot:  %#v\nwant: %#v", order, expected)
+	}
+}
+
+// walkCbRecord is a test helper callback that just records the order called.
+func walkCbRecord(order *[]interface{}) WalkFunc {
+	var l sync.Mutex
+	return func(v Vertex) tfdiags.Diagnostics {
+		l.Lock()
+		defer l.Unlock()
+		*order = append(*order, v)
+		return nil
+	}
+}
diff --git a/v1.5.7/internal/depsfile/doc.go b/v1.5.7/internal/depsfile/doc.go
new file mode 100644
index 0000000..d432642
--- /dev/null
+++ b/v1.5.7/internal/depsfile/doc.go
@@ -0,0 +1,25 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package depsfile contains the logic for reading and writing Terraform's
+// dependency lock and development override configuration files.
+//
+// These files are separate from the main Terraform configuration files (.tf)
+// for a number of reasons. The first is to help establish a distinction
+// where .tf files configure a particular module while these configure
+// a whole configuration tree. Another, more practical consideration is that
+// we intend both of these files to be primarily maintained automatically by
+// Terraform itself, rather than by human-originated edits, and so keeping
+// them separate means that it's easier to distinguish the files that Terraform
+// will change automatically during normal workflow from the files that
+// Terraform only edits on direct request.
+//
+// Both files use HCL syntax, for consistency with other files in Terraform
+// that we expect humans to (in this case, only occasionally) edit directly.
+// A dependency lock file tracks the most recently selected upstream versions
+// of each dependency, and is intended for checkin to version control.
+// A development override file allows for temporarily overriding upstream
+// dependencies with local files/directories on disk as an aid to testing
+// a cross-codebase change during development, and should not be saved in
+// version control.
+package depsfile
diff --git a/v1.5.7/internal/depsfile/locks.go b/v1.5.7/internal/depsfile/locks.go
new file mode 100644
index 0000000..3cf4472
--- /dev/null
+++ b/v1.5.7/internal/depsfile/locks.go
@@ -0,0 +1,442 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package depsfile
+
+import (
+	"fmt"
+	"sort"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+// Locks is the top-level type representing the information retained in a
+// dependency lock file.
+//
+// Locks and the other types used within it are mutable via various setter
+// methods, but they are not safe for concurrent  modifications, so it's the
+// caller's responsibility to prevent concurrent writes and writes concurrent
+// with reads.
+type Locks struct {
+	providers map[addrs.Provider]*ProviderLock
+
+	// overriddenProviders is a subset of providers which we might be tracking
+	// in field providers but whose lock information we're disregarding for
+	// this particular run due to some feature that forces Terraform to not
+	// use a normally-installed plugin for it. For example, the "provider dev
+	// overrides" feature means that we'll be using an arbitrary directory on
+	// disk as the package, regardless of what might be selected in "providers".
+	//
+	// overriddenProviders is an in-memory-only annotation, never stored as
+	// part of a lock file and thus not persistent between Terraform runs.
+	// The CLI layer is generally the one responsible for populating this,
+	// by calling SetProviderOverridden in response to CLI Configuration
+	// settings, environment variables, or whatever similar sources.
+	overriddenProviders map[addrs.Provider]struct{}
+
+	// TODO: In future we'll also have module locks, but the design of that
+	// still needs some more work and we're deferring that to get the
+	// provider locking capability out sooner, because it's more common to
+	// directly depend on providers maintained outside your organization than
+	// modules maintained outside your organization.
+
+	// sources is a copy of the map of source buffers produced by the HCL
+	// parser during loading, which we retain only so that the caller can
+	// use it to produce source code snippets in error messages.
+	sources map[string][]byte
+}
+
+// NewLocks constructs and returns a new Locks object that initially contains
+// no locks at all.
+func NewLocks() *Locks {
+	return &Locks{
+		providers: make(map[addrs.Provider]*ProviderLock),
+
+		// no "sources" here, because that's only for locks objects loaded
+		// from files.
+	}
+}
+
+// Provider returns the stored lock for the given provider, or nil if that
+// provider currently has no lock.
+func (l *Locks) Provider(addr addrs.Provider) *ProviderLock {
+	return l.providers[addr]
+}
+
+// AllProviders returns a map describing all of the provider locks in the
+// receiver.
+func (l *Locks) AllProviders() map[addrs.Provider]*ProviderLock {
+	// We return a copy of our internal map so that future calls to
+	// SetProvider won't modify the map we're returning, or vice-versa.
+	ret := make(map[addrs.Provider]*ProviderLock, len(l.providers))
+	for k, v := range l.providers {
+		ret[k] = v
+	}
+	return ret
+}
+
+// SetProvider creates a new lock or replaces the existing lock for the given
+// provider.
+//
+// SetProvider returns the newly-created provider lock object, which
+// invalidates any ProviderLock object previously returned from Provider or
+// SetProvider for the given provider address.
+//
+// The ownership of the backing array for the slice of hashes passes to this
+// function, and so the caller must not read or write that backing array after
+// calling SetProvider.
+//
+// Only lockable providers can be passed to this method. If you pass a
+// non-lockable provider address then this function will panic. Use
+// function ProviderIsLockable to determine whether a particular provider
+// should participate in the version locking mechanism.
+func (l *Locks) SetProvider(addr addrs.Provider, version getproviders.Version, constraints getproviders.VersionConstraints, hashes []getproviders.Hash) *ProviderLock {
+	if !ProviderIsLockable(addr) {
+		panic(fmt.Sprintf("Locks.SetProvider with non-lockable provider %s", addr))
+	}
+
+	new := NewProviderLock(addr, version, constraints, hashes)
+	l.providers[new.addr] = new
+	return new
+}
+
+// RemoveProvider removes any existing lock file entry for the given provider.
+//
+// If the given provider did not already have a lock entry, RemoveProvider is
+// a no-op.
+//
+// Only lockable providers can be passed to this method. If you pass a
+// non-lockable provider address then this function will panic. Use
+// function ProviderIsLockable to determine whether a particular provider
+// should participate in the version locking mechanism.
+func (l *Locks) RemoveProvider(addr addrs.Provider) {
+	if !ProviderIsLockable(addr) {
+		panic(fmt.Sprintf("Locks.RemoveProvider with non-lockable provider %s", addr))
+	}
+
+	delete(l.providers, addr)
+}
+
+// SetProviderOverridden records that this particular Terraform process will
+// not pay attention to the recorded lock entry for the given provider, and
+// will instead access that provider's functionality in some other special
+// way that isn't sensitive to provider version selections or checksums.
+//
+// This is an in-memory-only annotation which lives only inside a particular
+// Locks object, and is never persisted as part of a saved lock file on disk.
+// It's valid to still use other methods of the reciever to access
+// already-stored lock information and to update lock information for an
+// overridden provider, but some callers may need to use ProviderIsOverridden
+// to selectively disregard stored lock information for overridden providers,
+// depending on what they intended to use the lock information for.
+func (l *Locks) SetProviderOverridden(addr addrs.Provider) {
+	if l.overriddenProviders == nil {
+		l.overriddenProviders = make(map[addrs.Provider]struct{})
+	}
+	l.overriddenProviders[addr] = struct{}{}
+}
+
+// ProviderIsOverridden returns true only if the given provider address was
+// previously registered as overridden by calling SetProviderOverridden.
+func (l *Locks) ProviderIsOverridden(addr addrs.Provider) bool {
+	_, ret := l.overriddenProviders[addr]
+	return ret
+}
+
+// SetSameOverriddenProviders updates the receiver to mark as overridden all
+// of the same providers already marked as overridden in the other given locks.
+//
+// This allows propagating override information between different lock objects,
+// as if calling SetProviderOverridden for each address already overridden
+// in the other given locks. If the reciever already has overridden providers,
+// SetSameOverriddenProviders will preserve them.
+func (l *Locks) SetSameOverriddenProviders(other *Locks) {
+	if other == nil {
+		return
+	}
+	for addr := range other.overriddenProviders {
+		l.SetProviderOverridden(addr)
+	}
+}
+
+// NewProviderLock creates a new ProviderLock object that isn't associated
+// with any Locks object.
+//
+// This is here primarily for testing. Most callers should use Locks.SetProvider
+// to construct a new provider lock and insert it into a Locks object at the
+// same time.
+//
+// The ownership of the backing array for the slice of hashes passes to this
+// function, and so the caller must not read or write that backing array after
+// calling NewProviderLock.
+//
+// Only lockable providers can be passed to this method. If you pass a
+// non-lockable provider address then this function will panic. Use
+// function ProviderIsLockable to determine whether a particular provider
+// should participate in the version locking mechanism.
+func NewProviderLock(addr addrs.Provider, version getproviders.Version, constraints getproviders.VersionConstraints, hashes []getproviders.Hash) *ProviderLock {
+	if !ProviderIsLockable(addr) {
+		panic(fmt.Sprintf("Locks.NewProviderLock with non-lockable provider %s", addr))
+	}
+
+	// Normalize the hashes into lexical order so that we can do straightforward
+	// equality tests between different locks for the same provider. The
+	// hashes are logically a set, so the given order is insignificant.
+	sort.Slice(hashes, func(i, j int) bool {
+		return string(hashes[i]) < string(hashes[j])
+	})
+
+	// This is a slightly-tricky in-place deduping to avoid unnecessarily
+	// allocating a new array in the common case where there are no duplicates:
+	// we iterate over "hashes" at the same time as appending to another slice
+	// with the same backing array, relying on the fact that deduping can only
+	// _skip_ elements from the input, and will never generate additional ones
+	// that would cause the writer to get ahead of the reader. This also
+	// assumes that we already sorted the items, which means that any duplicates
+	// will be consecutive in the sequence.
+	dedupeHashes := hashes[:0]
+	prevHash := getproviders.NilHash
+	for _, hash := range hashes {
+		if hash != prevHash {
+			dedupeHashes = append(dedupeHashes, hash)
+			prevHash = hash
+		}
+	}
+
+	return &ProviderLock{
+		addr:               addr,
+		version:            version,
+		versionConstraints: constraints,
+		hashes:             dedupeHashes,
+	}
+}
+
+// ProviderIsLockable returns true if the given provider is eligible for
+// version locking.
+//
+// Currently, all providers except builtin and legacy providers are eligible
+// for locking.
+func ProviderIsLockable(addr addrs.Provider) bool {
+	return !(addr.IsBuiltIn() || addr.IsLegacy())
+}
+
+// Sources returns the source code of the file the receiver was generated from,
+// or an empty map if the receiver wasn't generated from a file.
+//
+// This return type matches the one expected by HCL diagnostics printers to
+// produce source code snapshots, which is the only intended use for this
+// method.
+func (l *Locks) Sources() map[string][]byte {
+	return l.sources
+}
+
+// Equal returns true if the given Locks represents the same information as
+// the receiver.
+//
+// Equal explicitly _does not_ consider the equality of version constraints
+// in the saved locks, because those are saved only as hints to help the UI
+// explain what's changed between runs, and are never used as part of
+// dependency installation decisions.
+func (l *Locks) Equal(other *Locks) bool {
+	if len(l.providers) != len(other.providers) {
+		return false
+	}
+	for addr, thisLock := range l.providers {
+		otherLock, ok := other.providers[addr]
+		if !ok {
+			return false
+		}
+
+		if thisLock.addr != otherLock.addr {
+			// It'd be weird to get here because we already looked these up
+			// by address above.
+			return false
+		}
+		if thisLock.version != otherLock.version {
+			// Equality rather than "Version.Same" because changes to the
+			// build metadata are significant for the purpose of this function:
+			// it's a different package even if it has the same precedence.
+			return false
+		}
+
+		// Although "hashes" is declared as a slice, it's logically an
+		// unordered set. However, we normalize the slice of hashes when
+		// recieving it in NewProviderLock, so we can just do a simple
+		// item-by-item equality test here.
+		if len(thisLock.hashes) != len(otherLock.hashes) {
+			return false
+		}
+		for i := range thisLock.hashes {
+			if thisLock.hashes[i] != otherLock.hashes[i] {
+				return false
+			}
+		}
+	}
+	// We don't need to worry about providers that are in "other" but not
+	// in the receiver, because we tested the lengths being equal above.
+
+	return true
+}
+
+// EqualProviderAddress returns true if the given Locks have the same provider
+// address as the receiver. This doesn't check version and hashes.
+func (l *Locks) EqualProviderAddress(other *Locks) bool {
+	if len(l.providers) != len(other.providers) {
+		return false
+	}
+
+	for addr := range l.providers {
+		_, ok := other.providers[addr]
+		if !ok {
+			return false
+		}
+	}
+
+	return true
+}
+
+// Empty returns true if the given Locks object contains no actual locks.
+//
+// UI code might wish to use this to distinguish a lock file being
+// written for the first time from subsequent updates to that lock file.
+func (l *Locks) Empty() bool {
+	return len(l.providers) == 0
+}
+
+// DeepCopy creates a new Locks that represents the same information as the
+// receiver but does not share memory for any parts of the structure that.
+// are mutable through methods on Locks.
+//
+// Note that this does _not_ create deep copies of parts of the structure
+// that are technically mutable but are immutable by convention, such as the
+// array underlying the slice of version constraints. Callers may mutate the
+// resulting data structure only via the direct methods of Locks.
+func (l *Locks) DeepCopy() *Locks {
+	ret := NewLocks()
+	for addr, lock := range l.providers {
+		var hashes []getproviders.Hash
+		if len(lock.hashes) > 0 {
+			hashes = make([]getproviders.Hash, len(lock.hashes))
+			copy(hashes, lock.hashes)
+		}
+		ret.SetProvider(addr, lock.version, lock.versionConstraints, hashes)
+	}
+	return ret
+}
+
+// ProviderLock represents lock information for a specific provider.
+type ProviderLock struct {
+	// addr is the address of the provider this lock applies to.
+	addr addrs.Provider
+
+	// version is the specific version that was previously selected, while
+	// versionConstraints is the constraint that was used to make that
+	// selection, which we can potentially use to hint to run
+	// e.g. terraform init -upgrade if a user has changed a version
+	// constraint but the previous selection still remains valid.
+	// "version" is therefore authoritative, while "versionConstraints" is
+	// just for a UI hint and not used to make any real decisions.
+	version            getproviders.Version
+	versionConstraints getproviders.VersionConstraints
+
+	// hashes contains zero or more hashes of packages or package contents
+	// for the package associated with the selected version across all of
+	// the supported platforms.
+	//
+	// hashes can contain a mixture of hashes in different formats to support
+	// changes over time. The new-style hash format is to have a string
+	// starting with "h" followed by a version number and then a colon, like
+	// "h1:" for the first hash format version. Other hash versions following
+	// this scheme may come later. These versioned hash schemes are implemented
+	// in the getproviders package; for example, "h1:" is implemented in
+	// getproviders.HashV1 .
+	//
+	// There is also a legacy hash format which is just a lowercase-hex-encoded
+	// SHA256 hash of the official upstream .zip file for the selected version.
+	// We'll allow as that a stop-gap until we can upgrade Terraform Registry
+	// to support the new scheme, but is non-ideal because we can verify it only
+	// when we have the original .zip file exactly; we can't verify a local
+	// directory containing the unpacked contents of that .zip file.
+	//
+	// We ideally want to populate hashes for all available platforms at
+	// once, by referring to the signed checksums file in the upstream
+	// registry. In that ideal case it's possible to later work with the same
+	// configuration on a different platform while still verifying the hashes.
+	// However, installation from any method other than an origin registry
+	// means we can only populate the hash for the current platform, and so
+	// it won't be possible to verify a subsequent installation of the same
+	// provider on a different platform.
+	hashes []getproviders.Hash
+}
+
+// Provider returns the address of the provider this lock applies to.
+func (l *ProviderLock) Provider() addrs.Provider {
+	return l.addr
+}
+
+// Version returns the currently-selected version for the corresponding provider.
+func (l *ProviderLock) Version() getproviders.Version {
+	return l.version
+}
+
+// VersionConstraints returns the version constraints that were recorded as
+// being used to choose the version returned by Version.
+//
+// These version constraints are not authoritative for future selections and
+// are included only so Terraform can detect if the constraints in
+// configuration have changed since a selection was made, and thus hint to the
+// user that they may need to run terraform init -upgrade to apply the new
+// constraints.
+func (l *ProviderLock) VersionConstraints() getproviders.VersionConstraints {
+	return l.versionConstraints
+}
+
+// AllHashes returns all of the package hashes that were recorded when this
+// lock was created. If no hashes were recorded for that platform, the result
+// is a zero-length slice.
+//
+// If your intent is to verify a package against the recorded hashes, use
+// PreferredHashes to get only the hashes which the current version
+// of Terraform considers the strongest of the available hashing schemes, one
+// of which must match in order for verification to be considered successful.
+//
+// Do not modify the backing array of the returned slice.
+func (l *ProviderLock) AllHashes() []getproviders.Hash {
+	return l.hashes
+}
+
+// ContainsAll returns true if the hashes in this ProviderLock contains
+// all the hashes in the target.
+//
+// This function assumes the hashes are in each ProviderLock are sorted.
+// If the ProviderLock was created by the NewProviderLock constructor then
+// the hashes are guaranteed to be sorted.
+func (l *ProviderLock) ContainsAll(target *ProviderLock) bool {
+	if target == nil || len(target.hashes) == 0 {
+		return true
+	}
+
+	targetIndex := 0
+	for ix := 0; ix < len(l.hashes); ix++ {
+		if l.hashes[ix] == target.hashes[targetIndex] {
+			targetIndex++
+
+			if targetIndex >= len(target.hashes) {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+// PreferredHashes returns a filtered version of the AllHashes return value
+// which includes only the strongest of the availabile hash schemes, in
+// case legacy hash schemes are deprecated over time but still supported for
+// upgrade purposes.
+//
+// At least one of the given hashes must match for a package to be considered
+// valud.
+func (l *ProviderLock) PreferredHashes() []getproviders.Hash {
+	return getproviders.PreferredHashes(l.hashes)
+}
diff --git a/v1.5.7/internal/depsfile/locks_file.go b/v1.5.7/internal/depsfile/locks_file.go
new file mode 100644
index 0000000..cfc71d5
--- /dev/null
+++ b/v1.5.7/internal/depsfile/locks_file.go
@@ -0,0 +1,497 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package depsfile
+
+import (
+	"fmt"
+	"sort"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/gohcl"
+	"github.com/hashicorp/hcl/v2/hclparse"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/hcl/v2/hclwrite"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/hashicorp/terraform/internal/replacefile"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/hashicorp/terraform/version"
+)
+
+// LoadLocksFromFile reads locks from the given file, expecting it to be a
+// valid dependency lock file, or returns error diagnostics explaining why
+// that was not possible.
+//
+// The returned locks are a snapshot of what was present on disk at the time
+// the method was called. It does not take into account any subsequent writes
+// to the file, whether through this package's functions or by external
+// writers.
+//
+// If the returned diagnostics contains errors then the returned Locks may
+// be incomplete or invalid.
+func LoadLocksFromFile(filename string) (*Locks, tfdiags.Diagnostics) {
+	return loadLocks(func(parser *hclparse.Parser) (*hcl.File, hcl.Diagnostics) {
+		return parser.ParseHCLFile(filename)
+	})
+}
+
+// LoadLocksFromBytes reads locks from the given byte array, pretending that
+// it was read from the given filename.
+//
+// The constraints and behaviors are otherwise the same as for
+// LoadLocksFromFile. LoadLocksFromBytes is primarily to allow more convenient
+// integration testing (avoiding creating temporary files on disk); if you
+// are writing non-test code, consider whether LoadLocksFromFile might be
+// more appropriate to call.
+//
+// It is valid to use this with dependency lock information recorded as part of
+// a plan file, in which case the given filename will typically be a
+// placeholder that will only be seen in the unusual case that the plan file
+// contains an invalid lock file, which should only be possible if the user
+// edited it directly (Terraform bugs notwithstanding).
+func LoadLocksFromBytes(src []byte, filename string) (*Locks, tfdiags.Diagnostics) {
+	return loadLocks(func(parser *hclparse.Parser) (*hcl.File, hcl.Diagnostics) {
+		return parser.ParseHCL(src, filename)
+	})
+}
+
+func loadLocks(loadParse func(*hclparse.Parser) (*hcl.File, hcl.Diagnostics)) (*Locks, tfdiags.Diagnostics) {
+	ret := NewLocks()
+
+	var diags tfdiags.Diagnostics
+
+	parser := hclparse.NewParser()
+	f, hclDiags := loadParse(parser)
+	ret.sources = parser.Sources()
+	diags = diags.Append(hclDiags)
+	if f == nil {
+		// If we encountered an error loading the file then those errors
+		// should already be in diags from the above, but the file might
+		// also be nil itself and so we can't decode from it.
+		return ret, diags
+	}
+
+	moreDiags := decodeLocksFromHCL(ret, f.Body)
+	diags = diags.Append(moreDiags)
+	return ret, diags
+}
+
+// SaveLocksToFile writes the given locks object to the given file,
+// entirely replacing any content already in that file, or returns error
+// diagnostics explaining why that was not possible.
+//
+// SaveLocksToFile attempts an atomic replacement of the file, as an aid
+// to external tools such as text editor integrations that might be monitoring
+// the file as a signal to invalidate cached metadata. Consequently, other
+// temporary files may be temporarily created in the same directory as the
+// given filename during the operation.
+func SaveLocksToFile(locks *Locks, filename string) tfdiags.Diagnostics {
+	src, diags := SaveLocksToBytes(locks)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	err := replacefile.AtomicWriteFile(filename, src, 0644)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to update dependency lock file",
+			fmt.Sprintf("Error while writing new dependency lock information to %s: %s.", filename, err),
+		))
+		return diags
+	}
+
+	return diags
+}
+
+// SaveLocksToBytes writes the given locks object into a byte array,
+// using the same syntax that LoadLocksFromBytes expects to parse.
+func SaveLocksToBytes(locks *Locks) ([]byte, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// In other uses of the "hclwrite" package we typically try to make
+	// surgical updates to the author's existing files, preserving their
+	// block ordering, comments, etc. We intentionally don't do that here
+	// to reinforce the fact that this file primarily belongs to Terraform,
+	// and to help ensure that VCS diffs of the file primarily reflect
+	// changes that actually affect functionality rather than just cosmetic
+	// changes, by maintaining it in a highly-normalized form.
+
+	f := hclwrite.NewEmptyFile()
+	rootBody := f.Body()
+
+	// End-users _may_ edit the lock file in exceptional situations, like
+	// working around potential dependency selection bugs, but we intend it
+	// to be primarily maintained automatically by the "terraform init"
+	// command.
+	rootBody.AppendUnstructuredTokens(hclwrite.Tokens{
+		{
+			Type:  hclsyntax.TokenComment,
+			Bytes: []byte("# This file is maintained automatically by \"terraform init\".\n"),
+		},
+		{
+			Type:  hclsyntax.TokenComment,
+			Bytes: []byte("# Manual edits may be lost in future updates.\n"),
+		},
+	})
+
+	providers := make([]addrs.Provider, 0, len(locks.providers))
+	for provider := range locks.providers {
+		providers = append(providers, provider)
+	}
+	sort.Slice(providers, func(i, j int) bool {
+		return providers[i].LessThan(providers[j])
+	})
+
+	for _, provider := range providers {
+		lock := locks.providers[provider]
+		rootBody.AppendNewline()
+		block := rootBody.AppendNewBlock("provider", []string{lock.addr.String()})
+		body := block.Body()
+		body.SetAttributeValue("version", cty.StringVal(lock.version.String()))
+		if constraintsStr := getproviders.VersionConstraintsString(lock.versionConstraints); constraintsStr != "" {
+			body.SetAttributeValue("constraints", cty.StringVal(constraintsStr))
+		}
+		if len(lock.hashes) != 0 {
+			hashToks := encodeHashSetTokens(lock.hashes)
+			body.SetAttributeRaw("hashes", hashToks)
+		}
+	}
+
+	return f.Bytes(), diags
+}
+
+func decodeLocksFromHCL(locks *Locks, body hcl.Body) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	content, hclDiags := body.Content(&hcl.BodySchema{
+		Blocks: []hcl.BlockHeaderSchema{
+			{
+				Type:       "provider",
+				LabelNames: []string{"source_addr"},
+			},
+
+			// "module" is just a placeholder for future enhancement, so we
+			// can mostly-ignore the this block type we intend to add in
+			// future, but warn in case someone tries to use one e.g. if they
+			// downgraded to an earlier version of Terraform.
+			{
+				Type:       "module",
+				LabelNames: []string{"path"},
+			},
+		},
+	})
+	diags = diags.Append(hclDiags)
+
+	seenProviders := make(map[addrs.Provider]hcl.Range)
+	seenModule := false
+	for _, block := range content.Blocks {
+
+		switch block.Type {
+		case "provider":
+			lock, moreDiags := decodeProviderLockFromHCL(block)
+			diags = diags.Append(moreDiags)
+			if lock == nil {
+				continue
+			}
+			if previousRng, exists := seenProviders[lock.addr]; exists {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Duplicate provider lock",
+					Detail:   fmt.Sprintf("This lockfile already declared a lock for provider %s at %s.", lock.addr.String(), previousRng.String()),
+					Subject:  block.TypeRange.Ptr(),
+				})
+				continue
+			}
+			locks.providers[lock.addr] = lock
+			seenProviders[lock.addr] = block.DefRange
+
+		case "module":
+			// We'll just take the first module block to use for a single warning,
+			// because that's sufficient to get the point across without swamping
+			// the output with warning noise.
+			if !seenModule {
+				currentVersion := version.SemVer.String()
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagWarning,
+					Summary:  "Dependency locks for modules are not yet supported",
+					Detail:   fmt.Sprintf("Terraform v%s only supports dependency locks for providers, not for modules. This configuration may be intended for a later version of Terraform that also supports dependency locks for modules.", currentVersion),
+					Subject:  block.TypeRange.Ptr(),
+				})
+				seenModule = true
+			}
+
+		default:
+			// Shouldn't get here because this should be exhaustive for
+			// all of the block types in the schema above.
+		}
+
+	}
+
+	return diags
+}
+
+func decodeProviderLockFromHCL(block *hcl.Block) (*ProviderLock, tfdiags.Diagnostics) {
+	ret := &ProviderLock{}
+	var diags tfdiags.Diagnostics
+
+	rawAddr := block.Labels[0]
+	addr, moreDiags := addrs.ParseProviderSourceString(rawAddr)
+	if moreDiags.HasErrors() {
+		// The diagnostics from ParseProviderSourceString are, as the name
+		// suggests, written with an intended audience of someone who is
+		// writing a "source" attribute in a provider requirement, not
+		// our lock file. Therefore we're using a less helpful, fixed error
+		// here, which is non-ideal but hopefully okay for now because we
+		// don't intend end-users to typically be hand-editing these anyway.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider source address",
+			Detail:   "The provider source address for a provider lock must be a valid, fully-qualified address of the form \"hostname/namespace/type\".",
+			Subject:  block.LabelRanges[0].Ptr(),
+		})
+		return nil, diags
+	}
+	if !ProviderIsLockable(addr) {
+		if addr.IsBuiltIn() {
+			// A specialized error for built-in providers, because we have an
+			// explicit explanation for why those are not allowed.
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid provider source address",
+				Detail:   fmt.Sprintf("Cannot lock a version for built-in provider %s. Built-in providers are bundled inside Terraform itself, so you can't select a version for them independently of the Terraform release you are currently running.", addr),
+				Subject:  block.LabelRanges[0].Ptr(),
+			})
+			return nil, diags
+		}
+		// Otherwise, we'll use a generic error message.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider source address",
+			Detail:   fmt.Sprintf("Provider source address %s is a special provider that is not eligible for dependency locking.", addr),
+			Subject:  block.LabelRanges[0].Ptr(),
+		})
+		return nil, diags
+	}
+	if canonAddr := addr.String(); canonAddr != rawAddr {
+		// We also require the provider addresses in the lock file to be
+		// written in fully-qualified canonical form, so that it's totally
+		// clear to a reader which provider each block relates to. Again,
+		// we expect hand-editing of these to be atypical so it's reasonable
+		// to be stricter in parsing these than we would be in the main
+		// configuration.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Non-normalized provider source address",
+			Detail:   fmt.Sprintf("The provider source address for this provider lock must be written as %q, the fully-qualified and normalized form.", canonAddr),
+			Subject:  block.LabelRanges[0].Ptr(),
+		})
+		return nil, diags
+	}
+
+	ret.addr = addr
+
+	content, hclDiags := block.Body.Content(&hcl.BodySchema{
+		Attributes: []hcl.AttributeSchema{
+			{Name: "version", Required: true},
+			{Name: "constraints"},
+			{Name: "hashes"},
+		},
+	})
+	diags = diags.Append(hclDiags)
+
+	version, moreDiags := decodeProviderVersionArgument(addr, content.Attributes["version"])
+	ret.version = version
+	diags = diags.Append(moreDiags)
+
+	constraints, moreDiags := decodeProviderVersionConstraintsArgument(addr, content.Attributes["constraints"])
+	ret.versionConstraints = constraints
+	diags = diags.Append(moreDiags)
+
+	hashes, moreDiags := decodeProviderHashesArgument(addr, content.Attributes["hashes"])
+	ret.hashes = hashes
+	diags = diags.Append(moreDiags)
+
+	return ret, diags
+}
+
+func decodeProviderVersionArgument(provider addrs.Provider, attr *hcl.Attribute) (getproviders.Version, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	if attr == nil {
+		// It's not okay to omit this argument, but the caller should already
+		// have generated diagnostics about that.
+		return getproviders.UnspecifiedVersion, diags
+	}
+	expr := attr.Expr
+
+	var raw *string
+	hclDiags := gohcl.DecodeExpression(expr, nil, &raw)
+	diags = diags.Append(hclDiags)
+	if hclDiags.HasErrors() {
+		return getproviders.UnspecifiedVersion, diags
+	}
+	if raw == nil {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Missing required argument",
+			Detail:   "A provider lock block must contain a \"version\" argument.",
+			Subject:  expr.Range().Ptr(), // the range for a missing argument's expression is the body's missing item range
+		})
+		return getproviders.UnspecifiedVersion, diags
+	}
+	version, err := getproviders.ParseVersion(*raw)
+	if err != nil {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider version number",
+			Detail:   fmt.Sprintf("The selected version number for provider %s is invalid: %s.", provider, err),
+			Subject:  expr.Range().Ptr(),
+		})
+	}
+	if canon := version.String(); canon != *raw {
+		// Canonical forms are required in the lock file, to reduce the risk
+		// that a file diff will show changes that are entirely cosmetic.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider version number",
+			Detail:   fmt.Sprintf("The selected version number for provider %s must be written in normalized form: %q.", provider, canon),
+			Subject:  expr.Range().Ptr(),
+		})
+	}
+	return version, diags
+}
+
+func decodeProviderVersionConstraintsArgument(provider addrs.Provider, attr *hcl.Attribute) (getproviders.VersionConstraints, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	if attr == nil {
+		// It's okay to omit this argument.
+		return nil, diags
+	}
+	expr := attr.Expr
+
+	var raw string
+	hclDiags := gohcl.DecodeExpression(expr, nil, &raw)
+	diags = diags.Append(hclDiags)
+	if hclDiags.HasErrors() {
+		return nil, diags
+	}
+	constraints, err := getproviders.ParseVersionConstraints(raw)
+	if err != nil {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider version constraints",
+			Detail:   fmt.Sprintf("The recorded version constraints for provider %s are invalid: %s.", provider, err),
+			Subject:  expr.Range().Ptr(),
+		})
+	}
+	if canon := getproviders.VersionConstraintsString(constraints); canon != raw {
+		// Canonical forms are required in the lock file, to reduce the risk
+		// that a file diff will show changes that are entirely cosmetic.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider version constraints",
+			Detail:   fmt.Sprintf("The recorded version constraints for provider %s must be written in normalized form: %q.", provider, canon),
+			Subject:  expr.Range().Ptr(),
+		})
+	}
+
+	return constraints, diags
+}
+
+func decodeProviderHashesArgument(provider addrs.Provider, attr *hcl.Attribute) ([]getproviders.Hash, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	if attr == nil {
+		// It's okay to omit this argument.
+		return nil, diags
+	}
+	expr := attr.Expr
+
+	// We'll decode this argument using the HCL static analysis mode, because
+	// there's no reason for the hashes list to be dynamic and this way we can
+	// give more precise feedback on individual elements that are invalid,
+	// with direct source locations.
+	hashExprs, hclDiags := hcl.ExprList(expr)
+	diags = diags.Append(hclDiags)
+	if hclDiags.HasErrors() {
+		return nil, diags
+	}
+	if len(hashExprs) == 0 {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider hash set",
+			Detail:   "The \"hashes\" argument must either be omitted or contain at least one hash value.",
+			Subject:  expr.Range().Ptr(),
+		})
+		return nil, diags
+	}
+
+	ret := make([]getproviders.Hash, 0, len(hashExprs))
+	for _, hashExpr := range hashExprs {
+		var raw string
+		hclDiags := gohcl.DecodeExpression(hashExpr, nil, &raw)
+		diags = diags.Append(hclDiags)
+		if hclDiags.HasErrors() {
+			continue
+		}
+
+		hash, err := getproviders.ParseHash(raw)
+		if err != nil {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid provider hash string",
+				Detail:   fmt.Sprintf("Cannot interpret %q as a provider hash: %s.", raw, err),
+				Subject:  expr.Range().Ptr(),
+			})
+			continue
+		}
+
+		ret = append(ret, hash)
+	}
+
+	return ret, diags
+}
+
+func encodeHashSetTokens(hashes []getproviders.Hash) hclwrite.Tokens {
+	// We'll generate the source code in a low-level way here (direct
+	// token manipulation) because it's desirable to maintain exactly
+	// the layout implemented here so that diffs against the locks
+	// file are easy to read; we don't want potential future changes to
+	// hclwrite to inadvertently introduce whitespace changes here.
+	ret := hclwrite.Tokens{
+		{
+			Type:  hclsyntax.TokenOBrack,
+			Bytes: []byte{'['},
+		},
+		{
+			Type:  hclsyntax.TokenNewline,
+			Bytes: []byte{'\n'},
+		},
+	}
+
+	// Although lock.hashes is a slice, we de-dupe and sort it on
+	// initialization so it's normalized for interpretation as a logical
+	// set, and so we can just trust it's already in a good order here.
+	for _, hash := range hashes {
+		hashVal := cty.StringVal(hash.String())
+		ret = append(ret, hclwrite.TokensForValue(hashVal)...)
+		ret = append(ret, hclwrite.Tokens{
+			{
+				Type:  hclsyntax.TokenComma,
+				Bytes: []byte{','},
+			},
+			{
+				Type:  hclsyntax.TokenNewline,
+				Bytes: []byte{'\n'},
+			},
+		}...)
+	}
+	ret = append(ret, &hclwrite.Token{
+		Type:  hclsyntax.TokenCBrack,
+		Bytes: []byte{']'},
+	})
+
+	return ret
+}
diff --git a/v1.5.7/internal/depsfile/locks_file_test.go b/v1.5.7/internal/depsfile/locks_file_test.go
new file mode 100644
index 0000000..5b3d78a
--- /dev/null
+++ b/v1.5.7/internal/depsfile/locks_file_test.go
@@ -0,0 +1,277 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package depsfile
+
+import (
+	"bufio"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestLoadLocksFromFile(t *testing.T) {
+	// For ease of test maintenance we treat every file under
+	// test-data/locks-files as a test case which is subject
+	// at least to testing that it produces an expected set
+	// of diagnostics represented via specially-formatted comments
+	// in the fixture files (which might be the empty set, if
+	// there are no such comments).
+	//
+	// Some of the files also have additional assertions that
+	// are encoded in the test code below. These must pass
+	// in addition to the standard diagnostics tests, if present.
+	files, err := ioutil.ReadDir("testdata/locks-files")
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+
+	for _, info := range files {
+		testName := filepath.Base(info.Name())
+		filename := filepath.Join("testdata/locks-files", testName)
+		t.Run(testName, func(t *testing.T) {
+			f, err := os.Open(filename)
+			if err != nil {
+				t.Fatal(err.Error())
+			}
+			defer f.Close()
+			const errorPrefix = "# ERROR: "
+			const warningPrefix = "# WARNING: "
+			wantErrors := map[int]string{}
+			wantWarnings := map[int]string{}
+			sc := bufio.NewScanner(f)
+			lineNum := 1
+			for sc.Scan() {
+				l := sc.Text()
+				if pos := strings.Index(l, errorPrefix); pos != -1 {
+					wantSummary := l[pos+len(errorPrefix):]
+					wantErrors[lineNum] = wantSummary
+				}
+				if pos := strings.Index(l, warningPrefix); pos != -1 {
+					wantSummary := l[pos+len(warningPrefix):]
+					wantWarnings[lineNum] = wantSummary
+				}
+				lineNum++
+			}
+			if err := sc.Err(); err != nil {
+				t.Fatal(err.Error())
+			}
+
+			locks, diags := LoadLocksFromFile(filename)
+			gotErrors := map[int]string{}
+			gotWarnings := map[int]string{}
+			for _, diag := range diags {
+				summary := diag.Description().Summary
+				if diag.Source().Subject == nil {
+					// We don't expect any sourceless diagnostics here.
+					t.Errorf("unexpected sourceless diagnostic: %s", summary)
+					continue
+				}
+				lineNum := diag.Source().Subject.Start.Line
+				switch sev := diag.Severity(); sev {
+				case tfdiags.Error:
+					gotErrors[lineNum] = summary
+				case tfdiags.Warning:
+					gotWarnings[lineNum] = summary
+				default:
+					t.Errorf("unexpected diagnostic severity %s", sev)
+				}
+			}
+
+			if diff := cmp.Diff(wantErrors, gotErrors); diff != "" {
+				t.Errorf("wrong errors\n%s", diff)
+			}
+			if diff := cmp.Diff(wantWarnings, gotWarnings); diff != "" {
+				t.Errorf("wrong warnings\n%s", diff)
+			}
+
+			switch testName {
+			// These are the file-specific test assertions. Not all files
+			// need custom test assertions in addition to the standard
+			// diagnostics assertions implemented above, so the cases here
+			// don't need to be exhaustive for all files.
+			//
+			// Please keep these in alphabetical order so the list is easy
+			// to scan!
+
+			case "empty.hcl":
+				if got, want := len(locks.providers), 0; got != want {
+					t.Errorf("wrong number of providers %d; want %d", got, want)
+				}
+
+			case "valid-provider-locks.hcl":
+				if got, want := len(locks.providers), 3; got != want {
+					t.Errorf("wrong number of providers %d; want %d", got, want)
+				}
+
+				t.Run("version-only", func(t *testing.T) {
+					if lock := locks.Provider(addrs.MustParseProviderSourceString("terraform.io/test/version-only")); lock != nil {
+						if got, want := lock.Version().String(), "1.0.0"; got != want {
+							t.Errorf("wrong version\ngot:  %s\nwant: %s", got, want)
+						}
+						if got, want := getproviders.VersionConstraintsString(lock.VersionConstraints()), ""; got != want {
+							t.Errorf("wrong version constraints\ngot:  %s\nwant: %s", got, want)
+						}
+						if got, want := len(lock.hashes), 0; got != want {
+							t.Errorf("wrong number of hashes %d; want %d", got, want)
+						}
+					}
+				})
+
+				t.Run("version-and-constraints", func(t *testing.T) {
+					if lock := locks.Provider(addrs.MustParseProviderSourceString("terraform.io/test/version-and-constraints")); lock != nil {
+						if got, want := lock.Version().String(), "1.2.0"; got != want {
+							t.Errorf("wrong version\ngot:  %s\nwant: %s", got, want)
+						}
+						if got, want := getproviders.VersionConstraintsString(lock.VersionConstraints()), "~> 1.2"; got != want {
+							t.Errorf("wrong version constraints\ngot:  %s\nwant: %s", got, want)
+						}
+						if got, want := len(lock.hashes), 0; got != want {
+							t.Errorf("wrong number of hashes %d; want %d", got, want)
+						}
+					}
+				})
+
+				t.Run("all-the-things", func(t *testing.T) {
+					if lock := locks.Provider(addrs.MustParseProviderSourceString("terraform.io/test/all-the-things")); lock != nil {
+						if got, want := lock.Version().String(), "3.0.10"; got != want {
+							t.Errorf("wrong version\ngot:  %s\nwant: %s", got, want)
+						}
+						if got, want := getproviders.VersionConstraintsString(lock.VersionConstraints()), ">= 3.0.2"; got != want {
+							t.Errorf("wrong version constraints\ngot:  %s\nwant: %s", got, want)
+						}
+						wantHashes := []getproviders.Hash{
+							getproviders.MustParseHash("test:placeholder-hash-1"),
+							getproviders.MustParseHash("test:placeholder-hash-2"),
+							getproviders.MustParseHash("test:placeholder-hash-3"),
+						}
+						if diff := cmp.Diff(wantHashes, lock.hashes); diff != "" {
+							t.Errorf("wrong hashes\n%s", diff)
+						}
+					}
+				})
+			}
+		})
+	}
+}
+
+func TestLoadLocksFromFileAbsent(t *testing.T) {
+	t.Run("lock file is a directory", func(t *testing.T) {
+		// This can never happen when Terraform is the one generating the
+		// lock file, but might arise if the user makes a directory with the
+		// lock file's name for some reason. (There is no actual reason to do
+		// so, so that would always be a mistake.)
+		locks, diags := LoadLocksFromFile("testdata")
+		if len(locks.providers) != 0 {
+			t.Errorf("returned locks has providers; expected empty locks")
+		}
+		if !diags.HasErrors() {
+			t.Fatalf("LoadLocksFromFile succeeded; want error")
+		}
+		// This is a generic error message from HCL itself, so upgrading HCL
+		// in future might cause a different error message here.
+		want := `Failed to read file: The configuration file "testdata" could not be read.`
+		got := diags.Err().Error()
+		if got != want {
+			t.Errorf("wrong error message\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run("lock file doesn't exist", func(t *testing.T) {
+		locks, diags := LoadLocksFromFile("testdata/nonexist.hcl")
+		if len(locks.providers) != 0 {
+			t.Errorf("returned locks has providers; expected empty locks")
+		}
+		if !diags.HasErrors() {
+			t.Fatalf("LoadLocksFromFile succeeded; want error")
+		}
+		// This is a generic error message from HCL itself, so upgrading HCL
+		// in future might cause a different error message here.
+		want := `Failed to read file: The configuration file "testdata/nonexist.hcl" could not be read.`
+		got := diags.Err().Error()
+		if got != want {
+			t.Errorf("wrong error message\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+}
+
+func TestSaveLocksToFile(t *testing.T) {
+	locks := NewLocks()
+
+	fooProvider := addrs.MustParseProviderSourceString("test/foo")
+	barProvider := addrs.MustParseProviderSourceString("test/bar")
+	bazProvider := addrs.MustParseProviderSourceString("test/baz")
+	booProvider := addrs.MustParseProviderSourceString("test/boo")
+	oneDotOh := getproviders.MustParseVersion("1.0.0")
+	oneDotTwo := getproviders.MustParseVersion("1.2.0")
+	atLeastOneDotOh := getproviders.MustParseVersionConstraints(">= 1.0.0")
+	pessimisticOneDotOh := getproviders.MustParseVersionConstraints("~> 1")
+	abbreviatedOneDotTwo := getproviders.MustParseVersionConstraints("1.2")
+	hashes := []getproviders.Hash{
+		getproviders.MustParseHash("test:cccccccccccccccccccccccccccccccccccccccccccccccc"),
+		getproviders.MustParseHash("test:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
+		getproviders.MustParseHash("test:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
+	}
+	locks.SetProvider(fooProvider, oneDotOh, atLeastOneDotOh, hashes)
+	locks.SetProvider(barProvider, oneDotTwo, pessimisticOneDotOh, nil)
+	locks.SetProvider(bazProvider, oneDotTwo, nil, nil)
+	locks.SetProvider(booProvider, oneDotTwo, abbreviatedOneDotTwo, nil)
+
+	dir := t.TempDir()
+
+	filename := filepath.Join(dir, LockFilePath)
+	diags := SaveLocksToFile(locks, filename)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	fileInfo, err := os.Stat(filename)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+	if mode := fileInfo.Mode(); mode&0111 != 0 {
+		t.Fatalf("Expected lock file to be non-executable: %o", mode)
+	}
+
+	gotContentBytes, err := ioutil.ReadFile(filename)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+	gotContent := string(gotContentBytes)
+	wantContent := `# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/test/bar" {
+  version     = "1.2.0"
+  constraints = "~> 1.0"
+}
+
+provider "registry.terraform.io/test/baz" {
+  version = "1.2.0"
+}
+
+provider "registry.terraform.io/test/boo" {
+  version     = "1.2.0"
+  constraints = "1.2.0"
+}
+
+provider "registry.terraform.io/test/foo" {
+  version     = "1.0.0"
+  constraints = ">= 1.0.0"
+  hashes = [
+    "test:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+    "test:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+    "test:cccccccccccccccccccccccccccccccccccccccccccccccc",
+  ]
+}
+`
+	if diff := cmp.Diff(wantContent, gotContent); diff != "" {
+		t.Errorf("wrong result\n%s", diff)
+	}
+}
diff --git a/v1.5.7/internal/depsfile/locks_test.go b/v1.5.7/internal/depsfile/locks_test.go
new file mode 100644
index 0000000..eb371b4
--- /dev/null
+++ b/v1.5.7/internal/depsfile/locks_test.go
@@ -0,0 +1,312 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package depsfile
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+func TestLocksEqual(t *testing.T) {
+	boopProvider := addrs.NewDefaultProvider("boop")
+	v2 := getproviders.MustParseVersion("2.0.0")
+	v2LocalBuild := getproviders.MustParseVersion("2.0.0+awesomecorp.1")
+	v2GtConstraints := getproviders.MustParseVersionConstraints(">= 2.0.0")
+	v2EqConstraints := getproviders.MustParseVersionConstraints("2.0.0")
+	hash1 := getproviders.HashScheme("test").New("1")
+	hash2 := getproviders.HashScheme("test").New("2")
+	hash3 := getproviders.HashScheme("test").New("3")
+
+	equalBothWays := func(t *testing.T, a, b *Locks) {
+		t.Helper()
+		if !a.Equal(b) {
+			t.Errorf("a should be equal to b")
+		}
+		if !b.Equal(a) {
+			t.Errorf("b should be equal to a")
+		}
+	}
+	nonEqualBothWays := func(t *testing.T, a, b *Locks) {
+		t.Helper()
+		if a.Equal(b) {
+			t.Errorf("a should be equal to b")
+		}
+		if b.Equal(a) {
+			t.Errorf("b should be equal to a")
+		}
+	}
+
+	t.Run("both empty", func(t *testing.T) {
+		a := NewLocks()
+		b := NewLocks()
+		equalBothWays(t, a, b)
+	})
+	t.Run("an extra provider lock", func(t *testing.T) {
+		a := NewLocks()
+		b := NewLocks()
+		b.SetProvider(boopProvider, v2, v2GtConstraints, nil)
+		nonEqualBothWays(t, a, b)
+	})
+	t.Run("both have boop provider with same version", func(t *testing.T) {
+		a := NewLocks()
+		b := NewLocks()
+		// Note: the constraints are not part of the definition of "Equal", so they can differ
+		a.SetProvider(boopProvider, v2, v2GtConstraints, nil)
+		b.SetProvider(boopProvider, v2, v2EqConstraints, nil)
+		equalBothWays(t, a, b)
+	})
+	t.Run("both have boop provider with different versions", func(t *testing.T) {
+		a := NewLocks()
+		b := NewLocks()
+		a.SetProvider(boopProvider, v2, v2EqConstraints, nil)
+		b.SetProvider(boopProvider, v2LocalBuild, v2EqConstraints, nil)
+		nonEqualBothWays(t, a, b)
+	})
+	t.Run("both have boop provider with same version and same hashes", func(t *testing.T) {
+		a := NewLocks()
+		b := NewLocks()
+		hashes := []getproviders.Hash{hash1, hash2, hash3}
+		a.SetProvider(boopProvider, v2, v2EqConstraints, hashes)
+		b.SetProvider(boopProvider, v2, v2EqConstraints, hashes)
+		equalBothWays(t, a, b)
+	})
+	t.Run("both have boop provider with same version but different hashes", func(t *testing.T) {
+		a := NewLocks()
+		b := NewLocks()
+		hashesA := []getproviders.Hash{hash1, hash2}
+		hashesB := []getproviders.Hash{hash1, hash3}
+		a.SetProvider(boopProvider, v2, v2EqConstraints, hashesA)
+		b.SetProvider(boopProvider, v2, v2EqConstraints, hashesB)
+		nonEqualBothWays(t, a, b)
+	})
+}
+
+func TestLocksEqualProviderAddress(t *testing.T) {
+	boopProvider := addrs.NewDefaultProvider("boop")
+	v2 := getproviders.MustParseVersion("2.0.0")
+	v2LocalBuild := getproviders.MustParseVersion("2.0.0+awesomecorp.1")
+	v2GtConstraints := getproviders.MustParseVersionConstraints(">= 2.0.0")
+	v2EqConstraints := getproviders.MustParseVersionConstraints("2.0.0")
+	hash1 := getproviders.HashScheme("test").New("1")
+	hash2 := getproviders.HashScheme("test").New("2")
+	hash3 := getproviders.HashScheme("test").New("3")
+
+	equalProviderAddressBothWays := func(t *testing.T, a, b *Locks) {
+		t.Helper()
+		if !a.EqualProviderAddress(b) {
+			t.Errorf("a should be equal to b")
+		}
+		if !b.EqualProviderAddress(a) {
+			t.Errorf("b should be equal to a")
+		}
+	}
+	nonEqualProviderAddressBothWays := func(t *testing.T, a, b *Locks) {
+		t.Helper()
+		if a.EqualProviderAddress(b) {
+			t.Errorf("a should be equal to b")
+		}
+		if b.EqualProviderAddress(a) {
+			t.Errorf("b should be equal to a")
+		}
+	}
+
+	t.Run("both empty", func(t *testing.T) {
+		a := NewLocks()
+		b := NewLocks()
+		equalProviderAddressBothWays(t, a, b)
+	})
+	t.Run("an extra provider lock", func(t *testing.T) {
+		a := NewLocks()
+		b := NewLocks()
+		b.SetProvider(boopProvider, v2, v2GtConstraints, nil)
+		nonEqualProviderAddressBothWays(t, a, b)
+	})
+	t.Run("both have boop provider with different versions", func(t *testing.T) {
+		a := NewLocks()
+		b := NewLocks()
+		a.SetProvider(boopProvider, v2, v2EqConstraints, nil)
+		b.SetProvider(boopProvider, v2LocalBuild, v2EqConstraints, nil)
+		equalProviderAddressBothWays(t, a, b)
+	})
+	t.Run("both have boop provider with same version but different hashes", func(t *testing.T) {
+		a := NewLocks()
+		b := NewLocks()
+		hashesA := []getproviders.Hash{hash1, hash2}
+		hashesB := []getproviders.Hash{hash1, hash3}
+		a.SetProvider(boopProvider, v2, v2EqConstraints, hashesA)
+		b.SetProvider(boopProvider, v2, v2EqConstraints, hashesB)
+		equalProviderAddressBothWays(t, a, b)
+	})
+}
+
+func TestLocksProviderSetRemove(t *testing.T) {
+	beepProvider := addrs.NewDefaultProvider("beep")
+	boopProvider := addrs.NewDefaultProvider("boop")
+	v2 := getproviders.MustParseVersion("2.0.0")
+	v2EqConstraints := getproviders.MustParseVersionConstraints("2.0.0")
+	v2GtConstraints := getproviders.MustParseVersionConstraints(">= 2.0.0")
+	hash := getproviders.HashScheme("test").New("1")
+
+	locks := NewLocks()
+	if got, want := len(locks.AllProviders()), 0; got != want {
+		t.Fatalf("fresh locks object already has providers")
+	}
+
+	locks.SetProvider(boopProvider, v2, v2EqConstraints, []getproviders.Hash{hash})
+	{
+		got := locks.AllProviders()
+		want := map[addrs.Provider]*ProviderLock{
+			boopProvider: {
+				addr:               boopProvider,
+				version:            v2,
+				versionConstraints: v2EqConstraints,
+				hashes:             []getproviders.Hash{hash},
+			},
+		}
+		if diff := cmp.Diff(want, got, ProviderLockComparer); diff != "" {
+			t.Fatalf("wrong providers after SetProvider boop\n%s", diff)
+		}
+	}
+
+	locks.SetProvider(beepProvider, v2, v2GtConstraints, []getproviders.Hash{hash})
+	{
+		got := locks.AllProviders()
+		want := map[addrs.Provider]*ProviderLock{
+			boopProvider: {
+				addr:               boopProvider,
+				version:            v2,
+				versionConstraints: v2EqConstraints,
+				hashes:             []getproviders.Hash{hash},
+			},
+			beepProvider: {
+				addr:               beepProvider,
+				version:            v2,
+				versionConstraints: v2GtConstraints,
+				hashes:             []getproviders.Hash{hash},
+			},
+		}
+		if diff := cmp.Diff(want, got, ProviderLockComparer); diff != "" {
+			t.Fatalf("wrong providers after SetProvider beep\n%s", diff)
+		}
+	}
+
+	locks.RemoveProvider(boopProvider)
+	{
+		got := locks.AllProviders()
+		want := map[addrs.Provider]*ProviderLock{
+			beepProvider: {
+				addr:               beepProvider,
+				version:            v2,
+				versionConstraints: v2GtConstraints,
+				hashes:             []getproviders.Hash{hash},
+			},
+		}
+		if diff := cmp.Diff(want, got, ProviderLockComparer); diff != "" {
+			t.Fatalf("wrong providers after RemoveProvider boop\n%s", diff)
+		}
+	}
+
+	locks.RemoveProvider(beepProvider)
+	{
+		got := locks.AllProviders()
+		want := map[addrs.Provider]*ProviderLock{}
+		if diff := cmp.Diff(want, got, ProviderLockComparer); diff != "" {
+			t.Fatalf("wrong providers after RemoveProvider beep\n%s", diff)
+		}
+	}
+}
+
+func TestProviderLockContainsAll(t *testing.T) {
+	provider := addrs.NewDefaultProvider("provider")
+	v2 := getproviders.MustParseVersion("2.0.0")
+	v2EqConstraints := getproviders.MustParseVersionConstraints("2.0.0")
+
+	t.Run("non-symmetric", func(t *testing.T) {
+		target := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
+			"9r3i9a9QmASqMnQM",
+			"K43RHM2klOoywtyW",
+			"swJPXfuCNhJsTM5c",
+		})
+
+		original := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
+			"9r3i9a9QmASqMnQM",
+			"1ZAChGWUMWn4zmIk",
+			"K43RHM2klOoywtyW",
+			"HWjRvIuWZ1LVatnc",
+			"swJPXfuCNhJsTM5c",
+			"KwhJK4p/U2dqbKhI",
+		})
+
+		if !original.ContainsAll(target) {
+			t.Errorf("orginal should contain all hashes in target")
+		}
+		if target.ContainsAll(original) {
+			t.Errorf("target should not contain all hashes in orginal")
+		}
+	})
+
+	t.Run("symmetric", func(t *testing.T) {
+		target := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
+			"9r3i9a9QmASqMnQM",
+			"K43RHM2klOoywtyW",
+			"swJPXfuCNhJsTM5c",
+		})
+
+		original := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
+			"9r3i9a9QmASqMnQM",
+			"K43RHM2klOoywtyW",
+			"swJPXfuCNhJsTM5c",
+		})
+
+		if !original.ContainsAll(target) {
+			t.Errorf("orginal should contain all hashes in target")
+		}
+		if !target.ContainsAll(original) {
+			t.Errorf("target should not contain all hashes in orginal")
+		}
+	})
+
+	t.Run("edge case - null", func(t *testing.T) {
+		original := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
+			"9r3i9a9QmASqMnQM",
+			"K43RHM2klOoywtyW",
+			"swJPXfuCNhJsTM5c",
+		})
+
+		if !original.ContainsAll(nil) {
+			t.Fatalf("orginal should report true on nil")
+		}
+	})
+
+	t.Run("edge case - empty", func(t *testing.T) {
+		original := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
+			"9r3i9a9QmASqMnQM",
+			"K43RHM2klOoywtyW",
+			"swJPXfuCNhJsTM5c",
+		})
+
+		target := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{})
+
+		if !original.ContainsAll(target) {
+			t.Fatalf("orginal should report true on empty")
+		}
+	})
+
+	t.Run("edge case - original empty", func(t *testing.T) {
+		original := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{})
+
+		target := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
+			"9r3i9a9QmASqMnQM",
+			"K43RHM2klOoywtyW",
+			"swJPXfuCNhJsTM5c",
+		})
+
+		if original.ContainsAll(target) {
+			t.Fatalf("orginal should report false when empty")
+		}
+	})
+}
diff --git a/v1.5.7/internal/depsfile/paths.go b/v1.5.7/internal/depsfile/paths.go
new file mode 100644
index 0000000..806dba6
--- /dev/null
+++ b/v1.5.7/internal/depsfile/paths.go
@@ -0,0 +1,21 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package depsfile
+
+// LockFilePath is the path, relative to a configuration's root module
+// directory, where Terraform expects to find the dependency lock file for
+// that configuration.
+//
+// This file is intended to be kept in version control, so it lives directly
+// in the root module directory. The ".terraform" prefix is intended to
+// suggest that it's metadata about several types of objects that ultimately
+// end up in the .terraform directory after running "terraform init".
+const LockFilePath = ".terraform.lock.hcl"
+
+// DevOverrideFilePath is the path, relative to a configuration's root module
+// directory, where Terraform will look to find a possible override file that
+// represents a request to temporarily (within a single working directory only)
+// use specific local directories in place of packages that would normally
+// need to be installed from a remote location.
+const DevOverrideFilePath = ".terraform/dev-overrides.hcl"
diff --git a/v1.5.7/internal/depsfile/testdata/locks-files/empty.hcl b/v1.5.7/internal/depsfile/testdata/locks-files/empty.hcl
new file mode 100644
index 0000000..66169c2
--- /dev/null
+++ b/v1.5.7/internal/depsfile/testdata/locks-files/empty.hcl
@@ -0,0 +1 @@
+# An empty locks file is a bit of a degenerate case, but it is valid.
diff --git a/v1.5.7/internal/depsfile/testdata/locks-files/invalid-provider-addrs.hcl b/v1.5.7/internal/depsfile/testdata/locks-files/invalid-provider-addrs.hcl
new file mode 100644
index 0000000..d5d2cdb
--- /dev/null
+++ b/v1.5.7/internal/depsfile/testdata/locks-files/invalid-provider-addrs.hcl
@@ -0,0 +1,44 @@
+provider "" { # ERROR: Invalid provider source address
+
+}
+
+provider "hashicorp/aws" { # ERROR: Non-normalized provider source address
+
+}
+
+provider "aws" { # ERROR: Non-normalized provider source address
+
+}
+
+provider "too/many/parts/here" { # ERROR: Invalid provider source address
+
+}
+
+provider "Registry.terraform.io/example/example" { # ERROR: Non-normalized provider source address
+
+}
+
+provider "registry.terraform.io/eXample/example" { # ERROR: Non-normalized provider source address
+
+}
+
+provider "registry.terraform.io/example/Example" { # ERROR: Non-normalized provider source address
+
+}
+
+provider "this/one/okay" {
+  version = "1.0.0"
+}
+
+provider "this/one/okay" { # ERROR: Duplicate provider lock
+}
+
+# Legacy providers are not allowed, because they existed only to
+# support the Terraform 0.13 upgrade process.
+provider "registry.terraform.io/-/null" { # ERROR: Invalid provider source address
+}
+
+# Built-in providers are not allowed, because they are not versioned
+# independently of the Terraform CLI release they are embedded in.
+provider "terraform.io/builtin/foo" { # ERROR: Invalid provider source address
+}
diff --git a/v1.5.7/internal/depsfile/testdata/locks-files/invalid-versions.hcl b/v1.5.7/internal/depsfile/testdata/locks-files/invalid-versions.hcl
new file mode 100644
index 0000000..d1e9647
--- /dev/null
+++ b/v1.5.7/internal/depsfile/testdata/locks-files/invalid-versions.hcl
@@ -0,0 +1,30 @@
+provider "terraform.io/test/foo" {
+  version = "" # ERROR: Invalid provider version number
+}
+
+provider "terraform.io/test/bar" {
+  # The "v" prefix is not expected here
+  version = "v1.0.0" # ERROR: Invalid provider version number
+}
+
+provider "terraform.io/test/baz" {
+  # Must be written in the canonical form, with three parts
+  version = "1.0" # ERROR: Invalid provider version number
+}
+
+provider "terraform.io/test/boop" {
+  # Must be written in the canonical form, with three parts
+  version = "1" # ERROR: Invalid provider version number
+}
+
+provider "terraform.io/test/blep" {
+  # Mustn't use redundant extra zero padding
+  version = "1.02" # ERROR: Invalid provider version number
+}
+
+provider "terraform.io/test/huzzah" { # ERROR: Missing required argument
+}
+
+provider "terraform.io/test/huzznot" {
+  version = null # ERROR: Missing required argument
+}
diff --git a/v1.5.7/internal/depsfile/testdata/locks-files/unsupported-block.hcl b/v1.5.7/internal/depsfile/testdata/locks-files/unsupported-block.hcl
new file mode 100644
index 0000000..41321fc
--- /dev/null
+++ b/v1.5.7/internal/depsfile/testdata/locks-files/unsupported-block.hcl
@@ -0,0 +1,2 @@
+doodad "blah" { # ERROR: Unsupported block type
+}
diff --git a/v1.5.7/internal/depsfile/testdata/locks-files/valid-provider-locks.hcl b/v1.5.7/internal/depsfile/testdata/locks-files/valid-provider-locks.hcl
new file mode 100644
index 0000000..1d19116
--- /dev/null
+++ b/v1.5.7/internal/depsfile/testdata/locks-files/valid-provider-locks.hcl
@@ -0,0 +1,20 @@
+
+provider "terraform.io/test/version-only" {
+  version = "1.0.0"
+}
+
+provider "terraform.io/test/version-and-constraints" {
+  version = "1.2.0"
+  constraints = "~> 1.2"
+}
+
+provider "terraform.io/test/all-the-things" {
+  version = "3.0.10"
+  constraints = ">= 3.0.2"
+
+  hashes = [
+    "test:placeholder-hash-1",
+    "test:placeholder-hash-2",
+    "test:placeholder-hash-3",
+  ]
+}
diff --git a/v1.5.7/internal/depsfile/testing.go b/v1.5.7/internal/depsfile/testing.go
new file mode 100644
index 0000000..6962a10
--- /dev/null
+++ b/v1.5.7/internal/depsfile/testing.go
@@ -0,0 +1,25 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package depsfile
+
+import (
+	"github.com/google/go-cmp/cmp"
+)
+
+// ProviderLockComparer is an option for github.com/google/go-cmp/cmp that
+// specifies how to compare values of type depsfile.ProviderLock.
+//
+// Use this, rather than crafting comparison options yourself, in case the
+// comparison strategy needs to change in future due to implementation details
+// of the ProviderLock type.
+var ProviderLockComparer cmp.Option
+
+func init() {
+	// For now, direct comparison of the unexported fields is good enough
+	// because we store everything in a normalized form. If that changes
+	// later then we might need to write a custom transformer to a hidden
+	// type with exported fields, so we can retain the ability for cmp to
+	// still report differences deeply.
+	ProviderLockComparer = cmp.AllowUnexported(ProviderLock{})
+}
diff --git a/v1.5.7/internal/didyoumean/name_suggestion.go b/v1.5.7/internal/didyoumean/name_suggestion.go
new file mode 100644
index 0000000..c065370
--- /dev/null
+++ b/v1.5.7/internal/didyoumean/name_suggestion.go
@@ -0,0 +1,27 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package didyoumean
+
+import (
+	"github.com/agext/levenshtein"
+)
+
+// NameSuggestion tries to find a name from the given slice of suggested names
+// that is close to the given name and returns it if found. If no suggestion
+// is close enough, returns the empty string.
+//
+// The suggestions are tried in order, so earlier suggestions take precedence
+// if the given string is similar to two or more suggestions.
+//
+// This function is intended to be used with a relatively-small number of
+// suggestions. It's not optimized for hundreds or thousands of them.
+func NameSuggestion(given string, suggestions []string) string {
+	for _, suggestion := range suggestions {
+		dist := levenshtein.Distance(given, suggestion, nil)
+		if dist < 3 { // threshold determined experimentally
+			return suggestion
+		}
+	}
+	return ""
+}
diff --git a/v1.5.7/internal/didyoumean/name_suggestion_test.go b/v1.5.7/internal/didyoumean/name_suggestion_test.go
new file mode 100644
index 0000000..eb31a2b
--- /dev/null
+++ b/v1.5.7/internal/didyoumean/name_suggestion_test.go
@@ -0,0 +1,56 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package didyoumean
+
+import (
+	"testing"
+)
+
+func TestNameSuggestion(t *testing.T) {
+	var keywords = []string{"false", "true", "null"}
+
+	tests := []struct {
+		Input, Want string
+	}{
+		{"true", "true"},
+		{"false", "false"},
+		{"null", "null"},
+		{"bananas", ""},
+		{"NaN", ""},
+		{"Inf", ""},
+		{"Infinity", ""},
+		{"void", ""},
+		{"undefined", ""},
+
+		{"ture", "true"},
+		{"tru", "true"},
+		{"tre", "true"},
+		{"treu", "true"},
+		{"rtue", "true"},
+
+		{"flase", "false"},
+		{"fales", "false"},
+		{"flse", "false"},
+		{"fasle", "false"},
+		{"fasel", "false"},
+		{"flue", "false"},
+
+		{"nil", "null"},
+		{"nul", "null"},
+		{"unll", "null"},
+		{"nll", "null"},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Input, func(t *testing.T) {
+			got := NameSuggestion(test.Input, keywords)
+			if got != test.Want {
+				t.Errorf(
+					"wrong result\ninput: %q\ngot:   %q\nwant:  %q",
+					test.Input, got, test.Want,
+				)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/e2e/e2e.go b/v1.5.7/internal/e2e/e2e.go
new file mode 100644
index 0000000..74ce8bd
--- /dev/null
+++ b/v1.5.7/internal/e2e/e2e.go
@@ -0,0 +1,273 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package e2e
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+)
+
+// Type binary represents the combination of a compiled binary
+// and a temporary working directory to run it in.
+type binary struct {
+	binPath string
+	workDir string
+	env     []string
+}
+
+// NewBinary prepares a temporary directory containing the files from the
+// given fixture and returns an instance of type binary that can run
+// the generated binary in that directory.
+//
+// If the temporary directory cannot be created, a fixture of the given name
+// cannot be found, or if an error occurs while _copying_ the fixture files,
+// this function will panic. Tests should be written to assume that this
+// function always succeeds.
+func NewBinary(t *testing.T, binaryPath, workingDir string) *binary {
+	tmpDir, err := filepath.EvalSymlinks(t.TempDir())
+	if err != nil {
+		panic(err)
+	}
+
+	// For our purposes here we do a very simplistic file copy that doesn't
+	// attempt to preserve file permissions, attributes, alternate data
+	// streams, etc. Since we only have to deal with our own fixtures in
+	// the testdata subdir, we know we don't need to deal with anything
+	// of this nature.
+	err = filepath.Walk(workingDir, func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+		if path == workingDir {
+			// nothing to do at the root
+			return nil
+		}
+
+		if filepath.Base(path) == ".exists" {
+			// We use this file just to let git know the "empty" fixture
+			// exists. It is not used by any test.
+			return nil
+		}
+
+		srcFn := path
+
+		path, err = filepath.Rel(workingDir, path)
+		if err != nil {
+			return err
+		}
+
+		dstFn := filepath.Join(tmpDir, path)
+
+		if info.IsDir() {
+			return os.Mkdir(dstFn, os.ModePerm)
+		}
+
+		src, err := os.Open(srcFn)
+		if err != nil {
+			return err
+		}
+		dst, err := os.OpenFile(dstFn, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.ModePerm)
+		if err != nil {
+			return err
+		}
+
+		_, err = io.Copy(dst, src)
+		if err != nil {
+			return err
+		}
+
+		if err := src.Close(); err != nil {
+			return err
+		}
+		if err := dst.Close(); err != nil {
+			return err
+		}
+
+		return nil
+	})
+	if err != nil {
+		panic(err)
+	}
+
+	return &binary{
+		binPath: binaryPath,
+		workDir: tmpDir,
+	}
+}
+
+// AddEnv appends an entry to the environment variable table passed to any
+// commands subsequently run.
+func (b *binary) AddEnv(entry string) {
+	b.env = append(b.env, entry)
+}
+
+// Cmd returns an exec.Cmd pre-configured to run the generated Terraform
+// binary with the given arguments in the temporary working directory.
+//
+// The returned object can be mutated by the caller to customize how the
+// process will be run, before calling Run.
+func (b *binary) Cmd(args ...string) *exec.Cmd {
+	cmd := exec.Command(b.binPath, args...)
+	cmd.Dir = b.workDir
+	cmd.Env = os.Environ()
+
+	// Disable checkpoint since we don't want to harass that service when
+	// our tests run. (This does, of course, mean we can't actually do
+	// end-to-end testing of our Checkpoint interactions.)
+	cmd.Env = append(cmd.Env, "CHECKPOINT_DISABLE=1")
+
+	cmd.Env = append(cmd.Env, b.env...)
+
+	return cmd
+}
+
+// Run executes the generated Terraform binary with the given arguments
+// and returns the bytes that it wrote to both stdout and stderr.
+//
+// This is a simple way to run Terraform for non-interactive commands
+// that don't need any special environment variables. For more complex
+// situations, use Cmd and customize the command before running it.
+func (b *binary) Run(args ...string) (stdout, stderr string, err error) {
+	cmd := b.Cmd(args...)
+	cmd.Stdin = nil
+	cmd.Stdout = &bytes.Buffer{}
+	cmd.Stderr = &bytes.Buffer{}
+	err = cmd.Run()
+	stdout = cmd.Stdout.(*bytes.Buffer).String()
+	stderr = cmd.Stderr.(*bytes.Buffer).String()
+	return
+}
+
+// Path returns a file path within the temporary working directory by
+// appending the given arguments as path segments.
+func (b *binary) Path(parts ...string) string {
+	args := make([]string, 0, len(parts)+1)
+	args = append(args, b.workDir)
+	args = append(args, parts...)
+	return filepath.Join(args...)
+}
+
+// OpenFile is a helper for easily opening a file from the working directory
+// for reading.
+func (b *binary) OpenFile(path ...string) (*os.File, error) {
+	flatPath := b.Path(path...)
+	return os.Open(flatPath)
+}
+
+// ReadFile is a helper for easily reading a whole file from the working
+// directory.
+func (b *binary) ReadFile(path ...string) ([]byte, error) {
+	flatPath := b.Path(path...)
+	return ioutil.ReadFile(flatPath)
+}
+
+// FileExists is a helper for easily testing whether a particular file
+// exists in the working directory.
+func (b *binary) FileExists(path ...string) bool {
+	flatPath := b.Path(path...)
+	_, err := os.Stat(flatPath)
+	return !os.IsNotExist(err)
+}
+
+// LocalState is a helper for easily reading the local backend's state file
+// terraform.tfstate from the working directory.
+func (b *binary) LocalState() (*states.State, error) {
+	return b.StateFromFile("terraform.tfstate")
+}
+
+// StateFromFile is a helper for easily reading a state snapshot from a file
+// on disk relative to the working directory.
+func (b *binary) StateFromFile(filename string) (*states.State, error) {
+	f, err := b.OpenFile(filename)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	stateFile, err := statefile.Read(f)
+	if err != nil {
+		return nil, fmt.Errorf("Error reading statefile: %s", err)
+	}
+	return stateFile.State, nil
+}
+
+// Plan is a helper for easily reading a plan file from the working directory.
+func (b *binary) Plan(path string) (*plans.Plan, error) {
+	path = b.Path(path)
+	pr, err := planfile.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer pr.Close()
+	plan, err := pr.ReadPlan()
+	if err != nil {
+		return nil, err
+	}
+	return plan, nil
+}
+
+// SetLocalState is a helper for easily writing to the file the local backend
+// uses for state in the working directory. This does not go through the
+// actual local backend code, so processing such as management of serials
+// does not apply and the given state will simply be written verbatim.
+func (b *binary) SetLocalState(state *states.State) error {
+	path := b.Path("terraform.tfstate")
+	f, err := os.OpenFile(path, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, os.ModePerm)
+	if err != nil {
+		return fmt.Errorf("failed to create temporary state file %s: %s", path, err)
+	}
+	defer f.Close()
+
+	sf := &statefile.File{
+		Serial:  0,
+		Lineage: "fake-for-testing",
+		State:   state,
+	}
+	return statefile.Write(sf, f)
+}
+
+func GoBuild(pkgPath, tmpPrefix string) string {
+	dir, prefix := filepath.Split(tmpPrefix)
+	tmpFile, err := ioutil.TempFile(dir, prefix)
+	if err != nil {
+		panic(err)
+	}
+	tmpFilename := tmpFile.Name()
+	if err = tmpFile.Close(); err != nil {
+		panic(err)
+	}
+
+	cmd := exec.Command(
+		"go", "build",
+		"-o", tmpFilename,
+		pkgPath,
+	)
+	cmd.Stderr = os.Stderr
+	cmd.Stdout = os.Stdout
+
+	err = cmd.Run()
+	if err != nil {
+		// The go compiler will have already produced some error messages
+		// on stderr by the time we get here.
+		panic(fmt.Sprintf("failed to build executable: %s", err))
+	}
+
+	return tmpFilename
+}
+
+// WorkDir() returns the binary workdir
+func (b *binary) WorkDir() string {
+	return b.workDir
+}
diff --git a/v1.5.7/internal/experiments/doc.go b/v1.5.7/internal/experiments/doc.go
new file mode 100644
index 0000000..5f273cf
--- /dev/null
+++ b/v1.5.7/internal/experiments/doc.go
@@ -0,0 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package experiments contains the models and logic for opt-in experiments
+// that can be activated for a particular Terraform module.
+//
+// We use experiments to get feedback on new configuration language features
+// in a way that permits breaking changes without waiting for a future minor
+// release. Any feature behind an experiment flag is subject to change in any
+// way in even a patch release, until we have enough confidence about the
+// design of the feature to make compatibility commitments about it.
+package experiments
diff --git a/v1.5.7/internal/experiments/errors.go b/v1.5.7/internal/experiments/errors.go
new file mode 100644
index 0000000..549f37e
--- /dev/null
+++ b/v1.5.7/internal/experiments/errors.go
@@ -0,0 +1,29 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package experiments
+
+import (
+	"fmt"
+)
+
+// UnavailableError is the error type returned by GetCurrent when the requested
+// experiment is not recognized at all.
+type UnavailableError struct {
+	ExperimentName string
+}
+
+func (e UnavailableError) Error() string {
+	return fmt.Sprintf("no current experiment is named %q", e.ExperimentName)
+}
+
+// ConcludedError is the error type returned by GetCurrent when the requested
+// experiment is recognized as concluded.
+type ConcludedError struct {
+	ExperimentName string
+	Message        string
+}
+
+func (e ConcludedError) Error() string {
+	return fmt.Sprintf("experiment %q has concluded: %s", e.ExperimentName, e.Message)
+}
diff --git a/v1.5.7/internal/experiments/experiment.go b/v1.5.7/internal/experiments/experiment.go
new file mode 100644
index 0000000..901c4e5
--- /dev/null
+++ b/v1.5.7/internal/experiments/experiment.go
@@ -0,0 +1,105 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package experiments
+
+// Experiment represents a particular experiment, which can be activated
+// independently of all other experiments.
+type Experiment string
+
+// All active and defunct experiments must be represented by constants whose
+// internal string values are unique.
+//
+// Each of these declared constants must also be registered as either a
+// current or a defunct experiment in the init() function below.
+//
+// Each experiment is represented by a string that must be a valid HCL
+// identifier so that it can be specified in configuration.
+const (
+	VariableValidation             = Experiment("variable_validation")
+	ModuleVariableOptionalAttrs    = Experiment("module_variable_optional_attrs")
+	SuppressProviderSensitiveAttrs = Experiment("provider_sensitive_attrs")
+	ConfigDrivenMove               = Experiment("config_driven_move")
+	PreconditionsPostconditions    = Experiment("preconditions_postconditions")
+)
+
+func init() {
+	// Each experiment constant defined above must be registered here as either
+	// a current or a concluded experiment.
+	registerConcludedExperiment(VariableValidation, "Custom variable validation can now be used by default, without enabling an experiment.")
+	registerConcludedExperiment(SuppressProviderSensitiveAttrs, "Provider-defined sensitive attributes are now redacted by default, without enabling an experiment.")
+	registerConcludedExperiment(ConfigDrivenMove, "Declarations of moved resource instances using \"moved\" blocks can now be used by default, without enabling an experiment.")
+	registerConcludedExperiment(PreconditionsPostconditions, "Condition blocks can now be used by default, without enabling an experiment.")
+	registerConcludedExperiment(ModuleVariableOptionalAttrs, "The final feature corresponding to this experiment differs from the experimental form and is available in the Terraform language from Terraform v1.3.0 onwards.")
+}
+
+// GetCurrent takes an experiment name and returns the experiment value
+// representing that expression if and only if it is a current experiment.
+//
+// If the selected experiment is concluded, GetCurrent will return an
+// error of type ConcludedError whose message hopefully includes some guidance
+// for users of the experiment on how to migrate to a stable feature that
+// succeeded it.
+//
+// If the selected experiment is not known at all, GetCurrent will return an
+// error of type UnavailableError.
+func GetCurrent(name string) (Experiment, error) {
+	exp := Experiment(name)
+	if currentExperiments.Has(exp) {
+		return exp, nil
+	}
+
+	if msg, concluded := concludedExperiments[exp]; concluded {
+		return Experiment(""), ConcludedError{ExperimentName: name, Message: msg}
+	}
+
+	return Experiment(""), UnavailableError{ExperimentName: name}
+}
+
+// Keyword returns the keyword that would be used to activate this experiment
+// in the configuration.
+func (e Experiment) Keyword() string {
+	return string(e)
+}
+
+// IsCurrent returns true if the receiver is considered a currently-selectable
+// experiment.
+func (e Experiment) IsCurrent() bool {
+	return currentExperiments.Has(e)
+}
+
+// IsConcluded returns true if the receiver is a concluded experiment.
+func (e Experiment) IsConcluded() bool {
+	_, exists := concludedExperiments[e]
+	return exists
+}
+
+// currentExperiments are those which are available to activate in the current
+// version of Terraform.
+//
+// Members of this set are registered in the init function above.
+var currentExperiments = make(Set)
+
+// concludedExperiments are those which were available to activate in an earlier
+// version of Terraform but are no longer available, either because the feature
+// in question has been implemented or because the experiment failed and the
+// feature was abandoned. Each experiment maps to a message describing the
+// outcome, so we can give users feedback about what they might do in modules
+// using concluded experiments.
+//
+// After an experiment has been concluded for a whole major release span it can
+// be removed, since we expect users to perform upgrades one major release at
+// at time without skipping and thus they will see the concludedness error
+// message as they upgrade through a prior major version.
+//
+// Members of this map are registered in the init function above.
+var concludedExperiments = make(map[Experiment]string)
+
+//lint:ignore U1000 No experiments are active
+func registerCurrentExperiment(exp Experiment) {
+	currentExperiments.Add(exp)
+}
+
+func registerConcludedExperiment(exp Experiment, message string) {
+	concludedExperiments[exp] = message
+}
diff --git a/v1.5.7/internal/experiments/set.go b/v1.5.7/internal/experiments/set.go
new file mode 100644
index 0000000..5366de5
--- /dev/null
+++ b/v1.5.7/internal/experiments/set.go
@@ -0,0 +1,49 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package experiments
+
+// Set is a collection of experiments where every experiment is either a member
+// or not.
+type Set map[Experiment]struct{}
+
+// NewSet constructs a new Set with the given experiments as its initial members.
+func NewSet(exps ...Experiment) Set {
+	ret := make(Set)
+	for _, exp := range exps {
+		ret.Add(exp)
+	}
+	return ret
+}
+
+// SetUnion constructs a new Set containing the members of all of the given
+// sets.
+func SetUnion(sets ...Set) Set {
+	ret := make(Set)
+	for _, set := range sets {
+		for exp := range set {
+			ret.Add(exp)
+		}
+	}
+	return ret
+}
+
+// Add inserts the given experiment into the set.
+//
+// If the given experiment is already present then this is a no-op.
+func (s Set) Add(exp Experiment) {
+	s[exp] = struct{}{}
+}
+
+// Remove takes the given experiment out of the set.
+//
+// If the given experiment not already present then this is a no-op.
+func (s Set) Remove(exp Experiment) {
+	delete(s, exp)
+}
+
+// Has tests whether the given experiment is in the receiving set.
+func (s Set) Has(exp Experiment) bool {
+	_, ok := s[exp]
+	return ok
+}
diff --git a/v1.5.7/internal/experiments/testing.go b/v1.5.7/internal/experiments/testing.go
new file mode 100644
index 0000000..d05da30
--- /dev/null
+++ b/v1.5.7/internal/experiments/testing.go
@@ -0,0 +1,36 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package experiments
+
+import (
+	"testing"
+)
+
+// OverrideForTesting temporarily overrides the global tables
+// of experiments in order to allow for a predictable set when unit testing
+// the experiments infrastructure code.
+//
+// The correct way to use this function is to defer a call to its result so
+// that the original tables can be restored at the conclusion of the calling
+// test:
+//
+//	defer experiments.OverrideForTesting(t, current, concluded)()
+//
+// This function modifies global variables that are normally fixed throughout
+// our execution, so this function must not be called from non-test code and
+// any test using it cannot safely run concurrently with other tests.
+func OverrideForTesting(t *testing.T, current Set, concluded map[Experiment]string) func() {
+	// We're not currently using the given *testing.T in here, but we're
+	// requiring it anyway in case we might need it in future, and because
+	// it hopefully reinforces that only test code should be calling this.
+
+	realCurrents := currentExperiments
+	realConcludeds := concludedExperiments
+	currentExperiments = current
+	concludedExperiments = concluded
+	return func() {
+		currentExperiments = realCurrents
+		concludedExperiments = realConcludeds
+	}
+}
diff --git a/v1.5.7/internal/genconfig/doc.go b/v1.5.7/internal/genconfig/doc.go
new file mode 100644
index 0000000..c1d7fd4
--- /dev/null
+++ b/v1.5.7/internal/genconfig/doc.go
@@ -0,0 +1,2 @@
+// Package genconfig implements config generation from provided state values.
+package genconfig
diff --git a/v1.5.7/internal/genconfig/generate_config.go b/v1.5.7/internal/genconfig/generate_config.go
new file mode 100644
index 0000000..8d3b56c
--- /dev/null
+++ b/v1.5.7/internal/genconfig/generate_config.go
@@ -0,0 +1,589 @@
+package genconfig
+
+import (
+	"fmt"
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclwrite"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// GenerateResourceContents generates HCL configuration code for the provided
+// resource and state value.
+//
+// If you want to generate actual valid Terraform code you should follow this
+// call up with a call to WrapResourceContents, which will place a Terraform
+// resource header around the attributes and blocks returned by this function.
+func GenerateResourceContents(addr addrs.AbsResourceInstance,
+	schema *configschema.Block,
+	pc addrs.LocalProviderConfig,
+	stateVal cty.Value) (string, tfdiags.Diagnostics) {
+	var buf strings.Builder
+
+	var diags tfdiags.Diagnostics
+
+	if pc.LocalName != addr.Resource.Resource.ImpliedProvider() || pc.Alias != "" {
+		buf.WriteString(strings.Repeat(" ", 2))
+		buf.WriteString(fmt.Sprintf("provider = %s\n", pc.StringCompact()))
+	}
+
+	stateVal = omitUnknowns(stateVal)
+	if stateVal.RawEquals(cty.NilVal) {
+		diags = diags.Append(writeConfigAttributes(addr, &buf, schema.Attributes, 2))
+		diags = diags.Append(writeConfigBlocks(addr, &buf, schema.BlockTypes, 2))
+	} else {
+		diags = diags.Append(writeConfigAttributesFromExisting(addr, &buf, stateVal, schema.Attributes, 2))
+		diags = diags.Append(writeConfigBlocksFromExisting(addr, &buf, stateVal, schema.BlockTypes, 2))
+	}
+
+	// The output better be valid HCL which can be parsed and formatted.
+	formatted := hclwrite.Format([]byte(buf.String()))
+	return string(formatted), diags
+}
+
+func WrapResourceContents(addr addrs.AbsResourceInstance, config string) string {
+	var buf strings.Builder
+
+	buf.WriteString(fmt.Sprintf("resource %q %q {\n", addr.Resource.Resource.Type, addr.Resource.Resource.Name))
+	buf.WriteString(config)
+	buf.WriteString("}")
+
+	// The output better be valid HCL which can be parsed and formatted.
+	formatted := hclwrite.Format([]byte(buf.String()))
+	return string(formatted)
+}
+
+func writeConfigAttributes(addr addrs.AbsResourceInstance, buf *strings.Builder, attrs map[string]*configschema.Attribute, indent int) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	if len(attrs) == 0 {
+		return diags
+	}
+
+	// Get a list of sorted attribute names so the output will be consistent between runs.
+	keys := make([]string, 0, len(attrs))
+	for k := range attrs {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+
+	for i := range keys {
+		name := keys[i]
+		attrS := attrs[name]
+		if attrS.NestedType != nil {
+			diags = diags.Append(writeConfigNestedTypeAttribute(addr, buf, name, attrS, indent))
+			continue
+		}
+		if attrS.Required {
+			buf.WriteString(strings.Repeat(" ", indent))
+			buf.WriteString(fmt.Sprintf("%s = ", name))
+			tok := hclwrite.TokensForValue(attrS.EmptyValue())
+			if _, err := tok.WriteTo(buf); err != nil {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagWarning,
+					Summary:  "Skipped part of config generation",
+					Detail:   fmt.Sprintf("Could not create attribute %s in %s when generating import configuration. The plan will likely report the missing attribute as being deleted.", name, addr),
+					Extra:    err,
+				})
+				continue
+			}
+			writeAttrTypeConstraint(buf, attrS)
+		} else if attrS.Optional {
+			buf.WriteString(strings.Repeat(" ", indent))
+			buf.WriteString(fmt.Sprintf("%s = ", name))
+			tok := hclwrite.TokensForValue(attrS.EmptyValue())
+			if _, err := tok.WriteTo(buf); err != nil {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagWarning,
+					Summary:  "Skipped part of config generation",
+					Detail:   fmt.Sprintf("Could not create attribute %s in %s when generating import configuration. The plan will likely report the missing attribute as being deleted.", name, addr),
+					Extra:    err,
+				})
+				continue
+			}
+			writeAttrTypeConstraint(buf, attrS)
+		}
+	}
+	return diags
+}
+
+func writeConfigAttributesFromExisting(addr addrs.AbsResourceInstance, buf *strings.Builder, stateVal cty.Value, attrs map[string]*configschema.Attribute, indent int) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+	if len(attrs) == 0 {
+		return diags
+	}
+
+	// Get a list of sorted attribute names so the output will be consistent between runs.
+	keys := make([]string, 0, len(attrs))
+	for k := range attrs {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+
+	for i := range keys {
+		name := keys[i]
+		attrS := attrs[name]
+		if attrS.NestedType != nil {
+			writeConfigNestedTypeAttributeFromExisting(addr, buf, name, attrS, stateVal, indent)
+			continue
+		}
+
+		// Exclude computed-only attributes
+		if attrS.Required || attrS.Optional {
+			buf.WriteString(strings.Repeat(" ", indent))
+			buf.WriteString(fmt.Sprintf("%s = ", name))
+
+			var val cty.Value
+			if !stateVal.IsNull() && stateVal.Type().HasAttribute(name) {
+				val = stateVal.GetAttr(name)
+			} else {
+				val = attrS.EmptyValue()
+			}
+			if val.Type() == cty.String {
+				// SHAMELESS HACK: If we have "" for an optional value, assume
+				// it is actually null, due to the legacy SDK.
+				if !val.IsNull() && attrS.Optional && len(val.AsString()) == 0 {
+					val = attrS.EmptyValue()
+				}
+			}
+			if attrS.Sensitive || val.IsMarked() {
+				buf.WriteString("null # sensitive")
+			} else {
+				tok := hclwrite.TokensForValue(val)
+				if _, err := tok.WriteTo(buf); err != nil {
+					diags = diags.Append(&hcl.Diagnostic{
+						Severity: hcl.DiagWarning,
+						Summary:  "Skipped part of config generation",
+						Detail:   fmt.Sprintf("Could not create attribute %s in %s when generating import configuration. The plan will likely report the missing attribute as being deleted.", name, addr),
+						Extra:    err,
+					})
+					continue
+				}
+			}
+
+			buf.WriteString("\n")
+		}
+	}
+	return diags
+}
+
+func writeConfigBlocks(addr addrs.AbsResourceInstance, buf *strings.Builder, blocks map[string]*configschema.NestedBlock, indent int) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	if len(blocks) == 0 {
+		return diags
+	}
+
+	// Get a list of sorted block names so the output will be consistent between runs.
+	names := make([]string, 0, len(blocks))
+	for k := range blocks {
+		names = append(names, k)
+	}
+	sort.Strings(names)
+
+	for i := range names {
+		name := names[i]
+		blockS := blocks[name]
+		diags = diags.Append(writeConfigNestedBlock(addr, buf, name, blockS, indent))
+	}
+	return diags
+}
+
+func writeConfigNestedBlock(addr addrs.AbsResourceInstance, buf *strings.Builder, name string, schema *configschema.NestedBlock, indent int) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	switch schema.Nesting {
+	case configschema.NestingSingle, configschema.NestingGroup:
+		buf.WriteString(strings.Repeat(" ", indent))
+		buf.WriteString(fmt.Sprintf("%s {", name))
+		writeBlockTypeConstraint(buf, schema)
+		diags = diags.Append(writeConfigAttributes(addr, buf, schema.Attributes, indent+2))
+		diags = diags.Append(writeConfigBlocks(addr, buf, schema.BlockTypes, indent+2))
+		buf.WriteString("}\n")
+		return diags
+	case configschema.NestingList, configschema.NestingSet:
+		buf.WriteString(strings.Repeat(" ", indent))
+		buf.WriteString(fmt.Sprintf("%s {", name))
+		writeBlockTypeConstraint(buf, schema)
+		diags = diags.Append(writeConfigAttributes(addr, buf, schema.Attributes, indent+2))
+		diags = diags.Append(writeConfigBlocks(addr, buf, schema.BlockTypes, indent+2))
+		buf.WriteString("}\n")
+		return diags
+	case configschema.NestingMap:
+		buf.WriteString(strings.Repeat(" ", indent))
+		// we use an arbitrary placeholder key (block label) "key"
+		buf.WriteString(fmt.Sprintf("%s \"key\" {", name))
+		writeBlockTypeConstraint(buf, schema)
+		diags = diags.Append(writeConfigAttributes(addr, buf, schema.Attributes, indent+2))
+		diags = diags.Append(writeConfigBlocks(addr, buf, schema.BlockTypes, indent+2))
+		buf.WriteString(strings.Repeat(" ", indent))
+		buf.WriteString("}\n")
+		return diags
+	default:
+		// This should not happen, the above should be exhaustive.
+		panic(fmt.Errorf("unsupported NestingMode %s", schema.Nesting.String()))
+	}
+}
+
+func writeConfigNestedTypeAttribute(addr addrs.AbsResourceInstance, buf *strings.Builder, name string, schema *configschema.Attribute, indent int) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	buf.WriteString(strings.Repeat(" ", indent))
+	buf.WriteString(fmt.Sprintf("%s = ", name))
+
+	switch schema.NestedType.Nesting {
+	case configschema.NestingSingle:
+		buf.WriteString("{")
+		writeAttrTypeConstraint(buf, schema)
+		diags = diags.Append(writeConfigAttributes(addr, buf, schema.NestedType.Attributes, indent+2))
+		buf.WriteString(strings.Repeat(" ", indent))
+		buf.WriteString("}\n")
+		return diags
+	case configschema.NestingList, configschema.NestingSet:
+		buf.WriteString("[{")
+		writeAttrTypeConstraint(buf, schema)
+		diags = diags.Append(writeConfigAttributes(addr, buf, schema.NestedType.Attributes, indent+2))
+		buf.WriteString(strings.Repeat(" ", indent))
+		buf.WriteString("}]\n")
+		return diags
+	case configschema.NestingMap:
+		buf.WriteString("{")
+		writeAttrTypeConstraint(buf, schema)
+		buf.WriteString(strings.Repeat(" ", indent+2))
+		// we use an arbitrary placeholder key "key"
+		buf.WriteString("key = {\n")
+		diags = diags.Append(writeConfigAttributes(addr, buf, schema.NestedType.Attributes, indent+4))
+		buf.WriteString(strings.Repeat(" ", indent+2))
+		buf.WriteString("}\n")
+		buf.WriteString(strings.Repeat(" ", indent))
+		buf.WriteString("}\n")
+		return diags
+	default:
+		// This should not happen, the above should be exhaustive.
+		panic(fmt.Errorf("unsupported NestingMode %s", schema.NestedType.Nesting.String()))
+	}
+}
+
+func writeConfigBlocksFromExisting(addr addrs.AbsResourceInstance, buf *strings.Builder, stateVal cty.Value, blocks map[string]*configschema.NestedBlock, indent int) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	if len(blocks) == 0 {
+		return diags
+	}
+
+	// Get a list of sorted block names so the output will be consistent between runs.
+	names := make([]string, 0, len(blocks))
+	for k := range blocks {
+		names = append(names, k)
+	}
+	sort.Strings(names)
+
+	for _, name := range names {
+		blockS := blocks[name]
+		// This shouldn't happen in real usage; state always has all values (set
+		// to null as needed), but it protects against panics in tests (and any
+		// really weird and unlikely cases).
+		if !stateVal.Type().HasAttribute(name) {
+			continue
+		}
+		blockVal := stateVal.GetAttr(name)
+		diags = diags.Append(writeConfigNestedBlockFromExisting(addr, buf, name, blockS, blockVal, indent))
+	}
+
+	return diags
+}
+
+func writeConfigNestedTypeAttributeFromExisting(addr addrs.AbsResourceInstance, buf *strings.Builder, name string, schema *configschema.Attribute, stateVal cty.Value, indent int) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	switch schema.NestedType.Nesting {
+	case configschema.NestingSingle:
+		if schema.Sensitive || stateVal.IsMarked() {
+			buf.WriteString(strings.Repeat(" ", indent))
+			buf.WriteString(fmt.Sprintf("%s = {} # sensitive\n", name))
+			return diags
+		}
+
+		// This shouldn't happen in real usage; state always has all values (set
+		// to null as needed), but it protects against panics in tests (and any
+		// really weird and unlikely cases).
+		if !stateVal.Type().HasAttribute(name) {
+			return diags
+		}
+		nestedVal := stateVal.GetAttr(name)
+
+		if nestedVal.IsNull() {
+			// There is a difference between a null object, and an object with
+			// no attributes.
+			buf.WriteString(strings.Repeat(" ", indent))
+			buf.WriteString(fmt.Sprintf("%s = null\n", name))
+			return diags
+		}
+
+		buf.WriteString(strings.Repeat(" ", indent))
+		buf.WriteString(fmt.Sprintf("%s = {\n", name))
+		diags = diags.Append(writeConfigAttributesFromExisting(addr, buf, nestedVal, schema.NestedType.Attributes, indent+2))
+		buf.WriteString("}\n")
+		return diags
+
+	case configschema.NestingList, configschema.NestingSet:
+
+		if schema.Sensitive || stateVal.IsMarked() {
+			buf.WriteString(strings.Repeat(" ", indent))
+			buf.WriteString(fmt.Sprintf("%s = [] # sensitive\n", name))
+			return diags
+		}
+
+		listVals := ctyCollectionValues(stateVal.GetAttr(name))
+		if listVals == nil {
+			// There is a difference between an empty list and a null list
+			buf.WriteString(strings.Repeat(" ", indent))
+			buf.WriteString(fmt.Sprintf("%s = null\n", name))
+			return diags
+		}
+
+		buf.WriteString(strings.Repeat(" ", indent))
+		buf.WriteString(fmt.Sprintf("%s = [\n", name))
+		for i := range listVals {
+			buf.WriteString(strings.Repeat(" ", indent+2))
+
+			// The entire element is marked.
+			if listVals[i].IsMarked() {
+				buf.WriteString("{}, # sensitive\n")
+				continue
+			}
+
+			buf.WriteString("{\n")
+			diags = diags.Append(writeConfigAttributesFromExisting(addr, buf, listVals[i], schema.NestedType.Attributes, indent+4))
+			buf.WriteString(strings.Repeat(" ", indent+2))
+			buf.WriteString("},\n")
+		}
+		buf.WriteString(strings.Repeat(" ", indent))
+		buf.WriteString("]\n")
+		return diags
+
+	case configschema.NestingMap:
+		if schema.Sensitive || stateVal.IsMarked() {
+			buf.WriteString(strings.Repeat(" ", indent))
+			buf.WriteString(fmt.Sprintf("%s = {} # sensitive\n", name))
+			return diags
+		}
+
+		attr := stateVal.GetAttr(name)
+		if attr.IsNull() {
+			// There is a difference between an empty map and a null map.
+			buf.WriteString(strings.Repeat(" ", indent))
+			buf.WriteString(fmt.Sprintf("%s = null\n", name))
+			return diags
+		}
+
+		vals := attr.AsValueMap()
+		keys := make([]string, 0, len(vals))
+		for key := range vals {
+			keys = append(keys, key)
+		}
+		sort.Strings(keys)
+
+		buf.WriteString(strings.Repeat(" ", indent))
+		buf.WriteString(fmt.Sprintf("%s = {\n", name))
+		for _, key := range keys {
+			buf.WriteString(strings.Repeat(" ", indent+2))
+			buf.WriteString(fmt.Sprintf("%s = {", key))
+
+			// This entire value is marked
+			if vals[key].IsMarked() {
+				buf.WriteString("} # sensitive\n")
+				continue
+			}
+
+			buf.WriteString("\n")
+			diags = diags.Append(writeConfigAttributesFromExisting(addr, buf, vals[key], schema.NestedType.Attributes, indent+4))
+			buf.WriteString(strings.Repeat(" ", indent+2))
+			buf.WriteString("}\n")
+		}
+		buf.WriteString(strings.Repeat(" ", indent))
+		buf.WriteString("}\n")
+		return diags
+
+	default:
+		// This should not happen, the above should be exhaustive.
+		panic(fmt.Errorf("unsupported NestingMode %s", schema.NestedType.Nesting.String()))
+	}
+}
+
+func writeConfigNestedBlockFromExisting(addr addrs.AbsResourceInstance, buf *strings.Builder, name string, schema *configschema.NestedBlock, stateVal cty.Value, indent int) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	switch schema.Nesting {
+	case configschema.NestingSingle, configschema.NestingGroup:
+		if stateVal.IsNull() {
+			return diags
+		}
+		buf.WriteString(strings.Repeat(" ", indent))
+		buf.WriteString(fmt.Sprintf("%s {", name))
+
+		// If the entire value is marked, don't print any nested attributes
+		if stateVal.IsMarked() {
+			buf.WriteString("} # sensitive\n")
+			return diags
+		}
+		buf.WriteString("\n")
+		diags = diags.Append(writeConfigAttributesFromExisting(addr, buf, stateVal, schema.Attributes, indent+2))
+		diags = diags.Append(writeConfigBlocksFromExisting(addr, buf, stateVal, schema.BlockTypes, indent+2))
+		buf.WriteString("}\n")
+		return diags
+	case configschema.NestingList, configschema.NestingSet:
+		if stateVal.IsMarked() {
+			buf.WriteString(strings.Repeat(" ", indent))
+			buf.WriteString(fmt.Sprintf("%s {} # sensitive\n", name))
+			return diags
+		}
+		listVals := ctyCollectionValues(stateVal)
+		for i := range listVals {
+			buf.WriteString(strings.Repeat(" ", indent))
+			buf.WriteString(fmt.Sprintf("%s {\n", name))
+			diags = diags.Append(writeConfigAttributesFromExisting(addr, buf, listVals[i], schema.Attributes, indent+2))
+			diags = diags.Append(writeConfigBlocksFromExisting(addr, buf, listVals[i], schema.BlockTypes, indent+2))
+			buf.WriteString("}\n")
+		}
+		return diags
+	case configschema.NestingMap:
+		// If the entire value is marked, don't print any nested attributes
+		if stateVal.IsMarked() {
+			buf.WriteString(fmt.Sprintf("%s {} # sensitive\n", name))
+			return diags
+		}
+
+		vals := stateVal.AsValueMap()
+		keys := make([]string, 0, len(vals))
+		for key := range vals {
+			keys = append(keys, key)
+		}
+		sort.Strings(keys)
+		for _, key := range keys {
+			buf.WriteString(strings.Repeat(" ", indent))
+			buf.WriteString(fmt.Sprintf("%s %q {", name, key))
+			// This entire map element is marked
+			if vals[key].IsMarked() {
+				buf.WriteString("} # sensitive\n")
+				return diags
+			}
+			buf.WriteString("\n")
+			diags = diags.Append(writeConfigAttributesFromExisting(addr, buf, vals[key], schema.Attributes, indent+2))
+			diags = diags.Append(writeConfigBlocksFromExisting(addr, buf, vals[key], schema.BlockTypes, indent+2))
+			buf.WriteString(strings.Repeat(" ", indent))
+			buf.WriteString("}\n")
+		}
+		return diags
+	default:
+		// This should not happen, the above should be exhaustive.
+		panic(fmt.Errorf("unsupported NestingMode %s", schema.Nesting.String()))
+	}
+}
+
+func writeAttrTypeConstraint(buf *strings.Builder, schema *configschema.Attribute) {
+	if schema.Required {
+		buf.WriteString(" # REQUIRED ")
+	} else {
+		buf.WriteString(" # OPTIONAL ")
+	}
+
+	if schema.NestedType != nil {
+		buf.WriteString(fmt.Sprintf("%s\n", schema.NestedType.ImpliedType().FriendlyName()))
+	} else {
+		buf.WriteString(fmt.Sprintf("%s\n", schema.Type.FriendlyName()))
+	}
+}
+
+func writeBlockTypeConstraint(buf *strings.Builder, schema *configschema.NestedBlock) {
+	if schema.MinItems > 0 {
+		buf.WriteString(" # REQUIRED block\n")
+	} else {
+		buf.WriteString(" # OPTIONAL block\n")
+	}
+}
+
+// copied from command/format/diff
+func ctyCollectionValues(val cty.Value) []cty.Value {
+	if !val.IsKnown() || val.IsNull() {
+		return nil
+	}
+
+	var len int
+	if val.IsMarked() {
+		val, _ = val.Unmark()
+		len = val.LengthInt()
+	} else {
+		len = val.LengthInt()
+	}
+
+	ret := make([]cty.Value, 0, len)
+	for it := val.ElementIterator(); it.Next(); {
+		_, value := it.Element()
+		ret = append(ret, value)
+	}
+
+	return ret
+}
+
+// omitUnknowns recursively walks the src cty.Value and returns a new cty.Value,
+// omitting any unknowns.
+//
+// The result also normalizes some types: all sequence types are turned into
+// tuple types and all mapping types are converted to object types, since we
+// assume the result of this is just going to be serialized as JSON (and thus
+// lose those distinctions) anyway.
+func omitUnknowns(val cty.Value) cty.Value {
+	ty := val.Type()
+	switch {
+	case val.IsNull():
+		return val
+	case !val.IsKnown():
+		return cty.NilVal
+	case ty.IsPrimitiveType():
+		return val
+	case ty.IsListType() || ty.IsTupleType() || ty.IsSetType():
+		var vals []cty.Value
+		it := val.ElementIterator()
+		for it.Next() {
+			_, v := it.Element()
+			newVal := omitUnknowns(v)
+			if newVal != cty.NilVal {
+				vals = append(vals, newVal)
+			} else if newVal == cty.NilVal {
+				// element order is how we correlate unknownness, so we must
+				// replace unknowns with nulls
+				vals = append(vals, cty.NullVal(v.Type()))
+			}
+		}
+		// We use tuple types always here, because the work we did above
+		// may have caused the individual elements to have different types,
+		// and we're doing this work to produce JSON anyway and JSON marshalling
+		// represents all of these sequence types as an array.
+		return cty.TupleVal(vals)
+	case ty.IsMapType() || ty.IsObjectType():
+		vals := make(map[string]cty.Value)
+		it := val.ElementIterator()
+		for it.Next() {
+			k, v := it.Element()
+			newVal := omitUnknowns(v)
+			if newVal != cty.NilVal {
+				vals[k.AsString()] = newVal
+			}
+		}
+		// We use object types always here, because the work we did above
+		// may have caused the individual elements to have different types,
+		// and we're doing this work to produce JSON anyway and JSON marshalling
+		// represents both of these mapping types as an object.
+		return cty.ObjectVal(vals)
+	default:
+		// Should never happen, since the above should cover all types
+		panic(fmt.Sprintf("omitUnknowns cannot handle %#v", val))
+	}
+}
diff --git a/v1.5.7/internal/genconfig/generate_config_test.go b/v1.5.7/internal/genconfig/generate_config_test.go
new file mode 100644
index 0000000..ed0f1e1
--- /dev/null
+++ b/v1.5.7/internal/genconfig/generate_config_test.go
@@ -0,0 +1,442 @@
+package genconfig
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+func TestConfigGeneration(t *testing.T) {
+	tcs := map[string]struct {
+		schema   *configschema.Block
+		addr     addrs.AbsResourceInstance
+		provider addrs.LocalProviderConfig
+		value    cty.Value
+		expected string
+	}{
+		"simple_resource": {
+			schema: &configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"list_block": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"nested_value": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Nesting: configschema.NestingSingle,
+					},
+				},
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"value": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			addr: addrs.AbsResourceInstance{
+				Module: nil,
+				Resource: addrs.ResourceInstance{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "tfcoremock_simple_resource",
+						Name: "empty",
+					},
+					Key: nil,
+				},
+			},
+			provider: addrs.LocalProviderConfig{
+				LocalName: "tfcoremock",
+			},
+			value: cty.NilVal,
+			expected: `
+resource "tfcoremock_simple_resource" "empty" {
+  value = null          # OPTIONAL string
+  list_block {          # OPTIONAL block
+    nested_value = null # OPTIONAL string
+  }
+}`,
+		},
+		"simple_resource_with_state": {
+			schema: &configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"list_block": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"nested_value": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Nesting: configschema.NestingSingle,
+					},
+				},
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"value": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			addr: addrs.AbsResourceInstance{
+				Module: nil,
+				Resource: addrs.ResourceInstance{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "tfcoremock_simple_resource",
+						Name: "empty",
+					},
+					Key: nil,
+				},
+			},
+			provider: addrs.LocalProviderConfig{
+				LocalName: "tfcoremock",
+			},
+			value: cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.StringVal("D2320658"),
+				"value": cty.StringVal("Hello, world!"),
+				"list_block": cty.ObjectVal(map[string]cty.Value{
+					"nested_value": cty.StringVal("Hello, solar system!"),
+				}),
+			}),
+			expected: `
+resource "tfcoremock_simple_resource" "empty" {
+  value = "Hello, world!"
+  list_block {
+    nested_value = "Hello, solar system!"
+  }
+}`,
+		},
+		"simple_resource_with_partial_state": {
+			schema: &configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"list_block": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"nested_value": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Nesting: configschema.NestingSingle,
+					},
+				},
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"value": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			addr: addrs.AbsResourceInstance{
+				Module: nil,
+				Resource: addrs.ResourceInstance{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "tfcoremock_simple_resource",
+						Name: "empty",
+					},
+					Key: nil,
+				},
+			},
+			provider: addrs.LocalProviderConfig{
+				LocalName: "tfcoremock",
+			},
+			value: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("D2320658"),
+				"list_block": cty.ObjectVal(map[string]cty.Value{
+					"nested_value": cty.StringVal("Hello, solar system!"),
+				}),
+			}),
+			expected: `
+resource "tfcoremock_simple_resource" "empty" {
+  value = null
+  list_block {
+    nested_value = "Hello, solar system!"
+  }
+}`,
+		},
+		"simple_resource_with_alternate_provider": {
+			schema: &configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"list_block": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"nested_value": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Nesting: configschema.NestingSingle,
+					},
+				},
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"value": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			addr: addrs.AbsResourceInstance{
+				Module: nil,
+				Resource: addrs.ResourceInstance{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "tfcoremock_simple_resource",
+						Name: "empty",
+					},
+					Key: nil,
+				},
+			},
+			provider: addrs.LocalProviderConfig{
+				LocalName: "mock",
+			},
+			value: cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.StringVal("D2320658"),
+				"value": cty.StringVal("Hello, world!"),
+				"list_block": cty.ObjectVal(map[string]cty.Value{
+					"nested_value": cty.StringVal("Hello, solar system!"),
+				}),
+			}),
+			expected: `
+resource "tfcoremock_simple_resource" "empty" {
+  provider = mock
+  value    = "Hello, world!"
+  list_block {
+    nested_value = "Hello, solar system!"
+  }
+}`,
+		},
+		"simple_resource_with_aliased_provider": {
+			schema: &configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"list_block": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"nested_value": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Nesting: configschema.NestingSingle,
+					},
+				},
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"value": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			addr: addrs.AbsResourceInstance{
+				Module: nil,
+				Resource: addrs.ResourceInstance{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "tfcoremock_simple_resource",
+						Name: "empty",
+					},
+					Key: nil,
+				},
+			},
+			provider: addrs.LocalProviderConfig{
+				LocalName: "tfcoremock",
+				Alias:     "alternate",
+			},
+			value: cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.StringVal("D2320658"),
+				"value": cty.StringVal("Hello, world!"),
+				"list_block": cty.ObjectVal(map[string]cty.Value{
+					"nested_value": cty.StringVal("Hello, solar system!"),
+				}),
+			}),
+			expected: `
+resource "tfcoremock_simple_resource" "empty" {
+  provider = tfcoremock.alternate
+  value    = "Hello, world!"
+  list_block {
+    nested_value = "Hello, solar system!"
+  }
+}`,
+		},
+		"resource_with_nulls": {
+			schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"single": {
+						NestedType: &configschema.Object{
+							Attributes: map[string]*configschema.Attribute{},
+							Nesting:    configschema.NestingSingle,
+						},
+						Required: true,
+					},
+					"list": {
+						NestedType: &configschema.Object{
+							Attributes: map[string]*configschema.Attribute{
+								"nested_id": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+							Nesting: configschema.NestingList,
+						},
+						Required: true,
+					},
+					"map": {
+						NestedType: &configschema.Object{
+							Attributes: map[string]*configschema.Attribute{
+								"nested_id": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+							Nesting: configschema.NestingMap,
+						},
+						Required: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"nested_single": {
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"nested_id": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+					// No configschema.NestingGroup example for this test, because this block type can never be null in state.
+					"nested_list": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"nested_id": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+					"nested_set": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"nested_id": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+					"nested_map": {
+						Nesting: configschema.NestingMap,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"nested_id": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			addr: addrs.AbsResourceInstance{
+				Module: nil,
+				Resource: addrs.ResourceInstance{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "tfcoremock_simple_resource",
+						Name: "empty",
+					},
+					Key: nil,
+				},
+			},
+			provider: addrs.LocalProviderConfig{
+				LocalName: "tfcoremock",
+			},
+			value: cty.ObjectVal(map[string]cty.Value{
+				"id":     cty.StringVal("D2320658"),
+				"single": cty.NullVal(cty.Object(map[string]cty.Type{})),
+				"list": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"nested_id": cty.String,
+				}))),
+				"map": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{
+					"nested_id": cty.String,
+				}))),
+				"nested_single": cty.NullVal(cty.Object(map[string]cty.Type{
+					"nested_id": cty.String,
+				})),
+				"nested_list": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+					"nested_id": cty.String,
+				})),
+				"nested_set": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"nested_id": cty.String,
+				})),
+				"nested_map": cty.MapValEmpty(cty.Object(map[string]cty.Type{
+					"nested_id": cty.String,
+				})),
+			}),
+			expected: `
+resource "tfcoremock_simple_resource" "empty" {
+  list   = null
+  map    = null
+  single = null
+}`,
+		},
+	}
+	for name, tc := range tcs {
+		t.Run(name, func(t *testing.T) {
+			err := tc.schema.InternalValidate()
+			if err != nil {
+				t.Fatalf("schema failed InternalValidate: %s", err)
+			}
+			contents, diags := GenerateResourceContents(tc.addr, tc.schema, tc.provider, tc.value)
+			if len(diags) > 0 {
+				t.Errorf("expected no diagnostics but found %s", diags)
+			}
+
+			got := WrapResourceContents(tc.addr, contents)
+			want := strings.TrimSpace(tc.expected)
+			if diff := cmp.Diff(got, want); len(diff) > 0 {
+				t.Errorf("got:\n%s\nwant:\n%s\ndiff:\n%s", got, want, diff)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/genconfig/generate_config_write.go b/v1.5.7/internal/genconfig/generate_config_write.go
new file mode 100644
index 0000000..99231bd
--- /dev/null
+++ b/v1.5.7/internal/genconfig/generate_config_write.go
@@ -0,0 +1,79 @@
+package genconfig
+
+import (
+	"fmt"
+	"io"
+	"os"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func ShouldWriteConfig(out string) bool {
+	// No specified out file, so don't write anything.
+	return len(out) != 0
+}
+
+func ValidateTargetFile(out string) (diags tfdiags.Diagnostics) {
+	if _, err := os.Stat(out); !os.IsNotExist(err) {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Target generated file already exists",
+			"Terraform can only write generated config into a new file. Either choose a different target location or move all existing configuration out of the target file, delete it and try again."))
+
+	}
+	return diags
+}
+
+type Change struct {
+	Addr            string
+	ImportID        string
+	GeneratedConfig string
+}
+
+func (c *Change) MaybeWriteConfig(writer io.Writer, out string) (io.Writer, bool, tfdiags.Diagnostics) {
+	var wroteConfig bool
+	var diags tfdiags.Diagnostics
+	if len(c.GeneratedConfig) > 0 {
+		if writer == nil {
+			// Lazily create the generated file, in case we have no
+			// generated config to create.
+			if w, err := os.Create(out); err != nil {
+				if os.IsPermission(err) {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Failed to create target generated file",
+						fmt.Sprintf("Terraform did not have permission to create the generated file (%s) in the target directory. Please modify permissions over the target directory, and try again.", out)))
+					return nil, false, diags
+				}
+
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to create target generated file",
+					fmt.Sprintf("Terraform could not create the generated file (%s) in the target directory: %v. Depending on the error message, this may be a bug in Terraform itself. If so, please report it!", out, err)))
+				return nil, false, diags
+			} else {
+				writer = w
+			}
+
+			header := "# __generated__ by Terraform\n# Please review these resources and move them into your main configuration files.\n"
+			// Missing the header from the file, isn't the end of the world
+			// so if this did return an error, then we will just ignore it.
+			_, _ = writer.Write([]byte(header))
+		}
+
+		header := "\n# __generated__ by Terraform"
+		if len(c.ImportID) > 0 {
+			header += fmt.Sprintf(" from %q", c.ImportID)
+		}
+		header += "\n"
+		if _, err := writer.Write([]byte(fmt.Sprintf("%s%s\n", header, c.GeneratedConfig))); err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Warning,
+				"Failed to save generated config",
+				fmt.Sprintf("Terraform encountered an error while writing generated config: %v. The config for %s must be created manually before applying. Depending on the error message, this may be a bug in Terraform itself. If so, please report it!", err, c.Addr)))
+		}
+		wroteConfig = true
+	}
+
+	return writer, wroteConfig, diags
+}
diff --git a/v1.5.7/internal/getmodules/doc.go b/v1.5.7/internal/getmodules/doc.go
new file mode 100644
index 0000000..5499d92
--- /dev/null
+++ b/v1.5.7/internal/getmodules/doc.go
@@ -0,0 +1,11 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package getmodules contains the low-level functionality for fetching
+// remote module packages. It's essentially just a thin wrapper around
+// go-getter.
+//
+// This package is only for remote module source addresses, not for local
+// or registry source addresses. The other address types are handled
+// elsewhere.
+package getmodules
diff --git a/v1.5.7/internal/getmodules/file_detector.go b/v1.5.7/internal/getmodules/file_detector.go
new file mode 100644
index 0000000..eb05977
--- /dev/null
+++ b/v1.5.7/internal/getmodules/file_detector.go
@@ -0,0 +1,68 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getmodules
+
+import (
+	"fmt"
+	"path/filepath"
+	"runtime"
+)
+
+// fileDetector is a replacement for go-getter's own file detector which
+// better meets Terraform's needs: specifically, it rejects relative filesystem
+// paths with a somewhat-decent error message.
+//
+// This is a replacement for some historical hackery we did where we tried to
+// avoid calling into go-getter altogether in this situation. This is,
+// therefore, a copy of getter.FileDetector but with the "not absolute path"
+// case replaced with a similar result as Terraform's old heuristic would've
+// returned: a custom error type that the caller can react to in order to
+// produce a hint error message if desired.
+type fileDetector struct{}
+
+func (d *fileDetector) Detect(src, pwd string) (string, bool, error) {
+	if len(src) == 0 {
+		return "", false, nil
+	}
+
+	if !filepath.IsAbs(src) {
+		return "", true, &MaybeRelativePathErr{src}
+	}
+
+	return fmtFileURL(src), true, nil
+}
+
+func fmtFileURL(path string) string {
+	if runtime.GOOS == "windows" {
+		// Make sure we're using "/" on Windows. URLs are "/"-based.
+		path = filepath.ToSlash(path)
+		return fmt.Sprintf("file://%s", path)
+	}
+
+	// Make sure that we don't start with "/" since we add that below.
+	if path[0] == '/' {
+		path = path[1:]
+	}
+	return fmt.Sprintf("file:///%s", path)
+}
+
+// MaybeRelativePathErr is the error type returned by NormalizePackageAddress
+// if the source address looks like it might be intended to be a relative
+// filesystem path but without the required "./" or "../" prefix.
+//
+// Specifically, NormalizePackageAddress will return a pointer to this type,
+// so the error type will be *MaybeRelativePathErr.
+//
+// It has a name starting with "Maybe" because in practice we can get here
+// with any string that isn't recognized as one of the supported schemes:
+// treating the address as a local filesystem path is our fallback for when
+// everything else fails, but it could just as easily be a typo in an attempt
+// to use one of the other schemes and thus not a filesystem path at all.
+type MaybeRelativePathErr struct {
+	Addr string
+}
+
+func (e *MaybeRelativePathErr) Error() string {
+	return fmt.Sprintf("Terraform cannot detect a supported external module source type for %s", e.Addr)
+}
diff --git a/v1.5.7/internal/getmodules/getter.go b/v1.5.7/internal/getmodules/getter.go
new file mode 100644
index 0000000..89c116c
--- /dev/null
+++ b/v1.5.7/internal/getmodules/getter.go
@@ -0,0 +1,167 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getmodules
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"os"
+
+	cleanhttp "github.com/hashicorp/go-cleanhttp"
+	getter "github.com/hashicorp/go-getter"
+	"github.com/hashicorp/terraform/internal/copy"
+)
+
+// We configure our own go-getter detector and getter sets here, because
+// the set of sources we support is part of Terraform's documentation and
+// so we don't want any new sources introduced in go-getter to sneak in here
+// and work even though they aren't documented. This also insulates us from
+// any meddling that might be done by other go-getter callers linked into our
+// executable.
+//
+// Note that over time we've found go-getter's design to be not wholly fit
+// for Terraform's purposes in various ways, and so we're continuing to use
+// it here because our backward compatibility with earlier versions depends
+// on it, but we use go-getter very carefully and always only indirectly via
+// the public API of this package so that we can get the subset of the
+// go-getter functionality we need while working around some of the less
+// helpful parts of its design. See the comments in various other functions
+// in this package which call into go-getter for more information on what
+// tradeoffs we're making here.
+
+var goGetterDetectors = []getter.Detector{
+	new(getter.GitHubDetector),
+	new(getter.GitDetector),
+
+	// Because historically BitBucket supported both Git and Mercurial
+	// repositories but used the same repository URL syntax for both,
+	// this detector takes the unusual step of actually reaching out
+	// to the BitBucket API to recognize the repository type. That
+	// means there's the possibility of an outgoing network request
+	// inside what is otherwise normally just a local string manipulation
+	// operation, but we continue to accept this for now.
+	//
+	// Perhaps a future version of go-getter will remove the check now
+	// that BitBucket only supports Git anyway. Aside from this historical
+	// exception, we should avoid adding any new detectors that make network
+	// requests in here, and limit ourselves only to ones that can operate
+	// entirely through local string manipulation.
+	new(getter.BitBucketDetector),
+
+	new(getter.GCSDetector),
+	new(getter.S3Detector),
+	new(fileDetector),
+}
+
+var goGetterNoDetectors = []getter.Detector{}
+
+var goGetterDecompressors = map[string]getter.Decompressor{
+	"bz2": new(getter.Bzip2Decompressor),
+	"gz":  new(getter.GzipDecompressor),
+	"xz":  new(getter.XzDecompressor),
+	"zip": new(getter.ZipDecompressor),
+
+	"tar.bz2":  new(getter.TarBzip2Decompressor),
+	"tar.tbz2": new(getter.TarBzip2Decompressor),
+
+	"tar.gz": new(getter.TarGzipDecompressor),
+	"tgz":    new(getter.TarGzipDecompressor),
+
+	"tar.xz": new(getter.TarXzDecompressor),
+	"txz":    new(getter.TarXzDecompressor),
+}
+
+var goGetterGetters = map[string]getter.Getter{
+	"file":  new(getter.FileGetter),
+	"gcs":   new(getter.GCSGetter),
+	"git":   new(getter.GitGetter),
+	"hg":    new(getter.HgGetter),
+	"s3":    new(getter.S3Getter),
+	"http":  getterHTTPGetter,
+	"https": getterHTTPGetter,
+}
+
+var getterHTTPClient = cleanhttp.DefaultClient()
+
+var getterHTTPGetter = &getter.HttpGetter{
+	Client:             getterHTTPClient,
+	Netrc:              true,
+	XTerraformGetLimit: 10,
+}
+
+// A reusingGetter is a helper for the module installer that remembers
+// the final resolved addresses of all of the sources it has already been
+// asked to install, and will copy from a prior installation directory if
+// it has the same resolved source address.
+//
+// The keys in a reusingGetter are the normalized (post-detection) package
+// addresses, and the values are the paths where each source was previously
+// installed. (Users of this map should treat the keys as addrs.ModulePackage
+// values, but we can't type them that way because the addrs package
+// imports getmodules in order to indirectly access our go-getter
+// configuration.)
+type reusingGetter map[string]string
+
+// getWithGoGetter fetches the package at the given address into the given
+// target directory. The given address must already be in normalized form
+// (using NormalizePackageAddress) or else the behavior is undefined.
+//
+// This function deals only in entire packages, so it's always the caller's
+// responsibility to handle any subdirectory specification and select a
+// suitable subdirectory of the given installation directory after installation
+// has succeeded.
+//
+// This function would ideally accept packageAddr as a value of type
+// addrs.ModulePackage, but we can't do that because the addrs package
+// depends on this package for package address parsing. Therefore we just
+// use a string here but assume that the caller got that value by calling
+// the String method on a valid addrs.ModulePackage value.
+//
+// The errors returned by this function are those surfaced by the underlying
+// go-getter library, which have very inconsistent quality as
+// end-user-actionable error messages. At this time we do not have any
+// reasonable way to improve these error messages at this layer because
+// the underlying errors are not separately recognizable.
+func (g reusingGetter) getWithGoGetter(ctx context.Context, instPath, packageAddr string) error {
+	var err error
+
+	if prevDir, exists := g[packageAddr]; exists {
+		log.Printf("[TRACE] getmodules: copying previous install of %q from %s to %s", packageAddr, prevDir, instPath)
+		err := os.Mkdir(instPath, os.ModePerm)
+		if err != nil {
+			return fmt.Errorf("failed to create directory %s: %s", instPath, err)
+		}
+		err = copy.CopyDir(instPath, prevDir)
+		if err != nil {
+			return fmt.Errorf("failed to copy from %s to %s: %s", prevDir, instPath, err)
+		}
+	} else {
+		log.Printf("[TRACE] getmodules: fetching %q to %q", packageAddr, instPath)
+		client := getter.Client{
+			Src: packageAddr,
+			Dst: instPath,
+			Pwd: instPath,
+
+			Mode: getter.ClientModeDir,
+
+			Detectors:     goGetterNoDetectors, // our caller should've already done detection
+			Decompressors: goGetterDecompressors,
+			Getters:       goGetterGetters,
+			Ctx:           ctx,
+		}
+		err = client.Get()
+		if err != nil {
+			return err
+		}
+		// Remember where we installed this so we might reuse this directory
+		// on subsequent calls to avoid re-downloading.
+		g[packageAddr] = instPath
+	}
+
+	// If we get down here then we've either downloaded the package or
+	// copied a previous tree we downloaded, and so either way we should
+	// have got the full module package structure written into instPath.
+	return nil
+}
diff --git a/v1.5.7/internal/getmodules/installer.go b/v1.5.7/internal/getmodules/installer.go
new file mode 100644
index 0000000..b9bad56
--- /dev/null
+++ b/v1.5.7/internal/getmodules/installer.go
@@ -0,0 +1,47 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getmodules
+
+import (
+	"context"
+)
+
+// PackageFetcher is a low-level utility for fetching remote module packages
+// into local filesystem directories in preparation for use by higher-level
+// module installer functionality implemented elsewhere.
+//
+// A PackageFetcher works only with entire module packages and never with
+// the individual modules within a package.
+//
+// A particular PackageFetcher instance remembers the target directory of
+// any successfully-installed package so that it can optimize future calls
+// that have the same package address by copying the local directory tree,
+// rather than fetching the package from its origin repeatedly. There is
+// no way to reset this cache, so a particular PackageFetcher instance should
+// live only for the duration of a single initialization process.
+type PackageFetcher struct {
+	getter reusingGetter
+}
+
+func NewPackageFetcher() *PackageFetcher {
+	return &PackageFetcher{
+		getter: reusingGetter{},
+	}
+}
+
+// FetchPackage downloads or otherwise retrieves the filesystem inside the
+// package at the given address into the given local installation directory.
+//
+// packageAddr must be formatted as if it were the result of an
+// addrs.ModulePackage.String() call. It's only defined as a raw string here
+// because the getmodules package can't import the addrs package due to
+// that creating a package dependency cycle.
+//
+// PackageFetcher only works with entire packages. If the caller is processing
+// a module source address which includes a subdirectory portion then the
+// caller must resolve that itself, possibly with the help of the
+// getmodules.SplitPackageSubdir and getmodules.ExpandSubdirGlobs functions.
+func (f *PackageFetcher) FetchPackage(ctx context.Context, instDir string, packageAddr string) error {
+	return f.getter.getWithGoGetter(ctx, instDir, packageAddr)
+}
diff --git a/v1.5.7/internal/getmodules/package.go b/v1.5.7/internal/getmodules/package.go
new file mode 100644
index 0000000..c7352f1
--- /dev/null
+++ b/v1.5.7/internal/getmodules/package.go
@@ -0,0 +1,72 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getmodules
+
+import (
+	getter "github.com/hashicorp/go-getter"
+)
+
+// NormalizePackageAddress uses the go-getter "detector" functionality in
+// order to turn a user-supplied source address into a normalized address
+// which always includes a prefix naming a protocol to fetch with and may
+// also include a transformed/normalized version of the protocol-specific
+// source address included afterward.
+//
+// This is part of the implementation of addrs.ParseModulePackage and of
+// addrs.ParseModuleSource, so for most callers it'd be better to call
+// one of those other functions instead. The addrs package can potentially
+// perform other processing in addition to just the go-getter detection.
+//
+// Note that this function expects to recieve only a package address, not
+// a full source address that might also include a subdirectory portion.
+// The caller must trim off any subdirectory portion using
+// getmodules.SplitPackageSubdir before calling this function, passing in
+// just the packageAddr return value, or the result will be incorrect.
+//
+// The detectors in go-getter can potentially introduce their own
+// package subdirectory portions. If that happens then this function will
+// return the subdirectory portion as a non-empty subDir return value,
+// which the caller must then use as a prefix for any subDir it already
+// extracted from the user's given package address.
+//
+// Some of go-getter's detectors make outgoing HTTP requests, and so
+// the behavior of this function may depend on the network connectivity
+// of the system where Terraform is running. However, most of the getters
+// we use are local-only, and so HTTP requests are only for some ambiguous
+// edge-cases, such as the BitBucket detector which has a mechanism to
+// detect whether to use Git or Mercurial, because earlier versions of
+// BitBucket used to support both.
+func NormalizePackageAddress(given string) (packageAddr, subDir string, err error) {
+	// Because we're passing go-getter no base directory here, the file
+	// detector will return an error if the user entered a relative filesystem
+	// path without a "../" or "./" prefix and thus ended up in here.
+	//
+	// go-getter's error message for that case is very poor, and so we'll
+	// try to heuristically detect that situation and return a better error
+	// message.
+
+	// NOTE: We're passing an empty string to the "current working directory"
+	// here because that's only relevant for relative filesystem paths,
+	// but Terraform handles relative filesystem paths itself outside of
+	// go-getter and so it'd always be an error to pass one into here.
+	// go-getter's "file" detector returns an error if it encounters a
+	// relative path when the pwd argument is empty.
+	//
+	// (Absolute filesystem paths _are_ valid though, for annoying historical
+	// reasons, and we treat them as remote packages even though "downloading"
+	// them just means a recursive copy of the source directory tree.)
+
+	result, err := getter.Detect(given, "", goGetterDetectors)
+	if err != nil {
+		// NOTE: go-getter's error messages are of very inconsistent quality
+		// and many are not suitable for an end-user audience, but they are all
+		// just strings and so we can't really do any sort of post-processing
+		// to improve them and thus we just accept some bad error messages for
+		// now.
+		return "", "", err
+	}
+
+	packageAddr, subDir = SplitPackageSubdir(result)
+	return packageAddr, subDir, nil
+}
diff --git a/v1.5.7/internal/getmodules/subdir.go b/v1.5.7/internal/getmodules/subdir.go
new file mode 100644
index 0000000..ee2e0f9
--- /dev/null
+++ b/v1.5.7/internal/getmodules/subdir.go
@@ -0,0 +1,60 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getmodules
+
+import (
+	"path"
+
+	getter "github.com/hashicorp/go-getter"
+)
+
+// SplitPackageSubdir detects whether the given address string has a
+// subdirectory portion, and if so returns a non-empty subDir string
+// along with the trimmed package address.
+//
+// If the given string doesn't have a subdirectory portion then it'll
+// just be returned verbatim in packageAddr, with an empty subDir value.
+//
+// Although the rest of this package is focused only on direct remote
+// module packages, this particular function and its companion
+// ExpandSubdirGlobs are both also relevant for registry-based module
+// addresses, because a registry translates such an address into a
+// remote module package address and thus can contribute its own
+// additions to the final subdirectory selection.
+func SplitPackageSubdir(given string) (packageAddr, subDir string) {
+	// We delegate this mostly to go-getter, because older Terraform
+	// versions just used go-getter directly and so we need to preserve
+	// its various quirks for compatibility reasons.
+	//
+	// However, note that in Terraform we _always_ split off the subdirectory
+	// portion and handle it within Terraform-level code, _never_ passing
+	// a subdirectory portion down into go-getter's own Get function, because
+	// Terraform's ability to refer between local paths inside the same
+	// package depends on Terraform itself always being aware of where the
+	// package's root directory ended up on disk, and always needs the
+	// package installed wholesale.
+	packageAddr, subDir = getter.SourceDirSubdir(given)
+	if subDir != "" {
+		subDir = path.Clean(subDir)
+	}
+	return packageAddr, subDir
+}
+
+// ExpandSubdirGlobs handles a subdir string that might contain glob syntax,
+// turning it into a concrete subdirectory path by referring to the actual
+// files on disk in the given directory which we assume contains the content
+// of whichever package this is a subdirectory glob for.
+//
+// Subdir globs are used, for example, when a module registry wants to specify
+// to select the contents of the single directory at the root of a conventional
+// tar archive but it doesn't actually know the exact name of that directory.
+// In that case it might specify a subdir of just "*", which this function
+// will then expand into the single subdirectory found inside instDir, or
+// return an error if the result would be ambiguous.
+func ExpandSubdirGlobs(instDir string, subDir string) (string, error) {
+	// We just delegate this entirely to go-getter, because older Terraform
+	// versions just used go-getter directly and so we need to preserve
+	// its various quirks for compatibility reasons.
+	return getter.SubdirGlob(instDir, subDir)
+}
diff --git a/v1.5.7/internal/getproviders/didyoumean.go b/v1.5.7/internal/getproviders/didyoumean.go
new file mode 100644
index 0000000..269ce6d
--- /dev/null
+++ b/v1.5.7/internal/getproviders/didyoumean.go
@@ -0,0 +1,265 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"net/url"
+	"path"
+
+	"github.com/hashicorp/go-retryablehttp"
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// MissingProviderSuggestion takes a provider address that failed installation
+// due to the remote registry reporting that it didn't exist, and attempts
+// to find another provider that the user might have meant to select.
+//
+// If the result is equal to the given address then that indicates that there
+// is no suggested alternative to offer, either because the function
+// successfully determined there is no recorded alternative or because the
+// lookup failed somehow. We don't consider a failure to find a suggestion
+// as an installation failure, because the caller should already be reporting
+// that the provider didn't exist anyway and this is only extra context for
+// that error message.
+//
+// The result of this is a best effort, so any UI presenting it should be
+// careful to give it only as a possibility and not necessarily a suitable
+// replacement for the given provider.
+//
+// In practice today this function only knows how to suggest alternatives for
+// "default" providers, which is to say ones that are in the hashicorp
+// namespace in the Terraform registry. It will always return no result for
+// any other provider. That might change in future if we introduce other ways
+// to discover provider suggestions.
+//
+// If the given context is cancelled then this function might not return a
+// renaming suggestion even if one would've been available for a completed
+// request.
+func MissingProviderSuggestion(ctx context.Context, addr addrs.Provider, source Source, reqs Requirements) addrs.Provider {
+	if !addrs.IsDefaultProvider(addr) {
+		return addr
+	}
+
+	// Before possibly looking up legacy naming, see if the user has another provider
+	// named in their requirements that is of the same type, and offer that
+	// as a suggestion
+	for req := range reqs {
+		if req != addr && req.Type == addr.Type {
+			return req
+		}
+	}
+
+	// Our strategy here, for a default provider, is to use the default
+	// registry's special API for looking up "legacy" providers and try looking
+	// for a legacy provider whose type name matches the type of the given
+	// provider. This should then find a suitable answer for any provider
+	// that was originally auto-installable in v0.12 and earlier but moved
+	// into a non-default namespace as part of introducing the hierarchical
+	// provider namespace.
+	//
+	// To achieve that, we need to find the direct registry client in
+	// particular from the given source, because that is the only Source
+	// implementation that can actually handle a legacy provider lookup.
+	regSource := findLegacyProviderLookupSource(addr.Hostname, source)
+	if regSource == nil {
+		// If there's no direct registry source in the installation config
+		// then we can't provide a renaming suggestion.
+		return addr
+	}
+
+	defaultNS, redirectNS, err := regSource.lookupLegacyProviderNamespace(ctx, addr.Hostname, addr.Type)
+	if err != nil {
+		return addr
+	}
+
+	switch {
+	case redirectNS != "":
+		return addrs.Provider{
+			Hostname:  addr.Hostname,
+			Namespace: redirectNS,
+			Type:      addr.Type,
+		}
+	default:
+		return addrs.Provider{
+			Hostname:  addr.Hostname,
+			Namespace: defaultNS,
+			Type:      addr.Type,
+		}
+	}
+}
+
+// findLegacyProviderLookupSource tries to find a *RegistrySource that can talk
+// to the given registry host in the given Source. It might be given directly,
+// or it might be given indirectly via a MultiSource where the selector
+// includes a wildcard for registry.terraform.io.
+//
+// Returns nil if the given source does not have any configured way to talk
+// directly to the given host.
+//
+// If the given source contains multiple sources that can talk to the given
+// host directly, the first one in the sequence takes preference. In practice
+// it's pointless to have two direct installation sources that match the same
+// hostname anyway, so this shouldn't arise in normal use.
+func findLegacyProviderLookupSource(host svchost.Hostname, source Source) *RegistrySource {
+	switch source := source.(type) {
+
+	case *RegistrySource:
+		// Easy case: the source is a registry source directly, and so we'll
+		// just use it.
+		return source
+
+	case *MemoizeSource:
+		// Also easy: the source is a memoize wrapper, so defer to its
+		// underlying source.
+		return findLegacyProviderLookupSource(host, source.underlying)
+
+	case MultiSource:
+		// Trickier case: if it's a multisource then we need to scan over
+		// its selectors until we find one that is a *RegistrySource _and_
+		// that is configured to accept arbitrary providers from the
+		// given hostname.
+
+		// For our matching purposes we'll use an address that would not be
+		// valid as a real provider FQN and thus can only match a selector
+		// that has no filters at all or a selector that wildcards everything
+		// except the hostname, like "registry.terraform.io/*/*"
+		matchAddr := addrs.Provider{
+			Hostname: host,
+			// Other fields are intentionally left empty, to make this invalid
+			// as a specific provider address.
+		}
+
+		for _, selector := range source {
+			// If this source has suitable matching patterns to install from
+			// the given hostname then we'll recursively search inside it
+			// for *RegistrySource objects.
+			if selector.CanHandleProvider(matchAddr) {
+				ret := findLegacyProviderLookupSource(host, selector.Source)
+				if ret != nil {
+					return ret
+				}
+			}
+		}
+
+		// If we get here then there were no selectors that are both configured
+		// to handle modules from the given hostname and that are registry
+		// sources, so we fail.
+		return nil
+
+	default:
+		// This source cannot be and cannot contain a *RegistrySource, so
+		// we fail.
+		return nil
+	}
+}
+
+// lookupLegacyProviderNamespace is a special method available only on
+// RegistrySource which can deal with legacy provider addresses that contain
+// only a type and leave the namespace implied.
+//
+// It asks the registry at the given hostname to provide a default namespace
+// for the given provider type, which can be combined with the given hostname
+// and type name to produce a fully-qualified provider address.
+//
+// Not all unqualified type names can be resolved to a default namespace. If
+// the request fails, this method returns an error describing the failure.
+//
+// This method exists only to allow compatibility with unqualified names
+// in older configurations. New configurations should be written so as not to
+// depend on it, and this fallback mechanism will likely be removed altogether
+// in a future Terraform version.
+func (s *RegistrySource) lookupLegacyProviderNamespace(ctx context.Context, hostname svchost.Hostname, typeName string) (string, string, error) {
+	client, err := s.registryClient(hostname)
+	if err != nil {
+		return "", "", err
+	}
+	return client.legacyProviderDefaultNamespace(ctx, typeName)
+}
+
+// legacyProviderDefaultNamespace returns the raw address strings produced by
+// the registry when asked about the given unqualified provider type name.
+// The returned namespace string is taken verbatim from the registry's response.
+//
+// This method exists only to allow compatibility with unqualified names
+// in older configurations. New configurations should be written so as not to
+// depend on it.
+func (c *registryClient) legacyProviderDefaultNamespace(ctx context.Context, typeName string) (string, string, error) {
+	endpointPath, err := url.Parse(path.Join("-", typeName, "versions"))
+	if err != nil {
+		// Should never happen because we're constructing this from
+		// already-validated components.
+		return "", "", err
+	}
+	endpointURL := c.baseURL.ResolveReference(endpointPath)
+
+	req, err := retryablehttp.NewRequest("GET", endpointURL.String(), nil)
+	if err != nil {
+		return "", "", err
+	}
+	req = req.WithContext(ctx)
+	c.addHeadersToRequest(req.Request)
+
+	// This is just to give us something to return in error messages. It's
+	// not a proper provider address.
+	placeholderProviderAddr := addrs.NewLegacyProvider(typeName)
+
+	resp, err := c.httpClient.Do(req)
+	if err != nil {
+		return "", "", c.errQueryFailed(placeholderProviderAddr, err)
+	}
+	defer resp.Body.Close()
+
+	switch resp.StatusCode {
+	case http.StatusOK:
+		// Great!
+	case http.StatusNotFound:
+		return "", "", ErrProviderNotFound{
+			Provider: placeholderProviderAddr,
+		}
+	case http.StatusUnauthorized, http.StatusForbidden:
+		return "", "", c.errUnauthorized(placeholderProviderAddr.Hostname)
+	default:
+		return "", "", c.errQueryFailed(placeholderProviderAddr, errors.New(resp.Status))
+	}
+
+	type ResponseBody struct {
+		Id      string `json:"id"`
+		MovedTo string `json:"moved_to"`
+	}
+	var body ResponseBody
+
+	dec := json.NewDecoder(resp.Body)
+	if err := dec.Decode(&body); err != nil {
+		return "", "", c.errQueryFailed(placeholderProviderAddr, err)
+	}
+
+	provider, diags := addrs.ParseProviderSourceString(body.Id)
+	if diags.HasErrors() {
+		return "", "", fmt.Errorf("Error parsing provider ID from Registry: %s", diags.Err())
+	}
+
+	if provider.Type != typeName {
+		return "", "", fmt.Errorf("Registry returned provider with type %q, expected %q", provider.Type, typeName)
+	}
+
+	var movedTo addrs.Provider
+	if body.MovedTo != "" {
+		movedTo, diags = addrs.ParseProviderSourceString(body.MovedTo)
+		if diags.HasErrors() {
+			return "", "", fmt.Errorf("Error parsing provider ID from Registry: %s", diags.Err())
+		}
+
+		if movedTo.Type != typeName {
+			return "", "", fmt.Errorf("Registry returned provider with type %q, expected %q", movedTo.Type, typeName)
+		}
+	}
+
+	return provider.Namespace, movedTo.Namespace, nil
+}
diff --git a/v1.5.7/internal/getproviders/didyoumean_test.go b/v1.5.7/internal/getproviders/didyoumean_test.go
new file mode 100644
index 0000000..a9d97cb
--- /dev/null
+++ b/v1.5.7/internal/getproviders/didyoumean_test.go
@@ -0,0 +1,198 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+	"testing"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestMissingProviderSuggestion(t *testing.T) {
+	// Most of these test cases rely on specific "magic" provider addresses
+	// that are implemented by the fake registry source returned by
+	// testRegistrySource. Refer to that function for more details on how
+	// they work.
+
+	t.Run("happy path", func(t *testing.T) {
+		ctx := context.Background()
+		source, _, close := testRegistrySource(t)
+		defer close()
+
+		// testRegistrySource handles -/legacy as a valid legacy provider
+		// lookup mapping to legacycorp/legacy.
+		legacyAddr := addrs.NewDefaultProvider("legacy")
+		got := MissingProviderSuggestion(
+			ctx,
+			addrs.NewDefaultProvider("legacy"),
+			source,
+			Requirements{
+				legacyAddr: MustParseVersionConstraints(">= 1.0.0"),
+			},
+		)
+
+		want := addrs.Provider{
+			Hostname:  defaultRegistryHost,
+			Namespace: "legacycorp",
+			Type:      "legacy",
+		}
+		if got != want {
+			t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run("provider moved", func(t *testing.T) {
+		ctx := context.Background()
+		source, _, close := testRegistrySource(t)
+		defer close()
+
+		// testRegistrySource handles -/moved as a valid legacy provider
+		// lookup mapping to hashicorp/moved but with an additional "redirect"
+		// to acme/moved. This mimics how for some providers there is both
+		// a copy under terraform-providers for v0.12 compatibility _and_ a
+		// copy in some other namespace for v0.13 or later to use. Our naming
+		// suggestions ignore the v0.12-compatible one and suggest the
+		// other one.
+		moved := addrs.NewDefaultProvider("moved")
+		want := addrs.Provider{
+			Hostname:  defaultRegistryHost,
+			Namespace: "acme",
+			Type:      "moved",
+		}
+
+		got := MissingProviderSuggestion(
+			ctx,
+			moved,
+			source,
+			Requirements{
+				moved: MustParseVersionConstraints(">= 1.0.0"),
+			},
+		)
+
+		if got != want {
+			t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+		}
+
+		// If a provider has moved, but there's provider requirements
+		// for something of the same type, we'll return that one
+		// and skip the legacy lookup process. In practice,
+		// hopefully this is also "acme" but it's "zcme" here to
+		// exercise the codepath
+		want2 := addrs.Provider{
+			Hostname:  defaultRegistryHost,
+			Namespace: "zcme",
+			Type:      "moved",
+		}
+		got2 := MissingProviderSuggestion(
+			ctx,
+			moved,
+			source,
+			Requirements{
+				moved: MustParseVersionConstraints(">= 1.0.0"),
+				want2: MustParseVersionConstraints(">= 1.0.0"),
+			},
+		)
+
+		if got2 != want2 {
+			t.Errorf("wrong result\ngot:  %s\nwant: %s", got2, want2)
+		}
+	})
+	t.Run("invalid response", func(t *testing.T) {
+		ctx := context.Background()
+		source, _, close := testRegistrySource(t)
+		defer close()
+
+		// testRegistrySource handles -/invalid by returning an invalid
+		// provider address, which MissingProviderSuggestion should reject
+		// and behave as if there was no suggestion available.
+		want := addrs.NewDefaultProvider("invalid")
+		got := MissingProviderSuggestion(
+			ctx,
+			want,
+			source,
+			Requirements{
+				want: MustParseVersionConstraints(">= 1.0.0"),
+			},
+		)
+		if got != want {
+			t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run("another registry", func(t *testing.T) {
+		ctx := context.Background()
+		source, _, close := testRegistrySource(t)
+		defer close()
+
+		// Because this provider address isn't on registry.terraform.io,
+		// MissingProviderSuggestion won't even attempt to make a suggestion
+		// for it.
+		want := addrs.Provider{
+			Hostname:  svchost.Hostname("example.com"),
+			Namespace: "whatever",
+			Type:      "foo",
+		}
+		got := MissingProviderSuggestion(
+			ctx,
+			want,
+			source,
+			Requirements{
+				want: MustParseVersionConstraints(">= 1.0.0"),
+			},
+		)
+		if got != want {
+			t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run("another namespace", func(t *testing.T) {
+		ctx := context.Background()
+		source, _, close := testRegistrySource(t)
+		defer close()
+
+		// Because this provider address isn't in
+		// registry.terraform.io/hashicorp/..., MissingProviderSuggestion
+		// will provide the same addr since there's no alternative in Requirements
+		want := addrs.Provider{
+			Hostname:  defaultRegistryHost,
+			Namespace: "whatever",
+			Type:      "foo",
+		}
+		got := MissingProviderSuggestion(
+			ctx,
+			want,
+			source,
+			Requirements{
+				want: MustParseVersionConstraints(">= 1.0.0"),
+			},
+		)
+		if got != want {
+			t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+		}
+
+		// If there is a provider required that has the same type,
+		// but different namespace, we can suggest that
+		foo := addrs.Provider{
+			Hostname:  defaultRegistryHost,
+			Namespace: "hashicorp",
+			Type:      "foo",
+		}
+		realFoo := addrs.Provider{
+			Hostname:  defaultRegistryHost,
+			Namespace: "acme",
+			Type:      "foo",
+		}
+		got2 := MissingProviderSuggestion(
+			ctx,
+			foo,
+			source,
+			Requirements{
+				foo:     MustParseVersionConstraints(">= 1.0.0"),
+				realFoo: MustParseVersionConstraints(">= 1.0.0"),
+			},
+		)
+		if got2 != realFoo {
+			t.Errorf("wrong result\ngot:  %s\nwant: %s", got2, realFoo)
+		}
+	})
+}
diff --git a/v1.5.7/internal/getproviders/doc.go b/v1.5.7/internal/getproviders/doc.go
new file mode 100644
index 0000000..715c9ae
--- /dev/null
+++ b/v1.5.7/internal/getproviders/doc.go
@@ -0,0 +1,14 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package getproviders is the lowest-level provider automatic installation
+// functionality. It can answer questions about what providers and provider
+// versions are available in a registry, and it can retrieve the URL for
+// the distribution archive for a specific version of a specific provider
+// targeting a particular platform.
+//
+// This package is not responsible for choosing the best version to install
+// from a set of available versions, or for any signature verification of the
+// archives it fetches. Callers will use this package in conjunction with other
+// logic elsewhere in order to construct a full provider installer.
+package getproviders
diff --git a/v1.5.7/internal/getproviders/errors.go b/v1.5.7/internal/getproviders/errors.go
new file mode 100644
index 0000000..aa87466
--- /dev/null
+++ b/v1.5.7/internal/getproviders/errors.go
@@ -0,0 +1,249 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"fmt"
+	"net/url"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// ErrHostNoProviders is an error type used to indicate that a hostname given
+// in a provider address does not support the provider registry protocol.
+type ErrHostNoProviders struct {
+	Hostname svchost.Hostname
+
+	// HasOtherVersionis set to true if the discovery process detected
+	// declarations of services named "providers" whose version numbers did not
+	// match any version supported by the current version of Terraform.
+	//
+	// If this is set, it's helpful to hint to the user in an error message
+	// that the provider host may be expecting an older or a newer version
+	// of Terraform, rather than that it isn't a provider registry host at all.
+	HasOtherVersion bool
+}
+
+func (err ErrHostNoProviders) Error() string {
+	switch {
+	case err.HasOtherVersion:
+		return fmt.Sprintf("host %s does not support the provider registry protocol required by this Terraform version, but may be compatible with a different Terraform version", err.Hostname.ForDisplay())
+	default:
+		return fmt.Sprintf("host %s does not offer a Terraform provider registry", err.Hostname.ForDisplay())
+	}
+}
+
+// ErrHostUnreachable is an error type used to indicate that a hostname
+// given in a provider address did not resolve in DNS, did not respond to an
+// HTTPS request for service discovery, or otherwise failed to correctly speak
+// the service discovery protocol.
+type ErrHostUnreachable struct {
+	Hostname svchost.Hostname
+	Wrapped  error
+}
+
+func (err ErrHostUnreachable) Error() string {
+	return fmt.Sprintf("could not connect to %s: %s", err.Hostname.ForDisplay(), err.Wrapped.Error())
+}
+
+// Unwrap returns the underlying error that occurred when trying to reach the
+// indicated host.
+func (err ErrHostUnreachable) Unwrap() error {
+	return err.Wrapped
+}
+
+// ErrUnauthorized is an error type used to indicate that a hostname
+// given in a provider address returned a "401 Unauthorized" or "403 Forbidden"
+// error response when we tried to access it.
+type ErrUnauthorized struct {
+	Hostname svchost.Hostname
+
+	// HaveCredentials is true when the request that failed included some
+	// credentials, and thus it seems that those credentials were invalid.
+	// Conversely, HaveCredentials is false if the request did not include
+	// credentials at all, in which case it seems that credentials must be
+	// provided.
+	HaveCredentials bool
+}
+
+func (err ErrUnauthorized) Error() string {
+	switch {
+	case err.HaveCredentials:
+		return fmt.Sprintf("host %s rejected the given authentication credentials", err.Hostname)
+	default:
+		return fmt.Sprintf("host %s requires authentication credentials", err.Hostname)
+	}
+}
+
+// ErrProviderNotFound is an error type used to indicate that requested provider
+// was not found in the source(s) included in the Description field. This can be
+// used to produce user-friendly error messages.
+type ErrProviderNotFound struct {
+	Provider addrs.Provider
+	Sources  []string
+}
+
+func (err ErrProviderNotFound) Error() string {
+	return fmt.Sprintf(
+		"provider %s was not found in any of the search locations",
+		err.Provider,
+	)
+}
+
+// ErrRegistryProviderNotKnown is an error type used to indicate that the hostname
+// given in a provider address does appear to be a provider registry but that
+// registry does not know about the given provider namespace or type.
+//
+// A caller serving requests from an end-user should recognize this error type
+// and use it to produce user-friendly hints for common errors such as failing
+// to specify an explicit source for a provider not in the default namespace
+// (one not under registry.terraform.io/hashicorp/). The default error message
+// for this type is a direct description of the problem with no such hints,
+// because we expect that the caller will have better context to decide what
+// hints are appropriate, e.g. by looking at the configuration given by the
+// user.
+type ErrRegistryProviderNotKnown struct {
+	Provider addrs.Provider
+}
+
+func (err ErrRegistryProviderNotKnown) Error() string {
+	return fmt.Sprintf(
+		"provider registry %s does not have a provider named %s",
+		err.Provider.Hostname.ForDisplay(),
+		err.Provider,
+	)
+}
+
+// ErrPlatformNotSupported is an error type used to indicate that a particular
+// version of a provider isn't available for a particular target platform.
+//
+// This is returned when DownloadLocation encounters a 404 Not Found response
+// from the underlying registry, because it presumes that a caller will only
+// ask for the DownloadLocation for a version it already found the existence
+// of via AvailableVersions.
+type ErrPlatformNotSupported struct {
+	Provider addrs.Provider
+	Version  Version
+	Platform Platform
+
+	// MirrorURL, if non-nil, is the base URL of the mirror that serviced
+	// the request in place of the provider's origin registry. MirrorURL
+	// is nil for a direct query.
+	MirrorURL *url.URL
+}
+
+func (err ErrPlatformNotSupported) Error() string {
+	if err.MirrorURL != nil {
+		return fmt.Sprintf(
+			"provider mirror %s does not have a package of %s %s for %s",
+			err.MirrorURL.String(),
+			err.Provider,
+			err.Version,
+			err.Platform,
+		)
+	}
+	return fmt.Sprintf(
+		"provider %s %s is not available for %s",
+		err.Provider,
+		err.Version,
+		err.Platform,
+	)
+}
+
+// ErrProtocolNotSupported is an error type used to indicate that a particular
+// version of a provider is not supported by the current version of Terraform.
+//
+// Specfically, this is returned when the version's plugin protocol is not supported.
+//
+// When available, the error will include a suggested version that can be displayed to
+// the user. Otherwise it will return UnspecifiedVersion
+type ErrProtocolNotSupported struct {
+	Provider   addrs.Provider
+	Version    Version
+	Suggestion Version
+}
+
+func (err ErrProtocolNotSupported) Error() string {
+	return fmt.Sprintf(
+		"provider %s %s is not supported by this version of terraform",
+		err.Provider,
+		err.Version,
+	)
+}
+
+// ErrQueryFailed is an error type used to indicate that the hostname given
+// in a provider address does appear to be a provider registry but that when
+// we queried it for metadata for the given provider the server returned an
+// unexpected error.
+//
+// This is used for any error responses other than "Not Found", which would
+// indicate the absense of a provider and is thus reported using
+// ErrProviderNotKnown instead.
+type ErrQueryFailed struct {
+	Provider addrs.Provider
+	Wrapped  error
+
+	// MirrorURL, if non-nil, is the base URL of the mirror that serviced
+	// the request in place of the provider's origin registry. MirrorURL
+	// is nil for a direct query.
+	MirrorURL *url.URL
+}
+
+func (err ErrQueryFailed) Error() string {
+	if err.MirrorURL != nil {
+		return fmt.Sprintf(
+			"failed to query provider mirror %s for %s: %s",
+			err.MirrorURL.String(),
+			err.Provider.String(),
+			err.Wrapped.Error(),
+		)
+	}
+	return fmt.Sprintf(
+		"could not query provider registry for %s: %s",
+		err.Provider.String(),
+		err.Wrapped.Error(),
+	)
+}
+
+// Unwrap returns the underlying error that occurred when trying to reach the
+// indicated host.
+func (err ErrQueryFailed) Unwrap() error {
+	return err.Wrapped
+}
+
+// ErrRequestCanceled is an error type used to indicate that an operation
+// failed due to being cancelled via the given context.Context object.
+//
+// This error type doesn't include information about what was cancelled,
+// because the expected treatment of this error type is to quickly abort and
+// exit with minimal ceremony.
+type ErrRequestCanceled struct {
+}
+
+func (err ErrRequestCanceled) Error() string {
+	return "request canceled"
+}
+
+// ErrIsNotExist returns true if and only if the given error is one of the
+// errors from this package that represents an affirmative response that a
+// requested object does not exist.
+//
+// This is as opposed to errors indicating that the source is unavailable
+// or misconfigured in some way, where we therefore cannot say for certain
+// whether the requested object exists.
+//
+// If a caller needs to take a special action based on something not existing,
+// such as falling back on some other source, use this function rather than
+// direct type assertions so that the set of possible "not exist" errors can
+// grow in future.
+func ErrIsNotExist(err error) bool {
+	switch err.(type) {
+	case ErrProviderNotFound, ErrRegistryProviderNotKnown, ErrPlatformNotSupported:
+		return true
+	default:
+		return false
+	}
+}
diff --git a/v1.5.7/internal/getproviders/filesystem_mirror_source.go b/v1.5.7/internal/getproviders/filesystem_mirror_source.go
new file mode 100644
index 0000000..039f06c
--- /dev/null
+++ b/v1.5.7/internal/getproviders/filesystem_mirror_source.go
@@ -0,0 +1,131 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// FilesystemMirrorSource is a source that reads providers and their metadata
+// from a directory prefix in the local filesystem.
+type FilesystemMirrorSource struct {
+	baseDir string
+
+	// allPackages caches the result of scanning the baseDir for all available
+	// packages on the first call that needs package availability information,
+	// to avoid re-scanning the filesystem on subsequent operations.
+	allPackages map[addrs.Provider]PackageMetaList
+}
+
+var _ Source = (*FilesystemMirrorSource)(nil)
+
+// NewFilesystemMirrorSource constructs and returns a new filesystem-based
+// mirror source with the given base directory.
+func NewFilesystemMirrorSource(baseDir string) *FilesystemMirrorSource {
+	return &FilesystemMirrorSource{
+		baseDir: baseDir,
+	}
+}
+
+// AvailableVersions scans the directory structure under the source's base
+// directory for locally-mirrored packages for the given provider, returning
+// a list of version numbers for the providers it found.
+func (s *FilesystemMirrorSource) AvailableVersions(ctx context.Context, provider addrs.Provider) (VersionList, Warnings, error) {
+	// s.allPackages is populated if scanAllVersions succeeds
+	err := s.scanAllVersions()
+	if err != nil {
+		return nil, nil, err
+	}
+
+	// There might be multiple packages for a given version in the filesystem,
+	// but the contract here is to return distinct versions so we'll dedupe
+	// them first, then sort them, and then return them.
+	versionsMap := make(map[Version]struct{})
+	for _, m := range s.allPackages[provider] {
+		versionsMap[m.Version] = struct{}{}
+	}
+	ret := make(VersionList, 0, len(versionsMap))
+	for v := range versionsMap {
+		ret = append(ret, v)
+	}
+	ret.Sort()
+	return ret, nil, nil
+}
+
+// PackageMeta checks to see if the source's base directory contains a
+// local copy of the distribution package for the given provider version on
+// the given target, and returns the metadata about it if so.
+func (s *FilesystemMirrorSource) PackageMeta(ctx context.Context, provider addrs.Provider, version Version, target Platform) (PackageMeta, error) {
+	// s.allPackages is populated if scanAllVersions succeeds
+	err := s.scanAllVersions()
+	if err != nil {
+		return PackageMeta{}, err
+	}
+
+	relevantPkgs := s.allPackages[provider].FilterProviderPlatformExactVersion(provider, target, version)
+	if len(relevantPkgs) == 0 {
+		// This is the local equivalent of a "404 Not Found" when retrieving
+		// a particular version from a registry or network mirror. Because
+		// the caller should've selected a version already found by
+		// AvailableVersions, the only discriminator that should fail here
+		// is the target platform, and so our error result assumes that,
+		// causing the caller to return an error like "This provider version is
+		// not compatible with aros_riscv".
+		return PackageMeta{}, ErrPlatformNotSupported{
+			Provider: provider,
+			Version:  version,
+			Platform: target,
+		}
+	}
+
+	// It's possible that there could be multiple copies of the same package
+	// available in the filesystem, if e.g. there's both a packed and an
+	// unpacked variant. For now we assume that the decision between them
+	// is arbitrary and just take the first one in the result.
+	return relevantPkgs[0], nil
+}
+
+// AllAvailablePackages scans the directory structure under the source's base
+// directory for locally-mirrored packages for all providers, returning a map
+// of the discovered packages with the fully-qualified provider names as
+// keys.
+//
+// This is not an operation generally supported by all Source implementations,
+// but the filesystem implementation offers it because we also use the
+// filesystem mirror source directly to scan our auto-install plugin directory
+// and in other automatic discovery situations.
+func (s *FilesystemMirrorSource) AllAvailablePackages() (map[addrs.Provider]PackageMetaList, error) {
+	// s.allPackages is populated if scanAllVersions succeeds
+	err := s.scanAllVersions()
+	return s.allPackages, err
+}
+
+func (s *FilesystemMirrorSource) scanAllVersions() error {
+	if s.allPackages != nil {
+		// we're distinguishing nil-ness from emptiness here so we can
+		// recognize when we've scanned the directory without errors, even
+		// if we found nothing during the scan.
+		return nil
+	}
+
+	ret, err := SearchLocalDirectory(s.baseDir)
+	if err != nil {
+		return err
+	}
+
+	// As noted above, we use an explicit empty map so we can distinguish a
+	// successful-but-empty result from a failure on future calls, so we'll
+	// make sure that's what we have before we assign it here.
+	if ret == nil {
+		ret = make(map[addrs.Provider]PackageMetaList)
+	}
+	s.allPackages = ret
+	return nil
+}
+
+func (s *FilesystemMirrorSource) ForDisplay(provider addrs.Provider) string {
+	return s.baseDir
+}
diff --git a/v1.5.7/internal/getproviders/filesystem_mirror_source_test.go b/v1.5.7/internal/getproviders/filesystem_mirror_source_test.go
new file mode 100644
index 0000000..ba3be8d
--- /dev/null
+++ b/v1.5.7/internal/getproviders/filesystem_mirror_source_test.go
@@ -0,0 +1,205 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+	"testing"
+
+	"github.com/apparentlymart/go-versions/versions"
+	"github.com/google/go-cmp/cmp"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestFilesystemMirrorSourceAllAvailablePackages(t *testing.T) {
+	source := NewFilesystemMirrorSource("testdata/filesystem-mirror")
+	got, err := source.AllAvailablePackages()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	want := map[addrs.Provider]PackageMetaList{
+		nullProvider: {
+			{
+				Provider:       nullProvider,
+				Version:        versions.MustParseVersion("2.0.0"),
+				TargetPlatform: Platform{"darwin", "amd64"},
+				Filename:       "terraform-provider-null_2.0.0_darwin_amd64.zip",
+				Location:       PackageLocalDir("testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64"),
+			},
+			{
+				Provider:       nullProvider,
+				Version:        versions.MustParseVersion("2.0.0"),
+				TargetPlatform: Platform{"linux", "amd64"},
+				Filename:       "terraform-provider-null_2.0.0_linux_amd64.zip",
+				Location:       PackageLocalDir("testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64"),
+			},
+			{
+				Provider:       nullProvider,
+				Version:        versions.MustParseVersion("2.1.0"),
+				TargetPlatform: Platform{"linux", "amd64"},
+				Filename:       "terraform-provider-null_2.1.0_linux_amd64.zip",
+				Location:       PackageLocalArchive("testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip"),
+			},
+			{
+				Provider:       nullProvider,
+				Version:        versions.MustParseVersion("2.0.0"),
+				TargetPlatform: Platform{"windows", "amd64"},
+				Filename:       "terraform-provider-null_2.0.0_windows_amd64.zip",
+				Location:       PackageLocalDir("testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64"),
+			},
+		},
+		randomBetaProvider: {
+			{
+				Provider:       randomBetaProvider,
+				Version:        versions.MustParseVersion("1.2.0"),
+				TargetPlatform: Platform{"linux", "amd64"},
+				Filename:       "terraform-provider-random-beta_1.2.0_linux_amd64.zip",
+				Location:       PackageLocalDir("testdata/filesystem-mirror/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64"),
+			},
+		},
+		randomProvider: {
+			{
+				Provider:       randomProvider,
+				Version:        versions.MustParseVersion("1.2.0"),
+				TargetPlatform: Platform{"linux", "amd64"},
+				Filename:       "terraform-provider-random_1.2.0_linux_amd64.zip",
+				Location:       PackageLocalDir("testdata/filesystem-mirror/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64"),
+			},
+		},
+
+		happycloudProvider: {
+			{
+				Provider:       happycloudProvider,
+				Version:        versions.MustParseVersion("0.1.0-alpha.2"),
+				TargetPlatform: Platform{"darwin", "amd64"},
+				Filename:       "terraform-provider-happycloud_0.1.0-alpha.2_darwin_amd64.zip",
+				Location:       PackageLocalDir("testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64"),
+			},
+		},
+		legacyProvider: {
+			{
+				Provider:       legacyProvider,
+				Version:        versions.MustParseVersion("1.0.0"),
+				TargetPlatform: Platform{"linux", "amd64"},
+				Filename:       "terraform-provider-legacy_1.0.0_linux_amd64.zip",
+				Location:       PackageLocalDir("testdata/filesystem-mirror/registry.terraform.io/-/legacy/1.0.0/linux_amd64"),
+			},
+		},
+	}
+
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Errorf("incorrect result\n%s", diff)
+	}
+}
+
+// In this test the directory layout is invalid (missing the hostname
+// subdirectory). The provider installer should ignore the invalid directory.
+func TestFilesystemMirrorSourceAllAvailablePackages_invalid(t *testing.T) {
+	source := NewFilesystemMirrorSource("testdata/filesystem-mirror-invalid")
+	_, err := source.AllAvailablePackages()
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestFilesystemMirrorSourceAvailableVersions(t *testing.T) {
+	source := NewFilesystemMirrorSource("testdata/filesystem-mirror")
+	got, _, err := source.AvailableVersions(context.Background(), nullProvider)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	want := VersionList{
+		versions.MustParseVersion("2.0.0"),
+		versions.MustParseVersion("2.1.0"),
+	}
+
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Errorf("incorrect result\n%s", diff)
+	}
+}
+
+func TestFilesystemMirrorSourcePackageMeta(t *testing.T) {
+	t.Run("available platform", func(t *testing.T) {
+		source := NewFilesystemMirrorSource("testdata/filesystem-mirror")
+		got, err := source.PackageMeta(
+			context.Background(),
+			nullProvider,
+			versions.MustParseVersion("2.0.0"),
+			Platform{"linux", "amd64"},
+		)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		want := PackageMeta{
+			Provider:       nullProvider,
+			Version:        versions.MustParseVersion("2.0.0"),
+			TargetPlatform: Platform{"linux", "amd64"},
+			Filename:       "terraform-provider-null_2.0.0_linux_amd64.zip",
+			Location:       PackageLocalDir("testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64"),
+		}
+
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("incorrect result\n%s", diff)
+		}
+
+		if gotHashes := got.AcceptableHashes(); len(gotHashes) != 0 {
+			t.Errorf("wrong acceptable hashes\ngot:  %#v\nwant: none", gotHashes)
+		}
+	})
+	t.Run("unavailable platform", func(t *testing.T) {
+		source := NewFilesystemMirrorSource("testdata/filesystem-mirror")
+		// We'll request a version that does exist in the fixture directory,
+		// but for a platform that isn't supported.
+		_, err := source.PackageMeta(
+			context.Background(),
+			nullProvider,
+			versions.MustParseVersion("2.0.0"),
+			Platform{"nonexist", "nonexist"},
+		)
+
+		if err == nil {
+			t.Fatalf("succeeded; want error")
+		}
+
+		// This specific error type is important so callers can use it to
+		// generate an actionable error message e.g. by checking to see if
+		// _any_ versions of this provider support the given platform, or
+		// similar helpful hints.
+		wantErr := ErrPlatformNotSupported{
+			Provider: nullProvider,
+			Version:  versions.MustParseVersion("2.0.0"),
+			Platform: Platform{"nonexist", "nonexist"},
+		}
+		if diff := cmp.Diff(wantErr, err); diff != "" {
+			t.Errorf("incorrect error\n%s", diff)
+		}
+	})
+}
+
+var nullProvider = addrs.Provider{
+	Hostname:  svchost.Hostname("registry.terraform.io"),
+	Namespace: "hashicorp",
+	Type:      "null",
+}
+var randomProvider = addrs.Provider{
+	Hostname:  svchost.Hostname("registry.terraform.io"),
+	Namespace: "hashicorp",
+	Type:      "random",
+}
+var randomBetaProvider = addrs.Provider{
+	Hostname:  svchost.Hostname("registry.terraform.io"),
+	Namespace: "hashicorp",
+	Type:      "random-beta",
+}
+var happycloudProvider = addrs.Provider{
+	Hostname:  svchost.Hostname("tfe.example.com"),
+	Namespace: "awesomecorp",
+	Type:      "happycloud",
+}
+var legacyProvider = addrs.NewLegacyProvider("legacy")
diff --git a/v1.5.7/internal/getproviders/filesystem_search.go b/v1.5.7/internal/getproviders/filesystem_search.go
new file mode 100644
index 0000000..c50a148
--- /dev/null
+++ b/v1.5.7/internal/getproviders/filesystem_search.go
@@ -0,0 +1,292 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// SearchLocalDirectory performs an immediate, one-off scan of the given base
+// directory for provider plugins using the directory structure defined for
+// FilesystemMirrorSource.
+//
+// This is separated to allow other callers, such as the provider plugin cache
+// management in the "internal/providercache" package, to use the same
+// directory structure conventions.
+func SearchLocalDirectory(baseDir string) (map[addrs.Provider]PackageMetaList, error) {
+	ret := make(map[addrs.Provider]PackageMetaList)
+
+	// We don't support symlinks at intermediate points inside the directory
+	// hierarchy because that could potentially cause our walk to get into
+	// an infinite loop, but as a measure of pragmatism we'll allow the
+	// top-level location itself to be a symlink, so that a user can
+	// potentially keep their plugins in a non-standard location but use a
+	// symlink to help Terraform find them anyway.
+	originalBaseDir := baseDir
+	if finalDir, err := filepath.EvalSymlinks(baseDir); err == nil {
+		if finalDir != filepath.Clean(baseDir) {
+			log.Printf("[TRACE] getproviders.SearchLocalDirectory: using %s instead of %s", finalDir, baseDir)
+		}
+		baseDir = finalDir
+	} else {
+		// We'll eat this particular error because if we're somehow able to
+		// find plugins via baseDir below anyway then we'd rather do that than
+		// hard fail, but we'll log it in case it's useful for diagnosing why
+		// discovery didn't produce the expected outcome.
+		log.Printf("[TRACE] getproviders.SearchLocalDirectory: failed to resolve symlinks for %s: %s", baseDir, err)
+	}
+
+	err := filepath.Walk(baseDir, func(fullPath string, info os.FileInfo, err error) error {
+		if err != nil {
+			return fmt.Errorf("cannot search %s: %s", fullPath, err)
+		}
+
+		// There are two valid directory structures that we support here...
+		// Unpacked: registry.terraform.io/hashicorp/aws/2.0.0/linux_amd64 (a directory)
+		// Packed:   registry.terraform.io/hashicorp/aws/terraform-provider-aws_2.0.0_linux_amd64.zip (a file)
+		//
+		// Both of these give us enough information to identify the package
+		// metadata.
+		fsPath, err := filepath.Rel(baseDir, fullPath)
+		if err != nil {
+			// This should never happen because the filepath.Walk contract is
+			// for the paths to include the base path.
+			log.Printf("[TRACE] getproviders.SearchLocalDirectory: ignoring malformed path %q during walk: %s", fullPath, err)
+			return nil
+		}
+		relPath := filepath.ToSlash(fsPath)
+		parts := strings.Split(relPath, "/")
+
+		if len(parts) < 3 {
+			// Likely a prefix of a valid path, so we'll ignore it and visit
+			// the full valid path on a later call.
+
+			if (info.Mode() & os.ModeSymlink) != 0 {
+				// We don't allow symlinks for intermediate steps in the
+				// hierarchy because otherwise this walk would risk getting
+				// itself into an infinite loop, but if we do find one then
+				// we'll warn about it to help with debugging.
+				log.Printf("[WARN] Provider plugin search ignored symlink %s: only the base directory %s may be a symlink", fullPath, originalBaseDir)
+			}
+
+			return nil
+		}
+
+		hostnameGiven := parts[0]
+		namespace := parts[1]
+		typeName := parts[2]
+
+		// validate each part
+		// The legacy provider namespace is a special case.
+		if namespace != addrs.LegacyProviderNamespace {
+			_, err = addrs.ParseProviderPart(namespace)
+			if err != nil {
+				log.Printf("[WARN] local provider path %q contains invalid namespace %q; ignoring", fullPath, namespace)
+				return nil
+			}
+		}
+
+		_, err = addrs.ParseProviderPart(typeName)
+		if err != nil {
+			log.Printf("[WARN] local provider path %q contains invalid type %q; ignoring", fullPath, typeName)
+			return nil
+		}
+
+		hostname, err := svchost.ForComparison(hostnameGiven)
+		if err != nil {
+			log.Printf("[WARN] local provider path %q contains invalid hostname %q; ignoring", fullPath, hostnameGiven)
+			return nil
+		}
+		var providerAddr addrs.Provider
+		if namespace == addrs.LegacyProviderNamespace {
+			if hostname != addrs.DefaultProviderRegistryHost {
+				log.Printf("[WARN] local provider path %q indicates a legacy provider not on the default registry host; ignoring", fullPath)
+				return nil
+			}
+			providerAddr = addrs.NewLegacyProvider(typeName)
+		} else {
+			providerAddr = addrs.NewProvider(hostname, namespace, typeName)
+		}
+
+		// The "info" passed to our function is an Lstat result, so it might
+		// be referring to a symbolic link. We'll do a full "Stat" on it
+		// now to make sure we're making tests against the real underlying
+		// filesystem object below.
+		info, err = os.Stat(fullPath)
+		if err != nil {
+			log.Printf("[WARN] failed to read metadata about %s: %s", fullPath, err)
+			return nil
+		}
+
+		switch len(parts) {
+		case 5: // Might be unpacked layout
+			if !info.IsDir() {
+				return nil // packed layout requires a directory
+			}
+
+			versionStr := parts[3]
+			version, err := ParseVersion(versionStr)
+			if err != nil {
+				log.Printf("[WARN] ignoring local provider path %q with invalid version %q: %s", fullPath, versionStr, err)
+				return nil
+			}
+
+			platformStr := parts[4]
+			platform, err := ParsePlatform(platformStr)
+			if err != nil {
+				log.Printf("[WARN] ignoring local provider path %q with invalid platform %q: %s", fullPath, platformStr, err)
+				return nil
+			}
+
+			log.Printf("[TRACE] getproviders.SearchLocalDirectory: found %s v%s for %s at %s", providerAddr, version, platform, fullPath)
+
+			meta := PackageMeta{
+				Provider: providerAddr,
+				Version:  version,
+
+				// FIXME: How do we populate this?
+				ProtocolVersions: nil,
+				TargetPlatform:   platform,
+
+				// Because this is already unpacked, the filename is synthetic
+				// based on the standard naming scheme.
+				Filename: fmt.Sprintf("terraform-provider-%s_%s_%s.zip", providerAddr.Type, version, platform),
+				Location: PackageLocalDir(fullPath),
+
+				// FIXME: What about the SHA256Sum field? As currently specified
+				// it's a hash of the zip file, but this thing is already
+				// unpacked and so we don't have the zip file to hash.
+			}
+			ret[providerAddr] = append(ret[providerAddr], meta)
+
+		case 4: // Might be packed layout
+			if info.IsDir() {
+				return nil // packed layout requires a file
+			}
+
+			filename := filepath.Base(fsPath)
+			// the filename components are matched case-insensitively, and
+			// the normalized form of them is in lowercase so we'll convert
+			// to lowercase for comparison here. (This normalizes only for case,
+			// because that is the primary constraint affecting compatibility
+			// between filesystem implementations on different platforms;
+			// filenames are expected to be pre-normalized and valid in other
+			// regards.)
+			normFilename := strings.ToLower(filename)
+
+			// In the packed layout, the version number and target platform
+			// are derived from the package filename, but only if the
+			// filename has the expected prefix identifying it as a package
+			// for the provider in question, and the suffix identifying it
+			// as a zip file.
+			prefix := "terraform-provider-" + providerAddr.Type + "_"
+			const suffix = ".zip"
+			if !strings.HasPrefix(normFilename, prefix) {
+				log.Printf("[WARN] ignoring file %q as possible package for %s: filename lacks expected prefix %q", fsPath, providerAddr, prefix)
+				return nil
+			}
+			if !strings.HasSuffix(normFilename, suffix) {
+				log.Printf("[WARN] ignoring file %q as possible package for %s: filename lacks expected suffix %q", fsPath, providerAddr, suffix)
+				return nil
+			}
+
+			// Extract the version and target part of the filename, which
+			// will look like "2.1.0_linux_amd64"
+			infoSlice := normFilename[len(prefix) : len(normFilename)-len(suffix)]
+			infoParts := strings.Split(infoSlice, "_")
+			if len(infoParts) < 3 {
+				log.Printf("[WARN] ignoring file %q as possible package for %s: filename does not include version number, target OS, and target architecture", fsPath, providerAddr)
+				return nil
+			}
+
+			versionStr := infoParts[0]
+			version, err := ParseVersion(versionStr)
+			if err != nil {
+				log.Printf("[WARN] ignoring local provider path %q with invalid version %q: %s", fullPath, versionStr, err)
+				return nil
+			}
+
+			// We'll reassemble this back into a single string just so we can
+			// easily re-use our existing parser and its normalization rules.
+			platformStr := infoParts[1] + "_" + infoParts[2]
+			platform, err := ParsePlatform(platformStr)
+			if err != nil {
+				log.Printf("[WARN] ignoring local provider path %q with invalid platform %q: %s", fullPath, platformStr, err)
+				return nil
+			}
+
+			log.Printf("[TRACE] getproviders.SearchLocalDirectory: found %s v%s for %s at %s", providerAddr, version, platform, fullPath)
+
+			meta := PackageMeta{
+				Provider: providerAddr,
+				Version:  version,
+
+				// FIXME: How do we populate this?
+				ProtocolVersions: nil,
+				TargetPlatform:   platform,
+
+				// Because this is already unpacked, the filename is synthetic
+				// based on the standard naming scheme.
+				Filename: normFilename,                  // normalized filename, because this field says what it _should_ be called, not what it _is_ called
+				Location: PackageLocalArchive(fullPath), // non-normalized here, because this is the actual physical location
+
+				// TODO: Also populate the SHA256Sum field. Skipping that
+				// for now because our initial uses of this result --
+				// scanning already-installed providers in local directories,
+				// rather than explicit filesystem mirrors -- doesn't do
+				// any hash verification anyway, and this is consistent with
+				// the FIXME in the unpacked case above even though technically
+				// we _could_ populate SHA256Sum here right now.
+			}
+			ret[providerAddr] = append(ret[providerAddr], meta)
+
+		}
+
+		return nil
+	})
+	if err != nil {
+		return nil, err
+	}
+	// Sort the results to be deterministic (aside from semver build metadata)
+	// and consistent with ordering from other functions.
+	for _, l := range ret {
+		l.Sort()
+	}
+	return ret, nil
+}
+
+// UnpackedDirectoryPathForPackage is similar to
+// PackageMeta.UnpackedDirectoryPath but makes its decision based on
+// individually-passed provider address, version, and target platform so that
+// it can be used by callers outside this package that may have other
+// types that represent package identifiers.
+func UnpackedDirectoryPathForPackage(baseDir string, provider addrs.Provider, version Version, platform Platform) string {
+	return filepath.ToSlash(filepath.Join(
+		baseDir,
+		provider.Hostname.ForDisplay(), provider.Namespace, provider.Type,
+		version.String(),
+		platform.String(),
+	))
+}
+
+// PackedFilePathForPackage is similar to
+// PackageMeta.PackedFilePath but makes its decision based on
+// individually-passed provider address, version, and target platform so that
+// it can be used by callers outside this package that may have other
+// types that represent package identifiers.
+func PackedFilePathForPackage(baseDir string, provider addrs.Provider, version Version, platform Platform) string {
+	return filepath.ToSlash(filepath.Join(
+		baseDir,
+		provider.Hostname.ForDisplay(), provider.Namespace, provider.Type,
+		fmt.Sprintf("terraform-provider-%s_%s_%s.zip", provider.Type, version.String(), platform.String()),
+	))
+}
diff --git a/v1.5.7/internal/getproviders/filesystem_search_test.go b/v1.5.7/internal/getproviders/filesystem_search_test.go
new file mode 100644
index 0000000..0658c99
--- /dev/null
+++ b/v1.5.7/internal/getproviders/filesystem_search_test.go
@@ -0,0 +1,55 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"path/filepath"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestSearchLocalDirectory(t *testing.T) {
+	tests := []struct {
+		Fixture string
+		Subdir  string
+		Want    map[addrs.Provider]PackageMetaList
+	}{
+		{
+			"symlinks",
+			"symlink",
+			map[addrs.Provider]PackageMetaList{
+				addrs.MustParseProviderSourceString("example.com/foo/bar"): {
+					{
+						Provider:       addrs.MustParseProviderSourceString("example.com/foo/bar"),
+						Version:        MustParseVersion("1.0.0"),
+						TargetPlatform: Platform{OS: "linux", Arch: "amd64"},
+						Filename:       "terraform-provider-bar_1.0.0_linux_amd64.zip",
+						Location:       PackageLocalDir("testdata/search-local-directory/symlinks/real/example.com/foo/bar/1.0.0/linux_amd64"),
+					},
+				},
+				// This search doesn't find example.net/foo/bar because only
+				// the top-level search directory is supported as being a
+				// symlink, and so we ignore the example.net symlink to
+				// example.com that is one level deeper.
+			},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Fixture, func(t *testing.T) {
+			fullDir := filepath.Join("testdata/search-local-directory", test.Fixture, test.Subdir)
+			got, err := SearchLocalDirectory(fullDir)
+			if err != nil {
+				t.Errorf("unexpected error: %s", err)
+			}
+			want := test.Want
+
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/getproviders/hanging_source.go b/v1.5.7/internal/getproviders/hanging_source.go
new file mode 100644
index 0000000..fe0dc8a
--- /dev/null
+++ b/v1.5.7/internal/getproviders/hanging_source.go
@@ -0,0 +1,32 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// HangingSource is an implementation of Source which hangs until the given
+// context is cancelled. This is useful only for unit tests of user-controlled
+// cancels.
+type HangingSource struct {
+}
+
+var _ Source = (*HangingSource)(nil)
+
+func (s *HangingSource) AvailableVersions(ctx context.Context, provider addrs.Provider) (VersionList, Warnings, error) {
+	<-ctx.Done()
+	return nil, nil, nil
+}
+
+func (s *HangingSource) PackageMeta(ctx context.Context, provider addrs.Provider, version Version, target Platform) (PackageMeta, error) {
+	<-ctx.Done()
+	return PackageMeta{}, nil
+}
+
+func (s *HangingSource) ForDisplay(provider addrs.Provider) string {
+	return "hanging source"
+}
diff --git a/v1.5.7/internal/getproviders/hash.go b/v1.5.7/internal/getproviders/hash.go
new file mode 100644
index 0000000..2f58207
--- /dev/null
+++ b/v1.5.7/internal/getproviders/hash.go
@@ -0,0 +1,454 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"crypto/sha256"
+	"fmt"
+	"io"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"golang.org/x/mod/sumdb/dirhash"
+)
+
+// Hash is a specially-formatted string representing a checksum of a package
+// or the contents of the package.
+//
+// A Hash string is always starts with a scheme, which is a short series of
+// alphanumeric characters followed by a colon, and then the remainder of the
+// string has a different meaning depending on the scheme prefix.
+//
+// The currently-valid schemes are defined as the constants of type HashScheme
+// in this package.
+//
+// Callers outside of this package must not create Hash values via direct
+// conversion. Instead, use either the HashScheme.New method on one of the
+// HashScheme contents (for a hash of a particular scheme) or the ParseHash
+// function (if hashes of any scheme are acceptable).
+type Hash string
+
+// NilHash is the zero value of Hash. It isn't a valid hash, so all of its
+// methods will panic.
+const NilHash = Hash("")
+
+// ParseHash parses the string representation of a Hash into a Hash value.
+//
+// A particular version of Terraform only supports a fixed set of hash schemes,
+// but this function intentionally allows unrecognized schemes so that we can
+// silently ignore other schemes that may be introduced in the future. For
+// that reason, the Scheme method of the returned Hash may return a value that
+// isn't in one of the HashScheme constants in this package.
+//
+// This function doesn't verify that the value portion of the given hash makes
+// sense for the given scheme. Invalid values are just considered to not match
+// any packages.
+//
+// If this function returns an error then the returned Hash is invalid and
+// must not be used.
+func ParseHash(s string) (Hash, error) {
+	colon := strings.Index(s, ":")
+	if colon < 1 { // 1 because a zero-length scheme is not allowed
+		return NilHash, fmt.Errorf("hash string must start with a scheme keyword followed by a colon")
+	}
+	return Hash(s), nil
+}
+
+// MustParseHash is a wrapper around ParseHash that panics if it returns an
+// error.
+func MustParseHash(s string) Hash {
+	hash, err := ParseHash(s)
+	if err != nil {
+		panic(err.Error())
+	}
+	return hash
+}
+
+// Scheme returns the scheme of the recieving hash. If the receiver is not
+// using valid syntax then this method will panic.
+func (h Hash) Scheme() HashScheme {
+	colon := strings.Index(string(h), ":")
+	if colon < 0 {
+		panic(fmt.Sprintf("invalid hash string %q", h))
+	}
+	return HashScheme(h[:colon+1])
+}
+
+// HasScheme returns true if the given scheme matches the receiver's scheme,
+// or false otherwise.
+//
+// If the receiver is not using valid syntax then this method will panic.
+func (h Hash) HasScheme(want HashScheme) bool {
+	return h.Scheme() == want
+}
+
+// Value returns the scheme-specific value from the recieving hash. The
+// meaning of this value depends on the scheme.
+//
+// If the receiver is not using valid syntax then this method will panic.
+func (h Hash) Value() string {
+	colon := strings.Index(string(h), ":")
+	if colon < 0 {
+		panic(fmt.Sprintf("invalid hash string %q", h))
+	}
+	return string(h[colon+1:])
+}
+
+// String returns a string representation of the receiving hash.
+func (h Hash) String() string {
+	return string(h)
+}
+
+// GoString returns a Go syntax representation of the receiving hash.
+//
+// This is here primarily to help with producing descriptive test failure
+// output; these results are not particularly useful at runtime.
+func (h Hash) GoString() string {
+	if h == NilHash {
+		return "getproviders.NilHash"
+	}
+	switch scheme := h.Scheme(); scheme {
+	case HashScheme1:
+		return fmt.Sprintf("getproviders.HashScheme1.New(%q)", h.Value())
+	case HashSchemeZip:
+		return fmt.Sprintf("getproviders.HashSchemeZip.New(%q)", h.Value())
+	default:
+		// This fallback is for when we encounter lock files or API responses
+		// with hash schemes that the current version of Terraform isn't
+		// familiar with. They were presumably introduced in a later version.
+		return fmt.Sprintf("getproviders.HashScheme(%q).New(%q)", scheme, h.Value())
+	}
+}
+
+// HashScheme is an enumeration of schemes that are allowed for values of type
+// Hash.
+type HashScheme string
+
+const (
+	// HashScheme1 is the scheme identifier for the first hash scheme.
+	//
+	// Use HashV1 (or one of its wrapper functions) to calculate hashes with
+	// this scheme.
+	HashScheme1 HashScheme = HashScheme("h1:")
+
+	// HashSchemeZip is the scheme identifier for the legacy hash scheme that
+	// applies to distribution archives (.zip files) rather than package
+	// contents, and can therefore only be verified against the original
+	// distribution .zip file, not an extracted directory.
+	//
+	// Use PackageHashLegacyZipSHA to calculate hashes with this scheme.
+	HashSchemeZip HashScheme = HashScheme("zh:")
+)
+
+// New creates a new Hash value with the receiver as its scheme and the given
+// raw string as its value.
+//
+// It's the caller's responsibility to make sure that the given value makes
+// sense for the selected scheme.
+func (hs HashScheme) New(value string) Hash {
+	return Hash(string(hs) + value)
+}
+
+// PackageHash computes a hash of the contents of the package at the given
+// location, using whichever hash algorithm is the current default.
+//
+// Currently, this method returns version 1 hashes as produced by the
+// function PackageHashV1, but this function may switch to other versions in
+// later releases. Call PackageHashV1 directly if you specifically need a V1
+// hash.
+//
+// PackageHash can be used only with the two local package location types
+// PackageLocalDir and PackageLocalArchive, because it needs to access the
+// contents of the indicated package in order to compute the hash. If given
+// a non-local location this function will always return an error.
+func PackageHash(loc PackageLocation) (Hash, error) {
+	return PackageHashV1(loc)
+}
+
+// PackageMatchesHash returns true if the package at the given location matches
+// the given hash, or false otherwise.
+//
+// If it cannot read from the given location, or if the given hash is in an
+// unsupported format, PackageMatchesHash returns an error.
+//
+// There is currently only one hash format, as implemented by HashV1. However,
+// if others are introduced in future PackageMatchesHash may accept multiple
+// formats, and may generate errors for any formats that become obsolete.
+//
+// PackageMatchesHash can be used only with the two local package location types
+// PackageLocalDir and PackageLocalArchive, because it needs to access the
+// contents of the indicated package in order to compute the hash. If given
+// a non-local location this function will always return an error.
+func PackageMatchesHash(loc PackageLocation, want Hash) (bool, error) {
+	switch want.Scheme() {
+	case HashScheme1:
+		got, err := PackageHashV1(loc)
+		if err != nil {
+			return false, err
+		}
+		return got == want, nil
+	case HashSchemeZip:
+		archiveLoc, ok := loc.(PackageLocalArchive)
+		if !ok {
+			return false, fmt.Errorf(`ziphash scheme ("zh:" prefix) is not supported for unpacked provider packages`)
+		}
+		got, err := PackageHashLegacyZipSHA(archiveLoc)
+		if err != nil {
+			return false, err
+		}
+		return got == want, nil
+	default:
+		return false, fmt.Errorf("unsupported hash format (this may require a newer version of Terraform)")
+	}
+}
+
+// PackageMatchesAnyHash returns true if the package at the given location
+// matches at least one of the given hashes, or false otherwise.
+//
+// If it cannot read from the given location, PackageMatchesAnyHash returns an
+// error. Unlike the singular PackageMatchesHash, PackageMatchesAnyHash
+// considers unsupported hash formats as successfully non-matching, rather
+// than returning an error.
+//
+// PackageMatchesAnyHash can be used only with the two local package location
+// types PackageLocalDir and PackageLocalArchive, because it needs to access the
+// contents of the indicated package in order to compute the hash. If given
+// a non-local location this function will always return an error.
+func PackageMatchesAnyHash(loc PackageLocation, allowed []Hash) (bool, error) {
+	// It's likely that we'll have multiple hashes of the same scheme in
+	// the "allowed" set, in which case we'll avoid repeatedly re-reading the
+	// given package by caching its result for each of the two
+	// currently-supported hash formats. These will be NilHash until we
+	// encounter the first hash of the corresponding scheme.
+	var v1Hash, zipHash Hash
+	for _, want := range allowed {
+		switch want.Scheme() {
+		case HashScheme1:
+			if v1Hash == NilHash {
+				got, err := PackageHashV1(loc)
+				if err != nil {
+					return false, err
+				}
+				v1Hash = got
+			}
+			if v1Hash == want {
+				return true, nil
+			}
+		case HashSchemeZip:
+			archiveLoc, ok := loc.(PackageLocalArchive)
+			if !ok {
+				// A zip hash can never match an unpacked directory
+				continue
+			}
+			if zipHash == NilHash {
+				got, err := PackageHashLegacyZipSHA(archiveLoc)
+				if err != nil {
+					return false, err
+				}
+				zipHash = got
+			}
+			if zipHash == want {
+				return true, nil
+			}
+		default:
+			// If it's not a supported format then it can't match.
+			continue
+		}
+	}
+	return false, nil
+}
+
+// PreferredHashes examines all of the given hash strings and returns the one
+// that the current version of Terraform considers to provide the strongest
+// verification.
+//
+// Returns an empty string if none of the given hashes are of a supported
+// format. If PreferredHash returns a non-empty string then it will be one
+// of the hash strings in "given", and that hash is the one that must pass
+// verification in order for a package to be considered valid.
+func PreferredHashes(given []Hash) []Hash {
+	// For now this is just filtering for the two hash formats we support,
+	// both of which are considered equally "preferred". If we introduce
+	// a new scheme like "h2:" in future then, depending on the characteristics
+	// of that new version, it might make sense to rework this function so
+	// that it only returns "h1:" hashes if the input has no "h2:" hashes,
+	// so that h2: is preferred when possible and h1: is only a fallback for
+	// interacting with older systems that haven't been updated with the new
+	// scheme yet.
+
+	var ret []Hash
+	for _, hash := range given {
+		switch hash.Scheme() {
+		case HashScheme1, HashSchemeZip:
+			ret = append(ret, hash)
+		}
+	}
+	return ret
+}
+
+// PackageHashLegacyZipSHA implements the old provider package hashing scheme
+// of taking a SHA256 hash of the containing .zip archive itself, rather than
+// of the contents of the archive.
+//
+// The result is a hash string with the "zh:" prefix, which is intended to
+// represent "zip hash". After the prefix is a lowercase-hex encoded SHA256
+// checksum, intended to exactly match the formatting used in the registry
+// API (apart from the prefix) so that checksums can be more conveniently
+// compared by humans.
+//
+// Because this hashing scheme uses the official provider .zip file as its
+// input, it accepts only PackageLocalArchive locations.
+func PackageHashLegacyZipSHA(loc PackageLocalArchive) (Hash, error) {
+	archivePath, err := filepath.EvalSymlinks(string(loc))
+	if err != nil {
+		return "", err
+	}
+
+	f, err := os.Open(archivePath)
+	if err != nil {
+		return "", err
+	}
+	defer f.Close()
+
+	h := sha256.New()
+	_, err = io.Copy(h, f)
+	if err != nil {
+		return "", err
+	}
+
+	gotHash := h.Sum(nil)
+	return HashSchemeZip.New(fmt.Sprintf("%x", gotHash)), nil
+}
+
+// HashLegacyZipSHAFromSHA is a convenience method to produce the schemed-string
+// hash format from an already-calculated hash of a provider .zip archive.
+//
+// This just adds the "zh:" prefix and encodes the string in hex, so that the
+// result is in the same format as PackageHashLegacyZipSHA.
+func HashLegacyZipSHAFromSHA(sum [sha256.Size]byte) Hash {
+	return HashSchemeZip.New(fmt.Sprintf("%x", sum[:]))
+}
+
+// PackageHashV1 computes a hash of the contents of the package at the given
+// location using hash algorithm 1. The resulting Hash is guaranteed to have
+// the scheme HashScheme1.
+//
+// The hash covers the paths to files in the directory and the contents of
+// those files. It does not cover other metadata about the files, such as
+// permissions.
+//
+// This function is named "PackageHashV1" in anticipation of other hashing
+// algorithms being added in a backward-compatible way in future. The result
+// from PackageHashV1 always begins with the prefix "h1:" so that callers can
+// distinguish the results of potentially multiple different hash algorithms in
+// future.
+//
+// PackageHashV1 can be used only with the two local package location types
+// PackageLocalDir and PackageLocalArchive, because it needs to access the
+// contents of the indicated package in order to compute the hash. If given
+// a non-local location this function will always return an error.
+func PackageHashV1(loc PackageLocation) (Hash, error) {
+	// Our HashV1 is really just the Go Modules hash version 1, which is
+	// sufficient for our needs and already well-used for identity of
+	// Go Modules distribution packages. It is also blocked from incompatible
+	// changes by being used in a wide array of go.sum files already.
+	//
+	// In particular, it also supports computing an equivalent hash from
+	// an unpacked zip file, which is not important for Terraform workflow
+	// today but is likely to become so in future if we adopt a top-level
+	// lockfile mechanism that is intended to be checked in to version control,
+	// rather than just a transient lock for a particular local cache directory.
+	// (In that case we'd need to check hashes of _packed_ packages, too.)
+	//
+	// Internally, dirhash.Hash1 produces a string containing a sequence of
+	// newline-separated path+filehash pairs for all of the files in the
+	// directory, and then finally produces a hash of that string to return.
+	// In both cases, the hash algorithm is SHA256.
+
+	switch loc := loc.(type) {
+
+	case PackageLocalDir:
+		// We'll first dereference a possible symlink at our PackageDir location,
+		// as would be created if this package were linked in from another cache.
+		packageDir, err := filepath.EvalSymlinks(string(loc))
+		if err != nil {
+			return "", err
+		}
+
+		// The dirhash.HashDir result is already in our expected h1:...
+		// format, so we can just convert directly to Hash.
+		s, err := dirhash.HashDir(packageDir, "", dirhash.Hash1)
+		return Hash(s), err
+
+	case PackageLocalArchive:
+		archivePath, err := filepath.EvalSymlinks(string(loc))
+		if err != nil {
+			return "", err
+		}
+
+		// The dirhash.HashDir result is already in our expected h1:...
+		// format, so we can just convert directly to Hash.
+		s, err := dirhash.HashZip(archivePath, dirhash.Hash1)
+		return Hash(s), err
+
+	default:
+		return "", fmt.Errorf("cannot hash package at %s", loc.String())
+	}
+}
+
+// Hash computes a hash of the contents of the package at the location
+// associated with the reciever, using whichever hash algorithm is the current
+// default.
+//
+// This method will change to use new hash versions as they are introduced
+// in future. If you need a specific hash version, call the method for that
+// version directly instead, such as HashV1.
+//
+// Hash can be used only with the two local package location types
+// PackageLocalDir and PackageLocalArchive, because it needs to access the
+// contents of the indicated package in order to compute the hash. If given
+// a non-local location this function will always return an error.
+func (m PackageMeta) Hash() (Hash, error) {
+	return PackageHash(m.Location)
+}
+
+// MatchesHash returns true if the package at the location associated with
+// the receiver matches the given hash, or false otherwise.
+//
+// If it cannot read from the given location, or if the given hash is in an
+// unsupported format, MatchesHash returns an error.
+//
+// MatchesHash can be used only with the two local package location types
+// PackageLocalDir and PackageLocalArchive, because it needs to access the
+// contents of the indicated package in order to compute the hash. If given
+// a non-local location this function will always return an error.
+func (m PackageMeta) MatchesHash(want Hash) (bool, error) {
+	return PackageMatchesHash(m.Location, want)
+}
+
+// MatchesAnyHash returns true if the package at the location associated with
+// the receiver matches at least one of the given hashes, or false otherwise.
+//
+// If it cannot read from the given location, MatchesHash returns an error.
+// Unlike the signular MatchesHash, MatchesAnyHash considers an unsupported
+// hash format to be a successful non-match.
+func (m PackageMeta) MatchesAnyHash(acceptable []Hash) (bool, error) {
+	return PackageMatchesAnyHash(m.Location, acceptable)
+}
+
+// HashV1 computes a hash of the contents of the package at the location
+// associated with the receiver using hash algorithm 1.
+//
+// The hash covers the paths to files in the directory and the contents of
+// those files. It does not cover other metadata about the files, such as
+// permissions.
+//
+// HashV1 can be used only with the two local package location types
+// PackageLocalDir and PackageLocalArchive, because it needs to access the
+// contents of the indicated package in order to compute the hash. If given
+// a non-local location this function will always return an error.
+func (m PackageMeta) HashV1() (Hash, error) {
+	return PackageHashV1(m.Location)
+}
diff --git a/v1.5.7/internal/getproviders/hash_test.go b/v1.5.7/internal/getproviders/hash_test.go
new file mode 100644
index 0000000..29dad2a
--- /dev/null
+++ b/v1.5.7/internal/getproviders/hash_test.go
@@ -0,0 +1,73 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"testing"
+)
+
+func TestParseHash(t *testing.T) {
+	tests := []struct {
+		Input   string
+		Want    Hash
+		WantErr string
+	}{
+		{
+			Input: "h1:foo",
+			Want:  HashScheme1.New("foo"),
+		},
+		{
+			Input: "zh:bar",
+			Want:  HashSchemeZip.New("bar"),
+		},
+		{
+			// A scheme we don't know is considered valid syntax, it just won't match anything.
+			Input: "unknown:baz",
+			Want:  HashScheme("unknown:").New("baz"),
+		},
+		{
+			// A scheme with an empty value is weird, but allowed.
+			Input: "unknown:",
+			Want:  HashScheme("unknown:").New(""),
+		},
+		{
+			Input:   "",
+			WantErr: "hash string must start with a scheme keyword followed by a colon",
+		},
+		{
+			// A naked SHA256 hash in hex format is not sufficient
+			Input:   "1e5f7a5f3ade7b8b1d1d59c5cea2e1a2f8d2f8c3f41962dbbe8647e222be8239",
+			WantErr: "hash string must start with a scheme keyword followed by a colon",
+		},
+		{
+			// An empty scheme is not allowed
+			Input:   ":blah",
+			WantErr: "hash string must start with a scheme keyword followed by a colon",
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Input, func(t *testing.T) {
+			got, err := ParseHash(test.Input)
+
+			if test.WantErr != "" {
+				if err == nil {
+					t.Fatalf("want error: %s", test.WantErr)
+				}
+				if got, want := err.Error(), test.WantErr; got != want {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			}
+
+			if err != nil {
+				t.Fatalf("unexpected error: %s", err.Error())
+			}
+
+			if got != test.Want {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/getproviders/http_mirror_source.go b/v1.5.7/internal/getproviders/http_mirror_source.go
new file mode 100644
index 0000000..a13d492
--- /dev/null
+++ b/v1.5.7/internal/getproviders/http_mirror_source.go
@@ -0,0 +1,431 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"io"
+	"log"
+	"mime"
+	"net/http"
+	"net/url"
+	"path"
+	"strings"
+
+	"github.com/hashicorp/go-retryablehttp"
+	svchost "github.com/hashicorp/terraform-svchost"
+	svcauth "github.com/hashicorp/terraform-svchost/auth"
+	"golang.org/x/net/idna"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/httpclient"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/version"
+)
+
+// HTTPMirrorSource is a source that reads provider metadata from a provider
+// mirror that is accessible over the HTTP provider mirror protocol.
+type HTTPMirrorSource struct {
+	baseURL    *url.URL
+	creds      svcauth.CredentialsSource
+	httpClient *retryablehttp.Client
+}
+
+var _ Source = (*HTTPMirrorSource)(nil)
+
+// NewHTTPMirrorSource constructs and returns a new network mirror source with
+// the given base URL. The relative URL offsets defined by the HTTP mirror
+// protocol will be resolve relative to the given URL.
+//
+// The given URL must use the "https" scheme, or this function will panic.
+// (When the URL comes from user input, such as in the CLI config, it's the
+// UI/config layer's responsibility to validate this and return a suitable
+// error message for the end-user audience.)
+func NewHTTPMirrorSource(baseURL *url.URL, creds svcauth.CredentialsSource) *HTTPMirrorSource {
+	httpClient := httpclient.New()
+	httpClient.Timeout = requestTimeout
+	httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
+		// If we get redirected more than five times we'll assume we're
+		// in a redirect loop and bail out, rather than hanging forever.
+		if len(via) > 5 {
+			return fmt.Errorf("too many redirects")
+		}
+		return nil
+	}
+	return newHTTPMirrorSourceWithHTTPClient(baseURL, creds, httpClient)
+}
+
+func newHTTPMirrorSourceWithHTTPClient(baseURL *url.URL, creds svcauth.CredentialsSource, httpClient *http.Client) *HTTPMirrorSource {
+	if baseURL.Scheme != "https" {
+		panic("non-https URL for HTTP mirror")
+	}
+
+	// We borrow the retry settings and behaviors from the registry client,
+	// because our needs here are very similar to those of the registry client.
+	retryableClient := retryablehttp.NewClient()
+	retryableClient.HTTPClient = httpClient
+	retryableClient.RetryMax = discoveryRetry
+	retryableClient.RequestLogHook = requestLogHook
+	retryableClient.ErrorHandler = maxRetryErrorHandler
+
+	retryableClient.Logger = log.New(logging.LogOutput(), "", log.Flags())
+
+	return &HTTPMirrorSource{
+		baseURL:    baseURL,
+		creds:      creds,
+		httpClient: retryableClient,
+	}
+}
+
+// AvailableVersions retrieves the available versions for the given provider
+// from the object's underlying HTTP mirror service.
+func (s *HTTPMirrorSource) AvailableVersions(ctx context.Context, provider addrs.Provider) (VersionList, Warnings, error) {
+	log.Printf("[DEBUG] Querying available versions of provider %s at network mirror %s", provider.String(), s.baseURL.String())
+
+	endpointPath := path.Join(
+		provider.Hostname.String(),
+		provider.Namespace,
+		provider.Type,
+		"index.json",
+	)
+
+	statusCode, body, finalURL, err := s.get(ctx, endpointPath)
+	defer func() {
+		if body != nil {
+			body.Close()
+		}
+	}()
+	if err != nil {
+		return nil, nil, s.errQueryFailed(provider, err)
+	}
+
+	switch statusCode {
+	case http.StatusOK:
+		// Great!
+	case http.StatusNotFound:
+		return nil, nil, ErrProviderNotFound{
+			Provider: provider,
+		}
+	case http.StatusUnauthorized, http.StatusForbidden:
+		return nil, nil, s.errUnauthorized(finalURL)
+	default:
+		return nil, nil, s.errQueryFailed(provider, fmt.Errorf("server returned unsuccessful status %d", statusCode))
+	}
+
+	// If we got here then the response had status OK and so our body
+	// will be non-nil and should contain some JSON for us to parse.
+	type ResponseBody struct {
+		Versions map[string]struct{} `json:"versions"`
+	}
+	var bodyContent ResponseBody
+
+	dec := json.NewDecoder(body)
+	if err := dec.Decode(&bodyContent); err != nil {
+		return nil, nil, s.errQueryFailed(provider, fmt.Errorf("invalid response content from mirror server: %s", err))
+	}
+
+	if len(bodyContent.Versions) == 0 {
+		return nil, nil, nil
+	}
+	ret := make(VersionList, 0, len(bodyContent.Versions))
+	for versionStr := range bodyContent.Versions {
+		version, err := ParseVersion(versionStr)
+		if err != nil {
+			log.Printf("[WARN] Ignoring invalid %s version string %q in provider mirror response", provider, versionStr)
+			continue
+		}
+		ret = append(ret, version)
+	}
+
+	ret.Sort()
+	return ret, nil, nil
+}
+
+// PackageMeta retrieves metadata for the requested provider package
+// from the object's underlying HTTP mirror service.
+func (s *HTTPMirrorSource) PackageMeta(ctx context.Context, provider addrs.Provider, version Version, target Platform) (PackageMeta, error) {
+	log.Printf("[DEBUG] Finding package URL for %s v%s on %s via network mirror %s", provider.String(), version.String(), target.String(), s.baseURL.String())
+
+	endpointPath := path.Join(
+		provider.Hostname.String(),
+		provider.Namespace,
+		provider.Type,
+		version.String()+".json",
+	)
+
+	statusCode, body, finalURL, err := s.get(ctx, endpointPath)
+	defer func() {
+		if body != nil {
+			body.Close()
+		}
+	}()
+	if err != nil {
+		return PackageMeta{}, s.errQueryFailed(provider, err)
+	}
+
+	switch statusCode {
+	case http.StatusOK:
+		// Great!
+	case http.StatusNotFound:
+		// A 404 Not Found for a version we previously saw in index.json is
+		// a protocol error, so we'll report this as "query failed.
+		return PackageMeta{}, s.errQueryFailed(provider, fmt.Errorf("provider mirror does not have archive index for previously-reported %s version %s", provider, version))
+	case http.StatusUnauthorized, http.StatusForbidden:
+		return PackageMeta{}, s.errUnauthorized(finalURL)
+	default:
+		return PackageMeta{}, s.errQueryFailed(provider, fmt.Errorf("server returned unsuccessful status %d", statusCode))
+	}
+
+	// If we got here then the response had status OK and so our body
+	// will be non-nil and should contain some JSON for us to parse.
+	type ResponseArchiveMeta struct {
+		RelativeURL string `json:"url"`
+		Hashes      []string
+	}
+	type ResponseBody struct {
+		Archives map[string]*ResponseArchiveMeta `json:"archives"`
+	}
+	var bodyContent ResponseBody
+
+	dec := json.NewDecoder(body)
+	if err := dec.Decode(&bodyContent); err != nil {
+		return PackageMeta{}, s.errQueryFailed(provider, fmt.Errorf("invalid response content from mirror server: %s", err))
+	}
+
+	archiveMeta, ok := bodyContent.Archives[target.String()]
+	if !ok {
+		return PackageMeta{}, ErrPlatformNotSupported{
+			Provider:  provider,
+			Version:   version,
+			Platform:  target,
+			MirrorURL: s.baseURL,
+		}
+	}
+
+	relURL, err := url.Parse(archiveMeta.RelativeURL)
+	if err != nil {
+		return PackageMeta{}, s.errQueryFailed(
+			provider,
+			fmt.Errorf("provider mirror returned invalid URL %q: %s", archiveMeta.RelativeURL, err),
+		)
+	}
+	absURL := finalURL.ResolveReference(relURL)
+
+	ret := PackageMeta{
+		Provider:       provider,
+		Version:        version,
+		TargetPlatform: target,
+
+		Location: PackageHTTPURL(absURL.String()),
+		Filename: path.Base(absURL.Path),
+	}
+	// A network mirror might not provide any hashes at all, in which case
+	// the package has no source-defined authentication whatsoever.
+	if len(archiveMeta.Hashes) > 0 {
+		hashes := make([]Hash, 0, len(archiveMeta.Hashes))
+		for _, hashStr := range archiveMeta.Hashes {
+			hash, err := ParseHash(hashStr)
+			if err != nil {
+				return PackageMeta{}, s.errQueryFailed(
+					provider,
+					fmt.Errorf("provider mirror returned invalid provider hash %q: %s", hashStr, err),
+				)
+			}
+			hashes = append(hashes, hash)
+		}
+		ret.Authentication = NewPackageHashAuthentication(target, hashes)
+	}
+
+	return ret, nil
+}
+
+// ForDisplay returns a string description of the source for user-facing output.
+func (s *HTTPMirrorSource) ForDisplay(provider addrs.Provider) string {
+	return "provider mirror at " + s.baseURL.String()
+}
+
+// mirrorHost extracts the hostname portion of the configured base URL and
+// returns it as a svchost.Hostname, normalized in the usual ways.
+//
+// If the returned error is non-nil then the given hostname doesn't comply
+// with the IETF RFC 5891 section 5.3 and 5.4 validation rules, and thus cannot
+// be interpreted as a valid Terraform service host. The IDNA validation errors
+// are unfortunately usually not very user-friendly, but they are also
+// relatively rare because the IDNA normalization rules are quite tolerant.
+func (s *HTTPMirrorSource) mirrorHost() (svchost.Hostname, error) {
+	return svchostFromURL(s.baseURL)
+}
+
+// mirrorHostCredentials returns the HostCredentials, if any, for the hostname
+// included in the mirror base URL.
+//
+// It might return an error if the mirror base URL is invalid, or if the
+// credentials lookup itself fails.
+func (s *HTTPMirrorSource) mirrorHostCredentials() (svcauth.HostCredentials, error) {
+	hostname, err := s.mirrorHost()
+	if err != nil {
+		return nil, fmt.Errorf("invalid provider mirror base URL %s: %s", s.baseURL.String(), err)
+	}
+
+	if s.creds == nil {
+		// No host-specific credentials, then.
+		return nil, nil
+	}
+
+	return s.creds.ForHost(hostname)
+}
+
+// get is the shared functionality for querying a JSON index from a mirror.
+//
+// It only handles the raw HTTP request. The "body" return value is the
+// reader from the response if and only if the response status code is 200 OK
+// and the Content-Type is application/json. In all other cases it's nil.
+// If body is non-nil then the caller must close it after reading it.
+//
+// If the "finalURL" return value is not empty then it's the URL that actually
+// produced the returned response, possibly after following some redirects.
+func (s *HTTPMirrorSource) get(ctx context.Context, relativePath string) (statusCode int, body io.ReadCloser, finalURL *url.URL, error error) {
+	endpointPath, err := url.Parse(relativePath)
+	if err != nil {
+		// Should never happen because the caller should validate all of the
+		// components it's including in the path.
+		return 0, nil, nil, err
+	}
+	endpointURL := s.baseURL.ResolveReference(endpointPath)
+
+	req, err := retryablehttp.NewRequest("GET", endpointURL.String(), nil)
+	if err != nil {
+		return 0, nil, endpointURL, err
+	}
+	req = req.WithContext(ctx)
+	req.Request.Header.Set(terraformVersionHeader, version.String())
+	creds, err := s.mirrorHostCredentials()
+	if err != nil {
+		return 0, nil, endpointURL, fmt.Errorf("failed to determine request credentials: %s", err)
+	}
+	if creds != nil {
+		// Note that if the initial requests gets redirected elsewhere
+		// then the credentials will still be included in the new request,
+		// even if they are on a different hostname. This is intentional
+		// and consistent with how we handle credentials for other
+		// Terraform-native services, because the user model is to configure
+		// credentials for the "friendly hostname" they configured, not for
+		// whatever hostname ends up ultimately serving the request as an
+		// implementation detail.
+		creds.PrepareRequest(req.Request)
+	}
+
+	resp, err := s.httpClient.Do(req)
+	if err != nil {
+		return 0, nil, endpointURL, err
+	}
+	defer func() {
+		// If we're not returning the body then we'll close it
+		// before we return.
+		if body == nil {
+			resp.Body.Close()
+		}
+	}()
+	// After this point, our final URL return value should always be the
+	// one from resp.Request, because that takes into account any redirects
+	// we followed along the way.
+	finalURL = resp.Request.URL
+
+	if resp.StatusCode == http.StatusOK {
+		// If and only if we get an OK response, we'll check that the response
+		// type is JSON and return the body reader.
+		ct := resp.Header.Get("Content-Type")
+		mt, params, err := mime.ParseMediaType(ct)
+		if err != nil {
+			return 0, nil, finalURL, fmt.Errorf("response has invalid Content-Type: %s", err)
+		}
+		if mt != "application/json" {
+			return 0, nil, finalURL, fmt.Errorf("response has invalid Content-Type: must be application/json")
+		}
+		for name := range params {
+			// The application/json content-type has no defined parameters,
+			// but some servers are configured to include a redundant "charset"
+			// parameter anyway, presumably out of a sense of completeness.
+			// We'll ignore them but warn that we're ignoring them in case the
+			// subsequent parsing fails due to the server trying to use an
+			// unsupported character encoding. (RFC 7159 defines its own
+			// JSON-specific character encoding rules.)
+			log.Printf("[WARN] Network mirror returned %q as part of its JSON content type, which is not defined. Ignoring.", name)
+		}
+		body = resp.Body
+	}
+
+	return resp.StatusCode, body, finalURL, nil
+}
+
+func (s *HTTPMirrorSource) errQueryFailed(provider addrs.Provider, err error) error {
+	if err == context.Canceled {
+		// This one has a special error type so that callers can
+		// handle it in a different way.
+		return ErrRequestCanceled{}
+	}
+	return ErrQueryFailed{
+		Provider:  provider,
+		Wrapped:   err,
+		MirrorURL: s.baseURL,
+	}
+}
+
+func (s *HTTPMirrorSource) errUnauthorized(finalURL *url.URL) error {
+	hostname, err := svchostFromURL(finalURL)
+	if err != nil {
+		// Again, weird but we'll tolerate it.
+		return fmt.Errorf("invalid credentials for %s", finalURL)
+	}
+
+	return ErrUnauthorized{
+		Hostname: hostname,
+
+		// We can't easily tell from here whether we had credentials or
+		// not, so for now we'll just assume we did because "host rejected
+		// the given credentials" is, hopefully, still understandable in
+		// the event that there were none. (If this ends up being confusing
+		// in practice then we'll need to do some refactoring of how
+		// we handle credentials in this source.)
+		HaveCredentials: true,
+	}
+}
+
+func svchostFromURL(u *url.URL) (svchost.Hostname, error) {
+	raw := u.Host
+
+	// When "friendly hostnames" appear in Terraform-specific identifiers we
+	// typically constrain their syntax more strictly than the
+	// Internationalized Domain Name specifications call for, such as
+	// forbidding direct use of punycode, but in this case we're just
+	// working with a standard http: or https: URL and so we'll first use the
+	// IDNA "lookup" rules directly, with no additional notational constraints,
+	// to effectively normalize away the differences that would normally
+	// produce an error.
+	var portPortion string
+	if colonPos := strings.Index(raw, ":"); colonPos != -1 {
+		raw, portPortion = raw[:colonPos], raw[colonPos:]
+	}
+	// HTTPMirrorSource requires all URLs to be https URLs, because running
+	// a network mirror over HTTP would potentially transmit any configured
+	// credentials in cleartext. Therefore we don't need to do any special
+	// handling of default ports here, because svchost.Hostname already
+	// considers the absense of a port to represent the standard HTTPS port
+	// 443, and will normalize away an explicit specification of port 443
+	// in svchost.ForComparison below.
+
+	normalized, err := idna.Display.ToUnicode(raw)
+	if err != nil {
+		return svchost.Hostname(""), err
+	}
+
+	// If ToUnicode succeeded above then "normalized" is now a hostname in the
+	// normalized IDNA form, with any direct punycode already interpreted and
+	// the case folding and other normalization rules applied. It should
+	// therefore now be accepted by svchost.ForComparison with no additional
+	// errors, but the port portion can still potentially be invalid.
+	return svchost.ForComparison(normalized + portPortion)
+}
diff --git a/v1.5.7/internal/getproviders/http_mirror_source_test.go b/v1.5.7/internal/getproviders/http_mirror_source_test.go
new file mode 100644
index 0000000..3679579
--- /dev/null
+++ b/v1.5.7/internal/getproviders/http_mirror_source_test.go
@@ -0,0 +1,327 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	svchost "github.com/hashicorp/terraform-svchost"
+	svcauth "github.com/hashicorp/terraform-svchost/auth"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestHTTPMirrorSource(t *testing.T) {
+	// For mirrors we require a HTTPS server, so we'll use httptest to create
+	// one. However, that means we need to instantiate the source in an unusual
+	// way to force it to use the test client that is configured to trust the
+	// test server.
+	httpServer := httptest.NewTLSServer(http.HandlerFunc(testHTTPMirrorSourceHandler))
+	defer httpServer.Close()
+	httpClient := httpServer.Client()
+	baseURL, err := url.Parse(httpServer.URL)
+	if err != nil {
+		t.Fatalf("httptest.NewTLSServer returned a server with an invalid URL")
+	}
+	creds := svcauth.StaticCredentialsSource(map[svchost.Hostname]map[string]interface{}{
+		svchost.Hostname(baseURL.Host): {
+			"token": "placeholder-token",
+		},
+	})
+	source := newHTTPMirrorSourceWithHTTPClient(baseURL, creds, httpClient)
+
+	existingProvider := addrs.MustParseProviderSourceString("terraform.io/test/exists")
+	missingProvider := addrs.MustParseProviderSourceString("terraform.io/test/missing")
+	failingProvider := addrs.MustParseProviderSourceString("terraform.io/test/fails")
+	redirectingProvider := addrs.MustParseProviderSourceString("terraform.io/test/redirects")
+	redirectLoopProvider := addrs.MustParseProviderSourceString("terraform.io/test/redirect-loop")
+	tosPlatform := Platform{OS: "tos", Arch: "m68k"}
+
+	t.Run("AvailableVersions for provider that exists", func(t *testing.T) {
+		got, _, err := source.AvailableVersions(context.Background(), existingProvider)
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		want := VersionList{
+			MustParseVersion("1.0.0"),
+			MustParseVersion("1.0.1"),
+			MustParseVersion("1.0.2-beta.1"),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("AvailableVersions for provider that doesn't exist", func(t *testing.T) {
+		_, _, err := source.AvailableVersions(context.Background(), missingProvider)
+		switch err := err.(type) {
+		case ErrProviderNotFound:
+			if got, want := err.Provider, missingProvider; got != want {
+				t.Errorf("wrong provider in error\ngot:  %s\nwant: %s", got, want)
+			}
+		default:
+			t.Fatalf("wrong error type %T; want ErrProviderNotFound", err)
+		}
+	})
+	t.Run("AvailableVersions without required credentials", func(t *testing.T) {
+		unauthSource := newHTTPMirrorSourceWithHTTPClient(baseURL, nil, httpClient)
+		_, _, err := unauthSource.AvailableVersions(context.Background(), existingProvider)
+		switch err := err.(type) {
+		case ErrUnauthorized:
+			if got, want := string(err.Hostname), baseURL.Host; got != want {
+				t.Errorf("wrong hostname in error\ngot:  %s\nwant: %s", got, want)
+			}
+		default:
+			t.Fatalf("wrong error type %T; want ErrUnauthorized", err)
+		}
+	})
+	t.Run("AvailableVersions when the response is a server error", func(t *testing.T) {
+		_, _, err := source.AvailableVersions(context.Background(), failingProvider)
+		switch err := err.(type) {
+		case ErrQueryFailed:
+			if got, want := err.Provider, failingProvider; got != want {
+				t.Errorf("wrong provider in error\ngot:  %s\nwant: %s", got, want)
+			}
+			if err.MirrorURL != source.baseURL {
+				t.Errorf("error does not refer to the mirror URL")
+			}
+		default:
+			t.Fatalf("wrong error type %T; want ErrQueryFailed", err)
+		}
+	})
+	t.Run("AvailableVersions for provider that redirects", func(t *testing.T) {
+		got, _, err := source.AvailableVersions(context.Background(), redirectingProvider)
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		want := VersionList{
+			MustParseVersion("1.0.0"),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("AvailableVersions for provider that redirects too much", func(t *testing.T) {
+		_, _, err := source.AvailableVersions(context.Background(), redirectLoopProvider)
+		if err == nil {
+			t.Fatalf("succeeded; expected error")
+		}
+	})
+	t.Run("PackageMeta for a version that exists and has a hash", func(t *testing.T) {
+		version := MustParseVersion("1.0.0")
+		got, err := source.PackageMeta(context.Background(), existingProvider, version, tosPlatform)
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+
+		want := PackageMeta{
+			Provider:       existingProvider,
+			Version:        version,
+			TargetPlatform: tosPlatform,
+			Filename:       "terraform-provider-test_v1.0.0_tos_m68k.zip",
+			Location:       PackageHTTPURL(httpServer.URL + "/terraform.io/test/exists/terraform-provider-test_v1.0.0_tos_m68k.zip"),
+			Authentication: packageHashAuthentication{
+				RequiredHashes: []Hash{"h1:placeholder-hash"},
+				AllHashes:      []Hash{"h1:placeholder-hash", "h0:unacceptable-hash"},
+				Platform:       Platform{"tos", "m68k"},
+			},
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+
+		gotHashes := got.AcceptableHashes()
+		wantHashes := []Hash{"h1:placeholder-hash", "h0:unacceptable-hash"}
+		if diff := cmp.Diff(wantHashes, gotHashes); diff != "" {
+			t.Errorf("wrong acceptable hashes\n%s", diff)
+		}
+	})
+	t.Run("PackageMeta for a version that exists and has no hash", func(t *testing.T) {
+		version := MustParseVersion("1.0.1")
+		got, err := source.PackageMeta(context.Background(), existingProvider, version, tosPlatform)
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+
+		want := PackageMeta{
+			Provider:       existingProvider,
+			Version:        version,
+			TargetPlatform: tosPlatform,
+			Filename:       "terraform-provider-test_v1.0.1_tos_m68k.zip",
+			Location:       PackageHTTPURL(httpServer.URL + "/terraform.io/test/exists/terraform-provider-test_v1.0.1_tos_m68k.zip"),
+			Authentication: nil,
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("PackageMeta for a version that exists but has no archives", func(t *testing.T) {
+		version := MustParseVersion("1.0.2-beta.1")
+		_, err := source.PackageMeta(context.Background(), existingProvider, version, tosPlatform)
+		switch err := err.(type) {
+		case ErrPlatformNotSupported:
+			if got, want := err.Provider, existingProvider; got != want {
+				t.Errorf("wrong provider in error\ngot:  %s\nwant: %s", got, want)
+			}
+			if got, want := err.Platform, tosPlatform; got != want {
+				t.Errorf("wrong platform in error\ngot:  %s\nwant: %s", got, want)
+			}
+			if err.MirrorURL != source.baseURL {
+				t.Errorf("error does not contain the mirror URL")
+			}
+		default:
+			t.Fatalf("wrong error type %T; want ErrPlatformNotSupported", err)
+		}
+	})
+	t.Run("PackageMeta with redirect to a version that exists", func(t *testing.T) {
+		version := MustParseVersion("1.0.0")
+		got, err := source.PackageMeta(context.Background(), redirectingProvider, version, tosPlatform)
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+
+		want := PackageMeta{
+			Provider:       redirectingProvider,
+			Version:        version,
+			TargetPlatform: tosPlatform,
+			Filename:       "terraform-provider-test.zip",
+
+			// NOTE: The final URL is interpreted relative to the redirect
+			// target, not relative to what we originally requested.
+			Location: PackageHTTPURL(httpServer.URL + "/redirect-target/terraform-provider-test.zip"),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("PackageMeta when the response is a server error", func(t *testing.T) {
+		version := MustParseVersion("1.0.0")
+		_, err := source.PackageMeta(context.Background(), failingProvider, version, tosPlatform)
+		switch err := err.(type) {
+		case ErrQueryFailed:
+			if got, want := err.Provider, failingProvider; got != want {
+				t.Errorf("wrong provider in error\ngot:  %s\nwant: %s", got, want)
+			}
+			if err.MirrorURL != source.baseURL {
+				t.Errorf("error does not contain the mirror URL")
+			}
+		default:
+			t.Fatalf("wrong error type %T; want ErrQueryFailed", err)
+		}
+	})
+}
+
+func testHTTPMirrorSourceHandler(resp http.ResponseWriter, req *http.Request) {
+	if auth := req.Header.Get("authorization"); auth != "Bearer placeholder-token" {
+		resp.WriteHeader(401)
+		fmt.Fprintln(resp, "incorrect auth token")
+	}
+
+	switch req.URL.Path {
+	case "/terraform.io/test/exists/index.json":
+		resp.Header().Add("Content-Type", "application/json; ignored=yes")
+		resp.WriteHeader(200)
+		fmt.Fprint(resp, `
+			{
+				"versions": {
+					"1.0.0": {},
+					"1.0.1": {},
+					"1.0.2-beta.1": {}
+				}
+			}
+		`)
+
+	case "/terraform.io/test/fails/index.json", "/terraform.io/test/fails/1.0.0.json":
+		resp.WriteHeader(500)
+		fmt.Fprint(resp, "server error")
+
+	case "/terraform.io/test/exists/1.0.0.json":
+		resp.Header().Add("Content-Type", "application/json; ignored=yes")
+		resp.WriteHeader(200)
+		fmt.Fprint(resp, `
+			{
+				"archives": {
+					"tos_m68k": {
+						"url": "terraform-provider-test_v1.0.0_tos_m68k.zip",
+						"hashes": [
+							"h1:placeholder-hash",
+							"h0:unacceptable-hash"
+						]
+					}
+				}
+			}
+		`)
+
+	case "/terraform.io/test/exists/1.0.1.json":
+		resp.Header().Add("Content-Type", "application/json; ignored=yes")
+		resp.WriteHeader(200)
+		fmt.Fprint(resp, `
+			{
+				"archives": {
+					"tos_m68k": {
+						"url": "terraform-provider-test_v1.0.1_tos_m68k.zip"
+					}
+				}
+			}
+		`)
+
+	case "/terraform.io/test/exists/1.0.2-beta.1.json":
+		resp.Header().Add("Content-Type", "application/json; ignored=yes")
+		resp.WriteHeader(200)
+		fmt.Fprint(resp, `
+			{
+				"archives": {}
+			}
+		`)
+
+	case "/terraform.io/test/redirects/index.json":
+		resp.Header().Add("location", "/redirect-target/index.json")
+		resp.WriteHeader(301)
+		fmt.Fprint(resp, "redirect")
+
+	case "/redirect-target/index.json":
+		resp.Header().Add("Content-Type", "application/json")
+		resp.WriteHeader(200)
+		fmt.Fprint(resp, `
+			{
+				"versions": {
+					"1.0.0": {}
+				}
+			}
+		`)
+
+	case "/terraform.io/test/redirects/1.0.0.json":
+		resp.Header().Add("location", "/redirect-target/1.0.0.json")
+		resp.WriteHeader(301)
+		fmt.Fprint(resp, "redirect")
+
+	case "/redirect-target/1.0.0.json":
+		resp.Header().Add("Content-Type", "application/json")
+		resp.WriteHeader(200)
+		fmt.Fprint(resp, `
+			{
+				"archives": {
+					"tos_m68k": {
+						"url": "terraform-provider-test.zip"
+					}
+				}
+			}
+		`)
+
+	case "/terraform.io/test/redirect-loop/index.json":
+		// This is intentionally redirecting to itself, to create a loop.
+		resp.Header().Add("location", req.URL.Path)
+		resp.WriteHeader(301)
+		fmt.Fprint(resp, "redirect loop")
+
+	default:
+		resp.WriteHeader(404)
+		fmt.Fprintln(resp, "not found")
+	}
+}
diff --git a/v1.5.7/internal/getproviders/memoize_source.go b/v1.5.7/internal/getproviders/memoize_source.go
new file mode 100644
index 0000000..4ae8add
--- /dev/null
+++ b/v1.5.7/internal/getproviders/memoize_source.go
@@ -0,0 +1,106 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// MemoizeSource is a Source that wraps another Source and remembers its
+// results so that they can be returned more quickly on future calls to the
+// same object.
+//
+// Each MemoizeSource maintains a cache of response it has seen as part of its
+// body. All responses are retained for the remaining lifetime of the object.
+// Errors from the underlying source are also cached, and so subsequent calls
+// with the same arguments will always produce the same errors.
+//
+// A MemoizeSource can be called concurrently, with incoming requests processed
+// sequentially.
+type MemoizeSource struct {
+	underlying        Source
+	availableVersions map[addrs.Provider]memoizeAvailableVersionsRet
+	packageMetas      map[memoizePackageMetaCall]memoizePackageMetaRet
+	mu                sync.Mutex
+}
+
+type memoizeAvailableVersionsRet struct {
+	VersionList VersionList
+	Warnings    Warnings
+	Err         error
+}
+
+type memoizePackageMetaCall struct {
+	Provider addrs.Provider
+	Version  Version
+	Target   Platform
+}
+
+type memoizePackageMetaRet struct {
+	PackageMeta PackageMeta
+	Err         error
+}
+
+var _ Source = (*MemoizeSource)(nil)
+
+// NewMemoizeSource constructs and returns a new MemoizeSource that wraps
+// the given underlying source and memoizes its results.
+func NewMemoizeSource(underlying Source) *MemoizeSource {
+	return &MemoizeSource{
+		underlying:        underlying,
+		availableVersions: make(map[addrs.Provider]memoizeAvailableVersionsRet),
+		packageMetas:      make(map[memoizePackageMetaCall]memoizePackageMetaRet),
+	}
+}
+
+// AvailableVersions requests the available versions from the underlying source
+// and caches them before returning them, or on subsequent calls returns the
+// result directly from the cache.
+func (s *MemoizeSource) AvailableVersions(ctx context.Context, provider addrs.Provider) (VersionList, Warnings, error) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	if existing, exists := s.availableVersions[provider]; exists {
+		return existing.VersionList, nil, existing.Err
+	}
+
+	ret, warnings, err := s.underlying.AvailableVersions(ctx, provider)
+	s.availableVersions[provider] = memoizeAvailableVersionsRet{
+		VersionList: ret,
+		Err:         err,
+		Warnings:    warnings,
+	}
+	return ret, warnings, err
+}
+
+// PackageMeta requests package metadata from the underlying source and caches
+// the result before returning it, or on subsequent calls returns the result
+// directly from the cache.
+func (s *MemoizeSource) PackageMeta(ctx context.Context, provider addrs.Provider, version Version, target Platform) (PackageMeta, error) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	key := memoizePackageMetaCall{
+		Provider: provider,
+		Version:  version,
+		Target:   target,
+	}
+	if existing, exists := s.packageMetas[key]; exists {
+		return existing.PackageMeta, existing.Err
+	}
+
+	ret, err := s.underlying.PackageMeta(ctx, provider, version, target)
+	s.packageMetas[key] = memoizePackageMetaRet{
+		PackageMeta: ret,
+		Err:         err,
+	}
+	return ret, err
+}
+
+func (s *MemoizeSource) ForDisplay(provider addrs.Provider) string {
+	return s.underlying.ForDisplay(provider)
+}
diff --git a/v1.5.7/internal/getproviders/memoize_source_test.go b/v1.5.7/internal/getproviders/memoize_source_test.go
new file mode 100644
index 0000000..f58d039
--- /dev/null
+++ b/v1.5.7/internal/getproviders/memoize_source_test.go
@@ -0,0 +1,190 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestMemoizeSource(t *testing.T) {
+	provider := addrs.NewDefaultProvider("foo")
+	version := MustParseVersion("1.0.0")
+	protocols := VersionList{MustParseVersion("5.0")}
+	platform := Platform{OS: "gameboy", Arch: "lr35902"}
+	meta := FakePackageMeta(provider, version, protocols, platform)
+	nonexistProvider := addrs.NewDefaultProvider("nonexist")
+	nonexistPlatform := Platform{OS: "gamegear", Arch: "z80"}
+
+	t.Run("AvailableVersions for existing provider", func(t *testing.T) {
+		mock := NewMockSource([]PackageMeta{meta}, nil)
+		source := NewMemoizeSource(mock)
+
+		got, _, err := source.AvailableVersions(context.Background(), provider)
+		want := VersionList{version}
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Fatalf("wrong result from first call to AvailableVersions\n%s", diff)
+		}
+
+		got, _, err = source.AvailableVersions(context.Background(), provider)
+		want = VersionList{version}
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Fatalf("wrong result from second call to AvailableVersions\n%s", diff)
+		}
+
+		_, _, err = source.AvailableVersions(context.Background(), nonexistProvider)
+		if want, ok := err.(ErrRegistryProviderNotKnown); !ok {
+			t.Fatalf("wrong error type from nonexist call:\ngot:  %T\nwant: %T", err, want)
+		}
+
+		got, _, err = source.AvailableVersions(context.Background(), provider)
+		want = VersionList{version}
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Fatalf("wrong result from third call to AvailableVersions\n%s", diff)
+		}
+
+		gotLog := mock.CallLog()
+		wantLog := [][]interface{}{
+			// Only one call for the main provider, because the others were returned from the cache.
+			{"AvailableVersions", provider},
+
+			// The call for nonexist also shows through, because it didn't match the cache.
+			{"AvailableVersions", nonexistProvider},
+		}
+		if diff := cmp.Diff(wantLog, gotLog); diff != "" {
+			t.Fatalf("unexpected call log\n%s", diff)
+		}
+	})
+	t.Run("AvailableVersions with warnings", func(t *testing.T) {
+		warnProvider := addrs.NewDefaultProvider("warning")
+		meta := FakePackageMeta(warnProvider, version, protocols, platform)
+		mock := NewMockSource([]PackageMeta{meta}, map[addrs.Provider]Warnings{warnProvider: {"WARNING!"}})
+		source := NewMemoizeSource(mock)
+
+		got, warns, err := source.AvailableVersions(context.Background(), warnProvider)
+		want := VersionList{version}
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Fatalf("wrong result from first call to AvailableVersions\n%s", diff)
+		}
+		if len(warns) != 1 {
+			t.Fatalf("wrong number of warnings. Got %d, expected 1", len(warns))
+		}
+		if warns[0] != "WARNING!" {
+			t.Fatalf("wrong result! Got %s, expected \"WARNING!\"", warns[0])
+		}
+
+	})
+	t.Run("PackageMeta for existing provider", func(t *testing.T) {
+		mock := NewMockSource([]PackageMeta{meta}, nil)
+		source := NewMemoizeSource(mock)
+
+		got, err := source.PackageMeta(context.Background(), provider, version, platform)
+		want := meta
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Fatalf("wrong result from first call to PackageMeta\n%s", diff)
+		}
+
+		got, err = source.PackageMeta(context.Background(), provider, version, platform)
+		want = meta
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Fatalf("wrong result from second call to PackageMeta\n%s", diff)
+		}
+
+		_, err = source.PackageMeta(context.Background(), nonexistProvider, version, platform)
+		if want, ok := err.(ErrPlatformNotSupported); !ok {
+			t.Fatalf("wrong error type from nonexist provider call:\ngot:  %T\nwant: %T", err, want)
+		}
+		_, err = source.PackageMeta(context.Background(), provider, version, nonexistPlatform)
+		if want, ok := err.(ErrPlatformNotSupported); !ok {
+			t.Fatalf("wrong error type from nonexist platform call:\ngot:  %T\nwant: %T", err, want)
+		}
+
+		got, err = source.PackageMeta(context.Background(), provider, version, platform)
+		want = meta
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Fatalf("wrong result from third call to PackageMeta\n%s", diff)
+		}
+
+		gotLog := mock.CallLog()
+		wantLog := [][]interface{}{
+			// Only one call for the main provider, because the others were returned from the cache.
+			{"PackageMeta", provider, version, platform},
+
+			// The other calls for non-exist things also show through, because they missed the cache.
+			{"PackageMeta", nonexistProvider, version, platform},
+			{"PackageMeta", provider, version, nonexistPlatform},
+		}
+		if diff := cmp.Diff(wantLog, gotLog); diff != "" {
+			t.Fatalf("unexpected call log\n%s", diff)
+		}
+	})
+	t.Run("AvailableVersions for non-existing provider", func(t *testing.T) {
+		mock := NewMockSource([]PackageMeta{meta}, nil)
+		source := NewMemoizeSource(mock)
+
+		_, _, err := source.AvailableVersions(context.Background(), nonexistProvider)
+		if want, ok := err.(ErrRegistryProviderNotKnown); !ok {
+			t.Fatalf("wrong error type from first call:\ngot:  %T\nwant: %T", err, want)
+		}
+		_, _, err = source.AvailableVersions(context.Background(), nonexistProvider)
+		if want, ok := err.(ErrRegistryProviderNotKnown); !ok {
+			t.Fatalf("wrong error type from second call:\ngot:  %T\nwant: %T", err, want)
+		}
+
+		gotLog := mock.CallLog()
+		wantLog := [][]interface{}{
+			// Only one call, because the other was returned from the cache.
+			{"AvailableVersions", nonexistProvider},
+		}
+		if diff := cmp.Diff(wantLog, gotLog); diff != "" {
+			t.Fatalf("unexpected call log\n%s", diff)
+		}
+	})
+	t.Run("PackageMeta for non-existing provider", func(t *testing.T) {
+		mock := NewMockSource([]PackageMeta{meta}, nil)
+		source := NewMemoizeSource(mock)
+
+		_, err := source.PackageMeta(context.Background(), nonexistProvider, version, platform)
+		if want, ok := err.(ErrPlatformNotSupported); !ok {
+			t.Fatalf("wrong error type from first call:\ngot:  %T\nwant: %T", err, want)
+		}
+		_, err = source.PackageMeta(context.Background(), nonexistProvider, version, platform)
+		if want, ok := err.(ErrPlatformNotSupported); !ok {
+			t.Fatalf("wrong error type from second call:\ngot:  %T\nwant: %T", err, want)
+		}
+
+		gotLog := mock.CallLog()
+		wantLog := [][]interface{}{
+			// Only one call, because the other was returned from the cache.
+			{"PackageMeta", nonexistProvider, version, platform},
+		}
+		if diff := cmp.Diff(wantLog, gotLog); diff != "" {
+			t.Fatalf("unexpected call log\n%s", diff)
+		}
+	})
+}
diff --git a/v1.5.7/internal/getproviders/mock_source.go b/v1.5.7/internal/getproviders/mock_source.go
new file mode 100644
index 0000000..930cbe3
--- /dev/null
+++ b/v1.5.7/internal/getproviders/mock_source.go
@@ -0,0 +1,217 @@
+package getproviders
+
+import (
+	"archive/zip"
+	"context"
+	"crypto/sha256"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// MockSource is an in-memory-only, statically-configured source intended for
+// use only in unit tests of other subsystems that consume provider sources.
+//
+// The MockSource also tracks calls to it in case a calling test wishes to
+// assert that particular calls were made.
+//
+// This should not be used outside of unit test code.
+type MockSource struct {
+	packages []PackageMeta
+	warnings map[addrs.Provider]Warnings
+	calls    [][]interface{}
+}
+
+var _ Source = (*MockSource)(nil)
+
+// NewMockSource creates and returns a MockSource with the given packages.
+//
+// The given packages don't necessarily need to refer to objects that actually
+// exist on disk or over the network, unless the calling test is planning to
+// use (directly or indirectly) the results for further provider installation
+// actions.
+func NewMockSource(packages []PackageMeta, warns map[addrs.Provider]Warnings) *MockSource {
+	return &MockSource{
+		packages: packages,
+		warnings: warns,
+	}
+}
+
+// AvailableVersions returns all of the versions of the given provider that
+// are available in the fixed set of packages that were passed to
+// NewMockSource when creating the receiving source.
+func (s *MockSource) AvailableVersions(ctx context.Context, provider addrs.Provider) (VersionList, Warnings, error) {
+	s.calls = append(s.calls, []interface{}{"AvailableVersions", provider})
+	var ret VersionList
+	for _, pkg := range s.packages {
+		if pkg.Provider == provider {
+			ret = append(ret, pkg.Version)
+		}
+	}
+	var warns []string
+	if s.warnings != nil {
+		if warnings, ok := s.warnings[provider]; ok {
+			warns = warnings
+		}
+	}
+	if len(ret) == 0 {
+		// In this case, we'll behave like a registry that doesn't know about
+		// this provider at all, rather than just returning an empty result.
+		return nil, warns, ErrRegistryProviderNotKnown{provider}
+	}
+	ret.Sort()
+	return ret, warns, nil
+}
+
+// PackageMeta returns the first package from the list given to NewMockSource
+// when creating the receiver that has the given provider, version, and
+// target platform.
+//
+// If none of the packages match, it returns ErrPlatformNotSupported to
+// simulate the situation where a provider release isn't available for a
+// particular platform.
+//
+// Note that if the list of packages passed to NewMockSource contains more
+// than one with the same provider, version, and target this function will
+// always return the first one in the list, which may not match the behavior
+// of other sources in an equivalent situation because it's a degenerate case
+// with undefined results.
+func (s *MockSource) PackageMeta(ctx context.Context, provider addrs.Provider, version Version, target Platform) (PackageMeta, error) {
+	s.calls = append(s.calls, []interface{}{"PackageMeta", provider, version, target})
+
+	for _, pkg := range s.packages {
+		if pkg.Provider != provider {
+			continue
+		}
+		if pkg.Version != version {
+			// (We're using strict equality rather than precedence here,
+			// because this is an exact version specification. The caller
+			// should consider precedence when selecting a version in the
+			// AvailableVersions response, and pass the exact selected
+			// version here.)
+			continue
+		}
+		if pkg.TargetPlatform != target {
+			continue
+		}
+		return pkg, nil
+	}
+
+	// If we fall out here then nothing matched at all, so we'll treat that
+	// as "platform not supported" for consistency with RegistrySource.
+	return PackageMeta{}, ErrPlatformNotSupported{
+		Provider: provider,
+		Version:  version,
+		Platform: target,
+	}
+}
+
+// CallLog returns a list of calls to other methods of the receiever that have
+// been called since it was created, in case a calling test wishes to verify
+// a particular sequence of operations.
+//
+// The result is a slice of slices where the first element of each inner slice
+// is the name of the method that was called, and then any subsequent elements
+// are positional arguments passed to that method.
+//
+// Callers are forbidden from modifying any objects accessible via the returned
+// value.
+func (s *MockSource) CallLog() [][]interface{} {
+	return s.calls
+}
+
+// FakePackageMeta constructs and returns a PackageMeta that carries the given
+// metadata but has fake location information that is likely to fail if
+// attempting to install from it.
+func FakePackageMeta(provider addrs.Provider, version Version, protocols VersionList, target Platform) PackageMeta {
+	return PackageMeta{
+		Provider:         provider,
+		Version:          version,
+		ProtocolVersions: protocols,
+		TargetPlatform:   target,
+
+		// Some fake but somewhat-realistic-looking other metadata. This
+		// points nowhere, so will fail if attempting to actually use it.
+		Filename: fmt.Sprintf("terraform-provider-%s_%s_%s.zip", provider.Type, version.String(), target.String()),
+		Location: PackageHTTPURL(fmt.Sprintf("https://fake.invalid/terraform-provider-%s_%s.zip", provider.Type, version.String())),
+	}
+}
+
+// FakeInstallablePackageMeta constructs and returns a PackageMeta that points
+// to a temporary archive file that could actually be installed in principle.
+//
+// Installing it will not produce a working provider though: just a fake file
+// posing as an executable. The filename for the executable defaults to the
+// standard terraform-provider-NAME_X.Y.Z format, but can be overridden with
+// the execFilename argument.
+//
+// It's the caller's responsibility to call the close callback returned
+// alongside the result in order to clean up the temporary file. The caller
+// should call the callback even if this function returns an error, because
+// some error conditions leave a partially-created file on disk.
+func FakeInstallablePackageMeta(provider addrs.Provider, version Version, protocols VersionList, target Platform, execFilename string) (PackageMeta, func(), error) {
+	f, err := ioutil.TempFile("", "terraform-getproviders-fake-package-")
+	if err != nil {
+		return PackageMeta{}, func() {}, err
+	}
+
+	// After this point, all of our return paths should include this as the
+	// close callback.
+	close := func() {
+		f.Close()
+		os.Remove(f.Name())
+	}
+
+	if execFilename == "" {
+		execFilename = fmt.Sprintf("terraform-provider-%s_%s", provider.Type, version.String())
+		if target.OS == "windows" {
+			// For a little more (technically unnecessary) realism...
+			execFilename += ".exe"
+		}
+	}
+
+	zw := zip.NewWriter(f)
+	fw, err := zw.Create(execFilename)
+	if err != nil {
+		return PackageMeta{}, close, fmt.Errorf("failed to add %s to mock zip file: %s", execFilename, err)
+	}
+	fmt.Fprintf(fw, "This is a fake provider package for %s %s, not a real provider.\n", provider, version)
+	err = zw.Close()
+	if err != nil {
+		return PackageMeta{}, close, fmt.Errorf("failed to close the mock zip file: %s", err)
+	}
+
+	// Compute the SHA256 checksum of the generated file, to allow package
+	// authentication code to be exercised.
+	f.Seek(0, io.SeekStart)
+	h := sha256.New()
+	io.Copy(h, f)
+	checksum := [32]byte{}
+	h.Sum(checksum[:0])
+
+	meta := PackageMeta{
+		Provider:         provider,
+		Version:          version,
+		ProtocolVersions: protocols,
+		TargetPlatform:   target,
+
+		Location: PackageLocalArchive(f.Name()),
+
+		// This is a fake filename that mimics what a real registry might
+		// indicate as a good filename for this package, in case some caller
+		// intends to use it to name a local copy of the temporary file.
+		// (At the time of writing, no caller actually does that, but who
+		// knows what the future holds?)
+		Filename: fmt.Sprintf("terraform-provider-%s_%s_%s.zip", provider.Type, version.String(), target.String()),
+
+		Authentication: NewArchiveChecksumAuthentication(target, checksum),
+	}
+	return meta, close, nil
+}
+
+func (s *MockSource) ForDisplay(provider addrs.Provider) string {
+	return "mock source"
+}
diff --git a/v1.5.7/internal/getproviders/multi_source.go b/v1.5.7/internal/getproviders/multi_source.go
new file mode 100644
index 0000000..9ef3226
--- /dev/null
+++ b/v1.5.7/internal/getproviders/multi_source.go
@@ -0,0 +1,259 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+	"fmt"
+	"strings"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// MultiSource is a Source that wraps a series of other sources and combines
+// their sets of available providers and provider versions.
+//
+// A MultiSource consists of a sequence of selectors that each specify an
+// underlying source to query and a set of matching patterns to decide which
+// providers can be retrieved from which sources. If multiple selectors find
+// a given provider version then the earliest one in the sequence takes
+// priority for deciding the package metadata for the provider.
+//
+// For underlying sources that make network requests, consider wrapping each
+// one in a MemoizeSource so that availability information retrieved in
+// AvailableVersions can be reused in PackageMeta.
+type MultiSource []MultiSourceSelector
+
+var _ Source = MultiSource(nil)
+
+// AvailableVersions retrieves all of the versions of the given provider
+// that are available across all of the underlying selectors, while respecting
+// each selector's matching patterns.
+func (s MultiSource) AvailableVersions(ctx context.Context, provider addrs.Provider) (VersionList, Warnings, error) {
+	if len(s) == 0 { // Easy case: there can be no available versions
+		return nil, nil, nil
+	}
+
+	// We will return the union of all versions reported by the nested
+	// sources that have matching patterns that accept the given provider.
+	vs := make(map[Version]struct{})
+	var registryError bool
+	var warnings []string
+	for _, selector := range s {
+		if !selector.CanHandleProvider(provider) {
+			continue // doesn't match the given patterns
+		}
+		thisSourceVersions, warningsResp, err := selector.Source.AvailableVersions(ctx, provider)
+		switch err.(type) {
+		case nil:
+		// okay
+		case ErrRegistryProviderNotKnown:
+			registryError = true
+			continue // ignore, then
+		case ErrProviderNotFound:
+			continue // ignore, then
+		default:
+			return nil, nil, err
+		}
+		for _, v := range thisSourceVersions {
+			vs[v] = struct{}{}
+		}
+		if len(warningsResp) > 0 {
+			warnings = append(warnings, warningsResp...)
+		}
+	}
+
+	if len(vs) == 0 {
+		if registryError {
+			return nil, nil, ErrRegistryProviderNotKnown{provider}
+		} else {
+			return nil, nil, ErrProviderNotFound{provider, s.sourcesForProvider(provider)}
+		}
+	}
+	ret := make(VersionList, 0, len(vs))
+	for v := range vs {
+		ret = append(ret, v)
+	}
+	ret.Sort()
+
+	return ret, warnings, nil
+}
+
+// PackageMeta retrieves the package metadata for the requested provider package
+// from the first selector that indicates availability of it.
+func (s MultiSource) PackageMeta(ctx context.Context, provider addrs.Provider, version Version, target Platform) (PackageMeta, error) {
+	if len(s) == 0 { // Easy case: no providers exist at all
+		return PackageMeta{}, ErrProviderNotFound{provider, s.sourcesForProvider(provider)}
+	}
+
+	for _, selector := range s {
+		if !selector.CanHandleProvider(provider) {
+			continue // doesn't match the given patterns
+		}
+		meta, err := selector.Source.PackageMeta(ctx, provider, version, target)
+		switch err.(type) {
+		case nil:
+			return meta, nil
+		case ErrProviderNotFound, ErrRegistryProviderNotKnown, ErrPlatformNotSupported:
+			continue // ignore, then
+		default:
+			return PackageMeta{}, err
+		}
+	}
+
+	// If we fall out here then none of the sources have the requested
+	// package.
+	return PackageMeta{}, ErrPlatformNotSupported{
+		Provider: provider,
+		Version:  version,
+		Platform: target,
+	}
+}
+
+// MultiSourceSelector is an element of the source selection configuration on
+// MultiSource. A MultiSource has zero or more of these to configure which
+// underlying sources it should consult for a given provider.
+type MultiSourceSelector struct {
+	// Source is the underlying source that this selector applies to.
+	Source Source
+
+	// Include and Exclude are sets of provider matching patterns that
+	// together define which providers are eligible to be potentially
+	// installed from the corresponding Source.
+	Include, Exclude MultiSourceMatchingPatterns
+}
+
+// MultiSourceMatchingPatterns is a set of patterns that together define a
+// set of providers by matching on the segments of the provider FQNs.
+//
+// The Provider address values in a MultiSourceMatchingPatterns are special in
+// that any of Hostname, Namespace, or Type can be getproviders.Wildcard
+// to indicate that any concrete value is permitted for that segment.
+type MultiSourceMatchingPatterns []addrs.Provider
+
+// ParseMultiSourceMatchingPatterns parses a slice of strings containing the
+// string form of provider matching patterns and, if all the given strings are
+// valid, returns the corresponding, normalized, MultiSourceMatchingPatterns
+// value.
+func ParseMultiSourceMatchingPatterns(strs []string) (MultiSourceMatchingPatterns, error) {
+	if len(strs) == 0 {
+		return nil, nil
+	}
+
+	ret := make(MultiSourceMatchingPatterns, len(strs))
+	for i, str := range strs {
+		parts := strings.Split(str, "/")
+		if len(parts) < 2 || len(parts) > 3 {
+			return nil, fmt.Errorf("invalid provider matching pattern %q: must have either two or three slash-separated segments", str)
+		}
+		host := defaultRegistryHost
+		explicitHost := len(parts) == 3
+		if explicitHost {
+			givenHost := parts[0]
+			if givenHost == "*" {
+				host = svchost.Hostname(Wildcard)
+			} else {
+				normalHost, err := svchost.ForComparison(givenHost)
+				if err != nil {
+					return nil, fmt.Errorf("invalid hostname in provider matching pattern %q: %s", str, err)
+				}
+
+				// The remaining code below deals only with the namespace/type portions.
+				host = normalHost
+			}
+
+			parts = parts[1:]
+		}
+
+		pType, err := normalizeProviderNameOrWildcard(parts[1])
+		if err != nil {
+			return nil, fmt.Errorf("invalid provider type %q in provider matching pattern %q: must either be the wildcard * or a provider type name", parts[1], str)
+		}
+		namespace, err := normalizeProviderNameOrWildcard(parts[0])
+		if err != nil {
+			return nil, fmt.Errorf("invalid registry namespace %q in provider matching pattern %q: must either be the wildcard * or a literal namespace", parts[1], str)
+		}
+
+		ret[i] = addrs.Provider{
+			Hostname:  host,
+			Namespace: namespace,
+			Type:      pType,
+		}
+
+		if ret[i].Hostname == svchost.Hostname(Wildcard) && !(ret[i].Namespace == Wildcard && ret[i].Type == Wildcard) {
+			return nil, fmt.Errorf("invalid provider matching pattern %q: hostname can be a wildcard only if both namespace and provider type are also wildcards", str)
+		}
+		if ret[i].Namespace == Wildcard && ret[i].Type != Wildcard {
+			return nil, fmt.Errorf("invalid provider matching pattern %q: namespace can be a wildcard only if the provider type is also a wildcard", str)
+		}
+	}
+	return ret, nil
+}
+
+// CanHandleProvider returns true if and only if the given provider address
+// is both included by the selector's include patterns and _not_ excluded
+// by its exclude patterns.
+//
+// The absense of any include patterns is treated the same as a pattern
+// that matches all addresses. Exclusions take priority over inclusions.
+func (s MultiSourceSelector) CanHandleProvider(addr addrs.Provider) bool {
+	switch {
+	case s.Exclude.MatchesProvider(addr):
+		return false
+	case len(s.Include) > 0:
+		return s.Include.MatchesProvider(addr)
+	default:
+		return true
+	}
+}
+
+// MatchesProvider tests whether the receiving matching patterns match with
+// the given concrete provider address.
+func (ps MultiSourceMatchingPatterns) MatchesProvider(addr addrs.Provider) bool {
+	for _, pattern := range ps {
+		hostMatch := (pattern.Hostname == svchost.Hostname(Wildcard) || pattern.Hostname == addr.Hostname)
+		namespaceMatch := (pattern.Namespace == Wildcard || pattern.Namespace == addr.Namespace)
+		typeMatch := (pattern.Type == Wildcard || pattern.Type == addr.Type)
+		if hostMatch && namespaceMatch && typeMatch {
+			return true
+		}
+	}
+	return false
+}
+
+// Wildcard is a string value representing a wildcard element in the Include
+// and Exclude patterns used with MultiSource. It is not valid to use Wildcard
+// anywhere else.
+const Wildcard string = "*"
+
+// We'll read the default registry host from over in the addrs package, to
+// avoid duplicating it. A "default" provider uses the default registry host
+// by definition.
+var defaultRegistryHost = addrs.DefaultProviderRegistryHost
+
+func normalizeProviderNameOrWildcard(s string) (string, error) {
+	if s == Wildcard {
+		return s, nil
+	}
+	return addrs.ParseProviderPart(s)
+}
+
+func (s MultiSource) ForDisplay(provider addrs.Provider) string {
+	return strings.Join(s.sourcesForProvider(provider), "\n")
+}
+
+// sourcesForProvider returns a list of source display strings configured for a
+// given provider, taking into account any `Exclude` statements.
+func (s MultiSource) sourcesForProvider(provider addrs.Provider) []string {
+	ret := make([]string, 0)
+	for _, selector := range s {
+		if !selector.CanHandleProvider(provider) {
+			continue // doesn't match the given patterns
+		}
+		ret = append(ret, selector.Source.ForDisplay(provider))
+	}
+	return ret
+}
diff --git a/v1.5.7/internal/getproviders/multi_source_test.go b/v1.5.7/internal/getproviders/multi_source_test.go
new file mode 100644
index 0000000..7860a3e
--- /dev/null
+++ b/v1.5.7/internal/getproviders/multi_source_test.go
@@ -0,0 +1,552 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestMultiSourceAvailableVersions(t *testing.T) {
+	platform1 := Platform{OS: "amigaos", Arch: "m68k"}
+	platform2 := Platform{OS: "aros", Arch: "arm"}
+
+	t.Run("unfiltered merging", func(t *testing.T) {
+		s1 := NewMockSource([]PackageMeta{
+			FakePackageMeta(
+				addrs.NewDefaultProvider("foo"),
+				MustParseVersion("1.0.0"),
+				VersionList{MustParseVersion("5.0")},
+				platform1,
+			),
+			FakePackageMeta(
+				addrs.NewDefaultProvider("foo"),
+				MustParseVersion("1.0.0"),
+				VersionList{MustParseVersion("5.0")},
+				platform2,
+			),
+			FakePackageMeta(
+				addrs.NewDefaultProvider("bar"),
+				MustParseVersion("1.0.0"),
+				VersionList{MustParseVersion("5.0")},
+				platform2,
+			),
+		},
+			nil,
+		)
+		s2 := NewMockSource([]PackageMeta{
+			FakePackageMeta(
+				addrs.NewDefaultProvider("foo"),
+				MustParseVersion("1.0.0"),
+				VersionList{MustParseVersion("5.0")},
+				platform1,
+			),
+			FakePackageMeta(
+				addrs.NewDefaultProvider("foo"),
+				MustParseVersion("1.2.0"),
+				VersionList{MustParseVersion("5.0")},
+				platform1,
+			),
+			FakePackageMeta(
+				addrs.NewDefaultProvider("bar"),
+				MustParseVersion("1.0.0"),
+				VersionList{MustParseVersion("5.0")},
+				platform1,
+			),
+		},
+			nil,
+		)
+		multi := MultiSource{
+			{Source: s1},
+			{Source: s2},
+		}
+
+		// AvailableVersions produces the union of all versions available
+		// across all of the sources.
+		got, _, err := multi.AvailableVersions(context.Background(), addrs.NewDefaultProvider("foo"))
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		want := VersionList{
+			MustParseVersion("1.0.0"),
+			MustParseVersion("1.2.0"),
+		}
+
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+
+		_, _, err = multi.AvailableVersions(context.Background(), addrs.NewDefaultProvider("baz"))
+		if want, ok := err.(ErrRegistryProviderNotKnown); !ok {
+			t.Fatalf("wrong error type:\ngot:  %T\nwant: %T", err, want)
+		}
+	})
+
+	t.Run("merging with filters", func(t *testing.T) {
+		// This is just testing that filters are being honored at all, using a
+		// specific pair of filters. The different filter combinations
+		// themselves are tested in TestMultiSourceSelector.
+
+		s1 := NewMockSource([]PackageMeta{
+			FakePackageMeta(
+				addrs.NewDefaultProvider("foo"),
+				MustParseVersion("1.0.0"),
+				VersionList{MustParseVersion("5.0")},
+				platform1,
+			),
+			FakePackageMeta(
+				addrs.NewDefaultProvider("bar"),
+				MustParseVersion("1.0.0"),
+				VersionList{MustParseVersion("5.0")},
+				platform1,
+			),
+		},
+			nil,
+		)
+		s2 := NewMockSource([]PackageMeta{
+			FakePackageMeta(
+				addrs.NewDefaultProvider("foo"),
+				MustParseVersion("1.2.0"),
+				VersionList{MustParseVersion("5.0")},
+				platform1,
+			),
+			FakePackageMeta(
+				addrs.NewDefaultProvider("bar"),
+				MustParseVersion("1.2.0"),
+				VersionList{MustParseVersion("5.0")},
+				platform1,
+			),
+		},
+			nil,
+		)
+		multi := MultiSource{
+			{
+				Source:  s1,
+				Include: mustParseMultiSourceMatchingPatterns("hashicorp/*"),
+			},
+			{
+				Source:  s2,
+				Include: mustParseMultiSourceMatchingPatterns("hashicorp/bar"),
+			},
+		}
+
+		got, _, err := multi.AvailableVersions(context.Background(), addrs.NewDefaultProvider("foo"))
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		want := VersionList{
+			MustParseVersion("1.0.0"),
+			// 1.2.0 isn't present because s3 doesn't include "foo"
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+
+		got, _, err = multi.AvailableVersions(context.Background(), addrs.NewDefaultProvider("bar"))
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		want = VersionList{
+			MustParseVersion("1.0.0"),
+			MustParseVersion("1.2.0"), // included because s2 matches "bar"
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+
+		_, _, err = multi.AvailableVersions(context.Background(), addrs.NewDefaultProvider("baz"))
+		if want, ok := err.(ErrRegistryProviderNotKnown); !ok {
+			t.Fatalf("wrong error type:\ngot:  %T\nwant: %T", err, want)
+		}
+	})
+
+	t.Run("provider not found", func(t *testing.T) {
+		s1 := NewMockSource(nil, nil)
+		s2 := NewMockSource(nil, nil)
+		multi := MultiSource{
+			{Source: s1},
+			{Source: s2},
+		}
+
+		_, _, err := multi.AvailableVersions(context.Background(), addrs.NewDefaultProvider("foo"))
+		if err == nil {
+			t.Fatal("expected error, got success")
+		}
+
+		wantErr := `provider registry registry.terraform.io does not have a provider named registry.terraform.io/hashicorp/foo`
+
+		if err.Error() != wantErr {
+			t.Fatalf("wrong error.\ngot:  %s\nwant: %s\n", err, wantErr)
+		}
+
+	})
+
+	t.Run("merging with warnings", func(t *testing.T) {
+		platform1 := Platform{OS: "amigaos", Arch: "m68k"}
+		platform2 := Platform{OS: "aros", Arch: "arm"}
+		s1 := NewMockSource([]PackageMeta{
+			FakePackageMeta(
+				addrs.NewDefaultProvider("bar"),
+				MustParseVersion("1.0.0"),
+				VersionList{MustParseVersion("5.0")},
+				platform2,
+			),
+		},
+			map[addrs.Provider]Warnings{
+				addrs.NewDefaultProvider("bar"): {"WARNING!"},
+			},
+		)
+		s2 := NewMockSource([]PackageMeta{
+			FakePackageMeta(
+				addrs.NewDefaultProvider("bar"),
+				MustParseVersion("1.0.0"),
+				VersionList{MustParseVersion("5.0")},
+				platform1,
+			),
+		},
+			nil,
+		)
+		multi := MultiSource{
+			{Source: s1},
+			{Source: s2},
+		}
+
+		// AvailableVersions produces the union of all versions available
+		// across all of the sources.
+		got, warns, err := multi.AvailableVersions(context.Background(), addrs.NewDefaultProvider("bar"))
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		want := VersionList{
+			MustParseVersion("1.0.0"),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+
+		if len(warns) != 1 {
+			t.Fatalf("wrong number of warnings. Got %d, wanted 1", len(warns))
+		}
+		if warns[0] != "WARNING!" {
+			t.Fatalf("wrong warnings. Got %s, wanted \"WARNING!\"", warns[0])
+		}
+	})
+}
+
+func TestMultiSourcePackageMeta(t *testing.T) {
+	platform1 := Platform{OS: "amigaos", Arch: "m68k"}
+	platform2 := Platform{OS: "aros", Arch: "arm"}
+
+	// We'll use the Filename field of the fake PackageMetas we created above
+	// to create a difference between the packages in s1 and the ones in s2,
+	// so we can test where individual packages came from below.
+	fakeFilename := func(fn string, meta PackageMeta) PackageMeta {
+		meta.Filename = fn
+		return meta
+	}
+
+	onlyInS1 := fakeFilename("s1", FakePackageMeta(
+		addrs.NewDefaultProvider("foo"),
+		MustParseVersion("1.0.0"),
+		VersionList{MustParseVersion("5.0")},
+		platform2,
+	))
+	onlyInS2 := fakeFilename("s2", FakePackageMeta(
+		addrs.NewDefaultProvider("foo"),
+		MustParseVersion("1.2.0"),
+		VersionList{MustParseVersion("5.0")},
+		platform1,
+	))
+	inBothS1 := fakeFilename("s1", FakePackageMeta(
+		addrs.NewDefaultProvider("foo"),
+		MustParseVersion("1.0.0"),
+		VersionList{MustParseVersion("5.0")},
+		platform1,
+	))
+	inBothS2 := fakeFilename("s2", inBothS1)
+	s1 := NewMockSource([]PackageMeta{
+		inBothS1,
+		onlyInS1,
+		fakeFilename("s1", FakePackageMeta(
+			addrs.NewDefaultProvider("bar"),
+			MustParseVersion("1.0.0"),
+			VersionList{MustParseVersion("5.0")},
+			platform2,
+		)),
+	},
+		nil,
+	)
+	s2 := NewMockSource([]PackageMeta{
+		inBothS2,
+		onlyInS2,
+		fakeFilename("s2", FakePackageMeta(
+			addrs.NewDefaultProvider("bar"),
+			MustParseVersion("1.0.0"),
+			VersionList{MustParseVersion("5.0")},
+			platform1,
+		)),
+	}, nil)
+	multi := MultiSource{
+		{Source: s1},
+		{Source: s2},
+	}
+
+	t.Run("only in s1", func(t *testing.T) {
+		got, err := multi.PackageMeta(
+			context.Background(),
+			addrs.NewDefaultProvider("foo"),
+			MustParseVersion("1.0.0"),
+			platform2,
+		)
+		want := onlyInS1
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("only in s2", func(t *testing.T) {
+		got, err := multi.PackageMeta(
+			context.Background(),
+			addrs.NewDefaultProvider("foo"),
+			MustParseVersion("1.2.0"),
+			platform1,
+		)
+		want := onlyInS2
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("in both", func(t *testing.T) {
+		got, err := multi.PackageMeta(
+			context.Background(),
+			addrs.NewDefaultProvider("foo"),
+			MustParseVersion("1.0.0"),
+			platform1,
+		)
+		want := inBothS1 // S1 "wins" because it's earlier in the MultiSource
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+
+		// Make sure inBothS1 and inBothS2 really are different; if not then
+		// that's a test bug which we'd rather catch than have this test
+		// accidentally passing without actually checking anything.
+		if diff := cmp.Diff(inBothS1, inBothS2); diff == "" {
+			t.Fatalf("test bug: inBothS1 and inBothS2 are indistinguishable")
+		}
+	})
+	t.Run("in neither", func(t *testing.T) {
+		_, err := multi.PackageMeta(
+			context.Background(),
+			addrs.NewDefaultProvider("nonexist"),
+			MustParseVersion("1.0.0"),
+			platform1,
+		)
+		// This case reports "platform not supported" because it assumes that
+		// a caller would only pass to it package versions that were returned
+		// by a previousc all to AvailableVersions, and therefore a missing
+		// object ought to be valid provider/version but an unsupported
+		// platform.
+		if want, ok := err.(ErrPlatformNotSupported); !ok {
+			t.Fatalf("wrong error type:\ngot:  %T\nwant: %T", err, want)
+		}
+	})
+}
+
+func TestMultiSourceSelector(t *testing.T) {
+	emptySource := NewMockSource(nil, nil)
+
+	tests := map[string]struct {
+		Selector  MultiSourceSelector
+		Provider  addrs.Provider
+		WantMatch bool
+	}{
+		"default provider with no constraints": {
+			MultiSourceSelector{
+				Source: emptySource,
+			},
+			addrs.NewDefaultProvider("foo"),
+			true,
+		},
+		"built-in provider with no constraints": {
+			MultiSourceSelector{
+				Source: emptySource,
+			},
+			addrs.NewBuiltInProvider("bar"),
+			true,
+		},
+
+		// Include constraints
+		"default provider with include constraint that matches it exactly": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Include: mustParseMultiSourceMatchingPatterns("hashicorp/foo"),
+			},
+			addrs.NewDefaultProvider("foo"),
+			true,
+		},
+		"default provider with include constraint that matches it via type wildcard": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Include: mustParseMultiSourceMatchingPatterns("hashicorp/*"),
+			},
+			addrs.NewDefaultProvider("foo"),
+			true,
+		},
+		"default provider with include constraint that matches it via namespace wildcard": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Include: mustParseMultiSourceMatchingPatterns("*/*"),
+			},
+			addrs.NewDefaultProvider("foo"),
+			true,
+		},
+		"default provider with non-normalized include constraint that matches it via type wildcard": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Include: mustParseMultiSourceMatchingPatterns("HashiCorp/*"),
+			},
+			addrs.NewDefaultProvider("foo"),
+			true,
+		},
+		"built-in provider with exact include constraint that does not match it": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Include: mustParseMultiSourceMatchingPatterns("hashicorp/foo"),
+			},
+			addrs.NewBuiltInProvider("bar"),
+			false,
+		},
+		"built-in provider with type-wild include constraint that does not match it": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Include: mustParseMultiSourceMatchingPatterns("hashicorp/*"),
+			},
+			addrs.NewBuiltInProvider("bar"),
+			false,
+		},
+		"built-in provider with namespace-wild include constraint that does not match it": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Include: mustParseMultiSourceMatchingPatterns("*/*"),
+			},
+			// Doesn't match because builtin providers are in "terraform.io",
+			// but a pattern with no hostname is for registry.terraform.io.
+			addrs.NewBuiltInProvider("bar"),
+			false,
+		},
+		"built-in provider with include constraint that matches it via type wildcard": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Include: mustParseMultiSourceMatchingPatterns("terraform.io/builtin/*"),
+			},
+			addrs.NewBuiltInProvider("bar"),
+			true,
+		},
+
+		// Exclude constraints
+		"default provider with exclude constraint that matches it exactly": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Exclude: mustParseMultiSourceMatchingPatterns("hashicorp/foo"),
+			},
+			addrs.NewDefaultProvider("foo"),
+			false,
+		},
+		"default provider with exclude constraint that matches it via type wildcard": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Exclude: mustParseMultiSourceMatchingPatterns("hashicorp/*"),
+			},
+			addrs.NewDefaultProvider("foo"),
+			false,
+		},
+		"default provider with exact exclude constraint that doesn't match it": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Exclude: mustParseMultiSourceMatchingPatterns("hashicorp/bar"),
+			},
+			addrs.NewDefaultProvider("foo"),
+			true,
+		},
+		"default provider with non-normalized exclude constraint that matches it via type wildcard": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Exclude: mustParseMultiSourceMatchingPatterns("HashiCorp/*"),
+			},
+			addrs.NewDefaultProvider("foo"),
+			false,
+		},
+
+		// Both include and exclude in a single selector
+		"default provider with exclude wildcard overriding include exact": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Include: mustParseMultiSourceMatchingPatterns("hashicorp/foo"),
+				Exclude: mustParseMultiSourceMatchingPatterns("hashicorp/*"),
+			},
+			addrs.NewDefaultProvider("foo"),
+			false,
+		},
+		"default provider with exclude wildcard overriding irrelevant include exact": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Include: mustParseMultiSourceMatchingPatterns("hashicorp/bar"),
+				Exclude: mustParseMultiSourceMatchingPatterns("hashicorp/*"),
+			},
+			addrs.NewDefaultProvider("foo"),
+			false,
+		},
+		"default provider with exclude exact overriding include wildcard": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Include: mustParseMultiSourceMatchingPatterns("hashicorp/*"),
+				Exclude: mustParseMultiSourceMatchingPatterns("hashicorp/foo"),
+			},
+			addrs.NewDefaultProvider("foo"),
+			false,
+		},
+		"default provider with irrelevant exclude exact overriding include wildcard": {
+			MultiSourceSelector{
+				Source:  emptySource,
+				Include: mustParseMultiSourceMatchingPatterns("hashicorp/*"),
+				Exclude: mustParseMultiSourceMatchingPatterns("hashicorp/bar"),
+			},
+			addrs.NewDefaultProvider("foo"),
+			true,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			t.Logf("include:  %s", test.Selector.Include)
+			t.Logf("exclude:  %s", test.Selector.Exclude)
+			t.Logf("provider: %s", test.Provider)
+			got := test.Selector.CanHandleProvider(test.Provider)
+			want := test.WantMatch
+			if got != want {
+				t.Errorf("wrong result %t; want %t", got, want)
+			}
+		})
+	}
+}
+
+func mustParseMultiSourceMatchingPatterns(strs ...string) MultiSourceMatchingPatterns {
+	ret, err := ParseMultiSourceMatchingPatterns(strs)
+	if err != nil {
+		panic(err)
+	}
+	return ret
+}
diff --git a/v1.5.7/internal/getproviders/package_authentication.go b/v1.5.7/internal/getproviders/package_authentication.go
new file mode 100644
index 0000000..106ba33
--- /dev/null
+++ b/v1.5.7/internal/getproviders/package_authentication.go
@@ -0,0 +1,557 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"bufio"
+	"bytes"
+	"crypto/sha256"
+	"encoding/hex"
+	"fmt"
+	"log"
+	"strings"
+
+	// TODO: replace crypto/openpgp since it is deprecated
+	// https://github.com/golang/go/issues/44226
+	//lint:file-ignore SA1019 openpgp is deprecated but there are no good alternatives yet
+	"golang.org/x/crypto/openpgp"
+	openpgpArmor "golang.org/x/crypto/openpgp/armor"
+	openpgpErrors "golang.org/x/crypto/openpgp/errors"
+)
+
+type packageAuthenticationResult int
+
+const (
+	verifiedChecksum packageAuthenticationResult = iota
+	officialProvider
+	partnerProvider
+	communityProvider
+)
+
+// PackageAuthenticationResult is returned from a PackageAuthentication
+// implementation. It is a mostly-opaque type intended for use in UI, which
+// implements Stringer.
+//
+// A failed PackageAuthentication attempt will return an "unauthenticated"
+// result, which is represented by nil.
+type PackageAuthenticationResult struct {
+	result packageAuthenticationResult
+	KeyID  string
+}
+
+func (t *PackageAuthenticationResult) String() string {
+	if t == nil {
+		return "unauthenticated"
+	}
+	return []string{
+		"verified checksum",
+		"signed by HashiCorp",
+		"signed by a HashiCorp partner",
+		"self-signed",
+	}[t.result]
+}
+
+// SignedByHashiCorp returns whether the package was authenticated as signed
+// by HashiCorp.
+func (t *PackageAuthenticationResult) SignedByHashiCorp() bool {
+	if t == nil {
+		return false
+	}
+	if t.result == officialProvider {
+		return true
+	}
+
+	return false
+}
+
+// SignedByAnyParty returns whether the package was authenticated as signed
+// by either HashiCorp or by a third-party.
+func (t *PackageAuthenticationResult) SignedByAnyParty() bool {
+	if t == nil {
+		return false
+	}
+	if t.result == officialProvider || t.result == partnerProvider || t.result == communityProvider {
+		return true
+	}
+
+	return false
+}
+
+// ThirdPartySigned returns whether the package was authenticated as signed by a party
+// other than HashiCorp.
+func (t *PackageAuthenticationResult) ThirdPartySigned() bool {
+	if t == nil {
+		return false
+	}
+	if t.result == partnerProvider || t.result == communityProvider {
+		return true
+	}
+
+	return false
+}
+
+// SigningKey represents a key used to sign packages from a registry, along
+// with an optional trust signature from the registry operator. These are
+// both in ASCII armored OpenPGP format.
+//
+// The JSON struct tags represent the field names used by the Registry API.
+type SigningKey struct {
+	ASCIIArmor     string `json:"ascii_armor"`
+	TrustSignature string `json:"trust_signature"`
+}
+
+// PackageAuthentication is an interface implemented by the optional package
+// authentication implementations a source may include on its PackageMeta
+// objects.
+//
+// A PackageAuthentication implementation is responsible for authenticating
+// that a package is what its distributor intended to distribute and that it
+// has not been tampered with.
+type PackageAuthentication interface {
+	// AuthenticatePackage takes the local location of a package (which may or
+	// may not be the same as the original source location), and returns a
+	// PackageAuthenticationResult, or an error if the authentication checks
+	// fail.
+	//
+	// The local location is guaranteed not to be a PackageHTTPURL: a remote
+	// package will always be staged locally for inspection first.
+	AuthenticatePackage(localLocation PackageLocation) (*PackageAuthenticationResult, error)
+}
+
+// PackageAuthenticationHashes is an optional interface implemented by
+// PackageAuthentication implementations that are able to return a set of
+// hashes they would consider valid if a given PackageLocation referred to
+// a package that matched that hash string.
+//
+// This can be used to record a set of acceptable hashes for a particular
+// package in a lock file so that future install operations can determine
+// whether the package has changed since its initial installation.
+type PackageAuthenticationHashes interface {
+	PackageAuthentication
+
+	// AcceptableHashes returns a set of hashes that this authenticator
+	// considers to be valid for the current package or, where possible,
+	// equivalent packages on other platforms. The order of the items in
+	// the result is not significant, and it may contain duplicates
+	// that are also not significant.
+	//
+	// This method's result should only be used to create a "lock" for a
+	// particular provider if an earlier call to AuthenticatePackage for
+	// the corresponding package succeeded. A caller might choose to apply
+	// differing levels of trust for the acceptable hashes depending on
+	// the authentication result: a "verified checksum" result only checked
+	// that the downloaded package matched what the source claimed, which
+	// could be considered to be less trustworthy than a check that includes
+	// verifying a signature from the origin registry, depending on what the
+	// hashes are going to be used for.
+	//
+	// Implementations of PackageAuthenticationHashes may return multiple
+	// hashes with different schemes, which means that all of them are equally
+	// acceptable. Implementors may also return hashes that use schemes the
+	// current version of the authenticator would not allow but that could be
+	// accepted by other versions of Terraform, e.g. if a particular hash
+	// scheme has been deprecated.
+	//
+	// Authenticators that don't use hashes as their authentication procedure
+	// will either not implement this interface or will have an implementation
+	// that returns an empty result.
+	AcceptableHashes() []Hash
+}
+
+type packageAuthenticationAll []PackageAuthentication
+
+// PackageAuthenticationAll combines several authentications together into a
+// single check value, which passes only if all of the given ones pass.
+//
+// The checks are processed in the order given, so a failure of an earlier
+// check will prevent execution of a later one.
+//
+// The returned result is from the last authentication, so callers should
+// take care to order the authentications such that the strongest is last.
+//
+// The returned object also implements the AcceptableHashes method from
+// interface PackageAuthenticationHashes, returning the hashes from the
+// last of the given checks that indicates at least one acceptable hash,
+// or no hashes at all if none of the constituents indicate any. The result
+// may therefore be incomplete if there is more than one check that can provide
+// hashes and they disagree about which hashes are acceptable.
+func PackageAuthenticationAll(checks ...PackageAuthentication) PackageAuthentication {
+	return packageAuthenticationAll(checks)
+}
+
+func (checks packageAuthenticationAll) AuthenticatePackage(localLocation PackageLocation) (*PackageAuthenticationResult, error) {
+	var authResult *PackageAuthenticationResult
+	for _, check := range checks {
+		var err error
+		authResult, err = check.AuthenticatePackage(localLocation)
+		if err != nil {
+			return authResult, err
+		}
+	}
+	return authResult, nil
+}
+
+func (checks packageAuthenticationAll) AcceptableHashes() []Hash {
+	// The elements of checks are expected to be ordered so that the strongest
+	// one is later in the list, so we'll visit them in reverse order and
+	// take the first one that implements the interface and returns a non-empty
+	// result.
+	for i := len(checks) - 1; i >= 0; i-- {
+		check, ok := checks[i].(PackageAuthenticationHashes)
+		if !ok {
+			continue
+		}
+		allHashes := check.AcceptableHashes()
+		if len(allHashes) > 0 {
+			return allHashes
+		}
+	}
+	return nil
+}
+
+type packageHashAuthentication struct {
+	RequiredHashes []Hash
+	AllHashes      []Hash
+	Platform       Platform
+}
+
+// NewPackageHashAuthentication returns a PackageAuthentication implementation
+// that checks whether the contents of the package match whatever subset of the
+// given hashes are considered acceptable by the current version of Terraform.
+//
+// This uses the hash algorithms implemented by functions PackageHash and
+// MatchesHash. The PreferredHashes function will select which of the given
+// hashes are considered by Terraform to be the strongest verification, and
+// authentication succeeds as long as one of those matches.
+func NewPackageHashAuthentication(platform Platform, validHashes []Hash) PackageAuthentication {
+	requiredHashes := PreferredHashes(validHashes)
+	return packageHashAuthentication{
+		RequiredHashes: requiredHashes,
+		AllHashes:      validHashes,
+		Platform:       platform,
+	}
+}
+
+func (a packageHashAuthentication) AuthenticatePackage(localLocation PackageLocation) (*PackageAuthenticationResult, error) {
+	if len(a.RequiredHashes) == 0 {
+		// Indicates that none of the hashes given to
+		// NewPackageHashAuthentication were considered to be usable by this
+		// version of Terraform.
+		return nil, fmt.Errorf("this version of Terraform does not support any of the checksum formats given for this provider")
+	}
+
+	matches, err := PackageMatchesAnyHash(localLocation, a.RequiredHashes)
+	if err != nil {
+		return nil, fmt.Errorf("failed to verify provider package checksums: %s", err)
+	}
+
+	if matches {
+		return &PackageAuthenticationResult{result: verifiedChecksum}, nil
+	}
+	if len(a.RequiredHashes) == 1 {
+		return nil, fmt.Errorf("provider package doesn't match the expected checksum %q", a.RequiredHashes[0].String())
+	}
+	// It's non-ideal that this doesn't actually list the expected checksums,
+	// but in the many-checksum case the message would get pretty unweildy.
+	// In practice today we typically use this authenticator only with a
+	// single hash returned from a network mirror, so the better message
+	// above will prevail in that case. Maybe we'll improve on this somehow
+	// if the future introduction of a new hash scheme causes there to more
+	// commonly be multiple hashes.
+	return nil, fmt.Errorf("provider package doesn't match the any of the expected checksums")
+}
+
+func (a packageHashAuthentication) AcceptableHashes() []Hash {
+	// In this case we include even hashes the current version of Terraform
+	// doesn't prefer, because this result is used for building a lock file
+	// and so it's helpful to include older hash formats that other Terraform
+	// versions might need in order to do authentication successfully.
+	return a.AllHashes
+}
+
+type archiveHashAuthentication struct {
+	Platform      Platform
+	WantSHA256Sum [sha256.Size]byte
+}
+
+// NewArchiveChecksumAuthentication returns a PackageAuthentication
+// implementation that checks that the original distribution archive matches
+// the given hash.
+//
+// This authentication is suitable only for PackageHTTPURL and
+// PackageLocalArchive source locations, because the unpacked layout
+// (represented by PackageLocalDir) does not retain access to the original
+// source archive. Therefore this authenticator will return an error if its
+// given localLocation is not PackageLocalArchive.
+//
+// NewPackageHashAuthentication is preferable to use when possible because
+// it uses the newer hashing scheme (implemented by function PackageHash) that
+// can work with both packed and unpacked provider packages.
+func NewArchiveChecksumAuthentication(platform Platform, wantSHA256Sum [sha256.Size]byte) PackageAuthentication {
+	return archiveHashAuthentication{platform, wantSHA256Sum}
+}
+
+func (a archiveHashAuthentication) AuthenticatePackage(localLocation PackageLocation) (*PackageAuthenticationResult, error) {
+	archiveLocation, ok := localLocation.(PackageLocalArchive)
+	if !ok {
+		// A source should not use this authentication type for non-archive
+		// locations.
+		return nil, fmt.Errorf("cannot check archive hash for non-archive location %s", localLocation)
+	}
+
+	gotHash, err := PackageHashLegacyZipSHA(archiveLocation)
+	if err != nil {
+		return nil, fmt.Errorf("failed to compute checksum for %s: %s", archiveLocation, err)
+	}
+	wantHash := HashLegacyZipSHAFromSHA(a.WantSHA256Sum)
+	if gotHash != wantHash {
+		return nil, fmt.Errorf("archive has incorrect checksum %s (expected %s)", gotHash, wantHash)
+	}
+	return &PackageAuthenticationResult{result: verifiedChecksum}, nil
+}
+
+func (a archiveHashAuthentication) AcceptableHashes() []Hash {
+	return []Hash{HashLegacyZipSHAFromSHA(a.WantSHA256Sum)}
+}
+
+type matchingChecksumAuthentication struct {
+	Document      []byte
+	Filename      string
+	WantSHA256Sum [sha256.Size]byte
+}
+
+// NewMatchingChecksumAuthentication returns a PackageAuthentication
+// implementation that scans a registry-provided SHA256SUMS document for a
+// specified filename, and compares the SHA256 hash against the expected hash.
+// This is necessary to ensure that the signed SHA256SUMS document matches the
+// declared SHA256 hash for the package, and therefore that a valid signature
+// of this document authenticates the package.
+//
+// This authentication always returns a nil result, since it alone cannot offer
+// any assertions about package integrity. It should be combined with other
+// authentications to be useful.
+func NewMatchingChecksumAuthentication(document []byte, filename string, wantSHA256Sum [sha256.Size]byte) PackageAuthentication {
+	return matchingChecksumAuthentication{
+		Document:      document,
+		Filename:      filename,
+		WantSHA256Sum: wantSHA256Sum,
+	}
+}
+
+func (m matchingChecksumAuthentication) AuthenticatePackage(location PackageLocation) (*PackageAuthenticationResult, error) {
+	// Find the checksum in the list with matching filename. The document is
+	// in the form "0123456789abcdef filename.zip".
+	filename := []byte(m.Filename)
+	var checksum []byte
+	for _, line := range bytes.Split(m.Document, []byte("\n")) {
+		parts := bytes.Fields(line)
+		if len(parts) > 1 && bytes.Equal(parts[1], filename) {
+			checksum = parts[0]
+			break
+		}
+	}
+	if checksum == nil {
+		return nil, fmt.Errorf("checksum list has no SHA-256 hash for %q", m.Filename)
+	}
+
+	// Decode the ASCII checksum into a byte array for comparison.
+	var gotSHA256Sum [sha256.Size]byte
+	if _, err := hex.Decode(gotSHA256Sum[:], checksum); err != nil {
+		return nil, fmt.Errorf("checksum list has invalid SHA256 hash %q: %s", string(checksum), err)
+	}
+
+	// If the checksums don't match, authentication fails.
+	if !bytes.Equal(gotSHA256Sum[:], m.WantSHA256Sum[:]) {
+		return nil, fmt.Errorf("checksum list has unexpected SHA-256 hash %x (expected %x)", gotSHA256Sum, m.WantSHA256Sum[:])
+	}
+
+	// Success! But this doesn't result in any real authentication, only a
+	// lack of authentication errors, so we return a nil result.
+	return nil, nil
+}
+
+type signatureAuthentication struct {
+	Document  []byte
+	Signature []byte
+	Keys      []SigningKey
+}
+
+// NewSignatureAuthentication returns a PackageAuthentication implementation
+// that verifies the cryptographic signature for a package against any of the
+// provided keys.
+//
+// The signing key for a package will be auto detected by attempting each key
+// in turn until one is successful. If such a key is found, there are three
+// possible successful authentication results:
+//
+//  1. If the signing key is the HashiCorp official key, it is an official
+//     provider;
+//  2. Otherwise, if the signing key has a trust signature from the HashiCorp
+//     Partners key, it is a partner provider;
+//  3. If neither of the above is true, it is a community provider.
+//
+// Any failure in the process of validating the signature will result in an
+// unauthenticated result.
+func NewSignatureAuthentication(document, signature []byte, keys []SigningKey) PackageAuthentication {
+	return signatureAuthentication{
+		Document:  document,
+		Signature: signature,
+		Keys:      keys,
+	}
+}
+
+func (s signatureAuthentication) AuthenticatePackage(location PackageLocation) (*PackageAuthenticationResult, error) {
+	// Find the key that signed the checksum file. This can fail if there is no
+	// valid signature for any of the provided keys.
+	signingKey, keyID, err := s.findSigningKey()
+	if err != nil {
+		return nil, err
+	}
+
+	// Verify the signature using the HashiCorp public key. If this succeeds,
+	// this is an official provider.
+	hashicorpKeyring, err := openpgp.ReadArmoredKeyRing(strings.NewReader(HashicorpPublicKey))
+	if err != nil {
+		return nil, fmt.Errorf("error creating HashiCorp keyring: %s", err)
+	}
+	_, err = openpgp.CheckDetachedSignature(hashicorpKeyring, bytes.NewReader(s.Document), bytes.NewReader(s.Signature))
+	if err == nil {
+		return &PackageAuthenticationResult{result: officialProvider, KeyID: keyID}, nil
+	}
+
+	// If the signing key has a trust signature, attempt to verify it with the
+	// HashiCorp partners public key.
+	if signingKey.TrustSignature != "" {
+		hashicorpPartnersKeyring, err := openpgp.ReadArmoredKeyRing(strings.NewReader(HashicorpPartnersKey))
+		if err != nil {
+			return nil, fmt.Errorf("error creating HashiCorp Partners keyring: %s", err)
+		}
+
+		authorKey, err := openpgpArmor.Decode(strings.NewReader(signingKey.ASCIIArmor))
+		if err != nil {
+			return nil, fmt.Errorf("error decoding signing key: %s", err)
+		}
+
+		trustSignature, err := openpgpArmor.Decode(strings.NewReader(signingKey.TrustSignature))
+		if err != nil {
+			return nil, fmt.Errorf("error decoding trust signature: %s", err)
+		}
+
+		_, err = openpgp.CheckDetachedSignature(hashicorpPartnersKeyring, authorKey.Body, trustSignature.Body)
+		if err != nil {
+			return nil, fmt.Errorf("error verifying trust signature: %s", err)
+		}
+
+		return &PackageAuthenticationResult{result: partnerProvider, KeyID: keyID}, nil
+	}
+
+	// We have a valid signature, but it's not from the HashiCorp key, and it
+	// also isn't a trusted partner. This is a community provider.
+	return &PackageAuthenticationResult{result: communityProvider, KeyID: keyID}, nil
+}
+
+func (s signatureAuthentication) AcceptableHashes() []Hash {
+	// This is a bit of an abstraction leak because signatureAuthentication
+	// otherwise just treats the document as an opaque blob that's been
+	// signed, but here we're making assumptions about its format because
+	// we only want to trust that _all_ of the checksums are valid (rather
+	// than just the current platform's one) if we've also verified that the
+	// bag of checksums is signed.
+	//
+	// In recognition of that layering quirk this implementation is intended to
+	// be somewhat resilient to potentially using this authenticator with
+	// non-checksums files in future (in which case it'll return nothing at all)
+	// but it might be better in the long run to instead combine
+	// signatureAuthentication and matchingChecksumAuthentication together and
+	// be explicit that the resulting merged authenticator is exclusively for
+	// checksums files.
+
+	var ret []Hash
+	sc := bufio.NewScanner(bytes.NewReader(s.Document))
+	for sc.Scan() {
+		parts := bytes.Fields(sc.Bytes())
+		if len(parts) != 0 && len(parts) < 2 {
+			// Doesn't look like a valid sums file line, so we'll assume
+			// this whole thing isn't a checksums file.
+			return nil
+		}
+
+		// If this is a checksums file then the first part should be a
+		// hex-encoded SHA256 hash, so it should be 64 characters long
+		// and contain only hex digits.
+		hashStr := parts[0]
+		if len(hashStr) != 64 {
+			return nil // doesn't look like a checksums file
+		}
+
+		var gotSHA256Sum [sha256.Size]byte
+		if _, err := hex.Decode(gotSHA256Sum[:], hashStr); err != nil {
+			return nil // doesn't look like a checksums file
+		}
+
+		ret = append(ret, HashLegacyZipSHAFromSHA(gotSHA256Sum))
+	}
+
+	return ret
+}
+
+// findSigningKey attempts to verify the signature using each of the keys
+// returned by the registry. If a valid signature is found, it returns the
+// signing key.
+//
+// Note: currently the registry only returns one key, but this may change in
+// the future.
+func (s signatureAuthentication) findSigningKey() (*SigningKey, string, error) {
+	for _, key := range s.Keys {
+		keyring, err := openpgp.ReadArmoredKeyRing(strings.NewReader(key.ASCIIArmor))
+		if err != nil {
+			return nil, "", fmt.Errorf("error decoding signing key: %s", err)
+		}
+
+		entity, err := openpgp.CheckDetachedSignature(keyring, bytes.NewReader(s.Document), bytes.NewReader(s.Signature))
+
+		// If the signature issuer does not match the the key, keep trying the
+		// rest of the provided keys.
+		if err == openpgpErrors.ErrUnknownIssuer {
+			continue
+		}
+
+		// Any other signature error is terminal.
+		if err != nil {
+			return nil, "", fmt.Errorf("error checking signature: %s", err)
+		}
+
+		keyID := "n/a"
+		if entity.PrimaryKey != nil {
+			keyID = entity.PrimaryKey.KeyIdString()
+		}
+
+		log.Printf("[DEBUG] Provider signed by %s", entityString(entity))
+		return &key, keyID, nil
+	}
+
+	// If none of the provided keys issued the signature, this package is
+	// unsigned. This is currently a terminal authentication error.
+	return nil, "", fmt.Errorf("authentication signature from unknown issuer")
+}
+
+// entityString extracts the key ID and identity name(s) from an openpgp.Entity
+// for logging.
+func entityString(entity *openpgp.Entity) string {
+	if entity == nil {
+		return ""
+	}
+
+	keyID := "n/a"
+	if entity.PrimaryKey != nil {
+		keyID = entity.PrimaryKey.KeyIdString()
+	}
+
+	var names []string
+	for _, identity := range entity.Identities {
+		names = append(names, identity.Name)
+	}
+
+	return fmt.Sprintf("%s %s", keyID, strings.Join(names, ", "))
+}
diff --git a/v1.5.7/internal/getproviders/package_authentication_test.go b/v1.5.7/internal/getproviders/package_authentication_test.go
new file mode 100644
index 0000000..27111ff
--- /dev/null
+++ b/v1.5.7/internal/getproviders/package_authentication_test.go
@@ -0,0 +1,744 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"crypto/sha256"
+	"encoding/base64"
+	"errors"
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+
+	// TODO: replace crypto/openpgp since it is deprecated
+	// https://github.com/golang/go/issues/44226
+	//lint:file-ignore SA1019 openpgp is deprecated but there are no good alternatives yet
+	"golang.org/x/crypto/openpgp"
+)
+
+func TestPackageAuthenticationResult(t *testing.T) {
+	tests := []struct {
+		result *PackageAuthenticationResult
+		want   string
+	}{
+		{
+			nil,
+			"unauthenticated",
+		},
+		{
+			&PackageAuthenticationResult{result: verifiedChecksum},
+			"verified checksum",
+		},
+		{
+			&PackageAuthenticationResult{result: officialProvider},
+			"signed by HashiCorp",
+		},
+		{
+			&PackageAuthenticationResult{result: partnerProvider},
+			"signed by a HashiCorp partner",
+		},
+		{
+			&PackageAuthenticationResult{result: communityProvider},
+			"self-signed",
+		},
+	}
+	for _, test := range tests {
+		if got := test.result.String(); got != test.want {
+			t.Errorf("wrong value: got %q, want %q", got, test.want)
+		}
+	}
+}
+
+// mockAuthentication is an implementation of the PackageAuthentication
+// interface which returns fixed values. This is used to test the combining
+// logic of PackageAuthenticationAll.
+type mockAuthentication struct {
+	result packageAuthenticationResult
+	err    error
+}
+
+func (m mockAuthentication) AuthenticatePackage(localLocation PackageLocation) (*PackageAuthenticationResult, error) {
+	if m.err == nil {
+		return &PackageAuthenticationResult{result: m.result}, nil
+	} else {
+		return nil, m.err
+	}
+}
+
+var _ PackageAuthentication = (*mockAuthentication)(nil)
+
+// If all authentications succeed, the returned result should come from the
+// last authentication.
+func TestPackageAuthenticationAll_success(t *testing.T) {
+	result, err := PackageAuthenticationAll(
+		&mockAuthentication{result: verifiedChecksum},
+		&mockAuthentication{result: communityProvider},
+	).AuthenticatePackage(nil)
+
+	want := PackageAuthenticationResult{result: communityProvider}
+	if result == nil || *result != want {
+		t.Errorf("wrong result: want %#v, got %#v", want, result)
+	}
+	if err != nil {
+		t.Errorf("wrong err: got %#v, want nil", err)
+	}
+}
+
+// If an authentication fails, its error should be returned along with a nil
+// result.
+func TestPackageAuthenticationAll_failure(t *testing.T) {
+	someError := errors.New("some error")
+	result, err := PackageAuthenticationAll(
+		&mockAuthentication{result: verifiedChecksum},
+		&mockAuthentication{err: someError},
+		&mockAuthentication{result: communityProvider},
+	).AuthenticatePackage(nil)
+
+	if result != nil {
+		t.Errorf("wrong result: got %#v, want nil", result)
+	}
+	if err != someError {
+		t.Errorf("wrong err: got %#v, want %#v", err, someError)
+	}
+}
+
+// Package hash authentication requires a zip file or directory fixture and a
+// known-good set of hashes, of which the authenticator will pick one. The
+// result should be "verified checksum".
+func TestPackageHashAuthentication_success(t *testing.T) {
+	// Location must be a PackageLocalArchive path
+	location := PackageLocalDir("testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64")
+
+	wantHashes := []Hash{
+		// Known-good HashV1 result for this directory
+		Hash("h1:qjsREM4DqEWECD43FcPqddZ9oxCG+IaMTxvWPciS05g="),
+	}
+
+	auth := NewPackageHashAuthentication(Platform{"linux", "amd64"}, wantHashes)
+	result, err := auth.AuthenticatePackage(location)
+
+	wantResult := PackageAuthenticationResult{result: verifiedChecksum}
+	if result == nil || *result != wantResult {
+		t.Errorf("wrong result: got %#v, want %#v", result, wantResult)
+	}
+	if err != nil {
+		t.Errorf("wrong err: got %s, want nil", err)
+	}
+}
+
+// Package has authentication can fail for various reasons.
+func TestPackageHashAuthentication_failure(t *testing.T) {
+	tests := map[string]struct {
+		location PackageLocation
+		err      string
+	}{
+		"missing file": {
+			PackageLocalArchive("testdata/no-package-here.zip"),
+			"failed to verify provider package checksums: lstat testdata/no-package-here.zip: no such file or directory",
+		},
+		"checksum mismatch": {
+			PackageLocalDir("testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64"),
+			"provider package doesn't match the expected checksum \"h1:invalid\"",
+		},
+		"invalid zip file": {
+			PackageLocalArchive("testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip"),
+			"failed to verify provider package checksums: zip: not a valid zip file",
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			// Invalid expected hash, either because we'll error before we
+			// reach it, or we want to force a checksum mismatch.
+			auth := NewPackageHashAuthentication(Platform{"linux", "amd64"}, []Hash{"h1:invalid"})
+			result, err := auth.AuthenticatePackage(test.location)
+
+			if result != nil {
+				t.Errorf("wrong result: got %#v, want nil", result)
+			}
+			if gotErr := err.Error(); gotErr != test.err {
+				t.Errorf("wrong err: got %q, want %q", gotErr, test.err)
+			}
+		})
+	}
+}
+
+// Archive checksum authentication requires a file fixture and a known-good
+// SHA256 hash. The result should be "verified checksum".
+func TestArchiveChecksumAuthentication_success(t *testing.T) {
+	// Location must be a PackageLocalArchive path
+	location := PackageLocalArchive("testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip")
+
+	// Known-good SHA256 hash for this archive
+	wantSHA256Sum := [sha256.Size]byte{
+		0x4f, 0xb3, 0x98, 0x49, 0xf2, 0xe1, 0x38, 0xeb,
+		0x16, 0xa1, 0x8b, 0xa0, 0xc6, 0x82, 0x63, 0x5d,
+		0x78, 0x1c, 0xb8, 0xc3, 0xb2, 0x59, 0x01, 0xdd,
+		0x5a, 0x79, 0x2a, 0xde, 0x97, 0x11, 0xf5, 0x01,
+	}
+
+	auth := NewArchiveChecksumAuthentication(Platform{"linux", "amd64"}, wantSHA256Sum)
+	result, err := auth.AuthenticatePackage(location)
+
+	wantResult := PackageAuthenticationResult{result: verifiedChecksum}
+	if result == nil || *result != wantResult {
+		t.Errorf("wrong result: got %#v, want %#v", result, wantResult)
+	}
+	if err != nil {
+		t.Errorf("wrong err: got %s, want nil", err)
+	}
+}
+
+// Archive checksum authentication can fail for various reasons. These test
+// cases are almost exhaustive, missing only an io.Copy error which is
+// difficult to induce.
+func TestArchiveChecksumAuthentication_failure(t *testing.T) {
+	tests := map[string]struct {
+		location PackageLocation
+		err      string
+	}{
+		"missing file": {
+			PackageLocalArchive("testdata/no-package-here.zip"),
+			"failed to compute checksum for testdata/no-package-here.zip: lstat testdata/no-package-here.zip: no such file or directory",
+		},
+		"checksum mismatch": {
+			PackageLocalArchive("testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip"),
+			"archive has incorrect checksum zh:4fb39849f2e138eb16a18ba0c682635d781cb8c3b25901dd5a792ade9711f501 (expected zh:0000000000000000000000000000000000000000000000000000000000000000)",
+		},
+		"invalid location": {
+			PackageLocalDir("testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64"),
+			"cannot check archive hash for non-archive location testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64",
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			// Zero expected checksum, either because we'll error before we
+			// reach it, or we want to force a checksum mismatch
+			auth := NewArchiveChecksumAuthentication(Platform{"linux", "amd64"}, [sha256.Size]byte{0})
+			result, err := auth.AuthenticatePackage(test.location)
+
+			if result != nil {
+				t.Errorf("wrong result: got %#v, want nil", result)
+			}
+			if gotErr := err.Error(); gotErr != test.err {
+				t.Errorf("wrong err: got %q, want %q", gotErr, test.err)
+			}
+		})
+	}
+}
+
+// Matching checksum authentication takes a SHA256SUMS document, an archive
+// filename, and an expected SHA256 hash. On success both return values should
+// be nil.
+func TestMatchingChecksumAuthentication_success(t *testing.T) {
+	// Location is unused
+	location := PackageLocalArchive("testdata/my-package.zip")
+
+	// Two different checksums for other files
+	wantSHA256Sum := [sha256.Size]byte{0xde, 0xca, 0xde}
+	otherSHA256Sum := [sha256.Size]byte{0xc0, 0xff, 0xee}
+
+	document := []byte(
+		fmt.Sprintf(
+			"%x README.txt\n%x my-package.zip\n",
+			otherSHA256Sum,
+			wantSHA256Sum,
+		),
+	)
+	filename := "my-package.zip"
+
+	auth := NewMatchingChecksumAuthentication(document, filename, wantSHA256Sum)
+	result, err := auth.AuthenticatePackage(location)
+
+	if result != nil {
+		t.Errorf("wrong result: got %#v, want nil", result)
+	}
+	if err != nil {
+		t.Errorf("wrong err: got %s, want nil", err)
+	}
+}
+
+// Matching checksum authentication can fail for three reasons: no checksum
+// in the document for the filename, invalid checksum value, and non-matching
+// checksum value.
+func TestMatchingChecksumAuthentication_failure(t *testing.T) {
+	wantSHA256Sum := [sha256.Size]byte{0xde, 0xca, 0xde}
+	filename := "my-package.zip"
+
+	tests := map[string]struct {
+		document []byte
+		err      string
+	}{
+		"no checksum for filename": {
+			[]byte(
+				fmt.Sprintf(
+					"%x README.txt",
+					[sha256.Size]byte{0xbe, 0xef},
+				),
+			),
+			`checksum list has no SHA-256 hash for "my-package.zip"`,
+		},
+		"invalid checksum": {
+			[]byte(
+				fmt.Sprintf(
+					"%s README.txt\n%s my-package.zip",
+					"horses",
+					"chickens",
+				),
+			),
+			`checksum list has invalid SHA256 hash "chickens": encoding/hex: invalid byte: U+0068 'h'`,
+		},
+		"checksum mismatch": {
+			[]byte(
+				fmt.Sprintf(
+					"%x README.txt\n%x my-package.zip",
+					[sha256.Size]byte{0xbe, 0xef},
+					[sha256.Size]byte{0xc0, 0xff, 0xee},
+				),
+			),
+			"checksum list has unexpected SHA-256 hash c0ffee0000000000000000000000000000000000000000000000000000000000 (expected decade0000000000000000000000000000000000000000000000000000000000)",
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			// Location is unused
+			location := PackageLocalArchive("testdata/my-package.zip")
+
+			auth := NewMatchingChecksumAuthentication(test.document, filename, wantSHA256Sum)
+			result, err := auth.AuthenticatePackage(location)
+
+			if result != nil {
+				t.Errorf("wrong result: got %#v, want nil", result)
+			}
+			if gotErr := err.Error(); gotErr != test.err {
+				t.Errorf("wrong err: got %q, want %q", gotErr, test.err)
+			}
+		})
+	}
+}
+
+// Signature authentication takes a checksum document, a signature, and a list
+// of signing keys. If the document is signed by one of the given keys, the
+// authentication is successful. The value of the result depends on the signing
+// key and its trust signature.
+func TestSignatureAuthentication_success(t *testing.T) {
+	tests := map[string]struct {
+		signature string
+		keys      []SigningKey
+		result    PackageAuthenticationResult
+	}{
+		"partner provider": {
+			testAuthorSignatureGoodBase64,
+			[]SigningKey{
+				{
+					ASCIIArmor:     testAuthorKeyArmor,
+					TrustSignature: testAuthorKeyTrustSignatureArmor,
+				},
+			},
+			PackageAuthenticationResult{
+				result: partnerProvider,
+				KeyID:  testAuthorKeyID,
+			},
+		},
+		"community provider": {
+			testAuthorSignatureGoodBase64,
+			[]SigningKey{
+				{
+					ASCIIArmor: testAuthorKeyArmor,
+				},
+			},
+			PackageAuthenticationResult{
+				result: communityProvider,
+				KeyID:  testAuthorKeyID,
+			},
+		},
+		"multiple signing keys": {
+			testAuthorSignatureGoodBase64,
+			[]SigningKey{
+				{
+					ASCIIArmor: HashicorpPartnersKey,
+				},
+				{
+					ASCIIArmor: testAuthorKeyArmor,
+				},
+			},
+			PackageAuthenticationResult{
+				result: communityProvider,
+				KeyID:  testAuthorKeyID,
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			// Location is unused
+			location := PackageLocalArchive("testdata/my-package.zip")
+
+			signature, err := base64.StdEncoding.DecodeString(test.signature)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			auth := NewSignatureAuthentication([]byte(testShaSumsPlaceholder), signature, test.keys)
+			result, err := auth.AuthenticatePackage(location)
+
+			if result == nil || *result != test.result {
+				t.Errorf("wrong result: got %#v, want %#v", result, test.result)
+			}
+			if err != nil {
+				t.Errorf("wrong err: got %s, want nil", err)
+			}
+		})
+	}
+}
+
+func TestNewSignatureAuthentication_success(t *testing.T) {
+	tests := map[string]struct {
+		signature string
+		keys      []SigningKey
+		result    PackageAuthenticationResult
+	}{
+		"official provider": {
+			testHashicorpSignatureGoodBase64,
+			[]SigningKey{
+				{
+					ASCIIArmor: HashicorpPublicKey,
+				},
+			},
+			PackageAuthenticationResult{
+				result: officialProvider,
+				KeyID:  testHashiCorpPublicKeyID,
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			// Location is unused
+			location := PackageLocalArchive("testdata/my-package.zip")
+
+			signature, err := base64.StdEncoding.DecodeString(test.signature)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			auth := NewSignatureAuthentication([]byte(testProviderShaSums), signature, test.keys)
+			result, err := auth.AuthenticatePackage(location)
+
+			if result == nil || *result != test.result {
+				t.Errorf("wrong result: got %#v, want %#v", result, test.result)
+			}
+			if err != nil {
+				t.Errorf("wrong err: got %s, want nil", err)
+			}
+		})
+	}
+}
+
+// Signature authentication can fail for many reasons, most of which are due
+// to OpenPGP failures from malformed keys or signatures.
+func TestSignatureAuthentication_failure(t *testing.T) {
+	tests := map[string]struct {
+		signature string
+		keys      []SigningKey
+		err       string
+	}{
+		"invalid key": {
+			testHashicorpSignatureGoodBase64,
+			[]SigningKey{
+				{
+					ASCIIArmor: "invalid PGP armor value",
+				},
+			},
+			"error decoding signing key: openpgp: invalid argument: no armored data found",
+		},
+		"invalid signature": {
+			testSignatureBadBase64,
+			[]SigningKey{
+				{
+					ASCIIArmor: testAuthorKeyArmor,
+				},
+			},
+			"error checking signature: openpgp: invalid data: signature subpacket truncated",
+		},
+		"no keys match signature": {
+			testAuthorSignatureGoodBase64,
+			[]SigningKey{
+				{
+					ASCIIArmor: HashicorpPublicKey,
+				},
+			},
+			"authentication signature from unknown issuer",
+		},
+		"invalid trust signature": {
+			testAuthorSignatureGoodBase64,
+			[]SigningKey{
+				{
+					ASCIIArmor:     testAuthorKeyArmor,
+					TrustSignature: "invalid PGP armor value",
+				},
+			},
+			"error decoding trust signature: EOF",
+		},
+		"unverified trust signature": {
+			testAuthorSignatureGoodBase64,
+			[]SigningKey{
+				{
+					ASCIIArmor:     testAuthorKeyArmor,
+					TrustSignature: testOtherKeyTrustSignatureArmor,
+				},
+			},
+			"error verifying trust signature: openpgp: invalid signature: hash tag doesn't match",
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			// Location is unused
+			location := PackageLocalArchive("testdata/my-package.zip")
+
+			signature, err := base64.StdEncoding.DecodeString(test.signature)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			auth := NewSignatureAuthentication([]byte(testShaSumsPlaceholder), signature, test.keys)
+			result, err := auth.AuthenticatePackage(location)
+
+			if result != nil {
+				t.Errorf("wrong result: got %#v, want nil", result)
+			}
+			if gotErr := err.Error(); gotErr != test.err {
+				t.Errorf("wrong err: got %s, want %s", gotErr, test.err)
+			}
+		})
+	}
+}
+
+func TestSignatureAuthentication_acceptableHashes(t *testing.T) {
+	auth := NewSignatureAuthentication([]byte(testShaSumsRealistic), nil, nil)
+	authWithHashes, ok := auth.(PackageAuthenticationHashes)
+	if !ok {
+		t.Fatalf("%T does not implement PackageAuthenticationHashes", auth)
+	}
+	got := authWithHashes.AcceptableHashes()
+	want := []Hash{
+		// These are the hashes encoded in constant testShaSumsRealistic
+		"zh:7d7e888fdd28abfe00894f9055209b9eec785153641de98e6852aa071008d4ee",
+		"zh:f8b6cf9ade087c17826d49d89cef21261cdc22bd27065bbc5b27d7dbf7fbbf6c",
+		"zh:a5ba9945606bb7bfb821ba303957eeb40dd9ee4e706ba8da1eaf7cbeb0356e63",
+		"zh:df3a5a8d6ffff7bacf19c92d10d0d500f98169ea17b3764b01a789f563d1aad7",
+		"zh:086119a26576d06b8281a97e8644380da89ce16197cd955f74ea5ee664e9358b",
+		"zh:1e5f7a5f3ade7b8b1d1d59c5cea2e1a2f8d2f8c3f41962dbbe8647e222be8239",
+		"zh:0e9fd0f3e2254b526a0e81e0cfdfc82583b0cd343778c53ead21aa7d52f776d7",
+		"zh:66a947e7de1c74caf9f584c3ed4e91d2cb1af6fe5ce8abaf1cf8f7ff626a09d1",
+		"zh:def1b73849bec0dc57a04405847921bf9206c75b52ae9de195476facb26bd85e",
+		"zh:48f1826ec31d6f104e46cc2022b41f30cd1019ef48eaec9697654ef9ec37a879",
+		"zh:17e0b496022bc4e4137be15e96d2b051c8acd6e14cb48d9b13b262330464f6cc",
+		"zh:2696c86228f491bc5425561c45904c9ce39b1c676b1e17734cb2ee6b578c4bcd",
+	}
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Errorf("wrong result\n%s", diff)
+	}
+}
+
+const testAuthorKeyID = `37A6AB3BCF2C170A`
+
+// testAuthorKeyArmor is test key ID 5BFEEC4317E746008621970637A6AB3BCF2C170A.
+const testAuthorKeyArmor = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBF5vhgYBCAC40OcC2hEx3yGiLhHMbt7DAVEQ0nZwAWy6oL98niknLumBa1VO
+nMYshP+o/FKOFatBl8aXhmDo606P6pD9d4Pg/WNehqT7hGNHcAFlm+8qjQAvE5uX
+Z/na/Np7dmWasCiL5hYyHEnKU/XFpc9KyicbkS7n8igP1LEb8xDD1pMLULQsQHA4
+258asvtwjoYTZIij1I6bUE178bGFPNCfj+FzQM8nKzPpDVxZ7njN9c2sB9FEdJ1+
+S9mZQNK5PbJuEAOpD5Jp9BnGE16jsLUhDmvGHBjFZAXMBkNSloEMHhs2ty9lEzoF
+eJmJx7XCGw+ds1SWp4MsHQPWzXxAlrfa4GMlABEBAAG0R1RlcnJhZm9ybSBUZXN0
+aW5nIChwbHVnaW4vZGlzY292ZXJ5LykgPHRlcnJhZm9ybSt0ZXN0aW5nQGhhc2hp
+Y29ycC5jb20+iQFOBBMBCAA4FiEEW/7sQxfnRgCGIZcGN6arO88sFwoFAl5vhgYC
+GwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQN6arO88sFwpWvQf/apaMu4Bm
+ea8AGjdl9acQhHBpWsyiHLIfZvN11xxN/f3+YITvPXIe2PMgveqNfXxu6PIeZGDb
+0DBvnBQy/vqmA+sCQ8t8+kIWdfZ1EeM2YcXdmAEtriooLvc85JFYjafLIKSj9N7o
+V/R/e1BCW/v1/7Je47c+6FSt3HHhwyT5AZ3BCq1zpw6PeCDSQ/gZr3Mvq4CjeLA/
+K+8TM3KyOF4qBGDvzGzp/t9umQSS2L0ozd90lxJtf5Q8ozqDaBiDo+f/osXT2EvN
+VwPP/xh/gABkXiNrPylFbeD+XPAC4N7NmYK5aPDzRYXXknP8e9PDMykoJKZ+bSdz
+F3IZ4q5RDHmmNbkBDQReb4YGAQgAt15e1F8TPQQm1jK8+scypHgfmPHbp7Qsulo1
+GTcUd8QmhbR4kayuLDEpJYzq6+IoTM4TPqsdVuq/1Nwey9oyK0wXk/SUR29nRIQh
+3GBg7JVg1YsObsfVTvEflYOdjk8T/Udqs4I6HnmSbtzsaohzybutpWXPUkW8OzFI
+ATwfVTrrz70Yxs+ly0nSEH2Yf+kg2uYZvv5KsJ3MNENhXnHnlaTy2IfhsxAX0xOG
+pa9fXV3NzdEbl0mYaEzMi77qRAyIQ9VrIL5F0yY/LlbpLSl6xk2+BB2v3a1Ey6SJ
+w4/le6AM0wlH2hKPCTlkvM0IvUWjlzrPzCkeu027iVc+fqdyiQARAQABiQE2BBgB
+CAAgFiEEW/7sQxfnRgCGIZcGN6arO88sFwoFAl5vhgYCGwwACgkQN6arO88sFwqz
+nAf/eF4oZG9F8sJX01mVdDm/L7Uthe4xjTdl7jwV4ygNX+pCyWrww3qc3qbd3QKg
+CFqIt/TAPE/OxHxCFuxalQefpOqfxjKzvcktxzWmpgxaWsvHaXiS4bKBPz78N/Ke
+MUtcjGHyLeSzYPUfjquqDzQxqXidRYhyHGSy9c0NKZ6wCElLZ6KcmCQb4sZxVwfu
+ssjwAFbPMp1nr0f5SWCJfhTh7QF7lO2ldJaKMlcBM8aebmqFQ52P7ZWOFcgeerng
+G7Zdrci1KEd943HhzDCsUFz4gJwbvUyiAYb2ddndpUBkYwCB/XrHWPOSnGxHgZoo
+1gIqed9OV/+s5wKxZPjL0pCStQ==
+=mYqJ
+-----END PGP PUBLIC KEY BLOCK-----`
+
+// testAuthorKeyTrustSignatureArmor is a trust signature of the data in
+// testAuthorKeyArmor signed with HashicorpPartnersKey.
+const testAuthorKeyTrustSignatureArmor = `-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCAAdFiEEUYkGV8Ws20uCMIZWfXLUJo5GYPwFAl5w9+YACgkQfXLUJo5G
+YPwjRBAAvy9jo3vvetb4qx/z2qhbRH2JbZN9byKuqlIggPzDhhaIsVJVZ9L6H6bE
+AMgPe/NaH58wfiqMYenulYxj9tZwJORT/OK0Y9ZFXXZk6kWPMNv7TEppyB0wKgqq
+ORKf07KjDcVQslDG9ARgnvDq2GA4UTHxhT0chKHdIKeDLmTm0VSkfNeOhQIkW7vB
+S/WT9y78319QJek8OKwJo0Jv0O93rvZZI0JFjXGtP15XNBfObMtPXn3l8qoLzhsv
+pJJG/u+BsVZ+y1JDQQlHaD1P2TLW/nGymFq12k693IOCmNyaIOa01Wa9B/j3a3RY
+v4SdkULvJKbttNMNBgIMJ74wZp5EUhEFs68sllrIrmthH8bW2fbcHEQ1g/MJCe3+
+43c9aoW8yNQmuEe7yre9lgqcJOIOxlb5XEJhH0Lh+8OBi5aHA/5wXGU5WrhWqHCR
+npXBsNqy2sKUuVkEzvn3Hd6aoKncVLrgNR8xA3VP86jJhawvO+M+YYMr1wOVHc/I
+PYq9hlyUR8qJ/0RpnaIE1iLbPYfEpGTg7oHORpbQVoZAUwMN/Sdox7sMkqCOb1RJ
+Cmy9J5o7iiNOoshvps5cxcbsM7LNfbf0vDhWpckAvsQehrS1mfVuFHkIiotVQhH1
+QXPfvB2cVF/SxMqqHWpnT+8c8klfS03kXSb0BdknrQ4DNPq1H5A=
+=3A1s
+-----END PGP SIGNATURE-----`
+
+// testOtherKeyTrustSignatureArmor is a trust signature of another key (not the
+// author key), signed with HashicorpPartnersKey.
+const testOtherKeyTrustSignatureArmor = `-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCAAdFiEEUYkGV8Ws20uCMIZWfXLUJo5GYPwFAl6POvsACgkQfXLUJo5G
+YPyGihAAomM1kGmrC5KRgWQ+V47r8wFoIkhsTgAYb9ENOzn/RVJt3SJSstcKxfA3
+7HW5R4kqAoXH1hcPYpUcOcdeAvtZxjGRQ9JgErV8NBg6sR11aQccCzAG4Hy0hWav
+/jB5NzTEX5JFEXH6WhpWI1avh0l2j6JxO1K1s+5+5PI3KbuO+XSqeZ3QmUz9FwGu
+pr0J6oYcERupzrpnmgMb5fbkpHfzffR2/MOYdF9Hae4EvDS1b7tokuuKsStNnCm0
+ge7PFdekwbj/OiQrQlqM1pOw2siPX3ouWCtW8oExm9tAxNw31Bn2g3oaNMkHMqJd
+hlVUZlqeJMyylUat3cY7GTQONfCnoyUHe/wv8exBUbV3v2glp9y2g9i2XmXkHOrV
+Z+pnNBc+jdp3a4O0Y8fXXZdjiIolZKY8BbvzheuMrQQIOmw4N3KrZbTpLKuqz8rb
+h8bqUbU42oWcJmBvzF4NZ4tQ+aFHs4CbOnjfDfS14baQr2Gqo9BqTfrzS5Pbs8lq
+AhY0r+zi71lQ1rBfgZfjd8zWlOzpDO//nwKhGCqYOWke/C/T6o0zxM0R4uR4zXwT
+KhvXK8/kK/L8Flaxqme0d5bzXLbsMe9I6I76DY5iNhkiFnnWt4+FhGoIDR03MTKS
+SnHodBLlpKLyUXi36DCDy/iKVsieqLsAdcYe0nQFuhoQcOme33A=
+=aHOG
+-----END PGP SIGNATURE-----`
+
+// testShaSumsPlaceholder is a string that represents a signed document that
+// the signature authenticator will check. Some of the signature valuesin
+// other constants in this file are signing this string.
+const testShaSumsPlaceholder = "example shasums data"
+
+// testShaSumsRealistic is a more realistic SHA256SUMS document that we can use
+// to test the AcceptableHashes method. The signature values in other constants
+// in this file do not sign this string.
+const testShaSumsRealistic = `7d7e888fdd28abfe00894f9055209b9eec785153641de98e6852aa071008d4ee  terraform_0.14.0-alpha20200923_darwin_amd64.zip
+f8b6cf9ade087c17826d49d89cef21261cdc22bd27065bbc5b27d7dbf7fbbf6c  terraform_0.14.0-alpha20200923_freebsd_386.zip
+a5ba9945606bb7bfb821ba303957eeb40dd9ee4e706ba8da1eaf7cbeb0356e63  terraform_0.14.0-alpha20200923_freebsd_amd64.zip
+df3a5a8d6ffff7bacf19c92d10d0d500f98169ea17b3764b01a789f563d1aad7  terraform_0.14.0-alpha20200923_freebsd_arm.zip
+086119a26576d06b8281a97e8644380da89ce16197cd955f74ea5ee664e9358b  terraform_0.14.0-alpha20200923_linux_386.zip
+1e5f7a5f3ade7b8b1d1d59c5cea2e1a2f8d2f8c3f41962dbbe8647e222be8239  terraform_0.14.0-alpha20200923_linux_amd64.zip
+0e9fd0f3e2254b526a0e81e0cfdfc82583b0cd343778c53ead21aa7d52f776d7  terraform_0.14.0-alpha20200923_linux_arm.zip
+66a947e7de1c74caf9f584c3ed4e91d2cb1af6fe5ce8abaf1cf8f7ff626a09d1  terraform_0.14.0-alpha20200923_openbsd_386.zip
+def1b73849bec0dc57a04405847921bf9206c75b52ae9de195476facb26bd85e  terraform_0.14.0-alpha20200923_openbsd_amd64.zip
+48f1826ec31d6f104e46cc2022b41f30cd1019ef48eaec9697654ef9ec37a879  terraform_0.14.0-alpha20200923_solaris_amd64.zip
+17e0b496022bc4e4137be15e96d2b051c8acd6e14cb48d9b13b262330464f6cc  terraform_0.14.0-alpha20200923_windows_386.zip
+2696c86228f491bc5425561c45904c9ce39b1c676b1e17734cb2ee6b578c4bcd  terraform_0.14.0-alpha20200923_windows_amd64.zip`
+
+// testAuthorSignatureGoodBase64 is a signature of testShaSums signed with
+// testAuthorKeyArmor, which represents the SHA256SUMS.sig file downloaded for
+// a release.
+const testAuthorSignatureGoodBase64 = `iQEzBAABCAAdFiEEW/7sQxfnRgCGIZcGN6arO88s` +
+	`FwoFAl5vh7gACgkQN6arO88sFwrAlQf6Al77qzjxNIj+NQNJfBGYUE5jHIgcuWOs1IPRTYUI` +
+	`rHQIUU2RVrdHoAefKTKNzGde653JK/pYTflSV+6ini3/aZZnXlF6t001w3wswmakdwTr0hXx` +
+	`Ez/hHYio72Gpn7+T/L+nl6dKkjeGqd/Kor5x2TY9uYB737ESmAe5T8ZlPaGMFHh0mYlNTeRq` +
+	`4qIKqL6DwddBF4Ju2svn2MeNMGfE358H31mxAl2k4PPrwBTR1sFUCUOzAXVA/g9Ov5Y9ni2G` +
+	`rkTahBtV9yuUUd1D+oRTTTdP0bj3A+3xxXmKTBhRuvurydPTicKuWzeILIJkcwp7Kl5UbI2N` +
+	`n1ayZdaCIw/r4w==`
+
+// testSignatureBadBase64 is an invalid signature.
+const testSignatureBadBase64 = `iQEzBAABCAAdFiEEW/7sQxfnRgCGIZcGN6arO88s` +
+	`4qIKqL6DwddBF4Ju2svn2MeNMGfE358H31mxAl2k4PPrwBTR1sFUCUOzAXVA/g9Ov5Y9ni2G` +
+	`rkTahBtV9yuUUd1D+oRTTTdP0bj3A+3xxXmKTBhRuvurydPTicKuWzeILIJkcwp7Kl5UbI2N` +
+	`n1ayZdaCIw/r4w==`
+
+// testHashiCorpPublicKeyID is the Key ID of the HashiCorpPublicKey.
+const testHashiCorpPublicKeyID = `34365D9472D7468F`
+
+const testProviderShaSums = `fea4227271ebf7d9e2b61b89ce2328c7262acd9fd190e1fd6d15a591abfa848e  terraform-provider-null_3.1.0_darwin_amd64.zip
+9ebf4d9704faba06b3ec7242c773c0fbfe12d62db7d00356d4f55385fc69bfb2  terraform-provider-null_3.1.0_darwin_arm64.zip
+a6576c81adc70326e4e1c999c04ad9ca37113a6e925aefab4765e5a5198efa7e  terraform-provider-null_3.1.0_freebsd_386.zip
+5f9200bf708913621d0f6514179d89700e9aa3097c77dac730e8ba6e5901d521  terraform-provider-null_3.1.0_freebsd_amd64.zip
+fc39cc1fe71234a0b0369d5c5c7f876c71b956d23d7d6f518289737a001ba69b  terraform-provider-null_3.1.0_freebsd_arm.zip
+c797744d08a5307d50210e0454f91ca4d1c7621c68740441cf4579390452321d  terraform-provider-null_3.1.0_linux_386.zip
+53e30545ff8926a8e30ad30648991ca8b93b6fa496272cd23b26763c8ee84515  terraform-provider-null_3.1.0_linux_amd64.zip
+cecb6a304046df34c11229f20a80b24b1603960b794d68361a67c5efe58e62b8  terraform-provider-null_3.1.0_linux_arm64.zip
+e1371aa1e502000d9974cfaff5be4cfa02f47b17400005a16f14d2ef30dc2a70  terraform-provider-null_3.1.0_linux_arm.zip
+a8a42d13346347aff6c63a37cda9b2c6aa5cc384a55b2fe6d6adfa390e609c53  terraform-provider-null_3.1.0_windows_386.zip
+02a1675fd8de126a00460942aaae242e65ca3380b5bb192e8773ef3da9073fd2  terraform-provider-null_3.1.0_windows_amd64.zip
+`
+
+// testHashicorpSignatureGoodBase64 is a signature of testProviderShaSums signed with
+// HashicorpPublicKey, which represents the SHA256SUMS.sig file downloaded for
+// an official release.
+const testHashicorpSignatureGoodBase64 = `wsFcBAABCAAQBQJgga+GCRCwtEEJdoW2dgAA` +
+	`o0YQAAW911BGDr2WHLo5NwcZenwHyxL5DX9g+4BknKbc/WxRC1hD8Afi3eygZk1yR6eT4Gp2H` +
+	`yNOwCjGL1PTONBumMfj9udIeuX8onrJMMvjFHh+bORGxBi4FKr4V3b2ZV1IYOjWMEyyTGRDvw` +
+	`SCdxBkp3apH3s2xZLmRoAj84JZ4KaxGF7hlT0j4IkNyQKd2T5cCByN9DV80+x+HtzaOieFwJL` +
+	`97iyGj6aznXfKfslK6S4oIrVTwyLTrQbxSxA0LsdUjRPHnJamL3sFOG77qUEUoXG3r61yi5vW` +
+	`V4P5gCH/+C+VkfGHqaB1s0jHYLxoTEXtwthe66MydDBPe2Hd0J12u9ppOIeK3leeb4uiixWIi` +
+	`rNdpWyjr/LU1KKWPxsDqMGYJ9TexyWkXjEpYmIEiY1Rxar8jrLh+FqVAhxRJajjgSRu5pZj50` +
+	`CNeKmmbyolLhPCmICjYYU/xKPGXSyDFqonVVyMWCSpO+8F38OmwDQHIk5AWyc8hPOAZ+g5N95` +
+	`cfUAzEqlvmNvVHQIU40Y6/Ip2HZzzFCLKQkMP1aDakYHq5w4ZO/ucjhKuoh1HDQMuMnZSu4eo` +
+	`2nMTBzYZnUxwtROrJZF1t103avbmP2QE/GaPvLIQn7o5WMV3ZcPCJ+szzzby7H2e33WIynrY/` +
+	`95ensBxh7mGFbcQ1C59b5o7viwIaaY2`
+
+// entityString function is used for logging the signing key.
+func TestEntityString(t *testing.T) {
+	var tests = []struct {
+		name     string
+		entity   *openpgp.Entity
+		expected string
+	}{
+		{
+			"nil",
+			nil,
+			"",
+		},
+		{
+			"testAuthorKeyArmor",
+			testReadArmoredEntity(t, testAuthorKeyArmor),
+			"37A6AB3BCF2C170A Terraform Testing (plugin/discovery/) <terraform+testing@hashicorp.com>",
+		},
+		{
+			"HashicorpPublicKey",
+			testReadArmoredEntity(t, HashicorpPublicKey),
+			"34365D9472D7468F HashiCorp Security (hashicorp.com/security) <security@hashicorp.com>",
+		},
+		{
+			"HashicorpPartnersKey",
+			testReadArmoredEntity(t, HashicorpPartnersKey),
+			"7D72D4268E4660FC HashiCorp Security (Terraform Partner Signing) <security+terraform@hashicorp.com>",
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			actual := entityString(tt.entity)
+			if actual != tt.expected {
+				t.Errorf("expected %s, actual %s", tt.expected, actual)
+			}
+		})
+	}
+}
+
+func testReadArmoredEntity(t *testing.T, armor string) *openpgp.Entity {
+	data := strings.NewReader(armor)
+
+	el, err := openpgp.ReadArmoredKeyRing(data)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if count := len(el); count != 1 {
+		t.Fatalf("expected 1 entity, got %d", count)
+	}
+
+	return el[0]
+}
diff --git a/v1.5.7/internal/getproviders/public_keys.go b/v1.5.7/internal/getproviders/public_keys.go
new file mode 100644
index 0000000..68a174d
--- /dev/null
+++ b/v1.5.7/internal/getproviders/public_keys.go
@@ -0,0 +1,184 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+// HashicorpPublicKey is the HashiCorp public key, also available at
+// https://www.hashicorp.com/security
+const HashicorpPublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQINBGB9+xkBEACabYZOWKmgZsHTdRDiyPJxhbuUiKX65GUWkyRMJKi/1dviVxOX
+PG6hBPtF48IFnVgxKpIb7G6NjBousAV+CuLlv5yqFKpOZEGC6sBV+Gx8Vu1CICpl
+Zm+HpQPcIzwBpN+Ar4l/exCG/f/MZq/oxGgH+TyRF3XcYDjG8dbJCpHO5nQ5Cy9h
+QIp3/Bh09kET6lk+4QlofNgHKVT2epV8iK1cXlbQe2tZtfCUtxk+pxvU0UHXp+AB
+0xc3/gIhjZp/dePmCOyQyGPJbp5bpO4UeAJ6frqhexmNlaw9Z897ltZmRLGq1p4a
+RnWL8FPkBz9SCSKXS8uNyV5oMNVn4G1obCkc106iWuKBTibffYQzq5TG8FYVJKrh
+RwWB6piacEB8hl20IIWSxIM3J9tT7CPSnk5RYYCTRHgA5OOrqZhC7JefudrP8n+M
+pxkDgNORDu7GCfAuisrf7dXYjLsxG4tu22DBJJC0c/IpRpXDnOuJN1Q5e/3VUKKW
+mypNumuQpP5lc1ZFG64TRzb1HR6oIdHfbrVQfdiQXpvdcFx+Fl57WuUraXRV6qfb
+4ZmKHX1JEwM/7tu21QE4F1dz0jroLSricZxfaCTHHWNfvGJoZ30/MZUrpSC0IfB3
+iQutxbZrwIlTBt+fGLtm3vDtwMFNWM+Rb1lrOxEQd2eijdxhvBOHtlIcswARAQAB
+tERIYXNoaUNvcnAgU2VjdXJpdHkgKGhhc2hpY29ycC5jb20vc2VjdXJpdHkpIDxz
+ZWN1cml0eUBoYXNoaWNvcnAuY29tPokCVAQTAQoAPhYhBMh0AR8KtAURDQIQVTQ2
+XZRy10aPBQJgffsZAhsDBQkJZgGABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJ
+EDQ2XZRy10aPtpcP/0PhJKiHtC1zREpRTrjGizoyk4Sl2SXpBZYhkdrG++abo6zs
+buaAG7kgWWChVXBo5E20L7dbstFK7OjVs7vAg/OLgO9dPD8n2M19rpqSbbvKYWvp
+0NSgvFTT7lbyDhtPj0/bzpkZEhmvQaDWGBsbDdb2dBHGitCXhGMpdP0BuuPWEix+
+QnUMaPwU51q9GM2guL45Tgks9EKNnpDR6ZdCeWcqo1IDmklloidxT8aKL21UOb8t
+cD+Bg8iPaAr73bW7Jh8TdcV6s6DBFub+xPJEB/0bVPmq3ZHs5B4NItroZ3r+h3ke
+VDoSOSIZLl6JtVooOJ2la9ZuMqxchO3mrXLlXxVCo6cGcSuOmOdQSz4OhQE5zBxx
+LuzA5ASIjASSeNZaRnffLIHmht17BPslgNPtm6ufyOk02P5XXwa69UCjA3RYrA2P
+QNNC+OWZ8qQLnzGldqE4MnRNAxRxV6cFNzv14ooKf7+k686LdZrP/3fQu2p3k5rY
+0xQUXKh1uwMUMtGR867ZBYaxYvwqDrg9XB7xi3N6aNyNQ+r7zI2lt65lzwG1v9hg
+FG2AHrDlBkQi/t3wiTS3JOo/GCT8BjN0nJh0lGaRFtQv2cXOQGVRW8+V/9IpqEJ1
+qQreftdBFWxvH7VJq2mSOXUJyRsoUrjkUuIivaA9Ocdipk2CkP8bpuGz7ZF4uQIN
+BGB9+xkBEACoklYsfvWRCjOwS8TOKBTfl8myuP9V9uBNbyHufzNETbhYeT33Cj0M
+GCNd9GdoaknzBQLbQVSQogA+spqVvQPz1MND18GIdtmr0BXENiZE7SRvu76jNqLp
+KxYALoK2Pc3yK0JGD30HcIIgx+lOofrVPA2dfVPTj1wXvm0rbSGA4Wd4Ng3d2AoR
+G/wZDAQ7sdZi1A9hhfugTFZwfqR3XAYCk+PUeoFrkJ0O7wngaon+6x2GJVedVPOs
+2x/XOR4l9ytFP3o+5ILhVnsK+ESVD9AQz2fhDEU6RhvzaqtHe+sQccR3oVLoGcat
+ma5rbfzH0Fhj0JtkbP7WreQf9udYgXxVJKXLQFQgel34egEGG+NlbGSPG+qHOZtY
+4uWdlDSvmo+1P95P4VG/EBteqyBbDDGDGiMs6lAMg2cULrwOsbxWjsWka8y2IN3z
+1stlIJFvW2kggU+bKnQ+sNQnclq3wzCJjeDBfucR3a5WRojDtGoJP6Fc3luUtS7V
+5TAdOx4dhaMFU9+01OoH8ZdTRiHZ1K7RFeAIslSyd4iA/xkhOhHq89F4ECQf3Bt4
+ZhGsXDTaA/VgHmf3AULbrC94O7HNqOvTWzwGiWHLfcxXQsr+ijIEQvh6rHKmJK8R
+9NMHqc3L18eMO6bqrzEHW0Xoiu9W8Yj+WuB3IKdhclT3w0pO4Pj8gQARAQABiQI8
+BBgBCgAmFiEEyHQBHwq0BRENAhBVNDZdlHLXRo8FAmB9+xkCGwwFCQlmAYAACgkQ
+NDZdlHLXRo9ZnA/7BmdpQLeTjEiXEJyW46efxlV1f6THn9U50GWcE9tebxCXgmQf
+u+Uju4hreltx6GDi/zbVVV3HCa0yaJ4JVvA4LBULJVe3ym6tXXSYaOfMdkiK6P1v
+JgfpBQ/b/mWB0yuWTUtWx18BQQwlNEQWcGe8n1lBbYsH9g7QkacRNb8tKUrUbWlQ
+QsU8wuFgly22m+Va1nO2N5C/eE/ZEHyN15jEQ+QwgQgPrK2wThcOMyNMQX/VNEr1
+Y3bI2wHfZFjotmek3d7ZfP2VjyDudnmCPQ5xjezWpKbN1kvjO3as2yhcVKfnvQI5
+P5Frj19NgMIGAp7X6pF5Csr4FX/Vw316+AFJd9Ibhfud79HAylvFydpcYbvZpScl
+7zgtgaXMCVtthe3GsG4gO7IdxxEBZ/Fm4NLnmbzCIWOsPMx/FxH06a539xFq/1E2
+1nYFjiKg8a5JFmYU/4mV9MQs4bP/3ip9byi10V+fEIfp5cEEmfNeVeW5E7J8PqG9
+t4rLJ8FR4yJgQUa2gs2SNYsjWQuwS/MJvAv4fDKlkQjQmYRAOp1SszAnyaplvri4
+ncmfDsf0r65/sd6S40g5lHH8LIbGxcOIN6kwthSTPWX89r42CbY8GzjTkaeejNKx
+v1aCrO58wAtursO1DiXCvBY7+NdafMRnoHwBk50iPqrVkNA8fv+auRyB2/G5Ag0E
+YH3+JQEQALivllTjMolxUW2OxrXb+a2Pt6vjCBsiJzrUj0Pa63U+lT9jldbCCfgP
+wDpcDuO1O05Q8k1MoYZ6HddjWnqKG7S3eqkV5c3ct3amAXp513QDKZUfIDylOmhU
+qvxjEgvGjdRjz6kECFGYr6Vnj/p6AwWv4/FBRFlrq7cnQgPynbIH4hrWvewp3Tqw
+GVgqm5RRofuAugi8iZQVlAiQZJo88yaztAQ/7VsXBiHTn61ugQ8bKdAsr8w/ZZU5
+HScHLqRolcYg0cKN91c0EbJq9k1LUC//CakPB9mhi5+aUVUGusIM8ECShUEgSTCi
+KQiJUPZ2CFbbPE9L5o9xoPCxjXoX+r7L/WyoCPTeoS3YRUMEnWKvc42Yxz3meRb+
+BmaqgbheNmzOah5nMwPupJYmHrjWPkX7oyyHxLSFw4dtoP2j6Z7GdRXKa2dUYdk2
+x3JYKocrDoPHh3Q0TAZujtpdjFi1BS8pbxYFb3hHmGSdvz7T7KcqP7ChC7k2RAKO
+GiG7QQe4NX3sSMgweYpl4OwvQOn73t5CVWYp/gIBNZGsU3Pto8g27vHeWyH9mKr4
+cSepDhw+/X8FGRNdxNfpLKm7Vc0Sm9Sof8TRFrBTqX+vIQupYHRi5QQCuYaV6OVr
+ITeegNK3So4m39d6ajCR9QxRbmjnx9UcnSYYDmIB6fpBuwT0ogNtABEBAAGJBHIE
+GAEKACYCGwIWIQTIdAEfCrQFEQ0CEFU0Nl2UctdGjwUCYH4bgAUJAeFQ2wJAwXQg
+BBkBCgAdFiEEs2y6kaLAcwxDX8KAsLRBCXaFtnYFAmB9/iUACgkQsLRBCXaFtnYX
+BhAAlxejyFXoQwyGo9U+2g9N6LUb/tNtH29RHYxy4A3/ZUY7d/FMkArmh4+dfjf0
+p9MJz98Zkps20kaYP+2YzYmaizO6OA6RIddcEXQDRCPHmLts3097mJ/skx9qLAf6
+rh9J7jWeSqWO6VW6Mlx8j9m7sm3Ae1OsjOx/m7lGZOhY4UYfY627+Jf7WQ5103Qs
+lgQ09es/vhTCx0g34SYEmMW15Tc3eCjQ21b1MeJD/V26npeakV8iCZ1kHZHawPq/
+aCCuYEcCeQOOteTWvl7HXaHMhHIx7jjOd8XX9V+UxsGz2WCIxX/j7EEEc7CAxwAN
+nWp9jXeLfxYfjrUB7XQZsGCd4EHHzUyCf7iRJL7OJ3tz5Z+rOlNjSgci+ycHEccL
+YeFAEV+Fz+sj7q4cFAferkr7imY1XEI0Ji5P8p/uRYw/n8uUf7LrLw5TzHmZsTSC
+UaiL4llRzkDC6cVhYfqQWUXDd/r385OkE4oalNNE+n+txNRx92rpvXWZ5qFYfv7E
+95fltvpXc0iOugPMzyof3lwo3Xi4WZKc1CC/jEviKTQhfn3WZukuF5lbz3V1PQfI
+xFsYe9WYQmp25XGgezjXzp89C/OIcYsVB1KJAKihgbYdHyUN4fRCmOszmOUwEAKR
+3k5j4X8V5bk08sA69NVXPn2ofxyk3YYOMYWW8ouObnXoS8QJEDQ2XZRy10aPMpsQ
+AIbwX21erVqUDMPn1uONP6o4NBEq4MwG7d+fT85rc1U0RfeKBwjucAE/iStZDQoM
+ZKWvGhFR+uoyg1LrXNKuSPB82unh2bpvj4zEnJsJadiwtShTKDsikhrfFEK3aCK8
+Zuhpiu3jxMFDhpFzlxsSwaCcGJqcdwGhWUx0ZAVD2X71UCFoOXPjF9fNnpy80YNp
+flPjj2RnOZbJyBIM0sWIVMd8F44qkTASf8K5Qb47WFN5tSpePq7OCm7s8u+lYZGK
+wR18K7VliundR+5a8XAOyUXOL5UsDaQCK4Lj4lRaeFXunXl3DJ4E+7BKzZhReJL6
+EugV5eaGonA52TWtFdB8p+79wPUeI3KcdPmQ9Ll5Zi/jBemY4bzasmgKzNeMtwWP
+fk6WgrvBwptqohw71HDymGxFUnUP7XYYjic2sVKhv9AevMGycVgwWBiWroDCQ9Ja
+btKfxHhI2p+g+rcywmBobWJbZsujTNjhtme+kNn1mhJsD3bKPjKQfAxaTskBLb0V
+wgV21891TS1Dq9kdPLwoS4XNpYg2LLB4p9hmeG3fu9+OmqwY5oKXsHiWc43dei9Y
+yxZ1AAUOIaIdPkq+YG/PhlGE4YcQZ4RPpltAr0HfGgZhmXWigbGS+66pUj+Ojysc
+j0K5tCVxVu0fhhFpOlHv0LWaxCbnkgkQH9jfMEJkAWMOuQINBGCAXCYBEADW6RNr
+ZVGNXvHVBqSiOWaxl1XOiEoiHPt50Aijt25yXbG+0kHIFSoR+1g6Lh20JTCChgfQ
+kGGjzQvEuG1HTw07YhsvLc0pkjNMfu6gJqFox/ogc53mz69OxXauzUQ/TZ27GDVp
+UBu+EhDKt1s3OtA6Bjz/csop/Um7gT0+ivHyvJ/jGdnPEZv8tNuSE/Uo+hn/Q9hg
+8SbveZzo3C+U4KcabCESEFl8Gq6aRi9vAfa65oxD5jKaIz7cy+pwb0lizqlW7H9t
+Qlr3dBfdIcdzgR55hTFC5/XrcwJ6/nHVH/xGskEasnfCQX8RYKMuy0UADJy72TkZ
+bYaCx+XXIcVB8GTOmJVoAhrTSSVLAZspfCnjwnSxisDn3ZzsYrq3cV6sU8b+QlIX
+7VAjurE+5cZiVlaxgCjyhKqlGgmonnReWOBacCgL/UvuwMmMp5TTLmiLXLT7uxeG
+ojEyoCk4sMrqrU1jevHyGlDJH9Taux15GILDwnYFfAvPF9WCid4UZ4Ouwjcaxfys
+3LxNiZIlUsXNKwS3mhiMRL4TRsbs4k4QE+LIMOsauIvcvm8/frydvQ/kUwIhVTH8
+0XGOH909bYtJvY3fudK7ShIwm7ZFTduBJUG473E/Fn3VkhTmBX6+PjOC50HR/Hyb
+waRCzfDruMe3TAcE/tSP5CUOb9C7+P+hPzQcDwARAQABiQRyBBgBCgAmFiEEyHQB
+Hwq0BRENAhBVNDZdlHLXRo8FAmCAXCYCGwIFCQlmAYACQAkQNDZdlHLXRo/BdCAE
+GQEKAB0WIQQ3TsdbSFkTYEqDHMfIIMbVzSerhwUCYIBcJgAKCRDIIMbVzSerh0Xw
+D/9ghnUsoNCu1OulcoJdHboMazJvDt/znttdQSnULBVElgM5zk0Uyv87zFBzuCyQ
+JWL3bWesQ2uFx5fRWEPDEfWVdDrjpQGb1OCCQyz1QlNPV/1M1/xhKGS9EeXrL8Dw
+F6KTGkRwn1yXiP4BGgfeFIQHmJcKXEZ9HkrpNb8mcexkROv4aIPAwn+IaE+NHVtt
+IBnufMXLyfpkWJQtJa9elh9PMLlHHnuvnYLvuAoOkhuvs7fXDMpfFZ01C+QSv1dz
+Hm52GSStERQzZ51w4c0rYDneYDniC/sQT1x3dP5Xf6wzO+EhRMabkvoTbMqPsTEP
+xyWr2pNtTBYp7pfQjsHxhJpQF0xjGN9C39z7f3gJG8IJhnPeulUqEZjhRFyVZQ6/
+siUeq7vu4+dM/JQL+i7KKe7Lp9UMrG6NLMH+ltaoD3+lVm8fdTUxS5MNPoA/I8cK
+1OWTJHkrp7V/XaY7mUtvQn5V1yET5b4bogz4nME6WLiFMd+7x73gB+YJ6MGYNuO8
+e/NFK67MfHbk1/AiPTAJ6s5uHRQIkZcBPG7y5PpfcHpIlwPYCDGYlTajZXblyKrw
+BttVnYKvKsnlysv11glSg0DphGxQJbXzWpvBNyhMNH5dffcfvd3eXJAxnD81GD2z
+ZAriMJ4Av2TfeqQ2nxd2ddn0jX4WVHtAvLXfCgLM2Gveho4jD/9sZ6PZz/rEeTvt
+h88t50qPcBa4bb25X0B5FO3TeK2LL3VKLuEp5lgdcHVonrcdqZFobN1CgGJua8TW
+SprIkh+8ATZ/FXQTi01NzLhHXT1IQzSpFaZw0gb2f5ruXwvTPpfXzQrs2omY+7s7
+fkCwGPesvpSXPKn9v8uhUwD7NGW/Dm+jUM+QtC/FqzX7+/Q+OuEPjClUh1cqopCZ
+EvAI3HjnavGrYuU6DgQdjyGT/UDbuwbCXqHxHojVVkISGzCTGpmBcQYQqhcFRedJ
+yJlu6PSXlA7+8Ajh52oiMJ3ez4xSssFgUQAyOB16432tm4erpGmCyakkoRmMUn3p
+wx+QIppxRlsHznhcCQKR3tcblUqH3vq5i4/ZAihusMCa0YrShtxfdSb13oKX+pFr
+aZXvxyZlCa5qoQQBV1sowmPL1N2j3dR9TVpdTyCFQSv4KeiExmowtLIjeCppRBEK
+eeYHJnlfkyKXPhxTVVO6H+dU4nVu0ASQZ07KiQjbI+zTpPKFLPp3/0sPRJM57r1+
+aTS71iR7nZNZ1f8LZV2OvGE6fJVtgJ1J4Nu02K54uuIhU3tg1+7Xt+IqwRc9rbVr
+pHH/hFCYBPW2D2dxB+k2pQlg5NI+TpsXj5Zun8kRw5RtVb+dLuiH/xmxArIee8Jq
+ZF5q4h4I33PSGDdSvGXn9UMY5Isjpg==
+=7pIB
+-----END PGP PUBLIC KEY BLOCK-----`
+
+// HashicorpPartnersKey is a key created by HashiCorp, used to generate and
+// verify trust signatures for Partner tier providers.
+const HashicorpPartnersKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQINBF5vdGkBEADKi3Nm83oqMcar+YSDFKBup7+/Ty7m+SldtDH4/RWT0vgVHuQ1
+0joA+TrjITR5/aBVQ1/i2pOiBiImnaWsykccjFw9f9AuJqHo520YrAbNCeA6LuGH
+Gvz4u0ReL/Cjbb9xCb34tejmrVOX+tmyiYBQd+oTae3DiyffOI9HxF6v+IKhOFKz
+Grs3/R5MDwU1ZQIXTO2bdBOM67XBwvTUC+dy6Nem5UmmwuCI0Qz/JWTGndG8aGDC
+EO9+DJ59/IwzBYlbs11iqdfqiGALNr+4FXTwftsxZOGpyxhjyAK00U2PP+gQ/wOK
+aeIOL7qpF94GdyVrZzDeMKVLUDmhXxDhyatG4UueRJVAoqNVvAFfEwavpYUrVpYl
+se/ZugCcTc9VeDodA4r4VI8yQQW805C+uZ/Q+Ym4r+xTsKcTyC4er4ogXgrMT73B
+9sgA2M1B4oGbMN5IuG/L2C9JZ1Tob0h0fX+UGMOvrpWeJkZEKTU8hm4mZwhxeRdL
+rrcqs6sewNPRnSiUlxz9ynJuf8vFNAD79Z6H9lULe6FnPuLImzH78FKH9QMQsoAW
+z1GlYDrxNs3rHDTkSmvglwmWKpsfCxUnfq4ecsYtroCDjAwhLsf2qO1WlXD8B53h
+6LU5DwPo7jJDpOv4B0YbjGuAJCf0oXmhXqdu9te6ybXb84ArtHlVO4EBRQARAQAB
+tFFIYXNoaUNvcnAgU2VjdXJpdHkgKFRlcnJhZm9ybSBQYXJ0bmVyIFNpZ25pbmcp
+IDxzZWN1cml0eSt0ZXJyYWZvcm1AaGFzaGljb3JwLmNvbT6JAk4EEwEIADgWIQRR
+iQZXxazbS4IwhlZ9ctQmjkZg/AUCXm90aQIbAwULCQgHAgYVCgkICwIEFgIDAQIe
+AQIXgAAKCRB9ctQmjkZg/LxFEACACTHlqULv38VCteo8UR4sRFcaSK4kwzXyRLI2
+oi3tnGdzc9AJ5Brp6/GwcERz0za3NU6LJ5kI7umHhuSb+FOjzQKLbttfKL+bTiNH
+HY9NyJPhr6wKJs4Mh8HJ7/FdU7Tsg0cpayNvO5ilU3Mf7H1zaWOVut8BFRYqXGKi
+K5/GGmw9C6QwaVSxR4i2kcZYUk4mnTikug53/4sQGnD3zScpDjipEqGTBMLk4r+E
+0792MZFRAYRIMmZ0NfaMoIGE7bnmtMrbqtNiw+VaPILk6EyDVK3XJxNDBY/4kwHW
+4pDa/qjD7nCL7LapP6NN8sDE++l2MSveorzjtR2yV+goqK1yV0VL2X8zwk1jANX7
+HatY6eKJwkx72BpL5N3ps915Od7kc/k7HdDgyoFQCOkuz9nHr7ix1ioltDcaEXwQ
+qTv33M21uG7muNlFsEav2yInPGmIRRqBaGg/5AjF8v1mnGOjzJKNMCIEXIpkYoPS
+fY9wud2s9DvHHvVuF+pT8YtmJDqKdGVAgv+VAH8z6zeIRaQXRRrbzFaCIozmz3qF
+RLPixaPhcw5EHB7MhWBVDnsPXJG811KjMxCrW57ldeBsbR+cEKydEpYFnSjwksGy
+FrCFPA4Vol/ks/ldotS7P9FDmYs7VfB0fco4fdyvwnxksRCfY1kg0dJA3Q0uj/uD
+MoBzF7kCDQReb3RpARAAr1uZ2iRuoFRTBiI2Ao9Mn2Nk0B+WEWT+4S6oDSuryf+6
+sKI9Z+wgSvp7DOKyNARoqv+hnjA5Z+t7y/2K7fZP4TYpqOKw8NRKIUoNH0U2/YED
+LN0FlXKuVdXtqfijoRZF/W/UyEMVRpub0yKwQDgsijoUDXIG1INVO/NSMGh5UJxE
+I+KoU+oIahNPSTgHPizqhJ5OEYkMMfvIr5eHErtB9uylqifVDlvojeHyzU46XmGw
+QLxYzufzLYoeBx9uZjZWIlxpxD2mVPmAYVJtDE0uKRZ29+fnlcxWzhx7Ow+wSVRp
+XLwDLxZh1YJseY/cGj6yzjA8NolG1fx94PRD1iF7VukHJ3LkukK3+Iw2o4JKmrFx
+FpVVcEoldb4bNRMnbY0KDOXn0/9LM+lhEnCRAo8y5zDO6kmjA56emy4iPHRBlngJ
+Egms8wnuKsgNkYG8uRaa6zC9FOY/4MbXtNPg8j3pPlWr5jQVdy053uB9UqGs7y3a
+C1z9bII58Otp8p4Hf5W97MNuXTxPgPDNmWXA6xu7k2+aut8dgvgz1msHTs31bTeG
+X4iRt23/XWlIy56Jar6NkV74rdiKevAbJRHp/sj9AIR4h0pm4yCjZSEKmMqELj7L
+nVSj0s9VSL0algqK5yXLoj6gYUWFfcuHcypnRGvjrpDzGgD9AKrDsmQ3pxFflZ8A
+EQEAAYkCNgQYAQgAIBYhBFGJBlfFrNtLgjCGVn1y1CaORmD8BQJeb3RpAhsMAAoJ
+EH1y1CaORmD89rUP/0gszqvnU3oXo1lMiwz44EfHDGWeY6sh1pJS0FfyjefIMEzE
+rAJvyWXbzRj+Dd2g7m7p5JUf/UEMO6EFdxe1l6IihHJBs+pC6hliFwlGosfJwVc2
+wtPg6okAfFI35RBedvrV3uzq01dqFlb+d85Gl24du6nOv6eBXiZ8Pr9F3zPDHLPw
+DTP/RtNDxnw8KOC0Z0TE9iQIY1rJCI2mekJ4btHRQ2q9eZQjGFp5HcHBXs/D2ZXC
+H/vwB0UskHrtduEUSeTgKkKuPuxbCU5rhE8RGprS41KLYozveD0r5BPa9kBx7qYZ
+iOHgWfwlJ4yRjgjtoZl4E9/7aGioYycHNG26UZ+ZHgwTwtDrTU+LP89WrhzoOQmq
+H0oU4P/oMe2YKnG6FgCWt8h+31Q08G5VJeXNUoOn+RG02M7HOMHYGeP5wkzAy2HY
+I4iehn+A3Cwudv8Gh6WaRqPjLGbk9GWr5fAUG3KLUgJ8iEqnt0/waP7KD78TVId8
+DgHymHMvAU+tAxi5wUcC3iQYrBEc1X0vcsRcW6aAi2Cxc/KEkVCz+PJ+HmFVZakS
+V+fniKpSnhUlDkwlG5dMGhkGp/THU3u8oDb3rSydRPcRXVe1D0AReUFE2rDOeRoT
+VYF2OtVmpc4ntcRyrItyhSkR/m7BQeBFIT8GQvbTmrCDQgrZCsFsIwxd4Cb4
+=5/s+
+-----END PGP PUBLIC KEY BLOCK-----`
diff --git a/v1.5.7/internal/getproviders/registry_client.go b/v1.5.7/internal/getproviders/registry_client.go
new file mode 100644
index 0000000..e8dabf4
--- /dev/null
+++ b/v1.5.7/internal/getproviders/registry_client.go
@@ -0,0 +1,525 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+	"crypto/sha256"
+	"encoding/hex"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"net/url"
+	"os"
+	"path"
+	"strconv"
+	"time"
+
+	"github.com/hashicorp/go-retryablehttp"
+	svchost "github.com/hashicorp/terraform-svchost"
+	svcauth "github.com/hashicorp/terraform-svchost/auth"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/httpclient"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/version"
+)
+
+const (
+	terraformVersionHeader = "X-Terraform-Version"
+
+	// registryDiscoveryRetryEnvName is the name of the environment variable that
+	// can be configured to customize number of retries for module and provider
+	// discovery requests with the remote registry.
+	registryDiscoveryRetryEnvName = "TF_REGISTRY_DISCOVERY_RETRY"
+	defaultRetry                  = 1
+
+	// registryClientTimeoutEnvName is the name of the environment variable that
+	// can be configured to customize the timeout duration (seconds) for module
+	// and provider discovery with the remote registry.
+	registryClientTimeoutEnvName = "TF_REGISTRY_CLIENT_TIMEOUT"
+
+	// defaultRequestTimeout is the default timeout duration for requests to the
+	// remote registry.
+	defaultRequestTimeout = 10 * time.Second
+)
+
+var (
+	discoveryRetry int
+	requestTimeout time.Duration
+)
+
+func init() {
+	configureDiscoveryRetry()
+	configureRequestTimeout()
+}
+
+var SupportedPluginProtocols = MustParseVersionConstraints(">= 5, <7")
+
+// registryClient is a client for the provider registry protocol that is
+// specialized only for the needs of this package. It's not intended as a
+// general registry API client.
+type registryClient struct {
+	baseURL *url.URL
+	creds   svcauth.HostCredentials
+
+	httpClient *retryablehttp.Client
+}
+
+func newRegistryClient(baseURL *url.URL, creds svcauth.HostCredentials) *registryClient {
+	httpClient := httpclient.New()
+	httpClient.Timeout = requestTimeout
+
+	retryableClient := retryablehttp.NewClient()
+	retryableClient.HTTPClient = httpClient
+	retryableClient.RetryMax = discoveryRetry
+	retryableClient.RequestLogHook = requestLogHook
+	retryableClient.ErrorHandler = maxRetryErrorHandler
+
+	retryableClient.Logger = log.New(logging.LogOutput(), "", log.Flags())
+
+	return &registryClient{
+		baseURL:    baseURL,
+		creds:      creds,
+		httpClient: retryableClient,
+	}
+}
+
+// ProviderVersions returns the raw version and protocol strings produced by the
+// registry for the given provider.
+//
+// The returned error will be ErrRegistryProviderNotKnown if the registry responds with
+// 404 Not Found to indicate that the namespace or provider type are not known,
+// ErrUnauthorized if the registry responds with 401 or 403 status codes, or
+// ErrQueryFailed for any other protocol or operational problem.
+func (c *registryClient) ProviderVersions(ctx context.Context, addr addrs.Provider) (map[string][]string, []string, error) {
+	endpointPath, err := url.Parse(path.Join(addr.Namespace, addr.Type, "versions"))
+	if err != nil {
+		// Should never happen because we're constructing this from
+		// already-validated components.
+		return nil, nil, err
+	}
+	endpointURL := c.baseURL.ResolveReference(endpointPath)
+	req, err := retryablehttp.NewRequest("GET", endpointURL.String(), nil)
+	if err != nil {
+		return nil, nil, err
+	}
+	req = req.WithContext(ctx)
+	c.addHeadersToRequest(req.Request)
+
+	resp, err := c.httpClient.Do(req)
+	if err != nil {
+		return nil, nil, c.errQueryFailed(addr, err)
+	}
+	defer resp.Body.Close()
+
+	switch resp.StatusCode {
+	case http.StatusOK:
+		// Great!
+	case http.StatusNotFound:
+		return nil, nil, ErrRegistryProviderNotKnown{
+			Provider: addr,
+		}
+	case http.StatusUnauthorized, http.StatusForbidden:
+		return nil, nil, c.errUnauthorized(addr.Hostname)
+	default:
+		return nil, nil, c.errQueryFailed(addr, errors.New(resp.Status))
+	}
+
+	// We ignore the platforms portion of the response body, because the
+	// installer verifies the platform compatibility after pulling a provider
+	// versions' metadata.
+	type ResponseBody struct {
+		Versions []struct {
+			Version   string   `json:"version"`
+			Protocols []string `json:"protocols"`
+		} `json:"versions"`
+		Warnings []string `json:"warnings"`
+	}
+	var body ResponseBody
+
+	dec := json.NewDecoder(resp.Body)
+	if err := dec.Decode(&body); err != nil {
+		return nil, nil, c.errQueryFailed(addr, err)
+	}
+
+	if len(body.Versions) == 0 {
+		return nil, body.Warnings, nil
+	}
+
+	ret := make(map[string][]string, len(body.Versions))
+	for _, v := range body.Versions {
+		ret[v.Version] = v.Protocols
+	}
+
+	return ret, body.Warnings, nil
+}
+
+// PackageMeta returns metadata about a distribution package for a provider.
+//
+// The returned error will be one of the following:
+//
+//   - ErrPlatformNotSupported if the registry responds with 404 Not Found,
+//     under the assumption that the caller previously checked that the provider
+//     and version are valid.
+//   - ErrProtocolNotSupported if the requested provider version's protocols are not
+//     supported by this version of terraform.
+//   - ErrUnauthorized if the registry responds with 401 or 403 status codes
+//   - ErrQueryFailed for any other operational problem.
+func (c *registryClient) PackageMeta(ctx context.Context, provider addrs.Provider, version Version, target Platform) (PackageMeta, error) {
+	endpointPath, err := url.Parse(path.Join(
+		provider.Namespace,
+		provider.Type,
+		version.String(),
+		"download",
+		target.OS,
+		target.Arch,
+	))
+	if err != nil {
+		// Should never happen because we're constructing this from
+		// already-validated components.
+		return PackageMeta{}, err
+	}
+	endpointURL := c.baseURL.ResolveReference(endpointPath)
+
+	req, err := retryablehttp.NewRequest("GET", endpointURL.String(), nil)
+	if err != nil {
+		return PackageMeta{}, err
+	}
+	req = req.WithContext(ctx)
+	c.addHeadersToRequest(req.Request)
+
+	resp, err := c.httpClient.Do(req)
+	if err != nil {
+		return PackageMeta{}, c.errQueryFailed(provider, err)
+	}
+	defer resp.Body.Close()
+
+	switch resp.StatusCode {
+	case http.StatusOK:
+		// Great!
+	case http.StatusNotFound:
+		return PackageMeta{}, ErrPlatformNotSupported{
+			Provider: provider,
+			Version:  version,
+			Platform: target,
+		}
+	case http.StatusUnauthorized, http.StatusForbidden:
+		return PackageMeta{}, c.errUnauthorized(provider.Hostname)
+	default:
+		return PackageMeta{}, c.errQueryFailed(provider, errors.New(resp.Status))
+	}
+
+	type SigningKeyList struct {
+		GPGPublicKeys []*SigningKey `json:"gpg_public_keys"`
+	}
+	type ResponseBody struct {
+		Protocols   []string `json:"protocols"`
+		OS          string   `json:"os"`
+		Arch        string   `json:"arch"`
+		Filename    string   `json:"filename"`
+		DownloadURL string   `json:"download_url"`
+		SHA256Sum   string   `json:"shasum"`
+
+		SHA256SumsURL          string `json:"shasums_url"`
+		SHA256SumsSignatureURL string `json:"shasums_signature_url"`
+
+		SigningKeys SigningKeyList `json:"signing_keys"`
+	}
+	var body ResponseBody
+
+	dec := json.NewDecoder(resp.Body)
+	if err := dec.Decode(&body); err != nil {
+		return PackageMeta{}, c.errQueryFailed(provider, err)
+	}
+
+	var protoVersions VersionList
+	for _, versionStr := range body.Protocols {
+		v, err := ParseVersion(versionStr)
+		if err != nil {
+			return PackageMeta{}, c.errQueryFailed(
+				provider,
+				fmt.Errorf("registry response includes invalid version string %q: %s", versionStr, err),
+			)
+		}
+		protoVersions = append(protoVersions, v)
+	}
+	protoVersions.Sort()
+
+	// Verify that this version of terraform supports the providers' protocol
+	// version(s)
+	if len(protoVersions) > 0 {
+		supportedProtos := MeetingConstraints(SupportedPluginProtocols)
+		protoErr := ErrProtocolNotSupported{
+			Provider: provider,
+			Version:  version,
+		}
+		match := false
+		for _, version := range protoVersions {
+			if supportedProtos.Has(version) {
+				match = true
+			}
+		}
+		if !match {
+			// If the protocol version is not supported, try to find the closest
+			// matching version.
+			closest, err := c.findClosestProtocolCompatibleVersion(ctx, provider, version)
+			if err != nil {
+				return PackageMeta{}, err
+			}
+			protoErr.Suggestion = closest
+			return PackageMeta{}, protoErr
+		}
+	}
+
+	if body.OS != target.OS || body.Arch != target.Arch {
+		return PackageMeta{}, fmt.Errorf("registry response to request for %s archive has incorrect target %s", target, Platform{body.OS, body.Arch})
+	}
+
+	downloadURL, err := url.Parse(body.DownloadURL)
+	if err != nil {
+		return PackageMeta{}, fmt.Errorf("registry response includes invalid download URL: %s", err)
+	}
+	downloadURL = resp.Request.URL.ResolveReference(downloadURL)
+	if downloadURL.Scheme != "http" && downloadURL.Scheme != "https" {
+		return PackageMeta{}, fmt.Errorf("registry response includes invalid download URL: must use http or https scheme")
+	}
+
+	ret := PackageMeta{
+		Provider:         provider,
+		Version:          version,
+		ProtocolVersions: protoVersions,
+		TargetPlatform: Platform{
+			OS:   body.OS,
+			Arch: body.Arch,
+		},
+		Filename: body.Filename,
+		Location: PackageHTTPURL(downloadURL.String()),
+		// "Authentication" is populated below
+	}
+
+	if len(body.SHA256Sum) != sha256.Size*2 { // *2 because it's hex-encoded
+		return PackageMeta{}, c.errQueryFailed(
+			provider,
+			fmt.Errorf("registry response includes invalid SHA256 hash %q: %s", body.SHA256Sum, err),
+		)
+	}
+
+	var checksum [sha256.Size]byte
+	_, err = hex.Decode(checksum[:], []byte(body.SHA256Sum))
+	if err != nil {
+		return PackageMeta{}, c.errQueryFailed(
+			provider,
+			fmt.Errorf("registry response includes invalid SHA256 hash %q: %s", body.SHA256Sum, err),
+		)
+	}
+
+	shasumsURL, err := url.Parse(body.SHA256SumsURL)
+	if err != nil {
+		return PackageMeta{}, fmt.Errorf("registry response includes invalid SHASUMS URL: %s", err)
+	}
+	shasumsURL = resp.Request.URL.ResolveReference(shasumsURL)
+	if shasumsURL.Scheme != "http" && shasumsURL.Scheme != "https" {
+		return PackageMeta{}, fmt.Errorf("registry response includes invalid SHASUMS URL: must use http or https scheme")
+	}
+	document, err := c.getFile(shasumsURL)
+	if err != nil {
+		return PackageMeta{}, c.errQueryFailed(
+			provider,
+			fmt.Errorf("failed to retrieve authentication checksums for provider: %s", err),
+		)
+	}
+	signatureURL, err := url.Parse(body.SHA256SumsSignatureURL)
+	if err != nil {
+		return PackageMeta{}, fmt.Errorf("registry response includes invalid SHASUMS signature URL: %s", err)
+	}
+	signatureURL = resp.Request.URL.ResolveReference(signatureURL)
+	if signatureURL.Scheme != "http" && signatureURL.Scheme != "https" {
+		return PackageMeta{}, fmt.Errorf("registry response includes invalid SHASUMS signature URL: must use http or https scheme")
+	}
+	signature, err := c.getFile(signatureURL)
+	if err != nil {
+		return PackageMeta{}, c.errQueryFailed(
+			provider,
+			fmt.Errorf("failed to retrieve cryptographic signature for provider: %s", err),
+		)
+	}
+
+	keys := make([]SigningKey, len(body.SigningKeys.GPGPublicKeys))
+	for i, key := range body.SigningKeys.GPGPublicKeys {
+		keys[i] = *key
+	}
+
+	ret.Authentication = PackageAuthenticationAll(
+		NewMatchingChecksumAuthentication(document, body.Filename, checksum),
+		NewArchiveChecksumAuthentication(ret.TargetPlatform, checksum),
+		NewSignatureAuthentication(document, signature, keys),
+	)
+
+	return ret, nil
+}
+
+// findClosestProtocolCompatibleVersion searches for the provider version with the closest protocol match.
+func (c *registryClient) findClosestProtocolCompatibleVersion(ctx context.Context, provider addrs.Provider, version Version) (Version, error) {
+	var match Version
+	available, _, err := c.ProviderVersions(ctx, provider)
+	if err != nil {
+		return UnspecifiedVersion, err
+	}
+
+	// extract the maps keys so we can make a sorted list of available versions.
+	versionList := make(VersionList, 0, len(available))
+	for versionStr := range available {
+		v, err := ParseVersion(versionStr)
+		if err != nil {
+			return UnspecifiedVersion, ErrQueryFailed{
+				Provider: provider,
+				Wrapped:  fmt.Errorf("registry response includes invalid version string %q: %s", versionStr, err),
+			}
+		}
+		versionList = append(versionList, v)
+	}
+	versionList.Sort() // lowest precedence first, preserving order when equal precedence
+
+	protoVersions := MeetingConstraints(SupportedPluginProtocols)
+FindMatch:
+	// put the versions in increasing order of precedence
+	for index := len(versionList) - 1; index >= 0; index-- { // walk backwards to consider newer versions first
+		for _, protoStr := range available[versionList[index].String()] {
+			p, err := ParseVersion(protoStr)
+			if err != nil {
+				return UnspecifiedVersion, ErrQueryFailed{
+					Provider: provider,
+					Wrapped:  fmt.Errorf("registry response includes invalid protocol string %q: %s", protoStr, err),
+				}
+			}
+			if protoVersions.Has(p) {
+				match = versionList[index]
+				break FindMatch
+			}
+		}
+	}
+	return match, nil
+}
+
+func (c *registryClient) addHeadersToRequest(req *http.Request) {
+	if c.creds != nil {
+		c.creds.PrepareRequest(req)
+	}
+	req.Header.Set(terraformVersionHeader, version.String())
+}
+
+func (c *registryClient) errQueryFailed(provider addrs.Provider, err error) error {
+	if err == context.Canceled {
+		// This one has a special error type so that callers can
+		// handle it in a different way.
+		return ErrRequestCanceled{}
+	}
+	return ErrQueryFailed{
+		Provider: provider,
+		Wrapped:  err,
+	}
+}
+
+func (c *registryClient) errUnauthorized(hostname svchost.Hostname) error {
+	return ErrUnauthorized{
+		Hostname:        hostname,
+		HaveCredentials: c.creds != nil,
+	}
+}
+
+func (c *registryClient) getFile(url *url.URL) ([]byte, error) {
+	resp, err := c.httpClient.Get(url.String())
+	if err != nil {
+		return nil, err
+	}
+	defer resp.Body.Close()
+
+	if resp.StatusCode != http.StatusOK {
+		return nil, fmt.Errorf("%s returned from %s", resp.Status, HostFromRequest(resp.Request))
+	}
+
+	data, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return data, err
+	}
+
+	return data, nil
+}
+
+// configureDiscoveryRetry configures the number of retries the registry client
+// will attempt for requests with retryable errors, like 502 status codes
+func configureDiscoveryRetry() {
+	discoveryRetry = defaultRetry
+
+	if v := os.Getenv(registryDiscoveryRetryEnvName); v != "" {
+		retry, err := strconv.Atoi(v)
+		if err == nil && retry > 0 {
+			discoveryRetry = retry
+		}
+	}
+}
+
+func requestLogHook(logger retryablehttp.Logger, req *http.Request, i int) {
+	if i > 0 {
+		logger.Printf("[INFO] Previous request to the remote registry failed, attempting retry.")
+	}
+}
+
+func maxRetryErrorHandler(resp *http.Response, err error, numTries int) (*http.Response, error) {
+	// Close the body per library instructions
+	if resp != nil {
+		resp.Body.Close()
+	}
+
+	// Additional error detail: if we have a response, use the status code;
+	// if we have an error, use that; otherwise nothing. We will never have
+	// both response and error.
+	var errMsg string
+	if resp != nil {
+		errMsg = fmt.Sprintf(": %s returned from %s", resp.Status, HostFromRequest(resp.Request))
+	} else if err != nil {
+		errMsg = fmt.Sprintf(": %s", err)
+	}
+
+	// This function is always called with numTries=RetryMax+1. If we made any
+	// retry attempts, include that in the error message.
+	if numTries > 1 {
+		return resp, fmt.Errorf("the request failed after %d attempts, please try again later%s",
+			numTries, errMsg)
+	}
+	return resp, fmt.Errorf("the request failed, please try again later%s", errMsg)
+}
+
+// HostFromRequest extracts host the same way net/http Request.Write would,
+// accounting for empty Request.Host
+func HostFromRequest(req *http.Request) string {
+	if req.Host != "" {
+		return req.Host
+	}
+	if req.URL != nil {
+		return req.URL.Host
+	}
+
+	// this should never happen and if it does
+	// it will be handled as part of Request.Write()
+	// https://cs.opensource.google/go/go/+/refs/tags/go1.18.4:src/net/http/request.go;l=574
+	return ""
+}
+
+// configureRequestTimeout configures the registry client request timeout from
+// environment variables
+func configureRequestTimeout() {
+	requestTimeout = defaultRequestTimeout
+
+	if v := os.Getenv(registryClientTimeoutEnvName); v != "" {
+		timeout, err := strconv.Atoi(v)
+		if err == nil && timeout > 0 {
+			requestTimeout = time.Duration(timeout) * time.Second
+		}
+	}
+}
diff --git a/v1.5.7/internal/getproviders/registry_client_test.go b/v1.5.7/internal/getproviders/registry_client_test.go
new file mode 100644
index 0000000..8741c02
--- /dev/null
+++ b/v1.5.7/internal/getproviders/registry_client_test.go
@@ -0,0 +1,459 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"log"
+	"net/http"
+	"net/http/httptest"
+	"os"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/apparentlymart/go-versions/versions"
+	"github.com/google/go-cmp/cmp"
+	svchost "github.com/hashicorp/terraform-svchost"
+	disco "github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestConfigureDiscoveryRetry(t *testing.T) {
+	t.Run("default retry", func(t *testing.T) {
+		if discoveryRetry != defaultRetry {
+			t.Fatalf("expected retry %q, got %q", defaultRetry, discoveryRetry)
+		}
+
+		rc := newRegistryClient(nil, nil)
+		if rc.httpClient.RetryMax != defaultRetry {
+			t.Fatalf("expected client retry %q, got %q",
+				defaultRetry, rc.httpClient.RetryMax)
+		}
+	})
+
+	t.Run("configured retry", func(t *testing.T) {
+		defer func(retryEnv string) {
+			os.Setenv(registryDiscoveryRetryEnvName, retryEnv)
+			discoveryRetry = defaultRetry
+		}(os.Getenv(registryDiscoveryRetryEnvName))
+		os.Setenv(registryDiscoveryRetryEnvName, "2")
+
+		configureDiscoveryRetry()
+		expected := 2
+		if discoveryRetry != expected {
+			t.Fatalf("expected retry %q, got %q",
+				expected, discoveryRetry)
+		}
+
+		rc := newRegistryClient(nil, nil)
+		if rc.httpClient.RetryMax != expected {
+			t.Fatalf("expected client retry %q, got %q",
+				expected, rc.httpClient.RetryMax)
+		}
+	})
+}
+
+func TestConfigureRegistryClientTimeout(t *testing.T) {
+	t.Run("default timeout", func(t *testing.T) {
+		if requestTimeout != defaultRequestTimeout {
+			t.Fatalf("expected timeout %q, got %q",
+				defaultRequestTimeout.String(), requestTimeout.String())
+		}
+
+		rc := newRegistryClient(nil, nil)
+		if rc.httpClient.HTTPClient.Timeout != defaultRequestTimeout {
+			t.Fatalf("expected client timeout %q, got %q",
+				defaultRequestTimeout.String(), rc.httpClient.HTTPClient.Timeout.String())
+		}
+	})
+
+	t.Run("configured timeout", func(t *testing.T) {
+		defer func(timeoutEnv string) {
+			os.Setenv(registryClientTimeoutEnvName, timeoutEnv)
+			requestTimeout = defaultRequestTimeout
+		}(os.Getenv(registryClientTimeoutEnvName))
+		os.Setenv(registryClientTimeoutEnvName, "20")
+
+		configureRequestTimeout()
+		expected := 20 * time.Second
+		if requestTimeout != expected {
+			t.Fatalf("expected timeout %q, got %q",
+				expected, requestTimeout.String())
+		}
+
+		rc := newRegistryClient(nil, nil)
+		if rc.httpClient.HTTPClient.Timeout != expected {
+			t.Fatalf("expected client timeout %q, got %q",
+				expected, rc.httpClient.HTTPClient.Timeout.String())
+		}
+	})
+}
+
+// testRegistryServices starts up a local HTTP server running a fake provider registry
+// service and returns a service discovery object pre-configured to consider
+// the host "example.com" to be served by the fake registry service.
+//
+// The returned discovery object also knows the hostname "not.example.com"
+// which does not have a provider registry at all and "too-new.example.com"
+// which has a "providers.v99" service that is inoperable but could be useful
+// to test the error reporting for detecting an unsupported protocol version.
+// It also knows fails.example.com but it refers to an endpoint that doesn't
+// correctly speak HTTP, to simulate a protocol error.
+//
+// The second return value is a function to call at the end of a test function
+// to shut down the test server. After you call that function, the discovery
+// object becomes useless.
+func testRegistryServices(t *testing.T) (services *disco.Disco, baseURL string, cleanup func()) {
+	server := httptest.NewServer(http.HandlerFunc(fakeRegistryHandler))
+
+	services = disco.New()
+	services.ForceHostServices(svchost.Hostname("example.com"), map[string]interface{}{
+		"providers.v1": server.URL + "/providers/v1/",
+	})
+	services.ForceHostServices(svchost.Hostname("not.example.com"), map[string]interface{}{})
+	services.ForceHostServices(svchost.Hostname("too-new.example.com"), map[string]interface{}{
+		// This service doesn't actually work; it's here only to be
+		// detected as "too new" by the discovery logic.
+		"providers.v99": server.URL + "/providers/v99/",
+	})
+	services.ForceHostServices(svchost.Hostname("fails.example.com"), map[string]interface{}{
+		"providers.v1": server.URL + "/fails-immediately/",
+	})
+
+	// We'll also permit registry.terraform.io here just because it's our
+	// default and has some unique features that are not allowed on any other
+	// hostname. It behaves the same as example.com, which should be preferred
+	// if you're not testing something specific to the default registry in order
+	// to ensure that most things are hostname-agnostic.
+	services.ForceHostServices(svchost.Hostname("registry.terraform.io"), map[string]interface{}{
+		"providers.v1": server.URL + "/providers/v1/",
+	})
+
+	return services, server.URL, func() {
+		server.Close()
+	}
+}
+
+// testRegistrySource is a wrapper around testServices that uses the created
+// discovery object to produce a Source instance that is ready to use with the
+// fake registry services.
+//
+// As with testServices, the second return value is a function to call at the end
+// of your test in order to shut down the test server.
+func testRegistrySource(t *testing.T) (source *RegistrySource, baseURL string, cleanup func()) {
+	services, baseURL, close := testRegistryServices(t)
+	source = NewRegistrySource(services)
+	return source, baseURL, close
+}
+
+func fakeRegistryHandler(resp http.ResponseWriter, req *http.Request) {
+	path := req.URL.EscapedPath()
+	if strings.HasPrefix(path, "/fails-immediately/") {
+		// Here we take over the socket and just close it immediately, to
+		// simulate one possible way a server might not be an HTTP server.
+		hijacker, ok := resp.(http.Hijacker)
+		if !ok {
+			// Not hijackable, so we'll just fail normally.
+			// If this happens, tests relying on this will fail.
+			resp.WriteHeader(500)
+			resp.Write([]byte(`cannot hijack`))
+			return
+		}
+		conn, _, err := hijacker.Hijack()
+		if err != nil {
+			resp.WriteHeader(500)
+			resp.Write([]byte(`hijack failed`))
+			return
+		}
+		conn.Close()
+		return
+	}
+
+	if strings.HasPrefix(path, "/pkg/") {
+		switch path {
+		case "/pkg/awesomesauce/happycloud_1.2.0.zip":
+			resp.Write([]byte("some zip file"))
+		case "/pkg/awesomesauce/happycloud_1.2.0_SHA256SUMS":
+			resp.Write([]byte("000000000000000000000000000000000000000000000000000000000000f00d happycloud_1.2.0.zip\n000000000000000000000000000000000000000000000000000000000000face happycloud_1.2.0_face.zip\n"))
+		case "/pkg/awesomesauce/happycloud_1.2.0_SHA256SUMS.sig":
+			resp.Write([]byte("GPG signature"))
+		default:
+			resp.WriteHeader(404)
+			resp.Write([]byte("unknown package file download"))
+		}
+		return
+	}
+
+	if !strings.HasPrefix(path, "/providers/v1/") {
+		resp.WriteHeader(404)
+		resp.Write([]byte(`not a provider registry endpoint`))
+		return
+	}
+
+	pathParts := strings.Split(path, "/")[3:]
+	if len(pathParts) < 3 {
+		resp.WriteHeader(404)
+		resp.Write([]byte(`unexpected number of path parts`))
+		return
+	}
+	log.Printf("[TRACE] fake provider registry request for %#v", pathParts)
+
+	if pathParts[2] == "versions" {
+		if len(pathParts) != 3 {
+			resp.WriteHeader(404)
+			resp.Write([]byte(`extraneous path parts`))
+			return
+		}
+
+		switch pathParts[0] + "/" + pathParts[1] {
+		case "awesomesauce/happycloud":
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			// Note that these version numbers are intentionally misordered
+			// so we can test that the client-side code places them in the
+			// correct order (lowest precedence first).
+			resp.Write([]byte(`{"versions":[{"version":"0.1.0","protocols":["1.0"]},{"version":"2.0.0","protocols":["99.0"]},{"version":"1.2.0","protocols":["5.0"]}, {"version":"1.0.0","protocols":["5.0"]}]}`))
+		case "weaksauce/unsupported-protocol":
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			resp.Write([]byte(`{"versions":[{"version":"1.0.0","protocols":["0.1"]}]}`))
+		case "weaksauce/protocol-six":
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			resp.Write([]byte(`{"versions":[{"version":"1.0.0","protocols":["6.0"]}]}`))
+		case "weaksauce/no-versions":
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			resp.Write([]byte(`{"versions":[],"warnings":["this provider is weaksauce"]}`))
+		case "-/legacy":
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			// This response is used for testing LookupLegacyProvider
+			resp.Write([]byte(`{"id":"legacycorp/legacy"}`))
+		case "-/moved":
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			// This response is used for testing LookupLegacyProvider
+			resp.Write([]byte(`{"id":"hashicorp/moved","moved_to":"acme/moved"}`))
+		case "-/changetype":
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			// This (unrealistic) response is used for error handling code coverage
+			resp.Write([]byte(`{"id":"legacycorp/newtype"}`))
+		case "-/invalid":
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			// This (unrealistic) response is used for error handling code coverage
+			resp.Write([]byte(`{"id":"some/invalid/id/string"}`))
+		default:
+			resp.WriteHeader(404)
+			resp.Write([]byte(`unknown namespace or provider type`))
+		}
+		return
+	}
+
+	if len(pathParts) == 6 && pathParts[3] == "download" {
+		switch pathParts[0] + "/" + pathParts[1] {
+		case "awesomesauce/happycloud":
+			if pathParts[4] == "nonexist" {
+				resp.WriteHeader(404)
+				resp.Write([]byte(`unsupported OS`))
+				return
+			}
+			var protocols []string
+			version := pathParts[2]
+			switch version {
+			case "0.1.0":
+				protocols = []string{"1.0"}
+			case "2.0.0":
+				protocols = []string{"99.0"}
+			default:
+				protocols = []string{"5.0"}
+			}
+
+			body := map[string]interface{}{
+				"protocols":             protocols,
+				"os":                    pathParts[4],
+				"arch":                  pathParts[5],
+				"filename":              "happycloud_" + version + ".zip",
+				"shasum":                "000000000000000000000000000000000000000000000000000000000000f00d",
+				"download_url":          "/pkg/awesomesauce/happycloud_" + version + ".zip",
+				"shasums_url":           "/pkg/awesomesauce/happycloud_" + version + "_SHA256SUMS",
+				"shasums_signature_url": "/pkg/awesomesauce/happycloud_" + version + "_SHA256SUMS.sig",
+				"signing_keys": map[string]interface{}{
+					"gpg_public_keys": []map[string]interface{}{
+						{
+							"ascii_armor": HashicorpPublicKey,
+						},
+					},
+				},
+			}
+			enc, err := json.Marshal(body)
+			if err != nil {
+				resp.WriteHeader(500)
+				resp.Write([]byte("failed to encode body"))
+			}
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			resp.Write(enc)
+		default:
+			resp.WriteHeader(404)
+			resp.Write([]byte(`unknown namespace/provider/version/architecture`))
+		}
+		return
+	}
+
+	resp.WriteHeader(404)
+	resp.Write([]byte(`unrecognized path scheme`))
+}
+
+func TestProviderVersions(t *testing.T) {
+	source, _, close := testRegistrySource(t)
+	defer close()
+
+	tests := []struct {
+		provider     addrs.Provider
+		wantVersions map[string][]string
+		wantErr      string
+	}{
+		{
+			addrs.MustParseProviderSourceString("example.com/awesomesauce/happycloud"),
+			map[string][]string{
+				"0.1.0": {"1.0"},
+				"1.0.0": {"5.0"},
+				"1.2.0": {"5.0"},
+				"2.0.0": {"99.0"},
+			},
+			``,
+		},
+		{
+			addrs.MustParseProviderSourceString("example.com/weaksauce/no-versions"),
+			nil,
+			``,
+		},
+		{
+			addrs.MustParseProviderSourceString("example.com/nonexist/nonexist"),
+			nil,
+			`provider registry example.com does not have a provider named example.com/nonexist/nonexist`,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.provider.String(), func(t *testing.T) {
+			client, err := source.registryClient(test.provider.Hostname)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			gotVersions, _, err := client.ProviderVersions(context.Background(), test.provider)
+
+			if err != nil {
+				if test.wantErr == "" {
+					t.Fatalf("wrong error\ngot:  %s\nwant: <nil>", err.Error())
+				}
+				if got, want := err.Error(), test.wantErr; got != want {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			}
+
+			if test.wantErr != "" {
+				t.Fatalf("wrong error\ngot:  <nil>\nwant: %s", test.wantErr)
+			}
+
+			if diff := cmp.Diff(test.wantVersions, gotVersions); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestFindClosestProtocolCompatibleVersion(t *testing.T) {
+	source, _, close := testRegistrySource(t)
+	defer close()
+
+	tests := map[string]struct {
+		provider       addrs.Provider
+		version        Version
+		wantSuggestion Version
+		wantErr        string
+	}{
+		"pinned version too old": {
+			addrs.MustParseProviderSourceString("example.com/awesomesauce/happycloud"),
+			MustParseVersion("0.1.0"),
+			MustParseVersion("1.2.0"),
+			``,
+		},
+		"pinned version too new": {
+			addrs.MustParseProviderSourceString("example.com/awesomesauce/happycloud"),
+			MustParseVersion("2.0.0"),
+			MustParseVersion("1.2.0"),
+			``,
+		},
+		// This should not actually happen, the function is only meant to be
+		// called when the requested provider version is not supported
+		"pinned version just right": {
+			addrs.MustParseProviderSourceString("example.com/awesomesauce/happycloud"),
+			MustParseVersion("1.2.0"),
+			MustParseVersion("1.2.0"),
+			``,
+		},
+		"nonexisting provider": {
+			addrs.MustParseProviderSourceString("example.com/nonexist/nonexist"),
+			MustParseVersion("1.2.0"),
+			versions.Unspecified,
+			`provider registry example.com does not have a provider named example.com/nonexist/nonexist`,
+		},
+		"versionless provider": {
+			addrs.MustParseProviderSourceString("example.com/weaksauce/no-versions"),
+			MustParseVersion("1.2.0"),
+			versions.Unspecified,
+			``,
+		},
+		"unsupported provider protocol": {
+			addrs.MustParseProviderSourceString("example.com/weaksauce/unsupported-protocol"),
+			MustParseVersion("1.0.0"),
+			versions.Unspecified,
+			``,
+		},
+		"provider protocol six": {
+			addrs.MustParseProviderSourceString("example.com/weaksauce/protocol-six"),
+			MustParseVersion("1.0.0"),
+			MustParseVersion("1.0.0"),
+			``,
+		},
+	}
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			client, err := source.registryClient(test.provider.Hostname)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			got, err := client.findClosestProtocolCompatibleVersion(context.Background(), test.provider, test.version)
+
+			if err != nil {
+				if test.wantErr == "" {
+					t.Fatalf("wrong error\ngot:  %s\nwant: <nil>", err.Error())
+				}
+				if got, want := err.Error(), test.wantErr; got != want {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			}
+
+			if test.wantErr != "" {
+				t.Fatalf("wrong error\ngot:  <nil>\nwant: %s", test.wantErr)
+			}
+
+			fmt.Printf("Got: %s, Want: %s\n", got, test.wantSuggestion)
+
+			if !got.Same(test.wantSuggestion) {
+				t.Fatalf("wrong result\ngot:  %s\nwant: %s", got.String(), test.wantSuggestion.String())
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/getproviders/registry_source.go b/v1.5.7/internal/getproviders/registry_source.go
new file mode 100644
index 0000000..e0db7c5
--- /dev/null
+++ b/v1.5.7/internal/getproviders/registry_source.go
@@ -0,0 +1,153 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+	"fmt"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+	disco "github.com/hashicorp/terraform-svchost/disco"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// RegistrySource is a Source that knows how to find and install providers from
+// their originating provider registries.
+type RegistrySource struct {
+	services *disco.Disco
+}
+
+var _ Source = (*RegistrySource)(nil)
+
+// NewRegistrySource creates and returns a new source that will install
+// providers from their originating provider registries.
+func NewRegistrySource(services *disco.Disco) *RegistrySource {
+	return &RegistrySource{
+		services: services,
+	}
+}
+
+// AvailableVersions returns all of the versions available for the provider
+// with the given address, or an error if that result cannot be determined.
+//
+// If the request fails, the returned error might be an value of
+// ErrHostNoProviders, ErrHostUnreachable, ErrUnauthenticated,
+// ErrProviderNotKnown, or ErrQueryFailed. Callers must be defensive and
+// expect errors of other types too, to allow for future expansion.
+func (s *RegistrySource) AvailableVersions(ctx context.Context, provider addrs.Provider) (VersionList, Warnings, error) {
+	client, err := s.registryClient(provider.Hostname)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	versionsResponse, warnings, err := client.ProviderVersions(ctx, provider)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	if len(versionsResponse) == 0 {
+		return nil, warnings, nil
+	}
+
+	// We ignore protocols here because our goal is to find out which versions
+	// are available _at all_. Which ones are compatible with the current
+	// Terraform becomes relevant only once we've selected one, at which point
+	// we'll return an error if the selected one is incompatible.
+	//
+	// We intentionally produce an error on incompatibility, rather than
+	// silently ignoring an incompatible version, in order to give the user
+	// explicit feedback about why their selection wasn't valid and allow them
+	// to decide whether to fix that by changing the selection or by some other
+	// action such as upgrading Terraform, using a different OS to run
+	// Terraform, etc. Changes that affect compatibility are considered breaking
+	// changes from a provider API standpoint, so provider teams should change
+	// compatibility only in new major versions.
+	ret := make(VersionList, 0, len(versionsResponse))
+	for str := range versionsResponse {
+		v, err := ParseVersion(str)
+		if err != nil {
+			return nil, nil, ErrQueryFailed{
+				Provider: provider,
+				Wrapped:  fmt.Errorf("registry response includes invalid version string %q: %s", str, err),
+			}
+		}
+		ret = append(ret, v)
+	}
+	ret.Sort() // lowest precedence first, preserving order when equal precedence
+	return ret, warnings, nil
+}
+
+// PackageMeta returns metadata about the location and capabilities of
+// a distribution package for a particular provider at a particular version
+// targeting a particular platform.
+//
+// Callers of PackageMeta should first call AvailableVersions and pass
+// one of the resulting versions to this function. This function cannot
+// distinguish between a version that is not available and an unsupported
+// target platform, so if it encounters either case it will return an error
+// suggesting that the target platform isn't supported under the assumption
+// that the caller already checked that the version is available at all.
+//
+// To find a package suitable for the platform where the provider installation
+// process is running, set the "target" argument to
+// getproviders.CurrentPlatform.
+//
+// If the request fails, the returned error might be an value of
+// ErrHostNoProviders, ErrHostUnreachable, ErrUnauthenticated,
+// ErrPlatformNotSupported, or ErrQueryFailed. Callers must be defensive and
+// expect errors of other types too, to allow for future expansion.
+func (s *RegistrySource) PackageMeta(ctx context.Context, provider addrs.Provider, version Version, target Platform) (PackageMeta, error) {
+	client, err := s.registryClient(provider.Hostname)
+	if err != nil {
+		return PackageMeta{}, err
+	}
+
+	return client.PackageMeta(ctx, provider, version, target)
+}
+
+func (s *RegistrySource) registryClient(hostname svchost.Hostname) (*registryClient, error) {
+	host, err := s.services.Discover(hostname)
+	if err != nil {
+		return nil, ErrHostUnreachable{
+			Hostname: hostname,
+			Wrapped:  err,
+		}
+	}
+
+	url, err := host.ServiceURL("providers.v1")
+	switch err := err.(type) {
+	case nil:
+		// okay! We'll fall through and return below.
+	case *disco.ErrServiceNotProvided:
+		return nil, ErrHostNoProviders{
+			Hostname: hostname,
+		}
+	case *disco.ErrVersionNotSupported:
+		return nil, ErrHostNoProviders{
+			Hostname:        hostname,
+			HasOtherVersion: true,
+		}
+	default:
+		return nil, ErrHostUnreachable{
+			Hostname: hostname,
+			Wrapped:  err,
+		}
+	}
+
+	// Check if we have credentials configured for this hostname.
+	creds, err := s.services.CredentialsForHost(hostname)
+	if err != nil {
+		// This indicates that a credentials helper failed, which means we
+		// can't do anything better than just pass through the helper's
+		// own error message.
+		return nil, fmt.Errorf("failed to retrieve credentials for %s: %s", hostname, err)
+	}
+
+	return newRegistryClient(url, creds), nil
+}
+
+func (s *RegistrySource) ForDisplay(provider addrs.Provider) string {
+	return fmt.Sprintf("registry %s", provider.Hostname.ForDisplay())
+}
diff --git a/v1.5.7/internal/getproviders/registry_source_test.go b/v1.5.7/internal/getproviders/registry_source_test.go
new file mode 100644
index 0000000..d88ca34
--- /dev/null
+++ b/v1.5.7/internal/getproviders/registry_source_test.go
@@ -0,0 +1,242 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+	"fmt"
+	"regexp"
+	"strings"
+	"testing"
+
+	"github.com/apparentlymart/go-versions/versions"
+	"github.com/google/go-cmp/cmp"
+	svchost "github.com/hashicorp/terraform-svchost"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestSourceAvailableVersions(t *testing.T) {
+	source, baseURL, close := testRegistrySource(t)
+	defer close()
+
+	tests := []struct {
+		provider     string
+		wantVersions []string
+		wantErr      string
+	}{
+		// These test cases are relying on behaviors of the fake provider
+		// registry server implemented in registry_client_test.go.
+		{
+			"example.com/awesomesauce/happycloud",
+			[]string{"0.1.0", "1.0.0", "1.2.0", "2.0.0"},
+			``,
+		},
+		{
+			"example.com/weaksauce/no-versions",
+			nil,
+			``, // having no versions is not an error, it's just odd
+		},
+		{
+			"example.com/nonexist/nonexist",
+			nil,
+			`provider registry example.com does not have a provider named example.com/nonexist/nonexist`,
+		},
+		{
+			"not.example.com/foo/bar",
+			nil,
+			`host not.example.com does not offer a Terraform provider registry`,
+		},
+		{
+			"too-new.example.com/foo/bar",
+			nil,
+			`host too-new.example.com does not support the provider registry protocol required by this Terraform version, but may be compatible with a different Terraform version`,
+		},
+		{
+			"fails.example.com/foo/bar",
+			nil,
+			`could not query provider registry for fails.example.com/foo/bar: the request failed after 2 attempts, please try again later: Get "` + baseURL + `/fails-immediately/foo/bar/versions": EOF`,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.provider, func(t *testing.T) {
+			provider := addrs.MustParseProviderSourceString(test.provider)
+			gotVersions, _, err := source.AvailableVersions(context.Background(), provider)
+
+			if err != nil {
+				if test.wantErr == "" {
+					t.Fatalf("wrong error\ngot:  %s\nwant: <nil>", err.Error())
+				}
+				if got, want := err.Error(), test.wantErr; got != want {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			}
+
+			if test.wantErr != "" {
+				t.Fatalf("wrong error\ngot:  <nil>\nwant: %s", test.wantErr)
+			}
+
+			var gotVersionsStr []string
+			if gotVersions != nil {
+				gotVersionsStr = make([]string, len(gotVersions))
+				for i, v := range gotVersions {
+					gotVersionsStr[i] = v.String()
+				}
+			}
+
+			if diff := cmp.Diff(test.wantVersions, gotVersionsStr); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestSourceAvailableVersions_warnings(t *testing.T) {
+	source, _, close := testRegistrySource(t)
+	defer close()
+
+	provider := addrs.MustParseProviderSourceString("example.com/weaksauce/no-versions")
+	_, warnings, err := source.AvailableVersions(context.Background(), provider)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err.Error())
+	}
+
+	if len(warnings) != 1 {
+		t.Fatalf("wrong number of warnings. Expected 1, got %d", len(warnings))
+	}
+
+}
+
+func TestSourcePackageMeta(t *testing.T) {
+	source, baseURL, close := testRegistrySource(t)
+	defer close()
+
+	tests := []struct {
+		provider   string
+		version    string
+		os, arch   string
+		want       PackageMeta
+		wantHashes []Hash
+		wantErr    string
+	}{
+		// These test cases are relying on behaviors of the fake provider
+		// registry server implemented in registry_client_test.go.
+		{
+			"example.com/awesomesauce/happycloud",
+			"1.2.0",
+			"linux", "amd64",
+			PackageMeta{
+				Provider: addrs.NewProvider(
+					svchost.Hostname("example.com"), "awesomesauce", "happycloud",
+				),
+				Version:          versions.MustParseVersion("1.2.0"),
+				ProtocolVersions: VersionList{versions.MustParseVersion("5.0.0")},
+				TargetPlatform:   Platform{"linux", "amd64"},
+				Filename:         "happycloud_1.2.0.zip",
+				Location:         PackageHTTPURL(baseURL + "/pkg/awesomesauce/happycloud_1.2.0.zip"),
+				Authentication: PackageAuthenticationAll(
+					NewMatchingChecksumAuthentication(
+						[]byte("000000000000000000000000000000000000000000000000000000000000f00d happycloud_1.2.0.zip\n000000000000000000000000000000000000000000000000000000000000face happycloud_1.2.0_face.zip\n"),
+						"happycloud_1.2.0.zip",
+						[32]byte{30: 0xf0, 31: 0x0d},
+					),
+					NewArchiveChecksumAuthentication(Platform{"linux", "amd64"}, [32]byte{30: 0xf0, 31: 0x0d}),
+					NewSignatureAuthentication(
+						[]byte("000000000000000000000000000000000000000000000000000000000000f00d happycloud_1.2.0.zip\n000000000000000000000000000000000000000000000000000000000000face happycloud_1.2.0_face.zip\n"),
+						[]byte("GPG signature"),
+						[]SigningKey{
+							{ASCIIArmor: HashicorpPublicKey},
+						},
+					),
+				),
+			},
+			[]Hash{
+				"zh:000000000000000000000000000000000000000000000000000000000000f00d",
+				"zh:000000000000000000000000000000000000000000000000000000000000face",
+			},
+			``,
+		},
+		{
+			"example.com/awesomesauce/happycloud",
+			"1.2.0",
+			"nonexist", "amd64",
+			PackageMeta{},
+			nil,
+			`provider example.com/awesomesauce/happycloud 1.2.0 is not available for nonexist_amd64`,
+		},
+		{
+			"not.example.com/awesomesauce/happycloud",
+			"1.2.0",
+			"linux", "amd64",
+			PackageMeta{},
+			nil,
+			`host not.example.com does not offer a Terraform provider registry`,
+		},
+		{
+			"too-new.example.com/awesomesauce/happycloud",
+			"1.2.0",
+			"linux", "amd64",
+			PackageMeta{},
+			nil,
+			`host too-new.example.com does not support the provider registry protocol required by this Terraform version, but may be compatible with a different Terraform version`,
+		},
+		{
+			"fails.example.com/awesomesauce/happycloud",
+			"1.2.0",
+			"linux", "amd64",
+			PackageMeta{},
+			nil,
+			`could not query provider registry for fails.example.com/awesomesauce/happycloud: the request failed after 2 attempts, please try again later: Get "http://placeholder-origin/fails-immediately/awesomesauce/happycloud/1.2.0/download/linux/amd64": EOF`,
+		},
+	}
+
+	// Sometimes error messages contain specific HTTP endpoint URLs, but
+	// since our test server is on a random port we'd not be able to
+	// consistently match those. Instead, we'll normalize the URLs.
+	urlPattern := regexp.MustCompile(`http://[^/]+/`)
+
+	cmpOpts := cmp.Comparer(Version.Same)
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%s for %s_%s", test.provider, test.os, test.arch), func(t *testing.T) {
+			// TEMP: We don't yet have a function for parsing provider
+			// source addresses so we'll just fake it in here for now.
+			parts := strings.Split(test.provider, "/")
+			providerAddr := addrs.Provider{
+				Hostname:  svchost.Hostname(parts[0]),
+				Namespace: parts[1],
+				Type:      parts[2],
+			}
+
+			version := versions.MustParseVersion(test.version)
+
+			got, err := source.PackageMeta(context.Background(), providerAddr, version, Platform{test.os, test.arch})
+
+			if err != nil {
+				if test.wantErr == "" {
+					t.Fatalf("wrong error\ngot:  %s\nwant: <nil>", err.Error())
+				}
+				gotErr := urlPattern.ReplaceAllLiteralString(err.Error(), "http://placeholder-origin/")
+				if got, want := gotErr, test.wantErr; got != want {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			}
+
+			if test.wantErr != "" {
+				t.Fatalf("wrong error\ngot:  <nil>\nwant: %s", test.wantErr)
+			}
+
+			if diff := cmp.Diff(test.want, got, cmpOpts); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+			if diff := cmp.Diff(test.wantHashes, got.AcceptableHashes()); diff != "" {
+				t.Errorf("wrong AcceptableHashes result\n%s", diff)
+			}
+		})
+	}
+
+}
diff --git a/v1.5.7/internal/getproviders/source.go b/v1.5.7/internal/getproviders/source.go
new file mode 100644
index 0000000..af6a6de
--- /dev/null
+++ b/v1.5.7/internal/getproviders/source.go
@@ -0,0 +1,18 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// A Source can query a particular source for information about providers
+// that are available to install.
+type Source interface {
+	AvailableVersions(ctx context.Context, provider addrs.Provider) (VersionList, Warnings, error)
+	PackageMeta(ctx context.Context, provider addrs.Provider, version Version, target Platform) (PackageMeta, error)
+	ForDisplay(provider addrs.Provider) string
+}
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/invalid b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/invalid
new file mode 100644
index 0000000..289663a
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/invalid
@@ -0,0 +1 @@
+This should be ignored because it doesn't follow the provider package naming scheme.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip
new file mode 100644
index 0000000..68a5502
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip
@@ -0,0 +1,5 @@
+This is just a placeholder file for discovery testing, not a real provider package.
+
+This file is what we'd find for mirrors using the "packed" mirror layout,
+where the mirror maintainer can just download the packages from upstream and
+have Terraform unpack them automatically when installing.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid.zip b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid.zip
new file mode 100644
index 0000000..289663a
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid.zip
@@ -0,0 +1 @@
+This should be ignored because it doesn't follow the provider package naming scheme.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip
new file mode 100644
index 0000000..289663a
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip
@@ -0,0 +1 @@
+This should be ignored because it doesn't follow the provider package naming scheme.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/invalid b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/invalid
new file mode 100644
index 0000000..289663a
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/invalid
@@ -0,0 +1 @@
+This should be ignored because it doesn't follow the provider package naming scheme.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip
new file mode 100644
index 0000000..68a5502
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip
@@ -0,0 +1,5 @@
+This is just a placeholder file for discovery testing, not a real provider package.
+
+This file is what we'd find for mirrors using the "packed" mirror layout,
+where the mirror maintainer can just download the packages from upstream and
+have Terraform unpack them automatically when installing.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip
new file mode 100644
index 0000000..289663a
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip
@@ -0,0 +1 @@
+This should be ignored because it doesn't follow the provider package naming scheme.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip
new file mode 100644
index 0000000..289663a
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip
@@ -0,0 +1 @@
+This should be ignored because it doesn't follow the provider package naming scheme.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt
new file mode 100644
index 0000000..8a1c7c3
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt
@@ -0,0 +1,6 @@
+Provider plugin packages are allowed to include other files such as any static
+data they need to operate, or possibly source files if the provider is written
+in an interpreted programming language.
+
+This extra file is here just to make sure that extra files don't cause any
+misbehavior during local discovery.
diff --git a/v1.5.7/internal/getproviders/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/getproviders/testdata/search-local-directory/symlinks/real/example.com/foo/bar/1.0.0/linux_amd64/terraform-provider-bar b/v1.5.7/internal/getproviders/testdata/search-local-directory/symlinks/real/example.com/foo/bar/1.0.0/linux_amd64/terraform-provider-bar
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/search-local-directory/symlinks/real/example.com/foo/bar/1.0.0/linux_amd64/terraform-provider-bar
diff --git a/v1.5.7/internal/getproviders/testdata/search-local-directory/symlinks/real/example.net b/v1.5.7/internal/getproviders/testdata/search-local-directory/symlinks/real/example.net
new file mode 120000
index 0000000..caa12a8
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/search-local-directory/symlinks/real/example.net
@@ -0,0 +1 @@
+example.com
\ No newline at end of file
diff --git a/v1.5.7/internal/getproviders/testdata/search-local-directory/symlinks/symlink b/v1.5.7/internal/getproviders/testdata/search-local-directory/symlinks/symlink
new file mode 120000
index 0000000..ac558a3
--- /dev/null
+++ b/v1.5.7/internal/getproviders/testdata/search-local-directory/symlinks/symlink
@@ -0,0 +1 @@
+real
\ No newline at end of file
diff --git a/v1.5.7/internal/getproviders/types.go b/v1.5.7/internal/getproviders/types.go
new file mode 100644
index 0000000..a4ca6e6
--- /dev/null
+++ b/v1.5.7/internal/getproviders/types.go
@@ -0,0 +1,561 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"fmt"
+	"runtime"
+	"sort"
+	"strings"
+
+	"github.com/apparentlymart/go-versions/versions"
+	"github.com/apparentlymart/go-versions/versions/constraints"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// Version represents a particular single version of a provider.
+type Version = versions.Version
+
+// UnspecifiedVersion is the zero value of Version, representing the absense
+// of a version number.
+var UnspecifiedVersion Version = versions.Unspecified
+
+// VersionList represents a list of versions. It is a []Version with some
+// extra methods for convenient filtering.
+type VersionList = versions.List
+
+// VersionSet represents a set of versions, usually describing the acceptable
+// versions that can be selected under a particular version constraint provided
+// by the end-user.
+type VersionSet = versions.Set
+
+// VersionConstraints represents a set of version constraints, which can
+// define the membership of a VersionSet by exclusion.
+type VersionConstraints = constraints.IntersectionSpec
+
+// Warnings represents a list of warnings returned by a Registry source.
+type Warnings = []string
+
+// Requirements gathers together requirements for many different providers
+// into a single data structure, as a convenient way to represent the full
+// set of requirements for a particular configuration or state or both.
+//
+// If an entry in a Requirements has a zero-length VersionConstraints then
+// that indicates that the provider is required but that any version is
+// acceptable. That's different than a provider being absent from the map
+// altogether, which means that it is not required at all.
+type Requirements map[addrs.Provider]VersionConstraints
+
+// Merge takes the requirements in the receiever and the requirements in the
+// other given value and produces a new set of requirements that combines
+// all of the requirements of both.
+//
+// The resulting requirements will permit only selections that both of the
+// source requirements would've allowed.
+func (r Requirements) Merge(other Requirements) Requirements {
+	ret := make(Requirements)
+	for addr, constraints := range r {
+		ret[addr] = constraints
+	}
+	for addr, constraints := range other {
+		ret[addr] = append(ret[addr], constraints...)
+	}
+	return ret
+}
+
+// Selections gathers together version selections for many different providers.
+//
+// This is the result of provider installation: a specific version selected
+// for each provider given in the requested Requirements, selected based on
+// the given version constraints.
+type Selections map[addrs.Provider]Version
+
+// ParseVersion parses a "semver"-style version string into a Version value,
+// which is the version syntax we use for provider versions.
+func ParseVersion(str string) (Version, error) {
+	return versions.ParseVersion(str)
+}
+
+// MustParseVersion is a variant of ParseVersion that panics if it encounters
+// an error while parsing.
+func MustParseVersion(str string) Version {
+	ret, err := ParseVersion(str)
+	if err != nil {
+		panic(err)
+	}
+	return ret
+}
+
+// ParseVersionConstraints parses a "Ruby-like" version constraint string
+// into a VersionConstraints value.
+func ParseVersionConstraints(str string) (VersionConstraints, error) {
+	return constraints.ParseRubyStyleMulti(str)
+}
+
+// MustParseVersionConstraints is a variant of ParseVersionConstraints that
+// panics if it encounters an error while parsing.
+func MustParseVersionConstraints(str string) VersionConstraints {
+	ret, err := ParseVersionConstraints(str)
+	if err != nil {
+		panic(err)
+	}
+	return ret
+}
+
+// MeetingConstraints returns a version set that contains all of the versions
+// that meet the given constraints, specified using the Spec type from the
+// constraints package.
+func MeetingConstraints(vc VersionConstraints) VersionSet {
+	return versions.MeetingConstraints(vc)
+}
+
+// Platform represents a target platform that a provider is or might be
+// available for.
+type Platform struct {
+	OS, Arch string
+}
+
+func (p Platform) String() string {
+	return p.OS + "_" + p.Arch
+}
+
+// LessThan returns true if the receiver should sort before the other given
+// Platform in an ordered list of platforms.
+//
+// The ordering is lexical first by OS and then by Architecture.
+// This ordering is primarily just to ensure that results of
+// functions in this package will be deterministic. The ordering is not
+// intended to have any semantic meaning and is subject to change in future.
+func (p Platform) LessThan(other Platform) bool {
+	switch {
+	case p.OS != other.OS:
+		return p.OS < other.OS
+	default:
+		return p.Arch < other.Arch
+	}
+}
+
+// ParsePlatform parses a string representation of a platform, like
+// "linux_amd64", or returns an error if the string is not valid.
+func ParsePlatform(str string) (Platform, error) {
+	parts := strings.Split(str, "_")
+	if len(parts) != 2 {
+		return Platform{}, fmt.Errorf("must be two words separated by an underscore")
+	}
+
+	os, arch := parts[0], parts[1]
+	if strings.ContainsAny(os, " \t\n\r") {
+		return Platform{}, fmt.Errorf("OS portion must not contain whitespace")
+	}
+	if strings.ContainsAny(arch, " \t\n\r") {
+		return Platform{}, fmt.Errorf("architecture portion must not contain whitespace")
+	}
+
+	return Platform{
+		OS:   os,
+		Arch: arch,
+	}, nil
+}
+
+// CurrentPlatform is the platform where the current program is running.
+//
+// If attempting to install providers for use on the same system where the
+// installation process is running, this is the right platform to use.
+var CurrentPlatform = Platform{
+	OS:   runtime.GOOS,
+	Arch: runtime.GOARCH,
+}
+
+// PackageMeta represents the metadata related to a particular downloadable
+// provider package targeting a single platform.
+//
+// Package findproviders does no signature verification or protocol version
+// compatibility checking of its own. A caller receving a PackageMeta must
+// verify that it has a correct signature and supports a protocol version
+// accepted by the current version of Terraform before trying to use the
+// described package.
+type PackageMeta struct {
+	Provider addrs.Provider
+	Version  Version
+
+	ProtocolVersions VersionList
+	TargetPlatform   Platform
+
+	Filename string
+	Location PackageLocation
+
+	// Authentication, if non-nil, is a request from the source that produced
+	// this meta for verification of the target package after it has been
+	// retrieved from the indicated Location.
+	//
+	// Different sources will support different authentication strategies --
+	// or possibly no strategies at all -- depending on what metadata they
+	// have available to them, such as checksums provided out-of-band by the
+	// original package author, expected signing keys, etc.
+	//
+	// If Authentication is non-nil then no authentication is requested.
+	// This is likely appropriate only for packages that are already available
+	// on the local system.
+	Authentication PackageAuthentication
+}
+
+// LessThan returns true if the receiver should sort before the given other
+// PackageMeta in a sorted list of PackageMeta.
+//
+// Sorting preference is given first to the provider address, then to the
+// taget platform, and the to the version number (using semver precedence).
+// Packages that differ only in semver build metadata have no defined
+// precedence and so will always return false.
+//
+// This ordering is primarily just to maximize the chance that results of
+// functions in this package will be deterministic. The ordering is not
+// intended to have any semantic meaning and is subject to change in future.
+func (m PackageMeta) LessThan(other PackageMeta) bool {
+	switch {
+	case m.Provider != other.Provider:
+		return m.Provider.LessThan(other.Provider)
+	case m.TargetPlatform != other.TargetPlatform:
+		return m.TargetPlatform.LessThan(other.TargetPlatform)
+	case m.Version != other.Version:
+		return m.Version.LessThan(other.Version)
+	default:
+		return false
+	}
+}
+
+// UnpackedDirectoryPath determines the path under the given base
+// directory where SearchLocalDirectory or the FilesystemMirrorSource would
+// expect to find an unpacked copy of the receiving PackageMeta.
+//
+// The result always uses forward slashes as path separator, even on Windows,
+// to produce a consistent result on all platforms. Windows accepts both
+// direction of slash as long as each individual path string is self-consistent.
+func (m PackageMeta) UnpackedDirectoryPath(baseDir string) string {
+	return UnpackedDirectoryPathForPackage(baseDir, m.Provider, m.Version, m.TargetPlatform)
+}
+
+// PackedFilePath determines the path under the given base
+// directory where SearchLocalDirectory or the FilesystemMirrorSource would
+// expect to find packed copy (a .zip archive) of the receiving PackageMeta.
+//
+// The result always uses forward slashes as path separator, even on Windows,
+// to produce a consistent result on all platforms. Windows accepts both
+// direction of slash as long as each individual path string is self-consistent.
+func (m PackageMeta) PackedFilePath(baseDir string) string {
+	return PackedFilePathForPackage(baseDir, m.Provider, m.Version, m.TargetPlatform)
+}
+
+// AcceptableHashes returns a set of hashes that could be recorded for
+// comparison to future results for the same provider version, to implement a
+// "trust on first use" scheme.
+//
+// The AcceptableHashes result is a platform-agnostic set of hashes, with the
+// intent that in most cases it will be used as an additional cross-check in
+// addition to a platform-specific hash check made during installation. However,
+// there are some situations (such as verifying an already-installed package
+// that's on local disk) where Terraform would check only against the results
+// of this function, meaning that it would in principle accept another
+// platform's package as a substitute for the correct platform. That's a
+// pragmatic compromise to allow lock files derived from the result of this
+// method to be portable across platforms.
+//
+// Callers of this method should typically also verify the package using the
+// object in the Authentication field, and consider how much trust to give
+// the result of this method depending on the authentication result: an
+// unauthenticated result or one that only verified a checksum could be
+// considered less trustworthy than one that checked the package against
+// a signature provided by the origin registry.
+//
+// The AcceptableHashes result is actually provided by the object in the
+// Authentication field. AcceptableHashes therefore returns an empty result
+// for a PackageMeta that has no authentication object, or has one that does
+// not make use of hashes.
+func (m PackageMeta) AcceptableHashes() []Hash {
+	auth, ok := m.Authentication.(PackageAuthenticationHashes)
+	if !ok {
+		return nil
+	}
+	return auth.AcceptableHashes()
+}
+
+// PackageLocation represents a location where a provider distribution package
+// can be obtained. A value of this type contains one of the following
+// concrete types: PackageLocalArchive, PackageLocalDir, or PackageHTTPURL.
+type PackageLocation interface {
+	packageLocation()
+	String() string
+}
+
+// PackageLocalArchive is the location of a provider distribution archive file
+// in the local filesystem. Its value is a local filesystem path using the
+// syntax understood by Go's standard path/filepath package on the operating
+// system where Terraform is running.
+type PackageLocalArchive string
+
+func (p PackageLocalArchive) packageLocation() {}
+func (p PackageLocalArchive) String() string   { return string(p) }
+
+// PackageLocalDir is the location of a directory containing an unpacked
+// provider distribution archive in the local filesystem. Its value is a local
+// filesystem path using the syntax understood by Go's standard path/filepath
+// package on the operating system where Terraform is running.
+type PackageLocalDir string
+
+func (p PackageLocalDir) packageLocation() {}
+func (p PackageLocalDir) String() string   { return string(p) }
+
+// PackageHTTPURL is a provider package location accessible via HTTP.
+// Its value is a URL string using either the http: scheme or the https: scheme.
+type PackageHTTPURL string
+
+func (p PackageHTTPURL) packageLocation() {}
+func (p PackageHTTPURL) String() string   { return string(p) }
+
+// PackageMetaList is a list of PackageMeta. It's just []PackageMeta with
+// some methods for convenient sorting and filtering.
+type PackageMetaList []PackageMeta
+
+func (l PackageMetaList) Len() int {
+	return len(l)
+}
+
+func (l PackageMetaList) Less(i, j int) bool {
+	return l[i].LessThan(l[j])
+}
+
+func (l PackageMetaList) Swap(i, j int) {
+	l[i], l[j] = l[j], l[i]
+}
+
+// Sort performs an in-place, stable sort on the contents of the list, using
+// the ordering given by method Less. This ordering is primarily to help
+// encourage deterministic results from functions and does not have any
+// semantic meaning.
+func (l PackageMetaList) Sort() {
+	sort.Stable(l)
+}
+
+// FilterPlatform constructs a new PackageMetaList that contains only the
+// elements of the receiver that are for the given target platform.
+//
+// Pass CurrentPlatform to filter only for packages targeting the platform
+// where this code is running.
+func (l PackageMetaList) FilterPlatform(target Platform) PackageMetaList {
+	var ret PackageMetaList
+	for _, m := range l {
+		if m.TargetPlatform == target {
+			ret = append(ret, m)
+		}
+	}
+	return ret
+}
+
+// FilterProviderExactVersion constructs a new PackageMetaList that contains
+// only the elements of the receiver that relate to the given provider address
+// and exact version.
+//
+// The version matching for this function is exact, including matching on
+// semver build metadata, because it's intended for handling a single exact
+// version selected by the caller from a set of available versions.
+func (l PackageMetaList) FilterProviderExactVersion(provider addrs.Provider, version Version) PackageMetaList {
+	var ret PackageMetaList
+	for _, m := range l {
+		if m.Provider == provider && m.Version == version {
+			ret = append(ret, m)
+		}
+	}
+	return ret
+}
+
+// FilterProviderPlatformExactVersion is a combination of both
+// FilterPlatform and FilterProviderExactVersion that filters by all three
+// criteria at once.
+func (l PackageMetaList) FilterProviderPlatformExactVersion(provider addrs.Provider, platform Platform, version Version) PackageMetaList {
+	var ret PackageMetaList
+	for _, m := range l {
+		if m.Provider == provider && m.Version == version && m.TargetPlatform == platform {
+			ret = append(ret, m)
+		}
+	}
+	return ret
+}
+
+// VersionConstraintsString returns a canonical string representation of
+// a VersionConstraints value.
+func VersionConstraintsString(spec VersionConstraints) string {
+	// (we have our own function for this because the upstream versions
+	// library prefers to use npm/cargo-style constraint syntax, but
+	// Terraform prefers Ruby-like. Maybe we can upstream a "RubyLikeString")
+	// function to do this later, but having this in here avoids blocking on
+	// that and this is the sort of thing that is unlikely to need ongoing
+	// maintenance because the version constraint syntax is unlikely to change.)
+	//
+	// ParseVersionConstraints allows some variations for convenience, but the
+	// return value from this function serves as the normalized form of a
+	// particular version constraint, which is the form we require in dependency
+	// lock files. Therefore the canonical forms produced here are a compatibility
+	// constraint for the dependency lock file parser.
+
+	if len(spec) == 0 {
+		return ""
+	}
+
+	// VersionConstraints values are typically assembled by combining together
+	// the version constraints from many separate declarations throughout
+	// a configuration, across many modules. As a consequence, they typically
+	// contain duplicates and the terms inside are in no particular order.
+	// For our canonical representation we'll both deduplicate the items
+	// and sort them into a consistent order.
+	sels := make(map[constraints.SelectionSpec]struct{})
+	for _, sel := range spec {
+		// The parser allows writing abbreviated version (such as 2) which
+		// end up being represented in memory with trailing unconstrained parts
+		// (for example 2.*.*). For the purpose of serialization with Ruby
+		// style syntax, these unconstrained parts can all be represented as 0
+		// with no loss of meaning, so we make that conversion here. Doing so
+		// allows us to deduplicate equivalent constraints, such as >= 2.0 and
+		// >= 2.0.0.
+		normalizedSel := constraints.SelectionSpec{
+			Operator: sel.Operator,
+			Boundary: sel.Boundary.ConstrainToZero(),
+		}
+		sels[normalizedSel] = struct{}{}
+	}
+	selsOrder := make([]constraints.SelectionSpec, 0, len(sels))
+	for sel := range sels {
+		selsOrder = append(selsOrder, sel)
+	}
+	sort.Slice(selsOrder, func(i, j int) bool {
+		is, js := selsOrder[i], selsOrder[j]
+		boundaryCmp := versionSelectionBoundaryCompare(is.Boundary, js.Boundary)
+		if boundaryCmp == 0 {
+			// The operator is the decider, then.
+			return versionSelectionOperatorLess(is.Operator, js.Operator)
+		}
+		return boundaryCmp < 0
+	})
+
+	var b strings.Builder
+	for i, sel := range selsOrder {
+		if i > 0 {
+			b.WriteString(", ")
+		}
+		switch sel.Operator {
+		case constraints.OpGreaterThan:
+			b.WriteString("> ")
+		case constraints.OpLessThan:
+			b.WriteString("< ")
+		case constraints.OpGreaterThanOrEqual:
+			b.WriteString(">= ")
+		case constraints.OpGreaterThanOrEqualPatchOnly, constraints.OpGreaterThanOrEqualMinorOnly:
+			// These two differ in how the version is written, not in the symbol.
+			b.WriteString("~> ")
+		case constraints.OpLessThanOrEqual:
+			b.WriteString("<= ")
+		case constraints.OpEqual:
+			b.WriteString("")
+		case constraints.OpNotEqual:
+			b.WriteString("!= ")
+		default:
+			// The above covers all of the operators we support during
+			// parsing, so we should not get here.
+			b.WriteString("??? ")
+		}
+
+		// We use a different constraint operator to distinguish between the
+		// two types of pessimistic constraint: minor-only and patch-only. For
+		// minor-only constraints, we always want to display only the major and
+		// minor version components, so we special-case that operator below.
+		//
+		// One final edge case is a minor-only constraint specified with only
+		// the major version, such as ~> 2. We treat this the same as ~> 2.0,
+		// because a major-only pessimistic constraint does not exist: it is
+		// logically identical to >= 2.0.0.
+		if sel.Operator == constraints.OpGreaterThanOrEqualMinorOnly {
+			// The minor-pessimistic syntax uses only two version components.
+			fmt.Fprintf(&b, "%s.%s", sel.Boundary.Major, sel.Boundary.Minor)
+		} else {
+			fmt.Fprintf(&b, "%s.%s.%s", sel.Boundary.Major, sel.Boundary.Minor, sel.Boundary.Patch)
+		}
+		if sel.Boundary.Prerelease != "" {
+			b.WriteString("-" + sel.Boundary.Prerelease)
+		}
+		if sel.Boundary.Metadata != "" {
+			b.WriteString("+" + sel.Boundary.Metadata)
+		}
+	}
+	return b.String()
+}
+
+// Our sort for selection operators is somewhat arbitrary and mainly motivated
+// by consistency rather than meaning, but this ordering does at least try
+// to make it so "simple" constraint sets will appear how a human might
+// typically write them, with the lower bounds first and the upper bounds
+// last. Weird mixtures of different sorts of constraints will likely seem
+// less intuitive, but they'd be unintuitive no matter the ordering.
+var versionSelectionsBoundaryPriority = map[constraints.SelectionOp]int{
+	// We skip zero here so that if we end up seeing an invalid
+	// operator (which the string function would render as "???")
+	// then it will have index zero and thus appear first.
+	constraints.OpGreaterThan:                 1,
+	constraints.OpGreaterThanOrEqual:          2,
+	constraints.OpEqual:                       3,
+	constraints.OpGreaterThanOrEqualPatchOnly: 4,
+	constraints.OpGreaterThanOrEqualMinorOnly: 5,
+	constraints.OpLessThanOrEqual:             6,
+	constraints.OpLessThan:                    7,
+	constraints.OpNotEqual:                    8,
+}
+
+func versionSelectionOperatorLess(i, j constraints.SelectionOp) bool {
+	iPrio := versionSelectionsBoundaryPriority[i]
+	jPrio := versionSelectionsBoundaryPriority[j]
+	return iPrio < jPrio
+}
+
+func versionSelectionBoundaryCompare(i, j constraints.VersionSpec) int {
+	// In the Ruby-style constraint syntax, unconstrained parts appear
+	// only for omitted portions of a version string, like writing
+	// "2" instead of "2.0.0". For sorting purposes we'll just
+	// consider those as zero, which also matches how we serialize them
+	// to strings.
+	i, j = i.ConstrainToZero(), j.ConstrainToZero()
+
+	// Once we've removed any unconstrained parts, we can safely
+	// convert to our main Version type so we can use its ordering.
+	iv := Version{
+		Major:      i.Major.Num,
+		Minor:      i.Minor.Num,
+		Patch:      i.Patch.Num,
+		Prerelease: versions.VersionExtra(i.Prerelease),
+		Metadata:   versions.VersionExtra(i.Metadata),
+	}
+	jv := Version{
+		Major:      j.Major.Num,
+		Minor:      j.Minor.Num,
+		Patch:      j.Patch.Num,
+		Prerelease: versions.VersionExtra(j.Prerelease),
+		Metadata:   versions.VersionExtra(j.Metadata),
+	}
+	if iv.Same(jv) {
+		// Although build metadata doesn't normally weigh in to
+		// precedence choices, we'll use it for our visual
+		// ordering just because we need to pick _some_ order.
+		switch {
+		case iv.Metadata.Raw() == jv.Metadata.Raw():
+			return 0
+		case iv.Metadata.LessThan(jv.Metadata):
+			return -1
+		default:
+			return 1 // greater, by elimination
+		}
+	}
+	switch {
+	case iv.LessThan(jv):
+		return -1
+	default:
+		return 1 // greater, by elimination
+	}
+}
diff --git a/v1.5.7/internal/getproviders/types_test.go b/v1.5.7/internal/getproviders/types_test.go
new file mode 100644
index 0000000..4c07f5d
--- /dev/null
+++ b/v1.5.7/internal/getproviders/types_test.go
@@ -0,0 +1,144 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package getproviders
+
+import (
+	"testing"
+)
+
+func TestVersionConstraintsString(t *testing.T) {
+	testCases := map[string]struct {
+		spec VersionConstraints
+		want string
+	}{
+		"exact": {
+			MustParseVersionConstraints("1.2.3"),
+			"1.2.3",
+		},
+		"prerelease": {
+			MustParseVersionConstraints("1.2.3-beta"),
+			"1.2.3-beta",
+		},
+		"metadata": {
+			MustParseVersionConstraints("1.2.3+foo.bar"),
+			"1.2.3+foo.bar",
+		},
+		"prerelease and metadata": {
+			MustParseVersionConstraints("1.2.3-beta+foo.bar"),
+			"1.2.3-beta+foo.bar",
+		},
+		"major only": {
+			MustParseVersionConstraints(">= 3"),
+			">= 3.0.0",
+		},
+		"major only with pessimistic operator": {
+			MustParseVersionConstraints("~> 3"),
+			"~> 3.0",
+		},
+		"pessimistic minor": {
+			MustParseVersionConstraints("~> 3.0"),
+			"~> 3.0",
+		},
+		"pessimistic patch": {
+			MustParseVersionConstraints("~> 3.0.0"),
+			"~> 3.0.0",
+		},
+		"other operators": {
+			MustParseVersionConstraints("> 1.0.0, < 1.0.0, >= 1.0.0, <= 1.0.0, != 1.0.0"),
+			"> 1.0.0, >= 1.0.0, <= 1.0.0, < 1.0.0, != 1.0.0",
+		},
+		"multiple": {
+			MustParseVersionConstraints(">= 3.0, < 4.0"),
+			">= 3.0.0, < 4.0.0",
+		},
+		"duplicates removed": {
+			MustParseVersionConstraints(">= 1.2.3, 1.2.3, ~> 1.2, 1.2.3"),
+			"~> 1.2, >= 1.2.3, 1.2.3",
+		},
+		"equivalent duplicates removed": {
+			MustParseVersionConstraints(">= 2.68, >= 2.68.0"),
+			">= 2.68.0",
+		},
+		"consistent ordering, exhaustive": {
+			// This weird jumble is just to exercise the different sort
+			// ordering codepaths. Hopefully nothing quite this horrific
+			// shows up often in practice.
+			MustParseVersionConstraints("< 1.2.3, <= 1.2.3, != 1.2.3, 1.2.3+local.2, 1.2.3+local.1, = 1.2.4, = 1.2.3, > 2, > 1.2.3, >= 1.2.3, ~> 1.2.3, ~> 1.2"),
+			"~> 1.2, > 1.2.3, >= 1.2.3, 1.2.3, ~> 1.2.3, <= 1.2.3, < 1.2.3, != 1.2.3, 1.2.3+local.1, 1.2.3+local.2, 1.2.4, > 2.0.0",
+		},
+		"consistent ordering, more typical": {
+			// This one is aiming to simulate a common situation where
+			// various different modules express compatible constraints
+			// but some modules are more constrained than others. The
+			// combined results here can be kinda confusing, but hopefully
+			// ordering them consistently makes them a _little_ easier to read.
+			MustParseVersionConstraints("~> 1.2, >= 1.2, 1.2.4"),
+			">= 1.2.0, ~> 1.2, 1.2.4",
+		},
+		"consistent ordering, disjoint": {
+			// One situation where our presentation of version constraints is
+			// particularly important is when a user accidentally ends up with
+			// disjoint constraints that can therefore never match. In that
+			// case, our ordering should hopefully make it easier to determine
+			// that the constraints are disjoint, as a first step to debugging,
+			// by showing > or >= constrains sorted after < or <= constraints.
+			MustParseVersionConstraints(">= 2, >= 1.2, < 1.3"),
+			">= 1.2.0, < 1.3.0, >= 2.0.0",
+		},
+	}
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got := VersionConstraintsString(tc.spec)
+
+			if got != tc.want {
+				t.Errorf("wrong\n got: %q\nwant: %q", got, tc.want)
+			}
+		})
+	}
+}
+
+func TestParsePlatform(t *testing.T) {
+	tests := []struct {
+		Input string
+		Want  Platform
+		Err   bool
+	}{
+		{
+			"",
+			Platform{},
+			true,
+		},
+		{
+			"too_many_notes",
+			Platform{},
+			true,
+		},
+		{
+			"extra _ whitespaces ",
+			Platform{},
+			true,
+		},
+		{
+			"arbitrary_os",
+			Platform{OS: "arbitrary", Arch: "os"},
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		got, err := ParsePlatform(test.Input)
+		if err != nil {
+			if test.Err == false {
+				t.Errorf("unexpected error: %s", err.Error())
+			}
+		} else {
+			if test.Err {
+				t.Errorf("wrong result: expected error, got none")
+			}
+		}
+		if got != test.Want {
+			t.Errorf("wrong\n got: %q\nwant: %q", got, test.Want)
+		}
+	}
+}
diff --git a/v1.5.7/internal/grpcwrap/provider.go b/v1.5.7/internal/grpcwrap/provider.go
new file mode 100644
index 0000000..203d836
--- /dev/null
+++ b/v1.5.7/internal/grpcwrap/provider.go
@@ -0,0 +1,422 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package grpcwrap
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform/internal/plugin/convert"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/tfplugin5"
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+	"github.com/zclconf/go-cty/cty/msgpack"
+)
+
+// New wraps a providers.Interface to implement a grpc ProviderServer.
+// This is useful for creating a test binary out of an internal provider
+// implementation.
+func Provider(p providers.Interface) tfplugin5.ProviderServer {
+	return &provider{
+		provider: p,
+		schema:   p.GetProviderSchema(),
+	}
+}
+
+type provider struct {
+	provider providers.Interface
+	schema   providers.GetProviderSchemaResponse
+}
+
+func (p *provider) GetSchema(_ context.Context, req *tfplugin5.GetProviderSchema_Request) (*tfplugin5.GetProviderSchema_Response, error) {
+	resp := &tfplugin5.GetProviderSchema_Response{
+		ResourceSchemas:   make(map[string]*tfplugin5.Schema),
+		DataSourceSchemas: make(map[string]*tfplugin5.Schema),
+	}
+
+	resp.Provider = &tfplugin5.Schema{
+		Block: &tfplugin5.Schema_Block{},
+	}
+	if p.schema.Provider.Block != nil {
+		resp.Provider.Block = convert.ConfigSchemaToProto(p.schema.Provider.Block)
+	}
+
+	resp.ProviderMeta = &tfplugin5.Schema{
+		Block: &tfplugin5.Schema_Block{},
+	}
+	if p.schema.ProviderMeta.Block != nil {
+		resp.ProviderMeta.Block = convert.ConfigSchemaToProto(p.schema.ProviderMeta.Block)
+	}
+
+	for typ, res := range p.schema.ResourceTypes {
+		resp.ResourceSchemas[typ] = &tfplugin5.Schema{
+			Version: res.Version,
+			Block:   convert.ConfigSchemaToProto(res.Block),
+		}
+	}
+	for typ, dat := range p.schema.DataSources {
+		resp.DataSourceSchemas[typ] = &tfplugin5.Schema{
+			Version: dat.Version,
+			Block:   convert.ConfigSchemaToProto(dat.Block),
+		}
+	}
+
+	resp.ServerCapabilities = &tfplugin5.GetProviderSchema_ServerCapabilities{
+		PlanDestroy: p.schema.ServerCapabilities.PlanDestroy,
+	}
+
+	// include any diagnostics from the original GetSchema call
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, p.schema.Diagnostics)
+
+	return resp, nil
+}
+
+func (p *provider) PrepareProviderConfig(_ context.Context, req *tfplugin5.PrepareProviderConfig_Request) (*tfplugin5.PrepareProviderConfig_Response, error) {
+	resp := &tfplugin5.PrepareProviderConfig_Response{}
+	ty := p.schema.Provider.Block.ImpliedType()
+
+	configVal, err := decodeDynamicValue(req.Config, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	prepareResp := p.provider.ValidateProviderConfig(providers.ValidateProviderConfigRequest{
+		Config: configVal,
+	})
+
+	// the PreparedConfig value is no longer used
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, prepareResp.Diagnostics)
+	return resp, nil
+}
+
+func (p *provider) ValidateResourceTypeConfig(_ context.Context, req *tfplugin5.ValidateResourceTypeConfig_Request) (*tfplugin5.ValidateResourceTypeConfig_Response, error) {
+	resp := &tfplugin5.ValidateResourceTypeConfig_Response{}
+	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
+
+	configVal, err := decodeDynamicValue(req.Config, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	validateResp := p.provider.ValidateResourceConfig(providers.ValidateResourceConfigRequest{
+		TypeName: req.TypeName,
+		Config:   configVal,
+	})
+
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, validateResp.Diagnostics)
+	return resp, nil
+}
+
+func (p *provider) ValidateDataSourceConfig(_ context.Context, req *tfplugin5.ValidateDataSourceConfig_Request) (*tfplugin5.ValidateDataSourceConfig_Response, error) {
+	resp := &tfplugin5.ValidateDataSourceConfig_Response{}
+	ty := p.schema.DataSources[req.TypeName].Block.ImpliedType()
+
+	configVal, err := decodeDynamicValue(req.Config, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	validateResp := p.provider.ValidateDataResourceConfig(providers.ValidateDataResourceConfigRequest{
+		TypeName: req.TypeName,
+		Config:   configVal,
+	})
+
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, validateResp.Diagnostics)
+	return resp, nil
+}
+
+func (p *provider) UpgradeResourceState(_ context.Context, req *tfplugin5.UpgradeResourceState_Request) (*tfplugin5.UpgradeResourceState_Response, error) {
+	resp := &tfplugin5.UpgradeResourceState_Response{}
+	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
+
+	upgradeResp := p.provider.UpgradeResourceState(providers.UpgradeResourceStateRequest{
+		TypeName:     req.TypeName,
+		Version:      req.Version,
+		RawStateJSON: req.RawState.Json,
+	})
+
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, upgradeResp.Diagnostics)
+	if upgradeResp.Diagnostics.HasErrors() {
+		return resp, nil
+	}
+
+	dv, err := encodeDynamicValue(upgradeResp.UpgradedState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	resp.UpgradedState = dv
+
+	return resp, nil
+}
+
+func (p *provider) Configure(_ context.Context, req *tfplugin5.Configure_Request) (*tfplugin5.Configure_Response, error) {
+	resp := &tfplugin5.Configure_Response{}
+	ty := p.schema.Provider.Block.ImpliedType()
+
+	configVal, err := decodeDynamicValue(req.Config, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	configureResp := p.provider.ConfigureProvider(providers.ConfigureProviderRequest{
+		TerraformVersion: req.TerraformVersion,
+		Config:           configVal,
+	})
+
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, configureResp.Diagnostics)
+	return resp, nil
+}
+
+func (p *provider) ReadResource(_ context.Context, req *tfplugin5.ReadResource_Request) (*tfplugin5.ReadResource_Response, error) {
+	resp := &tfplugin5.ReadResource_Response{}
+	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
+
+	stateVal, err := decodeDynamicValue(req.CurrentState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	metaTy := p.schema.ProviderMeta.Block.ImpliedType()
+	metaVal, err := decodeDynamicValue(req.ProviderMeta, metaTy)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	readResp := p.provider.ReadResource(providers.ReadResourceRequest{
+		TypeName:     req.TypeName,
+		PriorState:   stateVal,
+		Private:      req.Private,
+		ProviderMeta: metaVal,
+	})
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, readResp.Diagnostics)
+	if readResp.Diagnostics.HasErrors() {
+		return resp, nil
+	}
+	resp.Private = readResp.Private
+
+	dv, err := encodeDynamicValue(readResp.NewState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+	resp.NewState = dv
+
+	return resp, nil
+}
+
+func (p *provider) PlanResourceChange(_ context.Context, req *tfplugin5.PlanResourceChange_Request) (*tfplugin5.PlanResourceChange_Response, error) {
+	resp := &tfplugin5.PlanResourceChange_Response{}
+	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
+
+	priorStateVal, err := decodeDynamicValue(req.PriorState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	proposedStateVal, err := decodeDynamicValue(req.ProposedNewState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	configVal, err := decodeDynamicValue(req.Config, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	metaTy := p.schema.ProviderMeta.Block.ImpliedType()
+	metaVal, err := decodeDynamicValue(req.ProviderMeta, metaTy)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	planResp := p.provider.PlanResourceChange(providers.PlanResourceChangeRequest{
+		TypeName:         req.TypeName,
+		PriorState:       priorStateVal,
+		ProposedNewState: proposedStateVal,
+		Config:           configVal,
+		PriorPrivate:     req.PriorPrivate,
+		ProviderMeta:     metaVal,
+	})
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, planResp.Diagnostics)
+	if planResp.Diagnostics.HasErrors() {
+		return resp, nil
+	}
+
+	resp.PlannedPrivate = planResp.PlannedPrivate
+
+	resp.PlannedState, err = encodeDynamicValue(planResp.PlannedState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	for _, path := range planResp.RequiresReplace {
+		resp.RequiresReplace = append(resp.RequiresReplace, convert.PathToAttributePath(path))
+	}
+
+	return resp, nil
+}
+
+func (p *provider) ApplyResourceChange(_ context.Context, req *tfplugin5.ApplyResourceChange_Request) (*tfplugin5.ApplyResourceChange_Response, error) {
+	resp := &tfplugin5.ApplyResourceChange_Response{}
+	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
+
+	priorStateVal, err := decodeDynamicValue(req.PriorState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	plannedStateVal, err := decodeDynamicValue(req.PlannedState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	configVal, err := decodeDynamicValue(req.Config, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	metaTy := p.schema.ProviderMeta.Block.ImpliedType()
+	metaVal, err := decodeDynamicValue(req.ProviderMeta, metaTy)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	applyResp := p.provider.ApplyResourceChange(providers.ApplyResourceChangeRequest{
+		TypeName:       req.TypeName,
+		PriorState:     priorStateVal,
+		PlannedState:   plannedStateVal,
+		Config:         configVal,
+		PlannedPrivate: req.PlannedPrivate,
+		ProviderMeta:   metaVal,
+	})
+
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, applyResp.Diagnostics)
+	if applyResp.Diagnostics.HasErrors() {
+		return resp, nil
+	}
+	resp.Private = applyResp.Private
+
+	resp.NewState, err = encodeDynamicValue(applyResp.NewState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	return resp, nil
+}
+
+func (p *provider) ImportResourceState(_ context.Context, req *tfplugin5.ImportResourceState_Request) (*tfplugin5.ImportResourceState_Response, error) {
+	resp := &tfplugin5.ImportResourceState_Response{}
+
+	importResp := p.provider.ImportResourceState(providers.ImportResourceStateRequest{
+		TypeName: req.TypeName,
+		ID:       req.Id,
+	})
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, importResp.Diagnostics)
+
+	for _, res := range importResp.ImportedResources {
+		ty := p.schema.ResourceTypes[res.TypeName].Block.ImpliedType()
+		state, err := encodeDynamicValue(res.State, ty)
+		if err != nil {
+			resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+			continue
+		}
+
+		resp.ImportedResources = append(resp.ImportedResources, &tfplugin5.ImportResourceState_ImportedResource{
+			TypeName: res.TypeName,
+			State:    state,
+			Private:  res.Private,
+		})
+	}
+
+	return resp, nil
+}
+
+func (p *provider) ReadDataSource(_ context.Context, req *tfplugin5.ReadDataSource_Request) (*tfplugin5.ReadDataSource_Response, error) {
+	resp := &tfplugin5.ReadDataSource_Response{}
+	ty := p.schema.DataSources[req.TypeName].Block.ImpliedType()
+
+	configVal, err := decodeDynamicValue(req.Config, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	metaTy := p.schema.ProviderMeta.Block.ImpliedType()
+	metaVal, err := decodeDynamicValue(req.ProviderMeta, metaTy)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	readResp := p.provider.ReadDataSource(providers.ReadDataSourceRequest{
+		TypeName:     req.TypeName,
+		Config:       configVal,
+		ProviderMeta: metaVal,
+	})
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, readResp.Diagnostics)
+	if readResp.Diagnostics.HasErrors() {
+		return resp, nil
+	}
+
+	resp.State, err = encodeDynamicValue(readResp.State, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	return resp, nil
+}
+
+func (p *provider) Stop(context.Context, *tfplugin5.Stop_Request) (*tfplugin5.Stop_Response, error) {
+	resp := &tfplugin5.Stop_Response{}
+	err := p.provider.Stop()
+	if err != nil {
+		resp.Error = err.Error()
+	}
+	return resp, nil
+}
+
+// decode a DynamicValue from either the JSON or MsgPack encoding.
+func decodeDynamicValue(v *tfplugin5.DynamicValue, ty cty.Type) (cty.Value, error) {
+	// always return a valid value
+	var err error
+	res := cty.NullVal(ty)
+	if v == nil {
+		return res, nil
+	}
+
+	switch {
+	case len(v.Msgpack) > 0:
+		res, err = msgpack.Unmarshal(v.Msgpack, ty)
+	case len(v.Json) > 0:
+		res, err = ctyjson.Unmarshal(v.Json, ty)
+	}
+	return res, err
+}
+
+// encode a cty.Value into a DynamicValue msgpack payload.
+func encodeDynamicValue(v cty.Value, ty cty.Type) (*tfplugin5.DynamicValue, error) {
+	mp, err := msgpack.Marshal(v, ty)
+	return &tfplugin5.DynamicValue{
+		Msgpack: mp,
+	}, err
+}
diff --git a/v1.5.7/internal/grpcwrap/provider6.go b/v1.5.7/internal/grpcwrap/provider6.go
new file mode 100644
index 0000000..a6470a0
--- /dev/null
+++ b/v1.5.7/internal/grpcwrap/provider6.go
@@ -0,0 +1,422 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package grpcwrap
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform/internal/plugin6/convert"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/tfplugin6"
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+	"github.com/zclconf/go-cty/cty/msgpack"
+)
+
+// New wraps a providers.Interface to implement a grpc ProviderServer using
+// plugin protocol v6. This is useful for creating a test binary out of an
+// internal provider implementation.
+func Provider6(p providers.Interface) tfplugin6.ProviderServer {
+	return &provider6{
+		provider: p,
+		schema:   p.GetProviderSchema(),
+	}
+}
+
+type provider6 struct {
+	provider providers.Interface
+	schema   providers.GetProviderSchemaResponse
+}
+
+func (p *provider6) GetProviderSchema(_ context.Context, req *tfplugin6.GetProviderSchema_Request) (*tfplugin6.GetProviderSchema_Response, error) {
+	resp := &tfplugin6.GetProviderSchema_Response{
+		ResourceSchemas:   make(map[string]*tfplugin6.Schema),
+		DataSourceSchemas: make(map[string]*tfplugin6.Schema),
+	}
+
+	resp.Provider = &tfplugin6.Schema{
+		Block: &tfplugin6.Schema_Block{},
+	}
+	if p.schema.Provider.Block != nil {
+		resp.Provider.Block = convert.ConfigSchemaToProto(p.schema.Provider.Block)
+	}
+
+	resp.ProviderMeta = &tfplugin6.Schema{
+		Block: &tfplugin6.Schema_Block{},
+	}
+	if p.schema.ProviderMeta.Block != nil {
+		resp.ProviderMeta.Block = convert.ConfigSchemaToProto(p.schema.ProviderMeta.Block)
+	}
+
+	for typ, res := range p.schema.ResourceTypes {
+		resp.ResourceSchemas[typ] = &tfplugin6.Schema{
+			Version: res.Version,
+			Block:   convert.ConfigSchemaToProto(res.Block),
+		}
+	}
+	for typ, dat := range p.schema.DataSources {
+		resp.DataSourceSchemas[typ] = &tfplugin6.Schema{
+			Version: dat.Version,
+			Block:   convert.ConfigSchemaToProto(dat.Block),
+		}
+	}
+
+	resp.ServerCapabilities = &tfplugin6.GetProviderSchema_ServerCapabilities{
+		PlanDestroy: p.schema.ServerCapabilities.PlanDestroy,
+	}
+
+	// include any diagnostics from the original GetSchema call
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, p.schema.Diagnostics)
+
+	return resp, nil
+}
+
+func (p *provider6) ValidateProviderConfig(_ context.Context, req *tfplugin6.ValidateProviderConfig_Request) (*tfplugin6.ValidateProviderConfig_Response, error) {
+	resp := &tfplugin6.ValidateProviderConfig_Response{}
+	ty := p.schema.Provider.Block.ImpliedType()
+
+	configVal, err := decodeDynamicValue6(req.Config, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	prepareResp := p.provider.ValidateProviderConfig(providers.ValidateProviderConfigRequest{
+		Config: configVal,
+	})
+
+	// the PreparedConfig value is no longer used
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, prepareResp.Diagnostics)
+	return resp, nil
+}
+
+func (p *provider6) ValidateResourceConfig(_ context.Context, req *tfplugin6.ValidateResourceConfig_Request) (*tfplugin6.ValidateResourceConfig_Response, error) {
+	resp := &tfplugin6.ValidateResourceConfig_Response{}
+	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
+
+	configVal, err := decodeDynamicValue6(req.Config, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	validateResp := p.provider.ValidateResourceConfig(providers.ValidateResourceConfigRequest{
+		TypeName: req.TypeName,
+		Config:   configVal,
+	})
+
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, validateResp.Diagnostics)
+	return resp, nil
+}
+
+func (p *provider6) ValidateDataResourceConfig(_ context.Context, req *tfplugin6.ValidateDataResourceConfig_Request) (*tfplugin6.ValidateDataResourceConfig_Response, error) {
+	resp := &tfplugin6.ValidateDataResourceConfig_Response{}
+	ty := p.schema.DataSources[req.TypeName].Block.ImpliedType()
+
+	configVal, err := decodeDynamicValue6(req.Config, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	validateResp := p.provider.ValidateDataResourceConfig(providers.ValidateDataResourceConfigRequest{
+		TypeName: req.TypeName,
+		Config:   configVal,
+	})
+
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, validateResp.Diagnostics)
+	return resp, nil
+}
+
+func (p *provider6) UpgradeResourceState(_ context.Context, req *tfplugin6.UpgradeResourceState_Request) (*tfplugin6.UpgradeResourceState_Response, error) {
+	resp := &tfplugin6.UpgradeResourceState_Response{}
+	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
+
+	upgradeResp := p.provider.UpgradeResourceState(providers.UpgradeResourceStateRequest{
+		TypeName:     req.TypeName,
+		Version:      req.Version,
+		RawStateJSON: req.RawState.Json,
+	})
+
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, upgradeResp.Diagnostics)
+	if upgradeResp.Diagnostics.HasErrors() {
+		return resp, nil
+	}
+
+	dv, err := encodeDynamicValue6(upgradeResp.UpgradedState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	resp.UpgradedState = dv
+
+	return resp, nil
+}
+
+func (p *provider6) ConfigureProvider(_ context.Context, req *tfplugin6.ConfigureProvider_Request) (*tfplugin6.ConfigureProvider_Response, error) {
+	resp := &tfplugin6.ConfigureProvider_Response{}
+	ty := p.schema.Provider.Block.ImpliedType()
+
+	configVal, err := decodeDynamicValue6(req.Config, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	configureResp := p.provider.ConfigureProvider(providers.ConfigureProviderRequest{
+		TerraformVersion: req.TerraformVersion,
+		Config:           configVal,
+	})
+
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, configureResp.Diagnostics)
+	return resp, nil
+}
+
+func (p *provider6) ReadResource(_ context.Context, req *tfplugin6.ReadResource_Request) (*tfplugin6.ReadResource_Response, error) {
+	resp := &tfplugin6.ReadResource_Response{}
+	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
+
+	stateVal, err := decodeDynamicValue6(req.CurrentState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	metaTy := p.schema.ProviderMeta.Block.ImpliedType()
+	metaVal, err := decodeDynamicValue6(req.ProviderMeta, metaTy)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	readResp := p.provider.ReadResource(providers.ReadResourceRequest{
+		TypeName:     req.TypeName,
+		PriorState:   stateVal,
+		Private:      req.Private,
+		ProviderMeta: metaVal,
+	})
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, readResp.Diagnostics)
+	if readResp.Diagnostics.HasErrors() {
+		return resp, nil
+	}
+	resp.Private = readResp.Private
+
+	dv, err := encodeDynamicValue6(readResp.NewState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+	resp.NewState = dv
+
+	return resp, nil
+}
+
+func (p *provider6) PlanResourceChange(_ context.Context, req *tfplugin6.PlanResourceChange_Request) (*tfplugin6.PlanResourceChange_Response, error) {
+	resp := &tfplugin6.PlanResourceChange_Response{}
+	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
+
+	priorStateVal, err := decodeDynamicValue6(req.PriorState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	proposedStateVal, err := decodeDynamicValue6(req.ProposedNewState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	configVal, err := decodeDynamicValue6(req.Config, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	metaTy := p.schema.ProviderMeta.Block.ImpliedType()
+	metaVal, err := decodeDynamicValue6(req.ProviderMeta, metaTy)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	planResp := p.provider.PlanResourceChange(providers.PlanResourceChangeRequest{
+		TypeName:         req.TypeName,
+		PriorState:       priorStateVal,
+		ProposedNewState: proposedStateVal,
+		Config:           configVal,
+		PriorPrivate:     req.PriorPrivate,
+		ProviderMeta:     metaVal,
+	})
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, planResp.Diagnostics)
+	if planResp.Diagnostics.HasErrors() {
+		return resp, nil
+	}
+
+	resp.PlannedPrivate = planResp.PlannedPrivate
+
+	resp.PlannedState, err = encodeDynamicValue6(planResp.PlannedState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	for _, path := range planResp.RequiresReplace {
+		resp.RequiresReplace = append(resp.RequiresReplace, convert.PathToAttributePath(path))
+	}
+
+	return resp, nil
+}
+
+func (p *provider6) ApplyResourceChange(_ context.Context, req *tfplugin6.ApplyResourceChange_Request) (*tfplugin6.ApplyResourceChange_Response, error) {
+	resp := &tfplugin6.ApplyResourceChange_Response{}
+	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
+
+	priorStateVal, err := decodeDynamicValue6(req.PriorState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	plannedStateVal, err := decodeDynamicValue6(req.PlannedState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	configVal, err := decodeDynamicValue6(req.Config, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	metaTy := p.schema.ProviderMeta.Block.ImpliedType()
+	metaVal, err := decodeDynamicValue6(req.ProviderMeta, metaTy)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	applyResp := p.provider.ApplyResourceChange(providers.ApplyResourceChangeRequest{
+		TypeName:       req.TypeName,
+		PriorState:     priorStateVal,
+		PlannedState:   plannedStateVal,
+		Config:         configVal,
+		PlannedPrivate: req.PlannedPrivate,
+		ProviderMeta:   metaVal,
+	})
+
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, applyResp.Diagnostics)
+	if applyResp.Diagnostics.HasErrors() {
+		return resp, nil
+	}
+	resp.Private = applyResp.Private
+
+	resp.NewState, err = encodeDynamicValue6(applyResp.NewState, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	return resp, nil
+}
+
+func (p *provider6) ImportResourceState(_ context.Context, req *tfplugin6.ImportResourceState_Request) (*tfplugin6.ImportResourceState_Response, error) {
+	resp := &tfplugin6.ImportResourceState_Response{}
+
+	importResp := p.provider.ImportResourceState(providers.ImportResourceStateRequest{
+		TypeName: req.TypeName,
+		ID:       req.Id,
+	})
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, importResp.Diagnostics)
+
+	for _, res := range importResp.ImportedResources {
+		ty := p.schema.ResourceTypes[res.TypeName].Block.ImpliedType()
+		state, err := encodeDynamicValue6(res.State, ty)
+		if err != nil {
+			resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+			continue
+		}
+
+		resp.ImportedResources = append(resp.ImportedResources, &tfplugin6.ImportResourceState_ImportedResource{
+			TypeName: res.TypeName,
+			State:    state,
+			Private:  res.Private,
+		})
+	}
+
+	return resp, nil
+}
+
+func (p *provider6) ReadDataSource(_ context.Context, req *tfplugin6.ReadDataSource_Request) (*tfplugin6.ReadDataSource_Response, error) {
+	resp := &tfplugin6.ReadDataSource_Response{}
+	ty := p.schema.DataSources[req.TypeName].Block.ImpliedType()
+
+	configVal, err := decodeDynamicValue6(req.Config, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	metaTy := p.schema.ProviderMeta.Block.ImpliedType()
+	metaVal, err := decodeDynamicValue6(req.ProviderMeta, metaTy)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	readResp := p.provider.ReadDataSource(providers.ReadDataSourceRequest{
+		TypeName:     req.TypeName,
+		Config:       configVal,
+		ProviderMeta: metaVal,
+	})
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, readResp.Diagnostics)
+	if readResp.Diagnostics.HasErrors() {
+		return resp, nil
+	}
+
+	resp.State, err = encodeDynamicValue6(readResp.State, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	return resp, nil
+}
+
+func (p *provider6) StopProvider(context.Context, *tfplugin6.StopProvider_Request) (*tfplugin6.StopProvider_Response, error) {
+	resp := &tfplugin6.StopProvider_Response{}
+	err := p.provider.Stop()
+	if err != nil {
+		resp.Error = err.Error()
+	}
+	return resp, nil
+}
+
+// decode a DynamicValue from either the JSON or MsgPack encoding.
+func decodeDynamicValue6(v *tfplugin6.DynamicValue, ty cty.Type) (cty.Value, error) {
+	// always return a valid value
+	var err error
+	res := cty.NullVal(ty)
+	if v == nil {
+		return res, nil
+	}
+
+	switch {
+	case len(v.Msgpack) > 0:
+		res, err = msgpack.Unmarshal(v.Msgpack, ty)
+	case len(v.Json) > 0:
+		res, err = ctyjson.Unmarshal(v.Json, ty)
+	}
+	return res, err
+}
+
+// encode a cty.Value into a DynamicValue msgpack payload.
+func encodeDynamicValue6(v cty.Value, ty cty.Type) (*tfplugin6.DynamicValue, error) {
+	mp, err := msgpack.Marshal(v, ty)
+	return &tfplugin6.DynamicValue{
+		Msgpack: mp,
+	}, err
+}
diff --git a/v1.5.7/internal/grpcwrap/provisioner.go b/v1.5.7/internal/grpcwrap/provisioner.go
new file mode 100644
index 0000000..4033e51
--- /dev/null
+++ b/v1.5.7/internal/grpcwrap/provisioner.go
@@ -0,0 +1,119 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package grpcwrap
+
+import (
+	"context"
+	"log"
+	"strings"
+	"unicode/utf8"
+
+	"github.com/hashicorp/terraform/internal/communicator/shared"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/plugin/convert"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/tfplugin5"
+)
+
+// New wraps a provisioners.Interface to implement a grpc ProviderServer.
+// This is useful for creating a test binary out of an internal provider
+// implementation.
+func Provisioner(p provisioners.Interface) tfplugin5.ProvisionerServer {
+	return &provisioner{
+		provisioner: p,
+		schema:      p.GetSchema().Provisioner,
+	}
+}
+
+type provisioner struct {
+	provisioner provisioners.Interface
+	schema      *configschema.Block
+}
+
+func (p *provisioner) GetSchema(_ context.Context, req *tfplugin5.GetProvisionerSchema_Request) (*tfplugin5.GetProvisionerSchema_Response, error) {
+	resp := &tfplugin5.GetProvisionerSchema_Response{}
+
+	resp.Provisioner = &tfplugin5.Schema{
+		Block: &tfplugin5.Schema_Block{},
+	}
+
+	if p.schema != nil {
+		resp.Provisioner.Block = convert.ConfigSchemaToProto(p.schema)
+	}
+
+	return resp, nil
+}
+
+func (p *provisioner) ValidateProvisionerConfig(_ context.Context, req *tfplugin5.ValidateProvisionerConfig_Request) (*tfplugin5.ValidateProvisionerConfig_Response, error) {
+	resp := &tfplugin5.ValidateProvisionerConfig_Response{}
+	ty := p.schema.ImpliedType()
+
+	configVal, err := decodeDynamicValue(req.Config, ty)
+	if err != nil {
+		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
+		return resp, nil
+	}
+
+	validateResp := p.provisioner.ValidateProvisionerConfig(provisioners.ValidateProvisionerConfigRequest{
+		Config: configVal,
+	})
+
+	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, validateResp.Diagnostics)
+	return resp, nil
+}
+
+func (p *provisioner) ProvisionResource(req *tfplugin5.ProvisionResource_Request, srv tfplugin5.Provisioner_ProvisionResourceServer) error {
+	// We send back a diagnostics over the stream if there was a
+	// provisioner-side problem.
+	srvResp := &tfplugin5.ProvisionResource_Response{}
+
+	ty := p.schema.ImpliedType()
+	configVal, err := decodeDynamicValue(req.Config, ty)
+	if err != nil {
+		srvResp.Diagnostics = convert.AppendProtoDiag(srvResp.Diagnostics, err)
+		srv.Send(srvResp)
+		return nil
+	}
+
+	connVal, err := decodeDynamicValue(req.Connection, shared.ConnectionBlockSupersetSchema.ImpliedType())
+	if err != nil {
+		srvResp.Diagnostics = convert.AppendProtoDiag(srvResp.Diagnostics, err)
+		srv.Send(srvResp)
+		return nil
+	}
+
+	resp := p.provisioner.ProvisionResource(provisioners.ProvisionResourceRequest{
+		Config:     configVal,
+		Connection: connVal,
+		UIOutput:   uiOutput{srv},
+	})
+
+	srvResp.Diagnostics = convert.AppendProtoDiag(srvResp.Diagnostics, resp.Diagnostics)
+	srv.Send(srvResp)
+	return nil
+}
+
+func (p *provisioner) Stop(context.Context, *tfplugin5.Stop_Request) (*tfplugin5.Stop_Response, error) {
+	resp := &tfplugin5.Stop_Response{}
+	err := p.provisioner.Stop()
+	if err != nil {
+		resp.Error = err.Error()
+	}
+	return resp, nil
+}
+
+// uiOutput implements the terraform.UIOutput interface to adapt the grpc
+// stream to the legacy Provisioner.Apply method.
+type uiOutput struct {
+	srv tfplugin5.Provisioner_ProvisionResourceServer
+}
+
+func (o uiOutput) Output(s string) {
+	err := o.srv.Send(&tfplugin5.ProvisionResource_Response{
+		Output: strings.ToValidUTF8(s, string(utf8.RuneError)),
+	})
+	if err != nil {
+		log.Printf("[ERROR] %s", err)
+	}
+}
diff --git a/v1.5.7/internal/helper/slowmessage/slowmessage.go b/v1.5.7/internal/helper/slowmessage/slowmessage.go
new file mode 100644
index 0000000..df53e57
--- /dev/null
+++ b/v1.5.7/internal/helper/slowmessage/slowmessage.go
@@ -0,0 +1,37 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package slowmessage
+
+import (
+	"time"
+)
+
+// SlowFunc is the function that could be slow. Usually, you'll have to
+// wrap an existing function in a lambda to make it match this type signature.
+type SlowFunc func() error
+
+// CallbackFunc is the function that is triggered when the threshold is reached.
+type CallbackFunc func()
+
+// Do calls sf. If threshold time has passed, cb is called. Note that this
+// call will be made concurrently to sf still running.
+func Do(threshold time.Duration, sf SlowFunc, cb CallbackFunc) error {
+	// Call the slow function
+	errCh := make(chan error, 1)
+	go func() {
+		errCh <- sf()
+	}()
+
+	// Wait for it to complete or the threshold to pass
+	select {
+	case err := <-errCh:
+		return err
+	case <-time.After(threshold):
+		// Threshold reached, call the callback
+		cb()
+	}
+
+	// Wait an indefinite amount of time for it to finally complete
+	return <-errCh
+}
diff --git a/v1.5.7/internal/helper/slowmessage/slowmessage_test.go b/v1.5.7/internal/helper/slowmessage/slowmessage_test.go
new file mode 100644
index 0000000..48c320f
--- /dev/null
+++ b/v1.5.7/internal/helper/slowmessage/slowmessage_test.go
@@ -0,0 +1,85 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package slowmessage
+
+import (
+	"errors"
+	"testing"
+	"time"
+)
+
+func TestDo(t *testing.T) {
+	var sfErr error
+	cbCalled := false
+	sfCalled := false
+	sfSleep := 0 * time.Second
+
+	reset := func() {
+		cbCalled = false
+		sfCalled = false
+		sfErr = nil
+	}
+	sf := func() error {
+		sfCalled = true
+		time.Sleep(sfSleep)
+		return sfErr
+	}
+	cb := func() { cbCalled = true }
+
+	// SF is not slow
+	reset()
+	if err := Do(10*time.Millisecond, sf, cb); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !sfCalled {
+		t.Fatal("should call")
+	}
+	if cbCalled {
+		t.Fatal("should not call")
+	}
+
+	// SF is not slow (with error)
+	reset()
+	sfErr = errors.New("error")
+	if err := Do(10*time.Millisecond, sf, cb); err == nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !sfCalled {
+		t.Fatal("should call")
+	}
+	if cbCalled {
+		t.Fatal("should not call")
+	}
+
+	// SF is slow
+	reset()
+	sfSleep = 50 * time.Millisecond
+	if err := Do(10*time.Millisecond, sf, cb); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !sfCalled {
+		t.Fatal("should call")
+	}
+	if !cbCalled {
+		t.Fatal("should call")
+	}
+
+	// SF is slow (with error)
+	reset()
+	sfErr = errors.New("error")
+	sfSleep = 50 * time.Millisecond
+	if err := Do(10*time.Millisecond, sf, cb); err == nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !sfCalled {
+		t.Fatal("should call")
+	}
+	if !cbCalled {
+		t.Fatal("should call")
+	}
+}
diff --git a/v1.5.7/internal/httpclient/client.go b/v1.5.7/internal/httpclient/client.go
new file mode 100644
index 0000000..60a6551
--- /dev/null
+++ b/v1.5.7/internal/httpclient/client.go
@@ -0,0 +1,21 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package httpclient
+
+import (
+	"net/http"
+
+	cleanhttp "github.com/hashicorp/go-cleanhttp"
+)
+
+// New returns the DefaultPooledClient from the cleanhttp
+// package that will also send a Terraform User-Agent string.
+func New() *http.Client {
+	cli := cleanhttp.DefaultPooledClient()
+	cli.Transport = &userAgentRoundTripper{
+		userAgent: UserAgentString(),
+		inner:     cli.Transport,
+	}
+	return cli
+}
diff --git a/v1.5.7/internal/httpclient/client_test.go b/v1.5.7/internal/httpclient/client_test.go
new file mode 100644
index 0000000..029667a
--- /dev/null
+++ b/v1.5.7/internal/httpclient/client_test.go
@@ -0,0 +1,80 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package httpclient
+
+import (
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"testing"
+
+	"github.com/hashicorp/terraform/version"
+)
+
+func TestNew_userAgent(t *testing.T) {
+	var actualUserAgent string
+	ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
+		actualUserAgent = req.UserAgent()
+	}))
+	defer ts.Close()
+
+	tsURL, err := url.Parse(ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for i, c := range []struct {
+		expected string
+		request  func(c *http.Client) error
+	}{
+		{
+			fmt.Sprintf("Terraform/%s", version.Version),
+			func(c *http.Client) error {
+				_, err := c.Get(ts.URL)
+				return err
+			},
+		},
+		{
+			"foo/1",
+			func(c *http.Client) error {
+				req := &http.Request{
+					Method: "GET",
+					URL:    tsURL,
+					Header: http.Header{
+						"User-Agent": []string{"foo/1"},
+					},
+				}
+				_, err := c.Do(req)
+				return err
+			},
+		},
+		{
+			"",
+			func(c *http.Client) error {
+				req := &http.Request{
+					Method: "GET",
+					URL:    tsURL,
+					Header: http.Header{
+						"User-Agent": []string{""},
+					},
+				}
+				_, err := c.Do(req)
+				return err
+			},
+		},
+	} {
+		t.Run(fmt.Sprintf("%d %s", i, c.expected), func(t *testing.T) {
+			actualUserAgent = ""
+			cli := New()
+			err := c.request(cli)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if actualUserAgent != c.expected {
+				t.Fatalf("actual User-Agent '%s' is not '%s'", actualUserAgent, c.expected)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/httpclient/useragent.go b/v1.5.7/internal/httpclient/useragent.go
new file mode 100644
index 0000000..366a5ae
--- /dev/null
+++ b/v1.5.7/internal/httpclient/useragent.go
@@ -0,0 +1,59 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package httpclient
+
+import (
+	"fmt"
+	"log"
+	"net/http"
+	"os"
+	"strings"
+
+	"github.com/hashicorp/terraform/version"
+)
+
+const userAgentFormat = "Terraform/%s"
+const uaEnvVar = "TF_APPEND_USER_AGENT"
+
+// Deprecated: Use TerraformUserAgent(version) instead
+func UserAgentString() string {
+	ua := fmt.Sprintf(userAgentFormat, version.Version)
+
+	if add := os.Getenv(uaEnvVar); add != "" {
+		add = strings.TrimSpace(add)
+		if len(add) > 0 {
+			ua += " " + add
+			log.Printf("[DEBUG] Using modified User-Agent: %s", ua)
+		}
+	}
+
+	return ua
+}
+
+type userAgentRoundTripper struct {
+	inner     http.RoundTripper
+	userAgent string
+}
+
+func (rt *userAgentRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
+	if _, ok := req.Header["User-Agent"]; !ok {
+		req.Header.Set("User-Agent", rt.userAgent)
+	}
+	log.Printf("[TRACE] HTTP client %s request to %s", req.Method, req.URL.String())
+	return rt.inner.RoundTrip(req)
+}
+
+func TerraformUserAgent(version string) string {
+	ua := fmt.Sprintf("HashiCorp Terraform/%s (+https://www.terraform.io)", version)
+
+	if add := os.Getenv(uaEnvVar); add != "" {
+		add = strings.TrimSpace(add)
+		if len(add) > 0 {
+			ua += " " + add
+			log.Printf("[DEBUG] Using modified User-Agent: %s", ua)
+		}
+	}
+
+	return ua
+}
diff --git a/v1.5.7/internal/httpclient/useragent_test.go b/v1.5.7/internal/httpclient/useragent_test.go
new file mode 100644
index 0000000..9eda8e2
--- /dev/null
+++ b/v1.5.7/internal/httpclient/useragent_test.go
@@ -0,0 +1,81 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package httpclient
+
+import (
+	"fmt"
+	"os"
+	"testing"
+
+	"github.com/hashicorp/terraform/version"
+)
+
+func TestUserAgentString_env(t *testing.T) {
+	expectedBase := fmt.Sprintf(userAgentFormat, version.Version)
+	if oldenv, isSet := os.LookupEnv(uaEnvVar); isSet {
+		defer os.Setenv(uaEnvVar, oldenv)
+	} else {
+		defer os.Unsetenv(uaEnvVar)
+	}
+
+	for i, c := range []struct {
+		expected   string
+		additional string
+	}{
+		{expectedBase, ""},
+		{expectedBase, " "},
+		{expectedBase, " \n"},
+
+		{fmt.Sprintf("%s test/1", expectedBase), "test/1"},
+		{fmt.Sprintf("%s test/2", expectedBase), "test/2 "},
+		{fmt.Sprintf("%s test/3", expectedBase), " test/3 "},
+		{fmt.Sprintf("%s test/4", expectedBase), "test/4 \n"},
+	} {
+		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+			if c.additional == "" {
+				os.Unsetenv(uaEnvVar)
+			} else {
+				os.Setenv(uaEnvVar, c.additional)
+			}
+
+			actual := UserAgentString()
+
+			if c.expected != actual {
+				t.Fatalf("Expected User-Agent '%s' does not match '%s'", c.expected, actual)
+			}
+		})
+	}
+}
+
+func TestUserAgentAppendViaEnvVar(t *testing.T) {
+	if oldenv, isSet := os.LookupEnv(uaEnvVar); isSet {
+		defer os.Setenv(uaEnvVar, oldenv)
+	} else {
+		defer os.Unsetenv(uaEnvVar)
+	}
+
+	expectedBase := "HashiCorp Terraform/0.0.0 (+https://www.terraform.io)"
+
+	testCases := []struct {
+		envVarValue string
+		expected    string
+	}{
+		{"", expectedBase},
+		{" ", expectedBase},
+		{" \n", expectedBase},
+		{"test/1", expectedBase + " test/1"},
+		{"test/1 (comment)", expectedBase + " test/1 (comment)"},
+	}
+
+	for i, tc := range testCases {
+		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+			os.Unsetenv(uaEnvVar)
+			os.Setenv(uaEnvVar, tc.envVarValue)
+			givenUA := TerraformUserAgent("0.0.0")
+			if givenUA != tc.expected {
+				t.Fatalf("Expected User-Agent '%s' does not match '%s'", tc.expected, givenUA)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/initwd/doc.go b/v1.5.7/internal/initwd/doc.go
new file mode 100644
index 0000000..2336816
--- /dev/null
+++ b/v1.5.7/internal/initwd/doc.go
@@ -0,0 +1,10 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package initwd contains various helper functions used by the "terraform init"
+// command to initialize a working directory.
+//
+// These functions may also be used from testing code to simulate the behaviors
+// of "terraform init" against test fixtures, but should not be used elsewhere
+// in the main code.
+package initwd
diff --git a/v1.5.7/internal/initwd/from_module.go b/v1.5.7/internal/initwd/from_module.go
new file mode 100644
index 0000000..90949e9
--- /dev/null
+++ b/v1.5.7/internal/initwd/from_module.go
@@ -0,0 +1,411 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package initwd
+
+import (
+	"context"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/copy"
+	"github.com/hashicorp/terraform/internal/getmodules"
+
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/terraform/internal/modsdir"
+	"github.com/hashicorp/terraform/internal/registry"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+const initFromModuleRootCallName = "root"
+const initFromModuleRootFilename = "<main configuration>"
+const initFromModuleRootKeyPrefix = initFromModuleRootCallName + "."
+
+// DirFromModule populates the given directory (which must exist and be
+// empty) with the contents of the module at the given source address.
+//
+// It does this by installing the given module and all of its descendent
+// modules in a temporary root directory and then copying the installed
+// files into suitable locations. As a consequence, any diagnostics it
+// generates will reveal the location of this temporary directory to the
+// user.
+//
+// This rather roundabout installation approach is taken to ensure that
+// installation proceeds in a manner identical to normal module installation.
+//
+// If the given source address specifies a sub-directory of the given
+// package then only the sub-directory and its descendents will be copied
+// into the given root directory, which will cause any relative module
+// references using ../ from that module to be unresolvable. Error diagnostics
+// are produced in that case, to prompt the user to rewrite the source strings
+// to be absolute references to the original remote module.
+func DirFromModule(ctx context.Context, loader *configload.Loader, rootDir, modulesDir, sourceAddrStr string, reg *registry.Client, hooks ModuleInstallHooks) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	// The way this function works is pretty ugly, but we accept it because
+	// -from-module is a less important case than normal module installation
+	// and so it's better to keep this ugly complexity out here rather than
+	// adding even more complexity to the normal module installer.
+
+	// The target directory must exist but be empty.
+	{
+		entries, err := ioutil.ReadDir(rootDir)
+		if err != nil {
+			if os.IsNotExist(err) {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Target directory does not exist",
+					fmt.Sprintf("Cannot initialize non-existent directory %s.", rootDir),
+				))
+			} else {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to read target directory",
+					fmt.Sprintf("Error reading %s to ensure it is empty: %s.", rootDir, err),
+				))
+			}
+			return diags
+		}
+		haveEntries := false
+		for _, entry := range entries {
+			if entry.Name() == "." || entry.Name() == ".." || entry.Name() == ".terraform" {
+				continue
+			}
+			haveEntries = true
+		}
+		if haveEntries {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Can't populate non-empty directory",
+				fmt.Sprintf("The target directory %s is not empty, so it cannot be initialized with the -from-module=... option.", rootDir),
+			))
+			return diags
+		}
+	}
+
+	instDir := filepath.Join(rootDir, ".terraform/init-from-module")
+	inst := NewModuleInstaller(instDir, loader, reg)
+	log.Printf("[DEBUG] installing modules in %s to initialize working directory from %q", instDir, sourceAddrStr)
+	os.RemoveAll(instDir) // if this fails then we'll fail on MkdirAll below too
+	err := os.MkdirAll(instDir, os.ModePerm)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to create temporary directory",
+			fmt.Sprintf("Failed to create temporary directory %s: %s.", instDir, err),
+		))
+		return diags
+	}
+
+	instManifest := make(modsdir.Manifest)
+	retManifest := make(modsdir.Manifest)
+
+	// -from-module allows relative paths but it's different than a normal
+	// module address where it'd be resolved relative to the module call
+	// (which is synthetic, here.) To address this, we'll just patch up any
+	// relative paths to be absolute paths before we run, ensuring we'll
+	// get the right result. This also, as an important side-effect, ensures
+	// that the result will be "downloaded" with go-getter (copied from the
+	// source location), rather than just recorded as a relative path.
+	{
+		maybePath := filepath.ToSlash(sourceAddrStr)
+		if maybePath == "." || strings.HasPrefix(maybePath, "./") || strings.HasPrefix(maybePath, "../") {
+			if wd, err := os.Getwd(); err == nil {
+				sourceAddrStr = filepath.Join(wd, sourceAddrStr)
+				log.Printf("[TRACE] -from-module relative path rewritten to absolute path %s", sourceAddrStr)
+			}
+		}
+	}
+
+	// Now we need to create an artificial root module that will seed our
+	// installation process.
+	sourceAddr, err := addrs.ParseModuleSource(sourceAddrStr)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid module source address",
+			fmt.Sprintf("Failed to parse module source address: %s", err),
+		))
+	}
+	fakeRootModule := &configs.Module{
+		ModuleCalls: map[string]*configs.ModuleCall{
+			initFromModuleRootCallName: {
+				Name:       initFromModuleRootCallName,
+				SourceAddr: sourceAddr,
+				DeclRange: hcl.Range{
+					Filename: initFromModuleRootFilename,
+					Start:    hcl.InitialPos,
+					End:      hcl.InitialPos,
+				},
+			},
+		},
+		ProviderRequirements: &configs.RequiredProviders{},
+	}
+
+	// wrapHooks filters hook notifications to only include Download calls
+	// and to trim off the initFromModuleRootCallName prefix. We'll produce
+	// our own Install notifications directly below.
+	wrapHooks := installHooksInitDir{
+		Wrapped: hooks,
+	}
+	fetcher := getmodules.NewPackageFetcher()
+	_, instDiags := inst.installDescendentModules(ctx, fakeRootModule, rootDir, instManifest, true, wrapHooks, fetcher)
+	diags = append(diags, instDiags...)
+	if instDiags.HasErrors() {
+		return diags
+	}
+
+	// If all of that succeeded then we'll now migrate what was installed
+	// into the final directory structure.
+	err = os.MkdirAll(modulesDir, os.ModePerm)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to create local modules directory",
+			fmt.Sprintf("Failed to create modules directory %s: %s.", modulesDir, err),
+		))
+		return diags
+	}
+
+	recordKeys := make([]string, 0, len(instManifest))
+	for k := range instManifest {
+		recordKeys = append(recordKeys, k)
+	}
+	sort.Strings(recordKeys)
+
+	for _, recordKey := range recordKeys {
+		record := instManifest[recordKey]
+
+		if record.Key == initFromModuleRootCallName {
+			// We've found the module the user requested, which we must
+			// now copy into rootDir so it can be used directly.
+			log.Printf("[TRACE] copying new root module from %s to %s", record.Dir, rootDir)
+			err := copy.CopyDir(rootDir, record.Dir)
+			if err != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to copy root module",
+					fmt.Sprintf("Error copying root module %q from %s to %s: %s.", sourceAddrStr, record.Dir, rootDir, err),
+				))
+				continue
+			}
+
+			// We'll try to load the newly-copied module here just so we can
+			// sniff for any module calls that ../ out of the root directory
+			// and must thus be rewritten to be absolute addresses again.
+			// For now we can't do this rewriting automatically, but we'll
+			// generate an error to help the user do it manually.
+			mod, _ := loader.Parser().LoadConfigDir(rootDir) // ignore diagnostics since we're just doing value-add here anyway
+			if mod != nil {
+				for _, mc := range mod.ModuleCalls {
+					if pathTraversesUp(mc.SourceAddrRaw) {
+						packageAddr, givenSubdir := getmodules.SplitPackageSubdir(sourceAddrStr)
+						newSubdir := filepath.Join(givenSubdir, mc.SourceAddrRaw)
+						if pathTraversesUp(newSubdir) {
+							// This should never happen in any reasonable
+							// configuration since this suggests a path that
+							// traverses up out of the package root. We'll just
+							// ignore this, since we'll fail soon enough anyway
+							// trying to resolve this path when this module is
+							// loaded.
+							continue
+						}
+
+						var newAddr = packageAddr
+						if newSubdir != "" {
+							newAddr = fmt.Sprintf("%s//%s", newAddr, filepath.ToSlash(newSubdir))
+						}
+						diags = diags.Append(tfdiags.Sourceless(
+							tfdiags.Error,
+							"Root module references parent directory",
+							fmt.Sprintf("The requested module %q refers to a module via its parent directory. To use this as a new root module this source string must be rewritten as a remote source address, such as %q.", sourceAddrStr, newAddr),
+						))
+						continue
+					}
+				}
+			}
+
+			retManifest[""] = modsdir.Record{
+				Key: "",
+				Dir: rootDir,
+			}
+			continue
+		}
+
+		if !strings.HasPrefix(record.Key, initFromModuleRootKeyPrefix) {
+			// Ignore the *real* root module, whose key is empty, since
+			// we're only interested in the module named "root" and its
+			// descendents.
+			continue
+		}
+
+		newKey := record.Key[len(initFromModuleRootKeyPrefix):]
+		instPath := filepath.Join(modulesDir, newKey)
+		tempPath := filepath.Join(instDir, record.Key)
+
+		// tempPath won't be present for a module that was installed from
+		// a relative path, so in that case we just record the installation
+		// directory and assume it was already copied into place as part
+		// of its parent.
+		if _, err := os.Stat(tempPath); err != nil {
+			if !os.IsNotExist(err) {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to stat temporary module install directory",
+					fmt.Sprintf("Error from stat %s for module %s: %s.", instPath, newKey, err),
+				))
+				continue
+			}
+
+			var parentKey string
+			if lastDot := strings.LastIndexByte(newKey, '.'); lastDot != -1 {
+				parentKey = newKey[:lastDot]
+			}
+
+			var parentOld modsdir.Record
+			// "" is the root module; all other modules get `root.` added as a prefix
+			if parentKey == "" {
+				parentOld = instManifest[parentKey]
+			} else {
+				parentOld = instManifest[initFromModuleRootKeyPrefix+parentKey]
+			}
+			parentNew := retManifest[parentKey]
+
+			// We need to figure out which portion of our directory is the
+			// parent package path and which portion is the subdirectory
+			// under that.
+			var baseDirRel string
+			baseDirRel, err = filepath.Rel(parentOld.Dir, record.Dir)
+			if err != nil {
+				// This error may occur when installing a local module with a
+				// relative path, for e.g. if the source is in a directory above
+				// the destination ("../")
+				if parentOld.Dir == "." {
+					absDir, err := filepath.Abs(parentOld.Dir)
+					if err != nil {
+						diags = diags.Append(tfdiags.Sourceless(
+							tfdiags.Error,
+							"Failed to determine module install directory",
+							fmt.Sprintf("Error determine relative source directory for module %s: %s.", newKey, err),
+						))
+						continue
+					}
+					baseDirRel, err = filepath.Rel(absDir, record.Dir)
+					if err != nil {
+						diags = diags.Append(tfdiags.Sourceless(
+							tfdiags.Error,
+							"Failed to determine relative module source location",
+							fmt.Sprintf("Error determining relative source for module %s: %s.", newKey, err),
+						))
+						continue
+					}
+				} else {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Failed to determine relative module source location",
+						fmt.Sprintf("Error determining relative source for module %s: %s.", newKey, err),
+					))
+				}
+			}
+
+			newDir := filepath.Join(parentNew.Dir, baseDirRel)
+			log.Printf("[TRACE] relative reference for %s rewritten from %s to %s", newKey, record.Dir, newDir)
+			newRecord := record // shallow copy
+			newRecord.Dir = newDir
+			newRecord.Key = newKey
+			retManifest[newKey] = newRecord
+			hooks.Install(newRecord.Key, newRecord.Version, newRecord.Dir)
+			continue
+		}
+
+		err = os.MkdirAll(instPath, os.ModePerm)
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to create module install directory",
+				fmt.Sprintf("Error creating directory %s for module %s: %s.", instPath, newKey, err),
+			))
+			continue
+		}
+
+		// We copy rather than "rename" here because renaming between directories
+		// can be tricky in edge-cases like network filesystems, etc.
+		log.Printf("[TRACE] copying new module %s from %s to %s", newKey, record.Dir, instPath)
+		err := copy.CopyDir(instPath, tempPath)
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to copy descendent module",
+				fmt.Sprintf("Error copying module %q from %s to %s: %s.", newKey, tempPath, rootDir, err),
+			))
+			continue
+		}
+
+		subDir, err := filepath.Rel(tempPath, record.Dir)
+		if err != nil {
+			// Should never happen, because we constructed both directories
+			// from the same base and so they must have a common prefix.
+			panic(err)
+		}
+
+		newRecord := record // shallow copy
+		newRecord.Dir = filepath.Join(instPath, subDir)
+		newRecord.Key = newKey
+		retManifest[newKey] = newRecord
+		hooks.Install(newRecord.Key, newRecord.Version, newRecord.Dir)
+	}
+
+	retManifest.WriteSnapshotToDir(modulesDir)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to write module manifest",
+			fmt.Sprintf("Error writing module manifest: %s.", err),
+		))
+	}
+
+	if !diags.HasErrors() {
+		// Try to clean up our temporary directory, but don't worry if we don't
+		// succeed since it shouldn't hurt anything.
+		os.RemoveAll(instDir)
+	}
+
+	return diags
+}
+
+func pathTraversesUp(path string) bool {
+	return strings.HasPrefix(filepath.ToSlash(path), "../")
+}
+
+// installHooksInitDir is an adapter wrapper for an InstallHooks that
+// does some fakery to make downloads look like they are happening in their
+// final locations, rather than in the temporary loader we use.
+//
+// It also suppresses "Install" calls entirely, since InitDirFromModule
+// does its own installation steps after the initial installation pass
+// has completed.
+type installHooksInitDir struct {
+	Wrapped ModuleInstallHooks
+	ModuleInstallHooksImpl
+}
+
+func (h installHooksInitDir) Download(moduleAddr, packageAddr string, version *version.Version) {
+	if !strings.HasPrefix(moduleAddr, initFromModuleRootKeyPrefix) {
+		// We won't announce the root module, since hook implementations
+		// don't expect to see that and the caller will usually have produced
+		// its own user-facing notification about what it's doing anyway.
+		return
+	}
+
+	trimAddr := moduleAddr[len(initFromModuleRootKeyPrefix):]
+	h.Wrapped.Download(trimAddr, packageAddr, version)
+}
diff --git a/v1.5.7/internal/initwd/from_module_test.go b/v1.5.7/internal/initwd/from_module_test.go
new file mode 100644
index 0000000..2cf6f5e
--- /dev/null
+++ b/v1.5.7/internal/initwd/from_module_test.go
@@ -0,0 +1,307 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package initwd
+
+import (
+	"context"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/copy"
+	"github.com/hashicorp/terraform/internal/registry"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestDirFromModule_registry(t *testing.T) {
+	if os.Getenv("TF_ACC") == "" {
+		t.Skip("this test accesses registry.terraform.io and github.com; set TF_ACC=1 to run it")
+	}
+
+	fixtureDir := filepath.Clean("testdata/empty")
+	tmpDir, done := tempChdir(t, fixtureDir)
+	defer done()
+
+	// the module installer runs filepath.EvalSymlinks() on the destination
+	// directory before copying files, and the resultant directory is what is
+	// returned by the install hooks. Without this, tests could fail on machines
+	// where the default temp dir was a symlink.
+	dir, err := filepath.EvalSymlinks(tmpDir)
+	if err != nil {
+		t.Error(err)
+	}
+	modsDir := filepath.Join(dir, ".terraform/modules")
+
+	hooks := &testInstallHooks{}
+
+	reg := registry.NewClient(nil, nil)
+	loader, cleanup := configload.NewLoaderForTests(t)
+	defer cleanup()
+	diags := DirFromModule(context.Background(), loader, dir, modsDir, "hashicorp/module-installer-acctest/aws//examples/main", reg, hooks)
+	assertNoDiagnostics(t, diags)
+
+	v := version.Must(version.NewVersion("0.0.2"))
+
+	wantCalls := []testInstallHookCall{
+		// The module specified to populate the root directory is not mentioned
+		// here, because the hook mechanism is defined to talk about descendent
+		// modules only and so a caller to InitDirFromModule is expected to
+		// produce its own user-facing announcement about the root module being
+		// installed.
+
+		// Note that "root" in the following examples is, confusingly, the
+		// label on the module block in the example we've installed here:
+		//     module "root" {
+
+		{
+			Name:        "Download",
+			ModuleAddr:  "root",
+			PackageAddr: "registry.terraform.io/hashicorp/module-installer-acctest/aws",
+			Version:     v,
+		},
+		{
+			Name:       "Install",
+			ModuleAddr: "root",
+			Version:    v,
+			// NOTE: This local path and the other paths derived from it below
+			// can vary depending on how the registry is implemented. At the
+			// time of writing this test, registry.terraform.io returns
+			// git repository source addresses and so this path refers to the
+			// root of the git clone, but historically the registry referred
+			// to GitHub-provided tar archives which meant that there was an
+			// extra level of subdirectory here for the typical directory
+			// nesting in tar archives, which would've been reflected as
+			// an extra segment on this path. If this test fails due to an
+			// additional path segment in future, then a change to the upstream
+			// registry might be the root cause.
+			LocalPath: filepath.Join(dir, ".terraform/modules/root"),
+		},
+		{
+			Name:       "Install",
+			ModuleAddr: "root.child_a",
+			LocalPath:  filepath.Join(dir, ".terraform/modules/root/modules/child_a"),
+		},
+		{
+			Name:       "Install",
+			ModuleAddr: "root.child_a.child_b",
+			LocalPath:  filepath.Join(dir, ".terraform/modules/root/modules/child_b"),
+		},
+	}
+
+	if diff := cmp.Diff(wantCalls, hooks.Calls); diff != "" {
+		t.Fatalf("wrong installer calls\n%s", diff)
+	}
+
+	loader, err = configload.NewLoader(&configload.Config{
+		ModulesDir: modsDir,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Make sure the configuration is loadable now.
+	// (This ensures that correct information is recorded in the manifest.)
+	config, loadDiags := loader.LoadConfig(".")
+	if assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) {
+		return
+	}
+
+	wantTraces := map[string]string{
+		"":                     "in example",
+		"root":                 "in root module",
+		"root.child_a":         "in child_a module",
+		"root.child_a.child_b": "in child_b module",
+	}
+	gotTraces := map[string]string{}
+	config.DeepEach(func(c *configs.Config) {
+		path := strings.Join(c.Path, ".")
+		if c.Module.Variables["v"] == nil {
+			gotTraces[path] = "<missing>"
+			return
+		}
+		varDesc := c.Module.Variables["v"].Description
+		gotTraces[path] = varDesc
+	})
+	assertResultDeepEqual(t, gotTraces, wantTraces)
+}
+
+func TestDirFromModule_submodules(t *testing.T) {
+	fixtureDir := filepath.Clean("testdata/empty")
+	fromModuleDir, err := filepath.Abs("./testdata/local-modules")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// DirFromModule will expand ("canonicalize") the pathnames, so we must do
+	// the same for our "wantCalls" comparison values. Otherwise this test
+	// will fail when building in a source tree with symlinks in $PWD.
+	//
+	// See also: https://github.com/hashicorp/terraform/issues/26014
+	//
+	fromModuleDirRealpath, err := filepath.EvalSymlinks(fromModuleDir)
+	if err != nil {
+		t.Error(err)
+	}
+
+	tmpDir, done := tempChdir(t, fixtureDir)
+	defer done()
+
+	hooks := &testInstallHooks{}
+	dir, err := filepath.EvalSymlinks(tmpDir)
+	if err != nil {
+		t.Error(err)
+	}
+	modInstallDir := filepath.Join(dir, ".terraform/modules")
+
+	loader, cleanup := configload.NewLoaderForTests(t)
+	defer cleanup()
+	diags := DirFromModule(context.Background(), loader, dir, modInstallDir, fromModuleDir, nil, hooks)
+	assertNoDiagnostics(t, diags)
+	wantCalls := []testInstallHookCall{
+		{
+			Name:       "Install",
+			ModuleAddr: "child_a",
+			LocalPath:  filepath.Join(fromModuleDirRealpath, "child_a"),
+		},
+		{
+			Name:       "Install",
+			ModuleAddr: "child_a.child_b",
+			LocalPath:  filepath.Join(fromModuleDirRealpath, "child_a/child_b"),
+		},
+	}
+
+	if assertResultDeepEqual(t, hooks.Calls, wantCalls) {
+		return
+	}
+
+	loader, err = configload.NewLoader(&configload.Config{
+		ModulesDir: modInstallDir,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Make sure the configuration is loadable now.
+	// (This ensures that correct information is recorded in the manifest.)
+	config, loadDiags := loader.LoadConfig(".")
+	if assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) {
+		return
+	}
+	wantTraces := map[string]string{
+		"":                "in root module",
+		"child_a":         "in child_a module",
+		"child_a.child_b": "in child_b module",
+	}
+	gotTraces := map[string]string{}
+
+	config.DeepEach(func(c *configs.Config) {
+		path := strings.Join(c.Path, ".")
+		if c.Module.Variables["v"] == nil {
+			gotTraces[path] = "<missing>"
+			return
+		}
+		varDesc := c.Module.Variables["v"].Description
+		gotTraces[path] = varDesc
+	})
+	assertResultDeepEqual(t, gotTraces, wantTraces)
+}
+
+// TestDirFromModule_rel_submodules is similar to the test above, but the
+// from-module is relative to the install dir ("../"):
+// https://github.com/hashicorp/terraform/issues/23010
+func TestDirFromModule_rel_submodules(t *testing.T) {
+	// This test creates a tmpdir with the following directory structure:
+	// - tmpdir/local-modules (with contents of testdata/local-modules)
+	// - tmpdir/empty: the workDir we CD into for the test
+	// - tmpdir/empty/target (target, the destination for init -from-module)
+	tmpDir := t.TempDir()
+	fromModuleDir := filepath.Join(tmpDir, "local-modules")
+	workDir := filepath.Join(tmpDir, "empty")
+	if err := os.Mkdir(fromModuleDir, os.ModePerm); err != nil {
+		t.Fatal(err)
+	}
+	if err := copy.CopyDir(fromModuleDir, "testdata/local-modules"); err != nil {
+		t.Fatal(err)
+	}
+	if err := os.Mkdir(workDir, os.ModePerm); err != nil {
+		t.Fatal(err)
+	}
+
+	targetDir := filepath.Join(tmpDir, "target")
+	if err := os.Mkdir(targetDir, os.ModePerm); err != nil {
+		t.Fatal(err)
+	}
+	oldDir, err := os.Getwd()
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = os.Chdir(targetDir)
+	if err != nil {
+		t.Fatalf("failed to switch to temp dir %s: %s", tmpDir, err)
+	}
+	t.Cleanup(func() {
+		os.Chdir(oldDir)
+	})
+
+	hooks := &testInstallHooks{}
+
+	modInstallDir := ".terraform/modules"
+	sourceDir := "../local-modules"
+	loader, cleanup := configload.NewLoaderForTests(t)
+	defer cleanup()
+	diags := DirFromModule(context.Background(), loader, ".", modInstallDir, sourceDir, nil, hooks)
+	assertNoDiagnostics(t, diags)
+	wantCalls := []testInstallHookCall{
+		{
+			Name:       "Install",
+			ModuleAddr: "child_a",
+			LocalPath:  filepath.Join(sourceDir, "child_a"),
+		},
+		{
+			Name:       "Install",
+			ModuleAddr: "child_a.child_b",
+			LocalPath:  filepath.Join(sourceDir, "child_a/child_b"),
+		},
+	}
+
+	if assertResultDeepEqual(t, hooks.Calls, wantCalls) {
+		return
+	}
+
+	loader, err = configload.NewLoader(&configload.Config{
+		ModulesDir: modInstallDir,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Make sure the configuration is loadable now.
+	// (This ensures that correct information is recorded in the manifest.)
+	config, loadDiags := loader.LoadConfig(".")
+	if assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) {
+		return
+	}
+	wantTraces := map[string]string{
+		"":                "in root module",
+		"child_a":         "in child_a module",
+		"child_a.child_b": "in child_b module",
+	}
+	gotTraces := map[string]string{}
+
+	config.DeepEach(func(c *configs.Config) {
+		path := strings.Join(c.Path, ".")
+		if c.Module.Variables["v"] == nil {
+			gotTraces[path] = "<missing>"
+			return
+		}
+		varDesc := c.Module.Variables["v"].Description
+		gotTraces[path] = varDesc
+	})
+	assertResultDeepEqual(t, gotTraces, wantTraces)
+}
diff --git a/v1.5.7/internal/initwd/module_install.go b/v1.5.7/internal/initwd/module_install.go
new file mode 100644
index 0000000..28f9cb6
--- /dev/null
+++ b/v1.5.7/internal/initwd/module_install.go
@@ -0,0 +1,891 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package initwd
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"log"
+	"os"
+	"path"
+	"path/filepath"
+	"strings"
+
+	"github.com/apparentlymart/go-versions/versions"
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/getmodules"
+	"github.com/hashicorp/terraform/internal/modsdir"
+	"github.com/hashicorp/terraform/internal/registry"
+	"github.com/hashicorp/terraform/internal/registry/regsrc"
+	"github.com/hashicorp/terraform/internal/registry/response"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+type ModuleInstaller struct {
+	modsDir string
+	loader  *configload.Loader
+	reg     *registry.Client
+
+	// The keys in moduleVersions are resolved and trimmed registry source
+	// addresses and the values are the registry response.
+	registryPackageVersions map[addrs.ModuleRegistryPackage]*response.ModuleVersions
+
+	// The keys in moduleVersionsUrl are the moduleVersion struct below and
+	// addresses and the values are underlying remote source addresses.
+	registryPackageSources map[moduleVersion]addrs.ModuleSourceRemote
+}
+
+type moduleVersion struct {
+	module  addrs.ModuleRegistryPackage
+	version string
+}
+
+func NewModuleInstaller(modsDir string, loader *configload.Loader, reg *registry.Client) *ModuleInstaller {
+	return &ModuleInstaller{
+		modsDir:                 modsDir,
+		loader:                  loader,
+		reg:                     reg,
+		registryPackageVersions: make(map[addrs.ModuleRegistryPackage]*response.ModuleVersions),
+		registryPackageSources:  make(map[moduleVersion]addrs.ModuleSourceRemote),
+	}
+}
+
+// InstallModules analyses the root module in the given directory and installs
+// all of its direct and transitive dependencies into the given modules
+// directory, which must already exist.
+//
+// Since InstallModules makes possibly-time-consuming calls to remote services,
+// a hook interface is supported to allow the caller to be notified when
+// each module is installed and, for remote modules, when downloading begins.
+// LoadConfig guarantees that two hook calls will not happen concurrently but
+// it does not guarantee any particular ordering of hook calls. This mechanism
+// is for UI feedback only and does not give the caller any control over the
+// process.
+//
+// If modules are already installed in the target directory, they will be
+// skipped unless their source address or version have changed or unless
+// the upgrade flag is set.
+//
+// InstallModules never deletes any directory, except in the case where it
+// needs to replace a directory that is already present with a newly-extracted
+// package.
+//
+// If the returned diagnostics contains errors then the module installation
+// may have wholly or partially completed. Modules must be loaded in order
+// to find their dependencies, so this function does many of the same checks
+// as LoadConfig as a side-effect.
+//
+// If successful (the returned diagnostics contains no errors) then the
+// first return value is the early configuration tree that was constructed by
+// the installation process.
+func (i *ModuleInstaller) InstallModules(ctx context.Context, rootDir string, upgrade bool, hooks ModuleInstallHooks) (*configs.Config, tfdiags.Diagnostics) {
+	log.Printf("[TRACE] ModuleInstaller: installing child modules for %s into %s", rootDir, i.modsDir)
+	var diags tfdiags.Diagnostics
+
+	rootMod, mDiags := i.loader.Parser().LoadConfigDir(rootDir)
+	if rootMod == nil {
+		// We drop the diagnostics here because we only want to report module
+		// loading errors after checking the core version constraints, which we
+		// can only do if the module can be at least partially loaded.
+		return nil, diags
+	} else if vDiags := rootMod.CheckCoreVersionRequirements(nil, nil); vDiags.HasErrors() {
+		// If the core version requirements are not met, we drop any other
+		// diagnostics, as they may reflect language changes from future
+		// Terraform versions.
+		diags = diags.Append(vDiags)
+	} else {
+		diags = diags.Append(mDiags)
+	}
+
+	manifest, err := modsdir.ReadManifestSnapshotForDir(i.modsDir)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to read modules manifest file",
+			fmt.Sprintf("Error reading manifest for %s: %s.", i.modsDir, err),
+		))
+		return nil, diags
+	}
+
+	fetcher := getmodules.NewPackageFetcher()
+	cfg, instDiags := i.installDescendentModules(ctx, rootMod, rootDir, manifest, upgrade, hooks, fetcher)
+	diags = append(diags, instDiags...)
+
+	return cfg, diags
+}
+
+func (i *ModuleInstaller) installDescendentModules(ctx context.Context, rootMod *configs.Module, rootDir string, manifest modsdir.Manifest, upgrade bool, hooks ModuleInstallHooks, fetcher *getmodules.PackageFetcher) (*configs.Config, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	if hooks == nil {
+		// Use our no-op implementation as a placeholder
+		hooks = ModuleInstallHooksImpl{}
+	}
+
+	// Create a manifest record for the root module. This will be used if
+	// there are any relative-pathed modules in the root.
+	manifest[""] = modsdir.Record{
+		Key: "",
+		Dir: rootDir,
+	}
+
+	cfg, cDiags := configs.BuildConfig(rootMod, configs.ModuleWalkerFunc(
+		func(req *configs.ModuleRequest) (*configs.Module, *version.Version, hcl.Diagnostics) {
+			var diags hcl.Diagnostics
+
+			if req.SourceAddr == nil {
+				// If the parent module failed to parse the module source
+				// address, we can't load it here. Return nothing as the parent
+				// module's diagnostics should explain this.
+				return nil, nil, diags
+			}
+
+			if req.Name == "" {
+				// An empty string for a module instance name breaks our
+				// manifest map, which uses that to indicate the root module.
+				// Because we descend into modules which have errors, we need
+				// to look out for this case, but the config loader's
+				// diagnostics will report the error later.
+				return nil, nil, diags
+			}
+
+			if !hclsyntax.ValidIdentifier(req.Name) {
+				// A module with an invalid name shouldn't be installed at all. This is
+				// mostly a concern for remote modules, since we need to be able to convert
+				// the name to a valid path.
+				return nil, nil, diags
+			}
+
+			key := manifest.ModuleKey(req.Path)
+			instPath := i.packageInstallPath(req.Path)
+
+			log.Printf("[DEBUG] Module installer: begin %s", key)
+
+			// First we'll check if we need to upgrade/replace an existing
+			// installed module, and delete it out of the way if so.
+			replace := upgrade
+			if !replace {
+				record, recorded := manifest[key]
+				switch {
+				case !recorded:
+					log.Printf("[TRACE] ModuleInstaller: %s is not yet installed", key)
+					replace = true
+				case record.SourceAddr != req.SourceAddr.String():
+					log.Printf("[TRACE] ModuleInstaller: %s source address has changed from %q to %q", key, record.SourceAddr, req.SourceAddr)
+					replace = true
+				case record.Version != nil && !req.VersionConstraint.Required.Check(record.Version):
+					log.Printf("[TRACE] ModuleInstaller: %s version %s no longer compatible with constraints %s", key, record.Version, req.VersionConstraint.Required)
+					replace = true
+				}
+			}
+
+			// If we _are_ planning to replace this module, then we'll remove
+			// it now so our installation code below won't conflict with any
+			// existing remnants.
+			if replace {
+				if _, recorded := manifest[key]; recorded {
+					log.Printf("[TRACE] ModuleInstaller: discarding previous record of %s prior to reinstall", key)
+				}
+				delete(manifest, key)
+				// Deleting a module invalidates all of its descendent modules too.
+				keyPrefix := key + "."
+				for subKey := range manifest {
+					if strings.HasPrefix(subKey, keyPrefix) {
+						if _, recorded := manifest[subKey]; recorded {
+							log.Printf("[TRACE] ModuleInstaller: also discarding downstream %s", subKey)
+						}
+						delete(manifest, subKey)
+					}
+				}
+			}
+
+			record, recorded := manifest[key]
+			if !recorded {
+				// Clean up any stale cache directory that might be present.
+				// If this is a local (relative) source then the dir will
+				// not exist, but we'll ignore that.
+				log.Printf("[TRACE] ModuleInstaller: cleaning directory %s prior to install of %s", instPath, key)
+				err := os.RemoveAll(instPath)
+				if err != nil && !os.IsNotExist(err) {
+					log.Printf("[TRACE] ModuleInstaller: failed to remove %s: %s", key, err)
+					diags = diags.Append(&hcl.Diagnostic{
+						Severity: hcl.DiagError,
+						Summary:  "Failed to remove local module cache",
+						Detail: fmt.Sprintf(
+							"Terraform tried to remove %s in order to reinstall this module, but encountered an error: %s",
+							instPath, err,
+						),
+					})
+					return nil, nil, diags
+				}
+			} else {
+				// If this module is already recorded and its root directory
+				// exists then we will just load what's already there and
+				// keep our existing record.
+				info, err := os.Stat(record.Dir)
+				if err == nil && info.IsDir() {
+					mod, mDiags := i.loader.Parser().LoadConfigDir(record.Dir)
+					if mod == nil {
+						// nil indicates an unreadable module, which should never happen,
+						// so we return the full loader diagnostics here.
+						diags = diags.Extend(mDiags)
+					} else if vDiags := mod.CheckCoreVersionRequirements(req.Path, req.SourceAddr); vDiags.HasErrors() {
+						// If the core version requirements are not met, we drop any other
+						// diagnostics, as they may reflect language changes from future
+						// Terraform versions.
+						diags = diags.Extend(vDiags)
+					} else {
+						diags = diags.Extend(mDiags)
+					}
+
+					log.Printf("[TRACE] ModuleInstaller: Module installer: %s %s already installed in %s", key, record.Version, record.Dir)
+					return mod, record.Version, diags
+				}
+			}
+
+			// If we get down here then it's finally time to actually install
+			// the module. There are some variants to this process depending
+			// on what type of module source address we have.
+
+			switch addr := req.SourceAddr.(type) {
+
+			case addrs.ModuleSourceLocal:
+				log.Printf("[TRACE] ModuleInstaller: %s has local path %q", key, addr.String())
+				mod, mDiags := i.installLocalModule(req, key, manifest, hooks)
+				mDiags = maybeImproveLocalInstallError(req, mDiags)
+				diags = append(diags, mDiags...)
+				return mod, nil, diags
+
+			case addrs.ModuleSourceRegistry:
+				log.Printf("[TRACE] ModuleInstaller: %s is a registry module at %s", key, addr.String())
+				mod, v, mDiags := i.installRegistryModule(ctx, req, key, instPath, addr, manifest, hooks, fetcher)
+				diags = append(diags, mDiags...)
+				return mod, v, diags
+
+			case addrs.ModuleSourceRemote:
+				log.Printf("[TRACE] ModuleInstaller: %s address %q will be handled by go-getter", key, addr.String())
+				mod, mDiags := i.installGoGetterModule(ctx, req, key, instPath, manifest, hooks, fetcher)
+				diags = append(diags, mDiags...)
+				return mod, nil, diags
+
+			default:
+				// Shouldn't get here, because there are no other implementations
+				// of addrs.ModuleSource.
+				panic(fmt.Sprintf("unsupported module source address %#v", addr))
+			}
+
+		},
+	))
+	diags = diags.Append(cDiags)
+
+	err := manifest.WriteSnapshotToDir(i.modsDir)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to update module manifest",
+			fmt.Sprintf("Unable to write the module manifest file: %s", err),
+		))
+	}
+
+	return cfg, diags
+}
+
+func (i *ModuleInstaller) installLocalModule(req *configs.ModuleRequest, key string, manifest modsdir.Manifest, hooks ModuleInstallHooks) (*configs.Module, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+
+	parentKey := manifest.ModuleKey(req.Parent.Path)
+	parentRecord, recorded := manifest[parentKey]
+	if !recorded {
+		// This is indicative of a bug rather than a user-actionable error
+		panic(fmt.Errorf("missing manifest record for parent module %s", parentKey))
+	}
+
+	if len(req.VersionConstraint.Required) != 0 {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid version constraint",
+			Detail:   fmt.Sprintf("Cannot apply a version constraint to module %q (at %s:%d) because it has a relative local path.", req.Name, req.CallRange.Filename, req.CallRange.Start.Line),
+			Subject:  req.CallRange.Ptr(),
+		})
+	}
+
+	// For local sources we don't actually need to modify the
+	// filesystem at all because the parent already wrote
+	// the files we need, and so we just load up what's already here.
+	newDir := filepath.Join(parentRecord.Dir, req.SourceAddr.String())
+
+	log.Printf("[TRACE] ModuleInstaller: %s uses directory from parent: %s", key, newDir)
+	// it is possible that the local directory is a symlink
+	newDir, err := filepath.EvalSymlinks(newDir)
+	if err != nil {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Unreadable module directory",
+			Detail:   fmt.Sprintf("Unable to evaluate directory symlink: %s", err.Error()),
+		})
+	}
+
+	// Finally we are ready to try actually loading the module.
+	mod, mDiags := i.loader.Parser().LoadConfigDir(newDir)
+	if mod == nil {
+		// nil indicates missing or unreadable directory, so we'll
+		// discard the returned diags and return a more specific
+		// error message here.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Unreadable module directory",
+			Detail:   fmt.Sprintf("The directory %s could not be read for module %q at %s:%d.", newDir, req.Name, req.CallRange.Filename, req.CallRange.Start.Line),
+		})
+	} else if vDiags := mod.CheckCoreVersionRequirements(req.Path, req.SourceAddr); vDiags.HasErrors() {
+		// If the core version requirements are not met, we drop any other
+		// diagnostics, as they may reflect language changes from future
+		// Terraform versions.
+		diags = diags.Extend(vDiags)
+	} else {
+		diags = diags.Extend(mDiags)
+	}
+
+	// Note the local location in our manifest.
+	manifest[key] = modsdir.Record{
+		Key:        key,
+		Dir:        newDir,
+		SourceAddr: req.SourceAddr.String(),
+	}
+	log.Printf("[DEBUG] Module installer: %s installed at %s", key, newDir)
+	hooks.Install(key, nil, newDir)
+
+	return mod, diags
+}
+
+func (i *ModuleInstaller) installRegistryModule(ctx context.Context, req *configs.ModuleRequest, key string, instPath string, addr addrs.ModuleSourceRegistry, manifest modsdir.Manifest, hooks ModuleInstallHooks, fetcher *getmodules.PackageFetcher) (*configs.Module, *version.Version, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+
+	hostname := addr.Package.Host
+	reg := i.reg
+	var resp *response.ModuleVersions
+	var exists bool
+
+	// A registry entry isn't _really_ a module package, but we'll pretend it's
+	// one for the sake of this reporting by just trimming off any source
+	// directory.
+	packageAddr := addr.Package
+
+	// Our registry client is still using the legacy model of addresses, so
+	// we'll shim it here for now.
+	regsrcAddr := regsrc.ModuleFromRegistryPackageAddr(packageAddr)
+
+	// check if we've already looked up this module from the registry
+	if resp, exists = i.registryPackageVersions[packageAddr]; exists {
+		log.Printf("[TRACE] %s using already found available versions of %s at %s", key, addr, hostname)
+	} else {
+		var err error
+		log.Printf("[DEBUG] %s listing available versions of %s at %s", key, addr, hostname)
+		resp, err = reg.ModuleVersions(ctx, regsrcAddr)
+		if err != nil {
+			if registry.IsModuleNotFound(err) {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Module not found",
+					Detail:   fmt.Sprintf("Module %q (from %s:%d) cannot be found in the module registry at %s.", req.Name, req.CallRange.Filename, req.CallRange.Start.Line, hostname),
+					Subject:  req.CallRange.Ptr(),
+				})
+			} else if errors.Is(err, context.Canceled) {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Module installation was interrupted",
+					Detail:   fmt.Sprintf("Received interrupt signal while retrieving available versions for module %q.", req.Name),
+				})
+			} else {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Error accessing remote module registry",
+					Detail:   fmt.Sprintf("Failed to retrieve available versions for module %q (%s:%d) from %s: %s.", req.Name, req.CallRange.Filename, req.CallRange.Start.Line, hostname, err),
+					Subject:  req.CallRange.Ptr(),
+				})
+			}
+			return nil, nil, diags
+		}
+		i.registryPackageVersions[packageAddr] = resp
+	}
+
+	// The response might contain information about dependencies to allow us
+	// to potentially optimize future requests, but we don't currently do that
+	// and so for now we'll just take the first item which is guaranteed to
+	// be the address we requested.
+	if len(resp.Modules) < 1 {
+		// Should never happen, but since this is a remote service that may
+		// be implemented by third-parties we will handle it gracefully.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid response from remote module registry",
+			Detail:   fmt.Sprintf("The registry at %s returned an invalid response when Terraform requested available versions for module %q (%s:%d).", hostname, req.Name, req.CallRange.Filename, req.CallRange.Start.Line),
+			Subject:  req.CallRange.Ptr(),
+		})
+		return nil, nil, diags
+	}
+
+	modMeta := resp.Modules[0]
+
+	var latestMatch *version.Version
+	var latestVersion *version.Version
+	for _, mv := range modMeta.Versions {
+		v, err := version.NewVersion(mv.Version)
+		if err != nil {
+			// Should never happen if the registry server is compliant with
+			// the protocol, but we'll warn if not to assist someone who
+			// might be developing a module registry server.
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagWarning,
+				Summary:  "Invalid response from remote module registry",
+				Detail:   fmt.Sprintf("The registry at %s returned an invalid version string %q for module %q (%s:%d), which Terraform ignored.", hostname, mv.Version, req.Name, req.CallRange.Filename, req.CallRange.Start.Line),
+				Subject:  req.CallRange.Ptr(),
+			})
+			continue
+		}
+
+		// If we've found a pre-release version then we'll ignore it unless
+		// it was exactly requested.
+		//
+		// The prerelease checking will be handled by a different library for
+		// 2 reasons. First, this other library automatically includes the
+		// "prerelease versions must be exactly requested" behaviour that we are
+		// looking for. Second, this other library is used to handle all version
+		// constraints for the provider logic and this is the first step to
+		// making the module and provider version logic match.
+		if v.Prerelease() != "" {
+			// At this point all versions published by the module with
+			// prerelease metadata will be checked. Users may not have even
+			// requested this prerelease so don't print lots of unnecessary #
+			// warnings.
+			acceptableVersions, err := versions.MeetingConstraintsString(req.VersionConstraint.Required.String())
+			if err != nil {
+				log.Printf("[WARN] ModuleInstaller: %s ignoring %s because the version constraints (%s) could not be parsed: %s", key, v, req.VersionConstraint.Required.String(), err.Error())
+				continue
+			}
+
+			// Validate the version is also readable by the other versions
+			// library.
+			version, err := versions.ParseVersion(v.String())
+			if err != nil {
+				log.Printf("[WARN] ModuleInstaller: %s ignoring %s because the version (%s) reported by the module could not be parsed: %s", key, v, v.String(), err.Error())
+				continue
+			}
+
+			// Finally, check if the prerelease is acceptable to version. As
+			// highlighted previously, we go through all of this because the
+			// apparentlymart/go-versions library handles prerelease constraints
+			// in the apporach we want to.
+			if !acceptableVersions.Has(version) {
+				log.Printf("[TRACE] ModuleInstaller: %s ignoring %s because it is a pre-release and was not requested exactly", key, v)
+				continue
+			}
+
+			// If we reach here, it means this prerelease version was exactly
+			// requested according to the extra constraints of this library.
+			// We fall through and allow the other library to also validate it
+			// for consistency.
+		}
+
+		if latestVersion == nil || v.GreaterThan(latestVersion) {
+			latestVersion = v
+		}
+
+		if req.VersionConstraint.Required.Check(v) {
+			if latestMatch == nil || v.GreaterThan(latestMatch) {
+				latestMatch = v
+			}
+		}
+	}
+
+	if latestVersion == nil {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Module has no versions",
+			Detail:   fmt.Sprintf("Module %q (%s:%d) has no versions available on %s.", addr, req.CallRange.Filename, req.CallRange.Start.Line, hostname),
+			Subject:  req.CallRange.Ptr(),
+		})
+		return nil, nil, diags
+	}
+
+	if latestMatch == nil {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Unresolvable module version constraint",
+			Detail:   fmt.Sprintf("There is no available version of module %q (%s:%d) which matches the given version constraint. The newest available version is %s.", addr, req.CallRange.Filename, req.CallRange.Start.Line, latestVersion),
+			Subject:  req.CallRange.Ptr(),
+		})
+		return nil, nil, diags
+	}
+
+	// Report up to the caller that we're about to start downloading.
+	hooks.Download(key, packageAddr.String(), latestMatch)
+
+	// If we manage to get down here then we've found a suitable version to
+	// install, so we need to ask the registry where we should download it from.
+	// The response to this is a go-getter-style address string.
+
+	// first check the cache for the download URL
+	moduleAddr := moduleVersion{module: packageAddr, version: latestMatch.String()}
+	if _, exists := i.registryPackageSources[moduleAddr]; !exists {
+		realAddrRaw, err := reg.ModuleLocation(ctx, regsrcAddr, latestMatch.String())
+		if err != nil {
+			log.Printf("[ERROR] %s from %s %s: %s", key, addr, latestMatch, err)
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Error accessing remote module registry",
+				Detail:   fmt.Sprintf("Failed to retrieve a download URL for %s %s from %s: %s", addr, latestMatch, hostname, err),
+			})
+			return nil, nil, diags
+		}
+		realAddr, err := addrs.ParseModuleSource(realAddrRaw)
+		if err != nil {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid package location from module registry",
+				Detail:   fmt.Sprintf("Module registry %s returned invalid source location %q for %s %s: %s.", hostname, realAddrRaw, addr, latestMatch, err),
+			})
+			return nil, nil, diags
+		}
+		switch realAddr := realAddr.(type) {
+		// Only a remote source address is allowed here: a registry isn't
+		// allowed to return a local path (because it doesn't know what
+		// its being called from) and we also don't allow recursively pointing
+		// at another registry source for simplicity's sake.
+		case addrs.ModuleSourceRemote:
+			i.registryPackageSources[moduleAddr] = realAddr
+		default:
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid package location from module registry",
+				Detail:   fmt.Sprintf("Module registry %s returned invalid source location %q for %s %s: must be a direct remote package address.", hostname, realAddrRaw, addr, latestMatch),
+			})
+			return nil, nil, diags
+		}
+	}
+
+	dlAddr := i.registryPackageSources[moduleAddr]
+
+	log.Printf("[TRACE] ModuleInstaller: %s %s %s is available at %q", key, packageAddr, latestMatch, dlAddr.Package)
+
+	err := fetcher.FetchPackage(ctx, instPath, dlAddr.Package.String())
+	if errors.Is(err, context.Canceled) {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Module download was interrupted",
+			Detail:   fmt.Sprintf("Interrupt signal received when downloading module %s.", addr),
+		})
+		return nil, nil, diags
+	}
+	if err != nil {
+		// Errors returned by go-getter have very inconsistent quality as
+		// end-user error messages, but for now we're accepting that because
+		// we have no way to recognize any specific errors to improve them
+		// and masking the error entirely would hide valuable diagnostic
+		// information from the user.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Failed to download module",
+			Detail:   fmt.Sprintf("Could not download module %q (%s:%d) source code from %q: %s.", req.Name, req.CallRange.Filename, req.CallRange.Start.Line, dlAddr, err),
+			Subject:  req.CallRange.Ptr(),
+		})
+		return nil, nil, diags
+	}
+
+	log.Printf("[TRACE] ModuleInstaller: %s %q was downloaded to %s", key, dlAddr.Package, instPath)
+
+	// Incorporate any subdir information from the original path into the
+	// address returned by the registry in order to find the final directory
+	// of the target module.
+	finalAddr := dlAddr.FromRegistry(addr)
+	subDir := filepath.FromSlash(finalAddr.Subdir)
+	modDir := filepath.Join(instPath, subDir)
+
+	log.Printf("[TRACE] ModuleInstaller: %s should now be at %s", key, modDir)
+
+	// Finally we are ready to try actually loading the module.
+	mod, mDiags := i.loader.Parser().LoadConfigDir(modDir)
+	if mod == nil {
+		// nil indicates missing or unreadable directory, so we'll
+		// discard the returned diags and return a more specific
+		// error message here. For registry modules this actually
+		// indicates a bug in the code above, since it's not the
+		// user's responsibility to create the directory in this case.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Unreadable module directory",
+			Detail:   fmt.Sprintf("The directory %s could not be read. This is a bug in Terraform and should be reported.", modDir),
+		})
+	} else if vDiags := mod.CheckCoreVersionRequirements(req.Path, req.SourceAddr); vDiags.HasErrors() {
+		// If the core version requirements are not met, we drop any other
+		// diagnostics, as they may reflect language changes from future
+		// Terraform versions.
+		diags = diags.Extend(vDiags)
+	} else {
+		diags = diags.Extend(mDiags)
+	}
+
+	// Note the local location in our manifest.
+	manifest[key] = modsdir.Record{
+		Key:        key,
+		Version:    latestMatch,
+		Dir:        modDir,
+		SourceAddr: req.SourceAddr.String(),
+	}
+	log.Printf("[DEBUG] Module installer: %s installed at %s", key, modDir)
+	hooks.Install(key, latestMatch, modDir)
+
+	return mod, latestMatch, diags
+}
+
+func (i *ModuleInstaller) installGoGetterModule(ctx context.Context, req *configs.ModuleRequest, key string, instPath string, manifest modsdir.Manifest, hooks ModuleInstallHooks, fetcher *getmodules.PackageFetcher) (*configs.Module, hcl.Diagnostics) {
+	var diags hcl.Diagnostics
+
+	// Report up to the caller that we're about to start downloading.
+	addr := req.SourceAddr.(addrs.ModuleSourceRemote)
+	packageAddr := addr.Package
+	hooks.Download(key, packageAddr.String(), nil)
+
+	if len(req.VersionConstraint.Required) != 0 {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid version constraint",
+			Detail:   fmt.Sprintf("Cannot apply a version constraint to module %q (at %s:%d) because it doesn't come from a module registry.", req.Name, req.CallRange.Filename, req.CallRange.Start.Line),
+			Subject:  req.CallRange.Ptr(),
+		})
+		return nil, diags
+	}
+
+	err := fetcher.FetchPackage(ctx, instPath, packageAddr.String())
+	if err != nil {
+		// go-getter generates a poor error for an invalid relative path, so
+		// we'll detect that case and generate a better one.
+		if _, ok := err.(*getmodules.MaybeRelativePathErr); ok {
+			log.Printf(
+				"[TRACE] ModuleInstaller: %s looks like a local path but is missing ./ or ../",
+				req.SourceAddr,
+			)
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Module not found",
+				Detail: fmt.Sprintf(
+					"The module address %q could not be resolved.\n\n"+
+						"If you intended this as a path relative to the current "+
+						"module, use \"./%s\" instead. The \"./\" prefix "+
+						"indicates that the address is a relative filesystem path.",
+					req.SourceAddr, req.SourceAddr,
+				),
+			})
+		} else {
+			// Errors returned by go-getter have very inconsistent quality as
+			// end-user error messages, but for now we're accepting that because
+			// we have no way to recognize any specific errors to improve them
+			// and masking the error entirely would hide valuable diagnostic
+			// information from the user.
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Failed to download module",
+				Detail:   fmt.Sprintf("Could not download module %q (%s:%d) source code from %q: %s", req.Name, req.CallRange.Filename, req.CallRange.Start.Line, packageAddr, err),
+				Subject:  req.CallRange.Ptr(),
+			})
+		}
+		return nil, diags
+	}
+
+	modDir, err := getmodules.ExpandSubdirGlobs(instPath, addr.Subdir)
+	if err != nil {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Failed to expand subdir globs",
+			Detail:   err.Error(),
+		})
+		return nil, diags
+	}
+
+	log.Printf("[TRACE] ModuleInstaller: %s %q was downloaded to %s", key, addr, modDir)
+
+	// Finally we are ready to try actually loading the module.
+	mod, mDiags := i.loader.Parser().LoadConfigDir(modDir)
+	if mod == nil {
+		// nil indicates missing or unreadable directory, so we'll
+		// discard the returned diags and return a more specific
+		// error message here. For go-getter modules this actually
+		// indicates a bug in the code above, since it's not the
+		// user's responsibility to create the directory in this case.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Unreadable module directory",
+			Detail:   fmt.Sprintf("The directory %s could not be read. This is a bug in Terraform and should be reported.", modDir),
+		})
+	} else if vDiags := mod.CheckCoreVersionRequirements(req.Path, req.SourceAddr); vDiags.HasErrors() {
+		// If the core version requirements are not met, we drop any other
+		// diagnostics, as they may reflect language changes from future
+		// Terraform versions.
+		diags = diags.Extend(vDiags)
+	} else {
+		diags = diags.Extend(mDiags)
+	}
+
+	// Note the local location in our manifest.
+	manifest[key] = modsdir.Record{
+		Key:        key,
+		Dir:        modDir,
+		SourceAddr: req.SourceAddr.String(),
+	}
+	log.Printf("[DEBUG] Module installer: %s installed at %s", key, modDir)
+	hooks.Install(key, nil, modDir)
+
+	return mod, diags
+}
+
+func (i *ModuleInstaller) packageInstallPath(modulePath addrs.Module) string {
+	return filepath.Join(i.modsDir, strings.Join(modulePath, "."))
+}
+
+// maybeImproveLocalInstallError is a helper function which can recognize
+// some specific situations where it can return a more helpful error message
+// and thus replace the given errors with those if so.
+//
+// If this function can't do anything about a particular situation then it
+// will just return the given diags verbatim.
+//
+// This function's behavior is only reasonable for errors returned from the
+// ModuleInstaller.installLocalModule function.
+func maybeImproveLocalInstallError(req *configs.ModuleRequest, diags hcl.Diagnostics) hcl.Diagnostics {
+	if !diags.HasErrors() {
+		return diags
+	}
+
+	// The main situation we're interested in detecting here is whether the
+	// current module or any of its ancestors use relative paths that reach
+	// outside of the "package" established by the nearest non-local ancestor.
+	// That's never really valid, but unfortunately we historically didn't
+	// have any explicit checking for it and so now for compatibility in
+	// situations where things just happened to "work" we treat this as an
+	// error only in situations where installation would've failed anyway,
+	// so we can give a better error about it than just a generic
+	// "directory not found" or whatever.
+	//
+	// Since it's never actually valid to relative out of the containing
+	// package, we just assume that any failed local package install which
+	// does so was caused by that, because to stop doing it should always
+	// improve the situation, even if it leads to another error describing
+	// a different problem.
+
+	// To decide this we need to find the subset of our ancestors that
+	// belong to the same "package" as our request, along with the closest
+	// ancestor that defined that package, and then we can work forwards
+	// to see if any of the local paths "escaped" the package.
+	type Step struct {
+		Path       addrs.Module
+		SourceAddr addrs.ModuleSource
+	}
+	var packageDefiner Step
+	var localRefs []Step
+	localRefs = append(localRefs, Step{
+		Path:       req.Path,
+		SourceAddr: req.SourceAddr,
+	})
+	current := req.Parent // a configs.Config where Children isn't populated yet
+	for {
+		if current == nil || current.SourceAddr == nil {
+			// We've reached the root module, in which case we aren't
+			// in an external "package" at all and so our special case
+			// can't apply.
+			return diags
+		}
+		if _, ok := current.SourceAddr.(addrs.ModuleSourceLocal); !ok {
+			// We've found the package definer, then!
+			packageDefiner = Step{
+				Path:       current.Path,
+				SourceAddr: current.SourceAddr,
+			}
+			break
+		}
+
+		localRefs = append(localRefs, Step{
+			Path:       current.Path,
+			SourceAddr: current.SourceAddr,
+		})
+		current = current.Parent
+	}
+	// Our localRefs list is reversed because we were traversing up the tree,
+	// so we'll flip it the other way and thus walk "downwards" through it.
+	for i, j := 0, len(localRefs)-1; i < j; i, j = i+1, j-1 {
+		localRefs[i], localRefs[j] = localRefs[j], localRefs[i]
+	}
+
+	// Our method here is to start with a known base path prefix and
+	// then apply each of the local refs to it in sequence until one of
+	// them causes us to "lose" the prefix. If that happens, we've found
+	// an escape to report. This is not an exact science but good enough
+	// heuristic for choosing a better error message.
+	const prefix = "*/" // NOTE: this can find a false negative if the user chooses "*" as a directory name, but we consider that unlikely
+	packageAddr, startPath := splitAddrSubdir(packageDefiner.SourceAddr)
+	currentPath := path.Join(prefix, startPath)
+	for _, step := range localRefs {
+		rel := step.SourceAddr.String()
+
+		nextPath := path.Join(currentPath, rel)
+		if !strings.HasPrefix(nextPath, prefix) { // ESCAPED!
+			escapeeAddr := step.Path.String()
+
+			var newDiags hcl.Diagnostics
+
+			// First we'll copy over any non-error diagnostics from the source diags
+			for _, diag := range diags {
+				if diag.Severity != hcl.DiagError {
+					newDiags = newDiags.Append(diag)
+				}
+			}
+
+			// ...but we'll replace any errors with this more precise error.
+			var suggestion string
+			if strings.HasPrefix(packageAddr, "/") || filepath.VolumeName(packageAddr) != "" {
+				// It might be somewhat surprising that Terraform treats
+				// absolute filesystem paths as "external" even though it
+				// treats relative paths as local, so if it seems like that's
+				// what the user was doing then we'll add an additional note
+				// about it.
+				suggestion = "\n\nTerraform treats absolute filesystem paths as external modules which establish a new module package. To treat this directory as part of the same package as its caller, use a local path starting with either \"./\" or \"../\"."
+			}
+			newDiags = newDiags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Local module path escapes module package",
+				Detail: fmt.Sprintf(
+					"The given source directory for %s would be outside of its containing package %q. Local source addresses starting with \"../\" must stay within the same package that the calling module belongs to.%s",
+					escapeeAddr, packageAddr, suggestion,
+				),
+			})
+
+			return newDiags
+		}
+
+		currentPath = nextPath
+	}
+
+	// If we get down here then we have nothing useful to do, so we'll just
+	// echo back what we were given.
+	return diags
+}
+
+func splitAddrSubdir(addr addrs.ModuleSource) (string, string) {
+	switch addr := addr.(type) {
+	case addrs.ModuleSourceRegistry:
+		subDir := addr.Subdir
+		addr.Subdir = ""
+		return addr.String(), subDir
+	case addrs.ModuleSourceRemote:
+		return addr.Package.String(), addr.Subdir
+	case nil:
+		panic("splitAddrSubdir on nil addrs.ModuleSource")
+	default:
+		return addr.String(), ""
+	}
+}
diff --git a/v1.5.7/internal/initwd/module_install_hooks.go b/v1.5.7/internal/initwd/module_install_hooks.go
new file mode 100644
index 0000000..7352634
--- /dev/null
+++ b/v1.5.7/internal/initwd/module_install_hooks.go
@@ -0,0 +1,39 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package initwd
+
+import (
+	version "github.com/hashicorp/go-version"
+)
+
+// ModuleInstallHooks is an interface used to provide notifications about the
+// installation process being orchestrated by InstallModules.
+//
+// This interface may have new methods added in future, so implementers should
+// embed InstallHooksImpl to get no-op implementations of any unimplemented
+// methods.
+type ModuleInstallHooks interface {
+	// Download is called for modules that are retrieved from a remote source
+	// before that download begins, to allow a caller to give feedback
+	// on progress through a possibly-long sequence of downloads.
+	Download(moduleAddr, packageAddr string, version *version.Version)
+
+	// Install is called for each module that is installed, even if it did
+	// not need to be downloaded from a remote source.
+	Install(moduleAddr string, version *version.Version, localPath string)
+}
+
+// ModuleInstallHooksImpl is a do-nothing implementation of InstallHooks that
+// can be embedded in another implementation struct to allow only partial
+// implementation of the interface.
+type ModuleInstallHooksImpl struct {
+}
+
+func (h ModuleInstallHooksImpl) Download(moduleAddr, packageAddr string, version *version.Version) {
+}
+
+func (h ModuleInstallHooksImpl) Install(moduleAddr string, version *version.Version, localPath string) {
+}
+
+var _ ModuleInstallHooks = ModuleInstallHooksImpl{}
diff --git a/v1.5.7/internal/initwd/module_install_test.go b/v1.5.7/internal/initwd/module_install_test.go
new file mode 100644
index 0000000..48bad4f
--- /dev/null
+++ b/v1.5.7/internal/initwd/module_install_test.go
@@ -0,0 +1,849 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package initwd
+
+import (
+	"bytes"
+	"context"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/go-test/deep"
+	"github.com/google/go-cmp/cmp"
+	version "github.com/hashicorp/go-version"
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/copy"
+	"github.com/hashicorp/terraform/internal/registry"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+
+	_ "github.com/hashicorp/terraform/internal/logging"
+)
+
+func TestMain(m *testing.M) {
+	flag.Parse()
+	os.Exit(m.Run())
+}
+
+func TestModuleInstaller(t *testing.T) {
+	fixtureDir := filepath.Clean("testdata/local-modules")
+	dir, done := tempChdir(t, fixtureDir)
+	defer done()
+
+	hooks := &testInstallHooks{}
+
+	modulesDir := filepath.Join(dir, ".terraform/modules")
+	loader, close := configload.NewLoaderForTests(t)
+	defer close()
+	inst := NewModuleInstaller(modulesDir, loader, nil)
+	_, diags := inst.InstallModules(context.Background(), ".", false, hooks)
+	assertNoDiagnostics(t, diags)
+
+	wantCalls := []testInstallHookCall{
+		{
+			Name:        "Install",
+			ModuleAddr:  "child_a",
+			PackageAddr: "",
+			LocalPath:   "child_a",
+		},
+		{
+			Name:        "Install",
+			ModuleAddr:  "child_a.child_b",
+			PackageAddr: "",
+			LocalPath:   "child_a/child_b",
+		},
+	}
+
+	if assertResultDeepEqual(t, hooks.Calls, wantCalls) {
+		return
+	}
+
+	loader, err := configload.NewLoader(&configload.Config{
+		ModulesDir: modulesDir,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Make sure the configuration is loadable now.
+	// (This ensures that correct information is recorded in the manifest.)
+	config, loadDiags := loader.LoadConfig(".")
+	assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags))
+
+	wantTraces := map[string]string{
+		"":                "in root module",
+		"child_a":         "in child_a module",
+		"child_a.child_b": "in child_b module",
+	}
+	gotTraces := map[string]string{}
+	config.DeepEach(func(c *configs.Config) {
+		path := strings.Join(c.Path, ".")
+		if c.Module.Variables["v"] == nil {
+			gotTraces[path] = "<missing>"
+			return
+		}
+		varDesc := c.Module.Variables["v"].Description
+		gotTraces[path] = varDesc
+	})
+	assertResultDeepEqual(t, gotTraces, wantTraces)
+}
+
+func TestModuleInstaller_error(t *testing.T) {
+	fixtureDir := filepath.Clean("testdata/local-module-error")
+	dir, done := tempChdir(t, fixtureDir)
+	defer done()
+
+	hooks := &testInstallHooks{}
+
+	modulesDir := filepath.Join(dir, ".terraform/modules")
+
+	loader, close := configload.NewLoaderForTests(t)
+	defer close()
+	inst := NewModuleInstaller(modulesDir, loader, nil)
+	_, diags := inst.InstallModules(context.Background(), ".", false, hooks)
+
+	if !diags.HasErrors() {
+		t.Fatal("expected error")
+	} else {
+		assertDiagnosticSummary(t, diags, "Invalid module source address")
+	}
+}
+
+func TestModuleInstaller_emptyModuleName(t *testing.T) {
+	fixtureDir := filepath.Clean("testdata/empty-module-name")
+	dir, done := tempChdir(t, fixtureDir)
+	defer done()
+
+	hooks := &testInstallHooks{}
+
+	modulesDir := filepath.Join(dir, ".terraform/modules")
+
+	loader, close := configload.NewLoaderForTests(t)
+	defer close()
+	inst := NewModuleInstaller(modulesDir, loader, nil)
+	_, diags := inst.InstallModules(context.Background(), ".", false, hooks)
+
+	if !diags.HasErrors() {
+		t.Fatal("expected error")
+	} else {
+		assertDiagnosticSummary(t, diags, "Invalid module instance name")
+	}
+}
+
+func TestModuleInstaller_invalidModuleName(t *testing.T) {
+	fixtureDir := filepath.Clean("testdata/invalid-module-name")
+	dir, done := tempChdir(t, fixtureDir)
+	defer done()
+
+	hooks := &testInstallHooks{}
+
+	modulesDir := filepath.Join(dir, ".terraform/modules")
+
+	loader, close := configload.NewLoaderForTests(t)
+	defer close()
+	inst := NewModuleInstaller(modulesDir, loader, registry.NewClient(nil, nil))
+	_, diags := inst.InstallModules(context.Background(), dir, false, hooks)
+
+	if !diags.HasErrors() {
+		t.Fatal("expected error")
+	} else {
+		assertDiagnosticSummary(t, diags, "Invalid module instance name")
+	}
+}
+
+func TestModuleInstaller_packageEscapeError(t *testing.T) {
+	fixtureDir := filepath.Clean("testdata/load-module-package-escape")
+	dir, done := tempChdir(t, fixtureDir)
+	defer done()
+
+	// For this particular test we need an absolute path in the root module
+	// that must actually resolve to our temporary directory in "dir", so
+	// we need to do a little rewriting. We replace the arbitrary placeholder
+	// %%BASE%% with the temporary directory path.
+	{
+		rootFilename := filepath.Join(dir, "package-escape.tf")
+		template, err := ioutil.ReadFile(rootFilename)
+		if err != nil {
+			t.Fatal(err)
+		}
+		final := bytes.ReplaceAll(template, []byte("%%BASE%%"), []byte(filepath.ToSlash(dir)))
+		err = ioutil.WriteFile(rootFilename, final, 0644)
+		if err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	hooks := &testInstallHooks{}
+
+	modulesDir := filepath.Join(dir, ".terraform/modules")
+
+	loader, close := configload.NewLoaderForTests(t)
+	defer close()
+	inst := NewModuleInstaller(modulesDir, loader, nil)
+	_, diags := inst.InstallModules(context.Background(), ".", false, hooks)
+
+	if !diags.HasErrors() {
+		t.Fatal("expected error")
+	} else {
+		assertDiagnosticSummary(t, diags, "Local module path escapes module package")
+	}
+}
+
+func TestModuleInstaller_explicitPackageBoundary(t *testing.T) {
+	fixtureDir := filepath.Clean("testdata/load-module-package-prefix")
+	dir, done := tempChdir(t, fixtureDir)
+	defer done()
+
+	// For this particular test we need an absolute path in the root module
+	// that must actually resolve to our temporary directory in "dir", so
+	// we need to do a little rewriting. We replace the arbitrary placeholder
+	// %%BASE%% with the temporary directory path.
+	{
+		rootFilename := filepath.Join(dir, "package-prefix.tf")
+		template, err := ioutil.ReadFile(rootFilename)
+		if err != nil {
+			t.Fatal(err)
+		}
+		final := bytes.ReplaceAll(template, []byte("%%BASE%%"), []byte(filepath.ToSlash(dir)))
+		err = ioutil.WriteFile(rootFilename, final, 0644)
+		if err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	hooks := &testInstallHooks{}
+
+	modulesDir := filepath.Join(dir, ".terraform/modules")
+
+	loader, close := configload.NewLoaderForTests(t)
+	defer close()
+	inst := NewModuleInstaller(modulesDir, loader, nil)
+	_, diags := inst.InstallModules(context.Background(), ".", false, hooks)
+
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+}
+
+func TestModuleInstaller_ExactMatchPrerelease(t *testing.T) {
+	if os.Getenv("TF_ACC") == "" {
+		t.Skip("this test accesses registry.terraform.io and github.com; set TF_ACC=1 to run it")
+	}
+
+	fixtureDir := filepath.Clean("testdata/prerelease-version-constraint-match")
+	dir, done := tempChdir(t, fixtureDir)
+	defer done()
+
+	hooks := &testInstallHooks{}
+
+	modulesDir := filepath.Join(dir, ".terraform/modules")
+
+	loader, close := configload.NewLoaderForTests(t)
+	defer close()
+	inst := NewModuleInstaller(modulesDir, loader, registry.NewClient(nil, nil))
+	cfg, diags := inst.InstallModules(context.Background(), ".", false, hooks)
+
+	if diags.HasErrors() {
+		t.Fatalf("found unexpected errors: %s", diags.Err())
+	}
+
+	if !cfg.Children["acctest_exact"].Version.Equal(version.Must(version.NewVersion("v0.0.3-alpha.1"))) {
+		t.Fatalf("expected version %s but found version %s", "v0.0.3-alpha.1", cfg.Version.String())
+	}
+}
+
+func TestModuleInstaller_PartialMatchPrerelease(t *testing.T) {
+	if os.Getenv("TF_ACC") == "" {
+		t.Skip("this test accesses registry.terraform.io and github.com; set TF_ACC=1 to run it")
+	}
+
+	fixtureDir := filepath.Clean("testdata/prerelease-version-constraint")
+	dir, done := tempChdir(t, fixtureDir)
+	defer done()
+
+	hooks := &testInstallHooks{}
+
+	modulesDir := filepath.Join(dir, ".terraform/modules")
+
+	loader, close := configload.NewLoaderForTests(t)
+	defer close()
+	inst := NewModuleInstaller(modulesDir, loader, registry.NewClient(nil, nil))
+	cfg, diags := inst.InstallModules(context.Background(), ".", false, hooks)
+
+	if diags.HasErrors() {
+		t.Fatalf("found unexpected errors: %s", diags.Err())
+	}
+
+	if !cfg.Children["acctest_partial"].Version.Equal(version.Must(version.NewVersion("v0.0.2"))) {
+		t.Fatalf("expected version %s but found version %s", "v0.0.2", cfg.Version.String())
+	}
+}
+
+func TestModuleInstaller_invalid_version_constraint_error(t *testing.T) {
+	fixtureDir := filepath.Clean("testdata/invalid-version-constraint")
+	dir, done := tempChdir(t, fixtureDir)
+	defer done()
+
+	hooks := &testInstallHooks{}
+
+	modulesDir := filepath.Join(dir, ".terraform/modules")
+
+	loader, close := configload.NewLoaderForTests(t)
+	defer close()
+	inst := NewModuleInstaller(modulesDir, loader, nil)
+	_, diags := inst.InstallModules(context.Background(), ".", false, hooks)
+
+	if !diags.HasErrors() {
+		t.Fatal("expected error")
+	} else {
+		// We use the presence of the "version" argument as a heuristic for
+		// user intent to use a registry module, and so we intentionally catch
+		// this as an invalid registry module address rather than an invalid
+		// version constraint, so we can surface the specific address parsing
+		// error instead of a generic version constraint error.
+		assertDiagnosticSummary(t, diags, "Invalid registry module source address")
+	}
+}
+
+func TestModuleInstaller_invalidVersionConstraintGetter(t *testing.T) {
+	fixtureDir := filepath.Clean("testdata/invalid-version-constraint")
+	dir, done := tempChdir(t, fixtureDir)
+	defer done()
+
+	hooks := &testInstallHooks{}
+
+	modulesDir := filepath.Join(dir, ".terraform/modules")
+
+	loader, close := configload.NewLoaderForTests(t)
+	defer close()
+	inst := NewModuleInstaller(modulesDir, loader, nil)
+	_, diags := inst.InstallModules(context.Background(), ".", false, hooks)
+
+	if !diags.HasErrors() {
+		t.Fatal("expected error")
+	} else {
+		// We use the presence of the "version" argument as a heuristic for
+		// user intent to use a registry module, and so we intentionally catch
+		// this as an invalid registry module address rather than an invalid
+		// version constraint, so we can surface the specific address parsing
+		// error instead of a generic version constraint error.
+		assertDiagnosticSummary(t, diags, "Invalid registry module source address")
+	}
+}
+
+func TestModuleInstaller_invalidVersionConstraintLocal(t *testing.T) {
+	fixtureDir := filepath.Clean("testdata/invalid-version-constraint-local")
+	dir, done := tempChdir(t, fixtureDir)
+	defer done()
+
+	hooks := &testInstallHooks{}
+
+	modulesDir := filepath.Join(dir, ".terraform/modules")
+
+	loader, close := configload.NewLoaderForTests(t)
+	defer close()
+	inst := NewModuleInstaller(modulesDir, loader, nil)
+	_, diags := inst.InstallModules(context.Background(), ".", false, hooks)
+
+	if !diags.HasErrors() {
+		t.Fatal("expected error")
+	} else {
+		// We use the presence of the "version" argument as a heuristic for
+		// user intent to use a registry module, and so we intentionally catch
+		// this as an invalid registry module address rather than an invalid
+		// version constraint, so we can surface the specific address parsing
+		// error instead of a generic version constraint error.
+		assertDiagnosticSummary(t, diags, "Invalid registry module source address")
+	}
+}
+
+func TestModuleInstaller_symlink(t *testing.T) {
+	fixtureDir := filepath.Clean("testdata/local-module-symlink")
+	dir, done := tempChdir(t, fixtureDir)
+	defer done()
+
+	hooks := &testInstallHooks{}
+
+	modulesDir := filepath.Join(dir, ".terraform/modules")
+
+	loader, close := configload.NewLoaderForTests(t)
+	defer close()
+	inst := NewModuleInstaller(modulesDir, loader, nil)
+	_, diags := inst.InstallModules(context.Background(), ".", false, hooks)
+	assertNoDiagnostics(t, diags)
+
+	wantCalls := []testInstallHookCall{
+		{
+			Name:        "Install",
+			ModuleAddr:  "child_a",
+			PackageAddr: "",
+			LocalPath:   "child_a",
+		},
+		{
+			Name:        "Install",
+			ModuleAddr:  "child_a.child_b",
+			PackageAddr: "",
+			LocalPath:   "child_a/child_b",
+		},
+	}
+
+	if assertResultDeepEqual(t, hooks.Calls, wantCalls) {
+		return
+	}
+
+	loader, err := configload.NewLoader(&configload.Config{
+		ModulesDir: modulesDir,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Make sure the configuration is loadable now.
+	// (This ensures that correct information is recorded in the manifest.)
+	config, loadDiags := loader.LoadConfig(".")
+	assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags))
+
+	wantTraces := map[string]string{
+		"":                "in root module",
+		"child_a":         "in child_a module",
+		"child_a.child_b": "in child_b module",
+	}
+	gotTraces := map[string]string{}
+	config.DeepEach(func(c *configs.Config) {
+		path := strings.Join(c.Path, ".")
+		if c.Module.Variables["v"] == nil {
+			gotTraces[path] = "<missing>"
+			return
+		}
+		varDesc := c.Module.Variables["v"].Description
+		gotTraces[path] = varDesc
+	})
+	assertResultDeepEqual(t, gotTraces, wantTraces)
+}
+
+func TestLoaderInstallModules_registry(t *testing.T) {
+	if os.Getenv("TF_ACC") == "" {
+		t.Skip("this test accesses registry.terraform.io and github.com; set TF_ACC=1 to run it")
+	}
+
+	fixtureDir := filepath.Clean("testdata/registry-modules")
+	tmpDir, done := tempChdir(t, fixtureDir)
+	// the module installer runs filepath.EvalSymlinks() on the destination
+	// directory before copying files, and the resultant directory is what is
+	// returned by the install hooks. Without this, tests could fail on machines
+	// where the default temp dir was a symlink.
+	dir, err := filepath.EvalSymlinks(tmpDir)
+	if err != nil {
+		t.Error(err)
+	}
+
+	defer done()
+
+	hooks := &testInstallHooks{}
+	modulesDir := filepath.Join(dir, ".terraform/modules")
+
+	loader, close := configload.NewLoaderForTests(t)
+	defer close()
+	inst := NewModuleInstaller(modulesDir, loader, registry.NewClient(nil, nil))
+	_, diags := inst.InstallModules(context.Background(), dir, false, hooks)
+	assertNoDiagnostics(t, diags)
+
+	v := version.Must(version.NewVersion("0.0.1"))
+
+	wantCalls := []testInstallHookCall{
+		// the configuration builder visits each level of calls in lexicographical
+		// order by name, so the following list is kept in the same order.
+
+		// acctest_child_a accesses //modules/child_a directly
+		{
+			Name:        "Download",
+			ModuleAddr:  "acctest_child_a",
+			PackageAddr: "registry.terraform.io/hashicorp/module-installer-acctest/aws", // intentionally excludes the subdir because we're downloading the whole package here
+			Version:     v,
+		},
+		{
+			Name:       "Install",
+			ModuleAddr: "acctest_child_a",
+			Version:    v,
+			// NOTE: This local path and the other paths derived from it below
+			// can vary depending on how the registry is implemented. At the
+			// time of writing this test, registry.terraform.io returns
+			// git repository source addresses and so this path refers to the
+			// root of the git clone, but historically the registry referred
+			// to GitHub-provided tar archives which meant that there was an
+			// extra level of subdirectory here for the typical directory
+			// nesting in tar archives, which would've been reflected as
+			// an extra segment on this path. If this test fails due to an
+			// additional path segment in future, then a change to the upstream
+			// registry might be the root cause.
+			LocalPath: filepath.Join(dir, ".terraform/modules/acctest_child_a/modules/child_a"),
+		},
+
+		// acctest_child_a.child_b
+		// (no download because it's a relative path inside acctest_child_a)
+		{
+			Name:       "Install",
+			ModuleAddr: "acctest_child_a.child_b",
+			LocalPath:  filepath.Join(dir, ".terraform/modules/acctest_child_a/modules/child_b"),
+		},
+
+		// acctest_child_b accesses //modules/child_b directly
+		{
+			Name:        "Download",
+			ModuleAddr:  "acctest_child_b",
+			PackageAddr: "registry.terraform.io/hashicorp/module-installer-acctest/aws", // intentionally excludes the subdir because we're downloading the whole package here
+			Version:     v,
+		},
+		{
+			Name:       "Install",
+			ModuleAddr: "acctest_child_b",
+			Version:    v,
+			LocalPath:  filepath.Join(dir, ".terraform/modules/acctest_child_b/modules/child_b"),
+		},
+
+		// acctest_root
+		{
+			Name:        "Download",
+			ModuleAddr:  "acctest_root",
+			PackageAddr: "registry.terraform.io/hashicorp/module-installer-acctest/aws",
+			Version:     v,
+		},
+		{
+			Name:       "Install",
+			ModuleAddr: "acctest_root",
+			Version:    v,
+			LocalPath:  filepath.Join(dir, ".terraform/modules/acctest_root"),
+		},
+
+		// acctest_root.child_a
+		// (no download because it's a relative path inside acctest_root)
+		{
+			Name:       "Install",
+			ModuleAddr: "acctest_root.child_a",
+			LocalPath:  filepath.Join(dir, ".terraform/modules/acctest_root/modules/child_a"),
+		},
+
+		// acctest_root.child_a.child_b
+		// (no download because it's a relative path inside acctest_root, via acctest_root.child_a)
+		{
+			Name:       "Install",
+			ModuleAddr: "acctest_root.child_a.child_b",
+			LocalPath:  filepath.Join(dir, ".terraform/modules/acctest_root/modules/child_b"),
+		},
+	}
+
+	if diff := cmp.Diff(wantCalls, hooks.Calls); diff != "" {
+		t.Fatalf("wrong installer calls\n%s", diff)
+	}
+
+	//check that the registry reponses were cached
+	packageAddr := addrs.ModuleRegistryPackage{
+		Host:         svchost.Hostname("registry.terraform.io"),
+		Namespace:    "hashicorp",
+		Name:         "module-installer-acctest",
+		TargetSystem: "aws",
+	}
+	if _, ok := inst.registryPackageVersions[packageAddr]; !ok {
+		t.Errorf("module versions cache was not populated\ngot: %s\nwant: key hashicorp/module-installer-acctest/aws", spew.Sdump(inst.registryPackageVersions))
+	}
+	if _, ok := inst.registryPackageSources[moduleVersion{module: packageAddr, version: "0.0.1"}]; !ok {
+		t.Errorf("module download url cache was not populated\ngot: %s", spew.Sdump(inst.registryPackageSources))
+	}
+
+	loader, err = configload.NewLoader(&configload.Config{
+		ModulesDir: modulesDir,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Make sure the configuration is loadable now.
+	// (This ensures that correct information is recorded in the manifest.)
+	config, loadDiags := loader.LoadConfig(".")
+	assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags))
+
+	wantTraces := map[string]string{
+		"":                             "in local caller for registry-modules",
+		"acctest_root":                 "in root module",
+		"acctest_root.child_a":         "in child_a module",
+		"acctest_root.child_a.child_b": "in child_b module",
+		"acctest_child_a":              "in child_a module",
+		"acctest_child_a.child_b":      "in child_b module",
+		"acctest_child_b":              "in child_b module",
+	}
+	gotTraces := map[string]string{}
+	config.DeepEach(func(c *configs.Config) {
+		path := strings.Join(c.Path, ".")
+		if c.Module.Variables["v"] == nil {
+			gotTraces[path] = "<missing>"
+			return
+		}
+		varDesc := c.Module.Variables["v"].Description
+		gotTraces[path] = varDesc
+	})
+	assertResultDeepEqual(t, gotTraces, wantTraces)
+
+}
+
+func TestLoaderInstallModules_goGetter(t *testing.T) {
+	if os.Getenv("TF_ACC") == "" {
+		t.Skip("this test accesses github.com; set TF_ACC=1 to run it")
+	}
+
+	fixtureDir := filepath.Clean("testdata/go-getter-modules")
+	tmpDir, done := tempChdir(t, fixtureDir)
+	// the module installer runs filepath.EvalSymlinks() on the destination
+	// directory before copying files, and the resultant directory is what is
+	// returned by the install hooks. Without this, tests could fail on machines
+	// where the default temp dir was a symlink.
+	dir, err := filepath.EvalSymlinks(tmpDir)
+	if err != nil {
+		t.Error(err)
+	}
+	defer done()
+
+	hooks := &testInstallHooks{}
+	modulesDir := filepath.Join(dir, ".terraform/modules")
+
+	loader, close := configload.NewLoaderForTests(t)
+	defer close()
+	inst := NewModuleInstaller(modulesDir, loader, registry.NewClient(nil, nil))
+	_, diags := inst.InstallModules(context.Background(), dir, false, hooks)
+	assertNoDiagnostics(t, diags)
+
+	wantCalls := []testInstallHookCall{
+		// the configuration builder visits each level of calls in lexicographical
+		// order by name, so the following list is kept in the same order.
+
+		// acctest_child_a accesses //modules/child_a directly
+		{
+			Name:        "Download",
+			ModuleAddr:  "acctest_child_a",
+			PackageAddr: "git::https://github.com/hashicorp/terraform-aws-module-installer-acctest.git?ref=v0.0.1", // intentionally excludes the subdir because we're downloading the whole repo here
+		},
+		{
+			Name:       "Install",
+			ModuleAddr: "acctest_child_a",
+			LocalPath:  filepath.Join(dir, ".terraform/modules/acctest_child_a/modules/child_a"),
+		},
+
+		// acctest_child_a.child_b
+		// (no download because it's a relative path inside acctest_child_a)
+		{
+			Name:       "Install",
+			ModuleAddr: "acctest_child_a.child_b",
+			LocalPath:  filepath.Join(dir, ".terraform/modules/acctest_child_a/modules/child_b"),
+		},
+
+		// acctest_child_b accesses //modules/child_b directly
+		{
+			Name:        "Download",
+			ModuleAddr:  "acctest_child_b",
+			PackageAddr: "git::https://github.com/hashicorp/terraform-aws-module-installer-acctest.git?ref=v0.0.1", // intentionally excludes the subdir because we're downloading the whole package here
+		},
+		{
+			Name:       "Install",
+			ModuleAddr: "acctest_child_b",
+			LocalPath:  filepath.Join(dir, ".terraform/modules/acctest_child_b/modules/child_b"),
+		},
+
+		// acctest_root
+		{
+			Name:        "Download",
+			ModuleAddr:  "acctest_root",
+			PackageAddr: "git::https://github.com/hashicorp/terraform-aws-module-installer-acctest.git?ref=v0.0.1",
+		},
+		{
+			Name:       "Install",
+			ModuleAddr: "acctest_root",
+			LocalPath:  filepath.Join(dir, ".terraform/modules/acctest_root"),
+		},
+
+		// acctest_root.child_a
+		// (no download because it's a relative path inside acctest_root)
+		{
+			Name:       "Install",
+			ModuleAddr: "acctest_root.child_a",
+			LocalPath:  filepath.Join(dir, ".terraform/modules/acctest_root/modules/child_a"),
+		},
+
+		// acctest_root.child_a.child_b
+		// (no download because it's a relative path inside acctest_root, via acctest_root.child_a)
+		{
+			Name:       "Install",
+			ModuleAddr: "acctest_root.child_a.child_b",
+			LocalPath:  filepath.Join(dir, ".terraform/modules/acctest_root/modules/child_b"),
+		},
+	}
+
+	if diff := cmp.Diff(wantCalls, hooks.Calls); diff != "" {
+		t.Fatalf("wrong installer calls\n%s", diff)
+	}
+
+	loader, err = configload.NewLoader(&configload.Config{
+		ModulesDir: modulesDir,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Make sure the configuration is loadable now.
+	// (This ensures that correct information is recorded in the manifest.)
+	config, loadDiags := loader.LoadConfig(".")
+	assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags))
+
+	wantTraces := map[string]string{
+		"":                             "in local caller for go-getter-modules",
+		"acctest_root":                 "in root module",
+		"acctest_root.child_a":         "in child_a module",
+		"acctest_root.child_a.child_b": "in child_b module",
+		"acctest_child_a":              "in child_a module",
+		"acctest_child_a.child_b":      "in child_b module",
+		"acctest_child_b":              "in child_b module",
+	}
+	gotTraces := map[string]string{}
+	config.DeepEach(func(c *configs.Config) {
+		path := strings.Join(c.Path, ".")
+		if c.Module.Variables["v"] == nil {
+			gotTraces[path] = "<missing>"
+			return
+		}
+		varDesc := c.Module.Variables["v"].Description
+		gotTraces[path] = varDesc
+	})
+	assertResultDeepEqual(t, gotTraces, wantTraces)
+
+}
+
+type testInstallHooks struct {
+	Calls []testInstallHookCall
+}
+
+type testInstallHookCall struct {
+	Name        string
+	ModuleAddr  string
+	PackageAddr string
+	Version     *version.Version
+	LocalPath   string
+}
+
+func (h *testInstallHooks) Download(moduleAddr, packageAddr string, version *version.Version) {
+	h.Calls = append(h.Calls, testInstallHookCall{
+		Name:        "Download",
+		ModuleAddr:  moduleAddr,
+		PackageAddr: packageAddr,
+		Version:     version,
+	})
+}
+
+func (h *testInstallHooks) Install(moduleAddr string, version *version.Version, localPath string) {
+	h.Calls = append(h.Calls, testInstallHookCall{
+		Name:       "Install",
+		ModuleAddr: moduleAddr,
+		Version:    version,
+		LocalPath:  localPath,
+	})
+}
+
+// tempChdir copies the contents of the given directory to a temporary
+// directory and changes the test process's current working directory to
+// point to that directory. Also returned is a function that should be
+// called at the end of the test (e.g. via "defer") to restore the previous
+// working directory.
+//
+// Tests using this helper cannot safely be run in parallel with other tests.
+func tempChdir(t *testing.T, sourceDir string) (string, func()) {
+	t.Helper()
+
+	tmpDir, err := ioutil.TempDir("", "terraform-configload")
+	if err != nil {
+		t.Fatalf("failed to create temporary directory: %s", err)
+		return "", nil
+	}
+
+	if err := copy.CopyDir(tmpDir, sourceDir); err != nil {
+		t.Fatalf("failed to copy fixture to temporary directory: %s", err)
+		return "", nil
+	}
+
+	oldDir, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("failed to determine current working directory: %s", err)
+		return "", nil
+	}
+
+	err = os.Chdir(tmpDir)
+	if err != nil {
+		t.Fatalf("failed to switch to temp dir %s: %s", tmpDir, err)
+		return "", nil
+	}
+
+	// Most of the tests need this, so we'll make it just in case.
+	os.MkdirAll(filepath.Join(tmpDir, ".terraform/modules"), os.ModePerm)
+
+	t.Logf("tempChdir switched to %s after copying from %s", tmpDir, sourceDir)
+
+	return tmpDir, func() {
+		err := os.Chdir(oldDir)
+		if err != nil {
+			panic(fmt.Errorf("failed to restore previous working directory %s: %s", oldDir, err))
+		}
+
+		if os.Getenv("TF_CONFIGLOAD_TEST_KEEP_TMP") == "" {
+			os.RemoveAll(tmpDir)
+		}
+	}
+}
+
+func assertNoDiagnostics(t *testing.T, diags tfdiags.Diagnostics) bool {
+	t.Helper()
+	return assertDiagnosticCount(t, diags, 0)
+}
+
+func assertDiagnosticCount(t *testing.T, diags tfdiags.Diagnostics, want int) bool {
+	t.Helper()
+	if len(diags) != 0 {
+		t.Errorf("wrong number of diagnostics %d; want %d", len(diags), want)
+		for _, diag := range diags {
+			t.Logf("- %#v", diag)
+		}
+		return true
+	}
+	return false
+}
+
+func assertDiagnosticSummary(t *testing.T, diags tfdiags.Diagnostics, want string) bool {
+	t.Helper()
+
+	for _, diag := range diags {
+		if diag.Description().Summary == want {
+			return false
+		}
+	}
+
+	t.Errorf("missing diagnostic summary %q", want)
+	for _, diag := range diags {
+		t.Logf("- %#v", diag)
+	}
+	return true
+}
+
+func assertResultDeepEqual(t *testing.T, got, want interface{}) bool {
+	t.Helper()
+	if diff := deep.Equal(got, want); diff != nil {
+		for _, problem := range diff {
+			t.Errorf("%s", problem)
+		}
+		return true
+	}
+	return false
+}
diff --git a/v1.5.7/internal/initwd/testdata/already-installed/root.tf b/v1.5.7/internal/initwd/testdata/already-installed/root.tf
new file mode 100644
index 0000000..8a44739
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/already-installed/root.tf
@@ -0,0 +1,10 @@
+
+module "child_a" {
+  source  = "example.com/foo/bar_a/baz"
+  version = ">= 1.0.0"
+}
+
+module "child_b" {
+  source = "example.com/foo/bar_b/baz"
+  version = ">= 1.0.0"
+}
diff --git a/v1.5.7/internal/initwd/testdata/empty-module-name/child/main.tf b/v1.5.7/internal/initwd/testdata/empty-module-name/child/main.tf
new file mode 100644
index 0000000..6187fa6
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/empty-module-name/child/main.tf
@@ -0,0 +1,3 @@
+output "boop" {
+  value = "beep"
+}
diff --git a/v1.5.7/internal/initwd/testdata/empty-module-name/main.tf b/v1.5.7/internal/initwd/testdata/empty-module-name/main.tf
new file mode 100644
index 0000000..45add55
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/empty-module-name/main.tf
@@ -0,0 +1,3 @@
+module "" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/initwd/testdata/empty/.gitignore b/v1.5.7/internal/initwd/testdata/empty/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/empty/.gitignore
diff --git a/v1.5.7/internal/initwd/testdata/go-getter-modules/.gitignore b/v1.5.7/internal/initwd/testdata/go-getter-modules/.gitignore
new file mode 100644
index 0000000..6e0db03
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/go-getter-modules/.gitignore
@@ -0,0 +1 @@
+.terraform/*
diff --git a/v1.5.7/internal/initwd/testdata/go-getter-modules/root.tf b/v1.5.7/internal/initwd/testdata/go-getter-modules/root.tf
new file mode 100644
index 0000000..9b174a7
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/go-getter-modules/root.tf
@@ -0,0 +1,21 @@
+# This fixture depends on a github repo at:
+#     https://github.com/hashicorp/terraform-aws-module-installer-acctest
+# ...and expects its v0.0.1 tag to be pointing at the following commit:
+#     d676ab2559d4e0621d59e3c3c4cbb33958ac4608
+
+variable "v" {
+  description = "in local caller for go-getter-modules"
+  default     = ""
+}
+
+module "acctest_root" {
+  source = "github.com/hashicorp/terraform-aws-module-installer-acctest?ref=v0.0.1"
+}
+
+module "acctest_child_a" {
+  source = "github.com/hashicorp/terraform-aws-module-installer-acctest//modules/child_a?ref=v0.0.1"
+}
+
+module "acctest_child_b" {
+  source = "github.com/hashicorp/terraform-aws-module-installer-acctest//modules/child_b?ref=v0.0.1"
+}
diff --git a/v1.5.7/internal/initwd/testdata/invalid-module-name/child/main.tf b/v1.5.7/internal/initwd/testdata/invalid-module-name/child/main.tf
new file mode 100644
index 0000000..6187fa6
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/invalid-module-name/child/main.tf
@@ -0,0 +1,3 @@
+output "boop" {
+  value = "beep"
+}
diff --git a/v1.5.7/internal/initwd/testdata/invalid-module-name/main.tf b/v1.5.7/internal/initwd/testdata/invalid-module-name/main.tf
new file mode 100644
index 0000000..316afe4
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/invalid-module-name/main.tf
@@ -0,0 +1,3 @@
+module "../invalid" {
+  source  = "./child"
+}
diff --git a/v1.5.7/internal/initwd/testdata/invalid-version-constraint-local/.gitignore b/v1.5.7/internal/initwd/testdata/invalid-version-constraint-local/.gitignore
new file mode 100644
index 0000000..6e0db03
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/invalid-version-constraint-local/.gitignore
@@ -0,0 +1 @@
+.terraform/*
diff --git a/v1.5.7/internal/initwd/testdata/invalid-version-constraint-local/root.tf b/v1.5.7/internal/initwd/testdata/invalid-version-constraint-local/root.tf
new file mode 100644
index 0000000..e7dbaa3
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/invalid-version-constraint-local/root.tf
@@ -0,0 +1,9 @@
+# This fixture references the github repo at:
+#     https://github.com/hashicorp/terraform-aws-module-installer-acctest
+# However, due to the nature of this test (verifying early error), the URL will not be contacted,
+# and the test is safe to execute as part of the normal test suite.
+
+module "acctest_root" {
+  source  = "github.com/hashicorp/terraform-aws-module-installer-acctest"
+  version = "0.0.1"
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/initwd/testdata/invalid-version-constraint/.gitignore b/v1.5.7/internal/initwd/testdata/invalid-version-constraint/.gitignore
new file mode 100644
index 0000000..6e0db03
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/invalid-version-constraint/.gitignore
@@ -0,0 +1 @@
+.terraform/*
diff --git a/v1.5.7/internal/initwd/testdata/invalid-version-constraint/root.tf b/v1.5.7/internal/initwd/testdata/invalid-version-constraint/root.tf
new file mode 100644
index 0000000..a973dd0
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/invalid-version-constraint/root.tf
@@ -0,0 +1,4 @@
+module "local" {
+  source  = "./local"
+  version = "0.0.1" # Version constraint not allowed for a local module
+}
diff --git a/v1.5.7/internal/initwd/testdata/load-module-package-escape/child/package-escape-child.tf b/v1.5.7/internal/initwd/testdata/load-module-package-escape/child/package-escape-child.tf
new file mode 100644
index 0000000..935a02d
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/load-module-package-escape/child/package-escape-child.tf
@@ -0,0 +1,8 @@
+module "grandchild" {
+  # NOTE: This seems like it ought to work because there is indeed a
+  # ../grandchild directory, but our caller loaded us as an external
+  # module using an absolute path and so we're actually isolated from
+  # the parent directory in a separate "module package", and so we
+  # can't traverse out to find the grandchild module.
+  source = "../grandchild"
+}
diff --git a/v1.5.7/internal/initwd/testdata/load-module-package-escape/grandchild/package-escape-grandchild.tf b/v1.5.7/internal/initwd/testdata/load-module-package-escape/grandchild/package-escape-grandchild.tf
new file mode 100644
index 0000000..734d0d6
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/load-module-package-escape/grandchild/package-escape-grandchild.tf
@@ -0,0 +1,2 @@
+# This is intentionally empty, just here to be referred to by the "child"
+# module in ../child .
diff --git a/v1.5.7/internal/initwd/testdata/load-module-package-escape/package-escape.tf b/v1.5.7/internal/initwd/testdata/load-module-package-escape/package-escape.tf
new file mode 100644
index 0000000..7a665a4
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/load-module-package-escape/package-escape.tf
@@ -0,0 +1,9 @@
+module "child" {
+  # NOTE: For this test we need a working absolute path so that Terraform
+  # will see this a an "external" module and thus establish a separate
+  # package for it, but we won't know which temporary directory this
+  # will be in at runtime, so we'll rewrite this file inside the test
+  # code to replace %%BASE%% with the actual path. %%BASE%% is not normal
+  # Terraform syntax and won't work outside of this test.
+  source = "%%BASE%%/child"
+}
diff --git a/v1.5.7/internal/initwd/testdata/load-module-package-prefix/package-prefix.tf b/v1.5.7/internal/initwd/testdata/load-module-package-prefix/package-prefix.tf
new file mode 100644
index 0000000..08d5ced
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/load-module-package-prefix/package-prefix.tf
@@ -0,0 +1,15 @@
+module "child" {
+  # NOTE: For this test we need a working absolute path so that Terraform
+  # will see this a an "external" module and thus establish a separate
+  # package for it, but we won't know which temporary directory this
+  # will be in at runtime, so we'll rewrite this file inside the test
+  # code to replace %%BASE%% with the actual path. %%BASE%% is not normal
+  # Terraform syntax and won't work outside of this test.
+  #
+  # Note that we're intentionally using the special // delimiter to
+  # tell Terraform that it should treat the "package" directory as a
+  # whole as a module package, with all of its descendents "downloaded"
+  # (copied) together into ./.terraform/modules/child so that child
+  # can refer to ../grandchild successfully.
+  source = "%%BASE%%/package//child"
+}
diff --git a/v1.5.7/internal/initwd/testdata/load-module-package-prefix/package/child/package-prefix-child.tf b/v1.5.7/internal/initwd/testdata/load-module-package-prefix/package/child/package-prefix-child.tf
new file mode 100644
index 0000000..84b67ac
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/load-module-package-prefix/package/child/package-prefix-child.tf
@@ -0,0 +1,9 @@
+module "grandchild" {
+  # NOTE: This only works because our caller told Terraform to treat
+  # the parent directory as a whole as a module package, and so
+  # the "./terraform/modules/child" directory should contain both
+  # "child" and "grandchild" sub directories that we can traverse between.
+  # This is the same as local paths between different directories inside
+  # a single git repository or distribution archive.
+  source = "../grandchild"
+}
diff --git a/v1.5.7/internal/initwd/testdata/load-module-package-prefix/package/grandchild/package-prefix-grandchild.tf b/v1.5.7/internal/initwd/testdata/load-module-package-prefix/package/grandchild/package-prefix-grandchild.tf
new file mode 100644
index 0000000..734d0d6
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/load-module-package-prefix/package/grandchild/package-prefix-grandchild.tf
@@ -0,0 +1,2 @@
+# This is intentionally empty, just here to be referred to by the "child"
+# module in ../child .
diff --git a/v1.5.7/internal/initwd/testdata/local-module-error/child_a/main.tf b/v1.5.7/internal/initwd/testdata/local-module-error/child_a/main.tf
new file mode 100644
index 0000000..03ebd8e
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/local-module-error/child_a/main.tf
@@ -0,0 +1,8 @@
+variable "v" {
+  description = "in child_ba module"
+  default     = ""
+}
+
+output "hello" {
+  value = "Hello from child_a!"
+}
diff --git a/v1.5.7/internal/initwd/testdata/local-module-error/main.tf b/v1.5.7/internal/initwd/testdata/local-module-error/main.tf
new file mode 100644
index 0000000..a31f913
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/local-module-error/main.tf
@@ -0,0 +1,8 @@
+variable "v" {
+  description = "in root module"
+  default     = ""
+}
+
+module "child_a" {
+  source = "child_a"
+}
diff --git a/v1.5.7/internal/initwd/testdata/local-module-symlink/child_a/child_a.tf b/v1.5.7/internal/initwd/testdata/local-module-symlink/child_a/child_a.tf
new file mode 100644
index 0000000..68ebb8e
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/local-module-symlink/child_a/child_a.tf
@@ -0,0 +1,9 @@
+
+variable "v" {
+  description = "in child_a module"
+  default     = ""
+}
+
+module "child_b" {
+  source = "./child_b"
+}
diff --git a/v1.5.7/internal/initwd/testdata/local-module-symlink/child_a/child_b/child_b.tf b/v1.5.7/internal/initwd/testdata/local-module-symlink/child_a/child_b/child_b.tf
new file mode 100644
index 0000000..e2e2209
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/local-module-symlink/child_a/child_b/child_b.tf
@@ -0,0 +1,9 @@
+
+variable "v" {
+  description = "in child_b module"
+  default     = ""
+}
+
+output "hello" {
+  value = "Hello from child_b!"
+}
diff --git a/v1.5.7/internal/initwd/testdata/local-module-symlink/modules/child_a b/v1.5.7/internal/initwd/testdata/local-module-symlink/modules/child_a
new file mode 120000
index 0000000..0d568b1
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/local-module-symlink/modules/child_a
@@ -0,0 +1 @@
+../child_a/
\ No newline at end of file
diff --git a/v1.5.7/internal/initwd/testdata/local-module-symlink/root.tf b/v1.5.7/internal/initwd/testdata/local-module-symlink/root.tf
new file mode 100644
index 0000000..1ca7ca3
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/local-module-symlink/root.tf
@@ -0,0 +1,9 @@
+
+variable "v" {
+  description = "in root module"
+  default     = ""
+}
+
+module "child_a" {
+  source = "./modules/child_a"
+}
diff --git a/v1.5.7/internal/initwd/testdata/local-modules/child_a/child_a.tf b/v1.5.7/internal/initwd/testdata/local-modules/child_a/child_a.tf
new file mode 100644
index 0000000..68ebb8e
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/local-modules/child_a/child_a.tf
@@ -0,0 +1,9 @@
+
+variable "v" {
+  description = "in child_a module"
+  default     = ""
+}
+
+module "child_b" {
+  source = "./child_b"
+}
diff --git a/v1.5.7/internal/initwd/testdata/local-modules/child_a/child_b/child_b.tf b/v1.5.7/internal/initwd/testdata/local-modules/child_a/child_b/child_b.tf
new file mode 100644
index 0000000..e2e2209
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/local-modules/child_a/child_b/child_b.tf
@@ -0,0 +1,9 @@
+
+variable "v" {
+  description = "in child_b module"
+  default     = ""
+}
+
+output "hello" {
+  value = "Hello from child_b!"
+}
diff --git a/v1.5.7/internal/initwd/testdata/local-modules/root.tf b/v1.5.7/internal/initwd/testdata/local-modules/root.tf
new file mode 100644
index 0000000..3b4c641
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/local-modules/root.tf
@@ -0,0 +1,9 @@
+
+variable "v" {
+  description = "in root module"
+  default     = ""
+}
+
+module "child_a" {
+  source = "./child_a"
+}
diff --git a/v1.5.7/internal/initwd/testdata/prerelease-version-constraint-match/root.tf b/v1.5.7/internal/initwd/testdata/prerelease-version-constraint-match/root.tf
new file mode 100644
index 0000000..b68baf7
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/prerelease-version-constraint-match/root.tf
@@ -0,0 +1,7 @@
+# We expect this test to download the requested version because it is an exact
+# match for a prerelease version.
+
+module "acctest_exact" {
+  source = "hashicorp/module-installer-acctest/aws"
+  version = "=0.0.3-alpha.1"
+}
diff --git a/v1.5.7/internal/initwd/testdata/prerelease-version-constraint/root.tf b/v1.5.7/internal/initwd/testdata/prerelease-version-constraint/root.tf
new file mode 100644
index 0000000..8ff3dd6
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/prerelease-version-constraint/root.tf
@@ -0,0 +1,8 @@
+# We expect this test to download the version 0.0.2, the one before the
+# specified version even with the equality because the specified version is a
+# prerelease.
+
+module "acctest_partial" {
+  source = "hashicorp/module-installer-acctest/aws"
+  version = "<=0.0.3-alpha.1"
+}
diff --git a/v1.5.7/internal/initwd/testdata/registry-modules/.gitignore b/v1.5.7/internal/initwd/testdata/registry-modules/.gitignore
new file mode 100644
index 0000000..6e0db03
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/registry-modules/.gitignore
@@ -0,0 +1 @@
+.terraform/*
diff --git a/v1.5.7/internal/initwd/testdata/registry-modules/root.tf b/v1.5.7/internal/initwd/testdata/registry-modules/root.tf
new file mode 100644
index 0000000..4b5ad1f
--- /dev/null
+++ b/v1.5.7/internal/initwd/testdata/registry-modules/root.tf
@@ -0,0 +1,33 @@
+# This fixture indirectly depends on a github repo at:
+#     https://github.com/hashicorp/terraform-aws-module-installer-acctest
+# ...and expects its v0.0.1 tag to be pointing at the following commit:
+#     d676ab2559d4e0621d59e3c3c4cbb33958ac4608
+#
+# This repository is accessed indirectly via:
+#     https://registry.terraform.io/modules/hashicorp/module-installer-acctest/aws/0.0.1
+#
+# Since the tag's id is included in a downloaded archive, it is expected to
+# have the following id:
+#     853d03855b3290a3ca491d4c3a7684572dd42237
+# (this particular assumption is encoded in the tests that use this fixture)
+
+
+variable "v" {
+  description = "in local caller for registry-modules"
+  default     = ""
+}
+
+module "acctest_root" {
+  source  = "hashicorp/module-installer-acctest/aws"
+  version = "0.0.1"
+}
+
+module "acctest_child_a" {
+  source  = "hashicorp/module-installer-acctest/aws//modules/child_a"
+  version = "0.0.1"
+}
+
+module "acctest_child_b" {
+  source  = "hashicorp/module-installer-acctest/aws//modules/child_b"
+  version = "0.0.1"
+}
diff --git a/v1.5.7/internal/initwd/testing.go b/v1.5.7/internal/initwd/testing.go
new file mode 100644
index 0000000..ae8326c
--- /dev/null
+++ b/v1.5.7/internal/initwd/testing.go
@@ -0,0 +1,77 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package initwd
+
+import (
+	"context"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/registry"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// LoadConfigForTests is a convenience wrapper around configload.NewLoaderForTests,
+// ModuleInstaller.InstallModules and configload.Loader.LoadConfig that allows
+// a test configuration to be loaded in a single step.
+//
+// If module installation fails, t.Fatal (or similar) is called to halt
+// execution of the test, under the assumption that installation failures are
+// not expected. If installation failures _are_ expected then use
+// NewLoaderForTests and work with the loader object directly. If module
+// installation succeeds but generates warnings, these warnings are discarded.
+//
+// If installation succeeds but errors are detected during loading then a
+// possibly-incomplete config is returned along with error diagnostics. The
+// test run is not aborted in this case, so that the caller can make assertions
+// against the returned diagnostics.
+//
+// As with NewLoaderForTests, a cleanup function is returned which must be
+// called before the test completes in order to remove the temporary
+// modules directory.
+func LoadConfigForTests(t *testing.T, rootDir string) (*configs.Config, *configload.Loader, func(), tfdiags.Diagnostics) {
+	t.Helper()
+
+	var diags tfdiags.Diagnostics
+
+	loader, cleanup := configload.NewLoaderForTests(t)
+	inst := NewModuleInstaller(loader.ModulesDir(), loader, registry.NewClient(nil, nil))
+
+	_, moreDiags := inst.InstallModules(context.Background(), rootDir, true, ModuleInstallHooksImpl{})
+	diags = diags.Append(moreDiags)
+	if diags.HasErrors() {
+		cleanup()
+		t.Fatal(diags.Err())
+		return nil, nil, func() {}, diags
+	}
+
+	// Since module installer has modified the module manifest on disk, we need
+	// to refresh the cache of it in the loader.
+	if err := loader.RefreshModules(); err != nil {
+		t.Fatalf("failed to refresh modules after installation: %s", err)
+	}
+
+	config, hclDiags := loader.LoadConfig(rootDir)
+	diags = diags.Append(hclDiags)
+	return config, loader, cleanup, diags
+}
+
+// MustLoadConfigForTests is a variant of LoadConfigForTests which calls
+// t.Fatal (or similar) if there are any errors during loading, and thus
+// does not return diagnostics at all.
+//
+// This is useful for concisely writing tests that don't expect errors at
+// all. For tests that expect errors and need to assert against them, use
+// LoadConfigForTests instead.
+func MustLoadConfigForTests(t *testing.T, rootDir string) (*configs.Config, *configload.Loader, func()) {
+	t.Helper()
+
+	config, loader, cleanup, diags := LoadConfigForTests(t, rootDir)
+	if diags.HasErrors() {
+		cleanup()
+		t.Fatal(diags.Err())
+	}
+	return config, loader, cleanup
+}
diff --git a/v1.5.7/internal/instances/expander.go b/v1.5.7/internal/instances/expander.go
new file mode 100644
index 0000000..f72212b
--- /dev/null
+++ b/v1.5.7/internal/instances/expander.go
@@ -0,0 +1,530 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package instances
+
+import (
+	"fmt"
+	"sort"
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Expander instances serve as a coordination point for gathering object
+// repetition values (count and for_each in configuration) and then later
+// making use of them to fully enumerate all of the instances of an object.
+//
+// The two repeatable object types in Terraform are modules and resources.
+// Because resources belong to modules and modules can nest inside other
+// modules, module expansion in particular has a recursive effect that can
+// cause deep objects to expand exponentially. Expander assumes that all
+// instances of a module have the same static objects inside, and that they
+// differ only in the repetition count for some of those objects.
+//
+// Expander is a synchronized object whose methods can be safely called
+// from concurrent threads of execution. However, it does expect a certain
+// sequence of operations which is normally obtained by the caller traversing
+// a dependency graph: each object must have its repetition mode set exactly
+// once, and this must be done before any calls that depend on the repetition
+// mode. In other words, the count or for_each expression value for a module
+// must be provided before any object nested directly or indirectly inside
+// that module can be expanded. If this ordering is violated, the methods
+// will panic to enforce internal consistency.
+//
+// The Expand* methods of Expander only work directly with modules and with
+// resources. Addresses for other objects that nest within modules but
+// do not themselves support repetition can be obtained by calling ExpandModule
+// with the containing module path and then producing one absolute instance
+// address per module instance address returned.
+type Expander struct {
+	mu   sync.RWMutex
+	exps *expanderModule
+}
+
+// NewExpander initializes and returns a new Expander, empty and ready to use.
+func NewExpander() *Expander {
+	return &Expander{
+		exps: newExpanderModule(),
+	}
+}
+
+// SetModuleSingle records that the given module call inside the given parent
+// module does not use any repetition arguments and is therefore a singleton.
+func (e *Expander) SetModuleSingle(parentAddr addrs.ModuleInstance, callAddr addrs.ModuleCall) {
+	e.setModuleExpansion(parentAddr, callAddr, expansionSingleVal)
+}
+
+// SetModuleCount records that the given module call inside the given parent
+// module instance uses the "count" repetition argument, with the given value.
+func (e *Expander) SetModuleCount(parentAddr addrs.ModuleInstance, callAddr addrs.ModuleCall, count int) {
+	e.setModuleExpansion(parentAddr, callAddr, expansionCount(count))
+}
+
+// SetModuleForEach records that the given module call inside the given parent
+// module instance uses the "for_each" repetition argument, with the given
+// map value.
+//
+// In the configuration language the for_each argument can also accept a set.
+// It's the caller's responsibility to convert that into an identity map before
+// calling this method.
+func (e *Expander) SetModuleForEach(parentAddr addrs.ModuleInstance, callAddr addrs.ModuleCall, mapping map[string]cty.Value) {
+	e.setModuleExpansion(parentAddr, callAddr, expansionForEach(mapping))
+}
+
+// SetResourceSingle records that the given resource inside the given module
+// does not use any repetition arguments and is therefore a singleton.
+func (e *Expander) SetResourceSingle(moduleAddr addrs.ModuleInstance, resourceAddr addrs.Resource) {
+	e.setResourceExpansion(moduleAddr, resourceAddr, expansionSingleVal)
+}
+
+// SetResourceCount records that the given resource inside the given module
+// uses the "count" repetition argument, with the given value.
+func (e *Expander) SetResourceCount(moduleAddr addrs.ModuleInstance, resourceAddr addrs.Resource, count int) {
+	e.setResourceExpansion(moduleAddr, resourceAddr, expansionCount(count))
+}
+
+// SetResourceForEach records that the given resource inside the given module
+// uses the "for_each" repetition argument, with the given map value.
+//
+// In the configuration language the for_each argument can also accept a set.
+// It's the caller's responsibility to convert that into an identity map before
+// calling this method.
+func (e *Expander) SetResourceForEach(moduleAddr addrs.ModuleInstance, resourceAddr addrs.Resource, mapping map[string]cty.Value) {
+	e.setResourceExpansion(moduleAddr, resourceAddr, expansionForEach(mapping))
+}
+
+// ExpandModule finds the exhaustive set of module instances resulting from
+// the expansion of the given module and all of its ancestor modules.
+//
+// All of the modules on the path to the identified module must already have
+// had their expansion registered using one of the SetModule* methods before
+// calling, or this method will panic.
+func (e *Expander) ExpandModule(addr addrs.Module) []addrs.ModuleInstance {
+	return e.expandModule(addr, false)
+}
+
+// expandModule allows skipping unexpanded module addresses by setting skipUnknown to true.
+// This is used by instances.Set, which is only concerned with the expanded
+// instances, and should not panic when looking up unknown addresses.
+func (e *Expander) expandModule(addr addrs.Module, skipUnknown bool) []addrs.ModuleInstance {
+	if len(addr) == 0 {
+		// Root module is always a singleton.
+		return singletonRootModule
+	}
+
+	e.mu.RLock()
+	defer e.mu.RUnlock()
+
+	// We're going to be dynamically growing ModuleInstance addresses, so
+	// we'll preallocate some space to do it so that for typical shallow
+	// module trees we won't need to reallocate this.
+	// (moduleInstances does plenty of allocations itself, so the benefit of
+	// pre-allocating this is marginal but it's not hard to do.)
+	parentAddr := make(addrs.ModuleInstance, 0, 4)
+	ret := e.exps.moduleInstances(addr, parentAddr, skipUnknown)
+	sort.SliceStable(ret, func(i, j int) bool {
+		return ret[i].Less(ret[j])
+	})
+	return ret
+}
+
+// GetDeepestExistingModuleInstance is a funny specialized function for
+// determining how many steps we can traverse through the given module instance
+// address before encountering an undeclared instance of a declared module.
+//
+// The result is the longest prefix of the given address which steps only
+// through module instances that exist.
+//
+// All of the modules on the given path must already have had their
+// expansion registered using one of the SetModule* methods before calling,
+// or this method will panic.
+func (e *Expander) GetDeepestExistingModuleInstance(given addrs.ModuleInstance) addrs.ModuleInstance {
+	exps := e.exps // start with the root module expansions
+	for i := 0; i < len(given); i++ {
+		step := given[i]
+		callName := step.Name
+		if _, ok := exps.moduleCalls[addrs.ModuleCall{Name: callName}]; !ok {
+			// This is a bug in the caller, because it should always register
+			// expansions for an object and all of its ancestors before requesting
+			// expansion of it.
+			panic(fmt.Sprintf("no expansion has been registered for %s", given[:i].Child(callName, addrs.NoKey)))
+		}
+
+		var ok bool
+		exps, ok = exps.childInstances[step]
+		if !ok {
+			// We've found a non-existing instance, so we're done.
+			return given[:i]
+		}
+	}
+
+	// If we complete the loop above without returning early then the entire
+	// given address refers to a declared module instance.
+	return given
+}
+
+// ExpandModuleResource finds the exhaustive set of resource instances resulting from
+// the expansion of the given resource and all of its containing modules.
+//
+// All of the modules on the path to the identified resource and the resource
+// itself must already have had their expansion registered using one of the
+// SetModule*/SetResource* methods before calling, or this method will panic.
+func (e *Expander) ExpandModuleResource(moduleAddr addrs.Module, resourceAddr addrs.Resource) []addrs.AbsResourceInstance {
+	e.mu.RLock()
+	defer e.mu.RUnlock()
+
+	// We're going to be dynamically growing ModuleInstance addresses, so
+	// we'll preallocate some space to do it so that for typical shallow
+	// module trees we won't need to reallocate this.
+	// (moduleInstances does plenty of allocations itself, so the benefit of
+	// pre-allocating this is marginal but it's not hard to do.)
+	moduleInstanceAddr := make(addrs.ModuleInstance, 0, 4)
+	ret := e.exps.moduleResourceInstances(moduleAddr, resourceAddr, moduleInstanceAddr)
+	sort.SliceStable(ret, func(i, j int) bool {
+		return ret[i].Less(ret[j])
+	})
+	return ret
+}
+
+// ExpandResource finds the set of resource instances resulting from
+// the expansion of the given resource within its module instance.
+//
+// All of the modules on the path to the identified resource and the resource
+// itself must already have had their expansion registered using one of the
+// SetModule*/SetResource* methods before calling, or this method will panic.
+//
+// ExpandModuleResource returns all instances of a resource across all
+// instances of its containing module, whereas this ExpandResource function
+// is more specific and only expands within a single module instance. If
+// any of the module instances selected in the module path of the given address
+// aren't valid for that module's expansion then ExpandResource returns an
+// empty result, reflecting that a non-existing module instance can never
+// contain any existing resource instances.
+func (e *Expander) ExpandResource(resourceAddr addrs.AbsResource) []addrs.AbsResourceInstance {
+	e.mu.RLock()
+	defer e.mu.RUnlock()
+
+	moduleInstanceAddr := make(addrs.ModuleInstance, 0, 4)
+	ret := e.exps.resourceInstances(resourceAddr.Module, resourceAddr.Resource, moduleInstanceAddr)
+	sort.SliceStable(ret, func(i, j int) bool {
+		return ret[i].Less(ret[j])
+	})
+	return ret
+}
+
+// GetModuleInstanceRepetitionData returns an object describing the values
+// that should be available for each.key, each.value, and count.index within
+// the call block for the given module instance.
+func (e *Expander) GetModuleInstanceRepetitionData(addr addrs.ModuleInstance) RepetitionData {
+	if len(addr) == 0 {
+		// The root module is always a singleton, so it has no repetition data.
+		return RepetitionData{}
+	}
+
+	e.mu.RLock()
+	defer e.mu.RUnlock()
+
+	parentMod := e.findModule(addr[:len(addr)-1])
+	lastStep := addr[len(addr)-1]
+	exp, ok := parentMod.moduleCalls[addrs.ModuleCall{Name: lastStep.Name}]
+	if !ok {
+		panic(fmt.Sprintf("no expansion has been registered for %s", addr))
+	}
+	return exp.repetitionData(lastStep.InstanceKey)
+}
+
+// GetResourceInstanceRepetitionData returns an object describing the values
+// that should be available for each.key, each.value, and count.index within
+// the definition block for the given resource instance.
+func (e *Expander) GetResourceInstanceRepetitionData(addr addrs.AbsResourceInstance) RepetitionData {
+	e.mu.RLock()
+	defer e.mu.RUnlock()
+
+	parentMod := e.findModule(addr.Module)
+	exp, ok := parentMod.resources[addr.Resource.Resource]
+	if !ok {
+		panic(fmt.Sprintf("no expansion has been registered for %s", addr.ContainingResource()))
+	}
+	return exp.repetitionData(addr.Resource.Key)
+}
+
+// AllInstances returns a set of all of the module and resource instances known
+// to the expander.
+//
+// It generally doesn't make sense to call this until everything has already
+// been fully expanded by calling the SetModule* and SetResource* functions.
+// After that, the returned set is a convenient small API only for querying
+// whether particular instance addresses appeared as a result of those
+// expansions.
+func (e *Expander) AllInstances() Set {
+	return Set{e}
+}
+
+func (e *Expander) findModule(moduleInstAddr addrs.ModuleInstance) *expanderModule {
+	// We expect that all of the modules on the path to our module instance
+	// should already have expansions registered.
+	mod := e.exps
+	for i, step := range moduleInstAddr {
+		next, ok := mod.childInstances[step]
+		if !ok {
+			// Top-down ordering of registration is part of the contract of
+			// Expander, so this is always indicative of a bug in the caller.
+			panic(fmt.Sprintf("no expansion has been registered for ancestor module %s", moduleInstAddr[:i+1]))
+		}
+		mod = next
+	}
+	return mod
+}
+
+func (e *Expander) setModuleExpansion(parentAddr addrs.ModuleInstance, callAddr addrs.ModuleCall, exp expansion) {
+	e.mu.Lock()
+	defer e.mu.Unlock()
+
+	mod := e.findModule(parentAddr)
+	if _, exists := mod.moduleCalls[callAddr]; exists {
+		panic(fmt.Sprintf("expansion already registered for %s", parentAddr.Child(callAddr.Name, addrs.NoKey)))
+	}
+	// We'll also pre-register the child instances so that later calls can
+	// populate them as the caller traverses the configuration tree.
+	for _, key := range exp.instanceKeys() {
+		step := addrs.ModuleInstanceStep{Name: callAddr.Name, InstanceKey: key}
+		mod.childInstances[step] = newExpanderModule()
+	}
+	mod.moduleCalls[callAddr] = exp
+}
+
+func (e *Expander) setResourceExpansion(parentAddr addrs.ModuleInstance, resourceAddr addrs.Resource, exp expansion) {
+	e.mu.Lock()
+	defer e.mu.Unlock()
+
+	mod := e.findModule(parentAddr)
+	if _, exists := mod.resources[resourceAddr]; exists {
+		panic(fmt.Sprintf("expansion already registered for %s", resourceAddr.Absolute(parentAddr)))
+	}
+	mod.resources[resourceAddr] = exp
+}
+
+func (e *Expander) knowsModuleInstance(want addrs.ModuleInstance) bool {
+	if want.IsRoot() {
+		return true // root module instance is always present
+	}
+
+	e.mu.Lock()
+	defer e.mu.Unlock()
+
+	return e.exps.knowsModuleInstance(want)
+}
+
+func (e *Expander) knowsModuleCall(want addrs.AbsModuleCall) bool {
+	e.mu.Lock()
+	defer e.mu.Unlock()
+
+	return e.exps.knowsModuleCall(want)
+}
+
+func (e *Expander) knowsResourceInstance(want addrs.AbsResourceInstance) bool {
+	e.mu.Lock()
+	defer e.mu.Unlock()
+
+	return e.exps.knowsResourceInstance(want)
+}
+
+func (e *Expander) knowsResource(want addrs.AbsResource) bool {
+	e.mu.Lock()
+	defer e.mu.Unlock()
+
+	return e.exps.knowsResource(want)
+}
+
+type expanderModule struct {
+	moduleCalls    map[addrs.ModuleCall]expansion
+	resources      map[addrs.Resource]expansion
+	childInstances map[addrs.ModuleInstanceStep]*expanderModule
+}
+
+func newExpanderModule() *expanderModule {
+	return &expanderModule{
+		moduleCalls:    make(map[addrs.ModuleCall]expansion),
+		resources:      make(map[addrs.Resource]expansion),
+		childInstances: make(map[addrs.ModuleInstanceStep]*expanderModule),
+	}
+}
+
+var singletonRootModule = []addrs.ModuleInstance{addrs.RootModuleInstance}
+
+// if moduleInstances is being used to lookup known instances after all
+// expansions have been done, set skipUnknown to true which allows addrs which
+// may not have been seen to return with no instances rather than panicking.
+func (m *expanderModule) moduleInstances(addr addrs.Module, parentAddr addrs.ModuleInstance, skipUnknown bool) []addrs.ModuleInstance {
+	callName := addr[0]
+	exp, ok := m.moduleCalls[addrs.ModuleCall{Name: callName}]
+	if !ok {
+		if skipUnknown {
+			return nil
+		}
+		// This is a bug in the caller, because it should always register
+		// expansions for an object and all of its ancestors before requesting
+		// expansion of it.
+		panic(fmt.Sprintf("no expansion has been registered for %s", parentAddr.Child(callName, addrs.NoKey)))
+	}
+
+	var ret []addrs.ModuleInstance
+
+	// If there's more than one step remaining then we need to traverse deeper.
+	if len(addr) > 1 {
+		for step, inst := range m.childInstances {
+			if step.Name != callName {
+				continue
+			}
+			instAddr := append(parentAddr, step)
+			ret = append(ret, inst.moduleInstances(addr[1:], instAddr, skipUnknown)...)
+		}
+		return ret
+	}
+
+	// Otherwise, we'll use the expansion from the final step to produce
+	// a sequence of addresses under this prefix.
+	for _, k := range exp.instanceKeys() {
+		// We're reusing the buffer under parentAddr as we recurse through
+		// the structure, so we need to copy it here to produce a final
+		// immutable slice to return.
+		full := make(addrs.ModuleInstance, 0, len(parentAddr)+1)
+		full = append(full, parentAddr...)
+		full = full.Child(callName, k)
+		ret = append(ret, full)
+	}
+	return ret
+}
+
+func (m *expanderModule) moduleResourceInstances(moduleAddr addrs.Module, resourceAddr addrs.Resource, parentAddr addrs.ModuleInstance) []addrs.AbsResourceInstance {
+	if len(moduleAddr) > 0 {
+		var ret []addrs.AbsResourceInstance
+		// We need to traverse through the module levels first, so we can
+		// then iterate resource expansions in the context of each module
+		// path leading to them.
+		callName := moduleAddr[0]
+		if _, ok := m.moduleCalls[addrs.ModuleCall{Name: callName}]; !ok {
+			// This is a bug in the caller, because it should always register
+			// expansions for an object and all of its ancestors before requesting
+			// expansion of it.
+			panic(fmt.Sprintf("no expansion has been registered for %s", parentAddr.Child(callName, addrs.NoKey)))
+		}
+
+		for step, inst := range m.childInstances {
+			if step.Name != callName {
+				continue
+			}
+			moduleInstAddr := append(parentAddr, step)
+			ret = append(ret, inst.moduleResourceInstances(moduleAddr[1:], resourceAddr, moduleInstAddr)...)
+		}
+		return ret
+	}
+
+	return m.onlyResourceInstances(resourceAddr, parentAddr)
+}
+
+func (m *expanderModule) resourceInstances(moduleAddr addrs.ModuleInstance, resourceAddr addrs.Resource, parentAddr addrs.ModuleInstance) []addrs.AbsResourceInstance {
+	if len(moduleAddr) > 0 {
+		// We need to traverse through the module levels first, using only the
+		// module instances for our specific resource, as the resource may not
+		// yet be expanded in all module instances.
+		step := moduleAddr[0]
+		callName := step.Name
+		if _, ok := m.moduleCalls[addrs.ModuleCall{Name: callName}]; !ok {
+			// This is a bug in the caller, because it should always register
+			// expansions for an object and all of its ancestors before requesting
+			// expansion of it.
+			panic(fmt.Sprintf("no expansion has been registered for %s", parentAddr.Child(callName, addrs.NoKey)))
+		}
+
+		if inst, ok := m.childInstances[step]; ok {
+			moduleInstAddr := append(parentAddr, step)
+			return inst.resourceInstances(moduleAddr[1:], resourceAddr, moduleInstAddr)
+		} else {
+			// If we have the module _call_ registered (as we checked above)
+			// but we don't have the given module _instance_ registered, that
+			// suggests that the module instance key in "step" is not declared
+			// by the current definition of this module call. That means the
+			// module instance doesn't exist at all, and therefore it can't
+			// possibly declare any resource instances either.
+			//
+			// For example, if we were asked about module.foo[0].aws_instance.bar
+			// but module.foo doesn't currently have count set, then there is no
+			// module.foo[0] at all, and therefore no aws_instance.bar
+			// instances inside it.
+			return nil
+		}
+	}
+	return m.onlyResourceInstances(resourceAddr, parentAddr)
+}
+
+func (m *expanderModule) onlyResourceInstances(resourceAddr addrs.Resource, parentAddr addrs.ModuleInstance) []addrs.AbsResourceInstance {
+	var ret []addrs.AbsResourceInstance
+	exp, ok := m.resources[resourceAddr]
+	if !ok {
+		panic(fmt.Sprintf("no expansion has been registered for %s", resourceAddr.Absolute(parentAddr)))
+	}
+
+	for _, k := range exp.instanceKeys() {
+		// We're reusing the buffer under parentAddr as we recurse through
+		// the structure, so we need to copy it here to produce a final
+		// immutable slice to return.
+		moduleAddr := make(addrs.ModuleInstance, len(parentAddr))
+		copy(moduleAddr, parentAddr)
+		ret = append(ret, resourceAddr.Instance(k).Absolute(moduleAddr))
+	}
+	return ret
+}
+
+func (m *expanderModule) getModuleInstance(want addrs.ModuleInstance) *expanderModule {
+	current := m
+	for _, step := range want {
+		next := current.childInstances[step]
+		if next == nil {
+			return nil
+		}
+		current = next
+	}
+	return current
+}
+
+func (m *expanderModule) knowsModuleInstance(want addrs.ModuleInstance) bool {
+	return m.getModuleInstance(want) != nil
+}
+
+func (m *expanderModule) knowsModuleCall(want addrs.AbsModuleCall) bool {
+	modInst := m.getModuleInstance(want.Module)
+	if modInst == nil {
+		return false
+	}
+	_, ret := modInst.moduleCalls[want.Call]
+	return ret
+}
+
+func (m *expanderModule) knowsResourceInstance(want addrs.AbsResourceInstance) bool {
+	modInst := m.getModuleInstance(want.Module)
+	if modInst == nil {
+		return false
+	}
+	resourceExp := modInst.resources[want.Resource.Resource]
+	if resourceExp == nil {
+		return false
+	}
+	for _, key := range resourceExp.instanceKeys() {
+		if key == want.Resource.Key {
+			return true
+		}
+	}
+	return false
+}
+
+func (m *expanderModule) knowsResource(want addrs.AbsResource) bool {
+	modInst := m.getModuleInstance(want.Module)
+	if modInst == nil {
+		return false
+	}
+	_, ret := modInst.resources[want.Resource]
+	return ret
+}
diff --git a/v1.5.7/internal/instances/expander_test.go b/v1.5.7/internal/instances/expander_test.go
new file mode 100644
index 0000000..a0d0a38
--- /dev/null
+++ b/v1.5.7/internal/instances/expander_test.go
@@ -0,0 +1,537 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package instances
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestExpander(t *testing.T) {
+	// Some module and resource addresses and values we'll use repeatedly below.
+	singleModuleAddr := addrs.ModuleCall{Name: "single"}
+	count2ModuleAddr := addrs.ModuleCall{Name: "count2"}
+	count0ModuleAddr := addrs.ModuleCall{Name: "count0"}
+	forEachModuleAddr := addrs.ModuleCall{Name: "for_each"}
+	singleResourceAddr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test",
+		Name: "single",
+	}
+	count2ResourceAddr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test",
+		Name: "count2",
+	}
+	count0ResourceAddr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test",
+		Name: "count0",
+	}
+	forEachResourceAddr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test",
+		Name: "for_each",
+	}
+	eachMap := map[string]cty.Value{
+		"a": cty.NumberIntVal(1),
+		"b": cty.NumberIntVal(2),
+	}
+
+	// In normal use, Expander would be called in the context of a graph
+	// traversal to ensure that information is registered/requested in the
+	// correct sequence, but to keep this test self-contained we'll just
+	// manually write out the steps here.
+	//
+	// The steps below are assuming a configuration tree like the following:
+	// - root module
+	//   - resource test.single with no count or for_each
+	//   - resource test.count2 with count = 2
+	//   - resource test.count0 with count = 0
+	//   - resource test.for_each with for_each = { a = 1, b = 2 }
+	//   - child module "single" with no count or for_each
+	//     - resource test.single with no count or for_each
+	//     - resource test.count2 with count = 2
+	//   - child module "count2" with count = 2
+	//     - resource test.single with no count or for_each
+	//     - resource test.count2 with count = 2
+	//     - child module "count2" with count = 2
+	//       - resource test.count2 with count = 2
+	//   - child module "count0" with count = 0
+	//     - resource test.single with no count or for_each
+	//   - child module for_each with for_each = { a = 1, b = 2 }
+	//     - resource test.single with no count or for_each
+	//     - resource test.count2 with count = 2
+
+	ex := NewExpander()
+
+	// We don't register the root module, because it's always implied to exist.
+	//
+	// Below we're going to use braces and indentation just to help visually
+	// reflect the tree structure from the tree in the above comment, in the
+	// hope that the following is easier to follow.
+	//
+	// The Expander API requires that we register containing modules before
+	// registering anything inside them, so we'll work through the above
+	// in a depth-first order in the registration steps that follow.
+	{
+		ex.SetResourceSingle(addrs.RootModuleInstance, singleResourceAddr)
+		ex.SetResourceCount(addrs.RootModuleInstance, count2ResourceAddr, 2)
+		ex.SetResourceCount(addrs.RootModuleInstance, count0ResourceAddr, 0)
+		ex.SetResourceForEach(addrs.RootModuleInstance, forEachResourceAddr, eachMap)
+
+		ex.SetModuleSingle(addrs.RootModuleInstance, singleModuleAddr)
+		{
+			// The single instance of the module
+			moduleInstanceAddr := addrs.RootModuleInstance.Child("single", addrs.NoKey)
+			ex.SetResourceSingle(moduleInstanceAddr, singleResourceAddr)
+			ex.SetResourceCount(moduleInstanceAddr, count2ResourceAddr, 2)
+		}
+
+		ex.SetModuleCount(addrs.RootModuleInstance, count2ModuleAddr, 2)
+		for i1 := 0; i1 < 2; i1++ {
+			moduleInstanceAddr := addrs.RootModuleInstance.Child("count2", addrs.IntKey(i1))
+			ex.SetResourceSingle(moduleInstanceAddr, singleResourceAddr)
+			ex.SetResourceCount(moduleInstanceAddr, count2ResourceAddr, 2)
+			ex.SetModuleCount(moduleInstanceAddr, count2ModuleAddr, 2)
+			for i2 := 0; i2 < 2; i2++ {
+				moduleInstanceAddr := moduleInstanceAddr.Child("count2", addrs.IntKey(i2))
+				ex.SetResourceCount(moduleInstanceAddr, count2ResourceAddr, 2)
+			}
+		}
+
+		ex.SetModuleCount(addrs.RootModuleInstance, count0ModuleAddr, 0)
+		{
+			// There are no instances of module "count0", so our nested module
+			// would never actually get registered here: the expansion node
+			// for the resource would see that its containing module has no
+			// instances and so do nothing.
+		}
+
+		ex.SetModuleForEach(addrs.RootModuleInstance, forEachModuleAddr, eachMap)
+		for k := range eachMap {
+			moduleInstanceAddr := addrs.RootModuleInstance.Child("for_each", addrs.StringKey(k))
+			ex.SetResourceSingle(moduleInstanceAddr, singleResourceAddr)
+			ex.SetResourceCount(moduleInstanceAddr, count2ResourceAddr, 2)
+		}
+	}
+
+	t.Run("root module", func(t *testing.T) {
+		// Requesting expansion of the root module doesn't really mean anything
+		// since it's always a singleton, but for consistency it should work.
+		got := ex.ExpandModule(addrs.RootModule)
+		want := []addrs.ModuleInstance{addrs.RootModuleInstance}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("resource single", func(t *testing.T) {
+		got := ex.ExpandModuleResource(
+			addrs.RootModule,
+			singleResourceAddr,
+		)
+		want := []addrs.AbsResourceInstance{
+			mustAbsResourceInstanceAddr(`test.single`),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("resource count2", func(t *testing.T) {
+		got := ex.ExpandModuleResource(
+			addrs.RootModule,
+			count2ResourceAddr,
+		)
+		want := []addrs.AbsResourceInstance{
+			mustAbsResourceInstanceAddr(`test.count2[0]`),
+			mustAbsResourceInstanceAddr(`test.count2[1]`),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("resource count0", func(t *testing.T) {
+		got := ex.ExpandModuleResource(
+			addrs.RootModule,
+			count0ResourceAddr,
+		)
+		want := []addrs.AbsResourceInstance(nil)
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("resource for_each", func(t *testing.T) {
+		got := ex.ExpandModuleResource(
+			addrs.RootModule,
+			forEachResourceAddr,
+		)
+		want := []addrs.AbsResourceInstance{
+			mustAbsResourceInstanceAddr(`test.for_each["a"]`),
+			mustAbsResourceInstanceAddr(`test.for_each["b"]`),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("module single", func(t *testing.T) {
+		got := ex.ExpandModule(addrs.RootModule.Child("single"))
+		want := []addrs.ModuleInstance{
+			mustModuleInstanceAddr(`module.single`),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("module single resource single", func(t *testing.T) {
+		got := ex.ExpandModuleResource(
+			mustModuleAddr("single"),
+			singleResourceAddr,
+		)
+		want := []addrs.AbsResourceInstance{
+			mustAbsResourceInstanceAddr("module.single.test.single"),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("module single resource count2", func(t *testing.T) {
+		// Two different ways of asking the same question, which should
+		// both produce the same result.
+		// First: nested expansion of all instances of the resource across
+		// all instances of the module, but it's a single-instance module
+		// so the first level is a singleton.
+		got1 := ex.ExpandModuleResource(
+			mustModuleAddr(`single`),
+			count2ResourceAddr,
+		)
+		// Second: expansion of only instances belonging to a specific
+		// instance of the module, but again it's a single-instance module
+		// so there's only one to ask about.
+		got2 := ex.ExpandResource(
+			count2ResourceAddr.Absolute(
+				addrs.RootModuleInstance.Child("single", addrs.NoKey),
+			),
+		)
+		want := []addrs.AbsResourceInstance{
+			mustAbsResourceInstanceAddr(`module.single.test.count2[0]`),
+			mustAbsResourceInstanceAddr(`module.single.test.count2[1]`),
+		}
+		if diff := cmp.Diff(want, got1); diff != "" {
+			t.Errorf("wrong ExpandModuleResource result\n%s", diff)
+		}
+		if diff := cmp.Diff(want, got2); diff != "" {
+			t.Errorf("wrong ExpandResource result\n%s", diff)
+		}
+	})
+	t.Run("module single resource count2 with non-existing module instance", func(t *testing.T) {
+		got := ex.ExpandResource(
+			count2ResourceAddr.Absolute(
+				// Note: This is intentionally an invalid instance key,
+				// so we're asking about module.single[1].test.count2
+				// even though module.single doesn't have count set and
+				// therefore there is no module.single[1].
+				addrs.RootModuleInstance.Child("single", addrs.IntKey(1)),
+			),
+		)
+		// If the containing module instance doesn't exist then it can't
+		// possibly have any resource instances inside it.
+		want := ([]addrs.AbsResourceInstance)(nil)
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("module count2", func(t *testing.T) {
+		got := ex.ExpandModule(mustModuleAddr(`count2`))
+		want := []addrs.ModuleInstance{
+			mustModuleInstanceAddr(`module.count2[0]`),
+			mustModuleInstanceAddr(`module.count2[1]`),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("module count2 resource single", func(t *testing.T) {
+		got := ex.ExpandModuleResource(
+			mustModuleAddr(`count2`),
+			singleResourceAddr,
+		)
+		want := []addrs.AbsResourceInstance{
+			mustAbsResourceInstanceAddr(`module.count2[0].test.single`),
+			mustAbsResourceInstanceAddr(`module.count2[1].test.single`),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("module count2 resource count2", func(t *testing.T) {
+		got := ex.ExpandModuleResource(
+			mustModuleAddr(`count2`),
+			count2ResourceAddr,
+		)
+		want := []addrs.AbsResourceInstance{
+			mustAbsResourceInstanceAddr(`module.count2[0].test.count2[0]`),
+			mustAbsResourceInstanceAddr(`module.count2[0].test.count2[1]`),
+			mustAbsResourceInstanceAddr(`module.count2[1].test.count2[0]`),
+			mustAbsResourceInstanceAddr(`module.count2[1].test.count2[1]`),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("module count2 module count2", func(t *testing.T) {
+		got := ex.ExpandModule(mustModuleAddr(`count2.count2`))
+		want := []addrs.ModuleInstance{
+			mustModuleInstanceAddr(`module.count2[0].module.count2[0]`),
+			mustModuleInstanceAddr(`module.count2[0].module.count2[1]`),
+			mustModuleInstanceAddr(`module.count2[1].module.count2[0]`),
+			mustModuleInstanceAddr(`module.count2[1].module.count2[1]`),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("module count2 module count2 GetDeepestExistingModuleInstance", func(t *testing.T) {
+		t.Run("first step invalid", func(t *testing.T) {
+			got := ex.GetDeepestExistingModuleInstance(mustModuleInstanceAddr(`module.count2["nope"].module.count2[0]`))
+			want := addrs.RootModuleInstance
+			if !want.Equal(got) {
+				t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+			}
+		})
+		t.Run("second step invalid", func(t *testing.T) {
+			got := ex.GetDeepestExistingModuleInstance(mustModuleInstanceAddr(`module.count2[1].module.count2`))
+			want := mustModuleInstanceAddr(`module.count2[1]`)
+			if !want.Equal(got) {
+				t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+			}
+		})
+		t.Run("neither step valid", func(t *testing.T) {
+			got := ex.GetDeepestExistingModuleInstance(mustModuleInstanceAddr(`module.count2.module.count2["nope"]`))
+			want := addrs.RootModuleInstance
+			if !want.Equal(got) {
+				t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+			}
+		})
+		t.Run("both steps valid", func(t *testing.T) {
+			got := ex.GetDeepestExistingModuleInstance(mustModuleInstanceAddr(`module.count2[1].module.count2[0]`))
+			want := mustModuleInstanceAddr(`module.count2[1].module.count2[0]`)
+			if !want.Equal(got) {
+				t.Errorf("wrong result\ngot:  %s\nwant: %s", got, want)
+			}
+		})
+	})
+	t.Run("module count2 resource count2 resource count2", func(t *testing.T) {
+		got := ex.ExpandModuleResource(
+			mustModuleAddr(`count2.count2`),
+			count2ResourceAddr,
+		)
+		want := []addrs.AbsResourceInstance{
+			mustAbsResourceInstanceAddr(`module.count2[0].module.count2[0].test.count2[0]`),
+			mustAbsResourceInstanceAddr(`module.count2[0].module.count2[0].test.count2[1]`),
+			mustAbsResourceInstanceAddr(`module.count2[0].module.count2[1].test.count2[0]`),
+			mustAbsResourceInstanceAddr(`module.count2[0].module.count2[1].test.count2[1]`),
+			mustAbsResourceInstanceAddr(`module.count2[1].module.count2[0].test.count2[0]`),
+			mustAbsResourceInstanceAddr(`module.count2[1].module.count2[0].test.count2[1]`),
+			mustAbsResourceInstanceAddr(`module.count2[1].module.count2[1].test.count2[0]`),
+			mustAbsResourceInstanceAddr(`module.count2[1].module.count2[1].test.count2[1]`),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("module count2 resource count2 resource count2", func(t *testing.T) {
+		got := ex.ExpandResource(
+			count2ResourceAddr.Absolute(mustModuleInstanceAddr(`module.count2[0].module.count2[1]`)),
+		)
+		want := []addrs.AbsResourceInstance{
+			mustAbsResourceInstanceAddr(`module.count2[0].module.count2[1].test.count2[0]`),
+			mustAbsResourceInstanceAddr(`module.count2[0].module.count2[1].test.count2[1]`),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("module count0", func(t *testing.T) {
+		got := ex.ExpandModule(mustModuleAddr(`count0`))
+		want := []addrs.ModuleInstance(nil)
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("module count0 resource single", func(t *testing.T) {
+		got := ex.ExpandModuleResource(
+			mustModuleAddr(`count0`),
+			singleResourceAddr,
+		)
+		// The containing module has zero instances, so therefore there
+		// are zero instances of this resource even though it doesn't have
+		// count = 0 set itself.
+		want := []addrs.AbsResourceInstance(nil)
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("module for_each", func(t *testing.T) {
+		got := ex.ExpandModule(mustModuleAddr(`for_each`))
+		want := []addrs.ModuleInstance{
+			mustModuleInstanceAddr(`module.for_each["a"]`),
+			mustModuleInstanceAddr(`module.for_each["b"]`),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("module for_each resource single", func(t *testing.T) {
+		got := ex.ExpandModuleResource(
+			mustModuleAddr(`for_each`),
+			singleResourceAddr,
+		)
+		want := []addrs.AbsResourceInstance{
+			mustAbsResourceInstanceAddr(`module.for_each["a"].test.single`),
+			mustAbsResourceInstanceAddr(`module.for_each["b"].test.single`),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("module for_each resource count2", func(t *testing.T) {
+		got := ex.ExpandModuleResource(
+			mustModuleAddr(`for_each`),
+			count2ResourceAddr,
+		)
+		want := []addrs.AbsResourceInstance{
+			mustAbsResourceInstanceAddr(`module.for_each["a"].test.count2[0]`),
+			mustAbsResourceInstanceAddr(`module.for_each["a"].test.count2[1]`),
+			mustAbsResourceInstanceAddr(`module.for_each["b"].test.count2[0]`),
+			mustAbsResourceInstanceAddr(`module.for_each["b"].test.count2[1]`),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run("module for_each resource count2", func(t *testing.T) {
+		got := ex.ExpandResource(
+			count2ResourceAddr.Absolute(mustModuleInstanceAddr(`module.for_each["a"]`)),
+		)
+		want := []addrs.AbsResourceInstance{
+			mustAbsResourceInstanceAddr(`module.for_each["a"].test.count2[0]`),
+			mustAbsResourceInstanceAddr(`module.for_each["a"].test.count2[1]`),
+		}
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+
+	t.Run(`module.for_each["b"] repetitiondata`, func(t *testing.T) {
+		got := ex.GetModuleInstanceRepetitionData(
+			mustModuleInstanceAddr(`module.for_each["b"]`),
+		)
+		want := RepetitionData{
+			EachKey:   cty.StringVal("b"),
+			EachValue: cty.NumberIntVal(2),
+		}
+		if diff := cmp.Diff(want, got, cmp.Comparer(valueEquals)); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run(`module.count2[0].module.count2[1] repetitiondata`, func(t *testing.T) {
+		got := ex.GetModuleInstanceRepetitionData(
+			mustModuleInstanceAddr(`module.count2[0].module.count2[1]`),
+		)
+		want := RepetitionData{
+			CountIndex: cty.NumberIntVal(1),
+		}
+		if diff := cmp.Diff(want, got, cmp.Comparer(valueEquals)); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run(`module.for_each["a"] repetitiondata`, func(t *testing.T) {
+		got := ex.GetModuleInstanceRepetitionData(
+			mustModuleInstanceAddr(`module.for_each["a"]`),
+		)
+		want := RepetitionData{
+			EachKey:   cty.StringVal("a"),
+			EachValue: cty.NumberIntVal(1),
+		}
+		if diff := cmp.Diff(want, got, cmp.Comparer(valueEquals)); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+
+	t.Run(`test.for_each["a"] repetitiondata`, func(t *testing.T) {
+		got := ex.GetResourceInstanceRepetitionData(
+			mustAbsResourceInstanceAddr(`test.for_each["a"]`),
+		)
+		want := RepetitionData{
+			EachKey:   cty.StringVal("a"),
+			EachValue: cty.NumberIntVal(1),
+		}
+		if diff := cmp.Diff(want, got, cmp.Comparer(valueEquals)); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run(`module.for_each["a"].test.single repetitiondata`, func(t *testing.T) {
+		got := ex.GetResourceInstanceRepetitionData(
+			mustAbsResourceInstanceAddr(`module.for_each["a"].test.single`),
+		)
+		want := RepetitionData{}
+		if diff := cmp.Diff(want, got, cmp.Comparer(valueEquals)); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+	t.Run(`module.for_each["a"].test.count2[1] repetitiondata`, func(t *testing.T) {
+		got := ex.GetResourceInstanceRepetitionData(
+			mustAbsResourceInstanceAddr(`module.for_each["a"].test.count2[1]`),
+		)
+		want := RepetitionData{
+			CountIndex: cty.NumberIntVal(1),
+		}
+		if diff := cmp.Diff(want, got, cmp.Comparer(valueEquals)); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+}
+
+func mustAbsResourceInstanceAddr(str string) addrs.AbsResourceInstance {
+	addr, diags := addrs.ParseAbsResourceInstanceStr(str)
+	if diags.HasErrors() {
+		panic(fmt.Sprintf("invalid absolute resource instance address: %s", diags.Err()))
+	}
+	return addr
+}
+
+func mustModuleAddr(str string) addrs.Module {
+	if len(str) == 0 {
+		return addrs.RootModule
+	}
+	// We don't have a real parser for these because they don't appear in the
+	// language anywhere, but this interpretation mimics the format we
+	// produce from the String method on addrs.Module.
+	parts := strings.Split(str, ".")
+	return addrs.Module(parts)
+}
+
+func mustModuleInstanceAddr(str string) addrs.ModuleInstance {
+	if len(str) == 0 {
+		return addrs.RootModuleInstance
+	}
+	addr, diags := addrs.ParseModuleInstanceStr(str)
+	if diags.HasErrors() {
+		panic(fmt.Sprintf("invalid module instance address: %s", diags.Err()))
+	}
+	return addr
+}
+
+func valueEquals(a, b cty.Value) bool {
+	if a == cty.NilVal || b == cty.NilVal {
+		return a == b
+	}
+	return a.RawEquals(b)
+}
diff --git a/v1.5.7/internal/instances/expansion_mode.go b/v1.5.7/internal/instances/expansion_mode.go
new file mode 100644
index 0000000..f5e8b5b
--- /dev/null
+++ b/v1.5.7/internal/instances/expansion_mode.go
@@ -0,0 +1,88 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package instances
+
+import (
+	"fmt"
+	"sort"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// expansion is an internal interface used to represent the different
+// ways expansion can operate depending on how repetition is configured for
+// an object.
+type expansion interface {
+	instanceKeys() []addrs.InstanceKey
+	repetitionData(addrs.InstanceKey) RepetitionData
+}
+
+// expansionSingle is the expansion corresponding to no repetition arguments
+// at all, producing a single object with no key.
+//
+// expansionSingleVal is the only valid value of this type.
+type expansionSingle uintptr
+
+var singleKeys = []addrs.InstanceKey{addrs.NoKey}
+var expansionSingleVal expansionSingle
+
+func (e expansionSingle) instanceKeys() []addrs.InstanceKey {
+	return singleKeys
+}
+
+func (e expansionSingle) repetitionData(key addrs.InstanceKey) RepetitionData {
+	if key != addrs.NoKey {
+		panic("cannot use instance key with non-repeating object")
+	}
+	return RepetitionData{}
+}
+
+// expansionCount is the expansion corresponding to the "count" argument.
+type expansionCount int
+
+func (e expansionCount) instanceKeys() []addrs.InstanceKey {
+	ret := make([]addrs.InstanceKey, int(e))
+	for i := range ret {
+		ret[i] = addrs.IntKey(i)
+	}
+	return ret
+}
+
+func (e expansionCount) repetitionData(key addrs.InstanceKey) RepetitionData {
+	i := int(key.(addrs.IntKey))
+	if i < 0 || i >= int(e) {
+		panic(fmt.Sprintf("instance key %d out of range for count %d", i, e))
+	}
+	return RepetitionData{
+		CountIndex: cty.NumberIntVal(int64(i)),
+	}
+}
+
+// expansionForEach is the expansion corresponding to the "for_each" argument.
+type expansionForEach map[string]cty.Value
+
+func (e expansionForEach) instanceKeys() []addrs.InstanceKey {
+	ret := make([]addrs.InstanceKey, 0, len(e))
+	for k := range e {
+		ret = append(ret, addrs.StringKey(k))
+	}
+	sort.Slice(ret, func(i, j int) bool {
+		return ret[i].(addrs.StringKey) < ret[j].(addrs.StringKey)
+	})
+	return ret
+}
+
+func (e expansionForEach) repetitionData(key addrs.InstanceKey) RepetitionData {
+	k := string(key.(addrs.StringKey))
+	v, ok := e[k]
+	if !ok {
+		panic(fmt.Sprintf("instance key %q does not match any instance", k))
+	}
+	return RepetitionData{
+		EachKey:   cty.StringVal(k),
+		EachValue: v,
+	}
+}
diff --git a/v1.5.7/internal/instances/instance_key_data.go b/v1.5.7/internal/instances/instance_key_data.go
new file mode 100644
index 0000000..595f918
--- /dev/null
+++ b/v1.5.7/internal/instances/instance_key_data.go
@@ -0,0 +1,31 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package instances
+
+import (
+	"github.com/zclconf/go-cty/cty"
+)
+
+// RepetitionData represents the values available to identify individual
+// repetitions of a particular object.
+//
+// This corresponds to the each.key, each.value, and count.index symbols in
+// the configuration language.
+type RepetitionData struct {
+	// CountIndex is the value for count.index, or cty.NilVal if evaluating
+	// in a context where the "count" argument is not active.
+	//
+	// For correct operation, this should always be of type cty.Number if not
+	// nil.
+	CountIndex cty.Value
+
+	// EachKey and EachValue are the values for each.key and each.value
+	// respectively, or cty.NilVal if evaluating in a context where the
+	// "for_each" argument is not active. These must either both be set
+	// or neither set.
+	//
+	// For correct operation, EachKey must always be either of type cty.String
+	// or cty.Number if not nil.
+	EachKey, EachValue cty.Value
+}
diff --git a/v1.5.7/internal/instances/set.go b/v1.5.7/internal/instances/set.go
new file mode 100644
index 0000000..a1f8842
--- /dev/null
+++ b/v1.5.7/internal/instances/set.go
@@ -0,0 +1,54 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package instances
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// Set is a set of instances, intended mainly for the return value of
+// Expander.AllInstances, where it therefore represents all of the module
+// and resource instances known to the expander.
+type Set struct {
+	// Set currently really just wraps Expander with a reduced API that
+	// only supports lookups, to make it clear that a holder of a Set should
+	// not be modifying the expander any further.
+	exp *Expander
+}
+
+// HasModuleInstance returns true if and only if the set contains the module
+// instance with the given address.
+func (s Set) HasModuleInstance(want addrs.ModuleInstance) bool {
+	return s.exp.knowsModuleInstance(want)
+}
+
+// HasModuleCall returns true if and only if the set contains the module
+// call with the given address, even if that module call has no instances.
+func (s Set) HasModuleCall(want addrs.AbsModuleCall) bool {
+	return s.exp.knowsModuleCall(want)
+}
+
+// HasResourceInstance returns true if and only if the set contains the resource
+// instance with the given address.
+// TODO:
+func (s Set) HasResourceInstance(want addrs.AbsResourceInstance) bool {
+	return s.exp.knowsResourceInstance(want)
+}
+
+// HasResource returns true if and only if the set contains the resource with
+// the given address, even if that resource has no instances.
+// TODO:
+func (s Set) HasResource(want addrs.AbsResource) bool {
+	return s.exp.knowsResource(want)
+}
+
+// InstancesForModule returns all of the module instances that correspond with
+// the given static module path.
+//
+// If there are multiple module calls in the path that have repetition enabled
+// then the result is the full expansion of all combinations of all of their
+// declared instance keys.
+func (s Set) InstancesForModule(modAddr addrs.Module) []addrs.ModuleInstance {
+	return s.exp.expandModule(modAddr, true)
+}
diff --git a/v1.5.7/internal/instances/set_test.go b/v1.5.7/internal/instances/set_test.go
new file mode 100644
index 0000000..2b64147
--- /dev/null
+++ b/v1.5.7/internal/instances/set_test.go
@@ -0,0 +1,214 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package instances
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestSet(t *testing.T) {
+	exp := NewExpander()
+
+	// The following constructs the following imaginary module/resource tree:
+	// - root module
+	//   - test_thing.single: no repetition
+	//   - test_thing.count: count = 1
+	//   - test_thing.for_each: for_each = { c = "C" }
+	//   - module.single: no repetition
+	//     - test_thing.single: no repetition
+	//     - module.nested_single: no repetition
+	//       - module.zero_count: count = 0
+	//   - module.count: count = 2
+	//     - module.nested_for_each: [0] for_each = {}, [1] for_each = { e = "E" }
+	//   - module.for_each: for_each = { a = "A", b = "B" }
+	//     - test_thing.count: ["a"] count = 0, ["b"] count = 1
+	exp.SetModuleSingle(addrs.RootModuleInstance, addrs.ModuleCall{Name: "single"})
+	exp.SetModuleCount(addrs.RootModuleInstance, addrs.ModuleCall{Name: "count"}, 2)
+	exp.SetModuleForEach(addrs.RootModuleInstance, addrs.ModuleCall{Name: "for_each"}, map[string]cty.Value{
+		"a": cty.StringVal("A"),
+		"b": cty.StringVal("B"),
+	})
+	exp.SetModuleSingle(addrs.RootModuleInstance.Child("single", addrs.NoKey), addrs.ModuleCall{Name: "nested_single"})
+	exp.SetModuleForEach(addrs.RootModuleInstance.Child("count", addrs.IntKey(0)), addrs.ModuleCall{Name: "nested_for_each"}, nil)
+	exp.SetModuleForEach(addrs.RootModuleInstance.Child("count", addrs.IntKey(1)), addrs.ModuleCall{Name: "nested_for_each"}, map[string]cty.Value{
+		"e": cty.StringVal("E"),
+	})
+	exp.SetModuleCount(
+		addrs.RootModuleInstance.Child("single", addrs.NoKey).Child("nested_single", addrs.NoKey),
+		addrs.ModuleCall{Name: "zero_count"},
+		0,
+	)
+
+	rAddr := func(name string) addrs.Resource {
+		return addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_thing",
+			Name: name,
+		}
+	}
+	exp.SetResourceSingle(addrs.RootModuleInstance, rAddr("single"))
+	exp.SetResourceCount(addrs.RootModuleInstance, rAddr("count"), 1)
+	exp.SetResourceForEach(addrs.RootModuleInstance, rAddr("for_each"), map[string]cty.Value{
+		"c": cty.StringVal("C"),
+	})
+	exp.SetResourceSingle(addrs.RootModuleInstance.Child("single", addrs.NoKey), rAddr("single"))
+	exp.SetResourceCount(addrs.RootModuleInstance.Child("for_each", addrs.StringKey("a")), rAddr("count"), 0)
+	exp.SetResourceCount(addrs.RootModuleInstance.Child("for_each", addrs.StringKey("b")), rAddr("count"), 1)
+
+	set := exp.AllInstances()
+
+	// HasModuleInstance tests
+	if input := addrs.RootModuleInstance; !set.HasModuleInstance(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("single", addrs.NoKey); !set.HasModuleInstance(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("single", addrs.NoKey).Child("nested_single", addrs.NoKey); !set.HasModuleInstance(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("count", addrs.IntKey(0)); !set.HasModuleInstance(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("count", addrs.IntKey(1)); !set.HasModuleInstance(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("count", addrs.IntKey(1)).Child("nested_for_each", addrs.StringKey("e")); !set.HasModuleInstance(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("for_each", addrs.StringKey("a")); !set.HasModuleInstance(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("for_each", addrs.StringKey("b")); !set.HasModuleInstance(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("single", addrs.IntKey(0)); set.HasModuleInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("single", addrs.StringKey("a")); set.HasModuleInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("single", addrs.NoKey).Child("nonexist", addrs.NoKey); set.HasModuleInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("count", addrs.NoKey); set.HasModuleInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("count", addrs.IntKey(2)); set.HasModuleInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("count", addrs.StringKey("a")); set.HasModuleInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("count", addrs.IntKey(0)).Child("nested_for_each", addrs.StringKey("e")); set.HasModuleInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("single", addrs.NoKey).Child("nested_single", addrs.NoKey).Child("zero_count", addrs.NoKey); set.HasModuleInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("single", addrs.NoKey).Child("nested_single", addrs.NoKey).Child("zero_count", addrs.IntKey(0)); set.HasModuleInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+
+	// HasModuleCall tests
+	if input := addrs.RootModuleInstance.ChildCall("single"); !set.HasModuleCall(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("single", addrs.NoKey).ChildCall("nested_single"); !set.HasModuleCall(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.ChildCall("count"); !set.HasModuleCall(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("count", addrs.IntKey(0)).ChildCall("nested_for_each"); !set.HasModuleCall(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("count", addrs.IntKey(1)).ChildCall("nested_for_each"); !set.HasModuleCall(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.ChildCall("for_each"); !set.HasModuleCall(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("single", addrs.NoKey).Child("nested_single", addrs.NoKey).ChildCall("zero_count"); !set.HasModuleCall(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.ChildCall("nonexist"); set.HasModuleCall(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := addrs.RootModuleInstance.Child("single", addrs.NoKey).ChildCall("nonexist"); set.HasModuleCall(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+
+	// HasResourceInstance tests
+	if input := rAddr("single").Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance); !set.HasResourceInstance(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := rAddr("count").Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance); !set.HasResourceInstance(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := rAddr("for_each").Instance(addrs.StringKey("c")).Absolute(addrs.RootModuleInstance); !set.HasResourceInstance(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := rAddr("single").Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("single", addrs.NoKey)); !set.HasResourceInstance(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := rAddr("count").Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance.Child("for_each", addrs.StringKey("b"))); !set.HasResourceInstance(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := rAddr("single").Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance); set.HasResourceInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := rAddr("single").Instance(addrs.StringKey("")).Absolute(addrs.RootModuleInstance); set.HasResourceInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := rAddr("count").Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance); set.HasResourceInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := rAddr("count").Instance(addrs.StringKey("")).Absolute(addrs.RootModuleInstance); set.HasResourceInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := rAddr("count").Instance(addrs.IntKey(1)).Absolute(addrs.RootModuleInstance); set.HasResourceInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := rAddr("single").Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("single", addrs.IntKey(0))); set.HasResourceInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := rAddr("count").Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance.Child("for_each", addrs.StringKey("a"))); set.HasResourceInstance(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+
+	// HasResource tests
+	if input := rAddr("single").Absolute(addrs.RootModuleInstance); !set.HasResource(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := rAddr("count").Absolute(addrs.RootModuleInstance); !set.HasResource(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := rAddr("for_each").Absolute(addrs.RootModuleInstance); !set.HasResource(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := rAddr("single").Absolute(addrs.RootModuleInstance.Child("single", addrs.NoKey)); !set.HasResource(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := rAddr("count").Absolute(addrs.RootModuleInstance.Child("for_each", addrs.StringKey("a"))); !set.HasResource(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := rAddr("count").Absolute(addrs.RootModuleInstance.Child("for_each", addrs.StringKey("b"))); !set.HasResource(input) {
+		t.Errorf("missing %T %s", input, input.String())
+	}
+	if input := rAddr("nonexist").Absolute(addrs.RootModuleInstance); set.HasResource(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+	if input := rAddr("count").Absolute(addrs.RootModuleInstance.Child("for_each", addrs.StringKey("nonexist"))); set.HasResource(input) {
+		t.Errorf("unexpected %T %s", input, input.String())
+	}
+
+	// ensure we can lookup non-existent addrs in a set without panic
+	if set.InstancesForModule(addrs.RootModule.Child("missing")) != nil {
+		t.Error("unexpected instances from missing module")
+	}
+}
diff --git a/v1.5.7/internal/ipaddr/LICENSE b/v1.5.7/internal/ipaddr/LICENSE
new file mode 100644
index 0000000..7448756
--- /dev/null
+++ b/v1.5.7/internal/ipaddr/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2012 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/v1.5.7/internal/ipaddr/PATENTS b/v1.5.7/internal/ipaddr/PATENTS
new file mode 100644
index 0000000..7330990
--- /dev/null
+++ b/v1.5.7/internal/ipaddr/PATENTS
@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google hereby grants to You a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this section)
+patent license to make, have made, use, offer to sell, sell, import,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go.  This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation.  If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.
diff --git a/v1.5.7/internal/ipaddr/README.md b/v1.5.7/internal/ipaddr/README.md
new file mode 100644
index 0000000..f0d5498
--- /dev/null
+++ b/v1.5.7/internal/ipaddr/README.md
@@ -0,0 +1,34 @@
+# Forked IP address parsing functions
+
+This directory contains a subset of code from the Go project's `net` package
+as of Go 1.16, used under the Go project license which we've included here
+in [`LICENSE`](LICENSE) and [`PATENTS`](PATENTS), which are also copied from
+the Go project.
+
+Terraform has its own fork of these functions because Go 1.17 included a
+breaking change to reject IPv4 address octets written with leading zeros.
+
+The Go project rationale for that change was that Go historically interpreted
+leading-zero octets inconsistently with many other implementations, trimming
+off the zeros and still treating the rest as decimal rather than treating the
+octet as octal.
+
+The Go team made the reasonable observation that having a function that
+interprets a non-normalized form in a manner inconsistent with other
+implementations may cause naive validation or policy checks to produce
+incorrect results, and thus it's a potential security concern. For more
+information, see [Go issue #30999](https://golang.org/issue/30999).
+
+After careful consideration, the Terraform team has concluded that Terraform's
+use of these functions as part of the implementation of the `cidrhost`,
+`cidrsubnet`, `cidrsubnets`, and `cidrnetmask` functions has a more limited
+impact than the general availability of these functions in the Go standard
+library, and so we can't justify a similar exception to our Terraform 1.0
+compatibility promises as the Go team made to their Go 1.0 compatibility
+promises.
+
+If you're considering using this package for new functionality _other than_ the
+built-in functions mentioned above, please do so only if consistency with the
+behavior of those functions is important. Otherwise, new features are not
+burdened by the same compatibility constraints and so should typically prefer
+to use the stricter interpretation of the upstream parsing functions.
diff --git a/v1.5.7/internal/ipaddr/doc.go b/v1.5.7/internal/ipaddr/doc.go
new file mode 100644
index 0000000..e9438c1
--- /dev/null
+++ b/v1.5.7/internal/ipaddr/doc.go
@@ -0,0 +1,9 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package ipaddr is a fork of a subset of the Go standard "net" package which
+// retains parsing behaviors from Go 1.16 or earlier.
+//
+// Don't use this for any new code without careful consideration. See the
+// README.md in the package directory for more information.
+package ipaddr
diff --git a/v1.5.7/internal/ipaddr/ip.go b/v1.5.7/internal/ipaddr/ip.go
new file mode 100644
index 0000000..6d1c75d
--- /dev/null
+++ b/v1.5.7/internal/ipaddr/ip.go
@@ -0,0 +1,226 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// IP address manipulations
+//
+// IPv4 addresses are 4 bytes; IPv6 addresses are 16 bytes.
+// An IPv4 address can be converted to an IPv6 address by
+// adding a canonical prefix (10 zeros, 2 0xFFs).
+// This library accepts either size of byte slice but always
+// returns 16-byte addresses.
+
+package ipaddr
+
+import (
+	stdnet "net"
+)
+
+//
+// Lean on the standard net lib as much as possible.
+//
+
+type IP = stdnet.IP
+type IPNet = stdnet.IPNet
+type ParseError = stdnet.ParseError
+
+const IPv4len = stdnet.IPv4len
+const IPv6len = stdnet.IPv6len
+
+var CIDRMask = stdnet.CIDRMask
+var IPv4 = stdnet.IPv4
+
+// Parse IPv4 address (d.d.d.d).
+func parseIPv4(s string) IP {
+	var p [IPv4len]byte
+	for i := 0; i < IPv4len; i++ {
+		if len(s) == 0 {
+			// Missing octets.
+			return nil
+		}
+		if i > 0 {
+			if s[0] != '.' {
+				return nil
+			}
+			s = s[1:]
+		}
+		n, c, ok := dtoi(s)
+		if !ok || n > 0xFF {
+			return nil
+		}
+		//
+		// NOTE: This correct check was added for go-1.17, but is a
+		// backwards-incompatible change for Terraform users, who might have
+		// already written modules with leading zeroes.
+		//
+		//if c > 1 && s[0] == '0' {
+		//	// Reject non-zero components with leading zeroes.
+		//	return nil
+		//}
+		s = s[c:]
+		p[i] = byte(n)
+	}
+	if len(s) != 0 {
+		return nil
+	}
+	return IPv4(p[0], p[1], p[2], p[3])
+}
+
+// parseIPv6 parses s as a literal IPv6 address described in RFC 4291
+// and RFC 5952.
+func parseIPv6(s string) (ip IP) {
+	ip = make(IP, IPv6len)
+	ellipsis := -1 // position of ellipsis in ip
+
+	// Might have leading ellipsis
+	if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
+		ellipsis = 0
+		s = s[2:]
+		// Might be only ellipsis
+		if len(s) == 0 {
+			return ip
+		}
+	}
+
+	// Loop, parsing hex numbers followed by colon.
+	i := 0
+	for i < IPv6len {
+		// Hex number.
+		n, c, ok := xtoi(s)
+		if !ok || n > 0xFFFF {
+			return nil
+		}
+
+		// If followed by dot, might be in trailing IPv4.
+		if c < len(s) && s[c] == '.' {
+			if ellipsis < 0 && i != IPv6len-IPv4len {
+				// Not the right place.
+				return nil
+			}
+			if i+IPv4len > IPv6len {
+				// Not enough room.
+				return nil
+			}
+			ip4 := parseIPv4(s)
+			if ip4 == nil {
+				return nil
+			}
+			ip[i] = ip4[12]
+			ip[i+1] = ip4[13]
+			ip[i+2] = ip4[14]
+			ip[i+3] = ip4[15]
+			s = ""
+			i += IPv4len
+			break
+		}
+
+		// Save this 16-bit chunk.
+		ip[i] = byte(n >> 8)
+		ip[i+1] = byte(n)
+		i += 2
+
+		// Stop at end of string.
+		s = s[c:]
+		if len(s) == 0 {
+			break
+		}
+
+		// Otherwise must be followed by colon and more.
+		if s[0] != ':' || len(s) == 1 {
+			return nil
+		}
+		s = s[1:]
+
+		// Look for ellipsis.
+		if s[0] == ':' {
+			if ellipsis >= 0 { // already have one
+				return nil
+			}
+			ellipsis = i
+			s = s[1:]
+			if len(s) == 0 { // can be at end
+				break
+			}
+		}
+	}
+
+	// Must have used entire string.
+	if len(s) != 0 {
+		return nil
+	}
+
+	// If didn't parse enough, expand ellipsis.
+	if i < IPv6len {
+		if ellipsis < 0 {
+			return nil
+		}
+		n := IPv6len - i
+		for j := i - 1; j >= ellipsis; j-- {
+			ip[j+n] = ip[j]
+		}
+		for j := ellipsis + n - 1; j >= ellipsis; j-- {
+			ip[j] = 0
+		}
+	} else if ellipsis >= 0 {
+		// Ellipsis must represent at least one 0 group.
+		return nil
+	}
+	return ip
+}
+
+// ParseIP parses s as an IP address, returning the result.
+// The string s can be in IPv4 dotted decimal ("192.0.2.1"), IPv6
+// ("2001:db8::68"), or IPv4-mapped IPv6 ("::ffff:192.0.2.1") form.
+// If s is not a valid textual representation of an IP address,
+// ParseIP returns nil.
+func ParseIP(s string) IP {
+	for i := 0; i < len(s); i++ {
+		switch s[i] {
+		case '.':
+			return parseIPv4(s)
+		case ':':
+			return parseIPv6(s)
+		}
+	}
+	return nil
+}
+
+// ParseCIDR parses s as a CIDR notation IP address and prefix length,
+// like "192.0.2.0/24" or "2001:db8::/32", as defined in
+// RFC 4632 and RFC 4291.
+//
+// It returns the IP address and the network implied by the IP and
+// prefix length.
+// For example, ParseCIDR("192.0.2.1/24") returns the IP address
+// 192.0.2.1 and the network 192.0.2.0/24.
+func ParseCIDR(s string) (IP, *IPNet, error) {
+	i := indexByteString(s, '/')
+	if i < 0 {
+		return nil, nil, &ParseError{Type: "CIDR address", Text: s}
+	}
+	addr, mask := s[:i], s[i+1:]
+	iplen := IPv4len
+	ip := parseIPv4(addr)
+	if ip == nil {
+		iplen = IPv6len
+		ip = parseIPv6(addr)
+	}
+	n, i, ok := dtoi(mask)
+	if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen {
+		return nil, nil, &ParseError{Type: "CIDR address", Text: s}
+	}
+	m := CIDRMask(n, 8*iplen)
+	return ip, &IPNet{IP: ip.Mask(m), Mask: m}, nil
+}
+
+// This is copied from go/src/internal/bytealg, which includes versions
+// optimized for various platforms.  Those optimizations are elided here so we
+// don't have to maintain them.
+func indexByteString(s string, c byte) int {
+	for i := 0; i < len(s); i++ {
+		if s[i] == c {
+			return i
+		}
+	}
+	return -1
+}
diff --git a/v1.5.7/internal/ipaddr/ip_test.go b/v1.5.7/internal/ipaddr/ip_test.go
new file mode 100644
index 0000000..de20dc0
--- /dev/null
+++ b/v1.5.7/internal/ipaddr/ip_test.go
@@ -0,0 +1,124 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ipaddr
+
+import (
+	stdnet "net"
+	"reflect"
+	"testing"
+)
+
+// Lean on the standard net lib as much as possible.
+type IPMask = stdnet.IPMask
+
+var IPv4Mask = stdnet.IPv4Mask
+
+var parseIPTests = []struct {
+	in  string
+	out IP
+}{
+	{"127.0.1.2", IPv4(127, 0, 1, 2)},
+	{"127.0.0.1", IPv4(127, 0, 0, 1)},
+	{"127.001.002.003", IPv4(127, 1, 2, 3)},
+	{"127.007.008.009", IPv4(127, 7, 8, 9)},
+	{"127.010.020.030", IPv4(127, 10, 20, 30)},
+	{"::ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
+	{"::ffff:127.001.002.003", IPv4(127, 1, 2, 3)},
+	{"::ffff:127.007.008.009", IPv4(127, 7, 8, 9)},
+	{"::ffff:127.010.020.030", IPv4(127, 10, 20, 30)},
+	{"::ffff:7f01:0203", IPv4(127, 1, 2, 3)},
+	{"0:0:0:0:0000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
+	{"0:0:0:0:000000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
+	{"0:0:0:0::ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
+
+	{"2001:4860:0:2001::68", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
+	{"2001:4860:0000:2001:0000:0000:0000:0068", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
+
+	{"-0.0.0.0", nil},
+	{"0.-1.0.0", nil},
+	{"0.0.-2.0", nil},
+	{"0.0.0.-3", nil},
+	{"127.0.0.256", nil},
+	{"abc", nil},
+	{"123:", nil},
+	{"fe80::1%lo0", nil},
+	{"fe80::1%911", nil},
+	{"", nil},
+	{"a1:a2:a3:a4::b1:b2:b3:b4", nil}, // Issue 6628
+	//
+	// NOTE: These correct failures were added for go-1.17, but are a
+	// backwards-incompatible change for Terraform users, who might have
+	// already written modules using leading zeroes.
+	//
+	//{"127.001.002.003", nil},
+	//{"::ffff:127.001.002.003", nil},
+	//{"123.000.000.000", nil},
+	//{"1.2..4", nil},
+	//{"0123.0.0.1", nil},
+}
+
+func TestParseIP(t *testing.T) {
+	for _, tt := range parseIPTests {
+		if out := ParseIP(tt.in); !reflect.DeepEqual(out, tt.out) {
+			t.Errorf("ParseIP(%q) = %v, want %v", tt.in, out, tt.out)
+		}
+	}
+}
+
+var parseCIDRTests = []struct {
+	in  string
+	ip  IP
+	net *IPNet
+	err error
+}{
+	{"135.104.0.0/32", IPv4(135, 104, 0, 0), &IPNet{IP: IPv4(135, 104, 0, 0), Mask: IPv4Mask(255, 255, 255, 255)}, nil},
+	{"0.0.0.0/24", IPv4(0, 0, 0, 0), &IPNet{IP: IPv4(0, 0, 0, 0), Mask: IPv4Mask(255, 255, 255, 0)}, nil},
+	{"135.104.0.0/24", IPv4(135, 104, 0, 0), &IPNet{IP: IPv4(135, 104, 0, 0), Mask: IPv4Mask(255, 255, 255, 0)}, nil},
+	{"135.104.0.1/32", IPv4(135, 104, 0, 1), &IPNet{IP: IPv4(135, 104, 0, 1), Mask: IPv4Mask(255, 255, 255, 255)}, nil},
+	{"135.104.0.1/24", IPv4(135, 104, 0, 1), &IPNet{IP: IPv4(135, 104, 0, 0), Mask: IPv4Mask(255, 255, 255, 0)}, nil},
+	{"127.000.000.001/32", IPv4(127, 0, 0, 1), &IPNet{IP: IPv4(127, 0, 0, 1), Mask: IPv4Mask(255, 255, 255, 255)}, nil},
+	{"127.007.008.009/32", IPv4(127, 7, 8, 9), &IPNet{IP: IPv4(127, 7, 8, 9), Mask: IPv4Mask(255, 255, 255, 255)}, nil},
+	{"127.010.020.030/32", IPv4(127, 10, 20, 30), &IPNet{IP: IPv4(127, 10, 20, 30), Mask: IPv4Mask(255, 255, 255, 255)}, nil},
+	{"::1/128", ParseIP("::1"), &IPNet{IP: ParseIP("::1"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))}, nil},
+	{"abcd:2345::/127", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe"))}, nil},
+	{"abcd:2345::/65", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:8000::"))}, nil},
+	{"abcd:2345::/64", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff::"))}, nil},
+	{"abcd:2345::/63", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:fffe::"))}, nil},
+	{"abcd:2345::/33", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:8000::"))}, nil},
+	{"abcd:2345::/32", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff::"))}, nil},
+	{"abcd:2344::/31", ParseIP("abcd:2344::"), &IPNet{IP: ParseIP("abcd:2344::"), Mask: IPMask(ParseIP("ffff:fffe::"))}, nil},
+	{"abcd:2300::/24", ParseIP("abcd:2300::"), &IPNet{IP: ParseIP("abcd:2300::"), Mask: IPMask(ParseIP("ffff:ff00::"))}, nil},
+	{"abcd:2345::/24", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2300::"), Mask: IPMask(ParseIP("ffff:ff00::"))}, nil},
+	{"2001:DB8::/48", ParseIP("2001:DB8::"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
+	{"2001:DB8::1/48", ParseIP("2001:DB8::1"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
+	{"192.168.1.1/255.255.255.0", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/255.255.255.0"}},
+	{"192.168.1.1/35", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/35"}},
+	{"2001:db8::1/-1", nil, nil, &ParseError{Type: "CIDR address", Text: "2001:db8::1/-1"}},
+	{"2001:db8::1/-0", nil, nil, &ParseError{Type: "CIDR address", Text: "2001:db8::1/-0"}},
+	{"-0.0.0.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "-0.0.0.0/32"}},
+	{"0.-1.0.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.-1.0.0/32"}},
+	{"0.0.-2.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.-2.0/32"}},
+	{"0.0.0.-3/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.-3/32"}},
+	{"0.0.0.0/-0", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.0/-0"}},
+	//
+	// NOTE: Theis correct failure was added for go-1.17, but is a
+	// backwards-incompatible change for Terraform users, who might have
+	// already written modules using leading zeroes.
+	//
+	//{"127.000.000.001/32", nil, nil, &ParseError{Type: "CIDR address", Text: "127.000.000.001/32"}},
+	{"", nil, nil, &ParseError{Type: "CIDR address", Text: ""}},
+}
+
+func TestParseCIDR(t *testing.T) {
+	for _, tt := range parseCIDRTests {
+		ip, net, err := ParseCIDR(tt.in)
+		if !reflect.DeepEqual(err, tt.err) {
+			t.Errorf("ParseCIDR(%q) = %v, %v; want %v, %v", tt.in, ip, net, tt.ip, tt.net)
+		}
+		if err == nil && (!tt.ip.Equal(ip) || !tt.net.IP.Equal(net.IP) || !reflect.DeepEqual(net.Mask, tt.net.Mask)) {
+			t.Errorf("ParseCIDR(%q) = %v, {%v, %v}; want %v, {%v, %v}", tt.in, ip, net.IP, net.Mask, tt.ip, tt.net.IP, tt.net.Mask)
+		}
+	}
+}
diff --git a/v1.5.7/internal/ipaddr/parse.go b/v1.5.7/internal/ipaddr/parse.go
new file mode 100644
index 0000000..07d6eec
--- /dev/null
+++ b/v1.5.7/internal/ipaddr/parse.go
@@ -0,0 +1,54 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Simple file i/o and string manipulation, to avoid
+// depending on strconv and bufio and strings.
+
+package ipaddr
+
+// Bigger than we need, not too big to worry about overflow
+const big = 0xFFFFFF
+
+// Decimal to integer.
+// Returns number, characters consumed, success.
+func dtoi(s string) (n int, i int, ok bool) {
+	n = 0
+	for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
+		n = n*10 + int(s[i]-'0')
+		if n >= big {
+			return big, i, false
+		}
+	}
+	if i == 0 {
+		return 0, 0, false
+	}
+	return n, i, true
+}
+
+// Hexadecimal to integer.
+// Returns number, characters consumed, success.
+func xtoi(s string) (n int, i int, ok bool) {
+	n = 0
+	for i = 0; i < len(s); i++ {
+		if '0' <= s[i] && s[i] <= '9' {
+			n *= 16
+			n += int(s[i] - '0')
+		} else if 'a' <= s[i] && s[i] <= 'f' {
+			n *= 16
+			n += int(s[i]-'a') + 10
+		} else if 'A' <= s[i] && s[i] <= 'F' {
+			n *= 16
+			n += int(s[i]-'A') + 10
+		} else {
+			break
+		}
+		if n >= big {
+			return 0, i, false
+		}
+	}
+	if i == 0 {
+		return 0, i, false
+	}
+	return n, i, true
+}
diff --git a/v1.5.7/internal/lang/blocktoattr/doc.go b/v1.5.7/internal/lang/blocktoattr/doc.go
new file mode 100644
index 0000000..f3cf322
--- /dev/null
+++ b/v1.5.7/internal/lang/blocktoattr/doc.go
@@ -0,0 +1,8 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package blocktoattr includes some helper functions that can perform
+// preprocessing on a HCL body where a configschema.Block schema is available
+// in order to allow list and set attributes defined in the schema to be
+// optionally written by the user as block syntax.
+package blocktoattr
diff --git a/v1.5.7/internal/lang/blocktoattr/fixup.go b/v1.5.7/internal/lang/blocktoattr/fixup.go
new file mode 100644
index 0000000..f2233fd
--- /dev/null
+++ b/v1.5.7/internal/lang/blocktoattr/fixup.go
@@ -0,0 +1,258 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package blocktoattr
+
+import (
+	"log"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcldec"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// FixUpBlockAttrs takes a raw HCL body and adds some additional normalization
+// functionality to allow attributes that are specified as having list or set
+// type in the schema to be written with HCL block syntax as multiple nested
+// blocks with the attribute name as the block type.
+//
+// The fixup is only applied in the absence of structural attribute types. The
+// presence of these types indicate the use of a provider which does not
+// support mapping blocks to attributes.
+//
+// This partially restores some of the block/attribute confusion from HCL 1
+// so that existing patterns that depended on that confusion can continue to
+// be used in the short term while we settle on a longer-term strategy.
+//
+// Most of the fixup work is actually done when the returned body is
+// subsequently decoded, so while FixUpBlockAttrs always succeeds, the eventual
+// decode of the body might not, if the content of the body is so ambiguous
+// that there's no safe way to map it to the schema.
+func FixUpBlockAttrs(body hcl.Body, schema *configschema.Block) hcl.Body {
+	// The schema should never be nil, but in practice it seems to be sometimes
+	// in the presence of poorly-configured test mocks, so we'll be robust
+	// by synthesizing an empty one.
+	if schema == nil {
+		schema = &configschema.Block{}
+	}
+
+	if skipFixup(schema) {
+		// we don't have any context for the resource name or type, but
+		// hopefully this could help locate the evaluation in the logs if there
+		// were a problem
+		log.Println("[DEBUG] skipping FixUpBlockAttrs")
+		return body
+	}
+
+	return &fixupBody{
+		original: body,
+		schema:   schema,
+		names:    ambiguousNames(schema),
+	}
+}
+
+// skipFixup detects any use of Attribute.NestedType, or Types which could not
+// be generate by the legacy SDK when taking SchemaConfigModeAttr into account.
+func skipFixup(schema *configschema.Block) bool {
+	for _, attr := range schema.Attributes {
+		if attr.NestedType != nil {
+			return true
+		}
+		ty := attr.Type
+
+		// Lists and sets of objects could be generated by
+		// SchemaConfigModeAttr, but some other combinations can be ruled out.
+
+		// Tuples and objects could not be generated at all.
+		if ty.IsTupleType() || ty.IsObjectType() {
+			return true
+		}
+
+		// A map of objects was not possible.
+		if ty.IsMapType() && ty.ElementType().IsObjectType() {
+			return true
+		}
+
+		// Nested collections were not really supported, but could be generated
+		// with string types (though we conservatively limit this to primitive types)
+		if ty.IsCollectionType() {
+			ety := ty.ElementType()
+			if ety.IsCollectionType() && !ety.ElementType().IsPrimitiveType() {
+				return true
+			}
+		}
+	}
+
+	for _, block := range schema.BlockTypes {
+		if skipFixup(&block.Block) {
+			return true
+		}
+	}
+
+	return false
+}
+
+type fixupBody struct {
+	original hcl.Body
+	schema   *configschema.Block
+	names    map[string]struct{}
+}
+
+type unknownBlock interface {
+	Unknown() bool
+}
+
+func (b *fixupBody) Unknown() bool {
+	if u, ok := b.original.(unknownBlock); ok {
+		return u.Unknown()
+	}
+	return false
+}
+
+// Content decodes content from the body. The given schema must be the lower-level
+// representation of the same schema that was previously passed to FixUpBlockAttrs,
+// or else the result is undefined.
+func (b *fixupBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
+	schema = b.effectiveSchema(schema)
+	content, diags := b.original.Content(schema)
+	return b.fixupContent(content), diags
+}
+
+func (b *fixupBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
+	schema = b.effectiveSchema(schema)
+	content, remain, diags := b.original.PartialContent(schema)
+	remain = &fixupBody{
+		original: remain,
+		schema:   b.schema,
+		names:    b.names,
+	}
+	return b.fixupContent(content), remain, diags
+}
+
+func (b *fixupBody) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
+	// FixUpBlockAttrs is not intended to be used in situations where we'd use
+	// JustAttributes, so we just pass this through verbatim to complete our
+	// implementation of hcl.Body.
+	return b.original.JustAttributes()
+}
+
+func (b *fixupBody) MissingItemRange() hcl.Range {
+	return b.original.MissingItemRange()
+}
+
+// effectiveSchema produces a derived *hcl.BodySchema by sniffing the body's
+// content to determine whether the author has used attribute or block syntax
+// for each of the ambigious attributes where both are permitted.
+//
+// The resulting schema will always contain all of the same names that are
+// in the given schema, but some attribute schemas may instead be replaced by
+// block header schemas.
+func (b *fixupBody) effectiveSchema(given *hcl.BodySchema) *hcl.BodySchema {
+	return effectiveSchema(given, b.original, b.names, true)
+}
+
+func (b *fixupBody) fixupContent(content *hcl.BodyContent) *hcl.BodyContent {
+	var ret hcl.BodyContent
+	ret.Attributes = make(hcl.Attributes)
+	for name, attr := range content.Attributes {
+		ret.Attributes[name] = attr
+	}
+	blockAttrVals := make(map[string][]*hcl.Block)
+	for _, block := range content.Blocks {
+		if _, exists := b.names[block.Type]; exists {
+			// If we get here then we've found a block type whose instances need
+			// to be re-interpreted as a list-of-objects attribute. We'll gather
+			// those up and fix them up below.
+			blockAttrVals[block.Type] = append(blockAttrVals[block.Type], block)
+			continue
+		}
+
+		// We need to now re-wrap our inner body so it will be subject to the
+		// same attribute-as-block fixup when recursively decoded.
+		retBlock := *block // shallow copy
+		if blockS, ok := b.schema.BlockTypes[block.Type]; ok {
+			// Would be weird if not ok, but we'll allow it for robustness; body just won't be fixed up, then
+			retBlock.Body = FixUpBlockAttrs(retBlock.Body, &blockS.Block)
+		}
+
+		ret.Blocks = append(ret.Blocks, &retBlock)
+	}
+	// No we'll install synthetic attributes for each of our fixups. We can't
+	// do this exactly because HCL's information model expects an attribute
+	// to be a single decl but we have multiple separate blocks. We'll
+	// approximate things, then, by using only our first block for the source
+	// location information. (We are guaranteed at least one by the above logic.)
+	for name, blocks := range blockAttrVals {
+		ret.Attributes[name] = &hcl.Attribute{
+			Name: name,
+			Expr: &fixupBlocksExpr{
+				blocks: blocks,
+				ety:    b.schema.Attributes[name].Type.ElementType(),
+			},
+
+			Range:     blocks[0].DefRange,
+			NameRange: blocks[0].TypeRange,
+		}
+	}
+
+	ret.MissingItemRange = b.MissingItemRange()
+	return &ret
+}
+
+type fixupBlocksExpr struct {
+	blocks hcl.Blocks
+	ety    cty.Type
+}
+
+func (e *fixupBlocksExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
+	// In order to produce a suitable value for our expression we need to
+	// now decode the whole descendent block structure under each of our block
+	// bodies.
+	//
+	// That requires us to do something rather strange: we must construct a
+	// synthetic block type schema derived from the element type of the
+	// attribute, thus inverting our usual direction of lowering a schema
+	// into an implied type. Because a type is less detailed than a schema,
+	// the result is imprecise and in particular will just consider all
+	// the attributes to be optional and let the provider eventually decide
+	// whether to return errors if they turn out to be null when required.
+	schema := SchemaForCtyElementType(e.ety) // this schema's ImpliedType will match e.ety
+	spec := schema.DecoderSpec()
+
+	vals := make([]cty.Value, len(e.blocks))
+	var diags hcl.Diagnostics
+	for i, block := range e.blocks {
+		body := FixUpBlockAttrs(block.Body, schema)
+		val, blockDiags := hcldec.Decode(body, spec, ctx)
+		diags = append(diags, blockDiags...)
+		if val == cty.NilVal {
+			val = cty.UnknownVal(e.ety)
+		}
+		vals[i] = val
+	}
+	if len(vals) == 0 {
+		return cty.ListValEmpty(e.ety), diags
+	}
+	return cty.ListVal(vals), diags
+}
+
+func (e *fixupBlocksExpr) Variables() []hcl.Traversal {
+	var ret []hcl.Traversal
+	schema := SchemaForCtyElementType(e.ety)
+	spec := schema.DecoderSpec()
+	for _, block := range e.blocks {
+		ret = append(ret, hcldec.Variables(block.Body, spec)...)
+	}
+	return ret
+}
+
+func (e *fixupBlocksExpr) Range() hcl.Range {
+	// This is not really an appropriate range for the expression but it's
+	// the best we can do from here.
+	return e.blocks[0].DefRange
+}
+
+func (e *fixupBlocksExpr) StartRange() hcl.Range {
+	return e.blocks[0].DefRange
+}
diff --git a/v1.5.7/internal/lang/blocktoattr/fixup_bench_test.go b/v1.5.7/internal/lang/blocktoattr/fixup_bench_test.go
new file mode 100644
index 0000000..45e5ef5
--- /dev/null
+++ b/v1.5.7/internal/lang/blocktoattr/fixup_bench_test.go
@@ -0,0 +1,100 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package blocktoattr
+
+import (
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcldec"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func ambiguousNestedBlock(nesting int) *configschema.NestedBlock {
+	ret := &configschema.NestedBlock{
+		Nesting: configschema.NestingList,
+		Block: configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"a": {Type: cty.String, Required: true},
+				"b": {Type: cty.String, Optional: true},
+			},
+		},
+	}
+	if nesting > 0 {
+		ret.BlockTypes = map[string]*configschema.NestedBlock{
+			"nested0": ambiguousNestedBlock(nesting - 1),
+			"nested1": ambiguousNestedBlock(nesting - 1),
+			"nested2": ambiguousNestedBlock(nesting - 1),
+			"nested3": ambiguousNestedBlock(nesting - 1),
+			"nested4": ambiguousNestedBlock(nesting - 1),
+			"nested5": ambiguousNestedBlock(nesting - 1),
+			"nested6": ambiguousNestedBlock(nesting - 1),
+			"nested7": ambiguousNestedBlock(nesting - 1),
+			"nested8": ambiguousNestedBlock(nesting - 1),
+			"nested9": ambiguousNestedBlock(nesting - 1),
+		}
+	}
+	return ret
+}
+
+func schemaWithAmbiguousNestedBlock(nesting int) *configschema.Block {
+	return &configschema.Block{
+		BlockTypes: map[string]*configschema.NestedBlock{
+			"maybe_block": ambiguousNestedBlock(nesting),
+		},
+	}
+}
+
+const configForFixupBlockAttrsBenchmark = `
+maybe_block {
+  a = "hello"
+  b = "world"
+  nested0 {
+    a = "the"
+    nested1 {
+	  a = "deeper"
+      nested2 {
+        a = "we"
+        nested3 {
+          a = "go"
+          b = "inside"
+        }
+      }
+    }
+  }
+}
+`
+
+func configBodyForFixupBlockAttrsBenchmark() hcl.Body {
+	f, diags := hclsyntax.ParseConfig([]byte(configForFixupBlockAttrsBenchmark), "", hcl.Pos{Line: 1, Column: 1})
+	if diags.HasErrors() {
+		panic("test configuration is invalid")
+	}
+	return f.Body
+}
+
+func BenchmarkFixUpBlockAttrs(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		b.StopTimer()
+		body := configBodyForFixupBlockAttrsBenchmark()
+		schema := schemaWithAmbiguousNestedBlock(5)
+		b.StartTimer()
+
+		spec := schema.DecoderSpec()
+		fixedBody := FixUpBlockAttrs(body, schema)
+		val, diags := hcldec.Decode(fixedBody, spec, nil)
+		if diags.HasErrors() {
+			b.Fatal("diagnostics during decoding", diags)
+		}
+		if !val.Type().IsObjectType() {
+			b.Fatal("result is not an object")
+		}
+		blockVal := val.GetAttr("maybe_block")
+		if !blockVal.Type().IsListType() || blockVal.LengthInt() != 1 {
+			b.Fatal("result has wrong value for 'maybe_block'")
+		}
+	}
+}
diff --git a/v1.5.7/internal/lang/blocktoattr/fixup_test.go b/v1.5.7/internal/lang/blocktoattr/fixup_test.go
new file mode 100644
index 0000000..11b3782
--- /dev/null
+++ b/v1.5.7/internal/lang/blocktoattr/fixup_test.go
@@ -0,0 +1,524 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package blocktoattr
+
+import (
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/ext/dynblock"
+	"github.com/hashicorp/hcl/v2/hcldec"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	hcljson "github.com/hashicorp/hcl/v2/json"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestFixUpBlockAttrs(t *testing.T) {
+	fooSchema := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"foo": {
+				Type: cty.List(cty.Object(map[string]cty.Type{
+					"bar": cty.String,
+				})),
+				Optional: true,
+			},
+		},
+	}
+
+	tests := map[string]struct {
+		src      string
+		json     bool
+		schema   *configschema.Block
+		want     cty.Value
+		wantErrs bool
+	}{
+		"empty": {
+			src:    ``,
+			schema: &configschema.Block{},
+			want:   cty.EmptyObjectVal,
+		},
+		"empty JSON": {
+			src:    `{}`,
+			json:   true,
+			schema: &configschema.Block{},
+			want:   cty.EmptyObjectVal,
+		},
+		"unset": {
+			src:    ``,
+			schema: fooSchema,
+			want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(fooSchema.Attributes["foo"].Type),
+			}),
+		},
+		"unset JSON": {
+			src:    `{}`,
+			json:   true,
+			schema: fooSchema,
+			want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(fooSchema.Attributes["foo"].Type),
+			}),
+		},
+		"no fixup required, with one value": {
+			src: `
+foo = [
+  {
+    bar = "baz"
+  },
+]
+`,
+			schema: fooSchema,
+			want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("baz"),
+					}),
+				}),
+			}),
+		},
+		"no fixup required, with two values": {
+			src: `
+foo = [
+  {
+    bar = "baz"
+  },
+  {
+    bar = "boop"
+  },
+]
+`,
+			schema: fooSchema,
+			want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("baz"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("boop"),
+					}),
+				}),
+			}),
+		},
+		"no fixup required, with values, JSON": {
+			src:    `{"foo": [{"bar": "baz"}]}`,
+			json:   true,
+			schema: fooSchema,
+			want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("baz"),
+					}),
+				}),
+			}),
+		},
+		"no fixup required, empty": {
+			src: `
+foo = []
+`,
+			schema: fooSchema,
+			want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListValEmpty(fooSchema.Attributes["foo"].Type.ElementType()),
+			}),
+		},
+		"no fixup required, empty, JSON": {
+			src:    `{"foo":[]}`,
+			json:   true,
+			schema: fooSchema,
+			want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListValEmpty(fooSchema.Attributes["foo"].Type.ElementType()),
+			}),
+		},
+		"fixup one block": {
+			src: `
+foo {
+  bar = "baz"
+}
+`,
+			schema: fooSchema,
+			want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("baz"),
+					}),
+				}),
+			}),
+		},
+		"fixup one block omitting attribute": {
+			src: `
+foo {}
+`,
+			schema: fooSchema,
+			want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+		},
+		"fixup two blocks": {
+			src: `
+foo {
+  bar = baz
+}
+foo {
+  bar = "boop"
+}
+`,
+			schema: fooSchema,
+			want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("baz value"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("boop"),
+					}),
+				}),
+			}),
+		},
+		"interaction with dynamic block generation": {
+			src: `
+dynamic "foo" {
+  for_each = ["baz", beep]
+  content {
+    bar = foo.value
+  }
+}
+`,
+			schema: fooSchema,
+			want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("baz"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("beep value"),
+					}),
+				}),
+			}),
+		},
+		"dynamic block with empty iterator": {
+			src: `
+dynamic "foo" {
+  for_each = []
+  content {
+    bar = foo.value
+  }
+}
+`,
+			schema: fooSchema,
+			want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(fooSchema.Attributes["foo"].Type),
+			}),
+		},
+		"both attribute and block syntax": {
+			src: `
+foo = []
+foo {
+  bar = "baz"
+}
+`,
+			schema:   fooSchema,
+			wantErrs: true, // Unsupported block type (user must be consistent about whether they consider foo to be a block type or an attribute)
+			want: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("baz"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("boop"),
+					}),
+				}),
+			}),
+		},
+		"fixup inside block": {
+			src: `
+container {
+  foo {
+    bar = "baz"
+  }
+  foo {
+    bar = "boop"
+  }
+}
+container {
+  foo {
+    bar = beep
+  }
+}
+`,
+			schema: &configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"container": {
+						Nesting: configschema.NestingList,
+						Block:   *fooSchema,
+					},
+				},
+			},
+			want: cty.ObjectVal(map[string]cty.Value{
+				"container": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.ListVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"bar": cty.StringVal("baz"),
+							}),
+							cty.ObjectVal(map[string]cty.Value{
+								"bar": cty.StringVal("boop"),
+							}),
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.ListVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"bar": cty.StringVal("beep value"),
+							}),
+						}),
+					}),
+				}),
+			}),
+		},
+		"fixup inside attribute-as-block": {
+			src: `
+container {
+  foo {
+    bar = "baz"
+  }
+  foo {
+    bar = "boop"
+  }
+}
+container {
+  foo {
+    bar = beep
+  }
+}
+`,
+			schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"container": {
+						Type: cty.List(cty.Object(map[string]cty.Type{
+							"foo": cty.List(cty.Object(map[string]cty.Type{
+								"bar": cty.String,
+							})),
+						})),
+						Optional: true,
+					},
+				},
+			},
+			want: cty.ObjectVal(map[string]cty.Value{
+				"container": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.ListVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"bar": cty.StringVal("baz"),
+							}),
+							cty.ObjectVal(map[string]cty.Value{
+								"bar": cty.StringVal("boop"),
+							}),
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.ListVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"bar": cty.StringVal("beep value"),
+							}),
+						}),
+					}),
+				}),
+			}),
+		},
+		"nested fixup with dynamic block generation": {
+			src: `
+container {
+  dynamic "foo" {
+    for_each = ["baz", beep]
+    content {
+      bar = foo.value
+    }
+  }
+}
+`,
+			schema: &configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"container": {
+						Nesting: configschema.NestingList,
+						Block:   *fooSchema,
+					},
+				},
+			},
+			want: cty.ObjectVal(map[string]cty.Value{
+				"container": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.ListVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"bar": cty.StringVal("baz"),
+							}),
+							cty.ObjectVal(map[string]cty.Value{
+								"bar": cty.StringVal("beep value"),
+							}),
+						}),
+					}),
+				}),
+			}),
+		},
+
+		"missing nested block items": {
+			src: `
+container {
+  foo {
+    bar = "one"
+  }
+}
+`,
+			schema: &configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"container": {
+						Nesting:  configschema.NestingList,
+						MinItems: 2,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"foo": {
+									Type: cty.List(cty.Object(map[string]cty.Type{
+										"bar": cty.String,
+									})),
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			want: cty.ObjectVal(map[string]cty.Value{
+				"container": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.ListVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"bar": cty.StringVal("baz"),
+							}),
+						}),
+					}),
+				}),
+			}),
+			wantErrs: true,
+		},
+		"no fixup allowed with NestedType": {
+			src: `
+ container {
+   foo = "one"
+ }
+ `,
+			schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"container": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"foo": {
+									Type: cty.String,
+								},
+							},
+						},
+					},
+				},
+			},
+			want: cty.ObjectVal(map[string]cty.Value{
+				"container": cty.NullVal(cty.List(
+					cty.Object(map[string]cty.Type{
+						"foo": cty.String,
+					}),
+				)),
+			}),
+			wantErrs: true,
+		},
+		"no fixup allowed new types": {
+			src: `
+ container {
+   foo = "one"
+ }
+ `,
+			schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					// This could be a ConfigModeAttr fixup
+					"container": {
+						Type: cty.List(cty.Object(map[string]cty.Type{
+							"foo": cty.String,
+						})),
+					},
+					// But the presence of this type means it must have been
+					// declared by a new SDK
+					"new_type": {
+						Type: cty.Object(map[string]cty.Type{
+							"boo": cty.String,
+						}),
+					},
+				},
+			},
+			want: cty.ObjectVal(map[string]cty.Value{
+				"container": cty.NullVal(cty.List(
+					cty.Object(map[string]cty.Type{
+						"foo": cty.String,
+					}),
+				)),
+			}),
+			wantErrs: true,
+		},
+	}
+
+	ctx := &hcl.EvalContext{
+		Variables: map[string]cty.Value{
+			"bar":  cty.StringVal("bar value"),
+			"baz":  cty.StringVal("baz value"),
+			"beep": cty.StringVal("beep value"),
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			var f *hcl.File
+			var diags hcl.Diagnostics
+			if test.json {
+				f, diags = hcljson.Parse([]byte(test.src), "test.tf.json")
+			} else {
+				f, diags = hclsyntax.ParseConfig([]byte(test.src), "test.tf", hcl.Pos{Line: 1, Column: 1})
+			}
+			if diags.HasErrors() {
+				for _, diag := range diags {
+					t.Errorf("unexpected diagnostic: %s", diag)
+				}
+				t.FailNow()
+			}
+
+			// We'll expand dynamic blocks in the body first, to mimic how
+			// we process this fixup when using the main "lang" package API.
+			spec := test.schema.DecoderSpec()
+			body := dynblock.Expand(f.Body, ctx)
+
+			body = FixUpBlockAttrs(body, test.schema)
+			got, diags := hcldec.Decode(body, spec, ctx)
+
+			if test.wantErrs {
+				if !diags.HasErrors() {
+					t.Errorf("succeeded, but want error\ngot: %#v", got)
+				}
+
+				// check that our wrapped body returns the correct context by
+				// verifying the Subject is valid.
+				for _, d := range diags {
+					if d.Subject.Filename == "" {
+						t.Errorf("empty diagnostic subject: %#v", d.Subject)
+					}
+				}
+				return
+			}
+
+			if !test.want.RawEquals(got) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.want)
+			}
+			for _, diag := range diags {
+				t.Errorf("unexpected diagnostic: %s", diag)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/lang/blocktoattr/schema.go b/v1.5.7/internal/lang/blocktoattr/schema.go
new file mode 100644
index 0000000..67caa90
--- /dev/null
+++ b/v1.5.7/internal/lang/blocktoattr/schema.go
@@ -0,0 +1,149 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package blocktoattr
+
+import (
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func ambiguousNames(schema *configschema.Block) map[string]struct{} {
+	if schema == nil {
+		return nil
+	}
+	ambiguousNames := make(map[string]struct{})
+	for name, attrS := range schema.Attributes {
+		aty := attrS.Type
+		if (aty.IsListType() || aty.IsSetType()) && aty.ElementType().IsObjectType() {
+			ambiguousNames[name] = struct{}{}
+		}
+	}
+	return ambiguousNames
+}
+
+func effectiveSchema(given *hcl.BodySchema, body hcl.Body, ambiguousNames map[string]struct{}, dynamicExpanded bool) *hcl.BodySchema {
+	ret := &hcl.BodySchema{}
+
+	appearsAsBlock := make(map[string]struct{})
+	{
+		// We'll construct some throwaway schemas here just to probe for
+		// whether each of our ambiguous names seems to be being used as
+		// an attribute or a block. We need to check both because in JSON
+		// syntax we rely on the schema to decide between attribute or block
+		// interpretation and so JSON will always answer yes to both of
+		// these questions and we want to prefer the attribute interpretation
+		// in that case.
+		var probeSchema hcl.BodySchema
+
+		for name := range ambiguousNames {
+			probeSchema = hcl.BodySchema{
+				Attributes: []hcl.AttributeSchema{
+					{
+						Name: name,
+					},
+				},
+			}
+			content, _, _ := body.PartialContent(&probeSchema)
+			if _, exists := content.Attributes[name]; exists {
+				// Can decode as an attribute, so we'll go with that.
+				continue
+			}
+			probeSchema = hcl.BodySchema{
+				Blocks: []hcl.BlockHeaderSchema{
+					{
+						Type: name,
+					},
+				},
+			}
+			content, _, _ = body.PartialContent(&probeSchema)
+			if len(content.Blocks) > 0 || dynamicExpanded {
+				// A dynamic block with an empty iterator returns nothing.
+				// If there's no attribute and we have either a block or a
+				// dynamic expansion, we need to rewrite this one as a
+				// block for a successful result.
+				appearsAsBlock[name] = struct{}{}
+			}
+		}
+		if !dynamicExpanded {
+			// If we're deciding for a context where dynamic blocks haven't
+			// been expanded yet then we need to probe for those too.
+			probeSchema = hcl.BodySchema{
+				Blocks: []hcl.BlockHeaderSchema{
+					{
+						Type:       "dynamic",
+						LabelNames: []string{"type"},
+					},
+				},
+			}
+			content, _, _ := body.PartialContent(&probeSchema)
+			for _, block := range content.Blocks {
+				if _, exists := ambiguousNames[block.Labels[0]]; exists {
+					appearsAsBlock[block.Labels[0]] = struct{}{}
+				}
+			}
+		}
+	}
+
+	for _, attrS := range given.Attributes {
+		if _, exists := appearsAsBlock[attrS.Name]; exists {
+			ret.Blocks = append(ret.Blocks, hcl.BlockHeaderSchema{
+				Type: attrS.Name,
+			})
+		} else {
+			ret.Attributes = append(ret.Attributes, attrS)
+		}
+	}
+
+	// Anything that is specified as a block type in the input schema remains
+	// that way by just passing through verbatim.
+	ret.Blocks = append(ret.Blocks, given.Blocks...)
+
+	return ret
+}
+
+// SchemaForCtyElementType converts a cty object type into an
+// approximately-equivalent configschema.Block representing the element of
+// a list or set. If the given type is not an object type then this
+// function will panic.
+func SchemaForCtyElementType(ty cty.Type) *configschema.Block {
+	atys := ty.AttributeTypes()
+	ret := &configschema.Block{
+		Attributes: make(map[string]*configschema.Attribute, len(atys)),
+	}
+	for name, aty := range atys {
+		ret.Attributes[name] = &configschema.Attribute{
+			Type:     aty,
+			Optional: true,
+		}
+	}
+	return ret
+}
+
+// SchemaForCtyContainerType converts a cty list-of-object or set-of-object type
+// into an approximately-equivalent configschema.NestedBlock. If the given type
+// is not of the expected kind then this function will panic.
+func SchemaForCtyContainerType(ty cty.Type) *configschema.NestedBlock {
+	var nesting configschema.NestingMode
+	switch {
+	case ty.IsListType():
+		nesting = configschema.NestingList
+	case ty.IsSetType():
+		nesting = configschema.NestingSet
+	default:
+		panic("unsuitable type")
+	}
+	nested := SchemaForCtyElementType(ty.ElementType())
+	return &configschema.NestedBlock{
+		Nesting: nesting,
+		Block:   *nested,
+	}
+}
+
+// TypeCanBeBlocks returns true if the given type is a list-of-object or
+// set-of-object type, and would thus be subject to the blocktoattr fixup
+// if used as an attribute type.
+func TypeCanBeBlocks(ty cty.Type) bool {
+	return (ty.IsListType() || ty.IsSetType()) && ty.ElementType().IsObjectType()
+}
diff --git a/v1.5.7/internal/lang/blocktoattr/variables.go b/v1.5.7/internal/lang/blocktoattr/variables.go
new file mode 100644
index 0000000..cde3138
--- /dev/null
+++ b/v1.5.7/internal/lang/blocktoattr/variables.go
@@ -0,0 +1,48 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package blocktoattr
+
+import (
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/ext/dynblock"
+	"github.com/hashicorp/hcl/v2/hcldec"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+// ExpandedVariables finds all of the global variables referenced in the
+// given body with the given schema while taking into account the possibilities
+// both of "dynamic" blocks being expanded and the possibility of certain
+// attributes being written instead as nested blocks as allowed by the
+// FixUpBlockAttrs function.
+//
+// This function exists to allow variables to be analyzed prior to dynamic
+// block expansion while also dealing with the fact that dynamic block expansion
+// might in turn produce nested blocks that are subject to FixUpBlockAttrs.
+//
+// This is intended as a drop-in replacement for dynblock.VariablesHCLDec,
+// which is itself a drop-in replacement for hcldec.Variables.
+func ExpandedVariables(body hcl.Body, schema *configschema.Block) []hcl.Traversal {
+	rootNode := dynblock.WalkVariables(body)
+	return walkVariables(rootNode, body, schema)
+}
+
+func walkVariables(node dynblock.WalkVariablesNode, body hcl.Body, schema *configschema.Block) []hcl.Traversal {
+	givenRawSchema := hcldec.ImpliedSchema(schema.DecoderSpec())
+	ambiguousNames := ambiguousNames(schema)
+	effectiveRawSchema := effectiveSchema(givenRawSchema, body, ambiguousNames, false)
+	vars, children := node.Visit(effectiveRawSchema)
+
+	for _, child := range children {
+		if blockS, exists := schema.BlockTypes[child.BlockTypeName]; exists {
+			vars = append(vars, walkVariables(child.Node, child.Body(), &blockS.Block)...)
+		} else if attrS, exists := schema.Attributes[child.BlockTypeName]; exists && attrS.Type.IsCollectionType() && attrS.Type.ElementType().IsObjectType() {
+			// ☝️Check for collection type before element type, because if this is a mis-placed reference,
+			// a panic here will prevent other useful diags from being elevated to show the user what to fix
+			synthSchema := SchemaForCtyElementType(attrS.Type.ElementType())
+			vars = append(vars, walkVariables(child.Node, child.Body(), synthSchema)...)
+		}
+	}
+
+	return vars
+}
diff --git a/v1.5.7/internal/lang/blocktoattr/variables_test.go b/v1.5.7/internal/lang/blocktoattr/variables_test.go
new file mode 100644
index 0000000..a8fed79
--- /dev/null
+++ b/v1.5.7/internal/lang/blocktoattr/variables_test.go
@@ -0,0 +1,203 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package blocktoattr
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	hcljson "github.com/hashicorp/hcl/v2/json"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestExpandedVariables(t *testing.T) {
+	fooSchema := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"foo": {
+				Type: cty.List(cty.Object(map[string]cty.Type{
+					"bar": cty.String,
+				})),
+				Optional: true,
+			},
+			"bar": {
+				Type:     cty.Map(cty.String),
+				Optional: true,
+			},
+		},
+	}
+
+	tests := map[string]struct {
+		src    string
+		json   bool
+		schema *configschema.Block
+		want   []hcl.Traversal
+	}{
+		"empty": {
+			src:    ``,
+			schema: &configschema.Block{},
+			want:   nil,
+		},
+		"attribute syntax": {
+			src: `
+foo = [
+  {
+    bar = baz
+  },
+]
+`,
+			schema: fooSchema,
+			want: []hcl.Traversal{
+				{
+					hcl.TraverseRoot{
+						Name: "baz",
+						SrcRange: hcl.Range{
+							Filename: "test.tf",
+							Start:    hcl.Pos{Line: 4, Column: 11, Byte: 23},
+							End:      hcl.Pos{Line: 4, Column: 14, Byte: 26},
+						},
+					},
+				},
+			},
+		},
+		"block syntax": {
+			src: `
+foo {
+  bar = baz
+}
+`,
+			schema: fooSchema,
+			want: []hcl.Traversal{
+				{
+					hcl.TraverseRoot{
+						Name: "baz",
+						SrcRange: hcl.Range{
+							Filename: "test.tf",
+							Start:    hcl.Pos{Line: 3, Column: 9, Byte: 15},
+							End:      hcl.Pos{Line: 3, Column: 12, Byte: 18},
+						},
+					},
+				},
+			},
+		},
+		"block syntax with nested blocks": {
+			src: `
+foo {
+  bar {
+    boop = baz
+  }
+}
+`,
+			schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type: cty.List(cty.Object(map[string]cty.Type{
+							"bar": cty.List(cty.Object(map[string]cty.Type{
+								"boop": cty.String,
+							})),
+						})),
+						Optional: true,
+					},
+				},
+			},
+			want: []hcl.Traversal{
+				{
+					hcl.TraverseRoot{
+						Name: "baz",
+						SrcRange: hcl.Range{
+							Filename: "test.tf",
+							Start:    hcl.Pos{Line: 4, Column: 12, Byte: 26},
+							End:      hcl.Pos{Line: 4, Column: 15, Byte: 29},
+						},
+					},
+				},
+			},
+		},
+		"dynamic block syntax": {
+			src: `
+dynamic "foo" {
+  for_each = beep
+  content {
+    bar = baz
+  }
+}
+`,
+			schema: fooSchema,
+			want: []hcl.Traversal{
+				{
+					hcl.TraverseRoot{
+						Name: "beep",
+						SrcRange: hcl.Range{
+							Filename: "test.tf",
+							Start:    hcl.Pos{Line: 3, Column: 14, Byte: 30},
+							End:      hcl.Pos{Line: 3, Column: 18, Byte: 34},
+						},
+					},
+				},
+				{
+					hcl.TraverseRoot{
+						Name: "baz",
+						SrcRange: hcl.Range{
+							Filename: "test.tf",
+							Start:    hcl.Pos{Line: 5, Column: 11, Byte: 57},
+							End:      hcl.Pos{Line: 5, Column: 14, Byte: 60},
+						},
+					},
+				},
+			},
+		},
+		"misplaced dynamic block": {
+			src: `
+dynamic "bar" {
+  for_each = beep
+  content {
+    key = val
+  }
+}
+`,
+			schema: fooSchema,
+			want: []hcl.Traversal{
+				{
+					hcl.TraverseRoot{
+						Name: "beep",
+						SrcRange: hcl.Range{
+							Filename: "test.tf",
+							Start:    hcl.Pos{Line: 3, Column: 14, Byte: 30},
+							End:      hcl.Pos{Line: 3, Column: 18, Byte: 34},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			var f *hcl.File
+			var diags hcl.Diagnostics
+			if test.json {
+				f, diags = hcljson.Parse([]byte(test.src), "test.tf.json")
+			} else {
+				f, diags = hclsyntax.ParseConfig([]byte(test.src), "test.tf", hcl.Pos{Line: 1, Column: 1})
+			}
+			if diags.HasErrors() {
+				for _, diag := range diags {
+					t.Errorf("unexpected diagnostic: %s", diag)
+				}
+				t.FailNow()
+			}
+
+			got := ExpandedVariables(f.Body, test.schema)
+
+			co := cmpopts.IgnoreUnexported(hcl.TraverseRoot{})
+			if !cmp.Equal(got, test.want, co) {
+				t.Errorf("wrong result\n%s", cmp.Diff(test.want, got, co))
+			}
+		})
+	}
+
+}
diff --git a/v1.5.7/internal/lang/data.go b/v1.5.7/internal/lang/data.go
new file mode 100644
index 0000000..2eb4f02
--- /dev/null
+++ b/v1.5.7/internal/lang/data.go
@@ -0,0 +1,36 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package lang
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Data is an interface whose implementations can provide cty.Value
+// representations of objects identified by referenceable addresses from
+// the addrs package.
+//
+// This interface will grow each time a new type of reference is added, and so
+// implementations outside of the Terraform codebases are not advised.
+//
+// Each method returns a suitable value and optionally some diagnostics. If the
+// returned diagnostics contains errors then the type of the returned value is
+// used to construct an unknown value of the same type which is then used in
+// place of the requested object so that type checking can still proceed. In
+// cases where it's not possible to even determine a suitable result type,
+// cty.DynamicVal is returned along with errors describing the problem.
+type Data interface {
+	StaticValidateReferences(refs []*addrs.Reference, self addrs.Referenceable, source addrs.Referenceable) tfdiags.Diagnostics
+
+	GetCountAttr(addrs.CountAttr, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
+	GetForEachAttr(addrs.ForEachAttr, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
+	GetResource(addrs.Resource, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
+	GetLocalValue(addrs.LocalValue, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
+	GetModule(addrs.ModuleCall, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
+	GetPathAttr(addrs.PathAttr, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
+	GetTerraformAttr(addrs.TerraformAttr, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
+	GetInputVariable(addrs.InputVariable, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
+}
diff --git a/v1.5.7/internal/lang/data_test.go b/v1.5.7/internal/lang/data_test.go
new file mode 100644
index 0000000..acaae54
--- /dev/null
+++ b/v1.5.7/internal/lang/data_test.go
@@ -0,0 +1,65 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package lang
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+type dataForTests struct {
+	CountAttrs     map[string]cty.Value
+	ForEachAttrs   map[string]cty.Value
+	Resources      map[string]cty.Value
+	LocalValues    map[string]cty.Value
+	Modules        map[string]cty.Value
+	PathAttrs      map[string]cty.Value
+	TerraformAttrs map[string]cty.Value
+	InputVariables map[string]cty.Value
+}
+
+var _ Data = &dataForTests{}
+
+func (d *dataForTests) StaticValidateReferences(refs []*addrs.Reference, self addrs.Referenceable, source addrs.Referenceable) tfdiags.Diagnostics {
+	return nil // does nothing in this stub implementation
+}
+
+func (d *dataForTests) GetCountAttr(addr addrs.CountAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	return d.CountAttrs[addr.Name], nil
+}
+
+func (d *dataForTests) GetForEachAttr(addr addrs.ForEachAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	return d.ForEachAttrs[addr.Name], nil
+}
+
+func (d *dataForTests) GetResource(addr addrs.Resource, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	return d.Resources[addr.String()], nil
+}
+
+func (d *dataForTests) GetInputVariable(addr addrs.InputVariable, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	return d.InputVariables[addr.Name], nil
+}
+
+func (d *dataForTests) GetLocalValue(addr addrs.LocalValue, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	return d.LocalValues[addr.Name], nil
+}
+
+func (d *dataForTests) GetModule(addr addrs.ModuleCall, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	return d.Modules[addr.String()], nil
+}
+
+func (d *dataForTests) GetModuleInstanceOutput(addr addrs.ModuleCallInstanceOutput, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	// This will panic if the module object does not have the requested attribute
+	obj := d.Modules[addr.Call.String()]
+	return obj.GetAttr(addr.Name), nil
+}
+
+func (d *dataForTests) GetPathAttr(addr addrs.PathAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	return d.PathAttrs[addr.Name], nil
+}
+
+func (d *dataForTests) GetTerraformAttr(addr addrs.TerraformAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	return d.TerraformAttrs[addr.Name], nil
+}
diff --git a/v1.5.7/internal/lang/doc.go b/v1.5.7/internal/lang/doc.go
new file mode 100644
index 0000000..eea4495
--- /dev/null
+++ b/v1.5.7/internal/lang/doc.go
@@ -0,0 +1,8 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package lang deals with the runtime aspects of Terraform's configuration
+// language, with concerns such as expression evaluation. It is closely related
+// to sibling package "configs", which is responsible for configuration
+// parsing and static validation.
+package lang
diff --git a/v1.5.7/internal/lang/eval.go b/v1.5.7/internal/lang/eval.go
new file mode 100644
index 0000000..6928a49
--- /dev/null
+++ b/v1.5.7/internal/lang/eval.go
@@ -0,0 +1,456 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package lang
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/ext/dynblock"
+	"github.com/hashicorp/hcl/v2/hcldec"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/lang/blocktoattr"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/convert"
+)
+
+// ExpandBlock expands any "dynamic" blocks present in the given body. The
+// result is a body with those blocks expanded, ready to be evaluated with
+// EvalBlock.
+//
+// If the returned diagnostics contains errors then the result may be
+// incomplete or invalid.
+func (s *Scope) ExpandBlock(body hcl.Body, schema *configschema.Block) (hcl.Body, tfdiags.Diagnostics) {
+	spec := schema.DecoderSpec()
+
+	traversals := dynblock.ExpandVariablesHCLDec(body, spec)
+	refs, diags := References(traversals)
+
+	ctx, ctxDiags := s.EvalContext(refs)
+	diags = diags.Append(ctxDiags)
+
+	return dynblock.Expand(body, ctx), diags
+}
+
+// EvalBlock evaluates the given body using the given block schema and returns
+// a cty object value representing its contents. The type of the result conforms
+// to the implied type of the given schema.
+//
+// This function does not automatically expand "dynamic" blocks within the
+// body. If that is desired, first call the ExpandBlock method to obtain
+// an expanded body to pass to this method.
+//
+// If the returned diagnostics contains errors then the result may be
+// incomplete or invalid.
+func (s *Scope) EvalBlock(body hcl.Body, schema *configschema.Block) (cty.Value, tfdiags.Diagnostics) {
+	spec := schema.DecoderSpec()
+
+	refs, diags := ReferencesInBlock(body, schema)
+
+	ctx, ctxDiags := s.EvalContext(refs)
+	diags = diags.Append(ctxDiags)
+	if diags.HasErrors() {
+		// We'll stop early if we found problems in the references, because
+		// it's likely evaluation will produce redundant copies of the same errors.
+		return cty.UnknownVal(schema.ImpliedType()), diags
+	}
+
+	// HACK: In order to remain compatible with some assumptions made in
+	// Terraform v0.11 and earlier about the approximate equivalence of
+	// attribute vs. block syntax, we do a just-in-time fixup here to allow
+	// any attribute in the schema that has a list-of-objects or set-of-objects
+	// kind to potentially be populated instead by one or more nested blocks
+	// whose type is the attribute name.
+	body = blocktoattr.FixUpBlockAttrs(body, schema)
+
+	val, evalDiags := hcldec.Decode(body, spec, ctx)
+	diags = diags.Append(evalDiags)
+
+	return val, diags
+}
+
+// EvalSelfBlock evaluates the given body only within the scope of the provided
+// object and instance key data. References to the object must use self, and the
+// key data will only contain count.index or each.key. The static values for
+// terraform and path will also be available in this context.
+func (s *Scope) EvalSelfBlock(body hcl.Body, self cty.Value, schema *configschema.Block, keyData instances.RepetitionData) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	spec := schema.DecoderSpec()
+
+	vals := make(map[string]cty.Value)
+	vals["self"] = self
+
+	if !keyData.CountIndex.IsNull() {
+		vals["count"] = cty.ObjectVal(map[string]cty.Value{
+			"index": keyData.CountIndex,
+		})
+	}
+	if !keyData.EachKey.IsNull() {
+		vals["each"] = cty.ObjectVal(map[string]cty.Value{
+			"key": keyData.EachKey,
+		})
+	}
+
+	refs, refDiags := References(hcldec.Variables(body, spec))
+	diags = diags.Append(refDiags)
+
+	terraformAttrs := map[string]cty.Value{}
+	pathAttrs := map[string]cty.Value{}
+
+	// We could always load the static values for Path and Terraform values,
+	// but we want to parse the references so that we can get source ranges for
+	// user diagnostics.
+	for _, ref := range refs {
+		// we already loaded the self value
+		if ref.Subject == addrs.Self {
+			continue
+		}
+
+		switch subj := ref.Subject.(type) {
+		case addrs.PathAttr:
+			val, valDiags := normalizeRefValue(s.Data.GetPathAttr(subj, ref.SourceRange))
+			diags = diags.Append(valDiags)
+			pathAttrs[subj.Name] = val
+
+		case addrs.TerraformAttr:
+			val, valDiags := normalizeRefValue(s.Data.GetTerraformAttr(subj, ref.SourceRange))
+			diags = diags.Append(valDiags)
+			terraformAttrs[subj.Name] = val
+
+		case addrs.CountAttr, addrs.ForEachAttr:
+			// each and count have already been handled.
+
+		default:
+			// This should have been caught in validation, but point the user
+			// to the correct location in case something slipped through.
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  `Invalid reference`,
+				Detail:   fmt.Sprintf("The reference to %q is not valid in this context", ref.Subject),
+				Subject:  ref.SourceRange.ToHCL().Ptr(),
+			})
+		}
+	}
+
+	vals["path"] = cty.ObjectVal(pathAttrs)
+	vals["terraform"] = cty.ObjectVal(terraformAttrs)
+
+	ctx := &hcl.EvalContext{
+		Variables: vals,
+		Functions: s.Functions(),
+	}
+
+	val, decDiags := hcldec.Decode(body, schema.DecoderSpec(), ctx)
+	diags = diags.Append(decDiags)
+	return val, diags
+}
+
+// EvalExpr evaluates a single expression in the receiving context and returns
+// the resulting value. The value will be converted to the given type before
+// it is returned if possible, or else an error diagnostic will be produced
+// describing the conversion error.
+//
+// Pass an expected type of cty.DynamicPseudoType to skip automatic conversion
+// and just obtain the returned value directly.
+//
+// If the returned diagnostics contains errors then the result may be
+// incomplete, but will always be of the requested type.
+func (s *Scope) EvalExpr(expr hcl.Expression, wantType cty.Type) (cty.Value, tfdiags.Diagnostics) {
+	refs, diags := ReferencesInExpr(expr)
+
+	ctx, ctxDiags := s.EvalContext(refs)
+	diags = diags.Append(ctxDiags)
+	if diags.HasErrors() {
+		// We'll stop early if we found problems in the references, because
+		// it's likely evaluation will produce redundant copies of the same errors.
+		return cty.UnknownVal(wantType), diags
+	}
+
+	val, evalDiags := expr.Value(ctx)
+	diags = diags.Append(evalDiags)
+
+	if wantType != cty.DynamicPseudoType {
+		var convErr error
+		val, convErr = convert.Convert(val, wantType)
+		if convErr != nil {
+			val = cty.UnknownVal(wantType)
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity:    hcl.DiagError,
+				Summary:     "Incorrect value type",
+				Detail:      fmt.Sprintf("Invalid expression value: %s.", tfdiags.FormatError(convErr)),
+				Subject:     expr.Range().Ptr(),
+				Expression:  expr,
+				EvalContext: ctx,
+			})
+		}
+	}
+
+	return val, diags
+}
+
+// EvalReference evaluates the given reference in the receiving scope and
+// returns the resulting value. The value will be converted to the given type before
+// it is returned if possible, or else an error diagnostic will be produced
+// describing the conversion error.
+//
+// Pass an expected type of cty.DynamicPseudoType to skip automatic conversion
+// and just obtain the returned value directly.
+//
+// If the returned diagnostics contains errors then the result may be
+// incomplete, but will always be of the requested type.
+func (s *Scope) EvalReference(ref *addrs.Reference, wantType cty.Type) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// We cheat a bit here and just build an EvalContext for our requested
+	// reference with the "self" address overridden, and then pull the "self"
+	// result out of it to return.
+	ctx, ctxDiags := s.evalContext([]*addrs.Reference{ref}, ref.Subject)
+	diags = diags.Append(ctxDiags)
+	val := ctx.Variables["self"]
+	if val == cty.NilVal {
+		val = cty.DynamicVal
+	}
+
+	var convErr error
+	val, convErr = convert.Convert(val, wantType)
+	if convErr != nil {
+		val = cty.UnknownVal(wantType)
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Incorrect value type",
+			Detail:   fmt.Sprintf("Invalid expression value: %s.", tfdiags.FormatError(convErr)),
+			Subject:  ref.SourceRange.ToHCL().Ptr(),
+		})
+	}
+
+	return val, diags
+}
+
+// EvalContext constructs a HCL expression evaluation context whose variable
+// scope contains sufficient values to satisfy the given set of references.
+//
+// Most callers should prefer to use the evaluation helper methods that
+// this type offers, but this is here for less common situations where the
+// caller will handle the evaluation calls itself.
+func (s *Scope) EvalContext(refs []*addrs.Reference) (*hcl.EvalContext, tfdiags.Diagnostics) {
+	return s.evalContext(refs, s.SelfAddr)
+}
+
+func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceable) (*hcl.EvalContext, tfdiags.Diagnostics) {
+	if s == nil {
+		panic("attempt to construct EvalContext for nil Scope")
+	}
+
+	var diags tfdiags.Diagnostics
+	vals := make(map[string]cty.Value)
+	funcs := s.Functions()
+	ctx := &hcl.EvalContext{
+		Variables: vals,
+		Functions: funcs,
+	}
+
+	if len(refs) == 0 {
+		// Easy path for common case where there are no references at all.
+		return ctx, diags
+	}
+
+	// First we'll do static validation of the references. This catches things
+	// early that might otherwise not get caught due to unknown values being
+	// present in the scope during planning.
+	staticDiags := s.Data.StaticValidateReferences(refs, selfAddr, s.SourceAddr)
+	diags = diags.Append(staticDiags)
+	if staticDiags.HasErrors() {
+		return ctx, diags
+	}
+
+	// The reference set we are given has not been de-duped, and so there can
+	// be redundant requests in it for two reasons:
+	//  - The same item is referenced multiple times
+	//  - Both an item and that item's container are separately referenced.
+	// We will still visit every reference here and ask our data source for
+	// it, since that allows us to gather a full set of any errors and
+	// warnings, but once we've gathered all the data we'll then skip anything
+	// that's redundant in the process of populating our values map.
+	dataResources := map[string]map[string]cty.Value{}
+	managedResources := map[string]map[string]cty.Value{}
+	wholeModules := map[string]cty.Value{}
+	inputVariables := map[string]cty.Value{}
+	localValues := map[string]cty.Value{}
+	pathAttrs := map[string]cty.Value{}
+	terraformAttrs := map[string]cty.Value{}
+	countAttrs := map[string]cty.Value{}
+	forEachAttrs := map[string]cty.Value{}
+	var self cty.Value
+
+	for _, ref := range refs {
+		rng := ref.SourceRange
+
+		rawSubj := ref.Subject
+		if rawSubj == addrs.Self {
+			if selfAddr == nil {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  `Invalid "self" reference`,
+					// This detail message mentions some current practice that
+					// this codepath doesn't really "know about". If the "self"
+					// object starts being supported in more contexts later then
+					// we'll need to adjust this message.
+					Detail:  `The "self" object is not available in this context. This object can be used only in resource provisioner, connection, and postcondition blocks.`,
+					Subject: ref.SourceRange.ToHCL().Ptr(),
+				})
+				continue
+			}
+
+			if selfAddr == addrs.Self {
+				// Programming error: the self address cannot alias itself.
+				panic("scope SelfAddr attempting to alias itself")
+			}
+
+			// self can only be used within a resource instance
+			subj := selfAddr.(addrs.ResourceInstance)
+
+			val, valDiags := normalizeRefValue(s.Data.GetResource(subj.ContainingResource(), rng))
+
+			diags = diags.Append(valDiags)
+
+			// Self is an exception in that it must always resolve to a
+			// particular instance. We will still insert the full resource into
+			// the context below.
+			var hclDiags hcl.Diagnostics
+			// We should always have a valid self index by this point, but in
+			// the case of an error, self may end up as a cty.DynamicValue.
+			switch k := subj.Key.(type) {
+			case addrs.IntKey:
+				self, hclDiags = hcl.Index(val, cty.NumberIntVal(int64(k)), ref.SourceRange.ToHCL().Ptr())
+				diags = diags.Append(hclDiags)
+			case addrs.StringKey:
+				self, hclDiags = hcl.Index(val, cty.StringVal(string(k)), ref.SourceRange.ToHCL().Ptr())
+				diags = diags.Append(hclDiags)
+			default:
+				self = val
+			}
+			continue
+		}
+
+		// This type switch must cover all of the "Referenceable" implementations
+		// in package addrs, however we are removing the possibility of
+		// Instances beforehand.
+		switch addr := rawSubj.(type) {
+		case addrs.ResourceInstance:
+			rawSubj = addr.ContainingResource()
+		case addrs.ModuleCallInstance:
+			rawSubj = addr.Call
+		case addrs.ModuleCallInstanceOutput:
+			rawSubj = addr.Call.Call
+		}
+
+		switch subj := rawSubj.(type) {
+		case addrs.Resource:
+			var into map[string]map[string]cty.Value
+			switch subj.Mode {
+			case addrs.ManagedResourceMode:
+				into = managedResources
+			case addrs.DataResourceMode:
+				into = dataResources
+			default:
+				panic(fmt.Errorf("unsupported ResourceMode %s", subj.Mode))
+			}
+
+			val, valDiags := normalizeRefValue(s.Data.GetResource(subj, rng))
+			diags = diags.Append(valDiags)
+
+			r := subj
+			if into[r.Type] == nil {
+				into[r.Type] = make(map[string]cty.Value)
+			}
+			into[r.Type][r.Name] = val
+
+		case addrs.ModuleCall:
+			val, valDiags := normalizeRefValue(s.Data.GetModule(subj, rng))
+			diags = diags.Append(valDiags)
+			wholeModules[subj.Name] = val
+
+		case addrs.InputVariable:
+			val, valDiags := normalizeRefValue(s.Data.GetInputVariable(subj, rng))
+			diags = diags.Append(valDiags)
+			inputVariables[subj.Name] = val
+
+		case addrs.LocalValue:
+			val, valDiags := normalizeRefValue(s.Data.GetLocalValue(subj, rng))
+			diags = diags.Append(valDiags)
+			localValues[subj.Name] = val
+
+		case addrs.PathAttr:
+			val, valDiags := normalizeRefValue(s.Data.GetPathAttr(subj, rng))
+			diags = diags.Append(valDiags)
+			pathAttrs[subj.Name] = val
+
+		case addrs.TerraformAttr:
+			val, valDiags := normalizeRefValue(s.Data.GetTerraformAttr(subj, rng))
+			diags = diags.Append(valDiags)
+			terraformAttrs[subj.Name] = val
+
+		case addrs.CountAttr:
+			val, valDiags := normalizeRefValue(s.Data.GetCountAttr(subj, rng))
+			diags = diags.Append(valDiags)
+			countAttrs[subj.Name] = val
+
+		case addrs.ForEachAttr:
+			val, valDiags := normalizeRefValue(s.Data.GetForEachAttr(subj, rng))
+			diags = diags.Append(valDiags)
+			forEachAttrs[subj.Name] = val
+
+		default:
+			// Should never happen
+			panic(fmt.Errorf("Scope.buildEvalContext cannot handle address type %T", rawSubj))
+		}
+	}
+
+	// Managed resources are exposed in two different locations. The primary
+	// is at the top level where the resource type name is the root of the
+	// traversal, but we also expose them under "resource" as an escaping
+	// technique if we add a reserved name in a future language edition which
+	// conflicts with someone's existing provider.
+	for k, v := range buildResourceObjects(managedResources) {
+		vals[k] = v
+	}
+	vals["resource"] = cty.ObjectVal(buildResourceObjects(managedResources))
+
+	vals["data"] = cty.ObjectVal(buildResourceObjects(dataResources))
+	vals["module"] = cty.ObjectVal(wholeModules)
+	vals["var"] = cty.ObjectVal(inputVariables)
+	vals["local"] = cty.ObjectVal(localValues)
+	vals["path"] = cty.ObjectVal(pathAttrs)
+	vals["terraform"] = cty.ObjectVal(terraformAttrs)
+	vals["count"] = cty.ObjectVal(countAttrs)
+	vals["each"] = cty.ObjectVal(forEachAttrs)
+	if self != cty.NilVal {
+		vals["self"] = self
+	}
+
+	return ctx, diags
+}
+
+func buildResourceObjects(resources map[string]map[string]cty.Value) map[string]cty.Value {
+	vals := make(map[string]cty.Value)
+	for typeName, nameVals := range resources {
+		vals[typeName] = cty.ObjectVal(nameVals)
+	}
+	return vals
+}
+
+func normalizeRefValue(val cty.Value, diags tfdiags.Diagnostics) (cty.Value, tfdiags.Diagnostics) {
+	if diags.HasErrors() {
+		// If there are errors then we will force an unknown result so that
+		// we can still evaluate and catch type errors but we'll avoid
+		// producing redundant re-statements of the same errors we've already
+		// dealt with here.
+		return cty.UnknownVal(val.Type()), diags
+	}
+	return val, diags
+}
diff --git a/v1.5.7/internal/lang/eval_test.go b/v1.5.7/internal/lang/eval_test.go
new file mode 100644
index 0000000..07190dd
--- /dev/null
+++ b/v1.5.7/internal/lang/eval_test.go
@@ -0,0 +1,847 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package lang
+
+import (
+	"bytes"
+	"encoding/json"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/instances"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+)
+
+func TestScopeEvalContext(t *testing.T) {
+	data := &dataForTests{
+		CountAttrs: map[string]cty.Value{
+			"index": cty.NumberIntVal(0),
+		},
+		ForEachAttrs: map[string]cty.Value{
+			"key":   cty.StringVal("a"),
+			"value": cty.NumberIntVal(1),
+		},
+		Resources: map[string]cty.Value{
+			"null_resource.foo": cty.ObjectVal(map[string]cty.Value{
+				"attr": cty.StringVal("bar"),
+			}),
+			"data.null_data_source.foo": cty.ObjectVal(map[string]cty.Value{
+				"attr": cty.StringVal("bar"),
+			}),
+			"null_resource.multi": cty.TupleVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"attr": cty.StringVal("multi0"),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"attr": cty.StringVal("multi1"),
+				}),
+			}),
+			"null_resource.each": cty.ObjectVal(map[string]cty.Value{
+				"each0": cty.ObjectVal(map[string]cty.Value{
+					"attr": cty.StringVal("each0"),
+				}),
+				"each1": cty.ObjectVal(map[string]cty.Value{
+					"attr": cty.StringVal("each1"),
+				}),
+			}),
+			"null_resource.multi[1]": cty.ObjectVal(map[string]cty.Value{
+				"attr": cty.StringVal("multi1"),
+			}),
+		},
+		LocalValues: map[string]cty.Value{
+			"foo": cty.StringVal("bar"),
+		},
+		Modules: map[string]cty.Value{
+			"module.foo": cty.ObjectVal(map[string]cty.Value{
+				"output0": cty.StringVal("bar0"),
+				"output1": cty.StringVal("bar1"),
+			}),
+		},
+		PathAttrs: map[string]cty.Value{
+			"module": cty.StringVal("foo/bar"),
+		},
+		TerraformAttrs: map[string]cty.Value{
+			"workspace": cty.StringVal("default"),
+		},
+		InputVariables: map[string]cty.Value{
+			"baz": cty.StringVal("boop"),
+		},
+	}
+
+	tests := []struct {
+		Expr string
+		Want map[string]cty.Value
+	}{
+		{
+			`12`,
+			map[string]cty.Value{},
+		},
+		{
+			`count.index`,
+			map[string]cty.Value{
+				"count": cty.ObjectVal(map[string]cty.Value{
+					"index": cty.NumberIntVal(0),
+				}),
+			},
+		},
+		{
+			`each.key`,
+			map[string]cty.Value{
+				"each": cty.ObjectVal(map[string]cty.Value{
+					"key": cty.StringVal("a"),
+				}),
+			},
+		},
+		{
+			`each.value`,
+			map[string]cty.Value{
+				"each": cty.ObjectVal(map[string]cty.Value{
+					"value": cty.NumberIntVal(1),
+				}),
+			},
+		},
+		{
+			`local.foo`,
+			map[string]cty.Value{
+				"local": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("bar"),
+				}),
+			},
+		},
+		{
+			`null_resource.foo`,
+			map[string]cty.Value{
+				"null_resource": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.ObjectVal(map[string]cty.Value{
+						"attr": cty.StringVal("bar"),
+					}),
+				}),
+				"resource": cty.ObjectVal(map[string]cty.Value{
+					"null_resource": cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.ObjectVal(map[string]cty.Value{
+							"attr": cty.StringVal("bar"),
+						}),
+					}),
+				}),
+			},
+		},
+		{
+			`null_resource.foo.attr`,
+			map[string]cty.Value{
+				"null_resource": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.ObjectVal(map[string]cty.Value{
+						"attr": cty.StringVal("bar"),
+					}),
+				}),
+				"resource": cty.ObjectVal(map[string]cty.Value{
+					"null_resource": cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.ObjectVal(map[string]cty.Value{
+							"attr": cty.StringVal("bar"),
+						}),
+					}),
+				}),
+			},
+		},
+		{
+			`null_resource.multi`,
+			map[string]cty.Value{
+				"null_resource": cty.ObjectVal(map[string]cty.Value{
+					"multi": cty.TupleVal([]cty.Value{
+						cty.ObjectVal(map[string]cty.Value{
+							"attr": cty.StringVal("multi0"),
+						}),
+						cty.ObjectVal(map[string]cty.Value{
+							"attr": cty.StringVal("multi1"),
+						}),
+					}),
+				}),
+				"resource": cty.ObjectVal(map[string]cty.Value{
+					"null_resource": cty.ObjectVal(map[string]cty.Value{
+						"multi": cty.TupleVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"attr": cty.StringVal("multi0"),
+							}),
+							cty.ObjectVal(map[string]cty.Value{
+								"attr": cty.StringVal("multi1"),
+							}),
+						}),
+					}),
+				}),
+			},
+		},
+		{
+			// at this level, all instance references return the entire resource
+			`null_resource.multi[1]`,
+			map[string]cty.Value{
+				"null_resource": cty.ObjectVal(map[string]cty.Value{
+					"multi": cty.TupleVal([]cty.Value{
+						cty.ObjectVal(map[string]cty.Value{
+							"attr": cty.StringVal("multi0"),
+						}),
+						cty.ObjectVal(map[string]cty.Value{
+							"attr": cty.StringVal("multi1"),
+						}),
+					}),
+				}),
+				"resource": cty.ObjectVal(map[string]cty.Value{
+					"null_resource": cty.ObjectVal(map[string]cty.Value{
+						"multi": cty.TupleVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"attr": cty.StringVal("multi0"),
+							}),
+							cty.ObjectVal(map[string]cty.Value{
+								"attr": cty.StringVal("multi1"),
+							}),
+						}),
+					}),
+				}),
+			},
+		},
+		{
+			// at this level, all instance references return the entire resource
+			`null_resource.each["each1"]`,
+			map[string]cty.Value{
+				"null_resource": cty.ObjectVal(map[string]cty.Value{
+					"each": cty.ObjectVal(map[string]cty.Value{
+						"each0": cty.ObjectVal(map[string]cty.Value{
+							"attr": cty.StringVal("each0"),
+						}),
+						"each1": cty.ObjectVal(map[string]cty.Value{
+							"attr": cty.StringVal("each1"),
+						}),
+					}),
+				}),
+				"resource": cty.ObjectVal(map[string]cty.Value{
+					"null_resource": cty.ObjectVal(map[string]cty.Value{
+						"each": cty.ObjectVal(map[string]cty.Value{
+							"each0": cty.ObjectVal(map[string]cty.Value{
+								"attr": cty.StringVal("each0"),
+							}),
+							"each1": cty.ObjectVal(map[string]cty.Value{
+								"attr": cty.StringVal("each1"),
+							}),
+						}),
+					}),
+				}),
+			},
+		},
+		{
+			// at this level, all instance references return the entire resource
+			`null_resource.each["each1"].attr`,
+			map[string]cty.Value{
+				"null_resource": cty.ObjectVal(map[string]cty.Value{
+					"each": cty.ObjectVal(map[string]cty.Value{
+						"each0": cty.ObjectVal(map[string]cty.Value{
+							"attr": cty.StringVal("each0"),
+						}),
+						"each1": cty.ObjectVal(map[string]cty.Value{
+							"attr": cty.StringVal("each1"),
+						}),
+					}),
+				}),
+				"resource": cty.ObjectVal(map[string]cty.Value{
+					"null_resource": cty.ObjectVal(map[string]cty.Value{
+						"each": cty.ObjectVal(map[string]cty.Value{
+							"each0": cty.ObjectVal(map[string]cty.Value{
+								"attr": cty.StringVal("each0"),
+							}),
+							"each1": cty.ObjectVal(map[string]cty.Value{
+								"attr": cty.StringVal("each1"),
+							}),
+						}),
+					}),
+				}),
+			},
+		},
+		{
+			`foo(null_resource.multi, null_resource.multi[1])`,
+			map[string]cty.Value{
+				"null_resource": cty.ObjectVal(map[string]cty.Value{
+					"multi": cty.TupleVal([]cty.Value{
+						cty.ObjectVal(map[string]cty.Value{
+							"attr": cty.StringVal("multi0"),
+						}),
+						cty.ObjectVal(map[string]cty.Value{
+							"attr": cty.StringVal("multi1"),
+						}),
+					}),
+				}),
+				"resource": cty.ObjectVal(map[string]cty.Value{
+					"null_resource": cty.ObjectVal(map[string]cty.Value{
+						"multi": cty.TupleVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"attr": cty.StringVal("multi0"),
+							}),
+							cty.ObjectVal(map[string]cty.Value{
+								"attr": cty.StringVal("multi1"),
+							}),
+						}),
+					}),
+				}),
+			},
+		},
+		{
+			`data.null_data_source.foo`,
+			map[string]cty.Value{
+				"data": cty.ObjectVal(map[string]cty.Value{
+					"null_data_source": cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.ObjectVal(map[string]cty.Value{
+							"attr": cty.StringVal("bar"),
+						}),
+					}),
+				}),
+			},
+		},
+		{
+			`module.foo`,
+			map[string]cty.Value{
+				"module": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.ObjectVal(map[string]cty.Value{
+						"output0": cty.StringVal("bar0"),
+						"output1": cty.StringVal("bar1"),
+					}),
+				}),
+			},
+		},
+		// any module reference returns the entire module
+		{
+			`module.foo.output1`,
+			map[string]cty.Value{
+				"module": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.ObjectVal(map[string]cty.Value{
+						"output0": cty.StringVal("bar0"),
+						"output1": cty.StringVal("bar1"),
+					}),
+				}),
+			},
+		},
+		{
+			`path.module`,
+			map[string]cty.Value{
+				"path": cty.ObjectVal(map[string]cty.Value{
+					"module": cty.StringVal("foo/bar"),
+				}),
+			},
+		},
+		{
+			`self.baz`,
+			map[string]cty.Value{
+				"self": cty.ObjectVal(map[string]cty.Value{
+					"attr": cty.StringVal("multi1"),
+				}),
+			},
+		},
+		{
+			`terraform.workspace`,
+			map[string]cty.Value{
+				"terraform": cty.ObjectVal(map[string]cty.Value{
+					"workspace": cty.StringVal("default"),
+				}),
+			},
+		},
+		{
+			`var.baz`,
+			map[string]cty.Value{
+				"var": cty.ObjectVal(map[string]cty.Value{
+					"baz": cty.StringVal("boop"),
+				}),
+			},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Expr, func(t *testing.T) {
+			expr, parseDiags := hclsyntax.ParseExpression([]byte(test.Expr), "", hcl.Pos{Line: 1, Column: 1})
+			if len(parseDiags) != 0 {
+				t.Errorf("unexpected diagnostics during parse")
+				for _, diag := range parseDiags {
+					t.Errorf("- %s", diag)
+				}
+				return
+			}
+
+			refs, refsDiags := ReferencesInExpr(expr)
+			if refsDiags.HasErrors() {
+				t.Fatal(refsDiags.Err())
+			}
+
+			scope := &Scope{
+				Data: data,
+
+				// "self" will just be an arbitrary one of the several resource
+				// instances we have in our test dataset.
+				SelfAddr: addrs.ResourceInstance{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "null_resource",
+						Name: "multi",
+					},
+					Key: addrs.IntKey(1),
+				},
+			}
+			ctx, ctxDiags := scope.EvalContext(refs)
+			if ctxDiags.HasErrors() {
+				t.Fatal(ctxDiags.Err())
+			}
+
+			// For easier test assertions we'll just remove any top-level
+			// empty objects from our variables map.
+			for k, v := range ctx.Variables {
+				if v.RawEquals(cty.EmptyObjectVal) {
+					delete(ctx.Variables, k)
+				}
+			}
+
+			gotVal := cty.ObjectVal(ctx.Variables)
+			wantVal := cty.ObjectVal(test.Want)
+
+			if !gotVal.RawEquals(wantVal) {
+				// We'll JSON-ize our values here just so it's easier to
+				// read them in the assertion output.
+				gotJSON := formattedJSONValue(gotVal)
+				wantJSON := formattedJSONValue(wantVal)
+
+				t.Errorf(
+					"wrong result\nexpr: %s\ngot:  %s\nwant: %s",
+					test.Expr, gotJSON, wantJSON,
+				)
+			}
+		})
+	}
+}
+
+func TestScopeExpandEvalBlock(t *testing.T) {
+	nestedObjTy := cty.Object(map[string]cty.Type{
+		"boop": cty.String,
+	})
+	schema := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"foo":         {Type: cty.String, Optional: true},
+			"list_of_obj": {Type: cty.List(nestedObjTy), Optional: true},
+		},
+		BlockTypes: map[string]*configschema.NestedBlock{
+			"bar": {
+				Nesting: configschema.NestingMap,
+				Block: configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"baz": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	data := &dataForTests{
+		LocalValues: map[string]cty.Value{
+			"greeting": cty.StringVal("howdy"),
+			"list": cty.ListVal([]cty.Value{
+				cty.StringVal("elem0"),
+				cty.StringVal("elem1"),
+			}),
+			"map": cty.MapVal(map[string]cty.Value{
+				"key1": cty.StringVal("val1"),
+				"key2": cty.StringVal("val2"),
+			}),
+		},
+	}
+
+	tests := map[string]struct {
+		Config string
+		Want   cty.Value
+	}{
+		"empty": {
+			`
+			`,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo":         cty.NullVal(cty.String),
+				"list_of_obj": cty.NullVal(cty.List(nestedObjTy)),
+				"bar": cty.MapValEmpty(cty.Object(map[string]cty.Type{
+					"baz": cty.String,
+				})),
+			}),
+		},
+		"literal attribute": {
+			`
+			foo = "hello"
+			`,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo":         cty.StringVal("hello"),
+				"list_of_obj": cty.NullVal(cty.List(nestedObjTy)),
+				"bar": cty.MapValEmpty(cty.Object(map[string]cty.Type{
+					"baz": cty.String,
+				})),
+			}),
+		},
+		"variable attribute": {
+			`
+			foo = local.greeting
+			`,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo":         cty.StringVal("howdy"),
+				"list_of_obj": cty.NullVal(cty.List(nestedObjTy)),
+				"bar": cty.MapValEmpty(cty.Object(map[string]cty.Type{
+					"baz": cty.String,
+				})),
+			}),
+		},
+		"one static block": {
+			`
+			bar "static" {}
+			`,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo":         cty.NullVal(cty.String),
+				"list_of_obj": cty.NullVal(cty.List(nestedObjTy)),
+				"bar": cty.MapVal(map[string]cty.Value{
+					"static": cty.ObjectVal(map[string]cty.Value{
+						"baz": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+		},
+		"two static blocks": {
+			`
+			bar "static0" {
+				baz = 0
+			}
+			bar "static1" {
+				baz = 1
+			}
+			`,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo":         cty.NullVal(cty.String),
+				"list_of_obj": cty.NullVal(cty.List(nestedObjTy)),
+				"bar": cty.MapVal(map[string]cty.Value{
+					"static0": cty.ObjectVal(map[string]cty.Value{
+						"baz": cty.StringVal("0"),
+					}),
+					"static1": cty.ObjectVal(map[string]cty.Value{
+						"baz": cty.StringVal("1"),
+					}),
+				}),
+			}),
+		},
+		"dynamic blocks from list": {
+			`
+			dynamic "bar" {
+				for_each = local.list
+				labels = [bar.value]
+				content {
+					baz = bar.key
+				}
+			}
+			`,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo":         cty.NullVal(cty.String),
+				"list_of_obj": cty.NullVal(cty.List(nestedObjTy)),
+				"bar": cty.MapVal(map[string]cty.Value{
+					"elem0": cty.ObjectVal(map[string]cty.Value{
+						"baz": cty.StringVal("0"),
+					}),
+					"elem1": cty.ObjectVal(map[string]cty.Value{
+						"baz": cty.StringVal("1"),
+					}),
+				}),
+			}),
+		},
+		"dynamic blocks from map": {
+			`
+			dynamic "bar" {
+				for_each = local.map
+				labels = [bar.key]
+				content {
+					baz = bar.value
+				}
+			}
+			`,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo":         cty.NullVal(cty.String),
+				"list_of_obj": cty.NullVal(cty.List(nestedObjTy)),
+				"bar": cty.MapVal(map[string]cty.Value{
+					"key1": cty.ObjectVal(map[string]cty.Value{
+						"baz": cty.StringVal("val1"),
+					}),
+					"key2": cty.ObjectVal(map[string]cty.Value{
+						"baz": cty.StringVal("val2"),
+					}),
+				}),
+			}),
+		},
+		"list-of-object attribute": {
+			`
+			list_of_obj = [
+				{
+					boop = local.greeting
+				},
+			]
+			`,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(cty.String),
+				"list_of_obj": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"boop": cty.StringVal("howdy"),
+					}),
+				}),
+				"bar": cty.MapValEmpty(cty.Object(map[string]cty.Type{
+					"baz": cty.String,
+				})),
+			}),
+		},
+		"list-of-object attribute as blocks": {
+			`
+			list_of_obj {
+				boop = local.greeting
+			}
+			`,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(cty.String),
+				"list_of_obj": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"boop": cty.StringVal("howdy"),
+					}),
+				}),
+				"bar": cty.MapValEmpty(cty.Object(map[string]cty.Type{
+					"baz": cty.String,
+				})),
+			}),
+		},
+		"lots of things at once": {
+			`
+			foo = "whoop"
+			bar "static0" {
+				baz = "s0"
+			}
+			dynamic "bar" {
+				for_each = local.list
+				labels = [bar.value]
+				content {
+					baz = bar.key
+				}
+			}
+			bar "static1" {
+				baz = "s1"
+			}
+			dynamic "bar" {
+				for_each = local.map
+				labels = [bar.key]
+				content {
+					baz = bar.value
+				}
+			}
+			bar "static2" {
+				baz = "s2"
+			}
+			`,
+			cty.ObjectVal(map[string]cty.Value{
+				"foo":         cty.StringVal("whoop"),
+				"list_of_obj": cty.NullVal(cty.List(nestedObjTy)),
+				"bar": cty.MapVal(map[string]cty.Value{
+					"key1": cty.ObjectVal(map[string]cty.Value{
+						"baz": cty.StringVal("val1"),
+					}),
+					"key2": cty.ObjectVal(map[string]cty.Value{
+						"baz": cty.StringVal("val2"),
+					}),
+					"elem0": cty.ObjectVal(map[string]cty.Value{
+						"baz": cty.StringVal("0"),
+					}),
+					"elem1": cty.ObjectVal(map[string]cty.Value{
+						"baz": cty.StringVal("1"),
+					}),
+					"static0": cty.ObjectVal(map[string]cty.Value{
+						"baz": cty.StringVal("s0"),
+					}),
+					"static1": cty.ObjectVal(map[string]cty.Value{
+						"baz": cty.StringVal("s1"),
+					}),
+					"static2": cty.ObjectVal(map[string]cty.Value{
+						"baz": cty.StringVal("s2"),
+					}),
+				}),
+			}),
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			file, parseDiags := hclsyntax.ParseConfig([]byte(test.Config), "", hcl.Pos{Line: 1, Column: 1})
+			if len(parseDiags) != 0 {
+				t.Errorf("unexpected diagnostics during parse")
+				for _, diag := range parseDiags {
+					t.Errorf("- %s", diag)
+				}
+				return
+			}
+
+			body := file.Body
+			scope := &Scope{
+				Data: data,
+			}
+
+			body, expandDiags := scope.ExpandBlock(body, schema)
+			if expandDiags.HasErrors() {
+				t.Fatal(expandDiags.Err())
+			}
+
+			got, valDiags := scope.EvalBlock(body, schema)
+			if valDiags.HasErrors() {
+				t.Fatal(valDiags.Err())
+			}
+
+			if !got.RawEquals(test.Want) {
+				// We'll JSON-ize our values here just so it's easier to
+				// read them in the assertion output.
+				gotJSON := formattedJSONValue(got)
+				wantJSON := formattedJSONValue(test.Want)
+
+				t.Errorf(
+					"wrong result\nconfig: %s\ngot:   %s\nwant:  %s",
+					test.Config, gotJSON, wantJSON,
+				)
+			}
+
+		})
+	}
+
+}
+
+func formattedJSONValue(val cty.Value) string {
+	val = cty.UnknownAsNull(val) // since JSON can't represent unknowns
+	j, err := ctyjson.Marshal(val, val.Type())
+	if err != nil {
+		panic(err)
+	}
+	var buf bytes.Buffer
+	json.Indent(&buf, j, "", "  ")
+	return buf.String()
+}
+
+func TestScopeEvalSelfBlock(t *testing.T) {
+	data := &dataForTests{
+		PathAttrs: map[string]cty.Value{
+			"module": cty.StringVal("foo/bar"),
+			"cwd":    cty.StringVal("/home/foo/bar"),
+			"root":   cty.StringVal("/home/foo"),
+		},
+		TerraformAttrs: map[string]cty.Value{
+			"workspace": cty.StringVal("default"),
+		},
+	}
+	schema := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"attr": {
+				Type: cty.String,
+			},
+			"num": {
+				Type: cty.Number,
+			},
+		},
+	}
+
+	tests := []struct {
+		Config  string
+		Self    cty.Value
+		KeyData instances.RepetitionData
+		Want    map[string]cty.Value
+	}{
+		{
+			Config: `attr = self.foo`,
+			Self: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+			}),
+			KeyData: instances.RepetitionData{
+				CountIndex: cty.NumberIntVal(0),
+			},
+			Want: map[string]cty.Value{
+				"attr": cty.StringVal("bar"),
+				"num":  cty.NullVal(cty.Number),
+			},
+		},
+		{
+			Config: `num = count.index`,
+			KeyData: instances.RepetitionData{
+				CountIndex: cty.NumberIntVal(0),
+			},
+			Want: map[string]cty.Value{
+				"attr": cty.NullVal(cty.String),
+				"num":  cty.NumberIntVal(0),
+			},
+		},
+		{
+			Config: `attr = each.key`,
+			KeyData: instances.RepetitionData{
+				EachKey: cty.StringVal("a"),
+			},
+			Want: map[string]cty.Value{
+				"attr": cty.StringVal("a"),
+				"num":  cty.NullVal(cty.Number),
+			},
+		},
+		{
+			Config: `attr = path.cwd`,
+			Want: map[string]cty.Value{
+				"attr": cty.StringVal("/home/foo/bar"),
+				"num":  cty.NullVal(cty.Number),
+			},
+		},
+		{
+			Config: `attr = path.module`,
+			Want: map[string]cty.Value{
+				"attr": cty.StringVal("foo/bar"),
+				"num":  cty.NullVal(cty.Number),
+			},
+		},
+		{
+			Config: `attr = path.root`,
+			Want: map[string]cty.Value{
+				"attr": cty.StringVal("/home/foo"),
+				"num":  cty.NullVal(cty.Number),
+			},
+		},
+		{
+			Config: `attr = terraform.workspace`,
+			Want: map[string]cty.Value{
+				"attr": cty.StringVal("default"),
+				"num":  cty.NullVal(cty.Number),
+			},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Config, func(t *testing.T) {
+			file, parseDiags := hclsyntax.ParseConfig([]byte(test.Config), "", hcl.Pos{Line: 1, Column: 1})
+			if len(parseDiags) != 0 {
+				t.Errorf("unexpected diagnostics during parse")
+				for _, diag := range parseDiags {
+					t.Errorf("- %s", diag)
+				}
+				return
+			}
+
+			body := file.Body
+
+			scope := &Scope{
+				Data: data,
+			}
+
+			gotVal, ctxDiags := scope.EvalSelfBlock(body, test.Self, schema, test.KeyData)
+			if ctxDiags.HasErrors() {
+				t.Fatal(ctxDiags.Err())
+			}
+
+			wantVal := cty.ObjectVal(test.Want)
+
+			if !gotVal.RawEquals(wantVal) {
+				t.Errorf(
+					"wrong result\nexpr: %s\ngot:  %#v\nwant: %#v",
+					test.Config, gotVal, wantVal,
+				)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/lang/funcs/cidr.go b/v1.5.7/internal/lang/funcs/cidr.go
new file mode 100644
index 0000000..d183e7a
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/cidr.go
@@ -0,0 +1,218 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"fmt"
+	"math/big"
+
+	"github.com/apparentlymart/go-cidr/cidr"
+	"github.com/hashicorp/terraform/internal/ipaddr"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+	"github.com/zclconf/go-cty/cty/gocty"
+)
+
+// CidrHostFunc contructs a function that calculates a full host IP address
+// within a given IP network address prefix.
+var CidrHostFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "prefix",
+			Type: cty.String,
+		},
+		{
+			Name: "hostnum",
+			Type: cty.Number,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		var hostNum *big.Int
+		if err := gocty.FromCtyValue(args[1], &hostNum); err != nil {
+			return cty.UnknownVal(cty.String), err
+		}
+		_, network, err := ipaddr.ParseCIDR(args[0].AsString())
+		if err != nil {
+			return cty.UnknownVal(cty.String), fmt.Errorf("invalid CIDR expression: %s", err)
+		}
+
+		ip, err := cidr.HostBig(network, hostNum)
+		if err != nil {
+			return cty.UnknownVal(cty.String), err
+		}
+
+		return cty.StringVal(ip.String()), nil
+	},
+})
+
+// CidrNetmaskFunc contructs a function that converts an IPv4 address prefix given
+// in CIDR notation into a subnet mask address.
+var CidrNetmaskFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "prefix",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		_, network, err := ipaddr.ParseCIDR(args[0].AsString())
+		if err != nil {
+			return cty.UnknownVal(cty.String), fmt.Errorf("invalid CIDR expression: %s", err)
+		}
+
+		if network.IP.To4() == nil {
+			return cty.UnknownVal(cty.String), fmt.Errorf("IPv6 addresses cannot have a netmask: %s", args[0].AsString())
+		}
+
+		return cty.StringVal(ipaddr.IP(network.Mask).String()), nil
+	},
+})
+
+// CidrSubnetFunc contructs a function that calculates a subnet address within
+// a given IP network address prefix.
+var CidrSubnetFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "prefix",
+			Type: cty.String,
+		},
+		{
+			Name: "newbits",
+			Type: cty.Number,
+		},
+		{
+			Name: "netnum",
+			Type: cty.Number,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		var newbits int
+		if err := gocty.FromCtyValue(args[1], &newbits); err != nil {
+			return cty.UnknownVal(cty.String), err
+		}
+		var netnum *big.Int
+		if err := gocty.FromCtyValue(args[2], &netnum); err != nil {
+			return cty.UnknownVal(cty.String), err
+		}
+
+		_, network, err := ipaddr.ParseCIDR(args[0].AsString())
+		if err != nil {
+			return cty.UnknownVal(cty.String), fmt.Errorf("invalid CIDR expression: %s", err)
+		}
+
+		newNetwork, err := cidr.SubnetBig(network, newbits, netnum)
+		if err != nil {
+			return cty.UnknownVal(cty.String), err
+		}
+
+		return cty.StringVal(newNetwork.String()), nil
+	},
+})
+
+// CidrSubnetsFunc is similar to CidrSubnetFunc but calculates many consecutive
+// subnet addresses at once, rather than just a single subnet extension.
+var CidrSubnetsFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "prefix",
+			Type: cty.String,
+		},
+	},
+	VarParam: &function.Parameter{
+		Name: "newbits",
+		Type: cty.Number,
+	},
+	Type: function.StaticReturnType(cty.List(cty.String)),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		_, network, err := ipaddr.ParseCIDR(args[0].AsString())
+		if err != nil {
+			return cty.UnknownVal(cty.String), function.NewArgErrorf(0, "invalid CIDR expression: %s", err)
+		}
+		startPrefixLen, _ := network.Mask.Size()
+
+		prefixLengthArgs := args[1:]
+		if len(prefixLengthArgs) == 0 {
+			return cty.ListValEmpty(cty.String), nil
+		}
+
+		var firstLength int
+		if err := gocty.FromCtyValue(prefixLengthArgs[0], &firstLength); err != nil {
+			return cty.UnknownVal(cty.String), function.NewArgError(1, err)
+		}
+		firstLength += startPrefixLen
+
+		retVals := make([]cty.Value, len(prefixLengthArgs))
+
+		current, _ := cidr.PreviousSubnet(network, firstLength)
+		for i, lengthArg := range prefixLengthArgs {
+			var length int
+			if err := gocty.FromCtyValue(lengthArg, &length); err != nil {
+				return cty.UnknownVal(cty.String), function.NewArgError(i+1, err)
+			}
+
+			if length < 1 {
+				return cty.UnknownVal(cty.String), function.NewArgErrorf(i+1, "must extend prefix by at least one bit")
+			}
+			// For portability with 32-bit systems where the subnet number
+			// will be a 32-bit int, we only allow extension of 32 bits in
+			// one call even if we're running on a 64-bit machine.
+			// (Of course, this is significant only for IPv6.)
+			if length > 32 {
+				return cty.UnknownVal(cty.String), function.NewArgErrorf(i+1, "may not extend prefix by more than 32 bits")
+			}
+			length += startPrefixLen
+			if length > (len(network.IP) * 8) {
+				protocol := "IP"
+				switch len(network.IP) * 8 {
+				case 32:
+					protocol = "IPv4"
+				case 128:
+					protocol = "IPv6"
+				}
+				return cty.UnknownVal(cty.String), function.NewArgErrorf(i+1, "would extend prefix to %d bits, which is too long for an %s address", length, protocol)
+			}
+
+			next, rollover := cidr.NextSubnet(current, length)
+			if rollover || !network.Contains(next.IP) {
+				// If we run out of suffix bits in the base CIDR prefix then
+				// NextSubnet will start incrementing the prefix bits, which
+				// we don't allow because it would then allocate addresses
+				// outside of the caller's given prefix.
+				return cty.UnknownVal(cty.String), function.NewArgErrorf(i+1, "not enough remaining address space for a subnet with a prefix of %d bits after %s", length, current.String())
+			}
+
+			current = next
+			retVals[i] = cty.StringVal(current.String())
+		}
+
+		return cty.ListVal(retVals), nil
+	},
+})
+
+// CidrHost calculates a full host IP address within a given IP network address prefix.
+func CidrHost(prefix, hostnum cty.Value) (cty.Value, error) {
+	return CidrHostFunc.Call([]cty.Value{prefix, hostnum})
+}
+
+// CidrNetmask converts an IPv4 address prefix given in CIDR notation into a subnet mask address.
+func CidrNetmask(prefix cty.Value) (cty.Value, error) {
+	return CidrNetmaskFunc.Call([]cty.Value{prefix})
+}
+
+// CidrSubnet calculates a subnet address within a given IP network address prefix.
+func CidrSubnet(prefix, newbits, netnum cty.Value) (cty.Value, error) {
+	return CidrSubnetFunc.Call([]cty.Value{prefix, newbits, netnum})
+}
+
+// CidrSubnets calculates a sequence of consecutive subnet prefixes that may
+// be of different prefix lengths under a common base prefix.
+func CidrSubnets(prefix cty.Value, newbits ...cty.Value) (cty.Value, error) {
+	args := make([]cty.Value, len(newbits)+1)
+	args[0] = prefix
+	copy(args[1:], newbits)
+	return CidrSubnetsFunc.Call(args)
+}
diff --git a/v1.5.7/internal/lang/funcs/cidr_test.go b/v1.5.7/internal/lang/funcs/cidr_test.go
new file mode 100644
index 0000000..3b0591c
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/cidr_test.go
@@ -0,0 +1,398 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestCidrHost(t *testing.T) {
+	tests := []struct {
+		Prefix  cty.Value
+		Hostnum cty.Value
+		Want    cty.Value
+		Err     bool
+	}{
+		{
+			cty.StringVal("192.168.1.0/24"),
+			cty.NumberIntVal(5),
+			cty.StringVal("192.168.1.5"),
+			false,
+		},
+		{
+			cty.StringVal("192.168.1.0/24"),
+			cty.NumberIntVal(-5),
+			cty.StringVal("192.168.1.251"),
+			false,
+		},
+		{
+			cty.StringVal("192.168.1.0/24"),
+			cty.NumberIntVal(-256),
+			cty.StringVal("192.168.1.0"),
+			false,
+		},
+		{
+			// We inadvertently inherited a pre-Go1.17 standard library quirk
+			// if parsing zero-prefix parts as decimal rather than octal.
+			// Go 1.17 resolved that quirk by making zero-prefix invalid, but
+			// we've preserved our existing behavior for backward compatibility,
+			// on the grounds that these functions are for generating addresses
+			// rather than validating or processing them. We do always generate
+			// a canonical result regardless of the input, though.
+			cty.StringVal("010.001.0.0/24"),
+			cty.NumberIntVal(6),
+			cty.StringVal("10.1.0.6"),
+			false,
+		},
+		{
+			cty.StringVal("192.168.1.0/30"),
+			cty.NumberIntVal(255),
+			cty.UnknownVal(cty.String),
+			true, // 255 doesn't fit in two bits
+		},
+		{
+			cty.StringVal("192.168.1.0/30"),
+			cty.NumberIntVal(-255),
+			cty.UnknownVal(cty.String),
+			true, // 255 doesn't fit in two bits
+		},
+		{
+			cty.StringVal("not-a-cidr"),
+			cty.NumberIntVal(6),
+			cty.UnknownVal(cty.String),
+			true, // not a valid CIDR mask
+		},
+		{
+			cty.StringVal("10.256.0.0/8"),
+			cty.NumberIntVal(6),
+			cty.UnknownVal(cty.String),
+			true, // can't have an octet >255
+		},
+		{ // fractions are Not Ok
+			cty.StringVal("10.256.0.0/8"),
+			cty.NumberFloatVal(.75),
+			cty.UnknownVal(cty.String),
+			true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("cidrhost(%#v, %#v)", test.Prefix, test.Hostnum), func(t *testing.T) {
+			got, err := CidrHost(test.Prefix, test.Hostnum)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestCidrNetmask(t *testing.T) {
+	tests := []struct {
+		Prefix cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		{
+			cty.StringVal("192.168.1.0/24"),
+			cty.StringVal("255.255.255.0"),
+			false,
+		},
+		{
+			cty.StringVal("192.168.1.0/32"),
+			cty.StringVal("255.255.255.255"),
+			false,
+		},
+		{
+			cty.StringVal("0.0.0.0/0"),
+			cty.StringVal("0.0.0.0"),
+			false,
+		},
+		{
+			// We inadvertently inherited a pre-Go1.17 standard library quirk
+			// if parsing zero-prefix parts as decimal rather than octal.
+			// Go 1.17 resolved that quirk by making zero-prefix invalid, but
+			// we've preserved our existing behavior for backward compatibility,
+			// on the grounds that these functions are for generating addresses
+			// rather than validating or processing them.
+			cty.StringVal("010.001.0.0/24"),
+			cty.StringVal("255.255.255.0"),
+			false,
+		},
+		{
+			cty.StringVal("not-a-cidr"),
+			cty.UnknownVal(cty.String),
+			true, // not a valid CIDR mask
+		},
+		{
+			cty.StringVal("110.256.0.0/8"),
+			cty.UnknownVal(cty.String),
+			true, // can't have an octet >255
+		},
+		{
+			cty.StringVal("1::/64"),
+			cty.UnknownVal(cty.String),
+			true, // IPv6 is invalid
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("cidrnetmask(%#v)", test.Prefix), func(t *testing.T) {
+			got, err := CidrNetmask(test.Prefix)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestCidrSubnet(t *testing.T) {
+	tests := []struct {
+		Prefix  cty.Value
+		Newbits cty.Value
+		Netnum  cty.Value
+		Want    cty.Value
+		Err     bool
+	}{
+		{
+			cty.StringVal("192.168.2.0/20"),
+			cty.NumberIntVal(4),
+			cty.NumberIntVal(6),
+			cty.StringVal("192.168.6.0/24"),
+			false,
+		},
+		{
+			cty.StringVal("fe80::/48"),
+			cty.NumberIntVal(16),
+			cty.NumberIntVal(6),
+			cty.StringVal("fe80:0:0:6::/64"),
+			false,
+		},
+		{ // IPv4 address encoded in IPv6 syntax gets normalized
+			cty.StringVal("::ffff:192.168.0.0/112"),
+			cty.NumberIntVal(8),
+			cty.NumberIntVal(6),
+			cty.StringVal("192.168.6.0/24"),
+			false,
+		},
+		{
+			cty.StringVal("fe80::/48"),
+			cty.NumberIntVal(33),
+			cty.NumberIntVal(6),
+			cty.StringVal("fe80::3:0:0:0/81"),
+			false,
+		},
+		{
+			// We inadvertently inherited a pre-Go1.17 standard library quirk
+			// if parsing zero-prefix parts as decimal rather than octal.
+			// Go 1.17 resolved that quirk by making zero-prefix invalid, but
+			// we've preserved our existing behavior for backward compatibility,
+			// on the grounds that these functions are for generating addresses
+			// rather than validating or processing them. We do always generate
+			// a canonical result regardless of the input, though.
+			cty.StringVal("010.001.0.0/24"),
+			cty.NumberIntVal(4),
+			cty.NumberIntVal(1),
+			cty.StringVal("10.1.0.16/28"),
+			false,
+		},
+		{ // not enough bits left
+			cty.StringVal("192.168.0.0/30"),
+			cty.NumberIntVal(4),
+			cty.NumberIntVal(6),
+			cty.UnknownVal(cty.String),
+			true,
+		},
+		{ // can't encode 16 in 2 bits
+			cty.StringVal("192.168.0.0/168"),
+			cty.NumberIntVal(2),
+			cty.NumberIntVal(16),
+			cty.UnknownVal(cty.String),
+			true,
+		},
+		{ // not a valid CIDR mask
+			cty.StringVal("not-a-cidr"),
+			cty.NumberIntVal(4),
+			cty.NumberIntVal(6),
+			cty.UnknownVal(cty.String),
+			true,
+		},
+		{ // can't have an octet >255
+			cty.StringVal("10.256.0.0/8"),
+			cty.NumberIntVal(4),
+			cty.NumberIntVal(6),
+			cty.UnknownVal(cty.String),
+			true,
+		},
+		{ // fractions are Not Ok
+			cty.StringVal("10.256.0.0/8"),
+			cty.NumberFloatVal(2.0 / 3.0),
+			cty.NumberFloatVal(.75),
+			cty.UnknownVal(cty.String),
+			true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("cidrsubnet(%#v, %#v, %#v)", test.Prefix, test.Newbits, test.Netnum), func(t *testing.T) {
+			got, err := CidrSubnet(test.Prefix, test.Newbits, test.Netnum)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+func TestCidrSubnets(t *testing.T) {
+	tests := []struct {
+		Prefix  cty.Value
+		Newbits []cty.Value
+		Want    cty.Value
+		Err     string
+	}{
+		{
+			cty.StringVal("10.0.0.0/21"),
+			[]cty.Value{
+				cty.NumberIntVal(3),
+				cty.NumberIntVal(3),
+				cty.NumberIntVal(3),
+				cty.NumberIntVal(4),
+				cty.NumberIntVal(4),
+				cty.NumberIntVal(4),
+				cty.NumberIntVal(7),
+				cty.NumberIntVal(7),
+				cty.NumberIntVal(7),
+			},
+			cty.ListVal([]cty.Value{
+				cty.StringVal("10.0.0.0/24"),
+				cty.StringVal("10.0.1.0/24"),
+				cty.StringVal("10.0.2.0/24"),
+				cty.StringVal("10.0.3.0/25"),
+				cty.StringVal("10.0.3.128/25"),
+				cty.StringVal("10.0.4.0/25"),
+				cty.StringVal("10.0.4.128/28"),
+				cty.StringVal("10.0.4.144/28"),
+				cty.StringVal("10.0.4.160/28"),
+			}),
+			``,
+		},
+		{
+			// We inadvertently inherited a pre-Go1.17 standard library quirk
+			// if parsing zero-prefix parts as decimal rather than octal.
+			// Go 1.17 resolved that quirk by making zero-prefix invalid, but
+			// we've preserved our existing behavior for backward compatibility,
+			// on the grounds that these functions are for generating addresses
+			// rather than validating or processing them. We do always generate
+			// a canonical result regardless of the input, though.
+			cty.StringVal("010.0.0.0/21"),
+			[]cty.Value{
+				cty.NumberIntVal(3),
+			},
+			cty.ListVal([]cty.Value{
+				cty.StringVal("10.0.0.0/24"),
+			}),
+			``,
+		},
+		{
+			cty.StringVal("10.0.0.0/30"),
+			[]cty.Value{
+				cty.NumberIntVal(1),
+				cty.NumberIntVal(3),
+			},
+			cty.UnknownVal(cty.List(cty.String)),
+			`would extend prefix to 33 bits, which is too long for an IPv4 address`,
+		},
+		{
+			cty.StringVal("10.0.0.0/8"),
+			[]cty.Value{
+				cty.NumberIntVal(1),
+				cty.NumberIntVal(1),
+				cty.NumberIntVal(1),
+			},
+			cty.UnknownVal(cty.List(cty.String)),
+			`not enough remaining address space for a subnet with a prefix of 9 bits after 10.128.0.0/9`,
+		},
+		{
+			cty.StringVal("10.0.0.0/8"),
+			[]cty.Value{
+				cty.NumberIntVal(1),
+				cty.NumberIntVal(0),
+			},
+			cty.UnknownVal(cty.List(cty.String)),
+			`must extend prefix by at least one bit`,
+		},
+		{
+			cty.StringVal("10.0.0.0/8"),
+			[]cty.Value{
+				cty.NumberIntVal(1),
+				cty.NumberIntVal(-1),
+			},
+			cty.UnknownVal(cty.List(cty.String)),
+			`must extend prefix by at least one bit`,
+		},
+		{
+			cty.StringVal("fe80::/48"),
+			[]cty.Value{
+				cty.NumberIntVal(1),
+				cty.NumberIntVal(33),
+			},
+			cty.UnknownVal(cty.List(cty.String)),
+			`may not extend prefix by more than 32 bits`,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("cidrsubnets(%#v, %#v)", test.Prefix, test.Newbits), func(t *testing.T) {
+			got, err := CidrSubnets(test.Prefix, test.Newbits...)
+			wantErr := test.Err != ""
+
+			if wantErr {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				if err.Error() != test.Err {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", err.Error(), test.Err)
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/lang/funcs/collection.go b/v1.5.7/internal/lang/funcs/collection.go
new file mode 100644
index 0000000..03b87a4
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/collection.go
@@ -0,0 +1,718 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"errors"
+	"fmt"
+	"math/big"
+	"sort"
+
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/convert"
+	"github.com/zclconf/go-cty/cty/function"
+	"github.com/zclconf/go-cty/cty/function/stdlib"
+	"github.com/zclconf/go-cty/cty/gocty"
+)
+
+var LengthFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name:             "value",
+			Type:             cty.DynamicPseudoType,
+			AllowDynamicType: true,
+			AllowUnknown:     true,
+			AllowMarked:      true,
+		},
+	},
+	Type: func(args []cty.Value) (cty.Type, error) {
+		collTy := args[0].Type()
+		switch {
+		case collTy == cty.String || collTy.IsTupleType() || collTy.IsObjectType() || collTy.IsListType() || collTy.IsMapType() || collTy.IsSetType() || collTy == cty.DynamicPseudoType:
+			return cty.Number, nil
+		default:
+			return cty.Number, errors.New("argument must be a string, a collection type, or a structural type")
+		}
+	},
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		coll := args[0]
+		collTy := args[0].Type()
+		marks := coll.Marks()
+		switch {
+		case collTy == cty.DynamicPseudoType:
+			return cty.UnknownVal(cty.Number).WithMarks(marks), nil
+		case collTy.IsTupleType():
+			l := len(collTy.TupleElementTypes())
+			return cty.NumberIntVal(int64(l)).WithMarks(marks), nil
+		case collTy.IsObjectType():
+			l := len(collTy.AttributeTypes())
+			return cty.NumberIntVal(int64(l)).WithMarks(marks), nil
+		case collTy == cty.String:
+			// We'll delegate to the cty stdlib strlen function here, because
+			// it deals with all of the complexities of tokenizing unicode
+			// grapheme clusters.
+			return stdlib.Strlen(coll)
+		case collTy.IsListType() || collTy.IsSetType() || collTy.IsMapType():
+			return coll.Length(), nil
+		default:
+			// Should never happen, because of the checks in our Type func above
+			return cty.UnknownVal(cty.Number), errors.New("impossible value type for length(...)")
+		}
+	},
+})
+
+// AllTrueFunc constructs a function that returns true if all elements of the
+// list are true. If the list is empty, return true.
+var AllTrueFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "list",
+			Type: cty.List(cty.Bool),
+		},
+	},
+	Type: function.StaticReturnType(cty.Bool),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		result := cty.True
+		for it := args[0].ElementIterator(); it.Next(); {
+			_, v := it.Element()
+			if !v.IsKnown() {
+				return cty.UnknownVal(cty.Bool), nil
+			}
+			if v.IsNull() {
+				return cty.False, nil
+			}
+			result = result.And(v)
+			if result.False() {
+				return cty.False, nil
+			}
+		}
+		return result, nil
+	},
+})
+
+// AnyTrueFunc constructs a function that returns true if any element of the
+// list is true. If the list is empty, return false.
+var AnyTrueFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "list",
+			Type: cty.List(cty.Bool),
+		},
+	},
+	Type: function.StaticReturnType(cty.Bool),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		result := cty.False
+		var hasUnknown bool
+		for it := args[0].ElementIterator(); it.Next(); {
+			_, v := it.Element()
+			if !v.IsKnown() {
+				hasUnknown = true
+				continue
+			}
+			if v.IsNull() {
+				continue
+			}
+			result = result.Or(v)
+			if result.True() {
+				return cty.True, nil
+			}
+		}
+		if hasUnknown {
+			return cty.UnknownVal(cty.Bool), nil
+		}
+		return result, nil
+	},
+})
+
+// CoalesceFunc constructs a function that takes any number of arguments and
+// returns the first one that isn't empty. This function was copied from go-cty
+// stdlib and modified so that it returns the first *non-empty* non-null element
+// from a sequence, instead of merely the first non-null.
+var CoalesceFunc = function.New(&function.Spec{
+	Params: []function.Parameter{},
+	VarParam: &function.Parameter{
+		Name:             "vals",
+		Type:             cty.DynamicPseudoType,
+		AllowUnknown:     true,
+		AllowDynamicType: true,
+		AllowNull:        true,
+	},
+	Type: func(args []cty.Value) (ret cty.Type, err error) {
+		argTypes := make([]cty.Type, len(args))
+		for i, val := range args {
+			argTypes[i] = val.Type()
+		}
+		retType, _ := convert.UnifyUnsafe(argTypes)
+		if retType == cty.NilType {
+			return cty.NilType, errors.New("all arguments must have the same type")
+		}
+		return retType, nil
+	},
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		for _, argVal := range args {
+			// We already know this will succeed because of the checks in our Type func above
+			argVal, _ = convert.Convert(argVal, retType)
+			if !argVal.IsKnown() {
+				return cty.UnknownVal(retType), nil
+			}
+			if argVal.IsNull() {
+				continue
+			}
+			if retType == cty.String && argVal.RawEquals(cty.StringVal("")) {
+				continue
+			}
+
+			return argVal, nil
+		}
+		return cty.NilVal, errors.New("no non-null, non-empty-string arguments")
+	},
+})
+
+// IndexFunc constructs a function that finds the element index for a given value in a list.
+var IndexFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "list",
+			Type: cty.DynamicPseudoType,
+		},
+		{
+			Name: "value",
+			Type: cty.DynamicPseudoType,
+		},
+	},
+	Type: function.StaticReturnType(cty.Number),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		if !(args[0].Type().IsListType() || args[0].Type().IsTupleType()) {
+			return cty.NilVal, errors.New("argument must be a list or tuple")
+		}
+
+		if !args[0].IsKnown() {
+			return cty.UnknownVal(cty.Number), nil
+		}
+
+		if args[0].LengthInt() == 0 { // Easy path
+			return cty.NilVal, errors.New("cannot search an empty list")
+		}
+
+		for it := args[0].ElementIterator(); it.Next(); {
+			i, v := it.Element()
+			eq, err := stdlib.Equal(v, args[1])
+			if err != nil {
+				return cty.NilVal, err
+			}
+			if !eq.IsKnown() {
+				return cty.UnknownVal(cty.Number), nil
+			}
+			if eq.True() {
+				return i, nil
+			}
+		}
+		return cty.NilVal, errors.New("item not found")
+
+	},
+})
+
+// LookupFunc constructs a function that performs dynamic lookups of map types.
+var LookupFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name:        "inputMap",
+			Type:        cty.DynamicPseudoType,
+			AllowMarked: true,
+		},
+		{
+			Name:        "key",
+			Type:        cty.String,
+			AllowMarked: true,
+		},
+	},
+	VarParam: &function.Parameter{
+		Name:             "default",
+		Type:             cty.DynamicPseudoType,
+		AllowUnknown:     true,
+		AllowDynamicType: true,
+		AllowNull:        true,
+		AllowMarked:      true,
+	},
+	Type: func(args []cty.Value) (ret cty.Type, err error) {
+		if len(args) < 1 || len(args) > 3 {
+			return cty.NilType, fmt.Errorf("lookup() takes two or three arguments, got %d", len(args))
+		}
+
+		ty := args[0].Type()
+
+		switch {
+		case ty.IsObjectType():
+			if !args[1].IsKnown() {
+				return cty.DynamicPseudoType, nil
+			}
+
+			keyVal, _ := args[1].Unmark()
+			key := keyVal.AsString()
+			if ty.HasAttribute(key) {
+				return args[0].GetAttr(key).Type(), nil
+			} else if len(args) == 3 {
+				// if the key isn't found but a default is provided,
+				// return the default type
+				return args[2].Type(), nil
+			}
+			return cty.DynamicPseudoType, function.NewArgErrorf(0, "the given object has no attribute %q", key)
+		case ty.IsMapType():
+			if len(args) == 3 {
+				_, err = convert.Convert(args[2], ty.ElementType())
+				if err != nil {
+					return cty.NilType, function.NewArgErrorf(2, "the default value must have the same type as the map elements")
+				}
+			}
+			return ty.ElementType(), nil
+		default:
+			return cty.NilType, function.NewArgErrorf(0, "lookup() requires a map as the first argument")
+		}
+	},
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		var defaultVal cty.Value
+		defaultValueSet := false
+
+		if len(args) == 3 {
+			// intentionally leave default value marked
+			defaultVal = args[2]
+			defaultValueSet = true
+		}
+
+		// keep track of marks from the collection and key
+		var markses []cty.ValueMarks
+
+		// unmark collection, retain marks to reapply later
+		mapVar, mapMarks := args[0].Unmark()
+		markses = append(markses, mapMarks)
+
+		// include marks on the key in the result
+		keyVal, keyMarks := args[1].Unmark()
+		if len(keyMarks) > 0 {
+			markses = append(markses, keyMarks)
+		}
+		lookupKey := keyVal.AsString()
+
+		if !mapVar.IsKnown() {
+			return cty.UnknownVal(retType).WithMarks(markses...), nil
+		}
+
+		if mapVar.Type().IsObjectType() {
+			if mapVar.Type().HasAttribute(lookupKey) {
+				return mapVar.GetAttr(lookupKey).WithMarks(markses...), nil
+			}
+		} else if mapVar.HasIndex(cty.StringVal(lookupKey)) == cty.True {
+			return mapVar.Index(cty.StringVal(lookupKey)).WithMarks(markses...), nil
+		}
+
+		if defaultValueSet {
+			defaultVal, err = convert.Convert(defaultVal, retType)
+			if err != nil {
+				return cty.NilVal, err
+			}
+			return defaultVal.WithMarks(markses...), nil
+		}
+
+		return cty.UnknownVal(cty.DynamicPseudoType), fmt.Errorf(
+			"lookup failed to find key %s", redactIfSensitive(lookupKey, keyMarks))
+	},
+})
+
+// MatchkeysFunc constructs a function that constructs a new list by taking a
+// subset of elements from one list whose indexes match the corresponding
+// indexes of values in another list.
+var MatchkeysFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "values",
+			Type: cty.List(cty.DynamicPseudoType),
+		},
+		{
+			Name: "keys",
+			Type: cty.List(cty.DynamicPseudoType),
+		},
+		{
+			Name: "searchset",
+			Type: cty.List(cty.DynamicPseudoType),
+		},
+	},
+	Type: func(args []cty.Value) (cty.Type, error) {
+		ty, _ := convert.UnifyUnsafe([]cty.Type{args[1].Type(), args[2].Type()})
+		if ty == cty.NilType {
+			return cty.NilType, errors.New("keys and searchset must be of the same type")
+		}
+
+		// the return type is based on args[0] (values)
+		return args[0].Type(), nil
+	},
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		if !args[0].IsKnown() {
+			return cty.UnknownVal(cty.List(retType.ElementType())), nil
+		}
+
+		if args[0].LengthInt() != args[1].LengthInt() {
+			return cty.ListValEmpty(retType.ElementType()), errors.New("length of keys and values should be equal")
+		}
+
+		output := make([]cty.Value, 0)
+		values := args[0]
+
+		// Keys and searchset must be the same type.
+		// We can skip error checking here because we've already verified that
+		// they can be unified in the Type function
+		ty, _ := convert.UnifyUnsafe([]cty.Type{args[1].Type(), args[2].Type()})
+		keys, _ := convert.Convert(args[1], ty)
+		searchset, _ := convert.Convert(args[2], ty)
+
+		// if searchset is empty, return an empty list.
+		if searchset.LengthInt() == 0 {
+			return cty.ListValEmpty(retType.ElementType()), nil
+		}
+
+		if !values.IsWhollyKnown() || !keys.IsWhollyKnown() {
+			return cty.UnknownVal(retType), nil
+		}
+
+		i := 0
+		for it := keys.ElementIterator(); it.Next(); {
+			_, key := it.Element()
+			for iter := searchset.ElementIterator(); iter.Next(); {
+				_, search := iter.Element()
+				eq, err := stdlib.Equal(key, search)
+				if err != nil {
+					return cty.NilVal, err
+				}
+				if !eq.IsKnown() {
+					return cty.ListValEmpty(retType.ElementType()), nil
+				}
+				if eq.True() {
+					v := values.Index(cty.NumberIntVal(int64(i)))
+					output = append(output, v)
+					break
+				}
+			}
+			i++
+		}
+
+		// if we haven't matched any key, then output is an empty list.
+		if len(output) == 0 {
+			return cty.ListValEmpty(retType.ElementType()), nil
+		}
+		return cty.ListVal(output), nil
+	},
+})
+
+// OneFunc returns either the first element of a one-element list, or null
+// if given a zero-element list.
+var OneFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "list",
+			Type: cty.DynamicPseudoType,
+		},
+	},
+	Type: func(args []cty.Value) (cty.Type, error) {
+		ty := args[0].Type()
+		switch {
+		case ty.IsListType() || ty.IsSetType():
+			return ty.ElementType(), nil
+		case ty.IsTupleType():
+			etys := ty.TupleElementTypes()
+			switch len(etys) {
+			case 0:
+				// No specific type information, so we'll ultimately return
+				// a null value of unknown type.
+				return cty.DynamicPseudoType, nil
+			case 1:
+				return etys[0], nil
+			}
+		}
+		return cty.NilType, function.NewArgErrorf(0, "must be a list, set, or tuple value with either zero or one elements")
+	},
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		val := args[0]
+		ty := val.Type()
+
+		// Our parameter spec above doesn't set AllowUnknown or AllowNull,
+		// so we can assume our top-level collection is both known and non-null
+		// in here.
+
+		switch {
+		case ty.IsListType() || ty.IsSetType():
+			lenVal := val.Length()
+			if !lenVal.IsKnown() {
+				return cty.UnknownVal(retType), nil
+			}
+			var l int
+			err := gocty.FromCtyValue(lenVal, &l)
+			if err != nil {
+				// It would be very strange to get here, because that would
+				// suggest that the length is either not a number or isn't
+				// an integer, which would suggest a bug in cty.
+				return cty.NilVal, fmt.Errorf("invalid collection length: %s", err)
+			}
+			switch l {
+			case 0:
+				return cty.NullVal(retType), nil
+			case 1:
+				var ret cty.Value
+				// We'll use an iterator here because that works for both lists
+				// and sets, whereas indexing directly would only work for lists.
+				// Since we've just checked the length, we should only actually
+				// run this loop body once.
+				for it := val.ElementIterator(); it.Next(); {
+					_, ret = it.Element()
+				}
+				return ret, nil
+			}
+		case ty.IsTupleType():
+			etys := ty.TupleElementTypes()
+			switch len(etys) {
+			case 0:
+				return cty.NullVal(retType), nil
+			case 1:
+				ret := val.Index(cty.NumberIntVal(0))
+				return ret, nil
+			}
+		}
+		return cty.NilVal, function.NewArgErrorf(0, "must be a list, set, or tuple value with either zero or one elements")
+	},
+})
+
+// SumFunc constructs a function that returns the sum of all
+// numbers provided in a list
+var SumFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "list",
+			Type: cty.DynamicPseudoType,
+		},
+	},
+	Type: function.StaticReturnType(cty.Number),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+
+		if !args[0].CanIterateElements() {
+			return cty.NilVal, function.NewArgErrorf(0, "cannot sum noniterable")
+		}
+
+		if args[0].LengthInt() == 0 { // Easy path
+			return cty.NilVal, function.NewArgErrorf(0, "cannot sum an empty list")
+		}
+
+		arg := args[0].AsValueSlice()
+		ty := args[0].Type()
+
+		if !ty.IsListType() && !ty.IsSetType() && !ty.IsTupleType() {
+			return cty.NilVal, function.NewArgErrorf(0, fmt.Sprintf("argument must be list, set, or tuple. Received %s", ty.FriendlyName()))
+		}
+
+		if !args[0].IsWhollyKnown() {
+			return cty.UnknownVal(cty.Number), nil
+		}
+
+		// big.Float.Add can panic if the input values are opposing infinities,
+		// so we must catch that here in order to remain within
+		// the cty Function abstraction.
+		defer func() {
+			if r := recover(); r != nil {
+				if _, ok := r.(big.ErrNaN); ok {
+					ret = cty.NilVal
+					err = fmt.Errorf("can't compute sum of opposing infinities")
+				} else {
+					// not a panic we recognize
+					panic(r)
+				}
+			}
+		}()
+
+		s := arg[0]
+		if s.IsNull() {
+			return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values")
+		}
+		s, err = convert.Convert(s, cty.Number)
+		if err != nil {
+			return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values")
+		}
+		for _, v := range arg[1:] {
+			if v.IsNull() {
+				return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values")
+			}
+			v, err = convert.Convert(v, cty.Number)
+			if err != nil {
+				return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values")
+			}
+			s = s.Add(v)
+		}
+
+		return s, nil
+	},
+})
+
+// TransposeFunc constructs a function that takes a map of lists of strings and
+// swaps the keys and values to produce a new map of lists of strings.
+var TransposeFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "values",
+			Type: cty.Map(cty.List(cty.String)),
+		},
+	},
+	Type: function.StaticReturnType(cty.Map(cty.List(cty.String))),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		inputMap := args[0]
+		if !inputMap.IsWhollyKnown() {
+			return cty.UnknownVal(retType), nil
+		}
+
+		outputMap := make(map[string]cty.Value)
+		tmpMap := make(map[string][]string)
+
+		for it := inputMap.ElementIterator(); it.Next(); {
+			inKey, inVal := it.Element()
+			for iter := inVal.ElementIterator(); iter.Next(); {
+				_, val := iter.Element()
+				if !val.Type().Equals(cty.String) {
+					return cty.MapValEmpty(cty.List(cty.String)), errors.New("input must be a map of lists of strings")
+				}
+
+				outKey := val.AsString()
+				if _, ok := tmpMap[outKey]; !ok {
+					tmpMap[outKey] = make([]string, 0)
+				}
+				outVal := tmpMap[outKey]
+				outVal = append(outVal, inKey.AsString())
+				sort.Strings(outVal)
+				tmpMap[outKey] = outVal
+			}
+		}
+
+		for outKey, outVal := range tmpMap {
+			values := make([]cty.Value, 0)
+			for _, v := range outVal {
+				values = append(values, cty.StringVal(v))
+			}
+			outputMap[outKey] = cty.ListVal(values)
+		}
+
+		if len(outputMap) == 0 {
+			return cty.MapValEmpty(cty.List(cty.String)), nil
+		}
+
+		return cty.MapVal(outputMap), nil
+	},
+})
+
+// ListFunc constructs a function that takes an arbitrary number of arguments
+// and returns a list containing those values in the same order.
+//
+// This function is deprecated in Terraform v0.12
+var ListFunc = function.New(&function.Spec{
+	Params: []function.Parameter{},
+	VarParam: &function.Parameter{
+		Name:             "vals",
+		Type:             cty.DynamicPseudoType,
+		AllowUnknown:     true,
+		AllowDynamicType: true,
+		AllowNull:        true,
+	},
+	Type: func(args []cty.Value) (ret cty.Type, err error) {
+		return cty.DynamicPseudoType, fmt.Errorf("the \"list\" function was deprecated in Terraform v0.12 and is no longer available; use tolist([ ... ]) syntax to write a literal list")
+	},
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		return cty.DynamicVal, fmt.Errorf("the \"list\" function was deprecated in Terraform v0.12 and is no longer available; use tolist([ ... ]) syntax to write a literal list")
+	},
+})
+
+// MapFunc constructs a function that takes an even number of arguments and
+// returns a map whose elements are constructed from consecutive pairs of arguments.
+//
+// This function is deprecated in Terraform v0.12
+var MapFunc = function.New(&function.Spec{
+	Params: []function.Parameter{},
+	VarParam: &function.Parameter{
+		Name:             "vals",
+		Type:             cty.DynamicPseudoType,
+		AllowUnknown:     true,
+		AllowDynamicType: true,
+		AllowNull:        true,
+	},
+	Type: func(args []cty.Value) (ret cty.Type, err error) {
+		return cty.DynamicPseudoType, fmt.Errorf("the \"map\" function was deprecated in Terraform v0.12 and is no longer available; use tomap({ ... }) syntax to write a literal map")
+	},
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		return cty.DynamicVal, fmt.Errorf("the \"map\" function was deprecated in Terraform v0.12 and is no longer available; use tomap({ ... }) syntax to write a literal map")
+	},
+})
+
+// Length returns the number of elements in the given collection or number of
+// Unicode characters in the given string.
+func Length(collection cty.Value) (cty.Value, error) {
+	return LengthFunc.Call([]cty.Value{collection})
+}
+
+// AllTrue returns true if all elements of the list are true. If the list is empty,
+// return true.
+func AllTrue(collection cty.Value) (cty.Value, error) {
+	return AllTrueFunc.Call([]cty.Value{collection})
+}
+
+// AnyTrue returns true if any element of the list is true. If the list is empty,
+// return false.
+func AnyTrue(collection cty.Value) (cty.Value, error) {
+	return AnyTrueFunc.Call([]cty.Value{collection})
+}
+
+// Coalesce takes any number of arguments and returns the first one that isn't empty.
+func Coalesce(args ...cty.Value) (cty.Value, error) {
+	return CoalesceFunc.Call(args)
+}
+
+// Index finds the element index for a given value in a list.
+func Index(list, value cty.Value) (cty.Value, error) {
+	return IndexFunc.Call([]cty.Value{list, value})
+}
+
+// List takes any number of arguments of types that can unify into a single
+// type and returns a list containing those values in the same order, or
+// returns an error if there is no single element type that all values can
+// convert to.
+func List(args ...cty.Value) (cty.Value, error) {
+	return ListFunc.Call(args)
+}
+
+// Lookup performs a dynamic lookup into a map.
+// There are two required arguments, map and key, plus an optional default,
+// which is a value to return if no key is found in map.
+func Lookup(args ...cty.Value) (cty.Value, error) {
+	return LookupFunc.Call(args)
+}
+
+// Map takes an even number of arguments and returns a map whose elements are constructed
+// from consecutive pairs of arguments.
+func Map(args ...cty.Value) (cty.Value, error) {
+	return MapFunc.Call(args)
+}
+
+// Matchkeys constructs a new list by taking a subset of elements from one list
+// whose indexes match the corresponding indexes of values in another list.
+func Matchkeys(values, keys, searchset cty.Value) (cty.Value, error) {
+	return MatchkeysFunc.Call([]cty.Value{values, keys, searchset})
+}
+
+// One returns either the first element of a one-element list, or null
+// if given a zero-element list..
+func One(list cty.Value) (cty.Value, error) {
+	return OneFunc.Call([]cty.Value{list})
+}
+
+// Sum adds numbers in a list, set, or tuple
+func Sum(list cty.Value) (cty.Value, error) {
+	return SumFunc.Call([]cty.Value{list})
+}
+
+// Transpose takes a map of lists of strings and swaps the keys and values to
+// produce a new map of lists of strings.
+func Transpose(values cty.Value) (cty.Value, error) {
+	return TransposeFunc.Call([]cty.Value{values})
+}
diff --git a/v1.5.7/internal/lang/funcs/collection_test.go b/v1.5.7/internal/lang/funcs/collection_test.go
new file mode 100644
index 0000000..d045941
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/collection_test.go
@@ -0,0 +1,1840 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"fmt"
+	"math"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestLength(t *testing.T) {
+	tests := []struct {
+		Value cty.Value
+		Want  cty.Value
+	}{
+		{
+			cty.ListValEmpty(cty.Number),
+			cty.NumberIntVal(0),
+		},
+		{
+			cty.ListVal([]cty.Value{cty.True}),
+			cty.NumberIntVal(1),
+		},
+		{
+			cty.ListVal([]cty.Value{cty.UnknownVal(cty.Bool)}),
+			cty.NumberIntVal(1),
+		},
+		{
+			cty.SetValEmpty(cty.Number),
+			cty.NumberIntVal(0),
+		},
+		{
+			cty.SetVal([]cty.Value{cty.True}),
+			cty.NumberIntVal(1),
+		},
+		{
+			cty.MapValEmpty(cty.Bool),
+			cty.NumberIntVal(0),
+		},
+		{
+			cty.MapVal(map[string]cty.Value{"hello": cty.True}),
+			cty.NumberIntVal(1),
+		},
+		{
+			cty.EmptyTupleVal,
+			cty.NumberIntVal(0),
+		},
+		{
+			cty.UnknownVal(cty.EmptyTuple),
+			cty.NumberIntVal(0),
+		},
+		{
+			cty.TupleVal([]cty.Value{cty.True}),
+			cty.NumberIntVal(1),
+		},
+		{
+			cty.EmptyObjectVal,
+			cty.NumberIntVal(0),
+		},
+		{
+			cty.UnknownVal(cty.EmptyObject),
+			cty.NumberIntVal(0),
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{"true": cty.True}),
+			cty.NumberIntVal(1),
+		},
+		{
+			cty.UnknownVal(cty.List(cty.Bool)),
+			cty.UnknownVal(cty.Number),
+		},
+		{
+			cty.DynamicVal,
+			cty.UnknownVal(cty.Number),
+		},
+		{
+			cty.StringVal("hello"),
+			cty.NumberIntVal(5),
+		},
+		{
+			cty.StringVal(""),
+			cty.NumberIntVal(0),
+		},
+		{
+			cty.StringVal("1"),
+			cty.NumberIntVal(1),
+		},
+		{
+			cty.StringVal("Живой Журнал"),
+			cty.NumberIntVal(12),
+		},
+		{
+			// note that the dieresis here is intentionally a combining
+			// ligature.
+			cty.StringVal("noël"),
+			cty.NumberIntVal(4),
+		},
+		{
+			// The Es in this string has three combining acute accents.
+			// This tests something that NFC-normalization cannot collapse
+			// into a single precombined codepoint, since otherwise we might
+			// be cheating and relying on the single-codepoint forms.
+			cty.StringVal("wé́́é́́é́́!"),
+			cty.NumberIntVal(5),
+		},
+		{
+			// Go's normalization forms don't handle this ligature, so we
+			// will produce the wrong result but this is now a compatibility
+			// constraint and so we'll test it.
+			cty.StringVal("baffle"),
+			cty.NumberIntVal(4),
+		},
+		{
+			cty.StringVal("😸😾"),
+			cty.NumberIntVal(2),
+		},
+		{
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.Number),
+		},
+		{
+			cty.DynamicVal,
+			cty.UnknownVal(cty.Number),
+		},
+		{ // Marked collections return a marked length
+			cty.ListVal([]cty.Value{
+				cty.StringVal("hello"),
+				cty.StringVal("world"),
+			}).Mark("secret"),
+			cty.NumberIntVal(2).Mark("secret"),
+		},
+		{ // Marks on values in unmarked collections do not propagate
+			cty.ListVal([]cty.Value{
+				cty.StringVal("hello").Mark("a"),
+				cty.StringVal("world").Mark("b"),
+			}),
+			cty.NumberIntVal(2),
+		},
+		{ // Marked strings return a marked length
+			cty.StringVal("hello world").Mark("secret"),
+			cty.NumberIntVal(11).Mark("secret"),
+		},
+		{ // Marked tuples return a marked length
+			cty.TupleVal([]cty.Value{
+				cty.StringVal("hello"),
+				cty.StringVal("world"),
+			}).Mark("secret"),
+			cty.NumberIntVal(2).Mark("secret"),
+		},
+		{ // Marks on values in unmarked tuples do not propagate
+			cty.TupleVal([]cty.Value{
+				cty.StringVal("hello").Mark("a"),
+				cty.StringVal("world").Mark("b"),
+			}),
+			cty.NumberIntVal(2),
+		},
+		{ // Marked objects return a marked length
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("hello"),
+				"b": cty.StringVal("world"),
+				"c": cty.StringVal("nice to meet you"),
+			}).Mark("secret"),
+			cty.NumberIntVal(3).Mark("secret"),
+		},
+		{ // Marks on object attribute values do not propagate
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("hello").Mark("a"),
+				"b": cty.StringVal("world").Mark("b"),
+				"c": cty.StringVal("nice to meet you").Mark("c"),
+			}),
+			cty.NumberIntVal(3),
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("Length(%#v)", test.Value), func(t *testing.T) {
+			got, err := Length(test.Value)
+
+			if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestAllTrue(t *testing.T) {
+	tests := []struct {
+		Collection cty.Value
+		Want       cty.Value
+		Err        bool
+	}{
+		{
+			cty.ListValEmpty(cty.Bool),
+			cty.True,
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.True}),
+			cty.True,
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.False}),
+			cty.False,
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.True, cty.False}),
+			cty.False,
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.False, cty.True}),
+			cty.False,
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.True, cty.NullVal(cty.Bool)}),
+			cty.False,
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.UnknownVal(cty.Bool)}),
+			cty.UnknownVal(cty.Bool),
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.UnknownVal(cty.Bool),
+				cty.UnknownVal(cty.Bool),
+			}),
+			cty.UnknownVal(cty.Bool),
+			false,
+		},
+		{
+			cty.UnknownVal(cty.List(cty.Bool)),
+			cty.UnknownVal(cty.Bool),
+			false,
+		},
+		{
+			cty.NullVal(cty.List(cty.Bool)),
+			cty.NilVal,
+			true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("alltrue(%#v)", test.Collection), func(t *testing.T) {
+			got, err := AllTrue(test.Collection)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestAnyTrue(t *testing.T) {
+	tests := []struct {
+		Collection cty.Value
+		Want       cty.Value
+		Err        bool
+	}{
+		{
+			cty.ListValEmpty(cty.Bool),
+			cty.False,
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.True}),
+			cty.True,
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.False}),
+			cty.False,
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.True, cty.False}),
+			cty.True,
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.False, cty.True}),
+			cty.True,
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.NullVal(cty.Bool), cty.True}),
+			cty.True,
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.UnknownVal(cty.Bool)}),
+			cty.UnknownVal(cty.Bool),
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.UnknownVal(cty.Bool),
+				cty.False,
+			}),
+			cty.UnknownVal(cty.Bool),
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.UnknownVal(cty.Bool),
+				cty.True,
+			}),
+			cty.True,
+			false,
+		},
+		{
+			cty.UnknownVal(cty.List(cty.Bool)),
+			cty.UnknownVal(cty.Bool),
+			false,
+		},
+		{
+			cty.NullVal(cty.List(cty.Bool)),
+			cty.NilVal,
+			true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("anytrue(%#v)", test.Collection), func(t *testing.T) {
+			got, err := AnyTrue(test.Collection)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestCoalesce(t *testing.T) {
+	tests := []struct {
+		Values []cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		{
+			[]cty.Value{cty.StringVal("first"), cty.StringVal("second"), cty.StringVal("third")},
+			cty.StringVal("first"),
+			false,
+		},
+		{
+			[]cty.Value{cty.StringVal(""), cty.StringVal("second"), cty.StringVal("third")},
+			cty.StringVal("second"),
+			false,
+		},
+		{
+			[]cty.Value{cty.StringVal(""), cty.StringVal("")},
+			cty.NilVal,
+			true,
+		},
+		{
+			[]cty.Value{cty.True},
+			cty.True,
+			false,
+		},
+		{
+			[]cty.Value{cty.NullVal(cty.Bool), cty.True},
+			cty.True,
+			false,
+		},
+		{
+			[]cty.Value{cty.NullVal(cty.Bool), cty.False},
+			cty.False,
+			false,
+		},
+		{
+			[]cty.Value{cty.NullVal(cty.Bool), cty.False, cty.StringVal("hello")},
+			cty.StringVal("false"),
+			false,
+		},
+		{
+			[]cty.Value{cty.True, cty.UnknownVal(cty.Bool)},
+			cty.True,
+			false,
+		},
+		{
+			[]cty.Value{cty.UnknownVal(cty.Bool), cty.True},
+			cty.UnknownVal(cty.Bool),
+			false,
+		},
+		{
+			[]cty.Value{cty.UnknownVal(cty.Bool), cty.StringVal("hello")},
+			cty.UnknownVal(cty.String),
+			false,
+		},
+		{
+			[]cty.Value{cty.DynamicVal, cty.True},
+			cty.UnknownVal(cty.Bool),
+			false,
+		},
+		{
+			[]cty.Value{cty.DynamicVal},
+			cty.DynamicVal,
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("Coalesce(%#v...)", test.Values), func(t *testing.T) {
+			got, err := Coalesce(test.Values...)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestIndex(t *testing.T) {
+	tests := []struct {
+		List  cty.Value
+		Value cty.Value
+		Want  cty.Value
+		Err   bool
+	}{
+		{
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+				cty.StringVal("b"),
+				cty.StringVal("c"),
+			}),
+			cty.StringVal("a"),
+			cty.NumberIntVal(0),
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+				cty.StringVal("b"),
+				cty.UnknownVal(cty.String),
+			}),
+			cty.StringVal("a"),
+			cty.NumberIntVal(0),
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+				cty.StringVal("b"),
+				cty.StringVal("c"),
+			}),
+			cty.StringVal("b"),
+			cty.NumberIntVal(1),
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+				cty.StringVal("b"),
+				cty.StringVal("c"),
+			}),
+			cty.StringVal("z"),
+			cty.NilVal,
+			true,
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.StringVal("1"),
+				cty.StringVal("2"),
+				cty.StringVal("3"),
+			}),
+			cty.NumberIntVal(1),
+			cty.NumberIntVal(0),
+			true,
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.NumberIntVal(1),
+				cty.NumberIntVal(2),
+				cty.NumberIntVal(3),
+			}),
+			cty.NumberIntVal(2),
+			cty.NumberIntVal(1),
+			false,
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.NumberIntVal(1),
+				cty.NumberIntVal(2),
+				cty.NumberIntVal(3),
+			}),
+			cty.NumberIntVal(4),
+			cty.NilVal,
+			true,
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.NumberIntVal(1),
+				cty.NumberIntVal(2),
+				cty.NumberIntVal(3),
+			}),
+			cty.StringVal("1"),
+			cty.NumberIntVal(0),
+			true,
+		},
+		{
+			cty.TupleVal([]cty.Value{
+				cty.NumberIntVal(1),
+				cty.NumberIntVal(2),
+				cty.NumberIntVal(3),
+			}),
+			cty.NumberIntVal(1),
+			cty.NumberIntVal(0),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("index(%#v, %#v)", test.List, test.Value), func(t *testing.T) {
+			got, err := Index(test.List, test.Value)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestLookup(t *testing.T) {
+	simpleMap := cty.MapVal(map[string]cty.Value{
+		"foo": cty.StringVal("bar"),
+	})
+	intsMap := cty.MapVal(map[string]cty.Value{
+		"foo": cty.NumberIntVal(42),
+	})
+	mapOfLists := cty.MapVal(map[string]cty.Value{
+		"foo": cty.ListVal([]cty.Value{
+			cty.StringVal("bar"),
+			cty.StringVal("baz"),
+		}),
+	})
+	mapOfMaps := cty.MapVal(map[string]cty.Value{
+		"foo": cty.MapVal(map[string]cty.Value{
+			"a": cty.StringVal("bar"),
+		}),
+		"baz": cty.MapVal(map[string]cty.Value{
+			"b": cty.StringVal("bat"),
+		}),
+	})
+	mapOfTuples := cty.MapVal(map[string]cty.Value{
+		"foo": cty.TupleVal([]cty.Value{cty.StringVal("bar")}),
+		"baz": cty.TupleVal([]cty.Value{cty.StringVal("bat")}),
+	})
+	objectOfMaps := cty.ObjectVal(map[string]cty.Value{
+		"foo": cty.MapVal(map[string]cty.Value{
+			"a": cty.StringVal("bar"),
+		}),
+		"baz": cty.MapVal(map[string]cty.Value{
+			"b": cty.StringVal("bat"),
+		}),
+	})
+	mapWithUnknowns := cty.MapVal(map[string]cty.Value{
+		"foo": cty.StringVal("bar"),
+		"baz": cty.UnknownVal(cty.String),
+	})
+	mapWithObjects := cty.ObjectVal(map[string]cty.Value{
+		"foo": cty.StringVal("bar"),
+		"baz": cty.NumberIntVal(42),
+	})
+
+	tests := []struct {
+		Values []cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		{
+			[]cty.Value{
+				simpleMap,
+				cty.StringVal("foo"),
+			},
+			cty.StringVal("bar"),
+			false,
+		},
+		{
+			[]cty.Value{
+				mapWithObjects,
+				cty.StringVal("foo"),
+			},
+			cty.StringVal("bar"),
+			false,
+		},
+		{
+			[]cty.Value{
+				intsMap,
+				cty.StringVal("foo"),
+			},
+			cty.NumberIntVal(42),
+			false,
+		},
+		{
+			[]cty.Value{
+				mapOfMaps,
+				cty.StringVal("foo"),
+			},
+			cty.MapVal(map[string]cty.Value{
+				"a": cty.StringVal("bar"),
+			}),
+			false,
+		},
+		{
+			[]cty.Value{
+				objectOfMaps,
+				cty.StringVal("foo"),
+			},
+			cty.MapVal(map[string]cty.Value{
+				"a": cty.StringVal("bar"),
+			}),
+			false,
+		},
+		{
+			[]cty.Value{
+				mapOfTuples,
+				cty.StringVal("foo"),
+			},
+			cty.TupleVal([]cty.Value{cty.StringVal("bar")}),
+			false,
+		},
+		{ // Invalid key
+			[]cty.Value{
+				simpleMap,
+				cty.StringVal("bar"),
+			},
+			cty.NilVal,
+			true,
+		},
+		{ // Invalid key
+			[]cty.Value{
+				mapWithObjects,
+				cty.StringVal("bar"),
+			},
+			cty.NilVal,
+			true,
+		},
+		{ // Supplied default with valid key
+			[]cty.Value{
+				simpleMap,
+				cty.StringVal("foo"),
+				cty.StringVal(""),
+			},
+			cty.StringVal("bar"),
+			false,
+		},
+		{ // Supplied default with valid (int) key
+			[]cty.Value{
+				simpleMap,
+				cty.StringVal("foo"),
+				cty.NumberIntVal(-1),
+			},
+			cty.StringVal("bar"),
+			false,
+		},
+		{ // Supplied default with valid (int) key
+			[]cty.Value{
+				simpleMap,
+				cty.StringVal("foobar"),
+				cty.NumberIntVal(-1),
+			},
+			cty.StringVal("-1"),
+			false,
+		},
+		{ // Supplied default with valid key
+			[]cty.Value{
+				mapWithObjects,
+				cty.StringVal("foobar"),
+				cty.StringVal(""),
+			},
+			cty.StringVal(""),
+			false,
+		},
+		{ // Supplied default with invalid key
+			[]cty.Value{
+				simpleMap,
+				cty.StringVal("baz"),
+				cty.StringVal(""),
+			},
+			cty.StringVal(""),
+			false,
+		},
+		{ // Supplied default with type mismatch: expects a map return
+			[]cty.Value{
+				mapOfMaps,
+				cty.StringVal("foo"),
+				cty.StringVal(""),
+			},
+			cty.NilVal,
+			true,
+		},
+		{ // Supplied non-empty default with invalid key
+			[]cty.Value{
+				simpleMap,
+				cty.StringVal("bar"),
+				cty.StringVal("xyz"),
+			},
+			cty.StringVal("xyz"),
+			false,
+		},
+		{ // too many args
+			[]cty.Value{
+				simpleMap,
+				cty.StringVal("foo"),
+				cty.StringVal("bar"),
+				cty.StringVal("baz"),
+			},
+			cty.NilVal,
+			true,
+		},
+		{ // cannot search a map of lists
+			[]cty.Value{
+				mapOfLists,
+				cty.StringVal("baz"),
+			},
+			cty.NilVal,
+			true,
+		},
+		{
+			[]cty.Value{
+				mapWithUnknowns,
+				cty.StringVal("baz"),
+			},
+			cty.UnknownVal(cty.String),
+			false,
+		},
+		{
+			[]cty.Value{
+				mapWithUnknowns,
+				cty.StringVal("foo"),
+			},
+			cty.StringVal("bar"),
+			false,
+		},
+		{
+			[]cty.Value{
+				simpleMap,
+				cty.UnknownVal(cty.String),
+			},
+			cty.UnknownVal(cty.String),
+			false,
+		},
+		{
+			[]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("a"),
+					"bar": cty.StringVal("b"),
+				}),
+				cty.UnknownVal(cty.String),
+			},
+			cty.DynamicVal, // if the key is unknown then we don't know which object attribute and thus can't know the type
+			false,
+		},
+		{ // successful marked collection lookup returns marked value
+			[]cty.Value{
+				cty.MapVal(map[string]cty.Value{
+					"boop": cty.StringVal("beep"),
+				}).Mark("a"),
+				cty.StringVal("boop"),
+				cty.StringVal("nope"),
+			},
+			cty.StringVal("beep").Mark("a"),
+			false,
+		},
+		{ // apply collection marks to unknown return vaue
+			[]cty.Value{
+				cty.MapVal(map[string]cty.Value{
+					"boop": cty.StringVal("beep"),
+					"frob": cty.UnknownVal(cty.String),
+				}).Mark("a"),
+				cty.StringVal("frob"),
+				cty.StringVal("nope"),
+			},
+			cty.UnknownVal(cty.String).Mark("a"),
+			false,
+		},
+		{ // propagate collection marks to default when returning
+			[]cty.Value{
+				cty.MapVal(map[string]cty.Value{
+					"boop": cty.StringVal("beep"),
+				}).Mark("a"),
+				cty.StringVal("frob"),
+				cty.StringVal("nope").Mark("b"),
+			},
+			cty.StringVal("nope").WithMarks(cty.NewValueMarks("a", "b")),
+			false,
+		},
+		{ // on unmarked collection, return only marks from found value
+			[]cty.Value{
+				cty.MapVal(map[string]cty.Value{
+					"boop": cty.StringVal("beep").Mark("a"),
+					"frob": cty.StringVal("honk").Mark("b"),
+				}),
+				cty.StringVal("frob"),
+				cty.StringVal("nope").Mark("c"),
+			},
+			cty.StringVal("honk").Mark("b"),
+			false,
+		},
+		{ // on unmarked collection, return default exactly on missing
+			[]cty.Value{
+				cty.MapVal(map[string]cty.Value{
+					"boop": cty.StringVal("beep").Mark("a"),
+					"frob": cty.StringVal("honk").Mark("b"),
+				}),
+				cty.StringVal("squish"),
+				cty.StringVal("nope").Mark("c"),
+			},
+			cty.StringVal("nope").Mark("c"),
+			false,
+		},
+		{ // retain marks on default if converted
+			[]cty.Value{
+				cty.MapVal(map[string]cty.Value{
+					"boop": cty.StringVal("beep").Mark("a"),
+					"frob": cty.StringVal("honk").Mark("b"),
+				}),
+				cty.StringVal("squish"),
+				cty.NumberIntVal(5).Mark("c"),
+			},
+			cty.StringVal("5").Mark("c"),
+			false,
+		},
+		{ // propagate marks from key
+			[]cty.Value{
+				cty.MapVal(map[string]cty.Value{
+					"boop": cty.StringVal("beep"),
+					"frob": cty.StringVal("honk"),
+				}),
+				cty.StringVal("boop").Mark("a"),
+				cty.StringVal("nope"),
+			},
+			cty.StringVal("beep").Mark("a"),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("lookup(%#v)", test.Values), func(t *testing.T) {
+			got, err := Lookup(test.Values...)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestLookup_error(t *testing.T) {
+	simpleMap := cty.MapVal(map[string]cty.Value{
+		"foo": cty.StringVal("bar"),
+	})
+
+	tests := map[string]struct {
+		Values  []cty.Value
+		WantErr string
+	}{
+		"failed to find non-sensitive key": {
+			[]cty.Value{
+				simpleMap,
+				cty.StringVal("boop"),
+			},
+			`lookup failed to find key "boop"`,
+		},
+		"failed to find sensitive key": {
+			[]cty.Value{
+				simpleMap,
+				cty.StringVal("boop").Mark(marks.Sensitive),
+			},
+			"lookup failed to find key (sensitive value)",
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			_, err := Lookup(test.Values...)
+
+			if err == nil {
+				t.Fatal("succeeded; want error")
+			}
+
+			if err.Error() != test.WantErr {
+				t.Errorf("wrong error\ngot:  %#v\nwant: %#v", err, test.WantErr)
+			}
+		})
+	}
+}
+
+func TestMatchkeys(t *testing.T) {
+	tests := []struct {
+		Keys      cty.Value
+		Values    cty.Value
+		Searchset cty.Value
+		Want      cty.Value
+		Err       bool
+	}{
+		{ // normal usage
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+				cty.StringVal("b"),
+				cty.StringVal("c"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("ref1"),
+				cty.StringVal("ref2"),
+				cty.StringVal("ref3"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("ref1"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+			}),
+			false,
+		},
+		{ // normal usage 2, check the order
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+				cty.StringVal("b"),
+				cty.StringVal("c"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("ref1"),
+				cty.StringVal("ref2"),
+				cty.StringVal("ref3"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("ref2"),
+				cty.StringVal("ref1"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+				cty.StringVal("b"),
+			}),
+			false,
+		},
+		{ // no matches
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+				cty.StringVal("b"),
+				cty.StringVal("c"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("ref1"),
+				cty.StringVal("ref2"),
+				cty.StringVal("ref3"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("ref4"),
+			}),
+			cty.ListValEmpty(cty.String),
+			false,
+		},
+		{ // no matches 2
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+				cty.StringVal("b"),
+				cty.StringVal("c"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("ref1"),
+				cty.StringVal("ref2"),
+				cty.StringVal("ref3"),
+			}),
+			cty.ListValEmpty(cty.String),
+			cty.ListValEmpty(cty.String),
+			false,
+		},
+		{ // zero case
+			cty.ListValEmpty(cty.String),
+			cty.ListValEmpty(cty.String),
+			cty.ListVal([]cty.Value{cty.StringVal("nope")}),
+			cty.ListValEmpty(cty.String),
+			false,
+		},
+		{ // complex values
+			cty.ListVal([]cty.Value{
+				cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal("a"),
+				}),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal("a"),
+				}),
+			}),
+			false,
+		},
+		{ // unknowns
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+				cty.StringVal("b"),
+				cty.UnknownVal(cty.String),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("ref1"),
+				cty.StringVal("ref2"),
+				cty.UnknownVal(cty.String),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("ref1"),
+			}),
+			cty.UnknownVal(cty.List(cty.String)),
+			false,
+		},
+		{ // different types that can be unified
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.NumberIntVal(1),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+			}),
+			cty.ListValEmpty(cty.String),
+			false,
+		},
+		{ // complex values: values is a different type from keys and searchset
+			cty.ListVal([]cty.Value{
+				cty.MapVal(map[string]cty.Value{
+					"foo": cty.StringVal("bar"),
+				}),
+				cty.MapVal(map[string]cty.Value{
+					"foo": cty.StringVal("baz"),
+				}),
+				cty.MapVal(map[string]cty.Value{
+					"foo": cty.StringVal("beep"),
+				}),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+				cty.StringVal("b"),
+				cty.StringVal("c"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+				cty.StringVal("c"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.MapVal(map[string]cty.Value{
+					"foo": cty.StringVal("bar"),
+				}),
+				cty.MapVal(map[string]cty.Value{
+					"foo": cty.StringVal("beep"),
+				}),
+			}),
+			false,
+		},
+		// errors
+		{ // different types
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+				}),
+				cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+				}),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+			}),
+			cty.NilVal,
+			true,
+		},
+		{ // lists of different length
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+				cty.StringVal("b"),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+			}),
+			cty.NilVal,
+			true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("matchkeys(%#v, %#v, %#v)", test.Keys, test.Values, test.Searchset), func(t *testing.T) {
+			got, err := Matchkeys(test.Keys, test.Values, test.Searchset)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestOne(t *testing.T) {
+	tests := []struct {
+		List cty.Value
+		Want cty.Value
+		Err  string
+	}{
+		{
+			cty.ListVal([]cty.Value{
+				cty.NumberIntVal(1),
+			}),
+			cty.NumberIntVal(1),
+			"",
+		},
+		{
+			cty.ListValEmpty(cty.Number),
+			cty.NullVal(cty.Number),
+			"",
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.NumberIntVal(1),
+				cty.NumberIntVal(2),
+				cty.NumberIntVal(3),
+			}),
+			cty.NilVal,
+			"must be a list, set, or tuple value with either zero or one elements",
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.UnknownVal(cty.Number),
+			}),
+			cty.UnknownVal(cty.Number),
+			"",
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.UnknownVal(cty.Number),
+				cty.UnknownVal(cty.Number),
+			}),
+			cty.NilVal,
+			"must be a list, set, or tuple value with either zero or one elements",
+		},
+		{
+			cty.UnknownVal(cty.List(cty.String)),
+			cty.UnknownVal(cty.String),
+			"",
+		},
+		{
+			cty.NullVal(cty.List(cty.String)),
+			cty.NilVal,
+			"argument must not be null",
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.NumberIntVal(1),
+			}).Mark("boop"),
+			cty.NumberIntVal(1).Mark("boop"),
+			"",
+		},
+		{
+			cty.ListValEmpty(cty.Bool).Mark("boop"),
+			cty.NullVal(cty.Bool).Mark("boop"),
+			"",
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.NumberIntVal(1).Mark("boop"),
+			}),
+			cty.NumberIntVal(1).Mark("boop"),
+			"",
+		},
+
+		{
+			cty.SetVal([]cty.Value{
+				cty.NumberIntVal(1),
+			}),
+			cty.NumberIntVal(1),
+			"",
+		},
+		{
+			cty.SetValEmpty(cty.Number),
+			cty.NullVal(cty.Number),
+			"",
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.NumberIntVal(1),
+				cty.NumberIntVal(2),
+				cty.NumberIntVal(3),
+			}),
+			cty.NilVal,
+			"must be a list, set, or tuple value with either zero or one elements",
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.UnknownVal(cty.Number),
+			}),
+			cty.UnknownVal(cty.Number),
+			"",
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.UnknownVal(cty.Number),
+				cty.UnknownVal(cty.Number),
+			}),
+			// The above would be valid if those two unknown values were
+			// equal known values, so this returns unknown rather than failing.
+			cty.UnknownVal(cty.Number),
+			"",
+		},
+		{
+			cty.UnknownVal(cty.Set(cty.String)),
+			cty.UnknownVal(cty.String),
+			"",
+		},
+		{
+			cty.NullVal(cty.Set(cty.String)),
+			cty.NilVal,
+			"argument must not be null",
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.NumberIntVal(1),
+			}).Mark("boop"),
+			cty.NumberIntVal(1).Mark("boop"),
+			"",
+		},
+		{
+			cty.SetValEmpty(cty.Bool).Mark("boop"),
+			cty.NullVal(cty.Bool).Mark("boop"),
+			"",
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.NumberIntVal(1).Mark("boop"),
+			}),
+			cty.NumberIntVal(1).Mark("boop"),
+			"",
+		},
+
+		{
+			cty.TupleVal([]cty.Value{
+				cty.NumberIntVal(1),
+			}),
+			cty.NumberIntVal(1),
+			"",
+		},
+		{
+			cty.EmptyTupleVal,
+			cty.NullVal(cty.DynamicPseudoType),
+			"",
+		},
+		{
+			cty.TupleVal([]cty.Value{
+				cty.NumberIntVal(1),
+				cty.NumberIntVal(2),
+				cty.NumberIntVal(3),
+			}),
+			cty.NilVal,
+			"must be a list, set, or tuple value with either zero or one elements",
+		},
+		{
+			cty.TupleVal([]cty.Value{
+				cty.UnknownVal(cty.Number),
+			}),
+			cty.UnknownVal(cty.Number),
+			"",
+		},
+		{
+			cty.TupleVal([]cty.Value{
+				cty.UnknownVal(cty.Number),
+				cty.UnknownVal(cty.Number),
+			}),
+			cty.NilVal,
+			"must be a list, set, or tuple value with either zero or one elements",
+		},
+		{
+			cty.UnknownVal(cty.EmptyTuple),
+			// Could actually return null here, but don't for consistency with unknown lists
+			cty.UnknownVal(cty.DynamicPseudoType),
+			"",
+		},
+		{
+			cty.UnknownVal(cty.Tuple([]cty.Type{cty.Bool})),
+			cty.UnknownVal(cty.Bool),
+			"",
+		},
+		{
+			cty.UnknownVal(cty.Tuple([]cty.Type{cty.Bool, cty.Number})),
+			cty.NilVal,
+			"must be a list, set, or tuple value with either zero or one elements",
+		},
+		{
+			cty.NullVal(cty.EmptyTuple),
+			cty.NilVal,
+			"argument must not be null",
+		},
+		{
+			cty.NullVal(cty.Tuple([]cty.Type{cty.Bool})),
+			cty.NilVal,
+			"argument must not be null",
+		},
+		{
+			cty.NullVal(cty.Tuple([]cty.Type{cty.Bool, cty.Number})),
+			cty.NilVal,
+			"argument must not be null",
+		},
+		{
+			cty.TupleVal([]cty.Value{
+				cty.NumberIntVal(1),
+			}).Mark("boop"),
+			cty.NumberIntVal(1).Mark("boop"),
+			"",
+		},
+		{
+			cty.EmptyTupleVal.Mark("boop"),
+			cty.NullVal(cty.DynamicPseudoType).Mark("boop"),
+			"",
+		},
+		{
+			cty.TupleVal([]cty.Value{
+				cty.NumberIntVal(1).Mark("boop"),
+			}),
+			cty.NumberIntVal(1).Mark("boop"),
+			"",
+		},
+
+		{
+			cty.DynamicVal,
+			cty.DynamicVal,
+			"",
+		},
+		{
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.NilVal,
+			"argument must not be null",
+		},
+		{
+			cty.MapValEmpty(cty.String),
+			cty.NilVal,
+			"must be a list, set, or tuple value with either zero or one elements",
+		},
+		{
+			cty.EmptyObjectVal,
+			cty.NilVal,
+			"must be a list, set, or tuple value with either zero or one elements",
+		},
+		{
+			cty.True,
+			cty.NilVal,
+			"must be a list, set, or tuple value with either zero or one elements",
+		},
+		{
+			cty.UnknownVal(cty.Bool),
+			cty.NilVal,
+			"must be a list, set, or tuple value with either zero or one elements",
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("one(%#v)", test.List), func(t *testing.T) {
+			got, err := One(test.List)
+
+			if test.Err != "" {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				} else if got, want := err.Error(), test.Err; got != want {
+					t.Fatalf("wrong error\n got: %s\nwant: %s", got, want)
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !test.Want.RawEquals(got) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestSum(t *testing.T) {
+	tests := []struct {
+		List cty.Value
+		Want cty.Value
+		Err  string
+	}{
+		{
+			cty.ListVal([]cty.Value{
+				cty.NumberIntVal(1),
+				cty.NumberIntVal(2),
+				cty.NumberIntVal(3),
+			}),
+			cty.NumberIntVal(6),
+			"",
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.NumberIntVal(1476),
+				cty.NumberIntVal(2093),
+				cty.NumberIntVal(2092495),
+				cty.NumberIntVal(64589234),
+				cty.NumberIntVal(234),
+			}),
+			cty.NumberIntVal(66685532),
+			"",
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.StringVal("a"),
+				cty.StringVal("b"),
+				cty.StringVal("c"),
+			}),
+			cty.UnknownVal(cty.String),
+			"argument must be list, set, or tuple of number values",
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.NumberIntVal(10),
+				cty.NumberIntVal(-19),
+				cty.NumberIntVal(5),
+			}),
+			cty.NumberIntVal(-4),
+			"",
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.NumberFloatVal(10.2),
+				cty.NumberFloatVal(19.4),
+				cty.NumberFloatVal(5.7),
+			}),
+			cty.NumberFloatVal(35.3),
+			"",
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.NumberFloatVal(-10.2),
+				cty.NumberFloatVal(-19.4),
+				cty.NumberFloatVal(-5.7),
+			}),
+			cty.NumberFloatVal(-35.3),
+			"",
+		},
+		{
+			cty.ListVal([]cty.Value{cty.NullVal(cty.Number)}),
+			cty.NilVal,
+			"argument must be list, set, or tuple of number values",
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.NumberIntVal(5),
+				cty.NullVal(cty.Number),
+			}),
+			cty.NilVal,
+			"argument must be list, set, or tuple of number values",
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.StringVal("a"),
+				cty.StringVal("b"),
+				cty.StringVal("c"),
+			}),
+			cty.UnknownVal(cty.String),
+			"argument must be list, set, or tuple of number values",
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.NumberIntVal(10),
+				cty.NumberIntVal(-19),
+				cty.NumberIntVal(5),
+			}),
+			cty.NumberIntVal(-4),
+			"",
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.NumberIntVal(10),
+				cty.NumberIntVal(25),
+				cty.NumberIntVal(30),
+			}),
+			cty.NumberIntVal(65),
+			"",
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.NumberFloatVal(2340.8),
+				cty.NumberFloatVal(10.2),
+				cty.NumberFloatVal(3),
+			}),
+			cty.NumberFloatVal(2354),
+			"",
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.NumberFloatVal(2),
+			}),
+			cty.NumberFloatVal(2),
+			"",
+		},
+		{
+			cty.SetVal([]cty.Value{
+				cty.NumberFloatVal(-2),
+				cty.NumberFloatVal(-50),
+				cty.NumberFloatVal(-20),
+				cty.NumberFloatVal(-123),
+				cty.NumberFloatVal(-4),
+			}),
+			cty.NumberFloatVal(-199),
+			"",
+		},
+		{
+			cty.TupleVal([]cty.Value{
+				cty.NumberIntVal(12),
+				cty.StringVal("a"),
+				cty.NumberIntVal(38),
+			}),
+			cty.UnknownVal(cty.String),
+			"argument must be list, set, or tuple of number values",
+		},
+		{
+			cty.NumberIntVal(12),
+			cty.NilVal,
+			"cannot sum noniterable",
+		},
+		{
+			cty.ListValEmpty(cty.Number),
+			cty.NilVal,
+			"cannot sum an empty list",
+		},
+		{
+			cty.MapVal(map[string]cty.Value{"hello": cty.True}),
+			cty.NilVal,
+			"argument must be list, set, or tuple. Received map of bool",
+		},
+		{
+			cty.UnknownVal(cty.Number),
+			cty.UnknownVal(cty.Number),
+			"",
+		},
+		{
+			cty.UnknownVal(cty.List(cty.Number)),
+			cty.UnknownVal(cty.Number),
+			"",
+		},
+		{ // known list containing unknown values
+			cty.ListVal([]cty.Value{cty.UnknownVal(cty.Number)}),
+			cty.UnknownVal(cty.Number),
+			"",
+		},
+		{ // numbers too large to represent as float64
+			cty.ListVal([]cty.Value{
+				cty.MustParseNumberVal("1e+500"),
+				cty.MustParseNumberVal("1e+500"),
+			}),
+			cty.MustParseNumberVal("2e+500"),
+			"",
+		},
+		{ // edge case we have a special error handler for
+			cty.ListVal([]cty.Value{
+				cty.NumberFloatVal(math.Inf(1)),
+				cty.NumberFloatVal(math.Inf(-1)),
+			}),
+			cty.NilVal,
+			"can't compute sum of opposing infinities",
+		},
+		{
+			cty.ListVal([]cty.Value{
+				cty.StringVal("1"),
+				cty.StringVal("2"),
+				cty.StringVal("3"),
+			}),
+			cty.NumberIntVal(6),
+			"",
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("sum(%#v)", test.List), func(t *testing.T) {
+			got, err := Sum(test.List)
+
+			if test.Err != "" {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				} else if got, want := err.Error(), test.Err; got != want {
+					t.Fatalf("wrong error\n got: %s\nwant: %s", got, want)
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestTranspose(t *testing.T) {
+	tests := []struct {
+		Values cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		{
+			cty.MapVal(map[string]cty.Value{
+				"key1": cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal("b"),
+				}),
+				"key2": cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal("b"),
+					cty.StringVal("c"),
+				}),
+				"key3": cty.ListVal([]cty.Value{
+					cty.StringVal("c"),
+				}),
+				"key4": cty.ListValEmpty(cty.String),
+			}),
+			cty.MapVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.StringVal("key1"),
+					cty.StringVal("key2"),
+				}),
+				"b": cty.ListVal([]cty.Value{
+					cty.StringVal("key1"),
+					cty.StringVal("key2"),
+				}),
+				"c": cty.ListVal([]cty.Value{
+					cty.StringVal("key2"),
+					cty.StringVal("key3"),
+				}),
+			}),
+			false,
+		},
+		{ // map - unknown value
+			cty.MapVal(map[string]cty.Value{
+				"key1": cty.UnknownVal(cty.List(cty.String)),
+			}),
+			cty.UnknownVal(cty.Map(cty.List(cty.String))),
+			false,
+		},
+		{ // bad map - empty value
+			cty.MapVal(map[string]cty.Value{
+				"key1": cty.ListValEmpty(cty.String),
+			}),
+			cty.MapValEmpty(cty.List(cty.String)),
+			false,
+		},
+		{ // bad map - value not a list
+			cty.MapVal(map[string]cty.Value{
+				"key1": cty.StringVal("a"),
+			}),
+			cty.NilVal,
+			true,
+		},
+		{ // marks (deep or shallow) on any elements will propegate to the entire return value
+			cty.MapVal(map[string]cty.Value{
+				"key1": cty.ListVal([]cty.Value{
+					cty.StringVal("a").Mark("beep"), // mark on the inner list element
+					cty.StringVal("b"),
+				}),
+				"key2": cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal("b"),
+					cty.StringVal("c"),
+				}).Mark("boop"), // mark on the map element
+				"key3": cty.ListVal([]cty.Value{
+					cty.StringVal("c"),
+				}),
+				"key4": cty.ListValEmpty(cty.String),
+			}),
+			cty.MapVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.StringVal("key1"),
+					cty.StringVal("key2"),
+				}),
+				"b": cty.ListVal([]cty.Value{
+					cty.StringVal("key1"),
+					cty.StringVal("key2"),
+				}),
+				"c": cty.ListVal([]cty.Value{
+					cty.StringVal("key2"),
+					cty.StringVal("key3")}),
+			}).WithMarks(cty.NewValueMarks("beep", "boop")),
+			false,
+		},
+		{ // Marks on the input value will be applied to the return value
+			cty.MapVal(map[string]cty.Value{
+				"key1": cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal("b"),
+				}),
+				"key2": cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal("b"),
+					cty.StringVal("c"),
+				}),
+				"key3": cty.ListVal([]cty.Value{
+					cty.StringVal("c"),
+				}),
+			}).Mark("beep"), // mark on the entire input value
+			cty.MapVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.StringVal("key1"),
+					cty.StringVal("key2"),
+				}),
+				"b": cty.ListVal([]cty.Value{
+					cty.StringVal("key1"),
+					cty.StringVal("key2"),
+				}),
+				"c": cty.ListVal([]cty.Value{
+					cty.StringVal("key2"),
+					cty.StringVal("key3"),
+				}),
+			}).Mark("beep"),
+			false,
+		},
+		{ // Marks on the entire input value AND inner elements (deep or shallow) ALL apply to the return
+			cty.MapVal(map[string]cty.Value{
+				"key1": cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal("b"),
+				}).Mark("beep"), // mark on the map element
+				"key2": cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal("b"),
+					cty.StringVal("c"),
+				}),
+				"key3": cty.ListVal([]cty.Value{
+					cty.StringVal("c").Mark("boop"), // mark on the inner list element
+				}),
+			}).Mark("bloop"), // mark on the entire input value
+			cty.MapVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.StringVal("key1"),
+					cty.StringVal("key2"),
+				}),
+				"b": cty.ListVal([]cty.Value{
+					cty.StringVal("key1"),
+					cty.StringVal("key2"),
+				}),
+				"c": cty.ListVal([]cty.Value{
+					cty.StringVal("key2"),
+					cty.StringVal("key3"),
+				}),
+			}).WithMarks(cty.NewValueMarks("beep", "boop", "bloop")),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("transpose(%#v)", test.Values), func(t *testing.T) {
+			got, err := Transpose(test.Values)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/lang/funcs/conversion.go b/v1.5.7/internal/lang/funcs/conversion.go
new file mode 100644
index 0000000..aa950e3
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/conversion.go
@@ -0,0 +1,124 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"strconv"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/lang/types"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/convert"
+	"github.com/zclconf/go-cty/cty/function"
+)
+
+// MakeToFunc constructs a "to..." function, like "tostring", which converts
+// its argument to a specific type or type kind.
+//
+// The given type wantTy can be any type constraint that cty's "convert" package
+// would accept. In particular, this means that you can pass
+// cty.List(cty.DynamicPseudoType) to mean "list of any single type", which
+// will then cause cty to attempt to unify all of the element types when given
+// a tuple.
+func MakeToFunc(wantTy cty.Type) function.Function {
+	return function.New(&function.Spec{
+		Params: []function.Parameter{
+			{
+				Name: "v",
+				// We use DynamicPseudoType rather than wantTy here so that
+				// all values will pass through the function API verbatim and
+				// we can handle the conversion logic within the Type and
+				// Impl functions. This allows us to customize the error
+				// messages to be more appropriate for an explicit type
+				// conversion, whereas the cty function system produces
+				// messages aimed at _implicit_ type conversions.
+				Type:             cty.DynamicPseudoType,
+				AllowNull:        true,
+				AllowMarked:      true,
+				AllowDynamicType: true,
+			},
+		},
+		Type: func(args []cty.Value) (cty.Type, error) {
+			gotTy := args[0].Type()
+			if gotTy.Equals(wantTy) {
+				return wantTy, nil
+			}
+			conv := convert.GetConversionUnsafe(args[0].Type(), wantTy)
+			if conv == nil {
+				// We'll use some specialized errors for some trickier cases,
+				// but most we can handle in a simple way.
+				switch {
+				case gotTy.IsTupleType() && wantTy.IsTupleType():
+					return cty.NilType, function.NewArgErrorf(0, "incompatible tuple type for conversion: %s", convert.MismatchMessage(gotTy, wantTy))
+				case gotTy.IsObjectType() && wantTy.IsObjectType():
+					return cty.NilType, function.NewArgErrorf(0, "incompatible object type for conversion: %s", convert.MismatchMessage(gotTy, wantTy))
+				default:
+					return cty.NilType, function.NewArgErrorf(0, "cannot convert %s to %s", gotTy.FriendlyName(), wantTy.FriendlyNameForConstraint())
+				}
+			}
+			// If a conversion is available then everything is fine.
+			return wantTy, nil
+		},
+		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+			// We didn't set "AllowUnknown" on our argument, so it is guaranteed
+			// to be known here but may still be null.
+			ret, err := convert.Convert(args[0], retType)
+			if err != nil {
+				val, _ := args[0].UnmarkDeep()
+				// Because we used GetConversionUnsafe above, conversion can
+				// still potentially fail in here. For example, if the user
+				// asks to convert the string "a" to bool then we'll
+				// optimistically permit it during type checking but fail here
+				// once we note that the value isn't either "true" or "false".
+				gotTy := val.Type()
+				switch {
+				case marks.Contains(args[0], marks.Sensitive):
+					// Generic message so we won't inadvertently disclose
+					// information about sensitive values.
+					return cty.NilVal, function.NewArgErrorf(0, "cannot convert this sensitive %s to %s", gotTy.FriendlyName(), wantTy.FriendlyNameForConstraint())
+
+				case gotTy == cty.String && wantTy == cty.Bool:
+					what := "string"
+					if !val.IsNull() {
+						what = strconv.Quote(val.AsString())
+					}
+					return cty.NilVal, function.NewArgErrorf(0, `cannot convert %s to bool; only the strings "true" or "false" are allowed`, what)
+				case gotTy == cty.String && wantTy == cty.Number:
+					what := "string"
+					if !val.IsNull() {
+						what = strconv.Quote(val.AsString())
+					}
+					return cty.NilVal, function.NewArgErrorf(0, `cannot convert %s to number; given string must be a decimal representation of a number`, what)
+				default:
+					return cty.NilVal, function.NewArgErrorf(0, "cannot convert %s to %s", gotTy.FriendlyName(), wantTy.FriendlyNameForConstraint())
+				}
+			}
+			return ret, nil
+		},
+	})
+}
+
+// TypeFunc returns an encapsulated value containing its argument's type. This
+// value is marked to allow us to limit the use of this function at the moment
+// to only a few supported use cases.
+var TypeFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name:             "value",
+			Type:             cty.DynamicPseudoType,
+			AllowDynamicType: true,
+			AllowUnknown:     true,
+			AllowNull:        true,
+		},
+	},
+	Type: function.StaticReturnType(types.TypeType),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		givenType := args[0].Type()
+		return cty.CapsuleVal(types.TypeType, &givenType).Mark(marks.TypeType), nil
+	},
+})
+
+func Type(input []cty.Value) (cty.Value, error) {
+	return TypeFunc.Call(input)
+}
diff --git a/v1.5.7/internal/lang/funcs/conversion_test.go b/v1.5.7/internal/lang/funcs/conversion_test.go
new file mode 100644
index 0000000..e5b0e5d
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/conversion_test.go
@@ -0,0 +1,205 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestTo(t *testing.T) {
+	tests := []struct {
+		Value    cty.Value
+		TargetTy cty.Type
+		Want     cty.Value
+		Err      string
+	}{
+		{
+			cty.StringVal("a"),
+			cty.String,
+			cty.StringVal("a"),
+			``,
+		},
+		{
+			cty.UnknownVal(cty.String),
+			cty.String,
+			cty.UnknownVal(cty.String),
+			``,
+		},
+		{
+			cty.NullVal(cty.String),
+			cty.String,
+			cty.NullVal(cty.String),
+			``,
+		},
+		{
+			// This test case represents evaluating the expression tostring(null)
+			// from HCL, since null in HCL is cty.NullVal(cty.DynamicPseudoType).
+			// The result in that case should still be null, but a null specifically
+			// of type string.
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.String,
+			cty.NullVal(cty.String),
+			``,
+		},
+		{
+			cty.StringVal("a").Mark("boop"),
+			cty.String,
+			cty.StringVal("a").Mark("boop"),
+			``,
+		},
+		{
+			cty.NullVal(cty.String).Mark("boop"),
+			cty.String,
+			cty.NullVal(cty.String).Mark("boop"),
+			``,
+		},
+		{
+			cty.True,
+			cty.String,
+			cty.StringVal("true"),
+			``,
+		},
+		{
+			cty.StringVal("a"),
+			cty.Bool,
+			cty.DynamicVal,
+			`cannot convert "a" to bool; only the strings "true" or "false" are allowed`,
+		},
+		{
+			cty.StringVal("a").Mark("boop"),
+			cty.Bool,
+			cty.DynamicVal,
+			`cannot convert "a" to bool; only the strings "true" or "false" are allowed`,
+		},
+		{
+			cty.StringVal("a").Mark(marks.Sensitive),
+			cty.Bool,
+			cty.DynamicVal,
+			`cannot convert this sensitive string to bool`,
+		},
+		{
+			cty.StringVal("a"),
+			cty.Number,
+			cty.DynamicVal,
+			`cannot convert "a" to number; given string must be a decimal representation of a number`,
+		},
+		{
+			cty.StringVal("a").Mark("boop"),
+			cty.Number,
+			cty.DynamicVal,
+			`cannot convert "a" to number; given string must be a decimal representation of a number`,
+		},
+		{
+			cty.StringVal("a").Mark(marks.Sensitive),
+			cty.Number,
+			cty.DynamicVal,
+			`cannot convert this sensitive string to number`,
+		},
+		{
+			cty.NullVal(cty.String),
+			cty.Number,
+			cty.NullVal(cty.Number),
+			``,
+		},
+		{
+			cty.UnknownVal(cty.Bool),
+			cty.String,
+			cty.UnknownVal(cty.String),
+			``,
+		},
+		{
+			cty.UnknownVal(cty.String),
+			cty.Bool,
+			cty.UnknownVal(cty.Bool), // conversion is optimistic
+			``,
+		},
+		{
+			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.True}),
+			cty.List(cty.String),
+			cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("true")}),
+			``,
+		},
+		{
+			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.True}),
+			cty.Set(cty.String),
+			cty.SetVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("true")}),
+			``,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.True}),
+			cty.Map(cty.String),
+			cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("true")}),
+			``,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world").Mark("boop")}),
+			cty.Map(cty.String),
+			cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world").Mark("boop")}),
+			``,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world")}).Mark("boop"),
+			cty.Map(cty.String),
+			cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world")}).Mark("boop"),
+			``,
+		},
+		{
+			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world").Mark("boop")}),
+			cty.List(cty.String),
+			cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world").Mark("boop")}),
+			``,
+		},
+		{
+			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world")}).Mark("boop"),
+			cty.List(cty.String),
+			cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world")}).Mark("boop"),
+			``,
+		},
+		{
+			cty.EmptyTupleVal,
+			cty.String,
+			cty.DynamicVal,
+			`cannot convert tuple to string`,
+		},
+		{
+			cty.UnknownVal(cty.EmptyTuple),
+			cty.String,
+			cty.DynamicVal,
+			`cannot convert tuple to string`,
+		},
+		{
+			cty.EmptyObjectVal,
+			cty.Object(map[string]cty.Type{"foo": cty.String}),
+			cty.DynamicVal,
+			`incompatible object type for conversion: attribute "foo" is required`,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("to %s(%#v)", test.TargetTy.FriendlyNameForConstraint(), test.Value), func(t *testing.T) {
+			f := MakeToFunc(test.TargetTy)
+			got, err := f.Call([]cty.Value{test.Value})
+
+			if test.Err != "" {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				if got, want := err.Error(), test.Err; got != want {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/lang/funcs/crypto.go b/v1.5.7/internal/lang/funcs/crypto.go
new file mode 100644
index 0000000..e5f33bf
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/crypto.go
@@ -0,0 +1,337 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"crypto/md5"
+	"crypto/rsa"
+	"crypto/sha1"
+	"crypto/sha256"
+	"crypto/sha512"
+	"encoding/asn1"
+	"encoding/base64"
+	"encoding/hex"
+	"fmt"
+	"hash"
+	"io"
+	"strings"
+
+	uuidv5 "github.com/google/uuid"
+	uuid "github.com/hashicorp/go-uuid"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+	"github.com/zclconf/go-cty/cty/gocty"
+	"golang.org/x/crypto/bcrypt"
+	"golang.org/x/crypto/ssh"
+)
+
+var UUIDFunc = function.New(&function.Spec{
+	Params: []function.Parameter{},
+	Type:   function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		result, err := uuid.GenerateUUID()
+		if err != nil {
+			return cty.UnknownVal(cty.String), err
+		}
+		return cty.StringVal(result), nil
+	},
+})
+
+var UUIDV5Func = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "namespace",
+			Type: cty.String,
+		},
+		{
+			Name: "name",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		var namespace uuidv5.UUID
+		switch {
+		case args[0].AsString() == "dns":
+			namespace = uuidv5.NameSpaceDNS
+		case args[0].AsString() == "url":
+			namespace = uuidv5.NameSpaceURL
+		case args[0].AsString() == "oid":
+			namespace = uuidv5.NameSpaceOID
+		case args[0].AsString() == "x500":
+			namespace = uuidv5.NameSpaceX500
+		default:
+			if namespace, err = uuidv5.Parse(args[0].AsString()); err != nil {
+				return cty.UnknownVal(cty.String), fmt.Errorf("uuidv5() doesn't support namespace %s (%v)", args[0].AsString(), err)
+			}
+		}
+		val := args[1].AsString()
+		return cty.StringVal(uuidv5.NewSHA1(namespace, []byte(val)).String()), nil
+	},
+})
+
+// Base64Sha256Func constructs a function that computes the SHA256 hash of a given string
+// and encodes it with Base64.
+var Base64Sha256Func = makeStringHashFunction(sha256.New, base64.StdEncoding.EncodeToString)
+
+// MakeFileBase64Sha256Func constructs a function that is like Base64Sha256Func but reads the
+// contents of a file rather than hashing a given literal string.
+func MakeFileBase64Sha256Func(baseDir string) function.Function {
+	return makeFileHashFunction(baseDir, sha256.New, base64.StdEncoding.EncodeToString)
+}
+
+// Base64Sha512Func constructs a function that computes the SHA256 hash of a given string
+// and encodes it with Base64.
+var Base64Sha512Func = makeStringHashFunction(sha512.New, base64.StdEncoding.EncodeToString)
+
+// MakeFileBase64Sha512Func constructs a function that is like Base64Sha512Func but reads the
+// contents of a file rather than hashing a given literal string.
+func MakeFileBase64Sha512Func(baseDir string) function.Function {
+	return makeFileHashFunction(baseDir, sha512.New, base64.StdEncoding.EncodeToString)
+}
+
+// BcryptFunc constructs a function that computes a hash of the given string using the Blowfish cipher.
+var BcryptFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "str",
+			Type: cty.String,
+		},
+	},
+	VarParam: &function.Parameter{
+		Name: "cost",
+		Type: cty.Number,
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		defaultCost := 10
+
+		if len(args) > 1 {
+			var val int
+			if err := gocty.FromCtyValue(args[1], &val); err != nil {
+				return cty.UnknownVal(cty.String), err
+			}
+			defaultCost = val
+		}
+
+		if len(args) > 2 {
+			return cty.UnknownVal(cty.String), fmt.Errorf("bcrypt() takes no more than two arguments")
+		}
+
+		input := args[0].AsString()
+		out, err := bcrypt.GenerateFromPassword([]byte(input), defaultCost)
+		if err != nil {
+			return cty.UnknownVal(cty.String), fmt.Errorf("error occured generating password %s", err.Error())
+		}
+
+		return cty.StringVal(string(out)), nil
+	},
+})
+
+// Md5Func constructs a function that computes the MD5 hash of a given string and encodes it with hexadecimal digits.
+var Md5Func = makeStringHashFunction(md5.New, hex.EncodeToString)
+
+// MakeFileMd5Func constructs a function that is like Md5Func but reads the
+// contents of a file rather than hashing a given literal string.
+func MakeFileMd5Func(baseDir string) function.Function {
+	return makeFileHashFunction(baseDir, md5.New, hex.EncodeToString)
+}
+
+// RsaDecryptFunc constructs a function that decrypts an RSA-encrypted ciphertext.
+var RsaDecryptFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "ciphertext",
+			Type: cty.String,
+		},
+		{
+			Name: "privatekey",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		s := args[0].AsString()
+		key := args[1].AsString()
+
+		b, err := base64.StdEncoding.DecodeString(s)
+		if err != nil {
+			return cty.UnknownVal(cty.String), function.NewArgErrorf(0, "failed to decode input %q: cipher text must be base64-encoded", s)
+		}
+
+		rawKey, err := ssh.ParseRawPrivateKey([]byte(key))
+		if err != nil {
+			var errStr string
+			switch e := err.(type) {
+			case asn1.SyntaxError:
+				errStr = strings.ReplaceAll(e.Error(), "asn1: syntax error", "invalid ASN1 data in the given private key")
+			case asn1.StructuralError:
+				errStr = strings.ReplaceAll(e.Error(), "asn1: struture error", "invalid ASN1 data in the given private key")
+			default:
+				errStr = fmt.Sprintf("invalid private key: %s", e)
+			}
+			return cty.UnknownVal(cty.String), function.NewArgErrorf(1, errStr)
+		}
+		privateKey, ok := rawKey.(*rsa.PrivateKey)
+		if !ok {
+			return cty.UnknownVal(cty.String), function.NewArgErrorf(1, "invalid private key type %t", rawKey)
+		}
+
+		out, err := rsa.DecryptPKCS1v15(nil, privateKey, b)
+		if err != nil {
+			return cty.UnknownVal(cty.String), fmt.Errorf("failed to decrypt: %s", err)
+		}
+
+		return cty.StringVal(string(out)), nil
+	},
+})
+
+// Sha1Func contructs a function that computes the SHA1 hash of a given string
+// and encodes it with hexadecimal digits.
+var Sha1Func = makeStringHashFunction(sha1.New, hex.EncodeToString)
+
+// MakeFileSha1Func constructs a function that is like Sha1Func but reads the
+// contents of a file rather than hashing a given literal string.
+func MakeFileSha1Func(baseDir string) function.Function {
+	return makeFileHashFunction(baseDir, sha1.New, hex.EncodeToString)
+}
+
+// Sha256Func contructs a function that computes the SHA256 hash of a given string
+// and encodes it with hexadecimal digits.
+var Sha256Func = makeStringHashFunction(sha256.New, hex.EncodeToString)
+
+// MakeFileSha256Func constructs a function that is like Sha256Func but reads the
+// contents of a file rather than hashing a given literal string.
+func MakeFileSha256Func(baseDir string) function.Function {
+	return makeFileHashFunction(baseDir, sha256.New, hex.EncodeToString)
+}
+
+// Sha512Func contructs a function that computes the SHA512 hash of a given string
+// and encodes it with hexadecimal digits.
+var Sha512Func = makeStringHashFunction(sha512.New, hex.EncodeToString)
+
+// MakeFileSha512Func constructs a function that is like Sha512Func but reads the
+// contents of a file rather than hashing a given literal string.
+func MakeFileSha512Func(baseDir string) function.Function {
+	return makeFileHashFunction(baseDir, sha512.New, hex.EncodeToString)
+}
+
+func makeStringHashFunction(hf func() hash.Hash, enc func([]byte) string) function.Function {
+	return function.New(&function.Spec{
+		Params: []function.Parameter{
+			{
+				Name: "str",
+				Type: cty.String,
+			},
+		},
+		Type: function.StaticReturnType(cty.String),
+		Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+			s := args[0].AsString()
+			h := hf()
+			h.Write([]byte(s))
+			rv := enc(h.Sum(nil))
+			return cty.StringVal(rv), nil
+		},
+	})
+}
+
+func makeFileHashFunction(baseDir string, hf func() hash.Hash, enc func([]byte) string) function.Function {
+	return function.New(&function.Spec{
+		Params: []function.Parameter{
+			{
+				Name: "path",
+				Type: cty.String,
+			},
+		},
+		Type: function.StaticReturnType(cty.String),
+		Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+			path := args[0].AsString()
+			f, err := openFile(baseDir, path)
+			if err != nil {
+				return cty.UnknownVal(cty.String), err
+			}
+			defer f.Close()
+
+			h := hf()
+			_, err = io.Copy(h, f)
+			if err != nil {
+				return cty.UnknownVal(cty.String), err
+			}
+			rv := enc(h.Sum(nil))
+			return cty.StringVal(rv), nil
+		},
+	})
+}
+
+// UUID generates and returns a Type-4 UUID in the standard hexadecimal string
+// format.
+//
+// This is not a pure function: it will generate a different result for each
+// call. It must therefore be registered as an impure function in the function
+// table in the "lang" package.
+func UUID() (cty.Value, error) {
+	return UUIDFunc.Call(nil)
+}
+
+// UUIDV5 generates and returns a Type-5 UUID in the standard hexadecimal string
+// format.
+func UUIDV5(namespace cty.Value, name cty.Value) (cty.Value, error) {
+	return UUIDV5Func.Call([]cty.Value{namespace, name})
+}
+
+// Base64Sha256 computes the SHA256 hash of a given string and encodes it with
+// Base64.
+//
+// The given string is first encoded as UTF-8 and then the SHA256 algorithm is applied
+// as defined in RFC 4634. The raw hash is then encoded with Base64 before returning.
+// Terraform uses the "standard" Base64 alphabet as defined in RFC 4648 section 4.
+func Base64Sha256(str cty.Value) (cty.Value, error) {
+	return Base64Sha256Func.Call([]cty.Value{str})
+}
+
+// Base64Sha512 computes the SHA512 hash of a given string and encodes it with
+// Base64.
+//
+// The given string is first encoded as UTF-8 and then the SHA256 algorithm is applied
+// as defined in RFC 4634. The raw hash is then encoded with Base64 before returning.
+// Terraform uses the "standard" Base64  alphabet as defined in RFC 4648 section 4
+func Base64Sha512(str cty.Value) (cty.Value, error) {
+	return Base64Sha512Func.Call([]cty.Value{str})
+}
+
+// Bcrypt computes a hash of the given string using the Blowfish cipher,
+// returning a string in the Modular Crypt Format
+// usually expected in the shadow password file on many Unix systems.
+func Bcrypt(str cty.Value, cost ...cty.Value) (cty.Value, error) {
+	args := make([]cty.Value, len(cost)+1)
+	args[0] = str
+	copy(args[1:], cost)
+	return BcryptFunc.Call(args)
+}
+
+// Md5 computes the MD5 hash of a given string and encodes it with hexadecimal digits.
+func Md5(str cty.Value) (cty.Value, error) {
+	return Md5Func.Call([]cty.Value{str})
+}
+
+// RsaDecrypt decrypts an RSA-encrypted ciphertext, returning the corresponding
+// cleartext.
+func RsaDecrypt(ciphertext, privatekey cty.Value) (cty.Value, error) {
+	return RsaDecryptFunc.Call([]cty.Value{ciphertext, privatekey})
+}
+
+// Sha1 computes the SHA1 hash of a given string and encodes it with hexadecimal digits.
+func Sha1(str cty.Value) (cty.Value, error) {
+	return Sha1Func.Call([]cty.Value{str})
+}
+
+// Sha256 computes the SHA256 hash of a given string and encodes it with hexadecimal digits.
+func Sha256(str cty.Value) (cty.Value, error) {
+	return Sha256Func.Call([]cty.Value{str})
+}
+
+// Sha512 computes the SHA512 hash of a given string and encodes it with hexadecimal digits.
+func Sha512(str cty.Value) (cty.Value, error) {
+	return Sha512Func.Call([]cty.Value{str})
+}
diff --git a/v1.5.7/internal/lang/funcs/crypto_test.go b/v1.5.7/internal/lang/funcs/crypto_test.go
new file mode 100644
index 0000000..0014565
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/crypto_test.go
@@ -0,0 +1,801 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+	"golang.org/x/crypto/bcrypt"
+)
+
+func TestUUID(t *testing.T) {
+	result, err := UUID()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	resultStr := result.AsString()
+	if got, want := len(resultStr), 36; got != want {
+		t.Errorf("wrong result length %d; want %d", got, want)
+	}
+}
+
+func TestUUIDV5(t *testing.T) {
+	tests := []struct {
+		Namespace cty.Value
+		Name      cty.Value
+		Want      cty.Value
+		Err       bool
+	}{
+		{
+			cty.StringVal("dns"),
+			cty.StringVal("tada"),
+			cty.StringVal("faa898db-9b9d-5b75-86a9-149e7bb8e3b8"),
+			false,
+		},
+		{
+			cty.StringVal("url"),
+			cty.StringVal("tada"),
+			cty.StringVal("2c1ff6b4-211f-577e-94de-d978b0caa16e"),
+			false,
+		},
+		{
+			cty.StringVal("oid"),
+			cty.StringVal("tada"),
+			cty.StringVal("61eeea26-5176-5288-87fc-232d6ed30d2f"),
+			false,
+		},
+		{
+			cty.StringVal("x500"),
+			cty.StringVal("tada"),
+			cty.StringVal("7e12415e-f7c9-57c3-9e43-52dc9950d264"),
+			false,
+		},
+		{
+			cty.StringVal("6ba7b810-9dad-11d1-80b4-00c04fd430c8"),
+			cty.StringVal("tada"),
+			cty.StringVal("faa898db-9b9d-5b75-86a9-149e7bb8e3b8"),
+			false,
+		},
+		{
+			cty.StringVal("tada"),
+			cty.StringVal("tada"),
+			cty.UnknownVal(cty.String),
+			true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("uuidv5(%#v, %#v)", test.Namespace, test.Name), func(t *testing.T) {
+			got, err := UUIDV5(test.Namespace, test.Name)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestBase64Sha256(t *testing.T) {
+	tests := []struct {
+		String cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		{
+			cty.StringVal("test"),
+			cty.StringVal("n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg="),
+			false,
+		},
+		// This would differ because we're base64-encoding hex represantiation, not raw bytes.
+		// base64encode(sha256("test")) =
+		// "OWY4NmQwODE4ODRjN2Q2NTlhMmZlYWEwYzU1YWQwMTVhM2JmNGYxYjJiMGI4MjJjZDE1ZDZjMTViMGYwMGEwOA=="
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("base64sha256(%#v)", test.String), func(t *testing.T) {
+			got, err := Base64Sha256(test.String)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestFileBase64Sha256(t *testing.T) {
+	tests := []struct {
+		Path cty.Value
+		Want cty.Value
+		Err  bool
+	}{
+		{
+			cty.StringVal("testdata/hello.txt"),
+			cty.StringVal("pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4="),
+			false,
+		},
+		{
+			cty.StringVal("testdata/icon.png"),
+			cty.StringVal("47U1q9IZW093SmAzdC820Skpn8vHPvc8szud/Y3ezpo="),
+			false,
+		},
+		{
+			cty.StringVal("testdata/missing"),
+			cty.NilVal,
+			true, // no file exists
+		},
+	}
+
+	fileSHA256 := MakeFileBase64Sha256Func(".")
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("filebase64sha256(%#v)", test.Path), func(t *testing.T) {
+			got, err := fileSHA256.Call([]cty.Value{test.Path})
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestBase64Sha512(t *testing.T) {
+	tests := []struct {
+		String cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		{
+			cty.StringVal("test"),
+			cty.StringVal("7iaw3Ur350mqGo7jwQrpkj9hiYB3Lkc/iBml1JQODbJ6wYX4oOHV+E+IvIh/1nsUNzLDBMxfqa2Ob1f1ACio/w=="),
+			false,
+		},
+		// This would differ because we're base64-encoding hex represantiation, not raw bytes
+		// base64encode(sha512("test")) =
+		// "OZWUyNmIwZGQ0YWY3ZTc0OWFhMWE4ZWUzYzEwYWU5OTIzZjYxODk4MDc3MmU0NzNmODgxOWE1ZDQ5NDBlMGRiMjdhYzE4NWY4YTBlMWQ1Zjg0Zjg4YmM4ODdmZDY3YjE0MzczMmMzMDRjYzVmYTlhZDhlNmY1N2Y1MDAyOGE4ZmY="
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("base64sha512(%#v)", test.String), func(t *testing.T) {
+			got, err := Base64Sha512(test.String)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestFileBase64Sha512(t *testing.T) {
+	tests := []struct {
+		Path cty.Value
+		Want cty.Value
+		Err  bool
+	}{
+		{
+			cty.StringVal("testdata/hello.txt"),
+			cty.StringVal("LHT9F+2v2A6ER7DUZ0HuJDt+t03SFJoKsbkkb7MDgvJ+hT2FhXGeDmfL2g2qj1FnEGRhXWRa4nrLFb+xRH9Fmw=="),
+			false,
+		},
+		{
+			cty.StringVal("testdata/icon.png"),
+			cty.StringVal("wSInO/tKEOaLGCAY2h/7gtLWMpzyLJ0ijFh95JTpYrPzXQYgviAdL9ZgpD9EAte8On+drvhFvjIFsfQUwxbNPQ=="),
+			false,
+		},
+		{
+			cty.StringVal("testdata/missing"),
+			cty.NilVal,
+			true, // no file exists
+		},
+	}
+
+	fileSHA512 := MakeFileBase64Sha512Func(".")
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("filebase64sha512(%#v)", test.Path), func(t *testing.T) {
+			got, err := fileSHA512.Call([]cty.Value{test.Path})
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestBcrypt(t *testing.T) {
+	// single variable test
+	p, err := Bcrypt(cty.StringVal("test"))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	err = bcrypt.CompareHashAndPassword([]byte(p.AsString()), []byte("test"))
+	if err != nil {
+		t.Fatalf("Error comparing hash and password: %s", err)
+	}
+
+	// testing with two parameters
+	p, err = Bcrypt(cty.StringVal("test"), cty.NumberIntVal(5))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	err = bcrypt.CompareHashAndPassword([]byte(p.AsString()), []byte("test"))
+	if err != nil {
+		t.Fatalf("Error comparing hash and password: %s", err)
+	}
+
+	// Negative test for more than two parameters
+	_, err = Bcrypt(cty.StringVal("test"), cty.NumberIntVal(10), cty.NumberIntVal(11))
+	if err == nil {
+		t.Fatal("succeeded; want error")
+	}
+}
+
+func TestMd5(t *testing.T) {
+	tests := []struct {
+		String cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		{
+			cty.StringVal("tada"),
+			cty.StringVal("ce47d07243bb6eaf5e1322c81baf9bbf"),
+			false,
+		},
+		{ // Confirm that we're not trimming any whitespaces
+			cty.StringVal(" tada "),
+			cty.StringVal("aadf191a583e53062de2d02c008141c4"),
+			false,
+		},
+		{ // We accept empty string too
+			cty.StringVal(""),
+			cty.StringVal("d41d8cd98f00b204e9800998ecf8427e"),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("md5(%#v)", test.String), func(t *testing.T) {
+			got, err := Md5(test.String)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestFileMD5(t *testing.T) {
+	tests := []struct {
+		Path cty.Value
+		Want cty.Value
+		Err  bool
+	}{
+		{
+			cty.StringVal("testdata/hello.txt"),
+			cty.StringVal("b10a8db164e0754105b7a99be72e3fe5"),
+			false,
+		},
+		{
+			cty.StringVal("testdata/icon.png"),
+			cty.StringVal("d7e6c283185a1078c58213beadca98b0"),
+			false,
+		},
+		{
+			cty.StringVal("testdata/missing"),
+			cty.NilVal,
+			true, // no file exists
+		},
+	}
+
+	fileMD5 := MakeFileMd5Func(".")
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("filemd5(%#v)", test.Path), func(t *testing.T) {
+			got, err := fileMD5.Call([]cty.Value{test.Path})
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestRsaDecrypt(t *testing.T) {
+	tests := []struct {
+		Ciphertext cty.Value
+		Privatekey cty.Value
+		Want       cty.Value
+		Err        string
+	}{
+		// Base-64 encoded cipher decrypts correctly
+		{
+			cty.StringVal(CipherBase64),
+			cty.StringVal(PrivateKey),
+			cty.StringVal("message"),
+			"",
+		},
+		// OpenSSH key format
+		{
+			cty.StringVal(CipherBase64),
+			cty.StringVal(OpenSSHPrivateKey),
+			cty.StringVal("message"),
+			"",
+		},
+		// Wrong key
+		{
+			cty.StringVal(CipherBase64),
+			cty.StringVal(WrongPrivateKey),
+			cty.UnknownVal(cty.String),
+			"failed to decrypt: crypto/rsa: decryption error",
+		},
+		// Bad key
+		{
+			cty.StringVal(CipherBase64),
+			cty.StringVal(BadPrivateKey),
+			cty.UnknownVal(cty.String),
+			"invalid ASN1 data in the given private key: data truncated",
+		},
+		// Empty key
+		{
+			cty.StringVal(CipherBase64),
+			cty.StringVal(""),
+			cty.UnknownVal(cty.String),
+			"invalid private key: ssh: no key found",
+		},
+		// Bad ciphertext
+		{
+			cty.StringVal("bad"),
+			cty.StringVal(PrivateKey),
+			cty.UnknownVal(cty.String),
+			`failed to decode input "bad": cipher text must be base64-encoded`,
+		},
+		// Empty ciphertext
+		{
+			cty.StringVal(""),
+			cty.StringVal(PrivateKey),
+			cty.UnknownVal(cty.String),
+			"failed to decrypt: crypto/rsa: decryption error",
+		},
+	}
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("RsaDecrypt(%#v, %#v)", test.Ciphertext, test.Privatekey), func(t *testing.T) {
+			got, err := RsaDecrypt(test.Ciphertext, test.Privatekey)
+
+			if test.Err != "" {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				} else if err.Error() != test.Err {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", err.Error(), test.Err)
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestSha1(t *testing.T) {
+	tests := []struct {
+		String cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		{
+			cty.StringVal("test"),
+			cty.StringVal("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("sha1(%#v)", test.String), func(t *testing.T) {
+			got, err := Sha1(test.String)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestFileSHA1(t *testing.T) {
+	tests := []struct {
+		Path cty.Value
+		Want cty.Value
+		Err  bool
+	}{
+		{
+			cty.StringVal("testdata/hello.txt"),
+			cty.StringVal("0a4d55a8d778e5022fab701977c5d840bbc486d0"),
+			false,
+		},
+		{
+			cty.StringVal("testdata/icon.png"),
+			cty.StringVal("2821bcc8379e1bd6f4f31b1e6a1fbb204b4a8be8"),
+			false,
+		},
+		{
+			cty.StringVal("testdata/missing"),
+			cty.NilVal,
+			true, // no file exists
+		},
+	}
+
+	fileSHA1 := MakeFileSha1Func(".")
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("filesha1(%#v)", test.Path), func(t *testing.T) {
+			got, err := fileSHA1.Call([]cty.Value{test.Path})
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestSha256(t *testing.T) {
+	tests := []struct {
+		String cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		{
+			cty.StringVal("test"),
+			cty.StringVal("9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("sha256(%#v)", test.String), func(t *testing.T) {
+			got, err := Sha256(test.String)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestFileSHA256(t *testing.T) {
+	tests := []struct {
+		Path cty.Value
+		Want cty.Value
+		Err  bool
+	}{
+		{
+			cty.StringVal("testdata/hello.txt"),
+			cty.StringVal("a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e"),
+			false,
+		},
+		{
+			cty.StringVal("testdata/icon.png"),
+			cty.StringVal("e3b535abd2195b4f774a6033742f36d129299fcbc73ef73cb33b9dfd8ddece9a"),
+			false,
+		},
+		{
+			cty.StringVal("testdata/missing"),
+			cty.NilVal,
+			true, // no file exists
+		},
+	}
+
+	fileSHA256 := MakeFileSha256Func(".")
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("filesha256(%#v)", test.Path), func(t *testing.T) {
+			got, err := fileSHA256.Call([]cty.Value{test.Path})
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestSha512(t *testing.T) {
+	tests := []struct {
+		String cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		{
+			cty.StringVal("test"),
+			cty.StringVal("ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff"),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("sha512(%#v)", test.String), func(t *testing.T) {
+			got, err := Sha512(test.String)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestFileSHA512(t *testing.T) {
+	tests := []struct {
+		Path cty.Value
+		Want cty.Value
+		Err  bool
+	}{
+		{
+			cty.StringVal("testdata/hello.txt"),
+			cty.StringVal("2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27e853d8585719e0e67cbda0daa8f51671064615d645ae27acb15bfb1447f459b"),
+			false,
+		},
+		{
+			cty.StringVal("testdata/icon.png"),
+			cty.StringVal("c122273bfb4a10e68b182018da1ffb82d2d6329cf22c9d228c587de494e962b3f35d0620be201d2fd660a43f4402d7bc3a7f9daef845be3205b1f414c316cd3d"),
+			false,
+		},
+		{
+			cty.StringVal("testdata/missing"),
+			cty.NilVal,
+			true, // no file exists
+		},
+	}
+
+	fileSHA512 := MakeFileSha512Func(".")
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("filesha512(%#v)", test.Path), func(t *testing.T) {
+			got, err := fileSHA512.Call([]cty.Value{test.Path})
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+const (
+	CipherBase64 = "eczGaDhXDbOFRZGhjx2etVzWbRqWDlmq0bvNt284JHVbwCgObiuyX9uV0LSAMY707IEgMkExJqXmsB4OWKxvB7epRB9G/3+F+pcrQpODlDuL9oDUAsa65zEpYF0Wbn7Oh7nrMQncyUPpyr9WUlALl0gRWytOA23S+y5joa4M34KFpawFgoqTu/2EEH4Xl1zo+0fy73fEto+nfkUY+meuyGZ1nUx/+DljP7ZqxHBFSlLODmtuTMdswUbHbXbWneW51D7Jm7xB8nSdiA2JQNK5+Sg5x8aNfgvFTt/m2w2+qpsyFa5Wjeu6fZmXSl840CA07aXbk9vN4I81WmJyblD/ZA=="
+	PrivateKey   = `
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAgUElV5mwqkloIrM8ZNZ72gSCcnSJt7+/Usa5G+D15YQUAdf9
+c1zEekTfHgDP+04nw/uFNFaE5v1RbHaPxhZYVg5ZErNCa/hzn+x10xzcepeS3KPV
+Xcxae4MR0BEegvqZqJzN9loXsNL/c3H/B+2Gle3hTxjlWFb3F5qLgR+4Mf4ruhER
+1v6eHQa/nchi03MBpT4UeJ7MrL92hTJYLdpSyCqmr8yjxkKJDVC2uRrr+sTSxfh7
+r6v24u/vp/QTmBIAlNPgadVAZw17iNNb7vjV7Gwl/5gHXonCUKURaV++dBNLrHIZ
+pqcAM8wHRph8mD1EfL9hsz77pHewxolBATV+7QIDAQABAoIBAC1rK+kFW3vrAYm3
++8/fQnQQw5nec4o6+crng6JVQXLeH32qXShNf8kLLG/Jj0vaYcTPPDZw9JCKkTMQ
+0mKj9XR/5DLbBMsV6eNXXuvJJ3x4iKW5eD9WkLD4FKlNarBRyO7j8sfPTqXW7uat
+NxWdFH7YsSRvNh/9pyQHLWA5OituidMrYbc3EUx8B1GPNyJ9W8Q8znNYLfwYOjU4
+Wv1SLE6qGQQH9Q0WzA2WUf8jklCYyMYTIywAjGb8kbAJlKhmj2t2Igjmqtwt1PYc
+pGlqbtQBDUiWXt5S4YX/1maIQ/49yeNUajjpbJiH3DbhJbHwFTzP3pZ9P9GHOzlG
+kYR+wSECgYEAw/Xida8kSv8n86V3qSY/I+fYQ5V+jDtXIE+JhRnS8xzbOzz3v0WS
+Oo5H+o4nJx5eL3Ghb3Gcm0Jn46dHrxinHbm+3RjXv/X6tlbxIYjRSQfHOTSMCTvd
+qcliF5vC6RCLXuc7R+IWR1Ky6eDEZGtrvt3DyeYABsp9fRUFR/6NluUCgYEAqNsw
+1aSl7WJa27F0DoJdlU9LWerpXcazlJcIdOz/S9QDmSK3RDQTdqfTxRmrxiYI9LEs
+mkOkvzlnnOBMpnZ3ZOU5qIRfprecRIi37KDAOHWGnlC0EWGgl46YLb7/jXiWf0AG
+Y+DfJJNd9i6TbIDWu8254/erAS6bKMhW/3q7f2kCgYAZ7Id/BiKJAWRpqTRBXlvw
+BhXoKvjI2HjYP21z/EyZ+PFPzur/lNaZhIUlMnUfibbwE9pFggQzzf8scM7c7Sf+
+mLoVSdoQ/Rujz7CqvQzi2nKSsM7t0curUIb3lJWee5/UeEaxZcmIufoNUrzohAWH
+BJOIPDM4ssUTLRq7wYM9uQKBgHCBau5OP8gE6mjKuXsZXWUoahpFLKwwwmJUp2vQ
+pOFPJ/6WZOlqkTVT6QPAcPUbTohKrF80hsZqZyDdSfT3peFx4ZLocBrS56m6NmHR
+UYHMvJ8rQm76T1fryHVidz85g3zRmfBeWg8yqT5oFg4LYgfLsPm1gRjOhs8LfPvI
+OLlRAoGBAIZ5Uv4Z3s8O7WKXXUe/lq6j7vfiVkR1NW/Z/WLKXZpnmvJ7FgxN4e56
+RXT7GwNQHIY8eDjDnsHxzrxd+raOxOZeKcMHj3XyjCX3NHfTscnsBPAGYpY/Wxzh
+T8UYnFu6RzkixElTf2rseEav7rkdKkI3LAeIZy7B0HulKKsmqVQ7
+-----END RSA PRIVATE KEY-----
+`
+	OpenSSHPrivateKey = `
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAQEAgUElV5mwqkloIrM8ZNZ72gSCcnSJt7+/Usa5G+D15YQUAdf9c1zE
+ekTfHgDP+04nw/uFNFaE5v1RbHaPxhZYVg5ZErNCa/hzn+x10xzcepeS3KPVXcxae4MR0B
+EegvqZqJzN9loXsNL/c3H/B+2Gle3hTxjlWFb3F5qLgR+4Mf4ruhER1v6eHQa/nchi03MB
+pT4UeJ7MrL92hTJYLdpSyCqmr8yjxkKJDVC2uRrr+sTSxfh7r6v24u/vp/QTmBIAlNPgad
+VAZw17iNNb7vjV7Gwl/5gHXonCUKURaV++dBNLrHIZpqcAM8wHRph8mD1EfL9hsz77pHew
+xolBATV+7QAAA7jbhEFk24RBZAAAAAdzc2gtcnNhAAABAQCBQSVXmbCqSWgiszxk1nvaBI
+JydIm3v79Sxrkb4PXlhBQB1/1zXMR6RN8eAM/7TifD+4U0VoTm/VFsdo/GFlhWDlkSs0Jr
++HOf7HXTHNx6l5Lco9VdzFp7gxHQER6C+pmonM32Whew0v9zcf8H7YaV7eFPGOVYVvcXmo
+uBH7gx/iu6ERHW/p4dBr+dyGLTcwGlPhR4nsysv3aFMlgt2lLIKqavzKPGQokNULa5Guv6
+xNLF+Huvq/bi7++n9BOYEgCU0+Bp1UBnDXuI01vu+NXsbCX/mAdeicJQpRFpX750E0usch
+mmpwAzzAdGmHyYPUR8v2GzPvukd7DGiUEBNX7tAAAAAwEAAQAAAQAtayvpBVt76wGJt/vP
+30J0EMOZ3nOKOvnK54OiVUFy3h99ql0oTX/JCyxvyY9L2mHEzzw2cPSQipEzENJio/V0f+
+Qy2wTLFenjV17rySd8eIiluXg/VpCw+BSpTWqwUcju4/LHz06l1u7mrTcVnRR+2LEkbzYf
+/ackBy1gOTorbonTK2G3NxFMfAdRjzcifVvEPM5zWC38GDo1OFr9UixOqhkEB/UNFswNll
+H/I5JQmMjGEyMsAIxm/JGwCZSoZo9rdiII5qrcLdT2HKRpam7UAQ1Ill7eUuGF/9ZmiEP+
+PcnjVGo46WyYh9w24SWx8BU8z96WfT/Rhzs5RpGEfsEhAAAAgQCGeVL+Gd7PDu1il11Hv5
+auo+734lZEdTVv2f1iyl2aZ5ryexYMTeHuekV0+xsDUByGPHg4w57B8c68Xfq2jsTmXinD
+B4918owl9zR307HJ7ATwBmKWP1sc4U/FGJxbukc5IsRJU39q7HhGr+65HSpCNywHiGcuwd
+B7pSirJqlUOwAAAIEAw/Xida8kSv8n86V3qSY/I+fYQ5V+jDtXIE+JhRnS8xzbOzz3v0WS
+Oo5H+o4nJx5eL3Ghb3Gcm0Jn46dHrxinHbm+3RjXv/X6tlbxIYjRSQfHOTSMCTvdqcliF5
+vC6RCLXuc7R+IWR1Ky6eDEZGtrvt3DyeYABsp9fRUFR/6NluUAAACBAKjbMNWkpe1iWtux
+dA6CXZVPS1nq6V3Gs5SXCHTs/0vUA5kit0Q0E3an08UZq8YmCPSxLJpDpL85Z5zgTKZ2d2
+TlOaiEX6a3nESIt+ygwDh1hp5QtBFhoJeOmC2+/414ln9ABmPg3ySTXfYuk2yA1rvNueP3
+qwEumyjIVv96u39pAAAAAAEC
+-----END OPENSSH PRIVATE KEY-----
+`
+	WrongPrivateKey = `
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAlrCgnEVgmNKCq7KPc+zUU5IrxPu1ClMNJS7RTsTPEkbwe5SB
+p+6V6WtCbD/X/lDRRGbOENChh1Phulb7lViqgrdpHydgsrKoS5ah3DfSIxLFLE00
+9Yo4TCYwgw6+s59j16ZAFVinaQ9l6Kmrb2ll136hMrz8QKh+qw+onOLd38WFgm+W
+ZtUqSXf2LANzfzzy4OWFNyFqKaCAolSkPdTS9Nz+svtScvp002DQp8OdP1AgPO+l
+o5N3M38Fftapwg0pCtJ5Zq0NRWIXEonXiTEMA6zy3gEZVOmDxoIFUWnmrqlMJLFy
+5S6LDrHSdqJhCxDK6WRZj43X9j8spktk3eGhMwIDAQABAoIBAAem8ID/BOi9x+Tw
+LFi2rhGQWqimH4tmrEQ3HGnjlKBY+d1MrUjZ1MMFr1nP5CgF8pqGnfA8p/c3Sz8r
+K5tp5T6+EZiDZ2WrrOApxg5ox0MAsQKO6SGO40z6o3wEQ6rbbTaGOrraxaWQIpyu
+AQanU4Sd6ZGqByVBaS1GnklZO+shCHqw73b7g1cpLEmFzcYnKHYHlUUIsstMe8E1
+BaCY0CH7JbWBjcbiTnBVwIRZuu+EjGiQuhTilYL2OWqoMVg1WU0L2IFpR8lkf/2W
+SBx5J6xhwbBGASOpM+qidiN580GdPzGhWYSqKGroHEzBm6xPSmV1tadNA26WFG4p
+pthLiAECgYEA5BsPRpNYJAQLu5B0N7mj9eEp0HABVEgL/MpwiImjaKdAwp78HM64
+IuPvJxs7r+xESiIz4JyjR8zrQjYOCKJsARYkmNlEuAz0SkHabCw1BdEBwUhjUGVB
+efoERK6GxfAoNqmSDwsOvHFOtsmDIlbHmg7G2rUxNVpeou415BSB0B8CgYEAqR4J
+YHKk2Ibr9rU+rBU33TcdTGw0aAkFNAVeqM9j0haWuFXmV3RArgoy09lH+2Ha6z/g
+fTX2xSDAWV7QUlLOlBRIhurPAo2jO2yCrGHPZcWiugstrR2hTTInigaSnCmK3i7F
+6sYmL3S7K01IcVNxSlWvGijtClT92Cl2WUCTfG0CgYAiEjyk4QtQTd5mxLvnOu5X
+oqs5PBGmwiAwQRiv/EcRMbJFn7Oupd3xMDSflbzDmTnWDOfMy/jDl8MoH6TW+1PA
+kcsjnYhbKWwvz0hN0giVdtOZSDO1ZXpzOrn6fEsbM7T9/TQY1SD9WrtUKCNTNL0Z
+sM1ZC6lu+7GZCpW4HKwLJwKBgQCRT0yxQXBg1/UxwuO5ynV4rx2Oh76z0WRWIXMH
+S0MyxdP1SWGkrS/SGtM3cg/GcHtA/V6vV0nUcWK0p6IJyjrTw2XZ/zGluPuTWJYi
+9dvVT26Vunshrz7kbH7KuwEICy3V4IyQQHeY+QzFlR70uMS0IVFWAepCoWqHbIDT
+CYhwNQKBgGPcLXmjpGtkZvggl0aZr9LsvCTckllSCFSI861kivL/rijdNoCHGxZv
+dfDkLTLcz9Gk41rD9Gxn/3sqodnTAc3Z2PxFnzg1Q/u3+x6YAgBwI/g/jE2xutGW
+H7CurtMwALQ/n/6LUKFmjRZjqbKX9SO2QSaC3grd6sY9Tu+bZjLe
+-----END RSA PRIVATE KEY-----
+`
+	BadPrivateKey = `
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAgUElV5mwqkloIrM8ZNZ72gSCcnSJt7+/Usa5G+D15YQUAdf9
+c1zEekTfHgDP+04nw/uFNFaE5v1RbHaPxhZYVg5ZErNCa/hzn+x10xzcepeS3KPV
+Xcxae4MR0BEegvqZqJzN9loXsNL/c3H/B+2Gle3hTxjlWFb3F5qLgR+4Mf4ruhER
+1v6eHQa/nchi03MBpT4UeJ7MrL92hTJYLdpSyCqmr8yjxkKJDVC2uRrr+sTSxfh7
+r6v24u/vp/QTmBIAlNPgadVAZw17iNNb7vjV7Gwl/5gHXonCUKURaV++dBNLrHIZ
+pqcAM8wHRph8mD1EfL9hsz77pHewxolBATV+7QIDAQABAoIBAC1rK+kFW3vrAYm3
++8/fQnQQw5nec4o6+crng6JVQXLeH32qXShNf8kLLG/Jj0vaYcTPPDZw9JCKkTMQ
+0mKj9XR/5DLbBMsV6eNXXuvJJ3x4iKW5eD9WkLD4FKlNarBRyO7j8sfPTqXW7uat
+NxWdFH7YsSRvNh/9pyQHLWA5OituidMrYbc3EUx8B1GPNyJ9W8Q8znNYLfwYOjU4
+Wv1SLE6qGQQH9Q0WzA2WUf8jklCYyMYTIywAjGb8kbAJlKhmj2t2Igjmqtwt1PYc
+pGlqbtQBDUiWXt5S4YX/1maIQ/49yeNUajjpbJiH3DbhJbHwFTzP3pZ9P9GHOzlG
+kYR+wSECgYEAw/Xida8kSv8n86V3qSY/I+fYQ5V+jDtXIE+JhRnS8xzbOzz3v0WS
+Oo5H+o4nJx5eL3Ghb3Gcm0Jn46dHrxinHbm+3RjXv/X6tlbxIYjRSQfHOTSMCTvd
+qcliF5vC6RCLXuc7R+IWR1Ky6eDEZGtrvt3DyeYABsp9fRUFR/6NluUCgYEAqNsw
+1aSl7WJa27F0DoJdlU9LWerpXcazlJcIdOz/S9QDmSK3RDQTdqfTxRmrxiYI9LEs
+mkOkvzlnnOBMpnZ3ZOU5qIRfprecRIi37KDAOHWGnlC0EWGgl46YLb7/jXiWf0AG
+BhXoKvjI2HjYP21z/EyZ+PFPzur/lNaZhIUlMnUfibbwE9pFggQzzf8scM7c7Sf+
+mLoVSdoQ/Rujz7CqvQzi2nKSsM7t0curUIb3lJWee5/UeEaxZcmIufoNUrzohAWH
+BJOIPDM4ssUTLRq7wYM9uQKBgHCBau5OP8gE6mjKuXsZXWUoahpFLKwwwmJUp2vQ
+pOFPJ/6WZOlqkTVT6QPAcPUbTohKrF80hsZqZyDdSfT3peFx4ZLocBrS56m6NmHR
+UYHMvJ8rQm76T1fryHVidz85g3zRmfBeWg8yqT5oFg4LYgfLsPm1gRjOhs8LfPvI
+OLlRAoGBAIZ5Uv4Z3s8O7WKXXUe/lq6j7vfiVkR1NW/Z/WLKXZpnmvJ7FgxN4e56
+RXT7GwNQHIY8eDjDnsHxzrxd+raOxOZeKcMHj3XyjCX3NHfTscnsBPAGYpY/Wxzh
+T8UYnFu6RzkixElTf2rseEav7rkdKkI3LAeIZy7B0HulKKsmqVQ7
+-----END RSA PRIVATE KEY-----
+`
+)
diff --git a/v1.5.7/internal/lang/funcs/datetime.go b/v1.5.7/internal/lang/funcs/datetime.go
new file mode 100644
index 0000000..ecf24ad
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/datetime.go
@@ -0,0 +1,199 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+)
+
+// TimestampFunc constructs a function that returns a string representation of the current date and time.
+var TimestampFunc = function.New(&function.Spec{
+	Params: []function.Parameter{},
+	Type:   function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		return cty.StringVal(time.Now().UTC().Format(time.RFC3339)), nil
+	},
+})
+
+// MakeStaticTimestampFunc constructs a function that returns a string
+// representation of the date and time specified by the provided argument.
+func MakeStaticTimestampFunc(static time.Time) function.Function {
+	return function.New(&function.Spec{
+		Params: []function.Parameter{},
+		Type:   function.StaticReturnType(cty.String),
+		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+			return cty.StringVal(static.Format(time.RFC3339)), nil
+		},
+	})
+}
+
+// TimeAddFunc constructs a function that adds a duration to a timestamp, returning a new timestamp.
+var TimeAddFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "timestamp",
+			Type: cty.String,
+		},
+		{
+			Name: "duration",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		ts, err := parseTimestamp(args[0].AsString())
+		if err != nil {
+			return cty.UnknownVal(cty.String), err
+		}
+		duration, err := time.ParseDuration(args[1].AsString())
+		if err != nil {
+			return cty.UnknownVal(cty.String), err
+		}
+
+		return cty.StringVal(ts.Add(duration).Format(time.RFC3339)), nil
+	},
+})
+
+// TimeCmpFunc is a function that compares two timestamps.
+var TimeCmpFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "timestamp_a",
+			Type: cty.String,
+		},
+		{
+			Name: "timestamp_b",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.Number),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		tsA, err := parseTimestamp(args[0].AsString())
+		if err != nil {
+			return cty.UnknownVal(cty.String), function.NewArgError(0, err)
+		}
+		tsB, err := parseTimestamp(args[1].AsString())
+		if err != nil {
+			return cty.UnknownVal(cty.String), function.NewArgError(1, err)
+		}
+
+		switch {
+		case tsA.Equal(tsB):
+			return cty.NumberIntVal(0), nil
+		case tsA.Before(tsB):
+			return cty.NumberIntVal(-1), nil
+		default:
+			// By elimintation, tsA must be after tsB.
+			return cty.NumberIntVal(1), nil
+		}
+	},
+})
+
+// Timestamp returns a string representation of the current date and time.
+//
+// In the Terraform language, timestamps are conventionally represented as
+// strings using RFC 3339 "Date and Time format" syntax, and so timestamp
+// returns a string in this format.
+func Timestamp() (cty.Value, error) {
+	return TimestampFunc.Call([]cty.Value{})
+}
+
+// TimeAdd adds a duration to a timestamp, returning a new timestamp.
+//
+// In the Terraform language, timestamps are conventionally represented as
+// strings using RFC 3339 "Date and Time format" syntax. Timeadd requires
+// the timestamp argument to be a string conforming to this syntax.
+//
+// `duration` is a string representation of a time difference, consisting of
+// sequences of number and unit pairs, like `"1.5h"` or `1h30m`. The accepted
+// units are `ns`, `us` (or `µs`), `"ms"`, `"s"`, `"m"`, and `"h"`. The first
+// number may be negative to indicate a negative duration, like `"-2h5m"`.
+//
+// The result is a string, also in RFC 3339 format, representing the result
+// of adding the given direction to the given timestamp.
+func TimeAdd(timestamp cty.Value, duration cty.Value) (cty.Value, error) {
+	return TimeAddFunc.Call([]cty.Value{timestamp, duration})
+}
+
+// TimeCmp compares two timestamps, indicating whether they are equal or
+// if one is before the other.
+//
+// TimeCmp considers the UTC offset of each given timestamp when making its
+// decision, so for example 6:00 +0200 and 4:00 UTC are equal.
+//
+// In the Terraform language, timestamps are conventionally represented as
+// strings using RFC 3339 "Date and Time format" syntax. TimeCmp requires
+// the timestamp argument to be a string conforming to this syntax.
+//
+// The result is always a number between -1 and 1. -1 indicates that
+// timestampA is earlier than timestampB. 1 indicates that timestampA is
+// later. 0 indicates that the two timestamps represent the same instant.
+func TimeCmp(timestampA, timestampB cty.Value) (cty.Value, error) {
+	return TimeCmpFunc.Call([]cty.Value{timestampA, timestampB})
+}
+
+func parseTimestamp(ts string) (time.Time, error) {
+	t, err := time.Parse(time.RFC3339, ts)
+	if err != nil {
+		switch err := err.(type) {
+		case *time.ParseError:
+			// If err is a time.ParseError then its string representation is not
+			// appropriate since it relies on details of Go's strange date format
+			// representation, which a caller of our functions is not expected
+			// to be familiar with.
+			//
+			// Therefore we do some light transformation to get a more suitable
+			// error that should make more sense to our callers. These are
+			// still not awesome error messages, but at least they refer to
+			// the timestamp portions by name rather than by Go's example
+			// values.
+			if err.LayoutElem == "" && err.ValueElem == "" && err.Message != "" {
+				// For some reason err.Message is populated with a ": " prefix
+				// by the time package.
+				return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp%s", err.Message)
+			}
+			var what string
+			switch err.LayoutElem {
+			case "2006":
+				what = "year"
+			case "01":
+				what = "month"
+			case "02":
+				what = "day of month"
+			case "15":
+				what = "hour"
+			case "04":
+				what = "minute"
+			case "05":
+				what = "second"
+			case "Z07:00":
+				what = "UTC offset"
+			case "T":
+				return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: missing required time introducer 'T'")
+			case ":", "-":
+				if err.ValueElem == "" {
+					return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: end of string where %q is expected", err.LayoutElem)
+				} else {
+					return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: found %q where %q is expected", err.ValueElem, err.LayoutElem)
+				}
+			default:
+				// Should never get here, because time.RFC3339 includes only the
+				// above portions, but since that might change in future we'll
+				// be robust here.
+				what = "timestamp segment"
+			}
+			if err.ValueElem == "" {
+				return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: end of string before %s", what)
+			} else {
+				return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: cannot use %q as %s", err.ValueElem, what)
+			}
+		}
+		return time.Time{}, err
+	}
+	return t, nil
+}
diff --git a/v1.5.7/internal/lang/funcs/datetime_test.go b/v1.5.7/internal/lang/funcs/datetime_test.go
new file mode 100644
index 0000000..e0387e8
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/datetime_test.go
@@ -0,0 +1,185 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestTimestamp(t *testing.T) {
+	currentTime := time.Now().UTC()
+	result, err := Timestamp()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	resultTime, err := time.Parse(time.RFC3339, result.AsString())
+	if err != nil {
+		t.Fatalf("Error parsing timestamp: %s", err)
+	}
+
+	if resultTime.Sub(currentTime).Seconds() > 10.0 {
+		t.Fatalf("Timestamp Diff too large. Expected: %s\nReceived: %s", currentTime.Format(time.RFC3339), result.AsString())
+	}
+
+}
+
+func TestTimeadd(t *testing.T) {
+	tests := []struct {
+		Time     cty.Value
+		Duration cty.Value
+		Want     cty.Value
+		Err      bool
+	}{
+		{
+			cty.StringVal("2017-11-22T00:00:00Z"),
+			cty.StringVal("1s"),
+			cty.StringVal("2017-11-22T00:00:01Z"),
+			false,
+		},
+		{
+			cty.StringVal("2017-11-22T00:00:00Z"),
+			cty.StringVal("10m1s"),
+			cty.StringVal("2017-11-22T00:10:01Z"),
+			false,
+		},
+		{ // also support subtraction
+			cty.StringVal("2017-11-22T00:00:00Z"),
+			cty.StringVal("-1h"),
+			cty.StringVal("2017-11-21T23:00:00Z"),
+			false,
+		},
+		{ // Invalid format timestamp
+			cty.StringVal("2017-11-22"),
+			cty.StringVal("-1h"),
+			cty.UnknownVal(cty.String),
+			true,
+		},
+		{ // Invalid format duration (day is not supported by ParseDuration)
+			cty.StringVal("2017-11-22T00:00:00Z"),
+			cty.StringVal("1d"),
+			cty.UnknownVal(cty.String),
+			true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("TimeAdd(%#v, %#v)", test.Time, test.Duration), func(t *testing.T) {
+			got, err := TimeAdd(test.Time, test.Duration)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestTimeCmp(t *testing.T) {
+	tests := []struct {
+		TimeA, TimeB cty.Value
+		Want         cty.Value
+		Err          string
+	}{
+		{
+			cty.StringVal("2017-11-22T00:00:00Z"),
+			cty.StringVal("2017-11-22T00:00:00Z"),
+			cty.Zero,
+			``,
+		},
+		{
+			cty.StringVal("2017-11-22T00:00:00Z"),
+			cty.StringVal("2017-11-22T01:00:00+01:00"),
+			cty.Zero,
+			``,
+		},
+		{
+			cty.StringVal("2017-11-22T00:00:01Z"),
+			cty.StringVal("2017-11-22T01:00:00+01:00"),
+			cty.NumberIntVal(1),
+			``,
+		},
+		{
+			cty.StringVal("2017-11-22T01:00:00Z"),
+			cty.StringVal("2017-11-22T00:59:00-01:00"),
+			cty.NumberIntVal(-1),
+			``,
+		},
+		{
+			cty.StringVal("2017-11-22T01:00:00+01:00"),
+			cty.StringVal("2017-11-22T01:00:00-01:00"),
+			cty.NumberIntVal(-1),
+			``,
+		},
+		{
+			cty.StringVal("2017-11-22T01:00:00-01:00"),
+			cty.StringVal("2017-11-22T01:00:00+01:00"),
+			cty.NumberIntVal(1),
+			``,
+		},
+		{
+			cty.StringVal("2017-11-22T00:00:00Z"),
+			cty.StringVal("bloop"),
+			cty.UnknownVal(cty.String),
+			`not a valid RFC3339 timestamp: cannot use "bloop" as year`,
+		},
+		{
+			cty.StringVal("2017-11-22 00:00:00Z"),
+			cty.StringVal("2017-11-22T00:00:00Z"),
+			cty.UnknownVal(cty.String),
+			`not a valid RFC3339 timestamp: missing required time introducer 'T'`,
+		},
+		{
+			cty.StringVal("2017-11-22T00:00:00Z"),
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.Number),
+			``,
+		},
+		{
+			cty.UnknownVal(cty.String),
+			cty.StringVal("2017-11-22T00:00:00Z"),
+			cty.UnknownVal(cty.Number),
+			``,
+		},
+		{
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.Number),
+			``,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("TimeCmp(%#v, %#v)", test.TimeA, test.TimeB), func(t *testing.T) {
+			got, err := TimeCmp(test.TimeA, test.TimeB)
+
+			if test.Err != "" {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				if got := err.Error(); got != test.Err {
+					t.Errorf("wrong error message\ngot:  %s\nwant: %s", got, test.Err)
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/lang/funcs/descriptions.go b/v1.5.7/internal/lang/funcs/descriptions.go
new file mode 100644
index 0000000..587614a
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/descriptions.go
@@ -0,0 +1,546 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import "github.com/zclconf/go-cty/cty/function"
+
+type descriptionEntry struct {
+	// Description is a description for the function.
+	Description string
+
+	// ParamDescription argument must match the number of parameters of the
+	// function. If the function has a VarParam then that counts as one
+	// parameter. The given descriptions will be assigned in order starting
+	// with the positional arguments in their declared order, followed by the
+	// variadic parameter if any.
+	ParamDescription []string
+}
+
+// DescriptionList is a consolidated list containing all descriptions for all
+// functions available within Terraform. A function's description should point
+// to the matching entry in this list.
+//
+// We keep this as a single list, so we can quickly review descriptions within
+// a single file and copy the whole list to other projects, like
+// terraform-schema.
+var DescriptionList = map[string]descriptionEntry{
+	"abs": {
+		Description:      "`abs` returns the absolute value of the given number. In other words, if the number is zero or positive then it is returned as-is, but if it is negative then it is multiplied by -1 to make it positive before returning it.",
+		ParamDescription: []string{""},
+	},
+	"abspath": {
+		Description:      "`abspath` takes a string containing a filesystem path and converts it to an absolute path. That is, if the path is not absolute, it will be joined with the current working directory.",
+		ParamDescription: []string{""},
+	},
+	"alltrue": {
+		Description:      "`alltrue` returns `true` if all elements in a given collection are `true` or `\"true\"`. It also returns `true` if the collection is empty.",
+		ParamDescription: []string{""},
+	},
+	"anytrue": {
+		Description:      "`anytrue` returns `true` if any element in a given collection is `true` or `\"true\"`. It also returns `false` if the collection is empty.",
+		ParamDescription: []string{""},
+	},
+	"base64decode": {
+		Description:      "`base64decode` takes a string containing a Base64 character sequence and returns the original string.",
+		ParamDescription: []string{""},
+	},
+	"base64encode": {
+		Description:      "`base64encode` applies Base64 encoding to a string.",
+		ParamDescription: []string{""},
+	},
+	"base64gzip": {
+		Description:      "`base64gzip` compresses a string with gzip and then encodes the result in Base64 encoding.",
+		ParamDescription: []string{""},
+	},
+	"base64sha256": {
+		Description:      "`base64sha256` computes the SHA256 hash of a given string and encodes it with Base64. This is not equivalent to `base64encode(sha256(\"test\"))` since `sha256()` returns hexadecimal representation.",
+		ParamDescription: []string{""},
+	},
+	"base64sha512": {
+		Description:      "`base64sha512` computes the SHA512 hash of a given string and encodes it with Base64. This is not equivalent to `base64encode(sha512(\"test\"))` since `sha512()` returns hexadecimal representation.",
+		ParamDescription: []string{""},
+	},
+	"basename": {
+		Description:      "`basename` takes a string containing a filesystem path and removes all except the last portion from it.",
+		ParamDescription: []string{""},
+	},
+	"bcrypt": {
+		Description: "`bcrypt` computes a hash of the given string using the Blowfish cipher, returning a string in [the _Modular Crypt Format_](https://passlib.readthedocs.io/en/stable/modular_crypt_format.html) usually expected in the shadow password file on many Unix systems.",
+		ParamDescription: []string{
+			"",
+			"The `cost` argument is optional and will default to 10 if unspecified.",
+		},
+	},
+	"can": {
+		Description:      "`can` evaluates the given expression and returns a boolean value indicating whether the expression produced a result without any errors.",
+		ParamDescription: []string{""},
+	},
+	"ceil": {
+		Description:      "`ceil` returns the closest whole number that is greater than or equal to the given value, which may be a fraction.",
+		ParamDescription: []string{""},
+	},
+	"chomp": {
+		Description:      "`chomp` removes newline characters at the end of a string.",
+		ParamDescription: []string{""},
+	},
+	"chunklist": {
+		Description: "`chunklist` splits a single list into fixed-size chunks, returning a list of lists.",
+		ParamDescription: []string{
+			"",
+			"The maximum length of each chunk. All but the last element of the result is guaranteed to be of exactly this size.",
+		},
+	},
+	"cidrhost": {
+		Description: "`cidrhost` calculates a full host IP address for a given host number within a given IP network address prefix.",
+		ParamDescription: []string{
+			"`prefix` must be given in CIDR notation, as defined in [RFC 4632 section 3.1](https://tools.ietf.org/html/rfc4632#section-3.1).",
+			"`hostnum` is a whole number that can be represented as a binary integer with no more than the number of digits remaining in the address after the given prefix.",
+		},
+	},
+	"cidrnetmask": {
+		Description: "`cidrnetmask` converts an IPv4 address prefix given in CIDR notation into a subnet mask address.",
+		ParamDescription: []string{
+			"`prefix` must be given in CIDR notation, as defined in [RFC 4632 section 3.1](https://tools.ietf.org/html/rfc4632#section-3.1).",
+		},
+	},
+	"cidrsubnet": {
+		Description: "`cidrsubnet` calculates a subnet address within given IP network address prefix.",
+		ParamDescription: []string{
+			"`prefix` must be given in CIDR notation, as defined in [RFC 4632 section 3.1](https://tools.ietf.org/html/rfc4632#section-3.1).",
+			"`newbits` is the number of additional bits with which to extend the prefix.",
+			"`netnum` is a whole number that can be represented as a binary integer with no more than `newbits` binary digits, which will be used to populate the additional bits added to the prefix."},
+	},
+	"cidrsubnets": {
+		Description: "`cidrsubnets` calculates a sequence of consecutive IP address ranges within a particular CIDR prefix.",
+		ParamDescription: []string{
+			"`prefix` must be given in CIDR notation, as defined in [RFC 4632 section 3.1](https://tools.ietf.org/html/rfc4632#section-3.1).",
+			"",
+		},
+	},
+	"coalesce": {
+		Description:      "`coalesce` takes any number of arguments and returns the first one that isn't null or an empty string.",
+		ParamDescription: []string{""},
+	},
+	"coalescelist": {
+		Description: "`coalescelist` takes any number of list arguments and returns the first one that isn't empty.",
+		ParamDescription: []string{
+			"List or tuple values to test in the given order.",
+		},
+	},
+	"compact": {
+		Description:      "`compact` takes a list of strings and returns a new list with any empty string elements removed.",
+		ParamDescription: []string{""},
+	},
+	"concat": {
+		Description:      "`concat` takes two or more lists and combines them into a single list.",
+		ParamDescription: []string{""},
+	},
+	"contains": {
+		Description:      "`contains` determines whether a given list or set contains a given single value as one of its elements.",
+		ParamDescription: []string{"", ""},
+	},
+	"csvdecode": {
+		Description:      "`csvdecode` decodes a string containing CSV-formatted data and produces a list of maps representing that data.",
+		ParamDescription: []string{""},
+	},
+	"dirname": {
+		Description:      "`dirname` takes a string containing a filesystem path and removes the last portion from it.",
+		ParamDescription: []string{""},
+	},
+	"distinct": {
+		Description:      "`distinct` takes a list and returns a new list with any duplicate elements removed.",
+		ParamDescription: []string{""},
+	},
+	"element": {
+		Description:      "`element` retrieves a single element from a list.",
+		ParamDescription: []string{"", ""},
+	},
+	"endswith": {
+		Description:      "`endswith` takes two values: a string to check and a suffix string. The function returns true if the first string ends with that exact suffix.",
+		ParamDescription: []string{"", ""},
+	},
+	"file": {
+		Description:      "`file` reads the contents of a file at the given path and returns them as a string.",
+		ParamDescription: []string{""},
+	},
+	"filebase64": {
+		Description:      "`filebase64` reads the contents of a file at the given path and returns them as a base64-encoded string.",
+		ParamDescription: []string{""},
+	},
+	"filebase64sha256": {
+		Description:      "`filebase64sha256` is a variant of `base64sha256` that hashes the contents of a given file rather than a literal string.",
+		ParamDescription: []string{""},
+	},
+	"filebase64sha512": {
+		Description:      "`filebase64sha512` is a variant of `base64sha512` that hashes the contents of a given file rather than a literal string.",
+		ParamDescription: []string{""},
+	},
+	"fileexists": {
+		Description:      "`fileexists` determines whether a file exists at a given path.",
+		ParamDescription: []string{""},
+	},
+	"filemd5": {
+		Description:      "`filemd5` is a variant of `md5` that hashes the contents of a given file rather than a literal string.",
+		ParamDescription: []string{""},
+	},
+	"fileset": {
+		Description:      "`fileset` enumerates a set of regular file names given a path and pattern. The path is automatically removed from the resulting set of file names and any result still containing path separators always returns forward slash (`/`) as the path separator for cross-system compatibility.",
+		ParamDescription: []string{"", ""},
+	},
+	"filesha1": {
+		Description:      "`filesha1` is a variant of `sha1` that hashes the contents of a given file rather than a literal string.",
+		ParamDescription: []string{""},
+	},
+	"filesha256": {
+		Description:      "`filesha256` is a variant of `sha256` that hashes the contents of a given file rather than a literal string.",
+		ParamDescription: []string{""},
+	},
+	"filesha512": {
+		Description:      "`filesha512` is a variant of `sha512` that hashes the contents of a given file rather than a literal string.",
+		ParamDescription: []string{""},
+	},
+	"flatten": {
+		Description:      "`flatten` takes a list and replaces any elements that are lists with a flattened sequence of the list contents.",
+		ParamDescription: []string{""},
+	},
+	"floor": {
+		Description:      "`floor` returns the closest whole number that is less than or equal to the given value, which may be a fraction.",
+		ParamDescription: []string{""},
+	},
+	"format": {
+		Description:      "The `format` function produces a string by formatting a number of other values according to a specification string. It is similar to the `printf` function in C, and other similar functions in other programming languages.",
+		ParamDescription: []string{"", ""},
+	},
+	"formatdate": {
+		Description:      "`formatdate` converts a timestamp into a different time format.",
+		ParamDescription: []string{"", ""},
+	},
+	"formatlist": {
+		Description:      "`formatlist` produces a list of strings by formatting a number of other values according to a specification string.",
+		ParamDescription: []string{"", ""},
+	},
+	"indent": {
+		Description: "`indent` adds a given number of spaces to the beginnings of all but the first line in a given multi-line string.",
+		ParamDescription: []string{
+			"Number of spaces to add after each newline character.",
+			"",
+		},
+	},
+	"index": {
+		Description:      "`index` finds the element index for a given value in a list.",
+		ParamDescription: []string{"", ""},
+	},
+	"join": {
+		Description: "`join` produces a string by concatenating together all elements of a given list of strings with the given delimiter.",
+		ParamDescription: []string{
+			"Delimiter to insert between the given strings.",
+			"One or more lists of strings to join.",
+		},
+	},
+	"jsondecode": {
+		Description:      "`jsondecode` interprets a given string as JSON, returning a representation of the result of decoding that string.",
+		ParamDescription: []string{""},
+	},
+	"jsonencode": {
+		Description:      "`jsonencode` encodes a given value to a string using JSON syntax.",
+		ParamDescription: []string{""},
+	},
+	"keys": {
+		Description: "`keys` takes a map and returns a list containing the keys from that map.",
+		ParamDescription: []string{
+			"The map to extract keys from. May instead be an object-typed value, in which case the result is a tuple of the object attributes.",
+		},
+	},
+	"length": {
+		Description:      "`length` determines the length of a given list, map, or string.",
+		ParamDescription: []string{""},
+	},
+	"list": {
+		Description:      "The `list` function is no longer available. Prior to Terraform v0.12 it was the only available syntax for writing a literal list inside an expression, but Terraform v0.12 introduced a new first-class syntax.",
+		ParamDescription: []string{""},
+	},
+	"log": {
+		Description:      "`log` returns the logarithm of a given number in a given base.",
+		ParamDescription: []string{"", ""},
+	},
+	"lookup": {
+		Description:      "`lookup` retrieves the value of a single element from a map, given its key. If the given key does not exist, the given default value is returned instead.",
+		ParamDescription: []string{"", "", ""},
+	},
+	"lower": {
+		Description:      "`lower` converts all cased letters in the given string to lowercase.",
+		ParamDescription: []string{""},
+	},
+	"map": {
+		Description:      "The `map` function is no longer available. Prior to Terraform v0.12 it was the only available syntax for writing a literal map inside an expression, but Terraform v0.12 introduced a new first-class syntax.",
+		ParamDescription: []string{""},
+	},
+	"matchkeys": {
+		Description:      "`matchkeys` constructs a new list by taking a subset of elements from one list whose indexes match the corresponding indexes of values in another list.",
+		ParamDescription: []string{"", "", ""},
+	},
+	"max": {
+		Description:      "`max` takes one or more numbers and returns the greatest number from the set.",
+		ParamDescription: []string{""},
+	},
+	"md5": {
+		Description:      "`md5` computes the MD5 hash of a given string and encodes it with hexadecimal digits.",
+		ParamDescription: []string{""},
+	},
+	"merge": {
+		Description:      "`merge` takes an arbitrary number of maps or objects, and returns a single map or object that contains a merged set of elements from all arguments.",
+		ParamDescription: []string{""},
+	},
+	"min": {
+		Description:      "`min` takes one or more numbers and returns the smallest number from the set.",
+		ParamDescription: []string{""},
+	},
+	"nonsensitive": {
+		Description:      "`nonsensitive` takes a sensitive value and returns a copy of that value with the sensitive marking removed, thereby exposing the sensitive value.",
+		ParamDescription: []string{""},
+	},
+	"one": {
+		Description:      "`one` takes a list, set, or tuple value with either zero or one elements. If the collection is empty, `one` returns `null`. Otherwise, `one` returns the first element. If there are two or more elements then `one` will return an error.",
+		ParamDescription: []string{""},
+	},
+	"parseint": {
+		Description:      "`parseint` parses the given string as a representation of an integer in the specified base and returns the resulting number. The base must be between 2 and 62 inclusive.",
+		ParamDescription: []string{"", ""},
+	},
+	"pathexpand": {
+		Description:      "`pathexpand` takes a filesystem path that might begin with a `~` segment, and if so it replaces that segment with the current user's home directory path.",
+		ParamDescription: []string{""},
+	},
+	"pow": {
+		Description:      "`pow` calculates an exponent, by raising its first argument to the power of the second argument.",
+		ParamDescription: []string{"", ""},
+	},
+	"range": {
+		Description:      "`range` generates a list of numbers using a start value, a limit value, and a step value.",
+		ParamDescription: []string{""},
+	},
+	"regex": {
+		Description:      "`regex` applies a [regular expression](https://en.wikipedia.org/wiki/Regular_expression) to a string and returns the matching substrings.",
+		ParamDescription: []string{"", ""},
+	},
+	"regexall": {
+		Description:      "`regexall` applies a [regular expression](https://en.wikipedia.org/wiki/Regular_expression) to a string and returns a list of all matches.",
+		ParamDescription: []string{"", ""},
+	},
+	"replace": {
+		Description:      "`replace` searches a given string for another given substring, and replaces each occurrence with a given replacement string.",
+		ParamDescription: []string{"", "", ""},
+	},
+	"reverse": {
+		Description:      "`reverse` takes a sequence and produces a new sequence of the same length with all of the same elements as the given sequence but in reverse order.",
+		ParamDescription: []string{""},
+	},
+	"rsadecrypt": {
+		Description:      "`rsadecrypt` decrypts an RSA-encrypted ciphertext, returning the corresponding cleartext.",
+		ParamDescription: []string{"", ""},
+	},
+	"sensitive": {
+		Description:      "`sensitive` takes any value and returns a copy of it marked so that Terraform will treat it as sensitive, with the same meaning and behavior as for [sensitive input variables](/language/values/variables#suppressing-values-in-cli-output).",
+		ParamDescription: []string{""},
+	},
+	"setintersection": {
+		Description:      "The `setintersection` function takes multiple sets and produces a single set containing only the elements that all of the given sets have in common. In other words, it computes the [intersection](https://en.wikipedia.org/wiki/Intersection_\\(set_theory\\)) of the sets.",
+		ParamDescription: []string{"", ""},
+	},
+	"setproduct": {
+		Description: "The `setproduct` function finds all of the possible combinations of elements from all of the given sets by computing the [Cartesian product](https://en.wikipedia.org/wiki/Cartesian_product).",
+		ParamDescription: []string{
+			"The sets to consider. Also accepts lists and tuples, and if all arguments are of list or tuple type then the result will preserve the input ordering",
+		},
+	},
+	"setsubtract": {
+		Description:      "The `setsubtract` function returns a new set containing the elements from the first set that are not present in the second set. In other words, it computes the [relative complement](https://en.wikipedia.org/wiki/Complement_\\(set_theory\\)#Relative_complement) of the second set.",
+		ParamDescription: []string{"", ""},
+	},
+	"setunion": {
+		Description:      "The `setunion` function takes multiple sets and produces a single set containing the elements from all of the given sets. In other words, it computes the [union](https://en.wikipedia.org/wiki/Union_\\(set_theory\\)) of the sets.",
+		ParamDescription: []string{"", ""},
+	},
+	"sha1": {
+		Description:      "`sha1` computes the SHA1 hash of a given string and encodes it with hexadecimal digits.",
+		ParamDescription: []string{""},
+	},
+	"sha256": {
+		Description:      "`sha256` computes the SHA256 hash of a given string and encodes it with hexadecimal digits.",
+		ParamDescription: []string{""},
+	},
+	"sha512": {
+		Description:      "`sha512` computes the SHA512 hash of a given string and encodes it with hexadecimal digits.",
+		ParamDescription: []string{""},
+	},
+	"signum": {
+		Description:      "`signum` determines the sign of a number, returning a number between -1 and 1 to represent the sign.",
+		ParamDescription: []string{""},
+	},
+	"slice": {
+		Description:      "`slice` extracts some consecutive elements from within a list.",
+		ParamDescription: []string{"", "", ""},
+	},
+	"sort": {
+		Description:      "`sort` takes a list of strings and returns a new list with those strings sorted lexicographically.",
+		ParamDescription: []string{""},
+	},
+	"split": {
+		Description:      "`split` produces a list by dividing a given string at all occurrences of a given separator.",
+		ParamDescription: []string{"", ""},
+	},
+	"startswith": {
+		Description:      "`startswith` takes two values: a string to check and a prefix string. The function returns true if the string begins with that exact prefix.",
+		ParamDescription: []string{"", ""},
+	},
+	"strcontains": {
+		Description:      "`strcontains` takes two values: a string to check and an expected substring. The function returns true if the string has the substring contained within it.",
+		ParamDescription: []string{"", ""},
+	},
+	"strrev": {
+		Description:      "`strrev` reverses the characters in a string. Note that the characters are treated as _Unicode characters_ (in technical terms, Unicode [grapheme cluster boundaries](https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) are respected).",
+		ParamDescription: []string{""},
+	},
+	"substr": {
+		Description:      "`substr` extracts a substring from a given string by offset and (maximum) length.",
+		ParamDescription: []string{"", "", ""},
+	},
+	"sum": {
+		Description:      "`sum` takes a list or set of numbers and returns the sum of those numbers.",
+		ParamDescription: []string{""},
+	},
+	"templatefile": {
+		Description:      "`templatefile` reads the file at the given path and renders its content as a template using a supplied set of template variables.",
+		ParamDescription: []string{"", ""},
+	},
+	"textdecodebase64": {
+		Description:      "`textdecodebase64` function decodes a string that was previously Base64-encoded, and then interprets the result as characters in a specified character encoding.",
+		ParamDescription: []string{"", ""},
+	},
+	"textencodebase64": {
+		Description:      "`textencodebase64` encodes the unicode characters in a given string using a specified character encoding, returning the result base64 encoded because Terraform language strings are always sequences of unicode characters.",
+		ParamDescription: []string{"", ""},
+	},
+	"timeadd": {
+		Description:      "`timeadd` adds a duration to a timestamp, returning a new timestamp.",
+		ParamDescription: []string{"", ""},
+	},
+	"timecmp": {
+		Description:      "`timecmp` compares two timestamps and returns a number that represents the ordering of the instants those timestamps represent.",
+		ParamDescription: []string{"", ""},
+	},
+	"timestamp": {
+		Description:      "`timestamp` returns a UTC timestamp string in [RFC 3339](https://tools.ietf.org/html/rfc3339) format.",
+		ParamDescription: []string{},
+	},
+	"plantimestamp": {
+		Description:      "`plantimestamp` returns a UTC timestamp string in [RFC 3339](https://tools.ietf.org/html/rfc3339) format, fixed to a constant time representing the time of the plan.",
+		ParamDescription: []string{},
+	},
+	"title": {
+		Description:      "`title` converts the first letter of each word in the given string to uppercase.",
+		ParamDescription: []string{""},
+	},
+	"tobool": {
+		Description:      "`tobool` converts its argument to a boolean value.",
+		ParamDescription: []string{""},
+	},
+	"tolist": {
+		Description:      "`tolist` converts its argument to a list value.",
+		ParamDescription: []string{""},
+	},
+	"tomap": {
+		Description:      "`tomap` converts its argument to a map value.",
+		ParamDescription: []string{""},
+	},
+	"tonumber": {
+		Description:      "`tonumber` converts its argument to a number value.",
+		ParamDescription: []string{""},
+	},
+	"toset": {
+		Description:      "`toset` converts its argument to a set value.",
+		ParamDescription: []string{""},
+	},
+	"tostring": {
+		Description:      "`tostring` converts its argument to a string value.",
+		ParamDescription: []string{""},
+	},
+	"transpose": {
+		Description:      "`transpose` takes a map of lists of strings and swaps the keys and values to produce a new map of lists of strings.",
+		ParamDescription: []string{""},
+	},
+	"trim": {
+		Description: "`trim` removes the specified set of characters from the start and end of the given string.",
+		ParamDescription: []string{
+			"",
+			"A string containing all of the characters to trim. Each character is taken separately, so the order of characters is insignificant.",
+		},
+	},
+	"trimprefix": {
+		Description:      "`trimprefix` removes the specified prefix from the start of the given string. If the string does not start with the prefix, the string is returned unchanged.",
+		ParamDescription: []string{"", ""},
+	},
+	"trimspace": {
+		Description:      "`trimspace` removes any space characters from the start and end of the given string.",
+		ParamDescription: []string{""},
+	},
+	"trimsuffix": {
+		Description:      "`trimsuffix` removes the specified suffix from the end of the given string.",
+		ParamDescription: []string{"", ""},
+	},
+	"try": {
+		Description:      "`try` evaluates all of its argument expressions in turn and returns the result of the first one that does not produce any errors.",
+		ParamDescription: []string{""},
+	},
+	"type": {
+		Description:      "`type` returns the type of a given value.",
+		ParamDescription: []string{""},
+	},
+	"upper": {
+		Description:      "`upper` converts all cased letters in the given string to uppercase.",
+		ParamDescription: []string{""},
+	},
+	"urlencode": {
+		Description:      "`urlencode` applies URL encoding to a given string.",
+		ParamDescription: []string{""},
+	},
+	"uuid": {
+		Description:      "`uuid` generates a unique identifier string.",
+		ParamDescription: []string{},
+	},
+	"uuidv5": {
+		Description:      "`uuidv5` generates a _name-based_ UUID, as described in [RFC 4122 section 4.3](https://tools.ietf.org/html/rfc4122#section-4.3), also known as a \"version 5\" UUID.",
+		ParamDescription: []string{"", ""},
+	},
+	"values": {
+		Description:      "`values` takes a map and returns a list containing the values of the elements in that map.",
+		ParamDescription: []string{""},
+	},
+	"yamldecode": {
+		Description:      "`yamldecode` parses a string as a subset of YAML, and produces a representation of its value.",
+		ParamDescription: []string{""},
+	},
+	"yamlencode": {
+		Description:      "`yamlencode` encodes a given value to a string using [YAML 1.2](https://yaml.org/spec/1.2/spec.html) block syntax.",
+		ParamDescription: []string{""},
+	},
+	"zipmap": {
+		Description:      "`zipmap` constructs a map from a list of keys and a corresponding list of values.",
+		ParamDescription: []string{"", ""},
+	},
+}
+
+// WithDescription looks up the description for a given function and uses
+// go-cty's WithNewDescriptions to replace the function's description and
+// parameter descriptions.
+func WithDescription(name string, f function.Function) function.Function {
+	desc, ok := DescriptionList[name]
+	if !ok {
+		return f
+	}
+
+	// Will panic if ParamDescription doesn't match the number of parameters
+	// the function expects
+	return f.WithNewDescriptions(desc.Description, desc.ParamDescription)
+}
diff --git a/v1.5.7/internal/lang/funcs/encoding.go b/v1.5.7/internal/lang/funcs/encoding.go
new file mode 100644
index 0000000..c00d416
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/encoding.go
@@ -0,0 +1,258 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"bytes"
+	"compress/gzip"
+	"encoding/base64"
+	"fmt"
+	"log"
+	"net/url"
+	"unicode/utf8"
+
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+	"golang.org/x/text/encoding/ianaindex"
+)
+
+// Base64DecodeFunc constructs a function that decodes a string containing a base64 sequence.
+var Base64DecodeFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name:        "str",
+			Type:        cty.String,
+			AllowMarked: true,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		str, strMarks := args[0].Unmark()
+		s := str.AsString()
+		sDec, err := base64.StdEncoding.DecodeString(s)
+		if err != nil {
+			return cty.UnknownVal(cty.String), fmt.Errorf("failed to decode base64 data %s", redactIfSensitive(s, strMarks))
+		}
+		if !utf8.Valid([]byte(sDec)) {
+			log.Printf("[DEBUG] the result of decoding the provided string is not valid UTF-8: %s", redactIfSensitive(sDec, strMarks))
+			return cty.UnknownVal(cty.String), fmt.Errorf("the result of decoding the provided string is not valid UTF-8")
+		}
+		return cty.StringVal(string(sDec)).WithMarks(strMarks), nil
+	},
+})
+
+// Base64EncodeFunc constructs a function that encodes a string to a base64 sequence.
+var Base64EncodeFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "str",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		return cty.StringVal(base64.StdEncoding.EncodeToString([]byte(args[0].AsString()))), nil
+	},
+})
+
+// TextEncodeBase64Func constructs a function that encodes a string to a target encoding and then to a base64 sequence.
+var TextEncodeBase64Func = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "string",
+			Type: cty.String,
+		},
+		{
+			Name: "encoding",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		encoding, err := ianaindex.IANA.Encoding(args[1].AsString())
+		if err != nil || encoding == nil {
+			return cty.UnknownVal(cty.String), function.NewArgErrorf(1, "%q is not a supported IANA encoding name or alias in this Terraform version", args[1].AsString())
+		}
+
+		encName, err := ianaindex.IANA.Name(encoding)
+		if err != nil { // would be weird, since we just read this encoding out
+			encName = args[1].AsString()
+		}
+
+		encoder := encoding.NewEncoder()
+		encodedInput, err := encoder.Bytes([]byte(args[0].AsString()))
+		if err != nil {
+			// The string representations of "err" disclose implementation
+			// details of the underlying library, and the main error we might
+			// like to return a special message for is unexported as
+			// golang.org/x/text/encoding/internal.RepertoireError, so this
+			// is just a generic error message for now.
+			//
+			// We also don't include the string itself in the message because
+			// it can typically be very large, contain newline characters,
+			// etc.
+			return cty.UnknownVal(cty.String), function.NewArgErrorf(0, "the given string contains characters that cannot be represented in %s", encName)
+		}
+
+		return cty.StringVal(base64.StdEncoding.EncodeToString(encodedInput)), nil
+	},
+})
+
+// TextDecodeBase64Func constructs a function that decodes a base64 sequence to a target encoding.
+var TextDecodeBase64Func = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "source",
+			Type: cty.String,
+		},
+		{
+			Name: "encoding",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		encoding, err := ianaindex.IANA.Encoding(args[1].AsString())
+		if err != nil || encoding == nil {
+			return cty.UnknownVal(cty.String), function.NewArgErrorf(1, "%q is not a supported IANA encoding name or alias in this Terraform version", args[1].AsString())
+		}
+
+		encName, err := ianaindex.IANA.Name(encoding)
+		if err != nil { // would be weird, since we just read this encoding out
+			encName = args[1].AsString()
+		}
+
+		s := args[0].AsString()
+		sDec, err := base64.StdEncoding.DecodeString(s)
+		if err != nil {
+			switch err := err.(type) {
+			case base64.CorruptInputError:
+				return cty.UnknownVal(cty.String), function.NewArgErrorf(0, "the given value is has an invalid base64 symbol at offset %d", int(err))
+			default:
+				return cty.UnknownVal(cty.String), function.NewArgErrorf(0, "invalid source string: %w", err)
+			}
+
+		}
+
+		decoder := encoding.NewDecoder()
+		decoded, err := decoder.Bytes(sDec)
+		if err != nil || bytes.ContainsRune(decoded, '�') {
+			return cty.UnknownVal(cty.String), function.NewArgErrorf(0, "the given string contains symbols that are not defined for %s", encName)
+		}
+
+		return cty.StringVal(string(decoded)), nil
+	},
+})
+
+// Base64GzipFunc constructs a function that compresses a string with gzip and then encodes the result in
+// Base64 encoding.
+var Base64GzipFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "str",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		s := args[0].AsString()
+
+		var b bytes.Buffer
+		gz := gzip.NewWriter(&b)
+		if _, err := gz.Write([]byte(s)); err != nil {
+			return cty.UnknownVal(cty.String), fmt.Errorf("failed to write gzip raw data: %w", err)
+		}
+		if err := gz.Flush(); err != nil {
+			return cty.UnknownVal(cty.String), fmt.Errorf("failed to flush gzip writer: %w", err)
+		}
+		if err := gz.Close(); err != nil {
+			return cty.UnknownVal(cty.String), fmt.Errorf("failed to close gzip writer: %w", err)
+		}
+		return cty.StringVal(base64.StdEncoding.EncodeToString(b.Bytes())), nil
+	},
+})
+
+// URLEncodeFunc constructs a function that applies URL encoding to a given string.
+var URLEncodeFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "str",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		return cty.StringVal(url.QueryEscape(args[0].AsString())), nil
+	},
+})
+
+// Base64Decode decodes a string containing a base64 sequence.
+//
+// Terraform uses the "standard" Base64 alphabet as defined in RFC 4648 section 4.
+//
+// Strings in the Terraform language are sequences of unicode characters rather
+// than bytes, so this function will also interpret the resulting bytes as
+// UTF-8. If the bytes after Base64 decoding are _not_ valid UTF-8, this function
+// produces an error.
+func Base64Decode(str cty.Value) (cty.Value, error) {
+	return Base64DecodeFunc.Call([]cty.Value{str})
+}
+
+// Base64Encode applies Base64 encoding to a string.
+//
+// Terraform uses the "standard" Base64 alphabet as defined in RFC 4648 section 4.
+//
+// Strings in the Terraform language are sequences of unicode characters rather
+// than bytes, so this function will first encode the characters from the string
+// as UTF-8, and then apply Base64 encoding to the result.
+func Base64Encode(str cty.Value) (cty.Value, error) {
+	return Base64EncodeFunc.Call([]cty.Value{str})
+}
+
+// Base64Gzip compresses a string with gzip and then encodes the result in
+// Base64 encoding.
+//
+// Terraform uses the "standard" Base64 alphabet as defined in RFC 4648 section 4.
+//
+// Strings in the Terraform language are sequences of unicode characters rather
+// than bytes, so this function will first encode the characters from the string
+// as UTF-8, then apply gzip compression, and then finally apply Base64 encoding.
+func Base64Gzip(str cty.Value) (cty.Value, error) {
+	return Base64GzipFunc.Call([]cty.Value{str})
+}
+
+// URLEncode applies URL encoding to a given string.
+//
+// This function identifies characters in the given string that would have a
+// special meaning when included as a query string argument in a URL and
+// escapes them using RFC 3986 "percent encoding".
+//
+// If the given string contains non-ASCII characters, these are first encoded as
+// UTF-8 and then percent encoding is applied separately to each UTF-8 byte.
+func URLEncode(str cty.Value) (cty.Value, error) {
+	return URLEncodeFunc.Call([]cty.Value{str})
+}
+
+// TextEncodeBase64 applies Base64 encoding to a string that was encoded before with a target encoding.
+//
+// Terraform uses the "standard" Base64 alphabet as defined in RFC 4648 section 4.
+//
+// First step is to apply the target IANA encoding (e.g. UTF-16LE).
+// Strings in the Terraform language are sequences of unicode characters rather
+// than bytes, so this function will first encode the characters from the string
+// as UTF-8, and then apply Base64 encoding to the result.
+func TextEncodeBase64(str, enc cty.Value) (cty.Value, error) {
+	return TextEncodeBase64Func.Call([]cty.Value{str, enc})
+}
+
+// TextDecodeBase64 decodes a string containing a base64 sequence whereas a specific encoding of the string is expected.
+//
+// Terraform uses the "standard" Base64 alphabet as defined in RFC 4648 section 4.
+//
+// Strings in the Terraform language are sequences of unicode characters rather
+// than bytes, so this function will also interpret the resulting bytes as
+// the target encoding.
+func TextDecodeBase64(str, enc cty.Value) (cty.Value, error) {
+	return TextDecodeBase64Func.Call([]cty.Value{str, enc})
+}
diff --git a/v1.5.7/internal/lang/funcs/encoding_test.go b/v1.5.7/internal/lang/funcs/encoding_test.go
new file mode 100644
index 0000000..4c556f8
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/encoding_test.go
@@ -0,0 +1,362 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestBase64Decode(t *testing.T) {
+	tests := []struct {
+		String cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		{
+			cty.StringVal("YWJjMTIzIT8kKiYoKSctPUB+"),
+			cty.StringVal("abc123!?$*&()'-=@~"),
+			false,
+		},
+		{
+			cty.StringVal("YWJjMTIzIT8kKiYoKSctPUB+").Mark(marks.Sensitive),
+			cty.StringVal("abc123!?$*&()'-=@~").Mark(marks.Sensitive),
+			false,
+		},
+		{ // Invalid base64 data decoding
+			cty.StringVal("this-is-an-invalid-base64-data"),
+			cty.UnknownVal(cty.String),
+			true,
+		},
+		{ // Invalid utf-8
+			cty.StringVal("\xc3\x28"),
+			cty.UnknownVal(cty.String),
+			true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("base64decode(%#v)", test.String), func(t *testing.T) {
+			got, err := Base64Decode(test.String)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestBase64Decode_error(t *testing.T) {
+	tests := map[string]struct {
+		String  cty.Value
+		WantErr string
+	}{
+		"invalid base64": {
+			cty.StringVal("dfg"),
+			`failed to decode base64 data "dfg"`,
+		},
+		"sensitive invalid base64": {
+			cty.StringVal("dfg").Mark(marks.Sensitive),
+			`failed to decode base64 data (sensitive value)`,
+		},
+		"invalid utf-8": {
+			cty.StringVal("whee"),
+			"the result of decoding the provided string is not valid UTF-8",
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			_, err := Base64Decode(test.String)
+
+			if err == nil {
+				t.Fatal("succeeded; want error")
+			}
+
+			if err.Error() != test.WantErr {
+				t.Errorf("wrong error result\ngot:  %#v\nwant: %#v", err.Error(), test.WantErr)
+			}
+		})
+	}
+}
+
+func TestBase64Encode(t *testing.T) {
+	tests := []struct {
+		String cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		{
+			cty.StringVal("abc123!?$*&()'-=@~"),
+			cty.StringVal("YWJjMTIzIT8kKiYoKSctPUB+"),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("base64encode(%#v)", test.String), func(t *testing.T) {
+			got, err := Base64Encode(test.String)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestBase64Gzip(t *testing.T) {
+	tests := []struct {
+		String cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		{
+			cty.StringVal("test"),
+			cty.StringVal("H4sIAAAAAAAA/ypJLS4BAAAA//8BAAD//wx+f9gEAAAA"),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("base64gzip(%#v)", test.String), func(t *testing.T) {
+			got, err := Base64Gzip(test.String)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestURLEncode(t *testing.T) {
+	tests := []struct {
+		String cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		{
+			cty.StringVal("abc123-_"),
+			cty.StringVal("abc123-_"),
+			false,
+		},
+		{
+			cty.StringVal("foo:bar@localhost?foo=bar&bar=baz"),
+			cty.StringVal("foo%3Abar%40localhost%3Ffoo%3Dbar%26bar%3Dbaz"),
+			false,
+		},
+		{
+			cty.StringVal("mailto:email?subject=this+is+my+subject"),
+			cty.StringVal("mailto%3Aemail%3Fsubject%3Dthis%2Bis%2Bmy%2Bsubject"),
+			false,
+		},
+		{
+			cty.StringVal("foo/bar"),
+			cty.StringVal("foo%2Fbar"),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("urlencode(%#v)", test.String), func(t *testing.T) {
+			got, err := URLEncode(test.String)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestBase64TextEncode(t *testing.T) {
+	tests := []struct {
+		String   cty.Value
+		Encoding cty.Value
+		Want     cty.Value
+		Err      string
+	}{
+		{
+			cty.StringVal("abc123!?$*&()'-=@~"),
+			cty.StringVal("UTF-8"),
+			cty.StringVal("YWJjMTIzIT8kKiYoKSctPUB+"),
+			``,
+		},
+		{
+			cty.StringVal("abc123!?$*&()'-=@~"),
+			cty.StringVal("UTF-16LE"),
+			cty.StringVal("YQBiAGMAMQAyADMAIQA/ACQAKgAmACgAKQAnAC0APQBAAH4A"),
+			``,
+		},
+		{
+			cty.StringVal("abc123!?$*&()'-=@~"),
+			cty.StringVal("CP936"),
+			cty.StringVal("YWJjMTIzIT8kKiYoKSctPUB+"),
+			``,
+		},
+		{
+			cty.StringVal("abc123!?$*&()'-=@~"),
+			cty.StringVal("NOT-EXISTS"),
+			cty.UnknownVal(cty.String),
+			`"NOT-EXISTS" is not a supported IANA encoding name or alias in this Terraform version`,
+		},
+		{
+			cty.StringVal("🤔"),
+			cty.StringVal("cp437"),
+			cty.UnknownVal(cty.String),
+			`the given string contains characters that cannot be represented in IBM437`,
+		},
+		{
+			cty.UnknownVal(cty.String),
+			cty.StringVal("windows-1250"),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+		{
+			cty.StringVal("hello world"),
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("textencodebase64(%#v, %#v)", test.String, test.Encoding), func(t *testing.T) {
+			got, err := TextEncodeBase64(test.String, test.Encoding)
+
+			if test.Err != "" {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				if got, want := err.Error(), test.Err; got != want {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestBase64TextDecode(t *testing.T) {
+	tests := []struct {
+		String   cty.Value
+		Encoding cty.Value
+		Want     cty.Value
+		Err      string
+	}{
+		{
+			cty.StringVal("YWJjMTIzIT8kKiYoKSctPUB+"),
+			cty.StringVal("UTF-8"),
+			cty.StringVal("abc123!?$*&()'-=@~"),
+			``,
+		},
+		{
+			cty.StringVal("YQBiAGMAMQAyADMAIQA/ACQAKgAmACgAKQAnAC0APQBAAH4A"),
+			cty.StringVal("UTF-16LE"),
+			cty.StringVal("abc123!?$*&()'-=@~"),
+			``,
+		},
+		{
+			cty.StringVal("YWJjMTIzIT8kKiYoKSctPUB+"),
+			cty.StringVal("CP936"),
+			cty.StringVal("abc123!?$*&()'-=@~"),
+			``,
+		},
+		{
+			cty.StringVal("doesn't matter"),
+			cty.StringVal("NOT-EXISTS"),
+			cty.UnknownVal(cty.String),
+			`"NOT-EXISTS" is not a supported IANA encoding name or alias in this Terraform version`,
+		},
+		{
+			cty.StringVal("<invalid base64>"),
+			cty.StringVal("cp437"),
+			cty.UnknownVal(cty.String),
+			`the given value is has an invalid base64 symbol at offset 0`,
+		},
+		{
+			cty.StringVal("gQ=="), // this is 0x81, which is not defined in windows-1250
+			cty.StringVal("windows-1250"),
+			cty.StringVal("�"),
+			`the given string contains symbols that are not defined for windows-1250`,
+		},
+		{
+			cty.UnknownVal(cty.String),
+			cty.StringVal("windows-1250"),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+		{
+			cty.StringVal("YQBiAGMAMQAyADMAIQA/ACQAKgAmACgAKQAnAC0APQBAAH4A"),
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("textdecodebase64(%#v, %#v)", test.String, test.Encoding), func(t *testing.T) {
+			got, err := TextDecodeBase64(test.String, test.Encoding)
+
+			if test.Err != "" {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				if got, want := err.Error(), test.Err; got != want {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/lang/funcs/filesystem.go b/v1.5.7/internal/lang/funcs/filesystem.go
new file mode 100644
index 0000000..2399fc7
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/filesystem.go
@@ -0,0 +1,503 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"encoding/base64"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"unicode/utf8"
+
+	"github.com/bmatcuk/doublestar"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	homedir "github.com/mitchellh/go-homedir"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+)
+
+// MakeFileFunc constructs a function that takes a file path and returns the
+// contents of that file, either directly as a string (where valid UTF-8 is
+// required) or as a string containing base64 bytes.
+func MakeFileFunc(baseDir string, encBase64 bool) function.Function {
+	return function.New(&function.Spec{
+		Params: []function.Parameter{
+			{
+				Name:        "path",
+				Type:        cty.String,
+				AllowMarked: true,
+			},
+		},
+		Type: function.StaticReturnType(cty.String),
+		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+			pathArg, pathMarks := args[0].Unmark()
+			path := pathArg.AsString()
+			src, err := readFileBytes(baseDir, path, pathMarks)
+			if err != nil {
+				err = function.NewArgError(0, err)
+				return cty.UnknownVal(cty.String), err
+			}
+
+			switch {
+			case encBase64:
+				enc := base64.StdEncoding.EncodeToString(src)
+				return cty.StringVal(enc).WithMarks(pathMarks), nil
+			default:
+				if !utf8.Valid(src) {
+					return cty.UnknownVal(cty.String), fmt.Errorf("contents of %s are not valid UTF-8; use the filebase64 function to obtain the Base64 encoded contents or the other file functions (e.g. filemd5, filesha256) to obtain file hashing results instead", redactIfSensitive(path, pathMarks))
+				}
+				return cty.StringVal(string(src)).WithMarks(pathMarks), nil
+			}
+		},
+	})
+}
+
+// MakeTemplateFileFunc constructs a function that takes a file path and
+// an arbitrary object of named values and attempts to render the referenced
+// file as a template using HCL template syntax.
+//
+// The template itself may recursively call other functions so a callback
+// must be provided to get access to those functions. The template cannot,
+// however, access any variables defined in the scope: it is restricted only to
+// those variables provided in the second function argument, to ensure that all
+// dependencies on other graph nodes can be seen before executing this function.
+//
+// As a special exception, a referenced template file may not recursively call
+// the templatefile function, since that would risk the same file being
+// included into itself indefinitely.
+func MakeTemplateFileFunc(baseDir string, funcsCb func() map[string]function.Function) function.Function {
+
+	params := []function.Parameter{
+		{
+			Name:        "path",
+			Type:        cty.String,
+			AllowMarked: true,
+		},
+		{
+			Name: "vars",
+			Type: cty.DynamicPseudoType,
+		},
+	}
+
+	loadTmpl := func(fn string, marks cty.ValueMarks) (hcl.Expression, error) {
+		// We re-use File here to ensure the same filename interpretation
+		// as it does, along with its other safety checks.
+		tmplVal, err := File(baseDir, cty.StringVal(fn).WithMarks(marks))
+		if err != nil {
+			return nil, err
+		}
+
+		expr, diags := hclsyntax.ParseTemplate([]byte(tmplVal.AsString()), fn, hcl.Pos{Line: 1, Column: 1})
+		if diags.HasErrors() {
+			return nil, diags
+		}
+
+		return expr, nil
+	}
+
+	renderTmpl := func(expr hcl.Expression, varsVal cty.Value) (cty.Value, error) {
+		if varsTy := varsVal.Type(); !(varsTy.IsMapType() || varsTy.IsObjectType()) {
+			return cty.DynamicVal, function.NewArgErrorf(1, "invalid vars value: must be a map") // or an object, but we don't strongly distinguish these most of the time
+		}
+
+		ctx := &hcl.EvalContext{
+			Variables: varsVal.AsValueMap(),
+		}
+
+		// We require all of the variables to be valid HCL identifiers, because
+		// otherwise there would be no way to refer to them in the template
+		// anyway. Rejecting this here gives better feedback to the user
+		// than a syntax error somewhere in the template itself.
+		for n := range ctx.Variables {
+			if !hclsyntax.ValidIdentifier(n) {
+				// This error message intentionally doesn't describe _all_ of
+				// the different permutations that are technically valid as an
+				// HCL identifier, but rather focuses on what we might
+				// consider to be an "idiomatic" variable name.
+				return cty.DynamicVal, function.NewArgErrorf(1, "invalid template variable name %q: must start with a letter, followed by zero or more letters, digits, and underscores", n)
+			}
+		}
+
+		// We'll pre-check references in the template here so we can give a
+		// more specialized error message than HCL would by default, so it's
+		// clearer that this problem is coming from a templatefile call.
+		for _, traversal := range expr.Variables() {
+			root := traversal.RootName()
+			if _, ok := ctx.Variables[root]; !ok {
+				return cty.DynamicVal, function.NewArgErrorf(1, "vars map does not contain key %q, referenced at %s", root, traversal[0].SourceRange())
+			}
+		}
+
+		givenFuncs := funcsCb() // this callback indirection is to avoid chicken/egg problems
+		funcs := make(map[string]function.Function, len(givenFuncs))
+		for name, fn := range givenFuncs {
+			if name == "templatefile" {
+				// We stub this one out to prevent recursive calls.
+				funcs[name] = function.New(&function.Spec{
+					Params: params,
+					Type: func(args []cty.Value) (cty.Type, error) {
+						return cty.NilType, fmt.Errorf("cannot recursively call templatefile from inside templatefile call")
+					},
+				})
+				continue
+			}
+			funcs[name] = fn
+		}
+		ctx.Functions = funcs
+
+		val, diags := expr.Value(ctx)
+		if diags.HasErrors() {
+			return cty.DynamicVal, diags
+		}
+		return val, nil
+	}
+
+	return function.New(&function.Spec{
+		Params: params,
+		Type: func(args []cty.Value) (cty.Type, error) {
+			if !(args[0].IsKnown() && args[1].IsKnown()) {
+				return cty.DynamicPseudoType, nil
+			}
+
+			// We'll render our template now to see what result type it produces.
+			// A template consisting only of a single interpolation an potentially
+			// return any type.
+
+			pathArg, pathMarks := args[0].Unmark()
+			expr, err := loadTmpl(pathArg.AsString(), pathMarks)
+			if err != nil {
+				return cty.DynamicPseudoType, err
+			}
+
+			// This is safe even if args[1] contains unknowns because the HCL
+			// template renderer itself knows how to short-circuit those.
+			val, err := renderTmpl(expr, args[1])
+			return val.Type(), err
+		},
+		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+			pathArg, pathMarks := args[0].Unmark()
+			expr, err := loadTmpl(pathArg.AsString(), pathMarks)
+			if err != nil {
+				return cty.DynamicVal, err
+			}
+			result, err := renderTmpl(expr, args[1])
+			return result.WithMarks(pathMarks), err
+		},
+	})
+
+}
+
+// MakeFileExistsFunc constructs a function that takes a path
+// and determines whether a file exists at that path
+func MakeFileExistsFunc(baseDir string) function.Function {
+	return function.New(&function.Spec{
+		Params: []function.Parameter{
+			{
+				Name:        "path",
+				Type:        cty.String,
+				AllowMarked: true,
+			},
+		},
+		Type: function.StaticReturnType(cty.Bool),
+		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+			pathArg, pathMarks := args[0].Unmark()
+			path := pathArg.AsString()
+			path, err := homedir.Expand(path)
+			if err != nil {
+				return cty.UnknownVal(cty.Bool), fmt.Errorf("failed to expand ~: %w", err)
+			}
+
+			if !filepath.IsAbs(path) {
+				path = filepath.Join(baseDir, path)
+			}
+
+			// Ensure that the path is canonical for the host OS
+			path = filepath.Clean(path)
+
+			fi, err := os.Stat(path)
+			if err != nil {
+				if os.IsNotExist(err) {
+					return cty.False.WithMarks(pathMarks), nil
+				}
+				return cty.UnknownVal(cty.Bool), fmt.Errorf("failed to stat %s", redactIfSensitive(path, pathMarks))
+			}
+
+			if fi.Mode().IsRegular() {
+				return cty.True.WithMarks(pathMarks), nil
+			}
+
+			// The Go stat API only provides convenient access to whether it's
+			// a directory or not, so we need to do some bit fiddling to
+			// recognize other irregular file types.
+			filename := redactIfSensitive(path, pathMarks)
+			fileType := fi.Mode().Type()
+			switch {
+			case (fileType & os.ModeDir) != 0:
+				err = function.NewArgErrorf(1, "%s is a directory, not a file", filename)
+			case (fileType & os.ModeDevice) != 0:
+				err = function.NewArgErrorf(1, "%s is a device node, not a regular file", filename)
+			case (fileType & os.ModeNamedPipe) != 0:
+				err = function.NewArgErrorf(1, "%s is a named pipe, not a regular file", filename)
+			case (fileType & os.ModeSocket) != 0:
+				err = function.NewArgErrorf(1, "%s is a unix domain socket, not a regular file", filename)
+			default:
+				// If it's not a type we recognize then we'll just return a
+				// generic error message. This should be very rare.
+				err = function.NewArgErrorf(1, "%s is not a regular file", filename)
+
+				// Note: os.ModeSymlink should be impossible because we used
+				// os.Stat above, not os.Lstat.
+			}
+
+			return cty.False, err
+		},
+	})
+}
+
+// MakeFileSetFunc constructs a function that takes a glob pattern
+// and enumerates a file set from that pattern
+func MakeFileSetFunc(baseDir string) function.Function {
+	return function.New(&function.Spec{
+		Params: []function.Parameter{
+			{
+				Name:        "path",
+				Type:        cty.String,
+				AllowMarked: true,
+			},
+			{
+				Name:        "pattern",
+				Type:        cty.String,
+				AllowMarked: true,
+			},
+		},
+		Type: function.StaticReturnType(cty.Set(cty.String)),
+		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+			pathArg, pathMarks := args[0].Unmark()
+			path := pathArg.AsString()
+			patternArg, patternMarks := args[1].Unmark()
+			pattern := patternArg.AsString()
+
+			marks := []cty.ValueMarks{pathMarks, patternMarks}
+
+			if !filepath.IsAbs(path) {
+				path = filepath.Join(baseDir, path)
+			}
+
+			// Join the path to the glob pattern, while ensuring the full
+			// pattern is canonical for the host OS. The joined path is
+			// automatically cleaned during this operation.
+			pattern = filepath.Join(path, pattern)
+
+			matches, err := doublestar.Glob(pattern)
+			if err != nil {
+				return cty.UnknownVal(cty.Set(cty.String)), fmt.Errorf("failed to glob pattern %s: %w", redactIfSensitive(pattern, marks...), err)
+			}
+
+			var matchVals []cty.Value
+			for _, match := range matches {
+				fi, err := os.Stat(match)
+
+				if err != nil {
+					return cty.UnknownVal(cty.Set(cty.String)), fmt.Errorf("failed to stat %s: %w", redactIfSensitive(match, marks...), err)
+				}
+
+				if !fi.Mode().IsRegular() {
+					continue
+				}
+
+				// Remove the path and file separator from matches.
+				match, err = filepath.Rel(path, match)
+
+				if err != nil {
+					return cty.UnknownVal(cty.Set(cty.String)), fmt.Errorf("failed to trim path of match %s: %w", redactIfSensitive(match, marks...), err)
+				}
+
+				// Replace any remaining file separators with forward slash (/)
+				// separators for cross-system compatibility.
+				match = filepath.ToSlash(match)
+
+				matchVals = append(matchVals, cty.StringVal(match))
+			}
+
+			if len(matchVals) == 0 {
+				return cty.SetValEmpty(cty.String).WithMarks(marks...), nil
+			}
+
+			return cty.SetVal(matchVals).WithMarks(marks...), nil
+		},
+	})
+}
+
+// BasenameFunc constructs a function that takes a string containing a filesystem path
+// and removes all except the last portion from it.
+var BasenameFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "path",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		return cty.StringVal(filepath.Base(args[0].AsString())), nil
+	},
+})
+
+// DirnameFunc constructs a function that takes a string containing a filesystem path
+// and removes the last portion from it.
+var DirnameFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "path",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		return cty.StringVal(filepath.Dir(args[0].AsString())), nil
+	},
+})
+
+// AbsPathFunc constructs a function that converts a filesystem path to an absolute path
+var AbsPathFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "path",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		absPath, err := filepath.Abs(args[0].AsString())
+		return cty.StringVal(filepath.ToSlash(absPath)), err
+	},
+})
+
+// PathExpandFunc constructs a function that expands a leading ~ character to the current user's home directory.
+var PathExpandFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "path",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+
+		homePath, err := homedir.Expand(args[0].AsString())
+		return cty.StringVal(homePath), err
+	},
+})
+
+func openFile(baseDir, path string) (*os.File, error) {
+	path, err := homedir.Expand(path)
+	if err != nil {
+		return nil, fmt.Errorf("failed to expand ~: %w", err)
+	}
+
+	if !filepath.IsAbs(path) {
+		path = filepath.Join(baseDir, path)
+	}
+
+	// Ensure that the path is canonical for the host OS
+	path = filepath.Clean(path)
+
+	return os.Open(path)
+}
+
+func readFileBytes(baseDir, path string, marks cty.ValueMarks) ([]byte, error) {
+	f, err := openFile(baseDir, path)
+	if err != nil {
+		if os.IsNotExist(err) {
+			// An extra Terraform-specific hint for this situation
+			return nil, fmt.Errorf("no file exists at %s; this function works only with files that are distributed as part of the configuration source code, so if this file will be created by a resource in this configuration you must instead obtain this result from an attribute of that resource", redactIfSensitive(path, marks))
+		}
+		return nil, err
+	}
+	defer f.Close()
+
+	src, err := ioutil.ReadAll(f)
+	if err != nil {
+		return nil, fmt.Errorf("failed to read file: %w", err)
+	}
+
+	return src, nil
+}
+
+// File reads the contents of the file at the given path.
+//
+// The file must contain valid UTF-8 bytes, or this function will return an error.
+//
+// The underlying function implementation works relative to a particular base
+// directory, so this wrapper takes a base directory string and uses it to
+// construct the underlying function before calling it.
+func File(baseDir string, path cty.Value) (cty.Value, error) {
+	fn := MakeFileFunc(baseDir, false)
+	return fn.Call([]cty.Value{path})
+}
+
+// FileExists determines whether a file exists at the given path.
+//
+// The underlying function implementation works relative to a particular base
+// directory, so this wrapper takes a base directory string and uses it to
+// construct the underlying function before calling it.
+func FileExists(baseDir string, path cty.Value) (cty.Value, error) {
+	fn := MakeFileExistsFunc(baseDir)
+	return fn.Call([]cty.Value{path})
+}
+
+// FileSet enumerates a set of files given a glob pattern
+//
+// The underlying function implementation works relative to a particular base
+// directory, so this wrapper takes a base directory string and uses it to
+// construct the underlying function before calling it.
+func FileSet(baseDir string, path, pattern cty.Value) (cty.Value, error) {
+	fn := MakeFileSetFunc(baseDir)
+	return fn.Call([]cty.Value{path, pattern})
+}
+
+// FileBase64 reads the contents of the file at the given path.
+//
+// The bytes from the file are encoded as base64 before returning.
+//
+// The underlying function implementation works relative to a particular base
+// directory, so this wrapper takes a base directory string and uses it to
+// construct the underlying function before calling it.
+func FileBase64(baseDir string, path cty.Value) (cty.Value, error) {
+	fn := MakeFileFunc(baseDir, true)
+	return fn.Call([]cty.Value{path})
+}
+
+// Basename takes a string containing a filesystem path and removes all except the last portion from it.
+//
+// The underlying function implementation works only with the path string and does not access the filesystem itself.
+// It is therefore unable to take into account filesystem features such as symlinks.
+//
+// If the path is empty then the result is ".", representing the current working directory.
+func Basename(path cty.Value) (cty.Value, error) {
+	return BasenameFunc.Call([]cty.Value{path})
+}
+
+// Dirname takes a string containing a filesystem path and removes the last portion from it.
+//
+// The underlying function implementation works only with the path string and does not access the filesystem itself.
+// It is therefore unable to take into account filesystem features such as symlinks.
+//
+// If the path is empty then the result is ".", representing the current working directory.
+func Dirname(path cty.Value) (cty.Value, error) {
+	return DirnameFunc.Call([]cty.Value{path})
+}
+
+// Pathexpand takes a string that might begin with a `~` segment, and if so it replaces that segment with
+// the current user's home directory path.
+//
+// The underlying function implementation works only with the path string and does not access the filesystem itself.
+// It is therefore unable to take into account filesystem features such as symlinks.
+//
+// If the leading segment in the path is not `~` then the given path is returned unmodified.
+func Pathexpand(path cty.Value) (cty.Value, error) {
+	return PathExpandFunc.Call([]cty.Value{path})
+}
diff --git a/v1.5.7/internal/lang/funcs/filesystem_test.go b/v1.5.7/internal/lang/funcs/filesystem_test.go
new file mode 100644
index 0000000..8232280
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/filesystem_test.go
@@ -0,0 +1,698 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	homedir "github.com/mitchellh/go-homedir"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+	"github.com/zclconf/go-cty/cty/function/stdlib"
+)
+
+func TestFile(t *testing.T) {
+	tests := []struct {
+		Path cty.Value
+		Want cty.Value
+		Err  string
+	}{
+		{
+			cty.StringVal("testdata/hello.txt"),
+			cty.StringVal("Hello World"),
+			``,
+		},
+		{
+			cty.StringVal("testdata/icon.png"),
+			cty.NilVal,
+			`contents of "testdata/icon.png" are not valid UTF-8; use the filebase64 function to obtain the Base64 encoded contents or the other file functions (e.g. filemd5, filesha256) to obtain file hashing results instead`,
+		},
+		{
+			cty.StringVal("testdata/icon.png").Mark(marks.Sensitive),
+			cty.NilVal,
+			`contents of (sensitive value) are not valid UTF-8; use the filebase64 function to obtain the Base64 encoded contents or the other file functions (e.g. filemd5, filesha256) to obtain file hashing results instead`,
+		},
+		{
+			cty.StringVal("testdata/missing"),
+			cty.NilVal,
+			`no file exists at "testdata/missing"; this function works only with files that are distributed as part of the configuration source code, so if this file will be created by a resource in this configuration you must instead obtain this result from an attribute of that resource`,
+		},
+		{
+			cty.StringVal("testdata/missing").Mark(marks.Sensitive),
+			cty.NilVal,
+			`no file exists at (sensitive value); this function works only with files that are distributed as part of the configuration source code, so if this file will be created by a resource in this configuration you must instead obtain this result from an attribute of that resource`,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("File(\".\", %#v)", test.Path), func(t *testing.T) {
+			got, err := File(".", test.Path)
+
+			if test.Err != "" {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				if got, want := err.Error(), test.Err; got != want {
+					t.Errorf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestTemplateFile(t *testing.T) {
+	tests := []struct {
+		Path cty.Value
+		Vars cty.Value
+		Want cty.Value
+		Err  string
+	}{
+		{
+			cty.StringVal("testdata/hello.txt"),
+			cty.EmptyObjectVal,
+			cty.StringVal("Hello World"),
+			``,
+		},
+		{
+			cty.StringVal("testdata/icon.png"),
+			cty.EmptyObjectVal,
+			cty.NilVal,
+			`contents of "testdata/icon.png" are not valid UTF-8; use the filebase64 function to obtain the Base64 encoded contents or the other file functions (e.g. filemd5, filesha256) to obtain file hashing results instead`,
+		},
+		{
+			cty.StringVal("testdata/missing"),
+			cty.EmptyObjectVal,
+			cty.NilVal,
+			`no file exists at "testdata/missing"; this function works only with files that are distributed as part of the configuration source code, so if this file will be created by a resource in this configuration you must instead obtain this result from an attribute of that resource`,
+		},
+		{
+			cty.StringVal("testdata/secrets.txt").Mark(marks.Sensitive),
+			cty.EmptyObjectVal,
+			cty.NilVal,
+			`no file exists at (sensitive value); this function works only with files that are distributed as part of the configuration source code, so if this file will be created by a resource in this configuration you must instead obtain this result from an attribute of that resource`,
+		},
+		{
+			cty.StringVal("testdata/hello.tmpl"),
+			cty.MapVal(map[string]cty.Value{
+				"name": cty.StringVal("Jodie"),
+			}),
+			cty.StringVal("Hello, Jodie!"),
+			``,
+		},
+		{
+			cty.StringVal("testdata/hello.tmpl"),
+			cty.MapVal(map[string]cty.Value{
+				"name!": cty.StringVal("Jodie"),
+			}),
+			cty.NilVal,
+			`invalid template variable name "name!": must start with a letter, followed by zero or more letters, digits, and underscores`,
+		},
+		{
+			cty.StringVal("testdata/hello.tmpl"),
+			cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("Jimbo"),
+			}),
+			cty.StringVal("Hello, Jimbo!"),
+			``,
+		},
+		{
+			cty.StringVal("testdata/hello.tmpl"),
+			cty.EmptyObjectVal,
+			cty.NilVal,
+			`vars map does not contain key "name", referenced at testdata/hello.tmpl:1,10-14`,
+		},
+		{
+			cty.StringVal("testdata/func.tmpl"),
+			cty.ObjectVal(map[string]cty.Value{
+				"list": cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal("b"),
+					cty.StringVal("c"),
+				}),
+			}),
+			cty.StringVal("The items are a, b, c"),
+			``,
+		},
+		{
+			cty.StringVal("testdata/recursive.tmpl"),
+			cty.MapValEmpty(cty.String),
+			cty.NilVal,
+			`testdata/recursive.tmpl:1,3-16: Error in function call; Call to function "templatefile" failed: cannot recursively call templatefile from inside templatefile call.`,
+		},
+		{
+			cty.StringVal("testdata/list.tmpl"),
+			cty.ObjectVal(map[string]cty.Value{
+				"list": cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal("b"),
+					cty.StringVal("c"),
+				}),
+			}),
+			cty.StringVal("- a\n- b\n- c\n"),
+			``,
+		},
+		{
+			cty.StringVal("testdata/list.tmpl"),
+			cty.ObjectVal(map[string]cty.Value{
+				"list": cty.True,
+			}),
+			cty.NilVal,
+			`testdata/list.tmpl:1,13-17: Iteration over non-iterable value; A value of type bool cannot be used as the collection in a 'for' expression.`,
+		},
+		{
+			cty.StringVal("testdata/bare.tmpl"),
+			cty.ObjectVal(map[string]cty.Value{
+				"val": cty.True,
+			}),
+			cty.True, // since this template contains only an interpolation, its true value shines through
+			``,
+		},
+	}
+
+	templateFileFn := MakeTemplateFileFunc(".", func() map[string]function.Function {
+		return map[string]function.Function{
+			"join":         stdlib.JoinFunc,
+			"templatefile": MakeFileFunc(".", false), // just a placeholder, since templatefile itself overrides this
+		}
+	})
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("TemplateFile(%#v, %#v)", test.Path, test.Vars), func(t *testing.T) {
+			got, err := templateFileFn.Call([]cty.Value{test.Path, test.Vars})
+
+			if argErr, ok := err.(function.ArgError); ok {
+				if argErr.Index < 0 || argErr.Index > 1 {
+					t.Errorf("ArgError index %d is out of range for templatefile (must be 0 or 1)", argErr.Index)
+				}
+			}
+
+			if test.Err != "" {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				if got, want := err.Error(), test.Err; got != want {
+					t.Errorf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestFileExists(t *testing.T) {
+	tests := []struct {
+		Path cty.Value
+		Want cty.Value
+		Err  string
+	}{
+		{
+			cty.StringVal("testdata/hello.txt"),
+			cty.BoolVal(true),
+			``,
+		},
+		{
+			cty.StringVal(""),
+			cty.BoolVal(false),
+			`"." is a directory, not a file`,
+		},
+		{
+			cty.StringVal("testdata").Mark(marks.Sensitive),
+			cty.BoolVal(false),
+			`(sensitive value) is a directory, not a file`,
+		},
+		{
+			cty.StringVal("testdata/missing"),
+			cty.BoolVal(false),
+			``,
+		},
+		{
+			cty.StringVal("testdata/unreadable/foobar"),
+			cty.BoolVal(false),
+			`failed to stat "testdata/unreadable/foobar"`,
+		},
+		{
+			cty.StringVal("testdata/unreadable/foobar").Mark(marks.Sensitive),
+			cty.BoolVal(false),
+			`failed to stat (sensitive value)`,
+		},
+	}
+
+	// Ensure "unreadable" directory cannot be listed during the test run
+	fi, err := os.Lstat("testdata/unreadable")
+	if err != nil {
+		t.Fatal(err)
+	}
+	os.Chmod("testdata/unreadable", 0000)
+	defer func(mode os.FileMode) {
+		os.Chmod("testdata/unreadable", mode)
+	}(fi.Mode())
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("FileExists(\".\", %#v)", test.Path), func(t *testing.T) {
+			got, err := FileExists(".", test.Path)
+
+			if test.Err != "" {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				if got, want := err.Error(), test.Err; got != want {
+					t.Errorf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestFileSet(t *testing.T) {
+	tests := []struct {
+		Path    cty.Value
+		Pattern cty.Value
+		Want    cty.Value
+		Err     string
+	}{
+		{
+			cty.StringVal("."),
+			cty.StringVal("testdata*"),
+			cty.SetValEmpty(cty.String),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("testdata"),
+			cty.SetValEmpty(cty.String),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("{testdata,missing}"),
+			cty.SetValEmpty(cty.String),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("testdata/missing"),
+			cty.SetValEmpty(cty.String),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("testdata/missing*"),
+			cty.SetValEmpty(cty.String),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("*/missing"),
+			cty.SetValEmpty(cty.String),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("**/missing"),
+			cty.SetValEmpty(cty.String),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("testdata/*.txt"),
+			cty.SetVal([]cty.Value{
+				cty.StringVal("testdata/hello.txt"),
+			}),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("testdata/hello.txt"),
+			cty.SetVal([]cty.Value{
+				cty.StringVal("testdata/hello.txt"),
+			}),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("testdata/hello.???"),
+			cty.SetVal([]cty.Value{
+				cty.StringVal("testdata/hello.txt"),
+			}),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("testdata/hello*"),
+			cty.SetVal([]cty.Value{
+				cty.StringVal("testdata/hello.tmpl"),
+				cty.StringVal("testdata/hello.txt"),
+			}),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("testdata/hello.{tmpl,txt}"),
+			cty.SetVal([]cty.Value{
+				cty.StringVal("testdata/hello.tmpl"),
+				cty.StringVal("testdata/hello.txt"),
+			}),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("*/hello.txt"),
+			cty.SetVal([]cty.Value{
+				cty.StringVal("testdata/hello.txt"),
+			}),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("*/*.txt"),
+			cty.SetVal([]cty.Value{
+				cty.StringVal("testdata/hello.txt"),
+			}),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("*/hello*"),
+			cty.SetVal([]cty.Value{
+				cty.StringVal("testdata/hello.tmpl"),
+				cty.StringVal("testdata/hello.txt"),
+			}),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("**/hello*"),
+			cty.SetVal([]cty.Value{
+				cty.StringVal("testdata/hello.tmpl"),
+				cty.StringVal("testdata/hello.txt"),
+			}),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("**/hello.{tmpl,txt}"),
+			cty.SetVal([]cty.Value{
+				cty.StringVal("testdata/hello.tmpl"),
+				cty.StringVal("testdata/hello.txt"),
+			}),
+			``,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("["),
+			cty.SetValEmpty(cty.String),
+			`failed to glob pattern "[": syntax error in pattern`,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("[").Mark(marks.Sensitive),
+			cty.SetValEmpty(cty.String),
+			`failed to glob pattern (sensitive value): syntax error in pattern`,
+		},
+		{
+			cty.StringVal("."),
+			cty.StringVal("\\"),
+			cty.SetValEmpty(cty.String),
+			`failed to glob pattern "\\": syntax error in pattern`,
+		},
+		{
+			cty.StringVal("testdata"),
+			cty.StringVal("missing"),
+			cty.SetValEmpty(cty.String),
+			``,
+		},
+		{
+			cty.StringVal("testdata"),
+			cty.StringVal("missing*"),
+			cty.SetValEmpty(cty.String),
+			``,
+		},
+		{
+			cty.StringVal("testdata"),
+			cty.StringVal("*.txt"),
+			cty.SetVal([]cty.Value{
+				cty.StringVal("hello.txt"),
+			}),
+			``,
+		},
+		{
+			cty.StringVal("testdata"),
+			cty.StringVal("hello.txt"),
+			cty.SetVal([]cty.Value{
+				cty.StringVal("hello.txt"),
+			}),
+			``,
+		},
+		{
+			cty.StringVal("testdata"),
+			cty.StringVal("hello.???"),
+			cty.SetVal([]cty.Value{
+				cty.StringVal("hello.txt"),
+			}),
+			``,
+		},
+		{
+			cty.StringVal("testdata"),
+			cty.StringVal("hello*"),
+			cty.SetVal([]cty.Value{
+				cty.StringVal("hello.tmpl"),
+				cty.StringVal("hello.txt"),
+			}),
+			``,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("FileSet(\".\", %#v, %#v)", test.Path, test.Pattern), func(t *testing.T) {
+			got, err := FileSet(".", test.Path, test.Pattern)
+
+			if test.Err != "" {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				if got, want := err.Error(), test.Err; got != want {
+					t.Errorf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestFileBase64(t *testing.T) {
+	tests := []struct {
+		Path cty.Value
+		Want cty.Value
+		Err  bool
+	}{
+		{
+			cty.StringVal("testdata/hello.txt"),
+			cty.StringVal("SGVsbG8gV29ybGQ="),
+			false,
+		},
+		{
+			cty.StringVal("testdata/icon.png"),
+			cty.StringVal("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAq1BMVEX///9cTuVeUeRcTuZcTuZcT+VbSe1cTuVdT+MAAP9JSbZcT+VcTuZAQLFAQLJcTuVcTuZcUuBBQbA/P7JAQLJaTuRcT+RcTuVGQ7xAQLJVVf9cTuVcTuVGRMFeUeRbTeJcTuU/P7JeTeZbTOVcTeZAQLJBQbNAQLNaUORcTeZbT+VcTuRAQLNAQLRdTuRHR8xgUOdgUN9cTuVdTeRdT+VZTulcTuVAQLL///8+GmETAAAANnRSTlMApibw+osO6DcBB3fIX87+oRk3yehB0/Nj/gNs7nsTRv3dHmu//JYUMLVr3bssjxkgEK5CaxeK03nIAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAADoQAAA6EBvJf9gwAAAAd0SU1FB+EEBRIQDxZNTKsAAACCSURBVBjTfc7JFsFQEATQQpCYxyBEzJ55rvf/f0ZHcyQLvelTd1GngEwWycs5+UISyKLraSi9geWKK9Gr1j7AeqOJVtt2XtD1Bchef2BjQDAcCTC0CsA4mihMtXw2XwgsV2sFw812F+4P3y2GdI6nn3FGSs//4HJNAXDzU4Dg/oj/E+bsEbhf5cMsAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA0LTA1VDE4OjE2OjE1KzAyOjAws5bLVQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNC0wNVQxODoxNjoxNSswMjowMMLLc+kAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAC3RFWHRUaXRsZQBHcm91cJYfIowAAABXelRYdFJhdyBwcm9maWxlIHR5cGUgaXB0YwAAeJzj8gwIcVYoKMpPy8xJ5VIAAyMLLmMLEyMTS5MUAxMgRIA0w2QDI7NUIMvY1MjEzMQcxAfLgEigSi4A6hcRdPJCNZUAAAAASUVORK5CYII="),
+			false,
+		},
+		{
+			cty.StringVal("testdata/missing"),
+			cty.NilVal,
+			true, // no file exists
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("FileBase64(\".\", %#v)", test.Path), func(t *testing.T) {
+			got, err := FileBase64(".", test.Path)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestBasename(t *testing.T) {
+	tests := []struct {
+		Path cty.Value
+		Want cty.Value
+		Err  bool
+	}{
+		{
+			cty.StringVal("testdata/hello.txt"),
+			cty.StringVal("hello.txt"),
+			false,
+		},
+		{
+			cty.StringVal("hello.txt"),
+			cty.StringVal("hello.txt"),
+			false,
+		},
+		{
+			cty.StringVal(""),
+			cty.StringVal("."),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("Basename(%#v)", test.Path), func(t *testing.T) {
+			got, err := Basename(test.Path)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestDirname(t *testing.T) {
+	tests := []struct {
+		Path cty.Value
+		Want cty.Value
+		Err  bool
+	}{
+		{
+			cty.StringVal("testdata/hello.txt"),
+			cty.StringVal("testdata"),
+			false,
+		},
+		{
+			cty.StringVal("testdata/foo/hello.txt"),
+			cty.StringVal("testdata/foo"),
+			false,
+		},
+		{
+			cty.StringVal("hello.txt"),
+			cty.StringVal("."),
+			false,
+		},
+		{
+			cty.StringVal(""),
+			cty.StringVal("."),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("Dirname(%#v)", test.Path), func(t *testing.T) {
+			got, err := Dirname(test.Path)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestPathExpand(t *testing.T) {
+	homePath, err := homedir.Dir()
+	if err != nil {
+		t.Fatalf("Error getting home directory: %v", err)
+	}
+
+	tests := []struct {
+		Path cty.Value
+		Want cty.Value
+		Err  bool
+	}{
+		{
+			cty.StringVal("~/test-file"),
+			cty.StringVal(filepath.Join(homePath, "test-file")),
+			false,
+		},
+		{
+			cty.StringVal("~/another/test/file"),
+			cty.StringVal(filepath.Join(homePath, "another/test/file")),
+			false,
+		},
+		{
+			cty.StringVal("/root/file"),
+			cty.StringVal("/root/file"),
+			false,
+		},
+		{
+			cty.StringVal("/"),
+			cty.StringVal("/"),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("Dirname(%#v)", test.Path), func(t *testing.T) {
+			got, err := Pathexpand(test.Path)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/lang/funcs/number.go b/v1.5.7/internal/lang/funcs/number.go
new file mode 100644
index 0000000..ed36424
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/number.go
@@ -0,0 +1,176 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"math"
+	"math/big"
+
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+	"github.com/zclconf/go-cty/cty/gocty"
+)
+
+// LogFunc contructs a function that returns the logarithm of a given number in a given base.
+var LogFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "num",
+			Type: cty.Number,
+		},
+		{
+			Name: "base",
+			Type: cty.Number,
+		},
+	},
+	Type: function.StaticReturnType(cty.Number),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		var num float64
+		if err := gocty.FromCtyValue(args[0], &num); err != nil {
+			return cty.UnknownVal(cty.String), err
+		}
+
+		var base float64
+		if err := gocty.FromCtyValue(args[1], &base); err != nil {
+			return cty.UnknownVal(cty.String), err
+		}
+
+		return cty.NumberFloatVal(math.Log(num) / math.Log(base)), nil
+	},
+})
+
+// PowFunc contructs a function that returns the logarithm of a given number in a given base.
+var PowFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "num",
+			Type: cty.Number,
+		},
+		{
+			Name: "power",
+			Type: cty.Number,
+		},
+	},
+	Type: function.StaticReturnType(cty.Number),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		var num float64
+		if err := gocty.FromCtyValue(args[0], &num); err != nil {
+			return cty.UnknownVal(cty.String), err
+		}
+
+		var power float64
+		if err := gocty.FromCtyValue(args[1], &power); err != nil {
+			return cty.UnknownVal(cty.String), err
+		}
+
+		return cty.NumberFloatVal(math.Pow(num, power)), nil
+	},
+})
+
+// SignumFunc contructs a function that returns the closest whole number greater
+// than or equal to the given value.
+var SignumFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "num",
+			Type: cty.Number,
+		},
+	},
+	Type: function.StaticReturnType(cty.Number),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		var num int
+		if err := gocty.FromCtyValue(args[0], &num); err != nil {
+			return cty.UnknownVal(cty.String), err
+		}
+		switch {
+		case num < 0:
+			return cty.NumberIntVal(-1), nil
+		case num > 0:
+			return cty.NumberIntVal(+1), nil
+		default:
+			return cty.NumberIntVal(0), nil
+		}
+	},
+})
+
+// ParseIntFunc contructs a function that parses a string argument and returns an integer of the specified base.
+var ParseIntFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name:        "number",
+			Type:        cty.DynamicPseudoType,
+			AllowMarked: true,
+		},
+		{
+			Name:        "base",
+			Type:        cty.Number,
+			AllowMarked: true,
+		},
+	},
+
+	Type: func(args []cty.Value) (cty.Type, error) {
+		if !args[0].Type().Equals(cty.String) {
+			return cty.Number, function.NewArgErrorf(0, "first argument must be a string, not %s", args[0].Type().FriendlyName())
+		}
+		return cty.Number, nil
+	},
+
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		var numstr string
+		var base int
+		var err error
+
+		numArg, numMarks := args[0].Unmark()
+		if err = gocty.FromCtyValue(numArg, &numstr); err != nil {
+			return cty.UnknownVal(cty.String), function.NewArgError(0, err)
+		}
+
+		baseArg, baseMarks := args[1].Unmark()
+		if err = gocty.FromCtyValue(baseArg, &base); err != nil {
+			return cty.UnknownVal(cty.Number), function.NewArgError(1, err)
+		}
+
+		if base < 2 || base > 62 {
+			return cty.UnknownVal(cty.Number), function.NewArgErrorf(
+				1,
+				"base must be a whole number between 2 and 62 inclusive",
+			)
+		}
+
+		num, ok := (&big.Int{}).SetString(numstr, base)
+		if !ok {
+			return cty.UnknownVal(cty.Number), function.NewArgErrorf(
+				0,
+				"cannot parse %s as a base %s integer",
+				redactIfSensitive(numstr, numMarks),
+				redactIfSensitive(base, baseMarks),
+			)
+		}
+
+		parsedNum := cty.NumberVal((&big.Float{}).SetInt(num)).WithMarks(numMarks, baseMarks)
+
+		return parsedNum, nil
+	},
+})
+
+// Log returns returns the logarithm of a given number in a given base.
+func Log(num, base cty.Value) (cty.Value, error) {
+	return LogFunc.Call([]cty.Value{num, base})
+}
+
+// Pow returns the logarithm of a given number in a given base.
+func Pow(num, power cty.Value) (cty.Value, error) {
+	return PowFunc.Call([]cty.Value{num, power})
+}
+
+// Signum determines the sign of a number, returning a number between -1 and
+// 1 to represent the sign.
+func Signum(num cty.Value) (cty.Value, error) {
+	return SignumFunc.Call([]cty.Value{num})
+}
+
+// ParseInt parses a string argument and returns an integer of the specified base.
+func ParseInt(num cty.Value, base cty.Value) (cty.Value, error) {
+	return ParseIntFunc.Call([]cty.Value{num, base})
+}
diff --git a/v1.5.7/internal/lang/funcs/number_test.go b/v1.5.7/internal/lang/funcs/number_test.go
new file mode 100644
index 0000000..ac2f2b6
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/number_test.go
@@ -0,0 +1,387 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestLog(t *testing.T) {
+	tests := []struct {
+		Num  cty.Value
+		Base cty.Value
+		Want cty.Value
+		Err  bool
+	}{
+		{
+			cty.NumberFloatVal(1),
+			cty.NumberFloatVal(10),
+			cty.NumberFloatVal(0),
+			false,
+		},
+		{
+			cty.NumberFloatVal(10),
+			cty.NumberFloatVal(10),
+			cty.NumberFloatVal(1),
+			false,
+		},
+
+		{
+			cty.NumberFloatVal(0),
+			cty.NumberFloatVal(10),
+			cty.NegativeInfinity,
+			false,
+		},
+		{
+			cty.NumberFloatVal(10),
+			cty.NumberFloatVal(0),
+			cty.NumberFloatVal(-0),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("log(%#v, %#v)", test.Num, test.Base), func(t *testing.T) {
+			got, err := Log(test.Num, test.Base)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestPow(t *testing.T) {
+	tests := []struct {
+		Num   cty.Value
+		Power cty.Value
+		Want  cty.Value
+		Err   bool
+	}{
+		{
+			cty.NumberFloatVal(1),
+			cty.NumberFloatVal(0),
+			cty.NumberFloatVal(1),
+			false,
+		},
+		{
+			cty.NumberFloatVal(1),
+			cty.NumberFloatVal(1),
+			cty.NumberFloatVal(1),
+			false,
+		},
+
+		{
+			cty.NumberFloatVal(2),
+			cty.NumberFloatVal(0),
+			cty.NumberFloatVal(1),
+			false,
+		},
+		{
+			cty.NumberFloatVal(2),
+			cty.NumberFloatVal(1),
+			cty.NumberFloatVal(2),
+			false,
+		},
+		{
+			cty.NumberFloatVal(3),
+			cty.NumberFloatVal(2),
+			cty.NumberFloatVal(9),
+			false,
+		},
+		{
+			cty.NumberFloatVal(-3),
+			cty.NumberFloatVal(2),
+			cty.NumberFloatVal(9),
+			false,
+		},
+		{
+			cty.NumberFloatVal(2),
+			cty.NumberFloatVal(-2),
+			cty.NumberFloatVal(0.25),
+			false,
+		},
+		{
+			cty.NumberFloatVal(0),
+			cty.NumberFloatVal(2),
+			cty.NumberFloatVal(0),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("pow(%#v, %#v)", test.Num, test.Power), func(t *testing.T) {
+			got, err := Pow(test.Num, test.Power)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestSignum(t *testing.T) {
+	tests := []struct {
+		Num  cty.Value
+		Want cty.Value
+		Err  bool
+	}{
+		{
+			cty.NumberFloatVal(0),
+			cty.NumberFloatVal(0),
+			false,
+		},
+		{
+			cty.NumberFloatVal(12),
+			cty.NumberFloatVal(1),
+			false,
+		},
+		{
+			cty.NumberFloatVal(-29),
+			cty.NumberFloatVal(-1),
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("signum(%#v)", test.Num), func(t *testing.T) {
+			got, err := Signum(test.Num)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestParseInt(t *testing.T) {
+	tests := []struct {
+		Num  cty.Value
+		Base cty.Value
+		Want cty.Value
+		Err  string
+	}{
+		{
+			cty.StringVal("128"),
+			cty.NumberIntVal(10),
+			cty.NumberIntVal(128),
+			``,
+		},
+		{
+			cty.StringVal("128").Mark(marks.Sensitive),
+			cty.NumberIntVal(10),
+			cty.NumberIntVal(128).Mark(marks.Sensitive),
+			``,
+		},
+		{
+			cty.StringVal("128"),
+			cty.NumberIntVal(10).Mark(marks.Sensitive),
+			cty.NumberIntVal(128).Mark(marks.Sensitive),
+			``,
+		},
+		{
+			cty.StringVal("128").Mark(marks.Sensitive),
+			cty.NumberIntVal(10).Mark(marks.Sensitive),
+			cty.NumberIntVal(128).Mark(marks.Sensitive),
+			``,
+		},
+		{
+			cty.StringVal("128").Mark("boop"),
+			cty.NumberIntVal(10).Mark(marks.Sensitive),
+			cty.NumberIntVal(128).WithMarks(cty.NewValueMarks("boop", marks.Sensitive)),
+			``,
+		},
+		{
+			cty.StringVal("-128"),
+			cty.NumberIntVal(10),
+			cty.NumberIntVal(-128),
+			``,
+		},
+		{
+			cty.StringVal("00128"),
+			cty.NumberIntVal(10),
+			cty.NumberIntVal(128),
+			``,
+		},
+		{
+			cty.StringVal("-00128"),
+			cty.NumberIntVal(10),
+			cty.NumberIntVal(-128),
+			``,
+		},
+		{
+			cty.StringVal("FF00"),
+			cty.NumberIntVal(16),
+			cty.NumberIntVal(65280),
+			``,
+		},
+		{
+			cty.StringVal("ff00"),
+			cty.NumberIntVal(16),
+			cty.NumberIntVal(65280),
+			``,
+		},
+		{
+			cty.StringVal("-FF00"),
+			cty.NumberIntVal(16),
+			cty.NumberIntVal(-65280),
+			``,
+		},
+		{
+			cty.StringVal("00FF00"),
+			cty.NumberIntVal(16),
+			cty.NumberIntVal(65280),
+			``,
+		},
+		{
+			cty.StringVal("-00FF00"),
+			cty.NumberIntVal(16),
+			cty.NumberIntVal(-65280),
+			``,
+		},
+		{
+			cty.StringVal("1011111011101111"),
+			cty.NumberIntVal(2),
+			cty.NumberIntVal(48879),
+			``,
+		},
+		{
+			cty.StringVal("aA"),
+			cty.NumberIntVal(62),
+			cty.NumberIntVal(656),
+			``,
+		},
+		{
+			cty.StringVal("Aa"),
+			cty.NumberIntVal(62),
+			cty.NumberIntVal(2242),
+			``,
+		},
+		{
+			cty.StringVal("999999999999999999999999999999999999999999999999999999999999"),
+			cty.NumberIntVal(10),
+			cty.MustParseNumberVal("999999999999999999999999999999999999999999999999999999999999"),
+			``,
+		},
+		{
+			cty.StringVal("FF"),
+			cty.NumberIntVal(10),
+			cty.UnknownVal(cty.Number),
+			`cannot parse "FF" as a base 10 integer`,
+		},
+		{
+			cty.StringVal("FF").Mark(marks.Sensitive),
+			cty.NumberIntVal(10),
+			cty.UnknownVal(cty.Number),
+			`cannot parse (sensitive value) as a base 10 integer`,
+		},
+		{
+			cty.StringVal("FF").Mark(marks.Sensitive),
+			cty.NumberIntVal(10).Mark(marks.Sensitive),
+			cty.UnknownVal(cty.Number),
+			`cannot parse (sensitive value) as a base (sensitive value) integer`,
+		},
+		{
+			cty.StringVal("00FF"),
+			cty.NumberIntVal(10),
+			cty.UnknownVal(cty.Number),
+			`cannot parse "00FF" as a base 10 integer`,
+		},
+		{
+			cty.StringVal("-00FF"),
+			cty.NumberIntVal(10),
+			cty.UnknownVal(cty.Number),
+			`cannot parse "-00FF" as a base 10 integer`,
+		},
+		{
+			cty.NumberIntVal(2),
+			cty.NumberIntVal(10),
+			cty.UnknownVal(cty.Number),
+			`first argument must be a string, not number`,
+		},
+		{
+			cty.StringVal("1"),
+			cty.NumberIntVal(63),
+			cty.UnknownVal(cty.Number),
+			`base must be a whole number between 2 and 62 inclusive`,
+		},
+		{
+			cty.StringVal("1"),
+			cty.NumberIntVal(-1),
+			cty.UnknownVal(cty.Number),
+			`base must be a whole number between 2 and 62 inclusive`,
+		},
+		{
+			cty.StringVal("1"),
+			cty.NumberIntVal(1),
+			cty.UnknownVal(cty.Number),
+			`base must be a whole number between 2 and 62 inclusive`,
+		},
+		{
+			cty.StringVal("1"),
+			cty.NumberIntVal(0),
+			cty.UnknownVal(cty.Number),
+			`base must be a whole number between 2 and 62 inclusive`,
+		},
+		{
+			cty.StringVal("1.2"),
+			cty.NumberIntVal(10),
+			cty.UnknownVal(cty.Number),
+			`cannot parse "1.2" as a base 10 integer`,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("parseint(%#v, %#v)", test.Num, test.Base), func(t *testing.T) {
+			got, err := ParseInt(test.Num, test.Base)
+
+			if test.Err != "" {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				if got, want := err.Error(), test.Err; got != want {
+					t.Errorf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/lang/funcs/redact.go b/v1.5.7/internal/lang/funcs/redact.go
new file mode 100644
index 0000000..5737850
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/redact.go
@@ -0,0 +1,23 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func redactIfSensitive(value interface{}, markses ...cty.ValueMarks) string {
+	if marks.Has(cty.DynamicVal.WithMarks(markses...), marks.Sensitive) {
+		return "(sensitive value)"
+	}
+	switch v := value.(type) {
+	case string:
+		return fmt.Sprintf("%q", v)
+	default:
+		return fmt.Sprintf("%v", v)
+	}
+}
diff --git a/v1.5.7/internal/lang/funcs/redact_test.go b/v1.5.7/internal/lang/funcs/redact_test.go
new file mode 100644
index 0000000..2c37fd8
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/redact_test.go
@@ -0,0 +1,54 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestRedactIfSensitive(t *testing.T) {
+	testCases := map[string]struct {
+		value interface{}
+		marks []cty.ValueMarks
+		want  string
+	}{
+		"sensitive string": {
+			value: "foo",
+			marks: []cty.ValueMarks{cty.NewValueMarks(marks.Sensitive)},
+			want:  "(sensitive value)",
+		},
+		"marked non-sensitive string": {
+			value: "foo",
+			marks: []cty.ValueMarks{cty.NewValueMarks("boop")},
+			want:  `"foo"`,
+		},
+		"sensitive string with other marks": {
+			value: "foo",
+			marks: []cty.ValueMarks{cty.NewValueMarks("boop"), cty.NewValueMarks(marks.Sensitive)},
+			want:  "(sensitive value)",
+		},
+		"sensitive number": {
+			value: 12345,
+			marks: []cty.ValueMarks{cty.NewValueMarks(marks.Sensitive)},
+			want:  "(sensitive value)",
+		},
+		"non-sensitive number": {
+			value: 12345,
+			marks: []cty.ValueMarks{},
+			want:  "12345",
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			got := redactIfSensitive(tc.value, tc.marks...)
+			if got != tc.want {
+				t.Errorf("wrong result, got %v, want %v", got, tc.want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/lang/funcs/sensitive.go b/v1.5.7/internal/lang/funcs/sensitive.go
new file mode 100644
index 0000000..ea8d3df
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/sensitive.go
@@ -0,0 +1,70 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+)
+
+// SensitiveFunc returns a value identical to its argument except that
+// Terraform will consider it to be sensitive.
+var SensitiveFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name:             "value",
+			Type:             cty.DynamicPseudoType,
+			AllowUnknown:     true,
+			AllowNull:        true,
+			AllowMarked:      true,
+			AllowDynamicType: true,
+		},
+	},
+	Type: func(args []cty.Value) (cty.Type, error) {
+		// This function only affects the value's marks, so the result
+		// type is always the same as the argument type.
+		return args[0].Type(), nil
+	},
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		val, _ := args[0].Unmark()
+		return val.Mark(marks.Sensitive), nil
+	},
+})
+
+// NonsensitiveFunc takes a sensitive value and returns the same value without
+// the sensitive marking, effectively exposing the value.
+var NonsensitiveFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name:             "value",
+			Type:             cty.DynamicPseudoType,
+			AllowUnknown:     true,
+			AllowNull:        true,
+			AllowMarked:      true,
+			AllowDynamicType: true,
+		},
+	},
+	Type: func(args []cty.Value) (cty.Type, error) {
+		// This function only affects the value's marks, so the result
+		// type is always the same as the argument type.
+		return args[0].Type(), nil
+	},
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		if args[0].IsKnown() && !args[0].HasMark(marks.Sensitive) {
+			return cty.DynamicVal, function.NewArgErrorf(0, "the given value is not sensitive, so this call is redundant")
+		}
+		v, m := args[0].Unmark()
+		delete(m, marks.Sensitive) // remove the sensitive marking
+		return v.WithMarks(m), nil
+	},
+})
+
+func Sensitive(v cty.Value) (cty.Value, error) {
+	return SensitiveFunc.Call([]cty.Value{v})
+}
+
+func Nonsensitive(v cty.Value) (cty.Value, error) {
+	return NonsensitiveFunc.Call([]cty.Value{v})
+}
diff --git a/v1.5.7/internal/lang/funcs/sensitive_test.go b/v1.5.7/internal/lang/funcs/sensitive_test.go
new file mode 100644
index 0000000..fb1a75f
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/sensitive_test.go
@@ -0,0 +1,182 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestSensitive(t *testing.T) {
+	tests := []struct {
+		Input   cty.Value
+		WantErr string
+	}{
+		{
+			cty.NumberIntVal(1),
+			``,
+		},
+		{
+			// Unknown values stay unknown while becoming sensitive
+			cty.UnknownVal(cty.String),
+			``,
+		},
+		{
+			// Null values stay unknown while becoming sensitive
+			cty.NullVal(cty.String),
+			``,
+		},
+		{
+			// DynamicVal can be marked as sensitive
+			cty.DynamicVal,
+			``,
+		},
+		{
+			// The marking is shallow only
+			cty.ListVal([]cty.Value{cty.NumberIntVal(1)}),
+			``,
+		},
+		{
+			// A value already marked is allowed and stays marked
+			cty.NumberIntVal(1).Mark(marks.Sensitive),
+			``,
+		},
+		{
+			// A value with some non-standard mark gets "fixed" to be marked
+			// with the standard "sensitive" mark. (This situation occurring
+			// would imply an inconsistency/bug elsewhere, so we're just
+			// being robust about it here.)
+			cty.NumberIntVal(1).Mark("bloop"),
+			``,
+		},
+		{
+			// A value deep already marked is allowed and stays marked,
+			// _and_ we'll also mark the outer collection as sensitive.
+			cty.ListVal([]cty.Value{cty.NumberIntVal(1).Mark(marks.Sensitive)}),
+			``,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("sensitive(%#v)", test.Input), func(t *testing.T) {
+			got, err := Sensitive(test.Input)
+
+			if test.WantErr != "" {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				if got, want := err.Error(), test.WantErr; got != want {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.HasMark(marks.Sensitive) {
+				t.Errorf("result is not marked sensitive")
+			}
+
+			gotRaw, gotMarks := got.Unmark()
+			if len(gotMarks) != 1 {
+				// We're only expecting to have the "sensitive" mark we checked
+				// above. Any others are an error, even if they happen to
+				// appear alongside "sensitive". (We might change this rule
+				// if someday we decide to use marks for some additional
+				// unrelated thing in Terraform, but currently we assume that
+				// _all_ marks imply sensitive, and so returning any other
+				// marks would be confusing.)
+				t.Errorf("extraneous marks %#v", gotMarks)
+			}
+
+			// Disregarding shallow marks, the result should have the same
+			// effective value as the input.
+			wantRaw, _ := test.Input.Unmark()
+			if !gotRaw.RawEquals(wantRaw) {
+				t.Errorf("wrong unmarked result\ngot:  %#v\nwant: %#v", got, wantRaw)
+			}
+		})
+	}
+}
+
+func TestNonsensitive(t *testing.T) {
+	tests := []struct {
+		Input   cty.Value
+		WantErr string
+	}{
+		{
+			cty.NumberIntVal(1).Mark(marks.Sensitive),
+			``,
+		},
+		{
+			cty.DynamicVal.Mark(marks.Sensitive),
+			``,
+		},
+		{
+			cty.UnknownVal(cty.String).Mark(marks.Sensitive),
+			``,
+		},
+		{
+			cty.NullVal(cty.EmptyObject).Mark(marks.Sensitive),
+			``,
+		},
+		{
+			// The inner sensitive remains afterwards
+			cty.ListVal([]cty.Value{cty.NumberIntVal(1).Mark(marks.Sensitive)}).Mark(marks.Sensitive),
+			``,
+		},
+
+		// Passing a value that is already non-sensitive is an error,
+		// because this function should always be used with specific
+		// intention, not just as a "make everything visible" hammer.
+		{
+			cty.NumberIntVal(1),
+			`the given value is not sensitive, so this call is redundant`,
+		},
+		{
+			cty.NullVal(cty.String),
+			`the given value is not sensitive, so this call is redundant`,
+		},
+
+		// Unknown values may become sensitive once they are known, so we
+		// permit them to be marked nonsensitive.
+		{
+			cty.DynamicVal,
+			``,
+		},
+		{
+			cty.UnknownVal(cty.String),
+			``,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("nonsensitive(%#v)", test.Input), func(t *testing.T) {
+			got, err := Nonsensitive(test.Input)
+
+			if test.WantErr != "" {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				if got, want := err.Error(), test.WantErr; got != want {
+					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if got.HasMark(marks.Sensitive) {
+				t.Errorf("result is still marked sensitive")
+			}
+			wantRaw, _ := test.Input.Unmark()
+			if !got.RawEquals(wantRaw) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Input)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/lang/funcs/string.go b/v1.5.7/internal/lang/funcs/string.go
new file mode 100644
index 0000000..ea7ada1
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/string.go
@@ -0,0 +1,134 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"regexp"
+	"strings"
+
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+)
+
+// StartsWithFunc constructs a function that checks if a string starts with
+// a specific prefix using strings.HasPrefix
+var StartsWithFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "str",
+			Type: cty.String,
+		},
+		{
+			Name: "prefix",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.Bool),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		str := args[0].AsString()
+		prefix := args[1].AsString()
+
+		if strings.HasPrefix(str, prefix) {
+			return cty.True, nil
+		}
+
+		return cty.False, nil
+	},
+})
+
+// EndsWithFunc constructs a function that checks if a string ends with
+// a specific suffix using strings.HasSuffix
+var EndsWithFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "str",
+			Type: cty.String,
+		},
+		{
+			Name: "suffix",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.Bool),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		str := args[0].AsString()
+		suffix := args[1].AsString()
+
+		if strings.HasSuffix(str, suffix) {
+			return cty.True, nil
+		}
+
+		return cty.False, nil
+	},
+})
+
+// ReplaceFunc constructs a function that searches a given string for another
+// given substring, and replaces each occurence with a given replacement string.
+var ReplaceFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "str",
+			Type: cty.String,
+		},
+		{
+			Name: "substr",
+			Type: cty.String,
+		},
+		{
+			Name: "replace",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		str := args[0].AsString()
+		substr := args[1].AsString()
+		replace := args[2].AsString()
+
+		// We search/replace using a regexp if the string is surrounded
+		// in forward slashes.
+		if len(substr) > 1 && substr[0] == '/' && substr[len(substr)-1] == '/' {
+			re, err := regexp.Compile(substr[1 : len(substr)-1])
+			if err != nil {
+				return cty.UnknownVal(cty.String), err
+			}
+
+			return cty.StringVal(re.ReplaceAllString(str, replace)), nil
+		}
+
+		return cty.StringVal(strings.Replace(str, substr, replace, -1)), nil
+	},
+})
+
+// Replace searches a given string for another given substring,
+// and replaces all occurences with a given replacement string.
+func Replace(str, substr, replace cty.Value) (cty.Value, error) {
+	return ReplaceFunc.Call([]cty.Value{str, substr, replace})
+}
+
+// StrContainsFunc searches a given string for another given substring,
+// if found the function returns true, otherwise returns false.
+var StrContainsFunc = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "str",
+			Type: cty.String,
+		},
+		{
+			Name: "substr",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.Bool),
+	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+		str := args[0].AsString()
+		substr := args[1].AsString()
+
+		if strings.Contains(str, substr) {
+			return cty.True, nil
+		}
+
+		return cty.False, nil
+	},
+})
diff --git a/v1.5.7/internal/lang/funcs/string_test.go b/v1.5.7/internal/lang/funcs/string_test.go
new file mode 100644
index 0000000..d5c5996
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/string_test.go
@@ -0,0 +1,139 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package funcs
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestReplace(t *testing.T) {
+	tests := []struct {
+		String  cty.Value
+		Substr  cty.Value
+		Replace cty.Value
+		Want    cty.Value
+		Err     bool
+	}{
+		{ // Regular search and replace
+			cty.StringVal("hello"),
+			cty.StringVal("hel"),
+			cty.StringVal("bel"),
+			cty.StringVal("bello"),
+			false,
+		},
+		{ // Search string doesn't match
+			cty.StringVal("hello"),
+			cty.StringVal("nope"),
+			cty.StringVal("bel"),
+			cty.StringVal("hello"),
+			false,
+		},
+		{ // Regular expression
+			cty.StringVal("hello"),
+			cty.StringVal("/l/"),
+			cty.StringVal("L"),
+			cty.StringVal("heLLo"),
+			false,
+		},
+		{
+			cty.StringVal("helo"),
+			cty.StringVal("/(l)/"),
+			cty.StringVal("$1$1"),
+			cty.StringVal("hello"),
+			false,
+		},
+		{ // Bad regexp
+			cty.StringVal("hello"),
+			cty.StringVal("/(l/"),
+			cty.StringVal("$1$1"),
+			cty.UnknownVal(cty.String),
+			true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("replace(%#v, %#v, %#v)", test.String, test.Substr, test.Replace), func(t *testing.T) {
+			got, err := Replace(test.String, test.Substr, test.Replace)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestStrContains(t *testing.T) {
+	tests := []struct {
+		String cty.Value
+		Substr cty.Value
+		Want   cty.Value
+		Err    bool
+	}{
+		{
+			cty.StringVal("hello"),
+			cty.StringVal("hel"),
+			cty.BoolVal(true),
+			false,
+		},
+		{
+			cty.StringVal("hello"),
+			cty.StringVal("lo"),
+			cty.BoolVal(true),
+			false,
+		},
+		{
+			cty.StringVal("hello1"),
+			cty.StringVal("1"),
+			cty.BoolVal(true),
+			false,
+		},
+		{
+			cty.StringVal("hello1"),
+			cty.StringVal("heo"),
+			cty.BoolVal(false),
+			false,
+		},
+		{
+			cty.StringVal("hello1"),
+			cty.NumberIntVal(1),
+			cty.UnknownVal(cty.Bool),
+			true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("includes(%#v, %#v)", test.String, test.Substr), func(t *testing.T) {
+			got, err := StrContains(test.String, test.Substr)
+
+			if test.Err {
+				if err == nil {
+					t.Fatal("succeeded; want error")
+				}
+				return
+			} else if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func StrContains(str, substr cty.Value) (cty.Value, error) {
+	return StrContainsFunc.Call([]cty.Value{str, substr})
+}
diff --git a/v1.5.7/internal/lang/funcs/testdata/bare.tmpl b/v1.5.7/internal/lang/funcs/testdata/bare.tmpl
new file mode 100644
index 0000000..da7cbab
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/testdata/bare.tmpl
@@ -0,0 +1 @@
+${val}
\ No newline at end of file
diff --git a/v1.5.7/internal/lang/funcs/testdata/func.tmpl b/v1.5.7/internal/lang/funcs/testdata/func.tmpl
new file mode 100644
index 0000000..33a2400
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/testdata/func.tmpl
@@ -0,0 +1 @@
+The items are ${join(", ", list)}
\ No newline at end of file
diff --git a/v1.5.7/internal/lang/funcs/testdata/hello.tmpl b/v1.5.7/internal/lang/funcs/testdata/hello.tmpl
new file mode 100644
index 0000000..f112ef8
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/testdata/hello.tmpl
@@ -0,0 +1 @@
+Hello, ${name}!
\ No newline at end of file
diff --git a/v1.5.7/internal/lang/funcs/testdata/hello.txt b/v1.5.7/internal/lang/funcs/testdata/hello.txt
new file mode 100644
index 0000000..5e1c309
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/testdata/hello.txt
@@ -0,0 +1 @@
+Hello World
\ No newline at end of file
diff --git a/v1.5.7/internal/lang/funcs/testdata/icon.png b/v1.5.7/internal/lang/funcs/testdata/icon.png
new file mode 100644
index 0000000..a474f14
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/testdata/icon.png
Binary files differ
diff --git a/v1.5.7/internal/lang/funcs/testdata/list.tmpl b/v1.5.7/internal/lang/funcs/testdata/list.tmpl
new file mode 100644
index 0000000..da8f474
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/testdata/list.tmpl
@@ -0,0 +1,3 @@
+%{ for x in list ~}
+- ${x}
+%{ endfor ~}
diff --git a/v1.5.7/internal/lang/funcs/testdata/recursive.tmpl b/v1.5.7/internal/lang/funcs/testdata/recursive.tmpl
new file mode 100644
index 0000000..f121b60
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/testdata/recursive.tmpl
@@ -0,0 +1 @@
+${templatefile("recursive.tmpl", {})}
\ No newline at end of file
diff --git a/v1.5.7/internal/lang/funcs/testdata/unreadable/foobar b/v1.5.7/internal/lang/funcs/testdata/unreadable/foobar
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/lang/funcs/testdata/unreadable/foobar
diff --git a/v1.5.7/internal/lang/functions.go b/v1.5.7/internal/lang/functions.go
new file mode 100644
index 0000000..5141355
--- /dev/null
+++ b/v1.5.7/internal/lang/functions.go
@@ -0,0 +1,222 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package lang
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2/ext/tryfunc"
+	ctyyaml "github.com/zclconf/go-cty-yaml"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/function"
+	"github.com/zclconf/go-cty/cty/function/stdlib"
+
+	"github.com/hashicorp/terraform/internal/experiments"
+	"github.com/hashicorp/terraform/internal/lang/funcs"
+)
+
+var impureFunctions = []string{
+	"bcrypt",
+	"timestamp",
+	"uuid",
+}
+
+// Functions returns the set of functions that should be used to when evaluating
+// expressions in the receiving scope.
+func (s *Scope) Functions() map[string]function.Function {
+	s.funcsLock.Lock()
+	if s.funcs == nil {
+		// Some of our functions are just directly the cty stdlib functions.
+		// Others are implemented in the subdirectory "funcs" here in this
+		// repository. New functions should generally start out their lives
+		// in the "funcs" directory and potentially graduate to cty stdlib
+		// later if the functionality seems to be something domain-agnostic
+		// that would be useful to all applications using cty functions.
+
+		s.funcs = map[string]function.Function{
+			"abs":              stdlib.AbsoluteFunc,
+			"abspath":          funcs.AbsPathFunc,
+			"alltrue":          funcs.AllTrueFunc,
+			"anytrue":          funcs.AnyTrueFunc,
+			"basename":         funcs.BasenameFunc,
+			"base64decode":     funcs.Base64DecodeFunc,
+			"base64encode":     funcs.Base64EncodeFunc,
+			"base64gzip":       funcs.Base64GzipFunc,
+			"base64sha256":     funcs.Base64Sha256Func,
+			"base64sha512":     funcs.Base64Sha512Func,
+			"bcrypt":           funcs.BcryptFunc,
+			"can":              tryfunc.CanFunc,
+			"ceil":             stdlib.CeilFunc,
+			"chomp":            stdlib.ChompFunc,
+			"cidrhost":         funcs.CidrHostFunc,
+			"cidrnetmask":      funcs.CidrNetmaskFunc,
+			"cidrsubnet":       funcs.CidrSubnetFunc,
+			"cidrsubnets":      funcs.CidrSubnetsFunc,
+			"coalesce":         funcs.CoalesceFunc,
+			"coalescelist":     stdlib.CoalesceListFunc,
+			"compact":          stdlib.CompactFunc,
+			"concat":           stdlib.ConcatFunc,
+			"contains":         stdlib.ContainsFunc,
+			"csvdecode":        stdlib.CSVDecodeFunc,
+			"dirname":          funcs.DirnameFunc,
+			"distinct":         stdlib.DistinctFunc,
+			"element":          stdlib.ElementFunc,
+			"endswith":         funcs.EndsWithFunc,
+			"chunklist":        stdlib.ChunklistFunc,
+			"file":             funcs.MakeFileFunc(s.BaseDir, false),
+			"fileexists":       funcs.MakeFileExistsFunc(s.BaseDir),
+			"fileset":          funcs.MakeFileSetFunc(s.BaseDir),
+			"filebase64":       funcs.MakeFileFunc(s.BaseDir, true),
+			"filebase64sha256": funcs.MakeFileBase64Sha256Func(s.BaseDir),
+			"filebase64sha512": funcs.MakeFileBase64Sha512Func(s.BaseDir),
+			"filemd5":          funcs.MakeFileMd5Func(s.BaseDir),
+			"filesha1":         funcs.MakeFileSha1Func(s.BaseDir),
+			"filesha256":       funcs.MakeFileSha256Func(s.BaseDir),
+			"filesha512":       funcs.MakeFileSha512Func(s.BaseDir),
+			"flatten":          stdlib.FlattenFunc,
+			"floor":            stdlib.FloorFunc,
+			"format":           stdlib.FormatFunc,
+			"formatdate":       stdlib.FormatDateFunc,
+			"formatlist":       stdlib.FormatListFunc,
+			"indent":           stdlib.IndentFunc,
+			"index":            funcs.IndexFunc, // stdlib.IndexFunc is not compatible
+			"join":             stdlib.JoinFunc,
+			"jsondecode":       stdlib.JSONDecodeFunc,
+			"jsonencode":       stdlib.JSONEncodeFunc,
+			"keys":             stdlib.KeysFunc,
+			"length":           funcs.LengthFunc,
+			"list":             funcs.ListFunc,
+			"log":              stdlib.LogFunc,
+			"lookup":           funcs.LookupFunc,
+			"lower":            stdlib.LowerFunc,
+			"map":              funcs.MapFunc,
+			"matchkeys":        funcs.MatchkeysFunc,
+			"max":              stdlib.MaxFunc,
+			"md5":              funcs.Md5Func,
+			"merge":            stdlib.MergeFunc,
+			"min":              stdlib.MinFunc,
+			"one":              funcs.OneFunc,
+			"parseint":         stdlib.ParseIntFunc,
+			"pathexpand":       funcs.PathExpandFunc,
+			"pow":              stdlib.PowFunc,
+			"range":            stdlib.RangeFunc,
+			"regex":            stdlib.RegexFunc,
+			"regexall":         stdlib.RegexAllFunc,
+			"replace":          funcs.ReplaceFunc,
+			"reverse":          stdlib.ReverseListFunc,
+			"rsadecrypt":       funcs.RsaDecryptFunc,
+			"sensitive":        funcs.SensitiveFunc,
+			"nonsensitive":     funcs.NonsensitiveFunc,
+			"setintersection":  stdlib.SetIntersectionFunc,
+			"setproduct":       stdlib.SetProductFunc,
+			"setsubtract":      stdlib.SetSubtractFunc,
+			"setunion":         stdlib.SetUnionFunc,
+			"sha1":             funcs.Sha1Func,
+			"sha256":           funcs.Sha256Func,
+			"sha512":           funcs.Sha512Func,
+			"signum":           stdlib.SignumFunc,
+			"slice":            stdlib.SliceFunc,
+			"sort":             stdlib.SortFunc,
+			"split":            stdlib.SplitFunc,
+			"startswith":       funcs.StartsWithFunc,
+			"strcontains":      funcs.StrContainsFunc,
+			"strrev":           stdlib.ReverseFunc,
+			"substr":           stdlib.SubstrFunc,
+			"sum":              funcs.SumFunc,
+			"textdecodebase64": funcs.TextDecodeBase64Func,
+			"textencodebase64": funcs.TextEncodeBase64Func,
+			"timestamp":        funcs.TimestampFunc,
+			"timeadd":          stdlib.TimeAddFunc,
+			"timecmp":          funcs.TimeCmpFunc,
+			"title":            stdlib.TitleFunc,
+			"tostring":         funcs.MakeToFunc(cty.String),
+			"tonumber":         funcs.MakeToFunc(cty.Number),
+			"tobool":           funcs.MakeToFunc(cty.Bool),
+			"toset":            funcs.MakeToFunc(cty.Set(cty.DynamicPseudoType)),
+			"tolist":           funcs.MakeToFunc(cty.List(cty.DynamicPseudoType)),
+			"tomap":            funcs.MakeToFunc(cty.Map(cty.DynamicPseudoType)),
+			"transpose":        funcs.TransposeFunc,
+			"trim":             stdlib.TrimFunc,
+			"trimprefix":       stdlib.TrimPrefixFunc,
+			"trimspace":        stdlib.TrimSpaceFunc,
+			"trimsuffix":       stdlib.TrimSuffixFunc,
+			"try":              tryfunc.TryFunc,
+			"upper":            stdlib.UpperFunc,
+			"urlencode":        funcs.URLEncodeFunc,
+			"uuid":             funcs.UUIDFunc,
+			"uuidv5":           funcs.UUIDV5Func,
+			"values":           stdlib.ValuesFunc,
+			"yamldecode":       ctyyaml.YAMLDecodeFunc,
+			"yamlencode":       ctyyaml.YAMLEncodeFunc,
+			"zipmap":           stdlib.ZipmapFunc,
+		}
+
+		s.funcs["templatefile"] = funcs.MakeTemplateFileFunc(s.BaseDir, func() map[string]function.Function {
+			// The templatefile function prevents recursive calls to itself
+			// by copying this map and overwriting the "templatefile" entry.
+			return s.funcs
+		})
+
+		if s.ConsoleMode {
+			// The type function is only available in terraform console.
+			s.funcs["type"] = funcs.TypeFunc
+		}
+
+		if !s.ConsoleMode {
+			// The plantimestamp function doesn't make sense in the terraform
+			// console.
+			s.funcs["plantimestamp"] = funcs.MakeStaticTimestampFunc(s.PlanTimestamp)
+		}
+
+		if s.PureOnly {
+			// Force our few impure functions to return unknown so that we
+			// can defer evaluating them until a later pass.
+			for _, name := range impureFunctions {
+				s.funcs[name] = function.Unpredictable(s.funcs[name])
+			}
+		}
+
+		// Add a description to each function and parameter based on the
+		// contents of descriptionList.
+		// One must create a matching description entry whenever a new
+		// function is introduced.
+		for name, f := range s.funcs {
+			s.funcs[name] = funcs.WithDescription(name, f)
+		}
+	}
+	s.funcsLock.Unlock()
+
+	return s.funcs
+}
+
+// experimentalFunction checks whether the given experiment is enabled for
+// the recieving scope. If so, it will return the given function verbatim.
+// If not, it will return a placeholder function that just returns an
+// error explaining that the function requires the experiment to be enabled.
+//
+//lint:ignore U1000 Ignore unused function error for now
+func (s *Scope) experimentalFunction(experiment experiments.Experiment, fn function.Function) function.Function {
+	if s.activeExperiments.Has(experiment) {
+		return fn
+	}
+
+	err := fmt.Errorf(
+		"this function is experimental and available only when the experiment keyword %s is enabled for the current module",
+		experiment.Keyword(),
+	)
+
+	return function.New(&function.Spec{
+		Params:   fn.Params(),
+		VarParam: fn.VarParam(),
+		Type: func(args []cty.Value) (cty.Type, error) {
+			return cty.DynamicPseudoType, err
+		},
+		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+			// It would be weird to get here because the Type function always
+			// fails, but we'll return an error here too anyway just to be
+			// robust.
+			return cty.DynamicVal, err
+		},
+	})
+}
diff --git a/v1.5.7/internal/lang/functions_descriptions_test.go b/v1.5.7/internal/lang/functions_descriptions_test.go
new file mode 100644
index 0000000..210cdae
--- /dev/null
+++ b/v1.5.7/internal/lang/functions_descriptions_test.go
@@ -0,0 +1,33 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package lang
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/lang/funcs"
+)
+
+func TestFunctionDescriptions(t *testing.T) {
+	scope := &Scope{
+		ConsoleMode: true,
+	}
+	// This will implicitly test the parameter description count since
+	// WithNewDescriptions will panic if the number doesn't match.
+	allFunctions := scope.Functions()
+
+	// plantimestamp isn't available with ConsoleMode: true
+	expectedFunctionCount := len(funcs.DescriptionList) - 1
+
+	if len(allFunctions) != expectedFunctionCount {
+		t.Errorf("DescriptionList length expected: %d, got %d", len(allFunctions), expectedFunctionCount)
+	}
+
+	for name := range allFunctions {
+		_, ok := funcs.DescriptionList[name]
+		if !ok {
+			t.Errorf("missing DescriptionList entry for function %q", name)
+		}
+	}
+}
diff --git a/v1.5.7/internal/lang/functions_test.go b/v1.5.7/internal/lang/functions_test.go
new file mode 100644
index 0000000..103b4eb
--- /dev/null
+++ b/v1.5.7/internal/lang/functions_test.go
@@ -0,0 +1,1334 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package lang
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/experiments"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	homedir "github.com/mitchellh/go-homedir"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// TestFunctions tests that functions are callable through the functionality
+// in the langs package, via HCL.
+//
+// These tests are primarily here to assert that the functions are properly
+// registered in the functions table, rather than to test all of the details
+// of the functions. Each function should only have one or two tests here,
+// since the main set of unit tests for a function should live alongside that
+// function either in the "funcs" subdirectory here or over in the cty
+// function/stdlib package.
+//
+// One exception to that is we can use this test mechanism to assert common
+// patterns that are used in real-world configurations which rely on behaviors
+// implemented either in this lang package or in HCL itself, such as automatic
+// type conversions. The function unit tests don't cover those things because
+// they call directly into the functions.
+//
+// With that said then, this test function should contain at least one simple
+// test case per function registered in the functions table (just to prove
+// it really is registered correctly) and possibly a small set of additional
+// functions showing real-world use-cases that rely on type conversion
+// behaviors.
+func TestFunctions(t *testing.T) {
+	// used in `pathexpand()` test
+	homePath, err := homedir.Dir()
+	if err != nil {
+		t.Fatalf("Error getting home directory: %v", err)
+	}
+
+	tests := map[string][]struct {
+		src  string
+		want cty.Value
+	}{
+		// Please maintain this list in alphabetical order by function, with
+		// a blank line between the group of tests for each function.
+
+		"abs": {
+			{
+				`abs(-1)`,
+				cty.NumberIntVal(1),
+			},
+		},
+
+		"abspath": {
+			{
+				`abspath(".")`,
+				cty.StringVal((func() string {
+					cwd, err := os.Getwd()
+					if err != nil {
+						panic(err)
+					}
+					return filepath.ToSlash(cwd)
+				})()),
+			},
+		},
+
+		"alltrue": {
+			{
+				`alltrue(["true", true])`,
+				cty.True,
+			},
+		},
+
+		"anytrue": {
+			{
+				`anytrue([])`,
+				cty.False,
+			},
+		},
+
+		"base64decode": {
+			{
+				`base64decode("YWJjMTIzIT8kKiYoKSctPUB+")`,
+				cty.StringVal("abc123!?$*&()'-=@~"),
+			},
+		},
+
+		"base64encode": {
+			{
+				`base64encode("abc123!?$*&()'-=@~")`,
+				cty.StringVal("YWJjMTIzIT8kKiYoKSctPUB+"),
+			},
+		},
+
+		"base64gzip": {
+			{
+				`base64gzip("test")`,
+				cty.StringVal("H4sIAAAAAAAA/ypJLS4BAAAA//8BAAD//wx+f9gEAAAA"),
+			},
+		},
+
+		"base64sha256": {
+			{
+				`base64sha256("test")`,
+				cty.StringVal("n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg="),
+			},
+		},
+
+		"base64sha512": {
+			{
+				`base64sha512("test")`,
+				cty.StringVal("7iaw3Ur350mqGo7jwQrpkj9hiYB3Lkc/iBml1JQODbJ6wYX4oOHV+E+IvIh/1nsUNzLDBMxfqa2Ob1f1ACio/w=="),
+			},
+		},
+
+		"basename": {
+			{
+				`basename("testdata/hello.txt")`,
+				cty.StringVal("hello.txt"),
+			},
+		},
+
+		"can": {
+			{
+				`can(true)`,
+				cty.True,
+			},
+			{
+				// Note: "can" only works with expressions that pass static
+				// validation, because it only gets an opportunity to run in
+				// that case. The following "works" (captures the error) because
+				// Terraform understands it as a reference to an attribute
+				// that does not exist during dynamic evaluation.
+				//
+				// "can" doesn't work with references that could never possibly
+				// be valid and are thus caught during static validation, such
+				// as an expression like "foo" alone which would be understood
+				// as an invalid resource reference.
+				`can({}.baz)`,
+				cty.False,
+			},
+		},
+
+		"ceil": {
+			{
+				`ceil(1.2)`,
+				cty.NumberIntVal(2),
+			},
+		},
+
+		"chomp": {
+			{
+				`chomp("goodbye\ncruel\nworld\n")`,
+				cty.StringVal("goodbye\ncruel\nworld"),
+			},
+		},
+
+		"chunklist": {
+			{
+				`chunklist(["a", "b", "c"], 1)`,
+				cty.ListVal([]cty.Value{
+					cty.ListVal([]cty.Value{
+						cty.StringVal("a"),
+					}),
+					cty.ListVal([]cty.Value{
+						cty.StringVal("b"),
+					}),
+					cty.ListVal([]cty.Value{
+						cty.StringVal("c"),
+					}),
+				}),
+			},
+		},
+
+		"cidrhost": {
+			{
+				`cidrhost("192.168.1.0/24", 5)`,
+				cty.StringVal("192.168.1.5"),
+			},
+		},
+
+		"cidrnetmask": {
+			{
+				`cidrnetmask("192.168.1.0/24")`,
+				cty.StringVal("255.255.255.0"),
+			},
+		},
+
+		"cidrsubnet": {
+			{
+				`cidrsubnet("192.168.2.0/20", 4, 6)`,
+				cty.StringVal("192.168.6.0/24"),
+			},
+		},
+
+		"cidrsubnets": {
+			{
+				`cidrsubnets("10.0.0.0/8", 8, 8, 16, 8)`,
+				cty.ListVal([]cty.Value{
+					cty.StringVal("10.0.0.0/16"),
+					cty.StringVal("10.1.0.0/16"),
+					cty.StringVal("10.2.0.0/24"),
+					cty.StringVal("10.3.0.0/16"),
+				}),
+			},
+		},
+
+		"coalesce": {
+			{
+				`coalesce("first", "second", "third")`,
+				cty.StringVal("first"),
+			},
+
+			{
+				`coalescelist(["first", "second"], ["third", "fourth"])`,
+				cty.TupleVal([]cty.Value{
+					cty.StringVal("first"), cty.StringVal("second"),
+				}),
+			},
+		},
+
+		"coalescelist": {
+			{
+				`coalescelist(tolist(["a", "b"]), tolist(["c", "d"]))`,
+				cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal("b"),
+				}),
+			},
+			{
+				`coalescelist(["a", "b"], ["c", "d"])`,
+				cty.TupleVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal("b"),
+				}),
+			},
+		},
+
+		"compact": {
+			{
+				`compact(["test", "", "test"])`,
+				cty.ListVal([]cty.Value{
+					cty.StringVal("test"), cty.StringVal("test"),
+				}),
+			},
+		},
+
+		"concat": {
+			{
+				`concat(["a", ""], ["b", "c"])`,
+				cty.TupleVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal(""),
+					cty.StringVal("b"),
+					cty.StringVal("c"),
+				}),
+			},
+		},
+
+		"contains": {
+			{
+				`contains(["a", "b"], "a")`,
+				cty.True,
+			},
+			{ // Should also work with sets, due to automatic conversion
+				`contains(toset(["a", "b"]), "a")`,
+				cty.True,
+			},
+		},
+
+		"csvdecode": {
+			{
+				`csvdecode("a,b,c\n1,2,3\n4,5,6")`,
+				cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"a": cty.StringVal("1"),
+						"b": cty.StringVal("2"),
+						"c": cty.StringVal("3"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"a": cty.StringVal("4"),
+						"b": cty.StringVal("5"),
+						"c": cty.StringVal("6"),
+					}),
+				}),
+			},
+		},
+
+		"dirname": {
+			{
+				`dirname("testdata/hello.txt")`,
+				cty.StringVal("testdata"),
+			},
+		},
+
+		"distinct": {
+			{
+				`distinct(["a", "b", "a", "b"])`,
+				cty.ListVal([]cty.Value{
+					cty.StringVal("a"), cty.StringVal("b"),
+				}),
+			},
+		},
+
+		"element": {
+			{
+				`element(["hello"], 0)`,
+				cty.StringVal("hello"),
+			},
+		},
+
+		"endswith": {
+			{
+				`endswith("hello world", "world")`,
+				cty.True,
+			},
+			{
+				`endswith("hello world", "hello")`,
+				cty.False,
+			},
+			{
+				`endswith("hello world", "")`,
+				cty.True,
+				// Completely empty suffix value  ( "" )
+				// will always evaluate to true for all strings.
+			},
+			{
+				`endswith("hello world", " ")`,
+				cty.False,
+			},
+			{
+				`endswith("", "")`,
+				cty.True,
+			},
+			{
+				`endswith("", " ")`,
+				cty.False,
+			},
+			{
+				`endswith(" ", "")`,
+				cty.True,
+			},
+			{
+				`endswith("", "hello")`,
+				cty.False,
+			},
+			{
+				`endswith(" ", "hello")`,
+				cty.False,
+			},
+		},
+
+		"file": {
+			{
+				`file("hello.txt")`,
+				cty.StringVal("hello!"),
+			},
+		},
+
+		"fileexists": {
+			{
+				`fileexists("hello.txt")`,
+				cty.BoolVal(true),
+			},
+		},
+
+		"fileset": {
+			{
+				`fileset(".", "*/hello.*")`,
+				cty.SetVal([]cty.Value{
+					cty.StringVal("subdirectory/hello.tmpl"),
+					cty.StringVal("subdirectory/hello.txt"),
+				}),
+			},
+			{
+				`fileset(".", "subdirectory/hello.*")`,
+				cty.SetVal([]cty.Value{
+					cty.StringVal("subdirectory/hello.tmpl"),
+					cty.StringVal("subdirectory/hello.txt"),
+				}),
+			},
+			{
+				`fileset(".", "hello.*")`,
+				cty.SetVal([]cty.Value{
+					cty.StringVal("hello.tmpl"),
+					cty.StringVal("hello.txt"),
+				}),
+			},
+			{
+				`fileset("subdirectory", "hello.*")`,
+				cty.SetVal([]cty.Value{
+					cty.StringVal("hello.tmpl"),
+					cty.StringVal("hello.txt"),
+				}),
+			},
+		},
+
+		"filebase64": {
+			{
+				`filebase64("hello.txt")`,
+				cty.StringVal("aGVsbG8h"),
+			},
+		},
+
+		"filebase64sha256": {
+			{
+				`filebase64sha256("hello.txt")`,
+				cty.StringVal("zgYJL7lI2f+sfRo3bkBLJrdXW8wR7gWkYV/vT+w6MIs="),
+			},
+		},
+
+		"filebase64sha512": {
+			{
+				`filebase64sha512("hello.txt")`,
+				cty.StringVal("xvgdsOn4IGyXHJ5YJuO6gj/7saOpAPgEdlKov3jqmP38dFhVo4U6Y1Z1RY620arxIJ6I6tLRkjgrXEy91oUOAg=="),
+			},
+		},
+
+		"filemd5": {
+			{
+				`filemd5("hello.txt")`,
+				cty.StringVal("5a8dd3ad0756a93ded72b823b19dd877"),
+			},
+		},
+
+		"filesha1": {
+			{
+				`filesha1("hello.txt")`,
+				cty.StringVal("8f7d88e901a5ad3a05d8cc0de93313fd76028f8c"),
+			},
+		},
+
+		"filesha256": {
+			{
+				`filesha256("hello.txt")`,
+				cty.StringVal("ce06092fb948d9ffac7d1a376e404b26b7575bcc11ee05a4615fef4fec3a308b"),
+			},
+		},
+
+		"filesha512": {
+			{
+				`filesha512("hello.txt")`,
+				cty.StringVal("c6f81db0e9f8206c971c9e5826e3ba823ffbb1a3a900f8047652a8bf78ea98fdfc745855a3853a635675458eb6d1aaf1209e88ead2d192382b5c4cbdd6850e02"),
+			},
+		},
+
+		"flatten": {
+			{
+				`flatten([["a", "b"], ["c", "d"]])`,
+				cty.TupleVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal("b"),
+					cty.StringVal("c"),
+					cty.StringVal("d"),
+				}),
+			},
+		},
+
+		"floor": {
+			{
+				`floor(-1.8)`,
+				cty.NumberFloatVal(-2),
+			},
+		},
+
+		"format": {
+			{
+				`format("Hello, %s!", "Ander")`,
+				cty.StringVal("Hello, Ander!"),
+			},
+		},
+
+		"formatlist": {
+			{
+				`formatlist("Hello, %s!", ["Valentina", "Ander", "Olivia", "Sam"])`,
+				cty.ListVal([]cty.Value{
+					cty.StringVal("Hello, Valentina!"),
+					cty.StringVal("Hello, Ander!"),
+					cty.StringVal("Hello, Olivia!"),
+					cty.StringVal("Hello, Sam!"),
+				}),
+			},
+		},
+
+		"formatdate": {
+			{
+				`formatdate("DD MMM YYYY hh:mm ZZZ", "2018-01-04T23:12:01Z")`,
+				cty.StringVal("04 Jan 2018 23:12 UTC"),
+			},
+		},
+
+		"indent": {
+			{
+				fmt.Sprintf("indent(4, %#v)", Poem),
+				cty.StringVal("Fleas:\n    Adam\n    Had'em\n    \n    E.E. Cummings"),
+			},
+		},
+
+		"index": {
+			{
+				`index(["a", "b", "c"], "a")`,
+				cty.NumberIntVal(0),
+			},
+		},
+
+		"join": {
+			{
+				`join(" ", ["Hello", "World"])`,
+				cty.StringVal("Hello World"),
+			},
+		},
+
+		"jsondecode": {
+			{
+				`jsondecode("{\"hello\": \"world\"}")`,
+				cty.ObjectVal(map[string]cty.Value{
+					"hello": cty.StringVal("world"),
+				}),
+			},
+		},
+
+		"jsonencode": {
+			{
+				`jsonencode({"hello"="world"})`,
+				cty.StringVal("{\"hello\":\"world\"}"),
+			},
+			// We are intentionally choosing to escape <, >, and & characters
+			// to preserve backwards compatibility with Terraform 0.11
+			{
+				`jsonencode({"hello"="<cats & kittens>"})`,
+				cty.StringVal("{\"hello\":\"\\u003ccats \\u0026 kittens\\u003e\"}"),
+			},
+		},
+
+		"keys": {
+			{
+				`keys({"hello"=1, "goodbye"=42})`,
+				cty.TupleVal([]cty.Value{
+					cty.StringVal("goodbye"),
+					cty.StringVal("hello"),
+				}),
+			},
+		},
+
+		"length": {
+			{
+				`length(["the", "quick", "brown", "bear"])`,
+				cty.NumberIntVal(4),
+			},
+		},
+
+		"list": {
+			// There are intentionally no test cases for "list" because
+			// it is a stub that always returns an error.
+		},
+
+		"log": {
+			{
+				`log(1, 10)`,
+				cty.NumberFloatVal(0),
+			},
+		},
+
+		"lookup": {
+			{
+				`lookup({hello=1, goodbye=42}, "goodbye")`,
+				cty.NumberIntVal(42),
+			},
+		},
+
+		"lower": {
+			{
+				`lower("HELLO")`,
+				cty.StringVal("hello"),
+			},
+		},
+
+		"map": {
+			// There are intentionally no test cases for "map" because
+			// it is a stub that always returns an error.
+		},
+
+		"matchkeys": {
+			{
+				`matchkeys(["a", "b", "c"], ["ref1", "ref2", "ref3"], ["ref1"])`,
+				cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+				}),
+			},
+			{ // mixing types in searchset
+				`matchkeys(["a", "b", "c"], [1, 2, 3], [1, "3"])`,
+				cty.ListVal([]cty.Value{
+					cty.StringVal("a"),
+					cty.StringVal("c"),
+				}),
+			},
+		},
+
+		"max": {
+			{
+				`max(12, 54, 3)`,
+				cty.NumberIntVal(54),
+			},
+		},
+
+		"md5": {
+			{
+				`md5("tada")`,
+				cty.StringVal("ce47d07243bb6eaf5e1322c81baf9bbf"),
+			},
+		},
+
+		"merge": {
+			{
+				`merge({"a"="b"}, {"c"="d"})`,
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.StringVal("b"),
+					"c": cty.StringVal("d"),
+				}),
+			},
+		},
+
+		"min": {
+			{
+				`min(12, 54, 3)`,
+				cty.NumberIntVal(3),
+			},
+		},
+
+		"nonsensitive": {
+			{
+				// Due to how this test is set up we have no way to get
+				// a sensitive value other than to generate one with
+				// another function, so this is a bit odd but does still
+				// meet the goal of verifying that the "nonsensitive"
+				// function is correctly registered.
+				`nonsensitive(sensitive(1))`,
+				cty.NumberIntVal(1),
+			},
+		},
+
+		"one": {
+			{
+				`one([])`,
+				cty.NullVal(cty.DynamicPseudoType),
+			},
+			{
+				`one([true])`,
+				cty.True,
+			},
+		},
+
+		"parseint": {
+			{
+				`parseint("100", 10)`,
+				cty.NumberIntVal(100),
+			},
+		},
+
+		"pathexpand": {
+			{
+				`pathexpand("~/test-file")`,
+				cty.StringVal(filepath.Join(homePath, "test-file")),
+			},
+		},
+
+		"plantimestamp": {
+			{
+				`plantimestamp()`,
+				cty.StringVal("2004-04-25T15:00:00Z"),
+			},
+		},
+
+		"pow": {
+			{
+				`pow(1,0)`,
+				cty.NumberFloatVal(1),
+			},
+		},
+
+		"range": {
+			{
+				`range(3)`,
+				cty.ListVal([]cty.Value{
+					cty.NumberIntVal(0),
+					cty.NumberIntVal(1),
+					cty.NumberIntVal(2),
+				}),
+			},
+			{
+				`range(1, 4)`,
+				cty.ListVal([]cty.Value{
+					cty.NumberIntVal(1),
+					cty.NumberIntVal(2),
+					cty.NumberIntVal(3),
+				}),
+			},
+			{
+				`range(1, 8, 2)`,
+				cty.ListVal([]cty.Value{
+					cty.NumberIntVal(1),
+					cty.NumberIntVal(3),
+					cty.NumberIntVal(5),
+					cty.NumberIntVal(7),
+				}),
+			},
+		},
+
+		"regex": {
+			{
+				`regex("(\\d+)([a-z]+)", "aaa111bbb222")`,
+				cty.TupleVal([]cty.Value{cty.StringVal("111"), cty.StringVal("bbb")}),
+			},
+		},
+
+		"regexall": {
+			{
+				`regexall("(\\d+)([a-z]+)", "...111aaa222bbb...")`,
+				cty.ListVal([]cty.Value{
+					cty.TupleVal([]cty.Value{cty.StringVal("111"), cty.StringVal("aaa")}),
+					cty.TupleVal([]cty.Value{cty.StringVal("222"), cty.StringVal("bbb")}),
+				}),
+			},
+		},
+
+		"replace": {
+			{
+				`replace("hello", "hel", "bel")`,
+				cty.StringVal("bello"),
+			},
+		},
+
+		"reverse": {
+			{
+				`reverse(["a", true, 0])`,
+				cty.TupleVal([]cty.Value{cty.Zero, cty.True, cty.StringVal("a")}),
+			},
+		},
+
+		"rsadecrypt": {
+			{
+				fmt.Sprintf("rsadecrypt(%#v, %#v)", CipherBase64, PrivateKey),
+				cty.StringVal("message"),
+			},
+		},
+
+		"sensitive": {
+			{
+				`sensitive(1)`,
+				cty.NumberIntVal(1).Mark(marks.Sensitive),
+			},
+		},
+
+		"setintersection": {
+			{
+				`setintersection(["a", "b"], ["b", "c"], ["b", "d"])`,
+				cty.SetVal([]cty.Value{
+					cty.StringVal("b"),
+				}),
+			},
+		},
+
+		"setproduct": {
+			{
+				`setproduct(["development", "staging", "production"], ["app1", "app2"])`,
+				cty.ListVal([]cty.Value{
+					cty.TupleVal([]cty.Value{cty.StringVal("development"), cty.StringVal("app1")}),
+					cty.TupleVal([]cty.Value{cty.StringVal("development"), cty.StringVal("app2")}),
+					cty.TupleVal([]cty.Value{cty.StringVal("staging"), cty.StringVal("app1")}),
+					cty.TupleVal([]cty.Value{cty.StringVal("staging"), cty.StringVal("app2")}),
+					cty.TupleVal([]cty.Value{cty.StringVal("production"), cty.StringVal("app1")}),
+					cty.TupleVal([]cty.Value{cty.StringVal("production"), cty.StringVal("app2")}),
+				}),
+			},
+		},
+
+		"setsubtract": {
+			{
+				`setsubtract(["a", "b", "c"], ["a", "c"])`,
+				cty.SetVal([]cty.Value{
+					cty.StringVal("b"),
+				}),
+			},
+		},
+
+		"setunion": {
+			{
+				`setunion(["a", "b"], ["b", "c"], ["d"])`,
+				cty.SetVal([]cty.Value{
+					cty.StringVal("d"),
+					cty.StringVal("b"),
+					cty.StringVal("a"),
+					cty.StringVal("c"),
+				}),
+			},
+		},
+
+		"sha1": {
+			{
+				`sha1("test")`,
+				cty.StringVal("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"),
+			},
+		},
+
+		"sha256": {
+			{
+				`sha256("test")`,
+				cty.StringVal("9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"),
+			},
+		},
+
+		"sha512": {
+			{
+				`sha512("test")`,
+				cty.StringVal("ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff"),
+			},
+		},
+
+		"signum": {
+			{
+				`signum(12)`,
+				cty.NumberFloatVal(1),
+			},
+		},
+
+		"slice": {
+			{
+				// force a list type here for testing
+				`slice(tolist(["a", "b", "c", "d"]), 1, 3)`,
+				cty.ListVal([]cty.Value{
+					cty.StringVal("b"), cty.StringVal("c"),
+				}),
+			},
+			{
+				`slice(["a", "b", 3, 4], 1, 3)`,
+				cty.TupleVal([]cty.Value{
+					cty.StringVal("b"), cty.NumberIntVal(3),
+				}),
+			},
+		},
+
+		"sort": {
+			{
+				`sort(["banana", "apple"])`,
+				cty.ListVal([]cty.Value{
+					cty.StringVal("apple"),
+					cty.StringVal("banana"),
+				}),
+			},
+		},
+
+		"split": {
+			{
+				`split(" ", "Hello World")`,
+				cty.ListVal([]cty.Value{
+					cty.StringVal("Hello"),
+					cty.StringVal("World"),
+				}),
+			},
+		},
+
+		"startswith": {
+			{
+				`startswith("hello world", "hello")`,
+				cty.True,
+			},
+			{
+				`startswith("hello world", "world")`,
+				cty.False,
+			},
+			{
+				`startswith("hello world", "")`,
+				cty.True,
+				// Completely empty prefix value  ( "" )
+				// will always evaluate to true for all strings.
+			},
+			{
+				`startswith("hello world", " ")`,
+				cty.False,
+			},
+			{
+				`startswith("", "")`,
+				cty.True,
+			},
+			{
+				`startswith("", " ")`,
+				cty.False,
+			},
+			{
+				`startswith(" ", "")`,
+				cty.True,
+			},
+			{
+				`startswith("", "hello")`,
+				cty.False,
+			},
+			{
+				`startswith(" ", "hello")`,
+				cty.False,
+			},
+		},
+
+		"strcontains": {
+			{
+				`strcontains("hello", "llo")`,
+				cty.BoolVal(true),
+			},
+			{
+				`strcontains("hello", "a")`,
+				cty.BoolVal(false),
+			},
+		},
+
+		"strrev": {
+			{
+				`strrev("hello world")`,
+				cty.StringVal("dlrow olleh"),
+			},
+		},
+
+		"substr": {
+			{
+				`substr("hello world", 1, 4)`,
+				cty.StringVal("ello"),
+			},
+		},
+
+		"sum": {
+			{
+				`sum([2340.5,10,3])`,
+				cty.NumberFloatVal(2353.5),
+			},
+		},
+
+		"textdecodebase64": {
+			{
+				`textdecodebase64("dABlAHMAdAA=", "UTF-16LE")`,
+				cty.StringVal("test"),
+			},
+		},
+
+		"textencodebase64": {
+			{
+				`textencodebase64("test", "UTF-16LE")`,
+				cty.StringVal("dABlAHMAdAA="),
+			},
+		},
+
+		"templatefile": {
+			{
+				`templatefile("hello.tmpl", {name = "Jodie"})`,
+				cty.StringVal("Hello, Jodie!"),
+			},
+		},
+
+		"timeadd": {
+			{
+				`timeadd("2017-11-22T00:00:00Z", "1s")`,
+				cty.StringVal("2017-11-22T00:00:01Z"),
+			},
+		},
+
+		"timecmp": {
+			{
+				`timecmp("2017-11-22T00:00:00Z", "2017-11-22T00:00:00Z")`,
+				cty.Zero,
+			},
+		},
+
+		"title": {
+			{
+				`title("hello")`,
+				cty.StringVal("Hello"),
+			},
+		},
+
+		"tobool": {
+			{
+				`tobool("false")`,
+				cty.False,
+			},
+		},
+
+		"tolist": {
+			{
+				`tolist(["a", "b", "c"])`,
+				cty.ListVal([]cty.Value{
+					cty.StringVal("a"), cty.StringVal("b"), cty.StringVal("c"),
+				}),
+			},
+		},
+
+		"tomap": {
+			{
+				`tomap({"a" = 1, "b" = 2})`,
+				cty.MapVal(map[string]cty.Value{
+					"a": cty.NumberIntVal(1),
+					"b": cty.NumberIntVal(2),
+				}),
+			},
+		},
+
+		"tonumber": {
+			{
+				`tonumber("42")`,
+				cty.NumberIntVal(42),
+			},
+		},
+
+		"toset": {
+			{
+				`toset(["a", "b", "c"])`,
+				cty.SetVal([]cty.Value{
+					cty.StringVal("a"), cty.StringVal("b"), cty.StringVal("c"),
+				}),
+			},
+		},
+
+		"tostring": {
+			{
+				`tostring("a")`,
+				cty.StringVal("a"),
+			},
+		},
+
+		"transpose": {
+			{
+				`transpose({"a" = ["1", "2"], "b" = ["2", "3"]})`,
+				cty.MapVal(map[string]cty.Value{
+					"1": cty.ListVal([]cty.Value{cty.StringVal("a")}),
+					"2": cty.ListVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b")}),
+					"3": cty.ListVal([]cty.Value{cty.StringVal("b")}),
+				}),
+			},
+		},
+
+		"trim": {
+			{
+				`trim("?!hello?!", "!?")`,
+				cty.StringVal("hello"),
+			},
+		},
+
+		"trimprefix": {
+			{
+				`trimprefix("helloworld", "hello")`,
+				cty.StringVal("world"),
+			},
+		},
+
+		"trimspace": {
+			{
+				`trimspace(" hello ")`,
+				cty.StringVal("hello"),
+			},
+		},
+
+		"trimsuffix": {
+			{
+				`trimsuffix("helloworld", "world")`,
+				cty.StringVal("hello"),
+			},
+		},
+
+		"try": {
+			{
+				// Note: "try" only works with expressions that pass static
+				// validation, because it only gets an opportunity to run in
+				// that case. The following "works" (captures the error) because
+				// Terraform understands it as a reference to an attribute
+				// that does not exist during dynamic evaluation.
+				//
+				// "try" doesn't work with references that could never possibly
+				// be valid and are thus caught during static validation, such
+				// as an expression like "foo" alone which would be understood
+				// as an invalid resource reference. That's okay because this
+				// function exists primarily to ease access to dynamically-typed
+				// structures that Terraform can't statically validate by
+				// definition.
+				`try({}.baz, "fallback")`,
+				cty.StringVal("fallback"),
+			},
+			{
+				`try("fallback")`,
+				cty.StringVal("fallback"),
+			},
+		},
+
+		"upper": {
+			{
+				`upper("hello")`,
+				cty.StringVal("HELLO"),
+			},
+		},
+
+		"urlencode": {
+			{
+				`urlencode("foo:bar@localhost?foo=bar&bar=baz")`,
+				cty.StringVal("foo%3Abar%40localhost%3Ffoo%3Dbar%26bar%3Dbaz"),
+			},
+		},
+
+		"uuidv5": {
+			{
+				`uuidv5("dns", "tada")`,
+				cty.StringVal("faa898db-9b9d-5b75-86a9-149e7bb8e3b8"),
+			},
+			{
+				`uuidv5("url", "tada")`,
+				cty.StringVal("2c1ff6b4-211f-577e-94de-d978b0caa16e"),
+			},
+			{
+				`uuidv5("oid", "tada")`,
+				cty.StringVal("61eeea26-5176-5288-87fc-232d6ed30d2f"),
+			},
+			{
+				`uuidv5("x500", "tada")`,
+				cty.StringVal("7e12415e-f7c9-57c3-9e43-52dc9950d264"),
+			},
+			{
+				`uuidv5("6ba7b810-9dad-11d1-80b4-00c04fd430c8", "tada")`,
+				cty.StringVal("faa898db-9b9d-5b75-86a9-149e7bb8e3b8"),
+			},
+		},
+
+		"values": {
+			{
+				`values({"hello"="world", "what's"="up"})`,
+				cty.TupleVal([]cty.Value{
+					cty.StringVal("world"),
+					cty.StringVal("up"),
+				}),
+			},
+		},
+
+		"yamldecode": {
+			{
+				`yamldecode("true")`,
+				cty.True,
+			},
+			{
+				`yamldecode("key: 0ba")`,
+				cty.ObjectVal(map[string]cty.Value{
+					"key": cty.StringVal("0ba"),
+				}),
+			},
+			{
+				`yamldecode("~")`,
+				cty.NullVal(cty.DynamicPseudoType),
+			},
+		},
+
+		"yamlencode": {
+			{
+				`yamlencode(["foo", "bar", true])`,
+				cty.StringVal("- \"foo\"\n- \"bar\"\n- true\n"),
+			},
+			{
+				`yamlencode({a = "b", c = "d"})`,
+				cty.StringVal("\"a\": \"b\"\n\"c\": \"d\"\n"),
+			},
+			{
+				`yamlencode(true)`,
+				// the ... here is an "end of document" marker, produced for implied primitive types only
+				cty.StringVal("true\n...\n"),
+			},
+		},
+
+		"zipmap": {
+			{
+				`zipmap(["hello", "bar"], ["world", "baz"])`,
+				cty.ObjectVal(map[string]cty.Value{
+					"hello": cty.StringVal("world"),
+					"bar":   cty.StringVal("baz"),
+				}),
+			},
+		},
+	}
+
+	experimentalFuncs := map[string]experiments.Experiment{}
+	experimentalFuncs["defaults"] = experiments.ModuleVariableOptionalAttrs
+
+	t.Run("all functions are tested", func(t *testing.T) {
+		data := &dataForTests{} // no variables available; we only need literals here
+		scope := &Scope{
+			Data:    data,
+			BaseDir: "./testdata/functions-test", // for the functions that read from the filesystem
+		}
+
+		// Check that there is at least one test case for each function, omitting
+		// those functions that do not return consistent values
+		allFunctions := scope.Functions()
+
+		// TODO: we can test the impure functions partially by configuring the scope
+		// with PureOnly: true and then verify that they return unknown values of a
+		// suitable type.
+		for _, impureFunc := range impureFunctions {
+			delete(allFunctions, impureFunc)
+		}
+		for f := range scope.Functions() {
+			if _, ok := tests[f]; !ok {
+				t.Errorf("Missing test for function %s\n", f)
+			}
+		}
+	})
+
+	for funcName, funcTests := range tests {
+		t.Run(funcName, func(t *testing.T) {
+
+			// prepareScope starts as a no-op, but if a function is marked as
+			// experimental in our experimentalFuncs table above then we'll
+			// reassign this to be a function that activates the appropriate
+			// experiment.
+			prepareScope := func(t *testing.T, scope *Scope) {}
+
+			if experiment, isExperimental := experimentalFuncs[funcName]; isExperimental {
+				// First, we'll run all of the tests without the experiment
+				// enabled to see that they do actually fail in that case.
+				for _, test := range funcTests {
+					testName := fmt.Sprintf("experimental(%s)", test.src)
+					t.Run(testName, func(t *testing.T) {
+						data := &dataForTests{} // no variables available; we only need literals here
+						scope := &Scope{
+							Data:    data,
+							BaseDir: "./testdata/functions-test", // for the functions that read from the filesystem
+						}
+
+						expr, parseDiags := hclsyntax.ParseExpression([]byte(test.src), "test.hcl", hcl.Pos{Line: 1, Column: 1})
+						if parseDiags.HasErrors() {
+							for _, diag := range parseDiags {
+								t.Error(diag.Error())
+							}
+							return
+						}
+
+						_, diags := scope.EvalExpr(expr, cty.DynamicPseudoType)
+						if !diags.HasErrors() {
+							t.Errorf("experimental function %q succeeded without its experiment %s enabled\nexpr: %s", funcName, experiment.Keyword(), test.src)
+						}
+					})
+				}
+
+				// Now make the experiment active in the scope so that the
+				// function will actually work when we test it below.
+				prepareScope = func(t *testing.T, scope *Scope) {
+					t.Helper()
+					t.Logf("activating experiment %s to test %q", experiment.Keyword(), funcName)
+					experimentsSet := experiments.NewSet()
+					experimentsSet.Add(experiment)
+					scope.SetActiveExperiments(experimentsSet)
+				}
+			}
+
+			for _, test := range funcTests {
+				t.Run(test.src, func(t *testing.T) {
+					data := &dataForTests{} // no variables available; we only need literals here
+					scope := &Scope{
+						Data:          data,
+						BaseDir:       "./testdata/functions-test", // for the functions that read from the filesystem
+						PlanTimestamp: time.Date(2004, 04, 25, 15, 00, 00, 000, time.UTC),
+					}
+					prepareScope(t, scope)
+
+					expr, parseDiags := hclsyntax.ParseExpression([]byte(test.src), "test.hcl", hcl.Pos{Line: 1, Column: 1})
+					if parseDiags.HasErrors() {
+						for _, diag := range parseDiags {
+							t.Error(diag.Error())
+						}
+						return
+					}
+
+					got, diags := scope.EvalExpr(expr, cty.DynamicPseudoType)
+					if diags.HasErrors() {
+						for _, diag := range diags {
+							t.Errorf("%s: %s", diag.Description().Summary, diag.Description().Detail)
+						}
+						return
+					}
+
+					if !test.want.RawEquals(got) {
+						t.Errorf("wrong result\nexpr: %s\ngot:  %#v\nwant: %#v", test.src, got, test.want)
+					}
+				})
+			}
+		})
+	}
+}
+
+const (
+	CipherBase64 = "eczGaDhXDbOFRZGhjx2etVzWbRqWDlmq0bvNt284JHVbwCgObiuyX9uV0LSAMY707IEgMkExJqXmsB4OWKxvB7epRB9G/3+F+pcrQpODlDuL9oDUAsa65zEpYF0Wbn7Oh7nrMQncyUPpyr9WUlALl0gRWytOA23S+y5joa4M34KFpawFgoqTu/2EEH4Xl1zo+0fy73fEto+nfkUY+meuyGZ1nUx/+DljP7ZqxHBFSlLODmtuTMdswUbHbXbWneW51D7Jm7xB8nSdiA2JQNK5+Sg5x8aNfgvFTt/m2w2+qpsyFa5Wjeu6fZmXSl840CA07aXbk9vN4I81WmJyblD/ZA=="
+	PrivateKey   = `
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAgUElV5mwqkloIrM8ZNZ72gSCcnSJt7+/Usa5G+D15YQUAdf9
+c1zEekTfHgDP+04nw/uFNFaE5v1RbHaPxhZYVg5ZErNCa/hzn+x10xzcepeS3KPV
+Xcxae4MR0BEegvqZqJzN9loXsNL/c3H/B+2Gle3hTxjlWFb3F5qLgR+4Mf4ruhER
+1v6eHQa/nchi03MBpT4UeJ7MrL92hTJYLdpSyCqmr8yjxkKJDVC2uRrr+sTSxfh7
+r6v24u/vp/QTmBIAlNPgadVAZw17iNNb7vjV7Gwl/5gHXonCUKURaV++dBNLrHIZ
+pqcAM8wHRph8mD1EfL9hsz77pHewxolBATV+7QIDAQABAoIBAC1rK+kFW3vrAYm3
++8/fQnQQw5nec4o6+crng6JVQXLeH32qXShNf8kLLG/Jj0vaYcTPPDZw9JCKkTMQ
+0mKj9XR/5DLbBMsV6eNXXuvJJ3x4iKW5eD9WkLD4FKlNarBRyO7j8sfPTqXW7uat
+NxWdFH7YsSRvNh/9pyQHLWA5OituidMrYbc3EUx8B1GPNyJ9W8Q8znNYLfwYOjU4
+Wv1SLE6qGQQH9Q0WzA2WUf8jklCYyMYTIywAjGb8kbAJlKhmj2t2Igjmqtwt1PYc
+pGlqbtQBDUiWXt5S4YX/1maIQ/49yeNUajjpbJiH3DbhJbHwFTzP3pZ9P9GHOzlG
+kYR+wSECgYEAw/Xida8kSv8n86V3qSY/I+fYQ5V+jDtXIE+JhRnS8xzbOzz3v0WS
+Oo5H+o4nJx5eL3Ghb3Gcm0Jn46dHrxinHbm+3RjXv/X6tlbxIYjRSQfHOTSMCTvd
+qcliF5vC6RCLXuc7R+IWR1Ky6eDEZGtrvt3DyeYABsp9fRUFR/6NluUCgYEAqNsw
+1aSl7WJa27F0DoJdlU9LWerpXcazlJcIdOz/S9QDmSK3RDQTdqfTxRmrxiYI9LEs
+mkOkvzlnnOBMpnZ3ZOU5qIRfprecRIi37KDAOHWGnlC0EWGgl46YLb7/jXiWf0AG
+Y+DfJJNd9i6TbIDWu8254/erAS6bKMhW/3q7f2kCgYAZ7Id/BiKJAWRpqTRBXlvw
+BhXoKvjI2HjYP21z/EyZ+PFPzur/lNaZhIUlMnUfibbwE9pFggQzzf8scM7c7Sf+
+mLoVSdoQ/Rujz7CqvQzi2nKSsM7t0curUIb3lJWee5/UeEaxZcmIufoNUrzohAWH
+BJOIPDM4ssUTLRq7wYM9uQKBgHCBau5OP8gE6mjKuXsZXWUoahpFLKwwwmJUp2vQ
+pOFPJ/6WZOlqkTVT6QPAcPUbTohKrF80hsZqZyDdSfT3peFx4ZLocBrS56m6NmHR
+UYHMvJ8rQm76T1fryHVidz85g3zRmfBeWg8yqT5oFg4LYgfLsPm1gRjOhs8LfPvI
+OLlRAoGBAIZ5Uv4Z3s8O7WKXXUe/lq6j7vfiVkR1NW/Z/WLKXZpnmvJ7FgxN4e56
+RXT7GwNQHIY8eDjDnsHxzrxd+raOxOZeKcMHj3XyjCX3NHfTscnsBPAGYpY/Wxzh
+T8UYnFu6RzkixElTf2rseEav7rkdKkI3LAeIZy7B0HulKKsmqVQ7
+-----END RSA PRIVATE KEY-----
+`
+	Poem = `Fleas:
+Adam
+Had'em
+
+E.E. Cummings`
+)
diff --git a/v1.5.7/internal/lang/globalref/analyzer.go b/v1.5.7/internal/lang/globalref/analyzer.go
new file mode 100644
index 0000000..fa78de8
--- /dev/null
+++ b/v1.5.7/internal/lang/globalref/analyzer.go
@@ -0,0 +1,71 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package globalref
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/providers"
+)
+
+// Analyzer is the main component of this package, serving as a container for
+// various state that the analysis algorithms depend on either for their core
+// functionality or for producing results more quickly.
+//
+// Global reference analysis is currently intended only for "best effort"
+// use-cases related to giving hints to the user or tailoring UI output.
+// Avoid using it for anything that would cause changes to the analyzer being
+// considered a breaking change under the v1 compatibility promises, because
+// we expect to continue to refine and evolve these rules over time in ways
+// that may cause us to detect either more or fewer references than today.
+// Typically we will conservatively return more references than would be
+// necessary dynamically, but that isn't guaranteed for all situations.
+//
+// In particular, we currently typically don't distinguish between multiple
+// instances of the same module, and so we overgeneralize references from
+// one instance of a module as references from the same location in all
+// instances of that module. We may make this more precise in future, which
+// would then remove various detected references from the analysis results.
+//
+// Each Analyzer works with a particular configs.Config object which it assumes
+// represents the root module of a configuration. Config objects are typically
+// immutable by convention anyway, but it's particularly important not to
+// modify a configuration while it's attached to a live Analyzer, because
+// the Analyzer contains caches derived from data in the configuration tree.
+type Analyzer struct {
+	cfg             *configs.Config
+	providerSchemas map[addrs.Provider]*providers.Schemas
+}
+
+// NewAnalyzer constructs a new analyzer bound to the given configuration and
+// provider schemas.
+//
+// The given object must represent a root module, or this function will panic.
+//
+// The given provider schemas must cover at least all of the providers used
+// in the given configuration. If not then analysis results will be silently
+// incomplete for any decision that requires checking schema.
+func NewAnalyzer(cfg *configs.Config, providerSchemas map[addrs.Provider]*providers.Schemas) *Analyzer {
+	if !cfg.Path.IsRoot() {
+		panic(fmt.Sprintf("constructing an Analyzer with non-root module %s", cfg.Path))
+	}
+
+	ret := &Analyzer{
+		cfg:             cfg,
+		providerSchemas: providerSchemas,
+	}
+	return ret
+}
+
+// ModuleConfig retrieves a module configuration from the configuration the
+// analyzer belongs to, or nil if there is no module with the given address.
+func (a *Analyzer) ModuleConfig(addr addrs.ModuleInstance) *configs.Module {
+	modCfg := a.cfg.DescendentForInstance(addr)
+	if modCfg == nil {
+		return nil
+	}
+	return modCfg.Module
+}
diff --git a/v1.5.7/internal/lang/globalref/analyzer_contributing_resources.go b/v1.5.7/internal/lang/globalref/analyzer_contributing_resources.go
new file mode 100644
index 0000000..23cc2d5
--- /dev/null
+++ b/v1.5.7/internal/lang/globalref/analyzer_contributing_resources.go
@@ -0,0 +1,133 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package globalref
+
+import (
+	"sort"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// ContributingResources analyzes all of the given references and
+// for each one tries to walk backwards through any named values to find all
+// resources whose values contributed either directly or indirectly to any of
+// them.
+//
+// This is a wrapper around ContributingResourceReferences which simplifies
+// the result to only include distinct resource addresses, not full references.
+// If the configuration includes several different references to different
+// parts of a resource, ContributingResources will not preserve that detail.
+func (a *Analyzer) ContributingResources(refs ...Reference) []addrs.AbsResource {
+	retRefs := a.ContributingResourceReferences(refs...)
+	if len(retRefs) == 0 {
+		return nil
+	}
+
+	uniq := make(map[string]addrs.AbsResource, len(refs))
+	for _, ref := range retRefs {
+		if addr, ok := resourceForAddr(ref.LocalRef.Subject); ok {
+			moduleAddr := ref.ModuleAddr()
+			absAddr := addr.Absolute(moduleAddr)
+			uniq[absAddr.String()] = absAddr
+		}
+	}
+	ret := make([]addrs.AbsResource, 0, len(uniq))
+	for _, addr := range uniq {
+		ret = append(ret, addr)
+	}
+	sort.Slice(ret, func(i, j int) bool {
+		// We only have a sorting function for resource _instances_, but
+		// it'll do well enough if we just pretend we have no-key instances.
+		return ret[i].Instance(addrs.NoKey).Less(ret[j].Instance(addrs.NoKey))
+	})
+	return ret
+}
+
+// ContributingResourceReferences analyzes all of the given references and
+// for each one tries to walk backwards through any named values to find all
+// references to resource attributes that contributed either directly or
+// indirectly to any of them.
+//
+// This is a global operation that can be potentially quite expensive for
+// complex configurations.
+func (a *Analyzer) ContributingResourceReferences(refs ...Reference) []Reference {
+	// Our methodology here is to keep digging through MetaReferences
+	// until we've visited everything we encounter directly or indirectly,
+	// and keep track of any resources we find along the way.
+
+	// We'll aggregate our result here, using the string representations of
+	// the resources as keys to avoid returning the same one more than once.
+	found := make(map[referenceAddrKey]Reference)
+
+	// We might encounter the same object multiple times as we walk,
+	// but we won't learn anything more by traversing them again and so we'll
+	// just skip them instead.
+	visitedObjects := make(map[referenceAddrKey]struct{})
+
+	// A queue of objects we still need to visit.
+	// Note that if we find multiple references to the same object then we'll
+	// just arbitrary choose any one of them, because for our purposes here
+	// it's immaterial which reference we actually followed.
+	pendingObjects := make(map[referenceAddrKey]Reference)
+
+	// Initial state: identify any directly-mentioned resources and
+	// queue up any named values we refer to.
+	for _, ref := range refs {
+		if _, ok := resourceForAddr(ref.LocalRef.Subject); ok {
+			found[ref.addrKey()] = ref
+		}
+		pendingObjects[ref.addrKey()] = ref
+	}
+
+	for len(pendingObjects) > 0 {
+		// Note: we modify this map while we're iterating over it, which means
+		// that anything we add might be either visited within a later
+		// iteration of the inner loop or in a later iteration of the outer
+		// loop, but we get the correct result either way because we keep
+		// working until we've fully depleted the queue.
+		for key, ref := range pendingObjects {
+			delete(pendingObjects, key)
+
+			// We do this _before_ the visit below just in case this is an
+			// invalid config with a self-referential local value, in which
+			// case we'll just silently ignore the self reference for our
+			// purposes here, and thus still eventually converge (albeit
+			// with an incomplete answer).
+			visitedObjects[key] = struct{}{}
+
+			moreRefs := a.MetaReferences(ref)
+			for _, newRef := range moreRefs {
+				if _, ok := resourceForAddr(newRef.LocalRef.Subject); ok {
+					found[newRef.addrKey()] = newRef
+				}
+
+				newKey := newRef.addrKey()
+				if _, visited := visitedObjects[newKey]; !visited {
+					pendingObjects[newKey] = newRef
+				}
+			}
+		}
+	}
+
+	if len(found) == 0 {
+		return nil
+	}
+
+	ret := make([]Reference, 0, len(found))
+	for _, ref := range found {
+		ret = append(ret, ref)
+	}
+	return ret
+}
+
+func resourceForAddr(addr addrs.Referenceable) (addrs.Resource, bool) {
+	switch addr := addr.(type) {
+	case addrs.Resource:
+		return addr, true
+	case addrs.ResourceInstance:
+		return addr.Resource, true
+	default:
+		return addrs.Resource{}, false
+	}
+}
diff --git a/v1.5.7/internal/lang/globalref/analyzer_contributing_resources_test.go b/v1.5.7/internal/lang/globalref/analyzer_contributing_resources_test.go
new file mode 100644
index 0000000..873b35f
--- /dev/null
+++ b/v1.5.7/internal/lang/globalref/analyzer_contributing_resources_test.go
@@ -0,0 +1,193 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package globalref
+
+import (
+	"sort"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestAnalyzerContributingResources(t *testing.T) {
+	azr := testAnalyzer(t, "contributing-resources")
+
+	tests := map[string]struct {
+		StartRefs func() []Reference
+		WantAddrs []string
+	}{
+		"root output 'network'": {
+			func() []Reference {
+				return azr.ReferencesFromOutputValue(
+					addrs.OutputValue{Name: "network"}.Absolute(addrs.RootModuleInstance),
+				)
+			},
+			[]string{
+				`data.test_thing.environment`,
+				`module.network.test_thing.subnet`,
+				`module.network.test_thing.vpc`,
+			},
+		},
+		"root output 'c10s_url'": {
+			func() []Reference {
+				return azr.ReferencesFromOutputValue(
+					addrs.OutputValue{Name: "c10s_url"}.Absolute(addrs.RootModuleInstance),
+				)
+			},
+			[]string{
+				`data.test_thing.environment`,
+				`module.compute.test_thing.load_balancer`,
+				`module.network.test_thing.subnet`,
+				`module.network.test_thing.vpc`,
+
+				// NOTE: module.compute.test_thing.controller isn't here
+				// because we can see statically that the output value refers
+				// only to the "string" attribute of
+				// module.compute.test_thing.load_balancer , and so we
+				// don't consider references inside the "list" blocks.
+			},
+		},
+		"module.compute.test_thing.load_balancer": {
+			func() []Reference {
+				return azr.ReferencesFromResourceInstance(
+					addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_thing",
+						Name: "load_balancer",
+					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("compute", addrs.NoKey)),
+				)
+			},
+			[]string{
+				`data.test_thing.environment`,
+				`module.compute.test_thing.controller`,
+				`module.network.test_thing.subnet`,
+				`module.network.test_thing.vpc`,
+			},
+		},
+		"data.test_thing.environment": {
+			func() []Reference {
+				return azr.ReferencesFromResourceInstance(
+					addrs.Resource{
+						Mode: addrs.DataResourceMode,
+						Type: "test_thing",
+						Name: "environment",
+					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+				)
+			},
+			[]string{
+				// Nothing! This one only refers to an input variable.
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			startRefs := test.StartRefs()
+			addrs := azr.ContributingResources(startRefs...)
+
+			want := test.WantAddrs
+			got := make([]string, len(addrs))
+			for i, addr := range addrs {
+				got[i] = addr.String()
+			}
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("wrong addresses\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestAnalyzerContributingResourceAttrs(t *testing.T) {
+	azr := testAnalyzer(t, "contributing-resources")
+
+	tests := map[string]struct {
+		StartRefs func() []Reference
+		WantAttrs []string
+	}{
+		"root output 'network'": {
+			func() []Reference {
+				return azr.ReferencesFromOutputValue(
+					addrs.OutputValue{Name: "network"}.Absolute(addrs.RootModuleInstance),
+				)
+			},
+			[]string{
+				`data.test_thing.environment.any.base_cidr_block`,
+				`data.test_thing.environment.any.subnet_count`,
+				`module.network.test_thing.subnet`,
+				`module.network.test_thing.vpc.string`,
+			},
+		},
+		"root output 'c10s_url'": {
+			func() []Reference {
+				return azr.ReferencesFromOutputValue(
+					addrs.OutputValue{Name: "c10s_url"}.Absolute(addrs.RootModuleInstance),
+				)
+			},
+			[]string{
+				`data.test_thing.environment.any.base_cidr_block`,
+				`data.test_thing.environment.any.subnet_count`,
+				`module.compute.test_thing.load_balancer.string`,
+				`module.network.test_thing.subnet`,
+				`module.network.test_thing.vpc.string`,
+			},
+		},
+		"module.compute.test_thing.load_balancer": {
+			func() []Reference {
+				return azr.ReferencesFromResourceInstance(
+					addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_thing",
+						Name: "load_balancer",
+					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("compute", addrs.NoKey)),
+				)
+			},
+			[]string{
+				`data.test_thing.environment.any.base_cidr_block`,
+				`data.test_thing.environment.any.subnet_count`,
+				`module.compute.test_thing.controller`,
+				`module.network.test_thing.subnet`,
+				`module.network.test_thing.vpc.string`,
+			},
+		},
+		"data.test_thing.environment": {
+			func() []Reference {
+				return azr.ReferencesFromResourceInstance(
+					addrs.Resource{
+						Mode: addrs.DataResourceMode,
+						Type: "test_thing",
+						Name: "environment",
+					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+				)
+			},
+			[]string{
+				// Nothing! This one only refers to an input variable.
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			startRefs := test.StartRefs()
+			refs := azr.ContributingResourceReferences(startRefs...)
+
+			want := test.WantAttrs
+			got := make([]string, len(refs))
+			for i, ref := range refs {
+				resAttr, ok := ref.ResourceAttr()
+				if !ok {
+					t.Errorf("%s is not a resource attr reference", resAttr.DebugString())
+					continue
+				}
+				got[i] = resAttr.DebugString()
+			}
+
+			sort.Strings(got)
+
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("wrong addresses\n%s", diff)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/lang/globalref/analyzer_meta_references.go b/v1.5.7/internal/lang/globalref/analyzer_meta_references.go
new file mode 100644
index 0000000..1e5f26a
--- /dev/null
+++ b/v1.5.7/internal/lang/globalref/analyzer_meta_references.go
@@ -0,0 +1,609 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package globalref
+
+import (
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/convert"
+	"github.com/zclconf/go-cty/cty/gocty"
+)
+
+// MetaReferences inspects the configuration to find the references contained
+// within the most specific object that the given address refers to.
+//
+// This finds only the direct references in that object, not any indirect
+// references from those. This is a building block for some other Analyzer
+// functions that can walk through multiple levels of reference.
+//
+// If the given reference refers to something that doesn't exist in the
+// configuration we're analyzing then MetaReferences will return no
+// meta-references at all, which is indistinguishable from an existing
+// object that doesn't refer to anything.
+func (a *Analyzer) MetaReferences(ref Reference) []Reference {
+	// This function is aiming to encapsulate the fact that a reference
+	// is actually quite a complex notion which includes both a specific
+	// object the reference is to, where each distinct object type has
+	// a very different representation in the configuration, and then
+	// also potentially an attribute or block within the definition of that
+	// object. Our goal is to make all of these different situations appear
+	// mostly the same to the caller, in that all of them can be reduced to
+	// a set of references regardless of which expression or expressions we
+	// derive those from.
+
+	moduleAddr := ref.ModuleAddr()
+	remaining := ref.LocalRef.Remaining
+
+	// Our first task then is to select an appropriate implementation based
+	// on which address type the reference refers to.
+	switch targetAddr := ref.LocalRef.Subject.(type) {
+	case addrs.InputVariable:
+		return a.metaReferencesInputVariable(moduleAddr, targetAddr, remaining)
+	case addrs.LocalValue:
+		return a.metaReferencesLocalValue(moduleAddr, targetAddr, remaining)
+	case addrs.ModuleCallInstanceOutput:
+		return a.metaReferencesOutputValue(moduleAddr, targetAddr, remaining)
+	case addrs.ModuleCallInstance:
+		return a.metaReferencesModuleCall(moduleAddr, targetAddr, remaining)
+	case addrs.ModuleCall:
+		// TODO: It isn't really correct to say that a reference to a module
+		// call is a reference to its no-key instance. Really what we want to
+		// say here is that it's a reference to _all_ instances, or to an
+		// instance with an unknown key, but we don't have any representation
+		// of that. For the moment it's pretty immaterial since most of our
+		// other analysis ignores instance keys anyway, but maybe we'll revisit
+		// this latter to distingish these two cases better.
+		return a.metaReferencesModuleCall(moduleAddr, targetAddr.Instance(addrs.NoKey), remaining)
+	case addrs.CountAttr, addrs.ForEachAttr:
+		if resourceAddr, ok := ref.ResourceInstance(); ok {
+			return a.metaReferencesCountOrEach(resourceAddr.ContainingResource())
+		}
+		return nil
+	case addrs.ResourceInstance:
+		return a.metaReferencesResourceInstance(moduleAddr, targetAddr, remaining)
+	case addrs.Resource:
+		// TODO: It isn't really correct to say that a reference to a resource
+		// is a reference to its no-key instance. Really what we want to say
+		// here is that it's a reference to _all_ instances, or to an instance
+		// with an unknown key, but we don't have any representation of that.
+		// For the moment it's pretty immaterial since most of our other
+		// analysis ignores instance keys anyway, but maybe we'll revisit this
+		// latter to distingish these two cases better.
+		return a.metaReferencesResourceInstance(moduleAddr, targetAddr.Instance(addrs.NoKey), remaining)
+	default:
+		// For anything we don't explicitly support we'll just return no
+		// references. This includes the reference types that don't really
+		// refer to configuration objects at all, like "path.module",
+		// and so which cannot possibly generate any references.
+		return nil
+	}
+}
+
+func (a *Analyzer) metaReferencesInputVariable(calleeAddr addrs.ModuleInstance, addr addrs.InputVariable, remain hcl.Traversal) []Reference {
+	if calleeAddr.IsRoot() {
+		// A root module variable definition can never refer to anything,
+		// because it conceptually exists outside of any module.
+		return nil
+	}
+
+	callerAddr, callAddr := calleeAddr.Call()
+
+	// We need to find the module call inside the caller module.
+	callerCfg := a.ModuleConfig(callerAddr)
+	if callerCfg == nil {
+		return nil
+	}
+	call := callerCfg.ModuleCalls[callAddr.Name]
+	if call == nil {
+		return nil
+	}
+
+	// Now we need to look for an attribute matching the variable name inside
+	// the module block body.
+	body := call.Config
+	schema := &hcl.BodySchema{
+		Attributes: []hcl.AttributeSchema{
+			{Name: addr.Name},
+		},
+	}
+	// We don't check for errors here because we'll make a best effort to
+	// analyze whatever partial result HCL is able to extract.
+	content, _, _ := body.PartialContent(schema)
+	attr := content.Attributes[addr.Name]
+	if attr == nil {
+		return nil
+	}
+	refs, _ := lang.ReferencesInExpr(attr.Expr)
+	return absoluteRefs(callerAddr, refs)
+}
+
+func (a *Analyzer) metaReferencesOutputValue(callerAddr addrs.ModuleInstance, addr addrs.ModuleCallInstanceOutput, remain hcl.Traversal) []Reference {
+	calleeAddr := callerAddr.Child(addr.Call.Call.Name, addr.Call.Key)
+
+	// We need to find the output value declaration inside the callee module.
+	calleeCfg := a.ModuleConfig(calleeAddr)
+	if calleeCfg == nil {
+		return nil
+	}
+
+	oc := calleeCfg.Outputs[addr.Name]
+	if oc == nil {
+		return nil
+	}
+
+	// We don't check for errors here because we'll make a best effort to
+	// analyze whatever partial result HCL is able to extract.
+	refs, _ := lang.ReferencesInExpr(oc.Expr)
+	return absoluteRefs(calleeAddr, refs)
+}
+
+func (a *Analyzer) metaReferencesLocalValue(moduleAddr addrs.ModuleInstance, addr addrs.LocalValue, remain hcl.Traversal) []Reference {
+	modCfg := a.ModuleConfig(moduleAddr)
+	if modCfg == nil {
+		return nil
+	}
+
+	local := modCfg.Locals[addr.Name]
+	if local == nil {
+		return nil
+	}
+
+	// We don't check for errors here because we'll make a best effort to
+	// analyze whatever partial result HCL is able to extract.
+	refs, _ := lang.ReferencesInExpr(local.Expr)
+	return absoluteRefs(moduleAddr, refs)
+}
+
+func (a *Analyzer) metaReferencesModuleCall(callerAddr addrs.ModuleInstance, addr addrs.ModuleCallInstance, remain hcl.Traversal) []Reference {
+	calleeAddr := callerAddr.Child(addr.Call.Name, addr.Key)
+
+	// What we're really doing here is just rolling up all of the references
+	// from all of this module's output values.
+	calleeCfg := a.ModuleConfig(calleeAddr)
+	if calleeCfg == nil {
+		return nil
+	}
+
+	var ret []Reference
+	for name := range calleeCfg.Outputs {
+		outputAddr := addrs.ModuleCallInstanceOutput{
+			Call: addr,
+			Name: name,
+		}
+		moreRefs := a.metaReferencesOutputValue(callerAddr, outputAddr, nil)
+		ret = append(ret, moreRefs...)
+	}
+	return ret
+}
+
+func (a *Analyzer) metaReferencesCountOrEach(resourceAddr addrs.AbsResource) []Reference {
+	return a.ReferencesFromResourceRepetition(resourceAddr)
+}
+
+func (a *Analyzer) metaReferencesResourceInstance(moduleAddr addrs.ModuleInstance, addr addrs.ResourceInstance, remain hcl.Traversal) []Reference {
+	modCfg := a.ModuleConfig(moduleAddr)
+	if modCfg == nil {
+		return nil
+	}
+
+	rc := modCfg.ResourceByAddr(addr.Resource)
+	if rc == nil {
+		return nil
+	}
+
+	// In valid cases we should have the schema for this resource type
+	// available. In invalid cases we might be dealing with partial information,
+	// and so the schema might be nil so we won't be able to return reference
+	// information for this particular situation.
+	providerSchema := a.providerSchemas[rc.Provider]
+	if providerSchema == nil {
+		return nil
+	}
+
+	resourceTypeSchema, _ := providerSchema.SchemaForResourceAddr(addr.Resource)
+	if resourceTypeSchema == nil {
+		return nil
+	}
+
+	// When analyzing the resource configuration to look for references, we'll
+	// make a best effort to narrow down to only a particular sub-portion of
+	// the configuration by following the remaining traversal steps. In the
+	// ideal case this will lead us to a specific expression, but as a
+	// compromise it might lead us to some nested blocks where at least we
+	// can limit our searching only to those.
+	bodies := []hcl.Body{rc.Config}
+	var exprs []hcl.Expression
+	schema := resourceTypeSchema
+	var steppingThrough *configschema.NestedBlock
+	var steppingThroughType string
+	nextStep := func(newBodies []hcl.Body, newExprs []hcl.Expression) {
+		// We append exprs but replace bodies because exprs represent extra
+		// expressions we collected on the path, such as dynamic block for_each,
+		// which can potentially contribute to the final evalcontext, but
+		// bodies never contribute any values themselves, and instead just
+		// narrow down where we're searching.
+		bodies = newBodies
+		exprs = append(exprs, newExprs...)
+		steppingThrough = nil
+		steppingThroughType = ""
+		// Caller must also update "schema" if necessary.
+	}
+	traverseInBlock := func(name string) ([]hcl.Body, []hcl.Expression) {
+		if attr := schema.Attributes[name]; attr != nil {
+			// When we reach a specific attribute we can't traverse any deeper, because attributes are the leaves of the schema.
+			schema = nil
+			return traverseAttr(bodies, name)
+		} else if blockType := schema.BlockTypes[name]; blockType != nil {
+			// We need to take a different action here depending on
+			// the nesting mode of the block type. Some require us
+			// to traverse in two steps in order to select a specific
+			// child block, while others we can just step through
+			// directly.
+			switch blockType.Nesting {
+			case configschema.NestingSingle, configschema.NestingGroup:
+				// There should be only zero or one blocks of this
+				// type, so we can traverse in only one step.
+				schema = &blockType.Block
+				return traverseNestedBlockSingle(bodies, name)
+			case configschema.NestingMap, configschema.NestingList, configschema.NestingSet:
+				steppingThrough = blockType
+				return bodies, exprs // Preserve current selections for the second step
+			default:
+				// The above should be exhaustive, but just in case
+				// we add something new in future we'll bail out
+				// here and conservatively return everything under
+				// the current traversal point.
+				schema = nil
+				return nil, nil
+			}
+		}
+
+		// We'll get here if the given name isn't in the schema at all. If so,
+		// there's nothing else to be done here.
+		schema = nil
+		return nil, nil
+	}
+Steps:
+	for _, step := range remain {
+		// If we filter out all of our bodies before we finish traversing then
+		// we know we won't find anything else, because all of our subsequent
+		// traversal steps won't have any bodies to search.
+		if len(bodies) == 0 {
+			return nil
+		}
+		// If we no longer have a schema then that suggests we've
+		// traversed as deep as what the schema covers (e.g. we reached
+		// a specific attribute) and so we'll stop early, assuming that
+		// any remaining steps are traversals into an attribute expression
+		// result.
+		if schema == nil {
+			break
+		}
+
+		switch step := step.(type) {
+
+		case hcl.TraverseAttr:
+			switch {
+			case steppingThrough != nil:
+				// If we're stepping through a NestingMap block then
+				// it's valid to use attribute syntax to select one of
+				// the blocks by its label. Other nesting types require
+				// TraverseIndex, so can never be valid.
+				if steppingThrough.Nesting != configschema.NestingMap {
+					nextStep(nil, nil) // bail out
+					continue
+				}
+				nextStep(traverseNestedBlockMap(bodies, steppingThroughType, step.Name))
+				schema = &steppingThrough.Block
+			default:
+				nextStep(traverseInBlock(step.Name))
+				if schema == nil {
+					// traverseInBlock determined that we've traversed as
+					// deep as we can with reference to schema, so we'll
+					// stop here and just process whatever's selected.
+					break Steps
+				}
+			}
+		case hcl.TraverseIndex:
+			switch {
+			case steppingThrough != nil:
+				switch steppingThrough.Nesting {
+				case configschema.NestingMap:
+					keyVal, err := convert.Convert(step.Key, cty.String)
+					if err != nil { // Invalid traversal, so can't have any refs
+						nextStep(nil, nil) // bail out
+						continue
+					}
+					nextStep(traverseNestedBlockMap(bodies, steppingThroughType, keyVal.AsString()))
+					schema = &steppingThrough.Block
+				case configschema.NestingList:
+					idxVal, err := convert.Convert(step.Key, cty.Number)
+					if err != nil { // Invalid traversal, so can't have any refs
+						nextStep(nil, nil) // bail out
+						continue
+					}
+					var idx int
+					err = gocty.FromCtyValue(idxVal, &idx)
+					if err != nil { // Invalid traversal, so can't have any refs
+						nextStep(nil, nil) // bail out
+						continue
+					}
+					nextStep(traverseNestedBlockList(bodies, steppingThroughType, idx))
+					schema = &steppingThrough.Block
+				default:
+					// Note that NestingSet ends up in here because we don't
+					// actually allow traversing into set-backed block types,
+					// and so such a reference would be invalid.
+					nextStep(nil, nil) // bail out
+					continue
+				}
+			default:
+				// When indexing the contents of a block directly we always
+				// interpret the key as a string representing an attribute
+				// name.
+				nameVal, err := convert.Convert(step.Key, cty.String)
+				if err != nil { // Invalid traversal, so can't have any refs
+					nextStep(nil, nil) // bail out
+					continue
+				}
+				nextStep(traverseInBlock(nameVal.AsString()))
+				if schema == nil {
+					// traverseInBlock determined that we've traversed as
+					// deep as we can with reference to schema, so we'll
+					// stop here and just process whatever's selected.
+					break Steps
+				}
+			}
+		default:
+			// We shouldn't get here, because the above cases are exhaustive
+			// for all of the relative traversal types, but we'll be robust in
+			// case HCL adds more in future and just pretend the traversal
+			// ended a bit early if so.
+			break Steps
+		}
+	}
+
+	if steppingThrough != nil {
+		// If we ended in the middle of "stepping through" then we'll conservatively
+		// use the bodies of _all_ nested blocks of the type we were stepping
+		// through, because the recipient of this value could refer to any
+		// of them dynamically.
+		var labelNames []string
+		if steppingThrough.Nesting == configschema.NestingMap {
+			labelNames = []string{"key"}
+		}
+		blocks := findBlocksInBodies(bodies, steppingThroughType, labelNames)
+		for _, block := range blocks {
+			bodies, exprs = blockParts(block)
+		}
+	}
+
+	if len(bodies) == 0 && len(exprs) == 0 {
+		return nil
+	}
+
+	var refs []*addrs.Reference
+	for _, expr := range exprs {
+		moreRefs, _ := lang.ReferencesInExpr(expr)
+		refs = append(refs, moreRefs...)
+	}
+	if schema != nil {
+		for _, body := range bodies {
+			moreRefs, _ := lang.ReferencesInBlock(body, schema)
+			refs = append(refs, moreRefs...)
+		}
+	}
+	return absoluteRefs(addr.Absolute(moduleAddr), refs)
+}
+
+func traverseAttr(bodies []hcl.Body, name string) ([]hcl.Body, []hcl.Expression) {
+	if len(bodies) == 0 {
+		return nil, nil
+	}
+	schema := &hcl.BodySchema{
+		Attributes: []hcl.AttributeSchema{
+			{Name: name},
+		},
+	}
+	// We can find at most one expression per body, because attribute names
+	// are always unique within a body.
+	retExprs := make([]hcl.Expression, 0, len(bodies))
+	for _, body := range bodies {
+		content, _, _ := body.PartialContent(schema)
+		if attr := content.Attributes[name]; attr != nil && attr.Expr != nil {
+			retExprs = append(retExprs, attr.Expr)
+		}
+	}
+	return nil, retExprs
+}
+
+func traverseNestedBlockSingle(bodies []hcl.Body, typeName string) ([]hcl.Body, []hcl.Expression) {
+	if len(bodies) == 0 {
+		return nil, nil
+	}
+
+	blocks := findBlocksInBodies(bodies, typeName, nil)
+	var retBodies []hcl.Body
+	var retExprs []hcl.Expression
+	for _, block := range blocks {
+		moreBodies, moreExprs := blockParts(block)
+		retBodies = append(retBodies, moreBodies...)
+		retExprs = append(retExprs, moreExprs...)
+	}
+	return retBodies, retExprs
+}
+
+func traverseNestedBlockMap(bodies []hcl.Body, typeName string, key string) ([]hcl.Body, []hcl.Expression) {
+	if len(bodies) == 0 {
+		return nil, nil
+	}
+
+	blocks := findBlocksInBodies(bodies, typeName, []string{"key"})
+	var retBodies []hcl.Body
+	var retExprs []hcl.Expression
+	for _, block := range blocks {
+		switch block.Type {
+		case "dynamic":
+			// For dynamic blocks we allow the key to be chosen dynamically
+			// and so we'll just conservatively include all dynamic block
+			// bodies. However, we need to also look for references in some
+			// arguments of the dynamic block itself.
+			argExprs, contentBody := dynamicBlockParts(block.Body)
+			retExprs = append(retExprs, argExprs...)
+			if contentBody != nil {
+				retBodies = append(retBodies, contentBody)
+			}
+		case typeName:
+			if len(block.Labels) == 1 && block.Labels[0] == key && block.Body != nil {
+				retBodies = append(retBodies, block.Body)
+			}
+		}
+	}
+	return retBodies, retExprs
+}
+
+func traverseNestedBlockList(bodies []hcl.Body, typeName string, idx int) ([]hcl.Body, []hcl.Expression) {
+	if len(bodies) == 0 {
+		return nil, nil
+	}
+
+	schema := &hcl.BodySchema{
+		Blocks: []hcl.BlockHeaderSchema{
+			{Type: typeName, LabelNames: nil},
+			{Type: "dynamic", LabelNames: []string{"type"}},
+		},
+	}
+	var retBodies []hcl.Body
+	var retExprs []hcl.Expression
+	for _, body := range bodies {
+		content, _, _ := body.PartialContent(schema)
+		blocks := content.Blocks
+
+		// A tricky aspect of this scenario is that if there are any "dynamic"
+		// blocks then we can't statically predict how many concrete blocks they
+		// will generate, and so consequently we can't predict the indices of
+		// any statically-defined blocks that might appear after them.
+		firstDynamic := -1 // -1 means "no dynamic blocks"
+		for i, block := range blocks {
+			if block.Type == "dynamic" {
+				firstDynamic = i
+				break
+			}
+		}
+
+		switch {
+		case firstDynamic >= 0 && idx >= firstDynamic:
+			// This is the unfortunate case where the selection could be
+			// any of the blocks from firstDynamic onwards, and so we
+			// need to conservatively include all of them in our result.
+			for _, block := range blocks[firstDynamic:] {
+				moreBodies, moreExprs := blockParts(block)
+				retBodies = append(retBodies, moreBodies...)
+				retExprs = append(retExprs, moreExprs...)
+			}
+		default:
+			// This is the happier case where we can select just a single
+			// static block based on idx. Note that this one is guaranteed
+			// to never be dynamic but we're using blockParts here just
+			// for consistency.
+			moreBodies, moreExprs := blockParts(blocks[idx])
+			retBodies = append(retBodies, moreBodies...)
+			retExprs = append(retExprs, moreExprs...)
+		}
+	}
+
+	return retBodies, retExprs
+}
+
+func findBlocksInBodies(bodies []hcl.Body, typeName string, labelNames []string) []*hcl.Block {
+	// We need to look for both static blocks of the given type, and any
+	// dynamic blocks whose label gives the expected type name.
+	schema := &hcl.BodySchema{
+		Blocks: []hcl.BlockHeaderSchema{
+			{Type: typeName, LabelNames: labelNames},
+			{Type: "dynamic", LabelNames: []string{"type"}},
+		},
+	}
+	var blocks []*hcl.Block
+	for _, body := range bodies {
+		// We ignore errors here because we'll just make a best effort to analyze
+		// whatever partial result HCL returns in that case.
+		content, _, _ := body.PartialContent(schema)
+
+		for _, block := range content.Blocks {
+			switch block.Type {
+			case "dynamic":
+				if len(block.Labels) != 1 { // Invalid
+					continue
+				}
+				if block.Labels[0] == typeName {
+					blocks = append(blocks, block)
+				}
+			case typeName:
+				blocks = append(blocks, block)
+			}
+		}
+	}
+
+	// NOTE: The caller still needs to check for dynamic vs. static in order
+	// to do further processing. The callers above all aim to encapsulate
+	// that.
+	return blocks
+}
+
+func blockParts(block *hcl.Block) ([]hcl.Body, []hcl.Expression) {
+	switch block.Type {
+	case "dynamic":
+		exprs, contentBody := dynamicBlockParts(block.Body)
+		var bodies []hcl.Body
+		if contentBody != nil {
+			bodies = []hcl.Body{contentBody}
+		}
+		return bodies, exprs
+	default:
+		if block.Body == nil {
+			return nil, nil
+		}
+		return []hcl.Body{block.Body}, nil
+	}
+}
+
+func dynamicBlockParts(body hcl.Body) ([]hcl.Expression, hcl.Body) {
+	if body == nil {
+		return nil, nil
+	}
+
+	// This is a subset of the "dynamic" block schema defined by the HCL
+	// dynblock extension, covering only the two arguments that are allowed
+	// to be arbitrary expressions possibly referring elsewhere.
+	schema := &hcl.BodySchema{
+		Attributes: []hcl.AttributeSchema{
+			{Name: "for_each"},
+			{Name: "labels"},
+		},
+		Blocks: []hcl.BlockHeaderSchema{
+			{Type: "content"},
+		},
+	}
+	content, _, _ := body.PartialContent(schema)
+	var exprs []hcl.Expression
+	if len(content.Attributes) != 0 {
+		exprs = make([]hcl.Expression, 0, len(content.Attributes))
+	}
+	for _, attr := range content.Attributes {
+		if attr.Expr != nil {
+			exprs = append(exprs, attr.Expr)
+		}
+	}
+	var contentBody hcl.Body
+	for _, block := range content.Blocks {
+		if block != nil && block.Type == "content" && block.Body != nil {
+			contentBody = block.Body
+		}
+	}
+	return exprs, contentBody
+}
diff --git a/v1.5.7/internal/lang/globalref/analyzer_meta_references_shortcuts.go b/v1.5.7/internal/lang/globalref/analyzer_meta_references_shortcuts.go
new file mode 100644
index 0000000..3518d14
--- /dev/null
+++ b/v1.5.7/internal/lang/globalref/analyzer_meta_references_shortcuts.go
@@ -0,0 +1,90 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package globalref
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/lang"
+)
+
+// ReferencesFromOutputValue returns all of the direct references from the
+// value expression of the given output value. It doesn't include any indirect
+// references.
+func (a *Analyzer) ReferencesFromOutputValue(addr addrs.AbsOutputValue) []Reference {
+	mc := a.ModuleConfig(addr.Module)
+	if mc == nil {
+		return nil
+	}
+	oc := mc.Outputs[addr.OutputValue.Name]
+	if oc == nil {
+		return nil
+	}
+	refs, _ := lang.ReferencesInExpr(oc.Expr)
+	return absoluteRefs(addr.Module, refs)
+}
+
+// ReferencesFromResourceInstance returns all of the direct references from the
+// definition of the resource instance at the given address. It doesn't include
+// any indirect references.
+//
+// The result doesn't directly include references from a "count" or "for_each"
+// expression belonging to the associated resource, but it will include any
+// references to count.index, each.key, or each.value that appear in the
+// expressions which you can then, if you wish, resolve indirectly using
+// Analyzer.MetaReferences. Alternatively, you can use
+// Analyzer.ReferencesFromResourceRepetition to get that same result directly.
+func (a *Analyzer) ReferencesFromResourceInstance(addr addrs.AbsResourceInstance) []Reference {
+	// Using MetaReferences for this is kinda overkill, since
+	// lang.ReferencesInBlock would be sufficient really, but
+	// this ensures we keep consistent in how we build the
+	// resulting absolute references and otherwise aside from
+	// some extra overhead this call boils down to a call to
+	// lang.ReferencesInBlock anyway.
+	fakeRef := Reference{
+		ContainerAddr: addr.Module,
+		LocalRef: &addrs.Reference{
+			Subject: addr.Resource,
+		},
+	}
+	return a.MetaReferences(fakeRef)
+}
+
+// ReferencesFromResourceRepetition returns the references from the given
+// resource's for_each or count expression, or an empty set if the resource
+// doesn't use repetition.
+//
+// This is a special-case sort of helper for use in situations where an
+// expression might refer to count.index, each.key, or each.value, and thus
+// we say that it depends indirectly on the repetition expression.
+func (a *Analyzer) ReferencesFromResourceRepetition(addr addrs.AbsResource) []Reference {
+	modCfg := a.ModuleConfig(addr.Module)
+	if modCfg == nil {
+		return nil
+	}
+	rc := modCfg.ResourceByAddr(addr.Resource)
+	if rc == nil {
+		return nil
+	}
+
+	// We're assuming here that resources can either have count or for_each,
+	// but never both, because that's a requirement enforced by the language
+	// decoder. But we'll assert it just to make sure we catch it if that
+	// changes for some reason.
+	if rc.ForEach != nil && rc.Count != nil {
+		panic(fmt.Sprintf("%s has both for_each and count", addr))
+	}
+
+	switch {
+	case rc.ForEach != nil:
+		refs, _ := lang.ReferencesInExpr(rc.ForEach)
+		return absoluteRefs(addr.Module, refs)
+	case rc.Count != nil:
+		refs, _ := lang.ReferencesInExpr(rc.Count)
+		return absoluteRefs(addr.Module, refs)
+	default:
+		return nil
+	}
+}
diff --git a/v1.5.7/internal/lang/globalref/analyzer_meta_references_test.go b/v1.5.7/internal/lang/globalref/analyzer_meta_references_test.go
new file mode 100644
index 0000000..13cabe3
--- /dev/null
+++ b/v1.5.7/internal/lang/globalref/analyzer_meta_references_test.go
@@ -0,0 +1,173 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package globalref
+
+import (
+	"sort"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestAnalyzerMetaReferences(t *testing.T) {
+	tests := []struct {
+		InputContainer string
+		InputRef       string
+		WantRefs       []string
+	}{
+		{
+			``,
+			`local.a`,
+			nil,
+		},
+		{
+			``,
+			`local.single`,
+			[]string{
+				"::test_thing.single.id",
+			},
+		},
+		{
+			``,
+			`test_thing.single`,
+			[]string{
+				"::local.a",
+				"::local.b",
+			},
+		},
+		{
+			``,
+			`test_thing.single.string`,
+			[]string{
+				"::local.a",
+			},
+		},
+		{
+			``,
+			`test_thing.for_each`,
+			[]string{
+				"::local.a",
+				"::test_thing.single.string",
+			},
+		},
+		{
+			``,
+			`test_thing.for_each["whatever"]`,
+			[]string{
+				"::local.a",
+				"::test_thing.single.string",
+			},
+		},
+		{
+			``,
+			`test_thing.for_each["whatever"].single`,
+			[]string{
+				"::test_thing.single.string",
+			},
+		},
+		{
+			``,
+			`test_thing.for_each["whatever"].single.z`,
+			[]string{
+				"::test_thing.single.string",
+			},
+		},
+		{
+			``,
+			`test_thing.count`,
+			[]string{
+				"::local.a",
+			},
+		},
+		{
+			``,
+			`test_thing.count[0]`,
+			[]string{
+				"::local.a",
+			},
+		},
+		{
+			``,
+			`module.single.a`,
+			[]string{
+				"module.single::test_thing.foo",
+				"module.single::var.a",
+			},
+		},
+		{
+			``,
+			`module.for_each["whatever"].a`,
+			[]string{
+				`module.for_each["whatever"]::test_thing.foo`,
+				`module.for_each["whatever"]::var.a`,
+			},
+		},
+		{
+			``,
+			`module.count[0].a`,
+			[]string{
+				`module.count[0]::test_thing.foo`,
+				`module.count[0]::var.a`,
+			},
+		},
+		{
+			`module.single`,
+			`var.a`,
+			[]string{
+				"::test_thing.single",
+			},
+		},
+		{
+			`module.single`,
+			`test_thing.foo`,
+			[]string{
+				"module.single::var.a",
+			},
+		},
+	}
+
+	azr := testAnalyzer(t, "assorted")
+
+	for _, test := range tests {
+		name := test.InputRef
+		if test.InputContainer != "" {
+			name = test.InputContainer + " " + test.InputRef
+		}
+		t.Run(name, func(t *testing.T) {
+			t.Logf("testing %s", name)
+			var containerAddr addrs.Targetable
+			containerAddr = addrs.RootModuleInstance
+			if test.InputContainer != "" {
+				moduleAddrTarget, diags := addrs.ParseTargetStr(test.InputContainer)
+				if diags.HasErrors() {
+					t.Fatalf("input module address is invalid: %s", diags.Err())
+				}
+				containerAddr = moduleAddrTarget.Subject
+			}
+
+			localRef, diags := addrs.ParseRefStr(test.InputRef)
+			if diags.HasErrors() {
+				t.Fatalf("input reference is invalid: %s", diags.Err())
+			}
+
+			ref := Reference{
+				ContainerAddr: containerAddr,
+				LocalRef:      localRef,
+			}
+
+			refs := azr.MetaReferences(ref)
+
+			want := test.WantRefs
+			var got []string
+			for _, ref := range refs {
+				got = append(got, ref.DebugString())
+			}
+			sort.Strings(got)
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("wrong references\n%s", diff)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/lang/globalref/analyzer_test.go b/v1.5.7/internal/lang/globalref/analyzer_test.go
new file mode 100644
index 0000000..46235d8
--- /dev/null
+++ b/v1.5.7/internal/lang/globalref/analyzer_test.go
@@ -0,0 +1,101 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package globalref
+
+import (
+	"context"
+	"path/filepath"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/registry"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func testAnalyzer(t *testing.T, fixtureName string) *Analyzer {
+	configDir := filepath.Join("testdata", fixtureName)
+
+	loader, cleanup := configload.NewLoaderForTests(t)
+	defer cleanup()
+
+	inst := initwd.NewModuleInstaller(loader.ModulesDir(), loader, registry.NewClient(nil, nil))
+	_, instDiags := inst.InstallModules(context.Background(), configDir, true, initwd.ModuleInstallHooksImpl{})
+	if instDiags.HasErrors() {
+		t.Fatalf("unexpected module installation errors: %s", instDiags.Err().Error())
+	}
+	if err := loader.RefreshModules(); err != nil {
+		t.Fatalf("failed to refresh modules after install: %s", err)
+	}
+
+	cfg, loadDiags := loader.LoadConfig(configDir)
+	if loadDiags.HasErrors() {
+		t.Fatalf("unexpected configuration errors: %s", loadDiags.Error())
+	}
+
+	resourceTypeSchema := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"string": {Type: cty.String, Optional: true},
+			"number": {Type: cty.Number, Optional: true},
+			"any":    {Type: cty.DynamicPseudoType, Optional: true},
+		},
+		BlockTypes: map[string]*configschema.NestedBlock{
+			"single": {
+				Nesting: configschema.NestingSingle,
+				Block: configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"z": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+			"group": {
+				Nesting: configschema.NestingGroup,
+				Block: configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"z": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+			"list": {
+				Nesting: configschema.NestingList,
+				Block: configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"z": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+			"map": {
+				Nesting: configschema.NestingMap,
+				Block: configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"z": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+			"set": {
+				Nesting: configschema.NestingSet,
+				Block: configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"z": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	schemas := map[addrs.Provider]*providers.Schemas{
+		addrs.MustParseProviderSourceString("hashicorp/test"): {
+			ResourceTypes: map[string]*configschema.Block{
+				"test_thing": resourceTypeSchema,
+			},
+			DataSources: map[string]*configschema.Block{
+				"test_thing": resourceTypeSchema,
+			},
+		},
+	}
+
+	return NewAnalyzer(cfg, schemas)
+}
diff --git a/v1.5.7/internal/lang/globalref/doc.go b/v1.5.7/internal/lang/globalref/doc.go
new file mode 100644
index 0000000..cca7eef
--- /dev/null
+++ b/v1.5.7/internal/lang/globalref/doc.go
@@ -0,0 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package globalref is home to some analysis algorithms that aim to answer
+// questions about references between objects and object attributes across
+// an entire configuration.
+//
+// This is a different problem than references within a single module, which
+// we handle using some relatively simpler functions in the "lang" package
+// in the parent directory. The globalref algorithms are often implemented
+// in terms of those module-local reference-checking functions.
+package globalref
diff --git a/v1.5.7/internal/lang/globalref/reference.go b/v1.5.7/internal/lang/globalref/reference.go
new file mode 100644
index 0000000..a6cacb4
--- /dev/null
+++ b/v1.5.7/internal/lang/globalref/reference.go
@@ -0,0 +1,203 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package globalref
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Reference combines an addrs.Reference with the address of the module
+// instance or resource instance where it was found.
+//
+// Because of the design of the Terraform language, our main model of
+// references only captures the module-local part of the reference and assumes
+// that it's always clear from context which module a reference belongs to.
+// That's not true for globalref because our whole purpose is to work across
+// module boundaries, and so this package in particular has its own
+// representation of references.
+type Reference struct {
+	// ContainerAddr is always either addrs.ModuleInstance or
+	// addrs.AbsResourceInstance. The latter is required if LocalRef's
+	// subject is either an addrs.CountAddr or addrs.ForEachAddr, so
+	// we can know which resource's repetition expression it's
+	// referring to.
+	ContainerAddr addrs.Targetable
+
+	// LocalRef is a reference that would be resolved in the context
+	// of the module instance or resource instance given in ContainerAddr.
+	LocalRef *addrs.Reference
+}
+
+func absoluteRef(containerAddr addrs.Targetable, localRef *addrs.Reference) Reference {
+	ret := Reference{
+		ContainerAddr: containerAddr,
+		LocalRef:      localRef,
+	}
+	// For simplicity's sake, we always reduce the ContainerAddr to be
+	// just the module address unless it's a count.index, each.key, or
+	// each.value reference, because for anything else it's immaterial
+	// which resource it belongs to.
+	switch localRef.Subject.(type) {
+	case addrs.CountAttr, addrs.ForEachAttr:
+		// nothing to do
+	default:
+		ret.ContainerAddr = ret.ModuleAddr()
+	}
+	return ret
+}
+
+func absoluteRefs(containerAddr addrs.Targetable, refs []*addrs.Reference) []Reference {
+	if len(refs) == 0 {
+		return nil
+	}
+
+	ret := make([]Reference, len(refs))
+	for i, ref := range refs {
+		ret[i] = absoluteRef(containerAddr, ref)
+	}
+	return ret
+}
+
+// ModuleAddr returns the address of the module where the reference would
+// be resolved.
+//
+// This is either ContainerAddr directly if it's already just a module
+// instance, or the module instance part of it if it's a resource instance.
+func (r Reference) ModuleAddr() addrs.ModuleInstance {
+	switch addr := r.ContainerAddr.(type) {
+	case addrs.ModuleInstance:
+		return addr
+	case addrs.AbsResourceInstance:
+		return addr.Module
+	default:
+		// NOTE: We're intentionally using only a subset of possible
+		// addrs.Targetable implementations here, so anything else
+		// is invalid.
+		panic(fmt.Sprintf("reference has invalid container address type %T", addr))
+	}
+}
+
+// ResourceInstance returns the address of the resource where the reference
+// would be resolved, if there is one.
+//
+// Because not all references belong to resources, the extra boolean return
+// value indicates whether the returned address is valid.
+func (r Reference) ResourceInstance() (addrs.AbsResourceInstance, bool) {
+	switch container := r.ContainerAddr.(type) {
+	case addrs.ModuleInstance:
+		moduleInstance := container
+
+		switch ref := r.LocalRef.Subject.(type) {
+		case addrs.Resource:
+			return ref.Instance(addrs.NoKey).Absolute(moduleInstance), true
+		case addrs.ResourceInstance:
+			return ref.Absolute(moduleInstance), true
+		}
+
+		return addrs.AbsResourceInstance{}, false
+
+	case addrs.AbsResourceInstance:
+		return container, true
+	default:
+		// NOTE: We're intentionally using only a subset of possible
+		// addrs.Targetable implementations here, so anything else
+		// is invalid.
+		panic(fmt.Sprintf("reference has invalid container address type %T", container))
+	}
+}
+
+// DebugString returns an internal (but still somewhat Terraform-language-like)
+// compact string representation of the reciever, which isn't an address that
+// any of our usual address parsers could accept but still captures the
+// essence of what the reference represents.
+//
+// The DebugString result is not suitable for end-user-oriented messages.
+//
+// DebugString is also not suitable for use as a unique key for a reference,
+// because it's ambiguous (between a no-key resource instance and a resource)
+// and because it discards the source location information in the LocalRef.
+func (r Reference) DebugString() string {
+	// As the doc comment insinuates, we don't have any real syntax for
+	// "absolute references": references are always local, and targets are
+	// always absolute but only include modules and resources.
+	return r.ContainerAddr.String() + "::" + r.LocalRef.DisplayString()
+}
+
+// ResourceAttr converts the Reference value to a more specific ResourceAttr
+// value.
+//
+// Because not all references belong to resources, the extra boolean return
+// value indicates whether the returned address is valid.
+func (r Reference) ResourceAttr() (ResourceAttr, bool) {
+	res, ok := r.ResourceInstance()
+	if !ok {
+		return ResourceAttr{}, ok
+	}
+
+	traversal := r.LocalRef.Remaining
+
+	path := make(cty.Path, len(traversal))
+	for si, step := range traversal {
+		switch ts := step.(type) {
+		case hcl.TraverseRoot:
+			path[si] = cty.GetAttrStep{
+				Name: ts.Name,
+			}
+		case hcl.TraverseAttr:
+			path[si] = cty.GetAttrStep{
+				Name: ts.Name,
+			}
+		case hcl.TraverseIndex:
+			path[si] = cty.IndexStep{
+				Key: ts.Key,
+			}
+		default:
+			panic(fmt.Sprintf("unsupported traversal step %#v", step))
+		}
+	}
+
+	return ResourceAttr{
+		Resource: res,
+		Attr:     path,
+	}, true
+}
+
+// addrKey returns the referenceAddrKey value for the item that
+// this reference refers to, discarding any source location information.
+//
+// See the referenceAddrKey doc comment for more information on what this
+// is suitable for.
+func (r Reference) addrKey() referenceAddrKey {
+	// This is a pretty arbitrary bunch of stuff. We include the type here
+	// just to differentiate between no-key resource instances and resources.
+	return referenceAddrKey(fmt.Sprintf("%s(%T)%s", r.ContainerAddr.String(), r.LocalRef.Subject, r.LocalRef.DisplayString()))
+}
+
+// referenceAddrKey is a special string type which conventionally contains
+// a unique string representation of the object that a reference refers to,
+// although not of the reference itself because it ignores the information
+// that would differentiate two different references to the same object.
+//
+// The actual content of a referenceAddrKey is arbitrary, for internal use
+// only. and subject to change in future. We use a named type here only to
+// make it easier to see when we're intentionally using strings to uniquely
+// identify absolute reference addresses.
+type referenceAddrKey string
+
+// ResourceAttr represents a global resource and attribute reference.
+// This is a more specific form of the Reference type since it can only refer
+// to a specific AbsResource and one of its attributes.
+type ResourceAttr struct {
+	Resource addrs.AbsResourceInstance
+	Attr     cty.Path
+}
+
+func (r ResourceAttr) DebugString() string {
+	return r.Resource.String() + tfdiags.FormatCtyPath(r.Attr)
+}
diff --git a/v1.5.7/internal/lang/globalref/testdata/assorted/assorted-root.tf b/v1.5.7/internal/lang/globalref/testdata/assorted/assorted-root.tf
new file mode 100644
index 0000000..09f730e
--- /dev/null
+++ b/v1.5.7/internal/lang/globalref/testdata/assorted/assorted-root.tf
@@ -0,0 +1,47 @@
+locals {
+  a = "hello world"
+  b = 2
+  single = test_thing.single.id
+}
+
+resource "test_thing" "single" {
+  string = local.a
+  number = local.b
+
+}
+
+resource "test_thing" "for_each" {
+  for_each = {"q": local.a}
+
+  string = local.a
+
+  single {
+    z = test_thing.single.string
+  }
+}
+
+resource "test_thing" "count" {
+  for_each = length(local.a)
+
+  string = local.a
+}
+
+module "single" {
+  source = "./child"
+
+  a = test_thing.single
+}
+
+module "for_each" {
+  source   = "./child"
+  for_each = {"q": test_thing.single}
+
+  a = test_thing.single
+}
+
+module "count" {
+  source = "./child"
+  count  = length(test_thing.single.string)
+
+  a = test_thing.single
+}
diff --git a/v1.5.7/internal/lang/globalref/testdata/assorted/child/assorted-child.tf b/v1.5.7/internal/lang/globalref/testdata/assorted/child/assorted-child.tf
new file mode 100644
index 0000000..e722fe8
--- /dev/null
+++ b/v1.5.7/internal/lang/globalref/testdata/assorted/child/assorted-child.tf
@@ -0,0 +1,13 @@
+variable "a" {
+}
+
+resource "test_thing" "foo" {
+  string = var.a
+}
+
+output "a" {
+  value = {
+    a   = var.a
+    foo = test_thing.foo
+  }
+}
diff --git a/v1.5.7/internal/lang/globalref/testdata/contributing-resources/compute/contributing-resources-compute.tf b/v1.5.7/internal/lang/globalref/testdata/contributing-resources/compute/contributing-resources-compute.tf
new file mode 100644
index 0000000..a88ec46
--- /dev/null
+++ b/v1.5.7/internal/lang/globalref/testdata/contributing-resources/compute/contributing-resources-compute.tf
@@ -0,0 +1,53 @@
+variable "network" {
+  type = object({
+    vpc_id     = string
+    subnet_ids = map(string)
+  })
+}
+
+resource "test_thing" "controller" {
+  for_each = var.network.subnet_ids
+
+  string = each.value
+}
+
+locals {
+  workers = flatten([
+    for k, id in var.network_subnet_ids : [
+      for n in range(3) : {
+        unique_key = "${k}:${n}"
+        subnet_id = n
+      }
+    ]
+  ])
+
+  controllers = test_thing.controller
+}
+
+resource "test_thing" "worker" {
+  for_each = { for o in local.workers : o.unique_key => o.subnet_id }
+
+  string = each.value
+
+  dynamic "list" {
+    for_each = test_thing.controller
+    content {
+      z = list.value.string
+    }
+  }
+}
+
+resource "test_thing" "load_balancer" {
+  string = var.network.vpc_id
+
+  dynamic "list" {
+    for_each = local.controllers
+    content {
+      z = list.value.string
+    }
+  }
+}
+
+output "compuneetees_api_url" {
+  value = test_thing.load_balancer.string
+}
diff --git a/v1.5.7/internal/lang/globalref/testdata/contributing-resources/contributing-resources-root.tf b/v1.5.7/internal/lang/globalref/testdata/contributing-resources/contributing-resources-root.tf
new file mode 100644
index 0000000..d6ec5c4
--- /dev/null
+++ b/v1.5.7/internal/lang/globalref/testdata/contributing-resources/contributing-resources-root.tf
@@ -0,0 +1,28 @@
+variable "environment" {
+  type = string
+}
+
+data "test_thing" "environment" {
+  string = var.environment
+}
+
+module "network" {
+  source = "./network"
+
+  base_cidr_block = data.test_thing.environment.any.base_cidr_block
+  subnet_count    = data.test_thing.environment.any.subnet_count
+}
+
+module "compute" {
+  source = "./compute"
+
+  network = module.network
+}
+
+output "network" {
+  value = module.network
+}
+
+output "c10s_url" {
+  value = module.compute.compuneetees_api_url
+}
diff --git a/v1.5.7/internal/lang/globalref/testdata/contributing-resources/network/contributing-resources-network.tf b/v1.5.7/internal/lang/globalref/testdata/contributing-resources/network/contributing-resources-network.tf
new file mode 100644
index 0000000..3a4c9dc
--- /dev/null
+++ b/v1.5.7/internal/lang/globalref/testdata/contributing-resources/network/contributing-resources-network.tf
@@ -0,0 +1,41 @@
+variable "base_cidr_block" {
+  type = string
+}
+
+variable "subnet_count" {
+  type = number
+}
+
+locals {
+  subnet_newbits = log(var.subnet_count, 2)
+  subnet_cidr_blocks = toset([
+    for n in range(var.subnet_count) : cidrsubnet(var.base_cidr_block, local.subnet_newbits, n)
+  ])
+}
+
+resource "test_thing" "vpc" {
+  string = var.base_cidr_block
+}
+
+resource "test_thing" "subnet" {
+  for_each = local.subnet_cidr_blocks
+
+  string = test_thing.vpc.string
+  single {
+    z = each.value
+  }
+}
+
+resource "test_thing" "route_table" {
+  for_each = local.subnet_cidr_blocks
+
+  string = each.value
+}
+
+output "vpc_id" {
+  value = test_thing.vpc.string
+}
+
+output "subnet_ids" {
+  value = { for k, sn in test_thing.subnet : k => sn.string }
+}
diff --git a/v1.5.7/internal/lang/marks/marks.go b/v1.5.7/internal/lang/marks/marks.go
new file mode 100644
index 0000000..4b98d1e
--- /dev/null
+++ b/v1.5.7/internal/lang/marks/marks.go
@@ -0,0 +1,45 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package marks
+
+import (
+	"github.com/zclconf/go-cty/cty"
+)
+
+// valueMarks allow creating strictly typed values for use as cty.Value marks.
+// Each distinct mark value must be a constant in this package whose value
+// is a valueMark whose underlying string matches the name of the variable.
+type valueMark string
+
+func (m valueMark) GoString() string {
+	return "marks." + string(m)
+}
+
+// Has returns true if and only if the cty.Value has the given mark.
+func Has(val cty.Value, mark valueMark) bool {
+	return val.HasMark(mark)
+}
+
+// Contains returns true if the cty.Value or any any value within it contains
+// the given mark.
+func Contains(val cty.Value, mark valueMark) bool {
+	ret := false
+	cty.Walk(val, func(_ cty.Path, v cty.Value) (bool, error) {
+		if v.HasMark(mark) {
+			ret = true
+			return false, nil
+		}
+		return true, nil
+	})
+	return ret
+}
+
+// Sensitive indicates that this value is marked as sensitive in the context of
+// Terraform.
+const Sensitive = valueMark("Sensitive")
+
+// TypeType is used to indicate that the value contains a representation of
+// another value's type. This is part of the implementation of the console-only
+// `type` function.
+const TypeType = valueMark("TypeType")
diff --git a/v1.5.7/internal/lang/references.go b/v1.5.7/internal/lang/references.go
new file mode 100644
index 0000000..a1d401a
--- /dev/null
+++ b/v1.5.7/internal/lang/references.go
@@ -0,0 +1,84 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package lang
+
+import (
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/lang/blocktoattr"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// References finds all of the references in the given set of traversals,
+// returning diagnostics if any of the traversals cannot be interpreted as a
+// reference.
+//
+// This function does not do any de-duplication of references, since references
+// have source location information embedded in them and so any invalid
+// references that are duplicated should have errors reported for each
+// occurence.
+//
+// If the returned diagnostics contains errors then the result may be
+// incomplete or invalid. Otherwise, the returned slice has one reference per
+// given traversal, though it is not guaranteed that the references will
+// appear in the same order as the given traversals.
+func References(traversals []hcl.Traversal) ([]*addrs.Reference, tfdiags.Diagnostics) {
+	if len(traversals) == 0 {
+		return nil, nil
+	}
+
+	var diags tfdiags.Diagnostics
+	refs := make([]*addrs.Reference, 0, len(traversals))
+
+	for _, traversal := range traversals {
+		ref, refDiags := addrs.ParseRef(traversal)
+		diags = diags.Append(refDiags)
+		if ref == nil {
+			continue
+		}
+		refs = append(refs, ref)
+	}
+
+	return refs, diags
+}
+
+// ReferencesInBlock is a helper wrapper around References that first searches
+// the given body for traversals, before converting those traversals to
+// references.
+//
+// A block schema must be provided so that this function can determine where in
+// the body variables are expected.
+func ReferencesInBlock(body hcl.Body, schema *configschema.Block) ([]*addrs.Reference, tfdiags.Diagnostics) {
+	if body == nil {
+		return nil, nil
+	}
+
+	// We use blocktoattr.ExpandedVariables instead of hcldec.Variables or
+	// dynblock.VariablesHCLDec here because when we evaluate a block we'll
+	// first apply the dynamic block extension and _then_ the blocktoattr
+	// transform, and so blocktoattr.ExpandedVariables takes into account
+	// both of those transforms when it analyzes the body to ensure we find
+	// all of the references as if they'd already moved into their final
+	// locations, even though we can't expand dynamic blocks yet until we
+	// already know which variables are required.
+	//
+	// The set of cases we want to detect here is covered by the tests for
+	// the plan graph builder in the main 'terraform' package, since it's
+	// in a better position to test this due to having mock providers etc
+	// available.
+	traversals := blocktoattr.ExpandedVariables(body, schema)
+	return References(traversals)
+}
+
+// ReferencesInExpr is a helper wrapper around References that first searches
+// the given expression for traversals, before converting those traversals
+// to references.
+func ReferencesInExpr(expr hcl.Expression) ([]*addrs.Reference, tfdiags.Diagnostics) {
+	if expr == nil {
+		return nil, nil
+	}
+	traversals := expr.Variables()
+	return References(traversals)
+}
diff --git a/v1.5.7/internal/lang/scope.go b/v1.5.7/internal/lang/scope.go
new file mode 100644
index 0000000..267d4c7
--- /dev/null
+++ b/v1.5.7/internal/lang/scope.go
@@ -0,0 +1,67 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package lang
+
+import (
+	"sync"
+	"time"
+
+	"github.com/zclconf/go-cty/cty/function"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/experiments"
+)
+
+// Scope is the main type in this package, allowing dynamic evaluation of
+// blocks and expressions based on some contextual information that informs
+// which variables and functions will be available.
+type Scope struct {
+	// Data is used to resolve references in expressions.
+	Data Data
+
+	// SelfAddr is the address that the "self" object should be an alias of,
+	// or nil if the "self" object should not be available at all.
+	SelfAddr addrs.Referenceable
+
+	// SourceAddr is the address of the source item for the scope. This will
+	// affect any scoped resources that can be accessed from within this scope.
+	//
+	// If nil, access is assumed to be at the module level. So, in practice this
+	// only needs to be set for items that should be able to access something
+	// hidden in their own scope.
+	SourceAddr addrs.Referenceable
+
+	// BaseDir is the base directory used by any interpolation functions that
+	// accept filesystem paths as arguments.
+	BaseDir string
+
+	// PureOnly can be set to true to request that any non-pure functions
+	// produce unknown value results rather than actually executing. This is
+	// important during a plan phase to avoid generating results that could
+	// then differ during apply.
+	PureOnly bool
+
+	funcs     map[string]function.Function
+	funcsLock sync.Mutex
+
+	// activeExperiments is an optional set of experiments that should be
+	// considered as active in the module that this scope will be used for.
+	// Callers can populate it by calling the SetActiveExperiments method.
+	activeExperiments experiments.Set
+
+	// ConsoleMode can be set to true to request any console-only functions are
+	// included in this scope.
+	ConsoleMode bool
+
+	// PlanTimestamp is a timestamp representing when the plan was made. It will
+	// either have been generated during this operation or read from the plan.
+	PlanTimestamp time.Time
+}
+
+// SetActiveExperiments allows a caller to declare that a set of experiments
+// is active for the module that the receiving Scope belongs to, which might
+// then cause the scope to activate some additional experimental behaviors.
+func (s *Scope) SetActiveExperiments(active experiments.Set) {
+	s.activeExperiments = active
+}
diff --git a/v1.5.7/internal/lang/testdata/functions-test/hello.tmpl b/v1.5.7/internal/lang/testdata/functions-test/hello.tmpl
new file mode 100644
index 0000000..f112ef8
--- /dev/null
+++ b/v1.5.7/internal/lang/testdata/functions-test/hello.tmpl
@@ -0,0 +1 @@
+Hello, ${name}!
\ No newline at end of file
diff --git a/v1.5.7/internal/lang/testdata/functions-test/hello.txt b/v1.5.7/internal/lang/testdata/functions-test/hello.txt
new file mode 100644
index 0000000..3462721
--- /dev/null
+++ b/v1.5.7/internal/lang/testdata/functions-test/hello.txt
@@ -0,0 +1 @@
+hello!
\ No newline at end of file
diff --git a/v1.5.7/internal/lang/testdata/functions-test/subdirectory/hello.tmpl b/v1.5.7/internal/lang/testdata/functions-test/subdirectory/hello.tmpl
new file mode 100644
index 0000000..f112ef8
--- /dev/null
+++ b/v1.5.7/internal/lang/testdata/functions-test/subdirectory/hello.tmpl
@@ -0,0 +1 @@
+Hello, ${name}!
\ No newline at end of file
diff --git a/v1.5.7/internal/lang/testdata/functions-test/subdirectory/hello.txt b/v1.5.7/internal/lang/testdata/functions-test/subdirectory/hello.txt
new file mode 100644
index 0000000..3462721
--- /dev/null
+++ b/v1.5.7/internal/lang/testdata/functions-test/subdirectory/hello.txt
@@ -0,0 +1 @@
+hello!
\ No newline at end of file
diff --git a/v1.5.7/internal/lang/types/type_type.go b/v1.5.7/internal/lang/types/type_type.go
new file mode 100644
index 0000000..e0c3cb9
--- /dev/null
+++ b/v1.5.7/internal/lang/types/type_type.go
@@ -0,0 +1,15 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package types
+
+import (
+	"reflect"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+// TypeType is a capsule type used to represent a cty.Type as a cty.Value. This
+// is used by the `type()` console function to smuggle cty.Type values to the
+// REPL session, where it can be displayed to the user directly.
+var TypeType = cty.Capsule("type", reflect.TypeOf(cty.Type{}))
diff --git a/v1.5.7/internal/lang/types/types.go b/v1.5.7/internal/lang/types/types.go
new file mode 100644
index 0000000..b322c6f
--- /dev/null
+++ b/v1.5.7/internal/lang/types/types.go
@@ -0,0 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package types contains non-standard cty types used only within Terraform.
+package types
diff --git a/v1.5.7/internal/legacy/helper/acctest/acctest.go b/v1.5.7/internal/legacy/helper/acctest/acctest.go
new file mode 100644
index 0000000..06b0229
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/acctest/acctest.go
@@ -0,0 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package acctest contains for Terraform Acceptance Tests
+package acctest
diff --git a/v1.5.7/internal/legacy/helper/acctest/random.go b/v1.5.7/internal/legacy/helper/acctest/random.go
new file mode 100644
index 0000000..bbbc48d
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/acctest/random.go
@@ -0,0 +1,179 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package acctest
+
+import (
+	"bytes"
+	crand "crypto/rand"
+	"crypto/rsa"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/pem"
+	"fmt"
+	"math/big"
+	"math/rand"
+	"net"
+	"strings"
+	"time"
+
+	"golang.org/x/crypto/ssh"
+
+	"github.com/apparentlymart/go-cidr/cidr"
+)
+
+func init() {
+	rand.Seed(time.Now().UTC().UnixNano())
+}
+
+// Helpers for generating random tidbits for use in identifiers to prevent
+// collisions in acceptance tests.
+
+// RandInt generates a random integer
+func RandInt() int {
+	return rand.New(rand.NewSource(time.Now().UnixNano())).Int()
+}
+
+// RandomWithPrefix is used to generate a unique name with a prefix, for
+// randomizing names in acceptance tests
+func RandomWithPrefix(name string) string {
+	return fmt.Sprintf("%s-%d", name, rand.New(rand.NewSource(time.Now().UnixNano())).Int())
+}
+
+func RandIntRange(min int, max int) int {
+	source := rand.New(rand.NewSource(time.Now().UnixNano()))
+	rangeMax := max - min
+
+	return int(source.Int31n(int32(rangeMax)))
+}
+
+// RandString generates a random alphanumeric string of the length specified
+func RandString(strlen int) string {
+	return RandStringFromCharSet(strlen, CharSetAlphaNum)
+}
+
+// RandStringFromCharSet generates a random string by selecting characters from
+// the charset provided
+func RandStringFromCharSet(strlen int, charSet string) string {
+	result := make([]byte, strlen)
+	for i := 0; i < strlen; i++ {
+		result[i] = charSet[rand.Intn(len(charSet))]
+	}
+	return string(result)
+}
+
+// RandSSHKeyPair generates a public and private SSH key pair. The public key is
+// returned in OpenSSH format, and the private key is PEM encoded.
+func RandSSHKeyPair(comment string) (string, string, error) {
+	privateKey, privateKeyPEM, err := genPrivateKey()
+	if err != nil {
+		return "", "", err
+	}
+
+	publicKey, err := ssh.NewPublicKey(&privateKey.PublicKey)
+	if err != nil {
+		return "", "", err
+	}
+	keyMaterial := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(publicKey)))
+	return fmt.Sprintf("%s %s", keyMaterial, comment), privateKeyPEM, nil
+}
+
+// RandTLSCert generates a self-signed TLS certificate with a newly created
+// private key, and returns both the cert and the private key PEM encoded.
+func RandTLSCert(orgName string) (string, string, error) {
+	template := &x509.Certificate{
+		SerialNumber: big.NewInt(int64(RandInt())),
+		Subject: pkix.Name{
+			Organization: []string{orgName},
+		},
+		NotBefore:             time.Now(),
+		NotAfter:              time.Now().Add(24 * time.Hour),
+		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+		BasicConstraintsValid: true,
+	}
+
+	privateKey, privateKeyPEM, err := genPrivateKey()
+	if err != nil {
+		return "", "", err
+	}
+
+	cert, err := x509.CreateCertificate(crand.Reader, template, template, &privateKey.PublicKey, privateKey)
+	if err != nil {
+		return "", "", err
+	}
+
+	certPEM, err := pemEncode(cert, "CERTIFICATE")
+	if err != nil {
+		return "", "", err
+	}
+
+	return certPEM, privateKeyPEM, nil
+}
+
+// RandIpAddress returns a random IP address in the specified CIDR block.
+// The prefix length must be less than 31.
+func RandIpAddress(s string) (string, error) {
+	_, network, err := net.ParseCIDR(s)
+	if err != nil {
+		return "", err
+	}
+
+	firstIp, lastIp := cidr.AddressRange(network)
+	first := &big.Int{}
+	first.SetBytes([]byte(firstIp))
+	last := &big.Int{}
+	last.SetBytes([]byte(lastIp))
+	r := &big.Int{}
+	r.Sub(last, first)
+	if len := r.BitLen(); len > 31 {
+		return "", fmt.Errorf("CIDR range is too large: %d", len)
+	}
+
+	max := int(r.Int64())
+	if max == 0 {
+		// panic: invalid argument to Int31n
+		return firstIp.String(), nil
+	}
+
+	host, err := cidr.Host(network, RandIntRange(0, max))
+	if err != nil {
+		return "", err
+	}
+
+	return host.String(), nil
+}
+
+func genPrivateKey() (*rsa.PrivateKey, string, error) {
+	privateKey, err := rsa.GenerateKey(crand.Reader, 1024)
+	if err != nil {
+		return nil, "", err
+	}
+
+	privateKeyPEM, err := pemEncode(x509.MarshalPKCS1PrivateKey(privateKey), "RSA PRIVATE KEY")
+	if err != nil {
+		return nil, "", err
+	}
+
+	return privateKey, privateKeyPEM, nil
+}
+
+func pemEncode(b []byte, block string) (string, error) {
+	var buf bytes.Buffer
+	pb := &pem.Block{Type: block, Bytes: b}
+	if err := pem.Encode(&buf, pb); err != nil {
+		return "", err
+	}
+
+	return buf.String(), nil
+}
+
+const (
+	// CharSetAlphaNum is the alphanumeric character set for use with
+	// RandStringFromCharSet
+	CharSetAlphaNum = "abcdefghijklmnopqrstuvwxyz012346789"
+
+	// CharSetAlpha is the alphabetical character set for use with
+	// RandStringFromCharSet
+	CharSetAlpha = "abcdefghijklmnopqrstuvwxyz"
+)
diff --git a/v1.5.7/internal/legacy/helper/acctest/random_test.go b/v1.5.7/internal/legacy/helper/acctest/random_test.go
new file mode 100644
index 0000000..5ae494c
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/acctest/random_test.go
@@ -0,0 +1,61 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package acctest
+
+import (
+	"regexp"
+	"testing"
+)
+
+func TestRandIpAddress(t *testing.T) {
+	testCases := []struct {
+		s           string
+		expected    *regexp.Regexp
+		expectedErr string
+	}{
+		{
+			s:        "1.1.1.1/32",
+			expected: regexp.MustCompile(`^1\.1\.1\.1$`),
+		},
+		{
+			s:        "10.0.0.0/8",
+			expected: regexp.MustCompile(`^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$`),
+		},
+		{
+			s:           "0.0.0.0/0",
+			expectedErr: "CIDR range is too large: 32",
+		},
+		{
+			s:        "449d:e5f1:14b1:ddf3:8525:7e9e:4a0d:4a82/128",
+			expected: regexp.MustCompile(`^449d:e5f1:14b1:ddf3:8525:7e9e:4a0d:4a82$`),
+		},
+		{
+			s:        "2001:db8::/112",
+			expected: regexp.MustCompile(`^2001:db8::[[:xdigit:]]{1,4}$`),
+		},
+		{
+			s:           "2001:db8::/64",
+			expectedErr: "CIDR range is too large: 64",
+		},
+		{
+			s:           "abcdefg",
+			expectedErr: "invalid CIDR address: abcdefg",
+		},
+	}
+
+	for i, tc := range testCases {
+		v, err := RandIpAddress(tc.s)
+		if err != nil {
+			msg := err.Error()
+			if tc.expectedErr == "" {
+				t.Fatalf("expected test case %d to succeed but got error %q, ", i, msg)
+			}
+			if msg != tc.expectedErr {
+				t.Fatalf("expected test case %d to fail with %q but got %q", i, tc.expectedErr, msg)
+			}
+		} else if !tc.expected.MatchString(v) {
+			t.Fatalf("expected test case %d to return %q but got %q", i, tc.expected, v)
+		}
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/acctest/remotetests.go b/v1.5.7/internal/legacy/helper/acctest/remotetests.go
new file mode 100644
index 0000000..2475575
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/acctest/remotetests.go
@@ -0,0 +1,30 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package acctest
+
+import (
+	"net/http"
+	"os"
+	"testing"
+)
+
+// SkipRemoteTestsEnvVar is an environment variable that can be set by a user
+// running the tests in an environment with limited network connectivity. By
+// default, tests requiring internet connectivity make an effort to skip if no
+// internet is available, but in some cases the smoke test will pass even
+// though the test should still be skipped.
+const SkipRemoteTestsEnvVar = "TF_SKIP_REMOTE_TESTS"
+
+// RemoteTestPrecheck is meant to be run by any unit test that requires
+// outbound internet connectivity. The test will be skipped if it's
+// unavailable.
+func RemoteTestPrecheck(t *testing.T) {
+	if os.Getenv(SkipRemoteTestsEnvVar) != "" {
+		t.Skipf("skipping test, %s was set", SkipRemoteTestsEnvVar)
+	}
+
+	if _, err := http.Get("http://google.com"); err != nil {
+		t.Skipf("skipping, internet seems to not be available: %s", err)
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/hashcode/hashcode.go b/v1.5.7/internal/legacy/helper/hashcode/hashcode.go
new file mode 100644
index 0000000..21622a0
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/hashcode/hashcode.go
@@ -0,0 +1,38 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package hashcode
+
+import (
+	"bytes"
+	"fmt"
+	"hash/crc32"
+)
+
+// String hashes a string to a unique hashcode.
+//
+// crc32 returns a uint32, but for our use we need
+// a non negative integer. Here we cast to an integer
+// and invert it if the result is negative.
+func String(s string) int {
+	v := int(crc32.ChecksumIEEE([]byte(s)))
+	if v >= 0 {
+		return v
+	}
+	if -v >= 0 {
+		return -v
+	}
+	// v == MinInt
+	return 0
+}
+
+// Strings hashes a list of strings to a unique hashcode.
+func Strings(strings []string) string {
+	var buf bytes.Buffer
+
+	for _, s := range strings {
+		buf.WriteString(fmt.Sprintf("%s-", s))
+	}
+
+	return fmt.Sprintf("%d", String(buf.String()))
+}
diff --git a/v1.5.7/internal/legacy/helper/hashcode/hashcode_test.go b/v1.5.7/internal/legacy/helper/hashcode/hashcode_test.go
new file mode 100644
index 0000000..3fb6049
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/hashcode/hashcode_test.go
@@ -0,0 +1,40 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package hashcode
+
+import (
+	"testing"
+)
+
+func TestString(t *testing.T) {
+	v := "hello, world"
+	expected := String(v)
+	for i := 0; i < 100; i++ {
+		actual := String(v)
+		if actual != expected {
+			t.Fatalf("bad: %#v\n\t%#v", actual, expected)
+		}
+	}
+}
+
+func TestStrings(t *testing.T) {
+	v := []string{"hello", ",", "world"}
+	expected := Strings(v)
+	for i := 0; i < 100; i++ {
+		actual := Strings(v)
+		if actual != expected {
+			t.Fatalf("bad: %#v\n\t%#v", actual, expected)
+		}
+	}
+}
+
+func TestString_positiveIndex(t *testing.T) {
+	// "2338615298" hashes to uint32(2147483648) which is math.MinInt32
+	ips := []string{"192.168.1.3", "192.168.1.5", "2338615298"}
+	for _, ip := range ips {
+		if index := String(ip); index < 0 {
+			t.Fatalf("Bad Index %#v for ip %s", index, ip)
+		}
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/backend.go b/v1.5.7/internal/legacy/helper/schema/backend.go
new file mode 100644
index 0000000..2301638
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/backend.go
@@ -0,0 +1,203 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+	ctyconvert "github.com/zclconf/go-cty/cty/convert"
+)
+
+// Backend represents a partial backend.Backend implementation and simplifies
+// the creation of configuration loading and validation.
+//
+// Unlike other schema structs such as Provider, this struct is meant to be
+// embedded within your actual implementation. It provides implementations
+// only for Input and Configure and gives you a method for accessing the
+// configuration in the form of a ResourceData that you're expected to call
+// from the other implementation funcs.
+type Backend struct {
+	// Schema is the schema for the configuration of this backend. If this
+	// Backend has no configuration this can be omitted.
+	Schema map[string]*Schema
+
+	// ConfigureFunc is called to configure the backend. Use the
+	// FromContext* methods to extract information from the context.
+	// This can be nil, in which case nothing will be called but the
+	// config will still be stored.
+	ConfigureFunc func(context.Context) error
+
+	config *ResourceData
+}
+
+var (
+	backendConfigKey = contextKey("backend config")
+)
+
+// FromContextBackendConfig extracts a ResourceData with the configuration
+// from the context. This should only be called by Backend functions.
+func FromContextBackendConfig(ctx context.Context) *ResourceData {
+	return ctx.Value(backendConfigKey).(*ResourceData)
+}
+
+func (b *Backend) ConfigSchema() *configschema.Block {
+	// This is an alias of CoreConfigSchema just to implement the
+	// backend.Backend interface.
+	return b.CoreConfigSchema()
+}
+
+func (b *Backend) PrepareConfig(configVal cty.Value) (cty.Value, tfdiags.Diagnostics) {
+	if b == nil {
+		return configVal, nil
+	}
+	var diags tfdiags.Diagnostics
+	var err error
+
+	// In order to use Transform below, this needs to be filled out completely
+	// according the schema.
+	configVal, err = b.CoreConfigSchema().CoerceValue(configVal)
+	if err != nil {
+		return configVal, diags.Append(err)
+	}
+
+	// lookup any required, top-level attributes that are Null, and see if we
+	// have a Default value available.
+	configVal, err = cty.Transform(configVal, func(path cty.Path, val cty.Value) (cty.Value, error) {
+		// we're only looking for top-level attributes
+		if len(path) != 1 {
+			return val, nil
+		}
+
+		// nothing to do if we already have a value
+		if !val.IsNull() {
+			return val, nil
+		}
+
+		// get the Schema definition for this attribute
+		getAttr, ok := path[0].(cty.GetAttrStep)
+		// these should all exist, but just ignore anything strange
+		if !ok {
+			return val, nil
+		}
+
+		attrSchema := b.Schema[getAttr.Name]
+		// continue to ignore anything that doesn't match
+		if attrSchema == nil {
+			return val, nil
+		}
+
+		// this is deprecated, so don't set it
+		if attrSchema.Deprecated != "" || attrSchema.Removed != "" {
+			return val, nil
+		}
+
+		// find a default value if it exists
+		def, err := attrSchema.DefaultValue()
+		if err != nil {
+			diags = diags.Append(fmt.Errorf("error getting default for %q: %s", getAttr.Name, err))
+			return val, err
+		}
+
+		// no default
+		if def == nil {
+			return val, nil
+		}
+
+		// create a cty.Value and make sure it's the correct type
+		tmpVal := hcl2shim.HCL2ValueFromConfigValue(def)
+
+		// helper/schema used to allow setting "" to a bool
+		if val.Type() == cty.Bool && tmpVal.RawEquals(cty.StringVal("")) {
+			// return a warning about the conversion
+			diags = diags.Append("provider set empty string as default value for bool " + getAttr.Name)
+			tmpVal = cty.False
+		}
+
+		val, err = ctyconvert.Convert(tmpVal, val.Type())
+		if err != nil {
+			diags = diags.Append(fmt.Errorf("error setting default for %q: %s", getAttr.Name, err))
+		}
+
+		return val, err
+	})
+	if err != nil {
+		// any error here was already added to the diagnostics
+		return configVal, diags
+	}
+
+	shimRC := b.shimConfig(configVal)
+	warns, errs := schemaMap(b.Schema).Validate(shimRC)
+	for _, warn := range warns {
+		diags = diags.Append(tfdiags.SimpleWarning(warn))
+	}
+	for _, err := range errs {
+		diags = diags.Append(err)
+	}
+	return configVal, diags
+}
+
+func (b *Backend) Configure(obj cty.Value) tfdiags.Diagnostics {
+	if b == nil {
+		return nil
+	}
+
+	var diags tfdiags.Diagnostics
+	sm := schemaMap(b.Schema)
+	shimRC := b.shimConfig(obj)
+
+	// Get a ResourceData for this configuration. To do this, we actually
+	// generate an intermediary "diff" although that is never exposed.
+	diff, err := sm.Diff(nil, shimRC, nil, nil, true)
+	if err != nil {
+		diags = diags.Append(err)
+		return diags
+	}
+
+	data, err := sm.Data(nil, diff)
+	if err != nil {
+		diags = diags.Append(err)
+		return diags
+	}
+	b.config = data
+
+	if b.ConfigureFunc != nil {
+		err = b.ConfigureFunc(context.WithValue(
+			context.Background(), backendConfigKey, data))
+		if err != nil {
+			diags = diags.Append(err)
+			return diags
+		}
+	}
+
+	return diags
+}
+
+// shimConfig turns a new-style cty.Value configuration (which must be of
+// an object type) into a minimal old-style *terraform.ResourceConfig object
+// that should be populated enough to appease the not-yet-updated functionality
+// in this package. This should be removed once everything is updated.
+func (b *Backend) shimConfig(obj cty.Value) *terraform.ResourceConfig {
+	shimMap, ok := hcl2shim.ConfigValueFromHCL2(obj).(map[string]interface{})
+	if !ok {
+		// If the configVal was nil, we still want a non-nil map here.
+		shimMap = map[string]interface{}{}
+	}
+	return &terraform.ResourceConfig{
+		Config: shimMap,
+		Raw:    shimMap,
+	}
+}
+
+// Config returns the configuration. This is available after Configure is
+// called.
+func (b *Backend) Config() *ResourceData {
+	return b.config
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/backend_test.go b/v1.5.7/internal/legacy/helper/schema/backend_test.go
new file mode 100644
index 0000000..ca28e06
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/backend_test.go
@@ -0,0 +1,196 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"context"
+	"fmt"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestBackendPrepare(t *testing.T) {
+	cases := []struct {
+		Name   string
+		B      *Backend
+		Config map[string]cty.Value
+		Expect map[string]cty.Value
+		Err    bool
+	}{
+		{
+			"Basic required field",
+			&Backend{
+				Schema: map[string]*Schema{
+					"foo": &Schema{
+						Required: true,
+						Type:     TypeString,
+					},
+				},
+			},
+			map[string]cty.Value{},
+			map[string]cty.Value{},
+			true,
+		},
+
+		{
+			"Null config",
+			&Backend{
+				Schema: map[string]*Schema{
+					"foo": &Schema{
+						Required: true,
+						Type:     TypeString,
+					},
+				},
+			},
+			nil,
+			map[string]cty.Value{},
+			true,
+		},
+
+		{
+			"Basic required field set",
+			&Backend{
+				Schema: map[string]*Schema{
+					"foo": &Schema{
+						Required: true,
+						Type:     TypeString,
+					},
+				},
+			},
+			map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+			},
+			map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+			},
+			false,
+		},
+
+		{
+			"unused default",
+			&Backend{
+				Schema: map[string]*Schema{
+					"foo": &Schema{
+						Optional: true,
+						Type:     TypeString,
+						Default:  "baz",
+					},
+				},
+			},
+			map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+			},
+			map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+			},
+			false,
+		},
+
+		{
+			"default",
+			&Backend{
+				Schema: map[string]*Schema{
+					"foo": &Schema{
+						Type:     TypeString,
+						Optional: true,
+						Default:  "baz",
+					},
+				},
+			},
+			map[string]cty.Value{},
+			map[string]cty.Value{
+				"foo": cty.StringVal("baz"),
+			},
+			false,
+		},
+
+		{
+			"default func",
+			&Backend{
+				Schema: map[string]*Schema{
+					"foo": &Schema{
+						Type:     TypeString,
+						Optional: true,
+						DefaultFunc: func() (interface{}, error) {
+							return "baz", nil
+						},
+					},
+				},
+			},
+			map[string]cty.Value{},
+			map[string]cty.Value{
+				"foo": cty.StringVal("baz"),
+			},
+			false,
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			cfgVal := cty.NullVal(cty.Object(map[string]cty.Type{}))
+			if tc.Config != nil {
+				cfgVal = cty.ObjectVal(tc.Config)
+			}
+			configVal, diags := tc.B.PrepareConfig(cfgVal)
+			if diags.HasErrors() != tc.Err {
+				for _, d := range diags {
+					t.Error(d.Description())
+				}
+			}
+
+			if tc.Err {
+				return
+			}
+
+			expect := cty.ObjectVal(tc.Expect)
+			if !expect.RawEquals(configVal) {
+				t.Fatalf("\nexpected: %#v\ngot:     %#v\n", expect, configVal)
+			}
+		})
+	}
+}
+
+func TestBackendConfigure(t *testing.T) {
+	cases := []struct {
+		Name   string
+		B      *Backend
+		Config map[string]cty.Value
+		Err    bool
+	}{
+		{
+			"Basic config",
+			&Backend{
+				Schema: map[string]*Schema{
+					"foo": &Schema{
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+
+				ConfigureFunc: func(ctx context.Context) error {
+					d := FromContextBackendConfig(ctx)
+					if d.Get("foo").(int) != 42 {
+						return fmt.Errorf("bad config data")
+					}
+
+					return nil
+				},
+			},
+			map[string]cty.Value{
+				"foo": cty.NumberIntVal(42),
+			},
+			false,
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			diags := tc.B.Configure(cty.ObjectVal(tc.Config))
+			if diags.HasErrors() != tc.Err {
+				t.Errorf("wrong number of diagnostics")
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/core_schema.go b/v1.5.7/internal/legacy/helper/schema/core_schema.go
new file mode 100644
index 0000000..490fa71
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/core_schema.go
@@ -0,0 +1,312 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// The functions and methods in this file are concerned with the conversion
+// of this package's schema model into the slightly-lower-level schema model
+// used by Terraform core for configuration parsing.
+
+// CoreConfigSchema lowers the receiver to the schema model expected by
+// Terraform core.
+//
+// This lower-level model has fewer features than the schema in this package,
+// describing only the basic structure of configuration and state values we
+// expect. The full schemaMap from this package is still required for full
+// validation, handling of default values, etc.
+//
+// This method presumes a schema that passes InternalValidate, and so may
+// panic or produce an invalid result if given an invalid schemaMap.
+func (m schemaMap) CoreConfigSchema() *configschema.Block {
+	if len(m) == 0 {
+		// We return an actual (empty) object here, rather than a nil,
+		// because a nil result would mean that we don't have a schema at
+		// all, rather than that we have an empty one.
+		return &configschema.Block{}
+	}
+
+	ret := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{},
+		BlockTypes: map[string]*configschema.NestedBlock{},
+	}
+
+	for name, schema := range m {
+		if schema.Elem == nil {
+			ret.Attributes[name] = schema.coreConfigSchemaAttribute()
+			continue
+		}
+		if schema.Type == TypeMap {
+			// For TypeMap in particular, it isn't valid for Elem to be a
+			// *Resource (since that would be ambiguous in flatmap) and
+			// so Elem is treated as a TypeString schema if so. This matches
+			// how the field readers treat this situation, for compatibility
+			// with configurations targeting Terraform 0.11 and earlier.
+			if _, isResource := schema.Elem.(*Resource); isResource {
+				sch := *schema // shallow copy
+				sch.Elem = &Schema{
+					Type: TypeString,
+				}
+				ret.Attributes[name] = sch.coreConfigSchemaAttribute()
+				continue
+			}
+		}
+		switch schema.ConfigMode {
+		case SchemaConfigModeAttr:
+			ret.Attributes[name] = schema.coreConfigSchemaAttribute()
+		case SchemaConfigModeBlock:
+			ret.BlockTypes[name] = schema.coreConfigSchemaBlock()
+		default: // SchemaConfigModeAuto, or any other invalid value
+			if schema.Computed && !schema.Optional {
+				// Computed-only schemas are always handled as attributes,
+				// because they never appear in configuration.
+				ret.Attributes[name] = schema.coreConfigSchemaAttribute()
+				continue
+			}
+			switch schema.Elem.(type) {
+			case *Schema, ValueType:
+				ret.Attributes[name] = schema.coreConfigSchemaAttribute()
+			case *Resource:
+				ret.BlockTypes[name] = schema.coreConfigSchemaBlock()
+			default:
+				// Should never happen for a valid schema
+				panic(fmt.Errorf("invalid Schema.Elem %#v; need *Schema or *Resource", schema.Elem))
+			}
+		}
+	}
+
+	return ret
+}
+
+// coreConfigSchemaAttribute prepares a configschema.Attribute representation
+// of a schema. This is appropriate only for primitives or collections whose
+// Elem is an instance of Schema. Use coreConfigSchemaBlock for collections
+// whose elem is a whole resource.
+func (s *Schema) coreConfigSchemaAttribute() *configschema.Attribute {
+	// The Schema.DefaultFunc capability adds some extra weirdness here since
+	// it can be combined with "Required: true" to create a situation where
+	// required-ness is conditional. Terraform Core doesn't share this concept,
+	// so we must sniff for this possibility here and conditionally turn
+	// off the "Required" flag if it looks like the DefaultFunc is going
+	// to provide a value.
+	// This is not 100% true to the original interface of DefaultFunc but
+	// works well enough for the EnvDefaultFunc and MultiEnvDefaultFunc
+	// situations, which are the main cases we care about.
+	//
+	// Note that this also has a consequence for commands that return schema
+	// information for documentation purposes: running those for certain
+	// providers will produce different results depending on which environment
+	// variables are set. We accept that weirdness in order to keep this
+	// interface to core otherwise simple.
+	reqd := s.Required
+	opt := s.Optional
+	if reqd && s.DefaultFunc != nil {
+		v, err := s.DefaultFunc()
+		// We can't report errors from here, so we'll instead just force
+		// "Required" to false and let the provider try calling its
+		// DefaultFunc again during the validate step, where it can then
+		// return the error.
+		if err != nil || (err == nil && v != nil) {
+			reqd = false
+			opt = true
+		}
+	}
+
+	return &configschema.Attribute{
+		Type:        s.coreConfigSchemaType(),
+		Optional:    opt,
+		Required:    reqd,
+		Computed:    s.Computed,
+		Sensitive:   s.Sensitive,
+		Description: s.Description,
+	}
+}
+
+// coreConfigSchemaBlock prepares a configschema.NestedBlock representation of
+// a schema. This is appropriate only for collections whose Elem is an instance
+// of Resource, and will panic otherwise.
+func (s *Schema) coreConfigSchemaBlock() *configschema.NestedBlock {
+	ret := &configschema.NestedBlock{}
+	if nested := s.Elem.(*Resource).coreConfigSchema(); nested != nil {
+		ret.Block = *nested
+	}
+	switch s.Type {
+	case TypeList:
+		ret.Nesting = configschema.NestingList
+	case TypeSet:
+		ret.Nesting = configschema.NestingSet
+	case TypeMap:
+		ret.Nesting = configschema.NestingMap
+	default:
+		// Should never happen for a valid schema
+		panic(fmt.Errorf("invalid s.Type %s for s.Elem being resource", s.Type))
+	}
+
+	ret.MinItems = s.MinItems
+	ret.MaxItems = s.MaxItems
+
+	if s.Required && s.MinItems == 0 {
+		// configschema doesn't have a "required" representation for nested
+		// blocks, but we can fake it by requiring at least one item.
+		ret.MinItems = 1
+	}
+	if s.Optional && s.MinItems > 0 {
+		// Historically helper/schema would ignore MinItems if Optional were
+		// set, so we must mimic this behavior here to ensure that providers
+		// relying on that undocumented behavior can continue to operate as
+		// they did before.
+		ret.MinItems = 0
+	}
+	if s.Computed && !s.Optional {
+		// MinItems/MaxItems are meaningless for computed nested blocks, since
+		// they are never set by the user anyway. This ensures that we'll never
+		// generate weird errors about them.
+		ret.MinItems = 0
+		ret.MaxItems = 0
+	}
+
+	return ret
+}
+
+// coreConfigSchemaType determines the core config schema type that corresponds
+// to a particular schema's type.
+func (s *Schema) coreConfigSchemaType() cty.Type {
+	switch s.Type {
+	case TypeString:
+		return cty.String
+	case TypeBool:
+		return cty.Bool
+	case TypeInt, TypeFloat:
+		// configschema doesn't distinguish int and float, so helper/schema
+		// will deal with this as an additional validation step after
+		// configuration has been parsed and decoded.
+		return cty.Number
+	case TypeList, TypeSet, TypeMap:
+		var elemType cty.Type
+		switch set := s.Elem.(type) {
+		case *Schema:
+			elemType = set.coreConfigSchemaType()
+		case ValueType:
+			// This represents a mistake in the provider code, but it's a
+			// common one so we'll just shim it.
+			elemType = (&Schema{Type: set}).coreConfigSchemaType()
+		case *Resource:
+			// By default we construct a NestedBlock in this case, but this
+			// behavior is selected either for computed-only schemas or
+			// when ConfigMode is explicitly SchemaConfigModeBlock.
+			// See schemaMap.CoreConfigSchema for the exact rules.
+			elemType = set.coreConfigSchema().ImpliedType()
+		default:
+			if set != nil {
+				// Should never happen for a valid schema
+				panic(fmt.Errorf("invalid Schema.Elem %#v; need *Schema or *Resource", s.Elem))
+			}
+			// Some pre-existing schemas assume string as default, so we need
+			// to be compatible with them.
+			elemType = cty.String
+		}
+		switch s.Type {
+		case TypeList:
+			return cty.List(elemType)
+		case TypeSet:
+			return cty.Set(elemType)
+		case TypeMap:
+			return cty.Map(elemType)
+		default:
+			// can never get here in practice, due to the case we're inside
+			panic("invalid collection type")
+		}
+	default:
+		// should never happen for a valid schema
+		panic(fmt.Errorf("invalid Schema.Type %s", s.Type))
+	}
+}
+
+// CoreConfigSchema is a convenient shortcut for calling CoreConfigSchema on
+// the resource's schema. CoreConfigSchema adds the implicitly required "id"
+// attribute for top level resources if it doesn't exist.
+func (r *Resource) CoreConfigSchema() *configschema.Block {
+	block := r.coreConfigSchema()
+
+	if block.Attributes == nil {
+		block.Attributes = map[string]*configschema.Attribute{}
+	}
+
+	// Add the implicitly required "id" field if it doesn't exist
+	if block.Attributes["id"] == nil {
+		block.Attributes["id"] = &configschema.Attribute{
+			Type:     cty.String,
+			Optional: true,
+			Computed: true,
+		}
+	}
+
+	_, timeoutsAttr := block.Attributes[TimeoutsConfigKey]
+	_, timeoutsBlock := block.BlockTypes[TimeoutsConfigKey]
+
+	// Insert configured timeout values into the schema, as long as the schema
+	// didn't define anything else by that name.
+	if r.Timeouts != nil && !timeoutsAttr && !timeoutsBlock {
+		timeouts := configschema.Block{
+			Attributes: map[string]*configschema.Attribute{},
+		}
+
+		if r.Timeouts.Create != nil {
+			timeouts.Attributes[TimeoutCreate] = &configschema.Attribute{
+				Type:     cty.String,
+				Optional: true,
+			}
+		}
+
+		if r.Timeouts.Read != nil {
+			timeouts.Attributes[TimeoutRead] = &configschema.Attribute{
+				Type:     cty.String,
+				Optional: true,
+			}
+		}
+
+		if r.Timeouts.Update != nil {
+			timeouts.Attributes[TimeoutUpdate] = &configschema.Attribute{
+				Type:     cty.String,
+				Optional: true,
+			}
+		}
+
+		if r.Timeouts.Delete != nil {
+			timeouts.Attributes[TimeoutDelete] = &configschema.Attribute{
+				Type:     cty.String,
+				Optional: true,
+			}
+		}
+
+		if r.Timeouts.Default != nil {
+			timeouts.Attributes[TimeoutDefault] = &configschema.Attribute{
+				Type:     cty.String,
+				Optional: true,
+			}
+		}
+
+		block.BlockTypes[TimeoutsConfigKey] = &configschema.NestedBlock{
+			Nesting: configschema.NestingSingle,
+			Block:   timeouts,
+		}
+	}
+
+	return block
+}
+
+func (r *Resource) coreConfigSchema() *configschema.Block {
+	return schemaMap(r.Schema).CoreConfigSchema()
+}
+
+// CoreConfigSchema is a convenient shortcut for calling CoreConfigSchema
+// on the backends's schema.
+func (r *Backend) CoreConfigSchema() *configschema.Block {
+	return schemaMap(r.Schema).CoreConfigSchema()
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/core_schema_test.go b/v1.5.7/internal/legacy/helper/schema/core_schema_test.go
new file mode 100644
index 0000000..903150b
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/core_schema_test.go
@@ -0,0 +1,461 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+// add the implicit "id" attribute for test resources
+func testResource(block *configschema.Block) *configschema.Block {
+	if block.Attributes == nil {
+		block.Attributes = make(map[string]*configschema.Attribute)
+	}
+
+	if block.BlockTypes == nil {
+		block.BlockTypes = make(map[string]*configschema.NestedBlock)
+	}
+
+	if block.Attributes["id"] == nil {
+		block.Attributes["id"] = &configschema.Attribute{
+			Type:     cty.String,
+			Optional: true,
+			Computed: true,
+		}
+	}
+	return block
+}
+
+func TestSchemaMapCoreConfigSchema(t *testing.T) {
+	tests := map[string]struct {
+		Schema map[string]*Schema
+		Want   *configschema.Block
+	}{
+		"empty": {
+			map[string]*Schema{},
+			testResource(&configschema.Block{}),
+		},
+		"primitives": {
+			map[string]*Schema{
+				"int": {
+					Type:        TypeInt,
+					Required:    true,
+					Description: "foo bar baz",
+				},
+				"float": {
+					Type:     TypeFloat,
+					Optional: true,
+				},
+				"bool": {
+					Type:     TypeBool,
+					Computed: true,
+				},
+				"string": {
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+			testResource(&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"int": {
+						Type:        cty.Number,
+						Required:    true,
+						Description: "foo bar baz",
+					},
+					"float": {
+						Type:     cty.Number,
+						Optional: true,
+					},
+					"bool": {
+						Type:     cty.Bool,
+						Computed: true,
+					},
+					"string": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{},
+			}),
+		},
+		"simple collections": {
+			map[string]*Schema{
+				"list": {
+					Type:     TypeList,
+					Required: true,
+					Elem: &Schema{
+						Type: TypeInt,
+					},
+				},
+				"set": {
+					Type:     TypeSet,
+					Optional: true,
+					Elem: &Schema{
+						Type: TypeString,
+					},
+				},
+				"map": {
+					Type:     TypeMap,
+					Optional: true,
+					Elem: &Schema{
+						Type: TypeBool,
+					},
+				},
+				"map_default_type": {
+					Type:     TypeMap,
+					Optional: true,
+					// Maps historically don't have elements because we
+					// assumed they would be strings, so this needs to work
+					// for pre-existing schemas.
+				},
+			},
+			testResource(&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"list": {
+						Type:     cty.List(cty.Number),
+						Required: true,
+					},
+					"set": {
+						Type:     cty.Set(cty.String),
+						Optional: true,
+					},
+					"map": {
+						Type:     cty.Map(cty.Bool),
+						Optional: true,
+					},
+					"map_default_type": {
+						Type:     cty.Map(cty.String),
+						Optional: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{},
+			}),
+		},
+		"incorrectly-specified collections": {
+			// Historically we tolerated setting a type directly as the Elem
+			// attribute, rather than a Schema object. This is common enough
+			// in existing provider code that we must support it as an alias
+			// for a schema object with the given type.
+			map[string]*Schema{
+				"list": {
+					Type:     TypeList,
+					Required: true,
+					Elem:     TypeInt,
+				},
+				"set": {
+					Type:     TypeSet,
+					Optional: true,
+					Elem:     TypeString,
+				},
+				"map": {
+					Type:     TypeMap,
+					Optional: true,
+					Elem:     TypeBool,
+				},
+			},
+			testResource(&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"list": {
+						Type:     cty.List(cty.Number),
+						Required: true,
+					},
+					"set": {
+						Type:     cty.Set(cty.String),
+						Optional: true,
+					},
+					"map": {
+						Type:     cty.Map(cty.Bool),
+						Optional: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{},
+			}),
+		},
+		"sub-resource collections": {
+			map[string]*Schema{
+				"list": {
+					Type:     TypeList,
+					Required: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{},
+					},
+					MinItems: 1,
+					MaxItems: 2,
+				},
+				"set": {
+					Type:     TypeSet,
+					Required: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{},
+					},
+				},
+				"map": {
+					Type:     TypeMap,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{},
+					},
+				},
+			},
+			testResource(&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					// This one becomes a string attribute because helper/schema
+					// doesn't actually support maps of resource. The given
+					// "Elem" is just ignored entirely here, which is important
+					// because that is also true of the helper/schema logic and
+					// existing providers rely on this being ignored for
+					// correct operation.
+					"map": {
+						Type:     cty.Map(cty.String),
+						Optional: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"list": {
+						Nesting:  configschema.NestingList,
+						Block:    configschema.Block{},
+						MinItems: 1,
+						MaxItems: 2,
+					},
+					"set": {
+						Nesting:  configschema.NestingSet,
+						Block:    configschema.Block{},
+						MinItems: 1, // because schema is Required
+					},
+				},
+			}),
+		},
+		"sub-resource collections minitems+optional": {
+			// This particular case is an odd one where the provider gives
+			// conflicting information about whether a sub-resource is required,
+			// by marking it as optional but also requiring one item.
+			// Historically the optional-ness "won" here, and so we must
+			// honor that for compatibility with providers that relied on this
+			// undocumented interaction.
+			map[string]*Schema{
+				"list": {
+					Type:     TypeList,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{},
+					},
+					MinItems: 1,
+					MaxItems: 1,
+				},
+				"set": {
+					Type:     TypeSet,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{},
+					},
+					MinItems: 1,
+					MaxItems: 1,
+				},
+			},
+			testResource(&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"list": {
+						Nesting:  configschema.NestingList,
+						Block:    configschema.Block{},
+						MinItems: 0,
+						MaxItems: 1,
+					},
+					"set": {
+						Nesting:  configschema.NestingSet,
+						Block:    configschema.Block{},
+						MinItems: 0,
+						MaxItems: 1,
+					},
+				},
+			}),
+		},
+		"sub-resource collections minitems+computed": {
+			map[string]*Schema{
+				"list": {
+					Type:     TypeList,
+					Computed: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{},
+					},
+					MinItems: 1,
+					MaxItems: 1,
+				},
+				"set": {
+					Type:     TypeSet,
+					Computed: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{},
+					},
+					MinItems: 1,
+					MaxItems: 1,
+				},
+			},
+			testResource(&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"list": {
+						Type:     cty.List(cty.EmptyObject),
+						Computed: true,
+					},
+					"set": {
+						Type:     cty.Set(cty.EmptyObject),
+						Computed: true,
+					},
+				},
+			}),
+		},
+		"nested attributes and blocks": {
+			map[string]*Schema{
+				"foo": {
+					Type:     TypeList,
+					Required: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"bar": {
+								Type:     TypeList,
+								Required: true,
+								Elem: &Schema{
+									Type: TypeList,
+									Elem: &Schema{
+										Type: TypeString,
+									},
+								},
+							},
+							"baz": {
+								Type:     TypeSet,
+								Optional: true,
+								Elem: &Resource{
+									Schema: map[string]*Schema{},
+								},
+							},
+						},
+					},
+				},
+			},
+			testResource(&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": &configschema.NestedBlock{
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {
+									Type:     cty.List(cty.List(cty.String)),
+									Required: true,
+								},
+							},
+							BlockTypes: map[string]*configschema.NestedBlock{
+								"baz": {
+									Nesting: configschema.NestingSet,
+									Block:   configschema.Block{},
+								},
+							},
+						},
+						MinItems: 1, // because schema is Required
+					},
+				},
+			}),
+		},
+		"sensitive": {
+			map[string]*Schema{
+				"string": {
+					Type:      TypeString,
+					Optional:  true,
+					Sensitive: true,
+				},
+			},
+			testResource(&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"string": {
+						Type:      cty.String,
+						Optional:  true,
+						Sensitive: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{},
+			}),
+		},
+		"conditionally required on": {
+			map[string]*Schema{
+				"string": {
+					Type:     TypeString,
+					Required: true,
+					DefaultFunc: func() (interface{}, error) {
+						return nil, nil
+					},
+				},
+			},
+			testResource(&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"string": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{},
+			}),
+		},
+		"conditionally required off": {
+			map[string]*Schema{
+				"string": {
+					Type:     TypeString,
+					Required: true,
+					DefaultFunc: func() (interface{}, error) {
+						// If we return a non-nil default then this overrides
+						// the "Required: true" for the purpose of building
+						// the core schema, so that core will ignore it not
+						// being set and let the provider handle it.
+						return "boop", nil
+					},
+				},
+			},
+			testResource(&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"string": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{},
+			}),
+		},
+		"conditionally required error": {
+			map[string]*Schema{
+				"string": {
+					Type:     TypeString,
+					Required: true,
+					DefaultFunc: func() (interface{}, error) {
+						return nil, fmt.Errorf("placeholder error")
+					},
+				},
+			},
+			testResource(&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"string": {
+						Type:     cty.String,
+						Optional: true, // Just so we can progress to provider-driven validation and return the error there
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{},
+			}),
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got := (&Resource{Schema: test.Schema}).CoreConfigSchema()
+			if !cmp.Equal(got, test.Want, equateEmpty, typeComparer) {
+				t.Error(cmp.Diff(got, test.Want, equateEmpty, typeComparer))
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/data_source_resource_shim.go b/v1.5.7/internal/legacy/helper/schema/data_source_resource_shim.go
new file mode 100644
index 0000000..3a01c0f
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/data_source_resource_shim.go
@@ -0,0 +1,62 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"fmt"
+)
+
+// DataSourceResourceShim takes a Resource instance describing a data source
+// (with a Read implementation and a Schema, at least) and returns a new
+// Resource instance with additional Create and Delete implementations that
+// allow the data source to be used as a resource.
+//
+// This is a backward-compatibility layer for data sources that were formerly
+// read-only resources before the data source concept was added. It should not
+// be used for any *new* data sources.
+//
+// The Read function for the data source *must* call d.SetId with a non-empty
+// id in order for this shim to function as expected.
+//
+// The provided Resource instance, and its schema, will be modified in-place
+// to make it suitable for use as a full resource.
+func DataSourceResourceShim(name string, dataSource *Resource) *Resource {
+	// Recursively, in-place adjust the schema so that it has ForceNew
+	// on any user-settable resource.
+	dataSourceResourceShimAdjustSchema(dataSource.Schema)
+
+	dataSource.Create = CreateFunc(dataSource.Read)
+	dataSource.Delete = func(d *ResourceData, meta interface{}) error {
+		d.SetId("")
+		return nil
+	}
+	dataSource.Update = nil // should already be nil, but let's make sure
+
+	// FIXME: Link to some further docs either on the website or in the
+	// changelog, once such a thing exists.
+	dataSource.DeprecationMessage = fmt.Sprintf(
+		"using %s as a resource is deprecated; consider using the data source instead",
+		name,
+	)
+
+	return dataSource
+}
+
+func dataSourceResourceShimAdjustSchema(schema map[string]*Schema) {
+	for _, s := range schema {
+		// If the attribute is configurable then it must be ForceNew,
+		// since we have no Update implementation.
+		if s.Required || s.Optional {
+			s.ForceNew = true
+		}
+
+		// If the attribute is a nested resource, we need to recursively
+		// apply these same adjustments to it.
+		if s.Elem != nil {
+			if r, ok := s.Elem.(*Resource); ok {
+				dataSourceResourceShimAdjustSchema(r.Schema)
+			}
+		}
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/doc.go b/v1.5.7/internal/legacy/helper/schema/doc.go
new file mode 100644
index 0000000..230e30e
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/doc.go
@@ -0,0 +1,8 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package schema is a legacy package that used to represent the SDK, which is now its own
+// library external to Terraform Core https://github.com/hashicorp/terraform-plugin-sdk
+// Some of it is still used by Terraform's remote state backends, but this entire
+// package should be removed in the future.
+package schema
diff --git a/v1.5.7/internal/legacy/helper/schema/equal.go b/v1.5.7/internal/legacy/helper/schema/equal.go
new file mode 100644
index 0000000..92a02b3
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/equal.go
@@ -0,0 +1,9 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+// Equal is an interface that checks for deep equality between two objects.
+type Equal interface {
+	Equal(interface{}) bool
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/field_reader.go b/v1.5.7/internal/legacy/helper/schema/field_reader.go
new file mode 100644
index 0000000..cd72a61
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/field_reader.go
@@ -0,0 +1,346 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+// FieldReaders are responsible for decoding fields out of data into
+// the proper typed representation. ResourceData uses this to query data
+// out of multiple sources: config, state, diffs, etc.
+type FieldReader interface {
+	ReadField([]string) (FieldReadResult, error)
+}
+
+// FieldReadResult encapsulates all the resulting data from reading
+// a field.
+type FieldReadResult struct {
+	// Value is the actual read value. NegValue is the _negative_ value
+	// or the items that should be removed (if they existed). NegValue
+	// doesn't make sense for primitives but is important for any
+	// container types such as maps, sets, lists.
+	Value          interface{}
+	ValueProcessed interface{}
+
+	// Exists is true if the field was found in the data. False means
+	// it wasn't found if there was no error.
+	Exists bool
+
+	// Computed is true if the field was found but the value
+	// is computed.
+	Computed bool
+}
+
+// ValueOrZero returns the value of this result or the zero value of the
+// schema type, ensuring a consistent non-nil return value.
+func (r *FieldReadResult) ValueOrZero(s *Schema) interface{} {
+	if r.Value != nil {
+		return r.Value
+	}
+
+	return s.ZeroValue()
+}
+
+// SchemasForFlatmapPath tries its best to find a sequence of schemas that
+// the given dot-delimited attribute path traverses through.
+func SchemasForFlatmapPath(path string, schemaMap map[string]*Schema) []*Schema {
+	parts := strings.Split(path, ".")
+	return addrToSchema(parts, schemaMap)
+}
+
+// addrToSchema finds the final element schema for the given address
+// and the given schema. It returns all the schemas that led to the final
+// schema. These are in order of the address (out to in).
+func addrToSchema(addr []string, schemaMap map[string]*Schema) []*Schema {
+	current := &Schema{
+		Type: typeObject,
+		Elem: schemaMap,
+	}
+
+	// If we aren't given an address, then the user is requesting the
+	// full object, so we return the special value which is the full object.
+	if len(addr) == 0 {
+		return []*Schema{current}
+	}
+
+	result := make([]*Schema, 0, len(addr))
+	for len(addr) > 0 {
+		k := addr[0]
+		addr = addr[1:]
+
+	REPEAT:
+		// We want to trim off the first "typeObject" since its not a
+		// real lookup that people do. i.e. []string{"foo"} in a structure
+		// isn't {typeObject, typeString}, its just a {typeString}.
+		if len(result) > 0 || current.Type != typeObject {
+			result = append(result, current)
+		}
+
+		switch t := current.Type; t {
+		case TypeBool, TypeInt, TypeFloat, TypeString:
+			if len(addr) > 0 {
+				return nil
+			}
+		case TypeList, TypeSet:
+			isIndex := len(addr) > 0 && addr[0] == "#"
+
+			switch v := current.Elem.(type) {
+			case *Resource:
+				current = &Schema{
+					Type: typeObject,
+					Elem: v.Schema,
+				}
+			case *Schema:
+				current = v
+			case ValueType:
+				current = &Schema{Type: v}
+			default:
+				// we may not know the Elem type and are just looking for the
+				// index
+				if isIndex {
+					break
+				}
+
+				if len(addr) == 0 {
+					// we've processed the address, so return what we've
+					// collected
+					return result
+				}
+
+				if len(addr) == 1 {
+					if _, err := strconv.Atoi(addr[0]); err == nil {
+						// we're indexing a value without a schema. This can
+						// happen if the list is nested in another schema type.
+						// Default to a TypeString like we do with a map
+						current = &Schema{Type: TypeString}
+						break
+					}
+				}
+
+				return nil
+			}
+
+			// If we only have one more thing and the next thing
+			// is a #, then we're accessing the index which is always
+			// an int.
+			if isIndex {
+				current = &Schema{Type: TypeInt}
+				break
+			}
+
+		case TypeMap:
+			if len(addr) > 0 {
+				switch v := current.Elem.(type) {
+				case ValueType:
+					current = &Schema{Type: v}
+				case *Schema:
+					current, _ = current.Elem.(*Schema)
+				default:
+					// maps default to string values. This is all we can have
+					// if this is nested in another list or map.
+					current = &Schema{Type: TypeString}
+				}
+			}
+		case typeObject:
+			// If we're already in the object, then we want to handle Sets
+			// and Lists specially. Basically, their next key is the lookup
+			// key (the set value or the list element). For these scenarios,
+			// we just want to skip it and move to the next element if there
+			// is one.
+			if len(result) > 0 {
+				lastType := result[len(result)-2].Type
+				if lastType == TypeSet || lastType == TypeList {
+					if len(addr) == 0 {
+						break
+					}
+
+					k = addr[0]
+					addr = addr[1:]
+				}
+			}
+
+			m := current.Elem.(map[string]*Schema)
+			val, ok := m[k]
+			if !ok {
+				return nil
+			}
+
+			current = val
+			goto REPEAT
+		}
+	}
+
+	return result
+}
+
+// readListField is a generic method for reading a list field out of a
+// a FieldReader. It does this based on the assumption that there is a key
+// "foo.#" for a list "foo" and that the indexes are "foo.0", "foo.1", etc.
+// after that point.
+func readListField(
+	r FieldReader, addr []string, schema *Schema) (FieldReadResult, error) {
+	addrPadded := make([]string, len(addr)+1)
+	copy(addrPadded, addr)
+	addrPadded[len(addrPadded)-1] = "#"
+
+	// Get the number of elements in the list
+	countResult, err := r.ReadField(addrPadded)
+	if err != nil {
+		return FieldReadResult{}, err
+	}
+	if !countResult.Exists {
+		// No count, means we have no list
+		countResult.Value = 0
+	}
+
+	// If we have an empty list, then return an empty list
+	if countResult.Computed || countResult.Value.(int) == 0 {
+		return FieldReadResult{
+			Value:    []interface{}{},
+			Exists:   countResult.Exists,
+			Computed: countResult.Computed,
+		}, nil
+	}
+
+	// Go through each count, and get the item value out of it
+	result := make([]interface{}, countResult.Value.(int))
+	for i, _ := range result {
+		is := strconv.FormatInt(int64(i), 10)
+		addrPadded[len(addrPadded)-1] = is
+		rawResult, err := r.ReadField(addrPadded)
+		if err != nil {
+			return FieldReadResult{}, err
+		}
+		if !rawResult.Exists {
+			// This should never happen, because by the time the data
+			// gets to the FieldReaders, all the defaults should be set by
+			// Schema.
+			rawResult.Value = nil
+		}
+
+		result[i] = rawResult.Value
+	}
+
+	return FieldReadResult{
+		Value:  result,
+		Exists: true,
+	}, nil
+}
+
+// readObjectField is a generic method for reading objects out of FieldReaders
+// based on the assumption that building an address of []string{k, FIELD}
+// will result in the proper field data.
+func readObjectField(
+	r FieldReader,
+	addr []string,
+	schema map[string]*Schema) (FieldReadResult, error) {
+	result := make(map[string]interface{})
+	exists := false
+	for field, s := range schema {
+		addrRead := make([]string, len(addr), len(addr)+1)
+		copy(addrRead, addr)
+		addrRead = append(addrRead, field)
+		rawResult, err := r.ReadField(addrRead)
+		if err != nil {
+			return FieldReadResult{}, err
+		}
+		if rawResult.Exists {
+			exists = true
+		}
+
+		result[field] = rawResult.ValueOrZero(s)
+	}
+
+	return FieldReadResult{
+		Value:  result,
+		Exists: exists,
+	}, nil
+}
+
+// convert map values to the proper primitive type based on schema.Elem
+func mapValuesToPrimitive(k string, m map[string]interface{}, schema *Schema) error {
+	elemType, err := getValueType(k, schema)
+	if err != nil {
+		return err
+	}
+
+	switch elemType {
+	case TypeInt, TypeFloat, TypeBool:
+		for k, v := range m {
+			vs, ok := v.(string)
+			if !ok {
+				continue
+			}
+
+			v, err := stringToPrimitive(vs, false, &Schema{Type: elemType})
+			if err != nil {
+				return err
+			}
+
+			m[k] = v
+		}
+	}
+	return nil
+}
+
+func stringToPrimitive(
+	value string, computed bool, schema *Schema) (interface{}, error) {
+	var returnVal interface{}
+	switch schema.Type {
+	case TypeBool:
+		if value == "" {
+			returnVal = false
+			break
+		}
+		if computed {
+			break
+		}
+
+		v, err := strconv.ParseBool(value)
+		if err != nil {
+			return nil, err
+		}
+
+		returnVal = v
+	case TypeFloat:
+		if value == "" {
+			returnVal = 0.0
+			break
+		}
+		if computed {
+			break
+		}
+
+		v, err := strconv.ParseFloat(value, 64)
+		if err != nil {
+			return nil, err
+		}
+
+		returnVal = v
+	case TypeInt:
+		if value == "" {
+			returnVal = 0
+			break
+		}
+		if computed {
+			break
+		}
+
+		v, err := strconv.ParseInt(value, 0, 0)
+		if err != nil {
+			return nil, err
+		}
+
+		returnVal = int(v)
+	case TypeString:
+		returnVal = value
+	default:
+		panic(fmt.Sprintf("Unknown type: %s", schema.Type))
+	}
+
+	return returnVal, nil
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/field_reader_config.go b/v1.5.7/internal/legacy/helper/schema/field_reader_config.go
new file mode 100644
index 0000000..3ee0459
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/field_reader_config.go
@@ -0,0 +1,356 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"fmt"
+	"log"
+	"strconv"
+	"strings"
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+	"github.com/mitchellh/mapstructure"
+)
+
+// ConfigFieldReader reads fields out of an untyped map[string]string to the
+// best of its ability. It also applies defaults from the Schema. (The other
+// field readers do not need default handling because they source fully
+// populated data structures.)
+type ConfigFieldReader struct {
+	Config *terraform.ResourceConfig
+	Schema map[string]*Schema
+
+	indexMaps map[string]map[string]int
+	once      sync.Once
+}
+
+func (r *ConfigFieldReader) ReadField(address []string) (FieldReadResult, error) {
+	r.once.Do(func() { r.indexMaps = make(map[string]map[string]int) })
+	return r.readField(address, false)
+}
+
+func (r *ConfigFieldReader) readField(
+	address []string, nested bool) (FieldReadResult, error) {
+	schemaList := addrToSchema(address, r.Schema)
+	if len(schemaList) == 0 {
+		return FieldReadResult{}, nil
+	}
+
+	if !nested {
+		// If we have a set anywhere in the address, then we need to
+		// read that set out in order and actually replace that part of
+		// the address with the real list index. i.e. set.50 might actually
+		// map to set.12 in the config, since it is in list order in the
+		// config, not indexed by set value.
+		for i, v := range schemaList {
+			// Sets are the only thing that cause this issue.
+			if v.Type != TypeSet {
+				continue
+			}
+
+			// If we're at the end of the list, then we don't have to worry
+			// about this because we're just requesting the whole set.
+			if i == len(schemaList)-1 {
+				continue
+			}
+
+			// If we're looking for the count, then ignore...
+			if address[i+1] == "#" {
+				continue
+			}
+
+			indexMap, ok := r.indexMaps[strings.Join(address[:i+1], ".")]
+			if !ok {
+				// Get the set so we can get the index map that tells us the
+				// mapping of the hash code to the list index
+				_, err := r.readSet(address[:i+1], v)
+				if err != nil {
+					return FieldReadResult{}, err
+				}
+				indexMap = r.indexMaps[strings.Join(address[:i+1], ".")]
+			}
+
+			index, ok := indexMap[address[i+1]]
+			if !ok {
+				return FieldReadResult{}, nil
+			}
+
+			address[i+1] = strconv.FormatInt(int64(index), 10)
+		}
+	}
+
+	k := strings.Join(address, ".")
+	schema := schemaList[len(schemaList)-1]
+
+	// If we're getting the single element of a promoted list, then
+	// check to see if we have a single element we need to promote.
+	if address[len(address)-1] == "0" && len(schemaList) > 1 {
+		lastSchema := schemaList[len(schemaList)-2]
+		if lastSchema.Type == TypeList && lastSchema.PromoteSingle {
+			k := strings.Join(address[:len(address)-1], ".")
+			result, err := r.readPrimitive(k, schema)
+			if err == nil {
+				return result, nil
+			}
+		}
+	}
+
+	if protoVersion5 {
+		switch schema.Type {
+		case TypeList, TypeSet, TypeMap, typeObject:
+			// Check if the value itself is unknown.
+			// The new protocol shims will add unknown values to this list of
+			// ComputedKeys. This is the only way we have to indicate that a
+			// collection is unknown in the config
+			for _, unknown := range r.Config.ComputedKeys {
+				if k == unknown {
+					log.Printf("[DEBUG] setting computed for %q from ComputedKeys", k)
+					return FieldReadResult{Computed: true, Exists: true}, nil
+				}
+			}
+		}
+	}
+
+	switch schema.Type {
+	case TypeBool, TypeFloat, TypeInt, TypeString:
+		return r.readPrimitive(k, schema)
+	case TypeList:
+		// If we support promotion then we first check if we have a lone
+		// value that we must promote.
+		// a value that is alone.
+		if schema.PromoteSingle {
+			result, err := r.readPrimitive(k, schema.Elem.(*Schema))
+			if err == nil && result.Exists {
+				result.Value = []interface{}{result.Value}
+				return result, nil
+			}
+		}
+
+		return readListField(&nestedConfigFieldReader{r}, address, schema)
+	case TypeMap:
+		return r.readMap(k, schema)
+	case TypeSet:
+		return r.readSet(address, schema)
+	case typeObject:
+		return readObjectField(
+			&nestedConfigFieldReader{r},
+			address, schema.Elem.(map[string]*Schema))
+	default:
+		panic(fmt.Sprintf("Unknown type: %s", schema.Type))
+	}
+}
+
+func (r *ConfigFieldReader) readMap(k string, schema *Schema) (FieldReadResult, error) {
+	// We want both the raw value and the interpolated. We use the interpolated
+	// to store actual values and we use the raw one to check for
+	// computed keys. Actual values are obtained in the switch, depending on
+	// the type of the raw value.
+	mraw, ok := r.Config.GetRaw(k)
+	if !ok {
+		// check if this is from an interpolated field by seeing if it exists
+		// in the config
+		_, ok := r.Config.Get(k)
+		if !ok {
+			// this really doesn't exist
+			return FieldReadResult{}, nil
+		}
+
+		// We couldn't fetch the value from a nested data structure, so treat the
+		// raw value as an interpolation string. The mraw value is only used
+		// for the type switch below.
+		mraw = "${INTERPOLATED}"
+	}
+
+	result := make(map[string]interface{})
+	computed := false
+	switch m := mraw.(type) {
+	case string:
+		// This is a map which has come out of an interpolated variable, so we
+		// can just get the value directly from config. Values cannot be computed
+		// currently.
+		v, _ := r.Config.Get(k)
+
+		// If this isn't a map[string]interface, it must be computed.
+		mapV, ok := v.(map[string]interface{})
+		if !ok {
+			return FieldReadResult{
+				Exists:   true,
+				Computed: true,
+			}, nil
+		}
+
+		// Otherwise we can proceed as usual.
+		for i, iv := range mapV {
+			result[i] = iv
+		}
+	case []interface{}:
+		for i, innerRaw := range m {
+			for ik := range innerRaw.(map[string]interface{}) {
+				key := fmt.Sprintf("%s.%d.%s", k, i, ik)
+				if r.Config.IsComputed(key) {
+					computed = true
+					break
+				}
+
+				v, _ := r.Config.Get(key)
+				result[ik] = v
+			}
+		}
+	case []map[string]interface{}:
+		for i, innerRaw := range m {
+			for ik := range innerRaw {
+				key := fmt.Sprintf("%s.%d.%s", k, i, ik)
+				if r.Config.IsComputed(key) {
+					computed = true
+					break
+				}
+
+				v, _ := r.Config.Get(key)
+				result[ik] = v
+			}
+		}
+	case map[string]interface{}:
+		for ik := range m {
+			key := fmt.Sprintf("%s.%s", k, ik)
+			if r.Config.IsComputed(key) {
+				computed = true
+				break
+			}
+
+			v, _ := r.Config.Get(key)
+			result[ik] = v
+		}
+	case nil:
+		// the map may have been empty on the configuration, so we leave the
+		// empty result
+	default:
+		panic(fmt.Sprintf("unknown type: %#v", mraw))
+	}
+
+	err := mapValuesToPrimitive(k, result, schema)
+	if err != nil {
+		return FieldReadResult{}, nil
+	}
+
+	var value interface{}
+	if !computed {
+		value = result
+	}
+
+	return FieldReadResult{
+		Value:    value,
+		Exists:   true,
+		Computed: computed,
+	}, nil
+}
+
+func (r *ConfigFieldReader) readPrimitive(
+	k string, schema *Schema) (FieldReadResult, error) {
+	raw, ok := r.Config.Get(k)
+	if !ok {
+		// Nothing in config, but we might still have a default from the schema
+		var err error
+		raw, err = schema.DefaultValue()
+		if err != nil {
+			return FieldReadResult{}, fmt.Errorf("%s, error loading default: %s", k, err)
+		}
+
+		if raw == nil {
+			return FieldReadResult{}, nil
+		}
+	}
+
+	var result string
+	if err := mapstructure.WeakDecode(raw, &result); err != nil {
+		return FieldReadResult{}, err
+	}
+
+	computed := r.Config.IsComputed(k)
+	returnVal, err := stringToPrimitive(result, computed, schema)
+	if err != nil {
+		return FieldReadResult{}, err
+	}
+
+	return FieldReadResult{
+		Value:    returnVal,
+		Exists:   true,
+		Computed: computed,
+	}, nil
+}
+
+func (r *ConfigFieldReader) readSet(
+	address []string, schema *Schema) (FieldReadResult, error) {
+	indexMap := make(map[string]int)
+	// Create the set that will be our result
+	set := schema.ZeroValue().(*Set)
+
+	raw, err := readListField(&nestedConfigFieldReader{r}, address, schema)
+	if err != nil {
+		return FieldReadResult{}, err
+	}
+	if !raw.Exists {
+		return FieldReadResult{Value: set}, nil
+	}
+
+	// If the list is computed, the set is necessarilly computed
+	if raw.Computed {
+		return FieldReadResult{
+			Value:    set,
+			Exists:   true,
+			Computed: raw.Computed,
+		}, nil
+	}
+
+	// Build up the set from the list elements
+	for i, v := range raw.Value.([]interface{}) {
+		// Check if any of the keys in this item are computed
+		computed := r.hasComputedSubKeys(
+			fmt.Sprintf("%s.%d", strings.Join(address, "."), i), schema)
+
+		code := set.add(v, computed)
+		indexMap[code] = i
+	}
+
+	r.indexMaps[strings.Join(address, ".")] = indexMap
+
+	return FieldReadResult{
+		Value:  set,
+		Exists: true,
+	}, nil
+}
+
+// hasComputedSubKeys walks through a schema and returns whether or not the
+// given key contains any subkeys that are computed.
+func (r *ConfigFieldReader) hasComputedSubKeys(key string, schema *Schema) bool {
+	prefix := key + "."
+
+	switch t := schema.Elem.(type) {
+	case *Resource:
+		for k, schema := range t.Schema {
+			if r.Config.IsComputed(prefix + k) {
+				return true
+			}
+
+			if r.hasComputedSubKeys(prefix+k, schema) {
+				return true
+			}
+		}
+	}
+
+	return false
+}
+
+// nestedConfigFieldReader is a funny little thing that just wraps a
+// ConfigFieldReader to call readField when ReadField is called so that
+// we don't recalculate the set rewrites in the address, which leads to
+// an infinite loop.
+type nestedConfigFieldReader struct {
+	Reader *ConfigFieldReader
+}
+
+func (r *nestedConfigFieldReader) ReadField(
+	address []string) (FieldReadResult, error) {
+	return r.Reader.readField(address, true)
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/field_reader_config_test.go b/v1.5.7/internal/legacy/helper/schema/field_reader_config_test.go
new file mode 100644
index 0000000..387f453
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/field_reader_config_test.go
@@ -0,0 +1,543 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"bytes"
+	"fmt"
+	"reflect"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/legacy/helper/hashcode"
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+func TestConfigFieldReader_impl(t *testing.T) {
+	var _ FieldReader = new(ConfigFieldReader)
+}
+
+func TestConfigFieldReader(t *testing.T) {
+	testFieldReader(t, func(s map[string]*Schema) FieldReader {
+		return &ConfigFieldReader{
+			Schema: s,
+
+			Config: testConfig(t, map[string]interface{}{
+				"bool":   true,
+				"float":  3.1415,
+				"int":    42,
+				"string": "string",
+
+				"list": []interface{}{"foo", "bar"},
+
+				"listInt": []interface{}{21, 42},
+
+				"map": map[string]interface{}{
+					"foo": "bar",
+					"bar": "baz",
+				},
+				"mapInt": map[string]interface{}{
+					"one": "1",
+					"two": "2",
+				},
+				"mapIntNestedSchema": map[string]interface{}{
+					"one": "1",
+					"two": "2",
+				},
+				"mapFloat": map[string]interface{}{
+					"oneDotTwo": "1.2",
+				},
+				"mapBool": map[string]interface{}{
+					"True":  "true",
+					"False": "false",
+				},
+
+				"set": []interface{}{10, 50},
+				"setDeep": []interface{}{
+					map[string]interface{}{
+						"index": 10,
+						"value": "foo",
+					},
+					map[string]interface{}{
+						"index": 50,
+						"value": "bar",
+					},
+				},
+			}),
+		}
+	})
+}
+
+// This contains custom table tests for our ConfigFieldReader
+func TestConfigFieldReader_custom(t *testing.T) {
+	schema := map[string]*Schema{
+		"bool": &Schema{
+			Type: TypeBool,
+		},
+	}
+
+	cases := map[string]struct {
+		Addr   []string
+		Result FieldReadResult
+		Config *terraform.ResourceConfig
+		Err    bool
+	}{
+		"basic": {
+			[]string{"bool"},
+			FieldReadResult{
+				Value:  true,
+				Exists: true,
+			},
+			testConfig(t, map[string]interface{}{
+				"bool": true,
+			}),
+			false,
+		},
+
+		"computed": {
+			[]string{"bool"},
+			FieldReadResult{
+				Exists:   true,
+				Computed: true,
+			},
+			testConfig(t, map[string]interface{}{
+				"bool": hcl2shim.UnknownVariableValue,
+			}),
+			false,
+		},
+	}
+
+	for name, tc := range cases {
+		t.Run(name, func(t *testing.T) {
+			r := &ConfigFieldReader{
+				Schema: schema,
+				Config: tc.Config,
+			}
+			out, err := r.ReadField(tc.Addr)
+			if err != nil != tc.Err {
+				t.Fatalf("%s: err: %s", name, err)
+			}
+			if s, ok := out.Value.(*Set); ok {
+				// If it is a set, convert to a list so its more easily checked.
+				out.Value = s.List()
+			}
+			if !reflect.DeepEqual(tc.Result, out) {
+				t.Fatalf("%s: bad: %#v", name, out)
+			}
+		})
+	}
+}
+
+func TestConfigFieldReader_DefaultHandling(t *testing.T) {
+	schema := map[string]*Schema{
+		"strWithDefault": &Schema{
+			Type:    TypeString,
+			Default: "ImADefault",
+		},
+		"strWithDefaultFunc": &Schema{
+			Type: TypeString,
+			DefaultFunc: func() (interface{}, error) {
+				return "FuncDefault", nil
+			},
+		},
+	}
+
+	cases := map[string]struct {
+		Addr   []string
+		Result FieldReadResult
+		Config *terraform.ResourceConfig
+		Err    bool
+	}{
+		"gets default value when no config set": {
+			[]string{"strWithDefault"},
+			FieldReadResult{
+				Value:    "ImADefault",
+				Exists:   true,
+				Computed: false,
+			},
+			testConfig(t, map[string]interface{}{}),
+			false,
+		},
+		"config overrides default value": {
+			[]string{"strWithDefault"},
+			FieldReadResult{
+				Value:    "fromConfig",
+				Exists:   true,
+				Computed: false,
+			},
+			testConfig(t, map[string]interface{}{
+				"strWithDefault": "fromConfig",
+			}),
+			false,
+		},
+		"gets default from function when no config set": {
+			[]string{"strWithDefaultFunc"},
+			FieldReadResult{
+				Value:    "FuncDefault",
+				Exists:   true,
+				Computed: false,
+			},
+			testConfig(t, map[string]interface{}{}),
+			false,
+		},
+		"config overrides default function": {
+			[]string{"strWithDefaultFunc"},
+			FieldReadResult{
+				Value:    "fromConfig",
+				Exists:   true,
+				Computed: false,
+			},
+			testConfig(t, map[string]interface{}{
+				"strWithDefaultFunc": "fromConfig",
+			}),
+			false,
+		},
+	}
+
+	for name, tc := range cases {
+		r := &ConfigFieldReader{
+			Schema: schema,
+			Config: tc.Config,
+		}
+		out, err := r.ReadField(tc.Addr)
+		if err != nil != tc.Err {
+			t.Fatalf("%s: err: %s", name, err)
+		}
+		if s, ok := out.Value.(*Set); ok {
+			// If it is a set, convert to a list so its more easily checked.
+			out.Value = s.List()
+		}
+		if !reflect.DeepEqual(tc.Result, out) {
+			t.Fatalf("%s: bad: %#v", name, out)
+		}
+	}
+}
+
+func TestConfigFieldReader_ComputedMap(t *testing.T) {
+	schema := map[string]*Schema{
+		"map": &Schema{
+			Type:     TypeMap,
+			Computed: true,
+		},
+		"listmap": &Schema{
+			Type:     TypeMap,
+			Computed: true,
+			Elem:     TypeList,
+		},
+		"maplist": &Schema{
+			Type:     TypeList,
+			Computed: true,
+			Elem:     TypeMap,
+		},
+	}
+
+	cases := []struct {
+		Name   string
+		Addr   []string
+		Result FieldReadResult
+		Config *terraform.ResourceConfig
+		Err    bool
+	}{
+		{
+			"set, normal",
+			[]string{"map"},
+			FieldReadResult{
+				Value: map[string]interface{}{
+					"foo": "bar",
+				},
+				Exists:   true,
+				Computed: false,
+			},
+			testConfig(t, map[string]interface{}{
+				"map": map[string]interface{}{
+					"foo": "bar",
+				},
+			}),
+			false,
+		},
+
+		{
+			"computed element",
+			[]string{"map"},
+			FieldReadResult{
+				Exists:   true,
+				Computed: true,
+			},
+			testConfig(t, map[string]interface{}{
+				"map": map[string]interface{}{
+					"foo": hcl2shim.UnknownVariableValue,
+				},
+			}),
+			false,
+		},
+
+		{
+			"native map",
+			[]string{"map"},
+			FieldReadResult{
+				Value: map[string]interface{}{
+					"bar": "baz",
+					"baz": "bar",
+				},
+				Exists:   true,
+				Computed: false,
+			},
+			testConfig(t, map[string]interface{}{
+				"map": map[string]interface{}{
+					"bar": "baz",
+					"baz": "bar",
+				},
+			}),
+			false,
+		},
+
+		{
+			"map-from-list-of-maps",
+			[]string{"maplist", "0"},
+			FieldReadResult{
+				Value: map[string]interface{}{
+					"key": "bar",
+				},
+				Exists:   true,
+				Computed: false,
+			},
+			testConfig(t, map[string]interface{}{
+				"maplist": []interface{}{
+					map[string]interface{}{
+						"key": "bar",
+					},
+				},
+			}),
+			false,
+		},
+
+		{
+			"value-from-list-of-maps",
+			[]string{"maplist", "0", "key"},
+			FieldReadResult{
+				Value:    "bar",
+				Exists:   true,
+				Computed: false,
+			},
+			testConfig(t, map[string]interface{}{
+				"maplist": []interface{}{
+					map[string]interface{}{
+						"key": "bar",
+					},
+				},
+			}),
+			false,
+		},
+
+		{
+			"list-from-map-of-lists",
+			[]string{"listmap", "key"},
+			FieldReadResult{
+				Value:    []interface{}{"bar"},
+				Exists:   true,
+				Computed: false,
+			},
+			testConfig(t, map[string]interface{}{
+				"listmap": map[string]interface{}{
+					"key": []interface{}{
+						"bar",
+					},
+				},
+			}),
+			false,
+		},
+
+		{
+			"value-from-map-of-lists",
+			[]string{"listmap", "key", "0"},
+			FieldReadResult{
+				Value:    "bar",
+				Exists:   true,
+				Computed: false,
+			},
+			testConfig(t, map[string]interface{}{
+				"listmap": map[string]interface{}{
+					"key": []interface{}{
+						"bar",
+					},
+				},
+			}),
+			false,
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			r := &ConfigFieldReader{
+				Schema: schema,
+				Config: tc.Config,
+			}
+			out, err := r.ReadField(tc.Addr)
+			if err != nil != tc.Err {
+				t.Fatal(err)
+			}
+			if s, ok := out.Value.(*Set); ok {
+				// If it is a set, convert to the raw map
+				out.Value = s.m
+				if len(s.m) == 0 {
+					out.Value = nil
+				}
+			}
+			if !reflect.DeepEqual(tc.Result, out) {
+				t.Fatalf("\nexpected: %#v\ngot:      %#v", tc.Result, out)
+			}
+		})
+	}
+}
+
+func TestConfigFieldReader_ComputedSet(t *testing.T) {
+	schema := map[string]*Schema{
+		"strSet": &Schema{
+			Type: TypeSet,
+			Elem: &Schema{Type: TypeString},
+			Set:  HashString,
+		},
+	}
+
+	cases := map[string]struct {
+		Addr   []string
+		Result FieldReadResult
+		Config *terraform.ResourceConfig
+		Err    bool
+	}{
+		"set, normal": {
+			[]string{"strSet"},
+			FieldReadResult{
+				Value: map[string]interface{}{
+					"2356372769": "foo",
+				},
+				Exists:   true,
+				Computed: false,
+			},
+			testConfig(t, map[string]interface{}{
+				"strSet": []interface{}{"foo"},
+			}),
+			false,
+		},
+
+		"set, computed element": {
+			[]string{"strSet"},
+			FieldReadResult{
+				Value:    nil,
+				Exists:   true,
+				Computed: true,
+			},
+			testConfig(t, map[string]interface{}{
+				"strSet": []interface{}{hcl2shim.UnknownVariableValue},
+			}),
+			false,
+		},
+	}
+
+	for name, tc := range cases {
+		r := &ConfigFieldReader{
+			Schema: schema,
+			Config: tc.Config,
+		}
+		out, err := r.ReadField(tc.Addr)
+		if err != nil != tc.Err {
+			t.Fatalf("%s: err: %s", name, err)
+		}
+		if s, ok := out.Value.(*Set); ok {
+			// If it is a set, convert to the raw map
+			out.Value = s.m
+			if len(s.m) == 0 {
+				out.Value = nil
+			}
+		}
+		if !reflect.DeepEqual(tc.Result, out) {
+			t.Fatalf("%s: bad: %#v", name, out)
+		}
+	}
+}
+
+func TestConfigFieldReader_computedComplexSet(t *testing.T) {
+	hashfunc := func(v interface{}) int {
+		var buf bytes.Buffer
+		m := v.(map[string]interface{})
+		buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
+		buf.WriteString(fmt.Sprintf("%s-", m["vhd_uri"].(string)))
+		return hashcode.String(buf.String())
+	}
+
+	schema := map[string]*Schema{
+		"set": &Schema{
+			Type: TypeSet,
+			Elem: &Resource{
+				Schema: map[string]*Schema{
+					"name": {
+						Type:     TypeString,
+						Required: true,
+					},
+
+					"vhd_uri": {
+						Type:     TypeString,
+						Required: true,
+					},
+				},
+			},
+			Set: hashfunc,
+		},
+	}
+
+	cases := map[string]struct {
+		Addr   []string
+		Result FieldReadResult
+		Config *terraform.ResourceConfig
+		Err    bool
+	}{
+		"set, normal": {
+			[]string{"set"},
+			FieldReadResult{
+				Value: map[string]interface{}{
+					"532860136": map[string]interface{}{
+						"name":    "myosdisk1",
+						"vhd_uri": "bar",
+					},
+				},
+				Exists:   true,
+				Computed: false,
+			},
+			testConfig(t, map[string]interface{}{
+				"set": []interface{}{
+					map[string]interface{}{
+						"name":    "myosdisk1",
+						"vhd_uri": "bar",
+					},
+				},
+			}),
+			false,
+		},
+	}
+
+	for name, tc := range cases {
+		r := &ConfigFieldReader{
+			Schema: schema,
+			Config: tc.Config,
+		}
+		out, err := r.ReadField(tc.Addr)
+		if err != nil != tc.Err {
+			t.Fatalf("%s: err: %s", name, err)
+		}
+		if s, ok := out.Value.(*Set); ok {
+			// If it is a set, convert to the raw map
+			out.Value = s.m
+			if len(s.m) == 0 {
+				out.Value = nil
+			}
+		}
+		if !reflect.DeepEqual(tc.Result, out) {
+			t.Fatalf("%s: bad: %#v", name, out)
+		}
+	}
+}
+
+func testConfig(t *testing.T, raw map[string]interface{}) *terraform.ResourceConfig {
+	return terraform.NewResourceConfigRaw(raw)
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/field_reader_diff.go b/v1.5.7/internal/legacy/helper/schema/field_reader_diff.go
new file mode 100644
index 0000000..b3326b4
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/field_reader_diff.go
@@ -0,0 +1,247 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+	"github.com/mitchellh/mapstructure"
+)
+
+// DiffFieldReader reads fields out of a diff structures.
+//
+// It also requires access to a Reader that reads fields from the structure
+// that the diff was derived from. This is usually the state. This is required
+// because a diff on its own doesn't have complete data about full objects
+// such as maps.
+//
+// The Source MUST be the data that the diff was derived from. If it isn't,
+// the behavior of this struct is undefined.
+//
+// Reading fields from a DiffFieldReader is identical to reading from
+// Source except the diff will be applied to the end result.
+//
+// The "Exists" field on the result will be set to true if the complete
+// field exists whether its from the source, diff, or a combination of both.
+// It cannot be determined whether a retrieved value is composed of
+// diff elements.
+type DiffFieldReader struct {
+	Diff   *terraform.InstanceDiff
+	Source FieldReader
+	Schema map[string]*Schema
+
+	// cache for memoizing ReadField calls.
+	cache map[string]cachedFieldReadResult
+}
+
+type cachedFieldReadResult struct {
+	val FieldReadResult
+	err error
+}
+
+func (r *DiffFieldReader) ReadField(address []string) (FieldReadResult, error) {
+	if r.cache == nil {
+		r.cache = make(map[string]cachedFieldReadResult)
+	}
+
+	// Create the cache key by joining around a value that isn't a valid part
+	// of an address. This assumes that the Source and Schema are not changed
+	// for the life of this DiffFieldReader.
+	cacheKey := strings.Join(address, "|")
+	if cached, ok := r.cache[cacheKey]; ok {
+		return cached.val, cached.err
+	}
+
+	schemaList := addrToSchema(address, r.Schema)
+	if len(schemaList) == 0 {
+		r.cache[cacheKey] = cachedFieldReadResult{}
+		return FieldReadResult{}, nil
+	}
+
+	var res FieldReadResult
+	var err error
+
+	schema := schemaList[len(schemaList)-1]
+	switch schema.Type {
+	case TypeBool, TypeInt, TypeFloat, TypeString:
+		res, err = r.readPrimitive(address, schema)
+	case TypeList:
+		res, err = readListField(r, address, schema)
+	case TypeMap:
+		res, err = r.readMap(address, schema)
+	case TypeSet:
+		res, err = r.readSet(address, schema)
+	case typeObject:
+		res, err = readObjectField(r, address, schema.Elem.(map[string]*Schema))
+	default:
+		panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
+	}
+
+	r.cache[cacheKey] = cachedFieldReadResult{
+		val: res,
+		err: err,
+	}
+	return res, err
+}
+
+func (r *DiffFieldReader) readMap(
+	address []string, schema *Schema) (FieldReadResult, error) {
+	result := make(map[string]interface{})
+	resultSet := false
+
+	// First read the map from the underlying source
+	source, err := r.Source.ReadField(address)
+	if err != nil {
+		return FieldReadResult{}, err
+	}
+	if source.Exists {
+		// readMap may return a nil value, or an unknown value placeholder in
+		// some cases, causing the type assertion to panic if we don't assign the ok value
+		result, _ = source.Value.(map[string]interface{})
+		resultSet = true
+	}
+
+	// Next, read all the elements we have in our diff, and apply
+	// the diff to our result.
+	prefix := strings.Join(address, ".") + "."
+	for k, v := range r.Diff.Attributes {
+		if !strings.HasPrefix(k, prefix) {
+			continue
+		}
+		if strings.HasPrefix(k, prefix+"%") {
+			// Ignore the count field
+			continue
+		}
+
+		resultSet = true
+
+		k = k[len(prefix):]
+		if v.NewRemoved {
+			delete(result, k)
+			continue
+		}
+
+		result[k] = v.New
+	}
+
+	key := address[len(address)-1]
+	err = mapValuesToPrimitive(key, result, schema)
+	if err != nil {
+		return FieldReadResult{}, nil
+	}
+
+	var resultVal interface{}
+	if resultSet {
+		resultVal = result
+	}
+
+	return FieldReadResult{
+		Value:  resultVal,
+		Exists: resultSet,
+	}, nil
+}
+
+func (r *DiffFieldReader) readPrimitive(
+	address []string, schema *Schema) (FieldReadResult, error) {
+	result, err := r.Source.ReadField(address)
+	if err != nil {
+		return FieldReadResult{}, err
+	}
+
+	attrD, ok := r.Diff.Attributes[strings.Join(address, ".")]
+	if !ok {
+		return result, nil
+	}
+
+	var resultVal string
+	if !attrD.NewComputed {
+		resultVal = attrD.New
+		if attrD.NewExtra != nil {
+			result.ValueProcessed = resultVal
+			if err := mapstructure.WeakDecode(attrD.NewExtra, &resultVal); err != nil {
+				return FieldReadResult{}, err
+			}
+		}
+	}
+
+	result.Computed = attrD.NewComputed
+	result.Exists = true
+	result.Value, err = stringToPrimitive(resultVal, false, schema)
+	if err != nil {
+		return FieldReadResult{}, err
+	}
+
+	return result, nil
+}
+
+func (r *DiffFieldReader) readSet(
+	address []string, schema *Schema) (FieldReadResult, error) {
+	// copy address to ensure we don't modify the argument
+	address = append([]string(nil), address...)
+
+	prefix := strings.Join(address, ".") + "."
+
+	// Create the set that will be our result
+	set := schema.ZeroValue().(*Set)
+
+	// Go through the map and find all the set items
+	for k, d := range r.Diff.Attributes {
+		if d.NewRemoved {
+			// If the field is removed, we always ignore it
+			continue
+		}
+		if !strings.HasPrefix(k, prefix) {
+			continue
+		}
+		if strings.HasSuffix(k, "#") {
+			// Ignore any count field
+			continue
+		}
+
+		// Split the key, since it might be a sub-object like "idx.field"
+		parts := strings.Split(k[len(prefix):], ".")
+		idx := parts[0]
+
+		raw, err := r.ReadField(append(address, idx))
+		if err != nil {
+			return FieldReadResult{}, err
+		}
+		if !raw.Exists {
+			// This shouldn't happen because we just verified it does exist
+			panic("missing field in set: " + k + "." + idx)
+		}
+
+		set.Add(raw.Value)
+	}
+
+	// Determine if the set "exists". It exists if there are items or if
+	// the diff explicitly wanted it empty.
+	exists := set.Len() > 0
+	if !exists {
+		// We could check if the diff value is "0" here but I think the
+		// existence of "#" on its own is enough to show it existed. This
+		// protects us in the future from the zero value changing from
+		// "0" to "" breaking us (if that were to happen).
+		if _, ok := r.Diff.Attributes[prefix+"#"]; ok {
+			exists = true
+		}
+	}
+
+	if !exists {
+		result, err := r.Source.ReadField(address)
+		if err != nil {
+			return FieldReadResult{}, err
+		}
+		if result.Exists {
+			return result, nil
+		}
+	}
+
+	return FieldReadResult{
+		Value:  set,
+		Exists: exists,
+	}, nil
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/field_reader_diff_test.go b/v1.5.7/internal/legacy/helper/schema/field_reader_diff_test.go
new file mode 100644
index 0000000..121cf8e
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/field_reader_diff_test.go
@@ -0,0 +1,527 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+func TestDiffFieldReader_impl(t *testing.T) {
+	var _ FieldReader = new(DiffFieldReader)
+}
+
+func TestDiffFieldReader_NestedSetUpdate(t *testing.T) {
+	hashFn := func(a interface{}) int {
+		m := a.(map[string]interface{})
+		return m["val"].(int)
+	}
+
+	schema := map[string]*Schema{
+		"list_of_sets_1": &Schema{
+			Type: TypeList,
+			Elem: &Resource{
+				Schema: map[string]*Schema{
+					"nested_set": &Schema{
+						Type: TypeSet,
+						Elem: &Resource{
+							Schema: map[string]*Schema{
+								"val": &Schema{
+									Type: TypeInt,
+								},
+							},
+						},
+						Set: hashFn,
+					},
+				},
+			},
+		},
+		"list_of_sets_2": &Schema{
+			Type: TypeList,
+			Elem: &Resource{
+				Schema: map[string]*Schema{
+					"nested_set": &Schema{
+						Type: TypeSet,
+						Elem: &Resource{
+							Schema: map[string]*Schema{
+								"val": &Schema{
+									Type: TypeInt,
+								},
+							},
+						},
+						Set: hashFn,
+					},
+				},
+			},
+		},
+	}
+
+	r := &DiffFieldReader{
+		Schema: schema,
+		Diff: &terraform.InstanceDiff{
+			Attributes: map[string]*terraform.ResourceAttrDiff{
+				"list_of_sets_1.0.nested_set.1.val": &terraform.ResourceAttrDiff{
+					Old:        "1",
+					New:        "0",
+					NewRemoved: true,
+				},
+				"list_of_sets_1.0.nested_set.2.val": &terraform.ResourceAttrDiff{
+					New: "2",
+				},
+			},
+		},
+	}
+
+	r.Source = &MultiLevelFieldReader{
+		Readers: map[string]FieldReader{
+			"diff": r,
+			"set":  &MapFieldReader{Schema: schema},
+			"state": &MapFieldReader{
+				Map: &BasicMapReader{
+					"list_of_sets_1.#":                  "1",
+					"list_of_sets_1.0.nested_set.#":     "1",
+					"list_of_sets_1.0.nested_set.1.val": "1",
+					"list_of_sets_2.#":                  "1",
+					"list_of_sets_2.0.nested_set.#":     "1",
+					"list_of_sets_2.0.nested_set.1.val": "1",
+				},
+				Schema: schema,
+			},
+		},
+		Levels: []string{"state", "config"},
+	}
+
+	out, err := r.ReadField([]string{"list_of_sets_2"})
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	s := &Set{F: hashFn}
+	s.Add(map[string]interface{}{"val": 1})
+	expected := s.List()
+
+	l := out.Value.([]interface{})
+	i := l[0].(map[string]interface{})
+	actual := i["nested_set"].(*Set).List()
+
+	if !reflect.DeepEqual(expected, actual) {
+		t.Fatalf("bad: NestedSetUpdate\n\nexpected: %#v\n\ngot: %#v\n\n", expected, actual)
+	}
+}
+
+// https://github.com/hashicorp/terraform/issues/914
+func TestDiffFieldReader_MapHandling(t *testing.T) {
+	schema := map[string]*Schema{
+		"tags": &Schema{
+			Type: TypeMap,
+		},
+	}
+	r := &DiffFieldReader{
+		Schema: schema,
+		Diff: &terraform.InstanceDiff{
+			Attributes: map[string]*terraform.ResourceAttrDiff{
+				"tags.%": &terraform.ResourceAttrDiff{
+					Old: "1",
+					New: "2",
+				},
+				"tags.baz": &terraform.ResourceAttrDiff{
+					Old: "",
+					New: "qux",
+				},
+			},
+		},
+		Source: &MapFieldReader{
+			Schema: schema,
+			Map: BasicMapReader(map[string]string{
+				"tags.%":   "1",
+				"tags.foo": "bar",
+			}),
+		},
+	}
+
+	result, err := r.ReadField([]string{"tags"})
+	if err != nil {
+		t.Fatalf("ReadField failed: %#v", err)
+	}
+
+	expected := map[string]interface{}{
+		"foo": "bar",
+		"baz": "qux",
+	}
+
+	if !reflect.DeepEqual(expected, result.Value) {
+		t.Fatalf("bad: DiffHandling\n\nexpected: %#v\n\ngot: %#v\n\n", expected, result.Value)
+	}
+}
+
+func TestDiffFieldReader_extra(t *testing.T) {
+	schema := map[string]*Schema{
+		"stringComputed": &Schema{Type: TypeString},
+
+		"listMap": &Schema{
+			Type: TypeList,
+			Elem: &Schema{
+				Type: TypeMap,
+			},
+		},
+
+		"mapRemove": &Schema{Type: TypeMap},
+
+		"setChange": &Schema{
+			Type:     TypeSet,
+			Optional: true,
+			Elem: &Resource{
+				Schema: map[string]*Schema{
+					"index": &Schema{
+						Type:     TypeInt,
+						Required: true,
+					},
+
+					"value": &Schema{
+						Type:     TypeString,
+						Required: true,
+					},
+				},
+			},
+			Set: func(a interface{}) int {
+				m := a.(map[string]interface{})
+				return m["index"].(int)
+			},
+		},
+
+		"setEmpty": &Schema{
+			Type:     TypeSet,
+			Optional: true,
+			Elem: &Resource{
+				Schema: map[string]*Schema{
+					"index": &Schema{
+						Type:     TypeInt,
+						Required: true,
+					},
+
+					"value": &Schema{
+						Type:     TypeString,
+						Required: true,
+					},
+				},
+			},
+			Set: func(a interface{}) int {
+				m := a.(map[string]interface{})
+				return m["index"].(int)
+			},
+		},
+	}
+
+	r := &DiffFieldReader{
+		Schema: schema,
+		Diff: &terraform.InstanceDiff{
+			Attributes: map[string]*terraform.ResourceAttrDiff{
+				"stringComputed": &terraform.ResourceAttrDiff{
+					Old:         "foo",
+					New:         "bar",
+					NewComputed: true,
+				},
+
+				"listMap.0.bar": &terraform.ResourceAttrDiff{
+					NewRemoved: true,
+				},
+
+				"mapRemove.bar": &terraform.ResourceAttrDiff{
+					NewRemoved: true,
+				},
+
+				"setChange.10.value": &terraform.ResourceAttrDiff{
+					Old: "50",
+					New: "80",
+				},
+
+				"setEmpty.#": &terraform.ResourceAttrDiff{
+					Old: "2",
+					New: "0",
+				},
+			},
+		},
+
+		Source: &MapFieldReader{
+			Schema: schema,
+			Map: BasicMapReader(map[string]string{
+				"listMap.#":     "2",
+				"listMap.0.foo": "bar",
+				"listMap.0.bar": "baz",
+				"listMap.1.baz": "baz",
+
+				"mapRemove.foo": "bar",
+				"mapRemove.bar": "bar",
+
+				"setChange.#":        "1",
+				"setChange.10.index": "10",
+				"setChange.10.value": "50",
+
+				"setEmpty.#":        "2",
+				"setEmpty.10.index": "10",
+				"setEmpty.10.value": "50",
+				"setEmpty.20.index": "20",
+				"setEmpty.20.value": "50",
+			}),
+		},
+	}
+
+	cases := map[string]struct {
+		Addr   []string
+		Result FieldReadResult
+		Err    bool
+	}{
+		"stringComputed": {
+			[]string{"stringComputed"},
+			FieldReadResult{
+				Value:    "",
+				Exists:   true,
+				Computed: true,
+			},
+			false,
+		},
+
+		"listMapRemoval": {
+			[]string{"listMap"},
+			FieldReadResult{
+				Value: []interface{}{
+					map[string]interface{}{
+						"foo": "bar",
+					},
+					map[string]interface{}{
+						"baz": "baz",
+					},
+				},
+				Exists: true,
+			},
+			false,
+		},
+
+		"mapRemove": {
+			[]string{"mapRemove"},
+			FieldReadResult{
+				Value: map[string]interface{}{
+					"foo": "bar",
+				},
+				Exists:   true,
+				Computed: false,
+			},
+			false,
+		},
+
+		"setChange": {
+			[]string{"setChange"},
+			FieldReadResult{
+				Value: []interface{}{
+					map[string]interface{}{
+						"index": 10,
+						"value": "80",
+					},
+				},
+				Exists: true,
+			},
+			false,
+		},
+
+		"setEmpty": {
+			[]string{"setEmpty"},
+			FieldReadResult{
+				Value:  []interface{}{},
+				Exists: true,
+			},
+			false,
+		},
+	}
+
+	for name, tc := range cases {
+		out, err := r.ReadField(tc.Addr)
+		if err != nil != tc.Err {
+			t.Fatalf("%s: err: %s", name, err)
+		}
+		if s, ok := out.Value.(*Set); ok {
+			// If it is a set, convert to a list so its more easily checked.
+			out.Value = s.List()
+		}
+		if !reflect.DeepEqual(tc.Result, out) {
+			t.Fatalf("%s: bad: %#v", name, out)
+		}
+	}
+}
+
+func TestDiffFieldReader(t *testing.T) {
+	testFieldReader(t, func(s map[string]*Schema) FieldReader {
+		return &DiffFieldReader{
+			Schema: s,
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"bool": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "true",
+					},
+
+					"int": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "42",
+					},
+
+					"float": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "3.1415",
+					},
+
+					"string": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "string",
+					},
+
+					"stringComputed": &terraform.ResourceAttrDiff{
+						Old:         "foo",
+						New:         "bar",
+						NewComputed: true,
+					},
+
+					"list.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "2",
+					},
+
+					"list.0": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+
+					"list.1": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "bar",
+					},
+
+					"listInt.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "2",
+					},
+
+					"listInt.0": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "21",
+					},
+
+					"listInt.1": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "42",
+					},
+
+					"map.foo": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "bar",
+					},
+
+					"map.bar": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "baz",
+					},
+
+					"mapInt.%": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "2",
+					},
+					"mapInt.one": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"mapInt.two": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "2",
+					},
+
+					"mapIntNestedSchema.%": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "2",
+					},
+					"mapIntNestedSchema.one": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"mapIntNestedSchema.two": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "2",
+					},
+
+					"mapFloat.%": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"mapFloat.oneDotTwo": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1.2",
+					},
+
+					"mapBool.%": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "2",
+					},
+					"mapBool.True": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "true",
+					},
+					"mapBool.False": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "false",
+					},
+
+					"set.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "2",
+					},
+
+					"set.10": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "10",
+					},
+
+					"set.50": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "50",
+					},
+
+					"setDeep.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "2",
+					},
+
+					"setDeep.10.index": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "10",
+					},
+
+					"setDeep.10.value": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+
+					"setDeep.50.index": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "50",
+					},
+
+					"setDeep.50.value": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "bar",
+					},
+				},
+			},
+
+			Source: &MapFieldReader{
+				Schema: s,
+				Map: BasicMapReader(map[string]string{
+					"listMap.#":     "2",
+					"listMap.0.foo": "bar",
+					"listMap.0.bar": "baz",
+					"listMap.1.baz": "baz",
+				}),
+			},
+		}
+	})
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/field_reader_map.go b/v1.5.7/internal/legacy/helper/schema/field_reader_map.go
new file mode 100644
index 0000000..0a96a24
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/field_reader_map.go
@@ -0,0 +1,238 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"fmt"
+	"strings"
+)
+
+// MapFieldReader reads fields out of an untyped map[string]string to
+// the best of its ability.
+type MapFieldReader struct {
+	Map    MapReader
+	Schema map[string]*Schema
+}
+
+func (r *MapFieldReader) ReadField(address []string) (FieldReadResult, error) {
+	k := strings.Join(address, ".")
+	schemaList := addrToSchema(address, r.Schema)
+	if len(schemaList) == 0 {
+		return FieldReadResult{}, nil
+	}
+
+	schema := schemaList[len(schemaList)-1]
+	switch schema.Type {
+	case TypeBool, TypeInt, TypeFloat, TypeString:
+		return r.readPrimitive(address, schema)
+	case TypeList:
+		return readListField(r, address, schema)
+	case TypeMap:
+		return r.readMap(k, schema)
+	case TypeSet:
+		return r.readSet(address, schema)
+	case typeObject:
+		return readObjectField(r, address, schema.Elem.(map[string]*Schema))
+	default:
+		panic(fmt.Sprintf("Unknown type: %s", schema.Type))
+	}
+}
+
+func (r *MapFieldReader) readMap(k string, schema *Schema) (FieldReadResult, error) {
+	result := make(map[string]interface{})
+	resultSet := false
+
+	// If the name of the map field is directly in the map with an
+	// empty string, it means that the map is being deleted, so mark
+	// that is is set.
+	if v, ok := r.Map.Access(k); ok && v == "" {
+		resultSet = true
+	}
+
+	prefix := k + "."
+	r.Map.Range(func(k, v string) bool {
+		if strings.HasPrefix(k, prefix) {
+			resultSet = true
+
+			key := k[len(prefix):]
+			if key != "%" && key != "#" {
+				result[key] = v
+			}
+		}
+
+		return true
+	})
+
+	err := mapValuesToPrimitive(k, result, schema)
+	if err != nil {
+		return FieldReadResult{}, nil
+	}
+
+	var resultVal interface{}
+	if resultSet {
+		resultVal = result
+	}
+
+	return FieldReadResult{
+		Value:  resultVal,
+		Exists: resultSet,
+	}, nil
+}
+
+func (r *MapFieldReader) readPrimitive(
+	address []string, schema *Schema) (FieldReadResult, error) {
+	k := strings.Join(address, ".")
+	result, ok := r.Map.Access(k)
+	if !ok {
+		return FieldReadResult{}, nil
+	}
+
+	returnVal, err := stringToPrimitive(result, false, schema)
+	if err != nil {
+		return FieldReadResult{}, err
+	}
+
+	return FieldReadResult{
+		Value:  returnVal,
+		Exists: true,
+	}, nil
+}
+
+func (r *MapFieldReader) readSet(
+	address []string, schema *Schema) (FieldReadResult, error) {
+	// copy address to ensure we don't modify the argument
+	address = append([]string(nil), address...)
+
+	// Get the number of elements in the list
+	countRaw, err := r.readPrimitive(
+		append(address, "#"), &Schema{Type: TypeInt})
+	if err != nil {
+		return FieldReadResult{}, err
+	}
+	if !countRaw.Exists {
+		// No count, means we have no list
+		countRaw.Value = 0
+	}
+
+	// Create the set that will be our result
+	set := schema.ZeroValue().(*Set)
+
+	// If we have an empty list, then return an empty list
+	if countRaw.Computed || countRaw.Value.(int) == 0 {
+		return FieldReadResult{
+			Value:    set,
+			Exists:   countRaw.Exists,
+			Computed: countRaw.Computed,
+		}, nil
+	}
+
+	// Go through the map and find all the set items
+	prefix := strings.Join(address, ".") + "."
+	countExpected := countRaw.Value.(int)
+	countActual := make(map[string]struct{})
+	completed := r.Map.Range(func(k, _ string) bool {
+		if !strings.HasPrefix(k, prefix) {
+			return true
+		}
+		if strings.HasPrefix(k, prefix+"#") {
+			// Ignore the count field
+			return true
+		}
+
+		// Split the key, since it might be a sub-object like "idx.field"
+		parts := strings.Split(k[len(prefix):], ".")
+		idx := parts[0]
+
+		var raw FieldReadResult
+		raw, err = r.ReadField(append(address, idx))
+		if err != nil {
+			return false
+		}
+		if !raw.Exists {
+			// This shouldn't happen because we just verified it does exist
+			panic("missing field in set: " + k + "." + idx)
+		}
+
+		set.Add(raw.Value)
+
+		// Due to the way multimap readers work, if we've seen the number
+		// of fields we expect, then exit so that we don't read later values.
+		// For example: the "set" map might have "ports.#", "ports.0", and
+		// "ports.1", but the "state" map might have those plus "ports.2".
+		// We don't want "ports.2"
+		countActual[idx] = struct{}{}
+		if len(countActual) >= countExpected {
+			return false
+		}
+
+		return true
+	})
+	if !completed && err != nil {
+		return FieldReadResult{}, err
+	}
+
+	return FieldReadResult{
+		Value:  set,
+		Exists: true,
+	}, nil
+}
+
+// MapReader is an interface that is given to MapFieldReader for accessing
+// a "map". This can be used to have alternate implementations. For a basic
+// map[string]string, use BasicMapReader.
+type MapReader interface {
+	Access(string) (string, bool)
+	Range(func(string, string) bool) bool
+}
+
+// BasicMapReader implements MapReader for a single map.
+type BasicMapReader map[string]string
+
+func (r BasicMapReader) Access(k string) (string, bool) {
+	v, ok := r[k]
+	return v, ok
+}
+
+func (r BasicMapReader) Range(f func(string, string) bool) bool {
+	for k, v := range r {
+		if cont := f(k, v); !cont {
+			return false
+		}
+	}
+
+	return true
+}
+
+// MultiMapReader reads over multiple maps, preferring keys that are
+// founder earlier (lower number index) vs. later (higher number index)
+type MultiMapReader []map[string]string
+
+func (r MultiMapReader) Access(k string) (string, bool) {
+	for _, m := range r {
+		if v, ok := m[k]; ok {
+			return v, ok
+		}
+	}
+
+	return "", false
+}
+
+func (r MultiMapReader) Range(f func(string, string) bool) bool {
+	done := make(map[string]struct{})
+	for _, m := range r {
+		for k, v := range m {
+			if _, ok := done[k]; ok {
+				continue
+			}
+
+			if cont := f(k, v); !cont {
+				return false
+			}
+
+			done[k] = struct{}{}
+		}
+	}
+
+	return true
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/field_reader_map_test.go b/v1.5.7/internal/legacy/helper/schema/field_reader_map_test.go
new file mode 100644
index 0000000..f3df889
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/field_reader_map_test.go
@@ -0,0 +1,126 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestMapFieldReader_impl(t *testing.T) {
+	var _ FieldReader = new(MapFieldReader)
+}
+
+func TestMapFieldReader(t *testing.T) {
+	testFieldReader(t, func(s map[string]*Schema) FieldReader {
+		return &MapFieldReader{
+			Schema: s,
+
+			Map: BasicMapReader(map[string]string{
+				"bool":   "true",
+				"int":    "42",
+				"float":  "3.1415",
+				"string": "string",
+
+				"list.#": "2",
+				"list.0": "foo",
+				"list.1": "bar",
+
+				"listInt.#": "2",
+				"listInt.0": "21",
+				"listInt.1": "42",
+
+				"map.%":   "2",
+				"map.foo": "bar",
+				"map.bar": "baz",
+
+				"set.#":  "2",
+				"set.10": "10",
+				"set.50": "50",
+
+				"setDeep.#":        "2",
+				"setDeep.10.index": "10",
+				"setDeep.10.value": "foo",
+				"setDeep.50.index": "50",
+				"setDeep.50.value": "bar",
+
+				"mapInt.%":   "2",
+				"mapInt.one": "1",
+				"mapInt.two": "2",
+
+				"mapIntNestedSchema.%":   "2",
+				"mapIntNestedSchema.one": "1",
+				"mapIntNestedSchema.two": "2",
+
+				"mapFloat.%":         "1",
+				"mapFloat.oneDotTwo": "1.2",
+
+				"mapBool.%":     "2",
+				"mapBool.True":  "true",
+				"mapBool.False": "false",
+			}),
+		}
+	})
+}
+
+func TestMapFieldReader_extra(t *testing.T) {
+	r := &MapFieldReader{
+		Schema: map[string]*Schema{
+			"mapDel":   &Schema{Type: TypeMap},
+			"mapEmpty": &Schema{Type: TypeMap},
+		},
+
+		Map: BasicMapReader(map[string]string{
+			"mapDel": "",
+
+			"mapEmpty.%": "0",
+		}),
+	}
+
+	cases := map[string]struct {
+		Addr        []string
+		Out         interface{}
+		OutOk       bool
+		OutComputed bool
+		OutErr      bool
+	}{
+		"mapDel": {
+			[]string{"mapDel"},
+			map[string]interface{}{},
+			true,
+			false,
+			false,
+		},
+
+		"mapEmpty": {
+			[]string{"mapEmpty"},
+			map[string]interface{}{},
+			true,
+			false,
+			false,
+		},
+	}
+
+	for name, tc := range cases {
+		out, err := r.ReadField(tc.Addr)
+		if err != nil != tc.OutErr {
+			t.Fatalf("%s: err: %s", name, err)
+		}
+		if out.Computed != tc.OutComputed {
+			t.Fatalf("%s: err: %#v", name, out.Computed)
+		}
+
+		if s, ok := out.Value.(*Set); ok {
+			// If it is a set, convert to a list so its more easily checked.
+			out.Value = s.List()
+		}
+
+		if !reflect.DeepEqual(out.Value, tc.Out) {
+			t.Fatalf("%s: out: %#v", name, out.Value)
+		}
+		if out.Exists != tc.OutOk {
+			t.Fatalf("%s: outOk: %#v", name, out.Exists)
+		}
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/field_reader_multi.go b/v1.5.7/internal/legacy/helper/schema/field_reader_multi.go
new file mode 100644
index 0000000..da4c9c8
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/field_reader_multi.go
@@ -0,0 +1,66 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"fmt"
+)
+
+// MultiLevelFieldReader reads from other field readers,
+// merging their results along the way in a specific order. You can specify
+// "levels" and name them in order to read only an exact level or up to
+// a specific level.
+//
+// This is useful for saying things such as "read the field from the state
+// and config and merge them" or "read the latest value of the field".
+type MultiLevelFieldReader struct {
+	Readers map[string]FieldReader
+	Levels  []string
+}
+
+func (r *MultiLevelFieldReader) ReadField(address []string) (FieldReadResult, error) {
+	return r.ReadFieldMerge(address, r.Levels[len(r.Levels)-1])
+}
+
+func (r *MultiLevelFieldReader) ReadFieldExact(
+	address []string, level string) (FieldReadResult, error) {
+	reader, ok := r.Readers[level]
+	if !ok {
+		return FieldReadResult{}, fmt.Errorf(
+			"Unknown reader level: %s", level)
+	}
+
+	result, err := reader.ReadField(address)
+	if err != nil {
+		return FieldReadResult{}, fmt.Errorf(
+			"Error reading level %s: %s", level, err)
+	}
+
+	return result, nil
+}
+
+func (r *MultiLevelFieldReader) ReadFieldMerge(
+	address []string, level string) (FieldReadResult, error) {
+	var result FieldReadResult
+	for _, l := range r.Levels {
+		if r, ok := r.Readers[l]; ok {
+			out, err := r.ReadField(address)
+			if err != nil {
+				return FieldReadResult{}, fmt.Errorf(
+					"Error reading level %s: %s", l, err)
+			}
+
+			// TODO: computed
+			if out.Exists {
+				result = out
+			}
+		}
+
+		if l == level {
+			break
+		}
+	}
+
+	return result, nil
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/field_reader_multi_test.go b/v1.5.7/internal/legacy/helper/schema/field_reader_multi_test.go
new file mode 100644
index 0000000..c4f4639
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/field_reader_multi_test.go
@@ -0,0 +1,273 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"reflect"
+	"strconv"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+func TestMultiLevelFieldReaderReadFieldExact(t *testing.T) {
+	cases := map[string]struct {
+		Addr    []string
+		Readers []FieldReader
+		Level   string
+		Result  FieldReadResult
+	}{
+		"specific": {
+			Addr: []string{"foo"},
+
+			Readers: []FieldReader{
+				&MapFieldReader{
+					Schema: map[string]*Schema{
+						"foo": &Schema{Type: TypeString},
+					},
+					Map: BasicMapReader(map[string]string{
+						"foo": "bar",
+					}),
+				},
+				&MapFieldReader{
+					Schema: map[string]*Schema{
+						"foo": &Schema{Type: TypeString},
+					},
+					Map: BasicMapReader(map[string]string{
+						"foo": "baz",
+					}),
+				},
+				&MapFieldReader{
+					Schema: map[string]*Schema{
+						"foo": &Schema{Type: TypeString},
+					},
+					Map: BasicMapReader(map[string]string{}),
+				},
+			},
+
+			Level: "1",
+			Result: FieldReadResult{
+				Value:  "baz",
+				Exists: true,
+			},
+		},
+	}
+
+	for name, tc := range cases {
+		readers := make(map[string]FieldReader)
+		levels := make([]string, len(tc.Readers))
+		for i, r := range tc.Readers {
+			is := strconv.FormatInt(int64(i), 10)
+			readers[is] = r
+			levels[i] = is
+		}
+
+		r := &MultiLevelFieldReader{
+			Readers: readers,
+			Levels:  levels,
+		}
+
+		out, err := r.ReadFieldExact(tc.Addr, tc.Level)
+		if err != nil {
+			t.Fatalf("%s: err: %s", name, err)
+		}
+
+		if !reflect.DeepEqual(tc.Result, out) {
+			t.Fatalf("%s: bad: %#v", name, out)
+		}
+	}
+}
+
+func TestMultiLevelFieldReaderReadFieldMerge(t *testing.T) {
+	cases := map[string]struct {
+		Addr    []string
+		Readers []FieldReader
+		Result  FieldReadResult
+	}{
+		"stringInDiff": {
+			Addr: []string{"availability_zone"},
+
+			Readers: []FieldReader{
+				&DiffFieldReader{
+					Schema: map[string]*Schema{
+						"availability_zone": &Schema{Type: TypeString},
+					},
+
+					Source: &MapFieldReader{
+						Schema: map[string]*Schema{
+							"availability_zone": &Schema{Type: TypeString},
+						},
+						Map: BasicMapReader(map[string]string{
+							"availability_zone": "foo",
+						}),
+					},
+
+					Diff: &terraform.InstanceDiff{
+						Attributes: map[string]*terraform.ResourceAttrDiff{
+							"availability_zone": &terraform.ResourceAttrDiff{
+								Old:         "foo",
+								New:         "bar",
+								RequiresNew: true,
+							},
+						},
+					},
+				},
+			},
+
+			Result: FieldReadResult{
+				Value:  "bar",
+				Exists: true,
+			},
+		},
+
+		"lastLevelComputed": {
+			Addr: []string{"availability_zone"},
+
+			Readers: []FieldReader{
+				&MapFieldReader{
+					Schema: map[string]*Schema{
+						"availability_zone": &Schema{Type: TypeString},
+					},
+
+					Map: BasicMapReader(map[string]string{
+						"availability_zone": "foo",
+					}),
+				},
+
+				&DiffFieldReader{
+					Schema: map[string]*Schema{
+						"availability_zone": &Schema{Type: TypeString},
+					},
+
+					Source: &MapFieldReader{
+						Schema: map[string]*Schema{
+							"availability_zone": &Schema{Type: TypeString},
+						},
+
+						Map: BasicMapReader(map[string]string{
+							"availability_zone": "foo",
+						}),
+					},
+
+					Diff: &terraform.InstanceDiff{
+						Attributes: map[string]*terraform.ResourceAttrDiff{
+							"availability_zone": &terraform.ResourceAttrDiff{
+								Old:         "foo",
+								New:         "bar",
+								NewComputed: true,
+							},
+						},
+					},
+				},
+			},
+
+			Result: FieldReadResult{
+				Value:    "",
+				Exists:   true,
+				Computed: true,
+			},
+		},
+
+		"list of maps with removal in diff": {
+			Addr: []string{"config_vars"},
+
+			Readers: []FieldReader{
+				&DiffFieldReader{
+					Schema: map[string]*Schema{
+						"config_vars": &Schema{
+							Type: TypeList,
+							Elem: &Schema{Type: TypeMap},
+						},
+					},
+
+					Source: &MapFieldReader{
+						Schema: map[string]*Schema{
+							"config_vars": &Schema{
+								Type: TypeList,
+								Elem: &Schema{Type: TypeMap},
+							},
+						},
+
+						Map: BasicMapReader(map[string]string{
+							"config_vars.#":     "2",
+							"config_vars.0.foo": "bar",
+							"config_vars.0.bar": "bar",
+							"config_vars.1.bar": "baz",
+						}),
+					},
+
+					Diff: &terraform.InstanceDiff{
+						Attributes: map[string]*terraform.ResourceAttrDiff{
+							"config_vars.0.bar": &terraform.ResourceAttrDiff{
+								NewRemoved: true,
+							},
+						},
+					},
+				},
+			},
+
+			Result: FieldReadResult{
+				Value: []interface{}{
+					map[string]interface{}{
+						"foo": "bar",
+					},
+					map[string]interface{}{
+						"bar": "baz",
+					},
+				},
+				Exists: true,
+			},
+		},
+
+		"first level only": {
+			Addr: []string{"foo"},
+
+			Readers: []FieldReader{
+				&MapFieldReader{
+					Schema: map[string]*Schema{
+						"foo": &Schema{Type: TypeString},
+					},
+					Map: BasicMapReader(map[string]string{
+						"foo": "bar",
+					}),
+				},
+				&MapFieldReader{
+					Schema: map[string]*Schema{
+						"foo": &Schema{Type: TypeString},
+					},
+					Map: BasicMapReader(map[string]string{}),
+				},
+			},
+
+			Result: FieldReadResult{
+				Value:  "bar",
+				Exists: true,
+			},
+		},
+	}
+
+	for name, tc := range cases {
+		readers := make(map[string]FieldReader)
+		levels := make([]string, len(tc.Readers))
+		for i, r := range tc.Readers {
+			is := strconv.FormatInt(int64(i), 10)
+			readers[is] = r
+			levels[i] = is
+		}
+
+		r := &MultiLevelFieldReader{
+			Readers: readers,
+			Levels:  levels,
+		}
+
+		out, err := r.ReadFieldMerge(tc.Addr, levels[len(levels)-1])
+		if err != nil {
+			t.Fatalf("%s: err: %s", name, err)
+		}
+
+		if !reflect.DeepEqual(tc.Result, out) {
+			t.Fatalf("%s: bad: %#v", name, out)
+		}
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/field_reader_test.go b/v1.5.7/internal/legacy/helper/schema/field_reader_test.go
new file mode 100644
index 0000000..4c5060f
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/field_reader_test.go
@@ -0,0 +1,474 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestAddrToSchema(t *testing.T) {
+	cases := map[string]struct {
+		Addr   []string
+		Schema map[string]*Schema
+		Result []ValueType
+	}{
+		"full object": {
+			[]string{},
+			map[string]*Schema{
+				"list": &Schema{
+					Type: TypeList,
+					Elem: &Schema{Type: TypeInt},
+				},
+			},
+			[]ValueType{typeObject},
+		},
+
+		"list": {
+			[]string{"list"},
+			map[string]*Schema{
+				"list": &Schema{
+					Type: TypeList,
+					Elem: &Schema{Type: TypeInt},
+				},
+			},
+			[]ValueType{TypeList},
+		},
+
+		"list.#": {
+			[]string{"list", "#"},
+			map[string]*Schema{
+				"list": &Schema{
+					Type: TypeList,
+					Elem: &Schema{Type: TypeInt},
+				},
+			},
+			[]ValueType{TypeList, TypeInt},
+		},
+
+		"list.0": {
+			[]string{"list", "0"},
+			map[string]*Schema{
+				"list": &Schema{
+					Type: TypeList,
+					Elem: &Schema{Type: TypeInt},
+				},
+			},
+			[]ValueType{TypeList, TypeInt},
+		},
+
+		"list.0 with resource": {
+			[]string{"list", "0"},
+			map[string]*Schema{
+				"list": &Schema{
+					Type: TypeList,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"field": &Schema{Type: TypeString},
+						},
+					},
+				},
+			},
+			[]ValueType{TypeList, typeObject},
+		},
+
+		"list.0.field": {
+			[]string{"list", "0", "field"},
+			map[string]*Schema{
+				"list": &Schema{
+					Type: TypeList,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"field": &Schema{Type: TypeString},
+						},
+					},
+				},
+			},
+			[]ValueType{TypeList, typeObject, TypeString},
+		},
+
+		"set": {
+			[]string{"set"},
+			map[string]*Schema{
+				"set": &Schema{
+					Type: TypeSet,
+					Elem: &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+			[]ValueType{TypeSet},
+		},
+
+		"set.#": {
+			[]string{"set", "#"},
+			map[string]*Schema{
+				"set": &Schema{
+					Type: TypeSet,
+					Elem: &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+			[]ValueType{TypeSet, TypeInt},
+		},
+
+		"set.0": {
+			[]string{"set", "0"},
+			map[string]*Schema{
+				"set": &Schema{
+					Type: TypeSet,
+					Elem: &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+			[]ValueType{TypeSet, TypeInt},
+		},
+
+		"set.0 with resource": {
+			[]string{"set", "0"},
+			map[string]*Schema{
+				"set": &Schema{
+					Type: TypeSet,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"field": &Schema{Type: TypeString},
+						},
+					},
+				},
+			},
+			[]ValueType{TypeSet, typeObject},
+		},
+
+		"mapElem": {
+			[]string{"map", "foo"},
+			map[string]*Schema{
+				"map": &Schema{Type: TypeMap},
+			},
+			[]ValueType{TypeMap, TypeString},
+		},
+
+		"setDeep": {
+			[]string{"set", "50", "index"},
+			map[string]*Schema{
+				"set": &Schema{
+					Type: TypeSet,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"index": &Schema{Type: TypeInt},
+							"value": &Schema{Type: TypeString},
+						},
+					},
+					Set: func(a interface{}) int {
+						return a.(map[string]interface{})["index"].(int)
+					},
+				},
+			},
+			[]ValueType{TypeSet, typeObject, TypeInt},
+		},
+	}
+
+	for name, tc := range cases {
+		result := addrToSchema(tc.Addr, tc.Schema)
+		types := make([]ValueType, len(result))
+		for i, v := range result {
+			types[i] = v.Type
+		}
+
+		if !reflect.DeepEqual(types, tc.Result) {
+			t.Fatalf("%s: %#v", name, types)
+		}
+	}
+}
+
+// testFieldReader is a helper that should be used to verify that
+// a FieldReader behaves properly in all the common cases.
+func testFieldReader(t *testing.T, f func(map[string]*Schema) FieldReader) {
+	schema := map[string]*Schema{
+		// Primitives
+		"bool":   &Schema{Type: TypeBool},
+		"float":  &Schema{Type: TypeFloat},
+		"int":    &Schema{Type: TypeInt},
+		"string": &Schema{Type: TypeString},
+
+		// Lists
+		"list": &Schema{
+			Type: TypeList,
+			Elem: &Schema{Type: TypeString},
+		},
+		"listInt": &Schema{
+			Type: TypeList,
+			Elem: &Schema{Type: TypeInt},
+		},
+		"listMap": &Schema{
+			Type: TypeList,
+			Elem: &Schema{
+				Type: TypeMap,
+			},
+		},
+
+		// Maps
+		"map": &Schema{Type: TypeMap},
+		"mapInt": &Schema{
+			Type: TypeMap,
+			Elem: TypeInt,
+		},
+
+		// This is used to verify that the type of a Map can be specified using the
+		// same syntax as for lists (as a nested *Schema passed to Elem)
+		"mapIntNestedSchema": &Schema{
+			Type: TypeMap,
+			Elem: &Schema{Type: TypeInt},
+		},
+		"mapFloat": &Schema{
+			Type: TypeMap,
+			Elem: TypeFloat,
+		},
+		"mapBool": &Schema{
+			Type: TypeMap,
+			Elem: TypeBool,
+		},
+
+		// Sets
+		"set": &Schema{
+			Type: TypeSet,
+			Elem: &Schema{Type: TypeInt},
+			Set: func(a interface{}) int {
+				return a.(int)
+			},
+		},
+		"setDeep": &Schema{
+			Type: TypeSet,
+			Elem: &Resource{
+				Schema: map[string]*Schema{
+					"index": &Schema{Type: TypeInt},
+					"value": &Schema{Type: TypeString},
+				},
+			},
+			Set: func(a interface{}) int {
+				return a.(map[string]interface{})["index"].(int)
+			},
+		},
+		"setEmpty": &Schema{
+			Type: TypeSet,
+			Elem: &Schema{Type: TypeInt},
+			Set: func(a interface{}) int {
+				return a.(int)
+			},
+		},
+	}
+
+	cases := map[string]struct {
+		Addr   []string
+		Result FieldReadResult
+		Err    bool
+	}{
+		"noexist": {
+			[]string{"boolNOPE"},
+			FieldReadResult{
+				Value:    nil,
+				Exists:   false,
+				Computed: false,
+			},
+			false,
+		},
+
+		"bool": {
+			[]string{"bool"},
+			FieldReadResult{
+				Value:    true,
+				Exists:   true,
+				Computed: false,
+			},
+			false,
+		},
+
+		"float": {
+			[]string{"float"},
+			FieldReadResult{
+				Value:    3.1415,
+				Exists:   true,
+				Computed: false,
+			},
+			false,
+		},
+
+		"int": {
+			[]string{"int"},
+			FieldReadResult{
+				Value:    42,
+				Exists:   true,
+				Computed: false,
+			},
+			false,
+		},
+
+		"string": {
+			[]string{"string"},
+			FieldReadResult{
+				Value:    "string",
+				Exists:   true,
+				Computed: false,
+			},
+			false,
+		},
+
+		"list": {
+			[]string{"list"},
+			FieldReadResult{
+				Value: []interface{}{
+					"foo",
+					"bar",
+				},
+				Exists:   true,
+				Computed: false,
+			},
+			false,
+		},
+
+		"listInt": {
+			[]string{"listInt"},
+			FieldReadResult{
+				Value: []interface{}{
+					21,
+					42,
+				},
+				Exists:   true,
+				Computed: false,
+			},
+			false,
+		},
+
+		"map": {
+			[]string{"map"},
+			FieldReadResult{
+				Value: map[string]interface{}{
+					"foo": "bar",
+					"bar": "baz",
+				},
+				Exists:   true,
+				Computed: false,
+			},
+			false,
+		},
+
+		"mapInt": {
+			[]string{"mapInt"},
+			FieldReadResult{
+				Value: map[string]interface{}{
+					"one": 1,
+					"two": 2,
+				},
+				Exists:   true,
+				Computed: false,
+			},
+			false,
+		},
+
+		"mapIntNestedSchema": {
+			[]string{"mapIntNestedSchema"},
+			FieldReadResult{
+				Value: map[string]interface{}{
+					"one": 1,
+					"two": 2,
+				},
+				Exists:   true,
+				Computed: false,
+			},
+			false,
+		},
+
+		"mapFloat": {
+			[]string{"mapFloat"},
+			FieldReadResult{
+				Value: map[string]interface{}{
+					"oneDotTwo": 1.2,
+				},
+				Exists:   true,
+				Computed: false,
+			},
+			false,
+		},
+
+		"mapBool": {
+			[]string{"mapBool"},
+			FieldReadResult{
+				Value: map[string]interface{}{
+					"True":  true,
+					"False": false,
+				},
+				Exists:   true,
+				Computed: false,
+			},
+			false,
+		},
+
+		"mapelem": {
+			[]string{"map", "foo"},
+			FieldReadResult{
+				Value:    "bar",
+				Exists:   true,
+				Computed: false,
+			},
+			false,
+		},
+
+		"set": {
+			[]string{"set"},
+			FieldReadResult{
+				Value:    []interface{}{10, 50},
+				Exists:   true,
+				Computed: false,
+			},
+			false,
+		},
+
+		"setDeep": {
+			[]string{"setDeep"},
+			FieldReadResult{
+				Value: []interface{}{
+					map[string]interface{}{
+						"index": 10,
+						"value": "foo",
+					},
+					map[string]interface{}{
+						"index": 50,
+						"value": "bar",
+					},
+				},
+				Exists:   true,
+				Computed: false,
+			},
+			false,
+		},
+
+		"setEmpty": {
+			[]string{"setEmpty"},
+			FieldReadResult{
+				Value:  []interface{}{},
+				Exists: false,
+			},
+			false,
+		},
+	}
+
+	for name, tc := range cases {
+		r := f(schema)
+		out, err := r.ReadField(tc.Addr)
+		if err != nil != tc.Err {
+			t.Fatalf("%s: err: %s", name, err)
+		}
+		if s, ok := out.Value.(*Set); ok {
+			// If it is a set, convert to a list so its more easily checked.
+			out.Value = s.List()
+		}
+		if !reflect.DeepEqual(tc.Result, out) {
+			t.Fatalf("%s: bad: %#v", name, out)
+		}
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/field_writer.go b/v1.5.7/internal/legacy/helper/schema/field_writer.go
new file mode 100644
index 0000000..be4fae5
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/field_writer.go
@@ -0,0 +1,11 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+// FieldWriters are responsible for writing fields by address into
+// a proper typed representation. ResourceData uses this to write new data
+// into existing sources.
+type FieldWriter interface {
+	WriteField([]string, interface{}) error
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/field_writer_map.go b/v1.5.7/internal/legacy/helper/schema/field_writer_map.go
new file mode 100644
index 0000000..f022b18
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/field_writer_map.go
@@ -0,0 +1,360 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"sync"
+
+	"github.com/mitchellh/mapstructure"
+)
+
+// MapFieldWriter writes data into a single map[string]string structure.
+type MapFieldWriter struct {
+	Schema map[string]*Schema
+
+	lock   sync.Mutex
+	result map[string]string
+}
+
+// Map returns the underlying map that is being written to.
+func (w *MapFieldWriter) Map() map[string]string {
+	w.lock.Lock()
+	defer w.lock.Unlock()
+	if w.result == nil {
+		w.result = make(map[string]string)
+	}
+
+	return w.result
+}
+
+func (w *MapFieldWriter) unsafeWriteField(addr string, value string) {
+	w.lock.Lock()
+	defer w.lock.Unlock()
+	if w.result == nil {
+		w.result = make(map[string]string)
+	}
+
+	w.result[addr] = value
+}
+
+// clearTree clears a field and any sub-fields of the given address out of the
+// map. This should be used to reset some kind of complex structures (namely
+// sets) before writing to make sure that any conflicting data is removed (for
+// example, if the set was previously written to the writer's layer).
+func (w *MapFieldWriter) clearTree(addr []string) {
+	prefix := strings.Join(addr, ".") + "."
+	for k := range w.result {
+		if strings.HasPrefix(k, prefix) {
+			delete(w.result, k)
+		}
+	}
+}
+
+func (w *MapFieldWriter) WriteField(addr []string, value interface{}) error {
+	w.lock.Lock()
+	defer w.lock.Unlock()
+	if w.result == nil {
+		w.result = make(map[string]string)
+	}
+
+	schemaList := addrToSchema(addr, w.Schema)
+	if len(schemaList) == 0 {
+		return fmt.Errorf("Invalid address to set: %#v", addr)
+	}
+
+	// If we're setting anything other than a list root or set root,
+	// then disallow it.
+	for _, schema := range schemaList[:len(schemaList)-1] {
+		if schema.Type == TypeList {
+			return fmt.Errorf(
+				"%s: can only set full list",
+				strings.Join(addr, "."))
+		}
+
+		if schema.Type == TypeMap {
+			return fmt.Errorf(
+				"%s: can only set full map",
+				strings.Join(addr, "."))
+		}
+
+		if schema.Type == TypeSet {
+			return fmt.Errorf(
+				"%s: can only set full set",
+				strings.Join(addr, "."))
+		}
+	}
+
+	return w.set(addr, value)
+}
+
+func (w *MapFieldWriter) set(addr []string, value interface{}) error {
+	schemaList := addrToSchema(addr, w.Schema)
+	if len(schemaList) == 0 {
+		return fmt.Errorf("Invalid address to set: %#v", addr)
+	}
+
+	schema := schemaList[len(schemaList)-1]
+	switch schema.Type {
+	case TypeBool, TypeInt, TypeFloat, TypeString:
+		return w.setPrimitive(addr, value, schema)
+	case TypeList:
+		return w.setList(addr, value, schema)
+	case TypeMap:
+		return w.setMap(addr, value, schema)
+	case TypeSet:
+		return w.setSet(addr, value, schema)
+	case typeObject:
+		return w.setObject(addr, value, schema)
+	default:
+		panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
+	}
+}
+
+func (w *MapFieldWriter) setList(
+	addr []string,
+	v interface{},
+	schema *Schema) error {
+	k := strings.Join(addr, ".")
+	setElement := func(idx string, value interface{}) error {
+		addrCopy := make([]string, len(addr), len(addr)+1)
+		copy(addrCopy, addr)
+		return w.set(append(addrCopy, idx), value)
+	}
+
+	var vs []interface{}
+	if err := mapstructure.Decode(v, &vs); err != nil {
+		return fmt.Errorf("%s: %s", k, err)
+	}
+
+	// Wipe the set from the current writer prior to writing if it exists.
+	// Multiple writes to the same layer is a lot safer for lists than sets due
+	// to the fact that indexes are always deterministic and the length will
+	// always be updated with the current length on the last write, but making
+	// sure we have a clean namespace removes any chance for edge cases to pop up
+	// and ensures that the last write to the set is the correct value.
+	w.clearTree(addr)
+
+	// Set the entire list.
+	var err error
+	for i, elem := range vs {
+		is := strconv.FormatInt(int64(i), 10)
+		err = setElement(is, elem)
+		if err != nil {
+			break
+		}
+	}
+	if err != nil {
+		for i, _ := range vs {
+			is := strconv.FormatInt(int64(i), 10)
+			setElement(is, nil)
+		}
+
+		return err
+	}
+
+	w.result[k+".#"] = strconv.FormatInt(int64(len(vs)), 10)
+	return nil
+}
+
+func (w *MapFieldWriter) setMap(
+	addr []string,
+	value interface{},
+	schema *Schema) error {
+	k := strings.Join(addr, ".")
+	v := reflect.ValueOf(value)
+	vs := make(map[string]interface{})
+
+	if value == nil {
+		// The empty string here means the map is removed.
+		w.result[k] = ""
+		return nil
+	}
+
+	if v.Kind() != reflect.Map {
+		return fmt.Errorf("%s: must be a map", k)
+	}
+	if v.Type().Key().Kind() != reflect.String {
+		return fmt.Errorf("%s: keys must strings", k)
+	}
+	for _, mk := range v.MapKeys() {
+		mv := v.MapIndex(mk)
+		vs[mk.String()] = mv.Interface()
+	}
+
+	// Wipe this address tree. The contents of the map should always reflect the
+	// last write made to it.
+	w.clearTree(addr)
+
+	// Remove the pure key since we're setting the full map value
+	delete(w.result, k)
+
+	// Set each subkey
+	addrCopy := make([]string, len(addr), len(addr)+1)
+	copy(addrCopy, addr)
+	for subKey, v := range vs {
+		if err := w.set(append(addrCopy, subKey), v); err != nil {
+			return err
+		}
+	}
+
+	// Set the count
+	w.result[k+".%"] = strconv.Itoa(len(vs))
+
+	return nil
+}
+
+func (w *MapFieldWriter) setObject(
+	addr []string,
+	value interface{},
+	schema *Schema) error {
+	// Set the entire object. First decode into a proper structure
+	var v map[string]interface{}
+	if err := mapstructure.Decode(value, &v); err != nil {
+		return fmt.Errorf("%s: %s", strings.Join(addr, "."), err)
+	}
+
+	// Make space for additional elements in the address
+	addrCopy := make([]string, len(addr), len(addr)+1)
+	copy(addrCopy, addr)
+
+	// Set each element in turn
+	var err error
+	for k1, v1 := range v {
+		if err = w.set(append(addrCopy, k1), v1); err != nil {
+			break
+		}
+	}
+	if err != nil {
+		for k1, _ := range v {
+			w.set(append(addrCopy, k1), nil)
+		}
+	}
+
+	return err
+}
+
+func (w *MapFieldWriter) setPrimitive(
+	addr []string,
+	v interface{},
+	schema *Schema) error {
+	k := strings.Join(addr, ".")
+
+	if v == nil {
+		// The empty string here means the value is removed.
+		w.result[k] = ""
+		return nil
+	}
+
+	var set string
+	switch schema.Type {
+	case TypeBool:
+		var b bool
+		if err := mapstructure.Decode(v, &b); err != nil {
+			return fmt.Errorf("%s: %s", k, err)
+		}
+
+		set = strconv.FormatBool(b)
+	case TypeString:
+		if err := mapstructure.Decode(v, &set); err != nil {
+			return fmt.Errorf("%s: %s", k, err)
+		}
+	case TypeInt:
+		var n int
+		if err := mapstructure.Decode(v, &n); err != nil {
+			return fmt.Errorf("%s: %s", k, err)
+		}
+		set = strconv.FormatInt(int64(n), 10)
+	case TypeFloat:
+		var n float64
+		if err := mapstructure.Decode(v, &n); err != nil {
+			return fmt.Errorf("%s: %s", k, err)
+		}
+		set = strconv.FormatFloat(float64(n), 'G', -1, 64)
+	default:
+		return fmt.Errorf("Unknown type: %#v", schema.Type)
+	}
+
+	w.result[k] = set
+	return nil
+}
+
+func (w *MapFieldWriter) setSet(
+	addr []string,
+	value interface{},
+	schema *Schema) error {
+	addrCopy := make([]string, len(addr), len(addr)+1)
+	copy(addrCopy, addr)
+	k := strings.Join(addr, ".")
+
+	if value == nil {
+		w.result[k+".#"] = "0"
+		return nil
+	}
+
+	// If it is a slice, then we have to turn it into a *Set so that
+	// we get the proper order back based on the hash code.
+	if v := reflect.ValueOf(value); v.Kind() == reflect.Slice {
+		// Build a temp *ResourceData to use for the conversion
+		tempAddr := addr[len(addr)-1:]
+		tempSchema := *schema
+		tempSchema.Type = TypeList
+		tempSchemaMap := map[string]*Schema{tempAddr[0]: &tempSchema}
+		tempW := &MapFieldWriter{Schema: tempSchemaMap}
+
+		// Set the entire list, this lets us get values out of it
+		if err := tempW.WriteField(tempAddr, value); err != nil {
+			return err
+		}
+
+		// Build the set by going over the list items in order and
+		// hashing them into the set. The reason we go over the list and
+		// not the `value` directly is because this forces all types
+		// to become []interface{} (generic) instead of []string, which
+		// most hash functions are expecting.
+		s := schema.ZeroValue().(*Set)
+		tempR := &MapFieldReader{
+			Map:    BasicMapReader(tempW.Map()),
+			Schema: tempSchemaMap,
+		}
+		for i := 0; i < v.Len(); i++ {
+			is := strconv.FormatInt(int64(i), 10)
+			result, err := tempR.ReadField(append(tempAddr, is))
+			if err != nil {
+				return err
+			}
+			if !result.Exists {
+				panic("set item just set doesn't exist")
+			}
+
+			s.Add(result.Value)
+		}
+
+		value = s
+	}
+
+	// Clear any keys that match the set address first. This is necessary because
+	// it's always possible and sometimes may be necessary to write to a certain
+	// writer layer more than once with different set data each time, which will
+	// lead to different keys being inserted, which can lead to determinism
+	// problems when the old data isn't wiped first.
+	w.clearTree(addr)
+
+	if value.(*Set) == nil {
+		w.result[k+".#"] = "0"
+		return nil
+	}
+
+	for code, elem := range value.(*Set).m {
+		if err := w.set(append(addrCopy, code), elem); err != nil {
+			return err
+		}
+	}
+
+	w.result[k+".#"] = strconv.Itoa(value.(*Set).Len())
+	return nil
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/field_writer_map_test.go b/v1.5.7/internal/legacy/helper/schema/field_writer_map_test.go
new file mode 100644
index 0000000..db0b711
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/field_writer_map_test.go
@@ -0,0 +1,550 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestMapFieldWriter_impl(t *testing.T) {
+	var _ FieldWriter = new(MapFieldWriter)
+}
+
+func TestMapFieldWriter(t *testing.T) {
+	schema := map[string]*Schema{
+		"bool":   &Schema{Type: TypeBool},
+		"int":    &Schema{Type: TypeInt},
+		"string": &Schema{Type: TypeString},
+		"list": &Schema{
+			Type: TypeList,
+			Elem: &Schema{Type: TypeString},
+		},
+		"listInt": &Schema{
+			Type: TypeList,
+			Elem: &Schema{Type: TypeInt},
+		},
+		"listResource": &Schema{
+			Type:     TypeList,
+			Optional: true,
+			Computed: true,
+			Elem: &Resource{
+				Schema: map[string]*Schema{
+					"value": &Schema{
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+			},
+		},
+		"map": &Schema{Type: TypeMap},
+		"set": &Schema{
+			Type: TypeSet,
+			Elem: &Schema{Type: TypeInt},
+			Set: func(a interface{}) int {
+				return a.(int)
+			},
+		},
+		"setDeep": &Schema{
+			Type: TypeSet,
+			Elem: &Resource{
+				Schema: map[string]*Schema{
+					"index": &Schema{Type: TypeInt},
+					"value": &Schema{Type: TypeString},
+				},
+			},
+			Set: func(a interface{}) int {
+				return a.(map[string]interface{})["index"].(int)
+			},
+		},
+	}
+
+	cases := map[string]struct {
+		Addr  []string
+		Value interface{}
+		Err   bool
+		Out   map[string]string
+	}{
+		"noexist": {
+			[]string{"noexist"},
+			42,
+			true,
+			map[string]string{},
+		},
+
+		"bool": {
+			[]string{"bool"},
+			false,
+			false,
+			map[string]string{
+				"bool": "false",
+			},
+		},
+
+		"int": {
+			[]string{"int"},
+			42,
+			false,
+			map[string]string{
+				"int": "42",
+			},
+		},
+
+		"string": {
+			[]string{"string"},
+			"42",
+			false,
+			map[string]string{
+				"string": "42",
+			},
+		},
+
+		"string nil": {
+			[]string{"string"},
+			nil,
+			false,
+			map[string]string{
+				"string": "",
+			},
+		},
+
+		"list of resources": {
+			[]string{"listResource"},
+			[]interface{}{
+				map[string]interface{}{
+					"value": 80,
+				},
+			},
+			false,
+			map[string]string{
+				"listResource.#":       "1",
+				"listResource.0.value": "80",
+			},
+		},
+
+		"list of resources empty": {
+			[]string{"listResource"},
+			[]interface{}{},
+			false,
+			map[string]string{
+				"listResource.#": "0",
+			},
+		},
+
+		"list of resources nil": {
+			[]string{"listResource"},
+			nil,
+			false,
+			map[string]string{
+				"listResource.#": "0",
+			},
+		},
+
+		"list of strings": {
+			[]string{"list"},
+			[]interface{}{"foo", "bar"},
+			false,
+			map[string]string{
+				"list.#": "2",
+				"list.0": "foo",
+				"list.1": "bar",
+			},
+		},
+
+		"list element": {
+			[]string{"list", "0"},
+			"string",
+			true,
+			map[string]string{},
+		},
+
+		"map": {
+			[]string{"map"},
+			map[string]interface{}{"foo": "bar"},
+			false,
+			map[string]string{
+				"map.%":   "1",
+				"map.foo": "bar",
+			},
+		},
+
+		"map delete": {
+			[]string{"map"},
+			nil,
+			false,
+			map[string]string{
+				"map": "",
+			},
+		},
+
+		"map element": {
+			[]string{"map", "foo"},
+			"bar",
+			true,
+			map[string]string{},
+		},
+
+		"set": {
+			[]string{"set"},
+			[]interface{}{1, 2, 5},
+			false,
+			map[string]string{
+				"set.#": "3",
+				"set.1": "1",
+				"set.2": "2",
+				"set.5": "5",
+			},
+		},
+
+		"set nil": {
+			[]string{"set"},
+			nil,
+			false,
+			map[string]string{
+				"set.#": "0",
+			},
+		},
+
+		"set typed nil": {
+			[]string{"set"},
+			func() *Set { return nil }(),
+			false,
+			map[string]string{
+				"set.#": "0",
+			},
+		},
+
+		"set resource": {
+			[]string{"setDeep"},
+			[]interface{}{
+				map[string]interface{}{
+					"index": 10,
+					"value": "foo",
+				},
+				map[string]interface{}{
+					"index": 50,
+					"value": "bar",
+				},
+			},
+			false,
+			map[string]string{
+				"setDeep.#":        "2",
+				"setDeep.10.index": "10",
+				"setDeep.10.value": "foo",
+				"setDeep.50.index": "50",
+				"setDeep.50.value": "bar",
+			},
+		},
+
+		"set element": {
+			[]string{"set", "5"},
+			5,
+			true,
+			map[string]string{},
+		},
+
+		"full object": {
+			nil,
+			map[string]interface{}{
+				"string": "foo",
+				"list":   []interface{}{"foo", "bar"},
+			},
+			false,
+			map[string]string{
+				"string": "foo",
+				"list.#": "2",
+				"list.0": "foo",
+				"list.1": "bar",
+			},
+		},
+	}
+
+	for name, tc := range cases {
+		w := &MapFieldWriter{Schema: schema}
+		err := w.WriteField(tc.Addr, tc.Value)
+		if err != nil != tc.Err {
+			t.Fatalf("%s: err: %s", name, err)
+		}
+
+		actual := w.Map()
+		if !reflect.DeepEqual(actual, tc.Out) {
+			t.Fatalf("%s: bad: %#v", name, actual)
+		}
+	}
+}
+
+func TestMapFieldWriterCleanSet(t *testing.T) {
+	schema := map[string]*Schema{
+		"setDeep": &Schema{
+			Type: TypeSet,
+			Elem: &Resource{
+				Schema: map[string]*Schema{
+					"index": &Schema{Type: TypeInt},
+					"value": &Schema{Type: TypeString},
+				},
+			},
+			Set: func(a interface{}) int {
+				return a.(map[string]interface{})["index"].(int)
+			},
+		},
+	}
+
+	values := []struct {
+		Addr  []string
+		Value interface{}
+		Out   map[string]string
+	}{
+		{
+			[]string{"setDeep"},
+			[]interface{}{
+				map[string]interface{}{
+					"index": 10,
+					"value": "foo",
+				},
+				map[string]interface{}{
+					"index": 50,
+					"value": "bar",
+				},
+			},
+			map[string]string{
+				"setDeep.#":        "2",
+				"setDeep.10.index": "10",
+				"setDeep.10.value": "foo",
+				"setDeep.50.index": "50",
+				"setDeep.50.value": "bar",
+			},
+		},
+		{
+			[]string{"setDeep"},
+			[]interface{}{
+				map[string]interface{}{
+					"index": 20,
+					"value": "baz",
+				},
+				map[string]interface{}{
+					"index": 60,
+					"value": "qux",
+				},
+			},
+			map[string]string{
+				"setDeep.#":        "2",
+				"setDeep.20.index": "20",
+				"setDeep.20.value": "baz",
+				"setDeep.60.index": "60",
+				"setDeep.60.value": "qux",
+			},
+		},
+		{
+			[]string{"setDeep"},
+			[]interface{}{
+				map[string]interface{}{
+					"index": 30,
+					"value": "one",
+				},
+				map[string]interface{}{
+					"index": 70,
+					"value": "two",
+				},
+			},
+			map[string]string{
+				"setDeep.#":        "2",
+				"setDeep.30.index": "30",
+				"setDeep.30.value": "one",
+				"setDeep.70.index": "70",
+				"setDeep.70.value": "two",
+			},
+		},
+	}
+
+	w := &MapFieldWriter{Schema: schema}
+
+	for n, tc := range values {
+		err := w.WriteField(tc.Addr, tc.Value)
+		if err != nil {
+			t.Fatalf("%d: err: %s", n, err)
+		}
+
+		actual := w.Map()
+		if !reflect.DeepEqual(actual, tc.Out) {
+			t.Fatalf("%d: bad: %#v", n, actual)
+		}
+	}
+}
+
+func TestMapFieldWriterCleanList(t *testing.T) {
+	schema := map[string]*Schema{
+		"listDeep": &Schema{
+			Type: TypeList,
+			Elem: &Resource{
+				Schema: map[string]*Schema{
+					"thing1": &Schema{Type: TypeString},
+					"thing2": &Schema{Type: TypeString},
+				},
+			},
+		},
+	}
+
+	values := []struct {
+		Addr  []string
+		Value interface{}
+		Out   map[string]string
+	}{
+		{
+			// Base list
+			[]string{"listDeep"},
+			[]interface{}{
+				map[string]interface{}{
+					"thing1": "a",
+					"thing2": "b",
+				},
+				map[string]interface{}{
+					"thing1": "c",
+					"thing2": "d",
+				},
+				map[string]interface{}{
+					"thing1": "e",
+					"thing2": "f",
+				},
+				map[string]interface{}{
+					"thing1": "g",
+					"thing2": "h",
+				},
+			},
+			map[string]string{
+				"listDeep.#":        "4",
+				"listDeep.0.thing1": "a",
+				"listDeep.0.thing2": "b",
+				"listDeep.1.thing1": "c",
+				"listDeep.1.thing2": "d",
+				"listDeep.2.thing1": "e",
+				"listDeep.2.thing2": "f",
+				"listDeep.3.thing1": "g",
+				"listDeep.3.thing2": "h",
+			},
+		},
+		{
+			// Remove an element
+			[]string{"listDeep"},
+			[]interface{}{
+				map[string]interface{}{
+					"thing1": "a",
+					"thing2": "b",
+				},
+				map[string]interface{}{
+					"thing1": "c",
+					"thing2": "d",
+				},
+				map[string]interface{}{
+					"thing1": "e",
+					"thing2": "f",
+				},
+			},
+			map[string]string{
+				"listDeep.#":        "3",
+				"listDeep.0.thing1": "a",
+				"listDeep.0.thing2": "b",
+				"listDeep.1.thing1": "c",
+				"listDeep.1.thing2": "d",
+				"listDeep.2.thing1": "e",
+				"listDeep.2.thing2": "f",
+			},
+		},
+		{
+			// Rewrite with missing keys. This should normally not be necessary, as
+			// hopefully the writers are writing zero values as necessary, but for
+			// brevity we want to make sure that what exists in the writer is exactly
+			// what the last write looked like coming from the provider.
+			[]string{"listDeep"},
+			[]interface{}{
+				map[string]interface{}{
+					"thing1": "a",
+				},
+				map[string]interface{}{
+					"thing1": "c",
+				},
+				map[string]interface{}{
+					"thing1": "e",
+				},
+			},
+			map[string]string{
+				"listDeep.#":        "3",
+				"listDeep.0.thing1": "a",
+				"listDeep.1.thing1": "c",
+				"listDeep.2.thing1": "e",
+			},
+		},
+	}
+
+	w := &MapFieldWriter{Schema: schema}
+
+	for n, tc := range values {
+		err := w.WriteField(tc.Addr, tc.Value)
+		if err != nil {
+			t.Fatalf("%d: err: %s", n, err)
+		}
+
+		actual := w.Map()
+		if !reflect.DeepEqual(actual, tc.Out) {
+			t.Fatalf("%d: bad: %#v", n, actual)
+		}
+	}
+}
+
+func TestMapFieldWriterCleanMap(t *testing.T) {
+	schema := map[string]*Schema{
+		"map": &Schema{
+			Type: TypeMap,
+		},
+	}
+
+	values := []struct {
+		Value interface{}
+		Out   map[string]string
+	}{
+		{
+			// Base map
+			map[string]interface{}{
+				"thing1": "a",
+				"thing2": "b",
+				"thing3": "c",
+				"thing4": "d",
+			},
+			map[string]string{
+				"map.%":      "4",
+				"map.thing1": "a",
+				"map.thing2": "b",
+				"map.thing3": "c",
+				"map.thing4": "d",
+			},
+		},
+		{
+			// Base map
+			map[string]interface{}{
+				"thing1": "a",
+				"thing2": "b",
+				"thing4": "d",
+			},
+			map[string]string{
+				"map.%":      "3",
+				"map.thing1": "a",
+				"map.thing2": "b",
+				"map.thing4": "d",
+			},
+		},
+	}
+
+	w := &MapFieldWriter{Schema: schema}
+
+	for n, tc := range values {
+		err := w.WriteField([]string{"map"}, tc.Value)
+		if err != nil {
+			t.Fatalf("%d: err: %s", n, err)
+		}
+
+		actual := w.Map()
+		if !reflect.DeepEqual(actual, tc.Out) {
+			t.Fatalf("%d: bad: %#v", n, actual)
+		}
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/getsource_string.go b/v1.5.7/internal/legacy/helper/schema/getsource_string.go
new file mode 100644
index 0000000..0184d7b
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/getsource_string.go
@@ -0,0 +1,46 @@
+// Code generated by "stringer -type=getSource resource_data_get_source.go"; DO NOT EDIT.
+
+package schema
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[getSourceState-1]
+	_ = x[getSourceConfig-2]
+	_ = x[getSourceDiff-4]
+	_ = x[getSourceSet-8]
+	_ = x[getSourceExact-16]
+	_ = x[getSourceLevelMask-15]
+}
+
+const (
+	_getSource_name_0 = "getSourceStategetSourceConfig"
+	_getSource_name_1 = "getSourceDiff"
+	_getSource_name_2 = "getSourceSet"
+	_getSource_name_3 = "getSourceLevelMaskgetSourceExact"
+)
+
+var (
+	_getSource_index_0 = [...]uint8{0, 14, 29}
+	_getSource_index_3 = [...]uint8{0, 18, 32}
+)
+
+func (i getSource) String() string {
+	switch {
+	case 1 <= i && i <= 2:
+		i -= 1
+		return _getSource_name_0[_getSource_index_0[i]:_getSource_index_0[i+1]]
+	case i == 4:
+		return _getSource_name_1
+	case i == 8:
+		return _getSource_name_2
+	case 15 <= i && i <= 16:
+		i -= 15
+		return _getSource_name_3[_getSource_index_3[i]:_getSource_index_3[i+1]]
+	default:
+		return "getSource(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/provider.go b/v1.5.7/internal/legacy/helper/schema/provider.go
new file mode 100644
index 0000000..a783a36
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/provider.go
@@ -0,0 +1,480 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"sort"
+	"sync"
+
+	multierror "github.com/hashicorp/go-multierror"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+var ReservedProviderFields = []string{
+	"alias",
+	"version",
+}
+
+// Provider represents a resource provider in Terraform, and properly
+// implements all of the ResourceProvider API.
+//
+// By defining a schema for the configuration of the provider, the
+// map of supporting resources, and a configuration function, the schema
+// framework takes over and handles all the provider operations for you.
+//
+// After defining the provider structure, it is unlikely that you'll require any
+// of the methods on Provider itself.
+type Provider struct {
+	// Schema is the schema for the configuration of this provider. If this
+	// provider has no configuration, this can be omitted.
+	//
+	// The keys of this map are the configuration keys, and the value is
+	// the schema describing the value of the configuration.
+	Schema map[string]*Schema
+
+	// ResourcesMap is the list of available resources that this provider
+	// can manage, along with their Resource structure defining their
+	// own schemas and CRUD operations.
+	//
+	// Provider automatically handles routing operations such as Apply,
+	// Diff, etc. to the proper resource.
+	ResourcesMap map[string]*Resource
+
+	// DataSourcesMap is the collection of available data sources that
+	// this provider implements, with a Resource instance defining
+	// the schema and Read operation of each.
+	//
+	// Resource instances for data sources must have a Read function
+	// and must *not* implement Create, Update or Delete.
+	DataSourcesMap map[string]*Resource
+
+	// ProviderMetaSchema is the schema for the configuration of the meta
+	// information for this provider. If this provider has no meta info,
+	// this can be omitted. This functionality is currently experimental
+	// and subject to change or break without warning; it should only be
+	// used by providers that are collaborating on its use with the
+	// Terraform team.
+	ProviderMetaSchema map[string]*Schema
+
+	// ConfigureFunc is a function for configuring the provider. If the
+	// provider doesn't need to be configured, this can be omitted.
+	//
+	// See the ConfigureFunc documentation for more information.
+	ConfigureFunc ConfigureFunc
+
+	// MetaReset is called by TestReset to reset any state stored in the meta
+	// interface.  This is especially important if the StopContext is stored by
+	// the provider.
+	MetaReset func() error
+
+	meta interface{}
+
+	// a mutex is required because TestReset can directly replace the stopCtx
+	stopMu        sync.Mutex
+	stopCtx       context.Context
+	stopCtxCancel context.CancelFunc
+	stopOnce      sync.Once
+
+	TerraformVersion string
+}
+
+// ConfigureFunc is the function used to configure a Provider.
+//
+// The interface{} value returned by this function is stored and passed into
+// the subsequent resources as the meta parameter. This return value is
+// usually used to pass along a configured API client, a configuration
+// structure, etc.
+type ConfigureFunc func(*ResourceData) (interface{}, error)
+
+// InternalValidate should be called to validate the structure
+// of the provider.
+//
+// This should be called in a unit test for any provider to verify
+// before release that a provider is properly configured for use with
+// this library.
+func (p *Provider) InternalValidate() error {
+	if p == nil {
+		return errors.New("provider is nil")
+	}
+
+	var validationErrors error
+	sm := schemaMap(p.Schema)
+	if err := sm.InternalValidate(sm); err != nil {
+		validationErrors = multierror.Append(validationErrors, err)
+	}
+
+	// Provider-specific checks
+	for k, _ := range sm {
+		if isReservedProviderFieldName(k) {
+			return fmt.Errorf("%s is a reserved field name for a provider", k)
+		}
+	}
+
+	for k, r := range p.ResourcesMap {
+		if err := r.InternalValidate(nil, true); err != nil {
+			validationErrors = multierror.Append(validationErrors, fmt.Errorf("resource %s: %s", k, err))
+		}
+	}
+
+	for k, r := range p.DataSourcesMap {
+		if err := r.InternalValidate(nil, false); err != nil {
+			validationErrors = multierror.Append(validationErrors, fmt.Errorf("data source %s: %s", k, err))
+		}
+	}
+
+	return validationErrors
+}
+
+func isReservedProviderFieldName(name string) bool {
+	for _, reservedName := range ReservedProviderFields {
+		if name == reservedName {
+			return true
+		}
+	}
+	return false
+}
+
+// Meta returns the metadata associated with this provider that was
+// returned by the Configure call. It will be nil until Configure is called.
+func (p *Provider) Meta() interface{} {
+	return p.meta
+}
+
+// SetMeta can be used to forcefully set the Meta object of the provider.
+// Note that if Configure is called the return value will override anything
+// set here.
+func (p *Provider) SetMeta(v interface{}) {
+	p.meta = v
+}
+
+// Stopped reports whether the provider has been stopped or not.
+func (p *Provider) Stopped() bool {
+	ctx := p.StopContext()
+	select {
+	case <-ctx.Done():
+		return true
+	default:
+		return false
+	}
+}
+
+// StopCh returns a channel that is closed once the provider is stopped.
+func (p *Provider) StopContext() context.Context {
+	p.stopOnce.Do(p.stopInit)
+
+	p.stopMu.Lock()
+	defer p.stopMu.Unlock()
+
+	return p.stopCtx
+}
+
+func (p *Provider) stopInit() {
+	p.stopMu.Lock()
+	defer p.stopMu.Unlock()
+
+	p.stopCtx, p.stopCtxCancel = context.WithCancel(context.Background())
+}
+
+// Stop implementation of terraform.ResourceProvider interface.
+func (p *Provider) Stop() error {
+	p.stopOnce.Do(p.stopInit)
+
+	p.stopMu.Lock()
+	defer p.stopMu.Unlock()
+
+	p.stopCtxCancel()
+	return nil
+}
+
+// TestReset resets any state stored in the Provider, and will call TestReset
+// on Meta if it implements the TestProvider interface.
+// This may be used to reset the schema.Provider at the start of a test, and is
+// automatically called by resource.Test.
+func (p *Provider) TestReset() error {
+	p.stopInit()
+	if p.MetaReset != nil {
+		return p.MetaReset()
+	}
+	return nil
+}
+
+// GetSchema implementation of terraform.ResourceProvider interface
+func (p *Provider) GetSchema(req *terraform.ProviderSchemaRequest) (*terraform.ProviderSchema, error) {
+	resourceTypes := map[string]*configschema.Block{}
+	dataSources := map[string]*configschema.Block{}
+
+	for _, name := range req.ResourceTypes {
+		if r, exists := p.ResourcesMap[name]; exists {
+			resourceTypes[name] = r.CoreConfigSchema()
+		}
+	}
+	for _, name := range req.DataSources {
+		if r, exists := p.DataSourcesMap[name]; exists {
+			dataSources[name] = r.CoreConfigSchema()
+		}
+	}
+
+	return &terraform.ProviderSchema{
+		Provider:      schemaMap(p.Schema).CoreConfigSchema(),
+		ResourceTypes: resourceTypes,
+		DataSources:   dataSources,
+	}, nil
+}
+
+// Input implementation of terraform.ResourceProvider interface.
+func (p *Provider) Input(
+	input terraform.UIInput,
+	c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) {
+	return schemaMap(p.Schema).Input(input, c)
+}
+
+// Validate implementation of terraform.ResourceProvider interface.
+func (p *Provider) Validate(c *terraform.ResourceConfig) ([]string, []error) {
+	if err := p.InternalValidate(); err != nil {
+		return nil, []error{fmt.Errorf(
+			"Internal validation of the provider failed! This is always a bug\n"+
+				"with the provider itself, and not a user issue. Please report\n"+
+				"this bug:\n\n%s", err)}
+	}
+
+	return schemaMap(p.Schema).Validate(c)
+}
+
+// ValidateResource implementation of terraform.ResourceProvider interface.
+func (p *Provider) ValidateResource(
+	t string, c *terraform.ResourceConfig) ([]string, []error) {
+	r, ok := p.ResourcesMap[t]
+	if !ok {
+		return nil, []error{fmt.Errorf(
+			"Provider doesn't support resource: %s", t)}
+	}
+
+	return r.Validate(c)
+}
+
+// Configure implementation of terraform.ResourceProvider interface.
+func (p *Provider) Configure(c *terraform.ResourceConfig) error {
+	// No configuration
+	if p.ConfigureFunc == nil {
+		return nil
+	}
+
+	sm := schemaMap(p.Schema)
+
+	// Get a ResourceData for this configuration. To do this, we actually
+	// generate an intermediary "diff" although that is never exposed.
+	diff, err := sm.Diff(nil, c, nil, p.meta, true)
+	if err != nil {
+		return err
+	}
+
+	data, err := sm.Data(nil, diff)
+	if err != nil {
+		return err
+	}
+
+	meta, err := p.ConfigureFunc(data)
+	if err != nil {
+		return err
+	}
+
+	p.meta = meta
+	return nil
+}
+
+// Apply implementation of terraform.ResourceProvider interface.
+func (p *Provider) Apply(
+	info *terraform.InstanceInfo,
+	s *terraform.InstanceState,
+	d *terraform.InstanceDiff) (*terraform.InstanceState, error) {
+	r, ok := p.ResourcesMap[info.Type]
+	if !ok {
+		return nil, fmt.Errorf("unknown resource type: %s", info.Type)
+	}
+
+	return r.Apply(s, d, p.meta)
+}
+
+// Diff implementation of terraform.ResourceProvider interface.
+func (p *Provider) Diff(
+	info *terraform.InstanceInfo,
+	s *terraform.InstanceState,
+	c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
+	r, ok := p.ResourcesMap[info.Type]
+	if !ok {
+		return nil, fmt.Errorf("unknown resource type: %s", info.Type)
+	}
+
+	return r.Diff(s, c, p.meta)
+}
+
+// SimpleDiff is used by the new protocol wrappers to get a diff that doesn't
+// attempt to calculate ignore_changes.
+func (p *Provider) SimpleDiff(
+	info *terraform.InstanceInfo,
+	s *terraform.InstanceState,
+	c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
+	r, ok := p.ResourcesMap[info.Type]
+	if !ok {
+		return nil, fmt.Errorf("unknown resource type: %s", info.Type)
+	}
+
+	return r.simpleDiff(s, c, p.meta)
+}
+
+// Refresh implementation of terraform.ResourceProvider interface.
+func (p *Provider) Refresh(
+	info *terraform.InstanceInfo,
+	s *terraform.InstanceState) (*terraform.InstanceState, error) {
+	r, ok := p.ResourcesMap[info.Type]
+	if !ok {
+		return nil, fmt.Errorf("unknown resource type: %s", info.Type)
+	}
+
+	return r.Refresh(s, p.meta)
+}
+
+// Resources implementation of terraform.ResourceProvider interface.
+func (p *Provider) Resources() []terraform.ResourceType {
+	keys := make([]string, 0, len(p.ResourcesMap))
+	for k := range p.ResourcesMap {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+
+	result := make([]terraform.ResourceType, 0, len(keys))
+	for _, k := range keys {
+		resource := p.ResourcesMap[k]
+
+		// This isn't really possible (it'd fail InternalValidate), but
+		// we do it anyways to avoid a panic.
+		if resource == nil {
+			resource = &Resource{}
+		}
+
+		result = append(result, terraform.ResourceType{
+			Name:       k,
+			Importable: resource.Importer != nil,
+
+			// Indicates that a provider is compiled against a new enough
+			// version of core to support the GetSchema method.
+			SchemaAvailable: true,
+		})
+	}
+
+	return result
+}
+
+func (p *Provider) ImportState(
+	info *terraform.InstanceInfo,
+	id string) ([]*terraform.InstanceState, error) {
+	// Find the resource
+	r, ok := p.ResourcesMap[info.Type]
+	if !ok {
+		return nil, fmt.Errorf("unknown resource type: %s", info.Type)
+	}
+
+	// If it doesn't support import, error
+	if r.Importer == nil {
+		return nil, fmt.Errorf("resource %s doesn't support import", info.Type)
+	}
+
+	// Create the data
+	data := r.Data(nil)
+	data.SetId(id)
+	data.SetType(info.Type)
+
+	// Call the import function
+	results := []*ResourceData{data}
+	if r.Importer.State != nil {
+		var err error
+		results, err = r.Importer.State(data, p.meta)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	// Convert the results to InstanceState values and return it
+	states := make([]*terraform.InstanceState, len(results))
+	for i, r := range results {
+		states[i] = r.State()
+	}
+
+	// Verify that all are non-nil. If there are any nil the error
+	// isn't obvious so we circumvent that with a friendlier error.
+	for _, s := range states {
+		if s == nil {
+			return nil, fmt.Errorf(
+				"nil entry in ImportState results. This is always a bug with\n" +
+					"the resource that is being imported. Please report this as\n" +
+					"a bug to Terraform.")
+		}
+	}
+
+	return states, nil
+}
+
+// ValidateDataSource implementation of terraform.ResourceProvider interface.
+func (p *Provider) ValidateDataSource(
+	t string, c *terraform.ResourceConfig) ([]string, []error) {
+	r, ok := p.DataSourcesMap[t]
+	if !ok {
+		return nil, []error{fmt.Errorf(
+			"Provider doesn't support data source: %s", t)}
+	}
+
+	return r.Validate(c)
+}
+
+// ReadDataDiff implementation of terraform.ResourceProvider interface.
+func (p *Provider) ReadDataDiff(
+	info *terraform.InstanceInfo,
+	c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
+
+	r, ok := p.DataSourcesMap[info.Type]
+	if !ok {
+		return nil, fmt.Errorf("unknown data source: %s", info.Type)
+	}
+
+	return r.Diff(nil, c, p.meta)
+}
+
+// RefreshData implementation of terraform.ResourceProvider interface.
+func (p *Provider) ReadDataApply(
+	info *terraform.InstanceInfo,
+	d *terraform.InstanceDiff) (*terraform.InstanceState, error) {
+
+	r, ok := p.DataSourcesMap[info.Type]
+	if !ok {
+		return nil, fmt.Errorf("unknown data source: %s", info.Type)
+	}
+
+	return r.ReadDataApply(d, p.meta)
+}
+
+// DataSources implementation of terraform.ResourceProvider interface.
+func (p *Provider) DataSources() []terraform.DataSource {
+	keys := make([]string, 0, len(p.DataSourcesMap))
+	for k, _ := range p.DataSourcesMap {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+
+	result := make([]terraform.DataSource, 0, len(keys))
+	for _, k := range keys {
+		result = append(result, terraform.DataSource{
+			Name: k,
+
+			// Indicates that a provider is compiled against a new enough
+			// version of core to support the GetSchema method.
+			SchemaAvailable: true,
+		})
+	}
+
+	return result
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/provider_test.go b/v1.5.7/internal/legacy/helper/schema/provider_test.go
new file mode 100644
index 0000000..2f2bc8d
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/provider_test.go
@@ -0,0 +1,623 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+func TestProvider_impl(t *testing.T) {
+	var _ terraform.ResourceProvider = new(Provider)
+}
+
+func TestProviderGetSchema(t *testing.T) {
+	// This functionality is already broadly tested in core_schema_test.go,
+	// so this is just to ensure that the call passes through correctly.
+	p := &Provider{
+		Schema: map[string]*Schema{
+			"bar": {
+				Type:     TypeString,
+				Required: true,
+			},
+		},
+		ResourcesMap: map[string]*Resource{
+			"foo": &Resource{
+				Schema: map[string]*Schema{
+					"bar": {
+						Type:     TypeString,
+						Required: true,
+					},
+				},
+			},
+		},
+		DataSourcesMap: map[string]*Resource{
+			"baz": &Resource{
+				Schema: map[string]*Schema{
+					"bur": {
+						Type:     TypeString,
+						Required: true,
+					},
+				},
+			},
+		},
+	}
+
+	want := &terraform.ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"bar": &configschema.Attribute{
+					Type:     cty.String,
+					Required: true,
+				},
+			},
+			BlockTypes: map[string]*configschema.NestedBlock{},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			"foo": testResource(&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"bar": &configschema.Attribute{
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{},
+			}),
+		},
+		DataSources: map[string]*configschema.Block{
+			"baz": testResource(&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"bur": &configschema.Attribute{
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{},
+			}),
+		},
+	}
+	got, err := p.GetSchema(&terraform.ProviderSchemaRequest{
+		ResourceTypes: []string{"foo", "bar"},
+		DataSources:   []string{"baz", "bar"},
+	})
+	if err != nil {
+		t.Fatalf("unexpected error %s", err)
+	}
+
+	if !cmp.Equal(got, want, equateEmpty, typeComparer) {
+		t.Error("wrong result:\n", cmp.Diff(got, want, equateEmpty, typeComparer))
+	}
+}
+
+func TestProviderConfigure(t *testing.T) {
+	cases := []struct {
+		P      *Provider
+		Config map[string]interface{}
+		Err    bool
+	}{
+		{
+			P:      &Provider{},
+			Config: nil,
+			Err:    false,
+		},
+
+		{
+			P: &Provider{
+				Schema: map[string]*Schema{
+					"foo": &Schema{
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+
+				ConfigureFunc: func(d *ResourceData) (interface{}, error) {
+					if d.Get("foo").(int) == 42 {
+						return nil, nil
+					}
+
+					return nil, fmt.Errorf("nope")
+				},
+			},
+			Config: map[string]interface{}{
+				"foo": 42,
+			},
+			Err: false,
+		},
+
+		{
+			P: &Provider{
+				Schema: map[string]*Schema{
+					"foo": &Schema{
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+
+				ConfigureFunc: func(d *ResourceData) (interface{}, error) {
+					if d.Get("foo").(int) == 42 {
+						return nil, nil
+					}
+
+					return nil, fmt.Errorf("nope")
+				},
+			},
+			Config: map[string]interface{}{
+				"foo": 52,
+			},
+			Err: true,
+		},
+	}
+
+	for i, tc := range cases {
+		c := terraform.NewResourceConfigRaw(tc.Config)
+		err := tc.P.Configure(c)
+		if err != nil != tc.Err {
+			t.Fatalf("%d: %s", i, err)
+		}
+	}
+}
+
+func TestProviderResources(t *testing.T) {
+	cases := []struct {
+		P      *Provider
+		Result []terraform.ResourceType
+	}{
+		{
+			P:      &Provider{},
+			Result: []terraform.ResourceType{},
+		},
+
+		{
+			P: &Provider{
+				ResourcesMap: map[string]*Resource{
+					"foo": nil,
+					"bar": nil,
+				},
+			},
+			Result: []terraform.ResourceType{
+				terraform.ResourceType{Name: "bar", SchemaAvailable: true},
+				terraform.ResourceType{Name: "foo", SchemaAvailable: true},
+			},
+		},
+
+		{
+			P: &Provider{
+				ResourcesMap: map[string]*Resource{
+					"foo": nil,
+					"bar": &Resource{Importer: &ResourceImporter{}},
+					"baz": nil,
+				},
+			},
+			Result: []terraform.ResourceType{
+				terraform.ResourceType{Name: "bar", Importable: true, SchemaAvailable: true},
+				terraform.ResourceType{Name: "baz", SchemaAvailable: true},
+				terraform.ResourceType{Name: "foo", SchemaAvailable: true},
+			},
+		},
+	}
+
+	for i, tc := range cases {
+		actual := tc.P.Resources()
+		if !reflect.DeepEqual(actual, tc.Result) {
+			t.Fatalf("%d: %#v", i, actual)
+		}
+	}
+}
+
+func TestProviderDataSources(t *testing.T) {
+	cases := []struct {
+		P      *Provider
+		Result []terraform.DataSource
+	}{
+		{
+			P:      &Provider{},
+			Result: []terraform.DataSource{},
+		},
+
+		{
+			P: &Provider{
+				DataSourcesMap: map[string]*Resource{
+					"foo": nil,
+					"bar": nil,
+				},
+			},
+			Result: []terraform.DataSource{
+				terraform.DataSource{Name: "bar", SchemaAvailable: true},
+				terraform.DataSource{Name: "foo", SchemaAvailable: true},
+			},
+		},
+	}
+
+	for i, tc := range cases {
+		actual := tc.P.DataSources()
+		if !reflect.DeepEqual(actual, tc.Result) {
+			t.Fatalf("%d: got %#v; want %#v", i, actual, tc.Result)
+		}
+	}
+}
+
+func TestProviderValidate(t *testing.T) {
+	cases := []struct {
+		P      *Provider
+		Config map[string]interface{}
+		Err    bool
+	}{
+		{
+			P: &Provider{
+				Schema: map[string]*Schema{
+					"foo": &Schema{},
+				},
+			},
+			Config: nil,
+			Err:    true,
+		},
+	}
+
+	for i, tc := range cases {
+		c := terraform.NewResourceConfigRaw(tc.Config)
+		_, es := tc.P.Validate(c)
+		if len(es) > 0 != tc.Err {
+			t.Fatalf("%d: %#v", i, es)
+		}
+	}
+}
+
+func TestProviderDiff_legacyTimeoutType(t *testing.T) {
+	p := &Provider{
+		ResourcesMap: map[string]*Resource{
+			"blah": &Resource{
+				Schema: map[string]*Schema{
+					"foo": {
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+				Timeouts: &ResourceTimeout{
+					Create: DefaultTimeout(10 * time.Minute),
+				},
+			},
+		},
+	}
+
+	invalidCfg := map[string]interface{}{
+		"foo": 42,
+		"timeouts": []interface{}{
+			map[string]interface{}{
+				"create": "40m",
+			},
+		},
+	}
+	ic := terraform.NewResourceConfigRaw(invalidCfg)
+	_, err := p.Diff(
+		&terraform.InstanceInfo{
+			Type: "blah",
+		},
+		nil,
+		ic,
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestProviderDiff_timeoutInvalidValue(t *testing.T) {
+	p := &Provider{
+		ResourcesMap: map[string]*Resource{
+			"blah": &Resource{
+				Schema: map[string]*Schema{
+					"foo": {
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+				Timeouts: &ResourceTimeout{
+					Create: DefaultTimeout(10 * time.Minute),
+				},
+			},
+		},
+	}
+
+	invalidCfg := map[string]interface{}{
+		"foo": 42,
+		"timeouts": map[string]interface{}{
+			"create": "invalid",
+		},
+	}
+	ic := terraform.NewResourceConfigRaw(invalidCfg)
+	_, err := p.Diff(
+		&terraform.InstanceInfo{
+			Type: "blah",
+		},
+		nil,
+		ic,
+	)
+	if err == nil {
+		t.Fatal("Expected provider.Diff to fail with invalid timeout value")
+	}
+	expectedErrMsg := `time: invalid duration "invalid"`
+	if !strings.Contains(err.Error(), expectedErrMsg) {
+		t.Fatalf("Unexpected error message: %q\nExpected message to contain %q",
+			err.Error(),
+			expectedErrMsg)
+	}
+}
+
+func TestProviderValidateResource(t *testing.T) {
+	cases := []struct {
+		P      *Provider
+		Type   string
+		Config map[string]interface{}
+		Err    bool
+	}{
+		{
+			P:      &Provider{},
+			Type:   "foo",
+			Config: nil,
+			Err:    true,
+		},
+
+		{
+			P: &Provider{
+				ResourcesMap: map[string]*Resource{
+					"foo": &Resource{},
+				},
+			},
+			Type:   "foo",
+			Config: nil,
+			Err:    false,
+		},
+	}
+
+	for i, tc := range cases {
+		c := terraform.NewResourceConfigRaw(tc.Config)
+		_, es := tc.P.ValidateResource(tc.Type, c)
+		if len(es) > 0 != tc.Err {
+			t.Fatalf("%d: %#v", i, es)
+		}
+	}
+}
+
+func TestProviderImportState_default(t *testing.T) {
+	p := &Provider{
+		ResourcesMap: map[string]*Resource{
+			"foo": &Resource{
+				Importer: &ResourceImporter{},
+			},
+		},
+	}
+
+	states, err := p.ImportState(&terraform.InstanceInfo{
+		Type: "foo",
+	}, "bar")
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if len(states) != 1 {
+		t.Fatalf("bad: %#v", states)
+	}
+	if states[0].ID != "bar" {
+		t.Fatalf("bad: %#v", states)
+	}
+}
+
+func TestProviderImportState_setsId(t *testing.T) {
+	var val string
+	stateFunc := func(d *ResourceData, meta interface{}) ([]*ResourceData, error) {
+		val = d.Id()
+		return []*ResourceData{d}, nil
+	}
+
+	p := &Provider{
+		ResourcesMap: map[string]*Resource{
+			"foo": &Resource{
+				Importer: &ResourceImporter{
+					State: stateFunc,
+				},
+			},
+		},
+	}
+
+	_, err := p.ImportState(&terraform.InstanceInfo{
+		Type: "foo",
+	}, "bar")
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if val != "bar" {
+		t.Fatal("should set id")
+	}
+}
+
+func TestProviderImportState_setsType(t *testing.T) {
+	var tVal string
+	stateFunc := func(d *ResourceData, meta interface{}) ([]*ResourceData, error) {
+		d.SetId("foo")
+		tVal = d.State().Ephemeral.Type
+		return []*ResourceData{d}, nil
+	}
+
+	p := &Provider{
+		ResourcesMap: map[string]*Resource{
+			"foo": &Resource{
+				Importer: &ResourceImporter{
+					State: stateFunc,
+				},
+			},
+		},
+	}
+
+	_, err := p.ImportState(&terraform.InstanceInfo{
+		Type: "foo",
+	}, "bar")
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if tVal != "foo" {
+		t.Fatal("should set type")
+	}
+}
+
+func TestProviderMeta(t *testing.T) {
+	p := new(Provider)
+	if v := p.Meta(); v != nil {
+		t.Fatalf("bad: %#v", v)
+	}
+
+	expected := 42
+	p.SetMeta(42)
+	if v := p.Meta(); !reflect.DeepEqual(v, expected) {
+		t.Fatalf("bad: %#v", v)
+	}
+}
+
+func TestProviderStop(t *testing.T) {
+	var p Provider
+
+	if p.Stopped() {
+		t.Fatal("should not be stopped")
+	}
+
+	// Verify stopch blocks
+	ch := p.StopContext().Done()
+	select {
+	case <-ch:
+		t.Fatal("should not be stopped")
+	case <-time.After(10 * time.Millisecond):
+	}
+
+	// Stop it
+	if err := p.Stop(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Verify
+	if !p.Stopped() {
+		t.Fatal("should be stopped")
+	}
+
+	select {
+	case <-ch:
+	case <-time.After(10 * time.Millisecond):
+		t.Fatal("should be stopped")
+	}
+}
+
+func TestProviderStop_stopFirst(t *testing.T) {
+	var p Provider
+
+	// Stop it
+	if err := p.Stop(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Verify
+	if !p.Stopped() {
+		t.Fatal("should be stopped")
+	}
+
+	select {
+	case <-p.StopContext().Done():
+	case <-time.After(10 * time.Millisecond):
+		t.Fatal("should be stopped")
+	}
+}
+
+func TestProviderReset(t *testing.T) {
+	var p Provider
+	stopCtx := p.StopContext()
+	p.MetaReset = func() error {
+		stopCtx = p.StopContext()
+		return nil
+	}
+
+	// cancel the current context
+	p.Stop()
+
+	if err := p.TestReset(); err != nil {
+		t.Fatal(err)
+	}
+
+	// the first context should have been replaced
+	if err := stopCtx.Err(); err != nil {
+		t.Fatal(err)
+	}
+
+	// we should not get a canceled context here either
+	if err := p.StopContext().Err(); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestProvider_InternalValidate(t *testing.T) {
+	cases := []struct {
+		P           *Provider
+		ExpectedErr error
+	}{
+		{
+			P: &Provider{
+				Schema: map[string]*Schema{
+					"foo": {
+						Type:     TypeBool,
+						Optional: true,
+					},
+				},
+			},
+			ExpectedErr: nil,
+		},
+		{ // Reserved resource fields should be allowed in provider block
+			P: &Provider{
+				Schema: map[string]*Schema{
+					"provisioner": {
+						Type:     TypeString,
+						Optional: true,
+					},
+					"count": {
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+			},
+			ExpectedErr: nil,
+		},
+		{ // Reserved provider fields should not be allowed
+			P: &Provider{
+				Schema: map[string]*Schema{
+					"alias": {
+						Type:     TypeString,
+						Optional: true,
+					},
+				},
+			},
+			ExpectedErr: fmt.Errorf("%s is a reserved field name for a provider", "alias"),
+		},
+	}
+
+	for i, tc := range cases {
+		err := tc.P.InternalValidate()
+		if tc.ExpectedErr == nil {
+			if err != nil {
+				t.Fatalf("%d: Error returned (expected no error): %s", i, err)
+			}
+			continue
+		}
+		if tc.ExpectedErr != nil && err == nil {
+			t.Fatalf("%d: Expected error (%s), but no error returned", i, tc.ExpectedErr)
+		}
+		if err.Error() != tc.ExpectedErr.Error() {
+			t.Fatalf("%d: Errors don't match. Expected: %#v Given: %#v", i, tc.ExpectedErr, err)
+		}
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/provisioner.go b/v1.5.7/internal/legacy/helper/schema/provisioner.go
new file mode 100644
index 0000000..02b1afc
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/provisioner.go
@@ -0,0 +1,208 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"sync"
+
+	"github.com/hashicorp/go-multierror"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+// Provisioner represents a resource provisioner in Terraform and properly
+// implements all of the ResourceProvisioner API.
+//
+// This higher level structure makes it much easier to implement a new or
+// custom provisioner for Terraform.
+//
+// The function callbacks for this structure are all passed a context object.
+// This context object has a number of pre-defined values that can be accessed
+// via the global functions defined in context.go.
+type Provisioner struct {
+	// ConnSchema is the schema for the connection settings for this
+	// provisioner.
+	//
+	// The keys of this map are the configuration keys, and the value is
+	// the schema describing the value of the configuration.
+	//
+	// NOTE: The value of connection keys can only be strings for now.
+	ConnSchema map[string]*Schema
+
+	// Schema is the schema for the usage of this provisioner.
+	//
+	// The keys of this map are the configuration keys, and the value is
+	// the schema describing the value of the configuration.
+	Schema map[string]*Schema
+
+	// ApplyFunc is the function for executing the provisioner. This is required.
+	// It is given a context. See the Provisioner struct docs for more
+	// information.
+	ApplyFunc func(ctx context.Context) error
+
+	// ValidateFunc is a function for extended validation. This is optional
+	// and should be used when individual field validation is not enough.
+	ValidateFunc func(*terraform.ResourceConfig) ([]string, []error)
+
+	stopCtx       context.Context
+	stopCtxCancel context.CancelFunc
+	stopOnce      sync.Once
+}
+
+// Keys that can be used to access data in the context parameters for
+// Provisioners.
+var (
+	connDataInvalid = contextKey("data invalid")
+
+	// This returns a *ResourceData for the connection information.
+	// Guaranteed to never be nil.
+	ProvConnDataKey = contextKey("provider conn data")
+
+	// This returns a *ResourceData for the config information.
+	// Guaranteed to never be nil.
+	ProvConfigDataKey = contextKey("provider config data")
+
+	// This returns a terraform.UIOutput. Guaranteed to never be nil.
+	ProvOutputKey = contextKey("provider output")
+
+	// This returns the raw InstanceState passed to Apply. Guaranteed to
+	// be set, but may be nil.
+	ProvRawStateKey = contextKey("provider raw state")
+)
+
+// InternalValidate should be called to validate the structure
+// of the provisioner.
+//
+// This should be called in a unit test to verify before release that this
+// structure is properly configured for use.
+func (p *Provisioner) InternalValidate() error {
+	if p == nil {
+		return errors.New("provisioner is nil")
+	}
+
+	var validationErrors error
+	{
+		sm := schemaMap(p.ConnSchema)
+		if err := sm.InternalValidate(sm); err != nil {
+			validationErrors = multierror.Append(validationErrors, err)
+		}
+	}
+
+	{
+		sm := schemaMap(p.Schema)
+		if err := sm.InternalValidate(sm); err != nil {
+			validationErrors = multierror.Append(validationErrors, err)
+		}
+	}
+
+	if p.ApplyFunc == nil {
+		validationErrors = multierror.Append(validationErrors, fmt.Errorf(
+			"ApplyFunc must not be nil"))
+	}
+
+	return validationErrors
+}
+
+// StopContext returns a context that checks whether a provisioner is stopped.
+func (p *Provisioner) StopContext() context.Context {
+	p.stopOnce.Do(p.stopInit)
+	return p.stopCtx
+}
+
+func (p *Provisioner) stopInit() {
+	p.stopCtx, p.stopCtxCancel = context.WithCancel(context.Background())
+}
+
+// Stop implementation of terraform.ResourceProvisioner interface.
+func (p *Provisioner) Stop() error {
+	p.stopOnce.Do(p.stopInit)
+	p.stopCtxCancel()
+	return nil
+}
+
+// GetConfigSchema implementation of terraform.ResourceProvisioner interface.
+func (p *Provisioner) GetConfigSchema() (*configschema.Block, error) {
+	return schemaMap(p.Schema).CoreConfigSchema(), nil
+}
+
+// Apply implementation of terraform.ResourceProvisioner interface.
+func (p *Provisioner) Apply(
+	o terraform.UIOutput,
+	s *terraform.InstanceState,
+	c *terraform.ResourceConfig) error {
+	var connData, configData *ResourceData
+
+	{
+		// We first need to turn the connection information into a
+		// terraform.ResourceConfig so that we can use that type to more
+		// easily build a ResourceData structure. We do this by simply treating
+		// the conn info as configuration input.
+		raw := make(map[string]interface{})
+		if s != nil {
+			for k, v := range s.Ephemeral.ConnInfo {
+				raw[k] = v
+			}
+		}
+
+		c := terraform.NewResourceConfigRaw(raw)
+		sm := schemaMap(p.ConnSchema)
+		diff, err := sm.Diff(nil, c, nil, nil, true)
+		if err != nil {
+			return err
+		}
+		connData, err = sm.Data(nil, diff)
+		if err != nil {
+			return err
+		}
+	}
+
+	{
+		// Build the configuration data. Doing this requires making a "diff"
+		// even though that's never used. We use that just to get the correct types.
+		configMap := schemaMap(p.Schema)
+		diff, err := configMap.Diff(nil, c, nil, nil, true)
+		if err != nil {
+			return err
+		}
+		configData, err = configMap.Data(nil, diff)
+		if err != nil {
+			return err
+		}
+	}
+
+	// Build the context and call the function
+	ctx := p.StopContext()
+	ctx = context.WithValue(ctx, ProvConnDataKey, connData)
+	ctx = context.WithValue(ctx, ProvConfigDataKey, configData)
+	ctx = context.WithValue(ctx, ProvOutputKey, o)
+	ctx = context.WithValue(ctx, ProvRawStateKey, s)
+	return p.ApplyFunc(ctx)
+}
+
+// Validate implements the terraform.ResourceProvisioner interface.
+func (p *Provisioner) Validate(c *terraform.ResourceConfig) (ws []string, es []error) {
+	if err := p.InternalValidate(); err != nil {
+		return nil, []error{fmt.Errorf(
+			"Internal validation of the provisioner failed! This is always a bug\n"+
+				"with the provisioner itself, and not a user issue. Please report\n"+
+				"this bug:\n\n%s", err)}
+	}
+
+	if p.Schema != nil {
+		w, e := schemaMap(p.Schema).Validate(c)
+		ws = append(ws, w...)
+		es = append(es, e...)
+	}
+
+	if p.ValidateFunc != nil {
+		w, e := p.ValidateFunc(c)
+		ws = append(ws, w...)
+		es = append(es, e...)
+	}
+
+	return ws, es
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/provisioner_test.go b/v1.5.7/internal/legacy/helper/schema/provisioner_test.go
new file mode 100644
index 0000000..a5a9318
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/provisioner_test.go
@@ -0,0 +1,337 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"context"
+	"fmt"
+	"reflect"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+func TestProvisioner_impl(t *testing.T) {
+	var _ terraform.ResourceProvisioner = new(Provisioner)
+}
+
+func noopApply(ctx context.Context) error {
+	return nil
+}
+
+func TestProvisionerValidate(t *testing.T) {
+	cases := []struct {
+		Name   string
+		P      *Provisioner
+		Config map[string]interface{}
+		Err    bool
+		Warns  []string
+	}{
+		{
+			Name:   "No ApplyFunc",
+			P:      &Provisioner{},
+			Config: nil,
+			Err:    true,
+		},
+		{
+			Name: "Incorrect schema",
+			P: &Provisioner{
+				Schema: map[string]*Schema{
+					"foo": {},
+				},
+				ApplyFunc: noopApply,
+			},
+			Config: nil,
+			Err:    true,
+		},
+		{
+			"Basic required field",
+			&Provisioner{
+				Schema: map[string]*Schema{
+					"foo": &Schema{
+						Required: true,
+						Type:     TypeString,
+					},
+				},
+				ApplyFunc: noopApply,
+			},
+			nil,
+			true,
+			nil,
+		},
+
+		{
+			"Basic required field set",
+			&Provisioner{
+				Schema: map[string]*Schema{
+					"foo": &Schema{
+						Required: true,
+						Type:     TypeString,
+					},
+				},
+				ApplyFunc: noopApply,
+			},
+			map[string]interface{}{
+				"foo": "bar",
+			},
+			false,
+			nil,
+		},
+		{
+			Name: "Warning from property validation",
+			P: &Provisioner{
+				Schema: map[string]*Schema{
+					"foo": {
+						Type:     TypeString,
+						Optional: true,
+						ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
+							ws = append(ws, "Simple warning from property validation")
+							return
+						},
+					},
+				},
+				ApplyFunc: noopApply,
+			},
+			Config: map[string]interface{}{
+				"foo": "",
+			},
+			Err:   false,
+			Warns: []string{"Simple warning from property validation"},
+		},
+		{
+			Name: "No schema",
+			P: &Provisioner{
+				Schema:    nil,
+				ApplyFunc: noopApply,
+			},
+			Config: nil,
+			Err:    false,
+		},
+		{
+			Name: "Warning from provisioner ValidateFunc",
+			P: &Provisioner{
+				Schema:    nil,
+				ApplyFunc: noopApply,
+				ValidateFunc: func(*terraform.ResourceConfig) (ws []string, errors []error) {
+					ws = append(ws, "Simple warning from provisioner ValidateFunc")
+					return
+				},
+			},
+			Config: nil,
+			Err:    false,
+			Warns:  []string{"Simple warning from provisioner ValidateFunc"},
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			c := terraform.NewResourceConfigRaw(tc.Config)
+			ws, es := tc.P.Validate(c)
+			if len(es) > 0 != tc.Err {
+				t.Fatalf("%d: %#v %s", i, es, es)
+			}
+			if (tc.Warns != nil || len(ws) != 0) && !reflect.DeepEqual(ws, tc.Warns) {
+				t.Fatalf("%d: warnings mismatch, actual: %#v", i, ws)
+			}
+		})
+	}
+}
+
+func TestProvisionerApply(t *testing.T) {
+	cases := []struct {
+		Name   string
+		P      *Provisioner
+		Conn   map[string]string
+		Config map[string]interface{}
+		Err    bool
+	}{
+		{
+			"Basic config",
+			&Provisioner{
+				ConnSchema: map[string]*Schema{
+					"foo": &Schema{
+						Type:     TypeString,
+						Optional: true,
+					},
+				},
+
+				Schema: map[string]*Schema{
+					"foo": &Schema{
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+
+				ApplyFunc: func(ctx context.Context) error {
+					cd := ctx.Value(ProvConnDataKey).(*ResourceData)
+					d := ctx.Value(ProvConfigDataKey).(*ResourceData)
+					if d.Get("foo").(int) != 42 {
+						return fmt.Errorf("bad config data")
+					}
+					if cd.Get("foo").(string) != "bar" {
+						return fmt.Errorf("bad conn data")
+					}
+
+					return nil
+				},
+			},
+			map[string]string{
+				"foo": "bar",
+			},
+			map[string]interface{}{
+				"foo": 42,
+			},
+			false,
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			c := terraform.NewResourceConfigRaw(tc.Config)
+
+			state := &terraform.InstanceState{
+				Ephemeral: terraform.EphemeralState{
+					ConnInfo: tc.Conn,
+				},
+			}
+
+			err := tc.P.Apply(nil, state, c)
+			if err != nil != tc.Err {
+				t.Fatalf("%d: %s", i, err)
+			}
+		})
+	}
+}
+
+func TestProvisionerApply_nilState(t *testing.T) {
+	p := &Provisioner{
+		ConnSchema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeString,
+				Optional: true,
+			},
+		},
+
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+
+		ApplyFunc: func(ctx context.Context) error {
+			return nil
+		},
+	}
+
+	conf := map[string]interface{}{
+		"foo": 42,
+	}
+
+	c := terraform.NewResourceConfigRaw(conf)
+	err := p.Apply(nil, nil, c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+}
+
+func TestProvisionerStop(t *testing.T) {
+	var p Provisioner
+
+	// Verify stopch blocks
+	ch := p.StopContext().Done()
+	select {
+	case <-ch:
+		t.Fatal("should not be stopped")
+	case <-time.After(10 * time.Millisecond):
+	}
+
+	// Stop it
+	if err := p.Stop(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	select {
+	case <-ch:
+	case <-time.After(10 * time.Millisecond):
+		t.Fatal("should be stopped")
+	}
+}
+
+func TestProvisionerStop_apply(t *testing.T) {
+	p := &Provisioner{
+		ConnSchema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeString,
+				Optional: true,
+			},
+		},
+
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+
+		ApplyFunc: func(ctx context.Context) error {
+			<-ctx.Done()
+			return nil
+		},
+	}
+
+	conn := map[string]string{
+		"foo": "bar",
+	}
+
+	conf := map[string]interface{}{
+		"foo": 42,
+	}
+
+	c := terraform.NewResourceConfigRaw(conf)
+	state := &terraform.InstanceState{
+		Ephemeral: terraform.EphemeralState{
+			ConnInfo: conn,
+		},
+	}
+
+	// Run the apply in a goroutine
+	doneCh := make(chan struct{})
+	go func() {
+		p.Apply(nil, state, c)
+		close(doneCh)
+	}()
+
+	// Should block
+	select {
+	case <-doneCh:
+		t.Fatal("should not be done")
+	case <-time.After(10 * time.Millisecond):
+	}
+
+	// Stop!
+	p.Stop()
+
+	select {
+	case <-doneCh:
+	case <-time.After(10 * time.Millisecond):
+		t.Fatal("should be done")
+	}
+}
+
+func TestProvisionerStop_stopFirst(t *testing.T) {
+	var p Provisioner
+
+	// Stop it
+	if err := p.Stop(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	select {
+	case <-p.StopContext().Done():
+	case <-time.After(10 * time.Millisecond):
+		t.Fatal("should be stopped")
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/resource.go b/v1.5.7/internal/legacy/helper/schema/resource.go
new file mode 100644
index 0000000..5cd468e
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/resource.go
@@ -0,0 +1,845 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"errors"
+	"fmt"
+	"log"
+	"strconv"
+
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+	"github.com/zclconf/go-cty/cty"
+)
+
+var ReservedDataSourceFields = []string{
+	"connection",
+	"count",
+	"depends_on",
+	"lifecycle",
+	"provider",
+	"provisioner",
+}
+
+var ReservedResourceFields = []string{
+	"connection",
+	"count",
+	"depends_on",
+	"id",
+	"lifecycle",
+	"provider",
+	"provisioner",
+}
+
+// Resource represents a thing in Terraform that has a set of configurable
+// attributes and a lifecycle (create, read, update, delete).
+//
+// The Resource schema is an abstraction that allows provider writers to
+// worry only about CRUD operations while off-loading validation, diff
+// generation, etc. to this higher level library.
+//
+// In spite of the name, this struct is not used only for terraform resources,
+// but also for data sources. In the case of data sources, the Create,
+// Update and Delete functions must not be provided.
+type Resource struct {
+	// Schema is the schema for the configuration of this resource.
+	//
+	// The keys of this map are the configuration keys, and the values
+	// describe the schema of the configuration value.
+	//
+	// The schema is used to represent both configurable data as well
+	// as data that might be computed in the process of creating this
+	// resource.
+	Schema map[string]*Schema
+
+	// SchemaVersion is the version number for this resource's Schema
+	// definition. The current SchemaVersion stored in the state for each
+	// resource. Provider authors can increment this version number
+	// when Schema semantics change. If the State's SchemaVersion is less than
+	// the current SchemaVersion, the InstanceState is yielded to the
+	// MigrateState callback, where the provider can make whatever changes it
+	// needs to update the state to be compatible to the latest version of the
+	// Schema.
+	//
+	// When unset, SchemaVersion defaults to 0, so provider authors can start
+	// their Versioning at any integer >= 1
+	SchemaVersion int
+
+	// MigrateState is deprecated and any new changes to a resource's schema
+	// should be handled by StateUpgraders. Existing MigrateState implementations
+	// should remain for compatibility with existing state. MigrateState will
+	// still be called if the stored SchemaVersion is less than the
+	// first version of the StateUpgraders.
+	//
+	// MigrateState is responsible for updating an InstanceState with an old
+	// version to the format expected by the current version of the Schema.
+	//
+	// It is called during Refresh if the State's stored SchemaVersion is less
+	// than the current SchemaVersion of the Resource.
+	//
+	// The function is yielded the state's stored SchemaVersion and a pointer to
+	// the InstanceState that needs updating, as well as the configured
+	// provider's configured meta interface{}, in case the migration process
+	// needs to make any remote API calls.
+	MigrateState StateMigrateFunc
+
+	// StateUpgraders contains the functions responsible for upgrading an
+	// existing state with an old schema version to a newer schema. It is
+	// called specifically by Terraform when the stored schema version is less
+	// than the current SchemaVersion of the Resource.
+	//
+	// StateUpgraders map specific schema versions to a StateUpgrader
+	// function. The registered versions are expected to be ordered,
+	// consecutive values. The initial value may be greater than 0 to account
+	// for legacy schemas that weren't recorded and can be handled by
+	// MigrateState.
+	StateUpgraders []StateUpgrader
+
+	// The functions below are the CRUD operations for this resource.
+	//
+	// The only optional operation is Update. If Update is not implemented,
+	// then updates will not be supported for this resource.
+	//
+	// The ResourceData parameter in the functions below are used to
+	// query configuration and changes for the resource as well as to set
+	// the ID, computed data, etc.
+	//
+	// The interface{} parameter is the result of the ConfigureFunc in
+	// the provider for this resource. If the provider does not define
+	// a ConfigureFunc, this will be nil. This parameter should be used
+	// to store API clients, configuration structures, etc.
+	//
+	// If any errors occur during each of the operation, an error should be
+	// returned. If a resource was partially updated, be careful to enable
+	// partial state mode for ResourceData and use it accordingly.
+	//
+	// Exists is a function that is called to check if a resource still
+	// exists. If this returns false, then this will affect the diff
+	// accordingly. If this function isn't set, it will not be called. You
+	// can also signal existence in the Read method by calling d.SetId("")
+	// if the Resource is no longer present and should be removed from state.
+	// The *ResourceData passed to Exists should _not_ be modified.
+	Create CreateFunc
+	Read   ReadFunc
+	Update UpdateFunc
+	Delete DeleteFunc
+	Exists ExistsFunc
+
+	// CustomizeDiff is a custom function for working with the diff that
+	// Terraform has created for this resource - it can be used to customize the
+	// diff that has been created, diff values not controlled by configuration,
+	// or even veto the diff altogether and abort the plan. It is passed a
+	// *ResourceDiff, a structure similar to ResourceData but lacking most write
+	// functions like Set, while introducing new functions that work with the
+	// diff such as SetNew, SetNewComputed, and ForceNew.
+	//
+	// The phases Terraform runs this in, and the state available via functions
+	// like Get and GetChange, are as follows:
+	//
+	//  * New resource: One run with no state
+	//  * Existing resource: One run with state
+	//   * Existing resource, forced new: One run with state (before ForceNew),
+	//     then one run without state (as if new resource)
+	//  * Tainted resource: No runs (custom diff logic is skipped)
+	//  * Destroy: No runs (standard diff logic is skipped on destroy diffs)
+	//
+	// This function needs to be resilient to support all scenarios.
+	//
+	// If this function needs to access external API resources, remember to flag
+	// the RequiresRefresh attribute mentioned below to ensure that
+	// -refresh=false is blocked when running plan or apply, as this means that
+	// this resource requires refresh-like behaviour to work effectively.
+	//
+	// For the most part, only computed fields can be customized by this
+	// function.
+	//
+	// This function is only allowed on regular resources (not data sources).
+	CustomizeDiff CustomizeDiffFunc
+
+	// Importer is the ResourceImporter implementation for this resource.
+	// If this is nil, then this resource does not support importing. If
+	// this is non-nil, then it supports importing and ResourceImporter
+	// must be validated. The validity of ResourceImporter is verified
+	// by InternalValidate on Resource.
+	Importer *ResourceImporter
+
+	// If non-empty, this string is emitted as a warning during Validate.
+	DeprecationMessage string
+
+	// Timeouts allow users to specify specific time durations in which an
+	// operation should time out, to allow them to extend an action to suit their
+	// usage. For example, a user may specify a large Creation timeout for their
+	// AWS RDS Instance due to it's size, or restoring from a snapshot.
+	// Resource implementors must enable Timeout support by adding the allowed
+	// actions (Create, Read, Update, Delete, Default) to the Resource struct, and
+	// accessing them in the matching methods.
+	Timeouts *ResourceTimeout
+}
+
+// ShimInstanceStateFromValue converts a cty.Value to a
+// terraform.InstanceState.
+func (r *Resource) ShimInstanceStateFromValue(state cty.Value) (*terraform.InstanceState, error) {
+	// Get the raw shimmed value. While this is correct, the set hashes don't
+	// match those from the Schema.
+	s := terraform.NewInstanceStateShimmedFromValue(state, r.SchemaVersion)
+
+	// We now rebuild the state through the ResourceData, so that the set indexes
+	// match what helper/schema expects.
+	data, err := schemaMap(r.Schema).Data(s, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	s = data.State()
+	if s == nil {
+		s = &terraform.InstanceState{}
+	}
+	return s, nil
+}
+
+// See Resource documentation.
+type CreateFunc func(*ResourceData, interface{}) error
+
+// See Resource documentation.
+type ReadFunc func(*ResourceData, interface{}) error
+
+// See Resource documentation.
+type UpdateFunc func(*ResourceData, interface{}) error
+
+// See Resource documentation.
+type DeleteFunc func(*ResourceData, interface{}) error
+
+// See Resource documentation.
+type ExistsFunc func(*ResourceData, interface{}) (bool, error)
+
+// See Resource documentation.
+type StateMigrateFunc func(
+	int, *terraform.InstanceState, interface{}) (*terraform.InstanceState, error)
+
+type StateUpgrader struct {
+	// Version is the version schema that this Upgrader will handle, converting
+	// it to Version+1.
+	Version int
+
+	// Type describes the schema that this function can upgrade. Type is
+	// required to decode the schema if the state was stored in a legacy
+	// flatmap format.
+	Type cty.Type
+
+	// Upgrade takes the JSON encoded state and the provider meta value, and
+	// upgrades the state one single schema version. The provided state is
+	// deocded into the default json types using a map[string]interface{}. It
+	// is up to the StateUpgradeFunc to ensure that the returned value can be
+	// encoded using the new schema.
+	Upgrade StateUpgradeFunc
+}
+
+// See StateUpgrader
+type StateUpgradeFunc func(rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error)
+
+// See Resource documentation.
+type CustomizeDiffFunc func(*ResourceDiff, interface{}) error
+
+// Apply creates, updates, and/or deletes a resource.
+func (r *Resource) Apply(
+	s *terraform.InstanceState,
+	d *terraform.InstanceDiff,
+	meta interface{}) (*terraform.InstanceState, error) {
+	data, err := schemaMap(r.Schema).Data(s, d)
+	if err != nil {
+		return s, err
+	}
+	if s != nil && data != nil {
+		data.providerMeta = s.ProviderMeta
+	}
+
+	// Instance Diff shoould have the timeout info, need to copy it over to the
+	// ResourceData meta
+	rt := ResourceTimeout{}
+	if _, ok := d.Meta[TimeoutKey]; ok {
+		if err := rt.DiffDecode(d); err != nil {
+			log.Printf("[ERR] Error decoding ResourceTimeout: %s", err)
+		}
+	} else if s != nil {
+		if _, ok := s.Meta[TimeoutKey]; ok {
+			if err := rt.StateDecode(s); err != nil {
+				log.Printf("[ERR] Error decoding ResourceTimeout: %s", err)
+			}
+		}
+	} else {
+		log.Printf("[DEBUG] No meta timeoutkey found in Apply()")
+	}
+	data.timeouts = &rt
+
+	if s == nil {
+		// The Terraform API dictates that this should never happen, but
+		// it doesn't hurt to be safe in this case.
+		s = new(terraform.InstanceState)
+	}
+
+	if d.Destroy || d.RequiresNew() {
+		if s.ID != "" {
+			// Destroy the resource since it is created
+			if err := r.Delete(data, meta); err != nil {
+				return r.recordCurrentSchemaVersion(data.State()), err
+			}
+
+			// Make sure the ID is gone.
+			data.SetId("")
+		}
+
+		// If we're only destroying, and not creating, then return
+		// now since we're done!
+		if !d.RequiresNew() {
+			return nil, nil
+		}
+
+		// Reset the data to be stateless since we just destroyed
+		data, err = schemaMap(r.Schema).Data(nil, d)
+		// data was reset, need to re-apply the parsed timeouts
+		data.timeouts = &rt
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	err = nil
+	if data.Id() == "" {
+		// We're creating, it is a new resource.
+		data.MarkNewResource()
+		err = r.Create(data, meta)
+	} else {
+		if r.Update == nil {
+			return s, fmt.Errorf("doesn't support update")
+		}
+
+		err = r.Update(data, meta)
+	}
+
+	return r.recordCurrentSchemaVersion(data.State()), err
+}
+
+// Diff returns a diff of this resource.
+func (r *Resource) Diff(
+	s *terraform.InstanceState,
+	c *terraform.ResourceConfig,
+	meta interface{}) (*terraform.InstanceDiff, error) {
+
+	t := &ResourceTimeout{}
+	err := t.ConfigDecode(r, c)
+
+	if err != nil {
+		return nil, fmt.Errorf("[ERR] Error decoding timeout: %s", err)
+	}
+
+	instanceDiff, err := schemaMap(r.Schema).Diff(s, c, r.CustomizeDiff, meta, true)
+	if err != nil {
+		return instanceDiff, err
+	}
+
+	if instanceDiff != nil {
+		if err := t.DiffEncode(instanceDiff); err != nil {
+			log.Printf("[ERR] Error encoding timeout to instance diff: %s", err)
+		}
+	} else {
+		log.Printf("[DEBUG] Instance Diff is nil in Diff()")
+	}
+
+	return instanceDiff, err
+}
+
+func (r *Resource) simpleDiff(
+	s *terraform.InstanceState,
+	c *terraform.ResourceConfig,
+	meta interface{}) (*terraform.InstanceDiff, error) {
+
+	instanceDiff, err := schemaMap(r.Schema).Diff(s, c, r.CustomizeDiff, meta, false)
+	if err != nil {
+		return instanceDiff, err
+	}
+
+	if instanceDiff == nil {
+		instanceDiff = terraform.NewInstanceDiff()
+	}
+
+	// Make sure the old value is set in each of the instance diffs.
+	// This was done by the RequiresNew logic in the full legacy Diff.
+	for k, attr := range instanceDiff.Attributes {
+		if attr == nil {
+			continue
+		}
+		if s != nil {
+			attr.Old = s.Attributes[k]
+		}
+	}
+
+	return instanceDiff, nil
+}
+
+// Validate validates the resource configuration against the schema.
+func (r *Resource) Validate(c *terraform.ResourceConfig) ([]string, []error) {
+	warns, errs := schemaMap(r.Schema).Validate(c)
+
+	if r.DeprecationMessage != "" {
+		warns = append(warns, r.DeprecationMessage)
+	}
+
+	return warns, errs
+}
+
+// ReadDataApply loads the data for a data source, given a diff that
+// describes the configuration arguments and desired computed attributes.
+func (r *Resource) ReadDataApply(
+	d *terraform.InstanceDiff,
+	meta interface{},
+) (*terraform.InstanceState, error) {
+	// Data sources are always built completely from scratch
+	// on each read, so the source state is always nil.
+	data, err := schemaMap(r.Schema).Data(nil, d)
+	if err != nil {
+		return nil, err
+	}
+
+	err = r.Read(data, meta)
+	state := data.State()
+	if state != nil && state.ID == "" {
+		// Data sources can set an ID if they want, but they aren't
+		// required to; we'll provide a placeholder if they don't,
+		// to preserve the invariant that all resources have non-empty
+		// ids.
+		state.ID = "-"
+	}
+
+	return r.recordCurrentSchemaVersion(state), err
+}
+
+// RefreshWithoutUpgrade reads the instance state, but does not call
+// MigrateState or the StateUpgraders, since those are now invoked in a
+// separate API call.
+// RefreshWithoutUpgrade is part of the new plugin shims.
+func (r *Resource) RefreshWithoutUpgrade(
+	s *terraform.InstanceState,
+	meta interface{}) (*terraform.InstanceState, error) {
+	// If the ID is already somehow blank, it doesn't exist
+	if s.ID == "" {
+		return nil, nil
+	}
+
+	rt := ResourceTimeout{}
+	if _, ok := s.Meta[TimeoutKey]; ok {
+		if err := rt.StateDecode(s); err != nil {
+			log.Printf("[ERR] Error decoding ResourceTimeout: %s", err)
+		}
+	}
+
+	if r.Exists != nil {
+		// Make a copy of data so that if it is modified it doesn't
+		// affect our Read later.
+		data, err := schemaMap(r.Schema).Data(s, nil)
+		data.timeouts = &rt
+
+		if err != nil {
+			return s, err
+		}
+
+		if s != nil {
+			data.providerMeta = s.ProviderMeta
+		}
+
+		exists, err := r.Exists(data, meta)
+		if err != nil {
+			return s, err
+		}
+		if !exists {
+			return nil, nil
+		}
+	}
+
+	data, err := schemaMap(r.Schema).Data(s, nil)
+	data.timeouts = &rt
+	if err != nil {
+		return s, err
+	}
+
+	if s != nil {
+		data.providerMeta = s.ProviderMeta
+	}
+
+	err = r.Read(data, meta)
+	state := data.State()
+	if state != nil && state.ID == "" {
+		state = nil
+	}
+
+	return r.recordCurrentSchemaVersion(state), err
+}
+
+// Refresh refreshes the state of the resource.
+func (r *Resource) Refresh(
+	s *terraform.InstanceState,
+	meta interface{}) (*terraform.InstanceState, error) {
+	// If the ID is already somehow blank, it doesn't exist
+	if s.ID == "" {
+		return nil, nil
+	}
+
+	rt := ResourceTimeout{}
+	if _, ok := s.Meta[TimeoutKey]; ok {
+		if err := rt.StateDecode(s); err != nil {
+			log.Printf("[ERR] Error decoding ResourceTimeout: %s", err)
+		}
+	}
+
+	if r.Exists != nil {
+		// Make a copy of data so that if it is modified it doesn't
+		// affect our Read later.
+		data, err := schemaMap(r.Schema).Data(s, nil)
+		data.timeouts = &rt
+
+		if err != nil {
+			return s, err
+		}
+
+		exists, err := r.Exists(data, meta)
+		if err != nil {
+			return s, err
+		}
+		if !exists {
+			return nil, nil
+		}
+	}
+
+	// there may be new StateUpgraders that need to be run
+	s, err := r.upgradeState(s, meta)
+	if err != nil {
+		return s, err
+	}
+
+	data, err := schemaMap(r.Schema).Data(s, nil)
+	data.timeouts = &rt
+	if err != nil {
+		return s, err
+	}
+
+	err = r.Read(data, meta)
+	state := data.State()
+	if state != nil && state.ID == "" {
+		state = nil
+	}
+
+	return r.recordCurrentSchemaVersion(state), err
+}
+
+func (r *Resource) upgradeState(s *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
+	var err error
+
+	needsMigration, stateSchemaVersion := r.checkSchemaVersion(s)
+	migrate := needsMigration && r.MigrateState != nil
+
+	if migrate {
+		s, err = r.MigrateState(stateSchemaVersion, s, meta)
+		if err != nil {
+			return s, err
+		}
+	}
+
+	if len(r.StateUpgraders) == 0 {
+		return s, nil
+	}
+
+	// If we ran MigrateState, then the stateSchemaVersion value is no longer
+	// correct. We can expect the first upgrade function to be the correct
+	// schema type version.
+	if migrate {
+		stateSchemaVersion = r.StateUpgraders[0].Version
+	}
+
+	schemaType := r.CoreConfigSchema().ImpliedType()
+	// find the expected type to convert the state
+	for _, upgrader := range r.StateUpgraders {
+		if stateSchemaVersion == upgrader.Version {
+			schemaType = upgrader.Type
+		}
+	}
+
+	// StateUpgraders only operate on the new JSON format state, so the state
+	// need to be converted.
+	stateVal, err := StateValueFromInstanceState(s, schemaType)
+	if err != nil {
+		return nil, err
+	}
+
+	jsonState, err := StateValueToJSONMap(stateVal, schemaType)
+	if err != nil {
+		return nil, err
+	}
+
+	for _, upgrader := range r.StateUpgraders {
+		if stateSchemaVersion != upgrader.Version {
+			continue
+		}
+
+		jsonState, err = upgrader.Upgrade(jsonState, meta)
+		if err != nil {
+			return nil, err
+		}
+		stateSchemaVersion++
+	}
+
+	// now we need to re-flatmap the new state
+	stateVal, err = JSONMapToStateValue(jsonState, r.CoreConfigSchema())
+	if err != nil {
+		return nil, err
+	}
+
+	return r.ShimInstanceStateFromValue(stateVal)
+}
+
+// InternalValidate should be called to validate the structure
+// of the resource.
+//
+// This should be called in a unit test for any resource to verify
+// before release that a resource is properly configured for use with
+// this library.
+//
+// Provider.InternalValidate() will automatically call this for all of
+// the resources it manages, so you don't need to call this manually if it
+// is part of a Provider.
+func (r *Resource) InternalValidate(topSchemaMap schemaMap, writable bool) error {
+	if r == nil {
+		return errors.New("resource is nil")
+	}
+
+	if !writable {
+		if r.Create != nil || r.Update != nil || r.Delete != nil {
+			return fmt.Errorf("must not implement Create, Update or Delete")
+		}
+
+		// CustomizeDiff cannot be defined for read-only resources
+		if r.CustomizeDiff != nil {
+			return fmt.Errorf("cannot implement CustomizeDiff")
+		}
+	}
+
+	tsm := topSchemaMap
+
+	if r.isTopLevel() && writable {
+		// All non-Computed attributes must be ForceNew if Update is not defined
+		if r.Update == nil {
+			nonForceNewAttrs := make([]string, 0)
+			for k, v := range r.Schema {
+				if !v.ForceNew && !v.Computed {
+					nonForceNewAttrs = append(nonForceNewAttrs, k)
+				}
+			}
+			if len(nonForceNewAttrs) > 0 {
+				return fmt.Errorf(
+					"No Update defined, must set ForceNew on: %#v", nonForceNewAttrs)
+			}
+		} else {
+			nonUpdateableAttrs := make([]string, 0)
+			for k, v := range r.Schema {
+				if v.ForceNew || v.Computed && !v.Optional {
+					nonUpdateableAttrs = append(nonUpdateableAttrs, k)
+				}
+			}
+			updateableAttrs := len(r.Schema) - len(nonUpdateableAttrs)
+			if updateableAttrs == 0 {
+				return fmt.Errorf(
+					"All fields are ForceNew or Computed w/out Optional, Update is superfluous")
+			}
+		}
+
+		tsm = schemaMap(r.Schema)
+
+		// Destroy, and Read are required
+		if r.Read == nil {
+			return fmt.Errorf("Read must be implemented")
+		}
+		if r.Delete == nil {
+			return fmt.Errorf("Delete must be implemented")
+		}
+
+		// If we have an importer, we need to verify the importer.
+		if r.Importer != nil {
+			if err := r.Importer.InternalValidate(); err != nil {
+				return err
+			}
+		}
+
+		for k, f := range tsm {
+			if isReservedResourceFieldName(k, f) {
+				return fmt.Errorf("%s is a reserved field name", k)
+			}
+		}
+	}
+
+	lastVersion := -1
+	for _, u := range r.StateUpgraders {
+		if lastVersion >= 0 && u.Version-lastVersion > 1 {
+			return fmt.Errorf("missing schema version between %d and %d", lastVersion, u.Version)
+		}
+
+		if u.Version >= r.SchemaVersion {
+			return fmt.Errorf("StateUpgrader version %d is >= current version %d", u.Version, r.SchemaVersion)
+		}
+
+		if !u.Type.IsObjectType() {
+			return fmt.Errorf("StateUpgrader %d type is not cty.Object", u.Version)
+		}
+
+		if u.Upgrade == nil {
+			return fmt.Errorf("StateUpgrader %d missing StateUpgradeFunc", u.Version)
+		}
+
+		lastVersion = u.Version
+	}
+
+	if lastVersion >= 0 && lastVersion != r.SchemaVersion-1 {
+		return fmt.Errorf("missing StateUpgrader between %d and %d", lastVersion, r.SchemaVersion)
+	}
+
+	// Data source
+	if r.isTopLevel() && !writable {
+		tsm = schemaMap(r.Schema)
+		for k, _ := range tsm {
+			if isReservedDataSourceFieldName(k) {
+				return fmt.Errorf("%s is a reserved field name", k)
+			}
+		}
+	}
+
+	return schemaMap(r.Schema).InternalValidate(tsm)
+}
+
+func isReservedDataSourceFieldName(name string) bool {
+	for _, reservedName := range ReservedDataSourceFields {
+		if name == reservedName {
+			return true
+		}
+	}
+	return false
+}
+
+func isReservedResourceFieldName(name string, s *Schema) bool {
+	// Allow phasing out "id"
+	// See https://github.com/terraform-providers/terraform-provider-aws/pull/1626#issuecomment-328881415
+	if name == "id" && (s.Deprecated != "" || s.Removed != "") {
+		return false
+	}
+
+	for _, reservedName := range ReservedResourceFields {
+		if name == reservedName {
+			return true
+		}
+	}
+	return false
+}
+
+// Data returns a ResourceData struct for this Resource. Each return value
+// is a separate copy and can be safely modified differently.
+//
+// The data returned from this function has no actual affect on the Resource
+// itself (including the state given to this function).
+//
+// This function is useful for unit tests and ResourceImporter functions.
+func (r *Resource) Data(s *terraform.InstanceState) *ResourceData {
+	result, err := schemaMap(r.Schema).Data(s, nil)
+	if err != nil {
+		// At the time of writing, this isn't possible (Data never returns
+		// non-nil errors). We panic to find this in the future if we have to.
+		// I don't see a reason for Data to ever return an error.
+		panic(err)
+	}
+
+	// load the Resource timeouts
+	result.timeouts = r.Timeouts
+	if result.timeouts == nil {
+		result.timeouts = &ResourceTimeout{}
+	}
+
+	// Set the schema version to latest by default
+	result.meta = map[string]interface{}{
+		"schema_version": strconv.Itoa(r.SchemaVersion),
+	}
+
+	return result
+}
+
+// TestResourceData Yields a ResourceData filled with this resource's schema for use in unit testing
+//
+// TODO: May be able to be removed with the above ResourceData function.
+func (r *Resource) TestResourceData() *ResourceData {
+	return &ResourceData{
+		schema: r.Schema,
+	}
+}
+
+// SchemasForFlatmapPath tries its best to find a sequence of schemas that
+// the given dot-delimited attribute path traverses through in the schema
+// of the receiving Resource.
+func (r *Resource) SchemasForFlatmapPath(path string) []*Schema {
+	return SchemasForFlatmapPath(path, r.Schema)
+}
+
+// Returns true if the resource is "top level" i.e. not a sub-resource.
+func (r *Resource) isTopLevel() bool {
+	// TODO: This is a heuristic; replace with a definitive attribute?
+	return (r.Create != nil || r.Read != nil)
+}
+
+// Determines if a given InstanceState needs to be migrated by checking the
+// stored version number with the current SchemaVersion
+func (r *Resource) checkSchemaVersion(is *terraform.InstanceState) (bool, int) {
+	// Get the raw interface{} value for the schema version. If it doesn't
+	// exist or is nil then set it to zero.
+	raw := is.Meta["schema_version"]
+	if raw == nil {
+		raw = "0"
+	}
+
+	// Try to convert it to a string. If it isn't a string then we pretend
+	// that it isn't set at all. It should never not be a string unless it
+	// was manually tampered with.
+	rawString, ok := raw.(string)
+	if !ok {
+		rawString = "0"
+	}
+
+	stateSchemaVersion, _ := strconv.Atoi(rawString)
+
+	// Don't run MigrateState if the version is handled by a StateUpgrader,
+	// since StateMigrateFuncs are not required to handle unknown versions
+	maxVersion := r.SchemaVersion
+	if len(r.StateUpgraders) > 0 {
+		maxVersion = r.StateUpgraders[0].Version
+	}
+
+	return stateSchemaVersion < maxVersion, stateSchemaVersion
+}
+
+func (r *Resource) recordCurrentSchemaVersion(
+	state *terraform.InstanceState) *terraform.InstanceState {
+	if state != nil && r.SchemaVersion > 0 {
+		if state.Meta == nil {
+			state.Meta = make(map[string]interface{})
+		}
+		state.Meta["schema_version"] = strconv.Itoa(r.SchemaVersion)
+	}
+	return state
+}
+
+// Noop is a convenience implementation of resource function which takes
+// no action and returns no error.
+func Noop(*ResourceData, interface{}) error {
+	return nil
+}
+
+// RemoveFromState is a convenience implementation of a resource function
+// which sets the resource ID to empty string (to remove it from state)
+// and returns no error.
+func RemoveFromState(d *ResourceData, _ interface{}) error {
+	d.SetId("")
+	return nil
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/resource_data.go b/v1.5.7/internal/legacy/helper/schema/resource_data.go
new file mode 100644
index 0000000..e3f393b
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/resource_data.go
@@ -0,0 +1,564 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"log"
+	"reflect"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/gocty"
+)
+
+// ResourceData is used to query and set the attributes of a resource.
+//
+// ResourceData is the primary argument received for CRUD operations on
+// a resource as well as configuration of a provider. It is a powerful
+// structure that can be used to not only query data, but check for changes,
+// define partial state updates, etc.
+//
+// The most relevant methods to take a look at are Get, Set, and Partial.
+type ResourceData struct {
+	// Settable (internally)
+	schema       map[string]*Schema
+	config       *terraform.ResourceConfig
+	state        *terraform.InstanceState
+	diff         *terraform.InstanceDiff
+	meta         map[string]interface{}
+	timeouts     *ResourceTimeout
+	providerMeta cty.Value
+
+	// Don't set
+	multiReader *MultiLevelFieldReader
+	setWriter   *MapFieldWriter
+	newState    *terraform.InstanceState
+	partial     bool
+	partialMap  map[string]struct{}
+	once        sync.Once
+	isNew       bool
+
+	panicOnError bool
+}
+
+// getResult is the internal structure that is generated when a Get
+// is called that contains some extra data that might be used.
+type getResult struct {
+	Value          interface{}
+	ValueProcessed interface{}
+	Computed       bool
+	Exists         bool
+	Schema         *Schema
+}
+
+// UnsafeSetFieldRaw allows setting arbitrary values in state to arbitrary
+// values, bypassing schema. This MUST NOT be used in normal circumstances -
+// it exists only to support the remote_state data source.
+//
+// Deprecated: Fully define schema attributes and use Set() instead.
+func (d *ResourceData) UnsafeSetFieldRaw(key string, value string) {
+	d.once.Do(d.init)
+
+	d.setWriter.unsafeWriteField(key, value)
+}
+
+// Get returns the data for the given key, or nil if the key doesn't exist
+// in the schema.
+//
+// If the key does exist in the schema but doesn't exist in the configuration,
+// then the default value for that type will be returned. For strings, this is
+// "", for numbers it is 0, etc.
+//
+// If you want to test if something is set at all in the configuration,
+// use GetOk.
+func (d *ResourceData) Get(key string) interface{} {
+	v, _ := d.GetOk(key)
+	return v
+}
+
+// GetChange returns the old and new value for a given key.
+//
+// HasChange should be used to check if a change exists. It is possible
+// that both the old and new value are the same if the old value was not
+// set and the new value is. This is common, for example, for boolean
+// fields which have a zero value of false.
+func (d *ResourceData) GetChange(key string) (interface{}, interface{}) {
+	o, n := d.getChange(key, getSourceState, getSourceDiff)
+	return o.Value, n.Value
+}
+
+// GetOk returns the data for the given key and whether or not the key
+// has been set to a non-zero value at some point.
+//
+// The first result will not necessarilly be nil if the value doesn't exist.
+// The second result should be checked to determine this information.
+func (d *ResourceData) GetOk(key string) (interface{}, bool) {
+	r := d.getRaw(key, getSourceSet)
+	exists := r.Exists && !r.Computed
+	if exists {
+		// If it exists, we also want to verify it is not the zero-value.
+		value := r.Value
+		zero := r.Schema.Type.Zero()
+
+		if eq, ok := value.(Equal); ok {
+			exists = !eq.Equal(zero)
+		} else {
+			exists = !reflect.DeepEqual(value, zero)
+		}
+	}
+
+	return r.Value, exists
+}
+
+// GetOkExists returns the data for a given key and whether or not the key
+// has been set to a non-zero value. This is only useful for determining
+// if boolean attributes have been set, if they are Optional but do not
+// have a Default value.
+//
+// This is nearly the same function as GetOk, yet it does not check
+// for the zero value of the attribute's type. This allows for attributes
+// without a default, to fully check for a literal assignment, regardless
+// of the zero-value for that type.
+// This should only be used if absolutely required/needed.
+func (d *ResourceData) GetOkExists(key string) (interface{}, bool) {
+	r := d.getRaw(key, getSourceSet)
+	exists := r.Exists && !r.Computed
+	return r.Value, exists
+}
+
+func (d *ResourceData) getRaw(key string, level getSource) getResult {
+	var parts []string
+	if key != "" {
+		parts = strings.Split(key, ".")
+	}
+
+	return d.get(parts, level)
+}
+
+// HasChange returns whether or not the given key has been changed.
+func (d *ResourceData) HasChange(key string) bool {
+	o, n := d.GetChange(key)
+
+	// If the type implements the Equal interface, then call that
+	// instead of just doing a reflect.DeepEqual. An example where this is
+	// needed is *Set
+	if eq, ok := o.(Equal); ok {
+		return !eq.Equal(n)
+	}
+
+	return !reflect.DeepEqual(o, n)
+}
+
+// Partial turns partial state mode on/off.
+//
+// When partial state mode is enabled, then only key prefixes specified
+// by SetPartial will be in the final state. This allows providers to return
+// partial states for partially applied resources (when errors occur).
+func (d *ResourceData) Partial(on bool) {
+	d.partial = on
+	if on {
+		if d.partialMap == nil {
+			d.partialMap = make(map[string]struct{})
+		}
+	} else {
+		d.partialMap = nil
+	}
+}
+
+// Set sets the value for the given key.
+//
+// If the key is invalid or the value is not a correct type, an error
+// will be returned.
+func (d *ResourceData) Set(key string, value interface{}) error {
+	d.once.Do(d.init)
+
+	// If the value is a pointer to a non-struct, get its value and
+	// use that. This allows Set to take a pointer to primitives to
+	// simplify the interface.
+	reflectVal := reflect.ValueOf(value)
+	if reflectVal.Kind() == reflect.Ptr {
+		if reflectVal.IsNil() {
+			// If the pointer is nil, then the value is just nil
+			value = nil
+		} else {
+			// Otherwise, we dereference the pointer as long as its not
+			// a pointer to a struct, since struct pointers are allowed.
+			reflectVal = reflect.Indirect(reflectVal)
+			if reflectVal.Kind() != reflect.Struct {
+				value = reflectVal.Interface()
+			}
+		}
+	}
+
+	err := d.setWriter.WriteField(strings.Split(key, "."), value)
+	if err != nil && d.panicOnError {
+		panic(err)
+	}
+	return err
+}
+
+// SetPartial adds the key to the final state output while
+// in partial state mode. The key must be a root key in the schema (i.e.
+// it cannot be "list.0").
+//
+// If partial state mode is disabled, then this has no effect. Additionally,
+// whenever partial state mode is toggled, the partial data is cleared.
+func (d *ResourceData) SetPartial(k string) {
+	if d.partial {
+		d.partialMap[k] = struct{}{}
+	}
+}
+
+func (d *ResourceData) MarkNewResource() {
+	d.isNew = true
+}
+
+func (d *ResourceData) IsNewResource() bool {
+	return d.isNew
+}
+
+// Id returns the ID of the resource.
+func (d *ResourceData) Id() string {
+	var result string
+
+	if d.state != nil {
+		result = d.state.ID
+		if result == "" {
+			result = d.state.Attributes["id"]
+		}
+	}
+
+	if d.newState != nil {
+		result = d.newState.ID
+		if result == "" {
+			result = d.newState.Attributes["id"]
+		}
+	}
+
+	return result
+}
+
+// ConnInfo returns the connection info for this resource.
+func (d *ResourceData) ConnInfo() map[string]string {
+	if d.newState != nil {
+		return d.newState.Ephemeral.ConnInfo
+	}
+
+	if d.state != nil {
+		return d.state.Ephemeral.ConnInfo
+	}
+
+	return nil
+}
+
+// SetId sets the ID of the resource. If the value is blank, then the
+// resource is destroyed.
+func (d *ResourceData) SetId(v string) {
+	d.once.Do(d.init)
+	d.newState.ID = v
+
+	// once we transition away from the legacy state types, "id" will no longer
+	// be a special field, and will become a normal attribute.
+	// set the attribute normally
+	d.setWriter.unsafeWriteField("id", v)
+
+	// Make sure the newState is also set, otherwise the old value
+	// may get precedence.
+	if d.newState.Attributes == nil {
+		d.newState.Attributes = map[string]string{}
+	}
+	d.newState.Attributes["id"] = v
+}
+
+// SetConnInfo sets the connection info for a resource.
+func (d *ResourceData) SetConnInfo(v map[string]string) {
+	d.once.Do(d.init)
+	d.newState.Ephemeral.ConnInfo = v
+}
+
+// SetType sets the ephemeral type for the data. This is only required
+// for importing.
+func (d *ResourceData) SetType(t string) {
+	d.once.Do(d.init)
+	d.newState.Ephemeral.Type = t
+}
+
+// State returns the new InstanceState after the diff and any Set
+// calls.
+func (d *ResourceData) State() *terraform.InstanceState {
+	var result terraform.InstanceState
+	result.ID = d.Id()
+	result.Meta = d.meta
+
+	// If we have no ID, then this resource doesn't exist and we just
+	// return nil.
+	if result.ID == "" {
+		return nil
+	}
+
+	if d.timeouts != nil {
+		if err := d.timeouts.StateEncode(&result); err != nil {
+			log.Printf("[ERR] Error encoding Timeout meta to Instance State: %s", err)
+		}
+	}
+
+	// Look for a magic key in the schema that determines we skip the
+	// integrity check of fields existing in the schema, allowing dynamic
+	// keys to be created.
+	hasDynamicAttributes := false
+	for k, _ := range d.schema {
+		if k == "__has_dynamic_attributes" {
+			hasDynamicAttributes = true
+			log.Printf("[INFO] Resource %s has dynamic attributes", result.ID)
+		}
+	}
+
+	// In order to build the final state attributes, we read the full
+	// attribute set as a map[string]interface{}, write it to a MapFieldWriter,
+	// and then use that map.
+	rawMap := make(map[string]interface{})
+	for k := range d.schema {
+		source := getSourceSet
+		if d.partial {
+			source = getSourceState
+			if _, ok := d.partialMap[k]; ok {
+				source = getSourceSet
+			}
+		}
+
+		raw := d.get([]string{k}, source)
+		if raw.Exists && !raw.Computed {
+			rawMap[k] = raw.Value
+			if raw.ValueProcessed != nil {
+				rawMap[k] = raw.ValueProcessed
+			}
+		}
+	}
+
+	mapW := &MapFieldWriter{Schema: d.schema}
+	if err := mapW.WriteField(nil, rawMap); err != nil {
+		log.Printf("[ERR] Error writing fields: %s", err)
+		return nil
+	}
+
+	result.Attributes = mapW.Map()
+
+	if hasDynamicAttributes {
+		// If we have dynamic attributes, just copy the attributes map
+		// one for one into the result attributes.
+		for k, v := range d.setWriter.Map() {
+			// Don't clobber schema values. This limits usage of dynamic
+			// attributes to names which _do not_ conflict with schema
+			// keys!
+			if _, ok := result.Attributes[k]; !ok {
+				result.Attributes[k] = v
+			}
+		}
+	}
+
+	if d.newState != nil {
+		result.Ephemeral = d.newState.Ephemeral
+	}
+
+	// TODO: This is hacky and we can remove this when we have a proper
+	// state writer. We should instead have a proper StateFieldWriter
+	// and use that.
+	for k, schema := range d.schema {
+		if schema.Type != TypeMap {
+			continue
+		}
+
+		if result.Attributes[k] == "" {
+			delete(result.Attributes, k)
+		}
+	}
+
+	if v := d.Id(); v != "" {
+		result.Attributes["id"] = d.Id()
+	}
+
+	if d.state != nil {
+		result.Tainted = d.state.Tainted
+	}
+
+	return &result
+}
+
+// Timeout returns the data for the given timeout key
+// Returns a duration of 20 minutes for any key not found, or not found and no default.
+func (d *ResourceData) Timeout(key string) time.Duration {
+	key = strings.ToLower(key)
+
+	// System default of 20 minutes
+	defaultTimeout := 20 * time.Minute
+
+	if d.timeouts == nil {
+		return defaultTimeout
+	}
+
+	var timeout *time.Duration
+	switch key {
+	case TimeoutCreate:
+		timeout = d.timeouts.Create
+	case TimeoutRead:
+		timeout = d.timeouts.Read
+	case TimeoutUpdate:
+		timeout = d.timeouts.Update
+	case TimeoutDelete:
+		timeout = d.timeouts.Delete
+	}
+
+	if timeout != nil {
+		return *timeout
+	}
+
+	if d.timeouts.Default != nil {
+		return *d.timeouts.Default
+	}
+
+	return defaultTimeout
+}
+
+func (d *ResourceData) init() {
+	// Initialize the field that will store our new state
+	var copyState terraform.InstanceState
+	if d.state != nil {
+		copyState = *d.state.DeepCopy()
+	}
+	d.newState = &copyState
+
+	// Initialize the map for storing set data
+	d.setWriter = &MapFieldWriter{Schema: d.schema}
+
+	// Initialize the reader for getting data from the
+	// underlying sources (config, diff, etc.)
+	readers := make(map[string]FieldReader)
+	var stateAttributes map[string]string
+	if d.state != nil {
+		stateAttributes = d.state.Attributes
+		readers["state"] = &MapFieldReader{
+			Schema: d.schema,
+			Map:    BasicMapReader(stateAttributes),
+		}
+	}
+	if d.config != nil {
+		readers["config"] = &ConfigFieldReader{
+			Schema: d.schema,
+			Config: d.config,
+		}
+	}
+	if d.diff != nil {
+		readers["diff"] = &DiffFieldReader{
+			Schema: d.schema,
+			Diff:   d.diff,
+			Source: &MultiLevelFieldReader{
+				Levels:  []string{"state", "config"},
+				Readers: readers,
+			},
+		}
+	}
+	readers["set"] = &MapFieldReader{
+		Schema: d.schema,
+		Map:    BasicMapReader(d.setWriter.Map()),
+	}
+	d.multiReader = &MultiLevelFieldReader{
+		Levels: []string{
+			"state",
+			"config",
+			"diff",
+			"set",
+		},
+
+		Readers: readers,
+	}
+}
+
+func (d *ResourceData) diffChange(
+	k string) (interface{}, interface{}, bool, bool, bool) {
+	// Get the change between the state and the config.
+	o, n := d.getChange(k, getSourceState, getSourceConfig|getSourceExact)
+	if !o.Exists {
+		o.Value = nil
+	}
+	if !n.Exists {
+		n.Value = nil
+	}
+
+	// Return the old, new, and whether there is a change
+	return o.Value, n.Value, !reflect.DeepEqual(o.Value, n.Value), n.Computed, false
+}
+
+func (d *ResourceData) getChange(
+	k string,
+	oldLevel getSource,
+	newLevel getSource) (getResult, getResult) {
+	var parts, parts2 []string
+	if k != "" {
+		parts = strings.Split(k, ".")
+		parts2 = strings.Split(k, ".")
+	}
+
+	o := d.get(parts, oldLevel)
+	n := d.get(parts2, newLevel)
+	return o, n
+}
+
+func (d *ResourceData) get(addr []string, source getSource) getResult {
+	d.once.Do(d.init)
+
+	level := "set"
+	flags := source & ^getSourceLevelMask
+	exact := flags&getSourceExact != 0
+	source = source & getSourceLevelMask
+	if source >= getSourceSet {
+		level = "set"
+	} else if source >= getSourceDiff {
+		level = "diff"
+	} else if source >= getSourceConfig {
+		level = "config"
+	} else {
+		level = "state"
+	}
+
+	var result FieldReadResult
+	var err error
+	if exact {
+		result, err = d.multiReader.ReadFieldExact(addr, level)
+	} else {
+		result, err = d.multiReader.ReadFieldMerge(addr, level)
+	}
+	if err != nil {
+		panic(err)
+	}
+
+	// If the result doesn't exist, then we set the value to the zero value
+	var schema *Schema
+	if schemaL := addrToSchema(addr, d.schema); len(schemaL) > 0 {
+		schema = schemaL[len(schemaL)-1]
+	}
+
+	if result.Value == nil && schema != nil {
+		result.Value = result.ValueOrZero(schema)
+	}
+
+	// Transform the FieldReadResult into a getResult. It might be worth
+	// merging these two structures one day.
+	return getResult{
+		Value:          result.Value,
+		ValueProcessed: result.ValueProcessed,
+		Computed:       result.Computed,
+		Exists:         result.Exists,
+		Schema:         schema,
+	}
+}
+
+func (d *ResourceData) GetProviderMeta(dst interface{}) error {
+	if d.providerMeta.IsNull() {
+		return nil
+	}
+	return gocty.FromCtyValue(d.providerMeta, &dst)
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/resource_data_get_source.go b/v1.5.7/internal/legacy/helper/schema/resource_data_get_source.go
new file mode 100644
index 0000000..3684ffc
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/resource_data_get_source.go
@@ -0,0 +1,20 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=getSource resource_data_get_source.go
+
+// getSource represents the level we want to get for a value (internally).
+// Any source less than or equal to the level will be loaded (whichever
+// has a value first).
+type getSource byte
+
+const (
+	getSourceState getSource = 1 << iota
+	getSourceConfig
+	getSourceDiff
+	getSourceSet
+	getSourceExact               // Only get from the _exact_ level
+	getSourceLevelMask getSource = getSourceState | getSourceConfig | getSourceDiff | getSourceSet
+)
diff --git a/v1.5.7/internal/legacy/helper/schema/resource_data_test.go b/v1.5.7/internal/legacy/helper/schema/resource_data_test.go
new file mode 100644
index 0000000..2160c30
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/resource_data_test.go
@@ -0,0 +1,3567 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"fmt"
+	"math"
+	"os"
+	"reflect"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+func TestResourceDataGet(t *testing.T) {
+	cases := []struct {
+		Schema map[string]*Schema
+		State  *terraform.InstanceState
+		Diff   *terraform.InstanceDiff
+		Key    string
+		Value  interface{}
+	}{
+		// #0
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "foo",
+						New:         "bar",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: "",
+		},
+
+		// #1
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "foo",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Key: "availability_zone",
+
+			Value: "foo",
+		},
+
+		// #2
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:      "",
+						New:      "foo!",
+						NewExtra: "foo",
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: "foo",
+		},
+
+		// #3
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "bar",
+				},
+			},
+
+			Diff: nil,
+
+			Key: "availability_zone",
+
+			Value: "bar",
+		},
+
+		// #4
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "foo",
+						New:         "bar",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: "",
+		},
+
+		// #5
+		{
+			Schema: map[string]*Schema{
+				"port": &Schema{
+					Type:     TypeInt,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"port": "80",
+				},
+			},
+
+			Diff: nil,
+
+			Key: "port",
+
+			Value: 80,
+		},
+
+		// #6
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "3",
+					"ports.0": "1",
+					"ports.1": "2",
+					"ports.2": "5",
+				},
+			},
+
+			Key: "ports.1",
+
+			Value: 2,
+		},
+
+		// #7
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "3",
+					"ports.0": "1",
+					"ports.1": "2",
+					"ports.2": "5",
+				},
+			},
+
+			Key: "ports.#",
+
+			Value: 3,
+		},
+
+		// #8
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: nil,
+
+			Key: "ports.#",
+
+			Value: 0,
+		},
+
+		// #9
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "3",
+					"ports.0": "1",
+					"ports.1": "2",
+					"ports.2": "5",
+				},
+			},
+
+			Key: "ports",
+
+			Value: []interface{}{1, 2, 5},
+		},
+
+		// #10
+		{
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"from": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+						},
+					},
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ingress.#": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"ingress.0.from": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "8080",
+					},
+				},
+			},
+
+			Key: "ingress.0",
+
+			Value: map[string]interface{}{
+				"from": 8080,
+			},
+		},
+
+		// #11
+		{
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"from": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+						},
+					},
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ingress.#": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"ingress.0.from": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "8080",
+					},
+				},
+			},
+
+			Key: "ingress",
+
+			Value: []interface{}{
+				map[string]interface{}{
+					"from": 8080,
+				},
+			},
+		},
+
+		// #12 Computed get
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+
+			Key: "availability_zone",
+
+			Value: "foo",
+		},
+
+		// #13 Full object
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "foo",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Key: "",
+
+			Value: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+		},
+
+		// #14 List of maps
+		{
+			Schema: map[string]*Schema{
+				"config_vars": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					Elem: &Schema{
+						Type: TypeMap,
+					},
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config_vars.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "2",
+					},
+					"config_vars.0.foo": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "bar",
+					},
+					"config_vars.1.bar": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "baz",
+					},
+				},
+			},
+
+			Key: "config_vars",
+
+			Value: []interface{}{
+				map[string]interface{}{
+					"foo": "bar",
+				},
+				map[string]interface{}{
+					"bar": "baz",
+				},
+			},
+		},
+
+		// #15 List of maps in state
+		{
+			Schema: map[string]*Schema{
+				"config_vars": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					Elem: &Schema{
+						Type: TypeMap,
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"config_vars.#":     "2",
+					"config_vars.0.foo": "baz",
+					"config_vars.1.bar": "bar",
+				},
+			},
+
+			Diff: nil,
+
+			Key: "config_vars",
+
+			Value: []interface{}{
+				map[string]interface{}{
+					"foo": "baz",
+				},
+				map[string]interface{}{
+					"bar": "bar",
+				},
+			},
+		},
+
+		// #16 List of maps with removal in diff
+		{
+			Schema: map[string]*Schema{
+				"config_vars": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					Elem: &Schema{
+						Type: TypeMap,
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"config_vars.#":     "1",
+					"config_vars.0.FOO": "bar",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config_vars.#": &terraform.ResourceAttrDiff{
+						Old: "1",
+						New: "0",
+					},
+					"config_vars.0.FOO": &terraform.ResourceAttrDiff{
+						Old:        "bar",
+						NewRemoved: true,
+					},
+				},
+			},
+
+			Key: "config_vars",
+
+			Value: []interface{}{},
+		},
+
+		// #17 Sets
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":  "1",
+					"ports.80": "80",
+				},
+			},
+
+			Diff: nil,
+
+			Key: "ports",
+
+			Value: []interface{}{80},
+		},
+
+		// #18
+		{
+			Schema: map[string]*Schema{
+				"data": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"index": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+
+							"value": &Schema{
+								Type:     TypeString,
+								Required: true,
+							},
+						},
+					},
+					Set: func(a interface{}) int {
+						m := a.(map[string]interface{})
+						return m["index"].(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"data.#":        "1",
+					"data.10.index": "10",
+					"data.10.value": "50",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"data.10.value": &terraform.ResourceAttrDiff{
+						Old: "50",
+						New: "80",
+					},
+				},
+			},
+
+			Key: "data",
+
+			Value: []interface{}{
+				map[string]interface{}{
+					"index": 10,
+					"value": "80",
+				},
+			},
+		},
+
+		// #19 Empty Set
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key: "ports",
+
+			Value: []interface{}{},
+		},
+
+		// #20 Float zero
+		{
+			Schema: map[string]*Schema{
+				"ratio": &Schema{
+					Type:     TypeFloat,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key: "ratio",
+
+			Value: 0.0,
+		},
+
+		// #21 Float given
+		{
+			Schema: map[string]*Schema{
+				"ratio": &Schema{
+					Type:     TypeFloat,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ratio": "0.5",
+				},
+			},
+
+			Diff: nil,
+
+			Key: "ratio",
+
+			Value: 0.5,
+		},
+
+		// #22 Float diff
+		{
+			Schema: map[string]*Schema{
+				"ratio": &Schema{
+					Type:     TypeFloat,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ratio": "-0.5",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ratio": &terraform.ResourceAttrDiff{
+						Old: "-0.5",
+						New: "33.0",
+					},
+				},
+			},
+
+			Key: "ratio",
+
+			Value: 33.0,
+		},
+
+		// #23 Sets with removed elements
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":  "1",
+					"ports.80": "80",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "2",
+						New: "1",
+					},
+					"ports.80": &terraform.ResourceAttrDiff{
+						Old: "80",
+						New: "80",
+					},
+					"ports.8080": &terraform.ResourceAttrDiff{
+						Old:        "8080",
+						New:        "0",
+						NewRemoved: true,
+					},
+				},
+			},
+
+			Key: "ports",
+
+			Value: []interface{}{80},
+		},
+	}
+
+	for i, tc := range cases {
+		d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		v := d.Get(tc.Key)
+		if s, ok := v.(*Set); ok {
+			v = s.List()
+		}
+
+		if !reflect.DeepEqual(v, tc.Value) {
+			t.Fatalf("Bad: %d\n\n%#v\n\nExpected: %#v", i, v, tc.Value)
+		}
+	}
+}
+
+func TestResourceDataGetChange(t *testing.T) {
+	cases := []struct {
+		Schema   map[string]*Schema
+		State    *terraform.InstanceState
+		Diff     *terraform.InstanceDiff
+		Key      string
+		OldValue interface{}
+		NewValue interface{}
+	}{
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "foo",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Key: "availability_zone",
+
+			OldValue: "",
+			NewValue: "foo",
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "foo",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Key: "availability_zone",
+
+			OldValue: "foo",
+			NewValue: "foo",
+		},
+	}
+
+	for i, tc := range cases {
+		d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		o, n := d.GetChange(tc.Key)
+		if !reflect.DeepEqual(o, tc.OldValue) {
+			t.Fatalf("Old Bad: %d\n\n%#v", i, o)
+		}
+		if !reflect.DeepEqual(n, tc.NewValue) {
+			t.Fatalf("New Bad: %d\n\n%#v", i, n)
+		}
+	}
+}
+
+func TestResourceDataGetOk(t *testing.T) {
+	cases := []struct {
+		Schema map[string]*Schema
+		State  *terraform.InstanceState
+		Diff   *terraform.InstanceDiff
+		Key    string
+		Value  interface{}
+		Ok     bool
+	}{
+		/*
+		 * Primitives
+		 */
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "",
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: "",
+			Ok:    false,
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: "",
+			Ok:    false,
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "availability_zone",
+			Value: "",
+			Ok:    false,
+		},
+
+		/*
+		 * Lists
+		 */
+
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "ports",
+			Value: []interface{}{},
+			Ok:    false,
+		},
+
+		/*
+		 * Map
+		 */
+
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeMap,
+					Optional: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "ports",
+			Value: map[string]interface{}{},
+			Ok:    false,
+		},
+
+		/*
+		 * Set
+		 */
+
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set:      func(a interface{}) int { return a.(int) },
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "ports",
+			Value: []interface{}{},
+			Ok:    false,
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set:      func(a interface{}) int { return a.(int) },
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "ports.0",
+			Value: 0,
+			Ok:    false,
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set:      func(a interface{}) int { return a.(int) },
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "0",
+					},
+				},
+			},
+
+			Key:   "ports",
+			Value: []interface{}{},
+			Ok:    false,
+		},
+
+		// Further illustrates and clarifiies the GetOk semantics from #933, and
+		// highlights the limitation that zero-value config is currently
+		// indistinguishable from unset config.
+		{
+			Schema: map[string]*Schema{
+				"from_port": &Schema{
+					Type:     TypeInt,
+					Optional: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"from_port": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "0",
+					},
+				},
+			},
+
+			Key:   "from_port",
+			Value: 0,
+			Ok:    false,
+		},
+	}
+
+	for i, tc := range cases {
+		d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		v, ok := d.GetOk(tc.Key)
+		if s, ok := v.(*Set); ok {
+			v = s.List()
+		}
+
+		if !reflect.DeepEqual(v, tc.Value) {
+			t.Fatalf("Bad: %d\n\n%#v", i, v)
+		}
+		if ok != tc.Ok {
+			t.Fatalf("%d: expected ok: %t, got: %t", i, tc.Ok, ok)
+		}
+	}
+}
+
+func TestResourceDataGetOkExists(t *testing.T) {
+	cases := []struct {
+		Name   string
+		Schema map[string]*Schema
+		State  *terraform.InstanceState
+		Diff   *terraform.InstanceDiff
+		Key    string
+		Value  interface{}
+		Ok     bool
+	}{
+		/*
+		 * Primitives
+		 */
+		{
+			Name: "string-literal-empty",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": {
+						Old: "",
+						New: "",
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: "",
+			Ok:    true,
+		},
+
+		{
+			Name: "string-computed-empty",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": {
+						Old:         "",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: "",
+			Ok:    false,
+		},
+
+		{
+			Name: "string-optional-computed-nil-diff",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "availability_zone",
+			Value: "",
+			Ok:    false,
+		},
+
+		/*
+		 * Lists
+		 */
+
+		{
+			Name: "list-optional",
+			Schema: map[string]*Schema{
+				"ports": {
+					Type:     TypeList,
+					Optional: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "ports",
+			Value: []interface{}{},
+			Ok:    false,
+		},
+
+		/*
+		 * Map
+		 */
+
+		{
+			Name: "map-optional",
+			Schema: map[string]*Schema{
+				"ports": {
+					Type:     TypeMap,
+					Optional: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "ports",
+			Value: map[string]interface{}{},
+			Ok:    false,
+		},
+
+		/*
+		 * Set
+		 */
+
+		{
+			Name: "set-optional",
+			Schema: map[string]*Schema{
+				"ports": {
+					Type:     TypeSet,
+					Optional: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set:      func(a interface{}) int { return a.(int) },
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "ports",
+			Value: []interface{}{},
+			Ok:    false,
+		},
+
+		{
+			Name: "set-optional-key",
+			Schema: map[string]*Schema{
+				"ports": {
+					Type:     TypeSet,
+					Optional: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set:      func(a interface{}) int { return a.(int) },
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "ports.0",
+			Value: 0,
+			Ok:    false,
+		},
+
+		{
+			Name: "bool-literal-empty",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeBool,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": {
+						Old: "",
+						New: "",
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: false,
+			Ok:    true,
+		},
+
+		{
+			Name: "bool-literal-set",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeBool,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": {
+						New: "true",
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: true,
+			Ok:    true,
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
+			if err != nil {
+				t.Fatalf("%s err: %s", tc.Name, err)
+			}
+
+			v, ok := d.GetOkExists(tc.Key)
+			if s, ok := v.(*Set); ok {
+				v = s.List()
+			}
+
+			if !reflect.DeepEqual(v, tc.Value) {
+				t.Fatalf("Bad %s: \n%#v", tc.Name, v)
+			}
+			if ok != tc.Ok {
+				t.Fatalf("%s: expected ok: %t, got: %t", tc.Name, tc.Ok, ok)
+			}
+		})
+	}
+}
+
+func TestResourceDataTimeout(t *testing.T) {
+	cases := []struct {
+		Name     string
+		Rd       *ResourceData
+		Expected *ResourceTimeout
+	}{
+		{
+			Name:     "Basic example default",
+			Rd:       &ResourceData{timeouts: timeoutForValues(10, 3, 0, 15, 0)},
+			Expected: expectedTimeoutForValues(10, 3, 0, 15, 0),
+		},
+		{
+			Name:     "Resource and config match update, create",
+			Rd:       &ResourceData{timeouts: timeoutForValues(10, 0, 3, 0, 0)},
+			Expected: expectedTimeoutForValues(10, 0, 3, 0, 0),
+		},
+		{
+			Name:     "Resource provides default",
+			Rd:       &ResourceData{timeouts: timeoutForValues(10, 0, 0, 0, 7)},
+			Expected: expectedTimeoutForValues(10, 7, 7, 7, 7),
+		},
+		{
+			Name:     "Resource provides default and delete",
+			Rd:       &ResourceData{timeouts: timeoutForValues(10, 0, 0, 15, 7)},
+			Expected: expectedTimeoutForValues(10, 7, 7, 15, 7),
+		},
+		{
+			Name:     "Resource provides default, config overwrites other values",
+			Rd:       &ResourceData{timeouts: timeoutForValues(10, 3, 0, 0, 13)},
+			Expected: expectedTimeoutForValues(10, 3, 13, 13, 13),
+		},
+		{
+			Name:     "Resource has no config",
+			Rd:       &ResourceData{},
+			Expected: expectedTimeoutForValues(0, 0, 0, 0, 0),
+		},
+	}
+
+	keys := timeoutKeys()
+	for i, c := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, c.Name), func(t *testing.T) {
+
+			for _, k := range keys {
+				got := c.Rd.Timeout(k)
+				var ex *time.Duration
+				switch k {
+				case TimeoutCreate:
+					ex = c.Expected.Create
+				case TimeoutRead:
+					ex = c.Expected.Read
+				case TimeoutUpdate:
+					ex = c.Expected.Update
+				case TimeoutDelete:
+					ex = c.Expected.Delete
+				case TimeoutDefault:
+					ex = c.Expected.Default
+				}
+
+				if got > 0 && ex == nil {
+					t.Fatalf("Unexpected value in (%s), case %d check 1:\n\texpected: %#v\n\tgot: %#v", k, i, ex, got)
+				}
+				if got == 0 && ex != nil {
+					t.Fatalf("Unexpected value in (%s), case %d check 2:\n\texpected: %#v\n\tgot: %#v", k, i, *ex, got)
+				}
+
+				// confirm values
+				if ex != nil {
+					if got != *ex {
+						t.Fatalf("Timeout %s case (%d) expected (%s), got (%s)", k, i, *ex, got)
+					}
+				}
+			}
+
+		})
+	}
+}
+
+func TestResourceDataHasChange(t *testing.T) {
+	cases := []struct {
+		Schema map[string]*Schema
+		State  *terraform.InstanceState
+		Diff   *terraform.InstanceDiff
+		Key    string
+		Change bool
+	}{
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "foo",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Key: "availability_zone",
+
+			Change: true,
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "foo",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Key: "availability_zone",
+
+			Change: false,
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"tags": &Schema{
+					Type:     TypeMap,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"tags.Name": &terraform.ResourceAttrDiff{
+						Old: "foo",
+						New: "foo",
+					},
+				},
+			},
+
+			Key: "tags",
+
+			Change: true,
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set:      func(a interface{}) int { return a.(int) },
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":  "1",
+					"ports.80": "80",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "1",
+						New: "0",
+					},
+				},
+			},
+
+			Key: "ports",
+
+			Change: true,
+		},
+
+		// https://github.com/hashicorp/terraform/issues/927
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set:      func(a interface{}) int { return a.(int) },
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":  "1",
+					"ports.80": "80",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"tags.foo": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "bar",
+					},
+				},
+			},
+
+			Key: "ports",
+
+			Change: false,
+		},
+	}
+
+	for i, tc := range cases {
+		d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		actual := d.HasChange(tc.Key)
+		if actual != tc.Change {
+			t.Fatalf("Bad: %d %#v", i, actual)
+		}
+	}
+}
+
+func TestResourceDataSet(t *testing.T) {
+	var testNilPtr *string
+
+	cases := []struct {
+		Schema   map[string]*Schema
+		State    *terraform.InstanceState
+		Diff     *terraform.InstanceDiff
+		Key      string
+		Value    interface{}
+		Err      bool
+		GetKey   string
+		GetValue interface{}
+
+		// GetPreProcess can be set to munge the return value before being
+		// compared to GetValue
+		GetPreProcess func(interface{}) interface{}
+	}{
+		// #0: Basic good
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "availability_zone",
+			Value: "foo",
+
+			GetKey:   "availability_zone",
+			GetValue: "foo",
+		},
+
+		// #1: Basic int
+		{
+			Schema: map[string]*Schema{
+				"port": &Schema{
+					Type:     TypeInt,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "port",
+			Value: 80,
+
+			GetKey:   "port",
+			GetValue: 80,
+		},
+
+		// #2: Basic bool
+		{
+			Schema: map[string]*Schema{
+				"vpc": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "vpc",
+			Value: true,
+
+			GetKey:   "vpc",
+			GetValue: true,
+		},
+
+		// #3
+		{
+			Schema: map[string]*Schema{
+				"vpc": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "vpc",
+			Value: false,
+
+			GetKey:   "vpc",
+			GetValue: false,
+		},
+
+		// #4: Invalid type
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "availability_zone",
+			Value: 80,
+			Err:   true,
+
+			GetKey:   "availability_zone",
+			GetValue: "",
+		},
+
+		// #5: List of primitives, set list
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "ports",
+			Value: []int{1, 2, 5},
+
+			GetKey:   "ports",
+			GetValue: []interface{}{1, 2, 5},
+		},
+
+		// #6: List of primitives, set list with error
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "ports",
+			Value: []interface{}{1, "NOPE", 5},
+			Err:   true,
+
+			GetKey:   "ports",
+			GetValue: []interface{}{},
+		},
+
+		// #7: Set a list of maps
+		{
+			Schema: map[string]*Schema{
+				"config_vars": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					Elem: &Schema{
+						Type: TypeMap,
+					},
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key: "config_vars",
+			Value: []interface{}{
+				map[string]interface{}{
+					"foo": "bar",
+				},
+				map[string]interface{}{
+					"bar": "baz",
+				},
+			},
+			Err: false,
+
+			GetKey: "config_vars",
+			GetValue: []interface{}{
+				map[string]interface{}{
+					"foo": "bar",
+				},
+				map[string]interface{}{
+					"bar": "baz",
+				},
+			},
+		},
+
+		// #8: Set, with list
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "3",
+					"ports.0": "100",
+					"ports.1": "80",
+					"ports.2": "80",
+				},
+			},
+
+			Key:   "ports",
+			Value: []interface{}{100, 125, 125},
+
+			GetKey:   "ports",
+			GetValue: []interface{}{100, 125},
+		},
+
+		// #9: Set, with Set
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":   "3",
+					"ports.100": "100",
+					"ports.80":  "80",
+					"ports.81":  "81",
+				},
+			},
+
+			Key: "ports",
+			Value: &Set{
+				m: map[string]interface{}{
+					"1": 1,
+					"2": 2,
+				},
+			},
+
+			GetKey:   "ports",
+			GetValue: []interface{}{1, 2},
+		},
+
+		// #10: Set single item
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":   "2",
+					"ports.100": "100",
+					"ports.80":  "80",
+				},
+			},
+
+			Key:   "ports.100",
+			Value: 256,
+			Err:   true,
+
+			GetKey:   "ports",
+			GetValue: []interface{}{100, 80},
+		},
+
+		// #11: Set with nested set
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type: TypeSet,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"port": &Schema{
+								Type: TypeInt,
+							},
+
+							"set": &Schema{
+								Type: TypeSet,
+								Elem: &Schema{Type: TypeInt},
+								Set: func(a interface{}) int {
+									return a.(int)
+								},
+							},
+						},
+					},
+					Set: func(a interface{}) int {
+						return a.(map[string]interface{})["port"].(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Key: "ports",
+			Value: []interface{}{
+				map[string]interface{}{
+					"port": 80,
+				},
+			},
+
+			GetKey: "ports",
+			GetValue: []interface{}{
+				map[string]interface{}{
+					"port": 80,
+					"set":  []interface{}{},
+				},
+			},
+
+			GetPreProcess: func(v interface{}) interface{} {
+				if v == nil {
+					return v
+				}
+				s, ok := v.([]interface{})
+				if !ok {
+					return v
+				}
+				for _, v := range s {
+					m, ok := v.(map[string]interface{})
+					if !ok {
+						continue
+					}
+					if m["set"] == nil {
+						continue
+					}
+					if s, ok := m["set"].(*Set); ok {
+						m["set"] = s.List()
+					}
+				}
+
+				return v
+			},
+		},
+
+		// #12: List of floats, set list
+		{
+			Schema: map[string]*Schema{
+				"ratios": &Schema{
+					Type:     TypeList,
+					Computed: true,
+					Elem:     &Schema{Type: TypeFloat},
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "ratios",
+			Value: []float64{1.0, 2.2, 5.5},
+
+			GetKey:   "ratios",
+			GetValue: []interface{}{1.0, 2.2, 5.5},
+		},
+
+		// #12: Set of floats, set list
+		{
+			Schema: map[string]*Schema{
+				"ratios": &Schema{
+					Type:     TypeSet,
+					Computed: true,
+					Elem:     &Schema{Type: TypeFloat},
+					Set: func(a interface{}) int {
+						return int(math.Float64bits(a.(float64)))
+					},
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "ratios",
+			Value: []float64{1.0, 2.2, 5.5},
+
+			GetKey:   "ratios",
+			GetValue: []interface{}{1.0, 2.2, 5.5},
+		},
+
+		// #13: Basic pointer
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "availability_zone",
+			Value: testPtrTo("foo"),
+
+			GetKey:   "availability_zone",
+			GetValue: "foo",
+		},
+
+		// #14: Basic nil value
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "availability_zone",
+			Value: testPtrTo(nil),
+
+			GetKey:   "availability_zone",
+			GetValue: "",
+		},
+
+		// #15: Basic nil pointer
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Key:   "availability_zone",
+			Value: testNilPtr,
+
+			GetKey:   "availability_zone",
+			GetValue: "",
+		},
+
+		// #16: Set in a list
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type: TypeList,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"set": &Schema{
+								Type: TypeSet,
+								Elem: &Schema{Type: TypeInt},
+								Set: func(a interface{}) int {
+									return a.(int)
+								},
+							},
+						},
+					},
+				},
+			},
+
+			State: nil,
+
+			Key: "ports",
+			Value: []interface{}{
+				map[string]interface{}{
+					"set": []interface{}{
+						1,
+					},
+				},
+			},
+
+			GetKey: "ports",
+			GetValue: []interface{}{
+				map[string]interface{}{
+					"set": []interface{}{
+						1,
+					},
+				},
+			},
+			GetPreProcess: func(v interface{}) interface{} {
+				if v == nil {
+					return v
+				}
+				s, ok := v.([]interface{})
+				if !ok {
+					return v
+				}
+				for _, v := range s {
+					m, ok := v.(map[string]interface{})
+					if !ok {
+						continue
+					}
+					if m["set"] == nil {
+						continue
+					}
+					if s, ok := m["set"].(*Set); ok {
+						m["set"] = s.List()
+					}
+				}
+
+				return v
+			},
+		},
+	}
+
+	oldEnv := os.Getenv(PanicOnErr)
+	os.Setenv(PanicOnErr, "")
+	defer os.Setenv(PanicOnErr, oldEnv)
+
+	for i, tc := range cases {
+		d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		err = d.Set(tc.Key, tc.Value)
+		if err != nil != tc.Err {
+			t.Fatalf("%d err: %s", i, err)
+		}
+
+		v := d.Get(tc.GetKey)
+		if s, ok := v.(*Set); ok {
+			v = s.List()
+		}
+
+		if tc.GetPreProcess != nil {
+			v = tc.GetPreProcess(v)
+		}
+
+		if !reflect.DeepEqual(v, tc.GetValue) {
+			t.Fatalf("Get Bad: %d\n\n%#v", i, v)
+		}
+	}
+}
+
+func TestResourceDataState_dynamicAttributes(t *testing.T) {
+	cases := []struct {
+		Schema    map[string]*Schema
+		State     *terraform.InstanceState
+		Diff      *terraform.InstanceDiff
+		Set       map[string]interface{}
+		UnsafeSet map[string]string
+		Result    *terraform.InstanceState
+	}{
+		{
+			Schema: map[string]*Schema{
+				"__has_dynamic_attributes": {
+					Type:     TypeString,
+					Optional: true,
+				},
+
+				"schema_field": {
+					Type:     TypeString,
+					Required: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Set: map[string]interface{}{
+				"schema_field": "present",
+			},
+
+			UnsafeSet: map[string]string{
+				"test1": "value",
+				"test2": "value",
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"schema_field": "present",
+					"test1":        "value",
+					"test2":        "value",
+				},
+			},
+		},
+	}
+
+	for i, tc := range cases {
+		d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		for k, v := range tc.Set {
+			d.Set(k, v)
+		}
+
+		for k, v := range tc.UnsafeSet {
+			d.UnsafeSetFieldRaw(k, v)
+		}
+
+		// Set an ID so that the state returned is not nil
+		idSet := false
+		if d.Id() == "" {
+			idSet = true
+			d.SetId("foo")
+		}
+
+		actual := d.State()
+
+		// If we set an ID, then undo what we did so the comparison works
+		if actual != nil && idSet {
+			actual.ID = ""
+			delete(actual.Attributes, "id")
+		}
+
+		if !reflect.DeepEqual(actual, tc.Result) {
+			t.Fatalf("Bad: %d\n\n%#v\n\nExpected:\n\n%#v", i, actual, tc.Result)
+		}
+	}
+}
+
+func TestResourceDataState_schema(t *testing.T) {
+	cases := []struct {
+		Schema  map[string]*Schema
+		State   *terraform.InstanceState
+		Diff    *terraform.InstanceDiff
+		Set     map[string]interface{}
+		Result  *terraform.InstanceState
+		Partial []string
+	}{
+		// #0 Basic primitive in diff
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "foo",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+		},
+
+		// #1 Basic primitive set override
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "foo",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Set: map[string]interface{}{
+				"availability_zone": "bar",
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "bar",
+				},
+			},
+		},
+
+		// #2
+		{
+			Schema: map[string]*Schema{
+				"vpc": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Set: map[string]interface{}{
+				"vpc": true,
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"vpc": "true",
+				},
+			},
+		},
+
+		// #3 Basic primitive with StateFunc set
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:      TypeString,
+					Optional:  true,
+					Computed:  true,
+					StateFunc: func(interface{}) string { return "" },
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:      "",
+						New:      "foo",
+						NewExtra: "foo!",
+					},
+				},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+		},
+
+		// #4 List
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "1",
+					"ports.0": "80",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "1",
+						New: "2",
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "100",
+					},
+				},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "2",
+					"ports.0": "80",
+					"ports.1": "100",
+				},
+			},
+		},
+
+		// #5 List of resources
+		{
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"from": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+						},
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ingress.#":      "1",
+					"ingress.0.from": "80",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ingress.#": &terraform.ResourceAttrDiff{
+						Old: "1",
+						New: "2",
+					},
+					"ingress.0.from": &terraform.ResourceAttrDiff{
+						Old: "80",
+						New: "150",
+					},
+					"ingress.1.from": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "100",
+					},
+				},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ingress.#":      "2",
+					"ingress.0.from": "150",
+					"ingress.1.from": "100",
+				},
+			},
+		},
+
+		// #6 List of maps
+		{
+			Schema: map[string]*Schema{
+				"config_vars": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					Elem: &Schema{
+						Type: TypeMap,
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"config_vars.#":     "2",
+					"config_vars.0.%":   "2",
+					"config_vars.0.foo": "bar",
+					"config_vars.0.bar": "bar",
+					"config_vars.1.%":   "1",
+					"config_vars.1.bar": "baz",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config_vars.0.bar": &terraform.ResourceAttrDiff{
+						NewRemoved: true,
+					},
+				},
+			},
+
+			Set: map[string]interface{}{
+				"config_vars": []map[string]interface{}{
+					map[string]interface{}{
+						"foo": "bar",
+					},
+					map[string]interface{}{
+						"baz": "bang",
+					},
+				},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"config_vars.#":     "2",
+					"config_vars.0.%":   "1",
+					"config_vars.0.foo": "bar",
+					"config_vars.1.%":   "1",
+					"config_vars.1.baz": "bang",
+				},
+			},
+		},
+
+		// #7 List of maps with removal in diff
+		{
+			Schema: map[string]*Schema{
+				"config_vars": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					Elem: &Schema{
+						Type: TypeMap,
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"config_vars.#":     "1",
+					"config_vars.0.FOO": "bar",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config_vars.#": &terraform.ResourceAttrDiff{
+						Old: "1",
+						New: "0",
+					},
+					"config_vars.0.FOO": &terraform.ResourceAttrDiff{
+						Old:        "bar",
+						NewRemoved: true,
+					},
+				},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"config_vars.#": "0",
+				},
+			},
+		},
+
+		// #8 Basic state with other keys
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "bar",
+				Attributes: map[string]string{
+					"id": "bar",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "foo",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Result: &terraform.InstanceState{
+				ID: "bar",
+				Attributes: map[string]string{
+					"id":                "bar",
+					"availability_zone": "foo",
+				},
+			},
+		},
+
+		// #9 Sets
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":   "3",
+					"ports.100": "100",
+					"ports.80":  "80",
+					"ports.81":  "81",
+				},
+			},
+
+			Diff: nil,
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":   "3",
+					"ports.80":  "80",
+					"ports.81":  "81",
+					"ports.100": "100",
+				},
+			},
+		},
+
+		// #10
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Set: map[string]interface{}{
+				"ports": []interface{}{100, 80},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":   "2",
+					"ports.80":  "80",
+					"ports.100": "100",
+				},
+			},
+		},
+
+		// #11
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"order": &Schema{
+								Type: TypeInt,
+							},
+
+							"a": &Schema{
+								Type: TypeList,
+								Elem: &Schema{Type: TypeInt},
+							},
+
+							"b": &Schema{
+								Type: TypeList,
+								Elem: &Schema{Type: TypeInt},
+							},
+						},
+					},
+					Set: func(a interface{}) int {
+						m := a.(map[string]interface{})
+						return m["order"].(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":        "2",
+					"ports.10.order": "10",
+					"ports.10.a.#":   "1",
+					"ports.10.a.0":   "80",
+					"ports.20.order": "20",
+					"ports.20.b.#":   "1",
+					"ports.20.b.0":   "100",
+				},
+			},
+
+			Set: map[string]interface{}{
+				"ports": []interface{}{
+					map[string]interface{}{
+						"order": 20,
+						"b":     []interface{}{100},
+					},
+					map[string]interface{}{
+						"order": 10,
+						"a":     []interface{}{80},
+					},
+				},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":        "2",
+					"ports.10.order": "10",
+					"ports.10.a.#":   "1",
+					"ports.10.a.0":   "80",
+					"ports.10.b.#":   "0",
+					"ports.20.order": "20",
+					"ports.20.a.#":   "0",
+					"ports.20.b.#":   "1",
+					"ports.20.b.0":   "100",
+				},
+			},
+		},
+
+		/*
+		 * PARTIAL STATES
+		 */
+
+		// #12 Basic primitive
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "foo",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Partial: []string{},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{},
+			},
+		},
+
+		// #13 List
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "1",
+					"ports.0": "80",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "1",
+						New: "2",
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "100",
+					},
+				},
+			},
+
+			Partial: []string{},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "1",
+					"ports.0": "80",
+				},
+			},
+		},
+
+		// #14
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Partial: []string{},
+
+			Set: map[string]interface{}{
+				"ports": []interface{}{},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{},
+			},
+		},
+
+		// #15 List of resources
+		{
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"from": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+						},
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ingress.#":      "1",
+					"ingress.0.from": "80",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ingress.#": &terraform.ResourceAttrDiff{
+						Old: "1",
+						New: "2",
+					},
+					"ingress.0.from": &terraform.ResourceAttrDiff{
+						Old: "80",
+						New: "150",
+					},
+					"ingress.1.from": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "100",
+					},
+				},
+			},
+
+			Partial: []string{},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ingress.#":      "1",
+					"ingress.0.from": "80",
+				},
+			},
+		},
+
+		// #16 List of maps
+		{
+			Schema: map[string]*Schema{
+				"config_vars": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					Elem: &Schema{
+						Type: TypeMap,
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"config_vars.#":     "2",
+					"config_vars.0.foo": "bar",
+					"config_vars.0.bar": "bar",
+					"config_vars.1.bar": "baz",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config_vars.0.bar": &terraform.ResourceAttrDiff{
+						NewRemoved: true,
+					},
+				},
+			},
+
+			Set: map[string]interface{}{
+				"config_vars": []map[string]interface{}{
+					map[string]interface{}{
+						"foo": "bar",
+					},
+					map[string]interface{}{
+						"baz": "bang",
+					},
+				},
+			},
+
+			Partial: []string{},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					// TODO: broken, shouldn't bar be removed?
+					"config_vars.#":     "2",
+					"config_vars.0.%":   "2",
+					"config_vars.0.foo": "bar",
+					"config_vars.0.bar": "bar",
+					"config_vars.1.%":   "1",
+					"config_vars.1.bar": "baz",
+				},
+			},
+		},
+
+		// #17 Sets
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":   "3",
+					"ports.100": "100",
+					"ports.80":  "80",
+					"ports.81":  "81",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.120": &terraform.ResourceAttrDiff{
+						New: "120",
+					},
+				},
+			},
+
+			Partial: []string{},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":   "3",
+					"ports.80":  "80",
+					"ports.81":  "81",
+					"ports.100": "100",
+				},
+			},
+		},
+
+		// #18
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Partial: []string{},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{},
+			},
+		},
+
+		// #19 Maps
+		{
+			Schema: map[string]*Schema{
+				"tags": &Schema{
+					Type:     TypeMap,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"tags.Name": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+				},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"tags.%":    "1",
+					"tags.Name": "foo",
+				},
+			},
+		},
+
+		// #20 empty computed map
+		{
+			Schema: map[string]*Schema{
+				"tags": &Schema{
+					Type:     TypeMap,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"tags.Name": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+				},
+			},
+
+			Set: map[string]interface{}{
+				"tags": map[string]string{},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"tags.%": "0",
+				},
+			},
+		},
+
+		// #21
+		{
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						NewComputed: true,
+					},
+				},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{},
+			},
+		},
+
+		// #22
+		{
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						NewComputed: true,
+					},
+				},
+			},
+
+			Set: map[string]interface{}{
+				"foo": "bar",
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+				},
+			},
+		},
+
+		// #23 Set of maps
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"index": &Schema{Type: TypeInt},
+							"uuids": &Schema{Type: TypeMap},
+						},
+					},
+					Set: func(a interface{}) int {
+						m := a.(map[string]interface{})
+						return m["index"].(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.10.uuids.#": &terraform.ResourceAttrDiff{
+						NewComputed: true,
+					},
+				},
+			},
+
+			Set: map[string]interface{}{
+				"ports": []interface{}{
+					map[string]interface{}{
+						"index": 10,
+						"uuids": map[string]interface{}{
+							"80": "value",
+						},
+					},
+				},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":           "1",
+					"ports.10.index":    "10",
+					"ports.10.uuids.%":  "1",
+					"ports.10.uuids.80": "value",
+				},
+			},
+		},
+
+		// #24
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":   "3",
+					"ports.100": "100",
+					"ports.80":  "80",
+					"ports.81":  "81",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "3",
+						New: "0",
+					},
+				},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "0",
+				},
+			},
+		},
+
+		// #25
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Set: map[string]interface{}{
+				"ports": []interface{}{},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "0",
+				},
+			},
+		},
+
+		// #26
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: nil,
+
+			Diff: nil,
+
+			Set: map[string]interface{}{
+				"ports": []interface{}{},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "0",
+				},
+			},
+		},
+
+		// #27 Set lists
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"index": &Schema{Type: TypeInt},
+							"uuids": &Schema{Type: TypeMap},
+						},
+					},
+				},
+			},
+
+			State: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						NewComputed: true,
+					},
+				},
+			},
+
+			Set: map[string]interface{}{
+				"ports": []interface{}{
+					map[string]interface{}{
+						"index": 10,
+						"uuids": map[string]interface{}{
+							"80": "value",
+						},
+					},
+				},
+			},
+
+			Result: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#":          "1",
+					"ports.0.index":    "10",
+					"ports.0.uuids.%":  "1",
+					"ports.0.uuids.80": "value",
+				},
+			},
+		},
+	}
+
+	for i, tc := range cases {
+		d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		for k, v := range tc.Set {
+			if err := d.Set(k, v); err != nil {
+				t.Fatalf("%d err: %s", i, err)
+			}
+		}
+
+		// Set an ID so that the state returned is not nil
+		idSet := false
+		if d.Id() == "" {
+			idSet = true
+			d.SetId("foo")
+		}
+
+		// If we have partial, then enable partial state mode.
+		if tc.Partial != nil {
+			d.Partial(true)
+			for _, k := range tc.Partial {
+				d.SetPartial(k)
+			}
+		}
+
+		actual := d.State()
+
+		// If we set an ID, then undo what we did so the comparison works
+		if actual != nil && idSet {
+			actual.ID = ""
+			delete(actual.Attributes, "id")
+		}
+
+		if !reflect.DeepEqual(actual, tc.Result) {
+			t.Fatalf("Bad: %d\n\n%#v\n\nExpected:\n\n%#v", i, actual, tc.Result)
+		}
+	}
+}
+
+func TestResourceData_nonStringValuesInMap(t *testing.T) {
+	cases := []struct {
+		Schema       map[string]*Schema
+		Diff         *terraform.InstanceDiff
+		MapFieldName string
+		ItemName     string
+		ExpectedType string
+	}{
+		{
+			Schema: map[string]*Schema{
+				"boolMap": &Schema{
+					Type:     TypeMap,
+					Elem:     TypeBool,
+					Optional: true,
+				},
+			},
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"boolMap.%": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"boolMap.boolField": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "true",
+					},
+				},
+			},
+			MapFieldName: "boolMap",
+			ItemName:     "boolField",
+			ExpectedType: "bool",
+		},
+		{
+			Schema: map[string]*Schema{
+				"intMap": &Schema{
+					Type:     TypeMap,
+					Elem:     TypeInt,
+					Optional: true,
+				},
+			},
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"intMap.%": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"intMap.intField": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "8",
+					},
+				},
+			},
+			MapFieldName: "intMap",
+			ItemName:     "intField",
+			ExpectedType: "int",
+		},
+		{
+			Schema: map[string]*Schema{
+				"floatMap": &Schema{
+					Type:     TypeMap,
+					Elem:     TypeFloat,
+					Optional: true,
+				},
+			},
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"floatMap.%": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"floatMap.floatField": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "8.22",
+					},
+				},
+			},
+			MapFieldName: "floatMap",
+			ItemName:     "floatField",
+			ExpectedType: "float64",
+		},
+	}
+
+	for _, c := range cases {
+		d, err := schemaMap(c.Schema).Data(nil, c.Diff)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		m, ok := d.Get(c.MapFieldName).(map[string]interface{})
+		if !ok {
+			t.Fatalf("expected %q to be castable to a map", c.MapFieldName)
+		}
+		field, ok := m[c.ItemName]
+		if !ok {
+			t.Fatalf("expected %q in the map", c.ItemName)
+		}
+
+		typeName := reflect.TypeOf(field).Name()
+		if typeName != c.ExpectedType {
+			t.Fatalf("expected %q to be %q, it is %q.",
+				c.ItemName, c.ExpectedType, typeName)
+		}
+	}
+}
+
+func TestResourceDataSetConnInfo(t *testing.T) {
+	d := &ResourceData{}
+	d.SetId("foo")
+	d.SetConnInfo(map[string]string{
+		"foo": "bar",
+	})
+
+	expected := map[string]string{
+		"foo": "bar",
+	}
+
+	actual := d.State()
+	if !reflect.DeepEqual(actual.Ephemeral.ConnInfo, expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceDataSetMeta_Timeouts(t *testing.T) {
+	d := &ResourceData{}
+	d.SetId("foo")
+
+	rt := ResourceTimeout{
+		Create: DefaultTimeout(7 * time.Minute),
+	}
+
+	d.timeouts = &rt
+
+	expected := expectedForValues(7, 0, 0, 0, 0)
+
+	actual := d.State()
+	if !reflect.DeepEqual(actual.Meta[TimeoutKey], expected) {
+		t.Fatalf("Bad Meta_timeout match:\n\texpected: %#v\n\tgot: %#v", expected, actual.Meta[TimeoutKey])
+	}
+}
+
+func TestResourceDataSetId(t *testing.T) {
+	d := &ResourceData{
+		state: &terraform.InstanceState{
+			ID: "test",
+			Attributes: map[string]string{
+				"id": "test",
+			},
+		},
+	}
+	d.SetId("foo")
+
+	actual := d.State()
+
+	// SetId should set both the ID field as well as the attribute, to aid in
+	// transitioning to the new type system.
+	if actual.ID != "foo" || actual.Attributes["id"] != "foo" {
+		t.Fatalf("bad: %#v", actual)
+	}
+
+	d.SetId("")
+	actual = d.State()
+	if actual != nil {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceDataSetId_clear(t *testing.T) {
+	d := &ResourceData{
+		state: &terraform.InstanceState{ID: "bar"},
+	}
+	d.SetId("")
+
+	actual := d.State()
+	if actual != nil {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceDataSetId_override(t *testing.T) {
+	d := &ResourceData{
+		state: &terraform.InstanceState{ID: "bar"},
+	}
+	d.SetId("foo")
+
+	actual := d.State()
+	if actual.ID != "foo" {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceDataSetType(t *testing.T) {
+	d := &ResourceData{}
+	d.SetId("foo")
+	d.SetType("bar")
+
+	actual := d.State()
+	if v := actual.Ephemeral.Type; v != "bar" {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func testPtrTo(raw interface{}) interface{} {
+	return &raw
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/resource_diff.go b/v1.5.7/internal/legacy/helper/schema/resource_diff.go
new file mode 100644
index 0000000..67c8c66
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/resource_diff.go
@@ -0,0 +1,562 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+// newValueWriter is a minor re-implementation of MapFieldWriter to include
+// keys that should be marked as computed, to represent the new part of a
+// pseudo-diff.
+type newValueWriter struct {
+	*MapFieldWriter
+
+	// A list of keys that should be marked as computed.
+	computedKeys map[string]bool
+
+	// A lock to prevent races on writes. The underlying writer will have one as
+	// well - this is for computed keys.
+	lock sync.Mutex
+
+	// To be used with init.
+	once sync.Once
+}
+
+// init performs any initialization tasks for the newValueWriter.
+func (w *newValueWriter) init() {
+	if w.computedKeys == nil {
+		w.computedKeys = make(map[string]bool)
+	}
+}
+
+// WriteField overrides MapValueWriter's WriteField, adding the ability to flag
+// the address as computed.
+func (w *newValueWriter) WriteField(address []string, value interface{}, computed bool) error {
+	// Fail the write if we have a non-nil value and computed is true.
+	// NewComputed values should not have a value when written.
+	if value != nil && computed {
+		return errors.New("Non-nil value with computed set")
+	}
+
+	if err := w.MapFieldWriter.WriteField(address, value); err != nil {
+		return err
+	}
+
+	w.once.Do(w.init)
+
+	w.lock.Lock()
+	defer w.lock.Unlock()
+	if computed {
+		w.computedKeys[strings.Join(address, ".")] = true
+	}
+	return nil
+}
+
+// ComputedKeysMap returns the underlying computed keys map.
+func (w *newValueWriter) ComputedKeysMap() map[string]bool {
+	w.once.Do(w.init)
+	return w.computedKeys
+}
+
+// newValueReader is a minor re-implementation of MapFieldReader and is the
+// read counterpart to MapValueWriter, allowing the read of keys flagged as
+// computed to accommodate the diff override logic in ResourceDiff.
+type newValueReader struct {
+	*MapFieldReader
+
+	// The list of computed keys from a newValueWriter.
+	computedKeys map[string]bool
+}
+
+// ReadField reads the values from the underlying writer, returning the
+// computed value if it is found as well.
+func (r *newValueReader) ReadField(address []string) (FieldReadResult, error) {
+	addrKey := strings.Join(address, ".")
+	v, err := r.MapFieldReader.ReadField(address)
+	if err != nil {
+		return FieldReadResult{}, err
+	}
+	for computedKey := range r.computedKeys {
+		if childAddrOf(addrKey, computedKey) {
+			if strings.HasSuffix(addrKey, ".#") {
+				// This is a count value for a list or set that has been marked as
+				// computed, or a sub-list/sub-set of a complex resource that has
+				// been marked as computed.  We need to pass through to other readers
+				// so that an accurate previous count can be fetched for the diff.
+				v.Exists = false
+			}
+			v.Computed = true
+		}
+	}
+
+	return v, nil
+}
+
+// ResourceDiff is used to query and make custom changes to an in-flight diff.
+// It can be used to veto particular changes in the diff, customize the diff
+// that has been created, or diff values not controlled by config.
+//
+// The object functions similar to ResourceData, however most notably lacks
+// Set, SetPartial, and Partial, as it should be used to change diff values
+// only.  Most other first-class ResourceData functions exist, namely Get,
+// GetOk, HasChange, and GetChange exist.
+//
+// All functions in ResourceDiff, save for ForceNew, can only be used on
+// computed fields.
+type ResourceDiff struct {
+	// The schema for the resource being worked on.
+	schema map[string]*Schema
+
+	// The current config for this resource.
+	config *terraform.ResourceConfig
+
+	// The state for this resource as it exists post-refresh, after the initial
+	// diff.
+	state *terraform.InstanceState
+
+	// The diff created by Terraform. This diff is used, along with state,
+	// config, and custom-set diff data, to provide a multi-level reader
+	// experience similar to ResourceData.
+	diff *terraform.InstanceDiff
+
+	// The internal reader structure that contains the state, config, the default
+	// diff, and the new diff.
+	multiReader *MultiLevelFieldReader
+
+	// A writer that writes overridden new fields.
+	newWriter *newValueWriter
+
+	// Tracks which keys have been updated by ResourceDiff to ensure that the
+	// diff does not get re-run on keys that were not touched, or diffs that were
+	// just removed (re-running on the latter would just roll back the removal).
+	updatedKeys map[string]bool
+
+	// Tracks which keys were flagged as forceNew. These keys are not saved in
+	// newWriter, but we need to track them so that they can be re-diffed later.
+	forcedNewKeys map[string]bool
+}
+
+// newResourceDiff creates a new ResourceDiff instance.
+func newResourceDiff(schema map[string]*Schema, config *terraform.ResourceConfig, state *terraform.InstanceState, diff *terraform.InstanceDiff) *ResourceDiff {
+	d := &ResourceDiff{
+		config: config,
+		state:  state,
+		diff:   diff,
+		schema: schema,
+	}
+
+	d.newWriter = &newValueWriter{
+		MapFieldWriter: &MapFieldWriter{Schema: d.schema},
+	}
+	readers := make(map[string]FieldReader)
+	var stateAttributes map[string]string
+	if d.state != nil {
+		stateAttributes = d.state.Attributes
+		readers["state"] = &MapFieldReader{
+			Schema: d.schema,
+			Map:    BasicMapReader(stateAttributes),
+		}
+	}
+	if d.config != nil {
+		readers["config"] = &ConfigFieldReader{
+			Schema: d.schema,
+			Config: d.config,
+		}
+	}
+	if d.diff != nil {
+		readers["diff"] = &DiffFieldReader{
+			Schema: d.schema,
+			Diff:   d.diff,
+			Source: &MultiLevelFieldReader{
+				Levels:  []string{"state", "config"},
+				Readers: readers,
+			},
+		}
+	}
+	readers["newDiff"] = &newValueReader{
+		MapFieldReader: &MapFieldReader{
+			Schema: d.schema,
+			Map:    BasicMapReader(d.newWriter.Map()),
+		},
+		computedKeys: d.newWriter.ComputedKeysMap(),
+	}
+	d.multiReader = &MultiLevelFieldReader{
+		Levels: []string{
+			"state",
+			"config",
+			"diff",
+			"newDiff",
+		},
+
+		Readers: readers,
+	}
+
+	d.updatedKeys = make(map[string]bool)
+	d.forcedNewKeys = make(map[string]bool)
+
+	return d
+}
+
+// UpdatedKeys returns the keys that were updated by this ResourceDiff run.
+// These are the only keys that a diff should be re-calculated for.
+//
+// This is the combined result of both keys for which diff values were updated
+// for or cleared, and also keys that were flagged to be re-diffed as a result
+// of ForceNew.
+func (d *ResourceDiff) UpdatedKeys() []string {
+	var s []string
+	for k := range d.updatedKeys {
+		s = append(s, k)
+	}
+	for k := range d.forcedNewKeys {
+		for _, l := range s {
+			if k == l {
+				break
+			}
+		}
+		s = append(s, k)
+	}
+	return s
+}
+
+// Clear wipes the diff for a particular key. It is called by ResourceDiff's
+// functionality to remove any possibility of conflicts, but can be called on
+// its own to just remove a specific key from the diff completely.
+//
+// Note that this does not wipe an override. This function is only allowed on
+// computed keys.
+func (d *ResourceDiff) Clear(key string) error {
+	if err := d.checkKey(key, "Clear", true); err != nil {
+		return err
+	}
+
+	return d.clear(key)
+}
+
+func (d *ResourceDiff) clear(key string) error {
+	// Check the schema to make sure that this key exists first.
+	schemaL := addrToSchema(strings.Split(key, "."), d.schema)
+	if len(schemaL) == 0 {
+		return fmt.Errorf("%s is not a valid key", key)
+	}
+
+	for k := range d.diff.Attributes {
+		if strings.HasPrefix(k, key) {
+			delete(d.diff.Attributes, k)
+		}
+	}
+	return nil
+}
+
+// GetChangedKeysPrefix helps to implement Resource.CustomizeDiff
+// where we need to act on all nested fields
+// without calling out each one separately
+func (d *ResourceDiff) GetChangedKeysPrefix(prefix string) []string {
+	keys := make([]string, 0)
+	for k := range d.diff.Attributes {
+		if strings.HasPrefix(k, prefix) {
+			keys = append(keys, k)
+		}
+	}
+	return keys
+}
+
+// diffChange helps to implement resourceDiffer and derives its change values
+// from ResourceDiff's own change data, in addition to existing diff, config, and state.
+func (d *ResourceDiff) diffChange(key string) (interface{}, interface{}, bool, bool, bool) {
+	old, new, customized := d.getChange(key)
+
+	if !old.Exists {
+		old.Value = nil
+	}
+	if !new.Exists || d.removed(key) {
+		new.Value = nil
+	}
+
+	return old.Value, new.Value, !reflect.DeepEqual(old.Value, new.Value), new.Computed, customized
+}
+
+// SetNew is used to set a new diff value for the mentioned key. The value must
+// be correct for the attribute's schema (mostly relevant for maps, lists, and
+// sets). The original value from the state is used as the old value.
+//
+// This function is only allowed on computed attributes.
+func (d *ResourceDiff) SetNew(key string, value interface{}) error {
+	if err := d.checkKey(key, "SetNew", false); err != nil {
+		return err
+	}
+
+	return d.setDiff(key, value, false)
+}
+
+// SetNewComputed functions like SetNew, except that it blanks out a new value
+// and marks it as computed.
+//
+// This function is only allowed on computed attributes.
+func (d *ResourceDiff) SetNewComputed(key string) error {
+	if err := d.checkKey(key, "SetNewComputed", false); err != nil {
+		return err
+	}
+
+	return d.setDiff(key, nil, true)
+}
+
+// setDiff performs common diff setting behaviour.
+func (d *ResourceDiff) setDiff(key string, new interface{}, computed bool) error {
+	if err := d.clear(key); err != nil {
+		return err
+	}
+
+	if err := d.newWriter.WriteField(strings.Split(key, "."), new, computed); err != nil {
+		return fmt.Errorf("Cannot set new diff value for key %s: %s", key, err)
+	}
+
+	d.updatedKeys[key] = true
+
+	return nil
+}
+
+// ForceNew force-flags ForceNew in the schema for a specific key, and
+// re-calculates its diff, effectively causing this attribute to force a new
+// resource.
+//
+// Keep in mind that forcing a new resource will force a second run of the
+// resource's CustomizeDiff function (with a new ResourceDiff) once the current
+// one has completed. This second run is performed without state. This behavior
+// will be the same as if a new resource is being created and is performed to
+// ensure that the diff looks like the diff for a new resource as much as
+// possible. CustomizeDiff should expect such a scenario and act correctly.
+//
+// This function is a no-op/error if there is no diff.
+//
+// Note that the change to schema is permanent for the lifecycle of this
+// specific ResourceDiff instance.
+func (d *ResourceDiff) ForceNew(key string) error {
+	if !d.HasChange(key) {
+		return fmt.Errorf("ForceNew: No changes for %s", key)
+	}
+
+	keyParts := strings.Split(key, ".")
+	var schema *Schema
+	schemaL := addrToSchema(keyParts, d.schema)
+	if len(schemaL) > 0 {
+		schema = schemaL[len(schemaL)-1]
+	} else {
+		return fmt.Errorf("ForceNew: %s is not a valid key", key)
+	}
+
+	schema.ForceNew = true
+
+	// Flag this for a re-diff. Don't save any values to guarantee that existing
+	// diffs aren't messed with, as this gets messy when dealing with complex
+	// structures, zero values, etc.
+	d.forcedNewKeys[keyParts[0]] = true
+
+	return nil
+}
+
+// Get hands off to ResourceData.Get.
+func (d *ResourceDiff) Get(key string) interface{} {
+	r, _ := d.GetOk(key)
+	return r
+}
+
+// GetChange gets the change between the state and diff, checking first to see
+// if an overridden diff exists.
+//
+// This implementation differs from ResourceData's in the way that we first get
+// results from the exact levels for the new diff, then from state and diff as
+// per normal.
+func (d *ResourceDiff) GetChange(key string) (interface{}, interface{}) {
+	old, new, _ := d.getChange(key)
+	return old.Value, new.Value
+}
+
+// GetOk functions the same way as ResourceData.GetOk, but it also checks the
+// new diff levels to provide data consistent with the current state of the
+// customized diff.
+func (d *ResourceDiff) GetOk(key string) (interface{}, bool) {
+	r := d.get(strings.Split(key, "."), "newDiff")
+	exists := r.Exists && !r.Computed
+	if exists {
+		// If it exists, we also want to verify it is not the zero-value.
+		value := r.Value
+		zero := r.Schema.Type.Zero()
+
+		if eq, ok := value.(Equal); ok {
+			exists = !eq.Equal(zero)
+		} else {
+			exists = !reflect.DeepEqual(value, zero)
+		}
+	}
+
+	return r.Value, exists
+}
+
+// GetOkExists functions the same way as GetOkExists within ResourceData, but
+// it also checks the new diff levels to provide data consistent with the
+// current state of the customized diff.
+//
+// This is nearly the same function as GetOk, yet it does not check
+// for the zero value of the attribute's type. This allows for attributes
+// without a default, to fully check for a literal assignment, regardless
+// of the zero-value for that type.
+func (d *ResourceDiff) GetOkExists(key string) (interface{}, bool) {
+	r := d.get(strings.Split(key, "."), "newDiff")
+	exists := r.Exists && !r.Computed
+	return r.Value, exists
+}
+
+// NewValueKnown returns true if the new value for the given key is available
+// as its final value at diff time. If the return value is false, this means
+// either the value is based of interpolation that was unavailable at diff
+// time, or that the value was explicitly marked as computed by SetNewComputed.
+func (d *ResourceDiff) NewValueKnown(key string) bool {
+	r := d.get(strings.Split(key, "."), "newDiff")
+	return !r.Computed
+}
+
+// HasChange checks to see if there is a change between state and the diff, or
+// in the overridden diff.
+func (d *ResourceDiff) HasChange(key string) bool {
+	old, new := d.GetChange(key)
+
+	// If the type implements the Equal interface, then call that
+	// instead of just doing a reflect.DeepEqual. An example where this is
+	// needed is *Set
+	if eq, ok := old.(Equal); ok {
+		return !eq.Equal(new)
+	}
+
+	return !reflect.DeepEqual(old, new)
+}
+
+// Id returns the ID of this resource.
+//
+// Note that technically, ID does not change during diffs (it either has
+// already changed in the refresh, or will change on update), hence we do not
+// support updating the ID or fetching it from anything else other than state.
+func (d *ResourceDiff) Id() string {
+	var result string
+
+	if d.state != nil {
+		result = d.state.ID
+	}
+	return result
+}
+
+// getChange gets values from two different levels, designed for use in
+// diffChange, HasChange, and GetChange.
+//
+// This implementation differs from ResourceData's in the way that we first get
+// results from the exact levels for the new diff, then from state and diff as
+// per normal.
+func (d *ResourceDiff) getChange(key string) (getResult, getResult, bool) {
+	old := d.get(strings.Split(key, "."), "state")
+	var new getResult
+	for p := range d.updatedKeys {
+		if childAddrOf(key, p) {
+			new = d.getExact(strings.Split(key, "."), "newDiff")
+			return old, new, true
+		}
+	}
+	new = d.get(strings.Split(key, "."), "newDiff")
+	return old, new, false
+}
+
+// removed checks to see if the key is present in the existing, pre-customized
+// diff and if it was marked as NewRemoved.
+func (d *ResourceDiff) removed(k string) bool {
+	diff, ok := d.diff.Attributes[k]
+	if !ok {
+		return false
+	}
+	return diff.NewRemoved
+}
+
+// get performs the appropriate multi-level reader logic for ResourceDiff,
+// starting at source. Refer to newResourceDiff for the level order.
+func (d *ResourceDiff) get(addr []string, source string) getResult {
+	result, err := d.multiReader.ReadFieldMerge(addr, source)
+	if err != nil {
+		panic(err)
+	}
+
+	return d.finalizeResult(addr, result)
+}
+
+// getExact gets an attribute from the exact level referenced by source.
+func (d *ResourceDiff) getExact(addr []string, source string) getResult {
+	result, err := d.multiReader.ReadFieldExact(addr, source)
+	if err != nil {
+		panic(err)
+	}
+
+	return d.finalizeResult(addr, result)
+}
+
+// finalizeResult does some post-processing of the result produced by get and getExact.
+func (d *ResourceDiff) finalizeResult(addr []string, result FieldReadResult) getResult {
+	// If the result doesn't exist, then we set the value to the zero value
+	var schema *Schema
+	if schemaL := addrToSchema(addr, d.schema); len(schemaL) > 0 {
+		schema = schemaL[len(schemaL)-1]
+	}
+
+	if result.Value == nil && schema != nil {
+		result.Value = result.ValueOrZero(schema)
+	}
+
+	// Transform the FieldReadResult into a getResult. It might be worth
+	// merging these two structures one day.
+	return getResult{
+		Value:          result.Value,
+		ValueProcessed: result.ValueProcessed,
+		Computed:       result.Computed,
+		Exists:         result.Exists,
+		Schema:         schema,
+	}
+}
+
+// childAddrOf does a comparison of two addresses to see if one is the child of
+// the other.
+func childAddrOf(child, parent string) bool {
+	cs := strings.Split(child, ".")
+	ps := strings.Split(parent, ".")
+	if len(ps) > len(cs) {
+		return false
+	}
+	return reflect.DeepEqual(ps, cs[:len(ps)])
+}
+
+// checkKey checks the key to make sure it exists and is computed.
+func (d *ResourceDiff) checkKey(key, caller string, nested bool) error {
+	var schema *Schema
+	if nested {
+		keyParts := strings.Split(key, ".")
+		schemaL := addrToSchema(keyParts, d.schema)
+		if len(schemaL) > 0 {
+			schema = schemaL[len(schemaL)-1]
+		}
+	} else {
+		s, ok := d.schema[key]
+		if ok {
+			schema = s
+		}
+	}
+	if schema == nil {
+		return fmt.Errorf("%s: invalid key: %s", caller, key)
+	}
+	if !schema.Computed {
+		return fmt.Errorf("%s only operates on computed keys - %s is not one", caller, key)
+	}
+	return nil
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/resource_diff_test.go b/v1.5.7/internal/legacy/helper/schema/resource_diff_test.go
new file mode 100644
index 0000000..6c20035
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/resource_diff_test.go
@@ -0,0 +1,2048 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"fmt"
+	"reflect"
+	"sort"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+// testSetFunc is a very simple function we use to test a foo/bar complex set.
+// Both "foo" and "bar" are int values.
+//
+// This is not foolproof as since it performs sums, you can run into
+// collisions. Spec tests accordingly. :P
+func testSetFunc(v interface{}) int {
+	m := v.(map[string]interface{})
+	return m["foo"].(int) + m["bar"].(int)
+}
+
+// resourceDiffTestCase provides a test case struct for SetNew and SetDiff.
+type resourceDiffTestCase struct {
+	Name          string
+	Schema        map[string]*Schema
+	State         *terraform.InstanceState
+	Config        *terraform.ResourceConfig
+	Diff          *terraform.InstanceDiff
+	Key           string
+	OldValue      interface{}
+	NewValue      interface{}
+	Expected      *terraform.InstanceDiff
+	ExpectedKeys  []string
+	ExpectedError bool
+}
+
+// testDiffCases produces a list of test cases for use with SetNew and SetDiff.
+func testDiffCases(t *testing.T, oldPrefix string, oldOffset int, computed bool) []resourceDiffTestCase {
+	return []resourceDiffTestCase{
+		resourceDiffTestCase{
+			Name: "basic primitive diff",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": "baz",
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: "baz",
+					},
+				},
+			},
+			Key:      "foo",
+			NewValue: "qux",
+			Expected: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: func() string {
+							if computed {
+								return ""
+							}
+							return "qux"
+						}(),
+						NewComputed: computed,
+					},
+				},
+			},
+		},
+		resourceDiffTestCase{
+			Name: "basic set diff",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeString},
+					Set:      HashString,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo.#":          "1",
+					"foo.1996459178": "bar",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": []interface{}{"baz"},
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo.1996459178": &terraform.ResourceAttrDiff{
+						Old:        "bar",
+						New:        "",
+						NewRemoved: true,
+					},
+					"foo.2015626392": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "baz",
+					},
+				},
+			},
+			Key:      "foo",
+			NewValue: []interface{}{"qux"},
+			Expected: &terraform.InstanceDiff{
+				Attributes: func() map[string]*terraform.ResourceAttrDiff {
+					result := map[string]*terraform.ResourceAttrDiff{}
+					if computed {
+						result["foo.#"] = &terraform.ResourceAttrDiff{
+							Old:         "1",
+							New:         "",
+							NewComputed: true,
+						}
+					} else {
+						result["foo.2800005064"] = &terraform.ResourceAttrDiff{
+							Old: "",
+							New: "qux",
+						}
+						result["foo.1996459178"] = &terraform.ResourceAttrDiff{
+							Old:        "bar",
+							New:        "",
+							NewRemoved: true,
+						}
+					}
+					return result
+				}(),
+			},
+		},
+		resourceDiffTestCase{
+			Name: "basic list diff",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeString},
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo.#": "1",
+					"foo.0": "bar",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": []interface{}{"baz"},
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo.0": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: "baz",
+					},
+				},
+			},
+			Key:      "foo",
+			NewValue: []interface{}{"qux"},
+			Expected: &terraform.InstanceDiff{
+				Attributes: func() map[string]*terraform.ResourceAttrDiff {
+					result := make(map[string]*terraform.ResourceAttrDiff)
+					if computed {
+						result["foo.#"] = &terraform.ResourceAttrDiff{
+							Old:         "1",
+							New:         "",
+							NewComputed: true,
+						}
+					} else {
+						result["foo.0"] = &terraform.ResourceAttrDiff{
+							Old: "bar",
+							New: "qux",
+						}
+					}
+					return result
+				}(),
+			},
+		},
+		resourceDiffTestCase{
+			Name: "basic map diff",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeMap,
+					Optional: true,
+					Computed: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo.%":   "1",
+					"foo.bar": "baz",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": map[string]interface{}{"bar": "qux"},
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo.bar": &terraform.ResourceAttrDiff{
+						Old: "baz",
+						New: "qux",
+					},
+				},
+			},
+			Key:      "foo",
+			NewValue: map[string]interface{}{"bar": "quux"},
+			Expected: &terraform.InstanceDiff{
+				Attributes: func() map[string]*terraform.ResourceAttrDiff {
+					result := make(map[string]*terraform.ResourceAttrDiff)
+					if computed {
+						result["foo.%"] = &terraform.ResourceAttrDiff{
+							Old:         "",
+							New:         "",
+							NewComputed: true,
+						}
+						result["foo.bar"] = &terraform.ResourceAttrDiff{
+							Old:        "baz",
+							New:        "",
+							NewRemoved: true,
+						}
+					} else {
+						result["foo.bar"] = &terraform.ResourceAttrDiff{
+							Old: "baz",
+							New: "quux",
+						}
+					}
+					return result
+				}(),
+			},
+		},
+		resourceDiffTestCase{
+			Name: "additional diff with primitive",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Optional: true,
+				},
+				"one": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+					"one": "two",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": "baz",
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: "baz",
+					},
+				},
+			},
+			Key:      "one",
+			NewValue: "four",
+			Expected: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: "baz",
+					},
+					"one": &terraform.ResourceAttrDiff{
+						Old: "two",
+						New: func() string {
+							if computed {
+								return ""
+							}
+							return "four"
+						}(),
+						NewComputed: computed,
+					},
+				},
+			},
+		},
+		resourceDiffTestCase{
+			Name: "additional diff with primitive computed only",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Optional: true,
+				},
+				"one": &Schema{
+					Type:     TypeString,
+					Computed: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+					"one": "two",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": "baz",
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: "baz",
+					},
+				},
+			},
+			Key:      "one",
+			NewValue: "three",
+			Expected: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: "baz",
+					},
+					"one": &terraform.ResourceAttrDiff{
+						Old: "two",
+						New: func() string {
+							if computed {
+								return ""
+							}
+							return "three"
+						}(),
+						NewComputed: computed,
+					},
+				},
+			},
+		},
+		resourceDiffTestCase{
+			Name: "complex-ish set diff",
+			Schema: map[string]*Schema{
+				"top": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"foo": &Schema{
+								Type:     TypeInt,
+								Optional: true,
+								Computed: true,
+							},
+							"bar": &Schema{
+								Type:     TypeInt,
+								Optional: true,
+								Computed: true,
+							},
+						},
+					},
+					Set: testSetFunc,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"top.#":      "2",
+					"top.3.foo":  "1",
+					"top.3.bar":  "2",
+					"top.23.foo": "11",
+					"top.23.bar": "12",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"top": []interface{}{
+					map[string]interface{}{
+						"foo": 1,
+						"bar": 3,
+					},
+					map[string]interface{}{
+						"foo": 12,
+						"bar": 12,
+					},
+				},
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"top.4.foo": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"top.4.bar": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "3",
+					},
+					"top.24.foo": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "12",
+					},
+					"top.24.bar": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "12",
+					},
+				},
+			},
+			Key: "top",
+			NewValue: NewSet(testSetFunc, []interface{}{
+				map[string]interface{}{
+					"foo": 1,
+					"bar": 4,
+				},
+				map[string]interface{}{
+					"foo": 13,
+					"bar": 12,
+				},
+				map[string]interface{}{
+					"foo": 21,
+					"bar": 22,
+				},
+			}),
+			Expected: &terraform.InstanceDiff{
+				Attributes: func() map[string]*terraform.ResourceAttrDiff {
+					result := make(map[string]*terraform.ResourceAttrDiff)
+					if computed {
+						result["top.#"] = &terraform.ResourceAttrDiff{
+							Old:         "2",
+							New:         "",
+							NewComputed: true,
+						}
+					} else {
+						result["top.#"] = &terraform.ResourceAttrDiff{
+							Old: "2",
+							New: "3",
+						}
+						result["top.5.foo"] = &terraform.ResourceAttrDiff{
+							Old: "",
+							New: "1",
+						}
+						result["top.5.bar"] = &terraform.ResourceAttrDiff{
+							Old: "",
+							New: "4",
+						}
+						result["top.25.foo"] = &terraform.ResourceAttrDiff{
+							Old: "",
+							New: "13",
+						}
+						result["top.25.bar"] = &terraform.ResourceAttrDiff{
+							Old: "",
+							New: "12",
+						}
+						result["top.43.foo"] = &terraform.ResourceAttrDiff{
+							Old: "",
+							New: "21",
+						}
+						result["top.43.bar"] = &terraform.ResourceAttrDiff{
+							Old: "",
+							New: "22",
+						}
+					}
+					return result
+				}(),
+			},
+		},
+		resourceDiffTestCase{
+			Name: "primitive, no diff, no refresh",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Computed: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+				},
+			},
+			Config:   testConfig(t, map[string]interface{}{}),
+			Diff:     &terraform.InstanceDiff{Attributes: map[string]*terraform.ResourceAttrDiff{}},
+			Key:      "foo",
+			NewValue: "baz",
+			Expected: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: func() string {
+							if computed {
+								return ""
+							}
+							return "baz"
+						}(),
+						NewComputed: computed,
+					},
+				},
+			},
+		},
+		resourceDiffTestCase{
+			Name: "non-computed key, should error",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Required: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": "baz",
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: "baz",
+					},
+				},
+			},
+			Key:           "foo",
+			NewValue:      "qux",
+			ExpectedError: true,
+		},
+		resourceDiffTestCase{
+			Name: "bad key, should error",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Required: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": "baz",
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: "baz",
+					},
+				},
+			},
+			Key:           "bad",
+			NewValue:      "qux",
+			ExpectedError: true,
+		},
+		resourceDiffTestCase{
+			// NOTE: This case is technically impossible in the current
+			// implementation, because optional+computed values never show up in the
+			// diff, and we actually clear existing diffs when SetNew or
+			// SetNewComputed is run.  This test is here to ensure that if either of
+			// these behaviors change that we don't introduce regressions.
+			Name: "NewRemoved in diff for Optional and Computed, should be fully overridden",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old:        "bar",
+						New:        "",
+						NewRemoved: true,
+					},
+				},
+			},
+			Key:      "foo",
+			NewValue: "qux",
+			Expected: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: func() string {
+							if computed {
+								return ""
+							}
+							return "qux"
+						}(),
+						NewComputed: computed,
+					},
+				},
+			},
+		},
+		resourceDiffTestCase{
+			Name: "NewComputed should always propagate",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Computed: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "",
+				},
+				ID: "pre-existing",
+			},
+			Config:   testConfig(t, map[string]interface{}{}),
+			Diff:     &terraform.InstanceDiff{Attributes: map[string]*terraform.ResourceAttrDiff{}},
+			Key:      "foo",
+			NewValue: "",
+			Expected: &terraform.InstanceDiff{
+				Attributes: func() map[string]*terraform.ResourceAttrDiff {
+					if computed {
+						return map[string]*terraform.ResourceAttrDiff{
+							"foo": &terraform.ResourceAttrDiff{
+								NewComputed: computed,
+							},
+						}
+					}
+					return map[string]*terraform.ResourceAttrDiff{}
+				}(),
+			},
+		},
+	}
+}
+
+func TestSetNew(t *testing.T) {
+	testCases := testDiffCases(t, "", 0, false)
+	for _, tc := range testCases {
+		t.Run(tc.Name, func(t *testing.T) {
+			m := schemaMap(tc.Schema)
+			d := newResourceDiff(tc.Schema, tc.Config, tc.State, tc.Diff)
+			err := d.SetNew(tc.Key, tc.NewValue)
+			switch {
+			case err != nil && !tc.ExpectedError:
+				t.Fatalf("bad: %s", err)
+			case err == nil && tc.ExpectedError:
+				t.Fatalf("Expected error, got none")
+			case err != nil && tc.ExpectedError:
+				return
+			}
+			for _, k := range d.UpdatedKeys() {
+				if err := m.diff(k, m[k], tc.Diff, d, false); err != nil {
+					t.Fatalf("bad: %s", err)
+				}
+			}
+			if !reflect.DeepEqual(tc.Expected, tc.Diff) {
+				t.Fatalf("Expected %s, got %s", spew.Sdump(tc.Expected), spew.Sdump(tc.Diff))
+			}
+		})
+	}
+}
+
+func TestSetNewComputed(t *testing.T) {
+	testCases := testDiffCases(t, "", 0, true)
+	for _, tc := range testCases {
+		t.Run(tc.Name, func(t *testing.T) {
+			m := schemaMap(tc.Schema)
+			d := newResourceDiff(tc.Schema, tc.Config, tc.State, tc.Diff)
+			err := d.SetNewComputed(tc.Key)
+			switch {
+			case err != nil && !tc.ExpectedError:
+				t.Fatalf("bad: %s", err)
+			case err == nil && tc.ExpectedError:
+				t.Fatalf("Expected error, got none")
+			case err != nil && tc.ExpectedError:
+				return
+			}
+			for _, k := range d.UpdatedKeys() {
+				if err := m.diff(k, m[k], tc.Diff, d, false); err != nil {
+					t.Fatalf("bad: %s", err)
+				}
+			}
+			if !reflect.DeepEqual(tc.Expected, tc.Diff) {
+				t.Fatalf("Expected %s, got %s", spew.Sdump(tc.Expected), spew.Sdump(tc.Diff))
+			}
+		})
+	}
+}
+
+func TestForceNew(t *testing.T) {
+	cases := []resourceDiffTestCase{
+		resourceDiffTestCase{
+			Name: "basic primitive diff",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": "baz",
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: "baz",
+					},
+				},
+			},
+			Key: "foo",
+			Expected: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old:         "bar",
+						New:         "baz",
+						RequiresNew: true,
+					},
+				},
+			},
+		},
+		resourceDiffTestCase{
+			Name: "no change, should error",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": "bar",
+			}),
+			ExpectedError: true,
+		},
+		resourceDiffTestCase{
+			Name: "basic primitive, non-computed key",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Required: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": "baz",
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: "baz",
+					},
+				},
+			},
+			Key: "foo",
+			Expected: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old:         "bar",
+						New:         "baz",
+						RequiresNew: true,
+					},
+				},
+			},
+		},
+		resourceDiffTestCase{
+			Name: "nested field",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeList,
+					Required: true,
+					MaxItems: 1,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"bar": {
+								Type:     TypeString,
+								Optional: true,
+							},
+							"baz": {
+								Type:     TypeString,
+								Optional: true,
+							},
+						},
+					},
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo.#":     "1",
+					"foo.0.bar": "abc",
+					"foo.0.baz": "xyz",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": []interface{}{
+					map[string]interface{}{
+						"bar": "abcdefg",
+						"baz": "changed",
+					},
+				},
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo.0.bar": &terraform.ResourceAttrDiff{
+						Old: "abc",
+						New: "abcdefg",
+					},
+					"foo.0.baz": &terraform.ResourceAttrDiff{
+						Old: "xyz",
+						New: "changed",
+					},
+				},
+			},
+			Key: "foo.0.baz",
+			Expected: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo.0.bar": &terraform.ResourceAttrDiff{
+						Old: "abc",
+						New: "abcdefg",
+					},
+					"foo.0.baz": &terraform.ResourceAttrDiff{
+						Old:         "xyz",
+						New:         "changed",
+						RequiresNew: true,
+					},
+				},
+			},
+		},
+		resourceDiffTestCase{
+			Name: "preserve NewRemoved on existing diff",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Optional: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old:        "bar",
+						New:        "",
+						NewRemoved: true,
+					},
+				},
+			},
+			Key: "foo",
+			Expected: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old:         "bar",
+						New:         "",
+						RequiresNew: true,
+						NewRemoved:  true,
+					},
+				},
+			},
+		},
+		resourceDiffTestCase{
+			Name: "nested field, preserve original diff without zero values",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeList,
+					Required: true,
+					MaxItems: 1,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"bar": {
+								Type:     TypeString,
+								Optional: true,
+							},
+							"baz": {
+								Type:     TypeInt,
+								Optional: true,
+							},
+						},
+					},
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo.#":     "1",
+					"foo.0.bar": "abc",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": []interface{}{
+					map[string]interface{}{
+						"bar": "abcdefg",
+					},
+				},
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo.0.bar": &terraform.ResourceAttrDiff{
+						Old: "abc",
+						New: "abcdefg",
+					},
+				},
+			},
+			Key: "foo.0.bar",
+			Expected: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo.0.bar": &terraform.ResourceAttrDiff{
+						Old:         "abc",
+						New:         "abcdefg",
+						RequiresNew: true,
+					},
+				},
+			},
+		},
+	}
+	for _, tc := range cases {
+		t.Run(tc.Name, func(t *testing.T) {
+			m := schemaMap(tc.Schema)
+			d := newResourceDiff(m, tc.Config, tc.State, tc.Diff)
+			err := d.ForceNew(tc.Key)
+			switch {
+			case err != nil && !tc.ExpectedError:
+				t.Fatalf("bad: %s", err)
+			case err == nil && tc.ExpectedError:
+				t.Fatalf("Expected error, got none")
+			case err != nil && tc.ExpectedError:
+				return
+			}
+			for _, k := range d.UpdatedKeys() {
+				if err := m.diff(k, m[k], tc.Diff, d, false); err != nil {
+					t.Fatalf("bad: %s", err)
+				}
+			}
+			if !reflect.DeepEqual(tc.Expected, tc.Diff) {
+				t.Fatalf("Expected %s, got %s", spew.Sdump(tc.Expected), spew.Sdump(tc.Diff))
+			}
+		})
+	}
+}
+
+func TestClear(t *testing.T) {
+	cases := []resourceDiffTestCase{
+		resourceDiffTestCase{
+			Name: "basic primitive diff",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": "baz",
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: "baz",
+					},
+				},
+			},
+			Key:      "foo",
+			Expected: &terraform.InstanceDiff{Attributes: map[string]*terraform.ResourceAttrDiff{}},
+		},
+		resourceDiffTestCase{
+			Name: "non-computed key, should error",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Required: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": "baz",
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: "baz",
+					},
+				},
+			},
+			Key:           "foo",
+			ExpectedError: true,
+		},
+		resourceDiffTestCase{
+			Name: "multi-value, one removed",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+				"one": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+					"one": "two",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": "baz",
+				"one": "three",
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: "baz",
+					},
+					"one": &terraform.ResourceAttrDiff{
+						Old: "two",
+						New: "three",
+					},
+				},
+			},
+			Key: "one",
+			Expected: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: "baz",
+					},
+				},
+			},
+		},
+		resourceDiffTestCase{
+			Name: "basic sub-block diff",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"bar": &Schema{
+								Type:     TypeString,
+								Optional: true,
+								Computed: true,
+							},
+							"baz": &Schema{
+								Type:     TypeString,
+								Optional: true,
+								Computed: true,
+							},
+						},
+					},
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo.0.bar": "bar1",
+					"foo.0.baz": "baz1",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": []interface{}{
+					map[string]interface{}{
+						"bar": "bar2",
+						"baz": "baz1",
+					},
+				},
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo.0.bar": &terraform.ResourceAttrDiff{
+						Old: "bar1",
+						New: "bar2",
+					},
+				},
+			},
+			Key:      "foo.0.bar",
+			Expected: &terraform.InstanceDiff{Attributes: map[string]*terraform.ResourceAttrDiff{}},
+		},
+		resourceDiffTestCase{
+			Name: "sub-block diff only partial clear",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"bar": &Schema{
+								Type:     TypeString,
+								Optional: true,
+								Computed: true,
+							},
+							"baz": &Schema{
+								Type:     TypeString,
+								Optional: true,
+								Computed: true,
+							},
+						},
+					},
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo.0.bar": "bar1",
+					"foo.0.baz": "baz1",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": []interface{}{
+					map[string]interface{}{
+						"bar": "bar2",
+						"baz": "baz2",
+					},
+				},
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo.0.bar": &terraform.ResourceAttrDiff{
+						Old: "bar1",
+						New: "bar2",
+					},
+					"foo.0.baz": &terraform.ResourceAttrDiff{
+						Old: "baz1",
+						New: "baz2",
+					},
+				},
+			},
+			Key: "foo.0.bar",
+			Expected: &terraform.InstanceDiff{Attributes: map[string]*terraform.ResourceAttrDiff{
+				"foo.0.baz": &terraform.ResourceAttrDiff{
+					Old: "baz1",
+					New: "baz2",
+				},
+			}},
+		},
+	}
+	for _, tc := range cases {
+		t.Run(tc.Name, func(t *testing.T) {
+			m := schemaMap(tc.Schema)
+			d := newResourceDiff(m, tc.Config, tc.State, tc.Diff)
+			err := d.Clear(tc.Key)
+			switch {
+			case err != nil && !tc.ExpectedError:
+				t.Fatalf("bad: %s", err)
+			case err == nil && tc.ExpectedError:
+				t.Fatalf("Expected error, got none")
+			case err != nil && tc.ExpectedError:
+				return
+			}
+			for _, k := range d.UpdatedKeys() {
+				if err := m.diff(k, m[k], tc.Diff, d, false); err != nil {
+					t.Fatalf("bad: %s", err)
+				}
+			}
+			if !reflect.DeepEqual(tc.Expected, tc.Diff) {
+				t.Fatalf("Expected %s, got %s", spew.Sdump(tc.Expected), spew.Sdump(tc.Diff))
+			}
+		})
+	}
+}
+
+func TestGetChangedKeysPrefix(t *testing.T) {
+	cases := []resourceDiffTestCase{
+		resourceDiffTestCase{
+			Name: "basic primitive diff",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"foo": "baz",
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old: "bar",
+						New: "baz",
+					},
+				},
+			},
+			Key: "foo",
+			ExpectedKeys: []string{
+				"foo",
+			},
+		},
+		resourceDiffTestCase{
+			Name: "nested field filtering",
+			Schema: map[string]*Schema{
+				"testfield": &Schema{
+					Type:     TypeString,
+					Required: true,
+				},
+				"foo": &Schema{
+					Type:     TypeList,
+					Required: true,
+					MaxItems: 1,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"bar": {
+								Type:     TypeString,
+								Optional: true,
+							},
+							"baz": {
+								Type:     TypeString,
+								Optional: true,
+							},
+						},
+					},
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"testfield": "blablah",
+					"foo.#":     "1",
+					"foo.0.bar": "abc",
+					"foo.0.baz": "xyz",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"testfield": "modified",
+				"foo": []interface{}{
+					map[string]interface{}{
+						"bar": "abcdefg",
+						"baz": "changed",
+					},
+				},
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"testfield": &terraform.ResourceAttrDiff{
+						Old: "blablah",
+						New: "modified",
+					},
+					"foo.0.bar": &terraform.ResourceAttrDiff{
+						Old: "abc",
+						New: "abcdefg",
+					},
+					"foo.0.baz": &terraform.ResourceAttrDiff{
+						Old: "xyz",
+						New: "changed",
+					},
+				},
+			},
+			Key: "foo",
+			ExpectedKeys: []string{
+				"foo.0.bar",
+				"foo.0.baz",
+			},
+		},
+	}
+	for _, tc := range cases {
+		t.Run(tc.Name, func(t *testing.T) {
+			m := schemaMap(tc.Schema)
+			d := newResourceDiff(m, tc.Config, tc.State, tc.Diff)
+			keys := d.GetChangedKeysPrefix(tc.Key)
+
+			for _, k := range d.UpdatedKeys() {
+				if err := m.diff(k, m[k], tc.Diff, d, false); err != nil {
+					t.Fatalf("bad: %s", err)
+				}
+			}
+
+			sort.Strings(keys)
+
+			if !reflect.DeepEqual(tc.ExpectedKeys, keys) {
+				t.Fatalf("Expected %s, got %s", spew.Sdump(tc.ExpectedKeys), spew.Sdump(keys))
+			}
+		})
+	}
+}
+
+func TestResourceDiffGetOkExists(t *testing.T) {
+	cases := []struct {
+		Name   string
+		Schema map[string]*Schema
+		State  *terraform.InstanceState
+		Config *terraform.ResourceConfig
+		Diff   *terraform.InstanceDiff
+		Key    string
+		Value  interface{}
+		Ok     bool
+	}{
+		/*
+		 * Primitives
+		 */
+		{
+			Name: "string-literal-empty",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State:  nil,
+			Config: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": {
+						Old: "",
+						New: "",
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: "",
+			Ok:    true,
+		},
+
+		{
+			Name: "string-computed-empty",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State:  nil,
+			Config: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": {
+						Old:         "",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: "",
+			Ok:    false,
+		},
+
+		{
+			Name: "string-optional-computed-nil-diff",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State:  nil,
+			Config: nil,
+
+			Diff: nil,
+
+			Key:   "availability_zone",
+			Value: "",
+			Ok:    false,
+		},
+
+		/*
+		 * Lists
+		 */
+
+		{
+			Name: "list-optional",
+			Schema: map[string]*Schema{
+				"ports": {
+					Type:     TypeList,
+					Optional: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State:  nil,
+			Config: nil,
+
+			Diff: nil,
+
+			Key:   "ports",
+			Value: []interface{}{},
+			Ok:    false,
+		},
+
+		/*
+		 * Map
+		 */
+
+		{
+			Name: "map-optional",
+			Schema: map[string]*Schema{
+				"ports": {
+					Type:     TypeMap,
+					Optional: true,
+				},
+			},
+
+			State:  nil,
+			Config: nil,
+
+			Diff: nil,
+
+			Key:   "ports",
+			Value: map[string]interface{}{},
+			Ok:    false,
+		},
+
+		/*
+		 * Set
+		 */
+
+		{
+			Name: "set-optional",
+			Schema: map[string]*Schema{
+				"ports": {
+					Type:     TypeSet,
+					Optional: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set:      func(a interface{}) int { return a.(int) },
+				},
+			},
+
+			State:  nil,
+			Config: nil,
+
+			Diff: nil,
+
+			Key:   "ports",
+			Value: []interface{}{},
+			Ok:    false,
+		},
+
+		{
+			Name: "set-optional-key",
+			Schema: map[string]*Schema{
+				"ports": {
+					Type:     TypeSet,
+					Optional: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set:      func(a interface{}) int { return a.(int) },
+				},
+			},
+
+			State:  nil,
+			Config: nil,
+
+			Diff: nil,
+
+			Key:   "ports.0",
+			Value: 0,
+			Ok:    false,
+		},
+
+		{
+			Name: "bool-literal-empty",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeBool,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State:  nil,
+			Config: nil,
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": {
+						Old: "",
+						New: "",
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: false,
+			Ok:    true,
+		},
+
+		{
+			Name: "bool-literal-set",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeBool,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State:  nil,
+			Config: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": {
+						New: "true",
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: true,
+			Ok:    true,
+		},
+		{
+			Name: "value-in-config",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"availability_zone": "foo",
+			}),
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{},
+			},
+
+			Key:   "availability_zone",
+			Value: "foo",
+			Ok:    true,
+		},
+		{
+			Name: "new-value-in-config",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+				},
+			},
+
+			State: nil,
+			Config: testConfig(t, map[string]interface{}{
+				"availability_zone": "foo",
+			}),
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": {
+						Old: "",
+						New: "foo",
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: "foo",
+			Ok:    true,
+		},
+		{
+			Name: "optional-computed-value-in-config",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"availability_zone": "bar",
+			}),
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": {
+						Old: "foo",
+						New: "bar",
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: "bar",
+			Ok:    true,
+		},
+		{
+			Name: "removed-value",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{}),
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": {
+						Old:        "foo",
+						New:        "",
+						NewRemoved: true,
+					},
+				},
+			},
+
+			Key:   "availability_zone",
+			Value: "",
+			Ok:    true,
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			d := newResourceDiff(tc.Schema, tc.Config, tc.State, tc.Diff)
+
+			v, ok := d.GetOkExists(tc.Key)
+			if s, ok := v.(*Set); ok {
+				v = s.List()
+			}
+
+			if !reflect.DeepEqual(v, tc.Value) {
+				t.Fatalf("Bad %s: \n%#v", tc.Name, v)
+			}
+			if ok != tc.Ok {
+				t.Fatalf("%s: expected ok: %t, got: %t", tc.Name, tc.Ok, ok)
+			}
+		})
+	}
+}
+
+func TestResourceDiffGetOkExistsSetNew(t *testing.T) {
+	tc := struct {
+		Schema map[string]*Schema
+		State  *terraform.InstanceState
+		Diff   *terraform.InstanceDiff
+		Key    string
+		Value  interface{}
+		Ok     bool
+	}{
+		Schema: map[string]*Schema{
+			"availability_zone": {
+				Type:     TypeString,
+				Optional: true,
+				Computed: true,
+			},
+		},
+
+		State: nil,
+
+		Diff: &terraform.InstanceDiff{
+			Attributes: map[string]*terraform.ResourceAttrDiff{},
+		},
+
+		Key:   "availability_zone",
+		Value: "foobar",
+		Ok:    true,
+	}
+
+	d := newResourceDiff(tc.Schema, testConfig(t, map[string]interface{}{}), tc.State, tc.Diff)
+	d.SetNew(tc.Key, tc.Value)
+
+	v, ok := d.GetOkExists(tc.Key)
+	if s, ok := v.(*Set); ok {
+		v = s.List()
+	}
+
+	if !reflect.DeepEqual(v, tc.Value) {
+		t.Fatalf("Bad: \n%#v", v)
+	}
+	if ok != tc.Ok {
+		t.Fatalf("expected ok: %t, got: %t", tc.Ok, ok)
+	}
+}
+
+func TestResourceDiffGetOkExistsSetNewComputed(t *testing.T) {
+	tc := struct {
+		Schema map[string]*Schema
+		State  *terraform.InstanceState
+		Diff   *terraform.InstanceDiff
+		Key    string
+		Value  interface{}
+		Ok     bool
+	}{
+		Schema: map[string]*Schema{
+			"availability_zone": {
+				Type:     TypeString,
+				Optional: true,
+				Computed: true,
+			},
+		},
+
+		State: &terraform.InstanceState{
+			Attributes: map[string]string{
+				"availability_zone": "foo",
+			},
+		},
+
+		Diff: &terraform.InstanceDiff{
+			Attributes: map[string]*terraform.ResourceAttrDiff{},
+		},
+
+		Key:   "availability_zone",
+		Value: "foobar",
+		Ok:    false,
+	}
+
+	d := newResourceDiff(tc.Schema, testConfig(t, map[string]interface{}{}), tc.State, tc.Diff)
+	d.SetNewComputed(tc.Key)
+
+	_, ok := d.GetOkExists(tc.Key)
+
+	if ok != tc.Ok {
+		t.Fatalf("expected ok: %t, got: %t", tc.Ok, ok)
+	}
+}
+
+func TestResourceDiffNewValueKnown(t *testing.T) {
+	cases := []struct {
+		Name     string
+		Schema   map[string]*Schema
+		State    *terraform.InstanceState
+		Config   *terraform.ResourceConfig
+		Diff     *terraform.InstanceDiff
+		Key      string
+		Expected bool
+	}{
+		{
+			Name: "in config, no state",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+				},
+			},
+			State: nil,
+			Config: testConfig(t, map[string]interface{}{
+				"availability_zone": "foo",
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": {
+						Old: "",
+						New: "foo",
+					},
+				},
+			},
+			Key:      "availability_zone",
+			Expected: true,
+		},
+		{
+			Name: "in config, has state, no diff",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"availability_zone": "foo",
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{},
+			},
+			Key:      "availability_zone",
+			Expected: true,
+		},
+		{
+			Name: "computed attribute, in state, no diff",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Computed: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{},
+			},
+			Key:      "availability_zone",
+			Expected: true,
+		},
+		{
+			Name: "optional and computed attribute, in state, no config",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{},
+			},
+			Key:      "availability_zone",
+			Expected: true,
+		},
+		{
+			Name: "optional and computed attribute, in state, with config",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+			Config: testConfig(t, map[string]interface{}{
+				"availability_zone": "foo",
+			}),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{},
+			},
+			Key:      "availability_zone",
+			Expected: true,
+		},
+		{
+			Name: "computed value, through config reader",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+			Config: testConfig(
+				t,
+				map[string]interface{}{
+					"availability_zone": hcl2shim.UnknownVariableValue,
+				},
+			),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{},
+			},
+			Key:      "availability_zone",
+			Expected: false,
+		},
+		{
+			Name: "computed value, through diff reader",
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+				},
+			},
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+			Config: testConfig(
+				t,
+				map[string]interface{}{
+					"availability_zone": hcl2shim.UnknownVariableValue,
+				},
+			),
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": {
+						Old:         "foo",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+			Key:      "availability_zone",
+			Expected: false,
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			d := newResourceDiff(tc.Schema, tc.Config, tc.State, tc.Diff)
+
+			actual := d.NewValueKnown(tc.Key)
+			if tc.Expected != actual {
+				t.Fatalf("%s: expected ok: %t, got: %t", tc.Name, tc.Expected, actual)
+			}
+		})
+	}
+}
+
+func TestResourceDiffNewValueKnownSetNew(t *testing.T) {
+	tc := struct {
+		Schema   map[string]*Schema
+		State    *terraform.InstanceState
+		Config   *terraform.ResourceConfig
+		Diff     *terraform.InstanceDiff
+		Key      string
+		Value    interface{}
+		Expected bool
+	}{
+		Schema: map[string]*Schema{
+			"availability_zone": {
+				Type:     TypeString,
+				Optional: true,
+				Computed: true,
+			},
+		},
+		State: &terraform.InstanceState{
+			Attributes: map[string]string{
+				"availability_zone": "foo",
+			},
+		},
+		Config: testConfig(
+			t,
+			map[string]interface{}{
+				"availability_zone": hcl2shim.UnknownVariableValue,
+			},
+		),
+		Diff: &terraform.InstanceDiff{
+			Attributes: map[string]*terraform.ResourceAttrDiff{
+				"availability_zone": {
+					Old:         "foo",
+					New:         "",
+					NewComputed: true,
+				},
+			},
+		},
+		Key:      "availability_zone",
+		Value:    "bar",
+		Expected: true,
+	}
+
+	d := newResourceDiff(tc.Schema, tc.Config, tc.State, tc.Diff)
+	d.SetNew(tc.Key, tc.Value)
+
+	actual := d.NewValueKnown(tc.Key)
+	if tc.Expected != actual {
+		t.Fatalf("expected ok: %t, got: %t", tc.Expected, actual)
+	}
+}
+
+func TestResourceDiffNewValueKnownSetNewComputed(t *testing.T) {
+	tc := struct {
+		Schema   map[string]*Schema
+		State    *terraform.InstanceState
+		Config   *terraform.ResourceConfig
+		Diff     *terraform.InstanceDiff
+		Key      string
+		Expected bool
+	}{
+		Schema: map[string]*Schema{
+			"availability_zone": {
+				Type:     TypeString,
+				Computed: true,
+			},
+		},
+		State: &terraform.InstanceState{
+			Attributes: map[string]string{
+				"availability_zone": "foo",
+			},
+		},
+		Config: testConfig(t, map[string]interface{}{}),
+		Diff: &terraform.InstanceDiff{
+			Attributes: map[string]*terraform.ResourceAttrDiff{},
+		},
+		Key:      "availability_zone",
+		Expected: false,
+	}
+
+	d := newResourceDiff(tc.Schema, tc.Config, tc.State, tc.Diff)
+	d.SetNewComputed(tc.Key)
+
+	actual := d.NewValueKnown(tc.Key)
+	if tc.Expected != actual {
+		t.Fatalf("expected ok: %t, got: %t", tc.Expected, actual)
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/resource_importer.go b/v1.5.7/internal/legacy/helper/schema/resource_importer.go
new file mode 100644
index 0000000..a2b84c6
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/resource_importer.go
@@ -0,0 +1,55 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+// ResourceImporter defines how a resource is imported in Terraform. This
+// can be set onto a Resource struct to make it Importable. Not all resources
+// have to be importable; if a Resource doesn't have a ResourceImporter then
+// it won't be importable.
+//
+// "Importing" in Terraform is the process of taking an already-created
+// resource and bringing it under Terraform management. This can include
+// updating Terraform state, generating Terraform configuration, etc.
+type ResourceImporter struct {
+	// The functions below must all be implemented for importing to work.
+
+	// State is called to convert an ID to one or more InstanceState to
+	// insert into the Terraform state. If this isn't specified, then
+	// the ID is passed straight through.
+	State StateFunc
+}
+
+// StateFunc is the function called to import a resource into the
+// Terraform state. It is given a ResourceData with only ID set. This
+// ID is going to be an arbitrary value given by the user and may not map
+// directly to the ID format that the resource expects, so that should
+// be validated.
+//
+// This should return a slice of ResourceData that turn into the state
+// that was imported. This might be as simple as returning only the argument
+// that was given to the function. In other cases (such as AWS security groups),
+// an import may fan out to multiple resources and this will have to return
+// multiple.
+//
+// To create the ResourceData structures for other resource types (if
+// you have to), instantiate your resource and call the Data function.
+type StateFunc func(*ResourceData, interface{}) ([]*ResourceData, error)
+
+// InternalValidate should be called to validate the structure of this
+// importer. This should be called in a unit test.
+//
+// Resource.InternalValidate() will automatically call this, so this doesn't
+// need to be called manually. Further, Resource.InternalValidate() is
+// automatically called by Provider.InternalValidate(), so you only need
+// to internal validate the provider.
+func (r *ResourceImporter) InternalValidate() error {
+	return nil
+}
+
+// ImportStatePassthrough is an implementation of StateFunc that can be
+// used to simply pass the ID directly through. This should be used only
+// in the case that an ID-only refresh is possible.
+func ImportStatePassthrough(d *ResourceData, m interface{}) ([]*ResourceData, error) {
+	return []*ResourceData{d}, nil
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/resource_test.go b/v1.5.7/internal/legacy/helper/schema/resource_test.go
new file mode 100644
index 0000000..139fe81
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/resource_test.go
@@ -0,0 +1,1690 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"encoding/json"
+	"fmt"
+	"reflect"
+	"strconv"
+	"testing"
+	"time"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+)
+
+func TestResourceApply_create(t *testing.T) {
+	r := &Resource{
+		SchemaVersion: 2,
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	called := false
+	r.Create = func(d *ResourceData, m interface{}) error {
+		called = true
+		d.SetId("foo")
+		return nil
+	}
+
+	var s *terraform.InstanceState = nil
+
+	d := &terraform.InstanceDiff{
+		Attributes: map[string]*terraform.ResourceAttrDiff{
+			"foo": &terraform.ResourceAttrDiff{
+				New: "42",
+			},
+		},
+	}
+
+	actual, err := r.Apply(s, d, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !called {
+		t.Fatal("not called")
+	}
+
+	expected := &terraform.InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"id":  "foo",
+			"foo": "42",
+		},
+		Meta: map[string]interface{}{
+			"schema_version": "2",
+		},
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceApply_Timeout_state(t *testing.T) {
+	r := &Resource{
+		SchemaVersion: 2,
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+		Timeouts: &ResourceTimeout{
+			Create: DefaultTimeout(40 * time.Minute),
+			Update: DefaultTimeout(80 * time.Minute),
+			Delete: DefaultTimeout(40 * time.Minute),
+		},
+	}
+
+	called := false
+	r.Create = func(d *ResourceData, m interface{}) error {
+		called = true
+		d.SetId("foo")
+		return nil
+	}
+
+	var s *terraform.InstanceState = nil
+
+	d := &terraform.InstanceDiff{
+		Attributes: map[string]*terraform.ResourceAttrDiff{
+			"foo": &terraform.ResourceAttrDiff{
+				New: "42",
+			},
+		},
+	}
+
+	diffTimeout := &ResourceTimeout{
+		Create: DefaultTimeout(40 * time.Minute),
+		Update: DefaultTimeout(80 * time.Minute),
+		Delete: DefaultTimeout(40 * time.Minute),
+	}
+
+	if err := diffTimeout.DiffEncode(d); err != nil {
+		t.Fatalf("Error encoding timeout to diff: %s", err)
+	}
+
+	actual, err := r.Apply(s, d, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !called {
+		t.Fatal("not called")
+	}
+
+	expected := &terraform.InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"id":  "foo",
+			"foo": "42",
+		},
+		Meta: map[string]interface{}{
+			"schema_version": "2",
+			TimeoutKey:       expectedForValues(40, 0, 80, 40, 0),
+		},
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("Not equal in Timeout State:\n\texpected: %#v\n\tactual: %#v", expected.Meta, actual.Meta)
+	}
+}
+
+// Regression test to ensure that the meta data is read from state, if a
+// resource is destroyed and the timeout meta is no longer available from the
+// config
+func TestResourceApply_Timeout_destroy(t *testing.T) {
+	timeouts := &ResourceTimeout{
+		Create: DefaultTimeout(40 * time.Minute),
+		Update: DefaultTimeout(80 * time.Minute),
+		Delete: DefaultTimeout(40 * time.Minute),
+	}
+
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+		Timeouts: timeouts,
+	}
+
+	called := false
+	var delTimeout time.Duration
+	r.Delete = func(d *ResourceData, m interface{}) error {
+		delTimeout = d.Timeout(TimeoutDelete)
+		called = true
+		return nil
+	}
+
+	s := &terraform.InstanceState{
+		ID: "bar",
+	}
+
+	if err := timeouts.StateEncode(s); err != nil {
+		t.Fatalf("Error encoding to state: %s", err)
+	}
+
+	d := &terraform.InstanceDiff{
+		Destroy: true,
+	}
+
+	actual, err := r.Apply(s, d, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !called {
+		t.Fatal("delete not called")
+	}
+
+	if *timeouts.Delete != delTimeout {
+		t.Fatalf("timeouts don't match, expected (%#v), got (%#v)", timeouts.Delete, delTimeout)
+	}
+
+	if actual != nil {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceDiff_Timeout_diff(t *testing.T) {
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+		Timeouts: &ResourceTimeout{
+			Create: DefaultTimeout(40 * time.Minute),
+			Update: DefaultTimeout(80 * time.Minute),
+			Delete: DefaultTimeout(40 * time.Minute),
+		},
+	}
+
+	r.Create = func(d *ResourceData, m interface{}) error {
+		d.SetId("foo")
+		return nil
+	}
+
+	conf := terraform.NewResourceConfigRaw(
+		map[string]interface{}{
+			"foo": 42,
+			TimeoutsConfigKey: map[string]interface{}{
+				"create": "2h",
+			},
+		},
+	)
+	var s *terraform.InstanceState
+
+	actual, err := r.Diff(s, conf, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := &terraform.InstanceDiff{
+		Attributes: map[string]*terraform.ResourceAttrDiff{
+			"foo": &terraform.ResourceAttrDiff{
+				New: "42",
+			},
+		},
+	}
+
+	diffTimeout := &ResourceTimeout{
+		Create: DefaultTimeout(120 * time.Minute),
+		Update: DefaultTimeout(80 * time.Minute),
+		Delete: DefaultTimeout(40 * time.Minute),
+	}
+
+	if err := diffTimeout.DiffEncode(expected); err != nil {
+		t.Fatalf("Error encoding timeout to diff: %s", err)
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("Not equal Meta in Timeout Diff:\n\texpected: %#v\n\tactual: %#v", expected.Meta, actual.Meta)
+	}
+}
+
+func TestResourceDiff_CustomizeFunc(t *testing.T) {
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	var called bool
+
+	r.CustomizeDiff = func(d *ResourceDiff, m interface{}) error {
+		called = true
+		return nil
+	}
+
+	conf := terraform.NewResourceConfigRaw(
+		map[string]interface{}{
+			"foo": 42,
+		},
+	)
+
+	var s *terraform.InstanceState
+
+	_, err := r.Diff(s, conf, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !called {
+		t.Fatalf("diff customization not called")
+	}
+}
+
+func TestResourceApply_destroy(t *testing.T) {
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	called := false
+	r.Delete = func(d *ResourceData, m interface{}) error {
+		called = true
+		return nil
+	}
+
+	s := &terraform.InstanceState{
+		ID: "bar",
+	}
+
+	d := &terraform.InstanceDiff{
+		Destroy: true,
+	}
+
+	actual, err := r.Apply(s, d, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !called {
+		t.Fatal("delete not called")
+	}
+
+	if actual != nil {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceApply_destroyCreate(t *testing.T) {
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+
+			"tags": &Schema{
+				Type:     TypeMap,
+				Optional: true,
+				Computed: true,
+			},
+		},
+	}
+
+	change := false
+	r.Create = func(d *ResourceData, m interface{}) error {
+		change = d.HasChange("tags")
+		d.SetId("foo")
+		return nil
+	}
+	r.Delete = func(d *ResourceData, m interface{}) error {
+		return nil
+	}
+
+	var s *terraform.InstanceState = &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"foo":       "bar",
+			"tags.Name": "foo",
+		},
+	}
+
+	d := &terraform.InstanceDiff{
+		Attributes: map[string]*terraform.ResourceAttrDiff{
+			"foo": &terraform.ResourceAttrDiff{
+				New:         "42",
+				RequiresNew: true,
+			},
+			"tags.Name": &terraform.ResourceAttrDiff{
+				Old:         "foo",
+				New:         "foo",
+				RequiresNew: true,
+			},
+		},
+	}
+
+	actual, err := r.Apply(s, d, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !change {
+		t.Fatal("should have change")
+	}
+
+	expected := &terraform.InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"id":        "foo",
+			"foo":       "42",
+			"tags.%":    "1",
+			"tags.Name": "foo",
+		},
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceApply_destroyPartial(t *testing.T) {
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+		SchemaVersion: 3,
+	}
+
+	r.Delete = func(d *ResourceData, m interface{}) error {
+		d.Set("foo", 42)
+		return fmt.Errorf("some error")
+	}
+
+	s := &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"foo": "12",
+		},
+	}
+
+	d := &terraform.InstanceDiff{
+		Destroy: true,
+	}
+
+	actual, err := r.Apply(s, d, nil)
+	if err == nil {
+		t.Fatal("should error")
+	}
+
+	expected := &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"id":  "bar",
+			"foo": "42",
+		},
+		Meta: map[string]interface{}{
+			"schema_version": "3",
+		},
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("expected:\n%#v\n\ngot:\n%#v", expected, actual)
+	}
+}
+
+func TestResourceApply_update(t *testing.T) {
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	r.Update = func(d *ResourceData, m interface{}) error {
+		d.Set("foo", 42)
+		return nil
+	}
+
+	s := &terraform.InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"foo": "12",
+		},
+	}
+
+	d := &terraform.InstanceDiff{
+		Attributes: map[string]*terraform.ResourceAttrDiff{
+			"foo": &terraform.ResourceAttrDiff{
+				New: "13",
+			},
+		},
+	}
+
+	actual, err := r.Apply(s, d, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := &terraform.InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"id":  "foo",
+			"foo": "42",
+		},
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceApply_updateNoCallback(t *testing.T) {
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	r.Update = nil
+
+	s := &terraform.InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"foo": "12",
+		},
+	}
+
+	d := &terraform.InstanceDiff{
+		Attributes: map[string]*terraform.ResourceAttrDiff{
+			"foo": &terraform.ResourceAttrDiff{
+				New: "13",
+			},
+		},
+	}
+
+	actual, err := r.Apply(s, d, nil)
+	if err == nil {
+		t.Fatal("should error")
+	}
+
+	expected := &terraform.InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"foo": "12",
+		},
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceApply_isNewResource(t *testing.T) {
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeString,
+				Optional: true,
+			},
+		},
+	}
+
+	updateFunc := func(d *ResourceData, m interface{}) error {
+		d.Set("foo", "updated")
+		if d.IsNewResource() {
+			d.Set("foo", "new-resource")
+		}
+		return nil
+	}
+	r.Create = func(d *ResourceData, m interface{}) error {
+		d.SetId("foo")
+		d.Set("foo", "created")
+		return updateFunc(d, m)
+	}
+	r.Update = updateFunc
+
+	d := &terraform.InstanceDiff{
+		Attributes: map[string]*terraform.ResourceAttrDiff{
+			"foo": &terraform.ResourceAttrDiff{
+				New: "bla-blah",
+			},
+		},
+	}
+
+	// positive test
+	var s *terraform.InstanceState = nil
+
+	actual, err := r.Apply(s, d, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := &terraform.InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"id":  "foo",
+			"foo": "new-resource",
+		},
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("actual: %#v\nexpected: %#v",
+			actual, expected)
+	}
+
+	// negative test
+	s = &terraform.InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"id":  "foo",
+			"foo": "new-resource",
+		},
+	}
+
+	actual, err = r.Apply(s, d, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected = &terraform.InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"id":  "foo",
+			"foo": "updated",
+		},
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("actual: %#v\nexpected: %#v",
+			actual, expected)
+	}
+}
+
+func TestResourceInternalValidate(t *testing.T) {
+	cases := []struct {
+		In       *Resource
+		Writable bool
+		Err      bool
+	}{
+		0: {
+			nil,
+			true,
+			true,
+		},
+
+		// No optional and no required
+		1: {
+			&Resource{
+				Schema: map[string]*Schema{
+					"foo": &Schema{
+						Type:     TypeInt,
+						Optional: true,
+						Required: true,
+					},
+				},
+			},
+			true,
+			true,
+		},
+
+		// Update undefined for non-ForceNew field
+		2: {
+			&Resource{
+				Create: func(d *ResourceData, meta interface{}) error { return nil },
+				Schema: map[string]*Schema{
+					"boo": &Schema{
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+			},
+			true,
+			true,
+		},
+
+		// Update defined for ForceNew field
+		3: {
+			&Resource{
+				Create: func(d *ResourceData, meta interface{}) error { return nil },
+				Update: func(d *ResourceData, meta interface{}) error { return nil },
+				Schema: map[string]*Schema{
+					"goo": &Schema{
+						Type:     TypeInt,
+						Optional: true,
+						ForceNew: true,
+					},
+				},
+			},
+			true,
+			true,
+		},
+
+		// non-writable doesn't need Update, Create or Delete
+		4: {
+			&Resource{
+				Schema: map[string]*Schema{
+					"goo": &Schema{
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+			},
+			false,
+			false,
+		},
+
+		// non-writable *must not* have Create
+		5: {
+			&Resource{
+				Create: func(d *ResourceData, meta interface{}) error { return nil },
+				Schema: map[string]*Schema{
+					"goo": &Schema{
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+			},
+			false,
+			true,
+		},
+
+		// writable must have Read
+		6: {
+			&Resource{
+				Create: func(d *ResourceData, meta interface{}) error { return nil },
+				Update: func(d *ResourceData, meta interface{}) error { return nil },
+				Delete: func(d *ResourceData, meta interface{}) error { return nil },
+				Schema: map[string]*Schema{
+					"goo": &Schema{
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+			},
+			true,
+			true,
+		},
+
+		// writable must have Delete
+		7: {
+			&Resource{
+				Create: func(d *ResourceData, meta interface{}) error { return nil },
+				Read:   func(d *ResourceData, meta interface{}) error { return nil },
+				Update: func(d *ResourceData, meta interface{}) error { return nil },
+				Schema: map[string]*Schema{
+					"goo": &Schema{
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+			},
+			true,
+			true,
+		},
+
+		8: { // Reserved name at root should be disallowed
+			&Resource{
+				Create: func(d *ResourceData, meta interface{}) error { return nil },
+				Read:   func(d *ResourceData, meta interface{}) error { return nil },
+				Update: func(d *ResourceData, meta interface{}) error { return nil },
+				Delete: func(d *ResourceData, meta interface{}) error { return nil },
+				Schema: map[string]*Schema{
+					"count": {
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+			},
+			true,
+			true,
+		},
+
+		9: { // Reserved name at nested levels should be allowed
+			&Resource{
+				Create: func(d *ResourceData, meta interface{}) error { return nil },
+				Read:   func(d *ResourceData, meta interface{}) error { return nil },
+				Update: func(d *ResourceData, meta interface{}) error { return nil },
+				Delete: func(d *ResourceData, meta interface{}) error { return nil },
+				Schema: map[string]*Schema{
+					"parent_list": &Schema{
+						Type:     TypeString,
+						Optional: true,
+						Elem: &Resource{
+							Schema: map[string]*Schema{
+								"provisioner": {
+									Type:     TypeString,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			true,
+			false,
+		},
+
+		10: { // Provider reserved name should be allowed in resource
+			&Resource{
+				Create: func(d *ResourceData, meta interface{}) error { return nil },
+				Read:   func(d *ResourceData, meta interface{}) error { return nil },
+				Update: func(d *ResourceData, meta interface{}) error { return nil },
+				Delete: func(d *ResourceData, meta interface{}) error { return nil },
+				Schema: map[string]*Schema{
+					"alias": &Schema{
+						Type:     TypeString,
+						Optional: true,
+					},
+				},
+			},
+			true,
+			false,
+		},
+
+		11: { // ID should be allowed in data source
+			&Resource{
+				Read: func(d *ResourceData, meta interface{}) error { return nil },
+				Schema: map[string]*Schema{
+					"id": &Schema{
+						Type:     TypeString,
+						Optional: true,
+					},
+				},
+			},
+			false,
+			false,
+		},
+
+		12: { // Deprecated ID should be allowed in resource
+			&Resource{
+				Create: func(d *ResourceData, meta interface{}) error { return nil },
+				Read:   func(d *ResourceData, meta interface{}) error { return nil },
+				Update: func(d *ResourceData, meta interface{}) error { return nil },
+				Delete: func(d *ResourceData, meta interface{}) error { return nil },
+				Schema: map[string]*Schema{
+					"id": &Schema{
+						Type:       TypeString,
+						Optional:   true,
+						Deprecated: "Use x_id instead",
+					},
+				},
+			},
+			true,
+			false,
+		},
+
+		13: { // non-writable must not define CustomizeDiff
+			&Resource{
+				Read: func(d *ResourceData, meta interface{}) error { return nil },
+				Schema: map[string]*Schema{
+					"goo": &Schema{
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+				CustomizeDiff: func(*ResourceDiff, interface{}) error { return nil },
+			},
+			false,
+			true,
+		},
+		14: { // Deprecated resource
+			&Resource{
+				Read: func(d *ResourceData, meta interface{}) error { return nil },
+				Schema: map[string]*Schema{
+					"goo": &Schema{
+						Type:     TypeInt,
+						Optional: true,
+					},
+				},
+				DeprecationMessage: "This resource has been deprecated.",
+			},
+			true,
+			true,
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
+			sm := schemaMap{}
+			if tc.In != nil {
+				sm = schemaMap(tc.In.Schema)
+			}
+
+			err := tc.In.InternalValidate(sm, tc.Writable)
+			if err != nil && !tc.Err {
+				t.Fatalf("%d: expected validation to pass: %s", i, err)
+			}
+			if err == nil && tc.Err {
+				t.Fatalf("%d: expected validation to fail", i)
+			}
+		})
+	}
+}
+
+func TestResourceRefresh(t *testing.T) {
+	r := &Resource{
+		SchemaVersion: 2,
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	r.Read = func(d *ResourceData, m interface{}) error {
+		if m != 42 {
+			return fmt.Errorf("meta not passed")
+		}
+
+		return d.Set("foo", d.Get("foo").(int)+1)
+	}
+
+	s := &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"foo": "12",
+		},
+	}
+
+	expected := &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"id":  "bar",
+			"foo": "13",
+		},
+		Meta: map[string]interface{}{
+			"schema_version": "2",
+		},
+	}
+
+	actual, err := r.Refresh(s, 42)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceRefresh_blankId(t *testing.T) {
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	r.Read = func(d *ResourceData, m interface{}) error {
+		d.SetId("foo")
+		return nil
+	}
+
+	s := &terraform.InstanceState{
+		ID:         "",
+		Attributes: map[string]string{},
+	}
+
+	actual, err := r.Refresh(s, 42)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if actual != nil {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceRefresh_delete(t *testing.T) {
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	r.Read = func(d *ResourceData, m interface{}) error {
+		d.SetId("")
+		return nil
+	}
+
+	s := &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"foo": "12",
+		},
+	}
+
+	actual, err := r.Refresh(s, 42)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if actual != nil {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceRefresh_existsError(t *testing.T) {
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	r.Exists = func(*ResourceData, interface{}) (bool, error) {
+		return false, fmt.Errorf("error")
+	}
+
+	r.Read = func(d *ResourceData, m interface{}) error {
+		panic("shouldn't be called")
+	}
+
+	s := &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"foo": "12",
+		},
+	}
+
+	actual, err := r.Refresh(s, 42)
+	if err == nil {
+		t.Fatalf("should error")
+	}
+	if !reflect.DeepEqual(actual, s) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceRefresh_noExists(t *testing.T) {
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	r.Exists = func(*ResourceData, interface{}) (bool, error) {
+		return false, nil
+	}
+
+	r.Read = func(d *ResourceData, m interface{}) error {
+		panic("shouldn't be called")
+	}
+
+	s := &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"foo": "12",
+		},
+	}
+
+	actual, err := r.Refresh(s, 42)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if actual != nil {
+		t.Fatalf("should have no state")
+	}
+}
+
+func TestResourceRefresh_needsMigration(t *testing.T) {
+	// Schema v2 it deals only in newfoo, which tracks foo as an int
+	r := &Resource{
+		SchemaVersion: 2,
+		Schema: map[string]*Schema{
+			"newfoo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	r.Read = func(d *ResourceData, m interface{}) error {
+		return d.Set("newfoo", d.Get("newfoo").(int)+1)
+	}
+
+	r.MigrateState = func(
+		v int,
+		s *terraform.InstanceState,
+		meta interface{}) (*terraform.InstanceState, error) {
+		// Real state migration functions will probably switch on this value,
+		// but we'll just assert on it for now.
+		if v != 1 {
+			t.Fatalf("Expected StateSchemaVersion to be 1, got %d", v)
+		}
+
+		if meta != 42 {
+			t.Fatal("Expected meta to be passed through to the migration function")
+		}
+
+		oldfoo, err := strconv.ParseFloat(s.Attributes["oldfoo"], 64)
+		if err != nil {
+			t.Fatalf("err: %#v", err)
+		}
+		s.Attributes["newfoo"] = strconv.Itoa(int(oldfoo * 10))
+		delete(s.Attributes, "oldfoo")
+
+		return s, nil
+	}
+
+	// State is v1 and deals in oldfoo, which tracked foo as a float at 1/10th
+	// the scale of newfoo
+	s := &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"oldfoo": "1.2",
+		},
+		Meta: map[string]interface{}{
+			"schema_version": "1",
+		},
+	}
+
+	actual, err := r.Refresh(s, 42)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"id":     "bar",
+			"newfoo": "13",
+		},
+		Meta: map[string]interface{}{
+			"schema_version": "2",
+		},
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad:\n\nexpected: %#v\ngot: %#v", expected, actual)
+	}
+}
+
+func TestResourceRefresh_noMigrationNeeded(t *testing.T) {
+	r := &Resource{
+		SchemaVersion: 2,
+		Schema: map[string]*Schema{
+			"newfoo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	r.Read = func(d *ResourceData, m interface{}) error {
+		return d.Set("newfoo", d.Get("newfoo").(int)+1)
+	}
+
+	r.MigrateState = func(
+		v int,
+		s *terraform.InstanceState,
+		meta interface{}) (*terraform.InstanceState, error) {
+		t.Fatal("Migrate function shouldn't be called!")
+		return nil, nil
+	}
+
+	s := &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"newfoo": "12",
+		},
+		Meta: map[string]interface{}{
+			"schema_version": "2",
+		},
+	}
+
+	actual, err := r.Refresh(s, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"id":     "bar",
+			"newfoo": "13",
+		},
+		Meta: map[string]interface{}{
+			"schema_version": "2",
+		},
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad:\n\nexpected: %#v\ngot: %#v", expected, actual)
+	}
+}
+
+func TestResourceRefresh_stateSchemaVersionUnset(t *testing.T) {
+	r := &Resource{
+		// Version 1 > Version 0
+		SchemaVersion: 1,
+		Schema: map[string]*Schema{
+			"newfoo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	r.Read = func(d *ResourceData, m interface{}) error {
+		return d.Set("newfoo", d.Get("newfoo").(int)+1)
+	}
+
+	r.MigrateState = func(
+		v int,
+		s *terraform.InstanceState,
+		meta interface{}) (*terraform.InstanceState, error) {
+		s.Attributes["newfoo"] = s.Attributes["oldfoo"]
+		return s, nil
+	}
+
+	s := &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"oldfoo": "12",
+		},
+	}
+
+	actual, err := r.Refresh(s, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"id":     "bar",
+			"newfoo": "13",
+		},
+		Meta: map[string]interface{}{
+			"schema_version": "1",
+		},
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad:\n\nexpected: %#v\ngot: %#v", expected, actual)
+	}
+}
+
+func TestResourceRefresh_migrateStateErr(t *testing.T) {
+	r := &Resource{
+		SchemaVersion: 2,
+		Schema: map[string]*Schema{
+			"newfoo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	r.Read = func(d *ResourceData, m interface{}) error {
+		t.Fatal("Read should never be called!")
+		return nil
+	}
+
+	r.MigrateState = func(
+		v int,
+		s *terraform.InstanceState,
+		meta interface{}) (*terraform.InstanceState, error) {
+		return s, fmt.Errorf("triggering an error")
+	}
+
+	s := &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"oldfoo": "12",
+		},
+	}
+
+	_, err := r.Refresh(s, nil)
+	if err == nil {
+		t.Fatal("expected error, but got none!")
+	}
+}
+
+func TestResourceData(t *testing.T) {
+	r := &Resource{
+		SchemaVersion: 2,
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	state := &terraform.InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"id":  "foo",
+			"foo": "42",
+		},
+	}
+
+	data := r.Data(state)
+	if data.Id() != "foo" {
+		t.Fatalf("err: %s", data.Id())
+	}
+	if v := data.Get("foo"); v != 42 {
+		t.Fatalf("bad: %#v", v)
+	}
+
+	// Set expectations
+	state.Meta = map[string]interface{}{
+		"schema_version": "2",
+	}
+
+	result := data.State()
+	if !reflect.DeepEqual(result, state) {
+		t.Fatalf("bad: %#v", result)
+	}
+}
+
+func TestResourceData_blank(t *testing.T) {
+	r := &Resource{
+		SchemaVersion: 2,
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	data := r.Data(nil)
+	if data.Id() != "" {
+		t.Fatalf("err: %s", data.Id())
+	}
+	if v := data.Get("foo"); v != 0 {
+		t.Fatalf("bad: %#v", v)
+	}
+}
+
+func TestResourceData_timeouts(t *testing.T) {
+	one := 1 * time.Second
+	two := 2 * time.Second
+	three := 3 * time.Second
+	four := 4 * time.Second
+	five := 5 * time.Second
+
+	timeouts := &ResourceTimeout{
+		Create:  &one,
+		Read:    &two,
+		Update:  &three,
+		Delete:  &four,
+		Default: &five,
+	}
+
+	r := &Resource{
+		SchemaVersion: 2,
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+		Timeouts: timeouts,
+	}
+
+	data := r.Data(nil)
+	if data.Id() != "" {
+		t.Fatalf("err: %s", data.Id())
+	}
+
+	if !reflect.DeepEqual(timeouts, data.timeouts) {
+		t.Fatalf("incorrect ResourceData timeouts: %#v\n", *data.timeouts)
+	}
+}
+
+func TestResource_UpgradeState(t *testing.T) {
+	// While this really only calls itself and therefore doesn't test any of
+	// the Resource code directly, it still serves as an example of registering
+	// a StateUpgrader.
+	r := &Resource{
+		SchemaVersion: 2,
+		Schema: map[string]*Schema{
+			"newfoo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	r.StateUpgraders = []StateUpgrader{
+		{
+			Version: 1,
+			Type: cty.Object(map[string]cty.Type{
+				"id":     cty.String,
+				"oldfoo": cty.Number,
+			}),
+			Upgrade: func(m map[string]interface{}, meta interface{}) (map[string]interface{}, error) {
+
+				oldfoo, ok := m["oldfoo"].(float64)
+				if !ok {
+					t.Fatalf("expected 1.2, got %#v", m["oldfoo"])
+				}
+				m["newfoo"] = int(oldfoo * 10)
+				delete(m, "oldfoo")
+
+				return m, nil
+			},
+		},
+	}
+
+	oldStateAttrs := map[string]string{
+		"id":     "bar",
+		"oldfoo": "1.2",
+	}
+
+	// convert the legacy flatmap state to the json equivalent
+	ty := r.StateUpgraders[0].Type
+	val, err := hcl2shim.HCL2ValueFromFlatmap(oldStateAttrs, ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+	js, err := ctyjson.Marshal(val, ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// unmarshal the state using the json default types
+	var m map[string]interface{}
+	if err := json.Unmarshal(js, &m); err != nil {
+		t.Fatal(err)
+	}
+
+	actual, err := r.StateUpgraders[0].Upgrade(m, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := map[string]interface{}{
+		"id":     "bar",
+		"newfoo": 12,
+	}
+
+	if !reflect.DeepEqual(expected, actual) {
+		t.Fatalf("expected: %#v\ngot: %#v\n", expected, actual)
+	}
+}
+
+func TestResource_ValidateUpgradeState(t *testing.T) {
+	r := &Resource{
+		SchemaVersion: 3,
+		Schema: map[string]*Schema{
+			"newfoo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	if err := r.InternalValidate(nil, true); err != nil {
+		t.Fatal(err)
+	}
+
+	r.StateUpgraders = append(r.StateUpgraders, StateUpgrader{
+		Version: 2,
+		Type: cty.Object(map[string]cty.Type{
+			"id": cty.String,
+		}),
+		Upgrade: func(m map[string]interface{}, _ interface{}) (map[string]interface{}, error) {
+			return m, nil
+		},
+	})
+	if err := r.InternalValidate(nil, true); err != nil {
+		t.Fatal(err)
+	}
+
+	// check for missing type
+	r.StateUpgraders[0].Type = cty.Type{}
+	if err := r.InternalValidate(nil, true); err == nil {
+		t.Fatal("StateUpgrader must have type")
+	}
+	r.StateUpgraders[0].Type = cty.Object(map[string]cty.Type{
+		"id": cty.String,
+	})
+
+	// check for missing Upgrade func
+	r.StateUpgraders[0].Upgrade = nil
+	if err := r.InternalValidate(nil, true); err == nil {
+		t.Fatal("StateUpgrader must have an Upgrade func")
+	}
+	r.StateUpgraders[0].Upgrade = func(m map[string]interface{}, _ interface{}) (map[string]interface{}, error) {
+		return m, nil
+	}
+
+	// check for skipped version
+	r.StateUpgraders[0].Version = 0
+	r.StateUpgraders = append(r.StateUpgraders, StateUpgrader{
+		Version: 2,
+		Type: cty.Object(map[string]cty.Type{
+			"id": cty.String,
+		}),
+		Upgrade: func(m map[string]interface{}, _ interface{}) (map[string]interface{}, error) {
+			return m, nil
+		},
+	})
+	if err := r.InternalValidate(nil, true); err == nil {
+		t.Fatal("StateUpgraders cannot skip versions")
+	}
+
+	// add the missing version, but fail because it's still out of order
+	r.StateUpgraders = append(r.StateUpgraders, StateUpgrader{
+		Version: 1,
+		Type: cty.Object(map[string]cty.Type{
+			"id": cty.String,
+		}),
+		Upgrade: func(m map[string]interface{}, _ interface{}) (map[string]interface{}, error) {
+			return m, nil
+		},
+	})
+	if err := r.InternalValidate(nil, true); err == nil {
+		t.Fatal("upgraders must be defined in order")
+	}
+
+	r.StateUpgraders[1], r.StateUpgraders[2] = r.StateUpgraders[2], r.StateUpgraders[1]
+	if err := r.InternalValidate(nil, true); err != nil {
+		t.Fatal(err)
+	}
+
+	// can't add an upgrader for a schema >= the current version
+	r.StateUpgraders = append(r.StateUpgraders, StateUpgrader{
+		Version: 3,
+		Type: cty.Object(map[string]cty.Type{
+			"id": cty.String,
+		}),
+		Upgrade: func(m map[string]interface{}, _ interface{}) (map[string]interface{}, error) {
+			return m, nil
+		},
+	})
+	if err := r.InternalValidate(nil, true); err == nil {
+		t.Fatal("StateUpgraders cannot have a version >= current SchemaVersion")
+	}
+}
+
+// The legacy provider will need to be able to handle both types of schema
+// transformations, which has been retrofitted into the Refresh method.
+func TestResource_migrateAndUpgrade(t *testing.T) {
+	r := &Resource{
+		SchemaVersion: 4,
+		Schema: map[string]*Schema{
+			"four": {
+				Type:     TypeInt,
+				Required: true,
+			},
+		},
+		// this MigrateState will take the state to version 2
+		MigrateState: func(v int, is *terraform.InstanceState, _ interface{}) (*terraform.InstanceState, error) {
+			switch v {
+			case 0:
+				_, ok := is.Attributes["zero"]
+				if !ok {
+					return nil, fmt.Errorf("zero not found in %#v", is.Attributes)
+				}
+				is.Attributes["one"] = "1"
+				delete(is.Attributes, "zero")
+				fallthrough
+			case 1:
+				_, ok := is.Attributes["one"]
+				if !ok {
+					return nil, fmt.Errorf("one not found in %#v", is.Attributes)
+				}
+				is.Attributes["two"] = "2"
+				delete(is.Attributes, "one")
+			default:
+				return nil, fmt.Errorf("invalid schema version %d", v)
+			}
+			return is, nil
+		},
+	}
+
+	r.Read = func(d *ResourceData, m interface{}) error {
+		return d.Set("four", 4)
+	}
+
+	r.StateUpgraders = []StateUpgrader{
+		{
+			Version: 2,
+			Type: cty.Object(map[string]cty.Type{
+				"id":  cty.String,
+				"two": cty.Number,
+			}),
+			Upgrade: func(m map[string]interface{}, meta interface{}) (map[string]interface{}, error) {
+				_, ok := m["two"].(float64)
+				if !ok {
+					return nil, fmt.Errorf("two not found in %#v", m)
+				}
+				m["three"] = float64(3)
+				delete(m, "two")
+				return m, nil
+			},
+		},
+		{
+			Version: 3,
+			Type: cty.Object(map[string]cty.Type{
+				"id":    cty.String,
+				"three": cty.Number,
+			}),
+			Upgrade: func(m map[string]interface{}, meta interface{}) (map[string]interface{}, error) {
+				_, ok := m["three"].(float64)
+				if !ok {
+					return nil, fmt.Errorf("three not found in %#v", m)
+				}
+				m["four"] = float64(4)
+				delete(m, "three")
+				return m, nil
+			},
+		},
+	}
+
+	testStates := []*terraform.InstanceState{
+		{
+			ID: "bar",
+			Attributes: map[string]string{
+				"id":   "bar",
+				"zero": "0",
+			},
+			Meta: map[string]interface{}{
+				"schema_version": "0",
+			},
+		},
+		{
+			ID: "bar",
+			Attributes: map[string]string{
+				"id":  "bar",
+				"one": "1",
+			},
+			Meta: map[string]interface{}{
+				"schema_version": "1",
+			},
+		},
+		{
+			ID: "bar",
+			Attributes: map[string]string{
+				"id":  "bar",
+				"two": "2",
+			},
+			Meta: map[string]interface{}{
+				"schema_version": "2",
+			},
+		},
+		{
+			ID: "bar",
+			Attributes: map[string]string{
+				"id":    "bar",
+				"three": "3",
+			},
+			Meta: map[string]interface{}{
+				"schema_version": "3",
+			},
+		},
+		{
+			ID: "bar",
+			Attributes: map[string]string{
+				"id":   "bar",
+				"four": "4",
+			},
+			Meta: map[string]interface{}{
+				"schema_version": "4",
+			},
+		},
+	}
+
+	for i, s := range testStates {
+		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+			newState, err := r.Refresh(s, nil)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			expected := &terraform.InstanceState{
+				ID: "bar",
+				Attributes: map[string]string{
+					"id":   "bar",
+					"four": "4",
+				},
+				Meta: map[string]interface{}{
+					"schema_version": "4",
+				},
+			}
+
+			if !cmp.Equal(expected, newState, equateEmpty) {
+				t.Fatal(cmp.Diff(expected, newState, equateEmpty))
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/resource_timeout.go b/v1.5.7/internal/legacy/helper/schema/resource_timeout.go
new file mode 100644
index 0000000..15b03cb
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/resource_timeout.go
@@ -0,0 +1,265 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"fmt"
+	"log"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+	"github.com/mitchellh/copystructure"
+)
+
+const TimeoutKey = "e2bfb730-ecaa-11e6-8f88-34363bc7c4c0"
+const TimeoutsConfigKey = "timeouts"
+
+const (
+	TimeoutCreate  = "create"
+	TimeoutRead    = "read"
+	TimeoutUpdate  = "update"
+	TimeoutDelete  = "delete"
+	TimeoutDefault = "default"
+)
+
+func timeoutKeys() []string {
+	return []string{
+		TimeoutCreate,
+		TimeoutRead,
+		TimeoutUpdate,
+		TimeoutDelete,
+		TimeoutDefault,
+	}
+}
+
+// could be time.Duration, int64 or float64
+func DefaultTimeout(tx interface{}) *time.Duration {
+	var td time.Duration
+	switch raw := tx.(type) {
+	case time.Duration:
+		return &raw
+	case int64:
+		td = time.Duration(raw)
+	case float64:
+		td = time.Duration(int64(raw))
+	default:
+		log.Printf("[WARN] Unknown type in DefaultTimeout: %#v", tx)
+	}
+	return &td
+}
+
+type ResourceTimeout struct {
+	Create, Read, Update, Delete, Default *time.Duration
+}
+
+// ConfigDecode takes a schema and the configuration (available in Diff) and
+// validates, parses the timeouts into `t`
+func (t *ResourceTimeout) ConfigDecode(s *Resource, c *terraform.ResourceConfig) error {
+	if s.Timeouts != nil {
+		raw, err := copystructure.Copy(s.Timeouts)
+		if err != nil {
+			log.Printf("[DEBUG] Error with deep copy: %s", err)
+		}
+		*t = *raw.(*ResourceTimeout)
+	}
+
+	if raw, ok := c.Config[TimeoutsConfigKey]; ok {
+		var rawTimeouts []map[string]interface{}
+		switch raw := raw.(type) {
+		case map[string]interface{}:
+			rawTimeouts = append(rawTimeouts, raw)
+		case []map[string]interface{}:
+			rawTimeouts = raw
+		case string:
+			if raw == hcl2shim.UnknownVariableValue {
+				// Timeout is not defined in the config
+				// Defaults will be used instead
+				return nil
+			} else {
+				log.Printf("[ERROR] Invalid timeout value: %q", raw)
+				return fmt.Errorf("Invalid Timeout value found")
+			}
+		case []interface{}:
+			for _, r := range raw {
+				if rMap, ok := r.(map[string]interface{}); ok {
+					rawTimeouts = append(rawTimeouts, rMap)
+				} else {
+					// Go will not allow a fallthrough
+					log.Printf("[ERROR] Invalid timeout structure: %#v", raw)
+					return fmt.Errorf("Invalid Timeout structure found")
+				}
+			}
+		default:
+			log.Printf("[ERROR] Invalid timeout structure: %#v", raw)
+			return fmt.Errorf("Invalid Timeout structure found")
+		}
+
+		for _, timeoutValues := range rawTimeouts {
+			for timeKey, timeValue := range timeoutValues {
+				// validate that we're dealing with the normal CRUD actions
+				var found bool
+				for _, key := range timeoutKeys() {
+					if timeKey == key {
+						found = true
+						break
+					}
+				}
+
+				if !found {
+					return fmt.Errorf("Unsupported Timeout configuration key found (%s)", timeKey)
+				}
+
+				// Get timeout
+				rt, err := time.ParseDuration(timeValue.(string))
+				if err != nil {
+					return fmt.Errorf("Error parsing %q timeout: %s", timeKey, err)
+				}
+
+				var timeout *time.Duration
+				switch timeKey {
+				case TimeoutCreate:
+					timeout = t.Create
+				case TimeoutUpdate:
+					timeout = t.Update
+				case TimeoutRead:
+					timeout = t.Read
+				case TimeoutDelete:
+					timeout = t.Delete
+				case TimeoutDefault:
+					timeout = t.Default
+				}
+
+				// If the resource has not delcared this in the definition, then error
+				// with an unsupported message
+				if timeout == nil {
+					return unsupportedTimeoutKeyError(timeKey)
+				}
+
+				*timeout = rt
+			}
+			return nil
+		}
+	}
+
+	return nil
+}
+
+func unsupportedTimeoutKeyError(key string) error {
+	return fmt.Errorf("Timeout Key (%s) is not supported", key)
+}
+
+// DiffEncode, StateEncode, and MetaDecode are analogous to the Go stdlib JSONEncoder
+// interface: they encode/decode a timeouts struct from an instance diff, which is
+// where the timeout data is stored after a diff to pass into Apply.
+//
+// StateEncode encodes the timeout into the ResourceData's InstanceState for
+// saving to state
+func (t *ResourceTimeout) DiffEncode(id *terraform.InstanceDiff) error {
+	return t.metaEncode(id)
+}
+
+func (t *ResourceTimeout) StateEncode(is *terraform.InstanceState) error {
+	return t.metaEncode(is)
+}
+
+// metaEncode encodes the ResourceTimeout into a map[string]interface{} format
+// and stores it in the Meta field of the interface it's given.
+// Assumes the interface is either *terraform.InstanceState or
+// *terraform.InstanceDiff, returns an error otherwise
+func (t *ResourceTimeout) metaEncode(ids interface{}) error {
+	m := make(map[string]interface{})
+
+	if t.Create != nil {
+		m[TimeoutCreate] = t.Create.Nanoseconds()
+	}
+	if t.Read != nil {
+		m[TimeoutRead] = t.Read.Nanoseconds()
+	}
+	if t.Update != nil {
+		m[TimeoutUpdate] = t.Update.Nanoseconds()
+	}
+	if t.Delete != nil {
+		m[TimeoutDelete] = t.Delete.Nanoseconds()
+	}
+	if t.Default != nil {
+		m[TimeoutDefault] = t.Default.Nanoseconds()
+		// for any key above that is nil, if default is specified, we need to
+		// populate it with the default
+		for _, k := range timeoutKeys() {
+			if _, ok := m[k]; !ok {
+				m[k] = t.Default.Nanoseconds()
+			}
+		}
+	}
+
+	// only add the Timeout to the Meta if we have values
+	if len(m) > 0 {
+		switch instance := ids.(type) {
+		case *terraform.InstanceDiff:
+			if instance.Meta == nil {
+				instance.Meta = make(map[string]interface{})
+			}
+			instance.Meta[TimeoutKey] = m
+		case *terraform.InstanceState:
+			if instance.Meta == nil {
+				instance.Meta = make(map[string]interface{})
+			}
+			instance.Meta[TimeoutKey] = m
+		default:
+			return fmt.Errorf("Error matching type for Diff Encode")
+		}
+	}
+
+	return nil
+}
+
+func (t *ResourceTimeout) StateDecode(id *terraform.InstanceState) error {
+	return t.metaDecode(id)
+}
+func (t *ResourceTimeout) DiffDecode(is *terraform.InstanceDiff) error {
+	return t.metaDecode(is)
+}
+
+func (t *ResourceTimeout) metaDecode(ids interface{}) error {
+	var rawMeta interface{}
+	var ok bool
+	switch rawInstance := ids.(type) {
+	case *terraform.InstanceDiff:
+		rawMeta, ok = rawInstance.Meta[TimeoutKey]
+		if !ok {
+			return nil
+		}
+	case *terraform.InstanceState:
+		rawMeta, ok = rawInstance.Meta[TimeoutKey]
+		if !ok {
+			return nil
+		}
+	default:
+		return fmt.Errorf("Unknown or unsupported type in metaDecode: %#v", ids)
+	}
+
+	times := rawMeta.(map[string]interface{})
+	if len(times) == 0 {
+		return nil
+	}
+
+	if v, ok := times[TimeoutCreate]; ok {
+		t.Create = DefaultTimeout(v)
+	}
+	if v, ok := times[TimeoutRead]; ok {
+		t.Read = DefaultTimeout(v)
+	}
+	if v, ok := times[TimeoutUpdate]; ok {
+		t.Update = DefaultTimeout(v)
+	}
+	if v, ok := times[TimeoutDelete]; ok {
+		t.Delete = DefaultTimeout(v)
+	}
+	if v, ok := times[TimeoutDefault]; ok {
+		t.Default = DefaultTimeout(v)
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/resource_timeout_test.go b/v1.5.7/internal/legacy/helper/schema/resource_timeout_test.go
new file mode 100644
index 0000000..4d96d55
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/resource_timeout_test.go
@@ -0,0 +1,379 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+func TestResourceTimeout_ConfigDecode_badkey(t *testing.T) {
+	cases := []struct {
+		Name string
+		// what the resource has defined in source
+		ResourceDefaultTimeout *ResourceTimeout
+		// configuration provider by user in tf file
+		Config map[string]interface{}
+		// what we expect the parsed ResourceTimeout to be
+		Expected *ResourceTimeout
+		// Should we have an error (key not defined in source)
+		ShouldErr bool
+	}{
+		{
+			Name:                   "Source does not define 'delete' key",
+			ResourceDefaultTimeout: timeoutForValues(10, 0, 5, 0, 0),
+			Config:                 expectedConfigForValues(2, 0, 0, 1, 0),
+			Expected:               timeoutForValues(10, 0, 5, 0, 0),
+			ShouldErr:              true,
+		},
+		{
+			Name:                   "Config overrides create",
+			ResourceDefaultTimeout: timeoutForValues(10, 0, 5, 0, 0),
+			Config:                 expectedConfigForValues(2, 0, 7, 0, 0),
+			Expected:               timeoutForValues(2, 0, 7, 0, 0),
+			ShouldErr:              false,
+		},
+		{
+			Name:                   "Config overrides create, default provided. Should still have zero values",
+			ResourceDefaultTimeout: timeoutForValues(10, 0, 5, 0, 3),
+			Config:                 expectedConfigForValues(2, 0, 7, 0, 0),
+			Expected:               timeoutForValues(2, 0, 7, 0, 3),
+			ShouldErr:              false,
+		},
+		{
+			Name:                   "Use something besides 'minutes'",
+			ResourceDefaultTimeout: timeoutForValues(10, 0, 5, 0, 3),
+			Config: map[string]interface{}{
+				"create": "2h",
+			},
+			Expected:  timeoutForValues(120, 0, 5, 0, 3),
+			ShouldErr: false,
+		},
+	}
+
+	for i, c := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, c.Name), func(t *testing.T) {
+			r := &Resource{
+				Timeouts: c.ResourceDefaultTimeout,
+			}
+
+			conf := terraform.NewResourceConfigRaw(
+				map[string]interface{}{
+					"foo":             "bar",
+					TimeoutsConfigKey: c.Config,
+				},
+			)
+
+			timeout := &ResourceTimeout{}
+			decodeErr := timeout.ConfigDecode(r, conf)
+			if c.ShouldErr {
+				if decodeErr == nil {
+					t.Fatalf("ConfigDecode case (%d): Expected bad timeout key: %s", i, decodeErr)
+				}
+				// should error, err was not nil, continue
+				return
+			} else {
+				if decodeErr != nil {
+					// should not error, error was not nil, fatal
+					t.Fatalf("decodeError was not nil: %s", decodeErr)
+				}
+			}
+
+			if !reflect.DeepEqual(c.Expected, timeout) {
+				t.Fatalf("ConfigDecode match error case (%d).\nExpected:\n%#v\nGot:\n%#v", i, c.Expected, timeout)
+			}
+		})
+	}
+}
+
+func TestResourceTimeout_ConfigDecode(t *testing.T) {
+	r := &Resource{
+		Timeouts: &ResourceTimeout{
+			Create: DefaultTimeout(10 * time.Minute),
+			Update: DefaultTimeout(5 * time.Minute),
+		},
+	}
+
+	c := terraform.NewResourceConfigRaw(
+		map[string]interface{}{
+			"foo": "bar",
+			TimeoutsConfigKey: map[string]interface{}{
+				"create": "2m",
+				"update": "1m",
+			},
+		},
+	)
+
+	timeout := &ResourceTimeout{}
+	err := timeout.ConfigDecode(r, c)
+	if err != nil {
+		t.Fatalf("Expected good timeout returned:, %s", err)
+	}
+
+	expected := &ResourceTimeout{
+		Create: DefaultTimeout(2 * time.Minute),
+		Update: DefaultTimeout(1 * time.Minute),
+	}
+
+	if !reflect.DeepEqual(timeout, expected) {
+		t.Fatalf("bad timeout decode.\nExpected:\n%#v\nGot:\n%#v\n", expected, timeout)
+	}
+}
+
+func TestResourceTimeout_legacyConfigDecode(t *testing.T) {
+	r := &Resource{
+		Timeouts: &ResourceTimeout{
+			Create: DefaultTimeout(10 * time.Minute),
+			Update: DefaultTimeout(5 * time.Minute),
+		},
+	}
+
+	c := terraform.NewResourceConfigRaw(
+		map[string]interface{}{
+			"foo": "bar",
+			TimeoutsConfigKey: []interface{}{
+				map[string]interface{}{
+					"create": "2m",
+					"update": "1m",
+				},
+			},
+		},
+	)
+
+	timeout := &ResourceTimeout{}
+	err := timeout.ConfigDecode(r, c)
+	if err != nil {
+		t.Fatalf("Expected good timeout returned:, %s", err)
+	}
+
+	expected := &ResourceTimeout{
+		Create: DefaultTimeout(2 * time.Minute),
+		Update: DefaultTimeout(1 * time.Minute),
+	}
+
+	if !reflect.DeepEqual(timeout, expected) {
+		t.Fatalf("bad timeout decode.\nExpected:\n%#v\nGot:\n%#v\n", expected, timeout)
+	}
+}
+
+func TestResourceTimeout_DiffEncode_basic(t *testing.T) {
+	cases := []struct {
+		Timeout  *ResourceTimeout
+		Expected map[string]interface{}
+		// Not immediately clear when an error would hit
+		ShouldErr bool
+	}{
+		// Two fields
+		{
+			Timeout:   timeoutForValues(10, 0, 5, 0, 0),
+			Expected:  map[string]interface{}{TimeoutKey: expectedForValues(10, 0, 5, 0, 0)},
+			ShouldErr: false,
+		},
+		// Two fields, one is Default
+		{
+			Timeout:   timeoutForValues(10, 0, 0, 0, 7),
+			Expected:  map[string]interface{}{TimeoutKey: expectedForValues(10, 0, 0, 0, 7)},
+			ShouldErr: false,
+		},
+		// All fields
+		{
+			Timeout:   timeoutForValues(10, 3, 4, 1, 7),
+			Expected:  map[string]interface{}{TimeoutKey: expectedForValues(10, 3, 4, 1, 7)},
+			ShouldErr: false,
+		},
+		// No fields
+		{
+			Timeout:   &ResourceTimeout{},
+			Expected:  nil,
+			ShouldErr: false,
+		},
+	}
+
+	for _, c := range cases {
+		state := &terraform.InstanceDiff{}
+		err := c.Timeout.DiffEncode(state)
+		if err != nil && !c.ShouldErr {
+			t.Fatalf("Error, expected:\n%#v\n got:\n%#v\n", c.Expected, state.Meta)
+		}
+
+		// should maybe just compare [TimeoutKey] but for now we're assuming only
+		// that in Meta
+		if !reflect.DeepEqual(state.Meta, c.Expected) {
+			t.Fatalf("Encode not equal, expected:\n%#v\n\ngot:\n%#v\n", c.Expected, state.Meta)
+		}
+	}
+	// same test cases but for InstanceState
+	for _, c := range cases {
+		state := &terraform.InstanceState{}
+		err := c.Timeout.StateEncode(state)
+		if err != nil && !c.ShouldErr {
+			t.Fatalf("Error, expected:\n%#v\n got:\n%#v\n", c.Expected, state.Meta)
+		}
+
+		// should maybe just compare [TimeoutKey] but for now we're assuming only
+		// that in Meta
+		if !reflect.DeepEqual(state.Meta, c.Expected) {
+			t.Fatalf("Encode not equal, expected:\n%#v\n\ngot:\n%#v\n", c.Expected, state.Meta)
+		}
+	}
+}
+
+func TestResourceTimeout_MetaDecode_basic(t *testing.T) {
+	cases := []struct {
+		State    *terraform.InstanceDiff
+		Expected *ResourceTimeout
+		// Not immediately clear when an error would hit
+		ShouldErr bool
+	}{
+		// Two fields
+		{
+			State:     &terraform.InstanceDiff{Meta: map[string]interface{}{TimeoutKey: expectedForValues(10, 0, 5, 0, 0)}},
+			Expected:  timeoutForValues(10, 0, 5, 0, 0),
+			ShouldErr: false,
+		},
+		// Two fields, one is Default
+		{
+			State:     &terraform.InstanceDiff{Meta: map[string]interface{}{TimeoutKey: expectedForValues(10, 0, 0, 0, 7)}},
+			Expected:  timeoutForValues(10, 7, 7, 7, 7),
+			ShouldErr: false,
+		},
+		// All fields
+		{
+			State:     &terraform.InstanceDiff{Meta: map[string]interface{}{TimeoutKey: expectedForValues(10, 3, 4, 1, 7)}},
+			Expected:  timeoutForValues(10, 3, 4, 1, 7),
+			ShouldErr: false,
+		},
+		// No fields
+		{
+			State:     &terraform.InstanceDiff{},
+			Expected:  &ResourceTimeout{},
+			ShouldErr: false,
+		},
+	}
+
+	for _, c := range cases {
+		rt := &ResourceTimeout{}
+		err := rt.DiffDecode(c.State)
+		if err != nil && !c.ShouldErr {
+			t.Fatalf("Error, expected:\n%#v\n got:\n%#v\n", c.Expected, rt)
+		}
+
+		// should maybe just compare [TimeoutKey] but for now we're assuming only
+		// that in Meta
+		if !reflect.DeepEqual(rt, c.Expected) {
+			t.Fatalf("Encode not equal, expected:\n%#v\n\ngot:\n%#v\n", c.Expected, rt)
+		}
+	}
+}
+
+func timeoutForValues(create, read, update, del, def int) *ResourceTimeout {
+	rt := ResourceTimeout{}
+
+	if create != 0 {
+		rt.Create = DefaultTimeout(time.Duration(create) * time.Minute)
+	}
+	if read != 0 {
+		rt.Read = DefaultTimeout(time.Duration(read) * time.Minute)
+	}
+	if update != 0 {
+		rt.Update = DefaultTimeout(time.Duration(update) * time.Minute)
+	}
+	if del != 0 {
+		rt.Delete = DefaultTimeout(time.Duration(del) * time.Minute)
+	}
+
+	if def != 0 {
+		rt.Default = DefaultTimeout(time.Duration(def) * time.Minute)
+	}
+
+	return &rt
+}
+
+// Generates a ResourceTimeout struct that should reflect the
+// d.Timeout("key") results
+func expectedTimeoutForValues(create, read, update, del, def int) *ResourceTimeout {
+	rt := ResourceTimeout{}
+
+	defaultValues := []*int{&create, &read, &update, &del, &def}
+	for _, v := range defaultValues {
+		if *v == 0 {
+			*v = 20
+		}
+	}
+
+	if create != 0 {
+		rt.Create = DefaultTimeout(time.Duration(create) * time.Minute)
+	}
+	if read != 0 {
+		rt.Read = DefaultTimeout(time.Duration(read) * time.Minute)
+	}
+	if update != 0 {
+		rt.Update = DefaultTimeout(time.Duration(update) * time.Minute)
+	}
+	if del != 0 {
+		rt.Delete = DefaultTimeout(time.Duration(del) * time.Minute)
+	}
+
+	if def != 0 {
+		rt.Default = DefaultTimeout(time.Duration(def) * time.Minute)
+	}
+
+	return &rt
+}
+
+func expectedForValues(create, read, update, del, def int) map[string]interface{} {
+	ex := make(map[string]interface{})
+
+	if create != 0 {
+		ex["create"] = DefaultTimeout(time.Duration(create) * time.Minute).Nanoseconds()
+	}
+	if read != 0 {
+		ex["read"] = DefaultTimeout(time.Duration(read) * time.Minute).Nanoseconds()
+	}
+	if update != 0 {
+		ex["update"] = DefaultTimeout(time.Duration(update) * time.Minute).Nanoseconds()
+	}
+	if del != 0 {
+		ex["delete"] = DefaultTimeout(time.Duration(del) * time.Minute).Nanoseconds()
+	}
+
+	if def != 0 {
+		defNano := DefaultTimeout(time.Duration(def) * time.Minute).Nanoseconds()
+		ex["default"] = defNano
+
+		for _, k := range timeoutKeys() {
+			if _, ok := ex[k]; !ok {
+				ex[k] = defNano
+			}
+		}
+	}
+
+	return ex
+}
+
+func expectedConfigForValues(create, read, update, delete, def int) map[string]interface{} {
+	ex := make(map[string]interface{}, 0)
+
+	if create != 0 {
+		ex["create"] = fmt.Sprintf("%dm", create)
+	}
+	if read != 0 {
+		ex["read"] = fmt.Sprintf("%dm", read)
+	}
+	if update != 0 {
+		ex["update"] = fmt.Sprintf("%dm", update)
+	}
+	if delete != 0 {
+		ex["delete"] = fmt.Sprintf("%dm", delete)
+	}
+
+	if def != 0 {
+		ex["default"] = fmt.Sprintf("%dm", def)
+	}
+	return ex
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/schema.go b/v1.5.7/internal/legacy/helper/schema/schema.go
new file mode 100644
index 0000000..f96002b
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/schema.go
@@ -0,0 +1,1857 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// schema is a high-level framework for easily writing new providers
+// for Terraform. Usage of schema is recommended over attempting to write
+// to the low-level plugin interfaces manually.
+//
+// schema breaks down provider creation into simple CRUD operations for
+// resources. The logic of diffing, destroying before creating, updating
+// or creating, etc. is all handled by the framework. The plugin author
+// only needs to implement a configuration schema and the CRUD operations and
+// everything else is meant to just work.
+//
+// A good starting point is to view the Provider structure.
+package schema
+
+import (
+	"context"
+	"fmt"
+	"os"
+	"reflect"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+	"github.com/mitchellh/copystructure"
+	"github.com/mitchellh/mapstructure"
+)
+
+// Name of ENV variable which (if not empty) prefers panic over error
+const PanicOnErr = "TF_SCHEMA_PANIC_ON_ERROR"
+
+// type used for schema package context keys
+type contextKey string
+
+var (
+	protoVersionMu sync.Mutex
+	protoVersion5  = false
+)
+
+func isProto5() bool {
+	protoVersionMu.Lock()
+	defer protoVersionMu.Unlock()
+	return protoVersion5
+
+}
+
+// SetProto5 enables a feature flag for any internal changes required required
+// to work with the new plugin protocol.  This should not be called by
+// provider.
+func SetProto5() {
+	protoVersionMu.Lock()
+	defer protoVersionMu.Unlock()
+	protoVersion5 = true
+}
+
+// Schema is used to describe the structure of a value.
+//
+// Read the documentation of the struct elements for important details.
+type Schema struct {
+	// Type is the type of the value and must be one of the ValueType values.
+	//
+	// This type not only determines what type is expected/valid in configuring
+	// this value, but also what type is returned when ResourceData.Get is
+	// called. The types returned by Get are:
+	//
+	//   TypeBool - bool
+	//   TypeInt - int
+	//   TypeFloat - float64
+	//   TypeString - string
+	//   TypeList - []interface{}
+	//   TypeMap - map[string]interface{}
+	//   TypeSet - *schema.Set
+	//
+	Type ValueType
+
+	// ConfigMode allows for overriding the default behaviors for mapping
+	// schema entries onto configuration constructs.
+	//
+	// By default, the Elem field is used to choose whether a particular
+	// schema is represented in configuration as an attribute or as a nested
+	// block; if Elem is a *schema.Resource then it's a block and it's an
+	// attribute otherwise.
+	//
+	// If Elem is *schema.Resource then setting ConfigMode to
+	// SchemaConfigModeAttr will force it to be represented in configuration
+	// as an attribute, which means that the Computed flag can be used to
+	// provide default elements when the argument isn't set at all, while still
+	// allowing the user to force zero elements by explicitly assigning an
+	// empty list.
+	//
+	// When Computed is set without Optional, the attribute is not settable
+	// in configuration at all and so SchemaConfigModeAttr is the automatic
+	// behavior, and SchemaConfigModeBlock is not permitted.
+	ConfigMode SchemaConfigMode
+
+	// If one of these is set, then this item can come from the configuration.
+	// Both cannot be set. If Optional is set, the value is optional. If
+	// Required is set, the value is required.
+	//
+	// One of these must be set if the value is not computed. That is:
+	// value either comes from the config, is computed, or is both.
+	Optional bool
+	Required bool
+
+	// If this is non-nil, the provided function will be used during diff
+	// of this field. If this is nil, a default diff for the type of the
+	// schema will be used.
+	//
+	// This allows comparison based on something other than primitive, list
+	// or map equality - for example SSH public keys may be considered
+	// equivalent regardless of trailing whitespace.
+	DiffSuppressFunc SchemaDiffSuppressFunc
+
+	// If this is non-nil, then this will be a default value that is used
+	// when this item is not set in the configuration.
+	//
+	// DefaultFunc can be specified to compute a dynamic default.
+	// Only one of Default or DefaultFunc can be set. If DefaultFunc is
+	// used then its return value should be stable to avoid generating
+	// confusing/perpetual diffs.
+	//
+	// Changing either Default or the return value of DefaultFunc can be
+	// a breaking change, especially if the attribute in question has
+	// ForceNew set. If a default needs to change to align with changing
+	// assumptions in an upstream API then it may be necessary to also use
+	// the MigrateState function on the resource to change the state to match,
+	// or have the Read function adjust the state value to align with the
+	// new default.
+	//
+	// If Required is true above, then Default cannot be set. DefaultFunc
+	// can be set with Required. If the DefaultFunc returns nil, then there
+	// will be no default and the user will be asked to fill it in.
+	//
+	// If either of these is set, then the user won't be asked for input
+	// for this key if the default is not nil.
+	Default     interface{}
+	DefaultFunc SchemaDefaultFunc
+
+	// Description is used as the description for docs or asking for user
+	// input. It should be relatively short (a few sentences max) and should
+	// be formatted to fit a CLI.
+	Description string
+
+	// InputDefault is the default value to use for when inputs are requested.
+	// This differs from Default in that if Default is set, no input is
+	// asked for. If Input is asked, this will be the default value offered.
+	InputDefault string
+
+	// The fields below relate to diffs.
+	//
+	// If Computed is true, then the result of this value is computed
+	// (unless specified by config) on creation.
+	//
+	// If ForceNew is true, then a change in this resource necessitates
+	// the creation of a new resource.
+	//
+	// StateFunc is a function called to change the value of this before
+	// storing it in the state (and likewise before comparing for diffs).
+	// The use for this is for example with large strings, you may want
+	// to simply store the hash of it.
+	Computed  bool
+	ForceNew  bool
+	StateFunc SchemaStateFunc
+
+	// The following fields are only set for a TypeList, TypeSet, or TypeMap.
+	//
+	// Elem represents the element type. For a TypeMap, it must be a *Schema
+	// with a Type that is one of the primitives: TypeString, TypeBool,
+	// TypeInt, or TypeFloat. Otherwise it may be either a *Schema or a
+	// *Resource. If it is *Schema, the element type is just a simple value.
+	// If it is *Resource, the element type is a complex structure,
+	// potentially managed via its own CRUD actions on the API.
+	Elem interface{}
+
+	// The following fields are only set for a TypeList or TypeSet.
+	//
+	// MaxItems defines a maximum amount of items that can exist within a
+	// TypeSet or TypeList. Specific use cases would be if a TypeSet is being
+	// used to wrap a complex structure, however more than one instance would
+	// cause instability.
+	//
+	// MinItems defines a minimum amount of items that can exist within a
+	// TypeSet or TypeList. Specific use cases would be if a TypeSet is being
+	// used to wrap a complex structure, however less than one instance would
+	// cause instability.
+	//
+	// If the field Optional is set to true then MinItems is ignored and thus
+	// effectively zero.
+	MaxItems int
+	MinItems int
+
+	// PromoteSingle originally allowed for a single element to be assigned
+	// where a primitive list was expected, but this no longer works from
+	// Terraform v0.12 onwards (Terraform Core will require a list to be set
+	// regardless of what this is set to) and so only applies to Terraform v0.11
+	// and earlier, and so should be used only to retain this functionality
+	// for those still using v0.11 with a provider that formerly used this.
+	PromoteSingle bool
+
+	// The following fields are only valid for a TypeSet type.
+	//
+	// Set defines a function to determine the unique ID of an item so that
+	// a proper set can be built.
+	Set SchemaSetFunc
+
+	// ComputedWhen is a set of queries on the configuration. Whenever any
+	// of these things is changed, it will require a recompute (this requires
+	// that Computed is set to true).
+	//
+	// NOTE: This currently does not work.
+	ComputedWhen []string
+
+	// ConflictsWith is a set of schema keys that conflict with this schema.
+	// This will only check that they're set in the _config_. This will not
+	// raise an error for a malfunctioning resource that sets a conflicting
+	// key.
+	ConflictsWith []string
+
+	// When Deprecated is set, this attribute is deprecated.
+	//
+	// A deprecated field still works, but will probably stop working in near
+	// future. This string is the message shown to the user with instructions on
+	// how to address the deprecation.
+	Deprecated string
+
+	// When Removed is set, this attribute has been removed from the schema
+	//
+	// Removed attributes can be left in the Schema to generate informative error
+	// messages for the user when they show up in resource configurations.
+	// This string is the message shown to the user with instructions on
+	// what do to about the removed attribute.
+	Removed string
+
+	// ValidateFunc allows individual fields to define arbitrary validation
+	// logic. It is yielded the provided config value as an interface{} that is
+	// guaranteed to be of the proper Schema type, and it can yield warnings or
+	// errors based on inspection of that value.
+	//
+	// ValidateFunc is honored only when the schema's Type is set to TypeInt,
+	// TypeFloat, TypeString, TypeBool, or TypeMap. It is ignored for all other types.
+	ValidateFunc SchemaValidateFunc
+
+	// Sensitive ensures that the attribute's value does not get displayed in
+	// logs or regular output. It should be used for passwords or other
+	// secret fields. Future versions of Terraform may encrypt these
+	// values.
+	Sensitive bool
+}
+
+// SchemaConfigMode is used to influence how a schema item is mapped into a
+// corresponding configuration construct, using the ConfigMode field of
+// Schema.
+type SchemaConfigMode int
+
+const (
+	SchemaConfigModeAuto SchemaConfigMode = iota
+	SchemaConfigModeAttr
+	SchemaConfigModeBlock
+)
+
+// SchemaDiffSuppressFunc is a function which can be used to determine
+// whether a detected diff on a schema element is "valid" or not, and
+// suppress it from the plan if necessary.
+//
+// Return true if the diff should be suppressed, false to retain it.
+type SchemaDiffSuppressFunc func(k, old, new string, d *ResourceData) bool
+
+// SchemaDefaultFunc is a function called to return a default value for
+// a field.
+type SchemaDefaultFunc func() (interface{}, error)
+
+// EnvDefaultFunc is a helper function that returns the value of the
+// given environment variable, if one exists, or the default value
+// otherwise.
+func EnvDefaultFunc(k string, dv interface{}) SchemaDefaultFunc {
+	return func() (interface{}, error) {
+		if v := os.Getenv(k); v != "" {
+			return v, nil
+		}
+
+		return dv, nil
+	}
+}
+
+// MultiEnvDefaultFunc is a helper function that returns the value of the first
+// environment variable in the given list that returns a non-empty value. If
+// none of the environment variables return a value, the default value is
+// returned.
+func MultiEnvDefaultFunc(ks []string, dv interface{}) SchemaDefaultFunc {
+	return func() (interface{}, error) {
+		for _, k := range ks {
+			if v := os.Getenv(k); v != "" {
+				return v, nil
+			}
+		}
+		return dv, nil
+	}
+}
+
+// SchemaSetFunc is a function that must return a unique ID for the given
+// element. This unique ID is used to store the element in a hash.
+type SchemaSetFunc func(interface{}) int
+
+// SchemaStateFunc is a function used to convert some type to a string
+// to be stored in the state.
+type SchemaStateFunc func(interface{}) string
+
+// SchemaValidateFunc is a function used to validate a single field in the
+// schema.
+type SchemaValidateFunc func(interface{}, string) ([]string, []error)
+
+func (s *Schema) GoString() string {
+	return fmt.Sprintf("*%#v", *s)
+}
+
+// Returns a default value for this schema by either reading Default or
+// evaluating DefaultFunc. If neither of these are defined, returns nil.
+func (s *Schema) DefaultValue() (interface{}, error) {
+	if s.Default != nil {
+		return s.Default, nil
+	}
+
+	if s.DefaultFunc != nil {
+		defaultValue, err := s.DefaultFunc()
+		if err != nil {
+			return nil, fmt.Errorf("error loading default: %s", err)
+		}
+		return defaultValue, nil
+	}
+
+	return nil, nil
+}
+
+// Returns a zero value for the schema.
+func (s *Schema) ZeroValue() interface{} {
+	// If it's a set then we'll do a bit of extra work to provide the
+	// right hashing function in our empty value.
+	if s.Type == TypeSet {
+		setFunc := s.Set
+		if setFunc == nil {
+			// Default set function uses the schema to hash the whole value
+			elem := s.Elem
+			switch t := elem.(type) {
+			case *Schema:
+				setFunc = HashSchema(t)
+			case *Resource:
+				setFunc = HashResource(t)
+			default:
+				panic("invalid set element type")
+			}
+		}
+		return &Set{F: setFunc}
+	} else {
+		return s.Type.Zero()
+	}
+}
+
+func (s *Schema) finalizeDiff(d *terraform.ResourceAttrDiff, customized bool) *terraform.ResourceAttrDiff {
+	if d == nil {
+		return d
+	}
+
+	if s.Type == TypeBool {
+		normalizeBoolString := func(s string) string {
+			switch s {
+			case "0":
+				return "false"
+			case "1":
+				return "true"
+			}
+			return s
+		}
+		d.Old = normalizeBoolString(d.Old)
+		d.New = normalizeBoolString(d.New)
+	}
+
+	if s.Computed && !d.NewRemoved && d.New == "" {
+		// Computed attribute without a new value set
+		d.NewComputed = true
+	}
+
+	if s.ForceNew {
+		// ForceNew, mark that this field is requiring new under the
+		// following conditions, explained below:
+		//
+		//   * Old != New - There is a change in value. This field
+		//       is therefore causing a new resource.
+		//
+		//   * NewComputed - This field is being computed, hence a
+		//       potential change in value, mark as causing a new resource.
+		d.RequiresNew = d.Old != d.New || d.NewComputed
+	}
+
+	if d.NewRemoved {
+		return d
+	}
+
+	if s.Computed {
+		// FIXME: This is where the customized bool from getChange finally
+		//        comes into play.  It allows the previously incorrect behavior
+		//        of an empty string being used as "unset" when the value is
+		//        computed. This should be removed once we can properly
+		//        represent an unset/nil value from the configuration.
+		if !customized {
+			if d.Old != "" && d.New == "" {
+				// This is a computed value with an old value set already,
+				// just let it go.
+				return nil
+			}
+		}
+
+		if d.New == "" && !d.NewComputed {
+			// Computed attribute without a new value set
+			d.NewComputed = true
+		}
+	}
+
+	if s.Sensitive {
+		// Set the Sensitive flag so output is hidden in the UI
+		d.Sensitive = true
+	}
+
+	return d
+}
+
+// InternalMap is used to aid in the transition to the new schema types and
+// protocol. The name is not meant to convey any usefulness, as this is not to
+// be used directly by any providers.
+type InternalMap = schemaMap
+
+// schemaMap is a wrapper that adds nice functions on top of schemas.
+type schemaMap map[string]*Schema
+
+func (m schemaMap) panicOnError() bool {
+	if os.Getenv(PanicOnErr) != "" {
+		return true
+	}
+	return false
+}
+
+// Data returns a ResourceData for the given schema, state, and diff.
+//
+// The diff is optional.
+func (m schemaMap) Data(
+	s *terraform.InstanceState,
+	d *terraform.InstanceDiff) (*ResourceData, error) {
+	return &ResourceData{
+		schema:       m,
+		state:        s,
+		diff:         d,
+		panicOnError: m.panicOnError(),
+	}, nil
+}
+
+// DeepCopy returns a copy of this schemaMap. The copy can be safely modified
+// without affecting the original.
+func (m *schemaMap) DeepCopy() schemaMap {
+	copy, err := copystructure.Config{Lock: true}.Copy(m)
+	if err != nil {
+		panic(err)
+	}
+	return *copy.(*schemaMap)
+}
+
+// Diff returns the diff for a resource given the schema map,
+// state, and configuration.
+func (m schemaMap) Diff(
+	s *terraform.InstanceState,
+	c *terraform.ResourceConfig,
+	customizeDiff CustomizeDiffFunc,
+	meta interface{},
+	handleRequiresNew bool) (*terraform.InstanceDiff, error) {
+	result := new(terraform.InstanceDiff)
+	result.Attributes = make(map[string]*terraform.ResourceAttrDiff)
+
+	// Make sure to mark if the resource is tainted
+	if s != nil {
+		result.DestroyTainted = s.Tainted
+	}
+
+	d := &ResourceData{
+		schema:       m,
+		state:        s,
+		config:       c,
+		panicOnError: m.panicOnError(),
+	}
+
+	for k, schema := range m {
+		err := m.diff(k, schema, result, d, false)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	// Remove any nil diffs just to keep things clean
+	for k, v := range result.Attributes {
+		if v == nil {
+			delete(result.Attributes, k)
+		}
+	}
+
+	// If this is a non-destroy diff, call any custom diff logic that has been
+	// defined.
+	if !result.DestroyTainted && customizeDiff != nil {
+		mc := m.DeepCopy()
+		rd := newResourceDiff(mc, c, s, result)
+		if err := customizeDiff(rd, meta); err != nil {
+			return nil, err
+		}
+		for _, k := range rd.UpdatedKeys() {
+			err := m.diff(k, mc[k], result, rd, false)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	if handleRequiresNew {
+		// If the diff requires a new resource, then we recompute the diff
+		// so we have the complete new resource diff, and preserve the
+		// RequiresNew fields where necessary so the user knows exactly what
+		// caused that.
+		if result.RequiresNew() {
+			// Create the new diff
+			result2 := new(terraform.InstanceDiff)
+			result2.Attributes = make(map[string]*terraform.ResourceAttrDiff)
+
+			// Preserve the DestroyTainted flag
+			result2.DestroyTainted = result.DestroyTainted
+
+			// Reset the data to not contain state. We have to call init()
+			// again in order to reset the FieldReaders.
+			d.state = nil
+			d.init()
+
+			// Perform the diff again
+			for k, schema := range m {
+				err := m.diff(k, schema, result2, d, false)
+				if err != nil {
+					return nil, err
+				}
+			}
+
+			// Re-run customization
+			if !result2.DestroyTainted && customizeDiff != nil {
+				mc := m.DeepCopy()
+				rd := newResourceDiff(mc, c, d.state, result2)
+				if err := customizeDiff(rd, meta); err != nil {
+					return nil, err
+				}
+				for _, k := range rd.UpdatedKeys() {
+					err := m.diff(k, mc[k], result2, rd, false)
+					if err != nil {
+						return nil, err
+					}
+				}
+			}
+
+			// Force all the fields to not force a new since we know what we
+			// want to force new.
+			for k, attr := range result2.Attributes {
+				if attr == nil {
+					continue
+				}
+
+				if attr.RequiresNew {
+					attr.RequiresNew = false
+				}
+
+				if s != nil {
+					attr.Old = s.Attributes[k]
+				}
+			}
+
+			// Now copy in all the requires new diffs...
+			for k, attr := range result.Attributes {
+				if attr == nil {
+					continue
+				}
+
+				newAttr, ok := result2.Attributes[k]
+				if !ok {
+					newAttr = attr
+				}
+
+				if attr.RequiresNew {
+					newAttr.RequiresNew = true
+				}
+
+				result2.Attributes[k] = newAttr
+			}
+
+			// And set the diff!
+			result = result2
+		}
+
+	}
+
+	// Go through and detect all of the ComputedWhens now that we've
+	// finished the diff.
+	// TODO
+
+	if result.Empty() {
+		// If we don't have any diff elements, just return nil
+		return nil, nil
+	}
+
+	return result, nil
+}
+
+// Input implements the terraform.ResourceProvider method by asking
+// for input for required configuration keys that don't have a value.
+func (m schemaMap) Input(
+	input terraform.UIInput,
+	c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) {
+	keys := make([]string, 0, len(m))
+	for k, _ := range m {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+
+	for _, k := range keys {
+		v := m[k]
+
+		// Skip things that don't require config, if that is even valid
+		// for a provider schema.
+		// Required XOR Optional must always be true to validate, so we only
+		// need to check one.
+		if v.Optional {
+			continue
+		}
+
+		// Deprecated fields should never prompt
+		if v.Deprecated != "" {
+			continue
+		}
+
+		// Skip things that have a value of some sort already
+		if _, ok := c.Raw[k]; ok {
+			continue
+		}
+
+		// Skip if it has a default value
+		defaultValue, err := v.DefaultValue()
+		if err != nil {
+			return nil, fmt.Errorf("%s: error loading default: %s", k, err)
+		}
+		if defaultValue != nil {
+			continue
+		}
+
+		var value interface{}
+		switch v.Type {
+		case TypeBool, TypeInt, TypeFloat, TypeSet, TypeList:
+			continue
+		case TypeString:
+			value, err = m.inputString(input, k, v)
+		default:
+			panic(fmt.Sprintf("Unknown type for input: %#v", v.Type))
+		}
+
+		if err != nil {
+			return nil, fmt.Errorf(
+				"%s: %s", k, err)
+		}
+
+		c.Config[k] = value
+	}
+
+	return c, nil
+}
+
+// Validate validates the configuration against this schema mapping.
+func (m schemaMap) Validate(c *terraform.ResourceConfig) ([]string, []error) {
+	return m.validateObject("", m, c)
+}
+
+// InternalValidate validates the format of this schema. This should be called
+// from a unit test (and not in user-path code) to verify that a schema
+// is properly built.
+func (m schemaMap) InternalValidate(topSchemaMap schemaMap) error {
+	return m.internalValidate(topSchemaMap, false)
+}
+
+func (m schemaMap) internalValidate(topSchemaMap schemaMap, attrsOnly bool) error {
+	if topSchemaMap == nil {
+		topSchemaMap = m
+	}
+	for k, v := range m {
+		if v.Type == TypeInvalid {
+			return fmt.Errorf("%s: Type must be specified", k)
+		}
+
+		if v.Optional && v.Required {
+			return fmt.Errorf("%s: Optional or Required must be set, not both", k)
+		}
+
+		if v.Required && v.Computed {
+			return fmt.Errorf("%s: Cannot be both Required and Computed", k)
+		}
+
+		if !v.Required && !v.Optional && !v.Computed {
+			return fmt.Errorf("%s: One of optional, required, or computed must be set", k)
+		}
+
+		computedOnly := v.Computed && !v.Optional
+
+		switch v.ConfigMode {
+		case SchemaConfigModeBlock:
+			if _, ok := v.Elem.(*Resource); !ok {
+				return fmt.Errorf("%s: ConfigMode of block is allowed only when Elem is *schema.Resource", k)
+			}
+			if attrsOnly {
+				return fmt.Errorf("%s: ConfigMode of block cannot be used in child of schema with ConfigMode of attribute", k)
+			}
+			if computedOnly {
+				return fmt.Errorf("%s: ConfigMode of block cannot be used for computed schema", k)
+			}
+		case SchemaConfigModeAttr:
+			// anything goes
+		case SchemaConfigModeAuto:
+			// Since "Auto" for Elem: *Resource would create a nested block,
+			// and that's impossible inside an attribute, we require it to be
+			// explicitly overridden as mode "Attr" for clarity.
+			if _, ok := v.Elem.(*Resource); ok {
+				if attrsOnly {
+					return fmt.Errorf("%s: in *schema.Resource with ConfigMode of attribute, so must also have ConfigMode of attribute", k)
+				}
+			}
+		default:
+			return fmt.Errorf("%s: invalid ConfigMode value", k)
+		}
+
+		if v.Computed && v.Default != nil {
+			return fmt.Errorf("%s: Default must be nil if computed", k)
+		}
+
+		if v.Required && v.Default != nil {
+			return fmt.Errorf("%s: Default cannot be set with Required", k)
+		}
+
+		if len(v.ComputedWhen) > 0 && !v.Computed {
+			return fmt.Errorf("%s: ComputedWhen can only be set with Computed", k)
+		}
+
+		if len(v.ConflictsWith) > 0 && v.Required {
+			return fmt.Errorf("%s: ConflictsWith cannot be set with Required", k)
+		}
+
+		if len(v.ConflictsWith) > 0 {
+			for _, key := range v.ConflictsWith {
+				parts := strings.Split(key, ".")
+				sm := topSchemaMap
+				var target *Schema
+				for _, part := range parts {
+					// Skip index fields
+					if _, err := strconv.Atoi(part); err == nil {
+						continue
+					}
+
+					var ok bool
+					if target, ok = sm[part]; !ok {
+						return fmt.Errorf("%s: ConflictsWith references unknown attribute (%s) at part (%s)", k, key, part)
+					}
+
+					if subResource, ok := target.Elem.(*Resource); ok {
+						sm = schemaMap(subResource.Schema)
+					}
+				}
+				if target == nil {
+					return fmt.Errorf("%s: ConflictsWith cannot find target attribute (%s), sm: %#v", k, key, sm)
+				}
+				if target.Required {
+					return fmt.Errorf("%s: ConflictsWith cannot contain Required attribute (%s)", k, key)
+				}
+
+				if len(target.ComputedWhen) > 0 {
+					return fmt.Errorf("%s: ConflictsWith cannot contain Computed(When) attribute (%s)", k, key)
+				}
+			}
+		}
+
+		if v.Type == TypeList || v.Type == TypeSet {
+			if v.Elem == nil {
+				return fmt.Errorf("%s: Elem must be set for lists", k)
+			}
+
+			if v.Default != nil {
+				return fmt.Errorf("%s: Default is not valid for lists or sets", k)
+			}
+
+			if v.Type != TypeSet && v.Set != nil {
+				return fmt.Errorf("%s: Set can only be set for TypeSet", k)
+			}
+
+			switch t := v.Elem.(type) {
+			case *Resource:
+				attrsOnly := attrsOnly || v.ConfigMode == SchemaConfigModeAttr
+
+				if err := schemaMap(t.Schema).internalValidate(topSchemaMap, attrsOnly); err != nil {
+					return err
+				}
+			case *Schema:
+				bad := t.Computed || t.Optional || t.Required
+				if bad {
+					return fmt.Errorf(
+						"%s: Elem must have only Type set", k)
+				}
+			}
+		} else {
+			if v.MaxItems > 0 || v.MinItems > 0 {
+				return fmt.Errorf("%s: MaxItems and MinItems are only supported on lists or sets", k)
+			}
+		}
+
+		// Computed-only field
+		if v.Computed && !v.Optional {
+			if v.ValidateFunc != nil {
+				return fmt.Errorf("%s: ValidateFunc is for validating user input, "+
+					"there's nothing to validate on computed-only field", k)
+			}
+			if v.DiffSuppressFunc != nil {
+				return fmt.Errorf("%s: DiffSuppressFunc is for suppressing differences"+
+					" between config and state representation. "+
+					"There is no config for computed-only field, nothing to compare.", k)
+			}
+		}
+
+		if v.ValidateFunc != nil {
+			switch v.Type {
+			case TypeList, TypeSet:
+				return fmt.Errorf("%s: ValidateFunc is not yet supported on lists or sets.", k)
+			}
+		}
+
+		if v.Deprecated == "" && v.Removed == "" {
+			if !isValidFieldName(k) {
+				return fmt.Errorf("%s: Field name may only contain lowercase alphanumeric characters & underscores.", k)
+			}
+		}
+	}
+
+	return nil
+}
+
+func isValidFieldName(name string) bool {
+	re := regexp.MustCompile("^[a-z0-9_]+$")
+	return re.MatchString(name)
+}
+
+// resourceDiffer is an interface that is used by the private diff functions.
+// This helps facilitate diff logic for both ResourceData and ResoureDiff with
+// minimal divergence in code.
+type resourceDiffer interface {
+	diffChange(string) (interface{}, interface{}, bool, bool, bool)
+	Get(string) interface{}
+	GetChange(string) (interface{}, interface{})
+	GetOk(string) (interface{}, bool)
+	HasChange(string) bool
+	Id() string
+}
+
+func (m schemaMap) diff(
+	k string,
+	schema *Schema,
+	diff *terraform.InstanceDiff,
+	d resourceDiffer,
+	all bool) error {
+
+	unsupressedDiff := new(terraform.InstanceDiff)
+	unsupressedDiff.Attributes = make(map[string]*terraform.ResourceAttrDiff)
+
+	var err error
+	switch schema.Type {
+	case TypeBool, TypeInt, TypeFloat, TypeString:
+		err = m.diffString(k, schema, unsupressedDiff, d, all)
+	case TypeList:
+		err = m.diffList(k, schema, unsupressedDiff, d, all)
+	case TypeMap:
+		err = m.diffMap(k, schema, unsupressedDiff, d, all)
+	case TypeSet:
+		err = m.diffSet(k, schema, unsupressedDiff, d, all)
+	default:
+		err = fmt.Errorf("%s: unknown type %#v", k, schema.Type)
+	}
+
+	for attrK, attrV := range unsupressedDiff.Attributes {
+		switch rd := d.(type) {
+		case *ResourceData:
+			if schema.DiffSuppressFunc != nil && attrV != nil &&
+				schema.DiffSuppressFunc(attrK, attrV.Old, attrV.New, rd) {
+				// If this attr diff is suppressed, we may still need it in the
+				// overall diff if it's contained within a set. Rather than
+				// dropping the diff, make it a NOOP.
+				if !all {
+					continue
+				}
+
+				attrV = &terraform.ResourceAttrDiff{
+					Old: attrV.Old,
+					New: attrV.Old,
+				}
+			}
+		}
+		diff.Attributes[attrK] = attrV
+	}
+
+	return err
+}
+
+func (m schemaMap) diffList(
+	k string,
+	schema *Schema,
+	diff *terraform.InstanceDiff,
+	d resourceDiffer,
+	all bool) error {
+	o, n, _, computedList, customized := d.diffChange(k)
+	if computedList {
+		n = nil
+	}
+	nSet := n != nil
+
+	// If we have an old value and no new value is set or will be
+	// computed once all variables can be interpolated and we're
+	// computed, then nothing has changed.
+	if o != nil && n == nil && !computedList && schema.Computed {
+		return nil
+	}
+
+	if o == nil {
+		o = []interface{}{}
+	}
+	if n == nil {
+		n = []interface{}{}
+	}
+	if s, ok := o.(*Set); ok {
+		o = s.List()
+	}
+	if s, ok := n.(*Set); ok {
+		n = s.List()
+	}
+	os := o.([]interface{})
+	vs := n.([]interface{})
+
+	// If the new value was set, and the two are equal, then we're done.
+	// We have to do this check here because sets might be NOT
+	// reflect.DeepEqual so we need to wait until we get the []interface{}
+	if !all && nSet && reflect.DeepEqual(os, vs) {
+		return nil
+	}
+
+	// Get the counts
+	oldLen := len(os)
+	newLen := len(vs)
+	oldStr := strconv.FormatInt(int64(oldLen), 10)
+
+	// If the whole list is computed, then say that the # is computed
+	if computedList {
+		diff.Attributes[k+".#"] = &terraform.ResourceAttrDiff{
+			Old:         oldStr,
+			NewComputed: true,
+			RequiresNew: schema.ForceNew,
+		}
+		return nil
+	}
+
+	// If the counts are not the same, then record that diff
+	changed := oldLen != newLen
+	computed := oldLen == 0 && newLen == 0 && schema.Computed
+	if changed || computed || all {
+		countSchema := &Schema{
+			Type:     TypeInt,
+			Computed: schema.Computed,
+			ForceNew: schema.ForceNew,
+		}
+
+		newStr := ""
+		if !computed {
+			newStr = strconv.FormatInt(int64(newLen), 10)
+		} else {
+			oldStr = ""
+		}
+
+		diff.Attributes[k+".#"] = countSchema.finalizeDiff(
+			&terraform.ResourceAttrDiff{
+				Old: oldStr,
+				New: newStr,
+			},
+			customized,
+		)
+	}
+
+	// Figure out the maximum
+	maxLen := oldLen
+	if newLen > maxLen {
+		maxLen = newLen
+	}
+
+	switch t := schema.Elem.(type) {
+	case *Resource:
+		// This is a complex resource
+		for i := 0; i < maxLen; i++ {
+			for k2, schema := range t.Schema {
+				subK := fmt.Sprintf("%s.%d.%s", k, i, k2)
+				err := m.diff(subK, schema, diff, d, all)
+				if err != nil {
+					return err
+				}
+			}
+		}
+	case *Schema:
+		// Copy the schema so that we can set Computed/ForceNew from
+		// the parent schema (the TypeList).
+		t2 := *t
+		t2.ForceNew = schema.ForceNew
+
+		// This is just a primitive element, so go through each and
+		// just diff each.
+		for i := 0; i < maxLen; i++ {
+			subK := fmt.Sprintf("%s.%d", k, i)
+			err := m.diff(subK, &t2, diff, d, all)
+			if err != nil {
+				return err
+			}
+		}
+	default:
+		return fmt.Errorf("%s: unknown element type (internal)", k)
+	}
+
+	return nil
+}
+
+func (m schemaMap) diffMap(
+	k string,
+	schema *Schema,
+	diff *terraform.InstanceDiff,
+	d resourceDiffer,
+	all bool) error {
+	prefix := k + "."
+
+	// First get all the values from the state
+	var stateMap, configMap map[string]string
+	o, n, _, nComputed, customized := d.diffChange(k)
+	if err := mapstructure.WeakDecode(o, &stateMap); err != nil {
+		return fmt.Errorf("%s: %s", k, err)
+	}
+	if err := mapstructure.WeakDecode(n, &configMap); err != nil {
+		return fmt.Errorf("%s: %s", k, err)
+	}
+
+	// Keep track of whether the state _exists_ at all prior to clearing it
+	stateExists := o != nil
+
+	// Delete any count values, since we don't use those
+	delete(configMap, "%")
+	delete(stateMap, "%")
+
+	// Check if the number of elements has changed.
+	oldLen, newLen := len(stateMap), len(configMap)
+	changed := oldLen != newLen
+	if oldLen != 0 && newLen == 0 && schema.Computed {
+		changed = false
+	}
+
+	// It is computed if we have no old value, no new value, the schema
+	// says it is computed, and it didn't exist in the state before. The
+	// last point means: if it existed in the state, even empty, then it
+	// has already been computed.
+	computed := oldLen == 0 && newLen == 0 && schema.Computed && !stateExists
+
+	// If the count has changed or we're computed, then add a diff for the
+	// count. "nComputed" means that the new value _contains_ a value that
+	// is computed. We don't do granular diffs for this yet, so we mark the
+	// whole map as computed.
+	if changed || computed || nComputed {
+		countSchema := &Schema{
+			Type:     TypeInt,
+			Computed: schema.Computed || nComputed,
+			ForceNew: schema.ForceNew,
+		}
+
+		oldStr := strconv.FormatInt(int64(oldLen), 10)
+		newStr := ""
+		if !computed && !nComputed {
+			newStr = strconv.FormatInt(int64(newLen), 10)
+		} else {
+			oldStr = ""
+		}
+
+		diff.Attributes[k+".%"] = countSchema.finalizeDiff(
+			&terraform.ResourceAttrDiff{
+				Old: oldStr,
+				New: newStr,
+			},
+			customized,
+		)
+	}
+
+	// If the new map is nil and we're computed, then ignore it.
+	if n == nil && schema.Computed {
+		return nil
+	}
+
+	// Now we compare, preferring values from the config map
+	for k, v := range configMap {
+		old, ok := stateMap[k]
+		delete(stateMap, k)
+
+		if old == v && ok && !all {
+			continue
+		}
+
+		diff.Attributes[prefix+k] = schema.finalizeDiff(
+			&terraform.ResourceAttrDiff{
+				Old: old,
+				New: v,
+			},
+			customized,
+		)
+	}
+	for k, v := range stateMap {
+		diff.Attributes[prefix+k] = schema.finalizeDiff(
+			&terraform.ResourceAttrDiff{
+				Old:        v,
+				NewRemoved: true,
+			},
+			customized,
+		)
+	}
+
+	return nil
+}
+
+func (m schemaMap) diffSet(
+	k string,
+	schema *Schema,
+	diff *terraform.InstanceDiff,
+	d resourceDiffer,
+	all bool) error {
+
+	o, n, _, computedSet, customized := d.diffChange(k)
+	if computedSet {
+		n = nil
+	}
+	nSet := n != nil
+
+	// If we have an old value and no new value is set or will be
+	// computed once all variables can be interpolated and we're
+	// computed, then nothing has changed.
+	if o != nil && n == nil && !computedSet && schema.Computed {
+		return nil
+	}
+
+	if o == nil {
+		o = schema.ZeroValue().(*Set)
+	}
+	if n == nil {
+		n = schema.ZeroValue().(*Set)
+	}
+	os := o.(*Set)
+	ns := n.(*Set)
+
+	// If the new value was set, compare the listCode's to determine if
+	// the two are equal. Comparing listCode's instead of the actual values
+	// is needed because there could be computed values in the set which
+	// would result in false positives while comparing.
+	if !all && nSet && reflect.DeepEqual(os.listCode(), ns.listCode()) {
+		return nil
+	}
+
+	// Get the counts
+	oldLen := os.Len()
+	newLen := ns.Len()
+	oldStr := strconv.Itoa(oldLen)
+	newStr := strconv.Itoa(newLen)
+
+	// Build a schema for our count
+	countSchema := &Schema{
+		Type:     TypeInt,
+		Computed: schema.Computed,
+		ForceNew: schema.ForceNew,
+	}
+
+	// If the set computed then say that the # is computed
+	if computedSet || schema.Computed && !nSet {
+		// If # already exists, equals 0 and no new set is supplied, there
+		// is nothing to record in the diff
+		count, ok := d.GetOk(k + ".#")
+		if ok && count.(int) == 0 && !nSet && !computedSet {
+			return nil
+		}
+
+		// Set the count but make sure that if # does not exist, we don't
+		// use the zeroed value
+		countStr := strconv.Itoa(count.(int))
+		if !ok {
+			countStr = ""
+		}
+
+		diff.Attributes[k+".#"] = countSchema.finalizeDiff(
+			&terraform.ResourceAttrDiff{
+				Old:         countStr,
+				NewComputed: true,
+			},
+			customized,
+		)
+		return nil
+	}
+
+	// If the counts are not the same, then record that diff
+	changed := oldLen != newLen
+	if changed || all {
+		diff.Attributes[k+".#"] = countSchema.finalizeDiff(
+			&terraform.ResourceAttrDiff{
+				Old: oldStr,
+				New: newStr,
+			},
+			customized,
+		)
+	}
+
+	// Build the list of codes that will make up our set. This is the
+	// removed codes as well as all the codes in the new codes.
+	codes := make([][]string, 2)
+	codes[0] = os.Difference(ns).listCode()
+	codes[1] = ns.listCode()
+	for _, list := range codes {
+		for _, code := range list {
+			switch t := schema.Elem.(type) {
+			case *Resource:
+				// This is a complex resource
+				for k2, schema := range t.Schema {
+					subK := fmt.Sprintf("%s.%s.%s", k, code, k2)
+					err := m.diff(subK, schema, diff, d, true)
+					if err != nil {
+						return err
+					}
+				}
+			case *Schema:
+				// Copy the schema so that we can set Computed/ForceNew from
+				// the parent schema (the TypeSet).
+				t2 := *t
+				t2.ForceNew = schema.ForceNew
+
+				// This is just a primitive element, so go through each and
+				// just diff each.
+				subK := fmt.Sprintf("%s.%s", k, code)
+				err := m.diff(subK, &t2, diff, d, true)
+				if err != nil {
+					return err
+				}
+			default:
+				return fmt.Errorf("%s: unknown element type (internal)", k)
+			}
+		}
+	}
+
+	return nil
+}
+
+func (m schemaMap) diffString(
+	k string,
+	schema *Schema,
+	diff *terraform.InstanceDiff,
+	d resourceDiffer,
+	all bool) error {
+	var originalN interface{}
+	var os, ns string
+	o, n, _, computed, customized := d.diffChange(k)
+	if schema.StateFunc != nil && n != nil {
+		originalN = n
+		n = schema.StateFunc(n)
+	}
+	nraw := n
+	if nraw == nil && o != nil {
+		nraw = schema.Type.Zero()
+	}
+	if err := mapstructure.WeakDecode(o, &os); err != nil {
+		return fmt.Errorf("%s: %s", k, err)
+	}
+	if err := mapstructure.WeakDecode(nraw, &ns); err != nil {
+		return fmt.Errorf("%s: %s", k, err)
+	}
+
+	if os == ns && !all && !computed {
+		// They're the same value. If there old value is not blank or we
+		// have an ID, then return right away since we're already set up.
+		if os != "" || d.Id() != "" {
+			return nil
+		}
+
+		// Otherwise, only continue if we're computed
+		if !schema.Computed {
+			return nil
+		}
+	}
+
+	removed := false
+	if o != nil && n == nil && !computed {
+		removed = true
+	}
+	if removed && schema.Computed {
+		return nil
+	}
+
+	diff.Attributes[k] = schema.finalizeDiff(
+		&terraform.ResourceAttrDiff{
+			Old:         os,
+			New:         ns,
+			NewExtra:    originalN,
+			NewRemoved:  removed,
+			NewComputed: computed,
+		},
+		customized,
+	)
+
+	return nil
+}
+
+func (m schemaMap) inputString(
+	input terraform.UIInput,
+	k string,
+	schema *Schema) (interface{}, error) {
+	result, err := input.Input(context.Background(), &terraform.InputOpts{
+		Id:          k,
+		Query:       k,
+		Description: schema.Description,
+		Default:     schema.InputDefault,
+	})
+
+	return result, err
+}
+
+func (m schemaMap) validate(
+	k string,
+	schema *Schema,
+	c *terraform.ResourceConfig) ([]string, []error) {
+	raw, ok := c.Get(k)
+	if !ok && schema.DefaultFunc != nil {
+		// We have a dynamic default. Check if we have a value.
+		var err error
+		raw, err = schema.DefaultFunc()
+		if err != nil {
+			return nil, []error{fmt.Errorf(
+				"%q, error loading default: %s", k, err)}
+		}
+
+		// We're okay as long as we had a value set
+		ok = raw != nil
+	}
+	if !ok {
+		if schema.Required {
+			return nil, []error{fmt.Errorf(
+				"%q: required field is not set", k)}
+		}
+
+		return nil, nil
+	}
+
+	if !schema.Required && !schema.Optional {
+		// This is a computed-only field
+		return nil, []error{fmt.Errorf(
+			"%q: this field cannot be set", k)}
+	}
+
+	// If the value is unknown then we can't validate it yet.
+	// In particular, this avoids spurious type errors where downstream
+	// validation code sees UnknownVariableValue as being just a string.
+	// The SDK has to allow the unknown value through initially, so that
+	// Required fields set via an interpolated value are accepted.
+	if !isWhollyKnown(raw) {
+		if schema.Deprecated != "" {
+			return []string{fmt.Sprintf("%q: [DEPRECATED] %s", k, schema.Deprecated)}, nil
+		}
+		return nil, nil
+	}
+
+	err := m.validateConflictingAttributes(k, schema, c)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	return m.validateType(k, raw, schema, c)
+}
+
+// isWhollyKnown returns false if the argument contains an UnknownVariableValue
+func isWhollyKnown(raw interface{}) bool {
+	switch raw := raw.(type) {
+	case string:
+		if raw == hcl2shim.UnknownVariableValue {
+			return false
+		}
+	case []interface{}:
+		for _, v := range raw {
+			if !isWhollyKnown(v) {
+				return false
+			}
+		}
+	case map[string]interface{}:
+		for _, v := range raw {
+			if !isWhollyKnown(v) {
+				return false
+			}
+		}
+	}
+	return true
+}
+func (m schemaMap) validateConflictingAttributes(
+	k string,
+	schema *Schema,
+	c *terraform.ResourceConfig) error {
+
+	if len(schema.ConflictsWith) == 0 {
+		return nil
+	}
+
+	for _, conflictingKey := range schema.ConflictsWith {
+		if raw, ok := c.Get(conflictingKey); ok {
+			if raw == hcl2shim.UnknownVariableValue {
+				// An unknown value might become unset (null) once known, so
+				// we must defer validation until it's known.
+				continue
+			}
+			return fmt.Errorf(
+				"%q: conflicts with %s", k, conflictingKey)
+		}
+	}
+
+	return nil
+}
+
+func (m schemaMap) validateList(
+	k string,
+	raw interface{},
+	schema *Schema,
+	c *terraform.ResourceConfig) ([]string, []error) {
+	// first check if the list is wholly unknown
+	if s, ok := raw.(string); ok {
+		if s == hcl2shim.UnknownVariableValue {
+			return nil, nil
+		}
+	}
+
+	// schemaMap can't validate nil
+	if raw == nil {
+		return nil, nil
+	}
+
+	// We use reflection to verify the slice because you can't
+	// case to []interface{} unless the slice is exactly that type.
+	rawV := reflect.ValueOf(raw)
+
+	// If we support promotion and the raw value isn't a slice, wrap
+	// it in []interface{} and check again.
+	if schema.PromoteSingle && rawV.Kind() != reflect.Slice {
+		raw = []interface{}{raw}
+		rawV = reflect.ValueOf(raw)
+	}
+
+	if rawV.Kind() != reflect.Slice {
+		return nil, []error{fmt.Errorf(
+			"%s: should be a list", k)}
+	}
+
+	// We can't validate list length if this came from a dynamic block.
+	// Since there's no way to determine if something was from a dynamic block
+	// at this point, we're going to skip validation in the new protocol if
+	// there are any unknowns. Validate will eventually be called again once
+	// all values are known.
+	if isProto5() && !isWhollyKnown(raw) {
+		return nil, nil
+	}
+
+	// Validate length
+	if schema.MaxItems > 0 && rawV.Len() > schema.MaxItems {
+		return nil, []error{fmt.Errorf(
+			"%s: attribute supports %d item maximum, config has %d declared", k, schema.MaxItems, rawV.Len())}
+	}
+
+	if schema.MinItems > 0 && rawV.Len() < schema.MinItems {
+		return nil, []error{fmt.Errorf(
+			"%s: attribute supports %d item as a minimum, config has %d declared", k, schema.MinItems, rawV.Len())}
+	}
+
+	// Now build the []interface{}
+	raws := make([]interface{}, rawV.Len())
+	for i, _ := range raws {
+		raws[i] = rawV.Index(i).Interface()
+	}
+
+	var ws []string
+	var es []error
+	for i, raw := range raws {
+		key := fmt.Sprintf("%s.%d", k, i)
+
+		// Reify the key value from the ResourceConfig.
+		// If the list was computed we have all raw values, but some of these
+		// may be known in the config, and aren't individually marked as Computed.
+		if r, ok := c.Get(key); ok {
+			raw = r
+		}
+
+		var ws2 []string
+		var es2 []error
+		switch t := schema.Elem.(type) {
+		case *Resource:
+			// This is a sub-resource
+			ws2, es2 = m.validateObject(key, t.Schema, c)
+		case *Schema:
+			ws2, es2 = m.validateType(key, raw, t, c)
+		}
+
+		if len(ws2) > 0 {
+			ws = append(ws, ws2...)
+		}
+		if len(es2) > 0 {
+			es = append(es, es2...)
+		}
+	}
+
+	return ws, es
+}
+
+func (m schemaMap) validateMap(
+	k string,
+	raw interface{},
+	schema *Schema,
+	c *terraform.ResourceConfig) ([]string, []error) {
+	// first check if the list is wholly unknown
+	if s, ok := raw.(string); ok {
+		if s == hcl2shim.UnknownVariableValue {
+			return nil, nil
+		}
+	}
+
+	// schemaMap can't validate nil
+	if raw == nil {
+		return nil, nil
+	}
+	// We use reflection to verify the slice because you can't
+	// case to []interface{} unless the slice is exactly that type.
+	rawV := reflect.ValueOf(raw)
+	switch rawV.Kind() {
+	case reflect.String:
+		// If raw and reified are equal, this is a string and should
+		// be rejected.
+		reified, reifiedOk := c.Get(k)
+		if reifiedOk && raw == reified && !c.IsComputed(k) {
+			return nil, []error{fmt.Errorf("%s: should be a map", k)}
+		}
+		// Otherwise it's likely raw is an interpolation.
+		return nil, nil
+	case reflect.Map:
+	case reflect.Slice:
+	default:
+		return nil, []error{fmt.Errorf("%s: should be a map", k)}
+	}
+
+	// If it is not a slice, validate directly
+	if rawV.Kind() != reflect.Slice {
+		mapIface := rawV.Interface()
+		if _, errs := validateMapValues(k, mapIface.(map[string]interface{}), schema); len(errs) > 0 {
+			return nil, errs
+		}
+		if schema.ValidateFunc != nil {
+			return schema.ValidateFunc(mapIface, k)
+		}
+		return nil, nil
+	}
+
+	// It is a slice, verify that all the elements are maps
+	raws := make([]interface{}, rawV.Len())
+	for i, _ := range raws {
+		raws[i] = rawV.Index(i).Interface()
+	}
+
+	for _, raw := range raws {
+		v := reflect.ValueOf(raw)
+		if v.Kind() != reflect.Map {
+			return nil, []error{fmt.Errorf(
+				"%s: should be a map", k)}
+		}
+		mapIface := v.Interface()
+		if _, errs := validateMapValues(k, mapIface.(map[string]interface{}), schema); len(errs) > 0 {
+			return nil, errs
+		}
+	}
+
+	if schema.ValidateFunc != nil {
+		validatableMap := make(map[string]interface{})
+		for _, raw := range raws {
+			for k, v := range raw.(map[string]interface{}) {
+				validatableMap[k] = v
+			}
+		}
+
+		return schema.ValidateFunc(validatableMap, k)
+	}
+
+	return nil, nil
+}
+
+func validateMapValues(k string, m map[string]interface{}, schema *Schema) ([]string, []error) {
+	for key, raw := range m {
+		valueType, err := getValueType(k, schema)
+		if err != nil {
+			return nil, []error{err}
+		}
+
+		switch valueType {
+		case TypeBool:
+			var n bool
+			if err := mapstructure.WeakDecode(raw, &n); err != nil {
+				return nil, []error{fmt.Errorf("%s (%s): %s", k, key, err)}
+			}
+		case TypeInt:
+			var n int
+			if err := mapstructure.WeakDecode(raw, &n); err != nil {
+				return nil, []error{fmt.Errorf("%s (%s): %s", k, key, err)}
+			}
+		case TypeFloat:
+			var n float64
+			if err := mapstructure.WeakDecode(raw, &n); err != nil {
+				return nil, []error{fmt.Errorf("%s (%s): %s", k, key, err)}
+			}
+		case TypeString:
+			var n string
+			if err := mapstructure.WeakDecode(raw, &n); err != nil {
+				return nil, []error{fmt.Errorf("%s (%s): %s", k, key, err)}
+			}
+		default:
+			panic(fmt.Sprintf("Unknown validation type: %#v", schema.Type))
+		}
+	}
+	return nil, nil
+}
+
+func getValueType(k string, schema *Schema) (ValueType, error) {
+	if schema.Elem == nil {
+		return TypeString, nil
+	}
+	if vt, ok := schema.Elem.(ValueType); ok {
+		return vt, nil
+	}
+
+	// If a Schema is provided to a Map, we use the Type of that schema
+	// as the type for each element in the Map.
+	if s, ok := schema.Elem.(*Schema); ok {
+		return s.Type, nil
+	}
+
+	if _, ok := schema.Elem.(*Resource); ok {
+		// TODO: We don't actually support this (yet)
+		// but silently pass the validation, until we decide
+		// how to handle nested structures in maps
+		return TypeString, nil
+	}
+	return 0, fmt.Errorf("%s: unexpected map value type: %#v", k, schema.Elem)
+}
+
+func (m schemaMap) validateObject(
+	k string,
+	schema map[string]*Schema,
+	c *terraform.ResourceConfig) ([]string, []error) {
+	raw, _ := c.Get(k)
+
+	// schemaMap can't validate nil
+	if raw == nil {
+		return nil, nil
+	}
+
+	if _, ok := raw.(map[string]interface{}); !ok && !c.IsComputed(k) {
+		return nil, []error{fmt.Errorf(
+			"%s: expected object, got %s",
+			k, reflect.ValueOf(raw).Kind())}
+	}
+
+	var ws []string
+	var es []error
+	for subK, s := range schema {
+		key := subK
+		if k != "" {
+			key = fmt.Sprintf("%s.%s", k, subK)
+		}
+
+		ws2, es2 := m.validate(key, s, c)
+		if len(ws2) > 0 {
+			ws = append(ws, ws2...)
+		}
+		if len(es2) > 0 {
+			es = append(es, es2...)
+		}
+	}
+
+	// Detect any extra/unknown keys and report those as errors.
+	if m, ok := raw.(map[string]interface{}); ok {
+		for subk, _ := range m {
+			if _, ok := schema[subk]; !ok {
+				if subk == TimeoutsConfigKey {
+					continue
+				}
+				es = append(es, fmt.Errorf(
+					"%s: invalid or unknown key: %s", k, subk))
+			}
+		}
+	}
+
+	return ws, es
+}
+
+func (m schemaMap) validatePrimitive(
+	k string,
+	raw interface{},
+	schema *Schema,
+	c *terraform.ResourceConfig) ([]string, []error) {
+
+	// a nil value shouldn't happen in the old protocol, and in the new
+	// protocol the types have already been validated. Either way, we can't
+	// reflect on nil, so don't panic.
+	if raw == nil {
+		return nil, nil
+	}
+
+	// Catch if the user gave a complex type where a primitive was
+	// expected, so we can return a friendly error message that
+	// doesn't contain Go type system terminology.
+	switch reflect.ValueOf(raw).Type().Kind() {
+	case reflect.Slice:
+		return nil, []error{
+			fmt.Errorf("%s must be a single value, not a list", k),
+		}
+	case reflect.Map:
+		return nil, []error{
+			fmt.Errorf("%s must be a single value, not a map", k),
+		}
+	default: // ok
+	}
+
+	if c.IsComputed(k) {
+		// If the key is being computed, then it is not an error as
+		// long as it's not a slice or map.
+		return nil, nil
+	}
+
+	var decoded interface{}
+	switch schema.Type {
+	case TypeBool:
+		// Verify that we can parse this as the correct type
+		var n bool
+		if err := mapstructure.WeakDecode(raw, &n); err != nil {
+			return nil, []error{fmt.Errorf("%s: %s", k, err)}
+		}
+		decoded = n
+	case TypeInt:
+		switch {
+		case isProto5():
+			// We need to verify the type precisely, because WeakDecode will
+			// decode a float as an integer.
+
+			// the config shims only use int for integral number values
+			if v, ok := raw.(int); ok {
+				decoded = v
+			} else {
+				return nil, []error{fmt.Errorf("%s: must be a whole number, got %v", k, raw)}
+			}
+		default:
+			// Verify that we can parse this as an int
+			var n int
+			if err := mapstructure.WeakDecode(raw, &n); err != nil {
+				return nil, []error{fmt.Errorf("%s: %s", k, err)}
+			}
+			decoded = n
+		}
+	case TypeFloat:
+		// Verify that we can parse this as an int
+		var n float64
+		if err := mapstructure.WeakDecode(raw, &n); err != nil {
+			return nil, []error{fmt.Errorf("%s: %s", k, err)}
+		}
+		decoded = n
+	case TypeString:
+		// Verify that we can parse this as a string
+		var n string
+		if err := mapstructure.WeakDecode(raw, &n); err != nil {
+			return nil, []error{fmt.Errorf("%s: %s", k, err)}
+		}
+		decoded = n
+	default:
+		panic(fmt.Sprintf("Unknown validation type: %#v", schema.Type))
+	}
+
+	if schema.ValidateFunc != nil {
+		return schema.ValidateFunc(decoded, k)
+	}
+
+	return nil, nil
+}
+
+func (m schemaMap) validateType(
+	k string,
+	raw interface{},
+	schema *Schema,
+	c *terraform.ResourceConfig) ([]string, []error) {
+	var ws []string
+	var es []error
+	switch schema.Type {
+	case TypeSet, TypeList:
+		ws, es = m.validateList(k, raw, schema, c)
+	case TypeMap:
+		ws, es = m.validateMap(k, raw, schema, c)
+	default:
+		ws, es = m.validatePrimitive(k, raw, schema, c)
+	}
+
+	if schema.Deprecated != "" {
+		ws = append(ws, fmt.Sprintf(
+			"%q: [DEPRECATED] %s", k, schema.Deprecated))
+	}
+
+	if schema.Removed != "" {
+		es = append(es, fmt.Errorf(
+			"%q: [REMOVED] %s", k, schema.Removed))
+	}
+
+	return ws, es
+}
+
+// Zero returns the zero value for a type.
+func (t ValueType) Zero() interface{} {
+	switch t {
+	case TypeInvalid:
+		return nil
+	case TypeBool:
+		return false
+	case TypeInt:
+		return 0
+	case TypeFloat:
+		return 0.0
+	case TypeString:
+		return ""
+	case TypeList:
+		return []interface{}{}
+	case TypeMap:
+		return map[string]interface{}{}
+	case TypeSet:
+		return new(Set)
+	case typeObject:
+		return map[string]interface{}{}
+	default:
+		panic(fmt.Sprintf("unknown type %s", t))
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/schema_test.go b/v1.5.7/internal/legacy/helper/schema/schema_test.go
new file mode 100644
index 0000000..6820f30
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/schema_test.go
@@ -0,0 +1,5561 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"os"
+	"reflect"
+	"sort"
+	"strconv"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/legacy/helper/hashcode"
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+func TestEnvDefaultFunc(t *testing.T) {
+	key := "TF_TEST_ENV_DEFAULT_FUNC"
+	defer os.Unsetenv(key)
+
+	f := EnvDefaultFunc(key, "42")
+	if err := os.Setenv(key, "foo"); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual, err := f()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if actual != "foo" {
+		t.Fatalf("bad: %#v", actual)
+	}
+
+	if err := os.Unsetenv(key); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual, err = f()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if actual != "42" {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestMultiEnvDefaultFunc(t *testing.T) {
+	keys := []string{
+		"TF_TEST_MULTI_ENV_DEFAULT_FUNC1",
+		"TF_TEST_MULTI_ENV_DEFAULT_FUNC2",
+	}
+	defer func() {
+		for _, k := range keys {
+			os.Unsetenv(k)
+		}
+	}()
+
+	// Test that the first key is returned first
+	f := MultiEnvDefaultFunc(keys, "42")
+	if err := os.Setenv(keys[0], "foo"); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual, err := f()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if actual != "foo" {
+		t.Fatalf("bad: %#v", actual)
+	}
+
+	if err := os.Unsetenv(keys[0]); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Test that the second key is returned if the first one is empty
+	f = MultiEnvDefaultFunc(keys, "42")
+	if err := os.Setenv(keys[1], "foo"); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual, err = f()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if actual != "foo" {
+		t.Fatalf("bad: %#v", actual)
+	}
+
+	if err := os.Unsetenv(keys[1]); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Test that the default value is returned when no keys are set
+	actual, err = f()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if actual != "42" {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestValueType_Zero(t *testing.T) {
+	cases := []struct {
+		Type  ValueType
+		Value interface{}
+	}{
+		{TypeBool, false},
+		{TypeInt, 0},
+		{TypeFloat, 0.0},
+		{TypeString, ""},
+		{TypeList, []interface{}{}},
+		{TypeMap, map[string]interface{}{}},
+		{TypeSet, new(Set)},
+	}
+
+	for i, tc := range cases {
+		actual := tc.Type.Zero()
+		if !reflect.DeepEqual(actual, tc.Value) {
+			t.Fatalf("%d: %#v != %#v", i, actual, tc.Value)
+		}
+	}
+}
+
+func TestSchemaMap_Diff(t *testing.T) {
+	cases := []struct {
+		Name          string
+		Schema        map[string]*Schema
+		State         *terraform.InstanceState
+		Config        map[string]interface{}
+		CustomizeDiff CustomizeDiffFunc
+		Diff          *terraform.InstanceDiff
+		Err           bool
+	}{
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "foo",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						NewComputed: true,
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "foo",
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Computed, but set in config",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"availability_zone": "bar",
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old: "foo",
+						New: "bar",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Default",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Default:  "foo",
+				},
+			},
+
+			State: nil,
+
+			Config: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "DefaultFunc, value",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					DefaultFunc: func() (interface{}, error) {
+						return "foo", nil
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "DefaultFunc, configuration set",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					DefaultFunc: func() (interface{}, error) {
+						return "foo", nil
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"availability_zone": "bar",
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "bar",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "String with StateFunc",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					StateFunc: func(a interface{}) string {
+						return a.(string) + "!"
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:      "",
+						New:      "foo!",
+						NewExtra: "foo",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "StateFunc not called with nil value",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					StateFunc: func(a interface{}) string {
+						t.Fatalf("should not get here!")
+						return ""
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Variable computed",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"availability_zone": hcl2shim.UnknownVariableValue,
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         hcl2shim.UnknownVariableValue,
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Int decode",
+			Schema: map[string]*Schema{
+				"port": &Schema{
+					Type:     TypeInt,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"port": 27,
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"port": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "27",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "bool decode",
+			Schema: map[string]*Schema{
+				"port": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"port": false,
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"port": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "false",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Bool",
+			Schema: map[string]*Schema{
+				"delete": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+					Default:  false,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"delete": "false",
+				},
+			},
+
+			Config: nil,
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "List decode",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{1, 2, 5},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "3",
+					},
+					"ports.0": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "2",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "5",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "List decode with promotion",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:          TypeList,
+					Required:      true,
+					Elem:          &Schema{Type: TypeInt},
+					PromoteSingle: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": "5",
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"ports.0": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "5",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "List decode with promotion with list",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:          TypeList,
+					Required:      true,
+					Elem:          &Schema{Type: TypeInt},
+					PromoteSingle: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{"5"},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"ports.0": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "5",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{1, 2, 5},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "3",
+					},
+					"ports.0": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "2",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "5",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{1, hcl2shim.UnknownVariableValue, 5},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old:         "0",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "3",
+					"ports.0": "1",
+					"ports.1": "2",
+					"ports.2": "5",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{1, 2, 5},
+			},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "2",
+					"ports.0": "1",
+					"ports.1": "2",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{1, 2, 5},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "2",
+						New: "3",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "5",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{1, 2, 5},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old:         "0",
+						New:         "3",
+						RequiresNew: true,
+					},
+					"ports.0": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "1",
+						RequiresNew: true,
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "2",
+						RequiresNew: true,
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "5",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "List with computed set",
+			Schema: map[string]*Schema{
+				"config": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					ForceNew: true,
+					MinItems: 1,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"name": {
+								Type:     TypeString,
+								Required: true,
+							},
+
+							"rules": {
+								Type:     TypeSet,
+								Computed: true,
+								Elem:     &Schema{Type: TypeString},
+								Set:      HashString,
+							},
+						},
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"config": []interface{}{
+					map[string]interface{}{
+						"name": "hello",
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config.#": &terraform.ResourceAttrDiff{
+						Old:         "0",
+						New:         "1",
+						RequiresNew: true,
+					},
+
+					"config.0.name": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "hello",
+					},
+
+					"config.0.rules.#": &terraform.ResourceAttrDiff{
+						Old:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{5, 2, 1},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "3",
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "2",
+					},
+					"ports.5": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "5",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Computed: true,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "0",
+				},
+			},
+
+			Config: nil,
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Set",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{"2", "5", 1},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "3",
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "2",
+					},
+					"ports.5": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "5",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{1, hcl2shim.UnknownVariableValue, "5"},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "2",
+					"ports.1": "1",
+					"ports.2": "2",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{5, 2, 1},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "2",
+						New: "3",
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "1",
+						New: "1",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "2",
+						New: "2",
+					},
+					"ports.5": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "5",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "2",
+					"ports.1": "1",
+					"ports.2": "2",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "2",
+						New: "0",
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old:        "1",
+						New:        "0",
+						NewRemoved: true,
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old:        "2",
+						New:        "0",
+						NewRemoved: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "bar",
+					"ports.#":           "1",
+					"ports.80":          "80",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Set",
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"ports": &Schema{
+								Type:     TypeList,
+								Optional: true,
+								Elem:     &Schema{Type: TypeInt},
+							},
+						},
+					},
+					Set: func(v interface{}) int {
+						m := v.(map[string]interface{})
+						ps := m["ports"].([]interface{})
+						result := 0
+						for _, p := range ps {
+							result += p.(int)
+						}
+						return result
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ingress.#":           "2",
+					"ingress.80.ports.#":  "1",
+					"ingress.80.ports.0":  "80",
+					"ingress.443.ports.#": "1",
+					"ingress.443.ports.0": "443",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ingress": []interface{}{
+					map[string]interface{}{
+						"ports": []interface{}{443},
+					},
+					map[string]interface{}{
+						"ports": []interface{}{80},
+					},
+				},
+			},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "List of structure decode",
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"from": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+						},
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ingress": []interface{}{
+					map[string]interface{}{
+						"from": 8080,
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ingress.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"ingress.0.from": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "8080",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "ComputedWhen",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:         TypeString,
+					Computed:     true,
+					ComputedWhen: []string{"port"},
+				},
+
+				"port": &Schema{
+					Type:     TypeInt,
+					Optional: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+					"port":              "80",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"port": 80,
+			},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:         TypeString,
+					Computed:     true,
+					ComputedWhen: []string{"port"},
+				},
+
+				"port": &Schema{
+					Type:     TypeInt,
+					Optional: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"port": "80",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"port": 80,
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		/* TODO
+		{
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:         TypeString,
+					Computed:     true,
+					ComputedWhen: []string{"port"},
+				},
+
+				"port": &Schema{
+					Type:     TypeInt,
+					Optional: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+					"port":              "80",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"port": 8080,
+			},
+
+			Diff: &terraform.ResourceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "foo",
+						NewComputed: true,
+					},
+					"port": &terraform.ResourceAttrDiff{
+						Old: "80",
+						New: "8080",
+					},
+				},
+			},
+
+			Err: false,
+		},
+		*/
+
+		{
+			Name: "Maps",
+			Schema: map[string]*Schema{
+				"config_vars": &Schema{
+					Type: TypeMap,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"config_vars": []interface{}{
+					map[string]interface{}{
+						"bar": "baz",
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config_vars.%": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+
+					"config_vars.bar": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "baz",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Maps",
+			Schema: map[string]*Schema{
+				"config_vars": &Schema{
+					Type: TypeMap,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"config_vars.foo": "bar",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"config_vars": []interface{}{
+					map[string]interface{}{
+						"bar": "baz",
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config_vars.foo": &terraform.ResourceAttrDiff{
+						Old:        "bar",
+						NewRemoved: true,
+					},
+					"config_vars.bar": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "baz",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Maps",
+			Schema: map[string]*Schema{
+				"vars": &Schema{
+					Type:     TypeMap,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"vars.foo": "bar",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"vars": []interface{}{
+					map[string]interface{}{
+						"bar": "baz",
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"vars.foo": &terraform.ResourceAttrDiff{
+						Old:        "bar",
+						New:        "",
+						NewRemoved: true,
+					},
+					"vars.bar": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "baz",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Maps",
+			Schema: map[string]*Schema{
+				"vars": &Schema{
+					Type:     TypeMap,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"vars.foo": "bar",
+				},
+			},
+
+			Config: nil,
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Maps",
+			Schema: map[string]*Schema{
+				"config_vars": &Schema{
+					Type: TypeList,
+					Elem: &Schema{Type: TypeMap},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"config_vars.#":     "1",
+					"config_vars.0.foo": "bar",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"config_vars": []interface{}{
+					map[string]interface{}{
+						"bar": "baz",
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config_vars.0.foo": &terraform.ResourceAttrDiff{
+						Old:        "bar",
+						NewRemoved: true,
+					},
+					"config_vars.0.bar": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "baz",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Maps",
+			Schema: map[string]*Schema{
+				"config_vars": &Schema{
+					Type: TypeList,
+					Elem: &Schema{Type: TypeMap},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"config_vars.#":     "1",
+					"config_vars.0.foo": "bar",
+					"config_vars.0.bar": "baz",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config_vars.#": &terraform.ResourceAttrDiff{
+						Old: "1",
+						New: "0",
+					},
+					"config_vars.0.%": &terraform.ResourceAttrDiff{
+						Old: "2",
+						New: "0",
+					},
+					"config_vars.0.foo": &terraform.ResourceAttrDiff{
+						Old:        "bar",
+						NewRemoved: true,
+					},
+					"config_vars.0.bar": &terraform.ResourceAttrDiff{
+						Old:        "baz",
+						NewRemoved: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "ForceNews",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					ForceNew: true,
+				},
+
+				"address": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "bar",
+					"address":           "foo",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "bar",
+						New:         "foo",
+						RequiresNew: true,
+					},
+
+					"address": &terraform.ResourceAttrDiff{
+						Old:         "foo",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					ForceNew: true,
+				},
+
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"availability_zone": "bar",
+					"ports.#":           "1",
+					"ports.80":          "80",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "bar",
+						New:         "foo",
+						RequiresNew: true,
+					},
+
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old:         "1",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set",
+			Schema: map[string]*Schema{
+				"instances": &Schema{
+					Type:     TypeSet,
+					Elem:     &Schema{Type: TypeString},
+					Optional: true,
+					Computed: true,
+					Set: func(v interface{}) int {
+						return len(v.(string))
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"instances.#": "0",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"instances": []interface{}{hcl2shim.UnknownVariableValue},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"instances.#": &terraform.ResourceAttrDiff{
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set",
+			Schema: map[string]*Schema{
+				"route": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"index": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+
+							"gateway": &Schema{
+								Type:     TypeString,
+								Optional: true,
+							},
+						},
+					},
+					Set: func(v interface{}) int {
+						m := v.(map[string]interface{})
+						return m["index"].(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"route": []interface{}{
+					map[string]interface{}{
+						"index":   "1",
+						"gateway": hcl2shim.UnknownVariableValue,
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"route.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"route.~1.index": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"route.~1.gateway": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         hcl2shim.UnknownVariableValue,
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set",
+			Schema: map[string]*Schema{
+				"route": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"index": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+
+							"gateway": &Schema{
+								Type:     TypeSet,
+								Optional: true,
+								Elem:     &Schema{Type: TypeInt},
+								Set: func(a interface{}) int {
+									return a.(int)
+								},
+							},
+						},
+					},
+					Set: func(v interface{}) int {
+						m := v.(map[string]interface{})
+						return m["index"].(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"route": []interface{}{
+					map[string]interface{}{
+						"index": "1",
+						"gateway": []interface{}{
+							hcl2shim.UnknownVariableValue,
+						},
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"route.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"route.~1.index": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"route.~1.gateway.#": &terraform.ResourceAttrDiff{
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Computed maps",
+			Schema: map[string]*Schema{
+				"vars": &Schema{
+					Type:     TypeMap,
+					Computed: true,
+				},
+			},
+
+			State: nil,
+
+			Config: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"vars.%": &terraform.ResourceAttrDiff{
+						Old:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Computed maps",
+			Schema: map[string]*Schema{
+				"vars": &Schema{
+					Type:     TypeMap,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"vars.%": "0",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"vars": map[string]interface{}{
+					"bar": hcl2shim.UnknownVariableValue,
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"vars.%": &terraform.ResourceAttrDiff{
+						Old:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name:   " - Empty",
+			Schema: map[string]*Schema{},
+
+			State: &terraform.InstanceState{},
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Float",
+			Schema: map[string]*Schema{
+				"some_threshold": &Schema{
+					Type: TypeFloat,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"some_threshold": "567.8",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"some_threshold": 12.34,
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"some_threshold": &terraform.ResourceAttrDiff{
+						Old: "567.8",
+						New: "12.34",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "https://github.com/hashicorp/terraform/issues/824",
+			Schema: map[string]*Schema{
+				"block_device": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"device_name": &Schema{
+								Type:     TypeString,
+								Required: true,
+							},
+							"delete_on_termination": &Schema{
+								Type:     TypeBool,
+								Optional: true,
+								Default:  true,
+							},
+						},
+					},
+					Set: func(v interface{}) int {
+						var buf bytes.Buffer
+						m := v.(map[string]interface{})
+						buf.WriteString(fmt.Sprintf("%s-", m["device_name"].(string)))
+						buf.WriteString(fmt.Sprintf("%t-", m["delete_on_termination"].(bool)))
+						return hashcode.String(buf.String())
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"block_device.#": "2",
+					"block_device.616397234.delete_on_termination":  "true",
+					"block_device.616397234.device_name":            "/dev/sda1",
+					"block_device.2801811477.delete_on_termination": "true",
+					"block_device.2801811477.device_name":           "/dev/sdx",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"block_device": []interface{}{
+					map[string]interface{}{
+						"device_name": "/dev/sda1",
+					},
+					map[string]interface{}{
+						"device_name": "/dev/sdx",
+					},
+				},
+			},
+			Diff: nil,
+			Err:  false,
+		},
+
+		{
+			Name: "Zero value in state shouldn't result in diff",
+			Schema: map[string]*Schema{
+				"port": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+					ForceNew: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"port": "false",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Same as prev, but for sets",
+			Schema: map[string]*Schema{
+				"route": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"index": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+
+							"gateway": &Schema{
+								Type:     TypeSet,
+								Optional: true,
+								Elem:     &Schema{Type: TypeInt},
+								Set: func(a interface{}) int {
+									return a.(int)
+								},
+							},
+						},
+					},
+					Set: func(v interface{}) int {
+						m := v.(map[string]interface{})
+						return m["index"].(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"route.#": "0",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "A set computed element shouldn't cause a diff",
+			Schema: map[string]*Schema{
+				"active": &Schema{
+					Type:     TypeBool,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"active": "true",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "An empty set should show up in the diff",
+			Schema: map[string]*Schema{
+				"instances": &Schema{
+					Type:     TypeSet,
+					Elem:     &Schema{Type: TypeString},
+					Optional: true,
+					ForceNew: true,
+					Set: func(v interface{}) int {
+						return len(v.(string))
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"instances.#": "1",
+					"instances.3": "foo",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"instances.#": &terraform.ResourceAttrDiff{
+						Old:         "1",
+						New:         "0",
+						RequiresNew: true,
+					},
+					"instances.3": &terraform.ResourceAttrDiff{
+						Old:         "foo",
+						New:         "",
+						NewRemoved:  true,
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Map with empty value",
+			Schema: map[string]*Schema{
+				"vars": &Schema{
+					Type: TypeMap,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"vars": map[string]interface{}{
+					"foo": "",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"vars.%": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"vars.foo": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Unset bool, not in state",
+			Schema: map[string]*Schema{
+				"force": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Unset set, not in state",
+			Schema: map[string]*Schema{
+				"metadata_keys": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					ForceNew: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set:      func(interface{}) int { return 0 },
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Unset list in state, should not show up computed",
+			Schema: map[string]*Schema{
+				"metadata_keys": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"metadata_keys.#": "0",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Set element computed element",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{1, hcl2shim.UnknownVariableValue},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Computed map without config that's known to be empty does not generate diff",
+			Schema: map[string]*Schema{
+				"tags": &Schema{
+					Type:     TypeMap,
+					Computed: true,
+				},
+			},
+
+			Config: nil,
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"tags.%": "0",
+				},
+			},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Set with hyphen keys",
+			Schema: map[string]*Schema{
+				"route": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"index": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+
+							"gateway-name": &Schema{
+								Type:     TypeString,
+								Optional: true,
+							},
+						},
+					},
+					Set: func(v interface{}) int {
+						m := v.(map[string]interface{})
+						return m["index"].(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"route": []interface{}{
+					map[string]interface{}{
+						"index":        "1",
+						"gateway-name": "hello",
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"route.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"route.1.index": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"route.1.gateway-name": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "hello",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: ": StateFunc in nested set (#1759)",
+			Schema: map[string]*Schema{
+				"service_account": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					ForceNew: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"scopes": &Schema{
+								Type:     TypeSet,
+								Required: true,
+								ForceNew: true,
+								Elem: &Schema{
+									Type: TypeString,
+									StateFunc: func(v interface{}) string {
+										return v.(string) + "!"
+									},
+								},
+								Set: func(v interface{}) int {
+									i, err := strconv.Atoi(v.(string))
+									if err != nil {
+										t.Fatalf("err: %s", err)
+									}
+									return i
+								},
+							},
+						},
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"service_account": []interface{}{
+					map[string]interface{}{
+						"scopes": []interface{}{"123"},
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"service_account.#": &terraform.ResourceAttrDiff{
+						Old:         "0",
+						New:         "1",
+						RequiresNew: true,
+					},
+					"service_account.0.scopes.#": &terraform.ResourceAttrDiff{
+						Old:         "0",
+						New:         "1",
+						RequiresNew: true,
+					},
+					"service_account.0.scopes.123": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "123!",
+						NewExtra:    "123",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Removing set elements",
+			Schema: map[string]*Schema{
+				"instances": &Schema{
+					Type:     TypeSet,
+					Elem:     &Schema{Type: TypeString},
+					Optional: true,
+					ForceNew: true,
+					Set: func(v interface{}) int {
+						return len(v.(string))
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"instances.#": "2",
+					"instances.3": "333",
+					"instances.2": "22",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"instances": []interface{}{"333", "4444"},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"instances.#": &terraform.ResourceAttrDiff{
+						Old: "2",
+						New: "2",
+					},
+					"instances.2": &terraform.ResourceAttrDiff{
+						Old:         "22",
+						New:         "",
+						NewRemoved:  true,
+						RequiresNew: true,
+					},
+					"instances.3": &terraform.ResourceAttrDiff{
+						Old: "333",
+						New: "333",
+					},
+					"instances.4": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "4444",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Bools can be set with 0/1 in config, still get true/false",
+			Schema: map[string]*Schema{
+				"one": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+				},
+				"two": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+				},
+				"three": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"one":   "false",
+					"two":   "true",
+					"three": "true",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"one": "1",
+				"two": "0",
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"one": &terraform.ResourceAttrDiff{
+						Old: "false",
+						New: "true",
+					},
+					"two": &terraform.ResourceAttrDiff{
+						Old: "true",
+						New: "false",
+					},
+					"three": &terraform.ResourceAttrDiff{
+						Old:        "true",
+						New:        "false",
+						NewRemoved: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name:   "tainted in state w/ no attr changes is still a replacement",
+			Schema: map[string]*Schema{},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"id": "someid",
+				},
+				Tainted: true,
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes:     map[string]*terraform.ResourceAttrDiff{},
+				DestroyTainted: true,
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set ForceNew only marks the changing element as ForceNew",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					ForceNew: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "3",
+					"ports.1": "1",
+					"ports.2": "2",
+					"ports.4": "4",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{5, 2, 1},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "3",
+						New: "3",
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "1",
+						New: "1",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "2",
+						New: "2",
+					},
+					"ports.5": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "5",
+						RequiresNew: true,
+					},
+					"ports.4": &terraform.ResourceAttrDiff{
+						Old:         "4",
+						New:         "0",
+						NewRemoved:  true,
+						RequiresNew: true,
+					},
+				},
+			},
+		},
+
+		{
+			Name: "removed optional items should trigger ForceNew",
+			Schema: map[string]*Schema{
+				"description": &Schema{
+					Type:     TypeString,
+					ForceNew: true,
+					Optional: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"description": "foo",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"description": &terraform.ResourceAttrDiff{
+						Old:         "foo",
+						New:         "",
+						RequiresNew: true,
+						NewRemoved:  true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		// GH-7715
+		{
+			Name: "computed value for boolean field",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeBool,
+					ForceNew: true,
+					Computed: true,
+					Optional: true,
+				},
+			},
+
+			State: &terraform.InstanceState{},
+
+			Config: map[string]interface{}{
+				"foo": hcl2shim.UnknownVariableValue,
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "false",
+						NewComputed: true,
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set ForceNew marks count as ForceNew if computed",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					ForceNew: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "3",
+					"ports.1": "1",
+					"ports.2": "2",
+					"ports.4": "4",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{hcl2shim.UnknownVariableValue, 2, 1},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old:         "3",
+						New:         "",
+						NewComputed: true,
+						RequiresNew: true,
+					},
+				},
+			},
+		},
+
+		{
+			Name: "List with computed schema and ForceNew",
+			Schema: map[string]*Schema{
+				"config": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					ForceNew: true,
+					Elem: &Schema{
+						Type: TypeString,
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"config.#": "2",
+					"config.0": "a",
+					"config.1": "b",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"config": []interface{}{hcl2shim.UnknownVariableValue, hcl2shim.UnknownVariableValue},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config.#": &terraform.ResourceAttrDiff{
+						Old:         "2",
+						New:         "",
+						RequiresNew: true,
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "overridden diff with a CustomizeDiff function, ForceNew not in schema",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				if err := d.SetNew("availability_zone", "bar"); err != nil {
+					return err
+				}
+				if err := d.ForceNew("availability_zone"); err != nil {
+					return err
+				}
+				return nil
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "bar",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			// NOTE: This case is technically impossible in the current
+			// implementation, because optional+computed values never show up in the
+			// diff. In the event behavior changes this test should ensure that the
+			// intended diff still shows up.
+			Name: "overridden removed attribute diff with a CustomizeDiff function, ForceNew not in schema",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				if err := d.SetNew("availability_zone", "bar"); err != nil {
+					return err
+				}
+				if err := d.ForceNew("availability_zone"); err != nil {
+					return err
+				}
+				return nil
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "bar",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+
+			Name: "overridden diff with a CustomizeDiff function, ForceNew in schema",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				if err := d.SetNew("availability_zone", "bar"); err != nil {
+					return err
+				}
+				return nil
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "bar",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "required field with computed diff added with CustomizeDiff function",
+			Schema: map[string]*Schema{
+				"ami_id": &Schema{
+					Type:     TypeString,
+					Required: true,
+				},
+				"instance_id": &Schema{
+					Type:     TypeString,
+					Computed: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ami_id": "foo",
+			},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				if err := d.SetNew("instance_id", "bar"); err != nil {
+					return err
+				}
+				return nil
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ami_id": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+					"instance_id": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "bar",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set ForceNew only marks the changing element as ForceNew - CustomizeDiffFunc edition",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"ports.#": "3",
+					"ports.1": "1",
+					"ports.2": "2",
+					"ports.4": "4",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{5, 2, 6},
+			},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				if err := d.SetNew("ports", []interface{}{5, 2, 1}); err != nil {
+					return err
+				}
+				if err := d.ForceNew("ports"); err != nil {
+					return err
+				}
+				return nil
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "3",
+						New: "3",
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "1",
+						New: "1",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "2",
+						New: "2",
+					},
+					"ports.5": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "5",
+						RequiresNew: true,
+					},
+					"ports.4": &terraform.ResourceAttrDiff{
+						Old:         "4",
+						New:         "0",
+						NewRemoved:  true,
+						RequiresNew: true,
+					},
+				},
+			},
+		},
+
+		{
+			Name:   "tainted resource does not run CustomizeDiffFunc",
+			Schema: map[string]*Schema{},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"id": "someid",
+				},
+				Tainted: true,
+			},
+
+			Config: map[string]interface{}{},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				return errors.New("diff customization should not have run")
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes:     map[string]*terraform.ResourceAttrDiff{},
+				DestroyTainted: true,
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "NewComputed based on a conditional with CustomizeDiffFunc",
+			Schema: map[string]*Schema{
+				"etag": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+				"version_id": &Schema{
+					Type:     TypeString,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"etag":       "foo",
+					"version_id": "1",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"etag": "bar",
+			},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				if d.HasChange("etag") {
+					d.SetNewComputed("version_id")
+				}
+				return nil
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"etag": &terraform.ResourceAttrDiff{
+						Old: "foo",
+						New: "bar",
+					},
+					"version_id": &terraform.ResourceAttrDiff{
+						Old:         "1",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "NewComputed should always propagate with CustomizeDiff",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "",
+				},
+				ID: "pre-existing",
+			},
+
+			Config: map[string]interface{}{},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				d.SetNewComputed("foo")
+				return nil
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "vetoing a diff",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"foo": "bar",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"foo": "baz",
+			},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				return fmt.Errorf("diff vetoed")
+			},
+
+			Err: true,
+		},
+
+		// A lot of resources currently depended on using the empty string as a
+		// nil/unset value.
+		// FIXME: We want this to eventually produce a diff, since there
+		// technically is a new value in the config.
+		{
+			Name: "optional, computed, empty string",
+			Schema: map[string]*Schema{
+				"attr": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"attr": "bar",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"attr": "",
+			},
+		},
+
+		{
+			Name: "optional, computed, empty string should not crash in CustomizeDiff",
+			Schema: map[string]*Schema{
+				"unrelated_set": {
+					Type:     TypeSet,
+					Optional: true,
+					Elem:     &Schema{Type: TypeString},
+				},
+				"stream_enabled": {
+					Type:     TypeBool,
+					Optional: true,
+				},
+				"stream_view_type": {
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				Attributes: map[string]string{
+					"unrelated_set.#":  "0",
+					"stream_enabled":   "true",
+					"stream_view_type": "KEYS_ONLY",
+				},
+			},
+			Config: map[string]interface{}{
+				"stream_enabled":   false,
+				"stream_view_type": "",
+			},
+			CustomizeDiff: func(diff *ResourceDiff, v interface{}) error {
+				v, ok := diff.GetOk("unrelated_set")
+				if ok {
+					return fmt.Errorf("Didn't expect unrelated_set: %#v", v)
+				}
+				return nil
+			},
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"stream_enabled": {
+						Old: "true",
+						New: "false",
+					},
+				},
+			},
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			c := terraform.NewResourceConfigRaw(tc.Config)
+
+			d, err := schemaMap(tc.Schema).Diff(tc.State, c, tc.CustomizeDiff, nil, true)
+			if err != nil != tc.Err {
+				t.Fatalf("err: %s", err)
+			}
+
+			if !reflect.DeepEqual(tc.Diff, d) {
+				t.Fatalf("expected:\n%#v\n\ngot:\n%#v", tc.Diff, d)
+			}
+		})
+	}
+}
+
+func TestSchemaMap_Input(t *testing.T) {
+	cases := map[string]struct {
+		Schema map[string]*Schema
+		Config map[string]interface{}
+		Input  map[string]string
+		Result map[string]interface{}
+		Err    bool
+	}{
+		/*
+		 * String decode
+		 */
+
+		"no input on optional field with no config": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+				},
+			},
+
+			Input:  map[string]string{},
+			Result: map[string]interface{}{},
+			Err:    false,
+		},
+
+		"input ignored when config has a value": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"availability_zone": "bar",
+			},
+
+			Input: map[string]string{
+				"availability_zone": "foo",
+			},
+
+			Result: map[string]interface{}{},
+
+			Err: false,
+		},
+
+		"input ignored when schema has a default": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Default:  "foo",
+					Optional: true,
+				},
+			},
+
+			Input: map[string]string{
+				"availability_zone": "bar",
+			},
+
+			Result: map[string]interface{}{},
+
+			Err: false,
+		},
+
+		"input ignored when default function returns a value": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type: TypeString,
+					DefaultFunc: func() (interface{}, error) {
+						return "foo", nil
+					},
+					Optional: true,
+				},
+			},
+
+			Input: map[string]string{
+				"availability_zone": "bar",
+			},
+
+			Result: map[string]interface{}{},
+
+			Err: false,
+		},
+
+		"input ignored when default function returns an empty string": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Default:  "",
+					Optional: true,
+				},
+			},
+
+			Input: map[string]string{
+				"availability_zone": "bar",
+			},
+
+			Result: map[string]interface{}{},
+
+			Err: false,
+		},
+
+		"input used when default function returns nil": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type: TypeString,
+					DefaultFunc: func() (interface{}, error) {
+						return nil, nil
+					},
+					Required: true,
+				},
+			},
+
+			Input: map[string]string{
+				"availability_zone": "bar",
+			},
+
+			Result: map[string]interface{}{
+				"availability_zone": "bar",
+			},
+
+			Err: false,
+		},
+
+		"input not used when optional default function returns nil": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type: TypeString,
+					DefaultFunc: func() (interface{}, error) {
+						return nil, nil
+					},
+					Optional: true,
+				},
+			},
+
+			Input:  map[string]string{},
+			Result: map[string]interface{}{},
+			Err:    false,
+		},
+	}
+
+	for i, tc := range cases {
+		if tc.Config == nil {
+			tc.Config = make(map[string]interface{})
+		}
+
+		input := new(terraform.MockUIInput)
+		input.InputReturnMap = tc.Input
+
+		rc := terraform.NewResourceConfigRaw(tc.Config)
+		rc.Config = make(map[string]interface{})
+
+		actual, err := schemaMap(tc.Schema).Input(input, rc)
+		if err != nil != tc.Err {
+			t.Fatalf("#%v err: %s", i, err)
+		}
+
+		if !reflect.DeepEqual(tc.Result, actual.Config) {
+			t.Fatalf("#%v: bad:\n\ngot: %#v\nexpected: %#v", i, actual.Config, tc.Result)
+		}
+	}
+}
+
+func TestSchemaMap_InputDefault(t *testing.T) {
+	emptyConfig := make(map[string]interface{})
+	rc := terraform.NewResourceConfigRaw(emptyConfig)
+	rc.Config = make(map[string]interface{})
+
+	input := new(terraform.MockUIInput)
+	input.InputFn = func(opts *terraform.InputOpts) (string, error) {
+		t.Fatalf("InputFn should not be called on: %#v", opts)
+		return "", nil
+	}
+
+	schema := map[string]*Schema{
+		"availability_zone": &Schema{
+			Type:     TypeString,
+			Default:  "foo",
+			Optional: true,
+		},
+	}
+	actual, err := schemaMap(schema).Input(input, rc)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := map[string]interface{}{}
+
+	if !reflect.DeepEqual(expected, actual.Config) {
+		t.Fatalf("got: %#v\nexpected: %#v", actual.Config, expected)
+	}
+}
+
+func TestSchemaMap_InputDeprecated(t *testing.T) {
+	emptyConfig := make(map[string]interface{})
+	rc := terraform.NewResourceConfigRaw(emptyConfig)
+	rc.Config = make(map[string]interface{})
+
+	input := new(terraform.MockUIInput)
+	input.InputFn = func(opts *terraform.InputOpts) (string, error) {
+		t.Fatalf("InputFn should not be called on: %#v", opts)
+		return "", nil
+	}
+
+	schema := map[string]*Schema{
+		"availability_zone": &Schema{
+			Type:       TypeString,
+			Deprecated: "long gone",
+			Optional:   true,
+		},
+	}
+	actual, err := schemaMap(schema).Input(input, rc)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := map[string]interface{}{}
+
+	if !reflect.DeepEqual(expected, actual.Config) {
+		t.Fatalf("got: %#v\nexpected: %#v", actual.Config, expected)
+	}
+}
+
+func TestSchemaMap_InternalValidate(t *testing.T) {
+	cases := map[string]struct {
+		In  map[string]*Schema
+		Err bool
+	}{
+		"nothing": {
+			nil,
+			false,
+		},
+
+		"Both optional and required": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeInt,
+					Optional: true,
+					Required: true,
+				},
+			},
+			true,
+		},
+
+		"No optional and no required": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Type: TypeInt,
+				},
+			},
+			true,
+		},
+
+		"Missing Type": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Required: true,
+				},
+			},
+			true,
+		},
+
+		"Required but computed": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeInt,
+					Required: true,
+					Computed: true,
+				},
+			},
+			true,
+		},
+
+		"Looks good": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Required: true,
+				},
+			},
+			false,
+		},
+
+		"Computed but has default": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeInt,
+					Optional: true,
+					Computed: true,
+					Default:  "foo",
+				},
+			},
+			true,
+		},
+
+		"Required but has default": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeInt,
+					Optional: true,
+					Required: true,
+					Default:  "foo",
+				},
+			},
+			true,
+		},
+
+		"List element not set": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Type: TypeList,
+				},
+			},
+			true,
+		},
+
+		"List default": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Type:    TypeList,
+					Elem:    &Schema{Type: TypeInt},
+					Default: "foo",
+				},
+			},
+			true,
+		},
+
+		"List element computed": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Elem: &Schema{
+						Type:     TypeInt,
+						Computed: true,
+					},
+				},
+			},
+			true,
+		},
+
+		"List element with Set set": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeList,
+					Elem:     &Schema{Type: TypeInt},
+					Set:      func(interface{}) int { return 0 },
+					Optional: true,
+				},
+			},
+			true,
+		},
+
+		"Set element with no Set set": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeSet,
+					Elem:     &Schema{Type: TypeInt},
+					Optional: true,
+				},
+			},
+			false,
+		},
+
+		"Required but computedWhen": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Type:         TypeInt,
+					Required:     true,
+					ComputedWhen: []string{"foo"},
+				},
+			},
+			true,
+		},
+
+		"Conflicting attributes cannot be required": {
+			map[string]*Schema{
+				"a": &Schema{
+					Type:     TypeBool,
+					Required: true,
+				},
+				"b": &Schema{
+					Type:          TypeBool,
+					Optional:      true,
+					ConflictsWith: []string{"a"},
+				},
+			},
+			true,
+		},
+
+		"Attribute with conflicts cannot be required": {
+			map[string]*Schema{
+				"b": &Schema{
+					Type:          TypeBool,
+					Required:      true,
+					ConflictsWith: []string{"a"},
+				},
+			},
+			true,
+		},
+
+		"ConflictsWith cannot be used w/ ComputedWhen": {
+			map[string]*Schema{
+				"a": &Schema{
+					Type:         TypeBool,
+					ComputedWhen: []string{"foor"},
+				},
+				"b": &Schema{
+					Type:          TypeBool,
+					Required:      true,
+					ConflictsWith: []string{"a"},
+				},
+			},
+			true,
+		},
+
+		"Sub-resource invalid": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"foo": new(Schema),
+						},
+					},
+				},
+			},
+			true,
+		},
+
+		"Sub-resource valid": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"foo": &Schema{
+								Type:     TypeInt,
+								Optional: true,
+							},
+						},
+					},
+				},
+			},
+			false,
+		},
+
+		"ValidateFunc on non-primitive": {
+			map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
+						return
+					},
+				},
+			},
+			true,
+		},
+
+		"computed-only field with validateFunc": {
+			map[string]*Schema{
+				"string": &Schema{
+					Type:     TypeString,
+					Computed: true,
+					ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
+						es = append(es, fmt.Errorf("this is not fine"))
+						return
+					},
+				},
+			},
+			true,
+		},
+
+		"computed-only field with diffSuppressFunc": {
+			map[string]*Schema{
+				"string": &Schema{
+					Type:     TypeString,
+					Computed: true,
+					DiffSuppressFunc: func(k, old, new string, d *ResourceData) bool {
+						// Always suppress any diff
+						return false
+					},
+				},
+			},
+			true,
+		},
+
+		"invalid field name format #1": {
+			map[string]*Schema{
+				"with space": &Schema{
+					Type:     TypeString,
+					Optional: true,
+				},
+			},
+			true,
+		},
+
+		"invalid field name format #2": {
+			map[string]*Schema{
+				"WithCapitals": &Schema{
+					Type:     TypeString,
+					Optional: true,
+				},
+			},
+			true,
+		},
+
+		"invalid field name format of a Deprecated field": {
+			map[string]*Schema{
+				"WithCapitals": &Schema{
+					Type:       TypeString,
+					Optional:   true,
+					Deprecated: "Use with_underscores instead",
+				},
+			},
+			false,
+		},
+
+		"invalid field name format of a Removed field": {
+			map[string]*Schema{
+				"WithCapitals": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Removed:  "Use with_underscores instead",
+				},
+			},
+			false,
+		},
+
+		"ConfigModeBlock with Elem *Resource": {
+			map[string]*Schema{
+				"block": &Schema{
+					Type:       TypeList,
+					ConfigMode: SchemaConfigModeBlock,
+					Optional:   true,
+					Elem:       &Resource{},
+				},
+			},
+			false,
+		},
+
+		"ConfigModeBlock Computed with Elem *Resource": {
+			map[string]*Schema{
+				"block": &Schema{
+					Type:       TypeList,
+					ConfigMode: SchemaConfigModeBlock,
+					Computed:   true,
+					Elem:       &Resource{},
+				},
+			},
+			true, // ConfigMode of block cannot be used for computed schema
+		},
+
+		"ConfigModeBlock with Elem *Schema": {
+			map[string]*Schema{
+				"block": &Schema{
+					Type:       TypeList,
+					ConfigMode: SchemaConfigModeBlock,
+					Optional:   true,
+					Elem: &Schema{
+						Type: TypeString,
+					},
+				},
+			},
+			true,
+		},
+
+		"ConfigModeBlock with no Elem": {
+			map[string]*Schema{
+				"block": &Schema{
+					Type:       TypeString,
+					ConfigMode: SchemaConfigModeBlock,
+					Optional:   true,
+				},
+			},
+			true,
+		},
+
+		"ConfigModeBlock inside ConfigModeAttr": {
+			map[string]*Schema{
+				"block": &Schema{
+					Type:       TypeList,
+					ConfigMode: SchemaConfigModeAttr,
+					Optional:   true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"sub": &Schema{
+								Type:       TypeList,
+								ConfigMode: SchemaConfigModeBlock,
+								Elem:       &Resource{},
+							},
+						},
+					},
+				},
+			},
+			true, // ConfigMode of block cannot be used in child of schema with ConfigMode of attribute
+		},
+
+		"ConfigModeAuto with *Resource inside ConfigModeAttr": {
+			map[string]*Schema{
+				"block": &Schema{
+					Type:       TypeList,
+					ConfigMode: SchemaConfigModeAttr,
+					Optional:   true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"sub": &Schema{
+								Type: TypeList,
+								Elem: &Resource{},
+							},
+						},
+					},
+				},
+			},
+			true, // in *schema.Resource with ConfigMode of attribute, so must also have ConfigMode of attribute
+		},
+	}
+
+	for tn, tc := range cases {
+		t.Run(tn, func(t *testing.T) {
+			err := schemaMap(tc.In).InternalValidate(nil)
+			if err != nil != tc.Err {
+				if tc.Err {
+					t.Fatalf("%q: Expected error did not occur:\n\n%#v", tn, tc.In)
+				}
+				t.Fatalf("%q: Unexpected error occurred: %s\n\n%#v", tn, err, tc.In)
+			}
+		})
+	}
+
+}
+
+func TestSchemaMap_DiffSuppress(t *testing.T) {
+	cases := map[string]struct {
+		Schema       map[string]*Schema
+		State        *terraform.InstanceState
+		Config       map[string]interface{}
+		ExpectedDiff *terraform.InstanceDiff
+		Err          bool
+	}{
+		"#0 - Suppress otherwise valid diff by returning true": {
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+					DiffSuppressFunc: func(k, old, new string, d *ResourceData) bool {
+						// Always suppress any diff
+						return true
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+
+			ExpectedDiff: nil,
+
+			Err: false,
+		},
+
+		"#1 - Don't suppress diff by returning false": {
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+					DiffSuppressFunc: func(k, old, new string, d *ResourceData) bool {
+						// Always suppress any diff
+						return false
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+
+			ExpectedDiff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": {
+						Old: "",
+						New: "foo",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		"Default with suppress makes no diff": {
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+					Default:  "foo",
+					DiffSuppressFunc: func(k, old, new string, d *ResourceData) bool {
+						return true
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{},
+
+			ExpectedDiff: nil,
+
+			Err: false,
+		},
+
+		"Default with false suppress makes diff": {
+			Schema: map[string]*Schema{
+				"availability_zone": {
+					Type:     TypeString,
+					Optional: true,
+					Default:  "foo",
+					DiffSuppressFunc: func(k, old, new string, d *ResourceData) bool {
+						return false
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{},
+
+			ExpectedDiff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": {
+						Old: "",
+						New: "foo",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		"Complex structure with set of computed string should mark root set as computed": {
+			Schema: map[string]*Schema{
+				"outer": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"outer_str": &Schema{
+								Type:     TypeString,
+								Optional: true,
+							},
+							"inner": &Schema{
+								Type:     TypeSet,
+								Optional: true,
+								Elem: &Resource{
+									Schema: map[string]*Schema{
+										"inner_str": &Schema{
+											Type:     TypeString,
+											Optional: true,
+										},
+									},
+								},
+								Set: func(v interface{}) int {
+									return 2
+								},
+							},
+						},
+					},
+					Set: func(v interface{}) int {
+						return 1
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"outer": []interface{}{
+					map[string]interface{}{
+						"outer_str": "foo",
+						"inner": []interface{}{
+							map[string]interface{}{
+								"inner_str": hcl2shim.UnknownVariableValue,
+							},
+						},
+					},
+				},
+			},
+
+			ExpectedDiff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"outer.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"outer.~1.outer_str": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+					"outer.~1.inner.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"outer.~1.inner.~2.inner_str": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         hcl2shim.UnknownVariableValue,
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		"Complex structure with complex list of computed string should mark root set as computed": {
+			Schema: map[string]*Schema{
+				"outer": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"outer_str": &Schema{
+								Type:     TypeString,
+								Optional: true,
+							},
+							"inner": &Schema{
+								Type:     TypeList,
+								Optional: true,
+								Elem: &Resource{
+									Schema: map[string]*Schema{
+										"inner_str": &Schema{
+											Type:     TypeString,
+											Optional: true,
+										},
+									},
+								},
+							},
+						},
+					},
+					Set: func(v interface{}) int {
+						return 1
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"outer": []interface{}{
+					map[string]interface{}{
+						"outer_str": "foo",
+						"inner": []interface{}{
+							map[string]interface{}{
+								"inner_str": hcl2shim.UnknownVariableValue,
+							},
+						},
+					},
+				},
+			},
+
+			ExpectedDiff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"outer.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"outer.~1.outer_str": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+					"outer.~1.inner.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"outer.~1.inner.0.inner_str": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         hcl2shim.UnknownVariableValue,
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+	}
+
+	for tn, tc := range cases {
+		t.Run(tn, func(t *testing.T) {
+			c := terraform.NewResourceConfigRaw(tc.Config)
+
+			d, err := schemaMap(tc.Schema).Diff(tc.State, c, nil, nil, true)
+			if err != nil != tc.Err {
+				t.Fatalf("#%q err: %s", tn, err)
+			}
+
+			if !reflect.DeepEqual(tc.ExpectedDiff, d) {
+				t.Fatalf("#%q:\n\nexpected:\n%#v\n\ngot:\n%#v", tn, tc.ExpectedDiff, d)
+			}
+		})
+	}
+}
+
+func TestSchemaMap_Validate(t *testing.T) {
+	cases := map[string]struct {
+		Schema   map[string]*Schema
+		Config   map[string]interface{}
+		Err      bool
+		Errors   []error
+		Warnings []string
+	}{
+		"Good": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+		},
+
+		"Good, because the var is not set and that error will come elsewhere": {
+			Schema: map[string]*Schema{
+				"size": &Schema{
+					Type:     TypeInt,
+					Required: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"size": hcl2shim.UnknownVariableValue,
+			},
+		},
+
+		"Required field not set": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Required: true,
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Err: true,
+		},
+
+		"Invalid basic type": {
+			Schema: map[string]*Schema{
+				"port": &Schema{
+					Type:     TypeInt,
+					Required: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"port": "I am invalid",
+			},
+
+			Err: true,
+		},
+
+		"Invalid complex type": {
+			Schema: map[string]*Schema{
+				"user_data": &Schema{
+					Type:     TypeString,
+					Optional: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"user_data": []interface{}{
+					map[string]interface{}{
+						"foo": "bar",
+					},
+				},
+			},
+
+			Err: true,
+		},
+
+		"Bad type": {
+			Schema: map[string]*Schema{
+				"size": &Schema{
+					Type:     TypeInt,
+					Required: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"size": "nope",
+			},
+
+			Err: true,
+		},
+
+		"Required but has DefaultFunc": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Required: true,
+					DefaultFunc: func() (interface{}, error) {
+						return "foo", nil
+					},
+				},
+			},
+
+			Config: nil,
+		},
+
+		"Required but has DefaultFunc return nil": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Required: true,
+					DefaultFunc: func() (interface{}, error) {
+						return nil, nil
+					},
+				},
+			},
+
+			Config: nil,
+
+			Err: true,
+		},
+
+		"List with promotion": {
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:          TypeList,
+					Elem:          &Schema{Type: TypeInt},
+					PromoteSingle: true,
+					Optional:      true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ingress": "5",
+			},
+
+			Err: false,
+		},
+
+		"List with promotion set as list": {
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:          TypeList,
+					Elem:          &Schema{Type: TypeInt},
+					PromoteSingle: true,
+					Optional:      true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ingress": []interface{}{"5"},
+			},
+
+			Err: false,
+		},
+
+		"Optional sub-resource": {
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type: TypeList,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"from": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+						},
+					},
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Err: false,
+		},
+
+		"Sub-resource is the wrong type": {
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"from": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+						},
+					},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ingress": []interface{}{"foo"},
+			},
+
+			Err: true,
+		},
+
+		"Not a list nested block": {
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"from": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+						},
+					},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ingress": "foo",
+			},
+
+			Err: true,
+			Errors: []error{
+				fmt.Errorf(`ingress: should be a list`),
+			},
+		},
+
+		"Not a list primitive": {
+			Schema: map[string]*Schema{
+				"strings": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Elem: &Schema{
+						Type: TypeString,
+					},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"strings": "foo",
+			},
+
+			Err: true,
+			Errors: []error{
+				fmt.Errorf(`strings: should be a list`),
+			},
+		},
+
+		"Unknown list": {
+			Schema: map[string]*Schema{
+				"strings": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Elem: &Schema{
+						Type: TypeString,
+					},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"strings": hcl2shim.UnknownVariableValue,
+			},
+
+			Err: false,
+		},
+
+		"Unknown + Deprecation": {
+			Schema: map[string]*Schema{
+				"old_news": &Schema{
+					Type:       TypeString,
+					Optional:   true,
+					Deprecated: "please use 'new_news' instead",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"old_news": hcl2shim.UnknownVariableValue,
+			},
+
+			Warnings: []string{
+				"\"old_news\": [DEPRECATED] please use 'new_news' instead",
+			},
+		},
+
+		"Required sub-resource field": {
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type: TypeList,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"from": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+						},
+					},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ingress": []interface{}{
+					map[string]interface{}{},
+				},
+			},
+
+			Err: true,
+		},
+
+		"Good sub-resource": {
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"from": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+						},
+					},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ingress": []interface{}{
+					map[string]interface{}{
+						"from": 80,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		"Good sub-resource, computed value": {
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"from": &Schema{
+								Type:     TypeInt,
+								Optional: true,
+							},
+						},
+					},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ingress": []interface{}{
+					map[string]interface{}{
+						"from": hcl2shim.UnknownVariableValue,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		"Invalid/unknown field": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"foo": "bar",
+			},
+
+			Err: true,
+		},
+
+		"Invalid/unknown field with computed value": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"foo": hcl2shim.UnknownVariableValue,
+			},
+
+			Err: true,
+		},
+
+		"Computed field set": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Computed: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"availability_zone": "bar",
+			},
+
+			Err: true,
+		},
+
+		"Not a set": {
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ports": "foo",
+			},
+
+			Err: true,
+		},
+
+		"Maps": {
+			Schema: map[string]*Schema{
+				"user_data": &Schema{
+					Type:     TypeMap,
+					Optional: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"user_data": "foo",
+			},
+
+			Err: true,
+		},
+
+		"Good map: data surrounded by extra slice": {
+			Schema: map[string]*Schema{
+				"user_data": &Schema{
+					Type:     TypeMap,
+					Optional: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"user_data": []interface{}{
+					map[string]interface{}{
+						"foo": "bar",
+					},
+				},
+			},
+		},
+
+		"Good map": {
+			Schema: map[string]*Schema{
+				"user_data": &Schema{
+					Type:     TypeMap,
+					Optional: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"user_data": map[string]interface{}{
+					"foo": "bar",
+				},
+			},
+		},
+
+		"Map with type specified as value type": {
+			Schema: map[string]*Schema{
+				"user_data": &Schema{
+					Type:     TypeMap,
+					Optional: true,
+					Elem:     TypeBool,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"user_data": map[string]interface{}{
+					"foo": "not_a_bool",
+				},
+			},
+
+			Err: true,
+		},
+
+		"Map with type specified as nested Schema": {
+			Schema: map[string]*Schema{
+				"user_data": &Schema{
+					Type:     TypeMap,
+					Optional: true,
+					Elem:     &Schema{Type: TypeBool},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"user_data": map[string]interface{}{
+					"foo": "not_a_bool",
+				},
+			},
+
+			Err: true,
+		},
+
+		"Bad map: just a slice": {
+			Schema: map[string]*Schema{
+				"user_data": &Schema{
+					Type:     TypeMap,
+					Optional: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"user_data": []interface{}{
+					"foo",
+				},
+			},
+
+			Err: true,
+		},
+
+		"Good set: config has slice with single interpolated value": {
+			Schema: map[string]*Schema{
+				"security_groups": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+					Elem:     &Schema{Type: TypeString},
+					Set: func(v interface{}) int {
+						return len(v.(string))
+					},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"security_groups": []interface{}{"${var.foo}"},
+			},
+
+			Err: false,
+		},
+
+		"Bad set: config has single interpolated value": {
+			Schema: map[string]*Schema{
+				"security_groups": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+					Elem:     &Schema{Type: TypeString},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"security_groups": "${var.foo}",
+			},
+
+			Err: true,
+		},
+
+		"Bad, subresource should not allow unknown elements": {
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"port": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+						},
+					},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ingress": []interface{}{
+					map[string]interface{}{
+						"port":  80,
+						"other": "yes",
+					},
+				},
+			},
+
+			Err: true,
+		},
+
+		"Bad, subresource should not allow invalid types": {
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"port": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+						},
+					},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ingress": []interface{}{
+					map[string]interface{}{
+						"port": "bad",
+					},
+				},
+			},
+
+			Err: true,
+		},
+
+		"Bad, should not allow lists to be assigned to string attributes": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Required: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"availability_zone": []interface{}{"foo", "bar", "baz"},
+			},
+
+			Err: true,
+		},
+
+		"Bad, should not allow maps to be assigned to string attributes": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Required: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				"availability_zone": map[string]interface{}{"foo": "bar", "baz": "thing"},
+			},
+
+			Err: true,
+		},
+
+		"Deprecated attribute usage generates warning, but not error": {
+			Schema: map[string]*Schema{
+				"old_news": &Schema{
+					Type:       TypeString,
+					Optional:   true,
+					Deprecated: "please use 'new_news' instead",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"old_news": "extra extra!",
+			},
+
+			Err: false,
+
+			Warnings: []string{
+				"\"old_news\": [DEPRECATED] please use 'new_news' instead",
+			},
+		},
+
+		"Deprecated generates no warnings if attr not used": {
+			Schema: map[string]*Schema{
+				"old_news": &Schema{
+					Type:       TypeString,
+					Optional:   true,
+					Deprecated: "please use 'new_news' instead",
+				},
+			},
+
+			Err: false,
+
+			Warnings: nil,
+		},
+
+		"Removed attribute usage generates error": {
+			Schema: map[string]*Schema{
+				"long_gone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Removed:  "no longer supported by Cloud API",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"long_gone": "still here!",
+			},
+
+			Err: true,
+			Errors: []error{
+				fmt.Errorf("\"long_gone\": [REMOVED] no longer supported by Cloud API"),
+			},
+		},
+
+		"Removed generates no errors if attr not used": {
+			Schema: map[string]*Schema{
+				"long_gone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Removed:  "no longer supported by Cloud API",
+				},
+			},
+
+			Err: false,
+		},
+
+		"Conflicting attributes generate error": {
+			Schema: map[string]*Schema{
+				"b": &Schema{
+					Type:     TypeString,
+					Optional: true,
+				},
+				"a": &Schema{
+					Type:          TypeString,
+					Optional:      true,
+					ConflictsWith: []string{"b"},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"b": "b-val",
+				"a": "a-val",
+			},
+
+			Err: true,
+			Errors: []error{
+				fmt.Errorf("\"a\": conflicts with b"),
+			},
+		},
+
+		"Conflicting attributes okay when unknown 1": {
+			Schema: map[string]*Schema{
+				"b": &Schema{
+					Type:     TypeString,
+					Optional: true,
+				},
+				"a": &Schema{
+					Type:          TypeString,
+					Optional:      true,
+					ConflictsWith: []string{"b"},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"b": "b-val",
+				"a": hcl2shim.UnknownVariableValue,
+			},
+
+			Err: false,
+		},
+
+		"Conflicting attributes okay when unknown 2": {
+			Schema: map[string]*Schema{
+				"b": &Schema{
+					Type:     TypeString,
+					Optional: true,
+				},
+				"a": &Schema{
+					Type:          TypeString,
+					Optional:      true,
+					ConflictsWith: []string{"b"},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"b": hcl2shim.UnknownVariableValue,
+				"a": "a-val",
+			},
+
+			Err: false,
+		},
+
+		"Conflicting attributes generate error even if one is unknown": {
+			Schema: map[string]*Schema{
+				"b": &Schema{
+					Type:          TypeString,
+					Optional:      true,
+					ConflictsWith: []string{"a", "c"},
+				},
+				"a": &Schema{
+					Type:          TypeString,
+					Optional:      true,
+					ConflictsWith: []string{"b", "c"},
+				},
+				"c": &Schema{
+					Type:          TypeString,
+					Optional:      true,
+					ConflictsWith: []string{"b", "a"},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"b": hcl2shim.UnknownVariableValue,
+				"a": "a-val",
+				"c": "c-val",
+			},
+
+			Err: true,
+			Errors: []error{
+				fmt.Errorf("\"a\": conflicts with c"),
+				fmt.Errorf("\"c\": conflicts with a"),
+			},
+		},
+
+		"Required attribute & undefined conflicting optional are good": {
+			Schema: map[string]*Schema{
+				"required_att": &Schema{
+					Type:     TypeString,
+					Required: true,
+				},
+				"optional_att": &Schema{
+					Type:          TypeString,
+					Optional:      true,
+					ConflictsWith: []string{"required_att"},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"required_att": "required-val",
+			},
+
+			Err: false,
+		},
+
+		"Required conflicting attribute & defined optional generate error": {
+			Schema: map[string]*Schema{
+				"required_att": &Schema{
+					Type:     TypeString,
+					Required: true,
+				},
+				"optional_att": &Schema{
+					Type:          TypeString,
+					Optional:      true,
+					ConflictsWith: []string{"required_att"},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"required_att": "required-val",
+				"optional_att": "optional-val",
+			},
+
+			Err: true,
+			Errors: []error{
+				fmt.Errorf(`"optional_att": conflicts with required_att`),
+			},
+		},
+
+		"Computed + Optional fields conflicting with each other": {
+			Schema: map[string]*Schema{
+				"foo_att": &Schema{
+					Type:          TypeString,
+					Optional:      true,
+					Computed:      true,
+					ConflictsWith: []string{"bar_att"},
+				},
+				"bar_att": &Schema{
+					Type:          TypeString,
+					Optional:      true,
+					Computed:      true,
+					ConflictsWith: []string{"foo_att"},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"foo_att": "foo-val",
+				"bar_att": "bar-val",
+			},
+
+			Err: true,
+			Errors: []error{
+				fmt.Errorf(`"foo_att": conflicts with bar_att`),
+				fmt.Errorf(`"bar_att": conflicts with foo_att`),
+			},
+		},
+
+		"Computed + Optional fields NOT conflicting with each other": {
+			Schema: map[string]*Schema{
+				"foo_att": &Schema{
+					Type:          TypeString,
+					Optional:      true,
+					Computed:      true,
+					ConflictsWith: []string{"bar_att"},
+				},
+				"bar_att": &Schema{
+					Type:          TypeString,
+					Optional:      true,
+					Computed:      true,
+					ConflictsWith: []string{"foo_att"},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"foo_att": "foo-val",
+			},
+
+			Err: false,
+		},
+
+		"Computed + Optional fields that conflict with none set": {
+			Schema: map[string]*Schema{
+				"foo_att": &Schema{
+					Type:          TypeString,
+					Optional:      true,
+					Computed:      true,
+					ConflictsWith: []string{"bar_att"},
+				},
+				"bar_att": &Schema{
+					Type:          TypeString,
+					Optional:      true,
+					Computed:      true,
+					ConflictsWith: []string{"foo_att"},
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Err: false,
+		},
+
+		"Good with ValidateFunc": {
+			Schema: map[string]*Schema{
+				"validate_me": &Schema{
+					Type:     TypeString,
+					Required: true,
+					ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
+						return
+					},
+				},
+			},
+			Config: map[string]interface{}{
+				"validate_me": "valid",
+			},
+			Err: false,
+		},
+
+		"Bad with ValidateFunc": {
+			Schema: map[string]*Schema{
+				"validate_me": &Schema{
+					Type:     TypeString,
+					Required: true,
+					ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
+						es = append(es, fmt.Errorf("something is not right here"))
+						return
+					},
+				},
+			},
+			Config: map[string]interface{}{
+				"validate_me": "invalid",
+			},
+			Err: true,
+			Errors: []error{
+				fmt.Errorf(`something is not right here`),
+			},
+		},
+
+		"ValidateFunc not called when type does not match": {
+			Schema: map[string]*Schema{
+				"number": &Schema{
+					Type:     TypeInt,
+					Required: true,
+					ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
+						t.Fatalf("Should not have gotten validate call")
+						return
+					},
+				},
+			},
+			Config: map[string]interface{}{
+				"number": "NaN",
+			},
+			Err: true,
+		},
+
+		"ValidateFunc gets decoded type": {
+			Schema: map[string]*Schema{
+				"maybe": &Schema{
+					Type:     TypeBool,
+					Required: true,
+					ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
+						if _, ok := v.(bool); !ok {
+							t.Fatalf("Expected bool, got: %#v", v)
+						}
+						return
+					},
+				},
+			},
+			Config: map[string]interface{}{
+				"maybe": "true",
+			},
+		},
+
+		"ValidateFunc is not called with a computed value": {
+			Schema: map[string]*Schema{
+				"validate_me": &Schema{
+					Type:     TypeString,
+					Required: true,
+					ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
+						es = append(es, fmt.Errorf("something is not right here"))
+						return
+					},
+				},
+			},
+			Config: map[string]interface{}{
+				"validate_me": hcl2shim.UnknownVariableValue,
+			},
+
+			Err: false,
+		},
+
+		"special timeouts field": {
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			Config: map[string]interface{}{
+				TimeoutsConfigKey: "bar",
+			},
+
+			Err: false,
+		},
+
+		"invalid bool field": {
+			Schema: map[string]*Schema{
+				"bool_field": {
+					Type:     TypeBool,
+					Optional: true,
+				},
+			},
+			Config: map[string]interface{}{
+				"bool_field": "abcdef",
+			},
+			Err: true,
+		},
+		"invalid integer field": {
+			Schema: map[string]*Schema{
+				"integer_field": {
+					Type:     TypeInt,
+					Optional: true,
+				},
+			},
+			Config: map[string]interface{}{
+				"integer_field": "abcdef",
+			},
+			Err: true,
+		},
+		"invalid float field": {
+			Schema: map[string]*Schema{
+				"float_field": {
+					Type:     TypeFloat,
+					Optional: true,
+				},
+			},
+			Config: map[string]interface{}{
+				"float_field": "abcdef",
+			},
+			Err: true,
+		},
+
+		// Invalid map values
+		"invalid bool map value": {
+			Schema: map[string]*Schema{
+				"boolMap": &Schema{
+					Type:     TypeMap,
+					Elem:     TypeBool,
+					Optional: true,
+				},
+			},
+			Config: map[string]interface{}{
+				"boolMap": map[string]interface{}{
+					"boolField": "notbool",
+				},
+			},
+			Err: true,
+		},
+		"invalid int map value": {
+			Schema: map[string]*Schema{
+				"intMap": &Schema{
+					Type:     TypeMap,
+					Elem:     TypeInt,
+					Optional: true,
+				},
+			},
+			Config: map[string]interface{}{
+				"intMap": map[string]interface{}{
+					"intField": "notInt",
+				},
+			},
+			Err: true,
+		},
+		"invalid float map value": {
+			Schema: map[string]*Schema{
+				"floatMap": &Schema{
+					Type:     TypeMap,
+					Elem:     TypeFloat,
+					Optional: true,
+				},
+			},
+			Config: map[string]interface{}{
+				"floatMap": map[string]interface{}{
+					"floatField": "notFloat",
+				},
+			},
+			Err: true,
+		},
+
+		"map with positive validate function": {
+			Schema: map[string]*Schema{
+				"floatInt": &Schema{
+					Type:     TypeMap,
+					Elem:     TypeInt,
+					Optional: true,
+					ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
+						return
+					},
+				},
+			},
+			Config: map[string]interface{}{
+				"floatInt": map[string]interface{}{
+					"rightAnswer": "42",
+					"tooMuch":     "43",
+				},
+			},
+			Err: false,
+		},
+		"map with negative validate function": {
+			Schema: map[string]*Schema{
+				"floatInt": &Schema{
+					Type:     TypeMap,
+					Elem:     TypeInt,
+					Optional: true,
+					ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
+						es = append(es, fmt.Errorf("this is not fine"))
+						return
+					},
+				},
+			},
+			Config: map[string]interface{}{
+				"floatInt": map[string]interface{}{
+					"rightAnswer": "42",
+					"tooMuch":     "43",
+				},
+			},
+			Err: true,
+		},
+
+		// The Validation function should not see interpolation strings from
+		// non-computed values.
+		"set with partially computed list and map": {
+			Schema: map[string]*Schema{
+				"outer": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"list": &Schema{
+								Type:     TypeList,
+								Optional: true,
+								Elem: &Schema{
+									Type: TypeString,
+									ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
+										if strings.HasPrefix(v.(string), "${") {
+											es = append(es, fmt.Errorf("should not have interpolations"))
+										}
+										return
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			Config: map[string]interface{}{
+				"outer": []interface{}{
+					map[string]interface{}{
+						"list": []interface{}{"A", hcl2shim.UnknownVariableValue, "c"},
+					},
+				},
+			},
+			Err: false,
+		},
+		"unexpected nils values": {
+			Schema: map[string]*Schema{
+				"strings": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Elem: &Schema{
+						Type: TypeString,
+					},
+				},
+				"block": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"int": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+						},
+					},
+				},
+			},
+
+			Config: map[string]interface{}{
+				"strings": []interface{}{"1", nil},
+				"block": []interface{}{map[string]interface{}{
+					"int": nil,
+				},
+					nil,
+				},
+			},
+			Err: true,
+		},
+	}
+
+	for tn, tc := range cases {
+		t.Run(tn, func(t *testing.T) {
+			c := terraform.NewResourceConfigRaw(tc.Config)
+
+			ws, es := schemaMap(tc.Schema).Validate(c)
+			if len(es) > 0 != tc.Err {
+				if len(es) == 0 {
+					t.Errorf("%q: no errors", tn)
+				}
+
+				for _, e := range es {
+					t.Errorf("%q: err: %s", tn, e)
+				}
+
+				t.FailNow()
+			}
+
+			if !reflect.DeepEqual(ws, tc.Warnings) {
+				t.Fatalf("%q: warnings:\n\nexpected: %#v\ngot:%#v", tn, tc.Warnings, ws)
+			}
+
+			if tc.Errors != nil {
+				sort.Sort(errorSort(es))
+				sort.Sort(errorSort(tc.Errors))
+
+				if !reflect.DeepEqual(es, tc.Errors) {
+					t.Fatalf("%q: errors:\n\nexpected: %q\ngot: %q", tn, tc.Errors, es)
+				}
+			}
+		})
+
+	}
+}
+
+func TestSchemaSet_ValidateMaxItems(t *testing.T) {
+	cases := map[string]struct {
+		Schema          map[string]*Schema
+		State           *terraform.InstanceState
+		Config          map[string]interface{}
+		ConfigVariables map[string]string
+		Diff            *terraform.InstanceDiff
+		Err             bool
+		Errors          []error
+	}{
+		"#0": {
+			Schema: map[string]*Schema{
+				"aliases": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					MaxItems: 1,
+					Elem:     &Schema{Type: TypeString},
+				},
+			},
+			State: nil,
+			Config: map[string]interface{}{
+				"aliases": []interface{}{"foo", "bar"},
+			},
+			Diff: nil,
+			Err:  true,
+			Errors: []error{
+				fmt.Errorf("aliases: attribute supports 1 item maximum, config has 2 declared"),
+			},
+		},
+		"#1": {
+			Schema: map[string]*Schema{
+				"aliases": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem:     &Schema{Type: TypeString},
+				},
+			},
+			State: nil,
+			Config: map[string]interface{}{
+				"aliases": []interface{}{"foo", "bar"},
+			},
+			Diff:   nil,
+			Err:    false,
+			Errors: nil,
+		},
+		"#2": {
+			Schema: map[string]*Schema{
+				"aliases": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					MaxItems: 1,
+					Elem:     &Schema{Type: TypeString},
+				},
+			},
+			State: nil,
+			Config: map[string]interface{}{
+				"aliases": []interface{}{"foo"},
+			},
+			Diff:   nil,
+			Err:    false,
+			Errors: nil,
+		},
+	}
+
+	for tn, tc := range cases {
+		c := terraform.NewResourceConfigRaw(tc.Config)
+		_, es := schemaMap(tc.Schema).Validate(c)
+
+		if len(es) > 0 != tc.Err {
+			if len(es) == 0 {
+				t.Errorf("%q: no errors", tn)
+			}
+
+			for _, e := range es {
+				t.Errorf("%q: err: %s", tn, e)
+			}
+
+			t.FailNow()
+		}
+
+		if tc.Errors != nil {
+			if !reflect.DeepEqual(es, tc.Errors) {
+				t.Fatalf("%q: expected: %q\ngot: %q", tn, tc.Errors, es)
+			}
+		}
+	}
+}
+
+func TestSchemaSet_ValidateMinItems(t *testing.T) {
+	cases := map[string]struct {
+		Schema          map[string]*Schema
+		State           *terraform.InstanceState
+		Config          map[string]interface{}
+		ConfigVariables map[string]string
+		Diff            *terraform.InstanceDiff
+		Err             bool
+		Errors          []error
+	}{
+		"#0": {
+			Schema: map[string]*Schema{
+				"aliases": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					MinItems: 2,
+					Elem:     &Schema{Type: TypeString},
+				},
+			},
+			State: nil,
+			Config: map[string]interface{}{
+				"aliases": []interface{}{"foo", "bar"},
+			},
+			Diff:   nil,
+			Err:    false,
+			Errors: nil,
+		},
+		"#1": {
+			Schema: map[string]*Schema{
+				"aliases": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem:     &Schema{Type: TypeString},
+				},
+			},
+			State: nil,
+			Config: map[string]interface{}{
+				"aliases": []interface{}{"foo", "bar"},
+			},
+			Diff:   nil,
+			Err:    false,
+			Errors: nil,
+		},
+		"#2": {
+			Schema: map[string]*Schema{
+				"aliases": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					MinItems: 2,
+					Elem:     &Schema{Type: TypeString},
+				},
+			},
+			State: nil,
+			Config: map[string]interface{}{
+				"aliases": []interface{}{"foo"},
+			},
+			Diff: nil,
+			Err:  true,
+			Errors: []error{
+				fmt.Errorf("aliases: attribute supports 2 item as a minimum, config has 1 declared"),
+			},
+		},
+	}
+
+	for tn, tc := range cases {
+		c := terraform.NewResourceConfigRaw(tc.Config)
+		_, es := schemaMap(tc.Schema).Validate(c)
+
+		if len(es) > 0 != tc.Err {
+			if len(es) == 0 {
+				t.Errorf("%q: no errors", tn)
+			}
+
+			for _, e := range es {
+				t.Errorf("%q: err: %s", tn, e)
+			}
+
+			t.FailNow()
+		}
+
+		if tc.Errors != nil {
+			if !reflect.DeepEqual(es, tc.Errors) {
+				t.Fatalf("%q: expected: %q\ngot: %q", tn, tc.Errors, es)
+			}
+		}
+	}
+}
+
+// errorSort implements sort.Interface to sort errors by their error message
+type errorSort []error
+
+func (e errorSort) Len() int      { return len(e) }
+func (e errorSort) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
+func (e errorSort) Less(i, j int) bool {
+	return e[i].Error() < e[j].Error()
+}
+
+func TestSchemaMapDeepCopy(t *testing.T) {
+	schema := map[string]*Schema{
+		"foo": &Schema{
+			Type: TypeString,
+		},
+	}
+	source := schemaMap(schema)
+	dest := source.DeepCopy()
+	dest["foo"].ForceNew = true
+	if reflect.DeepEqual(source, dest) {
+		t.Fatalf("source and dest should not match")
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/serialize.go b/v1.5.7/internal/legacy/helper/schema/serialize.go
new file mode 100644
index 0000000..a36f85b
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/serialize.go
@@ -0,0 +1,128 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"bytes"
+	"fmt"
+	"sort"
+	"strconv"
+)
+
+func SerializeValueForHash(buf *bytes.Buffer, val interface{}, schema *Schema) {
+	if val == nil {
+		buf.WriteRune(';')
+		return
+	}
+
+	switch schema.Type {
+	case TypeBool:
+		if val.(bool) {
+			buf.WriteRune('1')
+		} else {
+			buf.WriteRune('0')
+		}
+	case TypeInt:
+		buf.WriteString(strconv.Itoa(val.(int)))
+	case TypeFloat:
+		buf.WriteString(strconv.FormatFloat(val.(float64), 'g', -1, 64))
+	case TypeString:
+		buf.WriteString(val.(string))
+	case TypeList:
+		buf.WriteRune('(')
+		l := val.([]interface{})
+		for _, innerVal := range l {
+			serializeCollectionMemberForHash(buf, innerVal, schema.Elem)
+		}
+		buf.WriteRune(')')
+	case TypeMap:
+
+		m := val.(map[string]interface{})
+		var keys []string
+		for k := range m {
+			keys = append(keys, k)
+		}
+		sort.Strings(keys)
+		buf.WriteRune('[')
+		for _, k := range keys {
+			innerVal := m[k]
+			if innerVal == nil {
+				continue
+			}
+			buf.WriteString(k)
+			buf.WriteRune(':')
+
+			switch innerVal := innerVal.(type) {
+			case int:
+				buf.WriteString(strconv.Itoa(innerVal))
+			case float64:
+				buf.WriteString(strconv.FormatFloat(innerVal, 'g', -1, 64))
+			case string:
+				buf.WriteString(innerVal)
+			default:
+				panic(fmt.Sprintf("unknown value type in TypeMap %T", innerVal))
+			}
+
+			buf.WriteRune(';')
+		}
+		buf.WriteRune(']')
+	case TypeSet:
+		buf.WriteRune('{')
+		s := val.(*Set)
+		for _, innerVal := range s.List() {
+			serializeCollectionMemberForHash(buf, innerVal, schema.Elem)
+		}
+		buf.WriteRune('}')
+	default:
+		panic("unknown schema type to serialize")
+	}
+	buf.WriteRune(';')
+}
+
+// SerializeValueForHash appends a serialization of the given resource config
+// to the given buffer, guaranteeing deterministic results given the same value
+// and schema.
+//
+// Its primary purpose is as input into a hashing function in order
+// to hash complex substructures when used in sets, and so the serialization
+// is not reversible.
+func SerializeResourceForHash(buf *bytes.Buffer, val interface{}, resource *Resource) {
+	if val == nil {
+		return
+	}
+	sm := resource.Schema
+	m := val.(map[string]interface{})
+	var keys []string
+	for k := range sm {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+	for _, k := range keys {
+		innerSchema := sm[k]
+		// Skip attributes that are not user-provided. Computed attributes
+		// do not contribute to the hash since their ultimate value cannot
+		// be known at plan/diff time.
+		if !(innerSchema.Required || innerSchema.Optional) {
+			continue
+		}
+
+		buf.WriteString(k)
+		buf.WriteRune(':')
+		innerVal := m[k]
+		SerializeValueForHash(buf, innerVal, innerSchema)
+	}
+}
+
+func serializeCollectionMemberForHash(buf *bytes.Buffer, val interface{}, elem interface{}) {
+	switch tElem := elem.(type) {
+	case *Schema:
+		SerializeValueForHash(buf, val, tElem)
+	case *Resource:
+		buf.WriteRune('<')
+		SerializeResourceForHash(buf, val, tElem)
+		buf.WriteString(">;")
+	default:
+		panic(fmt.Sprintf("invalid element type: %T", tElem))
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/serialize_test.go b/v1.5.7/internal/legacy/helper/schema/serialize_test.go
new file mode 100644
index 0000000..499a603
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/serialize_test.go
@@ -0,0 +1,241 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"bytes"
+	"testing"
+)
+
+func TestSerializeForHash(t *testing.T) {
+	type testCase struct {
+		Schema   interface{}
+		Value    interface{}
+		Expected string
+	}
+
+	tests := []testCase{
+		testCase{
+			Schema: &Schema{
+				Type: TypeInt,
+			},
+			Value:    0,
+			Expected: "0;",
+		},
+
+		testCase{
+			Schema: &Schema{
+				Type: TypeInt,
+			},
+			Value:    200,
+			Expected: "200;",
+		},
+
+		testCase{
+			Schema: &Schema{
+				Type: TypeBool,
+			},
+			Value:    true,
+			Expected: "1;",
+		},
+
+		testCase{
+			Schema: &Schema{
+				Type: TypeBool,
+			},
+			Value:    false,
+			Expected: "0;",
+		},
+
+		testCase{
+			Schema: &Schema{
+				Type: TypeFloat,
+			},
+			Value:    1.0,
+			Expected: "1;",
+		},
+
+		testCase{
+			Schema: &Schema{
+				Type: TypeFloat,
+			},
+			Value:    1.54,
+			Expected: "1.54;",
+		},
+
+		testCase{
+			Schema: &Schema{
+				Type: TypeFloat,
+			},
+			Value:    0.1,
+			Expected: "0.1;",
+		},
+
+		testCase{
+			Schema: &Schema{
+				Type: TypeString,
+			},
+			Value:    "hello",
+			Expected: "hello;",
+		},
+
+		testCase{
+			Schema: &Schema{
+				Type: TypeString,
+			},
+			Value:    "1",
+			Expected: "1;",
+		},
+
+		testCase{
+			Schema: &Schema{
+				Type: TypeList,
+				Elem: &Schema{
+					Type: TypeString,
+				},
+			},
+			Value:    []interface{}{},
+			Expected: "();",
+		},
+
+		testCase{
+			Schema: &Schema{
+				Type: TypeList,
+				Elem: &Schema{
+					Type: TypeString,
+				},
+			},
+			Value:    []interface{}{"hello", "world"},
+			Expected: "(hello;world;);",
+		},
+
+		testCase{
+			Schema: &Schema{
+				Type: TypeList,
+				Elem: &Resource{
+					Schema: map[string]*Schema{
+						"fo": &Schema{
+							Type:     TypeString,
+							Required: true,
+						},
+						"fum": &Schema{
+							Type:     TypeString,
+							Required: true,
+						},
+					},
+				},
+			},
+			Value: []interface{}{
+				map[string]interface{}{
+					"fo": "bar",
+				},
+				map[string]interface{}{
+					"fo":  "baz",
+					"fum": "boz",
+				},
+			},
+			Expected: "(<fo:bar;fum:;>;<fo:baz;fum:boz;>;);",
+		},
+
+		testCase{
+			Schema: &Schema{
+				Type: TypeSet,
+				Elem: &Schema{
+					Type: TypeString,
+				},
+			},
+			Value: NewSet(func(i interface{}) int { return len(i.(string)) }, []interface{}{
+				"hello",
+				"woo",
+			}),
+			Expected: "{woo;hello;};",
+		},
+
+		testCase{
+			Schema: &Schema{
+				Type: TypeMap,
+				Elem: &Schema{
+					Type: TypeString,
+				},
+			},
+			Value: map[string]interface{}{
+				"foo": "bar",
+				"baz": "foo",
+			},
+			Expected: "[baz:foo;foo:bar;];",
+		},
+
+		testCase{
+			Schema: &Resource{
+				Schema: map[string]*Schema{
+					"name": &Schema{
+						Type:     TypeString,
+						Required: true,
+					},
+					"size": &Schema{
+						Type:     TypeInt,
+						Optional: true,
+					},
+					"green": &Schema{
+						Type:     TypeBool,
+						Optional: true,
+						Computed: true,
+					},
+					"upside_down": &Schema{
+						Type:     TypeBool,
+						Computed: true,
+					},
+				},
+			},
+			Value: map[string]interface{}{
+				"name":  "my-fun-database",
+				"size":  12,
+				"green": true,
+			},
+			Expected: "green:1;name:my-fun-database;size:12;",
+		},
+
+		// test TypeMap nested in Schema: GH-7091
+		testCase{
+			Schema: &Resource{
+				Schema: map[string]*Schema{
+					"outer": &Schema{
+						Type:     TypeSet,
+						Required: true,
+						Elem: &Schema{
+							Type:     TypeMap,
+							Optional: true,
+						},
+					},
+				},
+			},
+			Value: map[string]interface{}{
+				"outer": NewSet(func(i interface{}) int { return 42 }, []interface{}{
+					map[string]interface{}{
+						"foo": "bar",
+						"baz": "foo",
+					},
+				}),
+			},
+			Expected: "outer:{[baz:foo;foo:bar;];};",
+		},
+	}
+
+	for _, test := range tests {
+		var gotBuf bytes.Buffer
+		schema := test.Schema
+
+		switch s := schema.(type) {
+		case *Schema:
+			SerializeValueForHash(&gotBuf, test.Value, s)
+		case *Resource:
+			SerializeResourceForHash(&gotBuf, test.Value, s)
+		}
+
+		got := gotBuf.String()
+		if got != test.Expected {
+			t.Errorf("hash(%#v) got %#v, but want %#v", test.Value, got, test.Expected)
+		}
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/set.go b/v1.5.7/internal/legacy/helper/schema/set.go
new file mode 100644
index 0000000..cb640d8
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/set.go
@@ -0,0 +1,253 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"bytes"
+	"fmt"
+	"reflect"
+	"sort"
+	"strconv"
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/legacy/helper/hashcode"
+)
+
+// HashString hashes strings. If you want a Set of strings, this is the
+// SchemaSetFunc you want.
+func HashString(v interface{}) int {
+	return hashcode.String(v.(string))
+}
+
+// HashInt hashes integers. If you want a Set of integers, this is the
+// SchemaSetFunc you want.
+func HashInt(v interface{}) int {
+	return hashcode.String(strconv.Itoa(v.(int)))
+}
+
+// HashResource hashes complex structures that are described using
+// a *Resource. This is the default set implementation used when a set's
+// element type is a full resource.
+func HashResource(resource *Resource) SchemaSetFunc {
+	return func(v interface{}) int {
+		var buf bytes.Buffer
+		SerializeResourceForHash(&buf, v, resource)
+		return hashcode.String(buf.String())
+	}
+}
+
+// HashSchema hashes values that are described using a *Schema. This is the
+// default set implementation used when a set's element type is a single
+// schema.
+func HashSchema(schema *Schema) SchemaSetFunc {
+	return func(v interface{}) int {
+		var buf bytes.Buffer
+		SerializeValueForHash(&buf, v, schema)
+		return hashcode.String(buf.String())
+	}
+}
+
+// Set is a set data structure that is returned for elements of type
+// TypeSet.
+type Set struct {
+	F SchemaSetFunc
+
+	m    map[string]interface{}
+	once sync.Once
+}
+
+// NewSet is a convenience method for creating a new set with the given
+// items.
+func NewSet(f SchemaSetFunc, items []interface{}) *Set {
+	s := &Set{F: f}
+	for _, i := range items {
+		s.Add(i)
+	}
+
+	return s
+}
+
+// CopySet returns a copy of another set.
+func CopySet(otherSet *Set) *Set {
+	return NewSet(otherSet.F, otherSet.List())
+}
+
+// Add adds an item to the set if it isn't already in the set.
+func (s *Set) Add(item interface{}) {
+	s.add(item, false)
+}
+
+// Remove removes an item if it's already in the set. Idempotent.
+func (s *Set) Remove(item interface{}) {
+	s.remove(item)
+}
+
+// Contains checks if the set has the given item.
+func (s *Set) Contains(item interface{}) bool {
+	_, ok := s.m[s.hash(item)]
+	return ok
+}
+
+// Len returns the amount of items in the set.
+func (s *Set) Len() int {
+	return len(s.m)
+}
+
+// List returns the elements of this set in slice format.
+//
+// The order of the returned elements is deterministic. Given the same
+// set, the order of this will always be the same.
+func (s *Set) List() []interface{} {
+	result := make([]interface{}, len(s.m))
+	for i, k := range s.listCode() {
+		result[i] = s.m[k]
+	}
+
+	return result
+}
+
+// Difference performs a set difference of the two sets, returning
+// a new third set that has only the elements unique to this set.
+func (s *Set) Difference(other *Set) *Set {
+	result := &Set{F: s.F}
+	result.once.Do(result.init)
+
+	for k, v := range s.m {
+		if _, ok := other.m[k]; !ok {
+			result.m[k] = v
+		}
+	}
+
+	return result
+}
+
+// Intersection performs the set intersection of the two sets
+// and returns a new third set.
+func (s *Set) Intersection(other *Set) *Set {
+	result := &Set{F: s.F}
+	result.once.Do(result.init)
+
+	for k, v := range s.m {
+		if _, ok := other.m[k]; ok {
+			result.m[k] = v
+		}
+	}
+
+	return result
+}
+
+// Union performs the set union of the two sets and returns a new third
+// set.
+func (s *Set) Union(other *Set) *Set {
+	result := &Set{F: s.F}
+	result.once.Do(result.init)
+
+	for k, v := range s.m {
+		result.m[k] = v
+	}
+	for k, v := range other.m {
+		result.m[k] = v
+	}
+
+	return result
+}
+
+func (s *Set) Equal(raw interface{}) bool {
+	other, ok := raw.(*Set)
+	if !ok {
+		return false
+	}
+
+	return reflect.DeepEqual(s.m, other.m)
+}
+
+// HashEqual simply checks to the keys the top-level map to the keys in the
+// other set's top-level map to see if they are equal. This obviously assumes
+// you have a properly working hash function - use HashResource if in doubt.
+func (s *Set) HashEqual(raw interface{}) bool {
+	other, ok := raw.(*Set)
+	if !ok {
+		return false
+	}
+
+	ks1 := make([]string, 0)
+	ks2 := make([]string, 0)
+
+	for k := range s.m {
+		ks1 = append(ks1, k)
+	}
+	for k := range other.m {
+		ks2 = append(ks2, k)
+	}
+
+	sort.Strings(ks1)
+	sort.Strings(ks2)
+
+	return reflect.DeepEqual(ks1, ks2)
+}
+
+func (s *Set) GoString() string {
+	return fmt.Sprintf("*Set(%#v)", s.m)
+}
+
+func (s *Set) init() {
+	s.m = make(map[string]interface{})
+}
+
+func (s *Set) add(item interface{}, computed bool) string {
+	s.once.Do(s.init)
+
+	code := s.hash(item)
+	if computed {
+		code = "~" + code
+
+		if isProto5() {
+			tmpCode := code
+			count := 0
+			for _, exists := s.m[tmpCode]; exists; _, exists = s.m[tmpCode] {
+				count++
+				tmpCode = fmt.Sprintf("%s%d", code, count)
+			}
+			code = tmpCode
+		}
+	}
+
+	if _, ok := s.m[code]; !ok {
+		s.m[code] = item
+	}
+
+	return code
+}
+
+func (s *Set) hash(item interface{}) string {
+	code := s.F(item)
+	// Always return a nonnegative hashcode.
+	if code < 0 {
+		code = -code
+	}
+	return strconv.Itoa(code)
+}
+
+func (s *Set) remove(item interface{}) string {
+	s.once.Do(s.init)
+
+	code := s.hash(item)
+	delete(s.m, code)
+
+	return code
+}
+
+func (s *Set) index(item interface{}) int {
+	return sort.SearchStrings(s.listCode(), s.hash(item))
+}
+
+func (s *Set) listCode() []string {
+	// Sort the hash codes so the order of the list is deterministic
+	keys := make([]string, 0, len(s.m))
+	for k := range s.m {
+		keys = append(keys, k)
+	}
+	sort.Sort(sort.StringSlice(keys))
+	return keys
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/set_test.go b/v1.5.7/internal/legacy/helper/schema/set_test.go
new file mode 100644
index 0000000..1d37b24
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/set_test.go
@@ -0,0 +1,220 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestSetAdd(t *testing.T) {
+	s := &Set{F: testSetInt}
+	s.Add(1)
+	s.Add(5)
+	s.Add(25)
+
+	expected := []interface{}{1, 25, 5}
+	actual := s.List()
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestSetAdd_negative(t *testing.T) {
+	// Since we don't allow negative hashes, this should just hash to the
+	// same thing...
+	s := &Set{F: testSetInt}
+	s.Add(-1)
+	s.Add(1)
+
+	expected := []interface{}{-1}
+	actual := s.List()
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestSetContains(t *testing.T) {
+	s := &Set{F: testSetInt}
+	s.Add(5)
+	s.Add(-5)
+
+	if s.Contains(2) {
+		t.Fatal("should not contain")
+	}
+	if !s.Contains(5) {
+		t.Fatal("should contain")
+	}
+	if !s.Contains(-5) {
+		t.Fatal("should contain")
+	}
+}
+
+func TestSetDifference(t *testing.T) {
+	s1 := &Set{F: testSetInt}
+	s2 := &Set{F: testSetInt}
+
+	s1.Add(1)
+	s1.Add(5)
+
+	s2.Add(5)
+	s2.Add(25)
+
+	difference := s1.Difference(s2)
+	difference.Add(2)
+
+	expected := []interface{}{1, 2}
+	actual := difference.List()
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestSetIntersection(t *testing.T) {
+	s1 := &Set{F: testSetInt}
+	s2 := &Set{F: testSetInt}
+
+	s1.Add(1)
+	s1.Add(5)
+
+	s2.Add(5)
+	s2.Add(25)
+
+	intersection := s1.Intersection(s2)
+	intersection.Add(2)
+
+	expected := []interface{}{2, 5}
+	actual := intersection.List()
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestSetUnion(t *testing.T) {
+	s1 := &Set{F: testSetInt}
+	s2 := &Set{F: testSetInt}
+
+	s1.Add(1)
+	s1.Add(5)
+
+	s2.Add(5)
+	s2.Add(25)
+
+	union := s1.Union(s2)
+	union.Add(2)
+
+	expected := []interface{}{1, 2, 25, 5}
+	actual := union.List()
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func testSetInt(v interface{}) int {
+	return v.(int)
+}
+
+func TestHashResource_nil(t *testing.T) {
+	resource := &Resource{
+		Schema: map[string]*Schema{
+			"name": {
+				Type:     TypeString,
+				Optional: true,
+			},
+		},
+	}
+	f := HashResource(resource)
+
+	idx := f(nil)
+	if idx != 0 {
+		t.Fatalf("Expected 0 when hashing nil, given: %d", idx)
+	}
+}
+
+func TestHashEqual(t *testing.T) {
+	nested := &Resource{
+		Schema: map[string]*Schema{
+			"foo": {
+				Type:     TypeString,
+				Optional: true,
+			},
+		},
+	}
+	root := &Resource{
+		Schema: map[string]*Schema{
+			"bar": {
+				Type:     TypeString,
+				Optional: true,
+			},
+			"nested": {
+				Type:     TypeSet,
+				Optional: true,
+				Elem:     nested,
+			},
+		},
+	}
+	n1 := map[string]interface{}{"foo": "bar"}
+	n2 := map[string]interface{}{"foo": "baz"}
+
+	r1 := map[string]interface{}{
+		"bar":    "baz",
+		"nested": NewSet(HashResource(nested), []interface{}{n1}),
+	}
+	r2 := map[string]interface{}{
+		"bar":    "qux",
+		"nested": NewSet(HashResource(nested), []interface{}{n2}),
+	}
+	r3 := map[string]interface{}{
+		"bar":    "baz",
+		"nested": NewSet(HashResource(nested), []interface{}{n2}),
+	}
+	r4 := map[string]interface{}{
+		"bar":    "qux",
+		"nested": NewSet(HashResource(nested), []interface{}{n1}),
+	}
+	s1 := NewSet(HashResource(root), []interface{}{r1})
+	s2 := NewSet(HashResource(root), []interface{}{r2})
+	s3 := NewSet(HashResource(root), []interface{}{r3})
+	s4 := NewSet(HashResource(root), []interface{}{r4})
+
+	cases := []struct {
+		name     string
+		set      *Set
+		compare  *Set
+		expected bool
+	}{
+		{
+			name:     "equal",
+			set:      s1,
+			compare:  s1,
+			expected: true,
+		},
+		{
+			name:     "not equal",
+			set:      s1,
+			compare:  s2,
+			expected: false,
+		},
+		{
+			name:     "outer equal, should still not be equal",
+			set:      s1,
+			compare:  s3,
+			expected: false,
+		},
+		{
+			name:     "inner equal, should still not be equal",
+			set:      s1,
+			compare:  s4,
+			expected: false,
+		},
+	}
+	for _, tc := range cases {
+		t.Run(tc.name, func(t *testing.T) {
+			actual := tc.set.HashEqual(tc.compare)
+			if tc.expected != actual {
+				t.Fatalf("expected %t, got %t", tc.expected, actual)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/shims.go b/v1.5.7/internal/legacy/helper/schema/shims.go
new file mode 100644
index 0000000..8712209
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/shims.go
@@ -0,0 +1,118 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"encoding/json"
+
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+// DiffFromValues takes the current state and desired state as cty.Values and
+// derives a terraform.InstanceDiff to give to the legacy providers. This is
+// used to take the states provided by the new ApplyResourceChange method and
+// convert them to a state+diff required for the legacy Apply method.
+func DiffFromValues(prior, planned cty.Value, res *Resource) (*terraform.InstanceDiff, error) {
+	return diffFromValues(prior, planned, res, nil)
+}
+
+// diffFromValues takes an additional CustomizeDiffFunc, so we can generate our
+// test fixtures from the legacy tests. In the new provider protocol the diff
+// only needs to be created for the apply operation, and any customizations
+// have already been done.
+func diffFromValues(prior, planned cty.Value, res *Resource, cust CustomizeDiffFunc) (*terraform.InstanceDiff, error) {
+	instanceState, err := res.ShimInstanceStateFromValue(prior)
+	if err != nil {
+		return nil, err
+	}
+
+	configSchema := res.CoreConfigSchema()
+
+	cfg := terraform.NewResourceConfigShimmed(planned, configSchema)
+	removeConfigUnknowns(cfg.Config)
+	removeConfigUnknowns(cfg.Raw)
+
+	diff, err := schemaMap(res.Schema).Diff(instanceState, cfg, cust, nil, false)
+	if err != nil {
+		return nil, err
+	}
+
+	return diff, err
+}
+
+// During apply the only unknown values are those which are to be computed by
+// the resource itself. These may have been marked as unknown config values, and
+// need to be removed to prevent the UnknownVariableValue from appearing the diff.
+func removeConfigUnknowns(cfg map[string]interface{}) {
+	for k, v := range cfg {
+		switch v := v.(type) {
+		case string:
+			if v == hcl2shim.UnknownVariableValue {
+				delete(cfg, k)
+			}
+		case []interface{}:
+			for _, i := range v {
+				if m, ok := i.(map[string]interface{}); ok {
+					removeConfigUnknowns(m)
+				}
+			}
+		case map[string]interface{}:
+			removeConfigUnknowns(v)
+		}
+	}
+}
+
+// ApplyDiff takes a cty.Value state and applies a terraform.InstanceDiff to
+// get a new cty.Value state. This is used to convert the diff returned from
+// the legacy provider Diff method to the state required for the new
+// PlanResourceChange method.
+func ApplyDiff(base cty.Value, d *terraform.InstanceDiff, schema *configschema.Block) (cty.Value, error) {
+	return d.ApplyToValue(base, schema)
+}
+
+// StateValueToJSONMap converts a cty.Value to generic JSON map via the cty JSON
+// encoding.
+func StateValueToJSONMap(val cty.Value, ty cty.Type) (map[string]interface{}, error) {
+	js, err := ctyjson.Marshal(val, ty)
+	if err != nil {
+		return nil, err
+	}
+
+	var m map[string]interface{}
+	if err := json.Unmarshal(js, &m); err != nil {
+		return nil, err
+	}
+
+	return m, nil
+}
+
+// JSONMapToStateValue takes a generic json map[string]interface{} and converts it
+// to the specific type, ensuring that the values conform to the schema.
+func JSONMapToStateValue(m map[string]interface{}, block *configschema.Block) (cty.Value, error) {
+	var val cty.Value
+
+	js, err := json.Marshal(m)
+	if err != nil {
+		return val, err
+	}
+
+	val, err = ctyjson.Unmarshal(js, block.ImpliedType())
+	if err != nil {
+		return val, err
+	}
+
+	return block.CoerceValue(val)
+}
+
+// StateValueFromInstanceState converts a terraform.InstanceState to a
+// cty.Value as described by the provided cty.Type, and maintains the resource
+// ID as the "id" attribute.
+func StateValueFromInstanceState(is *terraform.InstanceState, ty cty.Type) (cty.Value, error) {
+	return is.AttrsAsObjectValue(ty)
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/shims_test.go b/v1.5.7/internal/legacy/helper/schema/shims_test.go
new file mode 100644
index 0000000..8a47b38
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/shims_test.go
@@ -0,0 +1,3524 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"reflect"
+	"strconv"
+	"testing"
+	"time"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/legacy/helper/hashcode"
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+var (
+	typeComparer  = cmp.Comparer(cty.Type.Equals)
+	valueComparer = cmp.Comparer(cty.Value.RawEquals)
+	equateEmpty   = cmpopts.EquateEmpty()
+)
+
+func testApplyDiff(t *testing.T,
+	resource *Resource,
+	state, expected *terraform.InstanceState,
+	diff *terraform.InstanceDiff) {
+
+	testSchema := providers.Schema{
+		Version: int64(resource.SchemaVersion),
+		Block:   resourceSchemaToBlock(resource.Schema),
+	}
+
+	stateVal, err := StateValueFromInstanceState(state, testSchema.Block.ImpliedType())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	newState, err := ApplyDiff(stateVal, diff, testSchema.Block)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// verify that "id" is correct
+	id := newState.AsValueMap()["id"]
+
+	switch {
+	case diff.Destroy || diff.DestroyDeposed || diff.DestroyTainted:
+		// there should be no id
+		if !id.IsNull() {
+			t.Fatalf("destroyed instance should have no id: %#v", id)
+		}
+	default:
+		// the "id" field always exists and is computed, so it must have a
+		// valid value or be unknown.
+		if id.IsNull() {
+			t.Fatal("new instance state cannot have a null id")
+		}
+
+		if id.IsKnown() && id.AsString() == "" {
+			t.Fatal("new instance id cannot be an empty string")
+		}
+	}
+
+	// Resource.Meta will be hanlded separately, so it's OK that we lose the
+	// timeout values here.
+	expectedState, err := StateValueFromInstanceState(expected, testSchema.Block.ImpliedType())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !cmp.Equal(expectedState, newState, equateEmpty, typeComparer, valueComparer) {
+		t.Fatalf(cmp.Diff(expectedState, newState, equateEmpty, typeComparer, valueComparer))
+	}
+}
+
+func TestShimResourcePlan_destroyCreate(t *testing.T) {
+	r := &Resource{
+		SchemaVersion: 2,
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+				ForceNew: true,
+			},
+		},
+	}
+
+	d := &terraform.InstanceDiff{
+		Attributes: map[string]*terraform.ResourceAttrDiff{
+			"foo": &terraform.ResourceAttrDiff{
+				RequiresNew: true,
+				Old:         "3",
+				New:         "42",
+			},
+		},
+	}
+
+	state := &terraform.InstanceState{
+		Attributes: map[string]string{"foo": "3"},
+	}
+
+	expected := &terraform.InstanceState{
+		ID: hcl2shim.UnknownVariableValue,
+		Attributes: map[string]string{
+			"id":  hcl2shim.UnknownVariableValue,
+			"foo": "42",
+		},
+		Meta: map[string]interface{}{
+			"schema_version": "2",
+		},
+	}
+
+	testApplyDiff(t, r, state, expected, d)
+}
+
+func TestShimResourceApply_create(t *testing.T) {
+	r := &Resource{
+		SchemaVersion: 2,
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	called := false
+	r.Create = func(d *ResourceData, m interface{}) error {
+		called = true
+		d.SetId("foo")
+		return nil
+	}
+
+	var s *terraform.InstanceState = nil
+
+	d := &terraform.InstanceDiff{
+		Attributes: map[string]*terraform.ResourceAttrDiff{
+			"foo": &terraform.ResourceAttrDiff{
+				New: "42",
+			},
+		},
+	}
+
+	actual, err := r.Apply(s, d, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !called {
+		t.Fatal("not called")
+	}
+
+	expected := &terraform.InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"id":  "foo",
+			"foo": "42",
+		},
+		Meta: map[string]interface{}{
+			"schema_version": "2",
+		},
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+
+	// Shim
+	// now that we have our diff and desired state, see if we can reproduce
+	// that with the shim
+	// we're not testing Resource.Create, so we need to start with the "created" state
+	createdState := &terraform.InstanceState{
+		ID:         "foo",
+		Attributes: map[string]string{"id": "foo"},
+	}
+
+	testApplyDiff(t, r, createdState, expected, d)
+}
+
+func TestShimResourceApply_Timeout_state(t *testing.T) {
+	r := &Resource{
+		SchemaVersion: 2,
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+		Timeouts: &ResourceTimeout{
+			Create: DefaultTimeout(40 * time.Minute),
+			Update: DefaultTimeout(80 * time.Minute),
+			Delete: DefaultTimeout(40 * time.Minute),
+		},
+	}
+
+	called := false
+	r.Create = func(d *ResourceData, m interface{}) error {
+		called = true
+		d.SetId("foo")
+		return nil
+	}
+
+	var s *terraform.InstanceState = nil
+
+	d := &terraform.InstanceDiff{
+		Attributes: map[string]*terraform.ResourceAttrDiff{
+			"foo": &terraform.ResourceAttrDiff{
+				New: "42",
+			},
+		},
+	}
+
+	diffTimeout := &ResourceTimeout{
+		Create: DefaultTimeout(40 * time.Minute),
+		Update: DefaultTimeout(80 * time.Minute),
+		Delete: DefaultTimeout(40 * time.Minute),
+	}
+
+	if err := diffTimeout.DiffEncode(d); err != nil {
+		t.Fatalf("Error encoding timeout to diff: %s", err)
+	}
+
+	actual, err := r.Apply(s, d, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !called {
+		t.Fatal("not called")
+	}
+
+	expected := &terraform.InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"id":  "foo",
+			"foo": "42",
+		},
+		Meta: map[string]interface{}{
+			"schema_version": "2",
+			TimeoutKey:       expectedForValues(40, 0, 80, 40, 0),
+		},
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("Not equal in Timeout State:\n\texpected: %#v\n\tactual: %#v", expected.Meta, actual.Meta)
+	}
+
+	// Shim
+	// we're not testing Resource.Create, so we need to start with the "created" state
+	createdState := &terraform.InstanceState{
+		ID:         "foo",
+		Attributes: map[string]string{"id": "foo"},
+	}
+
+	testApplyDiff(t, r, createdState, expected, d)
+}
+
+func TestShimResourceDiff_Timeout_diff(t *testing.T) {
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+		Timeouts: &ResourceTimeout{
+			Create: DefaultTimeout(40 * time.Minute),
+			Update: DefaultTimeout(80 * time.Minute),
+			Delete: DefaultTimeout(40 * time.Minute),
+		},
+	}
+
+	r.Create = func(d *ResourceData, m interface{}) error {
+		d.SetId("foo")
+		return nil
+	}
+
+	conf := terraform.NewResourceConfigRaw(map[string]interface{}{
+		"foo": 42,
+		TimeoutsConfigKey: map[string]interface{}{
+			"create": "2h",
+		},
+	})
+	var s *terraform.InstanceState
+
+	actual, err := r.Diff(s, conf, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := &terraform.InstanceDiff{
+		Attributes: map[string]*terraform.ResourceAttrDiff{
+			"foo": &terraform.ResourceAttrDiff{
+				New: "42",
+			},
+		},
+	}
+
+	diffTimeout := &ResourceTimeout{
+		Create: DefaultTimeout(120 * time.Minute),
+		Update: DefaultTimeout(80 * time.Minute),
+		Delete: DefaultTimeout(40 * time.Minute),
+	}
+
+	if err := diffTimeout.DiffEncode(expected); err != nil {
+		t.Fatalf("Error encoding timeout to diff: %s", err)
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("Not equal in Timeout Diff:\n\texpected: %#v\n\tactual: %#v", expected.Meta, actual.Meta)
+	}
+
+	// Shim
+	// apply this diff, so we have a state to compare
+	applied, err := r.Apply(s, actual, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// we're not testing Resource.Create, so we need to start with the "created" state
+	createdState := &terraform.InstanceState{
+		ID:         "foo",
+		Attributes: map[string]string{"id": "foo"},
+	}
+
+	testSchema := providers.Schema{
+		Version: int64(r.SchemaVersion),
+		Block:   resourceSchemaToBlock(r.Schema),
+	}
+
+	initialVal, err := StateValueFromInstanceState(createdState, testSchema.Block.ImpliedType())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	appliedVal, err := StateValueFromInstanceState(applied, testSchema.Block.ImpliedType())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	d, err := DiffFromValues(initialVal, appliedVal, r)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if eq, _ := d.Same(expected); !eq {
+		t.Fatal(cmp.Diff(d, expected))
+	}
+}
+
+func TestShimResourceApply_destroy(t *testing.T) {
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+			},
+		},
+	}
+
+	called := false
+	r.Delete = func(d *ResourceData, m interface{}) error {
+		called = true
+		return nil
+	}
+
+	s := &terraform.InstanceState{
+		ID: "bar",
+	}
+
+	d := &terraform.InstanceDiff{
+		Destroy: true,
+	}
+
+	actual, err := r.Apply(s, d, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !called {
+		t.Fatal("delete not called")
+	}
+
+	if actual != nil {
+		t.Fatalf("bad: %#v", actual)
+	}
+
+	// Shim
+	// now that we have our diff and desired state, see if we can reproduce
+	// that with the shim
+	testApplyDiff(t, r, s, actual, d)
+}
+
+func TestShimResourceApply_destroyCreate(t *testing.T) {
+	r := &Resource{
+		Schema: map[string]*Schema{
+			"foo": &Schema{
+				Type:     TypeInt,
+				Optional: true,
+				ForceNew: true,
+			},
+
+			"tags": &Schema{
+				Type:     TypeMap,
+				Optional: true,
+				Computed: true,
+			},
+		},
+	}
+
+	change := false
+	r.Create = func(d *ResourceData, m interface{}) error {
+		change = d.HasChange("tags")
+		d.SetId("foo")
+		return nil
+	}
+	r.Delete = func(d *ResourceData, m interface{}) error {
+		return nil
+	}
+
+	var s *terraform.InstanceState = &terraform.InstanceState{
+		ID: "bar",
+		Attributes: map[string]string{
+			"foo":       "7",
+			"tags.Name": "foo",
+		},
+	}
+
+	d := &terraform.InstanceDiff{
+		Attributes: map[string]*terraform.ResourceAttrDiff{
+			"id": &terraform.ResourceAttrDiff{
+				New: "foo",
+			},
+			"foo": &terraform.ResourceAttrDiff{
+				Old:         "7",
+				New:         "42",
+				RequiresNew: true,
+			},
+			"tags.Name": &terraform.ResourceAttrDiff{
+				Old:         "foo",
+				New:         "foo",
+				RequiresNew: true,
+			},
+		},
+	}
+
+	actual, err := r.Apply(s, d, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !change {
+		t.Fatal("should have change")
+	}
+
+	expected := &terraform.InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"id":        "foo",
+			"foo":       "42",
+			"tags.%":    "1",
+			"tags.Name": "foo",
+		},
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		cmp.Diff(actual, expected)
+	}
+
+	// Shim
+	// now that we have our diff and desired state, see if we can reproduce
+	// that with the shim
+	// we're not testing Resource.Create, so we need to start with the "created" state
+	createdState := &terraform.InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"id":        "foo",
+			"foo":       "7",
+			"tags.%":    "1",
+			"tags.Name": "foo",
+		},
+	}
+
+	testApplyDiff(t, r, createdState, expected, d)
+}
+
+func TestShimSchemaMap_Diff(t *testing.T) {
+	cases := []struct {
+		Name          string
+		Schema        map[string]*Schema
+		State         *terraform.InstanceState
+		Config        map[string]interface{}
+		CustomizeDiff CustomizeDiffFunc
+		Diff          *terraform.InstanceDiff
+		Err           bool
+	}{
+		{
+			Name: "diff-1",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "foo",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "diff-2",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						NewComputed: true,
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "diff-3",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "foo",
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Computed, but set in config",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"availability_zone": "bar",
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old: "foo",
+						New: "bar",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Default",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Default:  "foo",
+				},
+			},
+
+			State: nil,
+
+			Config: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "DefaultFunc, value",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					DefaultFunc: func() (interface{}, error) {
+						return "foo", nil
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "DefaultFunc, configuration set",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					DefaultFunc: func() (interface{}, error) {
+						return "foo", nil
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"availability_zone": "bar",
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "bar",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "String with StateFunc",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					StateFunc: func(a interface{}) string {
+						return a.(string) + "!"
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:      "",
+						New:      "foo!",
+						NewExtra: "foo",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "StateFunc not called with nil value",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					StateFunc: func(a interface{}) string {
+						t.Error("should not get here!")
+						return ""
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Variable computed",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"availability_zone": hcl2shim.UnknownVariableValue,
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         hcl2shim.UnknownVariableValue,
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Int decode",
+			Schema: map[string]*Schema{
+				"port": &Schema{
+					Type:     TypeInt,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"port": 27,
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"port": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "27",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "bool decode",
+			Schema: map[string]*Schema{
+				"port": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"port": false,
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"port": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "false",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Bool",
+			Schema: map[string]*Schema{
+				"delete": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+					Default:  false,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"delete": "false",
+				},
+			},
+
+			Config: nil,
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "List decode",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{1, 2, 5},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "3",
+					},
+					"ports.0": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "2",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "5",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "List decode with promotion with list",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:          TypeList,
+					Required:      true,
+					Elem:          &Schema{Type: TypeInt},
+					PromoteSingle: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{"5"},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"ports.0": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "5",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{1, 2, 5},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "3",
+					},
+					"ports.0": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "2",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "5",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{1, hcl2shim.UnknownVariableValue, "5"},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old:         "0",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"ports.#": "3",
+					"ports.0": "1",
+					"ports.1": "2",
+					"ports.2": "5",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{1, 2, 5},
+			},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"ports.#": "2",
+					"ports.0": "1",
+					"ports.1": "2",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{1, 2, 5},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "2",
+						New: "3",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "5",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{1, 2, 5},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old:         "0",
+						New:         "3",
+						RequiresNew: true,
+					},
+					"ports.0": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "1",
+						RequiresNew: true,
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "2",
+						RequiresNew: true,
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "5",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "List with computed set",
+			Schema: map[string]*Schema{
+				"config": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					ForceNew: true,
+					MinItems: 1,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"name": {
+								Type:     TypeString,
+								Required: true,
+							},
+
+							"rules": {
+								Type:     TypeSet,
+								Computed: true,
+								Elem:     &Schema{Type: TypeString},
+								Set:      HashString,
+							},
+						},
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"config": []interface{}{
+					map[string]interface{}{
+						"name": "hello",
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config.#": &terraform.ResourceAttrDiff{
+						Old:         "0",
+						New:         "1",
+						RequiresNew: true,
+					},
+
+					"config.0.name": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "hello",
+					},
+
+					"config.0.rules.#": &terraform.ResourceAttrDiff{
+						Old:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set-1",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{5, 2, 1},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "3",
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "2",
+					},
+					"ports.5": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "5",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set-2",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Computed: true,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"ports.#": "0",
+				},
+			},
+
+			Config: nil,
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Set-3",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set-4",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{"2", "5", 1},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "3",
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "2",
+					},
+					"ports.5": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "5",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set-5",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{1, hcl2shim.UnknownVariableValue, 5},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set-6",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"ports.#": "2",
+					"ports.1": "1",
+					"ports.2": "2",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{5, 2, 1},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						Old: "2",
+						New: "3",
+					},
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "1",
+						New: "1",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "2",
+						New: "2",
+					},
+					"ports.5": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "5",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set-8",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"availability_zone": "bar",
+					"ports.#":           "1",
+					"ports.80":          "80",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Set-9",
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"ports": &Schema{
+								Type:     TypeList,
+								Optional: true,
+								Elem:     &Schema{Type: TypeInt},
+							},
+						},
+					},
+					Set: func(v interface{}) int {
+						m := v.(map[string]interface{})
+						ps := m["ports"].([]interface{})
+						result := 0
+						for _, p := range ps {
+							result += p.(int)
+						}
+						return result
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"ingress.#":           "2",
+					"ingress.80.ports.#":  "1",
+					"ingress.80.ports.0":  "80",
+					"ingress.443.ports.#": "1",
+					"ingress.443.ports.0": "443",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ingress": []interface{}{
+					map[string]interface{}{
+						"ports": []interface{}{443},
+					},
+					map[string]interface{}{
+						"ports": []interface{}{80},
+					},
+				},
+			},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "List of structure decode",
+			Schema: map[string]*Schema{
+				"ingress": &Schema{
+					Type:     TypeList,
+					Required: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"from": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+						},
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ingress": []interface{}{
+					map[string]interface{}{
+						"from": 8080,
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ingress.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"ingress.0.from": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "8080",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "ComputedWhen",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:         TypeString,
+					Computed:     true,
+					ComputedWhen: []string{"port"},
+				},
+
+				"port": &Schema{
+					Type:     TypeInt,
+					Optional: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"availability_zone": "foo",
+					"port":              "80",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"port": 80,
+			},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "computed",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:         TypeString,
+					Computed:     true,
+					ComputedWhen: []string{"port"},
+				},
+
+				"port": &Schema{
+					Type:     TypeInt,
+					Optional: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"port": 80,
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						NewComputed: true,
+					},
+					"port": &terraform.ResourceAttrDiff{
+						New: "80",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "computed, exists",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:         TypeString,
+					Computed:     true,
+					ComputedWhen: []string{"port"},
+				},
+
+				"port": &Schema{
+					Type:     TypeInt,
+					Optional: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"port": "80",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"port": 80,
+			},
+
+			// there is no computed diff when the instance exists already
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Maps-1",
+			Schema: map[string]*Schema{
+				"config_vars": &Schema{
+					Type: TypeMap,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"config_vars": map[string]interface{}{
+					"bar": "baz",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config_vars.%": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+
+					"config_vars.bar": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "baz",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Maps-2",
+			Schema: map[string]*Schema{
+				"config_vars": &Schema{
+					Type: TypeMap,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"config_vars.%":   "1",
+					"config_vars.foo": "bar",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"config_vars": map[string]interface{}{
+					"bar": "baz",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config_vars.foo": &terraform.ResourceAttrDiff{
+						Old:        "bar",
+						NewRemoved: true,
+					},
+					"config_vars.bar": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "baz",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Maps-3",
+			Schema: map[string]*Schema{
+				"vars": &Schema{
+					Type:     TypeMap,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"vars.%":   "1",
+					"vars.foo": "bar",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"vars": map[string]interface{}{
+					"bar": "baz",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"vars.foo": &terraform.ResourceAttrDiff{
+						Old:        "bar",
+						New:        "",
+						NewRemoved: true,
+					},
+					"vars.bar": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "baz",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Maps-4",
+			Schema: map[string]*Schema{
+				"vars": &Schema{
+					Type:     TypeMap,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"vars.%":   "1",
+					"vars.foo": "bar",
+				},
+			},
+
+			Config: nil,
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Maps-5",
+			Schema: map[string]*Schema{
+				"config_vars": &Schema{
+					Type: TypeList,
+					Elem: &Schema{Type: TypeMap},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"config_vars.#":     "1",
+					"config_vars.0.%":   "1",
+					"config_vars.0.foo": "bar",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"config_vars": []interface{}{
+					map[string]interface{}{
+						"bar": "baz",
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config_vars.0.foo": &terraform.ResourceAttrDiff{
+						Old:        "bar",
+						NewRemoved: true,
+					},
+					"config_vars.0.bar": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "baz",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Maps-6",
+			Schema: map[string]*Schema{
+				"config_vars": &Schema{
+					Type:     TypeList,
+					Elem:     &Schema{Type: TypeMap},
+					Optional: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"config_vars.#":     "1",
+					"config_vars.0.%":   "2",
+					"config_vars.0.foo": "bar",
+					"config_vars.0.bar": "baz",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config_vars.#": &terraform.ResourceAttrDiff{
+						Old: "1",
+						New: "0",
+					},
+					"config_vars.0.%": &terraform.ResourceAttrDiff{
+						Old: "2",
+						New: "0",
+					},
+					"config_vars.0.foo": &terraform.ResourceAttrDiff{
+						Old:        "bar",
+						NewRemoved: true,
+					},
+					"config_vars.0.bar": &terraform.ResourceAttrDiff{
+						Old:        "baz",
+						NewRemoved: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "ForceNews",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					ForceNew: true,
+				},
+
+				"address": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"availability_zone": "bar",
+					"address":           "foo",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "bar",
+						New:         "foo",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set-10",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					ForceNew: true,
+				},
+
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"availability_zone": "bar",
+					"ports.#":           "1",
+					"ports.80":          "80",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "bar",
+						New:         "foo",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set-11",
+			Schema: map[string]*Schema{
+				"instances": &Schema{
+					Type:     TypeSet,
+					Elem:     &Schema{Type: TypeString},
+					Optional: true,
+					Computed: true,
+					Set: func(v interface{}) int {
+						return len(v.(string))
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"instances.#": "0",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"instances": []interface{}{hcl2shim.UnknownVariableValue},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"instances.#": &terraform.ResourceAttrDiff{
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set-12",
+			Schema: map[string]*Schema{
+				"route": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"index": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+
+							"gateway": &Schema{
+								Type:     TypeString,
+								Optional: true,
+							},
+						},
+					},
+					Set: func(v interface{}) int {
+						m := v.(map[string]interface{})
+						return m["index"].(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"route": []interface{}{
+					map[string]interface{}{
+						"index":   "1",
+						"gateway": hcl2shim.UnknownVariableValue,
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"route.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"route.~1.index": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"route.~1.gateway": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         hcl2shim.UnknownVariableValue,
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set-13",
+			Schema: map[string]*Schema{
+				"route": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"index": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+
+							"gateway": &Schema{
+								Type:     TypeSet,
+								Optional: true,
+								Elem:     &Schema{Type: TypeInt},
+								Set: func(a interface{}) int {
+									return a.(int)
+								},
+							},
+						},
+					},
+					Set: func(v interface{}) int {
+						m := v.(map[string]interface{})
+						return m["index"].(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"route": []interface{}{
+					map[string]interface{}{
+						"index": "1",
+						"gateway": []interface{}{
+							hcl2shim.UnknownVariableValue,
+						},
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"route.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"route.~1.index": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"route.~1.gateway.#": &terraform.ResourceAttrDiff{
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Computed maps",
+			Schema: map[string]*Schema{
+				"vars": &Schema{
+					Type:     TypeMap,
+					Computed: true,
+				},
+			},
+
+			State: nil,
+
+			Config: nil,
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"vars.%": &terraform.ResourceAttrDiff{
+						Old:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Computed maps",
+			Schema: map[string]*Schema{
+				"vars": &Schema{
+					Type:     TypeMap,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"vars.%": "0",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"vars": map[string]interface{}{
+					"bar": hcl2shim.UnknownVariableValue,
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"vars.%": &terraform.ResourceAttrDiff{
+						Old:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name:   "Empty",
+			Schema: map[string]*Schema{},
+
+			State: &terraform.InstanceState{},
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Float",
+			Schema: map[string]*Schema{
+				"some_threshold": &Schema{
+					Type: TypeFloat,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"some_threshold": "567.8",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"some_threshold": 12.34,
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"some_threshold": &terraform.ResourceAttrDiff{
+						Old: "567.8",
+						New: "12.34",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "https://github.com/hashicorp/terraform/issues/824",
+			Schema: map[string]*Schema{
+				"block_device": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"device_name": &Schema{
+								Type:     TypeString,
+								Required: true,
+							},
+							"delete_on_termination": &Schema{
+								Type:     TypeBool,
+								Optional: true,
+								Default:  true,
+							},
+						},
+					},
+					Set: func(v interface{}) int {
+						var buf bytes.Buffer
+						m := v.(map[string]interface{})
+						buf.WriteString(fmt.Sprintf("%s-", m["device_name"].(string)))
+						buf.WriteString(fmt.Sprintf("%t-", m["delete_on_termination"].(bool)))
+						return hashcode.String(buf.String())
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"block_device.#": "2",
+					"block_device.616397234.delete_on_termination":  "true",
+					"block_device.616397234.device_name":            "/dev/sda1",
+					"block_device.2801811477.delete_on_termination": "true",
+					"block_device.2801811477.device_name":           "/dev/sdx",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"block_device": []interface{}{
+					map[string]interface{}{
+						"device_name": "/dev/sda1",
+					},
+					map[string]interface{}{
+						"device_name": "/dev/sdx",
+					},
+				},
+			},
+			Diff: nil,
+			Err:  false,
+		},
+
+		{
+			Name: "Zero value in state shouldn't result in diff",
+			Schema: map[string]*Schema{
+				"port": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+					ForceNew: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"port": "false",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Same as prev, but for sets",
+			Schema: map[string]*Schema{
+				"route": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"index": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+
+							"gateway": &Schema{
+								Type:     TypeSet,
+								Optional: true,
+								Elem:     &Schema{Type: TypeInt},
+								Set: func(a interface{}) int {
+									return a.(int)
+								},
+							},
+						},
+					},
+					Set: func(v interface{}) int {
+						m := v.(map[string]interface{})
+						return m["index"].(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"route.#": "0",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "A set computed element shouldn't cause a diff",
+			Schema: map[string]*Schema{
+				"active": &Schema{
+					Type:     TypeBool,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"active": "true",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "An empty set should show up in the diff",
+			Schema: map[string]*Schema{
+				"instances": &Schema{
+					Type:     TypeSet,
+					Elem:     &Schema{Type: TypeString},
+					Optional: true,
+					ForceNew: true,
+					Set: func(v interface{}) int {
+						return len(v.(string))
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"instances.#": "1",
+					"instances.3": "foo",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"instances.#": &terraform.ResourceAttrDiff{
+						Old:         "1",
+						New:         "0",
+						RequiresNew: true,
+					},
+					"instances.3": &terraform.ResourceAttrDiff{
+						Old:         "foo",
+						New:         "",
+						NewRemoved:  true,
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Map with empty value",
+			Schema: map[string]*Schema{
+				"vars": &Schema{
+					Type: TypeMap,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"vars": map[string]interface{}{
+					"foo": "",
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"vars.%": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"vars.foo": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Unset bool, not in state",
+			Schema: map[string]*Schema{
+				"force": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Unset set, not in state",
+			Schema: map[string]*Schema{
+				"metadata_keys": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					ForceNew: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set:      func(interface{}) int { return 0 },
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Unset list in state, should not show up computed",
+			Schema: map[string]*Schema{
+				"metadata_keys": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+					Elem:     &Schema{Type: TypeInt},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"metadata_keys.#": "0",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Computed map without config that's known to be empty does not generate diff",
+			Schema: map[string]*Schema{
+				"tags": &Schema{
+					Type:     TypeMap,
+					Computed: true,
+				},
+			},
+
+			Config: nil,
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"tags.%": "0",
+				},
+			},
+
+			Diff: nil,
+
+			Err: false,
+		},
+
+		{
+			Name: "Set with hyphen keys",
+			Schema: map[string]*Schema{
+				"route": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"index": &Schema{
+								Type:     TypeInt,
+								Required: true,
+							},
+
+							"gateway-name": &Schema{
+								Type:     TypeString,
+								Optional: true,
+							},
+						},
+					},
+					Set: func(v interface{}) int {
+						m := v.(map[string]interface{})
+						return m["index"].(int)
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"route": []interface{}{
+					map[string]interface{}{
+						"index":        "1",
+						"gateway-name": "hello",
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"route.#": &terraform.ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"route.1.index": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "1",
+					},
+					"route.1.gateway-name": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "hello",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "StateFunc in nested set (#1759)",
+			Schema: map[string]*Schema{
+				"service_account": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					ForceNew: true,
+					Elem: &Resource{
+						Schema: map[string]*Schema{
+							"scopes": &Schema{
+								Type:     TypeSet,
+								Required: true,
+								ForceNew: true,
+								Elem: &Schema{
+									Type: TypeString,
+									StateFunc: func(v interface{}) string {
+										return v.(string) + "!"
+									},
+								},
+								Set: func(v interface{}) int {
+									i, err := strconv.Atoi(v.(string))
+									if err != nil {
+										t.Fatalf("err: %s", err)
+									}
+									return i
+								},
+							},
+						},
+					},
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"service_account": []interface{}{
+					map[string]interface{}{
+						"scopes": []interface{}{"123"},
+					},
+				},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"service_account.#": &terraform.ResourceAttrDiff{
+						Old:         "0",
+						New:         "1",
+						RequiresNew: true,
+					},
+					"service_account.0.scopes.#": &terraform.ResourceAttrDiff{
+						Old:         "0",
+						New:         "1",
+						RequiresNew: true,
+					},
+					"service_account.0.scopes.123": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "123!",
+						NewExtra:    "123",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Removing set elements",
+			Schema: map[string]*Schema{
+				"instances": &Schema{
+					Type:     TypeSet,
+					Elem:     &Schema{Type: TypeString},
+					Optional: true,
+					ForceNew: true,
+					Set: func(v interface{}) int {
+						return len(v.(string))
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"instances.#": "2",
+					"instances.3": "333",
+					"instances.2": "22",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"instances": []interface{}{"333", "4444"},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"instances.2": &terraform.ResourceAttrDiff{
+						Old:         "22",
+						New:         "",
+						NewRemoved:  true,
+						RequiresNew: true,
+					},
+					"instances.3": &terraform.ResourceAttrDiff{
+						Old: "333",
+						New: "333",
+					},
+					"instances.4": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "4444",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Bools can be set with 0/1 in config, still get true/false",
+			Schema: map[string]*Schema{
+				"one": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+				},
+				"two": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+				},
+				"three": &Schema{
+					Type:     TypeBool,
+					Optional: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"one":   "false",
+					"two":   "true",
+					"three": "true",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"one": "1",
+				"two": "0",
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"one": &terraform.ResourceAttrDiff{
+						Old: "false",
+						New: "true",
+					},
+					"two": &terraform.ResourceAttrDiff{
+						Old: "true",
+						New: "false",
+					},
+					"three": &terraform.ResourceAttrDiff{
+						Old:        "true",
+						New:        "false",
+						NewRemoved: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name:   "tainted in state w/ no attr changes is still a replacement",
+			Schema: map[string]*Schema{},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"id": "someid",
+				},
+				Tainted: true,
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes:     map[string]*terraform.ResourceAttrDiff{},
+				DestroyTainted: true,
+			},
+		},
+
+		{
+			Name: "Set ForceNew only marks the changing element as ForceNew",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					ForceNew: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"ports.#": "3",
+					"ports.1": "1",
+					"ports.2": "2",
+					"ports.4": "4",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{5, 2, 1},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "1",
+						New: "1",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "2",
+						New: "2",
+					},
+					"ports.5": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "5",
+						RequiresNew: true,
+					},
+					"ports.4": &terraform.ResourceAttrDiff{
+						Old:         "4",
+						New:         "0",
+						NewRemoved:  true,
+						RequiresNew: true,
+					},
+				},
+			},
+		},
+
+		{
+			Name: "removed optional items should trigger ForceNew",
+			Schema: map[string]*Schema{
+				"description": &Schema{
+					Type:     TypeString,
+					ForceNew: true,
+					Optional: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"description": "foo",
+				},
+			},
+
+			Config: map[string]interface{}{},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"description": &terraform.ResourceAttrDiff{
+						Old:         "foo",
+						New:         "",
+						RequiresNew: true,
+						NewRemoved:  true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		// GH-7715
+		{
+			Name: "computed value for boolean field",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeBool,
+					ForceNew: true,
+					Computed: true,
+					Optional: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+			},
+
+			Config: map[string]interface{}{
+				"foo": hcl2shim.UnknownVariableValue,
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"foo": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "false",
+						NewComputed: true,
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set ForceNew marks count as ForceNew if computed",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Required: true,
+					ForceNew: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"ports.#": "3",
+					"ports.1": "1",
+					"ports.2": "2",
+					"ports.4": "4",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{hcl2shim.UnknownVariableValue, 2, 1},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.#": &terraform.ResourceAttrDiff{
+						NewComputed: true,
+						RequiresNew: true,
+					},
+				},
+			},
+		},
+
+		{
+			Name: "List with computed schema and ForceNew",
+			Schema: map[string]*Schema{
+				"config": &Schema{
+					Type:     TypeList,
+					Optional: true,
+					ForceNew: true,
+					Elem: &Schema{
+						Type: TypeString,
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"config.#": "2",
+					"config.0": "a",
+					"config.1": "b",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"config": []interface{}{hcl2shim.UnknownVariableValue, hcl2shim.UnknownVariableValue},
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"config.#": &terraform.ResourceAttrDiff{
+						Old:         "2",
+						New:         "",
+						RequiresNew: true,
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "overridden diff with a CustomizeDiff function, ForceNew not in schema",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				if err := d.SetNew("availability_zone", "bar"); err != nil {
+					return err
+				}
+				if err := d.ForceNew("availability_zone"); err != nil {
+					return err
+				}
+				return nil
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "bar",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			// NOTE: This case is technically impossible in the current
+			// implementation, because optional+computed values never show up in the
+			// diff. In the event behavior changes this test should ensure that the
+			// intended diff still shows up.
+			Name: "overridden removed attribute diff with a CustomizeDiff function, ForceNew not in schema",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				if err := d.SetNew("availability_zone", "bar"); err != nil {
+					return err
+				}
+				if err := d.ForceNew("availability_zone"); err != nil {
+					return err
+				}
+				return nil
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "bar",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+
+			Name: "overridden diff with a CustomizeDiff function, ForceNew in schema",
+			Schema: map[string]*Schema{
+				"availability_zone": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+					ForceNew: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"availability_zone": "foo",
+			},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				if err := d.SetNew("availability_zone", "bar"); err != nil {
+					return err
+				}
+				return nil
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"availability_zone": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "bar",
+						RequiresNew: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "required field with computed diff added with CustomizeDiff function",
+			Schema: map[string]*Schema{
+				"ami_id": &Schema{
+					Type:     TypeString,
+					Required: true,
+				},
+				"instance_id": &Schema{
+					Type:     TypeString,
+					Computed: true,
+				},
+			},
+
+			State: nil,
+
+			Config: map[string]interface{}{
+				"ami_id": "foo",
+			},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				if err := d.SetNew("instance_id", "bar"); err != nil {
+					return err
+				}
+				return nil
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ami_id": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+					"instance_id": &terraform.ResourceAttrDiff{
+						Old: "",
+						New: "bar",
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "Set ForceNew only marks the changing element as ForceNew - CustomizeDiffFunc edition",
+			Schema: map[string]*Schema{
+				"ports": &Schema{
+					Type:     TypeSet,
+					Optional: true,
+					Computed: true,
+					Elem:     &Schema{Type: TypeInt},
+					Set: func(a interface{}) int {
+						return a.(int)
+					},
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"ports.#": "3",
+					"ports.1": "1",
+					"ports.2": "2",
+					"ports.4": "4",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"ports": []interface{}{5, 2, 6},
+			},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				if err := d.SetNew("ports", []interface{}{5, 2, 1}); err != nil {
+					return err
+				}
+				if err := d.ForceNew("ports"); err != nil {
+					return err
+				}
+				return nil
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"ports.1": &terraform.ResourceAttrDiff{
+						Old: "1",
+						New: "1",
+					},
+					"ports.2": &terraform.ResourceAttrDiff{
+						Old: "2",
+						New: "2",
+					},
+					"ports.5": &terraform.ResourceAttrDiff{
+						Old:         "",
+						New:         "5",
+						RequiresNew: true,
+					},
+					"ports.4": &terraform.ResourceAttrDiff{
+						Old:         "4",
+						New:         "0",
+						NewRemoved:  true,
+						RequiresNew: true,
+					},
+				},
+			},
+		},
+
+		{
+			Name:   "tainted resource does not run CustomizeDiffFunc",
+			Schema: map[string]*Schema{},
+
+			State: &terraform.InstanceState{
+				ID: "someid",
+				Attributes: map[string]string{
+					"id": "someid",
+				},
+				Tainted: true,
+			},
+
+			Config: map[string]interface{}{},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				return errors.New("diff customization should not have run")
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes:     map[string]*terraform.ResourceAttrDiff{},
+				DestroyTainted: true,
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "NewComputed based on a conditional with CustomizeDiffFunc",
+			Schema: map[string]*Schema{
+				"etag": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+				"version_id": &Schema{
+					Type:     TypeString,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"etag":       "foo",
+					"version_id": "1",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"etag": "bar",
+			},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				if d.HasChange("etag") {
+					d.SetNewComputed("version_id")
+				}
+				return nil
+			},
+
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"etag": &terraform.ResourceAttrDiff{
+						Old: "foo",
+						New: "bar",
+					},
+					"version_id": &terraform.ResourceAttrDiff{
+						Old:         "1",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+
+			Err: false,
+		},
+
+		{
+			Name: "vetoing a diff",
+			Schema: map[string]*Schema{
+				"foo": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"foo": "bar",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"foo": "baz",
+			},
+
+			CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
+				return fmt.Errorf("diff vetoed")
+			},
+
+			Err: true,
+		},
+
+		// A lot of resources currently depended on using the empty string as a
+		// nil/unset value.
+		{
+			Name: "optional, computed, empty string",
+			Schema: map[string]*Schema{
+				"attr": &Schema{
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"attr": "bar",
+				},
+			},
+
+			Config: map[string]interface{}{
+				"attr": "",
+			},
+		},
+
+		{
+			Name: "optional, computed, empty string should not crash in CustomizeDiff",
+			Schema: map[string]*Schema{
+				"unrelated_set": {
+					Type:     TypeSet,
+					Optional: true,
+					Elem:     &Schema{Type: TypeString},
+				},
+				"stream_enabled": {
+					Type:     TypeBool,
+					Optional: true,
+				},
+				"stream_view_type": {
+					Type:     TypeString,
+					Optional: true,
+					Computed: true,
+				},
+			},
+
+			State: &terraform.InstanceState{
+				ID: "id",
+				Attributes: map[string]string{
+					"unrelated_set.#":  "0",
+					"stream_enabled":   "true",
+					"stream_view_type": "KEYS_ONLY",
+				},
+			},
+			Config: map[string]interface{}{
+				"stream_enabled":   false,
+				"stream_view_type": "",
+			},
+			CustomizeDiff: func(diff *ResourceDiff, v interface{}) error {
+				v, ok := diff.GetOk("unrelated_set")
+				if ok {
+					return fmt.Errorf("Didn't expect unrelated_set: %#v", v)
+				}
+				return nil
+			},
+			Diff: &terraform.InstanceDiff{
+				Attributes: map[string]*terraform.ResourceAttrDiff{
+					"stream_enabled": {
+						Old: "true",
+						New: "false",
+					},
+				},
+			},
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			c := terraform.NewResourceConfigRaw(tc.Config)
+
+			{
+				d, err := schemaMap(tc.Schema).Diff(tc.State, c, tc.CustomizeDiff, nil, false)
+				if err != nil != tc.Err {
+					t.Fatalf("err: %s", err)
+				}
+				if !cmp.Equal(d, tc.Diff, equateEmpty) {
+					t.Fatal(cmp.Diff(d, tc.Diff, equateEmpty))
+				}
+			}
+			// up to here is already tested in helper/schema; we're just
+			// verify that we haven't broken any tests in transition.
+
+			// create a schema from the schemaMap
+			testSchema := resourceSchemaToBlock(tc.Schema)
+
+			// get our initial state cty.Value
+			stateVal, err := StateValueFromInstanceState(tc.State, testSchema.ImpliedType())
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			// this is the desired cty.Value from the configuration
+			configVal := hcl2shim.HCL2ValueFromConfigValue(c.Config)
+
+			// verify that we can round-trip the config
+			origConfig := hcl2shim.ConfigValueFromHCL2(configVal)
+			if !cmp.Equal(c.Config, origConfig, equateEmpty) {
+				t.Fatal(cmp.Diff(c.Config, origConfig, equateEmpty))
+			}
+
+			// make sure our config conforms precisely to the schema
+			configVal, err = testSchema.CoerceValue(configVal)
+			if err != nil {
+				t.Fatal(tfdiags.FormatError(err))
+			}
+
+			// The new API requires returning the desired state rather than a
+			// diff, so we need to verify that we can combine the state and
+			// diff and recreate a new state.
+
+			// now verify that we can create diff, using the new config and state values
+			// customize isn't run on tainted resources
+			tainted := tc.State != nil && tc.State.Tainted
+			if tainted {
+				tc.CustomizeDiff = nil
+			}
+
+			res := &Resource{Schema: tc.Schema}
+
+			d, err := diffFromValues(stateVal, configVal, res, tc.CustomizeDiff)
+			if err != nil {
+				if !tc.Err {
+					t.Fatal(err)
+				}
+			}
+
+			// In a real "apply" operation there would be no unknown values,
+			// so for tests containing unknowns we'll stop here: the steps
+			// after this point apply only to the apply phase.
+			if !configVal.IsWhollyKnown() {
+				return
+			}
+
+			// our diff function can't set DestroyTainted, but match the
+			// expected value here for the test fixtures
+			if tainted {
+				if d == nil {
+					d = &terraform.InstanceDiff{}
+				}
+				d.DestroyTainted = true
+			}
+
+			if eq, _ := d.Same(tc.Diff); !eq {
+				t.Fatal(cmp.Diff(d, tc.Diff))
+			}
+
+		})
+	}
+}
+
+func resourceSchemaToBlock(s map[string]*Schema) *configschema.Block {
+	return (&Resource{Schema: s}).CoreConfigSchema()
+}
+
+func TestRemoveConfigUnknowns(t *testing.T) {
+	cfg := map[string]interface{}{
+		"id": "74D93920-ED26-11E3-AC10-0800200C9A66",
+		"route_rules": []interface{}{
+			map[string]interface{}{
+				"cidr_block":        "74D93920-ED26-11E3-AC10-0800200C9A66",
+				"destination":       "0.0.0.0/0",
+				"destination_type":  "CIDR_BLOCK",
+				"network_entity_id": "1",
+			},
+			map[string]interface{}{
+				"cidr_block":       "74D93920-ED26-11E3-AC10-0800200C9A66",
+				"destination":      "0.0.0.0/0",
+				"destination_type": "CIDR_BLOCK",
+				"sub_block": []interface{}{
+					map[string]interface{}{
+						"computed": "74D93920-ED26-11E3-AC10-0800200C9A66",
+					},
+				},
+			},
+		},
+	}
+
+	expect := map[string]interface{}{
+		"route_rules": []interface{}{
+			map[string]interface{}{
+				"destination":       "0.0.0.0/0",
+				"destination_type":  "CIDR_BLOCK",
+				"network_entity_id": "1",
+			},
+			map[string]interface{}{
+				"destination":      "0.0.0.0/0",
+				"destination_type": "CIDR_BLOCK",
+				"sub_block": []interface{}{
+					map[string]interface{}{},
+				},
+			},
+		},
+	}
+
+	removeConfigUnknowns(cfg)
+
+	if !reflect.DeepEqual(cfg, expect) {
+		t.Fatalf("\nexpected: %#v\ngot:      %#v", expect, cfg)
+	}
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/testing.go b/v1.5.7/internal/legacy/helper/schema/testing.go
new file mode 100644
index 0000000..5958e6f
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/testing.go
@@ -0,0 +1,31 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/legacy/terraform"
+)
+
+// TestResourceDataRaw creates a ResourceData from a raw configuration map.
+func TestResourceDataRaw(
+	t *testing.T, schema map[string]*Schema, raw map[string]interface{}) *ResourceData {
+	t.Helper()
+
+	c := terraform.NewResourceConfigRaw(raw)
+
+	sm := schemaMap(schema)
+	diff, err := sm.Diff(nil, c, nil, nil, true)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	result, err := sm.Data(nil, diff)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	return result
+}
diff --git a/v1.5.7/internal/legacy/helper/schema/valuetype.go b/v1.5.7/internal/legacy/helper/schema/valuetype.go
new file mode 100644
index 0000000..70e73cf
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/valuetype.go
@@ -0,0 +1,24 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package schema
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=ValueType valuetype.go
+
+// ValueType is an enum of the type that can be represented by a schema.
+type ValueType int
+
+const (
+	TypeInvalid ValueType = iota
+	TypeBool
+	TypeInt
+	TypeFloat
+	TypeString
+	TypeList
+	TypeMap
+	TypeSet
+	typeObject
+)
+
+// NOTE: ValueType has more functions defined on it in schema.go. We can't
+// put them here because we reference other files.
diff --git a/v1.5.7/internal/legacy/helper/schema/valuetype_string.go b/v1.5.7/internal/legacy/helper/schema/valuetype_string.go
new file mode 100644
index 0000000..914ca32
--- /dev/null
+++ b/v1.5.7/internal/legacy/helper/schema/valuetype_string.go
@@ -0,0 +1,31 @@
+// Code generated by "stringer -type=ValueType valuetype.go"; DO NOT EDIT.
+
+package schema
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[TypeInvalid-0]
+	_ = x[TypeBool-1]
+	_ = x[TypeInt-2]
+	_ = x[TypeFloat-3]
+	_ = x[TypeString-4]
+	_ = x[TypeList-5]
+	_ = x[TypeMap-6]
+	_ = x[TypeSet-7]
+	_ = x[typeObject-8]
+}
+
+const _ValueType_name = "TypeInvalidTypeBoolTypeIntTypeFloatTypeStringTypeListTypeMapTypeSettypeObject"
+
+var _ValueType_index = [...]uint8{0, 11, 19, 26, 35, 45, 53, 60, 67, 77}
+
+func (i ValueType) String() string {
+	if i < 0 || i >= ValueType(len(_ValueType_index)-1) {
+		return "ValueType(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _ValueType_name[_ValueType_index[i]:_ValueType_index[i+1]]
+}
diff --git a/v1.5.7/internal/legacy/terraform/context_components.go b/v1.5.7/internal/legacy/terraform/context_components.go
new file mode 100644
index 0000000..b8176dd
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/context_components.go
@@ -0,0 +1,68 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+)
+
+// contextComponentFactory is the interface that Context uses
+// to initialize various components such as providers and provisioners.
+// This factory gets more information than the raw maps using to initialize
+// a Context. This information is used for debugging.
+type contextComponentFactory interface {
+	// ResourceProvider creates a new ResourceProvider with the given type.
+	ResourceProvider(typ addrs.Provider) (providers.Interface, error)
+	ResourceProviders() []string
+
+	// ResourceProvisioner creates a new ResourceProvisioner with the given
+	// type.
+	ResourceProvisioner(typ string) (provisioners.Interface, error)
+	ResourceProvisioners() []string
+}
+
+// basicComponentFactory just calls a factory from a map directly.
+type basicComponentFactory struct {
+	providers    map[addrs.Provider]providers.Factory
+	provisioners map[string]ProvisionerFactory
+}
+
+func (c *basicComponentFactory) ResourceProviders() []string {
+	var result []string
+	for k := range c.providers {
+		result = append(result, k.String())
+	}
+	return result
+}
+
+func (c *basicComponentFactory) ResourceProvisioners() []string {
+	var result []string
+	for k := range c.provisioners {
+		result = append(result, k)
+	}
+
+	return result
+}
+
+func (c *basicComponentFactory) ResourceProvider(typ addrs.Provider) (providers.Interface, error) {
+	f, ok := c.providers[typ]
+	if !ok {
+		return nil, fmt.Errorf("unknown provider %q", typ.String())
+	}
+
+	return f()
+}
+
+func (c *basicComponentFactory) ResourceProvisioner(typ string) (provisioners.Interface, error) {
+	f, ok := c.provisioners[typ]
+	if !ok {
+		return nil, fmt.Errorf("unknown provisioner %q", typ)
+	}
+
+	return f()
+}
diff --git a/v1.5.7/internal/legacy/terraform/diff.go b/v1.5.7/internal/legacy/terraform/diff.go
new file mode 100644
index 0000000..8ab24d8
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/diff.go
@@ -0,0 +1,1454 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"log"
+	"reflect"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/mitchellh/copystructure"
+)
+
+// DiffChangeType is an enum with the kind of changes a diff has planned.
+type DiffChangeType byte
+
+const (
+	DiffInvalid DiffChangeType = iota
+	DiffNone
+	DiffCreate
+	DiffUpdate
+	DiffDestroy
+	DiffDestroyCreate
+
+	// DiffRefresh is only used in the UI for displaying diffs.
+	// Managed resource reads never appear in plan, and when data source
+	// reads appear they are represented as DiffCreate in core before
+	// transforming to DiffRefresh in the UI layer.
+	DiffRefresh // TODO: Actually use DiffRefresh in core too, for less confusion
+)
+
+// multiVal matches the index key to a flatmapped set, list or map
+var multiVal = regexp.MustCompile(`\.(#|%)$`)
+
+// Diff tracks the changes that are necessary to apply a configuration
+// to an existing infrastructure.
+type Diff struct {
+	// Modules contains all the modules that have a diff
+	Modules []*ModuleDiff
+}
+
+// Prune cleans out unused structures in the diff without affecting
+// the behavior of the diff at all.
+//
+// This is not safe to call concurrently. This is safe to call on a
+// nil Diff.
+func (d *Diff) Prune() {
+	if d == nil {
+		return
+	}
+
+	// Prune all empty modules
+	newModules := make([]*ModuleDiff, 0, len(d.Modules))
+	for _, m := range d.Modules {
+		// If the module isn't empty, we keep it
+		if !m.Empty() {
+			newModules = append(newModules, m)
+		}
+	}
+	if len(newModules) == 0 {
+		newModules = nil
+	}
+	d.Modules = newModules
+}
+
+// AddModule adds the module with the given path to the diff.
+//
+// This should be the preferred method to add module diffs since it
+// allows us to optimize lookups later as well as control sorting.
+func (d *Diff) AddModule(path addrs.ModuleInstance) *ModuleDiff {
+	// Lower the new-style address into a legacy-style address.
+	// This requires that none of the steps have instance keys, which is
+	// true for all addresses at the time of implementing this because
+	// "count" and "for_each" are not yet implemented for modules.
+	legacyPath := make([]string, len(path))
+	for i, step := range path {
+		if step.InstanceKey != addrs.NoKey {
+			// FIXME: Once the rest of Terraform is ready to use count and
+			// for_each, remove all of this and just write the addrs.ModuleInstance
+			// value itself into the ModuleState.
+			panic("diff cannot represent modules with count or for_each keys")
+		}
+
+		legacyPath[i] = step.Name
+	}
+
+	m := &ModuleDiff{Path: legacyPath}
+	m.init()
+	d.Modules = append(d.Modules, m)
+	return m
+}
+
+// ModuleByPath is used to lookup the module diff for the given path.
+// This should be the preferred lookup mechanism as it allows for future
+// lookup optimizations.
+func (d *Diff) ModuleByPath(path addrs.ModuleInstance) *ModuleDiff {
+	if d == nil {
+		return nil
+	}
+	for _, mod := range d.Modules {
+		if mod.Path == nil {
+			panic("missing module path")
+		}
+		modPath := normalizeModulePath(mod.Path)
+		if modPath.String() == path.String() {
+			return mod
+		}
+	}
+	return nil
+}
+
+// RootModule returns the ModuleState for the root module
+func (d *Diff) RootModule() *ModuleDiff {
+	root := d.ModuleByPath(addrs.RootModuleInstance)
+	if root == nil {
+		panic("missing root module")
+	}
+	return root
+}
+
+// Empty returns true if the diff has no changes.
+func (d *Diff) Empty() bool {
+	if d == nil {
+		return true
+	}
+
+	for _, m := range d.Modules {
+		if !m.Empty() {
+			return false
+		}
+	}
+
+	return true
+}
+
+// Equal compares two diffs for exact equality.
+//
+// This is different from the Same comparison that is supported which
+// checks for operation equality taking into account computed values. Equal
+// instead checks for exact equality.
+func (d *Diff) Equal(d2 *Diff) bool {
+	// If one is nil, they must both be nil
+	if d == nil || d2 == nil {
+		return d == d2
+	}
+
+	// Sort the modules
+	sort.Sort(moduleDiffSort(d.Modules))
+	sort.Sort(moduleDiffSort(d2.Modules))
+
+	// Copy since we have to modify the module destroy flag to false so
+	// we don't compare that. TODO: delete this when we get rid of the
+	// destroy flag on modules.
+	dCopy := d.DeepCopy()
+	d2Copy := d2.DeepCopy()
+	for _, m := range dCopy.Modules {
+		m.Destroy = false
+	}
+	for _, m := range d2Copy.Modules {
+		m.Destroy = false
+	}
+
+	// Use DeepEqual
+	return reflect.DeepEqual(dCopy, d2Copy)
+}
+
+// DeepCopy performs a deep copy of all parts of the Diff, making the
+// resulting Diff safe to use without modifying this one.
+func (d *Diff) DeepCopy() *Diff {
+	copy, err := copystructure.Config{Lock: true}.Copy(d)
+	if err != nil {
+		panic(err)
+	}
+
+	return copy.(*Diff)
+}
+
+func (d *Diff) String() string {
+	var buf bytes.Buffer
+
+	keys := make([]string, 0, len(d.Modules))
+	lookup := make(map[string]*ModuleDiff)
+	for _, m := range d.Modules {
+		addr := normalizeModulePath(m.Path)
+		key := addr.String()
+		keys = append(keys, key)
+		lookup[key] = m
+	}
+	sort.Strings(keys)
+
+	for _, key := range keys {
+		m := lookup[key]
+		mStr := m.String()
+
+		// If we're the root module, we just write the output directly.
+		if reflect.DeepEqual(m.Path, rootModulePath) {
+			buf.WriteString(mStr + "\n")
+			continue
+		}
+
+		buf.WriteString(fmt.Sprintf("%s:\n", key))
+
+		s := bufio.NewScanner(strings.NewReader(mStr))
+		for s.Scan() {
+			buf.WriteString(fmt.Sprintf("  %s\n", s.Text()))
+		}
+	}
+
+	return strings.TrimSpace(buf.String())
+}
+
+func (d *Diff) init() {
+	if d.Modules == nil {
+		rootDiff := &ModuleDiff{Path: rootModulePath}
+		d.Modules = []*ModuleDiff{rootDiff}
+	}
+	for _, m := range d.Modules {
+		m.init()
+	}
+}
+
+// ModuleDiff tracks the differences between resources to apply within
+// a single module.
+type ModuleDiff struct {
+	Path      []string
+	Resources map[string]*InstanceDiff
+	Destroy   bool // Set only by the destroy plan
+}
+
+func (d *ModuleDiff) init() {
+	if d.Resources == nil {
+		d.Resources = make(map[string]*InstanceDiff)
+	}
+	for _, r := range d.Resources {
+		r.init()
+	}
+}
+
+// ChangeType returns the type of changes that the diff for this
+// module includes.
+//
+// At a module level, this will only be DiffNone, DiffUpdate, DiffDestroy, or
+// DiffCreate. If an instance within the module has a DiffDestroyCreate
+// then this will register as a DiffCreate for a module.
+func (d *ModuleDiff) ChangeType() DiffChangeType {
+	result := DiffNone
+	for _, r := range d.Resources {
+		change := r.ChangeType()
+		switch change {
+		case DiffCreate, DiffDestroy:
+			if result == DiffNone {
+				result = change
+			}
+		case DiffDestroyCreate, DiffUpdate:
+			result = DiffUpdate
+		}
+	}
+
+	return result
+}
+
+// Empty returns true if the diff has no changes within this module.
+func (d *ModuleDiff) Empty() bool {
+	if d.Destroy {
+		return false
+	}
+
+	if len(d.Resources) == 0 {
+		return true
+	}
+
+	for _, rd := range d.Resources {
+		if !rd.Empty() {
+			return false
+		}
+	}
+
+	return true
+}
+
+// Instances returns the instance diffs for the id given. This can return
+// multiple instance diffs if there are counts within the resource.
+func (d *ModuleDiff) Instances(id string) []*InstanceDiff {
+	var result []*InstanceDiff
+	for k, diff := range d.Resources {
+		if k == id || strings.HasPrefix(k, id+".") {
+			if !diff.Empty() {
+				result = append(result, diff)
+			}
+		}
+	}
+
+	return result
+}
+
+// IsRoot says whether or not this module diff is for the root module.
+func (d *ModuleDiff) IsRoot() bool {
+	return reflect.DeepEqual(d.Path, rootModulePath)
+}
+
+// String outputs the diff in a long but command-line friendly output
+// format that users can read to quickly inspect a diff.
+func (d *ModuleDiff) String() string {
+	var buf bytes.Buffer
+
+	names := make([]string, 0, len(d.Resources))
+	for name, _ := range d.Resources {
+		names = append(names, name)
+	}
+	sort.Strings(names)
+
+	for _, name := range names {
+		rdiff := d.Resources[name]
+
+		crud := "UPDATE"
+		switch {
+		case rdiff.RequiresNew() && (rdiff.GetDestroy() || rdiff.GetDestroyTainted()):
+			crud = "DESTROY/CREATE"
+		case rdiff.GetDestroy() || rdiff.GetDestroyDeposed():
+			crud = "DESTROY"
+		case rdiff.RequiresNew():
+			crud = "CREATE"
+		}
+
+		extra := ""
+		if !rdiff.GetDestroy() && rdiff.GetDestroyDeposed() {
+			extra = " (deposed only)"
+		}
+
+		buf.WriteString(fmt.Sprintf(
+			"%s: %s%s\n",
+			crud,
+			name,
+			extra))
+
+		keyLen := 0
+		rdiffAttrs := rdiff.CopyAttributes()
+		keys := make([]string, 0, len(rdiffAttrs))
+		for key, _ := range rdiffAttrs {
+			if key == "id" {
+				continue
+			}
+
+			keys = append(keys, key)
+			if len(key) > keyLen {
+				keyLen = len(key)
+			}
+		}
+		sort.Strings(keys)
+
+		for _, attrK := range keys {
+			attrDiff, _ := rdiff.GetAttribute(attrK)
+
+			v := attrDiff.New
+			u := attrDiff.Old
+			if attrDiff.NewComputed {
+				v = "<computed>"
+			}
+
+			if attrDiff.Sensitive {
+				u = "<sensitive>"
+				v = "<sensitive>"
+			}
+
+			updateMsg := ""
+			if attrDiff.RequiresNew {
+				updateMsg = " (forces new resource)"
+			} else if attrDiff.Sensitive {
+				updateMsg = " (attribute changed)"
+			}
+
+			buf.WriteString(fmt.Sprintf(
+				"  %s:%s %#v => %#v%s\n",
+				attrK,
+				strings.Repeat(" ", keyLen-len(attrK)),
+				u,
+				v,
+				updateMsg))
+		}
+	}
+
+	return buf.String()
+}
+
+// InstanceDiff is the diff of a resource from some state to another.
+type InstanceDiff struct {
+	mu             sync.Mutex
+	Attributes     map[string]*ResourceAttrDiff
+	Destroy        bool
+	DestroyDeposed bool
+	DestroyTainted bool
+
+	// Meta is a simple K/V map that is stored in a diff and persisted to
+	// plans but otherwise is completely ignored by Terraform core. It is
+	// meant to be used for additional data a resource may want to pass through.
+	// The value here must only contain Go primitives and collections.
+	Meta map[string]interface{}
+}
+
+func (d *InstanceDiff) Lock()   { d.mu.Lock() }
+func (d *InstanceDiff) Unlock() { d.mu.Unlock() }
+
+// ApplyToValue merges the receiver into the given base value, returning a
+// new value that incorporates the planned changes. The given value must
+// conform to the given schema, or this method will panic.
+//
+// This method is intended for shimming old subsystems that still use this
+// legacy diff type to work with the new-style types.
+func (d *InstanceDiff) ApplyToValue(base cty.Value, schema *configschema.Block) (cty.Value, error) {
+	// Create an InstanceState attributes from our existing state.
+	// We can use this to more easily apply the diff changes.
+	attrs := hcl2shim.FlatmapValueFromHCL2(base)
+	applied, err := d.Apply(attrs, schema)
+	if err != nil {
+		return base, err
+	}
+
+	val, err := hcl2shim.HCL2ValueFromFlatmap(applied, schema.ImpliedType())
+	if err != nil {
+		return base, err
+	}
+
+	return schema.CoerceValue(val)
+}
+
+// Apply applies the diff to the provided flatmapped attributes,
+// returning the new instance attributes.
+//
+// This method is intended for shimming old subsystems that still use this
+// legacy diff type to work with the new-style types.
+func (d *InstanceDiff) Apply(attrs map[string]string, schema *configschema.Block) (map[string]string, error) {
+	// We always build a new value here, even if the given diff is "empty",
+	// because we might be planning to create a new instance that happens
+	// to have no attributes set, and so we want to produce an empty object
+	// rather than just echoing back the null old value.
+	if attrs == nil {
+		attrs = map[string]string{}
+	}
+
+	// Rather applying the diff to mutate the attrs, we'll copy new values into
+	// here to avoid the possibility of leaving stale values.
+	result := map[string]string{}
+
+	if d.Destroy || d.DestroyDeposed || d.DestroyTainted {
+		return result, nil
+	}
+
+	return d.applyBlockDiff(nil, attrs, schema)
+}
+
+func (d *InstanceDiff) applyBlockDiff(path []string, attrs map[string]string, schema *configschema.Block) (map[string]string, error) {
+	result := map[string]string{}
+	name := ""
+	if len(path) > 0 {
+		name = path[len(path)-1]
+	}
+
+	// localPrefix is used to build the local result map
+	localPrefix := ""
+	if name != "" {
+		localPrefix = name + "."
+	}
+
+	// iterate over the schema rather than the attributes, so we can handle
+	// different block types separately from plain attributes
+	for n, attrSchema := range schema.Attributes {
+		var err error
+		newAttrs, err := d.applyAttrDiff(append(path, n), attrs, attrSchema)
+
+		if err != nil {
+			return result, err
+		}
+
+		for k, v := range newAttrs {
+			result[localPrefix+k] = v
+		}
+	}
+
+	blockPrefix := strings.Join(path, ".")
+	if blockPrefix != "" {
+		blockPrefix += "."
+	}
+	for n, block := range schema.BlockTypes {
+		// we need to find the set of all keys that traverse this block
+		candidateKeys := map[string]bool{}
+		blockKey := blockPrefix + n + "."
+		localBlockPrefix := localPrefix + n + "."
+
+		// we can only trust the diff for sets, since the path changes, so don't
+		// count existing values as candidate keys. If it turns out we're
+		// keeping the attributes, we will catch it down below with "keepBlock"
+		// after we check the set count.
+		if block.Nesting != configschema.NestingSet {
+			for k := range attrs {
+				if strings.HasPrefix(k, blockKey) {
+					nextDot := strings.Index(k[len(blockKey):], ".")
+					if nextDot < 0 {
+						continue
+					}
+					nextDot += len(blockKey)
+					candidateKeys[k[len(blockKey):nextDot]] = true
+				}
+			}
+		}
+
+		for k, diff := range d.Attributes {
+			// helper/schema should not insert nil diff values, but don't panic
+			// if it does.
+			if diff == nil {
+				continue
+			}
+
+			if strings.HasPrefix(k, blockKey) {
+				nextDot := strings.Index(k[len(blockKey):], ".")
+				if nextDot < 0 {
+					continue
+				}
+
+				if diff.NewRemoved {
+					continue
+				}
+
+				nextDot += len(blockKey)
+				candidateKeys[k[len(blockKey):nextDot]] = true
+			}
+		}
+
+		// check each set candidate to see if it was removed.
+		// we need to do this, because when entire sets are removed, they may
+		// have the wrong key, and ony show diffs going to ""
+		if block.Nesting == configschema.NestingSet {
+			for k := range candidateKeys {
+				indexPrefix := strings.Join(append(path, n, k), ".") + "."
+				keep := false
+				// now check each set element to see if it's a new diff, or one
+				// that we're dropping. Since we're only applying the "New"
+				// portion of the set, we can ignore diffs that only contain "Old"
+				for attr, diff := range d.Attributes {
+					// helper/schema should not insert nil diff values, but don't panic
+					// if it does.
+					if diff == nil {
+						continue
+					}
+
+					if !strings.HasPrefix(attr, indexPrefix) {
+						continue
+					}
+
+					// check for empty "count" keys
+					if (strings.HasSuffix(attr, ".#") || strings.HasSuffix(attr, ".%")) && diff.New == "0" {
+						continue
+					}
+
+					// removed items don't count either
+					if diff.NewRemoved {
+						continue
+					}
+
+					// this must be a diff to keep
+					keep = true
+					break
+				}
+				if !keep {
+					delete(candidateKeys, k)
+				}
+			}
+		}
+
+		for k := range candidateKeys {
+			newAttrs, err := d.applyBlockDiff(append(path, n, k), attrs, &block.Block)
+			if err != nil {
+				return result, err
+			}
+
+			for attr, v := range newAttrs {
+				result[localBlockPrefix+attr] = v
+			}
+		}
+
+		keepBlock := true
+		// check this block's count diff directly first, since we may not
+		// have candidates because it was removed and only set to "0"
+		if diff, ok := d.Attributes[blockKey+"#"]; ok {
+			if diff.New == "0" || diff.NewRemoved {
+				keepBlock = false
+			}
+		}
+
+		// if there was no diff at all, then we need to keep the block attributes
+		if len(candidateKeys) == 0 && keepBlock {
+			for k, v := range attrs {
+				if strings.HasPrefix(k, blockKey) {
+					// we need the key relative to this block, so remove the
+					// entire prefix, then re-insert the block name.
+					localKey := localBlockPrefix + k[len(blockKey):]
+					result[localKey] = v
+				}
+			}
+		}
+
+		countAddr := strings.Join(append(path, n, "#"), ".")
+		if countDiff, ok := d.Attributes[countAddr]; ok {
+			if countDiff.NewComputed {
+				result[localBlockPrefix+"#"] = hcl2shim.UnknownVariableValue
+			} else {
+				result[localBlockPrefix+"#"] = countDiff.New
+
+				// While sets are complete, list are not, and we may not have all the
+				// information to track removals. If the list was truncated, we need to
+				// remove the extra items from the result.
+				if block.Nesting == configschema.NestingList &&
+					countDiff.New != "" && countDiff.New != hcl2shim.UnknownVariableValue {
+					length, _ := strconv.Atoi(countDiff.New)
+					for k := range result {
+						if !strings.HasPrefix(k, localBlockPrefix) {
+							continue
+						}
+
+						index := k[len(localBlockPrefix):]
+						nextDot := strings.Index(index, ".")
+						if nextDot < 1 {
+							continue
+						}
+						index = index[:nextDot]
+						i, err := strconv.Atoi(index)
+						if err != nil {
+							// this shouldn't happen since we added these
+							// ourself, but make note of it just in case.
+							log.Printf("[ERROR] bad list index in %q: %s", k, err)
+							continue
+						}
+						if i >= length {
+							delete(result, k)
+						}
+					}
+				}
+			}
+		} else if origCount, ok := attrs[countAddr]; ok && keepBlock {
+			result[localBlockPrefix+"#"] = origCount
+		} else {
+			result[localBlockPrefix+"#"] = countFlatmapContainerValues(localBlockPrefix+"#", result)
+		}
+	}
+
+	return result, nil
+}
+
+func (d *InstanceDiff) applyAttrDiff(path []string, attrs map[string]string, attrSchema *configschema.Attribute) (map[string]string, error) {
+	ty := attrSchema.Type
+	switch {
+	case ty.IsListType(), ty.IsTupleType(), ty.IsMapType():
+		return d.applyCollectionDiff(path, attrs, attrSchema)
+	case ty.IsSetType():
+		return d.applySetDiff(path, attrs, attrSchema)
+	default:
+		return d.applySingleAttrDiff(path, attrs, attrSchema)
+	}
+}
+
+func (d *InstanceDiff) applySingleAttrDiff(path []string, attrs map[string]string, attrSchema *configschema.Attribute) (map[string]string, error) {
+	currentKey := strings.Join(path, ".")
+
+	attr := path[len(path)-1]
+
+	result := map[string]string{}
+	diff := d.Attributes[currentKey]
+	old, exists := attrs[currentKey]
+
+	if diff != nil && diff.NewComputed {
+		result[attr] = hcl2shim.UnknownVariableValue
+		return result, nil
+	}
+
+	// "id" must exist and not be an empty string, or it must be unknown.
+	// This only applied to top-level "id" fields.
+	if attr == "id" && len(path) == 1 {
+		if old == "" {
+			result[attr] = hcl2shim.UnknownVariableValue
+		} else {
+			result[attr] = old
+		}
+		return result, nil
+	}
+
+	// attribute diffs are sometimes missed, so assume no diff means keep the
+	// old value
+	if diff == nil {
+		if exists {
+			result[attr] = old
+		} else {
+			// We need required values, so set those with an empty value. It
+			// must be set in the config, since if it were missing it would have
+			// failed validation.
+			if attrSchema.Required {
+				// we only set a missing string here, since bool or number types
+				// would have distinct zero value which shouldn't have been
+				// lost.
+				if attrSchema.Type == cty.String {
+					result[attr] = ""
+				}
+			}
+		}
+		return result, nil
+	}
+
+	// check for missmatched diff values
+	if exists &&
+		old != diff.Old &&
+		old != hcl2shim.UnknownVariableValue &&
+		diff.Old != hcl2shim.UnknownVariableValue {
+		return result, fmt.Errorf("diff apply conflict for %s: diff expects %q, but prior value has %q", attr, diff.Old, old)
+	}
+
+	if diff.NewRemoved {
+		// don't set anything in the new value
+		return map[string]string{}, nil
+	}
+
+	if diff.Old == diff.New && diff.New == "" {
+		// this can only be a valid empty string
+		if attrSchema.Type == cty.String {
+			result[attr] = ""
+		}
+		return result, nil
+	}
+
+	if attrSchema.Computed && diff.NewComputed {
+		result[attr] = hcl2shim.UnknownVariableValue
+		return result, nil
+	}
+
+	result[attr] = diff.New
+
+	return result, nil
+}
+
+func (d *InstanceDiff) applyCollectionDiff(path []string, attrs map[string]string, attrSchema *configschema.Attribute) (map[string]string, error) {
+	result := map[string]string{}
+
+	prefix := ""
+	if len(path) > 1 {
+		prefix = strings.Join(path[:len(path)-1], ".") + "."
+	}
+
+	name := ""
+	if len(path) > 0 {
+		name = path[len(path)-1]
+	}
+
+	currentKey := prefix + name
+
+	// check the index first for special handling
+	for k, diff := range d.Attributes {
+		// check the index value, which can be set, and 0
+		if k == currentKey+".#" || k == currentKey+".%" || k == currentKey {
+			if diff.NewRemoved {
+				return result, nil
+			}
+
+			if diff.NewComputed {
+				result[k[len(prefix):]] = hcl2shim.UnknownVariableValue
+				return result, nil
+			}
+
+			// do what the diff tells us to here, so that it's consistent with applies
+			if diff.New == "0" {
+				result[k[len(prefix):]] = "0"
+				return result, nil
+			}
+		}
+	}
+
+	// collect all the keys from the diff and the old state
+	noDiff := true
+	keys := map[string]bool{}
+	for k := range d.Attributes {
+		if !strings.HasPrefix(k, currentKey+".") {
+			continue
+		}
+		noDiff = false
+		keys[k] = true
+	}
+
+	noAttrs := true
+	for k := range attrs {
+		if !strings.HasPrefix(k, currentKey+".") {
+			continue
+		}
+		noAttrs = false
+		keys[k] = true
+	}
+
+	// If there's no diff and no attrs, then there's no value at all.
+	// This prevents an unexpected zero-count attribute in the attributes.
+	if noDiff && noAttrs {
+		return result, nil
+	}
+
+	idx := "#"
+	if attrSchema.Type.IsMapType() {
+		idx = "%"
+	}
+
+	for k := range keys {
+		// generate an schema placeholder for the values
+		elSchema := &configschema.Attribute{
+			Type: attrSchema.Type.ElementType(),
+		}
+
+		res, err := d.applySingleAttrDiff(append(path, k[len(currentKey)+1:]), attrs, elSchema)
+		if err != nil {
+			return result, err
+		}
+
+		for k, v := range res {
+			result[name+"."+k] = v
+		}
+	}
+
+	// Just like in nested list blocks, for simple lists we may need to fill in
+	// missing empty strings.
+	countKey := name + "." + idx
+	count := result[countKey]
+	length, _ := strconv.Atoi(count)
+
+	if count != "" && count != hcl2shim.UnknownVariableValue &&
+		attrSchema.Type.Equals(cty.List(cty.String)) {
+		// insert empty strings into missing indexes
+		for i := 0; i < length; i++ {
+			key := fmt.Sprintf("%s.%d", name, i)
+			if _, ok := result[key]; !ok {
+				result[key] = ""
+			}
+		}
+	}
+
+	// now check for truncation in any type of list
+	if attrSchema.Type.IsListType() {
+		for key := range result {
+			if key == countKey {
+				continue
+			}
+
+			if len(key) <= len(name)+1 {
+				// not sure what this is, but don't panic
+				continue
+			}
+
+			index := key[len(name)+1:]
+
+			// It is possible to have nested sets or maps, so look for another dot
+			dot := strings.Index(index, ".")
+			if dot > 0 {
+				index = index[:dot]
+			}
+
+			// This shouldn't have any more dots, since the element type is only string.
+			num, err := strconv.Atoi(index)
+			if err != nil {
+				log.Printf("[ERROR] bad list index in %q: %s", currentKey, err)
+				continue
+			}
+
+			if num >= length {
+				delete(result, key)
+			}
+		}
+	}
+
+	// Fill in the count value if it wasn't present in the diff for some reason,
+	// or if there is no count at all.
+	_, countDiff := d.Attributes[countKey]
+	if result[countKey] == "" || (!countDiff && len(keys) != len(result)) {
+		result[countKey] = countFlatmapContainerValues(countKey, result)
+	}
+
+	return result, nil
+}
+
+func (d *InstanceDiff) applySetDiff(path []string, attrs map[string]string, attrSchema *configschema.Attribute) (map[string]string, error) {
+	// We only need this special behavior for sets of object.
+	if !attrSchema.Type.ElementType().IsObjectType() {
+		// The normal collection apply behavior will work okay for this one, then.
+		return d.applyCollectionDiff(path, attrs, attrSchema)
+	}
+
+	// When we're dealing with a set of an object type we actually want to
+	// use our normal _block type_ apply behaviors, so we'll construct ourselves
+	// a synthetic schema that treats the object type as a block type and
+	// then delegate to our block apply method.
+	synthSchema := &configschema.Block{
+		Attributes: make(map[string]*configschema.Attribute),
+	}
+
+	for name, ty := range attrSchema.Type.ElementType().AttributeTypes() {
+		// We can safely make everything into an attribute here because in the
+		// event that there are nested set attributes we'll end up back in
+		// here again recursively and can then deal with the next level of
+		// expansion.
+		synthSchema.Attributes[name] = &configschema.Attribute{
+			Type:     ty,
+			Optional: true,
+		}
+	}
+
+	parentPath := path[:len(path)-1]
+	childName := path[len(path)-1]
+	containerSchema := &configschema.Block{
+		BlockTypes: map[string]*configschema.NestedBlock{
+			childName: {
+				Nesting: configschema.NestingSet,
+				Block:   *synthSchema,
+			},
+		},
+	}
+
+	return d.applyBlockDiff(parentPath, attrs, containerSchema)
+}
+
+// countFlatmapContainerValues returns the number of values in the flatmapped container
+// (set, map, list) indexed by key. The key argument is expected to include the
+// trailing ".#", or ".%".
+func countFlatmapContainerValues(key string, attrs map[string]string) string {
+	if len(key) < 3 || !(strings.HasSuffix(key, ".#") || strings.HasSuffix(key, ".%")) {
+		panic(fmt.Sprintf("invalid index value %q", key))
+	}
+
+	prefix := key[:len(key)-1]
+	items := map[string]int{}
+
+	for k := range attrs {
+		if k == key {
+			continue
+		}
+		if !strings.HasPrefix(k, prefix) {
+			continue
+		}
+
+		suffix := k[len(prefix):]
+		dot := strings.Index(suffix, ".")
+		if dot > 0 {
+			suffix = suffix[:dot]
+		}
+
+		items[suffix]++
+	}
+	return strconv.Itoa(len(items))
+}
+
+// ResourceAttrDiff is the diff of a single attribute of a resource.
+type ResourceAttrDiff struct {
+	Old         string      // Old Value
+	New         string      // New Value
+	NewComputed bool        // True if new value is computed (unknown currently)
+	NewRemoved  bool        // True if this attribute is being removed
+	NewExtra    interface{} // Extra information for the provider
+	RequiresNew bool        // True if change requires new resource
+	Sensitive   bool        // True if the data should not be displayed in UI output
+	Type        DiffAttrType
+}
+
+// Empty returns true if the diff for this attr is neutral
+func (d *ResourceAttrDiff) Empty() bool {
+	return d.Old == d.New && !d.NewComputed && !d.NewRemoved
+}
+
+func (d *ResourceAttrDiff) GoString() string {
+	return fmt.Sprintf("*%#v", *d)
+}
+
+// DiffAttrType is an enum type that says whether a resource attribute
+// diff is an input attribute (comes from the configuration) or an
+// output attribute (comes as a result of applying the configuration). An
+// example input would be "ami" for AWS and an example output would be
+// "private_ip".
+type DiffAttrType byte
+
+const (
+	DiffAttrUnknown DiffAttrType = iota
+	DiffAttrInput
+	DiffAttrOutput
+)
+
+func (d *InstanceDiff) init() {
+	if d.Attributes == nil {
+		d.Attributes = make(map[string]*ResourceAttrDiff)
+	}
+}
+
+func NewInstanceDiff() *InstanceDiff {
+	return &InstanceDiff{Attributes: make(map[string]*ResourceAttrDiff)}
+}
+
+func (d *InstanceDiff) Copy() (*InstanceDiff, error) {
+	if d == nil {
+		return nil, nil
+	}
+
+	dCopy, err := copystructure.Config{Lock: true}.Copy(d)
+	if err != nil {
+		return nil, err
+	}
+
+	return dCopy.(*InstanceDiff), nil
+}
+
+// ChangeType returns the DiffChangeType represented by the diff
+// for this single instance.
+func (d *InstanceDiff) ChangeType() DiffChangeType {
+	if d.Empty() {
+		return DiffNone
+	}
+
+	if d.RequiresNew() && (d.GetDestroy() || d.GetDestroyTainted()) {
+		return DiffDestroyCreate
+	}
+
+	if d.GetDestroy() || d.GetDestroyDeposed() {
+		return DiffDestroy
+	}
+
+	if d.RequiresNew() {
+		return DiffCreate
+	}
+
+	return DiffUpdate
+}
+
+// Empty returns true if this diff encapsulates no changes.
+func (d *InstanceDiff) Empty() bool {
+	if d == nil {
+		return true
+	}
+
+	d.mu.Lock()
+	defer d.mu.Unlock()
+	return !d.Destroy &&
+		!d.DestroyTainted &&
+		!d.DestroyDeposed &&
+		len(d.Attributes) == 0
+}
+
+// Equal compares two diffs for exact equality.
+//
+// This is different from the Same comparison that is supported which
+// checks for operation equality taking into account computed values. Equal
+// instead checks for exact equality.
+func (d *InstanceDiff) Equal(d2 *InstanceDiff) bool {
+	// If one is nil, they must both be nil
+	if d == nil || d2 == nil {
+		return d == d2
+	}
+
+	// Use DeepEqual
+	return reflect.DeepEqual(d, d2)
+}
+
+// DeepCopy performs a deep copy of all parts of the InstanceDiff
+func (d *InstanceDiff) DeepCopy() *InstanceDiff {
+	copy, err := copystructure.Config{Lock: true}.Copy(d)
+	if err != nil {
+		panic(err)
+	}
+
+	return copy.(*InstanceDiff)
+}
+
+func (d *InstanceDiff) GoString() string {
+	return fmt.Sprintf("*%#v", InstanceDiff{
+		Attributes:     d.Attributes,
+		Destroy:        d.Destroy,
+		DestroyTainted: d.DestroyTainted,
+		DestroyDeposed: d.DestroyDeposed,
+	})
+}
+
+// RequiresNew returns true if the diff requires the creation of a new
+// resource (implying the destruction of the old).
+func (d *InstanceDiff) RequiresNew() bool {
+	if d == nil {
+		return false
+	}
+
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	return d.requiresNew()
+}
+
+func (d *InstanceDiff) requiresNew() bool {
+	if d == nil {
+		return false
+	}
+
+	if d.DestroyTainted {
+		return true
+	}
+
+	for _, rd := range d.Attributes {
+		if rd != nil && rd.RequiresNew {
+			return true
+		}
+	}
+
+	return false
+}
+
+func (d *InstanceDiff) GetDestroyDeposed() bool {
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	return d.DestroyDeposed
+}
+
+func (d *InstanceDiff) SetDestroyDeposed(b bool) {
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	d.DestroyDeposed = b
+}
+
+// These methods are properly locked, for use outside other InstanceDiff
+// methods but everywhere else within the terraform package.
+// TODO refactor the locking scheme
+func (d *InstanceDiff) SetTainted(b bool) {
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	d.DestroyTainted = b
+}
+
+func (d *InstanceDiff) GetDestroyTainted() bool {
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	return d.DestroyTainted
+}
+
+func (d *InstanceDiff) SetDestroy(b bool) {
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	d.Destroy = b
+}
+
+func (d *InstanceDiff) GetDestroy() bool {
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	return d.Destroy
+}
+
+func (d *InstanceDiff) SetAttribute(key string, attr *ResourceAttrDiff) {
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	d.Attributes[key] = attr
+}
+
+func (d *InstanceDiff) DelAttribute(key string) {
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	delete(d.Attributes, key)
+}
+
+func (d *InstanceDiff) GetAttribute(key string) (*ResourceAttrDiff, bool) {
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	attr, ok := d.Attributes[key]
+	return attr, ok
+}
+func (d *InstanceDiff) GetAttributesLen() int {
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	return len(d.Attributes)
+}
+
+// Safely copies the Attributes map
+func (d *InstanceDiff) CopyAttributes() map[string]*ResourceAttrDiff {
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	attrs := make(map[string]*ResourceAttrDiff)
+	for k, v := range d.Attributes {
+		attrs[k] = v
+	}
+
+	return attrs
+}
+
+// Same checks whether or not two InstanceDiff's are the "same". When
+// we say "same", it is not necessarily exactly equal. Instead, it is
+// just checking that the same attributes are changing, a destroy
+// isn't suddenly happening, etc.
+func (d *InstanceDiff) Same(d2 *InstanceDiff) (bool, string) {
+	// we can safely compare the pointers without a lock
+	switch {
+	case d == nil && d2 == nil:
+		return true, ""
+	case d == nil || d2 == nil:
+		return false, "one nil"
+	case d == d2:
+		return true, ""
+	}
+
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	// If we're going from requiring new to NOT requiring new, then we have
+	// to see if all required news were computed. If so, it is allowed since
+	// computed may also mean "same value and therefore not new".
+	oldNew := d.requiresNew()
+	newNew := d2.RequiresNew()
+	if oldNew && !newNew {
+		oldNew = false
+
+		// This section builds a list of ignorable attributes for requiresNew
+		// by removing off any elements of collections going to zero elements.
+		// For collections going to zero, they may not exist at all in the
+		// new diff (and hence RequiresNew == false).
+		ignoreAttrs := make(map[string]struct{})
+		for k, diffOld := range d.Attributes {
+			if !strings.HasSuffix(k, ".%") && !strings.HasSuffix(k, ".#") {
+				continue
+			}
+
+			// This case is in here as a protection measure. The bug that this
+			// code originally fixed (GH-11349) didn't have to deal with computed
+			// so I'm not 100% sure what the correct behavior is. Best to leave
+			// the old behavior.
+			if diffOld.NewComputed {
+				continue
+			}
+
+			// We're looking for the case a map goes to exactly 0.
+			if diffOld.New != "0" {
+				continue
+			}
+
+			// Found it! Ignore all of these. The prefix here is stripping
+			// off the "%" so it is just "k."
+			prefix := k[:len(k)-1]
+			for k2, _ := range d.Attributes {
+				if strings.HasPrefix(k2, prefix) {
+					ignoreAttrs[k2] = struct{}{}
+				}
+			}
+		}
+
+		for k, rd := range d.Attributes {
+			if _, ok := ignoreAttrs[k]; ok {
+				continue
+			}
+
+			// If the field is requires new and NOT computed, then what
+			// we have is a diff mismatch for sure. We set that the old
+			// diff does REQUIRE a ForceNew.
+			if rd != nil && rd.RequiresNew && !rd.NewComputed {
+				oldNew = true
+				break
+			}
+		}
+	}
+
+	if oldNew != newNew {
+		return false, fmt.Sprintf(
+			"diff RequiresNew; old: %t, new: %t", oldNew, newNew)
+	}
+
+	// Verify that destroy matches. The second boolean here allows us to
+	// have mismatching Destroy if we're moving from RequiresNew true
+	// to false above. Therefore, the second boolean will only pass if
+	// we're moving from Destroy: true to false as well.
+	if d.Destroy != d2.GetDestroy() && d.requiresNew() == oldNew {
+		return false, fmt.Sprintf(
+			"diff: Destroy; old: %t, new: %t", d.Destroy, d2.GetDestroy())
+	}
+
+	// Go through the old diff and make sure the new diff has all the
+	// same attributes. To start, build up the check map to be all the keys.
+	checkOld := make(map[string]struct{})
+	checkNew := make(map[string]struct{})
+	for k, _ := range d.Attributes {
+		checkOld[k] = struct{}{}
+	}
+	for k, _ := range d2.CopyAttributes() {
+		checkNew[k] = struct{}{}
+	}
+
+	// Make an ordered list so we are sure the approximated hashes are left
+	// to process at the end of the loop
+	keys := make([]string, 0, len(d.Attributes))
+	for k, _ := range d.Attributes {
+		keys = append(keys, k)
+	}
+	sort.StringSlice(keys).Sort()
+
+	for _, k := range keys {
+		diffOld := d.Attributes[k]
+
+		if _, ok := checkOld[k]; !ok {
+			// We're not checking this key for whatever reason (see where
+			// check is modified).
+			continue
+		}
+
+		// Remove this key since we'll never hit it again
+		delete(checkOld, k)
+		delete(checkNew, k)
+
+		_, ok := d2.GetAttribute(k)
+		if !ok {
+			// If there's no new attribute, and the old diff expected the attribute
+			// to be removed, that's just fine.
+			if diffOld.NewRemoved {
+				continue
+			}
+
+			// If the last diff was a computed value then the absense of
+			// that value is allowed since it may mean the value ended up
+			// being the same.
+			if diffOld.NewComputed {
+				ok = true
+			}
+
+			// No exact match, but maybe this is a set containing computed
+			// values. So check if there is an approximate hash in the key
+			// and if so, try to match the key.
+			if strings.Contains(k, "~") {
+				parts := strings.Split(k, ".")
+				parts2 := append([]string(nil), parts...)
+
+				re := regexp.MustCompile(`^~\d+$`)
+				for i, part := range parts {
+					if re.MatchString(part) {
+						// we're going to consider this the base of a
+						// computed hash, and remove all longer matching fields
+						ok = true
+
+						parts2[i] = `\d+`
+						parts2 = parts2[:i+1]
+						break
+					}
+				}
+
+				re, err := regexp.Compile("^" + strings.Join(parts2, `\.`))
+				if err != nil {
+					return false, fmt.Sprintf("regexp failed to compile; err: %#v", err)
+				}
+
+				for k2, _ := range checkNew {
+					if re.MatchString(k2) {
+						delete(checkNew, k2)
+					}
+				}
+			}
+
+			// This is a little tricky, but when a diff contains a computed
+			// list, set, or map that can only be interpolated after the apply
+			// command has created the dependent resources, it could turn out
+			// that the result is actually the same as the existing state which
+			// would remove the key from the diff.
+			if diffOld.NewComputed && (strings.HasSuffix(k, ".#") || strings.HasSuffix(k, ".%")) {
+				ok = true
+			}
+
+			// Similarly, in a RequiresNew scenario, a list that shows up in the plan
+			// diff can disappear from the apply diff, which is calculated from an
+			// empty state.
+			if d.requiresNew() && (strings.HasSuffix(k, ".#") || strings.HasSuffix(k, ".%")) {
+				ok = true
+			}
+
+			if !ok {
+				return false, fmt.Sprintf("attribute mismatch: %s", k)
+			}
+		}
+
+		// search for the suffix of the base of a [computed] map, list or set.
+		match := multiVal.FindStringSubmatch(k)
+
+		if diffOld.NewComputed && len(match) == 2 {
+			matchLen := len(match[1])
+
+			// This is a computed list, set, or map, so remove any keys with
+			// this prefix from the check list.
+			kprefix := k[:len(k)-matchLen]
+			for k2, _ := range checkOld {
+				if strings.HasPrefix(k2, kprefix) {
+					delete(checkOld, k2)
+				}
+			}
+			for k2, _ := range checkNew {
+				if strings.HasPrefix(k2, kprefix) {
+					delete(checkNew, k2)
+				}
+			}
+		}
+
+		// We don't compare the values because we can't currently actually
+		// guarantee to generate the same value two two diffs created from
+		// the same state+config: we have some pesky interpolation functions
+		// that do not behave as pure functions (uuid, timestamp) and so they
+		// can be different each time a diff is produced.
+		// FIXME: Re-organize our config handling so that we don't re-evaluate
+		// expressions when we produce a second comparison diff during
+		// apply (for EvalCompareDiff).
+	}
+
+	// Check for leftover attributes
+	if len(checkNew) > 0 {
+		extras := make([]string, 0, len(checkNew))
+		for attr, _ := range checkNew {
+			extras = append(extras, attr)
+		}
+		return false,
+			fmt.Sprintf("extra attributes: %s", strings.Join(extras, ", "))
+	}
+
+	return true, ""
+}
+
+// moduleDiffSort implements sort.Interface to sort module diffs by path.
+type moduleDiffSort []*ModuleDiff
+
+func (s moduleDiffSort) Len() int      { return len(s) }
+func (s moduleDiffSort) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s moduleDiffSort) Less(i, j int) bool {
+	a := s[i]
+	b := s[j]
+
+	// If the lengths are different, then the shorter one always wins
+	if len(a.Path) != len(b.Path) {
+		return len(a.Path) < len(b.Path)
+	}
+
+	// Otherwise, compare lexically
+	return strings.Join(a.Path, ".") < strings.Join(b.Path, ".")
+}
diff --git a/v1.5.7/internal/legacy/terraform/diff_test.go b/v1.5.7/internal/legacy/terraform/diff_test.go
new file mode 100644
index 0000000..aeead09
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/diff_test.go
@@ -0,0 +1,1255 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestDiffEmpty(t *testing.T) {
+	var diff *Diff
+	if !diff.Empty() {
+		t.Fatal("should be empty")
+	}
+
+	diff = new(Diff)
+	if !diff.Empty() {
+		t.Fatal("should be empty")
+	}
+
+	mod := diff.AddModule(addrs.RootModuleInstance)
+	mod.Resources["nodeA"] = &InstanceDiff{
+		Attributes: map[string]*ResourceAttrDiff{
+			"foo": &ResourceAttrDiff{
+				Old: "foo",
+				New: "bar",
+			},
+		},
+	}
+
+	if diff.Empty() {
+		t.Fatal("should not be empty")
+	}
+}
+
+func TestDiffEmpty_taintedIsNotEmpty(t *testing.T) {
+	diff := new(Diff)
+
+	mod := diff.AddModule(addrs.RootModuleInstance)
+	mod.Resources["nodeA"] = &InstanceDiff{
+		DestroyTainted: true,
+	}
+
+	if diff.Empty() {
+		t.Fatal("should not be empty, since DestroyTainted was set")
+	}
+}
+
+func TestDiffEqual(t *testing.T) {
+	cases := map[string]struct {
+		D1, D2 *Diff
+		Equal  bool
+	}{
+		"nil": {
+			nil,
+			new(Diff),
+			false,
+		},
+
+		"empty": {
+			new(Diff),
+			new(Diff),
+			true,
+		},
+
+		"different module order": {
+			&Diff{
+				Modules: []*ModuleDiff{
+					&ModuleDiff{Path: []string{"root", "foo"}},
+					&ModuleDiff{Path: []string{"root", "bar"}},
+				},
+			},
+			&Diff{
+				Modules: []*ModuleDiff{
+					&ModuleDiff{Path: []string{"root", "bar"}},
+					&ModuleDiff{Path: []string{"root", "foo"}},
+				},
+			},
+			true,
+		},
+
+		"different module diff destroys": {
+			&Diff{
+				Modules: []*ModuleDiff{
+					&ModuleDiff{Path: []string{"root", "foo"}, Destroy: true},
+				},
+			},
+			&Diff{
+				Modules: []*ModuleDiff{
+					&ModuleDiff{Path: []string{"root", "foo"}, Destroy: false},
+				},
+			},
+			true,
+		},
+	}
+
+	for name, tc := range cases {
+		t.Run(name, func(t *testing.T) {
+			actual := tc.D1.Equal(tc.D2)
+			if actual != tc.Equal {
+				t.Fatalf("expected: %v\n\n%#v\n\n%#v", tc.Equal, tc.D1, tc.D2)
+			}
+		})
+	}
+}
+
+func TestDiffPrune(t *testing.T) {
+	cases := map[string]struct {
+		D1, D2 *Diff
+	}{
+		"nil": {
+			nil,
+			nil,
+		},
+
+		"empty": {
+			new(Diff),
+			new(Diff),
+		},
+
+		"empty module": {
+			&Diff{
+				Modules: []*ModuleDiff{
+					&ModuleDiff{Path: []string{"root", "foo"}},
+				},
+			},
+			&Diff{},
+		},
+
+		"destroy module": {
+			&Diff{
+				Modules: []*ModuleDiff{
+					&ModuleDiff{Path: []string{"root", "foo"}, Destroy: true},
+				},
+			},
+			&Diff{
+				Modules: []*ModuleDiff{
+					&ModuleDiff{Path: []string{"root", "foo"}, Destroy: true},
+				},
+			},
+		},
+	}
+
+	for name, tc := range cases {
+		t.Run(name, func(t *testing.T) {
+			tc.D1.Prune()
+			if !tc.D1.Equal(tc.D2) {
+				t.Fatalf("bad:\n\n%#v\n\n%#v", tc.D1, tc.D2)
+			}
+		})
+	}
+}
+
+func TestModuleDiff_ChangeType(t *testing.T) {
+	cases := []struct {
+		Diff   *ModuleDiff
+		Result DiffChangeType
+	}{
+		{
+			&ModuleDiff{},
+			DiffNone,
+		},
+		{
+			&ModuleDiff{
+				Resources: map[string]*InstanceDiff{
+					"foo": &InstanceDiff{Destroy: true},
+				},
+			},
+			DiffDestroy,
+		},
+		{
+			&ModuleDiff{
+				Resources: map[string]*InstanceDiff{
+					"foo": &InstanceDiff{
+						Attributes: map[string]*ResourceAttrDiff{
+							"foo": &ResourceAttrDiff{
+								Old: "",
+								New: "bar",
+							},
+						},
+					},
+				},
+			},
+			DiffUpdate,
+		},
+		{
+			&ModuleDiff{
+				Resources: map[string]*InstanceDiff{
+					"foo": &InstanceDiff{
+						Attributes: map[string]*ResourceAttrDiff{
+							"foo": &ResourceAttrDiff{
+								Old:         "",
+								New:         "bar",
+								RequiresNew: true,
+							},
+						},
+					},
+				},
+			},
+			DiffCreate,
+		},
+		{
+			&ModuleDiff{
+				Resources: map[string]*InstanceDiff{
+					"foo": &InstanceDiff{
+						Destroy: true,
+						Attributes: map[string]*ResourceAttrDiff{
+							"foo": &ResourceAttrDiff{
+								Old:         "",
+								New:         "bar",
+								RequiresNew: true,
+							},
+						},
+					},
+				},
+			},
+			DiffUpdate,
+		},
+	}
+
+	for i, tc := range cases {
+		actual := tc.Diff.ChangeType()
+		if actual != tc.Result {
+			t.Fatalf("%d: %#v", i, actual)
+		}
+	}
+}
+
+func TestDiff_DeepCopy(t *testing.T) {
+	cases := map[string]*Diff{
+		"empty": &Diff{},
+
+		"basic diff": &Diff{
+			Modules: []*ModuleDiff{
+				&ModuleDiff{
+					Path: []string{"root"},
+					Resources: map[string]*InstanceDiff{
+						"aws_instance.foo": &InstanceDiff{
+							Attributes: map[string]*ResourceAttrDiff{
+								"num": &ResourceAttrDiff{
+									Old: "0",
+									New: "2",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for name, tc := range cases {
+		t.Run(name, func(t *testing.T) {
+			dup := tc.DeepCopy()
+			if !reflect.DeepEqual(dup, tc) {
+				t.Fatalf("\n%#v\n\n%#v", dup, tc)
+			}
+		})
+	}
+}
+
+func TestModuleDiff_Empty(t *testing.T) {
+	diff := new(ModuleDiff)
+	if !diff.Empty() {
+		t.Fatal("should be empty")
+	}
+
+	diff.Resources = map[string]*InstanceDiff{
+		"nodeA": &InstanceDiff{},
+	}
+
+	if !diff.Empty() {
+		t.Fatal("should be empty")
+	}
+
+	diff.Resources["nodeA"].Attributes = map[string]*ResourceAttrDiff{
+		"foo": &ResourceAttrDiff{
+			Old: "foo",
+			New: "bar",
+		},
+	}
+
+	if diff.Empty() {
+		t.Fatal("should not be empty")
+	}
+
+	diff.Resources["nodeA"].Attributes = nil
+	diff.Resources["nodeA"].Destroy = true
+
+	if diff.Empty() {
+		t.Fatal("should not be empty")
+	}
+}
+
+func TestModuleDiff_String(t *testing.T) {
+	diff := &ModuleDiff{
+		Resources: map[string]*InstanceDiff{
+			"nodeA": &InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{
+						Old: "foo",
+						New: "bar",
+					},
+					"bar": &ResourceAttrDiff{
+						Old:         "foo",
+						NewComputed: true,
+					},
+					"longfoo": &ResourceAttrDiff{
+						Old:         "foo",
+						New:         "bar",
+						RequiresNew: true,
+					},
+					"secretfoo": &ResourceAttrDiff{
+						Old:       "foo",
+						New:       "bar",
+						Sensitive: true,
+					},
+				},
+			},
+		},
+	}
+
+	actual := strings.TrimSpace(diff.String())
+	expected := strings.TrimSpace(moduleDiffStrBasic)
+	if actual != expected {
+		t.Fatalf("bad:\n%s", actual)
+	}
+}
+
+func TestInstanceDiff_ChangeType(t *testing.T) {
+	cases := []struct {
+		Diff   *InstanceDiff
+		Result DiffChangeType
+	}{
+		{
+			&InstanceDiff{},
+			DiffNone,
+		},
+		{
+			&InstanceDiff{Destroy: true},
+			DiffDestroy,
+		},
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{
+						Old: "",
+						New: "bar",
+					},
+				},
+			},
+			DiffUpdate,
+		},
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{
+						Old:         "",
+						New:         "bar",
+						RequiresNew: true,
+					},
+				},
+			},
+			DiffCreate,
+		},
+		{
+			&InstanceDiff{
+				Destroy: true,
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{
+						Old:         "",
+						New:         "bar",
+						RequiresNew: true,
+					},
+				},
+			},
+			DiffDestroyCreate,
+		},
+		{
+			&InstanceDiff{
+				DestroyTainted: true,
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{
+						Old:         "",
+						New:         "bar",
+						RequiresNew: true,
+					},
+				},
+			},
+			DiffDestroyCreate,
+		},
+	}
+
+	for i, tc := range cases {
+		actual := tc.Diff.ChangeType()
+		if actual != tc.Result {
+			t.Fatalf("%d: %#v", i, actual)
+		}
+	}
+}
+
+func TestInstanceDiff_Empty(t *testing.T) {
+	var rd *InstanceDiff
+
+	if !rd.Empty() {
+		t.Fatal("should be empty")
+	}
+
+	rd = new(InstanceDiff)
+
+	if !rd.Empty() {
+		t.Fatal("should be empty")
+	}
+
+	rd = &InstanceDiff{Destroy: true}
+
+	if rd.Empty() {
+		t.Fatal("should not be empty")
+	}
+
+	rd = &InstanceDiff{
+		Attributes: map[string]*ResourceAttrDiff{
+			"foo": &ResourceAttrDiff{
+				New: "bar",
+			},
+		},
+	}
+
+	if rd.Empty() {
+		t.Fatal("should not be empty")
+	}
+}
+
+func TestModuleDiff_Instances(t *testing.T) {
+	yesDiff := &InstanceDiff{Destroy: true}
+	noDiff := &InstanceDiff{Destroy: true, DestroyTainted: true}
+
+	cases := []struct {
+		Diff   *ModuleDiff
+		Id     string
+		Result []*InstanceDiff
+	}{
+		{
+			&ModuleDiff{
+				Resources: map[string]*InstanceDiff{
+					"foo": yesDiff,
+					"bar": noDiff,
+				},
+			},
+			"foo",
+			[]*InstanceDiff{
+				yesDiff,
+			},
+		},
+
+		{
+			&ModuleDiff{
+				Resources: map[string]*InstanceDiff{
+					"foo":   yesDiff,
+					"foo.0": yesDiff,
+					"bar":   noDiff,
+				},
+			},
+			"foo",
+			[]*InstanceDiff{
+				yesDiff,
+				yesDiff,
+			},
+		},
+
+		{
+			&ModuleDiff{
+				Resources: map[string]*InstanceDiff{
+					"foo":     yesDiff,
+					"foo.0":   yesDiff,
+					"foo_bar": noDiff,
+					"bar":     noDiff,
+				},
+			},
+			"foo",
+			[]*InstanceDiff{
+				yesDiff,
+				yesDiff,
+			},
+		},
+	}
+
+	for i, tc := range cases {
+		actual := tc.Diff.Instances(tc.Id)
+		if !reflect.DeepEqual(actual, tc.Result) {
+			t.Fatalf("%d: %#v", i, actual)
+		}
+	}
+}
+
+func TestInstanceDiff_RequiresNew(t *testing.T) {
+	rd := &InstanceDiff{
+		Attributes: map[string]*ResourceAttrDiff{
+			"foo": &ResourceAttrDiff{},
+		},
+	}
+
+	if rd.RequiresNew() {
+		t.Fatal("should not require new")
+	}
+
+	rd.Attributes["foo"].RequiresNew = true
+
+	if !rd.RequiresNew() {
+		t.Fatal("should require new")
+	}
+}
+
+func TestInstanceDiff_RequiresNew_nil(t *testing.T) {
+	var rd *InstanceDiff
+
+	if rd.RequiresNew() {
+		t.Fatal("should not require new")
+	}
+}
+
+func TestInstanceDiffSame(t *testing.T) {
+	cases := []struct {
+		One, Two *InstanceDiff
+		Same     bool
+		Reason   string
+	}{
+		{
+			&InstanceDiff{},
+			&InstanceDiff{},
+			true,
+			"",
+		},
+
+		{
+			nil,
+			nil,
+			true,
+			"",
+		},
+
+		{
+			&InstanceDiff{Destroy: false},
+			&InstanceDiff{Destroy: true},
+			false,
+			"diff: Destroy; old: false, new: true",
+		},
+
+		{
+			&InstanceDiff{Destroy: true},
+			&InstanceDiff{Destroy: true},
+			true,
+			"",
+		},
+
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{},
+				},
+			},
+			true,
+			"",
+		},
+
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"bar": &ResourceAttrDiff{},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{},
+				},
+			},
+			false,
+			"attribute mismatch: bar",
+		},
+
+		// Extra attributes
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{},
+					"bar": &ResourceAttrDiff{},
+				},
+			},
+			false,
+			"extra attributes: bar",
+		},
+
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{RequiresNew: true},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{RequiresNew: false},
+				},
+			},
+			false,
+			"diff RequiresNew; old: true, new: false",
+		},
+
+		// NewComputed on primitive
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{
+						Old:         "",
+						New:         "${var.foo}",
+						NewComputed: true,
+					},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+				},
+			},
+			true,
+			"",
+		},
+
+		// NewComputed on primitive, removed
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{
+						Old:         "",
+						New:         "${var.foo}",
+						NewComputed: true,
+					},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{},
+			},
+			true,
+			"",
+		},
+
+		// NewComputed on set, removed
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old:         "",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.1": &ResourceAttrDiff{
+						Old:        "foo",
+						New:        "",
+						NewRemoved: true,
+					},
+					"foo.2": &ResourceAttrDiff{
+						Old: "",
+						New: "bar",
+					},
+				},
+			},
+			true,
+			"",
+		},
+
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{NewComputed: true},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"foo.0": &ResourceAttrDiff{
+						Old: "",
+						New: "12",
+					},
+				},
+			},
+			true,
+			"",
+		},
+
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"foo.~35964334.bar": &ResourceAttrDiff{
+						Old: "",
+						New: "${var.foo}",
+					},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"foo.87654323.bar": &ResourceAttrDiff{
+						Old: "",
+						New: "12",
+					},
+				},
+			},
+			true,
+			"",
+		},
+
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old:         "0",
+						NewComputed: true,
+					},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{},
+			},
+			true,
+			"",
+		},
+
+		// Computed can change RequiresNew by removal, and that's okay
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old:         "0",
+						NewComputed: true,
+						RequiresNew: true,
+					},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{},
+			},
+			true,
+			"",
+		},
+
+		// Computed can change Destroy by removal, and that's okay
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old:         "0",
+						NewComputed: true,
+						RequiresNew: true,
+					},
+				},
+
+				Destroy: true,
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{},
+			},
+			true,
+			"",
+		},
+
+		// Computed can change Destroy by elements
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old:         "0",
+						NewComputed: true,
+						RequiresNew: true,
+					},
+				},
+
+				Destroy: true,
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old: "1",
+						New: "1",
+					},
+					"foo.12": &ResourceAttrDiff{
+						Old:         "4",
+						New:         "12",
+						RequiresNew: true,
+					},
+				},
+
+				Destroy: true,
+			},
+			true,
+			"",
+		},
+
+		// Computed sets may not contain all fields in the original diff, and
+		// because multiple entries for the same set can compute to the same
+		// hash before the values are computed or interpolated, the overall
+		// count can change as well.
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"foo.~35964334.bar": &ResourceAttrDiff{
+						Old: "",
+						New: "${var.foo}",
+					},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old: "0",
+						New: "2",
+					},
+					"foo.87654323.bar": &ResourceAttrDiff{
+						Old: "",
+						New: "12",
+					},
+					"foo.87654325.bar": &ResourceAttrDiff{
+						Old: "",
+						New: "12",
+					},
+					"foo.87654325.baz": &ResourceAttrDiff{
+						Old: "",
+						New: "12",
+					},
+				},
+			},
+			true,
+			"",
+		},
+
+		// Computed values in maps will fail the "Same" check as well
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.%": &ResourceAttrDiff{
+						Old:         "",
+						New:         "",
+						NewComputed: true,
+					},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.%": &ResourceAttrDiff{
+						Old:         "0",
+						New:         "1",
+						NewComputed: false,
+					},
+					"foo.val": &ResourceAttrDiff{
+						Old: "",
+						New: "something",
+					},
+				},
+			},
+			true,
+			"",
+		},
+
+		// In a DESTROY/CREATE scenario, the plan diff will be run against the
+		// state of the old instance, while the apply diff will be run against an
+		// empty state (because the state is cleared when the destroy runs.)
+		// For complex attributes, this can result in keys that seem to disappear
+		// between the two diffs, when in reality everything is working just fine.
+		//
+		// Same() needs to take into account this scenario by analyzing NewRemoved
+		// and treating as "Same" a diff that does indeed have that key removed.
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"somemap.oldkey": &ResourceAttrDiff{
+						Old:        "long ago",
+						New:        "",
+						NewRemoved: true,
+					},
+					"somemap.newkey": &ResourceAttrDiff{
+						Old: "",
+						New: "brave new world",
+					},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"somemap.newkey": &ResourceAttrDiff{
+						Old: "",
+						New: "brave new world",
+					},
+				},
+			},
+			true,
+			"",
+		},
+
+		// Another thing that can occur in DESTROY/CREATE scenarios is that list
+		// values that are going to zero have diffs that show up at plan time but
+		// are gone at apply time. The NewRemoved handling catches the fields and
+		// treats them as OK, but it also needs to treat the .# field itself as
+		// okay to be present in the old diff but not in the new one.
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"reqnew": &ResourceAttrDiff{
+						Old:         "old",
+						New:         "new",
+						RequiresNew: true,
+					},
+					"somemap.#": &ResourceAttrDiff{
+						Old: "1",
+						New: "0",
+					},
+					"somemap.oldkey": &ResourceAttrDiff{
+						Old:        "long ago",
+						New:        "",
+						NewRemoved: true,
+					},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"reqnew": &ResourceAttrDiff{
+						Old:         "",
+						New:         "new",
+						RequiresNew: true,
+					},
+				},
+			},
+			true,
+			"",
+		},
+
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"reqnew": &ResourceAttrDiff{
+						Old:         "old",
+						New:         "new",
+						RequiresNew: true,
+					},
+					"somemap.%": &ResourceAttrDiff{
+						Old: "1",
+						New: "0",
+					},
+					"somemap.oldkey": &ResourceAttrDiff{
+						Old:        "long ago",
+						New:        "",
+						NewRemoved: true,
+					},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"reqnew": &ResourceAttrDiff{
+						Old:         "",
+						New:         "new",
+						RequiresNew: true,
+					},
+				},
+			},
+			true,
+			"",
+		},
+
+		// Innner computed set should allow outer change in key
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"foo.~1.outer_val": &ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+					"foo.~1.inner.#": &ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"foo.~1.inner.~2.value": &ResourceAttrDiff{
+						Old:         "",
+						New:         "${var.bar}",
+						NewComputed: true,
+					},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"foo.12.outer_val": &ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+					"foo.12.inner.#": &ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"foo.12.inner.42.value": &ResourceAttrDiff{
+						Old: "",
+						New: "baz",
+					},
+				},
+			},
+			true,
+			"",
+		},
+
+		// Innner computed list should allow outer change in key
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"foo.~1.outer_val": &ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+					"foo.~1.inner.#": &ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"foo.~1.inner.0.value": &ResourceAttrDiff{
+						Old:         "",
+						New:         "${var.bar}",
+						NewComputed: true,
+					},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"foo.12.outer_val": &ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+					"foo.12.inner.#": &ResourceAttrDiff{
+						Old: "0",
+						New: "1",
+					},
+					"foo.12.inner.0.value": &ResourceAttrDiff{
+						Old: "",
+						New: "baz",
+					},
+				},
+			},
+			true,
+			"",
+		},
+
+		// When removing all collection items, the diff is allowed to contain
+		// nothing when re-creating the resource. This should be the "Same"
+		// since we said we were going from 1 to 0.
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.%": &ResourceAttrDiff{
+						Old:         "1",
+						New:         "0",
+						RequiresNew: true,
+					},
+					"foo.bar": &ResourceAttrDiff{
+						Old:         "baz",
+						New:         "",
+						NewRemoved:  true,
+						RequiresNew: true,
+					},
+				},
+			},
+			&InstanceDiff{},
+			true,
+			"",
+		},
+
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo.#": &ResourceAttrDiff{
+						Old:         "1",
+						New:         "0",
+						RequiresNew: true,
+					},
+					"foo.0": &ResourceAttrDiff{
+						Old:         "baz",
+						New:         "",
+						NewRemoved:  true,
+						RequiresNew: true,
+					},
+				},
+			},
+			&InstanceDiff{},
+			true,
+			"",
+		},
+
+		// Make sure that DestroyTainted diffs pass as well, especially when diff
+		// two works off of no state.
+		{
+			&InstanceDiff{
+				DestroyTainted: true,
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{
+						Old: "foo",
+						New: "foo",
+					},
+				},
+			},
+			&InstanceDiff{
+				DestroyTainted: true,
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+				},
+			},
+			true,
+			"",
+		},
+		// RequiresNew in different attribute
+		{
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{
+						Old: "foo",
+						New: "foo",
+					},
+					"bar": &ResourceAttrDiff{
+						Old:         "bar",
+						New:         "baz",
+						RequiresNew: true,
+					},
+				},
+			},
+			&InstanceDiff{
+				Attributes: map[string]*ResourceAttrDiff{
+					"foo": &ResourceAttrDiff{
+						Old: "",
+						New: "foo",
+					},
+					"bar": &ResourceAttrDiff{
+						Old:         "",
+						New:         "baz",
+						RequiresNew: true,
+					},
+				},
+			},
+			true,
+			"",
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+			same, reason := tc.One.Same(tc.Two)
+			if same != tc.Same {
+				t.Fatalf("%d: expected same: %t, got %t (%s)\n\n one: %#v\n\ntwo: %#v",
+					i, tc.Same, same, reason, tc.One, tc.Two)
+			}
+			if reason != tc.Reason {
+				t.Fatalf(
+					"%d: bad reason\n\nexpected: %#v\n\ngot: %#v", i, tc.Reason, reason)
+			}
+		})
+	}
+}
+
+const moduleDiffStrBasic = `
+CREATE: nodeA
+  bar:       "foo" => "<computed>"
+  foo:       "foo" => "bar"
+  longfoo:   "foo" => "bar" (forces new resource)
+  secretfoo: "<sensitive>" => "<sensitive>" (attribute changed)
+`
+
+func TestCountFlatmapContainerValues(t *testing.T) {
+	for i, tc := range []struct {
+		attrs map[string]string
+		key   string
+		count string
+	}{
+		{
+			attrs: map[string]string{"set.2.list.#": "9999", "set.2.list.0": "x", "set.2.list.0.z": "y", "set.2.attr": "bar", "set.#": "9999"},
+			key:   "set.2.list.#",
+			count: "1",
+		},
+		{
+			attrs: map[string]string{"set.2.list.#": "9999", "set.2.list.0": "x", "set.2.list.0.z": "y", "set.2.attr": "bar", "set.#": "9999"},
+			key:   "set.#",
+			count: "1",
+		},
+		{
+			attrs: map[string]string{"set.2.list.0": "x", "set.2.list.0.z": "y", "set.2.attr": "bar", "set.#": "9999"},
+			key:   "set.#",
+			count: "1",
+		},
+		{
+			attrs: map[string]string{"map.#": "3", "map.a": "b", "map.a.#": "0", "map.b": "4"},
+			key:   "map.#",
+			count: "2",
+		},
+	} {
+		t.Run(strconv.Itoa(i), func(t *testing.T) {
+			count := countFlatmapContainerValues(tc.key, tc.attrs)
+			if count != tc.count {
+				t.Fatalf("expected %q, got %q", tc.count, count)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/legacy/terraform/features.go b/v1.5.7/internal/legacy/terraform/features.go
new file mode 100644
index 0000000..62c43af
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/features.go
@@ -0,0 +1,10 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import "os"
+
+// This file holds feature flags for the next release
+
+var flagWarnOutputErrors = os.Getenv("TF_WARN_OUTPUT_ERRORS") != ""
diff --git a/v1.5.7/internal/legacy/terraform/instancetype.go b/v1.5.7/internal/legacy/terraform/instancetype.go
new file mode 100644
index 0000000..8bb3e73
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/instancetype.go
@@ -0,0 +1,16 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=InstanceType instancetype.go
+
+// InstanceType is an enum of the various types of instances store in the State
+type InstanceType int
+
+const (
+	TypeInvalid InstanceType = iota
+	TypePrimary
+	TypeTainted
+	TypeDeposed
+)
diff --git a/v1.5.7/internal/legacy/terraform/instancetype_string.go b/v1.5.7/internal/legacy/terraform/instancetype_string.go
new file mode 100644
index 0000000..95b7a98
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/instancetype_string.go
@@ -0,0 +1,26 @@
+// Code generated by "stringer -type=InstanceType instancetype.go"; DO NOT EDIT.
+
+package terraform
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[TypeInvalid-0]
+	_ = x[TypePrimary-1]
+	_ = x[TypeTainted-2]
+	_ = x[TypeDeposed-3]
+}
+
+const _InstanceType_name = "TypeInvalidTypePrimaryTypeTaintedTypeDeposed"
+
+var _InstanceType_index = [...]uint8{0, 11, 22, 33, 44}
+
+func (i InstanceType) String() string {
+	if i < 0 || i >= InstanceType(len(_InstanceType_index)-1) {
+		return "InstanceType(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _InstanceType_name[_InstanceType_index[i]:_InstanceType_index[i+1]]
+}
diff --git a/v1.5.7/internal/legacy/terraform/provider_mock.go b/v1.5.7/internal/legacy/terraform/provider_mock.go
new file mode 100644
index 0000000..7097c5f
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/provider_mock.go
@@ -0,0 +1,366 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"encoding/json"
+	"sync"
+
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/providers"
+)
+
+var _ providers.Interface = (*MockProvider)(nil)
+
+// MockProvider implements providers.Interface but mocks out all the
+// calls for testing purposes.
+type MockProvider struct {
+	sync.Mutex
+
+	// Anything you want, in case you need to store extra data with the mock.
+	Meta interface{}
+
+	GetSchemaCalled bool
+	GetSchemaReturn *ProviderSchema // This is using ProviderSchema directly rather than providers.GetProviderSchemaResponse for compatibility with old tests
+
+	ValidateProviderConfigCalled   bool
+	ValidateProviderConfigResponse providers.ValidateProviderConfigResponse
+	ValidateProviderConfigRequest  providers.ValidateProviderConfigRequest
+	ValidateProviderConfigFn       func(providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse
+
+	ValidateResourceConfigCalled   bool
+	ValidateResourceConfigTypeName string
+	ValidateResourceConfigResponse providers.ValidateResourceConfigResponse
+	ValidateResourceConfigRequest  providers.ValidateResourceConfigRequest
+	ValidateResourceConfigFn       func(providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse
+
+	ValidateDataResourceConfigCalled   bool
+	ValidateDataResourceConfigTypeName string
+	ValidateDataResourceConfigResponse providers.ValidateDataResourceConfigResponse
+	ValidateDataResourceConfigRequest  providers.ValidateDataResourceConfigRequest
+	ValidateDataResourceConfigFn       func(providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse
+
+	UpgradeResourceStateCalled   bool
+	UpgradeResourceStateTypeName string
+	UpgradeResourceStateResponse providers.UpgradeResourceStateResponse
+	UpgradeResourceStateRequest  providers.UpgradeResourceStateRequest
+	UpgradeResourceStateFn       func(providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse
+
+	ConfigureProviderCalled   bool
+	ConfigureProviderResponse providers.ConfigureProviderResponse
+	ConfigureProviderRequest  providers.ConfigureProviderRequest
+	ConfigureProviderFn       func(providers.ConfigureProviderRequest) providers.ConfigureProviderResponse
+
+	StopCalled   bool
+	StopFn       func() error
+	StopResponse error
+
+	ReadResourceCalled   bool
+	ReadResourceResponse providers.ReadResourceResponse
+	ReadResourceRequest  providers.ReadResourceRequest
+	ReadResourceFn       func(providers.ReadResourceRequest) providers.ReadResourceResponse
+
+	PlanResourceChangeCalled   bool
+	PlanResourceChangeResponse providers.PlanResourceChangeResponse
+	PlanResourceChangeRequest  providers.PlanResourceChangeRequest
+	PlanResourceChangeFn       func(providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse
+
+	ApplyResourceChangeCalled   bool
+	ApplyResourceChangeResponse providers.ApplyResourceChangeResponse
+	ApplyResourceChangeRequest  providers.ApplyResourceChangeRequest
+	ApplyResourceChangeFn       func(providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse
+
+	ImportResourceStateCalled   bool
+	ImportResourceStateResponse providers.ImportResourceStateResponse
+	ImportResourceStateRequest  providers.ImportResourceStateRequest
+	ImportResourceStateFn       func(providers.ImportResourceStateRequest) providers.ImportResourceStateResponse
+	// Legacy return type for existing tests, which will be shimmed into an
+	// ImportResourceStateResponse if set
+	ImportStateReturn []*InstanceState
+
+	ReadDataSourceCalled   bool
+	ReadDataSourceResponse providers.ReadDataSourceResponse
+	ReadDataSourceRequest  providers.ReadDataSourceRequest
+	ReadDataSourceFn       func(providers.ReadDataSourceRequest) providers.ReadDataSourceResponse
+
+	CloseCalled bool
+	CloseError  error
+}
+
+func (p *MockProvider) GetProviderSchema() providers.GetProviderSchemaResponse {
+	p.Lock()
+	defer p.Unlock()
+	p.GetSchemaCalled = true
+	return p.getSchema()
+}
+
+func (p *MockProvider) getSchema() providers.GetProviderSchemaResponse {
+	// This version of getSchema doesn't do any locking, so it's suitable to
+	// call from other methods of this mock as long as they are already
+	// holding the lock.
+
+	ret := providers.GetProviderSchemaResponse{
+		Provider:      providers.Schema{},
+		DataSources:   map[string]providers.Schema{},
+		ResourceTypes: map[string]providers.Schema{},
+	}
+	if p.GetSchemaReturn != nil {
+		ret.Provider.Block = p.GetSchemaReturn.Provider
+		ret.ProviderMeta.Block = p.GetSchemaReturn.ProviderMeta
+		for n, s := range p.GetSchemaReturn.DataSources {
+			ret.DataSources[n] = providers.Schema{
+				Block: s,
+			}
+		}
+		for n, s := range p.GetSchemaReturn.ResourceTypes {
+			ret.ResourceTypes[n] = providers.Schema{
+				Version: int64(p.GetSchemaReturn.ResourceTypeSchemaVersions[n]),
+				Block:   s,
+			}
+		}
+	}
+
+	return ret
+}
+
+func (p *MockProvider) ValidateProviderConfig(r providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ValidateProviderConfigCalled = true
+	p.ValidateProviderConfigRequest = r
+	if p.ValidateProviderConfigFn != nil {
+		return p.ValidateProviderConfigFn(r)
+	}
+	return p.ValidateProviderConfigResponse
+}
+
+func (p *MockProvider) ValidateResourceConfig(r providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ValidateResourceConfigCalled = true
+	p.ValidateResourceConfigRequest = r
+
+	if p.ValidateResourceConfigFn != nil {
+		return p.ValidateResourceConfigFn(r)
+	}
+
+	return p.ValidateResourceConfigResponse
+}
+
+func (p *MockProvider) ValidateDataResourceConfig(r providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ValidateDataResourceConfigCalled = true
+	p.ValidateDataResourceConfigRequest = r
+
+	if p.ValidateDataResourceConfigFn != nil {
+		return p.ValidateDataResourceConfigFn(r)
+	}
+
+	return p.ValidateDataResourceConfigResponse
+}
+
+func (p *MockProvider) UpgradeResourceState(r providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse {
+	p.Lock()
+	defer p.Unlock()
+
+	schemas := p.getSchema()
+	schema := schemas.ResourceTypes[r.TypeName]
+	schemaType := schema.Block.ImpliedType()
+
+	p.UpgradeResourceStateCalled = true
+	p.UpgradeResourceStateRequest = r
+
+	if p.UpgradeResourceStateFn != nil {
+		return p.UpgradeResourceStateFn(r)
+	}
+
+	resp := p.UpgradeResourceStateResponse
+
+	if resp.UpgradedState == cty.NilVal {
+		switch {
+		case r.RawStateFlatmap != nil:
+			v, err := hcl2shim.HCL2ValueFromFlatmap(r.RawStateFlatmap, schemaType)
+			if err != nil {
+				resp.Diagnostics = resp.Diagnostics.Append(err)
+				return resp
+			}
+			resp.UpgradedState = v
+		case len(r.RawStateJSON) > 0:
+			v, err := ctyjson.Unmarshal(r.RawStateJSON, schemaType)
+
+			if err != nil {
+				resp.Diagnostics = resp.Diagnostics.Append(err)
+				return resp
+			}
+			resp.UpgradedState = v
+		}
+	}
+	return resp
+}
+
+func (p *MockProvider) ConfigureProvider(r providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ConfigureProviderCalled = true
+	p.ConfigureProviderRequest = r
+
+	if p.ConfigureProviderFn != nil {
+		return p.ConfigureProviderFn(r)
+	}
+
+	return p.ConfigureProviderResponse
+}
+
+func (p *MockProvider) Stop() error {
+	// We intentionally don't lock in this one because the whole point of this
+	// method is to be called concurrently with another operation that can
+	// be cancelled.  The provider itself is responsible for handling
+	// any concurrency concerns in this case.
+
+	p.StopCalled = true
+	if p.StopFn != nil {
+		return p.StopFn()
+	}
+
+	return p.StopResponse
+}
+
+func (p *MockProvider) ReadResource(r providers.ReadResourceRequest) providers.ReadResourceResponse {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ReadResourceCalled = true
+	p.ReadResourceRequest = r
+
+	if p.ReadResourceFn != nil {
+		return p.ReadResourceFn(r)
+	}
+
+	resp := p.ReadResourceResponse
+	if resp.NewState != cty.NilVal {
+		// make sure the NewState fits the schema
+		// This isn't always the case for the existing tests
+		newState, err := p.GetSchemaReturn.ResourceTypes[r.TypeName].CoerceValue(resp.NewState)
+		if err != nil {
+			panic(err)
+		}
+		resp.NewState = newState
+		return resp
+	}
+
+	// just return the same state we received
+	resp.NewState = r.PriorState
+	return resp
+}
+
+func (p *MockProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+	p.Lock()
+	defer p.Unlock()
+
+	p.PlanResourceChangeCalled = true
+	p.PlanResourceChangeRequest = r
+
+	if p.PlanResourceChangeFn != nil {
+		return p.PlanResourceChangeFn(r)
+	}
+
+	return p.PlanResourceChangeResponse
+}
+
+func (p *MockProvider) ApplyResourceChange(r providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+	p.Lock()
+	p.ApplyResourceChangeCalled = true
+	p.ApplyResourceChangeRequest = r
+	p.Unlock()
+
+	if p.ApplyResourceChangeFn != nil {
+		return p.ApplyResourceChangeFn(r)
+	}
+
+	return p.ApplyResourceChangeResponse
+}
+
+func (p *MockProvider) ImportResourceState(r providers.ImportResourceStateRequest) providers.ImportResourceStateResponse {
+	p.Lock()
+	defer p.Unlock()
+
+	if p.ImportStateReturn != nil {
+		for _, is := range p.ImportStateReturn {
+			if is.Attributes == nil {
+				is.Attributes = make(map[string]string)
+			}
+			is.Attributes["id"] = is.ID
+
+			typeName := is.Ephemeral.Type
+			// Use the requested type if the resource has no type of it's own.
+			// We still return the empty type, which will error, but this prevents a panic.
+			if typeName == "" {
+				typeName = r.TypeName
+			}
+
+			schema := p.GetSchemaReturn.ResourceTypes[typeName]
+			if schema == nil {
+				panic("no schema found for " + typeName)
+			}
+
+			private, err := json.Marshal(is.Meta)
+			if err != nil {
+				panic(err)
+			}
+
+			state, err := hcl2shim.HCL2ValueFromFlatmap(is.Attributes, schema.ImpliedType())
+			if err != nil {
+				panic(err)
+			}
+
+			state, err = schema.CoerceValue(state)
+			if err != nil {
+				panic(err)
+			}
+
+			p.ImportResourceStateResponse.ImportedResources = append(
+				p.ImportResourceStateResponse.ImportedResources,
+				providers.ImportedResource{
+					TypeName: is.Ephemeral.Type,
+					State:    state,
+					Private:  private,
+				})
+		}
+	}
+
+	p.ImportResourceStateCalled = true
+	p.ImportResourceStateRequest = r
+	if p.ImportResourceStateFn != nil {
+		return p.ImportResourceStateFn(r)
+	}
+
+	return p.ImportResourceStateResponse
+}
+
+func (p *MockProvider) ReadDataSource(r providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ReadDataSourceCalled = true
+	p.ReadDataSourceRequest = r
+
+	if p.ReadDataSourceFn != nil {
+		return p.ReadDataSourceFn(r)
+	}
+
+	return p.ReadDataSourceResponse
+}
+
+func (p *MockProvider) Close() error {
+	p.CloseCalled = true
+	return p.CloseError
+}
diff --git a/v1.5.7/internal/legacy/terraform/provisioner_mock.go b/v1.5.7/internal/legacy/terraform/provisioner_mock.go
new file mode 100644
index 0000000..f2ffd82
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/provisioner_mock.go
@@ -0,0 +1,107 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/provisioners"
+)
+
+var _ provisioners.Interface = (*MockProvisioner)(nil)
+
+// MockProvisioner implements provisioners.Interface but mocks out all the
+// calls for testing purposes.
+type MockProvisioner struct {
+	sync.Mutex
+	// Anything you want, in case you need to store extra data with the mock.
+	Meta interface{}
+
+	GetSchemaCalled   bool
+	GetSchemaResponse provisioners.GetSchemaResponse
+
+	ValidateProvisionerConfigCalled   bool
+	ValidateProvisionerConfigRequest  provisioners.ValidateProvisionerConfigRequest
+	ValidateProvisionerConfigResponse provisioners.ValidateProvisionerConfigResponse
+	ValidateProvisionerConfigFn       func(provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse
+
+	ProvisionResourceCalled   bool
+	ProvisionResourceRequest  provisioners.ProvisionResourceRequest
+	ProvisionResourceResponse provisioners.ProvisionResourceResponse
+	ProvisionResourceFn       func(provisioners.ProvisionResourceRequest) provisioners.ProvisionResourceResponse
+
+	StopCalled   bool
+	StopResponse error
+	StopFn       func() error
+
+	CloseCalled   bool
+	CloseResponse error
+	CloseFn       func() error
+}
+
+func (p *MockProvisioner) GetSchema() provisioners.GetSchemaResponse {
+	p.Lock()
+	defer p.Unlock()
+
+	p.GetSchemaCalled = true
+	return p.getSchema()
+}
+
+// getSchema is the implementation of GetSchema, which can be called from other
+// methods on MockProvisioner that may already be holding the lock.
+func (p *MockProvisioner) getSchema() provisioners.GetSchemaResponse {
+	return p.GetSchemaResponse
+}
+
+func (p *MockProvisioner) ValidateProvisionerConfig(r provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ValidateProvisionerConfigCalled = true
+	p.ValidateProvisionerConfigRequest = r
+	if p.ValidateProvisionerConfigFn != nil {
+		return p.ValidateProvisionerConfigFn(r)
+	}
+	return p.ValidateProvisionerConfigResponse
+}
+
+func (p *MockProvisioner) ProvisionResource(r provisioners.ProvisionResourceRequest) provisioners.ProvisionResourceResponse {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ProvisionResourceCalled = true
+	p.ProvisionResourceRequest = r
+	if p.ProvisionResourceFn != nil {
+		fn := p.ProvisionResourceFn
+		return fn(r)
+	}
+
+	return p.ProvisionResourceResponse
+}
+
+func (p *MockProvisioner) Stop() error {
+	// We intentionally don't lock in this one because the whole point of this
+	// method is to be called concurrently with another operation that can
+	// be cancelled. The provisioner itself is responsible for handling
+	// any concurrency concerns in this case.
+
+	p.StopCalled = true
+	if p.StopFn != nil {
+		return p.StopFn()
+	}
+
+	return p.StopResponse
+}
+
+func (p *MockProvisioner) Close() error {
+	p.Lock()
+	defer p.Unlock()
+
+	p.CloseCalled = true
+	if p.CloseFn != nil {
+		return p.CloseFn()
+	}
+
+	return p.CloseResponse
+}
diff --git a/v1.5.7/internal/legacy/terraform/resource.go b/v1.5.7/internal/legacy/terraform/resource.go
new file mode 100644
index 0000000..f6ff18f
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/resource.go
@@ -0,0 +1,519 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"reflect"
+	"sort"
+	"strconv"
+	"strings"
+
+	"github.com/mitchellh/copystructure"
+	"github.com/mitchellh/reflectwalk"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+)
+
+// Resource is a legacy way to identify a particular resource instance.
+//
+// New code should use addrs.ResourceInstance instead. This is still here
+// only for codepaths that haven't been updated yet.
+type Resource struct {
+	// These are all used by the new EvalNode stuff.
+	Name       string
+	Type       string
+	CountIndex int
+
+	// These aren't really used anymore anywhere, but we keep them around
+	// since we haven't done a proper cleanup yet.
+	Id           string
+	Info         *InstanceInfo
+	Config       *ResourceConfig
+	Dependencies []string
+	Diff         *InstanceDiff
+	Provider     ResourceProvider
+	State        *InstanceState
+	Flags        ResourceFlag
+}
+
+// NewResource constructs a legacy Resource object from an
+// addrs.ResourceInstance value.
+//
+// This is provided to shim to old codepaths that haven't been updated away
+// from this type yet. Since this old type is not able to represent instances
+// that have string keys, this function will panic if given a resource address
+// that has a string key.
+func NewResource(addr addrs.ResourceInstance) *Resource {
+	ret := &Resource{
+		Name: addr.Resource.Name,
+		Type: addr.Resource.Type,
+	}
+
+	if addr.Key != addrs.NoKey {
+		switch tk := addr.Key.(type) {
+		case addrs.IntKey:
+			ret.CountIndex = int(tk)
+		default:
+			panic(fmt.Errorf("resource instance with key %#v is not supported", addr.Key))
+		}
+	}
+
+	return ret
+}
+
+// ResourceKind specifies what kind of instance we're working with, whether
+// its a primary instance, a tainted instance, or an orphan.
+type ResourceFlag byte
+
+// InstanceInfo is used to hold information about the instance and/or
+// resource being modified.
+type InstanceInfo struct {
+	// Id is a unique name to represent this instance. This is not related
+	// to InstanceState.ID in any way.
+	Id string
+
+	// ModulePath is the complete path of the module containing this
+	// instance.
+	ModulePath []string
+
+	// Type is the resource type of this instance
+	Type string
+
+	// uniqueExtra is an internal field that can be populated to supply
+	// extra metadata that is used to identify a unique instance in
+	// the graph walk. This will be appended to HumanID when uniqueId
+	// is called.
+	uniqueExtra string
+}
+
+// NewInstanceInfo constructs an InstanceInfo from an addrs.AbsResourceInstance.
+//
+// InstanceInfo is a legacy type, and uses of it should be gradually replaced
+// by direct use of addrs.AbsResource or addrs.AbsResourceInstance as
+// appropriate.
+//
+// The legacy InstanceInfo type cannot represent module instances with instance
+// keys, so this function will panic if given such a path. Uses of this type
+// should all be removed or replaced before implementing "count" and "for_each"
+// arguments on modules in order to avoid such panics.
+//
+// This legacy type also cannot represent resource instances with string
+// instance keys. It will panic if the given key is not either NoKey or an
+// IntKey.
+func NewInstanceInfo(addr addrs.AbsResourceInstance) *InstanceInfo {
+	// We need an old-style []string module path for InstanceInfo.
+	path := make([]string, len(addr.Module))
+	for i, step := range addr.Module {
+		if step.InstanceKey != addrs.NoKey {
+			panic("NewInstanceInfo cannot convert module instance with key")
+		}
+		path[i] = step.Name
+	}
+
+	// This is a funny old meaning of "id" that is no longer current. It should
+	// not be used for anything users might see. Note that it does not include
+	// a representation of the resource mode, and so it's impossible to
+	// determine from an InstanceInfo alone whether it is a managed or data
+	// resource that is being referred to.
+	id := fmt.Sprintf("%s.%s", addr.Resource.Resource.Type, addr.Resource.Resource.Name)
+	if addr.Resource.Resource.Mode == addrs.DataResourceMode {
+		id = "data." + id
+	}
+	if addr.Resource.Key != addrs.NoKey {
+		switch k := addr.Resource.Key.(type) {
+		case addrs.IntKey:
+			id = id + fmt.Sprintf(".%d", int(k))
+		default:
+			panic(fmt.Sprintf("NewInstanceInfo cannot convert resource instance with %T instance key", addr.Resource.Key))
+		}
+	}
+
+	return &InstanceInfo{
+		Id:         id,
+		ModulePath: path,
+		Type:       addr.Resource.Resource.Type,
+	}
+}
+
+// ResourceAddress returns the address of the resource that the receiver is describing.
+func (i *InstanceInfo) ResourceAddress() *ResourceAddress {
+	// GROSS: for tainted and deposed instances, their status gets appended
+	// to i.Id to create a unique id for the graph node. Historically these
+	// ids were displayed to the user, so it's designed to be human-readable:
+	//   "aws_instance.bar.0 (deposed #0)"
+	//
+	// So here we detect such suffixes and try to interpret them back to
+	// their original meaning so we can then produce a ResourceAddress
+	// with a suitable InstanceType.
+	id := i.Id
+	instanceType := TypeInvalid
+	if idx := strings.Index(id, " ("); idx != -1 {
+		remain := id[idx:]
+		id = id[:idx]
+
+		switch {
+		case strings.Contains(remain, "tainted"):
+			instanceType = TypeTainted
+		case strings.Contains(remain, "deposed"):
+			instanceType = TypeDeposed
+		}
+	}
+
+	addr, err := parseResourceAddressInternal(id)
+	if err != nil {
+		// should never happen, since that would indicate a bug in the
+		// code that constructed this InstanceInfo.
+		panic(fmt.Errorf("InstanceInfo has invalid Id %s", id))
+	}
+	if len(i.ModulePath) > 1 {
+		addr.Path = i.ModulePath[1:] // trim off "root" prefix, which is implied
+	}
+	if instanceType != TypeInvalid {
+		addr.InstanceTypeSet = true
+		addr.InstanceType = instanceType
+	}
+	return addr
+}
+
+// ResourceConfig is a legacy type that was formerly used to represent
+// interpolatable configuration blocks. It is now only used to shim to old
+// APIs that still use this type, via NewResourceConfigShimmed.
+type ResourceConfig struct {
+	ComputedKeys []string
+	Raw          map[string]interface{}
+	Config       map[string]interface{}
+}
+
+// NewResourceConfigRaw constructs a ResourceConfig whose content is exactly
+// the given value.
+//
+// The given value may contain hcl2shim.UnknownVariableValue to signal that
+// something is computed, but it must not contain unprocessed interpolation
+// sequences as we might've seen in Terraform v0.11 and prior.
+func NewResourceConfigRaw(raw map[string]interface{}) *ResourceConfig {
+	v := hcl2shim.HCL2ValueFromConfigValue(raw)
+
+	// This is a little weird but we round-trip the value through the hcl2shim
+	// package here for two reasons: firstly, because that reduces the risk
+	// of it including something unlike what NewResourceConfigShimmed would
+	// produce, and secondly because it creates a copy of "raw" just in case
+	// something is relying on the fact that in the old world the raw and
+	// config maps were always distinct, and thus you could in principle mutate
+	// one without affecting the other. (I sure hope nobody was doing that, though!)
+	cfg := hcl2shim.ConfigValueFromHCL2(v).(map[string]interface{})
+
+	return &ResourceConfig{
+		Raw:    raw,
+		Config: cfg,
+
+		ComputedKeys: newResourceConfigShimmedComputedKeys(v, ""),
+	}
+}
+
+// NewResourceConfigShimmed wraps a cty.Value of object type in a legacy
+// ResourceConfig object, so that it can be passed to older APIs that expect
+// this wrapping.
+//
+// The returned ResourceConfig is already interpolated and cannot be
+// re-interpolated. It is, therefore, useful only to functions that expect
+// an already-populated ResourceConfig which they then treat as read-only.
+//
+// If the given value is not of an object type that conforms to the given
+// schema then this function will panic.
+func NewResourceConfigShimmed(val cty.Value, schema *configschema.Block) *ResourceConfig {
+	if !val.Type().IsObjectType() {
+		panic(fmt.Errorf("NewResourceConfigShimmed given %#v; an object type is required", val.Type()))
+	}
+	ret := &ResourceConfig{}
+
+	legacyVal := hcl2shim.ConfigValueFromHCL2Block(val, schema)
+	if legacyVal != nil {
+		ret.Config = legacyVal
+
+		// Now we need to walk through our structure and find any unknown values,
+		// producing the separate list ComputedKeys to represent these. We use the
+		// schema here so that we can preserve the expected invariant
+		// that an attribute is always either wholly known or wholly unknown, while
+		// a child block can be partially unknown.
+		ret.ComputedKeys = newResourceConfigShimmedComputedKeys(val, "")
+	} else {
+		ret.Config = make(map[string]interface{})
+	}
+	ret.Raw = ret.Config
+
+	return ret
+}
+
+// Record the any config values in ComputedKeys. This field had been unused in
+// helper/schema, but in the new protocol we're using this so that the SDK can
+// now handle having an unknown collection. The legacy diff code doesn't
+// properly handle the unknown, because it can't be expressed in the same way
+// between the config and diff.
+func newResourceConfigShimmedComputedKeys(val cty.Value, path string) []string {
+	var ret []string
+	ty := val.Type()
+
+	if val.IsNull() {
+		return ret
+	}
+
+	if !val.IsKnown() {
+		// we shouldn't have an entirely unknown resource, but prevent empty
+		// strings just in case
+		if len(path) > 0 {
+			ret = append(ret, path)
+		}
+		return ret
+	}
+
+	if path != "" {
+		path += "."
+	}
+	switch {
+	case ty.IsListType(), ty.IsTupleType(), ty.IsSetType():
+		i := 0
+		for it := val.ElementIterator(); it.Next(); i++ {
+			_, subVal := it.Element()
+			keys := newResourceConfigShimmedComputedKeys(subVal, fmt.Sprintf("%s%d", path, i))
+			ret = append(ret, keys...)
+		}
+
+	case ty.IsMapType(), ty.IsObjectType():
+		for it := val.ElementIterator(); it.Next(); {
+			subK, subVal := it.Element()
+			keys := newResourceConfigShimmedComputedKeys(subVal, fmt.Sprintf("%s%s", path, subK.AsString()))
+			ret = append(ret, keys...)
+		}
+	}
+
+	return ret
+}
+
+// DeepCopy performs a deep copy of the configuration. This makes it safe
+// to modify any of the structures that are part of the resource config without
+// affecting the original configuration.
+func (c *ResourceConfig) DeepCopy() *ResourceConfig {
+	// DeepCopying a nil should return a nil to avoid panics
+	if c == nil {
+		return nil
+	}
+
+	// Copy, this will copy all the exported attributes
+	copy, err := copystructure.Config{Lock: true}.Copy(c)
+	if err != nil {
+		panic(err)
+	}
+
+	// Force the type
+	result := copy.(*ResourceConfig)
+
+	return result
+}
+
+// Equal checks the equality of two resource configs.
+func (c *ResourceConfig) Equal(c2 *ResourceConfig) bool {
+	// If either are nil, then they're only equal if they're both nil
+	if c == nil || c2 == nil {
+		return c == c2
+	}
+
+	// Sort the computed keys so they're deterministic
+	sort.Strings(c.ComputedKeys)
+	sort.Strings(c2.ComputedKeys)
+
+	// Two resource configs if their exported properties are equal.
+	// We don't compare "raw" because it is never used again after
+	// initialization and for all intents and purposes they are equal
+	// if the exported properties are equal.
+	check := [][2]interface{}{
+		{c.ComputedKeys, c2.ComputedKeys},
+		{c.Raw, c2.Raw},
+		{c.Config, c2.Config},
+	}
+	for _, pair := range check {
+		if !reflect.DeepEqual(pair[0], pair[1]) {
+			return false
+		}
+	}
+
+	return true
+}
+
+// CheckSet checks that the given list of configuration keys is
+// properly set. If not, errors are returned for each unset key.
+//
+// This is useful to be called in the Validate method of a ResourceProvider.
+func (c *ResourceConfig) CheckSet(keys []string) []error {
+	var errs []error
+
+	for _, k := range keys {
+		if !c.IsSet(k) {
+			errs = append(errs, fmt.Errorf("%s must be set", k))
+		}
+	}
+
+	return errs
+}
+
+// Get looks up a configuration value by key and returns the value.
+//
+// The second return value is true if the get was successful. Get will
+// return the raw value if the key is computed, so you should pair this
+// with IsComputed.
+func (c *ResourceConfig) Get(k string) (interface{}, bool) {
+	// We aim to get a value from the configuration. If it is computed,
+	// then we return the pure raw value.
+	source := c.Config
+	if c.IsComputed(k) {
+		source = c.Raw
+	}
+
+	return c.get(k, source)
+}
+
+// GetRaw looks up a configuration value by key and returns the value,
+// from the raw, uninterpolated config.
+//
+// The second return value is true if the get was successful. Get will
+// not succeed if the value is being computed.
+func (c *ResourceConfig) GetRaw(k string) (interface{}, bool) {
+	return c.get(k, c.Raw)
+}
+
+// IsComputed returns whether the given key is computed or not.
+func (c *ResourceConfig) IsComputed(k string) bool {
+	// The next thing we do is check the config if we get a computed
+	// value out of it.
+	v, ok := c.get(k, c.Config)
+	if !ok {
+		return false
+	}
+
+	// If value is nil, then it isn't computed
+	if v == nil {
+		return false
+	}
+
+	// Test if the value contains an unknown value
+	var w unknownCheckWalker
+	if err := reflectwalk.Walk(v, &w); err != nil {
+		panic(err)
+	}
+
+	return w.Unknown
+}
+
+// IsSet checks if the key in the configuration is set. A key is set if
+// it has a value or the value is being computed (is unknown currently).
+//
+// This function should be used rather than checking the keys of the
+// raw configuration itself, since a key may be omitted from the raw
+// configuration if it is being computed.
+func (c *ResourceConfig) IsSet(k string) bool {
+	if c == nil {
+		return false
+	}
+
+	if c.IsComputed(k) {
+		return true
+	}
+
+	if _, ok := c.Get(k); ok {
+		return true
+	}
+
+	return false
+}
+
+func (c *ResourceConfig) get(
+	k string, raw map[string]interface{}) (interface{}, bool) {
+	parts := strings.Split(k, ".")
+	if len(parts) == 1 && parts[0] == "" {
+		parts = nil
+	}
+
+	var current interface{} = raw
+	var previous interface{} = nil
+	for i, part := range parts {
+		if current == nil {
+			return nil, false
+		}
+
+		cv := reflect.ValueOf(current)
+		switch cv.Kind() {
+		case reflect.Map:
+			previous = current
+			v := cv.MapIndex(reflect.ValueOf(part))
+			if !v.IsValid() {
+				if i > 0 && i != (len(parts)-1) {
+					tryKey := strings.Join(parts[i:], ".")
+					v := cv.MapIndex(reflect.ValueOf(tryKey))
+					if !v.IsValid() {
+						return nil, false
+					}
+
+					return v.Interface(), true
+				}
+
+				return nil, false
+			}
+
+			current = v.Interface()
+		case reflect.Slice:
+			previous = current
+
+			if part == "#" {
+				// If any value in a list is computed, this whole thing
+				// is computed and we can't read any part of it.
+				for i := 0; i < cv.Len(); i++ {
+					if v := cv.Index(i).Interface(); v == hcl2shim.UnknownVariableValue {
+						return v, true
+					}
+				}
+
+				current = cv.Len()
+			} else {
+				i, err := strconv.ParseInt(part, 0, 0)
+				if err != nil {
+					return nil, false
+				}
+				if int(i) < 0 || int(i) >= cv.Len() {
+					return nil, false
+				}
+				current = cv.Index(int(i)).Interface()
+			}
+		case reflect.String:
+			// This happens when map keys contain "." and have a common
+			// prefix so were split as path components above.
+			actualKey := strings.Join(parts[i-1:], ".")
+			if prevMap, ok := previous.(map[string]interface{}); ok {
+				v, ok := prevMap[actualKey]
+				return v, ok
+			}
+
+			return nil, false
+		default:
+			panic(fmt.Sprintf("Unknown kind: %s", cv.Kind()))
+		}
+	}
+
+	return current, true
+}
+
+// unknownCheckWalker
+type unknownCheckWalker struct {
+	Unknown bool
+}
+
+func (w *unknownCheckWalker) Primitive(v reflect.Value) error {
+	if v.Interface() == hcl2shim.UnknownVariableValue {
+		w.Unknown = true
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/legacy/terraform/resource_address.go b/v1.5.7/internal/legacy/terraform/resource_address.go
new file mode 100644
index 0000000..66fc234
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/resource_address.go
@@ -0,0 +1,623 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"reflect"
+	"regexp"
+	"strconv"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+)
+
+// ResourceAddress is a way of identifying an individual resource (or,
+// eventually, a subset of resources) within the state. It is used for Targets.
+type ResourceAddress struct {
+	// Addresses a resource falling somewhere in the module path
+	// When specified alone, addresses all resources within a module path
+	Path []string
+
+	// Addresses a specific resource that occurs in a list
+	Index int
+
+	InstanceType    InstanceType
+	InstanceTypeSet bool
+	Name            string
+	Type            string
+	Mode            ResourceMode // significant only if InstanceTypeSet
+}
+
+// Copy returns a copy of this ResourceAddress
+func (r *ResourceAddress) Copy() *ResourceAddress {
+	if r == nil {
+		return nil
+	}
+
+	n := &ResourceAddress{
+		Path:         make([]string, 0, len(r.Path)),
+		Index:        r.Index,
+		InstanceType: r.InstanceType,
+		Name:         r.Name,
+		Type:         r.Type,
+		Mode:         r.Mode,
+	}
+
+	n.Path = append(n.Path, r.Path...)
+
+	return n
+}
+
+// String outputs the address that parses into this address.
+func (r *ResourceAddress) String() string {
+	var result []string
+	for _, p := range r.Path {
+		result = append(result, "module", p)
+	}
+
+	switch r.Mode {
+	case ManagedResourceMode:
+		// nothing to do
+	case DataResourceMode:
+		result = append(result, "data")
+	default:
+		panic(fmt.Errorf("unsupported resource mode %s", r.Mode))
+	}
+
+	if r.Type != "" {
+		result = append(result, r.Type)
+	}
+
+	if r.Name != "" {
+		name := r.Name
+		if r.InstanceTypeSet {
+			switch r.InstanceType {
+			case TypePrimary:
+				name += ".primary"
+			case TypeDeposed:
+				name += ".deposed"
+			case TypeTainted:
+				name += ".tainted"
+			}
+		}
+
+		if r.Index >= 0 {
+			name += fmt.Sprintf("[%d]", r.Index)
+		}
+		result = append(result, name)
+	}
+
+	return strings.Join(result, ".")
+}
+
+// HasResourceSpec returns true if the address has a resource spec, as
+// defined in the documentation:
+//
+//	https://www.terraform.io/docs/cli/state/resource-addressing.html
+//
+// In particular, this returns false if the address contains only
+// a module path, thus addressing the entire module.
+func (r *ResourceAddress) HasResourceSpec() bool {
+	return r.Type != "" && r.Name != ""
+}
+
+// WholeModuleAddress returns the resource address that refers to all
+// resources in the same module as the receiver address.
+func (r *ResourceAddress) WholeModuleAddress() *ResourceAddress {
+	return &ResourceAddress{
+		Path:            r.Path,
+		Index:           -1,
+		InstanceTypeSet: false,
+	}
+}
+
+// MatchesResourceConfig returns true if the receiver matches the given
+// configuration resource within the given _static_ module path. Note that
+// the module path in a resource address is a _dynamic_ module path, and
+// multiple dynamic resource paths may map to a single static path if
+// count and for_each are in use on module calls.
+//
+// Since resource configuration blocks represent all of the instances of
+// a multi-instance resource, the index of the address (if any) is not
+// considered.
+func (r *ResourceAddress) MatchesResourceConfig(path addrs.Module, rc *configs.Resource) bool {
+	if r.HasResourceSpec() {
+		// FIXME: Some ugliness while we are between worlds. Functionality
+		// in "addrs" should eventually replace this ResourceAddress idea
+		// completely, but for now we'll need to translate to the old
+		// way of representing resource modes.
+		switch r.Mode {
+		case ManagedResourceMode:
+			if rc.Mode != addrs.ManagedResourceMode {
+				return false
+			}
+		case DataResourceMode:
+			if rc.Mode != addrs.DataResourceMode {
+				return false
+			}
+		}
+		if r.Type != rc.Type || r.Name != rc.Name {
+			return false
+		}
+	}
+
+	addrPath := r.Path
+
+	// normalize
+	if len(addrPath) == 0 {
+		addrPath = nil
+	}
+	if len(path) == 0 {
+		path = nil
+	}
+	rawPath := []string(path)
+	return reflect.DeepEqual(addrPath, rawPath)
+}
+
+// stateId returns the ID that this resource should be entered with
+// in the state. This is also used for diffs. In the future, we'd like to
+// move away from this string field so I don't export this.
+func (r *ResourceAddress) stateId() string {
+	result := fmt.Sprintf("%s.%s", r.Type, r.Name)
+	switch r.Mode {
+	case ManagedResourceMode:
+		// Done
+	case DataResourceMode:
+		result = fmt.Sprintf("data.%s", result)
+	default:
+		panic(fmt.Errorf("unknown resource mode: %s", r.Mode))
+	}
+	if r.Index >= 0 {
+		result += fmt.Sprintf(".%d", r.Index)
+	}
+
+	return result
+}
+
+// parseResourceAddressInternal parses the somewhat bespoke resource
+// identifier used in states and diffs, such as "instance.name.0".
+func parseResourceAddressInternal(s string) (*ResourceAddress, error) {
+	// Split based on ".". Every resource address should have at least two
+	// elements (type and name).
+	parts := strings.Split(s, ".")
+	if len(parts) < 2 || len(parts) > 4 {
+		return nil, fmt.Errorf("Invalid internal resource address format: %s", s)
+	}
+
+	// Data resource if we have at least 3 parts and the first one is data
+	mode := ManagedResourceMode
+	if len(parts) > 2 && parts[0] == "data" {
+		mode = DataResourceMode
+		parts = parts[1:]
+	}
+
+	// If we're not a data resource and we have more than 3, then it is an error
+	if len(parts) > 3 && mode != DataResourceMode {
+		return nil, fmt.Errorf("Invalid internal resource address format: %s", s)
+	}
+
+	// Build the parts of the resource address that are guaranteed to exist
+	addr := &ResourceAddress{
+		Type:         parts[0],
+		Name:         parts[1],
+		Index:        -1,
+		InstanceType: TypePrimary,
+		Mode:         mode,
+	}
+
+	// If we have more parts, then we have an index. Parse that.
+	if len(parts) > 2 {
+		idx, err := strconv.ParseInt(parts[2], 0, 0)
+		if err != nil {
+			return nil, fmt.Errorf("Error parsing resource address %q: %s", s, err)
+		}
+
+		addr.Index = int(idx)
+	}
+
+	return addr, nil
+}
+
+func ParseResourceAddress(s string) (*ResourceAddress, error) {
+	matches, err := tokenizeResourceAddress(s)
+	if err != nil {
+		return nil, err
+	}
+	mode := ManagedResourceMode
+	if matches["data_prefix"] != "" {
+		mode = DataResourceMode
+	}
+	resourceIndex, err := ParseResourceIndex(matches["index"])
+	if err != nil {
+		return nil, err
+	}
+	instanceType, err := ParseInstanceType(matches["instance_type"])
+	if err != nil {
+		return nil, err
+	}
+	path := ParseResourcePath(matches["path"])
+
+	// not allowed to say "data." without a type following
+	if mode == DataResourceMode && matches["type"] == "" {
+		return nil, fmt.Errorf(
+			"invalid resource address %q: must target specific data instance",
+			s,
+		)
+	}
+
+	return &ResourceAddress{
+		Path:            path,
+		Index:           resourceIndex,
+		InstanceType:    instanceType,
+		InstanceTypeSet: matches["instance_type"] != "",
+		Name:            matches["name"],
+		Type:            matches["type"],
+		Mode:            mode,
+	}, nil
+}
+
+// ParseResourceAddressForInstanceDiff creates a ResourceAddress for a
+// resource name as described in a module diff.
+//
+// For historical reasons a different addressing format is used in this
+// context. The internal format should not be shown in the UI and instead
+// this function should be used to translate to a ResourceAddress and
+// then, where appropriate, use the String method to produce a canonical
+// resource address string for display in the UI.
+//
+// The given path slice must be empty (or nil) for the root module, and
+// otherwise consist of a sequence of module names traversing down into
+// the module tree. If a non-nil path is provided, the caller must not
+// modify its underlying array after passing it to this function.
+func ParseResourceAddressForInstanceDiff(path []string, key string) (*ResourceAddress, error) {
+	addr, err := parseResourceAddressInternal(key)
+	if err != nil {
+		return nil, err
+	}
+	addr.Path = path
+	return addr, nil
+}
+
+// NewLegacyResourceAddress creates a ResourceAddress from a new-style
+// addrs.AbsResource value.
+//
+// This is provided for shimming purposes so that we can still easily call into
+// older functions that expect the ResourceAddress type.
+func NewLegacyResourceAddress(addr addrs.AbsResource) *ResourceAddress {
+	ret := &ResourceAddress{
+		Type: addr.Resource.Type,
+		Name: addr.Resource.Name,
+	}
+
+	switch addr.Resource.Mode {
+	case addrs.ManagedResourceMode:
+		ret.Mode = ManagedResourceMode
+	case addrs.DataResourceMode:
+		ret.Mode = DataResourceMode
+	default:
+		panic(fmt.Errorf("cannot shim %s to legacy ResourceMode value", addr.Resource.Mode))
+	}
+
+	path := make([]string, len(addr.Module))
+	for i, step := range addr.Module {
+		if step.InstanceKey != addrs.NoKey {
+			// At the time of writing this can't happen because we don't
+			// ket generate keyed module instances. This legacy codepath must
+			// be removed before we can support "count" and "for_each" for
+			// modules.
+			panic(fmt.Errorf("cannot shim module instance step with key %#v to legacy ResourceAddress.Path", step.InstanceKey))
+		}
+
+		path[i] = step.Name
+	}
+	ret.Path = path
+	ret.Index = -1
+
+	return ret
+}
+
+// NewLegacyResourceInstanceAddress creates a ResourceAddress from a new-style
+// addrs.AbsResource value.
+//
+// This is provided for shimming purposes so that we can still easily call into
+// older functions that expect the ResourceAddress type.
+func NewLegacyResourceInstanceAddress(addr addrs.AbsResourceInstance) *ResourceAddress {
+	ret := &ResourceAddress{
+		Type: addr.Resource.Resource.Type,
+		Name: addr.Resource.Resource.Name,
+	}
+
+	switch addr.Resource.Resource.Mode {
+	case addrs.ManagedResourceMode:
+		ret.Mode = ManagedResourceMode
+	case addrs.DataResourceMode:
+		ret.Mode = DataResourceMode
+	default:
+		panic(fmt.Errorf("cannot shim %s to legacy ResourceMode value", addr.Resource.Resource.Mode))
+	}
+
+	path := make([]string, len(addr.Module))
+	for i, step := range addr.Module {
+		if step.InstanceKey != addrs.NoKey {
+			// At the time of writing this can't happen because we don't
+			// ket generate keyed module instances. This legacy codepath must
+			// be removed before we can support "count" and "for_each" for
+			// modules.
+			panic(fmt.Errorf("cannot shim module instance step with key %#v to legacy ResourceAddress.Path", step.InstanceKey))
+		}
+
+		path[i] = step.Name
+	}
+	ret.Path = path
+
+	if addr.Resource.Key == addrs.NoKey {
+		ret.Index = -1
+	} else if ik, ok := addr.Resource.Key.(addrs.IntKey); ok {
+		ret.Index = int(ik)
+	} else if _, ok := addr.Resource.Key.(addrs.StringKey); ok {
+		ret.Index = -1
+	} else {
+		panic(fmt.Errorf("cannot shim resource instance with key %#v to legacy ResourceAddress.Index", addr.Resource.Key))
+	}
+
+	return ret
+}
+
+// AbsResourceInstanceAddr converts the receiver, a legacy resource address, to
+// the new resource address type addrs.AbsResourceInstance.
+//
+// This method can be used only on an address that has a resource specification.
+// It will panic if called on a module-path-only ResourceAddress. Use
+// method HasResourceSpec to check before calling, in contexts where it is
+// unclear.
+//
+// addrs.AbsResourceInstance does not represent the "tainted" and "deposed"
+// states, and so if these are present on the receiver then they are discarded.
+//
+// This is provided for shimming purposes so that we can easily adapt functions
+// that are returning the legacy ResourceAddress type, for situations where
+// the new type is required.
+func (addr *ResourceAddress) AbsResourceInstanceAddr() addrs.AbsResourceInstance {
+	if !addr.HasResourceSpec() {
+		panic("AbsResourceInstanceAddr called on ResourceAddress with no resource spec")
+	}
+
+	ret := addrs.AbsResourceInstance{
+		Module: addr.ModuleInstanceAddr(),
+		Resource: addrs.ResourceInstance{
+			Resource: addrs.Resource{
+				Type: addr.Type,
+				Name: addr.Name,
+			},
+		},
+	}
+
+	switch addr.Mode {
+	case ManagedResourceMode:
+		ret.Resource.Resource.Mode = addrs.ManagedResourceMode
+	case DataResourceMode:
+		ret.Resource.Resource.Mode = addrs.DataResourceMode
+	default:
+		panic(fmt.Errorf("cannot shim %s to addrs.ResourceMode value", addr.Mode))
+	}
+
+	if addr.Index != -1 {
+		ret.Resource.Key = addrs.IntKey(addr.Index)
+	}
+
+	return ret
+}
+
+// ModuleInstanceAddr returns the module path portion of the receiver as a
+// addrs.ModuleInstance value.
+func (addr *ResourceAddress) ModuleInstanceAddr() addrs.ModuleInstance {
+	path := make(addrs.ModuleInstance, len(addr.Path))
+	for i, name := range addr.Path {
+		path[i] = addrs.ModuleInstanceStep{Name: name}
+	}
+	return path
+}
+
+// Contains returns true if and only if the given node is contained within
+// the receiver.
+//
+// Containment is defined in terms of the module and resource hierarchy:
+// a resource is contained within its module and any ancestor modules,
+// an indexed resource instance is contained with the unindexed resource, etc.
+func (addr *ResourceAddress) Contains(other *ResourceAddress) bool {
+	ourPath := addr.Path
+	givenPath := other.Path
+	if len(givenPath) < len(ourPath) {
+		return false
+	}
+	for i := range ourPath {
+		if ourPath[i] != givenPath[i] {
+			return false
+		}
+	}
+
+	// If the receiver is a whole-module address then the path prefix
+	// matching is all we need.
+	if !addr.HasResourceSpec() {
+		return true
+	}
+
+	if addr.Type != other.Type || addr.Name != other.Name || addr.Mode != other.Mode {
+		return false
+	}
+
+	if addr.Index != -1 && addr.Index != other.Index {
+		return false
+	}
+
+	if addr.InstanceTypeSet && (addr.InstanceTypeSet != other.InstanceTypeSet || addr.InstanceType != other.InstanceType) {
+		return false
+	}
+
+	return true
+}
+
+// Equals returns true if the receiver matches the given address.
+//
+// The name of this method is a misnomer, since it doesn't test for exact
+// equality. Instead, it tests that the _specified_ parts of each
+// address match, treating any unspecified parts as wildcards.
+//
+// See also Contains, which takes a more hierarchical approach to comparing
+// addresses.
+func (addr *ResourceAddress) Equals(raw interface{}) bool {
+	other, ok := raw.(*ResourceAddress)
+	if !ok {
+		return false
+	}
+
+	pathMatch := len(addr.Path) == 0 && len(other.Path) == 0 ||
+		reflect.DeepEqual(addr.Path, other.Path)
+
+	indexMatch := addr.Index == -1 ||
+		other.Index == -1 ||
+		addr.Index == other.Index
+
+	nameMatch := addr.Name == "" ||
+		other.Name == "" ||
+		addr.Name == other.Name
+
+	typeMatch := addr.Type == "" ||
+		other.Type == "" ||
+		addr.Type == other.Type
+
+	// mode is significant only when type is set
+	modeMatch := addr.Type == "" ||
+		other.Type == "" ||
+		addr.Mode == other.Mode
+
+	return pathMatch &&
+		indexMatch &&
+		addr.InstanceType == other.InstanceType &&
+		nameMatch &&
+		typeMatch &&
+		modeMatch
+}
+
+// Less returns true if and only if the receiver should be sorted before
+// the given address when presenting a list of resource addresses to
+// an end-user.
+//
+// This sort uses lexicographic sorting for most components, but uses
+// numeric sort for indices, thus causing index 10 to sort after
+// index 9, rather than after index 1.
+func (addr *ResourceAddress) Less(other *ResourceAddress) bool {
+
+	switch {
+
+	case len(addr.Path) != len(other.Path):
+		return len(addr.Path) < len(other.Path)
+
+	case !reflect.DeepEqual(addr.Path, other.Path):
+		// If the two paths are the same length but don't match, we'll just
+		// cheat and compare the string forms since it's easier than
+		// comparing all of the path segments in turn, and lexicographic
+		// comparison is correct for the module path portion.
+		addrStr := addr.String()
+		otherStr := other.String()
+		return addrStr < otherStr
+
+	case addr.Mode != other.Mode:
+		return addr.Mode == DataResourceMode
+
+	case addr.Type != other.Type:
+		return addr.Type < other.Type
+
+	case addr.Name != other.Name:
+		return addr.Name < other.Name
+
+	case addr.Index != other.Index:
+		// Since "Index" is -1 for an un-indexed address, this also conveniently
+		// sorts unindexed addresses before indexed ones, should they both
+		// appear for some reason.
+		return addr.Index < other.Index
+
+	case addr.InstanceTypeSet != other.InstanceTypeSet:
+		return !addr.InstanceTypeSet
+
+	case addr.InstanceType != other.InstanceType:
+		// InstanceType is actually an enum, so this is just an arbitrary
+		// sort based on the enum numeric values, and thus not particularly
+		// meaningful.
+		return addr.InstanceType < other.InstanceType
+
+	default:
+		return false
+
+	}
+}
+
+func ParseResourceIndex(s string) (int, error) {
+	if s == "" {
+		return -1, nil
+	}
+	return strconv.Atoi(s)
+}
+
+func ParseResourcePath(s string) []string {
+	if s == "" {
+		return nil
+	}
+	parts := strings.Split(s, ".")
+	path := make([]string, 0, len(parts))
+	for _, s := range parts {
+		// Due to the limitations of the regexp match below, the path match has
+		// some noise in it we have to filter out :|
+		if s == "" || s == "module" {
+			continue
+		}
+		path = append(path, s)
+	}
+	return path
+}
+
+func ParseInstanceType(s string) (InstanceType, error) {
+	switch s {
+	case "", "primary":
+		return TypePrimary, nil
+	case "deposed":
+		return TypeDeposed, nil
+	case "tainted":
+		return TypeTainted, nil
+	default:
+		return TypeInvalid, fmt.Errorf("Unexpected value for InstanceType field: %q", s)
+	}
+}
+
+func tokenizeResourceAddress(s string) (map[string]string, error) {
+	// Example of portions of the regexp below using the
+	// string "aws_instance.web.tainted[1]"
+	re := regexp.MustCompile(`\A` +
+		// "module.foo.module.bar" (optional)
+		`(?P<path>(?:module\.(?P<module_name>[^.]+)\.?)*)` +
+		// possibly "data.", if targeting is a data resource
+		`(?P<data_prefix>(?:data\.)?)` +
+		// "aws_instance.web" (optional when module path specified)
+		`(?:(?P<type>[^.]+)\.(?P<name>[^.[]+))?` +
+		// "tainted" (optional, omission implies: "primary")
+		`(?:\.(?P<instance_type>\w+))?` +
+		// "1" (optional, omission implies: "0")
+		`(?:\[(?P<index>\d+)\])?` +
+		`\z`)
+
+	groupNames := re.SubexpNames()
+	rawMatches := re.FindAllStringSubmatch(s, -1)
+	if len(rawMatches) != 1 {
+		return nil, fmt.Errorf("invalid resource address %q", s)
+	}
+
+	matches := make(map[string]string)
+	for i, m := range rawMatches[0] {
+		matches[groupNames[i]] = m
+	}
+
+	return matches, nil
+}
diff --git a/v1.5.7/internal/legacy/terraform/resource_address_test.go b/v1.5.7/internal/legacy/terraform/resource_address_test.go
new file mode 100644
index 0000000..1482850
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/resource_address_test.go
@@ -0,0 +1,1332 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+)
+
+func TestParseResourceAddressInternal(t *testing.T) {
+	cases := map[string]struct {
+		Input    string
+		Expected *ResourceAddress
+		Output   string
+	}{
+		"basic resource": {
+			"aws_instance.foo",
+			&ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			"aws_instance.foo",
+		},
+
+		"basic resource with count": {
+			"aws_instance.foo.1",
+			&ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        1,
+			},
+			"aws_instance.foo[1]",
+		},
+
+		"data resource": {
+			"data.aws_ami.foo",
+			&ResourceAddress{
+				Mode:         DataResourceMode,
+				Type:         "aws_ami",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			"data.aws_ami.foo",
+		},
+
+		"data resource with count": {
+			"data.aws_ami.foo.1",
+			&ResourceAddress{
+				Mode:         DataResourceMode,
+				Type:         "aws_ami",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        1,
+			},
+			"data.aws_ami.foo[1]",
+		},
+
+		"non-data resource with 4 elements": {
+			"aws_instance.foo.bar.1",
+			nil,
+			"",
+		},
+	}
+
+	for tn, tc := range cases {
+		t.Run(tc.Input, func(t *testing.T) {
+			out, err := parseResourceAddressInternal(tc.Input)
+			if (err != nil) != (tc.Expected == nil) {
+				t.Fatalf("%s: unexpected err: %#v", tn, err)
+			}
+			if err != nil {
+				return
+			}
+
+			if !reflect.DeepEqual(out, tc.Expected) {
+				t.Fatalf("bad: %q\n\nexpected:\n%#v\n\ngot:\n%#v", tn, tc.Expected, out)
+			}
+
+			// Compare outputs if those exist
+			expected := tc.Input
+			if tc.Output != "" {
+				expected = tc.Output
+			}
+			if out.String() != expected {
+				t.Fatalf("bad: %q\n\nexpected: %s\n\ngot: %s", tn, expected, out)
+			}
+
+			// Compare equality because the internal parse is used
+			// to compare equality to equal inputs.
+			if !out.Equals(tc.Expected) {
+				t.Fatalf("expected equality:\n\n%#v\n\n%#v", out, tc.Expected)
+			}
+		})
+	}
+}
+
+func TestParseResourceAddress(t *testing.T) {
+	cases := map[string]struct {
+		Input    string
+		Expected *ResourceAddress
+		Output   string
+		Err      bool
+	}{
+		"implicit primary managed instance, no specific index": {
+			"aws_instance.foo",
+			&ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			"",
+			false,
+		},
+		"implicit primary data instance, no specific index": {
+			"data.aws_instance.foo",
+			&ResourceAddress{
+				Mode:         DataResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			"",
+			false,
+		},
+		"implicit primary, explicit index": {
+			"aws_instance.foo[2]",
+			&ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        2,
+			},
+			"",
+			false,
+		},
+		"implicit primary, explicit index over ten": {
+			"aws_instance.foo[12]",
+			&ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        12,
+			},
+			"",
+			false,
+		},
+		"explicit primary, explicit index": {
+			"aws_instance.foo.primary[2]",
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceType:    TypePrimary,
+				InstanceTypeSet: true,
+				Index:           2,
+			},
+			"",
+			false,
+		},
+		"tainted": {
+			"aws_instance.foo.tainted",
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceType:    TypeTainted,
+				InstanceTypeSet: true,
+				Index:           -1,
+			},
+			"",
+			false,
+		},
+		"deposed": {
+			"aws_instance.foo.deposed",
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceType:    TypeDeposed,
+				InstanceTypeSet: true,
+				Index:           -1,
+			},
+			"",
+			false,
+		},
+		"with a hyphen": {
+			"aws_instance.foo-bar",
+			&ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo-bar",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			"",
+			false,
+		},
+		"managed in a module": {
+			"module.child.aws_instance.foo",
+			&ResourceAddress{
+				Path:         []string{"child"},
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			"",
+			false,
+		},
+		"data in a module": {
+			"module.child.data.aws_instance.foo",
+			&ResourceAddress{
+				Path:         []string{"child"},
+				Mode:         DataResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			"",
+			false,
+		},
+		"nested modules": {
+			"module.a.module.b.module.forever.aws_instance.foo",
+			&ResourceAddress{
+				Path:         []string{"a", "b", "forever"},
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			"",
+			false,
+		},
+		"just a module": {
+			"module.a",
+			&ResourceAddress{
+				Path:         []string{"a"},
+				Type:         "",
+				Name:         "",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			"",
+			false,
+		},
+		"just a nested module": {
+			"module.a.module.b",
+			&ResourceAddress{
+				Path:         []string{"a", "b"},
+				Type:         "",
+				Name:         "",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			"",
+			false,
+		},
+		"module missing resource type": {
+			"module.name.foo",
+			nil,
+			"",
+			true,
+		},
+	}
+
+	for tn, tc := range cases {
+		t.Run(tn, func(t *testing.T) {
+			out, err := ParseResourceAddress(tc.Input)
+			if (err != nil) != tc.Err {
+				t.Fatalf("%s: unexpected err: %#v", tn, err)
+			}
+			if tc.Err {
+				return
+			}
+
+			if !reflect.DeepEqual(out, tc.Expected) {
+				t.Fatalf("bad: %q\n\nexpected:\n%#v\n\ngot:\n%#v", tn, tc.Expected, out)
+			}
+
+			expected := tc.Input
+			if tc.Output != "" {
+				expected = tc.Output
+			}
+			if out.String() != expected {
+				t.Fatalf("bad: %q\n\nexpected: %s\n\ngot: %s", tn, expected, out)
+			}
+		})
+	}
+}
+
+func TestResourceAddressContains(t *testing.T) {
+	tests := []struct {
+		Address *ResourceAddress
+		Other   *ResourceAddress
+		Want    bool
+	}{
+		{
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: true,
+				InstanceType:    TypePrimary,
+				Index:           0,
+			},
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: true,
+				InstanceType:    TypePrimary,
+				Index:           0,
+			},
+			true,
+		},
+		{
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: false,
+				Index:           0,
+			},
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: true,
+				InstanceType:    TypePrimary,
+				Index:           0,
+			},
+			true,
+		},
+		{
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: true,
+				InstanceType:    TypePrimary,
+				Index:           0,
+			},
+			true,
+		},
+		{
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			true,
+		},
+		{
+			&ResourceAddress{
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			true,
+		},
+		{
+			&ResourceAddress{
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			&ResourceAddress{
+				Path:            []string{"bar"},
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			true,
+		},
+		{
+			&ResourceAddress{
+				Path:            []string{"bar"},
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			&ResourceAddress{
+				Path:            []string{"bar"},
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			true,
+		},
+		{
+			&ResourceAddress{
+				Path:            []string{"bar"},
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			&ResourceAddress{
+				Path:            []string{"bar", "baz"},
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			true,
+		},
+		{
+			&ResourceAddress{
+				Path:            []string{"bar"},
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			&ResourceAddress{
+				Path:            []string{"bar", "baz"},
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			true,
+		},
+		{
+			&ResourceAddress{
+				Path:            []string{"bar"},
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			&ResourceAddress{
+				Path:            []string{"bar", "baz", "foo", "pizza"},
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			true,
+		},
+
+		{
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "bar",
+				InstanceTypeSet: true,
+				InstanceType:    TypePrimary,
+				Index:           0,
+			},
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: true,
+				InstanceType:    TypePrimary,
+				Index:           0,
+			},
+			false,
+		},
+		{
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: true,
+				InstanceType:    TypePrimary,
+				Index:           0,
+			},
+			&ResourceAddress{
+				Mode:            DataResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: true,
+				InstanceType:    TypePrimary,
+				Index:           0,
+			},
+			false,
+		},
+		{
+			&ResourceAddress{
+				Path:            []string{"bar"},
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			&ResourceAddress{
+				Path:            []string{"baz"},
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			false,
+		},
+		{
+			&ResourceAddress{
+				Path:            []string{"bar"},
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			&ResourceAddress{
+				Path:            []string{"baz", "bar"},
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			false,
+		},
+		{
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: true,
+				InstanceType:    TypePrimary,
+				Index:           0,
+			},
+			&ResourceAddress{
+				Mode:            ManagedResourceMode,
+				Type:            "aws_instance",
+				Name:            "foo",
+				InstanceTypeSet: false,
+				Index:           0,
+			},
+			false,
+		},
+		{
+			&ResourceAddress{
+				Path:            []string{"bar", "baz"},
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			&ResourceAddress{
+				Path:            []string{"bar"},
+				InstanceTypeSet: false,
+				Index:           -1,
+			},
+			false,
+		},
+		{
+			&ResourceAddress{
+				Type:         "aws_instance",
+				Name:         "foo",
+				Index:        1,
+				InstanceType: TypePrimary,
+				Mode:         ManagedResourceMode,
+			},
+			&ResourceAddress{
+				Type:         "aws_instance",
+				Name:         "foo",
+				Index:        -1,
+				InstanceType: TypePrimary,
+				Mode:         ManagedResourceMode,
+			},
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%s contains %s", test.Address, test.Other), func(t *testing.T) {
+			got := test.Address.Contains(test.Other)
+			if got != test.Want {
+				t.Errorf(
+					"wrong result\nrecv:  %s\ngiven: %s\ngot:   %#v\nwant:  %#v",
+					test.Address, test.Other,
+					got, test.Want,
+				)
+			}
+		})
+	}
+}
+
+func TestResourceAddressEquals(t *testing.T) {
+	cases := map[string]struct {
+		Address *ResourceAddress
+		Other   interface{}
+		Expect  bool
+	}{
+		"basic match": {
+			Address: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        0,
+			},
+			Other: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        0,
+			},
+			Expect: true,
+		},
+		"address does not set index": {
+			Address: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			Other: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        3,
+			},
+			Expect: true,
+		},
+		"other does not set index": {
+			Address: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        3,
+			},
+			Other: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			Expect: true,
+		},
+		"neither sets index": {
+			Address: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			Other: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			Expect: true,
+		},
+		"index over ten": {
+			Address: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        1,
+			},
+			Other: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        13,
+			},
+			Expect: false,
+		},
+		"different type": {
+			Address: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        0,
+			},
+			Other: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_vpc",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        0,
+			},
+			Expect: false,
+		},
+		"different mode": {
+			Address: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        0,
+			},
+			Other: &ResourceAddress{
+				Mode:         DataResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        0,
+			},
+			Expect: false,
+		},
+		"different name": {
+			Address: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        0,
+			},
+			Other: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "bar",
+				InstanceType: TypePrimary,
+				Index:        0,
+			},
+			Expect: false,
+		},
+		"different instance type": {
+			Address: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        0,
+			},
+			Other: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypeTainted,
+				Index:        0,
+			},
+			Expect: false,
+		},
+		"different index": {
+			Address: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        0,
+			},
+			Other: &ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        1,
+			},
+			Expect: false,
+		},
+		"module address matches address of managed resource inside module": {
+			Address: &ResourceAddress{
+				Path:         []string{"a", "b"},
+				Type:         "",
+				Name:         "",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			Other: &ResourceAddress{
+				Path:         []string{"a", "b"},
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        0,
+			},
+			Expect: true,
+		},
+		"module address matches address of data resource inside module": {
+			Address: &ResourceAddress{
+				Path:         []string{"a", "b"},
+				Type:         "",
+				Name:         "",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			Other: &ResourceAddress{
+				Path:         []string{"a", "b"},
+				Mode:         DataResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        0,
+			},
+			Expect: true,
+		},
+		"module address doesn't match managed resource outside module": {
+			Address: &ResourceAddress{
+				Path:         []string{"a", "b"},
+				Type:         "",
+				Name:         "",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			Other: &ResourceAddress{
+				Path:         []string{"a"},
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        0,
+			},
+			Expect: false,
+		},
+		"module address doesn't match data resource outside module": {
+			Address: &ResourceAddress{
+				Path:         []string{"a", "b"},
+				Type:         "",
+				Name:         "",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			Other: &ResourceAddress{
+				Path:         []string{"a"},
+				Mode:         DataResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        0,
+			},
+			Expect: false,
+		},
+		"nil path vs empty path should match": {
+			Address: &ResourceAddress{
+				Path:         []string{},
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			Other: &ResourceAddress{
+				Path:         nil,
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        0,
+			},
+			Expect: true,
+		},
+	}
+
+	for tn, tc := range cases {
+		actual := tc.Address.Equals(tc.Other)
+		if actual != tc.Expect {
+			t.Fatalf("%q: expected equals: %t, got %t for:\n%#v\n%#v",
+				tn, tc.Expect, actual, tc.Address, tc.Other)
+		}
+	}
+}
+
+func TestResourceAddressStateId(t *testing.T) {
+	cases := map[string]struct {
+		Input    *ResourceAddress
+		Expected string
+	}{
+		"basic resource": {
+			&ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			"aws_instance.foo",
+		},
+
+		"basic resource with index": {
+			&ResourceAddress{
+				Mode:         ManagedResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        2,
+			},
+			"aws_instance.foo.2",
+		},
+
+		"data resource": {
+			&ResourceAddress{
+				Mode:         DataResourceMode,
+				Type:         "aws_instance",
+				Name:         "foo",
+				InstanceType: TypePrimary,
+				Index:        -1,
+			},
+			"data.aws_instance.foo",
+		},
+	}
+
+	for tn, tc := range cases {
+		t.Run(tn, func(t *testing.T) {
+			actual := tc.Input.stateId()
+			if actual != tc.Expected {
+				t.Fatalf("bad: %q\n\nexpected: %s\n\ngot: %s", tn, tc.Expected, actual)
+			}
+		})
+	}
+}
+
+func TestResourceAddressHasResourceSpec(t *testing.T) {
+	cases := []struct {
+		Input string
+		Want  bool
+	}{
+		{
+			"module.foo",
+			false,
+		},
+		{
+			"module.foo.module.bar",
+			false,
+		},
+		{
+			"null_resource.baz",
+			true,
+		},
+		{
+			"null_resource.baz[0]",
+			true,
+		},
+		{
+			"data.null_data_source.baz",
+			true,
+		},
+		{
+			"data.null_data_source.baz[0]",
+			true,
+		},
+		{
+			"module.foo.null_resource.baz",
+			true,
+		},
+		{
+			"module.foo.data.null_data_source.baz",
+			true,
+		},
+		{
+			"module.foo.module.bar.null_resource.baz",
+			true,
+		},
+	}
+
+	for _, test := range cases {
+		t.Run(test.Input, func(t *testing.T) {
+			addr, err := ParseResourceAddress(test.Input)
+			if err != nil {
+				t.Fatalf("error parsing address: %s", err)
+			}
+			got := addr.HasResourceSpec()
+			if got != test.Want {
+				t.Fatalf("%q: wrong result %#v; want %#v", test.Input, got, test.Want)
+			}
+		})
+	}
+}
+
+func TestResourceAddressWholeModuleAddress(t *testing.T) {
+	cases := []struct {
+		Input string
+		Want  string
+	}{
+		{
+			"module.foo",
+			"module.foo",
+		},
+		{
+			"module.foo.module.bar",
+			"module.foo.module.bar",
+		},
+		{
+			"null_resource.baz",
+			"",
+		},
+		{
+			"null_resource.baz[0]",
+			"",
+		},
+		{
+			"data.null_data_source.baz",
+			"",
+		},
+		{
+			"data.null_data_source.baz[0]",
+			"",
+		},
+		{
+			"module.foo.null_resource.baz",
+			"module.foo",
+		},
+		{
+			"module.foo.data.null_data_source.baz",
+			"module.foo",
+		},
+		{
+			"module.foo.module.bar.null_resource.baz",
+			"module.foo.module.bar",
+		},
+	}
+
+	for _, test := range cases {
+		t.Run(test.Input, func(t *testing.T) {
+			addr, err := ParseResourceAddress(test.Input)
+			if err != nil {
+				t.Fatalf("error parsing address: %s", err)
+			}
+			gotAddr := addr.WholeModuleAddress()
+			got := gotAddr.String()
+			if got != test.Want {
+				t.Fatalf("%q: wrong result %#v; want %#v", test.Input, got, test.Want)
+			}
+		})
+	}
+}
+
+func TestResourceAddressMatchesResourceConfig(t *testing.T) {
+	root := []string(nil)
+	child := []string{"child"}
+	grandchild := []string{"child", "grandchild"}
+	irrelevant := []string{"irrelevant"}
+
+	tests := []struct {
+		Addr       *ResourceAddress
+		ModulePath []string
+		Resource   *configs.Resource
+		Want       bool
+	}{
+		{
+			&ResourceAddress{
+				Mode:  ManagedResourceMode,
+				Type:  "null_resource",
+				Name:  "baz",
+				Index: -1,
+			},
+			root,
+			&configs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "null_resource",
+				Name: "baz",
+			},
+			true,
+		},
+		{
+			&ResourceAddress{
+				Path:  []string{"child"},
+				Mode:  ManagedResourceMode,
+				Type:  "null_resource",
+				Name:  "baz",
+				Index: -1,
+			},
+			child,
+			&configs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "null_resource",
+				Name: "baz",
+			},
+			true,
+		},
+		{
+			&ResourceAddress{
+				Path:  []string{"child", "grandchild"},
+				Mode:  ManagedResourceMode,
+				Type:  "null_resource",
+				Name:  "baz",
+				Index: -1,
+			},
+			grandchild,
+			&configs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "null_resource",
+				Name: "baz",
+			},
+			true,
+		},
+		{
+			&ResourceAddress{
+				Path:  []string{"child"},
+				Index: -1,
+			},
+			child,
+			&configs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "null_resource",
+				Name: "baz",
+			},
+			true,
+		},
+		{
+			&ResourceAddress{
+				Path:  []string{"child", "grandchild"},
+				Index: -1,
+			},
+			grandchild,
+			&configs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "null_resource",
+				Name: "baz",
+			},
+			true,
+		},
+		{
+			&ResourceAddress{
+				Mode:  DataResourceMode,
+				Type:  "null_resource",
+				Name:  "baz",
+				Index: -1,
+			},
+			irrelevant,
+			&configs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "null_resource",
+				Name: "baz",
+			},
+			false,
+		},
+		{
+			&ResourceAddress{
+				Mode:  ManagedResourceMode,
+				Type:  "null_resource",
+				Name:  "baz",
+				Index: -1,
+			},
+			irrelevant,
+			&configs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "null_resource",
+				Name: "pizza",
+			},
+			false,
+		},
+		{
+			&ResourceAddress{
+				Mode:  ManagedResourceMode,
+				Type:  "null_resource",
+				Name:  "baz",
+				Index: -1,
+			},
+			irrelevant,
+			&configs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "baz",
+			},
+			false,
+		},
+		{
+			&ResourceAddress{
+				Path:  []string{"child", "grandchild"},
+				Mode:  ManagedResourceMode,
+				Type:  "null_resource",
+				Name:  "baz",
+				Index: -1,
+			},
+			child,
+			&configs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "null_resource",
+				Name: "baz",
+			},
+			false,
+		},
+		{
+			&ResourceAddress{
+				Path:  []string{"child"},
+				Mode:  ManagedResourceMode,
+				Type:  "null_resource",
+				Name:  "baz",
+				Index: -1,
+			},
+			grandchild,
+			&configs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "null_resource",
+				Name: "baz",
+			},
+			false,
+		},
+	}
+
+	for i, test := range tests {
+		t.Run(fmt.Sprintf("%02d-%s", i, test.Addr), func(t *testing.T) {
+			got := test.Addr.MatchesResourceConfig(test.ModulePath, test.Resource)
+			if got != test.Want {
+				t.Errorf(
+					"wrong result\naddr: %s\nmod:  %#v\nrsrc: %#v\ngot:  %#v\nwant: %#v",
+					test.Addr, test.ModulePath, test.Resource, got, test.Want,
+				)
+			}
+		})
+	}
+}
+
+func TestResourceAddressLess(t *testing.T) {
+	tests := []struct {
+		A    string
+		B    string
+		Want bool
+	}{
+		{
+			"foo.bar",
+			"module.baz.foo.bar",
+			true,
+		},
+		{
+			"module.baz.foo.bar",
+			"zzz.bar", // would sort after "module" in lexicographical sort
+			false,
+		},
+		{
+			"module.baz.foo.bar",
+			"module.baz.foo.bar",
+			false,
+		},
+		{
+			"module.baz.foo.bar",
+			"module.boz.foo.bar",
+			true,
+		},
+		{
+			"module.boz.foo.bar",
+			"module.baz.foo.bar",
+			false,
+		},
+		{
+			"a.b",
+			"b.c",
+			true,
+		},
+		{
+			"a.b",
+			"a.c",
+			true,
+		},
+		{
+			"c.b",
+			"b.c",
+			false,
+		},
+		{
+			"a.b[9]",
+			"a.b[10]",
+			true,
+		},
+		{
+			"b.b[9]",
+			"a.b[10]",
+			false,
+		},
+		{
+			"a.b",
+			"a.b.deposed",
+			true,
+		},
+		{
+			"a.b.tainted",
+			"a.b.deposed",
+			true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%s < %s", test.A, test.B), func(t *testing.T) {
+			addrA, err := ParseResourceAddress(test.A)
+			if err != nil {
+				t.Fatal(err)
+			}
+			addrB, err := ParseResourceAddress(test.B)
+			if err != nil {
+				t.Fatal(err)
+			}
+			got := addrA.Less(addrB)
+			invGot := addrB.Less(addrA)
+			if got != test.Want {
+				t.Errorf(
+					"wrong result\ntest: %s < %s\ngot:  %#v\nwant: %#v",
+					test.A, test.B, got, test.Want,
+				)
+			}
+			if test.A != test.B { // inverse test doesn't apply when equal
+				if invGot != !test.Want {
+					t.Errorf(
+						"wrong inverse result\ntest: %s < %s\ngot:  %#v\nwant: %#v",
+						test.B, test.A, invGot, !test.Want,
+					)
+				}
+			} else {
+				if invGot != test.Want {
+					t.Errorf(
+						"wrong inverse result\ntest: %s < %s\ngot:  %#v\nwant: %#v",
+						test.B, test.A, invGot, test.Want,
+					)
+				}
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/legacy/terraform/resource_mode.go b/v1.5.7/internal/legacy/terraform/resource_mode.go
new file mode 100644
index 0000000..7153a9d
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/resource_mode.go
@@ -0,0 +1,15 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=ResourceMode -output=resource_mode_string.go resource_mode.go
+
+// ResourceMode is deprecated, use addrs.ResourceMode instead.
+// It has been preserved for backwards compatibility.
+type ResourceMode int
+
+const (
+	ManagedResourceMode ResourceMode = iota
+	DataResourceMode
+)
diff --git a/v1.5.7/internal/legacy/terraform/resource_mode_string.go b/v1.5.7/internal/legacy/terraform/resource_mode_string.go
new file mode 100644
index 0000000..ba84346
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/resource_mode_string.go
@@ -0,0 +1,24 @@
+// Code generated by "stringer -type=ResourceMode -output=resource_mode_string.go resource_mode.go"; DO NOT EDIT.
+
+package terraform
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[ManagedResourceMode-0]
+	_ = x[DataResourceMode-1]
+}
+
+const _ResourceMode_name = "ManagedResourceModeDataResourceMode"
+
+var _ResourceMode_index = [...]uint8{0, 19, 35}
+
+func (i ResourceMode) String() string {
+	if i < 0 || i >= ResourceMode(len(_ResourceMode_index)-1) {
+		return "ResourceMode(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _ResourceMode_name[_ResourceMode_index[i]:_ResourceMode_index[i+1]]
+}
diff --git a/v1.5.7/internal/legacy/terraform/resource_provider.go b/v1.5.7/internal/legacy/terraform/resource_provider.go
new file mode 100644
index 0000000..8f03525
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/resource_provider.go
@@ -0,0 +1,239 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+// ResourceProvider is a legacy interface for providers.
+//
+// This is retained only for compatibility with legacy code. The current
+// interface for providers is providers.Interface, in the sibling directory
+// named "providers".
+type ResourceProvider interface {
+	/*********************************************************************
+	* Functions related to the provider
+	*********************************************************************/
+
+	// ProviderSchema returns the config schema for the main provider
+	// configuration, as would appear in a "provider" block in the
+	// configuration files.
+	//
+	// Currently not all providers support schema. Callers must therefore
+	// first call Resources and DataSources and ensure that at least one
+	// resource or data source has the SchemaAvailable flag set.
+	GetSchema(*ProviderSchemaRequest) (*ProviderSchema, error)
+
+	// Input was used prior to v0.12 to ask the provider to prompt the user
+	// for input to complete the configuration.
+	//
+	// From v0.12 onwards this method is never called because Terraform Core
+	// is able to handle the necessary input logic itself based on the
+	// schema returned from GetSchema.
+	Input(UIInput, *ResourceConfig) (*ResourceConfig, error)
+
+	// Validate is called once at the beginning with the raw configuration
+	// (no interpolation done) and can return a list of warnings and/or
+	// errors.
+	//
+	// This is called once with the provider configuration only. It may not
+	// be called at all if no provider configuration is given.
+	//
+	// This should not assume that any values of the configurations are valid.
+	// The primary use case of this call is to check that required keys are
+	// set.
+	Validate(*ResourceConfig) ([]string, []error)
+
+	// Configure configures the provider itself with the configuration
+	// given. This is useful for setting things like access keys.
+	//
+	// This won't be called at all if no provider configuration is given.
+	//
+	// Configure returns an error if it occurred.
+	Configure(*ResourceConfig) error
+
+	// Resources returns all the available resource types that this provider
+	// knows how to manage.
+	Resources() []ResourceType
+
+	// Stop is called when the provider should halt any in-flight actions.
+	//
+	// This can be used to make a nicer Ctrl-C experience for Terraform.
+	// Even if this isn't implemented to do anything (just returns nil),
+	// Terraform will still cleanly stop after the currently executing
+	// graph node is complete. However, this API can be used to make more
+	// efficient halts.
+	//
+	// Stop doesn't have to and shouldn't block waiting for in-flight actions
+	// to complete. It should take any action it wants and return immediately
+	// acknowledging it has received the stop request. Terraform core will
+	// automatically not make any further API calls to the provider soon
+	// after Stop is called (technically exactly once the currently executing
+	// graph nodes are complete).
+	//
+	// The error returned, if non-nil, is assumed to mean that signaling the
+	// stop somehow failed and that the user should expect potentially waiting
+	// a longer period of time.
+	Stop() error
+
+	/*********************************************************************
+	* Functions related to individual resources
+	*********************************************************************/
+
+	// ValidateResource is called once at the beginning with the raw
+	// configuration (no interpolation done) and can return a list of warnings
+	// and/or errors.
+	//
+	// This is called once per resource.
+	//
+	// This should not assume any of the values in the resource configuration
+	// are valid since it is possible they have to be interpolated still.
+	// The primary use case of this call is to check that the required keys
+	// are set and that the general structure is correct.
+	ValidateResource(string, *ResourceConfig) ([]string, []error)
+
+	// Apply applies a diff to a specific resource and returns the new
+	// resource state along with an error.
+	//
+	// If the resource state given has an empty ID, then a new resource
+	// is expected to be created.
+	Apply(
+		*InstanceInfo,
+		*InstanceState,
+		*InstanceDiff) (*InstanceState, error)
+
+	// Diff diffs a resource versus a desired state and returns
+	// a diff.
+	Diff(
+		*InstanceInfo,
+		*InstanceState,
+		*ResourceConfig) (*InstanceDiff, error)
+
+	// Refresh refreshes a resource and updates all of its attributes
+	// with the latest information.
+	Refresh(*InstanceInfo, *InstanceState) (*InstanceState, error)
+
+	/*********************************************************************
+	* Functions related to importing
+	*********************************************************************/
+
+	// ImportState requests that the given resource be imported.
+	//
+	// The returned InstanceState only requires ID be set. Importing
+	// will always call Refresh after the state to complete it.
+	//
+	// IMPORTANT: InstanceState doesn't have the resource type attached
+	// to it. A type must be specified on the state via the Ephemeral
+	// field on the state.
+	//
+	// This function can return multiple states. Normally, an import
+	// will map 1:1 to a physical resource. However, some resources map
+	// to multiple. For example, an AWS security group may contain many rules.
+	// Each rule is represented by a separate resource in Terraform,
+	// therefore multiple states are returned.
+	ImportState(*InstanceInfo, string) ([]*InstanceState, error)
+
+	/*********************************************************************
+	* Functions related to data resources
+	*********************************************************************/
+
+	// ValidateDataSource is called once at the beginning with the raw
+	// configuration (no interpolation done) and can return a list of warnings
+	// and/or errors.
+	//
+	// This is called once per data source instance.
+	//
+	// This should not assume any of the values in the resource configuration
+	// are valid since it is possible they have to be interpolated still.
+	// The primary use case of this call is to check that the required keys
+	// are set and that the general structure is correct.
+	ValidateDataSource(string, *ResourceConfig) ([]string, []error)
+
+	// DataSources returns all of the available data sources that this
+	// provider implements.
+	DataSources() []DataSource
+
+	// ReadDataDiff produces a diff that represents the state that will
+	// be produced when the given data source is read using a later call
+	// to ReadDataApply.
+	ReadDataDiff(*InstanceInfo, *ResourceConfig) (*InstanceDiff, error)
+
+	// ReadDataApply initializes a data instance using the configuration
+	// in a diff produced by ReadDataDiff.
+	ReadDataApply(*InstanceInfo, *InstanceDiff) (*InstanceState, error)
+}
+
+// ResourceProviderCloser is an interface that providers that can close
+// connections that aren't needed anymore must implement.
+type ResourceProviderCloser interface {
+	Close() error
+}
+
+// ResourceType is a type of resource that a resource provider can manage.
+type ResourceType struct {
+	Name       string // Name of the resource, example "instance" (no provider prefix)
+	Importable bool   // Whether this resource supports importing
+
+	// SchemaAvailable is set if the provider supports the ProviderSchema,
+	// ResourceTypeSchema and DataSourceSchema methods. Although it is
+	// included on each resource type, it's actually a provider-wide setting
+	// that's smuggled here only because that avoids a breaking change to
+	// the plugin protocol.
+	SchemaAvailable bool
+}
+
+// DataSource is a data source that a resource provider implements.
+type DataSource struct {
+	Name string
+
+	// SchemaAvailable is set if the provider supports the ProviderSchema,
+	// ResourceTypeSchema and DataSourceSchema methods. Although it is
+	// included on each resource type, it's actually a provider-wide setting
+	// that's smuggled here only because that avoids a breaking change to
+	// the plugin protocol.
+	SchemaAvailable bool
+}
+
+// ResourceProviderFactory is a function type that creates a new instance
+// of a resource provider.
+type ResourceProviderFactory func() (ResourceProvider, error)
+
+// ResourceProviderFactoryFixed is a helper that creates a
+// ResourceProviderFactory that just returns some fixed provider.
+func ResourceProviderFactoryFixed(p ResourceProvider) ResourceProviderFactory {
+	return func() (ResourceProvider, error) {
+		return p, nil
+	}
+}
+
+func ProviderHasResource(p ResourceProvider, n string) bool {
+	for _, rt := range p.Resources() {
+		if rt.Name == n {
+			return true
+		}
+	}
+
+	return false
+}
+
+func ProviderHasDataSource(p ResourceProvider, n string) bool {
+	for _, rt := range p.DataSources() {
+		if rt.Name == n {
+			return true
+		}
+	}
+
+	return false
+}
+
+const errPluginInit = `
+Plugin reinitialization required. Please run "terraform init".
+
+Plugins are external binaries that Terraform uses to access and manipulate
+resources. The configuration provided requires plugins which can't be located,
+don't satisfy the version constraints, or are otherwise incompatible.
+
+Terraform automatically discovers provider requirements from your
+configuration, including providers used in child modules. To see the
+requirements and constraints, run "terraform providers".
+
+%s
+`
diff --git a/v1.5.7/internal/legacy/terraform/resource_provider_mock.go b/v1.5.7/internal/legacy/terraform/resource_provider_mock.go
new file mode 100644
index 0000000..c026be4
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/resource_provider_mock.go
@@ -0,0 +1,318 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"sync"
+)
+
+// MockResourceProvider implements ResourceProvider but mocks out all the
+// calls for testing purposes.
+type MockResourceProvider struct {
+	sync.Mutex
+
+	// Anything you want, in case you need to store extra data with the mock.
+	Meta interface{}
+
+	CloseCalled                    bool
+	CloseError                     error
+	GetSchemaCalled                bool
+	GetSchemaRequest               *ProviderSchemaRequest
+	GetSchemaReturn                *ProviderSchema
+	GetSchemaReturnError           error
+	InputCalled                    bool
+	InputInput                     UIInput
+	InputConfig                    *ResourceConfig
+	InputReturnConfig              *ResourceConfig
+	InputReturnError               error
+	InputFn                        func(UIInput, *ResourceConfig) (*ResourceConfig, error)
+	ApplyCalled                    bool
+	ApplyInfo                      *InstanceInfo
+	ApplyState                     *InstanceState
+	ApplyDiff                      *InstanceDiff
+	ApplyFn                        func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error)
+	ApplyReturn                    *InstanceState
+	ApplyReturnError               error
+	ConfigureCalled                bool
+	ConfigureConfig                *ResourceConfig
+	ConfigureProviderFn            func(*ResourceConfig) error
+	ConfigureReturnError           error
+	DiffCalled                     bool
+	DiffInfo                       *InstanceInfo
+	DiffState                      *InstanceState
+	DiffDesired                    *ResourceConfig
+	DiffFn                         func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error)
+	DiffReturn                     *InstanceDiff
+	DiffReturnError                error
+	RefreshCalled                  bool
+	RefreshInfo                    *InstanceInfo
+	RefreshState                   *InstanceState
+	RefreshFn                      func(*InstanceInfo, *InstanceState) (*InstanceState, error)
+	RefreshReturn                  *InstanceState
+	RefreshReturnError             error
+	ResourcesCalled                bool
+	ResourcesReturn                []ResourceType
+	ReadDataApplyCalled            bool
+	ReadDataApplyInfo              *InstanceInfo
+	ReadDataApplyDiff              *InstanceDiff
+	ReadDataApplyFn                func(*InstanceInfo, *InstanceDiff) (*InstanceState, error)
+	ReadDataApplyReturn            *InstanceState
+	ReadDataApplyReturnError       error
+	ReadDataDiffCalled             bool
+	ReadDataDiffInfo               *InstanceInfo
+	ReadDataDiffDesired            *ResourceConfig
+	ReadDataDiffFn                 func(*InstanceInfo, *ResourceConfig) (*InstanceDiff, error)
+	ReadDataDiffReturn             *InstanceDiff
+	ReadDataDiffReturnError        error
+	StopCalled                     bool
+	StopFn                         func() error
+	StopReturnError                error
+	DataSourcesCalled              bool
+	DataSourcesReturn              []DataSource
+	ValidateCalled                 bool
+	ValidateConfig                 *ResourceConfig
+	ValidateFn                     func(*ResourceConfig) ([]string, []error)
+	ValidateReturnWarns            []string
+	ValidateReturnErrors           []error
+	ValidateResourceFn             func(string, *ResourceConfig) ([]string, []error)
+	ValidateResourceCalled         bool
+	ValidateResourceType           string
+	ValidateResourceConfig         *ResourceConfig
+	ValidateResourceReturnWarns    []string
+	ValidateResourceReturnErrors   []error
+	ValidateDataSourceFn           func(string, *ResourceConfig) ([]string, []error)
+	ValidateDataSourceCalled       bool
+	ValidateDataSourceType         string
+	ValidateDataSourceConfig       *ResourceConfig
+	ValidateDataSourceReturnWarns  []string
+	ValidateDataSourceReturnErrors []error
+
+	ImportStateCalled      bool
+	ImportStateInfo        *InstanceInfo
+	ImportStateID          string
+	ImportStateReturn      []*InstanceState
+	ImportStateReturnError error
+	ImportStateFn          func(*InstanceInfo, string) ([]*InstanceState, error)
+}
+
+func (p *MockResourceProvider) Close() error {
+	p.CloseCalled = true
+	return p.CloseError
+}
+
+func (p *MockResourceProvider) GetSchema(req *ProviderSchemaRequest) (*ProviderSchema, error) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.GetSchemaCalled = true
+	p.GetSchemaRequest = req
+	return p.GetSchemaReturn, p.GetSchemaReturnError
+}
+
+func (p *MockResourceProvider) Input(
+	input UIInput, c *ResourceConfig) (*ResourceConfig, error) {
+	p.Lock()
+	defer p.Unlock()
+	p.InputCalled = true
+	p.InputInput = input
+	p.InputConfig = c
+	if p.InputFn != nil {
+		return p.InputFn(input, c)
+	}
+	return p.InputReturnConfig, p.InputReturnError
+}
+
+func (p *MockResourceProvider) Validate(c *ResourceConfig) ([]string, []error) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ValidateCalled = true
+	p.ValidateConfig = c
+	if p.ValidateFn != nil {
+		return p.ValidateFn(c)
+	}
+	return p.ValidateReturnWarns, p.ValidateReturnErrors
+}
+
+func (p *MockResourceProvider) ValidateResource(t string, c *ResourceConfig) ([]string, []error) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ValidateResourceCalled = true
+	p.ValidateResourceType = t
+	p.ValidateResourceConfig = c
+
+	if p.ValidateResourceFn != nil {
+		return p.ValidateResourceFn(t, c)
+	}
+
+	return p.ValidateResourceReturnWarns, p.ValidateResourceReturnErrors
+}
+
+func (p *MockResourceProvider) Configure(c *ResourceConfig) error {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ConfigureCalled = true
+	p.ConfigureConfig = c
+
+	if p.ConfigureProviderFn != nil {
+		return p.ConfigureProviderFn(c)
+	}
+
+	return p.ConfigureReturnError
+}
+
+func (p *MockResourceProvider) Stop() error {
+	p.Lock()
+	defer p.Unlock()
+
+	p.StopCalled = true
+	if p.StopFn != nil {
+		return p.StopFn()
+	}
+
+	return p.StopReturnError
+}
+
+func (p *MockResourceProvider) Apply(
+	info *InstanceInfo,
+	state *InstanceState,
+	diff *InstanceDiff) (*InstanceState, error) {
+	// We only lock while writing data. Reading is fine
+	p.Lock()
+	p.ApplyCalled = true
+	p.ApplyInfo = info
+	p.ApplyState = state
+	p.ApplyDiff = diff
+	p.Unlock()
+
+	if p.ApplyFn != nil {
+		return p.ApplyFn(info, state, diff)
+	}
+
+	return p.ApplyReturn.DeepCopy(), p.ApplyReturnError
+}
+
+func (p *MockResourceProvider) Diff(
+	info *InstanceInfo,
+	state *InstanceState,
+	desired *ResourceConfig) (*InstanceDiff, error) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.DiffCalled = true
+	p.DiffInfo = info
+	p.DiffState = state
+	p.DiffDesired = desired
+
+	if p.DiffFn != nil {
+		return p.DiffFn(info, state, desired)
+	}
+
+	return p.DiffReturn.DeepCopy(), p.DiffReturnError
+}
+
+func (p *MockResourceProvider) Refresh(
+	info *InstanceInfo,
+	s *InstanceState) (*InstanceState, error) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.RefreshCalled = true
+	p.RefreshInfo = info
+	p.RefreshState = s
+
+	if p.RefreshFn != nil {
+		return p.RefreshFn(info, s)
+	}
+
+	return p.RefreshReturn.DeepCopy(), p.RefreshReturnError
+}
+
+func (p *MockResourceProvider) Resources() []ResourceType {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ResourcesCalled = true
+	return p.ResourcesReturn
+}
+
+func (p *MockResourceProvider) ImportState(info *InstanceInfo, id string) ([]*InstanceState, error) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ImportStateCalled = true
+	p.ImportStateInfo = info
+	p.ImportStateID = id
+	if p.ImportStateFn != nil {
+		return p.ImportStateFn(info, id)
+	}
+
+	var result []*InstanceState
+	if p.ImportStateReturn != nil {
+		result = make([]*InstanceState, len(p.ImportStateReturn))
+		for i, v := range p.ImportStateReturn {
+			result[i] = v.DeepCopy()
+		}
+	}
+
+	return result, p.ImportStateReturnError
+}
+
+func (p *MockResourceProvider) ValidateDataSource(t string, c *ResourceConfig) ([]string, []error) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ValidateDataSourceCalled = true
+	p.ValidateDataSourceType = t
+	p.ValidateDataSourceConfig = c
+
+	if p.ValidateDataSourceFn != nil {
+		return p.ValidateDataSourceFn(t, c)
+	}
+
+	return p.ValidateDataSourceReturnWarns, p.ValidateDataSourceReturnErrors
+}
+
+func (p *MockResourceProvider) ReadDataDiff(
+	info *InstanceInfo,
+	desired *ResourceConfig) (*InstanceDiff, error) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ReadDataDiffCalled = true
+	p.ReadDataDiffInfo = info
+	p.ReadDataDiffDesired = desired
+	if p.ReadDataDiffFn != nil {
+		return p.ReadDataDiffFn(info, desired)
+	}
+
+	return p.ReadDataDiffReturn.DeepCopy(), p.ReadDataDiffReturnError
+}
+
+func (p *MockResourceProvider) ReadDataApply(
+	info *InstanceInfo,
+	d *InstanceDiff) (*InstanceState, error) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ReadDataApplyCalled = true
+	p.ReadDataApplyInfo = info
+	p.ReadDataApplyDiff = d
+
+	if p.ReadDataApplyFn != nil {
+		return p.ReadDataApplyFn(info, d)
+	}
+
+	return p.ReadDataApplyReturn.DeepCopy(), p.ReadDataApplyReturnError
+}
+
+func (p *MockResourceProvider) DataSources() []DataSource {
+	p.Lock()
+	defer p.Unlock()
+
+	p.DataSourcesCalled = true
+	return p.DataSourcesReturn
+}
diff --git a/v1.5.7/internal/legacy/terraform/resource_provisioner.go b/v1.5.7/internal/legacy/terraform/resource_provisioner.go
new file mode 100644
index 0000000..9cfb591
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/resource_provisioner.go
@@ -0,0 +1,72 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/provisioners"
+)
+
+// ResourceProvisioner is an interface that must be implemented by any
+// resource provisioner: the thing that initializes resources in
+// a Terraform configuration.
+type ResourceProvisioner interface {
+	// GetConfigSchema returns the schema for the provisioner type's main
+	// configuration block. This is called prior to Validate to enable some
+	// basic structural validation to be performed automatically and to allow
+	// the configuration to be properly extracted from potentially-ambiguous
+	// configuration file formats.
+	GetConfigSchema() (*configschema.Block, error)
+
+	// Validate is called once at the beginning with the raw
+	// configuration (no interpolation done) and can return a list of warnings
+	// and/or errors.
+	//
+	// This is called once per resource.
+	//
+	// This should not assume any of the values in the resource configuration
+	// are valid since it is possible they have to be interpolated still.
+	// The primary use case of this call is to check that the required keys
+	// are set and that the general structure is correct.
+	Validate(*ResourceConfig) ([]string, []error)
+
+	// Apply runs the provisioner on a specific resource and returns an error.
+	// Instead of a diff, the ResourceConfig is provided since provisioners
+	// only run after a resource has been newly created.
+	Apply(UIOutput, *InstanceState, *ResourceConfig) error
+
+	// Stop is called when the provisioner should halt any in-flight actions.
+	//
+	// This can be used to make a nicer Ctrl-C experience for Terraform.
+	// Even if this isn't implemented to do anything (just returns nil),
+	// Terraform will still cleanly stop after the currently executing
+	// graph node is complete. However, this API can be used to make more
+	// efficient halts.
+	//
+	// Stop doesn't have to and shouldn't block waiting for in-flight actions
+	// to complete. It should take any action it wants and return immediately
+	// acknowledging it has received the stop request. Terraform core will
+	// automatically not make any further API calls to the provider soon
+	// after Stop is called (technically exactly once the currently executing
+	// graph nodes are complete).
+	//
+	// The error returned, if non-nil, is assumed to mean that signaling the
+	// stop somehow failed and that the user should expect potentially waiting
+	// a longer period of time.
+	Stop() error
+}
+
+// ResourceProvisionerCloser is an interface that provisioners that can close
+// connections that aren't needed anymore must implement.
+type ResourceProvisionerCloser interface {
+	Close() error
+}
+
+// ResourceProvisionerFactory is a function type that creates a new instance
+// of a resource provisioner.
+type ResourceProvisionerFactory func() (ResourceProvisioner, error)
+
+// ProvisionerFactory is a function type that creates a new instance
+// of a provisioners.Interface.
+type ProvisionerFactory = provisioners.Factory
diff --git a/v1.5.7/internal/legacy/terraform/resource_provisioner_mock.go b/v1.5.7/internal/legacy/terraform/resource_provisioner_mock.go
new file mode 100644
index 0000000..a4c7682
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/resource_provisioner_mock.go
@@ -0,0 +1,90 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+// MockResourceProvisioner implements ResourceProvisioner but mocks out all the
+// calls for testing purposes.
+type MockResourceProvisioner struct {
+	sync.Mutex
+	// Anything you want, in case you need to store extra data with the mock.
+	Meta interface{}
+
+	GetConfigSchemaCalled       bool
+	GetConfigSchemaReturnSchema *configschema.Block
+	GetConfigSchemaReturnError  error
+
+	ApplyCalled      bool
+	ApplyOutput      UIOutput
+	ApplyState       *InstanceState
+	ApplyConfig      *ResourceConfig
+	ApplyFn          func(*InstanceState, *ResourceConfig) error
+	ApplyReturnError error
+
+	ValidateCalled       bool
+	ValidateConfig       *ResourceConfig
+	ValidateFn           func(c *ResourceConfig) ([]string, []error)
+	ValidateReturnWarns  []string
+	ValidateReturnErrors []error
+
+	StopCalled      bool
+	StopFn          func() error
+	StopReturnError error
+}
+
+var _ ResourceProvisioner = (*MockResourceProvisioner)(nil)
+
+func (p *MockResourceProvisioner) GetConfigSchema() (*configschema.Block, error) {
+	p.GetConfigSchemaCalled = true
+	return p.GetConfigSchemaReturnSchema, p.GetConfigSchemaReturnError
+}
+
+func (p *MockResourceProvisioner) Validate(c *ResourceConfig) ([]string, []error) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ValidateCalled = true
+	p.ValidateConfig = c
+	if p.ValidateFn != nil {
+		return p.ValidateFn(c)
+	}
+	return p.ValidateReturnWarns, p.ValidateReturnErrors
+}
+
+func (p *MockResourceProvisioner) Apply(
+	output UIOutput,
+	state *InstanceState,
+	c *ResourceConfig) error {
+	p.Lock()
+
+	p.ApplyCalled = true
+	p.ApplyOutput = output
+	p.ApplyState = state
+	p.ApplyConfig = c
+	if p.ApplyFn != nil {
+		fn := p.ApplyFn
+		p.Unlock()
+		return fn(state, c)
+	}
+
+	defer p.Unlock()
+	return p.ApplyReturnError
+}
+
+func (p *MockResourceProvisioner) Stop() error {
+	p.Lock()
+	defer p.Unlock()
+
+	p.StopCalled = true
+	if p.StopFn != nil {
+		return p.StopFn()
+	}
+
+	return p.StopReturnError
+}
diff --git a/v1.5.7/internal/legacy/terraform/resource_test.go b/v1.5.7/internal/legacy/terraform/resource_test.go
new file mode 100644
index 0000000..3baf620
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/resource_test.go
@@ -0,0 +1,677 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/mitchellh/reflectwalk"
+)
+
+func TestResourceConfigGet(t *testing.T) {
+	fooStringSchema := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"foo": {Type: cty.String, Optional: true},
+		},
+	}
+	fooListSchema := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"foo": {Type: cty.List(cty.Number), Optional: true},
+		},
+	}
+
+	cases := []struct {
+		Config cty.Value
+		Schema *configschema.Block
+		Key    string
+		Value  interface{}
+	}{
+		{
+			Config: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+			}),
+			Schema: fooStringSchema,
+			Key:    "foo",
+			Value:  "bar",
+		},
+
+		{
+			Config: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.UnknownVal(cty.String),
+			}),
+			Schema: fooStringSchema,
+			Key:    "foo",
+			Value:  hcl2shim.UnknownVariableValue,
+		},
+
+		{
+			Config: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.NumberIntVal(1),
+					cty.NumberIntVal(2),
+					cty.NumberIntVal(5),
+				}),
+			}),
+			Schema: fooListSchema,
+			Key:    "foo.0",
+			Value:  1,
+		},
+
+		{
+			Config: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.NumberIntVal(1),
+					cty.NumberIntVal(2),
+					cty.NumberIntVal(5),
+				}),
+			}),
+			Schema: fooListSchema,
+			Key:    "foo.5",
+			Value:  nil,
+		},
+
+		{
+			Config: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.NumberIntVal(1),
+					cty.NumberIntVal(2),
+					cty.NumberIntVal(5),
+				}),
+			}),
+			Schema: fooListSchema,
+			Key:    "foo.-1",
+			Value:  nil,
+		},
+
+		// get from map
+		{
+			Config: cty.ObjectVal(map[string]cty.Value{
+				"mapname": cty.ListVal([]cty.Value{
+					cty.MapVal(map[string]cty.Value{
+						"key": cty.NumberIntVal(1),
+					}),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"mapname": {Type: cty.List(cty.Map(cty.Number)), Optional: true},
+				},
+			},
+			Key:   "mapname.0.key",
+			Value: 1,
+		},
+
+		// get from map with dot in key
+		{
+			Config: cty.ObjectVal(map[string]cty.Value{
+				"mapname": cty.ListVal([]cty.Value{
+					cty.MapVal(map[string]cty.Value{
+						"key.name": cty.NumberIntVal(1),
+					}),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"mapname": {Type: cty.List(cty.Map(cty.Number)), Optional: true},
+				},
+			},
+			Key:   "mapname.0.key.name",
+			Value: 1,
+		},
+
+		// get from map with overlapping key names
+		{
+			Config: cty.ObjectVal(map[string]cty.Value{
+				"mapname": cty.ListVal([]cty.Value{
+					cty.MapVal(map[string]cty.Value{
+						"key.name":   cty.NumberIntVal(1),
+						"key.name.2": cty.NumberIntVal(2),
+					}),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"mapname": {Type: cty.List(cty.Map(cty.Number)), Optional: true},
+				},
+			},
+			Key:   "mapname.0.key.name.2",
+			Value: 2,
+		},
+		{
+			Config: cty.ObjectVal(map[string]cty.Value{
+				"mapname": cty.ListVal([]cty.Value{
+					cty.MapVal(map[string]cty.Value{
+						"key.name":     cty.NumberIntVal(1),
+						"key.name.foo": cty.NumberIntVal(2),
+					}),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"mapname": {Type: cty.List(cty.Map(cty.Number)), Optional: true},
+				},
+			},
+			Key:   "mapname.0.key.name",
+			Value: 1,
+		},
+		{
+			Config: cty.ObjectVal(map[string]cty.Value{
+				"mapname": cty.ListVal([]cty.Value{
+					cty.MapVal(map[string]cty.Value{
+						"listkey": cty.ListVal([]cty.Value{
+							cty.MapVal(map[string]cty.Value{
+								"key": cty.NumberIntVal(3),
+							}),
+						}),
+					}),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"mapname": {Type: cty.List(cty.Map(cty.List(cty.Map(cty.Number)))), Optional: true},
+				},
+			},
+			Key:   "mapname.0.listkey.0.key",
+			Value: 3,
+		},
+	}
+
+	for i, tc := range cases {
+		rc := NewResourceConfigShimmed(tc.Config, tc.Schema)
+
+		// Test getting a key
+		t.Run(fmt.Sprintf("get-%d", i), func(t *testing.T) {
+			v, ok := rc.Get(tc.Key)
+			if ok && v == nil {
+				t.Fatal("(nil, true) returned from Get")
+			}
+
+			if !reflect.DeepEqual(v, tc.Value) {
+				t.Fatalf("%d bad: %#v", i, v)
+			}
+		})
+
+		// Test copying and equality
+		t.Run(fmt.Sprintf("copy-and-equal-%d", i), func(t *testing.T) {
+			copy := rc.DeepCopy()
+			if !reflect.DeepEqual(copy, rc) {
+				t.Fatalf("bad:\n\n%#v\n\n%#v", copy, rc)
+			}
+
+			if !copy.Equal(rc) {
+				t.Fatalf("copy != rc:\n\n%#v\n\n%#v", copy, rc)
+			}
+			if !rc.Equal(copy) {
+				t.Fatalf("rc != copy:\n\n%#v\n\n%#v", copy, rc)
+			}
+		})
+	}
+}
+
+func TestResourceConfigDeepCopy_nil(t *testing.T) {
+	var nilRc *ResourceConfig
+	actual := nilRc.DeepCopy()
+	if actual != nil {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceConfigDeepCopy_nilComputed(t *testing.T) {
+	rc := &ResourceConfig{}
+	actual := rc.DeepCopy()
+	if actual.ComputedKeys != nil {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestResourceConfigEqual_nil(t *testing.T) {
+	var nilRc *ResourceConfig
+	notNil := NewResourceConfigShimmed(cty.EmptyObjectVal, &configschema.Block{})
+
+	if nilRc.Equal(notNil) {
+		t.Fatal("should not be equal")
+	}
+
+	if notNil.Equal(nilRc) {
+		t.Fatal("should not be equal")
+	}
+}
+
+func TestResourceConfigEqual_computedKeyOrder(t *testing.T) {
+	v := cty.ObjectVal(map[string]cty.Value{
+		"foo": cty.UnknownVal(cty.String),
+	})
+	schema := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"foo": {Type: cty.String, Optional: true},
+		},
+	}
+	rc := NewResourceConfigShimmed(v, schema)
+	rc2 := NewResourceConfigShimmed(v, schema)
+
+	// Set the computed keys manually to force ordering to differ
+	rc.ComputedKeys = []string{"foo", "bar"}
+	rc2.ComputedKeys = []string{"bar", "foo"}
+
+	if !rc.Equal(rc2) {
+		t.Fatal("should be equal")
+	}
+}
+
+func TestUnknownCheckWalker(t *testing.T) {
+	cases := []struct {
+		Name   string
+		Input  interface{}
+		Result bool
+	}{
+		{
+			"primitive",
+			42,
+			false,
+		},
+
+		{
+			"primitive computed",
+			hcl2shim.UnknownVariableValue,
+			true,
+		},
+
+		{
+			"list",
+			[]interface{}{"foo", hcl2shim.UnknownVariableValue},
+			true,
+		},
+
+		{
+			"nested list",
+			[]interface{}{
+				"foo",
+				[]interface{}{hcl2shim.UnknownVariableValue},
+			},
+			true,
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			var w unknownCheckWalker
+			if err := reflectwalk.Walk(tc.Input, &w); err != nil {
+				t.Fatalf("err: %s", err)
+			}
+
+			if w.Unknown != tc.Result {
+				t.Fatalf("bad: %v", w.Unknown)
+			}
+		})
+	}
+}
+
+func TestNewResourceConfigShimmed(t *testing.T) {
+	for _, tc := range []struct {
+		Name     string
+		Val      cty.Value
+		Schema   *configschema.Block
+		Expected *ResourceConfig
+	}{
+		{
+			Name: "empty object",
+			Val:  cty.NullVal(cty.EmptyObject),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			Expected: &ResourceConfig{
+				Raw:    map[string]interface{}{},
+				Config: map[string]interface{}{},
+			},
+		},
+		{
+			Name: "basic",
+			Val: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			Expected: &ResourceConfig{
+				Raw: map[string]interface{}{
+					"foo": "bar",
+				},
+				Config: map[string]interface{}{
+					"foo": "bar",
+				},
+			},
+		},
+		{
+			Name: "null string",
+			Val: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(cty.String),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			Expected: &ResourceConfig{
+				Raw:    map[string]interface{}{},
+				Config: map[string]interface{}{},
+			},
+		},
+		{
+			Name: "unknown string",
+			Val: cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.UnknownVal(cty.String),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			Expected: &ResourceConfig{
+				ComputedKeys: []string{"foo"},
+				Raw: map[string]interface{}{
+					"foo": hcl2shim.UnknownVariableValue,
+				},
+				Config: map[string]interface{}{
+					"foo": hcl2shim.UnknownVariableValue,
+				},
+			},
+		},
+		{
+			Name: "unknown collections",
+			Val: cty.ObjectVal(map[string]cty.Value{
+				"bar": cty.UnknownVal(cty.Map(cty.String)),
+				"baz": cty.UnknownVal(cty.List(cty.String)),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"bar": {
+						Type:     cty.Map(cty.String),
+						Required: true,
+					},
+					"baz": {
+						Type:     cty.List(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			Expected: &ResourceConfig{
+				ComputedKeys: []string{"bar", "baz"},
+				Raw: map[string]interface{}{
+					"bar": hcl2shim.UnknownVariableValue,
+					"baz": hcl2shim.UnknownVariableValue,
+				},
+				Config: map[string]interface{}{
+					"bar": hcl2shim.UnknownVariableValue,
+					"baz": hcl2shim.UnknownVariableValue,
+				},
+			},
+		},
+		{
+			Name: "null collections",
+			Val: cty.ObjectVal(map[string]cty.Value{
+				"bar": cty.NullVal(cty.Map(cty.String)),
+				"baz": cty.NullVal(cty.List(cty.String)),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"bar": {
+						Type:     cty.Map(cty.String),
+						Required: true,
+					},
+					"baz": {
+						Type:     cty.List(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			Expected: &ResourceConfig{
+				Raw:    map[string]interface{}{},
+				Config: map[string]interface{}{},
+			},
+		},
+		{
+			Name: "unknown blocks",
+			Val: cty.ObjectVal(map[string]cty.Value{
+				"bar": cty.UnknownVal(cty.Map(cty.String)),
+				"baz": cty.UnknownVal(cty.List(cty.String)),
+			}),
+			Schema: &configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"bar": {
+						Block:   configschema.Block{},
+						Nesting: configschema.NestingList,
+					},
+					"baz": {
+						Block:   configschema.Block{},
+						Nesting: configschema.NestingSet,
+					},
+				},
+			},
+			Expected: &ResourceConfig{
+				ComputedKeys: []string{"bar", "baz"},
+				Raw: map[string]interface{}{
+					"bar": hcl2shim.UnknownVariableValue,
+					"baz": hcl2shim.UnknownVariableValue,
+				},
+				Config: map[string]interface{}{
+					"bar": hcl2shim.UnknownVariableValue,
+					"baz": hcl2shim.UnknownVariableValue,
+				},
+			},
+		},
+		{
+			Name: "unknown in nested blocks",
+			Val: cty.ObjectVal(map[string]cty.Value{
+				"bar": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"baz": cty.ListVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"list": cty.UnknownVal(cty.List(cty.String)),
+							}),
+						}),
+					}),
+				}),
+			}),
+			Schema: &configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"bar": {
+						Block: configschema.Block{
+							BlockTypes: map[string]*configschema.NestedBlock{
+								"baz": {
+									Block: configschema.Block{
+										Attributes: map[string]*configschema.Attribute{
+											"list": {Type: cty.List(cty.String),
+												Optional: true,
+											},
+										},
+									},
+									Nesting: configschema.NestingList,
+								},
+							},
+						},
+						Nesting: configschema.NestingList,
+					},
+				},
+			},
+			Expected: &ResourceConfig{
+				ComputedKeys: []string{"bar.0.baz.0.list"},
+				Raw: map[string]interface{}{
+					"bar": []interface{}{map[string]interface{}{
+						"baz": []interface{}{map[string]interface{}{
+							"list": "74D93920-ED26-11E3-AC10-0800200C9A66",
+						}},
+					}},
+				},
+				Config: map[string]interface{}{
+					"bar": []interface{}{map[string]interface{}{
+						"baz": []interface{}{map[string]interface{}{
+							"list": "74D93920-ED26-11E3-AC10-0800200C9A66",
+						}},
+					}},
+				},
+			},
+		},
+		{
+			Name: "unknown in set",
+			Val: cty.ObjectVal(map[string]cty.Value{
+				"bar": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"val": cty.UnknownVal(cty.String),
+					}),
+				}),
+			}),
+			Schema: &configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"bar": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"val": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Nesting: configschema.NestingSet,
+					},
+				},
+			},
+			Expected: &ResourceConfig{
+				ComputedKeys: []string{"bar.0.val"},
+				Raw: map[string]interface{}{
+					"bar": []interface{}{map[string]interface{}{
+						"val": "74D93920-ED26-11E3-AC10-0800200C9A66",
+					}},
+				},
+				Config: map[string]interface{}{
+					"bar": []interface{}{map[string]interface{}{
+						"val": "74D93920-ED26-11E3-AC10-0800200C9A66",
+					}},
+				},
+			},
+		},
+		{
+			Name: "unknown in attribute sets",
+			Val: cty.ObjectVal(map[string]cty.Value{
+				"bar": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"val": cty.UnknownVal(cty.String),
+					}),
+				}),
+				"baz": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.UnknownVal(cty.Object(map[string]cty.Type{
+							"attr": cty.List(cty.String),
+						})),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"attr": cty.UnknownVal(cty.List(cty.String)),
+						}),
+					}),
+				}),
+			}),
+			Schema: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"bar": &configschema.Attribute{
+						Type: cty.Set(cty.Object(map[string]cty.Type{
+							"val": cty.String,
+						})),
+					},
+					"baz": &configschema.Attribute{
+						Type: cty.Set(cty.Object(map[string]cty.Type{
+							"obj": cty.Object(map[string]cty.Type{
+								"attr": cty.List(cty.String),
+							}),
+						})),
+					},
+				},
+			},
+			Expected: &ResourceConfig{
+				ComputedKeys: []string{"bar.0.val", "baz.0.obj.attr", "baz.1.obj"},
+				Raw: map[string]interface{}{
+					"bar": []interface{}{map[string]interface{}{
+						"val": "74D93920-ED26-11E3-AC10-0800200C9A66",
+					}},
+					"baz": []interface{}{
+						map[string]interface{}{
+							"obj": map[string]interface{}{
+								"attr": "74D93920-ED26-11E3-AC10-0800200C9A66",
+							},
+						},
+						map[string]interface{}{
+							"obj": "74D93920-ED26-11E3-AC10-0800200C9A66",
+						},
+					},
+				},
+				Config: map[string]interface{}{
+					"bar": []interface{}{map[string]interface{}{
+						"val": "74D93920-ED26-11E3-AC10-0800200C9A66",
+					}},
+					"baz": []interface{}{
+						map[string]interface{}{
+							"obj": map[string]interface{}{
+								"attr": "74D93920-ED26-11E3-AC10-0800200C9A66",
+							},
+						},
+						map[string]interface{}{
+							"obj": "74D93920-ED26-11E3-AC10-0800200C9A66",
+						},
+					},
+				},
+			},
+		},
+		{
+			Name: "null blocks",
+			Val: cty.ObjectVal(map[string]cty.Value{
+				"bar": cty.NullVal(cty.Map(cty.String)),
+				"baz": cty.NullVal(cty.List(cty.String)),
+			}),
+			Schema: &configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"bar": {
+						Block:   configschema.Block{},
+						Nesting: configschema.NestingMap,
+					},
+					"baz": {
+						Block:   configschema.Block{},
+						Nesting: configschema.NestingSingle,
+					},
+				},
+			},
+			Expected: &ResourceConfig{
+				Raw:    map[string]interface{}{},
+				Config: map[string]interface{}{},
+			},
+		},
+	} {
+		t.Run(tc.Name, func(*testing.T) {
+			cfg := NewResourceConfigShimmed(tc.Val, tc.Schema)
+			if !tc.Expected.Equal(cfg) {
+				t.Fatalf("expected:\n%#v\ngot:\n%#v", tc.Expected, cfg)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/legacy/terraform/schemas.go b/v1.5.7/internal/legacy/terraform/schemas.go
new file mode 100644
index 0000000..3d8a625
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/schemas.go
@@ -0,0 +1,288 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Schemas is a container for various kinds of schema that Terraform needs
+// during processing.
+type Schemas struct {
+	Providers    map[addrs.Provider]*ProviderSchema
+	Provisioners map[string]*configschema.Block
+}
+
+// ProviderSchema returns the entire ProviderSchema object that was produced
+// by the plugin for the given provider, or nil if no such schema is available.
+//
+// It's usually better to go use the more precise methods offered by type
+// Schemas to handle this detail automatically.
+func (ss *Schemas) ProviderSchema(provider addrs.Provider) *ProviderSchema {
+	if ss.Providers == nil {
+		return nil
+	}
+	return ss.Providers[provider]
+}
+
+// ProviderConfig returns the schema for the provider configuration of the
+// given provider type, or nil if no such schema is available.
+func (ss *Schemas) ProviderConfig(provider addrs.Provider) *configschema.Block {
+	ps := ss.ProviderSchema(provider)
+	if ps == nil {
+		return nil
+	}
+	return ps.Provider
+}
+
+// ResourceTypeConfig returns the schema for the configuration of a given
+// resource type belonging to a given provider type, or nil of no such
+// schema is available.
+//
+// In many cases the provider type is inferrable from the resource type name,
+// but this is not always true because users can override the provider for
+// a resource using the "provider" meta-argument. Therefore it's important to
+// always pass the correct provider name, even though it many cases it feels
+// redundant.
+func (ss *Schemas) ResourceTypeConfig(provider addrs.Provider, resourceMode addrs.ResourceMode, resourceType string) (block *configschema.Block, schemaVersion uint64) {
+	ps := ss.ProviderSchema(provider)
+	if ps == nil || ps.ResourceTypes == nil {
+		return nil, 0
+	}
+	return ps.SchemaForResourceType(resourceMode, resourceType)
+}
+
+// ProvisionerConfig returns the schema for the configuration of a given
+// provisioner, or nil of no such schema is available.
+func (ss *Schemas) ProvisionerConfig(name string) *configschema.Block {
+	return ss.Provisioners[name]
+}
+
+// LoadSchemas searches the given configuration, state  and plan (any of which
+// may be nil) for constructs that have an associated schema, requests the
+// necessary schemas from the given component factory (which must _not_ be nil),
+// and returns a single object representing all of the necessary schemas.
+//
+// If an error is returned, it may be a wrapped tfdiags.Diagnostics describing
+// errors across multiple separate objects. Errors here will usually indicate
+// either misbehavior on the part of one of the providers or of the provider
+// protocol itself. When returned with errors, the returned schemas object is
+// still valid but may be incomplete.
+func LoadSchemas(config *configs.Config, state *states.State, components contextComponentFactory) (*Schemas, error) {
+	schemas := &Schemas{
+		Providers:    map[addrs.Provider]*ProviderSchema{},
+		Provisioners: map[string]*configschema.Block{},
+	}
+	var diags tfdiags.Diagnostics
+
+	newDiags := loadProviderSchemas(schemas.Providers, config, state, components)
+	diags = diags.Append(newDiags)
+	newDiags = loadProvisionerSchemas(schemas.Provisioners, config, components)
+	diags = diags.Append(newDiags)
+
+	return schemas, diags.Err()
+}
+
+func loadProviderSchemas(schemas map[addrs.Provider]*ProviderSchema, config *configs.Config, state *states.State, components contextComponentFactory) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	ensure := func(fqn addrs.Provider) {
+		name := fqn.String()
+
+		if _, exists := schemas[fqn]; exists {
+			return
+		}
+
+		log.Printf("[TRACE] LoadSchemas: retrieving schema for provider type %q", name)
+		provider, err := components.ResourceProvider(fqn)
+		if err != nil {
+			// We'll put a stub in the map so we won't re-attempt this on
+			// future calls.
+			schemas[fqn] = &ProviderSchema{}
+			diags = diags.Append(
+				fmt.Errorf("Failed to instantiate provider %q to obtain schema: %s", name, err),
+			)
+			return
+		}
+		defer func() {
+			provider.Close()
+		}()
+
+		resp := provider.GetProviderSchema()
+		if resp.Diagnostics.HasErrors() {
+			// We'll put a stub in the map so we won't re-attempt this on
+			// future calls.
+			schemas[fqn] = &ProviderSchema{}
+			diags = diags.Append(
+				fmt.Errorf("Failed to retrieve schema from provider %q: %s", name, resp.Diagnostics.Err()),
+			)
+			return
+		}
+
+		s := &ProviderSchema{
+			Provider:      resp.Provider.Block,
+			ResourceTypes: make(map[string]*configschema.Block),
+			DataSources:   make(map[string]*configschema.Block),
+
+			ResourceTypeSchemaVersions: make(map[string]uint64),
+		}
+
+		if resp.Provider.Version < 0 {
+			// We're not using the version numbers here yet, but we'll check
+			// for validity anyway in case we start using them in future.
+			diags = diags.Append(
+				fmt.Errorf("invalid negative schema version provider configuration for provider %q", name),
+			)
+		}
+
+		for t, r := range resp.ResourceTypes {
+			s.ResourceTypes[t] = r.Block
+			s.ResourceTypeSchemaVersions[t] = uint64(r.Version)
+			if r.Version < 0 {
+				diags = diags.Append(
+					fmt.Errorf("invalid negative schema version for resource type %s in provider %q", t, name),
+				)
+			}
+		}
+
+		for t, d := range resp.DataSources {
+			s.DataSources[t] = d.Block
+			if d.Version < 0 {
+				// We're not using the version numbers here yet, but we'll check
+				// for validity anyway in case we start using them in future.
+				diags = diags.Append(
+					fmt.Errorf("invalid negative schema version for data source %s in provider %q", t, name),
+				)
+			}
+		}
+
+		schemas[fqn] = s
+
+		if resp.ProviderMeta.Block != nil {
+			s.ProviderMeta = resp.ProviderMeta.Block
+		}
+	}
+
+	if config != nil {
+		for _, fqn := range config.ProviderTypes() {
+			ensure(fqn)
+		}
+	}
+
+	if state != nil {
+		needed := providers.AddressedTypesAbs(state.ProviderAddrs())
+		for _, typeAddr := range needed {
+			ensure(typeAddr)
+		}
+	}
+
+	return diags
+}
+
+func loadProvisionerSchemas(schemas map[string]*configschema.Block, config *configs.Config, components contextComponentFactory) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	ensure := func(name string) {
+		if _, exists := schemas[name]; exists {
+			return
+		}
+
+		log.Printf("[TRACE] LoadSchemas: retrieving schema for provisioner %q", name)
+		provisioner, err := components.ResourceProvisioner(name)
+		if err != nil {
+			// We'll put a stub in the map so we won't re-attempt this on
+			// future calls.
+			schemas[name] = &configschema.Block{}
+			diags = diags.Append(
+				fmt.Errorf("Failed to instantiate provisioner %q to obtain schema: %s", name, err),
+			)
+			return
+		}
+		defer func() {
+			if closer, ok := provisioner.(ResourceProvisionerCloser); ok {
+				closer.Close()
+			}
+		}()
+
+		resp := provisioner.GetSchema()
+		if resp.Diagnostics.HasErrors() {
+			// We'll put a stub in the map so we won't re-attempt this on
+			// future calls.
+			schemas[name] = &configschema.Block{}
+			diags = diags.Append(
+				fmt.Errorf("Failed to retrieve schema from provisioner %q: %s", name, resp.Diagnostics.Err()),
+			)
+			return
+		}
+
+		schemas[name] = resp.Provisioner
+	}
+
+	if config != nil {
+		for _, rc := range config.Module.ManagedResources {
+			for _, pc := range rc.Managed.Provisioners {
+				ensure(pc.Type)
+			}
+		}
+
+		// Must also visit our child modules, recursively.
+		for _, cc := range config.Children {
+			childDiags := loadProvisionerSchemas(schemas, cc, components)
+			diags = diags.Append(childDiags)
+		}
+	}
+
+	return diags
+}
+
+// ProviderSchema represents the schema for a provider's own configuration
+// and the configuration for some or all of its resources and data sources.
+//
+// The completeness of this structure depends on how it was constructed.
+// When constructed for a configuration, it will generally include only
+// resource types and data sources used by that configuration.
+type ProviderSchema struct {
+	Provider      *configschema.Block
+	ProviderMeta  *configschema.Block
+	ResourceTypes map[string]*configschema.Block
+	DataSources   map[string]*configschema.Block
+
+	ResourceTypeSchemaVersions map[string]uint64
+}
+
+// SchemaForResourceType attempts to find a schema for the given mode and type.
+// Returns nil if no such schema is available.
+func (ps *ProviderSchema) SchemaForResourceType(mode addrs.ResourceMode, typeName string) (schema *configschema.Block, version uint64) {
+	switch mode {
+	case addrs.ManagedResourceMode:
+		return ps.ResourceTypes[typeName], ps.ResourceTypeSchemaVersions[typeName]
+	case addrs.DataResourceMode:
+		// Data resources don't have schema versions right now, since state is discarded for each refresh
+		return ps.DataSources[typeName], 0
+	default:
+		// Shouldn't happen, because the above cases are comprehensive.
+		return nil, 0
+	}
+}
+
+// SchemaForResourceAddr attempts to find a schema for the mode and type from
+// the given resource address. Returns nil if no such schema is available.
+func (ps *ProviderSchema) SchemaForResourceAddr(addr addrs.Resource) (schema *configschema.Block, version uint64) {
+	return ps.SchemaForResourceType(addr.Mode, addr.Type)
+}
+
+// ProviderSchemaRequest is used to describe to a ResourceProvider which
+// aspects of schema are required, when calling the GetSchema method.
+type ProviderSchemaRequest struct {
+	ResourceTypes []string
+	DataSources   []string
+}
diff --git a/v1.5.7/internal/legacy/terraform/state.go b/v1.5.7/internal/legacy/terraform/state.go
new file mode 100644
index 0000000..46fdd62
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/state.go
@@ -0,0 +1,2257 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"reflect"
+	"sort"
+	"strconv"
+	"strings"
+	"sync"
+
+	"github.com/hashicorp/errwrap"
+	multierror "github.com/hashicorp/go-multierror"
+	uuid "github.com/hashicorp/go-uuid"
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	tfversion "github.com/hashicorp/terraform/version"
+	"github.com/mitchellh/copystructure"
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+)
+
+const (
+	// StateVersion is the current version for our state file
+	StateVersion = 3
+)
+
+// rootModulePath is the path of the root module
+var rootModulePath = []string{"root"}
+
+// normalizeModulePath transforms a legacy module path (which may or may not
+// have a redundant "root" label at the start of it) into an
+// addrs.ModuleInstance representing the same module.
+//
+// For legacy reasons, different parts of Terraform disagree about whether the
+// root module has the path []string{} or []string{"root"}, and so this
+// function accepts both and trims off the "root". An implication of this is
+// that it's not possible to actually have a module call in the root module
+// that is itself named "root", since that would be ambiguous.
+//
+// normalizeModulePath takes a raw module path and returns a path that
+// has the rootModulePath prepended to it. If I could go back in time I
+// would've never had a rootModulePath (empty path would be root). We can
+// still fix this but thats a big refactor that my branch doesn't make sense
+// for. Instead, this function normalizes paths.
+func normalizeModulePath(p []string) addrs.ModuleInstance {
+	// FIXME: Remove this once everyone is using addrs.ModuleInstance.
+
+	if len(p) > 0 && p[0] == "root" {
+		p = p[1:]
+	}
+
+	ret := make(addrs.ModuleInstance, len(p))
+	for i, name := range p {
+		// For now we don't actually support modules with multiple instances
+		// identified by keys, so we just treat every path element as a
+		// step with no key.
+		ret[i] = addrs.ModuleInstanceStep{
+			Name: name,
+		}
+	}
+	return ret
+}
+
+// State keeps track of a snapshot state-of-the-world that Terraform
+// can use to keep track of what real world resources it is actually
+// managing.
+type State struct {
+	// Version is the state file protocol version.
+	Version int `json:"version"`
+
+	// TFVersion is the version of Terraform that wrote this state.
+	TFVersion string `json:"terraform_version,omitempty"`
+
+	// Serial is incremented on any operation that modifies
+	// the State file. It is used to detect potentially conflicting
+	// updates.
+	Serial int64 `json:"serial"`
+
+	// Lineage is set when a new, blank state is created and then
+	// never updated. This allows us to determine whether the serials
+	// of two states can be meaningfully compared.
+	// Apart from the guarantee that collisions between two lineages
+	// are very unlikely, this value is opaque and external callers
+	// should only compare lineage strings byte-for-byte for equality.
+	Lineage string `json:"lineage"`
+
+	// Remote is used to track the metadata required to
+	// pull and push state files from a remote storage endpoint.
+	Remote *RemoteState `json:"remote,omitempty"`
+
+	// Backend tracks the configuration for the backend in use with
+	// this state. This is used to track any changes in the backend
+	// configuration.
+	Backend *BackendState `json:"backend,omitempty"`
+
+	// Modules contains all the modules in a breadth-first order
+	Modules []*ModuleState `json:"modules"`
+
+	mu sync.Mutex
+}
+
+func (s *State) Lock()   { s.mu.Lock() }
+func (s *State) Unlock() { s.mu.Unlock() }
+
+// NewState is used to initialize a blank state
+func NewState() *State {
+	s := &State{}
+	s.init()
+	return s
+}
+
+// Children returns the ModuleStates that are direct children of
+// the given path. If the path is "root", for example, then children
+// returned might be "root.child", but not "root.child.grandchild".
+func (s *State) Children(path []string) []*ModuleState {
+	s.Lock()
+	defer s.Unlock()
+	// TODO: test
+
+	return s.children(path)
+}
+
+func (s *State) children(path []string) []*ModuleState {
+	result := make([]*ModuleState, 0)
+	for _, m := range s.Modules {
+		if m == nil {
+			continue
+		}
+
+		if len(m.Path) != len(path)+1 {
+			continue
+		}
+		if !reflect.DeepEqual(path, m.Path[:len(path)]) {
+			continue
+		}
+
+		result = append(result, m)
+	}
+
+	return result
+}
+
+// AddModule adds the module with the given path to the state.
+//
+// This should be the preferred method to add module states since it
+// allows us to optimize lookups later as well as control sorting.
+func (s *State) AddModule(path addrs.ModuleInstance) *ModuleState {
+	s.Lock()
+	defer s.Unlock()
+
+	return s.addModule(path)
+}
+
+func (s *State) addModule(path addrs.ModuleInstance) *ModuleState {
+	// check if the module exists first
+	m := s.moduleByPath(path)
+	if m != nil {
+		return m
+	}
+
+	// Lower the new-style address into a legacy-style address.
+	// This requires that none of the steps have instance keys, which is
+	// true for all addresses at the time of implementing this because
+	// "count" and "for_each" are not yet implemented for modules.
+	// For the purposes of state, the legacy address format also includes
+	// a redundant extra prefix element "root". It is important to include
+	// this because the "prune" method will remove any module that has a
+	// path length less than one, and other parts of the state code will
+	// trim off the first element indiscriminately.
+	legacyPath := make([]string, len(path)+1)
+	legacyPath[0] = "root"
+	for i, step := range path {
+		if step.InstanceKey != addrs.NoKey {
+			// FIXME: Once the rest of Terraform is ready to use count and
+			// for_each, remove all of this and just write the addrs.ModuleInstance
+			// value itself into the ModuleState.
+			panic("state cannot represent modules with count or for_each keys")
+		}
+
+		legacyPath[i+1] = step.Name
+	}
+
+	m = &ModuleState{Path: legacyPath}
+	m.init()
+	s.Modules = append(s.Modules, m)
+	s.sort()
+	return m
+}
+
+// ModuleByPath is used to lookup the module state for the given path.
+// This should be the preferred lookup mechanism as it allows for future
+// lookup optimizations.
+func (s *State) ModuleByPath(path addrs.ModuleInstance) *ModuleState {
+	if s == nil {
+		return nil
+	}
+	s.Lock()
+	defer s.Unlock()
+
+	return s.moduleByPath(path)
+}
+
+func (s *State) moduleByPath(path addrs.ModuleInstance) *ModuleState {
+	for _, mod := range s.Modules {
+		if mod == nil {
+			continue
+		}
+		if mod.Path == nil {
+			panic("missing module path")
+		}
+		modPath := normalizeModulePath(mod.Path)
+		if modPath.String() == path.String() {
+			return mod
+		}
+	}
+	return nil
+}
+
+// Empty returns true if the state is empty.
+func (s *State) Empty() bool {
+	if s == nil {
+		return true
+	}
+	s.Lock()
+	defer s.Unlock()
+
+	return len(s.Modules) == 0
+}
+
+// HasResources returns true if the state contains any resources.
+//
+// This is similar to !s.Empty, but returns true also in the case where the
+// state has modules but all of them are devoid of resources.
+func (s *State) HasResources() bool {
+	if s.Empty() {
+		return false
+	}
+
+	for _, mod := range s.Modules {
+		if len(mod.Resources) > 0 {
+			return true
+		}
+	}
+
+	return false
+}
+
+// IsRemote returns true if State represents a state that exists and is
+// remote.
+func (s *State) IsRemote() bool {
+	if s == nil {
+		return false
+	}
+	s.Lock()
+	defer s.Unlock()
+
+	if s.Remote == nil {
+		return false
+	}
+	if s.Remote.Type == "" {
+		return false
+	}
+
+	return true
+}
+
+// Validate validates the integrity of this state file.
+//
+// Certain properties of the statefile are expected by Terraform in order
+// to behave properly. The core of Terraform will assume that once it
+// receives a State structure that it has been validated. This validation
+// check should be called to ensure that.
+//
+// If this returns an error, then the user should be notified. The error
+// response will include detailed information on the nature of the error.
+func (s *State) Validate() error {
+	s.Lock()
+	defer s.Unlock()
+
+	var result error
+
+	// !!!! FOR DEVELOPERS !!!!
+	//
+	// Any errors returned from this Validate function will BLOCK TERRAFORM
+	// from loading a state file. Therefore, this should only contain checks
+	// that are only resolvable through manual intervention.
+	//
+	// !!!! FOR DEVELOPERS !!!!
+
+	// Make sure there are no duplicate module states. We open a new
+	// block here so we can use basic variable names and future validations
+	// can do the same.
+	{
+		found := make(map[string]struct{})
+		for _, ms := range s.Modules {
+			if ms == nil {
+				continue
+			}
+
+			key := strings.Join(ms.Path, ".")
+			if _, ok := found[key]; ok {
+				result = multierror.Append(result, fmt.Errorf(
+					strings.TrimSpace(stateValidateErrMultiModule), key))
+				continue
+			}
+
+			found[key] = struct{}{}
+		}
+	}
+
+	return result
+}
+
+// Remove removes the item in the state at the given address, returning
+// any errors that may have occurred.
+//
+// If the address references a module state or resource, it will delete
+// all children as well. To check what will be deleted, use a StateFilter
+// first.
+func (s *State) Remove(addr ...string) error {
+	s.Lock()
+	defer s.Unlock()
+
+	// Filter out what we need to delete
+	filter := &StateFilter{State: s}
+	results, err := filter.Filter(addr...)
+	if err != nil {
+		return err
+	}
+
+	// If we have no results, just exit early, we're not going to do anything.
+	// While what happens below is fairly fast, this is an important early
+	// exit since the prune below might modify the state more and we don't
+	// want to modify the state if we don't have to.
+	if len(results) == 0 {
+		return nil
+	}
+
+	// Go through each result and grab what we need
+	removed := make(map[interface{}]struct{})
+	for _, r := range results {
+		// Convert the path to our own type
+		path := append([]string{"root"}, r.Path...)
+
+		// If we removed this already, then ignore
+		if _, ok := removed[r.Value]; ok {
+			continue
+		}
+
+		// If we removed the parent already, then ignore
+		if r.Parent != nil {
+			if _, ok := removed[r.Parent.Value]; ok {
+				continue
+			}
+		}
+
+		// Add this to the removed list
+		removed[r.Value] = struct{}{}
+
+		switch v := r.Value.(type) {
+		case *ModuleState:
+			s.removeModule(path, v)
+		case *ResourceState:
+			s.removeResource(path, v)
+		case *InstanceState:
+			s.removeInstance(path, r.Parent.Value.(*ResourceState), v)
+		default:
+			return fmt.Errorf("unknown type to delete: %T", r.Value)
+		}
+	}
+
+	// Prune since the removal functions often do the bare minimum to
+	// remove a thing and may leave around dangling empty modules, resources,
+	// etc. Prune will clean that all up.
+	s.prune()
+
+	return nil
+}
+
+func (s *State) removeModule(path []string, v *ModuleState) {
+	for i, m := range s.Modules {
+		if m == v {
+			s.Modules, s.Modules[len(s.Modules)-1] = append(s.Modules[:i], s.Modules[i+1:]...), nil
+			return
+		}
+	}
+}
+
+func (s *State) removeResource(path []string, v *ResourceState) {
+	// Get the module this resource lives in. If it doesn't exist, we're done.
+	mod := s.moduleByPath(normalizeModulePath(path))
+	if mod == nil {
+		return
+	}
+
+	// Find this resource. This is a O(N) lookup when if we had the key
+	// it could be O(1) but even with thousands of resources this shouldn't
+	// matter right now. We can easily up performance here when the time comes.
+	for k, r := range mod.Resources {
+		if r == v {
+			// Found it
+			delete(mod.Resources, k)
+			return
+		}
+	}
+}
+
+func (s *State) removeInstance(path []string, r *ResourceState, v *InstanceState) {
+	// Go through the resource and find the instance that matches this
+	// (if any) and remove it.
+
+	// Check primary
+	if r.Primary == v {
+		r.Primary = nil
+		return
+	}
+
+	// Check lists
+	lists := [][]*InstanceState{r.Deposed}
+	for _, is := range lists {
+		for i, instance := range is {
+			if instance == v {
+				// Found it, remove it
+				is, is[len(is)-1] = append(is[:i], is[i+1:]...), nil
+
+				// Done
+				return
+			}
+		}
+	}
+}
+
+// RootModule returns the ModuleState for the root module
+func (s *State) RootModule() *ModuleState {
+	root := s.ModuleByPath(addrs.RootModuleInstance)
+	if root == nil {
+		panic("missing root module")
+	}
+	return root
+}
+
+// Equal tests if one state is equal to another.
+func (s *State) Equal(other *State) bool {
+	// If one is nil, we do a direct check
+	if s == nil || other == nil {
+		return s == other
+	}
+
+	s.Lock()
+	defer s.Unlock()
+	return s.equal(other)
+}
+
+func (s *State) equal(other *State) bool {
+	if s == nil || other == nil {
+		return s == other
+	}
+
+	// If the versions are different, they're certainly not equal
+	if s.Version != other.Version {
+		return false
+	}
+
+	// If any of the modules are not equal, then this state isn't equal
+	if len(s.Modules) != len(other.Modules) {
+		return false
+	}
+	for _, m := range s.Modules {
+		// This isn't very optimal currently but works.
+		otherM := other.moduleByPath(normalizeModulePath(m.Path))
+		if otherM == nil {
+			return false
+		}
+
+		// If they're not equal, then we're not equal!
+		if !m.Equal(otherM) {
+			return false
+		}
+	}
+
+	return true
+}
+
+// MarshalEqual is similar to Equal but provides a stronger definition of
+// "equal", where two states are equal if and only if their serialized form
+// is byte-for-byte identical.
+//
+// This is primarily useful for callers that are trying to save snapshots
+// of state to persistent storage, allowing them to detect when a new
+// snapshot must be taken.
+//
+// Note that the serial number and lineage are included in the serialized form,
+// so it's the caller's responsibility to properly manage these attributes
+// so that this method is only called on two states that have the same
+// serial and lineage, unless detecting such differences is desired.
+func (s *State) MarshalEqual(other *State) bool {
+	if s == nil && other == nil {
+		return true
+	} else if s == nil || other == nil {
+		return false
+	}
+
+	recvBuf := &bytes.Buffer{}
+	otherBuf := &bytes.Buffer{}
+
+	err := WriteState(s, recvBuf)
+	if err != nil {
+		// should never happen, since we're writing to a buffer
+		panic(err)
+	}
+
+	err = WriteState(other, otherBuf)
+	if err != nil {
+		// should never happen, since we're writing to a buffer
+		panic(err)
+	}
+
+	return bytes.Equal(recvBuf.Bytes(), otherBuf.Bytes())
+}
+
+type StateAgeComparison int
+
+const (
+	StateAgeEqual         StateAgeComparison = 0
+	StateAgeReceiverNewer StateAgeComparison = 1
+	StateAgeReceiverOlder StateAgeComparison = -1
+)
+
+// CompareAges compares one state with another for which is "older".
+//
+// This is a simple check using the state's serial, and is thus only as
+// reliable as the serial itself. In the normal case, only one state
+// exists for a given combination of lineage/serial, but Terraform
+// does not guarantee this and so the result of this method should be
+// used with care.
+//
+// Returns an integer that is negative if the receiver is older than
+// the argument, positive if the converse, and zero if they are equal.
+// An error is returned if the two states are not of the same lineage,
+// in which case the integer returned has no meaning.
+func (s *State) CompareAges(other *State) (StateAgeComparison, error) {
+	// nil states are "older" than actual states
+	switch {
+	case s != nil && other == nil:
+		return StateAgeReceiverNewer, nil
+	case s == nil && other != nil:
+		return StateAgeReceiverOlder, nil
+	case s == nil && other == nil:
+		return StateAgeEqual, nil
+	}
+
+	if !s.SameLineage(other) {
+		return StateAgeEqual, fmt.Errorf(
+			"can't compare two states of differing lineage",
+		)
+	}
+
+	s.Lock()
+	defer s.Unlock()
+
+	switch {
+	case s.Serial < other.Serial:
+		return StateAgeReceiverOlder, nil
+	case s.Serial > other.Serial:
+		return StateAgeReceiverNewer, nil
+	default:
+		return StateAgeEqual, nil
+	}
+}
+
+// SameLineage returns true only if the state given in argument belongs
+// to the same "lineage" of states as the receiver.
+func (s *State) SameLineage(other *State) bool {
+	s.Lock()
+	defer s.Unlock()
+
+	// If one of the states has no lineage then it is assumed to predate
+	// this concept, and so we'll accept it as belonging to any lineage
+	// so that a lineage string can be assigned to newer versions
+	// without breaking compatibility with older versions.
+	if s.Lineage == "" || other.Lineage == "" {
+		return true
+	}
+
+	return s.Lineage == other.Lineage
+}
+
+// DeepCopy performs a deep copy of the state structure and returns
+// a new structure.
+func (s *State) DeepCopy() *State {
+	if s == nil {
+		return nil
+	}
+
+	copy, err := copystructure.Config{Lock: true}.Copy(s)
+	if err != nil {
+		panic(err)
+	}
+
+	return copy.(*State)
+}
+
+// FromFutureTerraform checks if this state was written by a Terraform
+// version from the future.
+func (s *State) FromFutureTerraform() bool {
+	s.Lock()
+	defer s.Unlock()
+
+	// No TF version means it is certainly from the past
+	if s.TFVersion == "" {
+		return false
+	}
+
+	v := version.Must(version.NewVersion(s.TFVersion))
+	return tfversion.SemVer.LessThan(v)
+}
+
+func (s *State) Init() {
+	s.Lock()
+	defer s.Unlock()
+	s.init()
+}
+
+func (s *State) init() {
+	if s.Version == 0 {
+		s.Version = StateVersion
+	}
+
+	if s.moduleByPath(addrs.RootModuleInstance) == nil {
+		s.addModule(addrs.RootModuleInstance)
+	}
+	s.ensureHasLineage()
+
+	for _, mod := range s.Modules {
+		if mod != nil {
+			mod.init()
+		}
+	}
+
+	if s.Remote != nil {
+		s.Remote.init()
+	}
+
+}
+
+func (s *State) EnsureHasLineage() {
+	s.Lock()
+	defer s.Unlock()
+
+	s.ensureHasLineage()
+}
+
+func (s *State) ensureHasLineage() {
+	if s.Lineage == "" {
+		lineage, err := uuid.GenerateUUID()
+		if err != nil {
+			panic(fmt.Errorf("Failed to generate lineage: %v", err))
+		}
+		s.Lineage = lineage
+		log.Printf("[DEBUG] New state was assigned lineage %q\n", s.Lineage)
+	} else {
+		log.Printf("[TRACE] Preserving existing state lineage %q\n", s.Lineage)
+	}
+}
+
+// AddModuleState insert this module state and override any existing ModuleState
+func (s *State) AddModuleState(mod *ModuleState) {
+	mod.init()
+	s.Lock()
+	defer s.Unlock()
+
+	s.addModuleState(mod)
+}
+
+func (s *State) addModuleState(mod *ModuleState) {
+	for i, m := range s.Modules {
+		if reflect.DeepEqual(m.Path, mod.Path) {
+			s.Modules[i] = mod
+			return
+		}
+	}
+
+	s.Modules = append(s.Modules, mod)
+	s.sort()
+}
+
+// prune is used to remove any resources that are no longer required
+func (s *State) prune() {
+	if s == nil {
+		return
+	}
+
+	// Filter out empty modules.
+	// A module is always assumed to have a path, and it's length isn't always
+	// bounds checked later on. Modules may be "emptied" during destroy, but we
+	// never want to store those in the state.
+	for i := 0; i < len(s.Modules); i++ {
+		if s.Modules[i] == nil || len(s.Modules[i].Path) == 0 {
+			s.Modules = append(s.Modules[:i], s.Modules[i+1:]...)
+			i--
+		}
+	}
+
+	for _, mod := range s.Modules {
+		mod.prune()
+	}
+	if s.Remote != nil && s.Remote.Empty() {
+		s.Remote = nil
+	}
+}
+
+// sort sorts the modules
+func (s *State) sort() {
+	sort.Sort(moduleStateSort(s.Modules))
+
+	// Allow modules to be sorted
+	for _, m := range s.Modules {
+		if m != nil {
+			m.sort()
+		}
+	}
+}
+
+func (s *State) String() string {
+	if s == nil {
+		return "<nil>"
+	}
+	s.Lock()
+	defer s.Unlock()
+
+	var buf bytes.Buffer
+	for _, m := range s.Modules {
+		mStr := m.String()
+
+		// If we're the root module, we just write the output directly.
+		if reflect.DeepEqual(m.Path, rootModulePath) {
+			buf.WriteString(mStr + "\n")
+			continue
+		}
+
+		buf.WriteString(fmt.Sprintf("module.%s:\n", strings.Join(m.Path[1:], ".")))
+
+		s := bufio.NewScanner(strings.NewReader(mStr))
+		for s.Scan() {
+			text := s.Text()
+			if text != "" {
+				text = "  " + text
+			}
+
+			buf.WriteString(fmt.Sprintf("%s\n", text))
+		}
+	}
+
+	return strings.TrimSpace(buf.String())
+}
+
+// BackendState stores the configuration to connect to a remote backend.
+type BackendState struct {
+	Type      string          `json:"type"`   // Backend type
+	ConfigRaw json.RawMessage `json:"config"` // Backend raw config
+	Hash      uint64          `json:"hash"`   // Hash of portion of configuration from config files
+}
+
+// Empty returns true if BackendState has no state.
+func (s *BackendState) Empty() bool {
+	return s == nil || s.Type == ""
+}
+
+// Config decodes the type-specific configuration object using the provided
+// schema and returns the result as a cty.Value.
+//
+// An error is returned if the stored configuration does not conform to the
+// given schema.
+func (s *BackendState) Config(schema *configschema.Block) (cty.Value, error) {
+	ty := schema.ImpliedType()
+	if s == nil {
+		return cty.NullVal(ty), nil
+	}
+	return ctyjson.Unmarshal(s.ConfigRaw, ty)
+}
+
+// SetConfig replaces (in-place) the type-specific configuration object using
+// the provided value and associated schema.
+//
+// An error is returned if the given value does not conform to the implied
+// type of the schema.
+func (s *BackendState) SetConfig(val cty.Value, schema *configschema.Block) error {
+	ty := schema.ImpliedType()
+	buf, err := ctyjson.Marshal(val, ty)
+	if err != nil {
+		return err
+	}
+	s.ConfigRaw = buf
+	return nil
+}
+
+// ForPlan produces an alternative representation of the reciever that is
+// suitable for storing in a plan. The current workspace must additionally
+// be provided, to be stored alongside the backend configuration.
+//
+// The backend configuration schema is required in order to properly
+// encode the backend-specific configuration settings.
+func (s *BackendState) ForPlan(schema *configschema.Block, workspaceName string) (*plans.Backend, error) {
+	if s == nil {
+		return nil, nil
+	}
+
+	configVal, err := s.Config(schema)
+	if err != nil {
+		return nil, errwrap.Wrapf("failed to decode backend config: {{err}}", err)
+	}
+	return plans.NewBackend(s.Type, configVal, schema, workspaceName)
+}
+
+// RemoteState is used to track the information about a remote
+// state store that we push/pull state to.
+type RemoteState struct {
+	// Type controls the client we use for the remote state
+	Type string `json:"type"`
+
+	// Config is used to store arbitrary configuration that
+	// is type specific
+	Config map[string]string `json:"config"`
+
+	mu sync.Mutex
+}
+
+func (s *RemoteState) Lock()   { s.mu.Lock() }
+func (s *RemoteState) Unlock() { s.mu.Unlock() }
+
+func (r *RemoteState) init() {
+	r.Lock()
+	defer r.Unlock()
+
+	if r.Config == nil {
+		r.Config = make(map[string]string)
+	}
+}
+
+func (r *RemoteState) deepcopy() *RemoteState {
+	r.Lock()
+	defer r.Unlock()
+
+	confCopy := make(map[string]string, len(r.Config))
+	for k, v := range r.Config {
+		confCopy[k] = v
+	}
+	return &RemoteState{
+		Type:   r.Type,
+		Config: confCopy,
+	}
+}
+
+func (r *RemoteState) Empty() bool {
+	if r == nil {
+		return true
+	}
+	r.Lock()
+	defer r.Unlock()
+
+	return r.Type == ""
+}
+
+func (r *RemoteState) Equals(other *RemoteState) bool {
+	r.Lock()
+	defer r.Unlock()
+
+	if r.Type != other.Type {
+		return false
+	}
+	if len(r.Config) != len(other.Config) {
+		return false
+	}
+	for k, v := range r.Config {
+		if other.Config[k] != v {
+			return false
+		}
+	}
+	return true
+}
+
+// OutputState is used to track the state relevant to a single output.
+type OutputState struct {
+	// Sensitive describes whether the output is considered sensitive,
+	// which may lead to masking the value on screen in some cases.
+	Sensitive bool `json:"sensitive"`
+	// Type describes the structure of Value. Valid values are "string",
+	// "map" and "list"
+	Type string `json:"type"`
+	// Value contains the value of the output, in the structure described
+	// by the Type field.
+	Value interface{} `json:"value"`
+
+	mu sync.Mutex
+}
+
+func (s *OutputState) Lock()   { s.mu.Lock() }
+func (s *OutputState) Unlock() { s.mu.Unlock() }
+
+func (s *OutputState) String() string {
+	return fmt.Sprintf("%#v", s.Value)
+}
+
+// Equal compares two OutputState structures for equality. nil values are
+// considered equal.
+func (s *OutputState) Equal(other *OutputState) bool {
+	if s == nil && other == nil {
+		return true
+	}
+
+	if s == nil || other == nil {
+		return false
+	}
+	s.Lock()
+	defer s.Unlock()
+
+	if s.Type != other.Type {
+		return false
+	}
+
+	if s.Sensitive != other.Sensitive {
+		return false
+	}
+
+	if !reflect.DeepEqual(s.Value, other.Value) {
+		return false
+	}
+
+	return true
+}
+
+func (s *OutputState) deepcopy() *OutputState {
+	if s == nil {
+		return nil
+	}
+
+	stateCopy, err := copystructure.Config{Lock: true}.Copy(s)
+	if err != nil {
+		panic(fmt.Errorf("Error copying output value: %s", err))
+	}
+
+	return stateCopy.(*OutputState)
+}
+
+// ModuleState is used to track all the state relevant to a single
+// module. Previous to Terraform 0.3, all state belonged to the "root"
+// module.
+type ModuleState struct {
+	// Path is the import path from the root module. Modules imports are
+	// always disjoint, so the path represents amodule tree
+	Path []string `json:"path"`
+
+	// Locals are kept only transiently in-memory, because we can always
+	// re-compute them.
+	Locals map[string]interface{} `json:"-"`
+
+	// Outputs declared by the module and maintained for each module
+	// even though only the root module technically needs to be kept.
+	// This allows operators to inspect values at the boundaries.
+	Outputs map[string]*OutputState `json:"outputs"`
+
+	// Resources is a mapping of the logically named resource to
+	// the state of the resource. Each resource may actually have
+	// N instances underneath, although a user only needs to think
+	// about the 1:1 case.
+	Resources map[string]*ResourceState `json:"resources"`
+
+	// Dependencies are a list of things that this module relies on
+	// existing to remain intact. For example: an module may depend
+	// on a VPC ID given by an aws_vpc resource.
+	//
+	// Terraform uses this information to build valid destruction
+	// orders and to warn the user if they're destroying a module that
+	// another resource depends on.
+	//
+	// Things can be put into this list that may not be managed by
+	// Terraform. If Terraform doesn't find a matching ID in the
+	// overall state, then it assumes it isn't managed and doesn't
+	// worry about it.
+	Dependencies []string `json:"depends_on"`
+
+	mu sync.Mutex
+}
+
+func (s *ModuleState) Lock()   { s.mu.Lock() }
+func (s *ModuleState) Unlock() { s.mu.Unlock() }
+
+// Equal tests whether one module state is equal to another.
+func (m *ModuleState) Equal(other *ModuleState) bool {
+	m.Lock()
+	defer m.Unlock()
+
+	// Paths must be equal
+	if !reflect.DeepEqual(m.Path, other.Path) {
+		return false
+	}
+
+	// Outputs must be equal
+	if len(m.Outputs) != len(other.Outputs) {
+		return false
+	}
+	for k, v := range m.Outputs {
+		if !other.Outputs[k].Equal(v) {
+			return false
+		}
+	}
+
+	// Dependencies must be equal. This sorts these in place but
+	// this shouldn't cause any problems.
+	sort.Strings(m.Dependencies)
+	sort.Strings(other.Dependencies)
+	if len(m.Dependencies) != len(other.Dependencies) {
+		return false
+	}
+	for i, d := range m.Dependencies {
+		if other.Dependencies[i] != d {
+			return false
+		}
+	}
+
+	// Resources must be equal
+	if len(m.Resources) != len(other.Resources) {
+		return false
+	}
+	for k, r := range m.Resources {
+		otherR, ok := other.Resources[k]
+		if !ok {
+			return false
+		}
+
+		if !r.Equal(otherR) {
+			return false
+		}
+	}
+
+	return true
+}
+
+// IsRoot says whether or not this module diff is for the root module.
+func (m *ModuleState) IsRoot() bool {
+	m.Lock()
+	defer m.Unlock()
+	return reflect.DeepEqual(m.Path, rootModulePath)
+}
+
+// IsDescendent returns true if other is a descendent of this module.
+func (m *ModuleState) IsDescendent(other *ModuleState) bool {
+	m.Lock()
+	defer m.Unlock()
+
+	i := len(m.Path)
+	return len(other.Path) > i && reflect.DeepEqual(other.Path[:i], m.Path)
+}
+
+// Orphans returns a list of keys of resources that are in the State
+// but aren't present in the configuration itself. Hence, these keys
+// represent the state of resources that are orphans.
+func (m *ModuleState) Orphans(c *configs.Module) []addrs.ResourceInstance {
+	m.Lock()
+	defer m.Unlock()
+
+	inConfig := make(map[string]struct{})
+	if c != nil {
+		for _, r := range c.ManagedResources {
+			inConfig[r.Addr().String()] = struct{}{}
+		}
+		for _, r := range c.DataResources {
+			inConfig[r.Addr().String()] = struct{}{}
+		}
+	}
+
+	var result []addrs.ResourceInstance
+	for k := range m.Resources {
+		// Since we've not yet updated state to use our new address format,
+		// we need to do some shimming here.
+		legacyAddr, err := parseResourceAddressInternal(k)
+		if err != nil {
+			// Suggests that the user tampered with the state, since we always
+			// generate valid internal addresses.
+			log.Printf("ModuleState has invalid resource key %q. Ignoring.", k)
+			continue
+		}
+
+		addr := legacyAddr.AbsResourceInstanceAddr().Resource
+		compareKey := addr.Resource.String() // compare by resource address, ignoring instance key
+		if _, exists := inConfig[compareKey]; !exists {
+			result = append(result, addr)
+		}
+	}
+	return result
+}
+
+// RemovedOutputs returns a list of outputs that are in the State but aren't
+// present in the configuration itself.
+func (s *ModuleState) RemovedOutputs(outputs map[string]*configs.Output) []addrs.OutputValue {
+	if outputs == nil {
+		// If we got no output map at all then we'll just treat our set of
+		// configured outputs as empty, since that suggests that they've all
+		// been removed by removing their containing module.
+		outputs = make(map[string]*configs.Output)
+	}
+
+	s.Lock()
+	defer s.Unlock()
+
+	var ret []addrs.OutputValue
+	for n := range s.Outputs {
+		if _, declared := outputs[n]; !declared {
+			ret = append(ret, addrs.OutputValue{
+				Name: n,
+			})
+		}
+	}
+
+	return ret
+}
+
+// View returns a view with the given resource prefix.
+func (m *ModuleState) View(id string) *ModuleState {
+	if m == nil {
+		return m
+	}
+
+	r := m.deepcopy()
+	for k, _ := range r.Resources {
+		if id == k || strings.HasPrefix(k, id+".") {
+			continue
+		}
+
+		delete(r.Resources, k)
+	}
+
+	return r
+}
+
+func (m *ModuleState) init() {
+	m.Lock()
+	defer m.Unlock()
+
+	if m.Path == nil {
+		m.Path = []string{}
+	}
+	if m.Outputs == nil {
+		m.Outputs = make(map[string]*OutputState)
+	}
+	if m.Resources == nil {
+		m.Resources = make(map[string]*ResourceState)
+	}
+
+	if m.Dependencies == nil {
+		m.Dependencies = make([]string, 0)
+	}
+
+	for _, rs := range m.Resources {
+		rs.init()
+	}
+}
+
+func (m *ModuleState) deepcopy() *ModuleState {
+	if m == nil {
+		return nil
+	}
+
+	stateCopy, err := copystructure.Config{Lock: true}.Copy(m)
+	if err != nil {
+		panic(err)
+	}
+
+	return stateCopy.(*ModuleState)
+}
+
+// prune is used to remove any resources that are no longer required
+func (m *ModuleState) prune() {
+	m.Lock()
+	defer m.Unlock()
+
+	for k, v := range m.Resources {
+		if v == nil || (v.Primary == nil || v.Primary.ID == "") && len(v.Deposed) == 0 {
+			delete(m.Resources, k)
+			continue
+		}
+
+		v.prune()
+	}
+
+	for k, v := range m.Outputs {
+		if v.Value == hcl2shim.UnknownVariableValue {
+			delete(m.Outputs, k)
+		}
+	}
+
+	m.Dependencies = uniqueStrings(m.Dependencies)
+}
+
+func (m *ModuleState) sort() {
+	for _, v := range m.Resources {
+		v.sort()
+	}
+}
+
+func (m *ModuleState) String() string {
+	m.Lock()
+	defer m.Unlock()
+
+	var buf bytes.Buffer
+
+	if len(m.Resources) == 0 {
+		buf.WriteString("<no state>")
+	}
+
+	names := make([]string, 0, len(m.Resources))
+	for name, _ := range m.Resources {
+		names = append(names, name)
+	}
+
+	sort.Sort(resourceNameSort(names))
+
+	for _, k := range names {
+		rs := m.Resources[k]
+		var id string
+		if rs.Primary != nil {
+			id = rs.Primary.ID
+		}
+		if id == "" {
+			id = "<not created>"
+		}
+
+		taintStr := ""
+		if rs.Primary.Tainted {
+			taintStr = " (tainted)"
+		}
+
+		deposedStr := ""
+		if len(rs.Deposed) > 0 {
+			deposedStr = fmt.Sprintf(" (%d deposed)", len(rs.Deposed))
+		}
+
+		buf.WriteString(fmt.Sprintf("%s:%s%s\n", k, taintStr, deposedStr))
+		buf.WriteString(fmt.Sprintf("  ID = %s\n", id))
+		if rs.Provider != "" {
+			buf.WriteString(fmt.Sprintf("  provider = %s\n", rs.Provider))
+		}
+
+		var attributes map[string]string
+		if rs.Primary != nil {
+			attributes = rs.Primary.Attributes
+		}
+		attrKeys := make([]string, 0, len(attributes))
+		for ak, _ := range attributes {
+			if ak == "id" {
+				continue
+			}
+
+			attrKeys = append(attrKeys, ak)
+		}
+
+		sort.Strings(attrKeys)
+
+		for _, ak := range attrKeys {
+			av := attributes[ak]
+			buf.WriteString(fmt.Sprintf("  %s = %s\n", ak, av))
+		}
+
+		for idx, t := range rs.Deposed {
+			taintStr := ""
+			if t.Tainted {
+				taintStr = " (tainted)"
+			}
+			buf.WriteString(fmt.Sprintf("  Deposed ID %d = %s%s\n", idx+1, t.ID, taintStr))
+		}
+
+		if len(rs.Dependencies) > 0 {
+			buf.WriteString(fmt.Sprintf("\n  Dependencies:\n"))
+			for _, dep := range rs.Dependencies {
+				buf.WriteString(fmt.Sprintf("    %s\n", dep))
+			}
+		}
+	}
+
+	if len(m.Outputs) > 0 {
+		buf.WriteString("\nOutputs:\n\n")
+
+		ks := make([]string, 0, len(m.Outputs))
+		for k, _ := range m.Outputs {
+			ks = append(ks, k)
+		}
+
+		sort.Strings(ks)
+
+		for _, k := range ks {
+			v := m.Outputs[k]
+			switch vTyped := v.Value.(type) {
+			case string:
+				buf.WriteString(fmt.Sprintf("%s = %s\n", k, vTyped))
+			case []interface{}:
+				buf.WriteString(fmt.Sprintf("%s = %s\n", k, vTyped))
+			case map[string]interface{}:
+				var mapKeys []string
+				for key, _ := range vTyped {
+					mapKeys = append(mapKeys, key)
+				}
+				sort.Strings(mapKeys)
+
+				var mapBuf bytes.Buffer
+				mapBuf.WriteString("{")
+				for _, key := range mapKeys {
+					mapBuf.WriteString(fmt.Sprintf("%s:%s ", key, vTyped[key]))
+				}
+				mapBuf.WriteString("}")
+
+				buf.WriteString(fmt.Sprintf("%s = %s\n", k, mapBuf.String()))
+			}
+		}
+	}
+
+	return buf.String()
+}
+
+func (m *ModuleState) Empty() bool {
+	return len(m.Locals) == 0 && len(m.Outputs) == 0 && len(m.Resources) == 0
+}
+
+// ResourceStateKey is a structured representation of the key used for the
+// ModuleState.Resources mapping
+type ResourceStateKey struct {
+	Name  string
+	Type  string
+	Mode  ResourceMode
+	Index int
+}
+
+// Equal determines whether two ResourceStateKeys are the same
+func (rsk *ResourceStateKey) Equal(other *ResourceStateKey) bool {
+	if rsk == nil || other == nil {
+		return false
+	}
+	if rsk.Mode != other.Mode {
+		return false
+	}
+	if rsk.Type != other.Type {
+		return false
+	}
+	if rsk.Name != other.Name {
+		return false
+	}
+	if rsk.Index != other.Index {
+		return false
+	}
+	return true
+}
+
+func (rsk *ResourceStateKey) String() string {
+	if rsk == nil {
+		return ""
+	}
+	var prefix string
+	switch rsk.Mode {
+	case ManagedResourceMode:
+		prefix = ""
+	case DataResourceMode:
+		prefix = "data."
+	default:
+		panic(fmt.Errorf("unknown resource mode %s", rsk.Mode))
+	}
+	if rsk.Index == -1 {
+		return fmt.Sprintf("%s%s.%s", prefix, rsk.Type, rsk.Name)
+	}
+	return fmt.Sprintf("%s%s.%s.%d", prefix, rsk.Type, rsk.Name, rsk.Index)
+}
+
+// ParseResourceStateKey accepts a key in the format used by
+// ModuleState.Resources and returns a resource name and resource index. In the
+// state, a resource has the format "type.name.index" or "type.name". In the
+// latter case, the index is returned as -1.
+func ParseResourceStateKey(k string) (*ResourceStateKey, error) {
+	parts := strings.Split(k, ".")
+	mode := ManagedResourceMode
+	if len(parts) > 0 && parts[0] == "data" {
+		mode = DataResourceMode
+		// Don't need the constant "data" prefix for parsing
+		// now that we've figured out the mode.
+		parts = parts[1:]
+	}
+	if len(parts) < 2 || len(parts) > 3 {
+		return nil, fmt.Errorf("Malformed resource state key: %s", k)
+	}
+	rsk := &ResourceStateKey{
+		Mode:  mode,
+		Type:  parts[0],
+		Name:  parts[1],
+		Index: -1,
+	}
+	if len(parts) == 3 {
+		index, err := strconv.Atoi(parts[2])
+		if err != nil {
+			return nil, fmt.Errorf("Malformed resource state key index: %s", k)
+		}
+		rsk.Index = index
+	}
+	return rsk, nil
+}
+
+// ResourceState holds the state of a resource that is used so that
+// a provider can find and manage an existing resource as well as for
+// storing attributes that are used to populate variables of child
+// resources.
+//
+// Attributes has attributes about the created resource that are
+// queryable in interpolation: "${type.id.attr}"
+//
+// Extra is just extra data that a provider can return that we store
+// for later, but is not exposed in any way to the user.
+type ResourceState struct {
+	// This is filled in and managed by Terraform, and is the resource
+	// type itself such as "mycloud_instance". If a resource provider sets
+	// this value, it won't be persisted.
+	Type string `json:"type"`
+
+	// Dependencies are a list of things that this resource relies on
+	// existing to remain intact. For example: an AWS instance might
+	// depend on a subnet (which itself might depend on a VPC, and so
+	// on).
+	//
+	// Terraform uses this information to build valid destruction
+	// orders and to warn the user if they're destroying a resource that
+	// another resource depends on.
+	//
+	// Things can be put into this list that may not be managed by
+	// Terraform. If Terraform doesn't find a matching ID in the
+	// overall state, then it assumes it isn't managed and doesn't
+	// worry about it.
+	Dependencies []string `json:"depends_on"`
+
+	// Primary is the current active instance for this resource.
+	// It can be replaced but only after a successful creation.
+	// This is the instances on which providers will act.
+	Primary *InstanceState `json:"primary"`
+
+	// Deposed is used in the mechanics of CreateBeforeDestroy: the existing
+	// Primary is Deposed to get it out of the way for the replacement Primary to
+	// be created by Apply. If the replacement Primary creates successfully, the
+	// Deposed instance is cleaned up.
+	//
+	// If there were problems creating the replacement Primary, the Deposed
+	// instance and the (now tainted) replacement Primary will be swapped so the
+	// tainted replacement will be cleaned up instead.
+	//
+	// An instance will remain in the Deposed list until it is successfully
+	// destroyed and purged.
+	Deposed []*InstanceState `json:"deposed"`
+
+	// Provider is used when a resource is connected to a provider with an alias.
+	// If this string is empty, the resource is connected to the default provider,
+	// e.g. "aws_instance" goes with the "aws" provider.
+	// If the resource block contained a "provider" key, that value will be set here.
+	Provider string `json:"provider"`
+
+	mu sync.Mutex
+}
+
+func (s *ResourceState) Lock()   { s.mu.Lock() }
+func (s *ResourceState) Unlock() { s.mu.Unlock() }
+
+// Equal tests whether two ResourceStates are equal.
+func (s *ResourceState) Equal(other *ResourceState) bool {
+	s.Lock()
+	defer s.Unlock()
+
+	if s.Type != other.Type {
+		return false
+	}
+
+	if s.Provider != other.Provider {
+		return false
+	}
+
+	// Dependencies must be equal
+	sort.Strings(s.Dependencies)
+	sort.Strings(other.Dependencies)
+	if len(s.Dependencies) != len(other.Dependencies) {
+		return false
+	}
+	for i, d := range s.Dependencies {
+		if other.Dependencies[i] != d {
+			return false
+		}
+	}
+
+	// States must be equal
+	if !s.Primary.Equal(other.Primary) {
+		return false
+	}
+
+	return true
+}
+
+// Taint marks a resource as tainted.
+func (s *ResourceState) Taint() {
+	s.Lock()
+	defer s.Unlock()
+
+	if s.Primary != nil {
+		s.Primary.Tainted = true
+	}
+}
+
+// Untaint unmarks a resource as tainted.
+func (s *ResourceState) Untaint() {
+	s.Lock()
+	defer s.Unlock()
+
+	if s.Primary != nil {
+		s.Primary.Tainted = false
+	}
+}
+
+// ProviderAddr returns the provider address for the receiver, by parsing the
+// string representation saved in state. An error can be returned if the
+// value in state is corrupt.
+func (s *ResourceState) ProviderAddr() (addrs.AbsProviderConfig, error) {
+	var diags tfdiags.Diagnostics
+
+	str := s.Provider
+	traversal, travDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1})
+	diags = diags.Append(travDiags)
+	if travDiags.HasErrors() {
+		return addrs.AbsProviderConfig{}, diags.Err()
+	}
+
+	addr, addrDiags := addrs.ParseAbsProviderConfig(traversal)
+	diags = diags.Append(addrDiags)
+	return addr, diags.Err()
+}
+
+func (s *ResourceState) init() {
+	s.Lock()
+	defer s.Unlock()
+
+	if s.Primary == nil {
+		s.Primary = &InstanceState{}
+	}
+	s.Primary.init()
+
+	if s.Dependencies == nil {
+		s.Dependencies = []string{}
+	}
+
+	if s.Deposed == nil {
+		s.Deposed = make([]*InstanceState, 0)
+	}
+}
+
+func (s *ResourceState) deepcopy() *ResourceState {
+	copy, err := copystructure.Config{Lock: true}.Copy(s)
+	if err != nil {
+		panic(err)
+	}
+
+	return copy.(*ResourceState)
+}
+
+// prune is used to remove any instances that are no longer required
+func (s *ResourceState) prune() {
+	s.Lock()
+	defer s.Unlock()
+
+	n := len(s.Deposed)
+	for i := 0; i < n; i++ {
+		inst := s.Deposed[i]
+		if inst == nil || inst.ID == "" {
+			copy(s.Deposed[i:], s.Deposed[i+1:])
+			s.Deposed[n-1] = nil
+			n--
+			i--
+		}
+	}
+	s.Deposed = s.Deposed[:n]
+
+	s.Dependencies = uniqueStrings(s.Dependencies)
+}
+
+func (s *ResourceState) sort() {
+	s.Lock()
+	defer s.Unlock()
+
+	sort.Strings(s.Dependencies)
+}
+
+func (s *ResourceState) String() string {
+	s.Lock()
+	defer s.Unlock()
+
+	var buf bytes.Buffer
+	buf.WriteString(fmt.Sprintf("Type = %s", s.Type))
+	return buf.String()
+}
+
+// InstanceState is used to track the unique state information belonging
+// to a given instance.
+type InstanceState struct {
+	// A unique ID for this resource. This is opaque to Terraform
+	// and is only meant as a lookup mechanism for the providers.
+	ID string `json:"id"`
+
+	// Attributes are basic information about the resource. Any keys here
+	// are accessible in variable format within Terraform configurations:
+	// ${resourcetype.name.attribute}.
+	Attributes map[string]string `json:"attributes"`
+
+	// Ephemeral is used to store any state associated with this instance
+	// that is necessary for the Terraform run to complete, but is not
+	// persisted to a state file.
+	Ephemeral EphemeralState `json:"-"`
+
+	// Meta is a simple K/V map that is persisted to the State but otherwise
+	// ignored by Terraform core. It's meant to be used for accounting by
+	// external client code. The value here must only contain Go primitives
+	// and collections.
+	Meta map[string]interface{} `json:"meta"`
+
+	ProviderMeta cty.Value
+
+	// Tainted is used to mark a resource for recreation.
+	Tainted bool `json:"tainted"`
+
+	mu sync.Mutex
+}
+
+func (s *InstanceState) Lock()   { s.mu.Lock() }
+func (s *InstanceState) Unlock() { s.mu.Unlock() }
+
+func (s *InstanceState) init() {
+	s.Lock()
+	defer s.Unlock()
+
+	if s.Attributes == nil {
+		s.Attributes = make(map[string]string)
+	}
+	if s.Meta == nil {
+		s.Meta = make(map[string]interface{})
+	}
+	s.Ephemeral.init()
+}
+
+// NewInstanceStateShimmedFromValue is a shim method to lower a new-style
+// object value representing the attributes of an instance object into the
+// legacy InstanceState representation.
+//
+// This is for shimming to old components only and should not be used in new code.
+func NewInstanceStateShimmedFromValue(state cty.Value, schemaVersion int) *InstanceState {
+	attrs := hcl2shim.FlatmapValueFromHCL2(state)
+	return &InstanceState{
+		ID:         attrs["id"],
+		Attributes: attrs,
+		Meta: map[string]interface{}{
+			"schema_version": schemaVersion,
+		},
+	}
+}
+
+// AttrsAsObjectValue shims from the legacy InstanceState representation to
+// a new-style cty object value representation of the state attributes, using
+// the given type for guidance.
+//
+// The given type must be the implied type of the schema of the resource type
+// of the object whose state is being converted, or the result is undefined.
+//
+// This is for shimming from old components only and should not be used in
+// new code.
+func (s *InstanceState) AttrsAsObjectValue(ty cty.Type) (cty.Value, error) {
+	if s == nil {
+		// if the state is nil, we need to construct a complete cty.Value with
+		// null attributes, rather than a single cty.NullVal(ty)
+		s = &InstanceState{}
+	}
+
+	if s.Attributes == nil {
+		s.Attributes = map[string]string{}
+	}
+
+	// make sure ID is included in the attributes. The InstanceState.ID value
+	// takes precedence.
+	if s.ID != "" {
+		s.Attributes["id"] = s.ID
+	}
+
+	return hcl2shim.HCL2ValueFromFlatmap(s.Attributes, ty)
+}
+
+// Copy all the Fields from another InstanceState
+func (s *InstanceState) Set(from *InstanceState) {
+	s.Lock()
+	defer s.Unlock()
+
+	from.Lock()
+	defer from.Unlock()
+
+	s.ID = from.ID
+	s.Attributes = from.Attributes
+	s.Ephemeral = from.Ephemeral
+	s.Meta = from.Meta
+	s.Tainted = from.Tainted
+}
+
+func (s *InstanceState) DeepCopy() *InstanceState {
+	copy, err := copystructure.Config{Lock: true}.Copy(s)
+	if err != nil {
+		panic(err)
+	}
+
+	return copy.(*InstanceState)
+}
+
+func (s *InstanceState) Empty() bool {
+	if s == nil {
+		return true
+	}
+	s.Lock()
+	defer s.Unlock()
+
+	return s.ID == ""
+}
+
+func (s *InstanceState) Equal(other *InstanceState) bool {
+	// Short circuit some nil checks
+	if s == nil || other == nil {
+		return s == other
+	}
+	s.Lock()
+	defer s.Unlock()
+
+	// IDs must be equal
+	if s.ID != other.ID {
+		return false
+	}
+
+	// Attributes must be equal
+	if len(s.Attributes) != len(other.Attributes) {
+		return false
+	}
+	for k, v := range s.Attributes {
+		otherV, ok := other.Attributes[k]
+		if !ok {
+			return false
+		}
+
+		if v != otherV {
+			return false
+		}
+	}
+
+	// Meta must be equal
+	if len(s.Meta) != len(other.Meta) {
+		return false
+	}
+	if s.Meta != nil && other.Meta != nil {
+		// We only do the deep check if both are non-nil. If one is nil
+		// we treat it as equal since their lengths are both zero (check
+		// above).
+		//
+		// Since this can contain numeric values that may change types during
+		// serialization, let's compare the serialized values.
+		sMeta, err := json.Marshal(s.Meta)
+		if err != nil {
+			// marshaling primitives shouldn't ever error out
+			panic(err)
+		}
+		otherMeta, err := json.Marshal(other.Meta)
+		if err != nil {
+			panic(err)
+		}
+
+		if !bytes.Equal(sMeta, otherMeta) {
+			return false
+		}
+	}
+
+	if s.Tainted != other.Tainted {
+		return false
+	}
+
+	return true
+}
+
+// MergeDiff takes a ResourceDiff and merges the attributes into
+// this resource state in order to generate a new state. This new
+// state can be used to provide updated attribute lookups for
+// variable interpolation.
+//
+// If the diff attribute requires computing the value, and hence
+// won't be available until apply, the value is replaced with the
+// computeID.
+func (s *InstanceState) MergeDiff(d *InstanceDiff) *InstanceState {
+	result := s.DeepCopy()
+	if result == nil {
+		result = new(InstanceState)
+	}
+	result.init()
+
+	if s != nil {
+		s.Lock()
+		defer s.Unlock()
+		for k, v := range s.Attributes {
+			result.Attributes[k] = v
+		}
+	}
+	if d != nil {
+		for k, diff := range d.CopyAttributes() {
+			if diff.NewRemoved {
+				delete(result.Attributes, k)
+				continue
+			}
+			if diff.NewComputed {
+				result.Attributes[k] = hcl2shim.UnknownVariableValue
+				continue
+			}
+
+			result.Attributes[k] = diff.New
+		}
+	}
+
+	return result
+}
+
+func (s *InstanceState) String() string {
+	notCreated := "<not created>"
+
+	if s == nil {
+		return notCreated
+	}
+
+	s.Lock()
+	defer s.Unlock()
+
+	var buf bytes.Buffer
+
+	if s.ID == "" {
+		return notCreated
+	}
+
+	buf.WriteString(fmt.Sprintf("ID = %s\n", s.ID))
+
+	attributes := s.Attributes
+	attrKeys := make([]string, 0, len(attributes))
+	for ak, _ := range attributes {
+		if ak == "id" {
+			continue
+		}
+
+		attrKeys = append(attrKeys, ak)
+	}
+	sort.Strings(attrKeys)
+
+	for _, ak := range attrKeys {
+		av := attributes[ak]
+		buf.WriteString(fmt.Sprintf("%s = %s\n", ak, av))
+	}
+
+	buf.WriteString(fmt.Sprintf("Tainted = %t\n", s.Tainted))
+
+	return buf.String()
+}
+
+// EphemeralState is used for transient state that is only kept in-memory
+type EphemeralState struct {
+	// ConnInfo is used for the providers to export information which is
+	// used to connect to the resource for provisioning. For example,
+	// this could contain SSH or WinRM credentials.
+	ConnInfo map[string]string `json:"-"`
+
+	// Type is used to specify the resource type for this instance. This is only
+	// required for import operations (as documented). If the documentation
+	// doesn't state that you need to set this, then don't worry about
+	// setting it.
+	Type string `json:"-"`
+}
+
+func (e *EphemeralState) init() {
+	if e.ConnInfo == nil {
+		e.ConnInfo = make(map[string]string)
+	}
+}
+
+func (e *EphemeralState) DeepCopy() *EphemeralState {
+	copy, err := copystructure.Config{Lock: true}.Copy(e)
+	if err != nil {
+		panic(err)
+	}
+
+	return copy.(*EphemeralState)
+}
+
+type jsonStateVersionIdentifier struct {
+	Version int `json:"version"`
+}
+
+// Check if this is a V0 format - the magic bytes at the start of the file
+// should be "tfstate" if so. We no longer support upgrading this type of
+// state but return an error message explaining to a user how they can
+// upgrade via the 0.6.x series.
+func testForV0State(buf *bufio.Reader) error {
+	start, err := buf.Peek(len("tfstate"))
+	if err != nil {
+		return fmt.Errorf("Failed to check for magic bytes: %v", err)
+	}
+	if string(start) == "tfstate" {
+		return fmt.Errorf("Terraform 0.7 no longer supports upgrading the binary state\n" +
+			"format which was used prior to Terraform 0.3. Please upgrade\n" +
+			"this state file using Terraform 0.6.16 prior to using it with\n" +
+			"Terraform 0.7.")
+	}
+
+	return nil
+}
+
+// ErrNoState is returned by ReadState when the io.Reader contains no data
+var ErrNoState = errors.New("no state")
+
+// ReadState reads a state structure out of a reader in the format that
+// was written by WriteState.
+func ReadState(src io.Reader) (*State, error) {
+	// check for a nil file specifically, since that produces a platform
+	// specific error if we try to use it in a bufio.Reader.
+	if f, ok := src.(*os.File); ok && f == nil {
+		return nil, ErrNoState
+	}
+
+	buf := bufio.NewReader(src)
+
+	if _, err := buf.Peek(1); err != nil {
+		if err == io.EOF {
+			return nil, ErrNoState
+		}
+		return nil, err
+	}
+
+	if err := testForV0State(buf); err != nil {
+		return nil, err
+	}
+
+	// If we are JSON we buffer the whole thing in memory so we can read it twice.
+	// This is suboptimal, but will work for now.
+	jsonBytes, err := ioutil.ReadAll(buf)
+	if err != nil {
+		return nil, fmt.Errorf("Reading state file failed: %v", err)
+	}
+
+	versionIdentifier := &jsonStateVersionIdentifier{}
+	if err := json.Unmarshal(jsonBytes, versionIdentifier); err != nil {
+		return nil, fmt.Errorf("Decoding state file version failed: %v", err)
+	}
+
+	var result *State
+	switch versionIdentifier.Version {
+	case 0:
+		return nil, fmt.Errorf("State version 0 is not supported as JSON.")
+	case 1:
+		v1State, err := ReadStateV1(jsonBytes)
+		if err != nil {
+			return nil, err
+		}
+
+		v2State, err := upgradeStateV1ToV2(v1State)
+		if err != nil {
+			return nil, err
+		}
+
+		v3State, err := upgradeStateV2ToV3(v2State)
+		if err != nil {
+			return nil, err
+		}
+
+		// increment the Serial whenever we upgrade state
+		v3State.Serial++
+		result = v3State
+	case 2:
+		v2State, err := ReadStateV2(jsonBytes)
+		if err != nil {
+			return nil, err
+		}
+		v3State, err := upgradeStateV2ToV3(v2State)
+		if err != nil {
+			return nil, err
+		}
+
+		v3State.Serial++
+		result = v3State
+	case 3:
+		v3State, err := ReadStateV3(jsonBytes)
+		if err != nil {
+			return nil, err
+		}
+
+		result = v3State
+	default:
+		return nil, fmt.Errorf("Terraform %s does not support state version %d, please update.",
+			tfversion.SemVer.String(), versionIdentifier.Version)
+	}
+
+	// If we reached this place we must have a result set
+	if result == nil {
+		panic("resulting state in load not set, assertion failed")
+	}
+
+	// Prune the state when read it. Its possible to write unpruned states or
+	// for a user to make a state unpruned (nil-ing a module state for example).
+	result.prune()
+
+	// Validate the state file is valid
+	if err := result.Validate(); err != nil {
+		return nil, err
+	}
+
+	return result, nil
+}
+
+func ReadStateV1(jsonBytes []byte) (*stateV1, error) {
+	v1State := &stateV1{}
+	if err := json.Unmarshal(jsonBytes, v1State); err != nil {
+		return nil, fmt.Errorf("Decoding state file failed: %v", err)
+	}
+
+	if v1State.Version != 1 {
+		return nil, fmt.Errorf("Decoded state version did not match the decoder selection: "+
+			"read %d, expected 1", v1State.Version)
+	}
+
+	return v1State, nil
+}
+
+func ReadStateV2(jsonBytes []byte) (*State, error) {
+	state := &State{}
+	if err := json.Unmarshal(jsonBytes, state); err != nil {
+		return nil, fmt.Errorf("Decoding state file failed: %v", err)
+	}
+
+	// Check the version, this to ensure we don't read a future
+	// version that we don't understand
+	if state.Version > StateVersion {
+		return nil, fmt.Errorf("Terraform %s does not support state version %d, please update.",
+			tfversion.SemVer.String(), state.Version)
+	}
+
+	// Make sure the version is semantic
+	if state.TFVersion != "" {
+		if _, err := version.NewVersion(state.TFVersion); err != nil {
+			return nil, fmt.Errorf(
+				"State contains invalid version: %s\n\n"+
+					"Terraform validates the version format prior to writing it. This\n"+
+					"means that this is invalid of the state becoming corrupted through\n"+
+					"some external means. Please manually modify the Terraform version\n"+
+					"field to be a proper semantic version.",
+				state.TFVersion)
+		}
+	}
+
+	// catch any unitialized fields in the state
+	state.init()
+
+	// Sort it
+	state.sort()
+
+	return state, nil
+}
+
+func ReadStateV3(jsonBytes []byte) (*State, error) {
+	state := &State{}
+	if err := json.Unmarshal(jsonBytes, state); err != nil {
+		return nil, fmt.Errorf("Decoding state file failed: %v", err)
+	}
+
+	// Check the version, this to ensure we don't read a future
+	// version that we don't understand
+	if state.Version > StateVersion {
+		return nil, fmt.Errorf("Terraform %s does not support state version %d, please update.",
+			tfversion.SemVer.String(), state.Version)
+	}
+
+	// Make sure the version is semantic
+	if state.TFVersion != "" {
+		if _, err := version.NewVersion(state.TFVersion); err != nil {
+			return nil, fmt.Errorf(
+				"State contains invalid version: %s\n\n"+
+					"Terraform validates the version format prior to writing it. This\n"+
+					"means that this is invalid of the state becoming corrupted through\n"+
+					"some external means. Please manually modify the Terraform version\n"+
+					"field to be a proper semantic version.",
+				state.TFVersion)
+		}
+	}
+
+	// catch any unitialized fields in the state
+	state.init()
+
+	// Sort it
+	state.sort()
+
+	// Now we write the state back out to detect any changes in normaliztion.
+	// If our state is now written out differently, bump the serial number to
+	// prevent conflicts.
+	var buf bytes.Buffer
+	err := WriteState(state, &buf)
+	if err != nil {
+		return nil, err
+	}
+
+	if !bytes.Equal(jsonBytes, buf.Bytes()) {
+		log.Println("[INFO] state modified during read or write. incrementing serial number")
+		state.Serial++
+	}
+
+	return state, nil
+}
+
+// WriteState writes a state somewhere in a binary format.
+func WriteState(d *State, dst io.Writer) error {
+	// writing a nil state is a noop.
+	if d == nil {
+		return nil
+	}
+
+	// make sure we have no uninitialized fields
+	d.init()
+
+	// Make sure it is sorted
+	d.sort()
+
+	// Ensure the version is set
+	d.Version = StateVersion
+
+	// If the TFVersion is set, verify it. We used to just set the version
+	// here, but this isn't safe since it changes the MD5 sum on some remote
+	// state storage backends such as Atlas. We now leave it be if needed.
+	if d.TFVersion != "" {
+		if _, err := version.NewVersion(d.TFVersion); err != nil {
+			return fmt.Errorf(
+				"Error writing state, invalid version: %s\n\n"+
+					"The Terraform version when writing the state must be a semantic\n"+
+					"version.",
+				d.TFVersion)
+		}
+	}
+
+	// Encode the data in a human-friendly way
+	data, err := json.MarshalIndent(d, "", "    ")
+	if err != nil {
+		return fmt.Errorf("Failed to encode state: %s", err)
+	}
+
+	// We append a newline to the data because MarshalIndent doesn't
+	data = append(data, '\n')
+
+	// Write the data out to the dst
+	if _, err := io.Copy(dst, bytes.NewReader(data)); err != nil {
+		return fmt.Errorf("Failed to write state: %v", err)
+	}
+
+	return nil
+}
+
+// resourceNameSort implements the sort.Interface to sort name parts lexically for
+// strings and numerically for integer indexes.
+type resourceNameSort []string
+
+func (r resourceNameSort) Len() int      { return len(r) }
+func (r resourceNameSort) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
+
+func (r resourceNameSort) Less(i, j int) bool {
+	iParts := strings.Split(r[i], ".")
+	jParts := strings.Split(r[j], ".")
+
+	end := len(iParts)
+	if len(jParts) < end {
+		end = len(jParts)
+	}
+
+	for idx := 0; idx < end; idx++ {
+		if iParts[idx] == jParts[idx] {
+			continue
+		}
+
+		// sort on the first non-matching part
+		iInt, iIntErr := strconv.Atoi(iParts[idx])
+		jInt, jIntErr := strconv.Atoi(jParts[idx])
+
+		switch {
+		case iIntErr == nil && jIntErr == nil:
+			// sort numerically if both parts are integers
+			return iInt < jInt
+		case iIntErr == nil:
+			// numbers sort before strings
+			return true
+		case jIntErr == nil:
+			return false
+		default:
+			return iParts[idx] < jParts[idx]
+		}
+	}
+
+	return r[i] < r[j]
+}
+
+// moduleStateSort implements sort.Interface to sort module states
+type moduleStateSort []*ModuleState
+
+func (s moduleStateSort) Len() int {
+	return len(s)
+}
+
+func (s moduleStateSort) Less(i, j int) bool {
+	a := s[i]
+	b := s[j]
+
+	// If either is nil, then the nil one is "less" than
+	if a == nil || b == nil {
+		return a == nil
+	}
+
+	// If the lengths are different, then the shorter one always wins
+	if len(a.Path) != len(b.Path) {
+		return len(a.Path) < len(b.Path)
+	}
+
+	// Otherwise, compare lexically
+	return strings.Join(a.Path, ".") < strings.Join(b.Path, ".")
+}
+
+func (s moduleStateSort) Swap(i, j int) {
+	s[i], s[j] = s[j], s[i]
+}
+
+const stateValidateErrMultiModule = `
+Multiple modules with the same path: %s
+
+This means that there are multiple entries in the "modules" field
+in your state file that point to the same module. This will cause Terraform
+to behave in unexpected and error prone ways and is invalid. Please back up
+and modify your state file manually to resolve this.
+`
diff --git a/v1.5.7/internal/legacy/terraform/state_filter.go b/v1.5.7/internal/legacy/terraform/state_filter.go
new file mode 100644
index 0000000..b605bf0
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/state_filter.go
@@ -0,0 +1,270 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"sort"
+)
+
+// StateFilter is responsible for filtering and searching a state.
+//
+// This is a separate struct from State rather than a method on State
+// because StateFilter might create sidecar data structures to optimize
+// filtering on the state.
+//
+// If you change the State, the filter created is invalid and either
+// Reset should be called or a new one should be allocated. StateFilter
+// will not watch State for changes and do this for you. If you filter after
+// changing the State without calling Reset, the behavior is not defined.
+type StateFilter struct {
+	State *State
+}
+
+// Filter takes the addresses specified by fs and finds all the matches.
+// The values of fs are resource addressing syntax that can be parsed by
+// ParseResourceAddress.
+func (f *StateFilter) Filter(fs ...string) ([]*StateFilterResult, error) {
+	// Parse all the addresses
+	as := make([]*ResourceAddress, len(fs))
+	for i, v := range fs {
+		a, err := ParseResourceAddress(v)
+		if err != nil {
+			return nil, fmt.Errorf("Error parsing address '%s': %s", v, err)
+		}
+
+		as[i] = a
+	}
+
+	// If we weren't given any filters, then we list all
+	if len(fs) == 0 {
+		as = append(as, &ResourceAddress{Index: -1})
+	}
+
+	// Filter each of the address. We keep track of this in a map to
+	// strip duplicates.
+	resultSet := make(map[string]*StateFilterResult)
+	for _, a := range as {
+		for _, r := range f.filterSingle(a) {
+			resultSet[r.String()] = r
+		}
+	}
+
+	// Make the result list
+	results := make([]*StateFilterResult, 0, len(resultSet))
+	for _, v := range resultSet {
+		results = append(results, v)
+	}
+
+	// Sort them and return
+	sort.Sort(StateFilterResultSlice(results))
+	return results, nil
+}
+
+func (f *StateFilter) filterSingle(a *ResourceAddress) []*StateFilterResult {
+	// The slice to keep track of results
+	var results []*StateFilterResult
+
+	// Go through modules first.
+	modules := make([]*ModuleState, 0, len(f.State.Modules))
+	for _, m := range f.State.Modules {
+		if f.relevant(a, m) {
+			modules = append(modules, m)
+
+			// Only add the module to the results if we haven't specified a type.
+			// We also ignore the root module.
+			if a.Type == "" && len(m.Path) > 1 {
+				results = append(results, &StateFilterResult{
+					Path:    m.Path[1:],
+					Address: (&ResourceAddress{Path: m.Path[1:]}).String(),
+					Value:   m,
+				})
+			}
+		}
+	}
+
+	// With the modules set, go through all the resources within
+	// the modules to find relevant resources.
+	for _, m := range modules {
+		for n, r := range m.Resources {
+			// The name in the state contains valuable information. Parse.
+			key, err := ParseResourceStateKey(n)
+			if err != nil {
+				// If we get an error parsing, then just ignore it
+				// out of the state.
+				continue
+			}
+
+			// Older states and test fixtures often don't contain the
+			// type directly on the ResourceState. We add this so StateFilter
+			// is a bit more robust.
+			if r.Type == "" {
+				r.Type = key.Type
+			}
+
+			if f.relevant(a, r) {
+				if a.Name != "" && a.Name != key.Name {
+					// Name doesn't match
+					continue
+				}
+
+				if a.Index >= 0 && key.Index != a.Index {
+					// Index doesn't match
+					continue
+				}
+
+				if a.Name != "" && a.Name != key.Name {
+					continue
+				}
+
+				// Build the address for this resource
+				addr := &ResourceAddress{
+					Path:  m.Path[1:],
+					Name:  key.Name,
+					Type:  key.Type,
+					Index: key.Index,
+				}
+
+				// Add the resource level result
+				resourceResult := &StateFilterResult{
+					Path:    addr.Path,
+					Address: addr.String(),
+					Value:   r,
+				}
+				if !a.InstanceTypeSet {
+					results = append(results, resourceResult)
+				}
+
+				// Add the instances
+				if r.Primary != nil {
+					addr.InstanceType = TypePrimary
+					addr.InstanceTypeSet = false
+					results = append(results, &StateFilterResult{
+						Path:    addr.Path,
+						Address: addr.String(),
+						Parent:  resourceResult,
+						Value:   r.Primary,
+					})
+				}
+
+				for _, instance := range r.Deposed {
+					if f.relevant(a, instance) {
+						addr.InstanceType = TypeDeposed
+						addr.InstanceTypeSet = true
+						results = append(results, &StateFilterResult{
+							Path:    addr.Path,
+							Address: addr.String(),
+							Parent:  resourceResult,
+							Value:   instance,
+						})
+					}
+				}
+			}
+		}
+	}
+
+	return results
+}
+
+// relevant checks for relevance of this address against the given value.
+func (f *StateFilter) relevant(addr *ResourceAddress, raw interface{}) bool {
+	switch v := raw.(type) {
+	case *ModuleState:
+		path := v.Path[1:]
+
+		if len(addr.Path) > len(path) {
+			// Longer path in address means there is no way we match.
+			return false
+		}
+
+		// Check for a prefix match
+		for i, p := range addr.Path {
+			if path[i] != p {
+				// Any mismatches don't match.
+				return false
+			}
+		}
+
+		return true
+	case *ResourceState:
+		if addr.Type == "" {
+			// If we have no resource type, then we're interested in all!
+			return true
+		}
+
+		// If the type doesn't match we fail immediately
+		if v.Type != addr.Type {
+			return false
+		}
+
+		return true
+	default:
+		// If we don't know about it, let's just say no
+		return false
+	}
+}
+
+// StateFilterResult is a single result from a filter operation. Filter
+// can match multiple things within a state (module, resource, instance, etc.)
+// and this unifies that.
+type StateFilterResult struct {
+	// Module path of the result
+	Path []string
+
+	// Address is the address that can be used to reference this exact result.
+	Address string
+
+	// Parent, if non-nil, is a parent of this result. For instances, the
+	// parent would be a resource. For resources, the parent would be
+	// a module. For modules, this is currently nil.
+	Parent *StateFilterResult
+
+	// Value is the actual value. This must be type switched on. It can be
+	// any data structures that `State` can hold: `ModuleState`,
+	// `ResourceState`, `InstanceState`.
+	Value interface{}
+}
+
+func (r *StateFilterResult) String() string {
+	return fmt.Sprintf("%T: %s", r.Value, r.Address)
+}
+
+func (r *StateFilterResult) sortedType() int {
+	switch r.Value.(type) {
+	case *ModuleState:
+		return 0
+	case *ResourceState:
+		return 1
+	case *InstanceState:
+		return 2
+	default:
+		return 50
+	}
+}
+
+// StateFilterResultSlice is a slice of results that implements
+// sort.Interface. The sorting goal is what is most appealing to
+// human output.
+type StateFilterResultSlice []*StateFilterResult
+
+func (s StateFilterResultSlice) Len() int      { return len(s) }
+func (s StateFilterResultSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s StateFilterResultSlice) Less(i, j int) bool {
+	a, b := s[i], s[j]
+
+	// if these address contain an index, we want to sort by index rather than name
+	addrA, errA := ParseResourceAddress(a.Address)
+	addrB, errB := ParseResourceAddress(b.Address)
+	if errA == nil && errB == nil && addrA.Name == addrB.Name && addrA.Index != addrB.Index {
+		return addrA.Index < addrB.Index
+	}
+
+	// If the addresses are different it is just lexographic sorting
+	if a.Address != b.Address {
+		return a.Address < b.Address
+	}
+
+	// Addresses are the same, which means it matters on the type
+	return a.sortedType() < b.sortedType()
+}
diff --git a/v1.5.7/internal/legacy/terraform/state_test.go b/v1.5.7/internal/legacy/terraform/state_test.go
new file mode 100644
index 0000000..c5a0e17
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/state_test.go
@@ -0,0 +1,1897 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"os"
+	"reflect"
+	"sort"
+	"strings"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+)
+
+func TestStateValidate(t *testing.T) {
+	cases := map[string]struct {
+		In  *State
+		Err bool
+	}{
+		"empty state": {
+			&State{},
+			false,
+		},
+
+		"multiple modules": {
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: []string{"root", "foo"},
+					},
+					&ModuleState{
+						Path: []string{"root", "foo"},
+					},
+				},
+			},
+			true,
+		},
+	}
+
+	for name, tc := range cases {
+		// Init the state
+		tc.In.init()
+
+		err := tc.In.Validate()
+		if (err != nil) != tc.Err {
+			t.Fatalf("%s: err: %s", name, err)
+		}
+	}
+}
+
+func TestStateAddModule(t *testing.T) {
+	cases := []struct {
+		In  []addrs.ModuleInstance
+		Out [][]string
+	}{
+		{
+			[]addrs.ModuleInstance{
+				addrs.RootModuleInstance,
+				addrs.RootModuleInstance.Child("child", addrs.NoKey),
+			},
+			[][]string{
+				[]string{"root"},
+				[]string{"root", "child"},
+			},
+		},
+
+		{
+			[]addrs.ModuleInstance{
+				addrs.RootModuleInstance.Child("foo", addrs.NoKey).Child("bar", addrs.NoKey),
+				addrs.RootModuleInstance.Child("foo", addrs.NoKey),
+				addrs.RootModuleInstance,
+				addrs.RootModuleInstance.Child("bar", addrs.NoKey),
+			},
+			[][]string{
+				[]string{"root"},
+				[]string{"root", "bar"},
+				[]string{"root", "foo"},
+				[]string{"root", "foo", "bar"},
+			},
+		},
+		// Same last element, different middle element
+		{
+			[]addrs.ModuleInstance{
+				addrs.RootModuleInstance.Child("foo", addrs.NoKey).Child("bar", addrs.NoKey), // This one should sort after...
+				addrs.RootModuleInstance.Child("foo", addrs.NoKey),
+				addrs.RootModuleInstance,
+				addrs.RootModuleInstance.Child("bar", addrs.NoKey).Child("bar", addrs.NoKey), // ...this one.
+				addrs.RootModuleInstance.Child("bar", addrs.NoKey),
+			},
+			[][]string{
+				[]string{"root"},
+				[]string{"root", "bar"},
+				[]string{"root", "foo"},
+				[]string{"root", "bar", "bar"},
+				[]string{"root", "foo", "bar"},
+			},
+		},
+	}
+
+	for _, tc := range cases {
+		s := new(State)
+		for _, p := range tc.In {
+			s.AddModule(p)
+		}
+
+		actual := make([][]string, 0, len(tc.In))
+		for _, m := range s.Modules {
+			actual = append(actual, m.Path)
+		}
+
+		if !reflect.DeepEqual(actual, tc.Out) {
+			t.Fatalf("wrong result\ninput: %sgot:   %#v\nwant:  %#v", spew.Sdump(tc.In), actual, tc.Out)
+		}
+	}
+}
+
+func TestStateOutputTypeRoundTrip(t *testing.T) {
+	state := &State{
+		Modules: []*ModuleState{
+			&ModuleState{
+				Path: []string{"root"},
+				Outputs: map[string]*OutputState{
+					"string_output": &OutputState{
+						Value: "String Value",
+						Type:  "string",
+					},
+				},
+			},
+		},
+	}
+	state.init()
+
+	buf := new(bytes.Buffer)
+	if err := WriteState(state, buf); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	roundTripped, err := ReadState(buf)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !reflect.DeepEqual(state, roundTripped) {
+		t.Logf("expected:\n%#v", state)
+		t.Fatalf("got:\n%#v", roundTripped)
+	}
+}
+
+func TestStateDeepCopy(t *testing.T) {
+	cases := []struct {
+		State *State
+	}{
+		// Nil
+		{nil},
+
+		// Version
+		{
+			&State{Version: 5},
+		},
+		// TFVersion
+		{
+			&State{TFVersion: "5"},
+		},
+		// Modules
+		{
+			&State{
+				Version: 6,
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Primary: &InstanceState{
+									Meta: map[string]interface{}{},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		// Deposed
+		// The nil values shouldn't be there if the State was properly init'ed,
+		// but the Copy should still work anyway.
+		{
+			&State{
+				Version: 6,
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Primary: &InstanceState{
+									Meta: map[string]interface{}{},
+								},
+								Deposed: []*InstanceState{
+									{ID: "test"},
+									nil,
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("copy-%d", i), func(t *testing.T) {
+			actual := tc.State.DeepCopy()
+			expected := tc.State
+			if !reflect.DeepEqual(actual, expected) {
+				t.Fatalf("Expected: %#v\nRecevied: %#v\n", expected, actual)
+			}
+		})
+	}
+}
+
+func TestStateEqual(t *testing.T) {
+	cases := []struct {
+		Name     string
+		Result   bool
+		One, Two *State
+	}{
+		// Nils
+		{
+			"one nil",
+			false,
+			nil,
+			&State{Version: 2},
+		},
+
+		{
+			"both nil",
+			true,
+			nil,
+			nil,
+		},
+
+		// Different versions
+		{
+			"different state versions",
+			false,
+			&State{Version: 5},
+			&State{Version: 2},
+		},
+
+		// Different modules
+		{
+			"different module states",
+			false,
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: []string{"root"},
+					},
+				},
+			},
+			&State{},
+		},
+
+		{
+			"same module states",
+			true,
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: []string{"root"},
+					},
+				},
+			},
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: []string{"root"},
+					},
+				},
+			},
+		},
+
+		// Meta differs
+		{
+			"differing meta values with primitives",
+			false,
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Primary: &InstanceState{
+									Meta: map[string]interface{}{
+										"schema_version": "1",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Primary: &InstanceState{
+									Meta: map[string]interface{}{
+										"schema_version": "2",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+
+		// Meta with complex types
+		{
+			"same meta with complex types",
+			true,
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Primary: &InstanceState{
+									Meta: map[string]interface{}{
+										"timeouts": map[string]interface{}{
+											"create": 42,
+											"read":   "27",
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Primary: &InstanceState{
+									Meta: map[string]interface{}{
+										"timeouts": map[string]interface{}{
+											"create": 42,
+											"read":   "27",
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+
+		// Meta with complex types that have been altered during serialization
+		{
+			"same meta with complex types that have been json-ified",
+			true,
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Primary: &InstanceState{
+									Meta: map[string]interface{}{
+										"timeouts": map[string]interface{}{
+											"create": int(42),
+											"read":   "27",
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Primary: &InstanceState{
+									Meta: map[string]interface{}{
+										"timeouts": map[string]interface{}{
+											"create": float64(42),
+											"read":   "27",
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			if tc.One.Equal(tc.Two) != tc.Result {
+				t.Fatalf("Bad: %d\n\n%s\n\n%s", i, tc.One.String(), tc.Two.String())
+			}
+			if tc.Two.Equal(tc.One) != tc.Result {
+				t.Fatalf("Bad: %d\n\n%s\n\n%s", i, tc.One.String(), tc.Two.String())
+			}
+		})
+	}
+}
+
+func TestStateCompareAges(t *testing.T) {
+	cases := []struct {
+		Result   StateAgeComparison
+		Err      bool
+		One, Two *State
+	}{
+		{
+			StateAgeEqual, false,
+			&State{
+				Lineage: "1",
+				Serial:  2,
+			},
+			&State{
+				Lineage: "1",
+				Serial:  2,
+			},
+		},
+		{
+			StateAgeReceiverOlder, false,
+			&State{
+				Lineage: "1",
+				Serial:  2,
+			},
+			&State{
+				Lineage: "1",
+				Serial:  3,
+			},
+		},
+		{
+			StateAgeReceiverNewer, false,
+			&State{
+				Lineage: "1",
+				Serial:  3,
+			},
+			&State{
+				Lineage: "1",
+				Serial:  2,
+			},
+		},
+		{
+			StateAgeEqual, true,
+			&State{
+				Lineage: "1",
+				Serial:  2,
+			},
+			&State{
+				Lineage: "2",
+				Serial:  2,
+			},
+		},
+		{
+			StateAgeEqual, true,
+			&State{
+				Lineage: "1",
+				Serial:  3,
+			},
+			&State{
+				Lineage: "2",
+				Serial:  2,
+			},
+		},
+	}
+
+	for i, tc := range cases {
+		result, err := tc.One.CompareAges(tc.Two)
+
+		if err != nil && !tc.Err {
+			t.Errorf(
+				"%d: got error, but want success\n\n%s\n\n%s",
+				i, tc.One, tc.Two,
+			)
+			continue
+		}
+
+		if err == nil && tc.Err {
+			t.Errorf(
+				"%d: got success, but want error\n\n%s\n\n%s",
+				i, tc.One, tc.Two,
+			)
+			continue
+		}
+
+		if result != tc.Result {
+			t.Errorf(
+				"%d: got result %d, but want %d\n\n%s\n\n%s",
+				i, result, tc.Result, tc.One, tc.Two,
+			)
+			continue
+		}
+	}
+}
+
+func TestStateSameLineage(t *testing.T) {
+	cases := []struct {
+		Result   bool
+		One, Two *State
+	}{
+		{
+			true,
+			&State{
+				Lineage: "1",
+			},
+			&State{
+				Lineage: "1",
+			},
+		},
+		{
+			// Empty lineage is compatible with all
+			true,
+			&State{
+				Lineage: "",
+			},
+			&State{
+				Lineage: "1",
+			},
+		},
+		{
+			// Empty lineage is compatible with all
+			true,
+			&State{
+				Lineage: "1",
+			},
+			&State{
+				Lineage: "",
+			},
+		},
+		{
+			false,
+			&State{
+				Lineage: "1",
+			},
+			&State{
+				Lineage: "2",
+			},
+		},
+	}
+
+	for i, tc := range cases {
+		result := tc.One.SameLineage(tc.Two)
+
+		if result != tc.Result {
+			t.Errorf(
+				"%d: got %v, but want %v\n\n%s\n\n%s",
+				i, result, tc.Result, tc.One, tc.Two,
+			)
+			continue
+		}
+	}
+}
+
+func TestStateMarshalEqual(t *testing.T) {
+	tests := map[string]struct {
+		S1, S2 *State
+		Want   bool
+	}{
+		"both nil": {
+			nil,
+			nil,
+			true,
+		},
+		"first zero, second nil": {
+			&State{},
+			nil,
+			false,
+		},
+		"first nil, second zero": {
+			nil,
+			&State{},
+			false,
+		},
+		"both zero": {
+			// These are not equal because they both implicitly init with
+			// different lineage.
+			&State{},
+			&State{},
+			false,
+		},
+		"both set, same lineage": {
+			&State{
+				Lineage: "abc123",
+			},
+			&State{
+				Lineage: "abc123",
+			},
+			true,
+		},
+		"both set, same lineage, different serial": {
+			&State{
+				Lineage: "abc123",
+				Serial:  1,
+			},
+			&State{
+				Lineage: "abc123",
+				Serial:  2,
+			},
+			false,
+		},
+		"both set, same lineage, same serial, same resources": {
+			&State{
+				Lineage: "abc123",
+				Serial:  1,
+				Modules: []*ModuleState{
+					{
+						Path: []string{"root"},
+						Resources: map[string]*ResourceState{
+							"foo_bar.baz": {},
+						},
+					},
+				},
+			},
+			&State{
+				Lineage: "abc123",
+				Serial:  1,
+				Modules: []*ModuleState{
+					{
+						Path: []string{"root"},
+						Resources: map[string]*ResourceState{
+							"foo_bar.baz": {},
+						},
+					},
+				},
+			},
+			true,
+		},
+		"both set, same lineage, same serial, different resources": {
+			&State{
+				Lineage: "abc123",
+				Serial:  1,
+				Modules: []*ModuleState{
+					{
+						Path: []string{"root"},
+						Resources: map[string]*ResourceState{
+							"foo_bar.baz": {},
+						},
+					},
+				},
+			},
+			&State{
+				Lineage: "abc123",
+				Serial:  1,
+				Modules: []*ModuleState{
+					{
+						Path: []string{"root"},
+						Resources: map[string]*ResourceState{
+							"pizza_crust.tasty": {},
+						},
+					},
+				},
+			},
+			false,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got := test.S1.MarshalEqual(test.S2)
+			if got != test.Want {
+				t.Errorf("wrong result %#v; want %#v", got, test.Want)
+				s1Buf := &bytes.Buffer{}
+				s2Buf := &bytes.Buffer{}
+				_ = WriteState(test.S1, s1Buf)
+				_ = WriteState(test.S2, s2Buf)
+				t.Logf("\nState 1: %s\nState 2: %s", s1Buf.Bytes(), s2Buf.Bytes())
+			}
+		})
+	}
+}
+
+func TestStateRemove(t *testing.T) {
+	cases := map[string]struct {
+		Address  string
+		One, Two *State
+	}{
+		"simple resource": {
+			"test_instance.foo",
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+
+							"test_instance.bar": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+						},
+					},
+				},
+			},
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.bar": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+
+		"single instance": {
+			"test_instance.foo.primary",
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+						},
+					},
+				},
+			},
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path:      rootModulePath,
+						Resources: map[string]*ResourceState{},
+					},
+				},
+			},
+		},
+
+		"single instance in multi-count": {
+			"test_instance.foo[0]",
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo.0": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+
+							"test_instance.foo.1": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+						},
+					},
+				},
+			},
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo.1": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+
+		"single resource, multi-count": {
+			"test_instance.foo",
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo.0": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+
+							"test_instance.foo.1": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+						},
+					},
+				},
+			},
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path:      rootModulePath,
+						Resources: map[string]*ResourceState{},
+					},
+				},
+			},
+		},
+
+		"full module": {
+			"module.foo",
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+						},
+					},
+
+					&ModuleState{
+						Path: []string{"root", "foo"},
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+
+							"test_instance.bar": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+						},
+					},
+				},
+			},
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+
+		"module and children": {
+			"module.foo",
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+						},
+					},
+
+					&ModuleState{
+						Path: []string{"root", "foo"},
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+
+							"test_instance.bar": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+						},
+					},
+
+					&ModuleState{
+						Path: []string{"root", "foo", "bar"},
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+
+							"test_instance.bar": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+						},
+					},
+				},
+			},
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{
+						Path: rootModulePath,
+						Resources: map[string]*ResourceState{
+							"test_instance.foo": &ResourceState{
+								Type: "test_instance",
+								Primary: &InstanceState{
+									ID: "foo",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for k, tc := range cases {
+		if err := tc.One.Remove(tc.Address); err != nil {
+			t.Fatalf("bad: %s\n\n%s", k, err)
+		}
+
+		if !tc.One.Equal(tc.Two) {
+			t.Fatalf("Bad: %s\n\n%s\n\n%s", k, tc.One.String(), tc.Two.String())
+		}
+	}
+}
+
+func TestResourceStateEqual(t *testing.T) {
+	cases := []struct {
+		Result   bool
+		One, Two *ResourceState
+	}{
+		// Different types
+		{
+			false,
+			&ResourceState{Type: "foo"},
+			&ResourceState{Type: "bar"},
+		},
+
+		// Different dependencies
+		{
+			false,
+			&ResourceState{Dependencies: []string{"foo"}},
+			&ResourceState{Dependencies: []string{"bar"}},
+		},
+
+		{
+			false,
+			&ResourceState{Dependencies: []string{"foo", "bar"}},
+			&ResourceState{Dependencies: []string{"foo"}},
+		},
+
+		{
+			true,
+			&ResourceState{Dependencies: []string{"bar", "foo"}},
+			&ResourceState{Dependencies: []string{"foo", "bar"}},
+		},
+
+		// Different primaries
+		{
+			false,
+			&ResourceState{Primary: nil},
+			&ResourceState{Primary: &InstanceState{ID: "foo"}},
+		},
+
+		{
+			true,
+			&ResourceState{Primary: &InstanceState{ID: "foo"}},
+			&ResourceState{Primary: &InstanceState{ID: "foo"}},
+		},
+
+		// Different tainted
+		{
+			false,
+			&ResourceState{
+				Primary: &InstanceState{
+					ID: "foo",
+				},
+			},
+			&ResourceState{
+				Primary: &InstanceState{
+					ID:      "foo",
+					Tainted: true,
+				},
+			},
+		},
+
+		{
+			true,
+			&ResourceState{
+				Primary: &InstanceState{
+					ID:      "foo",
+					Tainted: true,
+				},
+			},
+			&ResourceState{
+				Primary: &InstanceState{
+					ID:      "foo",
+					Tainted: true,
+				},
+			},
+		},
+	}
+
+	for i, tc := range cases {
+		if tc.One.Equal(tc.Two) != tc.Result {
+			t.Fatalf("Bad: %d\n\n%s\n\n%s", i, tc.One.String(), tc.Two.String())
+		}
+		if tc.Two.Equal(tc.One) != tc.Result {
+			t.Fatalf("Bad: %d\n\n%s\n\n%s", i, tc.One.String(), tc.Two.String())
+		}
+	}
+}
+
+func TestResourceStateTaint(t *testing.T) {
+	cases := map[string]struct {
+		Input  *ResourceState
+		Output *ResourceState
+	}{
+		"no primary": {
+			&ResourceState{},
+			&ResourceState{},
+		},
+
+		"primary, not tainted": {
+			&ResourceState{
+				Primary: &InstanceState{ID: "foo"},
+			},
+			&ResourceState{
+				Primary: &InstanceState{
+					ID:      "foo",
+					Tainted: true,
+				},
+			},
+		},
+
+		"primary, tainted": {
+			&ResourceState{
+				Primary: &InstanceState{
+					ID:      "foo",
+					Tainted: true,
+				},
+			},
+			&ResourceState{
+				Primary: &InstanceState{
+					ID:      "foo",
+					Tainted: true,
+				},
+			},
+		},
+	}
+
+	for k, tc := range cases {
+		tc.Input.Taint()
+		if !reflect.DeepEqual(tc.Input, tc.Output) {
+			t.Fatalf(
+				"Failure: %s\n\nExpected: %#v\n\nGot: %#v",
+				k, tc.Output, tc.Input)
+		}
+	}
+}
+
+func TestResourceStateUntaint(t *testing.T) {
+	cases := map[string]struct {
+		Input          *ResourceState
+		ExpectedOutput *ResourceState
+	}{
+		"no primary, err": {
+			Input:          &ResourceState{},
+			ExpectedOutput: &ResourceState{},
+		},
+
+		"primary, not tainted": {
+			Input: &ResourceState{
+				Primary: &InstanceState{ID: "foo"},
+			},
+			ExpectedOutput: &ResourceState{
+				Primary: &InstanceState{ID: "foo"},
+			},
+		},
+		"primary, tainted": {
+			Input: &ResourceState{
+				Primary: &InstanceState{
+					ID:      "foo",
+					Tainted: true,
+				},
+			},
+			ExpectedOutput: &ResourceState{
+				Primary: &InstanceState{ID: "foo"},
+			},
+		},
+	}
+
+	for k, tc := range cases {
+		tc.Input.Untaint()
+		if !reflect.DeepEqual(tc.Input, tc.ExpectedOutput) {
+			t.Fatalf(
+				"Failure: %s\n\nExpected: %#v\n\nGot: %#v",
+				k, tc.ExpectedOutput, tc.Input)
+		}
+	}
+}
+
+func TestInstanceStateEmpty(t *testing.T) {
+	cases := map[string]struct {
+		In     *InstanceState
+		Result bool
+	}{
+		"nil is empty": {
+			nil,
+			true,
+		},
+		"non-nil but without ID is empty": {
+			&InstanceState{},
+			true,
+		},
+		"with ID is not empty": {
+			&InstanceState{
+				ID: "i-abc123",
+			},
+			false,
+		},
+	}
+
+	for tn, tc := range cases {
+		if tc.In.Empty() != tc.Result {
+			t.Fatalf("%q expected %#v to be empty: %#v", tn, tc.In, tc.Result)
+		}
+	}
+}
+
+func TestInstanceStateEqual(t *testing.T) {
+	cases := []struct {
+		Result   bool
+		One, Two *InstanceState
+	}{
+		// Nils
+		{
+			false,
+			nil,
+			&InstanceState{},
+		},
+
+		{
+			false,
+			&InstanceState{},
+			nil,
+		},
+
+		// Different IDs
+		{
+			false,
+			&InstanceState{ID: "foo"},
+			&InstanceState{ID: "bar"},
+		},
+
+		// Different Attributes
+		{
+			false,
+			&InstanceState{Attributes: map[string]string{"foo": "bar"}},
+			&InstanceState{Attributes: map[string]string{"foo": "baz"}},
+		},
+
+		// Different Attribute keys
+		{
+			false,
+			&InstanceState{Attributes: map[string]string{"foo": "bar"}},
+			&InstanceState{Attributes: map[string]string{"bar": "baz"}},
+		},
+
+		{
+			false,
+			&InstanceState{Attributes: map[string]string{"bar": "baz"}},
+			&InstanceState{Attributes: map[string]string{"foo": "bar"}},
+		},
+	}
+
+	for i, tc := range cases {
+		if tc.One.Equal(tc.Two) != tc.Result {
+			t.Fatalf("Bad: %d\n\n%s\n\n%s", i, tc.One.String(), tc.Two.String())
+		}
+	}
+}
+
+func TestStateEmpty(t *testing.T) {
+	cases := []struct {
+		In     *State
+		Result bool
+	}{
+		{
+			nil,
+			true,
+		},
+		{
+			&State{},
+			true,
+		},
+		{
+			&State{
+				Remote: &RemoteState{Type: "foo"},
+			},
+			true,
+		},
+		{
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{},
+				},
+			},
+			false,
+		},
+	}
+
+	for i, tc := range cases {
+		if tc.In.Empty() != tc.Result {
+			t.Fatalf("bad %d %#v:\n\n%#v", i, tc.Result, tc.In)
+		}
+	}
+}
+
+func TestStateHasResources(t *testing.T) {
+	cases := []struct {
+		In     *State
+		Result bool
+	}{
+		{
+			nil,
+			false,
+		},
+		{
+			&State{},
+			false,
+		},
+		{
+			&State{
+				Remote: &RemoteState{Type: "foo"},
+			},
+			false,
+		},
+		{
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{},
+				},
+			},
+			false,
+		},
+		{
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{},
+					&ModuleState{},
+				},
+			},
+			false,
+		},
+		{
+			&State{
+				Modules: []*ModuleState{
+					&ModuleState{},
+					&ModuleState{
+						Resources: map[string]*ResourceState{
+							"foo.foo": &ResourceState{},
+						},
+					},
+				},
+			},
+			true,
+		},
+	}
+
+	for i, tc := range cases {
+		if tc.In.HasResources() != tc.Result {
+			t.Fatalf("bad %d %#v:\n\n%#v", i, tc.Result, tc.In)
+		}
+	}
+}
+
+func TestStateFromFutureTerraform(t *testing.T) {
+	cases := []struct {
+		In     string
+		Result bool
+	}{
+		{
+			"",
+			false,
+		},
+		{
+			"0.1",
+			false,
+		},
+		{
+			"999.15.1",
+			true,
+		},
+	}
+
+	for _, tc := range cases {
+		state := &State{TFVersion: tc.In}
+		actual := state.FromFutureTerraform()
+		if actual != tc.Result {
+			t.Fatalf("%s: bad: %v", tc.In, actual)
+		}
+	}
+}
+
+func TestStateIsRemote(t *testing.T) {
+	cases := []struct {
+		In     *State
+		Result bool
+	}{
+		{
+			nil,
+			false,
+		},
+		{
+			&State{},
+			false,
+		},
+		{
+			&State{
+				Remote: &RemoteState{Type: "foo"},
+			},
+			true,
+		},
+	}
+
+	for i, tc := range cases {
+		if tc.In.IsRemote() != tc.Result {
+			t.Fatalf("bad %d %#v:\n\n%#v", i, tc.Result, tc.In)
+		}
+	}
+}
+
+func TestInstanceState_MergeDiff(t *testing.T) {
+	is := InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"foo":  "bar",
+			"port": "8000",
+		},
+	}
+
+	diff := &InstanceDiff{
+		Attributes: map[string]*ResourceAttrDiff{
+			"foo": &ResourceAttrDiff{
+				Old: "bar",
+				New: "baz",
+			},
+			"bar": &ResourceAttrDiff{
+				Old: "",
+				New: "foo",
+			},
+			"baz": &ResourceAttrDiff{
+				Old:         "",
+				New:         "foo",
+				NewComputed: true,
+			},
+			"port": &ResourceAttrDiff{
+				NewRemoved: true,
+			},
+		},
+	}
+
+	is2 := is.MergeDiff(diff)
+
+	expected := map[string]string{
+		"foo": "baz",
+		"bar": "foo",
+		"baz": hcl2shim.UnknownVariableValue,
+	}
+
+	if !reflect.DeepEqual(expected, is2.Attributes) {
+		t.Fatalf("bad: %#v", is2.Attributes)
+	}
+}
+
+// GH-12183. This tests that a list with a computed set generates the
+// right partial state. This never failed but is put here for completion
+// of the test case for GH-12183.
+func TestInstanceState_MergeDiff_computedSet(t *testing.T) {
+	is := InstanceState{}
+
+	diff := &InstanceDiff{
+		Attributes: map[string]*ResourceAttrDiff{
+			"config.#": &ResourceAttrDiff{
+				Old:         "0",
+				New:         "1",
+				RequiresNew: true,
+			},
+
+			"config.0.name": &ResourceAttrDiff{
+				Old: "",
+				New: "hello",
+			},
+
+			"config.0.rules.#": &ResourceAttrDiff{
+				Old:         "",
+				NewComputed: true,
+			},
+		},
+	}
+
+	is2 := is.MergeDiff(diff)
+
+	expected := map[string]string{
+		"config.#":         "1",
+		"config.0.name":    "hello",
+		"config.0.rules.#": hcl2shim.UnknownVariableValue,
+	}
+
+	if !reflect.DeepEqual(expected, is2.Attributes) {
+		t.Fatalf("bad: %#v", is2.Attributes)
+	}
+}
+
+func TestInstanceState_MergeDiff_nil(t *testing.T) {
+	var is *InstanceState
+
+	diff := &InstanceDiff{
+		Attributes: map[string]*ResourceAttrDiff{
+			"foo": &ResourceAttrDiff{
+				Old: "",
+				New: "baz",
+			},
+		},
+	}
+
+	is2 := is.MergeDiff(diff)
+
+	expected := map[string]string{
+		"foo": "baz",
+	}
+
+	if !reflect.DeepEqual(expected, is2.Attributes) {
+		t.Fatalf("bad: %#v", is2.Attributes)
+	}
+}
+
+func TestInstanceState_MergeDiff_nilDiff(t *testing.T) {
+	is := InstanceState{
+		ID: "foo",
+		Attributes: map[string]string{
+			"foo": "bar",
+		},
+	}
+
+	is2 := is.MergeDiff(nil)
+
+	expected := map[string]string{
+		"foo": "bar",
+	}
+
+	if !reflect.DeepEqual(expected, is2.Attributes) {
+		t.Fatalf("bad: %#v", is2.Attributes)
+	}
+}
+
+func TestReadWriteState(t *testing.T) {
+	state := &State{
+		Serial:  9,
+		Lineage: "5d1ad1a1-4027-4665-a908-dbe6adff11d8",
+		Remote: &RemoteState{
+			Type: "http",
+			Config: map[string]string{
+				"url": "http://my-cool-server.com/",
+			},
+		},
+		Modules: []*ModuleState{
+			&ModuleState{
+				Path: rootModulePath,
+				Dependencies: []string{
+					"aws_instance.bar",
+				},
+				Resources: map[string]*ResourceState{
+					"foo": &ResourceState{
+						Primary: &InstanceState{
+							ID: "bar",
+							Ephemeral: EphemeralState{
+								ConnInfo: map[string]string{
+									"type":     "ssh",
+									"user":     "root",
+									"password": "supersecret",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	state.init()
+
+	buf := new(bytes.Buffer)
+	if err := WriteState(state, buf); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Verify that the version and serial are set
+	if state.Version != StateVersion {
+		t.Fatalf("bad version number: %d", state.Version)
+	}
+
+	actual, err := ReadState(buf)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// ReadState should not restore sensitive information!
+	mod := state.RootModule()
+	mod.Resources["foo"].Primary.Ephemeral = EphemeralState{}
+	mod.Resources["foo"].Primary.Ephemeral.init()
+
+	if !reflect.DeepEqual(actual, state) {
+		t.Logf("expected:\n%#v", state)
+		t.Fatalf("got:\n%#v", actual)
+	}
+}
+
+func TestReadStateNewVersion(t *testing.T) {
+	type out struct {
+		Version int
+	}
+
+	buf, err := json.Marshal(&out{StateVersion + 1})
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	s, err := ReadState(bytes.NewReader(buf))
+	if s != nil {
+		t.Fatalf("unexpected: %#v", s)
+	}
+	if !strings.Contains(err.Error(), "does not support state version") {
+		t.Fatalf("err: %v", err)
+	}
+}
+
+func TestReadStateEmptyOrNilFile(t *testing.T) {
+	var emptyState bytes.Buffer
+	_, err := ReadState(&emptyState)
+	if err != ErrNoState {
+		t.Fatal("expected ErrNostate, got", err)
+	}
+
+	var nilFile *os.File
+	_, err = ReadState(nilFile)
+	if err != ErrNoState {
+		t.Fatal("expected ErrNostate, got", err)
+	}
+}
+
+func TestReadStateTFVersion(t *testing.T) {
+	type tfVersion struct {
+		Version   int    `json:"version"`
+		TFVersion string `json:"terraform_version"`
+	}
+
+	cases := []struct {
+		Written string
+		Read    string
+		Err     bool
+	}{
+		{
+			"0.0.0",
+			"0.0.0",
+			false,
+		},
+		{
+			"",
+			"",
+			false,
+		},
+		{
+			"bad",
+			"",
+			true,
+		},
+	}
+
+	for _, tc := range cases {
+		buf, err := json.Marshal(&tfVersion{
+			Version:   2,
+			TFVersion: tc.Written,
+		})
+		if err != nil {
+			t.Fatalf("err: %v", err)
+		}
+
+		s, err := ReadState(bytes.NewReader(buf))
+		if (err != nil) != tc.Err {
+			t.Fatalf("%s: err: %s", tc.Written, err)
+		}
+		if err != nil {
+			continue
+		}
+
+		if s.TFVersion != tc.Read {
+			t.Fatalf("%s: bad: %s", tc.Written, s.TFVersion)
+		}
+	}
+}
+
+func TestWriteStateTFVersion(t *testing.T) {
+	cases := []struct {
+		Write string
+		Read  string
+		Err   bool
+	}{
+		{
+			"0.0.0",
+			"0.0.0",
+			false,
+		},
+		{
+			"",
+			"",
+			false,
+		},
+		{
+			"bad",
+			"",
+			true,
+		},
+	}
+
+	for _, tc := range cases {
+		var buf bytes.Buffer
+		err := WriteState(&State{TFVersion: tc.Write}, &buf)
+		if (err != nil) != tc.Err {
+			t.Fatalf("%s: err: %s", tc.Write, err)
+		}
+		if err != nil {
+			continue
+		}
+
+		s, err := ReadState(&buf)
+		if err != nil {
+			t.Fatalf("%s: err: %s", tc.Write, err)
+		}
+
+		if s.TFVersion != tc.Read {
+			t.Fatalf("%s: bad: %s", tc.Write, s.TFVersion)
+		}
+	}
+}
+
+func TestParseResourceStateKey(t *testing.T) {
+	cases := []struct {
+		Input       string
+		Expected    *ResourceStateKey
+		ExpectedErr bool
+	}{
+		{
+			Input: "aws_instance.foo.3",
+			Expected: &ResourceStateKey{
+				Mode:  ManagedResourceMode,
+				Type:  "aws_instance",
+				Name:  "foo",
+				Index: 3,
+			},
+		},
+		{
+			Input: "aws_instance.foo.0",
+			Expected: &ResourceStateKey{
+				Mode:  ManagedResourceMode,
+				Type:  "aws_instance",
+				Name:  "foo",
+				Index: 0,
+			},
+		},
+		{
+			Input: "aws_instance.foo",
+			Expected: &ResourceStateKey{
+				Mode:  ManagedResourceMode,
+				Type:  "aws_instance",
+				Name:  "foo",
+				Index: -1,
+			},
+		},
+		{
+			Input: "data.aws_ami.foo",
+			Expected: &ResourceStateKey{
+				Mode:  DataResourceMode,
+				Type:  "aws_ami",
+				Name:  "foo",
+				Index: -1,
+			},
+		},
+		{
+			Input:       "aws_instance.foo.malformed",
+			ExpectedErr: true,
+		},
+		{
+			Input:       "aws_instance.foo.malformedwithnumber.123",
+			ExpectedErr: true,
+		},
+		{
+			Input:       "malformed",
+			ExpectedErr: true,
+		},
+	}
+	for _, tc := range cases {
+		rsk, err := ParseResourceStateKey(tc.Input)
+		if rsk != nil && tc.Expected != nil && !rsk.Equal(tc.Expected) {
+			t.Fatalf("%s: expected %s, got %s", tc.Input, tc.Expected, rsk)
+		}
+		if (err != nil) != tc.ExpectedErr {
+			t.Fatalf("%s: expected err: %t, got %s", tc.Input, tc.ExpectedErr, err)
+		}
+	}
+}
+
+func TestReadState_prune(t *testing.T) {
+	state := &State{
+		Modules: []*ModuleState{
+			&ModuleState{Path: rootModulePath},
+			nil,
+		},
+	}
+	state.init()
+
+	buf := new(bytes.Buffer)
+	if err := WriteState(state, buf); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual, err := ReadState(buf)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := &State{
+		Version: state.Version,
+		Lineage: state.Lineage,
+	}
+	expected.init()
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("got:\n%#v", actual)
+	}
+}
+
+func TestReadState_pruneDependencies(t *testing.T) {
+	state := &State{
+		Serial:  9,
+		Lineage: "5d1ad1a1-4027-4665-a908-dbe6adff11d8",
+		Remote: &RemoteState{
+			Type: "http",
+			Config: map[string]string{
+				"url": "http://my-cool-server.com/",
+			},
+		},
+		Modules: []*ModuleState{
+			&ModuleState{
+				Path: rootModulePath,
+				Dependencies: []string{
+					"aws_instance.bar",
+					"aws_instance.bar",
+				},
+				Resources: map[string]*ResourceState{
+					"foo": &ResourceState{
+						Dependencies: []string{
+							"aws_instance.baz",
+							"aws_instance.baz",
+						},
+						Primary: &InstanceState{
+							ID: "bar",
+						},
+					},
+				},
+			},
+		},
+	}
+	state.init()
+
+	buf := new(bytes.Buffer)
+	if err := WriteState(state, buf); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual, err := ReadState(buf)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// make sure the duplicate Dependencies are filtered
+	modDeps := actual.Modules[0].Dependencies
+	resourceDeps := actual.Modules[0].Resources["foo"].Dependencies
+
+	if len(modDeps) > 1 || modDeps[0] != "aws_instance.bar" {
+		t.Fatalf("expected 1 module depends_on entry, got %q", modDeps)
+	}
+
+	if len(resourceDeps) > 1 || resourceDeps[0] != "aws_instance.baz" {
+		t.Fatalf("expected 1 resource depends_on entry, got  %q", resourceDeps)
+	}
+}
+
+func TestReadState_bigHash(t *testing.T) {
+	expected := uint64(14885267135666261723)
+	s := strings.NewReader(`{"version": 3, "backend":{"hash":14885267135666261723}}`)
+
+	actual, err := ReadState(s)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if actual.Backend.Hash != expected {
+		t.Fatalf("expected backend hash %d, got %d", expected, actual.Backend.Hash)
+	}
+}
+
+func TestResourceNameSort(t *testing.T) {
+	names := []string{
+		"a",
+		"b",
+		"a.0",
+		"a.c",
+		"a.d",
+		"c",
+		"a.b.0",
+		"a.b.1",
+		"a.b.10",
+		"a.b.2",
+	}
+
+	sort.Sort(resourceNameSort(names))
+
+	expected := []string{
+		"a",
+		"a.0",
+		"a.b.0",
+		"a.b.1",
+		"a.b.2",
+		"a.b.10",
+		"a.c",
+		"a.d",
+		"b",
+		"c",
+	}
+
+	if !reflect.DeepEqual(names, expected) {
+		t.Fatalf("got: %q\nexpected: %q\n", names, expected)
+	}
+}
diff --git a/v1.5.7/internal/legacy/terraform/state_upgrade_v1_to_v2.go b/v1.5.7/internal/legacy/terraform/state_upgrade_v1_to_v2.go
new file mode 100644
index 0000000..757a3d0
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/state_upgrade_v1_to_v2.go
@@ -0,0 +1,192 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+
+	"github.com/mitchellh/copystructure"
+)
+
+// upgradeStateV1ToV2 is used to upgrade a V1 state representation
+// into a V2 state representation
+func upgradeStateV1ToV2(old *stateV1) (*State, error) {
+	if old == nil {
+		return nil, nil
+	}
+
+	remote, err := old.Remote.upgradeToV2()
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading State V1: %v", err)
+	}
+
+	modules := make([]*ModuleState, len(old.Modules))
+	for i, module := range old.Modules {
+		upgraded, err := module.upgradeToV2()
+		if err != nil {
+			return nil, fmt.Errorf("Error upgrading State V1: %v", err)
+		}
+		modules[i] = upgraded
+	}
+	if len(modules) == 0 {
+		modules = nil
+	}
+
+	newState := &State{
+		Version: 2,
+		Serial:  old.Serial,
+		Remote:  remote,
+		Modules: modules,
+	}
+
+	newState.sort()
+	newState.init()
+
+	return newState, nil
+}
+
+func (old *remoteStateV1) upgradeToV2() (*RemoteState, error) {
+	if old == nil {
+		return nil, nil
+	}
+
+	config, err := copystructure.Copy(old.Config)
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading RemoteState V1: %v", err)
+	}
+
+	return &RemoteState{
+		Type:   old.Type,
+		Config: config.(map[string]string),
+	}, nil
+}
+
+func (old *moduleStateV1) upgradeToV2() (*ModuleState, error) {
+	if old == nil {
+		return nil, nil
+	}
+
+	pathRaw, err := copystructure.Copy(old.Path)
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading ModuleState V1: %v", err)
+	}
+	path, ok := pathRaw.([]string)
+	if !ok {
+		return nil, fmt.Errorf("Error upgrading ModuleState V1: path is not a list of strings")
+	}
+	if len(path) == 0 {
+		// We found some V1 states with a nil path. Assume root and catch
+		// duplicate path errors later (as part of Validate).
+		path = rootModulePath
+	}
+
+	// Outputs needs upgrading to use the new structure
+	outputs := make(map[string]*OutputState)
+	for key, output := range old.Outputs {
+		outputs[key] = &OutputState{
+			Type:      "string",
+			Value:     output,
+			Sensitive: false,
+		}
+	}
+
+	resources := make(map[string]*ResourceState)
+	for key, oldResource := range old.Resources {
+		upgraded, err := oldResource.upgradeToV2()
+		if err != nil {
+			return nil, fmt.Errorf("Error upgrading ModuleState V1: %v", err)
+		}
+		resources[key] = upgraded
+	}
+
+	dependencies, err := copystructure.Copy(old.Dependencies)
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading ModuleState V1: %v", err)
+	}
+
+	return &ModuleState{
+		Path:         path,
+		Outputs:      outputs,
+		Resources:    resources,
+		Dependencies: dependencies.([]string),
+	}, nil
+}
+
+func (old *resourceStateV1) upgradeToV2() (*ResourceState, error) {
+	if old == nil {
+		return nil, nil
+	}
+
+	dependencies, err := copystructure.Copy(old.Dependencies)
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading ResourceState V1: %v", err)
+	}
+
+	primary, err := old.Primary.upgradeToV2()
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading ResourceState V1: %v", err)
+	}
+
+	deposed := make([]*InstanceState, len(old.Deposed))
+	for i, v := range old.Deposed {
+		upgraded, err := v.upgradeToV2()
+		if err != nil {
+			return nil, fmt.Errorf("Error upgrading ResourceState V1: %v", err)
+		}
+		deposed[i] = upgraded
+	}
+	if len(deposed) == 0 {
+		deposed = nil
+	}
+
+	return &ResourceState{
+		Type:         old.Type,
+		Dependencies: dependencies.([]string),
+		Primary:      primary,
+		Deposed:      deposed,
+		Provider:     old.Provider,
+	}, nil
+}
+
+func (old *instanceStateV1) upgradeToV2() (*InstanceState, error) {
+	if old == nil {
+		return nil, nil
+	}
+
+	attributes, err := copystructure.Copy(old.Attributes)
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading InstanceState V1: %v", err)
+	}
+	ephemeral, err := old.Ephemeral.upgradeToV2()
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading InstanceState V1: %v", err)
+	}
+
+	meta, err := copystructure.Copy(old.Meta)
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading InstanceState V1: %v", err)
+	}
+
+	newMeta := make(map[string]interface{})
+	for k, v := range meta.(map[string]string) {
+		newMeta[k] = v
+	}
+
+	return &InstanceState{
+		ID:         old.ID,
+		Attributes: attributes.(map[string]string),
+		Ephemeral:  *ephemeral,
+		Meta:       newMeta,
+	}, nil
+}
+
+func (old *ephemeralStateV1) upgradeToV2() (*EphemeralState, error) {
+	connInfo, err := copystructure.Copy(old.ConnInfo)
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading EphemeralState V1: %v", err)
+	}
+	return &EphemeralState{
+		ConnInfo: connInfo.(map[string]string),
+	}, nil
+}
diff --git a/v1.5.7/internal/legacy/terraform/state_upgrade_v2_to_v3.go b/v1.5.7/internal/legacy/terraform/state_upgrade_v2_to_v3.go
new file mode 100644
index 0000000..ead9b61
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/state_upgrade_v2_to_v3.go
@@ -0,0 +1,145 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+// The upgrade process from V2 to V3 state does not affect the structure,
+// so we do not need to redeclare all of the structs involved - we just
+// take a deep copy of the old structure and assert the version number is
+// as we expect.
+func upgradeStateV2ToV3(old *State) (*State, error) {
+	new := old.DeepCopy()
+
+	// Ensure the copied version is v2 before attempting to upgrade
+	if new.Version != 2 {
+		return nil, fmt.Errorf("Cannot apply v2->v3 state upgrade to " +
+			"a state which is not version 2.")
+	}
+
+	// Set the new version number
+	new.Version = 3
+
+	// Change the counts for things which look like maps to use the %
+	// syntax. Remove counts for empty collections - they will be added
+	// back in later.
+	for _, module := range new.Modules {
+		for _, resource := range module.Resources {
+			// Upgrade Primary
+			if resource.Primary != nil {
+				upgradeAttributesV2ToV3(resource.Primary)
+			}
+
+			// Upgrade Deposed
+			if resource.Deposed != nil {
+				for _, deposed := range resource.Deposed {
+					upgradeAttributesV2ToV3(deposed)
+				}
+			}
+		}
+	}
+
+	return new, nil
+}
+
+func upgradeAttributesV2ToV3(instanceState *InstanceState) error {
+	collectionKeyRegexp := regexp.MustCompile(`^(.*\.)#$`)
+	collectionSubkeyRegexp := regexp.MustCompile(`^([^\.]+)\..*`)
+
+	// Identify the key prefix of anything which is a collection
+	var collectionKeyPrefixes []string
+	for key := range instanceState.Attributes {
+		if submatches := collectionKeyRegexp.FindAllStringSubmatch(key, -1); len(submatches) > 0 {
+			collectionKeyPrefixes = append(collectionKeyPrefixes, submatches[0][1])
+		}
+	}
+	sort.Strings(collectionKeyPrefixes)
+
+	log.Printf("[STATE UPGRADE] Detected the following collections in state: %v", collectionKeyPrefixes)
+
+	// This could be rolled into fewer loops, but it is somewhat clearer this way, and will not
+	// run very often.
+	for _, prefix := range collectionKeyPrefixes {
+		// First get the actual keys that belong to this prefix
+		var potentialKeysMatching []string
+		for key := range instanceState.Attributes {
+			if strings.HasPrefix(key, prefix) {
+				potentialKeysMatching = append(potentialKeysMatching, strings.TrimPrefix(key, prefix))
+			}
+		}
+		sort.Strings(potentialKeysMatching)
+
+		var actualKeysMatching []string
+		for _, key := range potentialKeysMatching {
+			if submatches := collectionSubkeyRegexp.FindAllStringSubmatch(key, -1); len(submatches) > 0 {
+				actualKeysMatching = append(actualKeysMatching, submatches[0][1])
+			} else {
+				if key != "#" {
+					actualKeysMatching = append(actualKeysMatching, key)
+				}
+			}
+		}
+		actualKeysMatching = uniqueSortedStrings(actualKeysMatching)
+
+		// Now inspect the keys in order to determine whether this is most likely to be
+		// a map, list or set. There is room for error here, so we log in each case. If
+		// there is no method of telling, we remove the key from the InstanceState in
+		// order that it will be recreated. Again, this could be rolled into fewer loops
+		// but we prefer clarity.
+
+		oldCountKey := fmt.Sprintf("%s#", prefix)
+
+		// First, detect "obvious" maps - which have non-numeric keys (mostly).
+		hasNonNumericKeys := false
+		for _, key := range actualKeysMatching {
+			if _, err := strconv.Atoi(key); err != nil {
+				hasNonNumericKeys = true
+			}
+		}
+		if hasNonNumericKeys {
+			newCountKey := fmt.Sprintf("%s%%", prefix)
+
+			instanceState.Attributes[newCountKey] = instanceState.Attributes[oldCountKey]
+			delete(instanceState.Attributes, oldCountKey)
+			log.Printf("[STATE UPGRADE] Detected %s as a map. Replaced count = %s",
+				strings.TrimSuffix(prefix, "."), instanceState.Attributes[newCountKey])
+		}
+
+		// Now detect empty collections and remove them from state.
+		if len(actualKeysMatching) == 0 {
+			delete(instanceState.Attributes, oldCountKey)
+			log.Printf("[STATE UPGRADE] Detected %s as an empty collection. Removed from state.",
+				strings.TrimSuffix(prefix, "."))
+		}
+	}
+
+	return nil
+}
+
+// uniqueSortedStrings removes duplicates from a slice of strings and returns
+// a sorted slice of the unique strings.
+func uniqueSortedStrings(input []string) []string {
+	uniquemap := make(map[string]struct{})
+	for _, str := range input {
+		uniquemap[str] = struct{}{}
+	}
+
+	output := make([]string, len(uniquemap))
+
+	i := 0
+	for key := range uniquemap {
+		output[i] = key
+		i = i + 1
+	}
+
+	sort.Strings(output)
+	return output
+}
diff --git a/v1.5.7/internal/legacy/terraform/state_v1.go b/v1.5.7/internal/legacy/terraform/state_v1.go
new file mode 100644
index 0000000..d225766
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/state_v1.go
@@ -0,0 +1,148 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+// stateV1 keeps track of a snapshot state-of-the-world that Terraform
+// can use to keep track of what real world resources it is actually
+// managing.
+//
+// stateV1 is _only used for the purposes of backwards compatibility
+// and is no longer used in Terraform.
+//
+// For the upgrade process, see state_upgrade_v1_to_v2.go
+type stateV1 struct {
+	// Version is the protocol version. "1" for a StateV1.
+	Version int `json:"version"`
+
+	// Serial is incremented on any operation that modifies
+	// the State file. It is used to detect potentially conflicting
+	// updates.
+	Serial int64 `json:"serial"`
+
+	// Remote is used to track the metadata required to
+	// pull and push state files from a remote storage endpoint.
+	Remote *remoteStateV1 `json:"remote,omitempty"`
+
+	// Modules contains all the modules in a breadth-first order
+	Modules []*moduleStateV1 `json:"modules"`
+}
+
+type remoteStateV1 struct {
+	// Type controls the client we use for the remote state
+	Type string `json:"type"`
+
+	// Config is used to store arbitrary configuration that
+	// is type specific
+	Config map[string]string `json:"config"`
+}
+
+type moduleStateV1 struct {
+	// Path is the import path from the root module. Modules imports are
+	// always disjoint, so the path represents amodule tree
+	Path []string `json:"path"`
+
+	// Outputs declared by the module and maintained for each module
+	// even though only the root module technically needs to be kept.
+	// This allows operators to inspect values at the boundaries.
+	Outputs map[string]string `json:"outputs"`
+
+	// Resources is a mapping of the logically named resource to
+	// the state of the resource. Each resource may actually have
+	// N instances underneath, although a user only needs to think
+	// about the 1:1 case.
+	Resources map[string]*resourceStateV1 `json:"resources"`
+
+	// Dependencies are a list of things that this module relies on
+	// existing to remain intact. For example: an module may depend
+	// on a VPC ID given by an aws_vpc resource.
+	//
+	// Terraform uses this information to build valid destruction
+	// orders and to warn the user if they're destroying a module that
+	// another resource depends on.
+	//
+	// Things can be put into this list that may not be managed by
+	// Terraform. If Terraform doesn't find a matching ID in the
+	// overall state, then it assumes it isn't managed and doesn't
+	// worry about it.
+	Dependencies []string `json:"depends_on,omitempty"`
+}
+
+type resourceStateV1 struct {
+	// This is filled in and managed by Terraform, and is the resource
+	// type itself such as "mycloud_instance". If a resource provider sets
+	// this value, it won't be persisted.
+	Type string `json:"type"`
+
+	// Dependencies are a list of things that this resource relies on
+	// existing to remain intact. For example: an AWS instance might
+	// depend on a subnet (which itself might depend on a VPC, and so
+	// on).
+	//
+	// Terraform uses this information to build valid destruction
+	// orders and to warn the user if they're destroying a resource that
+	// another resource depends on.
+	//
+	// Things can be put into this list that may not be managed by
+	// Terraform. If Terraform doesn't find a matching ID in the
+	// overall state, then it assumes it isn't managed and doesn't
+	// worry about it.
+	Dependencies []string `json:"depends_on,omitempty"`
+
+	// Primary is the current active instance for this resource.
+	// It can be replaced but only after a successful creation.
+	// This is the instances on which providers will act.
+	Primary *instanceStateV1 `json:"primary"`
+
+	// Tainted is used to track any underlying instances that
+	// have been created but are in a bad or unknown state and
+	// need to be cleaned up subsequently.  In the
+	// standard case, there is only at most a single instance.
+	// However, in pathological cases, it is possible for the number
+	// of instances to accumulate.
+	Tainted []*instanceStateV1 `json:"tainted,omitempty"`
+
+	// Deposed is used in the mechanics of CreateBeforeDestroy: the existing
+	// Primary is Deposed to get it out of the way for the replacement Primary to
+	// be created by Apply. If the replacement Primary creates successfully, the
+	// Deposed instance is cleaned up. If there were problems creating the
+	// replacement, the instance remains in the Deposed list so it can be
+	// destroyed in a future run. Functionally, Deposed instances are very
+	// similar to Tainted instances in that Terraform is only tracking them in
+	// order to remember to destroy them.
+	Deposed []*instanceStateV1 `json:"deposed,omitempty"`
+
+	// Provider is used when a resource is connected to a provider with an alias.
+	// If this string is empty, the resource is connected to the default provider,
+	// e.g. "aws_instance" goes with the "aws" provider.
+	// If the resource block contained a "provider" key, that value will be set here.
+	Provider string `json:"provider,omitempty"`
+}
+
+type instanceStateV1 struct {
+	// A unique ID for this resource. This is opaque to Terraform
+	// and is only meant as a lookup mechanism for the providers.
+	ID string `json:"id"`
+
+	// Attributes are basic information about the resource. Any keys here
+	// are accessible in variable format within Terraform configurations:
+	// ${resourcetype.name.attribute}.
+	Attributes map[string]string `json:"attributes,omitempty"`
+
+	// Ephemeral is used to store any state associated with this instance
+	// that is necessary for the Terraform run to complete, but is not
+	// persisted to a state file.
+	Ephemeral ephemeralStateV1 `json:"-"`
+
+	// Meta is a simple K/V map that is persisted to the State but otherwise
+	// ignored by Terraform core. It's meant to be used for accounting by
+	// external client code.
+	Meta map[string]string `json:"meta,omitempty"`
+}
+
+type ephemeralStateV1 struct {
+	// ConnInfo is used for the providers to export information which is
+	// used to connect to the resource for provisioning. For example,
+	// this could contain SSH or WinRM credentials.
+	ConnInfo map[string]string `json:"-"`
+}
diff --git a/v1.5.7/internal/legacy/terraform/testing.go b/v1.5.7/internal/legacy/terraform/testing.go
new file mode 100644
index 0000000..a1337a8
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/testing.go
@@ -0,0 +1,22 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"os"
+	"testing"
+)
+
+// TestStateFile writes the given state to the path.
+func TestStateFile(t *testing.T, path string, state *State) {
+	f, err := os.Create(path)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer f.Close()
+
+	if err := WriteState(state, f); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+}
diff --git a/v1.5.7/internal/legacy/terraform/ui_input.go b/v1.5.7/internal/legacy/terraform/ui_input.go
new file mode 100644
index 0000000..4c59177
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/ui_input.go
@@ -0,0 +1,35 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import "context"
+
+// UIInput is the interface that must be implemented to ask for input
+// from this user. This should forward the request to wherever the user
+// inputs things to ask for values.
+type UIInput interface {
+	Input(context.Context, *InputOpts) (string, error)
+}
+
+// InputOpts are options for asking for input.
+type InputOpts struct {
+	// Id is a unique ID for the question being asked that might be
+	// used for logging or to look up a prior answered question.
+	Id string
+
+	// Query is a human-friendly question for inputting this value.
+	Query string
+
+	// Description is a description about what this option is. Be wary
+	// that this will probably be in a terminal so split lines as you see
+	// necessary.
+	Description string
+
+	// Default will be the value returned if no data is entered.
+	Default string
+
+	// Secret should be true if we are asking for sensitive input.
+	// If attached to a TTY, Terraform will disable echo.
+	Secret bool
+}
diff --git a/v1.5.7/internal/legacy/terraform/ui_input_mock.go b/v1.5.7/internal/legacy/terraform/ui_input_mock.go
new file mode 100644
index 0000000..4d8e028
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/ui_input_mock.go
@@ -0,0 +1,28 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import "context"
+
+// MockUIInput is an implementation of UIInput that can be used for tests.
+type MockUIInput struct {
+	InputCalled       bool
+	InputOpts         *InputOpts
+	InputReturnMap    map[string]string
+	InputReturnString string
+	InputReturnError  error
+	InputFn           func(*InputOpts) (string, error)
+}
+
+func (i *MockUIInput) Input(ctx context.Context, opts *InputOpts) (string, error) {
+	i.InputCalled = true
+	i.InputOpts = opts
+	if i.InputFn != nil {
+		return i.InputFn(opts)
+	}
+	if i.InputReturnMap != nil {
+		return i.InputReturnMap[opts.Id], i.InputReturnError
+	}
+	return i.InputReturnString, i.InputReturnError
+}
diff --git a/v1.5.7/internal/legacy/terraform/ui_input_prefix.go b/v1.5.7/internal/legacy/terraform/ui_input_prefix.go
new file mode 100644
index 0000000..69a7032
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/ui_input_prefix.go
@@ -0,0 +1,23 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"context"
+	"fmt"
+)
+
+// PrefixUIInput is an implementation of UIInput that prefixes the ID
+// with a string, allowing queries to be namespaced.
+type PrefixUIInput struct {
+	IdPrefix    string
+	QueryPrefix string
+	UIInput     UIInput
+}
+
+func (i *PrefixUIInput) Input(ctx context.Context, opts *InputOpts) (string, error) {
+	opts.Id = fmt.Sprintf("%s.%s", i.IdPrefix, opts.Id)
+	opts.Query = fmt.Sprintf("%s%s", i.QueryPrefix, opts.Query)
+	return i.UIInput.Input(ctx, opts)
+}
diff --git a/v1.5.7/internal/legacy/terraform/ui_input_prefix_test.go b/v1.5.7/internal/legacy/terraform/ui_input_prefix_test.go
new file mode 100644
index 0000000..d6a83ac
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/ui_input_prefix_test.go
@@ -0,0 +1,30 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"context"
+	"testing"
+)
+
+func TestPrefixUIInput_impl(t *testing.T) {
+	var _ UIInput = new(PrefixUIInput)
+}
+
+func TestPrefixUIInput(t *testing.T) {
+	input := new(MockUIInput)
+	prefix := &PrefixUIInput{
+		IdPrefix: "foo",
+		UIInput:  input,
+	}
+
+	_, err := prefix.Input(context.Background(), &InputOpts{Id: "bar"})
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if input.InputOpts.Id != "foo.bar" {
+		t.Fatalf("bad: %#v", input.InputOpts)
+	}
+}
diff --git a/v1.5.7/internal/legacy/terraform/ui_output.go b/v1.5.7/internal/legacy/terraform/ui_output.go
new file mode 100644
index 0000000..a816b0d
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/ui_output.go
@@ -0,0 +1,10 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+// UIOutput is the interface that must be implemented to output
+// data to the end user.
+type UIOutput interface {
+	Output(string)
+}
diff --git a/v1.5.7/internal/legacy/terraform/ui_output_callback.go b/v1.5.7/internal/legacy/terraform/ui_output_callback.go
new file mode 100644
index 0000000..e79f082
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/ui_output_callback.go
@@ -0,0 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+type CallbackUIOutput struct {
+	OutputFn func(string)
+}
+
+func (o *CallbackUIOutput) Output(v string) {
+	o.OutputFn(v)
+}
diff --git a/v1.5.7/internal/legacy/terraform/ui_output_callback_test.go b/v1.5.7/internal/legacy/terraform/ui_output_callback_test.go
new file mode 100644
index 0000000..8748c0b
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/ui_output_callback_test.go
@@ -0,0 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+)
+
+func TestCallbackUIOutput_impl(t *testing.T) {
+	var _ UIOutput = new(CallbackUIOutput)
+}
diff --git a/v1.5.7/internal/legacy/terraform/ui_output_mock.go b/v1.5.7/internal/legacy/terraform/ui_output_mock.go
new file mode 100644
index 0000000..641d076
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/ui_output_mock.go
@@ -0,0 +1,24 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import "sync"
+
+// MockUIOutput is an implementation of UIOutput that can be used for tests.
+type MockUIOutput struct {
+	sync.Mutex
+	OutputCalled  bool
+	OutputMessage string
+	OutputFn      func(string)
+}
+
+func (o *MockUIOutput) Output(v string) {
+	o.Lock()
+	defer o.Unlock()
+	o.OutputCalled = true
+	o.OutputMessage = v
+	if o.OutputFn != nil {
+		o.OutputFn(v)
+	}
+}
diff --git a/v1.5.7/internal/legacy/terraform/ui_output_mock_test.go b/v1.5.7/internal/legacy/terraform/ui_output_mock_test.go
new file mode 100644
index 0000000..89d564a
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/ui_output_mock_test.go
@@ -0,0 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+)
+
+func TestMockUIOutput(t *testing.T) {
+	var _ UIOutput = new(MockUIOutput)
+}
diff --git a/v1.5.7/internal/legacy/terraform/upgrade_state_v1_test.go b/v1.5.7/internal/legacy/terraform/upgrade_state_v1_test.go
new file mode 100644
index 0000000..fd46aa9
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/upgrade_state_v1_test.go
@@ -0,0 +1,193 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"bytes"
+	"reflect"
+	"strings"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+)
+
+// TestReadUpgradeStateV1toV3 tests the state upgrade process from the V1 state
+// to the current version, and needs editing each time. This means it tests the
+// entire pipeline of upgrades (which migrate version to version).
+func TestReadUpgradeStateV1toV3(t *testing.T) {
+	// ReadState should transparently detect the old version but will upgrade
+	// it on Write.
+	actual, err := ReadState(strings.NewReader(testV1State))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	buf := new(bytes.Buffer)
+	if err := WriteState(actual, buf); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if actual.Version != 3 {
+		t.Fatalf("bad: State version not incremented; is %d", actual.Version)
+	}
+
+	roundTripped, err := ReadState(buf)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !reflect.DeepEqual(actual, roundTripped) {
+		t.Logf("actual:\n%#v", actual)
+		t.Fatalf("roundTripped:\n%#v", roundTripped)
+	}
+}
+
+func TestReadUpgradeStateV1toV3_outputs(t *testing.T) {
+	// ReadState should transparently detect the old version but will upgrade
+	// it on Write.
+	actual, err := ReadState(strings.NewReader(testV1StateWithOutputs))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	buf := new(bytes.Buffer)
+	if err := WriteState(actual, buf); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if actual.Version != 3 {
+		t.Fatalf("bad: State version not incremented; is %d", actual.Version)
+	}
+
+	roundTripped, err := ReadState(buf)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !reflect.DeepEqual(actual, roundTripped) {
+		spew.Config.DisableMethods = true
+		t.Fatalf("bad:\n%s\n\nround tripped:\n%s\n", spew.Sdump(actual), spew.Sdump(roundTripped))
+		spew.Config.DisableMethods = false
+	}
+}
+
+// Upgrading the state should not lose empty module Outputs and Resources maps
+// during upgrade. The init for a new module initializes new maps, so we may not
+// be expecting to check for a nil map.
+func TestReadUpgradeStateV1toV3_emptyState(t *testing.T) {
+	// ReadState should transparently detect the old version but will upgrade
+	// it on Write.
+	orig, err := ReadStateV1([]byte(testV1EmptyState))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	stateV2, err := upgradeStateV1ToV2(orig)
+	if err != nil {
+		t.Fatalf("error attempting upgradeStateV1ToV2: %s", err)
+	}
+
+	for _, m := range stateV2.Modules {
+		if m.Resources == nil {
+			t.Fatal("V1 to V2 upgrade lost module.Resources")
+		}
+		if m.Outputs == nil {
+			t.Fatal("V1 to V2 upgrade lost module.Outputs")
+		}
+	}
+
+	stateV3, err := upgradeStateV2ToV3(stateV2)
+	if err != nil {
+		t.Fatalf("error attempting to upgradeStateV2ToV3: %s", err)
+	}
+	for _, m := range stateV3.Modules {
+		if m.Resources == nil {
+			t.Fatal("V2 to V3 upgrade lost module.Resources")
+		}
+		if m.Outputs == nil {
+			t.Fatal("V2 to V3 upgrade lost module.Outputs")
+		}
+	}
+
+}
+
+const testV1EmptyState = `{
+    "version": 1,
+    "serial": 0,
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {}
+        }
+    ]
+}
+`
+
+const testV1State = `{
+    "version": 1,
+    "serial": 9,
+    "remote": {
+        "type": "http",
+        "config": {
+            "url": "http://my-cool-server.com/"
+        }
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": null,
+            "resources": {
+                "foo": {
+                    "type": "",
+                    "primary": {
+                        "id": "bar"
+                    }
+                }
+            },
+            "depends_on": [
+                "aws_instance.bar"
+            ]
+        }
+    ]
+}
+`
+
+const testV1StateWithOutputs = `{
+    "version": 1,
+    "serial": 9,
+    "remote": {
+        "type": "http",
+        "config": {
+            "url": "http://my-cool-server.com/"
+        }
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {
+            	"foo": "bar",
+            	"baz": "foo"
+            },
+            "resources": {
+                "foo": {
+                    "type": "",
+                    "primary": {
+                        "id": "bar"
+                    }
+                }
+            },
+            "depends_on": [
+                "aws_instance.bar"
+            ]
+        }
+    ]
+}
+`
diff --git a/v1.5.7/internal/legacy/terraform/upgrade_state_v2_test.go b/v1.5.7/internal/legacy/terraform/upgrade_state_v2_test.go
new file mode 100644
index 0000000..68658ca
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/upgrade_state_v2_test.go
@@ -0,0 +1,205 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"bytes"
+	"strings"
+	"testing"
+)
+
+// TestReadUpgradeStateV2toV3 tests the state upgrade process from the V2 state
+// to the current version, and needs editing each time. This means it tests the
+// entire pipeline of upgrades (which migrate version to version).
+func TestReadUpgradeStateV2toV3(t *testing.T) {
+	// ReadState should transparently detect the old version but will upgrade
+	// it on Write.
+	upgraded, err := ReadState(strings.NewReader(testV2State))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	buf := new(bytes.Buffer)
+	if err := WriteState(upgraded, buf); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if upgraded.Version != 3 {
+		t.Fatalf("bad: State version not incremented; is %d", upgraded.Version)
+	}
+
+	// For this test we cannot assert that we match the round trip because an
+	// empty map has been removed from state. Instead we make assertions against
+	// some of the key fields in the _upgraded_ state.
+	instanceState, ok := upgraded.RootModule().Resources["test_resource.main"]
+	if !ok {
+		t.Fatalf("Instance state for test_resource.main was removed from state during upgrade")
+	}
+
+	primary := instanceState.Primary
+	if primary == nil {
+		t.Fatalf("Primary instance was removed from state for test_resource.main")
+	}
+
+	// Non-empty computed map is moved from .# to .%
+	if _, ok := primary.Attributes["computed_map.#"]; ok {
+		t.Fatalf("Count was not upgraded from .# to .%% for computed_map")
+	}
+	if count, ok := primary.Attributes["computed_map.%"]; !ok || count != "1" {
+		t.Fatalf("Count was not in .%% or was not 2 for computed_map")
+	}
+
+	// list_of_map top level retains .#
+	if count, ok := primary.Attributes["list_of_map.#"]; !ok || count != "2" {
+		t.Fatal("Count for list_of_map was migrated incorrectly")
+	}
+
+	// list_of_map.0 is moved from .# to .%
+	if _, ok := primary.Attributes["list_of_map.0.#"]; ok {
+		t.Fatalf("Count was not upgraded from .# to .%% for list_of_map.0")
+	}
+	if count, ok := primary.Attributes["list_of_map.0.%"]; !ok || count != "2" {
+		t.Fatalf("Count was not in .%% or was not 2 for list_of_map.0")
+	}
+
+	// list_of_map.1 is moved from .# to .%
+	if _, ok := primary.Attributes["list_of_map.1.#"]; ok {
+		t.Fatalf("Count was not upgraded from .# to .%% for list_of_map.1")
+	}
+	if count, ok := primary.Attributes["list_of_map.1.%"]; !ok || count != "2" {
+		t.Fatalf("Count was not in .%% or was not 2 for list_of_map.1")
+	}
+
+	// map is moved from .# to .%
+	if _, ok := primary.Attributes["map.#"]; ok {
+		t.Fatalf("Count was not upgraded from .# to .%% for map")
+	}
+	if count, ok := primary.Attributes["map.%"]; !ok || count != "2" {
+		t.Fatalf("Count was not in .%% or was not 2 for map")
+	}
+
+	// optional_computed_map should be removed from state
+	if _, ok := primary.Attributes["optional_computed_map"]; ok {
+		t.Fatal("optional_computed_map was not removed from state")
+	}
+
+	// required_map is moved from .# to .%
+	if _, ok := primary.Attributes["required_map.#"]; ok {
+		t.Fatalf("Count was not upgraded from .# to .%% for required_map")
+	}
+	if count, ok := primary.Attributes["required_map.%"]; !ok || count != "3" {
+		t.Fatalf("Count was not in .%% or was not 3 for map")
+	}
+
+	// computed_list keeps .#
+	if count, ok := primary.Attributes["computed_list.#"]; !ok || count != "2" {
+		t.Fatal("Count was migrated incorrectly for computed_list")
+	}
+
+	// computed_set keeps .#
+	if count, ok := primary.Attributes["computed_set.#"]; !ok || count != "2" {
+		t.Fatal("Count was migrated incorrectly for computed_set")
+	}
+	if val, ok := primary.Attributes["computed_set.2337322984"]; !ok || val != "setval1" {
+		t.Fatal("Set item for computed_set.2337322984 changed or moved")
+	}
+	if val, ok := primary.Attributes["computed_set.307881554"]; !ok || val != "setval2" {
+		t.Fatal("Set item for computed_set.307881554 changed or moved")
+	}
+
+	// string properties are unaffected
+	if val, ok := primary.Attributes["id"]; !ok || val != "testId" {
+		t.Fatal("id was not set correctly after migration")
+	}
+}
+
+const testV2State = `{
+    "version": 2,
+    "terraform_version": "0.7.0",
+    "serial": 2,
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {
+                "computed_map": {
+                    "sensitive": false,
+                    "type": "map",
+                    "value": {
+                        "key1": "value1"
+                    }
+                },
+                "computed_set": {
+                    "sensitive": false,
+                    "type": "list",
+                    "value": [
+                        "setval1",
+                        "setval2"
+                    ]
+                },
+                "map": {
+                    "sensitive": false,
+                    "type": "map",
+                    "value": {
+                        "key": "test",
+                        "test": "test"
+                    }
+                },
+                "set": {
+                    "sensitive": false,
+                    "type": "list",
+                    "value": [
+                        "test1",
+                        "test2"
+                    ]
+                }
+            },
+            "resources": {
+                "test_resource.main": {
+                    "type": "test_resource",
+                    "primary": {
+                        "id": "testId",
+                        "attributes": {
+                            "computed_list.#": "2",
+                            "computed_list.0": "listval1",
+                            "computed_list.1": "listval2",
+                            "computed_map.#": "1",
+                            "computed_map.key1": "value1",
+                            "computed_read_only": "value_from_api",
+                            "computed_read_only_force_new": "value_from_api",
+                            "computed_set.#": "2",
+                            "computed_set.2337322984": "setval1",
+                            "computed_set.307881554": "setval2",
+                            "id": "testId",
+                            "list_of_map.#": "2",
+                            "list_of_map.0.#": "2",
+                            "list_of_map.0.key1": "value1",
+                            "list_of_map.0.key2": "value2",
+                            "list_of_map.1.#": "2",
+                            "list_of_map.1.key3": "value3",
+                            "list_of_map.1.key4": "value4",
+                            "map.#": "2",
+                            "map.key": "test",
+                            "map.test": "test",
+                            "map_that_look_like_set.#": "2",
+                            "map_that_look_like_set.12352223": "hello",
+                            "map_that_look_like_set.36234341": "world",
+                            "optional_computed_map.#": "0",
+                            "required": "Hello World",
+                            "required_map.#": "3",
+                            "required_map.key1": "value1",
+                            "required_map.key2": "value2",
+                            "required_map.key3": "value3",
+                            "set.#": "2",
+                            "set.2326977762": "test1",
+                            "set.331058520": "test2"
+                        }
+                    }
+                }
+            }
+        }
+    ]
+}
+`
diff --git a/v1.5.7/internal/legacy/terraform/util.go b/v1.5.7/internal/legacy/terraform/util.go
new file mode 100644
index 0000000..d25e105
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/util.go
@@ -0,0 +1,78 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"sort"
+)
+
+// Semaphore is a wrapper around a channel to provide
+// utility methods to clarify that we are treating the
+// channel as a semaphore
+type Semaphore chan struct{}
+
+// NewSemaphore creates a semaphore that allows up
+// to a given limit of simultaneous acquisitions
+func NewSemaphore(n int) Semaphore {
+	if n <= 0 {
+		panic("semaphore with limit <=0")
+	}
+	ch := make(chan struct{}, n)
+	return Semaphore(ch)
+}
+
+// Acquire is used to acquire an available slot.
+// Blocks until available.
+func (s Semaphore) Acquire() {
+	s <- struct{}{}
+}
+
+// TryAcquire is used to do a non-blocking acquire.
+// Returns a bool indicating success
+func (s Semaphore) TryAcquire() bool {
+	select {
+	case s <- struct{}{}:
+		return true
+	default:
+		return false
+	}
+}
+
+// Release is used to return a slot. Acquire must
+// be called as a pre-condition.
+func (s Semaphore) Release() {
+	select {
+	case <-s:
+	default:
+		panic("release without an acquire")
+	}
+}
+
+// strSliceContains checks if a given string is contained in a slice
+// When anybody asks why Go needs generics, here you go.
+func strSliceContains(haystack []string, needle string) bool {
+	for _, s := range haystack {
+		if s == needle {
+			return true
+		}
+	}
+	return false
+}
+
+// deduplicate a slice of strings
+func uniqueStrings(s []string) []string {
+	if len(s) < 2 {
+		return s
+	}
+
+	sort.Strings(s)
+	result := make([]string, 1, len(s))
+	result[0] = s[0]
+	for i := 1; i < len(s); i++ {
+		if s[i] != result[len(result)-1] {
+			result = append(result, s[i])
+		}
+	}
+	return result
+}
diff --git a/v1.5.7/internal/legacy/terraform/util_test.go b/v1.5.7/internal/legacy/terraform/util_test.go
new file mode 100644
index 0000000..0676c6f
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/util_test.go
@@ -0,0 +1,94 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+	"time"
+)
+
+func TestSemaphore(t *testing.T) {
+	s := NewSemaphore(2)
+	timer := time.AfterFunc(time.Second, func() {
+		panic("deadlock")
+	})
+	defer timer.Stop()
+
+	s.Acquire()
+	if !s.TryAcquire() {
+		t.Fatalf("should acquire")
+	}
+	if s.TryAcquire() {
+		t.Fatalf("should not acquire")
+	}
+	s.Release()
+	s.Release()
+
+	// This release should panic
+	defer func() {
+		r := recover()
+		if r == nil {
+			t.Fatalf("should panic")
+		}
+	}()
+	s.Release()
+}
+
+func TestStrSliceContains(t *testing.T) {
+	if strSliceContains(nil, "foo") {
+		t.Fatalf("Bad")
+	}
+	if strSliceContains([]string{}, "foo") {
+		t.Fatalf("Bad")
+	}
+	if strSliceContains([]string{"bar"}, "foo") {
+		t.Fatalf("Bad")
+	}
+	if !strSliceContains([]string{"bar", "foo"}, "foo") {
+		t.Fatalf("Bad")
+	}
+}
+
+func TestUniqueStrings(t *testing.T) {
+	cases := []struct {
+		Input    []string
+		Expected []string
+	}{
+		{
+			[]string{},
+			[]string{},
+		},
+		{
+			[]string{"x"},
+			[]string{"x"},
+		},
+		{
+			[]string{"a", "b", "c"},
+			[]string{"a", "b", "c"},
+		},
+		{
+			[]string{"a", "a", "a"},
+			[]string{"a"},
+		},
+		{
+			[]string{"a", "b", "a", "b", "a", "a"},
+			[]string{"a", "b"},
+		},
+		{
+			[]string{"c", "b", "a", "c", "b"},
+			[]string{"a", "b", "c"},
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("unique-%d", i), func(t *testing.T) {
+			actual := uniqueStrings(tc.Input)
+			if !reflect.DeepEqual(tc.Expected, actual) {
+				t.Fatalf("Expected: %q\nGot: %q", tc.Expected, actual)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/legacy/terraform/version.go b/v1.5.7/internal/legacy/terraform/version.go
new file mode 100644
index 0000000..6ee2e93
--- /dev/null
+++ b/v1.5.7/internal/legacy/terraform/version.go
@@ -0,0 +1,13 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/version"
+)
+
+// Deprecated: Providers should use schema.Provider.TerraformVersion instead
+func VersionString() string {
+	return version.String()
+}
diff --git a/v1.5.7/internal/logging/indent.go b/v1.5.7/internal/logging/indent.go
new file mode 100644
index 0000000..b3c9df4
--- /dev/null
+++ b/v1.5.7/internal/logging/indent.go
@@ -0,0 +1,26 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package logging
+
+import (
+	"strings"
+)
+
+// Indent adds two spaces to the beginning of each line of the given string,
+// with the goal of making the log level filter understand it as a line
+// continuation rather than possibly as new log lines.
+func Indent(s string) string {
+	var b strings.Builder
+	for len(s) > 0 {
+		end := strings.IndexByte(s, '\n')
+		if end == -1 {
+			end = len(s) - 1
+		}
+		var l string
+		l, s = s[:end+1], s[end+1:]
+		b.WriteString("  ")
+		b.WriteString(l)
+	}
+	return b.String()
+}
diff --git a/v1.5.7/internal/logging/indent_test.go b/v1.5.7/internal/logging/indent_test.go
new file mode 100644
index 0000000..b358fcb
--- /dev/null
+++ b/v1.5.7/internal/logging/indent_test.go
@@ -0,0 +1,18 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package logging
+
+import (
+	"testing"
+)
+
+func TestIndent(t *testing.T) {
+	s := "hello\n  world\ngoodbye\n  moon"
+	got := Indent(s)
+	want := "  hello\n    world\n  goodbye\n    moon"
+
+	if got != want {
+		t.Errorf("wrong result\ngot:\n%s\n\nwant:\n%s", got, want)
+	}
+}
diff --git a/v1.5.7/internal/logging/logging.go b/v1.5.7/internal/logging/logging.go
new file mode 100644
index 0000000..325b747
--- /dev/null
+++ b/v1.5.7/internal/logging/logging.go
@@ -0,0 +1,229 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package logging
+
+import (
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"strings"
+	"syscall"
+
+	// go.etcd.io/etcd imports capnslog, which calls log.SetOutput in its
+	// init() function, so importing it here means that our log.SetOutput
+	// wins. this is fixed in coreos v3.5, which is not released yet. See
+	// https://github.com/etcd-io/etcd/issues/12498 for more information.
+	_ "github.com/coreos/pkg/capnslog"
+	"github.com/hashicorp/go-hclog"
+)
+
+// These are the environmental variables that determine if we log, and if
+// we log whether or not the log should go to a file.
+const (
+	envLog     = "TF_LOG"
+	envLogFile = "TF_LOG_PATH"
+
+	// Allow logging of specific subsystems.
+	// We only separate core and providers for now, but this could be extended
+	// to other loggers, like provisioners and remote-state backends.
+	envLogCore     = "TF_LOG_CORE"
+	envLogProvider = "TF_LOG_PROVIDER"
+)
+
+var (
+	// ValidLevels are the log level names that Terraform recognizes.
+	ValidLevels = []string{"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF"}
+
+	// logger is the global hclog logger
+	logger hclog.Logger
+
+	// logWriter is a global writer for logs, to be used with the std log package
+	logWriter io.Writer
+
+	// initialize our cache of panic output from providers
+	panics = &panicRecorder{
+		panics:   make(map[string][]string),
+		maxLines: 100,
+	}
+)
+
+func init() {
+	logger = newHCLogger("")
+	logWriter = logger.StandardWriter(&hclog.StandardLoggerOptions{InferLevels: true})
+
+	// set up the default std library logger to use our output
+	log.SetFlags(0)
+	log.SetPrefix("")
+	log.SetOutput(logWriter)
+}
+
+// SetupTempLog adds a new log sink which writes all logs to the given file.
+func RegisterSink(f *os.File) {
+	l, ok := logger.(hclog.InterceptLogger)
+	if !ok {
+		panic("global logger is not an InterceptLogger")
+	}
+
+	if f == nil {
+		return
+	}
+
+	l.RegisterSink(hclog.NewSinkAdapter(&hclog.LoggerOptions{
+		Level:  hclog.Trace,
+		Output: f,
+	}))
+}
+
+// LogOutput return the default global log io.Writer
+func LogOutput() io.Writer {
+	return logWriter
+}
+
+// HCLogger returns the default global hclog logger
+func HCLogger() hclog.Logger {
+	return logger
+}
+
+// newHCLogger returns a new hclog.Logger instance with the given name
+func newHCLogger(name string) hclog.Logger {
+	logOutput := io.Writer(os.Stderr)
+	logLevel, json := globalLogLevel()
+
+	if logPath := os.Getenv(envLogFile); logPath != "" {
+		f, err := os.OpenFile(logPath, syscall.O_CREAT|syscall.O_RDWR|syscall.O_APPEND, 0666)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "Error opening log file: %v\n", err)
+		} else {
+			logOutput = f
+		}
+	}
+
+	return hclog.NewInterceptLogger(&hclog.LoggerOptions{
+		Name:              name,
+		Level:             logLevel,
+		Output:            logOutput,
+		IndependentLevels: true,
+		JSONFormat:        json,
+	})
+}
+
+// NewLogger returns a new logger based in the current global logger, with the
+// given name appended.
+func NewLogger(name string) hclog.Logger {
+	if name == "" {
+		panic("logger name required")
+	}
+	return &logPanicWrapper{
+		Logger: logger.Named(name),
+	}
+}
+
+// NewProviderLogger returns a logger for the provider plugin, possibly with a
+// different log level from the global logger.
+func NewProviderLogger(prefix string) hclog.Logger {
+	l := &logPanicWrapper{
+		Logger: logger.Named(prefix + "provider"),
+	}
+
+	level := providerLogLevel()
+	logger.Debug("created provider logger", "level", level)
+
+	l.SetLevel(level)
+	return l
+}
+
+// CurrentLogLevel returns the current log level string based the environment vars
+func CurrentLogLevel() string {
+	ll, _ := globalLogLevel()
+	return strings.ToUpper(ll.String())
+}
+
+func providerLogLevel() hclog.Level {
+	providerEnvLevel := strings.ToUpper(os.Getenv(envLogProvider))
+	if providerEnvLevel == "" {
+		providerEnvLevel = strings.ToUpper(os.Getenv(envLog))
+	}
+
+	return parseLogLevel(providerEnvLevel)
+}
+
+func globalLogLevel() (hclog.Level, bool) {
+	var json bool
+	envLevel := strings.ToUpper(os.Getenv(envLog))
+	if envLevel == "" {
+		envLevel = strings.ToUpper(os.Getenv(envLogCore))
+	}
+	if envLevel == "JSON" {
+		json = true
+	}
+	return parseLogLevel(envLevel), json
+}
+
+func parseLogLevel(envLevel string) hclog.Level {
+	if envLevel == "" {
+		return hclog.Off
+	}
+	if envLevel == "JSON" {
+		envLevel = "TRACE"
+	}
+
+	logLevel := hclog.Trace
+	if isValidLogLevel(envLevel) {
+		logLevel = hclog.LevelFromString(envLevel)
+	} else {
+		fmt.Fprintf(os.Stderr, "[WARN] Invalid log level: %q. Defaulting to level: TRACE. Valid levels are: %+v",
+			envLevel, ValidLevels)
+	}
+
+	return logLevel
+}
+
+// IsDebugOrHigher returns whether or not the current log level is debug or trace
+func IsDebugOrHigher() bool {
+	level, _ := globalLogLevel()
+	return level == hclog.Debug || level == hclog.Trace
+}
+
+func isValidLogLevel(level string) bool {
+	for _, l := range ValidLevels {
+		if level == string(l) {
+			return true
+		}
+	}
+
+	return false
+}
+
+// PluginOutputMonitor creates an io.Writer that will warn about any writes in
+// the default logger. This is used to catch unexpected output from plugins,
+// notifying them about the problem as well as surfacing the lost data for
+// context.
+func PluginOutputMonitor(source string) io.Writer {
+	return pluginOutputMonitor{
+		source: source,
+		log:    logger,
+	}
+}
+
+// pluginOutputMonitor is an io.Writer that logs all writes as
+// "unexpected data" with the source name.
+type pluginOutputMonitor struct {
+	source string
+	log    hclog.Logger
+}
+
+func (w pluginOutputMonitor) Write(d []byte) (int, error) {
+	// Limit the write size to 1024 bytes We're not expecting any data to come
+	// through this channel, so accidental writes will usually be stray fmt
+	// debugging statements and the like, but we want to provide context to the
+	// provider to indicate what the unexpected data might be.
+	n := len(d)
+	if n > 1024 {
+		d = append(d[:1024], '.', '.', '.')
+	}
+
+	w.log.Warn("unexpected data", w.source, strings.TrimSpace(string(d)))
+	return n, nil
+}
diff --git a/v1.5.7/internal/logging/panic.go b/v1.5.7/internal/logging/panic.go
new file mode 100644
index 0000000..79c81f2
--- /dev/null
+++ b/v1.5.7/internal/logging/panic.go
@@ -0,0 +1,175 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package logging
+
+import (
+	"fmt"
+	"os"
+	"runtime/debug"
+	"strings"
+	"sync"
+
+	"github.com/hashicorp/go-hclog"
+)
+
+// This output is shown if a panic happens.
+const panicOutput = `
+!!!!!!!!!!!!!!!!!!!!!!!!!!! TERRAFORM CRASH !!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+Terraform crashed! This is always indicative of a bug within Terraform.
+Please report the crash with Terraform[1] so that we can fix this.
+
+When reporting bugs, please include your terraform version, the stack trace
+shown below, and any additional information which may help replicate the issue.
+
+[1]: https://github.com/hashicorp/terraform/issues
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!! TERRAFORM CRASH !!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+`
+
+// In case multiple goroutines panic concurrently, ensure only the first one
+// recovered by PanicHandler starts printing.
+var panicMutex sync.Mutex
+
+// PanicHandler is called to recover from an internal panic in Terraform, and
+// augments the standard stack trace with a more user friendly error message.
+// PanicHandler must be called as a defered function, and must be the first
+// defer called at the start of a new goroutine.
+func PanicHandler() {
+	// Have all managed goroutines checkin here, and prevent them from exiting
+	// if there's a panic in progress. While this can't lock the entire runtime
+	// to block progress, we can prevent some cases where Terraform may return
+	// early before the panic has been printed out.
+	panicMutex.Lock()
+	defer panicMutex.Unlock()
+
+	recovered := recover()
+	if recovered == nil {
+		return
+	}
+
+	fmt.Fprint(os.Stderr, panicOutput)
+	fmt.Fprint(os.Stderr, recovered, "\n")
+
+	// When called from a deferred function, debug.PrintStack will include the
+	// full stack from the point of the pending panic.
+	debug.PrintStack()
+
+	// An exit code of 11 keeps us out of the way of the detailed exitcodes
+	// from plan, and also happens to be the same code as SIGSEGV which is
+	// roughly the same type of condition that causes most panics.
+	os.Exit(11)
+}
+
+const pluginPanicOutput = `
+Stack trace from the %[1]s plugin:
+
+%s
+
+Error: The %[1]s plugin crashed!
+
+This is always indicative of a bug within the plugin. It would be immensely
+helpful if you could report the crash with the plugin's maintainers so that it
+can be fixed. The output above should help diagnose the issue.
+`
+
+// PluginPanics returns a series of provider panics that were collected during
+// execution, and formatted for output.
+func PluginPanics() []string {
+	return panics.allPanics()
+}
+
+// panicRecorder provides a registry to check for plugin panics that may have
+// happened when a plugin suddenly terminates.
+type panicRecorder struct {
+	sync.Mutex
+
+	// panics maps the plugin name to the panic output lines received from
+	// the logger.
+	panics map[string][]string
+
+	// maxLines is the max number of lines we'll record after seeing a
+	// panic header. Since this is going to be printed in the UI output, we
+	// don't want to destroy the scrollback. In most cases, the first few lines
+	// of the stack trace is all that are required.
+	maxLines int
+}
+
+// registerPlugin returns an accumulator function which will accept lines of
+// a panic stack trace to collect into an error when requested.
+func (p *panicRecorder) registerPlugin(name string) func(string) {
+	p.Lock()
+	defer p.Unlock()
+
+	// In most cases we shouldn't be starting a plugin if it already
+	// panicked, but clear out previous entries just in case.
+	delete(p.panics, name)
+
+	count := 0
+
+	// this callback is used by the logger to store panic output
+	return func(line string) {
+		p.Lock()
+		defer p.Unlock()
+
+		// stop recording if there are too many lines.
+		if count > p.maxLines {
+			return
+		}
+		count++
+
+		p.panics[name] = append(p.panics[name], line)
+	}
+}
+
+func (p *panicRecorder) allPanics() []string {
+	p.Lock()
+	defer p.Unlock()
+
+	var res []string
+	for name, lines := range p.panics {
+		if len(lines) == 0 {
+			continue
+		}
+
+		res = append(res, fmt.Sprintf(pluginPanicOutput, name, strings.Join(lines, "\n")))
+	}
+	return res
+}
+
+// logPanicWrapper wraps an hclog.Logger and intercepts and records any output
+// that appears to be a panic.
+type logPanicWrapper struct {
+	hclog.Logger
+	panicRecorder func(string)
+	inPanic       bool
+}
+
+// go-plugin will create a new named logger for each plugin binary.
+func (l *logPanicWrapper) Named(name string) hclog.Logger {
+	return &logPanicWrapper{
+		Logger:        l.Logger.Named(name),
+		panicRecorder: panics.registerPlugin(name),
+	}
+}
+
+// we only need to implement Debug, since that is the default output level used
+// by go-plugin when encountering unstructured output on stderr.
+func (l *logPanicWrapper) Debug(msg string, args ...interface{}) {
+	// We don't have access to the binary itself, so guess based on the stderr
+	// output if this is the start of the traceback. An occasional false
+	// positive shouldn't be a big deal, since this is only retrieved after an
+	// error of some sort.
+
+	panicPrefix := strings.HasPrefix(msg, "panic: ") || strings.HasPrefix(msg, "fatal error: ")
+
+	l.inPanic = l.inPanic || panicPrefix
+
+	if l.inPanic && l.panicRecorder != nil {
+		l.panicRecorder(msg)
+	}
+
+	l.Logger.Debug(msg, args...)
+}
diff --git a/v1.5.7/internal/logging/panic_test.go b/v1.5.7/internal/logging/panic_test.go
new file mode 100644
index 0000000..0b34464
--- /dev/null
+++ b/v1.5.7/internal/logging/panic_test.go
@@ -0,0 +1,54 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package logging
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+)
+
+func TestPanicRecorder(t *testing.T) {
+	rec := panics.registerPlugin("test")
+
+	output := []string{
+		"panic: test",
+		"  stack info",
+	}
+
+	for _, line := range output {
+		rec(line)
+	}
+
+	expected := fmt.Sprintf(pluginPanicOutput, "test", strings.Join(output, "\n"))
+
+	res := PluginPanics()
+	if len(res) == 0 {
+		t.Fatal("no output")
+	}
+
+	if res[0] != expected {
+		t.Fatalf("expected: %q\ngot: %q", expected, res[0])
+	}
+}
+
+func TestPanicLimit(t *testing.T) {
+	rec := panics.registerPlugin("test")
+
+	rec("panic: test")
+
+	for i := 0; i < 200; i++ {
+		rec(fmt.Sprintf("LINE: %d", i))
+	}
+
+	res := PluginPanics()
+	// take the extra content into account
+	max := strings.Count(pluginPanicOutput, "\n") + panics.maxLines
+	for _, out := range res {
+		found := strings.Count(out, "\n")
+		if found > max {
+			t.Fatalf("expected no more than %d lines, got: %d", max, found)
+		}
+	}
+}
diff --git a/v1.5.7/internal/modsdir/doc.go b/v1.5.7/internal/modsdir/doc.go
new file mode 100644
index 0000000..63f722b
--- /dev/null
+++ b/v1.5.7/internal/modsdir/doc.go
@@ -0,0 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package modsdir is an internal package containing the model types used to
+// represent the manifest of modules in a local modules cache directory.
+package modsdir
diff --git a/v1.5.7/internal/modsdir/manifest.go b/v1.5.7/internal/modsdir/manifest.go
new file mode 100644
index 0000000..ed4de72
--- /dev/null
+++ b/v1.5.7/internal/modsdir/manifest.go
@@ -0,0 +1,182 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package modsdir
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+
+	version "github.com/hashicorp/go-version"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// Record represents some metadata about an installed module, as part
+// of a ModuleManifest.
+type Record struct {
+	// Key is a unique identifier for this particular module, based on its
+	// position within the static module tree.
+	Key string `json:"Key"`
+
+	// SourceAddr is the source address given for this module in configuration.
+	// This is used only to detect if the source was changed in configuration
+	// since the module was last installed, which means that the installer
+	// must re-install it.
+	//
+	// This should always be the result of calling method String on an
+	// addrs.ModuleSource value, to get a suitably-normalized result.
+	SourceAddr string `json:"Source"`
+
+	// Version is the exact version of the module, which results from parsing
+	// VersionStr. nil for un-versioned modules.
+	Version *version.Version `json:"-"`
+
+	// VersionStr is the version specifier string. This is used only for
+	// serialization in snapshots and should not be accessed or updated
+	// by any other codepaths; use "Version" instead.
+	VersionStr string `json:"Version,omitempty"`
+
+	// Dir is the path to the local directory where the module is installed.
+	Dir string `json:"Dir"`
+}
+
+// Manifest is a map used to keep track of the filesystem locations
+// and other metadata about installed modules.
+//
+// The configuration loader refers to this, while the module installer updates
+// it to reflect any changes to the installed modules.
+type Manifest map[string]Record
+
+func (m Manifest) ModuleKey(path addrs.Module) string {
+	if len(path) == 0 {
+		return ""
+	}
+	return strings.Join([]string(path), ".")
+
+}
+
+// manifestSnapshotFile is an internal struct used only to assist in our JSON
+// serialization of manifest snapshots. It should not be used for any other
+// purpose.
+type manifestSnapshotFile struct {
+	Records []Record `json:"Modules"`
+}
+
+func ReadManifestSnapshot(r io.Reader) (Manifest, error) {
+	src, err := ioutil.ReadAll(r)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(src) == 0 {
+		// This should never happen, but we'll tolerate it as if it were
+		// a valid empty JSON object.
+		return make(Manifest), nil
+	}
+
+	var read manifestSnapshotFile
+	err = json.Unmarshal(src, &read)
+	if err != nil {
+		return nil, fmt.Errorf("error unmarshalling snapshot: %v", err)
+	}
+	new := make(Manifest)
+	for _, record := range read.Records {
+		if record.VersionStr != "" {
+			record.Version, err = version.NewVersion(record.VersionStr)
+			if err != nil {
+				return nil, fmt.Errorf("invalid version %q for %s: %s", record.VersionStr, record.Key, err)
+			}
+		}
+
+		// Historically we didn't normalize the module source addresses when
+		// writing them into the manifest, and so we'll make a best effort
+		// to normalize them back in on read so that we can just gracefully
+		// upgrade on the next "terraform init".
+		if record.SourceAddr != "" {
+			if addr, err := addrs.ParseModuleSource(record.SourceAddr); err == nil {
+				// This is a best effort sort of thing. If the source
+				// address isn't valid then we'll just leave it as-is
+				// and let another component detect that downstream,
+				// to preserve the old behavior in that case.
+				record.SourceAddr = addr.String()
+			}
+		}
+
+		// Ensure Windows is using the proper modules path format after
+		// reading the modules manifest Dir records
+		record.Dir = filepath.FromSlash(record.Dir)
+
+		if _, exists := new[record.Key]; exists {
+			// This should never happen in any valid file, so we'll catch it
+			// and report it to avoid confusing/undefined behavior if the
+			// snapshot file was edited incorrectly outside of Terraform.
+			return nil, fmt.Errorf("snapshot file contains two records for path %s", record.Key)
+		}
+		new[record.Key] = record
+	}
+	return new, nil
+}
+
+func ReadManifestSnapshotForDir(dir string) (Manifest, error) {
+	fn := filepath.Join(dir, ManifestSnapshotFilename)
+	r, err := os.Open(fn)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return make(Manifest), nil // missing file is okay and treated as empty
+		}
+		return nil, err
+	}
+	return ReadManifestSnapshot(r)
+}
+
+func (m Manifest) WriteSnapshot(w io.Writer) error {
+	var write manifestSnapshotFile
+
+	var keys []string
+	for k := range m {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+	for _, k := range keys {
+		record := m[k]
+
+		// Make sure VersionStr is in sync with Version, since we encourage
+		// callers to manipulate Version and ignore VersionStr.
+		if record.Version != nil {
+			record.VersionStr = record.Version.String()
+		} else {
+			record.VersionStr = ""
+		}
+
+		// Ensure Dir is written in a format that can be read by Linux and
+		// Windows nodes for remote and apply compatibility
+		record.Dir = filepath.ToSlash(record.Dir)
+		write.Records = append(write.Records, record)
+	}
+
+	src, err := json.Marshal(write)
+	if err != nil {
+		return err
+	}
+
+	_, err = w.Write(src)
+	return err
+}
+
+func (m Manifest) WriteSnapshotToDir(dir string) error {
+	fn := filepath.Join(dir, ManifestSnapshotFilename)
+	log.Printf("[TRACE] modsdir: writing modules manifest to %s", fn)
+	w, err := os.Create(fn)
+	if err != nil {
+		return err
+	}
+	return m.WriteSnapshot(w)
+}
diff --git a/v1.5.7/internal/modsdir/paths.go b/v1.5.7/internal/modsdir/paths.go
new file mode 100644
index 0000000..0352ca2
--- /dev/null
+++ b/v1.5.7/internal/modsdir/paths.go
@@ -0,0 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package modsdir
+
+const ManifestSnapshotFilename = "modules.json"
diff --git a/v1.5.7/internal/moduledeps/dependencies.go b/v1.5.7/internal/moduledeps/dependencies.go
new file mode 100644
index 0000000..49e6adb
--- /dev/null
+++ b/v1.5.7/internal/moduledeps/dependencies.go
@@ -0,0 +1,47 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package moduledeps
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plugin/discovery"
+)
+
+// Providers describes a set of provider dependencies for a given module.
+//
+// Each named provider instance can have one version constraint.
+type Providers map[addrs.Provider]ProviderDependency
+
+// ProviderDependency describes the dependency for a particular provider
+// instance, including both the set of allowed versions and the reason for
+// the dependency.
+type ProviderDependency struct {
+	Constraints discovery.Constraints
+	Reason      ProviderDependencyReason
+}
+
+// ProviderDependencyReason is an enumeration of reasons why a dependency might be
+// present.
+type ProviderDependencyReason int
+
+const (
+	// ProviderDependencyExplicit means that there is an explicit "provider"
+	// block in the configuration for this module.
+	ProviderDependencyExplicit ProviderDependencyReason = iota
+
+	// ProviderDependencyImplicit means that there is no explicit "provider"
+	// block but there is at least one resource that uses this provider.
+	ProviderDependencyImplicit
+
+	// ProviderDependencyInherited is a special case of
+	// ProviderDependencyImplicit where a parent module has defined a
+	// configuration for the provider that has been inherited by at least one
+	// resource in this module.
+	ProviderDependencyInherited
+
+	// ProviderDependencyFromState means that this provider is not currently
+	// referenced by configuration at all, but some existing instances in
+	// the state still depend on it.
+	ProviderDependencyFromState
+)
diff --git a/v1.5.7/internal/moduledeps/doc.go b/v1.5.7/internal/moduledeps/doc.go
new file mode 100644
index 0000000..c1a0748
--- /dev/null
+++ b/v1.5.7/internal/moduledeps/doc.go
@@ -0,0 +1,10 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package moduledeps contains types that can be used to describe the
+// providers required for all of the modules in a module tree.
+//
+// It does not itself contain the functionality for populating such
+// data structures; that's in Terraform core, since this package intentionally
+// does not depend on terraform core to avoid package dependency cycles.
+package moduledeps
diff --git a/v1.5.7/internal/moduledeps/module.go b/v1.5.7/internal/moduledeps/module.go
new file mode 100644
index 0000000..b8cbac3
--- /dev/null
+++ b/v1.5.7/internal/moduledeps/module.go
@@ -0,0 +1,202 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package moduledeps
+
+import (
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/plugin/discovery"
+)
+
+// Module represents the dependencies of a single module, as well being
+// a node in a tree of such structures representing the dependencies of
+// an entire configuration.
+type Module struct {
+	Name      string
+	Providers Providers
+	Children  []*Module
+}
+
+// WalkFunc is a callback type for use with Module.WalkTree
+type WalkFunc func(path []string, parent *Module, current *Module) error
+
+// WalkTree calls the given callback once for the receiver and then
+// once for each descendent, in an order such that parents are called
+// before their children and siblings are called in the order they
+// appear in the Children slice.
+//
+// When calling the callback, parent will be nil for the first call
+// for the receiving module, and then set to the direct parent of
+// each module for the subsequent calls.
+//
+// The path given to the callback is valid only until the callback
+// returns, after which it will be mutated and reused. Callbacks must
+// therefore copy the path slice if they wish to retain it.
+//
+// If the given callback returns an error, the walk will be aborted at
+// that point and that error returned to the caller.
+//
+// This function is not thread-safe for concurrent modifications of the
+// data structure, so it's the caller's responsibility to arrange for that
+// should it be needed.
+//
+// It is safe for a callback to modify the descendents of the "current"
+// module, including the ordering of the Children slice itself, but the
+// callback MUST NOT modify the parent module.
+func (m *Module) WalkTree(cb WalkFunc) error {
+	return walkModuleTree(make([]string, 0, 1), nil, m, cb)
+}
+
+func walkModuleTree(path []string, parent *Module, current *Module, cb WalkFunc) error {
+	path = append(path, current.Name)
+	err := cb(path, parent, current)
+	if err != nil {
+		return err
+	}
+
+	for _, child := range current.Children {
+		err := walkModuleTree(path, current, child, cb)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// SortChildren sorts the Children slice into lexicographic order by
+// name, in-place.
+//
+// This is primarily useful prior to calling WalkTree so that the walk
+// will proceed in a consistent order.
+func (m *Module) SortChildren() {
+	sort.Sort(sortModules{m.Children})
+}
+
+// SortDescendents is a convenience wrapper for calling SortChildren on
+// the receiver and all of its descendent modules.
+func (m *Module) SortDescendents() {
+	m.WalkTree(func(path []string, parent *Module, current *Module) error {
+		current.SortChildren()
+		return nil
+	})
+}
+
+type sortModules struct {
+	modules []*Module
+}
+
+func (s sortModules) Len() int {
+	return len(s.modules)
+}
+
+func (s sortModules) Less(i, j int) bool {
+	cmp := strings.Compare(s.modules[i].Name, s.modules[j].Name)
+	return cmp < 0
+}
+
+func (s sortModules) Swap(i, j int) {
+	s.modules[i], s.modules[j] = s.modules[j], s.modules[i]
+}
+
+// ProviderRequirements produces a PluginRequirements structure that can
+// be used with discovery.PluginMetaSet.ConstrainVersions to identify
+// suitable plugins to satisfy the module's provider dependencies.
+//
+// This method only considers the direct requirements of the receiver.
+// Use AllPluginRequirements to flatten the dependencies for the
+// entire tree of modules.
+//
+// Requirements returned by this method include only version constraints,
+// and apply no particular SHA256 hash constraint.
+func (m *Module) ProviderRequirements() discovery.PluginRequirements {
+	ret := make(discovery.PluginRequirements)
+	for pFqn, dep := range m.Providers {
+		providerType := pFqn.Type
+		if existing, exists := ret[providerType]; exists {
+			ret[providerType].Versions = existing.Versions.Append(dep.Constraints)
+		} else {
+			ret[providerType] = &discovery.PluginConstraints{
+				Versions: dep.Constraints,
+			}
+		}
+	}
+	return ret
+}
+
+// AllProviderRequirements calls ProviderRequirements for the receiver and all
+// of its descendents, and merges the result into a single PluginRequirements
+// structure that would satisfy all of the modules together.
+//
+// Requirements returned by this method include only version constraints,
+// and apply no particular SHA256 hash constraint.
+func (m *Module) AllProviderRequirements() discovery.PluginRequirements {
+	var ret discovery.PluginRequirements
+	m.WalkTree(func(path []string, parent *Module, current *Module) error {
+		ret = ret.Merge(current.ProviderRequirements())
+		return nil
+	})
+	return ret
+}
+
+// Equal returns true if the receiver is the root of an identical tree
+// to the other given Module. This is a deep comparison that considers
+// the equality of all downstream modules too.
+//
+// The children are considered to be ordered, so callers may wish to use
+// SortDescendents first to normalize the order of the slices of child nodes.
+//
+// The implementation of this function is not optimized since it is provided
+// primarily for use in tests.
+func (m *Module) Equal(other *Module) bool {
+	// take care of nils first
+	if m == nil && other == nil {
+		return true
+	} else if (m == nil && other != nil) || (m != nil && other == nil) {
+		return false
+	}
+
+	if m.Name != other.Name {
+		return false
+	}
+
+	if len(m.Providers) != len(other.Providers) {
+		return false
+	}
+	if len(m.Children) != len(other.Children) {
+		return false
+	}
+
+	// Can't use reflect.DeepEqual on this provider structure because
+	// the nested Constraints objects contain function pointers that
+	// never compare as equal. So we'll need to walk it the long way.
+	for inst, dep := range m.Providers {
+		if _, exists := other.Providers[inst]; !exists {
+			return false
+		}
+
+		if dep.Reason != other.Providers[inst].Reason {
+			return false
+		}
+
+		// Constraints are not too easy to compare robustly, so
+		// we'll just use their string representations as a proxy
+		// for now.
+		if dep.Constraints.String() != other.Providers[inst].Constraints.String() {
+			return false
+		}
+	}
+
+	// Above we already checked that we have the same number of children
+	// in each module, so now we just need to check that they are
+	// recursively equal.
+	for i := range m.Children {
+		if !m.Children[i].Equal(other.Children[i]) {
+			return false
+		}
+	}
+
+	// If we fall out here then they are equal
+	return true
+}
diff --git a/v1.5.7/internal/moduledeps/module_test.go b/v1.5.7/internal/moduledeps/module_test.go
new file mode 100644
index 0000000..cfa532c
--- /dev/null
+++ b/v1.5.7/internal/moduledeps/module_test.go
@@ -0,0 +1,217 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package moduledeps
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plugin/discovery"
+)
+
+func TestModuleWalkTree(t *testing.T) {
+	type walkStep struct {
+		Path       []string
+		ParentName string
+	}
+
+	tests := []struct {
+		Root      *Module
+		WalkOrder []walkStep
+	}{
+		{
+			&Module{
+				Name:     "root",
+				Children: nil,
+			},
+			[]walkStep{
+				{
+					Path:       []string{"root"},
+					ParentName: "",
+				},
+			},
+		},
+		{
+			&Module{
+				Name: "root",
+				Children: []*Module{
+					{
+						Name: "child",
+					},
+				},
+			},
+			[]walkStep{
+				{
+					Path:       []string{"root"},
+					ParentName: "",
+				},
+				{
+					Path:       []string{"root", "child"},
+					ParentName: "root",
+				},
+			},
+		},
+		{
+			&Module{
+				Name: "root",
+				Children: []*Module{
+					{
+						Name: "child",
+						Children: []*Module{
+							{
+								Name: "grandchild",
+							},
+						},
+					},
+				},
+			},
+			[]walkStep{
+				{
+					Path:       []string{"root"},
+					ParentName: "",
+				},
+				{
+					Path:       []string{"root", "child"},
+					ParentName: "root",
+				},
+				{
+					Path:       []string{"root", "child", "grandchild"},
+					ParentName: "child",
+				},
+			},
+		},
+		{
+			&Module{
+				Name: "root",
+				Children: []*Module{
+					{
+						Name: "child1",
+						Children: []*Module{
+							{
+								Name: "grandchild1",
+							},
+						},
+					},
+					{
+						Name: "child2",
+						Children: []*Module{
+							{
+								Name: "grandchild2",
+							},
+						},
+					},
+				},
+			},
+			[]walkStep{
+				{
+					Path:       []string{"root"},
+					ParentName: "",
+				},
+				{
+					Path:       []string{"root", "child1"},
+					ParentName: "root",
+				},
+				{
+					Path:       []string{"root", "child1", "grandchild1"},
+					ParentName: "child1",
+				},
+				{
+					Path:       []string{"root", "child2"},
+					ParentName: "root",
+				},
+				{
+					Path:       []string{"root", "child2", "grandchild2"},
+					ParentName: "child2",
+				},
+			},
+		},
+	}
+
+	for i, test := range tests {
+		t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
+			wo := test.WalkOrder
+			test.Root.WalkTree(func(path []string, parent *Module, current *Module) error {
+				if len(wo) == 0 {
+					t.Fatalf("ran out of walk steps while expecting one for %#v", path)
+				}
+				step := wo[0]
+				wo = wo[1:]
+				if got, want := path, step.Path; !reflect.DeepEqual(got, want) {
+					t.Errorf("wrong path %#v; want %#v", got, want)
+				}
+				parentName := ""
+				if parent != nil {
+					parentName = parent.Name
+				}
+				if got, want := parentName, step.ParentName; got != want {
+					t.Errorf("wrong parent name %q; want %q", got, want)
+				}
+
+				if got, want := current.Name, path[len(path)-1]; got != want {
+					t.Errorf("mismatching current.Name %q and final path element %q", got, want)
+				}
+				return nil
+			})
+		})
+	}
+}
+
+func TestModuleSortChildren(t *testing.T) {
+	m := &Module{
+		Name: "root",
+		Children: []*Module{
+			{
+				Name: "apple",
+			},
+			{
+				Name: "zebra",
+			},
+			{
+				Name: "xylophone",
+			},
+			{
+				Name: "pig",
+			},
+		},
+	}
+
+	m.SortChildren()
+
+	want := []string{"apple", "pig", "xylophone", "zebra"}
+	var got []string
+	for _, c := range m.Children {
+		got = append(got, c.Name)
+	}
+
+	if !reflect.DeepEqual(want, got) {
+		t.Errorf("wrong order %#v; want %#v", want, got)
+	}
+}
+
+func TestModuleProviderRequirements(t *testing.T) {
+	m := &Module{
+		Name: "root",
+		Providers: Providers{
+			addrs.NewDefaultProvider("foo"): ProviderDependency{
+				Constraints: discovery.ConstraintStr(">=1.0.0").MustParse(),
+			},
+			addrs.NewDefaultProvider("baz"): ProviderDependency{
+				Constraints: discovery.ConstraintStr(">=3.0.0").MustParse(),
+			},
+		},
+	}
+
+	reqd := m.ProviderRequirements()
+	if len(reqd) != 2 {
+		t.Errorf("wrong number of elements in %#v; want 2", reqd)
+	}
+	if got, want := reqd["foo"].Versions.String(), ">=1.0.0"; got != want {
+		t.Errorf("wrong combination of versions for 'foo' %q; want %q", got, want)
+	}
+	if got, want := reqd["baz"].Versions.String(), ">=3.0.0"; got != want {
+		t.Errorf("wrong combination of versions for 'baz' %q; want %q", got, want)
+	}
+}
diff --git a/v1.5.7/internal/moduletest/assertion.go b/v1.5.7/internal/moduletest/assertion.go
new file mode 100644
index 0000000..8dae966
--- /dev/null
+++ b/v1.5.7/internal/moduletest/assertion.go
@@ -0,0 +1,69 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package moduletest
+
+import (
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Assertion is the description of a single test assertion, whether
+// successful or unsuccessful.
+type Assertion struct {
+	Outcome Status
+
+	// Description is a user-provided, human-readable description of what
+	// this assertion represents.
+	Description string
+
+	// Message is typically relevant only for TestFailed or TestError
+	// assertions, giving a human-readable description of the problem,
+	// formatted in the way our format package expects to receive paragraphs
+	// for terminal word wrapping.
+	Message string
+
+	// Diagnostics includes diagnostics specific to the current test assertion,
+	// if available.
+	Diagnostics tfdiags.Diagnostics
+}
+
+// Component represents a component being tested, each of which can have
+// several associated test assertions.
+type Component struct {
+	Assertions map[string]*Assertion
+}
+
+// Status is an enumeration of possible outcomes of a test assertion.
+type Status rune
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=Status assertion.go
+
+const (
+	// Pending indicates that the test was registered (during planning)
+	// but didn't register an outcome during apply, perhaps due to being
+	// blocked by some other upstream failure.
+	Pending Status = '?'
+
+	// Passed indicates that the test condition succeeded.
+	Passed Status = 'P'
+
+	// Failed indicates that the test condition was valid but did not
+	// succeed.
+	Failed Status = 'F'
+
+	// Error indicates that the test condition was invalid or that the
+	// test report failed in some other way.
+	Error Status = 'E'
+)
+
+// SuiteCanPass returns true if a suite containing an assertion with this
+// status could possibly succeed. The suite as a whole succeeds only if all
+// of its assertions have statuses where SuiteCanPass returns true.
+func (s Status) SuiteCanPass() bool {
+	switch s {
+	case Failed, Error:
+		return false
+	default:
+		return true
+	}
+}
diff --git a/v1.5.7/internal/moduletest/doc.go b/v1.5.7/internal/moduletest/doc.go
new file mode 100644
index 0000000..430004f
--- /dev/null
+++ b/v1.5.7/internal/moduletest/doc.go
@@ -0,0 +1,11 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package moduletest contains the support code for some experimental features
+// we're using to evaluate strategies for having an opinionated approach to
+// testing of Terraform modules.
+//
+// At the moment nothing in this module is considered stable, so any features
+// that are usable by end-users ought to emit experiment warnings saying that
+// everything is subject to change even in patch releases.
+package moduletest
diff --git a/v1.5.7/internal/moduletest/provider.go b/v1.5.7/internal/moduletest/provider.go
new file mode 100644
index 0000000..efc11dd
--- /dev/null
+++ b/v1.5.7/internal/moduletest/provider.go
@@ -0,0 +1,578 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package moduletest
+
+import (
+	"fmt"
+	"log"
+	"sync"
+
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/gocty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/repl"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Provider is an implementation of providers.Interface which we're
+// using as a likely-only-temporary vehicle for research on an opinionated
+// module testing workflow in Terraform.
+//
+// We expose this to configuration as "terraform.io/builtin/test", but
+// any attempt to configure it will emit a warning that it is experimental
+// and likely to change or be removed entirely in future Terraform CLI
+// releases.
+//
+// The testing provider exists to gather up test results during a Terraform
+// apply operation. Its "test_results" managed resource type doesn't have any
+// user-visible effect on its own, but when used in conjunction with the
+// "terraform test" experimental command it is the intermediary that holds
+// the test results while the test runs, so that the test command can then
+// report them.
+//
+// For correct behavior of the assertion tracking, the "terraform test"
+// command must be sure to use the same instance of Provider for both the
+// plan and apply steps, so that the assertions that were planned can still
+// be tracked during apply. For other commands that don't explicitly support
+// test assertions, the provider will still succeed but the assertions data
+// may not be complete if the apply step fails.
+type Provider struct {
+	// components tracks all of the "component" names that have been
+	// used in test assertions resources so far. Each resource must have
+	// a unique component name.
+	components map[string]*Component
+
+	// Must lock mutex in order to interact with the components map, because
+	// test assertions can potentially run concurrently.
+	mutex sync.RWMutex
+}
+
+var _ providers.Interface = (*Provider)(nil)
+
+// NewProvider returns a new instance of the test provider.
+func NewProvider() *Provider {
+	return &Provider{
+		components: make(map[string]*Component),
+	}
+}
+
+// TestResults returns the current record of test results tracked inside the
+// provider.
+//
+// The result is a direct reference to the internal state of the provider,
+// so the caller mustn't modify it nor store it across calls to provider
+// operations.
+func (p *Provider) TestResults() map[string]*Component {
+	return p.components
+}
+
+// Reset returns the recieving provider back to its original state, with no
+// recorded test results.
+//
+// It additionally detaches the instance from any data structure previously
+// returned by method TestResults, freeing the caller from the constraints
+// in its documentation about mutability and storage.
+//
+// For convenience in the presumed common case of resetting as part of
+// capturing the results for storage, this method also returns the result
+// that method TestResults would've returned if called prior to the call
+// to Reset.
+func (p *Provider) Reset() map[string]*Component {
+	p.mutex.Lock()
+	log.Print("[TRACE] moduletest.Provider: Reset")
+	ret := p.components
+	p.components = make(map[string]*Component)
+	p.mutex.Unlock()
+	return ret
+}
+
+// GetProviderSchema returns the complete schema for the provider.
+func (p *Provider) GetProviderSchema() providers.GetProviderSchemaResponse {
+	return providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_assertions": testAssertionsSchema,
+		},
+	}
+}
+
+// ValidateProviderConfig validates the provider configuration.
+func (p *Provider) ValidateProviderConfig(req providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse {
+	// This provider has no configurable settings, so nothing to validate.
+	var res providers.ValidateProviderConfigResponse
+	return res
+}
+
+// ConfigureProvider configures and initializes the provider.
+func (p *Provider) ConfigureProvider(providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
+	// This provider has no configurable settings, but we use the configure
+	// request as an opportunity to generate a warning about it being
+	// experimental.
+	var res providers.ConfigureProviderResponse
+	res.Diagnostics = res.Diagnostics.Append(tfdiags.AttributeValue(
+		tfdiags.Warning,
+		"The test provider is experimental",
+		"The Terraform team is using the test provider (terraform.io/builtin/test) as part of ongoing research about declarative testing of Terraform modules.\n\nThe availability and behavior of this provider is expected to change significantly even in patch releases, so we recommend using this provider only in test configurations and constraining your test configurations to an exact Terraform version.",
+		nil,
+	))
+	return res
+}
+
+// ValidateResourceConfig is used to validate configuration values for a resource.
+func (p *Provider) ValidateResourceConfig(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+	log.Print("[TRACE] moduletest.Provider: ValidateResourceConfig")
+
+	var res providers.ValidateResourceConfigResponse
+	if req.TypeName != "test_assertions" { // we only have one resource type
+		res.Diagnostics = res.Diagnostics.Append(fmt.Errorf("unsupported resource type %s", req.TypeName))
+		return res
+	}
+
+	config := req.Config
+	if !config.GetAttr("component").IsKnown() {
+		res.Diagnostics = res.Diagnostics.Append(tfdiags.AttributeValue(
+			tfdiags.Error,
+			"Invalid component expression",
+			"The component name must be a static value given in the configuration, and may not be derived from a resource type attribute that will only be known during the apply step.",
+			cty.GetAttrPath("component"),
+		))
+	}
+	if !hclsyntax.ValidIdentifier(config.GetAttr("component").AsString()) {
+		res.Diagnostics = res.Diagnostics.Append(tfdiags.AttributeValue(
+			tfdiags.Error,
+			"Invalid component name",
+			"The component name must be a valid identifier, starting with a letter followed by zero or more letters, digits, and underscores.",
+			cty.GetAttrPath("component"),
+		))
+	}
+	for it := config.GetAttr("equal").ElementIterator(); it.Next(); {
+		k, obj := it.Element()
+		if !hclsyntax.ValidIdentifier(k.AsString()) {
+			res.Diagnostics = res.Diagnostics.Append(tfdiags.AttributeValue(
+				tfdiags.Error,
+				"Invalid assertion name",
+				"An assertion name must be a valid identifier, starting with a letter followed by zero or more letters, digits, and underscores.",
+				cty.GetAttrPath("equal").Index(k),
+			))
+		}
+		if !obj.GetAttr("description").IsKnown() {
+			res.Diagnostics = res.Diagnostics.Append(tfdiags.AttributeValue(
+				tfdiags.Error,
+				"Invalid description expression",
+				"The description must be a static value given in the configuration, and may not be derived from a resource type attribute that will only be known during the apply step.",
+				cty.GetAttrPath("equal").Index(k).GetAttr("description"),
+			))
+		}
+	}
+	for it := config.GetAttr("check").ElementIterator(); it.Next(); {
+		k, obj := it.Element()
+		if !hclsyntax.ValidIdentifier(k.AsString()) {
+			res.Diagnostics = res.Diagnostics.Append(tfdiags.AttributeValue(
+				tfdiags.Error,
+				"Invalid assertion name",
+				"An assertion name must be a valid identifier, starting with a letter followed by zero or more letters, digits, and underscores.",
+				cty.GetAttrPath("check").Index(k),
+			))
+		}
+		if !obj.GetAttr("description").IsKnown() {
+			res.Diagnostics = res.Diagnostics.Append(tfdiags.AttributeValue(
+				tfdiags.Error,
+				"Invalid description expression",
+				"The description must be a static value given in the configuration, and may not be derived from a resource type attribute that will only be known during the apply step.",
+				cty.GetAttrPath("equal").Index(k).GetAttr("description"),
+			))
+		}
+	}
+
+	return res
+}
+
+// ReadResource refreshes a resource and returns its current state.
+func (p *Provider) ReadResource(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+	log.Print("[TRACE] moduletest.Provider: ReadResource")
+
+	var res providers.ReadResourceResponse
+	if req.TypeName != "test_assertions" { // we only have one resource type
+		res.Diagnostics = res.Diagnostics.Append(fmt.Errorf("unsupported resource type %s", req.TypeName))
+		return res
+	}
+	// Test assertions are not a real remote object, so there isn't actually
+	// anything to refresh here.
+	res.NewState = req.PriorState
+	return res
+}
+
+// UpgradeResourceState is called to allow the provider to adapt the raw value
+// stored in the state in case the schema has changed since it was originally
+// written.
+func (p *Provider) UpgradeResourceState(req providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse {
+	log.Print("[TRACE] moduletest.Provider: UpgradeResourceState")
+
+	var res providers.UpgradeResourceStateResponse
+	if req.TypeName != "test_assertions" { // we only have one resource type
+		res.Diagnostics = res.Diagnostics.Append(fmt.Errorf("unsupported resource type %s", req.TypeName))
+		return res
+	}
+
+	// We assume here that there can never be a flatmap version of this
+	// resource type's data, because this provider was never included in a
+	// version of Terraform that used flatmap and this provider's schema
+	// contains attributes that are not flatmap-compatible anyway.
+	if len(req.RawStateFlatmap) != 0 {
+		res.Diagnostics = res.Diagnostics.Append(fmt.Errorf("can't upgrade a flatmap state for %q", req.TypeName))
+		return res
+	}
+	if req.Version != 0 {
+		res.Diagnostics = res.Diagnostics.Append(fmt.Errorf("the state for this %s was created by a newer version of the provider", req.TypeName))
+		return res
+	}
+
+	v, err := ctyjson.Unmarshal(req.RawStateJSON, testAssertionsSchema.Block.ImpliedType())
+	if err != nil {
+		res.Diagnostics = res.Diagnostics.Append(fmt.Errorf("failed to decode state for %s: %s", req.TypeName, err))
+		return res
+	}
+
+	res.UpgradedState = v
+	return res
+}
+
+// PlanResourceChange takes the current state and proposed state of a
+// resource, and returns the planned final state.
+func (p *Provider) PlanResourceChange(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+	log.Print("[TRACE] moduletest.Provider: PlanResourceChange")
+
+	// this is a destroy plan,
+	if req.ProposedNewState.IsNull() {
+		resp.PlannedState = req.ProposedNewState
+		resp.PlannedPrivate = req.PriorPrivate
+		return resp
+	}
+
+	var res providers.PlanResourceChangeResponse
+	if req.TypeName != "test_assertions" { // we only have one resource type
+		res.Diagnostics = res.Diagnostics.Append(fmt.Errorf("unsupported resource type %s", req.TypeName))
+		return res
+	}
+
+	// During planning, our job is to gather up all of the planned test
+	// assertions marked as pending, which will then allow us to include
+	// all of them in test results even if there's a failure during apply
+	// that prevents the full completion of the graph walk.
+	//
+	// In a sense our plan phase is similar to the compile step for a
+	// test program written in another language. Planning itself can fail,
+	// which means we won't be able to form a complete test plan at all,
+	// but if we succeed in planning then subsequent problems can be treated
+	// as test failures at "runtime", while still keeping a full manifest
+	// of all of the tests that ought to have run if the apply had run to
+	// completion.
+
+	proposed := req.ProposedNewState
+	res.PlannedState = proposed
+	componentName := proposed.GetAttr("component").AsString() // proven known during validate
+	p.mutex.Lock()
+	defer p.mutex.Unlock()
+	// NOTE: Ideally we'd do something here to verify if two assertions
+	// resources in the configuration attempt to declare the same component,
+	// but we can't actually do that because Terraform calls PlanResourceChange
+	// during both plan and apply, and so the second one would always fail.
+	// Since this is just providing a temporary pseudo-syntax for writing tests
+	// anyway, we'll live with this for now and aim to solve it with a future
+	// iteration of testing that's better integrated into the Terraform
+	// language.
+	/*
+		if _, exists := p.components[componentName]; exists {
+			res.Diagnostics = res.Diagnostics.Append(tfdiags.AttributeValue(
+				tfdiags.Error,
+				"Duplicate test component",
+				fmt.Sprintf("Another test_assertions resource already declared assertions for the component name %q.", componentName),
+				cty.GetAttrPath("component"),
+			))
+			return res
+		}
+	*/
+
+	component := Component{
+		Assertions: make(map[string]*Assertion),
+	}
+
+	for it := proposed.GetAttr("equal").ElementIterator(); it.Next(); {
+		k, obj := it.Element()
+		name := k.AsString()
+		if _, exists := component.Assertions[name]; exists {
+			// We can't actually get here in practice because so far we've
+			// only been pulling keys from one map, and so any duplicates
+			// would've been caught during config decoding, but this is here
+			// just to make these two blocks symmetrical to avoid mishaps in
+			// future refactoring/reorganization.
+			res.Diagnostics = res.Diagnostics.Append(tfdiags.AttributeValue(
+				tfdiags.Error,
+				"Duplicate test assertion",
+				fmt.Sprintf("Another assertion block in this resource already declared an assertion named %q.", name),
+				cty.GetAttrPath("equal").Index(k),
+			))
+			continue
+		}
+
+		var desc string
+		descVal := obj.GetAttr("description")
+		if descVal.IsNull() {
+			descVal = cty.StringVal("")
+		}
+		err := gocty.FromCtyValue(descVal, &desc)
+		if err != nil {
+			// We shouldn't get here because we've already validated everything
+			// that would make FromCtyValue fail above and during validate.
+			res.Diagnostics = res.Diagnostics.Append(err)
+		}
+
+		component.Assertions[name] = &Assertion{
+			Outcome:     Pending,
+			Description: desc,
+		}
+	}
+
+	for it := proposed.GetAttr("check").ElementIterator(); it.Next(); {
+		k, obj := it.Element()
+		name := k.AsString()
+		if _, exists := component.Assertions[name]; exists {
+			res.Diagnostics = res.Diagnostics.Append(tfdiags.AttributeValue(
+				tfdiags.Error,
+				"Duplicate test assertion",
+				fmt.Sprintf("Another assertion block in this resource already declared an assertion named %q.", name),
+				cty.GetAttrPath("check").Index(k),
+			))
+			continue
+		}
+
+		var desc string
+		descVal := obj.GetAttr("description")
+		if descVal.IsNull() {
+			descVal = cty.StringVal("")
+		}
+		err := gocty.FromCtyValue(descVal, &desc)
+		if err != nil {
+			// We shouldn't get here because we've already validated everything
+			// that would make FromCtyValue fail above and during validate.
+			res.Diagnostics = res.Diagnostics.Append(err)
+		}
+
+		component.Assertions[name] = &Assertion{
+			Outcome:     Pending,
+			Description: desc,
+		}
+	}
+
+	p.components[componentName] = &component
+	return res
+}
+
+// ApplyResourceChange takes the planned state for a resource, which may
+// yet contain unknown computed values, and applies the changes returning
+// the final state.
+func (p *Provider) ApplyResourceChange(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+	log.Print("[TRACE] moduletest.Provider: ApplyResourceChange")
+
+	var res providers.ApplyResourceChangeResponse
+	if req.TypeName != "test_assertions" { // we only have one resource type
+		res.Diagnostics = res.Diagnostics.Append(fmt.Errorf("unsupported resource type %s", req.TypeName))
+		return res
+	}
+
+	// During apply we actually check the assertions and record the results.
+	// An assertion failure isn't reflected as an error from the apply call
+	// because if possible we'd like to continue exercising other objects
+	// downstream in case that allows us to gather more information to report.
+	// (If something downstream returns an error then that could prevent us
+	// from completing other assertions, though.)
+
+	planned := req.PlannedState
+	res.NewState = planned
+	if res.NewState.IsNull() {
+		// If we're destroying then we'll just quickly return success to
+		// allow the test process to clean up after itself.
+		return res
+	}
+	componentName := planned.GetAttr("component").AsString() // proven known during validate
+
+	p.mutex.Lock()
+	defer p.mutex.Unlock()
+	component := p.components[componentName]
+	if component == nil {
+		// We might get here when using this provider outside of the
+		// "terraform test" command, where there won't be any mechanism to
+		// preserve the test provider instance between the plan and apply
+		// phases. In that case, we assume that nobody will come looking to
+		// collect the results anyway, and so we can just silently skip
+		// checking.
+		return res
+	}
+
+	for it := planned.GetAttr("equal").ElementIterator(); it.Next(); {
+		k, obj := it.Element()
+		name := k.AsString()
+		var desc string
+		if plan, exists := component.Assertions[name]; exists {
+			desc = plan.Description
+		}
+		assert := &Assertion{
+			Outcome:     Pending,
+			Description: desc,
+		}
+
+		gotVal := obj.GetAttr("got")
+		wantVal := obj.GetAttr("want")
+		switch {
+		case wantVal.RawEquals(gotVal):
+			assert.Outcome = Passed
+			gotStr := repl.FormatValue(gotVal, 4)
+			assert.Message = fmt.Sprintf("correct value\n    got: %s\n", gotStr)
+		default:
+			assert.Outcome = Failed
+			gotStr := repl.FormatValue(gotVal, 4)
+			wantStr := repl.FormatValue(wantVal, 4)
+			assert.Message = fmt.Sprintf("wrong value\n    got:  %s\n    want: %s\n", gotStr, wantStr)
+		}
+
+		component.Assertions[name] = assert
+	}
+
+	for it := planned.GetAttr("check").ElementIterator(); it.Next(); {
+		k, obj := it.Element()
+		name := k.AsString()
+		var desc string
+		if plan, exists := component.Assertions[name]; exists {
+			desc = plan.Description
+		}
+		assert := &Assertion{
+			Outcome:     Pending,
+			Description: desc,
+		}
+
+		condVal := obj.GetAttr("condition")
+		switch {
+		case condVal.IsNull():
+			res.Diagnostics = res.Diagnostics.Append(tfdiags.AttributeValue(
+				tfdiags.Error,
+				"Invalid check condition",
+				"The condition value must be a boolean expression, not null.",
+				cty.GetAttrPath("check").Index(k).GetAttr("condition"),
+			))
+			continue
+		case condVal.True():
+			assert.Outcome = Passed
+			assert.Message = "condition passed"
+		default:
+			assert.Outcome = Failed
+			// For "check" we can't really return a decent error message
+			// because we've lost all of the context by the time we get here.
+			// "equal" will be better for most tests for that reason, and also
+			// this is one reason why in the long run it would be better for
+			// test assertions to be a first-class language feature rather than
+			// just a provider-based concept.
+			assert.Message = "condition failed"
+		}
+
+		component.Assertions[name] = assert
+	}
+
+	return res
+}
+
+// ImportResourceState requests that the given resource be imported.
+func (p *Provider) ImportResourceState(req providers.ImportResourceStateRequest) providers.ImportResourceStateResponse {
+	var res providers.ImportResourceStateResponse
+	res.Diagnostics = res.Diagnostics.Append(fmt.Errorf("%s is not importable", req.TypeName))
+	return res
+}
+
+// ValidateDataResourceConfig is used to to validate the resource configuration values.
+func (p *Provider) ValidateDataResourceConfig(req providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse {
+	// This provider has no data resouce types at all.
+	var res providers.ValidateDataResourceConfigResponse
+	res.Diagnostics = res.Diagnostics.Append(fmt.Errorf("unsupported data source %s", req.TypeName))
+	return res
+}
+
+// ReadDataSource returns the data source's current state.
+func (p *Provider) ReadDataSource(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+	// This provider has no data resouce types at all.
+	var res providers.ReadDataSourceResponse
+	res.Diagnostics = res.Diagnostics.Append(fmt.Errorf("unsupported data source %s", req.TypeName))
+	return res
+}
+
+// Stop is called when the provider should halt any in-flight actions.
+func (p *Provider) Stop() error {
+	// This provider doesn't do anything that can be cancelled.
+	return nil
+}
+
+// Close is a noop for this provider, since it's run in-process.
+func (p *Provider) Close() error {
+	return nil
+}
+
+var testAssertionsSchema = providers.Schema{
+	Block: &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"component": {
+				Type:            cty.String,
+				Description:     "The name of the component being tested. This is just for namespacing assertions in a result report.",
+				DescriptionKind: configschema.StringPlain,
+				Required:        true,
+			},
+		},
+		BlockTypes: map[string]*configschema.NestedBlock{
+			"equal": {
+				Nesting: configschema.NestingMap,
+				Block: configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"description": {
+							Type:            cty.String,
+							Description:     "An optional human-readable description of what's being tested by this assertion.",
+							DescriptionKind: configschema.StringPlain,
+							Required:        true,
+						},
+						"got": {
+							Type:            cty.DynamicPseudoType,
+							Description:     "The actual result value generated by the relevant component.",
+							DescriptionKind: configschema.StringPlain,
+							Required:        true,
+						},
+						"want": {
+							Type:            cty.DynamicPseudoType,
+							Description:     "The value that the component is expected to have generated.",
+							DescriptionKind: configschema.StringPlain,
+							Required:        true,
+						},
+					},
+				},
+			},
+			"check": {
+				Nesting: configschema.NestingMap,
+				Block: configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"description": {
+							Type:            cty.String,
+							Description:     "An optional (but strongly recommended) human-readable description of what's being tested by this assertion.",
+							DescriptionKind: configschema.StringPlain,
+							Required:        true,
+						},
+						"condition": {
+							Type:            cty.Bool,
+							Description:     "An expression that must be true in order for the test to pass.",
+							DescriptionKind: configschema.StringPlain,
+							Required:        true,
+						},
+					},
+				},
+			},
+		},
+	},
+}
diff --git a/v1.5.7/internal/moduletest/provider_test.go b/v1.5.7/internal/moduletest/provider_test.go
new file mode 100644
index 0000000..fa62260
--- /dev/null
+++ b/v1.5.7/internal/moduletest/provider_test.go
@@ -0,0 +1,158 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package moduletest
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/zclconf/go-cty-debug/ctydebug"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestProvider(t *testing.T) {
+
+	assertionConfig := cty.ObjectVal(map[string]cty.Value{
+		"component": cty.StringVal("spline_reticulator"),
+		"equal": cty.MapVal(map[string]cty.Value{
+			"match": cty.ObjectVal(map[string]cty.Value{
+				"description": cty.StringVal("this should match"),
+				"got":         cty.StringVal("a"),
+				"want":        cty.StringVal("a"),
+			}),
+			"unmatch": cty.ObjectVal(map[string]cty.Value{
+				"description": cty.StringVal("this should not match"),
+				"got":         cty.StringVal("a"),
+				"want":        cty.StringVal("b"),
+			}),
+		}),
+		"check": cty.MapVal(map[string]cty.Value{
+			"pass": cty.ObjectVal(map[string]cty.Value{
+				"description": cty.StringVal("this should pass"),
+				"condition":   cty.True,
+			}),
+			"fail": cty.ObjectVal(map[string]cty.Value{
+				"description": cty.StringVal("this should fail"),
+				"condition":   cty.False,
+			}),
+		}),
+	})
+
+	// The provider code expects to receive an object that was decoded from
+	// HCL using the schema, so to make sure we're testing a more realistic
+	// situation here we'll require the config to conform to the schema. If
+	// this fails, it's a bug in the configuration definition above rather
+	// than in the provider itself.
+	for _, err := range assertionConfig.Type().TestConformance(testAssertionsSchema.Block.ImpliedType()) {
+		t.Error(err)
+	}
+
+	p := NewProvider()
+
+	configureResp := p.ConfigureProvider(providers.ConfigureProviderRequest{
+		Config: cty.EmptyObjectVal,
+	})
+	if got, want := len(configureResp.Diagnostics), 1; got != want {
+		t.Fatalf("got %d Configure diagnostics, but want %d", got, want)
+	}
+	if got, want := configureResp.Diagnostics[0].Description().Summary, "The test provider is experimental"; got != want {
+		t.Fatalf("wrong diagnostic message\ngot:  %s\nwant: %s", got, want)
+	}
+
+	validateResp := p.ValidateResourceConfig(providers.ValidateResourceConfigRequest{
+		TypeName: "test_assertions",
+		Config:   assertionConfig,
+	})
+	if got, want := len(validateResp.Diagnostics), 0; got != want {
+		t.Fatalf("got %d ValidateResourceTypeConfig diagnostics, but want %d", got, want)
+	}
+
+	planResp := p.PlanResourceChange(providers.PlanResourceChangeRequest{
+		TypeName:         "test_assertions",
+		Config:           assertionConfig,
+		PriorState:       cty.NullVal(assertionConfig.Type()),
+		ProposedNewState: assertionConfig,
+	})
+	if got, want := len(planResp.Diagnostics), 0; got != want {
+		t.Fatalf("got %d PlanResourceChange diagnostics, but want %d", got, want)
+	}
+	planned := planResp.PlannedState
+	if got, want := planned, assertionConfig; !want.RawEquals(got) {
+		t.Fatalf("wrong planned new value\n%s", ctydebug.DiffValues(want, got))
+	}
+
+	gotComponents := p.TestResults()
+	wantComponents := map[string]*Component{
+		"spline_reticulator": {
+			Assertions: map[string]*Assertion{
+				"pass": {
+					Outcome:     Pending,
+					Description: "this should pass",
+				},
+				"fail": {
+					Outcome:     Pending,
+					Description: "this should fail",
+				},
+				"match": {
+					Outcome:     Pending,
+					Description: "this should match",
+				},
+				"unmatch": {
+					Outcome:     Pending,
+					Description: "this should not match",
+				},
+			},
+		},
+	}
+	if diff := cmp.Diff(wantComponents, gotComponents); diff != "" {
+		t.Fatalf("wrong test results after planning\n%s", diff)
+	}
+
+	applyResp := p.ApplyResourceChange(providers.ApplyResourceChangeRequest{
+		TypeName:     "test_assertions",
+		Config:       assertionConfig,
+		PriorState:   cty.NullVal(assertionConfig.Type()),
+		PlannedState: planned,
+	})
+	if got, want := len(applyResp.Diagnostics), 0; got != want {
+		t.Fatalf("got %d ApplyResourceChange diagnostics, but want %d", got, want)
+	}
+	final := applyResp.NewState
+	if got, want := final, assertionConfig; !want.RawEquals(got) {
+		t.Fatalf("wrong new value\n%s", ctydebug.DiffValues(want, got))
+	}
+
+	gotComponents = p.TestResults()
+	wantComponents = map[string]*Component{
+		"spline_reticulator": {
+			Assertions: map[string]*Assertion{
+				"pass": {
+					Outcome:     Passed,
+					Description: "this should pass",
+					Message:     "condition passed",
+				},
+				"fail": {
+					Outcome:     Failed,
+					Description: "this should fail",
+					Message:     "condition failed",
+				},
+				"match": {
+					Outcome:     Passed,
+					Description: "this should match",
+					Message:     "correct value\n    got: \"a\"\n",
+				},
+				"unmatch": {
+					Outcome:     Failed,
+					Description: "this should not match",
+					Message:     "wrong value\n    got:  \"a\"\n    want: \"b\"\n",
+				},
+			},
+		},
+	}
+	if diff := cmp.Diff(wantComponents, gotComponents); diff != "" {
+		t.Fatalf("wrong test results after applying\n%s", diff)
+	}
+
+}
diff --git a/v1.5.7/internal/moduletest/status_string.go b/v1.5.7/internal/moduletest/status_string.go
new file mode 100644
index 0000000..f224997
--- /dev/null
+++ b/v1.5.7/internal/moduletest/status_string.go
@@ -0,0 +1,39 @@
+// Code generated by "stringer -type=Status assertion.go"; DO NOT EDIT.
+
+package moduletest
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[Pending-63]
+	_ = x[Passed-80]
+	_ = x[Failed-70]
+	_ = x[Error-69]
+}
+
+const (
+	_Status_name_0 = "Pending"
+	_Status_name_1 = "ErrorFailed"
+	_Status_name_2 = "Passed"
+)
+
+var (
+	_Status_index_1 = [...]uint8{0, 5, 11}
+)
+
+func (i Status) String() string {
+	switch {
+	case i == 63:
+		return _Status_name_0
+	case 69 <= i && i <= 70:
+		i -= 69
+		return _Status_name_1[_Status_index_1[i]:_Status_index_1[i+1]]
+	case i == 80:
+		return _Status_name_2
+	default:
+		return "Status(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/v1.5.7/internal/moduletest/suite.go b/v1.5.7/internal/moduletest/suite.go
new file mode 100644
index 0000000..5177c45
--- /dev/null
+++ b/v1.5.7/internal/moduletest/suite.go
@@ -0,0 +1,10 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package moduletest
+
+// A Suite is a set of tests run together as a single Terraform configuration.
+type Suite struct {
+	Name       string
+	Components map[string]*Component
+}
diff --git a/v1.5.7/internal/plans/action.go b/v1.5.7/internal/plans/action.go
new file mode 100644
index 0000000..a27b20f
--- /dev/null
+++ b/v1.5.7/internal/plans/action.go
@@ -0,0 +1,25 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plans
+
+type Action rune
+
+const (
+	NoOp             Action = 0
+	Create           Action = '+'
+	Read             Action = '←'
+	Update           Action = '~'
+	DeleteThenCreate Action = '∓'
+	CreateThenDelete Action = '±'
+	Delete           Action = '-'
+)
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type Action
+
+// IsReplace returns true if the action is one of the two actions that
+// represents replacing an existing object with a new object:
+// DeleteThenCreate or CreateThenDelete.
+func (a Action) IsReplace() bool {
+	return a == DeleteThenCreate || a == CreateThenDelete
+}
diff --git a/v1.5.7/internal/plans/action_string.go b/v1.5.7/internal/plans/action_string.go
new file mode 100644
index 0000000..be43ab1
--- /dev/null
+++ b/v1.5.7/internal/plans/action_string.go
@@ -0,0 +1,49 @@
+// Code generated by "stringer -type Action"; DO NOT EDIT.
+
+package plans
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[NoOp-0]
+	_ = x[Create-43]
+	_ = x[Read-8592]
+	_ = x[Update-126]
+	_ = x[DeleteThenCreate-8723]
+	_ = x[CreateThenDelete-177]
+	_ = x[Delete-45]
+}
+
+const (
+	_Action_name_0 = "NoOp"
+	_Action_name_1 = "Create"
+	_Action_name_2 = "Delete"
+	_Action_name_3 = "Update"
+	_Action_name_4 = "CreateThenDelete"
+	_Action_name_5 = "Read"
+	_Action_name_6 = "DeleteThenCreate"
+)
+
+func (i Action) String() string {
+	switch {
+	case i == 0:
+		return _Action_name_0
+	case i == 43:
+		return _Action_name_1
+	case i == 45:
+		return _Action_name_2
+	case i == 126:
+		return _Action_name_3
+	case i == 177:
+		return _Action_name_4
+	case i == 8592:
+		return _Action_name_5
+	case i == 8723:
+		return _Action_name_6
+	default:
+		return "Action(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/v1.5.7/internal/plans/changes.go b/v1.5.7/internal/plans/changes.go
new file mode 100644
index 0000000..a216fd1
--- /dev/null
+++ b/v1.5.7/internal/plans/changes.go
@@ -0,0 +1,593 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plans
+
+import (
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// Changes describes various actions that Terraform will attempt to take if
+// the corresponding plan is applied.
+//
+// A Changes object can be rendered into a visual diff (by the caller, using
+// code in another package) for display to the user.
+type Changes struct {
+	// Resources tracks planned changes to resource instance objects.
+	Resources []*ResourceInstanceChangeSrc
+
+	// Outputs tracks planned changes output values.
+	//
+	// Note that although an in-memory plan contains planned changes for
+	// outputs throughout the configuration, a plan serialized
+	// to disk retains only the root outputs because they are
+	// externally-visible, while other outputs are implementation details and
+	// can be easily re-calculated during the apply phase. Therefore only root
+	// module outputs will survive a round-trip through a plan file.
+	Outputs []*OutputChangeSrc
+}
+
+// NewChanges returns a valid Changes object that describes no changes.
+func NewChanges() *Changes {
+	return &Changes{}
+}
+
+func (c *Changes) Empty() bool {
+	for _, res := range c.Resources {
+		if res.Action != NoOp || res.Moved() {
+			return false
+		}
+
+		if res.Importing != nil {
+			return false
+		}
+	}
+
+	for _, out := range c.Outputs {
+		if out.Addr.Module.IsRoot() && out.Action != NoOp {
+			return false
+		}
+	}
+
+	return true
+}
+
+// ResourceInstance returns the planned change for the current object of the
+// resource instance of the given address, if any. Returns nil if no change is
+// planned.
+func (c *Changes) ResourceInstance(addr addrs.AbsResourceInstance) *ResourceInstanceChangeSrc {
+	for _, rc := range c.Resources {
+		if rc.Addr.Equal(addr) && rc.DeposedKey == states.NotDeposed {
+			return rc
+		}
+	}
+
+	return nil
+
+}
+
+// InstancesForAbsResource returns the planned change for the current objects
+// of the resource instances of the given address, if any. Returns nil if no
+// changes are planned.
+func (c *Changes) InstancesForAbsResource(addr addrs.AbsResource) []*ResourceInstanceChangeSrc {
+	var changes []*ResourceInstanceChangeSrc
+	for _, rc := range c.Resources {
+		resAddr := rc.Addr.ContainingResource()
+		if resAddr.Equal(addr) && rc.DeposedKey == states.NotDeposed {
+			changes = append(changes, rc)
+		}
+	}
+
+	return changes
+}
+
+// InstancesForConfigResource returns the planned change for the current objects
+// of the resource instances of the given address, if any. Returns nil if no
+// changes are planned.
+func (c *Changes) InstancesForConfigResource(addr addrs.ConfigResource) []*ResourceInstanceChangeSrc {
+	var changes []*ResourceInstanceChangeSrc
+	for _, rc := range c.Resources {
+		resAddr := rc.Addr.ContainingResource().Config()
+		if resAddr.Equal(addr) && rc.DeposedKey == states.NotDeposed {
+			changes = append(changes, rc)
+		}
+	}
+
+	return changes
+}
+
+// ResourceInstanceDeposed returns the plan change of a deposed object of
+// the resource instance of the given address, if any. Returns nil if no change
+// is planned.
+func (c *Changes) ResourceInstanceDeposed(addr addrs.AbsResourceInstance, key states.DeposedKey) *ResourceInstanceChangeSrc {
+	for _, rc := range c.Resources {
+		if rc.Addr.Equal(addr) && rc.DeposedKey == key {
+			return rc
+		}
+	}
+
+	return nil
+}
+
+// OutputValue returns the planned change for the output value with the
+//
+//	given address, if any. Returns nil if no change is planned.
+func (c *Changes) OutputValue(addr addrs.AbsOutputValue) *OutputChangeSrc {
+	for _, oc := range c.Outputs {
+		if oc.Addr.Equal(addr) {
+			return oc
+		}
+	}
+
+	return nil
+}
+
+// RootOutputValues returns planned changes for all outputs of the root module.
+func (c *Changes) RootOutputValues() []*OutputChangeSrc {
+	var res []*OutputChangeSrc
+
+	for _, oc := range c.Outputs {
+		// we can't evaluate root module outputs
+		if !oc.Addr.Module.Equal(addrs.RootModuleInstance) {
+			continue
+		}
+
+		res = append(res, oc)
+
+	}
+
+	return res
+}
+
+// OutputValues returns planned changes for all outputs for all module
+// instances that reside in the parent path.  Returns nil if no changes are
+// planned.
+func (c *Changes) OutputValues(parent addrs.ModuleInstance, module addrs.ModuleCall) []*OutputChangeSrc {
+	var res []*OutputChangeSrc
+
+	for _, oc := range c.Outputs {
+		// we can't evaluate root module outputs
+		if oc.Addr.Module.Equal(addrs.RootModuleInstance) {
+			continue
+		}
+
+		changeMod, changeCall := oc.Addr.Module.Call()
+		// this does not reside on our parent instance path
+		if !changeMod.Equal(parent) {
+			continue
+		}
+
+		// this is not the module you're looking for
+		if changeCall.Name != module.Name {
+			continue
+		}
+
+		res = append(res, oc)
+
+	}
+
+	return res
+}
+
+// SyncWrapper returns a wrapper object around the receiver that can be used
+// to make certain changes to the receiver in a concurrency-safe way, as long
+// as all callers share the same wrapper object.
+func (c *Changes) SyncWrapper() *ChangesSync {
+	return &ChangesSync{
+		changes: c,
+	}
+}
+
+// ResourceInstanceChange describes a change to a particular resource instance
+// object.
+type ResourceInstanceChange struct {
+	// Addr is the absolute address of the resource instance that the change
+	// will apply to.
+	Addr addrs.AbsResourceInstance
+
+	// PrevRunAddr is the absolute address that this resource instance had at
+	// the conclusion of a previous run.
+	//
+	// This will typically be the same as Addr, but can be different if the
+	// previous resource instance was subject to a "moved" block that we
+	// handled in the process of creating this plan.
+	//
+	// For the initial creation of a resource instance there isn't really any
+	// meaningful "previous run address", but PrevRunAddr will still be set
+	// equal to Addr in that case in order to simplify logic elsewhere which
+	// aims to detect and react to the movement of instances between addresses.
+	PrevRunAddr addrs.AbsResourceInstance
+
+	// DeposedKey is the identifier for a deposed object associated with the
+	// given instance, or states.NotDeposed if this change applies to the
+	// current object.
+	//
+	// A Replace change for a resource with create_before_destroy set will
+	// create a new DeposedKey temporarily during replacement. In that case,
+	// DeposedKey in the plan is always states.NotDeposed, representing that
+	// the current object is being replaced with the deposed.
+	DeposedKey states.DeposedKey
+
+	// Provider is the address of the provider configuration that was used
+	// to plan this change, and thus the configuration that must also be
+	// used to apply it.
+	ProviderAddr addrs.AbsProviderConfig
+
+	// Change is an embedded description of the change.
+	Change
+
+	// ActionReason is an optional extra indication of why we chose the
+	// action recorded in Change.Action for this particular resource instance.
+	//
+	// This is an approximate mechanism only for the purpose of explaining the
+	// plan to end-users in the UI and is not to be used for any
+	// decision-making during the apply step; if apply behavior needs to vary
+	// depending on the "action reason" then the information for that decision
+	// must be recorded more precisely elsewhere for that purpose.
+	//
+	// Sometimes there might be more than one reason for choosing a particular
+	// action. In that case, it's up to the codepath making that decision to
+	// decide which value would provide the most relevant explanation to the
+	// end-user and return that. It's not a goal of this field to represent
+	// fine details about the planning process.
+	ActionReason ResourceInstanceChangeActionReason
+
+	// RequiredReplace is a set of paths that caused the change action to be
+	// Replace rather than Update. Always nil if the change action is not
+	// Replace.
+	//
+	// This is retained only for UI-plan-rendering purposes and so it does not
+	// currently survive a round-trip through a saved plan file.
+	RequiredReplace cty.PathSet
+
+	// Private allows a provider to stash any extra data that is opaque to
+	// Terraform that relates to this change. Terraform will save this
+	// byte-for-byte and return it to the provider in the apply call.
+	Private []byte
+}
+
+// Encode produces a variant of the reciever that has its change values
+// serialized so it can be written to a plan file. Pass the implied type of the
+// corresponding resource type schema for correct operation.
+func (rc *ResourceInstanceChange) Encode(ty cty.Type) (*ResourceInstanceChangeSrc, error) {
+	cs, err := rc.Change.Encode(ty)
+	if err != nil {
+		return nil, err
+	}
+	prevRunAddr := rc.PrevRunAddr
+	if prevRunAddr.Resource.Resource.Type == "" {
+		// Suggests an old caller that hasn't been properly updated to
+		// populate this yet.
+		prevRunAddr = rc.Addr
+	}
+	return &ResourceInstanceChangeSrc{
+		Addr:            rc.Addr,
+		PrevRunAddr:     prevRunAddr,
+		DeposedKey:      rc.DeposedKey,
+		ProviderAddr:    rc.ProviderAddr,
+		ChangeSrc:       *cs,
+		ActionReason:    rc.ActionReason,
+		RequiredReplace: rc.RequiredReplace,
+		Private:         rc.Private,
+	}, err
+}
+
+func (rc *ResourceInstanceChange) Moved() bool {
+	return !rc.Addr.Equal(rc.PrevRunAddr)
+}
+
+// Simplify will, where possible, produce a change with a simpler action than
+// the receiever given a flag indicating whether the caller is dealing with
+// a normal apply or a destroy. This flag deals with the fact that Terraform
+// Core uses a specialized graph node type for destroying; only that
+// specialized node should set "destroying" to true.
+//
+// The following table shows the simplification behavior:
+//
+//	Action    Destroying?   New Action
+//	--------+-------------+-----------
+//	Create    true          NoOp
+//	Delete    false         NoOp
+//	Replace   true          Delete
+//	Replace   false         Create
+//
+// For any combination not in the above table, the Simplify just returns the
+// receiver as-is.
+func (rc *ResourceInstanceChange) Simplify(destroying bool) *ResourceInstanceChange {
+	if destroying {
+		switch rc.Action {
+		case Delete:
+			// We'll fall out and just return rc verbatim, then.
+		case CreateThenDelete, DeleteThenCreate:
+			return &ResourceInstanceChange{
+				Addr:         rc.Addr,
+				DeposedKey:   rc.DeposedKey,
+				Private:      rc.Private,
+				ProviderAddr: rc.ProviderAddr,
+				Change: Change{
+					Action:          Delete,
+					Before:          rc.Before,
+					After:           cty.NullVal(rc.Before.Type()),
+					Importing:       rc.Importing,
+					GeneratedConfig: rc.GeneratedConfig,
+				},
+			}
+		default:
+			return &ResourceInstanceChange{
+				Addr:         rc.Addr,
+				DeposedKey:   rc.DeposedKey,
+				Private:      rc.Private,
+				ProviderAddr: rc.ProviderAddr,
+				Change: Change{
+					Action:          NoOp,
+					Before:          rc.Before,
+					After:           rc.Before,
+					Importing:       rc.Importing,
+					GeneratedConfig: rc.GeneratedConfig,
+				},
+			}
+		}
+	} else {
+		switch rc.Action {
+		case Delete:
+			return &ResourceInstanceChange{
+				Addr:         rc.Addr,
+				DeposedKey:   rc.DeposedKey,
+				Private:      rc.Private,
+				ProviderAddr: rc.ProviderAddr,
+				Change: Change{
+					Action:          NoOp,
+					Before:          rc.Before,
+					After:           rc.Before,
+					Importing:       rc.Importing,
+					GeneratedConfig: rc.GeneratedConfig,
+				},
+			}
+		case CreateThenDelete, DeleteThenCreate:
+			return &ResourceInstanceChange{
+				Addr:         rc.Addr,
+				DeposedKey:   rc.DeposedKey,
+				Private:      rc.Private,
+				ProviderAddr: rc.ProviderAddr,
+				Change: Change{
+					Action:          Create,
+					Before:          cty.NullVal(rc.After.Type()),
+					After:           rc.After,
+					Importing:       rc.Importing,
+					GeneratedConfig: rc.GeneratedConfig,
+				},
+			}
+		}
+	}
+
+	// If we fall out here then our change is already simple enough.
+	return rc
+}
+
+// ResourceInstanceChangeActionReason allows for some extra user-facing
+// reasoning for why a particular change action was chosen for a particular
+// resource instance.
+//
+// This only represents sufficient detail to give a suitable explanation to
+// an end-user, and mustn't be used for any real decision-making during the
+// apply step.
+type ResourceInstanceChangeActionReason rune
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=ResourceInstanceChangeActionReason changes.go
+
+const (
+	// In most cases there's no special reason for choosing a particular
+	// action, which is represented by ResourceInstanceChangeNoReason.
+	ResourceInstanceChangeNoReason ResourceInstanceChangeActionReason = 0
+
+	// ResourceInstanceReplaceBecauseTainted indicates that the resource
+	// instance must be replaced because its existing current object is
+	// marked as "tainted".
+	ResourceInstanceReplaceBecauseTainted ResourceInstanceChangeActionReason = 'T'
+
+	// ResourceInstanceReplaceByRequest indicates that the resource instance
+	// is planned to be replaced because a caller specifically asked for it
+	// to be using ReplaceAddrs. (On the command line, the -replace=...
+	// planning option.)
+	ResourceInstanceReplaceByRequest ResourceInstanceChangeActionReason = 'R'
+
+	// ResourceInstanceReplaceByTriggers indicates that the resource instance
+	// is planned to be replaced because of a corresponding change in a
+	// replace_triggered_by reference.
+	ResourceInstanceReplaceByTriggers ResourceInstanceChangeActionReason = 'D'
+
+	// ResourceInstanceReplaceBecauseCannotUpdate indicates that the resource
+	// instance is planned to be replaced because the provider has indicated
+	// that a requested change cannot be applied as an update.
+	//
+	// In this case, the RequiredReplace field will typically be populated on
+	// the ResourceInstanceChange object to give information about specifically
+	// which arguments changed in a non-updatable way.
+	ResourceInstanceReplaceBecauseCannotUpdate ResourceInstanceChangeActionReason = 'F'
+
+	// ResourceInstanceDeleteBecauseNoResourceConfig indicates that the
+	// resource instance is planned to be deleted because there's no
+	// corresponding resource configuration block in the configuration.
+	ResourceInstanceDeleteBecauseNoResourceConfig ResourceInstanceChangeActionReason = 'N'
+
+	// ResourceInstanceDeleteBecauseWrongRepetition indicates that the
+	// resource instance is planned to be deleted because the instance key
+	// type isn't consistent with the repetition mode selected in the
+	// resource configuration.
+	ResourceInstanceDeleteBecauseWrongRepetition ResourceInstanceChangeActionReason = 'W'
+
+	// ResourceInstanceDeleteBecauseCountIndex indicates that the resource
+	// instance is planned to be deleted because its integer instance key
+	// is out of range for the current configured resource "count" value.
+	ResourceInstanceDeleteBecauseCountIndex ResourceInstanceChangeActionReason = 'C'
+
+	// ResourceInstanceDeleteBecauseEachKey indicates that the resource
+	// instance is planned to be deleted because its string instance key
+	// isn't one of the keys included in the current configured resource
+	// "for_each" value.
+	ResourceInstanceDeleteBecauseEachKey ResourceInstanceChangeActionReason = 'E'
+
+	// ResourceInstanceDeleteBecauseNoModule indicates that the resource
+	// instance is planned to be deleted because it belongs to a module
+	// instance that's no longer declared in the configuration.
+	//
+	// This is less specific than the reasons we return for the various ways
+	// a resource instance itself can be no longer declared, including both
+	// the total removal of a module block and changes to its count/for_each
+	// arguments. This difference in detail is out of pragmatism, because
+	// potentially multiple nested modules could all contribute conflicting
+	// specific reasons for a particular instance to no longer be declared.
+	ResourceInstanceDeleteBecauseNoModule ResourceInstanceChangeActionReason = 'M'
+
+	// ResourceInstanceDeleteBecauseNoMoveTarget indicates that the resource
+	// address appears as the target ("to") in a moved block, but no
+	// configuration exists for that resource. According to our move rules,
+	// this combination evaluates to a deletion of the "new" resource.
+	ResourceInstanceDeleteBecauseNoMoveTarget ResourceInstanceChangeActionReason = 'A'
+
+	// ResourceInstanceReadBecauseConfigUnknown indicates that the resource
+	// must be read during apply (rather than during planning) because its
+	// configuration contains unknown values. This reason applies only to
+	// data resources.
+	ResourceInstanceReadBecauseConfigUnknown ResourceInstanceChangeActionReason = '?'
+
+	// ResourceInstanceReadBecauseDependencyPending indicates that the resource
+	// must be read during apply (rather than during planning) because it
+	// depends on a managed resource instance which has its own changes
+	// pending.
+	ResourceInstanceReadBecauseDependencyPending ResourceInstanceChangeActionReason = '!'
+
+	// ResourceInstanceReadBecauseCheckNested indicates that the resource must
+	// be read during apply (as well as during planning) because it is inside
+	// a check block and when the check assertions execute we want them to use
+	// the most up-to-date data.
+	ResourceInstanceReadBecauseCheckNested ResourceInstanceChangeActionReason = '#'
+)
+
+// OutputChange describes a change to an output value.
+type OutputChange struct {
+	// Addr is the absolute address of the output value that the change
+	// will apply to.
+	Addr addrs.AbsOutputValue
+
+	// Change is an embedded description of the change.
+	//
+	// For output value changes, the type constraint for the DynamicValue
+	// instances is always cty.DynamicPseudoType.
+	Change
+
+	// Sensitive, if true, indicates that either the old or new value in the
+	// change is sensitive and so a rendered version of the plan in the UI
+	// should elide the actual values while still indicating the action of the
+	// change.
+	Sensitive bool
+}
+
+// Encode produces a variant of the reciever that has its change values
+// serialized so it can be written to a plan file.
+func (oc *OutputChange) Encode() (*OutputChangeSrc, error) {
+	cs, err := oc.Change.Encode(cty.DynamicPseudoType)
+	if err != nil {
+		return nil, err
+	}
+	return &OutputChangeSrc{
+		Addr:      oc.Addr,
+		ChangeSrc: *cs,
+		Sensitive: oc.Sensitive,
+	}, err
+}
+
+// Importing is the part of a ChangeSrc that describes the embedded import
+// action.
+//
+// The fields in here are subject to change, so downstream consumers should be
+// prepared for backwards compatibility in case the contents changes.
+type Importing struct {
+	// ID is the original ID of the imported resource.
+	ID string
+}
+
+// Change describes a single change with a given action.
+type Change struct {
+	// Action defines what kind of change is being made.
+	Action Action
+
+	// Interpretation of Before and After depend on Action:
+	//
+	//     NoOp     Before and After are the same, unchanged value
+	//     Create   Before is nil, and After is the expected value after create.
+	//     Read     Before is any prior value (nil if no prior), and After is the
+	//              value that was or will be read.
+	//     Update   Before is the value prior to update, and After is the expected
+	//              value after update.
+	//     Replace  As with Update.
+	//     Delete   Before is the value prior to delete, and After is always nil.
+	//
+	// Unknown values may appear anywhere within the Before and After values,
+	// either as the values themselves or as nested elements within known
+	// collections/structures.
+	Before, After cty.Value
+
+	// Importing is present if the resource is being imported as part of this
+	// change.
+	//
+	// Use the simple presence of this field to detect if a ChangeSrc is to be
+	// imported, the contents of this structure may be modified going forward.
+	Importing *Importing
+
+	// GeneratedConfig contains any HCL config generated for this resource
+	// during planning, as a string. If GeneratedConfig is populated, Importing
+	// should be true. However, not all Importing changes contain generated
+	// config.
+	GeneratedConfig string
+}
+
+// Encode produces a variant of the reciever that has its change values
+// serialized so it can be written to a plan file. Pass the type constraint
+// that the values are expected to conform to; to properly decode the values
+// later an identical type constraint must be provided at that time.
+//
+// Where a Change is embedded in some other struct, it's generally better
+// to call the corresponding Encode method of that struct rather than working
+// directly with its embedded Change.
+func (c *Change) Encode(ty cty.Type) (*ChangeSrc, error) {
+	// Storing unmarked values so that we can encode unmarked values
+	// and save the PathValueMarks for re-marking the values later
+	var beforeVM, afterVM []cty.PathValueMarks
+	unmarkedBefore := c.Before
+	unmarkedAfter := c.After
+
+	if c.Before.ContainsMarked() {
+		unmarkedBefore, beforeVM = c.Before.UnmarkDeepWithPaths()
+	}
+	beforeDV, err := NewDynamicValue(unmarkedBefore, ty)
+	if err != nil {
+		return nil, err
+	}
+
+	if c.After.ContainsMarked() {
+		unmarkedAfter, afterVM = c.After.UnmarkDeepWithPaths()
+	}
+	afterDV, err := NewDynamicValue(unmarkedAfter, ty)
+	if err != nil {
+		return nil, err
+	}
+
+	var importing *ImportingSrc
+	if c.Importing != nil {
+		importing = &ImportingSrc{ID: c.Importing.ID}
+	}
+
+	return &ChangeSrc{
+		Action:          c.Action,
+		Before:          beforeDV,
+		After:           afterDV,
+		BeforeValMarks:  beforeVM,
+		AfterValMarks:   afterVM,
+		Importing:       importing,
+		GeneratedConfig: c.GeneratedConfig,
+	}, nil
+}
diff --git a/v1.5.7/internal/plans/changes_src.go b/v1.5.7/internal/plans/changes_src.go
new file mode 100644
index 0000000..c6e19cd
--- /dev/null
+++ b/v1.5.7/internal/plans/changes_src.go
@@ -0,0 +1,266 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plans
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// ResourceInstanceChangeSrc is a not-yet-decoded ResourceInstanceChange.
+// Pass the associated resource type's schema type to method Decode to
+// obtain a ResourceInstanceChange.
+type ResourceInstanceChangeSrc struct {
+	// Addr is the absolute address of the resource instance that the change
+	// will apply to.
+	Addr addrs.AbsResourceInstance
+
+	// PrevRunAddr is the absolute address that this resource instance had at
+	// the conclusion of a previous run.
+	//
+	// This will typically be the same as Addr, but can be different if the
+	// previous resource instance was subject to a "moved" block that we
+	// handled in the process of creating this plan.
+	//
+	// For the initial creation of a resource instance there isn't really any
+	// meaningful "previous run address", but PrevRunAddr will still be set
+	// equal to Addr in that case in order to simplify logic elsewhere which
+	// aims to detect and react to the movement of instances between addresses.
+	PrevRunAddr addrs.AbsResourceInstance
+
+	// DeposedKey is the identifier for a deposed object associated with the
+	// given instance, or states.NotDeposed if this change applies to the
+	// current object.
+	//
+	// A Replace change for a resource with create_before_destroy set will
+	// create a new DeposedKey temporarily during replacement. In that case,
+	// DeposedKey in the plan is always states.NotDeposed, representing that
+	// the current object is being replaced with the deposed.
+	DeposedKey states.DeposedKey
+
+	// Provider is the address of the provider configuration that was used
+	// to plan this change, and thus the configuration that must also be
+	// used to apply it.
+	ProviderAddr addrs.AbsProviderConfig
+
+	// ChangeSrc is an embedded description of the not-yet-decoded change.
+	ChangeSrc
+
+	// ActionReason is an optional extra indication of why we chose the
+	// action recorded in Change.Action for this particular resource instance.
+	//
+	// This is an approximate mechanism only for the purpose of explaining the
+	// plan to end-users in the UI and is not to be used for any
+	// decision-making during the apply step; if apply behavior needs to vary
+	// depending on the "action reason" then the information for that decision
+	// must be recorded more precisely elsewhere for that purpose.
+	//
+	// See the field of the same name in ResourceInstanceChange for more
+	// details.
+	ActionReason ResourceInstanceChangeActionReason
+
+	// RequiredReplace is a set of paths that caused the change action to be
+	// Replace rather than Update. Always nil if the change action is not
+	// Replace.
+	RequiredReplace cty.PathSet
+
+	// Private allows a provider to stash any extra data that is opaque to
+	// Terraform that relates to this change. Terraform will save this
+	// byte-for-byte and return it to the provider in the apply call.
+	Private []byte
+}
+
+// Decode unmarshals the raw representation of the instance object being
+// changed. Pass the implied type of the corresponding resource type schema
+// for correct operation.
+func (rcs *ResourceInstanceChangeSrc) Decode(ty cty.Type) (*ResourceInstanceChange, error) {
+	change, err := rcs.ChangeSrc.Decode(ty)
+	if err != nil {
+		return nil, err
+	}
+	prevRunAddr := rcs.PrevRunAddr
+	if prevRunAddr.Resource.Resource.Type == "" {
+		// Suggests an old caller that hasn't been properly updated to
+		// populate this yet.
+		prevRunAddr = rcs.Addr
+	}
+	return &ResourceInstanceChange{
+		Addr:            rcs.Addr,
+		PrevRunAddr:     prevRunAddr,
+		DeposedKey:      rcs.DeposedKey,
+		ProviderAddr:    rcs.ProviderAddr,
+		Change:          *change,
+		ActionReason:    rcs.ActionReason,
+		RequiredReplace: rcs.RequiredReplace,
+		Private:         rcs.Private,
+	}, nil
+}
+
+// DeepCopy creates a copy of the receiver where any pointers to nested mutable
+// values are also copied, thus ensuring that future mutations of the receiver
+// will not affect the copy.
+//
+// Some types used within a resource change are immutable by convention even
+// though the Go language allows them to be mutated, such as the types from
+// the addrs package. These are _not_ copied by this method, under the
+// assumption that callers will behave themselves.
+func (rcs *ResourceInstanceChangeSrc) DeepCopy() *ResourceInstanceChangeSrc {
+	if rcs == nil {
+		return nil
+	}
+	ret := *rcs
+
+	ret.RequiredReplace = cty.NewPathSet(ret.RequiredReplace.List()...)
+
+	if len(ret.Private) != 0 {
+		private := make([]byte, len(ret.Private))
+		copy(private, ret.Private)
+		ret.Private = private
+	}
+
+	ret.ChangeSrc.Before = ret.ChangeSrc.Before.Copy()
+	ret.ChangeSrc.After = ret.ChangeSrc.After.Copy()
+
+	return &ret
+}
+
+func (rcs *ResourceInstanceChangeSrc) Moved() bool {
+	return !rcs.Addr.Equal(rcs.PrevRunAddr)
+}
+
+// OutputChangeSrc describes a change to an output value.
+type OutputChangeSrc struct {
+	// Addr is the absolute address of the output value that the change
+	// will apply to.
+	Addr addrs.AbsOutputValue
+
+	// ChangeSrc is an embedded description of the not-yet-decoded change.
+	//
+	// For output value changes, the type constraint for the DynamicValue
+	// instances is always cty.DynamicPseudoType.
+	ChangeSrc
+
+	// Sensitive, if true, indicates that either the old or new value in the
+	// change is sensitive and so a rendered version of the plan in the UI
+	// should elide the actual values while still indicating the action of the
+	// change.
+	Sensitive bool
+}
+
+// Decode unmarshals the raw representation of the output value being
+// changed.
+func (ocs *OutputChangeSrc) Decode() (*OutputChange, error) {
+	change, err := ocs.ChangeSrc.Decode(cty.DynamicPseudoType)
+	if err != nil {
+		return nil, err
+	}
+	return &OutputChange{
+		Addr:      ocs.Addr,
+		Change:    *change,
+		Sensitive: ocs.Sensitive,
+	}, nil
+}
+
+// DeepCopy creates a copy of the receiver where any pointers to nested mutable
+// values are also copied, thus ensuring that future mutations of the receiver
+// will not affect the copy.
+//
+// Some types used within a resource change are immutable by convention even
+// though the Go language allows them to be mutated, such as the types from
+// the addrs package. These are _not_ copied by this method, under the
+// assumption that callers will behave themselves.
+func (ocs *OutputChangeSrc) DeepCopy() *OutputChangeSrc {
+	if ocs == nil {
+		return nil
+	}
+	ret := *ocs
+
+	ret.ChangeSrc.Before = ret.ChangeSrc.Before.Copy()
+	ret.ChangeSrc.After = ret.ChangeSrc.After.Copy()
+
+	return &ret
+}
+
+// ImportingSrc is the part of a ChangeSrc that describes the embedded import
+// action.
+//
+// The fields in here are subject to change, so downstream consumers should be
+// prepared for backwards compatibility in case the contents changes.
+type ImportingSrc struct {
+	// ID is the original ID of the imported resource.
+	ID string
+}
+
+// ChangeSrc is a not-yet-decoded Change.
+type ChangeSrc struct {
+	// Action defines what kind of change is being made.
+	Action Action
+
+	// Before and After correspond to the fields of the same name in Change,
+	// but have not yet been decoded from the serialized value used for
+	// storage.
+	Before, After DynamicValue
+
+	// BeforeValMarks and AfterValMarks are stored path+mark combinations
+	// that might be discovered when encoding a change. Marks are removed
+	// to enable encoding (marked values cannot be marshalled), and so storing
+	// the path+mark combinations allow us to re-mark the value later
+	// when, for example, displaying the diff to the UI.
+	BeforeValMarks, AfterValMarks []cty.PathValueMarks
+
+	// Importing is present if the resource is being imported as part of this
+	// change.
+	//
+	// Use the simple presence of this field to detect if a ChangeSrc is to be
+	// imported, the contents of this structure may be modified going forward.
+	Importing *ImportingSrc
+
+	// GeneratedConfig contains any HCL config generated for this resource
+	// during planning, as a string. If GeneratedConfig is populated, Importing
+	// should be true. However, not all Importing changes contain generated
+	// config.
+	GeneratedConfig string
+}
+
+// Decode unmarshals the raw representations of the before and after values
+// to produce a Change object. Pass the type constraint that the result must
+// conform to.
+//
+// Where a ChangeSrc is embedded in some other struct, it's generally better
+// to call the corresponding Decode method of that struct rather than working
+// directly with its embedded Change.
+func (cs *ChangeSrc) Decode(ty cty.Type) (*Change, error) {
+	var err error
+	before := cty.NullVal(ty)
+	after := cty.NullVal(ty)
+
+	if len(cs.Before) > 0 {
+		before, err = cs.Before.Decode(ty)
+		if err != nil {
+			return nil, fmt.Errorf("error decoding 'before' value: %s", err)
+		}
+	}
+	if len(cs.After) > 0 {
+		after, err = cs.After.Decode(ty)
+		if err != nil {
+			return nil, fmt.Errorf("error decoding 'after' value: %s", err)
+		}
+	}
+
+	var importing *Importing
+	if cs.Importing != nil {
+		importing = &Importing{ID: cs.Importing.ID}
+	}
+
+	return &Change{
+		Action:          cs.Action,
+		Before:          before.MarkWithPaths(cs.BeforeValMarks),
+		After:           after.MarkWithPaths(cs.AfterValMarks),
+		Importing:       importing,
+		GeneratedConfig: cs.GeneratedConfig,
+	}, nil
+}
diff --git a/v1.5.7/internal/plans/changes_state.go b/v1.5.7/internal/plans/changes_state.go
new file mode 100644
index 0000000..89a5a0c
--- /dev/null
+++ b/v1.5.7/internal/plans/changes_state.go
@@ -0,0 +1,18 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plans
+
+import (
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// PlannedState merges the set of changes described by the receiver into the
+// given prior state to produce the planned result state.
+//
+// The result is an approximation of the state as it would exist after
+// applying these changes, omitting any values that cannot be determined until
+// the changes are actually applied.
+func (c *Changes) PlannedState(prior *states.State) (*states.State, error) {
+	panic("Changes.PlannedState not yet implemented")
+}
diff --git a/v1.5.7/internal/plans/changes_sync.go b/v1.5.7/internal/plans/changes_sync.go
new file mode 100644
index 0000000..27a5dcc
--- /dev/null
+++ b/v1.5.7/internal/plans/changes_sync.go
@@ -0,0 +1,225 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plans
+
+import (
+	"fmt"
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// ChangesSync is a wrapper around a Changes that provides a concurrency-safe
+// interface to insert new changes and retrieve copies of existing changes.
+//
+// Each ChangesSync is independent of all others, so all concurrent writers
+// to a particular Changes must share a single ChangesSync. Behavior is
+// undefined if any other caller makes changes to the underlying Changes
+// object or its nested objects concurrently with any of the methods of a
+// particular ChangesSync.
+type ChangesSync struct {
+	lock    sync.Mutex
+	changes *Changes
+}
+
+// AppendResourceInstanceChange records the given resource instance change in
+// the set of planned resource changes.
+//
+// The caller must ensure that there are no concurrent writes to the given
+// change while this method is running, but it is safe to resume mutating
+// it after this method returns without affecting the saved change.
+func (cs *ChangesSync) AppendResourceInstanceChange(changeSrc *ResourceInstanceChangeSrc) {
+	if cs == nil {
+		panic("AppendResourceInstanceChange on nil ChangesSync")
+	}
+	cs.lock.Lock()
+	defer cs.lock.Unlock()
+
+	s := changeSrc.DeepCopy()
+	cs.changes.Resources = append(cs.changes.Resources, s)
+}
+
+// GetResourceInstanceChange searches the set of resource instance changes for
+// one matching the given address and generation, returning it if it exists.
+//
+// If no such change exists, nil is returned.
+//
+// The returned object is a deep copy of the change recorded in the plan, so
+// callers may mutate it although it's generally better (less confusing) to
+// treat planned changes as immutable after they've been initially constructed.
+func (cs *ChangesSync) GetResourceInstanceChange(addr addrs.AbsResourceInstance, gen states.Generation) *ResourceInstanceChangeSrc {
+	if cs == nil {
+		panic("GetResourceInstanceChange on nil ChangesSync")
+	}
+	cs.lock.Lock()
+	defer cs.lock.Unlock()
+
+	if gen == states.CurrentGen {
+		return cs.changes.ResourceInstance(addr).DeepCopy()
+	}
+	if dk, ok := gen.(states.DeposedKey); ok {
+		return cs.changes.ResourceInstanceDeposed(addr, dk).DeepCopy()
+	}
+	panic(fmt.Sprintf("unsupported generation value %#v", gen))
+}
+
+// GetChangesForConfigResource searches the set of resource instance
+// changes and returns all changes related to a given configuration address.
+// This is be used to find possible changes related to a configuration
+// reference.
+//
+// If no such changes exist, nil is returned.
+//
+// The returned objects are a deep copy of the change recorded in the plan, so
+// callers may mutate them although it's generally better (less confusing) to
+// treat planned changes as immutable after they've been initially constructed.
+func (cs *ChangesSync) GetChangesForConfigResource(addr addrs.ConfigResource) []*ResourceInstanceChangeSrc {
+	if cs == nil {
+		panic("GetChangesForConfigResource on nil ChangesSync")
+	}
+	cs.lock.Lock()
+	defer cs.lock.Unlock()
+	var changes []*ResourceInstanceChangeSrc
+	for _, c := range cs.changes.InstancesForConfigResource(addr) {
+		changes = append(changes, c.DeepCopy())
+	}
+	return changes
+}
+
+// GetChangesForAbsResource searches the set of resource instance
+// changes and returns all changes related to a given configuration address.
+//
+// If no such changes exist, nil is returned.
+//
+// The returned objects are a deep copy of the change recorded in the plan, so
+// callers may mutate them although it's generally better (less confusing) to
+// treat planned changes as immutable after they've been initially constructed.
+func (cs *ChangesSync) GetChangesForAbsResource(addr addrs.AbsResource) []*ResourceInstanceChangeSrc {
+	if cs == nil {
+		panic("GetChangesForAbsResource on nil ChangesSync")
+	}
+	cs.lock.Lock()
+	defer cs.lock.Unlock()
+	var changes []*ResourceInstanceChangeSrc
+	for _, c := range cs.changes.InstancesForAbsResource(addr) {
+		changes = append(changes, c.DeepCopy())
+	}
+	return changes
+}
+
+// RemoveResourceInstanceChange searches the set of resource instance changes
+// for one matching the given address and generation, and removes it from the
+// set if it exists.
+func (cs *ChangesSync) RemoveResourceInstanceChange(addr addrs.AbsResourceInstance, gen states.Generation) {
+	if cs == nil {
+		panic("RemoveResourceInstanceChange on nil ChangesSync")
+	}
+	cs.lock.Lock()
+	defer cs.lock.Unlock()
+
+	dk := states.NotDeposed
+	if realDK, ok := gen.(states.DeposedKey); ok {
+		dk = realDK
+	}
+
+	addrStr := addr.String()
+	for i, r := range cs.changes.Resources {
+		if r.Addr.String() != addrStr || r.DeposedKey != dk {
+			continue
+		}
+		copy(cs.changes.Resources[i:], cs.changes.Resources[i+1:])
+		cs.changes.Resources = cs.changes.Resources[:len(cs.changes.Resources)-1]
+		return
+	}
+}
+
+// AppendOutputChange records the given output value change in the set of
+// planned value changes.
+//
+// The caller must ensure that there are no concurrent writes to the given
+// change while this method is running, but it is safe to resume mutating
+// it after this method returns without affecting the saved change.
+func (cs *ChangesSync) AppendOutputChange(changeSrc *OutputChangeSrc) {
+	if cs == nil {
+		panic("AppendOutputChange on nil ChangesSync")
+	}
+	cs.lock.Lock()
+	defer cs.lock.Unlock()
+
+	s := changeSrc.DeepCopy()
+	cs.changes.Outputs = append(cs.changes.Outputs, s)
+}
+
+// GetOutputChange searches the set of output value changes for one matching
+// the given address, returning it if it exists.
+//
+// If no such change exists, nil is returned.
+//
+// The returned object is a deep copy of the change recorded in the plan, so
+// callers may mutate it although it's generally better (less confusing) to
+// treat planned changes as immutable after they've been initially constructed.
+func (cs *ChangesSync) GetOutputChange(addr addrs.AbsOutputValue) *OutputChangeSrc {
+	if cs == nil {
+		panic("GetOutputChange on nil ChangesSync")
+	}
+	cs.lock.Lock()
+	defer cs.lock.Unlock()
+
+	return cs.changes.OutputValue(addr)
+}
+
+// GetRootOutputChanges searches the set of output changes for any that reside
+// the root module. If no such changes exist, nil is returned.
+//
+// The returned objects are a deep copy of the change recorded in the plan, so
+// callers may mutate them although it's generally better (less confusing) to
+// treat planned changes as immutable after they've been initially constructed.
+func (cs *ChangesSync) GetRootOutputChanges() []*OutputChangeSrc {
+	if cs == nil {
+		panic("GetRootOutputChanges on nil ChangesSync")
+	}
+	cs.lock.Lock()
+	defer cs.lock.Unlock()
+
+	return cs.changes.RootOutputValues()
+}
+
+// GetOutputChanges searches the set of output changes for any that reside in
+// module instances beneath the given module. If no changes exist, nil
+// is returned.
+//
+// The returned objects are a deep copy of the change recorded in the plan, so
+// callers may mutate them although it's generally better (less confusing) to
+// treat planned changes as immutable after they've been initially constructed.
+func (cs *ChangesSync) GetOutputChanges(parent addrs.ModuleInstance, module addrs.ModuleCall) []*OutputChangeSrc {
+	if cs == nil {
+		panic("GetOutputChange on nil ChangesSync")
+	}
+	cs.lock.Lock()
+	defer cs.lock.Unlock()
+
+	return cs.changes.OutputValues(parent, module)
+}
+
+// RemoveOutputChange searches the set of output value changes for one matching
+// the given address, and removes it from the set if it exists.
+func (cs *ChangesSync) RemoveOutputChange(addr addrs.AbsOutputValue) {
+	if cs == nil {
+		panic("RemoveOutputChange on nil ChangesSync")
+	}
+	cs.lock.Lock()
+	defer cs.lock.Unlock()
+
+	addrStr := addr.String()
+
+	for i, o := range cs.changes.Outputs {
+		if o.Addr.String() != addrStr {
+			continue
+		}
+		copy(cs.changes.Outputs[i:], cs.changes.Outputs[i+1:])
+		cs.changes.Outputs = cs.changes.Outputs[:len(cs.changes.Outputs)-1]
+		return
+	}
+}
diff --git a/v1.5.7/internal/plans/changes_test.go b/v1.5.7/internal/plans/changes_test.go
new file mode 100644
index 0000000..2886675
--- /dev/null
+++ b/v1.5.7/internal/plans/changes_test.go
@@ -0,0 +1,162 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plans
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestChangesEmpty(t *testing.T) {
+	testCases := map[string]struct {
+		changes *Changes
+		want    bool
+	}{
+		"no changes": {
+			&Changes{},
+			true,
+		},
+		"resource change": {
+			&Changes{
+				Resources: []*ResourceInstanceChangeSrc{
+					{
+						Addr: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "woot",
+						}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+						PrevRunAddr: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "woot",
+						}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+						ChangeSrc: ChangeSrc{
+							Action: Update,
+						},
+					},
+				},
+			},
+			false,
+		},
+		"resource change with no-op action": {
+			&Changes{
+				Resources: []*ResourceInstanceChangeSrc{
+					{
+						Addr: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "woot",
+						}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+						PrevRunAddr: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "woot",
+						}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+						ChangeSrc: ChangeSrc{
+							Action: NoOp,
+						},
+					},
+				},
+			},
+			true,
+		},
+		"resource moved with no-op change": {
+			&Changes{
+				Resources: []*ResourceInstanceChangeSrc{
+					{
+						Addr: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "woot",
+						}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+						PrevRunAddr: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "toot",
+						}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+						ChangeSrc: ChangeSrc{
+							Action: NoOp,
+						},
+					},
+				},
+			},
+			false,
+		},
+		"output change": {
+			&Changes{
+				Outputs: []*OutputChangeSrc{
+					{
+						Addr: addrs.OutputValue{
+							Name: "result",
+						}.Absolute(addrs.RootModuleInstance),
+						ChangeSrc: ChangeSrc{
+							Action: Update,
+						},
+					},
+				},
+			},
+			false,
+		},
+		"output change no-op": {
+			&Changes{
+				Outputs: []*OutputChangeSrc{
+					{
+						Addr: addrs.OutputValue{
+							Name: "result",
+						}.Absolute(addrs.RootModuleInstance),
+						ChangeSrc: ChangeSrc{
+							Action: NoOp,
+						},
+					},
+				},
+			},
+			true,
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			if got, want := tc.changes.Empty(), tc.want; got != want {
+				t.Fatalf("unexpected result: got %v, want %v", got, want)
+			}
+		})
+	}
+}
+
+func TestChangeEncodeSensitive(t *testing.T) {
+	testVals := []cty.Value{
+		cty.ObjectVal(map[string]cty.Value{
+			"ding": cty.StringVal("dong").Mark(marks.Sensitive),
+		}),
+		cty.StringVal("bleep").Mark("bloop"),
+		cty.ListVal([]cty.Value{cty.UnknownVal(cty.String).Mark("sup?")}),
+	}
+
+	for _, v := range testVals {
+		t.Run(fmt.Sprintf("%#v", v), func(t *testing.T) {
+			change := Change{
+				Before: cty.NullVal(v.Type()),
+				After:  v,
+			}
+
+			encoded, err := change.Encode(v.Type())
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			decoded, err := encoded.Decode(v.Type())
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			if !v.RawEquals(decoded.After) {
+				t.Fatalf("%#v != %#v\n", decoded.After, v)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/plans/doc.go b/v1.5.7/internal/plans/doc.go
new file mode 100644
index 0000000..e53063c
--- /dev/null
+++ b/v1.5.7/internal/plans/doc.go
@@ -0,0 +1,8 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package plans contains the types that are used to represent Terraform plans.
+//
+// A plan describes a set of changes that Terraform will make to update remote
+// objects to match with changes to the configuration.
+package plans
diff --git a/v1.5.7/internal/plans/dynamic_value.go b/v1.5.7/internal/plans/dynamic_value.go
new file mode 100644
index 0000000..8d7485f
--- /dev/null
+++ b/v1.5.7/internal/plans/dynamic_value.go
@@ -0,0 +1,99 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plans
+
+import (
+	"github.com/zclconf/go-cty/cty"
+	ctymsgpack "github.com/zclconf/go-cty/cty/msgpack"
+)
+
+// DynamicValue is the representation in the plan of a value whose type cannot
+// be determined at compile time, such as because it comes from a schema
+// defined in a plugin.
+//
+// This type is used as an indirection so that the overall plan structure can
+// be decoded without schema available, and then the dynamic values accessed
+// at a later time once the appropriate schema has been determined.
+//
+// Internally, DynamicValue is a serialized version of a cty.Value created
+// against a particular type constraint. Callers should not access directly
+// the serialized form, whose format may change in future. Values of this
+// type must always be created by calling NewDynamicValue.
+//
+// The zero value of DynamicValue is nil, and represents the absense of a
+// value within the Go type system. This is distinct from a cty.NullVal
+// result, which represents the absense of a value within the cty type system.
+type DynamicValue []byte
+
+// NewDynamicValue creates a DynamicValue by serializing the given value
+// against the given type constraint. The value must conform to the type
+// constraint, or the result is undefined.
+//
+// If the value to be encoded has no predefined schema (for example, for
+// module output values and input variables), set the type constraint to
+// cty.DynamicPseudoType in order to save type information as part of the
+// value, and then also pass cty.DynamicPseudoType to method Decode to recover
+// the original value.
+//
+// cty.NilVal can be used to represent the absense of a value, but callers
+// must be careful to distinguish values that are absent at the Go layer
+// (cty.NilVal) vs. values that are absent at the cty layer (cty.NullVal
+// results).
+func NewDynamicValue(val cty.Value, ty cty.Type) (DynamicValue, error) {
+	// If we're given cty.NilVal (the zero value of cty.Value, which is
+	// distinct from a typed null value created by cty.NullVal) then we'll
+	// assume the caller is trying to represent the _absense_ of a value,
+	// and so we'll return a nil DynamicValue.
+	if val == cty.NilVal {
+		return DynamicValue(nil), nil
+	}
+
+	// Currently our internal encoding is msgpack, via ctymsgpack.
+	buf, err := ctymsgpack.Marshal(val, ty)
+	if err != nil {
+		return nil, err
+	}
+
+	return DynamicValue(buf), nil
+}
+
+// Decode retrieves the effective value from the receiever by interpreting the
+// serialized form against the given type constraint. For correct results,
+// the type constraint must match (or be consistent with) the one that was
+// used to create the receiver.
+//
+// A nil DynamicValue decodes to cty.NilVal, which is not a valid value and
+// instead represents the absense of a value.
+func (v DynamicValue) Decode(ty cty.Type) (cty.Value, error) {
+	if v == nil {
+		return cty.NilVal, nil
+	}
+
+	return ctymsgpack.Unmarshal([]byte(v), ty)
+}
+
+// ImpliedType returns the type implied by the serialized structure of the
+// receiving value.
+//
+// This will not necessarily be exactly the type that was given when the
+// value was encoded, and in particular must not be used for values that
+// were encoded with their static type given as cty.DynamicPseudoType.
+// It is however safe to use this method for values that were encoded using
+// their runtime type as the conforming type, with the result being
+// semantically equivalent but with all lists and sets represented as tuples,
+// and maps as objects, due to ambiguities of the serialization.
+func (v DynamicValue) ImpliedType() (cty.Type, error) {
+	return ctymsgpack.ImpliedType([]byte(v))
+}
+
+// Copy produces a copy of the receiver with a distinct backing array.
+func (v DynamicValue) Copy() DynamicValue {
+	if v == nil {
+		return nil
+	}
+
+	ret := make(DynamicValue, len(v))
+	copy(ret, v)
+	return ret
+}
diff --git a/v1.5.7/internal/plans/internal/planproto/doc.go b/v1.5.7/internal/plans/internal/planproto/doc.go
new file mode 100644
index 0000000..727eb2d
--- /dev/null
+++ b/v1.5.7/internal/plans/internal/planproto/doc.go
@@ -0,0 +1,10 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package planproto is home to the Go stubs generated from the tfplan protobuf
+// schema.
+//
+// This is an internal package to be used only by Terraform's planfile package.
+// From elsewhere in Terraform, use the API exported by the planfile package
+// itself.
+package planproto
diff --git a/v1.5.7/internal/plans/internal/planproto/planfile.pb.go b/v1.5.7/internal/plans/internal/planproto/planfile.pb.go
new file mode 100644
index 0000000..0c3e65b
--- /dev/null
+++ b/v1.5.7/internal/plans/internal/planproto/planfile.pb.go
@@ -0,0 +1,1786 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.28.1
+// 	protoc        v3.15.6
+// source: planfile.proto
+
+package planproto
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// Mode describes the planning mode that created the plan.
+type Mode int32
+
+const (
+	Mode_NORMAL       Mode = 0
+	Mode_DESTROY      Mode = 1
+	Mode_REFRESH_ONLY Mode = 2
+)
+
+// Enum value maps for Mode.
+var (
+	Mode_name = map[int32]string{
+		0: "NORMAL",
+		1: "DESTROY",
+		2: "REFRESH_ONLY",
+	}
+	Mode_value = map[string]int32{
+		"NORMAL":       0,
+		"DESTROY":      1,
+		"REFRESH_ONLY": 2,
+	}
+)
+
+func (x Mode) Enum() *Mode {
+	p := new(Mode)
+	*p = x
+	return p
+}
+
+func (x Mode) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Mode) Descriptor() protoreflect.EnumDescriptor {
+	return file_planfile_proto_enumTypes[0].Descriptor()
+}
+
+func (Mode) Type() protoreflect.EnumType {
+	return &file_planfile_proto_enumTypes[0]
+}
+
+func (x Mode) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Mode.Descriptor instead.
+func (Mode) EnumDescriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{0}
+}
+
+// Action describes the type of action planned for an object.
+// Not all action values are valid for all object types.
+type Action int32
+
+const (
+	Action_NOOP               Action = 0
+	Action_CREATE             Action = 1
+	Action_READ               Action = 2
+	Action_UPDATE             Action = 3
+	Action_DELETE             Action = 5
+	Action_DELETE_THEN_CREATE Action = 6
+	Action_CREATE_THEN_DELETE Action = 7
+)
+
+// Enum value maps for Action.
+var (
+	Action_name = map[int32]string{
+		0: "NOOP",
+		1: "CREATE",
+		2: "READ",
+		3: "UPDATE",
+		5: "DELETE",
+		6: "DELETE_THEN_CREATE",
+		7: "CREATE_THEN_DELETE",
+	}
+	Action_value = map[string]int32{
+		"NOOP":               0,
+		"CREATE":             1,
+		"READ":               2,
+		"UPDATE":             3,
+		"DELETE":             5,
+		"DELETE_THEN_CREATE": 6,
+		"CREATE_THEN_DELETE": 7,
+	}
+)
+
+func (x Action) Enum() *Action {
+	p := new(Action)
+	*p = x
+	return p
+}
+
+func (x Action) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Action) Descriptor() protoreflect.EnumDescriptor {
+	return file_planfile_proto_enumTypes[1].Descriptor()
+}
+
+func (Action) Type() protoreflect.EnumType {
+	return &file_planfile_proto_enumTypes[1]
+}
+
+func (x Action) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Action.Descriptor instead.
+func (Action) EnumDescriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{1}
+}
+
+// ResourceInstanceActionReason sometimes provides some additional user-facing
+// context for why a particular action was chosen for a resource instance.
+// This is for user feedback only and never used to drive behavior during the
+// subsequent apply step.
+type ResourceInstanceActionReason int32
+
+const (
+	ResourceInstanceActionReason_NONE                              ResourceInstanceActionReason = 0
+	ResourceInstanceActionReason_REPLACE_BECAUSE_TAINTED           ResourceInstanceActionReason = 1
+	ResourceInstanceActionReason_REPLACE_BY_REQUEST                ResourceInstanceActionReason = 2
+	ResourceInstanceActionReason_REPLACE_BECAUSE_CANNOT_UPDATE     ResourceInstanceActionReason = 3
+	ResourceInstanceActionReason_DELETE_BECAUSE_NO_RESOURCE_CONFIG ResourceInstanceActionReason = 4
+	ResourceInstanceActionReason_DELETE_BECAUSE_WRONG_REPETITION   ResourceInstanceActionReason = 5
+	ResourceInstanceActionReason_DELETE_BECAUSE_COUNT_INDEX        ResourceInstanceActionReason = 6
+	ResourceInstanceActionReason_DELETE_BECAUSE_EACH_KEY           ResourceInstanceActionReason = 7
+	ResourceInstanceActionReason_DELETE_BECAUSE_NO_MODULE          ResourceInstanceActionReason = 8
+	ResourceInstanceActionReason_REPLACE_BY_TRIGGERS               ResourceInstanceActionReason = 9
+	ResourceInstanceActionReason_READ_BECAUSE_CONFIG_UNKNOWN       ResourceInstanceActionReason = 10
+	ResourceInstanceActionReason_READ_BECAUSE_DEPENDENCY_PENDING   ResourceInstanceActionReason = 11
+	ResourceInstanceActionReason_READ_BECAUSE_CHECK_NESTED         ResourceInstanceActionReason = 13
+	ResourceInstanceActionReason_DELETE_BECAUSE_NO_MOVE_TARGET     ResourceInstanceActionReason = 12
+)
+
+// Enum value maps for ResourceInstanceActionReason.
+var (
+	ResourceInstanceActionReason_name = map[int32]string{
+		0:  "NONE",
+		1:  "REPLACE_BECAUSE_TAINTED",
+		2:  "REPLACE_BY_REQUEST",
+		3:  "REPLACE_BECAUSE_CANNOT_UPDATE",
+		4:  "DELETE_BECAUSE_NO_RESOURCE_CONFIG",
+		5:  "DELETE_BECAUSE_WRONG_REPETITION",
+		6:  "DELETE_BECAUSE_COUNT_INDEX",
+		7:  "DELETE_BECAUSE_EACH_KEY",
+		8:  "DELETE_BECAUSE_NO_MODULE",
+		9:  "REPLACE_BY_TRIGGERS",
+		10: "READ_BECAUSE_CONFIG_UNKNOWN",
+		11: "READ_BECAUSE_DEPENDENCY_PENDING",
+		13: "READ_BECAUSE_CHECK_NESTED",
+		12: "DELETE_BECAUSE_NO_MOVE_TARGET",
+	}
+	ResourceInstanceActionReason_value = map[string]int32{
+		"NONE":                              0,
+		"REPLACE_BECAUSE_TAINTED":           1,
+		"REPLACE_BY_REQUEST":                2,
+		"REPLACE_BECAUSE_CANNOT_UPDATE":     3,
+		"DELETE_BECAUSE_NO_RESOURCE_CONFIG": 4,
+		"DELETE_BECAUSE_WRONG_REPETITION":   5,
+		"DELETE_BECAUSE_COUNT_INDEX":        6,
+		"DELETE_BECAUSE_EACH_KEY":           7,
+		"DELETE_BECAUSE_NO_MODULE":          8,
+		"REPLACE_BY_TRIGGERS":               9,
+		"READ_BECAUSE_CONFIG_UNKNOWN":       10,
+		"READ_BECAUSE_DEPENDENCY_PENDING":   11,
+		"READ_BECAUSE_CHECK_NESTED":         13,
+		"DELETE_BECAUSE_NO_MOVE_TARGET":     12,
+	}
+)
+
+func (x ResourceInstanceActionReason) Enum() *ResourceInstanceActionReason {
+	p := new(ResourceInstanceActionReason)
+	*p = x
+	return p
+}
+
+func (x ResourceInstanceActionReason) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ResourceInstanceActionReason) Descriptor() protoreflect.EnumDescriptor {
+	return file_planfile_proto_enumTypes[2].Descriptor()
+}
+
+func (ResourceInstanceActionReason) Type() protoreflect.EnumType {
+	return &file_planfile_proto_enumTypes[2]
+}
+
+func (x ResourceInstanceActionReason) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use ResourceInstanceActionReason.Descriptor instead.
+func (ResourceInstanceActionReason) EnumDescriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{2}
+}
+
+// Status describes the status of a particular checkable object at the
+// completion of the plan.
+type CheckResults_Status int32
+
+const (
+	CheckResults_UNKNOWN CheckResults_Status = 0
+	CheckResults_PASS    CheckResults_Status = 1
+	CheckResults_FAIL    CheckResults_Status = 2
+	CheckResults_ERROR   CheckResults_Status = 3
+)
+
+// Enum value maps for CheckResults_Status.
+var (
+	CheckResults_Status_name = map[int32]string{
+		0: "UNKNOWN",
+		1: "PASS",
+		2: "FAIL",
+		3: "ERROR",
+	}
+	CheckResults_Status_value = map[string]int32{
+		"UNKNOWN": 0,
+		"PASS":    1,
+		"FAIL":    2,
+		"ERROR":   3,
+	}
+)
+
+func (x CheckResults_Status) Enum() *CheckResults_Status {
+	p := new(CheckResults_Status)
+	*p = x
+	return p
+}
+
+func (x CheckResults_Status) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (CheckResults_Status) Descriptor() protoreflect.EnumDescriptor {
+	return file_planfile_proto_enumTypes[3].Descriptor()
+}
+
+func (CheckResults_Status) Type() protoreflect.EnumType {
+	return &file_planfile_proto_enumTypes[3]
+}
+
+func (x CheckResults_Status) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use CheckResults_Status.Descriptor instead.
+func (CheckResults_Status) EnumDescriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{5, 0}
+}
+
+type CheckResults_ObjectKind int32
+
+const (
+	CheckResults_UNSPECIFIED  CheckResults_ObjectKind = 0
+	CheckResults_RESOURCE     CheckResults_ObjectKind = 1
+	CheckResults_OUTPUT_VALUE CheckResults_ObjectKind = 2
+	CheckResults_CHECK        CheckResults_ObjectKind = 3
+)
+
+// Enum value maps for CheckResults_ObjectKind.
+var (
+	CheckResults_ObjectKind_name = map[int32]string{
+		0: "UNSPECIFIED",
+		1: "RESOURCE",
+		2: "OUTPUT_VALUE",
+		3: "CHECK",
+	}
+	CheckResults_ObjectKind_value = map[string]int32{
+		"UNSPECIFIED":  0,
+		"RESOURCE":     1,
+		"OUTPUT_VALUE": 2,
+		"CHECK":        3,
+	}
+)
+
+func (x CheckResults_ObjectKind) Enum() *CheckResults_ObjectKind {
+	p := new(CheckResults_ObjectKind)
+	*p = x
+	return p
+}
+
+func (x CheckResults_ObjectKind) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (CheckResults_ObjectKind) Descriptor() protoreflect.EnumDescriptor {
+	return file_planfile_proto_enumTypes[4].Descriptor()
+}
+
+func (CheckResults_ObjectKind) Type() protoreflect.EnumType {
+	return &file_planfile_proto_enumTypes[4]
+}
+
+func (x CheckResults_ObjectKind) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use CheckResults_ObjectKind.Descriptor instead.
+func (CheckResults_ObjectKind) EnumDescriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{5, 1}
+}
+
+// Plan is the root message type for the tfplan file
+type Plan struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Version is incremented whenever there is a breaking change to
+	// the serialization format. Programs reading serialized plans should
+	// verify that version is set to the expected value and abort processing
+	// if not. A breaking change is any change that may cause an older
+	// consumer to interpret the structure incorrectly. This number will
+	// not be incremented if an existing consumer can either safely ignore
+	// changes to the format or if an existing consumer would fail to process
+	// the file for another message- or field-specific reason.
+	Version uint64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
+	// The mode that was active when this plan was created.
+	//
+	// This is saved only for UI purposes, so that Terraform can tailor its
+	// rendering of the plan depending on the mode. This must never be used to
+	// make decisions in Terraform Core during the applying of a plan.
+	UiMode Mode `protobuf:"varint,17,opt,name=ui_mode,json=uiMode,proto3,enum=tfplan.Mode" json:"ui_mode,omitempty"`
+	// Errored is true for any plan whose creation was interrupted by an
+	// error. A plan with this flag set cannot be applied, and the changes
+	// it proposes are likely to be incomplete.
+	Errored bool `protobuf:"varint,20,opt,name=errored,proto3" json:"errored,omitempty"`
+	// The variables that were set when creating the plan. Each value is
+	// a msgpack serialization of an HCL value.
+	Variables map[string]*DynamicValue `protobuf:"bytes,2,rep,name=variables,proto3" json:"variables,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	// An unordered set of proposed changes to resources throughout the
+	// configuration, including any nested modules. Use the address of
+	// each resource to determine which module it belongs to.
+	ResourceChanges []*ResourceInstanceChange `protobuf:"bytes,3,rep,name=resource_changes,json=resourceChanges,proto3" json:"resource_changes,omitempty"`
+	// An unordered set of detected drift: changes made to resources outside of
+	// Terraform, computed by comparing the previous run's state to the state
+	// after refresh.
+	ResourceDrift []*ResourceInstanceChange `protobuf:"bytes,18,rep,name=resource_drift,json=resourceDrift,proto3" json:"resource_drift,omitempty"`
+	// An unordered set of proposed changes to outputs in the root module
+	// of the configuration. This set also includes "no action" changes for
+	// outputs that are not changing, as context for detecting inconsistencies
+	// at apply time.
+	OutputChanges []*OutputChange `protobuf:"bytes,4,rep,name=output_changes,json=outputChanges,proto3" json:"output_changes,omitempty"`
+	// An unordered set of check results for the entire configuration.
+	//
+	// Each element represents a single static configuration object that has
+	// checks, and each of those may have zero or more dynamic objects that
+	// the checks were applied to nested within.
+	CheckResults []*CheckResults `protobuf:"bytes,19,rep,name=check_results,json=checkResults,proto3" json:"check_results,omitempty"`
+	// An unordered set of target addresses to include when applying. If no
+	// target addresses are present, the plan applies to the whole
+	// configuration.
+	TargetAddrs []string `protobuf:"bytes,5,rep,name=target_addrs,json=targetAddrs,proto3" json:"target_addrs,omitempty"`
+	// An unordered set of force-replace addresses to include when applying.
+	// This must match the set of addresses that was used when creating the
+	// plan, or else applying the plan will fail when it reaches a different
+	// conclusion about what action a particular resource instance needs.
+	ForceReplaceAddrs []string `protobuf:"bytes,16,rep,name=force_replace_addrs,json=forceReplaceAddrs,proto3" json:"force_replace_addrs,omitempty"`
+	// The version string for the Terraform binary that created this plan.
+	TerraformVersion string `protobuf:"bytes,14,opt,name=terraform_version,json=terraformVersion,proto3" json:"terraform_version,omitempty"`
+	// Backend is a description of the backend configuration and other related
+	// settings at the time the plan was created.
+	Backend *Backend `protobuf:"bytes,13,opt,name=backend,proto3" json:"backend,omitempty"`
+	// RelevantAttributes lists individual resource attributes from
+	// ResourceDrift which may have contributed to the plan changes.
+	RelevantAttributes []*PlanResourceAttr `protobuf:"bytes,15,rep,name=relevant_attributes,json=relevantAttributes,proto3" json:"relevant_attributes,omitempty"`
+	// timestamp is the record of truth for when the plan happened.
+	Timestamp string `protobuf:"bytes,21,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+}
+
+func (x *Plan) Reset() {
+	*x = Plan{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_planfile_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Plan) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Plan) ProtoMessage() {}
+
+func (x *Plan) ProtoReflect() protoreflect.Message {
+	mi := &file_planfile_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Plan.ProtoReflect.Descriptor instead.
+func (*Plan) Descriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Plan) GetVersion() uint64 {
+	if x != nil {
+		return x.Version
+	}
+	return 0
+}
+
+func (x *Plan) GetUiMode() Mode {
+	if x != nil {
+		return x.UiMode
+	}
+	return Mode_NORMAL
+}
+
+func (x *Plan) GetErrored() bool {
+	if x != nil {
+		return x.Errored
+	}
+	return false
+}
+
+func (x *Plan) GetVariables() map[string]*DynamicValue {
+	if x != nil {
+		return x.Variables
+	}
+	return nil
+}
+
+func (x *Plan) GetResourceChanges() []*ResourceInstanceChange {
+	if x != nil {
+		return x.ResourceChanges
+	}
+	return nil
+}
+
+func (x *Plan) GetResourceDrift() []*ResourceInstanceChange {
+	if x != nil {
+		return x.ResourceDrift
+	}
+	return nil
+}
+
+func (x *Plan) GetOutputChanges() []*OutputChange {
+	if x != nil {
+		return x.OutputChanges
+	}
+	return nil
+}
+
+func (x *Plan) GetCheckResults() []*CheckResults {
+	if x != nil {
+		return x.CheckResults
+	}
+	return nil
+}
+
+func (x *Plan) GetTargetAddrs() []string {
+	if x != nil {
+		return x.TargetAddrs
+	}
+	return nil
+}
+
+func (x *Plan) GetForceReplaceAddrs() []string {
+	if x != nil {
+		return x.ForceReplaceAddrs
+	}
+	return nil
+}
+
+func (x *Plan) GetTerraformVersion() string {
+	if x != nil {
+		return x.TerraformVersion
+	}
+	return ""
+}
+
+func (x *Plan) GetBackend() *Backend {
+	if x != nil {
+		return x.Backend
+	}
+	return nil
+}
+
+func (x *Plan) GetRelevantAttributes() []*PlanResourceAttr {
+	if x != nil {
+		return x.RelevantAttributes
+	}
+	return nil
+}
+
+func (x *Plan) GetTimestamp() string {
+	if x != nil {
+		return x.Timestamp
+	}
+	return ""
+}
+
+// Backend is a description of backend configuration and other related settings.
+type Backend struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Type      string        `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
+	Config    *DynamicValue `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"`
+	Workspace string        `protobuf:"bytes,3,opt,name=workspace,proto3" json:"workspace,omitempty"`
+}
+
+func (x *Backend) Reset() {
+	*x = Backend{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_planfile_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Backend) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Backend) ProtoMessage() {}
+
+func (x *Backend) ProtoReflect() protoreflect.Message {
+	mi := &file_planfile_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Backend.ProtoReflect.Descriptor instead.
+func (*Backend) Descriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *Backend) GetType() string {
+	if x != nil {
+		return x.Type
+	}
+	return ""
+}
+
+func (x *Backend) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+func (x *Backend) GetWorkspace() string {
+	if x != nil {
+		return x.Workspace
+	}
+	return ""
+}
+
+// Change represents a change made to some object, transforming it from an old
+// state to a new state.
+type Change struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Not all action values are valid for all object types. Consult
+	// the documentation for any message that embeds Change.
+	Action Action `protobuf:"varint,1,opt,name=action,proto3,enum=tfplan.Action" json:"action,omitempty"`
+	// msgpack-encoded HCL values involved in the change.
+	//   - For update and replace, two values are provided that give the old and new values,
+	//     respectively.
+	//   - For create, one value is provided that gives the new value to be created
+	//   - For delete, one value is provided that describes the value being deleted
+	//   - For read, two values are provided that give the prior value for this object
+	//     (or null, if no prior value exists) and the value that was or will be read,
+	//     respectively.
+	//   - For no-op, one value is provided that is left unmodified by this non-change.
+	Values []*DynamicValue `protobuf:"bytes,2,rep,name=values,proto3" json:"values,omitempty"`
+	// An unordered set of paths into the old value which are marked as
+	// sensitive. Values at these paths should be obscured in human-readable
+	// output. This set is always empty for create.
+	BeforeSensitivePaths []*Path `protobuf:"bytes,3,rep,name=before_sensitive_paths,json=beforeSensitivePaths,proto3" json:"before_sensitive_paths,omitempty"`
+	// An unordered set of paths into the new value which are marked as
+	// sensitive. Values at these paths should be obscured in human-readable
+	// output. This set is always empty for delete.
+	AfterSensitivePaths []*Path `protobuf:"bytes,4,rep,name=after_sensitive_paths,json=afterSensitivePaths,proto3" json:"after_sensitive_paths,omitempty"`
+	// Importing, if true, specifies that the resource is being imported as part
+	// of the change.
+	Importing *Importing `protobuf:"bytes,5,opt,name=importing,proto3" json:"importing,omitempty"`
+	// GeneratedConfig contains any configuration that was generated as part of
+	// the change, as an HCL string.
+	GeneratedConfig string `protobuf:"bytes,6,opt,name=generated_config,json=generatedConfig,proto3" json:"generated_config,omitempty"`
+}
+
+func (x *Change) Reset() {
+	*x = Change{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_planfile_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Change) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Change) ProtoMessage() {}
+
+func (x *Change) ProtoReflect() protoreflect.Message {
+	mi := &file_planfile_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Change.ProtoReflect.Descriptor instead.
+func (*Change) Descriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *Change) GetAction() Action {
+	if x != nil {
+		return x.Action
+	}
+	return Action_NOOP
+}
+
+func (x *Change) GetValues() []*DynamicValue {
+	if x != nil {
+		return x.Values
+	}
+	return nil
+}
+
+func (x *Change) GetBeforeSensitivePaths() []*Path {
+	if x != nil {
+		return x.BeforeSensitivePaths
+	}
+	return nil
+}
+
+func (x *Change) GetAfterSensitivePaths() []*Path {
+	if x != nil {
+		return x.AfterSensitivePaths
+	}
+	return nil
+}
+
+func (x *Change) GetImporting() *Importing {
+	if x != nil {
+		return x.Importing
+	}
+	return nil
+}
+
+func (x *Change) GetGeneratedConfig() string {
+	if x != nil {
+		return x.GeneratedConfig
+	}
+	return ""
+}
+
+type ResourceInstanceChange struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// addr is a string representation of the resource instance address that
+	// this change will apply to.
+	Addr string `protobuf:"bytes,13,opt,name=addr,proto3" json:"addr,omitempty"`
+	// prev_run_addr is a string representation of the address at which
+	// this resource instance was tracked during the previous apply operation.
+	//
+	// This is populated only if it would be different from addr due to
+	// Terraform having reacted to refactoring annotations in the configuration.
+	// If empty, the previous run address is the same as the current address.
+	PrevRunAddr string `protobuf:"bytes,14,opt,name=prev_run_addr,json=prevRunAddr,proto3" json:"prev_run_addr,omitempty"`
+	// deposed_key, if set, indicates that this change applies to a deposed
+	// object for the indicated instance with the given deposed key. If not
+	// set, the change applies to the instance's current object.
+	DeposedKey string `protobuf:"bytes,7,opt,name=deposed_key,json=deposedKey,proto3" json:"deposed_key,omitempty"`
+	// provider is the address of the provider configuration that this change
+	// was planned with, and thus the configuration that must be used to
+	// apply it.
+	Provider string `protobuf:"bytes,8,opt,name=provider,proto3" json:"provider,omitempty"`
+	// Description of the proposed change. May use "create", "read", "update",
+	// "replace", "delete" and "no-op" actions.
+	Change *Change `protobuf:"bytes,9,opt,name=change,proto3" json:"change,omitempty"`
+	// raw blob value provided by the provider as additional context for the
+	// change. Must be considered an opaque value for any consumer other than
+	// the provider that generated it, and will be returned verbatim to the
+	// provider during the subsequent apply operation.
+	Private []byte `protobuf:"bytes,10,opt,name=private,proto3" json:"private,omitempty"`
+	// An unordered set of paths that prompted the change action to be
+	// "replace" rather than "update". Empty for any action other than
+	// "replace".
+	RequiredReplace []*Path `protobuf:"bytes,11,rep,name=required_replace,json=requiredReplace,proto3" json:"required_replace,omitempty"`
+	// Optional extra user-oriented context for why change.Action was chosen.
+	// This is for user feedback only and never used to drive behavior during
+	// apply.
+	ActionReason ResourceInstanceActionReason `protobuf:"varint,12,opt,name=action_reason,json=actionReason,proto3,enum=tfplan.ResourceInstanceActionReason" json:"action_reason,omitempty"`
+}
+
+func (x *ResourceInstanceChange) Reset() {
+	*x = ResourceInstanceChange{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_planfile_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ResourceInstanceChange) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ResourceInstanceChange) ProtoMessage() {}
+
+func (x *ResourceInstanceChange) ProtoReflect() protoreflect.Message {
+	mi := &file_planfile_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ResourceInstanceChange.ProtoReflect.Descriptor instead.
+func (*ResourceInstanceChange) Descriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *ResourceInstanceChange) GetAddr() string {
+	if x != nil {
+		return x.Addr
+	}
+	return ""
+}
+
+func (x *ResourceInstanceChange) GetPrevRunAddr() string {
+	if x != nil {
+		return x.PrevRunAddr
+	}
+	return ""
+}
+
+func (x *ResourceInstanceChange) GetDeposedKey() string {
+	if x != nil {
+		return x.DeposedKey
+	}
+	return ""
+}
+
+func (x *ResourceInstanceChange) GetProvider() string {
+	if x != nil {
+		return x.Provider
+	}
+	return ""
+}
+
+func (x *ResourceInstanceChange) GetChange() *Change {
+	if x != nil {
+		return x.Change
+	}
+	return nil
+}
+
+func (x *ResourceInstanceChange) GetPrivate() []byte {
+	if x != nil {
+		return x.Private
+	}
+	return nil
+}
+
+func (x *ResourceInstanceChange) GetRequiredReplace() []*Path {
+	if x != nil {
+		return x.RequiredReplace
+	}
+	return nil
+}
+
+func (x *ResourceInstanceChange) GetActionReason() ResourceInstanceActionReason {
+	if x != nil {
+		return x.ActionReason
+	}
+	return ResourceInstanceActionReason_NONE
+}
+
+type OutputChange struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Name of the output as defined in the root module.
+	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	// Description of the proposed change. May use "no-op", "create",
+	// "update" and "delete" actions.
+	Change *Change `protobuf:"bytes,2,opt,name=change,proto3" json:"change,omitempty"`
+	// Sensitive, if true, indicates that one or more of the values given
+	// in "change" is sensitive and should not be shown directly in any
+	// rendered plan.
+	Sensitive bool `protobuf:"varint,3,opt,name=sensitive,proto3" json:"sensitive,omitempty"`
+}
+
+func (x *OutputChange) Reset() {
+	*x = OutputChange{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_planfile_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *OutputChange) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OutputChange) ProtoMessage() {}
+
+func (x *OutputChange) ProtoReflect() protoreflect.Message {
+	mi := &file_planfile_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use OutputChange.ProtoReflect.Descriptor instead.
+func (*OutputChange) Descriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *OutputChange) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *OutputChange) GetChange() *Change {
+	if x != nil {
+		return x.Change
+	}
+	return nil
+}
+
+func (x *OutputChange) GetSensitive() bool {
+	if x != nil {
+		return x.Sensitive
+	}
+	return false
+}
+
+type CheckResults struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Kind CheckResults_ObjectKind `protobuf:"varint,1,opt,name=kind,proto3,enum=tfplan.CheckResults_ObjectKind" json:"kind,omitempty"`
+	// Address of the configuration object that declared the checks.
+	ConfigAddr string `protobuf:"bytes,2,opt,name=config_addr,json=configAddr,proto3" json:"config_addr,omitempty"`
+	// The aggregate status of the entire configuration object, based on
+	// the statuses of its zero or more checkable objects.
+	Status CheckResults_Status `protobuf:"varint,3,opt,name=status,proto3,enum=tfplan.CheckResults_Status" json:"status,omitempty"`
+	// The results for individual objects that were declared by the
+	// configuration object named in config_addr.
+	Objects []*CheckResults_ObjectResult `protobuf:"bytes,4,rep,name=objects,proto3" json:"objects,omitempty"`
+}
+
+func (x *CheckResults) Reset() {
+	*x = CheckResults{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_planfile_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CheckResults) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CheckResults) ProtoMessage() {}
+
+func (x *CheckResults) ProtoReflect() protoreflect.Message {
+	mi := &file_planfile_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CheckResults.ProtoReflect.Descriptor instead.
+func (*CheckResults) Descriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *CheckResults) GetKind() CheckResults_ObjectKind {
+	if x != nil {
+		return x.Kind
+	}
+	return CheckResults_UNSPECIFIED
+}
+
+func (x *CheckResults) GetConfigAddr() string {
+	if x != nil {
+		return x.ConfigAddr
+	}
+	return ""
+}
+
+func (x *CheckResults) GetStatus() CheckResults_Status {
+	if x != nil {
+		return x.Status
+	}
+	return CheckResults_UNKNOWN
+}
+
+func (x *CheckResults) GetObjects() []*CheckResults_ObjectResult {
+	if x != nil {
+		return x.Objects
+	}
+	return nil
+}
+
+// DynamicValue represents a value whose type is not decided until runtime,
+// often based on schema information obtained from a plugin.
+//
+// At present dynamic values are always encoded as msgpack, with extension
+// id 0 used to represent the special "unknown" value indicating results
+// that won't be known until after apply.
+//
+// In future other serialization formats may be used, possibly with a
+// transitional period of including both as separate attributes of this type.
+// Consumers must ignore attributes they don't support and fail if no supported
+// attribute is present. The top-level format version will not be incremented
+// for changes to the set of dynamic serialization formats.
+type DynamicValue struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Msgpack []byte `protobuf:"bytes,1,opt,name=msgpack,proto3" json:"msgpack,omitempty"`
+}
+
+func (x *DynamicValue) Reset() {
+	*x = DynamicValue{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_planfile_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DynamicValue) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DynamicValue) ProtoMessage() {}
+
+func (x *DynamicValue) ProtoReflect() protoreflect.Message {
+	mi := &file_planfile_proto_msgTypes[6]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use DynamicValue.ProtoReflect.Descriptor instead.
+func (*DynamicValue) Descriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *DynamicValue) GetMsgpack() []byte {
+	if x != nil {
+		return x.Msgpack
+	}
+	return nil
+}
+
+// Path represents a set of steps to traverse into a data structure. It is
+// used to refer to a sub-structure within a dynamic data structure presented
+// separately.
+type Path struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Steps []*Path_Step `protobuf:"bytes,1,rep,name=steps,proto3" json:"steps,omitempty"`
+}
+
+func (x *Path) Reset() {
+	*x = Path{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_planfile_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Path) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Path) ProtoMessage() {}
+
+func (x *Path) ProtoReflect() protoreflect.Message {
+	mi := &file_planfile_proto_msgTypes[7]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Path.ProtoReflect.Descriptor instead.
+func (*Path) Descriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *Path) GetSteps() []*Path_Step {
+	if x != nil {
+		return x.Steps
+	}
+	return nil
+}
+
+// Importing contains the embedded metadata about the import operation if this
+// change describes it.
+type Importing struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The original ID of the resource.
+	Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+}
+
+func (x *Importing) Reset() {
+	*x = Importing{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_planfile_proto_msgTypes[8]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Importing) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Importing) ProtoMessage() {}
+
+func (x *Importing) ProtoReflect() protoreflect.Message {
+	mi := &file_planfile_proto_msgTypes[8]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Importing.ProtoReflect.Descriptor instead.
+func (*Importing) Descriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *Importing) GetId() string {
+	if x != nil {
+		return x.Id
+	}
+	return ""
+}
+
+type PlanResourceAttr struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Resource string `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"`
+	Attr     *Path  `protobuf:"bytes,2,opt,name=attr,proto3" json:"attr,omitempty"`
+}
+
+func (x *PlanResourceAttr) Reset() {
+	*x = PlanResourceAttr{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_planfile_proto_msgTypes[10]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PlanResourceAttr) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PlanResourceAttr) ProtoMessage() {}
+
+func (x *PlanResourceAttr) ProtoReflect() protoreflect.Message {
+	mi := &file_planfile_proto_msgTypes[10]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PlanResourceAttr.ProtoReflect.Descriptor instead.
+func (*PlanResourceAttr) Descriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{0, 1}
+}
+
+func (x *PlanResourceAttr) GetResource() string {
+	if x != nil {
+		return x.Resource
+	}
+	return ""
+}
+
+func (x *PlanResourceAttr) GetAttr() *Path {
+	if x != nil {
+		return x.Attr
+	}
+	return nil
+}
+
+type CheckResults_ObjectResult struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	ObjectAddr      string              `protobuf:"bytes,1,opt,name=object_addr,json=objectAddr,proto3" json:"object_addr,omitempty"`
+	Status          CheckResults_Status `protobuf:"varint,2,opt,name=status,proto3,enum=tfplan.CheckResults_Status" json:"status,omitempty"`
+	FailureMessages []string            `protobuf:"bytes,3,rep,name=failure_messages,json=failureMessages,proto3" json:"failure_messages,omitempty"`
+}
+
+func (x *CheckResults_ObjectResult) Reset() {
+	*x = CheckResults_ObjectResult{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_planfile_proto_msgTypes[11]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CheckResults_ObjectResult) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CheckResults_ObjectResult) ProtoMessage() {}
+
+func (x *CheckResults_ObjectResult) ProtoReflect() protoreflect.Message {
+	mi := &file_planfile_proto_msgTypes[11]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CheckResults_ObjectResult.ProtoReflect.Descriptor instead.
+func (*CheckResults_ObjectResult) Descriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{5, 0}
+}
+
+func (x *CheckResults_ObjectResult) GetObjectAddr() string {
+	if x != nil {
+		return x.ObjectAddr
+	}
+	return ""
+}
+
+func (x *CheckResults_ObjectResult) GetStatus() CheckResults_Status {
+	if x != nil {
+		return x.Status
+	}
+	return CheckResults_UNKNOWN
+}
+
+func (x *CheckResults_ObjectResult) GetFailureMessages() []string {
+	if x != nil {
+		return x.FailureMessages
+	}
+	return nil
+}
+
+type Path_Step struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Types that are assignable to Selector:
+	//
+	//	*Path_Step_AttributeName
+	//	*Path_Step_ElementKey
+	Selector isPath_Step_Selector `protobuf_oneof:"selector"`
+}
+
+func (x *Path_Step) Reset() {
+	*x = Path_Step{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_planfile_proto_msgTypes[12]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Path_Step) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Path_Step) ProtoMessage() {}
+
+func (x *Path_Step) ProtoReflect() protoreflect.Message {
+	mi := &file_planfile_proto_msgTypes[12]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Path_Step.ProtoReflect.Descriptor instead.
+func (*Path_Step) Descriptor() ([]byte, []int) {
+	return file_planfile_proto_rawDescGZIP(), []int{7, 0}
+}
+
+func (m *Path_Step) GetSelector() isPath_Step_Selector {
+	if m != nil {
+		return m.Selector
+	}
+	return nil
+}
+
+func (x *Path_Step) GetAttributeName() string {
+	if x, ok := x.GetSelector().(*Path_Step_AttributeName); ok {
+		return x.AttributeName
+	}
+	return ""
+}
+
+func (x *Path_Step) GetElementKey() *DynamicValue {
+	if x, ok := x.GetSelector().(*Path_Step_ElementKey); ok {
+		return x.ElementKey
+	}
+	return nil
+}
+
+type isPath_Step_Selector interface {
+	isPath_Step_Selector()
+}
+
+type Path_Step_AttributeName struct {
+	// Set "attribute_name" to represent looking up an attribute
+	// in the current object value.
+	AttributeName string `protobuf:"bytes,1,opt,name=attribute_name,json=attributeName,proto3,oneof"`
+}
+
+type Path_Step_ElementKey struct {
+	// Set "element_key" to represent looking up an element in
+	// an indexable collection type.
+	ElementKey *DynamicValue `protobuf:"bytes,2,opt,name=element_key,json=elementKey,proto3,oneof"`
+}
+
+func (*Path_Step_AttributeName) isPath_Step_Selector() {}
+
+func (*Path_Step_ElementKey) isPath_Step_Selector() {}
+
+var File_planfile_proto protoreflect.FileDescriptor
+
+var file_planfile_proto_rawDesc = []byte{
+	0x0a, 0x0e, 0x70, 0x6c, 0x61, 0x6e, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x12, 0x06, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x22, 0xdf, 0x06, 0x0a, 0x04, 0x50, 0x6c, 0x61,
+	0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x07, 0x75,
+	0x69, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x74,
+	0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x06, 0x75, 0x69, 0x4d, 0x6f,
+	0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x65, 0x64, 0x18, 0x14, 0x20,
+	0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x65, 0x64, 0x12, 0x39, 0x0a, 0x09,
+	0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x1b, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x2e, 0x56, 0x61,
+	0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x76, 0x61,
+	0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x49, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75,
+	0x72, 0x63, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75,
+	0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67,
+	0x65, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67,
+	0x65, 0x73, 0x12, 0x45, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x64,
+	0x72, 0x69, 0x66, 0x74, 0x18, 0x12, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x61, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74,
+	0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f,
+	0x75, 0x72, 0x63, 0x65, 0x44, 0x72, 0x69, 0x66, 0x74, 0x12, 0x3b, 0x0a, 0x0e, 0x6f, 0x75, 0x74,
+	0x70, 0x75, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75,
+	0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0d, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x43,
+	0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x0d, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f,
+	0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e,
+	0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x75,
+	0x6c, 0x74, 0x73, 0x52, 0x0c, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
+	0x73, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72,
+	0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x41,
+	0x64, 0x64, 0x72, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65,
+	0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28,
+	0x09, 0x52, 0x11, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x41,
+	0x64, 0x64, 0x72, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x74, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72,
+	0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x10, 0x74, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
+	0x6e, 0x12, 0x29, 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x18, 0x0d, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x42, 0x61, 0x63, 0x6b,
+	0x65, 0x6e, 0x64, 0x52, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x12, 0x4b, 0x0a, 0x13,
+	0x72, 0x65, 0x6c, 0x65, 0x76, 0x61, 0x6e, 0x74, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
+	0x74, 0x65, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x66, 0x70, 0x6c,
+	0x61, 0x6e, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+	0x5f, 0x61, 0x74, 0x74, 0x72, 0x52, 0x12, 0x72, 0x65, 0x6c, 0x65, 0x76, 0x61, 0x6e, 0x74, 0x41,
+	0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d,
+	0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69,
+	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x1a, 0x52, 0x0a, 0x0e, 0x56, 0x61, 0x72, 0x69, 0x61,
+	0x62, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x61, 0x6e, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65,
+	0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4d, 0x0a, 0x0d, 0x72,
+	0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x12, 0x1a, 0x0a, 0x08,
+	0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+	0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x04, 0x61, 0x74, 0x74, 0x72,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e,
+	0x50, 0x61, 0x74, 0x68, 0x52, 0x04, 0x61, 0x74, 0x74, 0x72, 0x22, 0x69, 0x0a, 0x07, 0x42, 0x61,
+	0x63, 0x6b, 0x65, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2c, 0x0a, 0x06, 0x63, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, 0x70, 0x6c,
+	0x61, 0x6e, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52,
+	0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x73,
+	0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x77, 0x6f, 0x72, 0x6b,
+	0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0xc0, 0x02, 0x0a, 0x06, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65,
+	0x12, 0x26, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
+	0x32, 0x0e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+	0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75,
+	0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61,
+	0x6e, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x16, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65,
+	0x5f, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
+	0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e,
+	0x50, 0x61, 0x74, 0x68, 0x52, 0x14, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x53, 0x65, 0x6e, 0x73,
+	0x69, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x40, 0x0a, 0x15, 0x61, 0x66,
+	0x74, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61,
+	0x74, 0x68, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x66, 0x70, 0x6c,
+	0x61, 0x6e, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x52, 0x13, 0x61, 0x66, 0x74, 0x65, 0x72, 0x53, 0x65,
+	0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x2f, 0x0a, 0x09,
+	0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x11, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x69,
+	0x6e, 0x67, 0x52, 0x09, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x29, 0x0a,
+	0x10, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
+	0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74,
+	0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xd3, 0x02, 0x0a, 0x16, 0x52, 0x65, 0x73,
+	0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x61,
+	0x6e, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x70, 0x72, 0x65, 0x76, 0x5f,
+	0x72, 0x75, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
+	0x70, 0x72, 0x65, 0x76, 0x52, 0x75, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x64,
+	0x65, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0a, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08,
+	0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+	0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x06, 0x63, 0x68, 0x61, 0x6e,
+	0x67, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61,
+	0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
+	0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28,
+	0x0c, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x10, 0x72, 0x65,
+	0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x18, 0x0b,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x61,
+	0x74, 0x68, 0x52, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c,
+	0x61, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65,
+	0x61, 0x73, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x61, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74,
+	0x61, 0x6e, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e,
+	0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x68,
+	0x0a, 0x0c, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x12,
+	0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
+	0x6d, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e,
+	0x67, 0x65, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65,
+	0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73,
+	0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x22, 0xe8, 0x03, 0x0a, 0x0c, 0x43, 0x68, 0x65,
+	0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x33, 0x0a, 0x04, 0x6b, 0x69, 0x6e,
+	0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e,
+	0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x4f, 0x62,
+	0x6a, 0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x1f,
+	0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x41, 0x64, 0x64, 0x72, 0x12,
+	0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,
+	0x1b, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65,
+	0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74,
+	0x61, 0x74, 0x75, 0x73, 0x12, 0x3b, 0x0a, 0x07, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18,
+	0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43,
+	0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x4f, 0x62, 0x6a, 0x65,
+	0x63, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74,
+	0x73, 0x1a, 0x8f, 0x01, 0x0a, 0x0c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x75,
+	0x6c, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64,
+	0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41,
+	0x64, 0x64, 0x72, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43, 0x68, 0x65,
+	0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
+	0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x66, 0x61, 0x69, 0x6c,
+	0x75, 0x72, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03,
+	0x28, 0x09, 0x52, 0x0f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x73, 0x22, 0x34, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a,
+	0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x41,
+	0x53, 0x53, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x41, 0x49, 0x4c, 0x10, 0x02, 0x12, 0x09,
+	0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x22, 0x48, 0x0a, 0x0a, 0x4f, 0x62, 0x6a,
+	0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45,
+	0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x53, 0x4f,
+	0x55, 0x52, 0x43, 0x45, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54,
+	0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x48, 0x45, 0x43,
+	0x4b, 0x10, 0x03, 0x22, 0x28, 0x0a, 0x0c, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61,
+	0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x73, 0x67, 0x70, 0x61, 0x63, 0x6b, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x73, 0x67, 0x70, 0x61, 0x63, 0x6b, 0x22, 0xa5, 0x01,
+	0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x27, 0x0a, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x18,
+	0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50,
+	0x61, 0x74, 0x68, 0x2e, 0x53, 0x74, 0x65, 0x70, 0x52, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x1a,
+	0x74, 0x0a, 0x04, 0x53, 0x74, 0x65, 0x70, 0x12, 0x27, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69,
+	0x62, 0x75, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48,
+	0x00, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65,
+	0x12, 0x37, 0x0a, 0x0b, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x44,
+	0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x65,
+	0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x0a, 0x0a, 0x08, 0x73, 0x65, 0x6c,
+	0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x1b, 0x0a, 0x09, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x69,
+	0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02,
+	0x69, 0x64, 0x2a, 0x31, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f,
+	0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4f,
+	0x59, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x46, 0x52, 0x45, 0x53, 0x48, 0x5f, 0x4f,
+	0x4e, 0x4c, 0x59, 0x10, 0x02, 0x2a, 0x70, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12,
+	0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4f, 0x50, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x52, 0x45,
+	0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x52, 0x45, 0x41, 0x44, 0x10, 0x02, 0x12,
+	0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x44,
+	0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x45, 0x4c, 0x45, 0x54,
+	0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x06, 0x12,
+	0x16, 0x0a, 0x12, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f, 0x44,
+	0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x07, 0x2a, 0xc8, 0x03, 0x0a, 0x1c, 0x52, 0x65, 0x73, 0x6f,
+	0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69,
+	0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45,
+	0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x45,
+	0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x54, 0x41, 0x49, 0x4e, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12,
+	0x16, 0x0a, 0x12, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x59, 0x5f, 0x52, 0x45,
+	0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x52, 0x45, 0x50, 0x4c, 0x41,
+	0x43, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x41, 0x4e, 0x4e, 0x4f,
+	0x54, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x03, 0x12, 0x25, 0x0a, 0x21, 0x44, 0x45,
+	0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x4e, 0x4f, 0x5f,
+	0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10,
+	0x04, 0x12, 0x23, 0x0a, 0x1f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41,
+	0x55, 0x53, 0x45, 0x5f, 0x57, 0x52, 0x4f, 0x4e, 0x47, 0x5f, 0x52, 0x45, 0x50, 0x45, 0x54, 0x49,
+	0x54, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x12, 0x1e, 0x0a, 0x1a, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45,
+	0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x49,
+	0x4e, 0x44, 0x45, 0x58, 0x10, 0x06, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45,
+	0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x45, 0x41, 0x43, 0x48, 0x5f, 0x4b, 0x45,
+	0x59, 0x10, 0x07, 0x12, 0x1c, 0x0a, 0x18, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45,
+	0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x4f, 0x44, 0x55, 0x4c, 0x45, 0x10,
+	0x08, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x59, 0x5f,
+	0x54, 0x52, 0x49, 0x47, 0x47, 0x45, 0x52, 0x53, 0x10, 0x09, 0x12, 0x1f, 0x0a, 0x1b, 0x52, 0x45,
+	0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49,
+	0x47, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x0a, 0x12, 0x23, 0x0a, 0x1f, 0x52,
+	0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x44, 0x45, 0x50, 0x45,
+	0x4e, 0x44, 0x45, 0x4e, 0x43, 0x59, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x0b,
+	0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45,
+	0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x5f, 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, 0x10, 0x0d, 0x12,
+	0x21, 0x0a, 0x1d, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53,
+	0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x4f, 0x56, 0x45, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54,
+	0x10, 0x0c, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+	0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x74, 0x65, 0x72, 0x72, 0x61,
+	0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x6c,
+	0x61, 0x6e, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x6c, 0x61,
+	0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_planfile_proto_rawDescOnce sync.Once
+	file_planfile_proto_rawDescData = file_planfile_proto_rawDesc
+)
+
+func file_planfile_proto_rawDescGZIP() []byte {
+	file_planfile_proto_rawDescOnce.Do(func() {
+		file_planfile_proto_rawDescData = protoimpl.X.CompressGZIP(file_planfile_proto_rawDescData)
+	})
+	return file_planfile_proto_rawDescData
+}
+
+var file_planfile_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
+var file_planfile_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
+var file_planfile_proto_goTypes = []interface{}{
+	(Mode)(0),                         // 0: tfplan.Mode
+	(Action)(0),                       // 1: tfplan.Action
+	(ResourceInstanceActionReason)(0), // 2: tfplan.ResourceInstanceActionReason
+	(CheckResults_Status)(0),          // 3: tfplan.CheckResults.Status
+	(CheckResults_ObjectKind)(0),      // 4: tfplan.CheckResults.ObjectKind
+	(*Plan)(nil),                      // 5: tfplan.Plan
+	(*Backend)(nil),                   // 6: tfplan.Backend
+	(*Change)(nil),                    // 7: tfplan.Change
+	(*ResourceInstanceChange)(nil),    // 8: tfplan.ResourceInstanceChange
+	(*OutputChange)(nil),              // 9: tfplan.OutputChange
+	(*CheckResults)(nil),              // 10: tfplan.CheckResults
+	(*DynamicValue)(nil),              // 11: tfplan.DynamicValue
+	(*Path)(nil),                      // 12: tfplan.Path
+	(*Importing)(nil),                 // 13: tfplan.Importing
+	nil,                               // 14: tfplan.Plan.VariablesEntry
+	(*PlanResourceAttr)(nil),          // 15: tfplan.Plan.resource_attr
+	(*CheckResults_ObjectResult)(nil), // 16: tfplan.CheckResults.ObjectResult
+	(*Path_Step)(nil),                 // 17: tfplan.Path.Step
+}
+var file_planfile_proto_depIdxs = []int32{
+	0,  // 0: tfplan.Plan.ui_mode:type_name -> tfplan.Mode
+	14, // 1: tfplan.Plan.variables:type_name -> tfplan.Plan.VariablesEntry
+	8,  // 2: tfplan.Plan.resource_changes:type_name -> tfplan.ResourceInstanceChange
+	8,  // 3: tfplan.Plan.resource_drift:type_name -> tfplan.ResourceInstanceChange
+	9,  // 4: tfplan.Plan.output_changes:type_name -> tfplan.OutputChange
+	10, // 5: tfplan.Plan.check_results:type_name -> tfplan.CheckResults
+	6,  // 6: tfplan.Plan.backend:type_name -> tfplan.Backend
+	15, // 7: tfplan.Plan.relevant_attributes:type_name -> tfplan.Plan.resource_attr
+	11, // 8: tfplan.Backend.config:type_name -> tfplan.DynamicValue
+	1,  // 9: tfplan.Change.action:type_name -> tfplan.Action
+	11, // 10: tfplan.Change.values:type_name -> tfplan.DynamicValue
+	12, // 11: tfplan.Change.before_sensitive_paths:type_name -> tfplan.Path
+	12, // 12: tfplan.Change.after_sensitive_paths:type_name -> tfplan.Path
+	13, // 13: tfplan.Change.importing:type_name -> tfplan.Importing
+	7,  // 14: tfplan.ResourceInstanceChange.change:type_name -> tfplan.Change
+	12, // 15: tfplan.ResourceInstanceChange.required_replace:type_name -> tfplan.Path
+	2,  // 16: tfplan.ResourceInstanceChange.action_reason:type_name -> tfplan.ResourceInstanceActionReason
+	7,  // 17: tfplan.OutputChange.change:type_name -> tfplan.Change
+	4,  // 18: tfplan.CheckResults.kind:type_name -> tfplan.CheckResults.ObjectKind
+	3,  // 19: tfplan.CheckResults.status:type_name -> tfplan.CheckResults.Status
+	16, // 20: tfplan.CheckResults.objects:type_name -> tfplan.CheckResults.ObjectResult
+	17, // 21: tfplan.Path.steps:type_name -> tfplan.Path.Step
+	11, // 22: tfplan.Plan.VariablesEntry.value:type_name -> tfplan.DynamicValue
+	12, // 23: tfplan.Plan.resource_attr.attr:type_name -> tfplan.Path
+	3,  // 24: tfplan.CheckResults.ObjectResult.status:type_name -> tfplan.CheckResults.Status
+	11, // 25: tfplan.Path.Step.element_key:type_name -> tfplan.DynamicValue
+	26, // [26:26] is the sub-list for method output_type
+	26, // [26:26] is the sub-list for method input_type
+	26, // [26:26] is the sub-list for extension type_name
+	26, // [26:26] is the sub-list for extension extendee
+	0,  // [0:26] is the sub-list for field type_name
+}
+
+func init() { file_planfile_proto_init() }
+func file_planfile_proto_init() {
+	if File_planfile_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_planfile_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Plan); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_planfile_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Backend); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_planfile_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Change); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_planfile_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ResourceInstanceChange); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_planfile_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*OutputChange); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_planfile_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CheckResults); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_planfile_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DynamicValue); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_planfile_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Path); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_planfile_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Importing); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_planfile_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*PlanResourceAttr); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_planfile_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CheckResults_ObjectResult); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_planfile_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Path_Step); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	file_planfile_proto_msgTypes[12].OneofWrappers = []interface{}{
+		(*Path_Step_AttributeName)(nil),
+		(*Path_Step_ElementKey)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_planfile_proto_rawDesc,
+			NumEnums:      5,
+			NumMessages:   13,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_planfile_proto_goTypes,
+		DependencyIndexes: file_planfile_proto_depIdxs,
+		EnumInfos:         file_planfile_proto_enumTypes,
+		MessageInfos:      file_planfile_proto_msgTypes,
+	}.Build()
+	File_planfile_proto = out.File
+	file_planfile_proto_rawDesc = nil
+	file_planfile_proto_goTypes = nil
+	file_planfile_proto_depIdxs = nil
+}
diff --git a/v1.5.7/internal/plans/internal/planproto/planfile.proto b/v1.5.7/internal/plans/internal/planproto/planfile.proto
new file mode 100644
index 0000000..47b5478
--- /dev/null
+++ b/v1.5.7/internal/plans/internal/planproto/planfile.proto
@@ -0,0 +1,317 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+syntax = "proto3";
+package tfplan;
+
+// For Terraform's own parsing, the proto stub types go into an internal Go
+// package. The public API is in github.com/hashicorp/terraform/plans/planfile .
+option go_package = "github.com/hashicorp/terraform/internal/plans/internal/planproto";
+
+// Plan is the root message type for the tfplan file
+message Plan {
+    // Version is incremented whenever there is a breaking change to
+    // the serialization format. Programs reading serialized plans should
+    // verify that version is set to the expected value and abort processing
+    // if not. A breaking change is any change that may cause an older
+    // consumer to interpret the structure incorrectly. This number will
+    // not be incremented if an existing consumer can either safely ignore
+    // changes to the format or if an existing consumer would fail to process
+    // the file for another message- or field-specific reason.
+    uint64 version = 1;
+
+    // The mode that was active when this plan was created.
+    //
+    // This is saved only for UI purposes, so that Terraform can tailor its
+    // rendering of the plan depending on the mode. This must never be used to
+    // make decisions in Terraform Core during the applying of a plan.
+    Mode ui_mode = 17;
+
+    // Errored is true for any plan whose creation was interrupted by an
+    // error. A plan with this flag set cannot be applied, and the changes
+    // it proposes are likely to be incomplete.
+    bool errored = 20;
+
+    // The variables that were set when creating the plan. Each value is
+    // a msgpack serialization of an HCL value.
+    map<string, DynamicValue> variables = 2;
+
+    // An unordered set of proposed changes to resources throughout the
+    // configuration, including any nested modules. Use the address of
+    // each resource to determine which module it belongs to.
+    repeated ResourceInstanceChange resource_changes = 3;
+
+    // An unordered set of detected drift: changes made to resources outside of
+    // Terraform, computed by comparing the previous run's state to the state
+    // after refresh.
+    repeated ResourceInstanceChange resource_drift = 18;
+
+    // An unordered set of proposed changes to outputs in the root module
+    // of the configuration. This set also includes "no action" changes for
+    // outputs that are not changing, as context for detecting inconsistencies
+    // at apply time.
+    repeated OutputChange output_changes = 4;
+
+    // An unordered set of check results for the entire configuration.
+    //
+    // Each element represents a single static configuration object that has
+    // checks, and each of those may have zero or more dynamic objects that
+    // the checks were applied to nested within.
+    repeated CheckResults check_results = 19;
+
+    // An unordered set of target addresses to include when applying. If no
+    // target addresses are present, the plan applies to the whole
+    // configuration.
+    repeated string target_addrs = 5;
+
+    // An unordered set of force-replace addresses to include when applying.
+    // This must match the set of addresses that was used when creating the
+    // plan, or else applying the plan will fail when it reaches a different
+    // conclusion about what action a particular resource instance needs.
+    repeated string force_replace_addrs = 16;
+
+    // The version string for the Terraform binary that created this plan.
+    string terraform_version = 14;
+
+    // Backend is a description of the backend configuration and other related
+    // settings at the time the plan was created.
+    Backend backend = 13;
+
+    message resource_attr {
+       string resource = 1;
+       Path attr= 2;
+    };
+
+    // RelevantAttributes lists individual resource attributes from
+    // ResourceDrift which may have contributed to the plan changes.
+    repeated resource_attr relevant_attributes = 15;
+
+    // timestamp is the record of truth for when the plan happened.
+    string timestamp = 21;
+}
+
+// Mode describes the planning mode that created the plan.
+enum Mode {
+    NORMAL = 0;
+    DESTROY = 1;
+    REFRESH_ONLY = 2;
+}
+
+// Backend is a description of backend configuration and other related settings.
+message Backend {
+    string type = 1;
+    DynamicValue config = 2;
+    string workspace = 3;
+}
+
+// Action describes the type of action planned for an object.
+// Not all action values are valid for all object types.
+enum Action {
+    NOOP = 0;
+    CREATE = 1;
+    READ = 2;
+    UPDATE = 3;
+    DELETE = 5;
+    DELETE_THEN_CREATE = 6;
+    CREATE_THEN_DELETE = 7;
+}
+
+// Change represents a change made to some object, transforming it from an old
+// state to a new state.
+message Change {
+    // Not all action values are valid for all object types. Consult
+    // the documentation for any message that embeds Change.
+    Action action = 1;
+
+    // msgpack-encoded HCL values involved in the change.
+    // - For update and replace, two values are provided that give the old and new values,
+    //   respectively.
+    // - For create, one value is provided that gives the new value to be created
+    // - For delete, one value is provided that describes the value being deleted
+    // - For read, two values are provided that give the prior value for this object
+    //   (or null, if no prior value exists) and the value that was or will be read,
+    //   respectively.
+    // - For no-op, one value is provided that is left unmodified by this non-change.
+    repeated DynamicValue values = 2;
+
+    // An unordered set of paths into the old value which are marked as
+    // sensitive. Values at these paths should be obscured in human-readable
+    // output. This set is always empty for create.
+    repeated Path before_sensitive_paths = 3;
+
+    // An unordered set of paths into the new value which are marked as
+    // sensitive. Values at these paths should be obscured in human-readable
+    // output. This set is always empty for delete.
+    repeated Path after_sensitive_paths = 4;
+
+    // Importing, if true, specifies that the resource is being imported as part
+    // of the change.
+    Importing importing = 5;
+
+    // GeneratedConfig contains any configuration that was generated as part of
+    // the change, as an HCL string.
+    string generated_config = 6;
+}
+
+// ResourceInstanceActionReason sometimes provides some additional user-facing
+// context for why a particular action was chosen for a resource instance.
+// This is for user feedback only and never used to drive behavior during the
+// subsequent apply step.
+enum ResourceInstanceActionReason {
+    NONE = 0;
+    REPLACE_BECAUSE_TAINTED = 1;
+    REPLACE_BY_REQUEST = 2;
+    REPLACE_BECAUSE_CANNOT_UPDATE = 3;
+    DELETE_BECAUSE_NO_RESOURCE_CONFIG = 4;
+    DELETE_BECAUSE_WRONG_REPETITION = 5;
+    DELETE_BECAUSE_COUNT_INDEX = 6;
+    DELETE_BECAUSE_EACH_KEY = 7;
+    DELETE_BECAUSE_NO_MODULE = 8;
+    REPLACE_BY_TRIGGERS = 9;
+    READ_BECAUSE_CONFIG_UNKNOWN = 10;
+    READ_BECAUSE_DEPENDENCY_PENDING = 11;
+    READ_BECAUSE_CHECK_NESTED = 13;
+    DELETE_BECAUSE_NO_MOVE_TARGET = 12;
+}
+
+message ResourceInstanceChange {
+    // addr is a string representation of the resource instance address that
+    // this change will apply to.
+    string addr = 13;
+
+    // prev_run_addr is a string representation of the address at which
+    // this resource instance was tracked during the previous apply operation.
+    //
+    // This is populated only if it would be different from addr due to
+    // Terraform having reacted to refactoring annotations in the configuration.
+    // If empty, the previous run address is the same as the current address.
+    string prev_run_addr = 14;
+
+    // NOTE: Earlier versions of this format had fields 1 through 6 describing
+    // various indivdual parts of "addr". We're now using our standard compact
+    // string representation to capture the same information. We don't support
+    // preserving plan files from one Terraform version to the next, so we
+    // no longer declare nor accept those fields.
+
+    // deposed_key, if set, indicates that this change applies to a deposed
+    // object for the indicated instance with the given deposed key. If not
+    // set, the change applies to the instance's current object.
+    string deposed_key = 7;
+
+    // provider is the address of the provider configuration that this change
+    // was planned with, and thus the configuration that must be used to
+    // apply it.
+    string provider = 8;
+
+    // Description of the proposed change. May use "create", "read", "update",
+    // "replace", "delete" and "no-op" actions.
+    Change change = 9;
+
+    // raw blob value provided by the provider as additional context for the
+    // change. Must be considered an opaque value for any consumer other than
+    // the provider that generated it, and will be returned verbatim to the
+    // provider during the subsequent apply operation.
+    bytes private = 10;
+
+    // An unordered set of paths that prompted the change action to be
+    // "replace" rather than "update". Empty for any action other than
+    // "replace".
+    repeated Path required_replace = 11;
+
+    // Optional extra user-oriented context for why change.Action was chosen.
+    // This is for user feedback only and never used to drive behavior during
+    // apply.
+    ResourceInstanceActionReason action_reason = 12;
+}
+
+message OutputChange {
+    // Name of the output as defined in the root module.
+    string name = 1;
+
+    // Description of the proposed change. May use "no-op", "create",
+    // "update" and "delete" actions.
+    Change change = 2;
+
+    // Sensitive, if true, indicates that one or more of the values given
+    // in "change" is sensitive and should not be shown directly in any
+    // rendered plan.
+    bool sensitive = 3;
+}
+
+message CheckResults {
+    // Status describes the status of a particular checkable object at the
+    // completion of the plan.
+    enum Status {
+        UNKNOWN = 0;
+        PASS    = 1;
+        FAIL    = 2;
+        ERROR   = 3;
+    }
+
+    enum ObjectKind {
+        UNSPECIFIED = 0;
+        RESOURCE = 1;
+        OUTPUT_VALUE = 2;
+        CHECK = 3;
+    }
+
+    message ObjectResult {
+        string object_addr = 1;
+        Status status = 2;
+        repeated string failure_messages = 3;
+    }
+
+    ObjectKind kind = 1;
+
+    // Address of the configuration object that declared the checks.
+    string config_addr = 2;
+
+    // The aggregate status of the entire configuration object, based on
+    // the statuses of its zero or more checkable objects.
+    Status status = 3;
+
+    // The results for individual objects that were declared by the
+    // configuration object named in config_addr.
+    repeated ObjectResult objects = 4;
+}
+
+// DynamicValue represents a value whose type is not decided until runtime,
+// often based on schema information obtained from a plugin.
+//
+// At present dynamic values are always encoded as msgpack, with extension
+// id 0 used to represent the special "unknown" value indicating results
+// that won't be known until after apply.
+//
+// In future other serialization formats may be used, possibly with a
+// transitional period of including both as separate attributes of this type.
+// Consumers must ignore attributes they don't support and fail if no supported
+// attribute is present. The top-level format version will not be incremented
+// for changes to the set of dynamic serialization formats.
+message DynamicValue {
+    bytes msgpack = 1;
+}
+
+// Path represents a set of steps to traverse into a data structure. It is
+// used to refer to a sub-structure within a dynamic data structure presented
+// separately.
+message Path {
+    message Step {
+        oneof selector {
+            // Set "attribute_name" to represent looking up an attribute
+            // in the current object value.
+            string attribute_name = 1;
+
+            // Set "element_key" to represent looking up an element in
+            // an indexable collection type.
+            DynamicValue element_key = 2;
+        }
+    }
+    repeated Step steps = 1;
+}
+
+// Importing contains the embedded metadata about the import operation if this
+// change describes it.
+message Importing {
+    // The original ID of the resource.
+    string id = 1;
+}
diff --git a/v1.5.7/internal/plans/mode.go b/v1.5.7/internal/plans/mode.go
new file mode 100644
index 0000000..176318b
--- /dev/null
+++ b/v1.5.7/internal/plans/mode.go
@@ -0,0 +1,34 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plans
+
+// Mode represents the various mutually-exclusive modes for creating a plan.
+type Mode rune
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type Mode
+
+const (
+	// NormalMode is the default planning mode, which aims to synchronize the
+	// prior state with remote objects and plan a set of actions intended to
+	// make those remote objects better match the current configuration.
+	NormalMode Mode = 0
+
+	// DestroyMode is a special planning mode for situations where the goal
+	// is to destroy all remote objects that are bound to instances in the
+	// prior state, even if the configuration for those instances is still
+	// present.
+	//
+	// This mode corresponds with the "-destroy" option to "terraform plan",
+	// and with the plan created by the "terraform destroy" command.
+	DestroyMode Mode = 'D'
+
+	// RefreshOnlyMode is a special planning mode which only performs the
+	// synchronization of prior state with remote objects, and skips any
+	// effort to generate any change actions for resource instances even if
+	// the configuration has changed relative to the state.
+	//
+	// This mode corresponds with the "-refresh-only" option to
+	// "terraform plan".
+	RefreshOnlyMode Mode = 'R'
+)
diff --git a/v1.5.7/internal/plans/mode_string.go b/v1.5.7/internal/plans/mode_string.go
new file mode 100644
index 0000000..f1757e8
--- /dev/null
+++ b/v1.5.7/internal/plans/mode_string.go
@@ -0,0 +1,33 @@
+// Code generated by "stringer -type Mode"; DO NOT EDIT.
+
+package plans
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[NormalMode-0]
+	_ = x[DestroyMode-68]
+	_ = x[RefreshOnlyMode-82]
+}
+
+const (
+	_Mode_name_0 = "NormalMode"
+	_Mode_name_1 = "DestroyMode"
+	_Mode_name_2 = "RefreshOnlyMode"
+)
+
+func (i Mode) String() string {
+	switch {
+	case i == 0:
+		return _Mode_name_0
+	case i == 68:
+		return _Mode_name_1
+	case i == 82:
+		return _Mode_name_2
+	default:
+		return "Mode(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/v1.5.7/internal/plans/objchange/compatible.go b/v1.5.7/internal/plans/objchange/compatible.go
new file mode 100644
index 0000000..c6f0c2b
--- /dev/null
+++ b/v1.5.7/internal/plans/objchange/compatible.go
@@ -0,0 +1,376 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package objchange
+
+import (
+	"fmt"
+	"strconv"
+
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/convert"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+)
+
+// AssertObjectCompatible checks whether the given "actual" value is a valid
+// completion of the possibly-partially-unknown "planned" value.
+//
+// This means that any known leaf value in "planned" must be equal to the
+// corresponding value in "actual", and various other similar constraints.
+//
+// Any inconsistencies are reported by returning a non-zero number of errors.
+// These errors are usually (but not necessarily) cty.PathError values
+// referring to a particular nested value within the "actual" value.
+//
+// The two values must have types that conform to the given schema's implied
+// type, or this function will panic.
+func AssertObjectCompatible(schema *configschema.Block, planned, actual cty.Value) []error {
+	return assertObjectCompatible(schema, planned, actual, nil)
+}
+
+func assertObjectCompatible(schema *configschema.Block, planned, actual cty.Value, path cty.Path) []error {
+	var errs []error
+	var atRoot string
+	if len(path) == 0 {
+		atRoot = "Root resource "
+	}
+
+	if planned.IsNull() && !actual.IsNull() {
+		errs = append(errs, path.NewErrorf(fmt.Sprintf("%swas absent, but now present", atRoot)))
+		return errs
+	}
+	if actual.IsNull() && !planned.IsNull() {
+		errs = append(errs, path.NewErrorf(fmt.Sprintf("%swas present, but now absent", atRoot)))
+		return errs
+	}
+	if planned.IsNull() {
+		// No further checks possible if both values are null
+		return errs
+	}
+
+	for name, attrS := range schema.Attributes {
+		plannedV := planned.GetAttr(name)
+		actualV := actual.GetAttr(name)
+
+		path := append(path, cty.GetAttrStep{Name: name})
+
+		// Unmark values here before checking value assertions,
+		// but save the marks so we can see if we should supress
+		// exposing a value through errors
+		unmarkedActualV, marksA := actualV.UnmarkDeep()
+		unmarkedPlannedV, marksP := plannedV.UnmarkDeep()
+		_, isSensitiveActual := marksA[marks.Sensitive]
+		_, isSensitivePlanned := marksP[marks.Sensitive]
+
+		moreErrs := assertValueCompatible(unmarkedPlannedV, unmarkedActualV, path)
+		if attrS.Sensitive || isSensitiveActual || isSensitivePlanned {
+			if len(moreErrs) > 0 {
+				// Use a vague placeholder message instead, to avoid disclosing
+				// sensitive information.
+				errs = append(errs, path.NewErrorf("inconsistent values for sensitive attribute"))
+			}
+		} else {
+			errs = append(errs, moreErrs...)
+		}
+	}
+	for name, blockS := range schema.BlockTypes {
+		plannedV, _ := planned.GetAttr(name).Unmark()
+		actualV, _ := actual.GetAttr(name).Unmark()
+
+		path := append(path, cty.GetAttrStep{Name: name})
+		switch blockS.Nesting {
+		case configschema.NestingSingle, configschema.NestingGroup:
+			// If an unknown block placeholder was present then the placeholder
+			// may have expanded out into zero blocks, which is okay.
+			if !plannedV.IsKnown() && actualV.IsNull() {
+				continue
+			}
+			moreErrs := assertObjectCompatible(&blockS.Block, plannedV, actualV, path)
+			errs = append(errs, moreErrs...)
+		case configschema.NestingList:
+			// A NestingList might either be a list or a tuple, depending on
+			// whether there are dynamically-typed attributes inside. However,
+			// both support a similar-enough API that we can treat them the
+			// same for our purposes here.
+			if !plannedV.IsKnown() || !actualV.IsKnown() || plannedV.IsNull() || actualV.IsNull() {
+				continue
+			}
+
+			plannedL := plannedV.LengthInt()
+			actualL := actualV.LengthInt()
+			if plannedL != actualL {
+				errs = append(errs, path.NewErrorf("block count changed from %d to %d", plannedL, actualL))
+				continue
+			}
+			for it := plannedV.ElementIterator(); it.Next(); {
+				idx, plannedEV := it.Element()
+				if !actualV.HasIndex(idx).True() {
+					continue
+				}
+				actualEV := actualV.Index(idx)
+				moreErrs := assertObjectCompatible(&blockS.Block, plannedEV, actualEV, append(path, cty.IndexStep{Key: idx}))
+				errs = append(errs, moreErrs...)
+			}
+		case configschema.NestingMap:
+			// A NestingMap might either be a map or an object, depending on
+			// whether there are dynamically-typed attributes inside, but
+			// that's decided statically and so both values will have the same
+			// kind.
+			if plannedV.Type().IsObjectType() {
+				plannedAtys := plannedV.Type().AttributeTypes()
+				actualAtys := actualV.Type().AttributeTypes()
+				for k := range plannedAtys {
+					if _, ok := actualAtys[k]; !ok {
+						errs = append(errs, path.NewErrorf("block key %q has vanished", k))
+						continue
+					}
+
+					plannedEV := plannedV.GetAttr(k)
+					actualEV := actualV.GetAttr(k)
+					moreErrs := assertObjectCompatible(&blockS.Block, plannedEV, actualEV, append(path, cty.GetAttrStep{Name: k}))
+					errs = append(errs, moreErrs...)
+				}
+				if plannedV.IsKnown() { // new blocks may appear if unknown blocks were present in the plan
+					for k := range actualAtys {
+						if _, ok := plannedAtys[k]; !ok {
+							errs = append(errs, path.NewErrorf("new block key %q has appeared", k))
+							continue
+						}
+					}
+				}
+			} else {
+				if !plannedV.IsKnown() || plannedV.IsNull() || actualV.IsNull() {
+					continue
+				}
+				plannedL := plannedV.LengthInt()
+				actualL := actualV.LengthInt()
+				if plannedL != actualL && plannedV.IsKnown() { // new blocks may appear if unknown blocks were persent in the plan
+					errs = append(errs, path.NewErrorf("block count changed from %d to %d", plannedL, actualL))
+					continue
+				}
+				for it := plannedV.ElementIterator(); it.Next(); {
+					idx, plannedEV := it.Element()
+					if !actualV.HasIndex(idx).True() {
+						continue
+					}
+					actualEV := actualV.Index(idx)
+					moreErrs := assertObjectCompatible(&blockS.Block, plannedEV, actualEV, append(path, cty.IndexStep{Key: idx}))
+					errs = append(errs, moreErrs...)
+				}
+			}
+		case configschema.NestingSet:
+			if !plannedV.IsKnown() || !actualV.IsKnown() || plannedV.IsNull() || actualV.IsNull() {
+				continue
+			}
+
+			if !plannedV.IsKnown() {
+				// When unknown blocks are present the final number of blocks
+				// may be different, either because the unknown set values
+				// become equal and are collapsed, or the count is unknown due
+				// a dynamic block. Unfortunately this means we can't do our
+				// usual checks in this case without generating false
+				// negatives.
+				continue
+			}
+
+			setErrs := assertSetValuesCompatible(plannedV, actualV, path, func(plannedEV, actualEV cty.Value) bool {
+				errs := assertObjectCompatible(&blockS.Block, plannedEV, actualEV, append(path, cty.IndexStep{Key: actualEV}))
+				return len(errs) == 0
+			})
+			errs = append(errs, setErrs...)
+
+			// There can be fewer elements in a set after its elements are all
+			// known (values that turn out to be equal will coalesce) but the
+			// number of elements must never get larger.
+			plannedL := plannedV.LengthInt()
+			actualL := actualV.LengthInt()
+			if plannedL < actualL {
+				errs = append(errs, path.NewErrorf("block set length changed from %d to %d", plannedL, actualL))
+			}
+		default:
+			panic(fmt.Sprintf("unsupported nesting mode %s", blockS.Nesting))
+		}
+	}
+	return errs
+}
+
+func assertValueCompatible(planned, actual cty.Value, path cty.Path) []error {
+	// NOTE: We don't normally use the GoString rendering of cty.Value in
+	// user-facing error messages as a rule, but we make an exception
+	// for this function because we expect the user to pass this message on
+	// verbatim to the provider development team and so more detail is better.
+
+	var errs []error
+	if planned.Type() == cty.DynamicPseudoType {
+		// Anything goes, then
+		return errs
+	}
+	if problems := actual.Type().TestConformance(planned.Type()); len(problems) > 0 {
+		errs = append(errs, path.NewErrorf("wrong final value type: %s", convert.MismatchMessage(actual.Type(), planned.Type())))
+		// If the types don't match then we can't do any other comparisons,
+		// so we bail early.
+		return errs
+	}
+
+	if !planned.IsKnown() {
+		// We didn't know what were going to end up with during plan, so
+		// anything goes during apply.
+		return errs
+	}
+
+	if actual.IsNull() {
+		if planned.IsNull() {
+			return nil
+		}
+		errs = append(errs, path.NewErrorf("was %#v, but now null", planned))
+		return errs
+	}
+	if planned.IsNull() {
+		errs = append(errs, path.NewErrorf("was null, but now %#v", actual))
+		return errs
+	}
+
+	ty := planned.Type()
+	switch {
+
+	case !actual.IsKnown():
+		errs = append(errs, path.NewErrorf("was known, but now unknown"))
+
+	case ty.IsPrimitiveType():
+		if !actual.Equals(planned).True() {
+			errs = append(errs, path.NewErrorf("was %#v, but now %#v", planned, actual))
+		}
+
+	case ty.IsListType() || ty.IsMapType() || ty.IsTupleType():
+		for it := planned.ElementIterator(); it.Next(); {
+			k, plannedV := it.Element()
+			if !actual.HasIndex(k).True() {
+				errs = append(errs, path.NewErrorf("element %s has vanished", indexStrForErrors(k)))
+				continue
+			}
+
+			actualV := actual.Index(k)
+			moreErrs := assertValueCompatible(plannedV, actualV, append(path, cty.IndexStep{Key: k}))
+			errs = append(errs, moreErrs...)
+		}
+
+		for it := actual.ElementIterator(); it.Next(); {
+			k, _ := it.Element()
+			if !planned.HasIndex(k).True() {
+				errs = append(errs, path.NewErrorf("new element %s has appeared", indexStrForErrors(k)))
+			}
+		}
+
+	case ty.IsObjectType():
+		atys := ty.AttributeTypes()
+		for name := range atys {
+			// Because we already tested that the two values have the same type,
+			// we can assume that the same attributes are present in both and
+			// focus just on testing their values.
+			plannedV := planned.GetAttr(name)
+			actualV := actual.GetAttr(name)
+			moreErrs := assertValueCompatible(plannedV, actualV, append(path, cty.GetAttrStep{Name: name}))
+			errs = append(errs, moreErrs...)
+		}
+
+	case ty.IsSetType():
+		// We can't really do anything useful for sets here because changing
+		// an unknown element to known changes the identity of the element, and
+		// so we can't correlate them properly. However, we will at least check
+		// to ensure that the number of elements is consistent, along with
+		// the general type-match checks we ran earlier in this function.
+		if planned.IsKnown() && !planned.IsNull() && !actual.IsNull() {
+
+			setErrs := assertSetValuesCompatible(planned, actual, path, func(plannedV, actualV cty.Value) bool {
+				errs := assertValueCompatible(plannedV, actualV, append(path, cty.IndexStep{Key: actualV}))
+				return len(errs) == 0
+			})
+			errs = append(errs, setErrs...)
+
+			// There can be fewer elements in a set after its elements are all
+			// known (values that turn out to be equal will coalesce) but the
+			// number of elements must never get larger.
+
+			plannedL := planned.LengthInt()
+			actualL := actual.LengthInt()
+			if plannedL < actualL {
+				errs = append(errs, path.NewErrorf("length changed from %d to %d", plannedL, actualL))
+			}
+		}
+	}
+
+	return errs
+}
+
+func indexStrForErrors(v cty.Value) string {
+	switch v.Type() {
+	case cty.Number:
+		return v.AsBigFloat().Text('f', -1)
+	case cty.String:
+		return strconv.Quote(v.AsString())
+	default:
+		// Should be impossible, since no other index types are allowed!
+		return fmt.Sprintf("%#v", v)
+	}
+}
+
+// assertSetValuesCompatible checks that each of the elements in a can
+// be correlated with at least one equivalent element in b and vice-versa,
+// using the given correlation function.
+//
+// This allows the number of elements in the sets to change as long as all
+// elements in both sets can be correlated, making this function safe to use
+// with sets that may contain unknown values as long as the unknown case is
+// addressed in some reasonable way in the callback function.
+//
+// The callback always recieves values from set a as its first argument and
+// values from set b in its second argument, so it is safe to use with
+// non-commutative functions.
+//
+// As with assertValueCompatible, we assume that the target audience of error
+// messages here is a provider developer (via a bug report from a user) and so
+// we intentionally violate our usual rule of keeping cty implementation
+// details out of error messages.
+func assertSetValuesCompatible(planned, actual cty.Value, path cty.Path, f func(aVal, bVal cty.Value) bool) []error {
+	a := planned
+	b := actual
+
+	// Our methodology here is a little tricky, to deal with the fact that
+	// it's impossible to directly correlate two non-equal set elements because
+	// they don't have identities separate from their values.
+	// The approach is to count the number of equivalent elements each element
+	// of a has in b and vice-versa, and then return true only if each element
+	// in both sets has at least one equivalent.
+	as := a.AsValueSlice()
+	bs := b.AsValueSlice()
+	aeqs := make([]bool, len(as))
+	beqs := make([]bool, len(bs))
+	for ai, av := range as {
+		for bi, bv := range bs {
+			if f(av, bv) {
+				aeqs[ai] = true
+				beqs[bi] = true
+			}
+		}
+	}
+
+	var errs []error
+	for i, eq := range aeqs {
+		if !eq {
+			errs = append(errs, path.NewErrorf("planned set element %#v does not correlate with any element in actual", as[i]))
+		}
+	}
+	if len(errs) > 0 {
+		// Exit early since otherwise we're likely to generate duplicate
+		// error messages from the other perspective in the subsequent loop.
+		return errs
+	}
+	for i, eq := range beqs {
+		if !eq {
+			errs = append(errs, path.NewErrorf("actual set element %#v does not correlate with any element in plan", bs[i]))
+		}
+	}
+	return errs
+}
diff --git a/v1.5.7/internal/plans/objchange/compatible_test.go b/v1.5.7/internal/plans/objchange/compatible_test.go
new file mode 100644
index 0000000..60c9876
--- /dev/null
+++ b/v1.5.7/internal/plans/objchange/compatible_test.go
@@ -0,0 +1,1379 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package objchange
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/apparentlymart/go-dump/dump"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestAssertObjectCompatible(t *testing.T) {
+	schemaWithFoo := configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"foo": {Type: cty.String, Optional: true},
+		},
+	}
+	fooBlockValue := cty.ObjectVal(map[string]cty.Value{
+		"foo": cty.StringVal("bar"),
+	})
+	schemaWithFooBar := configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"foo": {Type: cty.String, Optional: true},
+			"bar": {Type: cty.String, Optional: true},
+		},
+	}
+	fooBarBlockValue := cty.ObjectVal(map[string]cty.Value{
+		"foo": cty.StringVal("bar"),
+		"bar": cty.NullVal(cty.String), // simulating the situation where bar isn't set in the config at all
+	})
+
+	tests := []struct {
+		Schema   *configschema.Block
+		Planned  cty.Value
+		Actual   cty.Value
+		WantErrs []string
+	}{
+		{
+			&configschema.Block{},
+			cty.EmptyObjectVal,
+			cty.EmptyObjectVal,
+			nil,
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"name": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"name": cty.StringVal("thingy"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"name": cty.StringVal("thingy"),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"name": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"name": cty.UnknownVal(cty.String),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"name": cty.StringVal("thingy"),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"name": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"name": cty.StringVal("wotsit"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"name": cty.StringVal("thingy"),
+			}),
+			[]string{
+				`.name: was cty.StringVal("wotsit"), but now cty.StringVal("thingy")`,
+			},
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"name": {
+						Type:      cty.String,
+						Required:  true,
+						Sensitive: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"name": cty.StringVal("wotsit"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"name": cty.StringVal("thingy"),
+			}),
+			[]string{
+				`.name: inconsistent values for sensitive attribute`,
+			},
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"name": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"name": cty.StringVal("wotsit").Mark(marks.Sensitive),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"name": cty.StringVal("thingy"),
+			}),
+			[]string{
+				`.name: inconsistent values for sensitive attribute`,
+			},
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"name": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"name": cty.StringVal("wotsit"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"name": cty.StringVal("thingy").Mark(marks.Sensitive),
+			}),
+			[]string{
+				`.name: inconsistent values for sensitive attribute`,
+			},
+		},
+		{
+			// This tests the codepath that leads to couldHaveUnknownBlockPlaceholder,
+			// where a set may be sensitive and need to be unmarked before it
+			// is iterated upon
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"configuration": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							BlockTypes: map[string]*configschema.NestedBlock{
+								"sensitive_fields": {
+									Nesting: configschema.NestingSet,
+									Block:   schemaWithFoo,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"configuration": cty.TupleVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"sensitive_fields": cty.SetVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.StringVal("secret"),
+							}),
+						}).Mark(marks.Sensitive),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"configuration": cty.TupleVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"sensitive_fields": cty.SetVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.StringVal("secret"),
+							}),
+						}).Mark(marks.Sensitive),
+					}),
+				}),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"stuff": {
+						Type:     cty.DynamicPseudoType,
+						Required: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.UnknownVal(cty.String),
+				"stuff": cty.DynamicVal,
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.UnknownVal(cty.String),
+				"stuff": cty.StringVal("thingy"),
+			}),
+			[]string{},
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"obj": {
+						Type: cty.Object(map[string]cty.Type{
+							"stuff": cty.DynamicPseudoType,
+						}),
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"obj": cty.ObjectVal(map[string]cty.Value{
+					"stuff": cty.DynamicVal,
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"obj": cty.ObjectVal(map[string]cty.Value{
+					"stuff": cty.NumberIntVal(3),
+				}),
+			}),
+			[]string{},
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"stuff": {
+						Type:     cty.DynamicPseudoType,
+						Required: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.UnknownVal(cty.String),
+				"stuff": cty.StringVal("wotsit"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.UnknownVal(cty.String),
+				"stuff": cty.StringVal("thingy"),
+			}),
+			[]string{
+				`.stuff: was cty.StringVal("wotsit"), but now cty.StringVal("thingy")`,
+			},
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"stuff": {
+						Type:     cty.DynamicPseudoType,
+						Required: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.UnknownVal(cty.String),
+				"stuff": cty.StringVal("true"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.UnknownVal(cty.String),
+				"stuff": cty.True,
+			}),
+			[]string{
+				`.stuff: wrong final value type: string required`,
+			},
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"stuff": {
+						Type:     cty.DynamicPseudoType,
+						Required: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.UnknownVal(cty.String),
+				"stuff": cty.DynamicVal,
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.UnknownVal(cty.String),
+				"stuff": cty.EmptyObjectVal,
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"stuff": {
+						Type:     cty.DynamicPseudoType,
+						Required: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"stuff": cty.ObjectVal(map[string]cty.Value{
+					"nonsense": cty.StringVal("yup"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.UnknownVal(cty.String),
+				"stuff": cty.EmptyObjectVal,
+			}),
+			[]string{
+				`.stuff: wrong final value type: attribute "nonsense" is required`,
+			},
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"tags": {
+						Type:     cty.Map(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.StringVal("thingy"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.StringVal("thingy"),
+				}),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"tags": {
+						Type:     cty.Map(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.UnknownVal(cty.String),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.StringVal("thingy"),
+				}),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"tags": {
+						Type:     cty.Map(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.StringVal("wotsit"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.StringVal("thingy"),
+				}),
+			}),
+			[]string{
+				`.tags["Name"]: was cty.StringVal("wotsit"), but now cty.StringVal("thingy")`,
+			},
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"tags": {
+						Type:     cty.Map(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.StringVal("thingy"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.StringVal("thingy"),
+					"Env":  cty.StringVal("production"),
+				}),
+			}),
+			[]string{
+				`.tags: new element "Env" has appeared`,
+			},
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"tags": {
+						Type:     cty.Map(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.StringVal("thingy"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"tags": cty.MapValEmpty(cty.String),
+			}),
+			[]string{
+				`.tags: element "Name" has vanished`,
+			},
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"tags": {
+						Type:     cty.Map(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.UnknownVal(cty.String),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"tags": cty.MapVal(map[string]cty.Value{
+					"Name": cty.NullVal(cty.String),
+				}),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"zones": {
+						Type:     cty.Set(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"zones": cty.SetVal([]cty.Value{
+					cty.StringVal("thingy"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"zones": cty.SetVal([]cty.Value{
+					cty.StringVal("thingy"),
+				}),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"zones": {
+						Type:     cty.Set(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"zones": cty.SetVal([]cty.Value{
+					cty.StringVal("thingy"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"zones": cty.SetVal([]cty.Value{
+					cty.StringVal("thingy"),
+					cty.StringVal("wotsit"),
+				}),
+			}),
+			[]string{
+				`.zones: actual set element cty.StringVal("wotsit") does not correlate with any element in plan`,
+				`.zones: length changed from 1 to 2`,
+			},
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"zones": {
+						Type:     cty.Set(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"zones": cty.SetVal([]cty.Value{
+					cty.UnknownVal(cty.String),
+					cty.UnknownVal(cty.String),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"zones": cty.SetVal([]cty.Value{
+					// Imagine that both of our unknown values ultimately resolved to "thingy",
+					// causing them to collapse into a single element. That's valid,
+					// even though it's also a little confusing and counter-intuitive.
+					cty.StringVal("thingy"),
+				}),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"names": {
+						Type:     cty.List(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"names": cty.ListVal([]cty.Value{
+					cty.StringVal("thingy"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"names": cty.ListVal([]cty.Value{
+					cty.StringVal("thingy"),
+				}),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"names": {
+						Type:     cty.List(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id":    cty.UnknownVal(cty.String),
+				"names": cty.UnknownVal(cty.List(cty.String)),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"names": cty.ListVal([]cty.Value{
+					cty.StringVal("thingy"),
+				}),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"names": {
+						Type:     cty.List(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"names": cty.ListVal([]cty.Value{
+					cty.UnknownVal(cty.String),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"names": cty.ListVal([]cty.Value{
+					cty.StringVal("thingy"),
+				}),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"names": {
+						Type:     cty.List(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"names": cty.ListVal([]cty.Value{
+					cty.StringVal("thingy"),
+					cty.UnknownVal(cty.String),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"names": cty.ListVal([]cty.Value{
+					cty.StringVal("thingy"),
+					cty.StringVal("wotsit"),
+				}),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"names": {
+						Type:     cty.List(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"names": cty.ListVal([]cty.Value{
+					cty.UnknownVal(cty.String),
+					cty.StringVal("thingy"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"names": cty.ListVal([]cty.Value{
+					cty.StringVal("thingy"),
+					cty.StringVal("wotsit"),
+				}),
+			}),
+			[]string{
+				`.names[1]: was cty.StringVal("thingy"), but now cty.StringVal("wotsit")`,
+			},
+		},
+		{
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"names": {
+						Type:     cty.List(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"names": cty.ListVal([]cty.Value{
+					cty.UnknownVal(cty.String),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+				"names": cty.ListVal([]cty.Value{
+					cty.StringVal("thingy"),
+					cty.StringVal("wotsit"),
+				}),
+			}),
+			[]string{
+				`.names: new element 1 has appeared`,
+			},
+		},
+
+		// NestingSingle blocks
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"key": {
+						Nesting: configschema.NestingSingle,
+						Block:   configschema.Block{},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.EmptyObjectVal,
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.EmptyObjectVal,
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"key": {
+						Nesting: configschema.NestingSingle,
+						Block:   configschema.Block{},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.UnknownVal(cty.EmptyObject),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.EmptyObjectVal,
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"key": {
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"foo": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.NullVal(cty.Object(map[string]cty.Type{
+					"foo": cty.String,
+				})),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("hello"),
+				}),
+			}),
+			[]string{
+				`.key: was absent, but now present`,
+			},
+		},
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"key": {
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"foo": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("hello"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.NullVal(cty.Object(map[string]cty.Type{
+					"foo": cty.String,
+				})),
+			}),
+			[]string{
+				`.key: was present, but now absent`,
+			},
+		},
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"key": {
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"foo": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.UnknownVal(cty.Object(map[string]cty.Type{
+				"key": cty.Object(map[string]cty.Type{
+					"foo": cty.String,
+				}),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.NullVal(cty.Object(map[string]cty.Type{
+					"foo": cty.String,
+				})),
+			}),
+			nil,
+		},
+
+		// NestingList blocks
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"key": {
+						Nesting: configschema.NestingList,
+						Block:   schemaWithFoo,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.ListVal([]cty.Value{
+					fooBlockValue,
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.ListVal([]cty.Value{
+					fooBlockValue,
+				}),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"key": {
+						Nesting: configschema.NestingList,
+						Block:   schemaWithFoo,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.TupleVal([]cty.Value{
+					fooBlockValue,
+					fooBlockValue,
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.TupleVal([]cty.Value{
+					fooBlockValue,
+				}),
+			}),
+			[]string{
+				`.key: block count changed from 2 to 1`,
+			},
+		},
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"key": {
+						Nesting: configschema.NestingList,
+						Block:   schemaWithFoo,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.TupleVal([]cty.Value{}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.TupleVal([]cty.Value{
+					fooBlockValue,
+					fooBlockValue,
+				}),
+			}),
+			[]string{
+				`.key: block count changed from 0 to 2`,
+			},
+		},
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"key": {
+						Nesting: configschema.NestingList,
+						Block:   schemaWithFooBar,
+					},
+				},
+			},
+			cty.UnknownVal(cty.Object(map[string]cty.Type{
+				"key": cty.List(fooBarBlockValue.Type()),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("hello"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("world"),
+					}),
+				}),
+			}),
+			nil, // an unknown block is allowed to expand into multiple, because that's how dynamic blocks behave when for_each is unknown
+		},
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"key": {
+						Nesting: configschema.NestingList,
+						Block:   schemaWithFooBar,
+					},
+				},
+			},
+			// While we must make an exception for empty strings in sets due to
+			// the legacy SDK, lists should be compared more strictly.
+			// This does not count as a dynamic block placeholder
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.ListVal([]cty.Value{
+					fooBarBlockValue,
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.UnknownVal(cty.String),
+						"bar": cty.StringVal(""),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"key": cty.ListVal([]cty.Value{
+					fooBlockValue,
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("hello"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("world"),
+					}),
+				}),
+			}),
+			[]string{".key: block count changed from 2 to 3"},
+		},
+
+		// NestingSet blocks
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"block": {
+						Nesting: configschema.NestingSet,
+						Block:   schemaWithFoo,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("hello"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("world"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("hello"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("world"),
+					}),
+				}),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"block": {
+						Nesting: configschema.NestingSet,
+						Block:   schemaWithFoo,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.UnknownVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.UnknownVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.SetVal([]cty.Value{
+					// This is testing the scenario where the two unknown values
+					// turned out to be equal after we learned their values,
+					// and so they coalesced together into a single element.
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("hello"),
+					}),
+				}),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"block": {
+						Nesting: configschema.NestingSet,
+						Block:   schemaWithFoo,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.UnknownVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.UnknownVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("hello"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("world"),
+					}),
+				}),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"block": {
+						Nesting: configschema.NestingSet,
+						Block:   schemaWithFoo,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.UnknownVal(cty.Set(
+					cty.Object(map[string]cty.Type{
+						"foo": cty.String,
+					}),
+				)),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("hello"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("world"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("nope"),
+					}),
+				}),
+			}),
+			// there is no error here, because the presence of unknowns
+			// indicates this may be a dynamic block, and the length is unknown
+			nil,
+		},
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"block": {
+						Nesting: configschema.NestingSet,
+						Block:   schemaWithFoo,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("hello"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("world"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("howdy"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("world"),
+					}),
+				}),
+			}),
+			[]string{
+				`.block: planned set element cty.ObjectVal(map[string]cty.Value{"foo":cty.StringVal("hello")}) does not correlate with any element in actual`,
+			},
+		},
+		{
+			// This one is an odd situation where the value representing the
+			// block itself is unknown. This is never supposed to be true,
+			// but in legacy SDK mode we allow such things to pass through as
+			// a warning, and so we must tolerate them for matching purposes.
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"block": {
+						Nesting: configschema.NestingSet,
+						Block:   schemaWithFoo,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.UnknownVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.UnknownVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.UnknownVal(cty.Set(cty.Object(map[string]cty.Type{
+					"foo": cty.String,
+				}))),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"block": {
+						Nesting: configschema.NestingSet,
+						Block:   schemaWithFoo,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.UnknownVal(cty.Set(fooBlockValue.Type())),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("a"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("b"),
+					}),
+				}),
+			}),
+			nil,
+		},
+		// test a set with an unknown dynamic count going to 0 values
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"block2": {
+						Nesting: configschema.NestingSet,
+						Block:   schemaWithFoo,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"block2": cty.UnknownVal(cty.Set(fooBlockValue.Type())),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"block2": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"foo": cty.String,
+				})),
+			}),
+			nil,
+		},
+		// test a set with a patially known dynamic count reducing it's values
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"block3": {
+						Nesting: configschema.NestingSet,
+						Block:   schemaWithFoo,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"block3": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("a"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.UnknownVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"block3": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("a"),
+					}),
+				}),
+			}),
+			nil,
+		},
+		{
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"block": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"foo": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.EmptyObjectVal,
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"block": cty.UnknownVal(cty.List(cty.Object(map[string]cty.Type{
+					"foo": cty.String,
+				}))),
+			}),
+			nil,
+		},
+	}
+
+	for i, test := range tests {
+		t.Run(fmt.Sprintf("%02d: %#v and %#v", i, test.Planned, test.Actual), func(t *testing.T) {
+			errs := AssertObjectCompatible(test.Schema, test.Planned, test.Actual)
+
+			wantErrs := make(map[string]struct{})
+			gotErrs := make(map[string]struct{})
+			for _, err := range errs {
+				gotErrs[tfdiags.FormatError(err)] = struct{}{}
+			}
+			for _, msg := range test.WantErrs {
+				wantErrs[msg] = struct{}{}
+			}
+
+			t.Logf("\nplanned: %sactual:  %s", dump.Value(test.Planned), dump.Value(test.Actual))
+			for msg := range wantErrs {
+				if _, ok := gotErrs[msg]; !ok {
+					t.Errorf("missing expected error: %s", msg)
+				}
+			}
+			for msg := range gotErrs {
+				if _, ok := wantErrs[msg]; !ok {
+					t.Errorf("unexpected extra error: %s", msg)
+				}
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/plans/objchange/doc.go b/v1.5.7/internal/plans/objchange/doc.go
new file mode 100644
index 0000000..b3a136e
--- /dev/null
+++ b/v1.5.7/internal/plans/objchange/doc.go
@@ -0,0 +1,7 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package objchange deals with the business logic of taking a prior state
+// value and a config value and producing a proposed new merged value, along
+// with other related rules in this domain.
+package objchange
diff --git a/v1.5.7/internal/plans/objchange/lcs.go b/v1.5.7/internal/plans/objchange/lcs.go
new file mode 100644
index 0000000..e02e5f9
--- /dev/null
+++ b/v1.5.7/internal/plans/objchange/lcs.go
@@ -0,0 +1,121 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package objchange
+
+import (
+	"github.com/zclconf/go-cty/cty"
+)
+
+// ValueEqual provides an implementation of the equals function that can be
+// passed into LongestCommonSubsequence when comparing cty.Value types.
+func ValueEqual(x, y cty.Value) bool {
+	unmarkedX, xMarks := x.UnmarkDeep()
+	unmarkedY, yMarks := y.UnmarkDeep()
+	eqV := unmarkedX.Equals(unmarkedY)
+	if len(xMarks) != len(yMarks) {
+		eqV = cty.False
+	}
+	if eqV.IsKnown() && eqV.True() {
+		return true
+	}
+	return false
+}
+
+// LongestCommonSubsequence finds a sequence of values that are common to both
+// x and y, with the same relative ordering as in both collections. This result
+// is useful as a first step towards computing a diff showing added/removed
+// elements in a sequence.
+//
+// The approached used here is a "naive" one, assuming that both xs and ys will
+// generally be small in most reasonable Terraform configurations. For larger
+// lists the time/space usage may be sub-optimal.
+//
+// A pair of lists may have multiple longest common subsequences. In that
+// case, the one selected by this function is undefined.
+func LongestCommonSubsequence[V any](xs, ys []V, equals func(x, y V) bool) []V {
+	if len(xs) == 0 || len(ys) == 0 {
+		return make([]V, 0)
+	}
+
+	c := make([]int, len(xs)*len(ys))
+	eqs := make([]bool, len(xs)*len(ys))
+	w := len(xs)
+
+	for y := 0; y < len(ys); y++ {
+		for x := 0; x < len(xs); x++ {
+			eq := false
+			if equals(xs[x], ys[y]) {
+				eq = true
+				eqs[(w*y)+x] = true // equality tests can be expensive, so cache it
+			}
+			if eq {
+				// Sequence gets one longer than for the cell at top left,
+				// since we'd append a new item to the sequence here.
+				if x == 0 || y == 0 {
+					c[(w*y)+x] = 1
+				} else {
+					c[(w*y)+x] = c[(w*(y-1))+(x-1)] + 1
+				}
+			} else {
+				// We follow the longest of the sequence above and the sequence
+				// to the left of us in the matrix.
+				l := 0
+				u := 0
+				if x > 0 {
+					l = c[(w*y)+(x-1)]
+				}
+				if y > 0 {
+					u = c[(w*(y-1))+x]
+				}
+				if l > u {
+					c[(w*y)+x] = l
+				} else {
+					c[(w*y)+x] = u
+				}
+			}
+		}
+	}
+
+	// The bottom right cell tells us how long our longest sequence will be
+	seq := make([]V, c[len(c)-1])
+
+	// Now we will walk back from the bottom right cell, finding again all
+	// of the equal pairs to construct our sequence.
+	x := len(xs) - 1
+	y := len(ys) - 1
+	i := len(seq) - 1
+
+	for x > -1 && y > -1 {
+		if eqs[(w*y)+x] {
+			// Add the value to our result list and then walk diagonally
+			// up and to the left.
+			seq[i] = xs[x]
+			x--
+			y--
+			i--
+		} else {
+			// Take the path with the greatest sequence length in the matrix.
+			l := 0
+			u := 0
+			if x > 0 {
+				l = c[(w*y)+(x-1)]
+			}
+			if y > 0 {
+				u = c[(w*(y-1))+x]
+			}
+			if l > u {
+				x--
+			} else {
+				y--
+			}
+		}
+	}
+
+	if i > -1 {
+		// should never happen if the matrix was constructed properly
+		panic("not enough elements in sequence")
+	}
+
+	return seq
+}
diff --git a/v1.5.7/internal/plans/objchange/lcs_test.go b/v1.5.7/internal/plans/objchange/lcs_test.go
new file mode 100644
index 0000000..413d71d
--- /dev/null
+++ b/v1.5.7/internal/plans/objchange/lcs_test.go
@@ -0,0 +1,136 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package objchange
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestLongestCommonSubsequence(t *testing.T) {
+	tests := []struct {
+		xs   []cty.Value
+		ys   []cty.Value
+		want []cty.Value
+	}{
+		{
+			[]cty.Value{},
+			[]cty.Value{},
+			[]cty.Value{},
+		},
+		{
+			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)},
+			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)},
+			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)},
+		},
+		{
+			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)},
+			[]cty.Value{cty.NumberIntVal(3), cty.NumberIntVal(4)},
+			[]cty.Value{},
+		},
+		{
+			[]cty.Value{cty.NumberIntVal(2)},
+			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)},
+			[]cty.Value{cty.NumberIntVal(2)},
+		},
+		{
+			[]cty.Value{cty.NumberIntVal(1)},
+			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)},
+			[]cty.Value{cty.NumberIntVal(1)},
+		},
+		{
+			[]cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(1)},
+			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2)},
+			[]cty.Value{cty.NumberIntVal(1)}, // arbitrarily selected 1; 2 would also be valid
+		},
+		{
+			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2), cty.NumberIntVal(3), cty.NumberIntVal(4)},
+			[]cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(4), cty.NumberIntVal(5)},
+			[]cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(4)},
+		},
+		{
+			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2), cty.NumberIntVal(3), cty.NumberIntVal(4)},
+			[]cty.Value{cty.NumberIntVal(4), cty.NumberIntVal(2), cty.NumberIntVal(5)},
+			[]cty.Value{cty.NumberIntVal(4)}, // 2 would also be valid
+		},
+		{
+			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2), cty.NumberIntVal(3), cty.NumberIntVal(5)},
+			[]cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(4), cty.NumberIntVal(5)},
+			[]cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(5)},
+		},
+
+		// unknowns never compare as equal
+		{
+			[]cty.Value{cty.NumberIntVal(1), cty.UnknownVal(cty.Number), cty.NumberIntVal(3)},
+			[]cty.Value{cty.NumberIntVal(1), cty.UnknownVal(cty.Number), cty.NumberIntVal(3)},
+			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(3)},
+		},
+		{
+			[]cty.Value{cty.UnknownVal(cty.Number)},
+			[]cty.Value{cty.UnknownVal(cty.Number)},
+			[]cty.Value{},
+		},
+
+		// marked values
+		{
+			[]cty.Value{cty.NumberIntVal(1).Mark("foo"), cty.NumberIntVal(2).Mark("foo"), cty.NumberIntVal(3)},
+			[]cty.Value{cty.NumberIntVal(1).Mark("foo"), cty.NumberIntVal(2).Mark("foo")},
+			[]cty.Value{cty.NumberIntVal(1).Mark("foo"), cty.NumberIntVal(2).Mark("foo")},
+		},
+		{
+			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2).Mark("foo"), cty.NumberIntVal(3)},
+			[]cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(3)},
+			[]cty.Value{cty.NumberIntVal(3)},
+		},
+		{
+			[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2).Mark("foo")},
+			[]cty.Value{cty.NumberIntVal(2)},
+			[]cty.Value{},
+		},
+		{
+			[]cty.Value{
+				cty.MapVal(map[string]cty.Value{"a": cty.StringVal("x").Mark(marks.Sensitive)}),
+				cty.MapVal(map[string]cty.Value{"b": cty.StringVal("y")}),
+			},
+			[]cty.Value{
+				cty.MapVal(map[string]cty.Value{"a": cty.StringVal("x").Mark(marks.Sensitive)}),
+				cty.MapVal(map[string]cty.Value{"b": cty.StringVal("y")}),
+				cty.MapVal(map[string]cty.Value{"c": cty.StringVal("z")}),
+			},
+			[]cty.Value{
+				cty.MapVal(map[string]cty.Value{"a": cty.StringVal("x").Mark(marks.Sensitive)}),
+				cty.MapVal(map[string]cty.Value{"b": cty.StringVal("y")}),
+			},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%#v,%#v", test.xs, test.ys), func(t *testing.T) {
+			got := LongestCommonSubsequence(test.xs, test.ys, ValueEqual)
+
+			wrong := func() {
+				t.Fatalf(
+					"wrong result\nX:    %#v\nY:    %#v\ngot:  %#v\nwant: %#v",
+					test.xs, test.ys, got, test.want,
+				)
+			}
+
+			if len(got) != len(test.want) {
+				wrong()
+			}
+
+			for i := range got {
+				if got[i] == cty.NilVal {
+					wrong()
+				}
+				if !got[i].RawEquals(test.want[i]) {
+					wrong()
+				}
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/plans/objchange/normalize_obj.go b/v1.5.7/internal/plans/objchange/normalize_obj.go
new file mode 100644
index 0000000..1972f51
--- /dev/null
+++ b/v1.5.7/internal/plans/objchange/normalize_obj.go
@@ -0,0 +1,141 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package objchange
+
+import (
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// NormalizeObjectFromLegacySDK takes an object that may have been generated
+// by the legacy Terraform SDK (i.e. returned from a provider with the
+// LegacyTypeSystem opt-out set) and does its best to normalize it for the
+// assumptions we would normally enforce if the provider had not opted out.
+//
+// In particular, this function guarantees that a value representing a nested
+// block will never itself be unknown or null, instead representing that as
+// a non-null value that may contain null/unknown values.
+//
+// The input value must still conform to the implied type of the given schema,
+// or else this function may produce garbage results or panic. This is usually
+// okay because type consistency is enforced when deserializing the value
+// returned from the provider over the RPC wire protocol anyway.
+func NormalizeObjectFromLegacySDK(val cty.Value, schema *configschema.Block) cty.Value {
+	val, valMarks := val.UnmarkDeepWithPaths()
+	val = normalizeObjectFromLegacySDK(val, schema)
+	return val.MarkWithPaths(valMarks)
+}
+
+func normalizeObjectFromLegacySDK(val cty.Value, schema *configschema.Block) cty.Value {
+	if val == cty.NilVal || val.IsNull() {
+		// This should never happen in reasonable use, but we'll allow it
+		// and normalize to a null of the expected type rather than panicking
+		// below.
+		return cty.NullVal(schema.ImpliedType())
+	}
+
+	vals := make(map[string]cty.Value)
+	for name := range schema.Attributes {
+		// No normalization for attributes, since them being type-conformant
+		// is all that we require.
+		vals[name] = val.GetAttr(name)
+	}
+	for name, blockS := range schema.BlockTypes {
+		lv := val.GetAttr(name)
+
+		// Legacy SDK never generates dynamically-typed attributes and so our
+		// normalization code doesn't deal with them, but we need to make sure
+		// we still pass them through properly so that we don't interfere with
+		// objects generated by other SDKs.
+		if ty := blockS.Block.ImpliedType(); ty.HasDynamicTypes() {
+			vals[name] = lv
+			continue
+		}
+
+		switch blockS.Nesting {
+		case configschema.NestingSingle, configschema.NestingGroup:
+			if lv.IsKnown() {
+				if lv.IsNull() && blockS.Nesting == configschema.NestingGroup {
+					vals[name] = blockS.EmptyValue()
+				} else {
+					vals[name] = normalizeObjectFromLegacySDK(lv, &blockS.Block)
+				}
+			} else {
+				vals[name] = unknownBlockStub(&blockS.Block)
+			}
+		case configschema.NestingList:
+			switch {
+			case !lv.IsKnown():
+				vals[name] = cty.ListVal([]cty.Value{unknownBlockStub(&blockS.Block)})
+			case lv.IsNull() || lv.LengthInt() == 0:
+				vals[name] = cty.ListValEmpty(blockS.Block.ImpliedType())
+			default:
+				subVals := make([]cty.Value, 0, lv.LengthInt())
+				for it := lv.ElementIterator(); it.Next(); {
+					_, subVal := it.Element()
+					subVals = append(subVals, normalizeObjectFromLegacySDK(subVal, &blockS.Block))
+				}
+				vals[name] = cty.ListVal(subVals)
+			}
+		case configschema.NestingSet:
+			switch {
+			case !lv.IsKnown():
+				vals[name] = cty.SetVal([]cty.Value{unknownBlockStub(&blockS.Block)})
+			case lv.IsNull() || lv.LengthInt() == 0:
+				vals[name] = cty.SetValEmpty(blockS.Block.ImpliedType())
+			default:
+				subVals := make([]cty.Value, 0, lv.LengthInt())
+				for it := lv.ElementIterator(); it.Next(); {
+					_, subVal := it.Element()
+					subVals = append(subVals, normalizeObjectFromLegacySDK(subVal, &blockS.Block))
+				}
+				vals[name] = cty.SetVal(subVals)
+			}
+		default:
+			// The legacy SDK doesn't support NestingMap, so we just assume
+			// maps are always okay. (If not, we would've detected and returned
+			// an error to the user before we got here.)
+			vals[name] = lv
+		}
+	}
+	return cty.ObjectVal(vals)
+}
+
+// unknownBlockStub constructs an object value that approximates an unknown
+// block by producing a known block object with all of its leaf attribute
+// values set to unknown.
+//
+// Blocks themselves cannot be unknown, so if the legacy SDK tries to return
+// such a thing, we'll use this result instead. This convention mimics how
+// the dynamic block feature deals with being asked to iterate over an unknown
+// value, because our value-checking functions already accept this convention
+// as a special case.
+func unknownBlockStub(schema *configschema.Block) cty.Value {
+	vals := make(map[string]cty.Value)
+	for name, attrS := range schema.Attributes {
+		vals[name] = cty.UnknownVal(attrS.Type)
+	}
+	for name, blockS := range schema.BlockTypes {
+		switch blockS.Nesting {
+		case configschema.NestingSingle, configschema.NestingGroup:
+			vals[name] = unknownBlockStub(&blockS.Block)
+		case configschema.NestingList:
+			// In principle we may be expected to produce a tuple value here,
+			// if there are any dynamically-typed attributes in our nested block,
+			// but the legacy SDK doesn't support that, so we just assume it'll
+			// never be necessary to normalize those. (Incorrect usage in any
+			// other SDK would be caught and returned as an error before we
+			// get here.)
+			vals[name] = cty.ListVal([]cty.Value{unknownBlockStub(&blockS.Block)})
+		case configschema.NestingSet:
+			vals[name] = cty.SetVal([]cty.Value{unknownBlockStub(&blockS.Block)})
+		case configschema.NestingMap:
+			// A nesting map can never be unknown since we then wouldn't know
+			// what the keys are. (Legacy SDK doesn't support NestingMap anyway,
+			// so this should never arise.)
+			vals[name] = cty.MapValEmpty(blockS.Block.ImpliedType())
+		}
+	}
+	return cty.ObjectVal(vals)
+}
diff --git a/v1.5.7/internal/plans/objchange/normalize_obj_test.go b/v1.5.7/internal/plans/objchange/normalize_obj_test.go
new file mode 100644
index 0000000..2b99966
--- /dev/null
+++ b/v1.5.7/internal/plans/objchange/normalize_obj_test.go
@@ -0,0 +1,311 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package objchange
+
+import (
+	"testing"
+
+	"github.com/apparentlymart/go-dump/dump"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestNormalizeObjectFromLegacySDK(t *testing.T) {
+	tests := map[string]struct {
+		Schema *configschema.Block
+		Input  cty.Value
+		Want   cty.Value
+	}{
+		"empty": {
+			&configschema.Block{},
+			cty.EmptyObjectVal,
+			cty.EmptyObjectVal,
+		},
+		"attributes only": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"a": {Type: cty.String, Required: true},
+					"b": {Type: cty.String, Optional: true},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.StringVal("b value"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.StringVal("b value"),
+			}),
+		},
+		"null block single": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"a": {
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"b": {Type: cty.String, Optional: true},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.Object(map[string]cty.Type{
+					"b": cty.String,
+				})),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.Object(map[string]cty.Type{
+					"b": cty.String,
+				})),
+			}),
+		},
+		"unknown block single": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"a": {
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"b": {Type: cty.String, Optional: true},
+							},
+							BlockTypes: map[string]*configschema.NestedBlock{
+								"c": {Nesting: configschema.NestingSingle},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.UnknownVal(cty.Object(map[string]cty.Type{
+					"b": cty.String,
+					"c": cty.EmptyObject,
+				})),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ObjectVal(map[string]cty.Value{
+					"b": cty.UnknownVal(cty.String),
+					"c": cty.EmptyObjectVal,
+				}),
+			}),
+		},
+		"null block list": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"a": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"b": {Type: cty.String, Optional: true},
+							},
+							BlockTypes: map[string]*configschema.NestedBlock{
+								"c": {Nesting: configschema.NestingSingle},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"b": cty.String,
+					"c": cty.EmptyObject,
+				}))),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+					"b": cty.String,
+					"c": cty.EmptyObject,
+				})),
+			}),
+		},
+		"unknown block list": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"a": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"b": {Type: cty.String, Optional: true},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.UnknownVal(cty.List(cty.Object(map[string]cty.Type{
+					"b": cty.String,
+				}))),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.UnknownVal(cty.String),
+					}),
+				}),
+			}),
+		},
+		"null block set": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"a": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"b": {Type: cty.String, Optional: true},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{
+					"b": cty.String,
+				}))),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"b": cty.String,
+				})),
+			}),
+		},
+		"unknown block set": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"a": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"b": {Type: cty.String, Optional: true},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.UnknownVal(cty.Set(cty.Object(map[string]cty.Type{
+					"b": cty.String,
+				}))),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.UnknownVal(cty.String),
+					}),
+				}),
+			}),
+		},
+		"map block passes through": {
+			// Legacy SDK doesn't use NestingMap, so we don't do any transforms
+			// related to it but we still need to verify that map blocks pass
+			// through unscathed.
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"a": {
+						Nesting: configschema.NestingMap,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"b": {Type: cty.String, Optional: true},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"foo": cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("b value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"foo": cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("b value"),
+					}),
+				}),
+			}),
+		},
+		"block list with dynamic type": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"a": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"b": {Type: cty.DynamicPseudoType, Optional: true},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.TupleVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("hello"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.True,
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.TupleVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("hello"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.True,
+					}),
+				}),
+			}),
+		},
+		"block map with dynamic type": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"a": {
+						Nesting: configschema.NestingMap,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"b": {Type: cty.DynamicPseudoType, Optional: true},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ObjectVal(map[string]cty.Value{
+					"one": cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("hello"),
+					}),
+					"another": cty.ObjectVal(map[string]cty.Value{
+						"b": cty.True,
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ObjectVal(map[string]cty.Value{
+					"one": cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("hello"),
+					}),
+					"another": cty.ObjectVal(map[string]cty.Value{
+						"b": cty.True,
+					}),
+				}),
+			}),
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got := NormalizeObjectFromLegacySDK(test.Input, test.Schema)
+			if !got.RawEquals(test.Want) {
+				t.Errorf(
+					"wrong result\ngot:  %s\nwant: %s",
+					dump.Value(got), dump.Value(test.Want),
+				)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/plans/objchange/objchange.go b/v1.5.7/internal/plans/objchange/objchange.go
new file mode 100644
index 0000000..f806174
--- /dev/null
+++ b/v1.5.7/internal/plans/objchange/objchange.go
@@ -0,0 +1,494 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package objchange
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+// ProposedNew constructs a proposed new object value by combining the
+// computed attribute values from "prior" with the configured attribute values
+// from "config".
+//
+// Both value must conform to the given schema's implied type, or this function
+// will panic.
+//
+// The prior value must be wholly known, but the config value may be unknown
+// or have nested unknown values.
+//
+// The merging of the two objects includes the attributes of any nested blocks,
+// which will be correlated in a manner appropriate for their nesting mode.
+// Note in particular that the correlation for blocks backed by sets is a
+// heuristic based on matching non-computed attribute values and so it may
+// produce strange results with more "extreme" cases, such as a nested set
+// block where _all_ attributes are computed.
+func ProposedNew(schema *configschema.Block, prior, config cty.Value) cty.Value {
+	// If the config and prior are both null, return early here before
+	// populating the prior block. The prevents non-null blocks from appearing
+	// the proposed state value.
+	if config.IsNull() && prior.IsNull() {
+		return prior
+	}
+
+	if prior.IsNull() {
+		// In this case, we will construct a synthetic prior value that is
+		// similar to the result of decoding an empty configuration block,
+		// which simplifies our handling of the top-level attributes/blocks
+		// below by giving us one non-null level of object to pull values from.
+		//
+		// "All attributes null" happens to be the definition of EmptyValue for
+		// a Block, so we can just delegate to that
+		prior = schema.EmptyValue()
+	}
+	return proposedNew(schema, prior, config)
+}
+
+// PlannedDataResourceObject is similar to proposedNewBlock but tailored for
+// planning data resources in particular. Specifically, it replaces the values
+// of any Computed attributes not set in the configuration with an unknown
+// value, which serves as a placeholder for a value to be filled in by the
+// provider when the data resource is finally read.
+//
+// Data resources are different because the planning of them is handled
+// entirely within Terraform Core and not subject to customization by the
+// provider. This function is, in effect, producing an equivalent result to
+// passing the proposedNewBlock result into a provider's PlanResourceChange
+// function, assuming a fixed implementation of PlanResourceChange that just
+// fills in unknown values as needed.
+func PlannedDataResourceObject(schema *configschema.Block, config cty.Value) cty.Value {
+	// Our trick here is to run the proposedNewBlock logic with an
+	// entirely-unknown prior value. Because of cty's unknown short-circuit
+	// behavior, any operation on prior returns another unknown, and so
+	// unknown values propagate into all of the parts of the resulting value
+	// that would normally be filled in by preserving the prior state.
+	prior := cty.UnknownVal(schema.ImpliedType())
+	return proposedNew(schema, prior, config)
+}
+
+func proposedNew(schema *configschema.Block, prior, config cty.Value) cty.Value {
+	if config.IsNull() || !config.IsKnown() {
+		// A block config should never be null at this point. The only nullable
+		// block type is NestingSingle, which will return early before coming
+		// back here. We'll allow the null here anyway to free callers from
+		// needing to specifically check for these cases, and any mismatch will
+		// be caught in validation, so just take the prior value rather than
+		// the invalid null.
+		return prior
+	}
+
+	if (!prior.Type().IsObjectType()) || (!config.Type().IsObjectType()) {
+		panic("ProposedNew only supports object-typed values")
+	}
+
+	// From this point onwards, we can assume that both values are non-null
+	// object types, and that the config value itself is known (though it
+	// may contain nested values that are unknown.)
+	newAttrs := proposedNewAttributes(schema.Attributes, prior, config)
+
+	// Merging nested blocks is a little more complex, since we need to
+	// correlate blocks between both objects and then recursively propose
+	// a new object for each. The correlation logic depends on the nesting
+	// mode for each block type.
+	for name, blockType := range schema.BlockTypes {
+		priorV := prior.GetAttr(name)
+		configV := config.GetAttr(name)
+		newAttrs[name] = proposedNewNestedBlock(blockType, priorV, configV)
+	}
+
+	return cty.ObjectVal(newAttrs)
+}
+
+// proposedNewBlockOrObject dispatched the schema to either ProposedNew or
+// proposedNewObjectAttributes depending on the given type.
+func proposedNewBlockOrObject(schema nestedSchema, prior, config cty.Value) cty.Value {
+	switch schema := schema.(type) {
+	case *configschema.Block:
+		return ProposedNew(schema, prior, config)
+	case *configschema.Object:
+		return proposedNewObjectAttributes(schema, prior, config)
+	default:
+		panic(fmt.Sprintf("unexpected schema type %T", schema))
+	}
+}
+
+func proposedNewNestedBlock(schema *configschema.NestedBlock, prior, config cty.Value) cty.Value {
+	// The only time we should encounter an entirely unknown block is from the
+	// use of dynamic with an unknown for_each expression.
+	if !config.IsKnown() {
+		return config
+	}
+
+	newV := config
+
+	switch schema.Nesting {
+	case configschema.NestingSingle:
+		// A NestingSingle configuration block value can be null, and since it
+		// cannot be computed we can always take the configuration value.
+		if config.IsNull() {
+			break
+		}
+
+		// Otherwise use the same assignment rules as NestingGroup
+		fallthrough
+	case configschema.NestingGroup:
+		newV = ProposedNew(&schema.Block, prior, config)
+
+	case configschema.NestingList:
+		newV = proposedNewNestingList(&schema.Block, prior, config)
+
+	case configschema.NestingMap:
+		newV = proposedNewNestingMap(&schema.Block, prior, config)
+
+	case configschema.NestingSet:
+		newV = proposedNewNestingSet(&schema.Block, prior, config)
+
+	default:
+		// Should never happen, since the above cases are comprehensive.
+		panic(fmt.Sprintf("unsupported block nesting mode %s", schema.Nesting))
+	}
+
+	return newV
+}
+
+func proposedNewNestedType(schema *configschema.Object, prior, config cty.Value) cty.Value {
+	// if the config isn't known at all, then we must use that value
+	if !config.IsKnown() {
+		return config
+	}
+
+	// Even if the config is null or empty, we will be using this default value.
+	newV := config
+
+	switch schema.Nesting {
+	case configschema.NestingSingle:
+		// If the config is null, we already have our value. If the attribute
+		// is optional+computed, we won't reach this branch with a null value
+		// since the computed case would have been taken.
+		if config.IsNull() {
+			break
+		}
+
+		newV = proposedNewObjectAttributes(schema, prior, config)
+
+	case configschema.NestingList:
+		newV = proposedNewNestingList(schema, prior, config)
+
+	case configschema.NestingMap:
+		newV = proposedNewNestingMap(schema, prior, config)
+
+	case configschema.NestingSet:
+		newV = proposedNewNestingSet(schema, prior, config)
+
+	default:
+		// Should never happen, since the above cases are comprehensive.
+		panic(fmt.Sprintf("unsupported attribute nesting mode %s", schema.Nesting))
+	}
+
+	return newV
+}
+
+func proposedNewNestingList(schema nestedSchema, prior, config cty.Value) cty.Value {
+	newV := config
+
+	// Nested blocks are correlated by index.
+	configVLen := 0
+	if !config.IsNull() {
+		configVLen = config.LengthInt()
+	}
+	if configVLen > 0 {
+		newVals := make([]cty.Value, 0, configVLen)
+		for it := config.ElementIterator(); it.Next(); {
+			idx, configEV := it.Element()
+			if prior.IsKnown() && (prior.IsNull() || !prior.HasIndex(idx).True()) {
+				// If there is no corresponding prior element then
+				// we just take the config value as-is.
+				newVals = append(newVals, configEV)
+				continue
+			}
+			priorEV := prior.Index(idx)
+
+			newVals = append(newVals, proposedNewBlockOrObject(schema, priorEV, configEV))
+		}
+		// Despite the name, a NestingList might also be a tuple, if
+		// its nested schema contains dynamically-typed attributes.
+		if config.Type().IsTupleType() {
+			newV = cty.TupleVal(newVals)
+		} else {
+			newV = cty.ListVal(newVals)
+		}
+	}
+
+	return newV
+}
+
+func proposedNewNestingMap(schema nestedSchema, prior, config cty.Value) cty.Value {
+	newV := config
+
+	newVals := map[string]cty.Value{}
+
+	if config.IsNull() || !config.IsKnown() || config.LengthInt() == 0 {
+		// We already assigned newVal and there's nothing to compare in
+		// config.
+		return newV
+	}
+	cfgMap := config.AsValueMap()
+
+	// prior may be null or empty
+	priorMap := map[string]cty.Value{}
+	if !prior.IsNull() && prior.IsKnown() && prior.LengthInt() > 0 {
+		priorMap = prior.AsValueMap()
+	}
+
+	for name, configEV := range cfgMap {
+		priorEV, inPrior := priorMap[name]
+		if !inPrior {
+			// If there is no corresponding prior element then
+			// we just take the config value as-is.
+			newVals[name] = configEV
+			continue
+		}
+
+		newVals[name] = proposedNewBlockOrObject(schema, priorEV, configEV)
+	}
+
+	// The value must leave as the same type it came in as
+	switch {
+	case config.Type().IsObjectType():
+		// Although we call the nesting mode "map", we actually use
+		// object values so that elements might have different types
+		// in case of dynamically-typed attributes.
+		newV = cty.ObjectVal(newVals)
+	default:
+		newV = cty.MapVal(newVals)
+	}
+
+	return newV
+}
+
+func proposedNewNestingSet(schema nestedSchema, prior, config cty.Value) cty.Value {
+	if !config.Type().IsSetType() {
+		panic("configschema.NestingSet value is not a set as expected")
+	}
+
+	newV := config
+	if !config.IsKnown() || config.IsNull() || config.LengthInt() == 0 {
+		return newV
+	}
+
+	var priorVals []cty.Value
+	if prior.IsKnown() && !prior.IsNull() {
+		priorVals = prior.AsValueSlice()
+	}
+
+	var newVals []cty.Value
+	// track which prior elements have been used
+	used := make([]bool, len(priorVals))
+
+	for _, configEV := range config.AsValueSlice() {
+		var priorEV cty.Value
+		for i, priorCmp := range priorVals {
+			if used[i] {
+				continue
+			}
+
+			// It is possible that multiple prior elements could be valid
+			// matches for a configuration value, in which case we will end up
+			// picking the first match encountered (but it will always be
+			// consistent due to cty's iteration order). Because configured set
+			// elements must also be entirely unique in order to be included in
+			// the set, these matches either will not matter because they only
+			// differ by computed values, or could not have come from a valid
+			// config with all unique set elements.
+			if validPriorFromConfig(schema, priorCmp, configEV) {
+				priorEV = priorCmp
+				used[i] = true
+				break
+			}
+		}
+
+		if priorEV == cty.NilVal {
+			priorEV = cty.NullVal(config.Type().ElementType())
+		}
+
+		newVals = append(newVals, proposedNewBlockOrObject(schema, priorEV, configEV))
+	}
+
+	return cty.SetVal(newVals)
+}
+
+func proposedNewObjectAttributes(schema *configschema.Object, prior, config cty.Value) cty.Value {
+	if config.IsNull() {
+		return config
+	}
+
+	return cty.ObjectVal(proposedNewAttributes(schema.Attributes, prior, config))
+}
+
+func proposedNewAttributes(attrs map[string]*configschema.Attribute, prior, config cty.Value) map[string]cty.Value {
+	newAttrs := make(map[string]cty.Value, len(attrs))
+	for name, attr := range attrs {
+		var priorV cty.Value
+		if prior.IsNull() {
+			priorV = cty.NullVal(prior.Type().AttributeType(name))
+		} else {
+			priorV = prior.GetAttr(name)
+		}
+
+		configV := config.GetAttr(name)
+
+		var newV cty.Value
+		switch {
+		// required isn't considered when constructing the plan, so attributes
+		// are essentially either computed or not computed. In the case of
+		// optional+computed, they are only computed when there is no
+		// configuration.
+		case attr.Computed && configV.IsNull():
+			// configV will always be null in this case, by definition.
+			// priorV may also be null, but that's okay.
+			newV = priorV
+
+			// the exception to the above is that if the config is optional and
+			// the _prior_ value contains non-computed values, we can infer
+			// that the config must have been non-null previously.
+			if optionalValueNotComputable(attr, priorV) {
+				newV = configV
+			}
+
+		case attr.NestedType != nil:
+			// For non-computed NestedType attributes, we need to descend
+			// into the individual nested attributes to build the final
+			// value, unless the entire nested attribute is unknown.
+			newV = proposedNewNestedType(attr.NestedType, priorV, configV)
+		default:
+			// For non-computed attributes, we always take the config value,
+			// even if it is null. If it's _required_ then null values
+			// should've been caught during an earlier validation step, and
+			// so we don't really care about that here.
+			newV = configV
+		}
+		newAttrs[name] = newV
+	}
+	return newAttrs
+}
+
+// nestedSchema is used as a generic container for either a
+// *configschema.Object, or *configschema.Block.
+type nestedSchema interface {
+	AttributeByPath(cty.Path) *configschema.Attribute
+}
+
+// optionalValueNotComputable is used to check if an object in state must
+// have at least partially come from configuration. If the prior value has any
+// non-null attributes which are not computed in the schema, then we know there
+// was previously a configuration value which set those.
+//
+// This is used when the configuration contains a null optional+computed value,
+// and we want to know if we should plan to send the null value or the prior
+// state.
+func optionalValueNotComputable(schema *configschema.Attribute, val cty.Value) bool {
+	if !schema.Optional {
+		return false
+	}
+
+	// We must have a NestedType for complex nested attributes in order
+	// to find nested computed values in the first place.
+	if schema.NestedType == nil {
+		return false
+	}
+
+	foundNonComputedAttr := false
+	cty.Walk(val, func(path cty.Path, v cty.Value) (bool, error) {
+		if v.IsNull() {
+			return true, nil
+		}
+
+		attr := schema.NestedType.AttributeByPath(path)
+		if attr == nil {
+			return true, nil
+		}
+
+		if !attr.Computed {
+			foundNonComputedAttr = true
+			return false, nil
+		}
+		return true, nil
+	})
+
+	return foundNonComputedAttr
+}
+
+// validPriorFromConfig returns true if the prior object could have been
+// derived from the configuration. We do this by walking the prior value to
+// determine if it is a valid superset of the config, and only computable
+// values have been added. This function is only used to correlated
+// configuration with possible valid prior values within sets.
+func validPriorFromConfig(schema nestedSchema, prior, config cty.Value) bool {
+	if config.RawEquals(prior) {
+		return true
+	}
+
+	// error value to halt the walk
+	stop := errors.New("stop")
+
+	valid := true
+	cty.Walk(prior, func(path cty.Path, priorV cty.Value) (bool, error) {
+		configV, err := path.Apply(config)
+		if err != nil {
+			// most likely dynamic objects with different types
+			valid = false
+			return false, stop
+		}
+
+		// we don't need to know the schema if both are equal
+		if configV.RawEquals(priorV) {
+			// we know they are equal, so no need to descend further
+			return false, nil
+		}
+
+		// We can't descend into nested sets to correlate configuration, so the
+		// overall values must be equal.
+		if configV.Type().IsSetType() {
+			valid = false
+			return false, stop
+		}
+
+		attr := schema.AttributeByPath(path)
+		if attr == nil {
+			// Not at a schema attribute, so we can continue until we find leaf
+			// attributes.
+			return true, nil
+		}
+
+		// If we have nested object attributes we'll be descending into those
+		// to compare the individual values and determine why this level is not
+		// equal
+		if attr.NestedType != nil {
+			return true, nil
+		}
+
+		// This is a leaf attribute, so it must be computed in order to differ
+		// from config.
+		if !attr.Computed {
+			valid = false
+			return false, stop
+		}
+
+		// And if it is computed, the config must be null to allow a change.
+		if !configV.IsNull() {
+			valid = false
+			return false, stop
+		}
+
+		// We sill stop here. The cty value could be far larger, but this was
+		// the last level of prescribed schema.
+		return false, nil
+	})
+
+	return valid
+}
diff --git a/v1.5.7/internal/plans/objchange/objchange_test.go b/v1.5.7/internal/plans/objchange/objchange_test.go
new file mode 100644
index 0000000..2f64f16
--- /dev/null
+++ b/v1.5.7/internal/plans/objchange/objchange_test.go
@@ -0,0 +1,2761 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package objchange
+
+import (
+	"testing"
+
+	"github.com/apparentlymart/go-dump/dump"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+func TestProposedNew(t *testing.T) {
+	tests := map[string]struct {
+		Schema *configschema.Block
+		Prior  cty.Value
+		Config cty.Value
+		Want   cty.Value
+	}{
+		"empty": {
+			&configschema.Block{},
+			cty.EmptyObjectVal,
+			cty.EmptyObjectVal,
+			cty.EmptyObjectVal,
+		},
+		"no prior": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"bar": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSingle,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+						Computed: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"baz": {
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"boz": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+								"biz": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("hello"),
+				"bloop": cty.NullVal(cty.Object(map[string]cty.Type{
+					"blop": cty.String,
+				})),
+				"bar": cty.NullVal(cty.String),
+				"baz": cty.ObjectVal(map[string]cty.Value{
+					"boz": cty.StringVal("world"),
+
+					// An unknown in the config represents a situation where
+					// an argument is explicitly set to an expression result
+					// that is derived from an unknown value. This is distinct
+					// from leaving it null, which allows the provider itself
+					// to decide the value during PlanResourceChange.
+					"biz": cty.UnknownVal(cty.String),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("hello"),
+
+				// unset computed attributes are null in the proposal; provider
+				// usually changes them to "unknown" during PlanResourceChange,
+				// to indicate that the value will be decided during apply.
+				"bar": cty.NullVal(cty.String),
+				"bloop": cty.NullVal(cty.Object(map[string]cty.Type{
+					"blop": cty.String,
+				})),
+
+				"baz": cty.ObjectVal(map[string]cty.Value{
+					"boz": cty.StringVal("world"),
+					"biz": cty.UnknownVal(cty.String), // explicit unknown preserved from config
+				}),
+			}),
+		},
+		"null block remains null": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSingle,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+						Computed: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"baz": {
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"boz": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+				"bloop": cty.NullVal(cty.Object(map[string]cty.Type{
+					"blop": cty.String,
+				})),
+				"baz": cty.NullVal(cty.Object(map[string]cty.Type{
+					"boz": cty.String,
+				})),
+			}),
+			// The bloop attribue and baz block does not exist in the config,
+			// and therefore shouldn't be planned.
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+				"bloop": cty.NullVal(cty.Object(map[string]cty.Type{
+					"blop": cty.String,
+				})),
+				"baz": cty.NullVal(cty.Object(map[string]cty.Type{
+					"boz": cty.String,
+				})),
+			}),
+		},
+		"no prior with set": {
+			// This one is here because our handling of sets is more complex
+			// than others (due to the fuzzy correlation heuristic) and
+			// historically that caused us some panic-related grief.
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"baz": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"boz": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+						Computed: true,
+						Optional: true,
+					},
+				},
+			},
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.ObjectVal(map[string]cty.Value{
+				"baz": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"boz": cty.StringVal("world"),
+					}),
+				}),
+				"bloop": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("blub"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"baz": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"boz": cty.StringVal("world"),
+					}),
+				}),
+				"bloop": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("blub"),
+					}),
+				}),
+			}),
+		},
+		"prior attributes": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"bar": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"baz": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+					"boz": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSingle,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("bonjour"),
+				"bar": cty.StringVal("petit dejeuner"),
+				"baz": cty.StringVal("grande dejeuner"),
+				"boz": cty.StringVal("a la monde"),
+				"bloop": cty.ObjectVal(map[string]cty.Value{
+					"blop": cty.StringVal("glub"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("hello"),
+				"bar": cty.NullVal(cty.String),
+				"baz": cty.NullVal(cty.String),
+				"boz": cty.StringVal("world"),
+				"bloop": cty.ObjectVal(map[string]cty.Value{
+					"blop": cty.StringVal("bleep"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("hello"),
+				"bar": cty.StringVal("petit dejeuner"),
+				"baz": cty.StringVal("grande dejeuner"),
+				"boz": cty.StringVal("world"),
+				"bloop": cty.ObjectVal(map[string]cty.Value{
+					"blop": cty.StringVal("bleep"),
+				}),
+			}),
+		},
+		"prior nested single": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": {
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+								"baz": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSingle,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Required: true,
+								},
+								"bleep": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ObjectVal(map[string]cty.Value{
+					"bar": cty.StringVal("beep"),
+					"baz": cty.StringVal("boop"),
+				}),
+				"bloop": cty.ObjectVal(map[string]cty.Value{
+					"blop":  cty.StringVal("glub"),
+					"bleep": cty.NullVal(cty.String),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ObjectVal(map[string]cty.Value{
+					"bar": cty.StringVal("bap"),
+					"baz": cty.NullVal(cty.String),
+				}),
+				"bloop": cty.ObjectVal(map[string]cty.Value{
+					"blop":  cty.StringVal("glub"),
+					"bleep": cty.StringVal("beep"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ObjectVal(map[string]cty.Value{
+					"bar": cty.StringVal("bap"),
+					"baz": cty.StringVal("boop"),
+				}),
+				"bloop": cty.ObjectVal(map[string]cty.Value{
+					"blop":  cty.StringVal("glub"),
+					"bleep": cty.StringVal("beep"),
+				}),
+			}),
+		},
+		"prior nested single to null": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": {
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+								"baz": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSingle,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Required: true,
+								},
+								"bleep": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ObjectVal(map[string]cty.Value{
+					"bar": cty.StringVal("beep"),
+					"baz": cty.StringVal("boop"),
+				}),
+				"bloop": cty.ObjectVal(map[string]cty.Value{
+					"blop":  cty.StringVal("glub"),
+					"bleep": cty.NullVal(cty.String),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(cty.Object(map[string]cty.Type{
+					"bar": cty.String,
+					"baz": cty.String,
+				})),
+				"bloop": cty.NullVal(cty.Object(map[string]cty.Type{
+					"blop":  cty.String,
+					"bleep": cty.String,
+				})),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.NullVal(cty.Object(map[string]cty.Type{
+					"bar": cty.String,
+					"baz": cty.String,
+				})),
+				"bloop": cty.NullVal(cty.Object(map[string]cty.Type{
+					"blop":  cty.String,
+					"bleep": cty.String,
+				})),
+			}),
+		},
+
+		"prior optional computed nested single to null": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSingle,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Required: true,
+								},
+								"bleep": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+						Computed: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.ObjectVal(map[string]cty.Value{
+					"blop":  cty.StringVal("glub"),
+					"bleep": cty.NullVal(cty.String),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.NullVal(cty.Object(map[string]cty.Type{
+					"blop":  cty.String,
+					"bleep": cty.String,
+				})),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.NullVal(cty.Object(map[string]cty.Type{
+					"blop":  cty.String,
+					"bleep": cty.String,
+				})),
+			}),
+		},
+
+		"prior nested list": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+								"baz": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("beep"),
+						"baz": cty.StringVal("boop"),
+					}),
+				}),
+				"bloop": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("bar"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("baz"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bap"),
+						"baz": cty.NullVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("blep"),
+						"baz": cty.NullVal(cty.String),
+					}),
+				}),
+				"bloop": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("bar"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("baz"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bap"),
+						"baz": cty.StringVal("boop"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("blep"),
+						"baz": cty.NullVal(cty.String),
+					}),
+				}),
+				"bloop": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("bar"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("baz"),
+					}),
+				}),
+			}),
+		},
+		"prior nested list with dynamic": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+								"baz": {
+									Type:     cty.DynamicPseudoType,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.DynamicPseudoType,
+									Required: true,
+								},
+								"blub": {
+									Type:     cty.DynamicPseudoType,
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.TupleVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("beep"),
+						"baz": cty.StringVal("boop"),
+					}),
+				}),
+				"bloop": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("bar"),
+						"blub": cty.StringVal("glub"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("baz"),
+						"blub": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.TupleVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bap"),
+						"baz": cty.NullVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("blep"),
+						"baz": cty.NullVal(cty.String),
+					}),
+				}),
+				"bloop": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("bar"),
+						"blub": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.TupleVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bap"),
+						"baz": cty.StringVal("boop"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("blep"),
+						"baz": cty.NullVal(cty.String),
+					}),
+				}),
+				"bloop": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("bar"),
+						"blub": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+		},
+		"prior nested map": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": {
+						Nesting: configschema.NestingMap,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+								"baz": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("beep"),
+						"baz": cty.StringVal("boop"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("blep"),
+						"baz": cty.StringVal("boot"),
+					}),
+				}),
+				"bloop": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("glub"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("blub"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bap"),
+						"baz": cty.NullVal(cty.String),
+					}),
+					"c": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bosh"),
+						"baz": cty.NullVal(cty.String),
+					}),
+				}),
+				"bloop": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("glub"),
+					}),
+					"c": cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("blub"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bap"),
+						"baz": cty.StringVal("boop"),
+					}),
+					"c": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bosh"),
+						"baz": cty.NullVal(cty.String),
+					}),
+				}),
+				"bloop": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("glub"),
+					}),
+					"c": cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("blub"),
+					}),
+				}),
+			}),
+		},
+
+		"prior optional computed nested map elem to null": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Optional: true,
+								},
+								"bleep": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"blop":  cty.StringVal("glub"),
+						"bleep": cty.StringVal("computed"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"blop":  cty.StringVal("blub"),
+						"bleep": cty.StringVal("computed"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.MapVal(map[string]cty.Value{
+					"a": cty.NullVal(cty.Object(map[string]cty.Type{
+						"blop":  cty.String,
+						"bleep": cty.String,
+					})),
+					"c": cty.ObjectVal(map[string]cty.Value{
+						"blop":  cty.StringVal("blub"),
+						"bleep": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.MapVal(map[string]cty.Value{
+					"a": cty.NullVal(cty.Object(map[string]cty.Type{
+						"blop":  cty.String,
+						"bleep": cty.String,
+					})),
+					"c": cty.ObjectVal(map[string]cty.Value{
+						"blop":  cty.StringVal("blub"),
+						"bleep": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+		},
+
+		"prior optional computed nested map to null": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Optional: true,
+								},
+								"bleep": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+						Optional: true,
+						Computed: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"blop":  cty.StringVal("glub"),
+						"bleep": cty.StringVal("computed"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"blop":  cty.StringVal("blub"),
+						"bleep": cty.StringVal("computed"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.NullVal(cty.Map(
+					cty.Object(map[string]cty.Type{
+						"blop":  cty.String,
+						"bleep": cty.String,
+					}),
+				)),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.NullVal(cty.Map(
+					cty.Object(map[string]cty.Type{
+						"blop":  cty.String,
+						"bleep": cty.String,
+					}),
+				)),
+			}),
+		},
+
+		"prior nested map with dynamic": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": {
+						Nesting: configschema.NestingMap,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+								"baz": {
+									Type:     cty.DynamicPseudoType,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.DynamicPseudoType,
+									Required: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ObjectVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("beep"),
+						"baz": cty.StringVal("boop"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("blep"),
+						"baz": cty.ListVal([]cty.Value{cty.StringVal("boot")}),
+					}),
+				}),
+				"bloop": cty.ObjectVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("glub"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.NumberIntVal(13),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ObjectVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bap"),
+						"baz": cty.NullVal(cty.String),
+					}),
+					"c": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bosh"),
+						"baz": cty.NullVal(cty.List(cty.String)),
+					}),
+				}),
+				"bloop": cty.ObjectVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("blep"),
+					}),
+					"c": cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.NumberIntVal(13),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ObjectVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bap"),
+						"baz": cty.StringVal("boop"),
+					}),
+					"c": cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bosh"),
+						"baz": cty.NullVal(cty.List(cty.String)),
+					}),
+				}),
+				"bloop": cty.ObjectVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("blep"),
+					}),
+					"c": cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.NumberIntVal(13),
+					}),
+				}),
+			}),
+		},
+		"prior nested set": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {
+									// This non-computed attribute will serve
+									// as our matching key for propagating
+									// "baz" from elements in the prior value.
+									Type:     cty.String,
+									Optional: true,
+								},
+								"baz": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Required: true,
+								},
+								"bleep": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("beep"),
+						"baz": cty.StringVal("boop"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("blep"),
+						"baz": cty.StringVal("boot"),
+					}),
+				}),
+				"bloop": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop":  cty.StringVal("glubglub"),
+						"bleep": cty.NullVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"blop":  cty.StringVal("glubglub"),
+						"bleep": cty.StringVal("beep"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("beep"),
+						"baz": cty.NullVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bosh"),
+						"baz": cty.NullVal(cty.String),
+					}),
+				}),
+				"bloop": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop":  cty.StringVal("glubglub"),
+						"bleep": cty.NullVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"blop":  cty.StringVal("glub"),
+						"bleep": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("beep"),
+						"baz": cty.StringVal("boop"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("bosh"),
+						"baz": cty.NullVal(cty.String),
+					}),
+				}),
+				"bloop": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop":  cty.StringVal("glubglub"),
+						"bleep": cty.NullVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"blop":  cty.StringVal("glub"),
+						"bleep": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+		},
+
+		"set with partial optional computed change": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"multi": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"opt": {
+									Type:     cty.String,
+									Optional: true,
+								},
+								"cmp": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"cmp": cty.StringVal("OK"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("two"),
+						"cmp": cty.StringVal("OK"),
+					}),
+				}),
+			}),
+
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"cmp": cty.NullVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("replaced"),
+						"cmp": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			// "one" can be correlated because it is a non-computed value in
+			// the configuration.
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"cmp": cty.StringVal("OK"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("replaced"),
+						"cmp": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+		},
+
+		"set without partial optional computed change": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"multi": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"opt": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+								"req": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"req": cty.StringVal("one"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("two"),
+						"req": cty.StringVal("two"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.NullVal(cty.String),
+						"req": cty.StringVal("one"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.NullVal(cty.String),
+						"req": cty.StringVal("two"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"req": cty.StringVal("one"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("two"),
+						"req": cty.StringVal("two"),
+					}),
+				}),
+			}),
+		},
+
+		"sets differing only by unknown": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"multi": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"optional": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"optional": cty.UnknownVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"optional": cty.UnknownVal(cty.String),
+					}),
+				}),
+				"bloop": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.UnknownVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.UnknownVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					// These remain distinct because unknown values never
+					// compare equal. They may be consolidated together once
+					// the values become known, though.
+					cty.ObjectVal(map[string]cty.Value{
+						"optional": cty.UnknownVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"optional": cty.UnknownVal(cty.String),
+					}),
+				}),
+				"bloop": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.UnknownVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.UnknownVal(cty.String),
+					}),
+				}),
+			}),
+		},
+		"nested list in set": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							BlockTypes: map[string]*configschema.NestedBlock{
+								"bar": {
+									Nesting: configschema.NestingList,
+									Block: configschema.Block{
+										Attributes: map[string]*configschema.Attribute{
+											"baz": {
+												Type: cty.String,
+											},
+											"qux": {
+												Type:     cty.String,
+												Computed: true,
+												Optional: true,
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.ListVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"baz": cty.StringVal("beep"),
+								"qux": cty.StringVal("boop"),
+							}),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.ListVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"baz": cty.StringVal("beep"),
+								"qux": cty.NullVal(cty.String),
+							}),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.ListVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"baz": cty.StringVal("beep"),
+								"qux": cty.StringVal("boop"),
+							}),
+						}),
+					}),
+				}),
+			}),
+		},
+		"empty nested list in set": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							BlockTypes: map[string]*configschema.NestedBlock{
+								"bar": {
+									Nesting: configschema.NestingList,
+									Block:   configschema.Block{},
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.ListValEmpty((&configschema.Block{}).ImpliedType()),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.ListValEmpty((&configschema.Block{}).ImpliedType()),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.ListValEmpty((&configschema.Block{}).ImpliedType()),
+					}),
+				}),
+			}),
+		},
+		"nested list with dynamic in set": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							BlockTypes: map[string]*configschema.NestedBlock{
+								"bar": {
+									Nesting: configschema.NestingList,
+									Block: configschema.Block{
+										Attributes: map[string]*configschema.Attribute{
+											"baz": {
+												Type: cty.DynamicPseudoType,
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.TupleVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"baz": cty.StringVal("true"),
+							}),
+							cty.ObjectVal(map[string]cty.Value{
+								"baz": cty.ListVal([]cty.Value{cty.StringVal("true")}),
+							}),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.TupleVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"baz": cty.StringVal("true"),
+							}),
+							cty.ObjectVal(map[string]cty.Value{
+								"baz": cty.ListVal([]cty.Value{cty.StringVal("true")}),
+							}),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.TupleVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"baz": cty.StringVal("true"),
+							}),
+							cty.ObjectVal(map[string]cty.Value{
+								"baz": cty.ListVal([]cty.Value{cty.StringVal("true")}),
+							}),
+						}),
+					}),
+				}),
+			}),
+		},
+		"nested map with dynamic in set": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							BlockTypes: map[string]*configschema.NestedBlock{
+								"bar": {
+									Nesting: configschema.NestingMap,
+									Block: configschema.Block{
+										Attributes: map[string]*configschema.Attribute{
+											"baz": {
+												Type:     cty.DynamicPseudoType,
+												Optional: true,
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.ObjectVal(map[string]cty.Value{
+							"bing": cty.ObjectVal(map[string]cty.Value{
+								"baz": cty.StringVal("true"),
+							}),
+							"bang": cty.ObjectVal(map[string]cty.Value{
+								"baz": cty.ListVal([]cty.Value{cty.StringVal("true")}),
+							}),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.ObjectVal(map[string]cty.Value{
+							"bing": cty.ObjectVal(map[string]cty.Value{
+								"baz": cty.ListVal([]cty.Value{cty.StringVal("true")}),
+							}),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.ObjectVal(map[string]cty.Value{
+							"bing": cty.ObjectVal(map[string]cty.Value{
+								"baz": cty.ListVal([]cty.Value{cty.StringVal("true")}),
+							}),
+						}),
+					}),
+				}),
+			}),
+		},
+		"empty nested map in set": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							BlockTypes: map[string]*configschema.NestedBlock{
+								"bar": {
+									Nesting: configschema.NestingMap,
+									Block: configschema.Block{
+										Attributes: map[string]*configschema.Attribute{
+											"baz": {
+												Type:     cty.String,
+												Optional: true,
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.MapValEmpty(cty.Object(map[string]cty.Type{
+							"baz": cty.String,
+						})),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.MapVal(map[string]cty.Value{
+							"bing": cty.ObjectVal(map[string]cty.Value{
+								"baz": cty.StringVal("true"),
+							}),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.MapVal(map[string]cty.Value{
+							"bing": cty.ObjectVal(map[string]cty.Value{
+								"baz": cty.StringVal("true"),
+							}),
+						}),
+					}),
+				}),
+			}),
+		},
+		// This example has a mixture of optional, computed and required in a deeply-nested NestedType attribute
+		"deeply NestedType": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSingle,
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {
+									NestedType: &configschema.Object{
+										Nesting:    configschema.NestingSingle,
+										Attributes: testAttributes,
+									},
+									Required: true,
+								},
+								"baz": {
+									NestedType: &configschema.Object{
+										Nesting:    configschema.NestingSingle,
+										Attributes: testAttributes,
+									},
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			// prior
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ObjectVal(map[string]cty.Value{
+					"bar": cty.NullVal(cty.DynamicPseudoType),
+					"baz": cty.ObjectVal(map[string]cty.Value{
+						"optional":          cty.NullVal(cty.String),
+						"computed":          cty.StringVal("hello"),
+						"optional_computed": cty.StringVal("prior"),
+						"required":          cty.StringVal("present"),
+					}),
+				}),
+			}),
+			// config
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ObjectVal(map[string]cty.Value{
+					"bar": cty.UnknownVal(cty.Object(map[string]cty.Type{ // explicit unknown from the config
+						"optional":          cty.String,
+						"computed":          cty.String,
+						"optional_computed": cty.String,
+						"required":          cty.String,
+					})),
+					"baz": cty.ObjectVal(map[string]cty.Value{
+						"optional":          cty.NullVal(cty.String),
+						"computed":          cty.NullVal(cty.String),
+						"optional_computed": cty.StringVal("hello"),
+						"required":          cty.StringVal("present"),
+					}),
+				}),
+			}),
+			// want
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.ObjectVal(map[string]cty.Value{
+					"bar": cty.UnknownVal(cty.Object(map[string]cty.Type{ // explicit unknown preserved from the config
+						"optional":          cty.String,
+						"computed":          cty.String,
+						"optional_computed": cty.String,
+						"required":          cty.String,
+					})),
+					"baz": cty.ObjectVal(map[string]cty.Value{
+						"optional":          cty.NullVal(cty.String),  // config is null
+						"computed":          cty.StringVal("hello"),   // computed values come from prior
+						"optional_computed": cty.StringVal("hello"),   // config takes precedent over prior in opt+computed
+						"required":          cty.StringVal("present"), // value from config
+					}),
+				}),
+			}),
+		},
+		"deeply nested set": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {
+									NestedType: &configschema.Object{
+										Nesting:    configschema.NestingSet,
+										Attributes: testAttributes,
+									},
+									Required: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			// prior values
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.SetVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"optional":          cty.StringVal("prior"),
+								"computed":          cty.StringVal("prior"),
+								"optional_computed": cty.StringVal("prior"),
+								"required":          cty.StringVal("prior"),
+							}),
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.SetVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"optional":          cty.StringVal("other_prior"),
+								"computed":          cty.StringVal("other_prior"),
+								"optional_computed": cty.StringVal("other_prior"),
+								"required":          cty.StringVal("other_prior"),
+							}),
+						}),
+					}),
+				}),
+			}),
+			// config differs from prior
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+							"optional":          cty.StringVal("configured"),
+							"computed":          cty.NullVal(cty.String), // computed attrs are null in config
+							"optional_computed": cty.StringVal("configured"),
+							"required":          cty.StringVal("configured"),
+						})}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+							"optional":          cty.NullVal(cty.String), // explicit null in config
+							"computed":          cty.NullVal(cty.String), // computed attrs are null in config
+							"optional_computed": cty.StringVal("other_configured"),
+							"required":          cty.StringVal("other_configured"),
+						})}),
+					}),
+				}),
+			}),
+			// want:
+			cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+							"optional":          cty.StringVal("configured"),
+							"computed":          cty.NullVal(cty.String),
+							"optional_computed": cty.StringVal("configured"),
+							"required":          cty.StringVal("configured"),
+						})}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+							"optional":          cty.NullVal(cty.String), // explicit null in config is preserved
+							"computed":          cty.NullVal(cty.String),
+							"optional_computed": cty.StringVal("other_configured"),
+							"required":          cty.StringVal("other_configured"),
+						})}),
+					}),
+				}),
+			}),
+		},
+		"expected null NestedTypes": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"single": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSingle,
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {Type: cty.String},
+							},
+						},
+						Optional: true,
+					},
+					"list": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {Type: cty.String},
+							},
+						},
+						Optional: true,
+					},
+					"set": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {Type: cty.String},
+							},
+						},
+						Optional: true,
+					},
+					"map": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {Type: cty.String},
+							},
+						},
+						Optional: true,
+					},
+					"nested_map": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"inner": {
+									NestedType: &configschema.Object{
+										Nesting:    configschema.NestingSingle,
+										Attributes: testAttributes,
+									},
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"single": cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("baz")}),
+				"list":   cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("baz")})}),
+				"map": cty.MapVal(map[string]cty.Value{
+					"map_entry": cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("baz")}),
+				}),
+				"set": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("baz")})}),
+				"nested_map": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"inner": cty.ObjectVal(map[string]cty.Value{
+							"optional":          cty.StringVal("foo"),
+							"computed":          cty.StringVal("foo"),
+							"optional_computed": cty.StringVal("foo"),
+							"required":          cty.StringVal("foo"),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"single": cty.NullVal(cty.Object(map[string]cty.Type{"bar": cty.String})),
+				"list":   cty.NullVal(cty.List(cty.Object(map[string]cty.Type{"bar": cty.String}))),
+				"map":    cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{"bar": cty.String}))),
+				"set":    cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{"bar": cty.String}))),
+				"nested_map": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{
+					"inner": cty.Object(map[string]cty.Type{
+						"optional":          cty.String,
+						"computed":          cty.String,
+						"optional_computed": cty.String,
+						"required":          cty.String,
+					}),
+				}))),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"single": cty.NullVal(cty.Object(map[string]cty.Type{"bar": cty.String})),
+				"list":   cty.NullVal(cty.List(cty.Object(map[string]cty.Type{"bar": cty.String}))),
+				"map":    cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{"bar": cty.String}))),
+				"set":    cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{"bar": cty.String}))),
+				"nested_map": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{
+					"inner": cty.Object(map[string]cty.Type{
+						"optional":          cty.String,
+						"computed":          cty.String,
+						"optional_computed": cty.String,
+						"required":          cty.String,
+					}),
+				}))),
+			}),
+		},
+		"expected empty NestedTypes": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"set": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {Type: cty.String},
+							},
+						},
+						Optional: true,
+					},
+					"map": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {Type: cty.String},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"map": cty.MapValEmpty(cty.Object(map[string]cty.Type{"bar": cty.String})),
+				"set": cty.SetValEmpty(cty.Object(map[string]cty.Type{"bar": cty.String})),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"map": cty.MapValEmpty(cty.Object(map[string]cty.Type{"bar": cty.String})),
+				"set": cty.SetValEmpty(cty.Object(map[string]cty.Type{"bar": cty.String})),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"map": cty.MapValEmpty(cty.Object(map[string]cty.Type{"bar": cty.String})),
+				"set": cty.SetValEmpty(cty.Object(map[string]cty.Type{"bar": cty.String})),
+			}),
+		},
+		"optional types set replacement": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"set": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("old"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("new"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bar": cty.StringVal("new"),
+					}),
+				}),
+			}),
+		},
+		"prior null nested objects": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"single": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSingle,
+							Attributes: map[string]*configschema.Attribute{
+								"list": {
+									NestedType: &configschema.Object{
+										Nesting: configschema.NestingList,
+										Attributes: map[string]*configschema.Attribute{
+											"foo": {
+												Type: cty.String,
+											},
+										},
+									},
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+					"map": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"map": {
+									NestedType: &configschema.Object{
+										Nesting: configschema.NestingList,
+										Attributes: map[string]*configschema.Attribute{
+											"foo": {
+												Type: cty.String,
+											},
+										},
+									},
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"single": cty.Object(map[string]cty.Type{
+					"list": cty.List(cty.Object(map[string]cty.Type{
+						"foo": cty.String,
+					})),
+				}),
+				"map": cty.Map(cty.Object(map[string]cty.Type{
+					"list": cty.List(cty.Object(map[string]cty.Type{
+						"foo": cty.String,
+					})),
+				})),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"single": cty.ObjectVal(map[string]cty.Value{
+					"list": cty.ListVal([]cty.Value{
+						cty.ObjectVal(map[string]cty.Value{
+							"foo": cty.StringVal("a"),
+						}),
+						cty.ObjectVal(map[string]cty.Value{
+							"foo": cty.StringVal("b"),
+						}),
+					}),
+				}),
+				"map": cty.MapVal(map[string]cty.Value{
+					"one": cty.ObjectVal(map[string]cty.Value{
+						"list": cty.ListVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.StringVal("a"),
+							}),
+							cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.StringVal("b"),
+							}),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"single": cty.ObjectVal(map[string]cty.Value{
+					"list": cty.ListVal([]cty.Value{
+						cty.ObjectVal(map[string]cty.Value{
+							"foo": cty.StringVal("a"),
+						}),
+						cty.ObjectVal(map[string]cty.Value{
+							"foo": cty.StringVal("b"),
+						}),
+					}),
+				}),
+				"map": cty.MapVal(map[string]cty.Value{
+					"one": cty.ObjectVal(map[string]cty.Value{
+						"list": cty.ListVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.StringVal("a"),
+							}),
+							cty.ObjectVal(map[string]cty.Value{
+								"foo": cty.StringVal("b"),
+							}),
+						}),
+					}),
+				}),
+			}),
+		},
+
+		// Data sources are planned with an unknown value.
+		// Note that this plan fails AssertPlanValid, because for managed
+		// resources an instance would never be completely unknown.
+		"unknown prior nested objects": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"list": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"list": {
+									NestedType: &configschema.Object{
+										Nesting: configschema.NestingList,
+										Attributes: map[string]*configschema.Attribute{
+											"foo": {
+												Type: cty.String,
+											},
+										},
+									},
+									Computed: true,
+								},
+							},
+						},
+						Computed: true,
+					},
+				},
+			},
+			cty.UnknownVal(cty.Object(map[string]cty.Type{
+				"list": cty.List(cty.Object(map[string]cty.Type{
+					"list": cty.List(cty.Object(map[string]cty.Type{
+						"foo": cty.String,
+					})),
+				})),
+			})),
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"list": cty.List(cty.Object(map[string]cty.Type{
+					"list": cty.List(cty.Object(map[string]cty.Type{
+						"foo": cty.String,
+					})),
+				})),
+			})),
+			cty.UnknownVal(cty.Object(map[string]cty.Type{
+				"list": cty.List(cty.Object(map[string]cty.Type{
+					"list": cty.List(cty.Object(map[string]cty.Type{
+						"foo": cty.String,
+					})),
+				})),
+			})),
+		},
+
+		// A nested object with computed attributes, which is contained in an
+		// optional+computed container. The nested computed values should be
+		// represented in the proposed new object.
+		"config within optional+computed": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"list_obj": {
+						Optional: true,
+						Computed: true,
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"obj": {
+									Optional: true,
+									NestedType: &configschema.Object{
+										Nesting: configschema.NestingSingle,
+										Attributes: map[string]*configschema.Attribute{
+											"optional": {Type: cty.String, Optional: true},
+											"computed": {Type: cty.String, Computed: true},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"list_obj": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("prior"),
+							"computed": cty.StringVal("prior computed"),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"list_obj": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("prior"),
+							"computed": cty.NullVal(cty.String),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"list_obj": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("prior"),
+							"computed": cty.StringVal("prior computed"),
+						}),
+					}),
+				}),
+			}),
+		},
+
+		// A nested object with computed attributes, which is contained in an
+		// optional+computed container. The prior nested object contains values
+		// which could not be computed, therefor the proposed new value must be
+		// the null value from the configuration.
+		"computed within optional+computed": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"list_obj": {
+						Optional: true,
+						Computed: true,
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"obj": {
+									Optional: true,
+									NestedType: &configschema.Object{
+										Nesting: configschema.NestingSingle,
+										Attributes: map[string]*configschema.Attribute{
+											"optional": {Type: cty.String, Optional: true},
+											"computed": {Type: cty.String, Computed: true},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"list_obj": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("prior"),
+							"computed": cty.StringVal("prior computed"),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"list_obj": cty.NullVal(cty.List(
+					cty.Object(map[string]cty.Type{
+						"obj": cty.Object(map[string]cty.Type{
+							"optional": cty.String,
+							"computed": cty.String,
+						}),
+					}),
+				)),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"list_obj": cty.NullVal(cty.List(
+					cty.Object(map[string]cty.Type{
+						"obj": cty.Object(map[string]cty.Type{
+							"optional": cty.String,
+							"computed": cty.String,
+						}),
+					}),
+				)),
+			}),
+		},
+
+		// A nested object with computed attributes, which is contained in an
+		// optional+computed set. The nested computed values should be
+		// represented in the proposed new object, and correlated with state
+		// via the non-computed attributes.
+		"config add within optional+computed set": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"set_obj": {
+						Optional: true,
+						Computed: true,
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"obj": {
+									Optional: true,
+									NestedType: &configschema.Object{
+										Nesting: configschema.NestingSingle,
+										Attributes: map[string]*configschema.Attribute{
+											"optional": {Type: cty.String, Optional: true},
+											"computed": {Type: cty.String, Computed: true},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"set_obj": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("first"),
+							"computed": cty.StringVal("first computed"),
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("second"),
+							"computed": cty.StringVal("second computed"),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"set_obj": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("first"),
+							"computed": cty.NullVal(cty.String),
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("second"),
+							"computed": cty.NullVal(cty.String),
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("third"),
+							"computed": cty.NullVal(cty.String),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"set_obj": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("first"),
+							"computed": cty.StringVal("first computed"),
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("second"),
+							"computed": cty.StringVal("second computed"),
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("third"),
+							"computed": cty.NullVal(cty.String),
+						}),
+					}),
+				}),
+			}),
+		},
+
+		// A nested object with computed attributes, which is contained in a
+		// set. The nested computed values should be represented in the
+		// proposed new object, and correlated with state via the non-computed
+		// attributes.
+		"config add within set block": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"set_obj": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"obj": {
+									Optional: true,
+									NestedType: &configschema.Object{
+										Nesting: configschema.NestingSingle,
+										Attributes: map[string]*configschema.Attribute{
+											"optional": {Type: cty.String, Optional: true},
+											"computed": {Type: cty.String, Optional: true, Computed: true},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"set_obj": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("first"),
+							"computed": cty.StringVal("first computed"),
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("second"),
+							"computed": cty.StringVal("second from config"),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"set_obj": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("first"),
+							"computed": cty.NullVal(cty.String),
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("second"),
+							"computed": cty.StringVal("second from config"),
+						}),
+					}),
+					// new "third" value added
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("third"),
+							"computed": cty.NullVal(cty.String),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"set_obj": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("first"),
+							"computed": cty.StringVal("first computed"),
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("second"),
+							"computed": cty.StringVal("second from config"),
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("third"),
+							"computed": cty.NullVal(cty.String),
+						}),
+					}),
+				}),
+			}),
+		},
+
+		// A nested object with computed attributes, which is contained in a
+		// set. The nested computed values should be represented in the
+		// proposed new object, and correlated with state via the non-computed
+		// attributes.
+		"config change within set block": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"set_obj": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"obj": {
+									Optional: true,
+									NestedType: &configschema.Object{
+										Nesting: configschema.NestingSingle,
+										Attributes: map[string]*configschema.Attribute{
+											"optional": {Type: cty.String, Optional: true},
+											"computed": {Type: cty.String, Optional: true, Computed: true},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"set_obj": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("first"),
+							"computed": cty.StringVal("first computed"),
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("second"),
+							"computed": cty.StringVal("second computed"),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"set_obj": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("first"),
+							"computed": cty.NullVal(cty.String),
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("changed"),
+							"computed": cty.NullVal(cty.String),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"set_obj": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("first"),
+							"computed": cty.StringVal("first computed"),
+						}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"obj": cty.ObjectVal(map[string]cty.Value{
+							"optional": cty.StringVal("changed"),
+							"computed": cty.NullVal(cty.String),
+						}),
+					}),
+				}),
+			}),
+		},
+
+		"set attr with partial optional computed change": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"multi": {
+						Optional: true,
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"opt": {
+									Type:     cty.String,
+									Optional: true,
+								},
+								"oc": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"oc":  cty.StringVal("OK"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("two"),
+						"oc":  cty.StringVal("OK"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"oc":  cty.NullVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("replaced"),
+						"oc":  cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"oc":  cty.StringVal("OK"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("replaced"),
+						"oc":  cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+		},
+
+		"set attr without optional computed change": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"multi": {
+						Optional: true,
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"opt": {
+									Type:     cty.String,
+									Optional: true,
+								},
+								"oc": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"oc":  cty.StringVal("OK"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("two"),
+						"oc":  cty.StringVal("OK"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"oc":  cty.NullVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("two"),
+						"oc":  cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"oc":  cty.StringVal("OK"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("two"),
+						"oc":  cty.StringVal("OK"),
+					}),
+				}),
+			}),
+		},
+
+		"set attr with all optional computed": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"multi": {
+						Optional: true,
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"opt": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+								"oc": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"oc":  cty.StringVal("OK"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("two"),
+						"oc":  cty.StringVal("OK"),
+					}),
+				}),
+			}),
+			// Each of these values can be correlated by the existence of the
+			// optional config attribute. Because "one" and "two" are set in
+			// the config, they must exist in the state regardless of
+			// optional&computed.
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"oc":  cty.NullVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("two"),
+						"oc":  cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"oc":  cty.StringVal("OK"),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("two"),
+						"oc":  cty.StringVal("OK"),
+					}),
+				}),
+			}),
+		},
+
+		"set block with all optional computed and nested object types": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"multi": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"opt": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+								"oc": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+								"attr": {
+									Optional: true,
+									NestedType: &configschema.Object{
+										Nesting: configschema.NestingSet,
+										Attributes: map[string]*configschema.Attribute{
+											"opt": {
+												Type:     cty.String,
+												Optional: true,
+												Computed: true,
+											},
+											"oc": {
+												Type:     cty.String,
+												Optional: true,
+												Computed: true,
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"oc":  cty.StringVal("OK"),
+						"attr": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+							"opt": cty.StringVal("one"),
+							"oc":  cty.StringVal("OK"),
+						})}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("two"),
+						"oc":  cty.StringVal("OK"),
+						"attr": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+							"opt": cty.StringVal("two"),
+							"oc":  cty.StringVal("OK"),
+						})}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"oc":  cty.NullVal(cty.String),
+						"attr": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+							"opt": cty.StringVal("one"),
+							"oc":  cty.StringVal("OK"),
+						})}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("two"),
+						"oc":  cty.StringVal("OK"),
+						"attr": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+							"opt": cty.StringVal("two"),
+							"oc":  cty.NullVal(cty.String),
+						})}),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("three"),
+						"oc":  cty.NullVal(cty.String),
+						"attr": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{
+							"opt": cty.String,
+							"oc":  cty.String,
+						}))),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"multi": cty.SetVal([]cty.Value{
+					// We can correlate this with prior from the outer object
+					// attributes, and the equal nested set.
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("one"),
+						"oc":  cty.StringVal("OK"),
+						"attr": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+							"opt": cty.StringVal("one"),
+							"oc":  cty.StringVal("OK"),
+						})}),
+					}),
+					// This value is overridden by config, because we can't
+					// correlate optional+computed config values within nested
+					// sets.
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("two"),
+						"oc":  cty.StringVal("OK"),
+						"attr": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+							"opt": cty.StringVal("two"),
+							"oc":  cty.NullVal(cty.String),
+						})}),
+					}),
+					// This value was taken only from config
+					cty.ObjectVal(map[string]cty.Value{
+						"opt": cty.StringVal("three"),
+						"oc":  cty.NullVal(cty.String),
+						"attr": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{
+							"opt": cty.String,
+							"oc":  cty.String,
+						}))),
+					}),
+				}),
+			}),
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			got := ProposedNew(test.Schema, test.Prior, test.Config)
+			if !got.RawEquals(test.Want) {
+				t.Errorf("wrong result\ngot:  %swant: %s", dump.Value(got), dump.Value(test.Want))
+			}
+		})
+	}
+}
+
+var testAttributes = map[string]*configschema.Attribute{
+	"optional": {
+		Type:     cty.String,
+		Optional: true,
+	},
+	"computed": {
+		Type:     cty.String,
+		Computed: true,
+	},
+	"optional_computed": {
+		Type:     cty.String,
+		Computed: true,
+		Optional: true,
+	},
+	"required": {
+		Type:     cty.String,
+		Required: true,
+	},
+}
diff --git a/v1.5.7/internal/plans/objchange/plan_valid.go b/v1.5.7/internal/plans/objchange/plan_valid.go
new file mode 100644
index 0000000..ca30e1a
--- /dev/null
+++ b/v1.5.7/internal/plans/objchange/plan_valid.go
@@ -0,0 +1,468 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package objchange
+
+import (
+	"fmt"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+// AssertPlanValid checks checks whether a planned new state returned by a
+// provider's PlanResourceChange method is suitable to achieve a change
+// from priorState to config. It returns a slice with nonzero length if
+// any problems are detected. Because problems here indicate bugs in the
+// provider that generated the plannedState, they are written with provider
+// developers as an audience, rather than end-users.
+//
+// All of the given values must have the same type and must conform to the
+// implied type of the given schema, or this function may panic or produce
+// garbage results.
+//
+// During planning, a provider may only make changes to attributes that are
+// null (unset) in the configuration and are marked as "computed" in the
+// resource type schema, in order to insert any default values the provider
+// may know about. If the default value cannot be determined until apply time,
+// the provider can return an unknown value. Providers are forbidden from
+// planning a change that disagrees with any non-null argument in the
+// configuration.
+//
+// As a special exception, providers _are_ allowed to provide attribute values
+// conflicting with configuration if and only if the planned value exactly
+// matches the corresponding attribute value in the prior state. The provider
+// can use this to signal that the new value is functionally equivalent to
+// the old and thus no change is required.
+func AssertPlanValid(schema *configschema.Block, priorState, config, plannedState cty.Value) []error {
+	return assertPlanValid(schema, priorState, config, plannedState, nil)
+}
+
+func assertPlanValid(schema *configschema.Block, priorState, config, plannedState cty.Value, path cty.Path) []error {
+	var errs []error
+	if plannedState.IsNull() && !config.IsNull() {
+		errs = append(errs, path.NewErrorf("planned for absence but config wants existence"))
+		return errs
+	}
+	if config.IsNull() && !plannedState.IsNull() {
+		errs = append(errs, path.NewErrorf("planned for existence but config wants absence"))
+		return errs
+	}
+	if plannedState.IsNull() {
+		// No further checks possible if the planned value is null
+		return errs
+	}
+
+	impTy := schema.ImpliedType()
+
+	// verify attributes
+	moreErrs := assertPlannedAttrsValid(schema.Attributes, priorState, config, plannedState, path)
+	errs = append(errs, moreErrs...)
+
+	for name, blockS := range schema.BlockTypes {
+		path := append(path, cty.GetAttrStep{Name: name})
+		plannedV := plannedState.GetAttr(name)
+		configV := config.GetAttr(name)
+		priorV := cty.NullVal(impTy.AttributeType(name))
+		if !priorState.IsNull() {
+			priorV = priorState.GetAttr(name)
+		}
+		if plannedV.RawEquals(configV) {
+			// Easy path: nothing has changed at all
+			continue
+		}
+
+		if !configV.IsKnown() {
+			// An unknown config block represents a dynamic block where the
+			// for_each value is unknown, and therefor cannot be altered by the
+			// provider.
+			errs = append(errs, path.NewErrorf("planned value %#v for unknown dynamic block", plannedV))
+			continue
+		}
+
+		if !plannedV.IsKnown() {
+			// Only dynamic configuration can set blocks to unknown, so this is
+			// not allowed from the provider. This means that either the config
+			// and plan should match, or we have an error where the plan
+			// changed the config value, both of which have been checked.
+			errs = append(errs, path.NewErrorf("attribute representing nested block must not be unknown itself; set nested attribute values to unknown instead"))
+			continue
+		}
+
+		switch blockS.Nesting {
+		case configschema.NestingSingle, configschema.NestingGroup:
+			moreErrs := assertPlanValid(&blockS.Block, priorV, configV, plannedV, path)
+			errs = append(errs, moreErrs...)
+		case configschema.NestingList:
+			// A NestingList might either be a list or a tuple, depending on
+			// whether there are dynamically-typed attributes inside. However,
+			// both support a similar-enough API that we can treat them the
+			// same for our purposes here.
+			if plannedV.IsNull() {
+				errs = append(errs, path.NewErrorf("attribute representing a list of nested blocks must be empty to indicate no blocks, not null"))
+				continue
+			}
+
+			if configV.IsNull() {
+				// Configuration cannot decode a block into a null value, but
+				// we could be dealing with a null returned by a legacy
+				// provider and inserted via ignore_changes. Fix the value in
+				// place so the length can still be compared.
+				configV = cty.ListValEmpty(configV.Type().ElementType())
+			}
+
+			plannedL := plannedV.LengthInt()
+			configL := configV.LengthInt()
+			if plannedL != configL {
+				errs = append(errs, path.NewErrorf("block count in plan (%d) disagrees with count in config (%d)", plannedL, configL))
+				continue
+			}
+
+			for it := plannedV.ElementIterator(); it.Next(); {
+				idx, plannedEV := it.Element()
+				path := append(path, cty.IndexStep{Key: idx})
+				if !plannedEV.IsKnown() {
+					errs = append(errs, path.NewErrorf("element representing nested block must not be unknown itself; set nested attribute values to unknown instead"))
+					continue
+				}
+				if !configV.HasIndex(idx).True() {
+					continue // should never happen since we checked the lengths above
+				}
+				configEV := configV.Index(idx)
+				priorEV := cty.NullVal(blockS.ImpliedType())
+				if !priorV.IsNull() && priorV.HasIndex(idx).True() {
+					priorEV = priorV.Index(idx)
+				}
+
+				moreErrs := assertPlanValid(&blockS.Block, priorEV, configEV, plannedEV, path)
+				errs = append(errs, moreErrs...)
+			}
+		case configschema.NestingMap:
+			if plannedV.IsNull() {
+				errs = append(errs, path.NewErrorf("attribute representing a map of nested blocks must be empty to indicate no blocks, not null"))
+				continue
+			}
+
+			// A NestingMap might either be a map or an object, depending on
+			// whether there are dynamically-typed attributes inside, but
+			// that's decided statically and so all values will have the same
+			// kind.
+			if plannedV.Type().IsObjectType() {
+				plannedAtys := plannedV.Type().AttributeTypes()
+				configAtys := configV.Type().AttributeTypes()
+				for k := range plannedAtys {
+					if _, ok := configAtys[k]; !ok {
+						errs = append(errs, path.NewErrorf("block key %q from plan is not present in config", k))
+						continue
+					}
+					path := append(path, cty.GetAttrStep{Name: k})
+
+					plannedEV := plannedV.GetAttr(k)
+					if !plannedEV.IsKnown() {
+						errs = append(errs, path.NewErrorf("element representing nested block must not be unknown itself; set nested attribute values to unknown instead"))
+						continue
+					}
+					configEV := configV.GetAttr(k)
+					priorEV := cty.NullVal(blockS.ImpliedType())
+					if !priorV.IsNull() && priorV.Type().HasAttribute(k) {
+						priorEV = priorV.GetAttr(k)
+					}
+					moreErrs := assertPlanValid(&blockS.Block, priorEV, configEV, plannedEV, path)
+					errs = append(errs, moreErrs...)
+				}
+				for k := range configAtys {
+					if _, ok := plannedAtys[k]; !ok {
+						errs = append(errs, path.NewErrorf("block key %q from config is not present in plan", k))
+						continue
+					}
+				}
+			} else {
+				plannedL := plannedV.LengthInt()
+				configL := configV.LengthInt()
+				if plannedL != configL {
+					errs = append(errs, path.NewErrorf("block count in plan (%d) disagrees with count in config (%d)", plannedL, configL))
+					continue
+				}
+				for it := plannedV.ElementIterator(); it.Next(); {
+					idx, plannedEV := it.Element()
+					path := append(path, cty.IndexStep{Key: idx})
+					if !plannedEV.IsKnown() {
+						errs = append(errs, path.NewErrorf("element representing nested block must not be unknown itself; set nested attribute values to unknown instead"))
+						continue
+					}
+					k := idx.AsString()
+					if !configV.HasIndex(idx).True() {
+						errs = append(errs, path.NewErrorf("block key %q from plan is not present in config", k))
+						continue
+					}
+					configEV := configV.Index(idx)
+					priorEV := cty.NullVal(blockS.ImpliedType())
+					if !priorV.IsNull() && priorV.HasIndex(idx).True() {
+						priorEV = priorV.Index(idx)
+					}
+					moreErrs := assertPlanValid(&blockS.Block, priorEV, configEV, plannedEV, path)
+					errs = append(errs, moreErrs...)
+				}
+				for it := configV.ElementIterator(); it.Next(); {
+					idx, _ := it.Element()
+					if !plannedV.HasIndex(idx).True() {
+						errs = append(errs, path.NewErrorf("block key %q from config is not present in plan", idx.AsString()))
+						continue
+					}
+				}
+			}
+		case configschema.NestingSet:
+			if plannedV.IsNull() {
+				errs = append(errs, path.NewErrorf("attribute representing a set of nested blocks must be empty to indicate no blocks, not null"))
+				continue
+			}
+
+			// Because set elements have no identifier with which to correlate
+			// them, we can't robustly validate the plan for a nested block
+			// backed by a set, and so unfortunately we need to just trust the
+			// provider to do the right thing. :(
+			//
+			// (In principle we could correlate elements by matching the
+			// subset of attributes explicitly set in config, except for the
+			// special diff suppression rule which allows for there to be a
+			// planned value that is constructed by mixing part of a prior
+			// value with part of a config value, creating an entirely new
+			// element that is not present in either prior nor config.)
+			for it := plannedV.ElementIterator(); it.Next(); {
+				idx, plannedEV := it.Element()
+				path := append(path, cty.IndexStep{Key: idx})
+				if !plannedEV.IsKnown() {
+					errs = append(errs, path.NewErrorf("element representing nested block must not be unknown itself; set nested attribute values to unknown instead"))
+					continue
+				}
+			}
+
+		default:
+			panic(fmt.Sprintf("unsupported nesting mode %s", blockS.Nesting))
+		}
+	}
+
+	return errs
+}
+
+func assertPlannedAttrsValid(schema map[string]*configschema.Attribute, priorState, config, plannedState cty.Value, path cty.Path) []error {
+	var errs []error
+	for name, attrS := range schema {
+		moreErrs := assertPlannedAttrValid(name, attrS, priorState, config, plannedState, path)
+		errs = append(errs, moreErrs...)
+	}
+	return errs
+}
+
+func assertPlannedAttrValid(name string, attrS *configschema.Attribute, priorState, config, plannedState cty.Value, path cty.Path) []error {
+	plannedV := plannedState.GetAttr(name)
+	configV := config.GetAttr(name)
+	priorV := cty.NullVal(attrS.Type)
+	if !priorState.IsNull() {
+		priorV = priorState.GetAttr(name)
+	}
+	path = append(path, cty.GetAttrStep{Name: name})
+
+	return assertPlannedValueValid(attrS, priorV, configV, plannedV, path)
+}
+
+func assertPlannedValueValid(attrS *configschema.Attribute, priorV, configV, plannedV cty.Value, path cty.Path) []error {
+
+	var errs []error
+	if plannedV.RawEquals(configV) {
+		// This is the easy path: provider didn't change anything at all.
+		return errs
+	}
+	if plannedV.RawEquals(priorV) && !priorV.IsNull() && !configV.IsNull() {
+		// Also pretty easy: there is a prior value and the provider has
+		// returned it unchanged. This indicates that configV and plannedV
+		// are functionally equivalent and so the provider wishes to disregard
+		// the configuration value in favor of the prior.
+		return errs
+	}
+
+	switch {
+	// The provider can plan any value for a computed-only attribute. There may
+	// be a config value here in the case where a user used `ignore_changes` on
+	// a computed attribute and ignored the warning, or we failed to validate
+	// computed attributes in the config, but regardless it's not a plan error
+	// caused by the provider.
+	case attrS.Computed && !attrS.Optional:
+		return errs
+
+	// The provider is allowed to insert optional values when the config is
+	// null, but only if the attribute is computed.
+	case configV.IsNull() && attrS.Computed:
+		return errs
+
+	case configV.IsNull() && !plannedV.IsNull():
+		// if the attribute is not computed, then any planned value is incorrect
+		if attrS.Sensitive {
+			errs = append(errs, path.NewErrorf("sensitive planned value for a non-computed attribute"))
+		} else {
+			errs = append(errs, path.NewErrorf("planned value %#v for a non-computed attribute", plannedV))
+		}
+		return errs
+	}
+
+	// If this attribute has a NestedType, validate the nested object
+	if attrS.NestedType != nil {
+		return assertPlannedObjectValid(attrS.NestedType, priorV, configV, plannedV, path)
+	}
+
+	// If none of the above conditions match, the provider has made an invalid
+	// change to this attribute.
+	if priorV.IsNull() {
+		if attrS.Sensitive {
+			errs = append(errs, path.NewErrorf("sensitive planned value does not match config value"))
+		} else {
+			errs = append(errs, path.NewErrorf("planned value %#v does not match config value %#v", plannedV, configV))
+		}
+		return errs
+	}
+
+	if attrS.Sensitive {
+		errs = append(errs, path.NewErrorf("sensitive planned value does not match config value nor prior value"))
+	} else {
+		errs = append(errs, path.NewErrorf("planned value %#v does not match config value %#v nor prior value %#v", plannedV, configV, priorV))
+	}
+
+	return errs
+}
+
+func assertPlannedObjectValid(schema *configschema.Object, prior, config, planned cty.Value, path cty.Path) []error {
+	var errs []error
+
+	if planned.IsNull() && !config.IsNull() {
+		errs = append(errs, path.NewErrorf("planned for absence but config wants existence"))
+		return errs
+	}
+	if config.IsNull() && !planned.IsNull() {
+		errs = append(errs, path.NewErrorf("planned for existence but config wants absence"))
+		return errs
+	}
+	if !config.IsNull() && !planned.IsKnown() {
+		errs = append(errs, path.NewErrorf("planned unknown for configured value"))
+		return errs
+	}
+
+	if planned.IsNull() {
+		// No further checks possible if the planned value is null
+		return errs
+	}
+
+	switch schema.Nesting {
+	case configschema.NestingSingle, configschema.NestingGroup:
+		moreErrs := assertPlannedAttrsValid(schema.Attributes, prior, config, planned, path)
+		errs = append(errs, moreErrs...)
+
+	case configschema.NestingList:
+		// A NestingList might either be a list or a tuple, depending on
+		// whether there are dynamically-typed attributes inside. However,
+		// both support a similar-enough API that we can treat them the
+		// same for our purposes here.
+
+		plannedL := planned.Length()
+		configL := config.Length()
+
+		// config wasn't known, then planned should be unknown too
+		if !plannedL.IsKnown() && !configL.IsKnown() {
+			return errs
+		}
+
+		lenEqual := plannedL.Equals(configL)
+		if !lenEqual.IsKnown() || lenEqual.False() {
+			errs = append(errs, path.NewErrorf("count in plan (%#v) disagrees with count in config (%#v)", plannedL, configL))
+			return errs
+		}
+		for it := planned.ElementIterator(); it.Next(); {
+			idx, plannedEV := it.Element()
+			path := append(path, cty.IndexStep{Key: idx})
+			if !config.HasIndex(idx).True() {
+				continue // should never happen since we checked the lengths above
+			}
+			configEV := config.Index(idx)
+			priorEV := cty.NullVal(schema.ImpliedType())
+			if !prior.IsNull() && prior.HasIndex(idx).True() {
+				priorEV = prior.Index(idx)
+			}
+
+			moreErrs := assertPlannedAttrsValid(schema.Attributes, priorEV, configEV, plannedEV, path)
+			errs = append(errs, moreErrs...)
+		}
+
+	case configschema.NestingMap:
+		// A NestingMap might either be a map or an object, depending on
+		// whether there are dynamically-typed attributes inside, so we will
+		// break these down to maps to handle them both in the same manner.
+		plannedVals := map[string]cty.Value{}
+		configVals := map[string]cty.Value{}
+		priorVals := map[string]cty.Value{}
+
+		plannedL := planned.Length()
+		configL := config.Length()
+
+		// config wasn't known, then planned should be unknown too
+		if !plannedL.IsKnown() && !configL.IsKnown() {
+			return errs
+		}
+
+		lenEqual := plannedL.Equals(configL)
+		if !lenEqual.IsKnown() || lenEqual.False() {
+			errs = append(errs, path.NewErrorf("count in plan (%#v) disagrees with count in config (%#v)", plannedL, configL))
+			return errs
+		}
+
+		if !planned.IsNull() {
+			plannedVals = planned.AsValueMap()
+		}
+		if !config.IsNull() {
+			configVals = config.AsValueMap()
+		}
+		if !prior.IsNull() {
+			priorVals = prior.AsValueMap()
+		}
+
+		for k, plannedEV := range plannedVals {
+			configEV, ok := configVals[k]
+			if !ok {
+				errs = append(errs, path.NewErrorf("map key %q from plan is not present in config", k))
+				continue
+			}
+			path := append(path, cty.GetAttrStep{Name: k})
+
+			priorEV, ok := priorVals[k]
+			if !ok {
+				priorEV = cty.NullVal(schema.ImpliedType())
+			}
+			moreErrs := assertPlannedAttrsValid(schema.Attributes, priorEV, configEV, plannedEV, path)
+			errs = append(errs, moreErrs...)
+		}
+		for k := range configVals {
+			if _, ok := plannedVals[k]; !ok {
+				errs = append(errs, path.NewErrorf("map key %q from config is not present in plan", k))
+				continue
+			}
+		}
+
+	case configschema.NestingSet:
+		if !planned.IsKnown() || !config.IsKnown() {
+			// if either is unknown we cannot check the lengths
+			return errs
+		}
+
+		plannedL := planned.LengthInt()
+		configL := config.LengthInt()
+		if plannedL != configL {
+			errs = append(errs, path.NewErrorf("count in plan (%#v) disagrees with count in config (%#v)", plannedL, configL))
+			return errs
+		}
+		// Because set elements have no identifier with which to correlate
+		// them, we can't robustly validate the plan for a nested object
+		// backed by a set, and so unfortunately we need to just trust the
+		// provider to do the right thing.
+	}
+
+	return errs
+}
diff --git a/v1.5.7/internal/plans/objchange/plan_valid_test.go b/v1.5.7/internal/plans/objchange/plan_valid_test.go
new file mode 100644
index 0000000..1ef8060
--- /dev/null
+++ b/v1.5.7/internal/plans/objchange/plan_valid_test.go
@@ -0,0 +1,1899 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package objchange
+
+import (
+	"testing"
+
+	"github.com/apparentlymart/go-dump/dump"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestAssertPlanValid(t *testing.T) {
+	tests := map[string]struct {
+		Schema   *configschema.Block
+		Prior    cty.Value
+		Config   cty.Value
+		Planned  cty.Value
+		WantErrs []string
+	}{
+		"all empty": {
+			&configschema.Block{},
+			cty.EmptyObjectVal,
+			cty.EmptyObjectVal,
+			cty.EmptyObjectVal,
+			nil,
+		},
+		"no computed, all match": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"a": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"b": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"c": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			nil,
+		},
+		"no computed, plan matches, no prior": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"a": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"b": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"c": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"a": cty.String,
+				"b": cty.List(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				})),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			nil,
+		},
+		"no computed, invalid change in plan": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"a": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"b": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"c": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"a": cty.String,
+				"b": cty.List(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				})),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("new c value"),
+					}),
+				}),
+			}),
+			[]string{
+				`.b[0].c: planned value cty.StringVal("new c value") does not match config value cty.StringVal("c value")`,
+			},
+		},
+		"no computed, invalid change in plan sensitive": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"a": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"b": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"c": {
+									Type:      cty.String,
+									Optional:  true,
+									Sensitive: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"a": cty.String,
+				"b": cty.List(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				})),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("new c value"),
+					}),
+				}),
+			}),
+			[]string{
+				`.b[0].c: sensitive planned value does not match config value`,
+			},
+		},
+		"no computed, diff suppression in plan": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"a": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"b": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"c": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("new c value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"), // plan uses value from prior object
+					}),
+				}),
+			}),
+			nil,
+		},
+		"no computed, all null": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"a": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"b": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"c": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.String),
+				"b": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.String),
+				"b": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.String),
+				"b": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			nil,
+		},
+		"nested map, normal update": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"b": {
+						Nesting: configschema.NestingMap,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"c": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.MapVal(map[string]cty.Value{
+					"boop": cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("hello"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.MapVal(map[string]cty.Value{
+					"boop": cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("howdy"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.MapVal(map[string]cty.Value{
+					"boop": cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("howdy"),
+					}),
+				}),
+			}),
+			nil,
+		},
+
+		// Nested block collections are never null
+		"nested list, null in plan": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"b": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"c": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"b": cty.List(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				})),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				})),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				}))),
+			}),
+			[]string{
+				`.b: attribute representing a list of nested blocks must be empty to indicate no blocks, not null`,
+			},
+		},
+
+		// but don't panic on a null list just in case
+		"nested list, null in config": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"b": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"c": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				})),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				}))),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				})),
+			}),
+			nil,
+		},
+
+		// blocks can be unknown when using dynamic
+		"nested list, unknown nested dynamic": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"a": {
+						Nesting: configschema.NestingList,
+						Block: configschema.Block{
+							BlockTypes: map[string]*configschema.NestedBlock{
+								"b": {
+									Nesting: configschema.NestingList,
+									Block: configschema.Block{
+										Attributes: map[string]*configschema.Attribute{
+											"c": {
+												Type:     cty.String,
+												Optional: true,
+											},
+											"computed": {
+												Type:     cty.String,
+												Computed: true,
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+					"computed": cty.NullVal(cty.String),
+					"b": cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("x"),
+					})}),
+				})}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+					"b": cty.UnknownVal(cty.List(cty.Object(map[string]cty.Type{
+						"c":        cty.String,
+						"computed": cty.String,
+					}))),
+				})}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+					"b": cty.UnknownVal(cty.List(cty.Object(map[string]cty.Type{
+						"c":        cty.String,
+						"computed": cty.String,
+					}))),
+				})}),
+			}),
+			[]string{},
+		},
+
+		"nested set, unknown dynamic cannot be planned": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"computed": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"b": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"c": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+
+			cty.ObjectVal(map[string]cty.Value{
+				"computed": cty.NullVal(cty.String),
+				"b": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+					"c": cty.StringVal("x"),
+				})}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"computed": cty.NullVal(cty.String),
+				"b": cty.UnknownVal(cty.Set(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				}))),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"computed": cty.StringVal("default"),
+				"b": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+					"c": cty.StringVal("oops"),
+				})}),
+			}),
+
+			[]string{
+				`.b: planned value cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"c":cty.StringVal("oops")})}) for unknown dynamic block`,
+			},
+		},
+
+		"nested set, null in plan": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"b": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"c": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"b": cty.Set(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				})),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.SetValEmpty(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				})),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				}))),
+			}),
+			[]string{
+				`.b: attribute representing a set of nested blocks must be empty to indicate no blocks, not null`,
+			},
+		},
+		"nested map, null in plan": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"b": {
+						Nesting: configschema.NestingMap,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"c": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"b": cty.Map(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				})),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.MapValEmpty(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				})),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{
+					"c": cty.String,
+				}))),
+			}),
+			[]string{
+				`.b: attribute representing a map of nested blocks must be empty to indicate no blocks, not null`,
+			},
+		},
+
+		// We don't actually do any validation for nested set blocks, and so
+		// the remaining cases here are just intending to ensure we don't
+		// inadvertently start generating errors incorrectly in future.
+		"nested set, no computed, no changes": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"b": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"c": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			nil,
+		},
+		"nested set, no computed, invalid change in plan": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"b": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"c": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("new c value"), // matches neither prior nor config
+					}),
+				}),
+			}),
+			nil,
+		},
+		"nested set, no computed, diff suppressed": {
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"b": {
+						Nesting: configschema.NestingSet,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"c": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("new c value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"b": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"c": cty.StringVal("c value"), // plan uses value from prior object
+					}),
+				}),
+			}),
+			nil,
+		},
+
+		// Attributes with NestedTypes
+		"NestedType attr, no computed, all match": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"a": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"b": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("b value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("b value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("b value"),
+					}),
+				}),
+			}),
+			nil,
+		},
+		"NestedType attr, no computed, plan matches, no prior": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"a": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"b": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"a": cty.List(cty.Object(map[string]cty.Type{
+					"b": cty.String,
+				})),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			nil,
+		},
+		"NestedType, no computed, invalid change in plan": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"a": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"b": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"a": cty.List(cty.Object(map[string]cty.Type{
+					"b": cty.String,
+				})),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("c value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("new c value"),
+					}),
+				}),
+			}),
+			[]string{
+				`.a[0].b: planned value cty.StringVal("new c value") does not match config value cty.StringVal("c value")`,
+			},
+		},
+		"NestedType attr, no computed, invalid change in plan sensitive": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"a": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"b": {
+									Type:      cty.String,
+									Optional:  true,
+									Sensitive: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"a": cty.List(cty.Object(map[string]cty.Type{
+					"b": cty.String,
+				})),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("b value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("new b value"),
+					}),
+				}),
+			}),
+			[]string{
+				`.a[0].b: sensitive planned value does not match config value`,
+			},
+		},
+		"NestedType attr, no computed, diff suppression in plan": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"a": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"b": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("b value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("new b value"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"b": cty.StringVal("b value"), // plan uses value from prior object
+					}),
+				}),
+			}),
+			nil,
+		},
+		"NestedType attr, no computed, all null": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"a": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"b": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.DynamicPseudoType),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.DynamicPseudoType),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.DynamicPseudoType),
+			}),
+			nil,
+		},
+		"NestedType attr, no computed, all zero value": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"a": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"b": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"b": cty.String,
+				}))),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"b": cty.String,
+				}))),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"b": cty.String,
+				}))),
+			}),
+			nil,
+		},
+		"NestedType NestingSet attribute to null": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Required: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("ok"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{
+					"blop": cty.String,
+				}))),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{
+					"blop": cty.String,
+				}))),
+			}),
+			nil,
+		},
+		"NestedType deep nested optional set attribute to null": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"bleep": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"bloop": {
+									NestedType: &configschema.Object{
+										Nesting: configschema.NestingSet,
+										Attributes: map[string]*configschema.Attribute{
+											"blome": {
+												Type:     cty.String,
+												Optional: true,
+											},
+										},
+									},
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"bleep": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bloop": cty.SetVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"blome": cty.StringVal("ok"),
+							}),
+						}),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"bleep": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bloop": cty.NullVal(cty.Set(
+							cty.Object(map[string]cty.Type{
+								"blome": cty.String,
+							}),
+						)),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"bleep": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bloop": cty.NullVal(cty.List(
+							cty.Object(map[string]cty.Type{
+								"blome": cty.String,
+							}),
+						)),
+					}),
+				}),
+			}),
+			nil,
+		},
+		"NestedType deep nested set": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"bleep": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"bloop": {
+									NestedType: &configschema.Object{
+										Nesting: configschema.NestingSet,
+										Attributes: map[string]*configschema.Attribute{
+											"blome": {
+												Type:     cty.String,
+												Optional: true,
+											},
+										},
+									},
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"bleep": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bloop": cty.SetVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"blome": cty.StringVal("ok"),
+							}),
+						}),
+					}),
+				}),
+			}),
+			// Note: bloop is null in the config
+			cty.ObjectVal(map[string]cty.Value{
+				"bleep": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bloop": cty.NullVal(cty.Set(
+							cty.Object(map[string]cty.Type{
+								"blome": cty.String,
+							}),
+						)),
+					}),
+				}),
+			}),
+			// provider sends back the prior value, not matching the config
+			cty.ObjectVal(map[string]cty.Value{
+				"bleep": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"bloop": cty.SetVal([]cty.Value{
+							cty.ObjectVal(map[string]cty.Value{
+								"blome": cty.StringVal("ok"),
+							}),
+						}),
+					}),
+				}),
+			}),
+			nil, // we cannot validate individual set elements, and trust the provider's response
+		},
+		"NestedType nested computed list attribute": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Computed: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("ok"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"blop": cty.String,
+				}))),
+			}),
+
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("ok"),
+					}),
+				}),
+			}),
+			nil,
+		},
+		"NestedType nested list attribute to null": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("ok"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"blop": cty.String,
+				}))),
+			}),
+
+			// provider returned the old value
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("ok"),
+					}),
+				}),
+			}),
+			[]string{`.bloop: planned value cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"blop":cty.StringVal("ok")})}) for a non-computed attribute`},
+		},
+		"NestedType nested set attribute to null": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"bloop": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"blop": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+						Optional: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("ok"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{
+					"blop": cty.String,
+				}))),
+			}),
+			// provider returned the old value
+			cty.ObjectVal(map[string]cty.Value{
+				"bloop": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"blop": cty.StringVal("ok"),
+					}),
+				}),
+			}),
+			[]string{`.bloop: planned value cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"blop":cty.StringVal("ok")})}) for a non-computed attribute`},
+		},
+		"computed within nested objects": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"map": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type:     cty.String,
+									Computed: true,
+								},
+							},
+						},
+					},
+					// When an object has dynamic attrs, the map may be
+					// handled as an object.
+					"map_as_obj": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type:     cty.String,
+									Computed: true,
+								},
+							},
+						},
+					},
+					"list": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type:     cty.String,
+									Computed: true,
+								},
+							},
+						},
+					},
+					"set": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type:     cty.String,
+									Computed: true,
+								},
+							},
+						},
+					},
+					"single": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSingle,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type:     cty.DynamicPseudoType,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"map": cty.Map(cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				})),
+				"map_as_obj": cty.Map(cty.Object(map[string]cty.Type{
+					"name": cty.DynamicPseudoType,
+				})),
+				"list": cty.List(cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				})),
+				"set": cty.Set(cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				})),
+				"single": cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				}),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"map": cty.MapVal(map[string]cty.Value{
+					"one": cty.ObjectVal(map[string]cty.Value{
+						"name": cty.NullVal(cty.String),
+					}),
+				}),
+				"map_as_obj": cty.MapVal(map[string]cty.Value{
+					"one": cty.ObjectVal(map[string]cty.Value{
+						"name": cty.NullVal(cty.DynamicPseudoType),
+					}),
+				}),
+				"list": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"name": cty.NullVal(cty.String),
+					}),
+				}),
+				"set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"name": cty.NullVal(cty.String),
+					}),
+				}),
+				"single": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.NullVal(cty.String),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"map": cty.MapVal(map[string]cty.Value{
+					"one": cty.ObjectVal(map[string]cty.Value{
+						"name": cty.NullVal(cty.String),
+					}),
+				}),
+				"map_as_obj": cty.ObjectVal(map[string]cty.Value{
+					"one": cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("computed"),
+					}),
+				}),
+				"list": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"name": cty.NullVal(cty.String),
+					}),
+				}),
+				"set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"name": cty.NullVal(cty.String),
+					}),
+				}),
+				"single": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.NullVal(cty.String),
+				}),
+			}),
+			nil,
+		},
+		"computed nested objects": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"map": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type: cty.String,
+								},
+							},
+						},
+						Computed: true,
+					},
+					"list": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type: cty.String,
+								},
+							},
+						},
+						Computed: true,
+					},
+					"set": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type: cty.String,
+								},
+							},
+						},
+						Optional: true,
+						Computed: true,
+					},
+					"single": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSingle,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type: cty.DynamicPseudoType,
+								},
+							},
+						},
+						Computed: true,
+					},
+				},
+			},
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"map": cty.Map(cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				})),
+				"list": cty.List(cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				})),
+				"set": cty.Set(cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				})),
+				"single": cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				}),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"map": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				}))),
+				"list": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				}))),
+				"set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("from_config"),
+					}),
+				}),
+				"single": cty.NullVal(cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				})),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"map": cty.MapVal(map[string]cty.Value{
+					"one": cty.UnknownVal(cty.Object(map[string]cty.Type{
+						"name": cty.String,
+					})),
+				}),
+				"list": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("computed"),
+					}),
+				}),
+				"set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("from_config"),
+					}),
+				}),
+				"single": cty.UnknownVal(cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				})),
+			}),
+			nil,
+		},
+		"optional computed within nested objects": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"map": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type:     cty.String,
+									Computed: true,
+								},
+							},
+						},
+					},
+					// When an object has dynamic attrs, the map may be
+					// handled as an object.
+					"map_as_obj": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+					"list": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+					"set": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type:     cty.String,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+					"single": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSingle,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type:     cty.DynamicPseudoType,
+									Optional: true,
+									Computed: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"map": cty.Map(cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				})),
+				"map_as_obj": cty.Map(cty.Object(map[string]cty.Type{
+					"name": cty.DynamicPseudoType,
+				})),
+				"list": cty.List(cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				})),
+				"set": cty.Set(cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				})),
+				"single": cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				}),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"map": cty.MapVal(map[string]cty.Value{
+					"one": cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("from_config"),
+					}),
+				}),
+				"map_as_obj": cty.MapVal(map[string]cty.Value{
+					"one": cty.ObjectVal(map[string]cty.Value{
+						"name": cty.NullVal(cty.DynamicPseudoType),
+					}),
+				}),
+				"list": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"name": cty.NullVal(cty.String),
+					}),
+				}),
+				"set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"name": cty.NullVal(cty.String),
+					}),
+				}),
+				"single": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("from_config"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"map": cty.MapVal(map[string]cty.Value{
+					"one": cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("from_config"),
+					}),
+				}),
+				"map_as_obj": cty.ObjectVal(map[string]cty.Value{
+					"one": cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("computed"),
+					}),
+				}),
+				"list": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("computed"),
+					}),
+				}),
+				"set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"name": cty.NullVal(cty.String),
+					}),
+				}),
+				"single": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("from_config"),
+				}),
+			}),
+			nil,
+		},
+		"cannot replace config nested attr": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"map": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type:     cty.String,
+									Computed: true,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"map": cty.Map(cty.Object(map[string]cty.Type{
+					"name": cty.String,
+				})),
+			})),
+			cty.ObjectVal(map[string]cty.Value{
+				"map": cty.MapVal(map[string]cty.Value{
+					"one": cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("from_config"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"map": cty.MapVal(map[string]cty.Value{
+					"one": cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("from_provider"),
+					}),
+				}),
+			}),
+			[]string{`.map.one.name: planned value cty.StringVal("from_provider") does not match config value cty.StringVal("from_config")`},
+		},
+
+		// If a config value ended up in a computed-only attribute it can still
+		// be a valid plan. We either got here because the user ignore warnings
+		// about ignore_changes on computed attributes, or we failed to
+		// validate a config with computed values. Either way, we don't want to
+		// indicate an error with the provider.
+		"computed only value with config": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"a": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("old"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("old"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.UnknownVal(cty.String),
+			}),
+			nil,
+		},
+
+		// When validating collections we start by comparing length, which
+		// requires guarding for any unknown values incorrectly returned by the
+		// provider.
+		"nested collection attrs planned unknown": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"set": {
+						Computed: true,
+						Optional: true,
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type:     cty.String,
+									Computed: true,
+									Optional: true,
+								},
+							},
+						},
+					},
+					"list": {
+						Computed: true,
+						Optional: true,
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type:     cty.String,
+									Computed: true,
+									Optional: true,
+								},
+							},
+						},
+					},
+					"map": {
+						Computed: true,
+						Optional: true,
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"name": {
+									Type:     cty.String,
+									Computed: true,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("from_config"),
+					}),
+				}),
+				"list": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("from_config"),
+					}),
+				}),
+				"map": cty.MapVal(map[string]cty.Value{
+					"key": cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("from_config"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("from_config"),
+					}),
+				}),
+				"list": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("from_config"),
+					}),
+				}),
+				"map": cty.MapVal(map[string]cty.Value{
+					"key": cty.ObjectVal(map[string]cty.Value{
+						"name": cty.StringVal("from_config"),
+					}),
+				}),
+			}),
+			// provider cannot override the config
+			cty.ObjectVal(map[string]cty.Value{
+				"set": cty.UnknownVal(cty.Set(
+					cty.Object(map[string]cty.Type{
+						"name": cty.String,
+					}),
+				)),
+				"list": cty.UnknownVal(cty.Set(
+					cty.Object(map[string]cty.Type{
+						"name": cty.String,
+					}),
+				)),
+				"map": cty.UnknownVal(cty.Map(
+					cty.Object(map[string]cty.Type{
+						"name": cty.String,
+					}),
+				)),
+			}),
+			[]string{
+				`.set: planned unknown for configured value`,
+				`.list: planned unknown for configured value`,
+				`.map: planned unknown for configured value`,
+			},
+		},
+
+		"nested set values can contain computed unknown": {
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"set": {
+						Optional: true,
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"input": {
+									Type:     cty.String,
+									Optional: true,
+								},
+								"computed": {
+									Type:     cty.String,
+									Computed: true,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			cty.ObjectVal(map[string]cty.Value{
+				"set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"input":    cty.StringVal("a"),
+						"computed": cty.NullVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"input":    cty.StringVal("b"),
+						"computed": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"input":    cty.StringVal("a"),
+						"computed": cty.NullVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"input":    cty.StringVal("b"),
+						"computed": cty.NullVal(cty.String),
+					}),
+				}),
+			}),
+			// Plan can mark the null computed values as unknown
+			cty.ObjectVal(map[string]cty.Value{
+				"set": cty.SetVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"input":    cty.StringVal("a"),
+						"computed": cty.UnknownVal(cty.String),
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"input":    cty.StringVal("b"),
+						"computed": cty.UnknownVal(cty.String),
+					}),
+				}),
+			}),
+			[]string{},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			errs := AssertPlanValid(test.Schema, test.Prior, test.Config, test.Planned)
+
+			wantErrs := make(map[string]struct{})
+			gotErrs := make(map[string]struct{})
+			for _, err := range errs {
+				gotErrs[tfdiags.FormatError(err)] = struct{}{}
+			}
+			for _, msg := range test.WantErrs {
+				wantErrs[msg] = struct{}{}
+			}
+
+			t.Logf(
+				"\nprior:  %sconfig:  %splanned: %s",
+				dump.Value(test.Prior),
+				dump.Value(test.Config),
+				dump.Value(test.Planned),
+			)
+			for msg := range wantErrs {
+				if _, ok := gotErrs[msg]; !ok {
+					t.Errorf("missing expected error: %s", msg)
+				}
+			}
+			for msg := range gotErrs {
+				if _, ok := wantErrs[msg]; !ok {
+					t.Errorf("unexpected extra error: %s", msg)
+				}
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/plans/plan.go b/v1.5.7/internal/plans/plan.go
new file mode 100644
index 0000000..a95653e
--- /dev/null
+++ b/v1.5.7/internal/plans/plan.go
@@ -0,0 +1,204 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plans
+
+import (
+	"sort"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/lang/globalref"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Plan is the top-level type representing a planned set of changes.
+//
+// A plan is a summary of the set of changes required to move from a current
+// state to a goal state derived from configuration. The described changes
+// are not applied directly, but contain an approximation of the final
+// result that will be completed during apply by resolving any values that
+// cannot be predicted.
+//
+// A plan must always be accompanied by the configuration it was built from,
+// since the plan does not itself include all of the information required to
+// make the changes indicated.
+type Plan struct {
+	// Mode is the mode under which this plan was created.
+	//
+	// This is only recorded to allow for UI differences when presenting plans
+	// to the end-user, and so it must not be used to influence apply-time
+	// behavior. The actions during apply must be described entirely by
+	// the Changes field, regardless of how the plan was created.
+	//
+	// FIXME: destroy operations still rely on DestroyMode being set, because
+	// there is no other source of this information in the plan. New behavior
+	// should not be added based on this flag, and changing the flag should be
+	// checked carefully against existing destroy behaviors.
+	UIMode Mode
+
+	VariableValues    map[string]DynamicValue
+	Changes           *Changes
+	DriftedResources  []*ResourceInstanceChangeSrc
+	TargetAddrs       []addrs.Targetable
+	ForceReplaceAddrs []addrs.AbsResourceInstance
+	Backend           Backend
+
+	// Errored is true if the Changes information is incomplete because
+	// the planning operation failed. An errored plan cannot be applied,
+	// but can be cautiously inspected for debugging purposes.
+	Errored bool
+
+	// Checks captures a snapshot of the (probably-incomplete) check results
+	// at the end of the planning process.
+	//
+	// If this plan is applyable (that is, if the planning process completed
+	// without errors) then the set of checks here should be complete even
+	// though some of them will likely have StatusUnknown where the check
+	// condition depends on values we won't know until the apply step.
+	Checks *states.CheckResults
+
+	// RelevantAttributes is a set of resource instance addresses and
+	// attributes that are either directly affected by proposed changes or may
+	// have indirectly contributed to them via references in expressions.
+	//
+	// This is the result of a heuristic and is intended only as a hint to
+	// the UI layer in case it wants to emphasize or de-emphasize certain
+	// resources. Don't use this to drive any non-cosmetic behavior, especially
+	// including anything that would be subject to compatibility constraints.
+	RelevantAttributes []globalref.ResourceAttr
+
+	// PrevRunState and PriorState both describe the situation that the plan
+	// was derived from:
+	//
+	// PrevRunState is a representation of the outcome of the previous
+	// Terraform operation, without any updates from the remote system but
+	// potentially including some changes that resulted from state upgrade
+	// actions.
+	//
+	// PriorState is a representation of the current state of remote objects,
+	// which will differ from PrevRunState if the "refresh" step returned
+	// different data, which might reflect drift.
+	//
+	// PriorState is the main snapshot we use for actions during apply.
+	// PrevRunState is only here so that we can diff PriorState against it in
+	// order to report to the user any out-of-band changes we've detected.
+	PrevRunState *states.State
+	PriorState   *states.State
+
+	// Timestamp is the record of truth for when the plan happened.
+	Timestamp time.Time
+}
+
+// CanApply returns true if and only if the recieving plan includes content
+// that would make sense to apply. If it returns false, the plan operation
+// should indicate that there's nothing to do and Terraform should exit
+// without prompting the user to confirm the changes.
+//
+// This function represents our main business logic for making the decision
+// about whether a given plan represents meaningful "changes", and so its
+// exact definition may change over time; the intent is just to centralize the
+// rules for that rather than duplicating different versions of it at various
+// locations in the UI code.
+func (p *Plan) CanApply() bool {
+	switch {
+	case p.Errored:
+		// An errored plan can never be applied, because it is incomplete.
+		// Such a plan is only useful for describing the subset of actions
+		// planned so far in case they are useful for understanding the
+		// causes of the errors.
+		return false
+
+	case !p.Changes.Empty():
+		// "Empty" means that everything in the changes is a "NoOp", so if
+		// not empty then there's at least one non-NoOp change.
+		return true
+
+	case !p.PriorState.ManagedResourcesEqual(p.PrevRunState):
+		// If there are no changes planned but we detected some
+		// outside-Terraform changes while refreshing then we consider
+		// that applyable in isolation only if this was a refresh-only
+		// plan where we expect updating the state to include these
+		// changes was the intended goal.
+		//
+		// (We don't treat a "refresh only" plan as applyable in normal
+		// planning mode because historically the refresh result wasn't
+		// considered part of a plan at all, and so it would be
+		// a disruptive breaking change if refreshing alone suddenly
+		// became applyable in the normal case and an existing configuration
+		// was relying on ignore_changes in order to be convergent in spite
+		// of intentional out-of-band operations.)
+		return p.UIMode == RefreshOnlyMode
+
+	default:
+		// Otherwise, there are either no changes to apply or they are changes
+		// our cases above don't consider as worthy of applying in isolation.
+		return false
+	}
+}
+
+// ProviderAddrs returns a list of all of the provider configuration addresses
+// referenced throughout the receiving plan.
+//
+// The result is de-duplicated so that each distinct address appears only once.
+func (p *Plan) ProviderAddrs() []addrs.AbsProviderConfig {
+	if p == nil || p.Changes == nil {
+		return nil
+	}
+
+	m := map[string]addrs.AbsProviderConfig{}
+	for _, rc := range p.Changes.Resources {
+		m[rc.ProviderAddr.String()] = rc.ProviderAddr
+	}
+	if len(m) == 0 {
+		return nil
+	}
+
+	// This is mainly just so we'll get stable results for testing purposes.
+	keys := make([]string, 0, len(m))
+	for k := range m {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+
+	ret := make([]addrs.AbsProviderConfig, len(keys))
+	for i, key := range keys {
+		ret[i] = m[key]
+	}
+
+	return ret
+}
+
+// Backend represents the backend-related configuration and other data as it
+// existed when a plan was created.
+type Backend struct {
+	// Type is the type of backend that the plan will apply against.
+	Type string
+
+	// Config is the configuration of the backend, whose schema is decided by
+	// the backend Type.
+	Config DynamicValue
+
+	// Workspace is the name of the workspace that was active when the plan
+	// was created. It is illegal to apply a plan created for one workspace
+	// to the state of another workspace.
+	// (This constraint is already enforced by the statefile lineage mechanism,
+	// but storing this explicitly allows us to return a better error message
+	// in the situation where the user has the wrong workspace selected.)
+	Workspace string
+}
+
+func NewBackend(typeName string, config cty.Value, configSchema *configschema.Block, workspaceName string) (*Backend, error) {
+	dv, err := NewDynamicValue(config, configSchema.ImpliedType())
+	if err != nil {
+		return nil, err
+	}
+
+	return &Backend{
+		Type:      typeName,
+		Config:    dv,
+		Workspace: workspaceName,
+	}, nil
+}
diff --git a/v1.5.7/internal/plans/plan_test.go b/v1.5.7/internal/plans/plan_test.go
new file mode 100644
index 0000000..cbfbfad
--- /dev/null
+++ b/v1.5.7/internal/plans/plan_test.go
@@ -0,0 +1,98 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plans
+
+import (
+	"testing"
+
+	"github.com/go-test/deep"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestProviderAddrs(t *testing.T) {
+
+	plan := &Plan{
+		VariableValues: map[string]DynamicValue{},
+		Changes: &Changes{
+			Resources: []*ResourceInstanceChangeSrc{
+				{
+					Addr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_thing",
+						Name: "woot",
+					}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+					ProviderAddr: addrs.AbsProviderConfig{
+						Module:   addrs.RootModule,
+						Provider: addrs.NewDefaultProvider("test"),
+					},
+				},
+				{
+					Addr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_thing",
+						Name: "woot",
+					}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+					DeposedKey: "foodface",
+					ProviderAddr: addrs.AbsProviderConfig{
+						Module:   addrs.RootModule,
+						Provider: addrs.NewDefaultProvider("test"),
+					},
+				},
+				{
+					Addr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_thing",
+						Name: "what",
+					}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+					ProviderAddr: addrs.AbsProviderConfig{
+						Module:   addrs.RootModule.Child("foo"),
+						Provider: addrs.NewDefaultProvider("test"),
+					},
+				},
+			},
+		},
+	}
+
+	got := plan.ProviderAddrs()
+	want := []addrs.AbsProviderConfig{
+		addrs.AbsProviderConfig{
+			Module:   addrs.RootModule.Child("foo"),
+			Provider: addrs.NewDefaultProvider("test"),
+		},
+		addrs.AbsProviderConfig{
+			Module:   addrs.RootModule,
+			Provider: addrs.NewDefaultProvider("test"),
+		},
+	}
+
+	for _, problem := range deep.Equal(got, want) {
+		t.Error(problem)
+	}
+}
+
+// Module outputs should not effect the result of Empty
+func TestModuleOutputChangesEmpty(t *testing.T) {
+	changes := &Changes{
+		Outputs: []*OutputChangeSrc{
+			{
+				Addr: addrs.AbsOutputValue{
+					Module: addrs.RootModuleInstance.Child("child", addrs.NoKey),
+					OutputValue: addrs.OutputValue{
+						Name: "output",
+					},
+				},
+				ChangeSrc: ChangeSrc{
+					Action: Update,
+					Before: []byte("a"),
+					After:  []byte("b"),
+				},
+			},
+		},
+	}
+
+	if !changes.Empty() {
+		t.Fatal("plan has no visible changes")
+	}
+}
diff --git a/v1.5.7/internal/plans/planfile/config_snapshot.go b/v1.5.7/internal/plans/planfile/config_snapshot.go
new file mode 100644
index 0000000..0f28ec0
--- /dev/null
+++ b/v1.5.7/internal/plans/planfile/config_snapshot.go
@@ -0,0 +1,221 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package planfile
+
+import (
+	"archive/zip"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"path"
+	"sort"
+	"strings"
+	"time"
+
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+)
+
+const configSnapshotPrefix = "tfconfig/"
+const configSnapshotManifestFile = configSnapshotPrefix + "modules.json"
+const configSnapshotModulePrefix = configSnapshotPrefix + "m-"
+
+type configSnapshotModuleRecord struct {
+	Key        string `json:"Key"`
+	SourceAddr string `json:"Source,omitempty"`
+	VersionStr string `json:"Version,omitempty"`
+	Dir        string `json:"Dir"`
+}
+type configSnapshotModuleManifest []configSnapshotModuleRecord
+
+func readConfigSnapshot(z *zip.Reader) (*configload.Snapshot, error) {
+	// Errors from this function are expected to be reported with some
+	// additional prefix context about them being in a config snapshot,
+	// so they should not themselves refer to the config snapshot.
+	// They are also generally indicative of an invalid file, and so since
+	// plan files should not be hand-constructed we don't need to worry
+	// about making the messages user-actionable.
+
+	snap := &configload.Snapshot{
+		Modules: map[string]*configload.SnapshotModule{},
+	}
+	var manifestSrc []byte
+
+	// For processing our source files, we'll just sweep over all the files
+	// and react to the one-by-one to start, and then clean up afterwards
+	// when we'll presumably have found the manifest file.
+	for _, file := range z.File {
+		switch {
+
+		case file.Name == configSnapshotManifestFile:
+			// It's the manifest file, so we'll just read it raw into
+			// manifestSrc for now and process it below.
+			r, err := file.Open()
+			if err != nil {
+				return nil, fmt.Errorf("failed to open module manifest: %s", r)
+			}
+			manifestSrc, err = ioutil.ReadAll(r)
+			if err != nil {
+				return nil, fmt.Errorf("failed to read module manifest: %s", r)
+			}
+
+		case strings.HasPrefix(file.Name, configSnapshotModulePrefix):
+			relName := file.Name[len(configSnapshotModulePrefix):]
+			moduleKey, fileName := path.Split(relName)
+
+			// moduleKey should currently have a trailing slash on it, which we
+			// can use to recognize the difference between the root module
+			// (just a trailing slash) and no module path at all (empty string).
+			if moduleKey == "" {
+				// ignore invalid config entry
+				continue
+			}
+			moduleKey = moduleKey[:len(moduleKey)-1] // trim trailing slash
+
+			r, err := file.Open()
+			if err != nil {
+				return nil, fmt.Errorf("failed to open snapshot of %s from module %q: %s", fileName, moduleKey, err)
+			}
+			fileSrc, err := ioutil.ReadAll(r)
+			if err != nil {
+				return nil, fmt.Errorf("failed to read snapshot of %s from module %q: %s", fileName, moduleKey, err)
+			}
+
+			if _, exists := snap.Modules[moduleKey]; !exists {
+				snap.Modules[moduleKey] = &configload.SnapshotModule{
+					Files: map[string][]byte{},
+					// Will fill in everything else afterwards, when we
+					// process the manifest.
+				}
+			}
+			snap.Modules[moduleKey].Files[fileName] = fileSrc
+		}
+	}
+
+	if manifestSrc == nil {
+		return nil, fmt.Errorf("config snapshot does not have manifest file")
+	}
+
+	var manifest configSnapshotModuleManifest
+	err := json.Unmarshal(manifestSrc, &manifest)
+	if err != nil {
+		return nil, fmt.Errorf("invalid module manifest: %s", err)
+	}
+
+	for _, record := range manifest {
+		modSnap, exists := snap.Modules[record.Key]
+		if !exists {
+			// We'll allow this, assuming that it's a module with no files.
+			// This is still weird, since we generally reject modules with
+			// no files, but we'll allow it because downstream errors will
+			// catch it in that case.
+			modSnap = &configload.SnapshotModule{
+				Files: map[string][]byte{},
+			}
+			snap.Modules[record.Key] = modSnap
+		}
+		modSnap.SourceAddr = record.SourceAddr
+		modSnap.Dir = record.Dir
+		if record.VersionStr != "" {
+			v, err := version.NewVersion(record.VersionStr)
+			if err != nil {
+				return nil, fmt.Errorf("manifest has invalid version string %q for module %q", record.VersionStr, record.Key)
+			}
+			modSnap.Version = v
+		}
+	}
+
+	// Finally, we'll make sure we don't have any errant files for modules that
+	// aren't in the manifest.
+	for k := range snap.Modules {
+		found := false
+		for _, record := range manifest {
+			if record.Key == k {
+				found = true
+				break
+			}
+		}
+		if !found {
+			return nil, fmt.Errorf("found files for module %q that isn't recorded in the manifest", k)
+		}
+	}
+
+	return snap, nil
+}
+
+// writeConfigSnapshot adds to the given zip.Writer one or more files
+// representing the given snapshot.
+//
+// This file creates new files in the writer, so any already-open writer
+// for the file will be invalidated by this call. The writer remains open
+// when this function returns.
+func writeConfigSnapshot(snap *configload.Snapshot, z *zip.Writer) error {
+	// Errors from this function are expected to be reported with some
+	// additional prefix context about them being in a config snapshot,
+	// so they should not themselves refer to the config snapshot.
+	// They are also indicative of a bug in the caller, so they do not
+	// need to be user-actionable.
+
+	var manifest configSnapshotModuleManifest
+	keys := make([]string, 0, len(snap.Modules))
+	for k := range snap.Modules {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+
+	// We'll re-use this fileheader for each Create we do below.
+
+	for _, k := range keys {
+		snapMod := snap.Modules[k]
+		record := configSnapshotModuleRecord{
+			Dir:        snapMod.Dir,
+			Key:        k,
+			SourceAddr: snapMod.SourceAddr,
+		}
+		if snapMod.Version != nil {
+			record.VersionStr = snapMod.Version.String()
+		}
+		manifest = append(manifest, record)
+
+		pathPrefix := fmt.Sprintf("%s%s/", configSnapshotModulePrefix, k)
+		for filename, src := range snapMod.Files {
+			zh := &zip.FileHeader{
+				Name:     pathPrefix + filename,
+				Method:   zip.Deflate,
+				Modified: time.Now(),
+			}
+			w, err := z.CreateHeader(zh)
+			if err != nil {
+				return fmt.Errorf("failed to create snapshot of %s from module %q: %s", zh.Name, k, err)
+			}
+			_, err = w.Write(src)
+			if err != nil {
+				return fmt.Errorf("failed to write snapshot of %s from module %q: %s", zh.Name, k, err)
+			}
+		}
+	}
+
+	// Now we'll write our manifest
+	{
+		zh := &zip.FileHeader{
+			Name:     configSnapshotManifestFile,
+			Method:   zip.Deflate,
+			Modified: time.Now(),
+		}
+		src, err := json.MarshalIndent(manifest, "", "  ")
+		if err != nil {
+			return fmt.Errorf("failed to serialize module manifest: %s", err)
+		}
+		w, err := z.CreateHeader(zh)
+		if err != nil {
+			return fmt.Errorf("failed to create module manifest: %s", err)
+		}
+		_, err = w.Write(src)
+		if err != nil {
+			return fmt.Errorf("failed to write module manifest: %s", err)
+		}
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/plans/planfile/config_snapshot_test.go b/v1.5.7/internal/plans/planfile/config_snapshot_test.go
new file mode 100644
index 0000000..b0e7110
--- /dev/null
+++ b/v1.5.7/internal/plans/planfile/config_snapshot_test.go
@@ -0,0 +1,55 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package planfile
+
+import (
+	"archive/zip"
+	"bytes"
+	"path/filepath"
+	"reflect"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+
+	"github.com/hashicorp/terraform/internal/configs/configload"
+)
+
+func TestConfigSnapshotRoundtrip(t *testing.T) {
+	fixtureDir := filepath.Join("testdata", "test-config")
+	loader, err := configload.NewLoader(&configload.Config{
+		ModulesDir: filepath.Join(fixtureDir, ".terraform", "modules"),
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, snapIn, diags := loader.LoadConfigWithSnapshot(fixtureDir)
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	var buf bytes.Buffer
+	zw := zip.NewWriter(&buf)
+	err = writeConfigSnapshot(snapIn, zw)
+	if err != nil {
+		t.Fatalf("failed to write snapshot: %s", err)
+	}
+	zw.Close()
+
+	raw := buf.Bytes()
+	r := bytes.NewReader(raw)
+	zr, err := zip.NewReader(r, int64(len(raw)))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	snapOut, err := readConfigSnapshot(zr)
+	if err != nil {
+		t.Fatalf("failed to read snapshot: %s", err)
+	}
+
+	if !reflect.DeepEqual(snapIn, snapOut) {
+		t.Errorf("result does not match input\nresult: %sinput: %s", spew.Sdump(snapOut), spew.Sdump(snapIn))
+	}
+}
diff --git a/v1.5.7/internal/plans/planfile/doc.go b/v1.5.7/internal/plans/planfile/doc.go
new file mode 100644
index 0000000..8843bae
--- /dev/null
+++ b/v1.5.7/internal/plans/planfile/doc.go
@@ -0,0 +1,9 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package planfile deals with the file format used to serialize plans to disk
+// and then deserialize them back into memory later.
+//
+// A plan file contains the planned changes along with the configuration and
+// state snapshot that they are based on.
+package planfile
diff --git a/v1.5.7/internal/plans/planfile/planfile_test.go b/v1.5.7/internal/plans/planfile/planfile_test.go
new file mode 100644
index 0000000..dc6e864
--- /dev/null
+++ b/v1.5.7/internal/plans/planfile/planfile_test.go
@@ -0,0 +1,169 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package planfile
+
+import (
+	"path/filepath"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+func TestRoundtrip(t *testing.T) {
+	fixtureDir := filepath.Join("testdata", "test-config")
+	loader, err := configload.NewLoader(&configload.Config{
+		ModulesDir: filepath.Join(fixtureDir, ".terraform", "modules"),
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, snapIn, diags := loader.LoadConfigWithSnapshot(fixtureDir)
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	// Just a minimal state file so we can test that it comes out again at all.
+	// We don't need to test the entire thing because the state file
+	// serialization is already tested in its own package.
+	stateFileIn := &statefile.File{
+		TerraformVersion: tfversion.SemVer,
+		Serial:           2,
+		Lineage:          "abc123",
+		State:            states.NewState(),
+	}
+	prevStateFileIn := &statefile.File{
+		TerraformVersion: tfversion.SemVer,
+		Serial:           1,
+		Lineage:          "abc123",
+		State:            states.NewState(),
+	}
+
+	// Minimal plan too, since the serialization of the tfplan portion of the
+	// file is tested more fully in tfplan_test.go .
+	planIn := &plans.Plan{
+		Changes: &plans.Changes{
+			Resources: []*plans.ResourceInstanceChangeSrc{},
+			Outputs:   []*plans.OutputChangeSrc{},
+		},
+		DriftedResources: []*plans.ResourceInstanceChangeSrc{},
+		VariableValues: map[string]plans.DynamicValue{
+			"foo": plans.DynamicValue([]byte("foo placeholder")),
+		},
+		Backend: plans.Backend{
+			Type:      "local",
+			Config:    plans.DynamicValue([]byte("config placeholder")),
+			Workspace: "default",
+		},
+		Checks: &states.CheckResults{},
+
+		// Due to some historical oddities in how we've changed modelling over
+		// time, we also include the states (without the corresponding file
+		// headers) in the plans.Plan object. This is currently ignored by
+		// Create but will be returned by ReadPlan and so we need to include
+		// it here so that we'll get a match when we compare input and output
+		// below.
+		PrevRunState: prevStateFileIn.State,
+		PriorState:   stateFileIn.State,
+	}
+
+	locksIn := depsfile.NewLocks()
+	locksIn.SetProvider(
+		addrs.NewDefaultProvider("boop"),
+		getproviders.MustParseVersion("1.0.0"),
+		getproviders.MustParseVersionConstraints(">= 1.0.0"),
+		[]getproviders.Hash{
+			getproviders.MustParseHash("fake:hello"),
+		},
+	)
+
+	planFn := filepath.Join(t.TempDir(), "tfplan")
+
+	err = Create(planFn, CreateArgs{
+		ConfigSnapshot:       snapIn,
+		PreviousRunStateFile: prevStateFileIn,
+		StateFile:            stateFileIn,
+		Plan:                 planIn,
+		DependencyLocks:      locksIn,
+	})
+	if err != nil {
+		t.Fatalf("failed to create plan file: %s", err)
+	}
+
+	pr, err := Open(planFn)
+	if err != nil {
+		t.Fatalf("failed to open plan file for reading: %s", err)
+	}
+
+	t.Run("ReadPlan", func(t *testing.T) {
+		planOut, err := pr.ReadPlan()
+		if err != nil {
+			t.Fatalf("failed to read plan: %s", err)
+		}
+		if diff := cmp.Diff(planIn, planOut); diff != "" {
+			t.Errorf("plan did not survive round-trip\n%s", diff)
+		}
+	})
+
+	t.Run("ReadStateFile", func(t *testing.T) {
+		stateFileOut, err := pr.ReadStateFile()
+		if err != nil {
+			t.Fatalf("failed to read state: %s", err)
+		}
+		if diff := cmp.Diff(stateFileIn, stateFileOut); diff != "" {
+			t.Errorf("state file did not survive round-trip\n%s", diff)
+		}
+	})
+
+	t.Run("ReadPrevStateFile", func(t *testing.T) {
+		prevStateFileOut, err := pr.ReadPrevStateFile()
+		if err != nil {
+			t.Fatalf("failed to read state: %s", err)
+		}
+		if diff := cmp.Diff(prevStateFileIn, prevStateFileOut); diff != "" {
+			t.Errorf("state file did not survive round-trip\n%s", diff)
+		}
+	})
+
+	t.Run("ReadConfigSnapshot", func(t *testing.T) {
+		snapOut, err := pr.ReadConfigSnapshot()
+		if err != nil {
+			t.Fatalf("failed to read config snapshot: %s", err)
+		}
+		if diff := cmp.Diff(snapIn, snapOut); diff != "" {
+			t.Errorf("config snapshot did not survive round-trip\n%s", diff)
+		}
+	})
+
+	t.Run("ReadConfig", func(t *testing.T) {
+		// Reading from snapshots is tested in the configload package, so
+		// here we'll just test that we can successfully do it, to see if the
+		// glue code in _this_ package is correct.
+		_, diags := pr.ReadConfig()
+		if diags.HasErrors() {
+			t.Errorf("when reading config: %s", diags.Err())
+		}
+	})
+
+	t.Run("ReadDependencyLocks", func(t *testing.T) {
+		locksOut, diags := pr.ReadDependencyLocks()
+		if diags.HasErrors() {
+			t.Fatalf("when reading config: %s", diags.Err())
+		}
+		got := locksOut.AllProviders()
+		want := locksIn.AllProviders()
+		if diff := cmp.Diff(want, got, cmp.AllowUnexported(depsfile.ProviderLock{})); diff != "" {
+			t.Errorf("provider locks did not survive round-trip\n%s", diff)
+		}
+	})
+}
diff --git a/v1.5.7/internal/plans/planfile/reader.go b/v1.5.7/internal/plans/planfile/reader.go
new file mode 100644
index 0000000..c55de5f
--- /dev/null
+++ b/v1.5.7/internal/plans/planfile/reader.go
@@ -0,0 +1,245 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package planfile
+
+import (
+	"archive/zip"
+	"bytes"
+	"fmt"
+	"io/ioutil"
+
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+const tfstateFilename = "tfstate"
+const tfstatePreviousFilename = "tfstate-prev"
+const dependencyLocksFilename = ".terraform.lock.hcl" // matches the conventional name in an input configuration
+
+// Reader is the main type used to read plan files. Create a Reader by calling
+// Open.
+//
+// A plan file is a random-access file format, so methods of Reader must
+// be used to access the individual portions of the file for further
+// processing.
+type Reader struct {
+	zip *zip.ReadCloser
+}
+
+// Open creates a Reader for the file at the given filename, or returns an
+// error if the file doesn't seem to be a planfile.
+func Open(filename string) (*Reader, error) {
+	r, err := zip.OpenReader(filename)
+	if err != nil {
+		// To give a better error message, we'll sniff to see if this looks
+		// like our old plan format from versions prior to 0.12.
+		if b, sErr := ioutil.ReadFile(filename); sErr == nil {
+			if bytes.HasPrefix(b, []byte("tfplan")) {
+				return nil, fmt.Errorf("the given plan file was created by an earlier version of Terraform; plan files cannot be shared between different Terraform versions")
+			}
+		}
+		return nil, err
+	}
+
+	// Sniff to make sure this looks like a plan file, as opposed to any other
+	// random zip file the user might have around.
+	var planFile *zip.File
+	for _, file := range r.File {
+		if file.Name == tfplanFilename {
+			planFile = file
+			break
+		}
+	}
+	if planFile == nil {
+		return nil, fmt.Errorf("the given file is not a valid plan file")
+	}
+
+	// For now, we'll just accept the presence of the tfplan file as enough,
+	// and wait to validate the version when the caller requests the plan
+	// itself.
+
+	return &Reader{
+		zip: r,
+	}, nil
+}
+
+// ReadPlan reads the plan embedded in the plan file.
+//
+// Errors can be returned for various reasons, including if the plan file
+// is not of an appropriate format version, if it was created by a different
+// version of Terraform, if it is invalid, etc.
+func (r *Reader) ReadPlan() (*plans.Plan, error) {
+	var planFile *zip.File
+	for _, file := range r.zip.File {
+		if file.Name == tfplanFilename {
+			planFile = file
+			break
+		}
+	}
+	if planFile == nil {
+		// This should never happen because we checked for this file during
+		// Open, but we'll check anyway to be safe.
+		return nil, fmt.Errorf("the plan file is invalid")
+	}
+
+	pr, err := planFile.Open()
+	if err != nil {
+		return nil, fmt.Errorf("failed to retrieve plan from plan file: %s", err)
+	}
+	defer pr.Close()
+
+	// There's a slight mismatch in how plans.Plan is modeled vs. how
+	// the underlying plan file format works, because the "tfplan" embedded
+	// file contains only some top-level metadata and the planned changes,
+	// and not the previous run or prior states. Therefore we need to
+	// build this up in multiple steps.
+	// This is some technical debt because historically we considered the
+	// planned changes and prior state as totally separate, but later realized
+	// that it made sense for a plans.Plan to include the prior state directly
+	// so we can see what state the plan applies to. Hopefully later we'll
+	// clean this up some more so that we don't have two different ways to
+	// access the prior state (this and the ReadStateFile method).
+	ret, err := readTfplan(pr)
+	if err != nil {
+		return nil, err
+	}
+
+	prevRunStateFile, err := r.ReadPrevStateFile()
+	if err != nil {
+		return nil, fmt.Errorf("failed to read previous run state from plan file: %s", err)
+	}
+	priorStateFile, err := r.ReadStateFile()
+	if err != nil {
+		return nil, fmt.Errorf("failed to read prior state from plan file: %s", err)
+	}
+
+	ret.PrevRunState = prevRunStateFile.State
+	ret.PriorState = priorStateFile.State
+
+	return ret, nil
+}
+
+// ReadStateFile reads the state file embedded in the plan file, which
+// represents the "PriorState" as defined in plans.Plan.
+//
+// If the plan file contains no embedded state file, the returned error is
+// statefile.ErrNoState.
+func (r *Reader) ReadStateFile() (*statefile.File, error) {
+	for _, file := range r.zip.File {
+		if file.Name == tfstateFilename {
+			r, err := file.Open()
+			if err != nil {
+				return nil, fmt.Errorf("failed to extract state from plan file: %s", err)
+			}
+			return statefile.Read(r)
+		}
+	}
+	return nil, statefile.ErrNoState
+}
+
+// ReadPrevStateFile reads the previous state file embedded in the plan file, which
+// represents the "PrevRunState" as defined in plans.Plan.
+//
+// If the plan file contains no embedded previous state file, the returned error is
+// statefile.ErrNoState.
+func (r *Reader) ReadPrevStateFile() (*statefile.File, error) {
+	for _, file := range r.zip.File {
+		if file.Name == tfstatePreviousFilename {
+			r, err := file.Open()
+			if err != nil {
+				return nil, fmt.Errorf("failed to extract previous state from plan file: %s", err)
+			}
+			return statefile.Read(r)
+		}
+	}
+	return nil, statefile.ErrNoState
+}
+
+// ReadConfigSnapshot reads the configuration snapshot embedded in the plan
+// file.
+//
+// This is a lower-level alternative to ReadConfig that just extracts the
+// source files, without attempting to parse them.
+func (r *Reader) ReadConfigSnapshot() (*configload.Snapshot, error) {
+	return readConfigSnapshot(&r.zip.Reader)
+}
+
+// ReadConfig reads the configuration embedded in the plan file.
+//
+// Internally this function delegates to the configs/configload package to
+// parse the embedded configuration and so it returns diagnostics (rather than
+// a native Go error as with other methods on Reader).
+func (r *Reader) ReadConfig() (*configs.Config, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	snap, err := r.ReadConfigSnapshot()
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to read configuration from plan file",
+			fmt.Sprintf("The configuration file snapshot in the plan file could not be read: %s.", err),
+		))
+		return nil, diags
+	}
+
+	loader := configload.NewLoaderFromSnapshot(snap)
+	rootDir := snap.Modules[""].Dir // Root module base directory
+	config, configDiags := loader.LoadConfig(rootDir)
+	diags = diags.Append(configDiags)
+
+	return config, diags
+}
+
+// ReadDependencyLocks reads the dependency lock information embedded in
+// the plan file.
+//
+// Some test codepaths create plan files without dependency lock information,
+// but all main codepaths should populate this. If reading a file without
+// the dependency information, this will return error diagnostics.
+func (r *Reader) ReadDependencyLocks() (*depsfile.Locks, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	for _, file := range r.zip.File {
+		if file.Name == dependencyLocksFilename {
+			r, err := file.Open()
+			if err != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to read dependency locks from plan file",
+					fmt.Sprintf("Couldn't read the dependency lock information embedded in the plan file: %s.", err),
+				))
+				return nil, diags
+			}
+			src, err := ioutil.ReadAll(r)
+			if err != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to read dependency locks from plan file",
+					fmt.Sprintf("Couldn't read the dependency lock information embedded in the plan file: %s.", err),
+				))
+				return nil, diags
+			}
+			locks, moreDiags := depsfile.LoadLocksFromBytes(src, "<saved-plan>")
+			diags = diags.Append(moreDiags)
+			return locks, diags
+		}
+	}
+
+	// If we fall out here then this is a file without dependency information.
+	diags = diags.Append(tfdiags.Sourceless(
+		tfdiags.Error,
+		"Saved plan has no dependency lock information",
+		"The specified saved plan file does not include any dependency lock information. This is a bug in the previous run of Terraform that created this file.",
+	))
+	return nil, diags
+}
+
+// Close closes the file, after which no other operations may be performed.
+func (r *Reader) Close() error {
+	return r.zip.Close()
+}
diff --git a/v1.5.7/internal/plans/planfile/testdata/test-config/.terraform/modules/child_a/child_a.tf b/v1.5.7/internal/plans/planfile/testdata/test-config/.terraform/modules/child_a/child_a.tf
new file mode 100644
index 0000000..2f4d0f1
--- /dev/null
+++ b/v1.5.7/internal/plans/planfile/testdata/test-config/.terraform/modules/child_a/child_a.tf
@@ -0,0 +1,4 @@
+
+module "child_c" {
+  source  = "./child_c"
+}
diff --git a/v1.5.7/internal/plans/planfile/testdata/test-config/.terraform/modules/child_a/child_c/child_c.tf b/v1.5.7/internal/plans/planfile/testdata/test-config/.terraform/modules/child_a/child_c/child_c.tf
new file mode 100644
index 0000000..785d98d
--- /dev/null
+++ b/v1.5.7/internal/plans/planfile/testdata/test-config/.terraform/modules/child_a/child_c/child_c.tf
@@ -0,0 +1,4 @@
+
+output "hello" {
+  value = "Hello from child_c"
+}
diff --git a/v1.5.7/internal/plans/planfile/testdata/test-config/.terraform/modules/child_b.child_d/child_d.tf b/v1.5.7/internal/plans/planfile/testdata/test-config/.terraform/modules/child_b.child_d/child_d.tf
new file mode 100644
index 0000000..145576a
--- /dev/null
+++ b/v1.5.7/internal/plans/planfile/testdata/test-config/.terraform/modules/child_b.child_d/child_d.tf
@@ -0,0 +1,4 @@
+
+output "hello" {
+  value = "Hello from child_d"
+}
diff --git a/v1.5.7/internal/plans/planfile/testdata/test-config/.terraform/modules/child_b/child_b.tf b/v1.5.7/internal/plans/planfile/testdata/test-config/.terraform/modules/child_b/child_b.tf
new file mode 100644
index 0000000..4a1b247
--- /dev/null
+++ b/v1.5.7/internal/plans/planfile/testdata/test-config/.terraform/modules/child_b/child_b.tf
@@ -0,0 +1,5 @@
+
+module "child_d" {
+  source  = "example.com/foo/bar_d/baz"
+  # Intentionally no version here
+}
diff --git a/v1.5.7/internal/plans/planfile/testdata/test-config/.terraform/modules/modules.json b/v1.5.7/internal/plans/planfile/testdata/test-config/.terraform/modules/modules.json
new file mode 100644
index 0000000..ba69187
--- /dev/null
+++ b/v1.5.7/internal/plans/planfile/testdata/test-config/.terraform/modules/modules.json
@@ -0,0 +1,32 @@
+{
+  "Modules": [
+    {
+      "Key": "",
+      "Source": "",
+      "Dir": "testdata/test-config"
+    },
+    {
+      "Key": "child_a",
+      "Source": "example.com/foo/bar_a/baz",
+      "Version": "1.0.1",
+      "Dir": "testdata/test-config/.terraform/modules/child_a"
+    },
+    {
+      "Key": "child_b",
+      "Source": "example.com/foo/bar_b/baz",
+      "Version": "1.0.0",
+      "Dir": "testdata/test-config/.terraform/modules/child_b"
+    },
+    {
+      "Key": "child_a.child_c",
+      "Source": "./child_c",
+      "Dir": "testdata/test-config/.terraform/modules/child_a/child_c"
+    },
+    {
+      "Key": "child_b.child_d",
+      "Source": "example.com/foo/bar_d/baz",
+      "Version": "1.2.0",
+      "Dir": "testdata/test-config/.terraform/modules/child_b.child_d"
+    }
+  ]
+}
diff --git a/v1.5.7/internal/plans/planfile/testdata/test-config/root.tf b/v1.5.7/internal/plans/planfile/testdata/test-config/root.tf
new file mode 100644
index 0000000..8a44739
--- /dev/null
+++ b/v1.5.7/internal/plans/planfile/testdata/test-config/root.tf
@@ -0,0 +1,10 @@
+
+module "child_a" {
+  source  = "example.com/foo/bar_a/baz"
+  version = ">= 1.0.0"
+}
+
+module "child_b" {
+  source = "example.com/foo/bar_b/baz"
+  version = ">= 1.0.0"
+}
diff --git a/v1.5.7/internal/plans/planfile/tfplan.go b/v1.5.7/internal/plans/planfile/tfplan.go
new file mode 100644
index 0000000..d7f5cb0
--- /dev/null
+++ b/v1.5.7/internal/plans/planfile/tfplan.go
@@ -0,0 +1,898 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package planfile
+
+import (
+	"fmt"
+	"io"
+	"io/ioutil"
+	"time"
+
+	"github.com/zclconf/go-cty/cty"
+	"google.golang.org/protobuf/proto"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/lang/globalref"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/internal/planproto"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/version"
+)
+
+const tfplanFormatVersion = 3
+const tfplanFilename = "tfplan"
+
+// ---------------------------------------------------------------------------
+// This file deals with the internal structure of the "tfplan" sub-file within
+// the plan file format. It's all private API, wrapped by methods defined
+// elsewhere. This is the only file that should import the
+// ../internal/planproto package, which contains the ugly stubs generated
+// by the protobuf compiler.
+// ---------------------------------------------------------------------------
+
+// readTfplan reads a protobuf-encoded description from the plan portion of
+// a plan file, which is stored in a special file in the archive called
+// "tfplan".
+func readTfplan(r io.Reader) (*plans.Plan, error) {
+	src, err := ioutil.ReadAll(r)
+	if err != nil {
+		return nil, err
+	}
+
+	var rawPlan planproto.Plan
+	err = proto.Unmarshal(src, &rawPlan)
+	if err != nil {
+		return nil, fmt.Errorf("parse error: %s", err)
+	}
+
+	if rawPlan.Version != tfplanFormatVersion {
+		return nil, fmt.Errorf("unsupported plan file format version %d; only version %d is supported", rawPlan.Version, tfplanFormatVersion)
+	}
+
+	if rawPlan.TerraformVersion != version.String() {
+		return nil, fmt.Errorf("plan file was created by Terraform %s, but this is %s; plan files cannot be transferred between different Terraform versions", rawPlan.TerraformVersion, version.String())
+	}
+
+	plan := &plans.Plan{
+		VariableValues: map[string]plans.DynamicValue{},
+		Changes: &plans.Changes{
+			Outputs:   []*plans.OutputChangeSrc{},
+			Resources: []*plans.ResourceInstanceChangeSrc{},
+		},
+		DriftedResources: []*plans.ResourceInstanceChangeSrc{},
+		Checks:           &states.CheckResults{},
+	}
+
+	plan.Errored = rawPlan.Errored
+
+	switch rawPlan.UiMode {
+	case planproto.Mode_NORMAL:
+		plan.UIMode = plans.NormalMode
+	case planproto.Mode_DESTROY:
+		plan.UIMode = plans.DestroyMode
+	case planproto.Mode_REFRESH_ONLY:
+		plan.UIMode = plans.RefreshOnlyMode
+	default:
+		return nil, fmt.Errorf("plan has invalid mode %s", rawPlan.UiMode)
+	}
+
+	for _, rawOC := range rawPlan.OutputChanges {
+		name := rawOC.Name
+		change, err := changeFromTfplan(rawOC.Change)
+		if err != nil {
+			return nil, fmt.Errorf("invalid plan for output %q: %s", name, err)
+		}
+
+		plan.Changes.Outputs = append(plan.Changes.Outputs, &plans.OutputChangeSrc{
+			// All output values saved in the plan file are root module outputs,
+			// since we don't retain others. (They can be easily recomputed
+			// during apply).
+			Addr:      addrs.OutputValue{Name: name}.Absolute(addrs.RootModuleInstance),
+			ChangeSrc: *change,
+			Sensitive: rawOC.Sensitive,
+		})
+	}
+
+	plan.Checks.ConfigResults = addrs.MakeMap[addrs.ConfigCheckable, *states.CheckResultAggregate]()
+	for _, rawCRs := range rawPlan.CheckResults {
+		aggr := &states.CheckResultAggregate{}
+		switch rawCRs.Status {
+		case planproto.CheckResults_UNKNOWN:
+			aggr.Status = checks.StatusUnknown
+		case planproto.CheckResults_PASS:
+			aggr.Status = checks.StatusPass
+		case planproto.CheckResults_FAIL:
+			aggr.Status = checks.StatusFail
+		case planproto.CheckResults_ERROR:
+			aggr.Status = checks.StatusError
+		default:
+			return nil, fmt.Errorf("aggregate check results for %s have unsupported status %#v", rawCRs.ConfigAddr, rawCRs.Status)
+		}
+
+		var objKind addrs.CheckableKind
+		switch rawCRs.Kind {
+		case planproto.CheckResults_RESOURCE:
+			objKind = addrs.CheckableResource
+		case planproto.CheckResults_OUTPUT_VALUE:
+			objKind = addrs.CheckableOutputValue
+		case planproto.CheckResults_CHECK:
+			objKind = addrs.CheckableCheck
+		default:
+			return nil, fmt.Errorf("aggregate check results for %s have unsupported object kind %s", rawCRs.ConfigAddr, objKind)
+		}
+
+		// Some trickiness here: we only have an address parser for
+		// addrs.Checkable and not for addrs.ConfigCheckable, but that's okay
+		// because once we have an addrs.Checkable we can always derive an
+		// addrs.ConfigCheckable from it, and a ConfigCheckable should always
+		// be the same syntax as a Checkable with no index information and
+		// thus we can reuse the same parser for both here.
+		configAddrProxy, diags := addrs.ParseCheckableStr(objKind, rawCRs.ConfigAddr)
+		if diags.HasErrors() {
+			return nil, diags.Err()
+		}
+		configAddr := configAddrProxy.ConfigCheckable()
+		if configAddr.String() != configAddrProxy.String() {
+			// This is how we catch if the config address included index
+			// information that would be allowed in a Checkable but not
+			// in a ConfigCheckable.
+			return nil, fmt.Errorf("invalid checkable config address %s", rawCRs.ConfigAddr)
+		}
+
+		aggr.ObjectResults = addrs.MakeMap[addrs.Checkable, *states.CheckResultObject]()
+		for _, rawCR := range rawCRs.Objects {
+			objectAddr, diags := addrs.ParseCheckableStr(objKind, rawCR.ObjectAddr)
+			if diags.HasErrors() {
+				return nil, diags.Err()
+			}
+			if !addrs.Equivalent(objectAddr.ConfigCheckable(), configAddr) {
+				return nil, fmt.Errorf("checkable object %s should not be grouped under %s", objectAddr, configAddr)
+			}
+
+			obj := &states.CheckResultObject{
+				FailureMessages: rawCR.FailureMessages,
+			}
+			switch rawCR.Status {
+			case planproto.CheckResults_UNKNOWN:
+				obj.Status = checks.StatusUnknown
+			case planproto.CheckResults_PASS:
+				obj.Status = checks.StatusPass
+			case planproto.CheckResults_FAIL:
+				obj.Status = checks.StatusFail
+			case planproto.CheckResults_ERROR:
+				obj.Status = checks.StatusError
+			default:
+				return nil, fmt.Errorf("object check results for %s has unsupported status %#v", rawCR.ObjectAddr, rawCR.Status)
+			}
+
+			aggr.ObjectResults.Put(objectAddr, obj)
+		}
+		// If we ended up with no elements in the map then we'll just nil it,
+		// primarily just to make life easier for our round-trip tests.
+		if aggr.ObjectResults.Len() == 0 {
+			aggr.ObjectResults.Elems = nil
+		}
+
+		plan.Checks.ConfigResults.Put(configAddr, aggr)
+	}
+	// If we ended up with no elements in the map then we'll just nil it,
+	// primarily just to make life easier for our round-trip tests.
+	if plan.Checks.ConfigResults.Len() == 0 {
+		plan.Checks.ConfigResults.Elems = nil
+	}
+
+	for _, rawRC := range rawPlan.ResourceChanges {
+		change, err := resourceChangeFromTfplan(rawRC)
+		if err != nil {
+			// errors from resourceChangeFromTfplan already include context
+			return nil, err
+		}
+
+		plan.Changes.Resources = append(plan.Changes.Resources, change)
+	}
+
+	for _, rawRC := range rawPlan.ResourceDrift {
+		change, err := resourceChangeFromTfplan(rawRC)
+		if err != nil {
+			// errors from resourceChangeFromTfplan already include context
+			return nil, err
+		}
+
+		plan.DriftedResources = append(plan.DriftedResources, change)
+	}
+
+	for _, rawRA := range rawPlan.RelevantAttributes {
+		ra, err := resourceAttrFromTfplan(rawRA)
+		if err != nil {
+			return nil, err
+		}
+		plan.RelevantAttributes = append(plan.RelevantAttributes, ra)
+	}
+
+	for _, rawTargetAddr := range rawPlan.TargetAddrs {
+		target, diags := addrs.ParseTargetStr(rawTargetAddr)
+		if diags.HasErrors() {
+			return nil, fmt.Errorf("plan contains invalid target address %q: %s", target, diags.Err())
+		}
+		plan.TargetAddrs = append(plan.TargetAddrs, target.Subject)
+	}
+
+	for _, rawReplaceAddr := range rawPlan.ForceReplaceAddrs {
+		addr, diags := addrs.ParseAbsResourceInstanceStr(rawReplaceAddr)
+		if diags.HasErrors() {
+			return nil, fmt.Errorf("plan contains invalid force-replace address %q: %s", addr, diags.Err())
+		}
+		plan.ForceReplaceAddrs = append(plan.ForceReplaceAddrs, addr)
+	}
+
+	for name, rawVal := range rawPlan.Variables {
+		val, err := valueFromTfplan(rawVal)
+		if err != nil {
+			return nil, fmt.Errorf("invalid value for input variable %q: %s", name, err)
+		}
+		plan.VariableValues[name] = val
+	}
+
+	if rawBackend := rawPlan.Backend; rawBackend == nil {
+		return nil, fmt.Errorf("plan file has no backend settings; backend settings are required")
+	} else {
+		config, err := valueFromTfplan(rawBackend.Config)
+		if err != nil {
+			return nil, fmt.Errorf("plan file has invalid backend configuration: %s", err)
+		}
+		plan.Backend = plans.Backend{
+			Type:      rawBackend.Type,
+			Config:    config,
+			Workspace: rawBackend.Workspace,
+		}
+	}
+
+	if plan.Timestamp, err = time.Parse(time.RFC3339, rawPlan.Timestamp); err != nil {
+		return nil, fmt.Errorf("invalid value for timestamp %s: %s", rawPlan.Timestamp, err)
+	}
+
+	return plan, nil
+}
+
+func resourceChangeFromTfplan(rawChange *planproto.ResourceInstanceChange) (*plans.ResourceInstanceChangeSrc, error) {
+	if rawChange == nil {
+		// Should never happen in practice, since protobuf can't represent
+		// a nil value in a list.
+		return nil, fmt.Errorf("resource change object is absent")
+	}
+
+	ret := &plans.ResourceInstanceChangeSrc{}
+
+	if rawChange.Addr == "" {
+		// If "Addr" isn't populated then seems likely that this is a plan
+		// file created by an earlier version of Terraform, which had the
+		// same information spread over various other fields:
+		// ModulePath, Mode, Name, Type, and InstanceKey.
+		return nil, fmt.Errorf("no instance address for resource instance change; perhaps this plan was created by a different version of Terraform?")
+	}
+
+	instAddr, diags := addrs.ParseAbsResourceInstanceStr(rawChange.Addr)
+	if diags.HasErrors() {
+		return nil, fmt.Errorf("invalid resource instance address %q: %w", rawChange.Addr, diags.Err())
+	}
+	prevRunAddr := instAddr
+	if rawChange.PrevRunAddr != "" {
+		prevRunAddr, diags = addrs.ParseAbsResourceInstanceStr(rawChange.PrevRunAddr)
+		if diags.HasErrors() {
+			return nil, fmt.Errorf("invalid resource instance previous run address %q: %w", rawChange.PrevRunAddr, diags.Err())
+		}
+	}
+
+	providerAddr, diags := addrs.ParseAbsProviderConfigStr(rawChange.Provider)
+	if diags.HasErrors() {
+		return nil, diags.Err()
+	}
+	ret.ProviderAddr = providerAddr
+
+	ret.Addr = instAddr
+	ret.PrevRunAddr = prevRunAddr
+
+	if rawChange.DeposedKey != "" {
+		if len(rawChange.DeposedKey) != 8 {
+			return nil, fmt.Errorf("deposed object for %s has invalid deposed key %q", ret.Addr, rawChange.DeposedKey)
+		}
+		ret.DeposedKey = states.DeposedKey(rawChange.DeposedKey)
+	}
+
+	ret.RequiredReplace = cty.NewPathSet()
+	for _, p := range rawChange.RequiredReplace {
+		path, err := pathFromTfplan(p)
+		if err != nil {
+			return nil, fmt.Errorf("invalid path in required replace: %s", err)
+		}
+		ret.RequiredReplace.Add(path)
+	}
+
+	change, err := changeFromTfplan(rawChange.Change)
+	if err != nil {
+		return nil, fmt.Errorf("invalid plan for resource %s: %s", ret.Addr, err)
+	}
+
+	ret.ChangeSrc = *change
+
+	switch rawChange.ActionReason {
+	case planproto.ResourceInstanceActionReason_NONE:
+		ret.ActionReason = plans.ResourceInstanceChangeNoReason
+	case planproto.ResourceInstanceActionReason_REPLACE_BECAUSE_CANNOT_UPDATE:
+		ret.ActionReason = plans.ResourceInstanceReplaceBecauseCannotUpdate
+	case planproto.ResourceInstanceActionReason_REPLACE_BECAUSE_TAINTED:
+		ret.ActionReason = plans.ResourceInstanceReplaceBecauseTainted
+	case planproto.ResourceInstanceActionReason_REPLACE_BY_REQUEST:
+		ret.ActionReason = plans.ResourceInstanceReplaceByRequest
+	case planproto.ResourceInstanceActionReason_REPLACE_BY_TRIGGERS:
+		ret.ActionReason = plans.ResourceInstanceReplaceByTriggers
+	case planproto.ResourceInstanceActionReason_DELETE_BECAUSE_NO_RESOURCE_CONFIG:
+		ret.ActionReason = plans.ResourceInstanceDeleteBecauseNoResourceConfig
+	case planproto.ResourceInstanceActionReason_DELETE_BECAUSE_WRONG_REPETITION:
+		ret.ActionReason = plans.ResourceInstanceDeleteBecauseWrongRepetition
+	case planproto.ResourceInstanceActionReason_DELETE_BECAUSE_COUNT_INDEX:
+		ret.ActionReason = plans.ResourceInstanceDeleteBecauseCountIndex
+	case planproto.ResourceInstanceActionReason_DELETE_BECAUSE_EACH_KEY:
+		ret.ActionReason = plans.ResourceInstanceDeleteBecauseEachKey
+	case planproto.ResourceInstanceActionReason_DELETE_BECAUSE_NO_MODULE:
+		ret.ActionReason = plans.ResourceInstanceDeleteBecauseNoModule
+	case planproto.ResourceInstanceActionReason_READ_BECAUSE_CONFIG_UNKNOWN:
+		ret.ActionReason = plans.ResourceInstanceReadBecauseConfigUnknown
+	case planproto.ResourceInstanceActionReason_READ_BECAUSE_DEPENDENCY_PENDING:
+		ret.ActionReason = plans.ResourceInstanceReadBecauseDependencyPending
+	case planproto.ResourceInstanceActionReason_READ_BECAUSE_CHECK_NESTED:
+		ret.ActionReason = plans.ResourceInstanceReadBecauseCheckNested
+	case planproto.ResourceInstanceActionReason_DELETE_BECAUSE_NO_MOVE_TARGET:
+		ret.ActionReason = plans.ResourceInstanceDeleteBecauseNoMoveTarget
+	default:
+		return nil, fmt.Errorf("resource has invalid action reason %s", rawChange.ActionReason)
+	}
+
+	if len(rawChange.Private) != 0 {
+		ret.Private = rawChange.Private
+	}
+
+	return ret, nil
+}
+
+func changeFromTfplan(rawChange *planproto.Change) (*plans.ChangeSrc, error) {
+	if rawChange == nil {
+		return nil, fmt.Errorf("change object is absent")
+	}
+
+	ret := &plans.ChangeSrc{}
+
+	// -1 indicates that there is no index. We'll customize these below
+	// depending on the change action, and then decode.
+	beforeIdx, afterIdx := -1, -1
+
+	switch rawChange.Action {
+	case planproto.Action_NOOP:
+		ret.Action = plans.NoOp
+		beforeIdx = 0
+		afterIdx = 0
+	case planproto.Action_CREATE:
+		ret.Action = plans.Create
+		afterIdx = 0
+	case planproto.Action_READ:
+		ret.Action = plans.Read
+		beforeIdx = 0
+		afterIdx = 1
+	case planproto.Action_UPDATE:
+		ret.Action = plans.Update
+		beforeIdx = 0
+		afterIdx = 1
+	case planproto.Action_DELETE:
+		ret.Action = plans.Delete
+		beforeIdx = 0
+	case planproto.Action_CREATE_THEN_DELETE:
+		ret.Action = plans.CreateThenDelete
+		beforeIdx = 0
+		afterIdx = 1
+	case planproto.Action_DELETE_THEN_CREATE:
+		ret.Action = plans.DeleteThenCreate
+		beforeIdx = 0
+		afterIdx = 1
+	default:
+		return nil, fmt.Errorf("invalid change action %s", rawChange.Action)
+	}
+
+	if beforeIdx != -1 {
+		if l := len(rawChange.Values); l <= beforeIdx {
+			return nil, fmt.Errorf("incorrect number of values (%d) for %s change", l, rawChange.Action)
+		}
+		var err error
+		ret.Before, err = valueFromTfplan(rawChange.Values[beforeIdx])
+		if err != nil {
+			return nil, fmt.Errorf("invalid \"before\" value: %s", err)
+		}
+		if ret.Before == nil {
+			return nil, fmt.Errorf("missing \"before\" value: %s", err)
+		}
+	}
+	if afterIdx != -1 {
+		if l := len(rawChange.Values); l <= afterIdx {
+			return nil, fmt.Errorf("incorrect number of values (%d) for %s change", l, rawChange.Action)
+		}
+		var err error
+		ret.After, err = valueFromTfplan(rawChange.Values[afterIdx])
+		if err != nil {
+			return nil, fmt.Errorf("invalid \"after\" value: %s", err)
+		}
+		if ret.After == nil {
+			return nil, fmt.Errorf("missing \"after\" value: %s", err)
+		}
+	}
+
+	if rawChange.Importing != nil {
+		ret.Importing = &plans.ImportingSrc{
+			ID: rawChange.Importing.Id,
+		}
+	}
+	ret.GeneratedConfig = rawChange.GeneratedConfig
+
+	sensitive := cty.NewValueMarks(marks.Sensitive)
+	beforeValMarks, err := pathValueMarksFromTfplan(rawChange.BeforeSensitivePaths, sensitive)
+	if err != nil {
+		return nil, fmt.Errorf("failed to decode before sensitive paths: %s", err)
+	}
+	afterValMarks, err := pathValueMarksFromTfplan(rawChange.AfterSensitivePaths, sensitive)
+	if err != nil {
+		return nil, fmt.Errorf("failed to decode after sensitive paths: %s", err)
+	}
+	if len(beforeValMarks) > 0 {
+		ret.BeforeValMarks = beforeValMarks
+	}
+	if len(afterValMarks) > 0 {
+		ret.AfterValMarks = afterValMarks
+	}
+
+	return ret, nil
+}
+
+func valueFromTfplan(rawV *planproto.DynamicValue) (plans.DynamicValue, error) {
+	if len(rawV.Msgpack) == 0 { // len(0) because that's the default value for a "bytes" in protobuf
+		return nil, fmt.Errorf("dynamic value does not have msgpack serialization")
+	}
+
+	return plans.DynamicValue(rawV.Msgpack), nil
+}
+
+// writeTfplan serializes the given plan into the protobuf-based format used
+// for the "tfplan" portion of a plan file.
+func writeTfplan(plan *plans.Plan, w io.Writer) error {
+	if plan == nil {
+		return fmt.Errorf("cannot write plan file for nil plan")
+	}
+	if plan.Changes == nil {
+		return fmt.Errorf("cannot write plan file with nil changeset")
+	}
+
+	rawPlan := &planproto.Plan{
+		Version:          tfplanFormatVersion,
+		TerraformVersion: version.String(),
+
+		Variables:       map[string]*planproto.DynamicValue{},
+		OutputChanges:   []*planproto.OutputChange{},
+		CheckResults:    []*planproto.CheckResults{},
+		ResourceChanges: []*planproto.ResourceInstanceChange{},
+		ResourceDrift:   []*planproto.ResourceInstanceChange{},
+	}
+
+	rawPlan.Errored = plan.Errored
+
+	switch plan.UIMode {
+	case plans.NormalMode:
+		rawPlan.UiMode = planproto.Mode_NORMAL
+	case plans.DestroyMode:
+		rawPlan.UiMode = planproto.Mode_DESTROY
+	case plans.RefreshOnlyMode:
+		rawPlan.UiMode = planproto.Mode_REFRESH_ONLY
+	default:
+		return fmt.Errorf("plan has unsupported mode %s", plan.UIMode)
+	}
+
+	for _, oc := range plan.Changes.Outputs {
+		// When serializing a plan we only retain the root outputs, since
+		// changes to these are externally-visible side effects (e.g. via
+		// terraform_remote_state).
+		if !oc.Addr.Module.IsRoot() {
+			continue
+		}
+
+		name := oc.Addr.OutputValue.Name
+
+		// Writing outputs as cty.DynamicPseudoType forces the stored values
+		// to also contain dynamic type information, so we can recover the
+		// original type when we read the values back in readTFPlan.
+		protoChange, err := changeToTfplan(&oc.ChangeSrc)
+		if err != nil {
+			return fmt.Errorf("cannot write output value %q: %s", name, err)
+		}
+
+		rawPlan.OutputChanges = append(rawPlan.OutputChanges, &planproto.OutputChange{
+			Name:      name,
+			Change:    protoChange,
+			Sensitive: oc.Sensitive,
+		})
+	}
+
+	if plan.Checks != nil {
+		for _, configElem := range plan.Checks.ConfigResults.Elems {
+			crs := configElem.Value
+			pcrs := &planproto.CheckResults{
+				ConfigAddr: configElem.Key.String(),
+			}
+			switch crs.Status {
+			case checks.StatusUnknown:
+				pcrs.Status = planproto.CheckResults_UNKNOWN
+			case checks.StatusPass:
+				pcrs.Status = planproto.CheckResults_PASS
+			case checks.StatusFail:
+				pcrs.Status = planproto.CheckResults_FAIL
+			case checks.StatusError:
+				pcrs.Status = planproto.CheckResults_ERROR
+			default:
+				return fmt.Errorf("checkable configuration %s has unsupported aggregate status %s", configElem.Key, crs.Status)
+			}
+			switch kind := configElem.Key.CheckableKind(); kind {
+			case addrs.CheckableResource:
+				pcrs.Kind = planproto.CheckResults_RESOURCE
+			case addrs.CheckableOutputValue:
+				pcrs.Kind = planproto.CheckResults_OUTPUT_VALUE
+			case addrs.CheckableCheck:
+				pcrs.Kind = planproto.CheckResults_CHECK
+			default:
+				return fmt.Errorf("checkable configuration %s has unsupported object type kind %s", configElem.Key, kind)
+			}
+
+			for _, objectElem := range configElem.Value.ObjectResults.Elems {
+				cr := objectElem.Value
+				pcr := &planproto.CheckResults_ObjectResult{
+					ObjectAddr:      objectElem.Key.String(),
+					FailureMessages: objectElem.Value.FailureMessages,
+				}
+				switch cr.Status {
+				case checks.StatusUnknown:
+					pcr.Status = planproto.CheckResults_UNKNOWN
+				case checks.StatusPass:
+					pcr.Status = planproto.CheckResults_PASS
+				case checks.StatusFail:
+					pcr.Status = planproto.CheckResults_FAIL
+				case checks.StatusError:
+					pcr.Status = planproto.CheckResults_ERROR
+				default:
+					return fmt.Errorf("checkable object %s has unsupported status %s", objectElem.Key, crs.Status)
+				}
+				pcrs.Objects = append(pcrs.Objects, pcr)
+			}
+
+			rawPlan.CheckResults = append(rawPlan.CheckResults, pcrs)
+		}
+	}
+
+	for _, rc := range plan.Changes.Resources {
+		rawRC, err := resourceChangeToTfplan(rc)
+		if err != nil {
+			return err
+		}
+		rawPlan.ResourceChanges = append(rawPlan.ResourceChanges, rawRC)
+	}
+
+	for _, rc := range plan.DriftedResources {
+		rawRC, err := resourceChangeToTfplan(rc)
+		if err != nil {
+			return err
+		}
+		rawPlan.ResourceDrift = append(rawPlan.ResourceDrift, rawRC)
+	}
+
+	for _, ra := range plan.RelevantAttributes {
+		rawRA, err := resourceAttrToTfplan(ra)
+		if err != nil {
+			return err
+		}
+		rawPlan.RelevantAttributes = append(rawPlan.RelevantAttributes, rawRA)
+	}
+
+	for _, targetAddr := range plan.TargetAddrs {
+		rawPlan.TargetAddrs = append(rawPlan.TargetAddrs, targetAddr.String())
+	}
+
+	for _, replaceAddr := range plan.ForceReplaceAddrs {
+		rawPlan.ForceReplaceAddrs = append(rawPlan.ForceReplaceAddrs, replaceAddr.String())
+	}
+
+	for name, val := range plan.VariableValues {
+		rawPlan.Variables[name] = valueToTfplan(val)
+	}
+
+	if plan.Backend.Type == "" || plan.Backend.Config == nil {
+		// This suggests a bug in the code that created the plan, since it
+		// ought to always have a backend populated, even if it's the default
+		// "local" backend with a local state file.
+		return fmt.Errorf("plan does not have a backend configuration")
+	}
+
+	rawPlan.Backend = &planproto.Backend{
+		Type:      plan.Backend.Type,
+		Config:    valueToTfplan(plan.Backend.Config),
+		Workspace: plan.Backend.Workspace,
+	}
+
+	rawPlan.Timestamp = plan.Timestamp.Format(time.RFC3339)
+
+	src, err := proto.Marshal(rawPlan)
+	if err != nil {
+		return fmt.Errorf("serialization error: %s", err)
+	}
+
+	_, err = w.Write(src)
+	if err != nil {
+		return fmt.Errorf("failed to write plan to plan file: %s", err)
+	}
+
+	return nil
+}
+
+func resourceAttrToTfplan(ra globalref.ResourceAttr) (*planproto.PlanResourceAttr, error) {
+	res := &planproto.PlanResourceAttr{}
+
+	res.Resource = ra.Resource.String()
+	attr, err := pathToTfplan(ra.Attr)
+	if err != nil {
+		return res, err
+	}
+	res.Attr = attr
+	return res, nil
+}
+
+func resourceAttrFromTfplan(ra *planproto.PlanResourceAttr) (globalref.ResourceAttr, error) {
+	var res globalref.ResourceAttr
+	if ra.Resource == "" {
+		return res, fmt.Errorf("missing resource address from relevant attribute")
+	}
+
+	instAddr, diags := addrs.ParseAbsResourceInstanceStr(ra.Resource)
+	if diags.HasErrors() {
+		return res, fmt.Errorf("invalid resource instance address %q in relevant attributes: %w", ra.Resource, diags.Err())
+	}
+
+	res.Resource = instAddr
+	path, err := pathFromTfplan(ra.Attr)
+	if err != nil {
+		return res, fmt.Errorf("invalid path in %q relevant attribute: %s", res.Resource, err)
+	}
+
+	res.Attr = path
+	return res, nil
+}
+
+func resourceChangeToTfplan(change *plans.ResourceInstanceChangeSrc) (*planproto.ResourceInstanceChange, error) {
+	ret := &planproto.ResourceInstanceChange{}
+
+	if change.PrevRunAddr.Resource.Resource.Type == "" {
+		// Suggests that an old caller wasn't yet updated to populate this
+		// properly. All code that generates plans should populate this field,
+		// even if it's just to write in the same value as in change.Addr.
+		change.PrevRunAddr = change.Addr
+	}
+
+	ret.Addr = change.Addr.String()
+	ret.PrevRunAddr = change.PrevRunAddr.String()
+	if ret.PrevRunAddr == ret.Addr {
+		// In the on-disk format we leave PrevRunAddr unpopulated in the common
+		// case where it's the same as Addr, and then fill it back in again on
+		// read.
+		ret.PrevRunAddr = ""
+	}
+
+	ret.DeposedKey = string(change.DeposedKey)
+	ret.Provider = change.ProviderAddr.String()
+
+	requiredReplace := change.RequiredReplace.List()
+	ret.RequiredReplace = make([]*planproto.Path, 0, len(requiredReplace))
+	for _, p := range requiredReplace {
+		path, err := pathToTfplan(p)
+		if err != nil {
+			return nil, fmt.Errorf("invalid path in required replace: %s", err)
+		}
+		ret.RequiredReplace = append(ret.RequiredReplace, path)
+	}
+
+	valChange, err := changeToTfplan(&change.ChangeSrc)
+	if err != nil {
+		return nil, fmt.Errorf("failed to serialize resource %s change: %s", change.Addr, err)
+	}
+	ret.Change = valChange
+
+	switch change.ActionReason {
+	case plans.ResourceInstanceChangeNoReason:
+		ret.ActionReason = planproto.ResourceInstanceActionReason_NONE
+	case plans.ResourceInstanceReplaceBecauseCannotUpdate:
+		ret.ActionReason = planproto.ResourceInstanceActionReason_REPLACE_BECAUSE_CANNOT_UPDATE
+	case plans.ResourceInstanceReplaceBecauseTainted:
+		ret.ActionReason = planproto.ResourceInstanceActionReason_REPLACE_BECAUSE_TAINTED
+	case plans.ResourceInstanceReplaceByRequest:
+		ret.ActionReason = planproto.ResourceInstanceActionReason_REPLACE_BY_REQUEST
+	case plans.ResourceInstanceReplaceByTriggers:
+		ret.ActionReason = planproto.ResourceInstanceActionReason_REPLACE_BY_TRIGGERS
+	case plans.ResourceInstanceDeleteBecauseNoResourceConfig:
+		ret.ActionReason = planproto.ResourceInstanceActionReason_DELETE_BECAUSE_NO_RESOURCE_CONFIG
+	case plans.ResourceInstanceDeleteBecauseWrongRepetition:
+		ret.ActionReason = planproto.ResourceInstanceActionReason_DELETE_BECAUSE_WRONG_REPETITION
+	case plans.ResourceInstanceDeleteBecauseCountIndex:
+		ret.ActionReason = planproto.ResourceInstanceActionReason_DELETE_BECAUSE_COUNT_INDEX
+	case plans.ResourceInstanceDeleteBecauseEachKey:
+		ret.ActionReason = planproto.ResourceInstanceActionReason_DELETE_BECAUSE_EACH_KEY
+	case plans.ResourceInstanceDeleteBecauseNoModule:
+		ret.ActionReason = planproto.ResourceInstanceActionReason_DELETE_BECAUSE_NO_MODULE
+	case plans.ResourceInstanceReadBecauseConfigUnknown:
+		ret.ActionReason = planproto.ResourceInstanceActionReason_READ_BECAUSE_CONFIG_UNKNOWN
+	case plans.ResourceInstanceReadBecauseDependencyPending:
+		ret.ActionReason = planproto.ResourceInstanceActionReason_READ_BECAUSE_DEPENDENCY_PENDING
+	case plans.ResourceInstanceReadBecauseCheckNested:
+		ret.ActionReason = planproto.ResourceInstanceActionReason_READ_BECAUSE_CHECK_NESTED
+	case plans.ResourceInstanceDeleteBecauseNoMoveTarget:
+		ret.ActionReason = planproto.ResourceInstanceActionReason_DELETE_BECAUSE_NO_MOVE_TARGET
+	default:
+		return nil, fmt.Errorf("resource %s has unsupported action reason %s", change.Addr, change.ActionReason)
+	}
+
+	if len(change.Private) > 0 {
+		ret.Private = change.Private
+	}
+
+	return ret, nil
+}
+
+func changeToTfplan(change *plans.ChangeSrc) (*planproto.Change, error) {
+	ret := &planproto.Change{}
+
+	before := valueToTfplan(change.Before)
+	after := valueToTfplan(change.After)
+
+	beforeSensitivePaths, err := pathValueMarksToTfplan(change.BeforeValMarks)
+	if err != nil {
+		return nil, err
+	}
+	afterSensitivePaths, err := pathValueMarksToTfplan(change.AfterValMarks)
+	if err != nil {
+		return nil, err
+	}
+	ret.BeforeSensitivePaths = beforeSensitivePaths
+	ret.AfterSensitivePaths = afterSensitivePaths
+
+	if change.Importing != nil {
+		ret.Importing = &planproto.Importing{
+			Id: change.Importing.ID,
+		}
+
+	}
+	ret.GeneratedConfig = change.GeneratedConfig
+
+	switch change.Action {
+	case plans.NoOp:
+		ret.Action = planproto.Action_NOOP
+		ret.Values = []*planproto.DynamicValue{before} // before and after should be identical
+	case plans.Create:
+		ret.Action = planproto.Action_CREATE
+		ret.Values = []*planproto.DynamicValue{after}
+	case plans.Read:
+		ret.Action = planproto.Action_READ
+		ret.Values = []*planproto.DynamicValue{before, after}
+	case plans.Update:
+		ret.Action = planproto.Action_UPDATE
+		ret.Values = []*planproto.DynamicValue{before, after}
+	case plans.Delete:
+		ret.Action = planproto.Action_DELETE
+		ret.Values = []*planproto.DynamicValue{before}
+	case plans.DeleteThenCreate:
+		ret.Action = planproto.Action_DELETE_THEN_CREATE
+		ret.Values = []*planproto.DynamicValue{before, after}
+	case plans.CreateThenDelete:
+		ret.Action = planproto.Action_CREATE_THEN_DELETE
+		ret.Values = []*planproto.DynamicValue{before, after}
+	default:
+		return nil, fmt.Errorf("invalid change action %s", change.Action)
+	}
+
+	return ret, nil
+}
+
+func valueToTfplan(val plans.DynamicValue) *planproto.DynamicValue {
+	if val == nil {
+		// protobuf can't represent nil, so we'll represent it as a
+		// DynamicValue that has no serializations at all.
+		return &planproto.DynamicValue{}
+	}
+	return &planproto.DynamicValue{
+		Msgpack: []byte(val),
+	}
+}
+
+func pathValueMarksFromTfplan(paths []*planproto.Path, marks cty.ValueMarks) ([]cty.PathValueMarks, error) {
+	ret := make([]cty.PathValueMarks, 0, len(paths))
+	for _, p := range paths {
+		path, err := pathFromTfplan(p)
+		if err != nil {
+			return nil, err
+		}
+		ret = append(ret, cty.PathValueMarks{
+			Path:  path,
+			Marks: marks,
+		})
+	}
+	return ret, nil
+}
+
+func pathValueMarksToTfplan(pvm []cty.PathValueMarks) ([]*planproto.Path, error) {
+	ret := make([]*planproto.Path, 0, len(pvm))
+	for _, p := range pvm {
+		path, err := pathToTfplan(p.Path)
+		if err != nil {
+			return nil, err
+		}
+		ret = append(ret, path)
+	}
+	return ret, nil
+}
+
+func pathFromTfplan(path *planproto.Path) (cty.Path, error) {
+	ret := make([]cty.PathStep, 0, len(path.Steps))
+	for _, step := range path.Steps {
+		switch s := step.Selector.(type) {
+		case *planproto.Path_Step_ElementKey:
+			dynamicVal, err := valueFromTfplan(s.ElementKey)
+			if err != nil {
+				return nil, fmt.Errorf("error decoding path index step: %s", err)
+			}
+			ty, err := dynamicVal.ImpliedType()
+			if err != nil {
+				return nil, fmt.Errorf("error determining path index type: %s", err)
+			}
+			val, err := dynamicVal.Decode(ty)
+			if err != nil {
+				return nil, fmt.Errorf("error decoding path index value: %s", err)
+			}
+			ret = append(ret, cty.IndexStep{Key: val})
+		case *planproto.Path_Step_AttributeName:
+			ret = append(ret, cty.GetAttrStep{Name: s.AttributeName})
+		default:
+			return nil, fmt.Errorf("Unsupported path step %t", step.Selector)
+		}
+	}
+	return ret, nil
+}
+
+func pathToTfplan(path cty.Path) (*planproto.Path, error) {
+	steps := make([]*planproto.Path_Step, 0, len(path))
+	for _, step := range path {
+		switch s := step.(type) {
+		case cty.IndexStep:
+			value, err := plans.NewDynamicValue(s.Key, s.Key.Type())
+			if err != nil {
+				return nil, fmt.Errorf("Error encoding path step: %s", err)
+			}
+			steps = append(steps, &planproto.Path_Step{
+				Selector: &planproto.Path_Step_ElementKey{
+					ElementKey: valueToTfplan(value),
+				},
+			})
+		case cty.GetAttrStep:
+			steps = append(steps, &planproto.Path_Step{
+				Selector: &planproto.Path_Step_AttributeName{
+					AttributeName: s.Name,
+				},
+			})
+		default:
+			return nil, fmt.Errorf("Unsupported path step %#v (%t)", step, step)
+		}
+	}
+	return &planproto.Path{
+		Steps: steps,
+	}, nil
+}
diff --git a/v1.5.7/internal/plans/planfile/tfplan_test.go b/v1.5.7/internal/plans/planfile/tfplan_test.go
new file mode 100644
index 0000000..2374fbe
--- /dev/null
+++ b/v1.5.7/internal/plans/planfile/tfplan_test.go
@@ -0,0 +1,420 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package planfile
+
+import (
+	"bytes"
+	"testing"
+
+	"github.com/go-test/deep"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/lang/globalref"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestTFPlanRoundTrip(t *testing.T) {
+	objTy := cty.Object(map[string]cty.Type{
+		"id": cty.String,
+	})
+
+	plan := &plans.Plan{
+		VariableValues: map[string]plans.DynamicValue{
+			"foo": mustNewDynamicValueStr("foo value"),
+		},
+		Changes: &plans.Changes{
+			Outputs: []*plans.OutputChangeSrc{
+				{
+					Addr: addrs.OutputValue{Name: "bar"}.Absolute(addrs.RootModuleInstance),
+					ChangeSrc: plans.ChangeSrc{
+						Action: plans.Create,
+						After:  mustDynamicOutputValue("bar value"),
+					},
+					Sensitive: false,
+				},
+				{
+					Addr: addrs.OutputValue{Name: "baz"}.Absolute(addrs.RootModuleInstance),
+					ChangeSrc: plans.ChangeSrc{
+						Action: plans.NoOp,
+						Before: mustDynamicOutputValue("baz value"),
+						After:  mustDynamicOutputValue("baz value"),
+					},
+					Sensitive: false,
+				},
+				{
+					Addr: addrs.OutputValue{Name: "secret"}.Absolute(addrs.RootModuleInstance),
+					ChangeSrc: plans.ChangeSrc{
+						Action: plans.Update,
+						Before: mustDynamicOutputValue("old secret value"),
+						After:  mustDynamicOutputValue("new secret value"),
+					},
+					Sensitive: true,
+				},
+			},
+			Resources: []*plans.ResourceInstanceChangeSrc{
+				{
+					Addr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_thing",
+						Name: "woot",
+					}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+					PrevRunAddr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_thing",
+						Name: "woot",
+					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+					ProviderAddr: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("test"),
+						Module:   addrs.RootModule,
+					},
+					ChangeSrc: plans.ChangeSrc{
+						Action: plans.DeleteThenCreate,
+						Before: mustNewDynamicValue(cty.ObjectVal(map[string]cty.Value{
+							"id": cty.StringVal("foo-bar-baz"),
+							"boop": cty.ListVal([]cty.Value{
+								cty.StringVal("beep"),
+							}),
+						}), objTy),
+						After: mustNewDynamicValue(cty.ObjectVal(map[string]cty.Value{
+							"id": cty.UnknownVal(cty.String),
+							"boop": cty.ListVal([]cty.Value{
+								cty.StringVal("beep"),
+								cty.StringVal("honk"),
+							}),
+						}), objTy),
+						AfterValMarks: []cty.PathValueMarks{
+							{
+								Path:  cty.GetAttrPath("boop").IndexInt(1),
+								Marks: cty.NewValueMarks(marks.Sensitive),
+							},
+						},
+					},
+					RequiredReplace: cty.NewPathSet(
+						cty.GetAttrPath("boop"),
+					),
+					ActionReason: plans.ResourceInstanceReplaceBecauseCannotUpdate,
+				},
+				{
+					Addr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_thing",
+						Name: "woot",
+					}.Instance(addrs.IntKey(1)).Absolute(addrs.RootModuleInstance),
+					PrevRunAddr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_thing",
+						Name: "woot",
+					}.Instance(addrs.IntKey(1)).Absolute(addrs.RootModuleInstance),
+					DeposedKey: "foodface",
+					ProviderAddr: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("test"),
+						Module:   addrs.RootModule,
+					},
+					ChangeSrc: plans.ChangeSrc{
+						Action: plans.Delete,
+						Before: mustNewDynamicValue(cty.ObjectVal(map[string]cty.Value{
+							"id": cty.StringVal("bar-baz-foo"),
+						}), objTy),
+					},
+				},
+				{
+					Addr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_thing",
+						Name: "importing",
+					}.Instance(addrs.IntKey(1)).Absolute(addrs.RootModuleInstance),
+					PrevRunAddr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_thing",
+						Name: "importing",
+					}.Instance(addrs.IntKey(1)).Absolute(addrs.RootModuleInstance),
+					ProviderAddr: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("test"),
+						Module:   addrs.RootModule,
+					},
+					ChangeSrc: plans.ChangeSrc{
+						Action: plans.NoOp,
+						Before: mustNewDynamicValue(cty.ObjectVal(map[string]cty.Value{
+							"id": cty.StringVal("testing"),
+						}), objTy),
+						After: mustNewDynamicValue(cty.ObjectVal(map[string]cty.Value{
+							"id": cty.StringVal("testing"),
+						}), objTy),
+						Importing:       &plans.ImportingSrc{ID: "testing"},
+						GeneratedConfig: "resource \\\"test_thing\\\" \\\"importing\\\" {}",
+					},
+				},
+			},
+		},
+		DriftedResources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: addrs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "test_thing",
+					Name: "woot",
+				}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+				PrevRunAddr: addrs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "test_thing",
+					Name: "woot",
+				}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+				ProviderAddr: addrs.AbsProviderConfig{
+					Provider: addrs.NewDefaultProvider("test"),
+					Module:   addrs.RootModule,
+				},
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.DeleteThenCreate,
+					Before: mustNewDynamicValue(cty.ObjectVal(map[string]cty.Value{
+						"id": cty.StringVal("foo-bar-baz"),
+						"boop": cty.ListVal([]cty.Value{
+							cty.StringVal("beep"),
+						}),
+					}), objTy),
+					After: mustNewDynamicValue(cty.ObjectVal(map[string]cty.Value{
+						"id": cty.UnknownVal(cty.String),
+						"boop": cty.ListVal([]cty.Value{
+							cty.StringVal("beep"),
+							cty.StringVal("bonk"),
+						}),
+					}), objTy),
+					AfterValMarks: []cty.PathValueMarks{
+						{
+							Path:  cty.GetAttrPath("boop").IndexInt(1),
+							Marks: cty.NewValueMarks(marks.Sensitive),
+						},
+					},
+				},
+			},
+		},
+		RelevantAttributes: []globalref.ResourceAttr{
+			{
+				Resource: addrs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "test_thing",
+					Name: "woot",
+				}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+				Attr: cty.GetAttrPath("boop").Index(cty.NumberIntVal(1)),
+			},
+		},
+		Checks: &states.CheckResults{
+			ConfigResults: addrs.MakeMap(
+				addrs.MakeMapElem[addrs.ConfigCheckable](
+					addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_thing",
+						Name: "woot",
+					}.InModule(addrs.RootModule),
+					&states.CheckResultAggregate{
+						Status: checks.StatusFail,
+						ObjectResults: addrs.MakeMap(
+							addrs.MakeMapElem[addrs.Checkable](
+								addrs.Resource{
+									Mode: addrs.ManagedResourceMode,
+									Type: "test_thing",
+									Name: "woot",
+								}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+								&states.CheckResultObject{
+									Status:          checks.StatusFail,
+									FailureMessages: []string{"Oh no!"},
+								},
+							),
+						),
+					},
+				),
+				addrs.MakeMapElem[addrs.ConfigCheckable](
+					addrs.Check{
+						Name: "check",
+					}.InModule(addrs.RootModule),
+					&states.CheckResultAggregate{
+						Status: checks.StatusFail,
+						ObjectResults: addrs.MakeMap(
+							addrs.MakeMapElem[addrs.Checkable](
+								addrs.Check{
+									Name: "check",
+								}.Absolute(addrs.RootModuleInstance),
+								&states.CheckResultObject{
+									Status:          checks.StatusFail,
+									FailureMessages: []string{"check failed"},
+								},
+							),
+						),
+					},
+				),
+			),
+		},
+		TargetAddrs: []addrs.Targetable{
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_thing",
+				Name: "woot",
+			}.Absolute(addrs.RootModuleInstance),
+		},
+		Backend: plans.Backend{
+			Type: "local",
+			Config: mustNewDynamicValue(
+				cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("bar"),
+				}),
+				cty.Object(map[string]cty.Type{
+					"foo": cty.String,
+				}),
+			),
+			Workspace: "default",
+		},
+	}
+
+	var buf bytes.Buffer
+	err := writeTfplan(plan, &buf)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	newPlan, err := readTfplan(&buf)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	{
+		oldDepth := deep.MaxDepth
+		oldCompare := deep.CompareUnexportedFields
+		deep.MaxDepth = 20
+		deep.CompareUnexportedFields = true
+		defer func() {
+			deep.MaxDepth = oldDepth
+			deep.CompareUnexportedFields = oldCompare
+		}()
+	}
+	for _, problem := range deep.Equal(newPlan, plan) {
+		t.Error(problem)
+	}
+}
+
+func mustDynamicOutputValue(val string) plans.DynamicValue {
+	ret, err := plans.NewDynamicValue(cty.StringVal(val), cty.DynamicPseudoType)
+	if err != nil {
+		panic(err)
+	}
+	return ret
+}
+
+func mustNewDynamicValue(val cty.Value, ty cty.Type) plans.DynamicValue {
+	ret, err := plans.NewDynamicValue(val, ty)
+	if err != nil {
+		panic(err)
+	}
+	return ret
+}
+
+func mustNewDynamicValueStr(val string) plans.DynamicValue {
+	realVal := cty.StringVal(val)
+	ret, err := plans.NewDynamicValue(realVal, cty.String)
+	if err != nil {
+		panic(err)
+	}
+	return ret
+}
+
+// TestTFPlanRoundTripDestroy ensures that encoding and decoding null values for
+// destroy doesn't leave us with any nil values.
+func TestTFPlanRoundTripDestroy(t *testing.T) {
+	objTy := cty.Object(map[string]cty.Type{
+		"id": cty.String,
+	})
+
+	plan := &plans.Plan{
+		Changes: &plans.Changes{
+			Outputs: []*plans.OutputChangeSrc{
+				{
+					Addr: addrs.OutputValue{Name: "bar"}.Absolute(addrs.RootModuleInstance),
+					ChangeSrc: plans.ChangeSrc{
+						Action: plans.Delete,
+						Before: mustDynamicOutputValue("output"),
+						After:  mustNewDynamicValue(cty.NullVal(cty.String), cty.String),
+					},
+				},
+			},
+			Resources: []*plans.ResourceInstanceChangeSrc{
+				{
+					Addr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_thing",
+						Name: "woot",
+					}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+					PrevRunAddr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_thing",
+						Name: "woot",
+					}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+					ProviderAddr: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("test"),
+						Module:   addrs.RootModule,
+					},
+					ChangeSrc: plans.ChangeSrc{
+						Action: plans.Delete,
+						Before: mustNewDynamicValue(cty.ObjectVal(map[string]cty.Value{
+							"id": cty.StringVal("foo-bar-baz"),
+						}), objTy),
+						After: mustNewDynamicValue(cty.NullVal(objTy), objTy),
+					},
+				},
+			},
+		},
+		DriftedResources: []*plans.ResourceInstanceChangeSrc{},
+		TargetAddrs: []addrs.Targetable{
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_thing",
+				Name: "woot",
+			}.Absolute(addrs.RootModuleInstance),
+		},
+		Backend: plans.Backend{
+			Type: "local",
+			Config: mustNewDynamicValue(
+				cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("bar"),
+				}),
+				cty.Object(map[string]cty.Type{
+					"foo": cty.String,
+				}),
+			),
+			Workspace: "default",
+		},
+	}
+
+	var buf bytes.Buffer
+	err := writeTfplan(plan, &buf)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	newPlan, err := readTfplan(&buf)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, rics := range newPlan.Changes.Resources {
+		ric, err := rics.Decode(objTy)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if ric.After == cty.NilVal {
+			t.Fatalf("unexpected nil After value: %#v\n", ric)
+		}
+	}
+	for _, ocs := range newPlan.Changes.Outputs {
+		oc, err := ocs.Decode()
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if oc.After == cty.NilVal {
+			t.Fatalf("unexpected nil After value: %#v\n", ocs)
+		}
+	}
+}
diff --git a/v1.5.7/internal/plans/planfile/writer.go b/v1.5.7/internal/plans/planfile/writer.go
new file mode 100644
index 0000000..8780974
--- /dev/null
+++ b/v1.5.7/internal/plans/planfile/writer.go
@@ -0,0 +1,142 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package planfile
+
+import (
+	"archive/zip"
+	"fmt"
+	"os"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+)
+
+type CreateArgs struct {
+	// ConfigSnapshot is a snapshot of the configuration that the plan
+	// was created from.
+	ConfigSnapshot *configload.Snapshot
+
+	// PreviousRunStateFile is a representation of the state snapshot we used
+	// as the original input when creating this plan, containing the same
+	// information as recorded at the end of the previous apply except for
+	// upgrading managed resource instance data to the provider's latest
+	// schema versions.
+	PreviousRunStateFile *statefile.File
+
+	// BaseStateFile is a representation of the state snapshot we used to
+	// create the plan, which is the result of asking the providers to refresh
+	// all previously-stored objects to match the current situation in the
+	// remote system. (If this plan was created with refreshing disabled,
+	// this should be the same as PreviousRunStateFile.)
+	StateFile *statefile.File
+
+	// Plan records the plan itself, which is the main artifact inside a
+	// saved plan file.
+	Plan *plans.Plan
+
+	// DependencyLocks records the dependency lock information that we
+	// checked prior to creating the plan, so we can make sure that all of the
+	// same dependencies are still available when applying the plan.
+	DependencyLocks *depsfile.Locks
+}
+
+// Create creates a new plan file with the given filename, overwriting any
+// file that might already exist there.
+//
+// A plan file contains both a snapshot of the configuration and of the latest
+// state file in addition to the plan itself, so that Terraform can detect
+// if the world has changed since the plan was created and thus refuse to
+// apply it.
+func Create(filename string, args CreateArgs) error {
+	f, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	zw := zip.NewWriter(f)
+	defer zw.Close()
+
+	// tfplan file
+	{
+		w, err := zw.CreateHeader(&zip.FileHeader{
+			Name:     tfplanFilename,
+			Method:   zip.Deflate,
+			Modified: time.Now(),
+		})
+		if err != nil {
+			return fmt.Errorf("failed to create tfplan file: %s", err)
+		}
+		err = writeTfplan(args.Plan, w)
+		if err != nil {
+			return fmt.Errorf("failed to write plan: %s", err)
+		}
+	}
+
+	// tfstate file
+	{
+		w, err := zw.CreateHeader(&zip.FileHeader{
+			Name:     tfstateFilename,
+			Method:   zip.Deflate,
+			Modified: time.Now(),
+		})
+		if err != nil {
+			return fmt.Errorf("failed to create embedded tfstate file: %s", err)
+		}
+		err = statefile.Write(args.StateFile, w)
+		if err != nil {
+			return fmt.Errorf("failed to write state snapshot: %s", err)
+		}
+	}
+
+	// tfstate-prev file
+	{
+		w, err := zw.CreateHeader(&zip.FileHeader{
+			Name:     tfstatePreviousFilename,
+			Method:   zip.Deflate,
+			Modified: time.Now(),
+		})
+		if err != nil {
+			return fmt.Errorf("failed to create embedded tfstate-prev file: %s", err)
+		}
+		err = statefile.Write(args.PreviousRunStateFile, w)
+		if err != nil {
+			return fmt.Errorf("failed to write previous state snapshot: %s", err)
+		}
+	}
+
+	// tfconfig directory
+	{
+		err := writeConfigSnapshot(args.ConfigSnapshot, zw)
+		if err != nil {
+			return fmt.Errorf("failed to write config snapshot: %s", err)
+		}
+	}
+
+	// .terraform.lock.hcl file, containing dependency lock information
+	if args.DependencyLocks != nil { // (this was a later addition, so not all callers set it, but main callers should)
+		src, diags := depsfile.SaveLocksToBytes(args.DependencyLocks)
+		if diags.HasErrors() {
+			return fmt.Errorf("failed to write embedded dependency lock file: %s", diags.Err().Error())
+		}
+
+		w, err := zw.CreateHeader(&zip.FileHeader{
+			Name:     dependencyLocksFilename,
+			Method:   zip.Deflate,
+			Modified: time.Now(),
+		})
+		if err != nil {
+			return fmt.Errorf("failed to create embedded dependency lock file: %s", err)
+		}
+		_, err = w.Write(src)
+		if err != nil {
+			return fmt.Errorf("failed to write embedded dependency lock file: %s", err)
+		}
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/plans/resourceinstancechangeactionreason_string.go b/v1.5.7/internal/plans/resourceinstancechangeactionreason_string.go
new file mode 100644
index 0000000..9915ec8
--- /dev/null
+++ b/v1.5.7/internal/plans/resourceinstancechangeactionreason_string.go
@@ -0,0 +1,72 @@
+// Code generated by "stringer -type=ResourceInstanceChangeActionReason changes.go"; DO NOT EDIT.
+
+package plans
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[ResourceInstanceChangeNoReason-0]
+	_ = x[ResourceInstanceReplaceBecauseTainted-84]
+	_ = x[ResourceInstanceReplaceByRequest-82]
+	_ = x[ResourceInstanceReplaceByTriggers-68]
+	_ = x[ResourceInstanceReplaceBecauseCannotUpdate-70]
+	_ = x[ResourceInstanceDeleteBecauseNoResourceConfig-78]
+	_ = x[ResourceInstanceDeleteBecauseWrongRepetition-87]
+	_ = x[ResourceInstanceDeleteBecauseCountIndex-67]
+	_ = x[ResourceInstanceDeleteBecauseEachKey-69]
+	_ = x[ResourceInstanceDeleteBecauseNoModule-77]
+	_ = x[ResourceInstanceDeleteBecauseNoMoveTarget-65]
+	_ = x[ResourceInstanceReadBecauseConfigUnknown-63]
+	_ = x[ResourceInstanceReadBecauseDependencyPending-33]
+	_ = x[ResourceInstanceReadBecauseCheckNested-35]
+}
+
+const (
+	_ResourceInstanceChangeActionReason_name_0 = "ResourceInstanceChangeNoReason"
+	_ResourceInstanceChangeActionReason_name_1 = "ResourceInstanceReadBecauseDependencyPending"
+	_ResourceInstanceChangeActionReason_name_2 = "ResourceInstanceReadBecauseCheckNested"
+	_ResourceInstanceChangeActionReason_name_3 = "ResourceInstanceReadBecauseConfigUnknown"
+	_ResourceInstanceChangeActionReason_name_4 = "ResourceInstanceDeleteBecauseNoMoveTarget"
+	_ResourceInstanceChangeActionReason_name_5 = "ResourceInstanceDeleteBecauseCountIndexResourceInstanceReplaceByTriggersResourceInstanceDeleteBecauseEachKeyResourceInstanceReplaceBecauseCannotUpdate"
+	_ResourceInstanceChangeActionReason_name_6 = "ResourceInstanceDeleteBecauseNoModuleResourceInstanceDeleteBecauseNoResourceConfig"
+	_ResourceInstanceChangeActionReason_name_7 = "ResourceInstanceReplaceByRequest"
+	_ResourceInstanceChangeActionReason_name_8 = "ResourceInstanceReplaceBecauseTainted"
+	_ResourceInstanceChangeActionReason_name_9 = "ResourceInstanceDeleteBecauseWrongRepetition"
+)
+
+var (
+	_ResourceInstanceChangeActionReason_index_5 = [...]uint8{0, 39, 72, 108, 150}
+	_ResourceInstanceChangeActionReason_index_6 = [...]uint8{0, 37, 82}
+)
+
+func (i ResourceInstanceChangeActionReason) String() string {
+	switch {
+	case i == 0:
+		return _ResourceInstanceChangeActionReason_name_0
+	case i == 33:
+		return _ResourceInstanceChangeActionReason_name_1
+	case i == 35:
+		return _ResourceInstanceChangeActionReason_name_2
+	case i == 63:
+		return _ResourceInstanceChangeActionReason_name_3
+	case i == 65:
+		return _ResourceInstanceChangeActionReason_name_4
+	case 67 <= i && i <= 70:
+		i -= 67
+		return _ResourceInstanceChangeActionReason_name_5[_ResourceInstanceChangeActionReason_index_5[i]:_ResourceInstanceChangeActionReason_index_5[i+1]]
+	case 77 <= i && i <= 78:
+		i -= 77
+		return _ResourceInstanceChangeActionReason_name_6[_ResourceInstanceChangeActionReason_index_6[i]:_ResourceInstanceChangeActionReason_index_6[i+1]]
+	case i == 82:
+		return _ResourceInstanceChangeActionReason_name_7
+	case i == 84:
+		return _ResourceInstanceChangeActionReason_name_8
+	case i == 87:
+		return _ResourceInstanceChangeActionReason_name_9
+	default:
+		return "ResourceInstanceChangeActionReason(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/v1.5.7/internal/plugin/convert/diagnostics.go b/v1.5.7/internal/plugin/convert/diagnostics.go
new file mode 100644
index 0000000..7b1cd69
--- /dev/null
+++ b/v1.5.7/internal/plugin/convert/diagnostics.go
@@ -0,0 +1,135 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package convert
+
+import (
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	proto "github.com/hashicorp/terraform/internal/tfplugin5"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// WarnsAndErrorsToProto converts the warnings and errors return by the legacy
+// provider to protobuf diagnostics.
+func WarnsAndErrsToProto(warns []string, errs []error) (diags []*proto.Diagnostic) {
+	for _, w := range warns {
+		diags = AppendProtoDiag(diags, w)
+	}
+
+	for _, e := range errs {
+		diags = AppendProtoDiag(diags, e)
+	}
+
+	return diags
+}
+
+// AppendProtoDiag appends a new diagnostic from a warning string or an error.
+// This panics if d is not a string or error.
+func AppendProtoDiag(diags []*proto.Diagnostic, d interface{}) []*proto.Diagnostic {
+	switch d := d.(type) {
+	case cty.PathError:
+		ap := PathToAttributePath(d.Path)
+		diags = append(diags, &proto.Diagnostic{
+			Severity:  proto.Diagnostic_ERROR,
+			Summary:   d.Error(),
+			Attribute: ap,
+		})
+	case error:
+		diags = append(diags, &proto.Diagnostic{
+			Severity: proto.Diagnostic_ERROR,
+			Summary:  d.Error(),
+		})
+	case string:
+		diags = append(diags, &proto.Diagnostic{
+			Severity: proto.Diagnostic_WARNING,
+			Summary:  d,
+		})
+	case *proto.Diagnostic:
+		diags = append(diags, d)
+	case []*proto.Diagnostic:
+		diags = append(diags, d...)
+	}
+	return diags
+}
+
+// ProtoToDiagnostics converts a list of proto.Diagnostics to a tf.Diagnostics.
+func ProtoToDiagnostics(ds []*proto.Diagnostic) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+	for _, d := range ds {
+		var severity tfdiags.Severity
+
+		switch d.Severity {
+		case proto.Diagnostic_ERROR:
+			severity = tfdiags.Error
+		case proto.Diagnostic_WARNING:
+			severity = tfdiags.Warning
+		}
+
+		var newDiag tfdiags.Diagnostic
+
+		// if there's an attribute path, we need to create a AttributeValue diagnostic
+		if d.Attribute != nil && len(d.Attribute.Steps) > 0 {
+			path := AttributePathToPath(d.Attribute)
+			newDiag = tfdiags.AttributeValue(severity, d.Summary, d.Detail, path)
+		} else {
+			newDiag = tfdiags.WholeContainingBody(severity, d.Summary, d.Detail)
+		}
+
+		diags = diags.Append(newDiag)
+	}
+
+	return diags
+}
+
+// AttributePathToPath takes the proto encoded path and converts it to a cty.Path
+func AttributePathToPath(ap *proto.AttributePath) cty.Path {
+	var p cty.Path
+	for _, step := range ap.Steps {
+		switch selector := step.Selector.(type) {
+		case *proto.AttributePath_Step_AttributeName:
+			p = p.GetAttr(selector.AttributeName)
+		case *proto.AttributePath_Step_ElementKeyString:
+			p = p.Index(cty.StringVal(selector.ElementKeyString))
+		case *proto.AttributePath_Step_ElementKeyInt:
+			p = p.Index(cty.NumberIntVal(selector.ElementKeyInt))
+		}
+	}
+	return p
+}
+
+// AttributePathToPath takes a cty.Path and converts it to a proto-encoded path.
+func PathToAttributePath(p cty.Path) *proto.AttributePath {
+	ap := &proto.AttributePath{}
+	for _, step := range p {
+		switch selector := step.(type) {
+		case cty.GetAttrStep:
+			ap.Steps = append(ap.Steps, &proto.AttributePath_Step{
+				Selector: &proto.AttributePath_Step_AttributeName{
+					AttributeName: selector.Name,
+				},
+			})
+		case cty.IndexStep:
+			key := selector.Key
+			switch key.Type() {
+			case cty.String:
+				ap.Steps = append(ap.Steps, &proto.AttributePath_Step{
+					Selector: &proto.AttributePath_Step_ElementKeyString{
+						ElementKeyString: key.AsString(),
+					},
+				})
+			case cty.Number:
+				v, _ := key.AsBigFloat().Int64()
+				ap.Steps = append(ap.Steps, &proto.AttributePath_Step{
+					Selector: &proto.AttributePath_Step_ElementKeyInt{
+						ElementKeyInt: v,
+					},
+				})
+			default:
+				// We'll bail early if we encounter anything else, and just
+				// return the valid prefix.
+				return ap
+			}
+		}
+	}
+	return ap
+}
diff --git a/v1.5.7/internal/plugin/convert/diagnostics_test.go b/v1.5.7/internal/plugin/convert/diagnostics_test.go
new file mode 100644
index 0000000..f6601bb
--- /dev/null
+++ b/v1.5.7/internal/plugin/convert/diagnostics_test.go
@@ -0,0 +1,414 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package convert
+
+import (
+	"errors"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	proto "github.com/hashicorp/terraform/internal/tfplugin5"
+	"github.com/zclconf/go-cty/cty"
+)
+
+var ignoreUnexported = cmpopts.IgnoreUnexported(
+	proto.Diagnostic{},
+	proto.Schema_Block{},
+	proto.Schema_NestedBlock{},
+	proto.Schema_Attribute{},
+)
+
+func TestProtoDiagnostics(t *testing.T) {
+	diags := WarnsAndErrsToProto(
+		[]string{
+			"warning 1",
+			"warning 2",
+		},
+		[]error{
+			errors.New("error 1"),
+			errors.New("error 2"),
+		},
+	)
+
+	expected := []*proto.Diagnostic{
+		{
+			Severity: proto.Diagnostic_WARNING,
+			Summary:  "warning 1",
+		},
+		{
+			Severity: proto.Diagnostic_WARNING,
+			Summary:  "warning 2",
+		},
+		{
+			Severity: proto.Diagnostic_ERROR,
+			Summary:  "error 1",
+		},
+		{
+			Severity: proto.Diagnostic_ERROR,
+			Summary:  "error 2",
+		},
+	}
+
+	if !cmp.Equal(expected, diags, ignoreUnexported) {
+		t.Fatal(cmp.Diff(expected, diags, ignoreUnexported))
+	}
+}
+
+func TestDiagnostics(t *testing.T) {
+	type diagFlat struct {
+		Severity tfdiags.Severity
+		Attr     []interface{}
+		Summary  string
+		Detail   string
+	}
+
+	tests := map[string]struct {
+		Cons func([]*proto.Diagnostic) []*proto.Diagnostic
+		Want []diagFlat
+	}{
+		"nil": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				return diags
+			},
+			nil,
+		},
+		"error": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				return append(diags, &proto.Diagnostic{
+					Severity: proto.Diagnostic_ERROR,
+					Summary:  "simple error",
+				})
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Error,
+					Summary:  "simple error",
+				},
+			},
+		},
+		"detailed error": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				return append(diags, &proto.Diagnostic{
+					Severity: proto.Diagnostic_ERROR,
+					Summary:  "simple error",
+					Detail:   "detailed error",
+				})
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Error,
+					Summary:  "simple error",
+					Detail:   "detailed error",
+				},
+			},
+		},
+		"warning": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				return append(diags, &proto.Diagnostic{
+					Severity: proto.Diagnostic_WARNING,
+					Summary:  "simple warning",
+				})
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Warning,
+					Summary:  "simple warning",
+				},
+			},
+		},
+		"detailed warning": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				return append(diags, &proto.Diagnostic{
+					Severity: proto.Diagnostic_WARNING,
+					Summary:  "simple warning",
+					Detail:   "detailed warning",
+				})
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Warning,
+					Summary:  "simple warning",
+					Detail:   "detailed warning",
+				},
+			},
+		},
+		"multi error": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				diags = append(diags, &proto.Diagnostic{
+					Severity: proto.Diagnostic_ERROR,
+					Summary:  "first error",
+				}, &proto.Diagnostic{
+					Severity: proto.Diagnostic_ERROR,
+					Summary:  "second error",
+				})
+				return diags
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Error,
+					Summary:  "first error",
+				},
+				{
+					Severity: tfdiags.Error,
+					Summary:  "second error",
+				},
+			},
+		},
+		"warning and error": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				diags = append(diags, &proto.Diagnostic{
+					Severity: proto.Diagnostic_WARNING,
+					Summary:  "warning",
+				}, &proto.Diagnostic{
+					Severity: proto.Diagnostic_ERROR,
+					Summary:  "error",
+				})
+				return diags
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Warning,
+					Summary:  "warning",
+				},
+				{
+					Severity: tfdiags.Error,
+					Summary:  "error",
+				},
+			},
+		},
+		"attr error": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				diags = append(diags, &proto.Diagnostic{
+					Severity: proto.Diagnostic_ERROR,
+					Summary:  "error",
+					Detail:   "error detail",
+					Attribute: &proto.AttributePath{
+						Steps: []*proto.AttributePath_Step{
+							{
+								Selector: &proto.AttributePath_Step_AttributeName{
+									AttributeName: "attribute_name",
+								},
+							},
+						},
+					},
+				})
+				return diags
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Error,
+					Summary:  "error",
+					Detail:   "error detail",
+					Attr:     []interface{}{"attribute_name"},
+				},
+			},
+		},
+		"multi attr": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				diags = append(diags,
+					&proto.Diagnostic{
+						Severity: proto.Diagnostic_ERROR,
+						Summary:  "error 1",
+						Detail:   "error 1 detail",
+						Attribute: &proto.AttributePath{
+							Steps: []*proto.AttributePath_Step{
+								{
+									Selector: &proto.AttributePath_Step_AttributeName{
+										AttributeName: "attr",
+									},
+								},
+							},
+						},
+					},
+					&proto.Diagnostic{
+						Severity: proto.Diagnostic_ERROR,
+						Summary:  "error 2",
+						Detail:   "error 2 detail",
+						Attribute: &proto.AttributePath{
+							Steps: []*proto.AttributePath_Step{
+								{
+									Selector: &proto.AttributePath_Step_AttributeName{
+										AttributeName: "attr",
+									},
+								},
+								{
+									Selector: &proto.AttributePath_Step_AttributeName{
+										AttributeName: "sub",
+									},
+								},
+							},
+						},
+					},
+					&proto.Diagnostic{
+						Severity: proto.Diagnostic_WARNING,
+						Summary:  "warning",
+						Detail:   "warning detail",
+						Attribute: &proto.AttributePath{
+							Steps: []*proto.AttributePath_Step{
+								{
+									Selector: &proto.AttributePath_Step_AttributeName{
+										AttributeName: "attr",
+									},
+								},
+								{
+									Selector: &proto.AttributePath_Step_ElementKeyInt{
+										ElementKeyInt: 1,
+									},
+								},
+								{
+									Selector: &proto.AttributePath_Step_AttributeName{
+										AttributeName: "sub",
+									},
+								},
+							},
+						},
+					},
+					&proto.Diagnostic{
+						Severity: proto.Diagnostic_ERROR,
+						Summary:  "error 3",
+						Detail:   "error 3 detail",
+						Attribute: &proto.AttributePath{
+							Steps: []*proto.AttributePath_Step{
+								{
+									Selector: &proto.AttributePath_Step_AttributeName{
+										AttributeName: "attr",
+									},
+								},
+								{
+									Selector: &proto.AttributePath_Step_ElementKeyString{
+										ElementKeyString: "idx",
+									},
+								},
+								{
+									Selector: &proto.AttributePath_Step_AttributeName{
+										AttributeName: "sub",
+									},
+								},
+							},
+						},
+					},
+				)
+
+				return diags
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Error,
+					Summary:  "error 1",
+					Detail:   "error 1 detail",
+					Attr:     []interface{}{"attr"},
+				},
+				{
+					Severity: tfdiags.Error,
+					Summary:  "error 2",
+					Detail:   "error 2 detail",
+					Attr:     []interface{}{"attr", "sub"},
+				},
+				{
+					Severity: tfdiags.Warning,
+					Summary:  "warning",
+					Detail:   "warning detail",
+					Attr:     []interface{}{"attr", 1, "sub"},
+				},
+				{
+					Severity: tfdiags.Error,
+					Summary:  "error 3",
+					Detail:   "error 3 detail",
+					Attr:     []interface{}{"attr", "idx", "sub"},
+				},
+			},
+		},
+	}
+
+	flattenTFDiags := func(ds tfdiags.Diagnostics) []diagFlat {
+		var flat []diagFlat
+		for _, item := range ds {
+			desc := item.Description()
+
+			var attr []interface{}
+
+			for _, a := range tfdiags.GetAttribute(item) {
+				switch step := a.(type) {
+				case cty.GetAttrStep:
+					attr = append(attr, step.Name)
+				case cty.IndexStep:
+					switch step.Key.Type() {
+					case cty.Number:
+						i, _ := step.Key.AsBigFloat().Int64()
+						attr = append(attr, int(i))
+					case cty.String:
+						attr = append(attr, step.Key.AsString())
+					}
+				}
+			}
+
+			flat = append(flat, diagFlat{
+				Severity: item.Severity(),
+				Attr:     attr,
+				Summary:  desc.Summary,
+				Detail:   desc.Detail,
+			})
+		}
+		return flat
+	}
+
+	for name, tc := range tests {
+		t.Run(name, func(t *testing.T) {
+			// we take the
+			tfDiags := ProtoToDiagnostics(tc.Cons(nil))
+
+			flat := flattenTFDiags(tfDiags)
+
+			if !cmp.Equal(flat, tc.Want, typeComparer, valueComparer, equateEmpty) {
+				t.Fatal(cmp.Diff(flat, tc.Want, typeComparer, valueComparer, equateEmpty))
+			}
+		})
+	}
+}
+
+// Test that a diagnostic with a present but empty attribute results in a
+// whole body diagnostic. We verify this by inspecting the resulting Subject
+// from the diagnostic when considered in the context of a config body.
+func TestProtoDiagnostics_emptyAttributePath(t *testing.T) {
+	protoDiags := []*proto.Diagnostic{
+		{
+			Severity: proto.Diagnostic_ERROR,
+			Summary:  "error 1",
+			Detail:   "error 1 detail",
+			Attribute: &proto.AttributePath{
+				Steps: []*proto.AttributePath_Step{
+					// this slice is intentionally left empty
+				},
+			},
+		},
+	}
+	tfDiags := ProtoToDiagnostics(protoDiags)
+
+	testConfig := `provider "test" {
+  foo = "bar"
+}`
+	f, parseDiags := hclsyntax.ParseConfig([]byte(testConfig), "test.tf", hcl.Pos{Line: 1, Column: 1})
+	if parseDiags.HasErrors() {
+		t.Fatal(parseDiags)
+	}
+	diags := tfDiags.InConfigBody(f.Body, "")
+
+	if len(tfDiags) != 1 {
+		t.Fatalf("expected 1 diag, got %d", len(tfDiags))
+	}
+	got := diags[0].Source().Subject
+	want := &tfdiags.SourceRange{
+		Filename: "test.tf",
+		Start:    tfdiags.SourcePos{Line: 1, Column: 1},
+		End:      tfdiags.SourcePos{Line: 1, Column: 1},
+	}
+
+	if !cmp.Equal(got, want, typeComparer, valueComparer) {
+		t.Fatal(cmp.Diff(got, want, typeComparer, valueComparer))
+	}
+}
diff --git a/v1.5.7/internal/plugin/convert/schema.go b/v1.5.7/internal/plugin/convert/schema.go
new file mode 100644
index 0000000..137c6a9
--- /dev/null
+++ b/v1.5.7/internal/plugin/convert/schema.go
@@ -0,0 +1,188 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package convert
+
+import (
+	"encoding/json"
+	"reflect"
+	"sort"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	proto "github.com/hashicorp/terraform/internal/tfplugin5"
+)
+
+// ConfigSchemaToProto takes a *configschema.Block and converts it to a
+// proto.Schema_Block for a grpc response.
+func ConfigSchemaToProto(b *configschema.Block) *proto.Schema_Block {
+	block := &proto.Schema_Block{
+		Description:     b.Description,
+		DescriptionKind: protoStringKind(b.DescriptionKind),
+		Deprecated:      b.Deprecated,
+	}
+
+	for _, name := range sortedKeys(b.Attributes) {
+		a := b.Attributes[name]
+
+		attr := &proto.Schema_Attribute{
+			Name:            name,
+			Description:     a.Description,
+			DescriptionKind: protoStringKind(a.DescriptionKind),
+			Optional:        a.Optional,
+			Computed:        a.Computed,
+			Required:        a.Required,
+			Sensitive:       a.Sensitive,
+			Deprecated:      a.Deprecated,
+		}
+
+		ty, err := json.Marshal(a.Type)
+		if err != nil {
+			panic(err)
+		}
+
+		attr.Type = ty
+
+		block.Attributes = append(block.Attributes, attr)
+	}
+
+	for _, name := range sortedKeys(b.BlockTypes) {
+		b := b.BlockTypes[name]
+		block.BlockTypes = append(block.BlockTypes, protoSchemaNestedBlock(name, b))
+	}
+
+	return block
+}
+
+func protoStringKind(k configschema.StringKind) proto.StringKind {
+	switch k {
+	default:
+		return proto.StringKind_PLAIN
+	case configschema.StringMarkdown:
+		return proto.StringKind_MARKDOWN
+	}
+}
+
+func protoSchemaNestedBlock(name string, b *configschema.NestedBlock) *proto.Schema_NestedBlock {
+	var nesting proto.Schema_NestedBlock_NestingMode
+	switch b.Nesting {
+	case configschema.NestingSingle:
+		nesting = proto.Schema_NestedBlock_SINGLE
+	case configschema.NestingGroup:
+		nesting = proto.Schema_NestedBlock_GROUP
+	case configschema.NestingList:
+		nesting = proto.Schema_NestedBlock_LIST
+	case configschema.NestingSet:
+		nesting = proto.Schema_NestedBlock_SET
+	case configschema.NestingMap:
+		nesting = proto.Schema_NestedBlock_MAP
+	default:
+		nesting = proto.Schema_NestedBlock_INVALID
+	}
+	return &proto.Schema_NestedBlock{
+		TypeName: name,
+		Block:    ConfigSchemaToProto(&b.Block),
+		Nesting:  nesting,
+		MinItems: int64(b.MinItems),
+		MaxItems: int64(b.MaxItems),
+	}
+}
+
+// ProtoToProviderSchema takes a proto.Schema and converts it to a providers.Schema.
+func ProtoToProviderSchema(s *proto.Schema) providers.Schema {
+	return providers.Schema{
+		Version: s.Version,
+		Block:   ProtoToConfigSchema(s.Block),
+	}
+}
+
+// ProtoToConfigSchema takes the GetSchcema_Block from a grpc response and converts it
+// to a terraform *configschema.Block.
+func ProtoToConfigSchema(b *proto.Schema_Block) *configschema.Block {
+	block := &configschema.Block{
+		Attributes: make(map[string]*configschema.Attribute),
+		BlockTypes: make(map[string]*configschema.NestedBlock),
+
+		Description:     b.Description,
+		DescriptionKind: schemaStringKind(b.DescriptionKind),
+		Deprecated:      b.Deprecated,
+	}
+
+	for _, a := range b.Attributes {
+		attr := &configschema.Attribute{
+			Description:     a.Description,
+			DescriptionKind: schemaStringKind(a.DescriptionKind),
+			Required:        a.Required,
+			Optional:        a.Optional,
+			Computed:        a.Computed,
+			Sensitive:       a.Sensitive,
+			Deprecated:      a.Deprecated,
+		}
+
+		if err := json.Unmarshal(a.Type, &attr.Type); err != nil {
+			panic(err)
+		}
+
+		block.Attributes[a.Name] = attr
+	}
+
+	for _, b := range b.BlockTypes {
+		block.BlockTypes[b.TypeName] = schemaNestedBlock(b)
+	}
+
+	return block
+}
+
+func schemaStringKind(k proto.StringKind) configschema.StringKind {
+	switch k {
+	default:
+		return configschema.StringPlain
+	case proto.StringKind_MARKDOWN:
+		return configschema.StringMarkdown
+	}
+}
+
+func schemaNestedBlock(b *proto.Schema_NestedBlock) *configschema.NestedBlock {
+	var nesting configschema.NestingMode
+	switch b.Nesting {
+	case proto.Schema_NestedBlock_SINGLE:
+		nesting = configschema.NestingSingle
+	case proto.Schema_NestedBlock_GROUP:
+		nesting = configschema.NestingGroup
+	case proto.Schema_NestedBlock_LIST:
+		nesting = configschema.NestingList
+	case proto.Schema_NestedBlock_MAP:
+		nesting = configschema.NestingMap
+	case proto.Schema_NestedBlock_SET:
+		nesting = configschema.NestingSet
+	default:
+		// In all other cases we'll leave it as the zero value (invalid) and
+		// let the caller validate it and deal with this.
+	}
+
+	nb := &configschema.NestedBlock{
+		Nesting:  nesting,
+		MinItems: int(b.MinItems),
+		MaxItems: int(b.MaxItems),
+	}
+
+	nested := ProtoToConfigSchema(b.Block)
+	nb.Block = *nested
+	return nb
+}
+
+// sortedKeys returns the lexically sorted keys from the given map. This is
+// used to make schema conversions are deterministic. This panics if map keys
+// are not a string.
+func sortedKeys(m interface{}) []string {
+	v := reflect.ValueOf(m)
+	keys := make([]string, v.Len())
+
+	mapKeys := v.MapKeys()
+	for i, k := range mapKeys {
+		keys[i] = k.Interface().(string)
+	}
+
+	sort.Strings(keys)
+	return keys
+}
diff --git a/v1.5.7/internal/plugin/convert/schema_test.go b/v1.5.7/internal/plugin/convert/schema_test.go
new file mode 100644
index 0000000..14f8612
--- /dev/null
+++ b/v1.5.7/internal/plugin/convert/schema_test.go
@@ -0,0 +1,364 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package convert
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	proto "github.com/hashicorp/terraform/internal/tfplugin5"
+	"github.com/zclconf/go-cty/cty"
+)
+
+var (
+	equateEmpty   = cmpopts.EquateEmpty()
+	typeComparer  = cmp.Comparer(cty.Type.Equals)
+	valueComparer = cmp.Comparer(cty.Value.RawEquals)
+)
+
+// Test that we can convert configschema to protobuf types and back again.
+func TestConvertSchemaBlocks(t *testing.T) {
+	tests := map[string]struct {
+		Block *proto.Schema_Block
+		Want  *configschema.Block
+	}{
+		"attributes": {
+			&proto.Schema_Block{
+				Attributes: []*proto.Schema_Attribute{
+					{
+						Name:     "computed",
+						Type:     []byte(`["list","bool"]`),
+						Computed: true,
+					},
+					{
+						Name:     "optional",
+						Type:     []byte(`"string"`),
+						Optional: true,
+					},
+					{
+						Name:     "optional_computed",
+						Type:     []byte(`["map","bool"]`),
+						Optional: true,
+						Computed: true,
+					},
+					{
+						Name:     "required",
+						Type:     []byte(`"number"`),
+						Required: true,
+					},
+				},
+			},
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"computed": {
+						Type:     cty.List(cty.Bool),
+						Computed: true,
+					},
+					"optional": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"optional_computed": {
+						Type:     cty.Map(cty.Bool),
+						Optional: true,
+						Computed: true,
+					},
+					"required": {
+						Type:     cty.Number,
+						Required: true,
+					},
+				},
+			},
+		},
+		"blocks": {
+			&proto.Schema_Block{
+				BlockTypes: []*proto.Schema_NestedBlock{
+					{
+						TypeName: "list",
+						Nesting:  proto.Schema_NestedBlock_LIST,
+						Block:    &proto.Schema_Block{},
+					},
+					{
+						TypeName: "map",
+						Nesting:  proto.Schema_NestedBlock_MAP,
+						Block:    &proto.Schema_Block{},
+					},
+					{
+						TypeName: "set",
+						Nesting:  proto.Schema_NestedBlock_SET,
+						Block:    &proto.Schema_Block{},
+					},
+					{
+						TypeName: "single",
+						Nesting:  proto.Schema_NestedBlock_SINGLE,
+						Block: &proto.Schema_Block{
+							Attributes: []*proto.Schema_Attribute{
+								{
+									Name:     "foo",
+									Type:     []byte(`"dynamic"`),
+									Required: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"list": &configschema.NestedBlock{
+						Nesting: configschema.NestingList,
+					},
+					"map": &configschema.NestedBlock{
+						Nesting: configschema.NestingMap,
+					},
+					"set": &configschema.NestedBlock{
+						Nesting: configschema.NestingSet,
+					},
+					"single": &configschema.NestedBlock{
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"foo": {
+									Type:     cty.DynamicPseudoType,
+									Required: true,
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		"deep block nesting": {
+			&proto.Schema_Block{
+				BlockTypes: []*proto.Schema_NestedBlock{
+					{
+						TypeName: "single",
+						Nesting:  proto.Schema_NestedBlock_SINGLE,
+						Block: &proto.Schema_Block{
+							BlockTypes: []*proto.Schema_NestedBlock{
+								{
+									TypeName: "list",
+									Nesting:  proto.Schema_NestedBlock_LIST,
+									Block: &proto.Schema_Block{
+										BlockTypes: []*proto.Schema_NestedBlock{
+											{
+												TypeName: "set",
+												Nesting:  proto.Schema_NestedBlock_SET,
+												Block:    &proto.Schema_Block{},
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"single": &configschema.NestedBlock{
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							BlockTypes: map[string]*configschema.NestedBlock{
+								"list": &configschema.NestedBlock{
+									Nesting: configschema.NestingList,
+									Block: configschema.Block{
+										BlockTypes: map[string]*configschema.NestedBlock{
+											"set": &configschema.NestedBlock{
+												Nesting: configschema.NestingSet,
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for name, tc := range tests {
+		t.Run(name, func(t *testing.T) {
+			converted := ProtoToConfigSchema(tc.Block)
+			if !cmp.Equal(converted, tc.Want, typeComparer, valueComparer, equateEmpty) {
+				t.Fatal(cmp.Diff(converted, tc.Want, typeComparer, valueComparer, equateEmpty))
+			}
+		})
+	}
+}
+
+// Test that we can convert configschema to protobuf types and back again.
+func TestConvertProtoSchemaBlocks(t *testing.T) {
+	tests := map[string]struct {
+		Want  *proto.Schema_Block
+		Block *configschema.Block
+	}{
+		"attributes": {
+			&proto.Schema_Block{
+				Attributes: []*proto.Schema_Attribute{
+					{
+						Name:     "computed",
+						Type:     []byte(`["list","bool"]`),
+						Computed: true,
+					},
+					{
+						Name:     "optional",
+						Type:     []byte(`"string"`),
+						Optional: true,
+					},
+					{
+						Name:     "optional_computed",
+						Type:     []byte(`["map","bool"]`),
+						Optional: true,
+						Computed: true,
+					},
+					{
+						Name:     "required",
+						Type:     []byte(`"number"`),
+						Required: true,
+					},
+				},
+			},
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"computed": {
+						Type:     cty.List(cty.Bool),
+						Computed: true,
+					},
+					"optional": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"optional_computed": {
+						Type:     cty.Map(cty.Bool),
+						Optional: true,
+						Computed: true,
+					},
+					"required": {
+						Type:     cty.Number,
+						Required: true,
+					},
+				},
+			},
+		},
+		"blocks": {
+			&proto.Schema_Block{
+				BlockTypes: []*proto.Schema_NestedBlock{
+					{
+						TypeName: "list",
+						Nesting:  proto.Schema_NestedBlock_LIST,
+						Block:    &proto.Schema_Block{},
+					},
+					{
+						TypeName: "map",
+						Nesting:  proto.Schema_NestedBlock_MAP,
+						Block:    &proto.Schema_Block{},
+					},
+					{
+						TypeName: "set",
+						Nesting:  proto.Schema_NestedBlock_SET,
+						Block:    &proto.Schema_Block{},
+					},
+					{
+						TypeName: "single",
+						Nesting:  proto.Schema_NestedBlock_SINGLE,
+						Block: &proto.Schema_Block{
+							Attributes: []*proto.Schema_Attribute{
+								{
+									Name:     "foo",
+									Type:     []byte(`"dynamic"`),
+									Required: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"list": &configschema.NestedBlock{
+						Nesting: configschema.NestingList,
+					},
+					"map": &configschema.NestedBlock{
+						Nesting: configschema.NestingMap,
+					},
+					"set": &configschema.NestedBlock{
+						Nesting: configschema.NestingSet,
+					},
+					"single": &configschema.NestedBlock{
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"foo": {
+									Type:     cty.DynamicPseudoType,
+									Required: true,
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		"deep block nesting": {
+			&proto.Schema_Block{
+				BlockTypes: []*proto.Schema_NestedBlock{
+					{
+						TypeName: "single",
+						Nesting:  proto.Schema_NestedBlock_SINGLE,
+						Block: &proto.Schema_Block{
+							BlockTypes: []*proto.Schema_NestedBlock{
+								{
+									TypeName: "list",
+									Nesting:  proto.Schema_NestedBlock_LIST,
+									Block: &proto.Schema_Block{
+										BlockTypes: []*proto.Schema_NestedBlock{
+											{
+												TypeName: "set",
+												Nesting:  proto.Schema_NestedBlock_SET,
+												Block:    &proto.Schema_Block{},
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"single": &configschema.NestedBlock{
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							BlockTypes: map[string]*configschema.NestedBlock{
+								"list": &configschema.NestedBlock{
+									Nesting: configschema.NestingList,
+									Block: configschema.Block{
+										BlockTypes: map[string]*configschema.NestedBlock{
+											"set": &configschema.NestedBlock{
+												Nesting: configschema.NestingSet,
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for name, tc := range tests {
+		t.Run(name, func(t *testing.T) {
+			converted := ConfigSchemaToProto(tc.Block)
+			if !cmp.Equal(converted, tc.Want, typeComparer, equateEmpty, ignoreUnexported) {
+				t.Fatal(cmp.Diff(converted, tc.Want, typeComparer, equateEmpty, ignoreUnexported))
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/plugin/discovery/find.go b/v1.5.7/internal/plugin/discovery/find.go
new file mode 100644
index 0000000..a3893a7
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/find.go
@@ -0,0 +1,192 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package discovery
+
+import (
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+// FindPlugins looks in the given directories for files whose filenames
+// suggest that they are plugins of the given kind (e.g. "provider") and
+// returns a PluginMetaSet representing the discovered potential-plugins.
+//
+// Currently this supports two different naming schemes. The current
+// standard naming scheme is a subdirectory called $GOOS-$GOARCH containing
+// files named terraform-$KIND-$NAME-V$VERSION. The legacy naming scheme is
+// files directly in the given directory whose names are like
+// terraform-$KIND-$NAME.
+//
+// Only one plugin will be returned for each unique plugin (name, version)
+// pair, with preference given to files found in earlier directories.
+//
+// This is a convenience wrapper around FindPluginPaths and ResolvePluginsPaths.
+func FindPlugins(kind string, dirs []string) PluginMetaSet {
+	return ResolvePluginPaths(FindPluginPaths(kind, dirs))
+}
+
+// FindPluginPaths looks in the given directories for files whose filenames
+// suggest that they are plugins of the given kind (e.g. "provider").
+//
+// The return value is a list of absolute paths that appear to refer to
+// plugins in the given directories, based only on what can be inferred
+// from the naming scheme. The paths returned are ordered such that files
+// in later dirs appear after files in earlier dirs in the given directory
+// list. Within the same directory plugins are returned in a consistent but
+// undefined order.
+func FindPluginPaths(kind string, dirs []string) []string {
+	// This is just a thin wrapper around findPluginPaths so that we can
+	// use the latter in tests with a fake machineName so we can use our
+	// test fixtures.
+	return findPluginPaths(kind, dirs)
+}
+
+func findPluginPaths(kind string, dirs []string) []string {
+	prefix := "terraform-" + kind + "-"
+
+	ret := make([]string, 0, len(dirs))
+
+	for _, dir := range dirs {
+		items, err := ioutil.ReadDir(dir)
+		if err != nil {
+			// Ignore missing dirs, non-dirs, etc
+			continue
+		}
+
+		log.Printf("[DEBUG] checking for %s in %q", kind, dir)
+
+		for _, item := range items {
+			fullName := item.Name()
+
+			if !strings.HasPrefix(fullName, prefix) {
+				continue
+			}
+
+			// New-style paths must have a version segment in filename
+			if strings.Contains(strings.ToLower(fullName), "_v") {
+				absPath, err := filepath.Abs(filepath.Join(dir, fullName))
+				if err != nil {
+					log.Printf("[ERROR] plugin filepath error: %s", err)
+					continue
+				}
+
+				// Check that the file we found is usable
+				if !pathIsFile(absPath) {
+					log.Printf("[ERROR] ignoring non-file %s", absPath)
+					continue
+				}
+
+				log.Printf("[DEBUG] found %s %q", kind, fullName)
+				ret = append(ret, filepath.Clean(absPath))
+				continue
+			}
+
+			// Legacy style with files directly in the base directory
+			absPath, err := filepath.Abs(filepath.Join(dir, fullName))
+			if err != nil {
+				log.Printf("[ERROR] plugin filepath error: %s", err)
+				continue
+			}
+
+			// Check that the file we found is usable
+			if !pathIsFile(absPath) {
+				log.Printf("[ERROR] ignoring non-file %s", absPath)
+				continue
+			}
+
+			log.Printf("[WARN] found legacy %s %q", kind, fullName)
+
+			ret = append(ret, filepath.Clean(absPath))
+		}
+	}
+
+	return ret
+}
+
+// Returns true if and only if the given path refers to a file or a symlink
+// to a file.
+func pathIsFile(path string) bool {
+	info, err := os.Stat(path)
+	if err != nil {
+		return false
+	}
+
+	return !info.IsDir()
+}
+
+// ResolvePluginPaths takes a list of paths to plugin executables (as returned
+// by e.g. FindPluginPaths) and produces a PluginMetaSet describing the
+// referenced plugins.
+//
+// If the same combination of plugin name and version appears multiple times,
+// the earlier reference will be preferred. Several different versions of
+// the same plugin name may be returned, in which case the methods of
+// PluginMetaSet can be used to filter down.
+func ResolvePluginPaths(paths []string) PluginMetaSet {
+	s := make(PluginMetaSet)
+
+	type nameVersion struct {
+		Name    string
+		Version string
+	}
+	found := make(map[nameVersion]struct{})
+
+	for _, path := range paths {
+		baseName := strings.ToLower(filepath.Base(path))
+		if !strings.HasPrefix(baseName, "terraform-") {
+			// Should never happen with reasonable input
+			continue
+		}
+
+		baseName = baseName[10:]
+		firstDash := strings.Index(baseName, "-")
+		if firstDash == -1 {
+			// Should never happen with reasonable input
+			continue
+		}
+
+		baseName = baseName[firstDash+1:]
+		if baseName == "" {
+			// Should never happen with reasonable input
+			continue
+		}
+
+		// Trim the .exe suffix used on Windows before we start wrangling
+		// the remainder of the path.
+		baseName = strings.TrimSuffix(baseName, ".exe")
+
+		parts := strings.SplitN(baseName, "_v", 2)
+		name := parts[0]
+		version := VersionZero
+		if len(parts) == 2 {
+			version = parts[1]
+		}
+
+		// Auto-installed plugins contain an extra name portion representing
+		// the expected plugin version, which we must trim off.
+		if underX := strings.Index(version, "_x"); underX != -1 {
+			version = version[:underX]
+		}
+
+		if _, ok := found[nameVersion{name, version}]; ok {
+			// Skip duplicate versions of the same plugin
+			// (We do this during this step because after this we will be
+			// dealing with sets and thus lose our ordering with which to
+			// decide preference.)
+			continue
+		}
+
+		s.Add(PluginMeta{
+			Name:    name,
+			Version: VersionStr(version),
+			Path:    path,
+		})
+		found[nameVersion{name, version}] = struct{}{}
+	}
+
+	return s
+}
diff --git a/v1.5.7/internal/plugin/discovery/find_test.go b/v1.5.7/internal/plugin/discovery/find_test.go
new file mode 100644
index 0000000..b9a75b0
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/find_test.go
@@ -0,0 +1,142 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package discovery
+
+import (
+	"os"
+	"path/filepath"
+	"reflect"
+	"testing"
+)
+
+func TestFindPluginPaths(t *testing.T) {
+	got := findPluginPaths(
+		"foo",
+		[]string{
+			"testdata/current-style-plugins/mockos_mockarch",
+			"testdata/legacy-style-plugins",
+			"testdata/non-existent",
+			"testdata/not-a-dir",
+		},
+	)
+	want := []string{
+		filepath.Join("testdata", "current-style-plugins", "mockos_mockarch", "terraform-foo-bar_v0.0.1"),
+		filepath.Join("testdata", "current-style-plugins", "mockos_mockarch", "terraform-foo-bar_v1.0.0.exe"),
+		// un-versioned plugins are still picked up, even in current-style paths
+		filepath.Join("testdata", "current-style-plugins", "mockos_mockarch", "terraform-foo-missing-version"),
+		filepath.Join("testdata", "legacy-style-plugins", "terraform-foo-bar"),
+		filepath.Join("testdata", "legacy-style-plugins", "terraform-foo-baz"),
+	}
+
+	// Turn the paths back into relative paths, since we don't care exactly
+	// where this code is present on the system for the sake of this test.
+	baseDir, err := os.Getwd()
+	if err != nil {
+		// Should never happen
+		panic(err)
+	}
+	for i, absPath := range got {
+		if !filepath.IsAbs(absPath) {
+			t.Errorf("got non-absolute path %s", absPath)
+		}
+
+		got[i], err = filepath.Rel(baseDir, absPath)
+		if err != nil {
+			t.Fatalf("Can't make %s relative to current directory %s", absPath, baseDir)
+		}
+	}
+
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestResolvePluginPaths(t *testing.T) {
+	got := ResolvePluginPaths([]string{
+		"/example/mockos_mockarch/terraform-foo-bar_v0.0.1",
+		"/example/mockos_mockarch/terraform-foo-baz_v0.0.1",
+		"/example/mockos_mockarch/terraform-foo-baz_v1.0.0",
+		"/example/mockos_mockarch/terraform-foo-baz_v2.0.0_x4",
+		"/example/mockos_mockarch/terraform-foo-upper_V2.0.0_X4",
+		"/example/terraform-foo-bar",
+		"/example/mockos_mockarch/terraform-foo-bar_vbananas",
+		"/example/mockos_mockarch/terraform-foo-bar_v",
+		"/example/mockos_mockarch/terraform-foo-windowsthing1_v1.0.0.exe",
+		"/example/mockos_mockarch/terraform-foo-windowsthing2_v1.0.0_x4.exe",
+		"/example/mockos_mockarch/terraform-foo-windowsthing3.exe",
+		"/example2/mockos_mockarch/terraform-foo-bar_v0.0.1",
+	})
+
+	want := []PluginMeta{
+		{
+			Name:    "bar",
+			Version: "0.0.1",
+			Path:    "/example/mockos_mockarch/terraform-foo-bar_v0.0.1",
+		},
+		{
+			Name:    "baz",
+			Version: "0.0.1",
+			Path:    "/example/mockos_mockarch/terraform-foo-baz_v0.0.1",
+		},
+		{
+			Name:    "baz",
+			Version: "1.0.0",
+			Path:    "/example/mockos_mockarch/terraform-foo-baz_v1.0.0",
+		},
+		{
+			Name:    "baz",
+			Version: "2.0.0",
+			Path:    "/example/mockos_mockarch/terraform-foo-baz_v2.0.0_x4",
+		},
+		{
+			Name:    "upper",
+			Version: "2.0.0",
+			Path:    "/example/mockos_mockarch/terraform-foo-upper_V2.0.0_X4",
+		},
+		{
+			Name:    "bar",
+			Version: "0.0.0",
+			Path:    "/example/terraform-foo-bar",
+		},
+		{
+			Name:    "bar",
+			Version: "bananas",
+			Path:    "/example/mockos_mockarch/terraform-foo-bar_vbananas",
+		},
+		{
+			Name:    "bar",
+			Version: "",
+			Path:    "/example/mockos_mockarch/terraform-foo-bar_v",
+		},
+		{
+			Name:    "windowsthing1",
+			Version: "1.0.0",
+			Path:    "/example/mockos_mockarch/terraform-foo-windowsthing1_v1.0.0.exe",
+		},
+		{
+			Name:    "windowsthing2",
+			Version: "1.0.0",
+			Path:    "/example/mockos_mockarch/terraform-foo-windowsthing2_v1.0.0_x4.exe",
+		},
+		{
+			Name:    "windowsthing3",
+			Version: "0.0.0",
+			Path:    "/example/mockos_mockarch/terraform-foo-windowsthing3.exe",
+		},
+	}
+
+	for p := range got {
+		t.Logf("got %#v", p)
+	}
+
+	if got, want := got.Count(), len(want); got != want {
+		t.Errorf("got %d items; want %d", got, want)
+	}
+
+	for _, wantMeta := range want {
+		if !got.Has(wantMeta) {
+			t.Errorf("missing meta %#v", wantMeta)
+		}
+	}
+}
diff --git a/v1.5.7/internal/plugin/discovery/get_cache.go b/v1.5.7/internal/plugin/discovery/get_cache.go
new file mode 100644
index 0000000..f765ad7
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/get_cache.go
@@ -0,0 +1,51 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package discovery
+
+// PluginCache is an interface implemented by objects that are able to maintain
+// a cache of plugins.
+type PluginCache interface {
+	// CachedPluginPath returns a path where the requested plugin is already
+	// cached, or an empty string if the requested plugin is not yet cached.
+	CachedPluginPath(kind string, name string, version Version) string
+
+	// InstallDir returns the directory that new plugins should be installed into
+	// in order to populate the cache. This directory should be used as the
+	// first argument to getter.Get when downloading plugins with go-getter.
+	//
+	// After installing into this directory, use CachedPluginPath to obtain the
+	// path where the plugin was installed.
+	InstallDir() string
+}
+
+// NewLocalPluginCache returns a PluginCache that caches plugins in a
+// given local directory.
+func NewLocalPluginCache(dir string) PluginCache {
+	return &pluginCache{
+		Dir: dir,
+	}
+}
+
+type pluginCache struct {
+	Dir string
+}
+
+func (c *pluginCache) CachedPluginPath(kind string, name string, version Version) string {
+	allPlugins := FindPlugins(kind, []string{c.Dir})
+	plugins := allPlugins.WithName(name).WithVersion(version)
+
+	if plugins.Count() == 0 {
+		// nothing cached
+		return ""
+	}
+
+	// There should generally be only one plugin here; if there's more than
+	// one match for some reason then we'll just choose one arbitrarily.
+	plugin := plugins.Newest()
+	return plugin.Path
+}
+
+func (c *pluginCache) InstallDir() string {
+	return c.Dir
+}
diff --git a/v1.5.7/internal/plugin/discovery/get_cache_test.go b/v1.5.7/internal/plugin/discovery/get_cache_test.go
new file mode 100644
index 0000000..fd49c3f
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/get_cache_test.go
@@ -0,0 +1,32 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package discovery
+
+import (
+	"testing"
+)
+
+func TestLocalPluginCache(t *testing.T) {
+	cache := NewLocalPluginCache("testdata/plugin-cache")
+
+	foo1Path := cache.CachedPluginPath("provider", "foo", VersionStr("v0.0.1").MustParse())
+	if foo1Path == "" {
+		t.Errorf("foo v0.0.1 not found; should have been found")
+	}
+
+	foo2Path := cache.CachedPluginPath("provider", "foo", VersionStr("v0.0.2").MustParse())
+	if foo2Path != "" {
+		t.Errorf("foo v0.0.2 found at %s; should not have been found", foo2Path)
+	}
+
+	baz1Path := cache.CachedPluginPath("provider", "baz", VersionStr("v0.0.1").MustParse())
+	if baz1Path != "" {
+		t.Errorf("baz v0.0.1 found at %s; should not have been found", baz1Path)
+	}
+
+	baz2Path := cache.CachedPluginPath("provider", "baz", VersionStr("v0.0.2").MustParse())
+	if baz1Path != "" {
+		t.Errorf("baz v0.0.2 found at %s; should not have been found", baz2Path)
+	}
+}
diff --git a/v1.5.7/internal/plugin/discovery/meta.go b/v1.5.7/internal/plugin/discovery/meta.go
new file mode 100644
index 0000000..fe5c3f5
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/meta.go
@@ -0,0 +1,44 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package discovery
+
+import (
+	"crypto/sha256"
+	"io"
+	"os"
+)
+
+// PluginMeta is metadata about a plugin, useful for launching the plugin
+// and for understanding which plugins are available.
+type PluginMeta struct {
+	// Name is the name of the plugin, e.g. as inferred from the plugin
+	// binary's filename, or by explicit configuration.
+	Name string
+
+	// Version is the semver version of the plugin, expressed as a string
+	// that might not be semver-valid.
+	Version VersionStr
+
+	// Path is the absolute path of the executable that can be launched
+	// to provide the RPC server for this plugin.
+	Path string
+}
+
+// SHA256 returns a SHA256 hash of the content of the referenced executable
+// file, or an error if the file's contents cannot be read.
+func (m PluginMeta) SHA256() ([]byte, error) {
+	f, err := os.Open(m.Path)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	h := sha256.New()
+	_, err = io.Copy(h, f)
+	if err != nil {
+		return nil, err
+	}
+
+	return h.Sum(nil), nil
+}
diff --git a/v1.5.7/internal/plugin/discovery/meta_set.go b/v1.5.7/internal/plugin/discovery/meta_set.go
new file mode 100644
index 0000000..9932558
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/meta_set.go
@@ -0,0 +1,198 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package discovery
+
+// A PluginMetaSet is a set of PluginMeta objects meeting a certain criteria.
+//
+// Methods on this type allow filtering of the set to produce subsets that
+// meet more restrictive criteria.
+type PluginMetaSet map[PluginMeta]struct{}
+
+// Add inserts the given PluginMeta into the receiving set. This is a no-op
+// if the given meta is already present.
+func (s PluginMetaSet) Add(p PluginMeta) {
+	s[p] = struct{}{}
+}
+
+// Remove removes the given PluginMeta from the receiving set. This is a no-op
+// if the given meta is not already present.
+func (s PluginMetaSet) Remove(p PluginMeta) {
+	delete(s, p)
+}
+
+// Has returns true if the given meta is in the receiving set, or false
+// otherwise.
+func (s PluginMetaSet) Has(p PluginMeta) bool {
+	_, ok := s[p]
+	return ok
+}
+
+// Count returns the number of metas in the set
+func (s PluginMetaSet) Count() int {
+	return len(s)
+}
+
+// ValidateVersions returns two new PluginMetaSets, separating those with
+// versions that have syntax-valid semver versions from those that don't.
+//
+// Eliminating invalid versions from consideration (and possibly warning about
+// them) is usually the first step of working with a meta set after discovery
+// has completed.
+func (s PluginMetaSet) ValidateVersions() (valid, invalid PluginMetaSet) {
+	valid = make(PluginMetaSet)
+	invalid = make(PluginMetaSet)
+	for p := range s {
+		if _, err := p.Version.Parse(); err == nil {
+			valid.Add(p)
+		} else {
+			invalid.Add(p)
+		}
+	}
+	return
+}
+
+// WithName returns the subset of metas that have the given name.
+func (s PluginMetaSet) WithName(name string) PluginMetaSet {
+	ns := make(PluginMetaSet)
+	for p := range s {
+		if p.Name == name {
+			ns.Add(p)
+		}
+	}
+	return ns
+}
+
+// WithVersion returns the subset of metas that have the given version.
+//
+// This should be used only with the "valid" result from ValidateVersions;
+// it will ignore any plugin metas that have invalid version strings.
+func (s PluginMetaSet) WithVersion(version Version) PluginMetaSet {
+	ns := make(PluginMetaSet)
+	for p := range s {
+		gotVersion, err := p.Version.Parse()
+		if err != nil {
+			continue
+		}
+		if gotVersion.Equal(version) {
+			ns.Add(p)
+		}
+	}
+	return ns
+}
+
+// ByName groups the metas in the set by their Names, returning a map.
+func (s PluginMetaSet) ByName() map[string]PluginMetaSet {
+	ret := make(map[string]PluginMetaSet)
+	for p := range s {
+		if _, ok := ret[p.Name]; !ok {
+			ret[p.Name] = make(PluginMetaSet)
+		}
+		ret[p.Name].Add(p)
+	}
+	return ret
+}
+
+// Newest returns the one item from the set that has the newest Version value.
+//
+// The result is meaningful only if the set is already filtered such that
+// all of the metas have the same Name.
+//
+// If there isn't at least one meta in the set then this function will panic.
+// Use Count() to ensure that there is at least one value before calling.
+//
+// If any of the metas have invalid version strings then this function will
+// panic. Use ValidateVersions() first to filter out metas with invalid
+// versions.
+//
+// If two metas have the same Version then one is arbitrarily chosen. This
+// situation should be avoided by pre-filtering the set.
+func (s PluginMetaSet) Newest() PluginMeta {
+	if len(s) == 0 {
+		panic("can't call NewestStable on empty PluginMetaSet")
+	}
+
+	var first = true
+	var winner PluginMeta
+	var winnerVersion Version
+	for p := range s {
+		version, err := p.Version.Parse()
+		if err != nil {
+			panic(err)
+		}
+
+		if first || version.NewerThan(winnerVersion) {
+			winner = p
+			winnerVersion = version
+			first = false
+		}
+	}
+
+	return winner
+}
+
+// ConstrainVersions takes a set of requirements and attempts to
+// return a map from name to a set of metas that have the matching
+// name and an appropriate version.
+//
+// If any of the given requirements match *no* plugins then its PluginMetaSet
+// in the returned map will be empty.
+//
+// All viable metas are returned, so the caller can apply any desired filtering
+// to reduce down to a single option. For example, calling Newest() to obtain
+// the highest available version.
+//
+// If any of the metas in the set have invalid version strings then this
+// function will panic. Use ValidateVersions() first to filter out metas with
+// invalid versions.
+func (s PluginMetaSet) ConstrainVersions(reqd PluginRequirements) map[string]PluginMetaSet {
+	ret := make(map[string]PluginMetaSet)
+	for p := range s {
+		name := p.Name
+		allowedVersions, ok := reqd[name]
+		if !ok {
+			continue
+		}
+		if _, ok := ret[p.Name]; !ok {
+			ret[p.Name] = make(PluginMetaSet)
+		}
+		version, err := p.Version.Parse()
+		if err != nil {
+			panic(err)
+		}
+		if allowedVersions.Allows(version) {
+			ret[p.Name].Add(p)
+		}
+	}
+	return ret
+}
+
+// OverridePaths returns a new set where any existing plugins with the given
+// names are removed and replaced with the single path given in the map.
+//
+// This is here only to continue to support the legacy way of overriding
+// plugin binaries in the .terraformrc file. It treats all given plugins
+// as pre-versioning (version 0.0.0). This mechanism will eventually be
+// phased out, with vendor directories being the intended replacement.
+func (s PluginMetaSet) OverridePaths(paths map[string]string) PluginMetaSet {
+	ret := make(PluginMetaSet)
+	for p := range s {
+		if _, ok := paths[p.Name]; ok {
+			// Skip plugins that we're overridding
+			continue
+		}
+
+		ret.Add(p)
+	}
+
+	// Now add the metadata for overriding plugins
+	for name, path := range paths {
+		ret.Add(PluginMeta{
+			Name:    name,
+			Version: VersionZero,
+			Path:    path,
+		})
+	}
+
+	return ret
+}
diff --git a/v1.5.7/internal/plugin/discovery/meta_set_test.go b/v1.5.7/internal/plugin/discovery/meta_set_test.go
new file mode 100644
index 0000000..ea3b763
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/meta_set_test.go
@@ -0,0 +1,420 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package discovery
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+)
+
+func TestPluginMetaSetManipulation(t *testing.T) {
+	metas := []PluginMeta{
+		{
+			Name:    "foo",
+			Version: "1.0.0",
+			Path:    "test-foo",
+		},
+		{
+			Name:    "bar",
+			Version: "2.0.0",
+			Path:    "test-bar",
+		},
+		{
+			Name:    "baz",
+			Version: "2.0.0",
+			Path:    "test-bar",
+		},
+	}
+	s := make(PluginMetaSet)
+
+	if count := s.Count(); count != 0 {
+		t.Fatalf("set has Count %d before any items added", count)
+	}
+
+	// Can we add metas?
+	for _, p := range metas {
+		s.Add(p)
+		if !s.Has(p) {
+			t.Fatalf("%q not in set after adding it", p.Name)
+		}
+	}
+
+	if got, want := s.Count(), len(metas); got != want {
+		t.Fatalf("set has Count %d after all items added; want %d", got, want)
+	}
+
+	// Can we still retrieve earlier ones after we added later ones?
+	for _, p := range metas {
+		if !s.Has(p) {
+			t.Fatalf("%q not in set after all adds", p.Name)
+		}
+	}
+
+	// Can we remove metas?
+	for _, p := range metas {
+		s.Remove(p)
+		if s.Has(p) {
+			t.Fatalf("%q still in set after removing it", p.Name)
+		}
+	}
+
+	if count := s.Count(); count != 0 {
+		t.Fatalf("set has Count %d after all items removed", count)
+	}
+}
+
+func TestPluginMetaSetValidateVersions(t *testing.T) {
+	metas := []PluginMeta{
+		{
+			Name:    "foo",
+			Version: "1.0.0",
+			Path:    "test-foo",
+		},
+		{
+			Name:    "bar",
+			Version: "0.0.1",
+			Path:    "test-bar",
+		},
+		{
+			Name:    "baz",
+			Version: "bananas",
+			Path:    "test-bar",
+		},
+	}
+	s := make(PluginMetaSet)
+
+	for _, p := range metas {
+		s.Add(p)
+	}
+
+	valid, invalid := s.ValidateVersions()
+	if count := valid.Count(); count != 2 {
+		t.Errorf("valid set has %d metas; want 2", count)
+	}
+	if count := invalid.Count(); count != 1 {
+		t.Errorf("valid set has %d metas; want 1", count)
+	}
+
+	if !valid.Has(metas[0]) {
+		t.Errorf("'foo' not in valid set")
+	}
+	if !valid.Has(metas[1]) {
+		t.Errorf("'bar' not in valid set")
+	}
+	if !invalid.Has(metas[2]) {
+		t.Errorf("'baz' not in invalid set")
+	}
+
+	if invalid.Has(metas[0]) {
+		t.Errorf("'foo' in invalid set")
+	}
+	if invalid.Has(metas[1]) {
+		t.Errorf("'bar' in invalid set")
+	}
+	if valid.Has(metas[2]) {
+		t.Errorf("'baz' in valid set")
+	}
+
+}
+
+func TestPluginMetaSetWithName(t *testing.T) {
+	tests := []struct {
+		metas     []PluginMeta
+		name      string
+		wantCount int
+	}{
+		{
+			[]PluginMeta{},
+			"foo",
+			0,
+		},
+		{
+			[]PluginMeta{
+				{
+					Name:    "foo",
+					Version: "0.0.1",
+					Path:    "foo",
+				},
+			},
+			"foo",
+			1,
+		},
+		{
+			[]PluginMeta{
+				{
+					Name:    "foo",
+					Version: "0.0.1",
+					Path:    "foo",
+				},
+			},
+			"bar",
+			0,
+		},
+	}
+
+	for i, test := range tests {
+		t.Run(fmt.Sprintf("Test%02d", i), func(t *testing.T) {
+			s := make(PluginMetaSet)
+			for _, p := range test.metas {
+				s.Add(p)
+			}
+			filtered := s.WithName(test.name)
+			if gotCount := filtered.Count(); gotCount != test.wantCount {
+				t.Errorf("got count %d in %#v; want %d", gotCount, filtered, test.wantCount)
+			}
+		})
+	}
+}
+
+func TestPluginMetaSetByName(t *testing.T) {
+	metas := []PluginMeta{
+		{
+			Name:    "foo",
+			Version: "1.0.0",
+			Path:    "test-foo",
+		},
+		{
+			Name:    "foo",
+			Version: "2.0.0",
+			Path:    "test-foo-2",
+		},
+		{
+			Name:    "bar",
+			Version: "0.0.1",
+			Path:    "test-bar",
+		},
+		{
+			Name:    "baz",
+			Version: "1.2.0",
+			Path:    "test-bar",
+		},
+	}
+	s := make(PluginMetaSet)
+
+	for _, p := range metas {
+		s.Add(p)
+	}
+
+	byName := s.ByName()
+	if got, want := len(byName), 3; got != want {
+		t.Errorf("%d keys in ByName map; want %d", got, want)
+	}
+	if got, want := len(byName["foo"]), 2; got != want {
+		t.Errorf("%d metas for 'foo'; want %d", got, want)
+	}
+	if got, want := len(byName["bar"]), 1; got != want {
+		t.Errorf("%d metas for 'bar'; want %d", got, want)
+	}
+	if got, want := len(byName["baz"]), 1; got != want {
+		t.Errorf("%d metas for 'baz'; want %d", got, want)
+	}
+
+	if !byName["foo"].Has(metas[0]) {
+		t.Errorf("%#v missing from 'foo' set", metas[0])
+	}
+	if !byName["foo"].Has(metas[1]) {
+		t.Errorf("%#v missing from 'foo' set", metas[1])
+	}
+	if !byName["bar"].Has(metas[2]) {
+		t.Errorf("%#v missing from 'bar' set", metas[2])
+	}
+	if !byName["baz"].Has(metas[3]) {
+		t.Errorf("%#v missing from 'baz' set", metas[3])
+	}
+}
+
+func TestPluginMetaSetNewest(t *testing.T) {
+	tests := []struct {
+		versions []string
+		want     string
+	}{
+		{
+			[]string{
+				"0.0.1",
+			},
+			"0.0.1",
+		},
+		{
+			[]string{
+				"0.0.1",
+				"0.0.2",
+			},
+			"0.0.2",
+		},
+		{
+			[]string{
+				"1.0.0",
+				"1.0.0-beta1",
+			},
+			"1.0.0",
+		},
+		{
+			[]string{
+				"0.0.1",
+				"1.0.0",
+			},
+			"1.0.0",
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(strings.Join(test.versions, "|"), func(t *testing.T) {
+			s := make(PluginMetaSet)
+			for _, version := range test.versions {
+				s.Add(PluginMeta{
+					Name:    "foo",
+					Version: VersionStr(version),
+					Path:    "foo-V" + version,
+				})
+			}
+
+			newest := s.Newest()
+			if newest.Version != VersionStr(test.want) {
+				t.Errorf("version is %q; want %q", newest.Version, test.want)
+			}
+		})
+	}
+}
+
+func TestPluginMetaSetConstrainVersions(t *testing.T) {
+	metas := []PluginMeta{
+		{
+			Name:    "foo",
+			Version: "1.0.0",
+			Path:    "test-foo",
+		},
+		{
+			Name:    "foo",
+			Version: "2.0.0",
+			Path:    "test-foo-2",
+		},
+		{
+			Name:    "foo",
+			Version: "3.0.0",
+			Path:    "test-foo-2",
+		},
+		{
+			Name:    "bar",
+			Version: "0.0.5",
+			Path:    "test-bar",
+		},
+		{
+			Name:    "baz",
+			Version: "0.0.1",
+			Path:    "test-bar",
+		},
+	}
+	s := make(PluginMetaSet)
+
+	for _, p := range metas {
+		s.Add(p)
+	}
+
+	byName := s.ConstrainVersions(PluginRequirements{
+		"foo": &PluginConstraints{Versions: ConstraintStr(">=2.0.0").MustParse()},
+		"bar": &PluginConstraints{Versions: ConstraintStr(">=0.0.0").MustParse()},
+		"baz": &PluginConstraints{Versions: ConstraintStr(">=1.0.0").MustParse()},
+		"fun": &PluginConstraints{Versions: ConstraintStr(">5.0.0").MustParse()},
+	})
+	if got, want := len(byName), 3; got != want {
+		t.Errorf("%d keys in map; want %d", got, want)
+	}
+
+	if got, want := len(byName["foo"]), 2; got != want {
+		t.Errorf("%d metas for 'foo'; want %d", got, want)
+	}
+	if got, want := len(byName["bar"]), 1; got != want {
+		t.Errorf("%d metas for 'bar'; want %d", got, want)
+	}
+	if got, want := len(byName["baz"]), 0; got != want {
+		t.Errorf("%d metas for 'baz'; want %d", got, want)
+	}
+	// "fun" is not in the map at all, because we have no metas for that name
+
+	if !byName["foo"].Has(metas[1]) {
+		t.Errorf("%#v missing from 'foo' set", metas[1])
+	}
+	if !byName["foo"].Has(metas[2]) {
+		t.Errorf("%#v missing from 'foo' set", metas[2])
+	}
+	if !byName["bar"].Has(metas[3]) {
+		t.Errorf("%#v missing from 'bar' set", metas[3])
+	}
+
+}
+
+func TestPluginMetaSetOverridePaths(t *testing.T) {
+
+	metas := []PluginMeta{
+		{
+			Name:    "foo",
+			Version: "1.0.0",
+			Path:    "test-foo-1",
+		},
+		{
+			Name:    "foo",
+			Version: "2.0.0",
+			Path:    "test-foo-2",
+		},
+		{
+			Name:    "foo",
+			Version: "3.0.0",
+			Path:    "test-foo-3",
+		},
+		{
+			Name:    "bar",
+			Version: "0.0.5",
+			Path:    "test-bar-5",
+		},
+		{
+			Name:    "bar",
+			Version: "0.0.6",
+			Path:    "test-bar-6",
+		},
+		{
+			Name:    "baz",
+			Version: "0.0.1",
+			Path:    "test-bar",
+		},
+	}
+	s := make(PluginMetaSet)
+
+	for _, p := range metas {
+		s.Add(p)
+	}
+
+	ns := s.OverridePaths(map[string]string{
+		"foo": "override-foo",
+		"fun": "override-fun",
+	})
+
+	if got, want := ns.Count(), 5; got != want {
+		t.Errorf("got %d metas; want %d", got, want)
+	}
+
+	if !ns.Has(metas[3]) {
+		t.Errorf("new set is missing %#v", metas[3])
+	}
+	if !ns.Has(metas[4]) {
+		t.Errorf("new set is missing %#v", metas[4])
+	}
+	if !ns.Has(metas[5]) {
+		t.Errorf("new set is missing %#v", metas[5])
+	}
+	if !ns.Has(PluginMeta{
+		Name:    "foo",
+		Version: VersionZero,
+		Path:    "override-foo",
+	}) {
+		t.Errorf("new set is missing 'foo' override")
+	}
+	if !ns.Has(PluginMeta{
+		Name:    "fun",
+		Version: VersionZero,
+		Path:    "override-fun",
+	}) {
+		t.Errorf("new set is missing 'fun' override")
+	}
+}
diff --git a/v1.5.7/internal/plugin/discovery/meta_test.go b/v1.5.7/internal/plugin/discovery/meta_test.go
new file mode 100644
index 0000000..77fa1e5
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/meta_test.go
@@ -0,0 +1,25 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package discovery
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestMetaSHA256(t *testing.T) {
+	m := PluginMeta{
+		Path: "testdata/current-style-plugins/mockos_mockarch/terraform-foo-bar_v0.0.1",
+	}
+	hash, err := m.SHA256()
+	if err != nil {
+		t.Fatalf("failed: %s", err)
+	}
+
+	got := fmt.Sprintf("%x", hash)
+	want := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" // (hash of empty file)
+	if got != want {
+		t.Errorf("incorrect hash %s; want %s", got, want)
+	}
+}
diff --git a/v1.5.7/internal/plugin/discovery/requirements.go b/v1.5.7/internal/plugin/discovery/requirements.go
new file mode 100644
index 0000000..bf509e8
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/requirements.go
@@ -0,0 +1,114 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package discovery
+
+import (
+	"bytes"
+)
+
+// PluginInstallProtocolVersion is the protocol version TF-core
+// supports to communicate with servers, and is used to resolve
+// plugin discovery with terraform registry, in addition to
+// any specified plugin version constraints
+const PluginInstallProtocolVersion = 5
+
+// PluginRequirements describes a set of plugins (assumed to be of a consistent
+// kind) that are required to exist and have versions within the given
+// corresponding sets.
+type PluginRequirements map[string]*PluginConstraints
+
+// PluginConstraints represents an element of PluginRequirements describing
+// the constraints for a single plugin.
+type PluginConstraints struct {
+	// Specifies that the plugin's version must be within the given
+	// constraints.
+	Versions Constraints
+
+	// If non-nil, the hash of the on-disk plugin executable must exactly
+	// match the SHA256 hash given here.
+	SHA256 []byte
+}
+
+// Allows returns true if the given version is within the receiver's version
+// constraints.
+func (s *PluginConstraints) Allows(v Version) bool {
+	return s.Versions.Allows(v)
+}
+
+// AcceptsSHA256 returns true if the given executable SHA256 hash is acceptable,
+// either because it matches the constraint or because there is no such
+// constraint.
+func (s *PluginConstraints) AcceptsSHA256(digest []byte) bool {
+	if s.SHA256 == nil {
+		return true
+	}
+	return bytes.Equal(s.SHA256, digest)
+}
+
+// Merge takes the contents of the receiver and the other given requirements
+// object and merges them together into a single requirements structure
+// that satisfies both sets of requirements.
+//
+// Note that it doesn't make sense to merge two PluginRequirements with
+// differing required plugin SHA256 hashes, since the result will never
+// match any plugin.
+func (r PluginRequirements) Merge(other PluginRequirements) PluginRequirements {
+	ret := make(PluginRequirements)
+	for n, c := range r {
+		ret[n] = &PluginConstraints{
+			Versions: Constraints{}.Append(c.Versions),
+			SHA256:   c.SHA256,
+		}
+	}
+	for n, c := range other {
+		if existing, exists := ret[n]; exists {
+			ret[n].Versions = ret[n].Versions.Append(c.Versions)
+
+			if existing.SHA256 != nil {
+				if c.SHA256 != nil && !bytes.Equal(c.SHA256, existing.SHA256) {
+					// If we've been asked to merge two constraints with
+					// different SHA256 hashes then we'll produce a dummy value
+					// that can never match anything. This is a silly edge case
+					// that no reasonable caller should hit.
+					ret[n].SHA256 = []byte(invalidProviderHash)
+				}
+			} else {
+				ret[n].SHA256 = c.SHA256 // might still be nil
+			}
+		} else {
+			ret[n] = &PluginConstraints{
+				Versions: Constraints{}.Append(c.Versions),
+				SHA256:   c.SHA256,
+			}
+		}
+	}
+	return ret
+}
+
+// LockExecutables applies additional constraints to the receiver that
+// require plugin executables with specific SHA256 digests. This modifies
+// the receiver in-place, since it's intended to be applied after
+// version constraints have been resolved.
+//
+// The given map must include a key for every plugin that is already
+// required. If not, any missing keys will cause the corresponding plugin
+// to never match, though the direct caller doesn't necessarily need to
+// guarantee this as long as the downstream code _applying_ these constraints
+// is able to deal with the non-match in some way.
+func (r PluginRequirements) LockExecutables(sha256s map[string][]byte) {
+	for name, cons := range r {
+		digest := sha256s[name]
+
+		if digest == nil {
+			// Prevent any match, which will then presumably cause the
+			// downstream consumer of this requirements to report an error.
+			cons.SHA256 = []byte(invalidProviderHash)
+			continue
+		}
+
+		cons.SHA256 = digest
+	}
+}
+
+const invalidProviderHash = "<invalid>"
diff --git a/v1.5.7/internal/plugin/discovery/requirements_test.go b/v1.5.7/internal/plugin/discovery/requirements_test.go
new file mode 100644
index 0000000..eb209ea
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/requirements_test.go
@@ -0,0 +1,96 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package discovery
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestPluginConstraintsAllows(t *testing.T) {
+	tests := []struct {
+		Constraints *PluginConstraints
+		Version     string
+		Want        bool
+	}{
+		{
+			&PluginConstraints{
+				Versions: AllVersions,
+			},
+			"1.0.0",
+			true,
+		},
+		{
+			&PluginConstraints{
+				Versions: ConstraintStr(">1.0.0").MustParse(),
+			},
+			"1.0.0",
+			false,
+		},
+		// This is not an exhaustive test because the callees
+		// already have plentiful tests of their own.
+	}
+
+	for i, test := range tests {
+		t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
+			version := VersionStr(test.Version).MustParse()
+			got := test.Constraints.Allows(version)
+			if got != test.Want {
+				t.Logf("looking for %s in %#v", test.Version, test.Constraints)
+				t.Errorf("wrong result %#v; want %#v", got, test.Want)
+			}
+		})
+	}
+}
+
+func TestPluginConstraintsAcceptsSHA256(t *testing.T) {
+	mustUnhex := func(hex string) (ret []byte) {
+		_, err := fmt.Sscanf(hex, "%x", &ret)
+		if err != nil {
+			panic(err)
+		}
+		return ret
+	}
+
+	tests := []struct {
+		Constraints *PluginConstraints
+		Digest      []byte
+		Want        bool
+	}{
+		{
+			&PluginConstraints{
+				Versions: AllVersions,
+				SHA256:   mustUnhex("0123456789abcdef"),
+			},
+			mustUnhex("0123456789abcdef"),
+			true,
+		},
+		{
+			&PluginConstraints{
+				Versions: AllVersions,
+				SHA256:   mustUnhex("0123456789abcdef"),
+			},
+			mustUnhex("f00dface"),
+			false,
+		},
+		{
+			&PluginConstraints{
+				Versions: AllVersions,
+				SHA256:   nil,
+			},
+			mustUnhex("f00dface"),
+			true,
+		},
+	}
+
+	for i, test := range tests {
+		t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
+			got := test.Constraints.AcceptsSHA256(test.Digest)
+			if got != test.Want {
+				t.Logf("%#v.AcceptsSHA256(%#v)", test.Constraints, test.Digest)
+				t.Errorf("wrong result %#v; want %#v", got, test.Want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-bar_v0.0.1 b/v1.5.7/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-bar_v0.0.1
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-bar_v0.0.1
diff --git a/v1.5.7/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-bar_v1.0.0.exe b/v1.5.7/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-bar_v1.0.0.exe
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-bar_v1.0.0.exe
diff --git a/v1.5.7/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-missing-version b/v1.5.7/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-missing-version
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-missing-version
diff --git a/v1.5.7/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-notfoo-bar_v0.0.1 b/v1.5.7/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-notfoo-bar_v0.0.1
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-notfoo-bar_v0.0.1
diff --git a/v1.5.7/internal/plugin/discovery/testdata/legacy-style-plugins/terraform-foo-bar b/v1.5.7/internal/plugin/discovery/testdata/legacy-style-plugins/terraform-foo-bar
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/testdata/legacy-style-plugins/terraform-foo-bar
diff --git a/v1.5.7/internal/plugin/discovery/testdata/legacy-style-plugins/terraform-foo-baz b/v1.5.7/internal/plugin/discovery/testdata/legacy-style-plugins/terraform-foo-baz
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/testdata/legacy-style-plugins/terraform-foo-baz
diff --git a/v1.5.7/internal/plugin/discovery/testdata/legacy-style-plugins/terraform-notfoo-bar b/v1.5.7/internal/plugin/discovery/testdata/legacy-style-plugins/terraform-notfoo-bar
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/testdata/legacy-style-plugins/terraform-notfoo-bar
diff --git a/v1.5.7/internal/plugin/discovery/testdata/not-a-dir b/v1.5.7/internal/plugin/discovery/testdata/not-a-dir
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/testdata/not-a-dir
diff --git a/v1.5.7/internal/plugin/discovery/testdata/plugin-cache/terraform-provider-foo_v0.0.1_x4 b/v1.5.7/internal/plugin/discovery/testdata/plugin-cache/terraform-provider-foo_v0.0.1_x4
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/testdata/plugin-cache/terraform-provider-foo_v0.0.1_x4
diff --git a/v1.5.7/internal/plugin/discovery/version.go b/v1.5.7/internal/plugin/discovery/version.go
new file mode 100644
index 0000000..1cc7a40
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/version.go
@@ -0,0 +1,80 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package discovery
+
+import (
+	"fmt"
+	"sort"
+
+	version "github.com/hashicorp/go-version"
+)
+
+const VersionZero = "0.0.0"
+
+// A VersionStr is a string containing a possibly-invalid representation
+// of a semver version number. Call Parse on it to obtain a real Version
+// object, or discover that it is invalid.
+type VersionStr string
+
+// Parse transforms a VersionStr into a Version if it is
+// syntactically valid. If it isn't then an error is returned instead.
+func (s VersionStr) Parse() (Version, error) {
+	raw, err := version.NewVersion(string(s))
+	if err != nil {
+		return Version{}, err
+	}
+	return Version{raw}, nil
+}
+
+// MustParse transforms a VersionStr into a Version if it is
+// syntactically valid. If it isn't then it panics.
+func (s VersionStr) MustParse() Version {
+	ret, err := s.Parse()
+	if err != nil {
+		panic(err)
+	}
+	return ret
+}
+
+// Version represents a version number that has been parsed from
+// a semver string and known to be valid.
+type Version struct {
+	// We wrap this here just because it avoids a proliferation of
+	// direct go-version imports all over the place, and keeps the
+	// version-processing details within this package.
+	raw *version.Version
+}
+
+func (v Version) String() string {
+	return v.raw.String()
+}
+
+func (v Version) NewerThan(other Version) bool {
+	return v.raw.GreaterThan(other.raw)
+}
+
+func (v Version) Equal(other Version) bool {
+	return v.raw.Equal(other.raw)
+}
+
+// IsPrerelease determines if version is a prerelease
+func (v Version) IsPrerelease() bool {
+	return v.raw.Prerelease() != ""
+}
+
+// MinorUpgradeConstraintStr returns a ConstraintStr that would permit
+// minor upgrades relative to the receiving version.
+func (v Version) MinorUpgradeConstraintStr() ConstraintStr {
+	segments := v.raw.Segments()
+	return ConstraintStr(fmt.Sprintf("~> %d.%d", segments[0], segments[1]))
+}
+
+type Versions []Version
+
+// Sort sorts version from newest to oldest.
+func (v Versions) Sort() {
+	sort.Slice(v, func(i, j int) bool {
+		return v[i].NewerThan(v[j])
+	})
+}
diff --git a/v1.5.7/internal/plugin/discovery/version_set.go b/v1.5.7/internal/plugin/discovery/version_set.go
new file mode 100644
index 0000000..2876bfe
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/version_set.go
@@ -0,0 +1,92 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package discovery
+
+import (
+	"sort"
+
+	version "github.com/hashicorp/go-version"
+)
+
+// A ConstraintStr is a string containing a possibly-invalid representation
+// of a version constraint provided in configuration. Call Parse on it to
+// obtain a real Constraint object, or discover that it is invalid.
+type ConstraintStr string
+
+// Parse transforms a ConstraintStr into a Constraints if it is
+// syntactically valid. If it isn't then an error is returned instead.
+func (s ConstraintStr) Parse() (Constraints, error) {
+	raw, err := version.NewConstraint(string(s))
+	if err != nil {
+		return Constraints{}, err
+	}
+	return Constraints{raw}, nil
+}
+
+// MustParse is like Parse but it panics if the constraint string is invalid.
+func (s ConstraintStr) MustParse() Constraints {
+	ret, err := s.Parse()
+	if err != nil {
+		panic(err)
+	}
+	return ret
+}
+
+// Constraints represents a set of versions which any given Version is either
+// a member of or not.
+type Constraints struct {
+	raw version.Constraints
+}
+
+// NewConstraints creates a Constraints based on a version.Constraints.
+func NewConstraints(c version.Constraints) Constraints {
+	return Constraints{c}
+}
+
+// AllVersions is a Constraints containing all versions
+var AllVersions Constraints
+
+func init() {
+	AllVersions = Constraints{
+		raw: make(version.Constraints, 0),
+	}
+}
+
+// Allows returns true if the given version permitted by the receiving
+// constraints set.
+func (s Constraints) Allows(v Version) bool {
+	return s.raw.Check(v.raw)
+}
+
+// Append combines the receiving set with the given other set to produce
+// a set that is the intersection of both sets, which is to say that resulting
+// constraints contain only the versions that are members of both.
+func (s Constraints) Append(other Constraints) Constraints {
+	raw := make(version.Constraints, 0, len(s.raw)+len(other.raw))
+
+	// Since "raw" is a list of constraints that remove versions from the set,
+	// "Intersection" is implemented by concatenating together those lists,
+	// thus leaving behind only the versions not removed by either list.
+	raw = append(raw, s.raw...)
+	raw = append(raw, other.raw...)
+
+	// while the set is unordered, we sort these lexically for consistent output
+	sort.Slice(raw, func(i, j int) bool {
+		return raw[i].String() < raw[j].String()
+	})
+
+	return Constraints{raw}
+}
+
+// String returns a string representation of the set members as a set
+// of range constraints.
+func (s Constraints) String() string {
+	return s.raw.String()
+}
+
+// Unconstrained returns true if and only if the receiver is an empty
+// constraint set.
+func (s Constraints) Unconstrained() bool {
+	return len(s.raw) == 0
+}
diff --git a/v1.5.7/internal/plugin/discovery/version_set_test.go b/v1.5.7/internal/plugin/discovery/version_set_test.go
new file mode 100644
index 0000000..bfda4a5
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/version_set_test.go
@@ -0,0 +1,77 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package discovery
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestVersionSet(t *testing.T) {
+	tests := []struct {
+		ConstraintStr string
+		VersionStr    string
+		ShouldHave    bool
+	}{
+		// These test cases are not exhaustive since the underlying go-version
+		// library is well-tested. This is mainly here just to exercise our
+		// wrapper code, but also used as an opportunity to cover some basic
+		// but important cases such as the ~> constraint so that we'll be more
+		// likely to catch any accidental breaking behavior changes in the
+		// underlying library.
+		{
+			">=1.0.0",
+			"1.0.0",
+			true,
+		},
+		{
+			">=1.0.0",
+			"0.0.0",
+			false,
+		},
+		{
+			">=1.0.0",
+			"1.1.0-beta1",
+			false,
+		},
+		{
+			">=1.0.0",
+			"1.1.0",
+			true,
+		},
+		{
+			"~>1.1.0-a",
+			"1.1.0-beta1",
+			true,
+		},
+		{
+			"~>1.1.0",
+			"1.1.2",
+			true,
+		},
+		{
+			"~>1.1.0",
+			"1.2.0",
+			false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%s has %s", test.ConstraintStr, test.VersionStr), func(t *testing.T) {
+			accepted, err := ConstraintStr(test.ConstraintStr).Parse()
+			if err != nil {
+				t.Fatalf("unwanted error parsing constraints string %q: %s", test.ConstraintStr, err)
+			}
+
+			version, err := VersionStr(test.VersionStr).Parse()
+			if err != nil {
+				t.Fatalf("unwanted error parsing version string %q: %s", test.VersionStr, err)
+			}
+
+			if got, want := accepted.Allows(version), test.ShouldHave; got != want {
+				t.Errorf("Has returned %#v; want %#v", got, want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/plugin/discovery/version_test.go b/v1.5.7/internal/plugin/discovery/version_test.go
new file mode 100644
index 0000000..33ba66c
--- /dev/null
+++ b/v1.5.7/internal/plugin/discovery/version_test.go
@@ -0,0 +1,42 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package discovery
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestSortVersions(t *testing.T) {
+	versions := Versions{
+		VersionStr("4").MustParse(),
+		VersionStr("3.1").MustParse(),
+		VersionStr("1.2").MustParse(),
+		VersionStr("1.2.3").MustParse(),
+		VersionStr("2.2.3").MustParse(),
+		VersionStr("3.2.1").MustParse(),
+		VersionStr("2.3.2").MustParse(),
+	}
+
+	expected := []string{
+		"4.0.0",
+		"3.2.1",
+		"3.1.0",
+		"2.3.2",
+		"2.2.3",
+		"1.2.3",
+		"1.2.0",
+	}
+
+	versions.Sort()
+
+	var sorted []string
+	for _, v := range versions {
+		sorted = append(sorted, v.String())
+	}
+
+	if !reflect.DeepEqual(sorted, expected) {
+		t.Fatal("versions aren't sorted:", sorted)
+	}
+}
diff --git a/v1.5.7/internal/plugin/grpc_error.go b/v1.5.7/internal/plugin/grpc_error.go
new file mode 100644
index 0000000..17daf0a
--- /dev/null
+++ b/v1.5.7/internal/plugin/grpc_error.go
@@ -0,0 +1,77 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin
+
+import (
+	"fmt"
+	"path"
+	"runtime"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+)
+
+// grpcErr extracts some known error types and formats them into better
+// representations for core. This must only be called from plugin methods.
+// Since we don't use RPC status errors for the plugin protocol, these do not
+// contain any useful details, and we can return some text that at least
+// indicates the plugin call and possible error condition.
+func grpcErr(err error) (diags tfdiags.Diagnostics) {
+	if err == nil {
+		return
+	}
+
+	// extract the method name from the caller.
+	pc, _, _, ok := runtime.Caller(1)
+	if !ok {
+		logger.Error("unknown grpc call", "error", err)
+		return diags.Append(err)
+	}
+
+	f := runtime.FuncForPC(pc)
+
+	// Function names will contain the full import path. Take the last
+	// segment, which will let users know which method was being called.
+	_, requestName := path.Split(f.Name())
+
+	// Here we can at least correlate the error in the logs to a particular binary.
+	logger.Error(requestName, "error", err)
+
+	// TODO: while this expands the error codes into somewhat better messages,
+	// this still does not easily link the error to an actual user-recognizable
+	// plugin. The grpc plugin does not know its configured name, and the
+	// errors are in a list of diagnostics, making it hard for the caller to
+	// annotate the returned errors.
+	switch status.Code(err) {
+	case codes.Unavailable:
+		// This case is when the plugin has stopped running for some reason,
+		// and is usually the result of a crash.
+		diags = diags.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"Plugin did not respond",
+			fmt.Sprintf("The plugin encountered an error, and failed to respond to the %s call. "+
+				"The plugin logs may contain more details.", requestName),
+		))
+	case codes.Canceled:
+		diags = diags.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"Request cancelled",
+			fmt.Sprintf("The %s request was cancelled.", requestName),
+		))
+	case codes.Unimplemented:
+		diags = diags.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"Unsupported plugin method",
+			fmt.Sprintf("The %s method is not supported by this plugin.", requestName),
+		))
+	default:
+		diags = diags.Append(tfdiags.WholeContainingBody(
+			tfdiags.Error,
+			"Plugin error",
+			fmt.Sprintf("The plugin returned an unexpected error from %s: %v", requestName, err),
+		))
+	}
+	return
+}
diff --git a/v1.5.7/internal/plugin/grpc_provider.go b/v1.5.7/internal/plugin/grpc_provider.go
new file mode 100644
index 0000000..11098e2
--- /dev/null
+++ b/v1.5.7/internal/plugin/grpc_provider.go
@@ -0,0 +1,700 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"sync"
+
+	"github.com/zclconf/go-cty/cty"
+
+	plugin "github.com/hashicorp/go-plugin"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/plugin/convert"
+	"github.com/hashicorp/terraform/internal/providers"
+	proto "github.com/hashicorp/terraform/internal/tfplugin5"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+	"github.com/zclconf/go-cty/cty/msgpack"
+	"google.golang.org/grpc"
+)
+
+var logger = logging.HCLogger()
+
+// GRPCProviderPlugin implements plugin.GRPCPlugin for the go-plugin package.
+type GRPCProviderPlugin struct {
+	plugin.Plugin
+	GRPCProvider func() proto.ProviderServer
+}
+
+func (p *GRPCProviderPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
+	return &GRPCProvider{
+		client: proto.NewProviderClient(c),
+		ctx:    ctx,
+	}, nil
+}
+
+func (p *GRPCProviderPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
+	proto.RegisterProviderServer(s, p.GRPCProvider())
+	return nil
+}
+
+// GRPCProvider handles the client, or core side of the plugin rpc connection.
+// The GRPCProvider methods are mostly a translation layer between the
+// terraform providers types and the grpc proto types, directly converting
+// between the two.
+type GRPCProvider struct {
+	// PluginClient provides a reference to the plugin.Client which controls the plugin process.
+	// This allows the GRPCProvider a way to shutdown the plugin process.
+	PluginClient *plugin.Client
+
+	// TestServer contains a grpc.Server to close when the GRPCProvider is being
+	// used in an end to end test of a provider.
+	TestServer *grpc.Server
+
+	// Proto client use to make the grpc service calls.
+	client proto.ProviderClient
+
+	// this context is created by the plugin package, and is canceled when the
+	// plugin process ends.
+	ctx context.Context
+
+	// schema stores the schema for this provider. This is used to properly
+	// serialize the state for requests.
+	mu      sync.Mutex
+	schemas providers.GetProviderSchemaResponse
+}
+
+// getSchema is used internally to get the cached provider schema
+func (p *GRPCProvider) getSchema() providers.GetProviderSchemaResponse {
+	p.mu.Lock()
+	// unlock inline in case GetSchema needs to be called
+	if p.schemas.Provider.Block != nil {
+		p.mu.Unlock()
+		return p.schemas
+	}
+	p.mu.Unlock()
+
+	return p.GetProviderSchema()
+}
+
+func (p *GRPCProvider) GetProviderSchema() (resp providers.GetProviderSchemaResponse) {
+	logger.Trace("GRPCProvider: GetProviderSchema")
+	p.mu.Lock()
+	defer p.mu.Unlock()
+
+	if p.schemas.Provider.Block != nil {
+		return p.schemas
+	}
+
+	resp.ResourceTypes = make(map[string]providers.Schema)
+	resp.DataSources = make(map[string]providers.Schema)
+
+	// Some providers may generate quite large schemas, and the internal default
+	// grpc response size limit is 4MB. 64MB should cover most any use case, and
+	// if we get providers nearing that we may want to consider a finer-grained
+	// API to fetch individual resource schemas.
+	// Note: this option is marked as EXPERIMENTAL in the grpc API. We keep
+	// this for compatibility, but recent providers all set the max message
+	// size much higher on the server side, which is the supported method for
+	// determining payload size.
+	const maxRecvSize = 64 << 20
+	protoResp, err := p.client.GetSchema(p.ctx, new(proto.GetProviderSchema_Request), grpc.MaxRecvMsgSizeCallOption{MaxRecvMsgSize: maxRecvSize})
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+
+	if resp.Diagnostics.HasErrors() {
+		return resp
+	}
+
+	if protoResp.Provider == nil {
+		resp.Diagnostics = resp.Diagnostics.Append(errors.New("missing provider schema"))
+		return resp
+	}
+
+	resp.Provider = convert.ProtoToProviderSchema(protoResp.Provider)
+	if protoResp.ProviderMeta == nil {
+		logger.Debug("No provider meta schema returned")
+	} else {
+		resp.ProviderMeta = convert.ProtoToProviderSchema(protoResp.ProviderMeta)
+	}
+
+	for name, res := range protoResp.ResourceSchemas {
+		resp.ResourceTypes[name] = convert.ProtoToProviderSchema(res)
+	}
+
+	for name, data := range protoResp.DataSourceSchemas {
+		resp.DataSources[name] = convert.ProtoToProviderSchema(data)
+	}
+
+	if protoResp.ServerCapabilities != nil {
+		resp.ServerCapabilities.PlanDestroy = protoResp.ServerCapabilities.PlanDestroy
+	}
+
+	p.schemas = resp
+
+	return resp
+}
+
+func (p *GRPCProvider) ValidateProviderConfig(r providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
+	logger.Trace("GRPCProvider: ValidateProviderConfig")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	ty := schema.Provider.Block.ImpliedType()
+
+	mp, err := msgpack.Marshal(r.Config, ty)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto.PrepareProviderConfig_Request{
+		Config: &proto.DynamicValue{Msgpack: mp},
+	}
+
+	protoResp, err := p.client.PrepareProviderConfig(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+
+	config, err := decodeDynamicValue(protoResp.PreparedConfig, ty)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+	resp.PreparedConfig = config
+
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+	return resp
+}
+
+func (p *GRPCProvider) ValidateResourceConfig(r providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
+	logger.Trace("GRPCProvider: ValidateResourceConfig")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	resourceSchema, ok := schema.ResourceTypes[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type %q", r.TypeName))
+		return resp
+	}
+
+	mp, err := msgpack.Marshal(r.Config, resourceSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto.ValidateResourceTypeConfig_Request{
+		TypeName: r.TypeName,
+		Config:   &proto.DynamicValue{Msgpack: mp},
+	}
+
+	protoResp, err := p.client.ValidateResourceTypeConfig(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+	return resp
+}
+
+func (p *GRPCProvider) ValidateDataResourceConfig(r providers.ValidateDataResourceConfigRequest) (resp providers.ValidateDataResourceConfigResponse) {
+	logger.Trace("GRPCProvider: ValidateDataResourceConfig")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	dataSchema, ok := schema.DataSources[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown data source %q", r.TypeName))
+		return resp
+	}
+
+	mp, err := msgpack.Marshal(r.Config, dataSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto.ValidateDataSourceConfig_Request{
+		TypeName: r.TypeName,
+		Config:   &proto.DynamicValue{Msgpack: mp},
+	}
+
+	protoResp, err := p.client.ValidateDataSourceConfig(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+	return resp
+}
+
+func (p *GRPCProvider) UpgradeResourceState(r providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
+	logger.Trace("GRPCProvider: UpgradeResourceState")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	resSchema, ok := schema.ResourceTypes[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type %q", r.TypeName))
+		return resp
+	}
+
+	protoReq := &proto.UpgradeResourceState_Request{
+		TypeName: r.TypeName,
+		Version:  int64(r.Version),
+		RawState: &proto.RawState{
+			Json:    r.RawStateJSON,
+			Flatmap: r.RawStateFlatmap,
+		},
+	}
+
+	protoResp, err := p.client.UpgradeResourceState(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+
+	ty := resSchema.Block.ImpliedType()
+	resp.UpgradedState = cty.NullVal(ty)
+	if protoResp.UpgradedState == nil {
+		return resp
+	}
+
+	state, err := decodeDynamicValue(protoResp.UpgradedState, ty)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+	resp.UpgradedState = state
+
+	return resp
+}
+
+func (p *GRPCProvider) ConfigureProvider(r providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+	logger.Trace("GRPCProvider: ConfigureProvider")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	var mp []byte
+
+	// we don't have anything to marshal if there's no config
+	mp, err := msgpack.Marshal(r.Config, schema.Provider.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto.Configure_Request{
+		TerraformVersion: r.TerraformVersion,
+		Config: &proto.DynamicValue{
+			Msgpack: mp,
+		},
+	}
+
+	protoResp, err := p.client.Configure(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+	return resp
+}
+
+func (p *GRPCProvider) Stop() error {
+	logger.Trace("GRPCProvider: Stop")
+
+	resp, err := p.client.Stop(p.ctx, new(proto.Stop_Request))
+	if err != nil {
+		return err
+	}
+
+	if resp.Error != "" {
+		return errors.New(resp.Error)
+	}
+	return nil
+}
+
+func (p *GRPCProvider) ReadResource(r providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+	logger.Trace("GRPCProvider: ReadResource")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	resSchema, ok := schema.ResourceTypes[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type " + r.TypeName))
+		return resp
+	}
+
+	metaSchema := schema.ProviderMeta
+
+	mp, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto.ReadResource_Request{
+		TypeName:     r.TypeName,
+		CurrentState: &proto.DynamicValue{Msgpack: mp},
+		Private:      r.Private,
+	}
+
+	if metaSchema.Block != nil {
+		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
+		if err != nil {
+			resp.Diagnostics = resp.Diagnostics.Append(err)
+			return resp
+		}
+		protoReq.ProviderMeta = &proto.DynamicValue{Msgpack: metaMP}
+	}
+
+	protoResp, err := p.client.ReadResource(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+
+	state, err := decodeDynamicValue(protoResp.NewState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+	resp.NewState = state
+	resp.Private = protoResp.Private
+
+	return resp
+}
+
+func (p *GRPCProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+	logger.Trace("GRPCProvider: PlanResourceChange")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	resSchema, ok := schema.ResourceTypes[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type %q", r.TypeName))
+		return resp
+	}
+
+	metaSchema := schema.ProviderMeta
+	capabilities := schema.ServerCapabilities
+
+	// If the provider doesn't support planning a destroy operation, we can
+	// return immediately.
+	if r.ProposedNewState.IsNull() && !capabilities.PlanDestroy {
+		resp.PlannedState = r.ProposedNewState
+		resp.PlannedPrivate = r.PriorPrivate
+		return resp
+	}
+
+	priorMP, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	configMP, err := msgpack.Marshal(r.Config, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	propMP, err := msgpack.Marshal(r.ProposedNewState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto.PlanResourceChange_Request{
+		TypeName:         r.TypeName,
+		PriorState:       &proto.DynamicValue{Msgpack: priorMP},
+		Config:           &proto.DynamicValue{Msgpack: configMP},
+		ProposedNewState: &proto.DynamicValue{Msgpack: propMP},
+		PriorPrivate:     r.PriorPrivate,
+	}
+
+	if metaSchema.Block != nil {
+		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
+		if err != nil {
+			resp.Diagnostics = resp.Diagnostics.Append(err)
+			return resp
+		}
+		protoReq.ProviderMeta = &proto.DynamicValue{Msgpack: metaMP}
+	}
+
+	protoResp, err := p.client.PlanResourceChange(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+
+	state, err := decodeDynamicValue(protoResp.PlannedState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+	resp.PlannedState = state
+
+	for _, p := range protoResp.RequiresReplace {
+		resp.RequiresReplace = append(resp.RequiresReplace, convert.AttributePathToPath(p))
+	}
+
+	resp.PlannedPrivate = protoResp.PlannedPrivate
+
+	resp.LegacyTypeSystem = protoResp.LegacyTypeSystem
+
+	return resp
+}
+
+func (p *GRPCProvider) ApplyResourceChange(r providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+	logger.Trace("GRPCProvider: ApplyResourceChange")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	resSchema, ok := schema.ResourceTypes[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type %q", r.TypeName))
+		return resp
+	}
+
+	metaSchema := schema.ProviderMeta
+
+	priorMP, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+	plannedMP, err := msgpack.Marshal(r.PlannedState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+	configMP, err := msgpack.Marshal(r.Config, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto.ApplyResourceChange_Request{
+		TypeName:       r.TypeName,
+		PriorState:     &proto.DynamicValue{Msgpack: priorMP},
+		PlannedState:   &proto.DynamicValue{Msgpack: plannedMP},
+		Config:         &proto.DynamicValue{Msgpack: configMP},
+		PlannedPrivate: r.PlannedPrivate,
+	}
+
+	if metaSchema.Block != nil {
+		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
+		if err != nil {
+			resp.Diagnostics = resp.Diagnostics.Append(err)
+			return resp
+		}
+		protoReq.ProviderMeta = &proto.DynamicValue{Msgpack: metaMP}
+	}
+
+	protoResp, err := p.client.ApplyResourceChange(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+
+	resp.Private = protoResp.Private
+
+	state, err := decodeDynamicValue(protoResp.NewState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+	resp.NewState = state
+
+	resp.LegacyTypeSystem = protoResp.LegacyTypeSystem
+
+	return resp
+}
+
+func (p *GRPCProvider) ImportResourceState(r providers.ImportResourceStateRequest) (resp providers.ImportResourceStateResponse) {
+	logger.Trace("GRPCProvider: ImportResourceState")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	protoReq := &proto.ImportResourceState_Request{
+		TypeName: r.TypeName,
+		Id:       r.ID,
+	}
+
+	protoResp, err := p.client.ImportResourceState(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+
+	for _, imported := range protoResp.ImportedResources {
+		resource := providers.ImportedResource{
+			TypeName: imported.TypeName,
+			Private:  imported.Private,
+		}
+
+		resSchema, ok := schema.ResourceTypes[r.TypeName]
+		if !ok {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type %q", r.TypeName))
+			continue
+		}
+
+		state, err := decodeDynamicValue(imported.State, resSchema.Block.ImpliedType())
+		if err != nil {
+			resp.Diagnostics = resp.Diagnostics.Append(err)
+			return resp
+		}
+		resource.State = state
+		resp.ImportedResources = append(resp.ImportedResources, resource)
+	}
+
+	return resp
+}
+
+func (p *GRPCProvider) ReadDataSource(r providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+	logger.Trace("GRPCProvider: ReadDataSource")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	dataSchema, ok := schema.DataSources[r.TypeName]
+	if !ok {
+		schema.Diagnostics = schema.Diagnostics.Append(fmt.Errorf("unknown data source %q", r.TypeName))
+	}
+
+	metaSchema := schema.ProviderMeta
+
+	config, err := msgpack.Marshal(r.Config, dataSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto.ReadDataSource_Request{
+		TypeName: r.TypeName,
+		Config: &proto.DynamicValue{
+			Msgpack: config,
+		},
+	}
+
+	if metaSchema.Block != nil {
+		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
+		if err != nil {
+			resp.Diagnostics = resp.Diagnostics.Append(err)
+			return resp
+		}
+		protoReq.ProviderMeta = &proto.DynamicValue{Msgpack: metaMP}
+	}
+
+	protoResp, err := p.client.ReadDataSource(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+
+	state, err := decodeDynamicValue(protoResp.State, dataSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+	resp.State = state
+
+	return resp
+}
+
+// closing the grpc connection is final, and terraform will call it at the end of every phase.
+func (p *GRPCProvider) Close() error {
+	logger.Trace("GRPCProvider: Close")
+
+	// Make sure to stop the server if we're not running within go-plugin.
+	if p.TestServer != nil {
+		p.TestServer.Stop()
+	}
+
+	// Check this since it's not automatically inserted during plugin creation.
+	// It's currently only inserted by the command package, because that is
+	// where the factory is built and is the only point with access to the
+	// plugin.Client.
+	if p.PluginClient == nil {
+		logger.Debug("provider has no plugin.Client")
+		return nil
+	}
+
+	p.PluginClient.Kill()
+	return nil
+}
+
+// Decode a DynamicValue from either the JSON or MsgPack encoding.
+func decodeDynamicValue(v *proto.DynamicValue, ty cty.Type) (cty.Value, error) {
+	// always return a valid value
+	var err error
+	res := cty.NullVal(ty)
+	if v == nil {
+		return res, nil
+	}
+
+	switch {
+	case len(v.Msgpack) > 0:
+		res, err = msgpack.Unmarshal(v.Msgpack, ty)
+	case len(v.Json) > 0:
+		res, err = ctyjson.Unmarshal(v.Json, ty)
+	}
+	return res, err
+}
diff --git a/v1.5.7/internal/plugin/grpc_provider_test.go b/v1.5.7/internal/plugin/grpc_provider_test.go
new file mode 100644
index 0000000..beeee87
--- /dev/null
+++ b/v1.5.7/internal/plugin/grpc_provider_test.go
@@ -0,0 +1,780 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+
+	mockproto "github.com/hashicorp/terraform/internal/plugin/mock_proto"
+	proto "github.com/hashicorp/terraform/internal/tfplugin5"
+)
+
+var _ providers.Interface = (*GRPCProvider)(nil)
+
+func mockProviderClient(t *testing.T) *mockproto.MockProviderClient {
+	ctrl := gomock.NewController(t)
+	client := mockproto.NewMockProviderClient(ctrl)
+
+	// we always need a GetSchema method
+	client.EXPECT().GetSchema(
+		gomock.Any(),
+		gomock.Any(),
+		gomock.Any(),
+	).Return(providerProtoSchema(), nil)
+
+	return client
+}
+
+func checkDiags(t *testing.T, d tfdiags.Diagnostics) {
+	t.Helper()
+	if d.HasErrors() {
+		t.Fatal(d.Err())
+	}
+}
+
+// checkDiagsHasError ensures error diagnostics are present or fails the test.
+func checkDiagsHasError(t *testing.T, d tfdiags.Diagnostics) {
+	t.Helper()
+
+	if !d.HasErrors() {
+		t.Fatal("expected error diagnostics")
+	}
+}
+
+func providerProtoSchema() *proto.GetProviderSchema_Response {
+	return &proto.GetProviderSchema_Response{
+		Provider: &proto.Schema{
+			Block: &proto.Schema_Block{
+				Attributes: []*proto.Schema_Attribute{
+					{
+						Name:     "attr",
+						Type:     []byte(`"string"`),
+						Required: true,
+					},
+				},
+			},
+		},
+		ResourceSchemas: map[string]*proto.Schema{
+			"resource": &proto.Schema{
+				Version: 1,
+				Block: &proto.Schema_Block{
+					Attributes: []*proto.Schema_Attribute{
+						{
+							Name:     "attr",
+							Type:     []byte(`"string"`),
+							Required: true,
+						},
+					},
+				},
+			},
+		},
+		DataSourceSchemas: map[string]*proto.Schema{
+			"data": &proto.Schema{
+				Version: 1,
+				Block: &proto.Schema_Block{
+					Attributes: []*proto.Schema_Attribute{
+						{
+							Name:     "attr",
+							Type:     []byte(`"string"`),
+							Required: true,
+						},
+					},
+				},
+			},
+		},
+	}
+}
+
+func TestGRPCProvider_GetSchema(t *testing.T) {
+	p := &GRPCProvider{
+		client: mockProviderClient(t),
+	}
+
+	resp := p.GetProviderSchema()
+	checkDiags(t, resp.Diagnostics)
+}
+
+// Ensure that gRPC errors are returned early.
+// Reference: https://github.com/hashicorp/terraform/issues/31047
+func TestGRPCProvider_GetSchema_GRPCError(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	client := mockproto.NewMockProviderClient(ctrl)
+
+	client.EXPECT().GetSchema(
+		gomock.Any(),
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.GetProviderSchema_Response{}, fmt.Errorf("test error"))
+
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	resp := p.GetProviderSchema()
+
+	checkDiagsHasError(t, resp.Diagnostics)
+}
+
+// Ensure that provider error diagnostics are returned early.
+// Reference: https://github.com/hashicorp/terraform/issues/31047
+func TestGRPCProvider_GetSchema_ResponseErrorDiagnostic(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	client := mockproto.NewMockProviderClient(ctrl)
+
+	client.EXPECT().GetSchema(
+		gomock.Any(),
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.GetProviderSchema_Response{
+		Diagnostics: []*proto.Diagnostic{
+			{
+				Severity: proto.Diagnostic_ERROR,
+				Summary:  "error summary",
+				Detail:   "error detail",
+			},
+		},
+		// Trigger potential panics
+		Provider: &proto.Schema{},
+	}, nil)
+
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	resp := p.GetProviderSchema()
+
+	checkDiagsHasError(t, resp.Diagnostics)
+}
+
+func TestGRPCProvider_PrepareProviderConfig(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().PrepareProviderConfig(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.PrepareProviderConfig_Response{}, nil)
+
+	cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"})
+	resp := p.ValidateProviderConfig(providers.ValidateProviderConfigRequest{Config: cfg})
+	checkDiags(t, resp.Diagnostics)
+}
+
+func TestGRPCProvider_ValidateResourceConfig(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ValidateResourceTypeConfig(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ValidateResourceTypeConfig_Response{}, nil)
+
+	cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"})
+	resp := p.ValidateResourceConfig(providers.ValidateResourceConfigRequest{
+		TypeName: "resource",
+		Config:   cfg,
+	})
+	checkDiags(t, resp.Diagnostics)
+}
+
+func TestGRPCProvider_ValidateDataSourceConfig(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ValidateDataSourceConfig(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ValidateDataSourceConfig_Response{}, nil)
+
+	cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"})
+	resp := p.ValidateDataResourceConfig(providers.ValidateDataResourceConfigRequest{
+		TypeName: "data",
+		Config:   cfg,
+	})
+	checkDiags(t, resp.Diagnostics)
+}
+
+func TestGRPCProvider_UpgradeResourceState(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().UpgradeResourceState(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.UpgradeResourceState_Response{
+		UpgradedState: &proto.DynamicValue{
+			Msgpack: []byte("\x81\xa4attr\xa3bar"),
+		},
+	}, nil)
+
+	resp := p.UpgradeResourceState(providers.UpgradeResourceStateRequest{
+		TypeName:     "resource",
+		Version:      0,
+		RawStateJSON: []byte(`{"old_attr":"bar"}`),
+	})
+	checkDiags(t, resp.Diagnostics)
+
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty))
+	}
+}
+
+func TestGRPCProvider_UpgradeResourceStateJSON(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().UpgradeResourceState(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.UpgradeResourceState_Response{
+		UpgradedState: &proto.DynamicValue{
+			Json: []byte(`{"attr":"bar"}`),
+		},
+	}, nil)
+
+	resp := p.UpgradeResourceState(providers.UpgradeResourceStateRequest{
+		TypeName:     "resource",
+		Version:      0,
+		RawStateJSON: []byte(`{"old_attr":"bar"}`),
+	})
+	checkDiags(t, resp.Diagnostics)
+
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty))
+	}
+}
+
+func TestGRPCProvider_Configure(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().Configure(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.Configure_Response{}, nil)
+
+	resp := p.ConfigureProvider(providers.ConfigureProviderRequest{
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+	})
+	checkDiags(t, resp.Diagnostics)
+}
+
+func TestGRPCProvider_Stop(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	client := mockproto.NewMockProviderClient(ctrl)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().Stop(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.Stop_Response{}, nil)
+
+	err := p.Stop()
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestGRPCProvider_ReadResource(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ReadResource(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ReadResource_Response{
+		NewState: &proto.DynamicValue{
+			Msgpack: []byte("\x81\xa4attr\xa3bar"),
+		},
+	}, nil)
+
+	resp := p.ReadResource(providers.ReadResourceRequest{
+		TypeName: "resource",
+		PriorState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty))
+	}
+}
+
+func TestGRPCProvider_ReadResourceJSON(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ReadResource(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ReadResource_Response{
+		NewState: &proto.DynamicValue{
+			Json: []byte(`{"attr":"bar"}`),
+		},
+	}, nil)
+
+	resp := p.ReadResource(providers.ReadResourceRequest{
+		TypeName: "resource",
+		PriorState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty))
+	}
+}
+
+func TestGRPCProvider_ReadEmptyJSON(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ReadResource(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ReadResource_Response{
+		NewState: &proto.DynamicValue{
+			Json: []byte(``),
+		},
+	}, nil)
+
+	obj := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("foo"),
+	})
+	resp := p.ReadResource(providers.ReadResourceRequest{
+		TypeName:   "resource",
+		PriorState: obj,
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expected := cty.NullVal(obj.Type())
+
+	if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty))
+	}
+}
+
+func TestGRPCProvider_PlanResourceChange(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	expectedPrivate := []byte(`{"meta": "data"}`)
+
+	client.EXPECT().PlanResourceChange(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.PlanResourceChange_Response{
+		PlannedState: &proto.DynamicValue{
+			Msgpack: []byte("\x81\xa4attr\xa3bar"),
+		},
+		RequiresReplace: []*proto.AttributePath{
+			{
+				Steps: []*proto.AttributePath_Step{
+					{
+						Selector: &proto.AttributePath_Step_AttributeName{
+							AttributeName: "attr",
+						},
+					},
+				},
+			},
+		},
+		PlannedPrivate: expectedPrivate,
+	}, nil)
+
+	resp := p.PlanResourceChange(providers.PlanResourceChangeRequest{
+		TypeName: "resource",
+		PriorState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+		ProposedNewState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expectedState := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty))
+	}
+
+	expectedReplace := `[]cty.Path{cty.Path{cty.GetAttrStep{Name:"attr"}}}`
+	replace := fmt.Sprintf("%#v", resp.RequiresReplace)
+	if expectedReplace != replace {
+		t.Fatalf("expected %q, got %q", expectedReplace, replace)
+	}
+
+	if !bytes.Equal(expectedPrivate, resp.PlannedPrivate) {
+		t.Fatalf("expected %q, got %q", expectedPrivate, resp.PlannedPrivate)
+	}
+}
+
+func TestGRPCProvider_PlanResourceChangeJSON(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	expectedPrivate := []byte(`{"meta": "data"}`)
+
+	client.EXPECT().PlanResourceChange(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.PlanResourceChange_Response{
+		PlannedState: &proto.DynamicValue{
+			Json: []byte(`{"attr":"bar"}`),
+		},
+		RequiresReplace: []*proto.AttributePath{
+			{
+				Steps: []*proto.AttributePath_Step{
+					{
+						Selector: &proto.AttributePath_Step_AttributeName{
+							AttributeName: "attr",
+						},
+					},
+				},
+			},
+		},
+		PlannedPrivate: expectedPrivate,
+	}, nil)
+
+	resp := p.PlanResourceChange(providers.PlanResourceChangeRequest{
+		TypeName: "resource",
+		PriorState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+		ProposedNewState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expectedState := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty))
+	}
+
+	expectedReplace := `[]cty.Path{cty.Path{cty.GetAttrStep{Name:"attr"}}}`
+	replace := fmt.Sprintf("%#v", resp.RequiresReplace)
+	if expectedReplace != replace {
+		t.Fatalf("expected %q, got %q", expectedReplace, replace)
+	}
+
+	if !bytes.Equal(expectedPrivate, resp.PlannedPrivate) {
+		t.Fatalf("expected %q, got %q", expectedPrivate, resp.PlannedPrivate)
+	}
+}
+
+func TestGRPCProvider_ApplyResourceChange(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	expectedPrivate := []byte(`{"meta": "data"}`)
+
+	client.EXPECT().ApplyResourceChange(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ApplyResourceChange_Response{
+		NewState: &proto.DynamicValue{
+			Msgpack: []byte("\x81\xa4attr\xa3bar"),
+		},
+		Private: expectedPrivate,
+	}, nil)
+
+	resp := p.ApplyResourceChange(providers.ApplyResourceChangeRequest{
+		TypeName: "resource",
+		PriorState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+		PlannedState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		PlannedPrivate: expectedPrivate,
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expectedState := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty))
+	}
+
+	if !bytes.Equal(expectedPrivate, resp.Private) {
+		t.Fatalf("expected %q, got %q", expectedPrivate, resp.Private)
+	}
+}
+func TestGRPCProvider_ApplyResourceChangeJSON(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	expectedPrivate := []byte(`{"meta": "data"}`)
+
+	client.EXPECT().ApplyResourceChange(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ApplyResourceChange_Response{
+		NewState: &proto.DynamicValue{
+			Json: []byte(`{"attr":"bar"}`),
+		},
+		Private: expectedPrivate,
+	}, nil)
+
+	resp := p.ApplyResourceChange(providers.ApplyResourceChangeRequest{
+		TypeName: "resource",
+		PriorState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+		PlannedState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		PlannedPrivate: expectedPrivate,
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expectedState := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty))
+	}
+
+	if !bytes.Equal(expectedPrivate, resp.Private) {
+		t.Fatalf("expected %q, got %q", expectedPrivate, resp.Private)
+	}
+}
+
+func TestGRPCProvider_ImportResourceState(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	expectedPrivate := []byte(`{"meta": "data"}`)
+
+	client.EXPECT().ImportResourceState(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ImportResourceState_Response{
+		ImportedResources: []*proto.ImportResourceState_ImportedResource{
+			{
+				TypeName: "resource",
+				State: &proto.DynamicValue{
+					Msgpack: []byte("\x81\xa4attr\xa3bar"),
+				},
+				Private: expectedPrivate,
+			},
+		},
+	}, nil)
+
+	resp := p.ImportResourceState(providers.ImportResourceStateRequest{
+		TypeName: "resource",
+		ID:       "foo",
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expectedResource := providers.ImportedResource{
+		TypeName: "resource",
+		State: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		Private: expectedPrivate,
+	}
+
+	imported := resp.ImportedResources[0]
+	if !cmp.Equal(expectedResource, imported, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expectedResource, imported, typeComparer, valueComparer, equateEmpty))
+	}
+}
+func TestGRPCProvider_ImportResourceStateJSON(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	expectedPrivate := []byte(`{"meta": "data"}`)
+
+	client.EXPECT().ImportResourceState(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ImportResourceState_Response{
+		ImportedResources: []*proto.ImportResourceState_ImportedResource{
+			{
+				TypeName: "resource",
+				State: &proto.DynamicValue{
+					Json: []byte(`{"attr":"bar"}`),
+				},
+				Private: expectedPrivate,
+			},
+		},
+	}, nil)
+
+	resp := p.ImportResourceState(providers.ImportResourceStateRequest{
+		TypeName: "resource",
+		ID:       "foo",
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expectedResource := providers.ImportedResource{
+		TypeName: "resource",
+		State: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		Private: expectedPrivate,
+	}
+
+	imported := resp.ImportedResources[0]
+	if !cmp.Equal(expectedResource, imported, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expectedResource, imported, typeComparer, valueComparer, equateEmpty))
+	}
+}
+
+func TestGRPCProvider_ReadDataSource(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ReadDataSource(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ReadDataSource_Response{
+		State: &proto.DynamicValue{
+			Msgpack: []byte("\x81\xa4attr\xa3bar"),
+		},
+	}, nil)
+
+	resp := p.ReadDataSource(providers.ReadDataSourceRequest{
+		TypeName: "data",
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expected, resp.State, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expected, resp.State, typeComparer, valueComparer, equateEmpty))
+	}
+}
+
+func TestGRPCProvider_ReadDataSourceJSON(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ReadDataSource(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ReadDataSource_Response{
+		State: &proto.DynamicValue{
+			Json: []byte(`{"attr":"bar"}`),
+		},
+	}, nil)
+
+	resp := p.ReadDataSource(providers.ReadDataSourceRequest{
+		TypeName: "data",
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expected, resp.State, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expected, resp.State, typeComparer, valueComparer, equateEmpty))
+	}
+}
diff --git a/v1.5.7/internal/plugin/grpc_provisioner.go b/v1.5.7/internal/plugin/grpc_provisioner.go
new file mode 100644
index 0000000..acbc5d5
--- /dev/null
+++ b/v1.5.7/internal/plugin/grpc_provisioner.go
@@ -0,0 +1,180 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin
+
+import (
+	"context"
+	"errors"
+	"io"
+	"sync"
+
+	plugin "github.com/hashicorp/go-plugin"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/plugin/convert"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	proto "github.com/hashicorp/terraform/internal/tfplugin5"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/msgpack"
+	"google.golang.org/grpc"
+)
+
+// GRPCProvisionerPlugin is the plugin.GRPCPlugin implementation.
+type GRPCProvisionerPlugin struct {
+	plugin.Plugin
+	GRPCProvisioner func() proto.ProvisionerServer
+}
+
+func (p *GRPCProvisionerPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
+	return &GRPCProvisioner{
+		client: proto.NewProvisionerClient(c),
+		ctx:    ctx,
+	}, nil
+}
+
+func (p *GRPCProvisionerPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
+	proto.RegisterProvisionerServer(s, p.GRPCProvisioner())
+	return nil
+}
+
+// provisioners.Interface grpc implementation
+type GRPCProvisioner struct {
+	// PluginClient provides a reference to the plugin.Client which controls the plugin process.
+	// This allows the GRPCProvider a way to shutdown the plugin process.
+	PluginClient *plugin.Client
+
+	client proto.ProvisionerClient
+	ctx    context.Context
+
+	// Cache the schema since we need it for serialization in each method call.
+	mu     sync.Mutex
+	schema *configschema.Block
+}
+
+func (p *GRPCProvisioner) GetSchema() (resp provisioners.GetSchemaResponse) {
+	p.mu.Lock()
+	defer p.mu.Unlock()
+
+	if p.schema != nil {
+		return provisioners.GetSchemaResponse{
+			Provisioner: p.schema,
+		}
+	}
+
+	protoResp, err := p.client.GetSchema(p.ctx, new(proto.GetProvisionerSchema_Request))
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+
+	if protoResp.Provisioner == nil {
+		resp.Diagnostics = resp.Diagnostics.Append(errors.New("missing provisioner schema"))
+		return resp
+	}
+
+	resp.Provisioner = convert.ProtoToConfigSchema(protoResp.Provisioner.Block)
+
+	p.schema = resp.Provisioner
+
+	return resp
+}
+
+func (p *GRPCProvisioner) ValidateProvisionerConfig(r provisioners.ValidateProvisionerConfigRequest) (resp provisioners.ValidateProvisionerConfigResponse) {
+	schema := p.GetSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = resp.Diagnostics.Append(schema.Diagnostics)
+		return resp
+	}
+
+	mp, err := msgpack.Marshal(r.Config, schema.Provisioner.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto.ValidateProvisionerConfig_Request{
+		Config: &proto.DynamicValue{Msgpack: mp},
+	}
+	protoResp, err := p.client.ValidateProvisionerConfig(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+	return resp
+}
+
+func (p *GRPCProvisioner) ProvisionResource(r provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+	schema := p.GetSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = resp.Diagnostics.Append(schema.Diagnostics)
+		return resp
+	}
+
+	mp, err := msgpack.Marshal(r.Config, schema.Provisioner.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	// connection is always assumed to be a simple string map
+	connMP, err := msgpack.Marshal(r.Connection, cty.Map(cty.String))
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto.ProvisionResource_Request{
+		Config:     &proto.DynamicValue{Msgpack: mp},
+		Connection: &proto.DynamicValue{Msgpack: connMP},
+	}
+
+	outputClient, err := p.client.ProvisionResource(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+
+	for {
+		rcv, err := outputClient.Recv()
+		if rcv != nil {
+			r.UIOutput.Output(rcv.Output)
+		}
+		if err != nil {
+			if err != io.EOF {
+				resp.Diagnostics = resp.Diagnostics.Append(err)
+			}
+			break
+		}
+
+		if len(rcv.Diagnostics) > 0 {
+			resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(rcv.Diagnostics))
+			break
+		}
+	}
+
+	return resp
+}
+
+func (p *GRPCProvisioner) Stop() error {
+	protoResp, err := p.client.Stop(p.ctx, &proto.Stop_Request{})
+	if err != nil {
+		return err
+	}
+	if protoResp.Error != "" {
+		return errors.New(protoResp.Error)
+	}
+	return nil
+}
+
+func (p *GRPCProvisioner) Close() error {
+	// check this since it's not automatically inserted during plugin creation
+	if p.PluginClient == nil {
+		logger.Debug("provisioner has no plugin.Client")
+		return nil
+	}
+
+	p.PluginClient.Kill()
+	return nil
+}
diff --git a/v1.5.7/internal/plugin/grpc_provisioner_test.go b/v1.5.7/internal/plugin/grpc_provisioner_test.go
new file mode 100644
index 0000000..1822a0e
--- /dev/null
+++ b/v1.5.7/internal/plugin/grpc_provisioner_test.go
@@ -0,0 +1,150 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin
+
+import (
+	"io"
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	proto "github.com/hashicorp/terraform/internal/tfplugin5"
+	"github.com/zclconf/go-cty/cty"
+
+	mockproto "github.com/hashicorp/terraform/internal/plugin/mock_proto"
+)
+
+var _ provisioners.Interface = (*GRPCProvisioner)(nil)
+
+var (
+	equateEmpty   = cmpopts.EquateEmpty()
+	typeComparer  = cmp.Comparer(cty.Type.Equals)
+	valueComparer = cmp.Comparer(cty.Value.RawEquals)
+)
+
+func mockProvisionerClient(t *testing.T) *mockproto.MockProvisionerClient {
+	ctrl := gomock.NewController(t)
+	client := mockproto.NewMockProvisionerClient(ctrl)
+
+	// we always need a GetSchema method
+	client.EXPECT().GetSchema(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(provisionerProtoSchema(), nil)
+
+	return client
+}
+
+func provisionerProtoSchema() *proto.GetProvisionerSchema_Response {
+	return &proto.GetProvisionerSchema_Response{
+		Provisioner: &proto.Schema{
+			Block: &proto.Schema_Block{
+				Attributes: []*proto.Schema_Attribute{
+					{
+						Name:     "attr",
+						Type:     []byte(`"string"`),
+						Required: true,
+					},
+				},
+			},
+		},
+	}
+}
+
+func TestGRPCProvisioner_GetSchema(t *testing.T) {
+	p := &GRPCProvisioner{
+		client: mockProvisionerClient(t),
+	}
+
+	resp := p.GetSchema()
+	checkDiags(t, resp.Diagnostics)
+}
+
+func TestGRPCProvisioner_ValidateProvisionerConfig(t *testing.T) {
+	client := mockProvisionerClient(t)
+	p := &GRPCProvisioner{
+		client: client,
+	}
+
+	client.EXPECT().ValidateProvisionerConfig(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ValidateProvisionerConfig_Response{}, nil)
+
+	cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"})
+	resp := p.ValidateProvisionerConfig(provisioners.ValidateProvisionerConfigRequest{Config: cfg})
+	checkDiags(t, resp.Diagnostics)
+}
+
+func TestGRPCProvisioner_ProvisionResource(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	client := mockproto.NewMockProvisionerClient(ctrl)
+
+	// we always need a GetSchema method
+	client.EXPECT().GetSchema(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(provisionerProtoSchema(), nil)
+
+	stream := mockproto.NewMockProvisioner_ProvisionResourceClient(ctrl)
+	stream.EXPECT().Recv().Return(&proto.ProvisionResource_Response{
+		Output: "provisioned",
+	}, io.EOF)
+
+	client.EXPECT().ProvisionResource(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(stream, nil)
+
+	p := &GRPCProvisioner{
+		client: client,
+	}
+
+	rec := &provisionRecorder{}
+
+	resp := p.ProvisionResource(provisioners.ProvisionResourceRequest{
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("value"),
+		}),
+		Connection: cty.EmptyObjectVal,
+		UIOutput:   rec,
+	})
+
+	if resp.Diagnostics.HasErrors() {
+		t.Fatal(resp.Diagnostics.Err())
+	}
+
+	if len(rec.output) == 0 || rec.output[0] != "provisioned" {
+		t.Fatalf("expected %q, got %q", []string{"provisioned"}, rec.output)
+	}
+}
+
+type provisionRecorder struct {
+	output []string
+}
+
+func (r *provisionRecorder) Output(s string) {
+	r.output = append(r.output, s)
+}
+
+func TestGRPCProvisioner_Stop(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	client := mockproto.NewMockProvisionerClient(ctrl)
+	p := &GRPCProvisioner{
+		client: client,
+	}
+
+	client.EXPECT().Stop(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.Stop_Response{}, nil)
+
+	err := p.Stop()
+	if err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/v1.5.7/internal/plugin/mock_proto/generate.go b/v1.5.7/internal/plugin/mock_proto/generate.go
new file mode 100644
index 0000000..1bf4519
--- /dev/null
+++ b/v1.5.7/internal/plugin/mock_proto/generate.go
@@ -0,0 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:generate go run github.com/golang/mock/mockgen -destination mock.go github.com/hashicorp/terraform/internal/tfplugin5 ProviderClient,ProvisionerClient,Provisioner_ProvisionResourceClient,Provisioner_ProvisionResourceServer
+
+package mock_tfplugin5
diff --git a/v1.5.7/internal/plugin/mock_proto/mock.go b/v1.5.7/internal/plugin/mock_proto/mock.go
new file mode 100644
index 0000000..054fe1c
--- /dev/null
+++ b/v1.5.7/internal/plugin/mock_proto/mock.go
@@ -0,0 +1,623 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: github.com/hashicorp/terraform/internal/tfplugin5 (interfaces: ProviderClient,ProvisionerClient,Provisioner_ProvisionResourceClient,Provisioner_ProvisionResourceServer)
+
+// Package mock_tfplugin5 is a generated GoMock package.
+package mock_tfplugin5
+
+import (
+	context "context"
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	tfplugin5 "github.com/hashicorp/terraform/internal/tfplugin5"
+	grpc "google.golang.org/grpc"
+	metadata "google.golang.org/grpc/metadata"
+)
+
+// MockProviderClient is a mock of ProviderClient interface.
+type MockProviderClient struct {
+	ctrl     *gomock.Controller
+	recorder *MockProviderClientMockRecorder
+}
+
+// MockProviderClientMockRecorder is the mock recorder for MockProviderClient.
+type MockProviderClientMockRecorder struct {
+	mock *MockProviderClient
+}
+
+// NewMockProviderClient creates a new mock instance.
+func NewMockProviderClient(ctrl *gomock.Controller) *MockProviderClient {
+	mock := &MockProviderClient{ctrl: ctrl}
+	mock.recorder = &MockProviderClientMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockProviderClient) EXPECT() *MockProviderClientMockRecorder {
+	return m.recorder
+}
+
+// ApplyResourceChange mocks base method.
+func (m *MockProviderClient) ApplyResourceChange(arg0 context.Context, arg1 *tfplugin5.ApplyResourceChange_Request, arg2 ...grpc.CallOption) (*tfplugin5.ApplyResourceChange_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ApplyResourceChange", varargs...)
+	ret0, _ := ret[0].(*tfplugin5.ApplyResourceChange_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ApplyResourceChange indicates an expected call of ApplyResourceChange.
+func (mr *MockProviderClientMockRecorder) ApplyResourceChange(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyResourceChange", reflect.TypeOf((*MockProviderClient)(nil).ApplyResourceChange), varargs...)
+}
+
+// Configure mocks base method.
+func (m *MockProviderClient) Configure(arg0 context.Context, arg1 *tfplugin5.Configure_Request, arg2 ...grpc.CallOption) (*tfplugin5.Configure_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "Configure", varargs...)
+	ret0, _ := ret[0].(*tfplugin5.Configure_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Configure indicates an expected call of Configure.
+func (mr *MockProviderClientMockRecorder) Configure(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Configure", reflect.TypeOf((*MockProviderClient)(nil).Configure), varargs...)
+}
+
+// GetSchema mocks base method.
+func (m *MockProviderClient) GetSchema(arg0 context.Context, arg1 *tfplugin5.GetProviderSchema_Request, arg2 ...grpc.CallOption) (*tfplugin5.GetProviderSchema_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetSchema", varargs...)
+	ret0, _ := ret[0].(*tfplugin5.GetProviderSchema_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetSchema indicates an expected call of GetSchema.
+func (mr *MockProviderClientMockRecorder) GetSchema(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSchema", reflect.TypeOf((*MockProviderClient)(nil).GetSchema), varargs...)
+}
+
+// ImportResourceState mocks base method.
+func (m *MockProviderClient) ImportResourceState(arg0 context.Context, arg1 *tfplugin5.ImportResourceState_Request, arg2 ...grpc.CallOption) (*tfplugin5.ImportResourceState_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ImportResourceState", varargs...)
+	ret0, _ := ret[0].(*tfplugin5.ImportResourceState_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ImportResourceState indicates an expected call of ImportResourceState.
+func (mr *MockProviderClientMockRecorder) ImportResourceState(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ImportResourceState", reflect.TypeOf((*MockProviderClient)(nil).ImportResourceState), varargs...)
+}
+
+// PlanResourceChange mocks base method.
+func (m *MockProviderClient) PlanResourceChange(arg0 context.Context, arg1 *tfplugin5.PlanResourceChange_Request, arg2 ...grpc.CallOption) (*tfplugin5.PlanResourceChange_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "PlanResourceChange", varargs...)
+	ret0, _ := ret[0].(*tfplugin5.PlanResourceChange_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// PlanResourceChange indicates an expected call of PlanResourceChange.
+func (mr *MockProviderClientMockRecorder) PlanResourceChange(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PlanResourceChange", reflect.TypeOf((*MockProviderClient)(nil).PlanResourceChange), varargs...)
+}
+
+// PrepareProviderConfig mocks base method.
+func (m *MockProviderClient) PrepareProviderConfig(arg0 context.Context, arg1 *tfplugin5.PrepareProviderConfig_Request, arg2 ...grpc.CallOption) (*tfplugin5.PrepareProviderConfig_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "PrepareProviderConfig", varargs...)
+	ret0, _ := ret[0].(*tfplugin5.PrepareProviderConfig_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// PrepareProviderConfig indicates an expected call of PrepareProviderConfig.
+func (mr *MockProviderClientMockRecorder) PrepareProviderConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrepareProviderConfig", reflect.TypeOf((*MockProviderClient)(nil).PrepareProviderConfig), varargs...)
+}
+
+// ReadDataSource mocks base method.
+func (m *MockProviderClient) ReadDataSource(arg0 context.Context, arg1 *tfplugin5.ReadDataSource_Request, arg2 ...grpc.CallOption) (*tfplugin5.ReadDataSource_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ReadDataSource", varargs...)
+	ret0, _ := ret[0].(*tfplugin5.ReadDataSource_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ReadDataSource indicates an expected call of ReadDataSource.
+func (mr *MockProviderClientMockRecorder) ReadDataSource(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadDataSource", reflect.TypeOf((*MockProviderClient)(nil).ReadDataSource), varargs...)
+}
+
+// ReadResource mocks base method.
+func (m *MockProviderClient) ReadResource(arg0 context.Context, arg1 *tfplugin5.ReadResource_Request, arg2 ...grpc.CallOption) (*tfplugin5.ReadResource_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ReadResource", varargs...)
+	ret0, _ := ret[0].(*tfplugin5.ReadResource_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ReadResource indicates an expected call of ReadResource.
+func (mr *MockProviderClientMockRecorder) ReadResource(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadResource", reflect.TypeOf((*MockProviderClient)(nil).ReadResource), varargs...)
+}
+
+// Stop mocks base method.
+func (m *MockProviderClient) Stop(arg0 context.Context, arg1 *tfplugin5.Stop_Request, arg2 ...grpc.CallOption) (*tfplugin5.Stop_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "Stop", varargs...)
+	ret0, _ := ret[0].(*tfplugin5.Stop_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Stop indicates an expected call of Stop.
+func (mr *MockProviderClientMockRecorder) Stop(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockProviderClient)(nil).Stop), varargs...)
+}
+
+// UpgradeResourceState mocks base method.
+func (m *MockProviderClient) UpgradeResourceState(arg0 context.Context, arg1 *tfplugin5.UpgradeResourceState_Request, arg2 ...grpc.CallOption) (*tfplugin5.UpgradeResourceState_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "UpgradeResourceState", varargs...)
+	ret0, _ := ret[0].(*tfplugin5.UpgradeResourceState_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// UpgradeResourceState indicates an expected call of UpgradeResourceState.
+func (mr *MockProviderClientMockRecorder) UpgradeResourceState(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpgradeResourceState", reflect.TypeOf((*MockProviderClient)(nil).UpgradeResourceState), varargs...)
+}
+
+// ValidateDataSourceConfig mocks base method.
+func (m *MockProviderClient) ValidateDataSourceConfig(arg0 context.Context, arg1 *tfplugin5.ValidateDataSourceConfig_Request, arg2 ...grpc.CallOption) (*tfplugin5.ValidateDataSourceConfig_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ValidateDataSourceConfig", varargs...)
+	ret0, _ := ret[0].(*tfplugin5.ValidateDataSourceConfig_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ValidateDataSourceConfig indicates an expected call of ValidateDataSourceConfig.
+func (mr *MockProviderClientMockRecorder) ValidateDataSourceConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateDataSourceConfig", reflect.TypeOf((*MockProviderClient)(nil).ValidateDataSourceConfig), varargs...)
+}
+
+// ValidateResourceTypeConfig mocks base method.
+func (m *MockProviderClient) ValidateResourceTypeConfig(arg0 context.Context, arg1 *tfplugin5.ValidateResourceTypeConfig_Request, arg2 ...grpc.CallOption) (*tfplugin5.ValidateResourceTypeConfig_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ValidateResourceTypeConfig", varargs...)
+	ret0, _ := ret[0].(*tfplugin5.ValidateResourceTypeConfig_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ValidateResourceTypeConfig indicates an expected call of ValidateResourceTypeConfig.
+func (mr *MockProviderClientMockRecorder) ValidateResourceTypeConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateResourceTypeConfig", reflect.TypeOf((*MockProviderClient)(nil).ValidateResourceTypeConfig), varargs...)
+}
+
+// MockProvisionerClient is a mock of ProvisionerClient interface.
+type MockProvisionerClient struct {
+	ctrl     *gomock.Controller
+	recorder *MockProvisionerClientMockRecorder
+}
+
+// MockProvisionerClientMockRecorder is the mock recorder for MockProvisionerClient.
+type MockProvisionerClientMockRecorder struct {
+	mock *MockProvisionerClient
+}
+
+// NewMockProvisionerClient creates a new mock instance.
+func NewMockProvisionerClient(ctrl *gomock.Controller) *MockProvisionerClient {
+	mock := &MockProvisionerClient{ctrl: ctrl}
+	mock.recorder = &MockProvisionerClientMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockProvisionerClient) EXPECT() *MockProvisionerClientMockRecorder {
+	return m.recorder
+}
+
+// GetSchema mocks base method.
+func (m *MockProvisionerClient) GetSchema(arg0 context.Context, arg1 *tfplugin5.GetProvisionerSchema_Request, arg2 ...grpc.CallOption) (*tfplugin5.GetProvisionerSchema_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetSchema", varargs...)
+	ret0, _ := ret[0].(*tfplugin5.GetProvisionerSchema_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetSchema indicates an expected call of GetSchema.
+func (mr *MockProvisionerClientMockRecorder) GetSchema(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSchema", reflect.TypeOf((*MockProvisionerClient)(nil).GetSchema), varargs...)
+}
+
+// ProvisionResource mocks base method.
+func (m *MockProvisionerClient) ProvisionResource(arg0 context.Context, arg1 *tfplugin5.ProvisionResource_Request, arg2 ...grpc.CallOption) (tfplugin5.Provisioner_ProvisionResourceClient, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ProvisionResource", varargs...)
+	ret0, _ := ret[0].(tfplugin5.Provisioner_ProvisionResourceClient)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ProvisionResource indicates an expected call of ProvisionResource.
+func (mr *MockProvisionerClientMockRecorder) ProvisionResource(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvisionResource", reflect.TypeOf((*MockProvisionerClient)(nil).ProvisionResource), varargs...)
+}
+
+// Stop mocks base method.
+func (m *MockProvisionerClient) Stop(arg0 context.Context, arg1 *tfplugin5.Stop_Request, arg2 ...grpc.CallOption) (*tfplugin5.Stop_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "Stop", varargs...)
+	ret0, _ := ret[0].(*tfplugin5.Stop_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Stop indicates an expected call of Stop.
+func (mr *MockProvisionerClientMockRecorder) Stop(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockProvisionerClient)(nil).Stop), varargs...)
+}
+
+// ValidateProvisionerConfig mocks base method.
+func (m *MockProvisionerClient) ValidateProvisionerConfig(arg0 context.Context, arg1 *tfplugin5.ValidateProvisionerConfig_Request, arg2 ...grpc.CallOption) (*tfplugin5.ValidateProvisionerConfig_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ValidateProvisionerConfig", varargs...)
+	ret0, _ := ret[0].(*tfplugin5.ValidateProvisionerConfig_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ValidateProvisionerConfig indicates an expected call of ValidateProvisionerConfig.
+func (mr *MockProvisionerClientMockRecorder) ValidateProvisionerConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateProvisionerConfig", reflect.TypeOf((*MockProvisionerClient)(nil).ValidateProvisionerConfig), varargs...)
+}
+
+// MockProvisioner_ProvisionResourceClient is a mock of Provisioner_ProvisionResourceClient interface.
+type MockProvisioner_ProvisionResourceClient struct {
+	ctrl     *gomock.Controller
+	recorder *MockProvisioner_ProvisionResourceClientMockRecorder
+}
+
+// MockProvisioner_ProvisionResourceClientMockRecorder is the mock recorder for MockProvisioner_ProvisionResourceClient.
+type MockProvisioner_ProvisionResourceClientMockRecorder struct {
+	mock *MockProvisioner_ProvisionResourceClient
+}
+
+// NewMockProvisioner_ProvisionResourceClient creates a new mock instance.
+func NewMockProvisioner_ProvisionResourceClient(ctrl *gomock.Controller) *MockProvisioner_ProvisionResourceClient {
+	mock := &MockProvisioner_ProvisionResourceClient{ctrl: ctrl}
+	mock.recorder = &MockProvisioner_ProvisionResourceClientMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockProvisioner_ProvisionResourceClient) EXPECT() *MockProvisioner_ProvisionResourceClientMockRecorder {
+	return m.recorder
+}
+
+// CloseSend mocks base method.
+func (m *MockProvisioner_ProvisionResourceClient) CloseSend() error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CloseSend")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// CloseSend indicates an expected call of CloseSend.
+func (mr *MockProvisioner_ProvisionResourceClientMockRecorder) CloseSend() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseSend", reflect.TypeOf((*MockProvisioner_ProvisionResourceClient)(nil).CloseSend))
+}
+
+// Context mocks base method.
+func (m *MockProvisioner_ProvisionResourceClient) Context() context.Context {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Context")
+	ret0, _ := ret[0].(context.Context)
+	return ret0
+}
+
+// Context indicates an expected call of Context.
+func (mr *MockProvisioner_ProvisionResourceClientMockRecorder) Context() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockProvisioner_ProvisionResourceClient)(nil).Context))
+}
+
+// Header mocks base method.
+func (m *MockProvisioner_ProvisionResourceClient) Header() (metadata.MD, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Header")
+	ret0, _ := ret[0].(metadata.MD)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Header indicates an expected call of Header.
+func (mr *MockProvisioner_ProvisionResourceClientMockRecorder) Header() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockProvisioner_ProvisionResourceClient)(nil).Header))
+}
+
+// Recv mocks base method.
+func (m *MockProvisioner_ProvisionResourceClient) Recv() (*tfplugin5.ProvisionResource_Response, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Recv")
+	ret0, _ := ret[0].(*tfplugin5.ProvisionResource_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Recv indicates an expected call of Recv.
+func (mr *MockProvisioner_ProvisionResourceClientMockRecorder) Recv() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Recv", reflect.TypeOf((*MockProvisioner_ProvisionResourceClient)(nil).Recv))
+}
+
+// RecvMsg mocks base method.
+func (m *MockProvisioner_ProvisionResourceClient) RecvMsg(arg0 interface{}) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "RecvMsg", arg0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// RecvMsg indicates an expected call of RecvMsg.
+func (mr *MockProvisioner_ProvisionResourceClientMockRecorder) RecvMsg(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecvMsg", reflect.TypeOf((*MockProvisioner_ProvisionResourceClient)(nil).RecvMsg), arg0)
+}
+
+// SendMsg mocks base method.
+func (m *MockProvisioner_ProvisionResourceClient) SendMsg(arg0 interface{}) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "SendMsg", arg0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// SendMsg indicates an expected call of SendMsg.
+func (mr *MockProvisioner_ProvisionResourceClientMockRecorder) SendMsg(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMsg", reflect.TypeOf((*MockProvisioner_ProvisionResourceClient)(nil).SendMsg), arg0)
+}
+
+// Trailer mocks base method.
+func (m *MockProvisioner_ProvisionResourceClient) Trailer() metadata.MD {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Trailer")
+	ret0, _ := ret[0].(metadata.MD)
+	return ret0
+}
+
+// Trailer indicates an expected call of Trailer.
+func (mr *MockProvisioner_ProvisionResourceClientMockRecorder) Trailer() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Trailer", reflect.TypeOf((*MockProvisioner_ProvisionResourceClient)(nil).Trailer))
+}
+
+// MockProvisioner_ProvisionResourceServer is a mock of Provisioner_ProvisionResourceServer interface.
+type MockProvisioner_ProvisionResourceServer struct {
+	ctrl     *gomock.Controller
+	recorder *MockProvisioner_ProvisionResourceServerMockRecorder
+}
+
+// MockProvisioner_ProvisionResourceServerMockRecorder is the mock recorder for MockProvisioner_ProvisionResourceServer.
+type MockProvisioner_ProvisionResourceServerMockRecorder struct {
+	mock *MockProvisioner_ProvisionResourceServer
+}
+
+// NewMockProvisioner_ProvisionResourceServer creates a new mock instance.
+func NewMockProvisioner_ProvisionResourceServer(ctrl *gomock.Controller) *MockProvisioner_ProvisionResourceServer {
+	mock := &MockProvisioner_ProvisionResourceServer{ctrl: ctrl}
+	mock.recorder = &MockProvisioner_ProvisionResourceServerMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockProvisioner_ProvisionResourceServer) EXPECT() *MockProvisioner_ProvisionResourceServerMockRecorder {
+	return m.recorder
+}
+
+// Context mocks base method.
+func (m *MockProvisioner_ProvisionResourceServer) Context() context.Context {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Context")
+	ret0, _ := ret[0].(context.Context)
+	return ret0
+}
+
+// Context indicates an expected call of Context.
+func (mr *MockProvisioner_ProvisionResourceServerMockRecorder) Context() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockProvisioner_ProvisionResourceServer)(nil).Context))
+}
+
+// RecvMsg mocks base method.
+func (m *MockProvisioner_ProvisionResourceServer) RecvMsg(arg0 interface{}) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "RecvMsg", arg0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// RecvMsg indicates an expected call of RecvMsg.
+func (mr *MockProvisioner_ProvisionResourceServerMockRecorder) RecvMsg(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecvMsg", reflect.TypeOf((*MockProvisioner_ProvisionResourceServer)(nil).RecvMsg), arg0)
+}
+
+// Send mocks base method.
+func (m *MockProvisioner_ProvisionResourceServer) Send(arg0 *tfplugin5.ProvisionResource_Response) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Send", arg0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Send indicates an expected call of Send.
+func (mr *MockProvisioner_ProvisionResourceServerMockRecorder) Send(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockProvisioner_ProvisionResourceServer)(nil).Send), arg0)
+}
+
+// SendHeader mocks base method.
+func (m *MockProvisioner_ProvisionResourceServer) SendHeader(arg0 metadata.MD) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "SendHeader", arg0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// SendHeader indicates an expected call of SendHeader.
+func (mr *MockProvisioner_ProvisionResourceServerMockRecorder) SendHeader(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendHeader", reflect.TypeOf((*MockProvisioner_ProvisionResourceServer)(nil).SendHeader), arg0)
+}
+
+// SendMsg mocks base method.
+func (m *MockProvisioner_ProvisionResourceServer) SendMsg(arg0 interface{}) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "SendMsg", arg0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// SendMsg indicates an expected call of SendMsg.
+func (mr *MockProvisioner_ProvisionResourceServerMockRecorder) SendMsg(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMsg", reflect.TypeOf((*MockProvisioner_ProvisionResourceServer)(nil).SendMsg), arg0)
+}
+
+// SetHeader mocks base method.
+func (m *MockProvisioner_ProvisionResourceServer) SetHeader(arg0 metadata.MD) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "SetHeader", arg0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// SetHeader indicates an expected call of SetHeader.
+func (mr *MockProvisioner_ProvisionResourceServerMockRecorder) SetHeader(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHeader", reflect.TypeOf((*MockProvisioner_ProvisionResourceServer)(nil).SetHeader), arg0)
+}
+
+// SetTrailer mocks base method.
+func (m *MockProvisioner_ProvisionResourceServer) SetTrailer(arg0 metadata.MD) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "SetTrailer", arg0)
+}
+
+// SetTrailer indicates an expected call of SetTrailer.
+func (mr *MockProvisioner_ProvisionResourceServerMockRecorder) SetTrailer(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTrailer", reflect.TypeOf((*MockProvisioner_ProvisionResourceServer)(nil).SetTrailer), arg0)
+}
diff --git a/v1.5.7/internal/plugin/plugin.go b/v1.5.7/internal/plugin/plugin.go
new file mode 100644
index 0000000..7a88cb5
--- /dev/null
+++ b/v1.5.7/internal/plugin/plugin.go
@@ -0,0 +1,22 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin
+
+import (
+	"github.com/hashicorp/go-plugin"
+	"github.com/hashicorp/terraform/internal/plugin6"
+)
+
+// VersionedPlugins includes both protocol 5 and 6 because this is the function
+// called in providerFactory (command/meta_providers.go) to set up the initial
+// plugin client config.
+var VersionedPlugins = map[int]plugin.PluginSet{
+	5: {
+		"provider":    &GRPCProviderPlugin{},
+		"provisioner": &GRPCProvisionerPlugin{},
+	},
+	6: {
+		"provider": &plugin6.GRPCProviderPlugin{},
+	},
+}
diff --git a/v1.5.7/internal/plugin/serve.go b/v1.5.7/internal/plugin/serve.go
new file mode 100644
index 0000000..44d117e
--- /dev/null
+++ b/v1.5.7/internal/plugin/serve.go
@@ -0,0 +1,78 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin
+
+import (
+	"github.com/hashicorp/go-plugin"
+	proto "github.com/hashicorp/terraform/internal/tfplugin5"
+)
+
+const (
+	// The constants below are the names of the plugins that can be dispensed
+	// from the plugin server.
+	ProviderPluginName    = "provider"
+	ProvisionerPluginName = "provisioner"
+
+	// DefaultProtocolVersion is the protocol version assumed for legacy clients that don't specify
+	// a particular version during their handshake. This is the version used when Terraform 0.10
+	// and 0.11 launch plugins that were built with support for both versions 4 and 5, and must
+	// stay unchanged at 4 until we intentionally build plugins that are not compatible with 0.10 and
+	// 0.11.
+	DefaultProtocolVersion = 4
+)
+
+// Handshake is the HandshakeConfig used to configure clients and servers.
+var Handshake = plugin.HandshakeConfig{
+	// The ProtocolVersion is the version that must match between TF core
+	// and TF plugins. This should be bumped whenever a change happens in
+	// one or the other that makes it so that they can't safely communicate.
+	// This could be adding a new interface value, it could be how
+	// helper/schema computes diffs, etc.
+	ProtocolVersion: DefaultProtocolVersion,
+
+	// The magic cookie values should NEVER be changed.
+	MagicCookieKey:   "TF_PLUGIN_MAGIC_COOKIE",
+	MagicCookieValue: "d602bf8f470bc67ca7faa0386276bbdd4330efaf76d1a219cb4d6991ca9872b2",
+}
+
+type GRPCProviderFunc func() proto.ProviderServer
+type GRPCProvisionerFunc func() proto.ProvisionerServer
+
+// ServeOpts are the configurations to serve a plugin.
+type ServeOpts struct {
+	// Wrapped versions of the above plugins will automatically shimmed and
+	// added to the GRPC functions when possible.
+	GRPCProviderFunc    GRPCProviderFunc
+	GRPCProvisionerFunc GRPCProvisionerFunc
+}
+
+// Serve serves a plugin. This function never returns and should be the final
+// function called in the main function of the plugin.
+func Serve(opts *ServeOpts) {
+	plugin.Serve(&plugin.ServeConfig{
+		HandshakeConfig:  Handshake,
+		VersionedPlugins: pluginSet(opts),
+		GRPCServer:       plugin.DefaultGRPCServer,
+	})
+}
+
+func pluginSet(opts *ServeOpts) map[int]plugin.PluginSet {
+	plugins := map[int]plugin.PluginSet{}
+
+	// add the new protocol versions if they're configured
+	if opts.GRPCProviderFunc != nil || opts.GRPCProvisionerFunc != nil {
+		plugins[5] = plugin.PluginSet{}
+		if opts.GRPCProviderFunc != nil {
+			plugins[5]["provider"] = &GRPCProviderPlugin{
+				GRPCProvider: opts.GRPCProviderFunc,
+			}
+		}
+		if opts.GRPCProvisionerFunc != nil {
+			plugins[5]["provisioner"] = &GRPCProvisionerPlugin{
+				GRPCProvisioner: opts.GRPCProvisionerFunc,
+			}
+		}
+	}
+	return plugins
+}
diff --git a/v1.5.7/internal/plugin/ui_input.go b/v1.5.7/internal/plugin/ui_input.go
new file mode 100644
index 0000000..942b83d
--- /dev/null
+++ b/v1.5.7/internal/plugin/ui_input.go
@@ -0,0 +1,55 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin
+
+import (
+	"context"
+	"net/rpc"
+
+	"github.com/hashicorp/go-plugin"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// UIInput is an implementation of terraform.UIInput that communicates
+// over RPC.
+type UIInput struct {
+	Client *rpc.Client
+}
+
+func (i *UIInput) Input(ctx context.Context, opts *terraform.InputOpts) (string, error) {
+	var resp UIInputInputResponse
+	err := i.Client.Call("Plugin.Input", opts, &resp)
+	if err != nil {
+		return "", err
+	}
+	if resp.Error != nil {
+		err = resp.Error
+		return "", err
+	}
+
+	return resp.Value, nil
+}
+
+type UIInputInputResponse struct {
+	Value string
+	Error *plugin.BasicError
+}
+
+// UIInputServer is a net/rpc compatible structure for serving
+// a UIInputServer. This should not be used directly.
+type UIInputServer struct {
+	UIInput terraform.UIInput
+}
+
+func (s *UIInputServer) Input(
+	opts *terraform.InputOpts,
+	reply *UIInputInputResponse) error {
+	value, err := s.UIInput.Input(context.Background(), opts)
+	*reply = UIInputInputResponse{
+		Value: value,
+		Error: plugin.NewBasicError(err),
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/plugin/ui_input_test.go b/v1.5.7/internal/plugin/ui_input_test.go
new file mode 100644
index 0000000..a57f5c9
--- /dev/null
+++ b/v1.5.7/internal/plugin/ui_input_test.go
@@ -0,0 +1,53 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin
+
+import (
+	"context"
+	"reflect"
+	"testing"
+
+	"github.com/hashicorp/go-plugin"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+func TestUIInput_impl(t *testing.T) {
+	var _ terraform.UIInput = new(UIInput)
+}
+
+func TestUIInput_input(t *testing.T) {
+	client, server := plugin.TestRPCConn(t)
+	defer client.Close()
+
+	i := new(terraform.MockUIInput)
+	i.InputReturnString = "foo"
+
+	err := server.RegisterName("Plugin", &UIInputServer{
+		UIInput: i,
+	})
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	input := &UIInput{Client: client}
+
+	opts := &terraform.InputOpts{
+		Id: "foo",
+	}
+
+	v, err := input.Input(context.Background(), opts)
+	if !i.InputCalled {
+		t.Fatal("input should be called")
+	}
+	if !reflect.DeepEqual(i.InputOpts, opts) {
+		t.Fatalf("bad: %#v", i.InputOpts)
+	}
+	if err != nil {
+		t.Fatalf("bad: %#v", err)
+	}
+
+	if v != "foo" {
+		t.Fatalf("bad: %#v", v)
+	}
+}
diff --git a/v1.5.7/internal/plugin/ui_output.go b/v1.5.7/internal/plugin/ui_output.go
new file mode 100644
index 0000000..b323bfe
--- /dev/null
+++ b/v1.5.7/internal/plugin/ui_output.go
@@ -0,0 +1,32 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin
+
+import (
+	"net/rpc"
+
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// UIOutput is an implementatin of terraform.UIOutput that communicates
+// over RPC.
+type UIOutput struct {
+	Client *rpc.Client
+}
+
+func (o *UIOutput) Output(v string) {
+	o.Client.Call("Plugin.Output", v, new(interface{}))
+}
+
+// UIOutputServer is the RPC server for serving UIOutput.
+type UIOutputServer struct {
+	UIOutput terraform.UIOutput
+}
+
+func (s *UIOutputServer) Output(
+	v string,
+	reply *interface{}) error {
+	s.UIOutput.Output(v)
+	return nil
+}
diff --git a/v1.5.7/internal/plugin/ui_output_test.go b/v1.5.7/internal/plugin/ui_output_test.go
new file mode 100644
index 0000000..8d82184
--- /dev/null
+++ b/v1.5.7/internal/plugin/ui_output_test.go
@@ -0,0 +1,38 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin
+
+import (
+	"testing"
+
+	"github.com/hashicorp/go-plugin"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+func TestUIOutput_impl(t *testing.T) {
+	var _ terraform.UIOutput = new(UIOutput)
+}
+
+func TestUIOutput_input(t *testing.T) {
+	client, server := plugin.TestRPCConn(t)
+	defer client.Close()
+
+	o := new(terraform.MockUIOutput)
+
+	err := server.RegisterName("Plugin", &UIOutputServer{
+		UIOutput: o,
+	})
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	output := &UIOutput{Client: client}
+	output.Output("foo")
+	if !o.OutputCalled {
+		t.Fatal("output should be called")
+	}
+	if o.OutputMessage != "foo" {
+		t.Fatalf("bad: %#v", o.OutputMessage)
+	}
+}
diff --git a/v1.5.7/internal/plugin6/convert/diagnostics.go b/v1.5.7/internal/plugin6/convert/diagnostics.go
new file mode 100644
index 0000000..93f7f00
--- /dev/null
+++ b/v1.5.7/internal/plugin6/convert/diagnostics.go
@@ -0,0 +1,135 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package convert
+
+import (
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	proto "github.com/hashicorp/terraform/internal/tfplugin6"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// WarnsAndErrorsToProto converts the warnings and errors return by the legacy
+// provider to protobuf diagnostics.
+func WarnsAndErrsToProto(warns []string, errs []error) (diags []*proto.Diagnostic) {
+	for _, w := range warns {
+		diags = AppendProtoDiag(diags, w)
+	}
+
+	for _, e := range errs {
+		diags = AppendProtoDiag(diags, e)
+	}
+
+	return diags
+}
+
+// AppendProtoDiag appends a new diagnostic from a warning string or an error.
+// This panics if d is not a string or error.
+func AppendProtoDiag(diags []*proto.Diagnostic, d interface{}) []*proto.Diagnostic {
+	switch d := d.(type) {
+	case cty.PathError:
+		ap := PathToAttributePath(d.Path)
+		diags = append(diags, &proto.Diagnostic{
+			Severity:  proto.Diagnostic_ERROR,
+			Summary:   d.Error(),
+			Attribute: ap,
+		})
+	case error:
+		diags = append(diags, &proto.Diagnostic{
+			Severity: proto.Diagnostic_ERROR,
+			Summary:  d.Error(),
+		})
+	case string:
+		diags = append(diags, &proto.Diagnostic{
+			Severity: proto.Diagnostic_WARNING,
+			Summary:  d,
+		})
+	case *proto.Diagnostic:
+		diags = append(diags, d)
+	case []*proto.Diagnostic:
+		diags = append(diags, d...)
+	}
+	return diags
+}
+
+// ProtoToDiagnostics converts a list of proto.Diagnostics to a tf.Diagnostics.
+func ProtoToDiagnostics(ds []*proto.Diagnostic) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+	for _, d := range ds {
+		var severity tfdiags.Severity
+
+		switch d.Severity {
+		case proto.Diagnostic_ERROR:
+			severity = tfdiags.Error
+		case proto.Diagnostic_WARNING:
+			severity = tfdiags.Warning
+		}
+
+		var newDiag tfdiags.Diagnostic
+
+		// if there's an attribute path, we need to create a AttributeValue diagnostic
+		if d.Attribute != nil {
+			path := AttributePathToPath(d.Attribute)
+			newDiag = tfdiags.AttributeValue(severity, d.Summary, d.Detail, path)
+		} else {
+			newDiag = tfdiags.WholeContainingBody(severity, d.Summary, d.Detail)
+		}
+
+		diags = diags.Append(newDiag)
+	}
+
+	return diags
+}
+
+// AttributePathToPath takes the proto encoded path and converts it to a cty.Path
+func AttributePathToPath(ap *proto.AttributePath) cty.Path {
+	var p cty.Path
+	for _, step := range ap.Steps {
+		switch selector := step.Selector.(type) {
+		case *proto.AttributePath_Step_AttributeName:
+			p = p.GetAttr(selector.AttributeName)
+		case *proto.AttributePath_Step_ElementKeyString:
+			p = p.Index(cty.StringVal(selector.ElementKeyString))
+		case *proto.AttributePath_Step_ElementKeyInt:
+			p = p.Index(cty.NumberIntVal(selector.ElementKeyInt))
+		}
+	}
+	return p
+}
+
+// AttributePathToPath takes a cty.Path and converts it to a proto-encoded path.
+func PathToAttributePath(p cty.Path) *proto.AttributePath {
+	ap := &proto.AttributePath{}
+	for _, step := range p {
+		switch selector := step.(type) {
+		case cty.GetAttrStep:
+			ap.Steps = append(ap.Steps, &proto.AttributePath_Step{
+				Selector: &proto.AttributePath_Step_AttributeName{
+					AttributeName: selector.Name,
+				},
+			})
+		case cty.IndexStep:
+			key := selector.Key
+			switch key.Type() {
+			case cty.String:
+				ap.Steps = append(ap.Steps, &proto.AttributePath_Step{
+					Selector: &proto.AttributePath_Step_ElementKeyString{
+						ElementKeyString: key.AsString(),
+					},
+				})
+			case cty.Number:
+				v, _ := key.AsBigFloat().Int64()
+				ap.Steps = append(ap.Steps, &proto.AttributePath_Step{
+					Selector: &proto.AttributePath_Step_ElementKeyInt{
+						ElementKeyInt: v,
+					},
+				})
+			default:
+				// We'll bail early if we encounter anything else, and just
+				// return the valid prefix.
+				return ap
+			}
+		}
+	}
+	return ap
+}
diff --git a/v1.5.7/internal/plugin6/convert/diagnostics_test.go b/v1.5.7/internal/plugin6/convert/diagnostics_test.go
new file mode 100644
index 0000000..c14ca5f
--- /dev/null
+++ b/v1.5.7/internal/plugin6/convert/diagnostics_test.go
@@ -0,0 +1,370 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package convert
+
+import (
+	"errors"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	proto "github.com/hashicorp/terraform/internal/tfplugin6"
+	"github.com/zclconf/go-cty/cty"
+)
+
+var ignoreUnexported = cmpopts.IgnoreUnexported(
+	proto.Diagnostic{},
+	proto.Schema_Block{},
+	proto.Schema_NestedBlock{},
+	proto.Schema_Attribute{},
+)
+
+func TestProtoDiagnostics(t *testing.T) {
+	diags := WarnsAndErrsToProto(
+		[]string{
+			"warning 1",
+			"warning 2",
+		},
+		[]error{
+			errors.New("error 1"),
+			errors.New("error 2"),
+		},
+	)
+
+	expected := []*proto.Diagnostic{
+		{
+			Severity: proto.Diagnostic_WARNING,
+			Summary:  "warning 1",
+		},
+		{
+			Severity: proto.Diagnostic_WARNING,
+			Summary:  "warning 2",
+		},
+		{
+			Severity: proto.Diagnostic_ERROR,
+			Summary:  "error 1",
+		},
+		{
+			Severity: proto.Diagnostic_ERROR,
+			Summary:  "error 2",
+		},
+	}
+
+	if !cmp.Equal(expected, diags, ignoreUnexported) {
+		t.Fatal(cmp.Diff(expected, diags, ignoreUnexported))
+	}
+}
+
+func TestDiagnostics(t *testing.T) {
+	type diagFlat struct {
+		Severity tfdiags.Severity
+		Attr     []interface{}
+		Summary  string
+		Detail   string
+	}
+
+	tests := map[string]struct {
+		Cons func([]*proto.Diagnostic) []*proto.Diagnostic
+		Want []diagFlat
+	}{
+		"nil": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				return diags
+			},
+			nil,
+		},
+		"error": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				return append(diags, &proto.Diagnostic{
+					Severity: proto.Diagnostic_ERROR,
+					Summary:  "simple error",
+				})
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Error,
+					Summary:  "simple error",
+				},
+			},
+		},
+		"detailed error": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				return append(diags, &proto.Diagnostic{
+					Severity: proto.Diagnostic_ERROR,
+					Summary:  "simple error",
+					Detail:   "detailed error",
+				})
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Error,
+					Summary:  "simple error",
+					Detail:   "detailed error",
+				},
+			},
+		},
+		"warning": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				return append(diags, &proto.Diagnostic{
+					Severity: proto.Diagnostic_WARNING,
+					Summary:  "simple warning",
+				})
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Warning,
+					Summary:  "simple warning",
+				},
+			},
+		},
+		"detailed warning": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				return append(diags, &proto.Diagnostic{
+					Severity: proto.Diagnostic_WARNING,
+					Summary:  "simple warning",
+					Detail:   "detailed warning",
+				})
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Warning,
+					Summary:  "simple warning",
+					Detail:   "detailed warning",
+				},
+			},
+		},
+		"multi error": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				diags = append(diags, &proto.Diagnostic{
+					Severity: proto.Diagnostic_ERROR,
+					Summary:  "first error",
+				}, &proto.Diagnostic{
+					Severity: proto.Diagnostic_ERROR,
+					Summary:  "second error",
+				})
+				return diags
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Error,
+					Summary:  "first error",
+				},
+				{
+					Severity: tfdiags.Error,
+					Summary:  "second error",
+				},
+			},
+		},
+		"warning and error": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				diags = append(diags, &proto.Diagnostic{
+					Severity: proto.Diagnostic_WARNING,
+					Summary:  "warning",
+				}, &proto.Diagnostic{
+					Severity: proto.Diagnostic_ERROR,
+					Summary:  "error",
+				})
+				return diags
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Warning,
+					Summary:  "warning",
+				},
+				{
+					Severity: tfdiags.Error,
+					Summary:  "error",
+				},
+			},
+		},
+		"attr error": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				diags = append(diags, &proto.Diagnostic{
+					Severity: proto.Diagnostic_ERROR,
+					Summary:  "error",
+					Detail:   "error detail",
+					Attribute: &proto.AttributePath{
+						Steps: []*proto.AttributePath_Step{
+							{
+								Selector: &proto.AttributePath_Step_AttributeName{
+									AttributeName: "attribute_name",
+								},
+							},
+						},
+					},
+				})
+				return diags
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Error,
+					Summary:  "error",
+					Detail:   "error detail",
+					Attr:     []interface{}{"attribute_name"},
+				},
+			},
+		},
+		"multi attr": {
+			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
+				diags = append(diags,
+					&proto.Diagnostic{
+						Severity: proto.Diagnostic_ERROR,
+						Summary:  "error 1",
+						Detail:   "error 1 detail",
+						Attribute: &proto.AttributePath{
+							Steps: []*proto.AttributePath_Step{
+								{
+									Selector: &proto.AttributePath_Step_AttributeName{
+										AttributeName: "attr",
+									},
+								},
+							},
+						},
+					},
+					&proto.Diagnostic{
+						Severity: proto.Diagnostic_ERROR,
+						Summary:  "error 2",
+						Detail:   "error 2 detail",
+						Attribute: &proto.AttributePath{
+							Steps: []*proto.AttributePath_Step{
+								{
+									Selector: &proto.AttributePath_Step_AttributeName{
+										AttributeName: "attr",
+									},
+								},
+								{
+									Selector: &proto.AttributePath_Step_AttributeName{
+										AttributeName: "sub",
+									},
+								},
+							},
+						},
+					},
+					&proto.Diagnostic{
+						Severity: proto.Diagnostic_WARNING,
+						Summary:  "warning",
+						Detail:   "warning detail",
+						Attribute: &proto.AttributePath{
+							Steps: []*proto.AttributePath_Step{
+								{
+									Selector: &proto.AttributePath_Step_AttributeName{
+										AttributeName: "attr",
+									},
+								},
+								{
+									Selector: &proto.AttributePath_Step_ElementKeyInt{
+										ElementKeyInt: 1,
+									},
+								},
+								{
+									Selector: &proto.AttributePath_Step_AttributeName{
+										AttributeName: "sub",
+									},
+								},
+							},
+						},
+					},
+					&proto.Diagnostic{
+						Severity: proto.Diagnostic_ERROR,
+						Summary:  "error 3",
+						Detail:   "error 3 detail",
+						Attribute: &proto.AttributePath{
+							Steps: []*proto.AttributePath_Step{
+								{
+									Selector: &proto.AttributePath_Step_AttributeName{
+										AttributeName: "attr",
+									},
+								},
+								{
+									Selector: &proto.AttributePath_Step_ElementKeyString{
+										ElementKeyString: "idx",
+									},
+								},
+								{
+									Selector: &proto.AttributePath_Step_AttributeName{
+										AttributeName: "sub",
+									},
+								},
+							},
+						},
+					},
+				)
+
+				return diags
+			},
+			[]diagFlat{
+				{
+					Severity: tfdiags.Error,
+					Summary:  "error 1",
+					Detail:   "error 1 detail",
+					Attr:     []interface{}{"attr"},
+				},
+				{
+					Severity: tfdiags.Error,
+					Summary:  "error 2",
+					Detail:   "error 2 detail",
+					Attr:     []interface{}{"attr", "sub"},
+				},
+				{
+					Severity: tfdiags.Warning,
+					Summary:  "warning",
+					Detail:   "warning detail",
+					Attr:     []interface{}{"attr", 1, "sub"},
+				},
+				{
+					Severity: tfdiags.Error,
+					Summary:  "error 3",
+					Detail:   "error 3 detail",
+					Attr:     []interface{}{"attr", "idx", "sub"},
+				},
+			},
+		},
+	}
+
+	flattenTFDiags := func(ds tfdiags.Diagnostics) []diagFlat {
+		var flat []diagFlat
+		for _, item := range ds {
+			desc := item.Description()
+
+			var attr []interface{}
+
+			for _, a := range tfdiags.GetAttribute(item) {
+				switch step := a.(type) {
+				case cty.GetAttrStep:
+					attr = append(attr, step.Name)
+				case cty.IndexStep:
+					switch step.Key.Type() {
+					case cty.Number:
+						i, _ := step.Key.AsBigFloat().Int64()
+						attr = append(attr, int(i))
+					case cty.String:
+						attr = append(attr, step.Key.AsString())
+					}
+				}
+			}
+
+			flat = append(flat, diagFlat{
+				Severity: item.Severity(),
+				Attr:     attr,
+				Summary:  desc.Summary,
+				Detail:   desc.Detail,
+			})
+		}
+		return flat
+	}
+
+	for name, tc := range tests {
+		t.Run(name, func(t *testing.T) {
+			// we take the
+			tfDiags := ProtoToDiagnostics(tc.Cons(nil))
+
+			flat := flattenTFDiags(tfDiags)
+
+			if !cmp.Equal(flat, tc.Want, typeComparer, valueComparer, equateEmpty) {
+				t.Fatal(cmp.Diff(flat, tc.Want, typeComparer, valueComparer, equateEmpty))
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/plugin6/convert/schema.go b/v1.5.7/internal/plugin6/convert/schema.go
new file mode 100644
index 0000000..a635f60
--- /dev/null
+++ b/v1.5.7/internal/plugin6/convert/schema.go
@@ -0,0 +1,300 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package convert
+
+import (
+	"encoding/json"
+	"reflect"
+	"sort"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	proto "github.com/hashicorp/terraform/internal/tfplugin6"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// ConfigSchemaToProto takes a *configschema.Block and converts it to a
+// proto.Schema_Block for a grpc response.
+func ConfigSchemaToProto(b *configschema.Block) *proto.Schema_Block {
+	block := &proto.Schema_Block{
+		Description:     b.Description,
+		DescriptionKind: protoStringKind(b.DescriptionKind),
+		Deprecated:      b.Deprecated,
+	}
+
+	for _, name := range sortedKeys(b.Attributes) {
+		a := b.Attributes[name]
+
+		attr := &proto.Schema_Attribute{
+			Name:            name,
+			Description:     a.Description,
+			DescriptionKind: protoStringKind(a.DescriptionKind),
+			Optional:        a.Optional,
+			Computed:        a.Computed,
+			Required:        a.Required,
+			Sensitive:       a.Sensitive,
+			Deprecated:      a.Deprecated,
+		}
+
+		if a.Type != cty.NilType {
+			ty, err := json.Marshal(a.Type)
+			if err != nil {
+				panic(err)
+			}
+			attr.Type = ty
+		}
+
+		if a.NestedType != nil {
+			attr.NestedType = configschemaObjectToProto(a.NestedType)
+		}
+
+		block.Attributes = append(block.Attributes, attr)
+	}
+
+	for _, name := range sortedKeys(b.BlockTypes) {
+		b := b.BlockTypes[name]
+		block.BlockTypes = append(block.BlockTypes, protoSchemaNestedBlock(name, b))
+	}
+
+	return block
+}
+
+func protoStringKind(k configschema.StringKind) proto.StringKind {
+	switch k {
+	default:
+		return proto.StringKind_PLAIN
+	case configschema.StringMarkdown:
+		return proto.StringKind_MARKDOWN
+	}
+}
+
+func protoSchemaNestedBlock(name string, b *configschema.NestedBlock) *proto.Schema_NestedBlock {
+	var nesting proto.Schema_NestedBlock_NestingMode
+	switch b.Nesting {
+	case configschema.NestingSingle:
+		nesting = proto.Schema_NestedBlock_SINGLE
+	case configschema.NestingGroup:
+		nesting = proto.Schema_NestedBlock_GROUP
+	case configschema.NestingList:
+		nesting = proto.Schema_NestedBlock_LIST
+	case configschema.NestingSet:
+		nesting = proto.Schema_NestedBlock_SET
+	case configschema.NestingMap:
+		nesting = proto.Schema_NestedBlock_MAP
+	default:
+		nesting = proto.Schema_NestedBlock_INVALID
+	}
+	return &proto.Schema_NestedBlock{
+		TypeName: name,
+		Block:    ConfigSchemaToProto(&b.Block),
+		Nesting:  nesting,
+		MinItems: int64(b.MinItems),
+		MaxItems: int64(b.MaxItems),
+	}
+}
+
+// ProtoToProviderSchema takes a proto.Schema and converts it to a providers.Schema.
+func ProtoToProviderSchema(s *proto.Schema) providers.Schema {
+	return providers.Schema{
+		Version: s.Version,
+		Block:   ProtoToConfigSchema(s.Block),
+	}
+}
+
+// ProtoToConfigSchema takes the GetSchcema_Block from a grpc response and converts it
+// to a terraform *configschema.Block.
+func ProtoToConfigSchema(b *proto.Schema_Block) *configschema.Block {
+	block := &configschema.Block{
+		Attributes: make(map[string]*configschema.Attribute),
+		BlockTypes: make(map[string]*configschema.NestedBlock),
+
+		Description:     b.Description,
+		DescriptionKind: schemaStringKind(b.DescriptionKind),
+		Deprecated:      b.Deprecated,
+	}
+
+	for _, a := range b.Attributes {
+		attr := &configschema.Attribute{
+			Description:     a.Description,
+			DescriptionKind: schemaStringKind(a.DescriptionKind),
+			Required:        a.Required,
+			Optional:        a.Optional,
+			Computed:        a.Computed,
+			Sensitive:       a.Sensitive,
+			Deprecated:      a.Deprecated,
+		}
+
+		if a.Type != nil {
+			if err := json.Unmarshal(a.Type, &attr.Type); err != nil {
+				panic(err)
+			}
+		}
+
+		if a.NestedType != nil {
+			attr.NestedType = protoObjectToConfigSchema(a.NestedType)
+		}
+
+		block.Attributes[a.Name] = attr
+	}
+
+	for _, b := range b.BlockTypes {
+		block.BlockTypes[b.TypeName] = schemaNestedBlock(b)
+	}
+
+	return block
+}
+
+func schemaStringKind(k proto.StringKind) configschema.StringKind {
+	switch k {
+	default:
+		return configschema.StringPlain
+	case proto.StringKind_MARKDOWN:
+		return configschema.StringMarkdown
+	}
+}
+
+func schemaNestedBlock(b *proto.Schema_NestedBlock) *configschema.NestedBlock {
+	var nesting configschema.NestingMode
+	switch b.Nesting {
+	case proto.Schema_NestedBlock_SINGLE:
+		nesting = configschema.NestingSingle
+	case proto.Schema_NestedBlock_GROUP:
+		nesting = configschema.NestingGroup
+	case proto.Schema_NestedBlock_LIST:
+		nesting = configschema.NestingList
+	case proto.Schema_NestedBlock_MAP:
+		nesting = configschema.NestingMap
+	case proto.Schema_NestedBlock_SET:
+		nesting = configschema.NestingSet
+	default:
+		// In all other cases we'll leave it as the zero value (invalid) and
+		// let the caller validate it and deal with this.
+	}
+
+	nb := &configschema.NestedBlock{
+		Nesting:  nesting,
+		MinItems: int(b.MinItems),
+		MaxItems: int(b.MaxItems),
+	}
+
+	nested := ProtoToConfigSchema(b.Block)
+	nb.Block = *nested
+	return nb
+}
+
+func protoObjectToConfigSchema(b *proto.Schema_Object) *configschema.Object {
+	var nesting configschema.NestingMode
+	switch b.Nesting {
+	case proto.Schema_Object_SINGLE:
+		nesting = configschema.NestingSingle
+	case proto.Schema_Object_LIST:
+		nesting = configschema.NestingList
+	case proto.Schema_Object_MAP:
+		nesting = configschema.NestingMap
+	case proto.Schema_Object_SET:
+		nesting = configschema.NestingSet
+	default:
+		// In all other cases we'll leave it as the zero value (invalid) and
+		// let the caller validate it and deal with this.
+	}
+
+	object := &configschema.Object{
+		Attributes: make(map[string]*configschema.Attribute),
+		Nesting:    nesting,
+	}
+
+	for _, a := range b.Attributes {
+		attr := &configschema.Attribute{
+			Description:     a.Description,
+			DescriptionKind: schemaStringKind(a.DescriptionKind),
+			Required:        a.Required,
+			Optional:        a.Optional,
+			Computed:        a.Computed,
+			Sensitive:       a.Sensitive,
+			Deprecated:      a.Deprecated,
+		}
+
+		if a.Type != nil {
+			if err := json.Unmarshal(a.Type, &attr.Type); err != nil {
+				panic(err)
+			}
+		}
+
+		if a.NestedType != nil {
+			attr.NestedType = protoObjectToConfigSchema(a.NestedType)
+		}
+
+		object.Attributes[a.Name] = attr
+	}
+
+	return object
+}
+
+// sortedKeys returns the lexically sorted keys from the given map. This is
+// used to make schema conversions are deterministic. This panics if map keys
+// are not a string.
+func sortedKeys(m interface{}) []string {
+	v := reflect.ValueOf(m)
+	keys := make([]string, v.Len())
+
+	mapKeys := v.MapKeys()
+	for i, k := range mapKeys {
+		keys[i] = k.Interface().(string)
+	}
+
+	sort.Strings(keys)
+	return keys
+}
+
+func configschemaObjectToProto(b *configschema.Object) *proto.Schema_Object {
+	var nesting proto.Schema_Object_NestingMode
+	switch b.Nesting {
+	case configschema.NestingSingle:
+		nesting = proto.Schema_Object_SINGLE
+	case configschema.NestingList:
+		nesting = proto.Schema_Object_LIST
+	case configschema.NestingSet:
+		nesting = proto.Schema_Object_SET
+	case configschema.NestingMap:
+		nesting = proto.Schema_Object_MAP
+	default:
+		nesting = proto.Schema_Object_INVALID
+	}
+
+	attributes := make([]*proto.Schema_Attribute, 0, len(b.Attributes))
+
+	for _, name := range sortedKeys(b.Attributes) {
+		a := b.Attributes[name]
+
+		attr := &proto.Schema_Attribute{
+			Name:            name,
+			Description:     a.Description,
+			DescriptionKind: protoStringKind(a.DescriptionKind),
+			Optional:        a.Optional,
+			Computed:        a.Computed,
+			Required:        a.Required,
+			Sensitive:       a.Sensitive,
+			Deprecated:      a.Deprecated,
+		}
+
+		if a.Type != cty.NilType {
+			ty, err := json.Marshal(a.Type)
+			if err != nil {
+				panic(err)
+			}
+			attr.Type = ty
+		}
+
+		if a.NestedType != nil {
+			attr.NestedType = configschemaObjectToProto(a.NestedType)
+		}
+
+		attributes = append(attributes, attr)
+	}
+
+	return &proto.Schema_Object{
+		Attributes: attributes,
+		Nesting:    nesting,
+	}
+}
diff --git a/v1.5.7/internal/plugin6/convert/schema_test.go b/v1.5.7/internal/plugin6/convert/schema_test.go
new file mode 100644
index 0000000..4bdfab7
--- /dev/null
+++ b/v1.5.7/internal/plugin6/convert/schema_test.go
@@ -0,0 +1,569 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package convert
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	proto "github.com/hashicorp/terraform/internal/tfplugin6"
+	"github.com/zclconf/go-cty/cty"
+)
+
+var (
+	equateEmpty   = cmpopts.EquateEmpty()
+	typeComparer  = cmp.Comparer(cty.Type.Equals)
+	valueComparer = cmp.Comparer(cty.Value.RawEquals)
+)
+
+// Test that we can convert configschema to protobuf types and back again.
+func TestConvertSchemaBlocks(t *testing.T) {
+	tests := map[string]struct {
+		Block *proto.Schema_Block
+		Want  *configschema.Block
+	}{
+		"attributes": {
+			&proto.Schema_Block{
+				Attributes: []*proto.Schema_Attribute{
+					{
+						Name:     "computed",
+						Type:     []byte(`["list","bool"]`),
+						Computed: true,
+					},
+					{
+						Name:     "optional",
+						Type:     []byte(`"string"`),
+						Optional: true,
+					},
+					{
+						Name:     "optional_computed",
+						Type:     []byte(`["map","bool"]`),
+						Optional: true,
+						Computed: true,
+					},
+					{
+						Name:     "required",
+						Type:     []byte(`"number"`),
+						Required: true,
+					},
+					{
+						Name: "nested_type",
+						NestedType: &proto.Schema_Object{
+							Nesting: proto.Schema_Object_SINGLE,
+							Attributes: []*proto.Schema_Attribute{
+								{
+									Name:     "computed",
+									Type:     []byte(`["list","bool"]`),
+									Computed: true,
+								},
+								{
+									Name:     "optional",
+									Type:     []byte(`"string"`),
+									Optional: true,
+								},
+								{
+									Name:     "optional_computed",
+									Type:     []byte(`["map","bool"]`),
+									Optional: true,
+									Computed: true,
+								},
+								{
+									Name:     "required",
+									Type:     []byte(`"number"`),
+									Required: true,
+								},
+							},
+						},
+						Required: true,
+					},
+					{
+						Name: "deeply_nested_type",
+						NestedType: &proto.Schema_Object{
+							Nesting: proto.Schema_Object_SINGLE,
+							Attributes: []*proto.Schema_Attribute{
+								{
+									Name: "first_level",
+									NestedType: &proto.Schema_Object{
+										Nesting: proto.Schema_Object_SINGLE,
+										Attributes: []*proto.Schema_Attribute{
+											{
+												Name:     "computed",
+												Type:     []byte(`["list","bool"]`),
+												Computed: true,
+											},
+											{
+												Name:     "optional",
+												Type:     []byte(`"string"`),
+												Optional: true,
+											},
+											{
+												Name:     "optional_computed",
+												Type:     []byte(`["map","bool"]`),
+												Optional: true,
+												Computed: true,
+											},
+											{
+												Name:     "required",
+												Type:     []byte(`"number"`),
+												Required: true,
+											},
+										},
+									},
+									Computed: true,
+								},
+							},
+						},
+						Required: true,
+					},
+					{
+						Name: "nested_list",
+						NestedType: &proto.Schema_Object{
+							Nesting: proto.Schema_Object_LIST,
+							Attributes: []*proto.Schema_Attribute{
+								{
+									Name:     "required",
+									Type:     []byte(`"string"`),
+									Computed: true,
+								},
+							},
+						},
+						Required: true,
+					},
+					{
+						Name: "nested_set",
+						NestedType: &proto.Schema_Object{
+							Nesting: proto.Schema_Object_SET,
+							Attributes: []*proto.Schema_Attribute{
+								{
+									Name:     "required",
+									Type:     []byte(`"string"`),
+									Computed: true,
+								},
+							},
+						},
+						Required: true,
+					},
+					{
+						Name: "nested_map",
+						NestedType: &proto.Schema_Object{
+							Nesting: proto.Schema_Object_MAP,
+							Attributes: []*proto.Schema_Attribute{
+								{
+									Name:     "required",
+									Type:     []byte(`"string"`),
+									Computed: true,
+								},
+							},
+						},
+						Required: true,
+					},
+				},
+			},
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"computed": {
+						Type:     cty.List(cty.Bool),
+						Computed: true,
+					},
+					"optional": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"optional_computed": {
+						Type:     cty.Map(cty.Bool),
+						Optional: true,
+						Computed: true,
+					},
+					"required": {
+						Type:     cty.Number,
+						Required: true,
+					},
+					"nested_type": {
+						NestedType: &configschema.Object{
+							Attributes: map[string]*configschema.Attribute{
+								"computed": {
+									Type:     cty.List(cty.Bool),
+									Computed: true,
+								},
+								"optional": {
+									Type:     cty.String,
+									Optional: true,
+								},
+								"optional_computed": {
+									Type:     cty.Map(cty.Bool),
+									Optional: true,
+									Computed: true,
+								},
+								"required": {
+									Type:     cty.Number,
+									Required: true,
+								},
+							},
+							Nesting: configschema.NestingSingle,
+						},
+						Required: true,
+					},
+					"deeply_nested_type": {
+						NestedType: &configschema.Object{
+							Attributes: map[string]*configschema.Attribute{
+								"first_level": {
+									NestedType: &configschema.Object{
+										Nesting: configschema.NestingSingle,
+										Attributes: map[string]*configschema.Attribute{
+											"computed": {
+												Type:     cty.List(cty.Bool),
+												Computed: true,
+											},
+											"optional": {
+												Type:     cty.String,
+												Optional: true,
+											},
+											"optional_computed": {
+												Type:     cty.Map(cty.Bool),
+												Optional: true,
+												Computed: true,
+											},
+											"required": {
+												Type:     cty.Number,
+												Required: true,
+											},
+										},
+									},
+									Computed: true,
+								},
+							},
+							Nesting: configschema.NestingSingle,
+						},
+						Required: true,
+					},
+					"nested_list": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingList,
+							Attributes: map[string]*configschema.Attribute{
+								"required": {
+									Type:     cty.String,
+									Computed: true,
+								},
+							},
+						},
+						Required: true,
+					},
+					"nested_map": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingMap,
+							Attributes: map[string]*configschema.Attribute{
+								"required": {
+									Type:     cty.String,
+									Computed: true,
+								},
+							},
+						},
+						Required: true,
+					},
+					"nested_set": {
+						NestedType: &configschema.Object{
+							Nesting: configschema.NestingSet,
+							Attributes: map[string]*configschema.Attribute{
+								"required": {
+									Type:     cty.String,
+									Computed: true,
+								},
+							},
+						},
+						Required: true,
+					},
+				},
+			},
+		},
+		"blocks": {
+			&proto.Schema_Block{
+				BlockTypes: []*proto.Schema_NestedBlock{
+					{
+						TypeName: "list",
+						Nesting:  proto.Schema_NestedBlock_LIST,
+						Block:    &proto.Schema_Block{},
+					},
+					{
+						TypeName: "map",
+						Nesting:  proto.Schema_NestedBlock_MAP,
+						Block:    &proto.Schema_Block{},
+					},
+					{
+						TypeName: "set",
+						Nesting:  proto.Schema_NestedBlock_SET,
+						Block:    &proto.Schema_Block{},
+					},
+					{
+						TypeName: "single",
+						Nesting:  proto.Schema_NestedBlock_SINGLE,
+						Block: &proto.Schema_Block{
+							Attributes: []*proto.Schema_Attribute{
+								{
+									Name:     "foo",
+									Type:     []byte(`"dynamic"`),
+									Required: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"list": &configschema.NestedBlock{
+						Nesting: configschema.NestingList,
+					},
+					"map": &configschema.NestedBlock{
+						Nesting: configschema.NestingMap,
+					},
+					"set": &configschema.NestedBlock{
+						Nesting: configschema.NestingSet,
+					},
+					"single": &configschema.NestedBlock{
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"foo": {
+									Type:     cty.DynamicPseudoType,
+									Required: true,
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		"deep block nesting": {
+			&proto.Schema_Block{
+				BlockTypes: []*proto.Schema_NestedBlock{
+					{
+						TypeName: "single",
+						Nesting:  proto.Schema_NestedBlock_SINGLE,
+						Block: &proto.Schema_Block{
+							BlockTypes: []*proto.Schema_NestedBlock{
+								{
+									TypeName: "list",
+									Nesting:  proto.Schema_NestedBlock_LIST,
+									Block: &proto.Schema_Block{
+										BlockTypes: []*proto.Schema_NestedBlock{
+											{
+												TypeName: "set",
+												Nesting:  proto.Schema_NestedBlock_SET,
+												Block:    &proto.Schema_Block{},
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"single": &configschema.NestedBlock{
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							BlockTypes: map[string]*configschema.NestedBlock{
+								"list": &configschema.NestedBlock{
+									Nesting: configschema.NestingList,
+									Block: configschema.Block{
+										BlockTypes: map[string]*configschema.NestedBlock{
+											"set": &configschema.NestedBlock{
+												Nesting: configschema.NestingSet,
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for name, tc := range tests {
+		t.Run(name, func(t *testing.T) {
+			converted := ProtoToConfigSchema(tc.Block)
+			if !cmp.Equal(converted, tc.Want, typeComparer, valueComparer, equateEmpty) {
+				t.Fatal(cmp.Diff(converted, tc.Want, typeComparer, valueComparer, equateEmpty))
+			}
+		})
+	}
+}
+
+// Test that we can convert configschema to protobuf types and back again.
+func TestConvertProtoSchemaBlocks(t *testing.T) {
+	tests := map[string]struct {
+		Want  *proto.Schema_Block
+		Block *configschema.Block
+	}{
+		"attributes": {
+			&proto.Schema_Block{
+				Attributes: []*proto.Schema_Attribute{
+					{
+						Name:     "computed",
+						Type:     []byte(`["list","bool"]`),
+						Computed: true,
+					},
+					{
+						Name:     "optional",
+						Type:     []byte(`"string"`),
+						Optional: true,
+					},
+					{
+						Name:     "optional_computed",
+						Type:     []byte(`["map","bool"]`),
+						Optional: true,
+						Computed: true,
+					},
+					{
+						Name:     "required",
+						Type:     []byte(`"number"`),
+						Required: true,
+					},
+				},
+			},
+			&configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"computed": {
+						Type:     cty.List(cty.Bool),
+						Computed: true,
+					},
+					"optional": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"optional_computed": {
+						Type:     cty.Map(cty.Bool),
+						Optional: true,
+						Computed: true,
+					},
+					"required": {
+						Type:     cty.Number,
+						Required: true,
+					},
+				},
+			},
+		},
+		"blocks": {
+			&proto.Schema_Block{
+				BlockTypes: []*proto.Schema_NestedBlock{
+					{
+						TypeName: "list",
+						Nesting:  proto.Schema_NestedBlock_LIST,
+						Block:    &proto.Schema_Block{},
+					},
+					{
+						TypeName: "map",
+						Nesting:  proto.Schema_NestedBlock_MAP,
+						Block:    &proto.Schema_Block{},
+					},
+					{
+						TypeName: "set",
+						Nesting:  proto.Schema_NestedBlock_SET,
+						Block:    &proto.Schema_Block{},
+					},
+					{
+						TypeName: "single",
+						Nesting:  proto.Schema_NestedBlock_SINGLE,
+						Block: &proto.Schema_Block{
+							Attributes: []*proto.Schema_Attribute{
+								{
+									Name:     "foo",
+									Type:     []byte(`"dynamic"`),
+									Required: true,
+								},
+							},
+						},
+					},
+				},
+			},
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"list": &configschema.NestedBlock{
+						Nesting: configschema.NestingList,
+					},
+					"map": &configschema.NestedBlock{
+						Nesting: configschema.NestingMap,
+					},
+					"set": &configschema.NestedBlock{
+						Nesting: configschema.NestingSet,
+					},
+					"single": &configschema.NestedBlock{
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"foo": {
+									Type:     cty.DynamicPseudoType,
+									Required: true,
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		"deep block nesting": {
+			&proto.Schema_Block{
+				BlockTypes: []*proto.Schema_NestedBlock{
+					{
+						TypeName: "single",
+						Nesting:  proto.Schema_NestedBlock_SINGLE,
+						Block: &proto.Schema_Block{
+							BlockTypes: []*proto.Schema_NestedBlock{
+								{
+									TypeName: "list",
+									Nesting:  proto.Schema_NestedBlock_LIST,
+									Block: &proto.Schema_Block{
+										BlockTypes: []*proto.Schema_NestedBlock{
+											{
+												TypeName: "set",
+												Nesting:  proto.Schema_NestedBlock_SET,
+												Block:    &proto.Schema_Block{},
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			&configschema.Block{
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"single": &configschema.NestedBlock{
+						Nesting: configschema.NestingSingle,
+						Block: configschema.Block{
+							BlockTypes: map[string]*configschema.NestedBlock{
+								"list": &configschema.NestedBlock{
+									Nesting: configschema.NestingList,
+									Block: configschema.Block{
+										BlockTypes: map[string]*configschema.NestedBlock{
+											"set": &configschema.NestedBlock{
+												Nesting: configschema.NestingSet,
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for name, tc := range tests {
+		t.Run(name, func(t *testing.T) {
+			converted := ConfigSchemaToProto(tc.Block)
+			if !cmp.Equal(converted, tc.Want, typeComparer, equateEmpty, ignoreUnexported) {
+				t.Fatal(cmp.Diff(converted, tc.Want, typeComparer, equateEmpty, ignoreUnexported))
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/plugin6/doc.go b/v1.5.7/internal/plugin6/doc.go
new file mode 100644
index 0000000..473c9e9
--- /dev/null
+++ b/v1.5.7/internal/plugin6/doc.go
@@ -0,0 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin6
+
+// plugin6 builds on types in package plugin to include support for plugin
+// protocol v6. The main gRPC functions use by terraform (and initialized in
+// init.go), such as Serve, are in the plugin package. The version of those
+// functions in this package are used by various mocks and in tests.
+
+// When provider protocol v5 is deprecated, some functions may need to be moved
+// here, or the existing functions updated, before removing the plugin pacakge.
diff --git a/v1.5.7/internal/plugin6/grpc_error.go b/v1.5.7/internal/plugin6/grpc_error.go
new file mode 100644
index 0000000..a1e916c
--- /dev/null
+++ b/v1.5.7/internal/plugin6/grpc_error.go
@@ -0,0 +1,77 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin6
+
+import (
+	"fmt"
+	"path"
+	"runtime"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+)
+
+// grpcErr extracts some known error types and formats them into better
+// representations for core. This must only be called from plugin methods.
+// Since we don't use RPC status errors for the plugin protocol, these do not
+// contain any useful details, and we can return some text that at least
+// indicates the plugin call and possible error condition.
+func grpcErr(err error) (diags tfdiags.Diagnostics) {
+	if err == nil {
+		return
+	}
+
+	// extract the method name from the caller.
+	pc, _, _, ok := runtime.Caller(1)
+	if !ok {
+		logger.Error("unknown grpc call", "error", err)
+		return diags.Append(err)
+	}
+
+	f := runtime.FuncForPC(pc)
+
+	// Function names will contain the full import path. Take the last
+	// segment, which will let users know which method was being called.
+	_, requestName := path.Split(f.Name())
+
+	// Here we can at least correlate the error in the logs to a particular binary.
+	logger.Error(requestName, "error", err)
+
+	// TODO: while this expands the error codes into somewhat better messages,
+	// this still does not easily link the error to an actual user-recognizable
+	// plugin. The grpc plugin does not know its configured name, and the
+	// errors are in a list of diagnostics, making it hard for the caller to
+	// annotate the returned errors.
+	switch status.Code(err) {
+	case codes.Unavailable:
+		// This case is when the plugin has stopped running for some reason,
+		// and is usually the result of a crash.
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Plugin did not respond",
+			fmt.Sprintf("The plugin encountered an error, and failed to respond to the %s call. "+
+				"The plugin logs may contain more details.", requestName),
+		))
+	case codes.Canceled:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Request cancelled",
+			fmt.Sprintf("The %s request was cancelled.", requestName),
+		))
+	case codes.Unimplemented:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Unsupported plugin method",
+			fmt.Sprintf("The %s method is not supported by this plugin.", requestName),
+		))
+	default:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Plugin error",
+			fmt.Sprintf("The plugin returned an unexpected error from %s: %v", requestName, err),
+		))
+	}
+	return
+}
diff --git a/v1.5.7/internal/plugin6/grpc_provider.go b/v1.5.7/internal/plugin6/grpc_provider.go
new file mode 100644
index 0000000..a20d639
--- /dev/null
+++ b/v1.5.7/internal/plugin6/grpc_provider.go
@@ -0,0 +1,696 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin6
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"sync"
+
+	"github.com/zclconf/go-cty/cty"
+
+	plugin "github.com/hashicorp/go-plugin"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/plugin6/convert"
+	"github.com/hashicorp/terraform/internal/providers"
+	proto6 "github.com/hashicorp/terraform/internal/tfplugin6"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+	"github.com/zclconf/go-cty/cty/msgpack"
+	"google.golang.org/grpc"
+)
+
+var logger = logging.HCLogger()
+
+// GRPCProviderPlugin implements plugin.GRPCPlugin for the go-plugin package.
+type GRPCProviderPlugin struct {
+	plugin.Plugin
+	GRPCProvider func() proto6.ProviderServer
+}
+
+func (p *GRPCProviderPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
+	return &GRPCProvider{
+		client: proto6.NewProviderClient(c),
+		ctx:    ctx,
+	}, nil
+}
+
+func (p *GRPCProviderPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
+	proto6.RegisterProviderServer(s, p.GRPCProvider())
+	return nil
+}
+
+// GRPCProvider handles the client, or core side of the plugin rpc connection.
+// The GRPCProvider methods are mostly a translation layer between the
+// terraform providers types and the grpc proto types, directly converting
+// between the two.
+type GRPCProvider struct {
+	// PluginClient provides a reference to the plugin.Client which controls the plugin process.
+	// This allows the GRPCProvider a way to shutdown the plugin process.
+	PluginClient *plugin.Client
+
+	// TestServer contains a grpc.Server to close when the GRPCProvider is being
+	// used in an end to end test of a provider.
+	TestServer *grpc.Server
+
+	// Proto client use to make the grpc service calls.
+	client proto6.ProviderClient
+
+	// this context is created by the plugin package, and is canceled when the
+	// plugin process ends.
+	ctx context.Context
+
+	// schema stores the schema for this provider. This is used to properly
+	// serialize the state for requests.
+	mu      sync.Mutex
+	schemas providers.GetProviderSchemaResponse
+}
+
+func New(client proto6.ProviderClient, ctx context.Context) GRPCProvider {
+	return GRPCProvider{
+		client: client,
+		ctx:    ctx,
+	}
+}
+
+// getSchema is used internally to get the cached provider schema.
+func (p *GRPCProvider) getSchema() providers.GetProviderSchemaResponse {
+	p.mu.Lock()
+	// unlock inline in case GetProviderSchema needs to be called
+	if p.schemas.Provider.Block != nil {
+		p.mu.Unlock()
+		return p.schemas
+	}
+	p.mu.Unlock()
+
+	return p.GetProviderSchema()
+}
+
+func (p *GRPCProvider) GetProviderSchema() (resp providers.GetProviderSchemaResponse) {
+	logger.Trace("GRPCProvider.v6: GetProviderSchema")
+	p.mu.Lock()
+	defer p.mu.Unlock()
+
+	if p.schemas.Provider.Block != nil {
+		return p.schemas
+	}
+
+	resp.ResourceTypes = make(map[string]providers.Schema)
+	resp.DataSources = make(map[string]providers.Schema)
+
+	// Some providers may generate quite large schemas, and the internal default
+	// grpc response size limit is 4MB. 64MB should cover most any use case, and
+	// if we get providers nearing that we may want to consider a finer-grained
+	// API to fetch individual resource schemas.
+	// Note: this option is marked as EXPERIMENTAL in the grpc API. We keep
+	// this for compatibility, but recent providers all set the max message
+	// size much higher on the server side, which is the supported method for
+	// determining payload size.
+	const maxRecvSize = 64 << 20
+	protoResp, err := p.client.GetProviderSchema(p.ctx, new(proto6.GetProviderSchema_Request), grpc.MaxRecvMsgSizeCallOption{MaxRecvMsgSize: maxRecvSize})
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+
+	if resp.Diagnostics.HasErrors() {
+		return resp
+	}
+
+	if protoResp.Provider == nil {
+		resp.Diagnostics = resp.Diagnostics.Append(errors.New("missing provider schema"))
+		return resp
+	}
+
+	resp.Provider = convert.ProtoToProviderSchema(protoResp.Provider)
+	if protoResp.ProviderMeta == nil {
+		logger.Debug("No provider meta schema returned")
+	} else {
+		resp.ProviderMeta = convert.ProtoToProviderSchema(protoResp.ProviderMeta)
+	}
+
+	for name, res := range protoResp.ResourceSchemas {
+		resp.ResourceTypes[name] = convert.ProtoToProviderSchema(res)
+	}
+
+	for name, data := range protoResp.DataSourceSchemas {
+		resp.DataSources[name] = convert.ProtoToProviderSchema(data)
+	}
+
+	if protoResp.ServerCapabilities != nil {
+		resp.ServerCapabilities.PlanDestroy = protoResp.ServerCapabilities.PlanDestroy
+	}
+
+	p.schemas = resp
+
+	return resp
+}
+
+func (p *GRPCProvider) ValidateProviderConfig(r providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
+	logger.Trace("GRPCProvider.v6: ValidateProviderConfig")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	ty := schema.Provider.Block.ImpliedType()
+
+	mp, err := msgpack.Marshal(r.Config, ty)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto6.ValidateProviderConfig_Request{
+		Config: &proto6.DynamicValue{Msgpack: mp},
+	}
+
+	protoResp, err := p.client.ValidateProviderConfig(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+	return resp
+}
+
+func (p *GRPCProvider) ValidateResourceConfig(r providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
+	logger.Trace("GRPCProvider.v6: ValidateResourceConfig")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	resourceSchema, ok := schema.ResourceTypes[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type %q", r.TypeName))
+		return resp
+	}
+
+	mp, err := msgpack.Marshal(r.Config, resourceSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto6.ValidateResourceConfig_Request{
+		TypeName: r.TypeName,
+		Config:   &proto6.DynamicValue{Msgpack: mp},
+	}
+
+	protoResp, err := p.client.ValidateResourceConfig(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+	return resp
+}
+
+func (p *GRPCProvider) ValidateDataResourceConfig(r providers.ValidateDataResourceConfigRequest) (resp providers.ValidateDataResourceConfigResponse) {
+	logger.Trace("GRPCProvider.v6: ValidateDataResourceConfig")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	dataSchema, ok := schema.DataSources[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown data source %q", r.TypeName))
+		return resp
+	}
+
+	mp, err := msgpack.Marshal(r.Config, dataSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto6.ValidateDataResourceConfig_Request{
+		TypeName: r.TypeName,
+		Config:   &proto6.DynamicValue{Msgpack: mp},
+	}
+
+	protoResp, err := p.client.ValidateDataResourceConfig(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+	return resp
+}
+
+func (p *GRPCProvider) UpgradeResourceState(r providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
+	logger.Trace("GRPCProvider.v6: UpgradeResourceState")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	resSchema, ok := schema.ResourceTypes[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type %q", r.TypeName))
+		return resp
+	}
+
+	protoReq := &proto6.UpgradeResourceState_Request{
+		TypeName: r.TypeName,
+		Version:  int64(r.Version),
+		RawState: &proto6.RawState{
+			Json:    r.RawStateJSON,
+			Flatmap: r.RawStateFlatmap,
+		},
+	}
+
+	protoResp, err := p.client.UpgradeResourceState(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+
+	ty := resSchema.Block.ImpliedType()
+	resp.UpgradedState = cty.NullVal(ty)
+	if protoResp.UpgradedState == nil {
+		return resp
+	}
+
+	state, err := decodeDynamicValue(protoResp.UpgradedState, ty)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+	resp.UpgradedState = state
+
+	return resp
+}
+
+func (p *GRPCProvider) ConfigureProvider(r providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+	logger.Trace("GRPCProvider.v6: ConfigureProvider")
+
+	schema := p.getSchema()
+
+	var mp []byte
+
+	// we don't have anything to marshal if there's no config
+	mp, err := msgpack.Marshal(r.Config, schema.Provider.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto6.ConfigureProvider_Request{
+		TerraformVersion: r.TerraformVersion,
+		Config: &proto6.DynamicValue{
+			Msgpack: mp,
+		},
+	}
+
+	protoResp, err := p.client.ConfigureProvider(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+	return resp
+}
+
+func (p *GRPCProvider) Stop() error {
+	logger.Trace("GRPCProvider.v6: Stop")
+
+	resp, err := p.client.StopProvider(p.ctx, new(proto6.StopProvider_Request))
+	if err != nil {
+		return err
+	}
+
+	if resp.Error != "" {
+		return errors.New(resp.Error)
+	}
+	return nil
+}
+
+func (p *GRPCProvider) ReadResource(r providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+	logger.Trace("GRPCProvider.v6: ReadResource")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	resSchema, ok := schema.ResourceTypes[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type " + r.TypeName))
+		return resp
+	}
+
+	metaSchema := schema.ProviderMeta
+
+	mp, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto6.ReadResource_Request{
+		TypeName:     r.TypeName,
+		CurrentState: &proto6.DynamicValue{Msgpack: mp},
+		Private:      r.Private,
+	}
+
+	if metaSchema.Block != nil {
+		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
+		if err != nil {
+			resp.Diagnostics = resp.Diagnostics.Append(err)
+			return resp
+		}
+		protoReq.ProviderMeta = &proto6.DynamicValue{Msgpack: metaMP}
+	}
+
+	protoResp, err := p.client.ReadResource(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+
+	state, err := decodeDynamicValue(protoResp.NewState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+	resp.NewState = state
+	resp.Private = protoResp.Private
+
+	return resp
+}
+
+func (p *GRPCProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+	logger.Trace("GRPCProvider.v6: PlanResourceChange")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	resSchema, ok := schema.ResourceTypes[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type %q", r.TypeName))
+		return resp
+	}
+
+	metaSchema := schema.ProviderMeta
+	capabilities := schema.ServerCapabilities
+
+	// If the provider doesn't support planning a destroy operation, we can
+	// return immediately.
+	if r.ProposedNewState.IsNull() && !capabilities.PlanDestroy {
+		resp.PlannedState = r.ProposedNewState
+		resp.PlannedPrivate = r.PriorPrivate
+		return resp
+	}
+
+	priorMP, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	configMP, err := msgpack.Marshal(r.Config, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	propMP, err := msgpack.Marshal(r.ProposedNewState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto6.PlanResourceChange_Request{
+		TypeName:         r.TypeName,
+		PriorState:       &proto6.DynamicValue{Msgpack: priorMP},
+		Config:           &proto6.DynamicValue{Msgpack: configMP},
+		ProposedNewState: &proto6.DynamicValue{Msgpack: propMP},
+		PriorPrivate:     r.PriorPrivate,
+	}
+
+	if metaSchema.Block != nil {
+		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
+		if err != nil {
+			resp.Diagnostics = resp.Diagnostics.Append(err)
+			return resp
+		}
+		protoReq.ProviderMeta = &proto6.DynamicValue{Msgpack: metaMP}
+	}
+
+	protoResp, err := p.client.PlanResourceChange(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+
+	state, err := decodeDynamicValue(protoResp.PlannedState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+	resp.PlannedState = state
+
+	for _, p := range protoResp.RequiresReplace {
+		resp.RequiresReplace = append(resp.RequiresReplace, convert.AttributePathToPath(p))
+	}
+
+	resp.PlannedPrivate = protoResp.PlannedPrivate
+
+	resp.LegacyTypeSystem = protoResp.LegacyTypeSystem
+
+	return resp
+}
+
+func (p *GRPCProvider) ApplyResourceChange(r providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+	logger.Trace("GRPCProvider.v6: ApplyResourceChange")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	resSchema, ok := schema.ResourceTypes[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type %q", r.TypeName))
+		return resp
+	}
+
+	metaSchema := schema.ProviderMeta
+
+	priorMP, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+	plannedMP, err := msgpack.Marshal(r.PlannedState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+	configMP, err := msgpack.Marshal(r.Config, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto6.ApplyResourceChange_Request{
+		TypeName:       r.TypeName,
+		PriorState:     &proto6.DynamicValue{Msgpack: priorMP},
+		PlannedState:   &proto6.DynamicValue{Msgpack: plannedMP},
+		Config:         &proto6.DynamicValue{Msgpack: configMP},
+		PlannedPrivate: r.PlannedPrivate,
+	}
+
+	if metaSchema.Block != nil {
+		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
+		if err != nil {
+			resp.Diagnostics = resp.Diagnostics.Append(err)
+			return resp
+		}
+		protoReq.ProviderMeta = &proto6.DynamicValue{Msgpack: metaMP}
+	}
+
+	protoResp, err := p.client.ApplyResourceChange(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+
+	resp.Private = protoResp.Private
+
+	state, err := decodeDynamicValue(protoResp.NewState, resSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+	resp.NewState = state
+
+	resp.LegacyTypeSystem = protoResp.LegacyTypeSystem
+
+	return resp
+}
+
+func (p *GRPCProvider) ImportResourceState(r providers.ImportResourceStateRequest) (resp providers.ImportResourceStateResponse) {
+	logger.Trace("GRPCProvider.v6: ImportResourceState")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	protoReq := &proto6.ImportResourceState_Request{
+		TypeName: r.TypeName,
+		Id:       r.ID,
+	}
+
+	protoResp, err := p.client.ImportResourceState(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+
+	for _, imported := range protoResp.ImportedResources {
+		resource := providers.ImportedResource{
+			TypeName: imported.TypeName,
+			Private:  imported.Private,
+		}
+
+		resSchema, ok := schema.ResourceTypes[r.TypeName]
+		if !ok {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown resource type %q", r.TypeName))
+			continue
+		}
+
+		state, err := decodeDynamicValue(imported.State, resSchema.Block.ImpliedType())
+		if err != nil {
+			resp.Diagnostics = resp.Diagnostics.Append(err)
+			return resp
+		}
+		resource.State = state
+		resp.ImportedResources = append(resp.ImportedResources, resource)
+	}
+
+	return resp
+}
+
+func (p *GRPCProvider) ReadDataSource(r providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+	logger.Trace("GRPCProvider.v6: ReadDataSource")
+
+	schema := p.getSchema()
+	if schema.Diagnostics.HasErrors() {
+		resp.Diagnostics = schema.Diagnostics
+		return resp
+	}
+
+	dataSchema, ok := schema.DataSources[r.TypeName]
+	if !ok {
+		schema.Diagnostics = schema.Diagnostics.Append(fmt.Errorf("unknown data source %q", r.TypeName))
+	}
+
+	metaSchema := schema.ProviderMeta
+
+	config, err := msgpack.Marshal(r.Config, dataSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	protoReq := &proto6.ReadDataSource_Request{
+		TypeName: r.TypeName,
+		Config: &proto6.DynamicValue{
+			Msgpack: config,
+		},
+	}
+
+	if metaSchema.Block != nil {
+		metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType())
+		if err != nil {
+			resp.Diagnostics = resp.Diagnostics.Append(err)
+			return resp
+		}
+		protoReq.ProviderMeta = &proto6.DynamicValue{Msgpack: metaMP}
+	}
+
+	protoResp, err := p.client.ReadDataSource(p.ctx, protoReq)
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(grpcErr(err))
+		return resp
+	}
+	resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
+
+	state, err := decodeDynamicValue(protoResp.State, dataSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+	resp.State = state
+
+	return resp
+}
+
+// closing the grpc connection is final, and terraform will call it at the end of every phase.
+func (p *GRPCProvider) Close() error {
+	logger.Trace("GRPCProvider.v6: Close")
+
+	// Make sure to stop the server if we're not running within go-plugin.
+	if p.TestServer != nil {
+		p.TestServer.Stop()
+	}
+
+	// Check this since it's not automatically inserted during plugin creation.
+	// It's currently only inserted by the command package, because that is
+	// where the factory is built and is the only point with access to the
+	// plugin.Client.
+	if p.PluginClient == nil {
+		logger.Debug("provider has no plugin.Client")
+		return nil
+	}
+
+	p.PluginClient.Kill()
+	return nil
+}
+
+// Decode a DynamicValue from either the JSON or MsgPack encoding.
+func decodeDynamicValue(v *proto6.DynamicValue, ty cty.Type) (cty.Value, error) {
+	// always return a valid value
+	var err error
+	res := cty.NullVal(ty)
+	if v == nil {
+		return res, nil
+	}
+
+	switch {
+	case len(v.Msgpack) > 0:
+		res, err = msgpack.Unmarshal(v.Msgpack, ty)
+	case len(v.Json) > 0:
+		res, err = ctyjson.Unmarshal(v.Json, ty)
+	}
+	return res, err
+}
diff --git a/v1.5.7/internal/plugin6/grpc_provider_test.go b/v1.5.7/internal/plugin6/grpc_provider_test.go
new file mode 100644
index 0000000..4f81c01
--- /dev/null
+++ b/v1.5.7/internal/plugin6/grpc_provider_test.go
@@ -0,0 +1,787 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin6
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+
+	mockproto "github.com/hashicorp/terraform/internal/plugin6/mock_proto"
+	proto "github.com/hashicorp/terraform/internal/tfplugin6"
+)
+
+var _ providers.Interface = (*GRPCProvider)(nil)
+
+var (
+	equateEmpty   = cmpopts.EquateEmpty()
+	typeComparer  = cmp.Comparer(cty.Type.Equals)
+	valueComparer = cmp.Comparer(cty.Value.RawEquals)
+)
+
+func mockProviderClient(t *testing.T) *mockproto.MockProviderClient {
+	ctrl := gomock.NewController(t)
+	client := mockproto.NewMockProviderClient(ctrl)
+
+	// we always need a GetSchema method
+	client.EXPECT().GetProviderSchema(
+		gomock.Any(),
+		gomock.Any(),
+		gomock.Any(),
+	).Return(providerProtoSchema(), nil)
+
+	return client
+}
+
+func checkDiags(t *testing.T, d tfdiags.Diagnostics) {
+	t.Helper()
+	if d.HasErrors() {
+		t.Fatal(d.Err())
+	}
+}
+
+// checkDiagsHasError ensures error diagnostics are present or fails the test.
+func checkDiagsHasError(t *testing.T, d tfdiags.Diagnostics) {
+	t.Helper()
+
+	if !d.HasErrors() {
+		t.Fatal("expected error diagnostics")
+	}
+}
+
+func providerProtoSchema() *proto.GetProviderSchema_Response {
+	return &proto.GetProviderSchema_Response{
+		Provider: &proto.Schema{
+			Block: &proto.Schema_Block{
+				Attributes: []*proto.Schema_Attribute{
+					{
+						Name:     "attr",
+						Type:     []byte(`"string"`),
+						Required: true,
+					},
+				},
+			},
+		},
+		ResourceSchemas: map[string]*proto.Schema{
+			"resource": {
+				Version: 1,
+				Block: &proto.Schema_Block{
+					Attributes: []*proto.Schema_Attribute{
+						{
+							Name:     "attr",
+							Type:     []byte(`"string"`),
+							Required: true,
+						},
+					},
+				},
+			},
+		},
+		DataSourceSchemas: map[string]*proto.Schema{
+			"data": {
+				Version: 1,
+				Block: &proto.Schema_Block{
+					Attributes: []*proto.Schema_Attribute{
+						{
+							Name:     "attr",
+							Type:     []byte(`"string"`),
+							Required: true,
+						},
+					},
+				},
+			},
+		},
+	}
+}
+
+func TestGRPCProvider_GetSchema(t *testing.T) {
+	p := &GRPCProvider{
+		client: mockProviderClient(t),
+	}
+
+	resp := p.GetProviderSchema()
+	checkDiags(t, resp.Diagnostics)
+}
+
+// Ensure that gRPC errors are returned early.
+// Reference: https://github.com/hashicorp/terraform/issues/31047
+func TestGRPCProvider_GetSchema_GRPCError(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	client := mockproto.NewMockProviderClient(ctrl)
+
+	client.EXPECT().GetProviderSchema(
+		gomock.Any(),
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.GetProviderSchema_Response{}, fmt.Errorf("test error"))
+
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	resp := p.GetProviderSchema()
+
+	checkDiagsHasError(t, resp.Diagnostics)
+}
+
+// Ensure that provider error diagnostics are returned early.
+// Reference: https://github.com/hashicorp/terraform/issues/31047
+func TestGRPCProvider_GetSchema_ResponseErrorDiagnostic(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	client := mockproto.NewMockProviderClient(ctrl)
+
+	client.EXPECT().GetProviderSchema(
+		gomock.Any(),
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.GetProviderSchema_Response{
+		Diagnostics: []*proto.Diagnostic{
+			{
+				Severity: proto.Diagnostic_ERROR,
+				Summary:  "error summary",
+				Detail:   "error detail",
+			},
+		},
+		// Trigger potential panics
+		Provider: &proto.Schema{},
+	}, nil)
+
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	resp := p.GetProviderSchema()
+
+	checkDiagsHasError(t, resp.Diagnostics)
+}
+
+func TestGRPCProvider_PrepareProviderConfig(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ValidateProviderConfig(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ValidateProviderConfig_Response{}, nil)
+
+	cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"})
+	resp := p.ValidateProviderConfig(providers.ValidateProviderConfigRequest{Config: cfg})
+	checkDiags(t, resp.Diagnostics)
+}
+
+func TestGRPCProvider_ValidateResourceConfig(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ValidateResourceConfig(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ValidateResourceConfig_Response{}, nil)
+
+	cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"})
+	resp := p.ValidateResourceConfig(providers.ValidateResourceConfigRequest{
+		TypeName: "resource",
+		Config:   cfg,
+	})
+	checkDiags(t, resp.Diagnostics)
+}
+
+func TestGRPCProvider_ValidateDataResourceConfig(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ValidateDataResourceConfig(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ValidateDataResourceConfig_Response{}, nil)
+
+	cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"})
+	resp := p.ValidateDataResourceConfig(providers.ValidateDataResourceConfigRequest{
+		TypeName: "data",
+		Config:   cfg,
+	})
+	checkDiags(t, resp.Diagnostics)
+}
+
+func TestGRPCProvider_UpgradeResourceState(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().UpgradeResourceState(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.UpgradeResourceState_Response{
+		UpgradedState: &proto.DynamicValue{
+			Msgpack: []byte("\x81\xa4attr\xa3bar"),
+		},
+	}, nil)
+
+	resp := p.UpgradeResourceState(providers.UpgradeResourceStateRequest{
+		TypeName:     "resource",
+		Version:      0,
+		RawStateJSON: []byte(`{"old_attr":"bar"}`),
+	})
+	checkDiags(t, resp.Diagnostics)
+
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty))
+	}
+}
+
+func TestGRPCProvider_UpgradeResourceStateJSON(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().UpgradeResourceState(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.UpgradeResourceState_Response{
+		UpgradedState: &proto.DynamicValue{
+			Json: []byte(`{"attr":"bar"}`),
+		},
+	}, nil)
+
+	resp := p.UpgradeResourceState(providers.UpgradeResourceStateRequest{
+		TypeName:     "resource",
+		Version:      0,
+		RawStateJSON: []byte(`{"old_attr":"bar"}`),
+	})
+	checkDiags(t, resp.Diagnostics)
+
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty))
+	}
+}
+
+func TestGRPCProvider_Configure(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ConfigureProvider(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ConfigureProvider_Response{}, nil)
+
+	resp := p.ConfigureProvider(providers.ConfigureProviderRequest{
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+	})
+	checkDiags(t, resp.Diagnostics)
+}
+
+func TestGRPCProvider_Stop(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	client := mockproto.NewMockProviderClient(ctrl)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().StopProvider(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.StopProvider_Response{}, nil)
+
+	err := p.Stop()
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestGRPCProvider_ReadResource(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ReadResource(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ReadResource_Response{
+		NewState: &proto.DynamicValue{
+			Msgpack: []byte("\x81\xa4attr\xa3bar"),
+		},
+	}, nil)
+
+	resp := p.ReadResource(providers.ReadResourceRequest{
+		TypeName: "resource",
+		PriorState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty))
+	}
+}
+
+func TestGRPCProvider_ReadResourceJSON(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ReadResource(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ReadResource_Response{
+		NewState: &proto.DynamicValue{
+			Json: []byte(`{"attr":"bar"}`),
+		},
+	}, nil)
+
+	resp := p.ReadResource(providers.ReadResourceRequest{
+		TypeName: "resource",
+		PriorState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty))
+	}
+}
+
+func TestGRPCProvider_ReadEmptyJSON(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ReadResource(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ReadResource_Response{
+		NewState: &proto.DynamicValue{
+			Json: []byte(``),
+		},
+	}, nil)
+
+	obj := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("foo"),
+	})
+	resp := p.ReadResource(providers.ReadResourceRequest{
+		TypeName:   "resource",
+		PriorState: obj,
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expected := cty.NullVal(obj.Type())
+
+	if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty))
+	}
+}
+
+func TestGRPCProvider_PlanResourceChange(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	expectedPrivate := []byte(`{"meta": "data"}`)
+
+	client.EXPECT().PlanResourceChange(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.PlanResourceChange_Response{
+		PlannedState: &proto.DynamicValue{
+			Msgpack: []byte("\x81\xa4attr\xa3bar"),
+		},
+		RequiresReplace: []*proto.AttributePath{
+			{
+				Steps: []*proto.AttributePath_Step{
+					{
+						Selector: &proto.AttributePath_Step_AttributeName{
+							AttributeName: "attr",
+						},
+					},
+				},
+			},
+		},
+		PlannedPrivate: expectedPrivate,
+	}, nil)
+
+	resp := p.PlanResourceChange(providers.PlanResourceChangeRequest{
+		TypeName: "resource",
+		PriorState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+		ProposedNewState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expectedState := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty))
+	}
+
+	expectedReplace := `[]cty.Path{cty.Path{cty.GetAttrStep{Name:"attr"}}}`
+	replace := fmt.Sprintf("%#v", resp.RequiresReplace)
+	if expectedReplace != replace {
+		t.Fatalf("expected %q, got %q", expectedReplace, replace)
+	}
+
+	if !bytes.Equal(expectedPrivate, resp.PlannedPrivate) {
+		t.Fatalf("expected %q, got %q", expectedPrivate, resp.PlannedPrivate)
+	}
+}
+
+func TestGRPCProvider_PlanResourceChangeJSON(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	expectedPrivate := []byte(`{"meta": "data"}`)
+
+	client.EXPECT().PlanResourceChange(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.PlanResourceChange_Response{
+		PlannedState: &proto.DynamicValue{
+			Json: []byte(`{"attr":"bar"}`),
+		},
+		RequiresReplace: []*proto.AttributePath{
+			{
+				Steps: []*proto.AttributePath_Step{
+					{
+						Selector: &proto.AttributePath_Step_AttributeName{
+							AttributeName: "attr",
+						},
+					},
+				},
+			},
+		},
+		PlannedPrivate: expectedPrivate,
+	}, nil)
+
+	resp := p.PlanResourceChange(providers.PlanResourceChangeRequest{
+		TypeName: "resource",
+		PriorState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+		ProposedNewState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expectedState := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty))
+	}
+
+	expectedReplace := `[]cty.Path{cty.Path{cty.GetAttrStep{Name:"attr"}}}`
+	replace := fmt.Sprintf("%#v", resp.RequiresReplace)
+	if expectedReplace != replace {
+		t.Fatalf("expected %q, got %q", expectedReplace, replace)
+	}
+
+	if !bytes.Equal(expectedPrivate, resp.PlannedPrivate) {
+		t.Fatalf("expected %q, got %q", expectedPrivate, resp.PlannedPrivate)
+	}
+}
+
+func TestGRPCProvider_ApplyResourceChange(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	expectedPrivate := []byte(`{"meta": "data"}`)
+
+	client.EXPECT().ApplyResourceChange(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ApplyResourceChange_Response{
+		NewState: &proto.DynamicValue{
+			Msgpack: []byte("\x81\xa4attr\xa3bar"),
+		},
+		Private: expectedPrivate,
+	}, nil)
+
+	resp := p.ApplyResourceChange(providers.ApplyResourceChangeRequest{
+		TypeName: "resource",
+		PriorState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+		PlannedState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		PlannedPrivate: expectedPrivate,
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expectedState := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty))
+	}
+
+	if !bytes.Equal(expectedPrivate, resp.Private) {
+		t.Fatalf("expected %q, got %q", expectedPrivate, resp.Private)
+	}
+}
+func TestGRPCProvider_ApplyResourceChangeJSON(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	expectedPrivate := []byte(`{"meta": "data"}`)
+
+	client.EXPECT().ApplyResourceChange(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ApplyResourceChange_Response{
+		NewState: &proto.DynamicValue{
+			Json: []byte(`{"attr":"bar"}`),
+		},
+		Private: expectedPrivate,
+	}, nil)
+
+	resp := p.ApplyResourceChange(providers.ApplyResourceChangeRequest{
+		TypeName: "resource",
+		PriorState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+		PlannedState: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		PlannedPrivate: expectedPrivate,
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expectedState := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty))
+	}
+
+	if !bytes.Equal(expectedPrivate, resp.Private) {
+		t.Fatalf("expected %q, got %q", expectedPrivate, resp.Private)
+	}
+}
+
+func TestGRPCProvider_ImportResourceState(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	expectedPrivate := []byte(`{"meta": "data"}`)
+
+	client.EXPECT().ImportResourceState(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ImportResourceState_Response{
+		ImportedResources: []*proto.ImportResourceState_ImportedResource{
+			{
+				TypeName: "resource",
+				State: &proto.DynamicValue{
+					Msgpack: []byte("\x81\xa4attr\xa3bar"),
+				},
+				Private: expectedPrivate,
+			},
+		},
+	}, nil)
+
+	resp := p.ImportResourceState(providers.ImportResourceStateRequest{
+		TypeName: "resource",
+		ID:       "foo",
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expectedResource := providers.ImportedResource{
+		TypeName: "resource",
+		State: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		Private: expectedPrivate,
+	}
+
+	imported := resp.ImportedResources[0]
+	if !cmp.Equal(expectedResource, imported, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expectedResource, imported, typeComparer, valueComparer, equateEmpty))
+	}
+}
+func TestGRPCProvider_ImportResourceStateJSON(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	expectedPrivate := []byte(`{"meta": "data"}`)
+
+	client.EXPECT().ImportResourceState(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ImportResourceState_Response{
+		ImportedResources: []*proto.ImportResourceState_ImportedResource{
+			{
+				TypeName: "resource",
+				State: &proto.DynamicValue{
+					Json: []byte(`{"attr":"bar"}`),
+				},
+				Private: expectedPrivate,
+			},
+		},
+	}, nil)
+
+	resp := p.ImportResourceState(providers.ImportResourceStateRequest{
+		TypeName: "resource",
+		ID:       "foo",
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expectedResource := providers.ImportedResource{
+		TypeName: "resource",
+		State: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("bar"),
+		}),
+		Private: expectedPrivate,
+	}
+
+	imported := resp.ImportedResources[0]
+	if !cmp.Equal(expectedResource, imported, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expectedResource, imported, typeComparer, valueComparer, equateEmpty))
+	}
+}
+
+func TestGRPCProvider_ReadDataSource(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ReadDataSource(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ReadDataSource_Response{
+		State: &proto.DynamicValue{
+			Msgpack: []byte("\x81\xa4attr\xa3bar"),
+		},
+	}, nil)
+
+	resp := p.ReadDataSource(providers.ReadDataSourceRequest{
+		TypeName: "data",
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expected, resp.State, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expected, resp.State, typeComparer, valueComparer, equateEmpty))
+	}
+}
+
+func TestGRPCProvider_ReadDataSourceJSON(t *testing.T) {
+	client := mockProviderClient(t)
+	p := &GRPCProvider{
+		client: client,
+	}
+
+	client.EXPECT().ReadDataSource(
+		gomock.Any(),
+		gomock.Any(),
+	).Return(&proto.ReadDataSource_Response{
+		State: &proto.DynamicValue{
+			Json: []byte(`{"attr":"bar"}`),
+		},
+	}, nil)
+
+	resp := p.ReadDataSource(providers.ReadDataSourceRequest{
+		TypeName: "data",
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"attr": cty.StringVal("foo"),
+		}),
+	})
+
+	checkDiags(t, resp.Diagnostics)
+
+	expected := cty.ObjectVal(map[string]cty.Value{
+		"attr": cty.StringVal("bar"),
+	})
+
+	if !cmp.Equal(expected, resp.State, typeComparer, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expected, resp.State, typeComparer, valueComparer, equateEmpty))
+	}
+}
diff --git a/v1.5.7/internal/plugin6/mock_proto/generate.go b/v1.5.7/internal/plugin6/mock_proto/generate.go
new file mode 100644
index 0000000..a00208a
--- /dev/null
+++ b/v1.5.7/internal/plugin6/mock_proto/generate.go
@@ -0,0 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:generate go run github.com/golang/mock/mockgen -destination mock.go github.com/hashicorp/terraform/internal/tfplugin6 ProviderClient
+
+package mock_tfplugin6
diff --git a/v1.5.7/internal/plugin6/mock_proto/mock.go b/v1.5.7/internal/plugin6/mock_proto/mock.go
new file mode 100644
index 0000000..448008e
--- /dev/null
+++ b/v1.5.7/internal/plugin6/mock_proto/mock.go
@@ -0,0 +1,277 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: github.com/hashicorp/terraform/internal/tfplugin6 (interfaces: ProviderClient)
+
+// Package mock_tfplugin6 is a generated GoMock package.
+package mock_tfplugin6
+
+import (
+	context "context"
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	tfplugin6 "github.com/hashicorp/terraform/internal/tfplugin6"
+	grpc "google.golang.org/grpc"
+)
+
+// MockProviderClient is a mock of ProviderClient interface.
+type MockProviderClient struct {
+	ctrl     *gomock.Controller
+	recorder *MockProviderClientMockRecorder
+}
+
+// MockProviderClientMockRecorder is the mock recorder for MockProviderClient.
+type MockProviderClientMockRecorder struct {
+	mock *MockProviderClient
+}
+
+// NewMockProviderClient creates a new mock instance.
+func NewMockProviderClient(ctrl *gomock.Controller) *MockProviderClient {
+	mock := &MockProviderClient{ctrl: ctrl}
+	mock.recorder = &MockProviderClientMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockProviderClient) EXPECT() *MockProviderClientMockRecorder {
+	return m.recorder
+}
+
+// ApplyResourceChange mocks base method.
+func (m *MockProviderClient) ApplyResourceChange(arg0 context.Context, arg1 *tfplugin6.ApplyResourceChange_Request, arg2 ...grpc.CallOption) (*tfplugin6.ApplyResourceChange_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ApplyResourceChange", varargs...)
+	ret0, _ := ret[0].(*tfplugin6.ApplyResourceChange_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ApplyResourceChange indicates an expected call of ApplyResourceChange.
+func (mr *MockProviderClientMockRecorder) ApplyResourceChange(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyResourceChange", reflect.TypeOf((*MockProviderClient)(nil).ApplyResourceChange), varargs...)
+}
+
+// ConfigureProvider mocks base method.
+func (m *MockProviderClient) ConfigureProvider(arg0 context.Context, arg1 *tfplugin6.ConfigureProvider_Request, arg2 ...grpc.CallOption) (*tfplugin6.ConfigureProvider_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ConfigureProvider", varargs...)
+	ret0, _ := ret[0].(*tfplugin6.ConfigureProvider_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ConfigureProvider indicates an expected call of ConfigureProvider.
+func (mr *MockProviderClientMockRecorder) ConfigureProvider(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigureProvider", reflect.TypeOf((*MockProviderClient)(nil).ConfigureProvider), varargs...)
+}
+
+// GetProviderSchema mocks base method.
+func (m *MockProviderClient) GetProviderSchema(arg0 context.Context, arg1 *tfplugin6.GetProviderSchema_Request, arg2 ...grpc.CallOption) (*tfplugin6.GetProviderSchema_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetProviderSchema", varargs...)
+	ret0, _ := ret[0].(*tfplugin6.GetProviderSchema_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetProviderSchema indicates an expected call of GetProviderSchema.
+func (mr *MockProviderClientMockRecorder) GetProviderSchema(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProviderSchema", reflect.TypeOf((*MockProviderClient)(nil).GetProviderSchema), varargs...)
+}
+
+// ImportResourceState mocks base method.
+func (m *MockProviderClient) ImportResourceState(arg0 context.Context, arg1 *tfplugin6.ImportResourceState_Request, arg2 ...grpc.CallOption) (*tfplugin6.ImportResourceState_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ImportResourceState", varargs...)
+	ret0, _ := ret[0].(*tfplugin6.ImportResourceState_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ImportResourceState indicates an expected call of ImportResourceState.
+func (mr *MockProviderClientMockRecorder) ImportResourceState(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ImportResourceState", reflect.TypeOf((*MockProviderClient)(nil).ImportResourceState), varargs...)
+}
+
+// PlanResourceChange mocks base method.
+func (m *MockProviderClient) PlanResourceChange(arg0 context.Context, arg1 *tfplugin6.PlanResourceChange_Request, arg2 ...grpc.CallOption) (*tfplugin6.PlanResourceChange_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "PlanResourceChange", varargs...)
+	ret0, _ := ret[0].(*tfplugin6.PlanResourceChange_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// PlanResourceChange indicates an expected call of PlanResourceChange.
+func (mr *MockProviderClientMockRecorder) PlanResourceChange(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PlanResourceChange", reflect.TypeOf((*MockProviderClient)(nil).PlanResourceChange), varargs...)
+}
+
+// ReadDataSource mocks base method.
+func (m *MockProviderClient) ReadDataSource(arg0 context.Context, arg1 *tfplugin6.ReadDataSource_Request, arg2 ...grpc.CallOption) (*tfplugin6.ReadDataSource_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ReadDataSource", varargs...)
+	ret0, _ := ret[0].(*tfplugin6.ReadDataSource_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ReadDataSource indicates an expected call of ReadDataSource.
+func (mr *MockProviderClientMockRecorder) ReadDataSource(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadDataSource", reflect.TypeOf((*MockProviderClient)(nil).ReadDataSource), varargs...)
+}
+
+// ReadResource mocks base method.
+func (m *MockProviderClient) ReadResource(arg0 context.Context, arg1 *tfplugin6.ReadResource_Request, arg2 ...grpc.CallOption) (*tfplugin6.ReadResource_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ReadResource", varargs...)
+	ret0, _ := ret[0].(*tfplugin6.ReadResource_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ReadResource indicates an expected call of ReadResource.
+func (mr *MockProviderClientMockRecorder) ReadResource(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadResource", reflect.TypeOf((*MockProviderClient)(nil).ReadResource), varargs...)
+}
+
+// StopProvider mocks base method.
+func (m *MockProviderClient) StopProvider(arg0 context.Context, arg1 *tfplugin6.StopProvider_Request, arg2 ...grpc.CallOption) (*tfplugin6.StopProvider_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "StopProvider", varargs...)
+	ret0, _ := ret[0].(*tfplugin6.StopProvider_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// StopProvider indicates an expected call of StopProvider.
+func (mr *MockProviderClientMockRecorder) StopProvider(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StopProvider", reflect.TypeOf((*MockProviderClient)(nil).StopProvider), varargs...)
+}
+
+// UpgradeResourceState mocks base method.
+func (m *MockProviderClient) UpgradeResourceState(arg0 context.Context, arg1 *tfplugin6.UpgradeResourceState_Request, arg2 ...grpc.CallOption) (*tfplugin6.UpgradeResourceState_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "UpgradeResourceState", varargs...)
+	ret0, _ := ret[0].(*tfplugin6.UpgradeResourceState_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// UpgradeResourceState indicates an expected call of UpgradeResourceState.
+func (mr *MockProviderClientMockRecorder) UpgradeResourceState(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpgradeResourceState", reflect.TypeOf((*MockProviderClient)(nil).UpgradeResourceState), varargs...)
+}
+
+// ValidateDataResourceConfig mocks base method.
+func (m *MockProviderClient) ValidateDataResourceConfig(arg0 context.Context, arg1 *tfplugin6.ValidateDataResourceConfig_Request, arg2 ...grpc.CallOption) (*tfplugin6.ValidateDataResourceConfig_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ValidateDataResourceConfig", varargs...)
+	ret0, _ := ret[0].(*tfplugin6.ValidateDataResourceConfig_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ValidateDataResourceConfig indicates an expected call of ValidateDataResourceConfig.
+func (mr *MockProviderClientMockRecorder) ValidateDataResourceConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateDataResourceConfig", reflect.TypeOf((*MockProviderClient)(nil).ValidateDataResourceConfig), varargs...)
+}
+
+// ValidateProviderConfig mocks base method.
+func (m *MockProviderClient) ValidateProviderConfig(arg0 context.Context, arg1 *tfplugin6.ValidateProviderConfig_Request, arg2 ...grpc.CallOption) (*tfplugin6.ValidateProviderConfig_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ValidateProviderConfig", varargs...)
+	ret0, _ := ret[0].(*tfplugin6.ValidateProviderConfig_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ValidateProviderConfig indicates an expected call of ValidateProviderConfig.
+func (mr *MockProviderClientMockRecorder) ValidateProviderConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateProviderConfig", reflect.TypeOf((*MockProviderClient)(nil).ValidateProviderConfig), varargs...)
+}
+
+// ValidateResourceConfig mocks base method.
+func (m *MockProviderClient) ValidateResourceConfig(arg0 context.Context, arg1 *tfplugin6.ValidateResourceConfig_Request, arg2 ...grpc.CallOption) (*tfplugin6.ValidateResourceConfig_Response, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ValidateResourceConfig", varargs...)
+	ret0, _ := ret[0].(*tfplugin6.ValidateResourceConfig_Response)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ValidateResourceConfig indicates an expected call of ValidateResourceConfig.
+func (mr *MockProviderClientMockRecorder) ValidateResourceConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateResourceConfig", reflect.TypeOf((*MockProviderClient)(nil).ValidateResourceConfig), varargs...)
+}
diff --git a/v1.5.7/internal/plugin6/serve.go b/v1.5.7/internal/plugin6/serve.go
new file mode 100644
index 0000000..03ccff5
--- /dev/null
+++ b/v1.5.7/internal/plugin6/serve.go
@@ -0,0 +1,66 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package plugin6
+
+import (
+	"github.com/hashicorp/go-plugin"
+	proto "github.com/hashicorp/terraform/internal/tfplugin6"
+)
+
+const (
+	// The constants below are the names of the plugins that can be dispensed
+	// from the plugin server.
+	ProviderPluginName = "provider"
+
+	// DefaultProtocolVersion is the protocol version assumed for legacy clients
+	// that don't specify a particular version during their handshake. Since we
+	// explicitly set VersionedPlugins in Serve, this number does not need to
+	// change with the protocol version and can effectively stay 4 forever
+	// (unless we need the "biggest hammer" approach to break all provider
+	// compatibility).
+	DefaultProtocolVersion = 4
+)
+
+// Handshake is the HandshakeConfig used to configure clients and servers.
+var Handshake = plugin.HandshakeConfig{
+	// The ProtocolVersion is the version that must match between TF core
+	// and TF plugins.
+	ProtocolVersion: DefaultProtocolVersion,
+
+	// The magic cookie values should NEVER be changed.
+	MagicCookieKey:   "TF_PLUGIN_MAGIC_COOKIE",
+	MagicCookieValue: "d602bf8f470bc67ca7faa0386276bbdd4330efaf76d1a219cb4d6991ca9872b2",
+}
+
+type GRPCProviderFunc func() proto.ProviderServer
+
+// ServeOpts are the configurations to serve a plugin.
+type ServeOpts struct {
+	GRPCProviderFunc GRPCProviderFunc
+}
+
+// Serve serves a plugin. This function never returns and should be the final
+// function called in the main function of the plugin.
+func Serve(opts *ServeOpts) {
+	plugin.Serve(&plugin.ServeConfig{
+		HandshakeConfig:  Handshake,
+		VersionedPlugins: pluginSet(opts),
+		GRPCServer:       plugin.DefaultGRPCServer,
+	})
+}
+
+func pluginSet(opts *ServeOpts) map[int]plugin.PluginSet {
+	plugins := map[int]plugin.PluginSet{}
+
+	// add the new protocol versions if they're configured
+	if opts.GRPCProviderFunc != nil {
+		plugins[6] = plugin.PluginSet{}
+		if opts.GRPCProviderFunc != nil {
+			plugins[6]["provider"] = &GRPCProviderPlugin{
+				GRPCProvider: opts.GRPCProviderFunc,
+			}
+		}
+	}
+	return plugins
+}
diff --git a/v1.5.7/internal/provider-simple-v6/main/main.go b/v1.5.7/internal/provider-simple-v6/main/main.go
new file mode 100644
index 0000000..a68209b
--- /dev/null
+++ b/v1.5.7/internal/provider-simple-v6/main/main.go
@@ -0,0 +1,19 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"github.com/hashicorp/terraform/internal/grpcwrap"
+	plugin "github.com/hashicorp/terraform/internal/plugin6"
+	simple "github.com/hashicorp/terraform/internal/provider-simple-v6"
+	"github.com/hashicorp/terraform/internal/tfplugin6"
+)
+
+func main() {
+	plugin.Serve(&plugin.ServeOpts{
+		GRPCProviderFunc: func() tfplugin6.ProviderServer {
+			return grpcwrap.Provider6(simple.Provider())
+		},
+	})
+}
diff --git a/v1.5.7/internal/provider-simple-v6/provider.go b/v1.5.7/internal/provider-simple-v6/provider.go
new file mode 100644
index 0000000..faf2a3f
--- /dev/null
+++ b/v1.5.7/internal/provider-simple-v6/provider.go
@@ -0,0 +1,150 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// simple provider a minimal provider implementation for testing
+package simple
+
+import (
+	"errors"
+	"fmt"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+)
+
+type simple struct {
+	schema providers.GetProviderSchemaResponse
+}
+
+func Provider() providers.Interface {
+	simpleResource := providers.Schema{
+		Block: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"id": {
+					Computed: true,
+					Type:     cty.String,
+				},
+				"value": {
+					Optional: true,
+					Type:     cty.String,
+				},
+			},
+		},
+	}
+
+	return simple{
+		schema: providers.GetProviderSchemaResponse{
+			Provider: providers.Schema{
+				Block: nil,
+			},
+			ResourceTypes: map[string]providers.Schema{
+				"simple_resource": simpleResource,
+			},
+			DataSources: map[string]providers.Schema{
+				"simple_resource": simpleResource,
+			},
+			ServerCapabilities: providers.ServerCapabilities{
+				PlanDestroy: true,
+			},
+		},
+	}
+}
+
+func (s simple) GetProviderSchema() providers.GetProviderSchemaResponse {
+	return s.schema
+}
+
+func (s simple) ValidateProviderConfig(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
+	return resp
+}
+
+func (s simple) ValidateResourceConfig(req providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
+	return resp
+}
+
+func (s simple) ValidateDataResourceConfig(req providers.ValidateDataResourceConfigRequest) (resp providers.ValidateDataResourceConfigResponse) {
+	return resp
+}
+
+func (p simple) UpgradeResourceState(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
+	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
+	val, err := ctyjson.Unmarshal(req.RawStateJSON, ty)
+	resp.Diagnostics = resp.Diagnostics.Append(err)
+	resp.UpgradedState = val
+	return resp
+}
+
+func (s simple) ConfigureProvider(providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+	return resp
+}
+
+func (s simple) Stop() error {
+	return nil
+}
+
+func (s simple) ReadResource(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+	// just return the same state we received
+	resp.NewState = req.PriorState
+	return resp
+}
+
+func (s simple) PlanResourceChange(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+	if req.ProposedNewState.IsNull() {
+		// destroy op
+		resp.PlannedState = req.ProposedNewState
+
+		// signal that this resource was properly planned for destruction,
+		// verifying that the schema capabilities with PlanDestroy took effect.
+		resp.PlannedPrivate = []byte("destroy planned")
+		return resp
+	}
+
+	m := req.ProposedNewState.AsValueMap()
+	_, ok := m["id"]
+	if !ok {
+		m["id"] = cty.UnknownVal(cty.String)
+	}
+
+	resp.PlannedState = cty.ObjectVal(m)
+	return resp
+}
+
+func (s simple) ApplyResourceChange(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+	if req.PlannedState.IsNull() {
+		// make sure this was transferred from the plan action
+		if string(req.PlannedPrivate) != "destroy planned" {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("resource not planned for destroy, private data %q", req.PlannedPrivate))
+		}
+
+		resp.NewState = req.PlannedState
+		return resp
+	}
+
+	m := req.PlannedState.AsValueMap()
+	_, ok := m["id"]
+	if !ok {
+		m["id"] = cty.StringVal(time.Now().String())
+	}
+	resp.NewState = cty.ObjectVal(m)
+
+	return resp
+}
+
+func (s simple) ImportResourceState(providers.ImportResourceStateRequest) (resp providers.ImportResourceStateResponse) {
+	resp.Diagnostics = resp.Diagnostics.Append(errors.New("unsupported"))
+	return resp
+}
+
+func (s simple) ReadDataSource(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+	m := req.Config.AsValueMap()
+	m["id"] = cty.StringVal("static_id")
+	resp.State = cty.ObjectVal(m)
+	return resp
+}
+
+func (s simple) Close() error {
+	return nil
+}
diff --git a/v1.5.7/internal/provider-simple/main/main.go b/v1.5.7/internal/provider-simple/main/main.go
new file mode 100644
index 0000000..ccbb51d
--- /dev/null
+++ b/v1.5.7/internal/provider-simple/main/main.go
@@ -0,0 +1,19 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"github.com/hashicorp/terraform/internal/grpcwrap"
+	"github.com/hashicorp/terraform/internal/plugin"
+	simple "github.com/hashicorp/terraform/internal/provider-simple"
+	"github.com/hashicorp/terraform/internal/tfplugin5"
+)
+
+func main() {
+	plugin.Serve(&plugin.ServeOpts{
+		GRPCProviderFunc: func() tfplugin5.ProviderServer {
+			return grpcwrap.Provider(simple.Provider())
+		},
+	})
+}
diff --git a/v1.5.7/internal/provider-simple/provider.go b/v1.5.7/internal/provider-simple/provider.go
new file mode 100644
index 0000000..6b54fb8
--- /dev/null
+++ b/v1.5.7/internal/provider-simple/provider.go
@@ -0,0 +1,141 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// simple provider a minimal provider implementation for testing
+package simple
+
+import (
+	"errors"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+)
+
+type simple struct {
+	schema providers.GetProviderSchemaResponse
+}
+
+func Provider() providers.Interface {
+	simpleResource := providers.Schema{
+		Block: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"id": {
+					Computed: true,
+					Type:     cty.String,
+				},
+				"value": {
+					Optional: true,
+					Type:     cty.String,
+				},
+			},
+		},
+	}
+
+	return simple{
+		schema: providers.GetProviderSchemaResponse{
+			Provider: providers.Schema{
+				Block: nil,
+			},
+			ResourceTypes: map[string]providers.Schema{
+				"simple_resource": simpleResource,
+			},
+			DataSources: map[string]providers.Schema{
+				"simple_resource": simpleResource,
+			},
+			ServerCapabilities: providers.ServerCapabilities{
+				PlanDestroy: true,
+			},
+		},
+	}
+}
+
+func (s simple) GetProviderSchema() providers.GetProviderSchemaResponse {
+	return s.schema
+}
+
+func (s simple) ValidateProviderConfig(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
+	return resp
+}
+
+func (s simple) ValidateResourceConfig(req providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
+	return resp
+}
+
+func (s simple) ValidateDataResourceConfig(req providers.ValidateDataResourceConfigRequest) (resp providers.ValidateDataResourceConfigResponse) {
+	return resp
+}
+
+func (p simple) UpgradeResourceState(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
+	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
+	val, err := ctyjson.Unmarshal(req.RawStateJSON, ty)
+	resp.Diagnostics = resp.Diagnostics.Append(err)
+	resp.UpgradedState = val
+	return resp
+}
+
+func (s simple) ConfigureProvider(providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+	return resp
+}
+
+func (s simple) Stop() error {
+	return nil
+}
+
+func (s simple) ReadResource(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+	// just return the same state we received
+	resp.NewState = req.PriorState
+	return resp
+}
+
+func (s simple) PlanResourceChange(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+	if req.ProposedNewState.IsNull() {
+		// destroy op
+		resp.PlannedState = req.ProposedNewState
+		resp.PlannedPrivate = req.PriorPrivate
+		return resp
+	}
+
+	m := req.ProposedNewState.AsValueMap()
+	_, ok := m["id"]
+	if !ok {
+		m["id"] = cty.UnknownVal(cty.String)
+	}
+
+	resp.PlannedState = cty.ObjectVal(m)
+	return resp
+}
+
+func (s simple) ApplyResourceChange(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+	if req.PlannedState.IsNull() {
+		resp.NewState = req.PlannedState
+		return resp
+	}
+
+	m := req.PlannedState.AsValueMap()
+	_, ok := m["id"]
+	if !ok {
+		m["id"] = cty.StringVal(time.Now().String())
+	}
+	resp.NewState = cty.ObjectVal(m)
+
+	return resp
+}
+
+func (s simple) ImportResourceState(providers.ImportResourceStateRequest) (resp providers.ImportResourceStateResponse) {
+	resp.Diagnostics = resp.Diagnostics.Append(errors.New("unsupported"))
+	return resp
+}
+
+func (s simple) ReadDataSource(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+	m := req.Config.AsValueMap()
+	m["id"] = cty.StringVal("static_id")
+	resp.State = cty.ObjectVal(m)
+	return resp
+}
+
+func (s simple) Close() error {
+	return nil
+}
diff --git a/v1.5.7/internal/provider-terraform/main/main.go b/v1.5.7/internal/provider-terraform/main/main.go
new file mode 100644
index 0000000..45712f2
--- /dev/null
+++ b/v1.5.7/internal/provider-terraform/main/main.go
@@ -0,0 +1,20 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"github.com/hashicorp/terraform/internal/builtin/providers/terraform"
+	"github.com/hashicorp/terraform/internal/grpcwrap"
+	"github.com/hashicorp/terraform/internal/plugin"
+	"github.com/hashicorp/terraform/internal/tfplugin5"
+)
+
+func main() {
+	// Provide a binary version of the internal terraform provider for testing
+	plugin.Serve(&plugin.ServeOpts{
+		GRPCProviderFunc: func() tfplugin5.ProviderServer {
+			return grpcwrap.Provider(terraform.NewProvider())
+		},
+	})
+}
diff --git a/v1.5.7/internal/providercache/cached_provider.go b/v1.5.7/internal/providercache/cached_provider.go
new file mode 100644
index 0000000..cd1c83f
--- /dev/null
+++ b/v1.5.7/internal/providercache/cached_provider.go
@@ -0,0 +1,154 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providercache
+
+import (
+	"fmt"
+	"io/ioutil"
+	"path/filepath"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+// CachedProvider represents a provider package in a cache directory.
+type CachedProvider struct {
+	// Provider and Version together identify the specific provider version
+	// this cache entry represents.
+	Provider addrs.Provider
+	Version  getproviders.Version
+
+	// PackageDir is the local filesystem path to the root directory where
+	// the provider's distribution archive was unpacked.
+	//
+	// The path always uses slashes as path separators, even on Windows, so
+	// that the results are consistent between platforms. Windows accepts
+	// both slashes and backslashes as long as the separators are consistent
+	// within a particular path string.
+	PackageDir string
+}
+
+// PackageLocation returns the package directory given in the PackageDir field
+// as a getproviders.PackageLocation implementation.
+//
+// Because cached providers are always in the unpacked structure, the result is
+// always of the concrete type getproviders.PackageLocalDir.
+func (cp *CachedProvider) PackageLocation() getproviders.PackageLocalDir {
+	return getproviders.PackageLocalDir(cp.PackageDir)
+}
+
+// Hash computes a hash of the contents of the package directory associated
+// with the receiving cached provider, using whichever hash algorithm is
+// the current default.
+//
+// If you need a specific version of hash rather than just whichever one is
+// current default, call that version's corresponding method (e.g. HashV1)
+// directly instead.
+func (cp *CachedProvider) Hash() (getproviders.Hash, error) {
+	return getproviders.PackageHash(cp.PackageLocation())
+}
+
+// MatchesHash returns true if the package on disk matches the given hash,
+// or false otherwise. If it cannot traverse the package directory and read
+// all of the files in it, or if the hash is in an unsupported format,
+// MatchesHash returns an error.
+//
+// MatchesHash may accept hashes in a number of different formats. Over time
+// the set of supported formats may grow and shrink.
+func (cp *CachedProvider) MatchesHash(want getproviders.Hash) (bool, error) {
+	return getproviders.PackageMatchesHash(cp.PackageLocation(), want)
+}
+
+// MatchesAnyHash returns true if the package on disk matches the given hash,
+// or false otherwise. If it cannot traverse the package directory and read
+// all of the files in it, MatchesAnyHash returns an error.
+//
+// Unlike the singular MatchesHash, MatchesAnyHash considers unsupported hash
+// formats as successfully non-matching, rather than returning an error.
+func (cp *CachedProvider) MatchesAnyHash(allowed []getproviders.Hash) (bool, error) {
+	return getproviders.PackageMatchesAnyHash(cp.PackageLocation(), allowed)
+}
+
+// HashV1 computes a hash of the contents of the package directory associated
+// with the receiving cached provider using hash algorithm 1.
+//
+// The hash covers the paths to files in the directory and the contents of
+// those files. It does not cover other metadata about the files, such as
+// permissions.
+//
+// This function is named "HashV1" in anticipation of other hashing algorithms
+// being added (in a backward-compatible way) in future. The result from
+// HashV1 always begins with the prefix "h1:" so that callers can distinguish
+// the results of potentially multiple different hash algorithms in future.
+func (cp *CachedProvider) HashV1() (getproviders.Hash, error) {
+	return getproviders.PackageHashV1(cp.PackageLocation())
+}
+
+// ExecutableFile inspects the cached provider's unpacked package directory for
+// something that looks like it's intended to be the executable file for the
+// plugin.
+//
+// This is a bit messy and heuristic-y because historically Terraform used the
+// filename itself for local filesystem discovery, allowing some variance in
+// the filenames to capture extra metadata, whereas now we're using the
+// directory structure leading to the executable instead but need to remain
+// compatible with the executable names bundled into existing provider packages.
+//
+// It will return an error if it can't find a file following the expected
+// convention in the given directory.
+//
+// If found, the path always uses slashes as path separators, even on Windows,
+// so that the results are consistent between platforms. Windows accepts both
+// slashes and backslashes as long as the separators are consistent within a
+// particular path string.
+func (cp *CachedProvider) ExecutableFile() (string, error) {
+	infos, err := ioutil.ReadDir(cp.PackageDir)
+	if err != nil {
+		// If the directory itself doesn't exist or isn't readable then we
+		// can't access an executable in it.
+		return "", fmt.Errorf("could not read package directory: %s", err)
+	}
+
+	// For a provider named e.g. tf.example.com/awesomecorp/happycloud, we
+	// expect an executable file whose name starts with
+	// "terraform-provider-happycloud", followed by zero or more additional
+	// characters. If there _are_ additional characters then the first one
+	// must be an underscore or a period, like in thse examples:
+	// - terraform-provider-happycloud_v1.0.0
+	// - terraform-provider-happycloud.exe
+	//
+	// We don't require the version in the filename to match because the
+	// executable's name is no longer authoritative, but packages of "official"
+	// providers may continue to use versioned executable names for backward
+	// compatibility with Terraform 0.12.
+	//
+	// We also presume that providers packaged for Windows will include the
+	// necessary .exe extension on their filenames but do not explicitly check
+	// for that. If there's a provider package for Windows that has a file
+	// without that suffix then it will be detected as an executable but then
+	// we'll presumably fail later trying to run it.
+	wantPrefix := "terraform-provider-" + cp.Provider.Type
+
+	// We'll visit all of the directory entries and take the first (in
+	// name-lexical order) that looks like a plausible provider executable
+	// name. A package with multiple files meeting these criteria is degenerate
+	// but we will tolerate it by ignoring the subsequent entries.
+	for _, info := range infos {
+		if info.IsDir() {
+			continue // A directory can never be an executable
+		}
+		name := info.Name()
+		if !strings.HasPrefix(name, wantPrefix) {
+			continue
+		}
+		remainder := name[len(wantPrefix):]
+		if len(remainder) > 0 && (remainder[0] != '_' && remainder[0] != '.') {
+			continue // subsequent characters must be delimited by _ or .
+		}
+		return filepath.ToSlash(filepath.Join(cp.PackageDir, name)), nil
+	}
+
+	return "", fmt.Errorf("could not find executable file starting with %s", wantPrefix)
+}
diff --git a/v1.5.7/internal/providercache/cached_provider_test.go b/v1.5.7/internal/providercache/cached_provider_test.go
new file mode 100644
index 0000000..ed77e91
--- /dev/null
+++ b/v1.5.7/internal/providercache/cached_provider_test.go
@@ -0,0 +1,116 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providercache
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+func TestCachedProviderHash(t *testing.T) {
+	cp := &CachedProvider{
+		Provider: addrs.NewProvider(
+			addrs.DefaultProviderRegistryHost,
+			"hashicorp", "null",
+		),
+		Version: getproviders.MustParseVersion("2.0.0"),
+
+		PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64",
+	}
+
+	want := getproviders.MustParseHash("h1:qjsREM4DqEWECD43FcPqddZ9oxCG+IaMTxvWPciS05g=")
+	got, err := cp.Hash()
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	if got != want {
+		t.Errorf("wrong Hash result\ngot:  %s\nwant: %s", got, want)
+	}
+
+	gotMatches, err := cp.MatchesHash(want)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if wantMatches := true; gotMatches != wantMatches {
+		t.Errorf("wrong MatchesHash result\ngot:  %#v\nwant: %#v", gotMatches, wantMatches)
+	}
+
+	// The windows build has a different hash because its executable filename
+	// has a .exe suffix, but the darwin build (hashed above) does not.
+	cp2 := &CachedProvider{
+		Provider: addrs.NewProvider(
+			addrs.DefaultProviderRegistryHost,
+			"hashicorp", "null",
+		),
+		Version: getproviders.MustParseVersion("2.0.0"),
+
+		PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
+	}
+	gotMatches, err = cp2.MatchesHash(want)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if wantMatches := false; gotMatches != wantMatches {
+		t.Errorf("wrong MatchesHash result for other package\ngot:  %#v\nwant: %#v", gotMatches, wantMatches)
+	}
+
+}
+
+func TestExecutableFile(t *testing.T) {
+	testCases := map[string]struct {
+		cp   *CachedProvider
+		file string
+		err  string
+	}{
+		"linux": {
+			cp: &CachedProvider{
+				Provider:   addrs.NewProvider(addrs.DefaultProviderRegistryHost, "hashicorp", "null"),
+				Version:    getproviders.MustParseVersion("2.0.0"),
+				PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64",
+			},
+			file: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null",
+		},
+		"windows": {
+			cp: &CachedProvider{
+				Provider:   addrs.NewProvider(addrs.DefaultProviderRegistryHost, "hashicorp", "null"),
+				Version:    getproviders.MustParseVersion("2.0.0"),
+				PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
+			},
+			file: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe",
+		},
+		"missing-executable": {
+			cp: &CachedProvider{
+				Provider:   addrs.NewProvider(addrs.DefaultProviderRegistryHost, "missing", "executable"),
+				Version:    getproviders.MustParseVersion("2.0.0"),
+				PackageDir: "testdata/cachedir/registry.terraform.io/missing/executable/2.0.0/linux_amd64",
+			},
+			err: "could not find executable file starting with terraform-provider-executable",
+		},
+		"missing-dir": {
+			cp: &CachedProvider{
+				Provider:   addrs.NewProvider(addrs.DefaultProviderRegistryHost, "missing", "packagedir"),
+				Version:    getproviders.MustParseVersion("2.0.0"),
+				PackageDir: "testdata/cachedir/registry.terraform.io/missing/packagedir/2.0.0/linux_amd64",
+			},
+			err: "could not read package directory: open testdata/cachedir/registry.terraform.io/missing/packagedir/2.0.0/linux_amd64: no such file or directory",
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			file, err := tc.cp.ExecutableFile()
+			if file != tc.file {
+				t.Errorf("wrong file\n got: %q\nwant: %q", file, tc.file)
+			}
+			if err == nil && tc.err != "" {
+				t.Fatalf("no error returned, want: %q", tc.err)
+			} else if err != nil && err.Error() != tc.err {
+				t.Errorf("wrong error\n got: %q\nwant: %q", err, tc.err)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/providercache/dir.go b/v1.5.7/internal/providercache/dir.go
new file mode 100644
index 0000000..4458997
--- /dev/null
+++ b/v1.5.7/internal/providercache/dir.go
@@ -0,0 +1,201 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providercache
+
+import (
+	"log"
+	"path/filepath"
+	"sort"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+// Dir represents a single local filesystem directory containing cached
+// provider plugin packages that can be both read from (to find providers to
+// use for operations) and written to (during provider installation).
+//
+// The contents of a cache directory follow the same naming conventions as a
+// getproviders.FilesystemMirrorSource, except that the packages are always
+// kept in the "unpacked" form (a directory containing the contents of the
+// original distribution archive) so that they are ready for direct execution.
+//
+// A Dir also pays attention only to packages for the current host platform,
+// silently ignoring any cached packages for other platforms.
+//
+// Various Dir methods return values that are technically mutable due to the
+// restrictions of the Go typesystem, but callers are not permitted to mutate
+// any part of the returned data structures.
+type Dir struct {
+	baseDir        string
+	targetPlatform getproviders.Platform
+
+	// metaCache is a cache of the metadata of relevant packages available in
+	// the cache directory last time we scanned it. This can be nil to indicate
+	// that the cache is cold. The cache will be invalidated (set back to nil)
+	// by any operation that modifies the contents of the cache directory.
+	//
+	// We intentionally don't make effort to detect modifications to the
+	// directory made by other codepaths because the contract for NewDir
+	// explicitly defines using the same directory for multiple purposes
+	// as undefined behavior.
+	metaCache map[addrs.Provider][]CachedProvider
+}
+
+// NewDir creates and returns a new Dir object that will read and write
+// provider plugins in the given filesystem directory.
+//
+// If two instances of Dir are concurrently operating on a particular base
+// directory, or if a Dir base directory is also used as a filesystem mirror
+// source directory, the behavior is undefined.
+func NewDir(baseDir string) *Dir {
+	return &Dir{
+		baseDir:        baseDir,
+		targetPlatform: getproviders.CurrentPlatform,
+	}
+}
+
+// NewDirWithPlatform is a variant of NewDir that allows selecting a specific
+// target platform, rather than taking the current one where this code is
+// running.
+//
+// This is primarily intended for portable unit testing and not particularly
+// useful in "real" callers.
+func NewDirWithPlatform(baseDir string, platform getproviders.Platform) *Dir {
+	return &Dir{
+		baseDir:        baseDir,
+		targetPlatform: platform,
+	}
+}
+
+// BasePath returns the filesystem path of the base directory of this
+// cache directory.
+func (d *Dir) BasePath() string {
+	return filepath.Clean(d.baseDir)
+}
+
+// AllAvailablePackages returns a description of all of the packages already
+// present in the directory. The cache entries are grouped by the provider
+// they relate to and then sorted by version precedence, with highest
+// precedence first.
+//
+// This function will return an empty result both when the directory is empty
+// and when scanning the directory produces an error.
+//
+// The caller is forbidden from modifying the returned data structure in any
+// way, even though the Go type system permits it.
+func (d *Dir) AllAvailablePackages() map[addrs.Provider][]CachedProvider {
+	if err := d.fillMetaCache(); err != nil {
+		log.Printf("[WARN] Failed to scan provider cache directory %s: %s", d.baseDir, err)
+		return nil
+	}
+
+	return d.metaCache
+}
+
+// ProviderVersion returns the cache entry for the requested provider version,
+// or nil if the requested provider version isn't present in the cache.
+func (d *Dir) ProviderVersion(provider addrs.Provider, version getproviders.Version) *CachedProvider {
+	if err := d.fillMetaCache(); err != nil {
+		return nil
+	}
+
+	for _, entry := range d.metaCache[provider] {
+		// We're intentionally comparing exact version here, so if either
+		// version number contains build metadata and they don't match then
+		// this will not return true. The rule of ignoring build metadata
+		// applies only for handling version _constraints_ and for deciding
+		// version precedence.
+		if entry.Version == version {
+			return &entry
+		}
+	}
+
+	return nil
+}
+
+// ProviderLatestVersion returns the cache entry for the latest
+// version of the requested provider already available in the cache, or nil if
+// there are no versions of that provider available.
+func (d *Dir) ProviderLatestVersion(provider addrs.Provider) *CachedProvider {
+	if err := d.fillMetaCache(); err != nil {
+		return nil
+	}
+
+	entries := d.metaCache[provider]
+	if len(entries) == 0 {
+		return nil
+	}
+
+	return &entries[0]
+}
+
+func (d *Dir) fillMetaCache() error {
+	// For d.metaCache we consider nil to be different than a non-nil empty
+	// map, so we can distinguish between having scanned and got an empty
+	// result vs. not having scanned successfully at all yet.
+	if d.metaCache != nil {
+		log.Printf("[TRACE] providercache.fillMetaCache: using cached result from previous scan of %s", d.baseDir)
+		return nil
+	}
+	log.Printf("[TRACE] providercache.fillMetaCache: scanning directory %s", d.baseDir)
+
+	allData, err := getproviders.SearchLocalDirectory(d.baseDir)
+	if err != nil {
+		log.Printf("[TRACE] providercache.fillMetaCache: error while scanning directory %s: %s", d.baseDir, err)
+		return err
+	}
+
+	// The getproviders package just returns everything it found, but we're
+	// interested only in a subset of the results:
+	// - those that are for the current platform
+	// - those that are in the "unpacked" form, ready to execute
+	// ...so we'll filter in these ways while we're constructing our final
+	// map to save as the cache.
+	//
+	// We intentionally always make a non-nil map, even if it might ultimately
+	// be empty, because we use that to recognize that the cache is populated.
+	data := make(map[addrs.Provider][]CachedProvider)
+
+	for providerAddr, metas := range allData {
+		for _, meta := range metas {
+			if meta.TargetPlatform != d.targetPlatform {
+				log.Printf("[TRACE] providercache.fillMetaCache: ignoring %s because it is for %s, not %s", meta.Location, meta.TargetPlatform, d.targetPlatform)
+				continue
+			}
+			if _, ok := meta.Location.(getproviders.PackageLocalDir); !ok {
+				// PackageLocalDir indicates an unpacked provider package ready
+				// to execute.
+				log.Printf("[TRACE] providercache.fillMetaCache: ignoring %s because it is not an unpacked directory", meta.Location)
+				continue
+			}
+
+			packageDir := filepath.Clean(string(meta.Location.(getproviders.PackageLocalDir)))
+
+			log.Printf("[TRACE] providercache.fillMetaCache: including %s as a candidate package for %s %s", meta.Location, providerAddr, meta.Version)
+			data[providerAddr] = append(data[providerAddr], CachedProvider{
+				Provider:   providerAddr,
+				Version:    meta.Version,
+				PackageDir: filepath.ToSlash(packageDir),
+			})
+		}
+	}
+
+	// After we've built our lists per provider, we'll also sort them by
+	// version precedence so that the newest available version is always at
+	// index zero. If there are two versions that differ only in build metadata
+	// then it's undefined but deterministic which one we will select here,
+	// because we're preserving the order returned by SearchLocalDirectory
+	// in that case..
+	for _, entries := range data {
+		sort.SliceStable(entries, func(i, j int) bool {
+			// We're using GreaterThan rather than LessThan here because we
+			// want these in _decreasing_ order of precedence.
+			return entries[i].Version.GreaterThan(entries[j].Version)
+		})
+	}
+
+	d.metaCache = data
+	return nil
+}
diff --git a/v1.5.7/internal/providercache/dir_modify.go b/v1.5.7/internal/providercache/dir_modify.go
new file mode 100644
index 0000000..ff19785
--- /dev/null
+++ b/v1.5.7/internal/providercache/dir_modify.go
@@ -0,0 +1,110 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providercache
+
+import (
+	"context"
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+// InstallPackage takes a metadata object describing a package available for
+// installation, retrieves that package, and installs it into the receiving
+// cache directory.
+//
+// If the allowedHashes set has non-zero length then at least one of the hashes
+// in the set must match the package that "entry" refers to. If none of the
+// hashes match then the returned error message assumes that the hashes came
+// from a lock file.
+func (d *Dir) InstallPackage(ctx context.Context, meta getproviders.PackageMeta, allowedHashes []getproviders.Hash) (*getproviders.PackageAuthenticationResult, error) {
+	if meta.TargetPlatform != d.targetPlatform {
+		return nil, fmt.Errorf("can't install %s package into cache directory expecting %s", meta.TargetPlatform, d.targetPlatform)
+	}
+	newPath := getproviders.UnpackedDirectoryPathForPackage(
+		d.baseDir, meta.Provider, meta.Version, d.targetPlatform,
+	)
+
+	// Invalidate our metaCache so that subsequent read calls will re-scan to
+	// incorporate any changes we make here.
+	d.metaCache = nil
+
+	log.Printf("[TRACE] providercache.Dir.InstallPackage: installing %s v%s from %s", meta.Provider, meta.Version, meta.Location)
+	switch meta.Location.(type) {
+	case getproviders.PackageHTTPURL:
+		return installFromHTTPURL(ctx, meta, newPath, allowedHashes)
+	case getproviders.PackageLocalArchive:
+		return installFromLocalArchive(ctx, meta, newPath, allowedHashes)
+	case getproviders.PackageLocalDir:
+		return installFromLocalDir(ctx, meta, newPath, allowedHashes)
+	default:
+		// Should not get here, because the above should be exhaustive for
+		// all implementations of getproviders.Location.
+		return nil, fmt.Errorf("don't know how to install from a %T location", meta.Location)
+	}
+}
+
+// LinkFromOtherCache takes a CachedProvider value produced from another Dir
+// and links it into the cache represented by the receiver Dir.
+//
+// This is used to implement tiered caching, where new providers are first
+// populated into a system-wide shared cache and then linked from there into
+// a configuration-specific local cache.
+//
+// It's invalid to link a CachedProvider from a particular Dir into that same
+// Dir, because that would otherwise potentially replace a real package
+// directory with a circular link back to itself.
+//
+// If the allowedHashes set has non-zero length then at least one of the hashes
+// in the set must match the package that "entry" refers to. If none of the
+// hashes match then the returned error message assumes that the hashes came
+// from a lock file.
+func (d *Dir) LinkFromOtherCache(entry *CachedProvider, allowedHashes []getproviders.Hash) error {
+	if len(allowedHashes) > 0 {
+		if matches, err := entry.MatchesAnyHash(allowedHashes); err != nil {
+			return fmt.Errorf(
+				"failed to calculate checksum for cached copy of %s %s in %s: %s",
+				entry.Provider, entry.Version, d.baseDir, err,
+			)
+		} else if !matches {
+			return fmt.Errorf(
+				"the provider cache at %s has a copy of %s %s that doesn't match any of the checksums recorded in the dependency lock file",
+				d.baseDir, entry.Provider, entry.Version,
+			)
+		}
+	}
+
+	newPath := getproviders.UnpackedDirectoryPathForPackage(
+		d.baseDir, entry.Provider, entry.Version, d.targetPlatform,
+	)
+	currentPath := entry.PackageDir
+	log.Printf("[TRACE] providercache.Dir.LinkFromOtherCache: linking %s v%s from existing cache %s to %s", entry.Provider, entry.Version, currentPath, newPath)
+
+	// Invalidate our metaCache so that subsequent read calls will re-scan to
+	// incorporate any changes we make here.
+	d.metaCache = nil
+
+	// We re-use the process of installing from a local directory here, because
+	// the two operations are fundamentally the same: symlink if possible,
+	// deep-copy otherwise.
+	meta := getproviders.PackageMeta{
+		Provider: entry.Provider,
+		Version:  entry.Version,
+
+		// FIXME: How do we populate this?
+		ProtocolVersions: nil,
+		TargetPlatform:   d.targetPlatform,
+
+		// Because this is already unpacked, the filename is synthetic
+		// based on the standard naming scheme.
+		Filename: fmt.Sprintf("terraform-provider-%s_%s_%s.zip",
+			entry.Provider.Type, entry.Version, d.targetPlatform),
+		Location: getproviders.PackageLocalDir(currentPath),
+	}
+	// No further hash check here because we already checked the hash
+	// of the source directory above.
+	_, err := installFromLocalDir(context.TODO(), meta, newPath, nil)
+	return err
+}
diff --git a/v1.5.7/internal/providercache/dir_modify_test.go b/v1.5.7/internal/providercache/dir_modify_test.go
new file mode 100644
index 0000000..3ce6c3b
--- /dev/null
+++ b/v1.5.7/internal/providercache/dir_modify_test.go
@@ -0,0 +1,146 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providercache
+
+import (
+	"context"
+	"path/filepath"
+	"testing"
+
+	"github.com/apparentlymart/go-versions/versions"
+	"github.com/google/go-cmp/cmp"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+func TestInstallPackage(t *testing.T) {
+	tmpDirPath, err := filepath.EvalSymlinks(t.TempDir())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	linuxPlatform := getproviders.Platform{
+		OS:   "linux",
+		Arch: "amd64",
+	}
+	nullProvider := addrs.NewProvider(
+		addrs.DefaultProviderRegistryHost, "hashicorp", "null",
+	)
+
+	tmpDir := NewDirWithPlatform(tmpDirPath, linuxPlatform)
+
+	meta := getproviders.PackageMeta{
+		Provider: nullProvider,
+		Version:  versions.MustParseVersion("2.1.0"),
+
+		ProtocolVersions: getproviders.VersionList{versions.MustParseVersion("5.0.0")},
+		TargetPlatform:   linuxPlatform,
+
+		Filename: "terraform-provider-null_2.1.0_linux_amd64.zip",
+		Location: getproviders.PackageLocalArchive("testdata/terraform-provider-null_2.1.0_linux_amd64.zip"),
+	}
+
+	result, err := tmpDir.InstallPackage(context.TODO(), meta, nil)
+	if err != nil {
+		t.Fatalf("InstallPackage failed: %s", err)
+	}
+	if result != nil {
+		t.Errorf("unexpected result %#v, wanted nil", result)
+	}
+
+	// Now we should see the same version reflected in the temporary directory.
+	got := tmpDir.AllAvailablePackages()
+	want := map[addrs.Provider][]CachedProvider{
+		nullProvider: {
+			CachedProvider{
+				Provider: nullProvider,
+
+				Version: versions.MustParseVersion("2.1.0"),
+
+				PackageDir: tmpDirPath + "/registry.terraform.io/hashicorp/null/2.1.0/linux_amd64",
+			},
+		},
+	}
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Errorf("wrong cache contents after install\n%s", diff)
+	}
+}
+
+func TestLinkFromOtherCache(t *testing.T) {
+	srcDirPath := "testdata/cachedir"
+	tmpDirPath, err := filepath.EvalSymlinks(t.TempDir())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	windowsPlatform := getproviders.Platform{
+		OS:   "windows",
+		Arch: "amd64",
+	}
+	nullProvider := addrs.NewProvider(
+		addrs.DefaultProviderRegistryHost, "hashicorp", "null",
+	)
+
+	srcDir := NewDirWithPlatform(srcDirPath, windowsPlatform)
+	tmpDir := NewDirWithPlatform(tmpDirPath, windowsPlatform)
+
+	// First we'll check our preconditions: srcDir should have only the
+	// null provider version 2.0.0 in it, because we're faking that we're on
+	// Windows, and tmpDir should have no providers in it at all.
+
+	gotSrcInitial := srcDir.AllAvailablePackages()
+	wantSrcInitial := map[addrs.Provider][]CachedProvider{
+		nullProvider: {
+			CachedProvider{
+				Provider: nullProvider,
+
+				// We want 2.0.0 rather than 2.1.0 because the 2.1.0 package is
+				// still packed and thus not considered to be a cache member.
+				Version: versions.MustParseVersion("2.0.0"),
+
+				PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
+			},
+		},
+	}
+	if diff := cmp.Diff(wantSrcInitial, gotSrcInitial); diff != "" {
+		t.Fatalf("incorrect initial source directory contents\n%s", diff)
+	}
+
+	gotTmpInitial := tmpDir.AllAvailablePackages()
+	wantTmpInitial := map[addrs.Provider][]CachedProvider{}
+	if diff := cmp.Diff(wantTmpInitial, gotTmpInitial); diff != "" {
+		t.Fatalf("incorrect initial temp directory contents\n%s", diff)
+	}
+
+	cacheEntry := srcDir.ProviderLatestVersion(nullProvider)
+	if cacheEntry == nil {
+		// This is weird because we just checked for the presence of this above
+		t.Fatalf("null provider has no latest version in source directory")
+	}
+
+	err = tmpDir.LinkFromOtherCache(cacheEntry, nil)
+	if err != nil {
+		t.Fatalf("LinkFromOtherCache failed: %s", err)
+	}
+
+	// Now we should see the same version reflected in the temporary directory.
+	got := tmpDir.AllAvailablePackages()
+	want := map[addrs.Provider][]CachedProvider{
+		nullProvider: {
+			CachedProvider{
+				Provider: nullProvider,
+
+				// We want 2.0.0 rather than 2.1.0 because the 2.1.0 package is
+				// still packed and thus not considered to be a cache member.
+				Version: versions.MustParseVersion("2.0.0"),
+
+				PackageDir: tmpDirPath + "/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
+			},
+		},
+	}
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Errorf("wrong cache contents after link\n%s", diff)
+	}
+}
diff --git a/v1.5.7/internal/providercache/dir_test.go b/v1.5.7/internal/providercache/dir_test.go
new file mode 100644
index 0000000..ad013c7
--- /dev/null
+++ b/v1.5.7/internal/providercache/dir_test.go
@@ -0,0 +1,187 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providercache
+
+import (
+	"testing"
+
+	"github.com/apparentlymart/go-versions/versions"
+	"github.com/google/go-cmp/cmp"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+func TestDirReading(t *testing.T) {
+	testDir := "testdata/cachedir"
+
+	// We'll force using particular platforms for unit testing purposes,
+	// so that we'll get consistent results on all platforms.
+	windowsPlatform := getproviders.Platform{ // only null 2.0.0 is cached
+		OS:   "windows",
+		Arch: "amd64",
+	}
+	linuxPlatform := getproviders.Platform{ // various provider versions are cached
+		OS:   "linux",
+		Arch: "amd64",
+	}
+
+	nullProvider := addrs.NewProvider(
+		addrs.DefaultProviderRegistryHost, "hashicorp", "null",
+	)
+	randomProvider := addrs.NewProvider(
+		addrs.DefaultProviderRegistryHost, "hashicorp", "random",
+	)
+	randomBetaProvider := addrs.NewProvider(
+		addrs.DefaultProviderRegistryHost, "hashicorp", "random-beta",
+	)
+	nonExistProvider := addrs.NewProvider(
+		addrs.DefaultProviderRegistryHost, "bloop", "nonexist",
+	)
+	legacyProvider := addrs.NewLegacyProvider("legacy")
+	missingExecutableProvider := addrs.NewProvider(
+		addrs.DefaultProviderRegistryHost, "missing", "executable",
+	)
+
+	t.Run("ProviderLatestVersion", func(t *testing.T) {
+		t.Run("exists", func(t *testing.T) {
+			dir := NewDirWithPlatform(testDir, windowsPlatform)
+
+			got := dir.ProviderLatestVersion(nullProvider)
+			want := &CachedProvider{
+				Provider: nullProvider,
+
+				// We want 2.0.0 rather than 2.1.0 because the 2.1.0 package is
+				// still packed and thus not considered to be a cache member.
+				Version: versions.MustParseVersion("2.0.0"),
+
+				PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
+			}
+
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+		t.Run("no package for current platform", func(t *testing.T) {
+			dir := NewDirWithPlatform(testDir, windowsPlatform)
+
+			// random provider is only cached for linux_amd64 in our fixtures dir
+			got := dir.ProviderLatestVersion(randomProvider)
+			var want *CachedProvider
+
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+		t.Run("no versions available at all", func(t *testing.T) {
+			dir := NewDirWithPlatform(testDir, windowsPlatform)
+
+			// nonexist provider is not present in our fixtures dir at all
+			got := dir.ProviderLatestVersion(nonExistProvider)
+			var want *CachedProvider
+
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+	})
+
+	t.Run("ProviderVersion", func(t *testing.T) {
+		t.Run("exists", func(t *testing.T) {
+			dir := NewDirWithPlatform(testDir, windowsPlatform)
+
+			got := dir.ProviderVersion(nullProvider, versions.MustParseVersion("2.0.0"))
+			want := &CachedProvider{
+				Provider: nullProvider,
+				Version:  versions.MustParseVersion("2.0.0"),
+
+				PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
+			}
+
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+		t.Run("specified version is not cached", func(t *testing.T) {
+			dir := NewDirWithPlatform(testDir, windowsPlatform)
+
+			// there is no v5.0.0 package in our fixtures dir
+			got := dir.ProviderVersion(nullProvider, versions.MustParseVersion("5.0.0"))
+			var want *CachedProvider
+
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+		t.Run("no package for current platform", func(t *testing.T) {
+			dir := NewDirWithPlatform(testDir, windowsPlatform)
+
+			// random provider 1.2.0 is only cached for linux_amd64 in our fixtures dir
+			got := dir.ProviderVersion(randomProvider, versions.MustParseVersion("1.2.0"))
+			var want *CachedProvider
+
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+		t.Run("no versions available at all", func(t *testing.T) {
+			dir := NewDirWithPlatform(testDir, windowsPlatform)
+
+			// nonexist provider is not present in our fixtures dir at all
+			got := dir.ProviderVersion(nonExistProvider, versions.MustParseVersion("1.0.0"))
+			var want *CachedProvider
+
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("wrong result\n%s", diff)
+			}
+		})
+	})
+
+	t.Run("AllAvailablePackages", func(t *testing.T) {
+		dir := NewDirWithPlatform(testDir, linuxPlatform)
+
+		got := dir.AllAvailablePackages()
+		want := map[addrs.Provider][]CachedProvider{
+			legacyProvider: {
+				{
+					Provider:   legacyProvider,
+					Version:    versions.MustParseVersion("1.0.0"),
+					PackageDir: "testdata/cachedir/registry.terraform.io/-/legacy/1.0.0/linux_amd64",
+				},
+			},
+			nullProvider: {
+				{
+					Provider:   nullProvider,
+					Version:    versions.MustParseVersion("2.0.0"),
+					PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64",
+				},
+			},
+			randomProvider: {
+				{
+					Provider:   randomProvider,
+					Version:    versions.MustParseVersion("1.2.0"),
+					PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64",
+				},
+			},
+			randomBetaProvider: {
+				{
+					Provider:   randomBetaProvider,
+					Version:    versions.MustParseVersion("1.2.0"),
+					PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64",
+				},
+			},
+			missingExecutableProvider: {
+				{
+					Provider:   missingExecutableProvider,
+					Version:    versions.MustParseVersion("2.0.0"),
+					PackageDir: "testdata/cachedir/registry.terraform.io/missing/executable/2.0.0/linux_amd64",
+				},
+			},
+		}
+
+		if diff := cmp.Diff(want, got); diff != "" {
+			t.Errorf("wrong result\n%s", diff)
+		}
+	})
+}
diff --git a/v1.5.7/internal/providercache/doc.go b/v1.5.7/internal/providercache/doc.go
new file mode 100644
index 0000000..4bcc345
--- /dev/null
+++ b/v1.5.7/internal/providercache/doc.go
@@ -0,0 +1,13 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package providercache contains the logic for auto-installing providers from
+// packages obtained elsewhere, and for managing the local directories that
+// serve as global or single-configuration caches of those auto-installed
+// providers.
+//
+// It builds on the lower-level provider source functionality provided by
+// the internal/getproviders package, adding the additional behaviors around
+// obtaining the discovered providers and placing them in the cache
+// directories for subsequent use.
+package providercache
diff --git a/v1.5.7/internal/providercache/installer.go b/v1.5.7/internal/providercache/installer.go
new file mode 100644
index 0000000..2845861
--- /dev/null
+++ b/v1.5.7/internal/providercache/installer.go
@@ -0,0 +1,788 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providercache
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"sort"
+	"strings"
+
+	"github.com/apparentlymart/go-versions/versions"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	copydir "github.com/hashicorp/terraform/internal/copy"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+// Installer is the main type in this package, representing a provider installer
+// with a particular configuration-specific cache directory and an optional
+// global cache directory.
+type Installer struct {
+	// targetDir is the cache directory we're ultimately aiming to get the
+	// requested providers installed into.
+	targetDir *Dir
+
+	// source is the provider source that the installer will use to discover
+	// what provider versions are available for installation and to
+	// find the source locations for any versions that are not already
+	// available via one of the cache directories.
+	source getproviders.Source
+
+	// globalCacheDir is an optional additional directory that will, if
+	// provided, be treated as a read-through cache when retrieving new
+	// provider versions. That is, new packages are fetched into this
+	// directory first and then linked into targetDir, which allows sharing
+	// both the disk space and the download time for a particular provider
+	// version between different configurations on the same system.
+	globalCacheDir *Dir
+
+	// globalCacheDirMayBreakDependencyLockFile allows a temporary exception to
+	// the rule that an entry in globalCacheDir can normally only be used if
+	// its validity is already confirmed by an entry in the dependency lock
+	// file.
+	globalCacheDirMayBreakDependencyLockFile bool
+
+	// builtInProviderTypes is an optional set of types that should be
+	// considered valid to appear in the special terraform.io/builtin/...
+	// namespace, which we use for providers that are built in to Terraform
+	// and thus do not need any separate installation step.
+	builtInProviderTypes []string
+
+	// unmanagedProviderTypes is a set of provider addresses that should be
+	// considered implemented, but that Terraform does not manage the
+	// lifecycle for, and therefore does not need to worry about the
+	// installation of.
+	unmanagedProviderTypes map[addrs.Provider]struct{}
+}
+
+// NewInstaller constructs and returns a new installer with the given target
+// directory and provider source.
+//
+// A newly-created installer does not have a global cache directory configured,
+// but a caller can make a follow-up call to SetGlobalCacheDir to provide
+// one prior to taking any installation actions.
+//
+// The target directory MUST NOT also be an input consulted by the given source,
+// or the result is undefined.
+func NewInstaller(targetDir *Dir, source getproviders.Source) *Installer {
+	return &Installer{
+		targetDir: targetDir,
+		source:    source,
+	}
+}
+
+// Clone returns a new Installer which has the a new target directory but
+// the same optional global cache directory, the same installation sources,
+// and the same built-in/unmanaged providers. The result can be mutated further
+// using the various setter methods without affecting the original.
+func (i *Installer) Clone(targetDir *Dir) *Installer {
+	// For now all of our setter methods just overwrite field values in
+	// their entirety, rather than mutating things on the other side of
+	// the shared pointers, and so we can safely just shallow-copy the
+	// root. We might need to be more careful here if in future we add
+	// methods that allow deeper mutations through the stored pointers.
+	ret := *i
+	ret.targetDir = targetDir
+	return &ret
+}
+
+// ProviderSource returns the getproviders.Source that the installer would
+// use for installing any new providers.
+func (i *Installer) ProviderSource() getproviders.Source {
+	return i.source
+}
+
+// SetGlobalCacheDir activates a second tier of caching for the receiving
+// installer, with the given directory used as a read-through cache for
+// installation operations that need to retrieve new packages.
+//
+// The global cache directory for an installer must never be the same as its
+// target directory, and must not be used as one of its provider sources.
+// If these overlap then undefined behavior will result.
+func (i *Installer) SetGlobalCacheDir(cacheDir *Dir) {
+	// A little safety check to catch straightforward mistakes where the
+	// directories overlap. Better to panic early than to do
+	// possibly-distructive actions on the cache directory downstream.
+	if same, err := copydir.SameFile(i.targetDir.baseDir, cacheDir.baseDir); err == nil && same {
+		panic(fmt.Sprintf("global cache directory %s must not match the installation target directory %s", cacheDir.baseDir, i.targetDir.baseDir))
+	}
+	i.globalCacheDir = cacheDir
+}
+
+// SetGlobalCacheDirMayBreakDependencyLockFile activates or deactivates our
+// temporary exception to the rule that the global cache directory can be used
+// only when entries are confirmed by existing entries in the dependency lock
+// file.
+//
+// If this is set then if we install a provider for the first time from the
+// cache then the dependency lock file will include only the checksum from
+// the package in the global cache, which means the lock file won't be portable
+// to Terraform running on another operating system or CPU architecture.
+func (i *Installer) SetGlobalCacheDirMayBreakDependencyLockFile(mayBreak bool) {
+	i.globalCacheDirMayBreakDependencyLockFile = mayBreak
+}
+
+// HasGlobalCacheDir returns true if someone has previously called
+// SetGlobalCacheDir to configure a global cache directory for this installer.
+func (i *Installer) HasGlobalCacheDir() bool {
+	return i.globalCacheDir != nil
+}
+
+// SetBuiltInProviderTypes tells the receiver to consider the type names in the
+// given slice to be valid as providers in the special special
+// terraform.io/builtin/... namespace that we use for providers that are
+// built in to Terraform and thus do not need a separate installation step.
+//
+// If a caller requests installation of a provider in that namespace, the
+// installer will treat it as a no-op if its name exists in this list, but
+// will produce an error if it does not.
+//
+// The default, if this method isn't called, is for there to be no valid
+// builtin providers.
+//
+// Do not modify the buffer under the given slice after passing it to this
+// method.
+func (i *Installer) SetBuiltInProviderTypes(types []string) {
+	i.builtInProviderTypes = types
+}
+
+// SetUnmanagedProviderTypes tells the receiver to consider the providers
+// indicated by the passed addrs.Providers as unmanaged. Terraform does not
+// need to control the lifecycle of these providers, and they are assumed to be
+// running already when Terraform is started. Because these are essentially
+// processes, not binaries, Terraform will not do any work to ensure presence
+// or versioning of these binaries.
+func (i *Installer) SetUnmanagedProviderTypes(types map[addrs.Provider]struct{}) {
+	i.unmanagedProviderTypes = types
+}
+
+// EnsureProviderVersions compares the given provider requirements with what
+// is already available in the installer's target directory and then takes
+// appropriate installation actions to ensure that suitable packages
+// are available in the target cache directory.
+//
+// The given mode modifies how the operation will treat providers that already
+// have acceptable versions available in the target cache directory. See the
+// documentation for InstallMode and the InstallMode values for more
+// information.
+//
+// The given context can be used to cancel the overall installation operation
+// (causing any operations in progress to fail with an error), and can also
+// include an InstallerEvents value for optional intermediate progress
+// notifications.
+//
+// If a given InstallerEvents subscribes to notifications about installation
+// failures then those notifications will be redundant with the ones included
+// in the final returned error value so callers should show either one or the
+// other, and not both.
+func (i *Installer) EnsureProviderVersions(ctx context.Context, locks *depsfile.Locks, reqs getproviders.Requirements, mode InstallMode) (*depsfile.Locks, error) {
+	errs := map[addrs.Provider]error{}
+	evts := installerEventsForContext(ctx)
+
+	// We'll work with a copy of the given locks, so we can modify it and
+	// return the updated locks without affecting the caller's object.
+	// We'll add, replace, or remove locks in here during our work so that the
+	// final locks file reflects what the installer has selected.
+	locks = locks.DeepCopy()
+
+	if cb := evts.PendingProviders; cb != nil {
+		cb(reqs)
+	}
+
+	// Step 1: Which providers might we need to fetch a new version of?
+	// This produces the subset of requirements we need to ask the provider
+	// source about. If we're in the normal (non-upgrade) mode then we'll
+	// just ask the source to confirm the continued existence of what
+	// was locked, or otherwise we'll find the newest version matching the
+	// configured version constraint.
+	mightNeed := map[addrs.Provider]getproviders.VersionSet{}
+	locked := map[addrs.Provider]bool{}
+	for provider, versionConstraints := range reqs {
+		if provider.IsBuiltIn() {
+			// Built in providers do not require installation but we'll still
+			// verify that the requested provider name is valid.
+			valid := false
+			for _, name := range i.builtInProviderTypes {
+				if name == provider.Type {
+					valid = true
+					break
+				}
+			}
+			var err error
+			if valid {
+				if len(versionConstraints) == 0 {
+					// Other than reporting an event for the outcome of this
+					// provider, we'll do nothing else with it: it's just
+					// automatically available for use.
+					if cb := evts.BuiltInProviderAvailable; cb != nil {
+						cb(provider)
+					}
+				} else {
+					// A built-in provider is not permitted to have an explicit
+					// version constraint, because we can only use the version
+					// that is built in to the current Terraform release.
+					err = fmt.Errorf("built-in providers do not support explicit version constraints")
+				}
+			} else {
+				err = fmt.Errorf("this Terraform release has no built-in provider named %q", provider.Type)
+			}
+			if err != nil {
+				errs[provider] = err
+				if cb := evts.BuiltInProviderFailure; cb != nil {
+					cb(provider, err)
+				}
+			}
+			continue
+		}
+		if _, ok := i.unmanagedProviderTypes[provider]; ok {
+			// unmanaged providers do not require installation
+			continue
+		}
+		acceptableVersions := versions.MeetingConstraints(versionConstraints)
+		if !mode.forceQueryAllProviders() {
+			// If we're not forcing potential changes of version then an
+			// existing selection from the lock file takes priority over
+			// the currently-configured version constraints.
+			if lock := locks.Provider(provider); lock != nil {
+				if !acceptableVersions.Has(lock.Version()) {
+					err := fmt.Errorf(
+						"locked provider %s %s does not match configured version constraint %s; must use terraform init -upgrade to allow selection of new versions",
+						provider, lock.Version(), getproviders.VersionConstraintsString(versionConstraints),
+					)
+					errs[provider] = err
+					// This is a funny case where we're returning an error
+					// before we do any querying at all. To keep the event
+					// stream consistent without introducing an extra event
+					// type, we'll emit an artificial QueryPackagesBegin for
+					// this provider before we indicate that it failed using
+					// QueryPackagesFailure.
+					if cb := evts.QueryPackagesBegin; cb != nil {
+						cb(provider, versionConstraints, true)
+					}
+					if cb := evts.QueryPackagesFailure; cb != nil {
+						cb(provider, err)
+					}
+					continue
+				}
+				acceptableVersions = versions.Only(lock.Version())
+				locked[provider] = true
+			}
+		}
+		mightNeed[provider] = acceptableVersions
+	}
+
+	// Step 2: Query the provider source for each of the providers we selected
+	// in the first step and select the latest available version that is
+	// in the set of acceptable versions.
+	//
+	// This produces a set of packages to install to our cache in the next step.
+	need := map[addrs.Provider]getproviders.Version{}
+NeedProvider:
+	for provider, acceptableVersions := range mightNeed {
+		if err := ctx.Err(); err != nil {
+			// If our context has been cancelled or reached a timeout then
+			// we'll abort early, because subsequent operations against
+			// that context will fail immediately anyway.
+			return nil, err
+		}
+
+		if cb := evts.QueryPackagesBegin; cb != nil {
+			cb(provider, reqs[provider], locked[provider])
+		}
+		available, warnings, err := i.source.AvailableVersions(ctx, provider)
+		if err != nil {
+			// TODO: Consider retrying a few times for certain types of
+			// source errors that seem likely to be transient.
+			errs[provider] = err
+			if cb := evts.QueryPackagesFailure; cb != nil {
+				cb(provider, err)
+			}
+			// We will take no further actions for this provider.
+			continue
+		}
+		if len(warnings) > 0 {
+			if cb := evts.QueryPackagesWarning; cb != nil {
+				cb(provider, warnings)
+			}
+		}
+		available.Sort()                           // put the versions in increasing order of precedence
+		for i := len(available) - 1; i >= 0; i-- { // walk backwards to consider newer versions first
+			if acceptableVersions.Has(available[i]) {
+				need[provider] = available[i]
+				if cb := evts.QueryPackagesSuccess; cb != nil {
+					cb(provider, available[i])
+				}
+				continue NeedProvider
+			}
+		}
+		// If we get here then the source has no packages that meet the given
+		// version constraint, which we model as a query error.
+		if locked[provider] {
+			// This situation should be a rare one: it suggests that a
+			// version was previously available but was yanked for some
+			// reason.
+			lock := locks.Provider(provider)
+			err = fmt.Errorf("the previously-selected version %s is no longer available", lock.Version())
+		} else {
+			err = fmt.Errorf("no available releases match the given constraints %s", getproviders.VersionConstraintsString(reqs[provider]))
+		}
+		errs[provider] = err
+		if cb := evts.QueryPackagesFailure; cb != nil {
+			cb(provider, err)
+		}
+	}
+
+	// Step 3: For each provider version we've decided we need to install,
+	// install its package into our target cache (possibly via the global cache).
+	authResults := map[addrs.Provider]*getproviders.PackageAuthenticationResult{} // record auth results for all successfully fetched providers
+	targetPlatform := i.targetDir.targetPlatform                                  // we inherit this to behave correctly in unit tests
+	for provider, version := range need {
+		if err := ctx.Err(); err != nil {
+			// If our context has been cancelled or reached a timeout then
+			// we'll abort early, because subsequent operations against
+			// that context will fail immediately anyway.
+			return nil, err
+		}
+
+		lock := locks.Provider(provider)
+		var preferredHashes []getproviders.Hash
+		if lock != nil && lock.Version() == version { // hash changes are expected if the version is also changing
+			preferredHashes = lock.PreferredHashes()
+		}
+
+		// If our target directory already has the provider version that fulfills the lock file, carry on
+		if installed := i.targetDir.ProviderVersion(provider, version); installed != nil {
+			if len(preferredHashes) > 0 {
+				if matches, _ := installed.MatchesAnyHash(preferredHashes); matches {
+					if cb := evts.ProviderAlreadyInstalled; cb != nil {
+						cb(provider, version)
+					}
+					continue
+				}
+			}
+		}
+
+		if i.globalCacheDir != nil {
+			// Step 3a: If our global cache already has this version available then
+			// we'll just link it in.
+			if cached := i.globalCacheDir.ProviderVersion(provider, version); cached != nil {
+				// An existing cache entry is only an acceptable choice
+				// if there is already a lock file entry for this provider
+				// and the cache entry matches its checksums.
+				//
+				// If there was no lock file entry at all then we need to
+				// install the package for real so that we can lock as complete
+				// as possible a set of checksums for all of this provider's
+				// packages.
+				//
+				// If there was a lock file entry but the cache doesn't match
+				// it then we assume that the lock file checksums were only
+				// partially populated (e.g. from a local mirror where we can
+				// only see one package to checksum it) and so we'll fetch
+				// from upstream to see if the origin can give us a package
+				// that _does_ match. This might still not work out, but if
+				// it does then it allows us to avoid returning a checksum
+				// mismatch error.
+				acceptablePackage := false
+				if len(preferredHashes) != 0 {
+					var err error
+					acceptablePackage, err = cached.MatchesAnyHash(preferredHashes)
+					if err != nil {
+						// If we can't calculate the checksum for the cached
+						// package then we'll just treat it as a checksum failure.
+						acceptablePackage = false
+					}
+				}
+
+				if !acceptablePackage && i.globalCacheDirMayBreakDependencyLockFile {
+					// The "may break dependency lock file" setting effectively
+					// means that we'll accept any matching package that's
+					// already in the cache, regardless of whether it matches
+					// what's in the dependency lock file.
+					//
+					// That means two less-ideal situations might occur:
+					// - If this provider is not currently tracked in the lock
+					//   file at all then after installation the lock file will
+					//   only accept the package that was already present in
+					//   the cache as a valid checksum. That means the generated
+					//   lock file won't be portable to other operating systems
+					//   or CPU architectures.
+					// - If the provider _is_ currently tracked in the lock file
+					//   but the checksums there don't match what was in the
+					//   cache then the LinkFromOtherCache call below will
+					//   fail with a checksum error, and the user will need to
+					//   either manually remove the entry from the lock file
+					//   or remove the mismatching item from the cache,
+					//   depending on which of these they prefer to use as the
+					//   source of truth for the expected contents of the
+					//   package.
+					//
+					// If the lock file already includes this provider and the
+					// cache entry matches one of the locked checksums then
+					// there's no problem, but in that case we wouldn't enter
+					// this branch because acceptablePackage would already be
+					// true from the check above.
+					log.Printf(
+						"[WARN] plugin_cache_may_break_dependency_lock_file: Using global cache dir package for %s v%s even though it doesn't match this configuration's dependency lock file",
+						provider.String(), version.String(),
+					)
+					acceptablePackage = true
+				}
+
+				// TODO: Should we emit an event through the events object
+				// for "there was an entry in the cache but we ignored it
+				// because the checksum didn't match"? We can't use
+				// LinkFromCacheFailure in that case because this isn't a
+				// failure. For now we'll just be quiet about it.
+
+				if acceptablePackage {
+					if cb := evts.LinkFromCacheBegin; cb != nil {
+						cb(provider, version, i.globalCacheDir.baseDir)
+					}
+					if _, err := cached.ExecutableFile(); err != nil {
+						err := fmt.Errorf("provider binary not found: %s", err)
+						errs[provider] = err
+						if cb := evts.LinkFromCacheFailure; cb != nil {
+							cb(provider, version, err)
+						}
+						continue
+					}
+
+					err := i.targetDir.LinkFromOtherCache(cached, preferredHashes)
+					if err != nil {
+						errs[provider] = err
+						if cb := evts.LinkFromCacheFailure; cb != nil {
+							cb(provider, version, err)
+						}
+						continue
+					}
+					// We'll fetch what we just linked to make sure it actually
+					// did show up there.
+					new := i.targetDir.ProviderVersion(provider, version)
+					if new == nil {
+						err := fmt.Errorf("after linking %s from provider cache at %s it is still not detected in the target directory; this is a bug in Terraform", provider, i.globalCacheDir.baseDir)
+						errs[provider] = err
+						if cb := evts.LinkFromCacheFailure; cb != nil {
+							cb(provider, version, err)
+						}
+						continue
+					}
+
+					// The LinkFromOtherCache call above should've verified that
+					// the package matches one of the hashes previously recorded,
+					// if any. We'll now augment those hashes with one freshly
+					// calculated from the package we just linked, which allows
+					// the lock file to gradually transition to recording newer hash
+					// schemes when they become available.
+					var priorHashes []getproviders.Hash
+					if lock != nil && lock.Version() == version {
+						// If the version we're installing is identical to the
+						// one we previously locked then we'll keep all of the
+						// hashes we saved previously and add to it. Otherwise
+						// we'll be starting fresh, because each version has its
+						// own set of packages and thus its own hashes.
+						priorHashes = append(priorHashes, preferredHashes...)
+
+						// NOTE: The behavior here is unfortunate when a particular
+						// provider version was already cached on the first time
+						// the current configuration requested it, because that
+						// means we don't currently get the opportunity to fetch
+						// and verify the checksums for the new package from
+						// upstream. That's currently unavoidable because upstream
+						// checksums are in the "ziphash" format and so we can't
+						// verify them against our cache directory's unpacked
+						// packages: we'd need to go fetch the package from the
+						// origin and compare against it, which would defeat the
+						// purpose of the global cache.
+						//
+						// If we fetch from upstream on the first encounter with
+						// a particular provider then we'll end up in the other
+						// codepath below where we're able to also include the
+						// checksums from the origin registry.
+					}
+					newHash, err := cached.Hash()
+					if err != nil {
+						err := fmt.Errorf("after linking %s from provider cache at %s, failed to compute a checksum for it: %s", provider, i.globalCacheDir.baseDir, err)
+						errs[provider] = err
+						if cb := evts.LinkFromCacheFailure; cb != nil {
+							cb(provider, version, err)
+						}
+						continue
+					}
+					// The hashes slice gets deduplicated in the lock file
+					// implementation, so we don't worry about potentially
+					// creating a duplicate here.
+					var newHashes []getproviders.Hash
+					newHashes = append(newHashes, priorHashes...)
+					newHashes = append(newHashes, newHash)
+					locks.SetProvider(provider, version, reqs[provider], newHashes)
+					if cb := evts.ProvidersLockUpdated; cb != nil {
+						// We want to ensure that newHash and priorHashes are
+						// sorted. newHash is a single value, so it's definitely
+						// sorted. priorHashes are pulled from the lock file, so
+						// are also already sorted.
+						cb(provider, version, []getproviders.Hash{newHash}, nil, priorHashes)
+					}
+
+					if cb := evts.LinkFromCacheSuccess; cb != nil {
+						cb(provider, version, new.PackageDir)
+					}
+					continue // Don't need to do full install, then.
+				}
+			}
+		}
+
+		// Step 3b: Get the package metadata for the selected version from our
+		// provider source.
+		//
+		// This is the step where we might detect and report that the provider
+		// isn't available for the current platform.
+		if cb := evts.FetchPackageMeta; cb != nil {
+			cb(provider, version)
+		}
+		meta, err := i.source.PackageMeta(ctx, provider, version, targetPlatform)
+		if err != nil {
+			errs[provider] = err
+			if cb := evts.FetchPackageFailure; cb != nil {
+				cb(provider, version, err)
+			}
+			continue
+		}
+
+		// Step 3c: Retrieve the package indicated by the metadata we received,
+		// either directly into our target directory or via the global cache
+		// directory.
+		if cb := evts.FetchPackageBegin; cb != nil {
+			cb(provider, version, meta.Location)
+		}
+		var installTo, linkTo *Dir
+		if i.globalCacheDir != nil {
+			installTo = i.globalCacheDir
+			linkTo = i.targetDir
+		} else {
+			installTo = i.targetDir
+			linkTo = nil // no linking needed
+		}
+
+		allowedHashes := preferredHashes
+		if mode.forceInstallChecksums() {
+			allowedHashes = []getproviders.Hash{}
+		}
+
+		authResult, err := installTo.InstallPackage(ctx, meta, allowedHashes)
+		if err != nil {
+			// TODO: Consider retrying for certain kinds of error that seem
+			// likely to be transient. For now, we just treat all errors equally.
+			errs[provider] = err
+			if cb := evts.FetchPackageFailure; cb != nil {
+				cb(provider, version, err)
+			}
+			continue
+		}
+		new := installTo.ProviderVersion(provider, version)
+		if new == nil {
+			err := fmt.Errorf("after installing %s it is still not detected in %s; this is a bug in Terraform", provider, installTo.BasePath())
+			errs[provider] = err
+			if cb := evts.FetchPackageFailure; cb != nil {
+				cb(provider, version, err)
+			}
+			continue
+		}
+		if _, err := new.ExecutableFile(); err != nil {
+			err := fmt.Errorf("provider binary not found: %s", err)
+			errs[provider] = err
+			if cb := evts.FetchPackageFailure; cb != nil {
+				cb(provider, version, err)
+			}
+			continue
+		}
+		if linkTo != nil {
+			// We skip emitting the "LinkFromCache..." events here because
+			// it's simpler for the caller to treat them as mutually exclusive.
+			// We can just subsume the linking step under the "FetchPackage..."
+			// series here (and that's why we use FetchPackageFailure below).
+			// We also don't do a hash check here because we already did that
+			// as part of the installTo.InstallPackage call above.
+			err := linkTo.LinkFromOtherCache(new, nil)
+			if err != nil {
+				errs[provider] = err
+				if cb := evts.FetchPackageFailure; cb != nil {
+					cb(provider, version, err)
+				}
+				continue
+			}
+
+			// We should now also find the package in the linkTo dir, which
+			// gives us the final value of "new" where the path points in to
+			// the true target directory, rather than possibly the global
+			// cache directory.
+			new = linkTo.ProviderVersion(provider, version)
+			if new == nil {
+				err := fmt.Errorf("after installing %s it is still not detected in %s; this is a bug in Terraform", provider, linkTo.BasePath())
+				errs[provider] = err
+				if cb := evts.FetchPackageFailure; cb != nil {
+					cb(provider, version, err)
+				}
+				continue
+			}
+			if _, err := new.ExecutableFile(); err != nil {
+				err := fmt.Errorf("provider binary not found: %s", err)
+				errs[provider] = err
+				if cb := evts.FetchPackageFailure; cb != nil {
+					cb(provider, version, err)
+				}
+				continue
+			}
+		}
+		authResults[provider] = authResult
+
+		// The InstallPackage call above should've verified that
+		// the package matches one of the hashes previously recorded,
+		// if any. We'll now augment those hashes with a new set populated
+		// with the hashes returned by the upstream source and from the
+		// package we've just installed, which allows the lock file to
+		// gradually transition to newer hash schemes when they become
+		// available.
+		//
+		// This is assuming that if a package matches both a hash we saw before
+		// _and_ a new hash then the new hash is a valid substitute for
+		// the previous hash.
+		//
+		// The hashes slice gets deduplicated in the lock file
+		// implementation, so we don't worry about potentially
+		// creating duplicates here.
+		var priorHashes []getproviders.Hash
+		if lock != nil && lock.Version() == version {
+			// If the version we're installing is identical to the
+			// one we previously locked then we'll keep all of the
+			// hashes we saved previously and add to it. Otherwise
+			// we'll be starting fresh, because each version has its
+			// own set of packages and thus its own hashes.
+			priorHashes = append(priorHashes, preferredHashes...)
+		}
+		newHash, err := new.Hash()
+		if err != nil {
+			err := fmt.Errorf("after installing %s, failed to compute a checksum for it: %s", provider, err)
+			errs[provider] = err
+			if cb := evts.FetchPackageFailure; cb != nil {
+				cb(provider, version, err)
+			}
+			continue
+		}
+
+		var signedHashes []getproviders.Hash
+		if authResult.SignedByAnyParty() {
+			// We'll trust new hashes from upstream only if they were verified
+			// as signed by a suitable key. Otherwise, we'd record only
+			// a new hash we just calculated ourselves from the bytes on disk,
+			// and so the hashes would cover only the current platform.
+			signedHashes = append(signedHashes, meta.AcceptableHashes()...)
+		}
+
+		var newHashes []getproviders.Hash
+		newHashes = append(newHashes, newHash)
+		newHashes = append(newHashes, priorHashes...)
+		newHashes = append(newHashes, signedHashes...)
+
+		locks.SetProvider(provider, version, reqs[provider], newHashes)
+		if cb := evts.ProvidersLockUpdated; cb != nil {
+			// newHash and priorHashes are already sorted.
+			// But we do need to sort signedHashes so we can reason about it
+			// sensibly.
+			sort.Slice(signedHashes, func(i, j int) bool {
+				return string(signedHashes[i]) < string(signedHashes[j])
+			})
+
+			cb(provider, version, []getproviders.Hash{newHash}, signedHashes, priorHashes)
+		}
+
+		if cb := evts.FetchPackageSuccess; cb != nil {
+			cb(provider, version, new.PackageDir, authResult)
+		}
+	}
+
+	// Emit final event for fetching if any were successfully fetched
+	if cb := evts.ProvidersFetched; cb != nil && len(authResults) > 0 {
+		cb(authResults)
+	}
+
+	// Finally, if the lock structure contains locks for any providers that
+	// are no longer needed by this configuration, we'll remove them. This
+	// is important because we will not have installed those providers
+	// above and so a lock file still containing them would make the working
+	// directory invalid: not every provider in the lock file is available
+	// for use.
+	for providerAddr := range locks.AllProviders() {
+		if _, ok := reqs[providerAddr]; !ok {
+			locks.RemoveProvider(providerAddr)
+		}
+	}
+
+	if len(errs) > 0 {
+		return locks, InstallerError{
+			ProviderErrors: errs,
+		}
+	}
+	return locks, nil
+}
+
+// InstallMode customizes the details of how an install operation treats
+// providers that have versions already cached in the target directory.
+type InstallMode rune
+
+const (
+	// InstallNewProvidersOnly is an InstallMode that causes the installer
+	// to accept any existing version of a requested provider that is already
+	// cached as long as it's in the given version sets, without checking
+	// whether new versions are available that are also in the given version
+	// sets.
+	InstallNewProvidersOnly InstallMode = 'N'
+
+	// InstallNewProvidersForce is an InstallMode that follows the same
+	// logic as InstallNewProvidersOnly except it does not verify existing
+	// checksums but force installs new checksums for all given providers.
+	InstallNewProvidersForce InstallMode = 'F'
+
+	// InstallUpgrades is an InstallMode that causes the installer to check
+	// all requested providers to see if new versions are available that
+	// are also in the given version sets, even if a suitable version of
+	// a given provider is already available.
+	InstallUpgrades InstallMode = 'U'
+)
+
+func (m InstallMode) forceQueryAllProviders() bool {
+	return m == InstallUpgrades
+}
+
+func (m InstallMode) forceInstallChecksums() bool {
+	return m == InstallNewProvidersForce
+}
+
+// InstallerError is an error type that may be returned (but is not guaranteed)
+// from Installer.EnsureProviderVersions to indicate potentially several
+// separate failed installation outcomes for different providers included in
+// the overall request.
+type InstallerError struct {
+	ProviderErrors map[addrs.Provider]error
+}
+
+func (err InstallerError) Error() string {
+	addrs := make([]addrs.Provider, 0, len(err.ProviderErrors))
+	for addr := range err.ProviderErrors {
+		addrs = append(addrs, addr)
+	}
+	sort.Slice(addrs, func(i, j int) bool {
+		return addrs[i].LessThan(addrs[j])
+	})
+	var b strings.Builder
+	b.WriteString("some providers could not be installed:\n")
+	for _, addr := range addrs {
+		providerErr := err.ProviderErrors[addr]
+		fmt.Fprintf(&b, "- %s: %s\n", addr, providerErr)
+	}
+	return strings.TrimSpace(b.String())
+}
diff --git a/v1.5.7/internal/providercache/installer_events.go b/v1.5.7/internal/providercache/installer_events.go
new file mode 100644
index 0000000..b477376
--- /dev/null
+++ b/v1.5.7/internal/providercache/installer_events.go
@@ -0,0 +1,163 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providercache
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+// InstallerEvents is a collection of function references that can be
+// associated with an Installer object in order to be notified about various
+// installation lifecycle events during an install operation.
+//
+// The set of supported events is primarily motivated by allowing ongoing
+// progress reports in the UI of the command running provider installation,
+// and so this only exposes information interesting to display and does not
+// allow the recipient of the events to influence the ongoing process.
+//
+// Any of the fields may be left as nil to signal that the caller is not
+// interested in the associated event. It's better to leave a field set to
+// nil than to assign a do-nothing function into it because the installer
+// may choose to skip preparing certain temporary data structures if it can see
+// that a particular event is not used.
+type InstallerEvents struct {
+	// The PendingProviders event is called prior to other events to give
+	// the recipient prior notice of the full set of distinct provider
+	// addresses it can expect to see mentioned in the other events.
+	//
+	// A recipient driving a UI might, for example, use this to pre-allocate
+	// UI space for status reports for all of the providers and then update
+	// those positions in-place as other events arrive.
+	PendingProviders func(reqs map[addrs.Provider]getproviders.VersionConstraints)
+
+	// ProviderAlreadyInstalled is called for any provider that was included
+	// in PendingProviders but requires no further action because a suitable
+	// version is already present in the local provider cache directory.
+	//
+	// This event can also appear after the QueryPackages... series if
+	// querying determines that a version already available is the newest
+	// available version.
+	ProviderAlreadyInstalled func(provider addrs.Provider, selectedVersion getproviders.Version)
+
+	// The BuiltInProvider... family of events describe the outcome for any
+	// requested providers that are built in to Terraform. Only one of these
+	// methods will be called for each such provider, and no other method
+	// will be called for them except that they are included in the
+	// aggregate PendingProviders map.
+	//
+	// The "Available" event reports that the requested builtin provider is
+	// available in this release of Terraform. The "Failure" event reports
+	// either that the provider is unavailable or that the request for it
+	// is invalid somehow.
+	BuiltInProviderAvailable func(provider addrs.Provider)
+	BuiltInProviderFailure   func(provider addrs.Provider, err error)
+
+	// The QueryPackages... family of events delimit the operation of querying
+	// a provider source for information about available packages matching
+	// a particular version constraint, prior to selecting a single version
+	// to install.
+	//
+	// A particular install operation includes only one query per distinct
+	// provider, so a caller can use the provider argument as a unique
+	// identifier to correlate between successive events.
+	//
+	// The Begin, Success, and Failure events will each occur only once per
+	// distinct provider.
+	//
+	// The Warning event is unique to the registry source
+	QueryPackagesBegin   func(provider addrs.Provider, versionConstraints getproviders.VersionConstraints, locked bool)
+	QueryPackagesSuccess func(provider addrs.Provider, selectedVersion getproviders.Version)
+	QueryPackagesFailure func(provider addrs.Provider, err error)
+	QueryPackagesWarning func(provider addrs.Provider, warn []string)
+
+	// The LinkFromCache... family of events delimit the operation of linking
+	// a selected provider package from the system-wide shared cache into the
+	// current configuration's local cache.
+	//
+	// This sequence occurs instead of the FetchPackage... sequence if the
+	// QueryPackages... sequence selects a version that is already in the
+	// system-wide cache, and thus we will skip fetching it from the
+	// originating provider source and take it from the shared cache instead.
+	//
+	// Linking should, in most cases, be a much faster operation than
+	// fetching. However, it could still potentially be slow in some unusual
+	// cases like a particularly large source package on a system where symlinks
+	// are impossible, or when either of the cache directories are on a network
+	// filesystem accessed over a slow link.
+	LinkFromCacheBegin   func(provider addrs.Provider, version getproviders.Version, cacheRoot string)
+	LinkFromCacheSuccess func(provider addrs.Provider, version getproviders.Version, localDir string)
+	LinkFromCacheFailure func(provider addrs.Provider, version getproviders.Version, err error)
+
+	// The FetchPackage... family of events delimit the operation of retrieving
+	// a package from a particular source location.
+	//
+	// A particular install operation includes only one fetch per distinct
+	// provider, so a caller can use the provider argument as a unique
+	// identifier to correlate between successive events.
+	//
+	// A particular provider will either notify the LinkFromCache... events
+	// or the FetchPackage... events, never both in the same install operation.
+	//
+	// The Query, Begin, Success, and Failure events will each occur only once
+	// per distinct provider.
+	FetchPackageMeta    func(provider addrs.Provider, version getproviders.Version) // fetching metadata prior to real download
+	FetchPackageBegin   func(provider addrs.Provider, version getproviders.Version, location getproviders.PackageLocation)
+	FetchPackageSuccess func(provider addrs.Provider, version getproviders.Version, localDir string, authResult *getproviders.PackageAuthenticationResult)
+	FetchPackageFailure func(provider addrs.Provider, version getproviders.Version, err error)
+
+	// The ProvidersLockUpdated event is called whenever the lock file will be
+	// updated. It provides the following information:
+	//
+	//   - `localHashes`: Hashes computed on the local system by analyzing
+	//                    files on disk.
+	//   - `signedHashes`: Hashes signed by the private key that the origin
+	//                     registry claims is the owner of this provider.
+	//   - `priorHashes`: Hashes already present in the lock file before we
+	//                    made any changes.
+	//
+	// The final lock file will be updated with a union of all the provided
+	// hashes. It not just likely, but expected that there will be duplicates
+	// shared between all three collections of hashes i.e. the local hash and
+	// remote hashes could already be in the cached hashes.
+	//
+	// In addition, we place a guarantee that the hash slices will be ordered
+	// in the same manner enforced by the lock file within NewProviderLock.
+	ProvidersLockUpdated func(provider addrs.Provider, version getproviders.Version, localHashes []getproviders.Hash, signedHashes []getproviders.Hash, priorHashes []getproviders.Hash)
+
+	// The ProvidersFetched event is called after all fetch operations if at
+	// least one provider was fetched successfully.
+	ProvidersFetched func(authResults map[addrs.Provider]*getproviders.PackageAuthenticationResult)
+}
+
+// OnContext produces a context with all of the same behaviors as the given
+// context except that it will additionally carry the receiving
+// InstallerEvents.
+//
+// Passing the resulting context to an installer request will cause the
+// installer to send event notifications via the callbacks inside.
+func (e *InstallerEvents) OnContext(ctx context.Context) context.Context {
+	return context.WithValue(ctx, ctxInstallerEvents, e)
+}
+
+// installerEventsForContext looks on the given context for a registered
+// InstallerEvents and returns a pointer to it if so.
+//
+// For caller convenience, if there is no events object attached to the
+// given context this function will construct one that has all of its
+// fields set to nil and return that, freeing the caller from having to
+// do a nil check on the result before dereferencing it.
+func installerEventsForContext(ctx context.Context) *InstallerEvents {
+	v := ctx.Value(ctxInstallerEvents)
+	if v != nil {
+		return v.(*InstallerEvents)
+	}
+	return &InstallerEvents{}
+}
+
+type ctxInstallerEventsType int
+
+const ctxInstallerEvents = ctxInstallerEventsType(0)
diff --git a/v1.5.7/internal/providercache/installer_events_test.go b/v1.5.7/internal/providercache/installer_events_test.go
new file mode 100644
index 0000000..002d468
--- /dev/null
+++ b/v1.5.7/internal/providercache/installer_events_test.go
@@ -0,0 +1,189 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providercache
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+type testInstallerEventLogItem struct {
+	// The name of the event that occurred, using the same names as the
+	// fields of InstallerEvents.
+	Event string
+
+	// Most events relate to a specific provider. For the few event types
+	// that don't, this will be a zero-value Provider.
+	Provider addrs.Provider
+
+	// The type of Args will vary by event, but it should always be something
+	// that can be deterministically compared using the go-cmp package.
+	Args interface{}
+}
+
+// installerLogEventsForTests is a test helper that produces an InstallerEvents
+// that writes event notifications (*testInstallerEventLogItem values) to
+// the given channel as they occur.
+//
+// The caller must keep reading from the read side of the given channel
+// throughout any installer operation using the returned InstallerEvents.
+// It's the caller's responsibility to close the channel if needed and
+// clean up any goroutines it started to process the events.
+//
+// The exact sequence of events emitted for an installer operation might
+// change in future, if e.g. we introduce new event callbacks to the
+// InstallerEvents struct. Tests using this mechanism may therefore need to
+// be updated to reflect such changes.
+//
+// (The channel-based approach here is so that the control flow for event
+// processing will belong to the caller and thus it can safely use its
+// testing.T object(s) to emit log lines without non-test-case frames in the
+// call stack.)
+func installerLogEventsForTests(into chan<- *testInstallerEventLogItem) *InstallerEvents {
+	return &InstallerEvents{
+		PendingProviders: func(reqs map[addrs.Provider]getproviders.VersionConstraints) {
+			into <- &testInstallerEventLogItem{
+				Event: "PendingProviders",
+				Args:  reqs,
+			}
+		},
+		ProviderAlreadyInstalled: func(provider addrs.Provider, selectedVersion getproviders.Version) {
+			into <- &testInstallerEventLogItem{
+				Event:    "ProviderAlreadyInstalled",
+				Provider: provider,
+				Args:     selectedVersion,
+			}
+		},
+		BuiltInProviderAvailable: func(provider addrs.Provider) {
+			into <- &testInstallerEventLogItem{
+				Event:    "BuiltInProviderAvailable",
+				Provider: provider,
+			}
+		},
+		BuiltInProviderFailure: func(provider addrs.Provider, err error) {
+			into <- &testInstallerEventLogItem{
+				Event:    "BuiltInProviderFailure",
+				Provider: provider,
+				Args:     err.Error(), // stringified to guarantee cmp-ability
+			}
+		},
+		QueryPackagesBegin: func(provider addrs.Provider, versionConstraints getproviders.VersionConstraints, locked bool) {
+			into <- &testInstallerEventLogItem{
+				Event:    "QueryPackagesBegin",
+				Provider: provider,
+				Args: struct {
+					Constraints string
+					Locked      bool
+				}{getproviders.VersionConstraintsString(versionConstraints), locked},
+			}
+		},
+		QueryPackagesSuccess: func(provider addrs.Provider, selectedVersion getproviders.Version) {
+			into <- &testInstallerEventLogItem{
+				Event:    "QueryPackagesSuccess",
+				Provider: provider,
+				Args:     selectedVersion.String(),
+			}
+		},
+		QueryPackagesFailure: func(provider addrs.Provider, err error) {
+			into <- &testInstallerEventLogItem{
+				Event:    "QueryPackagesFailure",
+				Provider: provider,
+				Args:     err.Error(), // stringified to guarantee cmp-ability
+			}
+		},
+		QueryPackagesWarning: func(provider addrs.Provider, warns []string) {
+			into <- &testInstallerEventLogItem{
+				Event:    "QueryPackagesWarning",
+				Provider: provider,
+				Args:     warns,
+			}
+		},
+		LinkFromCacheBegin: func(provider addrs.Provider, version getproviders.Version, cacheRoot string) {
+			into <- &testInstallerEventLogItem{
+				Event:    "LinkFromCacheBegin",
+				Provider: provider,
+				Args: struct {
+					Version   string
+					CacheRoot string
+				}{version.String(), cacheRoot},
+			}
+		},
+		LinkFromCacheSuccess: func(provider addrs.Provider, version getproviders.Version, localDir string) {
+			into <- &testInstallerEventLogItem{
+				Event:    "LinkFromCacheSuccess",
+				Provider: provider,
+				Args: struct {
+					Version  string
+					LocalDir string
+				}{version.String(), localDir},
+			}
+		},
+		LinkFromCacheFailure: func(provider addrs.Provider, version getproviders.Version, err error) {
+			into <- &testInstallerEventLogItem{
+				Event:    "LinkFromCacheFailure",
+				Provider: provider,
+				Args: struct {
+					Version string
+					Error   string
+				}{version.String(), err.Error()},
+			}
+		},
+		FetchPackageMeta: func(provider addrs.Provider, version getproviders.Version) {
+			into <- &testInstallerEventLogItem{
+				Event:    "FetchPackageMeta",
+				Provider: provider,
+				Args:     version.String(),
+			}
+		},
+		FetchPackageBegin: func(provider addrs.Provider, version getproviders.Version, location getproviders.PackageLocation) {
+			into <- &testInstallerEventLogItem{
+				Event:    "FetchPackageBegin",
+				Provider: provider,
+				Args: struct {
+					Version  string
+					Location getproviders.PackageLocation
+				}{version.String(), location},
+			}
+		},
+		FetchPackageSuccess: func(provider addrs.Provider, version getproviders.Version, localDir string, authResult *getproviders.PackageAuthenticationResult) {
+			into <- &testInstallerEventLogItem{
+				Event:    "FetchPackageSuccess",
+				Provider: provider,
+				Args: struct {
+					Version    string
+					LocalDir   string
+					AuthResult string
+				}{version.String(), localDir, authResult.String()},
+			}
+		},
+		FetchPackageFailure: func(provider addrs.Provider, version getproviders.Version, err error) {
+			into <- &testInstallerEventLogItem{
+				Event:    "FetchPackageFailure",
+				Provider: provider,
+				Args: struct {
+					Version string
+					Error   string
+				}{version.String(), err.Error()},
+			}
+		},
+		ProvidersLockUpdated: func(provider addrs.Provider, version getproviders.Version, localHashes []getproviders.Hash, signedHashes []getproviders.Hash, priorHashes []getproviders.Hash) {
+			into <- &testInstallerEventLogItem{
+				Event:    "ProvidersLockUpdated",
+				Provider: provider,
+				Args: struct {
+					Version string
+					Local   []getproviders.Hash
+					Signed  []getproviders.Hash
+					Prior   []getproviders.Hash
+				}{version.String(), localHashes, signedHashes, priorHashes},
+			}
+		},
+		ProvidersFetched: func(authResults map[addrs.Provider]*getproviders.PackageAuthenticationResult) {
+			into <- &testInstallerEventLogItem{
+				Event: "ProvidersFetched",
+				Args:  authResults,
+			}
+		},
+	}
+}
diff --git a/v1.5.7/internal/providercache/installer_test.go b/v1.5.7/internal/providercache/installer_test.go
new file mode 100644
index 0000000..6115593
--- /dev/null
+++ b/v1.5.7/internal/providercache/installer_test.go
@@ -0,0 +1,2694 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providercache
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"log"
+	"net/http"
+	"net/http/httptest"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/apparentlymart/go-versions/versions"
+	"github.com/apparentlymart/go-versions/versions/constraints"
+	"github.com/davecgh/go-spew/spew"
+	"github.com/google/go-cmp/cmp"
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform-svchost/disco"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/depsfile"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+func TestEnsureProviderVersions(t *testing.T) {
+	// This is a sort of hybrid between table-driven and imperative-style
+	// testing, because the overall sequence of steps is the same for all
+	// of the test cases but the setup and verification have enough different
+	// permutations that it ends up being more concise to express them as
+	// normal code.
+	type Test struct {
+		Source     getproviders.Source
+		Prepare    func(*testing.T, *Installer, *Dir)
+		LockFile   string
+		Reqs       getproviders.Requirements
+		Mode       InstallMode
+		Check      func(*testing.T, *Dir, *depsfile.Locks)
+		WantErr    string
+		WantEvents func(*Installer, *Dir) map[addrs.Provider][]*testInstallerEventLogItem
+	}
+
+	// noProvider is just the zero value of addrs.Provider, which we're
+	// using in this test as the key for installer events that are not
+	// specific to a particular provider.
+	var noProvider addrs.Provider
+	beepProvider := addrs.MustParseProviderSourceString("example.com/foo/beep")
+	beepProviderDir := getproviders.PackageLocalDir("testdata/beep-provider")
+	fakePlatform := getproviders.Platform{OS: "bleep", Arch: "bloop"}
+	wrongPlatform := getproviders.Platform{OS: "wrong", Arch: "wrong"}
+	beepProviderHash := getproviders.HashScheme1.New("2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84=")
+	terraformProvider := addrs.MustParseProviderSourceString("terraform.io/builtin/terraform")
+
+	tests := map[string]Test{
+		"no dependencies": {
+			Mode: InstallNewProvidersOnly,
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 0 {
+					t.Errorf("unexpected cache directory entries\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 0 {
+					t.Errorf("unexpected provider lock entries\n%s", spew.Sdump(allLocked))
+				}
+			},
+			WantEvents: func(*Installer, *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args:  map[addrs.Provider]getproviders.VersionConstraints(nil),
+						},
+					},
+				}
+			},
+		},
+		"successful initial install of one provider": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("1.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.1.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+			},
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 1 {
+					t.Errorf("wrong number of cache directory entries; want only one\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 1 {
+					t.Errorf("wrong number of provider lock entries; want only one\n%s", spew.Sdump(allLocked))
+				}
+
+				gotLock := locks.Provider(beepProvider)
+				wantLock := depsfile.NewProviderLock(
+					beepProvider,
+					getproviders.MustParseVersion("2.1.0"),
+					getproviders.MustParseVersionConstraints(">= 2.0.0"),
+					[]getproviders.Hash{beepProviderHash},
+				)
+				if diff := cmp.Diff(wantLock, gotLock, depsfile.ProviderLockComparer); diff != "" {
+					t.Errorf("wrong lock entry\n%s", diff)
+				}
+
+				gotEntry := dir.ProviderLatestVersion(beepProvider)
+				wantEntry := &CachedProvider{
+					Provider:   beepProvider,
+					Version:    getproviders.MustParseVersion("2.1.0"),
+					PackageDir: filepath.Join(dir.BasePath(), "example.com/foo/beep/2.1.0/bleep_bloop"),
+				}
+				if diff := cmp.Diff(wantEntry, gotEntry); diff != "" {
+					t.Errorf("wrong cache entry\n%s", diff)
+				}
+			},
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+							},
+						},
+						{
+							Event: "ProvidersFetched",
+							Args: map[addrs.Provider]*getproviders.PackageAuthenticationResult{
+								beepProvider: nil,
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 2.0.0", false},
+						},
+						{
+							Event:    "QueryPackagesSuccess",
+							Provider: beepProvider,
+							Args:     "2.1.0",
+						},
+						{
+							Event:    "FetchPackageMeta",
+							Provider: beepProvider,
+							Args:     "2.1.0",
+						},
+						{
+							Event:    "FetchPackageBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Version  string
+								Location getproviders.PackageLocation
+							}{"2.1.0", beepProviderDir},
+						},
+						{
+							Event:    "ProvidersLockUpdated",
+							Provider: beepProvider,
+							Args: struct {
+								Version string
+								Local   []getproviders.Hash
+								Signed  []getproviders.Hash
+								Prior   []getproviders.Hash
+							}{
+								"2.1.0",
+								[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+								nil,
+								nil,
+							},
+						},
+						{
+							Event:    "FetchPackageSuccess",
+							Provider: beepProvider,
+							Args: struct {
+								Version    string
+								LocalDir   string
+								AuthResult string
+							}{
+								"2.1.0",
+								filepath.Join(dir.BasePath(), "example.com/foo/beep/2.1.0/bleep_bloop"),
+								"unauthenticated",
+							},
+						},
+					},
+				}
+			},
+		},
+		"successful initial install of one provider through a cold global cache": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.1.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			Prepare: func(t *testing.T, inst *Installer, dir *Dir) {
+				globalCacheDirPath := tmpDir(t)
+				globalCacheDir := NewDirWithPlatform(globalCacheDirPath, fakePlatform)
+				inst.SetGlobalCacheDir(globalCacheDir)
+			},
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+			},
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 1 {
+					t.Errorf("wrong number of cache directory entries; want only one\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 1 {
+					t.Errorf("wrong number of provider lock entries; want only one\n%s", spew.Sdump(allLocked))
+				}
+
+				gotLock := locks.Provider(beepProvider)
+				wantLock := depsfile.NewProviderLock(
+					beepProvider,
+					getproviders.MustParseVersion("2.1.0"),
+					getproviders.MustParseVersionConstraints(">= 2.0.0"),
+					[]getproviders.Hash{beepProviderHash},
+				)
+				if diff := cmp.Diff(wantLock, gotLock, depsfile.ProviderLockComparer); diff != "" {
+					t.Errorf("wrong lock entry\n%s", diff)
+				}
+
+				gotEntry := dir.ProviderLatestVersion(beepProvider)
+				wantEntry := &CachedProvider{
+					Provider:   beepProvider,
+					Version:    getproviders.MustParseVersion("2.1.0"),
+					PackageDir: filepath.Join(dir.BasePath(), "example.com/foo/beep/2.1.0/bleep_bloop"),
+				}
+				if diff := cmp.Diff(wantEntry, gotEntry); diff != "" {
+					t.Errorf("wrong cache entry\n%s", diff)
+				}
+			},
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+							},
+						},
+						{
+							Event: "ProvidersFetched",
+							Args: map[addrs.Provider]*getproviders.PackageAuthenticationResult{
+								beepProvider: nil,
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 2.0.0", false},
+						},
+						{
+							Event:    "QueryPackagesSuccess",
+							Provider: beepProvider,
+							Args:     "2.1.0",
+						},
+						{
+							Event:    "FetchPackageMeta",
+							Provider: beepProvider,
+							Args:     "2.1.0",
+						},
+						{
+							Event:    "FetchPackageBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Version  string
+								Location getproviders.PackageLocation
+							}{"2.1.0", beepProviderDir},
+						},
+						{
+							Event:    "ProvidersLockUpdated",
+							Provider: beepProvider,
+							Args: struct {
+								Version string
+								Local   []getproviders.Hash
+								Signed  []getproviders.Hash
+								Prior   []getproviders.Hash
+							}{
+								"2.1.0",
+								[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+								nil,
+								nil,
+							},
+						},
+						{
+							Event:    "FetchPackageSuccess",
+							Provider: beepProvider,
+							Args: struct {
+								Version    string
+								LocalDir   string
+								AuthResult string
+							}{
+								"2.1.0",
+								filepath.Join(dir.BasePath(), "example.com/foo/beep/2.1.0/bleep_bloop"),
+								"unauthenticated",
+							},
+						},
+					},
+				}
+			},
+		},
+		"successful initial install of one provider through a warm global cache but without a lock file entry": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.1.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			Prepare: func(t *testing.T, inst *Installer, dir *Dir) {
+				globalCacheDirPath := tmpDir(t)
+				globalCacheDir := NewDirWithPlatform(globalCacheDirPath, fakePlatform)
+				_, err := globalCacheDir.InstallPackage(
+					context.Background(),
+					getproviders.PackageMeta{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.1.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					nil,
+				)
+				if err != nil {
+					t.Fatalf("failed to populate global cache: %s", err)
+				}
+				inst.SetGlobalCacheDir(globalCacheDir)
+			},
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+			},
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 1 {
+					t.Errorf("wrong number of cache directory entries; want only one\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 1 {
+					t.Errorf("wrong number of provider lock entries; want only one\n%s", spew.Sdump(allLocked))
+				}
+
+				gotLock := locks.Provider(beepProvider)
+				wantLock := depsfile.NewProviderLock(
+					beepProvider,
+					getproviders.MustParseVersion("2.1.0"),
+					getproviders.MustParseVersionConstraints(">= 2.0.0"),
+					[]getproviders.Hash{beepProviderHash},
+				)
+				if diff := cmp.Diff(wantLock, gotLock, depsfile.ProviderLockComparer); diff != "" {
+					t.Errorf("wrong lock entry\n%s", diff)
+				}
+
+				gotEntry := dir.ProviderLatestVersion(beepProvider)
+				wantEntry := &CachedProvider{
+					Provider:   beepProvider,
+					Version:    getproviders.MustParseVersion("2.1.0"),
+					PackageDir: filepath.Join(dir.BasePath(), "example.com/foo/beep/2.1.0/bleep_bloop"),
+				}
+				if diff := cmp.Diff(wantEntry, gotEntry); diff != "" {
+					t.Errorf("wrong cache entry\n%s", diff)
+				}
+			},
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+							},
+						},
+						{
+							Event: "ProvidersFetched",
+							Args: map[addrs.Provider]*getproviders.PackageAuthenticationResult{
+								beepProvider: nil,
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 2.0.0", false},
+						},
+						{
+							Event:    "QueryPackagesSuccess",
+							Provider: beepProvider,
+							Args:     "2.1.0",
+						},
+						// Existing cache entry is ineligible for linking because
+						// we have no lock file checksums to compare it to.
+						// Instead, we install from upstream and lock with
+						// whatever checksums we learn in that process.
+						{
+							Event:    "FetchPackageMeta",
+							Provider: beepProvider,
+							Args:     "2.1.0",
+						},
+						{
+							Event:    "FetchPackageBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Version  string
+								Location getproviders.PackageLocation
+							}{
+								"2.1.0",
+								beepProviderDir,
+							},
+						},
+						{
+							Event:    "ProvidersLockUpdated",
+							Provider: beepProvider,
+							Args: struct {
+								Version string
+								Local   []getproviders.Hash
+								Signed  []getproviders.Hash
+								Prior   []getproviders.Hash
+							}{
+								"2.1.0",
+								[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+								nil,
+								nil,
+							},
+						},
+						{
+							Event:    "FetchPackageSuccess",
+							Provider: beepProvider,
+							Args: struct {
+								Version    string
+								LocalDir   string
+								AuthResult string
+							}{
+								"2.1.0",
+								filepath.Join(dir.BasePath(), "/example.com/foo/beep/2.1.0/bleep_bloop"),
+								"unauthenticated",
+							},
+						},
+					},
+				}
+			},
+		},
+		"successful initial install of one provider through a warm global cache and correct locked checksum": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.1.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			LockFile: `
+				# The existing cache entry is valid only if it matches a
+				# checksum already recorded in the lock file.
+				provider "example.com/foo/beep" {
+					version     = "2.1.0"
+					constraints = ">= 1.0.0"
+					hashes = [
+						"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84=",
+					]
+				}
+			`,
+			Prepare: func(t *testing.T, inst *Installer, dir *Dir) {
+				globalCacheDirPath := tmpDir(t)
+				globalCacheDir := NewDirWithPlatform(globalCacheDirPath, fakePlatform)
+				_, err := globalCacheDir.InstallPackage(
+					context.Background(),
+					getproviders.PackageMeta{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.1.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					nil,
+				)
+				if err != nil {
+					t.Fatalf("failed to populate global cache: %s", err)
+				}
+				inst.SetGlobalCacheDir(globalCacheDir)
+			},
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+			},
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 1 {
+					t.Errorf("wrong number of cache directory entries; want only one\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 1 {
+					t.Errorf("wrong number of provider lock entries; want only one\n%s", spew.Sdump(allLocked))
+				}
+
+				gotLock := locks.Provider(beepProvider)
+				wantLock := depsfile.NewProviderLock(
+					beepProvider,
+					getproviders.MustParseVersion("2.1.0"),
+					getproviders.MustParseVersionConstraints(">= 2.0.0"),
+					[]getproviders.Hash{beepProviderHash},
+				)
+				if diff := cmp.Diff(wantLock, gotLock, depsfile.ProviderLockComparer); diff != "" {
+					t.Errorf("wrong lock entry\n%s", diff)
+				}
+
+				gotEntry := dir.ProviderLatestVersion(beepProvider)
+				wantEntry := &CachedProvider{
+					Provider:   beepProvider,
+					Version:    getproviders.MustParseVersion("2.1.0"),
+					PackageDir: filepath.Join(dir.BasePath(), "example.com/foo/beep/2.1.0/bleep_bloop"),
+				}
+				if diff := cmp.Diff(wantEntry, gotEntry); diff != "" {
+					t.Errorf("wrong cache entry\n%s", diff)
+				}
+			},
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 2.0.0", true},
+						},
+						{
+							Event:    "QueryPackagesSuccess",
+							Provider: beepProvider,
+							Args:     "2.1.0",
+						},
+						{
+							Event:    "LinkFromCacheBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Version   string
+								CacheRoot string
+							}{
+								"2.1.0",
+								inst.globalCacheDir.BasePath(),
+							},
+						},
+						{
+							Event:    "ProvidersLockUpdated",
+							Provider: beepProvider,
+							Args: struct {
+								Version string
+								Local   []getproviders.Hash
+								Signed  []getproviders.Hash
+								Prior   []getproviders.Hash
+							}{
+								"2.1.0",
+								[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+								nil,
+								[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+							},
+						},
+						{
+							Event:    "LinkFromCacheSuccess",
+							Provider: beepProvider,
+							Args: struct {
+								Version  string
+								LocalDir string
+							}{
+								"2.1.0",
+								filepath.Join(dir.BasePath(), "/example.com/foo/beep/2.1.0/bleep_bloop"),
+							},
+						},
+					},
+				}
+			},
+		},
+		"successful initial install of one provider through a warm global cache with an incompatible checksum": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.1.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			LockFile: `
+				# This is approximating the awkward situation where the lock
+				# file was populated by someone who installed from a location
+				# other than the origin registry annd so the set of checksums
+				# is incomplete. In this case we can't prove that our cache
+				# entry is valid and so we silently ignore the cache entry
+				# and try to install from upstream anyway, in the hope that
+				# this will give us an opportunity to access the origin
+				# registry and get a checksum that works for the current
+				# platform.
+				provider "example.com/foo/beep" {
+					version     = "2.1.0"
+					constraints = ">= 1.0.0"
+					hashes = [
+						# NOTE: This is the correct checksum for the
+						# beepProviderDir package, but we're going to
+						# intentionally install from a different directory
+						# below so that the entry in the cache will not
+						# match this checksum.
+						"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84=",
+					]
+				}
+			`,
+			Prepare: func(t *testing.T, inst *Installer, dir *Dir) {
+				// This is another "beep provider" package directory that
+				// has a different checksum than the one in beepProviderDir.
+				// We're mimicking the situation where the lock file was
+				// originally built from beepProviderDir but the local system
+				// is running on a different platform and so its existing
+				// cache entry doesn't match the checksum.
+				beepProviderOtherPlatformDir := getproviders.PackageLocalDir("testdata/beep-provider-other-platform")
+
+				globalCacheDirPath := tmpDir(t)
+				globalCacheDir := NewDirWithPlatform(globalCacheDirPath, fakePlatform)
+				_, err := globalCacheDir.InstallPackage(
+					context.Background(),
+					getproviders.PackageMeta{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.1.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderOtherPlatformDir,
+					},
+					nil,
+				)
+				if err != nil {
+					t.Fatalf("failed to populate global cache: %s", err)
+				}
+				inst.SetGlobalCacheDir(globalCacheDir)
+			},
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+			},
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 1 {
+					t.Errorf("wrong number of cache directory entries; want only one\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 1 {
+					t.Errorf("wrong number of provider lock entries; want only one\n%s", spew.Sdump(allLocked))
+				}
+
+				gotLock := locks.Provider(beepProvider)
+				wantLock := depsfile.NewProviderLock(
+					beepProvider,
+					getproviders.MustParseVersion("2.1.0"),
+					getproviders.MustParseVersionConstraints(">= 2.0.0"),
+					[]getproviders.Hash{beepProviderHash},
+				)
+				if diff := cmp.Diff(wantLock, gotLock, depsfile.ProviderLockComparer); diff != "" {
+					t.Errorf("wrong lock entry\n%s", diff)
+				}
+
+				gotEntry := dir.ProviderLatestVersion(beepProvider)
+				wantEntry := &CachedProvider{
+					Provider:   beepProvider,
+					Version:    getproviders.MustParseVersion("2.1.0"),
+					PackageDir: filepath.Join(dir.BasePath(), "example.com/foo/beep/2.1.0/bleep_bloop"),
+				}
+				if diff := cmp.Diff(wantEntry, gotEntry); diff != "" {
+					t.Errorf("wrong cache entry\n%s", diff)
+				}
+			},
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+							},
+						},
+						{
+							Event: "ProvidersFetched",
+							Args: map[addrs.Provider]*getproviders.PackageAuthenticationResult{
+								beepProvider: nil,
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 2.0.0", true},
+						},
+						{
+							Event:    "QueryPackagesSuccess",
+							Provider: beepProvider,
+							Args:     "2.1.0",
+						},
+						{
+							Event:    "FetchPackageMeta",
+							Provider: beepProvider,
+							Args:     "2.1.0",
+						},
+						{
+							Event:    "FetchPackageBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Version  string
+								Location getproviders.PackageLocation
+							}{
+								"2.1.0",
+								beepProviderDir,
+							},
+						},
+						{
+							Event:    "ProvidersLockUpdated",
+							Provider: beepProvider,
+							Args: struct {
+								Version string
+								Local   []getproviders.Hash
+								Signed  []getproviders.Hash
+								Prior   []getproviders.Hash
+							}{
+								"2.1.0",
+								[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+								nil,
+								[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+							},
+						},
+						{
+							Event:    "FetchPackageSuccess",
+							Provider: beepProvider,
+							Args: struct {
+								Version    string
+								LocalDir   string
+								AuthResult string
+							}{
+								"2.1.0",
+								filepath.Join(dir.BasePath(), "/example.com/foo/beep/2.1.0/bleep_bloop"),
+								"unauthenticated",
+							},
+						},
+					},
+				}
+			},
+		},
+		"successful initial install of one provider through a warm global cache without a lock file entry but allowing the cache to break the lock file": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.1.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			LockFile: `
+				# (intentionally empty)
+			`,
+			Prepare: func(t *testing.T, inst *Installer, dir *Dir) {
+				globalCacheDirPath := tmpDir(t)
+				globalCacheDir := NewDirWithPlatform(globalCacheDirPath, fakePlatform)
+				_, err := globalCacheDir.InstallPackage(
+					context.Background(),
+					getproviders.PackageMeta{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.1.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					nil,
+				)
+				if err != nil {
+					t.Fatalf("failed to populate global cache: %s", err)
+				}
+				inst.SetGlobalCacheDir(globalCacheDir)
+				inst.SetGlobalCacheDirMayBreakDependencyLockFile(true)
+			},
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+			},
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 1 {
+					t.Errorf("wrong number of cache directory entries; want only one\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 1 {
+					t.Errorf("wrong number of provider lock entries; want only one\n%s", spew.Sdump(allLocked))
+				}
+
+				gotLock := locks.Provider(beepProvider)
+				wantLock := depsfile.NewProviderLock(
+					beepProvider,
+					getproviders.MustParseVersion("2.1.0"),
+					getproviders.MustParseVersionConstraints(">= 2.0.0"),
+					[]getproviders.Hash{beepProviderHash},
+				)
+				if diff := cmp.Diff(wantLock, gotLock, depsfile.ProviderLockComparer); diff != "" {
+					t.Errorf("wrong lock entry\n%s", diff)
+				}
+
+				gotEntry := dir.ProviderLatestVersion(beepProvider)
+				wantEntry := &CachedProvider{
+					Provider:   beepProvider,
+					Version:    getproviders.MustParseVersion("2.1.0"),
+					PackageDir: filepath.Join(dir.BasePath(), "example.com/foo/beep/2.1.0/bleep_bloop"),
+				}
+				if diff := cmp.Diff(wantEntry, gotEntry); diff != "" {
+					t.Errorf("wrong cache entry\n%s", diff)
+				}
+			},
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 2.0.0", false},
+						},
+						{
+							Event:    "QueryPackagesSuccess",
+							Provider: beepProvider,
+							Args:     "2.1.0",
+						},
+						{
+							Event:    "LinkFromCacheBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Version   string
+								CacheRoot string
+							}{
+								"2.1.0",
+								inst.globalCacheDir.BasePath(),
+							},
+						},
+						{
+							Event:    "ProvidersLockUpdated",
+							Provider: beepProvider,
+							Args: struct {
+								Version string
+								Local   []getproviders.Hash
+								Signed  []getproviders.Hash
+								Prior   []getproviders.Hash
+							}{
+								"2.1.0",
+								[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+								nil,
+								nil,
+							},
+						},
+						{
+							Event:    "LinkFromCacheSuccess",
+							Provider: beepProvider,
+							Args: struct {
+								Version  string
+								LocalDir string
+							}{
+								"2.1.0",
+								filepath.Join(dir.BasePath(), "/example.com/foo/beep/2.1.0/bleep_bloop"),
+							},
+						},
+					},
+				}
+			},
+		},
+		"failing install of one provider through a warm global cache with an incorrect locked checksum while allowing the cache to break the lock file": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.1.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			LockFile: `
+				# The existing cache entry is valid only if it matches a
+				# checksum already recorded in the lock file, but this
+				# test is overriding that rule using a special setting.
+				provider "example.com/foo/beep" {
+					version     = "2.1.0"
+					constraints = ">= 1.0.0"
+					hashes = [
+						"h1:wrong-not-matchy",
+					]
+				}
+			`,
+			Prepare: func(t *testing.T, inst *Installer, dir *Dir) {
+				globalCacheDirPath := tmpDir(t)
+				globalCacheDir := NewDirWithPlatform(globalCacheDirPath, fakePlatform)
+				_, err := globalCacheDir.InstallPackage(
+					context.Background(),
+					getproviders.PackageMeta{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.1.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					nil,
+				)
+				if err != nil {
+					t.Fatalf("failed to populate global cache: %s", err)
+				}
+				inst.SetGlobalCacheDir(globalCacheDir)
+				inst.SetGlobalCacheDirMayBreakDependencyLockFile(true)
+			},
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+			},
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 0 {
+					t.Errorf("wrong number of cache directory entries; want none\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 1 {
+					t.Errorf("wrong number of provider lock entries; want only one\n%s", spew.Sdump(allLocked))
+				}
+
+				gotLock := locks.Provider(beepProvider)
+				wantLock := depsfile.NewProviderLock(
+					// The lock file entry hasn't changed because the cache
+					// entry didn't match the existing lock file entry.
+					beepProvider,
+					getproviders.MustParseVersion("2.1.0"),
+					getproviders.MustParseVersionConstraints(">= 1.0.0"),
+					[]getproviders.Hash{"h1:wrong-not-matchy"},
+				)
+				if diff := cmp.Diff(wantLock, gotLock, depsfile.ProviderLockComparer); diff != "" {
+					t.Errorf("wrong lock entry\n%s", diff)
+				}
+
+				// The provider wasn't installed into the local cache directory
+				// because that would make the local cache mismatch the
+				// lock file.
+				gotEntry := dir.ProviderLatestVersion(beepProvider)
+				wantEntry := (*CachedProvider)(nil)
+				if diff := cmp.Diff(wantEntry, gotEntry); diff != "" {
+					t.Errorf("wrong cache entry\n%s", diff)
+				}
+			},
+			WantErr: `doesn't match any of the checksums`,
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 2.0.0", true},
+						},
+						{
+							Event:    "QueryPackagesSuccess",
+							Provider: beepProvider,
+							Args:     "2.1.0",
+						},
+						{
+							Event:    "LinkFromCacheBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Version   string
+								CacheRoot string
+							}{
+								"2.1.0",
+								inst.globalCacheDir.BasePath(),
+							},
+						},
+						{
+							Event:    "LinkFromCacheFailure",
+							Provider: beepProvider,
+							Args: struct {
+								Version string
+								Error   string
+							}{
+								"2.1.0",
+								fmt.Sprintf(
+									"the provider cache at %s has a copy of example.com/foo/beep 2.1.0 that doesn't match any of the checksums recorded in the dependency lock file",
+									dir.BasePath(),
+								),
+							},
+						},
+					},
+				}
+			},
+		},
+		"successful reinstall of one previously-locked provider": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("1.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.1.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			LockFile: `
+				provider "example.com/foo/beep" {
+					version     = "2.0.0"
+					constraints = ">= 2.0.0"
+					hashes = [
+						"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84=",
+					]
+				}
+			`,
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+			},
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 1 {
+					t.Errorf("wrong number of cache directory entries; want only one\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 1 {
+					t.Errorf("wrong number of provider lock entries; want only one\n%s", spew.Sdump(allLocked))
+				}
+
+				gotLock := locks.Provider(beepProvider)
+				wantLock := depsfile.NewProviderLock(
+					beepProvider,
+					getproviders.MustParseVersion("2.0.0"),
+					getproviders.MustParseVersionConstraints(">= 2.0.0"),
+					[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+				)
+				if diff := cmp.Diff(wantLock, gotLock, depsfile.ProviderLockComparer); diff != "" {
+					t.Errorf("wrong lock entry\n%s", diff)
+				}
+
+				gotEntry := dir.ProviderLatestVersion(beepProvider)
+				wantEntry := &CachedProvider{
+					Provider:   beepProvider,
+					Version:    getproviders.MustParseVersion("2.0.0"),
+					PackageDir: filepath.Join(dir.BasePath(), "example.com/foo/beep/2.0.0/bleep_bloop"),
+				}
+				if diff := cmp.Diff(wantEntry, gotEntry); diff != "" {
+					t.Errorf("wrong cache entry\n%s", diff)
+				}
+			},
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+							},
+						},
+						{
+							Event: "ProvidersFetched",
+							Args: map[addrs.Provider]*getproviders.PackageAuthenticationResult{
+								beepProvider: nil,
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 2.0.0", true},
+						},
+						{
+							Event:    "QueryPackagesSuccess",
+							Provider: beepProvider,
+							Args:     "2.0.0",
+						},
+						{
+							Event:    "FetchPackageMeta",
+							Provider: beepProvider,
+							Args:     "2.0.0",
+						},
+						{
+							Event:    "FetchPackageBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Version  string
+								Location getproviders.PackageLocation
+							}{"2.0.0", beepProviderDir},
+						},
+						{
+							Event:    "ProvidersLockUpdated",
+							Provider: beepProvider,
+							Args: struct {
+								Version string
+								Local   []getproviders.Hash
+								Signed  []getproviders.Hash
+								Prior   []getproviders.Hash
+							}{
+								"2.0.0",
+								[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+								nil,
+								[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+							},
+						},
+						{
+							Event:    "FetchPackageSuccess",
+							Provider: beepProvider,
+							Args: struct {
+								Version    string
+								LocalDir   string
+								AuthResult string
+							}{
+								"2.0.0",
+								filepath.Join(dir.BasePath(), "example.com/foo/beep/2.0.0/bleep_bloop"),
+								"unauthenticated",
+							},
+						},
+					},
+				}
+			},
+		},
+		"skipped install of one previously-locked and installed provider": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			LockFile: `
+				provider "example.com/foo/beep" {
+					version     = "2.0.0"
+					constraints = ">= 2.0.0"
+					hashes = [
+						"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84=",
+					]
+				}
+			`,
+			Prepare: func(t *testing.T, inst *Installer, dir *Dir) {
+				_, err := dir.InstallPackage(
+					context.Background(),
+					getproviders.PackageMeta{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					nil,
+				)
+				if err != nil {
+					t.Fatalf("installation to the test dir failed: %s", err)
+				}
+			},
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+			},
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 1 {
+					t.Errorf("wrong number of cache directory entries; want only one\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 1 {
+					t.Errorf("wrong number of provider lock entries; want only one\n%s", spew.Sdump(allLocked))
+				}
+
+				gotLock := locks.Provider(beepProvider)
+				wantLock := depsfile.NewProviderLock(
+					beepProvider,
+					getproviders.MustParseVersion("2.0.0"),
+					getproviders.MustParseVersionConstraints(">= 2.0.0"),
+					[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+				)
+				if diff := cmp.Diff(wantLock, gotLock, depsfile.ProviderLockComparer); diff != "" {
+					t.Errorf("wrong lock entry\n%s", diff)
+				}
+
+				gotEntry := dir.ProviderLatestVersion(beepProvider)
+				wantEntry := &CachedProvider{
+					Provider:   beepProvider,
+					Version:    getproviders.MustParseVersion("2.0.0"),
+					PackageDir: filepath.Join(dir.BasePath(), "example.com/foo/beep/2.0.0/bleep_bloop"),
+				}
+				if diff := cmp.Diff(wantEntry, gotEntry); diff != "" {
+					t.Errorf("wrong cache entry\n%s", diff)
+				}
+			},
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 2.0.0", true},
+						},
+						{
+							Event:    "QueryPackagesSuccess",
+							Provider: beepProvider,
+							Args:     "2.0.0",
+						},
+						{
+							Event:    "ProviderAlreadyInstalled",
+							Provider: beepProvider,
+							Args:     versions.Version{Major: 2, Minor: 0, Patch: 0},
+						},
+					},
+				}
+			},
+		},
+		"successful upgrade of one previously-locked provider": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("1.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.1.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			LockFile: `
+				provider "example.com/foo/beep" {
+					version     = "2.0.0"
+					constraints = ">= 2.0.0"
+					hashes = [
+						"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84=",
+					]
+				}
+			`,
+			Mode: InstallUpgrades,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+			},
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 1 {
+					t.Errorf("wrong number of cache directory entries; want only one\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 1 {
+					t.Errorf("wrong number of provider lock entries; want only one\n%s", spew.Sdump(allLocked))
+				}
+
+				gotLock := locks.Provider(beepProvider)
+				wantLock := depsfile.NewProviderLock(
+					beepProvider,
+					getproviders.MustParseVersion("2.1.0"),
+					getproviders.MustParseVersionConstraints(">= 2.0.0"),
+					[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+				)
+				if diff := cmp.Diff(wantLock, gotLock, depsfile.ProviderLockComparer); diff != "" {
+					t.Errorf("wrong lock entry\n%s", diff)
+				}
+
+				gotEntry := dir.ProviderLatestVersion(beepProvider)
+				wantEntry := &CachedProvider{
+					Provider:   beepProvider,
+					Version:    getproviders.MustParseVersion("2.1.0"),
+					PackageDir: filepath.Join(dir.BasePath(), "example.com/foo/beep/2.1.0/bleep_bloop"),
+				}
+				if diff := cmp.Diff(wantEntry, gotEntry); diff != "" {
+					t.Errorf("wrong cache entry\n%s", diff)
+				}
+			},
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+							},
+						},
+						{
+							Event: "ProvidersFetched",
+							Args: map[addrs.Provider]*getproviders.PackageAuthenticationResult{
+								beepProvider: nil,
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 2.0.0", false},
+						},
+						{
+							Event:    "QueryPackagesSuccess",
+							Provider: beepProvider,
+							Args:     "2.1.0",
+						},
+						{
+							Event:    "FetchPackageMeta",
+							Provider: beepProvider,
+							Args:     "2.1.0",
+						},
+						{
+							Event:    "FetchPackageBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Version  string
+								Location getproviders.PackageLocation
+							}{"2.1.0", beepProviderDir},
+						},
+						{
+							Event:    "ProvidersLockUpdated",
+							Provider: beepProvider,
+							Args: struct {
+								Version string
+								Local   []getproviders.Hash
+								Signed  []getproviders.Hash
+								Prior   []getproviders.Hash
+							}{
+								"2.1.0",
+								[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+								nil,
+								nil,
+							},
+						},
+						{
+							Event:    "FetchPackageSuccess",
+							Provider: beepProvider,
+							Args: struct {
+								Version    string
+								LocalDir   string
+								AuthResult string
+							}{
+								"2.1.0",
+								filepath.Join(dir.BasePath(), "example.com/foo/beep/2.1.0/bleep_bloop"),
+								"unauthenticated",
+							},
+						},
+					},
+				}
+			},
+		},
+		"successful install of a built-in provider": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{},
+				nil,
+			),
+			Prepare: func(t *testing.T, inst *Installer, dir *Dir) {
+				inst.SetBuiltInProviderTypes([]string{"terraform"})
+			},
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				terraformProvider: nil,
+			},
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				// Built-in providers are neither included in the cache
+				// directory nor mentioned in the lock file, because they
+				// are compiled directly into the Terraform executable.
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 0 {
+					t.Errorf("wrong number of cache directory entries; want none\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 0 {
+					t.Errorf("wrong number of provider lock entries; want none\n%s", spew.Sdump(allLocked))
+				}
+			},
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								terraformProvider: constraints.IntersectionSpec(nil),
+							},
+						},
+					},
+					terraformProvider: {
+						{
+							Event:    "BuiltInProviderAvailable",
+							Provider: terraformProvider,
+						},
+					},
+				}
+			},
+		},
+		"remove no-longer-needed provider from lock file": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("1.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			LockFile: `
+				provider "example.com/foo/beep" {
+					version     = "1.0.0"
+					constraints = ">= 1.0.0"
+					hashes = [
+						"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84=",
+					]
+				}
+				provider "example.com/foo/obsolete" {
+					version     = "2.0.0"
+					constraints = ">= 2.0.0"
+					hashes = [
+						"no:irrelevant",
+					]
+				}
+			`,
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 1.0.0"),
+			},
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 1 {
+					t.Errorf("wrong number of cache directory entries; want only one\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 1 {
+					t.Errorf("wrong number of provider lock entries; want only one\n%s", spew.Sdump(allLocked))
+				}
+
+				gotLock := locks.Provider(beepProvider)
+				wantLock := depsfile.NewProviderLock(
+					beepProvider,
+					getproviders.MustParseVersion("1.0.0"),
+					getproviders.MustParseVersionConstraints(">= 1.0.0"),
+					[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+				)
+				if diff := cmp.Diff(wantLock, gotLock, depsfile.ProviderLockComparer); diff != "" {
+					t.Errorf("wrong lock entry\n%s", diff)
+				}
+
+				gotEntry := dir.ProviderLatestVersion(beepProvider)
+				wantEntry := &CachedProvider{
+					Provider:   beepProvider,
+					Version:    getproviders.MustParseVersion("1.0.0"),
+					PackageDir: filepath.Join(dir.BasePath(), "example.com/foo/beep/1.0.0/bleep_bloop"),
+				}
+				if diff := cmp.Diff(wantEntry, gotEntry); diff != "" {
+					t.Errorf("wrong cache entry\n%s", diff)
+				}
+			},
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 1.0.0"),
+							},
+						},
+						{
+							Event: "ProvidersFetched",
+							Args: map[addrs.Provider]*getproviders.PackageAuthenticationResult{
+								beepProvider: nil,
+							},
+						},
+					},
+					// Note: intentionally no entries for example.com/foo/obsolete
+					// here, because it's no longer needed and therefore not
+					// installed.
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 1.0.0", true},
+						},
+						{
+							Event:    "QueryPackagesSuccess",
+							Provider: beepProvider,
+							Args:     "1.0.0",
+						},
+						{
+							Event:    "FetchPackageMeta",
+							Provider: beepProvider,
+							Args:     "1.0.0",
+						},
+						{
+							Event:    "FetchPackageBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Version  string
+								Location getproviders.PackageLocation
+							}{"1.0.0", beepProviderDir},
+						},
+						{
+							Event:    "ProvidersLockUpdated",
+							Provider: beepProvider,
+							Args: struct {
+								Version string
+								Local   []getproviders.Hash
+								Signed  []getproviders.Hash
+								Prior   []getproviders.Hash
+							}{
+								"1.0.0",
+								[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+								nil,
+								[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+							},
+						},
+						{
+							Event:    "FetchPackageSuccess",
+							Provider: beepProvider,
+							Args: struct {
+								Version    string
+								LocalDir   string
+								AuthResult string
+							}{
+								"1.0.0",
+								filepath.Join(dir.BasePath(), "example.com/foo/beep/1.0.0/bleep_bloop"),
+								"unauthenticated",
+							},
+						},
+					},
+				}
+			},
+		},
+		"failed install of a non-existing built-in provider": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{},
+				nil,
+			),
+			Prepare: func(t *testing.T, inst *Installer, dir *Dir) {
+				// NOTE: We're intentionally not calling
+				// inst.SetBuiltInProviderTypes to make the "terraform"
+				// built-in provider available here, so requests for it
+				// should fail.
+			},
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				terraformProvider: nil,
+			},
+			WantErr: `some providers could not be installed:
+- terraform.io/builtin/terraform: this Terraform release has no built-in provider named "terraform"`,
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								terraformProvider: constraints.IntersectionSpec(nil),
+							},
+						},
+					},
+					terraformProvider: {
+						{
+							Event:    "BuiltInProviderFailure",
+							Provider: terraformProvider,
+							Args:     `this Terraform release has no built-in provider named "terraform"`,
+						},
+					},
+				}
+			},
+		},
+		"failed install when a built-in provider has a version constraint": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{},
+				nil,
+			),
+			Prepare: func(t *testing.T, inst *Installer, dir *Dir) {
+				inst.SetBuiltInProviderTypes([]string{"terraform"})
+			},
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				terraformProvider: getproviders.MustParseVersionConstraints(">= 1.0.0"),
+			},
+			WantErr: `some providers could not be installed:
+- terraform.io/builtin/terraform: built-in providers do not support explicit version constraints`,
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								terraformProvider: getproviders.MustParseVersionConstraints(">= 1.0.0"),
+							},
+						},
+					},
+					terraformProvider: {
+						{
+							Event:    "BuiltInProviderFailure",
+							Provider: terraformProvider,
+							Args:     `built-in providers do not support explicit version constraints`,
+						},
+					},
+				}
+			},
+		},
+		"locked version is excluded by new version constraint": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("1.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			LockFile: `
+				provider "example.com/foo/beep" {
+					version     = "1.0.0"
+					constraints = ">= 1.0.0"
+					hashes = [
+						"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84=",
+					]
+				}
+			`,
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+			},
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 0 {
+					t.Errorf("wrong number of cache directory entries; want none\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 1 {
+					t.Errorf("wrong number of provider lock entries; want only one\n%s", spew.Sdump(allLocked))
+				}
+
+				gotLock := locks.Provider(beepProvider)
+				wantLock := depsfile.NewProviderLock(
+					beepProvider,
+					getproviders.MustParseVersion("1.0.0"),
+					getproviders.MustParseVersionConstraints(">= 1.0.0"),
+					[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+				)
+				if diff := cmp.Diff(wantLock, gotLock, depsfile.ProviderLockComparer); diff != "" {
+					t.Errorf("wrong lock entry\n%s", diff)
+				}
+			},
+			WantErr: `some providers could not be installed:
+- example.com/foo/beep: locked provider example.com/foo/beep 1.0.0 does not match configured version constraint >= 2.0.0; must use terraform init -upgrade to allow selection of new versions`,
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 2.0.0", true},
+						},
+						{
+							Event:    "QueryPackagesFailure",
+							Provider: beepProvider,
+							Args:     `locked provider example.com/foo/beep 1.0.0 does not match configured version constraint >= 2.0.0; must use terraform init -upgrade to allow selection of new versions`,
+						},
+					},
+				}
+			},
+		},
+		"locked version is no longer available": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("1.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("2.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			LockFile: `
+				provider "example.com/foo/beep" {
+					version     = "1.2.0"
+					constraints = ">= 1.0.0"
+					hashes = [
+						"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84=",
+					]
+				}
+			`,
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 1.0.0"),
+			},
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 0 {
+					t.Errorf("wrong number of cache directory entries; want none\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 1 {
+					t.Errorf("wrong number of provider lock entries; want only one\n%s", spew.Sdump(allLocked))
+				}
+
+				gotLock := locks.Provider(beepProvider)
+				wantLock := depsfile.NewProviderLock(
+					beepProvider,
+					getproviders.MustParseVersion("1.2.0"),
+					getproviders.MustParseVersionConstraints(">= 1.0.0"),
+					[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+				)
+				if diff := cmp.Diff(wantLock, gotLock, depsfile.ProviderLockComparer); diff != "" {
+					t.Errorf("wrong lock entry\n%s", diff)
+				}
+			},
+			WantErr: `some providers could not be installed:
+- example.com/foo/beep: the previously-selected version 1.2.0 is no longer available`,
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 1.0.0"),
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 1.0.0", true},
+						},
+						{
+							Event:    "QueryPackagesFailure",
+							Provider: beepProvider,
+							Args:     `the previously-selected version 1.2.0 is no longer available`,
+						},
+					},
+				}
+			},
+		},
+		"no versions match the version constraint": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("1.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+			},
+			WantErr: `some providers could not be installed:
+- example.com/foo/beep: no available releases match the given constraints >= 2.0.0`,
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 2.0.0"),
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 2.0.0", false},
+						},
+						{
+							Event:    "QueryPackagesFailure",
+							Provider: beepProvider,
+							Args:     `no available releases match the given constraints >= 2.0.0`,
+						},
+					},
+				}
+			},
+		},
+		"version exists but doesn't support the current platform": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("1.0.0"),
+						TargetPlatform: wrongPlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 1.0.0"),
+			},
+			WantErr: `some providers could not be installed:
+- example.com/foo/beep: provider example.com/foo/beep 1.0.0 is not available for bleep_bloop`,
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 1.0.0"),
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 1.0.0", false},
+						},
+						{
+							Event:    "QueryPackagesSuccess",
+							Provider: beepProvider,
+							Args:     "1.0.0",
+						},
+						{
+							Event:    "FetchPackageMeta",
+							Provider: beepProvider,
+							Args:     "1.0.0",
+						},
+						{
+							Event:    "FetchPackageFailure",
+							Provider: beepProvider,
+							Args: struct {
+								Version string
+								Error   string
+							}{
+								"1.0.0",
+								"provider example.com/foo/beep 1.0.0 is not available for bleep_bloop",
+							},
+						},
+					},
+				}
+			},
+		},
+		"available package doesn't match locked hash": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("1.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			LockFile: `
+				provider "example.com/foo/beep" {
+					version     = "1.0.0"
+					constraints = ">= 1.0.0"
+					hashes = [
+						"h1:does-not-match",
+					]
+				}
+			`,
+			Mode: InstallNewProvidersOnly,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 1.0.0"),
+			},
+			WantErr: `some providers could not be installed:
+- example.com/foo/beep: the local package for example.com/foo/beep 1.0.0 doesn't match any of the checksums previously recorded in the dependency lock file (this might be because the available checksums are for packages targeting different platforms); for more information: https://www.terraform.io/language/provider-checksum-verification`,
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 1.0.0"),
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 1.0.0", true},
+						},
+						{
+							Event:    "QueryPackagesSuccess",
+							Provider: beepProvider,
+							Args:     "1.0.0",
+						},
+						{
+							Event:    "FetchPackageMeta",
+							Provider: beepProvider,
+							Args:     "1.0.0",
+						},
+						{
+							Event:    "FetchPackageBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Version  string
+								Location getproviders.PackageLocation
+							}{"1.0.0", beepProviderDir},
+						},
+						{
+							Event:    "FetchPackageFailure",
+							Provider: beepProvider,
+							Args: struct {
+								Version string
+								Error   string
+							}{
+								"1.0.0",
+								`the local package for example.com/foo/beep 1.0.0 doesn't match any of the checksums previously recorded in the dependency lock file (this might be because the available checksums are for packages targeting different platforms); for more information: https://www.terraform.io/language/provider-checksum-verification`,
+							},
+						},
+					},
+				}
+			},
+		},
+		"force mode ignores hashes": {
+			Source: getproviders.NewMockSource(
+				[]getproviders.PackageMeta{
+					{
+						Provider:       beepProvider,
+						Version:        getproviders.MustParseVersion("1.0.0"),
+						TargetPlatform: fakePlatform,
+						Location:       beepProviderDir,
+					},
+				},
+				nil,
+			),
+			LockFile: `
+				provider "example.com/foo/beep" {
+					version     = "1.0.0"
+					constraints = ">= 1.0.0"
+					hashes = [
+						"h1:does-not-match",
+					]
+				}
+			`,
+			Mode: InstallNewProvidersForce,
+			Reqs: getproviders.Requirements{
+				beepProvider: getproviders.MustParseVersionConstraints(">= 1.0.0"),
+			},
+			Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
+				if allCached := dir.AllAvailablePackages(); len(allCached) != 1 {
+					t.Errorf("wrong number of cache directory entries; want only one\n%s", spew.Sdump(allCached))
+				}
+				if allLocked := locks.AllProviders(); len(allLocked) != 1 {
+					t.Errorf("wrong number of provider lock entries; want only one\n%s", spew.Sdump(allLocked))
+				}
+
+				gotLock := locks.Provider(beepProvider)
+				wantLock := depsfile.NewProviderLock(
+					beepProvider,
+					getproviders.MustParseVersion("1.0.0"),
+					getproviders.MustParseVersionConstraints(">= 1.0.0"),
+					[]getproviders.Hash{beepProviderHash, "h1:does-not-match"},
+				)
+				if diff := cmp.Diff(wantLock, gotLock, depsfile.ProviderLockComparer); diff != "" {
+					t.Errorf("wrong lock entry\n%s", diff)
+				}
+
+				gotEntry := dir.ProviderLatestVersion(beepProvider)
+				wantEntry := &CachedProvider{
+					Provider:   beepProvider,
+					Version:    getproviders.MustParseVersion("1.0.0"),
+					PackageDir: filepath.Join(dir.BasePath(), "example.com/foo/beep/1.0.0/bleep_bloop"),
+				}
+				if diff := cmp.Diff(wantEntry, gotEntry); diff != "" {
+					t.Errorf("wrong cache entry\n%s", diff)
+				}
+			},
+			WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
+				return map[addrs.Provider][]*testInstallerEventLogItem{
+					noProvider: {
+						{
+							Event: "PendingProviders",
+							Args: map[addrs.Provider]getproviders.VersionConstraints{
+								beepProvider: getproviders.MustParseVersionConstraints(">= 1.0.0"),
+							},
+						},
+						{
+							Event: "ProvidersFetched",
+							Args: map[addrs.Provider]*getproviders.PackageAuthenticationResult{
+								beepProvider: nil,
+							},
+						},
+					},
+					beepProvider: {
+						{
+							Event:    "QueryPackagesBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Constraints string
+								Locked      bool
+							}{">= 1.0.0", true},
+						},
+						{
+							Event:    "QueryPackagesSuccess",
+							Provider: beepProvider,
+							Args:     "1.0.0",
+						},
+						{
+							Event:    "FetchPackageMeta",
+							Provider: beepProvider,
+							Args:     "1.0.0",
+						},
+						{
+							Event:    "FetchPackageBegin",
+							Provider: beepProvider,
+							Args: struct {
+								Version  string
+								Location getproviders.PackageLocation
+							}{"1.0.0", beepProviderDir},
+						},
+						{
+							Event:    "ProvidersLockUpdated",
+							Provider: beepProvider,
+							Args: struct {
+								Version string
+								Local   []getproviders.Hash
+								Signed  []getproviders.Hash
+								Prior   []getproviders.Hash
+							}{
+								"1.0.0",
+								[]getproviders.Hash{"h1:2y06Ykj0FRneZfGCTxI9wRTori8iB7ZL5kQ6YyEnh84="},
+								nil,
+								[]getproviders.Hash{"h1:does-not-match"},
+							},
+						},
+						{
+							Event:    "FetchPackageSuccess",
+							Provider: beepProvider,
+							Args: struct {
+								Version    string
+								LocalDir   string
+								AuthResult string
+							}{
+								"1.0.0",
+								filepath.Join(dir.BasePath(), "example.com/foo/beep/1.0.0/bleep_bloop"),
+								"unauthenticated",
+							},
+						},
+					},
+				}
+			},
+		},
+	}
+
+	ctx := context.Background()
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			if test.Check == nil && test.WantEvents == nil && test.WantErr == "" {
+				t.Fatalf("invalid test: must set at least one of Check, WantEvents, or WantErr")
+			}
+
+			outputDir := NewDirWithPlatform(tmpDir(t), fakePlatform)
+			source := test.Source
+			if source == nil {
+				source = getproviders.NewMockSource(nil, nil)
+			}
+			inst := NewInstaller(outputDir, source)
+			if test.Prepare != nil {
+				test.Prepare(t, inst, outputDir)
+			} /* boop */
+
+			locks, lockDiags := depsfile.LoadLocksFromBytes([]byte(test.LockFile), "test.lock.hcl")
+			if lockDiags.HasErrors() {
+				t.Fatalf("invalid lock file: %s", lockDiags.Err().Error())
+			}
+
+			providerEvents := make(map[addrs.Provider][]*testInstallerEventLogItem)
+			eventsCh := make(chan *testInstallerEventLogItem)
+			var newLocks *depsfile.Locks
+			var instErr error
+			go func(ch chan *testInstallerEventLogItem) {
+				events := installerLogEventsForTests(ch)
+				ctx := events.OnContext(ctx)
+				newLocks, instErr = inst.EnsureProviderVersions(ctx, locks, test.Reqs, test.Mode)
+				close(eventsCh) // exits the event loop below
+			}(eventsCh)
+			for evt := range eventsCh {
+				// We do the event collection in the main goroutine, rather than
+				// running the installer itself in the main goroutine, so that
+				// we can safely t.Log in here without violating the testing.T
+				// usage rules.
+				if evt.Provider == (addrs.Provider{}) {
+					t.Logf("%s(%s)", evt.Event, spew.Sdump(evt.Args))
+				} else {
+					t.Logf("%s: %s(%s)", evt.Provider, evt.Event, spew.Sdump(evt.Args))
+				}
+				providerEvents[evt.Provider] = append(providerEvents[evt.Provider], evt)
+			}
+
+			if test.WantErr != "" {
+				if instErr == nil {
+					t.Errorf("succeeded; want error\nwant: %s", test.WantErr)
+				} else if got, want := instErr.Error(), test.WantErr; !strings.Contains(got, want) {
+					t.Errorf("wrong error\ngot: %s\nwant substring: %s", got, want)
+				}
+			} else if instErr != nil {
+				t.Errorf("unexpected error\ngot: %s", instErr.Error())
+			}
+
+			if test.Check != nil {
+				test.Check(t, outputDir, newLocks)
+			}
+
+			if test.WantEvents != nil {
+				wantEvents := test.WantEvents(inst, outputDir)
+				if diff := cmp.Diff(wantEvents, providerEvents); diff != "" {
+					t.Errorf("wrong installer events\n%s", diff)
+				}
+			}
+		})
+	}
+}
+
+func TestEnsureProviderVersions_local_source(t *testing.T) {
+	// create filesystem source using the test provider cache dir
+	source := getproviders.NewFilesystemMirrorSource("testdata/cachedir")
+
+	// create a temporary workdir
+	tmpDirPath := t.TempDir()
+
+	// set up the installer using the temporary directory and filesystem source
+	platform := getproviders.Platform{OS: "linux", Arch: "amd64"}
+	dir := NewDirWithPlatform(tmpDirPath, platform)
+	installer := NewInstaller(dir, source)
+
+	tests := map[string]struct {
+		provider string
+		version  string
+		wantHash getproviders.Hash // getproviders.NilHash if not expected to be installed
+		err      string
+	}{
+		"install-unpacked": {
+			provider: "null",
+			version:  "2.0.0",
+			wantHash: getproviders.HashScheme1.New("qjsREM4DqEWECD43FcPqddZ9oxCG+IaMTxvWPciS05g="),
+		},
+		"invalid-zip-file": {
+			provider: "null",
+			version:  "2.1.0",
+			wantHash: getproviders.NilHash,
+			err:      "zip: not a valid zip file",
+		},
+		"version-constraint-unmet": {
+			provider: "null",
+			version:  "2.2.0",
+			wantHash: getproviders.NilHash,
+			err:      "no available releases match the given constraints 2.2.0",
+		},
+		"missing-executable": {
+			provider: "missing/executable",
+			version:  "2.0.0",
+			wantHash: getproviders.NilHash, // installation fails for a provider with no executable
+			err:      "provider binary not found: could not find executable file starting with terraform-provider-executable",
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			ctx := context.TODO()
+
+			provider := addrs.MustParseProviderSourceString(test.provider)
+			versionConstraint := getproviders.MustParseVersionConstraints(test.version)
+			version := getproviders.MustParseVersion(test.version)
+			reqs := getproviders.Requirements{
+				provider: versionConstraint,
+			}
+
+			newLocks, err := installer.EnsureProviderVersions(ctx, depsfile.NewLocks(), reqs, InstallNewProvidersOnly)
+			gotProviderlocks := newLocks.AllProviders()
+			wantProviderLocks := map[addrs.Provider]*depsfile.ProviderLock{
+				provider: depsfile.NewProviderLock(
+					provider,
+					version,
+					getproviders.MustParseVersionConstraints("= 2.0.0"),
+					[]getproviders.Hash{
+						test.wantHash,
+					},
+				),
+			}
+			if test.wantHash == getproviders.NilHash {
+				wantProviderLocks = map[addrs.Provider]*depsfile.ProviderLock{}
+			}
+
+			if diff := cmp.Diff(wantProviderLocks, gotProviderlocks, depsfile.ProviderLockComparer); diff != "" {
+				t.Errorf("wrong selected\n%s", diff)
+			}
+
+			if test.err == "" && err == nil {
+				return
+			}
+
+			switch err := err.(type) {
+			case InstallerError:
+				providerError, ok := err.ProviderErrors[provider]
+				if !ok {
+					t.Fatalf("did not get error for provider %s", provider)
+				}
+
+				if got := providerError.Error(); got != test.err {
+					t.Fatalf("wrong result\ngot:  %s\nwant: %s\n", got, test.err)
+				}
+			default:
+				t.Fatalf("wrong error type. Expected InstallerError, got %T", err)
+			}
+		})
+	}
+}
+
+// This test only verifies protocol errors and does not try for successfull
+// installation (at the time of writing, the test files aren't signed so the
+// signature verification fails); that's left to the e2e tests.
+func TestEnsureProviderVersions_protocol_errors(t *testing.T) {
+	source, _, close := testRegistrySource(t)
+	defer close()
+
+	// create a temporary workdir
+	tmpDirPath := t.TempDir()
+
+	version0 := getproviders.MustParseVersionConstraints("0.1.0") // supports protocol version 1.0
+	version1 := getproviders.MustParseVersion("1.2.0")            // this is the expected result in tests with a match
+	version2 := getproviders.MustParseVersionConstraints("2.0")   // supports protocol version 99
+
+	// set up the installer using the temporary directory and mock source
+	platform := getproviders.Platform{OS: "gameboy", Arch: "lr35902"}
+	dir := NewDirWithPlatform(tmpDirPath, platform)
+	installer := NewInstaller(dir, source)
+
+	tests := map[string]struct {
+		provider     addrs.Provider
+		inputVersion getproviders.VersionConstraints
+		wantVersion  getproviders.Version
+	}{
+		"too old": {
+			addrs.MustParseProviderSourceString("example.com/awesomesauce/happycloud"),
+			version0,
+			version1,
+		},
+		"too new": {
+			addrs.MustParseProviderSourceString("example.com/awesomesauce/happycloud"),
+			version2,
+			version1,
+		},
+		"unsupported": {
+			addrs.MustParseProviderSourceString("example.com/weaksauce/unsupported-protocol"),
+			version0,
+			getproviders.UnspecifiedVersion,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			reqs := getproviders.Requirements{
+				test.provider: test.inputVersion,
+			}
+			ctx := context.TODO()
+			_, err := installer.EnsureProviderVersions(ctx, depsfile.NewLocks(), reqs, InstallNewProvidersOnly)
+
+			switch err := err.(type) {
+			case nil:
+				t.Fatalf("expected error, got success")
+			case InstallerError:
+				providerError, ok := err.ProviderErrors[test.provider]
+				if !ok {
+					t.Fatalf("did not get error for provider %s", test.provider)
+				}
+
+				switch providerError := providerError.(type) {
+				case getproviders.ErrProtocolNotSupported:
+					if !providerError.Suggestion.Same(test.wantVersion) {
+						t.Fatalf("wrong result\ngot:  %s\nwant: %s\n", providerError.Suggestion, test.wantVersion)
+					}
+				default:
+					t.Fatalf("wrong error type. Expected ErrProtocolNotSupported, got %T", err)
+				}
+			default:
+				t.Fatalf("wrong error type. Expected InstallerError, got %T", err)
+			}
+		})
+	}
+}
+
+// testServices starts up a local HTTP server running a fake provider registry
+// service and returns a service discovery object pre-configured to consider
+// the host "example.com" to be served by the fake registry service.
+//
+// The returned discovery object also knows the hostname "not.example.com"
+// which does not have a provider registry at all and "too-new.example.com"
+// which has a "providers.v99" service that is inoperable but could be useful
+// to test the error reporting for detecting an unsupported protocol version.
+// It also knows fails.example.com but it refers to an endpoint that doesn't
+// correctly speak HTTP, to simulate a protocol error.
+//
+// The second return value is a function to call at the end of a test function
+// to shut down the test server. After you call that function, the discovery
+// object becomes useless.
+func testServices(t *testing.T) (services *disco.Disco, baseURL string, cleanup func()) {
+	server := httptest.NewServer(http.HandlerFunc(fakeRegistryHandler))
+
+	services = disco.New()
+	services.ForceHostServices(svchost.Hostname("example.com"), map[string]interface{}{
+		"providers.v1": server.URL + "/providers/v1/",
+	})
+	services.ForceHostServices(svchost.Hostname("not.example.com"), map[string]interface{}{})
+	services.ForceHostServices(svchost.Hostname("too-new.example.com"), map[string]interface{}{
+		// This service doesn't actually work; it's here only to be
+		// detected as "too new" by the discovery logic.
+		"providers.v99": server.URL + "/providers/v99/",
+	})
+	services.ForceHostServices(svchost.Hostname("fails.example.com"), map[string]interface{}{
+		"providers.v1": server.URL + "/fails-immediately/",
+	})
+
+	// We'll also permit registry.terraform.io here just because it's our
+	// default and has some unique features that are not allowed on any other
+	// hostname. It behaves the same as example.com, which should be preferred
+	// if you're not testing something specific to the default registry in order
+	// to ensure that most things are hostname-agnostic.
+	services.ForceHostServices(svchost.Hostname("registry.terraform.io"), map[string]interface{}{
+		"providers.v1": server.URL + "/providers/v1/",
+	})
+
+	return services, server.URL, func() {
+		server.Close()
+	}
+}
+
+// testRegistrySource is a wrapper around testServices that uses the created
+// discovery object to produce a Source instance that is ready to use with the
+// fake registry services.
+//
+// As with testServices, the second return value is a function to call at the end
+// of your test in order to shut down the test server.
+func testRegistrySource(t *testing.T) (source *getproviders.RegistrySource, baseURL string, cleanup func()) {
+	services, baseURL, close := testServices(t)
+	source = getproviders.NewRegistrySource(services)
+	return source, baseURL, close
+}
+
+func fakeRegistryHandler(resp http.ResponseWriter, req *http.Request) {
+	path := req.URL.EscapedPath()
+	if strings.HasPrefix(path, "/fails-immediately/") {
+		// Here we take over the socket and just close it immediately, to
+		// simulate one possible way a server might not be an HTTP server.
+		hijacker, ok := resp.(http.Hijacker)
+		if !ok {
+			// Not hijackable, so we'll just fail normally.
+			// If this happens, tests relying on this will fail.
+			resp.WriteHeader(500)
+			resp.Write([]byte(`cannot hijack`))
+			return
+		}
+		conn, _, err := hijacker.Hijack()
+		if err != nil {
+			resp.WriteHeader(500)
+			resp.Write([]byte(`hijack failed`))
+			return
+		}
+		conn.Close()
+		return
+	}
+
+	if strings.HasPrefix(path, "/pkg/") {
+		switch path {
+		case "/pkg/awesomesauce/happycloud_1.2.0.zip":
+			resp.Write([]byte("some zip file"))
+		case "/pkg/awesomesauce/happycloud_1.2.0_SHA256SUMS":
+			resp.Write([]byte("000000000000000000000000000000000000000000000000000000000000f00d happycloud_1.2.0.zip\n"))
+		case "/pkg/awesomesauce/happycloud_1.2.0_SHA256SUMS.sig":
+			resp.Write([]byte("GPG signature"))
+		default:
+			resp.WriteHeader(404)
+			resp.Write([]byte("unknown package file download"))
+		}
+		return
+	}
+
+	if !strings.HasPrefix(path, "/providers/v1/") {
+		resp.WriteHeader(404)
+		resp.Write([]byte(`not a provider registry endpoint`))
+		return
+	}
+
+	pathParts := strings.Split(path, "/")[3:]
+	if len(pathParts) < 2 {
+		resp.WriteHeader(404)
+		resp.Write([]byte(`unexpected number of path parts`))
+		return
+	}
+	log.Printf("[TRACE] fake provider registry request for %#v", pathParts)
+	if len(pathParts) == 2 {
+		switch pathParts[0] + "/" + pathParts[1] {
+
+		case "-/legacy":
+			// NOTE: This legacy lookup endpoint is specific to
+			// registry.terraform.io and not expected to work on any other
+			// registry host.
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			resp.Write([]byte(`{"namespace":"legacycorp"}`))
+
+		default:
+			resp.WriteHeader(404)
+			resp.Write([]byte(`unknown namespace or provider type for direct lookup`))
+		}
+	}
+
+	if len(pathParts) < 3 {
+		resp.WriteHeader(404)
+		resp.Write([]byte(`unexpected number of path parts`))
+		return
+	}
+
+	if pathParts[2] == "versions" {
+		if len(pathParts) != 3 {
+			resp.WriteHeader(404)
+			resp.Write([]byte(`extraneous path parts`))
+			return
+		}
+
+		switch pathParts[0] + "/" + pathParts[1] {
+		case "awesomesauce/happycloud":
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			// Note that these version numbers are intentionally misordered
+			// so we can test that the client-side code places them in the
+			// correct order (lowest precedence first).
+			resp.Write([]byte(`{"versions":[{"version":"0.1.0","protocols":["1.0"]},{"version":"2.0.0","protocols":["99.0"]},{"version":"1.2.0","protocols":["5.0"]}, {"version":"1.0.0","protocols":["5.0"]}]}`))
+		case "weaksauce/unsupported-protocol":
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			resp.Write([]byte(`{"versions":[{"version":"0.1.0","protocols":["0.1"]}]}`))
+		case "weaksauce/no-versions":
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			resp.Write([]byte(`{"versions":[]}`))
+		default:
+			resp.WriteHeader(404)
+			resp.Write([]byte(`unknown namespace or provider type`))
+		}
+		return
+	}
+
+	if len(pathParts) == 6 && pathParts[3] == "download" {
+		switch pathParts[0] + "/" + pathParts[1] {
+		case "awesomesauce/happycloud":
+			if pathParts[4] == "nonexist" {
+				resp.WriteHeader(404)
+				resp.Write([]byte(`unsupported OS`))
+				return
+			}
+			version := pathParts[2]
+			body := map[string]interface{}{
+				"protocols":             []string{"99.0"},
+				"os":                    pathParts[4],
+				"arch":                  pathParts[5],
+				"filename":              "happycloud_" + version + ".zip",
+				"shasum":                "000000000000000000000000000000000000000000000000000000000000f00d",
+				"download_url":          "/pkg/awesomesauce/happycloud_" + version + ".zip",
+				"shasums_url":           "/pkg/awesomesauce/happycloud_" + version + "_SHA256SUMS",
+				"shasums_signature_url": "/pkg/awesomesauce/happycloud_" + version + "_SHA256SUMS.sig",
+				"signing_keys": map[string]interface{}{
+					"gpg_public_keys": []map[string]interface{}{
+						{
+							"ascii_armor": getproviders.HashicorpPublicKey,
+						},
+					},
+				},
+			}
+			enc, err := json.Marshal(body)
+			if err != nil {
+				resp.WriteHeader(500)
+				resp.Write([]byte("failed to encode body"))
+			}
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			resp.Write(enc)
+		case "weaksauce/unsupported-protocol":
+			var protocols []string
+			version := pathParts[2]
+			switch version {
+			case "0.1.0":
+				protocols = []string{"1.0"}
+			case "2.0.0":
+				protocols = []string{"99.0"}
+			default:
+				protocols = []string{"5.0"}
+			}
+
+			body := map[string]interface{}{
+				"protocols":             protocols,
+				"os":                    pathParts[4],
+				"arch":                  pathParts[5],
+				"filename":              "happycloud_" + version + ".zip",
+				"shasum":                "000000000000000000000000000000000000000000000000000000000000f00d",
+				"download_url":          "/pkg/awesomesauce/happycloud_" + version + ".zip",
+				"shasums_url":           "/pkg/awesomesauce/happycloud_" + version + "_SHA256SUMS",
+				"shasums_signature_url": "/pkg/awesomesauce/happycloud_" + version + "_SHA256SUMS.sig",
+				"signing_keys": map[string]interface{}{
+					"gpg_public_keys": []map[string]interface{}{
+						{
+							"ascii_armor": getproviders.HashicorpPublicKey,
+						},
+					},
+				},
+			}
+			enc, err := json.Marshal(body)
+			if err != nil {
+				resp.WriteHeader(500)
+				resp.Write([]byte("failed to encode body"))
+			}
+			resp.Header().Set("Content-Type", "application/json")
+			resp.WriteHeader(200)
+			resp.Write(enc)
+		default:
+			resp.WriteHeader(404)
+			resp.Write([]byte(`unknown namespace/provider/version/architecture`))
+		}
+		return
+	}
+
+	resp.WriteHeader(404)
+	resp.Write([]byte(`unrecognized path scheme`))
+}
+
+// In order to be able to compare the recorded temp dir paths, we need to
+// normalize the path to match what the installer would report.
+func tmpDir(t *testing.T) string {
+	unlinked, err := filepath.EvalSymlinks(t.TempDir())
+	if err != nil {
+		t.Fatal(err)
+	}
+	return filepath.Clean(unlinked)
+}
diff --git a/v1.5.7/internal/providercache/package_install.go b/v1.5.7/internal/providercache/package_install.go
new file mode 100644
index 0000000..6838307
--- /dev/null
+++ b/v1.5.7/internal/providercache/package_install.go
@@ -0,0 +1,264 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providercache
+
+import (
+	"context"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"os"
+	"path/filepath"
+
+	getter "github.com/hashicorp/go-getter"
+
+	"github.com/hashicorp/terraform/internal/copy"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/hashicorp/terraform/internal/httpclient"
+)
+
+// We borrow the "unpack a zip file into a target directory" logic from
+// go-getter, even though we're not otherwise using go-getter here.
+// (We don't need the same flexibility as we have for modules, because
+// providers _always_ come from provider registries, which have a very
+// specific protocol and set of expectations.)
+var unzip = getter.ZipDecompressor{}
+
+func installFromHTTPURL(ctx context.Context, meta getproviders.PackageMeta, targetDir string, allowedHashes []getproviders.Hash) (*getproviders.PackageAuthenticationResult, error) {
+	url := meta.Location.String()
+
+	// When we're installing from an HTTP URL we expect the URL to refer to
+	// a zip file. We'll fetch that into a temporary file here and then
+	// delegate to installFromLocalArchive below to actually extract it.
+	// (We're not using go-getter here because its HTTP getter has a bunch
+	// of extraneous functionality we don't need or want, like indirection
+	// through X-Terraform-Get header, attempting partial fetches for
+	// files that already exist, etc.)
+
+	httpClient := httpclient.New()
+	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
+	if err != nil {
+		return nil, fmt.Errorf("invalid provider download request: %s", err)
+	}
+	resp, err := httpClient.Do(req)
+	if err != nil {
+		if ctx.Err() == context.Canceled {
+			// "context canceled" is not a user-friendly error message,
+			// so we'll return a more appropriate one here.
+			return nil, fmt.Errorf("provider download was interrupted")
+		}
+		return nil, fmt.Errorf("%s: %w", getproviders.HostFromRequest(req), err)
+	}
+	defer resp.Body.Close()
+
+	if resp.StatusCode != http.StatusOK {
+		return nil, fmt.Errorf("unsuccessful request to %s: %s", url, resp.Status)
+	}
+
+	f, err := ioutil.TempFile("", "terraform-provider")
+	if err != nil {
+		return nil, fmt.Errorf("failed to open temporary file to download from %s: %w", url, err)
+	}
+	defer f.Close()
+	defer os.Remove(f.Name())
+
+	// We'll borrow go-getter's "cancelable copy" implementation here so that
+	// the download can potentially be interrupted partway through.
+	n, err := getter.Copy(ctx, f, resp.Body)
+	if err == nil && n < resp.ContentLength {
+		err = fmt.Errorf("incorrect response size: expected %d bytes, but got %d bytes", resp.ContentLength, n)
+	}
+	if err != nil {
+		return nil, err
+	}
+
+	archiveFilename := f.Name()
+	localLocation := getproviders.PackageLocalArchive(archiveFilename)
+
+	var authResult *getproviders.PackageAuthenticationResult
+	if meta.Authentication != nil {
+		if authResult, err = meta.Authentication.AuthenticatePackage(localLocation); err != nil {
+			return authResult, err
+		}
+	}
+
+	// We can now delegate to installFromLocalArchive for extraction. To do so,
+	// we construct a new package meta description using the local archive
+	// path as the location, and skipping authentication. installFromLocalMeta
+	// is responsible for verifying that the archive matches the allowedHashes,
+	// though.
+	localMeta := getproviders.PackageMeta{
+		Provider:         meta.Provider,
+		Version:          meta.Version,
+		ProtocolVersions: meta.ProtocolVersions,
+		TargetPlatform:   meta.TargetPlatform,
+		Filename:         meta.Filename,
+		Location:         localLocation,
+		Authentication:   nil,
+	}
+	if _, err := installFromLocalArchive(ctx, localMeta, targetDir, allowedHashes); err != nil {
+		return nil, err
+	}
+	return authResult, nil
+}
+
+func installFromLocalArchive(ctx context.Context, meta getproviders.PackageMeta, targetDir string, allowedHashes []getproviders.Hash) (*getproviders.PackageAuthenticationResult, error) {
+	var authResult *getproviders.PackageAuthenticationResult
+	if meta.Authentication != nil {
+		var err error
+		if authResult, err = meta.Authentication.AuthenticatePackage(meta.Location); err != nil {
+			return nil, err
+		}
+	}
+
+	if len(allowedHashes) > 0 {
+		if matches, err := meta.MatchesAnyHash(allowedHashes); err != nil {
+			return authResult, fmt.Errorf(
+				"failed to calculate checksum for %s %s package at %s: %s",
+				meta.Provider, meta.Version, meta.Location, err,
+			)
+		} else if !matches {
+			return authResult, fmt.Errorf(
+				"the current package for %s %s doesn't match any of the checksums previously recorded in the dependency lock file; for more information: https://www.terraform.io/language/provider-checksum-verification",
+				meta.Provider, meta.Version,
+			)
+		}
+	}
+
+	filename := meta.Location.String()
+
+	// NOTE: We're not checking whether there's already a directory at
+	// targetDir with some files in it. Packages are supposed to be immutable
+	// and therefore we'll just be overwriting all of the existing files with
+	// their same contents unless something unusual is happening. If something
+	// unusual _is_ happening then this will produce something that doesn't
+	// match the allowed hashes and so our caller should catch that after
+	// we return if so.
+
+	err := unzip.Decompress(targetDir, filename, true, 0000)
+	if err != nil {
+		return authResult, err
+	}
+
+	return authResult, nil
+}
+
+// installFromLocalDir is the implementation of both installing a package from
+// a local directory source _and_ of linking a package from another cache
+// in LinkFromOtherCache, because they both do fundamentally the same
+// operation: symlink if possible, or deep-copy otherwise.
+func installFromLocalDir(ctx context.Context, meta getproviders.PackageMeta, targetDir string, allowedHashes []getproviders.Hash) (*getproviders.PackageAuthenticationResult, error) {
+	sourceDir := meta.Location.String()
+
+	absNew, err := filepath.Abs(targetDir)
+	if err != nil {
+		return nil, fmt.Errorf("failed to make target path %s absolute: %s", targetDir, err)
+	}
+	absCurrent, err := filepath.Abs(sourceDir)
+	if err != nil {
+		return nil, fmt.Errorf("failed to make source path %s absolute: %s", sourceDir, err)
+	}
+
+	// Before we do anything else, we'll do a quick check to make sure that
+	// these two paths are not pointing at the same physical directory on
+	// disk. This compares the files by their OS-level device and directory
+	// entry identifiers, not by their virtual filesystem paths.
+	if same, err := copy.SameFile(absNew, absCurrent); same {
+		return nil, fmt.Errorf("cannot install existing provider directory %s to itself", targetDir)
+	} else if err != nil {
+		return nil, fmt.Errorf("failed to determine if %s and %s are the same: %s", sourceDir, targetDir, err)
+	}
+
+	var authResult *getproviders.PackageAuthenticationResult
+	if meta.Authentication != nil {
+		// (we have this here for completeness but note that local filesystem
+		// mirrors typically don't include enough information for package
+		// authentication and so we'll rarely get in here in practice.)
+		var err error
+		if authResult, err = meta.Authentication.AuthenticatePackage(meta.Location); err != nil {
+			return nil, err
+		}
+	}
+
+	// If the caller provided at least one hash in allowedHashes then at
+	// least one of those hashes ought to match. However, for local directories
+	// in particular we can't actually verify the legacy "zh:" hash scheme
+	// because it requires access to the original .zip archive, and so as a
+	// measure of pragmatism we'll treat a set of hashes where all are "zh:"
+	// the same as no hashes at all, and let anything pass. This is definitely
+	// non-ideal but accepted for two reasons:
+	// - Packages we find on local disk can be considered a little more trusted
+	//   than packages coming from over the network, because we assume that
+	//   they were either placed intentionally by an operator or they were
+	//   automatically installed by a previous network operation that would've
+	//   itself verified the hashes.
+	// - Our installer makes a concerted effort to record at least one new-style
+	//   hash for each lock entry, so we should very rarely end up in this
+	//   situation anyway.
+	suitableHashCount := 0
+	for _, hash := range allowedHashes {
+		if !hash.HasScheme(getproviders.HashSchemeZip) {
+			suitableHashCount++
+		}
+	}
+	if suitableHashCount > 0 {
+		if matches, err := meta.MatchesAnyHash(allowedHashes); err != nil {
+			return authResult, fmt.Errorf(
+				"failed to calculate checksum for %s %s package at %s: %s",
+				meta.Provider, meta.Version, meta.Location, err,
+			)
+		} else if !matches {
+			return authResult, fmt.Errorf(
+				"the local package for %s %s doesn't match any of the checksums previously recorded in the dependency lock file (this might be because the available checksums are for packages targeting different platforms); for more information: https://www.terraform.io/language/provider-checksum-verification",
+				meta.Provider, meta.Version,
+			)
+		}
+	}
+
+	// Delete anything that's already present at this path first.
+	err = os.RemoveAll(targetDir)
+	if err != nil && !os.IsNotExist(err) {
+		return nil, fmt.Errorf("failed to remove existing %s before linking it to %s: %s", sourceDir, targetDir, err)
+	}
+
+	// We'll prefer to create a symlink if possible, but we'll fall back to
+	// a recursive copy if symlink creation fails. It could fail for a number
+	// of reasons, including being on Windows 8 without administrator
+	// privileges or being on a legacy filesystem like FAT that has no way
+	// to represent a symlink. (Generalized symlink support for Windows was
+	// introduced in a Windows 10 minor update.)
+	//
+	// We use an absolute path for the symlink to reduce the risk of it being
+	// broken by moving things around later, since the source directory is
+	// likely to be a shared directory independent on any particular target
+	// and thus we can't assume that they will move around together.
+	linkTarget := absCurrent
+
+	parentDir := filepath.Dir(absNew)
+	err = os.MkdirAll(parentDir, 0755)
+	if err != nil {
+		return nil, fmt.Errorf("failed to create parent directories leading to %s: %s", targetDir, err)
+	}
+
+	err = os.Symlink(linkTarget, absNew)
+	if err == nil {
+		// Success, then!
+		return nil, nil
+	}
+
+	// If we get down here then symlinking failed and we need a deep copy
+	// instead. To make a copy, we first need to create the target directory,
+	// which would otherwise be a symlink.
+	err = os.Mkdir(absNew, 0755)
+	if err != nil && os.IsExist(err) {
+		return nil, fmt.Errorf("failed to create directory %s: %s", absNew, err)
+	}
+	err = copy.CopyDir(absNew, absCurrent)
+	if err != nil {
+		return nil, fmt.Errorf("failed to either symlink or copy %s to %s: %s", absCurrent, absNew, err)
+	}
+
+	// If we got here then apparently our copy succeeded, so we're done.
+	return nil, nil
+}
diff --git a/v1.5.7/internal/providercache/testdata/beep-provider-other-platform/terraform-provider-beep b/v1.5.7/internal/providercache/testdata/beep-provider-other-platform/terraform-provider-beep
new file mode 100644
index 0000000..18929cd
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/beep-provider-other-platform/terraform-provider-beep
@@ -0,0 +1,7 @@
+This is not a real provider executable. It's just here to give the installer
+something to copy in some of our installer test cases.
+
+This must be different than the file of the same name in the sibling directory
+"beep-provider", because we're using this to stand in for a valid package
+that was built for a different platform than the one whose checksum is recorded
+in the lock file.
diff --git a/v1.5.7/internal/providercache/testdata/beep-provider/terraform-provider-beep b/v1.5.7/internal/providercache/testdata/beep-provider/terraform-provider-beep
new file mode 100644
index 0000000..e0841fd
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/beep-provider/terraform-provider-beep
@@ -0,0 +1,2 @@
+This is not a real provider executable. It's just here to give the installer
+something to copy in some of our installer test cases.
diff --git a/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/invalid b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/invalid
new file mode 100644
index 0000000..289663a
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/invalid
@@ -0,0 +1 @@
+This should be ignored because it doesn't follow the provider package naming scheme.
diff --git a/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip
new file mode 100644
index 0000000..68a5502
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip
@@ -0,0 +1,5 @@
+This is just a placeholder file for discovery testing, not a real provider package.
+
+This file is what we'd find for mirrors using the "packed" mirror layout,
+where the mirror maintainer can just download the packages from upstream and
+have Terraform unpack them automatically when installing.
diff --git a/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip
new file mode 100644
index 0000000..289663a
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip
@@ -0,0 +1 @@
+This should be ignored because it doesn't follow the provider package naming scheme.
diff --git a/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip
new file mode 100644
index 0000000..289663a
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip
@@ -0,0 +1 @@
+This should be ignored because it doesn't follow the provider package naming scheme.
diff --git a/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/missing/executable/2.0.0/linux_amd64/executable b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/missing/executable/2.0.0/linux_amd64/executable
new file mode 100755
index 0000000..f7a5e52
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/cachedir/registry.terraform.io/missing/executable/2.0.0/linux_amd64/executable
@@ -0,0 +1 @@
+This file represents a misnamed provider executable.
diff --git a/v1.5.7/internal/providercache/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt b/v1.5.7/internal/providercache/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt
new file mode 100644
index 0000000..8a1c7c3
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt
@@ -0,0 +1,6 @@
+Provider plugin packages are allowed to include other files such as any static
+data they need to operate, or possibly source files if the provider is written
+in an interpreted programming language.
+
+This extra file is here just to make sure that extra files don't cause any
+misbehavior during local discovery.
diff --git a/v1.5.7/internal/providercache/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud b/v1.5.7/internal/providercache/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud
new file mode 100644
index 0000000..daa9e35
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud
@@ -0,0 +1 @@
+# This is just a placeholder file for discovery testing, not a real provider plugin.
diff --git a/v1.5.7/internal/providercache/testdata/terraform-provider-null_2.1.0_linux_amd64.zip b/v1.5.7/internal/providercache/testdata/terraform-provider-null_2.1.0_linux_amd64.zip
new file mode 100644
index 0000000..4b243f2
--- /dev/null
+++ b/v1.5.7/internal/providercache/testdata/terraform-provider-null_2.1.0_linux_amd64.zip
Binary files differ
diff --git a/v1.5.7/internal/providers/addressed_types.go b/v1.5.7/internal/providers/addressed_types.go
new file mode 100644
index 0000000..6d63f3a
--- /dev/null
+++ b/v1.5.7/internal/providers/addressed_types.go
@@ -0,0 +1,36 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providers
+
+import (
+	"sort"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// AddressedTypesAbs is a helper that extracts all of the distinct provider
+// types from the given list of absolute provider configuration addresses.
+func AddressedTypesAbs(providerAddrs []addrs.AbsProviderConfig) []addrs.Provider {
+	if len(providerAddrs) == 0 {
+		return nil
+	}
+	m := map[string]addrs.Provider{}
+	for _, addr := range providerAddrs {
+		m[addr.Provider.String()] = addr.Provider
+	}
+
+	names := make([]string, 0, len(m))
+	for typeName := range m {
+		names = append(names, typeName)
+	}
+
+	sort.Strings(names) // Stable result for tests
+
+	ret := make([]addrs.Provider, len(names))
+	for i, name := range names {
+		ret[i] = m[name]
+	}
+
+	return ret
+}
diff --git a/v1.5.7/internal/providers/addressed_types_test.go b/v1.5.7/internal/providers/addressed_types_test.go
new file mode 100644
index 0000000..3a6cbc9
--- /dev/null
+++ b/v1.5.7/internal/providers/addressed_types_test.go
@@ -0,0 +1,48 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providers
+
+import (
+	"testing"
+
+	"github.com/go-test/deep"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestAddressedTypesAbs(t *testing.T) {
+	providerAddrs := []addrs.AbsProviderConfig{
+		addrs.AbsProviderConfig{
+			Module:   addrs.RootModule,
+			Provider: addrs.NewDefaultProvider("aws"),
+		},
+		addrs.AbsProviderConfig{
+			Module:   addrs.RootModule,
+			Provider: addrs.NewDefaultProvider("aws"),
+			Alias:    "foo",
+		},
+		addrs.AbsProviderConfig{
+			Module:   addrs.RootModule,
+			Provider: addrs.NewDefaultProvider("azure"),
+		},
+		addrs.AbsProviderConfig{
+			Module:   addrs.RootModule,
+			Provider: addrs.NewDefaultProvider("null"),
+		},
+		addrs.AbsProviderConfig{
+			Module:   addrs.RootModule,
+			Provider: addrs.NewDefaultProvider("null"),
+		},
+	}
+
+	got := AddressedTypesAbs(providerAddrs)
+	want := []addrs.Provider{
+		addrs.NewDefaultProvider("aws"),
+		addrs.NewDefaultProvider("azure"),
+		addrs.NewDefaultProvider("null"),
+	}
+	for _, problem := range deep.Equal(got, want) {
+		t.Error(problem)
+	}
+}
diff --git a/v1.5.7/internal/providers/doc.go b/v1.5.7/internal/providers/doc.go
new file mode 100644
index 0000000..4068da2
--- /dev/null
+++ b/v1.5.7/internal/providers/doc.go
@@ -0,0 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package providers contains the interface and primary types required to
+// implement a Terraform resource provider.
+package providers
diff --git a/v1.5.7/internal/providers/factory.go b/v1.5.7/internal/providers/factory.go
new file mode 100644
index 0000000..8e28935
--- /dev/null
+++ b/v1.5.7/internal/providers/factory.go
@@ -0,0 +1,66 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providers
+
+// Factory is a function type that creates a new instance of a resource
+// provider, or returns an error if that is impossible.
+type Factory func() (Interface, error)
+
+// FactoryFixed is a helper that creates a Factory that just returns some given
+// single provider.
+//
+// Unlike usual factories, the exact same instance is returned for each call
+// to the factory and so this must be used in only specialized situations where
+// the caller can take care to either not mutate the given provider at all
+// or to mutate it in ways that will not cause unexpected behavior for others
+// holding the same reference.
+func FactoryFixed(p Interface) Factory {
+	return func() (Interface, error) {
+		return p, nil
+	}
+}
+
+// ProviderHasResource is a helper that requests schema from the given provider
+// and checks if it has a resource type of the given name.
+//
+// This function is more expensive than it may first appear since it must
+// retrieve the entire schema from the underlying provider, and so it should
+// be used sparingly and especially not in tight loops.
+//
+// Since retrieving the provider may fail (e.g. if the provider is accessed
+// over an RPC channel that has operational problems), this function will
+// return false if the schema cannot be retrieved, under the assumption that
+// a subsequent call to do anything with the resource type would fail
+// anyway.
+func ProviderHasResource(provider Interface, typeName string) bool {
+	resp := provider.GetProviderSchema()
+	if resp.Diagnostics.HasErrors() {
+		return false
+	}
+
+	_, exists := resp.ResourceTypes[typeName]
+	return exists
+}
+
+// ProviderHasDataSource is a helper that requests schema from the given
+// provider and checks if it has a data source of the given name.
+//
+// This function is more expensive than it may first appear since it must
+// retrieve the entire schema from the underlying provider, and so it should
+// be used sparingly and especially not in tight loops.
+//
+// Since retrieving the provider may fail (e.g. if the provider is accessed
+// over an RPC channel that has operational problems), this function will
+// return false if the schema cannot be retrieved, under the assumption that
+// a subsequent call to do anything with the data source would fail
+// anyway.
+func ProviderHasDataSource(provider Interface, dataSourceName string) bool {
+	resp := provider.GetProviderSchema()
+	if resp.Diagnostics.HasErrors() {
+		return false
+	}
+
+	_, exists := resp.DataSources[dataSourceName]
+	return exists
+}
diff --git a/v1.5.7/internal/providers/provider.go b/v1.5.7/internal/providers/provider.go
new file mode 100644
index 0000000..bfa400f
--- /dev/null
+++ b/v1.5.7/internal/providers/provider.go
@@ -0,0 +1,396 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providers
+
+import (
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Interface represents the set of methods required for a complete resource
+// provider plugin.
+type Interface interface {
+	// GetSchema returns the complete schema for the provider.
+	GetProviderSchema() GetProviderSchemaResponse
+
+	// ValidateProviderConfig allows the provider to validate the configuration.
+	// The ValidateProviderConfigResponse.PreparedConfig field is unused. The
+	// final configuration is not stored in the state, and any modifications
+	// that need to be made must be made during the Configure method call.
+	ValidateProviderConfig(ValidateProviderConfigRequest) ValidateProviderConfigResponse
+
+	// ValidateResourceConfig allows the provider to validate the resource
+	// configuration values.
+	ValidateResourceConfig(ValidateResourceConfigRequest) ValidateResourceConfigResponse
+
+	// ValidateDataResourceConfig allows the provider to validate the data source
+	// configuration values.
+	ValidateDataResourceConfig(ValidateDataResourceConfigRequest) ValidateDataResourceConfigResponse
+
+	// UpgradeResourceState is called when the state loader encounters an
+	// instance state whose schema version is less than the one reported by the
+	// currently-used version of the corresponding provider, and the upgraded
+	// result is used for any further processing.
+	UpgradeResourceState(UpgradeResourceStateRequest) UpgradeResourceStateResponse
+
+	// Configure configures and initialized the provider.
+	ConfigureProvider(ConfigureProviderRequest) ConfigureProviderResponse
+
+	// Stop is called when the provider should halt any in-flight actions.
+	//
+	// Stop should not block waiting for in-flight actions to complete. It
+	// should take any action it wants and return immediately acknowledging it
+	// has received the stop request. Terraform will not make any further API
+	// calls to the provider after Stop is called.
+	//
+	// The error returned, if non-nil, is assumed to mean that signaling the
+	// stop somehow failed and that the user should expect potentially waiting
+	// a longer period of time.
+	Stop() error
+
+	// ReadResource refreshes a resource and returns its current state.
+	ReadResource(ReadResourceRequest) ReadResourceResponse
+
+	// PlanResourceChange takes the current state and proposed state of a
+	// resource, and returns the planned final state.
+	PlanResourceChange(PlanResourceChangeRequest) PlanResourceChangeResponse
+
+	// ApplyResourceChange takes the planned state for a resource, which may
+	// yet contain unknown computed values, and applies the changes returning
+	// the final state.
+	ApplyResourceChange(ApplyResourceChangeRequest) ApplyResourceChangeResponse
+
+	// ImportResourceState requests that the given resource be imported.
+	ImportResourceState(ImportResourceStateRequest) ImportResourceStateResponse
+
+	// ReadDataSource returns the data source's current state.
+	ReadDataSource(ReadDataSourceRequest) ReadDataSourceResponse
+
+	// Close shuts down the plugin process if applicable.
+	Close() error
+}
+
+type GetProviderSchemaResponse struct {
+	// Provider is the schema for the provider itself.
+	Provider Schema
+
+	// ProviderMeta is the schema for the provider's meta info in a module
+	ProviderMeta Schema
+
+	// ResourceTypes map the resource type name to that type's schema.
+	ResourceTypes map[string]Schema
+
+	// DataSources maps the data source name to that data source's schema.
+	DataSources map[string]Schema
+
+	// Diagnostics contains any warnings or errors from the method call.
+	Diagnostics tfdiags.Diagnostics
+
+	// ServerCapabilities lists optional features supported by the provider.
+	ServerCapabilities ServerCapabilities
+}
+
+// ServerCapabilities allows providers to communicate extra information
+// regarding supported protocol features. This is used to indicate availability
+// of certain forward-compatible changes which may be optional in a major
+// protocol version, but cannot be tested for directly.
+type ServerCapabilities struct {
+	// PlanDestroy signals that this provider expects to receive a
+	// PlanResourceChange call for resources that are to be destroyed.
+	PlanDestroy bool
+}
+
+type ValidateProviderConfigRequest struct {
+	// Config is the raw configuration value for the provider.
+	Config cty.Value
+}
+
+type ValidateProviderConfigResponse struct {
+	// PreparedConfig is unused and will be removed with support for plugin protocol v5.
+	PreparedConfig cty.Value
+	// Diagnostics contains any warnings or errors from the method call.
+	Diagnostics tfdiags.Diagnostics
+}
+
+type ValidateResourceConfigRequest struct {
+	// TypeName is the name of the resource type to validate.
+	TypeName string
+
+	// Config is the configuration value to validate, which may contain unknown
+	// values.
+	Config cty.Value
+}
+
+type ValidateResourceConfigResponse struct {
+	// Diagnostics contains any warnings or errors from the method call.
+	Diagnostics tfdiags.Diagnostics
+}
+
+type ValidateDataResourceConfigRequest struct {
+	// TypeName is the name of the data source type to validate.
+	TypeName string
+
+	// Config is the configuration value to validate, which may contain unknown
+	// values.
+	Config cty.Value
+}
+
+type ValidateDataResourceConfigResponse struct {
+	// Diagnostics contains any warnings or errors from the method call.
+	Diagnostics tfdiags.Diagnostics
+}
+
+type UpgradeResourceStateRequest struct {
+	// TypeName is the name of the resource type being upgraded
+	TypeName string
+
+	// Version is version of the schema that created the current state.
+	Version int64
+
+	// RawStateJSON and RawStateFlatmap contiain the state that needs to be
+	// upgraded to match the current schema version. Because the schema is
+	// unknown, this contains only the raw data as stored in the state.
+	// RawStateJSON is the current json state encoding.
+	// RawStateFlatmap is the legacy flatmap encoding.
+	// Only on of these fields may be set for the upgrade request.
+	RawStateJSON    []byte
+	RawStateFlatmap map[string]string
+}
+
+type UpgradeResourceStateResponse struct {
+	// UpgradedState is the newly upgraded resource state.
+	UpgradedState cty.Value
+
+	// Diagnostics contains any warnings or errors from the method call.
+	Diagnostics tfdiags.Diagnostics
+}
+
+type ConfigureProviderRequest struct {
+	// Terraform version is the version string from the running instance of
+	// terraform. Providers can use TerraformVersion to verify compatibility,
+	// and to store for informational purposes.
+	TerraformVersion string
+
+	// Config is the complete configuration value for the provider.
+	Config cty.Value
+}
+
+type ConfigureProviderResponse struct {
+	// Diagnostics contains any warnings or errors from the method call.
+	Diagnostics tfdiags.Diagnostics
+}
+
+type ReadResourceRequest struct {
+	// TypeName is the name of the resource type being read.
+	TypeName string
+
+	// PriorState contains the previously saved state value for this resource.
+	PriorState cty.Value
+
+	// Private is an opaque blob that will be stored in state along with the
+	// resource. It is intended only for interpretation by the provider itself.
+	Private []byte
+
+	// ProviderMeta is the configuration for the provider_meta block for the
+	// module and provider this resource belongs to. Its use is defined by
+	// each provider, and it should not be used without coordination with
+	// HashiCorp. It is considered experimental and subject to change.
+	ProviderMeta cty.Value
+}
+
+type ReadResourceResponse struct {
+	// NewState contains the current state of the resource.
+	NewState cty.Value
+
+	// Diagnostics contains any warnings or errors from the method call.
+	Diagnostics tfdiags.Diagnostics
+
+	// Private is an opaque blob that will be stored in state along with the
+	// resource. It is intended only for interpretation by the provider itself.
+	Private []byte
+}
+
+type PlanResourceChangeRequest struct {
+	// TypeName is the name of the resource type to plan.
+	TypeName string
+
+	// PriorState is the previously saved state value for this resource.
+	PriorState cty.Value
+
+	// ProposedNewState is the expected state after the new configuration is
+	// applied. This is created by directly applying the configuration to the
+	// PriorState. The provider is then responsible for applying any further
+	// changes required to create the proposed final state.
+	ProposedNewState cty.Value
+
+	// Config is the resource configuration, before being merged with the
+	// PriorState. Any value not explicitly set in the configuration will be
+	// null. Config is supplied for reference, but Provider implementations
+	// should prefer the ProposedNewState in most circumstances.
+	Config cty.Value
+
+	// PriorPrivate is the previously saved private data returned from the
+	// provider during the last apply.
+	PriorPrivate []byte
+
+	// ProviderMeta is the configuration for the provider_meta block for the
+	// module and provider this resource belongs to. Its use is defined by
+	// each provider, and it should not be used without coordination with
+	// HashiCorp. It is considered experimental and subject to change.
+	ProviderMeta cty.Value
+}
+
+type PlanResourceChangeResponse struct {
+	// PlannedState is the expected state of the resource once the current
+	// configuration is applied.
+	PlannedState cty.Value
+
+	// RequiresReplace is the list of the attributes that are requiring
+	// resource replacement.
+	RequiresReplace []cty.Path
+
+	// PlannedPrivate is an opaque blob that is not interpreted by terraform
+	// core. This will be saved and relayed back to the provider during
+	// ApplyResourceChange.
+	PlannedPrivate []byte
+
+	// Diagnostics contains any warnings or errors from the method call.
+	Diagnostics tfdiags.Diagnostics
+
+	// LegacyTypeSystem is set only if the provider is using the legacy SDK
+	// whose type system cannot be precisely mapped into the Terraform type
+	// system. We use this to bypass certain consistency checks that would
+	// otherwise fail due to this imprecise mapping. No other provider or SDK
+	// implementation is permitted to set this.
+	LegacyTypeSystem bool
+}
+
+type ApplyResourceChangeRequest struct {
+	// TypeName is the name of the resource type being applied.
+	TypeName string
+
+	// PriorState is the current state of resource.
+	PriorState cty.Value
+
+	// Planned state is the state returned from PlanResourceChange, and should
+	// represent the new state, minus any remaining computed attributes.
+	PlannedState cty.Value
+
+	// Config is the resource configuration, before being merged with the
+	// PriorState. Any value not explicitly set in the configuration will be
+	// null. Config is supplied for reference, but Provider implementations
+	// should prefer the PlannedState in most circumstances.
+	Config cty.Value
+
+	// PlannedPrivate is the same value as returned by PlanResourceChange.
+	PlannedPrivate []byte
+
+	// ProviderMeta is the configuration for the provider_meta block for the
+	// module and provider this resource belongs to. Its use is defined by
+	// each provider, and it should not be used without coordination with
+	// HashiCorp. It is considered experimental and subject to change.
+	ProviderMeta cty.Value
+}
+
+type ApplyResourceChangeResponse struct {
+	// NewState is the new complete state after applying the planned change.
+	// In the event of an error, NewState should represent the most recent
+	// known state of the resource, if it exists.
+	NewState cty.Value
+
+	// Private is an opaque blob that will be stored in state along with the
+	// resource. It is intended only for interpretation by the provider itself.
+	Private []byte
+
+	// Diagnostics contains any warnings or errors from the method call.
+	Diagnostics tfdiags.Diagnostics
+
+	// LegacyTypeSystem is set only if the provider is using the legacy SDK
+	// whose type system cannot be precisely mapped into the Terraform type
+	// system. We use this to bypass certain consistency checks that would
+	// otherwise fail due to this imprecise mapping. No other provider or SDK
+	// implementation is permitted to set this.
+	LegacyTypeSystem bool
+}
+
+type ImportResourceStateRequest struct {
+	// TypeName is the name of the resource type to be imported.
+	TypeName string
+
+	// ID is a string with which the provider can identify the resource to be
+	// imported.
+	ID string
+}
+
+type ImportResourceStateResponse struct {
+	// ImportedResources contains one or more state values related to the
+	// imported resource. It is not required that these be complete, only that
+	// there is enough identifying information for the provider to successfully
+	// update the states in ReadResource.
+	ImportedResources []ImportedResource
+
+	// Diagnostics contains any warnings or errors from the method call.
+	Diagnostics tfdiags.Diagnostics
+}
+
+// ImportedResource represents an object being imported into Terraform with the
+// help of a provider. An ImportedObject is a RemoteObject that has been read
+// by the provider's import handler but hasn't yet been committed to state.
+type ImportedResource struct {
+	// TypeName is the name of the resource type associated with the
+	// returned state. It's possible for providers to import multiple related
+	// types with a single import request.
+	TypeName string
+
+	// State is the state of the remote object being imported. This may not be
+	// complete, but must contain enough information to uniquely identify the
+	// resource.
+	State cty.Value
+
+	// Private is an opaque blob that will be stored in state along with the
+	// resource. It is intended only for interpretation by the provider itself.
+	Private []byte
+}
+
+// AsInstanceObject converts the receiving ImportedObject into a
+// ResourceInstanceObject that has status ObjectReady.
+//
+// The returned object does not know its own resource type, so the caller must
+// retain the ResourceType value from the source object if this information is
+// needed.
+//
+// The returned object also has no dependency addresses, but the caller may
+// freely modify the direct fields of the returned object without affecting
+// the receiver.
+func (ir ImportedResource) AsInstanceObject() *states.ResourceInstanceObject {
+	return &states.ResourceInstanceObject{
+		Status:  states.ObjectReady,
+		Value:   ir.State,
+		Private: ir.Private,
+	}
+}
+
+type ReadDataSourceRequest struct {
+	// TypeName is the name of the data source type to Read.
+	TypeName string
+
+	// Config is the complete configuration for the requested data source.
+	Config cty.Value
+
+	// ProviderMeta is the configuration for the provider_meta block for the
+	// module and provider this resource belongs to. Its use is defined by
+	// each provider, and it should not be used without coordination with
+	// HashiCorp. It is considered experimental and subject to change.
+	ProviderMeta cty.Value
+}
+
+type ReadDataSourceResponse struct {
+	// State is the current state of the requested data source.
+	State cty.Value
+
+	// Diagnostics contains any warnings or errors from the method call.
+	Diagnostics tfdiags.Diagnostics
+}
diff --git a/v1.5.7/internal/providers/schemas.go b/v1.5.7/internal/providers/schemas.go
new file mode 100644
index 0000000..0fc40b4
--- /dev/null
+++ b/v1.5.7/internal/providers/schemas.go
@@ -0,0 +1,65 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package providers
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+// Schemas is an overall container for all of the schemas for all configurable
+// objects defined within a particular provider.
+//
+// The schema for each individual configurable object is represented by nested
+// instances of type Schema (singular) within this data structure.
+//
+// This type used to be known as terraform.ProviderSchema, but moved out here
+// as part of our ongoing efforts to shrink down the "terraform" package.
+// There's still a type alias at the old name, but we should prefer using
+// providers.Schema in new code. However, a consequence of this transitional
+// situation is that the "terraform" package still has the responsibility for
+// constructing a providers.Schemas object based on responses from the provider
+// API; hopefully we'll continue this refactor later so that functions in this
+// package totally encapsulate the unmarshalling and include this as part of
+// providers.GetProviderSchemaResponse.
+type Schemas struct {
+	Provider      *configschema.Block
+	ProviderMeta  *configschema.Block
+	ResourceTypes map[string]*configschema.Block
+	DataSources   map[string]*configschema.Block
+
+	ResourceTypeSchemaVersions map[string]uint64
+}
+
+// SchemaForResourceType attempts to find a schema for the given mode and type.
+// Returns nil if no such schema is available.
+func (ss *Schemas) SchemaForResourceType(mode addrs.ResourceMode, typeName string) (schema *configschema.Block, version uint64) {
+	switch mode {
+	case addrs.ManagedResourceMode:
+		return ss.ResourceTypes[typeName], ss.ResourceTypeSchemaVersions[typeName]
+	case addrs.DataResourceMode:
+		// Data resources don't have schema versions right now, since state is discarded for each refresh
+		return ss.DataSources[typeName], 0
+	default:
+		// Shouldn't happen, because the above cases are comprehensive.
+		return nil, 0
+	}
+}
+
+// SchemaForResourceAddr attempts to find a schema for the mode and type from
+// the given resource address. Returns nil if no such schema is available.
+func (ss *Schemas) SchemaForResourceAddr(addr addrs.Resource) (schema *configschema.Block, version uint64) {
+	return ss.SchemaForResourceType(addr.Mode, addr.Type)
+}
+
+// Schema pairs a provider or resource schema with that schema's version.
+// This is used to be able to upgrade the schema in UpgradeResourceState.
+//
+// This describes the schema for a single object within a provider. Type
+// "Schemas" (plural) instead represents the overall collection of schemas
+// for everything within a particular provider.
+type Schema struct {
+	Version int64
+	Block   *configschema.Block
+}
diff --git a/v1.5.7/internal/provisioner-local-exec/main/main.go b/v1.5.7/internal/provisioner-local-exec/main/main.go
new file mode 100644
index 0000000..c4bab57
--- /dev/null
+++ b/v1.5.7/internal/provisioner-local-exec/main/main.go
@@ -0,0 +1,20 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	localexec "github.com/hashicorp/terraform/internal/builtin/provisioners/local-exec"
+	"github.com/hashicorp/terraform/internal/grpcwrap"
+	"github.com/hashicorp/terraform/internal/plugin"
+	"github.com/hashicorp/terraform/internal/tfplugin5"
+)
+
+func main() {
+	// Provide a binary version of the internal terraform provider for testing
+	plugin.Serve(&plugin.ServeOpts{
+		GRPCProvisionerFunc: func() tfplugin5.ProvisionerServer {
+			return grpcwrap.Provisioner(localexec.New())
+		},
+	})
+}
diff --git a/v1.5.7/internal/provisioners/doc.go b/v1.5.7/internal/provisioners/doc.go
new file mode 100644
index 0000000..5f6c18b
--- /dev/null
+++ b/v1.5.7/internal/provisioners/doc.go
@@ -0,0 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package provisioners contains the interface and primary types to implement a
+// Terraform resource provisioner.
+package provisioners
diff --git a/v1.5.7/internal/provisioners/factory.go b/v1.5.7/internal/provisioners/factory.go
new file mode 100644
index 0000000..e2d6446
--- /dev/null
+++ b/v1.5.7/internal/provisioners/factory.go
@@ -0,0 +1,22 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provisioners
+
+// Factory is a function type that creates a new instance of a resource
+// provisioner, or returns an error if that is impossible.
+type Factory func() (Interface, error)
+
+// FactoryFixed is a helper that creates a Factory that just returns some given
+// single provisioner.
+//
+// Unlike usual factories, the exact same instance is returned for each call
+// to the factory and so this must be used in only specialized situations where
+// the caller can take care to either not mutate the given provider at all
+// or to mutate it in ways that will not cause unexpected behavior for others
+// holding the same reference.
+func FactoryFixed(p Interface) Factory {
+	return func() (Interface, error) {
+		return p, nil
+	}
+}
diff --git a/v1.5.7/internal/provisioners/provisioner.go b/v1.5.7/internal/provisioners/provisioner.go
new file mode 100644
index 0000000..4673d55
--- /dev/null
+++ b/v1.5.7/internal/provisioners/provisioner.go
@@ -0,0 +1,85 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provisioners
+
+import (
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Interface is the set of methods required for a resource provisioner plugin.
+type Interface interface {
+	// GetSchema returns the schema for the provisioner configuration.
+	GetSchema() GetSchemaResponse
+
+	// ValidateProvisionerConfig allows the provisioner to validate the
+	// configuration values.
+	ValidateProvisionerConfig(ValidateProvisionerConfigRequest) ValidateProvisionerConfigResponse
+
+	// ProvisionResource runs the provisioner with provided configuration.
+	// ProvisionResource blocks until the execution is complete.
+	// If the returned diagnostics contain any errors, the resource will be
+	// left in a tainted state.
+	ProvisionResource(ProvisionResourceRequest) ProvisionResourceResponse
+
+	// Stop is called to interrupt the provisioner.
+	//
+	// Stop should not block waiting for in-flight actions to complete. It
+	// should take any action it wants and return immediately acknowledging it
+	// has received the stop request. Terraform will not make any further API
+	// calls to the provisioner after Stop is called.
+	//
+	// The error returned, if non-nil, is assumed to mean that signaling the
+	// stop somehow failed and that the user should expect potentially waiting
+	// a longer period of time.
+	Stop() error
+
+	// Close shuts down the plugin process if applicable.
+	Close() error
+}
+
+type GetSchemaResponse struct {
+	// Provisioner contains the schema for this provisioner.
+	Provisioner *configschema.Block
+
+	// Diagnostics contains any warnings or errors from the method call.
+	Diagnostics tfdiags.Diagnostics
+}
+
+// UIOutput provides the Output method for resource provisioner
+// plugins to write any output to the UI.
+//
+// Provisioners may call the Output method multiple times while Apply is in
+// progress. It is invalid to call Output after Apply returns.
+type UIOutput interface {
+	Output(string)
+}
+
+type ValidateProvisionerConfigRequest struct {
+	// Config is the complete configuration to be used for the provisioner.
+	Config cty.Value
+}
+
+type ValidateProvisionerConfigResponse struct {
+	// Diagnostics contains any warnings or errors from the method call.
+	Diagnostics tfdiags.Diagnostics
+}
+
+type ProvisionResourceRequest struct {
+	// Config is the complete provisioner configuration.
+	Config cty.Value
+
+	// Connection contains any information required to access the resource
+	// instance.
+	Connection cty.Value
+
+	// UIOutput is used to return output during the Apply operation.
+	UIOutput UIOutput
+}
+
+type ProvisionResourceResponse struct {
+	// Diagnostics contains any warnings or errors from the method call.
+	Diagnostics tfdiags.Diagnostics
+}
diff --git a/v1.5.7/internal/refactoring/move_execute.go b/v1.5.7/internal/refactoring/move_execute.go
new file mode 100644
index 0000000..9aee835
--- /dev/null
+++ b/v1.5.7/internal/refactoring/move_execute.go
@@ -0,0 +1,345 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package refactoring
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// ApplyMoves modifies in-place the given state object so that any existing
+// objects that are matched by a "from" argument of one of the move statements
+// will be moved to instead appear at the "to" argument of that statement.
+//
+// The result is a map from the unique key of each absolute address that was
+// either the source or destination of a move to a MoveResult describing
+// what happened at that address.
+//
+// ApplyMoves does not have any error situations itself, and will instead just
+// ignore any unresolvable move statements. Validation of a set of moves is
+// a separate concern applied to the configuration, because validity of
+// moves is always dependent only on the configuration, not on the state.
+//
+// ApplyMoves expects exclusive access to the given state while it's running.
+// Don't read or write any part of the state structure until ApplyMoves returns.
+func ApplyMoves(stmts []MoveStatement, state *states.State) MoveResults {
+	ret := makeMoveResults()
+
+	if len(stmts) == 0 {
+		return ret
+	}
+
+	// The methodology here is to construct a small graph of all of the move
+	// statements where the edges represent where a particular statement
+	// is either chained from or nested inside the effect of another statement.
+	// That then means we can traverse the graph in topological sort order
+	// to gradually move objects through potentially multiple moves each.
+
+	g := buildMoveStatementGraph(stmts)
+
+	// If the graph is not valid the we will not take any action at all. The
+	// separate validation step should detect this and return an error.
+	if diags := validateMoveStatementGraph(g); diags.HasErrors() {
+		log.Printf("[ERROR] ApplyMoves: %s", diags.ErrWithWarnings())
+		return ret
+	}
+
+	// The graph must be reduced in order for ReverseDepthFirstWalk to work
+	// correctly, since it is built from following edges and can skip over
+	// dependencies if there is a direct edge to a transitive dependency.
+	g.TransitiveReduction()
+
+	// The starting nodes are the ones that don't depend on any other nodes.
+	startNodes := make(dag.Set, len(stmts))
+	for _, v := range g.Vertices() {
+		if len(g.DownEdges(v)) == 0 {
+			startNodes.Add(v)
+		}
+	}
+
+	if startNodes.Len() == 0 {
+		log.Println("[TRACE] refactoring.ApplyMoves: No 'moved' statements to consider in this configuration")
+		return ret
+	}
+
+	log.Printf("[TRACE] refactoring.ApplyMoves: Processing 'moved' statements in the configuration\n%s", logging.Indent(g.String()))
+
+	recordOldAddr := func(oldAddr, newAddr addrs.AbsResourceInstance) {
+		if prevMove, exists := ret.Changes.GetOk(oldAddr); exists {
+			// If the old address was _already_ the result of a move then
+			// we'll replace that entry so that our results summarize a chain
+			// of moves into a single entry.
+			ret.Changes.Remove(oldAddr)
+			oldAddr = prevMove.From
+		}
+		ret.Changes.Put(newAddr, MoveSuccess{
+			From: oldAddr,
+			To:   newAddr,
+		})
+	}
+	recordBlockage := func(newAddr, wantedAddr addrs.AbsMoveable) {
+		ret.Blocked.Put(newAddr, MoveBlocked{
+			Wanted: wantedAddr,
+			Actual: newAddr,
+		})
+	}
+
+	for _, v := range g.ReverseTopologicalOrder() {
+		stmt := v.(*MoveStatement)
+
+		for _, ms := range state.Modules {
+			modAddr := ms.Addr
+
+			// We don't yet know that the current module is relevant, and
+			// we determine that differently for each the object kind.
+			switch kind := stmt.ObjectKind(); kind {
+			case addrs.MoveEndpointModule:
+				// For a module endpoint we just try the module address
+				// directly, and execute the moves if it matches.
+				if newAddr, matches := modAddr.MoveDestination(stmt.From, stmt.To); matches {
+					log.Printf("[TRACE] refactoring.ApplyMoves: %s has moved to %s", modAddr, newAddr)
+
+					// If we already have a module at the new address then
+					// we'll skip this move and let the existing object take
+					// priority.
+					if ms := state.Module(newAddr); ms != nil {
+						log.Printf("[WARN] Skipped moving %s to %s, because there's already another module instance at the destination", modAddr, newAddr)
+						recordBlockage(modAddr, newAddr)
+						continue
+					}
+
+					// We need to visit all of the resource instances in the
+					// module and record them individually as results.
+					for _, rs := range ms.Resources {
+						relAddr := rs.Addr.Resource
+						for key := range rs.Instances {
+							oldInst := relAddr.Instance(key).Absolute(modAddr)
+							newInst := relAddr.Instance(key).Absolute(newAddr)
+							recordOldAddr(oldInst, newInst)
+						}
+					}
+
+					state.MoveModuleInstance(modAddr, newAddr)
+					continue
+				}
+			case addrs.MoveEndpointResource:
+				// For a resource endpoint we require an exact containing
+				// module match, because by definition a matching resource
+				// cannot be nested any deeper than that.
+				if !stmt.From.SelectsModule(modAddr) {
+					continue
+				}
+
+				// We then need to search each of the resources and resource
+				// instances in the module.
+				for _, rs := range ms.Resources {
+					rAddr := rs.Addr
+					if newAddr, matches := rAddr.MoveDestination(stmt.From, stmt.To); matches {
+						log.Printf("[TRACE] refactoring.ApplyMoves: resource %s has moved to %s", rAddr, newAddr)
+
+						// If we already have a resource at the new address then
+						// we'll skip this move and let the existing object take
+						// priority.
+						if rs := state.Resource(newAddr); rs != nil {
+							log.Printf("[WARN] Skipped moving %s to %s, because there's already another resource at the destination", rAddr, newAddr)
+							recordBlockage(rAddr, newAddr)
+							continue
+						}
+
+						for key := range rs.Instances {
+							oldInst := rAddr.Instance(key)
+							newInst := newAddr.Instance(key)
+							recordOldAddr(oldInst, newInst)
+						}
+						state.MoveAbsResource(rAddr, newAddr)
+						continue
+					}
+					for key := range rs.Instances {
+						iAddr := rAddr.Instance(key)
+						if newAddr, matches := iAddr.MoveDestination(stmt.From, stmt.To); matches {
+							log.Printf("[TRACE] refactoring.ApplyMoves: resource instance %s has moved to %s", iAddr, newAddr)
+
+							// If we already have a resource instance at the new
+							// address then we'll skip this move and let the existing
+							// object take priority.
+							if is := state.ResourceInstance(newAddr); is != nil {
+								log.Printf("[WARN] Skipped moving %s to %s, because there's already another resource instance at the destination", iAddr, newAddr)
+								recordBlockage(iAddr, newAddr)
+								continue
+							}
+
+							recordOldAddr(iAddr, newAddr)
+
+							state.MoveAbsResourceInstance(iAddr, newAddr)
+							continue
+						}
+					}
+				}
+			default:
+				panic(fmt.Sprintf("unhandled move object kind %s", kind))
+			}
+		}
+	}
+
+	return ret
+}
+
+// buildMoveStatementGraph constructs a dependency graph of the given move
+// statements, where the nodes are all pointers to statements in the given
+// slice and the edges represent either chaining or nesting relationships.
+//
+// buildMoveStatementGraph doesn't do any validation of the graph, so it
+// may contain cycles and other sorts of invalidity.
+func buildMoveStatementGraph(stmts []MoveStatement) *dag.AcyclicGraph {
+	g := &dag.AcyclicGraph{}
+	for i := range stmts {
+		// The graph nodes are pointers to the actual statements directly.
+		g.Add(&stmts[i])
+	}
+
+	// Now we'll add the edges representing chaining and nesting relationships.
+	// We assume that a reasonable configuration will have at most tens of
+	// move statements and thus this N*M algorithm is acceptable.
+	for dependerI := range stmts {
+		depender := &stmts[dependerI]
+		for dependeeI := range stmts {
+			if dependerI == dependeeI {
+				// skip comparing the statement to itself
+				continue
+			}
+			dependee := &stmts[dependeeI]
+
+			if statementDependsOn(depender, dependee) {
+				g.Connect(dag.BasicEdge(depender, dependee))
+			}
+		}
+	}
+
+	return g
+}
+
+// statementDependsOn returns true if statement a depends on statement b;
+// i.e. statement b must be executed before statement a.
+func statementDependsOn(a, b *MoveStatement) bool {
+	// chain-able moves are simple, as on the destination of one move could be
+	// equal to the source of another.
+	if a.From.CanChainFrom(b.To) {
+		return true
+	}
+
+	// Statement nesting in more complex, as we have 8 possible combinations to
+	// assess. Here we list all combinations, along with the statement which
+	// must be executed first when one address is nested within another.
+	// A.From  IsNestedWithin  B.From => A
+	// A.From  IsNestedWithin  B.To   => B
+	// A.To    IsNestedWithin  B.From => A
+	// A.To    IsNestedWithin  B.To   => B
+	// B.From  IsNestedWithin  A.From => B
+	// B.From  IsNestedWithin  A.To   => A
+	// B.To    IsNestedWithin  A.From => B
+	// B.To    IsNestedWithin  A.To   => A
+	//
+	// Since we are only interested in checking if A depends on B, we only need
+	// to check the 4 possibilities above which result in B being executed
+	// first. If we're there's no dependency at all we can return immediately.
+	if !(a.From.NestedWithin(b.To) || a.To.NestedWithin(b.To) ||
+		b.From.NestedWithin(a.From) || b.To.NestedWithin(a.From)) {
+		return false
+	}
+
+	// If a nested move has a dependency, we need to rule out the possibility
+	// that this is a move inside a module only changing indexes. If an
+	// ancestor module is only changing the index of a nested module, any
+	// nested move statements are going to match both the From and To address
+	// when the base name is not changing, causing a cycle in the order of
+	// operations.
+
+	// if A is not declared in an ancestor module, then we can't be nested
+	// within a module index change.
+	if len(a.To.Module()) >= len(b.To.Module()) {
+		return true
+	}
+	// We only want the nested move statement to depend on the outer module
+	// move, so we only test this in the reverse direction.
+	if a.From.IsModuleReIndex(a.To) {
+		return false
+	}
+
+	return true
+}
+
+// MoveResults describes the outcome of an ApplyMoves call.
+type MoveResults struct {
+	// Changes is a map from the unique keys of the final new resource
+	// instance addresses to an object describing what changed.
+	//
+	// This includes one entry for each resource instance address that was
+	// the destination of a move statement. It doesn't include resource
+	// instances that were not affected by moves at all, but it does include
+	// resource instance addresses that were "blocked" (also recorded in
+	// BlockedAddrs) if and only if they were able to move at least
+	// partially along a chain before being blocked.
+	//
+	// In the return value from ApplyMoves, all of the keys are guaranteed to
+	// be unique keys derived from addrs.AbsResourceInstance values.
+	Changes addrs.Map[addrs.AbsResourceInstance, MoveSuccess]
+
+	// Blocked is a map from the unique keys of the final new
+	// resource instances addresses to information about where they "wanted"
+	// to move, but were blocked by a pre-existing object at the same address.
+	//
+	// "Blocking" can arise in unusual situations where multiple points along
+	// a move chain were already bound to objects, and thus only one of them
+	// can actually adopt the final position in the chain. It can also
+	// occur in other similar situations, such as if a configuration contains
+	// a move of an entire module and a move of an individual resource into
+	// that module, such that the individual resource would collide with a
+	// resource in the whole module that was moved.
+	//
+	// In the return value from ApplyMoves, all of the keys are guaranteed to
+	// be unique keys derived from values of addrs.AbsMoveable types.
+	Blocked addrs.Map[addrs.AbsMoveable, MoveBlocked]
+}
+
+func makeMoveResults() MoveResults {
+	return MoveResults{
+		Changes: addrs.MakeMap[addrs.AbsResourceInstance, MoveSuccess](),
+		Blocked: addrs.MakeMap[addrs.AbsMoveable, MoveBlocked](),
+	}
+}
+
+type MoveSuccess struct {
+	From addrs.AbsResourceInstance
+	To   addrs.AbsResourceInstance
+}
+
+type MoveBlocked struct {
+	Wanted addrs.AbsMoveable
+	Actual addrs.AbsMoveable
+}
+
+// AddrMoved returns true if and only if the given resource instance moved to
+// a new address in the ApplyMoves call that the receiver is describing.
+//
+// If AddrMoved returns true, you can pass the same address to method OldAddr
+// to find its original address prior to moving.
+func (rs MoveResults) AddrMoved(newAddr addrs.AbsResourceInstance) bool {
+	return rs.Changes.Has(newAddr)
+}
+
+// OldAddr returns the old address of the given resource instance address, or
+// just returns back the same address if the given instance wasn't affected by
+// any move statements.
+func (rs MoveResults) OldAddr(newAddr addrs.AbsResourceInstance) addrs.AbsResourceInstance {
+	change, ok := rs.Changes.GetOk(newAddr)
+	if !ok {
+		return newAddr
+	}
+	return change.From
+}
diff --git a/v1.5.7/internal/refactoring/move_execute_test.go b/v1.5.7/internal/refactoring/move_execute_test.go
new file mode 100644
index 0000000..23f4227
--- /dev/null
+++ b/v1.5.7/internal/refactoring/move_execute_test.go
@@ -0,0 +1,693 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package refactoring
+
+import (
+	"fmt"
+	"sort"
+	"strings"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestApplyMoves(t *testing.T) {
+	providerAddr := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule,
+		Provider: addrs.MustParseProviderSourceString("example.com/foo/bar"),
+	}
+
+	mustParseInstAddr := func(s string) addrs.AbsResourceInstance {
+		addr, err := addrs.ParseAbsResourceInstanceStr(s)
+		if err != nil {
+			t.Fatal(err)
+		}
+		return addr
+	}
+
+	emptyResults := makeMoveResults()
+
+	tests := map[string]struct {
+		Stmts []MoveStatement
+		State *states.State
+
+		WantResults       MoveResults
+		WantInstanceAddrs []string
+	}{
+		"no moves and empty state": {
+			[]MoveStatement{},
+			states.NewState(),
+			emptyResults,
+			nil,
+		},
+		"no moves": {
+			[]MoveStatement{},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("foo.from"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			emptyResults,
+			[]string{
+				`foo.from`,
+			},
+		},
+		"single move of whole singleton resource": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "foo.from", "foo.to"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("foo.from"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				Changes: addrs.MakeMap(
+					addrs.MakeMapElem(mustParseInstAddr("foo.to"), MoveSuccess{
+						From: mustParseInstAddr("foo.from"),
+						To:   mustParseInstAddr("foo.to"),
+					}),
+				),
+				Blocked: emptyResults.Blocked,
+			},
+			[]string{
+				`foo.to`,
+			},
+		},
+		"single move of whole 'count' resource": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "foo.from", "foo.to"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("foo.from[0]"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				Changes: addrs.MakeMap(
+					addrs.MakeMapElem(mustParseInstAddr("foo.to[0]"), MoveSuccess{
+						From: mustParseInstAddr("foo.from[0]"),
+						To:   mustParseInstAddr("foo.to[0]"),
+					}),
+				),
+				Blocked: emptyResults.Blocked,
+			},
+			[]string{
+				`foo.to[0]`,
+			},
+		},
+		"chained move of whole singleton resource": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "foo.from", "foo.mid"),
+				testMoveStatement(t, "", "foo.mid", "foo.to"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("foo.from"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				Changes: addrs.MakeMap(
+					addrs.MakeMapElem(mustParseInstAddr("foo.to"), MoveSuccess{
+						From: mustParseInstAddr("foo.from"),
+						To:   mustParseInstAddr("foo.to"),
+					}),
+				),
+				Blocked: emptyResults.Blocked,
+			},
+			[]string{
+				`foo.to`,
+			},
+		},
+
+		"move whole resource into module": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "foo.from", "module.boo.foo.to"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("foo.from[0]"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				Changes: addrs.MakeMap(
+					addrs.MakeMapElem(mustParseInstAddr("module.boo.foo.to[0]"), MoveSuccess{
+						From: mustParseInstAddr("foo.from[0]"),
+						To:   mustParseInstAddr("module.boo.foo.to[0]"),
+					}),
+				),
+				Blocked: emptyResults.Blocked,
+			},
+			[]string{
+				`module.boo.foo.to[0]`,
+			},
+		},
+
+		"move resource instance between modules": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "module.boo.foo.from[0]", "module.bar[0].foo.to[0]"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("module.boo.foo.from[0]"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				Changes: addrs.MakeMap(
+					addrs.MakeMapElem(mustParseInstAddr("module.bar[0].foo.to[0]"), MoveSuccess{
+						From: mustParseInstAddr("module.boo.foo.from[0]"),
+						To:   mustParseInstAddr("module.bar[0].foo.to[0]"),
+					}),
+				),
+				Blocked: emptyResults.Blocked,
+			},
+			[]string{
+				`module.bar[0].foo.to[0]`,
+			},
+		},
+
+		"module move with child module": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "module.boo", "module.bar"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("module.boo.foo.from"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("module.boo.module.hoo.foo.from"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				Changes: addrs.MakeMap(
+					addrs.MakeMapElem(mustParseInstAddr("module.bar.foo.from"), MoveSuccess{
+						From: mustParseInstAddr("module.boo.foo.from"),
+						To:   mustParseInstAddr("module.bar.foo.from"),
+					}),
+					addrs.MakeMapElem(mustParseInstAddr("module.bar.module.hoo.foo.from"), MoveSuccess{
+						From: mustParseInstAddr("module.boo.module.hoo.foo.from"),
+						To:   mustParseInstAddr("module.bar.module.hoo.foo.from"),
+					}),
+				),
+				Blocked: emptyResults.Blocked,
+			},
+			[]string{
+				`module.bar.foo.from`,
+				`module.bar.module.hoo.foo.from`,
+			},
+		},
+
+		"move whole single module to indexed module": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "module.boo", "module.bar[0]"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("module.boo.foo.from[0]"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				Changes: addrs.MakeMap(
+					addrs.MakeMapElem(mustParseInstAddr("module.bar[0].foo.from[0]"), MoveSuccess{
+						From: mustParseInstAddr("module.boo.foo.from[0]"),
+						To:   mustParseInstAddr("module.bar[0].foo.from[0]"),
+					}),
+				),
+				Blocked: emptyResults.Blocked,
+			},
+			[]string{
+				`module.bar[0].foo.from[0]`,
+			},
+		},
+
+		"move whole module to indexed module and move instance chained": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "module.boo", "module.bar[0]"),
+				testMoveStatement(t, "bar", "foo.from[0]", "foo.to[0]"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("module.boo.foo.from[0]"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				Changes: addrs.MakeMap(
+					addrs.MakeMapElem(mustParseInstAddr("module.bar[0].foo.to[0]"), MoveSuccess{
+						From: mustParseInstAddr("module.boo.foo.from[0]"),
+						To:   mustParseInstAddr("module.bar[0].foo.to[0]"),
+					}),
+				),
+				Blocked: emptyResults.Blocked,
+			},
+			[]string{
+				`module.bar[0].foo.to[0]`,
+			},
+		},
+
+		"move instance to indexed module and instance chained": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "module.boo.foo.from[0]", "module.bar[0].foo.from[0]"),
+				testMoveStatement(t, "bar", "foo.from[0]", "foo.to[0]"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("module.boo.foo.from[0]"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				Changes: addrs.MakeMap(
+					addrs.MakeMapElem(mustParseInstAddr("module.bar[0].foo.to[0]"), MoveSuccess{
+						From: mustParseInstAddr("module.boo.foo.from[0]"),
+						To:   mustParseInstAddr("module.bar[0].foo.to[0]"),
+					}),
+				),
+				Blocked: emptyResults.Blocked,
+			},
+			[]string{
+				`module.bar[0].foo.to[0]`,
+			},
+		},
+
+		"move module instance to already-existing module instance": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "module.bar[0]", "module.boo"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("module.bar[0].foo.from"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("module.boo.foo.to[0]"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				// Nothing moved, because the module.b address is already
+				// occupied by another module.
+				Changes: emptyResults.Changes,
+				Blocked: addrs.MakeMap(
+					addrs.MakeMapElem[addrs.AbsMoveable](
+						mustParseInstAddr("module.bar[0].foo.from").Module,
+						MoveBlocked{
+							Wanted: mustParseInstAddr("module.boo.foo.to[0]").Module,
+							Actual: mustParseInstAddr("module.bar[0].foo.from").Module,
+						},
+					),
+				),
+			},
+			[]string{
+				`module.bar[0].foo.from`,
+				`module.boo.foo.to[0]`,
+			},
+		},
+
+		"move resource to already-existing resource": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "foo.from", "foo.to"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("foo.from"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("foo.to"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				// Nothing moved, because the from.to address is already
+				// occupied by another resource.
+				Changes: emptyResults.Changes,
+				Blocked: addrs.MakeMap(
+					addrs.MakeMapElem[addrs.AbsMoveable](
+						mustParseInstAddr("foo.from").ContainingResource(),
+						MoveBlocked{
+							Wanted: mustParseInstAddr("foo.to").ContainingResource(),
+							Actual: mustParseInstAddr("foo.from").ContainingResource(),
+						},
+					),
+				),
+			},
+			[]string{
+				`foo.from`,
+				`foo.to`,
+			},
+		},
+
+		"move resource instance to already-existing resource instance": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "foo.from", "foo.to[0]"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("foo.from"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("foo.to[0]"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				// Nothing moved, because the from.to[0] address is already
+				// occupied by another resource instance.
+				Changes: emptyResults.Changes,
+				Blocked: addrs.MakeMap(
+					addrs.MakeMapElem[addrs.AbsMoveable](
+						mustParseInstAddr("foo.from"),
+						MoveBlocked{
+							Wanted: mustParseInstAddr("foo.to[0]"),
+							Actual: mustParseInstAddr("foo.from"),
+						},
+					),
+				),
+			},
+			[]string{
+				`foo.from`,
+				`foo.to[0]`,
+			},
+		},
+		"move resource and containing module": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "module.boo", "module.bar[0]"),
+				testMoveStatement(t, "boo", "foo.from", "foo.to"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("module.boo.foo.from"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				Changes: addrs.MakeMap(
+					addrs.MakeMapElem(mustParseInstAddr("module.bar[0].foo.to"), MoveSuccess{
+						From: mustParseInstAddr("module.boo.foo.from"),
+						To:   mustParseInstAddr("module.bar[0].foo.to"),
+					}),
+				),
+				Blocked: emptyResults.Blocked,
+			},
+			[]string{
+				`module.bar[0].foo.to`,
+			},
+		},
+
+		"move module and then move resource into it": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "module.bar[0]", "module.boo"),
+				testMoveStatement(t, "", "foo.from", "module.boo.foo.from"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("module.bar[0].foo.to"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("foo.from"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				Changes: addrs.MakeMap(
+					addrs.MakeMapElem(mustParseInstAddr("module.boo.foo.from"), MoveSuccess{
+						mustParseInstAddr("foo.from"),
+						mustParseInstAddr("module.boo.foo.from"),
+					}),
+					addrs.MakeMapElem(mustParseInstAddr("module.boo.foo.to"), MoveSuccess{
+						mustParseInstAddr("module.bar[0].foo.to"),
+						mustParseInstAddr("module.boo.foo.to"),
+					}),
+				),
+				Blocked: emptyResults.Blocked,
+			},
+			[]string{
+				`module.boo.foo.from`,
+				`module.boo.foo.to`,
+			},
+		},
+
+		"move resources into module and then move module": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "foo.from", "module.boo.foo.to"),
+				testMoveStatement(t, "", "bar.from", "module.boo.bar.to"),
+				testMoveStatement(t, "", "module.boo", "module.bar[0]"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("foo.from"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("bar.from"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				Changes: addrs.MakeMap(
+					addrs.MakeMapElem(mustParseInstAddr("module.bar[0].foo.to"), MoveSuccess{
+						mustParseInstAddr("foo.from"),
+						mustParseInstAddr("module.bar[0].foo.to"),
+					}),
+					addrs.MakeMapElem(mustParseInstAddr("module.bar[0].bar.to"), MoveSuccess{
+						mustParseInstAddr("bar.from"),
+						mustParseInstAddr("module.bar[0].bar.to"),
+					}),
+				),
+				Blocked: emptyResults.Blocked,
+			},
+			[]string{
+				`module.bar[0].bar.to`,
+				`module.bar[0].foo.to`,
+			},
+		},
+
+		"module move collides with resource move": {
+			[]MoveStatement{
+				testMoveStatement(t, "", "module.bar[0]", "module.boo"),
+				testMoveStatement(t, "", "foo.from", "module.boo.foo.from"),
+			},
+			states.BuildState(func(s *states.SyncState) {
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("module.bar[0].foo.from"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+				s.SetResourceInstanceCurrent(
+					mustParseInstAddr("foo.from"),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{}`),
+					},
+					providerAddr,
+				)
+			}),
+			MoveResults{
+				Changes: addrs.MakeMap(
+					addrs.MakeMapElem(mustParseInstAddr("module.boo.foo.from"), MoveSuccess{
+						mustParseInstAddr("module.bar[0].foo.from"),
+						mustParseInstAddr("module.boo.foo.from"),
+					}),
+				),
+				Blocked: addrs.MakeMap(
+					addrs.MakeMapElem[addrs.AbsMoveable](
+						mustParseInstAddr("foo.from").ContainingResource(),
+						MoveBlocked{
+							Actual: mustParseInstAddr("foo.from").ContainingResource(),
+							Wanted: mustParseInstAddr("module.boo.foo.from").ContainingResource(),
+						},
+					),
+				),
+			},
+			[]string{
+				`foo.from`,
+				`module.boo.foo.from`,
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			var stmtsBuf strings.Builder
+			for _, stmt := range test.Stmts {
+				fmt.Fprintf(&stmtsBuf, "• from: %s\n  to:   %s\n", stmt.From, stmt.To)
+			}
+			t.Logf("move statements:\n%s", stmtsBuf.String())
+
+			t.Logf("resource instances in prior state:\n%s", spew.Sdump(allResourceInstanceAddrsInState(test.State)))
+
+			state := test.State.DeepCopy() // don't modify the test case in-place
+			gotResults := ApplyMoves(test.Stmts, state)
+
+			if diff := cmp.Diff(test.WantResults, gotResults); diff != "" {
+				t.Errorf("wrong results\n%s", diff)
+			}
+
+			gotInstAddrs := allResourceInstanceAddrsInState(state)
+			if diff := cmp.Diff(test.WantInstanceAddrs, gotInstAddrs); diff != "" {
+				t.Errorf("wrong resource instances in final state\n%s", diff)
+			}
+		})
+	}
+}
+
+func testMoveStatement(t *testing.T, module string, from string, to string) MoveStatement {
+	t.Helper()
+
+	moduleAddr := addrs.RootModule
+	if len(module) != 0 {
+		moduleAddr = addrs.Module(strings.Split(module, "."))
+	}
+
+	fromTraversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(from), "from", hcl.InitialPos)
+	if hclDiags.HasErrors() {
+		t.Fatalf("invalid 'from' argument: %s", hclDiags.Error())
+	}
+	fromAddr, diags := addrs.ParseMoveEndpoint(fromTraversal)
+	if diags.HasErrors() {
+		t.Fatalf("invalid 'from' argument: %s", diags.Err().Error())
+	}
+	toTraversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(to), "to", hcl.InitialPos)
+	if diags.HasErrors() {
+		t.Fatalf("invalid 'to' argument: %s", hclDiags.Error())
+	}
+	toAddr, diags := addrs.ParseMoveEndpoint(toTraversal)
+	if diags.HasErrors() {
+		t.Fatalf("invalid 'from' argument: %s", diags.Err().Error())
+	}
+
+	fromInModule, toInModule := addrs.UnifyMoveEndpoints(moduleAddr, fromAddr, toAddr)
+	if fromInModule == nil || toInModule == nil {
+		t.Fatalf("incompatible endpoints")
+	}
+
+	return MoveStatement{
+		From: fromInModule,
+		To:   toInModule,
+
+		// DeclRange not populated because it's unimportant for our tests
+	}
+}
+
+func allResourceInstanceAddrsInState(state *states.State) []string {
+	var ret []string
+	for _, ms := range state.Modules {
+		for _, rs := range ms.Resources {
+			for key := range rs.Instances {
+				ret = append(ret, rs.Addr.Instance(key).String())
+			}
+		}
+	}
+	sort.Strings(ret)
+	return ret
+}
diff --git a/v1.5.7/internal/refactoring/move_statement.go b/v1.5.7/internal/refactoring/move_statement.go
new file mode 100644
index 0000000..442501e
--- /dev/null
+++ b/v1.5.7/internal/refactoring/move_statement.go
@@ -0,0 +1,189 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package refactoring
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+type MoveStatement struct {
+	From, To  *addrs.MoveEndpointInModule
+	DeclRange tfdiags.SourceRange
+
+	// Implied is true for statements produced by ImpliedMoveStatements, and
+	// false for statements produced by FindMoveStatements.
+	//
+	// An "implied" statement is one that has no explicit "moved" block in
+	// the configuration and was instead generated automatically based on a
+	// comparison between current configuration and previous run state.
+	// For implied statements, the DeclRange field contains the source location
+	// of something in the source code that implied the statement, in which
+	// case it would probably be confusing to show that source range to the
+	// user, e.g. in an error message, without clearly mentioning that it's
+	// related to an implied move statement.
+	Implied bool
+}
+
+// FindMoveStatements recurses through the modules of the given configuration
+// and returns a flat set of all "moved" blocks defined within, in a
+// deterministic but undefined order.
+func FindMoveStatements(rootCfg *configs.Config) []MoveStatement {
+	return findMoveStatements(rootCfg, nil)
+}
+
+func findMoveStatements(cfg *configs.Config, into []MoveStatement) []MoveStatement {
+	modAddr := cfg.Path
+	for _, mc := range cfg.Module.Moved {
+		fromAddr, toAddr := addrs.UnifyMoveEndpoints(modAddr, mc.From, mc.To)
+		if fromAddr == nil || toAddr == nil {
+			// Invalid combination should've been caught during original
+			// configuration decoding, in the configs package.
+			panic(fmt.Sprintf("incompatible move endpoints in %s", mc.DeclRange))
+		}
+
+		into = append(into, MoveStatement{
+			From:      fromAddr,
+			To:        toAddr,
+			DeclRange: tfdiags.SourceRangeFromHCL(mc.DeclRange),
+			Implied:   false,
+		})
+	}
+
+	for _, childCfg := range cfg.Children {
+		into = findMoveStatements(childCfg, into)
+	}
+
+	return into
+}
+
+// ImpliedMoveStatements compares addresses in the given state with addresses
+// in the given configuration and potentially returns additional MoveStatement
+// objects representing moves we infer automatically, even though they aren't
+// explicitly recorded in the configuration.
+//
+// We do this primarily for backward compatibility with behaviors of Terraform
+// versions prior to introducing explicit "moved" blocks. Specifically, this
+// function aims to achieve the same result as the "NodeCountBoundary"
+// heuristic from Terraform v1.0 and earlier, where adding or removing the
+// "count" meta-argument from an already-created resource can automatically
+// preserve the zeroth or the NoKey instance, depending on the direction of
+// the change. We do this only for resources that aren't mentioned already
+// in at least one explicit move statement.
+//
+// As with the previous-version heuristics it replaces, this is a best effort
+// and doesn't handle all situations. An explicit move statement is always
+// preferred, but our goal here is to match exactly the same cases that the
+// old heuristic would've matched, to retain compatibility for existing modules.
+//
+// We should think very hard before adding any _new_ implication rules for
+// moved statements.
+func ImpliedMoveStatements(rootCfg *configs.Config, prevRunState *states.State, explicitStmts []MoveStatement) []MoveStatement {
+	return impliedMoveStatements(rootCfg, prevRunState, explicitStmts, nil)
+}
+
+func impliedMoveStatements(cfg *configs.Config, prevRunState *states.State, explicitStmts []MoveStatement, into []MoveStatement) []MoveStatement {
+	modAddr := cfg.Path
+
+	// There can be potentially many instances of the module, so we need
+	// to consider each of them separately.
+	for _, modState := range prevRunState.ModuleInstances(modAddr) {
+		// What we're looking for here is either a no-key resource instance
+		// where the configuration has count set or a zero-key resource
+		// instance where the configuration _doesn't_ have count set.
+		// If so, we'll generate a statement replacing no-key with zero-key or
+		// vice-versa.
+		for _, rState := range modState.Resources {
+			rAddr := rState.Addr
+			rCfg := cfg.Module.ResourceByAddr(rAddr.Resource)
+			if rCfg == nil {
+				// If there's no configuration at all then there can't be any
+				// automatic move fixup to do.
+				continue
+			}
+			approxSrcRange := tfdiags.SourceRangeFromHCL(rCfg.DeclRange)
+
+			// NOTE: We're intentionally not checking to see whether the
+			// "to" addresses in our implied statements already have
+			// instances recorded in state, because ApplyMoves should
+			// deal with such conflicts in a deterministic way for both
+			// explicit and implicit moves, and we'd rather have that
+			// handled all in one place.
+
+			var fromKey, toKey addrs.InstanceKey
+
+			switch {
+			case rCfg.Count != nil:
+				// If we have a count expression then we'll use _that_ as
+				// a slightly-more-precise approximate source range.
+				approxSrcRange = tfdiags.SourceRangeFromHCL(rCfg.Count.Range())
+
+				if riState := rState.Instances[addrs.NoKey]; riState != nil {
+					fromKey = addrs.NoKey
+					toKey = addrs.IntKey(0)
+				}
+			case rCfg.Count == nil && rCfg.ForEach == nil: // no repetition at all
+				if riState := rState.Instances[addrs.IntKey(0)]; riState != nil {
+					fromKey = addrs.IntKey(0)
+					toKey = addrs.NoKey
+				}
+			}
+
+			if fromKey != toKey {
+				// We mustn't generate an impied statement if the user already
+				// wrote an explicit statement referring to this resource,
+				// because they may wish to select an instance key other than
+				// zero as the one to retain.
+				if !haveMoveStatementForResource(rAddr, explicitStmts) {
+					into = append(into, MoveStatement{
+						From:      addrs.ImpliedMoveStatementEndpoint(rAddr.Instance(fromKey), approxSrcRange),
+						To:        addrs.ImpliedMoveStatementEndpoint(rAddr.Instance(toKey), approxSrcRange),
+						DeclRange: approxSrcRange,
+						Implied:   true,
+					})
+				}
+			}
+		}
+	}
+
+	for _, childCfg := range cfg.Children {
+		into = impliedMoveStatements(childCfg, prevRunState, explicitStmts, into)
+	}
+
+	return into
+}
+
+func (s *MoveStatement) ObjectKind() addrs.MoveEndpointKind {
+	// addrs.UnifyMoveEndpoints guarantees that both of our addresses have
+	// the same kind, so we can just arbitrary use From and assume To will
+	// match it.
+	return s.From.ObjectKind()
+}
+
+// Name is used internally for displaying the statement graph
+func (s *MoveStatement) Name() string {
+	return fmt.Sprintf("%s->%s", s.From, s.To)
+}
+
+func haveMoveStatementForResource(addr addrs.AbsResource, stmts []MoveStatement) bool {
+	// This is not a particularly optimal way to answer this question,
+	// particularly since our caller calls this function in a loop already,
+	// but we expect the total number of explicit statements to be small
+	// in any reasonable Terraform configuration and so a more complicated
+	// approach wouldn't be justified here.
+
+	for _, stmt := range stmts {
+		if stmt.From.SelectsResource(addr) {
+			return true
+		}
+		if stmt.To.SelectsResource(addr) {
+			return true
+		}
+	}
+	return false
+}
diff --git a/v1.5.7/internal/refactoring/move_statement_test.go b/v1.5.7/internal/refactoring/move_statement_test.go
new file mode 100644
index 0000000..410c2fb
--- /dev/null
+++ b/v1.5.7/internal/refactoring/move_statement_test.go
@@ -0,0 +1,193 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package refactoring
+
+import (
+	"sort"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestImpliedMoveStatements(t *testing.T) {
+	resourceAddr := func(name string) addrs.AbsResource {
+		return addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "foo",
+			Name: name,
+		}.Absolute(addrs.RootModuleInstance)
+	}
+
+	nestedResourceAddr := func(mod, name string) addrs.AbsResource {
+		return addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "foo",
+			Name: name,
+		}.Absolute(addrs.RootModuleInstance.Child(mod, addrs.NoKey))
+	}
+
+	instObjState := func() *states.ResourceInstanceObjectSrc {
+		return &states.ResourceInstanceObjectSrc{}
+	}
+	providerAddr := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule,
+		Provider: addrs.MustParseProviderSourceString("hashicorp/foo"),
+	}
+
+	rootCfg, _ := loadRefactoringFixture(t, "testdata/move-statement-implied")
+	prevRunState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			resourceAddr("formerly_count").Instance(addrs.IntKey(0)),
+			instObjState(),
+			providerAddr,
+		)
+		s.SetResourceInstanceCurrent(
+			resourceAddr("formerly_count").Instance(addrs.IntKey(1)),
+			instObjState(),
+			providerAddr,
+		)
+		s.SetResourceInstanceCurrent(
+			resourceAddr("now_count").Instance(addrs.NoKey),
+			instObjState(),
+			providerAddr,
+		)
+		s.SetResourceInstanceCurrent(
+			resourceAddr("formerly_count_explicit").Instance(addrs.IntKey(0)),
+			instObjState(),
+			providerAddr,
+		)
+		s.SetResourceInstanceCurrent(
+			resourceAddr("formerly_count_explicit").Instance(addrs.IntKey(1)),
+			instObjState(),
+			providerAddr,
+		)
+		s.SetResourceInstanceCurrent(
+			resourceAddr("now_count_explicit").Instance(addrs.NoKey),
+			instObjState(),
+			providerAddr,
+		)
+		s.SetResourceInstanceCurrent(
+			resourceAddr("now_for_each_formerly_count").Instance(addrs.IntKey(0)),
+			instObjState(),
+			providerAddr,
+		)
+		s.SetResourceInstanceCurrent(
+			resourceAddr("now_for_each_formerly_no_count").Instance(addrs.NoKey),
+			instObjState(),
+			providerAddr,
+		)
+
+		// This "ambiguous" resource is representing a rare but possible
+		// situation where we end up having a mixture of different index
+		// types in the state at the same time. The main way to get into
+		// this state would be to remove "count = 1" and then have the
+		// provider fail to destroy the zero-key instance even though we
+		// already created the no-key instance. Users can also get here
+		// by using "terraform state mv" in weird ways.
+		s.SetResourceInstanceCurrent(
+			resourceAddr("ambiguous").Instance(addrs.NoKey),
+			instObjState(),
+			providerAddr,
+		)
+		s.SetResourceInstanceCurrent(
+			resourceAddr("ambiguous").Instance(addrs.IntKey(0)),
+			instObjState(),
+			providerAddr,
+		)
+
+		// Add two resource nested in a module to ensure we find these
+		// recursively.
+		s.SetResourceInstanceCurrent(
+			nestedResourceAddr("child", "formerly_count").Instance(addrs.IntKey(0)),
+			instObjState(),
+			providerAddr,
+		)
+		s.SetResourceInstanceCurrent(
+			nestedResourceAddr("child", "now_count").Instance(addrs.NoKey),
+			instObjState(),
+			providerAddr,
+		)
+	})
+
+	explicitStmts := FindMoveStatements(rootCfg)
+	got := ImpliedMoveStatements(rootCfg, prevRunState, explicitStmts)
+	want := []MoveStatement{
+		{
+			From:    addrs.ImpliedMoveStatementEndpoint(resourceAddr("formerly_count").Instance(addrs.IntKey(0)), tfdiags.SourceRange{}),
+			To:      addrs.ImpliedMoveStatementEndpoint(resourceAddr("formerly_count").Instance(addrs.NoKey), tfdiags.SourceRange{}),
+			Implied: true,
+			DeclRange: tfdiags.SourceRange{
+				Filename: "testdata/move-statement-implied/move-statement-implied.tf",
+				Start:    tfdiags.SourcePos{Line: 5, Column: 1, Byte: 180},
+				End:      tfdiags.SourcePos{Line: 5, Column: 32, Byte: 211},
+			},
+		},
+
+		// Found implied moves in a nested module, ignoring the explicit moves
+		{
+			From:    addrs.ImpliedMoveStatementEndpoint(nestedResourceAddr("child", "formerly_count").Instance(addrs.IntKey(0)), tfdiags.SourceRange{}),
+			To:      addrs.ImpliedMoveStatementEndpoint(nestedResourceAddr("child", "formerly_count").Instance(addrs.NoKey), tfdiags.SourceRange{}),
+			Implied: true,
+			DeclRange: tfdiags.SourceRange{
+				Filename: "testdata/move-statement-implied/child/move-statement-implied.tf",
+				Start:    tfdiags.SourcePos{Line: 5, Column: 1, Byte: 180},
+				End:      tfdiags.SourcePos{Line: 5, Column: 32, Byte: 211},
+			},
+		},
+
+		{
+			From:    addrs.ImpliedMoveStatementEndpoint(resourceAddr("now_count").Instance(addrs.NoKey), tfdiags.SourceRange{}),
+			To:      addrs.ImpliedMoveStatementEndpoint(resourceAddr("now_count").Instance(addrs.IntKey(0)), tfdiags.SourceRange{}),
+			Implied: true,
+			DeclRange: tfdiags.SourceRange{
+				Filename: "testdata/move-statement-implied/move-statement-implied.tf",
+				Start:    tfdiags.SourcePos{Line: 10, Column: 11, Byte: 282},
+				End:      tfdiags.SourcePos{Line: 10, Column: 12, Byte: 283},
+			},
+		},
+
+		// Found implied moves in a nested module, ignoring the explicit moves
+		{
+			From:    addrs.ImpliedMoveStatementEndpoint(nestedResourceAddr("child", "now_count").Instance(addrs.NoKey), tfdiags.SourceRange{}),
+			To:      addrs.ImpliedMoveStatementEndpoint(nestedResourceAddr("child", "now_count").Instance(addrs.IntKey(0)), tfdiags.SourceRange{}),
+			Implied: true,
+			DeclRange: tfdiags.SourceRange{
+				Filename: "testdata/move-statement-implied/child/move-statement-implied.tf",
+				Start:    tfdiags.SourcePos{Line: 10, Column: 11, Byte: 282},
+				End:      tfdiags.SourcePos{Line: 10, Column: 12, Byte: 283},
+			},
+		},
+
+		// We generate foo.ambiguous[0] to foo.ambiguous here, even though
+		// there's already a foo.ambiguous in the state, because it's the
+		// responsibility of the later ApplyMoves step to deal with the
+		// situation where an object wants to move into an address already
+		// occupied by another object.
+		{
+			From:    addrs.ImpliedMoveStatementEndpoint(resourceAddr("ambiguous").Instance(addrs.IntKey(0)), tfdiags.SourceRange{}),
+			To:      addrs.ImpliedMoveStatementEndpoint(resourceAddr("ambiguous").Instance(addrs.NoKey), tfdiags.SourceRange{}),
+			Implied: true,
+			DeclRange: tfdiags.SourceRange{
+				Filename: "testdata/move-statement-implied/move-statement-implied.tf",
+				Start:    tfdiags.SourcePos{Line: 46, Column: 1, Byte: 806},
+				End:      tfdiags.SourcePos{Line: 46, Column: 27, Byte: 832},
+			},
+		},
+	}
+
+	sort.Slice(got, func(i, j int) bool {
+		// This is just an arbitrary sort to make the result consistent
+		// regardless of what order the ImpliedMoveStatements function
+		// visits the entries in the state/config.
+		return got[i].DeclRange.Start.Line < got[j].DeclRange.Start.Line
+	})
+
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Errorf("wrong result\n%s", diff)
+	}
+}
diff --git a/v1.5.7/internal/refactoring/move_validate.go b/v1.5.7/internal/refactoring/move_validate.go
new file mode 100644
index 0000000..4e7a0a8
--- /dev/null
+++ b/v1.5.7/internal/refactoring/move_validate.go
@@ -0,0 +1,343 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package refactoring
+
+import (
+	"fmt"
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ValidateMoves tests whether all of the given move statements comply with
+// both the single-statement validation rules and the "big picture" rules
+// that constrain statements in relation to one another.
+//
+// The validation rules are primarily in terms of the configuration, but
+// ValidateMoves also takes the expander that resulted from creating a plan
+// so that it can see which instances are defined for each module and resource,
+// to precisely validate move statements involving specific-instance addresses.
+//
+// Because validation depends on the planning result but move execution must
+// happen _before_ planning, we have the unusual situation where sibling
+// function ApplyMoves must run before ValidateMoves and must therefore
+// tolerate and ignore any invalid statements. The plan walk will then
+// construct in incorrect plan (because it'll be starting from the wrong
+// prior state) but ValidateMoves will block actually showing that invalid
+// plan to the user.
+func ValidateMoves(stmts []MoveStatement, rootCfg *configs.Config, declaredInsts instances.Set) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	if len(stmts) == 0 {
+		return diags
+	}
+
+	g := buildMoveStatementGraph(stmts)
+
+	// We need to track the absolute versions of our endpoint addresses in
+	// order to detect when there are ambiguous moves.
+	type AbsMoveEndpoint struct {
+		Other     addrs.AbsMoveable
+		StmtRange tfdiags.SourceRange
+	}
+	stmtFrom := addrs.MakeMap[addrs.AbsMoveable, AbsMoveEndpoint]()
+	stmtTo := addrs.MakeMap[addrs.AbsMoveable, AbsMoveEndpoint]()
+
+	for _, stmt := range stmts {
+		// Earlier code that constructs MoveStatement values should ensure that
+		// both stmt.From and stmt.To always belong to the same statement.
+		fromMod, _ := stmt.From.ModuleCallTraversals()
+
+		for _, fromModInst := range declaredInsts.InstancesForModule(fromMod) {
+			absFrom := stmt.From.InModuleInstance(fromModInst)
+
+			absTo := stmt.To.InModuleInstance(fromModInst)
+
+			if addrs.Equivalent(absFrom, absTo) {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Redundant move statement",
+					Detail: fmt.Sprintf(
+						"This statement declares a move from %s to the same address, which is the same as not declaring this move at all.",
+						absFrom,
+					),
+					Subject: stmt.DeclRange.ToHCL().Ptr(),
+				})
+				continue
+			}
+
+			var noun string
+			var shortNoun string
+			switch absFrom.(type) {
+			case addrs.ModuleInstance:
+				noun = "module instance"
+				shortNoun = "instance"
+			case addrs.AbsModuleCall:
+				noun = "module call"
+				shortNoun = "call"
+			case addrs.AbsResourceInstance:
+				noun = "resource instance"
+				shortNoun = "instance"
+			case addrs.AbsResource:
+				noun = "resource"
+				shortNoun = "resource"
+			default:
+				// The above cases should cover all of the AbsMoveable types
+				panic("unsupported AbsMoveable address type")
+			}
+
+			// It's invalid to have a move statement whose "from" address
+			// refers to something that is still declared in the configuration.
+			if moveableObjectExists(absFrom, declaredInsts) {
+				conflictRange, hasRange := movableObjectDeclRange(absFrom, rootCfg)
+				declaredAt := ""
+				if hasRange {
+					// NOTE: It'd be pretty weird to _not_ have a range, since
+					// we're only in this codepath because the plan phase
+					// thought this object existed in the configuration.
+					declaredAt = fmt.Sprintf(" at %s", conflictRange.StartString())
+				}
+
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Moved object still exists",
+					Detail: fmt.Sprintf(
+						"This statement declares a move from %s, but that %s is still declared%s.\n\nChange your configuration so that this %s will be declared as %s instead.",
+						absFrom, noun, declaredAt, shortNoun, absTo,
+					),
+					Subject: stmt.DeclRange.ToHCL().Ptr(),
+				})
+			}
+
+			// There can only be one destination for each source address.
+			if existing, exists := stmtFrom.GetOk(absFrom); exists {
+				if !addrs.Equivalent(existing.Other, absTo) {
+					diags = diags.Append(&hcl.Diagnostic{
+						Severity: hcl.DiagError,
+						Summary:  "Ambiguous move statements",
+						Detail: fmt.Sprintf(
+							"A statement at %s declared that %s moved to %s, but this statement instead declares that it moved to %s.\n\nEach %s can move to only one destination %s.",
+							existing.StmtRange.StartString(), absFrom, existing.Other, absTo,
+							noun, shortNoun,
+						),
+						Subject: stmt.DeclRange.ToHCL().Ptr(),
+					})
+				}
+			} else {
+				stmtFrom.Put(absFrom, AbsMoveEndpoint{
+					Other:     absTo,
+					StmtRange: stmt.DeclRange,
+				})
+			}
+
+			// There can only be one source for each destination address.
+			if existing, exists := stmtTo.GetOk(absTo); exists {
+				if !addrs.Equivalent(existing.Other, absFrom) {
+					diags = diags.Append(&hcl.Diagnostic{
+						Severity: hcl.DiagError,
+						Summary:  "Ambiguous move statements",
+						Detail: fmt.Sprintf(
+							"A statement at %s declared that %s moved to %s, but this statement instead declares that %s moved there.\n\nEach %s can have moved from only one source %s.",
+							existing.StmtRange.StartString(), existing.Other, absTo, absFrom,
+							noun, shortNoun,
+						),
+						Subject: stmt.DeclRange.ToHCL().Ptr(),
+					})
+				}
+			} else {
+				stmtTo.Put(absTo, AbsMoveEndpoint{
+					Other:     absFrom,
+					StmtRange: stmt.DeclRange,
+				})
+			}
+
+			// Resource types must match.
+			if resourceTypesDiffer(absFrom, absTo) {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Resource type mismatch",
+					Detail: fmt.Sprintf(
+						"This statement declares a move from %s to %s, which is a %s of a different type.", absFrom, absTo, noun,
+					),
+				})
+			}
+
+		}
+	}
+
+	// If we're not already returning other errors then we'll also check for
+	// and report cycles.
+	//
+	// Cycles alone are difficult to report in a helpful way because we don't
+	// have enough context to guess the user's intent. However, some particular
+	// mistakes that might lead to a cycle can also be caught by other
+	// validation rules above where we can make better suggestions, and so
+	// we'll use a cycle report only as a last resort.
+	if !diags.HasErrors() {
+		diags = diags.Append(validateMoveStatementGraph(g))
+	}
+
+	return diags
+}
+
+func validateMoveStatementGraph(g *dag.AcyclicGraph) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+	for _, cycle := range g.Cycles() {
+		// Reporting cycles is awkward because there isn't any definitive
+		// way to decide which of the objects in the cycle is the cause of
+		// the problem. Therefore we'll just list them all out and leave
+		// the user to figure it out. :(
+		stmtStrs := make([]string, 0, len(cycle))
+		for _, stmtI := range cycle {
+			// move statement graph nodes are pointers to move statements
+			stmt := stmtI.(*MoveStatement)
+			stmtStrs = append(stmtStrs, fmt.Sprintf(
+				"\n  - %s: %s → %s",
+				stmt.DeclRange.StartString(),
+				stmt.From.String(),
+				stmt.To.String(),
+			))
+		}
+		sort.Strings(stmtStrs) // just to make the order deterministic
+
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Cyclic dependency in move statements",
+			fmt.Sprintf(
+				"The following chained move statements form a cycle, and so there is no final location to move objects to:%s\n\nA chain of move statements must end with an address that doesn't appear in any other statements, and which typically also refers to an object still declared in the configuration.",
+				strings.Join(stmtStrs, ""),
+			),
+		))
+	}
+
+	// Look for cycles to self.
+	// A user shouldn't be able to create self-references, but we cannot
+	// correctly process a graph with them.
+	for _, e := range g.Edges() {
+		src := e.Source()
+		if src == e.Target() {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Self reference in move statements",
+				fmt.Sprintf(
+					"The move statement %s refers to itself the move dependency graph, which is invalid. This is a bug in Terraform; please report it!",
+					src.(*MoveStatement).Name(),
+				),
+			))
+		}
+	}
+
+	return diags
+}
+
+func moveableObjectExists(addr addrs.AbsMoveable, in instances.Set) bool {
+	switch addr := addr.(type) {
+	case addrs.ModuleInstance:
+		return in.HasModuleInstance(addr)
+	case addrs.AbsModuleCall:
+		return in.HasModuleCall(addr)
+	case addrs.AbsResourceInstance:
+		return in.HasResourceInstance(addr)
+	case addrs.AbsResource:
+		return in.HasResource(addr)
+	default:
+		// The above cases should cover all of the AbsMoveable types
+		panic("unsupported AbsMoveable address type")
+	}
+}
+
+func resourceTypesDiffer(absFrom, absTo addrs.AbsMoveable) bool {
+	switch absFrom := absFrom.(type) {
+	case addrs.AbsMoveableResource:
+		// addrs.UnifyMoveEndpoints guarantees that both addresses are of the
+		// same kind, so at this point we can assume that absTo is also an
+		// addrs.AbsResourceInstance or addrs.AbsResource.
+		absTo := absTo.(addrs.AbsMoveableResource)
+		return absFrom.AffectedAbsResource().Resource.Type != absTo.AffectedAbsResource().Resource.Type
+	default:
+		return false
+	}
+}
+
+func movableObjectDeclRange(addr addrs.AbsMoveable, cfg *configs.Config) (tfdiags.SourceRange, bool) {
+	switch addr := addr.(type) {
+	case addrs.ModuleInstance:
+		// For a module instance we're actually looking for the call that
+		// declared it, which belongs to the parent module.
+		// (NOTE: This assumes "addr" can never be the root module instance,
+		// because the root module is never moveable.)
+		parentAddr, callAddr := addr.Call()
+		modCfg := cfg.DescendentForInstance(parentAddr)
+		if modCfg == nil {
+			return tfdiags.SourceRange{}, false
+		}
+		call := modCfg.Module.ModuleCalls[callAddr.Name]
+		if call == nil {
+			return tfdiags.SourceRange{}, false
+		}
+
+		// If the call has either count or for_each set then we'll "blame"
+		// that expression, rather than the block as a whole, because it's
+		// the expression that decides which instances are available.
+		switch {
+		case call.ForEach != nil:
+			return tfdiags.SourceRangeFromHCL(call.ForEach.Range()), true
+		case call.Count != nil:
+			return tfdiags.SourceRangeFromHCL(call.Count.Range()), true
+		default:
+			return tfdiags.SourceRangeFromHCL(call.DeclRange), true
+		}
+	case addrs.AbsModuleCall:
+		modCfg := cfg.DescendentForInstance(addr.Module)
+		if modCfg == nil {
+			return tfdiags.SourceRange{}, false
+		}
+		call := modCfg.Module.ModuleCalls[addr.Call.Name]
+		if call == nil {
+			return tfdiags.SourceRange{}, false
+		}
+		return tfdiags.SourceRangeFromHCL(call.DeclRange), true
+	case addrs.AbsResourceInstance:
+		modCfg := cfg.DescendentForInstance(addr.Module)
+		if modCfg == nil {
+			return tfdiags.SourceRange{}, false
+		}
+		rc := modCfg.Module.ResourceByAddr(addr.Resource.Resource)
+		if rc == nil {
+			return tfdiags.SourceRange{}, false
+		}
+
+		// If the resource has either count or for_each set then we'll "blame"
+		// that expression, rather than the block as a whole, because it's
+		// the expression that decides which instances are available.
+		switch {
+		case rc.ForEach != nil:
+			return tfdiags.SourceRangeFromHCL(rc.ForEach.Range()), true
+		case rc.Count != nil:
+			return tfdiags.SourceRangeFromHCL(rc.Count.Range()), true
+		default:
+			return tfdiags.SourceRangeFromHCL(rc.DeclRange), true
+		}
+	case addrs.AbsResource:
+		modCfg := cfg.DescendentForInstance(addr.Module)
+		if modCfg == nil {
+			return tfdiags.SourceRange{}, false
+		}
+		rc := modCfg.Module.ResourceByAddr(addr.Resource)
+		if rc == nil {
+			return tfdiags.SourceRange{}, false
+		}
+		return tfdiags.SourceRangeFromHCL(rc.DeclRange), true
+	default:
+		// The above cases should cover all of the AbsMoveable types
+		panic("unsupported AbsMoveable address type")
+	}
+}
diff --git a/v1.5.7/internal/refactoring/move_validate_test.go b/v1.5.7/internal/refactoring/move_validate_test.go
new file mode 100644
index 0000000..3585abc
--- /dev/null
+++ b/v1.5.7/internal/refactoring/move_validate_test.go
@@ -0,0 +1,710 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package refactoring
+
+import (
+	"context"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/zclconf/go-cty/cty/gocty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/registry"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestValidateMoves(t *testing.T) {
+	rootCfg, instances := loadRefactoringFixture(t, "testdata/move-validate-zoo")
+
+	tests := map[string]struct {
+		Statements []MoveStatement
+		WantError  string
+	}{
+		"no move statements": {
+			Statements: nil,
+			WantError:  ``,
+		},
+		"some valid statements": {
+			Statements: []MoveStatement{
+				// This is just a grab bag of various valid cases that don't
+				// generate any errors at all.
+				makeTestMoveStmt(t,
+					``,
+					`test.nonexist1`,
+					`test.target1`,
+				),
+				makeTestMoveStmt(t,
+					`single`,
+					`test.nonexist1`,
+					`test.target1`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`test.nonexist2`,
+					`module.nonexist.test.nonexist2`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`module.single.test.nonexist3`,
+					`module.single.test.single`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`module.single.test.nonexist4`,
+					`test.target2`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`test.single[0]`, // valid because test.single doesn't have "count" set
+					`test.target3`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`test.zero_count[0]`, // valid because test.zero_count has count = 0
+					`test.target4`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`test.zero_count[1]`, // valid because test.zero_count has count = 0
+					`test.zero_count[0]`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`module.nonexist1`,
+					`module.target3`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`module.nonexist1[0]`,
+					`module.target4`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`module.single[0]`, // valid because module.single doesn't have "count" set
+					`module.target5`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`module.for_each["nonexist1"]`,
+					`module.for_each["a"]`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`module.for_each["nonexist2"]`,
+					`module.nonexist.module.nonexist`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`module.for_each["nonexist3"].test.single`, // valid because module.for_each doesn't currently have a "nonexist3"
+					`module.for_each["a"].test.single`,
+				),
+			},
+			WantError: ``,
+		},
+		"two statements with the same endpoints": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`module.a`,
+					`module.b`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`module.a`,
+					`module.b`,
+				),
+			},
+			WantError: ``,
+		},
+		"moving nowhere": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`module.a`,
+					`module.a`,
+				),
+			},
+			WantError: `Redundant move statement: This statement declares a move from module.a to the same address, which is the same as not declaring this move at all.`,
+		},
+		"cyclic chain": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`module.a`,
+					`module.b`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`module.b`,
+					`module.c`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`module.c`,
+					`module.a`,
+				),
+			},
+			WantError: `Cyclic dependency in move statements: The following chained move statements form a cycle, and so there is no final location to move objects to:
+  - test:1,1: module.a[*] → module.b[*]
+  - test:1,1: module.b[*] → module.c[*]
+  - test:1,1: module.c[*] → module.a[*]
+
+A chain of move statements must end with an address that doesn't appear in any other statements, and which typically also refers to an object still declared in the configuration.`,
+		},
+		"module.single as a call still exists in configuration": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`module.single`,
+					`module.other`,
+				),
+			},
+			WantError: `Moved object still exists: This statement declares a move from module.single, but that module call is still declared at testdata/move-validate-zoo/move-validate-root.tf:6,1.
+
+Change your configuration so that this call will be declared as module.other instead.`,
+		},
+		"module.single as an instance still exists in configuration": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`module.single`,
+					`module.other[0]`,
+				),
+			},
+			WantError: `Moved object still exists: This statement declares a move from module.single, but that module instance is still declared at testdata/move-validate-zoo/move-validate-root.tf:6,1.
+
+Change your configuration so that this instance will be declared as module.other[0] instead.`,
+		},
+		"module.count[0] still exists in configuration": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`module.count[0]`,
+					`module.other`,
+				),
+			},
+			WantError: `Moved object still exists: This statement declares a move from module.count[0], but that module instance is still declared at testdata/move-validate-zoo/move-validate-root.tf:12,12.
+
+Change your configuration so that this instance will be declared as module.other instead.`,
+		},
+		`module.for_each["a"] still exists in configuration`: {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`module.for_each["a"]`,
+					`module.other`,
+				),
+			},
+			WantError: `Moved object still exists: This statement declares a move from module.for_each["a"], but that module instance is still declared at testdata/move-validate-zoo/move-validate-root.tf:22,14.
+
+Change your configuration so that this instance will be declared as module.other instead.`,
+		},
+		"test.single as a resource still exists in configuration": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`test.single`,
+					`test.other`,
+				),
+			},
+			WantError: `Moved object still exists: This statement declares a move from test.single, but that resource is still declared at testdata/move-validate-zoo/move-validate-root.tf:27,1.
+
+Change your configuration so that this resource will be declared as test.other instead.`,
+		},
+		"test.single as an instance still exists in configuration": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`test.single`,
+					`test.other[0]`,
+				),
+			},
+			WantError: `Moved object still exists: This statement declares a move from test.single, but that resource instance is still declared at testdata/move-validate-zoo/move-validate-root.tf:27,1.
+
+Change your configuration so that this instance will be declared as test.other[0] instead.`,
+		},
+		"module.single.test.single as a resource still exists in configuration": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`module.single.test.single`,
+					`test.other`,
+				),
+			},
+			WantError: `Moved object still exists: This statement declares a move from module.single.test.single, but that resource is still declared at testdata/move-validate-zoo/child/move-validate-child.tf:6,1.
+
+Change your configuration so that this resource will be declared as test.other instead.`,
+		},
+		"module.single.test.single as a resource declared in module.single still exists in configuration": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					`single`,
+					`test.single`,
+					`test.other`,
+				),
+			},
+			WantError: `Moved object still exists: This statement declares a move from module.single.test.single, but that resource is still declared at testdata/move-validate-zoo/child/move-validate-child.tf:6,1.
+
+Change your configuration so that this resource will be declared as module.single.test.other instead.`,
+		},
+		"module.single.test.single as an instance still exists in configuration": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`module.single.test.single`,
+					`test.other[0]`,
+				),
+			},
+			WantError: `Moved object still exists: This statement declares a move from module.single.test.single, but that resource instance is still declared at testdata/move-validate-zoo/child/move-validate-child.tf:6,1.
+
+Change your configuration so that this instance will be declared as test.other[0] instead.`,
+		},
+		"module.count[0].test.single still exists in configuration": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`module.count[0].test.single`,
+					`test.other`,
+				),
+			},
+			WantError: `Moved object still exists: This statement declares a move from module.count[0].test.single, but that resource is still declared at testdata/move-validate-zoo/child/move-validate-child.tf:6,1.
+
+Change your configuration so that this resource will be declared as test.other instead.`,
+		},
+		"two different moves from test.nonexist": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`test.nonexist`,
+					`test.other1`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`test.nonexist`,
+					`test.other2`,
+				),
+			},
+			WantError: `Ambiguous move statements: A statement at test:1,1 declared that test.nonexist moved to test.other1, but this statement instead declares that it moved to test.other2.
+
+Each resource can move to only one destination resource.`,
+		},
+		"two different moves to test.single": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`test.other1`,
+					`test.single`,
+				),
+				makeTestMoveStmt(t,
+					``,
+					`test.other2`,
+					`test.single`,
+				),
+			},
+			WantError: `Ambiguous move statements: A statement at test:1,1 declared that test.other1 moved to test.single, but this statement instead declares that test.other2 moved there.
+
+Each resource can have moved from only one source resource.`,
+		},
+		"two different moves to module.count[0].test.single across two modules": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`test.other1`,
+					`module.count[0].test.single`,
+				),
+				makeTestMoveStmt(t,
+					`count`,
+					`test.other2`,
+					`test.single`,
+				),
+			},
+			WantError: `Ambiguous move statements: A statement at test:1,1 declared that test.other1 moved to module.count[0].test.single, but this statement instead declares that module.count[0].test.other2 moved there.
+
+Each resource can have moved from only one source resource.`,
+		},
+		"move from resource in another module package": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`module.fake_external.test.thing`,
+					`test.thing`,
+				),
+			},
+			WantError: ``,
+		},
+		"move to resource in another module package": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`test.thing`,
+					`module.fake_external.test.thing`,
+				),
+			},
+			WantError: ``,
+		},
+		"move from module call in another module package": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`module.fake_external.module.a`,
+					`module.b`,
+				),
+			},
+			WantError: ``,
+		},
+		"move to module call in another module package": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`module.a`,
+					`module.fake_external.module.b`,
+				),
+			},
+			WantError: ``,
+		},
+		"implied move from resource in another module package": {
+			Statements: []MoveStatement{
+				makeTestImpliedMoveStmt(t,
+					``,
+					`module.fake_external.test.thing`,
+					`test.thing`,
+				),
+			},
+			// Implied move statements are not subject to the cross-package restriction
+			WantError: ``,
+		},
+		"implied move to resource in another module package": {
+			Statements: []MoveStatement{
+				makeTestImpliedMoveStmt(t,
+					``,
+					`test.thing`,
+					`module.fake_external.test.thing`,
+				),
+			},
+			// Implied move statements are not subject to the cross-package restriction
+			WantError: ``,
+		},
+		"implied move from module call in another module package": {
+			Statements: []MoveStatement{
+				makeTestImpliedMoveStmt(t,
+					``,
+					`module.fake_external.module.a`,
+					`module.b`,
+				),
+			},
+			// Implied move statements are not subject to the cross-package restriction
+			WantError: ``,
+		},
+		"implied move to module call in another module package": {
+			Statements: []MoveStatement{
+				makeTestImpliedMoveStmt(t,
+					``,
+					`module.a`,
+					`module.fake_external.module.b`,
+				),
+			},
+			// Implied move statements are not subject to the cross-package restriction
+			WantError: ``,
+		},
+		"move to a call that refers to another module package": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`module.nonexist`,
+					`module.fake_external`,
+				),
+			},
+			WantError: ``, // This is okay because the call itself is not considered to be inside the package it refers to
+		},
+		"move to instance of a call that refers to another module package": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t,
+					``,
+					`module.nonexist`,
+					`module.fake_external[0]`,
+				),
+			},
+			WantError: ``, // This is okay because the call itself is not considered to be inside the package it refers to
+		},
+		"resource type mismatch": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t, ``,
+					`test.nonexist1`,
+					`other.single`,
+				),
+			},
+			WantError: `Resource type mismatch: This statement declares a move from test.nonexist1 to other.single, which is a resource of a different type.`,
+		},
+		"resource instance type mismatch": {
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t, ``,
+					`test.nonexist1[0]`,
+					`other.single`,
+				),
+			},
+			WantError: `Resource type mismatch: This statement declares a move from test.nonexist1[0] to other.single, which is a resource instance of a different type.`,
+		},
+		"crossing nested statements": {
+			// overlapping nested moves will result in a cycle.
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t, ``,
+					`module.nonexist.test.single`,
+					`module.count[0].test.count[0]`,
+				),
+				makeTestMoveStmt(t, ``,
+					`module.nonexist`,
+					`module.count[0]`,
+				),
+			},
+			WantError: `Cyclic dependency in move statements: The following chained move statements form a cycle, and so there is no final location to move objects to:
+  - test:1,1: module.nonexist → module.count[0]
+  - test:1,1: module.nonexist.test.single → module.count[0].test.count[0]
+
+A chain of move statements must end with an address that doesn't appear in any other statements, and which typically also refers to an object still declared in the configuration.`,
+		},
+		"fully contained nested statements": {
+			// we have to avoid a cycle because the nested moves appear in both
+			// the from and to address of the parent when only the module index
+			// is changing.
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t, `count`,
+					`test.count`,
+					`test.count[0]`,
+				),
+				makeTestMoveStmt(t, ``,
+					`module.count`,
+					`module.count[0]`,
+				),
+			},
+		},
+		"double fully contained nested statements": {
+			// we have to avoid a cycle because the nested moves appear in both
+			// the from and to address of the parent when only the module index
+			// is changing.
+			Statements: []MoveStatement{
+				makeTestMoveStmt(t, `count`,
+					`module.count`,
+					`module.count[0]`,
+				),
+				makeTestMoveStmt(t, `count.count`,
+					`test.count`,
+					`test.count[0]`,
+				),
+				makeTestMoveStmt(t, ``,
+					`module.count`,
+					`module.count[0]`,
+				),
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			gotDiags := ValidateMoves(test.Statements, rootCfg, instances)
+
+			switch {
+			case test.WantError != "":
+				if !gotDiags.HasErrors() {
+					t.Fatalf("unexpected success\nwant error: %s", test.WantError)
+				}
+				if got, want := gotDiags.Err().Error(), test.WantError; got != want {
+					t.Fatalf("wrong error\ngot error:  %s\nwant error: %s", got, want)
+				}
+			default:
+				if gotDiags.HasErrors() {
+					t.Fatalf("unexpected error\ngot error: %s", gotDiags.Err().Error())
+				}
+			}
+		})
+	}
+}
+
+// loadRefactoringFixture reads a configuration from the given directory and
+// does some naive static processing on any count and for_each expressions
+// inside, in order to get a realistic-looking instances.Set for what it
+// declares without having to run a full Terraform plan.
+func loadRefactoringFixture(t *testing.T, dir string) (*configs.Config, instances.Set) {
+	t.Helper()
+
+	loader, cleanup := configload.NewLoaderForTests(t)
+	defer cleanup()
+
+	inst := initwd.NewModuleInstaller(loader.ModulesDir(), loader, registry.NewClient(nil, nil))
+	_, instDiags := inst.InstallModules(context.Background(), dir, true, initwd.ModuleInstallHooksImpl{})
+	if instDiags.HasErrors() {
+		t.Fatal(instDiags.Err())
+	}
+
+	// Since module installer has modified the module manifest on disk, we need
+	// to refresh the cache of it in the loader.
+	if err := loader.RefreshModules(); err != nil {
+		t.Fatalf("failed to refresh modules after installation: %s", err)
+	}
+
+	rootCfg, diags := loader.LoadConfig(dir)
+	if diags.HasErrors() {
+		t.Fatalf("failed to load root module: %s", diags.Error())
+	}
+
+	expander := instances.NewExpander()
+	staticPopulateExpanderModule(t, rootCfg, addrs.RootModuleInstance, expander)
+	return rootCfg, expander.AllInstances()
+}
+
+func staticPopulateExpanderModule(t *testing.T, rootCfg *configs.Config, moduleAddr addrs.ModuleInstance, expander *instances.Expander) {
+	t.Helper()
+
+	modCfg := rootCfg.DescendentForInstance(moduleAddr)
+	if modCfg == nil {
+		t.Fatalf("no configuration for %s", moduleAddr)
+	}
+
+	if len(modCfg.Path) > 0 && modCfg.Path[len(modCfg.Path)-1] == "fake_external" {
+		// As a funny special case we modify the source address of this
+		// module to be something that counts as a separate package,
+		// so we can test rules relating to crossing package boundaries
+		// even though we really just loaded the module from a local path.
+		modCfg.SourceAddr = fakeExternalModuleSource
+	}
+
+	for _, call := range modCfg.Module.ModuleCalls {
+		callAddr := addrs.ModuleCall{Name: call.Name}
+
+		if call.Name == "fake_external" {
+			// As a funny special case we modify the source address of this
+			// module to be something that counts as a separate package,
+			// so we can test rules relating to crossing package boundaries
+			// even though we really just loaded the module from a local path.
+			call.SourceAddr = fakeExternalModuleSource
+		}
+
+		// In order to get a valid, useful set of instances here we're going
+		// to just statically evaluate the count and for_each expressions.
+		// Normally it's valid to use references and functions there, but for
+		// our unit tests we'll just limit it to literal values to avoid
+		// bringing all of the core evaluator complexity.
+		switch {
+		case call.ForEach != nil:
+			val, diags := call.ForEach.Value(nil)
+			if diags.HasErrors() {
+				t.Fatalf("invalid for_each: %s", diags.Error())
+			}
+			expander.SetModuleForEach(moduleAddr, callAddr, val.AsValueMap())
+		case call.Count != nil:
+			val, diags := call.Count.Value(nil)
+			if diags.HasErrors() {
+				t.Fatalf("invalid count: %s", diags.Error())
+			}
+			var count int
+			err := gocty.FromCtyValue(val, &count)
+			if err != nil {
+				t.Fatalf("invalid count at %s: %s", call.Count.Range(), err)
+			}
+			expander.SetModuleCount(moduleAddr, callAddr, count)
+		default:
+			expander.SetModuleSingle(moduleAddr, callAddr)
+		}
+
+		// We need to recursively analyze the child modules too.
+		calledMod := modCfg.Path.Child(call.Name)
+		for _, inst := range expander.ExpandModule(calledMod) {
+			staticPopulateExpanderModule(t, rootCfg, inst, expander)
+		}
+	}
+
+	for _, rc := range modCfg.Module.ManagedResources {
+		staticPopulateExpanderResource(t, moduleAddr, rc, expander)
+	}
+	for _, rc := range modCfg.Module.DataResources {
+		staticPopulateExpanderResource(t, moduleAddr, rc, expander)
+	}
+
+}
+
+func staticPopulateExpanderResource(t *testing.T, moduleAddr addrs.ModuleInstance, rCfg *configs.Resource, expander *instances.Expander) {
+	t.Helper()
+
+	addr := rCfg.Addr()
+	switch {
+	case rCfg.ForEach != nil:
+		val, diags := rCfg.ForEach.Value(nil)
+		if diags.HasErrors() {
+			t.Fatalf("invalid for_each: %s", diags.Error())
+		}
+		expander.SetResourceForEach(moduleAddr, addr, val.AsValueMap())
+	case rCfg.Count != nil:
+		val, diags := rCfg.Count.Value(nil)
+		if diags.HasErrors() {
+			t.Fatalf("invalid count: %s", diags.Error())
+		}
+		var count int
+		err := gocty.FromCtyValue(val, &count)
+		if err != nil {
+			t.Fatalf("invalid count at %s: %s", rCfg.Count.Range(), err)
+		}
+		expander.SetResourceCount(moduleAddr, addr, count)
+	default:
+		expander.SetResourceSingle(moduleAddr, addr)
+	}
+}
+
+func makeTestMoveStmt(t *testing.T, moduleStr, fromStr, toStr string) MoveStatement {
+	t.Helper()
+
+	module := addrs.RootModule
+	if moduleStr != "" {
+		module = addrs.Module(strings.Split(moduleStr, "."))
+	}
+
+	traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(fromStr), "", hcl.InitialPos)
+	if hclDiags.HasErrors() {
+		t.Fatalf("invalid from address: %s", hclDiags.Error())
+	}
+	fromEP, diags := addrs.ParseMoveEndpoint(traversal)
+	if diags.HasErrors() {
+		t.Fatalf("invalid from address: %s", diags.Err().Error())
+	}
+
+	traversal, hclDiags = hclsyntax.ParseTraversalAbs([]byte(toStr), "", hcl.InitialPos)
+	if hclDiags.HasErrors() {
+		t.Fatalf("invalid to address: %s", hclDiags.Error())
+	}
+	toEP, diags := addrs.ParseMoveEndpoint(traversal)
+	if diags.HasErrors() {
+		t.Fatalf("invalid to address: %s", diags.Err().Error())
+	}
+
+	fromInModule, toInModule := addrs.UnifyMoveEndpoints(module, fromEP, toEP)
+	if fromInModule == nil || toInModule == nil {
+		t.Fatalf("incompatible move endpoints")
+	}
+
+	return MoveStatement{
+		From: fromInModule,
+		To:   toInModule,
+		DeclRange: tfdiags.SourceRange{
+			Filename: "test",
+			Start:    tfdiags.SourcePos{Line: 1, Column: 1},
+			End:      tfdiags.SourcePos{Line: 1, Column: 1},
+		},
+	}
+}
+
+func makeTestImpliedMoveStmt(t *testing.T, moduleStr, fromStr, toStr string) MoveStatement {
+	t.Helper()
+	ret := makeTestMoveStmt(t, moduleStr, fromStr, toStr)
+	ret.Implied = true
+	return ret
+}
+
+var fakeExternalModuleSource = addrs.ModuleSourceRemote{
+	Package: addrs.ModulePackage("fake-external:///"),
+}
diff --git a/v1.5.7/internal/refactoring/testdata/move-statement-implied/child/move-statement-implied.tf b/v1.5.7/internal/refactoring/testdata/move-statement-implied/child/move-statement-implied.tf
new file mode 100644
index 0000000..87d09c8
--- /dev/null
+++ b/v1.5.7/internal/refactoring/testdata/move-statement-implied/child/move-statement-implied.tf
@@ -0,0 +1,16 @@
+# This fixture is useful only in conjunction with a previous run state that
+# conforms to the statements encoded in the resource names. It's for
+# TestImpliedMoveStatements only.
+
+resource "foo" "formerly_count" {
+  # but not count anymore
+}
+
+resource "foo" "now_count" {
+  count = 1
+}
+
+moved {
+  from = foo.no_longer_present[1]
+  to   = foo.no_longer_present
+}
diff --git a/v1.5.7/internal/refactoring/testdata/move-statement-implied/move-statement-implied.tf b/v1.5.7/internal/refactoring/testdata/move-statement-implied/move-statement-implied.tf
new file mode 100644
index 0000000..4ea628e
--- /dev/null
+++ b/v1.5.7/internal/refactoring/testdata/move-statement-implied/move-statement-implied.tf
@@ -0,0 +1,54 @@
+# This fixture is useful only in conjunction with a previous run state that
+# conforms to the statements encoded in the resource names. It's for
+# TestImpliedMoveStatements only.
+
+resource "foo" "formerly_count" {
+  # but not count anymore
+}
+
+resource "foo" "now_count" {
+  count = 2
+}
+
+resource "foo" "new_no_count" {
+}
+
+resource "foo" "new_count" {
+  count = 2
+}
+
+resource "foo" "formerly_count_explicit" {
+  # but not count anymore
+}
+
+moved {
+  from = foo.formerly_count_explicit[1]
+  to   = foo.formerly_count_explicit
+}
+
+resource "foo" "now_count_explicit" {
+  count = 2
+}
+
+moved {
+  from = foo.now_count_explicit
+  to   = foo.now_count_explicit[1]
+}
+
+resource "foo" "now_for_each_formerly_count" {
+  for_each = { a = 1 }
+}
+
+resource "foo" "now_for_each_formerly_no_count" {
+  for_each = { a = 1 }
+}
+
+resource "foo" "ambiguous" {
+  # this one doesn't have count in the config, but the test should
+  # set it up to have both no-key and zero-key instances in the
+  # state.
+}
+
+module "child" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/refactoring/testdata/move-validate-zoo/child/move-validate-child.tf b/v1.5.7/internal/refactoring/testdata/move-validate-zoo/child/move-validate-child.tf
new file mode 100644
index 0000000..8f3c4f4
--- /dev/null
+++ b/v1.5.7/internal/refactoring/testdata/move-validate-zoo/child/move-validate-child.tf
@@ -0,0 +1,21 @@
+
+# NOTE: This fixture is used in a test that doesn't run a full Terraform plan
+# operation, so the count and for_each expressions here can only be literal
+# values and mustn't include any references or function calls.
+
+resource "test" "single" {
+}
+
+resource "test" "count" {
+  count = 2
+}
+
+resource "test" "zero_count" {
+  count = 0
+}
+
+resource "test" "for_each" {
+  for_each = {
+    a = "A"
+  }
+}
diff --git a/v1.5.7/internal/refactoring/testdata/move-validate-zoo/move-validate-root.tf b/v1.5.7/internal/refactoring/testdata/move-validate-zoo/move-validate-root.tf
new file mode 100644
index 0000000..3cc8504
--- /dev/null
+++ b/v1.5.7/internal/refactoring/testdata/move-validate-zoo/move-validate-root.tf
@@ -0,0 +1,53 @@
+
+# NOTE: This fixture is used in a test that doesn't run a full Terraform plan
+# operation, so the count and for_each expressions here can only be literal
+# values and mustn't include any references or function calls.
+
+module "single" {
+  source = "./child"
+}
+
+module "count" {
+  source = "./child"
+  count  = 2
+}
+
+module "zero_count" {
+  source = "./child"
+  count  = 0
+}
+
+module "for_each" {
+  source = "./child"
+  for_each = {
+    a = "A"
+  }
+}
+
+resource "test" "single" {
+}
+
+resource "test" "count" {
+  count = 2
+}
+
+resource "test" "zero_count" {
+  count = 0
+}
+
+resource "test" "for_each" {
+  for_each = {
+    a = "A"
+  }
+}
+
+resource "other" "single" {
+}
+
+module "fake_external" {
+  # Our configuration fixture loader has a special case for a module call
+  # named "fake_external" where it will mutate the source address after
+  # loading to instead be an external address, so we can test rules relating
+  # to crossing module boundaries.
+  source = "./child"
+}
diff --git a/v1.5.7/internal/registry/client.go b/v1.5.7/internal/registry/client.go
new file mode 100644
index 0000000..59d2c3f
--- /dev/null
+++ b/v1.5.7/internal/registry/client.go
@@ -0,0 +1,330 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package registry
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"net/url"
+	"os"
+	"path"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/hashicorp/go-retryablehttp"
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/httpclient"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/registry/regsrc"
+	"github.com/hashicorp/terraform/internal/registry/response"
+	"github.com/hashicorp/terraform/version"
+)
+
+const (
+	xTerraformGet      = "X-Terraform-Get"
+	xTerraformVersion  = "X-Terraform-Version"
+	modulesServiceID   = "modules.v1"
+	providersServiceID = "providers.v1"
+
+	// registryDiscoveryRetryEnvName is the name of the environment variable that
+	// can be configured to customize number of retries for module and provider
+	// discovery requests with the remote registry.
+	registryDiscoveryRetryEnvName = "TF_REGISTRY_DISCOVERY_RETRY"
+	defaultRetry                  = 1
+
+	// registryClientTimeoutEnvName is the name of the environment variable that
+	// can be configured to customize the timeout duration (seconds) for module
+	// and provider discovery with the remote registry.
+	registryClientTimeoutEnvName = "TF_REGISTRY_CLIENT_TIMEOUT"
+
+	// defaultRequestTimeout is the default timeout duration for requests to the
+	// remote registry.
+	defaultRequestTimeout = 10 * time.Second
+)
+
+var (
+	tfVersion = version.String()
+
+	discoveryRetry int
+	requestTimeout time.Duration
+)
+
+func init() {
+	configureDiscoveryRetry()
+	configureRequestTimeout()
+}
+
+// Client provides methods to query Terraform Registries.
+type Client struct {
+	// this is the client to be used for all requests.
+	client *retryablehttp.Client
+
+	// services is a required *disco.Disco, which may have services and
+	// credentials pre-loaded.
+	services *disco.Disco
+}
+
+// NewClient returns a new initialized registry client.
+func NewClient(services *disco.Disco, client *http.Client) *Client {
+	if services == nil {
+		services = disco.New()
+	}
+
+	if client == nil {
+		client = httpclient.New()
+		client.Timeout = requestTimeout
+	}
+	retryableClient := retryablehttp.NewClient()
+	retryableClient.HTTPClient = client
+	retryableClient.RetryMax = discoveryRetry
+	retryableClient.RequestLogHook = requestLogHook
+	retryableClient.ErrorHandler = maxRetryErrorHandler
+
+	logOutput := logging.LogOutput()
+	retryableClient.Logger = log.New(logOutput, "", log.Flags())
+
+	services.Transport = retryableClient.HTTPClient.Transport
+
+	services.SetUserAgent(httpclient.TerraformUserAgent(version.String()))
+
+	return &Client{
+		client:   retryableClient,
+		services: services,
+	}
+}
+
+// Discover queries the host, and returns the url for the registry.
+func (c *Client) Discover(host svchost.Hostname, serviceID string) (*url.URL, error) {
+	service, err := c.services.DiscoverServiceURL(host, serviceID)
+	if err != nil {
+		return nil, &ServiceUnreachableError{err}
+	}
+	if !strings.HasSuffix(service.Path, "/") {
+		service.Path += "/"
+	}
+	return service, nil
+}
+
+// ModuleVersions queries the registry for a module, and returns the available versions.
+func (c *Client) ModuleVersions(ctx context.Context, module *regsrc.Module) (*response.ModuleVersions, error) {
+	host, err := module.SvcHost()
+	if err != nil {
+		return nil, err
+	}
+
+	service, err := c.Discover(host, modulesServiceID)
+	if err != nil {
+		return nil, err
+	}
+
+	p, err := url.Parse(path.Join(module.Module(), "versions"))
+	if err != nil {
+		return nil, err
+	}
+
+	service = service.ResolveReference(p)
+
+	log.Printf("[DEBUG] fetching module versions from %q", service)
+
+	req, err := retryablehttp.NewRequest("GET", service.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+	req = req.WithContext(ctx)
+
+	c.addRequestCreds(host, req.Request)
+	req.Header.Set(xTerraformVersion, tfVersion)
+
+	resp, err := c.client.Do(req)
+	if err != nil {
+		return nil, err
+	}
+	defer resp.Body.Close()
+
+	switch resp.StatusCode {
+	case http.StatusOK:
+		// OK
+	case http.StatusNotFound:
+		return nil, &errModuleNotFound{addr: module}
+	default:
+		return nil, fmt.Errorf("error looking up module versions: %s", resp.Status)
+	}
+
+	var versions response.ModuleVersions
+
+	dec := json.NewDecoder(resp.Body)
+	if err := dec.Decode(&versions); err != nil {
+		return nil, err
+	}
+
+	for _, mod := range versions.Modules {
+		for _, v := range mod.Versions {
+			log.Printf("[DEBUG] found available version %q for %s", v.Version, mod.Source)
+		}
+	}
+
+	return &versions, nil
+}
+
+func (c *Client) addRequestCreds(host svchost.Hostname, req *http.Request) {
+	creds, err := c.services.CredentialsForHost(host)
+	if err != nil {
+		log.Printf("[WARN] Failed to get credentials for %s: %s (ignoring)", host, err)
+		return
+	}
+
+	if creds != nil {
+		creds.PrepareRequest(req)
+	}
+}
+
+// ModuleLocation find the download location for a specific version module.
+// This returns a string, because the final location may contain special go-getter syntax.
+func (c *Client) ModuleLocation(ctx context.Context, module *regsrc.Module, version string) (string, error) {
+	host, err := module.SvcHost()
+	if err != nil {
+		return "", err
+	}
+
+	service, err := c.Discover(host, modulesServiceID)
+	if err != nil {
+		return "", err
+	}
+
+	var p *url.URL
+	if version == "" {
+		p, err = url.Parse(path.Join(module.Module(), "download"))
+	} else {
+		p, err = url.Parse(path.Join(module.Module(), version, "download"))
+	}
+	if err != nil {
+		return "", err
+	}
+	download := service.ResolveReference(p)
+
+	log.Printf("[DEBUG] looking up module location from %q", download)
+
+	req, err := retryablehttp.NewRequest("GET", download.String(), nil)
+	if err != nil {
+		return "", err
+	}
+
+	req = req.WithContext(ctx)
+
+	c.addRequestCreds(host, req.Request)
+	req.Header.Set(xTerraformVersion, tfVersion)
+
+	resp, err := c.client.Do(req)
+	if err != nil {
+		return "", err
+	}
+	defer resp.Body.Close()
+
+	// there should be no body, but save it for logging
+	body, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return "", fmt.Errorf("error reading response body from registry: %s", err)
+	}
+
+	switch resp.StatusCode {
+	case http.StatusOK, http.StatusNoContent:
+		// OK
+	case http.StatusNotFound:
+		return "", fmt.Errorf("module %q version %q not found", module, version)
+	default:
+		// anything else is an error:
+		return "", fmt.Errorf("error getting download location for %q: %s resp:%s", module, resp.Status, body)
+	}
+
+	// the download location is in the X-Terraform-Get header
+	location := resp.Header.Get(xTerraformGet)
+	if location == "" {
+		return "", fmt.Errorf("failed to get download URL for %q: %s resp:%s", module, resp.Status, body)
+	}
+
+	// If location looks like it's trying to be a relative URL, treat it as
+	// one.
+	//
+	// We don't do this for just _any_ location, since the X-Terraform-Get
+	// header is a go-getter location rather than a URL, and so not all
+	// possible values will parse reasonably as URLs.)
+	//
+	// When used in conjunction with go-getter we normally require this header
+	// to be an absolute URL, but we are more liberal here because third-party
+	// registry implementations may not "know" their own absolute URLs if
+	// e.g. they are running behind a reverse proxy frontend, or such.
+	if strings.HasPrefix(location, "/") || strings.HasPrefix(location, "./") || strings.HasPrefix(location, "../") {
+		locationURL, err := url.Parse(location)
+		if err != nil {
+			return "", fmt.Errorf("invalid relative URL for %q: %s", module, err)
+		}
+		locationURL = download.ResolveReference(locationURL)
+		location = locationURL.String()
+	}
+
+	return location, nil
+}
+
+// configureDiscoveryRetry configures the number of retries the registry client
+// will attempt for requests with retryable errors, like 502 status codes
+func configureDiscoveryRetry() {
+	discoveryRetry = defaultRetry
+
+	if v := os.Getenv(registryDiscoveryRetryEnvName); v != "" {
+		retry, err := strconv.Atoi(v)
+		if err == nil && retry > 0 {
+			discoveryRetry = retry
+		}
+	}
+}
+
+func requestLogHook(logger retryablehttp.Logger, req *http.Request, i int) {
+	if i > 0 {
+		logger.Printf("[INFO] Previous request to the remote registry failed, attempting retry.")
+	}
+}
+
+func maxRetryErrorHandler(resp *http.Response, err error, numTries int) (*http.Response, error) {
+	// Close the body per library instructions
+	if resp != nil {
+		resp.Body.Close()
+	}
+
+	// Additional error detail: if we have a response, use the status code;
+	// if we have an error, use that; otherwise nothing. We will never have
+	// both response and error.
+	var errMsg string
+	if resp != nil {
+		errMsg = fmt.Sprintf(": %s returned from %s", resp.Status, resp.Request.URL)
+	} else if err != nil {
+		errMsg = fmt.Sprintf(": %s", err)
+	}
+
+	// This function is always called with numTries=RetryMax+1. If we made any
+	// retry attempts, include that in the error message.
+	if numTries > 1 {
+		return resp, fmt.Errorf("the request failed after %d attempts, please try again later%s",
+			numTries, errMsg)
+	}
+	return resp, fmt.Errorf("the request failed, please try again later%s", errMsg)
+}
+
+// configureRequestTimeout configures the registry client request timeout from
+// environment variables
+func configureRequestTimeout() {
+	requestTimeout = defaultRequestTimeout
+
+	if v := os.Getenv(registryClientTimeoutEnvName); v != "" {
+		timeout, err := strconv.Atoi(v)
+		if err == nil && timeout > 0 {
+			requestTimeout = time.Duration(timeout) * time.Second
+		}
+	}
+}
diff --git a/v1.5.7/internal/registry/client_test.go b/v1.5.7/internal/registry/client_test.go
new file mode 100644
index 0000000..c60f2cb
--- /dev/null
+++ b/v1.5.7/internal/registry/client_test.go
@@ -0,0 +1,372 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package registry
+
+import (
+	"context"
+	"net/http"
+	"os"
+	"strings"
+	"testing"
+	"time"
+
+	version "github.com/hashicorp/go-version"
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/httpclient"
+	"github.com/hashicorp/terraform/internal/registry/regsrc"
+	"github.com/hashicorp/terraform/internal/registry/test"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+func TestConfigureDiscoveryRetry(t *testing.T) {
+	t.Run("default retry", func(t *testing.T) {
+		if discoveryRetry != defaultRetry {
+			t.Fatalf("expected retry %q, got %q", defaultRetry, discoveryRetry)
+		}
+
+		rc := NewClient(nil, nil)
+		if rc.client.RetryMax != defaultRetry {
+			t.Fatalf("expected client retry %q, got %q",
+				defaultRetry, rc.client.RetryMax)
+		}
+	})
+
+	t.Run("configured retry", func(t *testing.T) {
+		defer func(retryEnv string) {
+			os.Setenv(registryDiscoveryRetryEnvName, retryEnv)
+			discoveryRetry = defaultRetry
+		}(os.Getenv(registryDiscoveryRetryEnvName))
+		os.Setenv(registryDiscoveryRetryEnvName, "2")
+
+		configureDiscoveryRetry()
+		expected := 2
+		if discoveryRetry != expected {
+			t.Fatalf("expected retry %q, got %q",
+				expected, discoveryRetry)
+		}
+
+		rc := NewClient(nil, nil)
+		if rc.client.RetryMax != expected {
+			t.Fatalf("expected client retry %q, got %q",
+				expected, rc.client.RetryMax)
+		}
+	})
+}
+
+func TestConfigureRegistryClientTimeout(t *testing.T) {
+	t.Run("default timeout", func(t *testing.T) {
+		if requestTimeout != defaultRequestTimeout {
+			t.Fatalf("expected timeout %q, got %q",
+				defaultRequestTimeout.String(), requestTimeout.String())
+		}
+
+		rc := NewClient(nil, nil)
+		if rc.client.HTTPClient.Timeout != defaultRequestTimeout {
+			t.Fatalf("expected client timeout %q, got %q",
+				defaultRequestTimeout.String(), rc.client.HTTPClient.Timeout.String())
+		}
+	})
+
+	t.Run("configured timeout", func(t *testing.T) {
+		defer func(timeoutEnv string) {
+			os.Setenv(registryClientTimeoutEnvName, timeoutEnv)
+			requestTimeout = defaultRequestTimeout
+		}(os.Getenv(registryClientTimeoutEnvName))
+		os.Setenv(registryClientTimeoutEnvName, "20")
+
+		configureRequestTimeout()
+		expected := 20 * time.Second
+		if requestTimeout != expected {
+			t.Fatalf("expected timeout %q, got %q",
+				expected, requestTimeout.String())
+		}
+
+		rc := NewClient(nil, nil)
+		if rc.client.HTTPClient.Timeout != expected {
+			t.Fatalf("expected client timeout %q, got %q",
+				expected, rc.client.HTTPClient.Timeout.String())
+		}
+	})
+}
+
+func TestLookupModuleVersions(t *testing.T) {
+	server := test.Registry()
+	defer server.Close()
+
+	client := NewClient(test.Disco(server), nil)
+
+	// test with and without a hostname
+	for _, src := range []string{
+		"example.com/test-versions/name/provider",
+		"test-versions/name/provider",
+	} {
+		modsrc, err := regsrc.ParseModuleSource(src)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		resp, err := client.ModuleVersions(context.Background(), modsrc)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if len(resp.Modules) != 1 {
+			t.Fatal("expected 1 module, got", len(resp.Modules))
+		}
+
+		mod := resp.Modules[0]
+		name := "test-versions/name/provider"
+		if mod.Source != name {
+			t.Fatalf("expected module name %q, got %q", name, mod.Source)
+		}
+
+		if len(mod.Versions) != 4 {
+			t.Fatal("expected 4 versions, got", len(mod.Versions))
+		}
+
+		for _, v := range mod.Versions {
+			_, err := version.NewVersion(v.Version)
+			if err != nil {
+				t.Fatalf("invalid version %q: %s", v.Version, err)
+			}
+		}
+	}
+}
+
+func TestInvalidRegistry(t *testing.T) {
+	server := test.Registry()
+	defer server.Close()
+
+	client := NewClient(test.Disco(server), nil)
+
+	src := "non-existent.localhost.localdomain/test-versions/name/provider"
+	modsrc, err := regsrc.ParseModuleSource(src)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err := client.ModuleVersions(context.Background(), modsrc); err == nil {
+		t.Fatal("expected error")
+	}
+}
+
+func TestRegistryAuth(t *testing.T) {
+	server := test.Registry()
+	defer server.Close()
+
+	client := NewClient(test.Disco(server), nil)
+
+	src := "private/name/provider"
+	mod, err := regsrc.ParseModuleSource(src)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = client.ModuleVersions(context.Background(), mod)
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = client.ModuleLocation(context.Background(), mod, "1.0.0")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Also test without a credentials source
+	client.services.SetCredentialsSource(nil)
+
+	// both should fail without auth
+	_, err = client.ModuleVersions(context.Background(), mod)
+	if err == nil {
+		t.Fatal("expected error")
+	}
+	_, err = client.ModuleLocation(context.Background(), mod, "1.0.0")
+	if err == nil {
+		t.Fatal("expected error")
+	}
+}
+
+func TestLookupModuleLocationRelative(t *testing.T) {
+	server := test.Registry()
+	defer server.Close()
+
+	client := NewClient(test.Disco(server), nil)
+
+	src := "relative/foo/bar"
+	mod, err := regsrc.ParseModuleSource(src)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	got, err := client.ModuleLocation(context.Background(), mod, "0.2.0")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	want := server.URL + "/relative-path"
+	if got != want {
+		t.Errorf("wrong location %s; want %s", got, want)
+	}
+}
+
+func TestAccLookupModuleVersions(t *testing.T) {
+	if os.Getenv("TF_ACC") == "" {
+		t.Skip()
+	}
+	regDisco := disco.New()
+	regDisco.SetUserAgent(httpclient.TerraformUserAgent(tfversion.String()))
+
+	// test with and without a hostname
+	for _, src := range []string{
+		"terraform-aws-modules/vpc/aws",
+		regsrc.PublicRegistryHost.String() + "/terraform-aws-modules/vpc/aws",
+	} {
+		modsrc, err := regsrc.ParseModuleSource(src)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		s := NewClient(regDisco, nil)
+		resp, err := s.ModuleVersions(context.Background(), modsrc)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if len(resp.Modules) != 1 {
+			t.Fatal("expected 1 module, got", len(resp.Modules))
+		}
+
+		mod := resp.Modules[0]
+		name := "terraform-aws-modules/vpc/aws"
+		if mod.Source != name {
+			t.Fatalf("expected module name %q, got %q", name, mod.Source)
+		}
+
+		if len(mod.Versions) == 0 {
+			t.Fatal("expected multiple versions, got 0")
+		}
+
+		for _, v := range mod.Versions {
+			_, err := version.NewVersion(v.Version)
+			if err != nil {
+				t.Fatalf("invalid version %q: %s", v.Version, err)
+			}
+		}
+	}
+}
+
+// the error should reference the config source exactly, not the discovered path.
+func TestLookupLookupModuleError(t *testing.T) {
+	server := test.Registry()
+	defer server.Close()
+
+	client := NewClient(test.Disco(server), nil)
+
+	// this should not be found in the registry
+	src := "bad/local/path"
+	mod, err := regsrc.ParseModuleSource(src)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Instrument CheckRetry to make sure 404s are not retried
+	retries := 0
+	oldCheck := client.client.CheckRetry
+	client.client.CheckRetry = func(ctx context.Context, resp *http.Response, err error) (bool, error) {
+		if retries > 0 {
+			t.Fatal("retried after module not found")
+		}
+		retries++
+		return oldCheck(ctx, resp, err)
+	}
+
+	_, err = client.ModuleLocation(context.Background(), mod, "0.2.0")
+	if err == nil {
+		t.Fatal("expected error")
+	}
+
+	// check for the exact quoted string to ensure we didn't prepend a hostname.
+	if !strings.Contains(err.Error(), `"bad/local/path"`) {
+		t.Fatal("error should not include the hostname. got:", err)
+	}
+}
+
+func TestLookupModuleRetryError(t *testing.T) {
+	server := test.RegistryRetryableErrorsServer()
+	defer server.Close()
+
+	client := NewClient(test.Disco(server), nil)
+
+	src := "example.com/test-versions/name/provider"
+	modsrc, err := regsrc.ParseModuleSource(src)
+	if err != nil {
+		t.Fatal(err)
+	}
+	resp, err := client.ModuleVersions(context.Background(), modsrc)
+	if err == nil {
+		t.Fatal("expected requests to exceed retry", err)
+	}
+	if resp != nil {
+		t.Fatal("unexpected response", *resp)
+	}
+
+	// verify maxRetryErrorHandler handler returned the error
+	if !strings.Contains(err.Error(), "the request failed after 2 attempts, please try again later") {
+		t.Fatal("unexpected error, got:", err)
+	}
+}
+
+func TestLookupModuleNoRetryError(t *testing.T) {
+	// Disable retries
+	discoveryRetry = 0
+	defer configureDiscoveryRetry()
+
+	server := test.RegistryRetryableErrorsServer()
+	defer server.Close()
+
+	client := NewClient(test.Disco(server), nil)
+
+	src := "example.com/test-versions/name/provider"
+	modsrc, err := regsrc.ParseModuleSource(src)
+	if err != nil {
+		t.Fatal(err)
+	}
+	resp, err := client.ModuleVersions(context.Background(), modsrc)
+	if err == nil {
+		t.Fatal("expected request to fail", err)
+	}
+	if resp != nil {
+		t.Fatal("unexpected response", *resp)
+	}
+
+	// verify maxRetryErrorHandler handler returned the error
+	if !strings.Contains(err.Error(), "the request failed, please try again later") {
+		t.Fatal("unexpected error, got:", err)
+	}
+}
+
+func TestLookupModuleNetworkError(t *testing.T) {
+	server := test.RegistryRetryableErrorsServer()
+	client := NewClient(test.Disco(server), nil)
+
+	// Shut down the server to simulate network failure
+	server.Close()
+
+	src := "example.com/test-versions/name/provider"
+	modsrc, err := regsrc.ParseModuleSource(src)
+	if err != nil {
+		t.Fatal(err)
+	}
+	resp, err := client.ModuleVersions(context.Background(), modsrc)
+	if err == nil {
+		t.Fatal("expected request to fail", err)
+	}
+	if resp != nil {
+		t.Fatal("unexpected response", *resp)
+	}
+
+	// verify maxRetryErrorHandler handler returned the correct error
+	if !strings.Contains(err.Error(), "the request failed after 2 attempts, please try again later") {
+		t.Fatal("unexpected error, got:", err)
+	}
+}
diff --git a/v1.5.7/internal/registry/errors.go b/v1.5.7/internal/registry/errors.go
new file mode 100644
index 0000000..45b65de
--- /dev/null
+++ b/v1.5.7/internal/registry/errors.go
@@ -0,0 +1,50 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package registry
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/registry/regsrc"
+)
+
+type errModuleNotFound struct {
+	addr *regsrc.Module
+}
+
+func (e *errModuleNotFound) Error() string {
+	return fmt.Sprintf("module %s not found", e.addr)
+}
+
+// IsModuleNotFound returns true only if the given error is a "module not found"
+// error. This allows callers to recognize this particular error condition
+// as distinct from operational errors such as poor network connectivity.
+func IsModuleNotFound(err error) bool {
+	_, ok := err.(*errModuleNotFound)
+	return ok
+}
+
+// IsServiceNotProvided returns true only if the given error is a "service not provided"
+// error. This allows callers to recognize this particular error condition
+// as distinct from operational errors such as poor network connectivity.
+func IsServiceNotProvided(err error) bool {
+	_, ok := err.(*disco.ErrServiceNotProvided)
+	return ok
+}
+
+// ServiceUnreachableError Registry service is unreachable
+type ServiceUnreachableError struct {
+	err error
+}
+
+func (e *ServiceUnreachableError) Error() string {
+	return e.err.Error()
+}
+
+// IsServiceUnreachable returns true if the registry/discovery service was unreachable
+func IsServiceUnreachable(err error) bool {
+	_, ok := err.(*ServiceUnreachableError)
+	return ok
+}
diff --git a/v1.5.7/internal/registry/regsrc/friendly_host.go b/v1.5.7/internal/registry/regsrc/friendly_host.go
new file mode 100644
index 0000000..8430e3c
--- /dev/null
+++ b/v1.5.7/internal/registry/regsrc/friendly_host.go
@@ -0,0 +1,143 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package regsrc
+
+import (
+	"regexp"
+	"strings"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+)
+
+var (
+	// InvalidHostString is a placeholder returned when a raw host can't be
+	// converted by IDNA spec. It will never be returned for any host for which
+	// Valid() is true.
+	InvalidHostString = "<invalid host>"
+
+	// urlLabelEndSubRe is a sub-expression that matches any character that's
+	// allowed at the start or end of a URL label according to RFC1123.
+	urlLabelEndSubRe = "[0-9A-Za-z]"
+
+	// urlLabelEndSubRe is a sub-expression that matches any character that's
+	// allowed at in a non-start or end of a URL label according to RFC1123.
+	urlLabelMidSubRe = "[0-9A-Za-z-]"
+
+	// urlLabelUnicodeSubRe is a sub-expression that matches any non-ascii char
+	// in an IDN (Unicode) display URL. It's not strict - there are only ~15k
+	// valid Unicode points in IDN RFC (some with conditions). We are just going
+	// with being liberal with matching and then erroring if we fail to convert
+	// to punycode later (which validates chars fully). This at least ensures
+	// ascii chars dissalowed by the RC1123 parts above don't become legal
+	// again.
+	urlLabelUnicodeSubRe = "[^[:ascii:]]"
+
+	// hostLabelSubRe is the sub-expression that matches a valid hostname label.
+	// It does not anchor the start or end so it can be composed into more
+	// complex RegExps below. Note that for sanity we don't handle disallowing
+	// raw punycode in this regexp (esp. since re2 doesn't support negative
+	// lookbehind, but we can capture it's presence here to check later).
+	hostLabelSubRe = "" +
+		// Match valid initial char, or unicode char
+		"(?:" + urlLabelEndSubRe + "|" + urlLabelUnicodeSubRe + ")" +
+		// Optionally, match 0 to 61 valid URL or Unicode chars,
+		// followed by one valid end char or unicode char
+		"(?:" +
+		"(?:" + urlLabelMidSubRe + "|" + urlLabelUnicodeSubRe + "){0,61}" +
+		"(?:" + urlLabelEndSubRe + "|" + urlLabelUnicodeSubRe + ")" +
+		")?"
+
+	// hostSubRe is the sub-expression that matches a valid host prefix.
+	// Allows custom port.
+	hostSubRe = hostLabelSubRe + "(?:\\." + hostLabelSubRe + ")+(?::\\d+)?"
+
+	// hostRe is a regexp that matches a valid host prefix. Additional
+	// validation of unicode strings is needed for matches.
+	hostRe = regexp.MustCompile("^" + hostSubRe + "$")
+)
+
+// FriendlyHost describes a registry instance identified in source strings by a
+// simple bare hostname like registry.terraform.io.
+type FriendlyHost struct {
+	Raw string
+}
+
+func NewFriendlyHost(host string) *FriendlyHost {
+	return &FriendlyHost{Raw: host}
+}
+
+// ParseFriendlyHost attempts to parse a valid "friendly host" prefix from the
+// given string. If no valid prefix is found, host will be nil and rest will
+// contain the full source string. The host prefix must terminate at the end of
+// the input or at the first / character. If one or more characters exist after
+// the first /, they will be returned as rest (without the / delimiter).
+// Hostnames containing punycode WILL be parsed successfully since they may have
+// come from an internal normalized source string, however should be considered
+// invalid if the string came from a user directly. This must be checked
+// explicitly for user-input strings by calling Valid() on the
+// returned host.
+func ParseFriendlyHost(source string) (host *FriendlyHost, rest string) {
+	parts := strings.SplitN(source, "/", 2)
+
+	if hostRe.MatchString(parts[0]) {
+		host = &FriendlyHost{Raw: parts[0]}
+		if len(parts) == 2 {
+			rest = parts[1]
+		}
+		return
+	}
+
+	// No match, return whole string as rest along with nil host
+	rest = source
+	return
+}
+
+// Valid returns whether the host prefix is considered valid in any case.
+// Example of invalid prefixes might include ones that don't conform to the host
+// name specifications. Not that IDN prefixes containing punycode are not valid
+// input which we expect to always be in user-input or normalised display form.
+func (h *FriendlyHost) Valid() bool {
+	return svchost.IsValid(h.Raw)
+}
+
+// Display returns the host formatted for display to the user in CLI or web
+// output.
+func (h *FriendlyHost) Display() string {
+	return svchost.ForDisplay(h.Raw)
+}
+
+// Normalized returns the host formatted for internal reference or comparison.
+func (h *FriendlyHost) Normalized() string {
+	host, err := svchost.ForComparison(h.Raw)
+	if err != nil {
+		return InvalidHostString
+	}
+	return string(host)
+}
+
+// String returns the host formatted as the user originally typed it assuming it
+// was parsed from user input.
+func (h *FriendlyHost) String() string {
+	return h.Raw
+}
+
+// Equal compares the FriendlyHost against another instance taking normalization
+// into account. Invalid hosts cannot be compared and will always return false.
+func (h *FriendlyHost) Equal(other *FriendlyHost) bool {
+	if other == nil {
+		return false
+	}
+
+	otherHost, err := svchost.ForComparison(other.Raw)
+	if err != nil {
+		return false
+	}
+
+	host, err := svchost.ForComparison(h.Raw)
+	if err != nil {
+		return false
+	}
+
+	return otherHost == host
+}
diff --git a/v1.5.7/internal/registry/regsrc/friendly_host_test.go b/v1.5.7/internal/registry/regsrc/friendly_host_test.go
new file mode 100644
index 0000000..e320b27
--- /dev/null
+++ b/v1.5.7/internal/registry/regsrc/friendly_host_test.go
@@ -0,0 +1,144 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package regsrc
+
+import (
+	"strings"
+	"testing"
+)
+
+func TestFriendlyHost(t *testing.T) {
+	tests := []struct {
+		name        string
+		source      string
+		wantHost    string
+		wantDisplay string
+		wantNorm    string
+		wantValid   bool
+	}{
+		{
+			name:        "simple ascii",
+			source:      "registry.terraform.io",
+			wantHost:    "registry.terraform.io",
+			wantDisplay: "registry.terraform.io",
+			wantNorm:    "registry.terraform.io",
+			wantValid:   true,
+		},
+		{
+			name:        "mixed-case ascii",
+			source:      "Registry.TerraForm.io",
+			wantHost:    "Registry.TerraForm.io",
+			wantDisplay: "registry.terraform.io", // Display case folded
+			wantNorm:    "registry.terraform.io",
+			wantValid:   true,
+		},
+		{
+			name:        "IDN",
+			source:      "ʎɹʇsıƃǝɹ.ɯɹoɟɐɹɹǝʇ.io",
+			wantHost:    "ʎɹʇsıƃǝɹ.ɯɹoɟɐɹɹǝʇ.io",
+			wantDisplay: "ʎɹʇsıƃǝɹ.ɯɹoɟɐɹɹǝʇ.io",
+			wantNorm:    "xn--s-fka0wmm0zea7g8b.xn--o-8ta85a3b1dwcda1k.io",
+			wantValid:   true,
+		},
+		{
+			name:        "IDN TLD",
+			source:      "zhongwen.中国",
+			wantHost:    "zhongwen.中国",
+			wantDisplay: "zhongwen.中国",
+			wantNorm:    "zhongwen.xn--fiqs8s",
+			wantValid:   true,
+		},
+		{
+			name:        "IDN Case Folding",
+			source:      "Испытание.com",
+			wantHost:    "Испытание.com", // Raw input retains case
+			wantDisplay: "испытание.com", // Display form is unicode but case-folded
+			wantNorm:    "xn--80akhbyknj4f.com",
+			wantValid:   true,
+		},
+		{
+			name:        "Punycode is invalid as an input format",
+			source:      "xn--s-fka0wmm0zea7g8b.xn--o-8ta85a3b1dwcda1k.io",
+			wantHost:    "xn--s-fka0wmm0zea7g8b.xn--o-8ta85a3b1dwcda1k.io",
+			wantDisplay: "ʎɹʇsıƃǝɹ.ɯɹoɟɐɹɹǝʇ.io",
+			wantNorm:    InvalidHostString,
+			wantValid:   false,
+		},
+		{
+			name:        "non-host prefix is left alone",
+			source:      "foo/bar/baz",
+			wantHost:    "",
+			wantDisplay: "",
+			wantNorm:    "",
+			wantValid:   false,
+		},
+	}
+	for _, tt := range tests {
+		// Matrix each test with prefix and total match variants
+		for _, sfx := range []string{"", "/", "/foo/bar/baz"} {
+			t.Run(tt.name+" suffix:"+sfx, func(t *testing.T) {
+				gotHost, gotRest := ParseFriendlyHost(tt.source + sfx)
+
+				if gotHost == nil {
+					if tt.wantHost != "" {
+						t.Fatalf("ParseFriendlyHost() gotHost = nil, want %v", tt.wantHost)
+					}
+					// If we return nil host, the whole input string should be in rest
+					if gotRest != (tt.source + sfx) {
+						t.Fatalf("ParseFriendlyHost() was nil rest = %s, want %v", gotRest, tt.source+sfx)
+					}
+					return
+				}
+
+				if tt.wantHost == "" {
+					t.Fatalf("ParseFriendlyHost() gotHost.Raw = %v, want nil", gotHost.Raw)
+				}
+
+				if v := gotHost.String(); v != tt.wantHost {
+					t.Fatalf("String() = %v, want %v", v, tt.wantHost)
+				}
+				if v := gotHost.Display(); v != tt.wantDisplay {
+					t.Fatalf("Display() = %v, want %v", v, tt.wantDisplay)
+				}
+				if v := gotHost.Normalized(); v != tt.wantNorm {
+					t.Fatalf("Normalized() = %v, want %v", v, tt.wantNorm)
+				}
+				if v := gotHost.Valid(); v != tt.wantValid {
+					t.Fatalf("Valid() = %v, want %v", v, tt.wantValid)
+				}
+				if gotRest != strings.TrimLeft(sfx, "/") {
+					t.Fatalf("ParseFriendlyHost() rest = %v, want %v", gotRest, strings.TrimLeft(sfx, "/"))
+				}
+
+				// Also verify that host compares equal with all the variants.
+				if gotHost.Valid() && !gotHost.Equal(&FriendlyHost{Raw: tt.wantDisplay}) {
+					t.Fatalf("Equal() should be true for %s and %s", tt.wantHost, tt.wantDisplay)
+				}
+			})
+		}
+	}
+}
+
+func TestInvalidHostEquals(t *testing.T) {
+	invalid := NewFriendlyHost("NOT_A_HOST_NAME")
+	valid := PublicRegistryHost
+
+	// invalid hosts are not comparable
+	if invalid.Equal(invalid) {
+		t.Fatal("invalid host names are not comparable")
+	}
+
+	if valid.Equal(invalid) {
+		t.Fatalf("%q is not equal to %q", valid, invalid)
+	}
+
+	puny := NewFriendlyHost("xn--s-fka0wmm0zea7g8b.xn--o-8ta85a3b1dwcda1k.io")
+	display := NewFriendlyHost("ʎɹʇsıƃǝɹ.ɯɹoɟɐɹɹǝʇ.io")
+
+	// The pre-normalized host is not a valid source, and therefore not
+	// comparable to the display version.
+	if display.Equal(puny) {
+		t.Fatalf("invalid host %q should not be comparable", puny)
+	}
+}
diff --git a/v1.5.7/internal/registry/regsrc/module.go b/v1.5.7/internal/registry/regsrc/module.go
new file mode 100644
index 0000000..a0cfef9
--- /dev/null
+++ b/v1.5.7/internal/registry/regsrc/module.go
@@ -0,0 +1,248 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package regsrc
+
+import (
+	"errors"
+	"fmt"
+	"regexp"
+	"strings"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+var (
+	ErrInvalidModuleSource = errors.New("not a valid registry module source")
+
+	// nameSubRe is the sub-expression that matches a valid module namespace or
+	// name. It's strictly a super-set of what GitHub allows for user/org and
+	// repo names respectively, but more restrictive than our original repo-name
+	// regex which allowed periods but could cause ambiguity with hostname
+	// prefixes. It does not anchor the start or end so it can be composed into
+	// more complex RegExps below. Alphanumeric with - and _ allowed in non
+	// leading or trailing positions. Max length 64 chars. (GitHub username is
+	// 38 max.)
+	nameSubRe = "[0-9A-Za-z](?:[0-9A-Za-z-_]{0,62}[0-9A-Za-z])?"
+
+	// providerSubRe is the sub-expression that matches a valid provider. It
+	// does not anchor the start or end so it can be composed into more complex
+	// RegExps below. Only lowercase chars and digits are supported in practice.
+	// Max length 64 chars.
+	providerSubRe = "[0-9a-z]{1,64}"
+
+	// moduleSourceRe is a regular expression that matches the basic
+	// namespace/name/provider[//...] format for registry sources. It assumes
+	// any FriendlyHost prefix has already been removed if present.
+	moduleSourceRe = regexp.MustCompile(
+		fmt.Sprintf("^(%s)\\/(%s)\\/(%s)(?:\\/\\/(.*))?$",
+			nameSubRe, nameSubRe, providerSubRe))
+
+	// NameRe is a regular expression defining the format allowed for namespace
+	// or name fields in module registry implementations.
+	NameRe = regexp.MustCompile("^" + nameSubRe + "$")
+
+	// ProviderRe is a regular expression defining the format allowed for
+	// provider fields in module registry implementations.
+	ProviderRe = regexp.MustCompile("^" + providerSubRe + "$")
+
+	// these hostnames are not allowed as registry sources, because they are
+	// already special case module sources in terraform.
+	disallowed = map[string]bool{
+		"github.com":    true,
+		"bitbucket.org": true,
+	}
+)
+
+// Module describes a Terraform Registry Module source.
+type Module struct {
+	// RawHost is the friendly host prefix if one was present. It might be nil
+	// if the original source had no host prefix which implies
+	// PublicRegistryHost but is distinct from having an actual pointer to
+	// PublicRegistryHost since it encodes the fact the original string didn't
+	// include a host prefix at all which is significant for recovering actual
+	// input not just normalized form. Most callers should access it with Host()
+	// which will return public registry host instance if it's nil.
+	RawHost      *FriendlyHost
+	RawNamespace string
+	RawName      string
+	RawProvider  string
+	RawSubmodule string
+}
+
+// NewModule construct a new module source from separate parts. Pass empty
+// string if host or submodule are not needed.
+func NewModule(host, namespace, name, provider, submodule string) (*Module, error) {
+	m := &Module{
+		RawNamespace: namespace,
+		RawName:      name,
+		RawProvider:  provider,
+		RawSubmodule: submodule,
+	}
+	if host != "" {
+		h := NewFriendlyHost(host)
+		if h != nil {
+			fmt.Println("HOST:", h)
+			if !h.Valid() || disallowed[h.Display()] {
+				return nil, ErrInvalidModuleSource
+			}
+		}
+		m.RawHost = h
+	}
+	return m, nil
+}
+
+// ModuleFromModuleSourceAddr is an adapter to automatically transform the
+// modern representation of registry module addresses,
+// addrs.ModuleSourceRegistry, into the legacy representation regsrc.Module.
+//
+// Note that the new-style model always does normalization during parsing and
+// does not preserve the raw user input at all, and so although the fields
+// of regsrc.Module are all called "Raw...", initializing a Module indirectly
+// through an addrs.ModuleSourceRegistry will cause those values to be the
+// normalized ones, not the raw user input.
+//
+// Use this only for temporary shims to call into existing code that still
+// uses regsrc.Module. Eventually all other subsystems should be updated to
+// use addrs.ModuleSourceRegistry instead, and then package regsrc can be
+// removed altogether.
+func ModuleFromModuleSourceAddr(addr addrs.ModuleSourceRegistry) *Module {
+	ret := ModuleFromRegistryPackageAddr(addr.Package)
+	ret.RawSubmodule = addr.Subdir
+	return ret
+}
+
+// ModuleFromRegistryPackageAddr is similar to ModuleFromModuleSourceAddr, but
+// it works with just the isolated registry package address, and not the
+// full source address.
+//
+// The practical implication of that is that RawSubmodule will always be
+// the empty string in results from this function, because "Submodule" maps
+// to "Subdir" and that's a module source address concept, not a module
+// package concept. In practice this typically doesn't matter because the
+// registry client ignores the RawSubmodule field anyway; that's a concern
+// for the higher-level module installer to deal with.
+func ModuleFromRegistryPackageAddr(addr addrs.ModuleRegistryPackage) *Module {
+	return &Module{
+		RawHost:      NewFriendlyHost(addr.Host.String()),
+		RawNamespace: addr.Namespace,
+		RawName:      addr.Name,
+		RawProvider:  addr.TargetSystem, // this field was never actually enforced to be a provider address, so now has a more general name
+	}
+}
+
+// ParseModuleSource attempts to parse source as a Terraform registry module
+// source. If the string is not found to be in a valid format,
+// ErrInvalidModuleSource is returned. Note that this can only be used on
+// "input" strings, e.g. either ones supplied by the user or potentially
+// normalised but in Display form (unicode). It will fail to parse a source with
+// a punycoded domain since this is not permitted input from a user. If you have
+// an already normalized string internally, you can compare it without parsing
+// by comparing with the normalized version of the subject with the normal
+// string equality operator.
+func ParseModuleSource(source string) (*Module, error) {
+	// See if there is a friendly host prefix.
+	host, rest := ParseFriendlyHost(source)
+	if host != nil {
+		if !host.Valid() || disallowed[host.Display()] {
+			return nil, ErrInvalidModuleSource
+		}
+	}
+
+	matches := moduleSourceRe.FindStringSubmatch(rest)
+	if len(matches) < 4 {
+		return nil, ErrInvalidModuleSource
+	}
+
+	m := &Module{
+		RawHost:      host,
+		RawNamespace: matches[1],
+		RawName:      matches[2],
+		RawProvider:  matches[3],
+	}
+
+	if len(matches) == 5 {
+		m.RawSubmodule = matches[4]
+	}
+
+	return m, nil
+}
+
+// Display returns the source formatted for display to the user in CLI or web
+// output.
+func (m *Module) Display() string {
+	return m.formatWithPrefix(m.normalizedHostPrefix(m.Host().Display()), false)
+}
+
+// Normalized returns the source formatted for internal reference or comparison.
+func (m *Module) Normalized() string {
+	return m.formatWithPrefix(m.normalizedHostPrefix(m.Host().Normalized()), false)
+}
+
+// String returns the source formatted as the user originally typed it assuming
+// it was parsed from user input.
+func (m *Module) String() string {
+	// Don't normalize public registry hostname - leave it exactly like the user
+	// input it.
+	hostPrefix := ""
+	if m.RawHost != nil {
+		hostPrefix = m.RawHost.String() + "/"
+	}
+	return m.formatWithPrefix(hostPrefix, true)
+}
+
+// Equal compares the module source against another instance taking
+// normalization into account.
+func (m *Module) Equal(other *Module) bool {
+	return m.Normalized() == other.Normalized()
+}
+
+// Host returns the FriendlyHost object describing which registry this module is
+// in. If the original source string had not host component this will return the
+// PublicRegistryHost.
+func (m *Module) Host() *FriendlyHost {
+	if m.RawHost == nil {
+		return PublicRegistryHost
+	}
+	return m.RawHost
+}
+
+func (m *Module) normalizedHostPrefix(host string) string {
+	if m.Host().Equal(PublicRegistryHost) {
+		return ""
+	}
+	return host + "/"
+}
+
+func (m *Module) formatWithPrefix(hostPrefix string, preserveCase bool) string {
+	suffix := ""
+	if m.RawSubmodule != "" {
+		suffix = "//" + m.RawSubmodule
+	}
+	str := fmt.Sprintf("%s%s/%s/%s%s", hostPrefix, m.RawNamespace, m.RawName,
+		m.RawProvider, suffix)
+
+	// lower case by default
+	if !preserveCase {
+		return strings.ToLower(str)
+	}
+	return str
+}
+
+// Module returns just the registry ID of the module, without a hostname or
+// suffix.
+func (m *Module) Module() string {
+	return fmt.Sprintf("%s/%s/%s", m.RawNamespace, m.RawName, m.RawProvider)
+}
+
+// SvcHost returns the svchost.Hostname for this module. Since FriendlyHost may
+// contain an invalid hostname, this also returns an error indicating if it
+// could be converted to a svchost.Hostname. If no host is specified, the
+// default PublicRegistryHost is returned.
+func (m *Module) SvcHost() (svchost.Hostname, error) {
+	if m.RawHost == nil {
+		return svchost.ForComparison(PublicRegistryHost.Raw)
+	}
+	return svchost.ForComparison(m.RawHost.Raw)
+}
diff --git a/v1.5.7/internal/registry/regsrc/module_test.go b/v1.5.7/internal/registry/regsrc/module_test.go
new file mode 100644
index 0000000..38e6cc9
--- /dev/null
+++ b/v1.5.7/internal/registry/regsrc/module_test.go
@@ -0,0 +1,144 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package regsrc
+
+import (
+	"testing"
+)
+
+func TestModule(t *testing.T) {
+	tests := []struct {
+		name        string
+		source      string
+		wantString  string
+		wantDisplay string
+		wantNorm    string
+		wantErr     bool
+	}{
+		{
+			name:        "public registry",
+			source:      "hashicorp/consul/aws",
+			wantString:  "hashicorp/consul/aws",
+			wantDisplay: "hashicorp/consul/aws",
+			wantNorm:    "hashicorp/consul/aws",
+			wantErr:     false,
+		},
+		{
+			name:        "public registry, submodule",
+			source:      "hashicorp/consul/aws//foo",
+			wantString:  "hashicorp/consul/aws//foo",
+			wantDisplay: "hashicorp/consul/aws//foo",
+			wantNorm:    "hashicorp/consul/aws//foo",
+			wantErr:     false,
+		},
+		{
+			name:        "public registry, explicit host",
+			source:      "registry.terraform.io/hashicorp/consul/aws",
+			wantString:  "registry.terraform.io/hashicorp/consul/aws",
+			wantDisplay: "hashicorp/consul/aws",
+			wantNorm:    "hashicorp/consul/aws",
+			wantErr:     false,
+		},
+		{
+			name:        "public registry, mixed case",
+			source:      "HashiCorp/Consul/aws",
+			wantString:  "HashiCorp/Consul/aws",
+			wantDisplay: "hashicorp/consul/aws",
+			wantNorm:    "hashicorp/consul/aws",
+			wantErr:     false,
+		},
+		{
+			name:        "private registry, custom port",
+			source:      "Example.com:1234/HashiCorp/Consul/aws",
+			wantString:  "Example.com:1234/HashiCorp/Consul/aws",
+			wantDisplay: "example.com:1234/hashicorp/consul/aws",
+			wantNorm:    "example.com:1234/hashicorp/consul/aws",
+			wantErr:     false,
+		},
+		{
+			name:        "IDN registry",
+			source:      "Испытание.com/HashiCorp/Consul/aws",
+			wantString:  "Испытание.com/HashiCorp/Consul/aws",
+			wantDisplay: "испытание.com/hashicorp/consul/aws",
+			wantNorm:    "xn--80akhbyknj4f.com/hashicorp/consul/aws",
+			wantErr:     false,
+		},
+		{
+			name:       "IDN registry, submodule, custom port",
+			source:     "Испытание.com:1234/HashiCorp/Consul/aws//Foo",
+			wantString: "Испытание.com:1234/HashiCorp/Consul/aws//Foo",
+			// Note we DO lowercase submodule names. This might causes issues on
+			// some filesystems (e.g. HFS+) that are case-sensitive where
+			// //modules/Foo and //modules/foo describe different paths, but
+			// it's less confusing in general just to not support that. Any user
+			// with a module with submodules in both cases is already asking for
+			// portability issues, and terraform can ensure it does
+			// case-insensitive search for the dir in those cases.
+			wantDisplay: "испытание.com:1234/hashicorp/consul/aws//foo",
+			wantNorm:    "xn--80akhbyknj4f.com:1234/hashicorp/consul/aws//foo",
+			wantErr:     false,
+		},
+		{
+			name:    "invalid host",
+			source:  "---.com/HashiCorp/Consul/aws",
+			wantErr: true,
+		},
+		{
+			name:    "invalid format",
+			source:  "foo/var/baz/qux",
+			wantErr: true,
+		},
+		{
+			name:    "invalid suffix",
+			source:  "foo/var/baz?otherthing",
+			wantErr: true,
+		},
+		{
+			name:    "valid host, invalid format",
+			source:  "foo.com/var/baz?otherthing",
+			wantErr: true,
+		},
+		{
+			name:    "disallow github",
+			source:  "github.com/HashiCorp/Consul/aws",
+			wantErr: true,
+		},
+		{
+			name:    "disallow bitbucket",
+			source:  "bitbucket.org/HashiCorp/Consul/aws",
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := ParseModuleSource(tt.source)
+
+			if (err != nil) != tt.wantErr {
+				t.Fatalf("ParseModuleSource() error = %v, wantErr %v", err, tt.wantErr)
+			}
+
+			if err != nil {
+				return
+			}
+
+			if v := got.String(); v != tt.wantString {
+				t.Fatalf("String() = %v, want %v", v, tt.wantString)
+			}
+			if v := got.Display(); v != tt.wantDisplay {
+				t.Fatalf("Display() = %v, want %v", v, tt.wantDisplay)
+			}
+			if v := got.Normalized(); v != tt.wantNorm {
+				t.Fatalf("Normalized() = %v, want %v", v, tt.wantNorm)
+			}
+
+			gotDisplay, err := ParseModuleSource(tt.wantDisplay)
+			if err != nil {
+				t.Fatalf("ParseModuleSource(wantDisplay) error = %v", err)
+			}
+			if !got.Equal(gotDisplay) {
+				t.Fatalf("Equal() failed for %s and %s", tt.source, tt.wantDisplay)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/registry/regsrc/regsrc.go b/v1.5.7/internal/registry/regsrc/regsrc.go
new file mode 100644
index 0000000..98d6f4c
--- /dev/null
+++ b/v1.5.7/internal/registry/regsrc/regsrc.go
@@ -0,0 +1,11 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package regsrc provides helpers for working with source strings that identify
+// resources within a Terraform registry.
+package regsrc
+
+var (
+	// PublicRegistryHost is a FriendlyHost that represents the public registry.
+	PublicRegistryHost = NewFriendlyHost("registry.terraform.io")
+)
diff --git a/v1.5.7/internal/registry/response/module.go b/v1.5.7/internal/registry/response/module.go
new file mode 100644
index 0000000..2705a97
--- /dev/null
+++ b/v1.5.7/internal/registry/response/module.go
@@ -0,0 +1,96 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package response
+
+import (
+	"time"
+)
+
+// Module is the response structure with the data for a single module version.
+type Module struct {
+	ID string `json:"id"`
+
+	//---------------------------------------------------------------
+	// Metadata about the overall module.
+
+	Owner       string    `json:"owner"`
+	Namespace   string    `json:"namespace"`
+	Name        string    `json:"name"`
+	Version     string    `json:"version"`
+	Provider    string    `json:"provider"`
+	Description string    `json:"description"`
+	Source      string    `json:"source"`
+	PublishedAt time.Time `json:"published_at"`
+	Downloads   int       `json:"downloads"`
+	Verified    bool      `json:"verified"`
+}
+
+// ModuleDetail represents a module in full detail.
+type ModuleDetail struct {
+	Module
+
+	//---------------------------------------------------------------
+	// Metadata about the overall module. This is only available when
+	// requesting the specific module (not in list responses).
+
+	// Root is the root module.
+	Root *ModuleSubmodule `json:"root"`
+
+	// Submodules are the other submodules that are available within
+	// this module.
+	Submodules []*ModuleSubmodule `json:"submodules"`
+
+	//---------------------------------------------------------------
+	// The fields below are only set when requesting this specific
+	// module. They are available to easily know all available versions
+	// and providers without multiple API calls.
+
+	Providers []string `json:"providers"` // All available providers
+	Versions  []string `json:"versions"`  // All versions
+}
+
+// ModuleSubmodule is the metadata about a specific submodule within
+// a module. This includes the root module as a special case.
+type ModuleSubmodule struct {
+	Path   string `json:"path"`
+	Readme string `json:"readme"`
+	Empty  bool   `json:"empty"`
+
+	Inputs       []*ModuleInput    `json:"inputs"`
+	Outputs      []*ModuleOutput   `json:"outputs"`
+	Dependencies []*ModuleDep      `json:"dependencies"`
+	Resources    []*ModuleResource `json:"resources"`
+}
+
+// ModuleInput is an input for a module.
+type ModuleInput struct {
+	Name        string `json:"name"`
+	Description string `json:"description"`
+	Default     string `json:"default"`
+}
+
+// ModuleOutput is an output for a module.
+type ModuleOutput struct {
+	Name        string `json:"name"`
+	Description string `json:"description"`
+}
+
+// ModuleDep is an output for a module.
+type ModuleDep struct {
+	Name    string `json:"name"`
+	Source  string `json:"source"`
+	Version string `json:"version"`
+}
+
+// ModuleProviderDep is the output for a provider dependency
+type ModuleProviderDep struct {
+	Name    string `json:"name"`
+	Version string `json:"version"`
+}
+
+// ModuleResource is an output for a module.
+type ModuleResource struct {
+	Name string `json:"name"`
+	Type string `json:"type"`
+}
diff --git a/v1.5.7/internal/registry/response/module_list.go b/v1.5.7/internal/registry/response/module_list.go
new file mode 100644
index 0000000..6a258fc
--- /dev/null
+++ b/v1.5.7/internal/registry/response/module_list.go
@@ -0,0 +1,10 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package response
+
+// ModuleList is the response structure for a pageable list of modules.
+type ModuleList struct {
+	Meta    PaginationMeta `json:"meta"`
+	Modules []*Module      `json:"modules"`
+}
diff --git a/v1.5.7/internal/registry/response/module_provider.go b/v1.5.7/internal/registry/response/module_provider.go
new file mode 100644
index 0000000..88d24d6
--- /dev/null
+++ b/v1.5.7/internal/registry/response/module_provider.go
@@ -0,0 +1,17 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package response
+
+// ModuleProvider represents a single provider for modules.
+type ModuleProvider struct {
+	Name        string `json:"name"`
+	Downloads   int    `json:"downloads"`
+	ModuleCount int    `json:"module_count"`
+}
+
+// ModuleProviderList is the response structure for a pageable list of ModuleProviders.
+type ModuleProviderList struct {
+	Meta      PaginationMeta    `json:"meta"`
+	Providers []*ModuleProvider `json:"providers"`
+}
diff --git a/v1.5.7/internal/registry/response/module_versions.go b/v1.5.7/internal/registry/response/module_versions.go
new file mode 100644
index 0000000..9350635
--- /dev/null
+++ b/v1.5.7/internal/registry/response/module_versions.go
@@ -0,0 +1,35 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package response
+
+// ModuleVersions is the response format that contains all metadata about module
+// versions needed for terraform CLI to resolve version constraints. See RFC
+// TF-042 for details on this format.
+type ModuleVersions struct {
+	Modules []*ModuleProviderVersions `json:"modules"`
+}
+
+// ModuleProviderVersions is the response format for a single module instance,
+// containing metadata about all versions and their dependencies.
+type ModuleProviderVersions struct {
+	Source   string           `json:"source"`
+	Versions []*ModuleVersion `json:"versions"`
+}
+
+// ModuleVersion is the output metadata for a given version needed by CLI to
+// resolve candidate versions to satisfy requirements.
+type ModuleVersion struct {
+	Version    string              `json:"version"`
+	Root       VersionSubmodule    `json:"root"`
+	Submodules []*VersionSubmodule `json:"submodules"`
+}
+
+// VersionSubmodule is the output metadata for a submodule within a given
+// version needed by CLI to resolve candidate versions to satisfy requirements.
+// When representing the Root in JSON the path is omitted.
+type VersionSubmodule struct {
+	Path         string               `json:"path,omitempty"`
+	Providers    []*ModuleProviderDep `json:"providers"`
+	Dependencies []*ModuleDep         `json:"dependencies"`
+}
diff --git a/v1.5.7/internal/registry/response/pagination.go b/v1.5.7/internal/registry/response/pagination.go
new file mode 100644
index 0000000..3e2d7ee
--- /dev/null
+++ b/v1.5.7/internal/registry/response/pagination.go
@@ -0,0 +1,68 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package response
+
+import (
+	"net/url"
+	"strconv"
+)
+
+// PaginationMeta is a structure included in responses for pagination.
+type PaginationMeta struct {
+	Limit         int    `json:"limit"`
+	CurrentOffset int    `json:"current_offset"`
+	NextOffset    *int   `json:"next_offset,omitempty"`
+	PrevOffset    *int   `json:"prev_offset,omitempty"`
+	NextURL       string `json:"next_url,omitempty"`
+	PrevURL       string `json:"prev_url,omitempty"`
+}
+
+// NewPaginationMeta populates pagination meta data from result parameters
+func NewPaginationMeta(offset, limit int, hasMore bool, currentURL string) PaginationMeta {
+	pm := PaginationMeta{
+		Limit:         limit,
+		CurrentOffset: offset,
+	}
+
+	// Calculate next/prev offsets, leave nil if not valid pages
+	nextOffset := offset + limit
+	if hasMore {
+		pm.NextOffset = &nextOffset
+	}
+
+	prevOffset := offset - limit
+	if prevOffset < 0 {
+		prevOffset = 0
+	}
+	if prevOffset < offset {
+		pm.PrevOffset = &prevOffset
+	}
+
+	// If URL format provided, populate URLs. Intentionally swallow URL errors for now, API should
+	// catch missing URLs if we call with bad URL arg (and we care about them being present).
+	if currentURL != "" && pm.NextOffset != nil {
+		pm.NextURL, _ = setQueryParam(currentURL, "offset", *pm.NextOffset, 0)
+	}
+	if currentURL != "" && pm.PrevOffset != nil {
+		pm.PrevURL, _ = setQueryParam(currentURL, "offset", *pm.PrevOffset, 0)
+	}
+
+	return pm
+}
+
+func setQueryParam(baseURL, key string, val, defaultVal int) (string, error) {
+	u, err := url.Parse(baseURL)
+	if err != nil {
+		return "", err
+	}
+	q := u.Query()
+	if val == defaultVal {
+		// elide param if it's the default value
+		q.Del(key)
+	} else {
+		q.Set(key, strconv.Itoa(val))
+	}
+	u.RawQuery = q.Encode()
+	return u.String(), nil
+}
diff --git a/v1.5.7/internal/registry/response/pagination_test.go b/v1.5.7/internal/registry/response/pagination_test.go
new file mode 100644
index 0000000..f0ea296
--- /dev/null
+++ b/v1.5.7/internal/registry/response/pagination_test.go
@@ -0,0 +1,121 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package response
+
+import (
+	"encoding/json"
+	"testing"
+)
+
+func prettyJSON(o interface{}) (string, error) {
+	bytes, err := json.MarshalIndent(o, "", "\t")
+	if err != nil {
+		return "", err
+	}
+	return string(bytes), nil
+}
+
+func TestNewPaginationMeta(t *testing.T) {
+	type args struct {
+		offset     int
+		limit      int
+		hasMore    bool
+		currentURL string
+	}
+	tests := []struct {
+		name     string
+		args     args
+		wantJSON string
+	}{
+		{
+			name: "first page",
+			args: args{0, 10, true, "http://foo.com/v1/bar"},
+			wantJSON: `{
+	"limit": 10,
+	"current_offset": 0,
+	"next_offset": 10,
+	"next_url": "http://foo.com/v1/bar?offset=10"
+}`,
+		},
+		{
+			name: "second page",
+			args: args{10, 10, true, "http://foo.com/v1/bar"},
+			wantJSON: `{
+	"limit": 10,
+	"current_offset": 10,
+	"next_offset": 20,
+	"prev_offset": 0,
+	"next_url": "http://foo.com/v1/bar?offset=20",
+	"prev_url": "http://foo.com/v1/bar"
+}`,
+		},
+		{
+			name: "last page",
+			args: args{40, 10, false, "http://foo.com/v1/bar"},
+			wantJSON: `{
+	"limit": 10,
+	"current_offset": 40,
+	"prev_offset": 30,
+	"prev_url": "http://foo.com/v1/bar?offset=30"
+}`,
+		},
+		{
+			name: "misaligned start ending exactly on boundary",
+			args: args{32, 10, false, "http://foo.com/v1/bar"},
+			wantJSON: `{
+	"limit": 10,
+	"current_offset": 32,
+	"prev_offset": 22,
+	"prev_url": "http://foo.com/v1/bar?offset=22"
+}`,
+		},
+		{
+			name: "misaligned start partially through first page",
+			args: args{5, 12, true, "http://foo.com/v1/bar"},
+			wantJSON: `{
+	"limit": 12,
+	"current_offset": 5,
+	"next_offset": 17,
+	"prev_offset": 0,
+	"next_url": "http://foo.com/v1/bar?offset=17",
+	"prev_url": "http://foo.com/v1/bar"
+}`,
+		},
+		{
+			name: "no current URL",
+			args: args{10, 10, true, ""},
+			wantJSON: `{
+	"limit": 10,
+	"current_offset": 10,
+	"next_offset": 20,
+	"prev_offset": 0
+}`,
+		},
+		{
+			name: "#58 regression test",
+			args: args{1, 3, true, ""},
+			wantJSON: `{
+	"limit": 3,
+	"current_offset": 1,
+	"next_offset": 4,
+	"prev_offset": 0
+}`,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := NewPaginationMeta(tt.args.offset, tt.args.limit, tt.args.hasMore,
+				tt.args.currentURL)
+			gotJSON, err := prettyJSON(got)
+			if err != nil {
+				t.Fatalf("failed to marshal PaginationMeta to JSON: %s", err)
+			}
+			if gotJSON != tt.wantJSON {
+				// prettyJSON makes debugging easier due to the annoying pointer-to-ints, but it
+				// also implicitly tests JSON marshalling as we can see if it's omitting fields etc.
+				t.Fatalf("NewPaginationMeta() =\n%s\n  want:\n%s\n", gotJSON, tt.wantJSON)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/registry/response/redirect.go b/v1.5.7/internal/registry/response/redirect.go
new file mode 100644
index 0000000..c320a1f
--- /dev/null
+++ b/v1.5.7/internal/registry/response/redirect.go
@@ -0,0 +1,9 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package response
+
+// Redirect causes the frontend to perform a window redirect.
+type Redirect struct {
+	URL string `json:"url"`
+}
diff --git a/v1.5.7/internal/registry/test/mock_registry.go b/v1.5.7/internal/registry/test/mock_registry.go
new file mode 100644
index 0000000..079df1b
--- /dev/null
+++ b/v1.5.7/internal/registry/test/mock_registry.go
@@ -0,0 +1,263 @@
+package test
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/http"
+	"net/http/httptest"
+	"os"
+	"regexp"
+	"strings"
+
+	svchost "github.com/hashicorp/terraform-svchost"
+	"github.com/hashicorp/terraform-svchost/auth"
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/httpclient"
+	"github.com/hashicorp/terraform/internal/registry/regsrc"
+	"github.com/hashicorp/terraform/internal/registry/response"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+// Disco return a *disco.Disco mapping registry.terraform.io, localhost,
+// localhost.localdomain, and example.com to the test server.
+func Disco(s *httptest.Server) *disco.Disco {
+	services := map[string]interface{}{
+		// Note that both with and without trailing slashes are supported behaviours
+		// TODO: add specific tests to enumerate both possibilities.
+		"modules.v1":   fmt.Sprintf("%s/v1/modules", s.URL),
+		"providers.v1": fmt.Sprintf("%s/v1/providers", s.URL),
+	}
+	d := disco.NewWithCredentialsSource(credsSrc)
+	d.SetUserAgent(httpclient.TerraformUserAgent(tfversion.String()))
+
+	d.ForceHostServices(svchost.Hostname("registry.terraform.io"), services)
+	d.ForceHostServices(svchost.Hostname("localhost"), services)
+	d.ForceHostServices(svchost.Hostname("localhost.localdomain"), services)
+	d.ForceHostServices(svchost.Hostname("example.com"), services)
+	return d
+}
+
+// Map of module names and location of test modules.
+// Only one version for now, as we only lookup latest from the registry.
+type testMod struct {
+	location string
+	version  string
+}
+
+// Map of provider names and location of test providers.
+// Only one version for now, as we only lookup latest from the registry.
+type testProvider struct {
+	version string
+	url     string
+}
+
+const (
+	testCred = "test-auth-token"
+)
+
+var (
+	regHost  = svchost.Hostname(regsrc.PublicRegistryHost.Normalized())
+	credsSrc = auth.StaticCredentialsSource(map[svchost.Hostname]map[string]interface{}{
+		regHost: {"token": testCred},
+	})
+)
+
+// All the locationes from the mockRegistry start with a file:// scheme. If
+// the the location string here doesn't have a scheme, the mockRegistry will
+// find the absolute path and return a complete URL.
+var testMods = map[string][]testMod{
+	"registry/foo/bar": {{
+		location: "file:///download/registry/foo/bar/0.2.3//*?archive=tar.gz",
+		version:  "0.2.3",
+	}},
+	"registry/foo/baz": {{
+		location: "file:///download/registry/foo/baz/1.10.0//*?archive=tar.gz",
+		version:  "1.10.0",
+	}},
+	"registry/local/sub": {{
+		location: "testdata/registry-tar-subdir/foo.tgz//*?archive=tar.gz",
+		version:  "0.1.2",
+	}},
+	"exists-in-registry/identifier/provider": {{
+		location: "file:///registry/exists",
+		version:  "0.2.0",
+	}},
+	"relative/foo/bar": {{ // There is an exception for the "relative/" prefix in the test registry server
+		location: "/relative-path",
+		version:  "0.2.0",
+	}},
+	"test-versions/name/provider": {
+		{version: "2.2.0"},
+		{version: "2.1.1"},
+		{version: "1.2.2"},
+		{version: "1.2.1"},
+	},
+	"private/name/provider": {
+		{version: "1.0.0"},
+	},
+}
+
+var testProviders = map[string][]testProvider{
+	"-/foo": {
+		{
+			version: "0.2.3",
+			url:     "https://releases.hashicorp.com/terraform-provider-foo/0.2.3/terraform-provider-foo.zip",
+		},
+		{version: "0.3.0"},
+	},
+	"-/bar": {
+		{
+			version: "0.1.1",
+			url:     "https://releases.hashicorp.com/terraform-provider-bar/0.1.1/terraform-provider-bar.zip",
+		},
+		{version: "0.1.2"},
+	},
+}
+
+func providerAlias(provider string) string {
+	re := regexp.MustCompile("^-/")
+	if re.MatchString(provider) {
+		return re.ReplaceAllString(provider, "terraform-providers/")
+	}
+	return provider
+}
+
+func init() {
+	// Add provider aliases
+	for provider, info := range testProviders {
+		alias := providerAlias(provider)
+		testProviders[alias] = info
+	}
+}
+
+func mockRegHandler() http.Handler {
+	mux := http.NewServeMux()
+
+	moduleDownload := func(w http.ResponseWriter, r *http.Request) {
+		p := strings.TrimLeft(r.URL.Path, "/")
+		// handle download request
+		re := regexp.MustCompile(`^([-a-z]+/\w+/\w+).*/download$`)
+		// download lookup
+		matches := re.FindStringSubmatch(p)
+		if len(matches) != 2 {
+			w.WriteHeader(http.StatusBadRequest)
+			return
+		}
+
+		// check for auth
+		if strings.Contains(matches[0], "private/") {
+			if !strings.Contains(r.Header.Get("Authorization"), testCred) {
+				http.Error(w, "", http.StatusForbidden)
+				return
+			}
+		}
+
+		versions, ok := testMods[matches[1]]
+		if !ok {
+			http.NotFound(w, r)
+			return
+		}
+		mod := versions[0]
+
+		location := mod.location
+		if !strings.HasPrefix(matches[0], "relative/") && !strings.HasPrefix(location, "file:///") {
+			// we can't use filepath.Abs because it will clean `//`
+			wd, _ := os.Getwd()
+			location = fmt.Sprintf("file://%s/%s", wd, location)
+		}
+
+		w.Header().Set("X-Terraform-Get", location)
+		w.WriteHeader(http.StatusNoContent)
+		// no body
+	}
+
+	moduleVersions := func(w http.ResponseWriter, r *http.Request) {
+		p := strings.TrimLeft(r.URL.Path, "/")
+		re := regexp.MustCompile(`^([-a-z]+/\w+/\w+)/versions$`)
+		matches := re.FindStringSubmatch(p)
+		if len(matches) != 2 {
+			w.WriteHeader(http.StatusBadRequest)
+			return
+		}
+
+		// check for auth
+		if strings.Contains(matches[1], "private/") {
+			if !strings.Contains(r.Header.Get("Authorization"), testCred) {
+				http.Error(w, "", http.StatusForbidden)
+			}
+		}
+
+		name := matches[1]
+		versions, ok := testMods[name]
+		if !ok {
+			http.NotFound(w, r)
+			return
+		}
+
+		// only adding the single requested module for now
+		// this is the minimal that any regisry is epected to support
+		mpvs := &response.ModuleProviderVersions{
+			Source: name,
+		}
+
+		for _, v := range versions {
+			mv := &response.ModuleVersion{
+				Version: v.version,
+			}
+			mpvs.Versions = append(mpvs.Versions, mv)
+		}
+
+		resp := response.ModuleVersions{
+			Modules: []*response.ModuleProviderVersions{mpvs},
+		}
+
+		js, err := json.Marshal(resp)
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
+		w.Header().Set("Content-Type", "application/json")
+		w.Write(js)
+	}
+
+	mux.Handle("/v1/modules/",
+		http.StripPrefix("/v1/modules/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+			if strings.HasSuffix(r.URL.Path, "/download") {
+				moduleDownload(w, r)
+				return
+			}
+
+			if strings.HasSuffix(r.URL.Path, "/versions") {
+				moduleVersions(w, r)
+				return
+			}
+
+			http.NotFound(w, r)
+		})),
+	)
+
+	mux.HandleFunc("/.well-known/terraform.json", func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/json")
+		io.WriteString(w, `{"modules.v1":"http://localhost/v1/modules/", "providers.v1":"http://localhost/v1/providers/"}`)
+	})
+	return mux
+}
+
+// Registry returns an httptest server that mocks out some registry functionality.
+func Registry() *httptest.Server {
+	return httptest.NewServer(mockRegHandler())
+}
+
+// RegistryRetryableErrorsServer returns an httptest server that mocks out the
+// registry API to return 502 errors.
+func RegistryRetryableErrorsServer() *httptest.Server {
+	mux := http.NewServeMux()
+	mux.HandleFunc("/v1/modules/", func(w http.ResponseWriter, r *http.Request) {
+		http.Error(w, "mocked server error", http.StatusBadGateway)
+	})
+	mux.HandleFunc("/v1/providers/", func(w http.ResponseWriter, r *http.Request) {
+		http.Error(w, "mocked server error", http.StatusBadGateway)
+	})
+	return httptest.NewServer(mux)
+}
diff --git a/v1.5.7/internal/repl/format.go b/v1.5.7/internal/repl/format.go
new file mode 100644
index 0000000..fcd0738
--- /dev/null
+++ b/v1.5.7/internal/repl/format.go
@@ -0,0 +1,176 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package repl
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// FormatValue formats a value in a way that resembles Terraform language syntax
+// and uses the type conversion functions where necessary to indicate exactly
+// what type it is given, so that equality test failures can be quickly
+// understood.
+func FormatValue(v cty.Value, indent int) string {
+	if !v.IsKnown() {
+		return "(known after apply)"
+	}
+	if v.HasMark(marks.Sensitive) {
+		return "(sensitive value)"
+	}
+	if v.IsNull() {
+		ty := v.Type()
+		switch {
+		case ty == cty.DynamicPseudoType:
+			return "null"
+		case ty == cty.String:
+			return "tostring(null)"
+		case ty == cty.Number:
+			return "tonumber(null)"
+		case ty == cty.Bool:
+			return "tobool(null)"
+		case ty.IsListType():
+			return fmt.Sprintf("tolist(null) /* of %s */", ty.ElementType().FriendlyName())
+		case ty.IsSetType():
+			return fmt.Sprintf("toset(null) /* of %s */", ty.ElementType().FriendlyName())
+		case ty.IsMapType():
+			return fmt.Sprintf("tomap(null) /* of %s */", ty.ElementType().FriendlyName())
+		default:
+			return fmt.Sprintf("null /* %s */", ty.FriendlyName())
+		}
+	}
+
+	ty := v.Type()
+	switch {
+	case ty.IsPrimitiveType():
+		switch ty {
+		case cty.String:
+			if formatted, isMultiline := formatMultilineString(v, indent); isMultiline {
+				return formatted
+			}
+			return strconv.Quote(v.AsString())
+		case cty.Number:
+			bf := v.AsBigFloat()
+			return bf.Text('f', -1)
+		case cty.Bool:
+			if v.True() {
+				return "true"
+			} else {
+				return "false"
+			}
+		}
+	case ty.IsObjectType():
+		return formatMappingValue(v, indent)
+	case ty.IsTupleType():
+		return formatSequenceValue(v, indent)
+	case ty.IsListType():
+		return fmt.Sprintf("tolist(%s)", formatSequenceValue(v, indent))
+	case ty.IsSetType():
+		return fmt.Sprintf("toset(%s)", formatSequenceValue(v, indent))
+	case ty.IsMapType():
+		return fmt.Sprintf("tomap(%s)", formatMappingValue(v, indent))
+	}
+
+	// Should never get here because there are no other types
+	return fmt.Sprintf("%#v", v)
+}
+
+func formatMultilineString(v cty.Value, indent int) (string, bool) {
+	str := v.AsString()
+	lines := strings.Split(str, "\n")
+	if len(lines) < 2 {
+		return "", false
+	}
+
+	// If the value is indented, we use the indented form of heredoc for readability.
+	operator := "<<"
+	if indent > 0 {
+		operator = "<<-"
+	}
+
+	// Default delimiter is "End Of Text" by convention
+	delimiter := "EOT"
+
+OUTER:
+	for {
+		// Check if any of the lines are in conflict with the delimiter. The
+		// parser allows leading and trailing whitespace, so we must remove it
+		// before comparison.
+		for _, line := range lines {
+			// If the delimiter matches a line, extend it and start again
+			if strings.TrimSpace(line) == delimiter {
+				delimiter = delimiter + "_"
+				continue OUTER
+			}
+		}
+
+		// None of the lines match the delimiter, so we're ready
+		break
+	}
+
+	// Write the heredoc, with indentation as appropriate.
+	var buf strings.Builder
+
+	buf.WriteString(operator)
+	buf.WriteString(delimiter)
+	for _, line := range lines {
+		buf.WriteByte('\n')
+		buf.WriteString(strings.Repeat(" ", indent))
+		buf.WriteString(line)
+	}
+	buf.WriteByte('\n')
+	buf.WriteString(strings.Repeat(" ", indent))
+	buf.WriteString(delimiter)
+
+	return buf.String(), true
+}
+
+func formatMappingValue(v cty.Value, indent int) string {
+	var buf strings.Builder
+	count := 0
+	buf.WriteByte('{')
+	indent += 2
+	for it := v.ElementIterator(); it.Next(); {
+		count++
+		k, v := it.Element()
+		buf.WriteByte('\n')
+		buf.WriteString(strings.Repeat(" ", indent))
+		buf.WriteString(FormatValue(k, indent))
+		buf.WriteString(" = ")
+		buf.WriteString(FormatValue(v, indent))
+	}
+	indent -= 2
+	if count > 0 {
+		buf.WriteByte('\n')
+		buf.WriteString(strings.Repeat(" ", indent))
+	}
+	buf.WriteByte('}')
+	return buf.String()
+}
+
+func formatSequenceValue(v cty.Value, indent int) string {
+	var buf strings.Builder
+	count := 0
+	buf.WriteByte('[')
+	indent += 2
+	for it := v.ElementIterator(); it.Next(); {
+		count++
+		_, v := it.Element()
+		buf.WriteByte('\n')
+		buf.WriteString(strings.Repeat(" ", indent))
+		buf.WriteString(FormatValue(v, indent))
+		buf.WriteByte(',')
+	}
+	indent -= 2
+	if count > 0 {
+		buf.WriteByte('\n')
+		buf.WriteString(strings.Repeat(" ", indent))
+	}
+	buf.WriteByte(']')
+	return buf.String()
+}
diff --git a/v1.5.7/internal/repl/format_test.go b/v1.5.7/internal/repl/format_test.go
new file mode 100644
index 0000000..3bdd2ec
--- /dev/null
+++ b/v1.5.7/internal/repl/format_test.go
@@ -0,0 +1,190 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package repl
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestFormatValue(t *testing.T) {
+	tests := []struct {
+		Val  cty.Value
+		Want string
+	}{
+		{
+			cty.NullVal(cty.DynamicPseudoType),
+			`null`,
+		},
+		{
+			cty.NullVal(cty.String),
+			`tostring(null)`,
+		},
+		{
+			cty.NullVal(cty.Number),
+			`tonumber(null)`,
+		},
+		{
+			cty.NullVal(cty.Bool),
+			`tobool(null)`,
+		},
+		{
+			cty.NullVal(cty.List(cty.String)),
+			`tolist(null) /* of string */`,
+		},
+		{
+			cty.NullVal(cty.Set(cty.Number)),
+			`toset(null) /* of number */`,
+		},
+		{
+			cty.NullVal(cty.Map(cty.Bool)),
+			`tomap(null) /* of bool */`,
+		},
+		{
+			cty.NullVal(cty.Object(map[string]cty.Type{"a": cty.Bool})),
+			`null /* object */`, // Ideally this would display the full object type, including its attributes
+		},
+		{
+			cty.UnknownVal(cty.DynamicPseudoType),
+			`(known after apply)`,
+		},
+		{
+			cty.StringVal(""),
+			`""`,
+		},
+		{
+			cty.StringVal("hello"),
+			`"hello"`,
+		},
+		{
+			cty.StringVal("hello\nworld"),
+			`<<EOT
+hello
+world
+EOT`,
+		},
+		{
+			cty.StringVal("EOR\nEOS\nEOT\nEOU"),
+			`<<EOT_
+EOR
+EOS
+EOT
+EOU
+EOT_`,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("boop\nbeep")}),
+			`{
+  "foo" = <<-EOT
+  boop
+  beep
+  EOT
+}`,
+		},
+		{
+			cty.Zero,
+			`0`,
+		},
+		{
+			cty.NumberIntVal(5),
+			`5`,
+		},
+		{
+			cty.NumberIntVal(1234567890),
+			`1234567890`,
+		},
+		{
+			cty.NumberFloatVal(5.2),
+			`5.2`,
+		},
+		{
+			cty.NumberFloatVal(123456789.0),
+			`123456789`,
+		},
+		{
+			cty.NumberFloatVal(123456789.01),
+			`123456789.01`,
+		},
+		{
+			cty.False,
+			`false`,
+		},
+		{
+			cty.True,
+			`true`,
+		},
+		{
+			cty.EmptyObjectVal,
+			`{}`,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("b"),
+			}),
+			`{
+  "a" = "b"
+}`,
+		},
+		{
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("b"),
+				"c": cty.StringVal("d"),
+			}),
+			`{
+  "a" = "b"
+  "c" = "d"
+}`,
+		},
+		{
+			cty.MapValEmpty(cty.String),
+			`tomap({})`,
+		},
+		{
+			cty.EmptyTupleVal,
+			`[]`,
+		},
+		{
+			cty.TupleVal([]cty.Value{
+				cty.StringVal("b"),
+			}),
+			`[
+  "b",
+]`,
+		},
+		{
+			cty.TupleVal([]cty.Value{
+				cty.StringVal("b"),
+				cty.StringVal("d"),
+			}),
+			`[
+  "b",
+  "d",
+]`,
+		},
+		{
+			cty.ListValEmpty(cty.String),
+			`tolist([])`,
+		},
+		{
+			cty.SetValEmpty(cty.String),
+			`toset([])`,
+		},
+		{
+			cty.StringVal("a sensitive value").Mark(marks.Sensitive),
+			"(sensitive value)",
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%#v", test.Val), func(t *testing.T) {
+			got := FormatValue(test.Val, 0)
+			if got != test.Want {
+				t.Errorf("wrong result\nvalue: %#v\ngot:   %s\nwant:  %s", test.Val, got, test.Want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/repl/repl.go b/v1.5.7/internal/repl/repl.go
new file mode 100644
index 0000000..d4853e1
--- /dev/null
+++ b/v1.5.7/internal/repl/repl.go
@@ -0,0 +1,7 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package repl provides the structs and functions necessary to run
+// REPL for Terraform. The REPL allows experimentation of Terraform
+// interpolations without having to run a Terraform configuration.
+package repl
diff --git a/v1.5.7/internal/repl/session.go b/v1.5.7/internal/repl/session.go
new file mode 100644
index 0000000..0b8789b
--- /dev/null
+++ b/v1.5.7/internal/repl/session.go
@@ -0,0 +1,208 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package repl
+
+import (
+	"fmt"
+	"sort"
+	"strings"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/lang/types"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Session represents the state for a single REPL session.
+type Session struct {
+	// Scope is the evaluation scope where expressions will be evaluated.
+	Scope *lang.Scope
+}
+
+// Handle handles a single line of input from the REPL.
+//
+// This is a stateful operation if a command is given (such as setting
+// a variable). This function should not be called in parallel.
+//
+// The return value is the output and the error to show.
+func (s *Session) Handle(line string) (string, bool, tfdiags.Diagnostics) {
+	switch {
+	case strings.TrimSpace(line) == "":
+		return "", false, nil
+	case strings.TrimSpace(line) == "exit":
+		return "", true, nil
+	case strings.TrimSpace(line) == "help":
+		ret, diags := s.handleHelp()
+		return ret, false, diags
+	default:
+		ret, diags := s.handleEval(line)
+		return ret, false, diags
+	}
+}
+
+func (s *Session) handleEval(line string) (string, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// Parse the given line as an expression
+	expr, parseDiags := hclsyntax.ParseExpression([]byte(line), "<console-input>", hcl.Pos{Line: 1, Column: 1})
+	diags = diags.Append(parseDiags)
+	if parseDiags.HasErrors() {
+		return "", diags
+	}
+
+	val, valDiags := s.Scope.EvalExpr(expr, cty.DynamicPseudoType)
+	diags = diags.Append(valDiags)
+	if valDiags.HasErrors() {
+		return "", diags
+	}
+
+	// The TypeType mark is used only by the console-only `type` function, in
+	// order to smuggle the type of a given value back here. We can then
+	// display a representation of the type directly.
+	if marks.Contains(val, marks.TypeType) {
+		val, _ = val.UnmarkDeep()
+
+		valType := val.Type()
+		switch {
+		case valType.Equals(types.TypeType):
+			// An encapsulated type value, which should be displayed directly.
+			valType := val.EncapsulatedValue().(*cty.Type)
+			return typeString(*valType), diags
+		default:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid use of type function",
+				"The console-only \"type\" function cannot be used as part of an expression.",
+			))
+			return "", diags
+		}
+	}
+
+	return FormatValue(val, 0), diags
+}
+
+func (s *Session) handleHelp() (string, tfdiags.Diagnostics) {
+	text := `
+The Terraform console allows you to experiment with Terraform interpolations.
+You may access resources in the state (if you have one) just as you would
+from a configuration. For example: "aws_instance.foo.id" would evaluate
+to the ID of "aws_instance.foo" if it exists in your state.
+
+Type in the interpolation to test and hit <enter> to see the result.
+
+To exit the console, type "exit" and hit <enter>, or use Control-C or
+Control-D.
+`
+
+	return strings.TrimSpace(text), nil
+}
+
+// Modified copy of TypeString from go-cty:
+// https://github.com/zclconf/go-cty-debug/blob/master/ctydebug/type_string.go
+//
+// TypeString returns a string representation of a given type that is
+// reminiscent of Go syntax calling into the cty package but is mainly
+// intended for easy human inspection of values in tests, debug output, etc.
+//
+// The resulting string will include newlines and indentation in order to
+// increase the readability of complex structures. It always ends with a
+// newline, so you can print this result directly to your output.
+func typeString(ty cty.Type) string {
+	var b strings.Builder
+	writeType(ty, &b, 0)
+	return b.String()
+}
+
+func writeType(ty cty.Type, b *strings.Builder, indent int) {
+	switch {
+	case ty == cty.NilType:
+		b.WriteString("nil")
+		return
+	case ty.IsObjectType():
+		atys := ty.AttributeTypes()
+		if len(atys) == 0 {
+			b.WriteString("object({})")
+			return
+		}
+		attrNames := make([]string, 0, len(atys))
+		for name := range atys {
+			attrNames = append(attrNames, name)
+		}
+		sort.Strings(attrNames)
+		b.WriteString("object({\n")
+		indent++
+		for _, name := range attrNames {
+			aty := atys[name]
+			b.WriteString(indentSpaces(indent))
+			fmt.Fprintf(b, "%s: ", name)
+			writeType(aty, b, indent)
+			b.WriteString(",\n")
+		}
+		indent--
+		b.WriteString(indentSpaces(indent))
+		b.WriteString("})")
+	case ty.IsTupleType():
+		etys := ty.TupleElementTypes()
+		if len(etys) == 0 {
+			b.WriteString("tuple([])")
+			return
+		}
+		b.WriteString("tuple([\n")
+		indent++
+		for _, ety := range etys {
+			b.WriteString(indentSpaces(indent))
+			writeType(ety, b, indent)
+			b.WriteString(",\n")
+		}
+		indent--
+		b.WriteString(indentSpaces(indent))
+		b.WriteString("])")
+	case ty.IsCollectionType():
+		ety := ty.ElementType()
+		switch {
+		case ty.IsListType():
+			b.WriteString("list(")
+		case ty.IsMapType():
+			b.WriteString("map(")
+		case ty.IsSetType():
+			b.WriteString("set(")
+		default:
+			// At the time of writing there are no other collection types,
+			// but we'll be robust here and just pass through the GoString
+			// of anything we don't recognize.
+			b.WriteString(ty.FriendlyName())
+			return
+		}
+		// Because object and tuple types render split over multiple
+		// lines, a collection type container around them can end up
+		// being hard to see when scanning, so we'll generate some extra
+		// indentation to make a collection of structural type more visually
+		// distinct from the structural type alone.
+		complexElem := ety.IsObjectType() || ety.IsTupleType()
+		if complexElem {
+			indent++
+			b.WriteString("\n")
+			b.WriteString(indentSpaces(indent))
+		}
+		writeType(ty.ElementType(), b, indent)
+		if complexElem {
+			indent--
+			b.WriteString(",\n")
+			b.WriteString(indentSpaces(indent))
+		}
+		b.WriteString(")")
+	default:
+		// For any other type we'll just use its GoString and assume it'll
+		// follow the usual GoString conventions.
+		b.WriteString(ty.FriendlyName())
+	}
+}
+
+func indentSpaces(level int) string {
+	return strings.Repeat("    ", level)
+}
diff --git a/v1.5.7/internal/repl/session_test.go b/v1.5.7/internal/repl/session_test.go
new file mode 100644
index 0000000..58941dd
--- /dev/null
+++ b/v1.5.7/internal/repl/session_test.go
@@ -0,0 +1,448 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package repl
+
+import (
+	"flag"
+	"os"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+
+	_ "github.com/hashicorp/terraform/internal/logging"
+)
+
+func TestMain(m *testing.M) {
+	flag.Parse()
+	os.Exit(m.Run())
+}
+
+func TestSession_basicState(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectReady,
+				AttrsJSON: []byte(`{"id":"bar"}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("module", addrs.NoKey)),
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectReady,
+				AttrsJSON: []byte(`{"id":"bar"}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	t.Run("basic", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			State: state,
+			Inputs: []testSessionInput{
+				{
+					Input:  "test_instance.foo.id",
+					Output: `"bar"`,
+				},
+			},
+		})
+	})
+
+	t.Run("missing resource", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			State: state,
+			Inputs: []testSessionInput{
+				{
+					Input:         "test_instance.bar.id",
+					Error:         true,
+					ErrorContains: `A managed resource "test_instance" "bar" has not been declared`,
+				},
+			},
+		})
+	})
+
+	t.Run("missing module", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			State: state,
+			Inputs: []testSessionInput{
+				{
+					Input:         "module.child",
+					Error:         true,
+					ErrorContains: `No module call named "child" is declared in the root module.`,
+				},
+			},
+		})
+	})
+
+	t.Run("missing module referencing just one output", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			State: state,
+			Inputs: []testSessionInput{
+				{
+					Input:         "module.child.foo",
+					Error:         true,
+					ErrorContains: `No module call named "child" is declared in the root module.`,
+				},
+			},
+		})
+	})
+
+	t.Run("missing module output", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			State: state,
+			Inputs: []testSessionInput{
+				{
+					Input:         "module.module.foo",
+					Error:         true,
+					ErrorContains: `Unsupported attribute: This object does not have an attribute named "foo"`,
+				},
+			},
+		})
+	})
+
+	t.Run("type function", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			State: state,
+			Inputs: []testSessionInput{
+				{
+					Input: "type(test_instance.foo)",
+					Output: `object({
+    id: string,
+})`,
+				},
+			},
+		})
+	})
+}
+
+func TestSession_stateless(t *testing.T) {
+	t.Run("exit", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			Inputs: []testSessionInput{
+				{
+					Input: "exit",
+					Exit:  true,
+				},
+			},
+		})
+	})
+
+	t.Run("help", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			Inputs: []testSessionInput{
+				{
+					Input:          "help",
+					OutputContains: "allows you to",
+				},
+			},
+		})
+	})
+
+	t.Run("help with spaces", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			Inputs: []testSessionInput{
+				{
+					Input:          "help   ",
+					OutputContains: "allows you to",
+				},
+			},
+		})
+	})
+
+	t.Run("basic math", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			Inputs: []testSessionInput{
+				{
+					Input:  "1 + 5",
+					Output: "6",
+				},
+			},
+		})
+	})
+
+	t.Run("missing resource", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			Inputs: []testSessionInput{
+				{
+					Input:         "test_instance.bar.id",
+					Error:         true,
+					ErrorContains: `resource "test_instance" "bar" has not been declared`,
+				},
+			},
+		})
+	})
+
+	t.Run("type function", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			Inputs: []testSessionInput{
+				{
+					Input:  `type("foo")`,
+					Output: "string",
+				},
+			},
+		})
+	})
+
+	t.Run("type type is type", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			Inputs: []testSessionInput{
+				{
+					Input:  `type(type("foo"))`,
+					Output: "type",
+				},
+			},
+		})
+	})
+
+	t.Run("interpolating type with strings is not possible", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			Inputs: []testSessionInput{
+				{
+					Input:         `"quin${type([])}"`,
+					Error:         true,
+					ErrorContains: "Invalid template interpolation value",
+				},
+			},
+		})
+	})
+
+	t.Run("type function cannot be used in expressions", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			Inputs: []testSessionInput{
+				{
+					Input:         `[for i in [1, "two", true]: type(i)]`,
+					Output:        "",
+					Error:         true,
+					ErrorContains: "Invalid use of type function",
+				},
+			},
+		})
+	})
+
+	t.Run("type equality checks are not permitted", func(t *testing.T) {
+		testSession(t, testSessionTest{
+			Inputs: []testSessionInput{
+				{
+					Input:         `type("foo") == type("bar")`,
+					Output:        "",
+					Error:         true,
+					ErrorContains: "Invalid use of type function",
+				},
+			},
+		})
+	})
+}
+
+func testSession(t *testing.T, test testSessionTest) {
+	t.Helper()
+
+	p := &terraform.MockProvider{}
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Computed: true},
+					},
+				},
+			},
+		},
+	}
+
+	config, _, cleanup, configDiags := initwd.LoadConfigForTests(t, "testdata/config-fixture")
+	defer cleanup()
+	if configDiags.HasErrors() {
+		t.Fatalf("unexpected problems loading config: %s", configDiags.Err())
+	}
+
+	// Build the TF context
+	ctx, diags := terraform.NewContext(&terraform.ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): providers.FactoryFixed(p),
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("failed to create context: %s", diags.Err())
+	}
+
+	state := test.State
+	if state == nil {
+		state = states.NewState()
+	}
+	scope, diags := ctx.Eval(config, state, addrs.RootModuleInstance, &terraform.EvalOpts{})
+	if diags.HasErrors() {
+		t.Fatalf("failed to create scope: %s", diags.Err())
+	}
+
+	// Ensure that any console-only functions are available
+	scope.ConsoleMode = true
+
+	// Build the session
+	s := &Session{
+		Scope: scope,
+	}
+
+	// Test the inputs. We purposely don't use subtests here because
+	// the inputs don't represent subtests, but a sequence of stateful
+	// operations.
+	for _, input := range test.Inputs {
+		result, exit, diags := s.Handle(input.Input)
+		if exit != input.Exit {
+			t.Fatalf("incorrect 'exit' result %t; want %t", exit, input.Exit)
+		}
+		if (diags.HasErrors()) != input.Error {
+			t.Fatalf("%q: unexpected errors: %s", input.Input, diags.Err())
+		}
+		if diags.HasErrors() {
+			if input.ErrorContains != "" {
+				if !strings.Contains(diags.Err().Error(), input.ErrorContains) {
+					t.Fatalf(
+						"%q: diagnostics should contain: %q\n\n%s",
+						input.Input, input.ErrorContains, diags.Err(),
+					)
+				}
+			}
+
+			continue
+		}
+
+		if input.Output != "" && result != input.Output {
+			t.Fatalf(
+				"%q: expected:\n\n%s\n\ngot:\n\n%s",
+				input.Input, input.Output, result)
+		}
+
+		if input.OutputContains != "" && !strings.Contains(result, input.OutputContains) {
+			t.Fatalf(
+				"%q: expected contains:\n\n%s\n\ngot:\n\n%s",
+				input.Input, input.OutputContains, result)
+		}
+	}
+}
+
+type testSessionTest struct {
+	State  *states.State // State to use
+	Module string        // Module name in testdata to load
+
+	// Inputs are the list of test inputs that are run in order.
+	// Each input can test the output of each step.
+	Inputs []testSessionInput
+}
+
+// testSessionInput is a single input to test for a session.
+type testSessionInput struct {
+	Input          string // Input string
+	Output         string // Exact output string to check
+	OutputContains string
+	Error          bool // Error is true if error is expected
+	Exit           bool // Exit is true if exiting is expected
+	ErrorContains  string
+}
+
+func TestTypeString(t *testing.T) {
+	tests := []struct {
+		Input cty.Value
+		Want  string
+	}{
+		// Primititves
+		{
+			cty.StringVal("a"),
+			"string",
+		},
+		{
+			cty.NumberIntVal(42),
+			"number",
+		},
+		{
+			cty.BoolVal(true),
+			"bool",
+		},
+		// Collections
+		{
+			cty.EmptyObjectVal,
+			`object({})`,
+		},
+		{
+			cty.EmptyTupleVal,
+			`tuple([])`,
+		},
+		{
+			cty.ListValEmpty(cty.String),
+			`list(string)`,
+		},
+		{
+			cty.MapValEmpty(cty.String),
+			`map(string)`,
+		},
+		{
+			cty.SetValEmpty(cty.String),
+			`set(string)`,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.StringVal("a")}),
+			`list(string)`,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.ListVal([]cty.Value{cty.NumberIntVal(42)})}),
+			`list(list(number))`,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.MapValEmpty(cty.String)}),
+			`list(map(string))`,
+		},
+		{
+			cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("bar"),
+			})}),
+			"list(\n    object({\n        foo: string,\n    }),\n)",
+		},
+		// Unknowns and Nulls
+		{
+			cty.UnknownVal(cty.String),
+			"string",
+		},
+		{
+			cty.NullVal(cty.Object(map[string]cty.Type{
+				"foo": cty.String,
+			})),
+			"object({\n    foo: string,\n})",
+		},
+		{ // irrelevant marks do nothing
+			cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+				"foo": cty.StringVal("bar").Mark("ignore me"),
+			})}),
+			"list(\n    object({\n        foo: string,\n    }),\n)",
+		},
+	}
+	for _, test := range tests {
+		got := typeString(test.Input.Type())
+		if got != test.Want {
+			t.Errorf("wrong result:\n%s", cmp.Diff(got, test.Want))
+		}
+	}
+}
diff --git a/v1.5.7/internal/repl/testdata/config-fixture/child/empty.tf b/v1.5.7/internal/repl/testdata/config-fixture/child/empty.tf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/repl/testdata/config-fixture/child/empty.tf
diff --git a/v1.5.7/internal/repl/testdata/config-fixture/repl_test.tf b/v1.5.7/internal/repl/testdata/config-fixture/repl_test.tf
new file mode 100644
index 0000000..0912084
--- /dev/null
+++ b/v1.5.7/internal/repl/testdata/config-fixture/repl_test.tf
@@ -0,0 +1,11 @@
+
+# This configuration is just here to allow the tests in session_test to
+# evaluate expressions without getting errors about things not being declared.
+# Therefore it's intended to just be the minimum config to make those
+# expressions work against the equally-minimal mock provider.
+resource "test_instance" "foo" {
+}
+
+module "module" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/replacefile/doc.go b/v1.5.7/internal/replacefile/doc.go
new file mode 100644
index 0000000..eeb3413
--- /dev/null
+++ b/v1.5.7/internal/replacefile/doc.go
@@ -0,0 +1,15 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package replacefile is a small helper package focused directly at the
+// problem of atomically "renaming" one file over another one.
+//
+// On Unix systems this is the standard behavior of the rename function, but
+// the equivalent operation on Windows requires some specific operation flags
+// which this package encapsulates.
+//
+// This package uses conditional compilation to select a different
+// implementation for Windows vs. all other platforms. It may therefore
+// require further fiddling in future if Terraform is ported to another
+// OS that is neither Unix-like nor Windows.
+package replacefile
diff --git a/v1.5.7/internal/replacefile/replacefile_unix.go b/v1.5.7/internal/replacefile/replacefile_unix.go
new file mode 100644
index 0000000..8a8416c
--- /dev/null
+++ b/v1.5.7/internal/replacefile/replacefile_unix.go
@@ -0,0 +1,28 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build !windows
+// +build !windows
+
+package replacefile
+
+import (
+	"os"
+)
+
+// AtomicRename renames from the source path to the destination path,
+// atomically replacing any file that might already exist at the destination.
+//
+// Typically this operation can succeed only if the source and destination
+// are within the same physical filesystem, so this function is best reserved
+// for cases where the source and destination exist in the same directory and
+// only the local filename differs between them.
+//
+// The Unix implementation of AtomicRename relies on the atomicity of renaming
+// that is required by the ISO C standard, which in turn assumes that Go's
+// implementation of rename is calling into a system call that preserves that
+// guarantee.
+func AtomicRename(source, destination string) error {
+	// On Unix systems, a rename is sufficiently atomic.
+	return os.Rename(source, destination)
+}
diff --git a/v1.5.7/internal/replacefile/replacefile_windows.go b/v1.5.7/internal/replacefile/replacefile_windows.go
new file mode 100644
index 0000000..08e37d2
--- /dev/null
+++ b/v1.5.7/internal/replacefile/replacefile_windows.go
@@ -0,0 +1,44 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build windows
+// +build windows
+
+package replacefile
+
+import (
+	"os"
+	"syscall"
+
+	"golang.org/x/sys/windows"
+)
+
+// AtomicRename renames from the source path to the destination path,
+// atomically replacing any file that might already exist at the destination.
+//
+// Typically this operation can succeed only if the source and destination
+// are within the same physical filesystem, so this function is best reserved
+// for cases where the source and destination exist in the same directory and
+// only the local filename differs between them.
+func AtomicRename(source, destination string) error {
+	// On Windows, renaming one file over another is not atomic and certain
+	// error conditions can result in having only the source file and nothing
+	// at the destination file. Instead, we need to call into the MoveFileEx
+	// Windows API function, setting two flags to opt in to replacing an
+	// existing file.
+	srcPtr, err := syscall.UTF16PtrFromString(source)
+	if err != nil {
+		return &os.LinkError{"replace", source, destination, err}
+	}
+	destPtr, err := syscall.UTF16PtrFromString(destination)
+	if err != nil {
+		return &os.LinkError{"replace", source, destination, err}
+	}
+
+	flags := uint32(windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH)
+	err = windows.MoveFileEx(srcPtr, destPtr, flags)
+	if err != nil {
+		return &os.LinkError{"replace", source, destination, err}
+	}
+	return nil
+}
diff --git a/v1.5.7/internal/replacefile/writefile.go b/v1.5.7/internal/replacefile/writefile.go
new file mode 100644
index 0000000..00be0f8
--- /dev/null
+++ b/v1.5.7/internal/replacefile/writefile.go
@@ -0,0 +1,80 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package replacefile
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+)
+
+// AtomicWriteFile uses a temporary file along with this package's AtomicRename
+// function in order to provide a replacement for ioutil.WriteFile that
+// writes the given file into place as atomically as the underlying operating
+// system can support.
+//
+// The sense of "atomic" meant by this function is that the file at the
+// given filename will either contain the entirety of the previous contents
+// or the entirety of the given data array if opened and read at any point
+// during the execution of the function.
+//
+// On some platforms attempting to overwrite a file that has at least one
+// open filehandle will produce an error. On other platforms, the overwriting
+// will succeed but existing open handles will still refer to the old file,
+// even though its directory entry is no longer present.
+//
+// Although AtomicWriteFile tries its best to avoid leaving behind its
+// temporary file on error, some particularly messy error cases may result
+// in a leftover temporary file.
+func AtomicWriteFile(filename string, data []byte, perm os.FileMode) error {
+	dir, file := filepath.Split(filename)
+	if dir == "" {
+		// If the file is in the current working directory then dir will
+		// end up being "", but that's not right here because TempFile
+		// treats an empty dir as meaning "use the TMPDIR environment variable".
+		dir = "."
+	}
+	f, err := ioutil.TempFile(dir, file) // alongside target file and with a similar name
+	if err != nil {
+		return fmt.Errorf("cannot create temporary file to update %s: %s", filename, err)
+	}
+	tmpName := f.Name()
+	moved := false
+	defer func(f *os.File, name string) {
+		// Remove the temporary file if it hasn't been moved yet. We're
+		// ignoring errors here because there's nothing we can do about
+		// them anyway.
+		if !moved {
+			os.Remove(name)
+		}
+	}(f, tmpName)
+
+	// We'll try to apply the requested permissions. This may
+	// not be effective on all platforms, but should at least work on
+	// Unix-like targets and should be harmless elsewhere.
+	if err := os.Chmod(tmpName, perm); err != nil {
+		return fmt.Errorf("cannot set mode for temporary file %s: %s", tmpName, err)
+	}
+
+	// Write the credentials to the temporary file, then immediately close
+	// it, whether or not the write succeeds. Note that closing the file here
+	// is required because on Windows we can't move a file while it's open.
+	_, err = f.Write(data)
+	f.Close()
+	if err != nil {
+		return fmt.Errorf("cannot write to temporary file %s: %s", tmpName, err)
+	}
+
+	// Temporary file now replaces the original file, as atomically as
+	// possible. (At the very least, we should not end up with a file
+	// containing only a partial JSON object.)
+	err = AtomicRename(tmpName, filename)
+	if err != nil {
+		return fmt.Errorf("failed to replace %s with temporary file %s: %s", filename, tmpName, err)
+	}
+
+	moved = true
+	return nil
+}
diff --git a/v1.5.7/internal/states/checks.go b/v1.5.7/internal/states/checks.go
new file mode 100644
index 0000000..14558a6
--- /dev/null
+++ b/v1.5.7/internal/states/checks.go
@@ -0,0 +1,185 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package states
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+)
+
+// CheckResults represents a summary snapshot of the status of a set of checks
+// declared in configuration, updated after each Terraform Core run that
+// changes the state or remote system in a way that might impact the check
+// results.
+//
+// Unlike a checks.State, this type only tracks the overall results for
+// each checkable object and doesn't aim to preserve the identity of individual
+// checks in the configuration. For our UI reporting purposes, it is entire
+// objects that pass or fail based on their declared checks; the individual
+// checks have no durable identity between runs, and so are only a language
+// design convenience to help authors describe various independent conditions
+// with different failure messages each.
+//
+// CheckResults should typically be considered immutable once constructed:
+// instead of updating it in-place,instead construct an entirely new
+// CheckResults object based on a fresh checks.State.
+type CheckResults struct {
+	// ConfigResults has all of the individual check results grouped by the
+	// configuration object they relate to.
+	//
+	// The top-level map here will always have a key for every configuration
+	// object that includes checks at the time of evaluating the results,
+	// even if there turned out to be no instances of that object and
+	// therefore no individual check results.
+	ConfigResults addrs.Map[addrs.ConfigCheckable, *CheckResultAggregate]
+}
+
+// CheckResultAggregate represents both the overall result for a particular
+// configured object that has checks and the individual checkable objects
+// it declared, if any.
+type CheckResultAggregate struct {
+	// Status is the aggregate status across all objects.
+	//
+	// Sometimes an error or check failure during planning will prevent
+	// Terraform Core from even determining the individual checkable objects
+	// associated with a downstream configuration object, and that situation is
+	// described here by this Status being checks.StatusUnknown and there being
+	// no elements in the ObjectResults field.
+	//
+	// That's different than Terraform Core explicitly reporting that there are
+	// no instances of the config object (e.g. a resource with count = 0),
+	// which leads to the aggregate status being checks.StatusPass while
+	// ObjectResults is still empty.
+	Status checks.Status
+
+	ObjectResults addrs.Map[addrs.Checkable, *CheckResultObject]
+}
+
+// CheckResultObject is the check status for a single checkable object.
+//
+// This aggregates together all of the checks associated with a particular
+// object into a single pass/fail/error/unknown result, because checkable
+// objects have durable addresses that can survive between runs, but their
+// individual checks do not. (Module authors are free to reorder their checks
+// for a particular object in the configuration with no change in meaning.)
+type CheckResultObject struct {
+	// Status is the check status of the checkable object, derived from the
+	// results of all of its individual checks.
+	Status checks.Status
+
+	// FailureMessages is an optional set of module-author-defined messages
+	// describing the problems that the checks detected, for objects whose
+	// status is checks.StatusFail.
+	//
+	// (checks.StatusError problems get reported as normal diagnostics during
+	// evaluation instead, and so will not appear here.)
+	FailureMessages []string
+}
+
+// NewCheckResults constructs a new states.CheckResults object that is a
+// snapshot of the check statuses recorded in the given checks.State object.
+//
+// This should be called only after a Terraform Core run has completed and
+// recorded any results from running the checks in the given object.
+func NewCheckResults(source *checks.State) *CheckResults {
+	ret := &CheckResults{
+		ConfigResults: addrs.MakeMap[addrs.ConfigCheckable, *CheckResultAggregate](),
+	}
+
+	for _, configAddr := range source.AllConfigAddrs() {
+		aggr := &CheckResultAggregate{
+			Status:        source.AggregateCheckStatus(configAddr),
+			ObjectResults: addrs.MakeMap[addrs.Checkable, *CheckResultObject](),
+		}
+
+		for _, objectAddr := range source.ObjectAddrs(configAddr) {
+			obj := &CheckResultObject{
+				Status:          source.ObjectCheckStatus(objectAddr),
+				FailureMessages: source.ObjectFailureMessages(objectAddr),
+			}
+			aggr.ObjectResults.Put(objectAddr, obj)
+		}
+
+		ret.ConfigResults.Put(configAddr, aggr)
+	}
+
+	// If there aren't actually any configuration objects then we'll just
+	// leave the map as a whole nil, because having it be zero-value makes
+	// life easier for deep comparisons in unit tests elsewhere.
+	if ret.ConfigResults.Len() == 0 {
+		ret.ConfigResults.Elems = nil
+	}
+
+	return ret
+}
+
+// GetObjectResult looks up the result for a single object, or nil if there
+// is no such object.
+//
+// In main code we shouldn't typically need to look up individual objects
+// like this, since we'll usually be reporting check results in an aggregate
+// form, but determining the result of a particular object is useful in our
+// internal unit tests, and so this is here primarily for that purpose.
+func (r *CheckResults) GetObjectResult(objectAddr addrs.Checkable) *CheckResultObject {
+	configAddr := objectAddr.ConfigCheckable()
+
+	aggr := r.ConfigResults.Get(configAddr)
+	if aggr == nil {
+		return nil
+	}
+
+	return aggr.ObjectResults.Get(objectAddr)
+}
+
+func (r *CheckResults) DeepCopy() *CheckResults {
+	if r == nil {
+		return nil
+	}
+	ret := &CheckResults{}
+	if r.ConfigResults.Elems == nil {
+		return ret
+	}
+
+	ret.ConfigResults = addrs.MakeMap[addrs.ConfigCheckable, *CheckResultAggregate]()
+
+	for _, configElem := range r.ConfigResults.Elems {
+		aggr := &CheckResultAggregate{
+			Status: configElem.Value.Status,
+		}
+
+		if configElem.Value.ObjectResults.Elems != nil {
+			aggr.ObjectResults = addrs.MakeMap[addrs.Checkable, *CheckResultObject]()
+
+			for _, objectElem := range configElem.Value.ObjectResults.Elems {
+				result := &CheckResultObject{
+					Status: objectElem.Value.Status,
+
+					// NOTE: We don't deep-copy this slice because it's
+					// immutable once constructed by convention.
+					FailureMessages: objectElem.Value.FailureMessages,
+				}
+				aggr.ObjectResults.Put(objectElem.Key, result)
+			}
+		}
+
+		ret.ConfigResults.Put(configElem.Key, aggr)
+	}
+
+	return ret
+}
+
+// ObjectAddrsKnown determines whether the set of objects recorded in this
+// aggregate is accurate (true) or if it's incomplete as a result of the
+// run being interrupted before instance expansion.
+func (r *CheckResultAggregate) ObjectAddrsKnown() bool {
+	if r.ObjectResults.Len() != 0 {
+		// If there are any object results at all then we definitely know.
+		return true
+	}
+
+	// If we don't have any object addresses then we distinguish a known
+	// empty set of objects from an unknown set of objects by the aggregate
+	// status being unknown.
+	return r.Status != checks.StatusUnknown
+}
diff --git a/v1.5.7/internal/states/doc.go b/v1.5.7/internal/states/doc.go
new file mode 100644
index 0000000..98f0f99
--- /dev/null
+++ b/v1.5.7/internal/states/doc.go
@@ -0,0 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package states contains the types that are used to represent Terraform
+// states.
+package states
diff --git a/v1.5.7/internal/states/instance_generation.go b/v1.5.7/internal/states/instance_generation.go
new file mode 100644
index 0000000..6658d64
--- /dev/null
+++ b/v1.5.7/internal/states/instance_generation.go
@@ -0,0 +1,23 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package states
+
+// Generation is used to represent multiple objects in a succession of objects
+// represented by a single resource instance address. A resource instance can
+// have multiple generations over its lifetime due to object replacement
+// (when a change can't be applied without destroying and re-creating), and
+// multiple generations can exist at the same time when create_before_destroy
+// is used.
+//
+// A Generation value can either be the value of the variable "CurrentGen" or
+// a value of type DeposedKey. Generation values can be compared for equality
+// using "==" and used as map keys. The zero value of Generation (nil) is not
+// a valid generation and must not be used.
+type Generation interface {
+	generation()
+}
+
+// CurrentGen is the Generation representing the currently-active object for
+// a resource instance.
+var CurrentGen Generation
diff --git a/v1.5.7/internal/states/instance_object.go b/v1.5.7/internal/states/instance_object.go
new file mode 100644
index 0000000..2ce4982
--- /dev/null
+++ b/v1.5.7/internal/states/instance_object.go
@@ -0,0 +1,151 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package states
+
+import (
+	"sort"
+
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// ResourceInstanceObject is the local representation of a specific remote
+// object associated with a resource instance. In practice not all remote
+// objects are actually remote in the sense of being accessed over the network,
+// but this is the most common case.
+//
+// It is not valid to mutate a ResourceInstanceObject once it has been created.
+// Instead, create a new object and replace the existing one.
+type ResourceInstanceObject struct {
+	// Value is the object-typed value representing the remote object within
+	// Terraform.
+	Value cty.Value
+
+	// Private is an opaque value set by the provider when this object was
+	// last created or updated. Terraform Core does not use this value in
+	// any way and it is not exposed anywhere in the user interface, so
+	// a provider can use it for retaining any necessary private state.
+	Private []byte
+
+	// Status represents the "readiness" of the object as of the last time
+	// it was updated.
+	Status ObjectStatus
+
+	// Dependencies is a set of absolute address to other resources this
+	// instance dependeded on when it was applied. This is used to construct
+	// the dependency relationships for an object whose configuration is no
+	// longer available, such as if it has been removed from configuration
+	// altogether, or is now deposed.
+	Dependencies []addrs.ConfigResource
+
+	// CreateBeforeDestroy reflects the status of the lifecycle
+	// create_before_destroy option when this instance was last updated.
+	// Because create_before_destroy also effects the overall ordering of the
+	// destroy operations, we need to record the status to ensure a resource
+	// removed from the config will still be destroyed in the same manner.
+	CreateBeforeDestroy bool
+}
+
+// ObjectStatus represents the status of a RemoteObject.
+type ObjectStatus rune
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type ObjectStatus
+
+const (
+	// ObjectReady is an object status for an object that is ready to use.
+	ObjectReady ObjectStatus = 'R'
+
+	// ObjectTainted is an object status representing an object that is in
+	// an unrecoverable bad state due to a partial failure during a create,
+	// update, or delete operation. Since it cannot be moved into the
+	// ObjectRead state, a tainted object must be replaced.
+	ObjectTainted ObjectStatus = 'T'
+
+	// ObjectPlanned is a special object status used only for the transient
+	// placeholder objects we place into state during the refresh and plan
+	// walks to stand in for objects that will be created during apply.
+	//
+	// Any object of this status must have a corresponding change recorded
+	// in the current plan, whose value must then be used in preference to
+	// the value stored in state when evaluating expressions. A planned
+	// object stored in state will be incomplete if any of its attributes are
+	// not yet known, and the plan must be consulted in order to "see" those
+	// unknown values, because the state is not able to represent them.
+	ObjectPlanned ObjectStatus = 'P'
+)
+
+// Encode marshals the value within the receiver to produce a
+// ResourceInstanceObjectSrc ready to be written to a state file.
+//
+// The given type must be the implied type of the resource type schema, and
+// the given value must conform to it. It is important to pass the schema
+// type and not the object's own type so that dynamically-typed attributes
+// will be stored correctly. The caller must also provide the version number
+// of the schema that the given type was derived from, which will be recorded
+// in the source object so it can be used to detect when schema migration is
+// required on read.
+//
+// The returned object may share internal references with the receiver and
+// so the caller must not mutate the receiver any further once once this
+// method is called.
+func (o *ResourceInstanceObject) Encode(ty cty.Type, schemaVersion uint64) (*ResourceInstanceObjectSrc, error) {
+	// If it contains marks, remove these marks before traversing the
+	// structure with UnknownAsNull, and save the PathValueMarks
+	// so we can save them in state.
+	val, pvm := o.Value.UnmarkDeepWithPaths()
+
+	// Our state serialization can't represent unknown values, so we convert
+	// them to nulls here. This is lossy, but nobody should be writing unknown
+	// values here and expecting to get them out again later.
+	//
+	// We get unknown values here while we're building out a "planned state"
+	// during the plan phase, but the value stored in the plan takes precedence
+	// for expression evaluation. The apply step should never produce unknown
+	// values, but if it does it's the responsibility of the caller to detect
+	// and raise an error about that.
+	val = cty.UnknownAsNull(val)
+
+	src, err := ctyjson.Marshal(val, ty)
+	if err != nil {
+		return nil, err
+	}
+
+	// Dependencies are collected and merged in an unordered format (using map
+	// keys as a set), then later changed to a slice (in random ordering) to be
+	// stored in state as an array. To avoid pointless thrashing of state in
+	// refresh-only runs, we can either override comparison of dependency lists
+	// (more desirable, but tricky for Reasons) or just sort when encoding.
+	// Encoding of instances can happen concurrently, so we must copy the
+	// dependencies to avoid mutating what may be a shared array of values.
+	dependencies := make([]addrs.ConfigResource, len(o.Dependencies))
+	copy(dependencies, o.Dependencies)
+
+	sort.Slice(dependencies, func(i, j int) bool { return dependencies[i].String() < dependencies[j].String() })
+
+	return &ResourceInstanceObjectSrc{
+		SchemaVersion:       schemaVersion,
+		AttrsJSON:           src,
+		AttrSensitivePaths:  pvm,
+		Private:             o.Private,
+		Status:              o.Status,
+		Dependencies:        dependencies,
+		CreateBeforeDestroy: o.CreateBeforeDestroy,
+	}, nil
+}
+
+// AsTainted returns a deep copy of the receiver with the status updated to
+// ObjectTainted.
+func (o *ResourceInstanceObject) AsTainted() *ResourceInstanceObject {
+	if o == nil {
+		// A nil object can't be tainted, but we'll allow this anyway to
+		// avoid a crash, since we presumably intend to eventually record
+		// the object has having been deleted anyway.
+		return nil
+	}
+	ret := o.DeepCopy()
+	ret.Status = ObjectTainted
+	return ret
+}
diff --git a/v1.5.7/internal/states/instance_object_src.go b/v1.5.7/internal/states/instance_object_src.go
new file mode 100644
index 0000000..8e56d70
--- /dev/null
+++ b/v1.5.7/internal/states/instance_object_src.go
@@ -0,0 +1,126 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package states
+
+import (
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+)
+
+// ResourceInstanceObjectSrc is a not-fully-decoded version of
+// ResourceInstanceObject. Decoding of it can be completed by first handling
+// any schema migration steps to get to the latest schema version and then
+// calling method Decode with the implied type of the latest schema.
+type ResourceInstanceObjectSrc struct {
+	// SchemaVersion is the resource-type-specific schema version number that
+	// was current when either AttrsJSON or AttrsFlat was encoded. Migration
+	// steps are required if this is less than the current version number
+	// reported by the corresponding provider.
+	SchemaVersion uint64
+
+	// AttrsJSON is a JSON-encoded representation of the object attributes,
+	// encoding the value (of the object type implied by the associated resource
+	// type schema) that represents this remote object in Terraform Language
+	// expressions, and is compared with configuration when producing a diff.
+	//
+	// This is retained in JSON format here because it may require preprocessing
+	// before decoding if, for example, the stored attributes are for an older
+	// schema version which the provider must upgrade before use. If the
+	// version is current, it is valid to simply decode this using the
+	// type implied by the current schema, without the need for the provider
+	// to perform an upgrade first.
+	//
+	// When writing a ResourceInstanceObject into the state, AttrsJSON should
+	// always be conformant to the current schema version and the current
+	// schema version should be recorded in the SchemaVersion field.
+	AttrsJSON []byte
+
+	// AttrsFlat is a legacy form of attributes used in older state file
+	// formats, and in the new state format for objects that haven't yet been
+	// upgraded. This attribute is mutually exclusive with Attrs: for any
+	// ResourceInstanceObject, only one of these attributes may be populated
+	// and the other must be nil.
+	//
+	// An instance object with this field populated should be upgraded to use
+	// Attrs at the earliest opportunity, since this legacy flatmap-based
+	// format will be phased out over time. AttrsFlat should not be used when
+	// writing new or updated objects to state; instead, callers must follow
+	// the recommendations in the AttrsJSON documentation above.
+	AttrsFlat map[string]string
+
+	// AttrSensitivePaths is an array of paths to mark as sensitive coming out of
+	// state, or to save as sensitive paths when saving state
+	AttrSensitivePaths []cty.PathValueMarks
+
+	// These fields all correspond to the fields of the same name on
+	// ResourceInstanceObject.
+	Private             []byte
+	Status              ObjectStatus
+	Dependencies        []addrs.ConfigResource
+	CreateBeforeDestroy bool
+}
+
+// Decode unmarshals the raw representation of the object attributes. Pass the
+// implied type of the corresponding resource type schema for correct operation.
+//
+// Before calling Decode, the caller must check that the SchemaVersion field
+// exactly equals the version number of the schema whose implied type is being
+// passed, or else the result is undefined.
+//
+// The returned object may share internal references with the receiver and
+// so the caller must not mutate the receiver any further once once this
+// method is called.
+func (os *ResourceInstanceObjectSrc) Decode(ty cty.Type) (*ResourceInstanceObject, error) {
+	var val cty.Value
+	var err error
+	if os.AttrsFlat != nil {
+		// Legacy mode. We'll do our best to unpick this from the flatmap.
+		val, err = hcl2shim.HCL2ValueFromFlatmap(os.AttrsFlat, ty)
+		if err != nil {
+			return nil, err
+		}
+	} else {
+		val, err = ctyjson.Unmarshal(os.AttrsJSON, ty)
+		// Mark the value with paths if applicable
+		if os.AttrSensitivePaths != nil {
+			val = val.MarkWithPaths(os.AttrSensitivePaths)
+		}
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return &ResourceInstanceObject{
+		Value:               val,
+		Status:              os.Status,
+		Dependencies:        os.Dependencies,
+		Private:             os.Private,
+		CreateBeforeDestroy: os.CreateBeforeDestroy,
+	}, nil
+}
+
+// CompleteUpgrade creates a new ResourceInstanceObjectSrc by copying the
+// metadata from the receiver and writing in the given new schema version
+// and attribute value that are presumed to have resulted from upgrading
+// from an older schema version.
+func (os *ResourceInstanceObjectSrc) CompleteUpgrade(newAttrs cty.Value, newType cty.Type, newSchemaVersion uint64) (*ResourceInstanceObjectSrc, error) {
+	new := os.DeepCopy()
+	new.AttrsFlat = nil // We always use JSON after an upgrade, even if the source used flatmap
+
+	// This is the same principle as ResourceInstanceObject.Encode, but
+	// avoiding a decode/re-encode cycle because we don't have type info
+	// available for the "old" attributes.
+	newAttrs = cty.UnknownAsNull(newAttrs)
+	src, err := ctyjson.Marshal(newAttrs, newType)
+	if err != nil {
+		return nil, err
+	}
+
+	new.AttrsJSON = src
+	new.SchemaVersion = newSchemaVersion
+	return new, nil
+}
diff --git a/v1.5.7/internal/states/instance_object_test.go b/v1.5.7/internal/states/instance_object_test.go
new file mode 100644
index 0000000..dce945f
--- /dev/null
+++ b/v1.5.7/internal/states/instance_object_test.go
@@ -0,0 +1,86 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package states
+
+import (
+	"sync"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestResourceInstanceObject_encode(t *testing.T) {
+	value := cty.ObjectVal(map[string]cty.Value{
+		"foo": cty.True,
+	})
+	// The in-memory order of resource dependencies is random, since they're an
+	// unordered set.
+	depsOne := []addrs.ConfigResource{
+		addrs.RootModule.Resource(addrs.ManagedResourceMode, "test", "honk"),
+		addrs.RootModule.Child("child").Resource(addrs.ManagedResourceMode, "test", "flub"),
+		addrs.RootModule.Resource(addrs.ManagedResourceMode, "test", "boop"),
+	}
+	depsTwo := []addrs.ConfigResource{
+		addrs.RootModule.Child("child").Resource(addrs.ManagedResourceMode, "test", "flub"),
+		addrs.RootModule.Resource(addrs.ManagedResourceMode, "test", "boop"),
+		addrs.RootModule.Resource(addrs.ManagedResourceMode, "test", "honk"),
+	}
+
+	// multiple instances may have been assigned the same deps slice
+	objs := []*ResourceInstanceObject{
+		&ResourceInstanceObject{
+			Value:        value,
+			Status:       ObjectPlanned,
+			Dependencies: depsOne,
+		},
+		&ResourceInstanceObject{
+			Value:        value,
+			Status:       ObjectPlanned,
+			Dependencies: depsTwo,
+		},
+		&ResourceInstanceObject{
+			Value:        value,
+			Status:       ObjectPlanned,
+			Dependencies: depsOne,
+		},
+		&ResourceInstanceObject{
+			Value:        value,
+			Status:       ObjectPlanned,
+			Dependencies: depsOne,
+		},
+	}
+
+	var encoded []*ResourceInstanceObjectSrc
+
+	// Encoding can happen concurrently, so we need to make sure the shared
+	// Dependencies are safely handled
+	var wg sync.WaitGroup
+	var mu sync.Mutex
+
+	for _, obj := range objs {
+		obj := obj
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			rios, err := obj.Encode(value.Type(), 0)
+			if err != nil {
+				t.Errorf("unexpected error: %s", err)
+			}
+			mu.Lock()
+			encoded = append(encoded, rios)
+			mu.Unlock()
+		}()
+	}
+	wg.Wait()
+
+	// However, identical sets of dependencies should always be written to state
+	// in an identical order, so we don't do meaningless state updates on refresh.
+	for i := 0; i < len(encoded)-1; i++ {
+		if diff := cmp.Diff(encoded[i].Dependencies, encoded[i+1].Dependencies); diff != "" {
+			t.Errorf("identical dependencies got encoded in different orders:\n%s", diff)
+		}
+	}
+}
diff --git a/v1.5.7/internal/states/module.go b/v1.5.7/internal/states/module.go
new file mode 100644
index 0000000..ec2c9aa
--- /dev/null
+++ b/v1.5.7/internal/states/module.go
@@ -0,0 +1,324 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package states
+
+import (
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// Module is a container for the states of objects within a particular module.
+type Module struct {
+	Addr addrs.ModuleInstance
+
+	// Resources contains the state for each resource. The keys in this map are
+	// an implementation detail and must not be used by outside callers.
+	Resources map[string]*Resource
+
+	// OutputValues contains the state for each output value. The keys in this
+	// map are output value names.
+	OutputValues map[string]*OutputValue
+
+	// LocalValues contains the value for each named output value. The keys
+	// in this map are local value names.
+	LocalValues map[string]cty.Value
+}
+
+// NewModule constructs an empty module state for the given module address.
+func NewModule(addr addrs.ModuleInstance) *Module {
+	return &Module{
+		Addr:         addr,
+		Resources:    map[string]*Resource{},
+		OutputValues: map[string]*OutputValue{},
+		LocalValues:  map[string]cty.Value{},
+	}
+}
+
+// Resource returns the state for the resource with the given address within
+// the receiving module state, or nil if the requested resource is not tracked
+// in the state.
+func (ms *Module) Resource(addr addrs.Resource) *Resource {
+	return ms.Resources[addr.String()]
+}
+
+// ResourceInstance returns the state for the resource instance with the given
+// address within the receiving module state, or nil if the requested instance
+// is not tracked in the state.
+func (ms *Module) ResourceInstance(addr addrs.ResourceInstance) *ResourceInstance {
+	rs := ms.Resource(addr.Resource)
+	if rs == nil {
+		return nil
+	}
+	return rs.Instance(addr.Key)
+}
+
+// SetResourceProvider updates the resource-level metadata for the resource
+// with the given address, creating the resource state for it if it doesn't
+// already exist.
+func (ms *Module) SetResourceProvider(addr addrs.Resource, provider addrs.AbsProviderConfig) {
+	rs := ms.Resource(addr)
+	if rs == nil {
+		rs = &Resource{
+			Addr:      addr.Absolute(ms.Addr),
+			Instances: map[addrs.InstanceKey]*ResourceInstance{},
+		}
+		ms.Resources[addr.String()] = rs
+	}
+
+	rs.ProviderConfig = provider
+}
+
+// RemoveResource removes the entire state for the given resource, taking with
+// it any instances associated with the resource. This should generally be
+// called only for resource objects whose instances have all been destroyed.
+func (ms *Module) RemoveResource(addr addrs.Resource) {
+	delete(ms.Resources, addr.String())
+}
+
+// SetResourceInstanceCurrent saves the given instance object as the current
+// generation of the resource instance with the given address, simultaneously
+// updating the recorded provider configuration address and dependencies.
+//
+// Any existing current instance object for the given resource is overwritten.
+// Set obj to nil to remove the primary generation object altogether. If there
+// are no deposed objects then the instance will be removed altogether.
+//
+// The provider address is a resource-wide setting and is updated for all other
+// instances of the same resource as a side-effect of this call.
+func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
+	rs := ms.Resource(addr.Resource)
+	// if the resource is nil and the object is nil, don't do anything!
+	// you'll probably just cause issues
+	if obj == nil && rs == nil {
+		return
+	}
+	if obj == nil && rs != nil {
+		// does the resource have any other objects?
+		// if not then delete the whole resource
+		if len(rs.Instances) == 0 {
+			delete(ms.Resources, addr.Resource.String())
+			return
+		}
+		// check for an existing resource, now that we've ensured that rs.Instances is more than 0/not nil
+		is := rs.Instance(addr.Key)
+		if is == nil {
+			// if there is no instance on the resource with this address and obj is nil, return and change nothing
+			return
+		}
+		// if we have an instance, update the current
+		is.Current = obj
+		if !is.HasObjects() {
+			// If we have no objects at all then we'll clean up.
+			delete(rs.Instances, addr.Key)
+			// Delete the resource if it has no instances, but only if NoEach
+			if len(rs.Instances) == 0 {
+				delete(ms.Resources, addr.Resource.String())
+				return
+			}
+		}
+		// Nothing more to do here, so return!
+		return
+	}
+	if rs == nil && obj != nil {
+		// We don't have have a resource so make one, which is a side effect of setResourceMeta
+		ms.SetResourceProvider(addr.Resource, provider)
+		// now we have a resource! so update the rs value to point to it
+		rs = ms.Resource(addr.Resource)
+	}
+	// Get our instance from the resource; it could be there or not at this point
+	is := rs.Instance(addr.Key)
+	if is == nil {
+		// if we don't have a resource, create one and add to the instances
+		is = rs.CreateInstance(addr.Key)
+		// update the resource meta because we have a new
+		ms.SetResourceProvider(addr.Resource, provider)
+	}
+	// Update the resource's ProviderConfig, in case the provider has updated
+	rs.ProviderConfig = provider
+	is.Current = obj
+}
+
+// SetResourceInstanceDeposed saves the given instance object as a deposed
+// generation of the resource instance with the given address and deposed key.
+//
+// Call this method only for pre-existing deposed objects that already have
+// a known DeposedKey. For example, this method is useful if reloading objects
+// that were persisted to a state file. To mark the current object as deposed,
+// use DeposeResourceInstanceObject instead.
+//
+// The resource that contains the given instance must already exist in the
+// state, or this method will panic. Use Resource to check first if its
+// presence is not already guaranteed.
+//
+// Any existing current instance object for the given resource and deposed key
+// is overwritten. Set obj to nil to remove the deposed object altogether. If
+// the instance is left with no objects after this operation then it will
+// be removed from its containing resource altogether.
+func (ms *Module) SetResourceInstanceDeposed(addr addrs.ResourceInstance, key DeposedKey, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
+	ms.SetResourceProvider(addr.Resource, provider)
+
+	rs := ms.Resource(addr.Resource)
+	is := rs.EnsureInstance(addr.Key)
+	if obj != nil {
+		is.Deposed[key] = obj
+	} else {
+		delete(is.Deposed, key)
+	}
+
+	if !is.HasObjects() {
+		// If we have no objects at all then we'll clean up.
+		delete(rs.Instances, addr.Key)
+	}
+	if len(rs.Instances) == 0 {
+		// Also clean up if we only expect to have one instance anyway
+		// and there are none. We leave the resource behind if an each mode
+		// is active because an empty list or map of instances is a valid state.
+		delete(ms.Resources, addr.Resource.String())
+	}
+}
+
+// ForgetResourceInstanceAll removes the record of all objects associated with
+// the specified resource instance, if present. If not present, this is a no-op.
+func (ms *Module) ForgetResourceInstanceAll(addr addrs.ResourceInstance) {
+	rs := ms.Resource(addr.Resource)
+	if rs == nil {
+		return
+	}
+	delete(rs.Instances, addr.Key)
+
+	if len(rs.Instances) == 0 {
+		// Also clean up if we only expect to have one instance anyway
+		// and there are none. We leave the resource behind if an each mode
+		// is active because an empty list or map of instances is a valid state.
+		delete(ms.Resources, addr.Resource.String())
+	}
+}
+
+// ForgetResourceInstanceDeposed removes the record of the deposed object with
+// the given address and key, if present. If not present, this is a no-op.
+func (ms *Module) ForgetResourceInstanceDeposed(addr addrs.ResourceInstance, key DeposedKey) {
+	rs := ms.Resource(addr.Resource)
+	if rs == nil {
+		return
+	}
+	is := rs.Instance(addr.Key)
+	if is == nil {
+		return
+	}
+	delete(is.Deposed, key)
+
+	if !is.HasObjects() {
+		// If we have no objects at all then we'll clean up.
+		delete(rs.Instances, addr.Key)
+	}
+	if len(rs.Instances) == 0 {
+		// Also clean up if we only expect to have one instance anyway
+		// and there are none. We leave the resource behind if an each mode
+		// is active because an empty list or map of instances is a valid state.
+		delete(ms.Resources, addr.Resource.String())
+	}
+}
+
+// deposeResourceInstanceObject is the real implementation of
+// SyncState.DeposeResourceInstanceObject.
+func (ms *Module) deposeResourceInstanceObject(addr addrs.ResourceInstance, forceKey DeposedKey) DeposedKey {
+	is := ms.ResourceInstance(addr)
+	if is == nil {
+		return NotDeposed
+	}
+	return is.deposeCurrentObject(forceKey)
+}
+
+// maybeRestoreResourceInstanceDeposed is the real implementation of
+// SyncState.MaybeRestoreResourceInstanceDeposed.
+func (ms *Module) maybeRestoreResourceInstanceDeposed(addr addrs.ResourceInstance, key DeposedKey) bool {
+	rs := ms.Resource(addr.Resource)
+	if rs == nil {
+		return false
+	}
+	is := rs.Instance(addr.Key)
+	if is == nil {
+		return false
+	}
+	if is.Current != nil {
+		return false
+	}
+	if len(is.Deposed) == 0 {
+		return false
+	}
+	is.Current = is.Deposed[key]
+	delete(is.Deposed, key)
+	return true
+}
+
+// SetOutputValue writes an output value into the state, overwriting any
+// existing value of the same name.
+func (ms *Module) SetOutputValue(name string, value cty.Value, sensitive bool) *OutputValue {
+	os := &OutputValue{
+		Addr: addrs.AbsOutputValue{
+			Module: ms.Addr,
+			OutputValue: addrs.OutputValue{
+				Name: name,
+			},
+		},
+		Value:     value,
+		Sensitive: sensitive,
+	}
+	ms.OutputValues[name] = os
+	return os
+}
+
+// RemoveOutputValue removes the output value of the given name from the state,
+// if it exists. This method is a no-op if there is no value of the given
+// name.
+func (ms *Module) RemoveOutputValue(name string) {
+	delete(ms.OutputValues, name)
+}
+
+// SetLocalValue writes a local value into the state, overwriting any
+// existing value of the same name.
+func (ms *Module) SetLocalValue(name string, value cty.Value) {
+	ms.LocalValues[name] = value
+}
+
+// RemoveLocalValue removes the local value of the given name from the state,
+// if it exists. This method is a no-op if there is no value of the given
+// name.
+func (ms *Module) RemoveLocalValue(name string) {
+	delete(ms.LocalValues, name)
+}
+
+// PruneResourceHusks is a specialized method that will remove any Resource
+// objects that do not contain any instances, even if they have an EachMode.
+//
+// You probably shouldn't call this! See the method of the same name on
+// type State for more information on what this is for and the rare situations
+// where it is safe to use.
+func (ms *Module) PruneResourceHusks() {
+	for _, rs := range ms.Resources {
+		if len(rs.Instances) == 0 {
+			ms.RemoveResource(rs.Addr.Resource)
+		}
+	}
+}
+
+// empty returns true if the receving module state is contributing nothing
+// to the state. In other words, it returns true if the module could be
+// removed from the state altogether without changing the meaning of the state.
+//
+// In practice a module containing no objects is the same as a non-existent
+// module, and so we can opportunistically clean up once a module becomes
+// empty on the assumption that it will be re-added if needed later.
+func (ms *Module) empty() bool {
+	if ms == nil {
+		return true
+	}
+
+	// This must be updated to cover any new collections added to Module
+	// in future.
+	return (len(ms.Resources) == 0 &&
+		len(ms.OutputValues) == 0 &&
+		len(ms.LocalValues) == 0)
+}
diff --git a/v1.5.7/internal/states/objectstatus_string.go b/v1.5.7/internal/states/objectstatus_string.go
new file mode 100644
index 0000000..96a6db2
--- /dev/null
+++ b/v1.5.7/internal/states/objectstatus_string.go
@@ -0,0 +1,33 @@
+// Code generated by "stringer -type ObjectStatus"; DO NOT EDIT.
+
+package states
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[ObjectReady-82]
+	_ = x[ObjectTainted-84]
+	_ = x[ObjectPlanned-80]
+}
+
+const (
+	_ObjectStatus_name_0 = "ObjectPlanned"
+	_ObjectStatus_name_1 = "ObjectReady"
+	_ObjectStatus_name_2 = "ObjectTainted"
+)
+
+func (i ObjectStatus) String() string {
+	switch {
+	case i == 80:
+		return _ObjectStatus_name_0
+	case i == 82:
+		return _ObjectStatus_name_1
+	case i == 84:
+		return _ObjectStatus_name_2
+	default:
+		return "ObjectStatus(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/v1.5.7/internal/states/output_value.go b/v1.5.7/internal/states/output_value.go
new file mode 100644
index 0000000..0e5cedb
--- /dev/null
+++ b/v1.5.7/internal/states/output_value.go
@@ -0,0 +1,19 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package states
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// OutputValue represents the state of a particular output value.
+//
+// It is not valid to mutate an OutputValue object once it has been created.
+// Instead, create an entirely new OutputValue to replace the previous one.
+type OutputValue struct {
+	Addr      addrs.AbsOutputValue
+	Value     cty.Value
+	Sensitive bool
+}
diff --git a/v1.5.7/internal/states/remote/remote.go b/v1.5.7/internal/states/remote/remote.go
new file mode 100644
index 0000000..7b4fbb7
--- /dev/null
+++ b/v1.5.7/internal/states/remote/remote.go
@@ -0,0 +1,41 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+// Client is the interface that must be implemented for a remote state
+// driver. It supports dumb put/get/delete, and the higher level structs
+// handle persisting the state properly here.
+type Client interface {
+	Get() (*Payload, error)
+	Put([]byte) error
+	Delete() error
+}
+
+// ClientForcePusher is an optional interface that allows a remote
+// state to force push by managing a flag on the client that is
+// toggled on by a call to EnableForcePush.
+type ClientForcePusher interface {
+	Client
+	EnableForcePush()
+}
+
+// ClientLocker is an optional interface that allows a remote state
+// backend to enable state lock/unlock.
+type ClientLocker interface {
+	Client
+	statemgr.Locker
+}
+
+// Payload is the return value from the remote state storage.
+type Payload struct {
+	MD5  []byte
+	Data []byte
+}
+
+// Factory is the factory function to create a remote client.
+type Factory func(map[string]string) (Client, error)
diff --git a/v1.5.7/internal/states/remote/remote_test.go b/v1.5.7/internal/states/remote/remote_test.go
new file mode 100644
index 0000000..f28b989
--- /dev/null
+++ b/v1.5.7/internal/states/remote/remote_test.go
@@ -0,0 +1,133 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"crypto/md5"
+	"encoding/json"
+	"testing"
+)
+
+func TestRemoteClient_noPayload(t *testing.T) {
+	s := &State{
+		Client: nilClient{},
+	}
+	if err := s.RefreshState(); err != nil {
+		t.Fatal("error refreshing empty remote state")
+	}
+}
+
+// nilClient returns nil for everything
+type nilClient struct{}
+
+func (nilClient) Get() (*Payload, error) { return nil, nil }
+
+func (c nilClient) Put([]byte) error { return nil }
+
+func (c nilClient) Delete() error { return nil }
+
+// mockClient is a client that tracks persisted state snapshots only in
+// memory and also logs what it has been asked to do for use in test
+// assertions.
+type mockClient struct {
+	current []byte
+	log     []mockClientRequest
+}
+
+type mockClientRequest struct {
+	Method  string
+	Content map[string]interface{}
+}
+
+func (c *mockClient) Get() (*Payload, error) {
+	c.appendLog("Get", c.current)
+	if c.current == nil {
+		return nil, nil
+	}
+	checksum := md5.Sum(c.current)
+	return &Payload{
+		Data: c.current,
+		MD5:  checksum[:],
+	}, nil
+}
+
+func (c *mockClient) Put(data []byte) error {
+	c.appendLog("Put", data)
+	c.current = data
+	return nil
+}
+
+func (c *mockClient) Delete() error {
+	c.appendLog("Delete", c.current)
+	c.current = nil
+	return nil
+}
+
+func (c *mockClient) appendLog(method string, content []byte) {
+	// For easier test assertions, we actually log the result of decoding
+	// the content JSON rather than the raw bytes. Callers are in principle
+	// allowed to provide any arbitrary bytes here, but we know we're only
+	// using this to test our own State implementation here and that always
+	// uses the JSON state format, so this is fine.
+
+	var contentVal map[string]interface{}
+	if content != nil {
+		err := json.Unmarshal(content, &contentVal)
+		if err != nil {
+			panic(err) // should never happen because our tests control this input
+		}
+	}
+	c.log = append(c.log, mockClientRequest{method, contentVal})
+}
+
+// mockClientForcePusher is like mockClient, but also implements
+// EnableForcePush, allowing testing for this behavior
+type mockClientForcePusher struct {
+	current []byte
+	force   bool
+	log     []mockClientRequest
+}
+
+func (c *mockClientForcePusher) Get() (*Payload, error) {
+	c.appendLog("Get", c.current)
+	if c.current == nil {
+		return nil, nil
+	}
+	checksum := md5.Sum(c.current)
+	return &Payload{
+		Data: c.current,
+		MD5:  checksum[:],
+	}, nil
+}
+
+func (c *mockClientForcePusher) Put(data []byte) error {
+	if c.force {
+		c.appendLog("Force Put", data)
+	} else {
+		c.appendLog("Put", data)
+	}
+	c.current = data
+	return nil
+}
+
+// Implements remote.ClientForcePusher
+func (c *mockClientForcePusher) EnableForcePush() {
+	c.force = true
+}
+
+func (c *mockClientForcePusher) Delete() error {
+	c.appendLog("Delete", c.current)
+	c.current = nil
+	return nil
+}
+func (c *mockClientForcePusher) appendLog(method string, content []byte) {
+	var contentVal map[string]interface{}
+	if content != nil {
+		err := json.Unmarshal(content, &contentVal)
+		if err != nil {
+			panic(err) // should never happen because our tests control this input
+		}
+	}
+	c.log = append(c.log, mockClientRequest{method, contentVal})
+}
diff --git a/v1.5.7/internal/states/remote/state.go b/v1.5.7/internal/states/remote/state.go
new file mode 100644
index 0000000..f30a43d
--- /dev/null
+++ b/v1.5.7/internal/states/remote/state.go
@@ -0,0 +1,284 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"bytes"
+	"fmt"
+	"log"
+	"sync"
+
+	uuid "github.com/hashicorp/go-uuid"
+
+	"github.com/hashicorp/terraform/internal/backend/local"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// State implements the State interfaces in the state package to handle
+// reading and writing the remote state. This State on its own does no
+// local caching so every persist will go to the remote storage and local
+// writes will go to memory.
+type State struct {
+	mu sync.Mutex
+
+	Client Client
+
+	// We track two pieces of meta data in addition to the state itself:
+	//
+	// lineage - the state's unique ID
+	// serial  - the monotonic counter of "versions" of the state
+	//
+	// Both of these (along with state) have a sister field
+	// that represents the values read in from an existing source.
+	// All three of these values are used to determine if the new
+	// state has changed from an existing state we read in.
+	lineage, readLineage string
+	serial, readSerial   uint64
+	state, readState     *states.State
+	disableLocks         bool
+
+	// If this is set then the state manager will decline to store intermediate
+	// state snapshots created while a Terraform Core apply operation is in
+	// progress. Otherwise (by default) it will accept persistent snapshots
+	// using the default rules defined in the local backend.
+	DisableIntermediateSnapshots bool
+}
+
+var _ statemgr.Full = (*State)(nil)
+var _ statemgr.Migrator = (*State)(nil)
+var _ local.IntermediateStateConditionalPersister = (*State)(nil)
+
+// statemgr.Reader impl.
+func (s *State) State() *states.State {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	return s.state.DeepCopy()
+}
+
+func (s *State) GetRootOutputValues() (map[string]*states.OutputValue, error) {
+	if err := s.RefreshState(); err != nil {
+		return nil, fmt.Errorf("Failed to load state: %s", err)
+	}
+
+	state := s.State()
+	if state == nil {
+		state = states.NewState()
+	}
+
+	return state.RootModule().OutputValues, nil
+}
+
+// StateForMigration is part of our implementation of statemgr.Migrator.
+func (s *State) StateForMigration() *statefile.File {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	return statefile.New(s.state.DeepCopy(), s.lineage, s.serial)
+}
+
+// statemgr.Writer impl.
+func (s *State) WriteState(state *states.State) error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	// We create a deep copy of the state here, because the caller also has
+	// a reference to the given object and can potentially go on to mutate
+	// it after we return, but we want the snapshot at this point in time.
+	s.state = state.DeepCopy()
+
+	return nil
+}
+
+// WriteStateForMigration is part of our implementation of statemgr.Migrator.
+func (s *State) WriteStateForMigration(f *statefile.File, force bool) error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	if !force {
+		checkFile := statefile.New(s.state, s.lineage, s.serial)
+		if err := statemgr.CheckValidImport(f, checkFile); err != nil {
+			return err
+		}
+	}
+
+	// The remote backend needs to pass the `force` flag through to its client.
+	// For backends that support such operations, inform the client
+	// that a force push has been requested
+	c, isForcePusher := s.Client.(ClientForcePusher)
+	if force && isForcePusher {
+		c.EnableForcePush()
+	}
+
+	// We create a deep copy of the state here, because the caller also has
+	// a reference to the given object and can potentially go on to mutate
+	// it after we return, but we want the snapshot at this point in time.
+	s.state = f.State.DeepCopy()
+	s.lineage = f.Lineage
+	s.serial = f.Serial
+
+	return nil
+}
+
+// statemgr.Refresher impl.
+func (s *State) RefreshState() error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	return s.refreshState()
+}
+
+// refreshState is the main implementation of RefreshState, but split out so
+// that we can make internal calls to it from methods that are already holding
+// the s.mu lock.
+func (s *State) refreshState() error {
+	payload, err := s.Client.Get()
+	if err != nil {
+		return err
+	}
+
+	// no remote state is OK
+	if payload == nil {
+		s.readState = nil
+		s.lineage = ""
+		s.serial = 0
+		return nil
+	}
+
+	stateFile, err := statefile.Read(bytes.NewReader(payload.Data))
+	if err != nil {
+		return err
+	}
+
+	s.lineage = stateFile.Lineage
+	s.serial = stateFile.Serial
+	s.state = stateFile.State
+
+	// Properties from the remote must be separate so we can
+	// track changes as lineage, serial and/or state are mutated
+	s.readLineage = stateFile.Lineage
+	s.readSerial = stateFile.Serial
+	s.readState = s.state.DeepCopy()
+	return nil
+}
+
+// statemgr.Persister impl.
+func (s *State) PersistState(schemas *terraform.Schemas) error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	log.Printf("[DEBUG] states/remote: state read serial is: %d; serial is: %d", s.readSerial, s.serial)
+	log.Printf("[DEBUG] states/remote: state read lineage is: %s; lineage is: %s", s.readLineage, s.lineage)
+
+	if s.readState != nil {
+		lineageUnchanged := s.readLineage != "" && s.lineage == s.readLineage
+		serialUnchanged := s.readSerial != 0 && s.serial == s.readSerial
+		stateUnchanged := statefile.StatesMarshalEqual(s.state, s.readState)
+		if stateUnchanged && lineageUnchanged && serialUnchanged {
+			// If the state, lineage or serial haven't changed at all then we have nothing to do.
+			return nil
+		}
+		s.serial++
+	} else {
+		// We might be writing a new state altogether, but before we do that
+		// we'll check to make sure there isn't already a snapshot present
+		// that we ought to be updating.
+		err := s.refreshState()
+		if err != nil {
+			return fmt.Errorf("failed checking for existing remote state: %s", err)
+		}
+		log.Printf("[DEBUG] states/remote: after refresh, state read serial is: %d; serial is: %d", s.readSerial, s.serial)
+		log.Printf("[DEBUG] states/remote: after refresh, state read lineage is: %s; lineage is: %s", s.readLineage, s.lineage)
+		if s.lineage == "" { // indicates that no state snapshot is present yet
+			lineage, err := uuid.GenerateUUID()
+			if err != nil {
+				return fmt.Errorf("failed to generate initial lineage: %v", err)
+			}
+			s.lineage = lineage
+			s.serial++
+		}
+	}
+
+	f := statefile.New(s.state, s.lineage, s.serial)
+
+	var buf bytes.Buffer
+	err := statefile.Write(f, &buf)
+	if err != nil {
+		return err
+	}
+
+	err = s.Client.Put(buf.Bytes())
+	if err != nil {
+		return err
+	}
+
+	// After we've successfully persisted, what we just wrote is our new
+	// reference state until someone calls RefreshState again.
+	// We've potentially overwritten (via force) the state, lineage
+	// and / or serial (and serial was incremented) so we copy over all
+	// three fields so everything matches the new state and a subsequent
+	// operation would correctly detect no changes to the lineage, serial or state.
+	s.readState = s.state.DeepCopy()
+	s.readLineage = s.lineage
+	s.readSerial = s.serial
+	return nil
+}
+
+// ShouldPersistIntermediateState implements local.IntermediateStateConditionalPersister
+func (s *State) ShouldPersistIntermediateState(info *local.IntermediateStatePersistInfo) bool {
+	if s.DisableIntermediateSnapshots {
+		return false
+	}
+	return local.DefaultIntermediateStatePersistRule(info)
+}
+
+// Lock calls the Client's Lock method if it's implemented.
+func (s *State) Lock(info *statemgr.LockInfo) (string, error) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	if s.disableLocks {
+		return "", nil
+	}
+
+	if c, ok := s.Client.(ClientLocker); ok {
+		return c.Lock(info)
+	}
+	return "", nil
+}
+
+// Unlock calls the Client's Unlock method if it's implemented.
+func (s *State) Unlock(id string) error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	if s.disableLocks {
+		return nil
+	}
+
+	if c, ok := s.Client.(ClientLocker); ok {
+		return c.Unlock(id)
+	}
+	return nil
+}
+
+// DisableLocks turns the Lock and Unlock methods into no-ops. This is intended
+// to be called during initialization of a state manager and should not be
+// called after any of the statemgr.Full interface methods have been called.
+func (s *State) DisableLocks() {
+	s.disableLocks = true
+}
+
+// StateSnapshotMeta returns the metadata from the most recently persisted
+// or refreshed persistent state snapshot.
+//
+// This is an implementation of statemgr.PersistentMeta.
+func (s *State) StateSnapshotMeta() statemgr.SnapshotMeta {
+	return statemgr.SnapshotMeta{
+		Lineage: s.lineage,
+		Serial:  s.serial,
+	}
+}
diff --git a/v1.5.7/internal/states/remote/state_test.go b/v1.5.7/internal/states/remote/state_test.go
new file mode 100644
index 0000000..85d73a9
--- /dev/null
+++ b/v1.5.7/internal/states/remote/state_test.go
@@ -0,0 +1,743 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"log"
+	"sync"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/zclconf/go-cty/cty"
+
+	tfaddr "github.com/hashicorp/terraform-registry-address"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+	"github.com/hashicorp/terraform/version"
+)
+
+func TestState_impl(t *testing.T) {
+	var _ statemgr.Reader = new(State)
+	var _ statemgr.Writer = new(State)
+	var _ statemgr.Persister = new(State)
+	var _ statemgr.Refresher = new(State)
+	var _ statemgr.OutputReader = new(State)
+	var _ statemgr.Locker = new(State)
+}
+
+func TestStateRace(t *testing.T) {
+	s := &State{
+		Client: nilClient{},
+	}
+
+	current := states.NewState()
+
+	var wg sync.WaitGroup
+
+	for i := 0; i < 100; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			s.WriteState(current)
+			s.PersistState(nil)
+			s.RefreshState()
+		}()
+	}
+	wg.Wait()
+}
+
+// testCase encapsulates a test state test
+type testCase struct {
+	name string
+	// A function to mutate state and return a cleanup function
+	mutationFunc func(*State) (*states.State, func())
+	// The expected requests to have taken place
+	expectedRequests []mockClientRequest
+	// Mark this case as not having a request
+	noRequest bool
+}
+
+// isRequested ensures a test that is specified as not having
+// a request doesn't have one by checking if a method exists
+// on the expectedRequest.
+func (tc testCase) isRequested(t *testing.T) bool {
+	for _, expectedMethod := range tc.expectedRequests {
+		hasMethod := expectedMethod.Method != ""
+		if tc.noRequest && hasMethod {
+			t.Fatalf("expected no content for %q but got: %v", tc.name, expectedMethod)
+		}
+	}
+	return !tc.noRequest
+}
+
+func TestStatePersist(t *testing.T) {
+	testCases := []testCase{
+		{
+			name: "first state persistence",
+			mutationFunc: func(mgr *State) (*states.State, func()) {
+				mgr.state = &states.State{
+					Modules: map[string]*states.Module{"": {}},
+				}
+				s := mgr.State()
+				s.RootModule().SetResourceInstanceCurrent(
+					addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Name: "myfile",
+						Type: "local_file",
+					}.Instance(addrs.NoKey),
+					&states.ResourceInstanceObjectSrc{
+						AttrsFlat: map[string]string{
+							"filename": "file.txt",
+						},
+						Status: states.ObjectReady,
+					},
+					addrs.AbsProviderConfig{
+						Provider: tfaddr.Provider{Namespace: "local"},
+					},
+				)
+				return s, func() {}
+			},
+			expectedRequests: []mockClientRequest{
+				// Expect an initial refresh, which returns nothing since there is no remote state.
+				{
+					Method:  "Get",
+					Content: nil,
+				},
+				// Expect a second refresh, since the read state is nil
+				{
+					Method:  "Get",
+					Content: nil,
+				},
+				// Expect an initial push with values and a serial of 1
+				{
+					Method: "Put",
+					Content: map[string]interface{}{
+						"version":           4.0, // encoding/json decodes this as float64 by default
+						"lineage":           "some meaningless value",
+						"serial":            1.0, // encoding/json decodes this as float64 by default
+						"terraform_version": version.Version,
+						"outputs":           map[string]interface{}{},
+						"resources": []interface{}{
+							map[string]interface{}{
+								"instances": []interface{}{
+									map[string]interface{}{
+										"attributes_flat": map[string]interface{}{
+											"filename": "file.txt",
+										},
+										"schema_version":       0.0,
+										"sensitive_attributes": []interface{}{},
+									},
+								},
+								"mode":     "managed",
+								"name":     "myfile",
+								"provider": `provider["/local/"]`,
+								"type":     "local_file",
+							},
+						},
+						"check_results": nil,
+					},
+				},
+			},
+		},
+		// If lineage changes, expect the serial to increment
+		{
+			name: "change lineage",
+			mutationFunc: func(mgr *State) (*states.State, func()) {
+				mgr.lineage = "mock-lineage"
+				return mgr.State(), func() {}
+			},
+			expectedRequests: []mockClientRequest{
+				{
+					Method: "Put",
+					Content: map[string]interface{}{
+						"version":           4.0, // encoding/json decodes this as float64 by default
+						"lineage":           "mock-lineage",
+						"serial":            2.0, // encoding/json decodes this as float64 by default
+						"terraform_version": version.Version,
+						"outputs":           map[string]interface{}{},
+						"resources": []interface{}{
+							map[string]interface{}{
+								"instances": []interface{}{
+									map[string]interface{}{
+										"attributes_flat": map[string]interface{}{
+											"filename": "file.txt",
+										},
+										"schema_version":       0.0,
+										"sensitive_attributes": []interface{}{},
+									},
+								},
+								"mode":     "managed",
+								"name":     "myfile",
+								"provider": `provider["/local/"]`,
+								"type":     "local_file",
+							},
+						},
+						"check_results": nil,
+					},
+				},
+			},
+		},
+		// removing resources should increment the serial
+		{
+			name: "remove resources",
+			mutationFunc: func(mgr *State) (*states.State, func()) {
+				mgr.state.RootModule().Resources = map[string]*states.Resource{}
+				return mgr.State(), func() {}
+			},
+			expectedRequests: []mockClientRequest{
+				{
+					Method: "Put",
+					Content: map[string]interface{}{
+						"version":           4.0, // encoding/json decodes this as float64 by default
+						"lineage":           "mock-lineage",
+						"serial":            3.0, // encoding/json decodes this as float64 by default
+						"terraform_version": version.Version,
+						"outputs":           map[string]interface{}{},
+						"resources":         []interface{}{},
+						"check_results":     nil,
+					},
+				},
+			},
+		},
+		// If the remote serial is incremented, then we increment it once more.
+		{
+			name: "change serial",
+			mutationFunc: func(mgr *State) (*states.State, func()) {
+				originalSerial := mgr.serial
+				mgr.serial++
+				return mgr.State(), func() {
+					mgr.serial = originalSerial
+				}
+			},
+			expectedRequests: []mockClientRequest{
+				{
+					Method: "Put",
+					Content: map[string]interface{}{
+						"version":           4.0, // encoding/json decodes this as float64 by default
+						"lineage":           "mock-lineage",
+						"serial":            5.0, // encoding/json decodes this as float64 by default
+						"terraform_version": version.Version,
+						"outputs":           map[string]interface{}{},
+						"resources":         []interface{}{},
+						"check_results":     nil,
+					},
+				},
+			},
+		},
+		// Adding an output should cause the serial to increment as well.
+		{
+			name: "add output to state",
+			mutationFunc: func(mgr *State) (*states.State, func()) {
+				s := mgr.State()
+				s.RootModule().SetOutputValue("foo", cty.StringVal("bar"), false)
+				return s, func() {}
+			},
+			expectedRequests: []mockClientRequest{
+				{
+					Method: "Put",
+					Content: map[string]interface{}{
+						"version":           4.0, // encoding/json decodes this as float64 by default
+						"lineage":           "mock-lineage",
+						"serial":            4.0, // encoding/json decodes this as float64 by default
+						"terraform_version": version.Version,
+						"outputs": map[string]interface{}{
+							"foo": map[string]interface{}{
+								"type":  "string",
+								"value": "bar",
+							},
+						},
+						"resources":     []interface{}{},
+						"check_results": nil,
+					},
+				},
+			},
+		},
+		// ...as should changing an output
+		{
+			name: "mutate state bar -> baz",
+			mutationFunc: func(mgr *State) (*states.State, func()) {
+				s := mgr.State()
+				s.RootModule().SetOutputValue("foo", cty.StringVal("baz"), false)
+				return s, func() {}
+			},
+			expectedRequests: []mockClientRequest{
+				{
+					Method: "Put",
+					Content: map[string]interface{}{
+						"version":           4.0, // encoding/json decodes this as float64 by default
+						"lineage":           "mock-lineage",
+						"serial":            5.0, // encoding/json decodes this as float64 by default
+						"terraform_version": version.Version,
+						"outputs": map[string]interface{}{
+							"foo": map[string]interface{}{
+								"type":  "string",
+								"value": "baz",
+							},
+						},
+						"resources":     []interface{}{},
+						"check_results": nil,
+					},
+				},
+			},
+		},
+		{
+			name: "nothing changed",
+			mutationFunc: func(mgr *State) (*states.State, func()) {
+				s := mgr.State()
+				return s, func() {}
+			},
+			noRequest: true,
+		},
+		// If the remote state's serial is less (force push), then we
+		// increment it once from there.
+		{
+			name: "reset serial (force push style)",
+			mutationFunc: func(mgr *State) (*states.State, func()) {
+				mgr.serial = 2
+				return mgr.State(), func() {}
+			},
+			expectedRequests: []mockClientRequest{
+				{
+					Method: "Put",
+					Content: map[string]interface{}{
+						"version":           4.0, // encoding/json decodes this as float64 by default
+						"lineage":           "mock-lineage",
+						"serial":            3.0, // encoding/json decodes this as float64 by default
+						"terraform_version": version.Version,
+						"outputs": map[string]interface{}{
+							"foo": map[string]interface{}{
+								"type":  "string",
+								"value": "baz",
+							},
+						},
+						"resources":     []interface{}{},
+						"check_results": nil,
+					},
+				},
+			},
+		},
+	}
+
+	// Initial setup of state just to give us a fixed starting point for our
+	// test assertions below, or else we'd need to deal with
+	// random lineage.
+	mgr := &State{
+		Client: &mockClient{},
+	}
+
+	// In normal use (during a Terraform operation) we always refresh and read
+	// before any writes would happen, so we'll mimic that here for realism.
+	// NB This causes a GET to be logged so the first item in the test cases
+	// must account for this
+	if err := mgr.RefreshState(); err != nil {
+		t.Fatalf("failed to RefreshState: %s", err)
+	}
+
+	// Our client is a mockClient which has a log we
+	// use to check that operations generate expected requests
+	mockClient := mgr.Client.(*mockClient)
+
+	// logIdx tracks the current index of the log separate from
+	// the loop iteration so we can check operations that don't
+	// cause any requests to be generated
+	logIdx := 0
+
+	// Run tests in order.
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			s, cleanup := tc.mutationFunc(mgr)
+
+			if err := mgr.WriteState(s); err != nil {
+				t.Fatalf("failed to WriteState for %q: %s", tc.name, err)
+			}
+			if err := mgr.PersistState(nil); err != nil {
+				t.Fatalf("failed to PersistState for %q: %s", tc.name, err)
+			}
+
+			if tc.isRequested(t) {
+				// Get captured request from the mock client log
+				// based on the index of the current test
+				if logIdx >= len(mockClient.log) {
+					t.Fatalf("request lock and index are out of sync on %q: idx=%d len=%d", tc.name, logIdx, len(mockClient.log))
+				}
+				for expectedRequestIdx := 0; expectedRequestIdx < len(tc.expectedRequests); expectedRequestIdx++ {
+					loggedRequest := mockClient.log[logIdx]
+					logIdx++
+					if diff := cmp.Diff(tc.expectedRequests[expectedRequestIdx], loggedRequest, cmpopts.IgnoreMapEntries(func(key string, value interface{}) bool {
+						// This is required since the initial state creation causes the lineage to be a UUID that is not known at test time.
+						return tc.name == "first state persistence" && key == "lineage"
+					})); len(diff) > 0 {
+						t.Logf("incorrect client requests for %q:\n%s", tc.name, diff)
+						t.Fail()
+					}
+				}
+			}
+			cleanup()
+		})
+	}
+	logCnt := len(mockClient.log)
+	if logIdx != logCnt {
+		t.Fatalf("not all requests were read. Expected logIdx to be %d but got %d", logCnt, logIdx)
+	}
+}
+
+func TestState_GetRootOutputValues(t *testing.T) {
+	// Initial setup of state with outputs already defined
+	mgr := &State{
+		Client: &mockClient{
+			current: []byte(`
+				{
+					"version": 4,
+					"lineage": "mock-lineage",
+					"serial": 1,
+					"terraform_version":"0.0.0",
+					"outputs": {"foo": {"value":"bar", "type": "string"}},
+					"resources": []
+				}
+			`),
+		},
+	}
+
+	outputs, err := mgr.GetRootOutputValues()
+	if err != nil {
+		t.Errorf("Expected GetRootOutputValues to not return an error, but it returned %v", err)
+	}
+
+	if len(outputs) != 1 {
+		t.Errorf("Expected %d outputs, but received %d", 1, len(outputs))
+	}
+}
+
+type migrationTestCase struct {
+	name string
+	// A function to generate a statefile
+	stateFile func(*State) *statefile.File
+	// The expected request to have taken place
+	expectedRequest mockClientRequest
+	// Mark this case as not having a request
+	expectedError string
+	// force flag passed to client
+	force bool
+}
+
+func TestWriteStateForMigration(t *testing.T) {
+	mgr := &State{
+		Client: &mockClient{
+			current: []byte(`
+				{
+					"version": 4,
+					"lineage": "mock-lineage",
+					"serial": 3,
+					"terraform_version":"0.0.0",
+					"outputs": {"foo": {"value":"bar", "type": "string"}},
+					"resources": []
+				}
+			`),
+		},
+	}
+
+	testCases := []migrationTestCase{
+		// Refreshing state before we run the test loop causes a GET
+		{
+			name: "refresh state",
+			stateFile: func(mgr *State) *statefile.File {
+				return mgr.StateForMigration()
+			},
+			expectedRequest: mockClientRequest{
+				Method: "Get",
+				Content: map[string]interface{}{
+					"version":           4.0,
+					"lineage":           "mock-lineage",
+					"serial":            3.0,
+					"terraform_version": "0.0.0",
+					"outputs":           map[string]interface{}{"foo": map[string]interface{}{"type": string("string"), "value": string("bar")}},
+					"resources":         []interface{}{},
+				},
+			},
+		},
+		{
+			name: "cannot import lesser serial without force",
+			stateFile: func(mgr *State) *statefile.File {
+				return statefile.New(mgr.state, mgr.lineage, 1)
+			},
+			expectedError: "cannot import state with serial 1 over newer state with serial 3",
+		},
+		{
+			name: "cannot import differing lineage without force",
+			stateFile: func(mgr *State) *statefile.File {
+				return statefile.New(mgr.state, "different-lineage", mgr.serial)
+			},
+			expectedError: `cannot import state with lineage "different-lineage" over unrelated state with lineage "mock-lineage"`,
+		},
+		{
+			name: "can import lesser serial with force",
+			stateFile: func(mgr *State) *statefile.File {
+				return statefile.New(mgr.state, mgr.lineage, 1)
+			},
+			expectedRequest: mockClientRequest{
+				Method: "Put",
+				Content: map[string]interface{}{
+					"version":           4.0,
+					"lineage":           "mock-lineage",
+					"serial":            2.0,
+					"terraform_version": version.Version,
+					"outputs":           map[string]interface{}{"foo": map[string]interface{}{"type": string("string"), "value": string("bar")}},
+					"resources":         []interface{}{},
+					"check_results":     nil,
+				},
+			},
+			force: true,
+		},
+		{
+			name: "cannot import differing lineage without force",
+			stateFile: func(mgr *State) *statefile.File {
+				return statefile.New(mgr.state, "different-lineage", mgr.serial)
+			},
+			expectedRequest: mockClientRequest{
+				Method: "Put",
+				Content: map[string]interface{}{
+					"version":           4.0,
+					"lineage":           "different-lineage",
+					"serial":            3.0,
+					"terraform_version": version.Version,
+					"outputs":           map[string]interface{}{"foo": map[string]interface{}{"type": string("string"), "value": string("bar")}},
+					"resources":         []interface{}{},
+					"check_results":     nil,
+				},
+			},
+			force: true,
+		},
+	}
+
+	// In normal use (during a Terraform operation) we always refresh and read
+	// before any writes would happen, so we'll mimic that here for realism.
+	// NB This causes a GET to be logged so the first item in the test cases
+	// must account for this
+	if err := mgr.RefreshState(); err != nil {
+		t.Fatalf("failed to RefreshState: %s", err)
+	}
+
+	if err := mgr.WriteState(mgr.State()); err != nil {
+		t.Fatalf("failed to write initial state: %s", err)
+	}
+
+	// Our client is a mockClient which has a log we
+	// use to check that operations generate expected requests
+	mockClient := mgr.Client.(*mockClient)
+
+	// logIdx tracks the current index of the log separate from
+	// the loop iteration so we can check operations that don't
+	// cause any requests to be generated
+	logIdx := 0
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			sf := tc.stateFile(mgr)
+			err := mgr.WriteStateForMigration(sf, tc.force)
+			shouldError := tc.expectedError != ""
+
+			// If we are expecting and error check it and move on
+			if shouldError {
+				if err == nil {
+					t.Fatalf("test case %q should have failed with error %q", tc.name, tc.expectedError)
+				} else if err.Error() != tc.expectedError {
+					t.Fatalf("test case %q expected error %q but got %q", tc.name, tc.expectedError, err)
+				}
+				return
+			}
+
+			if err != nil {
+				t.Fatalf("test case %q failed: %v", tc.name, err)
+			}
+
+			// At this point we should just do a normal write and persist
+			// as would happen from the CLI
+			mgr.WriteState(mgr.State())
+			mgr.PersistState(nil)
+
+			if logIdx >= len(mockClient.log) {
+				t.Fatalf("request lock and index are out of sync on %q: idx=%d len=%d", tc.name, logIdx, len(mockClient.log))
+			}
+			loggedRequest := mockClient.log[logIdx]
+			logIdx++
+			if diff := cmp.Diff(tc.expectedRequest, loggedRequest); len(diff) > 0 {
+				t.Fatalf("incorrect client requests for %q:\n%s", tc.name, diff)
+			}
+		})
+	}
+
+	logCnt := len(mockClient.log)
+	if logIdx != logCnt {
+		log.Fatalf("not all requests were read. Expected logIdx to be %d but got %d", logCnt, logIdx)
+	}
+}
+
+// This test runs the same test cases as above, but with
+// a client that implements EnableForcePush -- this allows
+// us to test that -force continues to work for backends without
+// this interface, but that this interface works for those that do.
+func TestWriteStateForMigrationWithForcePushClient(t *testing.T) {
+	mgr := &State{
+		Client: &mockClientForcePusher{
+			current: []byte(`
+				{
+					"version": 4,
+					"lineage": "mock-lineage",
+					"serial": 3,
+					"terraform_version":"0.0.0",
+					"outputs": {"foo": {"value":"bar", "type": "string"}},
+					"resources": []
+				}
+			`),
+		},
+	}
+
+	testCases := []migrationTestCase{
+		// Refreshing state before we run the test loop causes a GET
+		{
+			name: "refresh state",
+			stateFile: func(mgr *State) *statefile.File {
+				return mgr.StateForMigration()
+			},
+			expectedRequest: mockClientRequest{
+				Method: "Get",
+				Content: map[string]interface{}{
+					"version":           4.0,
+					"lineage":           "mock-lineage",
+					"serial":            3.0,
+					"terraform_version": "0.0.0",
+					"outputs":           map[string]interface{}{"foo": map[string]interface{}{"type": string("string"), "value": string("bar")}},
+					"resources":         []interface{}{},
+				},
+			},
+		},
+		{
+			name: "cannot import lesser serial without force",
+			stateFile: func(mgr *State) *statefile.File {
+				return statefile.New(mgr.state, mgr.lineage, 1)
+			},
+			expectedError: "cannot import state with serial 1 over newer state with serial 3",
+		},
+		{
+			name: "cannot import differing lineage without force",
+			stateFile: func(mgr *State) *statefile.File {
+				return statefile.New(mgr.state, "different-lineage", mgr.serial)
+			},
+			expectedError: `cannot import state with lineage "different-lineage" over unrelated state with lineage "mock-lineage"`,
+		},
+		{
+			name: "can import lesser serial with force",
+			stateFile: func(mgr *State) *statefile.File {
+				return statefile.New(mgr.state, mgr.lineage, 1)
+			},
+			expectedRequest: mockClientRequest{
+				Method: "Force Put",
+				Content: map[string]interface{}{
+					"version":           4.0,
+					"lineage":           "mock-lineage",
+					"serial":            2.0,
+					"terraform_version": version.Version,
+					"outputs":           map[string]interface{}{"foo": map[string]interface{}{"type": string("string"), "value": string("bar")}},
+					"resources":         []interface{}{},
+					"check_results":     nil,
+				},
+			},
+			force: true,
+		},
+		{
+			name: "cannot import differing lineage without force",
+			stateFile: func(mgr *State) *statefile.File {
+				return statefile.New(mgr.state, "different-lineage", mgr.serial)
+			},
+			expectedRequest: mockClientRequest{
+				Method: "Force Put",
+				Content: map[string]interface{}{
+					"version":           4.0,
+					"lineage":           "different-lineage",
+					"serial":            3.0,
+					"terraform_version": version.Version,
+					"outputs":           map[string]interface{}{"foo": map[string]interface{}{"type": string("string"), "value": string("bar")}},
+					"resources":         []interface{}{},
+					"check_results":     nil,
+				},
+			},
+			force: true,
+		},
+	}
+
+	// In normal use (during a Terraform operation) we always refresh and read
+	// before any writes would happen, so we'll mimic that here for realism.
+	// NB This causes a GET to be logged so the first item in the test cases
+	// must account for this
+	if err := mgr.RefreshState(); err != nil {
+		t.Fatalf("failed to RefreshState: %s", err)
+	}
+
+	if err := mgr.WriteState(mgr.State()); err != nil {
+		t.Fatalf("failed to write initial state: %s", err)
+	}
+
+	// Our client is a mockClientForcePusher which has a log we
+	// use to check that operations generate expected requests
+	mockClient := mgr.Client.(*mockClientForcePusher)
+
+	if mockClient.force {
+		t.Fatalf("client should not default to force")
+	}
+
+	// logIdx tracks the current index of the log separate from
+	// the loop iteration so we can check operations that don't
+	// cause any requests to be generated
+	logIdx := 0
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			// Always reset client to not be force pushing
+			mockClient.force = false
+			sf := tc.stateFile(mgr)
+			err := mgr.WriteStateForMigration(sf, tc.force)
+			shouldError := tc.expectedError != ""
+
+			// If we are expecting and error check it and move on
+			if shouldError {
+				if err == nil {
+					t.Fatalf("test case %q should have failed with error %q", tc.name, tc.expectedError)
+				} else if err.Error() != tc.expectedError {
+					t.Fatalf("test case %q expected error %q but got %q", tc.name, tc.expectedError, err)
+				}
+				return
+			}
+
+			if err != nil {
+				t.Fatalf("test case %q failed: %v", tc.name, err)
+			}
+
+			if tc.force && !mockClient.force {
+				t.Fatalf("test case %q should have enabled force push", tc.name)
+			}
+
+			// At this point we should just do a normal write and persist
+			// as would happen from the CLI
+			mgr.WriteState(mgr.State())
+			mgr.PersistState(nil)
+
+			if logIdx >= len(mockClient.log) {
+				t.Fatalf("request lock and index are out of sync on %q: idx=%d len=%d", tc.name, logIdx, len(mockClient.log))
+			}
+			loggedRequest := mockClient.log[logIdx]
+			logIdx++
+			if diff := cmp.Diff(tc.expectedRequest, loggedRequest); len(diff) > 0 {
+				t.Fatalf("incorrect client requests for %q:\n%s", tc.name, diff)
+			}
+		})
+	}
+
+	logCnt := len(mockClient.log)
+	if logIdx != logCnt {
+		log.Fatalf("not all requests were read. Expected logIdx to be %d but got %d", logCnt, logIdx)
+	}
+}
diff --git a/v1.5.7/internal/states/remote/testing.go b/v1.5.7/internal/states/remote/testing.go
new file mode 100644
index 0000000..2c738cf
--- /dev/null
+++ b/v1.5.7/internal/states/remote/testing.go
@@ -0,0 +1,105 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package remote
+
+import (
+	"bytes"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+// TestClient is a generic function to test any client.
+func TestClient(t *testing.T, c Client) {
+	var buf bytes.Buffer
+	s := statemgr.TestFullInitialState()
+	sf := statefile.New(s, "stub-lineage", 2)
+	err := statefile.Write(sf, &buf)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	data := buf.Bytes()
+
+	if err := c.Put(data); err != nil {
+		t.Fatalf("put: %s", err)
+	}
+
+	p, err := c.Get()
+	if err != nil {
+		t.Fatalf("get: %s", err)
+	}
+	if !bytes.Equal(p.Data, data) {
+		t.Fatalf("expected full state %q\n\ngot: %q", string(p.Data), string(data))
+	}
+
+	if err := c.Delete(); err != nil {
+		t.Fatalf("delete: %s", err)
+	}
+
+	p, err = c.Get()
+	if err != nil {
+		t.Fatalf("get: %s", err)
+	}
+	if p != nil {
+		t.Fatalf("expected empty state, got: %q", string(p.Data))
+	}
+}
+
+// Test the lock implementation for a remote.Client.
+// This test requires 2 client instances, in oder to have multiple remote
+// clients since some implementations may tie the client to the lock, or may
+// have reentrant locks.
+func TestRemoteLocks(t *testing.T, a, b Client) {
+	lockerA, ok := a.(statemgr.Locker)
+	if !ok {
+		t.Fatal("client A not a statemgr.Locker")
+	}
+
+	lockerB, ok := b.(statemgr.Locker)
+	if !ok {
+		t.Fatal("client B not a statemgr.Locker")
+	}
+
+	infoA := statemgr.NewLockInfo()
+	infoA.Operation = "test"
+	infoA.Who = "clientA"
+
+	infoB := statemgr.NewLockInfo()
+	infoB.Operation = "test"
+	infoB.Who = "clientB"
+
+	lockIDA, err := lockerA.Lock(infoA)
+	if err != nil {
+		t.Fatal("unable to get initial lock:", err)
+	}
+
+	_, err = lockerB.Lock(infoB)
+	if err == nil {
+		lockerA.Unlock(lockIDA)
+		t.Fatal("client B obtained lock while held by client A")
+	}
+	if _, ok := err.(*statemgr.LockError); !ok {
+		t.Errorf("expected a LockError, but was %t: %s", err, err)
+	}
+
+	if err := lockerA.Unlock(lockIDA); err != nil {
+		t.Fatal("error unlocking client A", err)
+	}
+
+	lockIDB, err := lockerB.Lock(infoB)
+	if err != nil {
+		t.Fatal("unable to obtain lock from client B")
+	}
+
+	if lockIDB == lockIDA {
+		t.Fatalf("duplicate lock IDs: %q", lockIDB)
+	}
+
+	if err = lockerB.Unlock(lockIDB); err != nil {
+		t.Fatal("error unlocking client B:", err)
+	}
+
+	// TODO: Should we enforce that Unlock requires the correct ID?
+}
diff --git a/v1.5.7/internal/states/resource.go b/v1.5.7/internal/states/resource.go
new file mode 100644
index 0000000..ed42f6b
--- /dev/null
+++ b/v1.5.7/internal/states/resource.go
@@ -0,0 +1,218 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package states
+
+import (
+	"fmt"
+	"math/rand"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// Resource represents the state of a resource.
+type Resource struct {
+	// Addr is the absolute address for the resource this state object
+	// belongs to.
+	Addr addrs.AbsResource
+
+	// Instances contains the potentially-multiple instances associated with
+	// this resource. This map can contain a mixture of different key types,
+	// but only the ones of InstanceKeyType are considered current.
+	Instances map[addrs.InstanceKey]*ResourceInstance
+
+	// ProviderConfig is the absolute address for the provider configuration that
+	// most recently managed this resource. This is used to connect a resource
+	// with a provider configuration when the resource configuration block is
+	// not available, such as if it has been removed from configuration
+	// altogether.
+	ProviderConfig addrs.AbsProviderConfig
+}
+
+// Instance returns the state for the instance with the given key, or nil
+// if no such instance is tracked within the state.
+func (rs *Resource) Instance(key addrs.InstanceKey) *ResourceInstance {
+	return rs.Instances[key]
+}
+
+// CreateInstance creates an instance and adds it to the resource
+func (rs *Resource) CreateInstance(key addrs.InstanceKey) *ResourceInstance {
+	is := NewResourceInstance()
+	rs.Instances[key] = is
+	return is
+}
+
+// EnsureInstance returns the state for the instance with the given key,
+// creating a new empty state for it if one doesn't already exist.
+//
+// Because this may create and save a new state, it is considered to be
+// a write operation.
+func (rs *Resource) EnsureInstance(key addrs.InstanceKey) *ResourceInstance {
+	ret := rs.Instance(key)
+	if ret == nil {
+		ret = NewResourceInstance()
+		rs.Instances[key] = ret
+	}
+	return ret
+}
+
+// ResourceInstance represents the state of a particular instance of a resource.
+type ResourceInstance struct {
+	// Current, if non-nil, is the remote object that is currently represented
+	// by the corresponding resource instance.
+	Current *ResourceInstanceObjectSrc
+
+	// Deposed, if len > 0, contains any remote objects that were previously
+	// represented by the corresponding resource instance but have been
+	// replaced and are pending destruction due to the create_before_destroy
+	// lifecycle mode.
+	Deposed map[DeposedKey]*ResourceInstanceObjectSrc
+}
+
+// NewResourceInstance constructs and returns a new ResourceInstance, ready to
+// use.
+func NewResourceInstance() *ResourceInstance {
+	return &ResourceInstance{
+		Deposed: map[DeposedKey]*ResourceInstanceObjectSrc{},
+	}
+}
+
+// HasCurrent returns true if this resource instance has a "current"-generation
+// object. Most instances do, but this can briefly be false during a
+// create-before-destroy replace operation when the current has been deposed
+// but its replacement has not yet been created.
+func (i *ResourceInstance) HasCurrent() bool {
+	return i != nil && i.Current != nil
+}
+
+// HasDeposed returns true if this resource instance has a deposed object
+// with the given key.
+func (i *ResourceInstance) HasDeposed(key DeposedKey) bool {
+	return i != nil && i.Deposed[key] != nil
+}
+
+// HasAnyDeposed returns true if this resource instance has one or more
+// deposed objects.
+func (i *ResourceInstance) HasAnyDeposed() bool {
+	return i != nil && len(i.Deposed) > 0
+}
+
+// HasObjects returns true if this resource has any objects at all, whether
+// current or deposed.
+func (i *ResourceInstance) HasObjects() bool {
+	return i.Current != nil || len(i.Deposed) != 0
+}
+
+// deposeCurrentObject is part of the real implementation of
+// SyncState.DeposeResourceInstanceObject. The exported method uses a lock
+// to ensure that we can safely allocate an unused deposed key without
+// collision.
+func (i *ResourceInstance) deposeCurrentObject(forceKey DeposedKey) DeposedKey {
+	if !i.HasCurrent() {
+		return NotDeposed
+	}
+
+	key := forceKey
+	if key == NotDeposed {
+		key = i.findUnusedDeposedKey()
+	} else {
+		if _, exists := i.Deposed[key]; exists {
+			panic(fmt.Sprintf("forced key %s is already in use", forceKey))
+		}
+	}
+	i.Deposed[key] = i.Current
+	i.Current = nil
+	return key
+}
+
+// GetGeneration retrieves the object of the given generation from the
+// ResourceInstance, or returns nil if there is no such object.
+//
+// If the given generation is nil or invalid, this method will panic.
+func (i *ResourceInstance) GetGeneration(gen Generation) *ResourceInstanceObjectSrc {
+	if gen == CurrentGen {
+		return i.Current
+	}
+	if dk, ok := gen.(DeposedKey); ok {
+		return i.Deposed[dk]
+	}
+	if gen == nil {
+		panic("get with nil Generation")
+	}
+	// Should never fall out here, since the above covers all possible
+	// Generation values.
+	panic(fmt.Sprintf("get invalid Generation %#v", gen))
+}
+
+// FindUnusedDeposedKey generates a unique DeposedKey that is guaranteed not to
+// already be in use for this instance at the time of the call.
+//
+// Note that the validity of this result may change if new deposed keys are
+// allocated before it is used. To avoid this risk, instead use the
+// DeposeResourceInstanceObject method on the SyncState wrapper type, which
+// allocates a key and uses it atomically.
+func (i *ResourceInstance) FindUnusedDeposedKey() DeposedKey {
+	return i.findUnusedDeposedKey()
+}
+
+// findUnusedDeposedKey generates a unique DeposedKey that is guaranteed not to
+// already be in use for this instance.
+func (i *ResourceInstance) findUnusedDeposedKey() DeposedKey {
+	for {
+		key := NewDeposedKey()
+		if _, exists := i.Deposed[key]; !exists {
+			return key
+		}
+		// Spin until we find a unique one. This shouldn't take long, because
+		// we have a 32-bit keyspace and there's rarely more than one deposed
+		// instance.
+	}
+}
+
+// DeposedKey is a 8-character hex string used to uniquely identify deposed
+// instance objects in the state.
+type DeposedKey string
+
+// NotDeposed is a special invalid value of DeposedKey that is used to represent
+// the absense of a deposed key. It must not be used as an actual deposed key.
+const NotDeposed = DeposedKey("")
+
+var deposedKeyRand = rand.New(rand.NewSource(time.Now().UnixNano()))
+
+// NewDeposedKey generates a pseudo-random deposed key. Because of the short
+// length of these keys, uniqueness is not a natural consequence and so the
+// caller should test to see if the generated key is already in use and generate
+// another if so, until a unique key is found.
+func NewDeposedKey() DeposedKey {
+	v := deposedKeyRand.Uint32()
+	return DeposedKey(fmt.Sprintf("%08x", v))
+}
+
+func (k DeposedKey) String() string {
+	return string(k)
+}
+
+func (k DeposedKey) GoString() string {
+	ks := string(k)
+	switch {
+	case ks == "":
+		return "states.NotDeposed"
+	default:
+		return fmt.Sprintf("states.DeposedKey(%s)", ks)
+	}
+}
+
+// Generation is a helper method to convert a DeposedKey into a Generation.
+// If the reciever is anything other than NotDeposed then the result is
+// just the same value as a Generation. If the receiver is NotDeposed then
+// the result is CurrentGen.
+func (k DeposedKey) Generation() Generation {
+	if k == NotDeposed {
+		return CurrentGen
+	}
+	return k
+}
+
+// generation is an implementation of Generation.
+func (k DeposedKey) generation() {}
diff --git a/v1.5.7/internal/states/resource_test.go b/v1.5.7/internal/states/resource_test.go
new file mode 100644
index 0000000..f2dbd35
--- /dev/null
+++ b/v1.5.7/internal/states/resource_test.go
@@ -0,0 +1,59 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package states
+
+import (
+	"testing"
+)
+
+func TestResourceInstanceDeposeCurrentObject(t *testing.T) {
+	obj := &ResourceInstanceObjectSrc{
+		// Empty for the sake of this test, because we're just going to
+		// compare by pointer below anyway.
+	}
+
+	is := NewResourceInstance()
+	is.Current = obj
+	var dk DeposedKey
+
+	t.Run("first depose", func(t *testing.T) {
+		dk = is.deposeCurrentObject(NotDeposed) // dk is randomly-generated but should be eight characters long
+		t.Logf("deposedKey is %q", dk)
+
+		if got := is.Current; got != nil {
+			t.Errorf("current is %#v; want nil", got)
+		}
+		if got, want := is.Deposed[dk], obj; got != want {
+			t.Errorf("deposed object pointer is %#v; want %#v", got, want)
+		}
+		if got, want := len(is.Deposed), 1; got != want {
+			t.Errorf("wrong len(is.Deposed) %d; want %d", got, want)
+		}
+		if got, want := len(dk), 8; got != want {
+			t.Errorf("wrong len(deposedkey) %d; want %d", got, want)
+		}
+	})
+
+	t.Run("second depose", func(t *testing.T) {
+		notDK := is.deposeCurrentObject(NotDeposed)
+		if notDK != NotDeposed {
+			t.Errorf("got deposedKey %q; want NotDeposed", notDK)
+		}
+
+		// Make sure we really did abort early, and haven't corrupted the
+		// state somehow.
+		if got := is.Current; got != nil {
+			t.Errorf("current is %#v; want nil", got)
+		}
+		if got, want := is.Deposed[dk], obj; got != want {
+			t.Errorf("deposed object pointer is %#v; want %#v", got, want)
+		}
+		if got, want := len(is.Deposed), 1; got != want {
+			t.Errorf("wrong len(is.Deposed) %d; want %d", got, want)
+		}
+		if got, want := len(dk), 8; got != want {
+			t.Errorf("wrong len(deposedkey) %d; want %d", got, want)
+		}
+	})
+}
diff --git a/v1.5.7/internal/states/state.go b/v1.5.7/internal/states/state.go
new file mode 100644
index 0000000..8593e1c
--- /dev/null
+++ b/v1.5.7/internal/states/state.go
@@ -0,0 +1,637 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package states
+
+import (
+	"fmt"
+	"sort"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/getproviders"
+)
+
+// State is the top-level type of a Terraform state.
+//
+// A state should be mutated only via its accessor methods, to ensure that
+// invariants are preserved.
+//
+// Access to State and the nested values within it is not concurrency-safe,
+// so when accessing a State object concurrently it is the caller's
+// responsibility to ensure that only one write is in progress at a time
+// and that reads only occur when no write is in progress. The most common
+// way to achieve this is to wrap the State in a SyncState and use the
+// higher-level atomic operations supported by that type.
+type State struct {
+	// Modules contains the state for each module. The keys in this map are
+	// an implementation detail and must not be used by outside callers.
+	Modules map[string]*Module
+
+	// CheckResults contains a snapshot of the statuses of checks at the
+	// end of the most recent update to the state. Callers might compare
+	// checks between runs to see if e.g. a previously-failing check has
+	// been fixed since the last run, or similar.
+	//
+	// CheckResults can be nil to indicate that there are no check results
+	// from the previous run at all, which is subtly different than the
+	// previous run having affirmatively recorded that there are no checks
+	// to run. For example, if this object was created from a state snapshot
+	// created by a version of Terraform that didn't yet support checks
+	// then this field will be nil.
+	CheckResults *CheckResults
+}
+
+// NewState constructs a minimal empty state, containing an empty root module.
+func NewState() *State {
+	modules := map[string]*Module{}
+	modules[addrs.RootModuleInstance.String()] = NewModule(addrs.RootModuleInstance)
+	return &State{
+		Modules: modules,
+	}
+}
+
+// BuildState is a helper -- primarily intended for tests -- to build a state
+// using imperative code against the StateSync type while still acting as
+// an expression of type *State to assign into a containing struct.
+func BuildState(cb func(*SyncState)) *State {
+	s := NewState()
+	cb(s.SyncWrapper())
+	return s
+}
+
+// Empty returns true if there are no resources or populated output values
+// in the receiver. In other words, if this state could be safely replaced
+// with the return value of NewState and be functionally equivalent.
+func (s *State) Empty() bool {
+	if s == nil {
+		return true
+	}
+	for _, ms := range s.Modules {
+		if len(ms.Resources) != 0 {
+			return false
+		}
+		if len(ms.OutputValues) != 0 {
+			return false
+		}
+	}
+	return true
+}
+
+// Module returns the state for the module with the given address, or nil if
+// the requested module is not tracked in the state.
+func (s *State) Module(addr addrs.ModuleInstance) *Module {
+	if s == nil {
+		panic("State.Module on nil *State")
+	}
+	return s.Modules[addr.String()]
+}
+
+// ModuleInstances returns the set of Module states that matches the given path.
+func (s *State) ModuleInstances(addr addrs.Module) []*Module {
+	var ms []*Module
+	for _, m := range s.Modules {
+		if m.Addr.Module().Equal(addr) {
+			ms = append(ms, m)
+		}
+	}
+	return ms
+}
+
+// ModuleOutputs returns all outputs for the given module call under the
+// parentAddr instance.
+func (s *State) ModuleOutputs(parentAddr addrs.ModuleInstance, module addrs.ModuleCall) []*OutputValue {
+	var os []*OutputValue
+	for _, m := range s.Modules {
+		// can't get outputs from the root module
+		if m.Addr.IsRoot() {
+			continue
+		}
+
+		parent, call := m.Addr.Call()
+		// make sure this is a descendent in the correct path
+		if !parentAddr.Equal(parent) {
+			continue
+		}
+
+		// and check if this is the correct child
+		if call.Name != module.Name {
+			continue
+		}
+
+		for _, o := range m.OutputValues {
+			os = append(os, o)
+		}
+	}
+
+	return os
+}
+
+// RemoveModule removes the module with the given address from the state,
+// unless it is the root module. The root module cannot be deleted, and so
+// this method will panic if that is attempted.
+//
+// Removing a module implicitly discards all of the resources, outputs and
+// local values within it, and so this should usually be done only for empty
+// modules. For callers accessing the state through a SyncState wrapper, modules
+// are automatically pruned if they are empty after one of their contained
+// elements is removed.
+func (s *State) RemoveModule(addr addrs.ModuleInstance) {
+	if addr.IsRoot() {
+		panic("attempted to remove root module")
+	}
+
+	delete(s.Modules, addr.String())
+}
+
+// RootModule is a convenient alias for Module(addrs.RootModuleInstance).
+func (s *State) RootModule() *Module {
+	if s == nil {
+		panic("RootModule called on nil State")
+	}
+	return s.Modules[addrs.RootModuleInstance.String()]
+}
+
+// EnsureModule returns the state for the module with the given address,
+// creating and adding a new one if necessary.
+//
+// Since this might modify the state to add a new instance, it is considered
+// to be a write operation.
+func (s *State) EnsureModule(addr addrs.ModuleInstance) *Module {
+	ms := s.Module(addr)
+	if ms == nil {
+		ms = NewModule(addr)
+		s.Modules[addr.String()] = ms
+	}
+	return ms
+}
+
+// HasManagedResourceInstanceObjects returns true if there is at least one
+// resource instance object (current or deposed) associated with a managed
+// resource in the receiving state.
+//
+// A true result would suggest that just discarding this state without first
+// destroying these objects could leave "dangling" objects in remote systems,
+// no longer tracked by any Terraform state.
+func (s *State) HasManagedResourceInstanceObjects() bool {
+	if s == nil {
+		return false
+	}
+	for _, ms := range s.Modules {
+		for _, rs := range ms.Resources {
+			if rs.Addr.Resource.Mode != addrs.ManagedResourceMode {
+				continue
+			}
+			for _, is := range rs.Instances {
+				if is.Current != nil || len(is.Deposed) != 0 {
+					return true
+				}
+			}
+		}
+	}
+	return false
+}
+
+// Resource returns the state for the resource with the given address, or nil
+// if no such resource is tracked in the state.
+func (s *State) Resource(addr addrs.AbsResource) *Resource {
+	ms := s.Module(addr.Module)
+	if ms == nil {
+		return nil
+	}
+	return ms.Resource(addr.Resource)
+}
+
+// Resources returns the set of resources that match the given configuration path.
+func (s *State) Resources(addr addrs.ConfigResource) []*Resource {
+	var ret []*Resource
+	for _, m := range s.ModuleInstances(addr.Module) {
+		r := m.Resource(addr.Resource)
+		if r != nil {
+			ret = append(ret, r)
+		}
+	}
+	return ret
+}
+
+// AllManagedResourceInstanceObjectAddrs returns a set of addresses for all of
+// the leaf resource instance objects associated with managed resources that
+// are tracked in this state.
+//
+// This result is the set of objects that would be effectively "forgotten"
+// (like "terraform state rm") if this state were totally discarded, such as
+// by deleting a workspace. This function is intended only for reporting
+// context in error messages, such as when we reject deleting a "non-empty"
+// workspace as detected by s.HasManagedResourceInstanceObjects.
+//
+// The ordering of the result is meaningless but consistent. DeposedKey will
+// be NotDeposed (the zero value of DeposedKey) for any "current" objects.
+// This method is guaranteed to return at least one item if
+// s.HasManagedResourceInstanceObjects returns true for the same state, and
+// to return a zero-length slice if it returns false.
+func (s *State) AllResourceInstanceObjectAddrs() []struct {
+	Instance   addrs.AbsResourceInstance
+	DeposedKey DeposedKey
+} {
+	if s == nil {
+		return nil
+	}
+
+	// We use an unnamed return type here just because we currently have no
+	// general need to return pairs of instance address and deposed key aside
+	// from this method, and this method itself is only of marginal value
+	// when producing some error messages.
+	//
+	// If that need ends up arising more in future then it might make sense to
+	// name this as addrs.AbsResourceInstanceObject, although that would require
+	// moving DeposedKey into the addrs package too.
+	type ResourceInstanceObject = struct {
+		Instance   addrs.AbsResourceInstance
+		DeposedKey DeposedKey
+	}
+	var ret []ResourceInstanceObject
+
+	for _, ms := range s.Modules {
+		for _, rs := range ms.Resources {
+			if rs.Addr.Resource.Mode != addrs.ManagedResourceMode {
+				continue
+			}
+
+			for instKey, is := range rs.Instances {
+				instAddr := rs.Addr.Instance(instKey)
+				if is.Current != nil {
+					ret = append(ret, ResourceInstanceObject{instAddr, NotDeposed})
+				}
+				for deposedKey := range is.Deposed {
+					ret = append(ret, ResourceInstanceObject{instAddr, deposedKey})
+				}
+			}
+		}
+	}
+
+	sort.SliceStable(ret, func(i, j int) bool {
+		objI, objJ := ret[i], ret[j]
+		switch {
+		case !objI.Instance.Equal(objJ.Instance):
+			return objI.Instance.Less(objJ.Instance)
+		default:
+			return objI.DeposedKey < objJ.DeposedKey
+		}
+	})
+
+	return ret
+}
+
+// ResourceInstance returns the state for the resource instance with the given
+// address, or nil if no such resource is tracked in the state.
+func (s *State) ResourceInstance(addr addrs.AbsResourceInstance) *ResourceInstance {
+	if s == nil {
+		panic("State.ResourceInstance on nil *State")
+	}
+	ms := s.Module(addr.Module)
+	if ms == nil {
+		return nil
+	}
+	return ms.ResourceInstance(addr.Resource)
+}
+
+// OutputValue returns the state for the output value with the given address,
+// or nil if no such output value is tracked in the state.
+func (s *State) OutputValue(addr addrs.AbsOutputValue) *OutputValue {
+	ms := s.Module(addr.Module)
+	if ms == nil {
+		return nil
+	}
+	return ms.OutputValues[addr.OutputValue.Name]
+}
+
+// LocalValue returns the value of the named local value with the given address,
+// or cty.NilVal if no such value is tracked in the state.
+func (s *State) LocalValue(addr addrs.AbsLocalValue) cty.Value {
+	ms := s.Module(addr.Module)
+	if ms == nil {
+		return cty.NilVal
+	}
+	return ms.LocalValues[addr.LocalValue.Name]
+}
+
+// ProviderAddrs returns a list of all of the provider configuration addresses
+// referenced throughout the receiving state.
+//
+// The result is de-duplicated so that each distinct address appears only once.
+func (s *State) ProviderAddrs() []addrs.AbsProviderConfig {
+	if s == nil {
+		return nil
+	}
+
+	m := map[string]addrs.AbsProviderConfig{}
+	for _, ms := range s.Modules {
+		for _, rc := range ms.Resources {
+			m[rc.ProviderConfig.String()] = rc.ProviderConfig
+		}
+	}
+	if len(m) == 0 {
+		return nil
+	}
+
+	// This is mainly just so we'll get stable results for testing purposes.
+	keys := make([]string, 0, len(m))
+	for k := range m {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+
+	ret := make([]addrs.AbsProviderConfig, len(keys))
+	for i, key := range keys {
+		ret[i] = m[key]
+	}
+
+	return ret
+}
+
+// ProviderRequirements returns a description of all of the providers that
+// are required to work with the receiving state.
+//
+// Because the state does not track specific version information for providers,
+// the requirements returned by this method will always be unconstrained.
+// The result should usually be merged with a Requirements derived from the
+// current configuration in order to apply some constraints.
+func (s *State) ProviderRequirements() getproviders.Requirements {
+	configAddrs := s.ProviderAddrs()
+	ret := make(getproviders.Requirements, len(configAddrs))
+	for _, configAddr := range configAddrs {
+		ret[configAddr.Provider] = nil // unconstrained dependency
+	}
+	return ret
+}
+
+// PruneResourceHusks is a specialized method that will remove any Resource
+// objects that do not contain any instances, even if they have an EachMode.
+//
+// This should generally be used only after a "terraform destroy" operation,
+// to finalize the cleanup of the state. It is not correct to use this after
+// other operations because if a resource has "count = 0" or "for_each" over
+// an empty collection then we want to retain it in the state so that references
+// to it, particularly in "strange" contexts like "terraform console", can be
+// properly resolved.
+//
+// This method MUST NOT be called concurrently with other readers and writers
+// of the receiving state.
+func (s *State) PruneResourceHusks() {
+	for _, m := range s.Modules {
+		m.PruneResourceHusks()
+		if len(m.Resources) == 0 && !m.Addr.IsRoot() {
+			s.RemoveModule(m.Addr)
+		}
+	}
+}
+
+// SyncWrapper returns a SyncState object wrapping the receiver.
+func (s *State) SyncWrapper() *SyncState {
+	return &SyncState{
+		state: s,
+	}
+}
+
+// MoveAbsResource moves the given src AbsResource's current state to the new
+// dst address. This will panic if the src AbsResource does not exist in state,
+// or if there is already a resource at the dst address. It is the caller's
+// responsibility to verify the validity of the move (for example, that the src
+// and dst are compatible types).
+func (s *State) MoveAbsResource(src, dst addrs.AbsResource) {
+	// verify that the src address exists and the dst address does not
+	rs := s.Resource(src)
+	if rs == nil {
+		panic(fmt.Sprintf("no state for src address %s", src.String()))
+	}
+
+	ds := s.Resource(dst)
+	if ds != nil {
+		panic(fmt.Sprintf("dst resource %s already exists", dst.String()))
+	}
+
+	ms := s.Module(src.Module)
+	ms.RemoveResource(src.Resource)
+
+	// Remove the module if it is empty (and not root) after removing the
+	// resource.
+	if !ms.Addr.IsRoot() && ms.empty() {
+		s.RemoveModule(src.Module)
+	}
+
+	// Update the address before adding it to the state
+	rs.Addr = dst
+	s.EnsureModule(dst.Module).Resources[dst.Resource.String()] = rs
+}
+
+// MaybeMoveAbsResource moves the given src AbsResource's current state to the
+// new dst address. This function will succeed if both the src address does not
+// exist in state and the dst address does; the return value indicates whether
+// or not the move occurred. This function will panic if either the src does not
+// exist or the dst does exist (but not both).
+func (s *State) MaybeMoveAbsResource(src, dst addrs.AbsResource) bool {
+	// Get the source and destinatation addresses from state.
+	rs := s.Resource(src)
+	ds := s.Resource(dst)
+
+	// Normal case: the src exists in state, dst does not
+	if rs != nil && ds == nil {
+		s.MoveAbsResource(src, dst)
+		return true
+	}
+
+	if rs == nil && ds != nil {
+		// The source is not in state, the destination is. This is not
+		// guaranteed to be idempotent since we aren't tracking exact moves, but
+		// it's useful information for the caller.
+		return false
+	} else {
+		panic("invalid move")
+	}
+}
+
+// MoveAbsResourceInstance moves the given src AbsResourceInstance's current state to
+// the new dst address. This will panic if the src AbsResourceInstance does not
+// exist in state, or if there is already a resource at the dst address. It is
+// the caller's responsibility to verify the validity of the move (for example,
+// that the src and dst are compatible types).
+func (s *State) MoveAbsResourceInstance(src, dst addrs.AbsResourceInstance) {
+	srcInstanceState := s.ResourceInstance(src)
+	if srcInstanceState == nil {
+		panic(fmt.Sprintf("no state for src address %s", src.String()))
+	}
+
+	dstInstanceState := s.ResourceInstance(dst)
+	if dstInstanceState != nil {
+		panic(fmt.Sprintf("dst resource %s already exists", dst.String()))
+	}
+
+	srcResourceState := s.Resource(src.ContainingResource())
+	srcProviderAddr := srcResourceState.ProviderConfig
+	dstResourceAddr := dst.ContainingResource()
+
+	// Remove the source resource instance from the module's state, and then the
+	// module if empty.
+	ms := s.Module(src.Module)
+	ms.ForgetResourceInstanceAll(src.Resource)
+	if !ms.Addr.IsRoot() && ms.empty() {
+		s.RemoveModule(src.Module)
+	}
+
+	dstModule := s.EnsureModule(dst.Module)
+
+	// See if there is already a resource we can add this instance to.
+	dstResourceState := s.Resource(dstResourceAddr)
+	if dstResourceState == nil {
+		// If we're moving to an address without an index then that
+		// suggests the user's intent is to establish both the
+		// resource and the instance at the same time (since the
+		// address covers both). If there's an index in the
+		// target then allow creating the new instance here.
+		dstModule.SetResourceProvider(
+			dstResourceAddr.Resource,
+			srcProviderAddr, // in this case, we bring the provider along as if we were moving the whole resource
+		)
+		dstResourceState = dstModule.Resource(dstResourceAddr.Resource)
+	}
+
+	dstResourceState.Instances[dst.Resource.Key] = srcInstanceState
+}
+
+// MaybeMoveAbsResourceInstance moves the given src AbsResourceInstance's
+// current state to the new dst address. This function will succeed if both the
+// src address does not exist in state and the dst address does; the return
+// value indicates whether or not the move occured. This function will panic if
+// either the src does not exist or the dst does exist (but not both).
+func (s *State) MaybeMoveAbsResourceInstance(src, dst addrs.AbsResourceInstance) bool {
+	// get the src and dst resource instances from state
+	rs := s.ResourceInstance(src)
+	ds := s.ResourceInstance(dst)
+
+	// Normal case: the src exists in state, dst does not
+	if rs != nil && ds == nil {
+		s.MoveAbsResourceInstance(src, dst)
+		return true
+	}
+
+	if rs == nil && ds != nil {
+		// The source is not in state, the destination is. This is not
+		// guaranteed to be idempotent since we aren't tracking exact moves, but
+		// it's useful information.
+		return false
+	} else {
+		panic("invalid move")
+	}
+}
+
+// MoveModuleInstance moves the given src ModuleInstance's current state to the
+// new dst address. This will panic if the src ModuleInstance does not
+// exist in state, or if there is already a resource at the dst address. It is
+// the caller's responsibility to verify the validity of the move.
+func (s *State) MoveModuleInstance(src, dst addrs.ModuleInstance) {
+	if src.IsRoot() || dst.IsRoot() {
+		panic("cannot move to or from root module")
+	}
+
+	srcMod := s.Module(src)
+	if srcMod == nil {
+		panic(fmt.Sprintf("no state for src module %s", src.String()))
+	}
+
+	dstMod := s.Module(dst)
+	if dstMod != nil {
+		panic(fmt.Sprintf("dst module %s already exists in state", dst.String()))
+	}
+
+	s.RemoveModule(src)
+
+	srcMod.Addr = dst
+	s.EnsureModule(dst)
+	s.Modules[dst.String()] = srcMod
+
+	// Update any Resource's addresses.
+	if srcMod.Resources != nil {
+		for _, r := range srcMod.Resources {
+			r.Addr.Module = dst
+		}
+	}
+
+	// Update any OutputValues's addresses.
+	if srcMod.OutputValues != nil {
+		for _, ov := range srcMod.OutputValues {
+			ov.Addr.Module = dst
+		}
+	}
+}
+
+// MaybeMoveModuleInstance moves the given src ModuleInstance's current state to
+// the new dst address. This function will succeed if both the src address does
+// not exist in state and the dst address does; the return value indicates
+// whether or not the move occured. This function will panic if either the src
+// does not exist or the dst does exist (but not both).
+func (s *State) MaybeMoveModuleInstance(src, dst addrs.ModuleInstance) bool {
+	if src.IsRoot() || dst.IsRoot() {
+		panic("cannot move to or from root module")
+	}
+
+	srcMod := s.Module(src)
+	dstMod := s.Module(dst)
+
+	// Normal case: the src exists in state, dst does not
+	if srcMod != nil && dstMod == nil {
+		s.MoveModuleInstance(src, dst)
+		return true
+	}
+
+	if srcMod == nil || src.IsRoot() && dstMod != nil {
+		// The source is not in state, the destination is. This is not
+		// guaranteed to be idempotent since we aren't tracking exact moves, but
+		// it's useful information.
+		return false
+	} else {
+		panic("invalid move")
+	}
+}
+
+// MoveModule takes a source and destination addrs.Module address, and moves all
+// state Modules which are contained by the src address to the new address.
+func (s *State) MoveModule(src, dst addrs.AbsModuleCall) {
+	if src.Module.IsRoot() || dst.Module.IsRoot() {
+		panic("cannot move to or from root module")
+	}
+
+	// Modules only exist as ModuleInstances in state, so we need to check each
+	// state Module and see if it is contained by the src address to get a full
+	// list of modules to move.
+	var srcMIs []*Module
+	for _, module := range s.Modules {
+		if !module.Addr.IsRoot() {
+			if src.Module.TargetContains(module.Addr) {
+				srcMIs = append(srcMIs, module)
+			}
+		}
+	}
+
+	if len(srcMIs) == 0 {
+		panic(fmt.Sprintf("no matching module instances found for src module %s", src.String()))
+	}
+
+	for _, ms := range srcMIs {
+		newInst := make(addrs.ModuleInstance, len(ms.Addr))
+		copy(newInst, ms.Addr)
+		if ms.Addr.IsDeclaredByCall(src) {
+			// Easy case: we just need to update the last step with the new name
+			newInst[len(newInst)-1].Name = dst.Call.Name
+		} else {
+			// Trickier: this Module is a submodule. we need to find and update
+			// only that appropriate step
+			for s := range newInst {
+				if newInst[s].Name == src.Call.Name {
+					newInst[s].Name = dst.Call.Name
+				}
+			}
+		}
+		s.MoveModuleInstance(ms.Addr, newInst)
+	}
+}
diff --git a/v1.5.7/internal/states/state_deepcopy.go b/v1.5.7/internal/states/state_deepcopy.go
new file mode 100644
index 0000000..ec3131a
--- /dev/null
+++ b/v1.5.7/internal/states/state_deepcopy.go
@@ -0,0 +1,237 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package states
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Taking deep copies of states is an important operation because state is
+// otherwise a mutable data structure that is challenging to share across
+// many separate callers. It is important that the DeepCopy implementations
+// in this file comprehensively copy all parts of the state data structure
+// that could be mutated via pointers.
+
+// DeepCopy returns a new state that contains equivalent data to the reciever
+// but shares no backing memory in common.
+//
+// As with all methods on State, this method is not safe to use concurrently
+// with writing to any portion of the recieving data structure. It is the
+// caller's responsibility to ensure mutual exclusion for the duration of the
+// operation, but may then freely modify the receiver and the returned copy
+// independently once this method returns.
+func (s *State) DeepCopy() *State {
+	if s == nil {
+		return nil
+	}
+
+	modules := make(map[string]*Module, len(s.Modules))
+	for k, m := range s.Modules {
+		modules[k] = m.DeepCopy()
+	}
+	return &State{
+		Modules:      modules,
+		CheckResults: s.CheckResults.DeepCopy(),
+	}
+}
+
+// DeepCopy returns a new module state that contains equivalent data to the
+// receiver but shares no backing memory in common.
+//
+// As with all methods on Module, this method is not safe to use concurrently
+// with writing to any portion of the recieving data structure. It is the
+// caller's responsibility to ensure mutual exclusion for the duration of the
+// operation, but may then freely modify the receiver and the returned copy
+// independently once this method returns.
+func (ms *Module) DeepCopy() *Module {
+	if ms == nil {
+		return nil
+	}
+
+	resources := make(map[string]*Resource, len(ms.Resources))
+	for k, r := range ms.Resources {
+		resources[k] = r.DeepCopy()
+	}
+	outputValues := make(map[string]*OutputValue, len(ms.OutputValues))
+	for k, v := range ms.OutputValues {
+		outputValues[k] = v.DeepCopy()
+	}
+	localValues := make(map[string]cty.Value, len(ms.LocalValues))
+	for k, v := range ms.LocalValues {
+		// cty.Value is immutable, so we don't need to copy these.
+		localValues[k] = v
+	}
+
+	return &Module{
+		Addr:         ms.Addr, // technically mutable, but immutable by convention
+		Resources:    resources,
+		OutputValues: outputValues,
+		LocalValues:  localValues,
+	}
+}
+
+// DeepCopy returns a new resource state that contains equivalent data to the
+// receiver but shares no backing memory in common.
+//
+// As with all methods on Resource, this method is not safe to use concurrently
+// with writing to any portion of the recieving data structure. It is the
+// caller's responsibility to ensure mutual exclusion for the duration of the
+// operation, but may then freely modify the receiver and the returned copy
+// independently once this method returns.
+func (rs *Resource) DeepCopy() *Resource {
+	if rs == nil {
+		return nil
+	}
+
+	instances := make(map[addrs.InstanceKey]*ResourceInstance, len(rs.Instances))
+	for k, i := range rs.Instances {
+		instances[k] = i.DeepCopy()
+	}
+
+	return &Resource{
+		Addr:           rs.Addr,
+		Instances:      instances,
+		ProviderConfig: rs.ProviderConfig, // technically mutable, but immutable by convention
+	}
+}
+
+// DeepCopy returns a new resource instance state that contains equivalent data
+// to the receiver but shares no backing memory in common.
+//
+// As with all methods on ResourceInstance, this method is not safe to use
+// concurrently with writing to any portion of the recieving data structure. It
+// is the caller's responsibility to ensure mutual exclusion for the duration
+// of the operation, but may then freely modify the receiver and the returned
+// copy independently once this method returns.
+func (i *ResourceInstance) DeepCopy() *ResourceInstance {
+	if i == nil {
+		return nil
+	}
+
+	deposed := make(map[DeposedKey]*ResourceInstanceObjectSrc, len(i.Deposed))
+	for k, obj := range i.Deposed {
+		deposed[k] = obj.DeepCopy()
+	}
+
+	return &ResourceInstance{
+		Current: i.Current.DeepCopy(),
+		Deposed: deposed,
+	}
+}
+
+// DeepCopy returns a new resource instance object that contains equivalent data
+// to the receiver but shares no backing memory in common.
+//
+// As with all methods on ResourceInstanceObjectSrc, this method is not safe to
+// use concurrently with writing to any portion of the recieving data structure.
+// It is the caller's responsibility to ensure mutual exclusion for the duration
+// of the operation, but may then freely modify the receiver and the returned
+// copy independently once this method returns.
+func (os *ResourceInstanceObjectSrc) DeepCopy() *ResourceInstanceObjectSrc {
+	if os == nil {
+		return nil
+	}
+
+	var attrsFlat map[string]string
+	if os.AttrsFlat != nil {
+		attrsFlat = make(map[string]string, len(os.AttrsFlat))
+		for k, v := range os.AttrsFlat {
+			attrsFlat[k] = v
+		}
+	}
+
+	var attrsJSON []byte
+	if os.AttrsJSON != nil {
+		attrsJSON = make([]byte, len(os.AttrsJSON))
+		copy(attrsJSON, os.AttrsJSON)
+	}
+
+	var attrPaths []cty.PathValueMarks
+	if os.AttrSensitivePaths != nil {
+		attrPaths = make([]cty.PathValueMarks, len(os.AttrSensitivePaths))
+		copy(attrPaths, os.AttrSensitivePaths)
+	}
+
+	var private []byte
+	if os.Private != nil {
+		private = make([]byte, len(os.Private))
+		copy(private, os.Private)
+	}
+
+	// Some addrs.Referencable implementations are technically mutable, but
+	// we treat them as immutable by convention and so we don't deep-copy here.
+	var dependencies []addrs.ConfigResource
+	if os.Dependencies != nil {
+		dependencies = make([]addrs.ConfigResource, len(os.Dependencies))
+		copy(dependencies, os.Dependencies)
+	}
+
+	return &ResourceInstanceObjectSrc{
+		Status:              os.Status,
+		SchemaVersion:       os.SchemaVersion,
+		Private:             private,
+		AttrsFlat:           attrsFlat,
+		AttrsJSON:           attrsJSON,
+		AttrSensitivePaths:  attrPaths,
+		Dependencies:        dependencies,
+		CreateBeforeDestroy: os.CreateBeforeDestroy,
+	}
+}
+
+// DeepCopy returns a new resource instance object that contains equivalent data
+// to the receiver but shares no backing memory in common.
+//
+// As with all methods on ResourceInstanceObject, this method is not safe to use
+// concurrently with writing to any portion of the recieving data structure. It
+// is the caller's responsibility to ensure mutual exclusion for the duration
+// of the operation, but may then freely modify the receiver and the returned
+// copy independently once this method returns.
+func (o *ResourceInstanceObject) DeepCopy() *ResourceInstanceObject {
+	if o == nil {
+		return nil
+	}
+
+	var private []byte
+	if o.Private != nil {
+		private = make([]byte, len(o.Private))
+		copy(private, o.Private)
+	}
+
+	// Some addrs.Referenceable implementations are technically mutable, but
+	// we treat them as immutable by convention and so we don't deep-copy here.
+	var dependencies []addrs.ConfigResource
+	if o.Dependencies != nil {
+		dependencies = make([]addrs.ConfigResource, len(o.Dependencies))
+		copy(dependencies, o.Dependencies)
+	}
+
+	return &ResourceInstanceObject{
+		Value:               o.Value,
+		Status:              o.Status,
+		Private:             private,
+		Dependencies:        dependencies,
+		CreateBeforeDestroy: o.CreateBeforeDestroy,
+	}
+}
+
+// DeepCopy returns a new output value state that contains equivalent data
+// to the receiver but shares no backing memory in common.
+//
+// As with all methods on OutputValue, this method is not safe to use
+// concurrently with writing to any portion of the recieving data structure. It
+// is the caller's responsibility to ensure mutual exclusion for the duration
+// of the operation, but may then freely modify the receiver and the returned
+// copy independently once this method returns.
+func (os *OutputValue) DeepCopy() *OutputValue {
+	if os == nil {
+		return nil
+	}
+
+	return &OutputValue{
+		Addr:      os.Addr,
+		Value:     os.Value,
+		Sensitive: os.Sensitive,
+	}
+}
diff --git a/v1.5.7/internal/states/state_equal.go b/v1.5.7/internal/states/state_equal.go
new file mode 100644
index 0000000..f31d47b
--- /dev/null
+++ b/v1.5.7/internal/states/state_equal.go
@@ -0,0 +1,71 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package states
+
+import (
+	"reflect"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// Equal returns true if the receiver is functionally equivalent to other,
+// including any ephemeral portions of the state that would not be included
+// if the state were saved to files.
+//
+// To test only the persistent portions of two states for equality, instead
+// use statefile.StatesMarshalEqual.
+func (s *State) Equal(other *State) bool {
+	// For the moment this is sufficient, but we may need to do something
+	// more elaborate in future if we have any portions of state that require
+	// more sophisticated comparisons.
+	return reflect.DeepEqual(s, other)
+}
+
+// ManagedResourcesEqual returns true if all of the managed resources tracked
+// in the reciever are functionally equivalent to the same tracked in the
+// other given state.
+//
+// This is a more constrained version of Equal that disregards other
+// differences, including but not limited to changes to data resources and
+// changes to output values.
+func (s *State) ManagedResourcesEqual(other *State) bool {
+	// First, some accommodations for situations where one of the objects is
+	// nil, for robustness since we sometimes use a nil state to represent
+	// a prior state being entirely absent.
+	if s == nil && other == nil {
+		return true
+	}
+	if s == nil {
+		return !other.HasManagedResourceInstanceObjects()
+	}
+	if other == nil {
+		return !s.HasManagedResourceInstanceObjects()
+	}
+
+	// If we get here then both states are non-nil.
+
+	// sameManagedResources tests that its second argument has all the
+	// resources that the first one does, so we'll call it twice with the
+	// arguments inverted to ensure that we'll also catch situations where
+	// the second has resources that the first does not.
+	return sameManagedResources(s, other) && sameManagedResources(other, s)
+}
+
+func sameManagedResources(s1, s2 *State) bool {
+	for _, ms := range s1.Modules {
+		for _, rs := range ms.Resources {
+			addr := rs.Addr
+			if addr.Resource.Mode != addrs.ManagedResourceMode {
+				continue
+			}
+			otherRS := s2.Resource(addr)
+			if !reflect.DeepEqual(rs, otherRS) {
+				return false
+			}
+		}
+	}
+
+	return true
+
+}
diff --git a/v1.5.7/internal/states/state_string.go b/v1.5.7/internal/states/state_string.go
new file mode 100644
index 0000000..2e34834
--- /dev/null
+++ b/v1.5.7/internal/states/state_string.go
@@ -0,0 +1,277 @@
+package states
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"sort"
+	"strings"
+
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+)
+
+// String returns a rather-odd string representation of the entire state.
+//
+// This is intended to match the behavior of the older terraform.State.String
+// method that is used in lots of existing tests. It should not be used in
+// new tests: instead, use "cmp" to directly compare the state data structures
+// and print out a diff if they do not match.
+//
+// This method should never be used in non-test code, whether directly by call
+// or indirectly via a %s or %q verb in package fmt.
+func (s *State) String() string {
+	if s == nil {
+		return "<nil>"
+	}
+
+	// sort the modules by name for consistent output
+	modules := make([]string, 0, len(s.Modules))
+	for m := range s.Modules {
+		modules = append(modules, m)
+	}
+	sort.Strings(modules)
+
+	var buf bytes.Buffer
+	for _, name := range modules {
+		m := s.Modules[name]
+		mStr := m.testString()
+
+		// If we're the root module, we just write the output directly.
+		if m.Addr.IsRoot() {
+			buf.WriteString(mStr + "\n")
+			continue
+		}
+
+		// We need to build out a string that resembles the not-quite-standard
+		// format that terraform.State.String used to use, where there's a
+		// "module." prefix but then just a chain of all of the module names
+		// without any further "module." portions.
+		buf.WriteString("module")
+		for _, step := range m.Addr {
+			buf.WriteByte('.')
+			buf.WriteString(step.Name)
+			if step.InstanceKey != addrs.NoKey {
+				buf.WriteString(step.InstanceKey.String())
+			}
+		}
+		buf.WriteString(":\n")
+
+		s := bufio.NewScanner(strings.NewReader(mStr))
+		for s.Scan() {
+			text := s.Text()
+			if text != "" {
+				text = "  " + text
+			}
+
+			buf.WriteString(fmt.Sprintf("%s\n", text))
+		}
+	}
+
+	return strings.TrimSpace(buf.String())
+}
+
+// testString is used to produce part of the output of State.String. It should
+// never be used directly.
+func (ms *Module) testString() string {
+	var buf bytes.Buffer
+
+	if len(ms.Resources) == 0 {
+		buf.WriteString("<no state>")
+	}
+
+	// We use AbsResourceInstance here, even though everything belongs to
+	// the same module, just because we have a sorting behavior defined
+	// for those but not for just ResourceInstance.
+	addrsOrder := make([]addrs.AbsResourceInstance, 0, len(ms.Resources))
+	for _, rs := range ms.Resources {
+		for ik := range rs.Instances {
+			addrsOrder = append(addrsOrder, rs.Addr.Instance(ik))
+		}
+	}
+
+	sort.Slice(addrsOrder, func(i, j int) bool {
+		return addrsOrder[i].Less(addrsOrder[j])
+	})
+
+	for _, fakeAbsAddr := range addrsOrder {
+		addr := fakeAbsAddr.Resource
+		rs := ms.Resource(addr.ContainingResource())
+		is := ms.ResourceInstance(addr)
+
+		// Here we need to fake up a legacy-style address as the old state
+		// types would've used, since that's what our tests against those
+		// old types expect. The significant difference is that instancekey
+		// is dot-separated rather than using index brackets.
+		k := addr.ContainingResource().String()
+		if addr.Key != addrs.NoKey {
+			switch tk := addr.Key.(type) {
+			case addrs.IntKey:
+				k = fmt.Sprintf("%s.%d", k, tk)
+			default:
+				// No other key types existed for the legacy types, so we
+				// can do whatever we want here. We'll just use our standard
+				// syntax for these.
+				k = k + tk.String()
+			}
+		}
+
+		id := LegacyInstanceObjectID(is.Current)
+
+		taintStr := ""
+		if is.Current != nil && is.Current.Status == ObjectTainted {
+			taintStr = " (tainted)"
+		}
+
+		deposedStr := ""
+		if len(is.Deposed) > 0 {
+			deposedStr = fmt.Sprintf(" (%d deposed)", len(is.Deposed))
+		}
+
+		buf.WriteString(fmt.Sprintf("%s:%s%s\n", k, taintStr, deposedStr))
+		buf.WriteString(fmt.Sprintf("  ID = %s\n", id))
+		buf.WriteString(fmt.Sprintf("  provider = %s\n", rs.ProviderConfig.String()))
+
+		// Attributes were a flatmap before, but are not anymore. To preserve
+		// our old output as closely as possible we need to do a conversion
+		// to flatmap. Normally we'd want to do this with schema for
+		// accuracy, but for our purposes here it only needs to be approximate.
+		// This should produce an identical result for most cases, though
+		// in particular will differ in a few cases:
+		//  - The keys used for elements in a set will be different
+		//  - Values for attributes of type cty.DynamicPseudoType will be
+		//    misinterpreted (but these weren't possible in old world anyway)
+		var attributes map[string]string
+		if obj := is.Current; obj != nil {
+			switch {
+			case obj.AttrsFlat != nil:
+				// Easy (but increasingly unlikely) case: the state hasn't
+				// actually been upgraded to the new form yet.
+				attributes = obj.AttrsFlat
+			case obj.AttrsJSON != nil:
+				ty, err := ctyjson.ImpliedType(obj.AttrsJSON)
+				if err == nil {
+					val, err := ctyjson.Unmarshal(obj.AttrsJSON, ty)
+					if err == nil {
+						attributes = hcl2shim.FlatmapValueFromHCL2(val)
+					}
+				}
+			}
+		}
+		attrKeys := make([]string, 0, len(attributes))
+		for ak, val := range attributes {
+			if ak == "id" {
+				continue
+			}
+
+			// don't show empty containers in the output
+			if val == "0" && (strings.HasSuffix(ak, ".#") || strings.HasSuffix(ak, ".%")) {
+				continue
+			}
+
+			attrKeys = append(attrKeys, ak)
+		}
+
+		sort.Strings(attrKeys)
+
+		for _, ak := range attrKeys {
+			av := attributes[ak]
+			buf.WriteString(fmt.Sprintf("  %s = %s\n", ak, av))
+		}
+
+		// CAUTION: Since deposed keys are now random strings instead of
+		// incrementing integers, this result will not be deterministic
+		// if there is more than one deposed object.
+		i := 1
+		for _, t := range is.Deposed {
+			id := LegacyInstanceObjectID(t)
+			taintStr := ""
+			if t.Status == ObjectTainted {
+				taintStr = " (tainted)"
+			}
+			buf.WriteString(fmt.Sprintf("  Deposed ID %d = %s%s\n", i, id, taintStr))
+			i++
+		}
+
+		if obj := is.Current; obj != nil && len(obj.Dependencies) > 0 {
+			buf.WriteString("\n  Dependencies:\n")
+			for _, dep := range obj.Dependencies {
+				buf.WriteString(fmt.Sprintf("    %s\n", dep.String()))
+			}
+		}
+	}
+
+	if len(ms.OutputValues) > 0 {
+		buf.WriteString("\nOutputs:\n\n")
+
+		ks := make([]string, 0, len(ms.OutputValues))
+		for k := range ms.OutputValues {
+			ks = append(ks, k)
+		}
+		sort.Strings(ks)
+
+		for _, k := range ks {
+			v := ms.OutputValues[k]
+			lv := hcl2shim.ConfigValueFromHCL2(v.Value)
+			switch vTyped := lv.(type) {
+			case string:
+				buf.WriteString(fmt.Sprintf("%s = %s\n", k, vTyped))
+			case []interface{}:
+				buf.WriteString(fmt.Sprintf("%s = %s\n", k, vTyped))
+			case map[string]interface{}:
+				var mapKeys []string
+				for key := range vTyped {
+					mapKeys = append(mapKeys, key)
+				}
+				sort.Strings(mapKeys)
+
+				var mapBuf bytes.Buffer
+				mapBuf.WriteString("{")
+				for _, key := range mapKeys {
+					mapBuf.WriteString(fmt.Sprintf("%s:%s ", key, vTyped[key]))
+				}
+				mapBuf.WriteString("}")
+
+				buf.WriteString(fmt.Sprintf("%s = %s\n", k, mapBuf.String()))
+			default:
+				buf.WriteString(fmt.Sprintf("%s = %#v\n", k, lv))
+			}
+		}
+	}
+
+	return buf.String()
+}
+
+// LegacyInstanceObjectID is a helper for extracting an object id value from
+// an instance object in a way that approximates how we used to do this
+// for the old state types. ID is no longer first-class, so this is preserved
+// only for compatibility with old tests that include the id as part of their
+// expected value.
+func LegacyInstanceObjectID(obj *ResourceInstanceObjectSrc) string {
+	if obj == nil {
+		return "<not created>"
+	}
+
+	if obj.AttrsJSON != nil {
+		type WithID struct {
+			ID string `json:"id"`
+		}
+		var withID WithID
+		err := json.Unmarshal(obj.AttrsJSON, &withID)
+		if err == nil {
+			return withID.ID
+		}
+	} else if obj.AttrsFlat != nil {
+		if flatID, exists := obj.AttrsFlat["id"]; exists {
+			return flatID
+		}
+	}
+
+	// For resource types created after we removed id as special there may
+	// not actually be one at all. This is okay because older tests won't
+	// encounter this, and new tests shouldn't be using ids.
+	return "<none>"
+}
diff --git a/v1.5.7/internal/states/state_test.go b/v1.5.7/internal/states/state_test.go
new file mode 100644
index 0000000..a21a14d
--- /dev/null
+++ b/v1.5.7/internal/states/state_test.go
@@ -0,0 +1,1011 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package states
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+
+	"github.com/go-test/deep"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+)
+
+func TestState(t *testing.T) {
+	// This basic tests exercises the main mutation methods to construct
+	// a state. It is not fully comprehensive, so other tests should visit
+	// more esoteric codepaths.
+
+	state := NewState()
+
+	rootModule := state.RootModule()
+	if rootModule == nil {
+		t.Errorf("root module is nil; want valid object")
+	}
+
+	rootModule.SetLocalValue("foo", cty.StringVal("foo value"))
+	rootModule.SetOutputValue("bar", cty.StringVal("bar value"), false)
+	rootModule.SetOutputValue("secret", cty.StringVal("secret value"), true)
+	rootModule.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_thing",
+			Name: "baz",
+		}.Instance(addrs.IntKey(0)),
+		&ResourceInstanceObjectSrc{
+			Status:        ObjectReady,
+			SchemaVersion: 1,
+			AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	childModule := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	childModule.SetOutputValue("pizza", cty.StringVal("hawaiian"), false)
+	multiModA := state.EnsureModule(addrs.RootModuleInstance.Child("multi", addrs.StringKey("a")))
+	multiModA.SetOutputValue("pizza", cty.StringVal("cheese"), false)
+	multiModB := state.EnsureModule(addrs.RootModuleInstance.Child("multi", addrs.StringKey("b")))
+	multiModB.SetOutputValue("pizza", cty.StringVal("sausage"), false)
+
+	want := &State{
+		Modules: map[string]*Module{
+			"": {
+				Addr: addrs.RootModuleInstance,
+				LocalValues: map[string]cty.Value{
+					"foo": cty.StringVal("foo value"),
+				},
+				OutputValues: map[string]*OutputValue{
+					"bar": {
+						Addr: addrs.AbsOutputValue{
+							OutputValue: addrs.OutputValue{
+								Name: "bar",
+							},
+						},
+						Value:     cty.StringVal("bar value"),
+						Sensitive: false,
+					},
+					"secret": {
+						Addr: addrs.AbsOutputValue{
+							OutputValue: addrs.OutputValue{
+								Name: "secret",
+							},
+						},
+						Value:     cty.StringVal("secret value"),
+						Sensitive: true,
+					},
+				},
+				Resources: map[string]*Resource{
+					"test_thing.baz": {
+						Addr: addrs.Resource{
+							Mode: addrs.ManagedResourceMode,
+							Type: "test_thing",
+							Name: "baz",
+						}.Absolute(addrs.RootModuleInstance),
+
+						Instances: map[addrs.InstanceKey]*ResourceInstance{
+							addrs.IntKey(0): {
+								Current: &ResourceInstanceObjectSrc{
+									SchemaVersion: 1,
+									Status:        ObjectReady,
+									AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+								},
+								Deposed: map[DeposedKey]*ResourceInstanceObjectSrc{},
+							},
+						},
+						ProviderConfig: addrs.AbsProviderConfig{
+							Provider: addrs.NewDefaultProvider("test"),
+							Module:   addrs.RootModule,
+						},
+					},
+				},
+			},
+			"module.child": {
+				Addr:        addrs.RootModuleInstance.Child("child", addrs.NoKey),
+				LocalValues: map[string]cty.Value{},
+				OutputValues: map[string]*OutputValue{
+					"pizza": {
+						Addr: addrs.AbsOutputValue{
+							Module: addrs.RootModuleInstance.Child("child", addrs.NoKey),
+							OutputValue: addrs.OutputValue{
+								Name: "pizza",
+							},
+						},
+						Value:     cty.StringVal("hawaiian"),
+						Sensitive: false,
+					},
+				},
+				Resources: map[string]*Resource{},
+			},
+			`module.multi["a"]`: {
+				Addr:        addrs.RootModuleInstance.Child("multi", addrs.StringKey("a")),
+				LocalValues: map[string]cty.Value{},
+				OutputValues: map[string]*OutputValue{
+					"pizza": {
+						Addr: addrs.AbsOutputValue{
+							Module: addrs.RootModuleInstance.Child("multi", addrs.StringKey("a")),
+							OutputValue: addrs.OutputValue{
+								Name: "pizza",
+							},
+						},
+						Value:     cty.StringVal("cheese"),
+						Sensitive: false,
+					},
+				},
+				Resources: map[string]*Resource{},
+			},
+			`module.multi["b"]`: {
+				Addr:        addrs.RootModuleInstance.Child("multi", addrs.StringKey("b")),
+				LocalValues: map[string]cty.Value{},
+				OutputValues: map[string]*OutputValue{
+					"pizza": {
+						Addr: addrs.AbsOutputValue{
+							Module: addrs.RootModuleInstance.Child("multi", addrs.StringKey("b")),
+							OutputValue: addrs.OutputValue{
+								Name: "pizza",
+							},
+						},
+						Value:     cty.StringVal("sausage"),
+						Sensitive: false,
+					},
+				},
+				Resources: map[string]*Resource{},
+			},
+		},
+	}
+
+	{
+		// Our structure goes deep, so we need to temporarily override the
+		// deep package settings to ensure that we visit the full structure.
+		oldDeepDepth := deep.MaxDepth
+		oldDeepCompareUnexp := deep.CompareUnexportedFields
+		deep.MaxDepth = 50
+		deep.CompareUnexportedFields = true
+		defer func() {
+			deep.MaxDepth = oldDeepDepth
+			deep.CompareUnexportedFields = oldDeepCompareUnexp
+		}()
+	}
+
+	for _, problem := range deep.Equal(state, want) {
+		t.Error(problem)
+	}
+
+	expectedOutputs := map[string]string{
+		`module.multi["a"].output.pizza`: "cheese",
+		`module.multi["b"].output.pizza`: "sausage",
+	}
+
+	for _, o := range state.ModuleOutputs(addrs.RootModuleInstance, addrs.ModuleCall{Name: "multi"}) {
+		addr := o.Addr.String()
+		expected := expectedOutputs[addr]
+		delete(expectedOutputs, addr)
+
+		if expected != o.Value.AsString() {
+			t.Fatalf("expected %q:%q, got %q", addr, expected, o.Value.AsString())
+		}
+	}
+
+	for addr, o := range expectedOutputs {
+		t.Fatalf("missing output %q:%q", addr, o)
+	}
+}
+
+func TestStateDeepCopyObject(t *testing.T) {
+	obj := &ResourceInstanceObject{
+		Value: cty.ObjectVal(map[string]cty.Value{
+			"id": cty.StringVal("id"),
+		}),
+		Private: []byte("private"),
+		Status:  ObjectReady,
+		Dependencies: []addrs.ConfigResource{
+			{
+				Module: addrs.RootModule,
+				Resource: addrs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "test_instance",
+					Name: "bar",
+				},
+			},
+		},
+		CreateBeforeDestroy: true,
+	}
+
+	objCopy := obj.DeepCopy()
+	if !reflect.DeepEqual(obj, objCopy) {
+		t.Fatalf("not equal\n%#v\n%#v", obj, objCopy)
+	}
+}
+
+func TestStateDeepCopy(t *testing.T) {
+	state := NewState()
+
+	rootModule := state.RootModule()
+	if rootModule == nil {
+		t.Errorf("root module is nil; want valid object")
+	}
+
+	rootModule.SetLocalValue("foo", cty.StringVal("foo value"))
+	rootModule.SetOutputValue("bar", cty.StringVal("bar value"), false)
+	rootModule.SetOutputValue("secret", cty.StringVal("secret value"), true)
+	rootModule.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_thing",
+			Name: "baz",
+		}.Instance(addrs.IntKey(0)),
+		&ResourceInstanceObjectSrc{
+			Status:              ObjectReady,
+			SchemaVersion:       1,
+			AttrsJSON:           []byte(`{"woozles":"confuzles"}`),
+			Private:             []byte("private data"),
+			Dependencies:        []addrs.ConfigResource{},
+			CreateBeforeDestroy: true,
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	rootModule.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_thing",
+			Name: "bar",
+		}.Instance(addrs.IntKey(0)),
+		&ResourceInstanceObjectSrc{
+			Status:        ObjectReady,
+			SchemaVersion: 1,
+			AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+			// Sensitive path at "woozles"
+			AttrSensitivePaths: []cty.PathValueMarks{
+				{
+					Path:  cty.Path{cty.GetAttrStep{Name: "woozles"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			Private: []byte("private data"),
+			Dependencies: []addrs.ConfigResource{
+				{
+					Module: addrs.RootModule,
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_thing",
+						Name: "baz",
+					},
+				},
+			},
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	childModule := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	childModule.SetOutputValue("pizza", cty.StringVal("hawaiian"), false)
+
+	stateCopy := state.DeepCopy()
+	if !state.Equal(stateCopy) {
+		t.Fatalf("\nexpected:\n%q\ngot:\n%q\n", state, stateCopy)
+	}
+}
+
+func TestStateHasResourceInstanceObjects(t *testing.T) {
+	providerConfig := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule,
+		Provider: addrs.MustParseProviderSourceString("test/test"),
+	}
+	childModuleProviderConfig := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule.Child("child"),
+		Provider: addrs.MustParseProviderSourceString("test/test"),
+	}
+
+	tests := map[string]struct {
+		Setup func(ss *SyncState)
+		Want  bool
+	}{
+		"empty": {
+			func(ss *SyncState) {},
+			false,
+		},
+		"one current, ready object in root module": {
+			func(ss *SyncState) {
+				ss.SetResourceInstanceCurrent(
+					mustAbsResourceAddr("test.foo").Instance(addrs.NoKey),
+					&ResourceInstanceObjectSrc{
+						AttrsJSON: []byte(`{}`),
+						Status:    ObjectReady,
+					},
+					providerConfig,
+				)
+			},
+			true,
+		},
+		"one current, ready object in child module": {
+			func(ss *SyncState) {
+				ss.SetResourceInstanceCurrent(
+					mustAbsResourceAddr("module.child.test.foo").Instance(addrs.NoKey),
+					&ResourceInstanceObjectSrc{
+						AttrsJSON: []byte(`{}`),
+						Status:    ObjectReady,
+					},
+					childModuleProviderConfig,
+				)
+			},
+			true,
+		},
+		"one current, tainted object in root module": {
+			func(ss *SyncState) {
+				ss.SetResourceInstanceCurrent(
+					mustAbsResourceAddr("test.foo").Instance(addrs.NoKey),
+					&ResourceInstanceObjectSrc{
+						AttrsJSON: []byte(`{}`),
+						Status:    ObjectTainted,
+					},
+					providerConfig,
+				)
+			},
+			true,
+		},
+		"one deposed, ready object in root module": {
+			func(ss *SyncState) {
+				ss.SetResourceInstanceDeposed(
+					mustAbsResourceAddr("test.foo").Instance(addrs.NoKey),
+					DeposedKey("uhoh"),
+					&ResourceInstanceObjectSrc{
+						AttrsJSON: []byte(`{}`),
+						Status:    ObjectTainted,
+					},
+					providerConfig,
+				)
+			},
+			true,
+		},
+		"one empty resource husk in root module": {
+			func(ss *SyncState) {
+				// Current Terraform doesn't actually create resource husks
+				// as part of its everyday work, so this is a "should never
+				// happen" case but we'll test to make sure we're robust to
+				// it anyway, because this was a historical bug blocking
+				// "terraform workspace delete" and similar.
+				ss.SetResourceInstanceCurrent(
+					mustAbsResourceAddr("test.foo").Instance(addrs.NoKey),
+					&ResourceInstanceObjectSrc{
+						AttrsJSON: []byte(`{}`),
+						Status:    ObjectTainted,
+					},
+					providerConfig,
+				)
+				s := ss.Lock()
+				delete(s.Modules[""].Resources["test.foo"].Instances, addrs.NoKey)
+				ss.Unlock()
+			},
+			false,
+		},
+		"one current data resource object in root module": {
+			func(ss *SyncState) {
+				ss.SetResourceInstanceCurrent(
+					mustAbsResourceAddr("data.test.foo").Instance(addrs.NoKey),
+					&ResourceInstanceObjectSrc{
+						AttrsJSON: []byte(`{}`),
+						Status:    ObjectReady,
+					},
+					providerConfig,
+				)
+			},
+			false, // data resources aren't managed resources, so they don't count
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			state := BuildState(test.Setup)
+			got := state.HasManagedResourceInstanceObjects()
+			if got != test.Want {
+				t.Errorf("wrong result\nstate content: (using legacy state string format; might not be comprehensive)\n%s\n\ngot:  %t\nwant: %t", state, got, test.Want)
+			}
+		})
+	}
+
+}
+
+func TestState_MoveAbsResource(t *testing.T) {
+	// Set up a starter state for the embedded tests, which should start from a copy of this state.
+	state := NewState()
+	rootModule := state.RootModule()
+	rootModule.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_thing",
+			Name: "foo",
+		}.Instance(addrs.IntKey(0)),
+		&ResourceInstanceObjectSrc{
+			Status:        ObjectReady,
+			SchemaVersion: 1,
+			AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Absolute(addrs.RootModuleInstance)
+
+	t.Run("basic move", func(t *testing.T) {
+		s := state.DeepCopy()
+		dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "bar"}.Absolute(addrs.RootModuleInstance)
+
+		s.MoveAbsResource(src, dst)
+
+		if s.Empty() {
+			t.Fatal("unexpected empty state")
+		}
+
+		if len(s.RootModule().Resources) != 1 {
+			t.Fatalf("wrong number of resources in state; expected 1, found %d", len(state.RootModule().Resources))
+		}
+
+		got := s.Resource(dst)
+		if got.Addr.Resource != dst.Resource {
+			t.Fatalf("dst resource not in state")
+		}
+	})
+
+	t.Run("move to new module", func(t *testing.T) {
+		s := state.DeepCopy()
+		dstModule := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("one"))
+		dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "bar"}.Absolute(dstModule)
+
+		s.MoveAbsResource(src, dst)
+
+		if s.Empty() {
+			t.Fatal("unexpected empty state")
+		}
+
+		if s.Module(dstModule) == nil {
+			t.Fatalf("child module %s not in state", dstModule.String())
+		}
+
+		if len(s.Module(dstModule).Resources) != 1 {
+			t.Fatalf("wrong number of resources in state; expected 1, found %d", len(s.Module(dstModule).Resources))
+		}
+
+		got := s.Resource(dst)
+		if got.Addr.Resource != dst.Resource {
+			t.Fatalf("dst resource not in state")
+		}
+	})
+
+	t.Run("from a child module to root", func(t *testing.T) {
+		s := state.DeepCopy()
+		srcModule := addrs.RootModuleInstance.Child("kinder", addrs.NoKey)
+		cm := s.EnsureModule(srcModule)
+		cm.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_thing",
+				Name: "child",
+			}.Instance(addrs.IntKey(0)), // Moving the AbsResouce moves all instances
+			&ResourceInstanceObjectSrc{
+				Status:        ObjectReady,
+				SchemaVersion: 1,
+				AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+		cm.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_thing",
+				Name: "child",
+			}.Instance(addrs.IntKey(1)), // Moving the AbsResouce moves all instances
+			&ResourceInstanceObjectSrc{
+				Status:        ObjectReady,
+				SchemaVersion: 1,
+				AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+
+		src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "child"}.Absolute(srcModule)
+		dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "child"}.Absolute(addrs.RootModuleInstance)
+		s.MoveAbsResource(src, dst)
+
+		if s.Empty() {
+			t.Fatal("unexpected empty state")
+		}
+
+		// The child module should have been removed after removing its only resource
+		if s.Module(srcModule) != nil {
+			t.Fatalf("child module %s was not removed from state after mv", srcModule.String())
+		}
+
+		if len(s.RootModule().Resources) != 2 {
+			t.Fatalf("wrong number of resources in state; expected 2, found %d", len(s.RootModule().Resources))
+		}
+
+		if len(s.Resource(dst).Instances) != 2 {
+			t.Fatalf("wrong number of resource instances for dst, got %d expected 2", len(s.Resource(dst).Instances))
+		}
+
+		got := s.Resource(dst)
+		if got.Addr.Resource != dst.Resource {
+			t.Fatalf("dst resource not in state")
+		}
+	})
+
+	t.Run("module to new module", func(t *testing.T) {
+		s := NewState()
+		srcModule := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("exists"))
+		dstModule := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("new"))
+		cm := s.EnsureModule(srcModule)
+		cm.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_thing",
+				Name: "child",
+			}.Instance(addrs.NoKey),
+			&ResourceInstanceObjectSrc{
+				Status:        ObjectReady,
+				SchemaVersion: 1,
+				AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+
+		src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "child"}.Absolute(srcModule)
+		dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "child"}.Absolute(dstModule)
+		s.MoveAbsResource(src, dst)
+
+		if s.Empty() {
+			t.Fatal("unexpected empty state")
+		}
+
+		// The child module should have been removed after removing its only resource
+		if s.Module(srcModule) != nil {
+			t.Fatalf("child module %s was not removed from state after mv", srcModule.String())
+		}
+
+		gotMod := s.Module(dstModule)
+		if len(gotMod.Resources) != 1 {
+			t.Fatalf("wrong number of resources in state; expected 1, found %d", len(gotMod.Resources))
+		}
+
+		got := s.Resource(dst)
+		if got.Addr.Resource != dst.Resource {
+			t.Fatalf("dst resource not in state")
+		}
+	})
+
+	t.Run("module to new module", func(t *testing.T) {
+		s := NewState()
+		srcModule := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("exists"))
+		dstModule := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("new"))
+		cm := s.EnsureModule(srcModule)
+		cm.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_thing",
+				Name: "child",
+			}.Instance(addrs.NoKey),
+			&ResourceInstanceObjectSrc{
+				Status:        ObjectReady,
+				SchemaVersion: 1,
+				AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+
+		src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "child"}.Absolute(srcModule)
+		dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "child"}.Absolute(dstModule)
+		s.MoveAbsResource(src, dst)
+
+		if s.Empty() {
+			t.Fatal("unexpected empty state")
+		}
+
+		// The child module should have been removed after removing its only resource
+		if s.Module(srcModule) != nil {
+			t.Fatalf("child module %s was not removed from state after mv", srcModule.String())
+		}
+
+		gotMod := s.Module(dstModule)
+		if len(gotMod.Resources) != 1 {
+			t.Fatalf("wrong number of resources in state; expected 1, found %d", len(gotMod.Resources))
+		}
+
+		got := s.Resource(dst)
+		if got.Addr.Resource != dst.Resource {
+			t.Fatalf("dst resource not in state")
+		}
+	})
+}
+
+func TestState_MaybeMoveAbsResource(t *testing.T) {
+	state := NewState()
+	rootModule := state.RootModule()
+	rootModule.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_thing",
+			Name: "foo",
+		}.Instance(addrs.IntKey(0)),
+		&ResourceInstanceObjectSrc{
+			Status:        ObjectReady,
+			SchemaVersion: 1,
+			AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Absolute(addrs.RootModuleInstance)
+	dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "bar"}.Absolute(addrs.RootModuleInstance)
+
+	// First move, success
+	t.Run("first move", func(t *testing.T) {
+		moved := state.MaybeMoveAbsResource(src, dst)
+		if !moved {
+			t.Fatal("wrong result")
+		}
+	})
+
+	// Trying to move a resource that doesn't exist in state to a resource which does exist should be a noop.
+	t.Run("noop", func(t *testing.T) {
+		moved := state.MaybeMoveAbsResource(src, dst)
+		if moved {
+			t.Fatal("wrong result")
+		}
+	})
+}
+
+func TestState_MoveAbsResourceInstance(t *testing.T) {
+	state := NewState()
+	rootModule := state.RootModule()
+	rootModule.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_thing",
+			Name: "foo",
+		}.Instance(addrs.NoKey),
+		&ResourceInstanceObjectSrc{
+			Status:        ObjectReady,
+			SchemaVersion: 1,
+			AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	// src resource from the state above
+	src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	t.Run("resource to resource instance", func(t *testing.T) {
+		s := state.DeepCopy()
+		// For a little extra fun, move a resource to a resource instance: test_thing.foo to test_thing.foo[1]
+		dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Instance(addrs.IntKey(1)).Absolute(addrs.RootModuleInstance)
+
+		s.MoveAbsResourceInstance(src, dst)
+
+		if s.Empty() {
+			t.Fatal("unexpected empty state")
+		}
+
+		if len(s.RootModule().Resources) != 1 {
+			t.Fatalf("wrong number of resources in state; expected 1, found %d", len(state.RootModule().Resources))
+		}
+
+		got := s.ResourceInstance(dst)
+		if got == nil {
+			t.Fatalf("dst resource not in state")
+		}
+	})
+
+	t.Run("move to new module", func(t *testing.T) {
+		s := state.DeepCopy()
+		// test_thing.foo to module.kinder.test_thing.foo["baz"]
+		dstModule := addrs.RootModuleInstance.Child("kinder", addrs.NoKey)
+		dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Instance(addrs.IntKey(1)).Absolute(dstModule)
+
+		s.MoveAbsResourceInstance(src, dst)
+
+		if s.Empty() {
+			t.Fatal("unexpected empty state")
+		}
+
+		if s.Module(dstModule) == nil {
+			t.Fatalf("child module %s not in state", dstModule.String())
+		}
+
+		if len(s.Module(dstModule).Resources) != 1 {
+			t.Fatalf("wrong number of resources in state; expected 1, found %d", len(s.Module(dstModule).Resources))
+		}
+
+		got := s.ResourceInstance(dst)
+		if got == nil {
+			t.Fatalf("dst resource not in state")
+		}
+	})
+}
+
+func TestState_MaybeMoveAbsResourceInstance(t *testing.T) {
+	state := NewState()
+	rootModule := state.RootModule()
+	rootModule.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_thing",
+			Name: "foo",
+		}.Instance(addrs.NoKey),
+		&ResourceInstanceObjectSrc{
+			Status:        ObjectReady,
+			SchemaVersion: 1,
+			AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	// For a little extra fun, let's go from a resource to a resource instance: test_thing.foo to test_thing.bar[1]
+	src := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+	dst := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "foo"}.Instance(addrs.IntKey(1)).Absolute(addrs.RootModuleInstance)
+
+	// First move, success
+	t.Run("first move", func(t *testing.T) {
+		moved := state.MaybeMoveAbsResourceInstance(src, dst)
+		if !moved {
+			t.Fatal("wrong result")
+		}
+		got := state.ResourceInstance(dst)
+		if got == nil {
+			t.Fatal("destination resource instance not in state")
+		}
+	})
+
+	// Moving a resource instance that doesn't exist in state to a resource which does exist should be a noop.
+	t.Run("noop", func(t *testing.T) {
+		moved := state.MaybeMoveAbsResourceInstance(src, dst)
+		if moved {
+			t.Fatal("wrong result")
+		}
+	})
+}
+
+func TestState_MoveModuleInstance(t *testing.T) {
+	state := NewState()
+	srcModule := addrs.RootModuleInstance.Child("kinder", addrs.NoKey)
+	m := state.EnsureModule(srcModule)
+	m.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_thing",
+			Name: "foo",
+		}.Instance(addrs.NoKey),
+		&ResourceInstanceObjectSrc{
+			Status:        ObjectReady,
+			SchemaVersion: 1,
+			AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	dstModule := addrs.RootModuleInstance.Child("child", addrs.IntKey(3))
+	state.MoveModuleInstance(srcModule, dstModule)
+
+	// srcModule should have been removed, dstModule should exist and have one resource
+	if len(state.Modules) != 2 { // kinder[3] and root
+		t.Fatalf("wrong number of modules in state. Expected 2, got %d", len(state.Modules))
+	}
+
+	got := state.Module(dstModule)
+	if got == nil {
+		t.Fatal("dstModule not found")
+	}
+
+	gone := state.Module(srcModule)
+	if gone != nil {
+		t.Fatal("srcModule not removed from state")
+	}
+
+	r := got.Resource(mustAbsResourceAddr("test_thing.foo").Resource)
+	if r.Addr.Module.String() != dstModule.String() {
+		fmt.Println(r.Addr.Module.String())
+		t.Fatal("resource address was not updated")
+	}
+
+}
+
+func TestState_MaybeMoveModuleInstance(t *testing.T) {
+	state := NewState()
+	src := addrs.RootModuleInstance.Child("child", addrs.StringKey("a"))
+	cm := state.EnsureModule(src)
+	cm.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_thing",
+			Name: "foo",
+		}.Instance(addrs.NoKey),
+		&ResourceInstanceObjectSrc{
+			Status:        ObjectReady,
+			SchemaVersion: 1,
+			AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	dst := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("b"))
+
+	// First move, success
+	t.Run("first move", func(t *testing.T) {
+		moved := state.MaybeMoveModuleInstance(src, dst)
+		if !moved {
+			t.Fatal("wrong result")
+		}
+	})
+
+	// Second move, should be a noop
+	t.Run("noop", func(t *testing.T) {
+		moved := state.MaybeMoveModuleInstance(src, dst)
+		if moved {
+			t.Fatal("wrong result")
+		}
+	})
+}
+
+func TestState_MoveModule(t *testing.T) {
+	// For this test, add two module instances (kinder and kinder["a"]).
+	// MoveModule(kinder) should move both instances.
+	state := NewState() // starter state, should be copied by the subtests.
+	srcModule := addrs.RootModule.Child("kinder")
+	m := state.EnsureModule(srcModule.UnkeyedInstanceShim())
+	m.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_thing",
+			Name: "foo",
+		}.Instance(addrs.NoKey),
+		&ResourceInstanceObjectSrc{
+			Status:        ObjectReady,
+			SchemaVersion: 1,
+			AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	moduleInstance := addrs.RootModuleInstance.Child("kinder", addrs.StringKey("a"))
+	mi := state.EnsureModule(moduleInstance)
+	mi.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_thing",
+			Name: "foo",
+		}.Instance(addrs.NoKey),
+		&ResourceInstanceObjectSrc{
+			Status:        ObjectReady,
+			SchemaVersion: 1,
+			AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	_, mc := srcModule.Call()
+	src := mc.Absolute(addrs.RootModuleInstance.Child("kinder", addrs.NoKey))
+
+	t.Run("basic", func(t *testing.T) {
+		s := state.DeepCopy()
+		_, dstMC := addrs.RootModule.Child("child").Call()
+		dst := dstMC.Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+		s.MoveModule(src, dst)
+
+		// srcModule should have been removed, dstModule should exist and have one resource
+		if len(s.Modules) != 3 { // child, child["a"] and root
+			t.Fatalf("wrong number of modules in state. Expected 3, got %d", len(s.Modules))
+		}
+
+		got := s.Module(dst.Module)
+		if got == nil {
+			t.Fatal("dstModule not found")
+		}
+
+		got = s.Module(addrs.RootModuleInstance.Child("child", addrs.StringKey("a")))
+		if got == nil {
+			t.Fatal("dstModule instance \"a\" not found")
+		}
+
+		gone := s.Module(srcModule.UnkeyedInstanceShim())
+		if gone != nil {
+			t.Fatal("srcModule not removed from state")
+		}
+	})
+
+	t.Run("nested modules", func(t *testing.T) {
+		s := state.DeepCopy()
+
+		// add a child module to module.kinder
+		mi := mustParseModuleInstanceStr(`module.kinder.module.grand[1]`)
+		m := s.EnsureModule(mi)
+		m.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_thing",
+				Name: "foo",
+			}.Instance(addrs.NoKey),
+			&ResourceInstanceObjectSrc{
+				Status:        ObjectReady,
+				SchemaVersion: 1,
+				AttrsJSON:     []byte(`{"woozles":"confuzles"}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+
+		_, dstMC := addrs.RootModule.Child("child").Call()
+		dst := dstMC.Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+		s.MoveModule(src, dst)
+
+		moved := s.Module(addrs.RootModuleInstance.Child("child", addrs.StringKey("a")))
+		if moved == nil {
+			t.Fatal("dstModule not found")
+		}
+
+		// The nested module's relative address should also have been updated
+		nested := s.Module(mustParseModuleInstanceStr(`module.child.module.grand[1]`))
+		if nested == nil {
+			t.Fatal("nested child module of src wasn't moved")
+		}
+	})
+}
+
+func mustParseModuleInstanceStr(str string) addrs.ModuleInstance {
+	addr, diags := addrs.ParseModuleInstanceStr(str)
+	if diags.HasErrors() {
+		panic(diags.Err())
+	}
+	return addr
+}
+
+func mustAbsResourceAddr(s string) addrs.AbsResource {
+	addr, diags := addrs.ParseAbsResourceStr(s)
+	if diags.HasErrors() {
+		panic(diags.Err())
+	}
+	return addr
+}
diff --git a/v1.5.7/internal/states/statefile/diagnostics.go b/v1.5.7/internal/states/statefile/diagnostics.go
new file mode 100644
index 0000000..3b472ef
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/diagnostics.go
@@ -0,0 +1,65 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statefile
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+const invalidFormat = "Invalid state file format"
+
+// jsonUnmarshalDiags is a helper that translates errors returned from
+// json.Unmarshal into hopefully-more-helpful diagnostics messages.
+func jsonUnmarshalDiags(err error) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+	if err == nil {
+		return diags
+	}
+
+	switch tErr := err.(type) {
+	case *json.SyntaxError:
+		// We've usually already successfully parsed a source file as JSON at
+		// least once before we'd use jsonUnmarshalDiags with it (to sniff
+		// the version number) so this particular error should not appear much
+		// in practice.
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			invalidFormat,
+			fmt.Sprintf("The state file could not be parsed as JSON: syntax error at byte offset %d.", tErr.Offset),
+		))
+	case *json.UnmarshalTypeError:
+		// This is likely to be the most common area, describing a
+		// non-conformance between the file and the expected file format
+		// at a semantic level.
+		if tErr.Field != "" {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				invalidFormat,
+				fmt.Sprintf("The state file field %q has invalid value %s", tErr.Field, tErr.Value),
+			))
+			break
+		} else {
+			// Without a field name, we can't really say anything helpful.
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				invalidFormat,
+				"The state file does not conform to the expected JSON data structure.",
+			))
+		}
+	default:
+		// Fallback for all other types of errors. This can happen only for
+		// custom UnmarshalJSON implementations, so should be encountered
+		// only rarely.
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			invalidFormat,
+			fmt.Sprintf("The state file does not conform to the expected JSON data structure: %s.", err.Error()),
+		))
+	}
+
+	return diags
+}
diff --git a/v1.5.7/internal/states/statefile/doc.go b/v1.5.7/internal/states/statefile/doc.go
new file mode 100644
index 0000000..215a0ab
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/doc.go
@@ -0,0 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package statefile deals with the file format used to serialize states for
+// persistent storage and then deserialize them into memory again later.
+package statefile
diff --git a/v1.5.7/internal/states/statefile/file.go b/v1.5.7/internal/states/statefile/file.go
new file mode 100644
index 0000000..b05be62
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/file.go
@@ -0,0 +1,65 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statefile
+
+import (
+	version "github.com/hashicorp/go-version"
+
+	"github.com/hashicorp/terraform/internal/states"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+// File is the in-memory representation of a state file. It includes the state
+// itself along with various metadata used to track changing state files for
+// the same configuration over time.
+type File struct {
+	// TerraformVersion is the version of Terraform that wrote this state file.
+	TerraformVersion *version.Version
+
+	// Serial is incremented on any operation that modifies
+	// the State file. It is used to detect potentially conflicting
+	// updates.
+	Serial uint64
+
+	// Lineage is set when a new, blank state file is created and then
+	// never updated. This allows us to determine whether the serials
+	// of two states can be meaningfully compared.
+	// Apart from the guarantee that collisions between two lineages
+	// are very unlikely, this value is opaque and external callers
+	// should only compare lineage strings byte-for-byte for equality.
+	Lineage string
+
+	// State is the actual state represented by this file.
+	State *states.State
+}
+
+func New(state *states.State, lineage string, serial uint64) *File {
+	// To make life easier on callers, we'll accept a nil state here and just
+	// allocate an empty one, which is required for this file to be successfully
+	// written out.
+	if state == nil {
+		state = states.NewState()
+	}
+
+	return &File{
+		TerraformVersion: tfversion.SemVer,
+		State:            state,
+		Lineage:          lineage,
+		Serial:           serial,
+	}
+}
+
+// DeepCopy is a convenience method to create a new File object whose state
+// is a deep copy of the receiver's, as implemented by states.State.DeepCopy.
+func (f *File) DeepCopy() *File {
+	if f == nil {
+		return nil
+	}
+	return &File{
+		TerraformVersion: f.TerraformVersion,
+		Serial:           f.Serial,
+		Lineage:          f.Lineage,
+		State:            f.State.DeepCopy(),
+	}
+}
diff --git a/v1.5.7/internal/states/statefile/marshal_equal.go b/v1.5.7/internal/states/statefile/marshal_equal.go
new file mode 100644
index 0000000..6470fd7
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/marshal_equal.go
@@ -0,0 +1,43 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statefile
+
+import (
+	"bytes"
+
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// StatesMarshalEqual returns true if and only if the two given states have
+// an identical (byte-for-byte) statefile representation.
+//
+// This function compares only the portions of the state that are persisted
+// in state files, so for example it will not return false if the only
+// differences between the two states are local values or descendent module
+// outputs.
+func StatesMarshalEqual(a, b *states.State) bool {
+	var aBuf bytes.Buffer
+	var bBuf bytes.Buffer
+
+	// nil states are not valid states, and so they can never martial equal.
+	if a == nil || b == nil {
+		return false
+	}
+
+	// We write here some temporary files that have no header information
+	// populated, thus ensuring that we're only comparing the state itself
+	// and not any metadata.
+	err := Write(&File{State: a}, &aBuf)
+	if err != nil {
+		// Should never happen, because we're writing to an in-memory buffer
+		panic(err)
+	}
+	err = Write(&File{State: b}, &bBuf)
+	if err != nil {
+		// Should never happen, because we're writing to an in-memory buffer
+		panic(err)
+	}
+
+	return bytes.Equal(aBuf.Bytes(), bBuf.Bytes())
+}
diff --git a/v1.5.7/internal/states/statefile/read.go b/v1.5.7/internal/states/statefile/read.go
new file mode 100644
index 0000000..ceb6ce8
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/read.go
@@ -0,0 +1,203 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statefile
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+
+	version "github.com/hashicorp/go-version"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+// ErrNoState is returned by ReadState when the state file is empty.
+var ErrNoState = errors.New("no state")
+
+// Read reads a state from the given reader.
+//
+// Legacy state format versions 1 through 3 are supported, but the result will
+// contain object attributes in the deprecated "flatmap" format and so must
+// be upgraded by the caller before use.
+//
+// If the state file is empty, the special error value ErrNoState is returned.
+// Otherwise, the returned error might be a wrapper around tfdiags.Diagnostics
+// potentially describing multiple errors.
+func Read(r io.Reader) (*File, error) {
+	// Some callers provide us a "typed nil" *os.File here, which would
+	// cause us to panic below if we tried to use it.
+	if f, ok := r.(*os.File); ok && f == nil {
+		return nil, ErrNoState
+	}
+
+	var diags tfdiags.Diagnostics
+
+	// We actually just buffer the whole thing in memory, because states are
+	// generally not huge and we need to do be able to sniff for a version
+	// number before full parsing.
+	src, err := ioutil.ReadAll(r)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to read state file",
+			fmt.Sprintf("The state file could not be read: %s", err),
+		))
+		return nil, diags.Err()
+	}
+
+	if len(src) == 0 {
+		return nil, ErrNoState
+	}
+
+	state, diags := readState(src)
+	if diags.HasErrors() {
+		return nil, diags.Err()
+	}
+
+	if state == nil {
+		// Should never happen
+		panic("readState returned nil state with no errors")
+	}
+
+	return state, diags.Err()
+}
+
+func readState(src []byte) (*File, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	if looksLikeVersion0(src) {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			unsupportedFormat,
+			"The state is stored in a legacy binary format that is not supported since Terraform v0.7. To continue, first upgrade the state using Terraform 0.6.16 or earlier.",
+		))
+		return nil, diags
+	}
+
+	version, versionDiags := sniffJSONStateVersion(src)
+	diags = diags.Append(versionDiags)
+	if versionDiags.HasErrors() {
+		return nil, diags
+	}
+
+	switch version {
+	case 0:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			unsupportedFormat,
+			"The state file uses JSON syntax but has a version number of zero. There was never a JSON-based state format zero, so this state file is invalid and cannot be processed.",
+		))
+		return nil, diags
+	case 1:
+		return readStateV1(src)
+	case 2:
+		return readStateV2(src)
+	case 3:
+		return readStateV3(src)
+	case 4:
+		return readStateV4(src)
+	default:
+		thisVersion := tfversion.SemVer.String()
+		creatingVersion := sniffJSONStateTerraformVersion(src)
+		switch {
+		case creatingVersion != "":
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				unsupportedFormat,
+				fmt.Sprintf("The state file uses format version %d, which is not supported by Terraform %s. This state file was created by Terraform %s.", version, thisVersion, creatingVersion),
+			))
+		default:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				unsupportedFormat,
+				fmt.Sprintf("The state file uses format version %d, which is not supported by Terraform %s. This state file may have been created by a newer version of Terraform.", version, thisVersion),
+			))
+		}
+		return nil, diags
+	}
+}
+
+func sniffJSONStateVersion(src []byte) (uint64, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	type VersionSniff struct {
+		Version *uint64 `json:"version"`
+	}
+	var sniff VersionSniff
+	err := json.Unmarshal(src, &sniff)
+	if err != nil {
+		switch tErr := err.(type) {
+		case *json.SyntaxError:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				unsupportedFormat,
+				fmt.Sprintf("The state file could not be parsed as JSON: syntax error at byte offset %d.", tErr.Offset),
+			))
+		case *json.UnmarshalTypeError:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				unsupportedFormat,
+				fmt.Sprintf("The version in the state file is %s. A positive whole number is required.", tErr.Value),
+			))
+		default:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				unsupportedFormat,
+				"The state file could not be parsed as JSON.",
+			))
+		}
+	}
+
+	if sniff.Version == nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			unsupportedFormat,
+			"The state file does not have a \"version\" attribute, which is required to identify the format version.",
+		))
+		return 0, diags
+	}
+
+	return *sniff.Version, diags
+}
+
+// sniffJSONStateTerraformVersion attempts to sniff the Terraform version
+// specification from the given state file source code. The result is either
+// a version string or an empty string if no version number could be extracted.
+//
+// This is a best-effort function intended to produce nicer error messages. It
+// should not be used for any real processing.
+func sniffJSONStateTerraformVersion(src []byte) string {
+	type VersionSniff struct {
+		Version string `json:"terraform_version"`
+	}
+	var sniff VersionSniff
+
+	err := json.Unmarshal(src, &sniff)
+	if err != nil {
+		return ""
+	}
+
+	// Attempt to parse the string as a version so we won't report garbage
+	// as a version number.
+	_, err = version.NewVersion(sniff.Version)
+	if err != nil {
+		return ""
+	}
+
+	return sniff.Version
+}
+
+// unsupportedFormat is a diagnostic summary message for when the state file
+// seems to not be a state file at all, or is not a supported version.
+//
+// Use invalidFormat instead for the subtly-different case of "this looks like
+// it's intended to be a state file but it's not structured correctly".
+const unsupportedFormat = "Unsupported state file format"
+
+const upgradeFailed = "State format upgrade failed"
diff --git a/v1.5.7/internal/states/statefile/roundtrip_test.go b/v1.5.7/internal/states/statefile/roundtrip_test.go
new file mode 100644
index 0000000..208310b
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/roundtrip_test.go
@@ -0,0 +1,79 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statefile
+
+import (
+	"bytes"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+	"testing"
+
+	"github.com/go-test/deep"
+)
+
+func TestRoundtrip(t *testing.T) {
+	const dir = "testdata/roundtrip"
+	entries, err := ioutil.ReadDir(dir)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, info := range entries {
+		const inSuffix = ".in.tfstate"
+		const outSuffix = ".out.tfstate"
+
+		if info.IsDir() {
+			continue
+		}
+		inName := info.Name()
+		if !strings.HasSuffix(inName, inSuffix) {
+			continue
+		}
+		name := inName[:len(inName)-len(inSuffix)]
+		outName := name + outSuffix
+
+		t.Run(name, func(t *testing.T) {
+			oSrcWant, err := ioutil.ReadFile(filepath.Join(dir, outName))
+			if err != nil {
+				t.Fatal(err)
+			}
+			oWant, diags := readStateV4(oSrcWant)
+			if diags.HasErrors() {
+				t.Fatal(diags.Err())
+			}
+
+			ir, err := os.Open(filepath.Join(dir, inName))
+			if err != nil {
+				t.Fatal(err)
+			}
+			defer ir.Close()
+
+			f, err := Read(ir)
+			if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+
+			var buf bytes.Buffer
+			err = Write(f, &buf)
+			if err != nil {
+				t.Fatal(err)
+			}
+			oSrcWritten := buf.Bytes()
+
+			oGot, diags := readStateV4(oSrcWritten)
+			if diags.HasErrors() {
+				t.Fatal(diags.Err())
+			}
+
+			problems := deep.Equal(oGot, oWant)
+			sort.Strings(problems)
+			for _, problem := range problems {
+				t.Error(problem)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v1-simple.in.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v1-simple.in.tfstate
new file mode 100644
index 0000000..85524bf
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v1-simple.in.tfstate
@@ -0,0 +1,52 @@
+{
+    "version": 1,
+    "serial": 1,
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {
+                "numbers": "0,1"
+            },
+            "resources": {
+                "null_resource.bar": {
+                    "type": "null_resource",
+                    "depends_on": [
+                        "null_resource.foo"
+                    ],
+                    "primary": {
+                        "id": "6456912646020570139",
+                        "attributes": {
+                            "id": "6456912646020570139",
+                            "triggers.#": "1",
+                            "triggers.whaaat": "0,1"
+                        }
+                    }
+                },
+                "null_resource.foo.0": {
+                    "type": "null_resource",
+                    "primary": {
+                        "id": "3597404161631769617",
+                        "attributes": {
+                            "id": "3597404161631769617",
+                            "triggers.#": "1",
+                            "triggers.what": "0"
+                        }
+                    }
+                },
+                "null_resource.foo.1": {
+                    "type": "null_resource",
+                    "primary": {
+                        "id": "3214385801340650197",
+                        "attributes": {
+                            "id": "3214385801340650197",
+                            "triggers.#": "1",
+                            "triggers.what": "1"
+                        }
+                    }
+                }
+            }
+        }
+    ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v1-simple.out.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v1-simple.out.tfstate
new file mode 100644
index 0000000..7b9c180
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v1-simple.out.tfstate
@@ -0,0 +1,60 @@
+{
+    "version": 4,
+    "serial": 1,
+    "lineage": "",
+    "terraform_version": "0.0.0",
+    "outputs": {
+        "numbers": {
+            "type": "string",
+            "value": "0,1"
+        }
+    },
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "bar",
+            "provider": "provider[\"registry.terraform.io/-/null\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "6456912646020570139",
+                        "triggers.%": "1",
+                        "triggers.whaaat": "0,1"
+                    },
+                    "depends_on": [
+                        "null_resource.foo"
+                    ]
+                }
+            ]
+        },
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "foo",
+            "provider": "provider[\"registry.terraform.io/-/null\"]",
+            "each": "list",
+            "instances": [
+                {
+                    "index_key": 0,
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "3597404161631769617",
+                        "triggers.%": "1",
+                        "triggers.what": "0"
+                    }
+                },
+                {
+                    "index_key": 1,
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "3214385801340650197",
+                        "triggers.%": "1",
+                        "triggers.what": "1"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-bigint.in.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-bigint.in.tfstate
new file mode 100644
index 0000000..eadc3e7
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-bigint.in.tfstate
@@ -0,0 +1,136 @@
+{
+    "version": 3,
+    "terraform_version": "0.11.1",
+    "serial": 8,
+    "lineage": "0f5b2ff9-6ff5-8e9e-1f81-aa3ce9a483eb",
+    "backend": {
+        "hash": 10669755453527594976
+    },
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {
+                "results": {
+                    "sensitive": false,
+                    "type": "map",
+                    "value": {
+                        "aws_region": "us-west-2",
+                        "list": "[{\"triggers\":{\"index\":\"0\"}},{\"triggers\":{\"index\":\"1\"}}]",
+                        "list_item_0": "{\"triggers\":{\"index\":\"0\"}}",
+                        "list_item_1": "{\"triggers\":{\"index\":\"1\"}}",
+                        "list_triggers": "[{\"index\":\"0\"},{\"index\":\"1\"}]",
+                        "list_triggers_item": "{\"index\":\"0\"}",
+                        "module_object": "{\"test\":\"hello us-west-2\",\"test2\":\"hello world 2\"}",
+                        "module_output": "hello us-west-2",
+                        "single": "{\"triggers\":{\"baz\":\"BAR\",\"cwd_path\":\"/home/mart/Devel/terraform/tmp/hcl2-simple\",\"foo\":\"bar\",\"format\":\"Hello 12\",\"json\":\"{\\\"foo\\\":\\\"bar\\\",\\\"wonk\\\":[]}\",\"module_path\":\"/home/mart/Devel/terraform/tmp/hcl2-simple\",\"root_path\":\"/home/mart/Devel/terraform/tmp/hcl2-simple\",\"woot\":\"us-west-2\",\"workspace\":\"default\"}}"
+                    }
+                }
+            },
+            "resources": {
+                "null_resource.bar.0": {
+                    "type": "null_resource",
+                    "depends_on": [
+                        "null_resource.baz"
+                    ],
+                    "primary": {
+                        "id": "604776346677326098",
+                        "attributes": {
+                            "id": "604776346677326098",
+                            "triggers.%": "1",
+                            "triggers.index": "0"
+                        },
+                        "meta": {
+                            "schema_version": "1"
+                        },
+                        "tainted": false
+                    },
+                    "deposed": [],
+                    "provider": "provider.null"
+                },
+                "null_resource.bar.1": {
+                    "type": "null_resource",
+                    "depends_on": [
+                        "null_resource.baz"
+                    ],
+                    "primary": {
+                        "id": "4776432143683449212",
+                        "attributes": {
+                            "id": "4776432143683449212",
+                            "triggers.%": "1",
+                            "triggers.index": "1"
+                        },
+                        "meta": {},
+                        "tainted": false
+                    },
+                    "deposed": [],
+                    "provider": "provider.null"
+                },
+                "null_resource.baz": {
+                    "type": "null_resource",
+                    "depends_on": [],
+                    "primary": {
+                        "id": "1361331090091665738",
+                        "attributes": {
+                            "id": "1361331090091665738",
+                            "triggers.%": "9",
+                            "triggers.baz": "BAR",
+                            "triggers.cwd_path": "/home/mart/Devel/terraform/tmp/hcl2-simple",
+                            "triggers.foo": "bar",
+                            "triggers.format": "Hello 12",
+                            "triggers.json": "{\"foo\":\"bar\",\"wonk\":[]}",
+                            "triggers.module_path": "/home/mart/Devel/terraform/tmp/hcl2-simple",
+                            "triggers.root_path": "/home/mart/Devel/terraform/tmp/hcl2-simple",
+                            "triggers.woot": "us-west-2",
+                            "triggers.workspace": "default"
+                        },
+                        "meta": {
+                            "foo": "bar"
+                        },
+                        "tainted": false
+                    },
+                    "deposed": [],
+                    "provider": "provider.null"
+                }
+            },
+            "depends_on": []
+        },
+        {
+            "path": [
+                "root",
+                "child"
+            ],
+            "outputs": {
+                "test": {
+                    "sensitive": false,
+                    "type": "string",
+                    "value": "hello us-west-2"
+                },
+                "test2": {
+                    "sensitive": false,
+                    "type": "string",
+                    "value": "hello world 2"
+                }
+            },
+            "resources": {
+                "null_resource.foo": {
+                    "type": "null_resource",
+                    "depends_on": [],
+                    "primary": {
+                        "id": "1361",
+                        "attributes": {
+                            "id": "1361",
+                            "triggers.%": "0"
+                        },
+                        "meta": {},
+                        "tainted": false
+                    },
+                    "deposed": [],
+                    "provider": "provider.null"
+                }
+            },
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-bigint.out.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-bigint.out.tfstate
new file mode 100644
index 0000000..493fcde
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-bigint.out.tfstate
@@ -0,0 +1,101 @@
+{
+    "version": 4,
+    "terraform_version": "0.11.1",
+    "serial": 8,
+    "lineage": "0f5b2ff9-6ff5-8e9e-1f81-aa3ce9a483eb",
+    "outputs": {
+        "results": {
+            "type": [
+                "map",
+                "string"
+            ],
+            "value": {
+                "aws_region": "us-west-2",
+                "list": "[{\"triggers\":{\"index\":\"0\"}},{\"triggers\":{\"index\":\"1\"}}]",
+                "list_item_0": "{\"triggers\":{\"index\":\"0\"}}",
+                "list_item_1": "{\"triggers\":{\"index\":\"1\"}}",
+                "list_triggers": "[{\"index\":\"0\"},{\"index\":\"1\"}]",
+                "list_triggers_item": "{\"index\":\"0\"}",
+                "module_object": "{\"test\":\"hello us-west-2\",\"test2\":\"hello world 2\"}",
+                "module_output": "hello us-west-2",
+                "single": "{\"triggers\":{\"baz\":\"BAR\",\"cwd_path\":\"/home/mart/Devel/terraform/tmp/hcl2-simple\",\"foo\":\"bar\",\"format\":\"Hello 12\",\"json\":\"{\\\"foo\\\":\\\"bar\\\",\\\"wonk\\\":[]}\",\"module_path\":\"/home/mart/Devel/terraform/tmp/hcl2-simple\",\"root_path\":\"/home/mart/Devel/terraform/tmp/hcl2-simple\",\"woot\":\"us-west-2\",\"workspace\":\"default\"}}"
+            }
+        }
+    },
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "bar",
+            "each": "list",
+            "provider": "provider.null",
+            "instances": [
+                {
+                    "attributes_flat": {
+                        "id": "604776346677326098",
+                        "triggers.%": "1",
+                        "triggers.index": "0"
+                    },
+                    "depends_on": [
+                        "null_resource.baz"
+                    ],
+                    "index_key": 0,
+                    "schema_version": 1
+                },
+                {
+                    "attributes_flat": {
+                        "id": "4776432143683449212",
+                        "triggers.%": "1",
+                        "triggers.index": "1"
+                    },
+                    "depends_on": [
+                        "null_resource.baz"
+                    ],
+                    "index_key": 1,
+                    "schema_version": 0
+                }
+            ]
+        },
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "baz",
+            "provider": "provider.null",
+            "instances": [
+                {
+                    "attributes_flat": {
+                        "id": "1361331090091665738",
+                        "triggers.%": "9",
+                        "triggers.baz": "BAR",
+                        "triggers.cwd_path": "/home/mart/Devel/terraform/tmp/hcl2-simple",
+                        "triggers.foo": "bar",
+                        "triggers.format": "Hello 12",
+                        "triggers.json": "{\"foo\":\"bar\",\"wonk\":[]}",
+                        "triggers.module_path": "/home/mart/Devel/terraform/tmp/hcl2-simple",
+                        "triggers.root_path": "/home/mart/Devel/terraform/tmp/hcl2-simple",
+                        "triggers.woot": "us-west-2",
+                        "triggers.workspace": "default"
+                    },
+                    "schema_version": 0,
+                    "private": "eyJmb28iOiJiYXIifQ=="
+                }
+            ]
+        },
+        {
+            "module": "module.child",
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "foo",
+            "provider": "provider.null",
+            "instances": [
+                {
+                    "attributes_flat": {
+                        "id": "1361",
+                        "triggers.%": "0"
+                    },
+                    "schema_version": 0
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-builtin.in.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-builtin.in.tfstate
new file mode 100644
index 0000000..2e1ea0c
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-builtin.in.tfstate
@@ -0,0 +1,39 @@
+{
+    "version": 3,
+    "terraform_version": "0.11.14",
+    "serial": 1,
+    "lineage": "b707851e-4209-9792-e752-bc0dd6c81fcf",
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {},
+            "resources": {
+                "data.terraform_remote_state.test": {
+                    "type": "terraform_remote_state",
+                    "depends_on": [],
+                    "primary": {
+                        "id": "2020-08-14 19:13:36.875081 +0000 UTC",
+                        "attributes": {
+                            "backend": "remote",
+                            "config.#": "1",
+                            "config.345861710.organization": "hashicorp",
+                            "config.345861710.workspaces.#": "1",
+                            "config.345861710.workspaces.0.%": "1",
+                            "config.345861710.workspaces.0.name": "test",
+                            "environment": "default",
+                            "id": "2020-08-14 19:13:36.875081 +0000 UTC",
+                            "workspace": "default"
+                        },
+                        "meta": {},
+                        "tainted": false
+                    },
+                    "deposed": [],
+                    "provider": "provider.terraform"
+                }
+            },
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-builtin.out.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-builtin.out.tfstate
new file mode 100644
index 0000000..baef969
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-builtin.out.tfstate
@@ -0,0 +1,31 @@
+{
+  "version": 4,
+  "terraform_version": "0.12.28",
+  "serial": 1,
+  "lineage": "b707851e-4209-9792-e752-bc0dd6c81fcf",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "data",
+      "type": "terraform_remote_state",
+      "name": "test",
+      "provider": "provider.terraform",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes_flat": {
+            "backend": "remote",
+            "config.#": "1",
+            "config.345861710.organization": "hashicorp",
+            "config.345861710.workspaces.#": "1",
+            "config.345861710.workspaces.0.%": "1",
+            "config.345861710.workspaces.0.name": "test",
+            "environment": "default",
+            "id": "2020-08-14 19:13:36.875081 +0000 UTC",
+            "workspace": "default"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-grabbag.in.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-grabbag.in.tfstate
new file mode 100644
index 0000000..79b1e75
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-grabbag.in.tfstate
@@ -0,0 +1,133 @@
+{
+    "version": 3,
+    "terraform_version": "0.11.1",
+    "serial": 8,
+    "lineage": "0f5b2ff9-6ff5-8e9e-1f81-aa3ce9a483eb",
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {
+                "results": {
+                    "sensitive": false,
+                    "type": "map",
+                    "value": {
+                        "aws_region": "us-west-2",
+                        "list": "[{\"triggers\":{\"index\":\"0\"}},{\"triggers\":{\"index\":\"1\"}}]",
+                        "list_item_0": "{\"triggers\":{\"index\":\"0\"}}",
+                        "list_item_1": "{\"triggers\":{\"index\":\"1\"}}",
+                        "list_triggers": "[{\"index\":\"0\"},{\"index\":\"1\"}]",
+                        "list_triggers_item": "{\"index\":\"0\"}",
+                        "module_object": "{\"test\":\"hello us-west-2\",\"test2\":\"hello world 2\"}",
+                        "module_output": "hello us-west-2",
+                        "single": "{\"triggers\":{\"baz\":\"BAR\",\"cwd_path\":\"/home/mart/Devel/terraform/tmp/hcl2-simple\",\"foo\":\"bar\",\"format\":\"Hello 12\",\"json\":\"{\\\"foo\\\":\\\"bar\\\",\\\"wonk\\\":[]}\",\"module_path\":\"/home/mart/Devel/terraform/tmp/hcl2-simple\",\"root_path\":\"/home/mart/Devel/terraform/tmp/hcl2-simple\",\"woot\":\"us-west-2\",\"workspace\":\"default\"}}"
+                    }
+                }
+            },
+            "resources": {
+                "null_resource.bar.0": {
+                    "type": "null_resource",
+                    "depends_on": [
+                        "null_resource.baz"
+                    ],
+                    "primary": {
+                        "id": "604776346677326098",
+                        "attributes": {
+                            "id": "604776346677326098",
+                            "triggers.%": "1",
+                            "triggers.index": "0"
+                        },
+                        "meta": {
+                            "schema_version": "1"
+                        },
+                        "tainted": false
+                    },
+                    "deposed": [],
+                    "provider": "provider.null"
+                },
+                "null_resource.bar.1": {
+                    "type": "null_resource",
+                    "depends_on": [
+                        "null_resource.baz"
+                    ],
+                    "primary": {
+                        "id": "4776432143683449212",
+                        "attributes": {
+                            "id": "4776432143683449212",
+                            "triggers.%": "1",
+                            "triggers.index": "1"
+                        },
+                        "meta": {},
+                        "tainted": false
+                    },
+                    "deposed": [],
+                    "provider": "provider.null"
+                },
+                "null_resource.baz": {
+                    "type": "null_resource",
+                    "depends_on": [],
+                    "primary": {
+                        "id": "1361331090091665738",
+                        "attributes": {
+                            "id": "1361331090091665738",
+                            "triggers.%": "9",
+                            "triggers.baz": "BAR",
+                            "triggers.cwd_path": "/home/mart/Devel/terraform/tmp/hcl2-simple",
+                            "triggers.foo": "bar",
+                            "triggers.format": "Hello 12",
+                            "triggers.json": "{\"foo\":\"bar\",\"wonk\":[]}",
+                            "triggers.module_path": "/home/mart/Devel/terraform/tmp/hcl2-simple",
+                            "triggers.root_path": "/home/mart/Devel/terraform/tmp/hcl2-simple",
+                            "triggers.woot": "us-west-2",
+                            "triggers.workspace": "default"
+                        },
+                        "meta": {
+                            "foo": "bar"
+                        },
+                        "tainted": false
+                    },
+                    "deposed": [],
+                    "provider": "provider.null"
+                }
+            },
+            "depends_on": []
+        },
+        {
+            "path": [
+                "root",
+                "child"
+            ],
+            "outputs": {
+                "test": {
+                    "sensitive": false,
+                    "type": "string",
+                    "value": "hello us-west-2"
+                },
+                "test2": {
+                    "sensitive": false,
+                    "type": "string",
+                    "value": "hello world 2"
+                }
+            },
+            "resources": {
+                "null_resource.foo": {
+                    "type": "null_resource",
+                    "depends_on": [],
+                    "primary": {
+                        "id": "1361",
+                        "attributes": {
+                            "id": "1361",
+                            "triggers.%": "0"
+                        },
+                        "meta": {},
+                        "tainted": false
+                    },
+                    "deposed": [],
+                    "provider": "provider.null"
+                }
+            },
+            "depends_on": []
+        }
+    ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-grabbag.out.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-grabbag.out.tfstate
new file mode 100644
index 0000000..493fcde
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-grabbag.out.tfstate
@@ -0,0 +1,101 @@
+{
+    "version": 4,
+    "terraform_version": "0.11.1",
+    "serial": 8,
+    "lineage": "0f5b2ff9-6ff5-8e9e-1f81-aa3ce9a483eb",
+    "outputs": {
+        "results": {
+            "type": [
+                "map",
+                "string"
+            ],
+            "value": {
+                "aws_region": "us-west-2",
+                "list": "[{\"triggers\":{\"index\":\"0\"}},{\"triggers\":{\"index\":\"1\"}}]",
+                "list_item_0": "{\"triggers\":{\"index\":\"0\"}}",
+                "list_item_1": "{\"triggers\":{\"index\":\"1\"}}",
+                "list_triggers": "[{\"index\":\"0\"},{\"index\":\"1\"}]",
+                "list_triggers_item": "{\"index\":\"0\"}",
+                "module_object": "{\"test\":\"hello us-west-2\",\"test2\":\"hello world 2\"}",
+                "module_output": "hello us-west-2",
+                "single": "{\"triggers\":{\"baz\":\"BAR\",\"cwd_path\":\"/home/mart/Devel/terraform/tmp/hcl2-simple\",\"foo\":\"bar\",\"format\":\"Hello 12\",\"json\":\"{\\\"foo\\\":\\\"bar\\\",\\\"wonk\\\":[]}\",\"module_path\":\"/home/mart/Devel/terraform/tmp/hcl2-simple\",\"root_path\":\"/home/mart/Devel/terraform/tmp/hcl2-simple\",\"woot\":\"us-west-2\",\"workspace\":\"default\"}}"
+            }
+        }
+    },
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "bar",
+            "each": "list",
+            "provider": "provider.null",
+            "instances": [
+                {
+                    "attributes_flat": {
+                        "id": "604776346677326098",
+                        "triggers.%": "1",
+                        "triggers.index": "0"
+                    },
+                    "depends_on": [
+                        "null_resource.baz"
+                    ],
+                    "index_key": 0,
+                    "schema_version": 1
+                },
+                {
+                    "attributes_flat": {
+                        "id": "4776432143683449212",
+                        "triggers.%": "1",
+                        "triggers.index": "1"
+                    },
+                    "depends_on": [
+                        "null_resource.baz"
+                    ],
+                    "index_key": 1,
+                    "schema_version": 0
+                }
+            ]
+        },
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "baz",
+            "provider": "provider.null",
+            "instances": [
+                {
+                    "attributes_flat": {
+                        "id": "1361331090091665738",
+                        "triggers.%": "9",
+                        "triggers.baz": "BAR",
+                        "triggers.cwd_path": "/home/mart/Devel/terraform/tmp/hcl2-simple",
+                        "triggers.foo": "bar",
+                        "triggers.format": "Hello 12",
+                        "triggers.json": "{\"foo\":\"bar\",\"wonk\":[]}",
+                        "triggers.module_path": "/home/mart/Devel/terraform/tmp/hcl2-simple",
+                        "triggers.root_path": "/home/mart/Devel/terraform/tmp/hcl2-simple",
+                        "triggers.woot": "us-west-2",
+                        "triggers.workspace": "default"
+                    },
+                    "schema_version": 0,
+                    "private": "eyJmb28iOiJiYXIifQ=="
+                }
+            ]
+        },
+        {
+            "module": "module.child",
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "foo",
+            "provider": "provider.null",
+            "instances": [
+                {
+                    "attributes_flat": {
+                        "id": "1361",
+                        "triggers.%": "0"
+                    },
+                    "schema_version": 0
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-invalid-depends.in.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-invalid-depends.in.tfstate
new file mode 100644
index 0000000..6943b61
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-invalid-depends.in.tfstate
@@ -0,0 +1,42 @@
+{
+    "version": 3,
+    "terraform_version": "0.7.13",
+    "serial": 0,
+    "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04",
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {
+                "numbers": {
+                    "sensitive": false,
+                    "type": "string",
+                    "value": "0,1"
+                }
+            },
+            "resources": {
+                "null_resource.bar": {
+                    "type": "null_resource",
+                    "depends_on": [
+                        "null_resource.valid",
+                        "null_resource.1invalid"
+                    ],
+                    "primary": {
+                        "id": "5388490630832483079",
+                        "attributes": {
+                            "id": "5388490630832483079",
+                            "triggers.%": "1",
+                            "triggers.whaaat": "0,1"
+                        },
+                        "meta": {},
+                        "tainted": false
+                    },
+                    "deposed": [],
+                    "provider": ""
+                }
+            },
+            "depends_on": []
+        }
+    ]
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-invalid-depends.out.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-invalid-depends.out.tfstate
new file mode 100644
index 0000000..9ac170c
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-invalid-depends.out.tfstate
@@ -0,0 +1,33 @@
+{
+    "version": 4,
+    "serial": 0,
+    "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04",
+    "terraform_version": "0.7.13",
+    "outputs": {
+        "numbers": {
+            "type": "string",
+            "value": "0,1"
+        }
+    },
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "bar",
+            "provider": "provider.null",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "5388490630832483079",
+                        "triggers.%": "1",
+                        "triggers.whaaat": "0,1"
+                    },
+                    "depends_on": [
+                        "null_resource.valid"
+                    ]
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-simple.in.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-simple.in.tfstate
new file mode 100644
index 0000000..ec8ceeb
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-simple.in.tfstate
@@ -0,0 +1,91 @@
+{
+    "version": 3,
+    "terraform_version": "0.7.13",
+    "serial": 0,
+    "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04",
+    "modules": [
+        {
+            "path": [
+                "root"
+            ],
+            "outputs": {
+                "numbers": {
+                    "sensitive": false,
+                    "type": "string",
+                    "value": "0,1"
+                }
+            },
+            "resources": {
+                "null_resource.bar": {
+                    "type": "null_resource",
+                    "depends_on": [
+                        "null_resource.foo.*",
+                        "null_resource.foobar",
+                        "null_resource.foobar.1"
+                    ],
+                    "primary": {
+                        "id": "5388490630832483079",
+                        "attributes": {
+                            "id": "5388490630832483079",
+                            "triggers.%": "1",
+                            "triggers.whaaat": "0,1"
+                        },
+                        "meta": {},
+                        "tainted": false
+                    },
+                    "deposed": [],
+                    "provider": ""
+                },
+                "null_resource.foo.0": {
+                    "type": "null_resource",
+                    "depends_on": [],
+                    "primary": {
+                        "id": "8212585058302700791",
+                        "attributes": {
+                            "id": "8212585058302700791",
+                            "triggers.%": "1",
+                            "triggers.what": "0"
+                        },
+                        "meta": {},
+                        "tainted": false
+                    },
+                    "deposed": [],
+                    "provider": ""
+                },
+                "null_resource.foo.1": {
+                    "type": "null_resource",
+                    "depends_on": [],
+                    "primary": {
+                        "id": "1523897709610803586",
+                        "attributes": {
+                            "id": "1523897709610803586",
+                            "triggers.%": "1",
+                            "triggers.what": "1"
+                        },
+                        "meta": {},
+                        "tainted": false
+                    },
+                    "deposed": [],
+                    "provider": ""
+                },
+                "null_resource.foobar": {
+                    "type": "null_resource",
+                    "depends_on": [],
+                    "primary": {
+                        "id": "7388490630832483079",
+                        "attributes": {
+                            "id": "7388490630832483079",
+                            "triggers.%": "1",
+                            "triggers.whaaat": "0,1"
+                        },
+                        "meta": {},
+                        "tainted": false
+                    },
+                    "deposed": [],
+                    "provider": ""
+                }
+            },
+            "depends_on": []
+        }
+    ]
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-simple.out.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-simple.out.tfstate
new file mode 100644
index 0000000..b61661a
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v3-simple.out.tfstate
@@ -0,0 +1,78 @@
+{
+    "version": 4,
+    "serial": 0,
+    "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04",
+    "terraform_version": "0.7.13",
+    "outputs": {
+        "numbers": {
+            "type": "string",
+            "value": "0,1"
+        }
+    },
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "bar",
+            "provider": "provider.null",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "5388490630832483079",
+                        "triggers.%": "1",
+                        "triggers.whaaat": "0,1"
+                    },
+                    "depends_on": [
+                        "null_resource.foo",
+                        "null_resource.foobar",
+                        "null_resource.foobar[1]"
+                    ]
+                }
+            ]
+        },
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "foo",
+            "provider": "provider.null",
+            "each": "list",
+            "instances": [
+                {
+                    "index_key": 0,
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "8212585058302700791",
+                        "triggers.%": "1",
+                        "triggers.what": "0"
+                    }
+                },
+                {
+                    "index_key": 1,
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "1523897709610803586",
+                        "triggers.%": "1",
+                        "triggers.what": "1"
+                    }
+                }
+            ]
+        },
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "foobar",
+            "provider": "provider.null",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "7388490630832483079",
+                        "triggers.%": "1",
+                        "triggers.whaaat": "0,1"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-cbd.in.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-cbd.in.tfstate
new file mode 100644
index 0000000..35186cd
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-cbd.in.tfstate
@@ -0,0 +1,34 @@
+{
+  "version": 4,
+  "serial": 0,
+  "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04",
+  "terraform_version": "0.12.0",
+  "outputs": {
+    "numbers": {
+      "type": "string",
+      "value": "0,1"
+    }
+  },
+  "resources": [
+    {
+      "module": "module.modA",
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "resource",
+      "provider": "provider[\"registry.terraform.io/-/null\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "4639265839606265182",
+            "triggers": {
+              "input": "test"
+            }
+          },
+          "create_before_destroy": true,
+          "private": "bnVsbA=="
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-cbd.out.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-cbd.out.tfstate
new file mode 120000
index 0000000..3831d38
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-cbd.out.tfstate
@@ -0,0 +1 @@
+v4-cbd.in.tfstate
\ No newline at end of file
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-foreach.in.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-foreach.in.tfstate
new file mode 100644
index 0000000..dbca333
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-foreach.in.tfstate
@@ -0,0 +1,36 @@
+{
+  "version": 4,
+  "serial": 0,
+  "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04",
+  "terraform_version": "0.12.0",
+  "outputs": {
+    "numbers": {
+      "type": "string",
+      "value": "0,1"
+    }
+  },
+  "resources": [
+    {
+      "module": "module.modA",
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "resource",
+      "provider": "provider[\"registry.terraform.io/-/null\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "4639265839606265182",
+            "triggers": {
+              "input": "test"
+            }
+          },
+          "private": "bnVsbA==",
+          "depends_on": [
+            "var.input"
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-foreach.out.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-foreach.out.tfstate
new file mode 120000
index 0000000..d35986e
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-foreach.out.tfstate
@@ -0,0 +1 @@
+v4-foreach.in.tfstate
\ No newline at end of file
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-future.in.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-future.in.tfstate
new file mode 100644
index 0000000..71d759b
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-future.in.tfstate
@@ -0,0 +1,60 @@
+{
+    "version": 4,
+    "serial": 0,
+    "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04",
+    "terraform_version": "999.0.0",
+    "outputs": {
+        "numbers": {
+            "type": "string",
+            "value": "0,1"
+        }
+    },
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "bar",
+            "provider": "provider[\"registry.terraform.io/-/null\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "5388490630832483079",
+                        "triggers.%": "1",
+                        "triggers.whaaat": "0,1"
+                    },
+                    "depends_on": [
+                        "null_resource.foo"
+                    ]
+                }
+            ]
+        },
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "foo",
+            "provider": "provider[\"registry.terraform.io/-/null\"]",
+            "each": "list",
+            "instances": [
+                {
+                    "index_key": 0,
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "8212585058302700791",
+                        "triggers.%": "1",
+                        "triggers.what": "0"
+                    }
+                },
+                {
+                    "index_key": 1,
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "1523897709610803586",
+                        "triggers.%": "1",
+                        "triggers.what": "0"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-future.out.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-future.out.tfstate
new file mode 120000
index 0000000..b403737
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-future.out.tfstate
@@ -0,0 +1 @@
+v4-future.in.tfstate
\ No newline at end of file
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-foreach.in.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-foreach.in.tfstate
new file mode 100644
index 0000000..0b5085f
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-foreach.in.tfstate
@@ -0,0 +1,36 @@
+{
+  "version": 4,
+  "serial": 0,
+  "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04",
+  "terraform_version": "0.12.0",
+  "outputs": {
+    "numbers": {
+      "type": "string",
+      "value": "0,1"
+    }
+  },
+  "resources": [
+    {
+      "module": "module.modA",
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "resource",
+      "provider": "provider.null",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "4639265839606265182",
+            "triggers": {
+              "input": "test"
+            }
+          },
+          "private": "bnVsbA==",
+          "depends_on": [
+            "var.input"
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-foreach.out.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-foreach.out.tfstate
new file mode 100644
index 0000000..dbca333
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-foreach.out.tfstate
@@ -0,0 +1,36 @@
+{
+  "version": 4,
+  "serial": 0,
+  "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04",
+  "terraform_version": "0.12.0",
+  "outputs": {
+    "numbers": {
+      "type": "string",
+      "value": "0,1"
+    }
+  },
+  "resources": [
+    {
+      "module": "module.modA",
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "resource",
+      "provider": "provider[\"registry.terraform.io/-/null\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "4639265839606265182",
+            "triggers": {
+              "input": "test"
+            }
+          },
+          "private": "bnVsbA==",
+          "depends_on": [
+            "var.input"
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-modules.in.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-modules.in.tfstate
new file mode 100644
index 0000000..0e892ef
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-modules.in.tfstate
@@ -0,0 +1,88 @@
+{
+  "version": 4,
+  "terraform_version": "0.12.0",
+  "serial": 0,
+  "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04",
+  "outputs": {
+    "numbers": {
+      "value": "0,1",
+      "type": "string"
+    }
+  },
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "bar",
+      "provider": "provider.null",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes_flat": {
+            "id": "5388490630832483079",
+            "triggers.%": "1",
+            "triggers.whaaat": "0,1"
+          },
+          "depends_on": [
+            "null_resource.foo"
+          ]
+        }
+      ]
+    },
+    {
+      "module": "module.modB",
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "bar",
+      "each": "map",
+      "provider": "provider. null",
+      "instances": [
+        {
+          "index_key": "a",
+          "schema_version": 0,
+          "attributes_flat": {
+            "id": "8212585058302700791"
+          },
+          "dependencies": [
+            "module.modA.null_resource.resource"
+          ]
+        },
+        {
+          "index_key": "b",
+          "schema_version": 0,
+          "attributes_flat": {
+            "id": "1523897709610803586"
+          },
+          "dependencies": [
+            "module.modA.null_resource.resource"
+          ]
+        }
+      ]
+    },
+    {
+      "module": "module.modA",
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "resource",
+      "provider": "provider.null",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "4639265839606265182",
+            "triggers": {
+              "input": "test"
+            }
+          },
+          "private": "bnVsbA==",
+          "dependencies": [
+            "null_resource.bar"
+          ],
+          "depends_on": [
+            "var.input"
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-modules.out.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-modules.out.tfstate
new file mode 100644
index 0000000..b9ccd7c
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-modules.out.tfstate
@@ -0,0 +1,88 @@
+{
+  "version": 4,
+  "terraform_version": "0.12.0",
+  "serial": 0,
+  "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04",
+  "outputs": {
+    "numbers": {
+      "value": "0,1",
+      "type": "string"
+    }
+  },
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "bar",
+      "provider": "provider[\"registry.terraform.io/-/null\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes_flat": {
+            "id": "5388490630832483079",
+            "triggers.%": "1",
+            "triggers.whaaat": "0,1"
+          },
+          "depends_on": [
+            "null_resource.foo"
+          ]
+        }
+      ]
+    },
+    {
+      "module": "module.modB",
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "bar",
+      "each": "map",
+      "provider": "provider[\"registry.terraform.io/-/null\"]",
+      "instances": [
+        {
+          "index_key": "a",
+          "schema_version": 0,
+          "attributes_flat": {
+            "id": "8212585058302700791"
+          },
+          "dependencies": [
+            "module.modA.null_resource.resource"
+          ]
+        },
+        {
+          "index_key": "b",
+          "schema_version": 0,
+          "attributes_flat": {
+            "id": "1523897709610803586"
+          },
+          "dependencies": [
+            "module.modA.null_resource.resource"
+          ]
+        }
+      ]
+    },
+    {
+      "module": "module.modA",
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "resource",
+      "provider": "provider[\"registry.terraform.io/-/null\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "4639265839606265182",
+            "triggers": {
+              "input": "test"
+            }
+          },
+          "private": "bnVsbA==",
+          "dependencies": [
+            "null_resource.bar"
+          ],
+          "depends_on": [
+            "var.input"
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-simple.in.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-simple.in.tfstate
new file mode 100644
index 0000000..946c4f8
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-simple.in.tfstate
@@ -0,0 +1,74 @@
+{
+    "version": 4,
+    "serial": 0,
+    "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04",
+    "terraform_version": "0.12.0",
+    "outputs": {
+        "numbers": {
+            "type": "string",
+            "value": "0,1"
+        }
+    },
+    "resources": [
+        {
+            "mode": "data",
+            "type": "terraform_remote_state",
+            "name": "random",
+            "provider": "provider.terraform",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "backend": "remote"
+                    }
+                }
+            ]
+        },
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "bar",
+            "provider": "provider.null",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "5388490630832483079",
+                        "triggers.%": "1",
+                        "triggers.whaaat": "0,1"
+                    },
+                    "depends_on": [
+                        "null_resource.foo"
+                    ]
+                }
+            ]
+        },
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "foo",
+            "provider": "provider.null",
+            "each": "list",
+            "instances": [
+                {
+                    "index_key": 0,
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "8212585058302700791",
+                        "triggers.%": "1",
+                        "triggers.what": "0"
+                    }
+                },
+                {
+                    "index_key": 1,
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "1523897709610803586",
+                        "triggers.%": "1",
+                        "triggers.what": "0"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-simple.out.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-simple.out.tfstate
new file mode 100644
index 0000000..0c19a64
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-legacy-simple.out.tfstate
@@ -0,0 +1,74 @@
+{
+    "version": 4,
+    "serial": 0,
+    "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04",
+    "terraform_version": "0.12.0",
+    "outputs": {
+        "numbers": {
+            "type": "string",
+            "value": "0,1"
+        }
+    },
+    "resources": [
+        {
+            "mode": "data",
+            "type": "terraform_remote_state",
+            "name": "random",
+            "provider": "provider[\"terraform.io/builtin/terraform\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "backend": "remote"
+                    }
+                }
+            ]
+        },
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "bar",
+            "provider": "provider[\"registry.terraform.io/-/null\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "5388490630832483079",
+                        "triggers.%": "1",
+                        "triggers.whaaat": "0,1"
+                    },
+                    "depends_on": [
+                        "null_resource.foo"
+                    ]
+                }
+            ]
+        },
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "foo",
+            "provider": "provider.null",
+            "each": "list",
+            "instances": [
+                {
+                    "index_key": 0,
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "8212585058302700791",
+                        "triggers.%": "1",
+                        "triggers.what": "0"
+                    }
+                },
+                {
+                    "index_key": 1,
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "1523897709610803586",
+                        "triggers.%": "1",
+                        "triggers.what": "0"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-modules.in.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-modules.in.tfstate
new file mode 100644
index 0000000..b9ccd7c
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-modules.in.tfstate
@@ -0,0 +1,88 @@
+{
+  "version": 4,
+  "terraform_version": "0.12.0",
+  "serial": 0,
+  "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04",
+  "outputs": {
+    "numbers": {
+      "value": "0,1",
+      "type": "string"
+    }
+  },
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "bar",
+      "provider": "provider[\"registry.terraform.io/-/null\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes_flat": {
+            "id": "5388490630832483079",
+            "triggers.%": "1",
+            "triggers.whaaat": "0,1"
+          },
+          "depends_on": [
+            "null_resource.foo"
+          ]
+        }
+      ]
+    },
+    {
+      "module": "module.modB",
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "bar",
+      "each": "map",
+      "provider": "provider[\"registry.terraform.io/-/null\"]",
+      "instances": [
+        {
+          "index_key": "a",
+          "schema_version": 0,
+          "attributes_flat": {
+            "id": "8212585058302700791"
+          },
+          "dependencies": [
+            "module.modA.null_resource.resource"
+          ]
+        },
+        {
+          "index_key": "b",
+          "schema_version": 0,
+          "attributes_flat": {
+            "id": "1523897709610803586"
+          },
+          "dependencies": [
+            "module.modA.null_resource.resource"
+          ]
+        }
+      ]
+    },
+    {
+      "module": "module.modA",
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "resource",
+      "provider": "provider[\"registry.terraform.io/-/null\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "4639265839606265182",
+            "triggers": {
+              "input": "test"
+            }
+          },
+          "private": "bnVsbA==",
+          "dependencies": [
+            "null_resource.bar"
+          ],
+          "depends_on": [
+            "var.input"
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-modules.out.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-modules.out.tfstate
new file mode 120000
index 0000000..009f759
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-modules.out.tfstate
@@ -0,0 +1 @@
+v4-modules.in.tfstate
\ No newline at end of file
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-simple.in.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-simple.in.tfstate
new file mode 100644
index 0000000..8d54e6d
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-simple.in.tfstate
@@ -0,0 +1,60 @@
+{
+    "version": 4,
+    "serial": 0,
+    "lineage": "f2968801-fa14-41ab-a044-224f3a4adf04",
+    "terraform_version": "0.12.0",
+    "outputs": {
+        "numbers": {
+            "type": "string",
+            "value": "0,1"
+        }
+    },
+    "resources": [
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "bar",
+            "provider": "provider[\"registry.terraform.io/-/null\"]",
+            "instances": [
+                {
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "5388490630832483079",
+                        "triggers.%": "1",
+                        "triggers.whaaat": "0,1"
+                    },
+                    "depends_on": [
+                        "null_resource.foo"
+                    ]
+                }
+            ]
+        },
+        {
+            "mode": "managed",
+            "type": "null_resource",
+            "name": "foo",
+            "provider": "provider[\"registry.terraform.io/-/null\"]",
+            "each": "list",
+            "instances": [
+                {
+                    "index_key": 0,
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "8212585058302700791",
+                        "triggers.%": "1",
+                        "triggers.what": "0"
+                    }
+                },
+                {
+                    "index_key": 1,
+                    "schema_version": 0,
+                    "attributes_flat": {
+                        "id": "1523897709610803586",
+                        "triggers.%": "1",
+                        "triggers.what": "0"
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-simple.out.tfstate b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-simple.out.tfstate
new file mode 120000
index 0000000..d0e79c3
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/testdata/roundtrip/v4-simple.out.tfstate
@@ -0,0 +1 @@
+v4-simple.in.tfstate
\ No newline at end of file
diff --git a/v1.5.7/internal/states/statefile/version0.go b/v1.5.7/internal/states/statefile/version0.go
new file mode 100644
index 0000000..2cdd0d2
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/version0.go
@@ -0,0 +1,26 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statefile
+
+// looksLikeVersion0 sniffs for the signature indicating a version 0 state
+// file.
+//
+// Version 0 was the number retroactively assigned to Terraform's initial
+// (unversioned) binary state file format, which was later superseded by the
+// version 1 format in JSON.
+//
+// Version 0 is no longer supported, so this is used only to detect it and
+// return a nice error to the user.
+func looksLikeVersion0(src []byte) bool {
+	// Version 0 files begin with the magic prefix "tfstate".
+	const magic = "tfstate"
+	if len(src) < len(magic) {
+		// Not even long enough to have the magic prefix
+		return false
+	}
+	if string(src[0:len(magic)]) == magic {
+		return true
+	}
+	return false
+}
diff --git a/v1.5.7/internal/states/statefile/version1.go b/v1.5.7/internal/states/statefile/version1.go
new file mode 100644
index 0000000..b7d3279
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/version1.go
@@ -0,0 +1,170 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statefile
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func readStateV1(src []byte) (*File, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	sV1 := &stateV1{}
+	err := json.Unmarshal(src, sV1)
+	if err != nil {
+		diags = diags.Append(jsonUnmarshalDiags(err))
+		return nil, diags
+	}
+
+	file, prepDiags := prepareStateV1(sV1)
+	diags = diags.Append(prepDiags)
+	return file, diags
+}
+
+func prepareStateV1(sV1 *stateV1) (*File, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	sV2, err := upgradeStateV1ToV2(sV1)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			upgradeFailed,
+			fmt.Sprintf("Error upgrading state file format from version 1 to version 2: %s.", err),
+		))
+		return nil, diags
+	}
+
+	file, prepDiags := prepareStateV2(sV2)
+	diags = diags.Append(prepDiags)
+	return file, diags
+}
+
+// stateV1 is a representation of the legacy JSON state format version 1.
+//
+// It is only used to read version 1 JSON files prior to upgrading them to
+// the current format.
+type stateV1 struct {
+	// Version is the protocol version. "1" for a StateV1.
+	Version int `json:"version"`
+
+	// Serial is incremented on any operation that modifies
+	// the State file. It is used to detect potentially conflicting
+	// updates.
+	Serial int64 `json:"serial"`
+
+	// Remote is used to track the metadata required to
+	// pull and push state files from a remote storage endpoint.
+	Remote *remoteStateV1 `json:"remote,omitempty"`
+
+	// Modules contains all the modules in a breadth-first order
+	Modules []*moduleStateV1 `json:"modules"`
+}
+
+type remoteStateV1 struct {
+	// Type controls the client we use for the remote state
+	Type string `json:"type"`
+
+	// Config is used to store arbitrary configuration that
+	// is type specific
+	Config map[string]string `json:"config"`
+}
+
+type moduleStateV1 struct {
+	// Path is the import path from the root module. Modules imports are
+	// always disjoint, so the path represents amodule tree
+	Path []string `json:"path"`
+
+	// Outputs declared by the module and maintained for each module
+	// even though only the root module technically needs to be kept.
+	// This allows operators to inspect values at the boundaries.
+	Outputs map[string]string `json:"outputs"`
+
+	// Resources is a mapping of the logically named resource to
+	// the state of the resource. Each resource may actually have
+	// N instances underneath, although a user only needs to think
+	// about the 1:1 case.
+	Resources map[string]*resourceStateV1 `json:"resources"`
+
+	// Dependencies are a list of things that this module relies on
+	// existing to remain intact. For example: an module may depend
+	// on a VPC ID given by an aws_vpc resource.
+	//
+	// Terraform uses this information to build valid destruction
+	// orders and to warn the user if they're destroying a module that
+	// another resource depends on.
+	//
+	// Things can be put into this list that may not be managed by
+	// Terraform. If Terraform doesn't find a matching ID in the
+	// overall state, then it assumes it isn't managed and doesn't
+	// worry about it.
+	Dependencies []string `json:"depends_on,omitempty"`
+}
+
+type resourceStateV1 struct {
+	// This is filled in and managed by Terraform, and is the resource
+	// type itself such as "mycloud_instance". If a resource provider sets
+	// this value, it won't be persisted.
+	Type string `json:"type"`
+
+	// Dependencies are a list of things that this resource relies on
+	// existing to remain intact. For example: an AWS instance might
+	// depend on a subnet (which itself might depend on a VPC, and so
+	// on).
+	//
+	// Terraform uses this information to build valid destruction
+	// orders and to warn the user if they're destroying a resource that
+	// another resource depends on.
+	//
+	// Things can be put into this list that may not be managed by
+	// Terraform. If Terraform doesn't find a matching ID in the
+	// overall state, then it assumes it isn't managed and doesn't
+	// worry about it.
+	Dependencies []string `json:"depends_on,omitempty"`
+
+	// Primary is the current active instance for this resource.
+	// It can be replaced but only after a successful creation.
+	// This is the instances on which providers will act.
+	Primary *instanceStateV1 `json:"primary"`
+
+	// Tainted is used to track any underlying instances that
+	// have been created but are in a bad or unknown state and
+	// need to be cleaned up subsequently.  In the
+	// standard case, there is only at most a single instance.
+	// However, in pathological cases, it is possible for the number
+	// of instances to accumulate.
+	Tainted []*instanceStateV1 `json:"tainted,omitempty"`
+
+	// Deposed is used in the mechanics of CreateBeforeDestroy: the existing
+	// Primary is Deposed to get it out of the way for the replacement Primary to
+	// be created by Apply. If the replacement Primary creates successfully, the
+	// Deposed instance is cleaned up. If there were problems creating the
+	// replacement, the instance remains in the Deposed list so it can be
+	// destroyed in a future run. Functionally, Deposed instances are very
+	// similar to Tainted instances in that Terraform is only tracking them in
+	// order to remember to destroy them.
+	Deposed []*instanceStateV1 `json:"deposed,omitempty"`
+
+	// Provider is used when a resource is connected to a provider with an alias.
+	// If this string is empty, the resource is connected to the default provider,
+	// e.g. "aws_instance" goes with the "aws" provider.
+	// If the resource block contained a "provider" key, that value will be set here.
+	Provider string `json:"provider,omitempty"`
+}
+
+type instanceStateV1 struct {
+	// A unique ID for this resource. This is opaque to Terraform
+	// and is only meant as a lookup mechanism for the providers.
+	ID string `json:"id"`
+
+	// Attributes are basic information about the resource. Any keys here
+	// are accessible in variable format within Terraform configurations:
+	// ${resourcetype.name.attribute}.
+	Attributes map[string]string `json:"attributes,omitempty"`
+
+	// Meta is a simple K/V map that is persisted to the State but otherwise
+	// ignored by Terraform core. It's meant to be used for accounting by
+	// external client code.
+	Meta map[string]string `json:"meta,omitempty"`
+}
diff --git a/v1.5.7/internal/states/statefile/version1_upgrade.go b/v1.5.7/internal/states/statefile/version1_upgrade.go
new file mode 100644
index 0000000..3004f5e
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/version1_upgrade.go
@@ -0,0 +1,175 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statefile
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/mitchellh/copystructure"
+)
+
+// upgradeStateV1ToV2 is used to upgrade a V1 state representation
+// into a V2 state representation
+func upgradeStateV1ToV2(old *stateV1) (*stateV2, error) {
+	log.Printf("[TRACE] statefile.Read: upgrading format from v1 to v2")
+	if old == nil {
+		return nil, nil
+	}
+
+	remote, err := old.Remote.upgradeToV2()
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading State V1: %v", err)
+	}
+
+	modules := make([]*moduleStateV2, len(old.Modules))
+	for i, module := range old.Modules {
+		upgraded, err := module.upgradeToV2()
+		if err != nil {
+			return nil, fmt.Errorf("Error upgrading State V1: %v", err)
+		}
+		modules[i] = upgraded
+	}
+	if len(modules) == 0 {
+		modules = nil
+	}
+
+	newState := &stateV2{
+		Version: 2,
+		Serial:  old.Serial,
+		Remote:  remote,
+		Modules: modules,
+	}
+
+	return newState, nil
+}
+
+func (old *remoteStateV1) upgradeToV2() (*remoteStateV2, error) {
+	if old == nil {
+		return nil, nil
+	}
+
+	config, err := copystructure.Copy(old.Config)
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading RemoteState V1: %v", err)
+	}
+
+	return &remoteStateV2{
+		Type:   old.Type,
+		Config: config.(map[string]string),
+	}, nil
+}
+
+func (old *moduleStateV1) upgradeToV2() (*moduleStateV2, error) {
+	if old == nil {
+		return nil, nil
+	}
+
+	pathRaw, err := copystructure.Copy(old.Path)
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading ModuleState V1: %v", err)
+	}
+	path, ok := pathRaw.([]string)
+	if !ok {
+		return nil, fmt.Errorf("Error upgrading ModuleState V1: path is not a list of strings")
+	}
+	if len(path) == 0 {
+		// We found some V1 states with a nil path. Assume root.
+		path = []string{"root"}
+	}
+
+	// Outputs needs upgrading to use the new structure
+	outputs := make(map[string]*outputStateV2)
+	for key, output := range old.Outputs {
+		outputs[key] = &outputStateV2{
+			Type:      "string",
+			Value:     output,
+			Sensitive: false,
+		}
+	}
+
+	resources := make(map[string]*resourceStateV2)
+	for key, oldResource := range old.Resources {
+		upgraded, err := oldResource.upgradeToV2()
+		if err != nil {
+			return nil, fmt.Errorf("Error upgrading ModuleState V1: %v", err)
+		}
+		resources[key] = upgraded
+	}
+
+	dependencies, err := copystructure.Copy(old.Dependencies)
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading ModuleState V1: %v", err)
+	}
+
+	return &moduleStateV2{
+		Path:         path,
+		Outputs:      outputs,
+		Resources:    resources,
+		Dependencies: dependencies.([]string),
+	}, nil
+}
+
+func (old *resourceStateV1) upgradeToV2() (*resourceStateV2, error) {
+	if old == nil {
+		return nil, nil
+	}
+
+	dependencies, err := copystructure.Copy(old.Dependencies)
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading ResourceState V1: %v", err)
+	}
+
+	primary, err := old.Primary.upgradeToV2()
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading ResourceState V1: %v", err)
+	}
+
+	deposed := make([]*instanceStateV2, len(old.Deposed))
+	for i, v := range old.Deposed {
+		upgraded, err := v.upgradeToV2()
+		if err != nil {
+			return nil, fmt.Errorf("Error upgrading ResourceState V1: %v", err)
+		}
+		deposed[i] = upgraded
+	}
+	if len(deposed) == 0 {
+		deposed = nil
+	}
+
+	return &resourceStateV2{
+		Type:         old.Type,
+		Dependencies: dependencies.([]string),
+		Primary:      primary,
+		Deposed:      deposed,
+		Provider:     old.Provider,
+	}, nil
+}
+
+func (old *instanceStateV1) upgradeToV2() (*instanceStateV2, error) {
+	if old == nil {
+		return nil, nil
+	}
+
+	attributes, err := copystructure.Copy(old.Attributes)
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading InstanceState V1: %v", err)
+	}
+
+	meta, err := copystructure.Copy(old.Meta)
+	if err != nil {
+		return nil, fmt.Errorf("Error upgrading InstanceState V1: %v", err)
+	}
+
+	newMeta := make(map[string]interface{})
+	for k, v := range meta.(map[string]string) {
+		newMeta[k] = v
+	}
+
+	return &instanceStateV2{
+		ID:         old.ID,
+		Attributes: attributes.(map[string]string),
+		Meta:       newMeta,
+	}, nil
+}
diff --git a/v1.5.7/internal/states/statefile/version2.go b/v1.5.7/internal/states/statefile/version2.go
new file mode 100644
index 0000000..0d3907e
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/version2.go
@@ -0,0 +1,207 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statefile
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func readStateV2(src []byte) (*File, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	sV2 := &stateV2{}
+	err := json.Unmarshal(src, sV2)
+	if err != nil {
+		diags = diags.Append(jsonUnmarshalDiags(err))
+		return nil, diags
+	}
+
+	file, prepDiags := prepareStateV2(sV2)
+	diags = diags.Append(prepDiags)
+	return file, diags
+}
+
+func prepareStateV2(sV2 *stateV2) (*File, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	sV3, err := upgradeStateV2ToV3(sV2)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			upgradeFailed,
+			fmt.Sprintf("Error upgrading state file format from version 2 to version 3: %s.", err),
+		))
+		return nil, diags
+	}
+
+	file, prepDiags := prepareStateV3(sV3)
+	diags = diags.Append(prepDiags)
+	return file, diags
+}
+
+// stateV2 is a representation of the legacy JSON state format version 2.
+//
+// It is only used to read version 2 JSON files prior to upgrading them to
+// the current format.
+type stateV2 struct {
+	// Version is the state file protocol version.
+	Version int `json:"version"`
+
+	// TFVersion is the version of Terraform that wrote this state.
+	TFVersion string `json:"terraform_version,omitempty"`
+
+	// Serial is incremented on any operation that modifies
+	// the State file. It is used to detect potentially conflicting
+	// updates.
+	Serial int64 `json:"serial"`
+
+	// Lineage is set when a new, blank state is created and then
+	// never updated. This allows us to determine whether the serials
+	// of two states can be meaningfully compared.
+	// Apart from the guarantee that collisions between two lineages
+	// are very unlikely, this value is opaque and external callers
+	// should only compare lineage strings byte-for-byte for equality.
+	Lineage string `json:"lineage"`
+
+	// Remote is used to track the metadata required to
+	// pull and push state files from a remote storage endpoint.
+	Remote *remoteStateV2 `json:"remote,omitempty"`
+
+	// Backend tracks the configuration for the backend in use with
+	// this state. This is used to track any changes in the backend
+	// configuration.
+	Backend *backendStateV2 `json:"backend,omitempty"`
+
+	// Modules contains all the modules in a breadth-first order
+	Modules []*moduleStateV2 `json:"modules"`
+}
+
+type remoteStateV2 struct {
+	// Type controls the client we use for the remote state
+	Type string `json:"type"`
+
+	// Config is used to store arbitrary configuration that
+	// is type specific
+	Config map[string]string `json:"config"`
+}
+
+type outputStateV2 struct {
+	// Sensitive describes whether the output is considered sensitive,
+	// which may lead to masking the value on screen in some cases.
+	Sensitive bool `json:"sensitive"`
+	// Type describes the structure of Value. Valid values are "string",
+	// "map" and "list"
+	Type string `json:"type"`
+	// Value contains the value of the output, in the structure described
+	// by the Type field.
+	Value interface{} `json:"value"`
+}
+
+type moduleStateV2 struct {
+	// Path is the import path from the root module. Modules imports are
+	// always disjoint, so the path represents amodule tree
+	Path []string `json:"path"`
+
+	// Locals are kept only transiently in-memory, because we can always
+	// re-compute them.
+	Locals map[string]interface{} `json:"-"`
+
+	// Outputs declared by the module and maintained for each module
+	// even though only the root module technically needs to be kept.
+	// This allows operators to inspect values at the boundaries.
+	Outputs map[string]*outputStateV2 `json:"outputs"`
+
+	// Resources is a mapping of the logically named resource to
+	// the state of the resource. Each resource may actually have
+	// N instances underneath, although a user only needs to think
+	// about the 1:1 case.
+	Resources map[string]*resourceStateV2 `json:"resources"`
+
+	// Dependencies are a list of things that this module relies on
+	// existing to remain intact. For example: an module may depend
+	// on a VPC ID given by an aws_vpc resource.
+	//
+	// Terraform uses this information to build valid destruction
+	// orders and to warn the user if they're destroying a module that
+	// another resource depends on.
+	//
+	// Things can be put into this list that may not be managed by
+	// Terraform. If Terraform doesn't find a matching ID in the
+	// overall state, then it assumes it isn't managed and doesn't
+	// worry about it.
+	Dependencies []string `json:"depends_on"`
+}
+
+type resourceStateV2 struct {
+	// This is filled in and managed by Terraform, and is the resource
+	// type itself such as "mycloud_instance". If a resource provider sets
+	// this value, it won't be persisted.
+	Type string `json:"type"`
+
+	// Dependencies are a list of things that this resource relies on
+	// existing to remain intact. For example: an AWS instance might
+	// depend on a subnet (which itself might depend on a VPC, and so
+	// on).
+	//
+	// Terraform uses this information to build valid destruction
+	// orders and to warn the user if they're destroying a resource that
+	// another resource depends on.
+	//
+	// Things can be put into this list that may not be managed by
+	// Terraform. If Terraform doesn't find a matching ID in the
+	// overall state, then it assumes it isn't managed and doesn't
+	// worry about it.
+	Dependencies []string `json:"depends_on"`
+
+	// Primary is the current active instance for this resource.
+	// It can be replaced but only after a successful creation.
+	// This is the instances on which providers will act.
+	Primary *instanceStateV2 `json:"primary"`
+
+	// Deposed is used in the mechanics of CreateBeforeDestroy: the existing
+	// Primary is Deposed to get it out of the way for the replacement Primary to
+	// be created by Apply. If the replacement Primary creates successfully, the
+	// Deposed instance is cleaned up.
+	//
+	// If there were problems creating the replacement Primary, the Deposed
+	// instance and the (now tainted) replacement Primary will be swapped so the
+	// tainted replacement will be cleaned up instead.
+	//
+	// An instance will remain in the Deposed list until it is successfully
+	// destroyed and purged.
+	Deposed []*instanceStateV2 `json:"deposed"`
+
+	// Provider is used when a resource is connected to a provider with an alias.
+	// If this string is empty, the resource is connected to the default provider,
+	// e.g. "aws_instance" goes with the "aws" provider.
+	// If the resource block contained a "provider" key, that value will be set here.
+	Provider string `json:"provider"`
+}
+
+type instanceStateV2 struct {
+	// A unique ID for this resource. This is opaque to Terraform
+	// and is only meant as a lookup mechanism for the providers.
+	ID string `json:"id"`
+
+	// Attributes are basic information about the resource. Any keys here
+	// are accessible in variable format within Terraform configurations:
+	// ${resourcetype.name.attribute}.
+	Attributes map[string]string `json:"attributes"`
+
+	// Meta is a simple K/V map that is persisted to the State but otherwise
+	// ignored by Terraform core. It's meant to be used for accounting by
+	// external client code. The value here must only contain Go primitives
+	// and collections.
+	Meta map[string]interface{} `json:"meta"`
+
+	// Tainted is used to mark a resource for recreation.
+	Tainted bool `json:"tainted"`
+}
+
+type backendStateV2 struct {
+	Type      string          `json:"type"`   // Backend type
+	ConfigRaw json.RawMessage `json:"config"` // Backend raw config
+	Hash      uint64          `json:"hash"`   // Hash of portion of configuration from config files
+}
diff --git a/v1.5.7/internal/states/statefile/version2_upgrade.go b/v1.5.7/internal/states/statefile/version2_upgrade.go
new file mode 100644
index 0000000..3c9e860
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/version2_upgrade.go
@@ -0,0 +1,148 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statefile
+
+import (
+	"fmt"
+	"log"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+
+	"github.com/mitchellh/copystructure"
+)
+
+func upgradeStateV2ToV3(old *stateV2) (*stateV3, error) {
+	if old == nil {
+		return (*stateV3)(nil), nil
+	}
+
+	var new *stateV3
+	{
+		copy, err := copystructure.Config{Lock: true}.Copy(old)
+		if err != nil {
+			panic(err)
+		}
+		newWrongType := copy.(*stateV2)
+		newRightType := (stateV3)(*newWrongType)
+		new = &newRightType
+	}
+
+	// Set the new version number
+	new.Version = 3
+
+	// Change the counts for things which look like maps to use the %
+	// syntax. Remove counts for empty collections - they will be added
+	// back in later.
+	for _, module := range new.Modules {
+		for _, resource := range module.Resources {
+			// Upgrade Primary
+			if resource.Primary != nil {
+				upgradeAttributesV2ToV3(resource.Primary)
+			}
+
+			// Upgrade Deposed
+			for _, deposed := range resource.Deposed {
+				upgradeAttributesV2ToV3(deposed)
+			}
+		}
+	}
+
+	return new, nil
+}
+
+func upgradeAttributesV2ToV3(instanceState *instanceStateV2) error {
+	collectionKeyRegexp := regexp.MustCompile(`^(.*\.)#$`)
+	collectionSubkeyRegexp := regexp.MustCompile(`^([^\.]+)\..*`)
+
+	// Identify the key prefix of anything which is a collection
+	var collectionKeyPrefixes []string
+	for key := range instanceState.Attributes {
+		if submatches := collectionKeyRegexp.FindAllStringSubmatch(key, -1); len(submatches) > 0 {
+			collectionKeyPrefixes = append(collectionKeyPrefixes, submatches[0][1])
+		}
+	}
+	sort.Strings(collectionKeyPrefixes)
+
+	log.Printf("[STATE UPGRADE] Detected the following collections in state: %v", collectionKeyPrefixes)
+
+	// This could be rolled into fewer loops, but it is somewhat clearer this way, and will not
+	// run very often.
+	for _, prefix := range collectionKeyPrefixes {
+		// First get the actual keys that belong to this prefix
+		var potentialKeysMatching []string
+		for key := range instanceState.Attributes {
+			if strings.HasPrefix(key, prefix) {
+				potentialKeysMatching = append(potentialKeysMatching, strings.TrimPrefix(key, prefix))
+			}
+		}
+		sort.Strings(potentialKeysMatching)
+
+		var actualKeysMatching []string
+		for _, key := range potentialKeysMatching {
+			if submatches := collectionSubkeyRegexp.FindAllStringSubmatch(key, -1); len(submatches) > 0 {
+				actualKeysMatching = append(actualKeysMatching, submatches[0][1])
+			} else {
+				if key != "#" {
+					actualKeysMatching = append(actualKeysMatching, key)
+				}
+			}
+		}
+		actualKeysMatching = uniqueSortedStrings(actualKeysMatching)
+
+		// Now inspect the keys in order to determine whether this is most likely to be
+		// a map, list or set. There is room for error here, so we log in each case. If
+		// there is no method of telling, we remove the key from the InstanceState in
+		// order that it will be recreated. Again, this could be rolled into fewer loops
+		// but we prefer clarity.
+
+		oldCountKey := fmt.Sprintf("%s#", prefix)
+
+		// First, detect "obvious" maps - which have non-numeric keys (mostly).
+		hasNonNumericKeys := false
+		for _, key := range actualKeysMatching {
+			if _, err := strconv.Atoi(key); err != nil {
+				hasNonNumericKeys = true
+			}
+		}
+		if hasNonNumericKeys {
+			newCountKey := fmt.Sprintf("%s%%", prefix)
+
+			instanceState.Attributes[newCountKey] = instanceState.Attributes[oldCountKey]
+			delete(instanceState.Attributes, oldCountKey)
+			log.Printf("[STATE UPGRADE] Detected %s as a map. Replaced count = %s",
+				strings.TrimSuffix(prefix, "."), instanceState.Attributes[newCountKey])
+		}
+
+		// Now detect empty collections and remove them from state.
+		if len(actualKeysMatching) == 0 {
+			delete(instanceState.Attributes, oldCountKey)
+			log.Printf("[STATE UPGRADE] Detected %s as an empty collection. Removed from state.",
+				strings.TrimSuffix(prefix, "."))
+		}
+	}
+
+	return nil
+}
+
+// uniqueSortedStrings removes duplicates from a slice of strings and returns
+// a sorted slice of the unique strings.
+func uniqueSortedStrings(input []string) []string {
+	uniquemap := make(map[string]struct{})
+	for _, str := range input {
+		uniquemap[str] = struct{}{}
+	}
+
+	output := make([]string, len(uniquemap))
+
+	i := 0
+	for key := range uniquemap {
+		output[i] = key
+		i = i + 1
+	}
+
+	sort.Strings(output)
+	return output
+}
diff --git a/v1.5.7/internal/states/statefile/version3.go b/v1.5.7/internal/states/statefile/version3.go
new file mode 100644
index 0000000..684ba17
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/version3.go
@@ -0,0 +1,53 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statefile
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func readStateV3(src []byte) (*File, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	sV3 := &stateV3{}
+	err := json.Unmarshal(src, sV3)
+	if err != nil {
+		diags = diags.Append(jsonUnmarshalDiags(err))
+		return nil, diags
+	}
+
+	file, prepDiags := prepareStateV3(sV3)
+	diags = diags.Append(prepDiags)
+	return file, diags
+}
+
+func prepareStateV3(sV3 *stateV3) (*File, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	sV4, err := upgradeStateV3ToV4(sV3)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			upgradeFailed,
+			fmt.Sprintf("Error upgrading state file format from version 3 to version 4: %s.", err),
+		))
+		return nil, diags
+	}
+
+	file, prepDiags := prepareStateV4(sV4)
+	diags = diags.Append(prepDiags)
+	return file, diags
+}
+
+// stateV2 is a representation of the legacy JSON state format version 3.
+//
+// It is only used to read version 3 JSON files prior to upgrading them to
+// the current format.
+//
+// The differences between version 2 and version 3 are only in the data and
+// not in the structure, so stateV3 actually shares the same structs as
+// stateV2. Type stateV3 represents that the data within is formatted as
+// expected by the V3 format, rather than the V2 format.
+type stateV3 stateV2
diff --git a/v1.5.7/internal/states/statefile/version3_upgrade.go b/v1.5.7/internal/states/statefile/version3_upgrade.go
new file mode 100644
index 0000000..f53dffd
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/version3_upgrade.go
@@ -0,0 +1,448 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statefile
+
+import (
+	"encoding/json"
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func upgradeStateV3ToV4(old *stateV3) (*stateV4, error) {
+
+	if old.Serial < 0 {
+		// The new format is using uint64 here, which should be fine for any
+		// real state (we only used positive integers in practice) but we'll
+		// catch this explicitly here to avoid weird behavior if a state file
+		// has been tampered with in some way.
+		return nil, fmt.Errorf("state has serial less than zero, which is invalid")
+	}
+
+	new := &stateV4{
+		TerraformVersion: old.TFVersion,
+		Serial:           uint64(old.Serial),
+		Lineage:          old.Lineage,
+		RootOutputs:      map[string]outputStateV4{},
+		Resources:        []resourceStateV4{},
+	}
+
+	if new.TerraformVersion == "" {
+		// Older formats considered this to be optional, but now it's required
+		// and so we'll stub it out with something that's definitely older
+		// than the version that really created this state.
+		new.TerraformVersion = "0.0.0"
+	}
+
+	for _, msOld := range old.Modules {
+		if len(msOld.Path) < 1 || msOld.Path[0] != "root" {
+			return nil, fmt.Errorf("state contains invalid module path %#v", msOld.Path)
+		}
+
+		// Convert legacy-style module address into our newer address type.
+		// Since these old formats are only generated by versions of Terraform
+		// that don't support count and for_each on modules, we can just assume
+		// all of the modules are unkeyed.
+		moduleAddr := make(addrs.ModuleInstance, len(msOld.Path)-1)
+		for i, name := range msOld.Path[1:] {
+			if !hclsyntax.ValidIdentifier(name) {
+				// If we don't fail here then we'll produce an invalid state
+				// version 4 which subsequent operations will reject, so we'll
+				// fail early here for safety to make sure we can never
+				// inadvertently commit an invalid snapshot to a backend.
+				return nil, fmt.Errorf("state contains invalid module path %#v: %q is not a valid identifier; rename it in Terraform 0.11 before upgrading to Terraform 0.12", msOld.Path, name)
+			}
+			moduleAddr[i] = addrs.ModuleInstanceStep{
+				Name:        name,
+				InstanceKey: addrs.NoKey,
+			}
+		}
+
+		// In a v3 state file, a "resource state" is actually an instance
+		// state, so we need to fill in a missing level of hierarchy here
+		// by lazily creating resource states as we encounter them.
+		// We'll track them in here, keyed on the string representation of
+		// the resource address.
+		resourceStates := map[string]*resourceStateV4{}
+
+		for legacyAddr, rsOld := range msOld.Resources {
+			instAddr, err := parseLegacyResourceAddress(legacyAddr)
+			if err != nil {
+				return nil, err
+			}
+
+			resAddr := instAddr.Resource
+			rs, exists := resourceStates[resAddr.String()]
+			if !exists {
+				var modeStr string
+				switch resAddr.Mode {
+				case addrs.ManagedResourceMode:
+					modeStr = "managed"
+				case addrs.DataResourceMode:
+					modeStr = "data"
+				default:
+					return nil, fmt.Errorf("state contains resource %s with an unsupported resource mode %#v", resAddr, resAddr.Mode)
+				}
+
+				// In state versions prior to 4 we allowed each instance of a
+				// resource to have its own provider configuration address,
+				// which makes no real sense in practice because providers
+				// are associated with resources in the configuration. We
+				// elevate that to the resource level during this upgrade,
+				// implicitly taking the provider address of the first instance
+				// we encounter for each resource. While this is lossy in
+				// theory, in practice there is no reason for these values to
+				// differ between instances.
+				var providerAddr addrs.AbsProviderConfig
+				oldProviderAddr := rsOld.Provider
+				if strings.Contains(oldProviderAddr, "provider.") {
+					// Smells like a new-style provider address, but we'll test it.
+					var diags tfdiags.Diagnostics
+					providerAddr, diags = addrs.ParseLegacyAbsProviderConfigStr(oldProviderAddr)
+					if diags.HasErrors() {
+						if strings.Contains(oldProviderAddr, "${") {
+							// There seems to be a common misconception that
+							// interpolation was valid in provider aliases
+							// in 0.11, so we'll use a specialized error
+							// message for that case.
+							return nil, fmt.Errorf("invalid provider config reference %q for %s: this alias seems to contain a template interpolation sequence, which was not supported but also not error-checked in Terraform 0.11. To proceed, rename the associated provider alias to a valid identifier and apply the change with Terraform 0.11 before upgrading to Terraform 0.12", oldProviderAddr, instAddr)
+						}
+						return nil, fmt.Errorf("invalid provider config reference %q for %s: %s", oldProviderAddr, instAddr, diags.Err())
+					}
+				} else {
+					// Smells like an old-style module-local provider address,
+					// which we'll need to migrate. We'll assume it's referring
+					// to the same module the resource is in, which might be
+					// incorrect but it'll get fixed up next time any updates
+					// are made to an instance.
+					if oldProviderAddr != "" {
+						localAddr, diags := configs.ParseProviderConfigCompactStr(oldProviderAddr)
+						if diags.HasErrors() {
+							if strings.Contains(oldProviderAddr, "${") {
+								// There seems to be a common misconception that
+								// interpolation was valid in provider aliases
+								// in 0.11, so we'll use a specialized error
+								// message for that case.
+								return nil, fmt.Errorf("invalid legacy provider config reference %q for %s: this alias seems to contain a template interpolation sequence, which was not supported but also not error-checked in Terraform 0.11. To proceed, rename the associated provider alias to a valid identifier and apply the change with Terraform 0.11 before upgrading to Terraform 0.12", oldProviderAddr, instAddr)
+							}
+							return nil, fmt.Errorf("invalid legacy provider config reference %q for %s: %s", oldProviderAddr, instAddr, diags.Err())
+						}
+						providerAddr = addrs.AbsProviderConfig{
+							Module: moduleAddr.Module(),
+							// We use NewLegacyProvider here so we can use
+							// LegacyString() below to get the appropriate
+							// legacy-style provider string.
+							Provider: addrs.NewLegacyProvider(localAddr.LocalName),
+							Alias:    localAddr.Alias,
+						}
+					} else {
+						providerAddr = addrs.AbsProviderConfig{
+							Module: moduleAddr.Module(),
+							// We use NewLegacyProvider here so we can use
+							// LegacyString() below to get the appropriate
+							// legacy-style provider string.
+							Provider: addrs.NewLegacyProvider(resAddr.ImpliedProvider()),
+						}
+					}
+				}
+
+				rs = &resourceStateV4{
+					Module:         moduleAddr.String(),
+					Mode:           modeStr,
+					Type:           resAddr.Type,
+					Name:           resAddr.Name,
+					Instances:      []instanceObjectStateV4{},
+					ProviderConfig: providerAddr.LegacyString(),
+				}
+				resourceStates[resAddr.String()] = rs
+			}
+
+			// Now we'll deal with the instance itself, which may either be
+			// the first instance in a resource we just created or an additional
+			// instance for a resource added on a prior loop.
+			instKey := instAddr.Key
+			if isOld := rsOld.Primary; isOld != nil {
+				isNew, err := upgradeInstanceObjectV3ToV4(rsOld, isOld, instKey, states.NotDeposed)
+				if err != nil {
+					return nil, fmt.Errorf("failed to migrate primary generation of %s: %s", instAddr, err)
+				}
+				rs.Instances = append(rs.Instances, *isNew)
+			}
+			for i, isOld := range rsOld.Deposed {
+				// When we migrate old instances we'll use sequential deposed
+				// keys just so that the upgrade result is deterministic. New
+				// deposed keys allocated moving forward will be pseudorandomly
+				// selected, but we check for collisions and so these
+				// non-random ones won't hurt.
+				deposedKey := states.DeposedKey(fmt.Sprintf("%08x", i+1))
+				isNew, err := upgradeInstanceObjectV3ToV4(rsOld, isOld, instKey, deposedKey)
+				if err != nil {
+					return nil, fmt.Errorf("failed to migrate deposed generation index %d of %s: %s", i, instAddr, err)
+				}
+				rs.Instances = append(rs.Instances, *isNew)
+			}
+
+			if instKey != addrs.NoKey && rs.EachMode == "" {
+				rs.EachMode = "list"
+			}
+		}
+
+		for _, rs := range resourceStates {
+			new.Resources = append(new.Resources, *rs)
+		}
+
+		if len(msOld.Path) == 1 && msOld.Path[0] == "root" {
+			// We'll migrate the outputs for this module too, then.
+			for name, oldOS := range msOld.Outputs {
+				newOS := outputStateV4{
+					Sensitive: oldOS.Sensitive,
+				}
+
+				valRaw := oldOS.Value
+				valSrc, err := json.Marshal(valRaw)
+				if err != nil {
+					// Should never happen, because this value came from JSON
+					// in the first place and so we're just round-tripping here.
+					return nil, fmt.Errorf("failed to serialize output %q value as JSON: %s", name, err)
+				}
+
+				// The "type" field in state V2 wasn't really that useful
+				// since it was only able to capture string vs. list vs. map.
+				// For this reason, during upgrade we'll just discard it
+				// altogether and use cty's idea of the implied type of
+				// turning our old value into JSON.
+				ty, err := ctyjson.ImpliedType(valSrc)
+				if err != nil {
+					// REALLY should never happen, because we literally just
+					// encoded this as JSON above!
+					return nil, fmt.Errorf("failed to parse output %q value from JSON: %s", name, err)
+				}
+
+				// ImpliedType tends to produce structural types, but since older
+				// version of Terraform didn't support those a collection type
+				// is probably what was intended, so we'll see if we can
+				// interpret our value as one.
+				ty = simplifyImpliedValueType(ty)
+
+				tySrc, err := ctyjson.MarshalType(ty)
+				if err != nil {
+					return nil, fmt.Errorf("failed to serialize output %q type as JSON: %s", name, err)
+				}
+
+				newOS.ValueRaw = json.RawMessage(valSrc)
+				newOS.ValueTypeRaw = json.RawMessage(tySrc)
+
+				new.RootOutputs[name] = newOS
+			}
+		}
+	}
+
+	new.normalize()
+
+	return new, nil
+}
+
+func upgradeInstanceObjectV3ToV4(rsOld *resourceStateV2, isOld *instanceStateV2, instKey addrs.InstanceKey, deposedKey states.DeposedKey) (*instanceObjectStateV4, error) {
+
+	// Schema versions were, in prior formats, a private concern of the provider
+	// SDK, and not a first-class concept in the state format. Here we're
+	// sniffing for the pre-0.12 SDK's way of representing schema versions
+	// and promoting it to our first-class field if we find it. We'll ignore
+	// it if it doesn't look like what the SDK would've written. If this
+	// sniffing fails then we'll assume schema version 0.
+	var schemaVersion uint64
+	migratedSchemaVersion := false
+	if raw, exists := isOld.Meta["schema_version"]; exists {
+		switch tv := raw.(type) {
+		case string:
+			v, err := strconv.ParseUint(tv, 10, 64)
+			if err == nil {
+				schemaVersion = v
+				migratedSchemaVersion = true
+			}
+		case int:
+			schemaVersion = uint64(tv)
+			migratedSchemaVersion = true
+		case float64:
+			schemaVersion = uint64(tv)
+			migratedSchemaVersion = true
+		}
+	}
+
+	private := map[string]interface{}{}
+	for k, v := range isOld.Meta {
+		if k == "schema_version" && migratedSchemaVersion {
+			// We're gonna promote this into our first-class schema version field
+			continue
+		}
+		private[k] = v
+	}
+	var privateJSON []byte
+	if len(private) != 0 {
+		var err error
+		privateJSON, err = json.Marshal(private)
+		if err != nil {
+			// This shouldn't happen, because the Meta values all came from JSON
+			// originally anyway.
+			return nil, fmt.Errorf("cannot serialize private instance object data: %s", err)
+		}
+	}
+
+	var status string
+	if isOld.Tainted {
+		status = "tainted"
+	}
+
+	var instKeyRaw interface{}
+	switch tk := instKey.(type) {
+	case addrs.IntKey:
+		instKeyRaw = int(tk)
+	case addrs.StringKey:
+		instKeyRaw = string(tk)
+	default:
+		if instKeyRaw != nil {
+			return nil, fmt.Errorf("unsupported instance key: %#v", instKey)
+		}
+	}
+
+	var attributes map[string]string
+	if isOld.Attributes != nil {
+		attributes = make(map[string]string, len(isOld.Attributes))
+		for k, v := range isOld.Attributes {
+			attributes[k] = v
+		}
+	}
+	if isOld.ID != "" {
+		// As a special case, if we don't already have an "id" attribute and
+		// yet there's a non-empty first-class ID on the old object then we'll
+		// create a synthetic id attribute to avoid losing that first-class id.
+		// In practice this generally arises only in tests where state literals
+		// are hand-written in a non-standard way; real code prior to 0.12
+		// would always force the first-class ID to be copied into the
+		// id attribute before storing.
+		if attributes == nil {
+			attributes = make(map[string]string, len(isOld.Attributes))
+		}
+		if idVal := attributes["id"]; idVal == "" {
+			attributes["id"] = isOld.ID
+		}
+	}
+
+	return &instanceObjectStateV4{
+		IndexKey:       instKeyRaw,
+		Status:         status,
+		Deposed:        string(deposedKey),
+		AttributesFlat: attributes,
+		SchemaVersion:  schemaVersion,
+		PrivateRaw:     privateJSON,
+	}, nil
+}
+
+// parseLegacyResourceAddress parses the different identifier format used
+// state formats before version 4, like "instance.name.0".
+func parseLegacyResourceAddress(s string) (addrs.ResourceInstance, error) {
+	var ret addrs.ResourceInstance
+
+	// Split based on ".". Every resource address should have at least two
+	// elements (type and name).
+	parts := strings.Split(s, ".")
+	if len(parts) < 2 || len(parts) > 4 {
+		return ret, fmt.Errorf("invalid internal resource address format: %s", s)
+	}
+
+	// Data resource if we have at least 3 parts and the first one is data
+	ret.Resource.Mode = addrs.ManagedResourceMode
+	if len(parts) > 2 && parts[0] == "data" {
+		ret.Resource.Mode = addrs.DataResourceMode
+		parts = parts[1:]
+	}
+
+	// If we're not a data resource and we have more than 3, then it is an error
+	if len(parts) > 3 && ret.Resource.Mode != addrs.DataResourceMode {
+		return ret, fmt.Errorf("invalid internal resource address format: %s", s)
+	}
+
+	// Build the parts of the resource address that are guaranteed to exist
+	ret.Resource.Type = parts[0]
+	ret.Resource.Name = parts[1]
+	ret.Key = addrs.NoKey
+
+	// If we have more parts, then we have an index. Parse that.
+	if len(parts) > 2 {
+		idx, err := strconv.ParseInt(parts[2], 0, 0)
+		if err != nil {
+			return ret, fmt.Errorf("error parsing resource address %q: %s", s, err)
+		}
+
+		ret.Key = addrs.IntKey(idx)
+	}
+
+	return ret, nil
+}
+
+// simplifyImpliedValueType attempts to heuristically simplify a value type
+// derived from a legacy stored output value into something simpler that
+// is closer to what would've fitted into the pre-v0.12 value type system.
+func simplifyImpliedValueType(ty cty.Type) cty.Type {
+	switch {
+	case ty.IsTupleType():
+		// If all of the element types are the same then we'll make this
+		// a list instead. This is very likely to be true, since prior versions
+		// of Terraform did not officially support mixed-type collections.
+
+		if ty.Equals(cty.EmptyTuple) {
+			// Don't know what the element type would be, then.
+			return ty
+		}
+
+		etys := ty.TupleElementTypes()
+		ety := etys[0]
+		for _, other := range etys[1:] {
+			if !other.Equals(ety) {
+				// inconsistent types
+				return ty
+			}
+		}
+		ety = simplifyImpliedValueType(ety)
+		return cty.List(ety)
+
+	case ty.IsObjectType():
+		// If all of the attribute types are the same then we'll make this
+		// a map instead. This is very likely to be true, since prior versions
+		// of Terraform did not officially support mixed-type collections.
+
+		if ty.Equals(cty.EmptyObject) {
+			// Don't know what the element type would be, then.
+			return ty
+		}
+
+		atys := ty.AttributeTypes()
+		var ety cty.Type
+		for _, other := range atys {
+			if ety == cty.NilType {
+				ety = other
+				continue
+			}
+			if !other.Equals(ety) {
+				// inconsistent types
+				return ty
+			}
+		}
+		ety = simplifyImpliedValueType(ety)
+		return cty.Map(ety)
+
+	default:
+		// No other normalizations are possible
+		return ty
+	}
+}
diff --git a/v1.5.7/internal/states/statefile/version4.go b/v1.5.7/internal/states/statefile/version4.go
new file mode 100644
index 0000000..fe24e48
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/version4.go
@@ -0,0 +1,929 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statefile
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"sort"
+
+	version "github.com/hashicorp/go-version"
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func readStateV4(src []byte) (*File, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	sV4 := &stateV4{}
+	err := json.Unmarshal(src, sV4)
+	if err != nil {
+		diags = diags.Append(jsonUnmarshalDiags(err))
+		return nil, diags
+	}
+
+	file, prepDiags := prepareStateV4(sV4)
+	diags = diags.Append(prepDiags)
+	return file, diags
+}
+
+func prepareStateV4(sV4 *stateV4) (*File, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	var tfVersion *version.Version
+	if sV4.TerraformVersion != "" {
+		var err error
+		tfVersion, err = version.NewVersion(sV4.TerraformVersion)
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid Terraform version string",
+				fmt.Sprintf("State file claims to have been written by Terraform version %q, which is not a valid version string.", sV4.TerraformVersion),
+			))
+		}
+	}
+
+	file := &File{
+		TerraformVersion: tfVersion,
+		Serial:           sV4.Serial,
+		Lineage:          sV4.Lineage,
+	}
+
+	state := states.NewState()
+
+	for _, rsV4 := range sV4.Resources {
+		rAddr := addrs.Resource{
+			Type: rsV4.Type,
+			Name: rsV4.Name,
+		}
+		switch rsV4.Mode {
+		case "managed":
+			rAddr.Mode = addrs.ManagedResourceMode
+		case "data":
+			rAddr.Mode = addrs.DataResourceMode
+		default:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid resource mode in state",
+				fmt.Sprintf("State contains a resource with mode %q (%q %q) which is not supported.", rsV4.Mode, rAddr.Type, rAddr.Name),
+			))
+			continue
+		}
+
+		moduleAddr := addrs.RootModuleInstance
+		if rsV4.Module != "" {
+			var addrDiags tfdiags.Diagnostics
+			moduleAddr, addrDiags = addrs.ParseModuleInstanceStr(rsV4.Module)
+			diags = diags.Append(addrDiags)
+			if addrDiags.HasErrors() {
+				continue
+			}
+		}
+
+		providerAddr, addrDiags := addrs.ParseAbsProviderConfigStr(rsV4.ProviderConfig)
+		diags.Append(addrDiags)
+		if addrDiags.HasErrors() {
+			// If ParseAbsProviderConfigStr returns an error, the state may have
+			// been written before Provider FQNs were introduced and the
+			// AbsProviderConfig string format will need normalization. If so,
+			// we treat it like a legacy provider (namespace "-") and let the
+			// provider installer handle detecting the FQN.
+			var legacyAddrDiags tfdiags.Diagnostics
+			providerAddr, legacyAddrDiags = addrs.ParseLegacyAbsProviderConfigStr(rsV4.ProviderConfig)
+			if legacyAddrDiags.HasErrors() {
+				continue
+			}
+		}
+
+		ms := state.EnsureModule(moduleAddr)
+
+		// Ensure the resource container object is present in the state.
+		ms.SetResourceProvider(rAddr, providerAddr)
+
+		for _, isV4 := range rsV4.Instances {
+			keyRaw := isV4.IndexKey
+			var key addrs.InstanceKey
+			switch tk := keyRaw.(type) {
+			case int:
+				key = addrs.IntKey(tk)
+			case float64:
+				// Since JSON only has one number type, reading from encoding/json
+				// gives us a float64 here even if the number is whole.
+				// float64 has a smaller integer range than int, but in practice
+				// we rarely have more than a few tens of instances and so
+				// it's unlikely that we'll exhaust the 52 bits in a float64.
+				key = addrs.IntKey(int(tk))
+			case string:
+				key = addrs.StringKey(tk)
+			default:
+				if keyRaw != nil {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Invalid resource instance metadata in state",
+						fmt.Sprintf("Resource %s has an instance with the invalid instance key %#v.", rAddr.Absolute(moduleAddr), keyRaw),
+					))
+					continue
+				}
+				key = addrs.NoKey
+			}
+
+			instAddr := rAddr.Instance(key)
+
+			obj := &states.ResourceInstanceObjectSrc{
+				SchemaVersion:       isV4.SchemaVersion,
+				CreateBeforeDestroy: isV4.CreateBeforeDestroy,
+			}
+
+			{
+				// Instance attributes
+				switch {
+				case isV4.AttributesRaw != nil:
+					obj.AttrsJSON = isV4.AttributesRaw
+				case isV4.AttributesFlat != nil:
+					obj.AttrsFlat = isV4.AttributesFlat
+				default:
+					// This is odd, but we'll accept it and just treat the
+					// object has being empty. In practice this should arise
+					// only from the contrived sort of state objects we tend
+					// to hand-write inline in tests.
+					obj.AttrsJSON = []byte{'{', '}'}
+				}
+			}
+
+			// Sensitive paths
+			if isV4.AttributeSensitivePaths != nil {
+				paths, pathsDiags := unmarshalPaths([]byte(isV4.AttributeSensitivePaths))
+				diags = diags.Append(pathsDiags)
+				if pathsDiags.HasErrors() {
+					continue
+				}
+
+				var pvm []cty.PathValueMarks
+				for _, path := range paths {
+					pvm = append(pvm, cty.PathValueMarks{
+						Path:  path,
+						Marks: cty.NewValueMarks(marks.Sensitive),
+					})
+				}
+				obj.AttrSensitivePaths = pvm
+			}
+
+			{
+				// Status
+				raw := isV4.Status
+				switch raw {
+				case "":
+					obj.Status = states.ObjectReady
+				case "tainted":
+					obj.Status = states.ObjectTainted
+				default:
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Invalid resource instance metadata in state",
+						fmt.Sprintf("Instance %s has invalid status %q.", instAddr.Absolute(moduleAddr), raw),
+					))
+					continue
+				}
+			}
+
+			if raw := isV4.PrivateRaw; len(raw) > 0 {
+				obj.Private = raw
+			}
+
+			{
+				depsRaw := isV4.Dependencies
+				deps := make([]addrs.ConfigResource, 0, len(depsRaw))
+				for _, depRaw := range depsRaw {
+					addr, addrDiags := addrs.ParseAbsResourceStr(depRaw)
+					diags = diags.Append(addrDiags)
+					if addrDiags.HasErrors() {
+						continue
+					}
+					deps = append(deps, addr.Config())
+				}
+				obj.Dependencies = deps
+			}
+
+			switch {
+			case isV4.Deposed != "":
+				dk := states.DeposedKey(isV4.Deposed)
+				if len(dk) != 8 {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Invalid resource instance metadata in state",
+						fmt.Sprintf("Instance %s has an object with deposed key %q, which is not correctly formatted.", instAddr.Absolute(moduleAddr), isV4.Deposed),
+					))
+					continue
+				}
+				is := ms.ResourceInstance(instAddr)
+				if is.HasDeposed(dk) {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Duplicate resource instance in state",
+						fmt.Sprintf("Instance %s deposed object %q appears multiple times in the state file.", instAddr.Absolute(moduleAddr), dk),
+					))
+					continue
+				}
+
+				ms.SetResourceInstanceDeposed(instAddr, dk, obj, providerAddr)
+			default:
+				is := ms.ResourceInstance(instAddr)
+				if is.HasCurrent() {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Duplicate resource instance in state",
+						fmt.Sprintf("Instance %s appears multiple times in the state file.", instAddr.Absolute(moduleAddr)),
+					))
+					continue
+				}
+
+				ms.SetResourceInstanceCurrent(instAddr, obj, providerAddr)
+			}
+		}
+
+		// We repeat this after creating the instances because
+		// SetResourceInstanceCurrent automatically resets this metadata based
+		// on the incoming objects. That behavior is useful when we're making
+		// piecemeal updates to the state during an apply, but when we're
+		// reading the state file we want to reflect its contents exactly.
+		ms.SetResourceProvider(rAddr, providerAddr)
+	}
+
+	// The root module is special in that we persist its attributes and thus
+	// need to reload them now. (For descendent modules we just re-calculate
+	// them based on the latest configuration on each run.)
+	{
+		rootModule := state.RootModule()
+		for name, fos := range sV4.RootOutputs {
+			os := &states.OutputValue{
+				Addr: addrs.AbsOutputValue{
+					OutputValue: addrs.OutputValue{
+						Name: name,
+					},
+				},
+			}
+			os.Sensitive = fos.Sensitive
+
+			ty, err := ctyjson.UnmarshalType([]byte(fos.ValueTypeRaw))
+			if err != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid output value type in state",
+					fmt.Sprintf("The state file has an invalid type specification for output %q: %s.", name, err),
+				))
+				continue
+			}
+
+			val, err := ctyjson.Unmarshal([]byte(fos.ValueRaw), ty)
+			if err != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Invalid output value saved in state",
+					fmt.Sprintf("The state file has an invalid value for output %q: %s.", name, err),
+				))
+				continue
+			}
+
+			os.Value = val
+			rootModule.OutputValues[name] = os
+		}
+	}
+
+	// Saved check results from the previous run, if any.
+	// We differentiate absense from an empty array here so that we can
+	// recognize if the previous run was with a version of Terraform that
+	// didn't support checks yet, or if there just weren't any checkable
+	// objects to record, in case that's important for certain messaging.
+	if sV4.CheckResults != nil {
+		var moreDiags tfdiags.Diagnostics
+		state.CheckResults, moreDiags = decodeCheckResultsV4(sV4.CheckResults)
+		diags = diags.Append(moreDiags)
+	}
+
+	file.State = state
+	return file, diags
+}
+
+func writeStateV4(file *File, w io.Writer) tfdiags.Diagnostics {
+	// Here we'll convert back from the "File" representation to our
+	// stateV4 struct representation and write that.
+	//
+	// While we support legacy state formats for reading, we only support the
+	// latest for writing and so if a V5 is added in future then this function
+	// should be deleted and replaced with a writeStateV5, even though the
+	// read/prepare V4 functions above would stick around.
+
+	var diags tfdiags.Diagnostics
+	if file == nil || file.State == nil {
+		panic("attempt to write nil state to file")
+	}
+
+	var terraformVersion string
+	if file.TerraformVersion != nil {
+		terraformVersion = file.TerraformVersion.String()
+	}
+
+	sV4 := &stateV4{
+		TerraformVersion: terraformVersion,
+		Serial:           file.Serial,
+		Lineage:          file.Lineage,
+		RootOutputs:      map[string]outputStateV4{},
+		Resources:        []resourceStateV4{},
+	}
+
+	for name, os := range file.State.RootModule().OutputValues {
+		src, err := ctyjson.Marshal(os.Value, os.Value.Type())
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to serialize output value in state",
+				fmt.Sprintf("An error occured while serializing output value %q: %s.", name, err),
+			))
+			continue
+		}
+
+		typeSrc, err := ctyjson.MarshalType(os.Value.Type())
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to serialize output value in state",
+				fmt.Sprintf("An error occured while serializing the type of output value %q: %s.", name, err),
+			))
+			continue
+		}
+
+		sV4.RootOutputs[name] = outputStateV4{
+			Sensitive:    os.Sensitive,
+			ValueRaw:     json.RawMessage(src),
+			ValueTypeRaw: json.RawMessage(typeSrc),
+		}
+	}
+
+	for _, ms := range file.State.Modules {
+		moduleAddr := ms.Addr
+		for _, rs := range ms.Resources {
+			resourceAddr := rs.Addr.Resource
+
+			var mode string
+			switch resourceAddr.Mode {
+			case addrs.ManagedResourceMode:
+				mode = "managed"
+			case addrs.DataResourceMode:
+				mode = "data"
+			default:
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to serialize resource in state",
+					fmt.Sprintf("Resource %s has mode %s, which cannot be serialized in state", resourceAddr.Absolute(moduleAddr), resourceAddr.Mode),
+				))
+				continue
+			}
+
+			sV4.Resources = append(sV4.Resources, resourceStateV4{
+				Module:         moduleAddr.String(),
+				Mode:           mode,
+				Type:           resourceAddr.Type,
+				Name:           resourceAddr.Name,
+				ProviderConfig: rs.ProviderConfig.String(),
+				Instances:      []instanceObjectStateV4{},
+			})
+			rsV4 := &(sV4.Resources[len(sV4.Resources)-1])
+
+			for key, is := range rs.Instances {
+				if is.HasCurrent() {
+					var objDiags tfdiags.Diagnostics
+					rsV4.Instances, objDiags = appendInstanceObjectStateV4(
+						rs, is, key, is.Current, states.NotDeposed,
+						rsV4.Instances,
+					)
+					diags = diags.Append(objDiags)
+				}
+				for dk, obj := range is.Deposed {
+					var objDiags tfdiags.Diagnostics
+					rsV4.Instances, objDiags = appendInstanceObjectStateV4(
+						rs, is, key, obj, dk,
+						rsV4.Instances,
+					)
+					diags = diags.Append(objDiags)
+				}
+			}
+		}
+	}
+
+	sV4.CheckResults = encodeCheckResultsV4(file.State.CheckResults)
+
+	sV4.normalize()
+
+	src, err := json.MarshalIndent(sV4, "", "  ")
+	if err != nil {
+		// Shouldn't happen if we do our conversion to *stateV4 correctly above.
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to serialize state",
+			fmt.Sprintf("An error occured while serializing the state to save it. This is a bug in Terraform and should be reported: %s.", err),
+		))
+		return diags
+	}
+	src = append(src, '\n')
+
+	_, err = w.Write(src)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to write state",
+			fmt.Sprintf("An error occured while writing the serialized state: %s.", err),
+		))
+		return diags
+	}
+
+	return diags
+}
+
+func appendInstanceObjectStateV4(rs *states.Resource, is *states.ResourceInstance, key addrs.InstanceKey, obj *states.ResourceInstanceObjectSrc, deposed states.DeposedKey, isV4s []instanceObjectStateV4) ([]instanceObjectStateV4, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	var status string
+	switch obj.Status {
+	case states.ObjectReady:
+		status = ""
+	case states.ObjectTainted:
+		status = "tainted"
+	default:
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to serialize resource instance in state",
+			fmt.Sprintf("Instance %s has status %s, which cannot be saved in state.", rs.Addr.Instance(key), obj.Status),
+		))
+	}
+
+	var privateRaw []byte
+	if len(obj.Private) > 0 {
+		privateRaw = obj.Private
+	}
+
+	deps := make([]string, len(obj.Dependencies))
+	for i, depAddr := range obj.Dependencies {
+		deps[i] = depAddr.String()
+	}
+
+	var rawKey interface{}
+	switch tk := key.(type) {
+	case addrs.IntKey:
+		rawKey = int(tk)
+	case addrs.StringKey:
+		rawKey = string(tk)
+	default:
+		if key != addrs.NoKey {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to serialize resource instance in state",
+				fmt.Sprintf("Instance %s has an unsupported instance key: %#v.", rs.Addr.Instance(key), key),
+			))
+		}
+	}
+
+	// Extract paths from path value marks
+	var paths []cty.Path
+	for _, vm := range obj.AttrSensitivePaths {
+		paths = append(paths, vm.Path)
+	}
+
+	// Marshal paths to JSON
+	attributeSensitivePaths, pathsDiags := marshalPaths(paths)
+	diags = diags.Append(pathsDiags)
+
+	return append(isV4s, instanceObjectStateV4{
+		IndexKey:                rawKey,
+		Deposed:                 string(deposed),
+		Status:                  status,
+		SchemaVersion:           obj.SchemaVersion,
+		AttributesFlat:          obj.AttrsFlat,
+		AttributesRaw:           obj.AttrsJSON,
+		AttributeSensitivePaths: attributeSensitivePaths,
+		PrivateRaw:              privateRaw,
+		Dependencies:            deps,
+		CreateBeforeDestroy:     obj.CreateBeforeDestroy,
+	}), diags
+}
+
+func decodeCheckResultsV4(in []checkResultsV4) (*states.CheckResults, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	ret := &states.CheckResults{}
+	if len(in) == 0 {
+		return ret, diags
+	}
+
+	ret.ConfigResults = addrs.MakeMap[addrs.ConfigCheckable, *states.CheckResultAggregate]()
+	for _, aggrIn := range in {
+		objectKind := decodeCheckableObjectKindV4(aggrIn.ObjectKind)
+		if objectKind == addrs.CheckableKindInvalid {
+			// We cannot decode a future unknown check result kind, but
+			// for forwards compatibility we need not treat this as an
+			// error. Eliding unknown check results will not result in
+			// significant data loss and allows us to maintain state file
+			// interoperability in the 1.x series.
+			continue
+		}
+
+		// Some trickiness here: we only have an address parser for
+		// addrs.Checkable and not for addrs.ConfigCheckable, but that's okay
+		// because once we have an addrs.Checkable we can always derive an
+		// addrs.ConfigCheckable from it, and a ConfigCheckable should always
+		// be the same syntax as a Checkable with no index information and
+		// thus we can reuse the same parser for both here.
+		configAddrProxy, moreDiags := addrs.ParseCheckableStr(objectKind, aggrIn.ConfigAddr)
+		diags = diags.Append(moreDiags)
+		if moreDiags.HasErrors() {
+			continue
+		}
+		configAddr := configAddrProxy.ConfigCheckable()
+		if configAddr.String() != configAddrProxy.String() {
+			// This is how we catch if the config address included index
+			// information that would be allowed in a Checkable but not
+			// in a ConfigCheckable.
+			diags = diags.Append(fmt.Errorf("invalid checkable config address %s", aggrIn.ConfigAddr))
+			continue
+		}
+
+		aggr := &states.CheckResultAggregate{
+			Status: decodeCheckStatusV4(aggrIn.Status),
+		}
+
+		if len(aggrIn.Objects) != 0 {
+			aggr.ObjectResults = addrs.MakeMap[addrs.Checkable, *states.CheckResultObject]()
+			for _, objectIn := range aggrIn.Objects {
+				objectAddr, moreDiags := addrs.ParseCheckableStr(objectKind, objectIn.ObjectAddr)
+				diags = diags.Append(moreDiags)
+				if moreDiags.HasErrors() {
+					continue
+				}
+
+				obj := &states.CheckResultObject{
+					Status:          decodeCheckStatusV4(objectIn.Status),
+					FailureMessages: objectIn.FailureMessages,
+				}
+				aggr.ObjectResults.Put(objectAddr, obj)
+			}
+		}
+
+		ret.ConfigResults.Put(configAddr, aggr)
+	}
+
+	return ret, diags
+}
+
+func encodeCheckResultsV4(in *states.CheckResults) []checkResultsV4 {
+	// normalize empty and nil sets in the serialized state
+	if in == nil || in.ConfigResults.Len() == 0 {
+		return nil
+	}
+
+	ret := make([]checkResultsV4, 0, in.ConfigResults.Len())
+
+	for _, configElem := range in.ConfigResults.Elems {
+		configResultsOut := checkResultsV4{
+			ObjectKind: encodeCheckableObjectKindV4(configElem.Key.CheckableKind()),
+			ConfigAddr: configElem.Key.String(),
+			Status:     encodeCheckStatusV4(configElem.Value.Status),
+		}
+		for _, objectElem := range configElem.Value.ObjectResults.Elems {
+			configResultsOut.Objects = append(configResultsOut.Objects, checkResultsObjectV4{
+				ObjectAddr:      objectElem.Key.String(),
+				Status:          encodeCheckStatusV4(objectElem.Value.Status),
+				FailureMessages: objectElem.Value.FailureMessages,
+			})
+		}
+
+		ret = append(ret, configResultsOut)
+	}
+
+	return ret
+}
+
+func decodeCheckStatusV4(in string) checks.Status {
+	switch in {
+	case "pass":
+		return checks.StatusPass
+	case "fail":
+		return checks.StatusFail
+	case "error":
+		return checks.StatusError
+	default:
+		// We'll treat anything else as unknown just as a concession to
+		// forward-compatible parsing, in case a later version of Terraform
+		// introduces a new status.
+		return checks.StatusUnknown
+	}
+}
+
+func encodeCheckStatusV4(in checks.Status) string {
+	switch in {
+	case checks.StatusPass:
+		return "pass"
+	case checks.StatusFail:
+		return "fail"
+	case checks.StatusError:
+		return "error"
+	case checks.StatusUnknown:
+		return "unknown"
+	default:
+		panic(fmt.Sprintf("unsupported check status %s", in))
+	}
+}
+
+func decodeCheckableObjectKindV4(in string) addrs.CheckableKind {
+	switch in {
+	case "resource":
+		return addrs.CheckableResource
+	case "output":
+		return addrs.CheckableOutputValue
+	case "check":
+		return addrs.CheckableCheck
+	default:
+		// We'll treat anything else as invalid just as a concession to
+		// forward-compatible parsing, in case a later version of Terraform
+		// introduces a new status.
+		return addrs.CheckableKindInvalid
+	}
+}
+
+func encodeCheckableObjectKindV4(in addrs.CheckableKind) string {
+	switch in {
+	case addrs.CheckableResource:
+		return "resource"
+	case addrs.CheckableOutputValue:
+		return "output"
+	case addrs.CheckableCheck:
+		return "check"
+	default:
+		panic(fmt.Sprintf("unsupported checkable object kind %s", in))
+	}
+}
+
+type stateV4 struct {
+	Version          stateVersionV4           `json:"version"`
+	TerraformVersion string                   `json:"terraform_version"`
+	Serial           uint64                   `json:"serial"`
+	Lineage          string                   `json:"lineage"`
+	RootOutputs      map[string]outputStateV4 `json:"outputs"`
+	Resources        []resourceStateV4        `json:"resources"`
+	CheckResults     []checkResultsV4         `json:"check_results"`
+}
+
+// normalize makes some in-place changes to normalize the way items are
+// stored to ensure that two functionally-equivalent states will be stored
+// identically.
+func (s *stateV4) normalize() {
+	sort.Stable(sortResourcesV4(s.Resources))
+	for _, rs := range s.Resources {
+		sort.Stable(sortInstancesV4(rs.Instances))
+	}
+}
+
+type outputStateV4 struct {
+	ValueRaw     json.RawMessage `json:"value"`
+	ValueTypeRaw json.RawMessage `json:"type"`
+	Sensitive    bool            `json:"sensitive,omitempty"`
+}
+
+type resourceStateV4 struct {
+	Module         string                  `json:"module,omitempty"`
+	Mode           string                  `json:"mode"`
+	Type           string                  `json:"type"`
+	Name           string                  `json:"name"`
+	EachMode       string                  `json:"each,omitempty"`
+	ProviderConfig string                  `json:"provider"`
+	Instances      []instanceObjectStateV4 `json:"instances"`
+}
+
+type instanceObjectStateV4 struct {
+	IndexKey interface{} `json:"index_key,omitempty"`
+	Status   string      `json:"status,omitempty"`
+	Deposed  string      `json:"deposed,omitempty"`
+
+	SchemaVersion           uint64            `json:"schema_version"`
+	AttributesRaw           json.RawMessage   `json:"attributes,omitempty"`
+	AttributesFlat          map[string]string `json:"attributes_flat,omitempty"`
+	AttributeSensitivePaths json.RawMessage   `json:"sensitive_attributes,omitempty"`
+
+	PrivateRaw []byte `json:"private,omitempty"`
+
+	Dependencies []string `json:"dependencies,omitempty"`
+
+	CreateBeforeDestroy bool `json:"create_before_destroy,omitempty"`
+}
+
+type checkResultsV4 struct {
+	ObjectKind string                 `json:"object_kind"`
+	ConfigAddr string                 `json:"config_addr"`
+	Status     string                 `json:"status"`
+	Objects    []checkResultsObjectV4 `json:"objects"`
+}
+
+type checkResultsObjectV4 struct {
+	ObjectAddr      string   `json:"object_addr"`
+	Status          string   `json:"status"`
+	FailureMessages []string `json:"failure_messages,omitempty"`
+}
+
+// stateVersionV4 is a weird special type we use to produce our hard-coded
+// "version": 4 in the JSON serialization.
+type stateVersionV4 struct{}
+
+func (sv stateVersionV4) MarshalJSON() ([]byte, error) {
+	return []byte{'4'}, nil
+}
+
+func (sv stateVersionV4) UnmarshalJSON([]byte) error {
+	// Nothing to do: we already know we're version 4
+	return nil
+}
+
+type sortResourcesV4 []resourceStateV4
+
+func (sr sortResourcesV4) Len() int      { return len(sr) }
+func (sr sortResourcesV4) Swap(i, j int) { sr[i], sr[j] = sr[j], sr[i] }
+func (sr sortResourcesV4) Less(i, j int) bool {
+	switch {
+	case sr[i].Module != sr[j].Module:
+		return sr[i].Module < sr[j].Module
+	case sr[i].Mode != sr[j].Mode:
+		return sr[i].Mode < sr[j].Mode
+	case sr[i].Type != sr[j].Type:
+		return sr[i].Type < sr[j].Type
+	case sr[i].Name != sr[j].Name:
+		return sr[i].Name < sr[j].Name
+	default:
+		return false
+	}
+}
+
+type sortInstancesV4 []instanceObjectStateV4
+
+func (si sortInstancesV4) Len() int      { return len(si) }
+func (si sortInstancesV4) Swap(i, j int) { si[i], si[j] = si[j], si[i] }
+func (si sortInstancesV4) Less(i, j int) bool {
+	ki := si[i].IndexKey
+	kj := si[j].IndexKey
+	if ki != kj {
+		if (ki == nil) != (kj == nil) {
+			return ki == nil
+		}
+		if kii, isInt := ki.(int); isInt {
+			if kji, isInt := kj.(int); isInt {
+				return kii < kji
+			}
+			return true
+		}
+		if kis, isStr := ki.(string); isStr {
+			if kjs, isStr := kj.(string); isStr {
+				return kis < kjs
+			}
+			return true
+		}
+	}
+	if si[i].Deposed != si[j].Deposed {
+		return si[i].Deposed < si[j].Deposed
+	}
+	return false
+}
+
+// pathStep is an intermediate representation of a cty.PathStep to facilitate
+// consistent JSON serialization. The Value field can either be a cty.Value of
+// dynamic type (for index steps), or a string (for get attr steps).
+type pathStep struct {
+	Type  string          `json:"type"`
+	Value json.RawMessage `json:"value"`
+}
+
+const (
+	indexPathStepType   = "index"
+	getAttrPathStepType = "get_attr"
+)
+
+func unmarshalPaths(buf []byte) ([]cty.Path, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	var jsonPaths [][]pathStep
+
+	err := json.Unmarshal(buf, &jsonPaths)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Error unmarshaling path steps",
+			err.Error(),
+		))
+	}
+
+	paths := make([]cty.Path, 0, len(jsonPaths))
+
+unmarshalOuter:
+	for _, jsonPath := range jsonPaths {
+		var path cty.Path
+		for _, jsonStep := range jsonPath {
+			switch jsonStep.Type {
+			case indexPathStepType:
+				key, err := ctyjson.Unmarshal(jsonStep.Value, cty.DynamicPseudoType)
+				if err != nil {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Error unmarshaling path step",
+						fmt.Sprintf("Failed to unmarshal index step key: %s", err),
+					))
+					continue unmarshalOuter
+				}
+				path = append(path, cty.IndexStep{Key: key})
+			case getAttrPathStepType:
+				var name string
+				if err := json.Unmarshal(jsonStep.Value, &name); err != nil {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Error unmarshaling path step",
+						fmt.Sprintf("Failed to unmarshal get attr step name: %s", err),
+					))
+					continue unmarshalOuter
+				}
+				path = append(path, cty.GetAttrStep{Name: name})
+			default:
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Unsupported path step",
+					fmt.Sprintf("Unsupported path step type %q", jsonStep.Type),
+				))
+				continue unmarshalOuter
+			}
+		}
+		paths = append(paths, path)
+	}
+
+	return paths, diags
+}
+
+func marshalPaths(paths []cty.Path) ([]byte, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// cty.Path is a slice of cty.PathSteps, so our representation of a slice
+	// of paths is a nested slice of our intermediate pathStep struct
+	jsonPaths := make([][]pathStep, 0, len(paths))
+
+marshalOuter:
+	for _, path := range paths {
+		jsonPath := make([]pathStep, 0, len(path))
+		for _, step := range path {
+			var jsonStep pathStep
+			switch s := step.(type) {
+			case cty.IndexStep:
+				key, err := ctyjson.Marshal(s.Key, cty.DynamicPseudoType)
+				if err != nil {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Error marshaling path step",
+						fmt.Sprintf("Failed to marshal index step key %#v: %s", s.Key, err),
+					))
+					continue marshalOuter
+				}
+				jsonStep.Type = indexPathStepType
+				jsonStep.Value = key
+			case cty.GetAttrStep:
+				name, err := json.Marshal(s.Name)
+				if err != nil {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Error marshaling path step",
+						fmt.Sprintf("Failed to marshal get attr step name %s: %s", s.Name, err),
+					))
+					continue marshalOuter
+				}
+				jsonStep.Type = getAttrPathStepType
+				jsonStep.Value = name
+			default:
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Unsupported path step",
+					fmt.Sprintf("Unsupported path step %#v (%t)", step, step),
+				))
+				continue marshalOuter
+			}
+			jsonPath = append(jsonPath, jsonStep)
+		}
+		jsonPaths = append(jsonPaths, jsonPath)
+	}
+
+	buf, err := json.Marshal(jsonPaths)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Error marshaling path steps",
+			fmt.Sprintf("Failed to marshal path steps: %s", err),
+		))
+	}
+
+	return buf, diags
+}
diff --git a/v1.5.7/internal/states/statefile/version4_test.go b/v1.5.7/internal/states/statefile/version4_test.go
new file mode 100644
index 0000000..77b53a3
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/version4_test.go
@@ -0,0 +1,261 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statefile
+
+import (
+	"sort"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// This test verifies that modules are sorted before resources:
+// https://github.com/hashicorp/terraform/issues/21552
+func TestVersion4_sort(t *testing.T) {
+	resources := sortResourcesV4{
+		{
+			Module: "module.child",
+			Type:   "test_instance",
+			Name:   "foo",
+		},
+		{
+			Type: "test_instance",
+			Name: "foo",
+		},
+		{
+			Module: "module.kinder",
+			Type:   "test_instance",
+			Name:   "foo",
+		},
+		{
+			Module: "module.child.grandchild",
+			Type:   "test_instance",
+			Name:   "foo",
+		},
+	}
+	sort.Stable(resources)
+
+	moduleOrder := []string{"", "module.child", "module.child.grandchild", "module.kinder"}
+
+	for i, resource := range resources {
+		if resource.Module != moduleOrder[i] {
+			t.Errorf("wrong sort order: expected %q, got %q\n", moduleOrder[i], resource.Module)
+		}
+	}
+}
+
+func TestVersion4_unmarshalPaths(t *testing.T) {
+	testCases := map[string]struct {
+		json  string
+		paths []cty.Path
+		diags []string
+	}{
+		"no paths": {
+			json:  `[]`,
+			paths: []cty.Path{},
+		},
+		"attribute path": {
+			json: `[
+  [
+    {
+      "type": "get_attr",
+	  "value": "password"
+    }
+  ]
+]`,
+			paths: []cty.Path{cty.GetAttrPath("password")},
+		},
+		"attribute and string index": {
+			json: `[
+  [
+    {
+      "type": "get_attr",
+	  "value": "triggers"
+    },
+    {
+      "type": "index",
+      "value": {
+        "value": "secret",
+		"type": "string"
+      }
+    }
+  ]
+]`,
+			paths: []cty.Path{cty.GetAttrPath("triggers").IndexString("secret")},
+		},
+		"attribute, number index, attribute": {
+			json: `[
+  [
+    {
+      "type": "get_attr",
+	  "value": "identities"
+    },
+    {
+      "type": "index",
+      "value": {
+        "value": 2,
+		"type": "number"
+      }
+    },
+    {
+      "type": "get_attr",
+      "value": "private_key"
+    }
+  ]
+]`,
+			paths: []cty.Path{cty.GetAttrPath("identities").IndexInt(2).GetAttr("private_key")},
+		},
+		"multiple paths": {
+			json: `[
+  [
+    {
+      "type": "get_attr",
+	  "value": "alpha"
+    }
+  ],
+  [
+    {
+      "type": "get_attr",
+	  "value": "beta"
+    }
+  ],
+  [
+    {
+      "type": "get_attr",
+	  "value": "gamma"
+    }
+  ]
+]`,
+			paths: []cty.Path{cty.GetAttrPath("alpha"), cty.GetAttrPath("beta"), cty.GetAttrPath("gamma")},
+		},
+		"errors": {
+			json: `[
+  [
+    {
+      "type": "get_attr",
+	  "value": 5
+    }
+  ],
+  [
+    {
+      "type": "index",
+	  "value": "test"
+    }
+  ],
+  [
+    {
+      "type": "invalid_type",
+	  "value": ["this is invalid too"]
+    }
+  ]
+]`,
+			paths: []cty.Path{},
+			diags: []string{
+				"Failed to unmarshal get attr step name",
+				"Failed to unmarshal index step key",
+				"Unsupported path step",
+			},
+		},
+		"one invalid path, others valid": {
+			json: `[
+  [
+    {
+      "type": "get_attr",
+	  "value": "alpha"
+    }
+  ],
+  [
+    {
+      "type": "invalid_type",
+	  "value": ["this is invalid too"]
+    }
+  ],
+  [
+    {
+      "type": "get_attr",
+	  "value": "gamma"
+    }
+  ]
+]`,
+			paths: []cty.Path{cty.GetAttrPath("alpha"), cty.GetAttrPath("gamma")},
+			diags: []string{"Unsupported path step"},
+		},
+		"invalid structure": {
+			json:  `{}`,
+			paths: []cty.Path{},
+			diags: []string{"Error unmarshaling path steps"},
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			paths, diags := unmarshalPaths([]byte(tc.json))
+
+			if len(tc.diags) == 0 {
+				if len(diags) != 0 {
+					t.Errorf("expected no diags, got: %#v", diags)
+				}
+			} else {
+				if got, want := len(diags), len(tc.diags); got != want {
+					t.Fatalf("got %d diags, want %d\n%s", got, want, diags.Err())
+				}
+				for i := range tc.diags {
+					got := tfdiags.Diagnostics{diags[i]}.Err().Error()
+					if !strings.Contains(got, tc.diags[i]) {
+						t.Errorf("expected diag %d to contain %q, but was:\n%s", i, tc.diags[i], got)
+					}
+				}
+			}
+
+			if len(paths) != len(tc.paths) {
+				t.Fatalf("got %d paths, want %d", len(paths), len(tc.paths))
+			}
+			for i, path := range paths {
+				if !path.Equals(tc.paths[i]) {
+					t.Errorf("wrong paths\n got: %#v\nwant: %#v", path, tc.paths[i])
+				}
+			}
+		})
+	}
+}
+
+func TestVersion4_marshalPaths(t *testing.T) {
+	testCases := map[string]struct {
+		paths []cty.Path
+		json  string
+	}{
+		"no paths": {
+			paths: []cty.Path{},
+			json:  `[]`,
+		},
+		"attribute path": {
+			paths: []cty.Path{cty.GetAttrPath("password")},
+			json:  `[[{"type":"get_attr","value":"password"}]]`,
+		},
+		"attribute, number index, attribute": {
+			paths: []cty.Path{cty.GetAttrPath("identities").IndexInt(2).GetAttr("private_key")},
+			json:  `[[{"type":"get_attr","value":"identities"},{"type":"index","value":{"value":2,"type":"number"}},{"type":"get_attr","value":"private_key"}]]`,
+		},
+		"multiple paths": {
+			paths: []cty.Path{cty.GetAttrPath("a"), cty.GetAttrPath("b"), cty.GetAttrPath("c")},
+			json:  `[[{"type":"get_attr","value":"a"}],[{"type":"get_attr","value":"b"}],[{"type":"get_attr","value":"c"}]]`,
+		},
+	}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			json, diags := marshalPaths(tc.paths)
+
+			if len(diags) != 0 {
+				t.Fatalf("expected no diags, got: %#v", diags)
+			}
+
+			if got, want := string(json), tc.json; got != want {
+				t.Fatalf("wrong JSON output\n got: %s\nwant: %s\n", got, want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/states/statefile/write.go b/v1.5.7/internal/states/statefile/write.go
new file mode 100644
index 0000000..3295a72
--- /dev/null
+++ b/v1.5.7/internal/states/statefile/write.go
@@ -0,0 +1,29 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statefile
+
+import (
+	"io"
+
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+// Write writes the given state to the given writer in the current state
+// serialization format.
+func Write(s *File, w io.Writer) error {
+	// Always record the current terraform version in the state.
+	s.TerraformVersion = tfversion.SemVer
+
+	diags := writeStateV4(s, w)
+	return diags.Err()
+}
+
+// WriteForTest writes the given state to the given writer in the current state
+// serialization format without recording the current terraform version. This is
+// intended for use in tests that need to override the current terraform
+// version.
+func WriteForTest(s *File, w io.Writer) error {
+	diags := writeStateV4(s, w)
+	return diags.Err()
+}
diff --git a/v1.5.7/internal/states/statemgr/doc.go b/v1.5.7/internal/states/statemgr/doc.go
new file mode 100644
index 0000000..b134e40
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/doc.go
@@ -0,0 +1,24 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package statemgr defines the interfaces and some supporting functionality
+// for "state managers", which are components responsible for writing state
+// to some persistent storage and then later retrieving it.
+//
+// State managers will usually (but not necessarily) use the state file formats
+// implemented in the sibling directory "statefile" to serialize the persistent
+// parts of state for storage.
+//
+// State managers are responsible for ensuring that stored state can be updated
+// safely across multiple, possibly-concurrent Terraform runs (with reasonable
+// constraints and limitations). The rest of Terraform considers state to be
+// a mutable data structure, with state managers preserving that illusion
+// by creating snapshots of the state and updating them over time.
+//
+// From the perspective of callers of the general state manager API, a state
+// manager is able to return the latest snapshot and to replace that snapshot
+// with a new one. Some state managers may also preserve historical snapshots
+// using facilities offered by their storage backend, but this is always an
+// implementation detail: the historical versions are not visible to a user
+// of these interfaces.
+package statemgr
diff --git a/v1.5.7/internal/states/statemgr/filesystem.go b/v1.5.7/internal/states/statemgr/filesystem.go
new file mode 100644
index 0000000..bcdeea4
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/filesystem.go
@@ -0,0 +1,534 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"sync"
+	"time"
+
+	multierror "github.com/hashicorp/go-multierror"
+
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// Filesystem is a full state manager that uses a file in the local filesystem
+// for persistent storage.
+//
+// The transient storage for Filesystem is always in-memory.
+type Filesystem struct {
+	mu sync.Mutex
+
+	// path is the location where a file will be created or replaced for
+	// each persistent snapshot.
+	path string
+
+	// readPath is read by RefreshState instead of "path" until the first
+	// call to PersistState, after which it is ignored.
+	//
+	// The file at readPath must never be written to by this manager.
+	readPath string
+
+	// backupPath is an optional extra path which, if non-empty, will be
+	// created or overwritten with the first state snapshot we read if there
+	// is a subsequent call to write a different state.
+	backupPath string
+
+	// the file handle corresponding to PathOut
+	stateFileOut *os.File
+
+	// While the stateFileOut will correspond to the lock directly,
+	// store and check the lock ID to maintain a strict statemgr.Locker
+	// implementation.
+	lockID string
+
+	// created is set to true if stateFileOut didn't exist before we created it.
+	// This is mostly so we can clean up empty files during tests, but doesn't
+	// hurt to remove file we never wrote to.
+	created bool
+
+	file          *statefile.File
+	readFile      *statefile.File
+	backupFile    *statefile.File
+	writtenBackup bool
+}
+
+var (
+	_ Full           = (*Filesystem)(nil)
+	_ PersistentMeta = (*Filesystem)(nil)
+	_ Migrator       = (*Filesystem)(nil)
+)
+
+// NewFilesystem creates a filesystem-based state manager that reads and writes
+// state snapshots at the given filesystem path.
+//
+// This is equivalent to calling NewFileSystemBetweenPaths with statePath as
+// both of the path arguments.
+func NewFilesystem(statePath string) *Filesystem {
+	return &Filesystem{
+		path:     statePath,
+		readPath: statePath,
+	}
+}
+
+// NewFilesystemBetweenPaths creates a filesystem-based state manager that
+// reads an initial snapshot from readPath and then writes all new snapshots to
+// writePath.
+func NewFilesystemBetweenPaths(readPath, writePath string) *Filesystem {
+	return &Filesystem{
+		path:     writePath,
+		readPath: readPath,
+	}
+}
+
+// SetBackupPath configures the receiever so that it will create a local
+// backup file of the next state snapshot it reads (in State) if a different
+// snapshot is subsequently written (in WriteState). Only one backup is
+// written for the lifetime of the object, unless reset as described below.
+//
+// For correct operation, this must be called before any other state methods
+// are called. If called multiple times, each call resets the backup
+// function so that the next read will become the backup snapshot and a
+// following write will save a backup of it.
+func (s *Filesystem) SetBackupPath(path string) {
+	s.backupPath = path
+	s.backupFile = nil
+	s.writtenBackup = false
+}
+
+// BackupPath returns the manager's backup path if backup files are enabled,
+// or an empty string otherwise.
+func (s *Filesystem) BackupPath() string {
+	return s.backupPath
+}
+
+// State is an implementation of Reader.
+func (s *Filesystem) State() *states.State {
+	defer s.mutex()()
+	if s.file == nil {
+		return nil
+	}
+	return s.file.DeepCopy().State
+}
+
+// WriteState is an incorrect implementation of Writer that actually also
+// persists.
+func (s *Filesystem) WriteState(state *states.State) error {
+	// TODO: this should use a more robust method of writing state, by first
+	// writing to a temp file on the same filesystem, and renaming the file over
+	// the original.
+
+	defer s.mutex()()
+
+	if s.readFile == nil {
+		err := s.refreshState()
+		if err != nil {
+			return err
+		}
+	}
+
+	return s.writeState(state, nil)
+}
+
+func (s *Filesystem) writeState(state *states.State, meta *SnapshotMeta) error {
+	if s.stateFileOut == nil {
+		if err := s.createStateFiles(); err != nil {
+			return nil
+		}
+	}
+	defer s.stateFileOut.Sync()
+
+	// We'll try to write our backup first, so we can be sure we've created
+	// it successfully before clobbering the original file it came from.
+	if !s.writtenBackup && s.backupFile != nil && s.backupPath != "" {
+		if !statefile.StatesMarshalEqual(state, s.backupFile.State) {
+			log.Printf("[TRACE] statemgr.Filesystem: creating backup snapshot at %s", s.backupPath)
+			bfh, err := os.Create(s.backupPath)
+			if err != nil {
+				return fmt.Errorf("failed to create local state backup file: %s", err)
+			}
+			defer bfh.Close()
+
+			err = statefile.Write(s.backupFile, bfh)
+			if err != nil {
+				return fmt.Errorf("failed to write to local state backup file: %s", err)
+			}
+
+			s.writtenBackup = true
+		} else {
+			log.Print("[TRACE] statemgr.Filesystem: not making a backup, because the new snapshot is identical to the old")
+		}
+	} else {
+		// This branch is all just logging, to help understand why we didn't make a backup.
+		switch {
+		case s.backupPath == "":
+			log.Print("[TRACE] statemgr.Filesystem: state file backups are disabled")
+		case s.writtenBackup:
+			log.Printf("[TRACE] statemgr.Filesystem: have already backed up original %s to %s on a previous write", s.path, s.backupPath)
+		case s.backupFile == nil:
+			log.Printf("[TRACE] statemgr.Filesystem: no original state snapshot to back up")
+		default:
+			log.Printf("[TRACE] statemgr.Filesystem: not creating a backup for an unknown reason")
+		}
+	}
+
+	s.file = s.file.DeepCopy()
+	if s.file == nil {
+		s.file = NewStateFile()
+	}
+	s.file.State = state.DeepCopy()
+
+	if _, err := s.stateFileOut.Seek(0, io.SeekStart); err != nil {
+		return err
+	}
+	if err := s.stateFileOut.Truncate(0); err != nil {
+		return err
+	}
+
+	if state == nil {
+		// if we have no state, don't write anything else.
+		log.Print("[TRACE] statemgr.Filesystem: state is nil, so leaving the file empty")
+		return nil
+	}
+
+	if meta == nil {
+		if s.readFile == nil || !statefile.StatesMarshalEqual(s.file.State, s.readFile.State) {
+			s.file.Serial++
+			log.Printf("[TRACE] statemgr.Filesystem: state has changed since last snapshot, so incrementing serial to %d", s.file.Serial)
+		} else {
+			log.Print("[TRACE] statemgr.Filesystem: no state changes since last snapshot")
+		}
+	} else {
+		// Force new metadata
+		s.file.Lineage = meta.Lineage
+		s.file.Serial = meta.Serial
+		log.Printf("[TRACE] statemgr.Filesystem: forcing lineage %q serial %d for migration/import", s.file.Lineage, s.file.Serial)
+	}
+
+	log.Printf("[TRACE] statemgr.Filesystem: writing snapshot at %s", s.path)
+	if err := statefile.Write(s.file, s.stateFileOut); err != nil {
+		return err
+	}
+
+	// Any future reads must come from the file we've now updated
+	s.readPath = s.path
+	return nil
+}
+
+// PersistState is an implementation of Persister that does nothing because
+// this type's Writer implementation does its own persistence.
+func (s *Filesystem) PersistState(schemas *terraform.Schemas) error {
+	return nil
+}
+
+// RefreshState is an implementation of Refresher.
+func (s *Filesystem) RefreshState() error {
+	defer s.mutex()()
+	return s.refreshState()
+}
+
+func (s *Filesystem) GetRootOutputValues() (map[string]*states.OutputValue, error) {
+	err := s.RefreshState()
+	if err != nil {
+		return nil, err
+	}
+
+	state := s.State()
+	if state == nil {
+		state = states.NewState()
+	}
+
+	return state.RootModule().OutputValues, nil
+}
+
+func (s *Filesystem) refreshState() error {
+	var reader io.Reader
+
+	// The s.readPath file is only OK to read if we have not written any state out
+	// (in which case the same state needs to be read in), and no state output file
+	// has been opened (possibly via a lock) or the input path is different
+	// than the output path.
+	// This is important for Windows, as if the input file is the same as the
+	// output file, and the output file has been locked already, we can't open
+	// the file again.
+	if s.stateFileOut == nil || s.readPath != s.path {
+		// we haven't written a state file yet, so load from readPath
+		log.Printf("[TRACE] statemgr.Filesystem: reading initial snapshot from %s", s.readPath)
+		f, err := os.Open(s.readPath)
+		if err != nil {
+			// It is okay if the file doesn't exist; we'll treat that as a nil state.
+			if !os.IsNotExist(err) {
+				return err
+			}
+
+			// we need a non-nil reader for ReadState and an empty buffer works
+			// to return EOF immediately
+			reader = bytes.NewBuffer(nil)
+
+		} else {
+			defer f.Close()
+			reader = f
+		}
+	} else {
+		log.Printf("[TRACE] statemgr.Filesystem: reading latest snapshot from %s", s.path)
+		// no state to refresh
+		if s.stateFileOut == nil {
+			return nil
+		}
+
+		// we have a state file, make sure we're at the start
+		s.stateFileOut.Seek(0, io.SeekStart)
+		reader = s.stateFileOut
+	}
+
+	f, err := statefile.Read(reader)
+	// if there's no state then a nil file is fine
+	if err != nil {
+		if err != statefile.ErrNoState {
+			return err
+		}
+		log.Printf("[TRACE] statemgr.Filesystem: snapshot file has nil snapshot, but that's okay")
+	}
+
+	s.file = f
+	s.readFile = s.file.DeepCopy()
+	if s.file != nil {
+		log.Printf("[TRACE] statemgr.Filesystem: read snapshot with lineage %q serial %d", s.file.Lineage, s.file.Serial)
+	} else {
+		log.Print("[TRACE] statemgr.Filesystem: read nil snapshot")
+	}
+	return nil
+}
+
+// Lock implements Locker using filesystem discretionary locks.
+func (s *Filesystem) Lock(info *LockInfo) (string, error) {
+	defer s.mutex()()
+
+	if s.stateFileOut == nil {
+		if err := s.createStateFiles(); err != nil {
+			return "", err
+		}
+	}
+
+	if s.lockID != "" {
+		return "", fmt.Errorf("state %q already locked", s.stateFileOut.Name())
+	}
+
+	if err := s.lock(); err != nil {
+		info, infoErr := s.lockInfo()
+		if infoErr != nil {
+			err = multierror.Append(err, infoErr)
+		}
+
+		lockErr := &LockError{
+			Info: info,
+			Err:  err,
+		}
+
+		return "", lockErr
+	}
+
+	s.lockID = info.ID
+	return s.lockID, s.writeLockInfo(info)
+}
+
+// Unlock is the companion to Lock, completing the implemention of Locker.
+func (s *Filesystem) Unlock(id string) error {
+	defer s.mutex()()
+
+	if s.lockID == "" {
+		return fmt.Errorf("LocalState not locked")
+	}
+
+	if id != s.lockID {
+		idErr := fmt.Errorf("invalid lock id: %q. current id: %q", id, s.lockID)
+		info, err := s.lockInfo()
+		if err != nil {
+			idErr = multierror.Append(idErr, err)
+		}
+
+		return &LockError{
+			Err:  idErr,
+			Info: info,
+		}
+	}
+
+	lockInfoPath := s.lockInfoPath()
+	log.Printf("[TRACE] statemgr.Filesystem: removing lock metadata file %s", lockInfoPath)
+	os.Remove(lockInfoPath)
+
+	fileName := s.stateFileOut.Name()
+
+	unlockErr := s.unlock()
+
+	s.stateFileOut.Close()
+	s.stateFileOut = nil
+	s.lockID = ""
+
+	// clean up the state file if we created it an never wrote to it
+	stat, err := os.Stat(fileName)
+	if err == nil && stat.Size() == 0 && s.created {
+		os.Remove(fileName)
+	}
+
+	return unlockErr
+}
+
+// StateSnapshotMeta returns the metadata from the most recently persisted
+// or refreshed persistent state snapshot.
+//
+// This is an implementation of PersistentMeta.
+func (s *Filesystem) StateSnapshotMeta() SnapshotMeta {
+	if s.file == nil {
+		return SnapshotMeta{} // placeholder
+	}
+
+	return SnapshotMeta{
+		Lineage: s.file.Lineage,
+		Serial:  s.file.Serial,
+
+		TerraformVersion: s.file.TerraformVersion,
+	}
+}
+
+// StateForMigration is part of our implementation of Migrator.
+func (s *Filesystem) StateForMigration() *statefile.File {
+	return s.file.DeepCopy()
+}
+
+// WriteStateForMigration is part of our implementation of Migrator.
+func (s *Filesystem) WriteStateForMigration(f *statefile.File, force bool) error {
+	defer s.mutex()()
+
+	if s.readFile == nil {
+		err := s.refreshState()
+		if err != nil {
+			return err
+		}
+	}
+
+	if !force {
+		err := CheckValidImport(f, s.readFile)
+		if err != nil {
+			return err
+		}
+	}
+
+	if s.readFile != nil {
+		log.Printf(
+			"[TRACE] statemgr.Filesystem: Importing snapshot with lineage %q serial %d over snapshot with lineage %q serial %d at %s",
+			f.Lineage, f.Serial,
+			s.readFile.Lineage, s.readFile.Serial,
+			s.path,
+		)
+	} else {
+		log.Printf(
+			"[TRACE] statemgr.Filesystem: Importing snapshot with lineage %q serial %d as the initial state snapshot at %s",
+			f.Lineage, f.Serial,
+			s.path,
+		)
+	}
+
+	err := s.writeState(f.State, &SnapshotMeta{Lineage: f.Lineage, Serial: f.Serial})
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Open the state file, creating the directories and file as needed.
+func (s *Filesystem) createStateFiles() error {
+	log.Printf("[TRACE] statemgr.Filesystem: preparing to manage state snapshots at %s", s.path)
+
+	// This could race, but we only use it to clean up empty files
+	if _, err := os.Stat(s.path); os.IsNotExist(err) {
+		s.created = true
+	}
+
+	// Create all the directories
+	if err := os.MkdirAll(filepath.Dir(s.path), 0755); err != nil {
+		return err
+	}
+
+	f, err := os.OpenFile(s.path, os.O_RDWR|os.O_CREATE, 0666)
+	if err != nil {
+		return err
+	}
+
+	s.stateFileOut = f
+
+	// If the file already existed with content then that'll be the content
+	// of our backup file if we write a change later.
+	s.backupFile, err = statefile.Read(s.stateFileOut)
+	if err != nil {
+		if err != statefile.ErrNoState {
+			return err
+		}
+		log.Printf("[TRACE] statemgr.Filesystem: no previously-stored snapshot exists")
+	} else {
+		log.Printf("[TRACE] statemgr.Filesystem: existing snapshot has lineage %q serial %d", s.backupFile.Lineage, s.backupFile.Serial)
+	}
+
+	// Refresh now, to load in the snapshot if the file already existed
+	return nil
+}
+
+// return the path for the lockInfo metadata.
+func (s *Filesystem) lockInfoPath() string {
+	stateDir, stateName := filepath.Split(s.path)
+	if stateName == "" {
+		panic("empty state file path")
+	}
+
+	if stateName[0] == '.' {
+		stateName = stateName[1:]
+	}
+
+	return filepath.Join(stateDir, fmt.Sprintf(".%s.lock.info", stateName))
+}
+
+// lockInfo returns the data in a lock info file
+func (s *Filesystem) lockInfo() (*LockInfo, error) {
+	path := s.lockInfoPath()
+	infoData, err := ioutil.ReadFile(path)
+	if err != nil {
+		return nil, err
+	}
+
+	info := LockInfo{}
+	err = json.Unmarshal(infoData, &info)
+	if err != nil {
+		return nil, fmt.Errorf("state file %q locked, but could not unmarshal lock info: %s", s.readPath, err)
+	}
+	return &info, nil
+}
+
+// write a new lock info file
+func (s *Filesystem) writeLockInfo(info *LockInfo) error {
+	path := s.lockInfoPath()
+	info.Path = s.readPath
+	info.Created = time.Now().UTC()
+
+	log.Printf("[TRACE] statemgr.Filesystem: writing lock metadata to %s", path)
+	err := ioutil.WriteFile(path, info.Marshal(), 0600)
+	if err != nil {
+		return fmt.Errorf("could not write lock info for %q: %s", s.readPath, err)
+	}
+	return nil
+}
+
+func (s *Filesystem) mutex() func() {
+	s.mu.Lock()
+	return s.mu.Unlock
+}
diff --git a/v1.5.7/internal/states/statemgr/filesystem_lock_unix.go b/v1.5.7/internal/states/statemgr/filesystem_lock_unix.go
new file mode 100644
index 0000000..35df87e
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/filesystem_lock_unix.go
@@ -0,0 +1,41 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build !windows
+// +build !windows
+
+package statemgr
+
+import (
+	"io"
+	"log"
+	"syscall"
+)
+
+// use fcntl POSIX locks for the most consistent behavior across platforms, and
+// hopefully some campatibility over NFS and CIFS.
+func (s *Filesystem) lock() error {
+	log.Printf("[TRACE] statemgr.Filesystem: locking %s using fcntl flock", s.path)
+	flock := &syscall.Flock_t{
+		Type:   syscall.F_RDLCK | syscall.F_WRLCK,
+		Whence: int16(io.SeekStart),
+		Start:  0,
+		Len:    0,
+	}
+
+	fd := s.stateFileOut.Fd()
+	return syscall.FcntlFlock(fd, syscall.F_SETLK, flock)
+}
+
+func (s *Filesystem) unlock() error {
+	log.Printf("[TRACE] statemgr.Filesystem: unlocking %s using fcntl flock", s.path)
+	flock := &syscall.Flock_t{
+		Type:   syscall.F_UNLCK,
+		Whence: int16(io.SeekStart),
+		Start:  0,
+		Len:    0,
+	}
+
+	fd := s.stateFileOut.Fd()
+	return syscall.FcntlFlock(fd, syscall.F_SETLK, flock)
+}
diff --git a/v1.5.7/internal/states/statemgr/filesystem_lock_windows.go b/v1.5.7/internal/states/statemgr/filesystem_lock_windows.go
new file mode 100644
index 0000000..da6cab8
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/filesystem_lock_windows.go
@@ -0,0 +1,117 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build windows
+// +build windows
+
+package statemgr
+
+import (
+	"log"
+	"math"
+	"syscall"
+	"unsafe"
+)
+
+var (
+	modkernel32      = syscall.NewLazyDLL("kernel32.dll")
+	procLockFileEx   = modkernel32.NewProc("LockFileEx")
+	procCreateEventW = modkernel32.NewProc("CreateEventW")
+)
+
+const (
+	// dwFlags defined for LockFileEx
+	// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
+	_LOCKFILE_FAIL_IMMEDIATELY = 1
+	_LOCKFILE_EXCLUSIVE_LOCK   = 2
+)
+
+func (s *Filesystem) lock() error {
+	log.Printf("[TRACE] statemgr.Filesystem: locking %s using LockFileEx", s.path)
+
+	// even though we're failing immediately, an overlapped event structure is
+	// required
+	ol, err := newOverlapped()
+	if err != nil {
+		return err
+	}
+	defer syscall.CloseHandle(ol.HEvent)
+
+	return lockFileEx(
+		syscall.Handle(s.stateFileOut.Fd()),
+		_LOCKFILE_EXCLUSIVE_LOCK|_LOCKFILE_FAIL_IMMEDIATELY,
+		0,              // reserved
+		0,              // bytes low
+		math.MaxUint32, // bytes high
+		ol,
+	)
+}
+
+func (s *Filesystem) unlock() error {
+	log.Printf("[TRACE] statemgr.Filesystem: unlocked by closing %s", s.path)
+
+	// the file is closed in Unlock
+	return nil
+}
+
+func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
+	r1, _, e1 := syscall.Syscall6(
+		procLockFileEx.Addr(),
+		6,
+		uintptr(h),
+		uintptr(flags),
+		uintptr(reserved),
+		uintptr(locklow),
+		uintptr(lockhigh),
+		uintptr(unsafe.Pointer(ol)),
+	)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+// newOverlapped creates a structure used to track asynchronous
+// I/O requests that have been issued.
+func newOverlapped() (*syscall.Overlapped, error) {
+	event, err := createEvent(nil, true, false, nil)
+	if err != nil {
+		return nil, err
+	}
+	return &syscall.Overlapped{HEvent: event}, nil
+}
+
+func createEvent(sa *syscall.SecurityAttributes, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) {
+	var _p0 uint32
+	if manualReset {
+		_p0 = 1
+	}
+	var _p1 uint32
+	if initialState {
+		_p1 = 1
+	}
+
+	r0, _, e1 := syscall.Syscall6(
+		procCreateEventW.Addr(),
+		4,
+		uintptr(unsafe.Pointer(sa)),
+		uintptr(_p0),
+		uintptr(_p1),
+		uintptr(unsafe.Pointer(name)),
+		0,
+		0,
+	)
+	handle = syscall.Handle(r0)
+	if handle == syscall.InvalidHandle {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
diff --git a/v1.5.7/internal/states/statemgr/filesystem_test.go b/v1.5.7/internal/states/statemgr/filesystem_test.go
new file mode 100644
index 0000000..8e456e5
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/filesystem_test.go
@@ -0,0 +1,456 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+import (
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+	"sync"
+	"testing"
+
+	"github.com/go-test/deep"
+	version "github.com/hashicorp/go-version"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	tfversion "github.com/hashicorp/terraform/version"
+)
+
+func TestFilesystem(t *testing.T) {
+	defer testOverrideVersion(t, "1.2.3")()
+	ls := testFilesystem(t)
+	defer os.Remove(ls.readPath)
+	TestFull(t, ls)
+}
+
+func TestFilesystemRace(t *testing.T) {
+	defer testOverrideVersion(t, "1.2.3")()
+	ls := testFilesystem(t)
+	defer os.Remove(ls.readPath)
+
+	current := TestFullInitialState()
+
+	var wg sync.WaitGroup
+	for i := 0; i < 100; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			ls.WriteState(current)
+		}()
+	}
+	wg.Wait()
+}
+
+func TestFilesystemLocks(t *testing.T) {
+	defer testOverrideVersion(t, "1.2.3")()
+	s := testFilesystem(t)
+	defer os.Remove(s.readPath)
+
+	// lock first
+	info := NewLockInfo()
+	info.Operation = "test"
+	lockID, err := s.Lock(info)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	out, err := exec.Command("go", "run", "testdata/lockstate.go", s.path).CombinedOutput()
+	if err != nil {
+		t.Fatal("unexpected lock failure", err, string(out))
+	}
+
+	if !strings.Contains(string(out), "lock failed") {
+		t.Fatal("expected 'locked failed', got", string(out))
+	}
+
+	// check our lock info
+	lockInfo, err := s.lockInfo()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if lockInfo.Operation != "test" {
+		t.Fatalf("invalid lock info %#v\n", lockInfo)
+	}
+
+	// a noop, since we unlock on exit
+	if err := s.Unlock(lockID); err != nil {
+		t.Fatal(err)
+	}
+
+	// local locks can re-lock
+	lockID, err = s.Lock(info)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := s.Unlock(lockID); err != nil {
+		t.Fatal(err)
+	}
+
+	// we should not be able to unlock the same lock twice
+	if err := s.Unlock(lockID); err == nil {
+		t.Fatal("unlocking an unlocked state should fail")
+	}
+
+	// make sure lock info is gone
+	lockInfoPath := s.lockInfoPath()
+	if _, err := os.Stat(lockInfoPath); !os.IsNotExist(err) {
+		t.Fatal("lock info not removed")
+	}
+}
+
+// Verify that we can write to the state file, as Windows' mandatory locking
+// will prevent writing to a handle different than the one that hold the lock.
+func TestFilesystem_writeWhileLocked(t *testing.T) {
+	defer testOverrideVersion(t, "1.2.3")()
+	s := testFilesystem(t)
+	defer os.Remove(s.readPath)
+
+	// lock first
+	info := NewLockInfo()
+	info.Operation = "test"
+	lockID, err := s.Lock(info)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		if err := s.Unlock(lockID); err != nil {
+			t.Fatal(err)
+		}
+	}()
+
+	if err := s.WriteState(TestFullInitialState()); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestFilesystem_pathOut(t *testing.T) {
+	defer testOverrideVersion(t, "1.2.3")()
+	f, err := ioutil.TempFile("", "tf")
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	f.Close()
+	defer os.Remove(f.Name())
+
+	ls := testFilesystem(t)
+	ls.path = f.Name()
+	defer os.Remove(ls.path)
+
+	TestFull(t, ls)
+}
+
+func TestFilesystem_backup(t *testing.T) {
+	defer testOverrideVersion(t, "1.2.3")()
+	f, err := ioutil.TempFile("", "tf")
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	f.Close()
+	defer os.Remove(f.Name())
+
+	ls := testFilesystem(t)
+	backupPath := f.Name()
+	ls.SetBackupPath(backupPath)
+
+	TestFull(t, ls)
+
+	// The backup functionality should've saved a copy of the original state
+	// prior to all of the modifications that TestFull does.
+	bfh, err := os.Open(backupPath)
+	if err != nil {
+		t.Fatal(err)
+	}
+	bf, err := statefile.Read(bfh)
+	if err != nil {
+		t.Fatal(err)
+	}
+	origState := TestFullInitialState()
+	if !bf.State.Equal(origState) {
+		for _, problem := range deep.Equal(origState, bf.State) {
+			t.Error(problem)
+		}
+	}
+}
+
+// This test verifies a particularly tricky behavior where the input file
+// is overridden and backups are enabled at the same time. This combination
+// requires special care because we must ensure that when we create a backup
+// it is of the original contents of the output file (which we're overwriting),
+// not the contents of the input file (which is left unchanged).
+func TestFilesystem_backupAndReadPath(t *testing.T) {
+	defer testOverrideVersion(t, "1.2.3")()
+
+	workDir := t.TempDir()
+
+	markerOutput := addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance)
+
+	outState := states.BuildState(func(ss *states.SyncState) {
+		ss.SetOutputValue(
+			markerOutput,
+			cty.StringVal("from-output-state"),
+			false, // not sensitive
+		)
+	})
+	outFile, err := os.Create(filepath.Join(workDir, "output.tfstate"))
+	if err != nil {
+		t.Fatalf("failed to create temporary outFile %s", err)
+	}
+	defer outFile.Close()
+	err = statefile.Write(&statefile.File{
+		Lineage:          "-",
+		Serial:           0,
+		TerraformVersion: version.Must(version.NewVersion("1.2.3")),
+		State:            outState,
+	}, outFile)
+	if err != nil {
+		t.Fatalf("failed to write initial outfile state to %s: %s", outFile.Name(), err)
+	}
+
+	inState := states.BuildState(func(ss *states.SyncState) {
+		ss.SetOutputValue(
+			markerOutput,
+			cty.StringVal("from-input-state"),
+			false, // not sensitive
+		)
+	})
+	inFile, err := os.Create(filepath.Join(workDir, "input.tfstate"))
+	if err != nil {
+		t.Fatalf("failed to create temporary inFile %s", err)
+	}
+	defer inFile.Close()
+	err = statefile.Write(&statefile.File{
+		Lineage:          "-",
+		Serial:           0,
+		TerraformVersion: version.Must(version.NewVersion("1.2.3")),
+		State:            inState,
+	}, inFile)
+	if err != nil {
+		t.Fatalf("failed to write initial infile state to %s: %s", inFile.Name(), err)
+	}
+
+	backupPath := outFile.Name() + ".backup"
+
+	ls := NewFilesystemBetweenPaths(inFile.Name(), outFile.Name())
+	ls.SetBackupPath(backupPath)
+
+	newState := states.BuildState(func(ss *states.SyncState) {
+		ss.SetOutputValue(
+			markerOutput,
+			cty.StringVal("from-new-state"),
+			false, // not sensitive
+		)
+	})
+	err = ls.WriteState(newState)
+	if err != nil {
+		t.Fatalf("failed to write new state: %s", err)
+	}
+
+	// The backup functionality should've saved a copy of the original contents
+	// of the _output_ file, even though the first snapshot was read from
+	// the _input_ file.
+	t.Run("backup file", func(t *testing.T) {
+		bfh, err := os.Open(backupPath)
+		if err != nil {
+			t.Fatal(err)
+		}
+		bf, err := statefile.Read(bfh)
+		if err != nil {
+			t.Fatal(err)
+		}
+		os := bf.State.OutputValue(markerOutput)
+		if got, want := os.Value, cty.StringVal("from-output-state"); !want.RawEquals(got) {
+			t.Errorf("wrong marker value in backup state file\ngot:  %#v\nwant: %#v", got, want)
+		}
+	})
+	t.Run("output file", func(t *testing.T) {
+		ofh, err := os.Open(outFile.Name())
+		if err != nil {
+			t.Fatal(err)
+		}
+		of, err := statefile.Read(ofh)
+		if err != nil {
+			t.Fatal(err)
+		}
+		os := of.State.OutputValue(markerOutput)
+		if got, want := os.Value, cty.StringVal("from-new-state"); !want.RawEquals(got) {
+			t.Errorf("wrong marker value in backup state file\ngot:  %#v\nwant: %#v", got, want)
+		}
+	})
+}
+
+func TestFilesystem_nonExist(t *testing.T) {
+	defer testOverrideVersion(t, "1.2.3")()
+	ls := NewFilesystem("ishouldntexist")
+	if err := ls.RefreshState(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if state := ls.State(); state != nil {
+		t.Fatalf("bad: %#v", state)
+	}
+}
+
+func TestFilesystem_lockUnlockWithoutWrite(t *testing.T) {
+	info := NewLockInfo()
+	info.Operation = "test"
+
+	ls := testFilesystem(t)
+
+	// Delete the just-created tempfile so that Lock recreates it
+	os.Remove(ls.path)
+
+	// Lock the state, and in doing so recreate the tempfile
+	lockID, err := ls.Lock(info)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !ls.created {
+		t.Fatal("should have marked state as created")
+	}
+
+	if err := ls.Unlock(lockID); err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = os.Stat(ls.path)
+	if os.IsNotExist(err) {
+		// Success! Unlocking the state successfully deleted the tempfile
+		return
+	} else if err != nil {
+		t.Fatalf("unexpected error from os.Stat: %s", err)
+	} else {
+		os.Remove(ls.readPath)
+		t.Fatal("should have removed path, but exists")
+	}
+}
+
+func TestFilesystem_impl(t *testing.T) {
+	defer testOverrideVersion(t, "1.2.3")()
+	var _ Reader = new(Filesystem)
+	var _ Writer = new(Filesystem)
+	var _ Persister = new(Filesystem)
+	var _ Refresher = new(Filesystem)
+	var _ OutputReader = new(Filesystem)
+	var _ Locker = new(Filesystem)
+}
+
+func testFilesystem(t *testing.T) *Filesystem {
+	f, err := ioutil.TempFile("", "tf")
+	if err != nil {
+		t.Fatalf("failed to create temporary file %s", err)
+	}
+	t.Logf("temporary state file at %s", f.Name())
+
+	err = statefile.Write(&statefile.File{
+		Lineage:          "test-lineage",
+		Serial:           0,
+		TerraformVersion: version.Must(version.NewVersion("1.2.3")),
+		State:            TestFullInitialState(),
+	}, f)
+	if err != nil {
+		t.Fatalf("failed to write initial state to %s: %s", f.Name(), err)
+	}
+	f.Close()
+
+	ls := NewFilesystem(f.Name())
+	if err := ls.RefreshState(); err != nil {
+		t.Fatalf("initial refresh failed: %s", err)
+	}
+
+	return ls
+}
+
+// Make sure we can refresh while the state is locked
+func TestFilesystem_refreshWhileLocked(t *testing.T) {
+	defer testOverrideVersion(t, "1.2.3")()
+	f, err := ioutil.TempFile("", "tf")
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	err = statefile.Write(&statefile.File{
+		Lineage:          "test-lineage",
+		Serial:           0,
+		TerraformVersion: version.Must(version.NewVersion("1.2.3")),
+		State:            TestFullInitialState(),
+	}, f)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	f.Close()
+
+	s := NewFilesystem(f.Name())
+	defer os.Remove(s.path)
+
+	// lock first
+	info := NewLockInfo()
+	info.Operation = "test"
+	lockID, err := s.Lock(info)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		if err := s.Unlock(lockID); err != nil {
+			t.Fatal(err)
+		}
+	}()
+
+	if err := s.RefreshState(); err != nil {
+		t.Fatal(err)
+	}
+
+	readState := s.State()
+	if readState == nil {
+		t.Fatal("missing state")
+	}
+}
+
+func TestFilesystem_GetRootOutputValues(t *testing.T) {
+	fs := testFilesystem(t)
+
+	outputs, err := fs.GetRootOutputValues()
+	if err != nil {
+		t.Errorf("Expected GetRootOutputValues to not return an error, but it returned %v", err)
+	}
+
+	if len(outputs) != 2 {
+		t.Errorf("Expected %d outputs, but received %d", 2, len(outputs))
+	}
+}
+
+func testOverrideVersion(t *testing.T, v string) func() {
+	oldVersionStr := tfversion.Version
+	oldPrereleaseStr := tfversion.Prerelease
+	oldSemVer := tfversion.SemVer
+
+	var newPrereleaseStr string
+	if dash := strings.Index(v, "-"); dash != -1 {
+		newPrereleaseStr = v[dash+1:]
+		v = v[:dash]
+	}
+
+	newSemVer, err := version.NewVersion(v)
+	if err != nil {
+		t.Errorf("invalid override version %q: %s", v, err)
+	}
+	newVersionStr := newSemVer.String()
+
+	tfversion.Version = newVersionStr
+	tfversion.Prerelease = newPrereleaseStr
+	tfversion.SemVer = newSemVer
+
+	return func() { // reset function
+		tfversion.Version = oldVersionStr
+		tfversion.Prerelease = oldPrereleaseStr
+		tfversion.SemVer = oldSemVer
+	}
+}
diff --git a/v1.5.7/internal/states/statemgr/helper.go b/v1.5.7/internal/states/statemgr/helper.go
new file mode 100644
index 0000000..5c9749a
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/helper.go
@@ -0,0 +1,57 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+// The functions in this file are helper wrappers for common sequences of
+// operations done against full state managers.
+
+import (
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/terraform"
+	"github.com/hashicorp/terraform/version"
+)
+
+// NewStateFile creates a new statefile.File object, with a newly-minted
+// lineage identifier and serial 0, and returns a pointer to it.
+func NewStateFile() *statefile.File {
+	return &statefile.File{
+		Lineage:          NewLineage(),
+		TerraformVersion: version.SemVer,
+		State:            states.NewState(),
+	}
+}
+
+// RefreshAndRead refreshes the persistent snapshot in the given state manager
+// and then returns it.
+//
+// This is a wrapper around calling RefreshState and then State on the given
+// manager.
+func RefreshAndRead(mgr Storage) (*states.State, error) {
+	err := mgr.RefreshState()
+	if err != nil {
+		return nil, err
+	}
+	return mgr.State(), nil
+}
+
+// WriteAndPersist writes a snapshot of the given state to the given state
+// manager's transient store and then immediately persists it.
+//
+// The caller must ensure that the given state is not concurrently modified
+// while this function is running, but it is safe to modify it after this
+// function has returned.
+//
+// If an error is returned, it is undefined whether the state has been saved
+// to the transient store or not, and so the only safe response is to bail
+// out quickly with a user-facing error. In situations where more control
+// is required, call WriteState and PersistState on the state manager directly
+// and handle their errors.
+func WriteAndPersist(mgr Storage, state *states.State, schemas *terraform.Schemas) error {
+	err := mgr.WriteState(state)
+	if err != nil {
+		return err
+	}
+	return mgr.PersistState(schemas)
+}
diff --git a/v1.5.7/internal/states/statemgr/lineage.go b/v1.5.7/internal/states/statemgr/lineage.go
new file mode 100644
index 0000000..73e5c1d
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/lineage.go
@@ -0,0 +1,23 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+import (
+	"fmt"
+
+	uuid "github.com/hashicorp/go-uuid"
+)
+
+// NewLineage generates a new lineage identifier string. A lineage identifier
+// is an opaque string that is intended to be unique in space and time, chosen
+// when state is recorded at a location for the first time and then preserved
+// afterwards to allow Terraform to recognize when one state snapshot is a
+// predecessor or successor of another.
+func NewLineage() string {
+	lineage, err := uuid.GenerateUUID()
+	if err != nil {
+		panic(fmt.Errorf("Failed to generate lineage: %v", err))
+	}
+	return lineage
+}
diff --git a/v1.5.7/internal/states/statemgr/lock.go b/v1.5.7/internal/states/statemgr/lock.go
new file mode 100644
index 0000000..2910889
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/lock.go
@@ -0,0 +1,46 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+import (
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// LockDisabled implements State and Locker but disables state locking.
+// If State doesn't support locking, this is a no-op. This is useful for
+// easily disabling locking of an existing state or for tests.
+type LockDisabled struct {
+	// We can't embed State directly since Go dislikes that a field is
+	// State and State interface has a method State
+	Inner Full
+}
+
+func (s *LockDisabled) State() *states.State {
+	return s.Inner.State()
+}
+
+func (s *LockDisabled) GetRootOutputValues() (map[string]*states.OutputValue, error) {
+	return s.Inner.GetRootOutputValues()
+}
+
+func (s *LockDisabled) WriteState(v *states.State) error {
+	return s.Inner.WriteState(v)
+}
+
+func (s *LockDisabled) RefreshState() error {
+	return s.Inner.RefreshState()
+}
+
+func (s *LockDisabled) PersistState(schemas *terraform.Schemas) error {
+	return s.Inner.PersistState(schemas)
+}
+
+func (s *LockDisabled) Lock(info *LockInfo) (string, error) {
+	return "", nil
+}
+
+func (s *LockDisabled) Unlock(id string) error {
+	return nil
+}
diff --git a/v1.5.7/internal/states/statemgr/lock_test.go b/v1.5.7/internal/states/statemgr/lock_test.go
new file mode 100644
index 0000000..b085372
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/lock_test.go
@@ -0,0 +1,13 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+import (
+	"testing"
+)
+
+func TestLockDisabled_impl(t *testing.T) {
+	var _ Full = new(LockDisabled)
+	var _ Locker = new(LockDisabled)
+}
diff --git a/v1.5.7/internal/states/statemgr/locker.go b/v1.5.7/internal/states/statemgr/locker.go
new file mode 100644
index 0000000..1c60346
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/locker.go
@@ -0,0 +1,227 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"math/rand"
+	"os"
+	"os/user"
+	"strings"
+	"text/template"
+	"time"
+
+	uuid "github.com/hashicorp/go-uuid"
+	"github.com/hashicorp/terraform/version"
+)
+
+var rngSource = rand.New(rand.NewSource(time.Now().UnixNano()))
+
+// Locker is the interface for state managers that are able to manage
+// mutual-exclusion locks for state.
+//
+// Implementing Locker alongside Persistent relaxes some of the usual
+// implementation constraints for implementations of Refresher and Persister,
+// under the assumption that the locking mechanism effectively prevents
+// multiple Terraform processes from reading and writing state concurrently.
+// In particular, a type that implements both Locker and Persistent is only
+// required to that the Persistent implementation is concurrency-safe within
+// a single Terraform process.
+//
+// A Locker implementation must ensure that another processes with a
+// similarly-configured state manager cannot successfully obtain a lock while
+// the current process is holding it, or vice-versa, assuming that both
+// processes agree on the locking mechanism.
+//
+// A Locker is not required to prevent non-cooperating processes from
+// concurrently modifying the state, but is free to do so as an extra
+// protection. If a mandatory locking mechanism of this sort is implemented,
+// the state manager must ensure that RefreshState and PersistState calls
+// can succeed if made through the same manager instance that is holding the
+// lock, such has by retaining some sort of lock token that the Persistent
+// methods can then use.
+type Locker interface {
+	// Lock attempts to obtain a lock, using the given lock information.
+	//
+	// The result is an opaque id that can be passed to Unlock to release
+	// the lock, or an error if the lock cannot be acquired. Lock returns
+	// an instance of LockError immediately if the lock is already held,
+	// and the helper function LockWithContext uses this to automatically
+	// retry lock acquisition periodically until a timeout is reached.
+	Lock(info *LockInfo) (string, error)
+
+	// Unlock releases a lock previously acquired by Lock.
+	//
+	// If the lock cannot be released -- for example, if it was stolen by
+	// another user with some sort of administrative override privilege --
+	// then an error is returned explaining the situation in a way that
+	// is suitable for returning to an end-user.
+	Unlock(id string) error
+}
+
+// test hook to verify that LockWithContext has attempted a lock
+var postLockHook func()
+
+// LockWithContext locks the given state manager using the provided context
+// for both timeout and cancellation.
+//
+// This method has a built-in retry/backoff behavior up to the context's
+// timeout.
+func LockWithContext(ctx context.Context, s Locker, info *LockInfo) (string, error) {
+	delay := time.Second
+	maxDelay := 16 * time.Second
+	for {
+		id, err := s.Lock(info)
+		if err == nil {
+			return id, nil
+		}
+
+		le, ok := err.(*LockError)
+		if !ok {
+			// not a lock error, so we can't retry
+			return "", err
+		}
+
+		if le == nil || le.Info == nil || le.Info.ID == "" {
+			// If we don't have a complete LockError then there's something
+			// wrong with the lock.
+			return "", err
+		}
+
+		if postLockHook != nil {
+			postLockHook()
+		}
+
+		// there's an existing lock, wait and try again
+		select {
+		case <-ctx.Done():
+			// return the last lock error with the info
+			return "", err
+		case <-time.After(delay):
+			if delay < maxDelay {
+				delay *= 2
+			}
+		}
+	}
+}
+
+// LockInfo stores lock metadata.
+//
+// Only Operation and Info are required to be set by the caller of Lock.
+// Most callers should use NewLockInfo to create a LockInfo value with many
+// of the fields populated with suitable default values.
+type LockInfo struct {
+	// Unique ID for the lock. NewLockInfo provides a random ID, but this may
+	// be overridden by the lock implementation. The final value of ID will be
+	// returned by the call to Lock.
+	ID string
+
+	// Terraform operation, provided by the caller.
+	Operation string
+
+	// Extra information to store with the lock, provided by the caller.
+	Info string
+
+	// user@hostname when available
+	Who string
+
+	// Terraform version
+	Version string
+
+	// Time that the lock was taken.
+	Created time.Time
+
+	// Path to the state file when applicable. Set by the Lock implementation.
+	Path string
+}
+
+// NewLockInfo creates a LockInfo object and populates many of its fields
+// with suitable default values.
+func NewLockInfo() *LockInfo {
+	// this doesn't need to be cryptographically secure, just unique.
+	// Using math/rand alleviates the need to check handle the read error.
+	// Use a uuid format to match other IDs used throughout Terraform.
+	buf := make([]byte, 16)
+	rngSource.Read(buf)
+
+	id, err := uuid.FormatUUID(buf)
+	if err != nil {
+		// this of course shouldn't happen
+		panic(err)
+	}
+
+	// don't error out on user and hostname, as we don't require them
+	userName := ""
+	if userInfo, err := user.Current(); err == nil {
+		userName = userInfo.Username
+	}
+	host, _ := os.Hostname()
+
+	info := &LockInfo{
+		ID:      id,
+		Who:     fmt.Sprintf("%s@%s", userName, host),
+		Version: version.Version,
+		Created: time.Now().UTC(),
+	}
+	return info
+}
+
+// Err returns the lock info formatted in an error
+func (l *LockInfo) Err() error {
+	return errors.New(l.String())
+}
+
+// Marshal returns a string json representation of the LockInfo
+func (l *LockInfo) Marshal() []byte {
+	js, err := json.Marshal(l)
+	if err != nil {
+		panic(err)
+	}
+	return js
+}
+
+// String return a multi-line string representation of LockInfo
+func (l *LockInfo) String() string {
+	tmpl := `Lock Info:
+  ID:        {{.ID}}
+  Path:      {{.Path}}
+  Operation: {{.Operation}}
+  Who:       {{.Who}}
+  Version:   {{.Version}}
+  Created:   {{.Created}}
+  Info:      {{.Info}}
+`
+
+	t := template.Must(template.New("LockInfo").Parse(tmpl))
+	var out bytes.Buffer
+	if err := t.Execute(&out, l); err != nil {
+		panic(err)
+	}
+	return out.String()
+}
+
+// LockError is a specialization of type error that is returned by Locker.Lock
+// to indicate that the lock is already held by another process and that
+// retrying may be productive to take the lock once the other process releases
+// it.
+type LockError struct {
+	Info *LockInfo
+	Err  error
+}
+
+func (e *LockError) Error() string {
+	var out []string
+	if e.Err != nil {
+		out = append(out, e.Err.Error())
+	}
+
+	if e.Info != nil {
+		out = append(out, e.Info.String())
+	}
+	return strings.Join(out, "\n")
+}
diff --git a/v1.5.7/internal/states/statemgr/migrate.go b/v1.5.7/internal/states/statemgr/migrate.go
new file mode 100644
index 0000000..6abb9d3
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/migrate.go
@@ -0,0 +1,215 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/states/statefile"
+)
+
+// Migrator is an optional interface implemented by state managers that
+// are capable of direct migration of state snapshots with their associated
+// metadata unchanged.
+//
+// This interface is used when available by function Migrate. See that
+// function for more information on how it is used.
+type Migrator interface {
+	PersistentMeta
+
+	// StateForMigration returns a full statefile representing the latest
+	// snapshot (as would be returned by Reader.State) and the associated
+	// snapshot metadata (as would be returned by
+	// PersistentMeta.StateSnapshotMeta).
+	//
+	// Just as with Reader.State, this must not fail.
+	StateForMigration() *statefile.File
+
+	// WriteStateForMigration accepts a full statefile including associated
+	// snapshot metadata, and atomically updates the stored file (as with
+	// Writer.WriteState) and the metadata.
+	//
+	// If "force" is not set, the manager must call CheckValidImport with
+	// the given file and the current file and complete the update only if
+	// that function returns nil. If force is set this may override such
+	// checks, but some backends do not support forcing and so will act
+	// as if force is always false.
+	WriteStateForMigration(f *statefile.File, force bool) error
+}
+
+// Migrate writes the latest transient state snapshot from src into dest,
+// preserving snapshot metadata (serial and lineage) where possible.
+//
+// If both managers implement the optional interface Migrator then it will
+// be used to copy the snapshot and its associated metadata. Otherwise,
+// the normal Reader and Writer interfaces will be used instead.
+//
+// If the destination manager refuses the new state or fails to write it then
+// its error is returned directly.
+//
+// For state managers that also implement Persistent, it is the caller's
+// responsibility to persist the newly-written state after a successful result,
+// just as with calls to Writer.WriteState.
+//
+// This function doesn't do any locking of its own, so if the state managers
+// also implement Locker the caller should hold a lock on both managers
+// for the duration of this call.
+func Migrate(dst, src Transient) error {
+	if dstM, ok := dst.(Migrator); ok {
+		if srcM, ok := src.(Migrator); ok {
+			// Full-fidelity migration, them.
+			s := srcM.StateForMigration()
+			return dstM.WriteStateForMigration(s, true)
+		}
+	}
+
+	// Managers to not support full-fidelity migration, so migration will not
+	// preserve serial/lineage.
+	s := src.State()
+	return dst.WriteState(s)
+}
+
+// Import loads the given state snapshot into the given manager, preserving
+// its metadata (serial and lineage) if the target manager supports metadata.
+//
+// A state manager must implement the optional interface Migrator to get
+// access to the full metadata.
+//
+// Unless "force" is true, Import will check first that the metadata given
+// in the file matches the current snapshot metadata for the manager, if the
+// manager supports metadata. Some managers do not support forcing, so a
+// write with an unsuitable lineage or serial may still be rejected even if
+// "force" is set. "force" has no effect for managers that do not support
+// snapshot metadata.
+//
+// For state managers that also implement Persistent, it is the caller's
+// responsibility to persist the newly-written state after a successful result,
+// just as with calls to Writer.WriteState.
+//
+// This function doesn't do any locking of its own, so if the state manager
+// also implements Locker the caller should hold a lock on it for the
+// duration of this call.
+func Import(f *statefile.File, mgr Transient, force bool) error {
+	if mgrM, ok := mgr.(Migrator); ok {
+		return mgrM.WriteStateForMigration(f, force)
+	}
+
+	// For managers that don't implement Migrator, this is just a normal write
+	// of the state contained in the given file.
+	return mgr.WriteState(f.State)
+}
+
+// Export retrieves the latest state snapshot from the given manager, including
+// its metadata (serial and lineage) where possible.
+//
+// A state manager must also implement either Migrator or PersistentMeta
+// for the metadata to be included. Otherwise, the relevant fields will have
+// zero value in the returned object.
+//
+// For state managers that also implement Persistent, it is the caller's
+// responsibility to refresh from persistent storage first if needed.
+//
+// This function doesn't do any locking of its own, so if the state manager
+// also implements Locker the caller should hold a lock on it for the
+// duration of this call.
+func Export(mgr Reader) *statefile.File {
+	switch mgrT := mgr.(type) {
+	case Migrator:
+		return mgrT.StateForMigration()
+	case PersistentMeta:
+		s := mgr.State()
+		meta := mgrT.StateSnapshotMeta()
+		return statefile.New(s, meta.Lineage, meta.Serial)
+	default:
+		s := mgr.State()
+		return statefile.New(s, "", 0)
+	}
+}
+
+// SnapshotMetaRel describes a relationship between two SnapshotMeta values,
+// returned from the SnapshotMeta.Compare method where the "first" value
+// is the receiver of that method and the "second" is the given argument.
+type SnapshotMetaRel rune
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=SnapshotMetaRel
+
+const (
+	// SnapshotOlder indicates that two snapshots have a common lineage and
+	// that the first has a lower serial value.
+	SnapshotOlder SnapshotMetaRel = '<'
+
+	// SnapshotNewer indicates that two snapshots have a common lineage and
+	// that the first has a higher serial value.
+	SnapshotNewer SnapshotMetaRel = '>'
+
+	// SnapshotEqual indicates that two snapshots have a common lineage and
+	// the same serial value.
+	SnapshotEqual SnapshotMetaRel = '='
+
+	// SnapshotUnrelated indicates that two snapshots have different lineage
+	// and thus cannot be meaningfully compared.
+	SnapshotUnrelated SnapshotMetaRel = '!'
+
+	// SnapshotLegacy indicates that one or both of the snapshots
+	// does not have a lineage at all, and thus no comparison is possible.
+	SnapshotLegacy SnapshotMetaRel = '?'
+)
+
+// Compare determines the relationship, if any, between the given existing
+// SnapshotMeta and the potential "new" SnapshotMeta that is the receiver.
+func (m SnapshotMeta) Compare(existing SnapshotMeta) SnapshotMetaRel {
+	switch {
+	case m.Lineage == "" || existing.Lineage == "":
+		return SnapshotLegacy
+	case m.Lineage != existing.Lineage:
+		return SnapshotUnrelated
+	case m.Serial > existing.Serial:
+		return SnapshotNewer
+	case m.Serial < existing.Serial:
+		return SnapshotOlder
+	default:
+		// both serials are equal, by elimination
+		return SnapshotEqual
+	}
+}
+
+// CheckValidImport returns nil if the "new" snapshot can be imported as a
+// successor of the "existing" snapshot without forcing.
+//
+// If not, an error is returned describing why.
+func CheckValidImport(newFile, existingFile *statefile.File) error {
+	if existingFile == nil || existingFile.State.Empty() {
+		// It's always okay to overwrite an empty state, regardless of
+		// its lineage/serial.
+		return nil
+	}
+	new := SnapshotMeta{
+		Lineage: newFile.Lineage,
+		Serial:  newFile.Serial,
+	}
+	existing := SnapshotMeta{
+		Lineage: existingFile.Lineage,
+		Serial:  existingFile.Serial,
+	}
+	rel := new.Compare(existing)
+	switch rel {
+	case SnapshotNewer:
+		return nil // a newer snapshot is fine
+	case SnapshotLegacy:
+		return nil // anything goes for a legacy state
+	case SnapshotUnrelated:
+		return fmt.Errorf("cannot import state with lineage %q over unrelated state with lineage %q", new.Lineage, existing.Lineage)
+	case SnapshotEqual:
+		if statefile.StatesMarshalEqual(newFile.State, existingFile.State) {
+			// If lineage, serial, and state all match then this is fine.
+			return nil
+		}
+		return fmt.Errorf("cannot overwrite existing state with serial %d with a different state that has the same serial", new.Serial)
+	case SnapshotOlder:
+		return fmt.Errorf("cannot import state with serial %d over newer state with serial %d", new.Serial, existing.Serial)
+	default:
+		// Should never happen, but we'll check to make sure for safety
+		return fmt.Errorf("unsupported state snapshot relationship %s", rel)
+	}
+}
diff --git a/v1.5.7/internal/states/statemgr/migrate_test.go b/v1.5.7/internal/states/statemgr/migrate_test.go
new file mode 100644
index 0000000..4f1a943
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/migrate_test.go
@@ -0,0 +1,105 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+import (
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+)
+
+func TestCheckValidImport(t *testing.T) {
+	barState := states.BuildState(func(s *states.SyncState) {
+		s.SetOutputValue(
+			addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance),
+			cty.StringVal("bar"), false,
+		)
+	})
+	notBarState := states.BuildState(func(s *states.SyncState) {
+		s.SetOutputValue(
+			addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance),
+			cty.StringVal("not bar"), false,
+		)
+	})
+	emptyState := states.NewState()
+
+	tests := map[string]struct {
+		New      *statefile.File
+		Existing *statefile.File
+		WantErr  string
+	}{
+		"exact match": {
+			New:      statefile.New(barState, "lineage", 1),
+			Existing: statefile.New(barState, "lineage", 1),
+			WantErr:  ``,
+		},
+		"overwrite unrelated empty state": {
+			New:      statefile.New(barState, "lineage1", 1),
+			Existing: statefile.New(emptyState, "lineage2", 1),
+			WantErr:  ``,
+		},
+		"different state with same serial": {
+			New:      statefile.New(barState, "lineage", 1),
+			Existing: statefile.New(notBarState, "lineage", 1),
+			WantErr:  `cannot overwrite existing state with serial 1 with a different state that has the same serial`,
+		},
+		"different state with newer serial": {
+			New:      statefile.New(barState, "lineage", 2),
+			Existing: statefile.New(notBarState, "lineage", 1),
+			WantErr:  ``,
+		},
+		"different state with older serial": {
+			New:      statefile.New(barState, "lineage", 1),
+			Existing: statefile.New(notBarState, "lineage", 2),
+			WantErr:  `cannot import state with serial 1 over newer state with serial 2`,
+		},
+		"different lineage with same serial": {
+			New:      statefile.New(barState, "lineage1", 2),
+			Existing: statefile.New(notBarState, "lineage2", 2),
+			WantErr:  `cannot import state with lineage "lineage1" over unrelated state with lineage "lineage2"`,
+		},
+		"different lineage with different serial": {
+			New:      statefile.New(barState, "lineage1", 3),
+			Existing: statefile.New(notBarState, "lineage2", 2),
+			WantErr:  `cannot import state with lineage "lineage1" over unrelated state with lineage "lineage2"`,
+		},
+		"new state is legacy": {
+			New:      statefile.New(barState, "", 2),
+			Existing: statefile.New(notBarState, "lineage", 2),
+			WantErr:  ``,
+		},
+		"old state is legacy": {
+			New:      statefile.New(barState, "lineage", 2),
+			Existing: statefile.New(notBarState, "", 2),
+			WantErr:  ``,
+		},
+		"both states are legacy": {
+			New:      statefile.New(barState, "", 2),
+			Existing: statefile.New(notBarState, "", 2),
+			WantErr:  ``,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			gotErr := CheckValidImport(test.New, test.Existing)
+
+			if test.WantErr == "" {
+				if gotErr != nil {
+					t.Errorf("unexpected error: %s", gotErr)
+				}
+			} else {
+				if gotErr == nil {
+					t.Errorf("succeeded, but want error: %s", test.WantErr)
+				} else if got, want := gotErr.Error(), test.WantErr; got != want {
+					t.Errorf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/states/statemgr/persistent.go b/v1.5.7/internal/states/statemgr/persistent.go
new file mode 100644
index 0000000..86e8e5b
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/persistent.go
@@ -0,0 +1,124 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+import (
+	version "github.com/hashicorp/go-version"
+
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// Persistent is a union of the Refresher and Persistent interfaces, for types
+// that deal with persistent snapshots.
+//
+// Persistent snapshots are ones that are retained in storage that will
+// outlive a particular Terraform process, and are shared with other Terraform
+// processes that have a similarly-configured state manager.
+//
+// A manager may also choose to retain historical persistent snapshots, but
+// that is an implementation detail and not visible via this API.
+type Persistent interface {
+	Refresher
+	Persister
+	OutputReader
+}
+
+// OutputReader is the interface for managers that fetches output values from state
+// or another source. This is a refinement of fetching the entire state and digging
+// the output values from it because enhanced backends can apply special permissions
+// to differentiate reading the state and reading the outputs within the state.
+type OutputReader interface {
+	// GetRootOutputValues fetches the root module output values from state or another source
+	GetRootOutputValues() (map[string]*states.OutputValue, error)
+}
+
+// Refresher is the interface for managers that can read snapshots from
+// persistent storage.
+//
+// Refresher is usually implemented in conjunction with Reader, with
+// RefreshState copying the latest persistent snapshot into the latest
+// transient snapshot.
+//
+// For a type that implements both Refresher and Persister, RefreshState must
+// return the result of the most recently completed successful call to
+// PersistState, unless another concurrently-running process has persisted
+// another snapshot in the mean time.
+//
+// The Refresher implementation must guarantee that the snapshot is read
+// from persistent storage in a way that is safe under concurrent calls to
+// PersistState that may be happening in other processes.
+type Refresher interface {
+	// RefreshState retrieves a snapshot of state from persistent storage,
+	// returning an error if this is not possible.
+	//
+	// Types that implement RefreshState generally also implement a State
+	// method that returns the result of the latest successful refresh.
+	//
+	// Since only a subset of the data in a state is included when persisting,
+	// a round-trip through PersistState and then RefreshState will often
+	// return only a subset of what was written. Callers must assume that
+	// ephemeral portions of the state may be unpopulated after calling
+	// RefreshState.
+	RefreshState() error
+}
+
+// Persister is the interface for managers that can write snapshots to
+// persistent storage.
+//
+// Persister is usually implemented in conjunction with Writer, with
+// PersistState copying the latest transient snapshot to be the new latest
+// persistent snapshot.
+//
+// A Persister implementation must detect updates made by other processes
+// that may be running concurrently and avoid destroying those changes. This
+// is most commonly achieved by making use of atomic write capabilities on
+// the remote storage backend in conjunction with book-keeping with the
+// Serial and Lineage fields in the standard state file formats.
+//
+// Some implementations may optionally utilize config schema to persist
+// state. For example, when representing state in an external JSON
+// representation.
+type Persister interface {
+	PersistState(*terraform.Schemas) error
+}
+
+// PersistentMeta is an optional extension to Persistent that allows inspecting
+// the metadata associated with the snapshot that was most recently either
+// read by RefreshState or written by PersistState.
+type PersistentMeta interface {
+	// StateSnapshotMeta returns metadata about the state snapshot most
+	// recently created either by a call to PersistState or read by a call
+	// to RefreshState.
+	//
+	// If no persistent snapshot is yet available in the manager then
+	// the return value is meaningless. This method is primarily available
+	// for testing and logging purposes, and is of little use otherwise.
+	StateSnapshotMeta() SnapshotMeta
+}
+
+// SnapshotMeta contains metadata about a persisted state snapshot.
+//
+// This metadata is usually (but not necessarily) included as part of the
+// "header" of a state file, which is then written to a raw blob storage medium
+// by a persistent state manager.
+//
+// Not all state managers will have useful values for all fields in this
+// struct, so SnapshotMeta values are of little use beyond testing and logging
+// use-cases.
+type SnapshotMeta struct {
+	// Lineage and Serial can be used to understand the relationships between
+	// snapshots.
+	//
+	// If two snapshots both have an identical, non-empty Lineage
+	// then the one with the higher Serial is newer than the other.
+	// If the Lineage values are different or empty then the two snapshots
+	// are unrelated and cannot be compared for relative age.
+	Lineage string
+	Serial  uint64
+
+	// TerraformVersion is the number of the version of Terraform that created
+	// the snapshot.
+	TerraformVersion *version.Version
+}
diff --git a/v1.5.7/internal/states/statemgr/plan.go b/v1.5.7/internal/states/statemgr/plan.go
new file mode 100644
index 0000000..7d1aba6
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/plan.go
@@ -0,0 +1,74 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+)
+
+// PlannedStateUpdate is a special helper to obtain a statefile representation
+// of a not-yet-written state snapshot that can be written later by a call
+// to the companion function WritePlannedStateUpdate.
+//
+// The statefile object returned here has an unusual interpretation of its
+// metadata that is understood only by WritePlannedStateUpdate, and so the
+// returned object should not be used for any other purpose.
+//
+// If the state manager implements Locker then it is the caller's
+// responsibility to hold the lock at least for the duration of this call.
+// It is not safe to modify the given state concurrently while
+// PlannedStateUpdate is running.
+func PlannedStateUpdate(mgr Transient, planned *states.State) *statefile.File {
+	ret := &statefile.File{
+		State: planned.DeepCopy(),
+	}
+
+	// If the given manager uses snapshot metadata then we'll save that
+	// in our file so we can check it again during WritePlannedStateUpdate.
+	if mr, ok := mgr.(PersistentMeta); ok {
+		m := mr.StateSnapshotMeta()
+		ret.Lineage = m.Lineage
+		ret.Serial = m.Serial
+	}
+
+	return ret
+}
+
+// WritePlannedStateUpdate is a companion to PlannedStateUpdate that attempts
+// to apply a state update that was planned earlier to the given state
+// manager.
+//
+// An error is returned if this function detects that a new state snapshot
+// has been written to the backend since the update was planned, since that
+// invalidates the plan. An error is returned also if the manager itself
+// rejects the given state when asked to store it.
+//
+// If the returned error is nil, the given manager's transient state snapshot
+// is updated to match what was planned. It is the caller's responsibility
+// to then persist that state if the manager also implements Persistent and
+// the snapshot should be written to the persistent store.
+//
+// If the state manager implements Locker then it is the caller's
+// responsibility to hold the lock at least for the duration of this call.
+func WritePlannedStateUpdate(mgr Transient, planned *statefile.File) error {
+	// If the given manager uses snapshot metadata then we'll check to make
+	// sure no new snapshots have been created since we planned to write
+	// the given state file.
+	if mr, ok := mgr.(PersistentMeta); ok {
+		m := mr.StateSnapshotMeta()
+		if planned.Lineage != "" {
+			if planned.Lineage != m.Lineage {
+				return fmt.Errorf("planned state update is from an unrelated state lineage than the current state")
+			}
+			if planned.Serial != m.Serial {
+				return fmt.Errorf("stored state has been changed by another operation since the given update was planned")
+			}
+		}
+	}
+
+	return mgr.WriteState(planned.State)
+}
diff --git a/v1.5.7/internal/states/statemgr/snapshotmetarel_string.go b/v1.5.7/internal/states/statemgr/snapshotmetarel_string.go
new file mode 100644
index 0000000..a5b6613
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/snapshotmetarel_string.go
@@ -0,0 +1,37 @@
+// Code generated by "stringer -type=SnapshotMetaRel"; DO NOT EDIT.
+
+package statemgr
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[SnapshotOlder-60]
+	_ = x[SnapshotNewer-62]
+	_ = x[SnapshotEqual-61]
+	_ = x[SnapshotUnrelated-33]
+	_ = x[SnapshotLegacy-63]
+}
+
+const (
+	_SnapshotMetaRel_name_0 = "SnapshotUnrelated"
+	_SnapshotMetaRel_name_1 = "SnapshotOlderSnapshotEqualSnapshotNewerSnapshotLegacy"
+)
+
+var (
+	_SnapshotMetaRel_index_1 = [...]uint8{0, 13, 26, 39, 53}
+)
+
+func (i SnapshotMetaRel) String() string {
+	switch {
+	case i == 33:
+		return _SnapshotMetaRel_name_0
+	case 60 <= i && i <= 63:
+		i -= 60
+		return _SnapshotMetaRel_name_1[_SnapshotMetaRel_index_1[i]:_SnapshotMetaRel_index_1[i+1]]
+	default:
+		return "SnapshotMetaRel(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/v1.5.7/internal/states/statemgr/statemgr.go b/v1.5.7/internal/states/statemgr/statemgr.go
new file mode 100644
index 0000000..1236127
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/statemgr.go
@@ -0,0 +1,29 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+// Storage is the union of Transient and Persistent, for state managers that
+// have both transient and persistent storage.
+//
+// Types implementing this interface coordinate between their Transient
+// and Persistent implementations so that the persistent operations read
+// or write the transient store.
+type Storage interface {
+	Transient
+	Persistent
+}
+
+// Full is the union of all of the more-specific state interfaces.
+//
+// This interface may grow over time, so state implementations aiming to
+// implement it may need to be modified for future changes. To ensure that
+// this need can be detected, always include a statement nearby the declaration
+// of the implementing type that will fail at compile time if the interface
+// isn't satisfied, such as:
+//
+//	var _ statemgr.Full = (*ImplementingType)(nil)
+type Full interface {
+	Storage
+	Locker
+}
diff --git a/v1.5.7/internal/states/statemgr/statemgr_fake.go b/v1.5.7/internal/states/statemgr/statemgr_fake.go
new file mode 100644
index 0000000..4912de1
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/statemgr_fake.go
@@ -0,0 +1,144 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+import (
+	"errors"
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/terraform"
+)
+
+// NewFullFake returns a full state manager that really only supports transient
+// snapshots. This is primarily intended for testing and is not suitable for
+// general use.
+//
+// The persistent part of the interface is stubbed out as an in-memory store,
+// and so its snapshots are effectively also transient.
+//
+// The given Transient implementation is used to implement the transient
+// portion of the interface. If nil is given, NewTransientInMemory is
+// automatically called to create an in-memory transient manager with no
+// initial transient snapshot.
+//
+// If the given initial state is non-nil then a copy of it will be used as
+// the initial persistent snapshot.
+//
+// The Locker portion of the returned manager uses a local mutex to simulate
+// mutually-exclusive access to the fake persistent portion of the object.
+func NewFullFake(t Transient, initial *states.State) Full {
+	if t == nil {
+		t = NewTransientInMemory(nil)
+	}
+
+	// The "persistent" part of our manager is actually just another in-memory
+	// transient used to fake a secondary storage layer.
+	fakeP := NewTransientInMemory(initial.DeepCopy())
+
+	return &fakeFull{
+		t:     t,
+		fakeP: fakeP,
+	}
+}
+
+type fakeFull struct {
+	t     Transient
+	fakeP Transient
+
+	lockLock sync.Mutex
+	locked   bool
+}
+
+var _ Full = (*fakeFull)(nil)
+
+func (m *fakeFull) State() *states.State {
+	return m.t.State()
+}
+
+func (m *fakeFull) WriteState(s *states.State) error {
+	return m.t.WriteState(s)
+}
+
+func (m *fakeFull) RefreshState() error {
+	return m.t.WriteState(m.fakeP.State())
+}
+
+func (m *fakeFull) PersistState(schemas *terraform.Schemas) error {
+	return m.fakeP.WriteState(m.t.State())
+}
+
+func (m *fakeFull) GetRootOutputValues() (map[string]*states.OutputValue, error) {
+	return m.State().RootModule().OutputValues, nil
+}
+
+func (m *fakeFull) Lock(info *LockInfo) (string, error) {
+	m.lockLock.Lock()
+	defer m.lockLock.Unlock()
+
+	if m.locked {
+		return "", &LockError{
+			Err:  errors.New("fake state manager is locked"),
+			Info: info,
+		}
+	}
+
+	m.locked = true
+	return "placeholder", nil
+}
+
+func (m *fakeFull) Unlock(id string) error {
+	m.lockLock.Lock()
+	defer m.lockLock.Unlock()
+
+	if !m.locked {
+		return errors.New("fake state manager is not locked")
+	}
+	if id != "placeholder" {
+		return errors.New("wrong lock id for fake state manager")
+	}
+
+	m.locked = false
+	return nil
+}
+
+// NewUnlockErrorFull returns a state manager that is useful for testing errors
+// (mostly Unlock errors) when used with the clistate.Locker interface. Lock()
+// does not return an error because clistate.Locker Lock()s the state at the
+// start of Unlock(), so Lock() must succeeded for Unlock() to get called.
+func NewUnlockErrorFull(t Transient, initial *states.State) Full {
+	return &fakeErrorFull{}
+}
+
+type fakeErrorFull struct{}
+
+var _ Full = (*fakeErrorFull)(nil)
+
+func (m *fakeErrorFull) State() *states.State {
+	return nil
+}
+
+func (m *fakeErrorFull) GetRootOutputValues() (map[string]*states.OutputValue, error) {
+	return nil, errors.New("fake state manager error")
+}
+
+func (m *fakeErrorFull) WriteState(s *states.State) error {
+	return errors.New("fake state manager error")
+}
+
+func (m *fakeErrorFull) RefreshState() error {
+	return errors.New("fake state manager error")
+}
+
+func (m *fakeErrorFull) PersistState(schemas *terraform.Schemas) error {
+	return errors.New("fake state manager error")
+}
+
+func (m *fakeErrorFull) Lock(info *LockInfo) (string, error) {
+	return "placeholder", nil
+}
+
+func (m *fakeErrorFull) Unlock(id string) error {
+	return errors.New("fake state manager error")
+}
diff --git a/v1.5.7/internal/states/statemgr/statemgr_test.go b/v1.5.7/internal/states/statemgr/statemgr_test.go
new file mode 100644
index 0000000..5ef005e
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/statemgr_test.go
@@ -0,0 +1,98 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+import (
+	"context"
+	"encoding/json"
+	"flag"
+	"os"
+	"testing"
+	"time"
+
+	_ "github.com/hashicorp/terraform/internal/logging"
+)
+
+func TestNewLockInfo(t *testing.T) {
+	info1 := NewLockInfo()
+	info2 := NewLockInfo()
+
+	if info1.ID == "" {
+		t.Fatal("LockInfo missing ID")
+	}
+
+	if info1.Version == "" {
+		t.Fatal("LockInfo missing version")
+	}
+
+	if info1.Created.IsZero() {
+		t.Fatal("LockInfo missing Created")
+	}
+
+	if info1.ID == info2.ID {
+		t.Fatal("multiple LockInfo with identical IDs")
+	}
+
+	// test the JSON output is valid
+	newInfo := &LockInfo{}
+	err := json.Unmarshal(info1.Marshal(), newInfo)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestLockWithContext(t *testing.T) {
+	s := NewFullFake(nil, TestFullInitialState())
+
+	id, err := s.Lock(NewLockInfo())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// use a cancelled context for an immediate timeout
+	ctx, cancel := context.WithCancel(context.Background())
+	cancel()
+
+	info := NewLockInfo()
+	info.Info = "lock with context"
+	_, err = LockWithContext(ctx, s, info)
+	if err == nil {
+		t.Fatal("lock should have failed immediately")
+	}
+
+	// block until LockwithContext has made a first attempt
+	attempted := make(chan struct{})
+	postLockHook = func() {
+		close(attempted)
+		postLockHook = nil
+	}
+
+	// unlock the state during LockWithContext
+	unlocked := make(chan struct{})
+	var unlockErr error
+	go func() {
+		defer close(unlocked)
+		<-attempted
+		unlockErr = s.Unlock(id)
+	}()
+
+	ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
+	defer cancel()
+
+	id, err = LockWithContext(ctx, s, info)
+	if err != nil {
+		t.Fatal("lock should have completed within 2s:", err)
+	}
+
+	// ensure the goruotine completes
+	<-unlocked
+	if unlockErr != nil {
+		t.Fatal(unlockErr)
+	}
+}
+
+func TestMain(m *testing.M) {
+	flag.Parse()
+	os.Exit(m.Run())
+}
diff --git a/v1.5.7/internal/states/statemgr/testdata/lockstate.go b/v1.5.7/internal/states/statemgr/testdata/lockstate.go
new file mode 100644
index 0000000..a353900
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/testdata/lockstate.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+	"io"
+	"log"
+	"os"
+
+	"github.com/hashicorp/terraform/internal/states/statemgr"
+)
+
+// Attempt to open and lock a terraform state file.
+// Lock failure exits with 0 and writes "lock failed" to stderr.
+func main() {
+	if len(os.Args) != 2 {
+		log.Fatal(os.Args[0], "statefile")
+	}
+
+	s := statemgr.NewFilesystem(os.Args[1])
+
+	info := statemgr.NewLockInfo()
+	info.Operation = "test"
+	info.Info = "state locker"
+
+	_, err := s.Lock(info)
+	if err != nil {
+		io.WriteString(os.Stderr, "lock failed")
+	}
+}
diff --git a/v1.5.7/internal/states/statemgr/testing.go b/v1.5.7/internal/states/statemgr/testing.go
new file mode 100644
index 0000000..2d4c53d
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/testing.go
@@ -0,0 +1,166 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+)
+
+// TestFull is a helper for testing full state manager implementations. It
+// expects that the given implementation is pre-loaded with a snapshot of the
+// result from TestFullInitialState.
+//
+// If the given state manager also implements PersistentMeta, this function
+// will test that the snapshot metadata changes as expected between calls
+// to the methods of Persistent.
+func TestFull(t *testing.T, s Full) {
+	t.Helper()
+
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Check that the initial state is correct.
+	// These do have different Lineages, but we will replace current below.
+	initial := TestFullInitialState()
+	if state := s.State(); !state.Equal(initial) {
+		t.Fatalf("state does not match expected initial state\n\ngot:\n%s\nwant:\n%s", spew.Sdump(state), spew.Sdump(initial))
+	}
+
+	var initialMeta SnapshotMeta
+	if sm, ok := s.(PersistentMeta); ok {
+		initialMeta = sm.StateSnapshotMeta()
+	}
+
+	// Now we've proven that the state we're starting with is an initial
+	// state, we'll complete our work here with that state, since otherwise
+	// further writes would violate the invariant that we only try to write
+	// states that share the same lineage as what was initially written.
+	current := s.State()
+
+	// Write a new state and verify that we have it
+	current.RootModule().SetOutputValue("bar", cty.StringVal("baz"), false)
+
+	if err := s.WriteState(current); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if actual := s.State(); !actual.Equal(current) {
+		t.Fatalf("bad:\n%#v\n\n%#v", actual, current)
+	}
+
+	// Test persistence
+	if err := s.PersistState(nil); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Refresh if we got it
+	if err := s.RefreshState(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	var newMeta SnapshotMeta
+	if sm, ok := s.(PersistentMeta); ok {
+		newMeta = sm.StateSnapshotMeta()
+		if got, want := newMeta.Lineage, initialMeta.Lineage; got != want {
+			t.Errorf("Lineage changed from %q to %q", want, got)
+		}
+		if after, before := newMeta.Serial, initialMeta.Serial; after == before {
+			t.Errorf("Serial didn't change from %d after new module added", before)
+		}
+	}
+
+	// Same serial
+	serial := newMeta.Serial
+	if err := s.WriteState(current); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if err := s.PersistState(nil); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if sm, ok := s.(PersistentMeta); ok {
+		newMeta = sm.StateSnapshotMeta()
+		if newMeta.Serial != serial {
+			t.Fatalf("serial changed after persisting with no changes: got %d, want %d", newMeta.Serial, serial)
+		}
+	}
+
+	if sm, ok := s.(PersistentMeta); ok {
+		newMeta = sm.StateSnapshotMeta()
+	}
+
+	// Change the serial
+	current = current.DeepCopy()
+	current.EnsureModule(addrs.RootModuleInstance).SetOutputValue(
+		"serialCheck", cty.StringVal("true"), false,
+	)
+	if err := s.WriteState(current); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if err := s.PersistState(nil); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if sm, ok := s.(PersistentMeta); ok {
+		oldMeta := newMeta
+		newMeta = sm.StateSnapshotMeta()
+
+		if newMeta.Serial <= serial {
+			t.Fatalf("serial incorrect after persisting with changes: got %d, want > %d", newMeta.Serial, serial)
+		}
+
+		if newMeta.TerraformVersion != oldMeta.TerraformVersion {
+			t.Fatalf("TFVersion changed from %s to %s", oldMeta.TerraformVersion, newMeta.TerraformVersion)
+		}
+
+		// verify that Lineage doesn't change along with Serial, or during copying.
+		if newMeta.Lineage != oldMeta.Lineage {
+			t.Fatalf("Lineage changed from %q to %q", oldMeta.Lineage, newMeta.Lineage)
+		}
+	}
+
+	// Check that State() returns a copy by modifying the copy and comparing
+	// to the current state.
+	stateCopy := s.State()
+	stateCopy.EnsureModule(addrs.RootModuleInstance.Child("another", addrs.NoKey))
+	if reflect.DeepEqual(stateCopy, s.State()) {
+		t.Fatal("State() should return a copy")
+	}
+
+	// our current expected state should also marshal identically to the persisted state
+	if !statefile.StatesMarshalEqual(current, s.State()) {
+		t.Fatalf("Persisted state altered unexpectedly.\n\ngot:\n%s\nwant:\n%s", spew.Sdump(s.State()), spew.Sdump(current))
+	}
+}
+
+// TestFullInitialState is a state that should be snapshotted into a
+// full state manager before passing it into TestFull.
+func TestFullInitialState() *states.State {
+	state := states.NewState()
+	childMod := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	rAddr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "null_resource",
+		Name: "foo",
+	}
+	providerAddr := addrs.AbsProviderConfig{
+		Provider: addrs.NewDefaultProvider(rAddr.ImpliedProvider()),
+		Module:   addrs.RootModule,
+	}
+	childMod.SetResourceProvider(rAddr, providerAddr)
+
+	state.RootModule().SetOutputValue("sensitive_output", cty.StringVal("it's a secret"), true)
+	state.RootModule().SetOutputValue("nonsensitive_output", cty.StringVal("hello, world!"), false)
+
+	return state
+}
diff --git a/v1.5.7/internal/states/statemgr/transient.go b/v1.5.7/internal/states/statemgr/transient.go
new file mode 100644
index 0000000..1084db0
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/transient.go
@@ -0,0 +1,69 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+import "github.com/hashicorp/terraform/internal/states"
+
+// Transient is a union of the Reader and Writer interfaces, for types that
+// deal with transient snapshots.
+//
+// Transient snapshots are ones that are generally retained only locally and
+// to not create any historical version record when updated. Transient
+// snapshots are not expected to outlive a particular Terraform process,
+// and are not shared with any other process.
+//
+// A state manager type that is primarily concerned with persistent storage
+// may embed type Transient and then call State from its PersistState and
+// WriteState from its RefreshState in order to build on any existing
+// Transient implementation, such as the one returned by NewTransientInMemory.
+type Transient interface {
+	Reader
+	Writer
+}
+
+// Reader is the interface for managers that can return transient snapshots
+// of state.
+//
+// Retrieving the snapshot must not fail, so retrieving a snapshot from remote
+// storage (for example) should be dealt with elsewhere, often in an
+// implementation of Refresher. For a type that implements both Reader
+// and Refresher, it is okay for State to return nil if called before
+// a RefreshState call has completed.
+//
+// For a type that implements both Reader and Writer, State must return the
+// result of the most recently completed call to WriteState, and the state
+// manager must accept concurrent calls to both State and WriteState.
+//
+// Each caller of this function must get a distinct copy of the state, and
+// it must also be distinct from any instance cached inside the reader, to
+// ensure that mutations of the returned state will not affect the values
+// returned to other callers.
+type Reader interface {
+	// State returns the latest state.
+	//
+	// Each call to State returns an entirely-distinct copy of the state, with
+	// no storage shared with any other call, so the caller may freely mutate
+	// the returned object via the state APIs.
+	State() *states.State
+}
+
+// Writer is the interface for managers that can create transient snapshots
+// from state.
+//
+// Writer is the opposite of Reader, and so it must update whatever the State
+// method reads from. It does not write the state to any persistent
+// storage, and (for managers that support historical versions) must not
+// be recorded as a persistent new version of state.
+//
+// Implementations that cache the state in memory must take a deep copy of it,
+// since the caller may continue to modify the given state object after
+// WriteState returns.
+type Writer interface {
+	// WriteState saves a transient snapshot of the given state.
+	//
+	// The caller must ensure that the given state object is not concurrently
+	// modified while a WriteState call is in progress. WriteState itself
+	// will never modify the given state.
+	WriteState(*states.State) error
+}
diff --git a/v1.5.7/internal/states/statemgr/transient_inmem.go b/v1.5.7/internal/states/statemgr/transient_inmem.go
new file mode 100644
index 0000000..7854d1f
--- /dev/null
+++ b/v1.5.7/internal/states/statemgr/transient_inmem.go
@@ -0,0 +1,44 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package statemgr
+
+import (
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// NewTransientInMemory returns a Transient implementation that retains
+// transient snapshots only in memory, as part of the object.
+//
+// The given initial state, if any, must not be modified concurrently while
+// this function is running, but may be freely modified once this function
+// returns without affecting the stored transient snapshot.
+func NewTransientInMemory(initial *states.State) Transient {
+	return &transientInMemory{
+		current: initial.DeepCopy(),
+	}
+}
+
+type transientInMemory struct {
+	lock    sync.RWMutex
+	current *states.State
+}
+
+var _ Transient = (*transientInMemory)(nil)
+
+func (m *transientInMemory) State() *states.State {
+	m.lock.RLock()
+	defer m.lock.RUnlock()
+
+	return m.current.DeepCopy()
+}
+
+func (m *transientInMemory) WriteState(new *states.State) error {
+	m.lock.Lock()
+	defer m.lock.Unlock()
+
+	m.current = new.DeepCopy()
+	return nil
+}
diff --git a/v1.5.7/internal/states/sync.go b/v1.5.7/internal/states/sync.go
new file mode 100644
index 0000000..bfca09b
--- /dev/null
+++ b/v1.5.7/internal/states/sync.go
@@ -0,0 +1,576 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package states
+
+import (
+	"log"
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// SyncState is a wrapper around State that provides concurrency-safe access to
+// various common operations that occur during a Terraform graph walk, or other
+// similar concurrent contexts.
+//
+// When a SyncState wrapper is in use, no concurrent direct access to the
+// underlying objects is permitted unless the caller first acquires an explicit
+// lock, using the Lock and Unlock methods. Most callers should _not_
+// explicitly lock, and should instead use the other methods of this type that
+// handle locking automatically.
+//
+// Since SyncState is able to safely consolidate multiple updates into a single
+// atomic operation, many of its methods are at a higher level than those
+// of the underlying types, and operate on the state as a whole rather than
+// on individual sub-structures of the state.
+//
+// SyncState can only protect against races within its own methods. It cannot
+// provide any guarantees about the order in which concurrent operations will
+// be processed, so callers may still need to employ higher-level techniques
+// for ensuring correct operation sequencing, such as building and walking
+// a dependency graph.
+type SyncState struct {
+	state *State
+	lock  sync.RWMutex
+}
+
+// Module returns a snapshot of the state of the module instance with the given
+// address, or nil if no such module is tracked.
+//
+// The return value is a pointer to a copy of the module state, which the
+// caller may then freely access and mutate. However, since the module state
+// tends to be a large data structure with many child objects, where possible
+// callers should prefer to use a more granular accessor to access a child
+// module directly, and thus reduce the amount of copying required.
+func (s *SyncState) Module(addr addrs.ModuleInstance) *Module {
+	s.lock.RLock()
+	ret := s.state.Module(addr).DeepCopy()
+	s.lock.RUnlock()
+	return ret
+}
+
+// ModuleOutputs returns the set of OutputValues that matches the given path.
+func (s *SyncState) ModuleOutputs(parentAddr addrs.ModuleInstance, module addrs.ModuleCall) []*OutputValue {
+	s.lock.RLock()
+	defer s.lock.RUnlock()
+	var os []*OutputValue
+
+	for _, o := range s.state.ModuleOutputs(parentAddr, module) {
+		os = append(os, o.DeepCopy())
+	}
+	return os
+}
+
+// RemoveModule removes the entire state for the given module, taking with
+// it any resources associated with the module. This should generally be
+// called only for modules whose resources have all been destroyed, but
+// that is not enforced by this method.
+func (s *SyncState) RemoveModule(addr addrs.ModuleInstance) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	s.state.RemoveModule(addr)
+}
+
+// OutputValue returns a snapshot of the state of the output value with the
+// given address, or nil if no such output value is tracked.
+//
+// The return value is a pointer to a copy of the output value state, which the
+// caller may then freely access and mutate.
+func (s *SyncState) OutputValue(addr addrs.AbsOutputValue) *OutputValue {
+	s.lock.RLock()
+	ret := s.state.OutputValue(addr).DeepCopy()
+	s.lock.RUnlock()
+	return ret
+}
+
+// SetOutputValue writes a given output value into the state, overwriting
+// any existing value of the same name.
+//
+// If the module containing the output is not yet tracked in state then it
+// be added as a side-effect.
+func (s *SyncState) SetOutputValue(addr addrs.AbsOutputValue, value cty.Value, sensitive bool) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	ms := s.state.EnsureModule(addr.Module)
+	ms.SetOutputValue(addr.OutputValue.Name, value, sensitive)
+}
+
+// RemoveOutputValue removes the stored value for the output value with the
+// given address.
+//
+// If this results in its containing module being empty, the module will be
+// pruned from the state as a side-effect.
+func (s *SyncState) RemoveOutputValue(addr addrs.AbsOutputValue) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	ms := s.state.Module(addr.Module)
+	if ms == nil {
+		return
+	}
+	ms.RemoveOutputValue(addr.OutputValue.Name)
+	s.maybePruneModule(addr.Module)
+}
+
+// LocalValue returns the current value associated with the given local value
+// address.
+func (s *SyncState) LocalValue(addr addrs.AbsLocalValue) cty.Value {
+	s.lock.RLock()
+	// cty.Value is immutable, so we don't need any extra copying here.
+	ret := s.state.LocalValue(addr)
+	s.lock.RUnlock()
+	return ret
+}
+
+// SetLocalValue writes a given output value into the state, overwriting
+// any existing value of the same name.
+//
+// If the module containing the local value is not yet tracked in state then it
+// will be added as a side-effect.
+func (s *SyncState) SetLocalValue(addr addrs.AbsLocalValue, value cty.Value) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	ms := s.state.EnsureModule(addr.Module)
+	ms.SetLocalValue(addr.LocalValue.Name, value)
+}
+
+// RemoveLocalValue removes the stored value for the local value with the
+// given address.
+//
+// If this results in its containing module being empty, the module will be
+// pruned from the state as a side-effect.
+func (s *SyncState) RemoveLocalValue(addr addrs.AbsLocalValue) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	ms := s.state.Module(addr.Module)
+	if ms == nil {
+		return
+	}
+	ms.RemoveLocalValue(addr.LocalValue.Name)
+	s.maybePruneModule(addr.Module)
+}
+
+// Resource returns a snapshot of the state of the resource with the given
+// address, or nil if no such resource is tracked.
+//
+// The return value is a pointer to a copy of the resource state, which the
+// caller may then freely access and mutate.
+func (s *SyncState) Resource(addr addrs.AbsResource) *Resource {
+	s.lock.RLock()
+	ret := s.state.Resource(addr).DeepCopy()
+	s.lock.RUnlock()
+	return ret
+}
+
+// ResourceInstance returns a snapshot of the state the resource instance with
+// the given address, or nil if no such instance is tracked.
+//
+// The return value is a pointer to a copy of the instance state, which the
+// caller may then freely access and mutate.
+func (s *SyncState) ResourceInstance(addr addrs.AbsResourceInstance) *ResourceInstance {
+	s.lock.RLock()
+	ret := s.state.ResourceInstance(addr).DeepCopy()
+	s.lock.RUnlock()
+	return ret
+}
+
+// ResourceInstanceObject returns a snapshot of the current instance object
+// of the given generation belonging to the instance with the given address,
+// or nil if no such object is tracked..
+//
+// The return value is a pointer to a copy of the object, which the caller may
+// then freely access and mutate.
+func (s *SyncState) ResourceInstanceObject(addr addrs.AbsResourceInstance, gen Generation) *ResourceInstanceObjectSrc {
+	s.lock.RLock()
+	defer s.lock.RUnlock()
+
+	inst := s.state.ResourceInstance(addr)
+	if inst == nil {
+		return nil
+	}
+	return inst.GetGeneration(gen).DeepCopy()
+}
+
+// SetResourceMeta updates the resource-level metadata for the resource at
+// the given address, creating the containing module state and resource state
+// as a side-effect if not already present.
+func (s *SyncState) SetResourceProvider(addr addrs.AbsResource, provider addrs.AbsProviderConfig) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	ms := s.state.EnsureModule(addr.Module)
+	ms.SetResourceProvider(addr.Resource, provider)
+}
+
+// RemoveResource removes the entire state for the given resource, taking with
+// it any instances associated with the resource. This should generally be
+// called only for resource objects whose instances have all been destroyed,
+// but that is not enforced by this method. (Use RemoveResourceIfEmpty instead
+// to safely check first.)
+func (s *SyncState) RemoveResource(addr addrs.AbsResource) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	ms := s.state.EnsureModule(addr.Module)
+	ms.RemoveResource(addr.Resource)
+	s.maybePruneModule(addr.Module)
+}
+
+// RemoveResourceIfEmpty is similar to RemoveResource but first checks to
+// make sure there are no instances or objects left in the resource.
+//
+// Returns true if the resource was removed, or false if remaining child
+// objects prevented its removal. Returns true also if the resource was
+// already absent, and thus no action needed to be taken.
+func (s *SyncState) RemoveResourceIfEmpty(addr addrs.AbsResource) bool {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	ms := s.state.Module(addr.Module)
+	if ms == nil {
+		return true // nothing to do
+	}
+	rs := ms.Resource(addr.Resource)
+	if rs == nil {
+		return true // nothing to do
+	}
+	if len(rs.Instances) != 0 {
+		// We don't check here for the possibility of instances that exist
+		// but don't have any objects because it's the responsibility of the
+		// instance-mutation methods to prune those away automatically.
+		return false
+	}
+	ms.RemoveResource(addr.Resource)
+	s.maybePruneModule(addr.Module)
+	return true
+}
+
+// SetResourceInstanceCurrent saves the given instance object as the current
+// generation of the resource instance with the given address, simultaneously
+// updating the recorded provider configuration address, dependencies, and
+// resource EachMode.
+//
+// Any existing current instance object for the given resource is overwritten.
+// Set obj to nil to remove the primary generation object altogether. If there
+// are no deposed objects then the instance as a whole will be removed, which
+// may in turn also remove the containing module if it becomes empty.
+//
+// The caller must ensure that the given ResourceInstanceObject is not
+// concurrently mutated during this call, but may be freely used again once
+// this function returns.
+//
+// The provider address is a resource-wide settings and is updated
+// for all other instances of the same resource as a side-effect of this call.
+//
+// If the containing module for this resource or the resource itself are not
+// already tracked in state then they will be added as a side-effect.
+func (s *SyncState) SetResourceInstanceCurrent(addr addrs.AbsResourceInstance, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	ms := s.state.EnsureModule(addr.Module)
+	ms.SetResourceInstanceCurrent(addr.Resource, obj.DeepCopy(), provider)
+	s.maybePruneModule(addr.Module)
+}
+
+// SetResourceInstanceDeposed saves the given instance object as a deposed
+// generation of the resource instance with the given address and deposed key.
+//
+// Call this method only for pre-existing deposed objects that already have
+// a known DeposedKey. For example, this method is useful if reloading objects
+// that were persisted to a state file. To mark the current object as deposed,
+// use DeposeResourceInstanceObject instead.
+//
+// The caller must ensure that the given ResourceInstanceObject is not
+// concurrently mutated during this call, but may be freely used again once
+// this function returns.
+//
+// The resource that contains the given instance must already exist in the
+// state, or this method will panic. Use Resource to check first if its
+// presence is not already guaranteed.
+//
+// Any existing current instance object for the given resource and deposed key
+// is overwritten. Set obj to nil to remove the deposed object altogether. If
+// the instance is left with no objects after this operation then it will
+// be removed from its containing resource altogether.
+//
+// If the containing module for this resource or the resource itself are not
+// already tracked in state then they will be added as a side-effect.
+func (s *SyncState) SetResourceInstanceDeposed(addr addrs.AbsResourceInstance, key DeposedKey, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	ms := s.state.EnsureModule(addr.Module)
+	ms.SetResourceInstanceDeposed(addr.Resource, key, obj.DeepCopy(), provider)
+	s.maybePruneModule(addr.Module)
+}
+
+// DeposeResourceInstanceObject moves the current instance object for the
+// given resource instance address into the deposed set, leaving the instance
+// without a current object.
+//
+// The return value is the newly-allocated deposed key, or NotDeposed if the
+// given instance is already lacking a current object.
+//
+// If the containing module for this resource or the resource itself are not
+// already tracked in state then there cannot be a current object for the
+// given instance, and so NotDeposed will be returned without modifying the
+// state at all.
+func (s *SyncState) DeposeResourceInstanceObject(addr addrs.AbsResourceInstance) DeposedKey {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	ms := s.state.Module(addr.Module)
+	if ms == nil {
+		return NotDeposed
+	}
+
+	return ms.deposeResourceInstanceObject(addr.Resource, NotDeposed)
+}
+
+// DeposeResourceInstanceObjectForceKey is like DeposeResourceInstanceObject
+// but uses a pre-allocated key. It's the caller's responsibility to ensure
+// that there aren't any races to use a particular key; this method will panic
+// if the given key is already in use.
+func (s *SyncState) DeposeResourceInstanceObjectForceKey(addr addrs.AbsResourceInstance, forcedKey DeposedKey) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	if forcedKey == NotDeposed {
+		// Usage error: should use DeposeResourceInstanceObject in this case
+		panic("DeposeResourceInstanceObjectForceKey called without forced key")
+	}
+
+	ms := s.state.Module(addr.Module)
+	if ms == nil {
+		return // Nothing to do, since there can't be any current object either.
+	}
+
+	ms.deposeResourceInstanceObject(addr.Resource, forcedKey)
+}
+
+// ForgetResourceInstanceAll removes the record of all objects associated with
+// the specified resource instance, if present. If not present, this is a no-op.
+func (s *SyncState) ForgetResourceInstanceAll(addr addrs.AbsResourceInstance) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	ms := s.state.Module(addr.Module)
+	if ms == nil {
+		return
+	}
+	ms.ForgetResourceInstanceAll(addr.Resource)
+	s.maybePruneModule(addr.Module)
+}
+
+// ForgetResourceInstanceDeposed removes the record of the deposed object with
+// the given address and key, if present. If not present, this is a no-op.
+func (s *SyncState) ForgetResourceInstanceDeposed(addr addrs.AbsResourceInstance, key DeposedKey) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	ms := s.state.Module(addr.Module)
+	if ms == nil {
+		return
+	}
+	ms.ForgetResourceInstanceDeposed(addr.Resource, key)
+	s.maybePruneModule(addr.Module)
+}
+
+// MaybeRestoreResourceInstanceDeposed will restore the deposed object with the
+// given key on the specified resource as the current object for that instance
+// if and only if that would not cause us to forget an existing current
+// object for that instance.
+//
+// Returns true if the object was restored to current, or false if no change
+// was made at all.
+func (s *SyncState) MaybeRestoreResourceInstanceDeposed(addr addrs.AbsResourceInstance, key DeposedKey) bool {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	if key == NotDeposed {
+		panic("MaybeRestoreResourceInstanceDeposed called without DeposedKey")
+	}
+
+	ms := s.state.Module(addr.Module)
+	if ms == nil {
+		// Nothing to do, since the specified deposed object cannot exist.
+		return false
+	}
+
+	return ms.maybeRestoreResourceInstanceDeposed(addr.Resource, key)
+}
+
+// RemovePlannedResourceInstanceObjects removes from the state any resource
+// instance objects that have the status ObjectPlanned, indiciating that they
+// are just transient placeholders created during planning.
+//
+// Note that this does not restore any "ready" or "tainted" object that might
+// have been present before the planned object was written. The only real use
+// for this method is in preparing the state created during a refresh walk,
+// where we run the planning step for certain instances just to create enough
+// information to allow correct expression evaluation within provider and
+// data resource blocks. Discarding planned instances in that case is okay
+// because the refresh phase only creates planned objects to stand in for
+// objects that don't exist yet, and thus the planned object must have been
+// absent before by definition.
+func (s *SyncState) RemovePlannedResourceInstanceObjects() {
+	// TODO: Merge together the refresh and plan phases into a single walk,
+	// so we can remove the need to create this "partial plan" during refresh
+	// that we then need to clean up before proceeding.
+
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	for _, ms := range s.state.Modules {
+		moduleAddr := ms.Addr
+
+		for _, rs := range ms.Resources {
+			resAddr := rs.Addr.Resource
+
+			for ik, is := range rs.Instances {
+				instAddr := resAddr.Instance(ik)
+
+				if is.Current != nil && is.Current.Status == ObjectPlanned {
+					// Setting the current instance to nil removes it from the
+					// state altogether if there are not also deposed instances.
+					ms.SetResourceInstanceCurrent(instAddr, nil, rs.ProviderConfig)
+				}
+
+				for dk, obj := range is.Deposed {
+					// Deposed objects should never be "planned", but we'll
+					// do this anyway for the sake of completeness.
+					if obj.Status == ObjectPlanned {
+						ms.ForgetResourceInstanceDeposed(instAddr, dk)
+					}
+				}
+			}
+		}
+
+		// We may have deleted some objects, which means that we may have
+		// left a module empty, and so we must prune to preserve the invariant
+		// that only the root module is allowed to be empty.
+		s.maybePruneModule(moduleAddr)
+	}
+}
+
+// DiscardCheckResults discards any previously-recorded check results, with
+// the intent of preventing any references to them after they have become
+// stale due to starting (but possibly not completing) an update.
+func (s *SyncState) DiscardCheckResults() {
+	s.lock.Lock()
+	s.state.CheckResults = nil
+	s.lock.Unlock()
+}
+
+// RecordCheckResults replaces any check results already recorded in the state
+// with a new set taken from the given check state object.
+func (s *SyncState) RecordCheckResults(checkState *checks.State) {
+	newResults := NewCheckResults(checkState)
+	s.lock.Lock()
+	s.state.CheckResults = newResults
+	s.lock.Unlock()
+}
+
+// Lock acquires an explicit lock on the state, allowing direct read and write
+// access to the returned state object. The caller must call Unlock once
+// access is no longer needed, and then immediately discard the state pointer
+// pointer.
+//
+// Most callers should not use this. Instead, use the concurrency-safe
+// accessors and mutators provided directly on SyncState.
+func (s *SyncState) Lock() *State {
+	s.lock.Lock()
+	return s.state
+}
+
+// Unlock releases a lock previously acquired by Lock, at which point the
+// caller must cease all use of the state pointer that was returned.
+//
+// Do not call this method except to end an explicit lock acquired by
+// Lock. If a caller calls Unlock without first holding the lock, behavior
+// is undefined.
+func (s *SyncState) Unlock() {
+	s.lock.Unlock()
+}
+
+// Close extracts the underlying state from inside this wrapper, making the
+// wrapper invalid for any future operations.
+func (s *SyncState) Close() *State {
+	s.lock.Lock()
+	ret := s.state
+	s.state = nil // make sure future operations can't still modify it
+	s.lock.Unlock()
+	return ret
+}
+
+// maybePruneModule will remove a module from the state altogether if it is
+// empty, unless it's the root module which must always be present.
+//
+// This helper method is not concurrency-safe on its own, so must only be
+// called while the caller is already holding the lock for writing.
+func (s *SyncState) maybePruneModule(addr addrs.ModuleInstance) {
+	if addr.IsRoot() {
+		// We never prune the root.
+		return
+	}
+
+	ms := s.state.Module(addr)
+	if ms == nil {
+		return
+	}
+
+	if ms.empty() {
+		log.Printf("[TRACE] states.SyncState: pruning %s because it is empty", addr)
+		s.state.RemoveModule(addr)
+	}
+}
+
+func (s *SyncState) MoveAbsResource(src, dst addrs.AbsResource) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	s.state.MoveAbsResource(src, dst)
+}
+
+func (s *SyncState) MaybeMoveAbsResource(src, dst addrs.AbsResource) bool {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	return s.state.MaybeMoveAbsResource(src, dst)
+}
+
+func (s *SyncState) MoveResourceInstance(src, dst addrs.AbsResourceInstance) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	s.state.MoveAbsResourceInstance(src, dst)
+}
+
+func (s *SyncState) MaybeMoveResourceInstance(src, dst addrs.AbsResourceInstance) bool {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	return s.state.MaybeMoveAbsResourceInstance(src, dst)
+}
+
+func (s *SyncState) MoveModuleInstance(src, dst addrs.ModuleInstance) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	s.state.MoveModuleInstance(src, dst)
+}
+
+func (s *SyncState) MaybeMoveModuleInstance(src, dst addrs.ModuleInstance) bool {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	return s.state.MaybeMoveModuleInstance(src, dst)
+}
diff --git a/v1.5.7/internal/terminal/impl_others.go b/v1.5.7/internal/terminal/impl_others.go
new file mode 100644
index 0000000..8522392
--- /dev/null
+++ b/v1.5.7/internal/terminal/impl_others.go
@@ -0,0 +1,57 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build !windows
+// +build !windows
+
+package terminal
+
+import (
+	"os"
+
+	"golang.org/x/term"
+)
+
+// This is the implementation for all operating systems except Windows, where
+// we don't expect to need to do any special initialization to get a working
+// Virtual Terminal.
+//
+// For this implementation we just delegate everything upstream to
+// golang.org/x/term, since it already has a variety of different
+// implementations for quirks of more esoteric operating systems like plan9,
+// and will hopefully grow to include others as Go is ported to other platforms
+// in future.
+//
+// For operating systems that golang.org/x/term doesn't support either, it
+// defaults to indicating that nothing is a terminal and returns an error when
+// asked for a size, which we'll handle below.
+
+func configureOutputHandle(f *os.File) (*OutputStream, error) {
+	return &OutputStream{
+		File:       f,
+		isTerminal: isTerminalGolangXTerm,
+		getColumns: getColumnsGolangXTerm,
+	}, nil
+}
+
+func configureInputHandle(f *os.File) (*InputStream, error) {
+	return &InputStream{
+		File:       f,
+		isTerminal: isTerminalGolangXTerm,
+	}, nil
+}
+
+func isTerminalGolangXTerm(f *os.File) bool {
+	return term.IsTerminal(int(f.Fd()))
+}
+
+func getColumnsGolangXTerm(f *os.File) int {
+	width, _, err := term.GetSize(int(f.Fd()))
+	if err != nil {
+		// Suggests that it's either not a terminal at all or that we're on
+		// a platform that golang.org/x/term doesn't support. In both cases
+		// we'll just return the placeholder default value.
+		return defaultColumns
+	}
+	return width
+}
diff --git a/v1.5.7/internal/terminal/impl_windows.go b/v1.5.7/internal/terminal/impl_windows.go
new file mode 100644
index 0000000..0f94644
--- /dev/null
+++ b/v1.5.7/internal/terminal/impl_windows.go
@@ -0,0 +1,165 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build windows
+// +build windows
+
+package terminal
+
+import (
+	"fmt"
+	"os"
+	"syscall"
+
+	"golang.org/x/sys/windows"
+
+	// We're continuing to use this third-party library on Windows because it
+	// has the additional IsCygwinTerminal function, which includes some useful
+	// heuristics for recognizing when a pipe seems to be connected to a
+	// legacy terminal emulator on Windows versions that lack true pty support.
+	// We now use golang.org/x/term's functionality on other platforms.
+	isatty "github.com/mattn/go-isatty"
+)
+
+func configureOutputHandle(f *os.File) (*OutputStream, error) {
+	ret := &OutputStream{
+		File: f,
+	}
+
+	if fd := f.Fd(); isatty.IsTerminal(fd) {
+		// We have a few things to deal with here:
+		// - Activating UTF-8 output support (mandatory)
+		// - Activating virtual terminal support (optional)
+		// These will not succeed on Windows 8 or early versions of Windows 10.
+
+		// UTF-8 support means switching the console "code page" to CP_UTF8.
+		// Notice that this doesn't take the specific file descriptor, because
+		// the console is just ambiently associated with our process.
+		err := SetConsoleOutputCP(CP_UTF8)
+		if err != nil {
+			return nil, fmt.Errorf("failed to set the console to UTF-8 mode; you may need to use a newer version of Windows: %s", err)
+		}
+
+		// If the console also allows us to turn on
+		// ENABLE_VIRTUAL_TERMINAL_PROCESSING then we can potentially use VT
+		// output, although the methods of Settings will make the final
+		// determination on that because we might have some handles pointing at
+		// terminals and other handles pointing at files/pipes.
+		ret.getColumns = getColumnsWindowsConsole
+		var mode uint32
+		err = windows.GetConsoleMode(windows.Handle(fd), &mode)
+		if err != nil {
+			return ret, nil // We'll treat this as success but without VT support
+		}
+		mode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
+		err = windows.SetConsoleMode(windows.Handle(fd), mode)
+		if err != nil {
+			return ret, nil // We'll treat this as success but without VT support
+		}
+
+		// If we get here then we've successfully turned on VT processing, so
+		// we can return an OutputStream that answers true when asked if it
+		// is a Terminal.
+		ret.isTerminal = staticTrue
+		return ret, nil
+
+	} else if isatty.IsCygwinTerminal(fd) {
+		// Cygwin terminals -- and other VT100 "fakers" for older versions of
+		// Windows -- are not really terminals in the usual sense, but rather
+		// are pipes between the child process (Terraform) and the terminal
+		// emulator. isatty.IsCygwinTerminal uses some heuristics to
+		// distinguish those pipes from other pipes we might see if the user
+		// were, for example, using the | operator on the command line.
+		// If we get in here then we'll assume that we can send VT100 sequences
+		// to this stream, even though it isn't a terminal in the usual sense.
+
+		ret.isTerminal = staticTrue
+		// TODO: Is it possible to detect the width of these fake terminals?
+		return ret, nil
+	}
+
+	// If we fall out here then we have a non-terminal filehandle, so we'll
+	// just accept all of the default OutputStream behaviors
+	return ret, nil
+}
+
+func configureInputHandle(f *os.File) (*InputStream, error) {
+	ret := &InputStream{
+		File: f,
+	}
+
+	if fd := f.Fd(); isatty.IsTerminal(fd) {
+		// We have to activate UTF-8 input, or else we fail. This will not
+		// succeed on Windows 8 or early versions of Windows 10.
+		// Notice that this doesn't take the specific file descriptor, because
+		// the console is just ambiently associated with our process.
+		err := SetConsoleCP(CP_UTF8)
+		if err != nil {
+			return nil, fmt.Errorf("failed to set the console to UTF-8 mode; you may need to use a newer version of Windows: %s", err)
+		}
+		ret.isTerminal = staticTrue
+		return ret, nil
+	} else if isatty.IsCygwinTerminal(fd) {
+		// As with the output handles above, we'll use isatty's heuristic to
+		// pretend that a pipe from mintty or a similar userspace terminal
+		// emulator is actually a terminal.
+		ret.isTerminal = staticTrue
+		return ret, nil
+	}
+
+	// If we fall out here then we have a non-terminal filehandle, so we'll
+	// just accept all of the default InputStream behaviors
+	return ret, nil
+}
+
+func getColumnsWindowsConsole(f *os.File) int {
+	// We'll just unconditionally ask the given file for its console buffer
+	// info here, and let it fail if the file isn't actually a console.
+	// (In practice, the init functions above only hook up this function
+	// if the handle looks like a console, so this should succeed.)
+	var info windows.ConsoleScreenBufferInfo
+	err := windows.GetConsoleScreenBufferInfo(windows.Handle(f.Fd()), &info)
+	if err != nil {
+		return defaultColumns
+	}
+	return int(info.Size.X)
+}
+
+// Unfortunately not all of the Windows kernel functions we need are in
+// x/sys/windows at the time of writing, so we need to call some of them
+// directly. (If you're maintaining this in future and have the capacity to
+// test it well, consider checking if these functions have been added upstream
+// yet and switch to their wrapper stubs if so.
+var modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
+var procSetConsoleCP = modkernel32.NewProc("SetConsoleCP")
+var procSetConsoleOutputCP = modkernel32.NewProc("SetConsoleOutputCP")
+
+const CP_UTF8 = 65001
+
+// (These are written in the style of the stubs in x/sys/windows, which is
+// a little non-idiomatic just due to the awkwardness of the low-level syscall
+// interface.)
+
+func SetConsoleCP(codepageID uint32) (err error) {
+	r1, _, e1 := syscall.Syscall(procSetConsoleCP.Addr(), 1, uintptr(codepageID), 0, 0)
+	if r1 == 0 {
+		err = e1
+	}
+	return
+}
+
+func SetConsoleOutputCP(codepageID uint32) (err error) {
+	r1, _, e1 := syscall.Syscall(procSetConsoleOutputCP.Addr(), 1, uintptr(codepageID), 0, 0)
+	if r1 == 0 {
+		err = e1
+	}
+	return
+}
+
+func staticTrue(f *os.File) bool {
+	return true
+}
+
+func staticFalse(f *os.File) bool {
+	return false
+}
diff --git a/v1.5.7/internal/terminal/stream.go b/v1.5.7/internal/terminal/stream.go
new file mode 100644
index 0000000..afeec73
--- /dev/null
+++ b/v1.5.7/internal/terminal/stream.go
@@ -0,0 +1,83 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terminal
+
+import (
+	"os"
+)
+
+const defaultColumns int = 78
+const defaultIsTerminal bool = false
+
+// OutputStream represents an output stream that might or might not be connected
+// to a terminal.
+//
+// There are typically two instances of this: one representing stdout and one
+// representing stderr.
+type OutputStream struct {
+	File *os.File
+
+	// Interacting with a terminal is typically platform-specific, so we
+	// factor out these into virtual functions, although we have default
+	// behaviors suitable for non-Terminal output if any of these isn't
+	// set. (We're using function pointers rather than interfaces for this
+	// because it allows us to mix both normal methods and virtual methods
+	// on the same type, without a bunch of extra complexity.)
+	isTerminal func(*os.File) bool
+	getColumns func(*os.File) int
+}
+
+// Columns returns a number of character cell columns that we expect will
+// fill the width of the terminal that stdout is connected to, or a reasonable
+// placeholder value of 78 if the output doesn't seem to be a terminal.
+//
+// This is a best-effort sort of function which may give an inaccurate result
+// in various cases. For example, callers storing the result will not react
+// to subsequent changes in the terminal width, and indeed this function itself
+// may not be able to either, depending on the constraints of the current
+// execution context.
+func (s *OutputStream) Columns() int {
+	if s.getColumns == nil {
+		return defaultColumns
+	}
+	return s.getColumns(s.File)
+}
+
+// IsTerminal returns true if we expect that the stream is connected to a
+// terminal which supports VT100-style formatting and cursor control sequences.
+func (s *OutputStream) IsTerminal() bool {
+	if s.isTerminal == nil {
+		return defaultIsTerminal
+	}
+	return s.isTerminal(s.File)
+}
+
+// InputStream represents an input stream that might or might not be a terminal.
+//
+// There is typically only one instance of this type, representing stdin.
+type InputStream struct {
+	File *os.File
+
+	// Interacting with a terminal is typically platform-specific, so we
+	// factor out these into virtual functions, although we have default
+	// behaviors suitable for non-Terminal output if any of these isn't
+	// set. (We're using function pointers rather than interfaces for this
+	// because it allows us to mix both normal methods and virtual methods
+	// on the same type, without a bunch of extra complexity.)
+	isTerminal func(*os.File) bool
+}
+
+// IsTerminal returns true if we expect that the stream is connected to a
+// terminal which can support interactive input.
+//
+// If this returns false, callers might prefer to skip elaborate input prompt
+// functionality like tab completion and instead just treat the input as a
+// raw byte stream, or perhaps skip prompting for input at all depending on the
+// situation.
+func (s *InputStream) IsTerminal() bool {
+	if s.isTerminal == nil {
+		return defaultIsTerminal
+	}
+	return s.isTerminal(s.File)
+}
diff --git a/v1.5.7/internal/terminal/streams.go b/v1.5.7/internal/terminal/streams.go
new file mode 100644
index 0000000..af2bdc9
--- /dev/null
+++ b/v1.5.7/internal/terminal/streams.go
@@ -0,0 +1,108 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package terminal encapsulates some platform-specific logic for detecting
+// if we're running in a terminal and, if so, properly configuring that
+// terminal to meet the assumptions that the rest of Terraform makes.
+//
+// Specifically, Terraform requires a Terminal which supports virtual terminal
+// sequences and which accepts UTF-8-encoded text.
+//
+// This is an abstraction only over the platform-specific detection of and
+// possibly initialization of terminals. It's not intended to provide
+// higher-level abstractions of the sort provided by packages like termcap or
+// curses; ultimately we just assume that terminals are "standard" VT100-like
+// terminals and use a subset of control codes that works across the various
+// platforms we support. Our approximate target is "xterm-compatible"
+// virtual terminals.
+package terminal
+
+import (
+	"fmt"
+	"os"
+)
+
+// Streams represents a collection of three streams that each may or may not
+// be connected to a terminal.
+//
+// If a stream is connected to a terminal then there are more possibilities
+// available, such as detecting the current terminal width. If we're connected
+// to something else, such as a pipe or a file on disk, the stream will
+// typically provide placeholder values or do-nothing stubs for
+// terminal-requiring operatons.
+//
+// Note that it's possible for only a subset of the streams to be connected
+// to a terminal. For example, this happens if the user runs Terraform with
+// I/O redirection where Stdout might refer to a regular disk file while Stderr
+// refers to a terminal, or various other similar combinations.
+type Streams struct {
+	Stdout *OutputStream
+	Stderr *OutputStream
+	Stdin  *InputStream
+}
+
+// Init tries to initialize a terminal, if Terraform is running in one, and
+// returns an object describing what it was able to set up.
+//
+// An error for this function indicates that the current execution context
+// can't meet Terraform's assumptions. For example, on Windows Init will return
+// an error if Terraform is running in a Windows Console that refuses to
+// activate UTF-8 mode, which can happen if we're running on an unsupported old
+// version of Windows.
+//
+// Note that the success of this function doesn't mean that we're actually
+// running in a terminal. It could also represent successfully detecting that
+// one or more of the input/output streams is not a terminal.
+func Init() (*Streams, error) {
+	// These configure* functions are platform-specific functions in other
+	// files that use //+build constraints to vary based on target OS.
+
+	stderr, err := configureOutputHandle(os.Stderr)
+	if err != nil {
+		return nil, err
+	}
+	stdout, err := configureOutputHandle(os.Stdout)
+	if err != nil {
+		return nil, err
+	}
+	stdin, err := configureInputHandle(os.Stdin)
+	if err != nil {
+		return nil, err
+	}
+
+	return &Streams{
+		Stdout: stdout,
+		Stderr: stderr,
+		Stdin:  stdin,
+	}, nil
+}
+
+// Print is a helper for conveniently calling fmt.Fprint on the Stdout stream.
+func (s *Streams) Print(a ...interface{}) (n int, err error) {
+	return fmt.Fprint(s.Stdout.File, a...)
+}
+
+// Printf is a helper for conveniently calling fmt.Fprintf on the Stdout stream.
+func (s *Streams) Printf(format string, a ...interface{}) (n int, err error) {
+	return fmt.Fprintf(s.Stdout.File, format, a...)
+}
+
+// Println is a helper for conveniently calling fmt.Fprintln on the Stdout stream.
+func (s *Streams) Println(a ...interface{}) (n int, err error) {
+	return fmt.Fprintln(s.Stdout.File, a...)
+}
+
+// Eprint is a helper for conveniently calling fmt.Fprint on the Stderr stream.
+func (s *Streams) Eprint(a ...interface{}) (n int, err error) {
+	return fmt.Fprint(s.Stderr.File, a...)
+}
+
+// Eprintf is a helper for conveniently calling fmt.Fprintf on the Stderr stream.
+func (s *Streams) Eprintf(format string, a ...interface{}) (n int, err error) {
+	return fmt.Fprintf(s.Stderr.File, format, a...)
+}
+
+// Eprintln is a helper for conveniently calling fmt.Fprintln on the Stderr stream.
+func (s *Streams) Eprintln(a ...interface{}) (n int, err error) {
+	return fmt.Fprintln(s.Stderr.File, a...)
+}
diff --git a/v1.5.7/internal/terminal/streams_test.go b/v1.5.7/internal/terminal/streams_test.go
new file mode 100644
index 0000000..4735876
--- /dev/null
+++ b/v1.5.7/internal/terminal/streams_test.go
@@ -0,0 +1,41 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terminal
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+)
+
+func TestStreamsFmtHelpers(t *testing.T) {
+	streams, close := StreamsForTesting(t)
+
+	streams.Print("stdout print ", 5, "\n")
+	streams.Eprint("stderr print ", 6, "\n")
+	streams.Println("stdout println", 7)
+	streams.Eprintln("stderr println", 8)
+	streams.Printf("stdout printf %d\n", 9)
+	streams.Eprintf("stderr printf %d\n", 10)
+
+	outp := close(t)
+
+	gotOut := outp.Stdout()
+	wantOut := `stdout print 5
+stdout println 7
+stdout printf 9
+`
+	if diff := cmp.Diff(wantOut, gotOut); diff != "" {
+		t.Errorf("wrong stdout\n%s", diff)
+	}
+
+	gotErr := outp.Stderr()
+	wantErr := `stderr print 6
+stderr println 8
+stderr printf 10
+`
+	if diff := cmp.Diff(wantErr, gotErr); diff != "" {
+		t.Errorf("wrong stderr\n%s", diff)
+	}
+}
diff --git a/v1.5.7/internal/terminal/testing.go b/v1.5.7/internal/terminal/testing.go
new file mode 100644
index 0000000..11b907f
--- /dev/null
+++ b/v1.5.7/internal/terminal/testing.go
@@ -0,0 +1,194 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terminal
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"strings"
+	"sync"
+	"testing"
+)
+
+// StreamsForTesting is a helper for test code that is aiming to test functions
+// that interact with the input and output streams.
+//
+// This particular function is for the simple case of a function that only
+// produces output: the returned input stream is connected to the system's
+// "null device", as if a user had run Terraform with I/O redirection like
+// </dev/null on Unix. It also configures the output as a pipe rather than
+// as a terminal, and so can't be used to test whether code is able to adapt
+// to different terminal widths.
+//
+// The return values are a Streams object ready to pass into a function under
+// test, and a callback function for the test itself to call afterwards
+// in order to obtain any characters that were written to the streams. Once
+// you call the close function, the Streams object becomes invalid and must
+// not be used anymore. Any caller of this function _must_ call close before
+// its test concludes, even if it doesn't intend to check the output, or else
+// it will leak resources.
+//
+// Since this function is for testing only, for convenience it will react to
+// any setup errors by logging a message to the given testing.T object and
+// then failing the test, preventing any later code from running.
+func StreamsForTesting(t *testing.T) (streams *Streams, close func(*testing.T) *TestOutput) {
+	stdinR, err := os.Open(os.DevNull)
+	if err != nil {
+		t.Fatalf("failed to open /dev/null to represent stdin: %s", err)
+	}
+
+	// (Although we only have StreamsForTesting right now, it seems plausible
+	// that we'll want some other similar helpers for more complicated
+	// situations, such as codepaths that need to read from Stdin or
+	// tests for whether a function responds properly to terminal width.
+	// In that case, we'd probably want to factor out the core guts of this
+	// which set up the pipe *os.File values and the goroutines, but then
+	// let each caller produce its own Streams wrapping around those. For
+	// now though, it's simpler to just have this whole implementation together
+	// in one function.)
+
+	// Our idea of streams is only a very thin wrapper around OS-level file
+	// descriptors, so in order to produce a realistic implementation for
+	// the code under test while still allowing us to capture the output
+	// we'll OS-level pipes and concurrently copy anything we read from
+	// them into the output object.
+	outp := &TestOutput{}
+	var lock sync.Mutex // hold while appending to outp
+	stdoutR, stdoutW, err := os.Pipe()
+	if err != nil {
+		t.Fatalf("failed to create stdout pipe: %s", err)
+	}
+	stderrR, stderrW, err := os.Pipe()
+	if err != nil {
+		t.Fatalf("failed to create stderr pipe: %s", err)
+	}
+	var wg sync.WaitGroup // for waiting until our goroutines have exited
+
+	// We need an extra goroutine for each of the pipes so we can block
+	// on reading both of them alongside the caller hopefully writing to
+	// the write sides.
+	wg.Add(2)
+	consume := func(r *os.File, isErr bool) {
+		var buf [1024]byte
+		for {
+			n, err := r.Read(buf[:])
+			if err != nil {
+				if err != io.EOF {
+					// We aren't allowed to write to the testing.T from
+					// a different goroutine than it was created on, but
+					// encountering other errors would be weird here anyway
+					// so we'll just panic. (If we were to just ignore this
+					// and then drop out of the loop then we might deadlock
+					// anyone still trying to write to the write end.)
+					panic(fmt.Sprintf("failed to read from pipe: %s", err))
+				}
+				break
+			}
+			lock.Lock()
+			outp.parts = append(outp.parts, testOutputPart{
+				isErr: isErr,
+				bytes: append(([]byte)(nil), buf[:n]...), // copy so we can reuse the buffer
+			})
+			lock.Unlock()
+		}
+		wg.Done()
+	}
+	go consume(stdoutR, false)
+	go consume(stderrR, true)
+
+	close = func(t *testing.T) *TestOutput {
+		err := stdinR.Close()
+		if err != nil {
+			t.Errorf("failed to close stdin handle: %s", err)
+		}
+
+		// We'll close both of the writer streams now, which should in turn
+		// cause both of the "consume" goroutines above to terminate by
+		// encountering io.EOF.
+		err = stdoutW.Close()
+		if err != nil {
+			t.Errorf("failed to close stdout pipe: %s", err)
+		}
+		err = stderrW.Close()
+		if err != nil {
+			t.Errorf("failed to close stderr pipe: %s", err)
+		}
+
+		// The above error cases still allow this to complete and thus
+		// potentially allow the test to report its own result, but will
+		// ensure that the test doesn't pass while also leaking resources.
+
+		// Wait for the stream-copying goroutines to finish anything they
+		// are working on before we return, or else we might miss some
+		// late-arriving writes.
+		wg.Wait()
+		return outp
+	}
+
+	return &Streams{
+		Stdout: &OutputStream{
+			File: stdoutW,
+		},
+		Stderr: &OutputStream{
+			File: stderrW,
+		},
+		Stdin: &InputStream{
+			File: stdinR,
+		},
+	}, close
+}
+
+// TestOutput is a type used to return the results from the various stream
+// testing helpers. It encapsulates any captured writes to the output and
+// error streams, and has methods to consume that data in some different ways
+// to allow for a few different styles of testing.
+type TestOutput struct {
+	parts []testOutputPart
+}
+
+type testOutputPart struct {
+	// isErr is true if this part was written to the error stream, or false
+	// if it was written to the output stream.
+	isErr bool
+
+	// bytes are the raw bytes that were written
+	bytes []byte
+}
+
+// All returns the output written to both the Stdout and Stderr streams,
+// interleaved together in the order of writing in a single string.
+func (o TestOutput) All() string {
+	buf := &strings.Builder{}
+	for _, part := range o.parts {
+		buf.Write(part.bytes)
+	}
+	return buf.String()
+}
+
+// Stdout returns the output written to just the Stdout stream, ignoring
+// anything that was written to the Stderr stream.
+func (o TestOutput) Stdout() string {
+	buf := &strings.Builder{}
+	for _, part := range o.parts {
+		if part.isErr {
+			continue
+		}
+		buf.Write(part.bytes)
+	}
+	return buf.String()
+}
+
+// Stderr returns the output written to just the Stderr stream, ignoring
+// anything that was written to the Stdout stream.
+func (o TestOutput) Stderr() string {
+	buf := &strings.Builder{}
+	for _, part := range o.parts {
+		if !part.isErr {
+			continue
+		}
+		buf.Write(part.bytes)
+	}
+	return buf.String()
+}
diff --git a/v1.5.7/internal/terraform/context.go b/v1.5.7/internal/terraform/context.go
new file mode 100644
index 0000000..35e3a69
--- /dev/null
+++ b/v1.5.7/internal/terraform/context.go
@@ -0,0 +1,440 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"sort"
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// InputMode defines what sort of input will be asked for when Input
+// is called on Context.
+type InputMode byte
+
+const (
+	// InputModeProvider asks for provider variables
+	InputModeProvider InputMode = 1 << iota
+
+	// InputModeStd is the standard operating mode and asks for both variables
+	// and providers.
+	InputModeStd = InputModeProvider
+)
+
+// ContextOpts are the user-configurable options to create a context with
+// NewContext.
+type ContextOpts struct {
+	Meta         *ContextMeta
+	Hooks        []Hook
+	Parallelism  int
+	Providers    map[addrs.Provider]providers.Factory
+	Provisioners map[string]provisioners.Factory
+
+	UIInput UIInput
+}
+
+// ContextMeta is metadata about the running context. This is information
+// that this package or structure cannot determine on its own but exposes
+// into Terraform in various ways. This must be provided by the Context
+// initializer.
+type ContextMeta struct {
+	Env string // Env is the state environment
+
+	// OriginalWorkingDir is the working directory where the Terraform CLI
+	// was run from, which may no longer actually be the current working
+	// directory if the user included the -chdir=... option.
+	//
+	// If this string is empty then the original working directory is the same
+	// as the current working directory.
+	//
+	// In most cases we should respect the user's override by ignoring this
+	// path and just using the current working directory, but this is here
+	// for some exceptional cases where the original working directory is
+	// needed.
+	OriginalWorkingDir string
+}
+
+// Context represents all the context that Terraform needs in order to
+// perform operations on infrastructure. This structure is built using
+// NewContext.
+type Context struct {
+	// meta captures some misc. information about the working directory where
+	// we're taking these actions, and thus which should remain steady between
+	// operations.
+	meta *ContextMeta
+
+	plugins *contextPlugins
+
+	hooks   []Hook
+	sh      *stopHook
+	uiInput UIInput
+
+	l                   sync.Mutex // Lock acquired during any task
+	parallelSem         Semaphore
+	providerInputConfig map[string]map[string]cty.Value
+	runCond             *sync.Cond
+	runContext          context.Context
+	runContextCancel    context.CancelFunc
+}
+
+// (additional methods on Context can be found in context_*.go files.)
+
+// NewContext creates a new Context structure.
+//
+// Once a Context is created, the caller must not access or mutate any of
+// the objects referenced (directly or indirectly) by the ContextOpts fields.
+//
+// If the returned diagnostics contains errors then the resulting context is
+// invalid and must not be used.
+func NewContext(opts *ContextOpts) (*Context, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	log.Printf("[TRACE] terraform.NewContext: starting")
+
+	// Copy all the hooks and add our stop hook. We don't append directly
+	// to the Config so that we're not modifying that in-place.
+	sh := new(stopHook)
+	hooks := make([]Hook, len(opts.Hooks)+1)
+	copy(hooks, opts.Hooks)
+	hooks[len(opts.Hooks)] = sh
+
+	// Determine parallelism, default to 10. We do this both to limit
+	// CPU pressure but also to have an extra guard against rate throttling
+	// from providers.
+	// We throw an error in case of negative parallelism
+	par := opts.Parallelism
+	if par < 0 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid parallelism value",
+			fmt.Sprintf("The parallelism must be a positive value. Not %d.", par),
+		))
+		return nil, diags
+	}
+
+	if par == 0 {
+		par = 10
+	}
+
+	plugins := newContextPlugins(opts.Providers, opts.Provisioners)
+
+	log.Printf("[TRACE] terraform.NewContext: complete")
+
+	return &Context{
+		hooks:   hooks,
+		meta:    opts.Meta,
+		uiInput: opts.UIInput,
+
+		plugins: plugins,
+
+		parallelSem:         NewSemaphore(par),
+		providerInputConfig: make(map[string]map[string]cty.Value),
+		sh:                  sh,
+	}, diags
+}
+
+func (c *Context) Schemas(config *configs.Config, state *states.State) (*Schemas, tfdiags.Diagnostics) {
+	// TODO: This method gets called multiple times on the same context with
+	// the same inputs by different parts of Terraform that all need the
+	// schemas, and it's typically quite expensive because it has to spin up
+	// plugins to gather their schemas, so it'd be good to have some caching
+	// here to remember plugin schemas we already loaded since the plugin
+	// selections can't change during the life of a *Context object.
+
+	var diags tfdiags.Diagnostics
+
+	ret, err := loadSchemas(config, state, c.plugins)
+	if err != nil {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to load plugin schemas",
+			fmt.Sprintf("Error while loading schemas for plugin components: %s.", err),
+		))
+		return nil, diags
+	}
+	return ret, diags
+}
+
+type ContextGraphOpts struct {
+	// If true, validates the graph structure (checks for cycles).
+	Validate bool
+
+	// Legacy graphs only: won't prune the graph
+	Verbose bool
+}
+
+// Stop stops the running task.
+//
+// Stop will block until the task completes.
+func (c *Context) Stop() {
+	log.Printf("[WARN] terraform: Stop called, initiating interrupt sequence")
+
+	c.l.Lock()
+	defer c.l.Unlock()
+
+	// If we're running, then stop
+	if c.runContextCancel != nil {
+		log.Printf("[WARN] terraform: run context exists, stopping")
+
+		// Tell the hook we want to stop
+		c.sh.Stop()
+
+		// Stop the context
+		c.runContextCancel()
+		c.runContextCancel = nil
+	}
+
+	// Notify all of the hooks that we're stopping, in case they want to try
+	// to flush in-memory state to disk before a subsequent hard kill.
+	for _, hook := range c.hooks {
+		hook.Stopping()
+	}
+
+	// Grab the condition var before we exit
+	if cond := c.runCond; cond != nil {
+		log.Printf("[INFO] terraform: waiting for graceful stop to complete")
+		cond.Wait()
+	}
+
+	log.Printf("[WARN] terraform: stop complete")
+}
+
+func (c *Context) acquireRun(phase string) func() {
+	// With the run lock held, grab the context lock to make changes
+	// to the run context.
+	c.l.Lock()
+	defer c.l.Unlock()
+
+	// Wait until we're no longer running
+	for c.runCond != nil {
+		c.runCond.Wait()
+	}
+
+	// Build our lock
+	c.runCond = sync.NewCond(&c.l)
+
+	// Create a new run context
+	c.runContext, c.runContextCancel = context.WithCancel(context.Background())
+
+	// Reset the stop hook so we're not stopped
+	c.sh.Reset()
+
+	return c.releaseRun
+}
+
+func (c *Context) releaseRun() {
+	// Grab the context lock so that we can make modifications to fields
+	c.l.Lock()
+	defer c.l.Unlock()
+
+	// End our run. We check if runContext is non-nil because it can be
+	// set to nil if it was cancelled via Stop()
+	if c.runContextCancel != nil {
+		c.runContextCancel()
+	}
+
+	// Unlock all waiting our condition
+	cond := c.runCond
+	c.runCond = nil
+	cond.Broadcast()
+
+	// Unset the context
+	c.runContext = nil
+}
+
+// watchStop immediately returns a `stop` and a `wait` chan after dispatching
+// the watchStop goroutine. This will watch the runContext for cancellation and
+// stop the providers accordingly.  When the watch is no longer needed, the
+// `stop` chan should be closed before waiting on the `wait` chan.
+// The `wait` chan is important, because without synchronizing with the end of
+// the watchStop goroutine, the runContext may also be closed during the select
+// incorrectly causing providers to be stopped. Even if the graph walk is done
+// at that point, stopping a provider permanently cancels its StopContext which
+// can cause later actions to fail.
+func (c *Context) watchStop(walker *ContextGraphWalker) (chan struct{}, <-chan struct{}) {
+	stop := make(chan struct{})
+	wait := make(chan struct{})
+
+	// get the runContext cancellation channel now, because releaseRun will
+	// write to the runContext field.
+	done := c.runContext.Done()
+
+	go func() {
+		defer logging.PanicHandler()
+
+		defer close(wait)
+		// Wait for a stop or completion
+		select {
+		case <-done:
+			// done means the context was canceled, so we need to try and stop
+			// providers.
+		case <-stop:
+			// our own stop channel was closed.
+			return
+		}
+
+		// If we're here, we're stopped, trigger the call.
+		log.Printf("[TRACE] Context: requesting providers and provisioners to gracefully stop")
+
+		{
+			// Copy the providers so that a misbehaved blocking Stop doesn't
+			// completely hang Terraform.
+			walker.providerLock.Lock()
+			ps := make([]providers.Interface, 0, len(walker.providerCache))
+			for _, p := range walker.providerCache {
+				ps = append(ps, p)
+			}
+			defer walker.providerLock.Unlock()
+
+			for _, p := range ps {
+				// We ignore the error for now since there isn't any reasonable
+				// action to take if there is an error here, since the stop is still
+				// advisory: Terraform will exit once the graph node completes.
+				p.Stop()
+			}
+		}
+
+		{
+			// Call stop on all the provisioners
+			walker.provisionerLock.Lock()
+			ps := make([]provisioners.Interface, 0, len(walker.provisionerCache))
+			for _, p := range walker.provisionerCache {
+				ps = append(ps, p)
+			}
+			defer walker.provisionerLock.Unlock()
+
+			for _, p := range ps {
+				// We ignore the error for now since there isn't any reasonable
+				// action to take if there is an error here, since the stop is still
+				// advisory: Terraform will exit once the graph node completes.
+				p.Stop()
+			}
+		}
+	}()
+
+	return stop, wait
+}
+
+// checkConfigDependencies checks whether the recieving context is able to
+// support the given configuration, returning error diagnostics if not.
+//
+// Currently this function checks whether the current Terraform CLI version
+// matches the version requirements of all of the modules, and whether our
+// plugin library contains all of the plugin names/addresses needed.
+//
+// This function does *not* check that external modules are installed (that's
+// the responsibility of the configuration loader) and doesn't check that the
+// plugins are of suitable versions to match any version constraints (which is
+// the responsibility of the code which installed the plugins and then
+// constructed the Providers/Provisioners maps passed in to NewContext).
+//
+// In most cases we should typically catch the problems this function detects
+// before we reach this point, but this function can come into play in some
+// unusual cases outside of the main workflow, and can avoid some
+// potentially-more-confusing errors from later operations.
+func (c *Context) checkConfigDependencies(config *configs.Config) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	// This checks the Terraform CLI version constraints specified in all of
+	// the modules.
+	diags = diags.Append(CheckCoreVersionRequirements(config))
+
+	// We only check that we have a factory for each required provider, and
+	// assume the caller already assured that any separately-installed
+	// plugins are of a suitable version, match expected checksums, etc.
+	providerReqs, hclDiags := config.ProviderRequirements()
+	diags = diags.Append(hclDiags)
+	if hclDiags.HasErrors() {
+		return diags
+	}
+	for providerAddr := range providerReqs {
+		if !c.plugins.HasProvider(providerAddr) {
+			if !providerAddr.IsBuiltIn() {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Missing required provider",
+					fmt.Sprintf(
+						"This configuration requires provider %s, but that provider isn't available. You may be able to install it automatically by running:\n  terraform init",
+						providerAddr,
+					),
+				))
+			} else {
+				// Built-in providers can never be installed by "terraform init",
+				// so no point in confusing the user by suggesting that.
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Missing required provider",
+					fmt.Sprintf(
+						"This configuration requires built-in provider %s, but that provider isn't available in this Terraform version.",
+						providerAddr,
+					),
+				))
+			}
+		}
+	}
+
+	// Our handling of provisioners is much less sophisticated than providers
+	// because they are in many ways a legacy system. We need to go hunting
+	// for them more directly in the configuration.
+	config.DeepEach(func(modCfg *configs.Config) {
+		if modCfg == nil || modCfg.Module == nil {
+			return // should not happen, but we'll be robust
+		}
+		for _, rc := range modCfg.Module.ManagedResources {
+			if rc.Managed == nil {
+				continue // should not happen, but we'll be robust
+			}
+			for _, pc := range rc.Managed.Provisioners {
+				if !c.plugins.HasProvisioner(pc.Type) {
+					// This is not a very high-quality error, because really
+					// the caller of terraform.NewContext should've already
+					// done equivalent checks when doing plugin discovery.
+					// This is just to make sure we return a predictable
+					// error in a central place, rather than failing somewhere
+					// later in the non-deterministically-ordered graph walk.
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Missing required provisioner plugin",
+						fmt.Sprintf(
+							"This configuration requires provisioner plugin %q, which isn't available. If you're intending to use an external provisioner plugin, you must install it manually into one of the plugin search directories before running Terraform.",
+							pc.Type,
+						),
+					))
+				}
+			}
+		}
+	})
+
+	// Because we were doing a lot of map iteration above, and we're only
+	// generating sourceless diagnostics anyway, our diagnostics will not be
+	// in a deterministic order. To ensure stable output when there are
+	// multiple errors to report, we'll sort these particular diagnostics
+	// so they are at least always consistent alone. This ordering is
+	// arbitrary and not a compatibility constraint.
+	sort.Slice(diags, func(i, j int) bool {
+		// Because these are sourcelss diagnostics and we know they are all
+		// errors, we know they'll only differ in their description fields.
+		descI := diags[i].Description()
+		descJ := diags[j].Description()
+		switch {
+		case descI.Summary != descJ.Summary:
+			return descI.Summary < descJ.Summary
+		default:
+			return descI.Detail < descJ.Detail
+		}
+	})
+
+	return diags
+}
diff --git a/v1.5.7/internal/terraform/context_apply.go b/v1.5.7/internal/terraform/context_apply.go
new file mode 100644
index 0000000..4f5851f
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_apply.go
@@ -0,0 +1,206 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Apply performs the actions described by the given Plan object and returns
+// the resulting updated state.
+//
+// The given configuration *must* be the same configuration that was passed
+// earlier to Context.Plan in order to create this plan.
+//
+// Even if the returned diagnostics contains errors, Apply always returns the
+// resulting state which is likely to have been partially-updated.
+func (c *Context) Apply(plan *plans.Plan, config *configs.Config) (*states.State, tfdiags.Diagnostics) {
+	defer c.acquireRun("apply")()
+
+	log.Printf("[DEBUG] Building and walking apply graph for %s plan", plan.UIMode)
+
+	if plan.Errored {
+		var diags tfdiags.Diagnostics
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Cannot apply failed plan",
+			`The given plan is incomplete due to errors during planning, and so it cannot be applied.`,
+		))
+		return nil, diags
+	}
+
+	for _, rc := range plan.Changes.Resources {
+		// Import is a no-op change during an apply (all the real action happens during the plan) but we'd
+		// like to show some helpful output that mirrors the way we show other changes.
+		if rc.Importing != nil {
+			for _, h := range c.hooks {
+				// In future, we may need to call PostApplyImport separately elsewhere in the apply
+				// operation. For now, though, we'll call Pre and Post hooks together.
+				h.PreApplyImport(rc.Addr, *rc.Importing)
+				h.PostApplyImport(rc.Addr, *rc.Importing)
+			}
+		}
+	}
+
+	graph, operation, diags := c.applyGraph(plan, config, true)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	workingState := plan.PriorState.DeepCopy()
+	walker, walkDiags := c.walk(graph, operation, &graphWalkOpts{
+		Config:     config,
+		InputState: workingState,
+		Changes:    plan.Changes,
+
+		// We need to propagate the check results from the plan phase,
+		// because that will tell us which checkable objects we're expecting
+		// to see updated results from during the apply step.
+		PlanTimeCheckResults: plan.Checks,
+
+		// We also want to propagate the timestamp from the plan file.
+		PlanTimeTimestamp: plan.Timestamp,
+	})
+	diags = diags.Append(walker.NonFatalDiagnostics)
+	diags = diags.Append(walkDiags)
+
+	// After the walk is finished, we capture a simplified snapshot of the
+	// check result data as part of the new state.
+	walker.State.RecordCheckResults(walker.Checks)
+
+	newState := walker.State.Close()
+	if plan.UIMode == plans.DestroyMode && !diags.HasErrors() {
+		// NOTE: This is a vestigial violation of the rule that we mustn't
+		// use plan.UIMode to affect apply-time behavior.
+		// We ideally ought to just call newState.PruneResourceHusks
+		// unconditionally here, but we historically didn't and haven't yet
+		// verified that it'd be safe to do so.
+		newState.PruneResourceHusks()
+	}
+
+	if len(plan.TargetAddrs) > 0 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Warning,
+			"Applied changes may be incomplete",
+			`The plan was created with the -target option in effect, so some changes requested in the configuration may have been ignored and the output values may not be fully updated. Run the following command to verify that no other changes are pending:
+    terraform plan
+	
+Note that the -target option is not suitable for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`,
+		))
+	}
+
+	// FIXME: we cannot check for an empty plan for refresh-only, because root
+	// outputs are always stored as changes. The final condition of the state
+	// also depends on some cleanup which happens during the apply walk. It
+	// would probably make more sense if applying a refresh-only plan were
+	// simply just returning the planned state and checks, but some extra
+	// cleanup is going to be needed to make the plan state match what apply
+	// would do. For now we can copy the checks over which were overwritten
+	// during the apply walk.
+	// Despite the intent of UIMode, it must still be used for apply-time
+	// differences in destroy plans too, so we can make use of that here as
+	// well.
+	if plan.UIMode == plans.RefreshOnlyMode {
+		newState.CheckResults = plan.Checks.DeepCopy()
+	}
+
+	return newState, diags
+}
+
+func (c *Context) applyGraph(plan *plans.Plan, config *configs.Config, validate bool) (*Graph, walkOperation, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	variables := InputValues{}
+	for name, dyVal := range plan.VariableValues {
+		val, err := dyVal.Decode(cty.DynamicPseudoType)
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid variable value in plan",
+				fmt.Sprintf("Invalid value for variable %q recorded in plan file: %s.", name, err),
+			))
+			continue
+		}
+
+		variables[name] = &InputValue{
+			Value:      val,
+			SourceType: ValueFromPlan,
+		}
+	}
+	if diags.HasErrors() {
+		return nil, walkApply, diags
+	}
+
+	// The plan.VariableValues field only records variables that were actually
+	// set by the caller in the PlanOpts, so we may need to provide
+	// placeholders for any other variables that the user didn't set, in
+	// which case Terraform will once again use the default value from the
+	// configuration when we visit these variables during the graph walk.
+	for name := range config.Module.Variables {
+		if _, ok := variables[name]; ok {
+			continue
+		}
+		variables[name] = &InputValue{
+			Value:      cty.NilVal,
+			SourceType: ValueFromPlan,
+		}
+	}
+
+	operation := walkApply
+	if plan.UIMode == plans.DestroyMode {
+		// FIXME: Due to differences in how objects must be handled in the
+		// graph and evaluated during a complete destroy, we must continue to
+		// use plans.DestroyMode to switch on this behavior. If all objects
+		// which require special destroy handling can be tracked in the plan,
+		// then this switch will no longer be needed and we can remove the
+		// walkDestroy operation mode.
+		// TODO: Audit that and remove walkDestroy as an operation mode.
+		operation = walkDestroy
+	}
+
+	graph, moreDiags := (&ApplyGraphBuilder{
+		Config:             config,
+		Changes:            plan.Changes,
+		State:              plan.PriorState,
+		RootVariableValues: variables,
+		Plugins:            c.plugins,
+		Targets:            plan.TargetAddrs,
+		ForceReplace:       plan.ForceReplaceAddrs,
+		Operation:          operation,
+	}).Build(addrs.RootModuleInstance)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		return nil, walkApply, diags
+	}
+
+	return graph, operation, diags
+}
+
+// ApplyGraphForUI is a last vestage of graphs in the public interface of
+// Context (as opposed to graphs as an implementation detail) intended only for
+// use by the "terraform graph" command when asked to render an apply-time
+// graph.
+//
+// The result of this is intended only for rendering ot the user as a dot
+// graph, and so may change in future in order to make the result more useful
+// in that context, even if drifts away from the physical graph that Terraform
+// Core currently uses as an implementation detail of planning.
+func (c *Context) ApplyGraphForUI(plan *plans.Plan, config *configs.Config) (*Graph, tfdiags.Diagnostics) {
+	// For now though, this really is just the internal graph, confusing
+	// implementation details and all.
+
+	var diags tfdiags.Diagnostics
+
+	graph, _, moreDiags := c.applyGraph(plan, config, false)
+	diags = diags.Append(moreDiags)
+	return graph, diags
+}
diff --git a/v1.5.7/internal/terraform/context_apply2_test.go b/v1.5.7/internal/terraform/context_apply2_test.go
new file mode 100644
index 0000000..9442c22
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_apply2_test.go
@@ -0,0 +1,2164 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"strings"
+	"sync"
+	"testing"
+	"time"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Test that the PreApply hook is called with the correct deposed key
+func TestContext2Apply_createBeforeDestroy_deposedKeyPreApply(t *testing.T) {
+	m := testModule(t, "apply-cbd-deposed-only")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	deposedKey := states.NewDeposedKey()
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceDeposed(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		deposedKey,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	hook := new(MockHook)
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{hook},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf(legacyDiffComparisonString(plan.Changes))
+	}
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	// Verify PreApply was called correctly
+	if !hook.PreApplyCalled {
+		t.Fatalf("PreApply hook not called")
+	}
+	if addr, wantAddr := hook.PreApplyAddr, mustResourceInstanceAddr("aws_instance.bar"); !addr.Equal(wantAddr) {
+		t.Errorf("expected addr to be %s, but was %s", wantAddr, addr)
+	}
+	if gen := hook.PreApplyGen; gen != deposedKey {
+		t.Errorf("expected gen to be %q, but was %q", deposedKey, gen)
+	}
+}
+
+func TestContext2Apply_destroyWithDataSourceExpansion(t *testing.T) {
+	// While managed resources store their destroy-time dependencies, data
+	// sources do not. This means that if a provider were only included in a
+	// destroy graph because of data sources, it could have dependencies which
+	// are not correctly ordered. Here we verify that the provider is not
+	// included in the destroy operation, and all dependency evaluations
+	// succeed.
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod" {
+  source = "./mod"
+}
+
+provider "other" {
+  foo = module.mod.data
+}
+
+# this should not require the provider be present during destroy
+data "other_data_source" "a" {
+}
+`,
+
+		"mod/main.tf": `
+data "test_data_source" "a" {
+  count = 1
+}
+
+data "test_data_source" "b" {
+  count = data.test_data_source.a[0].foo == "ok" ? 1 : 0
+}
+
+output "data" {
+  value = data.test_data_source.a[0].foo == "ok" ? data.test_data_source.b[0].foo : "nope"
+}
+`,
+	})
+
+	testP := testProvider("test")
+	otherP := testProvider("other")
+
+	readData := func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		return providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("data_source"),
+				"foo": cty.StringVal("ok"),
+			}),
+		}
+	}
+
+	testP.ReadDataSourceFn = readData
+	otherP.ReadDataSourceFn = readData
+
+	ps := map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("test"):  testProviderFuncFixed(testP),
+		addrs.NewDefaultProvider("other"): testProviderFuncFixed(otherP),
+	}
+
+	otherP.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		foo := req.Config.GetAttr("foo")
+		if foo.IsNull() || foo.AsString() != "ok" {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("incorrect config val: %#v\n", foo))
+		}
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: ps,
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	// now destroy the whole thing
+	ctx = testContext2(t, &ContextOpts{
+		Providers: ps,
+	})
+
+	plan, diags = ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	otherP.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		// should not be used to destroy data sources
+		resp.Diagnostics = resp.Diagnostics.Append(errors.New("provider should not be used"))
+		return resp
+	}
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+}
+
+func TestContext2Apply_destroyThenUpdate(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_instance" "a" {
+	value = "udpated"
+}
+`,
+	})
+
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+
+	var orderMu sync.Mutex
+	var order []string
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		id := req.PriorState.GetAttr("id").AsString()
+		if id == "b" {
+			// slow down the b destroy, since a should wait for it
+			time.Sleep(100 * time.Millisecond)
+		}
+
+		orderMu.Lock()
+		order = append(order, id)
+		orderMu.Unlock()
+
+		resp.NewState = req.PlannedState
+		return resp
+	}
+
+	addrA := mustResourceInstanceAddr(`test_instance.a`)
+	addrB := mustResourceInstanceAddr(`test_instance.b`)
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{"id":"a","value":"old","type":"test"}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+
+		// test_instance.b depended on test_instance.a, and therefor should be
+		// destroyed before any changes to test_instance.a
+		s.SetResourceInstanceCurrent(addrB, &states.ResourceInstanceObjectSrc{
+			AttrsJSON:    []byte(`{"id":"b"}`),
+			Status:       states.ObjectReady,
+			Dependencies: []addrs.ConfigResource{addrA.ContainingResource().Config()},
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	if order[0] != "b" {
+		t.Fatalf("expected apply order [b, a], got: %v\n", order)
+	}
+}
+
+// verify that dependencies are updated in the state during refresh and apply
+func TestApply_updateDependencies(t *testing.T) {
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+
+	fooAddr := mustResourceInstanceAddr("aws_instance.foo")
+	barAddr := mustResourceInstanceAddr("aws_instance.bar")
+	bazAddr := mustResourceInstanceAddr("aws_instance.baz")
+	bamAddr := mustResourceInstanceAddr("aws_instance.bam")
+	binAddr := mustResourceInstanceAddr("aws_instance.bin")
+	root.SetResourceInstanceCurrent(
+		fooAddr.Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+			Dependencies: []addrs.ConfigResource{
+				bazAddr.ContainingResource().Config(),
+			},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		binAddr.Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bin","type":"aws_instance","unknown":"ok"}`),
+			Dependencies: []addrs.ConfigResource{
+				bazAddr.ContainingResource().Config(),
+			},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		bazAddr.Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"baz"}`),
+			Dependencies: []addrs.ConfigResource{
+				// Existing dependencies should not be removed from orphaned instances
+				bamAddr.ContainingResource().Config(),
+			},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		barAddr.Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","foo":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "aws_instance" "bar" {
+  foo = aws_instance.foo.id
+}
+
+resource "aws_instance" "foo" {
+}
+
+resource "aws_instance" "bin" {
+}
+`,
+	})
+
+	p := testProvider("aws")
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	bar := plan.PriorState.ResourceInstance(barAddr)
+	if len(bar.Current.Dependencies) == 0 || !bar.Current.Dependencies[0].Equal(fooAddr.ContainingResource().Config()) {
+		t.Fatalf("bar should depend on foo after refresh, but got %s", bar.Current.Dependencies)
+	}
+
+	foo := plan.PriorState.ResourceInstance(fooAddr)
+	if len(foo.Current.Dependencies) == 0 || !foo.Current.Dependencies[0].Equal(bazAddr.ContainingResource().Config()) {
+		t.Fatalf("foo should depend on baz after refresh because of the update, but got %s", foo.Current.Dependencies)
+	}
+
+	bin := plan.PriorState.ResourceInstance(binAddr)
+	if len(bin.Current.Dependencies) != 0 {
+		t.Fatalf("bin should depend on nothing after refresh because there is no change, but got %s", bin.Current.Dependencies)
+	}
+
+	baz := plan.PriorState.ResourceInstance(bazAddr)
+	if len(baz.Current.Dependencies) == 0 || !baz.Current.Dependencies[0].Equal(bamAddr.ContainingResource().Config()) {
+		t.Fatalf("baz should depend on bam after refresh, but got %s", baz.Current.Dependencies)
+	}
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	bar = state.ResourceInstance(barAddr)
+	if len(bar.Current.Dependencies) == 0 || !bar.Current.Dependencies[0].Equal(fooAddr.ContainingResource().Config()) {
+		t.Fatalf("bar should still depend on foo after apply, but got %s", bar.Current.Dependencies)
+	}
+
+	foo = state.ResourceInstance(fooAddr)
+	if len(foo.Current.Dependencies) != 0 {
+		t.Fatalf("foo should have no deps after apply, but got %s", foo.Current.Dependencies)
+	}
+
+}
+
+func TestContext2Apply_additionalSensitiveFromState(t *testing.T) {
+	// Ensure we're not trying to double-mark values decoded from state
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "secret" {
+  sensitive = true
+  default = ["secret"]
+}
+
+resource "test_resource" "a" {
+  sensitive_attr = var.secret
+}
+
+resource "test_resource" "b" {
+  value = test_resource.a.id
+}
+`,
+	})
+
+	p := new(MockProvider)
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"value": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"sensitive_attr": {
+						Type:      cty.List(cty.String),
+						Optional:  true,
+						Sensitive: true,
+					},
+				},
+			},
+		},
+	})
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			mustResourceInstanceAddr(`test_resource.a`),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"a","sensitive_attr":["secret"]}`),
+				AttrSensitivePaths: []cty.PathValueMarks{
+					{
+						Path:  cty.GetAttrPath("sensitive_attr"),
+						Marks: cty.NewValueMarks(marks.Sensitive),
+					},
+				},
+				Status: states.ObjectReady,
+			}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+		)
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+}
+
+func TestContext2Apply_sensitiveOutputPassthrough(t *testing.T) {
+	// Ensure we're not trying to double-mark values decoded from state
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod" {
+  source = "./mod"
+}
+
+resource "test_object" "a" {
+  test_string = module.mod.out
+}
+`,
+
+		"mod/main.tf": `
+variable "in" {
+  sensitive = true
+  default = "foo"
+}
+output "out" {
+  value = var.in
+}
+`,
+	})
+
+	p := simpleMockProvider()
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	obj := state.ResourceInstance(mustResourceInstanceAddr("test_object.a"))
+	if len(obj.Current.AttrSensitivePaths) != 1 {
+		t.Fatalf("Expected 1 sensitive mark for test_object.a, got %#v\n", obj.Current.AttrSensitivePaths)
+	}
+
+	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	// make sure the same marks are compared in the next plan as well
+	for _, c := range plan.Changes.Resources {
+		if c.Action != plans.NoOp {
+			t.Errorf("Unexpcetd %s change for %s", c.Action, c.Addr)
+		}
+	}
+}
+
+func TestContext2Apply_ignoreImpureFunctionChanges(t *testing.T) {
+	// The impure function call should not cause a planned change with
+	// ignore_changes
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "pw" {
+  sensitive = true
+  default = "foo"
+}
+
+resource "test_object" "x" {
+  test_map = {
+	string = "X${bcrypt(var.pw)}"
+  }
+  lifecycle {
+    ignore_changes = [ test_map["string"] ]
+  }
+}
+
+resource "test_object" "y" {
+  test_map = {
+	string = "X${bcrypt(var.pw)}"
+  }
+  lifecycle {
+    ignore_changes = [ test_map ]
+  }
+}
+
+`,
+	})
+
+	p := simpleMockProvider()
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	// FINAL PLAN:
+	plan, diags = ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+
+	// make sure the same marks are compared in the next plan as well
+	for _, c := range plan.Changes.Resources {
+		if c.Action != plans.NoOp {
+			t.Logf("marks before: %#v", c.BeforeValMarks)
+			t.Logf("marks after:  %#v", c.AfterValMarks)
+			t.Errorf("Unexpcetd %s change for %s", c.Action, c.Addr)
+		}
+	}
+}
+
+func TestContext2Apply_destroyWithDeposed(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "x" {
+  test_string = "ok"
+  lifecycle {
+    create_before_destroy = true
+  }
+}`,
+	})
+
+	p := simpleMockProvider()
+
+	deposedKey := states.NewDeposedKey()
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceDeposed(
+		mustResourceInstanceAddr("test_object.x").Resource,
+		deposedKey,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"test_string":"deposed"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("plan: %s", diags.Err())
+	}
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply: %s", diags.Err())
+	}
+
+}
+
+func TestContext2Apply_nullableVariables(t *testing.T) {
+	m := testModule(t, "apply-nullable-variables")
+	state := states.NewState()
+	ctx := testContext2(t, &ContextOpts{})
+	plan, diags := ctx.Plan(m, state, &PlanOpts{})
+	if diags.HasErrors() {
+		t.Fatalf("plan: %s", diags.Err())
+	}
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply: %s", diags.Err())
+	}
+
+	outputs := state.Module(addrs.RootModuleInstance).OutputValues
+	// we check for null outputs be seeing that they don't exists
+	if _, ok := outputs["nullable_null_default"]; ok {
+		t.Error("nullable_null_default: expected no output value")
+	}
+	if _, ok := outputs["nullable_non_null_default"]; ok {
+		t.Error("nullable_non_null_default: expected no output value")
+	}
+	if _, ok := outputs["nullable_no_default"]; ok {
+		t.Error("nullable_no_default: expected no output value")
+	}
+
+	if v := outputs["non_nullable_default"].Value; v.AsString() != "ok" {
+		t.Fatalf("incorrect 'non_nullable_default' output value: %#v\n", v)
+	}
+	if v := outputs["non_nullable_no_default"].Value; v.AsString() != "ok" {
+		t.Fatalf("incorrect 'non_nullable_no_default' output value: %#v\n", v)
+	}
+}
+
+func TestContext2Apply_targetedDestroyWithMoved(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "modb" {
+  source = "./mod"
+  for_each = toset(["a", "b"])
+}
+`,
+		"./mod/main.tf": `
+resource "test_object" "a" {
+}
+
+module "sub" {
+  for_each = toset(["a", "b"])
+  source = "./sub"
+}
+
+moved {
+  from = module.old
+  to = module.sub
+}
+`,
+		"./mod/sub/main.tf": `
+resource "test_object" "s" {
+}
+`})
+
+	p := simpleMockProvider()
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	// destroy only a single instance not included in the moved statements
+	_, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode:    plans.DestroyMode,
+		Targets: []addrs.Targetable{mustResourceInstanceAddr(`module.modb["a"].test_object.a`)},
+	})
+	assertNoErrors(t, diags)
+}
+
+func TestContext2Apply_graphError(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+  test_string = "ok"
+}
+
+resource "test_object" "b" {
+  test_string = test_object.a.test_string
+}
+`,
+	})
+
+	p := simpleMockProvider()
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"test_string":"ok"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.b").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"test_string":"ok"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("plan: %s", diags.Err())
+	}
+
+	// We're going to corrupt the stored state so that the dependencies will
+	// cause a cycle when building the apply graph.
+	testObjA := plan.PriorState.Modules[""].Resources["test_object.a"].Instances[addrs.NoKey].Current
+	testObjA.Dependencies = append(testObjA.Dependencies, mustResourceInstanceAddr("test_object.b").ContainingResource().Config())
+
+	_, diags = ctx.Apply(plan, m)
+	if !diags.HasErrors() {
+		t.Fatal("expected cycle error from apply")
+	}
+}
+
+func TestContext2Apply_resourcePostcondition(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "boop" {
+  type = string
+}
+
+resource "test_resource" "a" {
+	value = var.boop
+}
+
+resource "test_resource" "b" {
+  value = test_resource.a.output
+  lifecycle {
+    postcondition {
+      condition     = self.output != ""
+      error_message = "Output must not be blank."
+    }
+  }
+}
+
+resource "test_resource" "c" {
+  value = test_resource.b.output
+}
+`,
+	})
+
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"value": {
+						Type:     cty.String,
+						Required: true,
+					},
+					"output": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		m := req.ProposedNewState.AsValueMap()
+		m["output"] = cty.UnknownVal(cty.String)
+
+		resp.PlannedState = cty.ObjectVal(m)
+		resp.LegacyTypeSystem = true
+		return resp
+	}
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	t.Run("condition pass", func(t *testing.T) {
+		plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("boop"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+		if len(plan.Changes.Resources) != 3 {
+			t.Fatalf("unexpected plan changes: %#v", plan.Changes)
+		}
+
+		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+			m := req.PlannedState.AsValueMap()
+			m["output"] = cty.StringVal(fmt.Sprintf("new-%s", m["value"].AsString()))
+
+			resp.NewState = cty.ObjectVal(m)
+			return resp
+		}
+		state, diags := ctx.Apply(plan, m)
+		assertNoErrors(t, diags)
+
+		wantResourceAttrs := map[string]struct{ value, output string }{
+			"a": {"boop", "new-boop"},
+			"b": {"new-boop", "new-new-boop"},
+			"c": {"new-new-boop", "new-new-new-boop"},
+		}
+		for name, attrs := range wantResourceAttrs {
+			addr := mustResourceInstanceAddr(fmt.Sprintf("test_resource.%s", name))
+			r := state.ResourceInstance(addr)
+			rd, err := r.Current.Decode(cty.Object(map[string]cty.Type{
+				"value":  cty.String,
+				"output": cty.String,
+			}))
+			if err != nil {
+				t.Fatalf("error decoding test_resource.a: %s", err)
+			}
+			want := cty.ObjectVal(map[string]cty.Value{
+				"value":  cty.StringVal(attrs.value),
+				"output": cty.StringVal(attrs.output),
+			})
+			if !cmp.Equal(want, rd.Value, valueComparer) {
+				t.Errorf("wrong attrs for %s\n%s", addr, cmp.Diff(want, rd.Value, valueComparer))
+			}
+		}
+	})
+	t.Run("condition fail", func(t *testing.T) {
+		plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("boop"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+		if len(plan.Changes.Resources) != 3 {
+			t.Fatalf("unexpected plan changes: %#v", plan.Changes)
+		}
+
+		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+			m := req.PlannedState.AsValueMap()
+
+			// For the resource with a constraint, fudge the output to make the
+			// condition fail.
+			if value := m["value"].AsString(); value == "new-boop" {
+				m["output"] = cty.StringVal("")
+			} else {
+				m["output"] = cty.StringVal(fmt.Sprintf("new-%s", value))
+			}
+
+			resp.NewState = cty.ObjectVal(m)
+			return resp
+		}
+		state, diags := ctx.Apply(plan, m)
+		if !diags.HasErrors() {
+			t.Fatal("succeeded; want errors")
+		}
+		if got, want := diags.Err().Error(), "Resource postcondition failed: Output must not be blank."; got != want {
+			t.Fatalf("wrong error:\ngot:  %s\nwant: %q", got, want)
+		}
+
+		// Resources a and b should still be recorded in state
+		wantResourceAttrs := map[string]struct{ value, output string }{
+			"a": {"boop", "new-boop"},
+			"b": {"new-boop", ""},
+		}
+		for name, attrs := range wantResourceAttrs {
+			addr := mustResourceInstanceAddr(fmt.Sprintf("test_resource.%s", name))
+			r := state.ResourceInstance(addr)
+			rd, err := r.Current.Decode(cty.Object(map[string]cty.Type{
+				"value":  cty.String,
+				"output": cty.String,
+			}))
+			if err != nil {
+				t.Fatalf("error decoding test_resource.a: %s", err)
+			}
+			want := cty.ObjectVal(map[string]cty.Value{
+				"value":  cty.StringVal(attrs.value),
+				"output": cty.StringVal(attrs.output),
+			})
+			if !cmp.Equal(want, rd.Value, valueComparer) {
+				t.Errorf("wrong attrs for %s\n%s", addr, cmp.Diff(want, rd.Value, valueComparer))
+			}
+		}
+
+		// Resource c should not be in state
+		if state.ResourceInstance(mustResourceInstanceAddr("test_resource.c")) != nil {
+			t.Error("test_resource.c should not exist in state, but is")
+		}
+	})
+}
+
+func TestContext2Apply_outputValuePrecondition(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+			variable "input" {
+				type = string
+			}
+
+			module "child" {
+				source = "./child"
+
+				input = var.input
+			}
+
+			output "result" {
+				value = module.child.result
+
+				precondition {
+					condition     = var.input != ""
+					error_message = "Input must not be empty."
+				}
+			}
+		`,
+		"child/main.tf": `
+			variable "input" {
+				type = string
+			}
+
+			output "result" {
+				value = var.input
+
+				precondition {
+					condition     = var.input != ""
+					error_message = "Input must not be empty."
+				}
+			}
+		`,
+	})
+
+	checkableObjects := []addrs.Checkable{
+		addrs.OutputValue{Name: "result"}.Absolute(addrs.RootModuleInstance),
+		addrs.OutputValue{Name: "result"}.Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey)),
+	}
+
+	t.Run("pass", func(t *testing.T) {
+		ctx := testContext2(t, &ContextOpts{})
+		plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"input": &InputValue{
+					Value:      cty.StringVal("beep"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		assertNoDiagnostics(t, diags)
+
+		for _, addr := range checkableObjects {
+			result := plan.Checks.GetObjectResult(addr)
+			if result == nil {
+				t.Fatalf("no check result for %s in the plan", addr)
+			}
+			if got, want := result.Status, checks.StatusPass; got != want {
+				t.Fatalf("wrong check status for %s during planning\ngot:  %s\nwant: %s", addr, got, want)
+			}
+		}
+
+		state, diags := ctx.Apply(plan, m)
+		assertNoDiagnostics(t, diags)
+		for _, addr := range checkableObjects {
+			result := state.CheckResults.GetObjectResult(addr)
+			if result == nil {
+				t.Fatalf("no check result for %s in the final state", addr)
+			}
+			if got, want := result.Status, checks.StatusPass; got != want {
+				t.Errorf("wrong check status for %s after apply\ngot:  %s\nwant: %s", addr, got, want)
+			}
+		}
+	})
+
+	t.Run("fail", func(t *testing.T) {
+		// NOTE: This test actually catches a failure during planning and so
+		// cannot proceed to apply, so it's really more of a plan test
+		// than an apply test but better to keep all of these
+		// thematically-related test cases together.
+		ctx := testContext2(t, &ContextOpts{})
+		_, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"input": &InputValue{
+					Value:      cty.StringVal(""),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		if !diags.HasErrors() {
+			t.Fatalf("succeeded; want error")
+		}
+
+		const wantSummary = "Module output value precondition failed"
+		found := false
+		for _, diag := range diags {
+			if diag.Severity() == tfdiags.Error && diag.Description().Summary == wantSummary {
+				found = true
+				break
+			}
+		}
+
+		if !found {
+			t.Fatalf("missing expected error\nwant summary: %s\ngot: %s", wantSummary, diags.Err().Error())
+		}
+	})
+}
+
+func TestContext2Apply_resourceConditionApplyTimeFail(t *testing.T) {
+	// This tests the less common situation where a condition fails due to
+	// a change in a resource other than the one the condition is attached to,
+	// and the condition result is unknown during planning.
+	//
+	// This edge case is a tricky one because it relies on Terraform still
+	// visiting test_resource.b (in the configuration below) to evaluate
+	// its conditions even though there aren't any changes directly planned
+	// for it, so that we can consider whether changes to test_resource.a
+	// have changed the outcome.
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+			variable "input" {
+				type = string
+			}
+
+			resource "test_resource" "a" {
+				value = var.input
+			}
+
+			resource "test_resource" "b" {
+				value = "beep"
+
+				lifecycle {
+					postcondition {
+						condition     = test_resource.a.output == self.output
+						error_message = "Outputs must match."
+					}
+				}
+			}
+		`,
+	})
+
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"value": {
+						Type:     cty.String,
+						Required: true,
+					},
+					"output": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		// Whenever "value" changes, "output" follows it during the apply step,
+		// but is initially unknown during the plan step.
+
+		m := req.ProposedNewState.AsValueMap()
+		priorVal := cty.NullVal(cty.String)
+		if !req.PriorState.IsNull() {
+			priorVal = req.PriorState.GetAttr("value")
+		}
+		if m["output"].IsNull() || !priorVal.RawEquals(m["value"]) {
+			m["output"] = cty.UnknownVal(cty.String)
+		}
+
+		resp.PlannedState = cty.ObjectVal(m)
+		resp.LegacyTypeSystem = true
+		return resp
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		m := req.PlannedState.AsValueMap()
+		m["output"] = m["value"]
+		resp.NewState = cty.ObjectVal(m)
+		return resp
+	}
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	instA := mustResourceInstanceAddr("test_resource.a")
+	instB := mustResourceInstanceAddr("test_resource.b")
+
+	// Preparation: an initial plan and apply with a correct input variable
+	// should succeed and give us a valid and complete state to use for the
+	// subsequent plan and apply that we'll expect to fail.
+	var prevRunState *states.State
+	{
+		plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"input": &InputValue{
+					Value:      cty.StringVal("beep"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+		planA := plan.Changes.ResourceInstance(instA)
+		if planA == nil || planA.Action != plans.Create {
+			t.Fatalf("incorrect initial plan for instance A\nwant a 'create' change\ngot: %s", spew.Sdump(planA))
+		}
+		planB := plan.Changes.ResourceInstance(instB)
+		if planB == nil || planB.Action != plans.Create {
+			t.Fatalf("incorrect initial plan for instance B\nwant a 'create' change\ngot: %s", spew.Sdump(planB))
+		}
+
+		state, diags := ctx.Apply(plan, m)
+		assertNoErrors(t, diags)
+
+		stateA := state.ResourceInstance(instA)
+		if stateA == nil || stateA.Current == nil || !bytes.Contains(stateA.Current.AttrsJSON, []byte(`"beep"`)) {
+			t.Fatalf("incorrect initial state for instance A\ngot: %s", spew.Sdump(stateA))
+		}
+		stateB := state.ResourceInstance(instB)
+		if stateB == nil || stateB.Current == nil || !bytes.Contains(stateB.Current.AttrsJSON, []byte(`"beep"`)) {
+			t.Fatalf("incorrect initial state for instance B\ngot: %s", spew.Sdump(stateB))
+		}
+		prevRunState = state
+	}
+
+	// Now we'll run another plan and apply with a different value for
+	// var.input that should cause the test_resource.b condition to be unknown
+	// during planning and then fail during apply.
+	{
+		plan, diags := ctx.Plan(m, prevRunState, &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"input": &InputValue{
+					Value:      cty.StringVal("boop"), // NOTE: This has changed
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+		planA := plan.Changes.ResourceInstance(instA)
+		if planA == nil || planA.Action != plans.Update {
+			t.Fatalf("incorrect initial plan for instance A\nwant an 'update' change\ngot: %s", spew.Sdump(planA))
+		}
+		planB := plan.Changes.ResourceInstance(instB)
+		if planB == nil || planB.Action != plans.NoOp {
+			t.Fatalf("incorrect initial plan for instance B\nwant a 'no-op' change\ngot: %s", spew.Sdump(planB))
+		}
+
+		_, diags = ctx.Apply(plan, m)
+		if !diags.HasErrors() {
+			t.Fatal("final apply succeeded, but should've failed with a postcondition error")
+		}
+		if len(diags) != 1 {
+			t.Fatalf("expected exactly one diagnostic, but got: %s", diags.Err().Error())
+		}
+		if got, want := diags[0].Description().Summary, "Resource postcondition failed"; got != want {
+			t.Fatalf("wrong diagnostic summary\ngot:  %s\nwant: %s", got, want)
+		}
+	}
+}
+
+// pass an input through some expanded values, and back to a provider to make
+// sure we can fully evaluate a provider configuration during a destroy plan.
+func TestContext2Apply_destroyWithConfiguredProvider(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "in" {
+  type = map(string)
+  default = {
+    "a" = "first"
+    "b" = "second"
+  }
+}
+
+module "mod" {
+  source = "./mod"
+  for_each = var.in
+  in = each.value
+}
+
+locals {
+  config = [for each in module.mod : each.out]
+}
+
+provider "other" {
+  output = [for each in module.mod : each.out]
+  local = local.config
+  var = var.in
+}
+
+resource "other_object" "other" {
+}
+`,
+		"./mod/main.tf": `
+variable "in" {
+  type = string
+}
+
+data "test_object" "d" {
+  test_string = var.in
+}
+
+resource "test_object" "a" {
+  test_string = var.in
+}
+
+output "out" {
+  value = data.test_object.d.output
+}
+`})
+
+	testProvider := &MockProvider{
+		GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+			Provider: providers.Schema{Block: simpleTestSchema()},
+			ResourceTypes: map[string]providers.Schema{
+				"test_object": providers.Schema{Block: simpleTestSchema()},
+			},
+			DataSources: map[string]providers.Schema{
+				"test_object": providers.Schema{
+					Block: &configschema.Block{
+						Attributes: map[string]*configschema.Attribute{
+							"test_string": {
+								Type:     cty.String,
+								Optional: true,
+							},
+							"output": {
+								Type:     cty.String,
+								Computed: true,
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testProvider.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+		cfg := req.Config.AsValueMap()
+		s := cfg["test_string"].AsString()
+		if !strings.Contains("firstsecond", s) {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("expected 'first' or 'second', got %s", s))
+			return resp
+		}
+
+		cfg["output"] = cty.StringVal(s + "-ok")
+		resp.State = cty.ObjectVal(cfg)
+		return resp
+	}
+
+	otherProvider := &MockProvider{
+		GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+			Provider: providers.Schema{
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"output": {
+							Type:     cty.List(cty.String),
+							Optional: true,
+						},
+						"local": {
+							Type:     cty.List(cty.String),
+							Optional: true,
+						},
+						"var": {
+							Type:     cty.Map(cty.String),
+							Optional: true,
+						},
+					},
+				},
+			},
+			ResourceTypes: map[string]providers.Schema{
+				"other_object": providers.Schema{Block: simpleTestSchema()},
+			},
+		},
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"):  testProviderFuncFixed(testProvider),
+			addrs.NewDefaultProvider("other"): testProviderFuncFixed(otherProvider),
+		},
+	})
+
+	opts := SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))
+	plan, diags := ctx.Plan(m, states.NewState(), opts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	// Resource changes which have dependencies across providers which
+	// themselves depend on resources can result in cycles.
+	// Because other_object transitively depends on the module resources
+	// through its provider, we trigger changes on both sides of this boundary
+	// to ensure we can create a valid plan.
+	//
+	// Taint the object to make sure a replacement works in the plan.
+	otherObjAddr := mustResourceInstanceAddr("other_object.other")
+	otherObj := state.ResourceInstance(otherObjAddr)
+	otherObj.Current.Status = states.ObjectTainted
+	// Force a change which needs to be reverted.
+	testObjAddr := mustResourceInstanceAddr(`module.mod["a"].test_object.a`)
+	testObjA := state.ResourceInstance(testObjAddr)
+	testObjA.Current.AttrsJSON = []byte(`{"test_bool":null,"test_list":null,"test_map":null,"test_number":null,"test_string":"changed"}`)
+
+	_, diags = ctx.Plan(m, state, opts)
+	assertNoErrors(t, diags)
+	return
+
+	otherProvider.ConfigureProviderCalled = false
+	otherProvider.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		// check that our config is complete, even during a destroy plan
+		expected := cty.ObjectVal(map[string]cty.Value{
+			"local":  cty.ListVal([]cty.Value{cty.StringVal("first-ok"), cty.StringVal("second-ok")}),
+			"output": cty.ListVal([]cty.Value{cty.StringVal("first-ok"), cty.StringVal("second-ok")}),
+			"var": cty.MapVal(map[string]cty.Value{
+				"a": cty.StringVal("first"),
+				"b": cty.StringVal("second"),
+			}),
+		})
+
+		if !req.Config.RawEquals(expected) {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf(
+				`incorrect provider config:
+expected: %#v
+got:      %#v`,
+				expected, req.Config))
+		}
+
+		return resp
+	}
+
+	opts.Mode = plans.DestroyMode
+	// skip refresh so that we don't configure the provider before the destroy plan
+	opts.SkipRefresh = true
+
+	// destroy only a single instance not included in the moved statements
+	_, diags = ctx.Plan(m, state, opts)
+	assertNoErrors(t, diags)
+
+	if !otherProvider.ConfigureProviderCalled {
+		t.Fatal("failed to configure provider during destroy plan")
+	}
+}
+
+// check that a provider can verify a planned destroy
+func TestContext2Apply_plannedDestroy(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "x" {
+  test_string = "ok"
+}`,
+	})
+
+	p := simpleMockProvider()
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		if !req.ProposedNewState.IsNull() {
+			// we should only be destroying in this test
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unexpected plan with %#v", req.ProposedNewState))
+			return resp
+		}
+
+		resp.PlannedState = req.ProposedNewState
+		// we're going to verify the destroy plan by inserting private data required for destroy
+		resp.PlannedPrivate = append(resp.PlannedPrivate, []byte("planned")...)
+		return resp
+	}
+
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		// if the value is nil, we return that directly to correspond to a delete
+		if !req.PlannedState.IsNull() {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unexpected apply with %#v", req.PlannedState))
+			return resp
+		}
+
+		resp.NewState = req.PlannedState
+
+		// make sure we get our private data from the plan
+		private := string(req.PlannedPrivate)
+		if private != "planned" {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("missing private data from plan, got %q", private))
+		}
+		return resp
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.x").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"test_string":"ok"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+		// we don't want to refresh, because that actually runs a normal plan
+		SkipRefresh: true,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("plan: %s", diags.Err())
+	}
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply: %s", diags.Err())
+	}
+}
+
+func TestContext2Apply_missingOrphanedResource(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+# changed resource address to create a new object
+resource "test_object" "y" {
+  test_string = "y"
+}
+`,
+	})
+
+	p := simpleMockProvider()
+
+	// report the prior value is missing
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+		resp.NewState = cty.NullVal(req.PriorState.Type())
+		return resp
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.x").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"test_string":"x"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	opts := SimplePlanOpts(plans.NormalMode, nil)
+	plan, diags := ctx.Plan(m, state, opts)
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+}
+
+// Outputs should not cause evaluation errors during destroy
+// Check eval from both root level outputs and module outputs, which are
+// handled differently during apply.
+func TestContext2Apply_outputsNotToEvaluate(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod" {
+  source = "./mod"
+  cond = false
+}
+
+output "from_resource" {
+  value = module.mod.from_resource
+}
+
+output "from_data" {
+  value = module.mod.from_data
+}
+`,
+
+		"./mod/main.tf": `
+variable "cond" {
+  type = bool
+}
+
+module "mod" {
+  source = "../mod2/"
+  cond = var.cond
+}
+
+output "from_resource" {
+  value = module.mod.resource
+}
+
+output "from_data" {
+  value = module.mod.data
+}
+`,
+
+		"./mod2/main.tf": `
+variable "cond" {
+  type = bool
+}
+
+resource "test_object" "x" {
+  count = var.cond ? 0:1
+}
+
+data "test_object" "d" {
+  count = var.cond ? 0:1
+}
+
+output "resource" {
+  value = var.cond ? null : test_object.x.*.test_string[0]
+}
+
+output "data" {
+  value = one(data.test_object.d[*].test_string)
+}
+`})
+
+	p := simpleMockProvider()
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+		resp.State = req.Config
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	// apply the state
+	opts := SimplePlanOpts(plans.NormalMode, nil)
+	plan, diags := ctx.Plan(m, states.NewState(), opts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	// and destroy
+	opts = SimplePlanOpts(plans.DestroyMode, nil)
+	plan, diags = ctx.Plan(m, state, opts)
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	// and destroy again with no state
+	if !state.Empty() {
+		t.Fatal("expected empty state, got", state)
+	}
+
+	opts = SimplePlanOpts(plans.DestroyMode, nil)
+	plan, diags = ctx.Plan(m, state, opts)
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+}
+
+// don't evaluate conditions on outputs when destroying
+func TestContext2Apply_noOutputChecksOnDestroy(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod" {
+  source = "./mod"
+}
+
+output "from_resource" {
+  value = module.mod.from_resource
+}
+`,
+
+		"./mod/main.tf": `
+resource "test_object" "x" {
+  test_string = "wrong val"
+}
+
+output "from_resource" {
+  value = test_object.x.test_string
+  precondition {
+    condition     = test_object.x.test_string == "ok"
+    error_message = "resource error"
+  }
+}
+`})
+
+	p := simpleMockProvider()
+
+	state := states.NewState()
+	mod := state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.NoKey))
+	mod.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.x").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"test_string":"wrong_val"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	opts := SimplePlanOpts(plans.DestroyMode, nil)
+	plan, diags := ctx.Plan(m, state, opts)
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+}
+
+// -refresh-only should update checks
+func TestContext2Apply_refreshApplyUpdatesChecks(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "x" {
+  test_string = "ok"
+  lifecycle {
+    postcondition {
+      condition = self.test_string == "ok"
+      error_message = "wrong val"
+    }
+  }
+}
+
+output "from_resource" {
+  value = test_object.x.test_string
+  precondition {
+	condition     = test_object.x.test_string == "ok"
+	error_message = "wrong val"
+  }
+}
+`})
+
+	p := simpleMockProvider()
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"test_string": cty.StringVal("ok"),
+		}),
+	}
+
+	state := states.NewState()
+	mod := state.EnsureModule(addrs.RootModuleInstance)
+	mod.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.x").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"test_string":"wrong val"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	mod.SetOutputValue("from_resource", cty.StringVal("wrong val"), false)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	opts := SimplePlanOpts(plans.RefreshOnlyMode, nil)
+	plan, diags := ctx.Plan(m, state, opts)
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	resCheck := state.CheckResults.GetObjectResult(mustResourceInstanceAddr("test_object.x"))
+	if resCheck.Status != checks.StatusPass {
+		t.Fatalf("unexpected check %s: %s\n", resCheck.Status, resCheck.FailureMessages)
+	}
+
+	outAddr := addrs.AbsOutputValue{
+		Module: addrs.RootModuleInstance,
+		OutputValue: addrs.OutputValue{
+			Name: "from_resource",
+		},
+	}
+	outCheck := state.CheckResults.GetObjectResult(outAddr)
+	if outCheck.Status != checks.StatusPass {
+		t.Fatalf("unexpected check %s: %s\n", outCheck.Status, outCheck.FailureMessages)
+	}
+}
+
+// NoOp changes may have conditions to evaluate, but should not re-plan and
+// apply the entire resource.
+func TestContext2Apply_noRePlanNoOp(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "x" {
+}
+
+resource "test_object" "y" {
+  # test_object.w is being re-created, so this precondition must be evaluated
+  # during apply, however this resource should otherwise be a NoOp.
+  lifecycle {
+    precondition {
+      condition     = test_object.x.test_string == null
+      error_message = "test_object.x.test_string should be null"
+    }
+  }
+}
+`})
+
+	p := simpleMockProvider()
+	// make sure we can compute the attr
+	testString := p.GetProviderSchemaResponse.ResourceTypes["test_object"].Block.Attributes["test_string"]
+	testString.Computed = true
+	testString.Optional = false
+
+	yAddr := mustResourceInstanceAddr("test_object.y")
+
+	state := states.NewState()
+	mod := state.RootModule()
+	mod.SetResourceInstanceCurrent(
+		yAddr.Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"test_string":"y"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	opts := SimplePlanOpts(plans.NormalMode, nil)
+	plan, diags := ctx.Plan(m, state, opts)
+	assertNoErrors(t, diags)
+
+	for _, c := range plan.Changes.Resources {
+		if c.Addr.Equal(yAddr) && c.Action != plans.NoOp {
+			t.Fatalf("unexpected %s change for test_object.y", c.Action)
+		}
+	}
+
+	// test_object.y is a NoOp change from the plan, but is included in the
+	// graph due to the conditions which must be evaluated. This however should
+	// not cause the resource to be re-planned.
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		testString := req.ProposedNewState.GetAttr("test_string")
+		if !testString.IsNull() && testString.AsString() == "y" {
+			resp.Diagnostics = resp.Diagnostics.Append(errors.New("Unexpected apply-time plan for test_object.y. Original plan was a NoOp"))
+		}
+		resp.PlannedState = req.ProposedNewState
+		return resp
+	}
+
+	_, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+}
+
+// ensure all references from preconditions are tracked through plan and apply
+func TestContext2Apply_preconditionErrorMessageRef(t *testing.T) {
+	p := testProvider("test")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "nested" {
+  source = "./mod"
+}
+
+output "nested_a" {
+  value = module.nested.a
+}
+`,
+
+		"mod/main.tf": `
+variable "boop" {
+  default = "boop"
+}
+
+variable "msg" {
+  default = "Incorrect boop."
+}
+
+output "a" {
+  value     = "x"
+
+  precondition {
+    condition     = var.boop == "boop"
+    error_message = var.msg
+  }
+}
+`,
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+	})
+	assertNoErrors(t, diags)
+	_, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+}
+
+func TestContext2Apply_destroyNullModuleOutput(t *testing.T) {
+	p := testProvider("test")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "null_module" {
+  source = "./mod"
+}
+
+locals {
+  module_output = module.null_module.null_module_test
+}
+
+output "test_root" {
+  value = module.null_module.test_output
+}
+
+output "root_module" {
+  value = local.module_output #fails
+}
+`,
+
+		"mod/main.tf": `
+output "test_output" {
+  value = "test"
+}
+
+output "null_module_test" {
+  value = null
+}
+`,
+	})
+
+	// verify plan and apply
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+	})
+	assertNoErrors(t, diags)
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	// now destroy
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+	_, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+}
+
+func TestContext2Apply_moduleOutputWithSensitiveAttrs(t *testing.T) {
+	// Ensure that nested sensitive marks are stored when accessing non-root
+	// module outputs, and that they do not cause the entire output value to
+	// become sensitive.
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod" {
+  source = "./mod"
+}
+
+resource "test_resource" "b" {
+  // if the module output were wholly sensitive it would not be valid to use in
+  // for_each
+  for_each = module.mod.resources
+  value = each.value.output
+}
+
+output "root_output" {
+  // The root output cannot contain any sensitive marks at all.
+  // Applying nonsensitive would fail here if the nested sensitive mark were
+  // not maintained through the output.
+  value = [ for k, v in module.mod.resources : nonsensitive(v.output) ]
+}
+`,
+		"./mod/main.tf": `
+resource "test_resource" "a" {
+  for_each = {"key": "value"}
+  value = each.key
+}
+
+output "resources" {
+  value = test_resource.a
+}
+`,
+	})
+
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"value": {
+						Type:     cty.String,
+						Required: true,
+					},
+					"output": {
+						Type:      cty.String,
+						Sensitive: true,
+						Computed:  true,
+					},
+				},
+			},
+		},
+	})
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+	})
+	assertNoErrors(t, diags)
+	_, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+}
+
+func TestContext2Apply_timestamps(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_resource" "a" {
+  id = "timestamp"
+  value = timestamp()
+}
+
+resource "test_resource" "b" {
+  id = "plantimestamp"
+  value = plantimestamp()
+}
+`,
+	})
+
+	var plantime time.Time
+
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Required: true,
+					},
+					"value": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = func(request providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		values := request.ProposedNewState.AsValueMap()
+		if id := values["id"]; id.AsString() == "plantimestamp" {
+			var err error
+			plantime, err = time.Parse(time.RFC3339, values["value"].AsString())
+			if err != nil {
+				t.Errorf("couldn't parse plan time: %s", err)
+			}
+		}
+
+		return providers.PlanResourceChangeResponse{
+			PlannedState: request.ProposedNewState,
+		}
+	}
+	p.ApplyResourceChangeFn = func(request providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		values := request.PlannedState.AsValueMap()
+		if id := values["id"]; id.AsString() == "timestamp" {
+			applytime, err := time.Parse(time.RFC3339, values["value"].AsString())
+			if err != nil {
+				t.Errorf("couldn't parse apply time: %s", err)
+			}
+
+			if applytime.Before(plantime) {
+				t.Errorf("applytime (%s) should be after plantime (%s)", applytime.Format(time.RFC3339), plantime.Format(time.RFC3339))
+			}
+		} else if id.AsString() == "plantimestamp" {
+			otherplantime, err := time.Parse(time.RFC3339, values["value"].AsString())
+			if err != nil {
+				t.Errorf("couldn't parse plan time: %s", err)
+			}
+
+			if !plantime.Equal(otherplantime) {
+				t.Errorf("plantime changed from (%s) to (%s) during apply", plantime.Format(time.RFC3339), otherplantime.Format(time.RFC3339))
+			}
+		}
+
+		return providers.ApplyResourceChangeResponse{
+			NewState: request.PlannedState,
+		}
+	}
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+	})
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+}
+
+func TestContext2Apply_destroyUnusedModuleProvider(t *testing.T) {
+	// an unsued provider within a module should not be called during destroy
+	unusedProvider := testProvider("unused")
+	testProvider := testProvider("test")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"):   testProviderFuncFixed(testProvider),
+			addrs.NewDefaultProvider("unused"): testProviderFuncFixed(unusedProvider),
+		},
+	})
+
+	unusedProvider.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		resp.Diagnostics = resp.Diagnostics.Append(errors.New("configuration failed"))
+		return resp
+	}
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod" {
+  source = "./mod"
+}
+
+resource "test_resource" "test" {
+}
+`,
+
+		"mod/main.tf": `
+provider "unused" {
+}
+
+resource "unused_resource" "test" {
+}
+`,
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+	_, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+}
+
+func TestContext2Apply_import(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_resource" "a" {
+  id = "importable"
+}
+
+import {
+  to = test_resource.a
+  id = "importable" 
+}
+`,
+	})
+
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+	p.ImportResourceStateFn = func(req providers.ImportResourceStateRequest) providers.ImportResourceStateResponse {
+		return providers.ImportResourceStateResponse{
+			ImportedResources: []providers.ImportedResource{
+				{
+					TypeName: "test_instance",
+					State: cty.ObjectVal(map[string]cty.Value{
+						"id": cty.StringVal("importable"),
+					}),
+				},
+			},
+		}
+	}
+	hook := new(MockHook)
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{hook},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+	})
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	if !hook.PreApplyImportCalled {
+		t.Fatalf("PreApplyImport hook not called")
+	}
+	if addr, wantAddr := hook.PreApplyImportAddr, mustResourceInstanceAddr("test_resource.a"); !addr.Equal(wantAddr) {
+		t.Errorf("expected addr to be %s, but was %s", wantAddr, addr)
+	}
+
+	if !hook.PostApplyImportCalled {
+		t.Fatalf("PostApplyImport hook not called")
+	}
+	if addr, wantAddr := hook.PostApplyImportAddr, mustResourceInstanceAddr("test_resource.a"); !addr.Equal(wantAddr) {
+		t.Errorf("expected addr to be %s, but was %s", wantAddr, addr)
+	}
+}
diff --git a/v1.5.7/internal/terraform/context_apply_checks_test.go b/v1.5.7/internal/terraform/context_apply_checks_test.go
new file mode 100644
index 0000000..9dfca3e
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_apply_checks_test.go
@@ -0,0 +1,819 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// This file contains 'integration' tests for the Terraform check blocks.
+//
+// These tests could live in context_apply_test or context_apply2_test but given
+// the size of those files, it makes sense to keep these check related tests
+// grouped together.
+
+type checksTestingStatus struct {
+	status   checks.Status
+	messages []string
+}
+
+func TestContextChecks(t *testing.T) {
+	tests := map[string]struct {
+		configs      map[string]string
+		plan         map[string]checksTestingStatus
+		planError    string
+		planWarning  string
+		apply        map[string]checksTestingStatus
+		applyError   string
+		applyWarning string
+		state        *states.State
+		provider     *MockProvider
+		providerHook func(*MockProvider)
+	}{
+		"passing": {
+			configs: map[string]string{
+				"main.tf": `
+provider "checks" {}
+
+check "passing" {
+  data "checks_object" "positive" {}
+
+  assert {
+    condition     = data.checks_object.positive.number >= 0
+    error_message = "negative number"
+  }
+}
+`,
+			},
+			plan: map[string]checksTestingStatus{
+				"passing": {
+					status: checks.StatusPass,
+				},
+			},
+			apply: map[string]checksTestingStatus{
+				"passing": {
+					status: checks.StatusPass,
+				},
+			},
+			provider: &MockProvider{
+				Meta: "checks",
+				GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+					DataSources: map[string]providers.Schema{
+						"checks_object": {
+							Block: &configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"number": {
+										Type:     cty.Number,
+										Computed: true,
+									},
+								},
+							},
+						},
+					},
+				},
+				ReadDataSourceFn: func(request providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+					return providers.ReadDataSourceResponse{
+						State: cty.ObjectVal(map[string]cty.Value{
+							"number": cty.NumberIntVal(0),
+						}),
+					}
+				},
+			},
+		},
+		"failing": {
+			configs: map[string]string{
+				"main.tf": `
+provider "checks" {}
+
+check "failing" {
+  data "checks_object" "positive" {}
+
+  assert {
+    condition     = data.checks_object.positive.number >= 0
+    error_message = "negative number"
+  }
+}
+`,
+			},
+			plan: map[string]checksTestingStatus{
+				"failing": {
+					status:   checks.StatusFail,
+					messages: []string{"negative number"},
+				},
+			},
+			planWarning: "Check block assertion failed: negative number",
+			apply: map[string]checksTestingStatus{
+				"failing": {
+					status:   checks.StatusFail,
+					messages: []string{"negative number"},
+				},
+			},
+			applyWarning: "Check block assertion failed: negative number",
+			provider: &MockProvider{
+				Meta: "checks",
+				GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+					DataSources: map[string]providers.Schema{
+						"checks_object": {
+							Block: &configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"number": {
+										Type:     cty.Number,
+										Computed: true,
+									},
+								},
+							},
+						},
+					},
+				},
+				ReadDataSourceFn: func(request providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+					return providers.ReadDataSourceResponse{
+						State: cty.ObjectVal(map[string]cty.Value{
+							"number": cty.NumberIntVal(-1),
+						}),
+					}
+				},
+			},
+		},
+		"mixed": {
+			configs: map[string]string{
+				"main.tf": `
+provider "checks" {}
+
+check "failing" {
+  data "checks_object" "neutral" {}
+
+  assert {
+    condition     = data.checks_object.neutral.number >= 0
+    error_message = "negative number"
+  }
+
+  assert {
+    condition = data.checks_object.neutral.number < 0
+    error_message = "positive number"
+  }
+}
+`,
+			},
+			plan: map[string]checksTestingStatus{
+				"failing": {
+					status:   checks.StatusFail,
+					messages: []string{"positive number"},
+				},
+			},
+			planWarning: "Check block assertion failed: positive number",
+			apply: map[string]checksTestingStatus{
+				"failing": {
+					status:   checks.StatusFail,
+					messages: []string{"positive number"},
+				},
+			},
+			applyWarning: "Check block assertion failed: positive number",
+			provider: &MockProvider{
+				Meta: "checks",
+				GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+					DataSources: map[string]providers.Schema{
+						"checks_object": {
+							Block: &configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"number": {
+										Type:     cty.Number,
+										Computed: true,
+									},
+								},
+							},
+						},
+					},
+				},
+				ReadDataSourceFn: func(request providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+					return providers.ReadDataSourceResponse{
+						State: cty.ObjectVal(map[string]cty.Value{
+							"number": cty.NumberIntVal(0),
+						}),
+					}
+				},
+			},
+		},
+		"nested data blocks reload during apply": {
+			configs: map[string]string{
+				"main.tf": `
+provider "checks" {}
+
+data "checks_object" "data_block" {}
+
+check "data_block" {
+  assert {
+    condition     = data.checks_object.data_block.number >= 0
+    error_message = "negative number"
+  }
+}
+
+check "nested_data_block" {
+  data "checks_object" "nested_data_block" {}
+
+  assert {
+    condition     = data.checks_object.nested_data_block.number >= 0
+    error_message = "negative number"
+  }
+}
+`,
+			},
+			plan: map[string]checksTestingStatus{
+				"nested_data_block": {
+					status:   checks.StatusFail,
+					messages: []string{"negative number"},
+				},
+				"data_block": {
+					status:   checks.StatusFail,
+					messages: []string{"negative number"},
+				},
+			},
+			planWarning: "2 warnings:\n\n- Check block assertion failed: negative number\n- Check block assertion failed: negative number",
+			apply: map[string]checksTestingStatus{
+				"nested_data_block": {
+					status: checks.StatusPass,
+				},
+				"data_block": {
+					status:   checks.StatusFail,
+					messages: []string{"negative number"},
+				},
+			},
+			applyWarning: "Check block assertion failed: negative number",
+			provider: &MockProvider{
+				Meta: "checks",
+				GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+					DataSources: map[string]providers.Schema{
+						"checks_object": {
+							Block: &configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"number": {
+										Type:     cty.Number,
+										Computed: true,
+									},
+								},
+							},
+						},
+					},
+				},
+				ReadDataSourceFn: func(request providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+					return providers.ReadDataSourceResponse{
+						State: cty.ObjectVal(map[string]cty.Value{
+							"number": cty.NumberIntVal(-1),
+						}),
+					}
+				},
+			},
+			providerHook: func(provider *MockProvider) {
+				provider.ReadDataSourceFn = func(request providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+					// The data returned by the data sources are changing
+					// between the plan and apply stage. The nested data block
+					// will update to reflect this while the normal data block
+					// will not detect the change.
+					return providers.ReadDataSourceResponse{
+						State: cty.ObjectVal(map[string]cty.Value{
+							"number": cty.NumberIntVal(0),
+						}),
+					}
+				}
+			},
+		},
+		"returns unknown for unknown config": {
+			configs: map[string]string{
+				"main.tf": `
+provider "checks" {}
+
+resource "checks_object" "resource_block" {}
+
+check "resource_block" {
+  data "checks_object" "data_block" {
+    id = checks_object.resource_block.id
+  }
+
+  assert {
+    condition = data.checks_object.data_block.number >= 0
+    error_message = "negative number"
+  }
+}
+`,
+			},
+			plan: map[string]checksTestingStatus{
+				"resource_block": {
+					status: checks.StatusUnknown,
+				},
+			},
+			planWarning: "Check block assertion known after apply: The condition could not be evaluated at this time, a result will be known when this plan is applied.",
+			apply: map[string]checksTestingStatus{
+				"resource_block": {
+					status: checks.StatusPass,
+				},
+			},
+			provider: &MockProvider{
+				Meta: "checks",
+				GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+					ResourceTypes: map[string]providers.Schema{
+						"checks_object": {
+							Block: &configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"id": {
+										Type:     cty.String,
+										Computed: true,
+									},
+								},
+							},
+						},
+					},
+					DataSources: map[string]providers.Schema{
+						"checks_object": {
+							Block: &configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"id": {
+										Type:     cty.String,
+										Required: true,
+									},
+									"number": {
+										Type:     cty.Number,
+										Computed: true,
+									},
+								},
+							},
+						},
+					},
+				},
+				PlanResourceChangeFn: func(request providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+					return providers.PlanResourceChangeResponse{
+						PlannedState: cty.ObjectVal(map[string]cty.Value{
+							"id": cty.UnknownVal(cty.String),
+						}),
+					}
+				},
+				ApplyResourceChangeFn: func(request providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+					return providers.ApplyResourceChangeResponse{
+						NewState: cty.ObjectVal(map[string]cty.Value{
+							"id": cty.StringVal("7A9F887D-44C7-4281-80E5-578E41F99DFC"),
+						}),
+					}
+				},
+				ReadDataSourceFn: func(request providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+					values := request.Config.AsValueMap()
+					if id, ok := values["id"]; ok {
+						if id.IsKnown() && id.AsString() == "7A9F887D-44C7-4281-80E5-578E41F99DFC" {
+							return providers.ReadDataSourceResponse{
+								State: cty.ObjectVal(map[string]cty.Value{
+									"id":     cty.StringVal("7A9F887D-44C7-4281-80E5-578E41F99DFC"),
+									"number": cty.NumberIntVal(0),
+								}),
+							}
+						}
+					}
+
+					return providers.ReadDataSourceResponse{
+						Diagnostics: tfdiags.Diagnostics{tfdiags.Sourceless(tfdiags.Error, "shouldn't make it here", "really shouldn't make it here")},
+					}
+				},
+			},
+		},
+		"failing nested data source doesn't block the plan": {
+			configs: map[string]string{
+				"main.tf": `
+provider "checks" {}
+
+check "error" {
+  data "checks_object" "data_block" {}
+
+  assert {
+    condition = data.checks_object.data_block.number >= 0
+    error_message = "negative number"
+  }
+}
+`,
+			},
+			plan: map[string]checksTestingStatus{
+				"error": {
+					status: checks.StatusFail,
+					messages: []string{
+						"data source read failed: something bad happened and the provider couldn't read the data source",
+					},
+				},
+			},
+			planWarning: "data source read failed: something bad happened and the provider couldn't read the data source",
+			apply: map[string]checksTestingStatus{
+				"error": {
+					status: checks.StatusFail,
+					messages: []string{
+						"data source read failed: something bad happened and the provider couldn't read the data source",
+					},
+				},
+			},
+			applyWarning: "data source read failed: something bad happened and the provider couldn't read the data source",
+			provider: &MockProvider{
+				Meta: "checks",
+				GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+					DataSources: map[string]providers.Schema{
+						"checks_object": {
+							Block: &configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"number": {
+										Type:     cty.Number,
+										Computed: true,
+									},
+								},
+							},
+						},
+					},
+				},
+				ReadDataSourceFn: func(request providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+					return providers.ReadDataSourceResponse{
+						Diagnostics: tfdiags.Diagnostics{tfdiags.Sourceless(tfdiags.Error, "data source read failed", "something bad happened and the provider couldn't read the data source")},
+					}
+				},
+			},
+		}, "failing nested data source should prevent checks from executing": {
+			configs: map[string]string{
+				"main.tf": `
+provider "checks" {}
+
+resource "checks_object" "resource_block" {
+  number = -1
+}
+
+check "error" {
+  data "checks_object" "data_block" {}
+
+  assert {
+    condition = checks_object.resource_block.number >= 0
+    error_message = "negative number"
+  }
+}
+`,
+			},
+			state: states.BuildState(func(state *states.SyncState) {
+				state.SetResourceInstanceCurrent(
+					addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "checks_object",
+						Name: "resource_block",
+					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{"number": -1}`),
+					},
+					addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("test"),
+						Module:   addrs.RootModule,
+					})
+			}),
+			plan: map[string]checksTestingStatus{
+				"error": {
+					status: checks.StatusFail,
+					messages: []string{
+						"data source read failed: something bad happened and the provider couldn't read the data source",
+					},
+				},
+			},
+			planWarning: "data source read failed: something bad happened and the provider couldn't read the data source",
+			apply: map[string]checksTestingStatus{
+				"error": {
+					status: checks.StatusFail,
+					messages: []string{
+						"data source read failed: something bad happened and the provider couldn't read the data source",
+					},
+				},
+			},
+			applyWarning: "data source read failed: something bad happened and the provider couldn't read the data source",
+			provider: &MockProvider{
+				Meta: "checks",
+				GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+					ResourceTypes: map[string]providers.Schema{
+						"checks_object": {
+							Block: &configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"number": {
+										Type:     cty.Number,
+										Required: true,
+									},
+								},
+							},
+						},
+					},
+					DataSources: map[string]providers.Schema{
+						"checks_object": {
+							Block: &configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"number": {
+										Type:     cty.Number,
+										Computed: true,
+									},
+								},
+							},
+						},
+					},
+				},
+				PlanResourceChangeFn: func(request providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+					return providers.PlanResourceChangeResponse{
+						PlannedState: cty.ObjectVal(map[string]cty.Value{
+							"number": cty.NumberIntVal(-1),
+						}),
+					}
+				},
+				ApplyResourceChangeFn: func(request providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+					return providers.ApplyResourceChangeResponse{
+						NewState: cty.ObjectVal(map[string]cty.Value{
+							"number": cty.NumberIntVal(-1),
+						}),
+					}
+				},
+				ReadDataSourceFn: func(request providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+					return providers.ReadDataSourceResponse{
+						Diagnostics: tfdiags.Diagnostics{tfdiags.Sourceless(tfdiags.Error, "data source read failed", "something bad happened and the provider couldn't read the data source")},
+					}
+				},
+			},
+		},
+		"check failing in state and passing after plan and apply": {
+			configs: map[string]string{
+				"main.tf": `
+provider "checks" {}
+
+resource "checks_object" "resource" {
+  number = 0
+}
+
+check "passing" {
+  assert {
+    condition     = checks_object.resource.number >= 0
+    error_message = "negative number"
+  }
+}
+`,
+			},
+			state: states.BuildState(func(state *states.SyncState) {
+				state.SetResourceInstanceCurrent(
+					addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "checks_object",
+						Name: "resource",
+					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+					&states.ResourceInstanceObjectSrc{
+						Status:    states.ObjectReady,
+						AttrsJSON: []byte(`{"number": -1}`),
+					},
+					addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("test"),
+						Module:   addrs.RootModule,
+					})
+			}),
+			plan: map[string]checksTestingStatus{
+				"passing": {
+					status: checks.StatusPass,
+				},
+			},
+			apply: map[string]checksTestingStatus{
+				"passing": {
+					status: checks.StatusPass,
+				},
+			},
+			provider: &MockProvider{
+				Meta: "checks",
+				GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+					ResourceTypes: map[string]providers.Schema{
+						"checks_object": {
+							Block: &configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"number": {
+										Type:     cty.Number,
+										Required: true,
+									},
+								},
+							},
+						},
+					},
+				},
+				PlanResourceChangeFn: func(request providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+					return providers.PlanResourceChangeResponse{
+						PlannedState: cty.ObjectVal(map[string]cty.Value{
+							"number": cty.NumberIntVal(0),
+						}),
+					}
+				},
+				ApplyResourceChangeFn: func(request providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+					return providers.ApplyResourceChangeResponse{
+						NewState: cty.ObjectVal(map[string]cty.Value{
+							"number": cty.NumberIntVal(0),
+						}),
+					}
+				},
+			},
+		},
+		"failing data source does block the plan": {
+			configs: map[string]string{
+				"main.tf": `
+provider "checks" {}
+
+data "checks_object" "data_block" {}
+
+check "error" {
+  assert {
+    condition = data.checks_object.data_block.number >= 0
+    error_message = "negative number"
+  }
+}
+`,
+			},
+			planError: "data source read failed: something bad happened and the provider couldn't read the data source",
+			provider: &MockProvider{
+				Meta: "checks",
+				GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+					DataSources: map[string]providers.Schema{
+						"checks_object": {
+							Block: &configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"number": {
+										Type:     cty.Number,
+										Computed: true,
+									},
+								},
+							},
+						},
+					},
+				},
+				ReadDataSourceFn: func(request providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+					return providers.ReadDataSourceResponse{
+						Diagnostics: tfdiags.Diagnostics{tfdiags.Sourceless(tfdiags.Error, "data source read failed", "something bad happened and the provider couldn't read the data source")},
+					}
+				},
+			},
+		},
+		"invalid reference into check block": {
+			configs: map[string]string{
+				"main.tf": `
+provider "checks" {}
+
+data "checks_object" "data_block" {
+  id = data.checks_object.nested_data_block.id
+}
+
+check "error" {
+  data "checks_object" "nested_data_block" {}
+
+  assert {
+    condition = data.checks_object.data_block.number >= 0
+    error_message = "negative number"
+  }
+}
+`,
+			},
+			planError: "Reference to scoped resource: The referenced data resource \"checks_object\" \"nested_data_block\" is not available from this context.",
+			provider: &MockProvider{
+				Meta: "checks",
+				GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+					DataSources: map[string]providers.Schema{
+						"checks_object": {
+							Block: &configschema.Block{
+								Attributes: map[string]*configschema.Attribute{
+									"id": {
+										Type:     cty.String,
+										Computed: true,
+										Optional: true,
+									},
+								},
+							},
+						},
+					},
+				},
+				ReadDataSourceFn: func(request providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+					input := request.Config.AsValueMap()
+					if _, ok := input["id"]; ok {
+						return providers.ReadDataSourceResponse{
+							State: request.Config,
+						}
+					}
+
+					return providers.ReadDataSourceResponse{
+						State: cty.ObjectVal(map[string]cty.Value{
+							"id": cty.UnknownVal(cty.String),
+						}),
+					}
+				},
+			},
+		},
+	}
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			configs := testModuleInline(t, test.configs)
+			ctx := testContext2(t, &ContextOpts{
+				Providers: map[addrs.Provider]providers.Factory{
+					addrs.NewDefaultProvider(test.provider.Meta.(string)): testProviderFuncFixed(test.provider),
+				},
+			})
+
+			initialState := states.NewState()
+			if test.state != nil {
+				initialState = test.state
+			}
+
+			plan, diags := ctx.Plan(configs, initialState, &PlanOpts{
+				Mode: plans.NormalMode,
+			})
+			if validateCheckDiagnostics(t, "planning", test.planWarning, test.planError, diags) {
+				return
+			}
+			validateCheckResults(t, "planning", test.plan, plan.Checks)
+
+			if test.providerHook != nil {
+				// This gives an opportunity to change the behaviour of the
+				// provider between the plan and apply stages.
+				test.providerHook(test.provider)
+			}
+
+			state, diags := ctx.Apply(plan, configs)
+			if validateCheckDiagnostics(t, "apply", test.applyWarning, test.applyError, diags) {
+				return
+			}
+			validateCheckResults(t, "apply", test.apply, state.CheckResults)
+		})
+	}
+}
+
+func validateCheckDiagnostics(t *testing.T, stage string, expectedWarning, expectedError string, actual tfdiags.Diagnostics) bool {
+	if expectedError != "" {
+		if !actual.HasErrors() {
+			t.Errorf("expected %s to error with \"%s\", but no errors were returned", stage, expectedError)
+		} else if expectedError != actual.Err().Error() {
+			t.Errorf("expected %s to error with \"%s\" but found \"%s\"", stage, expectedError, actual.Err())
+		}
+
+		// If we expected an error then we won't finish the rest of the test.
+		return true
+	}
+
+	if expectedWarning != "" {
+		warnings := actual.ErrWithWarnings()
+		if actual.ErrWithWarnings() == nil {
+			t.Errorf("expected %s to warn with \"%s\", but no errors were returned", stage, expectedWarning)
+		} else if expectedWarning != warnings.Error() {
+			t.Errorf("expected %s to warn with \"%s\" but found \"%s\"", stage, expectedWarning, warnings)
+		}
+	} else {
+		if actual.ErrWithWarnings() != nil {
+			t.Errorf("expected %s to produce no diagnostics but found \"%s\"", stage, actual.ErrWithWarnings())
+		}
+	}
+
+	assertNoErrors(t, actual)
+	return false
+}
+
+func validateCheckResults(t *testing.T, stage string, expected map[string]checksTestingStatus, actual *states.CheckResults) {
+
+	// Just a quick sanity check that the plan or apply process didn't create
+	// some non-existent checks.
+	if len(expected) != len(actual.ConfigResults.Keys()) {
+		t.Errorf("expected %d check results but found %d after %s", len(expected), len(actual.ConfigResults.Keys()), stage)
+	}
+
+	// Now, lets make sure the checks all match what we expect.
+	for check, want := range expected {
+		results := actual.GetObjectResult(addrs.Check{
+			Name: check,
+		}.Absolute(addrs.RootModuleInstance))
+
+		if results.Status != want.status {
+			t.Errorf("%s: wanted %s but got %s after %s", check, want.status, results.Status, stage)
+		}
+
+		if len(want.messages) != len(results.FailureMessages) {
+			t.Errorf("%s: expected %d failure messages but had %d after %s", check, len(want.messages), len(results.FailureMessages), stage)
+		}
+
+		max := len(want.messages)
+		if len(results.FailureMessages) > max {
+			max = len(results.FailureMessages)
+		}
+
+		for ix := 0; ix < max; ix++ {
+			var expected, actual string
+			if ix < len(want.messages) {
+				expected = want.messages[ix]
+			}
+			if ix < len(results.FailureMessages) {
+				actual = results.FailureMessages[ix]
+			}
+
+			// Order matters!
+			if actual != expected {
+				t.Errorf("%s: expected failure message at %d to be \"%s\" but was \"%s\" after %s", check, ix, expected, actual, stage)
+			}
+		}
+
+	}
+}
diff --git a/v1.5.7/internal/terraform/context_apply_test.go b/v1.5.7/internal/terraform/context_apply_test.go
new file mode 100644
index 0000000..f6dd03b
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_apply_test.go
@@ -0,0 +1,12801 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"log"
+	"reflect"
+	"runtime"
+	"sort"
+	"strings"
+	"sync"
+	"sync/atomic"
+	"testing"
+	"time"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/go-test/deep"
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/gocty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestContext2Apply_basic(t *testing.T) {
+	m := testModule(t, "apply-good")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	mod := state.RootModule()
+	if len(mod.Resources) < 2 {
+		t.Fatalf("bad: %#v", mod.Resources)
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_stop(t *testing.T) {
+	t.Parallel()
+
+	m := testModule(t, "apply-stop")
+	stopCh := make(chan struct{})
+	waitCh := make(chan struct{})
+	stoppedCh := make(chan struct{})
+	stopCalled := uint32(0)
+	applyStopped := uint32(0)
+	p := &MockProvider{
+		GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+			ResourceTypes: map[string]providers.Schema{
+				"indefinite": {
+					Version: 1,
+					Block: &configschema.Block{
+						Attributes: map[string]*configschema.Attribute{
+							"result": {
+								Type:     cty.String,
+								Computed: true,
+							},
+						},
+					},
+				},
+			},
+		},
+		PlanResourceChangeFn: func(prcr providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+			log.Printf("[TRACE] TestContext2Apply_stop: no-op PlanResourceChange")
+			return providers.PlanResourceChangeResponse{
+				PlannedState: cty.ObjectVal(map[string]cty.Value{
+					"result": cty.UnknownVal(cty.String),
+				}),
+			}
+		},
+		ApplyResourceChangeFn: func(arcr providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+			// This will unblock the main test code once we reach this
+			// point, so that it'll then be guaranteed to call Stop
+			// while we're waiting in here.
+			close(waitCh)
+
+			log.Printf("[TRACE] TestContext2Apply_stop: ApplyResourceChange waiting for Stop call")
+			// This will block until StopFn closes this channel below.
+			<-stopCh
+			atomic.AddUint32(&applyStopped, 1)
+			// This unblocks StopFn below, thereby acknowledging the request
+			// to stop.
+			close(stoppedCh)
+			return providers.ApplyResourceChangeResponse{
+				NewState: cty.ObjectVal(map[string]cty.Value{
+					"result": cty.StringVal("complete"),
+				}),
+			}
+		},
+		StopFn: func() error {
+			// Closing this channel will unblock the channel read in
+			// ApplyResourceChangeFn above.
+			log.Printf("[TRACE] TestContext2Apply_stop: Stop called")
+			atomic.AddUint32(&stopCalled, 1)
+			close(stopCh)
+			// This will block until ApplyResourceChange has reacted to
+			// being stopped.
+			log.Printf("[TRACE] TestContext2Apply_stop: Waiting for ApplyResourceChange to react to being stopped")
+			<-stoppedCh
+			log.Printf("[TRACE] TestContext2Apply_stop: Stop is completing")
+			return nil
+		},
+	}
+
+	hook := &testHook{}
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{hook},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.MustParseProviderSourceString("terraform.io/test/indefinite"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	// We'll reset the hook events before we apply because we only care about
+	// the apply-time events.
+	hook.Calls = hook.Calls[:0]
+
+	// We'll apply in the background so that we can call Stop in the foreground.
+	stateCh := make(chan *states.State)
+	go func(plan *plans.Plan) {
+		state, _ := ctx.Apply(plan, m)
+		stateCh <- state
+	}(plan)
+
+	// We'll wait until the provider signals that we've reached the
+	// ApplyResourceChange function, so we can guarantee the expected
+	// order of operations so our hook events below will always match.
+	t.Log("waiting for the apply phase to get started")
+	<-waitCh
+
+	// This will block until the apply operation has unwound, so we should
+	// be able to observe all of the apply side-effects afterwards.
+	t.Log("waiting for ctx.Stop to return")
+	ctx.Stop()
+
+	t.Log("waiting for apply goroutine to return state")
+	state := <-stateCh
+
+	t.Log("apply is all complete")
+	if state == nil {
+		t.Fatalf("final state is nil")
+	}
+
+	if got, want := atomic.LoadUint32(&stopCalled), uint32(1); got != want {
+		t.Errorf("provider's Stop method was not called")
+	}
+	if got, want := atomic.LoadUint32(&applyStopped), uint32(1); got != want {
+		// This should not happen if things are working correctly but this is
+		// to catch weird situations such as if a bug in this test causes us
+		// to inadvertently stop Terraform before it reaches te apply phase,
+		// or if the apply operation fails in a way that causes it not to reach
+		// the ApplyResourceChange function.
+		t.Errorf("somehow provider's ApplyResourceChange didn't react to being stopped")
+	}
+
+	// Because we interrupted the apply phase while applying the resource,
+	// we should have halted immediately after we finished visiting that
+	// resource. We don't visit indefinite.bar at all.
+	gotEvents := hook.Calls
+	wantEvents := []*testHookCall{
+		{"PreDiff", "indefinite.foo"},
+		{"PostDiff", "indefinite.foo"},
+		{"PreApply", "indefinite.foo"},
+		{"PostApply", "indefinite.foo"},
+		{"PostStateUpdate", ""}, // State gets updated one more time to include the apply result.
+	}
+	// The "Stopping" event gets sent to the hook asynchronously from the others
+	// because it is triggered in the ctx.Stop call above, rather than from
+	// the goroutine where ctx.Apply was running, and therefore it doesn't
+	// appear in a guaranteed position in gotEvents. We already checked above
+	// that the provider's Stop method was called, so we'll just strip that
+	// event out of our gotEvents.
+	seenStopped := false
+	for i, call := range gotEvents {
+		if call.Action == "Stopping" {
+			seenStopped = true
+			// We'll shift up everything else in the slice to create the
+			// effect of the Stopping event not having been present at all,
+			// which should therefore make this slice match "wantEvents".
+			copy(gotEvents[i:], gotEvents[i+1:])
+			gotEvents = gotEvents[:len(gotEvents)-1]
+			break
+		}
+	}
+	if diff := cmp.Diff(wantEvents, gotEvents); diff != "" {
+		t.Errorf("wrong hook events\n%s", diff)
+	}
+	if !seenStopped {
+		t.Errorf("'Stopping' event did not get sent to the hook")
+	}
+
+	rov := state.OutputValue(addrs.OutputValue{Name: "result"}.Absolute(addrs.RootModuleInstance))
+	if rov != nil && rov.Value != cty.NilVal && !rov.Value.IsNull() {
+		t.Errorf("'result' output value unexpectedly populated: %#v", rov.Value)
+	}
+
+	resourceAddr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "indefinite",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+	rv := state.ResourceInstance(resourceAddr)
+	if rv == nil || rv.Current == nil {
+		t.Fatalf("no state entry for %s", resourceAddr)
+	}
+
+	resourceAddr.Resource.Resource.Name = "bar"
+	rv = state.ResourceInstance(resourceAddr)
+	if rv != nil && rv.Current != nil {
+		t.Fatalf("unexpected state entry for %s", resourceAddr)
+	}
+}
+
+func TestContext2Apply_unstable(t *testing.T) {
+	// This tests behavior when the configuration contains an unstable value,
+	// such as the result of uuid() or timestamp(), where each call produces
+	// a different result.
+	//
+	// This is an important case to test because we need to ensure that
+	// we don't re-call the function during the apply phase: the value should
+	// be fixed during plan
+
+	m := testModule(t, "apply-unstable")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error during Plan: %s", diags.Err())
+	}
+
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_resource",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+	schema := p.GetProviderSchemaResponse.ResourceTypes["test_resource"].Block
+	rds := plan.Changes.ResourceInstance(addr)
+	rd, err := rds.Decode(schema.ImpliedType())
+	if err != nil {
+		t.Fatal(err)
+	}
+	if rd.After.GetAttr("random").IsKnown() {
+		t.Fatalf("Attribute 'random' has known value %#v; should be unknown in plan", rd.After.GetAttr("random"))
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error during Apply: %s", diags.Err())
+	}
+
+	mod := state.Module(addr.Module)
+	rss := state.ResourceInstance(addr)
+
+	if len(mod.Resources) != 1 {
+		t.Fatalf("wrong number of resources %d; want 1", len(mod.Resources))
+	}
+
+	rs, err := rss.Current.Decode(schema.ImpliedType())
+	if err != nil {
+		t.Fatalf("decode error: %v", err)
+	}
+	got := rs.Value.GetAttr("random")
+	if !got.IsKnown() {
+		t.Fatalf("random is still unknown after apply")
+	}
+	if got, want := len(got.AsString()), 36; got != want {
+		t.Fatalf("random string has wrong length %d; want %d", got, want)
+	}
+}
+
+func TestContext2Apply_escape(t *testing.T) {
+	m := testModule(t, "apply-escape")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = "bar"
+  type = aws_instance
+`)
+}
+
+func TestContext2Apply_resourceCountOneList(t *testing.T) {
+	m := testModule(t, "apply-resource-count-one-list")
+	p := testProvider("null")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	assertNoDiagnostics(t, diags)
+
+	got := strings.TrimSpace(state.String())
+	want := strings.TrimSpace(`null_resource.foo.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/null"]
+
+Outputs:
+
+test = [foo]`)
+	if got != want {
+		t.Fatalf("got:\n%s\n\nwant:\n%s\n", got, want)
+	}
+}
+func TestContext2Apply_resourceCountZeroList(t *testing.T) {
+	m := testModule(t, "apply-resource-count-zero-list")
+	p := testProvider("null")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	got := strings.TrimSpace(state.String())
+	want := strings.TrimSpace(`<no state>
+Outputs:
+
+test = []`)
+	if got != want {
+		t.Fatalf("wrong state\n\ngot:\n%s\n\nwant:\n%s\n", got, want)
+	}
+}
+
+func TestContext2Apply_resourceDependsOnModule(t *testing.T) {
+	m := testModule(t, "apply-resource-depends-on-module")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	// verify the apply happens in the correct order
+	var mu sync.Mutex
+	var order []string
+
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		ami := req.PlannedState.GetAttr("ami").AsString()
+		switch ami {
+		case "child":
+
+			// make the child slower than the parent
+			time.Sleep(50 * time.Millisecond)
+
+			mu.Lock()
+			order = append(order, "child")
+			mu.Unlock()
+		case "parent":
+			mu.Lock()
+			order = append(order, "parent")
+			mu.Unlock()
+		}
+
+		return testApplyFn(req)
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	if !reflect.DeepEqual(order, []string{"child", "parent"}) {
+		t.Fatal("resources applied out of order")
+	}
+
+	checkStateString(t, state, testTerraformApplyResourceDependsOnModuleStr)
+}
+
+// Test that without a config, the Dependencies in the state are enough
+// to maintain proper ordering.
+func TestContext2Apply_resourceDependsOnModuleStateOnly(t *testing.T) {
+	m := testModule(t, "apply-resource-depends-on-module-empty")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"parent"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.aws_instance.child")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.child").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"child"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	{
+		// verify the apply happens in the correct order
+		var mu sync.Mutex
+		var order []string
+
+		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+			id := req.PriorState.GetAttr("id")
+			if id.IsKnown() && id.AsString() == "parent" {
+				// make the dep slower than the parent
+				time.Sleep(50 * time.Millisecond)
+
+				mu.Lock()
+				order = append(order, "child")
+				mu.Unlock()
+			} else {
+				mu.Lock()
+				order = append(order, "parent")
+				mu.Unlock()
+			}
+
+			return testApplyFn(req)
+		}
+
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+		assertNoErrors(t, diags)
+
+		state, diags := ctx.Apply(plan, m)
+		assertNoErrors(t, diags)
+
+		if !reflect.DeepEqual(order, []string{"child", "parent"}) {
+			t.Fatal("resources applied out of order")
+		}
+
+		checkStateString(t, state, "<no state>")
+	}
+}
+
+func TestContext2Apply_resourceDependsOnModuleDestroy(t *testing.T) {
+	m := testModule(t, "apply-resource-depends-on-module")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	var globalState *states.State
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+		assertNoErrors(t, diags)
+
+		state, diags := ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("diags: %s", diags.Err())
+		}
+
+		globalState = state
+	}
+
+	{
+		// Wait for the dependency, sleep, and verify the graph never
+		// called a child.
+		var called int32
+		var checked bool
+		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+			ami := req.PriorState.GetAttr("ami").AsString()
+			if ami == "parent" {
+				checked = true
+
+				// Sleep to allow parallel execution
+				time.Sleep(50 * time.Millisecond)
+
+				// Verify that called is 0 (dep not called)
+				if atomic.LoadInt32(&called) != 0 {
+					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("module child should not be called"))
+					return resp
+				}
+			}
+
+			atomic.AddInt32(&called, 1)
+			return testApplyFn(req)
+		}
+
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		plan, diags := ctx.Plan(m, globalState, &PlanOpts{
+			Mode: plans.DestroyMode,
+		})
+		assertNoErrors(t, diags)
+
+		state, diags := ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("diags: %s", diags.Err())
+		}
+
+		if !checked {
+			t.Fatal("should check")
+		}
+
+		checkStateString(t, state, `<no state>`)
+	}
+}
+
+func TestContext2Apply_resourceDependsOnModuleGrandchild(t *testing.T) {
+	m := testModule(t, "apply-resource-depends-on-module-deep")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	{
+		// Wait for the dependency, sleep, and verify the graph never
+		// called a child.
+		var called int32
+		var checked bool
+		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+			planned := req.PlannedState.AsValueMap()
+			if ami, ok := planned["ami"]; ok && ami.AsString() == "grandchild" {
+				checked = true
+
+				// Sleep to allow parallel execution
+				time.Sleep(50 * time.Millisecond)
+
+				// Verify that called is 0 (dep not called)
+				if atomic.LoadInt32(&called) != 0 {
+					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("aws_instance.a should not be called"))
+					return resp
+				}
+			}
+
+			atomic.AddInt32(&called, 1)
+			return testApplyFn(req)
+		}
+
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+		assertNoErrors(t, diags)
+
+		state, diags := ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("diags: %s", diags.Err())
+		}
+
+		if !checked {
+			t.Fatal("should check")
+		}
+
+		checkStateString(t, state, testTerraformApplyResourceDependsOnModuleDeepStr)
+	}
+}
+
+func TestContext2Apply_resourceDependsOnModuleInModule(t *testing.T) {
+	m := testModule(t, "apply-resource-depends-on-module-in-module")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	{
+		// Wait for the dependency, sleep, and verify the graph never
+		// called a child.
+		var called int32
+		var checked bool
+		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+			planned := req.PlannedState.AsValueMap()
+			if ami, ok := planned["ami"]; ok && ami.AsString() == "grandchild" {
+				checked = true
+
+				// Sleep to allow parallel execution
+				time.Sleep(50 * time.Millisecond)
+
+				// Verify that called is 0 (dep not called)
+				if atomic.LoadInt32(&called) != 0 {
+					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("something else was applied before grandchild; grandchild should be first"))
+					return resp
+				}
+			}
+
+			atomic.AddInt32(&called, 1)
+			return testApplyFn(req)
+		}
+
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+		assertNoErrors(t, diags)
+
+		state, diags := ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("diags: %s", diags.Err())
+		}
+
+		if !checked {
+			t.Fatal("should check")
+		}
+
+		checkStateString(t, state, testTerraformApplyResourceDependsOnModuleInModuleStr)
+	}
+}
+
+func TestContext2Apply_mapVarBetweenModules(t *testing.T) {
+	m := testModule(t, "apply-map-var-through-module")
+	p := testProvider("null")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(`<no state>
+Outputs:
+
+amis_from_module = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 }
+
+module.test:
+  null_resource.noop:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/null"]
+
+  Outputs:
+
+  amis_out = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 }`)
+	if actual != expected {
+		t.Fatalf("expected: \n%s\n\ngot: \n%s\n", expected, actual)
+	}
+}
+
+func TestContext2Apply_refCount(t *testing.T) {
+	m := testModule(t, "apply-ref-count")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	mod := state.RootModule()
+	if len(mod.Resources) < 2 {
+		t.Fatalf("bad: %#v", mod.Resources)
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyRefCountStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_providerAlias(t *testing.T) {
+	m := testModule(t, "apply-provider-alias")
+
+	// Each provider instance must be completely independent to ensure that we
+	// are verifying the correct state of each.
+	p := func() (providers.Interface, error) {
+		p := testProvider("aws")
+		p.PlanResourceChangeFn = testDiffFn
+		p.ApplyResourceChangeFn = testApplyFn
+		return p, nil
+	}
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): p,
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	mod := state.RootModule()
+	if len(mod.Resources) < 2 {
+		t.Fatalf("bad: %#v", mod.Resources)
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyProviderAliasStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+// Two providers that are configured should both be configured prior to apply
+func TestContext2Apply_providerAliasConfigure(t *testing.T) {
+	m := testModule(t, "apply-provider-alias-configure")
+
+	// Each provider instance must be completely independent to ensure that we
+	// are verifying the correct state of each.
+	p := func() (providers.Interface, error) {
+		p := testProvider("another")
+		p.ApplyResourceChangeFn = testApplyFn
+		p.PlanResourceChangeFn = testDiffFn
+		return p, nil
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("another"): p,
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf(legacyDiffComparisonString(plan.Changes))
+	}
+
+	// Configure to record calls AFTER Plan above
+	var configCount int32
+	p = func() (providers.Interface, error) {
+		p := testProvider("another")
+		p.ApplyResourceChangeFn = testApplyFn
+		p.PlanResourceChangeFn = testDiffFn
+		p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+			atomic.AddInt32(&configCount, 1)
+
+			foo := req.Config.GetAttr("foo").AsString()
+			if foo != "bar" {
+				resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("foo: %#v", foo))
+			}
+
+			return
+		}
+		return p, nil
+	}
+
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("another"): p,
+		},
+	})
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	if configCount != 2 {
+		t.Fatalf("provider config expected 2 calls, got: %d", configCount)
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyProviderAliasConfigStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+// GH-2870
+func TestContext2Apply_providerWarning(t *testing.T) {
+	m := testModule(t, "apply-provider-warning")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("just a warning"))
+		return
+	}
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(`
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+	`)
+	if actual != expected {
+		t.Fatalf("got: \n%s\n\nexpected:\n%s", actual, expected)
+	}
+
+	if !p.ConfigureProviderCalled {
+		t.Fatalf("provider Configure() was never called!")
+	}
+}
+
+func TestContext2Apply_emptyModule(t *testing.T) {
+	// A module with only outputs (no resources)
+	m := testModule(t, "apply-empty-module")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	actual = strings.Replace(actual, "  ", "", -1)
+	expected := strings.TrimSpace(testTerraformApplyEmptyModuleStr)
+	if actual != expected {
+		t.Fatalf("bad: \n%s\nexpect:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_createBeforeDestroy(t *testing.T) {
+	m := testModule(t, "apply-good-create-before")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf(legacyDiffComparisonString(plan.Changes))
+	}
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	mod := state.RootModule()
+	if got, want := len(mod.Resources), 1; got != want {
+		t.Logf("state:\n%s", state)
+		t.Fatalf("wrong number of resources %d; want %d", got, want)
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyCreateBeforeStr)
+	if actual != expected {
+		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
+	}
+}
+
+func TestContext2Apply_createBeforeDestroyUpdate(t *testing.T) {
+	m := testModule(t, "apply-good-create-before-update")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	// signal that resource foo has started applying
+	fooChan := make(chan struct{})
+
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		id := req.PriorState.GetAttr("id").AsString()
+		switch id {
+		case "bar":
+			select {
+			case <-fooChan:
+				resp.Diagnostics = resp.Diagnostics.Append(errors.New("bar must be updated before foo is destroyed"))
+				return resp
+			case <-time.After(100 * time.Millisecond):
+				// wait a moment to ensure that foo is not going to be destroyed first
+			}
+		case "foo":
+			close(fooChan)
+		}
+
+		return testApplyFn(req)
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	fooAddr := mustResourceInstanceAddr("aws_instance.foo")
+	root.SetResourceInstanceCurrent(
+		fooAddr.Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:              states.ObjectReady,
+			AttrsJSON:           []byte(`{"id":"foo","foo":"bar"}`),
+			CreateBeforeDestroy: true,
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:              states.ObjectReady,
+			AttrsJSON:           []byte(`{"id":"bar","foo":"bar"}`),
+			CreateBeforeDestroy: true,
+			Dependencies:        []addrs.ConfigResource{fooAddr.ContainingResource().Config()},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf(legacyDiffComparisonString(plan.Changes))
+	}
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	mod := state.RootModule()
+	if len(mod.Resources) != 1 {
+		t.Fatalf("bad: %s", state)
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyCreateBeforeUpdateStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+// This tests that when a CBD resource depends on a non-CBD resource,
+// we can still properly apply changes that require new for both.
+func TestContext2Apply_createBeforeDestroy_dependsNonCBD(t *testing.T) {
+	m := testModule(t, "apply-cbd-depends-non-cbd")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo", "require_new": "abc"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf(legacyDiffComparisonString(plan.Changes))
+	}
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  require_new = yes
+  type = aws_instance
+  value = foo
+
+  Dependencies:
+    aws_instance.foo
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  require_new = yes
+  type = aws_instance
+	`)
+}
+
+func TestContext2Apply_createBeforeDestroy_hook(t *testing.T) {
+	h := new(MockHook)
+	m := testModule(t, "apply-good-create-before")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	var actual []cty.Value
+	var actualLock sync.Mutex
+	h.PostApplyFn = func(addr addrs.AbsResourceInstance, gen states.Generation, sv cty.Value, e error) (HookAction, error) {
+		actualLock.Lock()
+
+		defer actualLock.Unlock()
+		actual = append(actual, sv)
+		return HookActionContinue, nil
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf(legacyDiffComparisonString(plan.Changes))
+	}
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	expected := []cty.Value{
+		cty.ObjectVal(map[string]cty.Value{
+			"id":          cty.StringVal("foo"),
+			"require_new": cty.StringVal("xyz"),
+			"type":        cty.StringVal("aws_instance"),
+		}),
+		cty.NullVal(cty.DynamicPseudoType),
+	}
+
+	cmpOpt := cmp.Transformer("ctyshim", hcl2shim.ConfigValueFromHCL2)
+	if !cmp.Equal(actual, expected, cmpOpt) {
+		t.Fatalf("wrong state snapshot sequence\n%s", cmp.Diff(expected, actual, cmpOpt))
+	}
+}
+
+// Test that we can perform an apply with CBD in a count with deposed instances.
+func TestContext2Apply_createBeforeDestroy_deposedCount(t *testing.T) {
+	m := testModule(t, "apply-cbd-count")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceDeposed(
+		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
+		states.NewDeposedKey(),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceDeposed(
+		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
+		states.NewDeposedKey(),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf(legacyDiffComparisonString(plan.Changes))
+	}
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `
+aws_instance.bar.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+aws_instance.bar.1:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+	`)
+}
+
+// Test that when we have a deposed instance but a good primary, we still
+// destroy the deposed instance.
+func TestContext2Apply_createBeforeDestroy_deposedOnly(t *testing.T) {
+	m := testModule(t, "apply-cbd-deposed-only")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceDeposed(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		states.NewDeposedKey(),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf(legacyDiffComparisonString(plan.Changes))
+	}
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `
+aws_instance.bar:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+	`)
+}
+
+func TestContext2Apply_destroyComputed(t *testing.T) {
+	m := testModule(t, "apply-destroy-computed")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo", "output": "value"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	if diags.HasErrors() {
+		logDiagnostics(t, diags)
+		t.Fatal("plan failed")
+	} else {
+		t.Logf("plan:\n\n%s", legacyDiffComparisonString(plan.Changes))
+	}
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		logDiagnostics(t, diags)
+		t.Fatal("apply failed")
+	}
+}
+
+// Test that the destroy operation uses depends_on as a source of ordering.
+func TestContext2Apply_destroyDependsOn(t *testing.T) {
+	// It is possible for this to be racy, so we loop a number of times
+	// just to check.
+	for i := 0; i < 10; i++ {
+		testContext2Apply_destroyDependsOn(t)
+	}
+}
+
+func testContext2Apply_destroyDependsOn(t *testing.T) {
+	m := testModule(t, "apply-destroy-depends-on")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"foo"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	// Record the order we see Apply
+	var actual []string
+	var actualLock sync.Mutex
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		actualLock.Lock()
+		defer actualLock.Unlock()
+		id := req.PriorState.GetAttr("id").AsString()
+		actual = append(actual, id)
+
+		return testApplyFn(req)
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Parallelism: 1, // To check ordering
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	expected := []string{"foo", "bar"}
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("wrong order\ngot:  %#v\nwant: %#v", actual, expected)
+	}
+}
+
+// Test that destroy ordering is correct with dependencies only
+// in the state.
+func TestContext2Apply_destroyDependsOnStateOnly(t *testing.T) {
+	newState := states.NewState()
+	root := newState.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "aws_instance",
+			Name: "foo",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"foo"}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("aws"),
+			Module:   addrs.RootModule,
+		},
+	)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "aws_instance",
+			Name: "bar",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+			Dependencies: []addrs.ConfigResource{
+				{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "aws_instance",
+						Name: "foo",
+					},
+					Module: root.Addr.Module(),
+				},
+			},
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("aws"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	// It is possible for this to be racy, so we loop a number of times
+	// just to check.
+	for i := 0; i < 10; i++ {
+		t.Run("new", func(t *testing.T) {
+			testContext2Apply_destroyDependsOnStateOnly(t, newState)
+		})
+	}
+}
+
+func testContext2Apply_destroyDependsOnStateOnly(t *testing.T, state *states.State) {
+	state = state.DeepCopy()
+	m := testModule(t, "empty")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	// Record the order we see Apply
+	var actual []string
+	var actualLock sync.Mutex
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		actualLock.Lock()
+		defer actualLock.Unlock()
+		id := req.PriorState.GetAttr("id").AsString()
+		actual = append(actual, id)
+		return testApplyFn(req)
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Parallelism: 1, // To check ordering
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	expected := []string{"bar", "foo"}
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("wrong order\ngot:  %#v\nwant: %#v", actual, expected)
+	}
+}
+
+// Test that destroy ordering is correct with dependencies only
+// in the state within a module (GH-11749)
+func TestContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T) {
+	newState := states.NewState()
+	child := newState.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "aws_instance",
+			Name: "foo",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"foo"}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("aws"),
+			Module:   addrs.RootModule,
+		},
+	)
+	child.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "aws_instance",
+			Name: "bar",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+			Dependencies: []addrs.ConfigResource{
+				{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "aws_instance",
+						Name: "foo",
+					},
+					Module: child.Addr.Module(),
+				},
+			},
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("aws"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	// It is possible for this to be racy, so we loop a number of times
+	// just to check.
+	for i := 0; i < 10; i++ {
+		t.Run("new", func(t *testing.T) {
+			testContext2Apply_destroyDependsOnStateOnlyModule(t, newState)
+		})
+	}
+}
+
+func testContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T, state *states.State) {
+	state = state.DeepCopy()
+	m := testModule(t, "empty")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	// Record the order we see Apply
+	var actual []string
+	var actualLock sync.Mutex
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		actualLock.Lock()
+		defer actualLock.Unlock()
+		id := req.PriorState.GetAttr("id").AsString()
+		actual = append(actual, id)
+		return testApplyFn(req)
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Parallelism: 1, // To check ordering
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	expected := []string{"bar", "foo"}
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("wrong order\ngot:  %#v\nwant: %#v", actual, expected)
+	}
+}
+
+func TestContext2Apply_dataBasic(t *testing.T) {
+	m := testModule(t, "apply-data-basic")
+	p := testProvider("null")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+		State: cty.ObjectVal(map[string]cty.Value{
+			"id":  cty.StringVal("yo"),
+			"foo": cty.NullVal(cty.String),
+		}),
+	}
+
+	hook := new(MockHook)
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{hook},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf(legacyDiffComparisonString(plan.Changes))
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyDataBasicStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+
+	if !hook.PreApplyCalled {
+		t.Fatal("PreApply not called for data source read")
+	}
+	if !hook.PostApplyCalled {
+		t.Fatal("PostApply not called for data source read")
+	}
+}
+
+func TestContext2Apply_destroyData(t *testing.T) {
+	m := testModule(t, "apply-destroy-data-resource")
+	p := testProvider("null")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		return providers.ReadDataSourceResponse{
+			State: req.Config,
+		}
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("data.null_data_source.testing").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"-"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/null"]`),
+	)
+
+	hook := &testHook{}
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		},
+		Hooks: []Hook{hook},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf(legacyDiffComparisonString(plan.Changes))
+	}
+
+	newState, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	if got := len(newState.Modules); got != 1 {
+		t.Fatalf("state has %d modules after destroy; want 1", got)
+	}
+
+	if got := len(newState.RootModule().Resources); got != 0 {
+		t.Fatalf("state has %d resources after destroy; want 0", got)
+	}
+
+	wantHookCalls := []*testHookCall{
+		{"PreApply", "data.null_data_source.testing"},
+		{"PostApply", "data.null_data_source.testing"},
+		{"PostStateUpdate", ""},
+	}
+	if !reflect.DeepEqual(hook.Calls, wantHookCalls) {
+		t.Errorf("wrong hook calls\ngot: %swant: %s", spew.Sdump(hook.Calls), spew.Sdump(wantHookCalls))
+	}
+}
+
+// https://github.com/hashicorp/terraform/pull/5096
+func TestContext2Apply_destroySkipsCBD(t *testing.T) {
+	// Config contains CBD resource depending on non-CBD resource, which triggers
+	// a cycle if they are both replaced, but should _not_ trigger a cycle when
+	// just doing a `terraform destroy`.
+	m := testModule(t, "apply-destroy-cbd")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf(legacyDiffComparisonString(plan.Changes))
+	}
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+}
+
+func TestContext2Apply_destroyModuleVarProviderConfig(t *testing.T) {
+	m := testModule(t, "apply-destroy-mod-var-provider-config")
+	p := func() (providers.Interface, error) {
+		p := testProvider("aws")
+		p.PlanResourceChangeFn = testDiffFn
+		return p, nil
+	}
+	state := states.NewState()
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): p,
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+}
+
+func TestContext2Apply_destroyCrossProviders(t *testing.T) {
+	m := testModule(t, "apply-destroy-cross-providers")
+
+	p_aws := testProvider("aws")
+	p_aws.ApplyResourceChangeFn = testApplyFn
+	p_aws.PlanResourceChangeFn = testDiffFn
+	p_aws.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+			"aws_vpc": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"value": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+		},
+	})
+
+	providers := map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p_aws),
+	}
+
+	ctx, m, state := getContextForApply_destroyCrossProviders(t, m, providers)
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		logDiagnostics(t, diags)
+		t.Fatal("apply failed")
+	}
+}
+
+func getContextForApply_destroyCrossProviders(t *testing.T, m *configs.Config, providerFactories map[addrs.Provider]providers.Factory) (*Context, *configs.Config, *states.State) {
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.shared").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"test"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_vpc.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id": "vpc-aaabbb12", "value":"test"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: providerFactories,
+	})
+
+	return ctx, m, state
+}
+
+func TestContext2Apply_minimal(t *testing.T) {
+	m := testModule(t, "apply-minimal")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyMinimalStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_cancel(t *testing.T) {
+	stopped := false
+
+	m := testModule(t, "apply-cancel")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		if !stopped {
+			stopped = true
+			go ctx.Stop()
+
+			for {
+				if ctx.sh.Stopped() {
+					break
+				}
+				time.Sleep(10 * time.Millisecond)
+			}
+		}
+		return testApplyFn(req)
+	}
+	p.PlanResourceChangeFn = testDiffFn
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	// Start the Apply in a goroutine
+	var applyDiags tfdiags.Diagnostics
+	stateCh := make(chan *states.State)
+	go func() {
+		state, diags := ctx.Apply(plan, m)
+		applyDiags = diags
+
+		stateCh <- state
+	}()
+
+	state := <-stateCh
+	// only expecting an early exit error
+	if !applyDiags.HasErrors() {
+		t.Fatal("expected early exit error")
+	}
+
+	for _, d := range applyDiags {
+		desc := d.Description()
+		if desc.Summary != "execution halted" {
+			t.Fatalf("unexpected error: %v", applyDiags.Err())
+		}
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyCancelStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+
+	if !p.StopCalled {
+		t.Fatal("stop should be called")
+	}
+}
+
+func TestContext2Apply_cancelBlock(t *testing.T) {
+	m := testModule(t, "apply-cancel-block")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	applyCh := make(chan struct{})
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		close(applyCh)
+
+		for !ctx.sh.Stopped() {
+			// Wait for stop to be called. We call Gosched here so that
+			// the other goroutines can always be scheduled to set Stopped.
+			runtime.Gosched()
+		}
+
+		// Sleep
+		time.Sleep(100 * time.Millisecond)
+		return testApplyFn(req)
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	// Start the Apply in a goroutine
+	var applyDiags tfdiags.Diagnostics
+	stateCh := make(chan *states.State)
+	go func() {
+		state, diags := ctx.Apply(plan, m)
+		applyDiags = diags
+
+		stateCh <- state
+	}()
+
+	stopDone := make(chan struct{})
+	go func() {
+		defer close(stopDone)
+		<-applyCh
+		ctx.Stop()
+	}()
+
+	// Make sure that stop blocks
+	select {
+	case <-stopDone:
+		t.Fatal("stop should block")
+	case <-time.After(10 * time.Millisecond):
+	}
+
+	// Wait for stop
+	select {
+	case <-stopDone:
+	case <-time.After(500 * time.Millisecond):
+		t.Fatal("stop should be done")
+	}
+
+	// Wait for apply to complete
+	state := <-stateCh
+	// only expecting an early exit error
+	if !applyDiags.HasErrors() {
+		t.Fatal("expected early exit error")
+	}
+
+	for _, d := range applyDiags {
+		desc := d.Description()
+		if desc.Summary != "execution halted" {
+			t.Fatalf("unexpected error: %v", applyDiags.Err())
+		}
+	}
+
+	checkStateString(t, state, `
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+	`)
+}
+
+func TestContext2Apply_cancelProvisioner(t *testing.T) {
+	m := testModule(t, "apply-cancel-provisioner")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	pr := testProvisioner()
+	pr.GetSchemaResponse = provisioners.GetSchemaResponse{
+		Provisioner: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"foo": {
+					Type:     cty.String,
+					Optional: true,
+				},
+			},
+		},
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	prStopped := make(chan struct{})
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		// Start the stop process
+		go ctx.Stop()
+
+		<-prStopped
+		return
+	}
+	pr.StopFn = func() error {
+		close(prStopped)
+		return nil
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	// Start the Apply in a goroutine
+	var applyDiags tfdiags.Diagnostics
+	stateCh := make(chan *states.State)
+	go func() {
+		state, diags := ctx.Apply(plan, m)
+		applyDiags = diags
+
+		stateCh <- state
+	}()
+
+	// Wait for completion
+	state := <-stateCh
+
+	// we are expecting only an early exit error
+	if !applyDiags.HasErrors() {
+		t.Fatal("expected early exit error")
+	}
+
+	for _, d := range applyDiags {
+		desc := d.Description()
+		if desc.Summary != "execution halted" {
+			t.Fatalf("unexpected error: %v", applyDiags.Err())
+		}
+	}
+
+	checkStateString(t, state, `
+aws_instance.foo: (tainted)
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+	`)
+
+	if !pr.StopCalled {
+		t.Fatal("stop should be called")
+	}
+}
+
+func TestContext2Apply_compute(t *testing.T) {
+	m := testModule(t, "apply-compute")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"num": {
+						Type:     cty.Number,
+						Optional: true,
+					},
+					"compute": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"compute_value": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"type": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"value": { // Populated from compute_value because compute = "value" in the config fixture
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		SetVariables: InputValues{
+			"value": &InputValue{
+				Value:      cty.NumberIntVal(1),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyComputeStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_countDecrease(t *testing.T) {
+	m := testModule(t, "apply-count-dec")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","foo": "foo","type": "aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","foo": "foo","type": "aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	s, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace(testTerraformApplyCountDecStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_countDecreaseToOneX(t *testing.T) {
+	m := testModule(t, "apply-count-dec-one")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	s, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace(testTerraformApplyCountDecToOneStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+// https://github.com/PeoplePerHour/terraform/pull/11
+//
+// This tests a rare but possible situation where we have both a no-key and
+// a zero-key instance of the same resource in the configuration when we
+// disable count.
+//
+// The main way to get here is for a provider to fail to destroy the zero-key
+// instance but succeed in creating the no-key instance, since those two
+// can typically happen concurrently. There are various other ways to get here
+// that might be considered user error, such as using "terraform state mv"
+// to create a strange combination of different key types on the same resource.
+//
+// This test indirectly exercises an intentional interaction between
+// refactoring.ImpliedMoveStatements and refactoring.ApplyMoves: we'll first
+// generate an implied move statement from aws_instance.foo[0] to
+// aws_instance.foo, but then refactoring.ApplyMoves should notice that and
+// ignore the statement, in the same way as it would if an explicit move
+// statement specified the same situation.
+func TestContext2Apply_countDecreaseToOneCorrupted(t *testing.T) {
+	m := testModule(t, "apply-count-dec-one")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"baz", "type": "aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+	{
+		got := strings.TrimSpace(legacyPlanComparisonString(state, plan.Changes))
+		want := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedPlanStr)
+		if got != want {
+			t.Fatalf("wrong plan result\ngot:\n%s\nwant:\n%s", got, want)
+		}
+	}
+	{
+		change := plan.Changes.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo[0]"))
+		if change == nil {
+			t.Fatalf("no planned change for instance zero")
+		}
+		if got, want := change.Action, plans.Delete; got != want {
+			t.Errorf("wrong action for instance zero %s; want %s", got, want)
+		}
+		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseWrongRepetition; got != want {
+			t.Errorf("wrong action reason for instance zero %s; want %s", got, want)
+		}
+	}
+	{
+		change := plan.Changes.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo"))
+		if change == nil {
+			t.Fatalf("no planned change for no-key instance")
+		}
+		if got, want := change.Action, plans.NoOp; got != want {
+			t.Errorf("wrong action for no-key instance %s; want %s", got, want)
+		}
+		if got, want := change.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason for no-key instance %s; want %s", got, want)
+		}
+	}
+
+	s, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedStr)
+	if actual != expected {
+		t.Fatalf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_countTainted(t *testing.T) {
+	m := testModule(t, "apply-count-tainted")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"bar", "type": "aws_instance", "foo": "foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+	{
+		got := strings.TrimSpace(legacyDiffComparisonString(plan.Changes))
+		want := strings.TrimSpace(`
+DESTROY/CREATE: aws_instance.foo[0]
+  foo:  "foo" => "foo"
+  id:   "bar" => "<computed>"
+  type: "aws_instance" => "<computed>"
+CREATE: aws_instance.foo[1]
+  foo:  "" => "foo"
+  id:   "" => "<computed>"
+  type: "" => "<computed>"
+`)
+		if got != want {
+			t.Fatalf("wrong plan\n\ngot:\n%s\n\nwant:\n%s", got, want)
+		}
+	}
+
+	s, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	got := strings.TrimSpace(s.String())
+	want := strings.TrimSpace(`
+aws_instance.foo.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  type = aws_instance
+aws_instance.foo.1:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  type = aws_instance
+`)
+	if got != want {
+		t.Fatalf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", got, want)
+	}
+}
+
+func TestContext2Apply_countVariable(t *testing.T) {
+	m := testModule(t, "apply-count-variable")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyCountVariableStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_countVariableRef(t *testing.T) {
+	m := testModule(t, "apply-count-variable-ref")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyCountVariableRefStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_provisionerInterpCount(t *testing.T) {
+	// This test ensures that a provisioner can interpolate a resource count
+	// even though the provisioner expression is evaluated during the plan
+	// walk. https://github.com/hashicorp/terraform/issues/16840
+
+	m, snap := testModuleWithSnapshot(t, "apply-provisioner-interp-count")
+
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	pr := testProvisioner()
+
+	Providers := map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+	}
+
+	provisioners := map[string]provisioners.Factory{
+		"local-exec": testProvisionerFuncFixed(pr),
+	}
+	ctx := testContext2(t, &ContextOpts{
+		Providers:    Providers,
+		Provisioners: provisioners,
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+
+	// We'll marshal and unmarshal the plan here, to ensure that we have
+	// a clean new context as would be created if we separately ran
+	// terraform plan -out=tfplan && terraform apply tfplan
+	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ctxOpts.Providers = Providers
+	ctxOpts.Provisioners = provisioners
+	ctx, diags = NewContext(ctxOpts)
+	if diags.HasErrors() {
+		t.Fatalf("failed to create context for plan: %s", diags.Err())
+	}
+
+	// Applying the plan should now succeed
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply failed unexpectedly: %s", diags.Err())
+	}
+
+	// Verify apply was invoked
+	if !pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner was not called")
+	}
+}
+
+func TestContext2Apply_foreachVariable(t *testing.T) {
+	m := testModule(t, "plan-for-each-unknown-value")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"foo": &InputValue{
+				Value: cty.StringVal("hello"),
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyForEachVariableStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_moduleBasic(t *testing.T) {
+	m := testModule(t, "apply-module")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyModuleStr)
+	if actual != expected {
+		t.Fatalf("bad, expected:\n%s\n\nactual:\n%s", expected, actual)
+	}
+}
+
+func TestContext2Apply_moduleDestroyOrder(t *testing.T) {
+	m := testModule(t, "apply-module-destroy-order")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	// Create a custom apply function to track the order they were destroyed
+	var order []string
+	var orderLock sync.Mutex
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		id := req.PriorState.GetAttr("id").AsString()
+
+		if id == "b" {
+			// Pause briefly to make any race conditions more visible, since
+			// missing edges here can cause undeterministic ordering.
+			time.Sleep(100 * time.Millisecond)
+		}
+
+		orderLock.Lock()
+		defer orderLock.Unlock()
+
+		order = append(order, id)
+		resp.NewState = req.PlannedState
+		return resp
+	}
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":    {Type: cty.String, Required: true},
+					"blah":  {Type: cty.String, Optional: true},
+					"value": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+
+	state := states.NewState()
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"a"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.b").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"b"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.aws_instance.a")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	expected := []string{"b", "a"}
+	if !reflect.DeepEqual(order, expected) {
+		t.Errorf("wrong order\ngot: %#v\nwant: %#v", order, expected)
+	}
+
+	{
+		actual := strings.TrimSpace(state.String())
+		expected := strings.TrimSpace(testTerraformApplyModuleDestroyOrderStr)
+		if actual != expected {
+			t.Errorf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+		}
+	}
+}
+
+func TestContext2Apply_moduleInheritAlias(t *testing.T) {
+	m := testModule(t, "apply-module-provider-inherit-alias")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		val := req.Config.GetAttr("value")
+		if val.IsNull() {
+			return
+		}
+
+		root := req.Config.GetAttr("root")
+		if !root.IsNull() {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("child should not get root"))
+		}
+
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `
+<no state>
+module.child:
+  aws_instance.foo:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"].eu
+    type = aws_instance
+	`)
+}
+
+func TestContext2Apply_orphanResource(t *testing.T) {
+	// This is a two-step test:
+	// 1. Apply a configuration with resources that have count set.
+	//    This should place the empty resource object in the state to record
+	//    that each exists, and record any instances.
+	// 2. Apply an empty configuration against the same state, which should
+	//    then clean up both the instances and the containing resource objects.
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_thing": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Computed: true},
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+
+	// Step 1: create the resources and instances
+	m := testModule(t, "apply-orphan-resource")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	// At this point both resources should be recorded in the state, along
+	// with the single instance associated with test_thing.one.
+	want := states.BuildState(func(s *states.SyncState) {
+		providerAddr := addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		}
+		oneAddr := addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_thing",
+			Name: "one",
+		}.Absolute(addrs.RootModuleInstance)
+		s.SetResourceProvider(oneAddr, providerAddr)
+		s.SetResourceInstanceCurrent(oneAddr.Instance(addrs.IntKey(0)), &states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		}, providerAddr)
+	})
+
+	if state.String() != want.String() {
+		t.Fatalf("wrong state after step 1\n%s", cmp.Diff(want, state))
+	}
+
+	// Step 2: update with an empty config, to destroy everything
+	m = testModule(t, "empty")
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+	{
+		addr := mustResourceInstanceAddr("test_thing.one[0]")
+		change := plan.Changes.ResourceInstance(addr)
+		if change == nil {
+			t.Fatalf("no planned change for %s", addr)
+		}
+		if got, want := change.Action, plans.Delete; got != want {
+			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
+		}
+		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseNoResourceConfig; got != want {
+			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
+		}
+	}
+
+	state, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	// The state should now be _totally_ empty, with just an empty root module
+	// (since that always exists) and no resources at all.
+	want = states.NewState()
+	want.CheckResults = &states.CheckResults{}
+	if !cmp.Equal(state, want) {
+		t.Fatalf("wrong state after step 2\ngot: %swant: %s", spew.Sdump(state), spew.Sdump(want))
+	}
+
+}
+
+func TestContext2Apply_moduleOrphanInheritAlias(t *testing.T) {
+	m := testModule(t, "apply-module-provider-inherit-alias-orphan")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		val := req.Config.GetAttr("value")
+		if val.IsNull() {
+			return
+		}
+
+		root := req.Config.GetAttr("root")
+		if !root.IsNull() {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("child should not get root"))
+		}
+
+		return
+	}
+
+	// Create a state with an orphan module
+	state := states.NewState()
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+	{
+		addr := mustResourceInstanceAddr("module.child.aws_instance.bar")
+		change := plan.Changes.ResourceInstance(addr)
+		if change == nil {
+			t.Fatalf("no planned change for %s", addr)
+		}
+		if got, want := change.Action, plans.Delete; got != want {
+			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
+		}
+		// This should ideally be ResourceInstanceDeleteBecauseNoModule, but
+		// the codepath deciding this doesn't currently have enough information
+		// to differentiate, and so this is a compromise.
+		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseNoResourceConfig; got != want {
+			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
+		}
+	}
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	if !p.ConfigureProviderCalled {
+		t.Fatal("must call configure")
+	}
+
+	checkStateString(t, state, "<no state>")
+}
+
+func TestContext2Apply_moduleOrphanProvider(t *testing.T) {
+	m := testModule(t, "apply-module-orphan-provider-inherit")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		val := req.Config.GetAttr("value")
+		if val.IsNull() {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
+		}
+
+		return
+	}
+
+	// Create a state with an orphan module
+	state := states.NewState()
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+}
+
+func TestContext2Apply_moduleOrphanGrandchildProvider(t *testing.T) {
+	m := testModule(t, "apply-module-orphan-provider-inherit")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		val := req.Config.GetAttr("value")
+		if val.IsNull() {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
+		}
+
+		return
+	}
+
+	// Create a state with an orphan module that is nested (grandchild)
+	state := states.NewState()
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+}
+
+func TestContext2Apply_moduleGrandchildProvider(t *testing.T) {
+	m := testModule(t, "apply-module-grandchild-provider-inherit")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	var callLock sync.Mutex
+	called := false
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		val := req.Config.GetAttr("value")
+		if val.IsNull() {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
+		}
+
+		callLock.Lock()
+		called = true
+		callLock.Unlock()
+
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	callLock.Lock()
+	defer callLock.Unlock()
+	if called != true {
+		t.Fatalf("err: configure never called")
+	}
+}
+
+// This tests an issue where all the providers in a module but not
+// in the root weren't being added to the root properly. In this test
+// case: aws is explicitly added to root, but "test" should be added to.
+// With the bug, it wasn't.
+func TestContext2Apply_moduleOnlyProvider(t *testing.T) {
+	m := testModule(t, "apply-module-only-provider")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	pTest := testProvider("test")
+	pTest.ApplyResourceChangeFn = testApplyFn
+	pTest.PlanResourceChangeFn = testDiffFn
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"):  testProviderFuncFixed(p),
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyModuleOnlyProviderStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_moduleProviderAlias(t *testing.T) {
+	m := testModule(t, "apply-module-provider-alias")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyModuleProviderAliasStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_moduleProviderAliasTargets(t *testing.T) {
+	m := testModule(t, "apply-module-provider-alias")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.ConfigResource{
+				Module: addrs.RootModule,
+				Resource: addrs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "nonexistent",
+					Name: "thing",
+				},
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(`
+<no state>
+	`)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_moduleProviderCloseNested(t *testing.T) {
+	m := testModule(t, "apply-module-provider-close-nested")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+}
+
+// Tests that variables used as module vars that reference data that
+// already exists in the state and requires no diff works properly. This
+// fixes an issue faced where module variables were pruned because they were
+// accessing "non-existent" resources (they existed, just not in the graph
+// cause they weren't in the diff).
+func TestContext2Apply_moduleVarRefExisting(t *testing.T) {
+	m := testModule(t, "apply-ref-existing")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo","foo":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyModuleVarRefExistingStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_moduleVarResourceCount(t *testing.T) {
+	m := testModule(t, "apply-module-var-resource-count")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.DestroyMode,
+		SetVariables: InputValues{
+			"num": &InputValue{
+				Value:      cty.NumberIntVal(2),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"num": &InputValue{
+				Value:      cty.NumberIntVal(5),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+}
+
+// GH-819
+func TestContext2Apply_moduleBool(t *testing.T) {
+	m := testModule(t, "apply-module-bool")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyModuleBoolStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+// Tests that a module can be targeted and everything is properly created.
+// This adds to the plan test to also just verify that apply works.
+func TestContext2Apply_moduleTarget(t *testing.T) {
+	m := testModule(t, "plan-targeted-cross-module")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Child("B", addrs.NoKey),
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `
+<no state>
+module.A:
+  aws_instance.foo:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    foo = bar
+    type = aws_instance
+
+  Outputs:
+
+  value = foo
+module.B:
+  aws_instance.bar:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    foo = foo
+    type = aws_instance
+
+    Dependencies:
+      module.A.aws_instance.foo
+	`)
+}
+
+func TestContext2Apply_multiProvider(t *testing.T) {
+	m := testModule(t, "apply-multi-provider")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	pDO := testProvider("do")
+	pDO.ApplyResourceChangeFn = testApplyFn
+	pDO.PlanResourceChangeFn = testDiffFn
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			addrs.NewDefaultProvider("do"):  testProviderFuncFixed(pDO),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	mod := state.RootModule()
+	if len(mod.Resources) < 2 {
+		t.Fatalf("bad: %#v", mod.Resources)
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyMultiProviderStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_multiProviderDestroy(t *testing.T) {
+	m := testModule(t, "apply-multi-provider-destroy")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"addr": {Type: cty.String, Optional: true},
+			},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Computed: true},
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+
+	p2 := testProvider("vault")
+	p2.ApplyResourceChangeFn = testApplyFn
+	p2.PlanResourceChangeFn = testDiffFn
+	p2.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"vault_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	var state *states.State
+
+	// First, create the instances
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
+				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
+			},
+		})
+
+		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+		assertNoErrors(t, diags)
+
+		s, diags := ctx.Apply(plan, m)
+		assertNoErrors(t, diags)
+
+		state = s
+	}
+
+	// Destroy them
+	{
+		// Verify that aws_instance.bar is destroyed first
+		var checked bool
+		var called int32
+		var lock sync.Mutex
+		applyFn := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+			lock.Lock()
+			defer lock.Unlock()
+
+			if req.TypeName == "aws_instance" {
+				checked = true
+
+				// Sleep to allow parallel execution
+				time.Sleep(50 * time.Millisecond)
+
+				// Verify that called is 0 (dep not called)
+				if atomic.LoadInt32(&called) != 0 {
+					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called"))
+					return resp
+				}
+			}
+
+			atomic.AddInt32(&called, 1)
+			return testApplyFn(req)
+		}
+
+		// Set the apply functions
+		p.ApplyResourceChangeFn = applyFn
+		p2.ApplyResourceChangeFn = applyFn
+
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
+				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
+			},
+		})
+
+		plan, diags := ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.DestroyMode,
+		})
+		assertNoErrors(t, diags)
+
+		s, diags := ctx.Apply(plan, m)
+		assertNoErrors(t, diags)
+
+		if !checked {
+			t.Fatal("should be checked")
+		}
+
+		state = s
+	}
+
+	checkStateString(t, state, `<no state>`)
+}
+
+// This is like the multiProviderDestroy test except it tests that
+// dependent resources within a child module that inherit provider
+// configuration are still destroyed first.
+func TestContext2Apply_multiProviderDestroyChild(t *testing.T) {
+	m := testModule(t, "apply-multi-provider-destroy-child")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"value": {Type: cty.String, Optional: true},
+			},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Computed: true},
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+
+	p2 := testProvider("vault")
+	p2.ApplyResourceChangeFn = testApplyFn
+	p2.PlanResourceChangeFn = testDiffFn
+	p2.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{},
+		ResourceTypes: map[string]*configschema.Block{
+			"vault_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	var state *states.State
+
+	// First, create the instances
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
+				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
+			},
+		})
+
+		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+		assertNoErrors(t, diags)
+
+		s, diags := ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("diags: %s", diags.Err())
+		}
+
+		state = s
+	}
+
+	// Destroy them
+	{
+		// Verify that aws_instance.bar is destroyed first
+		var checked bool
+		var called int32
+		var lock sync.Mutex
+		applyFn := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+			lock.Lock()
+			defer lock.Unlock()
+
+			if req.TypeName == "aws_instance" {
+				checked = true
+
+				// Sleep to allow parallel execution
+				time.Sleep(50 * time.Millisecond)
+
+				// Verify that called is 0 (dep not called)
+				if atomic.LoadInt32(&called) != 0 {
+					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called"))
+					return resp
+				}
+			}
+
+			atomic.AddInt32(&called, 1)
+			return testApplyFn(req)
+		}
+
+		// Set the apply functions
+		p.ApplyResourceChangeFn = applyFn
+		p2.ApplyResourceChangeFn = applyFn
+
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
+				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
+			},
+		})
+
+		plan, diags := ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.DestroyMode,
+		})
+		assertNoErrors(t, diags)
+
+		s, diags := ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("diags: %s", diags.Err())
+		}
+
+		if !checked {
+			t.Fatal("should be checked")
+		}
+
+		state = s
+	}
+
+	checkStateString(t, state, `
+<no state>
+`)
+}
+
+func TestContext2Apply_multiVar(t *testing.T) {
+	m := testModule(t, "apply-multi-var")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	// First, apply with a count of 3
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"num": &InputValue{
+				Value:      cty.NumberIntVal(3),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := state.RootModule().OutputValues["output"]
+	expected := cty.StringVal("bar0,bar1,bar2")
+	if actual == nil || actual.Value != expected {
+		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
+	}
+
+	t.Logf("Initial state: %s", state.String())
+
+	// Apply again, reduce the count to 1
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		plan, diags := ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"num": &InputValue{
+					Value:      cty.NumberIntVal(1),
+					SourceType: ValueFromCaller,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+
+		state, diags := ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("diags: %s", diags.Err())
+		}
+
+		t.Logf("End state: %s", state.String())
+
+		actual := state.RootModule().OutputValues["output"]
+		if actual == nil {
+			t.Fatal("missing output")
+		}
+
+		expected := cty.StringVal("bar0")
+		if actual.Value != expected {
+			t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
+		}
+	}
+}
+
+// This is a holistic test of multi-var (aka "splat variable") handling
+// across several different Terraform subsystems. This is here because
+// historically there were quirky differences in handling across different
+// parts of Terraform and so here we want to assert the expected behavior and
+// ensure that it remains consistent in future.
+func TestContext2Apply_multiVarComprehensive(t *testing.T) {
+	m := testModule(t, "apply-multi-var-comprehensive")
+	p := testProvider("test")
+
+	configs := map[string]cty.Value{}
+	var configsLock sync.Mutex
+
+	p.ApplyResourceChangeFn = testApplyFn
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		proposed := req.ProposedNewState
+		configsLock.Lock()
+		defer configsLock.Unlock()
+		key := proposed.GetAttr("key").AsString()
+		// This test was originally written using the legacy p.PlanResourceChangeFn interface,
+		// and so the assertions below expect an old-style ResourceConfig, which
+		// we'll construct via our shim for now to avoid rewriting all of the
+		// assertions.
+		configs[key] = req.ProposedNewState
+
+		retVals := make(map[string]cty.Value)
+		for it := proposed.ElementIterator(); it.Next(); {
+			idxVal, val := it.Element()
+			idx := idxVal.AsString()
+
+			switch idx {
+			case "id":
+				retVals[idx] = cty.UnknownVal(cty.String)
+			case "name":
+				retVals[idx] = cty.StringVal(key)
+			default:
+				retVals[idx] = val
+			}
+		}
+
+		return providers.PlanResourceChangeResponse{
+			PlannedState: cty.ObjectVal(retVals),
+		}
+	}
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_thing": {
+				Attributes: map[string]*configschema.Attribute{
+					"key": {Type: cty.String, Required: true},
+
+					"source_id":              {Type: cty.String, Optional: true},
+					"source_name":            {Type: cty.String, Optional: true},
+					"first_source_id":        {Type: cty.String, Optional: true},
+					"first_source_name":      {Type: cty.String, Optional: true},
+					"source_ids":             {Type: cty.List(cty.String), Optional: true},
+					"source_names":           {Type: cty.List(cty.String), Optional: true},
+					"source_ids_from_func":   {Type: cty.List(cty.String), Optional: true},
+					"source_names_from_func": {Type: cty.List(cty.String), Optional: true},
+					"source_ids_wrapped":     {Type: cty.List(cty.List(cty.String)), Optional: true},
+					"source_names_wrapped":   {Type: cty.List(cty.List(cty.String)), Optional: true},
+
+					"id":   {Type: cty.String, Computed: true},
+					"name": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	// First, apply with a count of 3
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"num": &InputValue{
+				Value:      cty.NumberIntVal(3),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	checkConfig := func(key string, want cty.Value) {
+		configsLock.Lock()
+		defer configsLock.Unlock()
+
+		got, ok := configs[key]
+		if !ok {
+			t.Errorf("no config recorded for %s; expected a configuration", key)
+			return
+		}
+
+		t.Run("config for "+key, func(t *testing.T) {
+			for _, problem := range deep.Equal(got, want) {
+				t.Errorf(problem)
+			}
+		})
+	}
+
+	checkConfig("multi_count_var.0", cty.ObjectVal(map[string]cty.Value{
+		"source_id":   cty.UnknownVal(cty.String),
+		"source_name": cty.StringVal("source.0"),
+	}))
+	checkConfig("multi_count_var.2", cty.ObjectVal(map[string]cty.Value{
+		"source_id":   cty.UnknownVal(cty.String),
+		"source_name": cty.StringVal("source.2"),
+	}))
+	checkConfig("multi_count_derived.0", cty.ObjectVal(map[string]cty.Value{
+		"source_id":   cty.UnknownVal(cty.String),
+		"source_name": cty.StringVal("source.0"),
+	}))
+	checkConfig("multi_count_derived.2", cty.ObjectVal(map[string]cty.Value{
+		"source_id":   cty.UnknownVal(cty.String),
+		"source_name": cty.StringVal("source.2"),
+	}))
+	checkConfig("whole_splat", cty.ObjectVal(map[string]cty.Value{
+		"source_ids": cty.ListVal([]cty.Value{
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+		}),
+		"source_names": cty.ListVal([]cty.Value{
+			cty.StringVal("source.0"),
+			cty.StringVal("source.1"),
+			cty.StringVal("source.2"),
+		}),
+		"source_ids_from_func": cty.UnknownVal(cty.String),
+		"source_names_from_func": cty.ListVal([]cty.Value{
+			cty.StringVal("source.0"),
+			cty.StringVal("source.1"),
+			cty.StringVal("source.2"),
+		}),
+		"source_ids_wrapped": cty.ListVal([]cty.Value{
+			cty.ListVal([]cty.Value{
+				cty.UnknownVal(cty.String),
+				cty.UnknownVal(cty.String),
+				cty.UnknownVal(cty.String),
+			}),
+		}),
+		"source_names_wrapped": cty.ListVal([]cty.Value{
+			cty.ListVal([]cty.Value{
+				cty.StringVal("source.0"),
+				cty.StringVal("source.1"),
+				cty.StringVal("source.2"),
+			}),
+		}),
+		"first_source_id":   cty.UnknownVal(cty.String),
+		"first_source_name": cty.StringVal("source.0"),
+	}))
+	checkConfig("child.whole_splat", cty.ObjectVal(map[string]cty.Value{
+		"source_ids": cty.ListVal([]cty.Value{
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+		}),
+		"source_names": cty.ListVal([]cty.Value{
+			cty.StringVal("source.0"),
+			cty.StringVal("source.1"),
+			cty.StringVal("source.2"),
+		}),
+		"source_ids_wrapped": cty.ListVal([]cty.Value{
+			cty.ListVal([]cty.Value{
+				cty.UnknownVal(cty.String),
+				cty.UnknownVal(cty.String),
+				cty.UnknownVal(cty.String),
+			}),
+		}),
+		"source_names_wrapped": cty.ListVal([]cty.Value{
+			cty.ListVal([]cty.Value{
+				cty.StringVal("source.0"),
+				cty.StringVal("source.1"),
+				cty.StringVal("source.2"),
+			}),
+		}),
+	}))
+
+	t.Run("apply", func(t *testing.T) {
+		state, diags := ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("error during apply: %s", diags.Err())
+		}
+
+		want := map[string]interface{}{
+			"source_ids": []interface{}{"foo", "foo", "foo"},
+			"source_names": []interface{}{
+				"source.0",
+				"source.1",
+				"source.2",
+			},
+		}
+		got := map[string]interface{}{}
+		for k, s := range state.RootModule().OutputValues {
+			got[k] = hcl2shim.ConfigValueFromHCL2(s.Value)
+		}
+		if !reflect.DeepEqual(got, want) {
+			t.Errorf(
+				"wrong outputs\ngot:  %s\nwant: %s",
+				spew.Sdump(got), spew.Sdump(want),
+			)
+		}
+	})
+}
+
+// Test that multi-var (splat) access is ordered by count, not by
+// value.
+func TestContext2Apply_multiVarOrder(t *testing.T) {
+	m := testModule(t, "apply-multi-var-order")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	// First, apply with a count of 3
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	t.Logf("State: %s", state.String())
+
+	actual := state.RootModule().OutputValues["should-be-11"]
+	expected := cty.StringVal("index-11")
+	if actual == nil || actual.Value != expected {
+		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
+	}
+}
+
+// Test that multi-var (splat) access is ordered by count, not by
+// value, through interpolations.
+func TestContext2Apply_multiVarOrderInterp(t *testing.T) {
+	m := testModule(t, "apply-multi-var-order-interp")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	// First, apply with a count of 3
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	t.Logf("State: %s", state.String())
+
+	actual := state.RootModule().OutputValues["should-be-11"]
+	expected := cty.StringVal("baz-index-11")
+	if actual == nil || actual.Value != expected {
+		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
+	}
+}
+
+// Based on GH-10440 where a graph edge wasn't properly being created
+// between a modified resource and a count instance being destroyed.
+func TestContext2Apply_multiVarCountDec(t *testing.T) {
+	var s *states.State
+
+	// First create resources. Nothing sneaky here.
+	{
+		m := testModule(t, "apply-multi-var-count-dec")
+		p := testProvider("aws")
+		p.PlanResourceChangeFn = testDiffFn
+		p.ApplyResourceChangeFn = testApplyFn
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		log.Print("\n========\nStep 1 Plan\n========")
+		plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"num": &InputValue{
+					Value:      cty.NumberIntVal(2),
+					SourceType: ValueFromCaller,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+
+		log.Print("\n========\nStep 1 Apply\n========")
+		state, diags := ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("diags: %s", diags.Err())
+		}
+
+		t.Logf("Step 1 state:\n%s", state)
+
+		s = state
+	}
+
+	// Decrease the count by 1 and verify that everything happens in the
+	// right order.
+	m := testModule(t, "apply-multi-var-count-dec")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	// Verify that aws_instance.bar is modified first and nothing
+	// else happens at the same time.
+	{
+		var checked bool
+		var called int32
+		var lock sync.Mutex
+		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+			lock.Lock()
+			defer lock.Unlock()
+
+			if !req.PlannedState.IsNull() {
+				s := req.PlannedState.AsValueMap()
+				if ami, ok := s["ami"]; ok && !ami.IsNull() && ami.AsString() == "special" {
+					checked = true
+
+					// Sleep to allow parallel execution
+					time.Sleep(50 * time.Millisecond)
+
+					// Verify that called is 0 (dep not called)
+					if atomic.LoadInt32(&called) != 1 {
+						resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called"))
+						return
+					}
+				}
+			}
+			atomic.AddInt32(&called, 1)
+			return testApplyFn(req)
+		}
+
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		log.Print("\n========\nStep 2 Plan\n========")
+		plan, diags := ctx.Plan(m, s, &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"num": &InputValue{
+					Value:      cty.NumberIntVal(1),
+					SourceType: ValueFromCaller,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+
+		t.Logf("Step 2 plan:\n%s", legacyDiffComparisonString(plan.Changes))
+
+		log.Print("\n========\nStep 2 Apply\n========")
+		_, diags = ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("apply errors: %s", diags.Err())
+		}
+
+		if !checked {
+			t.Error("apply never called")
+		}
+	}
+}
+
+// Test that we can resolve a multi-var (splat) for the first resource
+// created in a non-root module, which happens when the module state doesn't
+// exist yet.
+// https://github.com/hashicorp/terraform/issues/14438
+func TestContext2Apply_multiVarMissingState(t *testing.T) {
+	m := testModule(t, "apply-multi-var-missing-state")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_thing": {
+				Attributes: map[string]*configschema.Attribute{
+					"a_ids": {Type: cty.String, Optional: true},
+					"id":    {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	// First, apply with a count of 3
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	// Before the relevant bug was fixed, Terraform would panic during apply.
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply failed: %s", diags.Err())
+	}
+
+	// If we get here with no errors or panics then our test was successful.
+}
+
+func TestContext2Apply_outputOrphan(t *testing.T) {
+	m := testModule(t, "apply-output-orphan")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetOutputValue("foo", cty.StringVal("bar"), false)
+	root.SetOutputValue("bar", cty.StringVal("baz"), false)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyOutputOrphanStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_outputOrphanModule(t *testing.T) {
+	m := testModule(t, "apply-output-orphan-module")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	s, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace(testTerraformApplyOutputOrphanModuleStr)
+	if actual != expected {
+		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
+	}
+
+	// now apply with no module in the config, which should remove the
+	// remaining output
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	emptyConfig := configs.NewEmptyConfig()
+
+	// NOTE: While updating this test to pass the state in as a Plan argument,
+	// rather than into the testContext2 call above, it previously said
+	// State: state.DeepCopy(), which is a little weird since we just
+	// created "s" above as the result of the previous apply, but I've preserved
+	// it to avoid changing the flow of this test in case that's important
+	// for some reason.
+	plan, diags = ctx.Plan(emptyConfig, state.DeepCopy(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, emptyConfig)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	if !state.Empty() {
+		t.Fatalf("wrong final state %s\nwant empty state", spew.Sdump(state))
+	}
+}
+
+func TestContext2Apply_providerComputedVar(t *testing.T) {
+	m := testModule(t, "apply-provider-computed")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	pTest := testProvider("test")
+	pTest.ApplyResourceChangeFn = testApplyFn
+	pTest.PlanResourceChangeFn = testDiffFn
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"):  testProviderFuncFixed(p),
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest),
+		},
+	})
+
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		val := req.Config.GetAttr("value")
+		if val.IsNull() {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
+			return
+		}
+		return
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+}
+
+func TestContext2Apply_providerConfigureDisabled(t *testing.T) {
+	m := testModule(t, "apply-provider-configure-disabled")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		val := req.Config.GetAttr("value")
+		if val.IsNull() {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
+		}
+
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	if !p.ConfigureProviderCalled {
+		t.Fatal("configure never called")
+	}
+}
+
+func TestContext2Apply_provisionerModule(t *testing.T) {
+	m := testModule(t, "apply-provisioner-module")
+
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	pr := testProvisioner()
+	pr.GetSchemaResponse = provisioners.GetSchemaResponse{
+		Provisioner: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"foo": {Type: cty.String, Optional: true},
+			},
+		},
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyProvisionerModuleStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+
+	// Verify apply was invoked
+	if !pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner not invoked")
+	}
+}
+
+func TestContext2Apply_Provisioner_compute(t *testing.T) {
+	m := testModule(t, "apply-provisioner-compute")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+
+		val := req.Config.GetAttr("command").AsString()
+		if val != "computed_value" {
+			t.Fatalf("bad value for foo: %q", val)
+		}
+		req.UIOutput.Output(fmt.Sprintf("Executing: %q", val))
+
+		return
+	}
+	h := new(MockHook)
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"value": &InputValue{
+				Value:      cty.NumberIntVal(1),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyProvisionerStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+
+	// Verify apply was invoked
+	if !pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner not invoked")
+	}
+
+	// Verify output was rendered
+	if !h.ProvisionOutputCalled {
+		t.Fatalf("ProvisionOutput hook not called")
+	}
+	if got, want := h.ProvisionOutputMessage, `Executing: "computed_value"`; got != want {
+		t.Errorf("expected output to be %q, but was %q", want, got)
+	}
+}
+
+func TestContext2Apply_provisionerCreateFail(t *testing.T) {
+	m := testModule(t, "apply-provisioner-fail-create")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		resp := testApplyFn(req)
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
+
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags == nil {
+		t.Fatal("should error")
+	}
+
+	got := strings.TrimSpace(state.String())
+	want := strings.TrimSpace(testTerraformApplyProvisionerFailCreateStr)
+	if got != want {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", got, want)
+	}
+}
+
+func TestContext2Apply_provisionerCreateFailNoId(t *testing.T) {
+	m := testModule(t, "apply-provisioner-fail-create")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags == nil {
+		t.Fatal("should error")
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateNoIdStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_provisionerFail(t *testing.T) {
+	m := testModule(t, "apply-provisioner-fail")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	pr := testProvisioner()
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("EXPLOSION"))
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags == nil {
+		t.Fatal("should error")
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyProvisionerFailStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_provisionerFail_createBeforeDestroy(t *testing.T) {
+	m := testModule(t, "apply-provisioner-fail-create-before")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("EXPLOSION"))
+		return
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","require_new":"abc"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if !diags.HasErrors() {
+		t.Fatal("should error")
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateBeforeDestroyStr)
+	if actual != expected {
+		t.Fatalf("expected:\n%s\n:got\n%s", expected, actual)
+	}
+}
+
+func TestContext2Apply_error_createBeforeDestroy(t *testing.T) {
+	m := testModule(t, "apply-error-create-before")
+	p := testProvider("aws")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("placeholder error from ApplyFn"))
+		return
+	}
+	p.PlanResourceChangeFn = testDiffFn
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if !diags.HasErrors() {
+		t.Fatal("should have error")
+	}
+	if got, want := diags.Err().Error(), "placeholder error from ApplyFn"; got != want {
+		// We're looking for our artificial error from ApplyFn above, whose
+		// message is literally "placeholder error from ApplyFn".
+		t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyErrorCreateBeforeDestroyStr)
+	if actual != expected {
+		t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_errorDestroy_createBeforeDestroy(t *testing.T) {
+	m := testModule(t, "apply-error-create-before")
+	p := testProvider("aws")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		// Fail the destroy!
+		if req.PlannedState.IsNull() {
+			resp.NewState = req.PriorState
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
+			return
+		}
+
+		return testApplyFn(req)
+	}
+	p.PlanResourceChangeFn = testDiffFn
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if !diags.HasErrors() {
+		t.Fatal("should have error")
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyErrorDestroyCreateBeforeDestroyStr)
+	if actual != expected {
+		t.Fatalf("bad: actual:\n%s\n\nexpected:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) {
+	m := testModule(t, "apply-multi-depose-create-before-destroy")
+	p := testProvider("aws")
+	ps := map[addrs.Provider]providers.Factory{addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p)}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"require_new": {Type: cty.String, Optional: true},
+					"id":          {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.web").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	p.PlanResourceChangeFn = testDiffFn
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: ps,
+	})
+	createdInstanceId := "bar"
+	// Create works
+	createFunc := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		s := req.PlannedState.AsValueMap()
+		s["id"] = cty.StringVal(createdInstanceId)
+		resp.NewState = cty.ObjectVal(s)
+		return
+	}
+
+	// Destroy starts broken
+	destroyFunc := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		resp.NewState = req.PriorState
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("destroy failed"))
+		return
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		if req.PlannedState.IsNull() {
+			return destroyFunc(req)
+		} else {
+			return createFunc(req)
+		}
+	}
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"require_new": &InputValue{
+				Value: cty.StringVal("yes"),
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	// Destroy is broken, so even though CBD successfully replaces the instance,
+	// we'll have to save the Deposed instance to destroy later
+	state, diags = ctx.Apply(plan, m)
+	if !diags.HasErrors() {
+		t.Fatal("should have error")
+	}
+
+	checkStateString(t, state, `
+aws_instance.web: (1 deposed)
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  require_new = yes
+  Deposed ID 1 = foo
+	`)
+
+	createdInstanceId = "baz"
+	ctx = testContext2(t, &ContextOpts{
+		Providers: ps,
+	})
+
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"require_new": &InputValue{
+				Value: cty.StringVal("baz"),
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	// We're replacing the primary instance once again. Destroy is _still_
+	// broken, so the Deposed list gets longer
+	state, diags = ctx.Apply(plan, m)
+	if !diags.HasErrors() {
+		t.Fatal("should have error")
+	}
+
+	// For this one we can't rely on checkStateString because its result is
+	// not deterministic when multiple deposed objects are present. Instead,
+	// we will probe the state object directly.
+	{
+		is := state.RootModule().Resources["aws_instance.web"].Instances[addrs.NoKey]
+		if is.Current == nil {
+			t.Fatalf("no current object for aws_instance web; should have one")
+		}
+		if !bytes.Contains(is.Current.AttrsJSON, []byte("baz")) {
+			t.Fatalf("incorrect current object attrs %s; want id=baz", is.Current.AttrsJSON)
+		}
+		if got, want := len(is.Deposed), 2; got != want {
+			t.Fatalf("wrong number of deposed instances %d; want %d", got, want)
+		}
+		var foos, bars int
+		for _, obj := range is.Deposed {
+			if bytes.Contains(obj.AttrsJSON, []byte("foo")) {
+				foos++
+			}
+			if bytes.Contains(obj.AttrsJSON, []byte("bar")) {
+				bars++
+			}
+		}
+		if got, want := foos, 1; got != want {
+			t.Fatalf("wrong number of deposed instances with id=foo %d; want %d", got, want)
+		}
+		if got, want := bars, 1; got != want {
+			t.Fatalf("wrong number of deposed instances with id=bar %d; want %d", got, want)
+		}
+	}
+
+	// Destroy partially fixed!
+	destroyFunc = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		s := req.PriorState.AsValueMap()
+		id := s["id"].AsString()
+		if id == "foo" || id == "baz" {
+			resp.NewState = cty.NullVal(req.PriorState.Type())
+		} else {
+			resp.NewState = req.PriorState
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("destroy partially failed"))
+		}
+		return
+	}
+
+	createdInstanceId = "qux"
+	ctx = testContext2(t, &ContextOpts{
+		Providers: ps,
+	})
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"require_new": &InputValue{
+				Value: cty.StringVal("qux"),
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	// Expect error because 1/2 of Deposed destroys failed
+	if !diags.HasErrors() {
+		t.Fatal("should have error")
+	}
+
+	// foo and baz are now gone, bar sticks around
+	checkStateString(t, state, `
+aws_instance.web: (1 deposed)
+  ID = qux
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  require_new = qux
+  Deposed ID 1 = bar
+	`)
+
+	// Destroy working fully!
+	destroyFunc = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		resp.NewState = cty.NullVal(req.PriorState.Type())
+		return
+	}
+
+	createdInstanceId = "quux"
+	ctx = testContext2(t, &ContextOpts{
+		Providers: ps,
+	})
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"require_new": &InputValue{
+				Value: cty.StringVal("quux"),
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal("should not have error:", diags.Err())
+	}
+
+	// And finally the state is clean
+	checkStateString(t, state, `
+aws_instance.web:
+  ID = quux
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  require_new = quux
+	`)
+}
+
+// Verify that a normal provisioner with on_failure "continue" set won't
+// taint the resource and continues executing.
+func TestContext2Apply_provisionerFailContinue(t *testing.T) {
+	m := testModule(t, "apply-provisioner-fail-continue")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+  `)
+
+	// Verify apply was invoked
+	if !pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner not invoked")
+	}
+}
+
+// Verify that a normal provisioner with on_failure "continue" records
+// the error with the hook.
+func TestContext2Apply_provisionerFailContinueHook(t *testing.T) {
+	h := new(MockHook)
+	m := testModule(t, "apply-provisioner-fail-continue")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	if !h.PostProvisionInstanceStepCalled {
+		t.Fatal("PostProvisionInstanceStep not called")
+	}
+	if h.PostProvisionInstanceStepErrorArg == nil {
+		t.Fatal("should have error")
+	}
+}
+
+func TestContext2Apply_provisionerDestroy(t *testing.T) {
+	m := testModule(t, "apply-provisioner-destroy")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		val := req.Config.GetAttr("command").AsString()
+		if val != "destroy a bar" {
+			t.Fatalf("bad value for foo: %q", val)
+		}
+
+		return
+	}
+
+	state := states.NewState()
+	root := state.RootModule()
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","foo":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `<no state>`)
+
+	// Verify apply was invoked
+	if !pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner not invoked")
+	}
+}
+
+// Verify that on destroy provisioner failure, nothing happens to the instance
+func TestContext2Apply_provisionerDestroyFail(t *testing.T) {
+	m := testModule(t, "apply-provisioner-destroy")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
+		return
+	}
+
+	state := states.NewState()
+	root := state.RootModule()
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","foo":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags == nil {
+		t.Fatal("should error")
+	}
+
+	checkStateString(t, state, `
+aws_instance.foo["a"]:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+	`)
+
+	// Verify apply was invoked
+	if !pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner not invoked")
+	}
+}
+
+// Verify that on destroy provisioner failure with "continue" that
+// we continue to the next provisioner.
+func TestContext2Apply_provisionerDestroyFailContinue(t *testing.T) {
+	m := testModule(t, "apply-provisioner-destroy-continue")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+
+	var l sync.Mutex
+	var calls []string
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		val := req.Config.GetAttr("command")
+		if val.IsNull() {
+			t.Fatalf("bad value for foo: %#v", val)
+		}
+
+		l.Lock()
+		defer l.Unlock()
+		calls = append(calls, val.AsString())
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
+		return
+	}
+
+	state := states.NewState()
+	root := state.RootModule()
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `<no state>`)
+
+	// Verify apply was invoked
+	if !pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner not invoked")
+	}
+
+	expected := []string{"one", "two"}
+	if !reflect.DeepEqual(calls, expected) {
+		t.Fatalf("wrong commands\ngot:  %#v\nwant: %#v", calls, expected)
+	}
+}
+
+// Verify that on destroy provisioner failure with "continue" that
+// we continue to the next provisioner. But if the next provisioner defines
+// to fail, then we fail after running it.
+func TestContext2Apply_provisionerDestroyFailContinueFail(t *testing.T) {
+	m := testModule(t, "apply-provisioner-destroy-fail")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+
+	var l sync.Mutex
+	var calls []string
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		val := req.Config.GetAttr("command")
+		if val.IsNull() {
+			t.Fatalf("bad value for foo: %#v", val)
+		}
+
+		l.Lock()
+		defer l.Unlock()
+		calls = append(calls, val.AsString())
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
+		return
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags == nil {
+		t.Fatal("apply succeeded; wanted error from second provisioner")
+	}
+
+	checkStateString(t, state, `
+aws_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  `)
+
+	// Verify apply was invoked
+	if !pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner not invoked")
+	}
+
+	expected := []string{"one", "two"}
+	if !reflect.DeepEqual(calls, expected) {
+		t.Fatalf("bad: %#v", calls)
+	}
+}
+
+// Verify destroy provisioners are not run for tainted instances.
+func TestContext2Apply_provisionerDestroyTainted(t *testing.T) {
+	m := testModule(t, "apply-provisioner-destroy")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	destroyCalled := false
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		expected := "create a b"
+		val := req.Config.GetAttr("command")
+		if val.AsString() != expected {
+			t.Fatalf("bad value for command: %#v", val)
+		}
+
+		return
+	}
+
+	state := states.NewState()
+	root := state.RootModule()
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"input": &InputValue{
+				Value: cty.MapVal(map[string]cty.Value{
+					"a": cty.StringVal("b"),
+				}),
+				SourceType: ValueFromInput,
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `
+aws_instance.foo["a"]:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+	`)
+
+	// Verify apply was invoked
+	if !pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner not invoked")
+	}
+
+	if destroyCalled {
+		t.Fatal("destroy should not be called")
+	}
+}
+
+func TestContext2Apply_provisionerResourceRef(t *testing.T) {
+	m := testModule(t, "apply-provisioner-resource-ref")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	pr := testProvisioner()
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		val := req.Config.GetAttr("command")
+		if val.AsString() != "2" {
+			t.Fatalf("bad value for command: %#v", val)
+		}
+
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyProvisionerResourceRefStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+
+	// Verify apply was invoked
+	if !pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner not invoked")
+	}
+}
+
+func TestContext2Apply_provisionerSelfRef(t *testing.T) {
+	m := testModule(t, "apply-provisioner-self-ref")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		val := req.Config.GetAttr("command")
+		if val.AsString() != "bar" {
+			t.Fatalf("bad value for command: %#v", val)
+		}
+
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyProvisionerSelfRefStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+
+	// Verify apply was invoked
+	if !pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner not invoked")
+	}
+}
+
+func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) {
+	var lock sync.Mutex
+	commands := make([]string, 0, 5)
+
+	m := testModule(t, "apply-provisioner-multi-self-ref")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		lock.Lock()
+		defer lock.Unlock()
+
+		val := req.Config.GetAttr("command")
+		if val.IsNull() {
+			t.Fatalf("bad value for command: %#v", val)
+		}
+
+		commands = append(commands, val.AsString())
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+
+	// Verify apply was invoked
+	if !pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner not invoked")
+	}
+
+	// Verify our result
+	sort.Strings(commands)
+	expectedCommands := []string{"number 0", "number 1", "number 2"}
+	if !reflect.DeepEqual(commands, expectedCommands) {
+		t.Fatalf("bad: %#v", commands)
+	}
+}
+
+func TestContext2Apply_provisionerMultiSelfRefSingle(t *testing.T) {
+	var lock sync.Mutex
+	order := make([]string, 0, 5)
+
+	m := testModule(t, "apply-provisioner-multi-self-ref-single")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		lock.Lock()
+		defer lock.Unlock()
+
+		val := req.Config.GetAttr("order")
+		if val.IsNull() {
+			t.Fatalf("no val for order")
+		}
+
+		order = append(order, val.AsString())
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefSingleStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+
+	// Verify apply was invoked
+	if !pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner not invoked")
+	}
+
+	// Verify our result
+	sort.Strings(order)
+	expectedOrder := []string{"0", "1", "2"}
+	if !reflect.DeepEqual(order, expectedOrder) {
+		t.Fatalf("bad: %#v", order)
+	}
+}
+
+func TestContext2Apply_provisionerExplicitSelfRef(t *testing.T) {
+	m := testModule(t, "apply-provisioner-explicit-self-ref")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		val := req.Config.GetAttr("command")
+		if val.IsNull() || val.AsString() != "bar" {
+			t.Fatalf("bad value for command: %#v", val)
+		}
+
+		return
+	}
+
+	var state *states.State
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+			Provisioners: map[string]provisioners.Factory{
+				"shell": testProvisionerFuncFixed(pr),
+			},
+		})
+
+		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+		if diags.HasErrors() {
+			t.Fatalf("diags: %s", diags.Err())
+		}
+
+		state, diags = ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("diags: %s", diags.Err())
+		}
+
+		// Verify apply was invoked
+		if !pr.ProvisionResourceCalled {
+			t.Fatalf("provisioner not invoked")
+		}
+	}
+
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+			Provisioners: map[string]provisioners.Factory{
+				"shell": testProvisionerFuncFixed(pr),
+			},
+		})
+
+		plan, diags := ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.DestroyMode,
+		})
+		if diags.HasErrors() {
+			t.Fatalf("diags: %s", diags.Err())
+		}
+
+		state, diags = ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("diags: %s", diags.Err())
+		}
+
+		checkStateString(t, state, `<no state>`)
+	}
+}
+
+func TestContext2Apply_provisionerForEachSelfRef(t *testing.T) {
+	m := testModule(t, "apply-provisioner-for-each-self")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		val := req.Config.GetAttr("command")
+		if val.IsNull() {
+			t.Fatalf("bad value for command: %#v", val)
+		}
+
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+}
+
+// Provisioner should NOT run on a diff, only create
+func TestContext2Apply_Provisioner_Diff(t *testing.T) {
+	m := testModule(t, "apply-provisioner-diff")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		logDiagnostics(t, diags)
+		t.Fatal("apply failed")
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyProvisionerDiffStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+
+	// Verify apply was invoked
+	if !pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner was not called on first apply")
+	}
+	pr.ProvisionResourceCalled = false
+
+	// Change the state to force a diff
+	mod := state.RootModule()
+	obj := mod.Resources["aws_instance.bar"].Instances[addrs.NoKey].Current
+	var attrs map[string]interface{}
+	err := json.Unmarshal(obj.AttrsJSON, &attrs)
+	if err != nil {
+		t.Fatal(err)
+	}
+	attrs["foo"] = "baz"
+	obj.AttrsJSON, err = json.Marshal(attrs)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Re-create context with state
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state2, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		logDiagnostics(t, diags)
+		t.Fatal("apply failed")
+	}
+
+	actual = strings.TrimSpace(state2.String())
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+
+	// Verify apply was NOT invoked
+	if pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner was called on second apply; should not have been")
+	}
+}
+
+func TestContext2Apply_outputDiffVars(t *testing.T) {
+	m := testModule(t, "apply-good")
+	p := testProvider("aws")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.baz").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.PlanResourceChangeFn = testDiffFn
+	//func(info *InstanceInfo, s *InstanceState, rc *ResourceConfig) (*InstanceDiff, error) {
+	//    d := &InstanceDiff{
+	//        Attributes: map[string]*ResourceAttrDiff{},
+	//    }
+	//    if new, ok := rc.Get("value"); ok {
+	//        d.Attributes["value"] = &ResourceAttrDiff{
+	//            New: new.(string),
+	//        }
+	//    }
+	//    if new, ok := rc.Get("foo"); ok {
+	//        d.Attributes["foo"] = &ResourceAttrDiff{
+	//            New: new.(string),
+	//        }
+	//    } else if rc.IsComputed("foo") {
+	//        d.Attributes["foo"] = &ResourceAttrDiff{
+	//            NewComputed: true,
+	//            Type:        DiffAttrOutput, // This doesn't actually really do anything anymore, but this test originally set it.
+	//        }
+	//    }
+	//    if new, ok := rc.Get("num"); ok {
+	//        d.Attributes["num"] = &ResourceAttrDiff{
+	//            New: fmt.Sprintf("%#v", new),
+	//        }
+	//    }
+	//    return d, nil
+	//}
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+}
+
+func TestContext2Apply_destroyX(t *testing.T) {
+	m := testModule(t, "apply-destroy")
+	h := new(HookRecordApplyOrder)
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	// First plan and apply a create operation
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	// Next, plan and apply a destroy operation
+	h.Active = true
+	ctx = testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	// Test that things were destroyed
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyDestroyStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+
+	// Test that things were destroyed _in the right order_
+	expected2 := []string{"aws_instance.bar", "aws_instance.foo"}
+	actual2 := h.IDs
+	if !reflect.DeepEqual(actual2, expected2) {
+		t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2)
+	}
+}
+
+func TestContext2Apply_destroyOrder(t *testing.T) {
+	m := testModule(t, "apply-destroy")
+	h := new(HookRecordApplyOrder)
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	// First plan and apply a create operation
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	t.Logf("State 1: %s", state)
+
+	// Next, plan and apply a destroy
+	h.Active = true
+	ctx = testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	// Test that things were destroyed
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyDestroyStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+
+	// Test that things were destroyed _in the right order_
+	expected2 := []string{"aws_instance.bar", "aws_instance.foo"}
+	actual2 := h.IDs
+	if !reflect.DeepEqual(actual2, expected2) {
+		t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2)
+	}
+}
+
+// https://github.com/hashicorp/terraform/issues/2767
+func TestContext2Apply_destroyModulePrefix(t *testing.T) {
+	m := testModule(t, "apply-destroy-module-resource-prefix")
+	h := new(MockHook)
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	// First plan and apply a create operation
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	// Verify that we got the apply info correct
+	if v := h.PreApplyAddr.String(); v != "module.child.aws_instance.foo" {
+		t.Fatalf("bad: %s", v)
+	}
+
+	// Next, plan and apply a destroy operation and reset the hook
+	h = new(MockHook)
+	ctx = testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	// Test that things were destroyed
+	if v := h.PreApplyAddr.String(); v != "module.child.aws_instance.foo" {
+		t.Fatalf("bad: %s", v)
+	}
+}
+
+func TestContext2Apply_destroyNestedModule(t *testing.T) {
+	m := testModule(t, "apply-destroy-nested-module")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	// First plan and apply a create operation
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	s, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	// Test that things were destroyed
+	actual := strings.TrimSpace(s.String())
+	if actual != "<no state>" {
+		t.Fatalf("expected no state, got: %s", actual)
+	}
+}
+
+func TestContext2Apply_destroyDeeplyNestedModule(t *testing.T) {
+	m := testModule(t, "apply-destroy-deeply-nested-module")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	// First plan and apply a create operation
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	s, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	// Test that things were destroyed
+	if !s.Empty() {
+		t.Fatalf("wrong final state %s\nwant empty state", spew.Sdump(s))
+	}
+}
+
+// https://github.com/hashicorp/terraform/issues/5440
+func TestContext2Apply_destroyModuleWithAttrsReferencingResource(t *testing.T) {
+	m, snap := testModuleWithSnapshot(t, "apply-destroy-module-with-attrs")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	var state *states.State
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		// First plan and apply a create operation
+		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+		if diags.HasErrors() {
+			t.Fatalf("plan diags: %s", diags.Err())
+		} else {
+			t.Logf("Step 1 plan: %s", legacyDiffComparisonString(plan.Changes))
+		}
+
+		state, diags = ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("apply errs: %s", diags.Err())
+		}
+
+		t.Logf("Step 1 state: %s", state)
+	}
+
+	h := new(HookRecordApplyOrder)
+	h.Active = true
+
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Hooks: []Hook{h},
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		// First plan and apply a create operation
+		plan, diags := ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.DestroyMode,
+		})
+		if diags.HasErrors() {
+			t.Fatalf("destroy plan err: %s", diags.Err())
+		}
+
+		t.Logf("Step 2 plan: %s", legacyDiffComparisonString(plan.Changes))
+
+		ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
+		if err != nil {
+			t.Fatalf("failed to round-trip through planfile: %s", err)
+		}
+
+		ctxOpts.Providers = map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		}
+
+		ctx, diags = NewContext(ctxOpts)
+		if diags.HasErrors() {
+			t.Fatalf("err: %s", diags.Err())
+		}
+
+		state, diags = ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("destroy apply err: %s", diags.Err())
+		}
+
+		t.Logf("Step 2 state: %s", state)
+	}
+
+	//Test that things were destroyed
+	if state.HasManagedResourceInstanceObjects() {
+		t.Fatal("expected empty state, got:", state)
+	}
+}
+
+func TestContext2Apply_destroyWithModuleVariableAndCount(t *testing.T) {
+	m, snap := testModuleWithSnapshot(t, "apply-destroy-mod-var-and-count")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	var state *states.State
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		// First plan and apply a create operation
+		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+		assertNoErrors(t, diags)
+
+		state, diags = ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("apply err: %s", diags.Err())
+		}
+	}
+
+	h := new(HookRecordApplyOrder)
+	h.Active = true
+
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Hooks: []Hook{h},
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		// First plan and apply a create operation
+		plan, diags := ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.DestroyMode,
+		})
+		if diags.HasErrors() {
+			t.Fatalf("destroy plan err: %s", diags.Err())
+		}
+
+		ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
+		if err != nil {
+			t.Fatalf("failed to round-trip through planfile: %s", err)
+		}
+
+		ctxOpts.Providers =
+			map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			}
+
+		ctx, diags = NewContext(ctxOpts)
+		if diags.HasErrors() {
+			t.Fatalf("err: %s", diags.Err())
+		}
+
+		state, diags = ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("destroy apply err: %s", diags.Err())
+		}
+	}
+
+	//Test that things were destroyed
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(`
+<no state>`)
+	if actual != expected {
+		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
+	}
+}
+
+func TestContext2Apply_destroyTargetWithModuleVariableAndCount(t *testing.T) {
+	m := testModule(t, "apply-destroy-mod-var-and-count")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	var state *states.State
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		// First plan and apply a create operation
+		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+		assertNoErrors(t, diags)
+
+		state, diags = ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("apply err: %s", diags.Err())
+		}
+	}
+
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		plan, diags := ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.DestroyMode,
+			Targets: []addrs.Targetable{
+				addrs.RootModuleInstance.Child("child", addrs.NoKey),
+			},
+		})
+		if diags.HasErrors() {
+			t.Fatalf("plan err: %s", diags)
+		}
+		if len(diags) != 1 {
+			// Should have one warning that -target is in effect.
+			t.Fatalf("got %d diagnostics in plan; want 1", len(diags))
+		}
+		if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
+			t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
+		}
+		if got, want := diags[0].Description().Summary, "Resource targeting is in effect"; got != want {
+			t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
+		}
+
+		// Destroy, targeting the module explicitly
+		state, diags = ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("destroy apply err: %s", diags)
+		}
+		if len(diags) != 1 {
+			t.Fatalf("got %d diagnostics; want 1", len(diags))
+		}
+		if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
+			t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
+		}
+		if got, want := diags[0].Description().Summary, "Applied changes may be incomplete"; got != want {
+			t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
+		}
+	}
+
+	//Test that things were destroyed
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(`<no state>`)
+	if actual != expected {
+		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
+	}
+}
+
+func TestContext2Apply_destroyWithModuleVariableAndCountNested(t *testing.T) {
+	m, snap := testModuleWithSnapshot(t, "apply-destroy-mod-var-and-count-nested")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	var state *states.State
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		// First plan and apply a create operation
+		plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+		assertNoErrors(t, diags)
+
+		state, diags = ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("apply err: %s", diags.Err())
+		}
+	}
+
+	h := new(HookRecordApplyOrder)
+	h.Active = true
+
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Hooks: []Hook{h},
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		// First plan and apply a create operation
+		plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables)))
+		if diags.HasErrors() {
+			t.Fatalf("destroy plan err: %s", diags.Err())
+		}
+
+		ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
+		if err != nil {
+			t.Fatalf("failed to round-trip through planfile: %s", err)
+		}
+
+		ctxOpts.Providers =
+			map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			}
+
+		ctx, diags = NewContext(ctxOpts)
+		if diags.HasErrors() {
+			t.Fatalf("err: %s", diags.Err())
+		}
+
+		state, diags = ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("destroy apply err: %s", diags.Err())
+		}
+	}
+
+	//Test that things were destroyed
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(`
+<no state>`)
+	if actual != expected {
+		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
+	}
+}
+
+func TestContext2Apply_destroyOutputs(t *testing.T) {
+	m := testModule(t, "apply-destroy-outputs")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		// add the required id
+		m := req.Config.AsValueMap()
+		m["id"] = cty.StringVal("foo")
+
+		return providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(m),
+		}
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	// First plan and apply a create operation
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	// Next, plan and apply a destroy operation
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	mod := state.RootModule()
+	if len(mod.Resources) > 0 {
+		t.Fatalf("expected no resources, got: %#v", mod)
+	}
+
+	// destroying again should produce no errors
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+}
+
+func TestContext2Apply_destroyOrphan(t *testing.T) {
+	m := testModule(t, "apply-error")
+	p := testProvider("aws")
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.baz").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.PlanResourceChangeFn = testDiffFn
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	s, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	mod := s.RootModule()
+	if _, ok := mod.Resources["aws_instance.baz"]; ok {
+		t.Fatalf("bad: %#v", mod.Resources)
+	}
+}
+
+func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) {
+	m := testModule(t, "apply-destroy-provisioner")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	s, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	if pr.ProvisionResourceCalled {
+		t.Fatal("provisioner should not be called")
+	}
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace("<no state>")
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_error(t *testing.T) {
+	errored := false
+
+	m := testModule(t, "apply-error")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		if errored {
+			resp.NewState = req.PlannedState
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
+			return
+		}
+		errored = true
+
+		return testApplyFn(req)
+	}
+	p.PlanResourceChangeFn = testDiffFn
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags == nil {
+		t.Fatal("should have error")
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyErrorStr)
+	if actual != expected {
+		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
+	}
+}
+
+func TestContext2Apply_errorDestroy(t *testing.T) {
+	m := testModule(t, "empty")
+	p := testProvider("test")
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_thing": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		// Should actually be called for this test, because Terraform Core
+		// constructs the plan for a destroy operation itself.
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		// The apply (in this case, a destroy) always fails, so we can verify
+		// that the object stays in the state after a destroy fails even though
+		// we aren't returning a new state object here.
+		return providers.ApplyResourceChangeResponse{
+			Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("failed")),
+		}
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	state := states.BuildState(func(ss *states.SyncState) {
+		ss.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_thing",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectReady,
+				AttrsJSON: []byte(`{"id":"baz"}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if !diags.HasErrors() {
+		t.Fatal("should have error")
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(`
+test_thing.foo:
+  ID = baz
+  provider = provider["registry.terraform.io/hashicorp/test"]
+`) // test_thing.foo is still here, even though provider returned no new state along with its error
+	if actual != expected {
+		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
+	}
+}
+
+func TestContext2Apply_errorCreateInvalidNew(t *testing.T) {
+	m := testModule(t, "apply-error")
+
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"value": {Type: cty.String, Optional: true},
+					"foo":   {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		// We're intentionally returning an inconsistent new state here
+		// because we want to test that Terraform ignores the inconsistency
+		// when accompanied by another error.
+		return providers.ApplyResourceChangeResponse{
+			NewState: cty.ObjectVal(map[string]cty.Value{
+				"value": cty.StringVal("wrong wrong wrong wrong"),
+				"foo":   cty.StringVal("absolutely brimming over with wrongability"),
+			}),
+			Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("forced error")),
+		}
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags == nil {
+		t.Fatal("should have error")
+	}
+	if got, want := len(diags), 1; got != want {
+		// There should be no additional diagnostics generated by Terraform's own eval logic,
+		// because the provider's own error supersedes them.
+		t.Errorf("wrong number of diagnostics %d; want %d\n%s", got, want, diags.Err())
+	}
+	if got, want := diags.Err().Error(), "forced error"; !strings.Contains(got, want) {
+		t.Errorf("returned error does not contain %q, but it should\n%s", want, diags.Err())
+	}
+	if got, want := len(state.RootModule().Resources), 2; got != want {
+		t.Errorf("%d resources in state before prune; should have %d\n%s", got, want, spew.Sdump(state))
+	}
+	state.PruneResourceHusks() // aws_instance.bar with no instances gets left behind when we bail out, but that's okay
+	if got, want := len(state.RootModule().Resources), 1; got != want {
+		t.Errorf("%d resources in state after prune; should have only one (aws_instance.foo, tainted)\n%s", got, spew.Sdump(state))
+	}
+}
+
+func TestContext2Apply_errorUpdateNullNew(t *testing.T) {
+	m := testModule(t, "apply-error")
+
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"value": {Type: cty.String, Optional: true},
+					"foo":   {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		// We're intentionally returning no NewState here because we want to
+		// test that Terraform retains the prior state, rather than treating
+		// the returned null as "no state" (object deleted).
+		return providers.ApplyResourceChangeResponse{
+			Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("forced error")),
+		}
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	state := states.BuildState(func(ss *states.SyncState) {
+		ss.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectReady,
+				AttrsJSON: []byte(`{"value":"old"}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if !diags.HasErrors() {
+		t.Fatal("should have error")
+	}
+	if got, want := len(diags), 1; got != want {
+		// There should be no additional diagnostics generated by Terraform's own eval logic,
+		// because the provider's own error supersedes them.
+		t.Errorf("wrong number of diagnostics %d; want %d\n%s", got, want, diags.Err())
+	}
+	if got, want := diags.Err().Error(), "forced error"; !strings.Contains(got, want) {
+		t.Errorf("returned error does not contain %q, but it should\n%s", want, diags.Err())
+	}
+	state.PruneResourceHusks()
+	if got, want := len(state.RootModule().Resources), 1; got != want {
+		t.Fatalf("%d resources in state; should have only one (aws_instance.foo, unmodified)\n%s", got, spew.Sdump(state))
+	}
+
+	is := state.ResourceInstance(addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "aws_instance",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
+	if is == nil {
+		t.Fatalf("aws_instance.foo is not in the state after apply")
+	}
+	if got, want := is.Current.AttrsJSON, []byte(`"old"`); !bytes.Contains(got, want) {
+		t.Fatalf("incorrect attributes for aws_instance.foo\ngot: %s\nwant: JSON containing %s\n\n%s", got, want, spew.Sdump(is))
+	}
+}
+
+func TestContext2Apply_errorPartial(t *testing.T) {
+	errored := false
+
+	m := testModule(t, "apply-error")
+	p := testProvider("aws")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		if errored {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
+			return
+		}
+		errored = true
+
+		return testApplyFn(req)
+	}
+	p.PlanResourceChangeFn = testDiffFn
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	s, diags := ctx.Apply(plan, m)
+	if diags == nil {
+		t.Fatal("should have error")
+	}
+
+	mod := s.RootModule()
+	if len(mod.Resources) != 2 {
+		t.Fatalf("bad: %#v", mod.Resources)
+	}
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace(testTerraformApplyErrorPartialStr)
+	if actual != expected {
+		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
+	}
+}
+
+func TestContext2Apply_hook(t *testing.T) {
+	m := testModule(t, "apply-good")
+	h := new(MockHook)
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	if !h.PreApplyCalled {
+		t.Fatal("should be called")
+	}
+	if !h.PostApplyCalled {
+		t.Fatal("should be called")
+	}
+	if !h.PostStateUpdateCalled {
+		t.Fatalf("should call post state update")
+	}
+}
+
+func TestContext2Apply_hookOrphan(t *testing.T) {
+	m := testModule(t, "apply-blank")
+	h := new(MockHook)
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	if !h.PreApplyCalled {
+		t.Fatal("should be called")
+	}
+	if !h.PostApplyCalled {
+		t.Fatal("should be called")
+	}
+	if !h.PostStateUpdateCalled {
+		t.Fatalf("should call post state update")
+	}
+}
+
+func TestContext2Apply_idAttr(t *testing.T) {
+	m := testModule(t, "apply-idattr")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	mod := state.RootModule()
+	rs, ok := mod.Resources["aws_instance.foo"]
+	if !ok {
+		t.Fatal("not in state")
+	}
+	var attrs map[string]interface{}
+	err := json.Unmarshal(rs.Instances[addrs.NoKey].Current.AttrsJSON, &attrs)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if got, want := attrs["id"], "foo"; got != want {
+		t.Fatalf("wrong id\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestContext2Apply_outputBasic(t *testing.T) {
+	m := testModule(t, "apply-output")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyOutputStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_outputAdd(t *testing.T) {
+	m1 := testModule(t, "apply-output-add-before")
+	p1 := testProvider("aws")
+	p1.ApplyResourceChangeFn = testApplyFn
+	p1.PlanResourceChangeFn = testDiffFn
+	ctx1 := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p1),
+		},
+	})
+
+	plan1, diags := ctx1.Plan(m1, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state1, diags := ctx1.Apply(plan1, m1)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	m2 := testModule(t, "apply-output-add-after")
+	p2 := testProvider("aws")
+	p2.ApplyResourceChangeFn = testApplyFn
+	p2.PlanResourceChangeFn = testDiffFn
+	ctx2 := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p2),
+		},
+	})
+
+	plan2, diags := ctx1.Plan(m2, state1, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state2, diags := ctx2.Apply(plan2, m2)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state2.String())
+	expected := strings.TrimSpace(testTerraformApplyOutputAddStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_outputList(t *testing.T) {
+	m := testModule(t, "apply-output-list")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyOutputListStr)
+	if actual != expected {
+		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
+	}
+}
+
+func TestContext2Apply_outputMulti(t *testing.T) {
+	m := testModule(t, "apply-output-multi")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyOutputMultiStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_outputMultiIndex(t *testing.T) {
+	m := testModule(t, "apply-output-multi-index")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyOutputMultiIndexStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_taintX(t *testing.T) {
+	m := testModule(t, "apply-taint")
+	p := testProvider("aws")
+	// destroyCount tests against regression of
+	// https://github.com/hashicorp/terraform/issues/1056
+	var destroyCount = int32(0)
+	var once sync.Once
+	simulateProviderDelay := func() {
+		time.Sleep(10 * time.Millisecond)
+	}
+
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		once.Do(simulateProviderDelay)
+		if req.PlannedState.IsNull() {
+			atomic.AddInt32(&destroyCount, 1)
+		}
+		return testApplyFn(req)
+	}
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes))
+	}
+
+	s, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace(testTerraformApplyTaintStr)
+	if actual != expected {
+		t.Fatalf("bad:\n%s", actual)
+	}
+
+	if destroyCount != 1 {
+		t.Fatalf("Expected 1 destroy, got %d", destroyCount)
+	}
+}
+
+func TestContext2Apply_taintDep(t *testing.T) {
+	m := testModule(t, "apply-taint-dep")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"bar","num": "2", "type": "aws_instance", "foo": "baz"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes))
+	}
+
+	s, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace(testTerraformApplyTaintDepStr)
+	if actual != expected {
+		t.Fatalf("bad:\n%s", actual)
+	}
+}
+
+func TestContext2Apply_taintDepRequiresNew(t *testing.T) {
+	m := testModule(t, "apply-taint-dep-requires-new")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"bar","num": "2", "type": "aws_instance", "foo": "baz"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes))
+	}
+
+	s, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace(testTerraformApplyTaintDepRequireNewStr)
+	if actual != expected {
+		t.Fatalf("bad:\n%s", actual)
+	}
+}
+
+func TestContext2Apply_targeted(t *testing.T) {
+	m := testModule(t, "apply-targeted")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "foo",
+			),
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	mod := state.RootModule()
+	if len(mod.Resources) != 1 {
+		t.Fatalf("expected 1 resource, got: %#v", mod.Resources)
+	}
+
+	checkStateString(t, state, `
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+	`)
+}
+
+func TestContext2Apply_targetedCount(t *testing.T) {
+	m := testModule(t, "apply-targeted-count")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "foo",
+			),
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `
+aws_instance.foo.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+aws_instance.foo.1:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+aws_instance.foo.2:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+	`)
+}
+
+func TestContext2Apply_targetedCountIndex(t *testing.T) {
+	m := testModule(t, "apply-targeted-count")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.ResourceInstance(
+				addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(1),
+			),
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `
+aws_instance.foo.1:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+	`)
+}
+
+func TestContext2Apply_targetedDestroy(t *testing.T) {
+	m := testModule(t, "destroy-targeted")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetOutputValue("out", cty.StringVal("bar"), false)
+
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.b").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	if diags := ctx.Validate(m); diags.HasErrors() {
+		t.Fatalf("validate errors: %s", diags.Err())
+	}
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "a",
+			),
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	mod := state.RootModule()
+	if len(mod.Resources) != 0 {
+		t.Fatalf("expected 0 resources, got: %#v", mod.Resources)
+	}
+
+	// the root output should not get removed; only the targeted resource.
+	//
+	// Note: earlier versions of this test expected 0 outputs, but it turns out
+	// that was because Validate - not apply or destroy - removed the output
+	// (which depends on the targeted resource) from state. That version of this
+	// test did not match actual terraform behavior: the output remains in
+	// state.
+	//
+	// The reason it remains in the state is that we prune out the root module
+	// output values from the destroy graph as part of pruning out the "update"
+	// nodes for the resources, because otherwise the root module output values
+	// force the resources to stay in the graph and can therefore cause
+	// unwanted dependency cycles.
+	//
+	// TODO: Future refactoring may enable us to remove the output from state in
+	// this case, and that would be Just Fine - this test can be modified to
+	// expect 0 outputs.
+	if len(mod.OutputValues) != 1 {
+		t.Fatalf("expected 1 outputs, got: %#v", mod.OutputValues)
+	}
+
+	// the module instance should remain
+	mod = state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	if len(mod.Resources) != 1 {
+		t.Fatalf("expected 1 resources, got: %#v", mod.Resources)
+	}
+}
+
+func TestContext2Apply_targetedDestroyCountDeps(t *testing.T) {
+	m := testModule(t, "apply-destroy-targeted-count")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"i-abc123"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "foo",
+			),
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `<no state>`)
+}
+
+// https://github.com/hashicorp/terraform/issues/4462
+func TestContext2Apply_targetedDestroyModule(t *testing.T) {
+	m := testModule(t, "apply-targeted-module")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-abc123"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-abc123"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource(
+				addrs.ManagedResourceMode, "aws_instance", "foo",
+			),
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `
+aws_instance.bar:
+  ID = i-abc123
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+aws_instance.foo:
+  ID = i-bcd345
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+
+module.child:
+  aws_instance.bar:
+    ID = i-abc123
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+	`)
+}
+
+func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) {
+	m := testModule(t, "apply-targeted-count")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	foo := &states.ResourceInstanceObjectSrc{
+		Status:    states.ObjectReady,
+		AttrsJSON: []byte(`{"id":"i-bcd345"}`),
+	}
+	bar := &states.ResourceInstanceObjectSrc{
+		Status:    states.ObjectReady,
+		AttrsJSON: []byte(`{"id":"i-abc123"}`),
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		foo,
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
+		foo,
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
+		foo,
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
+		bar,
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
+		bar,
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar[2]").Resource,
+		bar,
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.ResourceInstance(
+				addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(2),
+			),
+			addrs.RootModuleInstance.ResourceInstance(
+				addrs.ManagedResourceMode, "aws_instance", "bar", addrs.IntKey(1),
+			),
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `
+aws_instance.bar.0:
+  ID = i-abc123
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+aws_instance.bar.2:
+  ID = i-abc123
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+aws_instance.foo.0:
+  ID = i-bcd345
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+aws_instance.foo.1:
+  ID = i-bcd345
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+	`)
+}
+
+func TestContext2Apply_targetedModule(t *testing.T) {
+	m := testModule(t, "apply-targeted-module")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Child("child", addrs.NoKey),
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	mod := state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	if mod == nil {
+		t.Fatalf("no child module found in the state!\n\n%#v", state)
+	}
+	if len(mod.Resources) != 2 {
+		t.Fatalf("expected 2 resources, got: %#v", mod.Resources)
+	}
+
+	checkStateString(t, state, `
+<no state>
+module.child:
+  aws_instance.bar:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    num = 2
+    type = aws_instance
+  aws_instance.foo:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    num = 2
+    type = aws_instance
+	`)
+}
+
+// GH-1858
+func TestContext2Apply_targetedModuleDep(t *testing.T) {
+	m := testModule(t, "apply-targeted-module-dep")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "foo",
+			),
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf("Diff: %s", legacyDiffComparisonString(plan.Changes))
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	checkStateString(t, state, `
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  type = aws_instance
+
+  Dependencies:
+    module.child.aws_instance.mod
+
+module.child:
+  aws_instance.mod:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    type = aws_instance
+
+  Outputs:
+
+  output = foo
+	`)
+}
+
+// GH-10911 untargeted outputs should not be in the graph, and therefore
+// not execute.
+func TestContext2Apply_targetedModuleUnrelatedOutputs(t *testing.T) {
+	m := testModule(t, "apply-targeted-module-unrelated-outputs")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	state := states.NewState()
+	_ = state.EnsureModule(addrs.RootModuleInstance.Child("child2", addrs.NoKey))
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Child("child2", addrs.NoKey),
+		},
+	})
+	assertNoErrors(t, diags)
+
+	s, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	// - module.child1's instance_id output is dropped because we don't preserve
+	//   non-root module outputs between runs (they can be recalculated from config)
+	// - module.child2's instance_id is updated because its dependency is updated
+	// - child2_id is updated because if its transitive dependency via module.child2
+	checkStateString(t, s, `
+<no state>
+Outputs:
+
+child2_id = foo
+
+module.child2:
+  aws_instance.foo:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    type = aws_instance
+
+  Outputs:
+
+  instance_id = foo
+`)
+}
+
+func TestContext2Apply_targetedModuleResource(t *testing.T) {
+	m := testModule(t, "apply-targeted-module-resource")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource(
+				addrs.ManagedResourceMode, "aws_instance", "foo",
+			),
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	mod := state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	if mod == nil || len(mod.Resources) != 1 {
+		t.Fatalf("expected 1 resource, got: %#v", mod)
+	}
+
+	checkStateString(t, state, `
+<no state>
+module.child:
+  aws_instance.foo:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    num = 2
+    type = aws_instance
+	`)
+}
+
+func TestContext2Apply_targetedResourceOrphanModule(t *testing.T) {
+	m := testModule(t, "apply-targeted-resource-orphan-module")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "foo",
+			),
+		},
+	})
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+}
+
+func TestContext2Apply_unknownAttribute(t *testing.T) {
+	m := testModule(t, "apply-unknown")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		resp = testDiffFn(req)
+		planned := resp.PlannedState.AsValueMap()
+		planned["unknown"] = cty.UnknownVal(cty.String)
+		resp.PlannedState = cty.ObjectVal(planned)
+		return resp
+	}
+	p.ApplyResourceChangeFn = testApplyFn
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":      {Type: cty.String, Computed: true},
+					"num":     {Type: cty.Number, Optional: true},
+					"unknown": {Type: cty.String, Computed: true},
+					"type":    {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if !diags.HasErrors() {
+		t.Error("should error, because attribute 'unknown' is still unknown after apply")
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyUnknownAttrStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_unknownAttributeInterpolate(t *testing.T) {
+	m := testModule(t, "apply-unknown-interpolate")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	if _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts); diags == nil {
+		t.Fatal("should error")
+	}
+}
+
+func TestContext2Apply_vars(t *testing.T) {
+	fixture := contextFixtureApplyVars(t)
+	opts := fixture.ContextOpts()
+	ctx := testContext2(t, opts)
+	m := fixture.Config
+
+	diags := ctx.Validate(m)
+	if len(diags) != 0 {
+		t.Fatalf("bad: %s", diags.ErrWithWarnings())
+	}
+
+	variables := InputValues{
+		"foo": &InputValue{
+			Value:      cty.StringVal("us-east-1"),
+			SourceType: ValueFromCaller,
+		},
+		"bar": &InputValue{
+			// This one is not explicitly set but that's okay because it
+			// has a declared default, which Terraform Core will use instead.
+			Value:      cty.NilVal,
+			SourceType: ValueFromCaller,
+		},
+		"test_list": &InputValue{
+			Value: cty.ListVal([]cty.Value{
+				cty.StringVal("Hello"),
+				cty.StringVal("World"),
+			}),
+			SourceType: ValueFromCaller,
+		},
+		"test_map": &InputValue{
+			Value: cty.MapVal(map[string]cty.Value{
+				"Hello": cty.StringVal("World"),
+				"Foo":   cty.StringVal("Bar"),
+				"Baz":   cty.StringVal("Foo"),
+			}),
+			SourceType: ValueFromCaller,
+		},
+		"amis": &InputValue{
+			Value: cty.MapVal(map[string]cty.Value{
+				"us-east-1": cty.StringVal("override"),
+			}),
+			SourceType: ValueFromCaller,
+		},
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode:         plans.NormalMode,
+		SetVariables: variables,
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	got := strings.TrimSpace(state.String())
+	want := strings.TrimSpace(testTerraformApplyVarsStr)
+	if got != want {
+		t.Errorf("wrong result\n\ngot:\n%s\n\nwant:\n%s", got, want)
+	}
+}
+
+func TestContext2Apply_varsEnv(t *testing.T) {
+	fixture := contextFixtureApplyVarsEnv(t)
+	opts := fixture.ContextOpts()
+	ctx := testContext2(t, opts)
+	m := fixture.Config
+
+	diags := ctx.Validate(m)
+	if len(diags) != 0 {
+		t.Fatalf("bad: %s", diags.ErrWithWarnings())
+	}
+
+	variables := InputValues{
+		"string": &InputValue{
+			Value:      cty.StringVal("baz"),
+			SourceType: ValueFromEnvVar,
+		},
+		"list": &InputValue{
+			Value: cty.ListVal([]cty.Value{
+				cty.StringVal("Hello"),
+				cty.StringVal("World"),
+			}),
+			SourceType: ValueFromEnvVar,
+		},
+		"map": &InputValue{
+			Value: cty.MapVal(map[string]cty.Value{
+				"Hello": cty.StringVal("World"),
+				"Foo":   cty.StringVal("Bar"),
+				"Baz":   cty.StringVal("Foo"),
+			}),
+			SourceType: ValueFromEnvVar,
+		},
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode:         plans.NormalMode,
+		SetVariables: variables,
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyVarsEnvStr)
+	if actual != expected {
+		t.Errorf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_createBefore_depends(t *testing.T) {
+	m := testModule(t, "apply-depends-create-before")
+	h := new(HookRecordApplyOrder)
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "aws_instance",
+			Name: "web",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","require_new":"ami-old"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("aws"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "aws_instance",
+			Name: "lb",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"baz","instance":"bar"}`),
+			Dependencies: []addrs.ConfigResource{
+				{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "aws_instance",
+						Name: "web",
+					},
+					Module: addrs.RootModule,
+				},
+			},
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("aws"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		logDiagnostics(t, diags)
+		t.Fatal("plan failed")
+	} else {
+		t.Logf("plan:\n%s", legacyDiffComparisonString(plan.Changes))
+	}
+
+	h.Active = true
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		logDiagnostics(t, diags)
+		t.Fatal("apply failed")
+	}
+
+	mod := state.RootModule()
+	if len(mod.Resources) < 2 {
+		t.Logf("state after apply:\n%s", state.String())
+		t.Fatalf("only %d resources in root module; want at least 2", len(mod.Resources))
+	}
+
+	got := strings.TrimSpace(state.String())
+	want := strings.TrimSpace(testTerraformApplyDependsCreateBeforeStr)
+	if got != want {
+		t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", got, want)
+	}
+
+	// Test that things were managed _in the right order_
+	order := h.States
+
+	diffs := h.Diffs
+	if !order[0].IsNull() || diffs[0].Action == plans.Delete {
+		t.Fatalf("should create new instance first: %#v", order)
+	}
+
+	if order[1].GetAttr("id").AsString() != "baz" {
+		t.Fatalf("update must happen after create: %#v", order[1])
+	}
+
+	if order[2].GetAttr("id").AsString() != "bar" || diffs[2].Action != plans.Delete {
+		t.Fatalf("destroy must happen after update: %#v", order[2])
+	}
+}
+
+func TestContext2Apply_singleDestroy(t *testing.T) {
+	m := testModule(t, "apply-depends-create-before")
+	h := new(HookRecordApplyOrder)
+	p := testProvider("aws")
+	invokeCount := 0
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		invokeCount++
+		switch invokeCount {
+		case 1:
+			if req.PlannedState.IsNull() {
+				t.Fatalf("should not destroy")
+			}
+			if id := req.PlannedState.GetAttr("id"); id.IsKnown() {
+				t.Fatalf("should not have ID")
+			}
+		case 2:
+			if req.PlannedState.IsNull() {
+				t.Fatalf("should not destroy")
+			}
+			if id := req.PlannedState.GetAttr("id"); id.AsString() != "baz" {
+				t.Fatalf("should have id")
+			}
+		case 3:
+			if !req.PlannedState.IsNull() {
+				t.Fatalf("should destroy")
+			}
+		default:
+			t.Fatalf("bad invoke count %d", invokeCount)
+		}
+		return testApplyFn(req)
+	}
+
+	p.PlanResourceChangeFn = testDiffFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "aws_instance",
+			Name: "web",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","require_new":"ami-old"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("aws"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "aws_instance",
+			Name: "lb",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"baz","instance":"bar"}`),
+			Dependencies: []addrs.ConfigResource{
+				{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "aws_instance",
+						Name: "web",
+					},
+					Module: addrs.RootModule,
+				},
+			},
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("aws"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	h.Active = true
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	if invokeCount != 3 {
+		t.Fatalf("bad: %d", invokeCount)
+	}
+}
+
+// GH-7824
+func TestContext2Apply_issue7824(t *testing.T) {
+	p := testProvider("template")
+	p.PlanResourceChangeFn = testDiffFn
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"template_file": {
+				Attributes: map[string]*configschema.Attribute{
+					"template":                {Type: cty.String, Optional: true},
+					"__template_requires_new": {Type: cty.Bool, Optional: true},
+				},
+			},
+		},
+	})
+
+	m, snap := testModuleWithSnapshot(t, "issue-7824")
+
+	// Apply cleanly step 0
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	// Write / Read plan to simulate running it through a Plan file
+	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
+	if err != nil {
+		t.Fatalf("failed to round-trip through planfile: %s", err)
+	}
+
+	ctxOpts.Providers =
+		map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
+		}
+
+	ctx, diags = NewContext(ctxOpts)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+}
+
+// This deals with the situation where a splat expression is used referring
+// to another resource whose count is non-constant.
+func TestContext2Apply_issue5254(t *testing.T) {
+	// Create a provider. We use "template" here just to match the repro
+	// we got from the issue itself.
+	p := testProvider("template")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"template_file": {
+				Attributes: map[string]*configschema.Attribute{
+					"template":                {Type: cty.String, Optional: true},
+					"__template_requires_new": {Type: cty.Bool, Optional: true},
+					"id":                      {Type: cty.String, Computed: true},
+					"type":                    {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	// Apply cleanly step 0
+	m := testModule(t, "issue-5254/step-0")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	m, snap := testModuleWithSnapshot(t, "issue-5254/step-1")
+
+	// Application success. Now make the modification and store a plan
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	// Write / Read plan to simulate running it through a Plan file
+	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
+	if err != nil {
+		t.Fatalf("failed to round-trip through planfile: %s", err)
+	}
+
+	ctxOpts.Providers = map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
+	}
+
+	ctx, diags = NewContext(ctxOpts)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(`
+template_file.child:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/template"]
+  __template_requires_new = true
+  template = Hi
+  type = template_file
+
+  Dependencies:
+    template_file.parent
+template_file.parent.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/template"]
+  template = Hi
+  type = template_file
+`)
+	if actual != expected {
+		t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Apply_targetedWithTaintedInState(t *testing.T) {
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	m, snap := testModuleWithSnapshot(t, "apply-tainted-targets")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.ifailedprovisioners").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"ifailedprovisioners"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "iambeingadded",
+			),
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	// Write / Read plan to simulate running it through a Plan file
+	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
+	if err != nil {
+		t.Fatalf("failed to round-trip through planfile: %s", err)
+	}
+
+	ctxOpts.Providers = map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+	}
+
+	ctx, diags = NewContext(ctxOpts)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	s, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace(`
+aws_instance.iambeingadded:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+aws_instance.ifailedprovisioners: (tainted)
+  ID = ifailedprovisioners
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+		`)
+	if actual != expected {
+		t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual)
+	}
+}
+
+// Higher level test exposing the bug this covers in
+// TestResource_ignoreChangesRequired
+func TestContext2Apply_ignoreChangesCreate(t *testing.T) {
+	m := testModule(t, "apply-ignore-changes-create")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	instanceSchema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	instanceSchema.Attributes["required_field"] = &configschema.Attribute{
+		Type:     cty.String,
+		Required: true,
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf(legacyDiffComparisonString(plan.Changes))
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	mod := state.RootModule()
+	if len(mod.Resources) != 1 {
+		t.Fatalf("bad: %s", state)
+	}
+
+	actual := strings.TrimSpace(state.String())
+	// Expect no changes from original state
+	expected := strings.TrimSpace(`
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  required_field = set
+  type = aws_instance
+`)
+	if actual != expected {
+		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
+	}
+}
+
+func TestContext2Apply_ignoreChangesWithDep(t *testing.T) {
+	m := testModule(t, "apply-ignore-changes-dep")
+	p := testProvider("aws")
+
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		resp.PlannedState = req.ProposedNewState
+
+		switch req.TypeName {
+		case "aws_instance":
+			resp.RequiresReplace = append(resp.RequiresReplace, cty.Path{cty.GetAttrStep{Name: "ami"}})
+		case "aws_eip":
+			return testDiffFn(req)
+		default:
+			t.Fatalf("Unexpected type: %s", req.TypeName)
+		}
+		return
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-abc123","ami":"ami-abcd1234"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-bcd234","ami":"i-bcd234"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_eip.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"eip-abc123","instance":"i-abc123"}`),
+			Dependencies: []addrs.ConfigResource{
+				{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "aws_instance",
+						Name: "foo",
+					},
+					Module: addrs.RootModule,
+				},
+			},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_eip.foo[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"eip-bcd234","instance":"i-bcd234"}`),
+			Dependencies: []addrs.ConfigResource{
+				{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "aws_instance",
+						Name: "foo",
+					},
+					Module: addrs.RootModule,
+				},
+			},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state.DeepCopy(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	s, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace(state.String())
+	if actual != expected {
+		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
+	}
+}
+
+func TestContext2Apply_ignoreChangesAll(t *testing.T) {
+	m := testModule(t, "apply-ignore-changes-all")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	instanceSchema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	instanceSchema.Attributes["required_field"] = &configschema.Attribute{
+		Type:     cty.String,
+		Required: true,
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		logDiagnostics(t, diags)
+		t.Fatal("plan failed")
+	} else {
+		t.Logf(legacyDiffComparisonString(plan.Changes))
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	mod := state.RootModule()
+	if len(mod.Resources) != 1 {
+		t.Fatalf("bad: %s", state)
+	}
+
+	actual := strings.TrimSpace(state.String())
+	// Expect no changes from original state
+	expected := strings.TrimSpace(`
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  required_field = set
+  type = aws_instance
+`)
+	if actual != expected {
+		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
+	}
+}
+
+// https://github.com/hashicorp/terraform/issues/7378
+func TestContext2Apply_destroyNestedModuleWithAttrsReferencingResource(t *testing.T) {
+	m, snap := testModuleWithSnapshot(t, "apply-destroy-nested-module-with-attrs")
+	p := testProvider("null")
+	p.PlanResourceChangeFn = testDiffFn
+
+	var state *states.State
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+			},
+		})
+
+		// First plan and apply a create operation
+		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+		assertNoErrors(t, diags)
+
+		state, diags = ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("apply err: %s", diags.Err())
+		}
+	}
+
+	{
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+			},
+		})
+
+		plan, diags := ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.DestroyMode,
+		})
+		if diags.HasErrors() {
+			t.Fatalf("destroy plan err: %s", diags.Err())
+		}
+
+		ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
+		if err != nil {
+			t.Fatalf("failed to round-trip through planfile: %s", err)
+		}
+
+		ctxOpts.Providers = map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		}
+
+		ctx, diags = NewContext(ctxOpts)
+		if diags.HasErrors() {
+			t.Fatalf("err: %s", diags.Err())
+		}
+
+		state, diags = ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("destroy apply err: %s", diags.Err())
+		}
+	}
+
+	if !state.Empty() {
+		t.Fatalf("state after apply: %s\nwant empty state", spew.Sdump(state))
+	}
+}
+
+// If a data source explicitly depends on another resource, it's because we need
+// that resource to be applied first.
+func TestContext2Apply_dataDependsOn(t *testing.T) {
+	p := testProvider("null")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "null_instance" "write" {
+  foo = "attribute"
+}
+
+data "null_data_source" "read" {
+  count = 1
+  depends_on = ["null_instance.write"]
+}
+
+resource "null_instance" "depends" {
+  foo = data.null_data_source.read[0].foo
+}
+`})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		},
+	})
+
+	// the "provisioner" here writes to this variable, because the intent is to
+	// create a dependency which can't be viewed through the graph, and depends
+	// solely on the configuration providing "depends_on"
+	provisionerOutput := ""
+
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		// the side effect of the resource being applied
+		provisionerOutput = "APPLIED"
+		return testApplyFn(req)
+	}
+
+	p.PlanResourceChangeFn = testDiffFn
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		return providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("boop"),
+				"foo": cty.StringVal(provisionerOutput),
+			}),
+		}
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	root := state.Module(addrs.RootModuleInstance)
+	is := root.ResourceInstance(addrs.Resource{
+		Mode: addrs.DataResourceMode,
+		Type: "null_data_source",
+		Name: "read",
+	}.Instance(addrs.IntKey(0)))
+	if is == nil {
+		t.Fatal("data resource instance is not present in state; should be")
+	}
+	var attrs map[string]interface{}
+	err := json.Unmarshal(is.Current.AttrsJSON, &attrs)
+	if err != nil {
+		t.Fatal(err)
+	}
+	actual := attrs["foo"]
+	expected := "APPLIED"
+	if actual != expected {
+		t.Fatalf("bad:\n%s", strings.TrimSpace(state.String()))
+	}
+
+	// run another plan to make sure the data source doesn't show as a change
+	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	for _, c := range plan.Changes.Resources {
+		if c.Action != plans.NoOp {
+			t.Fatalf("unexpected change for %s", c.Addr)
+		}
+	}
+
+	// now we cause a change in the first resource, which should trigger a plan
+	// in the data source, and the resource that depends on the data source
+	// must plan a change as well.
+	m = testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "null_instance" "write" {
+  foo = "new"
+}
+
+data "null_data_source" "read" {
+  depends_on = ["null_instance.write"]
+}
+
+resource "null_instance" "depends" {
+  foo = data.null_data_source.read.foo
+}
+`})
+
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		// the side effect of the resource being applied
+		provisionerOutput = "APPLIED_AGAIN"
+		return testApplyFn(req)
+	}
+
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	expectedChanges := map[string]plans.Action{
+		"null_instance.write":        plans.Update,
+		"data.null_data_source.read": plans.Read,
+		"null_instance.depends":      plans.Update,
+	}
+
+	for _, c := range plan.Changes.Resources {
+		if c.Action != expectedChanges[c.Addr.String()] {
+			t.Errorf("unexpected %s for %s", c.Action, c.Addr)
+		}
+	}
+}
+
+func TestContext2Apply_terraformWorkspace(t *testing.T) {
+	m := testModule(t, "apply-terraform-workspace")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	ctx := testContext2(t, &ContextOpts{
+		Meta: &ContextMeta{Env: "foo"},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	actual := state.RootModule().OutputValues["output"]
+	expected := cty.StringVal("foo")
+	if actual == nil || actual.Value != expected {
+		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
+	}
+}
+
+// verify that multiple config references only create a single depends_on entry
+func TestContext2Apply_multiRef(t *testing.T) {
+	m := testModule(t, "apply-multi-ref")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	deps := state.Modules[""].Resources["aws_instance.other"].Instances[addrs.NoKey].Current.Dependencies
+	if len(deps) != 1 || deps[0].String() != "aws_instance.create" {
+		t.Fatalf("expected 1 depends_on entry for aws_instance.create, got %q", deps)
+	}
+}
+
+func TestContext2Apply_targetedModuleRecursive(t *testing.T) {
+	m := testModule(t, "apply-targeted-module-recursive")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Child("child", addrs.NoKey),
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	mod := state.Module(
+		addrs.RootModuleInstance.Child("child", addrs.NoKey).Child("subchild", addrs.NoKey),
+	)
+	if mod == nil {
+		t.Fatalf("no subchild module found in the state!\n\n%#v", state)
+	}
+	if len(mod.Resources) != 1 {
+		t.Fatalf("expected 1 resources, got: %#v", mod.Resources)
+	}
+
+	checkStateString(t, state, `
+<no state>
+module.child.subchild:
+  aws_instance.foo:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    num = 2
+    type = aws_instance
+	`)
+}
+
+func TestContext2Apply_localVal(t *testing.T) {
+	m := testModule(t, "apply-local-val")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("error during apply: %s", diags.Err())
+	}
+
+	got := strings.TrimSpace(state.String())
+	want := strings.TrimSpace(`
+<no state>
+Outputs:
+
+result_1 = hello
+result_3 = hello world
+`)
+	if got != want {
+		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
+	}
+}
+
+func TestContext2Apply_destroyWithLocals(t *testing.T) {
+	m := testModule(t, "apply-destroy-with-locals")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetOutputValue("name", cty.StringVal("test-bar"), false)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	s, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("error during apply: %s", diags.Err())
+	}
+
+	got := strings.TrimSpace(s.String())
+	want := strings.TrimSpace(`<no state>`)
+	if got != want {
+		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
+	}
+}
+
+func TestContext2Apply_providerWithLocals(t *testing.T) {
+	m := testModule(t, "provider-with-locals")
+	p := testProvider("aws")
+
+	providerRegion := ""
+	// this should not be overridden during destroy
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		val := req.Config.GetAttr("region")
+		if !val.IsNull() {
+			providerRegion = val.AsString()
+		}
+
+		return
+	}
+
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	if state.HasManagedResourceInstanceObjects() {
+		t.Fatal("expected no state, got:", state)
+	}
+
+	if providerRegion != "bar" {
+		t.Fatalf("expected region %q, got: %q", "bar", providerRegion)
+	}
+}
+
+func TestContext2Apply_destroyWithProviders(t *testing.T) {
+	m := testModule(t, "destroy-module-with-provider")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	removed := state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.NoKey).Child("removed", addrs.NoKey))
+	removed.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.child").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"].baz`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	// test that we can't destroy if the provider is missing
+	if _, diags := ctx.Plan(m, state, &PlanOpts{Mode: plans.DestroyMode}); diags == nil {
+		t.Fatal("expected plan error, provider.aws.baz doesn't exist")
+	}
+
+	// correct the state
+	state.Modules["module.mod.module.removed"].Resources["aws_instance.child"].ProviderConfig = mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"].bar`)
+
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("error during apply: %s", diags.Err())
+	}
+
+	got := strings.TrimSpace(state.String())
+
+	want := strings.TrimSpace("<no state>")
+	if got != want {
+		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
+	}
+}
+
+func TestContext2Apply_providersFromState(t *testing.T) {
+	m := configs.NewEmptyConfig()
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	implicitProviderState := states.NewState()
+	impRoot := implicitProviderState.EnsureModule(addrs.RootModuleInstance)
+	impRoot.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	aliasedProviderState := states.NewState()
+	aliasRoot := aliasedProviderState.EnsureModule(addrs.RootModuleInstance)
+	aliasRoot.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"].bar`),
+	)
+
+	moduleProviderState := states.NewState()
+	moduleProviderRoot := moduleProviderState.EnsureModule(addrs.RootModuleInstance)
+	moduleProviderRoot.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`module.child.provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	for _, tc := range []struct {
+		name   string
+		state  *states.State
+		output string
+		err    bool
+	}{
+		{
+			name:   "add implicit provider",
+			state:  implicitProviderState,
+			err:    false,
+			output: "<no state>",
+		},
+
+		// an aliased provider must be in the config to remove a resource
+		{
+			name:  "add aliased provider",
+			state: aliasedProviderState,
+			err:   true,
+		},
+
+		// a provider in a module implies some sort of config, so this isn't
+		// allowed even without an alias
+		{
+			name:  "add unaliased module provider",
+			state: moduleProviderState,
+			err:   true,
+		},
+	} {
+		t.Run(tc.name, func(t *testing.T) {
+			ctx := testContext2(t, &ContextOpts{
+				Providers: map[addrs.Provider]providers.Factory{
+					addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+				},
+			})
+
+			plan, diags := ctx.Plan(m, tc.state, DefaultPlanOpts)
+			if tc.err {
+				if diags == nil {
+					t.Fatal("expected error")
+				} else {
+					return
+				}
+			}
+			if !tc.err && diags.HasErrors() {
+				t.Fatal(diags.Err())
+			}
+
+			state, diags := ctx.Apply(plan, m)
+			if diags.HasErrors() {
+				t.Fatalf("diags: %s", diags.Err())
+			}
+
+			checkStateString(t, state, "<no state>")
+
+		})
+	}
+}
+
+func TestContext2Apply_plannedInterpolatedCount(t *testing.T) {
+	m, snap := testModuleWithSnapshot(t, "apply-interpolated-count")
+
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	Providers := map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.test").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: Providers,
+	})
+
+	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatalf("plan failed: %s", diags.Err())
+	}
+
+	// We'll marshal and unmarshal the plan here, to ensure that we have
+	// a clean new context as would be created if we separately ran
+	// terraform plan -out=tfplan && terraform apply tfplan
+	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
+	if err != nil {
+		t.Fatalf("failed to round-trip through planfile: %s", err)
+	}
+
+	ctxOpts.Providers = Providers
+	ctx, diags = NewContext(ctxOpts)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	// Applying the plan should now succeed
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply failed: %s", diags.Err())
+	}
+}
+
+func TestContext2Apply_plannedDestroyInterpolatedCount(t *testing.T) {
+	m, snap := testModuleWithSnapshot(t, "plan-destroy-interpolated-count")
+
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	providers := map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.a[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.a[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetOutputValue("out", cty.ListVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("foo")}), false)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: providers,
+	})
+
+	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatalf("plan failed: %s", diags.Err())
+	}
+
+	// We'll marshal and unmarshal the plan here, to ensure that we have
+	// a clean new context as would be created if we separately ran
+	// terraform plan -out=tfplan && terraform apply tfplan
+	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
+	if err != nil {
+		t.Fatalf("failed to round-trip through planfile: %s", err)
+	}
+
+	ctxOpts.Providers = providers
+	ctx, diags = NewContext(ctxOpts)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	// Applying the plan should now succeed
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply failed: %s", diags.Err())
+	}
+	if !state.Empty() {
+		t.Fatalf("state not empty: %s\n", state)
+	}
+}
+
+func TestContext2Apply_scaleInMultivarRef(t *testing.T) {
+	m := testModule(t, "apply-resource-scale-in")
+
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	Providers := map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.one").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.two").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: Providers,
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"instance_count": {
+				Value:      cty.NumberIntVal(0),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+	{
+		addr := mustResourceInstanceAddr("aws_instance.one[0]")
+		change := plan.Changes.ResourceInstance(addr)
+		if change == nil {
+			t.Fatalf("no planned change for %s", addr)
+		}
+		// This test was originally written with Terraform v0.11 and earlier
+		// in mind, so it declares a no-key instance of aws_instance.one,
+		// but its configuration sets count (to zero) and so we end up first
+		// moving the no-key instance to the zero key and then planning to
+		// destroy the zero key.
+		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("aws_instance.one"); !want.Equal(got) {
+			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
+		}
+		if got, want := change.Action, plans.Delete; got != want {
+			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
+		}
+		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseCountIndex; got != want {
+			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
+		}
+	}
+	{
+		addr := mustResourceInstanceAddr("aws_instance.two")
+		change := plan.Changes.ResourceInstance(addr)
+		if change == nil {
+			t.Fatalf("no planned change for %s", addr)
+		}
+		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("aws_instance.two"); !want.Equal(got) {
+			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
+		}
+		if got, want := change.Action, plans.Update; got != want {
+			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
+		}
+		if got, want := change.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
+		}
+	}
+
+	// Applying the plan should now succeed
+	_, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+}
+
+func TestContext2Apply_inconsistentWithPlan(t *testing.T) {
+	m := testModule(t, "apply-inconsistent-with-plan")
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: cty.ObjectVal(map[string]cty.Value{
+				"id": cty.StringVal("before"),
+			}),
+		}
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		return providers.ApplyResourceChangeResponse{
+			NewState: cty.ObjectVal(map[string]cty.Value{
+				// This is intentionally incorrect: because id was fixed at "before"
+				// during plan, it must not change during apply.
+				"id": cty.StringVal("after"),
+			}),
+		}
+	}
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	if !diags.HasErrors() {
+		t.Fatalf("apply succeeded; want error")
+	}
+	if got, want := diags.Err().Error(), "Provider produced inconsistent result after apply"; !strings.Contains(got, want) {
+		t.Fatalf("wrong error\ngot: %s\nshould contain: %s", got, want)
+	}
+}
+
+// Issue 19908 was about retaining an existing object in the state when an
+// update to it fails and the provider does not return a partially-updated
+// value for it. Previously we were incorrectly removing it from the state
+// in that case, but instead it should be retained so the update can be
+// retried.
+func TestContext2Apply_issue19908(t *testing.T) {
+	m := testModule(t, "apply-issue19908")
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test": {
+				Attributes: map[string]*configschema.Attribute{
+					"baz": {Type: cty.String, Required: true},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		var diags tfdiags.Diagnostics
+		diags = diags.Append(fmt.Errorf("update failed"))
+		return providers.ApplyResourceChangeResponse{
+			Diagnostics: diags,
+		}
+	}
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"baz":"old"}`),
+				Status:    states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if !diags.HasErrors() {
+		t.Fatalf("apply succeeded; want error")
+	}
+	if got, want := diags.Err().Error(), "update failed"; !strings.Contains(got, want) {
+		t.Fatalf("wrong error\ngot: %s\nshould contain: %s", got, want)
+	}
+
+	mod := state.RootModule()
+	rs := mod.Resources["test.foo"]
+	if rs == nil {
+		t.Fatalf("test.foo not in state after apply, but should be")
+	}
+	is := rs.Instances[addrs.NoKey]
+	if is == nil {
+		t.Fatalf("test.foo not in state after apply, but should be")
+	}
+	obj := is.Current
+	if obj == nil {
+		t.Fatalf("test.foo has no current object in state after apply, but should do")
+	}
+
+	if got, want := obj.Status, states.ObjectReady; got != want {
+		t.Errorf("test.foo has wrong status %s after apply; want %s", got, want)
+	}
+	if got, want := obj.AttrsJSON, []byte(`"old"`); !bytes.Contains(got, want) {
+		t.Errorf("test.foo attributes JSON doesn't contain %s after apply\ngot: %s", want, got)
+	}
+}
+
+func TestContext2Apply_invalidIndexRef(t *testing.T) {
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"value": {Type: cty.String, Optional: true, Computed: true},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = testDiffFn
+
+	m := testModule(t, "apply-invalid-index")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected validation failure: %s", diags.Err())
+	}
+
+	wantErr := `The given key does not identify an element in this collection value`
+	_, diags = c.Plan(m, states.NewState(), DefaultPlanOpts)
+
+	if !diags.HasErrors() {
+		t.Fatalf("plan succeeded; want error")
+	}
+	gotErr := diags.Err().Error()
+
+	if !strings.Contains(gotErr, wantErr) {
+		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErr, wantErr)
+	}
+}
+
+func TestContext2Apply_moduleReplaceCycle(t *testing.T) {
+	for _, mode := range []string{"normal", "cbd"} {
+		var m *configs.Config
+
+		switch mode {
+		case "normal":
+			m = testModule(t, "apply-module-replace-cycle")
+		case "cbd":
+			m = testModule(t, "apply-module-replace-cycle-cbd")
+		}
+
+		p := testProvider("aws")
+		p.PlanResourceChangeFn = testDiffFn
+
+		instanceSchema := &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"id":          {Type: cty.String, Computed: true},
+				"require_new": {Type: cty.String, Optional: true},
+			},
+		}
+
+		p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+			ResourceTypes: map[string]*configschema.Block{
+				"aws_instance": instanceSchema,
+			},
+		})
+
+		state := states.NewState()
+		modA := state.EnsureModule(addrs.RootModuleInstance.Child("a", addrs.NoKey))
+		modA.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "a",
+			}.Instance(addrs.NoKey),
+			&states.ResourceInstanceObjectSrc{
+				Status:              states.ObjectReady,
+				AttrsJSON:           []byte(`{"id":"a","require_new":"old"}`),
+				CreateBeforeDestroy: mode == "cbd",
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+
+		modB := state.EnsureModule(addrs.RootModuleInstance.Child("b", addrs.NoKey))
+		modB.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "b",
+			}.Instance(addrs.IntKey(0)),
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectReady,
+				AttrsJSON: []byte(`{"id":"b","require_new":"old"}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+
+		aBefore, _ := plans.NewDynamicValue(
+			cty.ObjectVal(map[string]cty.Value{
+				"id":          cty.StringVal("a"),
+				"require_new": cty.StringVal("old"),
+			}), instanceSchema.ImpliedType())
+		aAfter, _ := plans.NewDynamicValue(
+			cty.ObjectVal(map[string]cty.Value{
+				"id":          cty.UnknownVal(cty.String),
+				"require_new": cty.StringVal("new"),
+			}), instanceSchema.ImpliedType())
+		bBefore, _ := plans.NewDynamicValue(
+			cty.ObjectVal(map[string]cty.Value{
+				"id":          cty.StringVal("b"),
+				"require_new": cty.StringVal("old"),
+			}), instanceSchema.ImpliedType())
+		bAfter, _ := plans.NewDynamicValue(
+			cty.ObjectVal(map[string]cty.Value{
+				"id":          cty.UnknownVal(cty.String),
+				"require_new": cty.UnknownVal(cty.String),
+			}), instanceSchema.ImpliedType())
+
+		var aAction plans.Action
+		switch mode {
+		case "normal":
+			aAction = plans.DeleteThenCreate
+		case "cbd":
+			aAction = plans.CreateThenDelete
+		}
+
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		changes := &plans.Changes{
+			Resources: []*plans.ResourceInstanceChangeSrc{
+				{
+					Addr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "aws_instance",
+						Name: "a",
+					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("a", addrs.NoKey)),
+					ProviderAddr: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("aws"),
+						Module:   addrs.RootModule,
+					},
+					ChangeSrc: plans.ChangeSrc{
+						Action: aAction,
+						Before: aBefore,
+						After:  aAfter,
+					},
+				},
+				{
+					Addr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "aws_instance",
+						Name: "b",
+					}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance.Child("b", addrs.NoKey)),
+					ProviderAddr: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("aws"),
+						Module:   addrs.RootModule,
+					},
+					ChangeSrc: plans.ChangeSrc{
+						Action: plans.DeleteThenCreate,
+						Before: bBefore,
+						After:  bAfter,
+					},
+				},
+			},
+		}
+
+		plan := &plans.Plan{
+			UIMode:       plans.NormalMode,
+			Changes:      changes,
+			PriorState:   state.DeepCopy(),
+			PrevRunState: state.DeepCopy(),
+		}
+
+		t.Run(mode, func(t *testing.T) {
+			_, diags := ctx.Apply(plan, m)
+			if diags.HasErrors() {
+				t.Fatal(diags.Err())
+			}
+		})
+	}
+}
+
+func TestContext2Apply_destroyDataCycle(t *testing.T) {
+	m, snap := testModuleWithSnapshot(t, "apply-destroy-data-cycle")
+	p := testProvider("null")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		return providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("new"),
+				"foo": cty.NullVal(cty.String),
+			}),
+		}
+	}
+
+	tp := testProvider("test")
+	tp.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "null_resource",
+			Name: "a",
+		}.Instance(addrs.IntKey(0)),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"a"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("null"),
+			Module:   addrs.RootModule,
+		},
+	)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_resource",
+			Name: "a",
+		}.Instance(addrs.IntKey(0)),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"a"}`),
+			Dependencies: []addrs.ConfigResource{
+				{
+					Resource: addrs.Resource{
+						Mode: addrs.DataResourceMode,
+						Type: "null_data_source",
+						Name: "d",
+					},
+					Module: addrs.RootModule,
+				},
+			},
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.DataResourceMode,
+			Type: "null_data_source",
+			Name: "d",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"old"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("null"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	Providers := map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		addrs.NewDefaultProvider("test"): testProviderFuncFixed(tp),
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: Providers,
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	diags.HasErrors()
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	// We'll marshal and unmarshal the plan here, to ensure that we have
+	// a clean new context as would be created if we separately ran
+	// terraform plan -out=tfplan && terraform apply tfplan
+	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ctxOpts.Providers = Providers
+	ctx, diags = NewContext(ctxOpts)
+	if diags.HasErrors() {
+		t.Fatalf("failed to create context for plan: %s", diags.Err())
+	}
+
+	tp.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		foo := req.Config.GetAttr("foo")
+		if !foo.IsKnown() {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown config value foo"))
+			return resp
+		}
+
+		if foo.AsString() != "new" {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("wrong config value: %q", foo.AsString()))
+		}
+		return resp
+	}
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+}
+
+func TestContext2Apply_taintedDestroyFailure(t *testing.T) {
+	m := testModule(t, "apply-destroy-tainted")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		// All destroys fail.
+		if req.PlannedState.IsNull() {
+			resp.Diagnostics = resp.Diagnostics.Append(errors.New("failure"))
+			return
+		}
+
+		// c will also fail to create, meaning the existing tainted instance
+		// becomes deposed, ans is then promoted back to current.
+		// only C has a foo attribute
+		planned := req.PlannedState.AsValueMap()
+		foo, ok := planned["foo"]
+		if ok && !foo.IsNull() && foo.AsString() == "c" {
+			resp.Diagnostics = resp.Diagnostics.Append(errors.New("failure"))
+			return
+		}
+
+		return testApplyFn(req)
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+		},
+	})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: "a",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"a","foo":"a"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: "b",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"b","foo":"b"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: "c",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"c","foo":"old"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	Providers := map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: Providers,
+		Hooks:     []Hook{&testHook{}},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	diags.HasErrors()
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	state, diags = ctx.Apply(plan, m)
+	if !diags.HasErrors() {
+		t.Fatal("expected error")
+	}
+
+	root = state.Module(addrs.RootModuleInstance)
+
+	// the instance that failed to destroy should remain tainted
+	a := root.ResourceInstance(addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "a",
+	}.Instance(addrs.NoKey))
+
+	if a.Current.Status != states.ObjectTainted {
+		t.Fatal("test_instance.a should be tainted")
+	}
+
+	// b is create_before_destroy, and the destroy failed, so there should be 1
+	// deposed instance.
+	b := root.ResourceInstance(addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "b",
+	}.Instance(addrs.NoKey))
+
+	if b.Current.Status != states.ObjectReady {
+		t.Fatal("test_instance.b should be Ready")
+	}
+
+	if len(b.Deposed) != 1 {
+		t.Fatal("test_instance.b failed to keep deposed instance")
+	}
+
+	// the desposed c instance should be promoted back to Current, and remain
+	// tainted
+	c := root.ResourceInstance(addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_instance",
+		Name: "c",
+	}.Instance(addrs.NoKey))
+
+	if c.Current == nil {
+		t.Fatal("test_instance.c has no current instance, but it should")
+	}
+
+	if c.Current.Status != states.ObjectTainted {
+		t.Fatal("test_instance.c should be tainted")
+	}
+
+	if len(c.Deposed) != 0 {
+		t.Fatal("test_instance.c should have no deposed instances")
+	}
+
+	if string(c.Current.AttrsJSON) != `{"foo":"old","id":"c"}` {
+		t.Fatalf("unexpected attrs for c: %q\n", c.Current.AttrsJSON)
+	}
+}
+
+func TestContext2Apply_plannedConnectionRefs(t *testing.T) {
+	m := testModule(t, "apply-plan-connection-refs")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		s := req.PlannedState.AsValueMap()
+		// delay "a" slightly, so if the reference edge is missing the "b"
+		// provisioner will see an unknown value.
+		if s["foo"].AsString() == "a" {
+			time.Sleep(500 * time.Millisecond)
+		}
+
+		s["id"] = cty.StringVal("ID")
+		if ty, ok := s["type"]; ok && !ty.IsKnown() {
+			s["type"] = cty.StringVal(req.TypeName)
+		}
+		resp.NewState = cty.ObjectVal(s)
+		return resp
+	}
+
+	provisionerFactory := func() (provisioners.Interface, error) {
+		pr := testProvisioner()
+		pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+			host := req.Connection.GetAttr("host")
+			if host.IsNull() || !host.IsKnown() {
+				resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("invalid host value: %#v", host))
+			}
+
+			return resp
+		}
+		return pr, nil
+	}
+
+	Providers := map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+	}
+
+	provisioners := map[string]provisioners.Factory{
+		"shell": provisionerFactory,
+	}
+
+	hook := &testHook{}
+	ctx := testContext2(t, &ContextOpts{
+		Providers:    Providers,
+		Provisioners: provisioners,
+		Hooks:        []Hook{hook},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	diags.HasErrors()
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+}
+
+func TestContext2Apply_cbdCycle(t *testing.T) {
+	m, snap := testModuleWithSnapshot(t, "apply-cbd-cycle")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: "a",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"a","require_new":"old","foo":"b"}`),
+			Dependencies: []addrs.ConfigResource{
+				{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_instance",
+						Name: "b",
+					},
+					Module: addrs.RootModule,
+				},
+				{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_instance",
+						Name: "c",
+					},
+					Module: addrs.RootModule,
+				},
+			},
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: "b",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"b","require_new":"old","foo":"c"}`),
+			Dependencies: []addrs.ConfigResource{
+				{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_instance",
+						Name: "c",
+					},
+					Module: addrs.RootModule,
+				},
+			},
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_instance",
+			Name: "c",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"c","require_new":"old"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	Providers := map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+	}
+
+	hook := &testHook{}
+	ctx := testContext2(t, &ContextOpts{
+		Providers: Providers,
+		Hooks:     []Hook{hook},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	diags.HasErrors()
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	// We'll marshal and unmarshal the plan here, to ensure that we have
+	// a clean new context as would be created if we separately ran
+	// terraform plan -out=tfplan && terraform apply tfplan
+	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ctxOpts.Providers = Providers
+	ctx, diags = NewContext(ctxOpts)
+	if diags.HasErrors() {
+		t.Fatalf("failed to create context for plan: %s", diags.Err())
+	}
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+}
+
+func TestContext2Apply_ProviderMeta_apply_set(t *testing.T) {
+	m := testModule(t, "provider-meta-set")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	schema := p.ProviderSchema()
+	schema.ProviderMeta = &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"baz": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	}
+
+	var pmMu sync.Mutex
+	arcPMs := map[string]cty.Value{}
+
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		pmMu.Lock()
+		defer pmMu.Unlock()
+		arcPMs[req.TypeName] = req.ProviderMeta
+
+		s := req.PlannedState.AsValueMap()
+		s["id"] = cty.StringVal("ID")
+		if ty, ok := s["type"]; ok && !ty.IsKnown() {
+			s["type"] = cty.StringVal(req.TypeName)
+		}
+		return providers.ApplyResourceChangeResponse{
+			NewState: cty.ObjectVal(s),
+		}
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	if !p.ApplyResourceChangeCalled {
+		t.Fatalf("ApplyResourceChange not called")
+	}
+
+	expectations := map[string]cty.Value{}
+
+	if pm, ok := arcPMs["test_resource"]; !ok {
+		t.Fatalf("sub-module ApplyResourceChange not called")
+	} else if pm.IsNull() {
+		t.Fatalf("null ProviderMeta in sub-module ApplyResourceChange")
+	} else {
+		expectations["quux-submodule"] = pm
+	}
+
+	if pm, ok := arcPMs["test_instance"]; !ok {
+		t.Fatalf("root module ApplyResourceChange not called")
+	} else if pm.IsNull() {
+		t.Fatalf("null ProviderMeta in root module ApplyResourceChange")
+	} else {
+		expectations["quux"] = pm
+	}
+
+	type metaStruct struct {
+		Baz string `cty:"baz"`
+	}
+
+	for expected, v := range expectations {
+		var meta metaStruct
+		err := gocty.FromCtyValue(v, &meta)
+		if err != nil {
+			t.Fatalf("Error parsing cty value: %s", err)
+		}
+		if meta.Baz != expected {
+			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
+		}
+	}
+}
+
+func TestContext2Apply_ProviderMeta_apply_unset(t *testing.T) {
+	m := testModule(t, "provider-meta-unset")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	schema := p.ProviderSchema()
+	schema.ProviderMeta = &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"baz": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	}
+	var pmMu sync.Mutex
+	arcPMs := map[string]cty.Value{}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		pmMu.Lock()
+		defer pmMu.Unlock()
+		arcPMs[req.TypeName] = req.ProviderMeta
+
+		s := req.PlannedState.AsValueMap()
+		s["id"] = cty.StringVal("ID")
+		if ty, ok := s["type"]; ok && !ty.IsKnown() {
+			s["type"] = cty.StringVal(req.TypeName)
+		}
+		return providers.ApplyResourceChangeResponse{
+			NewState: cty.ObjectVal(s),
+		}
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	if !p.ApplyResourceChangeCalled {
+		t.Fatalf("ApplyResourceChange not called")
+	}
+
+	if pm, ok := arcPMs["test_resource"]; !ok {
+		t.Fatalf("sub-module ApplyResourceChange not called")
+	} else if !pm.IsNull() {
+		t.Fatalf("non-null ProviderMeta in sub-module ApplyResourceChange: %+v", pm)
+	}
+
+	if pm, ok := arcPMs["test_instance"]; !ok {
+		t.Fatalf("root module ApplyResourceChange not called")
+	} else if !pm.IsNull() {
+		t.Fatalf("non-null ProviderMeta in root module ApplyResourceChange: %+v", pm)
+	}
+}
+
+func TestContext2Apply_ProviderMeta_plan_set(t *testing.T) {
+	m := testModule(t, "provider-meta-set")
+	p := testProvider("test")
+	schema := p.ProviderSchema()
+	schema.ProviderMeta = &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"baz": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	}
+	prcPMs := map[string]cty.Value{}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		prcPMs[req.TypeName] = req.ProviderMeta
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if !p.PlanResourceChangeCalled {
+		t.Fatalf("PlanResourceChange not called")
+	}
+
+	expectations := map[string]cty.Value{}
+
+	if pm, ok := prcPMs["test_resource"]; !ok {
+		t.Fatalf("sub-module PlanResourceChange not called")
+	} else if pm.IsNull() {
+		t.Fatalf("null ProviderMeta in sub-module PlanResourceChange")
+	} else {
+		expectations["quux-submodule"] = pm
+	}
+
+	if pm, ok := prcPMs["test_instance"]; !ok {
+		t.Fatalf("root module PlanResourceChange not called")
+	} else if pm.IsNull() {
+		t.Fatalf("null ProviderMeta in root module PlanResourceChange")
+	} else {
+		expectations["quux"] = pm
+	}
+
+	type metaStruct struct {
+		Baz string `cty:"baz"`
+	}
+
+	for expected, v := range expectations {
+		var meta metaStruct
+		err := gocty.FromCtyValue(v, &meta)
+		if err != nil {
+			t.Fatalf("Error parsing cty value: %s", err)
+		}
+		if meta.Baz != expected {
+			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
+		}
+	}
+}
+
+func TestContext2Apply_ProviderMeta_plan_unset(t *testing.T) {
+	m := testModule(t, "provider-meta-unset")
+	p := testProvider("test")
+	schema := p.ProviderSchema()
+	schema.ProviderMeta = &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"baz": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	}
+	prcPMs := map[string]cty.Value{}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		prcPMs[req.TypeName] = req.ProviderMeta
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if !p.PlanResourceChangeCalled {
+		t.Fatalf("PlanResourceChange not called")
+	}
+
+	if pm, ok := prcPMs["test_resource"]; !ok {
+		t.Fatalf("sub-module PlanResourceChange not called")
+	} else if !pm.IsNull() {
+		t.Fatalf("non-null ProviderMeta in sub-module PlanResourceChange: %+v", pm)
+	}
+
+	if pm, ok := prcPMs["test_instance"]; !ok {
+		t.Fatalf("root module PlanResourceChange not called")
+	} else if !pm.IsNull() {
+		t.Fatalf("non-null ProviderMeta in root module PlanResourceChange: %+v", pm)
+	}
+}
+
+func TestContext2Apply_ProviderMeta_plan_setNoSchema(t *testing.T) {
+	m := testModule(t, "provider-meta-set")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("plan supposed to error, has no errors")
+	}
+
+	var rootErr, subErr bool
+	errorSummary := "The resource test_%s.bar belongs to a provider that doesn't support provider_meta blocks"
+	for _, diag := range diags {
+		if diag.Description().Summary != "Provider registry.terraform.io/hashicorp/test doesn't support provider_meta" {
+			t.Errorf("Unexpected error: %+v", diag.Description())
+		}
+		switch diag.Description().Detail {
+		case fmt.Sprintf(errorSummary, "instance"):
+			rootErr = true
+		case fmt.Sprintf(errorSummary, "resource"):
+			subErr = true
+		default:
+			t.Errorf("Unexpected error: %s", diag.Description())
+		}
+	}
+	if !rootErr {
+		t.Errorf("Expected unsupported provider_meta block error for root module, none received")
+	}
+	if !subErr {
+		t.Errorf("Expected unsupported provider_meta block error for sub-module, none received")
+	}
+}
+
+func TestContext2Apply_ProviderMeta_plan_setInvalid(t *testing.T) {
+	m := testModule(t, "provider-meta-set")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	schema := p.ProviderSchema()
+	schema.ProviderMeta = &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"quux": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("plan supposed to error, has no errors")
+	}
+
+	var reqErr, invalidErr bool
+	for _, diag := range diags {
+		switch diag.Description().Summary {
+		case "Missing required argument":
+			if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` {
+				reqErr = true
+			} else {
+				t.Errorf("Unexpected error %+v", diag.Description())
+			}
+		case "Unsupported argument":
+			if diag.Description().Detail == `An argument named "baz" is not expected here.` {
+				invalidErr = true
+			} else {
+				t.Errorf("Unexpected error %+v", diag.Description())
+			}
+		default:
+			t.Errorf("Unexpected error %+v", diag.Description())
+		}
+	}
+	if !reqErr {
+		t.Errorf("Expected missing required argument error, none received")
+	}
+	if !invalidErr {
+		t.Errorf("Expected unsupported argument error, none received")
+	}
+}
+
+func TestContext2Apply_ProviderMeta_refresh_set(t *testing.T) {
+	m := testModule(t, "provider-meta-set")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	schema := p.ProviderSchema()
+	schema.ProviderMeta = &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"baz": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	}
+	rrcPMs := map[string]cty.Value{}
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+		rrcPMs[req.TypeName] = req.ProviderMeta
+		newState, err := p.GetProviderSchemaResponse.ResourceTypes[req.TypeName].Block.CoerceValue(req.PriorState)
+		if err != nil {
+			panic(err)
+		}
+		resp.NewState = newState
+		return resp
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if !p.ReadResourceCalled {
+		t.Fatalf("ReadResource not called")
+	}
+
+	expectations := map[string]cty.Value{}
+
+	if pm, ok := rrcPMs["test_resource"]; !ok {
+		t.Fatalf("sub-module ReadResource not called")
+	} else if pm.IsNull() {
+		t.Fatalf("null ProviderMeta in sub-module ReadResource")
+	} else {
+		expectations["quux-submodule"] = pm
+	}
+
+	if pm, ok := rrcPMs["test_instance"]; !ok {
+		t.Fatalf("root module ReadResource not called")
+	} else if pm.IsNull() {
+		t.Fatalf("null ProviderMeta in root module ReadResource")
+	} else {
+		expectations["quux"] = pm
+	}
+
+	type metaStruct struct {
+		Baz string `cty:"baz"`
+	}
+
+	for expected, v := range expectations {
+		var meta metaStruct
+		err := gocty.FromCtyValue(v, &meta)
+		if err != nil {
+			t.Fatalf("Error parsing cty value: %s", err)
+		}
+		if meta.Baz != expected {
+			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
+		}
+	}
+}
+
+func TestContext2Apply_ProviderMeta_refresh_setNoSchema(t *testing.T) {
+	m := testModule(t, "provider-meta-set")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+
+	// we need a schema for plan/apply so they don't error
+	schema := p.ProviderSchema()
+	schema.ProviderMeta = &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"baz": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	// drop the schema before refresh, to test that it errors
+	schema.ProviderMeta = nil
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("refresh supposed to error, has no errors")
+	}
+
+	var rootErr, subErr bool
+	errorSummary := "The resource test_%s.bar belongs to a provider that doesn't support provider_meta blocks"
+	for _, diag := range diags {
+		if diag.Description().Summary != "Provider registry.terraform.io/hashicorp/test doesn't support provider_meta" {
+			t.Errorf("Unexpected error: %+v", diag.Description())
+		}
+		switch diag.Description().Detail {
+		case fmt.Sprintf(errorSummary, "instance"):
+			rootErr = true
+		case fmt.Sprintf(errorSummary, "resource"):
+			subErr = true
+		default:
+			t.Errorf("Unexpected error: %s", diag.Description())
+		}
+	}
+	if !rootErr {
+		t.Errorf("Expected unsupported provider_meta block error for root module, none received")
+	}
+	if !subErr {
+		t.Errorf("Expected unsupported provider_meta block error for sub-module, none received")
+	}
+}
+
+func TestContext2Apply_ProviderMeta_refresh_setInvalid(t *testing.T) {
+	m := testModule(t, "provider-meta-set")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+
+	// we need a matching schema for plan/apply so they don't error
+	schema := p.ProviderSchema()
+	schema.ProviderMeta = &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"baz": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	// change the schema before refresh, to test that it errors
+	schema.ProviderMeta = &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"quux": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("refresh supposed to error, has no errors")
+	}
+
+	var reqErr, invalidErr bool
+	for _, diag := range diags {
+		switch diag.Description().Summary {
+		case "Missing required argument":
+			if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` {
+				reqErr = true
+			} else {
+				t.Errorf("Unexpected error %+v", diag.Description())
+			}
+		case "Unsupported argument":
+			if diag.Description().Detail == `An argument named "baz" is not expected here.` {
+				invalidErr = true
+			} else {
+				t.Errorf("Unexpected error %+v", diag.Description())
+			}
+		default:
+			t.Errorf("Unexpected error %+v", diag.Description())
+		}
+	}
+	if !reqErr {
+		t.Errorf("Expected missing required argument error, none received")
+	}
+	if !invalidErr {
+		t.Errorf("Expected unsupported argument error, none received")
+	}
+}
+
+func TestContext2Apply_ProviderMeta_refreshdata_set(t *testing.T) {
+	m := testModule(t, "provider-meta-data-set")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	schema := p.ProviderSchema()
+	schema.ProviderMeta = &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"baz": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	rdsPMs := map[string]cty.Value{}
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		rdsPMs[req.TypeName] = req.ProviderMeta
+		switch req.TypeName {
+		case "test_data_source":
+			log.Printf("[TRACE] test_data_source RDSR returning")
+			return providers.ReadDataSourceResponse{
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id":  cty.StringVal("yo"),
+					"foo": cty.StringVal("bar"),
+				}),
+			}
+		case "test_file":
+			log.Printf("[TRACE] test_file RDSR returning")
+			return providers.ReadDataSourceResponse{
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id":       cty.StringVal("bar"),
+					"rendered": cty.StringVal("baz"),
+					"template": cty.StringVal(""),
+				}),
+			}
+		default:
+			// config drift, oops
+			log.Printf("[TRACE] unknown request TypeName: %q", req.TypeName)
+			return providers.ReadDataSourceResponse{}
+		}
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if !p.ReadDataSourceCalled {
+		t.Fatalf("ReadDataSource not called")
+	}
+
+	expectations := map[string]cty.Value{}
+
+	if pm, ok := rdsPMs["test_file"]; !ok {
+		t.Fatalf("sub-module ReadDataSource not called")
+	} else if pm.IsNull() {
+		t.Fatalf("null ProviderMeta in sub-module ReadDataSource")
+	} else {
+		expectations["quux-submodule"] = pm
+	}
+
+	if pm, ok := rdsPMs["test_data_source"]; !ok {
+		t.Fatalf("root module ReadDataSource not called")
+	} else if pm.IsNull() {
+		t.Fatalf("null ProviderMeta in root module ReadDataSource")
+	} else {
+		expectations["quux"] = pm
+	}
+
+	type metaStruct struct {
+		Baz string `cty:"baz"`
+	}
+
+	for expected, v := range expectations {
+		var meta metaStruct
+		err := gocty.FromCtyValue(v, &meta)
+		if err != nil {
+			t.Fatalf("Error parsing cty value: %s", err)
+		}
+		if meta.Baz != expected {
+			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
+		}
+	}
+}
+
+func TestContext2Apply_ProviderMeta_refreshdata_unset(t *testing.T) {
+	m := testModule(t, "provider-meta-data-unset")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	schema := p.ProviderSchema()
+	schema.ProviderMeta = &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"baz": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	rdsPMs := map[string]cty.Value{}
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		rdsPMs[req.TypeName] = req.ProviderMeta
+		switch req.TypeName {
+		case "test_data_source":
+			return providers.ReadDataSourceResponse{
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id":  cty.StringVal("yo"),
+					"foo": cty.StringVal("bar"),
+				}),
+			}
+		case "test_file":
+			return providers.ReadDataSourceResponse{
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id":       cty.StringVal("bar"),
+					"rendered": cty.StringVal("baz"),
+					"template": cty.StringVal(""),
+				}),
+			}
+		default:
+			// config drift, oops
+			return providers.ReadDataSourceResponse{}
+		}
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	if !p.ReadDataSourceCalled {
+		t.Fatalf("ReadDataSource not called")
+	}
+
+	if pm, ok := rdsPMs["test_file"]; !ok {
+		t.Fatalf("sub-module ReadDataSource not called")
+	} else if !pm.IsNull() {
+		t.Fatalf("non-null ProviderMeta in sub-module ReadDataSource")
+	}
+
+	if pm, ok := rdsPMs["test_data_source"]; !ok {
+		t.Fatalf("root module ReadDataSource not called")
+	} else if !pm.IsNull() {
+		t.Fatalf("non-null ProviderMeta in root module ReadDataSource")
+	}
+}
+
+func TestContext2Apply_ProviderMeta_refreshdata_setNoSchema(t *testing.T) {
+	m := testModule(t, "provider-meta-data-set")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+		State: cty.ObjectVal(map[string]cty.Value{
+			"id":  cty.StringVal("yo"),
+			"foo": cty.StringVal("bar"),
+		}),
+	}
+
+	_, diags := ctx.Refresh(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("refresh supposed to error, has no errors")
+	}
+
+	var rootErr, subErr bool
+	errorSummary := "The resource data.test_%s.foo belongs to a provider that doesn't support provider_meta blocks"
+	for _, diag := range diags {
+		if diag.Description().Summary != "Provider registry.terraform.io/hashicorp/test doesn't support provider_meta" {
+			t.Errorf("Unexpected error: %+v", diag.Description())
+		}
+		switch diag.Description().Detail {
+		case fmt.Sprintf(errorSummary, "data_source"):
+			rootErr = true
+		case fmt.Sprintf(errorSummary, "file"):
+			subErr = true
+		default:
+			t.Errorf("Unexpected error: %s", diag.Description())
+		}
+	}
+	if !rootErr {
+		t.Errorf("Expected unsupported provider_meta block error for root module, none received")
+	}
+	if !subErr {
+		t.Errorf("Expected unsupported provider_meta block error for sub-module, none received")
+	}
+}
+
+func TestContext2Apply_ProviderMeta_refreshdata_setInvalid(t *testing.T) {
+	m := testModule(t, "provider-meta-data-set")
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	schema := p.ProviderSchema()
+	schema.ProviderMeta = &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"quux": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+		State: cty.ObjectVal(map[string]cty.Value{
+			"id":  cty.StringVal("yo"),
+			"foo": cty.StringVal("bar"),
+		}),
+	}
+
+	_, diags := ctx.Refresh(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("refresh supposed to error, has no errors")
+	}
+
+	var reqErr, invalidErr bool
+	for _, diag := range diags {
+		switch diag.Description().Summary {
+		case "Missing required argument":
+			if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` {
+				reqErr = true
+			} else {
+				t.Errorf("Unexpected error %+v", diag.Description())
+			}
+		case "Unsupported argument":
+			if diag.Description().Detail == `An argument named "baz" is not expected here.` {
+				invalidErr = true
+			} else {
+				t.Errorf("Unexpected error %+v", diag.Description())
+			}
+		default:
+			t.Errorf("Unexpected error %+v", diag.Description())
+		}
+	}
+	if !reqErr {
+		t.Errorf("Expected missing required argument error, none received")
+	}
+	if !invalidErr {
+		t.Errorf("Expected unsupported argument error, none received")
+	}
+}
+
+func TestContext2Apply_expandModuleVariables(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod1" {
+  for_each = toset(["a"])
+  source = "./mod"
+}
+
+module "mod2" {
+  source = "./mod"
+  in = module.mod1["a"].out
+}
+`,
+		"mod/main.tf": `
+resource "aws_instance" "foo" {
+  foo = var.in
+}
+
+variable "in" {
+  type = string
+  default = "default"
+}
+
+output "out" {
+  value = aws_instance.foo.id
+}
+`,
+	})
+
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	expected := `<no state>
+module.mod1["a"]:
+  aws_instance.foo:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    foo = default
+    type = aws_instance
+
+  Outputs:
+
+  out = foo
+module.mod2:
+  aws_instance.foo:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    foo = foo
+    type = aws_instance
+
+    Dependencies:
+      module.mod1.aws_instance.foo`
+
+	if state.String() != expected {
+		t.Fatalf("expected:\n%s\ngot:\n%s\n", expected, state)
+	}
+}
+
+func TestContext2Apply_inheritAndStoreCBD(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "aws_instance" "foo" {
+}
+
+resource "aws_instance" "cbd" {
+  foo = aws_instance.foo.id
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+`,
+	})
+
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	foo := state.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo"))
+	if !foo.Current.CreateBeforeDestroy {
+		t.Fatal("aws_instance.foo should also be create_before_destroy")
+	}
+}
+
+func TestContext2Apply_moduleDependsOn(t *testing.T) {
+	m := testModule(t, "apply-module-depends-on")
+
+	p := testProvider("test")
+
+	// each instance being applied should happen in sequential order
+	applied := int64(0)
+
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		cfg := req.Config.AsValueMap()
+		foo := cfg["foo"].AsString()
+		ord := atomic.LoadInt64(&applied)
+
+		resp := providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("data"),
+				"foo": cfg["foo"],
+			}),
+		}
+
+		if foo == "a" && ord < 4 {
+			// due to data source "a"'s module depending on instance 4, this
+			// should not be less than 4
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source a read too early"))
+		}
+		if foo == "b" && ord < 1 {
+			// due to data source "b"'s module depending on instance 1, this
+			// should not be less than 1
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source b read too early"))
+		}
+		return resp
+	}
+	p.PlanResourceChangeFn = testDiffFn
+
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		state := req.PlannedState.AsValueMap()
+		num, _ := state["num"].AsBigFloat().Float64()
+		ord := int64(num)
+		if !atomic.CompareAndSwapInt64(&applied, ord-1, ord) {
+			actual := atomic.LoadInt64(&applied)
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("instance %d was applied after %d", ord, actual))
+		}
+
+		state["id"] = cty.StringVal(fmt.Sprintf("test_%d", ord))
+		state["type"] = cty.StringVal("test_instance")
+		resp.NewState = cty.ObjectVal(state)
+
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.NoOp {
+			t.Fatalf("expected NoOp, got %s for %s", res.Action, res.Addr)
+		}
+	}
+}
+
+func TestContext2Apply_moduleSelfReference(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "test" {
+  source = "./test"
+
+  a = module.test.b
+}
+
+output "c" {
+  value = module.test.c
+}
+`,
+		"test/main.tf": `
+variable "a" {}
+
+resource "test_instance" "test" {
+}
+
+output "b" {
+  value = test_instance.test.id
+}
+
+output "c" {
+  value = var.a
+}`})
+
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	if !state.Empty() {
+		t.Fatal("expected empty state, got:", state)
+	}
+}
+
+func TestContext2Apply_moduleExpandDependsOn(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "child" {
+  count = 1
+  source = "./child"
+
+  depends_on = [test_instance.a, test_instance.b]
+}
+
+resource "test_instance" "a" {
+}
+
+
+resource "test_instance" "b" {
+}
+`,
+		"child/main.tf": `
+resource "test_instance" "foo" {
+}
+
+output "myoutput" {
+  value = "literal string"
+}
+`})
+
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	if !state.Empty() {
+		t.Fatal("expected empty state, got:", state)
+	}
+}
+
+func TestContext2Apply_scaleInCBD(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "ct" {
+  type = number
+}
+
+resource "test_instance" "a" {
+  count = var.ct
+}
+
+resource "test_instance" "b" {
+  require_new = local.removable
+  lifecycle {
+	create_before_destroy = true
+  }
+}
+
+resource "test_instance" "c" {
+  require_new = test_instance.b.id
+  lifecycle {
+	create_before_destroy = true
+  }
+}
+
+output "out" {
+  value = join(".", test_instance.a[*].id)
+}
+
+locals {
+  removable = join(".", test_instance.a[*].id)
+}
+`})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_instance.a[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:              states.ObjectReady,
+			AttrsJSON:           []byte(`{"id":"a0"}`),
+			Dependencies:        []addrs.ConfigResource{},
+			CreateBeforeDestroy: true,
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_instance.a[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:              states.ObjectReady,
+			AttrsJSON:           []byte(`{"id":"a1"}`),
+			Dependencies:        []addrs.ConfigResource{},
+			CreateBeforeDestroy: true,
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_instance.b").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:              states.ObjectReady,
+			AttrsJSON:           []byte(`{"id":"b", "require_new":"old.old"}`),
+			Dependencies:        []addrs.ConfigResource{mustConfigResourceAddr("test_instance.a")},
+			CreateBeforeDestroy: true,
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_instance.c").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"c", "require_new":"b"}`),
+			Dependencies: []addrs.ConfigResource{
+				mustConfigResourceAddr("test_instance.a"),
+				mustConfigResourceAddr("test_instance.b"),
+			},
+			CreateBeforeDestroy: true,
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	p := testProvider("test")
+
+	p.PlanResourceChangeFn = func(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		// this is a destroy plan
+		if r.ProposedNewState.IsNull() {
+			resp.PlannedState = r.ProposedNewState
+			resp.PlannedPrivate = r.PriorPrivate
+			return resp
+		}
+
+		n := r.ProposedNewState.AsValueMap()
+
+		if r.PriorState.IsNull() {
+			n["id"] = cty.UnknownVal(cty.String)
+			resp.PlannedState = cty.ObjectVal(n)
+			return resp
+		}
+
+		p := r.PriorState.AsValueMap()
+
+		priorRN := p["require_new"]
+		newRN := n["require_new"]
+
+		if eq := priorRN.Equals(newRN); !eq.IsKnown() || eq.False() {
+			resp.RequiresReplace = []cty.Path{{cty.GetAttrStep{Name: "require_new"}}}
+			n["id"] = cty.UnknownVal(cty.String)
+		}
+
+		resp.PlannedState = cty.ObjectVal(n)
+		return resp
+	}
+
+	// reduce the count to 1
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"ct": &InputValue{
+				Value:      cty.NumberIntVal(1),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+	{
+		addr := mustResourceInstanceAddr("test_instance.a[0]")
+		change := plan.Changes.ResourceInstance(addr)
+		if change == nil {
+			t.Fatalf("no planned change for %s", addr)
+		}
+		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("test_instance.a[0]"); !want.Equal(got) {
+			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
+		}
+		if got, want := change.Action, plans.NoOp; got != want {
+			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
+		}
+		if got, want := change.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
+		}
+	}
+	{
+		addr := mustResourceInstanceAddr("test_instance.a[1]")
+		change := plan.Changes.ResourceInstance(addr)
+		if change == nil {
+			t.Fatalf("no planned change for %s", addr)
+		}
+		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("test_instance.a[1]"); !want.Equal(got) {
+			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
+		}
+		if got, want := change.Action, plans.Delete; got != want {
+			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
+		}
+		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseCountIndex; got != want {
+			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
+		}
+	}
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		log.Fatal(diags.ErrWithWarnings())
+	}
+
+	// check the output, as those can't cause an error planning the value
+	out := state.RootModule().OutputValues["out"].Value.AsString()
+	if out != "a0" {
+		t.Fatalf(`expected output "a0", got: %q`, out)
+	}
+
+	// reduce the count to 0
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"ct": &InputValue{
+				Value:      cty.NumberIntVal(0),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+	{
+		addr := mustResourceInstanceAddr("test_instance.a[0]")
+		change := plan.Changes.ResourceInstance(addr)
+		if change == nil {
+			t.Fatalf("no planned change for %s", addr)
+		}
+		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("test_instance.a[0]"); !want.Equal(got) {
+			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
+		}
+		if got, want := change.Action, plans.Delete; got != want {
+			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
+		}
+		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseCountIndex; got != want {
+			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
+		}
+	}
+	{
+		addr := mustResourceInstanceAddr("test_instance.a[1]")
+		change := plan.Changes.ResourceInstance(addr)
+		if change != nil {
+			// It was already removed in the previous plan/apply
+			t.Errorf("unexpected planned change for %s", addr)
+		}
+	}
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	// check the output, as those can't cause an error planning the value
+	out = state.RootModule().OutputValues["out"].Value.AsString()
+	if out != "" {
+		t.Fatalf(`expected output "", got: %q`, out)
+	}
+}
+
+// Ensure that we can destroy when a provider references a resource that will
+// also be destroyed
+func TestContext2Apply_destroyProviderReference(t *testing.T) {
+	m, snap := testModuleWithSnapshot(t, "apply-destroy-provisider-refs")
+
+	schemaFn := func(name string) *ProviderSchema {
+		return &ProviderSchema{
+			Provider: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"value": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+			},
+			ResourceTypes: map[string]*configschema.Block{
+				name + "_instance": {
+					Attributes: map[string]*configschema.Attribute{
+						"id": {
+							Type:     cty.String,
+							Computed: true,
+						},
+						"foo": {
+							Type:     cty.String,
+							Optional: true,
+						},
+					},
+				},
+			},
+			DataSources: map[string]*configschema.Block{
+				name + "_data_source": {
+					Attributes: map[string]*configschema.Attribute{
+						"id": {
+							Type:     cty.String,
+							Computed: true,
+						},
+						"output": {
+							Type:     cty.String,
+							Computed: true,
+						},
+					},
+				},
+			},
+		}
+	}
+
+	testP := new(MockProvider)
+	testP.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		return providers.ReadResourceResponse{NewState: req.PriorState}
+	}
+	testP.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schemaFn("test"))
+
+	providerConfig := ""
+	testP.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		value := req.Config.GetAttr("value")
+		if value.IsKnown() && !value.IsNull() {
+			providerConfig = value.AsString()
+		} else {
+			providerConfig = ""
+		}
+		return resp
+	}
+	testP.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		if providerConfig != "valid" {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provider config is %q", providerConfig))
+			return
+		}
+		return testApplyFn(req)
+	}
+	testP.PlanResourceChangeFn = testDiffFn
+
+	nullP := new(MockProvider)
+	nullP.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		return providers.ReadResourceResponse{NewState: req.PriorState}
+	}
+	nullP.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schemaFn("null"))
+
+	nullP.ApplyResourceChangeFn = testApplyFn
+	nullP.PlanResourceChangeFn = testDiffFn
+
+	nullP.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+		State: cty.ObjectVal(map[string]cty.Value{
+			"id":     cty.StringVal("ID"),
+			"output": cty.StringVal("valid"),
+		}),
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(testP),
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(nullP),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	providers := map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("test"): testProviderFuncFixed(testP),
+		addrs.NewDefaultProvider("null"): testProviderFuncFixed(nullP),
+	}
+	ctx = testContext2(t, &ContextOpts{
+		Providers: providers,
+	})
+
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+
+	// We'll marshal and unmarshal the plan here, to ensure that we have
+	// a clean new context as would be created if we separately ran
+	// terraform plan -out=tfplan && terraform apply tfplan
+	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ctxOpts.Providers = providers
+	ctx, diags = NewContext(ctxOpts)
+
+	if diags.HasErrors() {
+		t.Fatalf("failed to create context for plan: %s", diags.Err())
+	}
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("destroy apply errors: %s", diags.Err())
+	}
+}
+
+// Destroying properly requires pruning out all unneeded config nodes to
+// prevent incorrect expansion evaluation.
+func TestContext2Apply_destroyInterModuleExpansion(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+data "test_data_source" "a" {
+  for_each = {
+    one = "thing"
+  }
+}
+
+locals {
+  module_input = {
+    for k, v in data.test_data_source.a : k => v.id
+  }
+}
+
+module "mod1" {
+  source = "./mod"
+  input = local.module_input
+}
+
+module "mod2" {
+  source = "./mod"
+  input = module.mod1.outputs
+}
+
+resource "test_instance" "bar" {
+  for_each = module.mod2.outputs
+}
+
+output "module_output" {
+  value = module.mod2.outputs
+}
+output "test_instances" {
+  value = test_instance.bar
+}
+`,
+		"mod/main.tf": `
+variable "input" {
+}
+
+data "test_data_source" "foo" {
+  for_each = var.input
+}
+
+output "outputs" {
+  value = data.test_data_source.foo
+}
+`})
+
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		return providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(map[string]cty.Value{
+				"id":  cty.StringVal("data_source"),
+				"foo": cty.StringVal("output"),
+			}),
+		}
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	destroy := func() {
+		ctx = testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+			},
+		})
+
+		plan, diags = ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.DestroyMode,
+		})
+		assertNoErrors(t, diags)
+
+		state, diags = ctx.Apply(plan, m)
+		if diags.HasErrors() {
+			t.Fatalf("destroy apply errors: %s", diags.Err())
+		}
+	}
+
+	destroy()
+	// Destroying again from the empty state should not cause any errors either
+	destroy()
+}
+
+func TestContext2Apply_createBeforeDestroyWithModule(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "v" {}
+
+module "mod" {
+    source = "./mod"
+    in = var.v
+}
+
+resource "test_resource" "a" {
+  value = var.v
+  depends_on = [module.mod]
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+`,
+		"mod/main.tf": `
+variable "in" {}
+
+resource "test_resource" "a" {
+  value = var.in
+}
+`})
+
+	p := testProvider("test")
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		// this is a destroy plan
+		if req.ProposedNewState.IsNull() {
+			resp.PlannedState = req.ProposedNewState
+			resp.PlannedPrivate = req.PriorPrivate
+			return resp
+		}
+
+		proposed := req.ProposedNewState.AsValueMap()
+		proposed["id"] = cty.UnknownVal(cty.String)
+
+		resp.PlannedState = cty.ObjectVal(proposed)
+		resp.RequiresReplace = []cty.Path{{cty.GetAttrStep{Name: "value"}}}
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"v": &InputValue{
+				Value: cty.StringVal("A"),
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"v": &InputValue{
+				Value: cty.StringVal("B"),
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+}
+
+func TestContext2Apply_forcedCBD(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "v" {}
+
+resource "test_instance" "a" {
+  require_new = var.v
+}
+
+resource "test_instance" "b" {
+  depends_on = [test_instance.a]
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+`})
+
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"v": &InputValue{
+				Value: cty.StringVal("A"),
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"v": &InputValue{
+				Value: cty.StringVal("B"),
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+}
+
+func TestContext2Apply_removeReferencedResource(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "ct" {
+}
+
+resource "test_resource" "to_remove" {
+  count = var.ct
+}
+
+resource "test_resource" "c" {
+  value = join("", test_resource.to_remove[*].id)
+}
+`})
+
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"ct": &InputValue{
+				Value: cty.NumberIntVal(1),
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"ct": &InputValue{
+				Value: cty.NumberIntVal(0),
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+}
+
+func TestContext2Apply_variableSensitivity(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "sensitive_var" {
+	default = "foo"
+	sensitive = true
+}
+
+variable "sensitive_id" {
+	default = "secret id"
+	sensitive = true
+}
+
+resource "test_resource" "foo" {
+	value   = var.sensitive_var
+
+	network_interface {
+		network_interface_id = var.sensitive_id
+	}
+}`,
+	})
+
+	p := new(MockProvider)
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		return providers.ReadResourceResponse{NewState: req.PriorState}
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{},
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"value": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"network_interface": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"network_interface_id": {Type: cty.String, Optional: true},
+								"device_index":         {Type: cty.Number, Optional: true},
+							},
+						},
+						Nesting: configschema.NestingSet,
+					},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = testDiffFn
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	// Run a second apply with no changes
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+
+	state, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	// Now change the variable value for sensitive_var
+	ctx = testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags = ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"sensitive_id": &InputValue{Value: cty.NilVal},
+			"sensitive_var": &InputValue{
+				Value: cty.StringVal("bar"),
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+}
+
+func TestContext2Apply_variableSensitivityPropagation(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "sensitive_map" {
+	type = map(string)
+	default = {
+		"x" = "foo"
+	}
+	sensitive = true
+}
+
+resource "test_resource" "foo" {
+	value = var.sensitive_map.x
+}
+`,
+	})
+
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatalf("plan errors: %s", diags.Err())
+	}
+
+	verifySensitiveValue := func(pvms []cty.PathValueMarks) {
+		if len(pvms) != 1 {
+			t.Fatalf("expected 1 sensitive path, got %d", len(pvms))
+		}
+		pvm := pvms[0]
+		if gotPath, wantPath := pvm.Path, cty.GetAttrPath("value"); !gotPath.Equals(wantPath) {
+			t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath)
+		}
+		if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) {
+			t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks)
+		}
+	}
+
+	addr := mustResourceInstanceAddr("test_resource.foo")
+	fooChangeSrc := plan.Changes.ResourceInstance(addr)
+	verifySensitiveValue(fooChangeSrc.AfterValMarks)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	fooState := state.ResourceInstance(addr)
+	verifySensitiveValue(fooState.Current.AttrSensitivePaths)
+}
+
+func TestContext2Apply_variableSensitivityProviders(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_resource" "foo" {
+	sensitive_value = "should get marked"
+}
+
+resource "test_resource" "bar" {
+	value  = test_resource.foo.sensitive_value
+	random = test_resource.foo.id # not sensitive
+
+	nesting_single {
+		value           = "abc"
+		sensitive_value = "xyz"
+	}
+}
+
+resource "test_resource" "baz" {
+	value = test_resource.bar.nesting_single.sensitive_value
+}
+`,
+	})
+
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("plan errors: %s", diags.Err())
+	}
+
+	verifySensitiveValue := func(pvms []cty.PathValueMarks) {
+		if len(pvms) != 1 {
+			t.Fatalf("expected 1 sensitive path, got %d", len(pvms))
+		}
+		pvm := pvms[0]
+		if gotPath, wantPath := pvm.Path, cty.GetAttrPath("value"); !gotPath.Equals(wantPath) {
+			t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath)
+		}
+		if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) {
+			t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks)
+		}
+	}
+
+	// Sensitive attributes (defined by the provider) are marked
+	// as sensitive when referenced from another resource
+	// "bar" references sensitive resources in "foo"
+	barAddr := mustResourceInstanceAddr("test_resource.bar")
+	barChangeSrc := plan.Changes.ResourceInstance(barAddr)
+	verifySensitiveValue(barChangeSrc.AfterValMarks)
+
+	bazAddr := mustResourceInstanceAddr("test_resource.baz")
+	bazChangeSrc := plan.Changes.ResourceInstance(bazAddr)
+	verifySensitiveValue(bazChangeSrc.AfterValMarks)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	barState := state.ResourceInstance(barAddr)
+	verifySensitiveValue(barState.Current.AttrSensitivePaths)
+
+	bazState := state.ResourceInstance(bazAddr)
+	verifySensitiveValue(bazState.Current.AttrSensitivePaths)
+}
+
+func TestContext2Apply_variableSensitivityChange(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "sensitive_var" {
+	default = "hello"
+	sensitive = true
+}
+
+resource "test_resource" "foo" {
+	value = var.sensitive_var
+}`,
+	})
+
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_resource",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectReady,
+				AttrsJSON: []byte(`{"id":"foo", "value":"hello"}`),
+				// No AttrSensitivePaths present
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+
+	addr := mustResourceInstanceAddr("test_resource.foo")
+
+	state, diags = ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	fooState := state.ResourceInstance(addr)
+
+	if len(fooState.Current.AttrSensitivePaths) != 1 {
+		t.Fatalf("wrong number of sensitive paths, expected 1, got, %v", len(fooState.Current.AttrSensitivePaths))
+	}
+	got := fooState.Current.AttrSensitivePaths[0]
+	want := cty.PathValueMarks{
+		Path:  cty.GetAttrPath("value"),
+		Marks: cty.NewValueMarks(marks.Sensitive),
+	}
+
+	if !got.Equal(want) {
+		t.Fatalf("wrong value marks; got:\n%#v\n\nwant:\n%#v\n", got, want)
+	}
+
+	m2 := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "sensitive_var" {
+	default = "hello"
+	sensitive = false
+}
+
+resource "test_resource" "foo" {
+	value = var.sensitive_var
+}`,
+	})
+
+	ctx2 := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	// NOTE: Prior to our refactoring to make the state an explicit argument
+	// of Plan, as opposed to hidden state inside Context, this test was
+	// calling ctx.Apply instead of ctx2.Apply and thus using the previous
+	// plan instead of this new plan. "Fixing" it to use the new plan seems
+	// to break the test, so we've preserved that oddity here by saving the
+	// old plan as oldPlan and essentially discarding the new plan entirely,
+	// but this seems rather suspicious and we should ideally figure out what
+	// this test was originally intending to do and make it do that.
+	oldPlan := plan
+	_, diags = ctx2.Plan(m2, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+	stateWithoutSensitive, diags := ctx.Apply(oldPlan, m)
+	assertNoErrors(t, diags)
+
+	fooState2 := stateWithoutSensitive.ResourceInstance(addr)
+	if len(fooState2.Current.AttrSensitivePaths) > 0 {
+		t.Fatalf(
+			"wrong number of sensitive paths, expected 0, got, %v\n%s",
+			len(fooState2.Current.AttrSensitivePaths),
+			spew.Sdump(fooState2.Current.AttrSensitivePaths),
+		)
+	}
+}
+
+func TestContext2Apply_moduleVariableOptionalAttributes(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "in" {
+  type = object({
+    required = string
+    optional = optional(string)
+    default  = optional(bool, true)
+    nested   = optional(
+      map(object({
+        a = optional(string, "foo")
+        b = optional(number, 5)
+      })), {
+        "boop": {}
+      }
+    )
+  })
+}
+
+output "out" {
+  value = var.in
+}
+`})
+
+	ctx := testContext2(t, &ContextOpts{})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"in": &InputValue{
+				Value: cty.MapVal(map[string]cty.Value{
+					"required": cty.StringVal("boop"),
+				}),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	got := state.RootModule().OutputValues["out"].Value
+	want := cty.ObjectVal(map[string]cty.Value{
+		"required": cty.StringVal("boop"),
+
+		// Because "optional" was marked as optional, it got silently filled
+		// in as a null value of string type rather than returning an error.
+		"optional": cty.NullVal(cty.String),
+
+		// Similarly, "default" was marked as optional with a default value,
+		// and since it was omitted should be filled in with that default.
+		"default": cty.True,
+
+		// Nested is a complex structure which has fully described defaults,
+		// so again it should be filled with the default structure.
+		"nested": cty.MapVal(map[string]cty.Value{
+			"boop": cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("foo"),
+				"b": cty.NumberIntVal(5),
+			}),
+		}),
+	})
+	if !want.RawEquals(got) {
+		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestContext2Apply_moduleVariableOptionalAttributesDefault(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "in" {
+  type    = object({
+    required = string
+    optional = optional(string)
+    default  = optional(bool, true)
+  })
+  default = {
+    required = "boop"
+  }
+}
+
+output "out" {
+  value = var.in
+}
+`})
+
+	ctx := testContext2(t, &ContextOpts{})
+
+	// We don't specify a value for the variable here, relying on its defined
+	// default.
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	got := state.RootModule().OutputValues["out"].Value
+	want := cty.ObjectVal(map[string]cty.Value{
+		"required": cty.StringVal("boop"),
+
+		// "optional" is not present in the variable default, so it is filled
+		// with null.
+		"optional": cty.NullVal(cty.String),
+
+		// Similarly, "default" is not present in the variable default, so its
+		// value is replaced with the type's specified default.
+		"default": cty.True,
+	})
+	if !want.RawEquals(got) {
+		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestContext2Apply_moduleVariableOptionalAttributesDefaultNull(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "in" {
+  type    = object({
+    required = string
+    optional = optional(string)
+    default  = optional(bool, true)
+  })
+  default = null
+}
+
+# Wrap the input variable in a tuple because a null output value is elided from
+# the plan, which prevents us from testing its type.
+output "out" {
+  value = [var.in]
+}
+`})
+
+	ctx := testContext2(t, &ContextOpts{})
+
+	// We don't specify a value for the variable here, relying on its defined
+	// default.
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	got := state.RootModule().OutputValues["out"].Value
+	// The null default value should be bound, after type converting to the
+	// full object type
+	want := cty.TupleVal([]cty.Value{cty.NullVal(cty.Object(map[string]cty.Type{
+		"required": cty.String,
+		"optional": cty.String,
+		"default":  cty.Bool,
+	}))})
+	if !want.RawEquals(got) {
+		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestContext2Apply_moduleVariableOptionalAttributesDefaultChild(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "in" {
+  type    = list(object({
+    a = optional(set(string))
+  }))
+  default = [
+	{ a = [ "foo" ] },
+	{ },
+  ]
+}
+
+module "child" {
+  source = "./child"
+  in     = var.in
+}
+
+output "out" {
+  value = module.child.out
+}
+`,
+		"child/main.tf": `
+variable "in" {
+  type    = list(object({
+    a = optional(set(string), [])
+  }))
+  default = []
+}
+
+output "out" {
+  value = var.in
+}
+`,
+	})
+
+	ctx := testContext2(t, &ContextOpts{})
+
+	// We don't specify a value for the variable here, relying on its defined
+	// default.
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	got := state.RootModule().OutputValues["out"].Value
+	want := cty.ListVal([]cty.Value{
+		cty.ObjectVal(map[string]cty.Value{
+			"a": cty.SetVal([]cty.Value{cty.StringVal("foo")}),
+		}),
+		cty.ObjectVal(map[string]cty.Value{
+			"a": cty.SetValEmpty(cty.String),
+		}),
+	})
+	if !want.RawEquals(got) {
+		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestContext2Apply_provisionerSensitive(t *testing.T) {
+	m := testModule(t, "apply-provisioner-sensitive")
+	p := testProvider("aws")
+
+	pr := testProvisioner()
+	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
+		if req.Config.ContainsMarked() {
+			t.Fatalf("unexpectedly marked config value: %#v", req.Config)
+		}
+		command := req.Config.GetAttr("command")
+		if command.IsMarked() {
+			t.Fatalf("unexpectedly marked command argument: %#v", command.Marks())
+		}
+		req.UIOutput.Output(fmt.Sprintf("Executing: %q", command.AsString()))
+		return
+	}
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = testApplyFn
+
+	h := new(MockHook)
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"password": &InputValue{
+				Value:      cty.StringVal("secret"),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	// "restart" provisioner
+	pr.CloseCalled = false
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		logDiagnostics(t, diags)
+		t.Fatal("apply failed")
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testTerraformApplyProvisionerSensitiveStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+
+	// Verify apply was invoked
+	if !pr.ProvisionResourceCalled {
+		t.Fatalf("provisioner was not called on apply")
+	}
+
+	// Verify output was suppressed
+	if !h.ProvisionOutputCalled {
+		t.Fatalf("ProvisionOutput hook not called")
+	}
+	if got, doNotWant := h.ProvisionOutputMessage, "secret"; strings.Contains(got, doNotWant) {
+		t.Errorf("sensitive value %q included in output:\n%s", doNotWant, got)
+	}
+	if got, want := h.ProvisionOutputMessage, "output suppressed"; !strings.Contains(got, want) {
+		t.Errorf("expected hook to be called with %q, but was:\n%s", want, got)
+	}
+}
+
+func TestContext2Apply_warnings(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_resource" "foo" {
+}`,
+	})
+
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
+		resp := testApplyFn(req)
+
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("warning"))
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	state, diags := ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	}
+
+	inst := state.ResourceInstance(mustResourceInstanceAddr("test_resource.foo"))
+	if inst == nil {
+		t.Fatal("missing 'test_resource.foo' in state:", state)
+	}
+}
+
+func TestContext2Apply_rpcDiagnostics(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_instance" "a" {
+}
+`,
+	})
+
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		resp = testApplyFn(req)
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("don't frobble"))
+		return resp
+	}
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	_, diags = ctx.Apply(plan, m)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	if len(diags) == 0 {
+		t.Fatal("expected warnings")
+	}
+
+	for _, d := range diags {
+		des := d.Description().Summary
+		if !strings.Contains(des, "frobble") {
+			t.Fatalf(`expected frobble, got %q`, des)
+		}
+	}
+}
+
+func TestContext2Apply_dataSensitive(t *testing.T) {
+	m := testModule(t, "apply-data-sensitive")
+	p := testProvider("null")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		// add the required id
+		m := req.Config.AsValueMap()
+		m["id"] = cty.StringVal("foo")
+
+		return providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(m),
+		}
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatalf("diags: %s", diags.Err())
+	} else {
+		t.Logf(legacyDiffComparisonString(plan.Changes))
+	}
+
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	addr := mustResourceInstanceAddr("data.null_data_source.testing")
+
+	dataSourceState := state.ResourceInstance(addr)
+	pvms := dataSourceState.Current.AttrSensitivePaths
+	if len(pvms) != 1 {
+		t.Fatalf("expected 1 sensitive path, got %d", len(pvms))
+	}
+	pvm := pvms[0]
+	if gotPath, wantPath := pvm.Path, cty.GetAttrPath("foo"); !gotPath.Equals(wantPath) {
+		t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath)
+	}
+	if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) {
+		t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks)
+	}
+}
+
+func TestContext2Apply_errorRestorePrivateData(t *testing.T) {
+	// empty config to remove our resource
+	m := testModuleInline(t, map[string]string{
+		"main.tf": "",
+	})
+
+	p := simpleMockProvider()
+	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{
+		// we error during apply, which will trigger core to preserve the last
+		// known state, including private data
+		Diagnostics: tfdiags.Diagnostics(nil).Append(errors.New("oops")),
+	}
+
+	addr := mustResourceInstanceAddr("test_object.a")
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+			Private:   []byte("private"),
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	state, _ = ctx.Apply(plan, m)
+	if string(state.ResourceInstance(addr).Current.Private) != "private" {
+		t.Fatal("missing private data in state")
+	}
+}
+
+func TestContext2Apply_errorRestoreStatus(t *testing.T) {
+	// empty config to remove our resource
+	m := testModuleInline(t, map[string]string{
+		"main.tf": "",
+	})
+
+	p := simpleMockProvider()
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		// We error during apply, but return the current object state.
+		resp.Diagnostics = resp.Diagnostics.Append(errors.New("oops"))
+		// return a warning too to make sure it isn't dropped
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("warned"))
+		resp.NewState = req.PriorState
+		resp.Private = req.PlannedPrivate
+		return resp
+	}
+
+	addr := mustResourceInstanceAddr("test_object.a")
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectTainted,
+			AttrsJSON:    []byte(`{"test_string":"foo"}`),
+			Private:      []byte("private"),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.b")},
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	state, diags = ctx.Apply(plan, m)
+
+	errString := diags.ErrWithWarnings().Error()
+	if !strings.Contains(errString, "oops") || !strings.Contains(errString, "warned") {
+		t.Fatalf("error missing expected info: %q", errString)
+	}
+
+	if len(diags) != 2 {
+		t.Fatalf("expected 1 error and 1 warning, got: %q", errString)
+	}
+
+	res := state.ResourceInstance(addr)
+	if res == nil {
+		t.Fatal("resource was removed from state")
+	}
+
+	if res.Current.Status != states.ObjectTainted {
+		t.Fatal("resource should still be tainted in the state")
+	}
+
+	if len(res.Current.Dependencies) != 1 || !res.Current.Dependencies[0].Equal(mustConfigResourceAddr("test_object.b")) {
+		t.Fatalf("incorrect dependencies, got %q", res.Current.Dependencies)
+	}
+
+	if string(res.Current.Private) != "private" {
+		t.Fatalf("incorrect private data, got %q", res.Current.Private)
+	}
+}
+
+func TestContext2Apply_nonConformingResponse(t *testing.T) {
+	// empty config to remove our resource
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+  test_string = "x"
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	respDiags := tfdiags.Diagnostics(nil).Append(tfdiags.SimpleWarning("warned"))
+	respDiags = respDiags.Append(errors.New("oops"))
+	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{
+		// Don't lose these diagnostics
+		Diagnostics: respDiags,
+		// This state is missing required attributes, and should produce an error
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"test_string": cty.StringVal("x"),
+		}),
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	_, diags = ctx.Apply(plan, m)
+	errString := diags.ErrWithWarnings().Error()
+	if !strings.Contains(errString, "oops") || !strings.Contains(errString, "warned") {
+		t.Fatalf("error missing expected info: %q", errString)
+	}
+
+	// we should have more than the ones returned from the provider, and they
+	// should not be coalesced into a single value
+	if len(diags) < 3 {
+		t.Fatalf("incorrect diagnostics, got %d values with %s", len(diags), diags.ErrWithWarnings())
+	}
+}
+
+func TestContext2Apply_nilResponse(t *testing.T) {
+	// empty config to remove our resource
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	_, diags = ctx.Apply(plan, m)
+	if !diags.HasErrors() {
+		t.Fatal("expected and error")
+	}
+
+	errString := diags.ErrWithWarnings().Error()
+	if !strings.Contains(errString, "invalid nil value") {
+		t.Fatalf("error missing expected info: %q", errString)
+	}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NOTE: Due to the size of this file, new tests should be added to
+// context_apply2_test.go.
+////////////////////////////////////////////////////////////////////////////////
diff --git a/v1.5.7/internal/terraform/context_eval.go b/v1.5.7/internal/terraform/context_eval.go
new file mode 100644
index 0000000..2b42c32
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_eval.go
@@ -0,0 +1,99 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+type EvalOpts struct {
+	SetVariables InputValues
+}
+
+// Eval produces a scope in which expressions can be evaluated for
+// the given module path.
+//
+// This method must first evaluate any ephemeral values (input variables, local
+// values, and output values) in the configuration. These ephemeral values are
+// not included in the persisted state, so they must be re-computed using other
+// values in the state before they can be properly evaluated. The updated
+// values are retained in the main state associated with the receiving context.
+//
+// This function takes no action against remote APIs but it does need access
+// to all provider and provisioner instances in order to obtain their schemas
+// for type checking.
+//
+// The result is an evaluation scope that can be used to resolve references
+// against the root module. If the returned diagnostics contains errors then
+// the returned scope may be nil. If it is not nil then it may still be used
+// to attempt expression evaluation or other analysis, but some expressions
+// may not behave as expected.
+func (c *Context) Eval(config *configs.Config, state *states.State, moduleAddr addrs.ModuleInstance, opts *EvalOpts) (*lang.Scope, tfdiags.Diagnostics) {
+	// This is intended for external callers such as the "terraform console"
+	// command. Internally, we create an evaluator in c.walk before walking
+	// the graph, and create scopes in ContextGraphWalker.
+
+	var diags tfdiags.Diagnostics
+	defer c.acquireRun("eval")()
+
+	// Start with a copy of state so that we don't affect the instance that
+	// the caller is holding.
+	state = state.DeepCopy()
+	var walker *ContextGraphWalker
+
+	variables := opts.SetVariables
+
+	// By the time we get here, we should have values defined for all of
+	// the root module variables, even if some of them are "unknown". It's the
+	// caller's responsibility to have already handled the decoding of these
+	// from the various ways the CLI allows them to be set and to produce
+	// user-friendly error messages if they are not all present, and so
+	// the error message from checkInputVariables should never be seen and
+	// includes language asking the user to report a bug.
+	varDiags := checkInputVariables(config.Module.Variables, variables)
+	diags = diags.Append(varDiags)
+
+	log.Printf("[DEBUG] Building and walking 'eval' graph")
+
+	graph, moreDiags := (&EvalGraphBuilder{
+		Config:             config,
+		State:              state,
+		RootVariableValues: variables,
+		Plugins:            c.plugins,
+	}).Build(addrs.RootModuleInstance)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		return nil, diags
+	}
+
+	walkOpts := &graphWalkOpts{
+		InputState: state,
+		Config:     config,
+	}
+
+	walker, moreDiags = c.walk(graph, walkEval, walkOpts)
+	diags = diags.Append(moreDiags)
+	if walker != nil {
+		diags = diags.Append(walker.NonFatalDiagnostics)
+	} else {
+		// If we skipped walking the graph (due to errors) then we'll just
+		// use a placeholder graph walker here, which'll refer to the
+		// unmodified state.
+		walker = c.graphWalker(walkEval, walkOpts)
+	}
+
+	// This is a bit weird since we don't normally evaluate outside of
+	// the context of a walk, but we'll "re-enter" our desired path here
+	// just to get hold of an EvalContext for it. ContextGraphWalker
+	// caches its contexts, so we should get hold of the context that was
+	// previously used for evaluation here, unless we skipped walking.
+	evalCtx := walker.EnterPath(moduleAddr)
+	return evalCtx.EvaluationScope(nil, nil, EvalDataForNoInstanceKey), diags
+}
diff --git a/v1.5.7/internal/terraform/context_eval_test.go b/v1.5.7/internal/terraform/context_eval_test.go
new file mode 100644
index 0000000..ed72a4f
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_eval_test.go
@@ -0,0 +1,133 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestContextEval(t *testing.T) {
+	// This test doesn't check the "Want" value for impure funcs, so the value
+	// on those doesn't matter.
+	tests := []struct {
+		Input      string
+		Want       cty.Value
+		ImpureFunc bool
+	}{
+		{ // An impure function: allowed in the console, but the result is nondeterministic
+			`bcrypt("example")`,
+			cty.NilVal,
+			true,
+		},
+		{
+			`keys(var.map)`,
+			cty.ListVal([]cty.Value{
+				cty.StringVal("foo"),
+				cty.StringVal("baz"),
+			}),
+			true,
+		},
+		{
+			`local.result`,
+			cty.NumberIntVal(6),
+			false,
+		},
+		{
+			`module.child.result`,
+			cty.NumberIntVal(6),
+			false,
+		},
+	}
+
+	// This module has a little bit of everything (and if it is missing somehitng, add to it):
+	// resources, variables, locals, modules, output
+	m := testModule(t, "eval-context-basic")
+	p := testProvider("test")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	scope, diags := ctx.Eval(m, states.NewState(), addrs.RootModuleInstance, &EvalOpts{
+		SetVariables: testInputValuesUnset(m.Module.Variables),
+	})
+	if diags.HasErrors() {
+		t.Fatalf("Eval errors: %s", diags.Err())
+	}
+
+	// Since we're testing 'eval' (used by terraform console), impure functions
+	// should be allowed by the scope.
+	if scope.PureOnly == true {
+		t.Fatal("wrong result: eval should allow impure funcs")
+	}
+
+	for _, test := range tests {
+		t.Run(test.Input, func(t *testing.T) {
+			// Parse the test input as an expression
+			expr, _ := hclsyntax.ParseExpression([]byte(test.Input), "<test-input>", hcl.Pos{Line: 1, Column: 1})
+			got, diags := scope.EvalExpr(expr, cty.DynamicPseudoType)
+
+			if diags.HasErrors() {
+				t.Fatalf("unexpected error: %s", diags.Err())
+			}
+
+			if !test.ImpureFunc {
+				if !got.RawEquals(test.Want) {
+					t.Fatalf("wrong result: want %#v, got %#v", test.Want, got)
+				}
+			}
+		})
+	}
+}
+
+// ensure that we can execute a console when outputs have preconditions
+func TestContextEval_outputsWithPreconditions(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod" {
+  source = "./mod"
+  input  = "ok"
+}
+
+output "out" {
+  value = module.mod.out
+}
+`,
+
+		"./mod/main.tf": `
+variable "input" {
+  type = string
+}
+
+output "out" {
+  value = var.input
+
+  precondition {
+    condition     = var.input != ""
+    error_message = "error"
+  }
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Eval(m, states.NewState(), addrs.RootModuleInstance, &EvalOpts{
+		SetVariables: testInputValuesUnset(m.Module.Variables),
+	})
+	assertNoErrors(t, diags)
+}
diff --git a/v1.5.7/internal/terraform/context_fixtures_test.go b/v1.5.7/internal/terraform/context_fixtures_test.go
new file mode 100644
index 0000000..f173f84
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_fixtures_test.go
@@ -0,0 +1,88 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// contextTestFixture is a container for a set of objects that work together
+// to create a base testing scenario. This is used to represent some common
+// situations used as the basis for multiple tests.
+type contextTestFixture struct {
+	Config       *configs.Config
+	Providers    map[addrs.Provider]providers.Factory
+	Provisioners map[string]provisioners.Factory
+}
+
+// ContextOpts returns a ContextOps pre-populated with the elements of this
+// fixture. Each call returns a distinct object, so callers can apply further
+// _shallow_ modifications to the options as needed.
+func (f *contextTestFixture) ContextOpts() *ContextOpts {
+	return &ContextOpts{
+		Providers:    f.Providers,
+		Provisioners: f.Provisioners,
+	}
+}
+
+// contextFixtureApplyVars builds and returns a test fixture for testing
+// input variables, primarily during the apply phase. The configuration is
+// loaded from testdata/apply-vars, and the provider resolver is
+// configured with a resource type schema for aws_instance that matches
+// what's used in that configuration.
+func contextFixtureApplyVars(t *testing.T) *contextTestFixture {
+	c := testModule(t, "apply-vars")
+	p := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"id":   {Type: cty.String, Computed: true},
+			"foo":  {Type: cty.String, Optional: true},
+			"bar":  {Type: cty.String, Optional: true},
+			"baz":  {Type: cty.String, Optional: true},
+			"num":  {Type: cty.Number, Optional: true},
+			"list": {Type: cty.List(cty.String), Optional: true},
+			"map":  {Type: cty.Map(cty.String), Optional: true},
+		},
+	})
+	p.ApplyResourceChangeFn = testApplyFn
+	p.PlanResourceChangeFn = testDiffFn
+	return &contextTestFixture{
+		Config: c,
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	}
+}
+
+// contextFixtureApplyVarsEnv builds and returns a test fixture for testing
+// input variables set from the environment. The configuration is
+// loaded from testdata/apply-vars-env, and the provider resolver is
+// configured with a resource type schema for aws_instance that matches
+// what's used in that configuration.
+func contextFixtureApplyVarsEnv(t *testing.T) *contextTestFixture {
+	c := testModule(t, "apply-vars-env")
+	p := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"string": {Type: cty.String, Optional: true},
+			"list":   {Type: cty.List(cty.String), Optional: true},
+			"map":    {Type: cty.Map(cty.String), Optional: true},
+			"id":     {Type: cty.String, Computed: true},
+			"type":   {Type: cty.String, Computed: true},
+		},
+	})
+	p.ApplyResourceChangeFn = testApplyFn
+	p.PlanResourceChangeFn = testDiffFn
+	return &contextTestFixture{
+		Config: c,
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	}
+}
diff --git a/v1.5.7/internal/terraform/context_import.go b/v1.5.7/internal/terraform/context_import.go
new file mode 100644
index 0000000..2b63873
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_import.go
@@ -0,0 +1,96 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ImportOpts are used as the configuration for Import.
+type ImportOpts struct {
+	// Targets are the targets to import
+	Targets []*ImportTarget
+
+	// SetVariables are the variables set outside of the configuration,
+	// such as on the command line, in variables files, etc.
+	SetVariables InputValues
+}
+
+// ImportTarget is a single resource to import.
+type ImportTarget struct {
+	// Config is the original import block for this import. This might be null
+	// if the import did not originate in config.
+	Config *configs.Import
+
+	// Addr is the address for the resource instance that the new object should
+	// be imported into.
+	Addr addrs.AbsResourceInstance
+
+	// ID is the ID of the resource to import. This is resource-specific.
+	ID string
+}
+
+// Import takes already-created external resources and brings them
+// under Terraform management. Import requires the exact type, name, and ID
+// of the resources to import.
+//
+// This operation is idempotent. If the requested resource is already
+// imported, no changes are made to the state.
+//
+// Further, this operation also gracefully handles partial state. If during
+// an import there is a failure, all previously imported resources remain
+// imported.
+func (c *Context) Import(config *configs.Config, prevRunState *states.State, opts *ImportOpts) (*states.State, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// Hold a lock since we can modify our own state here
+	defer c.acquireRun("import")()
+
+	// Don't modify our caller's state
+	state := prevRunState.DeepCopy()
+
+	log.Printf("[DEBUG] Building and walking import graph")
+
+	variables := opts.SetVariables
+
+	// Initialize our graph builder
+	builder := &PlanGraphBuilder{
+		ImportTargets:      opts.Targets,
+		Config:             config,
+		State:              state,
+		RootVariableValues: variables,
+		Plugins:            c.plugins,
+		Operation:          walkImport,
+	}
+
+	// Build the graph
+	graph, graphDiags := builder.Build(addrs.RootModuleInstance)
+	diags = diags.Append(graphDiags)
+	if graphDiags.HasErrors() {
+		return state, diags
+	}
+
+	// Walk it
+	walker, walkDiags := c.walk(graph, walkImport, &graphWalkOpts{
+		Config:     config,
+		InputState: state,
+	})
+	diags = diags.Append(walkDiags)
+	if walkDiags.HasErrors() {
+		return state, diags
+	}
+
+	// Data sources which could not be read during the import plan will be
+	// unknown. We need to strip those objects out so that the state can be
+	// serialized.
+	walker.State.RemovePlannedResourceInstanceObjects()
+
+	newState := walker.State.Close()
+	return newState, diags
+}
diff --git a/v1.5.7/internal/terraform/context_import_test.go b/v1.5.7/internal/terraform/context_import_test.go
new file mode 100644
index 0000000..b526ede
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_import_test.go
@@ -0,0 +1,1097 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"errors"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestContextImport_basic(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "import-provider")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "aws_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.ResourceInstance(
+					addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
+				),
+				ID: "bar",
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testImportStr)
+	if actual != expected {
+		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", actual, expected)
+	}
+}
+
+// import 1 of count instances in the configuration
+func TestContextImport_countIndex(t *testing.T) {
+	p := testProvider("aws")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+provider "aws" {
+  foo = "bar"
+}
+
+resource "aws_instance" "foo" {
+  count = 2
+}
+`})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "aws_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.ResourceInstance(
+					addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(0),
+				),
+				ID: "bar",
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testImportCountIndexStr)
+	if actual != expected {
+		t.Fatalf("bad: \n%s", actual)
+	}
+}
+
+func TestContextImport_collision(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "import-provider")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsFlat: map[string]string{
+					"id": "bar",
+				},
+				Status: states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "aws_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	state, diags := ctx.Import(m, state, &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.ResourceInstance(
+					addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
+				),
+				ID: "bar",
+			},
+		},
+	})
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want an error indicating that the resource already exists in state")
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := `aws_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]`
+
+	if actual != expected {
+		t.Fatalf("bad: \n%s", actual)
+	}
+}
+
+func TestContextImport_missingType(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "import-provider")
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.ResourceInstance(
+					addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
+				),
+				ID: "bar",
+			},
+		},
+	})
+	if !diags.HasErrors() {
+		t.Fatal("should error")
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := "<no state>"
+	if actual != expected {
+		t.Fatalf("bad: \n%s", actual)
+	}
+}
+
+func TestContextImport_moduleProvider(t *testing.T) {
+	p := testProvider("aws")
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "aws_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		foo := req.Config.GetAttr("foo").AsString()
+		if foo != "bar" {
+			resp.Diagnostics = resp.Diagnostics.Append(errors.New("not bar"))
+		}
+
+		return
+	}
+
+	m := testModule(t, "import-provider")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.ResourceInstance(
+					addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
+				),
+				ID: "bar",
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if !p.ConfigureProviderCalled {
+		t.Fatal("didn't configure provider")
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testImportStr)
+	if actual != expected {
+		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
+	}
+}
+
+// Importing into a module requires a provider config in that module.
+func TestContextImport_providerModule(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "import-module")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "aws_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		foo := req.Config.GetAttr("foo").AsString()
+		if foo != "bar" {
+			resp.Diagnostics = resp.Diagnostics.Append(errors.New("not bar"))
+		}
+
+		return
+	}
+
+	_, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.Child("child", addrs.NoKey).ResourceInstance(
+					addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
+				),
+				ID: "bar",
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if !p.ConfigureProviderCalled {
+		t.Fatal("didn't configure provider")
+	}
+}
+
+// Test that import will interpolate provider configuration and use
+// that configuration for import.
+func TestContextImport_providerConfig(t *testing.T) {
+	testCases := map[string]struct {
+		module string
+		value  string
+	}{
+		"variables": {
+			module: "import-provider-vars",
+			value:  "bar",
+		},
+		"locals": {
+			module: "import-provider-locals",
+			value:  "baz-bar",
+		},
+	}
+	for name, test := range testCases {
+		t.Run(name, func(t *testing.T) {
+			p := testProvider("aws")
+			m := testModule(t, test.module)
+			ctx := testContext2(t, &ContextOpts{
+				Providers: map[addrs.Provider]providers.Factory{
+					addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+				},
+			})
+
+			p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+				ImportedResources: []providers.ImportedResource{
+					{
+						TypeName: "aws_instance",
+						State: cty.ObjectVal(map[string]cty.Value{
+							"id": cty.StringVal("foo"),
+						}),
+					},
+				},
+			}
+
+			state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+				Targets: []*ImportTarget{
+					{
+						Addr: addrs.RootModuleInstance.ResourceInstance(
+							addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
+						),
+						ID: "bar",
+					},
+				},
+				SetVariables: InputValues{
+					"foo": &InputValue{
+						Value:      cty.StringVal("bar"),
+						SourceType: ValueFromCaller,
+					},
+				},
+			})
+			if diags.HasErrors() {
+				t.Fatalf("unexpected errors: %s", diags.Err())
+			}
+
+			if !p.ConfigureProviderCalled {
+				t.Fatal("didn't configure provider")
+			}
+
+			if foo := p.ConfigureProviderRequest.Config.GetAttr("foo").AsString(); foo != test.value {
+				t.Fatalf("bad value %#v; want %#v", foo, test.value)
+			}
+
+			actual := strings.TrimSpace(state.String())
+			expected := strings.TrimSpace(testImportStr)
+			if actual != expected {
+				t.Fatalf("bad: \n%s", actual)
+			}
+		})
+	}
+}
+
+// Test that provider configs can't reference resources.
+func TestContextImport_providerConfigResources(t *testing.T) {
+	p := testProvider("aws")
+	pTest := testProvider("test")
+	m := testModule(t, "import-provider-resources")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"):  testProviderFuncFixed(p),
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest),
+		},
+	})
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "aws_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	_, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.ResourceInstance(
+					addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
+				),
+				ID: "bar",
+			},
+		},
+	})
+	if !diags.HasErrors() {
+		t.Fatal("should error")
+	}
+	if got, want := diags.Err().Error(), `The configuration for provider["registry.terraform.io/hashicorp/aws"] depends on values that cannot be determined until apply.`; !strings.Contains(got, want) {
+		t.Errorf("wrong error\n got: %s\nwant: %s", got, want)
+	}
+}
+
+func TestContextImport_refresh(t *testing.T) {
+	p := testProvider("aws")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+provider "aws" {
+  foo = "bar"
+}
+
+resource "aws_instance" "foo" {
+}
+
+
+// we are only importing aws_instance.foo, so these resources will be unknown
+resource "aws_instance" "bar" {
+}
+data "aws_data_source" "bar" {
+  foo = aws_instance.bar.id
+}
+`})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "aws_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+		State: cty.ObjectVal(map[string]cty.Value{
+			"id":  cty.StringVal("id"),
+			"foo": cty.UnknownVal(cty.String),
+		}),
+	}
+
+	p.ReadResourceFn = nil
+
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"id":  cty.StringVal("foo"),
+			"foo": cty.StringVal("bar"),
+		}),
+	}
+
+	state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.ResourceInstance(
+					addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
+				),
+				ID: "bar",
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if d := state.ResourceInstance(mustResourceInstanceAddr("data.aws_data_source.bar")); d != nil {
+		t.Errorf("data.aws_data_source.bar has a status of ObjectPlanned and should not be in the state\ngot:%#v\n", d.Current)
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testImportRefreshStr)
+	if actual != expected {
+		t.Fatalf("bad: \n%s", actual)
+	}
+}
+
+func TestContextImport_refreshNil(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "import-provider")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "aws_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		return providers.ReadResourceResponse{
+			NewState: cty.NullVal(cty.DynamicPseudoType),
+		}
+	}
+
+	state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.ResourceInstance(
+					addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
+				),
+				ID: "bar",
+			},
+		},
+	})
+	if !diags.HasErrors() {
+		t.Fatal("should error")
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := "<no state>"
+	if actual != expected {
+		t.Fatalf("bad: \n%s", actual)
+	}
+}
+
+func TestContextImport_module(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "import-module")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "aws_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.Child("child", addrs.IntKey(0)).ResourceInstance(
+					addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
+				),
+				ID: "bar",
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testImportModuleStr)
+	if actual != expected {
+		t.Fatalf("bad: \n%s", actual)
+	}
+}
+
+func TestContextImport_moduleDepth2(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "import-module")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "aws_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.Child("child", addrs.IntKey(0)).Child("nested", addrs.NoKey).ResourceInstance(
+					addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
+				),
+				ID: "baz",
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testImportModuleDepth2Str)
+	if actual != expected {
+		t.Fatalf("bad: \n%s", actual)
+	}
+}
+
+func TestContextImport_moduleDiff(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "import-module")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "aws_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.Child("child", addrs.IntKey(0)).ResourceInstance(
+					addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
+				),
+				ID: "baz",
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testImportModuleStr)
+	if actual != expected {
+		t.Fatalf("\nexpected: %q\ngot:      %q\n", expected, actual)
+	}
+}
+
+func TestContextImport_multiState(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "import-provider")
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"foo": {Type: cty.String, Optional: true},
+			},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Computed: true},
+				},
+			},
+			"aws_instance_thing": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "aws_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("foo"),
+				}),
+			},
+			{
+				TypeName: "aws_instance_thing",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("bar"),
+				}),
+			},
+		},
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.ResourceInstance(
+					addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
+				),
+				ID: "bar",
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testImportMultiStr)
+	if actual != expected {
+		t.Fatalf("bad: \n%s", actual)
+	}
+}
+
+func TestContextImport_multiStateSame(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "import-provider")
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"foo": {Type: cty.String, Optional: true},
+			},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Computed: true},
+				},
+			},
+			"aws_instance_thing": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "aws_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("foo"),
+				}),
+			},
+			{
+				TypeName: "aws_instance_thing",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("bar"),
+				}),
+			},
+			{
+				TypeName: "aws_instance_thing",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("qux"),
+				}),
+			},
+		},
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.ResourceInstance(
+					addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
+				),
+				ID: "bar",
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testImportMultiSameStr)
+	if actual != expected {
+		t.Fatalf("bad: \n%s", actual)
+	}
+}
+
+func TestContextImport_nestedModuleImport(t *testing.T) {
+	p := testProvider("aws")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+locals {
+  xs = toset(["foo"])
+}
+
+module "a" {
+  for_each = local.xs
+  source   = "./a"
+}
+
+module "b" {
+  for_each = local.xs
+  source   = "./b"
+  y = module.a[each.key].y
+}
+
+resource "test_resource" "test" {
+}
+`,
+		"a/main.tf": `
+output "y" {
+  value = "bar"
+}
+`,
+		"b/main.tf": `
+variable "y" {
+  type = string
+}
+
+resource "test_resource" "unused" {
+  value = var.y
+  // missing required, but should not error
+}
+`,
+	})
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"foo": {Type: cty.String, Optional: true},
+			},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":       {Type: cty.String, Computed: true},
+					"required": {Type: cty.String, Required: true},
+				},
+			},
+		},
+	})
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_resource",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id":       cty.StringVal("test"),
+					"required": cty.StringVal("value"),
+				}),
+			},
+		},
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.ResourceInstance(
+					addrs.ManagedResourceMode, "test_resource", "test", addrs.NoKey,
+				),
+				ID: "test",
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	ri := state.ResourceInstance(mustResourceInstanceAddr("test_resource.test"))
+	expected := `{"id":"test","required":"value"}`
+	if ri == nil || ri.Current == nil {
+		t.Fatal("no state is recorded for resource instance test_resource.test")
+	}
+	if string(ri.Current.AttrsJSON) != expected {
+		t.Fatalf("expected %q, got %q\n", expected, ri.Current.AttrsJSON)
+	}
+}
+
+// New resources in the config during import won't exist for evaluation
+// purposes (until import is upgraded to using a complete plan). This means
+// that references to them are unknown, but in the case of single instances, we
+// can at least know the type of unknown value.
+func TestContextImport_newResourceUnknown(t *testing.T) {
+	p := testProvider("aws")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_resource" "one" {
+}
+
+resource "test_resource" "two" {
+  count = length(flatten([test_resource.one.id]))
+}
+
+resource "test_resource" "test" {
+}
+`})
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_resource",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("test"),
+				}),
+			},
+		},
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.ResourceInstance(
+					addrs.ManagedResourceMode, "test_resource", "test", addrs.NoKey,
+				),
+				ID: "test",
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	ri := state.ResourceInstance(mustResourceInstanceAddr("test_resource.test"))
+	expected := `{"id":"test"}`
+	if ri == nil || ri.Current == nil {
+		t.Fatal("no state is recorded for resource instance test_resource.test")
+	}
+	if string(ri.Current.AttrsJSON) != expected {
+		t.Fatalf("expected %q, got %q\n", expected, ri.Current.AttrsJSON)
+	}
+}
+
+func TestContextImport_33572(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "issue-33572")
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "aws_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
+		Targets: []*ImportTarget{
+			{
+				Addr: addrs.RootModuleInstance.ResourceInstance(
+					addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
+				),
+				ID: "bar",
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	actual := strings.TrimSpace(state.String())
+	expected := strings.TrimSpace(testImportStrWithDataSource)
+	if diff := cmp.Diff(actual, expected); len(diff) > 0 {
+		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s\ndiff:\n%s", actual, expected, diff)
+	}
+}
+
+const testImportStr = `
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+`
+
+const testImportStrWithDataSource = `
+data.aws_data_source.bar:
+  ID = baz
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+`
+
+const testImportCountIndexStr = `
+aws_instance.foo.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+`
+
+const testImportModuleStr = `
+<no state>
+module.child[0]:
+  aws_instance.foo:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+`
+
+const testImportModuleDepth2Str = `
+<no state>
+module.child[0].nested:
+  aws_instance.foo:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+`
+
+const testImportMultiStr = `
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+aws_instance_thing.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+`
+
+const testImportMultiSameStr = `
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+aws_instance_thing.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+aws_instance_thing.foo-1:
+  ID = qux
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+`
+
+const testImportRefreshStr = `
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+`
diff --git a/v1.5.7/internal/terraform/context_input.go b/v1.5.7/internal/terraform/context_input.go
new file mode 100644
index 0000000..efe5038
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_input.go
@@ -0,0 +1,209 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"context"
+	"log"
+	"sort"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcldec"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Input asks for input to fill unset required arguments in provider
+// configurations.
+//
+// Unlike the other better-behaved operation methods, this one actually
+// modifies some internal state inside the receving context so that the
+// captured values will be implicitly available to a subsequent call to Plan,
+// or to some other operation entry point. Hopefully a future iteration of
+// this will change design to make that data flow more explicit.
+//
+// Because Input saves the results inside the Context object, asking for
+// input twice on the same Context is invalid and will lead to undefined
+// behavior.
+//
+// Once you've called Input with a particular config, it's invalid to call
+// any other Context method with a different config, because the aforementioned
+// modified internal state won't match. Again, this is an architectural wart
+// that we'll hopefully resolve in future.
+func (c *Context) Input(config *configs.Config, mode InputMode) tfdiags.Diagnostics {
+	// This function used to be responsible for more than it is now, so its
+	// interface is more general than its current functionality requires.
+	// It now exists only to handle interactive prompts for provider
+	// configurations, with other prompts the responsibility of the CLI
+	// layer prior to calling in to this package.
+	//
+	// (Hopefully in future the remaining functionality here can move to the
+	// CLI layer too in order to avoid this odd situation where core code
+	// produces UI input prompts.)
+
+	var diags tfdiags.Diagnostics
+	defer c.acquireRun("input")()
+
+	schemas, moreDiags := c.Schemas(config, nil)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		return diags
+	}
+
+	if c.uiInput == nil {
+		log.Printf("[TRACE] Context.Input: uiInput is nil, so skipping")
+		return diags
+	}
+
+	ctx := context.Background()
+
+	if mode&InputModeProvider != 0 {
+		log.Printf("[TRACE] Context.Input: Prompting for provider arguments")
+
+		// We prompt for input only for provider configurations defined in
+		// the root module. Provider configurations in other modules are a
+		// legacy thing we no longer recommend, and even if they weren't we
+		// can't practically prompt for their inputs here because we've not
+		// yet done "expansion" and so we don't know whether the modules are
+		// using count or for_each.
+
+		pcs := make(map[string]*configs.Provider)
+		pas := make(map[string]addrs.LocalProviderConfig)
+		for _, pc := range config.Module.ProviderConfigs {
+			addr := pc.Addr()
+			pcs[addr.String()] = pc
+			pas[addr.String()] = addr
+			log.Printf("[TRACE] Context.Input: Provider %s declared at %s", addr, pc.DeclRange)
+		}
+		// We also need to detect _implied_ provider configs from resources.
+		// These won't have *configs.Provider objects, but they will still
+		// exist in the map and we'll just treat them as empty below.
+		for _, rc := range config.Module.ManagedResources {
+			pa := rc.ProviderConfigAddr()
+			if pa.Alias != "" {
+				continue // alias configurations cannot be implied
+			}
+			if _, exists := pcs[pa.String()]; !exists {
+				pcs[pa.String()] = nil
+				pas[pa.String()] = pa
+				log.Printf("[TRACE] Context.Input: Provider %s implied by resource block at %s", pa, rc.DeclRange)
+			}
+		}
+		for _, rc := range config.Module.DataResources {
+			pa := rc.ProviderConfigAddr()
+			if pa.Alias != "" {
+				continue // alias configurations cannot be implied
+			}
+			if _, exists := pcs[pa.String()]; !exists {
+				pcs[pa.String()] = nil
+				pas[pa.String()] = pa
+				log.Printf("[TRACE] Context.Input: Provider %s implied by data block at %s", pa, rc.DeclRange)
+			}
+		}
+
+		for pk, pa := range pas {
+			pc := pcs[pk] // will be nil if this is an implied config
+
+			// Wrap the input into a namespace
+			input := &PrefixUIInput{
+				IdPrefix:    pk,
+				QueryPrefix: pk + ".",
+				UIInput:     c.uiInput,
+			}
+
+			providerFqn := config.Module.ProviderForLocalConfig(pa)
+			schema := schemas.ProviderConfig(providerFqn)
+			if schema == nil {
+				// Could either be an incorrect config or just an incomplete
+				// mock in tests. We'll let a later pass decide, and just
+				// ignore this for the purposes of gathering input.
+				log.Printf("[TRACE] Context.Input: No schema available for provider type %q", pa.LocalName)
+				continue
+			}
+
+			// For our purposes here we just want to detect if attrbutes are
+			// set in config at all, so rather than doing a full decode
+			// (which would require us to prepare an evalcontext, etc) we'll
+			// use the low-level HCL API to process only the top-level
+			// structure.
+			var attrExprs hcl.Attributes // nil if there is no config
+			if pc != nil && pc.Config != nil {
+				lowLevelSchema := schemaForInputSniffing(hcldec.ImpliedSchema(schema.DecoderSpec()))
+				content, _, diags := pc.Config.PartialContent(lowLevelSchema)
+				if diags.HasErrors() {
+					log.Printf("[TRACE] Context.Input: %s has decode error, so ignoring: %s", pa, diags.Error())
+					continue
+				}
+				attrExprs = content.Attributes
+			}
+
+			keys := make([]string, 0, len(schema.Attributes))
+			for key := range schema.Attributes {
+				keys = append(keys, key)
+			}
+			sort.Strings(keys)
+
+			vals := map[string]cty.Value{}
+			for _, key := range keys {
+				attrS := schema.Attributes[key]
+				if attrS.Optional {
+					continue
+				}
+				if attrExprs != nil {
+					if _, exists := attrExprs[key]; exists {
+						continue
+					}
+				}
+				if !attrS.Type.Equals(cty.String) {
+					continue
+				}
+
+				log.Printf("[TRACE] Context.Input: Prompting for %s argument %s", pa, key)
+				rawVal, err := input.Input(ctx, &InputOpts{
+					Id:          key,
+					Query:       key,
+					Description: attrS.Description,
+				})
+				if err != nil {
+					log.Printf("[TRACE] Context.Input: Failed to prompt for %s argument %s: %s", pa, key, err)
+					continue
+				}
+
+				vals[key] = cty.StringVal(rawVal)
+			}
+
+			absConfigAddr := addrs.AbsProviderConfig{
+				Provider: providerFqn,
+				Alias:    pa.Alias,
+				Module:   config.Path,
+			}
+			c.providerInputConfig[absConfigAddr.String()] = vals
+
+			log.Printf("[TRACE] Context.Input: Input for %s: %#v", pk, vals)
+		}
+	}
+
+	return diags
+}
+
+// schemaForInputSniffing returns a transformed version of a given schema
+// that marks all attributes as optional, which the Context.Input method can
+// use to detect whether a required argument is set without missing arguments
+// themselves generating errors.
+func schemaForInputSniffing(schema *hcl.BodySchema) *hcl.BodySchema {
+	ret := &hcl.BodySchema{
+		Attributes: make([]hcl.AttributeSchema, len(schema.Attributes)),
+		Blocks:     schema.Blocks,
+	}
+
+	for i, attrS := range schema.Attributes {
+		ret.Attributes[i] = attrS
+		ret.Attributes[i].Required = false
+	}
+
+	return ret
+}
diff --git a/v1.5.7/internal/terraform/context_input_test.go b/v1.5.7/internal/terraform/context_input_test.go
new file mode 100644
index 0000000..745e48b
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_input_test.go
@@ -0,0 +1,472 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"reflect"
+	"strings"
+	"sync"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestContext2Input_provider(t *testing.T) {
+	m := testModule(t, "input-provider")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"foo": {
+					Type:        cty.String,
+					Required:    true,
+					Description: "something something",
+				},
+			},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+		},
+	})
+
+	inp := &MockUIInput{
+		InputReturnMap: map[string]string{
+			"provider.aws.foo": "bar",
+		},
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		UIInput: inp,
+	})
+
+	var actual interface{}
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		actual = req.Config.GetAttr("foo").AsString()
+		return
+	}
+
+	if diags := ctx.Input(m, InputModeStd); diags.HasErrors() {
+		t.Fatalf("input errors: %s", diags.Err())
+	}
+
+	if !inp.InputCalled {
+		t.Fatal("no input prompt; want prompt for argument \"foo\"")
+	}
+	if got, want := inp.InputOpts.Description, "something something"; got != want {
+		t.Errorf("wrong description\ngot:  %q\nwant: %q", got, want)
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	if !reflect.DeepEqual(actual, "bar") {
+		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", actual, "bar")
+	}
+}
+
+func TestContext2Input_providerMulti(t *testing.T) {
+	m := testModule(t, "input-provider-multi")
+
+	getProviderSchemaResponse := getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"foo": {
+					Type:        cty.String,
+					Required:    true,
+					Description: "something something",
+				},
+			},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+		},
+	})
+
+	// In order to update the provider to check only the configure calls during
+	// apply, we will need to inject a new factory function after plan. We must
+	// use a closure around the factory, because in order for the inputs to
+	// work during apply we need to maintain the same context value, preventing
+	// us from assigning a new Providers map.
+	providerFactory := func() (providers.Interface, error) {
+		p := testProvider("aws")
+		p.GetProviderSchemaResponse = getProviderSchemaResponse
+		return p, nil
+	}
+
+	inp := &MockUIInput{
+		InputReturnMap: map[string]string{
+			"provider.aws.foo":      "bar",
+			"provider.aws.east.foo": "bar",
+		},
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): func() (providers.Interface, error) {
+				return providerFactory()
+			},
+		},
+		UIInput: inp,
+	})
+
+	var actual []interface{}
+	var lock sync.Mutex
+
+	if diags := ctx.Input(m, InputModeStd); diags.HasErrors() {
+		t.Fatalf("input errors: %s", diags.Err())
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	providerFactory = func() (providers.Interface, error) {
+		p := testProvider("aws")
+		p.GetProviderSchemaResponse = getProviderSchemaResponse
+		p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+			lock.Lock()
+			defer lock.Unlock()
+			actual = append(actual, req.Config.GetAttr("foo").AsString())
+			return
+		}
+		return p, nil
+	}
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	expected := []interface{}{"bar", "bar"}
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", actual, expected)
+	}
+}
+
+func TestContext2Input_providerOnce(t *testing.T) {
+	m := testModule(t, "input-provider-once")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	if diags := ctx.Input(m, InputModeStd); diags.HasErrors() {
+		t.Fatalf("input errors: %s", diags.Err())
+	}
+}
+
+func TestContext2Input_providerId(t *testing.T) {
+	input := new(MockUIInput)
+
+	m := testModule(t, "input-provider")
+
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"foo": {
+					Type:        cty.String,
+					Required:    true,
+					Description: "something something",
+				},
+			},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		UIInput: input,
+	})
+
+	var actual interface{}
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		actual = req.Config.GetAttr("foo").AsString()
+		return
+	}
+
+	input.InputReturnMap = map[string]string{
+		"provider.aws.foo": "bar",
+	}
+
+	if diags := ctx.Input(m, InputModeStd); diags.HasErrors() {
+		t.Fatalf("input errors: %s", diags.Err())
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	if !reflect.DeepEqual(actual, "bar") {
+		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", actual, "bar")
+	}
+}
+
+func TestContext2Input_providerOnly(t *testing.T) {
+	input := new(MockUIInput)
+
+	m := testModule(t, "input-provider-vars")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"foo": {
+					Type:     cty.String,
+					Required: true,
+				},
+			},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo":  {Type: cty.String, Required: true},
+					"id":   {Type: cty.String, Computed: true},
+					"type": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		UIInput: input,
+	})
+
+	input.InputReturnMap = map[string]string{
+		"provider.aws.foo": "bar",
+	}
+
+	var actual interface{}
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		actual = req.Config.GetAttr("foo").AsString()
+		return
+	}
+
+	if err := ctx.Input(m, InputModeProvider); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// NOTE: This is a stale test case from an older version of Terraform
+	// where Input was responsible for prompting for both input variables _and_
+	// provider configuration arguments, where it was trying to test the case
+	// where we were turning off the mode of prompting for input variables.
+	// That's now always disabled, and so this is essentially the same as the
+	// normal Input test, but we're preserving it until we have time to review
+	// and make sure this isn't inadvertently providing unique test coverage
+	// other than what it set out to test.
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"foo": &InputValue{
+				Value:      cty.StringVal("us-west-2"),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	state, err := ctx.Apply(plan, m)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !reflect.DeepEqual(actual, "bar") {
+		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", actual, "bar")
+	}
+
+	actualStr := strings.TrimSpace(state.String())
+	expectedStr := strings.TrimSpace(testTerraformInputProviderOnlyStr)
+	if actualStr != expectedStr {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actualStr, expectedStr)
+	}
+}
+
+func TestContext2Input_providerVars(t *testing.T) {
+	input := new(MockUIInput)
+	m := testModule(t, "input-provider-with-vars")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		UIInput: input,
+	})
+
+	input.InputReturnMap = map[string]string{
+		"var.foo": "bar",
+	}
+
+	var actual interface{}
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		actual = req.Config.GetAttr("foo").AsString()
+		return
+	}
+	if diags := ctx.Input(m, InputModeStd); diags.HasErrors() {
+		t.Fatalf("input errors: %s", diags.Err())
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"foo": &InputValue{
+				Value:      cty.StringVal("bar"),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	assertNoErrors(t, diags)
+
+	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
+		t.Fatalf("apply errors: %s", diags.Err())
+	}
+
+	if !reflect.DeepEqual(actual, "bar") {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestContext2Input_providerVarsModuleInherit(t *testing.T) {
+	input := new(MockUIInput)
+	m := testModule(t, "input-provider-with-vars-and-module")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		UIInput: input,
+	})
+
+	if diags := ctx.Input(m, InputModeStd); diags.HasErrors() {
+		t.Fatalf("input errors: %s", diags.Err())
+	}
+}
+
+// adding a list interpolation in fails to interpolate the count variable
+func TestContext2Input_submoduleTriggersInvalidCount(t *testing.T) {
+	input := new(MockUIInput)
+	m := testModule(t, "input-submodule-count")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		UIInput: input,
+	})
+
+	if diags := ctx.Input(m, InputModeStd); diags.HasErrors() {
+		t.Fatalf("input errors: %s", diags.Err())
+	}
+}
+
+// In this case, a module variable can't be resolved from a data source until
+// it's refreshed, but it can't be refreshed during Input.
+func TestContext2Input_dataSourceRequiresRefresh(t *testing.T) {
+	input := new(MockUIInput)
+	p := testProvider("null")
+	m := testModule(t, "input-module-data-vars")
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		DataSources: map[string]*configschema.Block{
+			"null_data_source": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.List(cty.String), Optional: true},
+				},
+			},
+		},
+	})
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		return providers.ReadDataSourceResponse{
+			State: req.Config,
+		}
+	}
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.DataResourceMode,
+				Type: "null_data_source",
+				Name: "bar",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsFlat: map[string]string{
+					"id":    "-",
+					"foo.#": "1",
+					"foo.0": "a",
+					// foo.1 exists in the data source, but needs to be refreshed.
+				},
+				Status: states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("null"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		},
+		UIInput: input,
+	})
+
+	if diags := ctx.Input(m, InputModeStd); diags.HasErrors() {
+		t.Fatalf("input errors: %s", diags.Err())
+	}
+
+	// ensure that plan works after Refresh. This is a legacy test that
+	// doesn't really make sense anymore, because Refresh is really just
+	// a wrapper around plan anyway, but we're keeping it until we get a
+	// chance to review and check whether it's giving us any additional
+	// test coverage aside from what it's specifically intending to test.
+	if _, diags := ctx.Refresh(m, state, DefaultPlanOpts); diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+	if _, diags := ctx.Plan(m, state, DefaultPlanOpts); diags.HasErrors() {
+		t.Fatalf("plan errors: %s", diags.Err())
+	}
+}
diff --git a/v1.5.7/internal/terraform/context_plan.go b/v1.5.7/internal/terraform/context_plan.go
new file mode 100644
index 0000000..f921eab
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_plan.go
@@ -0,0 +1,939 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"bytes"
+	"fmt"
+	"log"
+	"sort"
+	"strings"
+	"time"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/lang/globalref"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/refactoring"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// PlanOpts are the various options that affect the details of how Terraform
+// will build a plan.
+type PlanOpts struct {
+	// Mode defines what variety of plan the caller wishes to create.
+	// Refer to the documentation of the plans.Mode type and its values
+	// for more information.
+	Mode plans.Mode
+
+	// SkipRefresh specifies to trust that the current values for managed
+	// resource instances in the prior state are accurate and to therefore
+	// disable the usual step of fetching updated values for each resource
+	// instance using its corresponding provider.
+	SkipRefresh bool
+
+	// PreDestroyRefresh indicated that this is being passed to a plan used to
+	// refresh the state immediately before a destroy plan.
+	// FIXME: This is a temporary fix to allow the pre-destroy refresh to
+	// succeed. The refreshing operation during destroy must be a special case,
+	// which can allow for missing instances in the state, and avoid blocking
+	// on failing condition tests. The destroy plan itself should be
+	// responsible for this special case of refreshing, and the separate
+	// pre-destroy plan removed entirely.
+	PreDestroyRefresh bool
+
+	// SetVariables are the raw values for root module variables as provided
+	// by the user who is requesting the run, prior to any normalization or
+	// substitution of defaults. See the documentation for the InputValue
+	// type for more information on how to correctly populate this.
+	SetVariables InputValues
+
+	// If Targets has a non-zero length then it activates targeted planning
+	// mode, where Terraform will take actions only for resource instances
+	// mentioned in this set and any other objects those resource instances
+	// depend on.
+	//
+	// Targeted planning mode is intended for exceptional use only,
+	// and so populating this field will cause Terraform to generate extra
+	// warnings as part of the planning result.
+	Targets []addrs.Targetable
+
+	// ForceReplace is a set of resource instance addresses whose corresponding
+	// objects should be forced planned for replacement if the provider's
+	// plan would otherwise have been to either update the object in-place or
+	// to take no action on it at all.
+	//
+	// A typical use of this argument is to ask Terraform to replace an object
+	// which the user has determined is somehow degraded (via information from
+	// outside of Terraform), thereby hopefully replacing it with a
+	// fully-functional new object.
+	ForceReplace []addrs.AbsResourceInstance
+
+	// ImportTargets is a list of target resources to import. These resources
+	// will be added to the plan graph.
+	ImportTargets []*ImportTarget
+
+	// GenerateConfig tells Terraform where to write any generated configuration
+	// for any ImportTargets that do not have configuration already.
+	//
+	// If empty, then no config will be generated.
+	GenerateConfigPath string
+}
+
+// Plan generates an execution plan by comparing the given configuration
+// with the given previous run state.
+//
+// The given planning options allow control of various other details of the
+// planning process that are not represented directly in the configuration.
+// You can use terraform.DefaultPlanOpts to generate a normal plan with no
+// special options.
+//
+// If the returned diagnostics contains no errors then the returned plan is
+// applyable, although Terraform cannot guarantee that applying it will fully
+// succeed. If the returned diagnostics contains errors but this method
+// still returns a non-nil Plan then the plan describes the subset of actions
+// planned so far, which is not safe to apply but could potentially be used
+// by the UI layer to give extra context to support understanding of the
+// returned error messages.
+func (c *Context) Plan(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*plans.Plan, tfdiags.Diagnostics) {
+	defer c.acquireRun("plan")()
+	var diags tfdiags.Diagnostics
+
+	// Save the downstream functions from needing to deal with these broken situations.
+	// No real callers should rely on these, but we have a bunch of old and
+	// sloppy tests that don't always populate arguments properly.
+	if config == nil {
+		config = configs.NewEmptyConfig()
+	}
+	if prevRunState == nil {
+		prevRunState = states.NewState()
+	}
+	if opts == nil {
+		opts = &PlanOpts{
+			Mode: plans.NormalMode,
+		}
+	}
+
+	moreDiags := c.checkConfigDependencies(config)
+	diags = diags.Append(moreDiags)
+	// If required dependencies are not available then we'll bail early since
+	// otherwise we're likely to just see a bunch of other errors related to
+	// incompatibilities, which could be overwhelming for the user.
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	switch opts.Mode {
+	case plans.NormalMode, plans.DestroyMode:
+		// OK
+	case plans.RefreshOnlyMode:
+		if opts.SkipRefresh {
+			// The CLI layer (and other similar callers) should prevent this
+			// combination of options.
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Incompatible plan options",
+				"Cannot skip refreshing in refresh-only mode. This is a bug in Terraform.",
+			))
+			return nil, diags
+		}
+	default:
+		// The CLI layer (and other similar callers) should not try to
+		// create a context for a mode that Terraform Core doesn't support.
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Unsupported plan mode",
+			fmt.Sprintf("Terraform Core doesn't know how to handle plan mode %s. This is a bug in Terraform.", opts.Mode),
+		))
+		return nil, diags
+	}
+	if len(opts.ForceReplace) > 0 && opts.Mode != plans.NormalMode {
+		// The other modes don't generate no-op or update actions that we might
+		// upgrade to be "replace", so doesn't make sense to combine those.
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Unsupported plan mode",
+			"Forcing resource instance replacement (with -replace=...) is allowed only in normal planning mode.",
+		))
+		return nil, diags
+	}
+
+	// By the time we get here, we should have values defined for all of
+	// the root module variables, even if some of them are "unknown". It's the
+	// caller's responsibility to have already handled the decoding of these
+	// from the various ways the CLI allows them to be set and to produce
+	// user-friendly error messages if they are not all present, and so
+	// the error message from checkInputVariables should never be seen and
+	// includes language asking the user to report a bug.
+	varDiags := checkInputVariables(config.Module.Variables, opts.SetVariables)
+	diags = diags.Append(varDiags)
+
+	if len(opts.Targets) > 0 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Warning,
+			"Resource targeting is in effect",
+			`You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current configuration.
+
+The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`,
+		))
+	}
+
+	var plan *plans.Plan
+	var planDiags tfdiags.Diagnostics
+	switch opts.Mode {
+	case plans.NormalMode:
+		plan, planDiags = c.plan(config, prevRunState, opts)
+	case plans.DestroyMode:
+		plan, planDiags = c.destroyPlan(config, prevRunState, opts)
+	case plans.RefreshOnlyMode:
+		plan, planDiags = c.refreshOnlyPlan(config, prevRunState, opts)
+	default:
+		panic(fmt.Sprintf("unsupported plan mode %s", opts.Mode))
+	}
+	diags = diags.Append(planDiags)
+	// NOTE: We're intentionally not returning early when diags.HasErrors
+	// here because we'll still populate other metadata below on a best-effort
+	// basis to try to give the UI some extra context to return alongside the
+	// error messages.
+
+	// convert the variables into the format expected for the plan
+	varVals := make(map[string]plans.DynamicValue, len(opts.SetVariables))
+	for k, iv := range opts.SetVariables {
+		if iv.Value == cty.NilVal {
+			continue // We only record values that the caller actually set
+		}
+
+		// We use cty.DynamicPseudoType here so that we'll save both the
+		// value _and_ its dynamic type in the plan, so we can recover
+		// exactly the same value later.
+		dv, err := plans.NewDynamicValue(iv.Value, cty.DynamicPseudoType)
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Failed to prepare variable value for plan",
+				fmt.Sprintf("The value for variable %q could not be serialized to store in the plan: %s.", k, err),
+			))
+			continue
+		}
+		varVals[k] = dv
+	}
+
+	// insert the run-specific data from the context into the plan; variables,
+	// targets and provider SHAs.
+	if plan != nil {
+		plan.VariableValues = varVals
+		plan.TargetAddrs = opts.Targets
+	} else if !diags.HasErrors() {
+		panic("nil plan but no errors")
+	}
+
+	if plan != nil {
+		relevantAttrs, rDiags := c.relevantResourceAttrsForPlan(config, plan)
+		diags = diags.Append(rDiags)
+		plan.RelevantAttributes = relevantAttrs
+	}
+
+	if diags.HasErrors() {
+		// We can't proceed further with an invalid plan, because an invalid
+		// plan isn't applyable by definition.
+		if plan != nil {
+			// We'll explicitly mark our plan as errored so that it can't
+			// be accidentally applied even though it's incomplete.
+			plan.Errored = true
+		}
+		return plan, diags
+	}
+
+	diags = diags.Append(c.checkApplyGraph(plan, config))
+
+	return plan, diags
+}
+
+// checkApplyGraph builds the apply graph out of the current plan to
+// check for any errors that may arise once the planned changes are added to
+// the graph. This allows terraform to report errors (mostly cycles) during
+// plan that would otherwise only crop up during apply
+func (c *Context) checkApplyGraph(plan *plans.Plan, config *configs.Config) tfdiags.Diagnostics {
+	if plan.Changes.Empty() {
+		log.Println("[DEBUG] no planned changes, skipping apply graph check")
+		return nil
+	}
+	log.Println("[DEBUG] building apply graph to check for errors")
+	_, _, diags := c.applyGraph(plan, config, true)
+	return diags
+}
+
+var DefaultPlanOpts = &PlanOpts{
+	Mode: plans.NormalMode,
+}
+
+// SimplePlanOpts is a constructor to help with creating "simple" values of
+// PlanOpts which only specify a mode and input variables.
+//
+// This helper function is primarily intended for use in straightforward
+// tests that don't need any of the more "esoteric" planning options. For
+// handling real user requests to run Terraform, it'd probably be better
+// to construct a *PlanOpts value directly and provide a way for the user
+// to set values for all of its fields.
+//
+// The "mode" and "setVariables" arguments become the values of the "Mode"
+// and "SetVariables" fields in the result. Refer to the PlanOpts type
+// documentation to learn about the meanings of those fields.
+func SimplePlanOpts(mode plans.Mode, setVariables InputValues) *PlanOpts {
+	return &PlanOpts{
+		Mode:         mode,
+		SetVariables: setVariables,
+	}
+}
+
+func (c *Context) plan(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*plans.Plan, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	if opts.Mode != plans.NormalMode {
+		panic(fmt.Sprintf("called Context.plan with %s", opts.Mode))
+	}
+
+	opts.ImportTargets = c.findImportTargets(config, prevRunState)
+	plan, walkDiags := c.planWalk(config, prevRunState, opts)
+	diags = diags.Append(walkDiags)
+
+	return plan, diags
+}
+
+func (c *Context) refreshOnlyPlan(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*plans.Plan, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	if opts.Mode != plans.RefreshOnlyMode {
+		panic(fmt.Sprintf("called Context.refreshOnlyPlan with %s", opts.Mode))
+	}
+
+	plan, walkDiags := c.planWalk(config, prevRunState, opts)
+	diags = diags.Append(walkDiags)
+	if diags.HasErrors() {
+		// Non-nil plan along with errors indicates a non-applyable partial
+		// plan that's only suitable to be shown to the user as extra context
+		// to help understand the errors.
+		return plan, diags
+	}
+
+	// If the graph builder and graph nodes correctly obeyed our directive
+	// to refresh only, the set of resource changes should always be empty.
+	// We'll safety-check that here so we can return a clear message about it,
+	// rather than probably just generating confusing output at the UI layer.
+	if len(plan.Changes.Resources) != 0 {
+		// Some extra context in the logs in case the user reports this message
+		// as a bug, as a starting point for debugging.
+		for _, rc := range plan.Changes.Resources {
+			if depKey := rc.DeposedKey; depKey == states.NotDeposed {
+				log.Printf("[DEBUG] Refresh-only plan includes %s change for %s", rc.Action, rc.Addr)
+			} else {
+				log.Printf("[DEBUG] Refresh-only plan includes %s change for %s deposed object %s", rc.Action, rc.Addr, depKey)
+			}
+		}
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid refresh-only plan",
+			"Terraform generated planned resource changes in a refresh-only plan. This is a bug in Terraform.",
+		))
+	}
+
+	// We don't populate RelevantResources for a refresh-only plan, because
+	// they never have any planned actions and so no resource can ever be
+	// "relevant" per the intended meaning of that field.
+
+	return plan, diags
+}
+
+func (c *Context) destroyPlan(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*plans.Plan, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	if opts.Mode != plans.DestroyMode {
+		panic(fmt.Sprintf("called Context.destroyPlan with %s", opts.Mode))
+	}
+
+	priorState := prevRunState
+
+	// A destroy plan starts by running Refresh to read any pending data
+	// sources, and remove missing managed resources. This is required because
+	// a "destroy plan" is only creating delete changes, and is essentially a
+	// local operation.
+	//
+	// NOTE: if skipRefresh _is_ set then we'll rely on the destroy-plan walk
+	// below to upgrade the prevRunState and priorState both to the latest
+	// resource type schemas, so NodePlanDestroyableResourceInstance.Execute
+	// must coordinate with this by taking that action only when c.skipRefresh
+	// _is_ set. This coupling between the two is unfortunate but necessary
+	// to work within our current structure.
+	if !opts.SkipRefresh && !prevRunState.Empty() {
+		log.Printf("[TRACE] Context.destroyPlan: calling Context.plan to get the effect of refreshing the prior state")
+		refreshOpts := *opts
+		refreshOpts.Mode = plans.NormalMode
+		refreshOpts.PreDestroyRefresh = true
+
+		// FIXME: A normal plan is required here to refresh the state, because
+		// the state and configuration may not match during a destroy, and a
+		// normal refresh plan can fail with evaluation errors. In the future
+		// the destroy plan should take care of refreshing instances itself,
+		// where the special cases of evaluation and skipping condition checks
+		// can be done.
+		refreshPlan, refreshDiags := c.plan(config, prevRunState, &refreshOpts)
+		if refreshDiags.HasErrors() {
+			// NOTE: Normally we'd append diagnostics regardless of whether
+			// there are errors, just in case there are warnings we'd want to
+			// preserve, but we're intentionally _not_ doing that here because
+			// if the first plan succeeded then we'll be running another plan
+			// in DestroyMode below, and we don't want to double-up any
+			// warnings that both plan walks would generate.
+			// (This does mean we won't show any warnings that would've been
+			// unique to only this walk, but we're assuming here that if the
+			// warnings aren't also applicable to a destroy plan then we'd
+			// rather not show them here, because this non-destroy plan for
+			// refreshing is largely an implementation detail.)
+			diags = diags.Append(refreshDiags)
+			return nil, diags
+		}
+
+		// We'll use the refreshed state -- which is the  "prior state" from
+		// the perspective of this "destroy plan" -- as the starting state
+		// for our destroy-plan walk, so it can take into account if we
+		// detected during refreshing that anything was already deleted outside
+		// of Terraform.
+		priorState = refreshPlan.PriorState.DeepCopy()
+
+		// The refresh plan may have upgraded state for some resources, make
+		// sure we store the new version.
+		prevRunState = refreshPlan.PrevRunState.DeepCopy()
+		log.Printf("[TRACE] Context.destroyPlan: now _really_ creating a destroy plan")
+	}
+
+	destroyPlan, walkDiags := c.planWalk(config, priorState, opts)
+	diags = diags.Append(walkDiags)
+	if walkDiags.HasErrors() {
+		// Non-nil plan along with errors indicates a non-applyable partial
+		// plan that's only suitable to be shown to the user as extra context
+		// to help understand the errors.
+		return destroyPlan, diags
+	}
+
+	if !opts.SkipRefresh {
+		// If we didn't skip refreshing then we want the previous run state to
+		// be the one we originally fed into the c.refreshOnlyPlan call above,
+		// not the refreshed version we used for the destroy planWalk.
+		destroyPlan.PrevRunState = prevRunState
+	}
+
+	relevantAttrs, rDiags := c.relevantResourceAttrsForPlan(config, destroyPlan)
+	diags = diags.Append(rDiags)
+
+	destroyPlan.RelevantAttributes = relevantAttrs
+	return destroyPlan, diags
+}
+
+func (c *Context) prePlanFindAndApplyMoves(config *configs.Config, prevRunState *states.State, targets []addrs.Targetable) ([]refactoring.MoveStatement, refactoring.MoveResults) {
+	explicitMoveStmts := refactoring.FindMoveStatements(config)
+	implicitMoveStmts := refactoring.ImpliedMoveStatements(config, prevRunState, explicitMoveStmts)
+	var moveStmts []refactoring.MoveStatement
+	if stmtsLen := len(explicitMoveStmts) + len(implicitMoveStmts); stmtsLen > 0 {
+		moveStmts = make([]refactoring.MoveStatement, 0, stmtsLen)
+		moveStmts = append(moveStmts, explicitMoveStmts...)
+		moveStmts = append(moveStmts, implicitMoveStmts...)
+	}
+	moveResults := refactoring.ApplyMoves(moveStmts, prevRunState)
+	return moveStmts, moveResults
+}
+
+func (c *Context) prePlanVerifyTargetedMoves(moveResults refactoring.MoveResults, targets []addrs.Targetable) tfdiags.Diagnostics {
+	if len(targets) < 1 {
+		return nil // the following only matters when targeting
+	}
+
+	var diags tfdiags.Diagnostics
+
+	var excluded []addrs.AbsResourceInstance
+	for _, result := range moveResults.Changes.Values() {
+		fromMatchesTarget := false
+		toMatchesTarget := false
+		for _, targetAddr := range targets {
+			if targetAddr.TargetContains(result.From) {
+				fromMatchesTarget = true
+			}
+			if targetAddr.TargetContains(result.To) {
+				toMatchesTarget = true
+			}
+		}
+		if !fromMatchesTarget {
+			excluded = append(excluded, result.From)
+		}
+		if !toMatchesTarget {
+			excluded = append(excluded, result.To)
+		}
+	}
+	if len(excluded) > 0 {
+		sort.Slice(excluded, func(i, j int) bool {
+			return excluded[i].Less(excluded[j])
+		})
+
+		var listBuf strings.Builder
+		var prevResourceAddr addrs.AbsResource
+		for _, instAddr := range excluded {
+			// Targeting generally ends up selecting whole resources rather
+			// than individual instances, because we don't factor in
+			// individual instances until DynamicExpand, so we're going to
+			// always show whole resource addresses here, excluding any
+			// instance keys. (This also neatly avoids dealing with the
+			// different quoting styles required for string instance keys
+			// on different shells, which is handy.)
+			//
+			// To avoid showing duplicates when we have multiple instances
+			// of the same resource, we'll remember the most recent
+			// resource we rendered in prevResource, which is sufficient
+			// because we sorted the list of instance addresses above, and
+			// our sort order always groups together instances of the same
+			// resource.
+			resourceAddr := instAddr.ContainingResource()
+			if resourceAddr.Equal(prevResourceAddr) {
+				continue
+			}
+			fmt.Fprintf(&listBuf, "\n  -target=%q", resourceAddr.String())
+			prevResourceAddr = resourceAddr
+		}
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Moved resource instances excluded by targeting",
+			fmt.Sprintf(
+				"Resource instances in your current state have moved to new addresses in the latest configuration. Terraform must include those resource instances while planning in order to ensure a correct result, but your -target=... options do not fully cover all of those resource instances.\n\nTo create a valid plan, either remove your -target=... options altogether or add the following additional target options:%s\n\nNote that adding these options may include further additional resource instances in your plan, in order to respect object dependencies.",
+				listBuf.String(),
+			),
+		))
+	}
+
+	return diags
+}
+
+func (c *Context) postPlanValidateMoves(config *configs.Config, stmts []refactoring.MoveStatement, allInsts instances.Set) tfdiags.Diagnostics {
+	return refactoring.ValidateMoves(stmts, config, allInsts)
+}
+
+// All import target addresses with a key must already exist in config.
+// When we are able to generate config for expanded resources, this rule can be
+// relaxed.
+func (c *Context) postPlanValidateImports(config *configs.Config, importTargets []*ImportTarget, allInst instances.Set) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+	for _, it := range importTargets {
+		// We only care about import target addresses that have a key.
+		// If the address does not have a key, we don't need it to be in config
+		// because are able to generate config.
+		if it.Addr.Resource.Key == nil {
+			continue
+		}
+
+		if !allInst.HasResourceInstance(it.Addr) {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Cannot import to non-existent resource address",
+				fmt.Sprintf(
+					"Importing to resource address %s is not possible, because that address does not exist in configuration. Please ensure that the resource key is correct, or remove this import block.",
+					it.Addr,
+				),
+			))
+		}
+	}
+	return diags
+}
+
+// findImportTargets builds a list of import targets by taking the import blocks
+// in the config and filtering out any that target a resource already in state.
+func (c *Context) findImportTargets(config *configs.Config, priorState *states.State) []*ImportTarget {
+	var importTargets []*ImportTarget
+	for _, ic := range config.Module.Import {
+		if priorState.ResourceInstance(ic.To) == nil {
+			importTargets = append(importTargets, &ImportTarget{
+				Addr:   ic.To,
+				ID:     ic.ID,
+				Config: ic,
+			})
+		}
+	}
+	return importTargets
+}
+
+func (c *Context) planWalk(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*plans.Plan, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	log.Printf("[DEBUG] Building and walking plan graph for %s", opts.Mode)
+
+	prevRunState = prevRunState.DeepCopy() // don't modify the caller's object when we process the moves
+	moveStmts, moveResults := c.prePlanFindAndApplyMoves(config, prevRunState, opts.Targets)
+
+	// If resource targeting is in effect then it might conflict with the
+	// move result.
+	diags = diags.Append(c.prePlanVerifyTargetedMoves(moveResults, opts.Targets))
+	if diags.HasErrors() {
+		// We'll return early here, because if we have any moved resource
+		// instances excluded by targeting then planning is likely to encounter
+		// strange problems that may lead to confusing error messages.
+		return nil, diags
+	}
+
+	graph, walkOp, moreDiags := c.planGraph(config, prevRunState, opts)
+	diags = diags.Append(moreDiags)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	timestamp := time.Now().UTC()
+
+	// If we get here then we should definitely have a non-nil "graph", which
+	// we can now walk.
+	changes := plans.NewChanges()
+	walker, walkDiags := c.walk(graph, walkOp, &graphWalkOpts{
+		Config:            config,
+		InputState:        prevRunState,
+		Changes:           changes,
+		MoveResults:       moveResults,
+		PlanTimeTimestamp: timestamp,
+	})
+	diags = diags.Append(walker.NonFatalDiagnostics)
+	diags = diags.Append(walkDiags)
+
+	allInsts := walker.InstanceExpander.AllInstances()
+
+	importValidateDiags := c.postPlanValidateImports(config, opts.ImportTargets, allInsts)
+	if importValidateDiags.HasErrors() {
+		return nil, importValidateDiags
+	}
+
+	moveValidateDiags := c.postPlanValidateMoves(config, moveStmts, allInsts)
+	if moveValidateDiags.HasErrors() {
+		// If any of the move statements are invalid then those errors take
+		// precedence over any other errors because an incomplete move graph
+		// is quite likely to be the _cause_ of various errors. This oddity
+		// comes from the fact that we need to apply the moves before we
+		// actually validate them, because validation depends on the result
+		// of first trying to plan.
+		return nil, moveValidateDiags
+	}
+	diags = diags.Append(moveValidateDiags) // might just contain warnings
+
+	if moveResults.Blocked.Len() > 0 && !diags.HasErrors() {
+		// If we had blocked moves and we're not going to be returning errors
+		// then we'll report the blockers as a warning. We do this only in the
+		// absense of errors because invalid move statements might well be
+		// the root cause of the blockers, and so better to give an actionable
+		// error message than a less-actionable warning.
+		diags = diags.Append(blockedMovesWarningDiag(moveResults))
+	}
+
+	// If we reach this point with error diagnostics then "changes" is a
+	// representation of the subset of changes we were able to plan before
+	// we encountered errors, which we'll return as part of a non-nil plan
+	// so that e.g. the UI can show what was planned so far in case that extra
+	// context helps the user to understand the error messages we're returning.
+	prevRunState = walker.PrevRunState.Close()
+
+	// The refreshed state may have data resource objects which were deferred
+	// to apply and cannot be serialized.
+	walker.RefreshState.RemovePlannedResourceInstanceObjects()
+	priorState := walker.RefreshState.Close()
+
+	driftedResources, driftDiags := c.driftedResources(config, prevRunState, priorState, moveResults)
+	diags = diags.Append(driftDiags)
+
+	plan := &plans.Plan{
+		UIMode:           opts.Mode,
+		Changes:          changes,
+		DriftedResources: driftedResources,
+		PrevRunState:     prevRunState,
+		PriorState:       priorState,
+		Checks:           states.NewCheckResults(walker.Checks),
+		Timestamp:        timestamp,
+
+		// Other fields get populated by Context.Plan after we return
+	}
+	return plan, diags
+}
+
+func (c *Context) planGraph(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*Graph, walkOperation, tfdiags.Diagnostics) {
+	switch mode := opts.Mode; mode {
+	case plans.NormalMode:
+		graph, diags := (&PlanGraphBuilder{
+			Config:             config,
+			State:              prevRunState,
+			RootVariableValues: opts.SetVariables,
+			Plugins:            c.plugins,
+			Targets:            opts.Targets,
+			ForceReplace:       opts.ForceReplace,
+			skipRefresh:        opts.SkipRefresh,
+			preDestroyRefresh:  opts.PreDestroyRefresh,
+			Operation:          walkPlan,
+			ImportTargets:      opts.ImportTargets,
+			GenerateConfigPath: opts.GenerateConfigPath,
+		}).Build(addrs.RootModuleInstance)
+		return graph, walkPlan, diags
+	case plans.RefreshOnlyMode:
+		graph, diags := (&PlanGraphBuilder{
+			Config:             config,
+			State:              prevRunState,
+			RootVariableValues: opts.SetVariables,
+			Plugins:            c.plugins,
+			Targets:            opts.Targets,
+			skipRefresh:        opts.SkipRefresh,
+			skipPlanChanges:    true, // this activates "refresh only" mode.
+			Operation:          walkPlan,
+		}).Build(addrs.RootModuleInstance)
+		return graph, walkPlan, diags
+	case plans.DestroyMode:
+		graph, diags := (&PlanGraphBuilder{
+			Config:             config,
+			State:              prevRunState,
+			RootVariableValues: opts.SetVariables,
+			Plugins:            c.plugins,
+			Targets:            opts.Targets,
+			skipRefresh:        opts.SkipRefresh,
+			Operation:          walkPlanDestroy,
+		}).Build(addrs.RootModuleInstance)
+		return graph, walkPlanDestroy, diags
+	default:
+		// The above should cover all plans.Mode values
+		panic(fmt.Sprintf("unsupported plan mode %s", mode))
+	}
+}
+
+// driftedResources is a best-effort attempt to compare the current and prior
+// state. If we cannot decode the prior state for some reason, this should only
+// return warnings to help the user correlate any missing resources in the
+// report. This is known to happen when targeting a subset of resources,
+// because the excluded instances will have been removed from the plan and
+// not upgraded.
+func (c *Context) driftedResources(config *configs.Config, oldState, newState *states.State, moves refactoring.MoveResults) ([]*plans.ResourceInstanceChangeSrc, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	if newState.ManagedResourcesEqual(oldState) && moves.Changes.Len() == 0 {
+		// Nothing to do, because we only detect and report drift for managed
+		// resource instances.
+		return nil, diags
+	}
+
+	schemas, schemaDiags := c.Schemas(config, newState)
+	diags = diags.Append(schemaDiags)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	var drs []*plans.ResourceInstanceChangeSrc
+
+	for _, ms := range oldState.Modules {
+		for _, rs := range ms.Resources {
+			if rs.Addr.Resource.Mode != addrs.ManagedResourceMode {
+				// Drift reporting is only for managed resources
+				continue
+			}
+
+			provider := rs.ProviderConfig.Provider
+			for key, oldIS := range rs.Instances {
+				if oldIS.Current == nil {
+					// Not interested in instances that only have deposed objects
+					continue
+				}
+				addr := rs.Addr.Instance(key)
+
+				// Previous run address defaults to the current address, but
+				// can differ if the resource moved before refreshing
+				prevRunAddr := addr
+				if move, ok := moves.Changes.GetOk(addr); ok {
+					prevRunAddr = move.From
+				}
+
+				newIS := newState.ResourceInstance(addr)
+
+				schema, _ := schemas.ResourceTypeConfig(
+					provider,
+					addr.Resource.Resource.Mode,
+					addr.Resource.Resource.Type,
+				)
+				if schema == nil {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Warning,
+						"Missing resource schema from provider",
+						fmt.Sprintf("No resource schema found for %s when decoding prior state", addr.Resource.Resource.Type),
+					))
+					continue
+				}
+				ty := schema.ImpliedType()
+
+				oldObj, err := oldIS.Current.Decode(ty)
+				if err != nil {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Warning,
+						"Failed to decode resource from state",
+						fmt.Sprintf("Error decoding %q from prior state: %s", addr.String(), err),
+					))
+					continue
+				}
+
+				var newObj *states.ResourceInstanceObject
+				if newIS != nil && newIS.Current != nil {
+					newObj, err = newIS.Current.Decode(ty)
+					if err != nil {
+						diags = diags.Append(tfdiags.Sourceless(
+							tfdiags.Warning,
+							"Failed to decode resource from state",
+							fmt.Sprintf("Error decoding %q from prior state: %s", addr.String(), err),
+						))
+						continue
+					}
+				}
+
+				var oldVal, newVal cty.Value
+				oldVal = oldObj.Value
+				if newObj != nil {
+					newVal = newObj.Value
+				} else {
+					newVal = cty.NullVal(ty)
+				}
+
+				if oldVal.RawEquals(newVal) && addr.Equal(prevRunAddr) {
+					// No drift if the two values are semantically equivalent
+					// and no move has happened
+					continue
+				}
+
+				// We can detect three types of changes after refreshing state,
+				// only two of which are easily understood as "drift":
+				//
+				// - Resources which were deleted outside of Terraform;
+				// - Resources where the object value has changed outside of
+				//   Terraform;
+				// - Resources which have been moved without other changes.
+				//
+				// All of these are returned as drift, to allow refresh-only plans
+				// to present a full set of changes which will be applied.
+				var action plans.Action
+				switch {
+				case newVal.IsNull():
+					action = plans.Delete
+				case !oldVal.RawEquals(newVal):
+					action = plans.Update
+				default:
+					action = plans.NoOp
+				}
+
+				change := &plans.ResourceInstanceChange{
+					Addr:         addr,
+					PrevRunAddr:  prevRunAddr,
+					ProviderAddr: rs.ProviderConfig,
+					Change: plans.Change{
+						Action: action,
+						Before: oldVal,
+						After:  newVal,
+					},
+				}
+
+				changeSrc, err := change.Encode(ty)
+				if err != nil {
+					diags = diags.Append(err)
+					return nil, diags
+				}
+
+				drs = append(drs, changeSrc)
+			}
+		}
+	}
+
+	return drs, diags
+}
+
+// PlanGraphForUI is a last vestage of graphs in the public interface of Context
+// (as opposed to graphs as an implementation detail) intended only for use
+// by the "terraform graph" command when asked to render a plan-time graph.
+//
+// The result of this is intended only for rendering to the user as a dot
+// graph, and so may change in future in order to make the result more useful
+// in that context, even if drifts away from the physical graph that Terraform
+// Core currently uses as an implementation detail of planning.
+func (c *Context) PlanGraphForUI(config *configs.Config, prevRunState *states.State, mode plans.Mode) (*Graph, tfdiags.Diagnostics) {
+	// For now though, this really is just the internal graph, confusing
+	// implementation details and all.
+
+	var diags tfdiags.Diagnostics
+
+	opts := &PlanOpts{Mode: mode}
+
+	graph, _, moreDiags := c.planGraph(config, prevRunState, opts)
+	diags = diags.Append(moreDiags)
+	return graph, diags
+}
+
+func blockedMovesWarningDiag(results refactoring.MoveResults) tfdiags.Diagnostic {
+	if results.Blocked.Len() < 1 {
+		// Caller should check first
+		panic("request to render blocked moves warning without any blocked moves")
+	}
+
+	var itemsBuf bytes.Buffer
+	for _, blocked := range results.Blocked.Values() {
+		fmt.Fprintf(&itemsBuf, "\n  - %s could not move to %s", blocked.Actual, blocked.Wanted)
+	}
+
+	return tfdiags.Sourceless(
+		tfdiags.Warning,
+		"Unresolved resource instance address changes",
+		fmt.Sprintf(
+			"Terraform tried to adjust resource instance addresses in the prior state based on change information recorded in the configuration, but some adjustments did not succeed due to existing objects already at the intended addresses:%s\n\nTerraform has planned to destroy these objects. If Terraform's proposed changes aren't appropriate, you must first resolve the conflicts using the \"terraform state\" subcommands and then create a new plan.",
+			itemsBuf.String(),
+		),
+	)
+}
+
+// referenceAnalyzer returns a globalref.Analyzer object to help with
+// global analysis of references within the configuration that's attached
+// to the receiving context.
+func (c *Context) referenceAnalyzer(config *configs.Config, state *states.State) (*globalref.Analyzer, tfdiags.Diagnostics) {
+	schemas, diags := c.Schemas(config, state)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+	return globalref.NewAnalyzer(config, schemas.Providers), diags
+}
+
+// relevantResourcesForPlan implements the heuristic we use to populate the
+// RelevantResources field of returned plans.
+func (c *Context) relevantResourceAttrsForPlan(config *configs.Config, plan *plans.Plan) ([]globalref.ResourceAttr, tfdiags.Diagnostics) {
+	azr, diags := c.referenceAnalyzer(config, plan.PriorState)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	var refs []globalref.Reference
+	for _, change := range plan.Changes.Resources {
+		if change.Action == plans.NoOp {
+			continue
+		}
+
+		moreRefs := azr.ReferencesFromResourceInstance(change.Addr)
+		refs = append(refs, moreRefs...)
+	}
+
+	for _, change := range plan.Changes.Outputs {
+		if change.Action == plans.NoOp {
+			continue
+		}
+
+		moreRefs := azr.ReferencesFromOutputValue(change.Addr)
+		refs = append(refs, moreRefs...)
+	}
+
+	var contributors []globalref.ResourceAttr
+
+	for _, ref := range azr.ContributingResourceReferences(refs...) {
+		if res, ok := ref.ResourceAttr(); ok {
+			contributors = append(contributors, res)
+		}
+	}
+
+	return contributors, diags
+}
diff --git a/v1.5.7/internal/terraform/context_plan2_test.go b/v1.5.7/internal/terraform/context_plan2_test.go
new file mode 100644
index 0000000..59b2206
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_plan2_test.go
@@ -0,0 +1,4890 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"strings"
+	"sync"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestContext2Plan_removedDuringRefresh(t *testing.T) {
+	// This tests the situation where an object tracked in the previous run
+	// state has been deleted outside of Terraform, which we should detect
+	// during the refresh step and thus ultimately produce a plan to recreate
+	// the object, since it's still present in the configuration.
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{Block: simpleTestSchema()},
+		ResourceTypes: map[string]providers.Schema{
+			"test_object": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"arg": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+		resp.NewState = cty.NullVal(req.PriorState.Type())
+		return resp
+	}
+	p.UpgradeResourceStateFn = func(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
+		// We should've been given the prior state JSON as our input to upgrade.
+		if !bytes.Contains(req.RawStateJSON, []byte("previous_run")) {
+			t.Fatalf("UpgradeResourceState request doesn't contain the previous run object\n%s", req.RawStateJSON)
+		}
+
+		// We'll put something different in "arg" as part of upgrading, just
+		// so that we can verify below that PrevRunState contains the upgraded
+		// (but NOT refreshed) version of the object.
+		resp.UpgradedState = cty.ObjectVal(map[string]cty.Value{
+			"arg": cty.StringVal("upgraded"),
+		})
+		return resp
+	}
+
+	addr := mustResourceInstanceAddr("test_object.a")
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{"arg":"previous_run"}`),
+			Status:    states.ObjectTainted,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if !p.UpgradeResourceStateCalled {
+		t.Errorf("Provider's UpgradeResourceState wasn't called; should've been")
+	}
+	if !p.ReadResourceCalled {
+		t.Errorf("Provider's ReadResource wasn't called; should've been")
+	}
+
+	// The object should be absent from the plan's prior state, because that
+	// records the result of refreshing.
+	if got := plan.PriorState.ResourceInstance(addr); got != nil {
+		t.Errorf(
+			"instance %s is in the prior state after planning; should've been removed\n%s",
+			addr, spew.Sdump(got),
+		)
+	}
+
+	// However, the object should still be in the PrevRunState, because
+	// that reflects what we believed to exist before refreshing.
+	if got := plan.PrevRunState.ResourceInstance(addr); got == nil {
+		t.Errorf(
+			"instance %s is missing from the previous run state after planning; should've been preserved",
+			addr,
+		)
+	} else {
+		if !bytes.Contains(got.Current.AttrsJSON, []byte("upgraded")) {
+			t.Fatalf("previous run state has non-upgraded object\n%s", got.Current.AttrsJSON)
+		}
+	}
+
+	// This situation should result in a drifted resource change.
+	var drifted *plans.ResourceInstanceChangeSrc
+	for _, dr := range plan.DriftedResources {
+		if dr.Addr.Equal(addr) {
+			drifted = dr
+			break
+		}
+	}
+
+	if drifted == nil {
+		t.Errorf("instance %s is missing from the drifted resource changes", addr)
+	} else {
+		if got, want := drifted.Action, plans.Delete; got != want {
+			t.Errorf("unexpected instance %s drifted resource change action. got: %s, want: %s", addr, got, want)
+		}
+	}
+
+	// Because the configuration still mentions test_object.a, we should've
+	// planned to recreate it in order to fix the drift.
+	for _, c := range plan.Changes.Resources {
+		if c.Action != plans.Create {
+			t.Fatalf("expected Create action for missing %s, got %s", c.Addr, c.Action)
+		}
+	}
+}
+
+func TestContext2Plan_noChangeDataSourceSensitiveNestedSet(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "bar" {
+  sensitive = true
+  default   = "baz"
+}
+
+data "test_data_source" "foo" {
+  foo {
+    bar = var.bar
+  }
+}
+`,
+	})
+
+	p := new(MockProvider)
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		DataSources: map[string]*configschema.Block{
+			"test_data_source": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {Type: cty.String, Optional: true},
+							},
+						},
+						Nesting: configschema.NestingSet,
+					},
+				},
+			},
+		},
+	})
+
+	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+		State: cty.ObjectVal(map[string]cty.Value{
+			"id":  cty.StringVal("data_id"),
+			"foo": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("baz")})}),
+		}),
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("data.test_data_source.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"data_id", "foo":[{"bar":"baz"}]}`),
+			AttrSensitivePaths: []cty.PathValueMarks{
+				{
+					Path:  cty.GetAttrPath("foo"),
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	assertNoErrors(t, diags)
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.NoOp {
+			t.Fatalf("expected NoOp, got: %q %s", res.Addr, res.Action)
+		}
+	}
+}
+
+func TestContext2Plan_orphanDataInstance(t *testing.T) {
+	// ensure the planned replacement of the data source is evaluated properly
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+data "test_object" "a" {
+  for_each = { new = "ok" }
+}
+
+output "out" {
+  value = [ for k, _ in data.test_object.a: k ]
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+		resp.State = req.Config
+		return resp
+	}
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(mustResourceInstanceAddr(`data.test_object.a["old"]`), &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{"test_string":"foo"}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	change, err := plan.Changes.Outputs[0].Decode()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expected := cty.TupleVal([]cty.Value{cty.StringVal("new")})
+
+	if change.After.Equals(expected).False() {
+		t.Fatalf("expected %#v, got %#v\n", expected, change.After)
+	}
+}
+
+func TestContext2Plan_basicConfigurationAliases(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+provider "test" {
+  alias = "z"
+  test_string = "config"
+}
+
+module "mod" {
+  source = "./mod"
+  providers = {
+    test.x = test.z
+  }
+}
+`,
+
+		"mod/main.tf": `
+terraform {
+  required_providers {
+    test = {
+      source = "registry.terraform.io/hashicorp/test"
+      configuration_aliases = [ test.x ]
+	}
+  }
+}
+
+resource "test_object" "a" {
+  provider = test.x
+}
+
+`,
+	})
+
+	p := simpleMockProvider()
+
+	// The resource within the module should be using the provider configured
+	// from the root module. We should never see an empty configuration.
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		if req.Config.GetAttr("test_string").IsNull() {
+			resp.Diagnostics = resp.Diagnostics.Append(errors.New("missing test_string value"))
+		}
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+}
+
+func TestContext2Plan_dataReferencesResourceInModules(t *testing.T) {
+	p := testProvider("test")
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+		cfg := req.Config.AsValueMap()
+		cfg["id"] = cty.StringVal("d")
+		resp.State = cty.ObjectVal(cfg)
+		return resp
+	}
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+locals {
+  things = {
+    old = "first"
+    new = "second"
+  }
+}
+
+module "mod" {
+  source = "./mod"
+  for_each = local.things
+}
+`,
+
+		"./mod/main.tf": `
+resource "test_resource" "a" {
+}
+
+data "test_data_source" "d" {
+  depends_on = [test_resource.a]
+}
+
+resource "test_resource" "b" {
+  value = data.test_data_source.d.id
+}
+`})
+
+	oldDataAddr := mustResourceInstanceAddr(`module.mod["old"].data.test_data_source.d`)
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			mustResourceInstanceAddr(`module.mod["old"].test_resource.a`),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"a"}`),
+				Status:    states.ObjectReady,
+			}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+		)
+		s.SetResourceInstanceCurrent(
+			mustResourceInstanceAddr(`module.mod["old"].test_resource.b`),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"b","value":"d"}`),
+				Status:    states.ObjectReady,
+			}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+		)
+		s.SetResourceInstanceCurrent(
+			oldDataAddr,
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"d"}`),
+				Status:    states.ObjectReady,
+			}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+		)
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	oldMod := oldDataAddr.Module
+
+	for _, c := range plan.Changes.Resources {
+		// there should be no changes from the old module instance
+		if c.Addr.Module.Equal(oldMod) && c.Action != plans.NoOp {
+			t.Errorf("unexpected change %s for %s\n", c.Action, c.Addr)
+		}
+	}
+}
+
+func TestContext2Plan_resourceChecksInExpandedModule(t *testing.T) {
+	// When a resource is in a nested module we have two levels of expansion
+	// to do: first expand the module the resource is declared in, and then
+	// expand the resource itself.
+	//
+	// In earlier versions of Terraform we did that expansion as two levels
+	// of DynamicExpand, which led to a bug where we didn't have any central
+	// location from which to register all of the instances of a checkable
+	// resource.
+	//
+	// We now handle the full expansion all in one graph node and one dynamic
+	// subgraph, which avoids the problem. This is a regression test for the
+	// earlier bug. If this test is panicking with "duplicate checkable objects
+	// report" then that suggests the bug is reintroduced and we're now back
+	// to reporting each module instance separately again, which is incorrect.
+
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test": {
+				Block: &configschema.Block{},
+			},
+		},
+	}
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+		resp.NewState = req.PriorState
+		return resp
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		resp.PlannedState = cty.EmptyObjectVal
+		return resp
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		resp.NewState = req.PlannedState
+		return resp
+	}
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+			module "child" {
+				source = "./child"
+				count = 2 # must be at least 2 for this test to be valid
+			}
+		`,
+		"child/child.tf": `
+			locals {
+				a = "a"
+			}
+
+			resource "test" "test1" {
+				lifecycle {
+					postcondition {
+						# It doesn't matter what this checks as long as it
+						# passes, because if we don't handle expansion properly
+						# then we'll crash before we even get to evaluating this.
+						condition = local.a == local.a
+						error_message = "Postcondition failed."
+					}
+				}
+			}
+
+			resource "test" "test2" {
+				count = 2
+
+				lifecycle {
+					postcondition {
+						# It doesn't matter what this checks as long as it
+						# passes, because if we don't handle expansion properly
+						# then we'll crash before we even get to evaluating this.
+						condition = local.a == local.a
+						error_message = "Postcondition failed."
+					}
+				}
+			}
+		`,
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	priorState := states.NewState()
+	plan, diags := ctx.Plan(m, priorState, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	resourceInsts := []addrs.AbsResourceInstance{
+		mustResourceInstanceAddr("module.child[0].test.test1"),
+		mustResourceInstanceAddr("module.child[0].test.test2[0]"),
+		mustResourceInstanceAddr("module.child[0].test.test2[1]"),
+		mustResourceInstanceAddr("module.child[1].test.test1"),
+		mustResourceInstanceAddr("module.child[1].test.test2[0]"),
+		mustResourceInstanceAddr("module.child[1].test.test2[1]"),
+	}
+
+	for _, instAddr := range resourceInsts {
+		t.Run(fmt.Sprintf("results for %s", instAddr), func(t *testing.T) {
+			if rc := plan.Changes.ResourceInstance(instAddr); rc != nil {
+				if got, want := rc.Action, plans.Create; got != want {
+					t.Errorf("wrong action for %s\ngot:  %s\nwant: %s", instAddr, got, want)
+				}
+				if got, want := rc.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+					t.Errorf("wrong action reason for %s\ngot:  %s\nwant: %s", instAddr, got, want)
+				}
+			} else {
+				t.Errorf("no planned change for %s", instAddr)
+			}
+
+			if checkResult := plan.Checks.GetObjectResult(instAddr); checkResult != nil {
+				if got, want := checkResult.Status, checks.StatusPass; got != want {
+					t.Errorf("wrong check status for %s\ngot:  %s\nwant: %s", instAddr, got, want)
+				}
+			} else {
+				t.Errorf("no check result for %s", instAddr)
+			}
+		})
+	}
+}
+
+func TestContext2Plan_dataResourceChecksManagedResourceChange(t *testing.T) {
+	// This tests the situation where the remote system contains data that
+	// isn't valid per a data resource postcondition, but that the
+	// configuration is destined to make the remote system valid during apply
+	// and so we must defer reading the data resource and checking its
+	// conditions until the apply step.
+	//
+	// This is an exception to the rule tested in
+	// TestContext2Plan_dataReferencesResourceIndirectly which is relevant
+	// whenever there's at least one precondition or postcondition attached
+	// to a data resource.
+	//
+	// See TestContext2Plan_managedResourceChecksOtherManagedResourceChange for
+	// an incorrect situation where a data resource is used only indirectly
+	// to drive a precondition elsewhere, which therefore doesn't achieve this
+	// special exception.
+
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_resource": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {
+							Type:     cty.String,
+							Computed: true,
+						},
+						"valid": {
+							Type:     cty.Bool,
+							Required: true,
+						},
+					},
+				},
+			},
+		},
+		DataSources: map[string]providers.Schema{
+			"test_data_source": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {
+							Type:     cty.String,
+							Required: true,
+						},
+						"valid": {
+							Type:     cty.Bool,
+							Computed: true,
+						},
+					},
+				},
+			},
+		},
+	}
+	var mu sync.Mutex
+	validVal := cty.False
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+		// NOTE: This assumes that the prior state declared below will have
+		// "valid" set to false already, and thus will match validVal above.
+		resp.NewState = req.PriorState
+		return resp
+	}
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+		cfg := req.Config.AsValueMap()
+		mu.Lock()
+		cfg["valid"] = validVal
+		mu.Unlock()
+		resp.State = cty.ObjectVal(cfg)
+		return resp
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		cfg := req.Config.AsValueMap()
+		prior := req.PriorState.AsValueMap()
+		resp.PlannedState = cty.ObjectVal(map[string]cty.Value{
+			"id":    prior["id"],
+			"valid": cfg["valid"],
+		})
+		return resp
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		planned := req.PlannedState.AsValueMap()
+
+		mu.Lock()
+		validVal = planned["valid"]
+		mu.Unlock()
+
+		resp.NewState = req.PlannedState
+		return resp
+	}
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+
+resource "test_resource" "a" {
+	valid = true
+}
+
+locals {
+	# NOTE: We intentionally read through a local value here to make sure
+	# that this behavior still works even if there isn't a direct dependency
+	# between the data resource and the managed resource.
+	object_id = test_resource.a.id
+}
+
+data "test_data_source" "a" {
+	id = local.object_id
+
+	lifecycle {
+		postcondition {
+			condition     = self.valid
+			error_message = "Not valid!"
+		}
+	}
+}
+`})
+
+	managedAddr := mustResourceInstanceAddr(`test_resource.a`)
+	dataAddr := mustResourceInstanceAddr(`data.test_data_source.a`)
+
+	// This state is intended to represent the outcome of a previous apply that
+	// failed due to postcondition failure but had already updated the
+	// relevant object to be invalid.
+	//
+	// It could also potentially represent a similar situation where the
+	// previous apply succeeded but there has been a change outside of
+	// Terraform that made it invalid, although technically in that scenario
+	// the state data would become invalid only during the planning step. For
+	// our purposes here that's close enough because we don't have a real
+	// remote system in place anyway.
+	priorState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			managedAddr,
+			&states.ResourceInstanceObjectSrc{
+				// NOTE: "valid" is false here but is true in the configuration
+				// above, which is intended to represent that applying the
+				// configuration change would make this object become valid.
+				AttrsJSON: []byte(`{"id":"boop","valid":false}`),
+				Status:    states.ObjectReady,
+			}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+		)
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, priorState, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if rc := plan.Changes.ResourceInstance(dataAddr); rc != nil {
+		if got, want := rc.Action, plans.Read; got != want {
+			t.Errorf("wrong action for %s\ngot:  %s\nwant: %s", dataAddr, got, want)
+		}
+		if got, want := rc.ActionReason, plans.ResourceInstanceReadBecauseDependencyPending; got != want {
+			t.Errorf("wrong action reason for %s\ngot:  %s\nwant: %s", dataAddr, got, want)
+		}
+	} else {
+		t.Fatalf("no planned change for %s", dataAddr)
+	}
+
+	if rc := plan.Changes.ResourceInstance(managedAddr); rc != nil {
+		if got, want := rc.Action, plans.Update; got != want {
+			t.Errorf("wrong action for %s\ngot:  %s\nwant: %s", managedAddr, got, want)
+		}
+		if got, want := rc.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason for %s\ngot:  %s\nwant: %s", managedAddr, got, want)
+		}
+	} else {
+		t.Fatalf("no planned change for %s", managedAddr)
+	}
+
+	// This is primarily a plan-time test, since the special handling of
+	// data resources is a plan-time concern, but we'll still try applying the
+	// plan here just to make sure it's valid.
+	newState, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	if rs := newState.ResourceInstance(dataAddr); rs != nil {
+		if !rs.HasCurrent() {
+			t.Errorf("no final state for %s", dataAddr)
+		}
+	} else {
+		t.Errorf("no final state for %s", dataAddr)
+	}
+
+	if rs := newState.ResourceInstance(managedAddr); rs != nil {
+		if !rs.HasCurrent() {
+			t.Errorf("no final state for %s", managedAddr)
+		}
+	} else {
+		t.Errorf("no final state for %s", managedAddr)
+	}
+
+	if got, want := validVal, cty.True; got != want {
+		t.Errorf("wrong final valid value\ngot:  %#v\nwant: %#v", got, want)
+	}
+
+}
+
+func TestContext2Plan_managedResourceChecksOtherManagedResourceChange(t *testing.T) {
+	// This tests the incorrect situation where a managed resource checks
+	// another managed resource indirectly via a data resource.
+	// This doesn't work because Terraform can't tell that the data resource
+	// outcome will be updated by a separate managed resource change and so
+	// we expect it to fail.
+	// This would ideally have worked except that we previously included a
+	// special case in the rules for data resources where they only consider
+	// direct dependencies when deciding whether to defer (except when the
+	// data resource itself has conditions) and so they can potentially
+	// read "too early" if the user creates the explicitly-not-recommended
+	// situation of a data resource and a managed resource in the same
+	// configuration both representing the same remote object.
+
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_resource": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {
+							Type:     cty.String,
+							Computed: true,
+						},
+						"valid": {
+							Type:     cty.Bool,
+							Required: true,
+						},
+					},
+				},
+			},
+		},
+		DataSources: map[string]providers.Schema{
+			"test_data_source": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {
+							Type:     cty.String,
+							Required: true,
+						},
+						"valid": {
+							Type:     cty.Bool,
+							Computed: true,
+						},
+					},
+				},
+			},
+		},
+	}
+	var mu sync.Mutex
+	validVal := cty.False
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+		// NOTE: This assumes that the prior state declared below will have
+		// "valid" set to false already, and thus will match validVal above.
+		resp.NewState = req.PriorState
+		return resp
+	}
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+		cfg := req.Config.AsValueMap()
+		if cfg["id"].AsString() == "main" {
+			mu.Lock()
+			cfg["valid"] = validVal
+			mu.Unlock()
+		}
+		resp.State = cty.ObjectVal(cfg)
+		return resp
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		cfg := req.Config.AsValueMap()
+		prior := req.PriorState.AsValueMap()
+		resp.PlannedState = cty.ObjectVal(map[string]cty.Value{
+			"id":    prior["id"],
+			"valid": cfg["valid"],
+		})
+		return resp
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		planned := req.PlannedState.AsValueMap()
+
+		if planned["id"].AsString() == "main" {
+			mu.Lock()
+			validVal = planned["valid"]
+			mu.Unlock()
+		}
+
+		resp.NewState = req.PlannedState
+		return resp
+	}
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+
+resource "test_resource" "a" {
+  valid = true
+}
+
+locals {
+	# NOTE: We intentionally read through a local value here because a
+	# direct reference from data.test_data_source.a to test_resource.a would
+	# cause Terraform to defer the data resource to the apply phase due to
+	# there being a pending change for the managed resource. We're explicitly
+	# testing the failure case where the data resource read happens too
+	# eagerly, which is what results from the reference being only indirect
+	# so Terraform can't "see" that the data resource result might be affected
+	# by changes to the managed resource.
+	object_id = test_resource.a.id
+}
+
+data "test_data_source" "a" {
+	id = local.object_id
+}
+
+resource "test_resource" "b" {
+	valid = true
+
+	lifecycle {
+		precondition {
+			condition     = data.test_data_source.a.valid
+			error_message = "Not valid!"
+		}
+	}
+}
+`})
+
+	managedAddrA := mustResourceInstanceAddr(`test_resource.a`)
+	managedAddrB := mustResourceInstanceAddr(`test_resource.b`)
+
+	// This state is intended to represent the outcome of a previous apply that
+	// failed due to postcondition failure but had already updated the
+	// relevant object to be invalid.
+	//
+	// It could also potentially represent a similar situation where the
+	// previous apply succeeded but there has been a change outside of
+	// Terraform that made it invalid, although technically in that scenario
+	// the state data would become invalid only during the planning step. For
+	// our purposes here that's close enough because we don't have a real
+	// remote system in place anyway.
+	priorState := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			managedAddrA,
+			&states.ResourceInstanceObjectSrc{
+				// NOTE: "valid" is false here but is true in the configuration
+				// above, which is intended to represent that applying the
+				// configuration change would make this object become valid.
+				AttrsJSON: []byte(`{"id":"main","valid":false}`),
+				Status:    states.ObjectReady,
+			}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+		)
+		s.SetResourceInstanceCurrent(
+			managedAddrB,
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"id":"checker","valid":true}`),
+				Status:    states.ObjectReady,
+			}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+		)
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, priorState, DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("unexpected successful plan; should've failed with non-passing precondition")
+	}
+
+	if got, want := diags.Err().Error(), "Resource precondition failed: Not valid!"; !strings.Contains(got, want) {
+		t.Errorf("Missing expected error message\ngot: %s\nwant substring: %s", got, want)
+	}
+}
+
+func TestContext2Plan_destroyWithRefresh(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{Block: simpleTestSchema()},
+		ResourceTypes: map[string]providers.Schema{
+			"test_object": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"arg": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	// This is called from the first instance of this provider, so we can't
+	// check p.ReadResourceCalled after plan.
+	readResourceCalled := false
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+		readResourceCalled = true
+		newVal, err := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) {
+			if len(path) == 1 && path[0] == (cty.GetAttrStep{Name: "arg"}) {
+				return cty.StringVal("current"), nil
+			}
+			return v, nil
+		})
+		if err != nil {
+			// shouldn't get here
+			t.Fatalf("ReadResourceFn transform failed")
+			return providers.ReadResourceResponse{}
+		}
+		return providers.ReadResourceResponse{
+			NewState: newVal,
+		}
+	}
+
+	upgradeResourceStateCalled := false
+	p.UpgradeResourceStateFn = func(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
+		upgradeResourceStateCalled = true
+		t.Logf("UpgradeResourceState %s", req.RawStateJSON)
+
+		// In the destroy-with-refresh codepath we end up calling
+		// UpgradeResourceState twice, because we do so once during refreshing
+		// (as part making a normal plan) and then again during the plan-destroy
+		// walk. The second call recieves the result of the earlier refresh,
+		// so we need to tolerate both "before" and "current" as possible
+		// inputs here.
+		if !bytes.Contains(req.RawStateJSON, []byte("before")) {
+			if !bytes.Contains(req.RawStateJSON, []byte("current")) {
+				t.Fatalf("UpgradeResourceState request doesn't contain the 'before' object or the 'current' object\n%s", req.RawStateJSON)
+			}
+		}
+
+		// We'll put something different in "arg" as part of upgrading, just
+		// so that we can verify below that PrevRunState contains the upgraded
+		// (but NOT refreshed) version of the object.
+		resp.UpgradedState = cty.ObjectVal(map[string]cty.Value{
+			"arg": cty.StringVal("upgraded"),
+		})
+		return resp
+	}
+
+	addr := mustResourceInstanceAddr("test_object.a")
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{"arg":"before"}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode:        plans.DestroyMode,
+		SkipRefresh: false, // the default
+	})
+	assertNoErrors(t, diags)
+
+	if !upgradeResourceStateCalled {
+		t.Errorf("Provider's UpgradeResourceState wasn't called; should've been")
+	}
+	if !readResourceCalled {
+		t.Errorf("Provider's ReadResource wasn't called; should've been")
+	}
+
+	if plan.PriorState == nil {
+		t.Fatal("missing plan state")
+	}
+
+	for _, c := range plan.Changes.Resources {
+		if c.Action != plans.Delete {
+			t.Errorf("unexpected %s change for %s", c.Action, c.Addr)
+		}
+	}
+
+	if instState := plan.PrevRunState.ResourceInstance(addr); instState == nil {
+		t.Errorf("%s has no previous run state at all after plan", addr)
+	} else {
+		if instState.Current == nil {
+			t.Errorf("%s has no current object in the previous run state", addr)
+		} else if got, want := instState.Current.AttrsJSON, `"upgraded"`; !bytes.Contains(got, []byte(want)) {
+			t.Errorf("%s has wrong previous run state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want)
+		}
+	}
+	if instState := plan.PriorState.ResourceInstance(addr); instState == nil {
+		t.Errorf("%s has no prior state at all after plan", addr)
+	} else {
+		if instState.Current == nil {
+			t.Errorf("%s has no current object in the prior state", addr)
+		} else if got, want := instState.Current.AttrsJSON, `"current"`; !bytes.Contains(got, []byte(want)) {
+			t.Errorf("%s has wrong prior state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want)
+		}
+	}
+}
+
+func TestContext2Plan_destroySkipRefresh(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{Block: simpleTestSchema()},
+		ResourceTypes: map[string]providers.Schema{
+			"test_object": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"arg": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+		t.Helper()
+		t.Errorf("unexpected call to ReadResource")
+		resp.NewState = req.PriorState
+		return resp
+	}
+	p.UpgradeResourceStateFn = func(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
+		t.Logf("UpgradeResourceState %s", req.RawStateJSON)
+		// We should've been given the prior state JSON as our input to upgrade.
+		if !bytes.Contains(req.RawStateJSON, []byte("before")) {
+			t.Fatalf("UpgradeResourceState request doesn't contain the 'before' object\n%s", req.RawStateJSON)
+		}
+
+		// We'll put something different in "arg" as part of upgrading, just
+		// so that we can verify below that PrevRunState contains the upgraded
+		// (but NOT refreshed) version of the object.
+		resp.UpgradedState = cty.ObjectVal(map[string]cty.Value{
+			"arg": cty.StringVal("upgraded"),
+		})
+		return resp
+	}
+
+	addr := mustResourceInstanceAddr("test_object.a")
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{"arg":"before"}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode:        plans.DestroyMode,
+		SkipRefresh: true,
+	})
+	assertNoErrors(t, diags)
+
+	if !p.UpgradeResourceStateCalled {
+		t.Errorf("Provider's UpgradeResourceState wasn't called; should've been")
+	}
+	if p.ReadResourceCalled {
+		t.Errorf("Provider's ReadResource was called; shouldn't have been")
+	}
+
+	if plan.PriorState == nil {
+		t.Fatal("missing plan state")
+	}
+
+	for _, c := range plan.Changes.Resources {
+		if c.Action != plans.Delete {
+			t.Errorf("unexpected %s change for %s", c.Action, c.Addr)
+		}
+	}
+
+	if instState := plan.PrevRunState.ResourceInstance(addr); instState == nil {
+		t.Errorf("%s has no previous run state at all after plan", addr)
+	} else {
+		if instState.Current == nil {
+			t.Errorf("%s has no current object in the previous run state", addr)
+		} else if got, want := instState.Current.AttrsJSON, `"upgraded"`; !bytes.Contains(got, []byte(want)) {
+			t.Errorf("%s has wrong previous run state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want)
+		}
+	}
+	if instState := plan.PriorState.ResourceInstance(addr); instState == nil {
+		t.Errorf("%s has no prior state at all after plan", addr)
+	} else {
+		if instState.Current == nil {
+			t.Errorf("%s has no current object in the prior state", addr)
+		} else if got, want := instState.Current.AttrsJSON, `"upgraded"`; !bytes.Contains(got, []byte(want)) {
+			// NOTE: The prior state should still have been _upgraded_, even
+			// though we skipped running refresh after upgrading it.
+			t.Errorf("%s has wrong prior state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want)
+		}
+	}
+}
+
+func TestContext2Plan_unmarkingSensitiveAttributeForOutput(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_resource" "foo" {
+}
+
+output "result" {
+  value = nonsensitive(test_resource.foo.sensitive_attr)
+}
+`,
+	})
+
+	p := new(MockProvider)
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"sensitive_attr": {
+						Type:      cty.String,
+						Computed:  true,
+						Sensitive: true,
+					},
+				},
+			},
+		},
+	})
+
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: cty.UnknownVal(cty.Object(map[string]cty.Type{
+				"id":             cty.String,
+				"sensitive_attr": cty.String,
+			})),
+		}
+	}
+
+	state := states.NewState()
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected create, got: %q %s", res.Addr, res.Action)
+		}
+	}
+}
+
+func TestContext2Plan_destroyNoProviderConfig(t *testing.T) {
+	// providers do not need to be configured during a destroy plan
+	p := simpleMockProvider()
+	p.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
+		v := req.Config.GetAttr("test_string")
+		if v.IsNull() || !v.IsKnown() || v.AsString() != "ok" {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("invalid provider configuration: %#v", req.Config))
+		}
+		return resp
+	}
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+locals {
+  value = "ok"
+}
+
+provider "test" {
+  test_string = local.value
+}
+`,
+	})
+
+	addr := mustResourceInstanceAddr("test_object.a")
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{"test_string":"foo"}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+}
+
+func TestContext2Plan_movedResourceBasic(t *testing.T) {
+	addrA := mustResourceInstanceAddr("test_object.a")
+	addrB := mustResourceInstanceAddr("test_object.b")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+			resource "test_object" "b" {
+			}
+
+			moved {
+				from = test_object.a
+				to   = test_object.b
+			}
+		`,
+	})
+
+	state := states.BuildState(func(s *states.SyncState) {
+		// The prior state tracks test_object.a, which we should treat as
+		// test_object.b because of the "moved" block in the config.
+		s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		ForceReplace: []addrs.AbsResourceInstance{
+			addrA,
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	t.Run(addrA.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addrA)
+		if instPlan != nil {
+			t.Fatalf("unexpected plan for %s; should've moved to %s", addrA, addrB)
+		}
+	})
+	t.Run(addrB.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addrB)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addrB)
+		}
+
+		if got, want := instPlan.Addr, addrB; !got.Equal(want) {
+			t.Errorf("wrong current address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.PrevRunAddr, addrA; !got.Equal(want) {
+			t.Errorf("wrong previous run address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.Action, plans.NoOp; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+}
+
+func TestContext2Plan_movedResourceCollision(t *testing.T) {
+	addrNoKey := mustResourceInstanceAddr("test_object.a")
+	addrZeroKey := mustResourceInstanceAddr("test_object.a[0]")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+			resource "test_object" "a" {
+				# No "count" set, so test_object.a[0] will want
+				# to implicitly move to test_object.a, but will get
+				# blocked by the existing object at that address.
+			}
+		`,
+	})
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(addrNoKey, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+		s.SetResourceInstanceCurrent(addrZeroKey, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	// We should have a warning, though! We'll lightly abuse the "for RPC"
+	// feature of diagnostics to get some more-readily-comparable diagnostic
+	// values.
+	gotDiags := diags.ForRPC()
+	wantDiags := tfdiags.Diagnostics{
+		tfdiags.Sourceless(
+			tfdiags.Warning,
+			"Unresolved resource instance address changes",
+			`Terraform tried to adjust resource instance addresses in the prior state based on change information recorded in the configuration, but some adjustments did not succeed due to existing objects already at the intended addresses:
+  - test_object.a[0] could not move to test_object.a
+
+Terraform has planned to destroy these objects. If Terraform's proposed changes aren't appropriate, you must first resolve the conflicts using the "terraform state" subcommands and then create a new plan.`,
+		),
+	}.ForRPC()
+	if diff := cmp.Diff(wantDiags, gotDiags); diff != "" {
+		t.Errorf("wrong diagnostics\n%s", diff)
+	}
+
+	t.Run(addrNoKey.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addrNoKey)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addrNoKey)
+		}
+
+		if got, want := instPlan.Addr, addrNoKey; !got.Equal(want) {
+			t.Errorf("wrong current address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.PrevRunAddr, addrNoKey; !got.Equal(want) {
+			t.Errorf("wrong previous run address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.Action, plans.NoOp; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run(addrZeroKey.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addrZeroKey)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addrZeroKey)
+		}
+
+		if got, want := instPlan.Addr, addrZeroKey; !got.Equal(want) {
+			t.Errorf("wrong current address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.PrevRunAddr, addrZeroKey; !got.Equal(want) {
+			t.Errorf("wrong previous run address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.Action, plans.Delete; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceDeleteBecauseWrongRepetition; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+}
+
+func TestContext2Plan_movedResourceCollisionDestroy(t *testing.T) {
+	// This is like TestContext2Plan_movedResourceCollision but intended to
+	// ensure we still produce the expected warning (and produce it only once)
+	// when we're creating a destroy plan, rather than a normal plan.
+	// (This case is interesting at the time of writing because we happen to
+	// use a normal plan as a trick to refresh before creating a destroy plan.
+	// This test will probably become uninteresting if a future change to
+	// the destroy-time planning behavior handles refreshing in a different
+	// way, which avoids this pre-processing step of running a normal plan
+	// first.)
+
+	addrNoKey := mustResourceInstanceAddr("test_object.a")
+	addrZeroKey := mustResourceInstanceAddr("test_object.a[0]")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+			resource "test_object" "a" {
+				# No "count" set, so test_object.a[0] will want
+				# to implicitly move to test_object.a, but will get
+				# blocked by the existing object at that address.
+			}
+		`,
+	})
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(addrNoKey, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+		s.SetResourceInstanceCurrent(addrZeroKey, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	// We should have a warning, though! We'll lightly abuse the "for RPC"
+	// feature of diagnostics to get some more-readily-comparable diagnostic
+	// values.
+	gotDiags := diags.ForRPC()
+	wantDiags := tfdiags.Diagnostics{
+		tfdiags.Sourceless(
+			tfdiags.Warning,
+			"Unresolved resource instance address changes",
+			// NOTE: This message is _lightly_ confusing in the destroy case,
+			// because it says "Terraform has planned to destroy these objects"
+			// but this is a plan to destroy all objects, anyway. We expect the
+			// conflict situation to be pretty rare though, and even rarer in
+			// a "terraform destroy", so we'll just live with that for now
+			// unless we see evidence that lots of folks are being confused by
+			// it in practice.
+			`Terraform tried to adjust resource instance addresses in the prior state based on change information recorded in the configuration, but some adjustments did not succeed due to existing objects already at the intended addresses:
+  - test_object.a[0] could not move to test_object.a
+
+Terraform has planned to destroy these objects. If Terraform's proposed changes aren't appropriate, you must first resolve the conflicts using the "terraform state" subcommands and then create a new plan.`,
+		),
+	}.ForRPC()
+	if diff := cmp.Diff(wantDiags, gotDiags); diff != "" {
+		// If we get here with a diff that makes it seem like the above warning
+		// is being reported twice, the likely cause is not correctly handling
+		// the warnings from the hidden normal plan we run as part of preparing
+		// for a destroy plan, unless that strategy has changed in the meantime
+		// since we originally wrote this test.
+		t.Errorf("wrong diagnostics\n%s", diff)
+	}
+
+	t.Run(addrNoKey.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addrNoKey)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addrNoKey)
+		}
+
+		if got, want := instPlan.Addr, addrNoKey; !got.Equal(want) {
+			t.Errorf("wrong current address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.PrevRunAddr, addrNoKey; !got.Equal(want) {
+			t.Errorf("wrong previous run address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.Action, plans.Delete; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run(addrZeroKey.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addrZeroKey)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addrZeroKey)
+		}
+
+		if got, want := instPlan.Addr, addrZeroKey; !got.Equal(want) {
+			t.Errorf("wrong current address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.PrevRunAddr, addrZeroKey; !got.Equal(want) {
+			t.Errorf("wrong previous run address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.Action, plans.Delete; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+}
+
+func TestContext2Plan_movedResourceUntargeted(t *testing.T) {
+	addrA := mustResourceInstanceAddr("test_object.a")
+	addrB := mustResourceInstanceAddr("test_object.b")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+			resource "test_object" "b" {
+			}
+
+			moved {
+				from = test_object.a
+				to   = test_object.b
+			}
+		`,
+	})
+
+	state := states.BuildState(func(s *states.SyncState) {
+		// The prior state tracks test_object.a, which we should treat as
+		// test_object.b because of the "moved" block in the config.
+		s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	t.Run("without targeting instance A", func(t *testing.T) {
+		_, diags := ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.NormalMode,
+			Targets: []addrs.Targetable{
+				// NOTE: addrA isn't included here, but it's pending move to addrB
+				// and so this plan request is invalid.
+				addrB,
+			},
+		})
+		diags.Sort()
+
+		// We're semi-abusing "ForRPC" here just to get diagnostics that are
+		// more easily comparable than the various different diagnostics types
+		// tfdiags uses internally. The RPC-friendly diagnostics are also
+		// comparison-friendly, by discarding all of the dynamic type information.
+		gotDiags := diags.ForRPC()
+		wantDiags := tfdiags.Diagnostics{
+			tfdiags.Sourceless(
+				tfdiags.Warning,
+				"Resource targeting is in effect",
+				`You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current configuration.
+
+The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`,
+			),
+			tfdiags.Sourceless(
+				tfdiags.Error,
+				"Moved resource instances excluded by targeting",
+				`Resource instances in your current state have moved to new addresses in the latest configuration. Terraform must include those resource instances while planning in order to ensure a correct result, but your -target=... options do not fully cover all of those resource instances.
+
+To create a valid plan, either remove your -target=... options altogether or add the following additional target options:
+  -target="test_object.a"
+
+Note that adding these options may include further additional resource instances in your plan, in order to respect object dependencies.`,
+			),
+		}.ForRPC()
+
+		if diff := cmp.Diff(wantDiags, gotDiags); diff != "" {
+			t.Errorf("wrong diagnostics\n%s", diff)
+		}
+	})
+	t.Run("without targeting instance B", func(t *testing.T) {
+		_, diags := ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.NormalMode,
+			Targets: []addrs.Targetable{
+				addrA,
+				// NOTE: addrB isn't included here, but it's pending move from
+				// addrA and so this plan request is invalid.
+			},
+		})
+		diags.Sort()
+
+		// We're semi-abusing "ForRPC" here just to get diagnostics that are
+		// more easily comparable than the various different diagnostics types
+		// tfdiags uses internally. The RPC-friendly diagnostics are also
+		// comparison-friendly, by discarding all of the dynamic type information.
+		gotDiags := diags.ForRPC()
+		wantDiags := tfdiags.Diagnostics{
+			tfdiags.Sourceless(
+				tfdiags.Warning,
+				"Resource targeting is in effect",
+				`You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current configuration.
+
+The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`,
+			),
+			tfdiags.Sourceless(
+				tfdiags.Error,
+				"Moved resource instances excluded by targeting",
+				`Resource instances in your current state have moved to new addresses in the latest configuration. Terraform must include those resource instances while planning in order to ensure a correct result, but your -target=... options do not fully cover all of those resource instances.
+
+To create a valid plan, either remove your -target=... options altogether or add the following additional target options:
+  -target="test_object.b"
+
+Note that adding these options may include further additional resource instances in your plan, in order to respect object dependencies.`,
+			),
+		}.ForRPC()
+
+		if diff := cmp.Diff(wantDiags, gotDiags); diff != "" {
+			t.Errorf("wrong diagnostics\n%s", diff)
+		}
+	})
+	t.Run("without targeting either instance", func(t *testing.T) {
+		_, diags := ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.NormalMode,
+			Targets: []addrs.Targetable{
+				mustResourceInstanceAddr("test_object.unrelated"),
+				// NOTE: neither addrA nor addrB are included here, but there's
+				// a pending move between them and so this is invalid.
+			},
+		})
+		diags.Sort()
+
+		// We're semi-abusing "ForRPC" here just to get diagnostics that are
+		// more easily comparable than the various different diagnostics types
+		// tfdiags uses internally. The RPC-friendly diagnostics are also
+		// comparison-friendly, by discarding all of the dynamic type information.
+		gotDiags := diags.ForRPC()
+		wantDiags := tfdiags.Diagnostics{
+			tfdiags.Sourceless(
+				tfdiags.Warning,
+				"Resource targeting is in effect",
+				`You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current configuration.
+
+The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`,
+			),
+			tfdiags.Sourceless(
+				tfdiags.Error,
+				"Moved resource instances excluded by targeting",
+				`Resource instances in your current state have moved to new addresses in the latest configuration. Terraform must include those resource instances while planning in order to ensure a correct result, but your -target=... options do not fully cover all of those resource instances.
+
+To create a valid plan, either remove your -target=... options altogether or add the following additional target options:
+  -target="test_object.a"
+  -target="test_object.b"
+
+Note that adding these options may include further additional resource instances in your plan, in order to respect object dependencies.`,
+			),
+		}.ForRPC()
+
+		if diff := cmp.Diff(wantDiags, gotDiags); diff != "" {
+			t.Errorf("wrong diagnostics\n%s", diff)
+		}
+	})
+	t.Run("with both addresses in the target set", func(t *testing.T) {
+		// The error messages in the other subtests above suggest adding
+		// addresses to the set of targets. This additional test makes sure that
+		// following that advice actually leads to a valid result.
+
+		_, diags := ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.NormalMode,
+			Targets: []addrs.Targetable{
+				// This time we're including both addresses in the target,
+				// to get the same effect an end-user would get if following
+				// the advice in our error message in the other subtests.
+				addrA,
+				addrB,
+			},
+		})
+		diags.Sort()
+
+		// We're semi-abusing "ForRPC" here just to get diagnostics that are
+		// more easily comparable than the various different diagnostics types
+		// tfdiags uses internally. The RPC-friendly diagnostics are also
+		// comparison-friendly, by discarding all of the dynamic type information.
+		gotDiags := diags.ForRPC()
+		wantDiags := tfdiags.Diagnostics{
+			// Still get the warning about the -target option...
+			tfdiags.Sourceless(
+				tfdiags.Warning,
+				"Resource targeting is in effect",
+				`You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current configuration.
+
+The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`,
+			),
+			// ...but now we have no error about test_object.a
+		}.ForRPC()
+
+		if diff := cmp.Diff(wantDiags, gotDiags); diff != "" {
+			t.Errorf("wrong diagnostics\n%s", diff)
+		}
+	})
+}
+
+func TestContext2Plan_untargetedResourceSchemaChange(t *testing.T) {
+	// an untargeted resource which requires a schema migration should not
+	// block planning due external changes in the plan.
+	addrA := mustResourceInstanceAddr("test_object.a")
+	addrB := mustResourceInstanceAddr("test_object.b")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+}
+resource "test_object" "b" {
+}`,
+	})
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+		s.SetResourceInstanceCurrent(addrB, &states.ResourceInstanceObjectSrc{
+			// old_list is no longer in the schema
+			AttrsJSON: []byte(`{"old_list":["used to be","a list here"]}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	p := simpleMockProvider()
+
+	// external changes trigger a "drift report", but because test_object.b was
+	// not targeted, the state was not fixed to match the schema and cannot be
+	// deocded for the report.
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+		obj := req.PriorState.AsValueMap()
+		// test_number changed externally
+		obj["test_number"] = cty.NumberIntVal(1)
+		resp.NewState = cty.ObjectVal(obj)
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrA,
+		},
+	})
+	//
+	assertNoErrors(t, diags)
+}
+
+func TestContext2Plan_movedResourceRefreshOnly(t *testing.T) {
+	addrA := mustResourceInstanceAddr("test_object.a")
+	addrB := mustResourceInstanceAddr("test_object.b")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+			resource "test_object" "b" {
+			}
+
+			moved {
+				from = test_object.a
+				to   = test_object.b
+			}
+		`,
+	})
+
+	state := states.BuildState(func(s *states.SyncState) {
+		// The prior state tracks test_object.a, which we should treat as
+		// test_object.b because of the "moved" block in the config.
+		s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.RefreshOnlyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	t.Run(addrA.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addrA)
+		if instPlan != nil {
+			t.Fatalf("unexpected plan for %s; should've moved to %s", addrA, addrB)
+		}
+	})
+	t.Run(addrB.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addrB)
+		if instPlan != nil {
+			t.Fatalf("unexpected plan for %s", addrB)
+		}
+	})
+	t.Run("drift", func(t *testing.T) {
+		var drifted *plans.ResourceInstanceChangeSrc
+		for _, dr := range plan.DriftedResources {
+			if dr.Addr.Equal(addrB) {
+				drifted = dr
+				break
+			}
+		}
+
+		if drifted == nil {
+			t.Fatalf("instance %s is missing from the drifted resource changes", addrB)
+		}
+
+		if got, want := drifted.PrevRunAddr, addrA; !got.Equal(want) {
+			t.Errorf("wrong previous run address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := drifted.Action, plans.NoOp; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+}
+
+func TestContext2Plan_refreshOnlyMode(t *testing.T) {
+	addr := mustResourceInstanceAddr("test_object.a")
+
+	// The configuration, the prior state, and the refresh result intentionally
+	// have different values for "test_string" so we can observe that the
+	// refresh took effect but the configuration change wasn't considered.
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+			resource "test_object" "a" {
+				arg = "after"
+			}
+
+			output "out" {
+				value = test_object.a.arg
+			}
+		`,
+	})
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{"arg":"before"}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	p := simpleMockProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{Block: simpleTestSchema()},
+		ResourceTypes: map[string]providers.Schema{
+			"test_object": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"arg": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		newVal, err := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) {
+			if len(path) == 1 && path[0] == (cty.GetAttrStep{Name: "arg"}) {
+				return cty.StringVal("current"), nil
+			}
+			return v, nil
+		})
+		if err != nil {
+			// shouldn't get here
+			t.Fatalf("ReadResourceFn transform failed")
+			return providers.ReadResourceResponse{}
+		}
+		return providers.ReadResourceResponse{
+			NewState: newVal,
+		}
+	}
+	p.UpgradeResourceStateFn = func(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
+		// We should've been given the prior state JSON as our input to upgrade.
+		if !bytes.Contains(req.RawStateJSON, []byte("before")) {
+			t.Fatalf("UpgradeResourceState request doesn't contain the 'before' object\n%s", req.RawStateJSON)
+		}
+
+		// We'll put something different in "arg" as part of upgrading, just
+		// so that we can verify below that PrevRunState contains the upgraded
+		// (but NOT refreshed) version of the object.
+		resp.UpgradedState = cty.ObjectVal(map[string]cty.Value{
+			"arg": cty.StringVal("upgraded"),
+		})
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.RefreshOnlyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	if !p.UpgradeResourceStateCalled {
+		t.Errorf("Provider's UpgradeResourceState wasn't called; should've been")
+	}
+	if !p.ReadResourceCalled {
+		t.Errorf("Provider's ReadResource wasn't called; should've been")
+	}
+
+	if got, want := len(plan.Changes.Resources), 0; got != want {
+		t.Errorf("plan contains resource changes; want none\n%s", spew.Sdump(plan.Changes.Resources))
+	}
+
+	if instState := plan.PriorState.ResourceInstance(addr); instState == nil {
+		t.Errorf("%s has no prior state at all after plan", addr)
+	} else {
+		if instState.Current == nil {
+			t.Errorf("%s has no current object after plan", addr)
+		} else if got, want := instState.Current.AttrsJSON, `"current"`; !bytes.Contains(got, []byte(want)) {
+			// Should've saved the result of refreshing
+			t.Errorf("%s has wrong prior state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want)
+		}
+	}
+	if instState := plan.PrevRunState.ResourceInstance(addr); instState == nil {
+		t.Errorf("%s has no previous run state at all after plan", addr)
+	} else {
+		if instState.Current == nil {
+			t.Errorf("%s has no current object in the previous run state", addr)
+		} else if got, want := instState.Current.AttrsJSON, `"upgraded"`; !bytes.Contains(got, []byte(want)) {
+			// Should've saved the result of upgrading
+			t.Errorf("%s has wrong previous run state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want)
+		}
+	}
+
+	// The output value should also have updated. If not, it's likely that we
+	// skipped updating the working state to match the refreshed state when we
+	// were evaluating the resource.
+	if outChangeSrc := plan.Changes.OutputValue(addrs.RootModuleInstance.OutputValue("out")); outChangeSrc == nil {
+		t.Errorf("no change planned for output value 'out'")
+	} else {
+		outChange, err := outChangeSrc.Decode()
+		if err != nil {
+			t.Fatalf("failed to decode output value 'out': %s", err)
+		}
+		got := outChange.After
+		want := cty.StringVal("current")
+		if !want.RawEquals(got) {
+			t.Errorf("wrong value for output value 'out'\ngot:  %#v\nwant: %#v", got, want)
+		}
+	}
+}
+
+func TestContext2Plan_refreshOnlyMode_deposed(t *testing.T) {
+	addr := mustResourceInstanceAddr("test_object.a")
+	deposedKey := states.DeposedKey("byebye")
+
+	// The configuration, the prior state, and the refresh result intentionally
+	// have different values for "test_string" so we can observe that the
+	// refresh took effect but the configuration change wasn't considered.
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+			resource "test_object" "a" {
+				arg = "after"
+			}
+
+			output "out" {
+				value = test_object.a.arg
+			}
+		`,
+	})
+	state := states.BuildState(func(s *states.SyncState) {
+		// Note that we're intentionally recording a _deposed_ object here,
+		// and not including a current object, so a normal (non-refresh)
+		// plan would normally plan to create a new object _and_ destroy
+		// the deposed one, but refresh-only mode should prevent that.
+		s.SetResourceInstanceDeposed(addr, deposedKey, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{"arg":"before"}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	p := simpleMockProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{Block: simpleTestSchema()},
+		ResourceTypes: map[string]providers.Schema{
+			"test_object": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"arg": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		newVal, err := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) {
+			if len(path) == 1 && path[0] == (cty.GetAttrStep{Name: "arg"}) {
+				return cty.StringVal("current"), nil
+			}
+			return v, nil
+		})
+		if err != nil {
+			// shouldn't get here
+			t.Fatalf("ReadResourceFn transform failed")
+			return providers.ReadResourceResponse{}
+		}
+		return providers.ReadResourceResponse{
+			NewState: newVal,
+		}
+	}
+	p.UpgradeResourceStateFn = func(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
+		// We should've been given the prior state JSON as our input to upgrade.
+		if !bytes.Contains(req.RawStateJSON, []byte("before")) {
+			t.Fatalf("UpgradeResourceState request doesn't contain the 'before' object\n%s", req.RawStateJSON)
+		}
+
+		// We'll put something different in "arg" as part of upgrading, just
+		// so that we can verify below that PrevRunState contains the upgraded
+		// (but NOT refreshed) version of the object.
+		resp.UpgradedState = cty.ObjectVal(map[string]cty.Value{
+			"arg": cty.StringVal("upgraded"),
+		})
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.RefreshOnlyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	if !p.UpgradeResourceStateCalled {
+		t.Errorf("Provider's UpgradeResourceState wasn't called; should've been")
+	}
+	if !p.ReadResourceCalled {
+		t.Errorf("Provider's ReadResource wasn't called; should've been")
+	}
+
+	if got, want := len(plan.Changes.Resources), 0; got != want {
+		t.Errorf("plan contains resource changes; want none\n%s", spew.Sdump(plan.Changes.Resources))
+	}
+
+	if instState := plan.PriorState.ResourceInstance(addr); instState == nil {
+		t.Errorf("%s has no prior state at all after plan", addr)
+	} else {
+		if obj := instState.Deposed[deposedKey]; obj == nil {
+			t.Errorf("%s has no deposed object after plan", addr)
+		} else if got, want := obj.AttrsJSON, `"current"`; !bytes.Contains(got, []byte(want)) {
+			// Should've saved the result of refreshing
+			t.Errorf("%s has wrong prior state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want)
+		}
+	}
+	if instState := plan.PrevRunState.ResourceInstance(addr); instState == nil {
+		t.Errorf("%s has no previous run state at all after plan", addr)
+	} else {
+		if obj := instState.Deposed[deposedKey]; obj == nil {
+			t.Errorf("%s has no deposed object in the previous run state", addr)
+		} else if got, want := obj.AttrsJSON, `"upgraded"`; !bytes.Contains(got, []byte(want)) {
+			// Should've saved the result of upgrading
+			t.Errorf("%s has wrong previous run state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want)
+		}
+	}
+
+	// The output value should also have updated. If not, it's likely that we
+	// skipped updating the working state to match the refreshed state when we
+	// were evaluating the resource.
+	if outChangeSrc := plan.Changes.OutputValue(addrs.RootModuleInstance.OutputValue("out")); outChangeSrc == nil {
+		t.Errorf("no change planned for output value 'out'")
+	} else {
+		outChange, err := outChangeSrc.Decode()
+		if err != nil {
+			t.Fatalf("failed to decode output value 'out': %s", err)
+		}
+		got := outChange.After
+		want := cty.UnknownVal(cty.String)
+		if !want.RawEquals(got) {
+			t.Errorf("wrong value for output value 'out'\ngot:  %#v\nwant: %#v", got, want)
+		}
+	}
+
+	// Deposed objects should not be represented in drift.
+	if len(plan.DriftedResources) > 0 {
+		t.Errorf("unexpected drifted resources (%d)", len(plan.DriftedResources))
+	}
+}
+
+func TestContext2Plan_refreshOnlyMode_orphan(t *testing.T) {
+	addr := mustAbsResourceAddr("test_object.a")
+
+	// The configuration, the prior state, and the refresh result intentionally
+	// have different values for "test_string" so we can observe that the
+	// refresh took effect but the configuration change wasn't considered.
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+			resource "test_object" "a" {
+				arg = "after"
+				count = 1
+			}
+
+			output "out" {
+				value = test_object.a.*.arg
+			}
+		`,
+	})
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(addr.Instance(addrs.IntKey(0)), &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{"arg":"before"}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+		s.SetResourceInstanceCurrent(addr.Instance(addrs.IntKey(1)), &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{"arg":"before"}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	p := simpleMockProvider()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{Block: simpleTestSchema()},
+		ResourceTypes: map[string]providers.Schema{
+			"test_object": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"arg": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		newVal, err := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) {
+			if len(path) == 1 && path[0] == (cty.GetAttrStep{Name: "arg"}) {
+				return cty.StringVal("current"), nil
+			}
+			return v, nil
+		})
+		if err != nil {
+			// shouldn't get here
+			t.Fatalf("ReadResourceFn transform failed")
+			return providers.ReadResourceResponse{}
+		}
+		return providers.ReadResourceResponse{
+			NewState: newVal,
+		}
+	}
+	p.UpgradeResourceStateFn = func(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
+		// We should've been given the prior state JSON as our input to upgrade.
+		if !bytes.Contains(req.RawStateJSON, []byte("before")) {
+			t.Fatalf("UpgradeResourceState request doesn't contain the 'before' object\n%s", req.RawStateJSON)
+		}
+
+		// We'll put something different in "arg" as part of upgrading, just
+		// so that we can verify below that PrevRunState contains the upgraded
+		// (but NOT refreshed) version of the object.
+		resp.UpgradedState = cty.ObjectVal(map[string]cty.Value{
+			"arg": cty.StringVal("upgraded"),
+		})
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.RefreshOnlyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	if !p.UpgradeResourceStateCalled {
+		t.Errorf("Provider's UpgradeResourceState wasn't called; should've been")
+	}
+	if !p.ReadResourceCalled {
+		t.Errorf("Provider's ReadResource wasn't called; should've been")
+	}
+
+	if got, want := len(plan.Changes.Resources), 0; got != want {
+		t.Errorf("plan contains resource changes; want none\n%s", spew.Sdump(plan.Changes.Resources))
+	}
+
+	if rState := plan.PriorState.Resource(addr); rState == nil {
+		t.Errorf("%s has no prior state at all after plan", addr)
+	} else {
+		for i := 0; i < 2; i++ {
+			instKey := addrs.IntKey(i)
+			if obj := rState.Instance(instKey).Current; obj == nil {
+				t.Errorf("%s%s has no object after plan", addr, instKey)
+			} else if got, want := obj.AttrsJSON, `"current"`; !bytes.Contains(got, []byte(want)) {
+				// Should've saved the result of refreshing
+				t.Errorf("%s%s has wrong prior state after plan\ngot:\n%s\n\nwant substring: %s", addr, instKey, got, want)
+			}
+		}
+	}
+	if rState := plan.PrevRunState.Resource(addr); rState == nil {
+		t.Errorf("%s has no prior state at all after plan", addr)
+	} else {
+		for i := 0; i < 2; i++ {
+			instKey := addrs.IntKey(i)
+			if obj := rState.Instance(instKey).Current; obj == nil {
+				t.Errorf("%s%s has no object after plan", addr, instKey)
+			} else if got, want := obj.AttrsJSON, `"upgraded"`; !bytes.Contains(got, []byte(want)) {
+				// Should've saved the result of upgrading
+				t.Errorf("%s%s has wrong prior state after plan\ngot:\n%s\n\nwant substring: %s", addr, instKey, got, want)
+			}
+		}
+	}
+
+	// The output value should also have updated. If not, it's likely that we
+	// skipped updating the working state to match the refreshed state when we
+	// were evaluating the resource.
+	if outChangeSrc := plan.Changes.OutputValue(addrs.RootModuleInstance.OutputValue("out")); outChangeSrc == nil {
+		t.Errorf("no change planned for output value 'out'")
+	} else {
+		outChange, err := outChangeSrc.Decode()
+		if err != nil {
+			t.Fatalf("failed to decode output value 'out': %s", err)
+		}
+		got := outChange.After
+		want := cty.TupleVal([]cty.Value{cty.StringVal("current"), cty.StringVal("current")})
+		if !want.RawEquals(got) {
+			t.Errorf("wrong value for output value 'out'\ngot:  %#v\nwant: %#v", got, want)
+		}
+	}
+}
+
+func TestContext2Plan_invalidSensitiveModuleOutput(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"child/main.tf": `
+output "out" {
+  value = sensitive("xyz")
+}`,
+		"main.tf": `
+module "child" {
+  source = "./child"
+}
+
+output "root" {
+  value = module.child.out
+}`,
+	})
+
+	ctx := testContext2(t, &ContextOpts{})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatal("succeeded; want errors")
+	}
+	if got, want := diags.Err().Error(), "Output refers to sensitive values"; !strings.Contains(got, want) {
+		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
+	}
+}
+
+func TestContext2Plan_planDataSourceSensitiveNested(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_instance" "bar" {
+}
+
+data "test_data_source" "foo" {
+  foo {
+    bar = test_instance.bar.sensitive
+  }
+}
+`,
+	})
+
+	p := new(MockProvider)
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		resp.PlannedState = cty.ObjectVal(map[string]cty.Value{
+			"sensitive": cty.UnknownVal(cty.String),
+		})
+		return resp
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"sensitive": {
+						Type:      cty.String,
+						Computed:  true,
+						Sensitive: true,
+					},
+				},
+			},
+		},
+		DataSources: map[string]*configschema.Block{
+			"test_data_source": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {Type: cty.String, Optional: true},
+							},
+						},
+						Nesting: configschema.NestingSet,
+					},
+				},
+			},
+		},
+	})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("data.test_data_source.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"string":"data_id", "foo":[{"bar":"old"}]}`),
+			AttrSensitivePaths: []cty.PathValueMarks{
+				{
+					Path:  cty.GetAttrPath("foo"),
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"sensitive":"old"}`),
+			AttrSensitivePaths: []cty.PathValueMarks{
+				{
+					Path:  cty.GetAttrPath("sensitive"),
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	for _, res := range plan.Changes.Resources {
+		switch res.Addr.String() {
+		case "test_instance.bar":
+			if res.Action != plans.Update {
+				t.Fatalf("unexpected %s change for %s", res.Action, res.Addr)
+			}
+		case "data.test_data_source.foo":
+			if res.Action != plans.Read {
+				t.Fatalf("unexpected %s change for %s", res.Action, res.Addr)
+			}
+		default:
+			t.Fatalf("unexpected %s change for %s", res.Action, res.Addr)
+		}
+	}
+}
+
+func TestContext2Plan_forceReplace(t *testing.T) {
+	addrA := mustResourceInstanceAddr("test_object.a")
+	addrB := mustResourceInstanceAddr("test_object.b")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+			resource "test_object" "a" {
+			}
+			resource "test_object" "b" {
+			}
+		`,
+	})
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+		s.SetResourceInstanceCurrent(addrB, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		ForceReplace: []addrs.AbsResourceInstance{
+			addrA,
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	t.Run(addrA.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addrA)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addrA)
+		}
+
+		if got, want := instPlan.Action, plans.DeleteThenCreate; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceReplaceByRequest; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run(addrB.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addrB)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addrB)
+		}
+
+		if got, want := instPlan.Action, plans.NoOp; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+}
+
+func TestContext2Plan_forceReplaceIncompleteAddr(t *testing.T) {
+	addr0 := mustResourceInstanceAddr("test_object.a[0]")
+	addr1 := mustResourceInstanceAddr("test_object.a[1]")
+	addrBare := mustResourceInstanceAddr("test_object.a")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+			resource "test_object" "a" {
+				count = 2
+			}
+		`,
+	})
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(addr0, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+		s.SetResourceInstanceCurrent(addr1, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		ForceReplace: []addrs.AbsResourceInstance{
+			addrBare,
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+	diagsErr := diags.ErrWithWarnings()
+	if diagsErr == nil {
+		t.Fatalf("no warnings were returned")
+	}
+	if got, want := diagsErr.Error(), "Incompletely-matched force-replace resource instance"; !strings.Contains(got, want) {
+		t.Errorf("missing expected warning\ngot:\n%s\n\nwant substring: %s", got, want)
+	}
+
+	t.Run(addr0.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addr0)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addr0)
+		}
+
+		if got, want := instPlan.Action, plans.NoOp; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run(addr1.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addr1)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addr1)
+		}
+
+		if got, want := instPlan.Action, plans.NoOp; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+}
+
+// Verify that adding a module instance does force existing module data sources
+// to be deferred
+func TestContext2Plan_noChangeDataSourceAddingModuleInstance(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+locals {
+  data = {
+    a = "a"
+    b = "b"
+  }
+}
+
+module "one" {
+  source   = "./mod"
+  for_each = local.data
+  input = each.value
+}
+
+module "two" {
+  source   = "./mod"
+  for_each = module.one
+  input = each.value.output
+}
+`,
+		"mod/main.tf": `
+variable "input" {
+}
+
+resource "test_resource" "x" {
+  value = var.input
+}
+
+data "test_data_source" "d" {
+  foo = test_resource.x.id
+}
+
+output "output" {
+  value = test_resource.x.id
+}
+`,
+	})
+
+	p := testProvider("test")
+	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+		State: cty.ObjectVal(map[string]cty.Value{
+			"id":  cty.StringVal("data"),
+			"foo": cty.StringVal("foo"),
+		}),
+	}
+	state := states.NewState()
+	modOne := addrs.RootModuleInstance.Child("one", addrs.StringKey("a"))
+	modTwo := addrs.RootModuleInstance.Child("two", addrs.StringKey("a"))
+	one := state.EnsureModule(modOne)
+	two := state.EnsureModule(modTwo)
+	one.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr(`test_resource.x`).Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo","value":"a"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	one.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr(`data.test_data_source.d`).Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"data"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	two.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr(`test_resource.x`).Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo","value":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	two.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr(`data.test_data_source.d`).Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"data"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	for _, res := range plan.Changes.Resources {
+		// both existing data sources should be read during plan
+		if res.Addr.Module[0].InstanceKey == addrs.StringKey("b") {
+			continue
+		}
+
+		if res.Addr.Resource.Resource.Mode == addrs.DataResourceMode && res.Action != plans.NoOp {
+			t.Errorf("unexpected %s plan for %s", res.Action, res.Addr)
+		}
+	}
+}
+
+func TestContext2Plan_moduleExpandOrphansResourceInstance(t *testing.T) {
+	// This test deals with the situation where a user has changed the
+	// repetition/expansion mode for a module call while there are already
+	// resource instances from the previous declaration in the state.
+	//
+	// This is conceptually just the same as removing the resources
+	// from the module configuration only for that instance, but the
+	// implementation of it ends up a little different because it's
+	// an entry in the resource address's _module path_ that we'll find
+	// missing, rather than the resource's own instance key, and so
+	// our analyses need to handle that situation by indicating that all
+	// of the resources under the missing module instance have zero
+	// instances, regardless of which resource in that module we might
+	// be asking about, and do so without tripping over any missing
+	// registrations in the instance expander that might lead to panics
+	// if we aren't careful.
+	//
+	// (For some history here, see https://github.com/hashicorp/terraform/issues/30110 )
+
+	addrNoKey := mustResourceInstanceAddr("module.child.test_object.a[0]")
+	addrZeroKey := mustResourceInstanceAddr("module.child[0].test_object.a[0]")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+			module "child" {
+				source = "./child"
+				count = 1
+			}
+		`,
+		"child/main.tf": `
+			resource "test_object" "a" {
+				count = 1
+			}
+		`,
+	})
+
+	state := states.BuildState(func(s *states.SyncState) {
+		// Notice that addrNoKey is the address which lacks any instance key
+		// for module.child, and so that module instance doesn't match the
+		// call declared above with count = 1, and therefore the resource
+		// inside is "orphaned" even though the resource block actually
+		// still exists there.
+		s.SetResourceInstanceCurrent(addrNoKey, &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	t.Run(addrNoKey.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addrNoKey)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addrNoKey)
+		}
+
+		if got, want := instPlan.Addr, addrNoKey; !got.Equal(want) {
+			t.Errorf("wrong current address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.PrevRunAddr, addrNoKey; !got.Equal(want) {
+			t.Errorf("wrong previous run address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.Action, plans.Delete; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceDeleteBecauseNoModule; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+
+	t.Run(addrZeroKey.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addrZeroKey)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addrZeroKey)
+		}
+
+		if got, want := instPlan.Addr, addrZeroKey; !got.Equal(want) {
+			t.Errorf("wrong current address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.PrevRunAddr, addrZeroKey; !got.Equal(want) {
+			t.Errorf("wrong previous run address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.Action, plans.Create; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+}
+
+func TestContext2Plan_resourcePreconditionPostcondition(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "boop" {
+  type = string
+}
+
+resource "test_resource" "a" {
+  value = var.boop
+  lifecycle {
+    precondition {
+      condition     = var.boop == "boop"
+      error_message = "Wrong boop."
+    }
+    postcondition {
+      condition     = self.output != ""
+      error_message = "Output must not be blank."
+    }
+  }
+}
+
+`,
+	})
+
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"value": {
+						Type:     cty.String,
+						Required: true,
+					},
+					"output": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	t.Run("conditions pass", func(t *testing.T) {
+		p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+			m := req.ProposedNewState.AsValueMap()
+			m["output"] = cty.StringVal("bar")
+
+			resp.PlannedState = cty.ObjectVal(m)
+			resp.LegacyTypeSystem = true
+			return resp
+		}
+		plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("boop"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+		for _, res := range plan.Changes.Resources {
+			switch res.Addr.String() {
+			case "test_resource.a":
+				if res.Action != plans.Create {
+					t.Fatalf("unexpected %s change for %s", res.Action, res.Addr)
+				}
+			default:
+				t.Fatalf("unexpected %s change for %s", res.Action, res.Addr)
+			}
+		}
+	})
+
+	t.Run("precondition fail", func(t *testing.T) {
+		_, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("nope"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		if !diags.HasErrors() {
+			t.Fatal("succeeded; want errors")
+		}
+		if got, want := diags.Err().Error(), "Resource precondition failed: Wrong boop."; got != want {
+			t.Fatalf("wrong error:\ngot:  %s\nwant: %q", got, want)
+		}
+		if p.PlanResourceChangeCalled {
+			t.Errorf("Provider's PlanResourceChange was called; should'nt've been")
+		}
+	})
+
+	t.Run("precondition fail refresh-only", func(t *testing.T) {
+		state := states.BuildState(func(s *states.SyncState) {
+			s.SetResourceInstanceCurrent(mustResourceInstanceAddr("test_resource.a"), &states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"value":"boop","output":"blorp"}`),
+				Status:    states.ObjectReady,
+			}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+		})
+		_, diags := ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.RefreshOnlyMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("nope"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+		if len(diags) == 0 {
+			t.Fatalf("no diags, but should have warnings")
+		}
+		if got, want := diags.ErrWithWarnings().Error(), "Resource precondition failed: Wrong boop."; got != want {
+			t.Fatalf("wrong warning:\ngot:  %s\nwant: %q", got, want)
+		}
+		if !p.ReadResourceCalled {
+			t.Errorf("Provider's ReadResource wasn't called; should've been")
+		}
+	})
+
+	t.Run("postcondition fail", func(t *testing.T) {
+		p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+			m := req.ProposedNewState.AsValueMap()
+			m["output"] = cty.StringVal("")
+
+			resp.PlannedState = cty.ObjectVal(m)
+			resp.LegacyTypeSystem = true
+			return resp
+		}
+		_, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("boop"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		if !diags.HasErrors() {
+			t.Fatal("succeeded; want errors")
+		}
+		if got, want := diags.Err().Error(), "Resource postcondition failed: Output must not be blank."; got != want {
+			t.Fatalf("wrong error:\ngot:  %s\nwant: %q", got, want)
+		}
+		if !p.PlanResourceChangeCalled {
+			t.Errorf("Provider's PlanResourceChange wasn't called; should've been")
+		}
+	})
+
+	t.Run("postcondition fail refresh-only", func(t *testing.T) {
+		state := states.BuildState(func(s *states.SyncState) {
+			s.SetResourceInstanceCurrent(mustResourceInstanceAddr("test_resource.a"), &states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"value":"boop","output":"blorp"}`),
+				Status:    states.ObjectReady,
+			}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+		})
+		p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+			newVal, err := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) {
+				if len(path) == 1 && path[0] == (cty.GetAttrStep{Name: "output"}) {
+					return cty.StringVal(""), nil
+				}
+				return v, nil
+			})
+			if err != nil {
+				// shouldn't get here
+				t.Fatalf("ReadResourceFn transform failed")
+				return providers.ReadResourceResponse{}
+			}
+			return providers.ReadResourceResponse{
+				NewState: newVal,
+			}
+		}
+		_, diags := ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.RefreshOnlyMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("boop"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+		if len(diags) == 0 {
+			t.Fatalf("no diags, but should have warnings")
+		}
+		if got, want := diags.ErrWithWarnings().Error(), "Resource postcondition failed: Output must not be blank."; got != want {
+			t.Fatalf("wrong warning:\ngot:  %s\nwant: %q", got, want)
+		}
+		if !p.ReadResourceCalled {
+			t.Errorf("Provider's ReadResource wasn't called; should've been")
+		}
+		if p.PlanResourceChangeCalled {
+			t.Errorf("Provider's PlanResourceChange was called; should'nt've been")
+		}
+	})
+
+	t.Run("precondition and postcondition fail refresh-only", func(t *testing.T) {
+		state := states.BuildState(func(s *states.SyncState) {
+			s.SetResourceInstanceCurrent(mustResourceInstanceAddr("test_resource.a"), &states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"value":"boop","output":"blorp"}`),
+				Status:    states.ObjectReady,
+			}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+		})
+		p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+			newVal, err := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) {
+				if len(path) == 1 && path[0] == (cty.GetAttrStep{Name: "output"}) {
+					return cty.StringVal(""), nil
+				}
+				return v, nil
+			})
+			if err != nil {
+				// shouldn't get here
+				t.Fatalf("ReadResourceFn transform failed")
+				return providers.ReadResourceResponse{}
+			}
+			return providers.ReadResourceResponse{
+				NewState: newVal,
+			}
+		}
+		_, diags := ctx.Plan(m, state, &PlanOpts{
+			Mode: plans.RefreshOnlyMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("nope"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+		if got, want := len(diags), 2; got != want {
+			t.Errorf("wrong number of warnings, got %d, want %d", got, want)
+		}
+		warnings := diags.ErrWithWarnings().Error()
+		wantWarnings := []string{
+			"Resource precondition failed: Wrong boop.",
+			"Resource postcondition failed: Output must not be blank.",
+		}
+		for _, want := range wantWarnings {
+			if !strings.Contains(warnings, want) {
+				t.Errorf("missing warning:\ngot:  %s\nwant to contain: %q", warnings, want)
+			}
+		}
+		if !p.ReadResourceCalled {
+			t.Errorf("Provider's ReadResource wasn't called; should've been")
+		}
+		if p.PlanResourceChangeCalled {
+			t.Errorf("Provider's PlanResourceChange was called; should'nt've been")
+		}
+	})
+}
+
+func TestContext2Plan_dataSourcePreconditionPostcondition(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "boop" {
+  type = string
+}
+
+data "test_data_source" "a" {
+  foo = var.boop
+  lifecycle {
+    precondition {
+      condition     = var.boop == "boop"
+      error_message = "Wrong boop."
+    }
+    postcondition {
+      condition     = length(self.results) > 0
+      error_message = "Results cannot be empty."
+    }
+  }
+}
+
+resource "test_resource" "a" {
+  value    = data.test_data_source.a.results[0]
+}
+`,
+	})
+
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"value": {
+						Type:     cty.String,
+						Required: true,
+					},
+				},
+			},
+		},
+		DataSources: map[string]*configschema.Block{
+			"test_data_source": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Required: true,
+					},
+					"results": {
+						Type:     cty.List(cty.String),
+						Computed: true,
+					},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	t.Run("conditions pass", func(t *testing.T) {
+		p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(map[string]cty.Value{
+				"foo":     cty.StringVal("boop"),
+				"results": cty.ListVal([]cty.Value{cty.StringVal("boop")}),
+			}),
+		}
+		plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("boop"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+		for _, res := range plan.Changes.Resources {
+			switch res.Addr.String() {
+			case "test_resource.a":
+				if res.Action != plans.Create {
+					t.Fatalf("unexpected %s change for %s", res.Action, res.Addr)
+				}
+			case "data.test_data_source.a":
+				if res.Action != plans.Read {
+					t.Fatalf("unexpected %s change for %s", res.Action, res.Addr)
+				}
+			default:
+				t.Fatalf("unexpected %s change for %s", res.Action, res.Addr)
+			}
+		}
+
+		addr := mustResourceInstanceAddr("data.test_data_source.a")
+		if gotResult := plan.Checks.GetObjectResult(addr); gotResult == nil {
+			t.Errorf("no check result for %s", addr)
+		} else {
+			wantResult := &states.CheckResultObject{
+				Status: checks.StatusPass,
+			}
+			if diff := cmp.Diff(wantResult, gotResult, valueComparer); diff != "" {
+				t.Errorf("wrong check result for %s\n%s", addr, diff)
+			}
+		}
+	})
+
+	t.Run("precondition fail", func(t *testing.T) {
+		_, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("nope"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		if !diags.HasErrors() {
+			t.Fatal("succeeded; want errors")
+		}
+		if got, want := diags.Err().Error(), "Resource precondition failed: Wrong boop."; got != want {
+			t.Fatalf("wrong error:\ngot:  %s\nwant: %q", got, want)
+		}
+		if p.ReadDataSourceCalled {
+			t.Errorf("Provider's ReadResource was called; should'nt've been")
+		}
+	})
+
+	t.Run("precondition fail refresh-only", func(t *testing.T) {
+		plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.RefreshOnlyMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("nope"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+		if len(diags) == 0 {
+			t.Fatalf("no diags, but should have warnings")
+		}
+		if got, want := diags.ErrWithWarnings().Error(), "Resource precondition failed: Wrong boop."; got != want {
+			t.Fatalf("wrong warning:\ngot:  %s\nwant: %q", got, want)
+		}
+		for _, res := range plan.Changes.Resources {
+			switch res.Addr.String() {
+			case "test_resource.a":
+				if res.Action != plans.Create {
+					t.Fatalf("unexpected %s change for %s", res.Action, res.Addr)
+				}
+			case "data.test_data_source.a":
+				if res.Action != plans.Read {
+					t.Fatalf("unexpected %s change for %s", res.Action, res.Addr)
+				}
+			default:
+				t.Fatalf("unexpected %s change for %s", res.Action, res.Addr)
+			}
+		}
+	})
+
+	t.Run("postcondition fail", func(t *testing.T) {
+		p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(map[string]cty.Value{
+				"foo":     cty.StringVal("boop"),
+				"results": cty.ListValEmpty(cty.String),
+			}),
+		}
+		_, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("boop"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		if !diags.HasErrors() {
+			t.Fatal("succeeded; want errors")
+		}
+		if got, want := diags.Err().Error(), "Resource postcondition failed: Results cannot be empty."; got != want {
+			t.Fatalf("wrong error:\ngot:  %s\nwant: %q", got, want)
+		}
+		if !p.ReadDataSourceCalled {
+			t.Errorf("Provider's ReadDataSource wasn't called; should've been")
+		}
+	})
+
+	t.Run("postcondition fail refresh-only", func(t *testing.T) {
+		p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(map[string]cty.Value{
+				"foo":     cty.StringVal("boop"),
+				"results": cty.ListValEmpty(cty.String),
+			}),
+		}
+		plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.RefreshOnlyMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("boop"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+		if got, want := diags.ErrWithWarnings().Error(), "Resource postcondition failed: Results cannot be empty."; got != want {
+			t.Fatalf("wrong error:\ngot:  %s\nwant: %q", got, want)
+		}
+		addr := mustResourceInstanceAddr("data.test_data_source.a")
+		if gotResult := plan.Checks.GetObjectResult(addr); gotResult == nil {
+			t.Errorf("no check result for %s", addr)
+		} else {
+			wantResult := &states.CheckResultObject{
+				Status: checks.StatusFail,
+				FailureMessages: []string{
+					"Results cannot be empty.",
+				},
+			}
+			if diff := cmp.Diff(wantResult, gotResult, valueComparer); diff != "" {
+				t.Errorf("wrong check result\n%s", diff)
+			}
+		}
+	})
+
+	t.Run("precondition and postcondition fail refresh-only", func(t *testing.T) {
+		p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(map[string]cty.Value{
+				"foo":     cty.StringVal("nope"),
+				"results": cty.ListValEmpty(cty.String),
+			}),
+		}
+		_, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.RefreshOnlyMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("nope"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+		if got, want := len(diags), 2; got != want {
+			t.Errorf("wrong number of warnings, got %d, want %d", got, want)
+		}
+		warnings := diags.ErrWithWarnings().Error()
+		wantWarnings := []string{
+			"Resource precondition failed: Wrong boop.",
+			"Resource postcondition failed: Results cannot be empty.",
+		}
+		for _, want := range wantWarnings {
+			if !strings.Contains(warnings, want) {
+				t.Errorf("missing warning:\ngot:  %s\nwant to contain: %q", warnings, want)
+			}
+		}
+	})
+}
+
+func TestContext2Plan_outputPrecondition(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "boop" {
+  type = string
+}
+
+output "a" {
+  value = var.boop
+  precondition {
+    condition     = var.boop == "boop"
+    error_message = "Wrong boop."
+  }
+}
+`,
+	})
+
+	p := testProvider("test")
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	t.Run("condition pass", func(t *testing.T) {
+		plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("boop"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+		addr := addrs.RootModuleInstance.OutputValue("a")
+		outputPlan := plan.Changes.OutputValue(addr)
+		if outputPlan == nil {
+			t.Fatalf("no plan for %s at all", addr)
+		}
+		if got, want := outputPlan.Addr, addr; !got.Equal(want) {
+			t.Errorf("wrong current address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := outputPlan.Action, plans.Create; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if gotResult := plan.Checks.GetObjectResult(addr); gotResult == nil {
+			t.Errorf("no check result for %s", addr)
+		} else {
+			wantResult := &states.CheckResultObject{
+				Status: checks.StatusPass,
+			}
+			if diff := cmp.Diff(wantResult, gotResult, valueComparer); diff != "" {
+				t.Errorf("wrong check result\n%s", diff)
+			}
+		}
+	})
+
+	t.Run("condition fail", func(t *testing.T) {
+		_, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.NormalMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("nope"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		if !diags.HasErrors() {
+			t.Fatal("succeeded; want errors")
+		}
+		if got, want := diags.Err().Error(), "Module output value precondition failed: Wrong boop."; got != want {
+			t.Fatalf("wrong error:\ngot:  %s\nwant: %q", got, want)
+		}
+	})
+
+	t.Run("condition fail refresh-only", func(t *testing.T) {
+		plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+			Mode: plans.RefreshOnlyMode,
+			SetVariables: InputValues{
+				"boop": &InputValue{
+					Value:      cty.StringVal("nope"),
+					SourceType: ValueFromCLIArg,
+				},
+			},
+		})
+		assertNoErrors(t, diags)
+		if len(diags) == 0 {
+			t.Fatalf("no diags, but should have warnings")
+		}
+		if got, want := diags.ErrWithWarnings().Error(), "Module output value precondition failed: Wrong boop."; got != want {
+			t.Errorf("wrong warning:\ngot:  %s\nwant: %q", got, want)
+		}
+		addr := addrs.RootModuleInstance.OutputValue("a")
+		outputPlan := plan.Changes.OutputValue(addr)
+		if outputPlan == nil {
+			t.Fatalf("no plan for %s at all", addr)
+		}
+		if got, want := outputPlan.Addr, addr; !got.Equal(want) {
+			t.Errorf("wrong current address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := outputPlan.Action, plans.Create; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if gotResult := plan.Checks.GetObjectResult(addr); gotResult == nil {
+			t.Errorf("no condition result for %s", addr)
+		} else {
+			wantResult := &states.CheckResultObject{
+				Status:          checks.StatusFail,
+				FailureMessages: []string{"Wrong boop."},
+			}
+			if diff := cmp.Diff(wantResult, gotResult, valueComparer); diff != "" {
+				t.Errorf("wrong condition result\n%s", diff)
+			}
+		}
+	})
+}
+
+func TestContext2Plan_preconditionErrors(t *testing.T) {
+	testCases := []struct {
+		condition   string
+		wantSummary string
+		wantDetail  string
+	}{
+		{
+			"data.test_data_source",
+			"Invalid reference",
+			`The "data" object must be followed by two attribute names`,
+		},
+		{
+			"self.value",
+			`Invalid "self" reference`,
+			"only in resource provisioner, connection, and postcondition blocks",
+		},
+		{
+			"data.foo.bar",
+			"Reference to undeclared resource",
+			`A data resource "foo" "bar" has not been declared in the root module`,
+		},
+		{
+			"test_resource.b.value",
+			"Invalid condition result",
+			"Condition expression must return either true or false",
+		},
+		{
+			"test_resource.c.value",
+			"Invalid condition result",
+			"Invalid condition result value: a bool is required",
+		},
+	}
+
+	p := testProvider("test")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	for _, tc := range testCases {
+		t.Run(tc.condition, func(t *testing.T) {
+			main := fmt.Sprintf(`
+			resource "test_resource" "a" {
+				value = var.boop
+				lifecycle {
+					precondition {
+						condition     = %s
+						error_message = "Not relevant."
+					}
+				}
+			}
+
+			resource "test_resource" "b" {
+				value = null
+			}
+
+			resource "test_resource" "c" {
+				value = "bar"
+			}
+			`, tc.condition)
+			m := testModuleInline(t, map[string]string{"main.tf": main})
+
+			plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+			if !diags.HasErrors() {
+				t.Fatal("succeeded; want errors")
+			}
+
+			if !plan.Errored {
+				t.Fatal("plan failed to record error")
+			}
+
+			diag := diags[0]
+			if got, want := diag.Description().Summary, tc.wantSummary; got != want {
+				t.Errorf("unexpected summary\n got: %s\nwant: %s", got, want)
+			}
+			if got, want := diag.Description().Detail, tc.wantDetail; !strings.Contains(got, want) {
+				t.Errorf("unexpected summary\ngot: %s\nwant to contain %q", got, want)
+			}
+
+			for _, kv := range plan.Checks.ConfigResults.Elements() {
+				// All these are configuration or evaluation errors
+				if kv.Value.Status != checks.StatusError {
+					t.Errorf("incorrect status, got %s", kv.Value.Status)
+				}
+			}
+		})
+	}
+}
+
+func TestContext2Plan_preconditionSensitiveValues(t *testing.T) {
+	p := testProvider("test")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "boop" {
+  sensitive = true
+  type      = string
+}
+
+output "a" {
+  sensitive = true
+  value     = var.boop
+
+  precondition {
+    condition     = length(var.boop) <= 4
+    error_message = "Boop is too long, ${length(var.boop)} > 4"
+  }
+}
+`,
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"boop": &InputValue{
+				Value:      cty.StringVal("bleep"),
+				SourceType: ValueFromCLIArg,
+			},
+		},
+	})
+	if !diags.HasErrors() {
+		t.Fatal("succeeded; want errors")
+	}
+	if got, want := len(diags), 2; got != want {
+		t.Errorf("wrong number of diags, got %d, want %d", got, want)
+	}
+	for _, diag := range diags {
+		desc := diag.Description()
+		if desc.Summary == "Module output value precondition failed" {
+			if got, want := desc.Detail, "This check failed, but has an invalid error message as described in the other accompanying messages."; !strings.Contains(got, want) {
+				t.Errorf("unexpected detail\ngot: %s\nwant to contain %q", got, want)
+			}
+		} else if desc.Summary == "Error message refers to sensitive values" {
+			if got, want := desc.Detail, "The error expression used to explain this condition refers to sensitive values, so Terraform will not display the resulting message."; !strings.Contains(got, want) {
+				t.Errorf("unexpected detail\ngot: %s\nwant to contain %q", got, want)
+			}
+		} else {
+			t.Errorf("unexpected summary\ngot: %s", desc.Summary)
+		}
+	}
+}
+
+func TestContext2Plan_triggeredBy(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+  count = 1
+  test_string = "new"
+}
+resource "test_object" "b" {
+  count = 1
+  test_string = test_object.a[count.index].test_string
+  lifecycle {
+    # the change to test_string in the other resource should trigger replacement
+    replace_triggered_by = [ test_object.a[count.index].test_string ]
+  }
+}
+`,
+	})
+
+	p := simpleMockProvider()
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			mustResourceInstanceAddr("test_object.a[0]"),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{"test_string":"old"}`),
+				Status:    states.ObjectReady,
+			},
+			mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+		)
+		s.SetResourceInstanceCurrent(
+			mustResourceInstanceAddr("test_object.b[0]"),
+			&states.ResourceInstanceObjectSrc{
+				AttrsJSON: []byte(`{}`),
+				Status:    states.ObjectReady,
+			},
+			mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+		)
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+	for _, c := range plan.Changes.Resources {
+		switch c.Addr.String() {
+		case "test_object.a[0]":
+			if c.Action != plans.Update {
+				t.Fatalf("unexpected %s change for %s\n", c.Action, c.Addr)
+			}
+		case "test_object.b[0]":
+			if c.Action != plans.DeleteThenCreate {
+				t.Fatalf("unexpected %s change for %s\n", c.Action, c.Addr)
+			}
+			if c.ActionReason != plans.ResourceInstanceReplaceByTriggers {
+				t.Fatalf("incorrect reason for change: %s\n", c.ActionReason)
+			}
+		default:
+			t.Fatal("unexpected change", c.Addr, c.Action)
+		}
+	}
+}
+
+func TestContext2Plan_dataSchemaChange(t *testing.T) {
+	// We can't decode the prior state when a data source upgrades the schema
+	// in an incompatible way. Since prior state for data sources is purely
+	// informational, decoding should be skipped altogether.
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+data "test_object" "a" {
+  obj {
+    # args changes from a list to a map
+    args = {
+      val = "string"
+	}
+  }
+}
+`,
+	})
+
+	p := new(MockProvider)
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		DataSources: map[string]*configschema.Block{
+			"test_object": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"obj": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"args": {Type: cty.Map(cty.String), Optional: true},
+							},
+						},
+						Nesting: configschema.NestingSet,
+					},
+				},
+			},
+		},
+	})
+
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+		resp.State = req.Config
+		return resp
+	}
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(mustResourceInstanceAddr(`data.test_object.a`), &states.ResourceInstanceObjectSrc{
+			AttrsJSON: []byte(`{"id":"old","obj":[{"args":["string"]}]}`),
+			Status:    states.ObjectReady,
+		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+}
+
+func TestContext2Plan_applyGraphError(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+}
+resource "test_object" "b" {
+	depends_on = [test_object.a]
+}
+`,
+	})
+
+	p := simpleMockProvider()
+
+	// Here we introduce a cycle via state which only shows up in the apply
+	// graph where the actual destroy instances are connected in the graph.
+	// This could happen for example when a user has an existing state with
+	// stored dependencies, and changes the config in such a way that
+	// contradicts the stored dependencies.
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectTainted,
+			AttrsJSON:    []byte(`{"test_string":"a"}`),
+			Dependencies: []addrs.ConfigResource{mustResourceInstanceAddr("test_object.b").ContainingResource().Config()},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.b").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"test_string":"b"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+	})
+	if !diags.HasErrors() {
+		t.Fatal("cycle error not detected")
+	}
+
+	msg := diags.ErrWithWarnings().Error()
+	if !strings.Contains(msg, "Cycle") {
+		t.Fatalf("no cycle error found:\n got: %s\n", msg)
+	}
+}
+
+// plan a destroy with no state where configuration could fail to evaluate
+// expansion indexes.
+func TestContext2Plan_emptyDestroy(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+locals {
+  enable = true
+  value  = local.enable ? module.example[0].out : null
+}
+
+module "example" {
+  count  = local.enable ? 1 : 0
+  source = "./example"
+}
+`,
+		"example/main.tf": `
+resource "test_resource" "x" {
+}
+
+output "out" {
+  value = test_resource.x
+}
+`,
+	})
+
+	p := testProvider("test")
+	state := states.NewState()
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+
+	assertNoErrors(t, diags)
+
+	// ensure that the given states are valid and can be serialized
+	if plan.PrevRunState == nil {
+		t.Fatal("nil plan.PrevRunState")
+	}
+	if plan.PriorState == nil {
+		t.Fatal("nil plan.PriorState")
+	}
+}
+
+// A deposed instances which no longer exists during ReadResource creates NoOp
+// change, which should not effect the plan.
+func TestContext2Plan_deposedNoLongerExists(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "b" {
+  count = 1
+  test_string = "updated"
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+		s := req.PriorState.GetAttr("test_string").AsString()
+		if s == "current" {
+			resp.NewState = req.PriorState
+			return resp
+		}
+		// pretend the non-current instance has been deleted already
+		resp.NewState = cty.NullVal(req.PriorState.Type())
+		return resp
+	}
+
+	// Here we introduce a cycle via state which only shows up in the apply
+	// graph where the actual destroy instances are connected in the graph.
+	// This could happen for example when a user has an existing state with
+	// stored dependencies, and changes the config in such a way that
+	// contradicts the stored dependencies.
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceDeposed(
+		mustResourceInstanceAddr("test_object.a[0]").Resource,
+		states.DeposedKey("deposed"),
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectTainted,
+			AttrsJSON:    []byte(`{"test_string":"old"}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.a[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectTainted,
+			AttrsJSON:    []byte(`{"test_string":"current"}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+	})
+	assertNoErrors(t, diags)
+}
+
+// make sure there are no cycles with changes around a provider configured via
+// managed resources.
+func TestContext2Plan_destroyWithResourceConfiguredProvider(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+  in = "a"
+}
+
+provider "test" {
+  alias = "other"
+  in = test_object.a.out
+}
+
+resource "test_object" "b" {
+  provider = test.other
+  in = "a"
+}
+`})
+
+	testProvider := &MockProvider{
+		GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+			Provider: providers.Schema{
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"in": {
+							Type:     cty.String,
+							Optional: true,
+						},
+					},
+				},
+			},
+			ResourceTypes: map[string]providers.Schema{
+				"test_object": providers.Schema{
+					Block: &configschema.Block{
+						Attributes: map[string]*configschema.Attribute{
+							"in": {
+								Type:     cty.String,
+								Optional: true,
+							},
+							"out": {
+								Type:     cty.Number,
+								Computed: true,
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(testProvider),
+		},
+	})
+
+	// plan+apply to create the initial state
+	opts := SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))
+	plan, diags := ctx.Plan(m, states.NewState(), opts)
+	assertNoErrors(t, diags)
+	state, diags := ctx.Apply(plan, m)
+	assertNoErrors(t, diags)
+
+	// Resource changes which have dependencies across providers which
+	// themselves depend on resources can result in cycles.
+	// Because other_object transitively depends on the module resources
+	// through its provider, we trigger changes on both sides of this boundary
+	// to ensure we can create a valid plan.
+	//
+	// Try to replace both instances
+	addrA := mustResourceInstanceAddr("test_object.a")
+	addrB := mustResourceInstanceAddr(`test_object.b`)
+	opts.ForceReplace = []addrs.AbsResourceInstance{addrA, addrB}
+
+	_, diags = ctx.Plan(m, state, opts)
+	assertNoErrors(t, diags)
+}
+
+func TestContext2Plan_destroyPartialState(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+}
+
+output "out" {
+  value = module.mod.out
+}
+
+module "mod" {
+  source = "./mod"
+}
+`,
+
+		"./mod/main.tf": `
+resource "test_object" "a" {
+  count = 2
+
+  lifecycle {
+    precondition {
+	  # test_object_b has already been destroyed, so referencing the first
+      # instance must not fail during a destroy plan.
+      condition = test_object.b[0].test_string == "invalid"
+      error_message = "should not block destroy"
+    }
+    precondition {
+      # this failing condition should bot block a destroy plan
+      condition = !local.continue
+      error_message = "should not block destroy"
+    }
+  }
+}
+
+resource "test_object" "b" {
+  count = 2
+}
+
+locals {
+  continue = true
+}
+
+output "out" {
+  # the reference to test_object.b[0] may not be valid during a destroy plan,
+  # but should not fail.
+  value = local.continue ? test_object.a[1].test_string != "invalid"  && test_object.b[0].test_string != "invalid" : false
+
+  precondition {
+    # test_object_b has already been destroyed, so referencing the first
+    # instance must not fail during a destroy plan.
+    condition = test_object.b[0].test_string == "invalid"
+    error_message = "should not block destroy"
+  }
+  precondition {
+    # this failing condition should bot block a destroy plan
+    condition = test_object.a[0].test_string == "invalid"
+    error_message = "should not block destroy"
+  }
+}
+`})
+
+	p := simpleMockProvider()
+
+	// This state could be the result of a failed destroy, leaving only 2
+	// remaining instances. We want to be able to continue the destroy to
+	// remove everything without blocking on invalid references or failing
+	// conditions.
+	state := states.NewState()
+	mod := state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.NoKey))
+	mod.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.a[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectTainted,
+			AttrsJSON:    []byte(`{"test_string":"current"}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	mod.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.a[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectTainted,
+			AttrsJSON:    []byte(`{"test_string":"current"}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+}
+
+func TestContext2Plan_destroyPartialStateLocalRef(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "already_destroyed" {
+  count = 1
+  source = "./mod"
+}
+
+locals {
+  eval_error = module.already_destroyed[0].out
+}
+
+output "already_destroyed" {
+  value = local.eval_error
+}
+
+`,
+
+		"./mod/main.tf": `
+resource "test_object" "a" {
+}
+
+output "out" {
+  value = test_object.a.test_string
+}
+`})
+
+	p := simpleMockProvider()
+
+	state := states.NewState()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	assertNoErrors(t, diags)
+}
+
+// Make sure the data sources in the prior state are serializeable even if
+// there were an error in the plan.
+func TestContext2Plan_dataSourceReadPlanError(t *testing.T) {
+	m, snap := testModuleWithSnapshot(t, "data-source-read-with-plan-error")
+	awsProvider := testProvider("aws")
+	testProvider := testProvider("test")
+
+	testProvider.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		resp.PlannedState = req.ProposedNewState
+		resp.Diagnostics = resp.Diagnostics.Append(errors.New("oops"))
+		return resp
+	}
+
+	state := states.NewState()
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"):  testProviderFuncFixed(awsProvider),
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(testProvider),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("expected plan error")
+	}
+
+	// make sure we can serialize the plan even if there were an error
+	_, _, _, err := contextOptsForPlanViaFile(t, snap, plan)
+	if err != nil {
+		t.Fatalf("failed to round-trip through planfile: %s", err)
+	}
+}
+
+func TestContext2Plan_ignoredMarkedValue(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+  map = {
+    prior = "value"
+    new   = sensitive("ignored")
+  }
+}
+`})
+
+	testProvider := &MockProvider{
+		GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+			ResourceTypes: map[string]providers.Schema{
+				"test_object": providers.Schema{
+					Block: &configschema.Block{
+						Attributes: map[string]*configschema.Attribute{
+							"map": {
+								Type:     cty.Map(cty.String),
+								Optional: true,
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testProvider.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		// We're going to ignore any changes here and return the prior state.
+		resp.PlannedState = req.PriorState
+		return resp
+	}
+
+	state := states.NewState()
+	root := state.RootModule()
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"map":{"prior":"value"}}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(testProvider),
+		},
+	})
+
+	// plan+apply to create the initial state
+	opts := SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))
+	plan, diags := ctx.Plan(m, state, opts)
+	assertNoErrors(t, diags)
+
+	for _, c := range plan.Changes.Resources {
+		if c.Action != plans.NoOp {
+			t.Errorf("unexpected %s change for %s", c.Action, c.Addr)
+		}
+	}
+}
+
+func TestContext2Plan_importResourceBasic(t *testing.T) {
+	addr := mustResourceInstanceAddr("test_object.a")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+  test_string = "foo"
+}
+
+import {
+  to   = test_object.a
+  id   = "123"
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	hook := new(MockHook)
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{hook},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"test_string": cty.StringVal("foo"),
+		}),
+	}
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_object",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"test_string": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	t.Run(addr.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addr)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addr)
+		}
+
+		if got, want := instPlan.Addr, addr; !got.Equal(want) {
+			t.Errorf("wrong current address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.PrevRunAddr, addr; !got.Equal(want) {
+			t.Errorf("wrong previous run address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.Action, plans.NoOp; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+		if instPlan.Importing.ID != "123" {
+			t.Errorf("expected import change from \"123\", got non-import change")
+		}
+
+		if !hook.PrePlanImportCalled {
+			t.Fatalf("PostPlanImport hook not called")
+		}
+		if addr, wantAddr := hook.PrePlanImportAddr, instPlan.Addr; !addr.Equal(wantAddr) {
+			t.Errorf("expected addr to be %s, but was %s", wantAddr, addr)
+		}
+
+		if !hook.PostPlanImportCalled {
+			t.Fatalf("PostPlanImport hook not called")
+		}
+		if addr, wantAddr := hook.PostPlanImportAddr, instPlan.Addr; !addr.Equal(wantAddr) {
+			t.Errorf("expected addr to be %s, but was %s", wantAddr, addr)
+		}
+	})
+}
+
+func TestContext2Plan_importResourceAlreadyInState(t *testing.T) {
+	addr := mustResourceInstanceAddr("test_object.a")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+  test_string = "foo"
+}
+
+import {
+  to   = test_object.a
+  id   = "123"
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"test_string": cty.StringVal("foo"),
+		}),
+	}
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_object",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"test_string": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"test_string":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	t.Run(addr.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addr)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addr)
+		}
+
+		if got, want := instPlan.Addr, addr; !got.Equal(want) {
+			t.Errorf("wrong current address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.PrevRunAddr, addr; !got.Equal(want) {
+			t.Errorf("wrong previous run address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.Action, plans.NoOp; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+		if instPlan.Importing != nil {
+			t.Errorf("expected non-import change, got import change %+v", instPlan.Importing)
+		}
+	})
+}
+
+func TestContext2Plan_importResourceUpdate(t *testing.T) {
+	addr := mustResourceInstanceAddr("test_object.a")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+  test_string = "bar"
+}
+
+import {
+  to   = test_object.a
+  id   = "123"
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"test_string": cty.StringVal("foo"),
+		}),
+	}
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_object",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"test_string": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	t.Run(addr.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addr)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addr)
+		}
+
+		if got, want := instPlan.Addr, addr; !got.Equal(want) {
+			t.Errorf("wrong current address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.PrevRunAddr, addr; !got.Equal(want) {
+			t.Errorf("wrong previous run address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.Action, plans.Update; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+		if instPlan.Importing.ID != "123" {
+			t.Errorf("expected import change from \"123\", got non-import change")
+		}
+	})
+}
+
+func TestContext2Plan_importResourceReplace(t *testing.T) {
+	addr := mustResourceInstanceAddr("test_object.a")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+  test_string = "bar"
+}
+
+import {
+  to   = test_object.a
+  id   = "123"
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"test_string": cty.StringVal("foo"),
+		}),
+	}
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_object",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"test_string": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		ForceReplace: []addrs.AbsResourceInstance{
+			addr,
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	t.Run(addr.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addr)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addr)
+		}
+
+		if got, want := instPlan.Addr, addr; !got.Equal(want) {
+			t.Errorf("wrong current address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.PrevRunAddr, addr; !got.Equal(want) {
+			t.Errorf("wrong previous run address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.Action, plans.DeleteThenCreate; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if instPlan.Importing.ID != "123" {
+			t.Errorf("expected import change from \"123\", got non-import change")
+		}
+	})
+}
+
+func TestContext2Plan_importRefreshOnce(t *testing.T) {
+	addr := mustResourceInstanceAddr("test_object.a")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+  test_string = "bar"
+}
+
+import {
+  to   = test_object.a
+  id   = "123"
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	readCalled := 0
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		readCalled++
+		state, _ := simpleTestSchema().CoerceValue(cty.ObjectVal(map[string]cty.Value{
+			"test_string": cty.StringVal("foo"),
+		}))
+
+		return providers.ReadResourceResponse{
+			NewState: state,
+		}
+	}
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_object",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"test_string": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	_, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		ForceReplace: []addrs.AbsResourceInstance{
+			addr,
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	if readCalled > 1 {
+		t.Error("ReadResource called multiple times for import")
+	}
+}
+
+func TestContext2Plan_importTargetWithKeyDoesNotExist(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_object" "a" {
+  count = 1
+  test_string = "bar"
+}
+
+import {
+  to   = test_object.a[42]
+  id   = "123"
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"test_string": cty.StringVal("foo"),
+		}),
+	}
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_object",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"test_string": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("expected error but got none")
+	}
+}
+
+func TestContext2Plan_importIntoModuleWithGeneratedConfig(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+import {
+  to = test_object.a
+  id = "123"
+}
+
+import {
+  to = module.mod.test_object.a
+  id = "456"
+}
+
+module "mod" {
+  source = "./mod"
+}
+`,
+		"./mod/main.tf": `
+resource "test_object" "a" {
+  test_string = "bar"
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"test_string": cty.StringVal("foo"),
+		}),
+	}
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_object",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"test_string": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_object",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"test_string": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode:               plans.NormalMode,
+		GenerateConfigPath: "generated.tf", // Actual value here doesn't matter, as long as it is not empty.
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	one := mustResourceInstanceAddr("test_object.a")
+	two := mustResourceInstanceAddr("module.mod.test_object.a")
+
+	onePlan := plan.Changes.ResourceInstance(one)
+	twoPlan := plan.Changes.ResourceInstance(two)
+
+	// This test is just to make sure things work e2e with modules and generated
+	// config, so we're not too careful about the actual responses - we're just
+	// happy nothing panicked. See the other import tests for actual validation
+	// of responses and the like.
+	if twoPlan.Action != plans.Update {
+		t.Errorf("expected nested item to be updated but was %s", twoPlan.Action)
+	}
+
+	if len(onePlan.GeneratedConfig) == 0 {
+		t.Errorf("expected root item to generate config but it didn't")
+	}
+}
+
+func TestContext2Plan_importResourceConfigGen(t *testing.T) {
+	addr := mustResourceInstanceAddr("test_object.a")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+import {
+  to   = test_object.a
+  id   = "123"
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"test_string": cty.StringVal("foo"),
+		}),
+	}
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_object",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"test_string": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode:               plans.NormalMode,
+		GenerateConfigPath: "generated.tf", // Actual value here doesn't matter, as long as it is not empty.
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	t.Run(addr.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addr)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addr)
+		}
+
+		if got, want := instPlan.Addr, addr; !got.Equal(want) {
+			t.Errorf("wrong current address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.PrevRunAddr, addr; !got.Equal(want) {
+			t.Errorf("wrong previous run address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.Action, plans.NoOp; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+		if instPlan.Importing.ID != "123" {
+			t.Errorf("expected import change from \"123\", got non-import change")
+		}
+
+		want := `resource "test_object" "a" {
+  test_bool   = null
+  test_list   = null
+  test_map    = null
+  test_number = null
+  test_string = "foo"
+}`
+		got := instPlan.GeneratedConfig
+		if diff := cmp.Diff(want, got); len(diff) > 0 {
+			t.Errorf("got:\n%s\nwant:\n%s\ndiff:\n%s", got, want, diff)
+		}
+	})
+}
+
+func TestContext2Plan_importResourceConfigGenWithAlias(t *testing.T) {
+	addr := mustResourceInstanceAddr("test_object.a")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+provider "test" {
+  alias = "backup"
+}
+
+import {
+  provider = test.backup
+  to       = test_object.a
+  id       = "123"
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"test_string": cty.StringVal("foo"),
+		}),
+	}
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_object",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"test_string": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode:               plans.NormalMode,
+		GenerateConfigPath: "generated.tf", // Actual value here doesn't matter, as long as it is not empty.
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors\n%s", diags.Err().Error())
+	}
+
+	t.Run(addr.String(), func(t *testing.T) {
+		instPlan := plan.Changes.ResourceInstance(addr)
+		if instPlan == nil {
+			t.Fatalf("no plan for %s at all", addr)
+		}
+
+		if got, want := instPlan.Addr, addr; !got.Equal(want) {
+			t.Errorf("wrong current address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.PrevRunAddr, addr; !got.Equal(want) {
+			t.Errorf("wrong previous run address\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.Action, plans.NoOp; got != want {
+			t.Errorf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+			t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+		}
+		if instPlan.Importing.ID != "123" {
+			t.Errorf("expected import change from \"123\", got non-import change")
+		}
+
+		want := `resource "test_object" "a" {
+  provider    = test.backup
+  test_bool   = null
+  test_list   = null
+  test_map    = null
+  test_number = null
+  test_string = "foo"
+}`
+		got := instPlan.GeneratedConfig
+		if diff := cmp.Diff(want, got); len(diff) > 0 {
+			t.Errorf("got:\n%s\nwant:\n%s\ndiff:\n%s", got, want, diff)
+		}
+	})
+}
+
+func TestContext2Plan_importResourceConfigGenExpandedResource(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+import {
+  to       = test_object.a[0]
+  id       = "123"
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"test_string": cty.StringVal("foo"),
+		}),
+	}
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_object",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"test_string": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	_, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode:               plans.NormalMode,
+		GenerateConfigPath: "generated.tf",
+	})
+	if !diags.HasErrors() {
+		t.Fatalf("expected plan to error, but it did not")
+	}
+}
+
+// config generation still succeeds even when planning fails
+func TestContext2Plan_importResourceConfigGenWithError(t *testing.T) {
+	addr := mustResourceInstanceAddr("test_object.a")
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+import {
+  to   = test_object.a
+  id   = "123"
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	p.PlanResourceChangeResponse = &providers.PlanResourceChangeResponse{
+		PlannedState: cty.NullVal(cty.DynamicPseudoType),
+		Diagnostics:  tfdiags.Diagnostics(nil).Append(errors.New("plan failed")),
+	}
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"test_string": cty.StringVal("foo"),
+		}),
+	}
+	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "test_object",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"test_string": cty.StringVal("foo"),
+				}),
+			},
+		},
+	}
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode:               plans.NormalMode,
+		GenerateConfigPath: "generated.tf", // Actual value here doesn't matter, as long as it is not empty.
+	})
+	if !diags.HasErrors() {
+		t.Fatal("expected error")
+	}
+
+	instPlan := plan.Changes.ResourceInstance(addr)
+	if instPlan == nil {
+		t.Fatalf("no plan for %s at all", addr)
+	}
+
+	want := `resource "test_object" "a" {
+  test_bool   = null
+  test_list   = null
+  test_map    = null
+  test_number = null
+  test_string = "foo"
+}`
+	got := instPlan.GeneratedConfig
+	if diff := cmp.Diff(want, got); len(diff) > 0 {
+		t.Errorf("got:\n%s\nwant:\n%s\ndiff:\n%s", got, want, diff)
+	}
+}
diff --git a/v1.5.7/internal/terraform/context_plan_test.go b/v1.5.7/internal/terraform/context_plan_test.go
new file mode 100644
index 0000000..2f9a7ff
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_plan_test.go
@@ -0,0 +1,6934 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"os"
+	"reflect"
+	"sort"
+	"strings"
+	"sync"
+	"sync/atomic"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestContext2Plan_basic(t *testing.T) {
+	m := testModule(t, "plan-good")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if l := len(plan.Changes.Resources); l < 2 {
+		t.Fatalf("wrong number of resources %d; want fewer than two\n%s", l, spew.Sdump(plan.Changes.Resources))
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+	for _, r := range plan.Changes.Resources {
+		ric, err := r.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			foo := ric.After.GetAttr("foo").AsString()
+			if foo != "2" {
+				t.Fatalf("incorrect plan for 'bar': %#v", ric.After)
+			}
+		case "aws_instance.foo":
+			num, _ := ric.After.GetAttr("num").AsBigFloat().Int64()
+			if num != 2 {
+				t.Fatalf("incorrect plan for 'foo': %#v", ric.After)
+			}
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+
+	if !p.ValidateProviderConfigCalled {
+		t.Fatal("provider config was not checked before Configure")
+	}
+
+}
+
+func TestContext2Plan_createBefore_deposed(t *testing.T) {
+	m := testModule(t, "plan-cbd")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"baz","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceDeposed(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		states.DeposedKey("00000001"),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	// the state should still show one deposed
+	expectedState := strings.TrimSpace(`
+ aws_instance.foo: (1 deposed)
+  ID = baz
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+  Deposed ID 1 = foo`)
+
+	if plan.PriorState.String() != expectedState {
+		t.Fatalf("\nexpected: %q\ngot:      %q\n", expectedState, plan.PriorState.String())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	type InstanceGen struct {
+		Addr       string
+		DeposedKey states.DeposedKey
+	}
+	want := map[InstanceGen]bool{
+		{
+			Addr: "aws_instance.foo",
+		}: true,
+		{
+			Addr:       "aws_instance.foo",
+			DeposedKey: states.DeposedKey("00000001"),
+		}: true,
+	}
+	got := make(map[InstanceGen]bool)
+	changes := make(map[InstanceGen]*plans.ResourceInstanceChangeSrc)
+
+	for _, change := range plan.Changes.Resources {
+		k := InstanceGen{
+			Addr:       change.Addr.String(),
+			DeposedKey: change.DeposedKey,
+		}
+		got[k] = true
+		changes[k] = change
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Fatalf("wrong resource instance object changes in plan\ngot: %s\nwant: %s", spew.Sdump(got), spew.Sdump(want))
+	}
+
+	{
+		ric, err := changes[InstanceGen{Addr: "aws_instance.foo"}].Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if got, want := ric.Action, plans.NoOp; got != want {
+			t.Errorf("current object change action is %s; want %s", got, want)
+		}
+
+		// the existing instance should only have an unchanged id
+		expected, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
+			"id":   cty.StringVal("baz"),
+			"type": cty.StringVal("aws_instance"),
+		}))
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		checkVals(t, expected, ric.After)
+	}
+
+	{
+		ric, err := changes[InstanceGen{Addr: "aws_instance.foo", DeposedKey: states.DeposedKey("00000001")}].Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if got, want := ric.Action, plans.Delete; got != want {
+			t.Errorf("deposed object change action is %s; want %s", got, want)
+		}
+	}
+}
+
+func TestContext2Plan_createBefore_maintainRoot(t *testing.T) {
+	m := testModule(t, "plan-cbd-maintain-root")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if !plan.PriorState.Empty() {
+		t.Fatal("expected empty prior state, got:", plan.PriorState)
+	}
+
+	if len(plan.Changes.Resources) != 4 {
+		t.Error("expected 4 resource in plan, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		// these should all be creates
+		if res.Action != plans.Create {
+			t.Fatalf("unexpected action %s for %s", res.Action, res.Addr.String())
+		}
+	}
+}
+
+func TestContext2Plan_emptyDiff(t *testing.T) {
+	m := testModule(t, "plan-empty")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		resp.PlannedState = req.ProposedNewState
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if !plan.PriorState.Empty() {
+		t.Fatal("expected empty state, got:", plan.PriorState)
+	}
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Error("expected 2 resource in plan, got", len(plan.Changes.Resources))
+	}
+
+	actions := map[string]plans.Action{}
+
+	for _, res := range plan.Changes.Resources {
+		actions[res.Addr.String()] = res.Action
+	}
+
+	expected := map[string]plans.Action{
+		"aws_instance.foo": plans.Create,
+		"aws_instance.bar": plans.Create,
+	}
+	if !cmp.Equal(expected, actions) {
+		t.Fatal(cmp.Diff(expected, actions))
+	}
+}
+
+func TestContext2Plan_escapedVar(t *testing.T) {
+	m := testModule(t, "plan-escaped-var")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if len(plan.Changes.Resources) != 1 {
+		t.Error("expected 1 resource in plan, got", len(plan.Changes.Resources))
+	}
+
+	res := plan.Changes.Resources[0]
+	if res.Action != plans.Create {
+		t.Fatalf("expected resource creation, got %s", res.Action)
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	ric, err := res.Decode(ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expected := objectVal(t, schema, map[string]cty.Value{
+		"id":   cty.UnknownVal(cty.String),
+		"foo":  cty.StringVal("bar-${baz}"),
+		"type": cty.UnknownVal(cty.String),
+	})
+
+	checkVals(t, expected, ric.After)
+}
+
+func TestContext2Plan_minimal(t *testing.T) {
+	m := testModule(t, "plan-empty")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if !plan.PriorState.Empty() {
+		t.Fatal("expected empty state, got:", plan.PriorState)
+	}
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Error("expected 2 resource in plan, got", len(plan.Changes.Resources))
+	}
+
+	actions := map[string]plans.Action{}
+
+	for _, res := range plan.Changes.Resources {
+		actions[res.Addr.String()] = res.Action
+	}
+
+	expected := map[string]plans.Action{
+		"aws_instance.foo": plans.Create,
+		"aws_instance.bar": plans.Create,
+	}
+	if !cmp.Equal(expected, actions) {
+		t.Fatal(cmp.Diff(expected, actions))
+	}
+}
+
+func TestContext2Plan_modules(t *testing.T) {
+	m := testModule(t, "plan-modules")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if len(plan.Changes.Resources) != 3 {
+		t.Error("expected 3 resource in plan, got", len(plan.Changes.Resources))
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	expectFoo := objectVal(t, schema, map[string]cty.Value{
+		"id":   cty.UnknownVal(cty.String),
+		"foo":  cty.StringVal("2"),
+		"type": cty.UnknownVal(cty.String),
+	})
+
+	expectNum := objectVal(t, schema, map[string]cty.Value{
+		"id":   cty.UnknownVal(cty.String),
+		"num":  cty.NumberIntVal(2),
+		"type": cty.UnknownVal(cty.String),
+	})
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		var expected cty.Value
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			expected = expectFoo
+		case "aws_instance.foo":
+			expected = expectNum
+		case "module.child.aws_instance.foo":
+			expected = expectNum
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+
+		checkVals(t, expected, ric.After)
+	}
+}
+func TestContext2Plan_moduleExpand(t *testing.T) {
+	// Test a smattering of plan expansion behavior
+	m := testModule(t, "plan-modules-expand")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	expected := map[string]struct{}{
+		`aws_instance.foo["a"]`:                          {},
+		`module.count_child[1].aws_instance.foo[0]`:      {},
+		`module.count_child[1].aws_instance.foo[1]`:      {},
+		`module.count_child[0].aws_instance.foo[0]`:      {},
+		`module.count_child[0].aws_instance.foo[1]`:      {},
+		`module.for_each_child["a"].aws_instance.foo[1]`: {},
+		`module.for_each_child["a"].aws_instance.foo[0]`: {},
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		_, ok := expected[ric.Addr.String()]
+		if !ok {
+			t.Fatal("unexpected resource:", ric.Addr.String())
+		}
+		delete(expected, ric.Addr.String())
+	}
+	for addr := range expected {
+		t.Error("missing resource", addr)
+	}
+}
+
+// GH-1475
+func TestContext2Plan_moduleCycle(t *testing.T) {
+	m := testModule(t, "plan-module-cycle")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":         {Type: cty.String, Computed: true},
+					"some_input": {Type: cty.String, Optional: true},
+					"type":       {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		var expected cty.Value
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.b":
+			expected = objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"type": cty.UnknownVal(cty.String),
+			})
+		case "aws_instance.c":
+			expected = objectVal(t, schema, map[string]cty.Value{
+				"id":         cty.UnknownVal(cty.String),
+				"some_input": cty.UnknownVal(cty.String),
+				"type":       cty.UnknownVal(cty.String),
+			})
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+
+		checkVals(t, expected, ric.After)
+	}
+}
+
+func TestContext2Plan_moduleDeadlock(t *testing.T) {
+	testCheckDeadlock(t, func() {
+		m := testModule(t, "plan-module-deadlock")
+		p := testProvider("aws")
+		p.PlanResourceChangeFn = testDiffFn
+
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		plan, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+		ty := schema.ImpliedType()
+
+		for _, res := range plan.Changes.Resources {
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource creation, got %s", res.Action)
+			}
+			ric, err := res.Decode(ty)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			expected := objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"type": cty.UnknownVal(cty.String),
+			})
+			switch i := ric.Addr.String(); i {
+			case "module.child.aws_instance.foo[0]":
+			case "module.child.aws_instance.foo[1]":
+			case "module.child.aws_instance.foo[2]":
+			default:
+				t.Fatal("unknown instance:", i)
+			}
+
+			checkVals(t, expected, ric.After)
+		}
+	})
+}
+
+func TestContext2Plan_moduleInput(t *testing.T) {
+	m := testModule(t, "plan-module-input")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		var expected cty.Value
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			expected = objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("2"),
+				"type": cty.UnknownVal(cty.String),
+			})
+		case "module.child.aws_instance.foo":
+			expected = objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("42"),
+				"type": cty.UnknownVal(cty.String),
+			})
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+
+		checkVals(t, expected, ric.After)
+	}
+}
+
+func TestContext2Plan_moduleInputComputed(t *testing.T) {
+	m := testModule(t, "plan-module-input-computed")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":      cty.UnknownVal(cty.String),
+				"foo":     cty.UnknownVal(cty.String),
+				"type":    cty.UnknownVal(cty.String),
+				"compute": cty.StringVal("foo"),
+			}), ric.After)
+		case "module.child.aws_instance.foo":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.UnknownVal(cty.String),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_moduleInputFromVar(t *testing.T) {
+	m := testModule(t, "plan-module-input-var")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"foo": &InputValue{
+				Value:      cty.StringVal("52"),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("2"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "module.child.aws_instance.foo":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("52"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_moduleMultiVar(t *testing.T) {
+	m := testModule(t, "plan-module-multi-var")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Computed: true},
+					"foo": {Type: cty.String, Optional: true},
+					"baz": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 5 {
+		t.Fatal("expected 5 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.parent[0]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.parent[1]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "module.child.aws_instance.bar[0]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"baz": cty.StringVal("baz"),
+			}), ric.After)
+		case "module.child.aws_instance.bar[1]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"baz": cty.StringVal("baz"),
+			}), ric.After)
+		case "module.child.aws_instance.foo":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":  cty.UnknownVal(cty.String),
+				"foo": cty.StringVal("baz,baz"),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_moduleOrphans(t *testing.T) {
+	m := testModule(t, "plan-modules-remove")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"baz"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.foo":
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource creation, got %s", res.Action)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"num":  cty.NumberIntVal(2),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "module.child.aws_instance.foo":
+			if res.Action != plans.Delete {
+				t.Fatalf("expected resource delete, got %s", res.Action)
+			}
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+
+	expectedState := `<no state>
+module.child:
+  aws_instance.foo:
+    ID = baz
+    provider = provider["registry.terraform.io/hashicorp/aws"]`
+
+	if plan.PriorState.String() != expectedState {
+		t.Fatalf("\nexpected state: %q\n\ngot: %q", expectedState, plan.PriorState.String())
+	}
+}
+
+// https://github.com/hashicorp/terraform/issues/3114
+func TestContext2Plan_moduleOrphansWithProvisioner(t *testing.T) {
+	m := testModule(t, "plan-modules-remove-provisioners")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	pr := testProvisioner()
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.top").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"top","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	child1 := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child1", addrs.NoKey))
+	child1.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"baz","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	child2 := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child2", addrs.NoKey))
+	child2.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"baz","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 3 {
+		t.Error("expected 3 planned resources, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "module.parent.module.child1.aws_instance.foo":
+			if res.Action != plans.Delete {
+				t.Fatalf("expected resource Delete, got %s", res.Action)
+			}
+		case "module.parent.module.child2.aws_instance.foo":
+			if res.Action != plans.Delete {
+				t.Fatalf("expected resource Delete, got %s", res.Action)
+			}
+		case "aws_instance.top":
+			if res.Action != plans.NoOp {
+				t.Fatalf("expected no changes, got %s", res.Action)
+			}
+		default:
+			t.Fatalf("unknown instance: %s\nafter: %#v", i, hcl2shim.ConfigValueFromHCL2(ric.After))
+		}
+	}
+
+	expectedState := `aws_instance.top:
+  ID = top
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+
+module.parent.child1:
+  aws_instance.foo:
+    ID = baz
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    type = aws_instance
+module.parent.child2:
+  aws_instance.foo:
+    ID = baz
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    type = aws_instance`
+
+	if expectedState != plan.PriorState.String() {
+		t.Fatalf("\nexpect state:\n%s\n\ngot state:\n%s\n", expectedState, plan.PriorState.String())
+	}
+}
+
+func TestContext2Plan_moduleProviderInherit(t *testing.T) {
+	var l sync.Mutex
+	var calls []string
+
+	m := testModule(t, "plan-module-provider-inherit")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): func() (providers.Interface, error) {
+				l.Lock()
+				defer l.Unlock()
+
+				p := testProvider("aws")
+				p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+					Provider: &configschema.Block{
+						Attributes: map[string]*configschema.Attribute{
+							"from": {Type: cty.String, Optional: true},
+						},
+					},
+					ResourceTypes: map[string]*configschema.Block{
+						"aws_instance": {
+							Attributes: map[string]*configschema.Attribute{
+								"from": {Type: cty.String, Optional: true},
+							},
+						},
+					},
+				})
+				p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+					from := req.Config.GetAttr("from")
+					if from.IsNull() || from.AsString() != "root" {
+						resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("not root"))
+					}
+
+					return
+				}
+				p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+					from := req.Config.GetAttr("from").AsString()
+
+					l.Lock()
+					defer l.Unlock()
+					calls = append(calls, from)
+					return testDiffFn(req)
+				}
+				return p, nil
+			},
+		},
+	})
+
+	_, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := calls
+	sort.Strings(actual)
+	expected := []string{"child", "root"}
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+// This tests (for GH-11282) that deeply nested modules properly inherit
+// configuration.
+func TestContext2Plan_moduleProviderInheritDeep(t *testing.T) {
+	var l sync.Mutex
+
+	m := testModule(t, "plan-module-provider-inherit-deep")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): func() (providers.Interface, error) {
+				l.Lock()
+				defer l.Unlock()
+
+				var from string
+				p := testProvider("aws")
+
+				p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+					Provider: &configschema.Block{
+						Attributes: map[string]*configschema.Attribute{
+							"from": {Type: cty.String, Optional: true},
+						},
+					},
+					ResourceTypes: map[string]*configschema.Block{
+						"aws_instance": {
+							Attributes: map[string]*configschema.Attribute{},
+						},
+					},
+				})
+
+				p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+					v := req.Config.GetAttr("from")
+					if v.IsNull() || v.AsString() != "root" {
+						resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("not root"))
+					}
+					from = v.AsString()
+
+					return
+				}
+
+				p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+					if from != "root" {
+						resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("bad resource"))
+						return
+					}
+
+					return testDiffFn(req)
+				}
+				return p, nil
+			},
+		},
+	})
+
+	_, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+}
+
+func TestContext2Plan_moduleProviderDefaultsVar(t *testing.T) {
+	var l sync.Mutex
+	var calls []string
+
+	m := testModule(t, "plan-module-provider-defaults-var")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): func() (providers.Interface, error) {
+				l.Lock()
+				defer l.Unlock()
+
+				p := testProvider("aws")
+				p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+					Provider: &configschema.Block{
+						Attributes: map[string]*configschema.Attribute{
+							"to":   {Type: cty.String, Optional: true},
+							"from": {Type: cty.String, Optional: true},
+						},
+					},
+					ResourceTypes: map[string]*configschema.Block{
+						"aws_instance": {
+							Attributes: map[string]*configschema.Attribute{
+								"from": {Type: cty.String, Optional: true},
+							},
+						},
+					},
+				})
+				p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+					var buf bytes.Buffer
+					from := req.Config.GetAttr("from")
+					if !from.IsNull() {
+						buf.WriteString(from.AsString() + "\n")
+					}
+					to := req.Config.GetAttr("to")
+					if !to.IsNull() {
+						buf.WriteString(to.AsString() + "\n")
+					}
+
+					l.Lock()
+					defer l.Unlock()
+					calls = append(calls, buf.String())
+					return
+				}
+
+				return p, nil
+			},
+		},
+	})
+
+	_, err := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"foo": &InputValue{
+				Value:      cty.StringVal("root"),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := []string{
+		"child\nchild\n",
+		"root\n",
+	}
+	sort.Strings(calls)
+	if !reflect.DeepEqual(calls, expected) {
+		t.Fatalf("expected:\n%#v\ngot:\n%#v\n", expected, calls)
+	}
+}
+
+func TestContext2Plan_moduleProviderVar(t *testing.T) {
+	m := testModule(t, "plan-module-provider-var")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"value": {Type: cty.String, Optional: true},
+			},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"value": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 1 {
+		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "module.child.aws_instance.test":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"value": cty.StringVal("hello"),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_moduleVar(t *testing.T) {
+	m := testModule(t, "plan-module-var")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		var expected cty.Value
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			expected = objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("2"),
+				"type": cty.UnknownVal(cty.String),
+			})
+		case "module.child.aws_instance.foo":
+			expected = objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"num":  cty.NumberIntVal(2),
+				"type": cty.UnknownVal(cty.String),
+			})
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+
+		checkVals(t, expected, ric.After)
+	}
+}
+
+func TestContext2Plan_moduleVarWrongTypeBasic(t *testing.T) {
+	m := testModule(t, "plan-module-wrong-var-type")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want errors")
+	}
+}
+
+func TestContext2Plan_moduleVarWrongTypeNested(t *testing.T) {
+	m := testModule(t, "plan-module-wrong-var-type-nested")
+	p := testProvider("null")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want errors")
+	}
+}
+
+func TestContext2Plan_moduleVarWithDefaultValue(t *testing.T) {
+	m := testModule(t, "plan-module-var-with-default-value")
+	p := testProvider("null")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+}
+
+func TestContext2Plan_moduleVarComputed(t *testing.T) {
+	m := testModule(t, "plan-module-var-computed")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.UnknownVal(cty.String),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "module.child.aws_instance.foo":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":      cty.UnknownVal(cty.String),
+				"foo":     cty.UnknownVal(cty.String),
+				"type":    cty.UnknownVal(cty.String),
+				"compute": cty.StringVal("foo"),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_preventDestroy_bad(t *testing.T) {
+	m := testModule(t, "plan-prevent-destroy-bad")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-abc123"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, err := ctx.Plan(m, state, DefaultPlanOpts)
+
+	expectedErr := "aws_instance.foo has lifecycle.prevent_destroy"
+	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
+		if plan != nil {
+			t.Logf(legacyDiffComparisonString(plan.Changes))
+		}
+		t.Fatalf("expected err would contain %q\nerr: %s", expectedErr, err)
+	}
+}
+
+func TestContext2Plan_preventDestroy_good(t *testing.T) {
+	m := testModule(t, "plan-prevent-destroy-good")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-abc123","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if !plan.Changes.Empty() {
+		t.Fatalf("expected no changes, got %#v\n", plan.Changes)
+	}
+}
+
+func TestContext2Plan_preventDestroy_countBad(t *testing.T) {
+	m := testModule(t, "plan-prevent-destroy-count-bad")
+	p := testProvider("aws")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-abc123"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-abc345"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, err := ctx.Plan(m, state, DefaultPlanOpts)
+
+	expectedErr := "aws_instance.foo[1] has lifecycle.prevent_destroy"
+	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
+		if plan != nil {
+			t.Logf(legacyDiffComparisonString(plan.Changes))
+		}
+		t.Fatalf("expected err would contain %q\nerr: %s", expectedErr, err)
+	}
+}
+
+func TestContext2Plan_preventDestroy_countGood(t *testing.T) {
+	m := testModule(t, "plan-prevent-destroy-count-good")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"current": {Type: cty.String, Optional: true},
+					"id":      {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-abc123"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-abc345"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if plan.Changes.Empty() {
+		t.Fatalf("Expected non-empty plan, got %s", legacyDiffComparisonString(plan.Changes))
+	}
+}
+
+func TestContext2Plan_preventDestroy_countGoodNoChange(t *testing.T) {
+	m := testModule(t, "plan-prevent-destroy-count-good")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"current": {Type: cty.String, Optional: true},
+					"type":    {Type: cty.String, Optional: true, Computed: true},
+					"id":      {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-abc123","current":"0","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if !plan.Changes.Empty() {
+		t.Fatalf("Expected empty plan, got %s", legacyDiffComparisonString(plan.Changes))
+	}
+}
+
+func TestContext2Plan_preventDestroy_destroyPlan(t *testing.T) {
+	m := testModule(t, "plan-prevent-destroy-good")
+	p := testProvider("aws")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-abc123"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+
+	expectedErr := "aws_instance.foo has lifecycle.prevent_destroy"
+	if !strings.Contains(fmt.Sprintf("%s", diags.Err()), expectedErr) {
+		if plan != nil {
+			t.Logf(legacyDiffComparisonString(plan.Changes))
+		}
+		t.Fatalf("expected diagnostics would contain %q\nactual diags: %s", expectedErr, diags.Err())
+	}
+}
+
+func TestContext2Plan_provisionerCycle(t *testing.T) {
+	m := testModule(t, "plan-provisioner-cycle")
+	p := testProvider("aws")
+	pr := testProvisioner()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"local-exec": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want errors")
+	}
+}
+
+func TestContext2Plan_computed(t *testing.T) {
+	m := testModule(t, "plan-computed")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.UnknownVal(cty.String),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":      cty.UnknownVal(cty.String),
+				"foo":     cty.UnknownVal(cty.String),
+				"num":     cty.NumberIntVal(2),
+				"type":    cty.UnknownVal(cty.String),
+				"compute": cty.StringVal("foo"),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_blockNestingGroup(t *testing.T) {
+	m := testModule(t, "plan-block-nesting-group")
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test": {
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"blah": {
+						Nesting: configschema.NestingGroup,
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"baz": {Type: cty.String, Required: true},
+							},
+						},
+					},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if got, want := 1, len(plan.Changes.Resources); got != want {
+		t.Fatalf("wrong number of planned resource changes %d; want %d\n%s", got, want, spew.Sdump(plan.Changes.Resources))
+	}
+
+	if !p.PlanResourceChangeCalled {
+		t.Fatalf("PlanResourceChange was not called at all")
+	}
+
+	got := p.PlanResourceChangeRequest
+	want := providers.PlanResourceChangeRequest{
+		TypeName: "test",
+
+		// Because block type "blah" is defined as NestingGroup, we get a non-null
+		// value for it with null nested attributes, rather than the "blah" object
+		// itself being null, when there's no "blah" block in the config at all.
+		//
+		// This represents the situation where the remote service _always_ creates
+		// a single "blah", regardless of whether the block is present, but when
+		// the block _is_ present the user can override some aspects of it. The
+		// absense of the block means "use the defaults", in that case.
+		Config: cty.ObjectVal(map[string]cty.Value{
+			"blah": cty.ObjectVal(map[string]cty.Value{
+				"baz": cty.NullVal(cty.String),
+			}),
+		}),
+		ProposedNewState: cty.ObjectVal(map[string]cty.Value{
+			"blah": cty.ObjectVal(map[string]cty.Value{
+				"baz": cty.NullVal(cty.String),
+			}),
+		}),
+	}
+	if !cmp.Equal(got, want, valueTrans) {
+		t.Errorf("wrong PlanResourceChange request\n%s", cmp.Diff(got, want, valueTrans))
+	}
+}
+
+func TestContext2Plan_computedDataResource(t *testing.T) {
+	m := testModule(t, "plan-computed-data-resource")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"num":     {Type: cty.String, Optional: true},
+					"compute": {Type: cty.String, Optional: true},
+					"foo":     {Type: cty.String, Computed: true},
+				},
+			},
+		},
+		DataSources: map[string]*configschema.Block{
+			"aws_vpc": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	schema := p.GetProviderSchemaResponse.DataSources["aws_vpc"].Block
+	ty := schema.ImpliedType()
+
+	if rc := plan.Changes.ResourceInstance(addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "aws_instance", Name: "foo"}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)); rc == nil {
+		t.Fatalf("missing diff for aws_instance.foo")
+	}
+	rcs := plan.Changes.ResourceInstance(addrs.Resource{
+		Mode: addrs.DataResourceMode,
+		Type: "aws_vpc",
+		Name: "bar",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
+	if rcs == nil {
+		t.Fatalf("missing diff for data.aws_vpc.bar")
+	}
+
+	rc, err := rcs.Decode(ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	checkVals(t,
+		cty.ObjectVal(map[string]cty.Value{
+			"foo": cty.UnknownVal(cty.String),
+		}),
+		rc.After,
+	)
+	if got, want := rc.ActionReason, plans.ResourceInstanceReadBecauseConfigUnknown; got != want {
+		t.Errorf("wrong ActionReason\ngot:  %s\nwant: %s", got, want)
+	}
+}
+
+func TestContext2Plan_computedInFunction(t *testing.T) {
+	m := testModule(t, "plan-computed-in-function")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"attr": {Type: cty.Number, Optional: true},
+				},
+			},
+		},
+		DataSources: map[string]*configschema.Block{
+			"aws_data_source": {
+				Attributes: map[string]*configschema.Attribute{
+					"computed": {Type: cty.List(cty.String), Computed: true},
+				},
+			},
+		},
+	})
+	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+		State: cty.ObjectVal(map[string]cty.Value{
+			"computed": cty.ListVal([]cty.Value{
+				cty.StringVal("foo"),
+			}),
+		}),
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	assertNoErrors(t, diags)
+
+	_, diags = ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	if !p.ReadDataSourceCalled {
+		t.Fatalf("ReadDataSource was not called on provider during plan; should've been called")
+	}
+}
+
+func TestContext2Plan_computedDataCountResource(t *testing.T) {
+	m := testModule(t, "plan-computed-data-count")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"num":     {Type: cty.String, Optional: true},
+					"compute": {Type: cty.String, Optional: true},
+					"foo":     {Type: cty.String, Computed: true},
+				},
+			},
+		},
+		DataSources: map[string]*configschema.Block{
+			"aws_vpc": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	// make sure we created 3 "bar"s
+	for i := 0; i < 3; i++ {
+		addr := addrs.Resource{
+			Mode: addrs.DataResourceMode,
+			Type: "aws_vpc",
+			Name: "bar",
+		}.Instance(addrs.IntKey(i)).Absolute(addrs.RootModuleInstance)
+
+		if rcs := plan.Changes.ResourceInstance(addr); rcs == nil {
+			t.Fatalf("missing changes for %s", addr)
+		}
+	}
+}
+
+func TestContext2Plan_localValueCount(t *testing.T) {
+	m := testModule(t, "plan-local-value-count")
+	p := testProvider("test")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	// make sure we created 3 "foo"s
+	for i := 0; i < 3; i++ {
+		addr := addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_resource",
+			Name: "foo",
+		}.Instance(addrs.IntKey(i)).Absolute(addrs.RootModuleInstance)
+
+		if rcs := plan.Changes.ResourceInstance(addr); rcs == nil {
+			t.Fatalf("missing changes for %s", addr)
+		}
+	}
+}
+
+func TestContext2Plan_dataResourceBecomesComputed(t *testing.T) {
+	m := testModule(t, "plan-data-resource-becomes-computed")
+	p := testProvider("aws")
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo":      {Type: cty.String, Optional: true},
+					"computed": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+		DataSources: map[string]*configschema.Block{
+			"aws_data_source": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Computed: true},
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		fooVal := req.ProposedNewState.GetAttr("foo")
+		return providers.PlanResourceChangeResponse{
+			PlannedState: cty.ObjectVal(map[string]cty.Value{
+				"foo":      fooVal,
+				"computed": cty.UnknownVal(cty.String),
+			}),
+			PlannedPrivate: req.PriorPrivate,
+		}
+	}
+
+	schema := p.GetProviderSchemaResponse.DataSources["aws_data_source"].Block
+	ty := schema.ImpliedType()
+
+	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+		// This should not be called, because the configuration for the
+		// data resource contains an unknown value for "foo".
+		Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("ReadDataSource called, but should not have been")),
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("data.aws_data_source.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-abc123","foo":"baz"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors during plan: %s", diags.Err())
+	}
+
+	rcs := plan.Changes.ResourceInstance(addrs.Resource{
+		Mode: addrs.DataResourceMode,
+		Type: "aws_data_source",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
+	if rcs == nil {
+		t.Logf("full changeset: %s", spew.Sdump(plan.Changes))
+		t.Fatalf("missing diff for data.aws_data_resource.foo")
+	}
+
+	rc, err := rcs.Decode(ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if got, want := rc.ActionReason, plans.ResourceInstanceReadBecauseConfigUnknown; got != want {
+		t.Errorf("wrong ActionReason\ngot:  %s\nwant: %s", got, want)
+	}
+
+	// foo should now be unknown
+	foo := rc.After.GetAttr("foo")
+	if foo.IsKnown() {
+		t.Fatalf("foo should be unknown, got %#v", foo)
+	}
+}
+
+func TestContext2Plan_computedList(t *testing.T) {
+	m := testModule(t, "plan-computed-list")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"compute": {Type: cty.String, Optional: true},
+					"foo":     {Type: cty.String, Optional: true},
+					"num":     {Type: cty.String, Optional: true},
+					"list":    {Type: cty.List(cty.String), Computed: true},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"foo": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"list":    cty.UnknownVal(cty.List(cty.String)),
+				"num":     cty.NumberIntVal(2),
+				"compute": cty.StringVal("list.#"),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+// GH-8695. This tests that you can index into a computed list on a
+// splatted resource.
+func TestContext2Plan_computedMultiIndex(t *testing.T) {
+	m := testModule(t, "plan-computed-multi-index")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"compute": {Type: cty.String, Optional: true},
+					"foo":     {Type: cty.List(cty.String), Optional: true},
+					"ip":      {Type: cty.List(cty.String), Computed: true},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 3 {
+		t.Fatal("expected 3 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.foo[0]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"ip":      cty.UnknownVal(cty.List(cty.String)),
+				"foo":     cty.NullVal(cty.List(cty.String)),
+				"compute": cty.StringVal("ip.#"),
+			}), ric.After)
+		case "aws_instance.foo[1]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"ip":      cty.UnknownVal(cty.List(cty.String)),
+				"foo":     cty.NullVal(cty.List(cty.String)),
+				"compute": cty.StringVal("ip.#"),
+			}), ric.After)
+		case "aws_instance.bar[0]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"foo": cty.UnknownVal(cty.List(cty.String)),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_count(t *testing.T) {
+	m := testModule(t, "plan-count")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 6 {
+		t.Fatal("expected 6 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo,foo,foo,foo,foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo[0]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo[1]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo[2]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo[3]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo[4]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_countComputed(t *testing.T) {
+	m := testModule(t, "plan-count-computed")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if err == nil {
+		t.Fatal("should error")
+	}
+}
+
+func TestContext2Plan_countComputedModule(t *testing.T) {
+	m := testModule(t, "plan-count-computed-module")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+
+	expectedErr := `The "count" value depends on resource attributes`
+	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
+		t.Fatalf("expected err would contain %q\nerr: %s\n",
+			expectedErr, err)
+	}
+}
+
+func TestContext2Plan_countModuleStatic(t *testing.T) {
+	m := testModule(t, "plan-count-module-static")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 3 {
+		t.Fatal("expected 3 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "module.child.aws_instance.foo[0]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "module.child.aws_instance.foo[1]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "module.child.aws_instance.foo[2]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_countModuleStaticGrandchild(t *testing.T) {
+	m := testModule(t, "plan-count-module-static-grandchild")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 3 {
+		t.Fatal("expected 3 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "module.child.module.child.aws_instance.foo[0]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "module.child.module.child.aws_instance.foo[1]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "module.child.module.child.aws_instance.foo[2]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_countIndex(t *testing.T) {
+	m := testModule(t, "plan-count-index")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.foo[0]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("0"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo[1]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("1"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_countVar(t *testing.T) {
+	m := testModule(t, "plan-count-var")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"instance_count": &InputValue{
+				Value:      cty.StringVal("3"),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 4 {
+		t.Fatal("expected 4 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo,foo,foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo[0]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo[1]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo[2]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_countZero(t *testing.T) {
+	m := testModule(t, "plan-count-zero")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.DynamicPseudoType, Optional: true},
+				},
+			},
+		},
+	})
+
+	// This schema contains a DynamicPseudoType, and therefore can't go through any shim functions
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		resp.PlannedState = req.ProposedNewState
+		resp.PlannedPrivate = req.PriorPrivate
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 1 {
+		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
+	}
+
+	res := plan.Changes.Resources[0]
+
+	if res.Action != plans.Create {
+		t.Fatalf("expected resource creation, got %s", res.Action)
+	}
+	ric, err := res.Decode(ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expected := cty.TupleVal(nil)
+
+	foo := ric.After.GetAttr("foo")
+
+	if !cmp.Equal(expected, foo, valueComparer) {
+		t.Fatal(cmp.Diff(expected, foo, valueComparer))
+	}
+}
+
+func TestContext2Plan_countOneIndex(t *testing.T) {
+	m := testModule(t, "plan-count-one-index")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo[0]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_countDecreaseToOne(t *testing.T) {
+	m := testModule(t, "plan-count-dec")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 4 {
+		t.Fatal("expected 4 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource create, got %s", res.Action)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("bar"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo":
+			if res.Action != plans.NoOp {
+				t.Fatalf("resource %s should be unchanged", i)
+			}
+		case "aws_instance.foo[1]":
+			if res.Action != plans.Delete {
+				t.Fatalf("expected resource delete, got %s", res.Action)
+			}
+		case "aws_instance.foo[2]":
+			if res.Action != plans.Delete {
+				t.Fatalf("expected resource delete, got %s", res.Action)
+			}
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+
+	expectedState := `aws_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  type = aws_instance
+aws_instance.foo.1:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+aws_instance.foo.2:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]`
+
+	if plan.PriorState.String() != expectedState {
+		t.Fatalf("epected state:\n%q\n\ngot state:\n%q\n", expectedState, plan.PriorState.String())
+	}
+}
+
+func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) {
+	m := testModule(t, "plan-count-inc")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","type":"aws_instance","foo":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 4 {
+		t.Fatal("expected 4 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource create, got %s", res.Action)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("bar"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo[0]":
+			if res.Action != plans.NoOp {
+				t.Fatalf("resource %s should be unchanged", i)
+			}
+		case "aws_instance.foo[1]":
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource create, got %s", res.Action)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo[2]":
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource create, got %s", res.Action)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_countIncreaseFromOne(t *testing.T) {
+	m := testModule(t, "plan-count-inc")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 4 {
+		t.Fatal("expected 4 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource create, got %s", res.Action)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("bar"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo[0]":
+			if res.Action != plans.NoOp {
+				t.Fatalf("resource %s should be unchanged", i)
+			}
+		case "aws_instance.foo[1]":
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource create, got %s", res.Action)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo[2]":
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource create, got %s", res.Action)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+// https://github.com/PeoplePerHour/terraform/pull/11
+//
+// This tests a case where both a "resource" and "resource.0" are in
+// the state file, which apparently is a reasonable backwards compatibility
+// concern found in the above 3rd party repo.
+func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) {
+	m := testModule(t, "plan-count-inc")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 5 {
+		t.Fatal("expected 5 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource create, got %s", res.Action)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("bar"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo":
+			if res.Action != plans.Delete {
+				t.Fatalf("resource %s should be removed", i)
+			}
+		case "aws_instance.foo[0]":
+			if res.Action != plans.NoOp {
+				t.Fatalf("resource %s should be unchanged", i)
+			}
+		case "aws_instance.foo[1]":
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource create, got %s", res.Action)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo[2]":
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource create, got %s", res.Action)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+// A common pattern in TF configs is to have a set of resources with the same
+// count and to use count.index to create correspondences between them:
+//
+//	foo_id = "${foo.bar.*.id[count.index]}"
+//
+// This test is for the situation where some instances already exist and the
+// count is increased. In that case, we should see only the create diffs
+// for the new instances and not any update diffs for the existing ones.
+func TestContext2Plan_countIncreaseWithSplatReference(t *testing.T) {
+	m := testModule(t, "plan-count-splat-reference")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"name":     {Type: cty.String, Optional: true},
+					"foo_name": {Type: cty.String, Optional: true},
+					"id":       {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","name":"foo 0"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","name":"foo 1"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","foo_name":"foo 0"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","foo_name":"foo 1"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 6 {
+		t.Fatal("expected 6 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar[0]", "aws_instance.bar[1]", "aws_instance.foo[0]", "aws_instance.foo[1]":
+			if res.Action != plans.NoOp {
+				t.Fatalf("resource %s should be unchanged", i)
+			}
+		case "aws_instance.bar[2]":
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource create, got %s", res.Action)
+			}
+			// The instance ID changed, so just check that the name updated
+			if ric.After.GetAttr("foo_name") != cty.StringVal("foo 2") {
+				t.Fatalf("resource %s attr \"foo_name\" should be changed", i)
+			}
+		case "aws_instance.foo[2]":
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource create, got %s", res.Action)
+			}
+			// The instance ID changed, so just check that the name updated
+			if ric.After.GetAttr("name") != cty.StringVal("foo 2") {
+				t.Fatalf("resource %s attr \"name\" should be changed", i)
+			}
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_forEach(t *testing.T) {
+	m := testModule(t, "plan-for-each")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 8 {
+		t.Fatal("expected 8 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		_, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+	}
+}
+
+func TestContext2Plan_forEachUnknownValue(t *testing.T) {
+	// This module has a variable defined, but it's value is unknown. We
+	// expect this to produce an error, but not to panic.
+	m := testModule(t, "plan-for-each-unknown-value")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"foo": {
+				Value:      cty.UnknownVal(cty.String),
+				SourceType: ValueFromCLIArg,
+			},
+		},
+	})
+	if !diags.HasErrors() {
+		// Should get this error:
+		// Invalid for_each argument: The "for_each" value depends on resource attributes that cannot be determined until apply...
+		t.Fatal("succeeded; want errors")
+	}
+
+	gotErrStr := diags.Err().Error()
+	wantErrStr := "Invalid for_each argument"
+	if !strings.Contains(gotErrStr, wantErrStr) {
+		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
+	}
+
+	// We should have a diagnostic that is marked as being caused by unknown
+	// values.
+	for _, diag := range diags {
+		if tfdiags.DiagnosticCausedByUnknown(diag) {
+			return // don't fall through to the error below
+		}
+	}
+	t.Fatalf("no diagnostic is marked as being caused by unknown\n%s", diags.Err().Error())
+}
+
+func TestContext2Plan_destroy(t *testing.T) {
+	m := testModule(t, "plan-destroy")
+	p := testProvider("aws")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.one").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.two").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"baz"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.one", "aws_instance.two":
+			if res.Action != plans.Delete {
+				t.Fatalf("resource %s should be removed", i)
+			}
+
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_moduleDestroy(t *testing.T) {
+	m := testModule(t, "plan-module-destroy")
+	p := testProvider("aws")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.foo", "module.child.aws_instance.foo":
+			if res.Action != plans.Delete {
+				t.Fatalf("resource %s should be removed", i)
+			}
+
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+// GH-1835
+func TestContext2Plan_moduleDestroyCycle(t *testing.T) {
+	m := testModule(t, "plan-module-destroy-gh-1835")
+	p := testProvider("aws")
+
+	state := states.NewState()
+	aModule := state.EnsureModule(addrs.RootModuleInstance.Child("a_module", addrs.NoKey))
+	aModule.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"a"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	bModule := state.EnsureModule(addrs.RootModuleInstance.Child("b_module", addrs.NoKey))
+	bModule.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.b").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"b"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "module.a_module.aws_instance.a", "module.b_module.aws_instance.b":
+			if res.Action != plans.Delete {
+				t.Fatalf("resource %s should be removed", i)
+			}
+
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_moduleDestroyMultivar(t *testing.T) {
+	m := testModule(t, "plan-module-destroy-multivar")
+	p := testProvider("aws")
+
+	state := states.NewState()
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar0"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar1"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "module.child.aws_instance.foo[0]", "module.child.aws_instance.foo[1]":
+			if res.Action != plans.Delete {
+				t.Fatalf("resource %s should be removed", i)
+			}
+
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_pathVar(t *testing.T) {
+	cwd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	m := testModule(t, "plan-path-var")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"cwd":    {Type: cty.String, Optional: true},
+					"module": {Type: cty.String, Optional: true},
+					"root":   {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 1 {
+		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.foo":
+			if res.Action != plans.Create {
+				t.Fatalf("resource %s should be created", i)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"cwd":    cty.StringVal(cwd + "/barpath"),
+				"module": cty.StringVal(m.Module.SourceDir + "/foopath"),
+				"root":   cty.StringVal(m.Module.SourceDir + "/barpath"),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_diffVar(t *testing.T) {
+	m := testModule(t, "plan-diffvar")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","num":"2","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			if res.Action != plans.Create {
+				t.Fatalf("resource %s should be created", i)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"num":  cty.NumberIntVal(3),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo":
+			if res.Action != plans.Update {
+				t.Fatalf("resource %s should be updated", i)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.StringVal("bar"),
+				"num":  cty.NumberIntVal(2),
+				"type": cty.StringVal("aws_instance"),
+			}), ric.Before)
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.StringVal("bar"),
+				"num":  cty.NumberIntVal(3),
+				"type": cty.StringVal("aws_instance"),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_hook(t *testing.T) {
+	m := testModule(t, "plan-good")
+	h := new(MockHook)
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if !h.PreDiffCalled {
+		t.Fatal("should be called")
+	}
+	if !h.PostDiffCalled {
+		t.Fatal("should be called")
+	}
+}
+
+func TestContext2Plan_closeProvider(t *testing.T) {
+	// this fixture only has an aliased provider located in the module, to make
+	// sure that the provier name contains a path more complex than
+	// "provider.aws".
+	m := testModule(t, "plan-close-module-provider")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if !p.CloseCalled {
+		t.Fatal("provider not closed")
+	}
+}
+
+func TestContext2Plan_orphan(t *testing.T) {
+	m := testModule(t, "plan-orphan")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.baz").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.baz":
+			if res.Action != plans.Delete {
+				t.Fatalf("resource %s should be removed", i)
+			}
+			if got, want := ric.ActionReason, plans.ResourceInstanceDeleteBecauseNoResourceConfig; got != want {
+				t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+			}
+		case "aws_instance.foo":
+			if res.Action != plans.Create {
+				t.Fatalf("resource %s should be created", i)
+			}
+			if got, want := ric.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+				t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"num":  cty.NumberIntVal(2),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+// This tests that configurations with UUIDs don't produce errors.
+// For shadows, this would produce errors since a UUID changes every time.
+func TestContext2Plan_shadowUuid(t *testing.T) {
+	m := testModule(t, "plan-shadow-uuid")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+}
+
+func TestContext2Plan_state(t *testing.T) {
+	m := testModule(t, "plan-good")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if len(plan.Changes.Resources) < 2 {
+		t.Fatalf("bad: %#v", plan.Changes.Resources)
+	}
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.bar":
+			if res.Action != plans.Create {
+				t.Fatalf("resource %s should be created", i)
+			}
+			if got, want := ric.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+				t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("2"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "aws_instance.foo":
+			if res.Action != plans.Update {
+				t.Fatalf("resource %s should be updated", i)
+			}
+			if got, want := ric.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+				t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.StringVal("bar"),
+				"num":  cty.NullVal(cty.Number),
+				"type": cty.NullVal(cty.String),
+			}), ric.Before)
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.StringVal("bar"),
+				"num":  cty.NumberIntVal(2),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_requiresReplace(t *testing.T) {
+	m := testModule(t, "plan-requires-replace")
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"test_thing": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"v": {
+							Type:     cty.String,
+							Required: true,
+						},
+					},
+				},
+			},
+		},
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+			RequiresReplace: []cty.Path{
+				cty.GetAttrPath("v"),
+			},
+		}
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_thing.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"v":"hello"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["test_thing"].Block
+	ty := schema.ImpliedType()
+
+	if got, want := len(plan.Changes.Resources), 1; got != want {
+		t.Fatalf("got %d changes; want %d", got, want)
+	}
+
+	for _, res := range plan.Changes.Resources {
+		t.Run(res.Addr.String(), func(t *testing.T) {
+			ric, err := res.Decode(ty)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			switch i := ric.Addr.String(); i {
+			case "test_thing.foo":
+				if got, want := ric.Action, plans.DeleteThenCreate; got != want {
+					t.Errorf("wrong action\ngot:  %s\nwant: %s", got, want)
+				}
+				if got, want := ric.ActionReason, plans.ResourceInstanceReplaceBecauseCannotUpdate; got != want {
+					t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+				}
+				checkVals(t, objectVal(t, schema, map[string]cty.Value{
+					"v": cty.StringVal("goodbye"),
+				}), ric.After)
+			default:
+				t.Fatalf("unexpected resource instance %s", i)
+			}
+		})
+	}
+}
+
+func TestContext2Plan_taint(t *testing.T) {
+	m := testModule(t, "plan-taint")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","num":"2","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"baz"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		t.Run(res.Addr.String(), func(t *testing.T) {
+			ric, err := res.Decode(ty)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			switch i := ric.Addr.String(); i {
+			case "aws_instance.bar":
+				if got, want := res.Action, plans.DeleteThenCreate; got != want {
+					t.Errorf("wrong action\ngot:  %s\nwant: %s", got, want)
+				}
+				if got, want := res.ActionReason, plans.ResourceInstanceReplaceBecauseTainted; got != want {
+					t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+				}
+				checkVals(t, objectVal(t, schema, map[string]cty.Value{
+					"id":   cty.UnknownVal(cty.String),
+					"foo":  cty.StringVal("2"),
+					"type": cty.UnknownVal(cty.String),
+				}), ric.After)
+			case "aws_instance.foo":
+				if got, want := res.Action, plans.NoOp; got != want {
+					t.Errorf("wrong action\ngot:  %s\nwant: %s", got, want)
+				}
+				if got, want := res.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
+					t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+				}
+			default:
+				t.Fatal("unknown instance:", i)
+			}
+		})
+	}
+}
+
+func TestContext2Plan_taintIgnoreChanges(t *testing.T) {
+	m := testModule(t, "plan-taint-ignore-changes")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":   {Type: cty.String, Computed: true},
+					"vars": {Type: cty.String, Optional: true},
+					"type": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"foo","vars":"foo","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 1 {
+		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.foo":
+			if got, want := res.Action, plans.DeleteThenCreate; got != want {
+				t.Errorf("wrong action\ngot:  %s\nwant: %s", got, want)
+			}
+			if got, want := res.ActionReason, plans.ResourceInstanceReplaceBecauseTainted; got != want {
+				t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.StringVal("foo"),
+				"vars": cty.StringVal("foo"),
+				"type": cty.StringVal("aws_instance"),
+			}), ric.Before)
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"vars": cty.StringVal("foo"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+// Fails about 50% of the time before the fix for GH-4982, covers the fix.
+func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) {
+	m := testModule(t, "plan-taint-interpolated-count")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	for i := 0; i < 100; i++ {
+		ctx := testContext2(t, &ContextOpts{
+			Providers: map[addrs.Provider]providers.Factory{
+				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+			},
+		})
+
+		plan, diags := ctx.Plan(m, state.DeepCopy(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+		if diags.HasErrors() {
+			t.Fatalf("unexpected errors: %s", diags.Err())
+		}
+
+		schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+		ty := schema.ImpliedType()
+
+		if len(plan.Changes.Resources) != 3 {
+			t.Fatal("expected 3 changes, got", len(plan.Changes.Resources))
+		}
+
+		for _, res := range plan.Changes.Resources {
+			ric, err := res.Decode(ty)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			switch i := ric.Addr.String(); i {
+			case "aws_instance.foo[0]":
+				if got, want := ric.Action, plans.DeleteThenCreate; got != want {
+					t.Errorf("wrong action\ngot:  %s\nwant: %s", got, want)
+				}
+				if got, want := ric.ActionReason, plans.ResourceInstanceReplaceBecauseTainted; got != want {
+					t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
+				}
+				checkVals(t, objectVal(t, schema, map[string]cty.Value{
+					"id":   cty.StringVal("bar"),
+					"type": cty.StringVal("aws_instance"),
+				}), ric.Before)
+				checkVals(t, objectVal(t, schema, map[string]cty.Value{
+					"id":   cty.UnknownVal(cty.String),
+					"type": cty.UnknownVal(cty.String),
+				}), ric.After)
+			case "aws_instance.foo[1]", "aws_instance.foo[2]":
+				if res.Action != plans.NoOp {
+					t.Fatalf("resource %s should not be changed", i)
+				}
+			default:
+				t.Fatal("unknown instance:", i)
+			}
+		}
+	}
+}
+
+func TestContext2Plan_targeted(t *testing.T) {
+	m := testModule(t, "plan-targeted")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "foo",
+			),
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 1 {
+		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.foo":
+			if res.Action != plans.Create {
+				t.Fatalf("resource %s should be created", i)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"num":  cty.NumberIntVal(2),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+// Test that targeting a module properly plans any inputs that depend
+// on another module.
+func TestContext2Plan_targetedCrossModule(t *testing.T) {
+	m := testModule(t, "plan-targeted-cross-module")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Child("B", addrs.NoKey),
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if res.Action != plans.Create {
+			t.Fatalf("resource %s should be created", ric.Addr)
+		}
+		switch i := ric.Addr.String(); i {
+		case "module.A.aws_instance.foo":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.StringVal("bar"),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "module.B.aws_instance.bar":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"foo":  cty.UnknownVal(cty.String),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_targetedModuleWithProvider(t *testing.T) {
+	m := testModule(t, "plan-targeted-module-with-provider")
+	p := testProvider("null")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"key": {Type: cty.String, Optional: true},
+			},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			"null_resource": {
+				Attributes: map[string]*configschema.Attribute{},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Child("child2", addrs.NoKey),
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["null_resource"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 1 {
+		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
+	}
+
+	res := plan.Changes.Resources[0]
+	ric, err := res.Decode(ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if ric.Addr.String() != "module.child2.null_resource.foo" {
+		t.Fatalf("unexpcetd resource: %s", ric.Addr)
+	}
+}
+
+func TestContext2Plan_targetedOrphan(t *testing.T) {
+	m := testModule(t, "plan-targeted-orphan")
+	p := testProvider("aws")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.orphan").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-789xyz"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.nottargeted").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-abc123"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "orphan",
+			),
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 1 {
+		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.orphan":
+			if res.Action != plans.Delete {
+				t.Fatalf("resource %s should be destroyed", ric.Addr)
+			}
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+// https://github.com/hashicorp/terraform/issues/2538
+func TestContext2Plan_targetedModuleOrphan(t *testing.T) {
+	m := testModule(t, "plan-targeted-module-orphan")
+	p := testProvider("aws")
+
+	state := states.NewState()
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.orphan").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-789xyz"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.nottargeted").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-abc123"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.DestroyMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource(
+				addrs.ManagedResourceMode, "aws_instance", "orphan",
+			),
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 1 {
+		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
+	}
+
+	res := plan.Changes.Resources[0]
+	ric, err := res.Decode(ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if ric.Addr.String() != "module.child.aws_instance.orphan" {
+		t.Fatalf("unexpected resource :%s", ric.Addr)
+	}
+	if res.Action != plans.Delete {
+		t.Fatalf("resource %s should be deleted", ric.Addr)
+	}
+}
+
+func TestContext2Plan_targetedModuleUntargetedVariable(t *testing.T) {
+	m := testModule(t, "plan-targeted-module-untargeted-variable")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "blue",
+			),
+			addrs.RootModuleInstance.Child("blue_mod", addrs.NoKey),
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if res.Action != plans.Create {
+			t.Fatalf("resource %s should be created", ric.Addr)
+		}
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.blue":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "module.blue_mod.aws_instance.mod":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":    cty.UnknownVal(cty.String),
+				"value": cty.UnknownVal(cty.String),
+				"type":  cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+// ensure that outputs missing references due to targetting are removed from
+// the graph.
+func TestContext2Plan_outputContainsTargetedResource(t *testing.T) {
+	m := testModule(t, "plan-untargeted-resource-output")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Child("mod", addrs.NoKey).Resource(
+				addrs.ManagedResourceMode, "aws_instance", "a",
+			),
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags)
+	}
+	if len(diags) != 1 {
+		t.Fatalf("got %d diagnostics; want 1", diags)
+	}
+	if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
+		t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
+	}
+	if got, want := diags[0].Description().Summary, "Resource targeting is in effect"; got != want {
+		t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
+	}
+}
+
+// https://github.com/hashicorp/terraform/issues/4515
+func TestContext2Plan_targetedOverTen(t *testing.T) {
+	m := testModule(t, "plan-targeted-over-ten")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	for i := 0; i < 13; i++ {
+		key := fmt.Sprintf("aws_instance.foo[%d]", i)
+		id := fmt.Sprintf("i-abc%d", i)
+		attrs := fmt.Sprintf(`{"id":"%s","type":"aws_instance"}`, id)
+
+		root.SetResourceInstanceCurrent(
+			mustResourceInstanceAddr(key).Resource,
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectReady,
+				AttrsJSON: []byte(attrs),
+			},
+			mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+		)
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.ResourceInstance(
+				addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(1),
+			),
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if res.Action != plans.NoOp {
+			t.Fatalf("unexpected action %s for %s", res.Action, ric.Addr)
+		}
+	}
+}
+
+func TestContext2Plan_provider(t *testing.T) {
+	m := testModule(t, "plan-provider")
+	p := testProvider("aws")
+
+	var value interface{}
+	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+		value = req.Config.GetAttr("foo").AsString()
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+	opts := &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"foo": &InputValue{
+				Value:      cty.StringVal("bar"),
+				SourceType: ValueFromCaller,
+			},
+		},
+	}
+
+	if _, err := ctx.Plan(m, states.NewState(), opts); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if value != "bar" {
+		t.Fatalf("bad: %#v", value)
+	}
+}
+
+func TestContext2Plan_varListErr(t *testing.T) {
+	m := testModule(t, "plan-var-list-err")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+
+	if err == nil {
+		t.Fatal("should error")
+	}
+}
+
+func TestContext2Plan_ignoreChanges(t *testing.T) {
+	m := testModule(t, "plan-ignore-changes")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","ami":"ami-abcd1234","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"foo": &InputValue{
+				Value:      cty.StringVal("ami-1234abcd"),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 1 {
+		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
+	}
+
+	res := plan.Changes.Resources[0]
+	ric, err := res.Decode(ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if ric.Addr.String() != "aws_instance.foo" {
+		t.Fatalf("unexpected resource: %s", ric.Addr)
+	}
+
+	checkVals(t, objectVal(t, schema, map[string]cty.Value{
+		"id":   cty.StringVal("bar"),
+		"ami":  cty.StringVal("ami-abcd1234"),
+		"type": cty.StringVal("aws_instance"),
+	}), ric.After)
+}
+
+func TestContext2Plan_ignoreChangesWildcard(t *testing.T) {
+	m := testModule(t, "plan-ignore-changes-wildcard")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		// computed attributes should not be set in config
+		id := req.Config.GetAttr("id")
+		if !id.IsNull() {
+			t.Error("computed id set in plan config")
+		}
+
+		foo := req.Config.GetAttr("foo")
+		if foo.IsNull() {
+			t.Error(`missing "foo" during plan, was set to "bar" in state and config`)
+		}
+
+		return testDiffFn(req)
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","ami":"ami-abcd1234","instance":"t2.micro","type":"aws_instance","foo":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"foo": &InputValue{
+				Value:      cty.StringVal("ami-1234abcd"),
+				SourceType: ValueFromCaller,
+			},
+			"bar": &InputValue{
+				Value:      cty.StringVal("t2.small"),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.NoOp {
+			t.Fatalf("unexpected resource diffs in root module: %s", spew.Sdump(plan.Changes.Resources))
+		}
+	}
+}
+
+func TestContext2Plan_ignoreChangesInMap(t *testing.T) {
+	p := testProvider("test")
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_ignore_changes_map": {
+				Attributes: map[string]*configschema.Attribute{
+					"tags": {Type: cty.Map(cty.String), Optional: true},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+
+	s := states.BuildState(func(ss *states.SyncState) {
+		ss.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_ignore_changes_map",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectReady,
+				AttrsJSON: []byte(`{"id":"foo","tags":{"ignored":"from state","other":"from state"},"type":"aws_instance"}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	m := testModule(t, "plan-ignore-changes-in-map")
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, s, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["test_ignore_changes_map"].Block
+	ty := schema.ImpliedType()
+
+	if got, want := len(plan.Changes.Resources), 1; got != want {
+		t.Fatalf("wrong number of changes %d; want %d", got, want)
+	}
+
+	res := plan.Changes.Resources[0]
+	ric, err := res.Decode(ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if res.Action != plans.Update {
+		t.Fatalf("resource %s should be updated, got %s", ric.Addr, res.Action)
+	}
+
+	if got, want := ric.Addr.String(), "test_ignore_changes_map.foo"; got != want {
+		t.Fatalf("unexpected resource address %s; want %s", got, want)
+	}
+
+	checkVals(t, objectVal(t, schema, map[string]cty.Value{
+		"tags": cty.MapVal(map[string]cty.Value{
+			"ignored": cty.StringVal("from state"),
+			"other":   cty.StringVal("from config"),
+		}),
+	}), ric.After)
+}
+
+func TestContext2Plan_ignoreChangesSensitive(t *testing.T) {
+	m := testModule(t, "plan-ignore-changes-sensitive")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar","ami":"ami-abcd1234","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"foo": &InputValue{
+				Value:      cty.StringVal("ami-1234abcd"),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 1 {
+		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
+	}
+
+	res := plan.Changes.Resources[0]
+	ric, err := res.Decode(ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if ric.Addr.String() != "aws_instance.foo" {
+		t.Fatalf("unexpected resource: %s", ric.Addr)
+	}
+
+	checkVals(t, objectVal(t, schema, map[string]cty.Value{
+		"id":   cty.StringVal("bar"),
+		"ami":  cty.StringVal("ami-abcd1234"),
+		"type": cty.StringVal("aws_instance"),
+	}), ric.After)
+}
+
+func TestContext2Plan_moduleMapLiteral(t *testing.T) {
+	m := testModule(t, "plan-module-map-literal")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"meta": {Type: cty.Map(cty.String), Optional: true},
+					"tags": {Type: cty.Map(cty.String), Optional: true},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		s := req.ProposedNewState.AsValueMap()
+		m := s["tags"].AsValueMap()
+
+		if m["foo"].AsString() != "bar" {
+			t.Fatalf("Bad value in tags attr: %#v", m)
+		}
+
+		meta := s["meta"].AsValueMap()
+		if len(meta) != 0 {
+			t.Fatalf("Meta attr not empty: %#v", meta)
+		}
+		return testDiffFn(req)
+	}
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+}
+
+func TestContext2Plan_computedValueInMap(t *testing.T) {
+	m := testModule(t, "plan-computed-value-in-map")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"looked_up": {Type: cty.String, Optional: true},
+				},
+			},
+			"aws_computed_source": {
+				Attributes: map[string]*configschema.Attribute{
+					"computed_read_only": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		resp = testDiffFn(req)
+
+		if req.TypeName != "aws_computed_source" {
+			return
+		}
+
+		planned := resp.PlannedState.AsValueMap()
+		planned["computed_read_only"] = cty.UnknownVal(cty.String)
+		resp.PlannedState = cty.ObjectVal(planned)
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		schema := p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block
+
+		ric, err := res.Decode(schema.ImpliedType())
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if res.Action != plans.Create {
+			t.Fatalf("resource %s should be created", ric.Addr)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_computed_source.intermediates":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"computed_read_only": cty.UnknownVal(cty.String),
+			}), ric.After)
+		case "module.test_mod.aws_instance.inner2":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"looked_up": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_moduleVariableFromSplat(t *testing.T) {
+	m := testModule(t, "plan-module-variable-from-splat")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"thing": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if len(plan.Changes.Resources) != 4 {
+		t.Fatal("expected 4 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		schema := p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block
+
+		ric, err := res.Decode(schema.ImpliedType())
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if res.Action != plans.Create {
+			t.Fatalf("resource %s should be created", ric.Addr)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "module.mod1.aws_instance.test[0]",
+			"module.mod1.aws_instance.test[1]",
+			"module.mod2.aws_instance.test[0]",
+			"module.mod2.aws_instance.test[1]":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"thing": cty.StringVal("doesnt"),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_createBeforeDestroy_depends_datasource(t *testing.T) {
+	m := testModule(t, "plan-cbd-depends-datasource")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"num":      {Type: cty.String, Optional: true},
+					"computed": {Type: cty.String, Optional: true, Computed: true},
+				},
+			},
+		},
+		DataSources: map[string]*configschema.Block{
+			"aws_vpc": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Computed: true},
+					"foo": {Type: cty.Number, Optional: true},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		computedVal := req.ProposedNewState.GetAttr("computed")
+		if computedVal.IsNull() {
+			computedVal = cty.UnknownVal(cty.String)
+		}
+		return providers.PlanResourceChangeResponse{
+			PlannedState: cty.ObjectVal(map[string]cty.Value{
+				"num":      req.ProposedNewState.GetAttr("num"),
+				"computed": computedVal,
+			}),
+		}
+	}
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		cfg := req.Config.AsValueMap()
+		cfg["id"] = cty.StringVal("data_id")
+		return providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(cfg),
+		}
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	seenAddrs := make(map[string]struct{})
+	for _, res := range plan.Changes.Resources {
+		var schema *configschema.Block
+		switch res.Addr.Resource.Resource.Mode {
+		case addrs.DataResourceMode:
+			schema = p.GetProviderSchemaResponse.DataSources[res.Addr.Resource.Resource.Type].Block
+		case addrs.ManagedResourceMode:
+			schema = p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block
+		}
+
+		ric, err := res.Decode(schema.ImpliedType())
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		seenAddrs[ric.Addr.String()] = struct{}{}
+
+		t.Run(ric.Addr.String(), func(t *testing.T) {
+			switch i := ric.Addr.String(); i {
+			case "aws_instance.foo[0]":
+				if res.Action != plans.Create {
+					t.Fatalf("resource %s should be created, got %s", ric.Addr, ric.Action)
+				}
+				checkVals(t, objectVal(t, schema, map[string]cty.Value{
+					"num":      cty.StringVal("2"),
+					"computed": cty.StringVal("data_id"),
+				}), ric.After)
+			case "aws_instance.foo[1]":
+				if res.Action != plans.Create {
+					t.Fatalf("resource %s should be created, got %s", ric.Addr, ric.Action)
+				}
+				checkVals(t, objectVal(t, schema, map[string]cty.Value{
+					"num":      cty.StringVal("2"),
+					"computed": cty.StringVal("data_id"),
+				}), ric.After)
+			default:
+				t.Fatal("unknown instance:", i)
+			}
+		})
+	}
+
+	wantAddrs := map[string]struct{}{
+		"aws_instance.foo[0]": {},
+		"aws_instance.foo[1]": {},
+	}
+	if !cmp.Equal(seenAddrs, wantAddrs) {
+		t.Errorf("incorrect addresses in changeset:\n%s", cmp.Diff(wantAddrs, seenAddrs))
+	}
+}
+
+// interpolated lists need to be stored in the original order.
+func TestContext2Plan_listOrder(t *testing.T) {
+	m := testModule(t, "plan-list-order")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.List(cty.String), Optional: true},
+				},
+			},
+		},
+	})
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	changes := plan.Changes
+	rDiffA := changes.ResourceInstance(addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "aws_instance",
+		Name: "a",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
+	rDiffB := changes.ResourceInstance(addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "aws_instance",
+		Name: "b",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
+
+	if !cmp.Equal(rDiffA.After, rDiffB.After, valueComparer) {
+		t.Fatal(cmp.Diff(rDiffA.After, rDiffB.After, valueComparer))
+	}
+}
+
+// Make sure ignore-changes doesn't interfere with set/list/map diffs.
+// If a resource was being replaced by a RequiresNew attribute that gets
+// ignored, we need to filter the diff properly to properly update rather than
+// replace.
+func TestContext2Plan_ignoreChangesWithFlatmaps(t *testing.T) {
+	m := testModule(t, "plan-ignore-changes-with-flatmaps")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"user_data":   {Type: cty.String, Optional: true},
+					"require_new": {Type: cty.String, Optional: true},
+
+					// This test predates the 0.12 work to integrate cty and
+					// HCL, and so it was ported as-is where its expected
+					// test output was clearly expecting a list of maps here
+					// even though it is named "set".
+					"set": {Type: cty.List(cty.Map(cty.String)), Optional: true},
+					"lst": {Type: cty.List(cty.String), Optional: true},
+				},
+			},
+		},
+	})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status: states.ObjectReady,
+			AttrsJSON: []byte(`{
+				"user_data":"x","require_new":"",
+				"set":[{"a":"1"}],
+				"lst":["j"]
+			}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	if len(plan.Changes.Resources) != 1 {
+		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
+	}
+
+	res := plan.Changes.Resources[0]
+	schema := p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block
+
+	ric, err := res.Decode(schema.ImpliedType())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if res.Action != plans.Update {
+		t.Fatalf("resource %s should be updated, got %s", ric.Addr, ric.Action)
+	}
+
+	if ric.Addr.String() != "aws_instance.foo" {
+		t.Fatalf("unknown resource: %s", ric.Addr)
+	}
+
+	checkVals(t, objectVal(t, schema, map[string]cty.Value{
+		"lst": cty.ListVal([]cty.Value{
+			cty.StringVal("j"),
+			cty.StringVal("k"),
+		}),
+		"require_new": cty.StringVal(""),
+		"user_data":   cty.StringVal("x"),
+		"set": cty.ListVal([]cty.Value{cty.MapVal(map[string]cty.Value{
+			"a": cty.StringVal("1"),
+			"b": cty.StringVal("2"),
+		})}),
+	}), ric.After)
+}
+
+// TestContext2Plan_resourceNestedCount ensures resource sets that depend on
+// the count of another resource set (ie: count of a data source that depends
+// on another data source's instance count - data.x.foo.*.id) get properly
+// normalized to the indexes they should be. This case comes up when there is
+// an existing state (after an initial apply).
+func TestContext2Plan_resourceNestedCount(t *testing.T) {
+	m := testModule(t, "nested-resource-count-plan")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		return providers.ReadResourceResponse{
+			NewState: req.PriorState,
+		}
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo0","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo1","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"bar0","type":"aws_instance"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"bar1","type":"aws_instance"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.baz[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"baz0","type":"aws_instance"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.baz[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"baz1","type":"aws_instance"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("validate errors: %s", diags.Err())
+	}
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("plan errors: %s", diags.Err())
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.NoOp {
+			t.Fatalf("resource %s should not change, plan returned %s", res.Addr, res.Action)
+		}
+	}
+}
+
+// Higher level test at TestResource_dataSourceListApplyPanic
+func TestContext2Plan_computedAttrRefTypeMismatch(t *testing.T) {
+	m := testModule(t, "plan-computed-attr-ref-type-mismatch")
+	p := testProvider("aws")
+	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+		var diags tfdiags.Diagnostics
+		if req.TypeName == "aws_instance" {
+			amiVal := req.Config.GetAttr("ami")
+			if amiVal.Type() != cty.String {
+				diags = diags.Append(fmt.Errorf("Expected ami to be cty.String, got %#v", amiVal))
+			}
+		}
+		return providers.ValidateResourceConfigResponse{
+			Diagnostics: diags,
+		}
+	}
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		if req.TypeName != "aws_ami_list" {
+			t.Fatalf("Reached apply for unexpected resource type! %s", req.TypeName)
+		}
+		// Pretend like we make a thing and the computed list "ids" is populated
+		s := req.PlannedState.AsValueMap()
+		s["id"] = cty.StringVal("someid")
+		s["ids"] = cty.ListVal([]cty.Value{
+			cty.StringVal("ami-abc123"),
+			cty.StringVal("ami-bcd345"),
+		})
+
+		resp.NewState = cty.ObjectVal(s)
+		return
+	}
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("Succeeded; want type mismatch error for 'ami' argument")
+	}
+
+	expected := `Inappropriate value for attribute "ami"`
+	if errStr := diags.Err().Error(); !strings.Contains(errStr, expected) {
+		t.Fatalf("expected:\n\n%s\n\nto contain:\n\n%s", errStr, expected)
+	}
+}
+
+func TestContext2Plan_selfRef(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+
+	m := testModule(t, "plan-self-ref")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected validation failure: %s", diags.Err())
+	}
+
+	_, diags = c.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("plan succeeded; want error")
+	}
+
+	gotErrStr := diags.Err().Error()
+	wantErrStr := "Self-referential block"
+	if !strings.Contains(gotErrStr, wantErrStr) {
+		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
+	}
+}
+
+func TestContext2Plan_selfRefMulti(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+
+	m := testModule(t, "plan-self-ref-multi")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected validation failure: %s", diags.Err())
+	}
+
+	_, diags = c.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("plan succeeded; want error")
+	}
+
+	gotErrStr := diags.Err().Error()
+	wantErrStr := "Self-referential block"
+	if !strings.Contains(gotErrStr, wantErrStr) {
+		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
+	}
+}
+
+func TestContext2Plan_selfRefMultiAll(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.List(cty.String), Optional: true},
+				},
+			},
+		},
+	})
+
+	m := testModule(t, "plan-self-ref-multi-all")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected validation failure: %s", diags.Err())
+	}
+
+	_, diags = c.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("plan succeeded; want error")
+	}
+
+	gotErrStr := diags.Err().Error()
+
+	// The graph is checked for cycles before we can walk it, so we don't
+	// encounter the self-reference check.
+	//wantErrStr := "Self-referential block"
+	wantErrStr := "Cycle"
+	if !strings.Contains(gotErrStr, wantErrStr) {
+		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
+	}
+}
+
+func TestContext2Plan_invalidOutput(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+data "aws_data_source" "name" {}
+
+output "out" {
+  value = data.aws_data_source.name.missing
+}`,
+	})
+
+	p := testProvider("aws")
+	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+		State: cty.ObjectVal(map[string]cty.Value{
+			"id":  cty.StringVal("data_id"),
+			"foo": cty.StringVal("foo"),
+		}),
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		// Should get this error:
+		// Unsupported attribute: This object does not have an attribute named "missing"
+		t.Fatal("succeeded; want errors")
+	}
+
+	gotErrStr := diags.Err().Error()
+	wantErrStr := "Unsupported attribute"
+	if !strings.Contains(gotErrStr, wantErrStr) {
+		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
+	}
+}
+
+func TestContext2Plan_invalidModuleOutput(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"child/main.tf": `
+data "aws_data_source" "name" {}
+
+output "out" {
+  value = "${data.aws_data_source.name.missing}"
+}`,
+		"main.tf": `
+module "child" {
+  source = "./child"
+}
+
+resource "aws_instance" "foo" {
+  foo = "${module.child.out}"
+}`,
+	})
+
+	p := testProvider("aws")
+	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+		State: cty.ObjectVal(map[string]cty.Value{
+			"id":  cty.StringVal("data_id"),
+			"foo": cty.StringVal("foo"),
+		}),
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		// Should get this error:
+		// Unsupported attribute: This object does not have an attribute named "missing"
+		t.Fatal("succeeded; want errors")
+	}
+
+	gotErrStr := diags.Err().Error()
+	wantErrStr := "Unsupported attribute"
+	if !strings.Contains(gotErrStr, wantErrStr) {
+		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
+	}
+}
+
+func TestContext2Plan_variableValidation(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "x" {
+  default = "bar"
+}
+
+resource "aws_instance" "foo" {
+  foo = var.x
+}`,
+	})
+
+	p := testProvider("aws")
+	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
+		foo := req.Config.GetAttr("foo").AsString()
+		if foo == "bar" {
+			resp.Diagnostics = resp.Diagnostics.Append(errors.New("foo cannot be bar"))
+		}
+		return
+	}
+
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		resp.PlannedState = req.ProposedNewState
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		// Should get this error:
+		// Unsupported attribute: This object does not have an attribute named "missing"
+		t.Fatal("succeeded; want errors")
+	}
+}
+
+func TestContext2Plan_variableSensitivity(t *testing.T) {
+	m := testModule(t, "plan-variable-sensitivity")
+
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		resp.PlannedState = req.ProposedNewState
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 1 {
+		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "aws_instance.foo":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"foo": cty.StringVal("foo").Mark(marks.Sensitive),
+			}), ric.After)
+			if len(res.ChangeSrc.BeforeValMarks) != 0 {
+				t.Errorf("unexpected BeforeValMarks: %#v", res.ChangeSrc.BeforeValMarks)
+			}
+			if len(res.ChangeSrc.AfterValMarks) != 1 {
+				t.Errorf("unexpected AfterValMarks: %#v", res.ChangeSrc.AfterValMarks)
+				continue
+			}
+			pvm := res.ChangeSrc.AfterValMarks[0]
+			if got, want := pvm.Path, cty.GetAttrPath("foo"); !got.Equals(want) {
+				t.Errorf("unexpected path for mark\n got: %#v\nwant: %#v", got, want)
+			}
+			if got, want := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !got.Equal(want) {
+				t.Errorf("unexpected value for mark\n got: %#v\nwant: %#v", got, want)
+			}
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_variableSensitivityModule(t *testing.T) {
+	m := testModule(t, "plan-variable-sensitivity-module")
+
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		resp.PlannedState = req.ProposedNewState
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		SetVariables: InputValues{
+			"sensitive_var": {Value: cty.NilVal},
+			"another_var": &InputValue{
+				Value:      cty.StringVal("boop"),
+				SourceType: ValueFromCaller,
+			},
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 1 {
+		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.Create {
+			t.Fatalf("expected resource creation, got %s", res.Action)
+		}
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "module.child.aws_instance.foo":
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"foo":   cty.StringVal("foo").Mark(marks.Sensitive),
+				"value": cty.StringVal("boop").Mark(marks.Sensitive),
+			}), ric.After)
+			if len(res.ChangeSrc.BeforeValMarks) != 0 {
+				t.Errorf("unexpected BeforeValMarks: %#v", res.ChangeSrc.BeforeValMarks)
+			}
+			if len(res.ChangeSrc.AfterValMarks) != 2 {
+				t.Errorf("expected AfterValMarks to contain two elements: %#v", res.ChangeSrc.AfterValMarks)
+				continue
+			}
+			// validate that the after marks have "foo" and "value"
+			contains := func(pvmSlice []cty.PathValueMarks, stepName string) bool {
+				for _, pvm := range pvmSlice {
+					if pvm.Path.Equals(cty.GetAttrPath(stepName)) {
+						if pvm.Marks.Equal(cty.NewValueMarks(marks.Sensitive)) {
+							return true
+						}
+					}
+				}
+				return false
+			}
+			if !contains(res.ChangeSrc.AfterValMarks, "foo") {
+				t.Error("unexpected AfterValMarks to contain \"foo\" with sensitive mark")
+			}
+			if !contains(res.ChangeSrc.AfterValMarks, "value") {
+				t.Error("unexpected AfterValMarks to contain \"value\" with sensitive mark")
+			}
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func checkVals(t *testing.T, expected, got cty.Value) {
+	t.Helper()
+	// The GoStringer format seems to result in the closest thing to a useful
+	// diff for values with marks.
+	// TODO: if we want to continue using cmp.Diff on cty.Values, we should
+	// make a transformer that creates a more comparable structure.
+	valueTrans := cmp.Transformer("gostring", func(v cty.Value) string {
+		return fmt.Sprintf("%#v\n", v)
+	})
+	if !cmp.Equal(expected, got, valueComparer, typeComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(expected, got, valueTrans, equateEmpty))
+	}
+}
+
+func objectVal(t *testing.T, schema *configschema.Block, m map[string]cty.Value) cty.Value {
+	t.Helper()
+	v, err := schema.CoerceValue(
+		cty.ObjectVal(m),
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	return v
+}
+
+func TestContext2Plan_requiredModuleOutput(t *testing.T) {
+	m := testModule(t, "plan-required-output")
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":       {Type: cty.String, Computed: true},
+					"required": {Type: cty.String, Required: true},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["test_resource"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		t.Run(fmt.Sprintf("%s %s", res.Action, res.Addr), func(t *testing.T) {
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource creation, got %s", res.Action)
+			}
+			ric, err := res.Decode(ty)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			var expected cty.Value
+			switch i := ric.Addr.String(); i {
+			case "test_resource.root":
+				expected = objectVal(t, schema, map[string]cty.Value{
+					"id":       cty.UnknownVal(cty.String),
+					"required": cty.UnknownVal(cty.String),
+				})
+			case "module.mod.test_resource.for_output":
+				expected = objectVal(t, schema, map[string]cty.Value{
+					"id":       cty.UnknownVal(cty.String),
+					"required": cty.StringVal("val"),
+				})
+			default:
+				t.Fatal("unknown instance:", i)
+			}
+
+			checkVals(t, expected, ric.After)
+		})
+	}
+}
+
+func TestContext2Plan_requiredModuleObject(t *testing.T) {
+	m := testModule(t, "plan-required-whole-mod")
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":       {Type: cty.String, Computed: true},
+					"required": {Type: cty.String, Required: true},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["test_resource"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 2 {
+		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		t.Run(fmt.Sprintf("%s %s", res.Action, res.Addr), func(t *testing.T) {
+			if res.Action != plans.Create {
+				t.Fatalf("expected resource creation, got %s", res.Action)
+			}
+			ric, err := res.Decode(ty)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			var expected cty.Value
+			switch i := ric.Addr.String(); i {
+			case "test_resource.root":
+				expected = objectVal(t, schema, map[string]cty.Value{
+					"id":       cty.UnknownVal(cty.String),
+					"required": cty.UnknownVal(cty.String),
+				})
+			case "module.mod.test_resource.for_output":
+				expected = objectVal(t, schema, map[string]cty.Value{
+					"id":       cty.UnknownVal(cty.String),
+					"required": cty.StringVal("val"),
+				})
+			default:
+				t.Fatal("unknown instance:", i)
+			}
+
+			checkVals(t, expected, ric.After)
+		})
+	}
+}
+
+func TestContext2Plan_expandOrphan(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod" {
+  count = 1
+  source = "./mod"
+}
+`,
+		"mod/main.tf": `
+resource "aws_instance" "foo" {
+}
+`,
+	})
+
+	state := states.NewState()
+	state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.IntKey(0))).SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"child","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.IntKey(1))).SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"child","type":"aws_instance"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	expected := map[string]plans.Action{
+		`module.mod[1].aws_instance.foo`: plans.Delete,
+		`module.mod[0].aws_instance.foo`: plans.NoOp,
+	}
+
+	for _, res := range plan.Changes.Resources {
+		want := expected[res.Addr.String()]
+		if res.Action != want {
+			t.Fatalf("expected %s action, got: %q %s", want, res.Addr, res.Action)
+		}
+		delete(expected, res.Addr.String())
+	}
+
+	for res, action := range expected {
+		t.Errorf("missing %s change for %s", action, res)
+	}
+}
+
+func TestContext2Plan_indexInVar(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "a" {
+  count = 1
+  source = "./mod"
+  in = "test"
+}
+
+module "b" {
+  count = 1
+  source = "./mod"
+  in = length(module.a)
+}
+`,
+		"mod/main.tf": `
+resource "aws_instance" "foo" {
+  foo = var.in
+}
+
+variable "in" {
+}
+
+output"out" {
+  value = aws_instance.foo.id
+}
+`,
+	})
+
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+}
+
+func TestContext2Plan_targetExpandedAddress(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod" {
+  count = 3
+  source = "./mod"
+}
+`,
+		"mod/main.tf": `
+resource "aws_instance" "foo" {
+  count = 2
+}
+`,
+	})
+
+	p := testProvider("aws")
+
+	targets := []addrs.Targetable{}
+	target, diags := addrs.ParseTargetStr("module.mod[1].aws_instance.foo[0]")
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+	targets = append(targets, target.Subject)
+
+	target, diags = addrs.ParseTargetStr("module.mod[2]")
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+	targets = append(targets, target.Subject)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode:    plans.NormalMode,
+		Targets: targets,
+	})
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	expected := map[string]plans.Action{
+		// the single targeted mod[1] instances
+		`module.mod[1].aws_instance.foo[0]`: plans.Create,
+		// the whole mode[2]
+		`module.mod[2].aws_instance.foo[0]`: plans.Create,
+		`module.mod[2].aws_instance.foo[1]`: plans.Create,
+	}
+
+	for _, res := range plan.Changes.Resources {
+		want := expected[res.Addr.String()]
+		if res.Action != want {
+			t.Fatalf("expected %s action, got: %q %s", want, res.Addr, res.Action)
+		}
+		delete(expected, res.Addr.String())
+	}
+
+	for res, action := range expected {
+		t.Errorf("missing %s change for %s", action, res)
+	}
+}
+
+func TestContext2Plan_targetResourceInModuleInstance(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod" {
+  count = 3
+  source = "./mod"
+}
+`,
+		"mod/main.tf": `
+resource "aws_instance" "foo" {
+}
+`,
+	})
+
+	p := testProvider("aws")
+
+	target, diags := addrs.ParseTargetStr("module.mod[1].aws_instance.foo")
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	targets := []addrs.Targetable{target.Subject}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode:    plans.NormalMode,
+		Targets: targets,
+	})
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	expected := map[string]plans.Action{
+		// the single targeted mod[1] instance
+		`module.mod[1].aws_instance.foo`: plans.Create,
+	}
+
+	for _, res := range plan.Changes.Resources {
+		want := expected[res.Addr.String()]
+		if res.Action != want {
+			t.Fatalf("expected %s action, got: %q %s", want, res.Addr, res.Action)
+		}
+		delete(expected, res.Addr.String())
+	}
+
+	for res, action := range expected {
+		t.Errorf("missing %s change for %s", action, res)
+	}
+}
+
+func TestContext2Plan_moduleRefIndex(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod" {
+  for_each = {
+    a = "thing"
+  }
+  in = null
+  source = "./mod"
+}
+
+module "single" {
+  source = "./mod"
+  in = module.mod["a"]
+}
+`,
+		"mod/main.tf": `
+variable "in" {
+}
+
+output "out" {
+  value = "foo"
+}
+
+resource "aws_instance" "foo" {
+}
+`,
+	})
+
+	p := testProvider("aws")
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+}
+
+func TestContext2Plan_noChangeDataPlan(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+data "test_data_source" "foo" {}
+`,
+	})
+
+	p := new(MockProvider)
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		DataSources: map[string]*configschema.Block{
+			"test_data_source": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+		},
+	})
+
+	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+		State: cty.ObjectVal(map[string]cty.Value{
+			"id":  cty.StringVal("data_id"),
+			"foo": cty.StringVal("foo"),
+		}),
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("data.test_data_source.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"data_id", "foo":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	for _, res := range plan.Changes.Resources {
+		if res.Action != plans.NoOp {
+			t.Fatalf("expected NoOp, got: %q %s", res.Addr, res.Action)
+		}
+	}
+}
+
+// for_each can reference a resource with 0 instances
+func TestContext2Plan_scaleInForEach(t *testing.T) {
+	p := testProvider("test")
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+locals {
+  m = {}
+}
+
+resource "test_instance" "a" {
+  for_each = local.m
+}
+
+resource "test_instance" "b" {
+  for_each = test_instance.a
+}
+`})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_instance.a[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"a0"}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_instance.b").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"b"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_instance.a")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	t.Run("test_instance.a[0]", func(t *testing.T) {
+		instAddr := mustResourceInstanceAddr("test_instance.a[0]")
+		change := plan.Changes.ResourceInstance(instAddr)
+		if change == nil {
+			t.Fatalf("no planned change for %s", instAddr)
+		}
+		if got, want := change.PrevRunAddr, instAddr; !want.Equal(got) {
+			t.Errorf("wrong previous run address for %s %s; want %s", instAddr, got, want)
+		}
+		if got, want := change.Action, plans.Delete; got != want {
+			t.Errorf("wrong action for %s %s; want %s", instAddr, got, want)
+		}
+		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseWrongRepetition; got != want {
+			t.Errorf("wrong action reason for %s %s; want %s", instAddr, got, want)
+		}
+	})
+	t.Run("test_instance.b", func(t *testing.T) {
+		instAddr := mustResourceInstanceAddr("test_instance.b")
+		change := plan.Changes.ResourceInstance(instAddr)
+		if change == nil {
+			t.Fatalf("no planned change for %s", instAddr)
+		}
+		if got, want := change.PrevRunAddr, instAddr; !want.Equal(got) {
+			t.Errorf("wrong previous run address for %s %s; want %s", instAddr, got, want)
+		}
+		if got, want := change.Action, plans.Delete; got != want {
+			t.Errorf("wrong action for %s %s; want %s", instAddr, got, want)
+		}
+		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseWrongRepetition; got != want {
+			t.Errorf("wrong action reason for %s %s; want %s", instAddr, got, want)
+		}
+	})
+}
+
+func TestContext2Plan_targetedModuleInstance(t *testing.T) {
+	m := testModule(t, "plan-targeted")
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Child("mod", addrs.IntKey(0)),
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	if len(plan.Changes.Resources) != 1 {
+		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
+	}
+
+	for _, res := range plan.Changes.Resources {
+		ric, err := res.Decode(ty)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		switch i := ric.Addr.String(); i {
+		case "module.mod[0].aws_instance.foo":
+			if res.Action != plans.Create {
+				t.Fatalf("resource %s should be created", i)
+			}
+			checkVals(t, objectVal(t, schema, map[string]cty.Value{
+				"id":   cty.UnknownVal(cty.String),
+				"num":  cty.NumberIntVal(2),
+				"type": cty.UnknownVal(cty.String),
+			}), ric.After)
+		default:
+			t.Fatal("unknown instance:", i)
+		}
+	}
+}
+
+func TestContext2Plan_dataRefreshedInPlan(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+data "test_data_source" "d" {
+}
+`})
+
+	p := testProvider("test")
+	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+		State: cty.ObjectVal(map[string]cty.Value{
+			"id":  cty.StringVal("this"),
+			"foo": cty.NullVal(cty.String),
+		}),
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+
+	d := plan.PriorState.ResourceInstance(mustResourceInstanceAddr("data.test_data_source.d"))
+	if d == nil || d.Current == nil {
+		t.Fatal("data.test_data_source.d not found in state:", plan.PriorState)
+	}
+
+	if d.Current.Status != states.ObjectReady {
+		t.Fatal("expected data.test_data_source.d to be fully read in refreshed state, got status", d.Current.Status)
+	}
+}
+
+func TestContext2Plan_dataReferencesResourceDirectly(t *testing.T) {
+	// When a data resource refers to a managed resource _directly_, any
+	// pending change for the managed resource will cause the data resource
+	// to be deferred to the apply step.
+	// See also TestContext2Plan_dataReferencesResourceIndirectly for the
+	// other case, where the reference is indirect.
+
+	p := testProvider("test")
+
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source should not be read"))
+		return resp
+	}
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+locals {
+  x = "value"
+}
+
+resource "test_resource" "a" {
+  value = local.x
+}
+
+// test_resource.a.value can be resolved during plan, but the reference implies
+// that the data source should wait until the resource is created.
+data "test_data_source" "d" {
+  foo = test_resource.a.value
+}
+
+// ensure referencing an indexed instance that has not yet created will also
+// delay reading the data source
+resource "test_resource" "b" {
+  count = 2
+  value = local.x
+}
+
+data "test_data_source" "e" {
+  foo = test_resource.b[0].value
+}
+`})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	rc := plan.Changes.ResourceInstance(addrs.Resource{
+		Mode: addrs.DataResourceMode,
+		Type: "test_data_source",
+		Name: "d",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
+	if rc != nil {
+		if got, want := rc.ActionReason, plans.ResourceInstanceReadBecauseDependencyPending; got != want {
+			t.Errorf("wrong ActionReason\ngot:  %s\nwant: %s", got, want)
+		}
+	} else {
+		t.Error("no change for test_data_source.e")
+	}
+}
+
+func TestContext2Plan_dataReferencesResourceIndirectly(t *testing.T) {
+	// When a data resource refers to a managed resource indirectly, pending
+	// changes for the managed resource _do not_ cause the data resource to
+	// be deferred to apply. This is a pragmatic special case added for
+	// backward compatibility with the old situation where we would _always_
+	// eagerly read data resources with known configurations, regardless of
+	// the plans for their dependencies.
+	// This test creates an indirection through a local value, but the same
+	// principle would apply for both input variable and output value
+	// indirection.
+	//
+	// See also TestContext2Plan_dataReferencesResourceDirectly for the
+	// other case, where the reference is direct.
+	// This special exception doesn't apply for a data resource that has
+	// custom conditions; see
+	// TestContext2Plan_dataResourceChecksManagedResourceChange for that
+	// situation.
+
+	p := testProvider("test")
+	var applyCount int64
+	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+		atomic.AddInt64(&applyCount, 1)
+		resp.NewState = req.PlannedState
+		return resp
+	}
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+		if atomic.LoadInt64(&applyCount) == 0 {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source read before managed resource apply"))
+		} else {
+			resp.State = req.Config
+		}
+		return resp
+	}
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+locals {
+	x = "value"
+}
+
+resource "test_resource" "a" {
+	value = local.x
+}
+
+locals {
+	y = test_resource.a.value
+}
+
+// test_resource.a.value would ideally cause a pending change for
+// test_resource.a to defer this to the apply step, but we intentionally don't
+// do that when it's indirect (through a local value, here) as a concession
+// to backward compatibility.
+data "test_data_source" "d" {
+	foo = local.y
+}
+`})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatalf("successful plan; want an error")
+	}
+
+	if got, want := diags.Err().Error(), "data source read before managed resource apply"; !strings.Contains(got, want) {
+		t.Errorf("Missing expected error message\ngot: %s\nwant substring: %s", got, want)
+	}
+}
+
+func TestContext2Plan_skipRefresh(t *testing.T) {
+	p := testProvider("test")
+	p.PlanResourceChangeFn = testDiffFn
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_instance" "a" {
+}
+`})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_instance.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"a","type":"test_instance"}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{
+		Mode:        plans.NormalMode,
+		SkipRefresh: true,
+	})
+	assertNoErrors(t, diags)
+
+	if p.ReadResourceCalled {
+		t.Fatal("Resource should not have been refreshed")
+	}
+
+	for _, c := range plan.Changes.Resources {
+		if c.Action != plans.NoOp {
+			t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr)
+		}
+	}
+}
+
+func TestContext2Plan_dataInModuleDependsOn(t *testing.T) {
+	p := testProvider("test")
+
+	readDataSourceB := false
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+		cfg := req.Config.AsValueMap()
+		foo := cfg["foo"].AsString()
+
+		cfg["id"] = cty.StringVal("ID")
+		cfg["foo"] = cty.StringVal("new")
+
+		if foo == "b" {
+			readDataSourceB = true
+		}
+
+		resp.State = cty.ObjectVal(cfg)
+		return resp
+	}
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "a" {
+  source = "./mod_a"
+}
+
+module "b" {
+  source = "./mod_b"
+  depends_on = [module.a]
+}`,
+		"mod_a/main.tf": `
+data "test_data_source" "a" {
+  foo = "a"
+}`,
+		"mod_b/main.tf": `
+data "test_data_source" "b" {
+  foo = "b"
+}`,
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	assertNoErrors(t, diags)
+
+	// The change to data source a should not prevent data source b from being
+	// read.
+	if !readDataSourceB {
+		t.Fatal("data source b was not read during plan")
+	}
+}
+
+func TestContext2Plan_rpcDiagnostics(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_instance" "a" {
+}
+`,
+	})
+
+	p := testProvider("test")
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		resp := testDiffFn(req)
+		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("don't frobble"))
+		return resp
+	}
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	if len(diags) == 0 {
+		t.Fatal("expected warnings")
+	}
+
+	for _, d := range diags {
+		des := d.Description().Summary
+		if !strings.Contains(des, "frobble") {
+			t.Fatalf(`expected frobble, got %q`, des)
+		}
+	}
+}
+
+// ignore_changes needs to be re-applied to the planned value for provider
+// using the LegacyTypeSystem
+func TestContext2Plan_legacyProviderIgnoreChanges(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_instance" "a" {
+  lifecycle {
+    ignore_changes = [data]
+  }
+}
+`,
+	})
+
+	p := testProvider("test")
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		m := req.ProposedNewState.AsValueMap()
+		// this provider "hashes" the data attribute as bar
+		m["data"] = cty.StringVal("bar")
+
+		resp.PlannedState = cty.ObjectVal(m)
+		resp.LegacyTypeSystem = true
+		return resp
+	}
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":   {Type: cty.String, Computed: true},
+					"data": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_instance.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"a","data":"foo"}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	for _, c := range plan.Changes.Resources {
+		if c.Action != plans.NoOp {
+			t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr)
+		}
+	}
+}
+
+func TestContext2Plan_validateIgnoreAll(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_instance" "a" {
+  lifecycle {
+    ignore_changes = all
+  }
+}
+`,
+	})
+
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":   {Type: cty.String, Computed: true},
+					"data": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+		var diags tfdiags.Diagnostics
+		if req.TypeName == "test_instance" {
+			if !req.Config.GetAttr("id").IsNull() {
+				diags = diags.Append(errors.New("id cannot be set in config"))
+			}
+		}
+		return providers.ValidateResourceConfigResponse{
+			Diagnostics: diags,
+		}
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_instance.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"a","data":"foo"}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	_, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+}
+
+func TestContext2Plan_legacyProviderIgnoreAll(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_instance" "a" {
+  lifecycle {
+    ignore_changes = all
+  }
+  data = "foo"
+}
+`,
+	})
+
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":   {Type: cty.String, Computed: true},
+					"data": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		plan := req.ProposedNewState.AsValueMap()
+		// Update both the computed id and the configured data.
+		// Legacy providers expect terraform to be able to ignore these.
+
+		plan["id"] = cty.StringVal("updated")
+		plan["data"] = cty.StringVal("updated")
+		resp.PlannedState = cty.ObjectVal(plan)
+		resp.LegacyTypeSystem = true
+		return resp
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_instance.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"orig","data":"orig"}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	for _, c := range plan.Changes.Resources {
+		if c.Action != plans.NoOp {
+			t.Fatalf("expected NoOp plan, got %s\n", c.Action)
+		}
+	}
+}
+
+func TestContext2Plan_dataRemovalNoProvider(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_instance" "a" {
+}
+`,
+	})
+
+	p := testProvider("test")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_instance.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"a","data":"foo"}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	// the provider for this data source is no longer in the config, but that
+	// should not matter for state removal.
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("data.test_data_source.d").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"d"}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/local/test"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+			// We still need to be able to locate the provider to decode the
+			// state, since we do not know during init that this provider is
+			// only used for an orphaned data source.
+			addrs.NewProvider("registry.terraform.io", "local", "test"): testProviderFuncFixed(p),
+		},
+	})
+	_, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+}
+
+func TestContext2Plan_noSensitivityChange(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "sensitive_var" {
+       default = "hello"
+       sensitive = true
+}
+
+resource "test_resource" "foo" {
+       value = var.sensitive_var
+       sensitive_value = var.sensitive_var
+}`,
+	})
+
+	p := testProvider("test")
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_resource",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectReady,
+				AttrsJSON: []byte(`{"id":"foo", "value":"hello", "sensitive_value":"hello"}`),
+				AttrSensitivePaths: []cty.PathValueMarks{
+					{Path: cty.Path{cty.GetAttrStep{Name: "value"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+					{Path: cty.Path{cty.GetAttrStep{Name: "sensitive_value"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+				},
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	for _, c := range plan.Changes.Resources {
+		if c.Action != plans.NoOp {
+			t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr)
+		}
+	}
+}
+
+func TestContext2Plan_variableCustomValidationsSensitive(t *testing.T) {
+	m := testModule(t, "validate-variable-custom-validations-child-sensitive")
+
+	p := testProvider("test")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		t.Fatal("succeeded; want errors")
+	}
+	if got, want := diags.Err().Error(), `Invalid value for variable: Value must not be "nope".`; !strings.Contains(got, want) {
+		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
+	}
+}
+
+func TestContext2Plan_nullOutputNoOp(t *testing.T) {
+	// this should always plan a NoOp change for the output
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+output "planned" {
+  value = false ? 1 : null
+}
+`,
+	})
+
+	ctx := testContext2(t, &ContextOpts{})
+	state := states.BuildState(func(s *states.SyncState) {
+		r := s.Module(addrs.RootModuleInstance)
+		r.SetOutputValue("planned", cty.NullVal(cty.DynamicPseudoType), false)
+	})
+	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	for _, c := range plan.Changes.Outputs {
+		if c.Action != plans.NoOp {
+			t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr)
+		}
+	}
+}
+
+func TestContext2Plan_createOutput(t *testing.T) {
+	// this should always plan a NoOp change for the output
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+output "planned" {
+  value = 1
+}
+`,
+	})
+
+	ctx := testContext2(t, &ContextOpts{})
+	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	for _, c := range plan.Changes.Outputs {
+		if c.Action != plans.Create {
+			t.Fatalf("expected Create change, got %s for %q", c.Action, c.Addr)
+		}
+	}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NOTE: Due to the size of this file, new tests should be added to
+// context_plan2_test.go.
+////////////////////////////////////////////////////////////////////////////////
diff --git a/v1.5.7/internal/terraform/context_plugins.go b/v1.5.7/internal/terraform/context_plugins.go
new file mode 100644
index 0000000..24e5371
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_plugins.go
@@ -0,0 +1,212 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+)
+
+// contextPlugins represents a library of available plugins (providers and
+// provisioners) which we assume will all be used with the same
+// terraform.Context, and thus it'll be safe to cache certain information
+// about the providers for performance reasons.
+type contextPlugins struct {
+	providerFactories    map[addrs.Provider]providers.Factory
+	provisionerFactories map[string]provisioners.Factory
+
+	// We memoize the schemas we've previously loaded in here, to avoid
+	// repeatedly paying the cost of activating the same plugins to access
+	// their schemas in various different spots. We use schemas for many
+	// purposes in Terraform, so there isn't a single choke point where
+	// it makes sense to preload all of them.
+	providerSchemas    map[addrs.Provider]*ProviderSchema
+	provisionerSchemas map[string]*configschema.Block
+	schemasLock        sync.Mutex
+}
+
+func newContextPlugins(providerFactories map[addrs.Provider]providers.Factory, provisionerFactories map[string]provisioners.Factory) *contextPlugins {
+	ret := &contextPlugins{
+		providerFactories:    providerFactories,
+		provisionerFactories: provisionerFactories,
+	}
+	ret.init()
+	return ret
+}
+
+func (cp *contextPlugins) init() {
+	cp.providerSchemas = make(map[addrs.Provider]*ProviderSchema, len(cp.providerFactories))
+	cp.provisionerSchemas = make(map[string]*configschema.Block, len(cp.provisionerFactories))
+}
+
+func (cp *contextPlugins) HasProvider(addr addrs.Provider) bool {
+	_, ok := cp.providerFactories[addr]
+	return ok
+}
+
+func (cp *contextPlugins) NewProviderInstance(addr addrs.Provider) (providers.Interface, error) {
+	f, ok := cp.providerFactories[addr]
+	if !ok {
+		return nil, fmt.Errorf("unavailable provider %q", addr.String())
+	}
+
+	return f()
+
+}
+
+func (cp *contextPlugins) HasProvisioner(typ string) bool {
+	_, ok := cp.provisionerFactories[typ]
+	return ok
+}
+
+func (cp *contextPlugins) NewProvisionerInstance(typ string) (provisioners.Interface, error) {
+	f, ok := cp.provisionerFactories[typ]
+	if !ok {
+		return nil, fmt.Errorf("unavailable provisioner %q", typ)
+	}
+
+	return f()
+}
+
+// ProviderSchema uses a temporary instance of the provider with the given
+// address to obtain the full schema for all aspects of that provider.
+//
+// ProviderSchema memoizes results by unique provider address, so it's fine
+// to repeatedly call this method with the same address if various different
+// parts of Terraform all need the same schema information.
+func (cp *contextPlugins) ProviderSchema(addr addrs.Provider) (*ProviderSchema, error) {
+	cp.schemasLock.Lock()
+	defer cp.schemasLock.Unlock()
+
+	if schema, ok := cp.providerSchemas[addr]; ok {
+		return schema, nil
+	}
+
+	log.Printf("[TRACE] terraform.contextPlugins: Initializing provider %q to read its schema", addr)
+
+	provider, err := cp.NewProviderInstance(addr)
+	if err != nil {
+		return nil, fmt.Errorf("failed to instantiate provider %q to obtain schema: %s", addr, err)
+	}
+	defer provider.Close()
+
+	resp := provider.GetProviderSchema()
+	if resp.Diagnostics.HasErrors() {
+		return nil, fmt.Errorf("failed to retrieve schema from provider %q: %s", addr, resp.Diagnostics.Err())
+	}
+
+	s := &ProviderSchema{
+		Provider:      resp.Provider.Block,
+		ResourceTypes: make(map[string]*configschema.Block),
+		DataSources:   make(map[string]*configschema.Block),
+
+		ResourceTypeSchemaVersions: make(map[string]uint64),
+	}
+
+	if resp.Provider.Version < 0 {
+		// We're not using the version numbers here yet, but we'll check
+		// for validity anyway in case we start using them in future.
+		return nil, fmt.Errorf("provider %s has invalid negative schema version for its configuration blocks,which is a bug in the provider ", addr)
+	}
+
+	for t, r := range resp.ResourceTypes {
+		if err := r.Block.InternalValidate(); err != nil {
+			return nil, fmt.Errorf("provider %s has invalid schema for managed resource type %q, which is a bug in the provider: %q", addr, t, err)
+		}
+		s.ResourceTypes[t] = r.Block
+		s.ResourceTypeSchemaVersions[t] = uint64(r.Version)
+		if r.Version < 0 {
+			return nil, fmt.Errorf("provider %s has invalid negative schema version for managed resource type %q, which is a bug in the provider", addr, t)
+		}
+	}
+
+	for t, d := range resp.DataSources {
+		if err := d.Block.InternalValidate(); err != nil {
+			return nil, fmt.Errorf("provider %s has invalid schema for data resource type %q, which is a bug in the provider: %q", addr, t, err)
+		}
+		s.DataSources[t] = d.Block
+		if d.Version < 0 {
+			// We're not using the version numbers here yet, but we'll check
+			// for validity anyway in case we start using them in future.
+			return nil, fmt.Errorf("provider %s has invalid negative schema version for data resource type %q, which is a bug in the provider", addr, t)
+		}
+	}
+
+	if resp.ProviderMeta.Block != nil {
+		s.ProviderMeta = resp.ProviderMeta.Block
+	}
+
+	cp.providerSchemas[addr] = s
+	return s, nil
+}
+
+// ProviderConfigSchema is a helper wrapper around ProviderSchema which first
+// reads the full schema of the given provider and then extracts just the
+// provider's configuration schema, which defines what's expected in a
+// "provider" block in the configuration when configuring this provider.
+func (cp *contextPlugins) ProviderConfigSchema(providerAddr addrs.Provider) (*configschema.Block, error) {
+	providerSchema, err := cp.ProviderSchema(providerAddr)
+	if err != nil {
+		return nil, err
+	}
+
+	return providerSchema.Provider, nil
+}
+
+// ResourceTypeSchema is a helper wrapper around ProviderSchema which first
+// reads the schema of the given provider and then tries to find the schema
+// for the resource type of the given resource mode in that provider.
+//
+// ResourceTypeSchema will return an error if the provider schema lookup
+// fails, but will return nil if the provider schema lookup succeeds but then
+// the provider doesn't have a resource of the requested type.
+//
+// Managed resource types have versioned schemas, so the second return value
+// is the current schema version number for the requested resource. The version
+// is irrelevant for other resource modes.
+func (cp *contextPlugins) ResourceTypeSchema(providerAddr addrs.Provider, resourceMode addrs.ResourceMode, resourceType string) (*configschema.Block, uint64, error) {
+	providerSchema, err := cp.ProviderSchema(providerAddr)
+	if err != nil {
+		return nil, 0, err
+	}
+
+	schema, version := providerSchema.SchemaForResourceType(resourceMode, resourceType)
+	return schema, version, nil
+}
+
+// ProvisionerSchema uses a temporary instance of the provisioner with the
+// given type name to obtain the schema for that provisioner's configuration.
+//
+// ProvisionerSchema memoizes results by provisioner type name, so it's fine
+// to repeatedly call this method with the same name if various different
+// parts of Terraform all need the same schema information.
+func (cp *contextPlugins) ProvisionerSchema(typ string) (*configschema.Block, error) {
+	cp.schemasLock.Lock()
+	defer cp.schemasLock.Unlock()
+
+	if schema, ok := cp.provisionerSchemas[typ]; ok {
+		return schema, nil
+	}
+
+	log.Printf("[TRACE] terraform.contextPlugins: Initializing provisioner %q to read its schema", typ)
+	provisioner, err := cp.NewProvisionerInstance(typ)
+	if err != nil {
+		return nil, fmt.Errorf("failed to instantiate provisioner %q to obtain schema: %s", typ, err)
+	}
+	defer provisioner.Close()
+
+	resp := provisioner.GetSchema()
+	if resp.Diagnostics.HasErrors() {
+		return nil, fmt.Errorf("failed to retrieve schema from provisioner %q: %s", typ, resp.Diagnostics.Err())
+	}
+
+	cp.provisionerSchemas[typ] = resp.Provisioner
+	return resp.Provisioner, nil
+}
diff --git a/v1.5.7/internal/terraform/context_plugins_test.go b/v1.5.7/internal/terraform/context_plugins_test.go
new file mode 100644
index 0000000..20b8945
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_plugins_test.go
@@ -0,0 +1,86 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+)
+
+// simpleMockPluginLibrary returns a plugin library pre-configured with
+// one provider and one provisioner, both called "test".
+//
+// The provider is built with simpleMockProvider and the provisioner with
+// simpleMockProvisioner, and all schemas used in both are as built by
+// function simpleTestSchema.
+//
+// Each call to this function produces an entirely-separate set of objects,
+// so the caller can feel free to modify the returned value to further
+// customize the mocks contained within.
+func simpleMockPluginLibrary() *contextPlugins {
+	// We create these out here, rather than in the factory functions below,
+	// because we want each call to the factory to return the _same_ instance,
+	// so that test code can customize it before passing this component
+	// factory into real code under test.
+	provider := simpleMockProvider()
+	provisioner := simpleMockProvisioner()
+	ret := &contextPlugins{
+		providerFactories: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): func() (providers.Interface, error) {
+				return provider, nil
+			},
+		},
+		provisionerFactories: map[string]provisioners.Factory{
+			"test": func() (provisioners.Interface, error) {
+				return provisioner, nil
+			},
+		},
+	}
+	ret.init() // prepare the internal cache data structures
+	return ret
+}
+
+// simpleTestSchema returns a block schema that contains a few optional
+// attributes for use in tests.
+//
+// The returned schema contains the following optional attributes:
+//
+//   - test_string, of type string
+//   - test_number, of type number
+//   - test_bool, of type bool
+//   - test_list, of type list(string)
+//   - test_map, of type map(string)
+//
+// Each call to this function produces an entirely new schema instance, so
+// callers can feel free to modify it once returned.
+func simpleTestSchema() *configschema.Block {
+	return &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"test_string": {
+				Type:     cty.String,
+				Optional: true,
+			},
+			"test_number": {
+				Type:     cty.Number,
+				Optional: true,
+			},
+			"test_bool": {
+				Type:     cty.Bool,
+				Optional: true,
+			},
+			"test_list": {
+				Type:     cty.List(cty.String),
+				Optional: true,
+			},
+			"test_map": {
+				Type:     cty.Map(cty.String),
+				Optional: true,
+			},
+		},
+	}
+}
diff --git a/v1.5.7/internal/terraform/context_refresh.go b/v1.5.7/internal/terraform/context_refresh.go
new file mode 100644
index 0000000..7b37605
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_refresh.go
@@ -0,0 +1,40 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Refresh is a vestigial operation that is equivalent to call to Plan and
+// then taking the prior state of the resulting plan.
+//
+// We retain this only as a measure of semi-backward-compatibility for
+// automation relying on the "terraform refresh" subcommand. The modern way
+// to get this effect is to create and then apply a plan in the refresh-only
+// mode.
+func (c *Context) Refresh(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*states.State, tfdiags.Diagnostics) {
+	if opts == nil {
+		// This fallback is only here for tests, not for real code.
+		opts = &PlanOpts{
+			Mode: plans.NormalMode,
+		}
+	}
+	if opts.Mode != plans.NormalMode {
+		panic("can only Refresh in the normal planning mode")
+	}
+
+	log.Printf("[DEBUG] Refresh is really just plan now, so creating a %s plan", opts.Mode)
+	p, diags := c.Plan(config, prevRunState, opts)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	return p.PriorState, diags
+}
diff --git a/v1.5.7/internal/terraform/context_refresh_test.go b/v1.5.7/internal/terraform/context_refresh_test.go
new file mode 100644
index 0000000..b181dd4
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_refresh_test.go
@@ -0,0 +1,1688 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"reflect"
+	"sort"
+	"strings"
+	"sync"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestContext2Refresh(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "refresh-basic")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.web").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo","foo":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+	readState, err := hcl2shim.HCL2ValueFromFlatmap(map[string]string{"id": "foo", "foo": "baz"}, ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: readState,
+	}
+
+	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	if !p.ReadResourceCalled {
+		t.Fatal("ReadResource should be called")
+	}
+
+	mod := s.RootModule()
+	fromState, err := mod.Resources["aws_instance.web"].Instances[addrs.NoKey].Current.Decode(ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	newState, err := schema.CoerceValue(fromState.Value)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !cmp.Equal(readState, newState, valueComparer) {
+		t.Fatal(cmp.Diff(readState, newState, valueComparer, equateEmpty))
+	}
+}
+
+func TestContext2Refresh_dynamicAttr(t *testing.T) {
+	m := testModule(t, "refresh-dynamic")
+
+	startingState := states.BuildState(func(ss *states.SyncState) {
+		ss.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectReady,
+				AttrsJSON: []byte(`{"dynamic":{"type":"string","value":"hello"}}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	readStateVal := cty.ObjectVal(map[string]cty.Value{
+		"dynamic": cty.EmptyTupleVal,
+	})
+
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"dynamic": {Type: cty.DynamicPseudoType, Optional: true},
+				},
+			},
+		},
+	})
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		return providers.ReadResourceResponse{
+			NewState: readStateVal,
+		}
+	}
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		resp.PlannedState = req.ProposedNewState
+		return resp
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["test_instance"].Block
+	ty := schema.ImpliedType()
+
+	s, diags := ctx.Refresh(m, startingState, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	if !p.ReadResourceCalled {
+		t.Fatal("ReadResource should be called")
+	}
+
+	mod := s.RootModule()
+	newState, err := mod.Resources["test_instance.foo"].Instances[addrs.NoKey].Current.Decode(ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !cmp.Equal(readStateVal, newState.Value, valueComparer) {
+		t.Error(cmp.Diff(newState.Value, readStateVal, valueComparer, equateEmpty))
+	}
+}
+
+func TestContext2Refresh_dataComputedModuleVar(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "refresh-data-module-var")
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		obj := req.ProposedNewState.AsValueMap()
+		obj["id"] = cty.UnknownVal(cty.String)
+		resp.PlannedState = cty.ObjectVal(obj)
+		return resp
+	}
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+		resp.State = req.Config
+		return resp
+	}
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+		},
+		DataSources: map[string]*configschema.Block{
+			"aws_data_source": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"output": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{Mode: plans.RefreshOnlyMode})
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+
+	checkStateString(t, plan.PriorState, `
+<no state>
+`)
+}
+
+func TestContext2Refresh_targeted(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_elb": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"instances": {
+						Type:     cty.Set(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"vpc_id": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			"aws_vpc": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+		},
+	})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	testSetResourceInstanceCurrent(root, "aws_vpc.metoo", `{"id":"vpc-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	testSetResourceInstanceCurrent(root, "aws_instance.notme", `{"id":"i-bcd345"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	testSetResourceInstanceCurrent(root, "aws_instance.me", `{"id":"i-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	testSetResourceInstanceCurrent(root, "aws_elb.meneither", `{"id":"lb-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+
+	m := testModule(t, "refresh-targeted")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	refreshedResources := make([]string, 0, 2)
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		refreshedResources = append(refreshedResources, req.PriorState.GetAttr("id").AsString())
+		return providers.ReadResourceResponse{
+			NewState: req.PriorState,
+		}
+	}
+
+	_, diags := ctx.Refresh(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "me",
+			),
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+
+	expected := []string{"vpc-abc123", "i-abc123"}
+	if !reflect.DeepEqual(refreshedResources, expected) {
+		t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources)
+	}
+}
+
+func TestContext2Refresh_targetedCount(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_elb": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"instances": {
+						Type:     cty.Set(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"vpc_id": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			"aws_vpc": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+		},
+	})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	testSetResourceInstanceCurrent(root, "aws_vpc.metoo", `{"id":"vpc-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	testSetResourceInstanceCurrent(root, "aws_instance.notme", `{"id":"i-bcd345"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	testSetResourceInstanceCurrent(root, "aws_instance.me[0]", `{"id":"i-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	testSetResourceInstanceCurrent(root, "aws_instance.me[1]", `{"id":"i-cde567"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	testSetResourceInstanceCurrent(root, "aws_instance.me[2]", `{"id":"i-cde789"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	testSetResourceInstanceCurrent(root, "aws_elb.meneither", `{"id":"lb-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+
+	m := testModule(t, "refresh-targeted-count")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	refreshedResources := make([]string, 0, 2)
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		refreshedResources = append(refreshedResources, req.PriorState.GetAttr("id").AsString())
+		return providers.ReadResourceResponse{
+			NewState: req.PriorState,
+		}
+	}
+
+	_, diags := ctx.Refresh(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "me",
+			),
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+
+	// Target didn't specify index, so we should get all our instances
+	expected := []string{
+		"vpc-abc123",
+		"i-abc123",
+		"i-cde567",
+		"i-cde789",
+	}
+	sort.Strings(expected)
+	sort.Strings(refreshedResources)
+	if !reflect.DeepEqual(refreshedResources, expected) {
+		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", refreshedResources, expected)
+	}
+}
+
+func TestContext2Refresh_targetedCountIndex(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_elb": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"instances": {
+						Type:     cty.Set(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"vpc_id": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			"aws_vpc": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+		},
+	})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	testSetResourceInstanceCurrent(root, "aws_vpc.metoo", `{"id":"vpc-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	testSetResourceInstanceCurrent(root, "aws_instance.notme", `{"id":"i-bcd345"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	testSetResourceInstanceCurrent(root, "aws_instance.me[0]", `{"id":"i-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	testSetResourceInstanceCurrent(root, "aws_instance.me[1]", `{"id":"i-cde567"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	testSetResourceInstanceCurrent(root, "aws_instance.me[2]", `{"id":"i-cde789"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	testSetResourceInstanceCurrent(root, "aws_elb.meneither", `{"id":"lb-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+
+	m := testModule(t, "refresh-targeted-count")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	refreshedResources := make([]string, 0, 2)
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		refreshedResources = append(refreshedResources, req.PriorState.GetAttr("id").AsString())
+		return providers.ReadResourceResponse{
+			NewState: req.PriorState,
+		}
+	}
+
+	_, diags := ctx.Refresh(m, state, &PlanOpts{
+		Mode: plans.NormalMode,
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.ResourceInstance(
+				addrs.ManagedResourceMode, "aws_instance", "me", addrs.IntKey(0),
+			),
+		},
+	})
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+
+	expected := []string{"vpc-abc123", "i-abc123"}
+	if !reflect.DeepEqual(refreshedResources, expected) {
+		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", refreshedResources, expected)
+	}
+}
+
+func TestContext2Refresh_moduleComputedVar(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"value": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+		},
+	})
+
+	m := testModule(t, "refresh-module-computed-var")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	// This was failing (see GH-2188) at some point, so this test just
+	// verifies that the failure goes away.
+	if _, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() {
+		t.Fatalf("refresh errs: %s", diags.Err())
+	}
+}
+
+func TestContext2Refresh_delete(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "refresh-basic")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.NullVal(p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block.ImpliedType()),
+	}
+
+	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+
+	mod := s.RootModule()
+	if len(mod.Resources) > 0 {
+		t.Fatal("resources should be empty")
+	}
+}
+
+func TestContext2Refresh_ignoreUncreated(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "refresh-basic")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"id": cty.StringVal("foo"),
+		}),
+	}
+
+	_, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+	if p.ReadResourceCalled {
+		t.Fatal("refresh should not be called")
+	}
+}
+
+func TestContext2Refresh_hook(t *testing.T) {
+	h := new(MockHook)
+	p := testProvider("aws")
+	m := testModule(t, "refresh-basic")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+
+	ctx := testContext2(t, &ContextOpts{
+		Hooks: []Hook{h},
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	if _, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() {
+		t.Fatalf("refresh errs: %s", diags.Err())
+	}
+	if !h.PreRefreshCalled {
+		t.Fatal("should be called")
+	}
+	if !h.PostRefreshCalled {
+		t.Fatal("should be called")
+	}
+}
+
+func TestContext2Refresh_modules(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "refresh-modules")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	testSetResourceInstanceTainted(root, "aws_instance.web", `{"id":"bar"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	testSetResourceInstanceCurrent(child, "aws_instance.web", `{"id":"baz"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		if !req.PriorState.GetAttr("id").RawEquals(cty.StringVal("baz")) {
+			return providers.ReadResourceResponse{
+				NewState: req.PriorState,
+			}
+		}
+
+		new, _ := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) {
+			if len(path) == 1 && path[0].(cty.GetAttrStep).Name == "id" {
+				return cty.StringVal("new"), nil
+			}
+			return v, nil
+		})
+		return providers.ReadResourceResponse{
+			NewState: new,
+		}
+	}
+
+	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace(testContextRefreshModuleStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Refresh_moduleInputComputedOutput(t *testing.T) {
+	m := testModule(t, "refresh-module-input-computed-output")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+					"compute": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	if _, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() {
+		t.Fatalf("refresh errs: %s", diags.Err())
+	}
+}
+
+func TestContext2Refresh_moduleVarModule(t *testing.T) {
+	m := testModule(t, "refresh-module-var-module")
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	if _, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() {
+		t.Fatalf("refresh errs: %s", diags.Err())
+	}
+}
+
+// GH-70
+func TestContext2Refresh_noState(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "refresh-no-state")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.ObjectVal(map[string]cty.Value{
+			"id": cty.StringVal("foo"),
+		}),
+	}
+
+	if _, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() {
+		t.Fatalf("refresh errs: %s", diags.Err())
+	}
+}
+
+func TestContext2Refresh_output(t *testing.T) {
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = testDiffFn
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+				},
+			},
+		},
+	})
+
+	m := testModule(t, "refresh-output")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo","foo":"bar"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	root.SetOutputValue("foo", cty.StringVal("foo"), false)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace(testContextRefreshOutputStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%q\n\nwant:\n%q", actual, expected)
+	}
+}
+
+func TestContext2Refresh_outputPartial(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "refresh-output-partial")
+
+	// Refresh creates a partial plan for any instances that don't have
+	// remote objects yet, to get stub values for interpolation. Therefore
+	// we need to make DiffFn available to let that complete.
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+		},
+	})
+
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.NullVal(p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block.ImpliedType()),
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	testSetResourceInstanceCurrent(root, "aws_instance.foo", `{}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace(testContextRefreshOutputPartialStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Refresh_stateBasic(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "refresh-basic")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"bar"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
+	ty := schema.ImpliedType()
+
+	readStateVal, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("foo"),
+	}))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: readStateVal,
+	}
+
+	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+
+	if !p.ReadResourceCalled {
+		t.Fatal("read resource should be called")
+	}
+
+	mod := s.RootModule()
+	newState, err := mod.Resources["aws_instance.web"].Instances[addrs.NoKey].Current.Decode(ty)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !cmp.Equal(readStateVal, newState.Value, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(readStateVal, newState.Value, valueComparer, equateEmpty))
+	}
+}
+
+func TestContext2Refresh_dataCount(t *testing.T) {
+	p := testProvider("test")
+	m := testModule(t, "refresh-data-count")
+
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		m := req.ProposedNewState.AsValueMap()
+		m["things"] = cty.ListVal([]cty.Value{cty.StringVal("foo")})
+		resp.PlannedState = cty.ObjectVal(m)
+		return resp
+	}
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":     {Type: cty.String, Computed: true},
+					"things": {Type: cty.List(cty.String), Computed: true},
+				},
+			},
+		},
+		DataSources: map[string]*configschema.Block{
+			"test": {},
+		},
+	})
+
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		return providers.ReadDataSourceResponse{
+			State: req.Config,
+		}
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	s, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode})
+
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+
+	checkStateString(t, s, `<no state>`)
+}
+
+func TestContext2Refresh_dataState(t *testing.T) {
+	m := testModule(t, "refresh-data-resource-basic")
+	state := states.NewState()
+	schema := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"inputs": {
+				Type:     cty.Map(cty.String),
+				Optional: true,
+			},
+		},
+	}
+
+	p := testProvider("null")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{},
+		DataSources: map[string]*configschema.Block{
+			"null_data_source": schema,
+		},
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		},
+	})
+
+	var readStateVal cty.Value
+
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		m := req.Config.AsValueMap()
+		readStateVal = cty.ObjectVal(m)
+
+		return providers.ReadDataSourceResponse{
+			State: readStateVal,
+		}
+	}
+
+	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+
+	if !p.ReadDataSourceCalled {
+		t.Fatal("ReadDataSource should have been called")
+	}
+
+	mod := s.RootModule()
+
+	newState, err := mod.Resources["data.null_data_source.testing"].Instances[addrs.NoKey].Current.Decode(schema.ImpliedType())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !cmp.Equal(readStateVal, newState.Value, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(readStateVal, newState.Value, valueComparer, equateEmpty))
+	}
+}
+
+func TestContext2Refresh_dataStateRefData(t *testing.T) {
+	p := testProvider("null")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{},
+		DataSources: map[string]*configschema.Block{
+			"null_data_source": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"bar": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+		},
+	})
+
+	m := testModule(t, "refresh-data-ref-data")
+	state := states.NewState()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
+		// add the required id
+		m := req.Config.AsValueMap()
+		m["id"] = cty.StringVal("foo")
+
+		return providers.ReadDataSourceResponse{
+			State: cty.ObjectVal(m),
+		}
+	}
+
+	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace(testTerraformRefreshDataRefDataStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestContext2Refresh_tainted(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "refresh-basic")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	testSetResourceInstanceTainted(root, "aws_instance.web", `{"id":"bar"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		// add the required id
+		m := req.PriorState.AsValueMap()
+		m["id"] = cty.StringVal("foo")
+
+		return providers.ReadResourceResponse{
+			NewState: cty.ObjectVal(m),
+		}
+	}
+
+	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+	if !p.ReadResourceCalled {
+		t.Fatal("ReadResource was not called; should have been")
+	}
+
+	actual := strings.TrimSpace(s.String())
+	expected := strings.TrimSpace(testContextRefreshTaintedStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+// Doing a Refresh (or any operation really, but Refresh usually
+// happens first) with a config with an unknown provider should result in
+// an error. The key bug this found was that this wasn't happening if
+// Providers was _empty_.
+func TestContext2Refresh_unknownProvider(t *testing.T) {
+	m := testModule(t, "refresh-unknown-provider")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+
+	c, diags := NewContext(&ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{},
+	})
+	assertNoDiagnostics(t, diags)
+
+	_, diags = c.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode})
+	if !diags.HasErrors() {
+		t.Fatal("successfully refreshed; want error")
+	}
+
+	if got, want := diags.Err().Error(), "Missing required provider"; !strings.Contains(got, want) {
+		t.Errorf("missing expected error\nwant substring: %s\ngot:\n%s", want, got)
+	}
+}
+
+func TestContext2Refresh_vars(t *testing.T) {
+	p := testProvider("aws")
+
+	schema := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"ami": {
+				Type:     cty.String,
+				Optional: true,
+			},
+			"id": {
+				Type:     cty.String,
+				Computed: true,
+			},
+		},
+	}
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider:      &configschema.Block{},
+		ResourceTypes: map[string]*configschema.Block{"aws_instance": schema},
+	})
+
+	m := testModule(t, "refresh-vars")
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	readStateVal, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("foo"),
+	}))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: readStateVal,
+	}
+
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
+		return providers.PlanResourceChangeResponse{
+			PlannedState: req.ProposedNewState,
+		}
+	}
+
+	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+
+	if !p.ReadResourceCalled {
+		t.Fatal("read resource should be called")
+	}
+
+	mod := s.RootModule()
+
+	newState, err := mod.Resources["aws_instance.web"].Instances[addrs.NoKey].Current.Decode(schema.ImpliedType())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !cmp.Equal(readStateVal, newState.Value, valueComparer, equateEmpty) {
+		t.Fatal(cmp.Diff(readStateVal, newState.Value, valueComparer, equateEmpty))
+	}
+
+	for _, r := range mod.Resources {
+		if r.Addr.Resource.Type == "" {
+			t.Fatalf("no type: %#v", r)
+		}
+	}
+}
+
+func TestContext2Refresh_orphanModule(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "refresh-module-orphan")
+
+	// Create a custom refresh function to track the order they were visited
+	var order []string
+	var orderLock sync.Mutex
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		orderLock.Lock()
+		defer orderLock.Unlock()
+
+		order = append(order, req.PriorState.GetAttr("id").AsString())
+		return providers.ReadResourceResponse{
+			NewState: req.PriorState,
+		}
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"i-abc123"}`),
+			Dependencies: []addrs.ConfigResource{
+				{Module: addrs.Module{"module.child"}},
+				{Module: addrs.Module{"module.child"}},
+			},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.bar").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"i-bcd23"}`),
+			Dependencies: []addrs.ConfigResource{{Module: addrs.Module{"module.grandchild"}}},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	grandchild := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey).Child("grandchild", addrs.NoKey))
+	testSetResourceInstanceCurrent(grandchild, "aws_instance.baz", `{"id":"i-cde345"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	testCheckDeadlock(t, func() {
+		_, err := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
+		if err != nil {
+			t.Fatalf("err: %s", err.Err())
+		}
+
+		// TODO: handle order properly for orphaned modules / resources
+		// expected := []string{"i-abc123", "i-bcd234", "i-cde345"}
+		// if !reflect.DeepEqual(order, expected) {
+		// 	t.Fatalf("expected: %#v, got: %#v", expected, order)
+		// }
+	})
+}
+
+func TestContext2Validate(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{},
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"num": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+		},
+	})
+
+	m := testModule(t, "validate-good")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if len(diags) != 0 {
+		t.Fatalf("unexpected error: %#v", diags.ErrWithWarnings())
+	}
+}
+
+func TestContext2Refresh_updateProviderInState(t *testing.T) {
+	m := testModule(t, "update-resource-provider")
+	p := testProvider("aws")
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	testSetResourceInstanceCurrent(root, "aws_instance.bar", `{"id":"foo"}`, `provider["registry.terraform.io/hashicorp/aws"].baz`)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	expected := strings.TrimSpace(`
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"].foo`)
+
+	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	actual := s.String()
+	if actual != expected {
+		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
+	}
+}
+
+func TestContext2Refresh_schemaUpgradeFlatmap(t *testing.T) {
+	m := testModule(t, "refresh-schema-upgrade")
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_thing": {
+				Attributes: map[string]*configschema.Attribute{
+					"name": { // imagining we renamed this from "id"
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+		},
+		ResourceTypeSchemaVersions: map[string]uint64{
+			"test_thing": 5,
+		},
+	})
+	p.UpgradeResourceStateResponse = &providers.UpgradeResourceStateResponse{
+		UpgradedState: cty.ObjectVal(map[string]cty.Value{
+			"name": cty.StringVal("foo"),
+		}),
+	}
+
+	s := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_thing",
+				Name: "bar",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				Status:        states.ObjectReady,
+				SchemaVersion: 3,
+				AttrsFlat: map[string]string{
+					"id": "foo",
+				},
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	state, diags := ctx.Refresh(m, s, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	{
+		got := p.UpgradeResourceStateRequest
+		want := providers.UpgradeResourceStateRequest{
+			TypeName: "test_thing",
+			Version:  3,
+			RawStateFlatmap: map[string]string{
+				"id": "foo",
+			},
+		}
+		if !cmp.Equal(got, want) {
+			t.Errorf("wrong upgrade request\n%s", cmp.Diff(want, got))
+		}
+	}
+
+	{
+		got := state.String()
+		want := strings.TrimSpace(`
+test_thing.bar:
+  ID = 
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  name = foo
+`)
+		if got != want {
+			t.Fatalf("wrong result state\ngot:\n%s\n\nwant:\n%s", got, want)
+		}
+	}
+}
+
+func TestContext2Refresh_schemaUpgradeJSON(t *testing.T) {
+	m := testModule(t, "refresh-schema-upgrade")
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_thing": {
+				Attributes: map[string]*configschema.Attribute{
+					"name": { // imagining we renamed this from "id"
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+		},
+		ResourceTypeSchemaVersions: map[string]uint64{
+			"test_thing": 5,
+		},
+	})
+	p.UpgradeResourceStateResponse = &providers.UpgradeResourceStateResponse{
+		UpgradedState: cty.ObjectVal(map[string]cty.Value{
+			"name": cty.StringVal("foo"),
+		}),
+	}
+
+	s := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_thing",
+				Name: "bar",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				Status:        states.ObjectReady,
+				SchemaVersion: 3,
+				AttrsJSON:     []byte(`{"id":"foo"}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	state, diags := ctx.Refresh(m, s, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	{
+		got := p.UpgradeResourceStateRequest
+		want := providers.UpgradeResourceStateRequest{
+			TypeName:     "test_thing",
+			Version:      3,
+			RawStateJSON: []byte(`{"id":"foo"}`),
+		}
+		if !cmp.Equal(got, want) {
+			t.Errorf("wrong upgrade request\n%s", cmp.Diff(want, got))
+		}
+	}
+
+	{
+		got := state.String()
+		want := strings.TrimSpace(`
+test_thing.bar:
+  ID = 
+  provider = provider["registry.terraform.io/hashicorp/test"]
+  name = foo
+`)
+		if got != want {
+			t.Fatalf("wrong result state\ngot:\n%s\n\nwant:\n%s", got, want)
+		}
+	}
+}
+
+func TestContext2Refresh_dataValidation(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+data "aws_data_source" "foo" {
+  foo = "bar"
+}
+`,
+	})
+
+	p := testProvider("aws")
+	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+		resp.PlannedState = req.ProposedNewState
+		return
+	}
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+		resp.State = req.Config
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		// Should get this error:
+		// Unsupported attribute: This object does not have an attribute named "missing"
+		t.Fatal(diags.Err())
+	}
+
+	if !p.ValidateDataResourceConfigCalled {
+		t.Fatal("ValidateDataSourceConfig not called during plan")
+	}
+}
+
+func TestContext2Refresh_dataResourceDependsOn(t *testing.T) {
+	m := testModule(t, "plan-data-depends-on")
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"id":  {Type: cty.String, Computed: true},
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		DataSources: map[string]*configschema.Block{
+			"test_data": {
+				Attributes: map[string]*configschema.Attribute{
+					"compute": {Type: cty.String, Computed: true},
+				},
+			},
+		},
+	})
+	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
+		State: cty.ObjectVal(map[string]cty.Value{
+			"compute": cty.StringVal("value"),
+		}),
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	testSetResourceInstanceCurrent(root, "test_resource.a", `{"id":"a"}`, `provider["registry.terraform.io/hashicorp/test"]`)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected errors: %s", diags.Err())
+	}
+}
+
+// verify that create_before_destroy is updated in the state during refresh
+func TestRefresh_updateLifecycle(t *testing.T) {
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "aws_instance",
+			Name: "bar",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("aws"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "aws_instance" "bar" {
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+`,
+	})
+
+	p := testProvider("aws")
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	state, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatalf("plan errors: %s", diags.Err())
+	}
+
+	r := state.ResourceInstance(mustResourceInstanceAddr("aws_instance.bar"))
+	if !r.Current.CreateBeforeDestroy {
+		t.Fatal("create_before_destroy not updated in instance state")
+	}
+}
+
+func TestContext2Refresh_dataSourceOrphan(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": ``,
+	})
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.DataResourceMode,
+			Type: "test_data_source",
+			Name: "foo",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"foo"}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	p := testProvider("test")
+	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+		resp.State = cty.NullVal(req.Config.Type())
+		return
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	_, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	if p.ReadResourceCalled {
+		t.Fatal("there are no managed resources to read")
+	}
+
+	if p.ReadDataSourceCalled {
+		t.Fatal("orphaned data source instance should not be read")
+	}
+}
+
+// Legacy providers may return invalid null values for blocks, causing noise in
+// the diff output and unexpected behavior with ignore_changes. Make sure
+// refresh fixes these up before storing the state.
+func TestContext2Refresh_reifyNullBlock(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_resource" "foo" {
+}
+`,
+	})
+
+	p := new(MockProvider)
+	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
+		// incorrectly return a null _set_block value
+		v := req.PriorState.AsValueMap()
+		v["set_block"] = cty.NullVal(v["set_block"].Type())
+		return providers.ReadResourceResponse{NewState: cty.ObjectVal(v)}
+	}
+
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{},
+		ResourceTypes: map[string]*configschema.Block{
+			"test_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"set_block": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"a": {Type: cty.String, Optional: true},
+							},
+						},
+						Nesting: configschema.NestingSet,
+					},
+				},
+			},
+		},
+	})
+	p.PlanResourceChangeFn = testDiffFn
+
+	fooAddr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_resource",
+		Name: "foo",
+	}.Instance(addrs.NoKey)
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		fooAddr,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"foo", "network_interface":[]}`),
+			Dependencies: []addrs.ConfigResource{},
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	plan, diags := ctx.Plan(m, state, &PlanOpts{Mode: plans.RefreshOnlyMode})
+	if diags.HasErrors() {
+		t.Fatalf("refresh errors: %s", diags.Err())
+	}
+
+	jsonState := plan.PriorState.ResourceInstance(fooAddr.Absolute(addrs.RootModuleInstance)).Current.AttrsJSON
+
+	// the set_block should still be an empty container, and not null
+	expected := `{"id":"foo","set_block":[]}`
+	if string(jsonState) != expected {
+		t.Fatalf("invalid state\nexpected: %s\ngot: %s\n", expected, jsonState)
+	}
+}
diff --git a/v1.5.7/internal/terraform/context_test.go b/v1.5.7/internal/terraform/context_test.go
new file mode 100644
index 0000000..085c44b
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_test.go
@@ -0,0 +1,1041 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"path/filepath"
+	"sort"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/hashicorp/go-version"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/planfile"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/states/statefile"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	tfversion "github.com/hashicorp/terraform/version"
+	"github.com/zclconf/go-cty/cty"
+)
+
+var (
+	equateEmpty   = cmpopts.EquateEmpty()
+	typeComparer  = cmp.Comparer(cty.Type.Equals)
+	valueComparer = cmp.Comparer(cty.Value.RawEquals)
+	valueTrans    = cmp.Transformer("hcl2shim", hcl2shim.ConfigValueFromHCL2)
+)
+
+func TestNewContextRequiredVersion(t *testing.T) {
+	cases := []struct {
+		Name    string
+		Version string
+		Value   string
+		Err     bool
+	}{
+		{
+			"no requirement",
+			"0.1.0",
+			"",
+			false,
+		},
+
+		{
+			"doesn't match",
+			"0.1.0",
+			"> 0.6.0",
+			true,
+		},
+
+		{
+			"matches",
+			"0.7.0",
+			"> 0.6.0",
+			false,
+		},
+
+		{
+			"prerelease doesn't match with inequality",
+			"0.8.0",
+			"> 0.7.0-beta",
+			true,
+		},
+
+		{
+			"prerelease doesn't match with equality",
+			"0.7.0",
+			"0.7.0-beta",
+			true,
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			// Reset the version for the tests
+			old := tfversion.SemVer
+			tfversion.SemVer = version.Must(version.NewVersion(tc.Version))
+			defer func() { tfversion.SemVer = old }()
+
+			mod := testModule(t, "context-required-version")
+			if tc.Value != "" {
+				constraint, err := version.NewConstraint(tc.Value)
+				if err != nil {
+					t.Fatalf("can't parse %q as version constraint", tc.Value)
+				}
+				mod.Module.CoreVersionConstraints = append(mod.Module.CoreVersionConstraints, configs.VersionConstraint{
+					Required: constraint,
+				})
+			}
+			c, diags := NewContext(&ContextOpts{})
+			if diags.HasErrors() {
+				t.Fatalf("unexpected NewContext errors: %s", diags.Err())
+			}
+
+			diags = c.Validate(mod)
+			if diags.HasErrors() != tc.Err {
+				t.Fatalf("err: %s", diags.Err())
+			}
+		})
+	}
+}
+
+func TestNewContextRequiredVersion_child(t *testing.T) {
+	mod := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "child" {
+  source = "./child"
+}
+`,
+		"child/main.tf": `
+terraform {}
+`,
+	})
+
+	cases := map[string]struct {
+		Version    string
+		Constraint string
+		Err        bool
+	}{
+		"matches": {
+			"0.5.0",
+			">= 0.5.0",
+			false,
+		},
+		"doesn't match": {
+			"0.4.0",
+			">= 0.5.0",
+			true,
+		},
+	}
+
+	for name, tc := range cases {
+		t.Run(name, func(t *testing.T) {
+			// Reset the version for the tests
+			old := tfversion.SemVer
+			tfversion.SemVer = version.Must(version.NewVersion(tc.Version))
+			defer func() { tfversion.SemVer = old }()
+
+			if tc.Constraint != "" {
+				constraint, err := version.NewConstraint(tc.Constraint)
+				if err != nil {
+					t.Fatalf("can't parse %q as version constraint", tc.Constraint)
+				}
+				child := mod.Children["child"]
+				child.Module.CoreVersionConstraints = append(child.Module.CoreVersionConstraints, configs.VersionConstraint{
+					Required: constraint,
+				})
+			}
+			c, diags := NewContext(&ContextOpts{})
+			if diags.HasErrors() {
+				t.Fatalf("unexpected NewContext errors: %s", diags.Err())
+			}
+
+			diags = c.Validate(mod)
+			if diags.HasErrors() != tc.Err {
+				t.Fatalf("err: %s", diags.Err())
+			}
+		})
+	}
+}
+
+func TestContext_missingPlugins(t *testing.T) {
+	ctx, diags := NewContext(&ContextOpts{})
+	assertNoDiagnostics(t, diags)
+
+	configSrc := `
+terraform {
+	required_providers {
+		explicit = {
+			source = "example.com/foo/beep"
+		}
+		builtin = {
+			source = "terraform.io/builtin/nonexist"
+		}
+	}
+}
+
+resource "implicit_thing" "a" {
+	provisioner "nonexist" {
+	}
+}
+
+resource "implicit_thing" "b" {
+	provider = implicit2
+}
+`
+
+	cfg := testModuleInline(t, map[string]string{
+		"main.tf": configSrc,
+	})
+
+	// Validate and Plan are the two entry points where we explicitly verify
+	// the available plugins match what the configuration needs. For other
+	// operations we typically fail more deeply in Terraform Core, with
+	// potentially-less-helpful error messages, because getting there would
+	// require doing some pretty weird things that aren't common enough to
+	// be worth the complexity to check for them.
+
+	validateDiags := ctx.Validate(cfg)
+	_, planDiags := ctx.Plan(cfg, nil, DefaultPlanOpts)
+
+	tests := map[string]tfdiags.Diagnostics{
+		"validate": validateDiags,
+		"plan":     planDiags,
+	}
+
+	for testName, gotDiags := range tests {
+		t.Run(testName, func(t *testing.T) {
+			var wantDiags tfdiags.Diagnostics
+			wantDiags = wantDiags.Append(
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Missing required provider",
+					"This configuration requires built-in provider terraform.io/builtin/nonexist, but that provider isn't available in this Terraform version.",
+				),
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Missing required provider",
+					"This configuration requires provider example.com/foo/beep, but that provider isn't available. You may be able to install it automatically by running:\n  terraform init",
+				),
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Missing required provider",
+					"This configuration requires provider registry.terraform.io/hashicorp/implicit, but that provider isn't available. You may be able to install it automatically by running:\n  terraform init",
+				),
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Missing required provider",
+					"This configuration requires provider registry.terraform.io/hashicorp/implicit2, but that provider isn't available. You may be able to install it automatically by running:\n  terraform init",
+				),
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Missing required provisioner plugin",
+					`This configuration requires provisioner plugin "nonexist", which isn't available. If you're intending to use an external provisioner plugin, you must install it manually into one of the plugin search directories before running Terraform.`,
+				),
+			)
+			assertDiagnosticsMatch(t, gotDiags, wantDiags)
+		})
+	}
+}
+
+func testContext2(t *testing.T, opts *ContextOpts) *Context {
+	t.Helper()
+
+	ctx, diags := NewContext(opts)
+	if diags.HasErrors() {
+		t.Fatalf("failed to create test context\n\n%s\n", diags.Err())
+	}
+
+	return ctx
+}
+
+func testApplyFn(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+	resp.NewState = req.PlannedState
+	if req.PlannedState.IsNull() {
+		resp.NewState = cty.NullVal(req.PriorState.Type())
+		return
+	}
+
+	planned := req.PlannedState.AsValueMap()
+	if planned == nil {
+		planned = map[string]cty.Value{}
+	}
+
+	id, ok := planned["id"]
+	if !ok || id.IsNull() || !id.IsKnown() {
+		planned["id"] = cty.StringVal("foo")
+	}
+
+	// our default schema has a computed "type" attr
+	if ty, ok := planned["type"]; ok && !ty.IsNull() {
+		planned["type"] = cty.StringVal(req.TypeName)
+	}
+
+	if cmp, ok := planned["compute"]; ok && !cmp.IsNull() {
+		computed := cmp.AsString()
+		if val, ok := planned[computed]; ok && !val.IsKnown() {
+			planned[computed] = cty.StringVal("computed_value")
+		}
+	}
+
+	for k, v := range planned {
+		if k == "unknown" {
+			// "unknown" should cause an error
+			continue
+		}
+
+		if !v.IsKnown() {
+			switch k {
+			case "type":
+				planned[k] = cty.StringVal(req.TypeName)
+			default:
+				planned[k] = cty.NullVal(v.Type())
+			}
+		}
+	}
+
+	resp.NewState = cty.ObjectVal(planned)
+	return
+}
+
+func testDiffFn(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+	var planned map[string]cty.Value
+
+	// this is a destroy plan
+	if req.ProposedNewState.IsNull() {
+		resp.PlannedState = req.ProposedNewState
+		resp.PlannedPrivate = req.PriorPrivate
+		return resp
+	}
+
+	if !req.ProposedNewState.IsNull() {
+		planned = req.ProposedNewState.AsValueMap()
+	}
+	if planned == nil {
+		planned = map[string]cty.Value{}
+	}
+
+	// id is always computed for the tests
+	if id, ok := planned["id"]; ok && id.IsNull() {
+		planned["id"] = cty.UnknownVal(cty.String)
+	}
+
+	// the old tests have require_new replace on every plan
+	if _, ok := planned["require_new"]; ok {
+		resp.RequiresReplace = append(resp.RequiresReplace, cty.Path{cty.GetAttrStep{Name: "require_new"}})
+	}
+
+	for k := range planned {
+		requiresNewKey := "__" + k + "_requires_new"
+		_, ok := planned[requiresNewKey]
+		if ok {
+			resp.RequiresReplace = append(resp.RequiresReplace, cty.Path{cty.GetAttrStep{Name: requiresNewKey}})
+		}
+	}
+
+	if v, ok := planned["compute"]; ok && !v.IsNull() {
+		k := v.AsString()
+		unknown := cty.UnknownVal(cty.String)
+		if strings.HasSuffix(k, ".#") {
+			k = k[:len(k)-2]
+			unknown = cty.UnknownVal(cty.List(cty.String))
+		}
+		planned[k] = unknown
+	}
+
+	if t, ok := planned["type"]; ok && t.IsNull() {
+		planned["type"] = cty.UnknownVal(cty.String)
+	}
+
+	resp.PlannedState = cty.ObjectVal(planned)
+	return
+}
+
+func testProvider(prefix string) *MockProvider {
+	p := new(MockProvider)
+	p.GetProviderSchemaResponse = testProviderSchema(prefix)
+
+	return p
+}
+
+func testProvisioner() *MockProvisioner {
+	p := new(MockProvisioner)
+	p.GetSchemaResponse = provisioners.GetSchemaResponse{
+		Provisioner: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"command": {
+					Type:     cty.String,
+					Optional: true,
+				},
+				"order": {
+					Type:     cty.String,
+					Optional: true,
+				},
+				"when": {
+					Type:     cty.String,
+					Optional: true,
+				},
+			},
+		},
+	}
+	return p
+}
+
+func checkStateString(t *testing.T, state *states.State, expected string) {
+	t.Helper()
+	actual := strings.TrimSpace(state.String())
+	expected = strings.TrimSpace(expected)
+
+	if actual != expected {
+		t.Fatalf("incorrect state\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+// Test helper that gives a function 3 seconds to finish, assumes deadlock and
+// fails test if it does not.
+func testCheckDeadlock(t *testing.T, f func()) {
+	t.Helper()
+	timeout := make(chan bool, 1)
+	done := make(chan bool, 1)
+	go func() {
+		time.Sleep(3 * time.Second)
+		timeout <- true
+	}()
+	go func(f func(), done chan bool) {
+		defer func() { done <- true }()
+		f()
+	}(f, done)
+	select {
+	case <-timeout:
+		t.Fatalf("timed out! probably deadlock")
+	case <-done:
+		// ok
+	}
+}
+
+func testProviderSchema(name string) *providers.GetProviderSchemaResponse {
+	return getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		Provider: &configschema.Block{
+			Attributes: map[string]*configschema.Attribute{
+				"region": {
+					Type:     cty.String,
+					Optional: true,
+				},
+				"foo": {
+					Type:     cty.String,
+					Optional: true,
+				},
+				"value": {
+					Type:     cty.String,
+					Optional: true,
+				},
+				"root": {
+					Type:     cty.Number,
+					Optional: true,
+				},
+			},
+		},
+		ResourceTypes: map[string]*configschema.Block{
+			name + "_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"ami": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"dep": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"num": {
+						Type:     cty.Number,
+						Optional: true,
+					},
+					"require_new": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"var": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+					"bar": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"compute": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: false,
+					},
+					"compute_value": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+					"value": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+					"output": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"write": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"instance": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"vpc_id": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"type": {
+						Type:     cty.String,
+						Computed: true,
+					},
+
+					// Generated by testDiffFn if compute = "unknown" is set in the test config
+					"unknown": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+			name + "_eip": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"instance": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+			name + "_resource": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"value": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"sensitive_value": {
+						Type:      cty.String,
+						Sensitive: true,
+						Optional:  true,
+					},
+					"random": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"nesting_single": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"value":           {Type: cty.String, Optional: true},
+								"sensitive_value": {Type: cty.String, Optional: true, Sensitive: true},
+							},
+						},
+						Nesting: configschema.NestingSingle,
+					},
+				},
+			},
+			name + "_ami_list": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+					"ids": {
+						Type:     cty.List(cty.String),
+						Optional: true,
+						Computed: true,
+					},
+				},
+			},
+			name + "_remote_state": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"output": {
+						Type:     cty.Map(cty.String),
+						Computed: true,
+					},
+				},
+			},
+			name + "_file": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"template": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"rendered": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"__template_requires_new": {
+						Type:     cty.String,
+						Optional: true,
+					},
+				},
+			},
+		},
+		DataSources: map[string]*configschema.Block{
+			name + "_data_source": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+						Computed: true,
+					},
+				},
+			},
+			name + "_remote_state": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"foo": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"output": {
+						Type:     cty.Map(cty.String),
+						Optional: true,
+					},
+				},
+			},
+			name + "_file": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"template": {
+						Type:     cty.String,
+						Optional: true,
+					},
+					"rendered": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+		},
+	})
+}
+
+// contextOptsForPlanViaFile is a helper that creates a temporary plan file,
+// then reads it back in again and produces a ContextOpts object containing the
+// planned changes, prior state and config from the plan file.
+//
+// This is intended for testing the separated plan/apply workflow in a more
+// convenient way than spelling out all of these steps every time. Normally
+// only the command and backend packages need to deal with such things, but
+// our context tests try to exercise lots of stuff at once and so having them
+// round-trip things through on-disk files is often an important part of
+// fully representing an old bug in a regression test.
+func contextOptsForPlanViaFile(t *testing.T, configSnap *configload.Snapshot, plan *plans.Plan) (*ContextOpts, *configs.Config, *plans.Plan, error) {
+	dir := t.TempDir()
+
+	// We'll just create a dummy statefile.File here because we're not going
+	// to run through any of the codepaths that care about Lineage/Serial/etc
+	// here anyway.
+	stateFile := &statefile.File{
+		State: plan.PriorState,
+	}
+	prevStateFile := &statefile.File{
+		State: plan.PrevRunState,
+	}
+
+	// To make life a little easier for test authors, we'll populate a simple
+	// backend configuration if they didn't set one, since the backend is
+	// usually dealt with in a calling package and so tests in this package
+	// don't really care about it.
+	if plan.Backend.Config == nil {
+		cfg, err := plans.NewDynamicValue(cty.EmptyObjectVal, cty.EmptyObject)
+		if err != nil {
+			panic(fmt.Sprintf("NewDynamicValue failed: %s", err)) // shouldn't happen because we control the inputs
+		}
+		plan.Backend.Type = "local"
+		plan.Backend.Config = cfg
+		plan.Backend.Workspace = "default"
+	}
+
+	filename := filepath.Join(dir, "tfplan")
+	err := planfile.Create(filename, planfile.CreateArgs{
+		ConfigSnapshot:       configSnap,
+		PreviousRunStateFile: prevStateFile,
+		StateFile:            stateFile,
+		Plan:                 plan,
+	})
+	if err != nil {
+		return nil, nil, nil, err
+	}
+
+	pr, err := planfile.Open(filename)
+	if err != nil {
+		return nil, nil, nil, err
+	}
+
+	config, diags := pr.ReadConfig()
+	if diags.HasErrors() {
+		return nil, nil, nil, diags.Err()
+	}
+
+	plan, err = pr.ReadPlan()
+	if err != nil {
+		return nil, nil, nil, err
+	}
+
+	// Note: This has grown rather silly over the course of ongoing refactoring,
+	// because ContextOpts is no longer actually responsible for carrying
+	// any information from a plan file and instead all of the information
+	// lives inside the config and plan objects. We continue to return a
+	// silly empty ContextOpts here just to keep all of the calling tests
+	// working.
+	return &ContextOpts{}, config, plan, nil
+}
+
+// legacyPlanComparisonString produces a string representation of the changes
+// from a plan and a given state togther, as was formerly produced by the
+// String method of terraform.Plan.
+//
+// This is here only for compatibility with existing tests that predate our
+// new plan and state types, and should not be used in new tests. Instead, use
+// a library like "cmp" to do a deep equality check and diff on the two
+// data structures.
+func legacyPlanComparisonString(state *states.State, changes *plans.Changes) string {
+	return fmt.Sprintf(
+		"DIFF:\n\n%s\n\nSTATE:\n\n%s",
+		legacyDiffComparisonString(changes),
+		state.String(),
+	)
+}
+
+// legacyDiffComparisonString produces a string representation of the changes
+// from a planned changes object, as was formerly produced by the String method
+// of terraform.Diff.
+//
+// This is here only for compatibility with existing tests that predate our
+// new plan types, and should not be used in new tests. Instead, use a library
+// like "cmp" to do a deep equality check and diff on the two data structures.
+func legacyDiffComparisonString(changes *plans.Changes) string {
+	// The old string representation of a plan was grouped by module, but
+	// our new plan structure is not grouped in that way and so we'll need
+	// to preprocess it in order to produce that grouping.
+	type ResourceChanges struct {
+		Current *plans.ResourceInstanceChangeSrc
+		Deposed map[states.DeposedKey]*plans.ResourceInstanceChangeSrc
+	}
+	byModule := map[string]map[string]*ResourceChanges{}
+	resourceKeys := map[string][]string{}
+	var moduleKeys []string
+	for _, rc := range changes.Resources {
+		if rc.Action == plans.NoOp {
+			// We won't mention no-op changes here at all, since the old plan
+			// model we are emulating here didn't have such a concept.
+			continue
+		}
+		moduleKey := rc.Addr.Module.String()
+		if _, exists := byModule[moduleKey]; !exists {
+			moduleKeys = append(moduleKeys, moduleKey)
+			byModule[moduleKey] = make(map[string]*ResourceChanges)
+		}
+		resourceKey := rc.Addr.Resource.String()
+		if _, exists := byModule[moduleKey][resourceKey]; !exists {
+			resourceKeys[moduleKey] = append(resourceKeys[moduleKey], resourceKey)
+			byModule[moduleKey][resourceKey] = &ResourceChanges{
+				Deposed: make(map[states.DeposedKey]*plans.ResourceInstanceChangeSrc),
+			}
+		}
+
+		if rc.DeposedKey == states.NotDeposed {
+			byModule[moduleKey][resourceKey].Current = rc
+		} else {
+			byModule[moduleKey][resourceKey].Deposed[rc.DeposedKey] = rc
+		}
+	}
+	sort.Strings(moduleKeys)
+	for _, ks := range resourceKeys {
+		sort.Strings(ks)
+	}
+
+	var buf bytes.Buffer
+
+	for _, moduleKey := range moduleKeys {
+		rcs := byModule[moduleKey]
+		var mBuf bytes.Buffer
+
+		for _, resourceKey := range resourceKeys[moduleKey] {
+			rc := rcs[resourceKey]
+
+			crud := "UPDATE"
+			if rc.Current != nil {
+				switch rc.Current.Action {
+				case plans.DeleteThenCreate:
+					crud = "DESTROY/CREATE"
+				case plans.CreateThenDelete:
+					crud = "CREATE/DESTROY"
+				case plans.Delete:
+					crud = "DESTROY"
+				case plans.Create:
+					crud = "CREATE"
+				}
+			} else {
+				// We must be working on a deposed object then, in which
+				// case destroying is the only possible action.
+				crud = "DESTROY"
+			}
+
+			extra := ""
+			if rc.Current == nil && len(rc.Deposed) > 0 {
+				extra = " (deposed only)"
+			}
+
+			fmt.Fprintf(
+				&mBuf, "%s: %s%s\n",
+				crud, resourceKey, extra,
+			)
+
+			attrNames := map[string]bool{}
+			var oldAttrs map[string]string
+			var newAttrs map[string]string
+			if rc.Current != nil {
+				if before := rc.Current.Before; before != nil {
+					ty, err := before.ImpliedType()
+					if err == nil {
+						val, err := before.Decode(ty)
+						if err == nil {
+							oldAttrs = hcl2shim.FlatmapValueFromHCL2(val)
+							for k := range oldAttrs {
+								attrNames[k] = true
+							}
+						}
+					}
+				}
+				if after := rc.Current.After; after != nil {
+					ty, err := after.ImpliedType()
+					if err == nil {
+						val, err := after.Decode(ty)
+						if err == nil {
+							newAttrs = hcl2shim.FlatmapValueFromHCL2(val)
+							for k := range newAttrs {
+								attrNames[k] = true
+							}
+						}
+					}
+				}
+			}
+			if oldAttrs == nil {
+				oldAttrs = make(map[string]string)
+			}
+			if newAttrs == nil {
+				newAttrs = make(map[string]string)
+			}
+
+			attrNamesOrder := make([]string, 0, len(attrNames))
+			keyLen := 0
+			for n := range attrNames {
+				attrNamesOrder = append(attrNamesOrder, n)
+				if len(n) > keyLen {
+					keyLen = len(n)
+				}
+			}
+			sort.Strings(attrNamesOrder)
+
+			for _, attrK := range attrNamesOrder {
+				v := newAttrs[attrK]
+				u := oldAttrs[attrK]
+
+				if v == hcl2shim.UnknownVariableValue {
+					v = "<computed>"
+				}
+				// NOTE: we don't support <sensitive> here because we would
+				// need schema to do that. Excluding sensitive values
+				// is now done at the UI layer, and so should not be tested
+				// at the core layer.
+
+				updateMsg := ""
+				// TODO: Mark " (forces new resource)" in updateMsg when appropriate.
+
+				fmt.Fprintf(
+					&mBuf, "  %s:%s %#v => %#v%s\n",
+					attrK,
+					strings.Repeat(" ", keyLen-len(attrK)),
+					u, v,
+					updateMsg,
+				)
+			}
+		}
+
+		if moduleKey == "" { // root module
+			buf.Write(mBuf.Bytes())
+			buf.WriteByte('\n')
+			continue
+		}
+
+		fmt.Fprintf(&buf, "%s:\n", moduleKey)
+		s := bufio.NewScanner(&mBuf)
+		for s.Scan() {
+			buf.WriteString(fmt.Sprintf("  %s\n", s.Text()))
+		}
+	}
+
+	return buf.String()
+}
+
+// assertNoDiagnostics fails the test in progress (using t.Fatal) if the given
+// diagnostics is non-empty.
+func assertNoDiagnostics(t *testing.T, diags tfdiags.Diagnostics) {
+	t.Helper()
+	if len(diags) == 0 {
+		return
+	}
+	logDiagnostics(t, diags)
+	t.FailNow()
+}
+
+// assertNoDiagnostics fails the test in progress (using t.Fatal) if the given
+// diagnostics has any errors.
+func assertNoErrors(t *testing.T, diags tfdiags.Diagnostics) {
+	t.Helper()
+	if !diags.HasErrors() {
+		return
+	}
+	logDiagnostics(t, diags)
+	t.FailNow()
+}
+
+// assertDiagnosticsMatch fails the test in progress (using t.Fatal) if the
+// two sets of diagnostics don't match after being normalized using the
+// "ForRPC" processing step, which eliminates the specific type information
+// and HCL expression information of each diagnostic.
+//
+// assertDiagnosticsMatch sorts the two sets of diagnostics in the usual way
+// before comparing them, though diagnostics only have a partial order so that
+// will not totally normalize the ordering of all diagnostics sets.
+func assertDiagnosticsMatch(t *testing.T, got, want tfdiags.Diagnostics) {
+	got = got.ForRPC()
+	want = want.ForRPC()
+	got.Sort()
+	want.Sort()
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Fatalf("wrong diagnostics\n%s", diff)
+	}
+}
+
+// logDiagnostics is a test helper that logs the given diagnostics to to the
+// given testing.T using t.Log, in a way that is hopefully useful in debugging
+// a test. It does not generate any errors or fail the test. See
+// assertNoDiagnostics and assertNoErrors for more specific helpers that can
+// also fail the test.
+func logDiagnostics(t *testing.T, diags tfdiags.Diagnostics) {
+	t.Helper()
+	for _, diag := range diags {
+		desc := diag.Description()
+		rng := diag.Source()
+
+		var severity string
+		switch diag.Severity() {
+		case tfdiags.Error:
+			severity = "ERROR"
+		case tfdiags.Warning:
+			severity = "WARN"
+		default:
+			severity = "???" // should never happen
+		}
+
+		if subj := rng.Subject; subj != nil {
+			if desc.Detail == "" {
+				t.Logf("[%s@%s] %s", severity, subj.StartString(), desc.Summary)
+			} else {
+				t.Logf("[%s@%s] %s: %s", severity, subj.StartString(), desc.Summary, desc.Detail)
+			}
+		} else {
+			if desc.Detail == "" {
+				t.Logf("[%s] %s", severity, desc.Summary)
+			} else {
+				t.Logf("[%s] %s: %s", severity, desc.Summary, desc.Detail)
+			}
+		}
+	}
+}
+
+const testContextRefreshModuleStr = `
+aws_instance.web: (tainted)
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+
+module.child:
+  aws_instance.web:
+    ID = new
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+`
+
+const testContextRefreshOutputStr = `
+aws_instance.web:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+
+Outputs:
+
+foo = bar
+`
+
+const testContextRefreshOutputPartialStr = `
+<no state>
+`
+
+const testContextRefreshTaintedStr = `
+aws_instance.web: (tainted)
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+`
diff --git a/v1.5.7/internal/terraform/context_validate.go b/v1.5.7/internal/terraform/context_validate.go
new file mode 100644
index 0000000..0dc1350
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_validate.go
@@ -0,0 +1,83 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// Validate performs semantic validation of a configuration, and returns
+// any warnings or errors.
+//
+// Syntax and structural checks are performed by the configuration loader,
+// and so are not repeated here.
+//
+// Validate considers only the configuration and so it won't catch any
+// errors caused by current values in the state, or other external information
+// such as root module input variables. However, the Plan function includes
+// all of the same checks as Validate, in addition to the other work it does
+// to consider the previous run state and the planning options.
+func (c *Context) Validate(config *configs.Config) tfdiags.Diagnostics {
+	defer c.acquireRun("validate")()
+
+	var diags tfdiags.Diagnostics
+
+	moreDiags := c.checkConfigDependencies(config)
+	diags = diags.Append(moreDiags)
+	// If required dependencies are not available then we'll bail early since
+	// otherwise we're likely to just see a bunch of other errors related to
+	// incompatibilities, which could be overwhelming for the user.
+	if diags.HasErrors() {
+		return diags
+	}
+
+	log.Printf("[DEBUG] Building and walking validate graph")
+
+	// Validate is to check if the given module is valid regardless of
+	// input values, current state, etc. Therefore we populate all of the
+	// input values with unknown values of the expected type, allowing us
+	// to perform a type check without assuming any particular values.
+	varValues := make(InputValues)
+	for name, variable := range config.Module.Variables {
+		ty := variable.Type
+		if ty == cty.NilType {
+			// Can't predict the type at all, so we'll just mark it as
+			// cty.DynamicVal (unknown value of cty.DynamicPseudoType).
+			ty = cty.DynamicPseudoType
+		}
+		varValues[name] = &InputValue{
+			Value:      cty.UnknownVal(ty),
+			SourceType: ValueFromUnknown,
+		}
+	}
+
+	graph, moreDiags := (&PlanGraphBuilder{
+		Config:             config,
+		Plugins:            c.plugins,
+		State:              states.NewState(),
+		RootVariableValues: varValues,
+		Operation:          walkValidate,
+	}).Build(addrs.RootModuleInstance)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		return diags
+	}
+
+	walker, walkDiags := c.walk(graph, walkValidate, &graphWalkOpts{
+		Config: config,
+	})
+	diags = diags.Append(walker.NonFatalDiagnostics)
+	diags = diags.Append(walkDiags)
+	if walkDiags.HasErrors() {
+		return diags
+	}
+
+	return diags
+}
diff --git a/v1.5.7/internal/terraform/context_validate_test.go b/v1.5.7/internal/terraform/context_validate_test.go
new file mode 100644
index 0000000..04dd41f
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_validate_test.go
@@ -0,0 +1,2487 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"errors"
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestContext2Validate_badCount(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{},
+			},
+		},
+	})
+
+	m := testModule(t, "validate-bad-count")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want error")
+	}
+}
+
+func TestContext2Validate_badResource_reference(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{},
+			},
+		},
+	})
+
+	m := testModule(t, "validate-bad-resource-count")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want error")
+	}
+}
+
+func TestContext2Validate_badVar(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+					"num": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+
+	m := testModule(t, "validate-bad-var")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want error")
+	}
+}
+
+func TestContext2Validate_varNoDefaultExplicitType(t *testing.T) {
+	m := testModule(t, "validate-var-no-default-explicit-type")
+	c, diags := NewContext(&ContextOpts{})
+	if diags.HasErrors() {
+		t.Fatalf("unexpected NewContext errors: %s", diags.Err())
+	}
+
+	// NOTE: This test has grown idiosyncratic because originally Terraform
+	// would (optionally) check variables during validation, and then in
+	// Terraform v0.12 we switched to checking variables during NewContext,
+	// and now most recently we've switched to checking variables only during
+	// planning because root variables are a plan option. Therefore this has
+	// grown into a plan test rather than a validate test, but it lives on
+	// here in order to make it easier to navigate through that history in
+	// version control.
+	_, diags = c.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		// Error should be: The input variable "maybe_a_map" has not been assigned a value.
+		t.Fatalf("succeeded; want error")
+	}
+}
+
+func TestContext2Validate_computedVar(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"value": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{},
+				},
+			},
+		},
+	}
+	pt := testProvider("test")
+	pt.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id":    {Type: cty.String, Computed: true},
+						"value": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	m := testModule(t, "validate-computed-var")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"):  testProviderFuncFixed(p),
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(pt),
+		},
+	})
+
+	p.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
+		val := req.Config.GetAttr("value")
+		if val.IsKnown() {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value isn't computed"))
+		}
+
+		return
+	}
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+	if p.ConfigureProviderCalled {
+		t.Fatal("Configure should not be called for provider")
+	}
+}
+
+func TestContext2Validate_computedInFunction(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"attr": {Type: cty.Number, Optional: true},
+					},
+				},
+			},
+		},
+		DataSources: map[string]providers.Schema{
+			"aws_data_source": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"optional_attr": {Type: cty.String, Optional: true},
+						"computed":      {Type: cty.String, Computed: true},
+					},
+				},
+			},
+		},
+	}
+
+	m := testModule(t, "validate-computed-in-function")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+// Test that validate allows through computed counts. We do this and allow
+// them to fail during "plan" since we can't know if the computed values
+// can be realized during a plan.
+func TestContext2Validate_countComputed(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{},
+				},
+			},
+		},
+		DataSources: map[string]providers.Schema{
+			"aws_data_source": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"compute": {Type: cty.String, Optional: true},
+						"value":   {Type: cty.String, Computed: true},
+					},
+				},
+			},
+		},
+	}
+
+	m := testModule(t, "validate-count-computed")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+func TestContext2Validate_countNegative(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{},
+				},
+			},
+		},
+	}
+	m := testModule(t, "validate-count-negative")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want error")
+	}
+}
+
+func TestContext2Validate_countVariable(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	m := testModule(t, "apply-count-variable")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+func TestContext2Validate_countVariableNoDefault(t *testing.T) {
+	p := testProvider("aws")
+	m := testModule(t, "validate-count-variable")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	c, diags := NewContext(&ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+	assertNoDiagnostics(t, diags)
+
+	_, diags = c.Plan(m, nil, &PlanOpts{})
+	if !diags.HasErrors() {
+		// Error should be: The input variable "foo" has not been assigned a value.
+		t.Fatalf("succeeded; want error")
+	}
+}
+
+func TestContext2Validate_moduleBadOutput(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	m := testModule(t, "validate-bad-module-output")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want error")
+	}
+}
+
+func TestContext2Validate_moduleGood(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	m := testModule(t, "validate-good-module")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+func TestContext2Validate_moduleBadResource(t *testing.T) {
+	m := testModule(t, "validate-module-bad-rc")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{},
+				},
+			},
+		},
+	}
+
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ValidateResourceConfigResponse = &providers.ValidateResourceConfigResponse{
+		Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")),
+	}
+
+	diags := c.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want error")
+	}
+}
+
+func TestContext2Validate_moduleDepsShouldNotCycle(t *testing.T) {
+	m := testModule(t, "validate-module-deps-cycle")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+func TestContext2Validate_moduleProviderVar(t *testing.T) {
+	m := testModule(t, "validate-module-pc-vars")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
+		if req.Config.GetAttr("foo").IsNull() {
+			resp.Diagnostics = resp.Diagnostics.Append(errors.New("foo is null"))
+		}
+		return
+	}
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+func TestContext2Validate_moduleProviderInheritUnused(t *testing.T) {
+	m := testModule(t, "validate-module-pc-inherit-unused")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
+		if req.Config.GetAttr("foo").IsNull() {
+			resp.Diagnostics = resp.Diagnostics.Append(errors.New("foo is null"))
+		}
+		return
+	}
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+func TestContext2Validate_orphans(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+						"num": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	m := testModule(t, "validate-good")
+
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+		var diags tfdiags.Diagnostics
+		if req.Config.GetAttr("foo").IsNull() {
+			diags = diags.Append(errors.New("foo is not set"))
+		}
+		return providers.ValidateResourceConfigResponse{
+			Diagnostics: diags,
+		}
+	}
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+func TestContext2Validate_providerConfig_bad(t *testing.T) {
+	m := testModule(t, "validate-bad-pc")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{},
+				},
+			},
+		},
+	}
+
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ValidateProviderConfigResponse = &providers.ValidateProviderConfigResponse{
+		Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")),
+	}
+
+	diags := c.Validate(m)
+	if len(diags) != 1 {
+		t.Fatalf("wrong number of diagnostics %d; want %d", len(diags), 1)
+	}
+	if !strings.Contains(diags.Err().Error(), "bad") {
+		t.Fatalf("bad: %s", diags.Err().Error())
+	}
+}
+
+func TestContext2Validate_providerConfig_skippedEmpty(t *testing.T) {
+	m := testModule(t, "validate-skipped-pc-empty")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{},
+				},
+			},
+		},
+	}
+
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ValidateProviderConfigResponse = &providers.ValidateProviderConfigResponse{
+		Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("should not be called")),
+	}
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+func TestContext2Validate_providerConfig_good(t *testing.T) {
+	m := testModule(t, "validate-bad-pc")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{},
+				},
+			},
+		},
+	}
+
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+// In this test there is a mismatch between the provider's fqn (hashicorp/test)
+// and it's local name set in required_providers (arbitrary).
+func TestContext2Validate_requiredProviderConfig(t *testing.T) {
+	m := testModule(t, "validate-required-provider-config")
+	p := testProvider("aws")
+
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"required_attribute": {Type: cty.String, Required: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{},
+				},
+			},
+		},
+	}
+
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+func TestContext2Validate_provisionerConfig_bad(t *testing.T) {
+	m := testModule(t, "validate-bad-prov-conf")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	pr := simpleMockProvisioner()
+
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	p.ValidateProviderConfigResponse = &providers.ValidateProviderConfigResponse{
+		Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")),
+	}
+
+	diags := c.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want error")
+	}
+}
+
+func TestContext2Validate_badResourceConnection(t *testing.T) {
+	m := testModule(t, "validate-bad-resource-connection")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	pr := simpleMockProvisioner()
+
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	diags := c.Validate(m)
+	t.Log(diags.Err())
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want error")
+	}
+}
+
+func TestContext2Validate_badProvisionerConnection(t *testing.T) {
+	m := testModule(t, "validate-bad-prov-connection")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	pr := simpleMockProvisioner()
+
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	diags := c.Validate(m)
+	t.Log(diags.Err())
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want error")
+	}
+}
+
+func TestContext2Validate_provisionerConfig_good(t *testing.T) {
+	m := testModule(t, "validate-bad-prov-conf")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		Provider: providers.Schema{
+			Block: &configschema.Block{
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	pr := simpleMockProvisioner()
+	pr.ValidateProvisionerConfigFn = func(req provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse {
+		var diags tfdiags.Diagnostics
+		if req.Config.GetAttr("test_string").IsNull() {
+			diags = diags.Append(errors.New("test_string is not set"))
+		}
+		return provisioners.ValidateProvisionerConfigResponse{
+			Diagnostics: diags,
+		}
+	}
+
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+func TestContext2Validate_requiredVar(t *testing.T) {
+	m := testModule(t, "validate-required-var")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"ami": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	c, diags := NewContext(&ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+	assertNoDiagnostics(t, diags)
+
+	// NOTE: This test has grown idiosyncratic because originally Terraform
+	// would (optionally) check variables during validation, and then in
+	// Terraform v0.12 we switched to checking variables during NewContext,
+	// and now most recently we've switched to checking variables only during
+	// planning because root variables are a plan option. Therefore this has
+	// grown into a plan test rather than a validate test, but it lives on
+	// here in order to make it easier to navigate through that history in
+	// version control.
+	_, diags = c.Plan(m, states.NewState(), DefaultPlanOpts)
+	if !diags.HasErrors() {
+		// Error should be: The input variable "foo" has not been assigned a value.
+		t.Fatalf("succeeded; want error")
+	}
+}
+
+func TestContext2Validate_resourceConfig_bad(t *testing.T) {
+	m := testModule(t, "validate-bad-rc")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ValidateResourceConfigResponse = &providers.ValidateResourceConfigResponse{
+		Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")),
+	}
+
+	diags := c.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want error")
+	}
+}
+
+func TestContext2Validate_resourceConfig_good(t *testing.T) {
+	m := testModule(t, "validate-bad-rc")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+func TestContext2Validate_tainted(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+						"num": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	m := testModule(t, "validate-good")
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+		var diags tfdiags.Diagnostics
+		if req.Config.GetAttr("foo").IsNull() {
+			diags = diags.Append(errors.New("foo is not set"))
+		}
+		return providers.ValidateResourceConfigResponse{
+			Diagnostics: diags,
+		}
+	}
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+func TestContext2Validate_targetedDestroy(t *testing.T) {
+	m := testModule(t, "validate-targeted")
+	p := testProvider("aws")
+	pr := simpleMockProvisioner()
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+						"num": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	testSetResourceInstanceCurrent(root, "aws_instance.foo", `{"id":"i-bcd345"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+	testSetResourceInstanceCurrent(root, "aws_instance.bar", `{"id":"i-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"shell": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+func TestContext2Validate_varRefUnknown(t *testing.T) {
+	m := testModule(t, "validate-variable-ref")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	var value cty.Value
+	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+		value = req.Config.GetAttr("foo")
+		return providers.ValidateResourceConfigResponse{}
+	}
+
+	c.Validate(m)
+
+	// Input variables are always unknown during the validate walk, because
+	// we're checking for validity of all possible input values. Validity
+	// against specific input values is checked during the plan walk.
+	if !value.RawEquals(cty.UnknownVal(cty.String)) {
+		t.Fatalf("bad: %#v", value)
+	}
+}
+
+// Module variables weren't being interpolated during Validate phase.
+// related to https://github.com/hashicorp/terraform/issues/5322
+func TestContext2Validate_interpolateVar(t *testing.T) {
+	input := new(MockUIInput)
+
+	m := testModule(t, "input-interpolate-var")
+	p := testProvider("null")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"template_file": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"template": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
+		},
+		UIInput: input,
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+// When module vars reference something that is actually computed, this
+// shouldn't cause validation to fail.
+func TestContext2Validate_interpolateComputedModuleVarDef(t *testing.T) {
+	input := new(MockUIInput)
+
+	m := testModule(t, "validate-computed-module-var-ref")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"attr": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		UIInput: input,
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+// Computed values are lost when a map is output from a module
+func TestContext2Validate_interpolateMap(t *testing.T) {
+	input := new(MockUIInput)
+
+	m := testModule(t, "issue-9549")
+	p := testProvider("template")
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
+		},
+		UIInput: input,
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
+
+func TestContext2Validate_varSensitive(t *testing.T) {
+	// Smoke test through validate where a variable has sensitive applied
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "foo" {
+  default = "xyz"
+  sensitive = true
+}
+
+variable "bar" {
+  sensitive = true
+}
+
+data "aws_data_source" "bar" {
+  foo = var.bar
+}
+
+resource "aws_instance" "foo" {
+  foo = var.foo
+}
+`,
+	})
+
+	p := testProvider("aws")
+	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+		// Providers receive unmarked values
+		if got, want := req.Config.GetAttr("foo"), cty.UnknownVal(cty.String); !got.RawEquals(want) {
+			t.Fatalf("wrong value for foo\ngot:  %#v\nwant: %#v", got, want)
+		}
+		return providers.ValidateResourceConfigResponse{}
+	}
+	p.ValidateDataResourceConfigFn = func(req providers.ValidateDataResourceConfigRequest) (resp providers.ValidateDataResourceConfigResponse) {
+		if got, want := req.Config.GetAttr("foo"), cty.UnknownVal(cty.String); !got.RawEquals(want) {
+			t.Fatalf("wrong value for foo\ngot:  %#v\nwant: %#v", got, want)
+		}
+		return providers.ValidateDataResourceConfigResponse{}
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	if !p.ValidateResourceConfigCalled {
+		t.Fatal("expected ValidateResourceConfigFn to be called")
+	}
+
+	if !p.ValidateDataResourceConfigCalled {
+		t.Fatal("expected ValidateDataSourceConfigFn to be called")
+	}
+}
+
+func TestContext2Validate_invalidOutput(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+data "aws_data_source" "name" {}
+
+output "out" {
+  value = "${data.aws_data_source.name.missing}"
+}`,
+	})
+
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatal("succeeded; want errors")
+	}
+	// Should get this error:
+	// Unsupported attribute: This object does not have an attribute named "missing"
+	if got, want := diags.Err().Error(), "Unsupported attribute"; !strings.Contains(got, want) {
+		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
+	}
+}
+
+func TestContext2Validate_invalidModuleOutput(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"child/main.tf": `
+data "aws_data_source" "name" {}
+
+output "out" {
+  value = "${data.aws_data_source.name.missing}"
+}`,
+		"main.tf": `
+module "child" {
+  source = "./child"
+}
+
+resource "aws_instance" "foo" {
+  foo = "${module.child.out}"
+}`,
+	})
+
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatal("succeeded; want errors")
+	}
+	// Should get this error:
+	// Unsupported attribute: This object does not have an attribute named "missing"
+	if got, want := diags.Err().Error(), "Unsupported attribute"; !strings.Contains(got, want) {
+		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
+	}
+}
+
+func TestContext2Validate_sensitiveRootModuleOutput(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"child/main.tf": `
+variable "foo" {
+  default = "xyz"
+  sensitive = true
+}
+
+output "out" {
+  value = var.foo
+}`,
+		"main.tf": `
+module "child" {
+  source = "./child"
+}
+
+output "root" {
+  value = module.child.out
+  sensitive = true
+}`,
+	})
+
+	ctx := testContext2(t, &ContextOpts{})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+}
+
+func TestContext2Validate_legacyResourceCount(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "aws_instance" "test" {}
+
+output "out" {
+  value = aws_instance.test.count
+}`,
+	})
+
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatal("succeeded; want errors")
+	}
+	// Should get this error:
+	// Invalid resource count attribute: The special "count" attribute is no longer supported after Terraform v0.12. Instead, use length(aws_instance.test) to count resource instances.
+	if got, want := diags.Err().Error(), "Invalid resource count attribute:"; !strings.Contains(got, want) {
+		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
+	}
+}
+
+func TestContext2Validate_invalidModuleRef(t *testing.T) {
+	// This test is verifying that we properly validate and report on references
+	// to modules that are not declared, since we were missing some validation
+	// here in early 0.12.0 alphas that led to a panic.
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+output "out" {
+  # Intentionally referencing undeclared module to ensure error
+  value = module.foo
+}`,
+	})
+
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatal("succeeded; want errors")
+	}
+	// Should get this error:
+	// Reference to undeclared module: No module call named "foo" is declared in the root module.
+	if got, want := diags.Err().Error(), "Reference to undeclared module:"; !strings.Contains(got, want) {
+		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
+	}
+}
+
+func TestContext2Validate_invalidModuleOutputRef(t *testing.T) {
+	// This test is verifying that we properly validate and report on references
+	// to modules that are not declared, since we were missing some validation
+	// here in early 0.12.0 alphas that led to a panic.
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+output "out" {
+  # Intentionally referencing undeclared module to ensure error
+  value = module.foo.bar
+}`,
+	})
+
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatal("succeeded; want errors")
+	}
+	// Should get this error:
+	// Reference to undeclared module: No module call named "foo" is declared in the root module.
+	if got, want := diags.Err().Error(), "Reference to undeclared module:"; !strings.Contains(got, want) {
+		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
+	}
+}
+
+func TestContext2Validate_invalidDependsOnResourceRef(t *testing.T) {
+	// This test is verifying that we raise an error if depends_on
+	// refers to something that doesn't exist in configuration.
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_instance" "bar" {
+  depends_on = [test_resource.nonexistant]
+}
+`,
+	})
+
+	p := testProvider("test")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatal("succeeded; want errors")
+	}
+	// Should get this error:
+	// Reference to undeclared module: No module call named "foo" is declared in the root module.
+	if got, want := diags.Err().Error(), "Reference to undeclared resource:"; !strings.Contains(got, want) {
+		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
+	}
+}
+
+func TestContext2Validate_invalidResourceIgnoreChanges(t *testing.T) {
+	// This test is verifying that we raise an error if ignore_changes
+	// refers to something that can be statically detected as not conforming
+	// to the resource type schema.
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_instance" "bar" {
+  lifecycle {
+    ignore_changes = [does_not_exist_in_schema]
+  }
+}
+`,
+	})
+
+	p := testProvider("test")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatal("succeeded; want errors")
+	}
+	// Should get this error:
+	// Reference to undeclared module: No module call named "foo" is declared in the root module.
+	if got, want := diags.Err().Error(), `no argument, nested block, or exported attribute named "does_not_exist_in_schema"`; !strings.Contains(got, want) {
+		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
+	}
+}
+
+func TestContext2Validate_variableCustomValidationsFail(t *testing.T) {
+	// This test is for custom validation rules associated with root module
+	// variables, and specifically that we handle the situation where the
+	// given value is invalid in a child module.
+	m := testModule(t, "validate-variable-custom-validations-child")
+
+	p := testProvider("test")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatal("succeeded; want errors")
+	}
+	if got, want := diags.Err().Error(), `Invalid value for variable: Value must not be "nope".`; !strings.Contains(got, want) {
+		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
+	}
+}
+
+func TestContext2Validate_variableCustomValidationsRoot(t *testing.T) {
+	// This test is for custom validation rules associated with root module
+	// variables, and specifically that we handle the situation where their
+	// values are unknown during validation, skipping the validation check
+	// altogether. (Root module variables are never known during validation.)
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "test" {
+  type = string
+
+  validation {
+	condition     = var.test != "nope"
+	error_message = "Value must not be \"nope\"."
+  }
+}
+`,
+	})
+
+	p := testProvider("test")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error\ngot: %s", diags.Err().Error())
+	}
+}
+
+func TestContext2Validate_expandModules(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod1" {
+  for_each = toset(["a", "b"])
+  source = "./mod"
+}
+
+module "mod2" {
+  for_each = module.mod1
+  source = "./mod"
+  input = module.mod1["a"].out
+}
+
+module "mod3" {
+  count = length(module.mod2)
+  source = "./mod"
+}
+`,
+		"mod/main.tf": `
+resource "aws_instance" "foo" {
+}
+
+output "out" {
+  value = 1
+}
+
+variable "input" {
+  type = number
+  default = 0
+}
+
+module "nested" {
+  count = 2
+  source = "./nested"
+  input = count.index
+}
+`,
+		"mod/nested/main.tf": `
+variable "input" {
+}
+
+resource "aws_instance" "foo" {
+  count = var.input
+}
+`,
+	})
+
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+}
+
+func TestContext2Validate_expandModulesInvalidCount(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod1" {
+  count = -1
+  source = "./mod"
+}
+`,
+		"mod/main.tf": `
+resource "aws_instance" "foo" {
+}
+`,
+	})
+
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatal("succeeded; want errors")
+	}
+	if got, want := diags.Err().Error(), `Invalid count argument`; !strings.Contains(got, want) {
+		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
+	}
+}
+
+func TestContext2Validate_expandModulesInvalidForEach(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod1" {
+  for_each = ["a", "b"]
+  source = "./mod"
+}
+`,
+		"mod/main.tf": `
+resource "aws_instance" "foo" {
+}
+`,
+	})
+
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatal("succeeded; want errors")
+	}
+	if got, want := diags.Err().Error(), `Invalid for_each argument`; !strings.Contains(got, want) {
+		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
+	}
+}
+
+func TestContext2Validate_expandMultipleNestedModules(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "modA" {
+  for_each = {
+    first = "m"
+	second = "n"
+  }
+  source = "./modA"
+}
+`,
+		"modA/main.tf": `
+locals {
+  m = {
+    first = "m"
+	second = "n"
+  }
+}
+
+module "modB" {
+  for_each = local.m
+  source = "./modB"
+  y = each.value
+}
+
+module "modC" {
+  for_each = local.m
+  source = "./modC"
+  x = module.modB[each.key].out
+  y = module.modB[each.key].out
+}
+
+`,
+		"modA/modB/main.tf": `
+variable "y" {
+  type = string
+}
+
+resource "aws_instance" "foo" {
+  foo = var.y
+}
+
+output "out" {
+  value = aws_instance.foo.id
+}
+`,
+		"modA/modC/main.tf": `
+variable "x" {
+  type = string
+}
+
+variable "y" {
+  type = string
+}
+
+resource "aws_instance" "foo" {
+  foo = var.x
+}
+
+output "out" {
+  value = var.y
+}
+`,
+	})
+
+	p := testProvider("aws")
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+}
+
+func TestContext2Validate_invalidModuleDependsOn(t *testing.T) {
+	// validate module and output depends_on
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod1" {
+  source = "./mod"
+  depends_on = [resource_foo.bar.baz]
+}
+
+module "mod2" {
+  source = "./mod"
+  depends_on = [resource_foo.bar.baz]
+}
+`,
+		"mod/main.tf": `
+output "out" {
+  value = "foo"
+}
+`,
+	})
+
+	diags := testContext2(t, &ContextOpts{}).Validate(m)
+	if !diags.HasErrors() {
+		t.Fatal("succeeded; want errors")
+	}
+
+	if len(diags) != 2 {
+		t.Fatalf("wanted 2 diagnostic errors, got %q", diags)
+	}
+
+	for _, d := range diags {
+		des := d.Description().Summary
+		if !strings.Contains(des, "Invalid depends_on reference") {
+			t.Fatalf(`expected "Invalid depends_on reference", got %q`, des)
+		}
+	}
+}
+
+func TestContext2Validate_invalidOutputDependsOn(t *testing.T) {
+	// validate module and output depends_on
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+module "mod1" {
+  source = "./mod"
+}
+
+output "out" {
+  value = "bar"
+  depends_on = [resource_foo.bar.baz]
+}
+`,
+		"mod/main.tf": `
+output "out" {
+  value = "bar"
+  depends_on = [resource_foo.bar.baz]
+}
+`,
+	})
+
+	diags := testContext2(t, &ContextOpts{}).Validate(m)
+	if !diags.HasErrors() {
+		t.Fatal("succeeded; want errors")
+	}
+
+	if len(diags) != 2 {
+		t.Fatalf("wanted 2 diagnostic errors, got %q", diags)
+	}
+
+	for _, d := range diags {
+		des := d.Description().Summary
+		if !strings.Contains(des, "Invalid depends_on reference") {
+			t.Fatalf(`expected "Invalid depends_on reference", got %q`, des)
+		}
+	}
+}
+
+func TestContext2Validate_rpcDiagnostics(t *testing.T) {
+	// validate module and output depends_on
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_instance" "a" {
+}
+`,
+	})
+
+	p := testProvider("test")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"test_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"id": {Type: cty.String, Computed: true},
+					},
+				},
+			},
+		},
+	}
+
+	p.ValidateResourceConfigResponse = &providers.ValidateResourceConfigResponse{
+		Diagnostics: tfdiags.Diagnostics(nil).Append(tfdiags.SimpleWarning("don't frobble")),
+	}
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatal(diags.Err())
+	}
+
+	if len(diags) == 0 {
+		t.Fatal("expected warnings")
+	}
+
+	for _, d := range diags {
+		des := d.Description().Summary
+		if !strings.Contains(des, "frobble") {
+			t.Fatalf(`expected frobble, got %q`, des)
+		}
+	}
+}
+
+func TestContext2Validate_sensitiveProvisionerConfig(t *testing.T) {
+	m := testModule(t, "validate-sensitive-provisioner-config")
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
+		ResourceTypes: map[string]providers.Schema{
+			"aws_instance": {
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	}
+
+	pr := simpleMockProvisioner()
+
+	c := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+		Provisioners: map[string]provisioners.Factory{
+			"test": testProvisionerFuncFixed(pr),
+		},
+	})
+
+	pr.ValidateProvisionerConfigFn = func(r provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse {
+		if r.Config.ContainsMarked() {
+			t.Errorf("provisioner config contains marked values")
+		}
+		return pr.ValidateProvisionerConfigResponse
+	}
+
+	diags := c.Validate(m)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+	if !pr.ValidateProvisionerConfigCalled {
+		t.Fatal("ValidateProvisionerConfig not called")
+	}
+}
+
+func TestContext2Plan_validateMinMaxDynamicBlock(t *testing.T) {
+	p := new(MockProvider)
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"things": {
+						Type:     cty.List(cty.String),
+						Computed: true,
+					},
+				},
+				BlockTypes: map[string]*configschema.NestedBlock{
+					"foo": {
+						Block: configschema.Block{
+							Attributes: map[string]*configschema.Attribute{
+								"bar": {Type: cty.String, Optional: true},
+							},
+						},
+						Nesting:  configschema.NestingList,
+						MinItems: 2,
+						MaxItems: 3,
+					},
+				},
+			},
+		},
+	})
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "test_instance" "a" {
+  // MinItems 2
+  foo {
+    bar = "a"
+  }
+  foo {
+    bar = "b"
+  }
+}
+
+resource "test_instance" "b" {
+  // one dymamic block can satisfy MinItems of 2
+  dynamic "foo" {
+	for_each = test_instance.a.things
+	content {
+	  bar = foo.value
+	}
+  }
+}
+
+resource "test_instance" "c" {
+  // we may have more than MaxItems dynamic blocks when they are unknown
+  foo {
+    bar = "b"
+  }
+  dynamic "foo" {
+    for_each = test_instance.a.things
+    content {
+      bar = foo.value
+    }
+  }
+  dynamic "foo" {
+    for_each = test_instance.a.things
+    content {
+      bar = "${foo.value}-2"
+    }
+  }
+  dynamic "foo" {
+    for_each = test_instance.b.things
+    content {
+      bar = foo.value
+    }
+  }
+}
+`})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+}
+
+func TestContext2Validate_passInheritedProvider(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+terraform {
+  required_providers {
+	test = {
+	  source = "hashicorp/test"
+	}
+  }
+}
+
+module "first" {
+  source = "./first"
+  providers = {
+    test = test
+  }
+}
+`,
+
+		// This module does not define a config for the test provider, but we
+		// should be able to pass whatever the implied config is to a child
+		// module.
+		"first/main.tf": `
+terraform {
+  required_providers {
+    test = {
+	  source = "hashicorp/test"
+    }
+  }
+}
+
+module "second" {
+  source = "./second"
+  providers = {
+	test.alias = test
+  }
+}`,
+
+		"first/second/main.tf": `
+terraform {
+  required_providers {
+    test = {
+	  source = "hashicorp/test"
+      configuration_aliases = [test.alias]
+    }
+  }
+}
+
+resource "test_object" "t" {
+  provider = test.alias
+}
+`,
+	})
+
+	p := simpleMockProvider()
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+}
+
+func TestContext2Plan_lookupMismatchedObjectTypes(t *testing.T) {
+	p := new(MockProvider)
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+					"things": {
+						Type:     cty.List(cty.String),
+						Optional: true,
+					},
+				},
+			},
+		},
+	})
+
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "items" {
+  type = list(string)
+  default = []
+}
+
+resource "test_instance" "a" {
+  for_each = length(var.items) > 0 ? { default = {} } : {}
+}
+
+output "out" {
+  // Strictly speaking, this expression is incorrect because the map element
+  // type is a different type from the default value, and the lookup
+  // implementation expects to be able to convert the default to match the
+  // element type.
+  // There are two reasons this works which we need to maintain for
+  // compatibility. First during validation the 'test_instance.a' expression
+  // only returns a dynamic value, preventing any type comparison. Later during
+  // plan and apply 'test_instance.a' is an object and not a map, and the
+  // lookup implementation skips the type comparison when the keys are known
+  // statically.
+  value = lookup(test_instance.a, "default", { id = null })["id"]
+}
+`})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+}
+
+func TestContext2Validate_nonNullableVariableDefaultValidation(t *testing.T) {
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+ module "first" {
+   source = "./mod"
+   input = null
+ }
+ `,
+
+		"mod/main.tf": `
+ variable "input" {
+   type        = string
+   default     = "default"
+   nullable    = false
+
+   // Validation expressions should receive the default with nullable=false and
+   // a null input.
+   validation {
+     condition     = var.input != null
+     error_message = "Input cannot be null!"
+   }
+ }
+ `,
+	})
+
+	ctx := testContext2(t, &ContextOpts{})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+}
+
+func TestContext2Validate_precondition_good(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "input" {
+  type    = string
+  default = "foo"
+}
+
+resource "aws_instance" "test" {
+  foo = var.input
+
+  lifecycle {
+    precondition {
+      condition     = length(var.input) > 0
+      error_message = "Input cannot be empty."
+    }
+  }
+}
+ `,
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+}
+
+func TestContext2Validate_precondition_badCondition(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "input" {
+  type    = string
+  default = "foo"
+}
+
+resource "aws_instance" "test" {
+  foo = var.input
+
+  lifecycle {
+    precondition {
+      condition     = length(one(var.input)) == 1
+      error_message = "You can't do that."
+    }
+  }
+}
+ `,
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want error")
+	}
+	if got, want := diags.Err().Error(), "Invalid function argument"; !strings.Contains(got, want) {
+		t.Errorf("unexpected error.\ngot: %s\nshould contain: %q", got, want)
+	}
+}
+
+func TestContext2Validate_precondition_badErrorMessage(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "input" {
+  type    = string
+  default = "foo"
+}
+
+resource "aws_instance" "test" {
+  foo = var.input
+
+  lifecycle {
+    precondition {
+      condition     = var.input != "foo"
+      error_message = "This is a bad use of a function: ${one(var.input)}."
+    }
+  }
+}
+ `,
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want error")
+	}
+	if got, want := diags.Err().Error(), "Invalid function argument"; !strings.Contains(got, want) {
+		t.Errorf("unexpected error.\ngot: %s\nshould contain: %q", got, want)
+	}
+}
+
+func TestContext2Validate_postcondition_good(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "aws_instance" "test" {
+  foo = "foo"
+
+  lifecycle {
+    postcondition {
+      condition     = length(self.foo) > 0
+      error_message = "Input cannot be empty."
+    }
+  }
+}
+ `,
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+}
+
+func TestContext2Validate_postcondition_badCondition(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+	// This postcondition's condition expression does not refer to self, which
+	// is unrealistic. This is because at the time of writing the test, self is
+	// always an unknown value of dynamic type during validation. As a result,
+	// validation of conditions which refer to resource arguments is not
+	// possible until plan time. For now we exercise the code by referring to
+	// an input variable.
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+variable "input" {
+  type    = string
+  default = "foo"
+}
+
+resource "aws_instance" "test" {
+  foo = var.input
+
+  lifecycle {
+    postcondition {
+      condition     = length(one(var.input)) == 1
+      error_message = "You can't do that."
+    }
+  }
+}
+ `,
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want error")
+	}
+	if got, want := diags.Err().Error(), "Invalid function argument"; !strings.Contains(got, want) {
+		t.Errorf("unexpected error.\ngot: %s\nshould contain: %q", got, want)
+	}
+}
+
+func TestContext2Validate_postcondition_badErrorMessage(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "aws_instance" "test" {
+  foo = "foo"
+
+  lifecycle {
+    postcondition {
+      condition     = self.foo != "foo"
+      error_message = "This is a bad use of a function: ${one("foo")}."
+    }
+  }
+}
+ `,
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if !diags.HasErrors() {
+		t.Fatalf("succeeded; want error")
+	}
+	if got, want := diags.Err().Error(), "Invalid function argument"; !strings.Contains(got, want) {
+		t.Errorf("unexpected error.\ngot: %s\nshould contain: %q", got, want)
+	}
+}
+
+func TestContext2Validate_precondition_count(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+locals {
+  foos = ["bar", "baz"]
+}
+
+resource "aws_instance" "test" {
+  count = 3
+  foo = local.foos[count.index]
+
+  lifecycle {
+    precondition {
+      condition     = count.index < length(local.foos)
+      error_message = "Insufficient foos."
+    }
+  }
+}
+ `,
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+}
+
+func TestContext2Validate_postcondition_forEach(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true},
+				},
+			},
+		},
+	})
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+locals {
+  foos = toset(["bar", "baz", "boop"])
+}
+
+resource "aws_instance" "test" {
+  for_each = local.foos
+  foo = "foo"
+
+  lifecycle {
+    postcondition {
+      condition     = length(each.value) == 3
+      error_message = "Short foo required, not \"${each.key}\"."
+    }
+  }
+}
+ `,
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	if diags.HasErrors() {
+		t.Fatal(diags.ErrWithWarnings())
+	}
+}
+
+func TestContext2Validate_deprecatedAttr(t *testing.T) {
+	p := testProvider("aws")
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"aws_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"foo": {Type: cty.String, Optional: true, Deprecated: true},
+				},
+			},
+		},
+	})
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "aws_instance" "test" {
+}
+locals {
+  deprecated = aws_instance.test.foo
+}
+
+ `,
+	})
+
+	ctx := testContext2(t, &ContextOpts{
+		Providers: map[addrs.Provider]providers.Factory{
+			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
+		},
+	})
+
+	diags := ctx.Validate(m)
+	warn := diags.ErrWithWarnings().Error()
+	if !strings.Contains(warn, `The attribute "foo" is deprecated`) {
+		t.Fatalf("expected deprecated warning, got: %q\n", warn)
+	}
+}
diff --git a/v1.5.7/internal/terraform/context_walk.go b/v1.5.7/internal/terraform/context_walk.go
new file mode 100644
index 0000000..7fbd667
--- /dev/null
+++ b/v1.5.7/internal/terraform/context_walk.go
@@ -0,0 +1,154 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+	"time"
+
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/refactoring"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// graphWalkOpts captures some transient values we use (and possibly mutate)
+// during a graph walk.
+//
+// The way these options get used unfortunately varies between the different
+// walkOperation types. This is a historical design wart that dates back to
+// us using the same graph structure for all operations; hopefully we'll
+// make the necessary differences between the walk types more explicit someday.
+type graphWalkOpts struct {
+	InputState *states.State
+	Changes    *plans.Changes
+	Config     *configs.Config
+
+	// PlanTimeCheckResults should be populated during the apply phase with
+	// the snapshot of check results that was generated during the plan step.
+	//
+	// This then propagates the decisions about which checkable objects exist
+	// from the plan phase into the apply phase without having to re-compute
+	// the module and resource expansion.
+	PlanTimeCheckResults *states.CheckResults
+
+	// PlanTimeTimestamp should be populated during the plan phase by retrieving
+	// the current UTC timestamp, and should be read from the plan file during
+	// the apply phase.
+	PlanTimeTimestamp time.Time
+
+	MoveResults refactoring.MoveResults
+}
+
+func (c *Context) walk(graph *Graph, operation walkOperation, opts *graphWalkOpts) (*ContextGraphWalker, tfdiags.Diagnostics) {
+	log.Printf("[DEBUG] Starting graph walk: %s", operation.String())
+
+	walker := c.graphWalker(operation, opts)
+
+	// Watch for a stop so we can call the provider Stop() API.
+	watchStop, watchWait := c.watchStop(walker)
+
+	// Walk the real graph, this will block until it completes
+	diags := graph.Walk(walker)
+
+	// Close the channel so the watcher stops, and wait for it to return.
+	close(watchStop)
+	<-watchWait
+
+	return walker, diags
+}
+
+func (c *Context) graphWalker(operation walkOperation, opts *graphWalkOpts) *ContextGraphWalker {
+	var state *states.SyncState
+	var refreshState *states.SyncState
+	var prevRunState *states.SyncState
+
+	// NOTE: None of the SyncState objects must directly wrap opts.InputState,
+	// because we use those to mutate the state object and opts.InputState
+	// belongs to our caller and thus we must treat it as immutable.
+	//
+	// To account for that, most of our SyncState values created below end up
+	// wrapping a _deep copy_ of opts.InputState instead.
+	inputState := opts.InputState
+	if inputState == nil {
+		// Lots of callers use nil to represent the "empty" case where we've
+		// not run Apply yet, so we tolerate that.
+		inputState = states.NewState()
+	}
+
+	switch operation {
+	case walkValidate:
+		// validate should not use any state
+		state = states.NewState().SyncWrapper()
+
+		// validate currently uses the plan graph, so we have to populate the
+		// refreshState and the prevRunState.
+		refreshState = states.NewState().SyncWrapper()
+		prevRunState = states.NewState().SyncWrapper()
+
+	case walkPlan, walkPlanDestroy, walkImport:
+		state = inputState.DeepCopy().SyncWrapper()
+		refreshState = inputState.DeepCopy().SyncWrapper()
+		prevRunState = inputState.DeepCopy().SyncWrapper()
+
+		// For both of our new states we'll discard the previous run's
+		// check results, since we can still refer to them from the
+		// prevRunState object if we need to.
+		state.DiscardCheckResults()
+		refreshState.DiscardCheckResults()
+
+	default:
+		state = inputState.DeepCopy().SyncWrapper()
+		// Only plan-like walks use refreshState and prevRunState
+
+		// Discard the input state's check results, because we should create
+		// a new set as a result of the graph walk.
+		state.DiscardCheckResults()
+	}
+
+	changes := opts.Changes
+	if changes == nil {
+		// Several of our non-plan walks end up sharing codepaths with the
+		// plan walk and thus expect to generate planned changes even though
+		// we don't care about them. To avoid those crashing, we'll just
+		// insert a placeholder changes object which'll get discarded
+		// afterwards.
+		changes = plans.NewChanges()
+	}
+
+	if opts.Config == nil {
+		panic("Context.graphWalker call without Config")
+	}
+
+	checkState := checks.NewState(opts.Config)
+	if opts.PlanTimeCheckResults != nil {
+		// We'll re-report all of the same objects we determined during the
+		// plan phase so that we can repeat the checks during the apply
+		// phase to finalize them.
+		for _, configElem := range opts.PlanTimeCheckResults.ConfigResults.Elems {
+			if configElem.Value.ObjectAddrsKnown() {
+				configAddr := configElem.Key
+				checkState.ReportCheckableObjects(configAddr, configElem.Value.ObjectResults.Keys())
+			}
+		}
+	}
+
+	return &ContextGraphWalker{
+		Context:          c,
+		State:            state,
+		Config:           opts.Config,
+		RefreshState:     refreshState,
+		PrevRunState:     prevRunState,
+		Changes:          changes.SyncWrapper(),
+		Checks:           checkState,
+		InstanceExpander: instances.NewExpander(),
+		MoveResults:      opts.MoveResults,
+		Operation:        operation,
+		StopContext:      c.runContext,
+		PlanTimestamp:    opts.PlanTimeTimestamp,
+	}
+}
diff --git a/v1.5.7/internal/terraform/diagnostics.go b/v1.5.7/internal/terraform/diagnostics.go
new file mode 100644
index 0000000..6f876f5
--- /dev/null
+++ b/v1.5.7/internal/terraform/diagnostics.go
@@ -0,0 +1,45 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// This file contains some package-local helpers for working with diagnostics.
+// For the main diagnostics API, see the separate "tfdiags" package.
+
+// diagnosticCausedByUnknown is an implementation of
+// tfdiags.DiagnosticExtraBecauseUnknown which we can use in the "Extra" field
+// of a diagnostic to indicate that the problem was caused by unknown values
+// being involved in an expression evaluation.
+//
+// When using this, set the Extra to diagnosticCausedByUnknown(true) and also
+// populate the EvalContext and Expression fields of the diagnostic so that
+// the diagnostic renderer can use all of that information together to assist
+// the user in understanding what was unknown.
+type diagnosticCausedByUnknown bool
+
+var _ tfdiags.DiagnosticExtraBecauseUnknown = diagnosticCausedByUnknown(true)
+
+func (e diagnosticCausedByUnknown) DiagnosticCausedByUnknown() bool {
+	return bool(e)
+}
+
+// diagnosticCausedBySensitive is an implementation of
+// tfdiags.DiagnosticExtraBecauseSensitive which we can use in the "Extra" field
+// of a diagnostic to indicate that the problem was caused by sensitive values
+// being involved in an expression evaluation.
+//
+// When using this, set the Extra to diagnosticCausedBySensitive(true) and also
+// populate the EvalContext and Expression fields of the diagnostic so that
+// the diagnostic renderer can use all of that information together to assist
+// the user in understanding what was sensitive.
+type diagnosticCausedBySensitive bool
+
+var _ tfdiags.DiagnosticExtraBecauseSensitive = diagnosticCausedBySensitive(true)
+
+func (e diagnosticCausedBySensitive) DiagnosticCausedBySensitive() bool {
+	return bool(e)
+}
diff --git a/v1.5.7/internal/terraform/eval_conditions.go b/v1.5.7/internal/terraform/eval_conditions.go
new file mode 100644
index 0000000..6c86f74
--- /dev/null
+++ b/v1.5.7/internal/terraform/eval_conditions.go
@@ -0,0 +1,277 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/convert"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// evalCheckRules ensures that all of the given check rules pass against
+// the given HCL evaluation context.
+//
+// If any check rules produce an unknown result then they will be silently
+// ignored on the assumption that the same checks will be run again later
+// with fewer unknown values in the EvalContext.
+//
+// If any of the rules do not pass, the returned diagnostics will contain
+// errors. Otherwise, it will either be empty or contain only warnings.
+func evalCheckRules(typ addrs.CheckRuleType, rules []*configs.CheckRule, ctx EvalContext, self addrs.Checkable, keyData instances.RepetitionData, diagSeverity tfdiags.Severity) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	checkState := ctx.Checks()
+	if !checkState.ConfigHasChecks(self.ConfigCheckable()) {
+		// We have nothing to do if this object doesn't have any checks,
+		// but the "rules" slice should agree that we don't.
+		if ct := len(rules); ct != 0 {
+			panic(fmt.Sprintf("check state says that %s should have no rules, but it has %d", self, ct))
+		}
+		return diags
+	}
+
+	if len(rules) == 0 {
+		// Nothing to do
+		return nil
+	}
+
+	severity := diagSeverity.ToHCL()
+
+	for i, rule := range rules {
+		result, ruleDiags := evalCheckRule(typ, rule, ctx, self, keyData, severity)
+		diags = diags.Append(ruleDiags)
+
+		log.Printf("[TRACE] evalCheckRules: %s status is now %s", self, result.Status)
+		if result.Status == checks.StatusFail {
+			checkState.ReportCheckFailure(self, typ, i, result.FailureMessage)
+		} else {
+			checkState.ReportCheckResult(self, typ, i, result.Status)
+		}
+	}
+
+	return diags
+}
+
+type checkResult struct {
+	Status         checks.Status
+	FailureMessage string
+}
+
+func validateCheckRule(typ addrs.CheckRuleType, rule *configs.CheckRule, ctx EvalContext, self addrs.Checkable, keyData instances.RepetitionData) (string, *hcl.EvalContext, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	refs, moreDiags := lang.ReferencesInExpr(rule.Condition)
+	diags = diags.Append(moreDiags)
+	moreRefs, moreDiags := lang.ReferencesInExpr(rule.ErrorMessage)
+	diags = diags.Append(moreDiags)
+	refs = append(refs, moreRefs...)
+
+	var selfReference, sourceReference addrs.Referenceable
+	switch typ {
+	case addrs.ResourcePostcondition:
+		switch s := self.(type) {
+		case addrs.AbsResourceInstance:
+			// Only resource postconditions can refer to self
+			selfReference = s.Resource
+		default:
+			panic(fmt.Sprintf("Invalid self reference type %t", self))
+		}
+	case addrs.CheckAssertion:
+		switch s := self.(type) {
+		case addrs.AbsCheck:
+			// Only check blocks have scoped resources so need to specify their
+			// source.
+			sourceReference = s.Check
+		default:
+			panic(fmt.Sprintf("Invalid source reference type %t", self))
+		}
+	}
+	scope := ctx.EvaluationScope(selfReference, sourceReference, keyData)
+
+	hclCtx, moreDiags := scope.EvalContext(refs)
+	diags = diags.Append(moreDiags)
+
+	errorMessage, moreDiags := evalCheckErrorMessage(rule.ErrorMessage, hclCtx)
+	diags = diags.Append(moreDiags)
+
+	return errorMessage, hclCtx, diags
+}
+
+func evalCheckRule(typ addrs.CheckRuleType, rule *configs.CheckRule, ctx EvalContext, self addrs.Checkable, keyData instances.RepetitionData, severity hcl.DiagnosticSeverity) (checkResult, tfdiags.Diagnostics) {
+	// NOTE: Intentionally not passing the caller's selected severity in here,
+	// because this reports errors in the configuration itself, not the failure
+	// of an otherwise-valid condition.
+	errorMessage, hclCtx, diags := validateCheckRule(typ, rule, ctx, self, keyData)
+
+	const errInvalidCondition = "Invalid condition result"
+
+	resultVal, hclDiags := rule.Condition.Value(hclCtx)
+	diags = diags.Append(hclDiags)
+
+	if diags.HasErrors() {
+		log.Printf("[TRACE] evalCheckRule: %s: %s", typ, diags.Err().Error())
+		return checkResult{Status: checks.StatusError}, diags
+	}
+
+	if !resultVal.IsKnown() {
+
+		// Check assertions warn if a status is unknown.
+		if typ == addrs.CheckAssertion {
+			diags = diags.Append(tfdiags.AsCheckBlockDiagnostic(&hcl.Diagnostic{
+				Severity:    hcl.DiagWarning,
+				Summary:     fmt.Sprintf("%s known after apply", typ.Description()),
+				Detail:      "The condition could not be evaluated at this time, a result will be known when this plan is applied.",
+				Subject:     rule.Condition.Range().Ptr(),
+				Expression:  rule.Condition,
+				EvalContext: hclCtx,
+			}))
+		}
+
+		// We'll wait until we've learned more, then.
+		return checkResult{Status: checks.StatusUnknown}, diags
+	}
+	if resultVal.IsNull() {
+		// NOTE: Intentionally not passing the caller's selected severity in here,
+		// because this reports errors in the configuration itself, not the failure
+		// of an otherwise-valid condition.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity:    hcl.DiagError,
+			Summary:     errInvalidCondition,
+			Detail:      "Condition expression must return either true or false, not null.",
+			Subject:     rule.Condition.Range().Ptr(),
+			Expression:  rule.Condition,
+			EvalContext: hclCtx,
+		})
+		return checkResult{Status: checks.StatusError}, diags
+	}
+	var err error
+	resultVal, err = convert.Convert(resultVal, cty.Bool)
+	if err != nil {
+		// NOTE: Intentionally not passing the caller's selected severity in here,
+		// because this reports errors in the configuration itself, not the failure
+		// of an otherwise-valid condition.
+		detail := fmt.Sprintf("Invalid condition result value: %s.", tfdiags.FormatError(err))
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity:    hcl.DiagError,
+			Summary:     errInvalidCondition,
+			Detail:      detail,
+			Subject:     rule.Condition.Range().Ptr(),
+			Expression:  rule.Condition,
+			EvalContext: hclCtx,
+		})
+		return checkResult{Status: checks.StatusError}, diags
+	}
+
+	// The condition result may be marked if the expression refers to a
+	// sensitive value.
+	resultVal, _ = resultVal.Unmark()
+
+	status := checks.StatusForCtyValue(resultVal)
+
+	if status != checks.StatusFail {
+		return checkResult{Status: status}, diags
+	}
+
+	errorMessageForDiags := errorMessage
+	if errorMessageForDiags == "" {
+		errorMessageForDiags = "This check failed, but has an invalid error message as described in the other accompanying messages."
+	}
+	diag := &hcl.Diagnostic{
+		// The caller gets to choose the severity of this one, because we
+		// treat condition failures as warnings in the presence of
+		// certain special planning options.
+		Severity:    severity,
+		Summary:     fmt.Sprintf("%s failed", typ.Description()),
+		Detail:      errorMessageForDiags,
+		Subject:     rule.Condition.Range().Ptr(),
+		Expression:  rule.Condition,
+		EvalContext: hclCtx,
+	}
+
+	if typ == addrs.CheckAssertion {
+		diags = diags.Append(tfdiags.AsCheckBlockDiagnostic(diag))
+	} else {
+		diags = diags.Append(diag)
+	}
+
+	return checkResult{
+		Status:         status,
+		FailureMessage: errorMessage,
+	}, diags
+}
+
+// evalCheckErrorMessage makes a best effort to evaluate the given expression,
+// as an error message string.
+//
+// It will either return a non-empty message string or it'll return diagnostics
+// with either errors or warnings that explain why the given expression isn't
+// acceptable.
+func evalCheckErrorMessage(expr hcl.Expression, hclCtx *hcl.EvalContext) (string, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	val, hclDiags := expr.Value(hclCtx)
+	diags = diags.Append(hclDiags)
+	if hclDiags.HasErrors() {
+		return "", diags
+	}
+
+	val, err := convert.Convert(val, cty.String)
+	if err != nil {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity:    hcl.DiagError,
+			Summary:     "Invalid error message",
+			Detail:      fmt.Sprintf("Unsuitable value for error message: %s.", tfdiags.FormatError(err)),
+			Subject:     expr.Range().Ptr(),
+			Expression:  expr,
+			EvalContext: hclCtx,
+		})
+		return "", diags
+	}
+	if !val.IsKnown() {
+		return "", diags
+	}
+	if val.IsNull() {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity:    hcl.DiagError,
+			Summary:     "Invalid error message",
+			Detail:      "Unsuitable value for error message: must not be null.",
+			Subject:     expr.Range().Ptr(),
+			Expression:  expr,
+			EvalContext: hclCtx,
+		})
+		return "", diags
+	}
+
+	val, valMarks := val.Unmark()
+	if _, sensitive := valMarks[marks.Sensitive]; sensitive {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagWarning,
+			Summary:  "Error message refers to sensitive values",
+			Detail: `The error expression used to explain this condition refers to sensitive values, so Terraform will not display the resulting message.
+
+You can correct this by removing references to sensitive values, or by carefully using the nonsensitive() function if the expression will not reveal the sensitive data.`,
+			Subject:     expr.Range().Ptr(),
+			Expression:  expr,
+			EvalContext: hclCtx,
+		})
+		return "", diags
+	}
+
+	// NOTE: We've discarded any other marks the string might have been carrying,
+	// aside from the sensitive mark.
+
+	return strings.TrimSpace(val.AsString()), diags
+}
diff --git a/v1.5.7/internal/terraform/eval_context.go b/v1.5.7/internal/terraform/eval_context.go
new file mode 100644
index 0000000..0835a35
--- /dev/null
+++ b/v1.5.7/internal/terraform/eval_context.go
@@ -0,0 +1,207 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/refactoring"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// EvalContext is the interface that is given to eval nodes to execute.
+type EvalContext interface {
+	// Stopped returns a channel that is closed when evaluation is stopped
+	// via Terraform.Context.Stop()
+	Stopped() <-chan struct{}
+
+	// Path is the current module path.
+	Path() addrs.ModuleInstance
+
+	// Hook is used to call hook methods. The callback is called for each
+	// hook and should return the hook action to take and the error.
+	Hook(func(Hook) (HookAction, error)) error
+
+	// Input is the UIInput object for interacting with the UI.
+	Input() UIInput
+
+	// InitProvider initializes the provider with the given address, and returns
+	// the implementation of the resource provider or an error.
+	//
+	// It is an error to initialize the same provider more than once. This
+	// method will panic if the module instance address of the given provider
+	// configuration does not match the Path() of the EvalContext.
+	InitProvider(addr addrs.AbsProviderConfig) (providers.Interface, error)
+
+	// Provider gets the provider instance with the given address (already
+	// initialized) or returns nil if the provider isn't initialized.
+	//
+	// This method expects an _absolute_ provider configuration address, since
+	// resources in one module are able to use providers from other modules.
+	// InitProvider must've been called on the EvalContext of the module
+	// that owns the given provider before calling this method.
+	Provider(addrs.AbsProviderConfig) providers.Interface
+
+	// ProviderSchema retrieves the schema for a particular provider, which
+	// must have already been initialized with InitProvider.
+	//
+	// This method expects an _absolute_ provider configuration address, since
+	// resources in one module are able to use providers from other modules.
+	ProviderSchema(addrs.AbsProviderConfig) (*ProviderSchema, error)
+
+	// CloseProvider closes provider connections that aren't needed anymore.
+	//
+	// This method will panic if the module instance address of the given
+	// provider configuration does not match the Path() of the EvalContext.
+	CloseProvider(addrs.AbsProviderConfig) error
+
+	// ConfigureProvider configures the provider with the given
+	// configuration. This is a separate context call because this call
+	// is used to store the provider configuration for inheritance lookups
+	// with ParentProviderConfig().
+	//
+	// This method will panic if the module instance address of the given
+	// provider configuration does not match the Path() of the EvalContext.
+	ConfigureProvider(addrs.AbsProviderConfig, cty.Value) tfdiags.Diagnostics
+
+	// ProviderInput and SetProviderInput are used to configure providers
+	// from user input.
+	//
+	// These methods will panic if the module instance address of the given
+	// provider configuration does not match the Path() of the EvalContext.
+	ProviderInput(addrs.AbsProviderConfig) map[string]cty.Value
+	SetProviderInput(addrs.AbsProviderConfig, map[string]cty.Value)
+
+	// Provisioner gets the provisioner instance with the given name.
+	Provisioner(string) (provisioners.Interface, error)
+
+	// ProvisionerSchema retrieves the main configuration schema for a
+	// particular provisioner, which must have already been initialized with
+	// InitProvisioner.
+	ProvisionerSchema(string) (*configschema.Block, error)
+
+	// CloseProvisioner closes all provisioner plugins.
+	CloseProvisioners() error
+
+	// EvaluateBlock takes the given raw configuration block and associated
+	// schema and evaluates it to produce a value of an object type that
+	// conforms to the implied type of the schema.
+	//
+	// The "self" argument is optional. If given, it is the referenceable
+	// address that the name "self" should behave as an alias for when
+	// evaluating. Set this to nil if the "self" object should not be available.
+	//
+	// The "key" argument is also optional. If given, it is the instance key
+	// of the current object within the multi-instance container it belongs
+	// to. For example, on a resource block with "count" set this should be
+	// set to a different addrs.IntKey for each instance created from that
+	// block. Set this to addrs.NoKey if not appropriate.
+	//
+	// The returned body is an expanded version of the given body, with any
+	// "dynamic" blocks replaced with zero or more static blocks. This can be
+	// used to extract correct source location information about attributes of
+	// the returned object value.
+	EvaluateBlock(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, keyData InstanceKeyEvalData) (cty.Value, hcl.Body, tfdiags.Diagnostics)
+
+	// EvaluateExpr takes the given HCL expression and evaluates it to produce
+	// a value.
+	//
+	// The "self" argument is optional. If given, it is the referenceable
+	// address that the name "self" should behave as an alias for when
+	// evaluating. Set this to nil if the "self" object should not be available.
+	EvaluateExpr(expr hcl.Expression, wantType cty.Type, self addrs.Referenceable) (cty.Value, tfdiags.Diagnostics)
+
+	// EvaluateReplaceTriggeredBy takes the raw reference expression from the
+	// config, and returns the evaluated *addrs.Reference along with a boolean
+	// indicating if that reference forces replacement.
+	EvaluateReplaceTriggeredBy(expr hcl.Expression, repData instances.RepetitionData) (*addrs.Reference, bool, tfdiags.Diagnostics)
+
+	// EvaluationScope returns a scope that can be used to evaluate reference
+	// addresses in this context.
+	EvaluationScope(self addrs.Referenceable, source addrs.Referenceable, keyData InstanceKeyEvalData) *lang.Scope
+
+	// SetRootModuleArgument defines the value for one variable of the root
+	// module. The caller must ensure that given value is a suitable
+	// "final value" for the variable, which means that it's already converted
+	// and validated to match any configured constraints and validation rules.
+	//
+	// Calling this function multiple times with the same variable address
+	// will silently overwrite the value provided by a previous call.
+	SetRootModuleArgument(addrs.InputVariable, cty.Value)
+
+	// SetModuleCallArgument defines the value for one input variable of a
+	// particular child module call. The caller must ensure that the given
+	// value is a suitable "final value" for the variable, which means that
+	// it's already converted and validated to match any configured
+	// constraints and validation rules.
+	//
+	// Calling this function multiple times with the same variable address
+	// will silently overwrite the value provided by a previous call.
+	SetModuleCallArgument(addrs.ModuleCallInstance, addrs.InputVariable, cty.Value)
+
+	// GetVariableValue returns the value provided for the input variable with
+	// the given address, or cty.DynamicVal if the variable hasn't been assigned
+	// a value yet.
+	//
+	// Most callers should deal with variable values only indirectly via
+	// EvaluationScope and the other expression evaluation functions, but
+	// this is provided because variables tend to be evaluated outside of
+	// the context of the module they belong to and so we sometimes need to
+	// override the normal expression evaluation behavior.
+	GetVariableValue(addr addrs.AbsInputVariableInstance) cty.Value
+
+	// Changes returns the writer object that can be used to write new proposed
+	// changes into the global changes set.
+	Changes() *plans.ChangesSync
+
+	// State returns a wrapper object that provides safe concurrent access to
+	// the global state.
+	State() *states.SyncState
+
+	// Checks returns the object that tracks the state of any custom checks
+	// declared in the configuration.
+	Checks() *checks.State
+
+	// RefreshState returns a wrapper object that provides safe concurrent
+	// access to the state used to store the most recently refreshed resource
+	// values.
+	RefreshState() *states.SyncState
+
+	// PrevRunState returns a wrapper object that provides safe concurrent
+	// access to the state which represents the result of the previous run,
+	// updated only so that object data conforms to current schemas for
+	// meaningful comparison with RefreshState.
+	PrevRunState() *states.SyncState
+
+	// InstanceExpander returns a helper object for tracking the expansion of
+	// graph nodes during the plan phase in response to "count" and "for_each"
+	// arguments.
+	//
+	// The InstanceExpander is a global object that is shared across all of the
+	// EvalContext objects for a given configuration.
+	InstanceExpander() *instances.Expander
+
+	// MoveResults returns a map describing the results of handling any
+	// resource instance move statements prior to the graph walk, so that
+	// the graph walk can then record that information appropriately in other
+	// artifacts produced by the graph walk.
+	//
+	// This data structure is created prior to the graph walk and read-only
+	// thereafter, so callers must not modify the returned map or any other
+	// objects accessible through it.
+	MoveResults() refactoring.MoveResults
+
+	// WithPath returns a copy of the context with the internal path set to the
+	// path argument.
+	WithPath(path addrs.ModuleInstance) EvalContext
+}
diff --git a/v1.5.7/internal/terraform/eval_context_builtin.go b/v1.5.7/internal/terraform/eval_context_builtin.go
new file mode 100644
index 0000000..0070cec
--- /dev/null
+++ b/v1.5.7/internal/terraform/eval_context_builtin.go
@@ -0,0 +1,505 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"sync"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/refactoring"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/hashicorp/terraform/version"
+)
+
+// BuiltinEvalContext is an EvalContext implementation that is used by
+// Terraform by default.
+type BuiltinEvalContext struct {
+	// StopContext is the context used to track whether we're complete
+	StopContext context.Context
+
+	// PathValue is the Path that this context is operating within.
+	PathValue addrs.ModuleInstance
+
+	// pathSet indicates that this context was explicitly created for a
+	// specific path, and can be safely used for evaluation. This lets us
+	// differentiate between PathValue being unset, and the zero value which is
+	// equivalent to RootModuleInstance.  Path and Evaluation methods will
+	// panic if this is not set.
+	pathSet bool
+
+	// Evaluator is used for evaluating expressions within the scope of this
+	// eval context.
+	Evaluator *Evaluator
+
+	// VariableValues contains the variable values across all modules. This
+	// structure is shared across the entire containing context, and so it
+	// may be accessed only when holding VariableValuesLock.
+	// The keys of the first level of VariableValues are the string
+	// representations of addrs.ModuleInstance values. The second-level keys
+	// are variable names within each module instance.
+	VariableValues     map[string]map[string]cty.Value
+	VariableValuesLock *sync.Mutex
+
+	// Plugins is a library of plugin components (providers and provisioners)
+	// available for use during a graph walk.
+	Plugins *contextPlugins
+
+	Hooks                 []Hook
+	InputValue            UIInput
+	ProviderCache         map[string]providers.Interface
+	ProviderInputConfig   map[string]map[string]cty.Value
+	ProviderLock          *sync.Mutex
+	ProvisionerCache      map[string]provisioners.Interface
+	ProvisionerLock       *sync.Mutex
+	ChangesValue          *plans.ChangesSync
+	StateValue            *states.SyncState
+	ChecksValue           *checks.State
+	RefreshStateValue     *states.SyncState
+	PrevRunStateValue     *states.SyncState
+	InstanceExpanderValue *instances.Expander
+	MoveResultsValue      refactoring.MoveResults
+}
+
+// BuiltinEvalContext implements EvalContext
+var _ EvalContext = (*BuiltinEvalContext)(nil)
+
+func (ctx *BuiltinEvalContext) WithPath(path addrs.ModuleInstance) EvalContext {
+	newCtx := *ctx
+	newCtx.pathSet = true
+	newCtx.PathValue = path
+	return &newCtx
+}
+
+func (ctx *BuiltinEvalContext) Stopped() <-chan struct{} {
+	// This can happen during tests. During tests, we just block forever.
+	if ctx.StopContext == nil {
+		return nil
+	}
+
+	return ctx.StopContext.Done()
+}
+
+func (ctx *BuiltinEvalContext) Hook(fn func(Hook) (HookAction, error)) error {
+	for _, h := range ctx.Hooks {
+		action, err := fn(h)
+		if err != nil {
+			return err
+		}
+
+		switch action {
+		case HookActionContinue:
+			continue
+		case HookActionHalt:
+			// Return an early exit error to trigger an early exit
+			log.Printf("[WARN] Early exit triggered by hook: %T", h)
+			return nil
+		}
+	}
+
+	return nil
+}
+
+func (ctx *BuiltinEvalContext) Input() UIInput {
+	return ctx.InputValue
+}
+
+func (ctx *BuiltinEvalContext) InitProvider(addr addrs.AbsProviderConfig) (providers.Interface, error) {
+	// If we already initialized, it is an error
+	if p := ctx.Provider(addr); p != nil {
+		return nil, fmt.Errorf("%s is already initialized", addr)
+	}
+
+	// Warning: make sure to acquire these locks AFTER the call to Provider
+	// above, since it also acquires locks.
+	ctx.ProviderLock.Lock()
+	defer ctx.ProviderLock.Unlock()
+
+	key := addr.String()
+
+	p, err := ctx.Plugins.NewProviderInstance(addr.Provider)
+	if err != nil {
+		return nil, err
+	}
+
+	log.Printf("[TRACE] BuiltinEvalContext: Initialized %q provider for %s", addr.String(), addr)
+	ctx.ProviderCache[key] = p
+
+	return p, nil
+}
+
+func (ctx *BuiltinEvalContext) Provider(addr addrs.AbsProviderConfig) providers.Interface {
+	ctx.ProviderLock.Lock()
+	defer ctx.ProviderLock.Unlock()
+
+	return ctx.ProviderCache[addr.String()]
+}
+
+func (ctx *BuiltinEvalContext) ProviderSchema(addr addrs.AbsProviderConfig) (*ProviderSchema, error) {
+	return ctx.Plugins.ProviderSchema(addr.Provider)
+}
+
+func (ctx *BuiltinEvalContext) CloseProvider(addr addrs.AbsProviderConfig) error {
+	ctx.ProviderLock.Lock()
+	defer ctx.ProviderLock.Unlock()
+
+	key := addr.String()
+	provider := ctx.ProviderCache[key]
+	if provider != nil {
+		delete(ctx.ProviderCache, key)
+		return provider.Close()
+	}
+
+	return nil
+}
+
+func (ctx *BuiltinEvalContext) ConfigureProvider(addr addrs.AbsProviderConfig, cfg cty.Value) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+	if !addr.Module.Equal(ctx.Path().Module()) {
+		// This indicates incorrect use of ConfigureProvider: it should be used
+		// only from the module that the provider configuration belongs to.
+		panic(fmt.Sprintf("%s configured by wrong module %s", addr, ctx.Path()))
+	}
+
+	p := ctx.Provider(addr)
+	if p == nil {
+		diags = diags.Append(fmt.Errorf("%s not initialized", addr))
+		return diags
+	}
+
+	providerSchema, err := ctx.ProviderSchema(addr)
+	if err != nil {
+		diags = diags.Append(fmt.Errorf("failed to read schema for %s: %s", addr, err))
+		return diags
+	}
+	if providerSchema == nil {
+		diags = diags.Append(fmt.Errorf("schema for %s is not available", addr))
+		return diags
+	}
+
+	req := providers.ConfigureProviderRequest{
+		TerraformVersion: version.String(),
+		Config:           cfg,
+	}
+
+	resp := p.ConfigureProvider(req)
+	return resp.Diagnostics
+}
+
+func (ctx *BuiltinEvalContext) ProviderInput(pc addrs.AbsProviderConfig) map[string]cty.Value {
+	ctx.ProviderLock.Lock()
+	defer ctx.ProviderLock.Unlock()
+
+	if !pc.Module.Equal(ctx.Path().Module()) {
+		// This indicates incorrect use of InitProvider: it should be used
+		// only from the module that the provider configuration belongs to.
+		panic(fmt.Sprintf("%s initialized by wrong module %s", pc, ctx.Path()))
+	}
+
+	if !ctx.Path().IsRoot() {
+		// Only root module provider configurations can have input.
+		return nil
+	}
+
+	return ctx.ProviderInputConfig[pc.String()]
+}
+
+func (ctx *BuiltinEvalContext) SetProviderInput(pc addrs.AbsProviderConfig, c map[string]cty.Value) {
+	absProvider := pc
+	if !pc.Module.IsRoot() {
+		// Only root module provider configurations can have input.
+		log.Printf("[WARN] BuiltinEvalContext: attempt to SetProviderInput for non-root module")
+		return
+	}
+
+	// Save the configuration
+	ctx.ProviderLock.Lock()
+	ctx.ProviderInputConfig[absProvider.String()] = c
+	ctx.ProviderLock.Unlock()
+}
+
+func (ctx *BuiltinEvalContext) Provisioner(n string) (provisioners.Interface, error) {
+	ctx.ProvisionerLock.Lock()
+	defer ctx.ProvisionerLock.Unlock()
+
+	p, ok := ctx.ProvisionerCache[n]
+	if !ok {
+		var err error
+		p, err = ctx.Plugins.NewProvisionerInstance(n)
+		if err != nil {
+			return nil, err
+		}
+
+		ctx.ProvisionerCache[n] = p
+	}
+
+	return p, nil
+}
+
+func (ctx *BuiltinEvalContext) ProvisionerSchema(n string) (*configschema.Block, error) {
+	return ctx.Plugins.ProvisionerSchema(n)
+}
+
+func (ctx *BuiltinEvalContext) CloseProvisioners() error {
+	var diags tfdiags.Diagnostics
+	ctx.ProvisionerLock.Lock()
+	defer ctx.ProvisionerLock.Unlock()
+
+	for name, prov := range ctx.ProvisionerCache {
+		err := prov.Close()
+		if err != nil {
+			diags = diags.Append(fmt.Errorf("provisioner.Close %s: %s", name, err))
+		}
+	}
+
+	return diags.Err()
+}
+
+func (ctx *BuiltinEvalContext) EvaluateBlock(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, keyData InstanceKeyEvalData) (cty.Value, hcl.Body, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	scope := ctx.EvaluationScope(self, nil, keyData)
+	body, evalDiags := scope.ExpandBlock(body, schema)
+	diags = diags.Append(evalDiags)
+	val, evalDiags := scope.EvalBlock(body, schema)
+	diags = diags.Append(evalDiags)
+	return val, body, diags
+}
+
+func (ctx *BuiltinEvalContext) EvaluateExpr(expr hcl.Expression, wantType cty.Type, self addrs.Referenceable) (cty.Value, tfdiags.Diagnostics) {
+	scope := ctx.EvaluationScope(self, nil, EvalDataForNoInstanceKey)
+	return scope.EvalExpr(expr, wantType)
+}
+
+func (ctx *BuiltinEvalContext) EvaluateReplaceTriggeredBy(expr hcl.Expression, repData instances.RepetitionData) (*addrs.Reference, bool, tfdiags.Diagnostics) {
+
+	// get the reference to lookup changes in the plan
+	ref, diags := evalReplaceTriggeredByExpr(expr, repData)
+	if diags.HasErrors() {
+		return nil, false, diags
+	}
+
+	var changes []*plans.ResourceInstanceChangeSrc
+	// store the address once we get it for validation
+	var resourceAddr addrs.Resource
+
+	// The reference is either a resource or resource instance
+	switch sub := ref.Subject.(type) {
+	case addrs.Resource:
+		resourceAddr = sub
+		rc := sub.Absolute(ctx.Path())
+		changes = ctx.Changes().GetChangesForAbsResource(rc)
+	case addrs.ResourceInstance:
+		resourceAddr = sub.ContainingResource()
+		rc := sub.Absolute(ctx.Path())
+		change := ctx.Changes().GetResourceInstanceChange(rc, states.CurrentGen)
+		if change != nil {
+			// we'll generate an error below if there was no change
+			changes = append(changes, change)
+		}
+	}
+
+	// Do some validation to make sure we are expecting a change at all
+	cfg := ctx.Evaluator.Config.Descendent(ctx.Path().Module())
+	resCfg := cfg.Module.ResourceByAddr(resourceAddr)
+	if resCfg == nil {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Reference to undeclared resource`,
+			Detail:   fmt.Sprintf(`A resource %s has not been declared in %s`, ref.Subject, moduleDisplayAddr(ctx.Path())),
+			Subject:  expr.Range().Ptr(),
+		})
+		return nil, false, diags
+	}
+
+	if len(changes) == 0 {
+		// If the resource is valid there should always be at least one change.
+		diags = diags.Append(fmt.Errorf("no change found for %s in %s", ref.Subject, moduleDisplayAddr(ctx.Path())))
+		return nil, false, diags
+	}
+
+	// If we don't have a traversal beyond the resource, then we can just look
+	// for any change.
+	if len(ref.Remaining) == 0 {
+		for _, c := range changes {
+			switch c.ChangeSrc.Action {
+			// Only immediate changes to the resource will trigger replacement.
+			case plans.Update, plans.DeleteThenCreate, plans.CreateThenDelete:
+				return ref, true, diags
+			}
+		}
+
+		// no change triggered
+		return nil, false, diags
+	}
+
+	// This must be an instances to have a remaining traversal, which means a
+	// single change.
+	change := changes[0]
+
+	// Make sure the change is actionable. A create or delete action will have
+	// a change in value, but are not valid for our purposes here.
+	switch change.ChangeSrc.Action {
+	case plans.Update, plans.DeleteThenCreate, plans.CreateThenDelete:
+		// OK
+	default:
+		return nil, false, diags
+	}
+
+	// Since we have a traversal after the resource reference, we will need to
+	// decode the changes, which means we need a schema.
+	providerAddr := change.ProviderAddr
+	schema, err := ctx.ProviderSchema(providerAddr)
+	if err != nil {
+		diags = diags.Append(err)
+		return nil, false, diags
+	}
+
+	resAddr := change.Addr.ContainingResource().Resource
+	resSchema, _ := schema.SchemaForResourceType(resAddr.Mode, resAddr.Type)
+	ty := resSchema.ImpliedType()
+
+	before, err := change.ChangeSrc.Before.Decode(ty)
+	if err != nil {
+		diags = diags.Append(err)
+		return nil, false, diags
+	}
+
+	after, err := change.ChangeSrc.After.Decode(ty)
+	if err != nil {
+		diags = diags.Append(err)
+		return nil, false, diags
+	}
+
+	path := traversalToPath(ref.Remaining)
+	attrBefore, _ := path.Apply(before)
+	attrAfter, _ := path.Apply(after)
+
+	if attrBefore == cty.NilVal || attrAfter == cty.NilVal {
+		replace := attrBefore != attrAfter
+		return ref, replace, diags
+	}
+
+	replace := !attrBefore.RawEquals(attrAfter)
+
+	return ref, replace, diags
+}
+
+func (ctx *BuiltinEvalContext) EvaluationScope(self addrs.Referenceable, source addrs.Referenceable, keyData InstanceKeyEvalData) *lang.Scope {
+	if !ctx.pathSet {
+		panic("context path not set")
+	}
+	data := &evaluationStateData{
+		Evaluator:       ctx.Evaluator,
+		ModulePath:      ctx.PathValue,
+		InstanceKeyData: keyData,
+		Operation:       ctx.Evaluator.Operation,
+	}
+	scope := ctx.Evaluator.Scope(data, self, source)
+
+	// ctx.PathValue is the path of the module that contains whatever
+	// expression the caller will be trying to evaluate, so this will
+	// activate only the experiments from that particular module, to
+	// be consistent with how experiment checking in the "configs"
+	// package itself works. The nil check here is for robustness in
+	// incompletely-mocked testing situations; mc should never be nil in
+	// real situations.
+	if mc := ctx.Evaluator.Config.DescendentForInstance(ctx.PathValue); mc != nil {
+		scope.SetActiveExperiments(mc.Module.ActiveExperiments)
+	}
+	return scope
+}
+
+func (ctx *BuiltinEvalContext) Path() addrs.ModuleInstance {
+	if !ctx.pathSet {
+		panic("context path not set")
+	}
+	return ctx.PathValue
+}
+
+func (ctx *BuiltinEvalContext) SetRootModuleArgument(addr addrs.InputVariable, v cty.Value) {
+	ctx.VariableValuesLock.Lock()
+	defer ctx.VariableValuesLock.Unlock()
+
+	log.Printf("[TRACE] BuiltinEvalContext: Storing final value for variable %s", addr.Absolute(addrs.RootModuleInstance))
+	key := addrs.RootModuleInstance.String()
+	args := ctx.VariableValues[key]
+	if args == nil {
+		args = make(map[string]cty.Value)
+		ctx.VariableValues[key] = args
+	}
+	args[addr.Name] = v
+}
+
+func (ctx *BuiltinEvalContext) SetModuleCallArgument(callAddr addrs.ModuleCallInstance, varAddr addrs.InputVariable, v cty.Value) {
+	ctx.VariableValuesLock.Lock()
+	defer ctx.VariableValuesLock.Unlock()
+
+	if !ctx.pathSet {
+		panic("context path not set")
+	}
+
+	childPath := callAddr.ModuleInstance(ctx.PathValue)
+	log.Printf("[TRACE] BuiltinEvalContext: Storing final value for variable %s", varAddr.Absolute(childPath))
+	key := childPath.String()
+	args := ctx.VariableValues[key]
+	if args == nil {
+		args = make(map[string]cty.Value)
+		ctx.VariableValues[key] = args
+	}
+	args[varAddr.Name] = v
+}
+
+func (ctx *BuiltinEvalContext) GetVariableValue(addr addrs.AbsInputVariableInstance) cty.Value {
+	ctx.VariableValuesLock.Lock()
+	defer ctx.VariableValuesLock.Unlock()
+
+	modKey := addr.Module.String()
+	modVars := ctx.VariableValues[modKey]
+	val, ok := modVars[addr.Variable.Name]
+	if !ok {
+		return cty.DynamicVal
+	}
+	return val
+}
+
+func (ctx *BuiltinEvalContext) Changes() *plans.ChangesSync {
+	return ctx.ChangesValue
+}
+
+func (ctx *BuiltinEvalContext) State() *states.SyncState {
+	return ctx.StateValue
+}
+
+func (ctx *BuiltinEvalContext) Checks() *checks.State {
+	return ctx.ChecksValue
+}
+
+func (ctx *BuiltinEvalContext) RefreshState() *states.SyncState {
+	return ctx.RefreshStateValue
+}
+
+func (ctx *BuiltinEvalContext) PrevRunState() *states.SyncState {
+	return ctx.PrevRunStateValue
+}
+
+func (ctx *BuiltinEvalContext) InstanceExpander() *instances.Expander {
+	return ctx.InstanceExpanderValue
+}
+
+func (ctx *BuiltinEvalContext) MoveResults() refactoring.MoveResults {
+	return ctx.MoveResultsValue
+}
diff --git a/v1.5.7/internal/terraform/eval_context_builtin_test.go b/v1.5.7/internal/terraform/eval_context_builtin_test.go
new file mode 100644
index 0000000..999d44e
--- /dev/null
+++ b/v1.5.7/internal/terraform/eval_context_builtin_test.go
@@ -0,0 +1,91 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"reflect"
+	"sync"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestBuiltinEvalContextProviderInput(t *testing.T) {
+	var lock sync.Mutex
+	cache := make(map[string]map[string]cty.Value)
+
+	ctx1 := testBuiltinEvalContext(t)
+	ctx1 = ctx1.WithPath(addrs.RootModuleInstance).(*BuiltinEvalContext)
+	ctx1.ProviderInputConfig = cache
+	ctx1.ProviderLock = &lock
+
+	ctx2 := testBuiltinEvalContext(t)
+	ctx2 = ctx2.WithPath(addrs.RootModuleInstance.Child("child", addrs.NoKey)).(*BuiltinEvalContext)
+	ctx2.ProviderInputConfig = cache
+	ctx2.ProviderLock = &lock
+
+	providerAddr1 := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule,
+		Provider: addrs.NewDefaultProvider("foo"),
+	}
+	providerAddr2 := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule.Child("child"),
+		Provider: addrs.NewDefaultProvider("foo"),
+	}
+
+	expected1 := map[string]cty.Value{"value": cty.StringVal("foo")}
+	ctx1.SetProviderInput(providerAddr1, expected1)
+
+	try2 := map[string]cty.Value{"value": cty.StringVal("bar")}
+	ctx2.SetProviderInput(providerAddr2, try2) // ignored because not a root module
+
+	actual1 := ctx1.ProviderInput(providerAddr1)
+	actual2 := ctx2.ProviderInput(providerAddr2)
+
+	if !reflect.DeepEqual(actual1, expected1) {
+		t.Errorf("wrong result 1\ngot:  %#v\nwant: %#v", actual1, expected1)
+	}
+	if actual2 != nil {
+		t.Errorf("wrong result 2\ngot:  %#v\nwant: %#v", actual2, nil)
+	}
+}
+
+func TestBuildingEvalContextInitProvider(t *testing.T) {
+	var lock sync.Mutex
+
+	testP := &MockProvider{}
+
+	ctx := testBuiltinEvalContext(t)
+	ctx = ctx.WithPath(addrs.RootModuleInstance).(*BuiltinEvalContext)
+	ctx.ProviderLock = &lock
+	ctx.ProviderCache = make(map[string]providers.Interface)
+	ctx.Plugins = newContextPlugins(map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("test"): providers.FactoryFixed(testP),
+	}, nil)
+
+	providerAddrDefault := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule,
+		Provider: addrs.NewDefaultProvider("test"),
+	}
+	providerAddrAlias := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule,
+		Provider: addrs.NewDefaultProvider("test"),
+		Alias:    "foo",
+	}
+
+	_, err := ctx.InitProvider(providerAddrDefault)
+	if err != nil {
+		t.Fatalf("error initializing provider test: %s", err)
+	}
+	_, err = ctx.InitProvider(providerAddrAlias)
+	if err != nil {
+		t.Fatalf("error initializing provider test.foo: %s", err)
+	}
+}
+
+func testBuiltinEvalContext(t *testing.T) *BuiltinEvalContext {
+	return &BuiltinEvalContext{}
+}
diff --git a/v1.5.7/internal/terraform/eval_context_mock.go b/v1.5.7/internal/terraform/eval_context_mock.go
new file mode 100644
index 0000000..30af84d
--- /dev/null
+++ b/v1.5.7/internal/terraform/eval_context_mock.go
@@ -0,0 +1,404 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcldec"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/refactoring"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/convert"
+)
+
+// MockEvalContext is a mock version of EvalContext that can be used
+// for tests.
+type MockEvalContext struct {
+	StoppedCalled bool
+	StoppedValue  <-chan struct{}
+
+	HookCalled bool
+	HookHook   Hook
+	HookError  error
+
+	InputCalled bool
+	InputInput  UIInput
+
+	InitProviderCalled   bool
+	InitProviderType     string
+	InitProviderAddr     addrs.AbsProviderConfig
+	InitProviderProvider providers.Interface
+	InitProviderError    error
+
+	ProviderCalled   bool
+	ProviderAddr     addrs.AbsProviderConfig
+	ProviderProvider providers.Interface
+
+	ProviderSchemaCalled bool
+	ProviderSchemaAddr   addrs.AbsProviderConfig
+	ProviderSchemaSchema *ProviderSchema
+	ProviderSchemaError  error
+
+	CloseProviderCalled   bool
+	CloseProviderAddr     addrs.AbsProviderConfig
+	CloseProviderProvider providers.Interface
+
+	ProviderInputCalled bool
+	ProviderInputAddr   addrs.AbsProviderConfig
+	ProviderInputValues map[string]cty.Value
+
+	SetProviderInputCalled bool
+	SetProviderInputAddr   addrs.AbsProviderConfig
+	SetProviderInputValues map[string]cty.Value
+
+	ConfigureProviderFn func(
+		addr addrs.AbsProviderConfig,
+		cfg cty.Value) tfdiags.Diagnostics // overrides the other values below, if set
+	ConfigureProviderCalled bool
+	ConfigureProviderAddr   addrs.AbsProviderConfig
+	ConfigureProviderConfig cty.Value
+	ConfigureProviderDiags  tfdiags.Diagnostics
+
+	ProvisionerCalled      bool
+	ProvisionerName        string
+	ProvisionerProvisioner provisioners.Interface
+
+	ProvisionerSchemaCalled bool
+	ProvisionerSchemaName   string
+	ProvisionerSchemaSchema *configschema.Block
+	ProvisionerSchemaError  error
+
+	CloseProvisionersCalled bool
+
+	EvaluateBlockCalled     bool
+	EvaluateBlockBody       hcl.Body
+	EvaluateBlockSchema     *configschema.Block
+	EvaluateBlockSelf       addrs.Referenceable
+	EvaluateBlockKeyData    InstanceKeyEvalData
+	EvaluateBlockResultFunc func(
+		body hcl.Body,
+		schema *configschema.Block,
+		self addrs.Referenceable,
+		keyData InstanceKeyEvalData,
+	) (cty.Value, hcl.Body, tfdiags.Diagnostics) // overrides the other values below, if set
+	EvaluateBlockResult       cty.Value
+	EvaluateBlockExpandedBody hcl.Body
+	EvaluateBlockDiags        tfdiags.Diagnostics
+
+	EvaluateExprCalled     bool
+	EvaluateExprExpr       hcl.Expression
+	EvaluateExprWantType   cty.Type
+	EvaluateExprSelf       addrs.Referenceable
+	EvaluateExprResultFunc func(
+		expr hcl.Expression,
+		wantType cty.Type,
+		self addrs.Referenceable,
+	) (cty.Value, tfdiags.Diagnostics) // overrides the other values below, if set
+	EvaluateExprResult cty.Value
+	EvaluateExprDiags  tfdiags.Diagnostics
+
+	EvaluationScopeCalled  bool
+	EvaluationScopeSelf    addrs.Referenceable
+	EvaluationScopeKeyData InstanceKeyEvalData
+	EvaluationScopeScope   *lang.Scope
+
+	PathCalled bool
+	PathPath   addrs.ModuleInstance
+
+	SetRootModuleArgumentCalled bool
+	SetRootModuleArgumentAddr   addrs.InputVariable
+	SetRootModuleArgumentValue  cty.Value
+	SetRootModuleArgumentFunc   func(addr addrs.InputVariable, v cty.Value)
+
+	SetModuleCallArgumentCalled     bool
+	SetModuleCallArgumentModuleCall addrs.ModuleCallInstance
+	SetModuleCallArgumentVariable   addrs.InputVariable
+	SetModuleCallArgumentValue      cty.Value
+	SetModuleCallArgumentFunc       func(callAddr addrs.ModuleCallInstance, varAddr addrs.InputVariable, v cty.Value)
+
+	GetVariableValueCalled bool
+	GetVariableValueAddr   addrs.AbsInputVariableInstance
+	GetVariableValueValue  cty.Value
+	GetVariableValueFunc   func(addr addrs.AbsInputVariableInstance) cty.Value // supersedes GetVariableValueValue
+
+	ChangesCalled  bool
+	ChangesChanges *plans.ChangesSync
+
+	StateCalled bool
+	StateState  *states.SyncState
+
+	ChecksCalled bool
+	ChecksState  *checks.State
+
+	RefreshStateCalled bool
+	RefreshStateState  *states.SyncState
+
+	PrevRunStateCalled bool
+	PrevRunStateState  *states.SyncState
+
+	MoveResultsCalled  bool
+	MoveResultsResults refactoring.MoveResults
+
+	InstanceExpanderCalled   bool
+	InstanceExpanderExpander *instances.Expander
+}
+
+// MockEvalContext implements EvalContext
+var _ EvalContext = (*MockEvalContext)(nil)
+
+func (c *MockEvalContext) Stopped() <-chan struct{} {
+	c.StoppedCalled = true
+	return c.StoppedValue
+}
+
+func (c *MockEvalContext) Hook(fn func(Hook) (HookAction, error)) error {
+	c.HookCalled = true
+	if c.HookHook != nil {
+		if _, err := fn(c.HookHook); err != nil {
+			return err
+		}
+	}
+
+	return c.HookError
+}
+
+func (c *MockEvalContext) Input() UIInput {
+	c.InputCalled = true
+	return c.InputInput
+}
+
+func (c *MockEvalContext) InitProvider(addr addrs.AbsProviderConfig) (providers.Interface, error) {
+	c.InitProviderCalled = true
+	c.InitProviderType = addr.String()
+	c.InitProviderAddr = addr
+	return c.InitProviderProvider, c.InitProviderError
+}
+
+func (c *MockEvalContext) Provider(addr addrs.AbsProviderConfig) providers.Interface {
+	c.ProviderCalled = true
+	c.ProviderAddr = addr
+	return c.ProviderProvider
+}
+
+func (c *MockEvalContext) ProviderSchema(addr addrs.AbsProviderConfig) (*ProviderSchema, error) {
+	c.ProviderSchemaCalled = true
+	c.ProviderSchemaAddr = addr
+	return c.ProviderSchemaSchema, c.ProviderSchemaError
+}
+
+func (c *MockEvalContext) CloseProvider(addr addrs.AbsProviderConfig) error {
+	c.CloseProviderCalled = true
+	c.CloseProviderAddr = addr
+	return nil
+}
+
+func (c *MockEvalContext) ConfigureProvider(addr addrs.AbsProviderConfig, cfg cty.Value) tfdiags.Diagnostics {
+
+	c.ConfigureProviderCalled = true
+	c.ConfigureProviderAddr = addr
+	c.ConfigureProviderConfig = cfg
+	if c.ConfigureProviderFn != nil {
+		return c.ConfigureProviderFn(addr, cfg)
+	}
+	return c.ConfigureProviderDiags
+}
+
+func (c *MockEvalContext) ProviderInput(addr addrs.AbsProviderConfig) map[string]cty.Value {
+	c.ProviderInputCalled = true
+	c.ProviderInputAddr = addr
+	return c.ProviderInputValues
+}
+
+func (c *MockEvalContext) SetProviderInput(addr addrs.AbsProviderConfig, vals map[string]cty.Value) {
+	c.SetProviderInputCalled = true
+	c.SetProviderInputAddr = addr
+	c.SetProviderInputValues = vals
+}
+
+func (c *MockEvalContext) Provisioner(n string) (provisioners.Interface, error) {
+	c.ProvisionerCalled = true
+	c.ProvisionerName = n
+	return c.ProvisionerProvisioner, nil
+}
+
+func (c *MockEvalContext) ProvisionerSchema(n string) (*configschema.Block, error) {
+	c.ProvisionerSchemaCalled = true
+	c.ProvisionerSchemaName = n
+	return c.ProvisionerSchemaSchema, c.ProvisionerSchemaError
+}
+
+func (c *MockEvalContext) CloseProvisioners() error {
+	c.CloseProvisionersCalled = true
+	return nil
+}
+
+func (c *MockEvalContext) EvaluateBlock(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, keyData InstanceKeyEvalData) (cty.Value, hcl.Body, tfdiags.Diagnostics) {
+	c.EvaluateBlockCalled = true
+	c.EvaluateBlockBody = body
+	c.EvaluateBlockSchema = schema
+	c.EvaluateBlockSelf = self
+	c.EvaluateBlockKeyData = keyData
+	if c.EvaluateBlockResultFunc != nil {
+		return c.EvaluateBlockResultFunc(body, schema, self, keyData)
+	}
+	return c.EvaluateBlockResult, c.EvaluateBlockExpandedBody, c.EvaluateBlockDiags
+}
+
+func (c *MockEvalContext) EvaluateExpr(expr hcl.Expression, wantType cty.Type, self addrs.Referenceable) (cty.Value, tfdiags.Diagnostics) {
+	c.EvaluateExprCalled = true
+	c.EvaluateExprExpr = expr
+	c.EvaluateExprWantType = wantType
+	c.EvaluateExprSelf = self
+	if c.EvaluateExprResultFunc != nil {
+		return c.EvaluateExprResultFunc(expr, wantType, self)
+	}
+	return c.EvaluateExprResult, c.EvaluateExprDiags
+}
+
+func (c *MockEvalContext) EvaluateReplaceTriggeredBy(hcl.Expression, instances.RepetitionData) (*addrs.Reference, bool, tfdiags.Diagnostics) {
+	return nil, false, nil
+}
+
+// installSimpleEval is a helper to install a simple mock implementation of
+// both EvaluateBlock and EvaluateExpr into the receiver.
+//
+// These default implementations will either evaluate the given input against
+// the scope in field EvaluationScopeScope or, if it is nil, with no eval
+// context at all so that only constant values may be used.
+//
+// This function overwrites any existing functions installed in fields
+// EvaluateBlockResultFunc and EvaluateExprResultFunc.
+func (c *MockEvalContext) installSimpleEval() {
+	c.EvaluateBlockResultFunc = func(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, keyData InstanceKeyEvalData) (cty.Value, hcl.Body, tfdiags.Diagnostics) {
+		if scope := c.EvaluationScopeScope; scope != nil {
+			// Fully-functional codepath.
+			var diags tfdiags.Diagnostics
+			body, diags = scope.ExpandBlock(body, schema)
+			if diags.HasErrors() {
+				return cty.DynamicVal, body, diags
+			}
+			val, evalDiags := c.EvaluationScopeScope.EvalBlock(body, schema)
+			diags = diags.Append(evalDiags)
+			if evalDiags.HasErrors() {
+				return cty.DynamicVal, body, diags
+			}
+			return val, body, diags
+		}
+
+		// Fallback codepath supporting constant values only.
+		val, hclDiags := hcldec.Decode(body, schema.DecoderSpec(), nil)
+		return val, body, tfdiags.Diagnostics(nil).Append(hclDiags)
+	}
+	c.EvaluateExprResultFunc = func(expr hcl.Expression, wantType cty.Type, self addrs.Referenceable) (cty.Value, tfdiags.Diagnostics) {
+		if scope := c.EvaluationScopeScope; scope != nil {
+			// Fully-functional codepath.
+			return scope.EvalExpr(expr, wantType)
+		}
+
+		// Fallback codepath supporting constant values only.
+		var diags tfdiags.Diagnostics
+		val, hclDiags := expr.Value(nil)
+		diags = diags.Append(hclDiags)
+		if hclDiags.HasErrors() {
+			return cty.DynamicVal, diags
+		}
+		var err error
+		val, err = convert.Convert(val, wantType)
+		if err != nil {
+			diags = diags.Append(err)
+			return cty.DynamicVal, diags
+		}
+		return val, diags
+	}
+}
+
+func (c *MockEvalContext) EvaluationScope(self addrs.Referenceable, source addrs.Referenceable, keyData InstanceKeyEvalData) *lang.Scope {
+	c.EvaluationScopeCalled = true
+	c.EvaluationScopeSelf = self
+	c.EvaluationScopeKeyData = keyData
+	return c.EvaluationScopeScope
+}
+
+func (c *MockEvalContext) WithPath(path addrs.ModuleInstance) EvalContext {
+	newC := *c
+	newC.PathPath = path
+	return &newC
+}
+
+func (c *MockEvalContext) Path() addrs.ModuleInstance {
+	c.PathCalled = true
+	return c.PathPath
+}
+
+func (c *MockEvalContext) SetRootModuleArgument(addr addrs.InputVariable, v cty.Value) {
+	c.SetRootModuleArgumentCalled = true
+	c.SetRootModuleArgumentAddr = addr
+	c.SetRootModuleArgumentValue = v
+	if c.SetRootModuleArgumentFunc != nil {
+		c.SetRootModuleArgumentFunc(addr, v)
+	}
+}
+
+func (c *MockEvalContext) SetModuleCallArgument(callAddr addrs.ModuleCallInstance, varAddr addrs.InputVariable, v cty.Value) {
+	c.SetModuleCallArgumentCalled = true
+	c.SetModuleCallArgumentModuleCall = callAddr
+	c.SetModuleCallArgumentVariable = varAddr
+	c.SetModuleCallArgumentValue = v
+	if c.SetModuleCallArgumentFunc != nil {
+		c.SetModuleCallArgumentFunc(callAddr, varAddr, v)
+	}
+}
+
+func (c *MockEvalContext) GetVariableValue(addr addrs.AbsInputVariableInstance) cty.Value {
+	c.GetVariableValueCalled = true
+	c.GetVariableValueAddr = addr
+	if c.GetVariableValueFunc != nil {
+		return c.GetVariableValueFunc(addr)
+	}
+	return c.GetVariableValueValue
+}
+
+func (c *MockEvalContext) Changes() *plans.ChangesSync {
+	c.ChangesCalled = true
+	return c.ChangesChanges
+}
+
+func (c *MockEvalContext) State() *states.SyncState {
+	c.StateCalled = true
+	return c.StateState
+}
+
+func (c *MockEvalContext) Checks() *checks.State {
+	c.ChecksCalled = true
+	return c.ChecksState
+}
+
+func (c *MockEvalContext) RefreshState() *states.SyncState {
+	c.RefreshStateCalled = true
+	return c.RefreshStateState
+}
+
+func (c *MockEvalContext) PrevRunState() *states.SyncState {
+	c.PrevRunStateCalled = true
+	return c.PrevRunStateState
+}
+
+func (c *MockEvalContext) MoveResults() refactoring.MoveResults {
+	c.MoveResultsCalled = true
+	return c.MoveResultsResults
+}
+
+func (c *MockEvalContext) InstanceExpander() *instances.Expander {
+	c.InstanceExpanderCalled = true
+	return c.InstanceExpanderExpander
+}
diff --git a/v1.5.7/internal/terraform/eval_count.go b/v1.5.7/internal/terraform/eval_count.go
new file mode 100644
index 0000000..3588f92
--- /dev/null
+++ b/v1.5.7/internal/terraform/eval_count.go
@@ -0,0 +1,110 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/gocty"
+)
+
+// evaluateCountExpression is our standard mechanism for interpreting an
+// expression given for a "count" argument on a resource or a module. This
+// should be called during expansion in order to determine the final count
+// value.
+//
+// evaluateCountExpression differs from evaluateCountExpressionValue by
+// returning an error if the count value is not known, and converting the
+// cty.Value to an integer.
+func evaluateCountExpression(expr hcl.Expression, ctx EvalContext) (int, tfdiags.Diagnostics) {
+	countVal, diags := evaluateCountExpressionValue(expr, ctx)
+	if !countVal.IsKnown() {
+		// Currently this is a rather bad outcome from a UX standpoint, since we have
+		// no real mechanism to deal with this situation and all we can do is produce
+		// an error message.
+		// FIXME: In future, implement a built-in mechanism for deferring changes that
+		// can't yet be predicted, and use it to guide the user through several
+		// plan/apply steps until the desired configuration is eventually reached.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid count argument",
+			Detail:   `The "count" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created. To work around this, use the -target argument to first apply only the resources that the count depends on.`,
+			Subject:  expr.Range().Ptr(),
+
+			// TODO: Also populate Expression and EvalContext in here, but
+			// we can't easily do that right now because the hcl.EvalContext
+			// (which is not the same as the ctx we have in scope here) is
+			// hidden away inside evaluateCountExpressionValue.
+			Extra: diagnosticCausedByUnknown(true),
+		})
+	}
+
+	if countVal.IsNull() || !countVal.IsKnown() {
+		return -1, diags
+	}
+
+	count, _ := countVal.AsBigFloat().Int64()
+	return int(count), diags
+}
+
+// evaluateCountExpressionValue is like evaluateCountExpression
+// except that it returns a cty.Value which must be a cty.Number and can be
+// unknown.
+func evaluateCountExpressionValue(expr hcl.Expression, ctx EvalContext) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	nullCount := cty.NullVal(cty.Number)
+	if expr == nil {
+		return nullCount, nil
+	}
+
+	countVal, countDiags := ctx.EvaluateExpr(expr, cty.Number, nil)
+	diags = diags.Append(countDiags)
+	if diags.HasErrors() {
+		return nullCount, diags
+	}
+
+	// Unmark the count value, sensitive values are allowed in count but not for_each,
+	// as using it here will not disclose the sensitive value
+	countVal, _ = countVal.Unmark()
+
+	switch {
+	case countVal.IsNull():
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid count argument",
+			Detail:   `The given "count" argument value is null. An integer is required.`,
+			Subject:  expr.Range().Ptr(),
+		})
+		return nullCount, diags
+
+	case !countVal.IsKnown():
+		return cty.UnknownVal(cty.Number), diags
+	}
+
+	var count int
+	err := gocty.FromCtyValue(countVal, &count)
+	if err != nil {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid count argument",
+			Detail:   fmt.Sprintf(`The given "count" argument value is unsuitable: %s.`, err),
+			Subject:  expr.Range().Ptr(),
+		})
+		return nullCount, diags
+	}
+	if count < 0 {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid count argument",
+			Detail:   `The given "count" argument value is unsuitable: must be greater than or equal to zero.`,
+			Subject:  expr.Range().Ptr(),
+		})
+		return nullCount, diags
+	}
+
+	return countVal, diags
+}
diff --git a/v1.5.7/internal/terraform/eval_count_test.go b/v1.5.7/internal/terraform/eval_count_test.go
new file mode 100644
index 0000000..80bb3d6
--- /dev/null
+++ b/v1.5.7/internal/terraform/eval_count_test.go
@@ -0,0 +1,49 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcltest"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestEvaluateCountExpression(t *testing.T) {
+	tests := map[string]struct {
+		Expr  hcl.Expression
+		Count int
+	}{
+		"zero": {
+			hcltest.MockExprLiteral(cty.NumberIntVal(0)),
+			0,
+		},
+		"expression with marked value": {
+			hcltest.MockExprLiteral(cty.NumberIntVal(8).Mark(marks.Sensitive)),
+			8,
+		},
+	}
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			ctx := &MockEvalContext{}
+			ctx.installSimpleEval()
+			countVal, diags := evaluateCountExpression(test.Expr, ctx)
+
+			if len(diags) != 0 {
+				t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
+			}
+
+			if !reflect.DeepEqual(countVal, test.Count) {
+				t.Errorf(
+					"wrong map value\ngot:  %swant: %s",
+					spew.Sdump(countVal), spew.Sdump(test.Count),
+				)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/terraform/eval_for_each.go b/v1.5.7/internal/terraform/eval_for_each.go
new file mode 100644
index 0000000..5905f2b
--- /dev/null
+++ b/v1.5.7/internal/terraform/eval_for_each.go
@@ -0,0 +1,196 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// evaluateForEachExpression is our standard mechanism for interpreting an
+// expression given for a "for_each" argument on a resource or a module. This
+// should be called during expansion in order to determine the final keys and
+// values.
+//
+// evaluateForEachExpression differs from evaluateForEachExpressionValue by
+// returning an error if the count value is not known, and converting the
+// cty.Value to a map[string]cty.Value for compatibility with other calls.
+func evaluateForEachExpression(expr hcl.Expression, ctx EvalContext) (forEach map[string]cty.Value, diags tfdiags.Diagnostics) {
+	forEachVal, diags := evaluateForEachExpressionValue(expr, ctx, false)
+	// forEachVal might be unknown, but if it is then there should already
+	// be an error about it in diags, which we'll return below.
+
+	if forEachVal.IsNull() || !forEachVal.IsKnown() || markSafeLengthInt(forEachVal) == 0 {
+		// we check length, because an empty set return a nil map
+		return map[string]cty.Value{}, diags
+	}
+
+	return forEachVal.AsValueMap(), diags
+}
+
+// evaluateForEachExpressionValue is like evaluateForEachExpression
+// except that it returns a cty.Value map or set which can be unknown.
+func evaluateForEachExpressionValue(expr hcl.Expression, ctx EvalContext, allowUnknown bool) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	nullMap := cty.NullVal(cty.Map(cty.DynamicPseudoType))
+
+	if expr == nil {
+		return nullMap, diags
+	}
+
+	refs, moreDiags := lang.ReferencesInExpr(expr)
+	diags = diags.Append(moreDiags)
+	scope := ctx.EvaluationScope(nil, nil, EvalDataForNoInstanceKey)
+	var hclCtx *hcl.EvalContext
+	if scope != nil {
+		hclCtx, moreDiags = scope.EvalContext(refs)
+	} else {
+		// This shouldn't happen in real code, but it can unfortunately arise
+		// in unit tests due to incompletely-implemented mocks. :(
+		hclCtx = &hcl.EvalContext{}
+	}
+	diags = diags.Append(moreDiags)
+	if diags.HasErrors() { // Can't continue if we don't even have a valid scope
+		return nullMap, diags
+	}
+
+	forEachVal, forEachDiags := expr.Value(hclCtx)
+	diags = diags.Append(forEachDiags)
+
+	// If a whole map is marked, or a set contains marked values (which means the set is then marked)
+	// give an error diagnostic as this value cannot be used in for_each
+	if forEachVal.HasMark(marks.Sensitive) {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity:    hcl.DiagError,
+			Summary:     "Invalid for_each argument",
+			Detail:      "Sensitive values, or values derived from sensitive values, cannot be used as for_each arguments. If used, the sensitive value could be exposed as a resource instance key.",
+			Subject:     expr.Range().Ptr(),
+			Expression:  expr,
+			EvalContext: hclCtx,
+			Extra:       diagnosticCausedBySensitive(true),
+		})
+	}
+
+	if diags.HasErrors() {
+		return nullMap, diags
+	}
+	ty := forEachVal.Type()
+
+	const errInvalidUnknownDetailMap = "The \"for_each\" map includes keys derived from resource attributes that cannot be determined until apply, and so Terraform cannot determine the full set of keys that will identify the instances of this resource.\n\nWhen working with unknown values in for_each, it's better to define the map keys statically in your configuration and place apply-time results only in the map values.\n\nAlternatively, you could use the -target planning option to first apply only the resources that the for_each value depends on, and then apply a second time to fully converge."
+	const errInvalidUnknownDetailSet = "The \"for_each\" set includes values derived from resource attributes that cannot be determined until apply, and so Terraform cannot determine the full set of keys that will identify the instances of this resource.\n\nWhen working with unknown values in for_each, it's better to use a map value where the keys are defined statically in your configuration and where only the values contain apply-time results.\n\nAlternatively, you could use the -target planning option to first apply only the resources that the for_each value depends on, and then apply a second time to fully converge."
+
+	switch {
+	case forEachVal.IsNull():
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity:    hcl.DiagError,
+			Summary:     "Invalid for_each argument",
+			Detail:      `The given "for_each" argument value is unsuitable: the given "for_each" argument value is null. A map, or set of strings is allowed.`,
+			Subject:     expr.Range().Ptr(),
+			Expression:  expr,
+			EvalContext: hclCtx,
+		})
+		return nullMap, diags
+	case !forEachVal.IsKnown():
+		if !allowUnknown {
+			var detailMsg string
+			switch {
+			case ty.IsSetType():
+				detailMsg = errInvalidUnknownDetailSet
+			default:
+				detailMsg = errInvalidUnknownDetailMap
+			}
+
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity:    hcl.DiagError,
+				Summary:     "Invalid for_each argument",
+				Detail:      detailMsg,
+				Subject:     expr.Range().Ptr(),
+				Expression:  expr,
+				EvalContext: hclCtx,
+				Extra:       diagnosticCausedByUnknown(true),
+			})
+		}
+		// ensure that we have a map, and not a DynamicValue
+		return cty.UnknownVal(cty.Map(cty.DynamicPseudoType)), diags
+
+	case !(ty.IsMapType() || ty.IsSetType() || ty.IsObjectType()):
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity:    hcl.DiagError,
+			Summary:     "Invalid for_each argument",
+			Detail:      fmt.Sprintf(`The given "for_each" argument value is unsuitable: the "for_each" argument must be a map, or set of strings, and you have provided a value of type %s.`, ty.FriendlyName()),
+			Subject:     expr.Range().Ptr(),
+			Expression:  expr,
+			EvalContext: hclCtx,
+		})
+		return nullMap, diags
+
+	case markSafeLengthInt(forEachVal) == 0:
+		// If the map is empty ({}), return an empty map, because cty will
+		// return nil when representing {} AsValueMap. This also covers an empty
+		// set (toset([]))
+		return forEachVal, diags
+	}
+
+	if ty.IsSetType() {
+		// since we can't use a set values that are unknown, we treat the
+		// entire set as unknown
+		if !forEachVal.IsWhollyKnown() {
+			if !allowUnknown {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity:    hcl.DiagError,
+					Summary:     "Invalid for_each argument",
+					Detail:      errInvalidUnknownDetailSet,
+					Subject:     expr.Range().Ptr(),
+					Expression:  expr,
+					EvalContext: hclCtx,
+					Extra:       diagnosticCausedByUnknown(true),
+				})
+			}
+			return cty.UnknownVal(ty), diags
+		}
+
+		if ty.ElementType() != cty.String {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity:    hcl.DiagError,
+				Summary:     "Invalid for_each set argument",
+				Detail:      fmt.Sprintf(`The given "for_each" argument value is unsuitable: "for_each" supports maps and sets of strings, but you have provided a set containing type %s.`, forEachVal.Type().ElementType().FriendlyName()),
+				Subject:     expr.Range().Ptr(),
+				Expression:  expr,
+				EvalContext: hclCtx,
+			})
+			return cty.NullVal(ty), diags
+		}
+
+		// A set of strings may contain null, which makes it impossible to
+		// convert to a map, so we must return an error
+		it := forEachVal.ElementIterator()
+		for it.Next() {
+			item, _ := it.Element()
+			if item.IsNull() {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity:    hcl.DiagError,
+					Summary:     "Invalid for_each set argument",
+					Detail:      `The given "for_each" argument value is unsuitable: "for_each" sets must not contain null values.`,
+					Subject:     expr.Range().Ptr(),
+					Expression:  expr,
+					EvalContext: hclCtx,
+				})
+				return cty.NullVal(ty), diags
+			}
+		}
+	}
+
+	return forEachVal, nil
+}
+
+// markSafeLengthInt allows calling LengthInt on marked values safely
+func markSafeLengthInt(val cty.Value) int {
+	v, _ := val.UnmarkDeep()
+	return v.LengthInt()
+}
diff --git a/v1.5.7/internal/terraform/eval_for_each_test.go b/v1.5.7/internal/terraform/eval_for_each_test.go
new file mode 100644
index 0000000..f01b9c2
--- /dev/null
+++ b/v1.5.7/internal/terraform/eval_for_each_test.go
@@ -0,0 +1,235 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"reflect"
+	"strings"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcltest"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestEvaluateForEachExpression_valid(t *testing.T) {
+	tests := map[string]struct {
+		Expr       hcl.Expression
+		ForEachMap map[string]cty.Value
+	}{
+		"empty set": {
+			hcltest.MockExprLiteral(cty.SetValEmpty(cty.String)),
+			map[string]cty.Value{},
+		},
+		"multi-value string set": {
+			hcltest.MockExprLiteral(cty.SetVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b")})),
+			map[string]cty.Value{
+				"a": cty.StringVal("a"),
+				"b": cty.StringVal("b"),
+			},
+		},
+		"empty map": {
+			hcltest.MockExprLiteral(cty.MapValEmpty(cty.Bool)),
+			map[string]cty.Value{},
+		},
+		"map": {
+			hcltest.MockExprLiteral(cty.MapVal(map[string]cty.Value{
+				"a": cty.BoolVal(true),
+				"b": cty.BoolVal(false),
+			})),
+			map[string]cty.Value{
+				"a": cty.BoolVal(true),
+				"b": cty.BoolVal(false),
+			},
+		},
+		"map containing unknown values": {
+			hcltest.MockExprLiteral(cty.MapVal(map[string]cty.Value{
+				"a": cty.UnknownVal(cty.Bool),
+				"b": cty.UnknownVal(cty.Bool),
+			})),
+			map[string]cty.Value{
+				"a": cty.UnknownVal(cty.Bool),
+				"b": cty.UnknownVal(cty.Bool),
+			},
+		},
+		"map containing sensitive values, but strings are literal": {
+			hcltest.MockExprLiteral(cty.MapVal(map[string]cty.Value{
+				"a": cty.BoolVal(true).Mark(marks.Sensitive),
+				"b": cty.BoolVal(false),
+			})),
+			map[string]cty.Value{
+				"a": cty.BoolVal(true).Mark(marks.Sensitive),
+				"b": cty.BoolVal(false),
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			ctx := &MockEvalContext{}
+			ctx.installSimpleEval()
+			forEachMap, diags := evaluateForEachExpression(test.Expr, ctx)
+
+			if len(diags) != 0 {
+				t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
+			}
+
+			if !reflect.DeepEqual(forEachMap, test.ForEachMap) {
+				t.Errorf(
+					"wrong map value\ngot:  %swant: %s",
+					spew.Sdump(forEachMap), spew.Sdump(test.ForEachMap),
+				)
+			}
+
+		})
+	}
+}
+
+func TestEvaluateForEachExpression_errors(t *testing.T) {
+	tests := map[string]struct {
+		Expr                               hcl.Expression
+		Summary, DetailSubstring           string
+		CausedByUnknown, CausedBySensitive bool
+	}{
+		"null set": {
+			hcltest.MockExprLiteral(cty.NullVal(cty.Set(cty.String))),
+			"Invalid for_each argument",
+			`the given "for_each" argument value is null`,
+			false, false,
+		},
+		"string": {
+			hcltest.MockExprLiteral(cty.StringVal("i am definitely a set")),
+			"Invalid for_each argument",
+			"must be a map, or set of strings, and you have provided a value of type string",
+			false, false,
+		},
+		"list": {
+			hcltest.MockExprLiteral(cty.ListVal([]cty.Value{cty.StringVal("a"), cty.StringVal("a")})),
+			"Invalid for_each argument",
+			"must be a map, or set of strings, and you have provided a value of type list",
+			false, false,
+		},
+		"tuple": {
+			hcltest.MockExprLiteral(cty.TupleVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b")})),
+			"Invalid for_each argument",
+			"must be a map, or set of strings, and you have provided a value of type tuple",
+			false, false,
+		},
+		"unknown string set": {
+			hcltest.MockExprLiteral(cty.UnknownVal(cty.Set(cty.String))),
+			"Invalid for_each argument",
+			"set includes values derived from resource attributes that cannot be determined until apply",
+			true, false,
+		},
+		"unknown map": {
+			hcltest.MockExprLiteral(cty.UnknownVal(cty.Map(cty.Bool))),
+			"Invalid for_each argument",
+			"map includes keys derived from resource attributes that cannot be determined until apply",
+			true, false,
+		},
+		"marked map": {
+			hcltest.MockExprLiteral(cty.MapVal(map[string]cty.Value{
+				"a": cty.BoolVal(true),
+				"b": cty.BoolVal(false),
+			}).Mark(marks.Sensitive)),
+			"Invalid for_each argument",
+			"Sensitive values, or values derived from sensitive values, cannot be used as for_each arguments. If used, the sensitive value could be exposed as a resource instance key.",
+			false, true,
+		},
+		"set containing booleans": {
+			hcltest.MockExprLiteral(cty.SetVal([]cty.Value{cty.BoolVal(true)})),
+			"Invalid for_each set argument",
+			"supports maps and sets of strings, but you have provided a set containing type bool",
+			false, false,
+		},
+		"set containing null": {
+			hcltest.MockExprLiteral(cty.SetVal([]cty.Value{cty.NullVal(cty.String)})),
+			"Invalid for_each set argument",
+			"must not contain null values",
+			false, false,
+		},
+		"set containing unknown value": {
+			hcltest.MockExprLiteral(cty.SetVal([]cty.Value{cty.UnknownVal(cty.String)})),
+			"Invalid for_each argument",
+			"set includes values derived from resource attributes that cannot be determined until apply",
+			true, false,
+		},
+		"set containing dynamic unknown value": {
+			hcltest.MockExprLiteral(cty.SetVal([]cty.Value{cty.UnknownVal(cty.DynamicPseudoType)})),
+			"Invalid for_each argument",
+			"set includes values derived from resource attributes that cannot be determined until apply",
+			true, false,
+		},
+		"set containing marked values": {
+			hcltest.MockExprLiteral(cty.SetVal([]cty.Value{cty.StringVal("beep").Mark(marks.Sensitive), cty.StringVal("boop")})),
+			"Invalid for_each argument",
+			"Sensitive values, or values derived from sensitive values, cannot be used as for_each arguments. If used, the sensitive value could be exposed as a resource instance key.",
+			false, true,
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			ctx := &MockEvalContext{}
+			ctx.installSimpleEval()
+			_, diags := evaluateForEachExpression(test.Expr, ctx)
+
+			if len(diags) != 1 {
+				t.Fatalf("got %d diagnostics; want 1", diags)
+			}
+			if got, want := diags[0].Severity(), tfdiags.Error; got != want {
+				t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
+			}
+			if got, want := diags[0].Description().Summary, test.Summary; got != want {
+				t.Errorf("wrong diagnostic summary\ngot:  %s\nwant: %s", got, want)
+			}
+			if got, want := diags[0].Description().Detail, test.DetailSubstring; !strings.Contains(got, want) {
+				t.Errorf("wrong diagnostic detail\ngot: %s\nwant substring: %s", got, want)
+			}
+			if fromExpr := diags[0].FromExpr(); fromExpr != nil {
+				if fromExpr.Expression == nil {
+					t.Errorf("diagnostic does not refer to an expression")
+				}
+				if fromExpr.EvalContext == nil {
+					t.Errorf("diagnostic does not refer to an EvalContext")
+				}
+			} else {
+				t.Errorf("diagnostic does not support FromExpr\ngot: %s", spew.Sdump(diags[0]))
+			}
+
+			if got, want := tfdiags.DiagnosticCausedByUnknown(diags[0]), test.CausedByUnknown; got != want {
+				t.Errorf("wrong result from tfdiags.DiagnosticCausedByUnknown\ngot:  %#v\nwant: %#v", got, want)
+			}
+			if got, want := tfdiags.DiagnosticCausedBySensitive(diags[0]), test.CausedBySensitive; got != want {
+				t.Errorf("wrong result from tfdiags.DiagnosticCausedBySensitive\ngot:  %#v\nwant: %#v", got, want)
+			}
+		})
+	}
+}
+
+func TestEvaluateForEachExpressionKnown(t *testing.T) {
+	tests := map[string]hcl.Expression{
+		"unknown string set": hcltest.MockExprLiteral(cty.UnknownVal(cty.Set(cty.String))),
+		"unknown map":        hcltest.MockExprLiteral(cty.UnknownVal(cty.Map(cty.Bool))),
+	}
+
+	for name, expr := range tests {
+		t.Run(name, func(t *testing.T) {
+			ctx := &MockEvalContext{}
+			ctx.installSimpleEval()
+			forEachVal, diags := evaluateForEachExpressionValue(expr, ctx, true)
+
+			if len(diags) != 0 {
+				t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
+			}
+
+			if forEachVal.IsKnown() {
+				t.Error("got known, want unknown")
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/terraform/eval_provider.go b/v1.5.7/internal/terraform/eval_provider.go
new file mode 100644
index 0000000..fd727dd
--- /dev/null
+++ b/v1.5.7/internal/terraform/eval_provider.go
@@ -0,0 +1,62 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/hcl/v2"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/providers"
+)
+
+func buildProviderConfig(ctx EvalContext, addr addrs.AbsProviderConfig, config *configs.Provider) hcl.Body {
+	var configBody hcl.Body
+	if config != nil {
+		configBody = config.Config
+	}
+
+	var inputBody hcl.Body
+	inputConfig := ctx.ProviderInput(addr)
+	if len(inputConfig) > 0 {
+		inputBody = configs.SynthBody("<input-prompt>", inputConfig)
+	}
+
+	switch {
+	case configBody != nil && inputBody != nil:
+		log.Printf("[TRACE] buildProviderConfig for %s: merging explicit config and input", addr)
+		return hcl.MergeBodies([]hcl.Body{inputBody, configBody})
+	case configBody != nil:
+		log.Printf("[TRACE] buildProviderConfig for %s: using explicit config only", addr)
+		return configBody
+	case inputBody != nil:
+		log.Printf("[TRACE] buildProviderConfig for %s: using input only", addr)
+		return inputBody
+	default:
+		log.Printf("[TRACE] buildProviderConfig for %s: no configuration at all", addr)
+		return hcl.EmptyBody()
+	}
+}
+
+// getProvider returns the providers.Interface and schema for a given provider.
+func getProvider(ctx EvalContext, addr addrs.AbsProviderConfig) (providers.Interface, *ProviderSchema, error) {
+	if addr.Provider.Type == "" {
+		// Should never happen
+		panic("GetProvider used with uninitialized provider configuration address")
+	}
+	provider := ctx.Provider(addr)
+	if provider == nil {
+		return nil, &ProviderSchema{}, fmt.Errorf("provider %s not initialized", addr)
+	}
+	// Not all callers require a schema, so we will leave checking for a nil
+	// schema to the callers.
+	schema, err := ctx.ProviderSchema(addr)
+	if err != nil {
+		return nil, &ProviderSchema{}, fmt.Errorf("failed to read schema for provider %s: %w", addr, err)
+	}
+	return provider, schema, nil
+}
diff --git a/v1.5.7/internal/terraform/eval_provider_test.go b/v1.5.7/internal/terraform/eval_provider_test.go
new file mode 100644
index 0000000..cf9188e
--- /dev/null
+++ b/v1.5.7/internal/terraform/eval_provider_test.go
@@ -0,0 +1,58 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/hashicorp/hcl/v2/hcldec"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+)
+
+func TestBuildProviderConfig(t *testing.T) {
+	configBody := configs.SynthBody("", map[string]cty.Value{
+		"set_in_config": cty.StringVal("config"),
+	})
+	providerAddr := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule,
+		Provider: addrs.NewDefaultProvider("foo"),
+	}
+
+	ctx := &MockEvalContext{
+		// The input values map is expected to contain only keys that aren't
+		// already present in the config, since we skip prompting for
+		// attributes that are already set.
+		ProviderInputValues: map[string]cty.Value{
+			"set_by_input": cty.StringVal("input"),
+		},
+	}
+	gotBody := buildProviderConfig(ctx, providerAddr, &configs.Provider{
+		Name:   "foo",
+		Config: configBody,
+	})
+
+	schema := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"set_in_config": {Type: cty.String, Optional: true},
+			"set_by_input":  {Type: cty.String, Optional: true},
+		},
+	}
+	got, diags := hcldec.Decode(gotBody, schema.DecoderSpec(), nil)
+	if diags.HasErrors() {
+		t.Fatalf("body decode failed: %s", diags.Error())
+	}
+
+	// We expect the provider config with the added input value
+	want := cty.ObjectVal(map[string]cty.Value{
+		"set_in_config": cty.StringVal("config"),
+		"set_by_input":  cty.StringVal("input"),
+	})
+	if !got.RawEquals(want) {
+		t.Fatalf("incorrect merged config\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
diff --git a/v1.5.7/internal/terraform/eval_variable.go b/v1.5.7/internal/terraform/eval_variable.go
new file mode 100644
index 0000000..7f291be
--- /dev/null
+++ b/v1.5.7/internal/terraform/eval_variable.go
@@ -0,0 +1,397 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/gohcl"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/convert"
+)
+
+func prepareFinalInputVariableValue(addr addrs.AbsInputVariableInstance, raw *InputValue, cfg *configs.Variable) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	convertTy := cfg.ConstraintType
+	log.Printf("[TRACE] prepareFinalInputVariableValue: preparing %s", addr)
+
+	var defaultVal cty.Value
+	if cfg.Default != cty.NilVal {
+		log.Printf("[TRACE] prepareFinalInputVariableValue: %s has a default value", addr)
+		var err error
+		defaultVal, err = convert.Convert(cfg.Default, convertTy)
+		if err != nil {
+			// Validation of the declaration should typically catch this,
+			// but we'll check it here too to be robust.
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid default value for module argument",
+				Detail: fmt.Sprintf(
+					"The default value for variable %q is incompatible with its type constraint: %s.",
+					cfg.Name, err,
+				),
+				Subject: &cfg.DeclRange,
+			})
+			// We'll return a placeholder unknown value to avoid producing
+			// redundant downstream errors.
+			return cty.UnknownVal(cfg.Type), diags
+		}
+	}
+
+	var sourceRange tfdiags.SourceRange
+	var nonFileSource string
+	if raw.HasSourceRange() {
+		sourceRange = raw.SourceRange
+	} else {
+		// If the value came from a place that isn't a file and thus doesn't
+		// have its own source range, we'll use the declaration range as
+		// our source range and generate some slightly different error
+		// messages.
+		sourceRange = tfdiags.SourceRangeFromHCL(cfg.DeclRange)
+		switch raw.SourceType {
+		case ValueFromCLIArg:
+			nonFileSource = fmt.Sprintf("set using -var=\"%s=...\"", addr.Variable.Name)
+		case ValueFromEnvVar:
+			nonFileSource = fmt.Sprintf("set using the TF_VAR_%s environment variable", addr.Variable.Name)
+		case ValueFromInput:
+			nonFileSource = "set using an interactive prompt"
+		default:
+			nonFileSource = "set from outside of the configuration"
+		}
+	}
+
+	given := raw.Value
+	if given == cty.NilVal { // The variable wasn't set at all (even to null)
+		log.Printf("[TRACE] prepareFinalInputVariableValue: %s has no defined value", addr)
+		if cfg.Required() {
+			// NOTE: The CLI layer typically checks for itself whether all of
+			// the required _root_ module variables are set, which would
+			// mask this error with a more specific one that refers to the
+			// CLI features for setting such variables. We can get here for
+			// child module variables, though.
+			log.Printf("[ERROR] prepareFinalInputVariableValue: %s is required but is not set", addr)
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  `Required variable not set`,
+				Detail:   fmt.Sprintf(`The variable %q is required, but is not set.`, addr.Variable.Name),
+				Subject:  cfg.DeclRange.Ptr(),
+			})
+			// We'll return a placeholder unknown value to avoid producing
+			// redundant downstream errors.
+			return cty.UnknownVal(cfg.Type), diags
+		}
+
+		given = defaultVal // must be set, because we checked above that the variable isn't required
+	}
+
+	// Apply defaults from the variable's type constraint to the converted value,
+	// unless the converted value is null. We do not apply defaults to top-level
+	// null values, as doing so could prevent assigning null to a nullable
+	// variable.
+	if cfg.TypeDefaults != nil && !given.IsNull() {
+		given = cfg.TypeDefaults.Apply(given)
+	}
+
+	val, err := convert.Convert(given, convertTy)
+	if err != nil {
+		log.Printf("[ERROR] prepareFinalInputVariableValue: %s has unsuitable type\n  got:  %s\n  want: %s", addr, given.Type(), convertTy)
+		var detail string
+		var subject *hcl.Range
+		if nonFileSource != "" {
+			detail = fmt.Sprintf(
+				"Unsuitable value for %s %s: %s.",
+				addr, nonFileSource, err,
+			)
+			subject = cfg.DeclRange.Ptr()
+		} else {
+			detail = fmt.Sprintf(
+				"The given value is not suitable for %s declared at %s: %s.",
+				addr, cfg.DeclRange.String(), err,
+			)
+			subject = sourceRange.ToHCL().Ptr()
+
+			// In some workflows, the operator running terraform does not have access to the variables
+			// themselves. They are for example stored in encrypted files that will be used by the CI toolset
+			// and not by the operator directly. In such a case, the failing secret value should not be
+			// displayed to the operator
+			if cfg.Sensitive {
+				detail = fmt.Sprintf(
+					"The given value is not suitable for %s, which is sensitive: %s. Invalid value defined at %s.",
+					addr, err, sourceRange.ToHCL(),
+				)
+				subject = cfg.DeclRange.Ptr()
+			}
+		}
+
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid value for input variable",
+			Detail:   detail,
+			Subject:  subject,
+		})
+		// We'll return a placeholder unknown value to avoid producing
+		// redundant downstream errors.
+		return cty.UnknownVal(cfg.Type), diags
+	}
+
+	// By the time we get here, we know:
+	// - val matches the variable's type constraint
+	// - val is definitely not cty.NilVal, but might be a null value if the given was already null.
+	//
+	// That means we just need to handle the case where the value is null,
+	// which might mean we need to use the default value, or produce an error.
+	//
+	// For historical reasons we do this only for a "non-nullable" variable.
+	// Nullable variables just appear as null if they were set to null,
+	// regardless of any default value.
+	if val.IsNull() && !cfg.Nullable {
+		log.Printf("[TRACE] prepareFinalInputVariableValue: %s is defined as null", addr)
+		if defaultVal != cty.NilVal {
+			val = defaultVal
+		} else {
+			log.Printf("[ERROR] prepareFinalInputVariableValue: %s is non-nullable but set to null, and is required", addr)
+			if nonFileSource != "" {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  `Required variable not set`,
+					Detail: fmt.Sprintf(
+						"Unsuitable value for %s %s: required variable may not be set to null.",
+						addr, nonFileSource,
+					),
+					Subject: cfg.DeclRange.Ptr(),
+				})
+			} else {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  `Required variable not set`,
+					Detail: fmt.Sprintf(
+						"The given value is not suitable for %s defined at %s: required variable may not be set to null.",
+						addr, cfg.DeclRange.String(),
+					),
+					Subject: sourceRange.ToHCL().Ptr(),
+				})
+			}
+			// Stub out our return value so that the semantic checker doesn't
+			// produce redundant downstream errors.
+			val = cty.UnknownVal(cfg.Type)
+		}
+	}
+
+	return val, diags
+}
+
+// evalVariableValidations ensures that all of the configured custom validations
+// for a variable are passing.
+//
+// This must be used only after any side-effects that make the value of the
+// variable available for use in expression evaluation, such as
+// EvalModuleCallArgument for variables in descendent modules.
+func evalVariableValidations(addr addrs.AbsInputVariableInstance, config *configs.Variable, expr hcl.Expression, ctx EvalContext) (diags tfdiags.Diagnostics) {
+	if config == nil || len(config.Validations) == 0 {
+		log.Printf("[TRACE] evalVariableValidations: no validation rules declared for %s, so skipping", addr)
+		return nil
+	}
+	log.Printf("[TRACE] evalVariableValidations: validating %s", addr)
+
+	// Variable nodes evaluate in the parent module to where they were declared
+	// because the value expression (n.Expr, if set) comes from the calling
+	// "module" block in the parent module.
+	//
+	// Validation expressions are statically validated (during configuration
+	// loading) to refer only to the variable being validated, so we can
+	// bypass our usual evaluation machinery here and just produce a minimal
+	// evaluation context containing just the required value, and thus avoid
+	// the problem that ctx's evaluation functions refer to the wrong module.
+	val := ctx.GetVariableValue(addr)
+	if val == cty.NilVal {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "No final value for variable",
+			Detail:   fmt.Sprintf("Terraform doesn't have a final value for %s during validation. This is a bug in Terraform; please report it!", addr),
+		})
+		return diags
+	}
+	hclCtx := &hcl.EvalContext{
+		Variables: map[string]cty.Value{
+			"var": cty.ObjectVal(map[string]cty.Value{
+				config.Name: val,
+			}),
+		},
+		Functions: ctx.EvaluationScope(nil, nil, EvalDataForNoInstanceKey).Functions(),
+	}
+
+	for _, validation := range config.Validations {
+		const errInvalidCondition = "Invalid variable validation result"
+		const errInvalidValue = "Invalid value for variable"
+		var ruleDiags tfdiags.Diagnostics
+
+		result, moreDiags := validation.Condition.Value(hclCtx)
+		ruleDiags = ruleDiags.Append(moreDiags)
+		errorValue, errorDiags := validation.ErrorMessage.Value(hclCtx)
+
+		// The following error handling is a workaround to preserve backwards
+		// compatibility. Due to an implementation quirk, all prior versions of
+		// Terraform would treat error messages specified using JSON
+		// configuration syntax (.tf.json) as string literals, even if they
+		// contained the "${" template expression operator. This behaviour did
+		// not match that of HCL configuration syntax, where a template
+		// expression would result in a validation error.
+		//
+		// As a result, users writing or generating JSON configuration syntax
+		// may have specified error messages which are invalid template
+		// expressions. As we add support for error message expressions, we are
+		// unable to perfectly distinguish between these two cases.
+		//
+		// To ensure that we don't break backwards compatibility, we have the
+		// below fallback logic if the error message fails to evaluate. This
+		// should only have any effect for JSON configurations. The gohcl
+		// DecodeExpression function behaves differently when the source of the
+		// expression is a JSON configuration file and a nil context is passed.
+		if errorDiags.HasErrors() {
+			// Attempt to decode the expression as a string literal. Passing
+			// nil as the context forces a JSON syntax string value to be
+			// interpreted as a string literal.
+			var errorString string
+			moreErrorDiags := gohcl.DecodeExpression(validation.ErrorMessage, nil, &errorString)
+			if !moreErrorDiags.HasErrors() {
+				// Decoding succeeded, meaning that this is a JSON syntax
+				// string value. We rewrap that as a cty value to allow later
+				// decoding to succeed.
+				errorValue = cty.StringVal(errorString)
+
+				// This warning diagnostic explains this odd behaviour, while
+				// giving us an escape hatch to change this to a hard failure
+				// in some future Terraform 1.x version.
+				errorDiags = hcl.Diagnostics{
+					&hcl.Diagnostic{
+						Severity:    hcl.DiagWarning,
+						Summary:     "Validation error message expression is invalid",
+						Detail:      fmt.Sprintf("The error message provided could not be evaluated as an expression, so Terraform is interpreting it as a string literal.\n\nIn future versions of Terraform, this will be considered an error. Please file a GitHub issue if this would break your workflow.\n\n%s", errorDiags.Error()),
+						Subject:     validation.ErrorMessage.Range().Ptr(),
+						Context:     validation.DeclRange.Ptr(),
+						Expression:  validation.ErrorMessage,
+						EvalContext: hclCtx,
+					},
+				}
+			}
+
+			// We want to either report the original diagnostics if the
+			// fallback failed, or the warning generated above if it succeeded.
+			ruleDiags = ruleDiags.Append(errorDiags)
+		}
+
+		diags = diags.Append(ruleDiags)
+
+		if ruleDiags.HasErrors() {
+			log.Printf("[TRACE] evalVariableValidations: %s rule %s check rule evaluation failed: %s", addr, validation.DeclRange, ruleDiags.Err().Error())
+		}
+		if !result.IsKnown() {
+			log.Printf("[TRACE] evalVariableValidations: %s rule %s condition value is unknown, so skipping validation for now", addr, validation.DeclRange)
+			continue // We'll wait until we've learned more, then.
+		}
+		if result.IsNull() {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity:    hcl.DiagError,
+				Summary:     errInvalidCondition,
+				Detail:      "Validation condition expression must return either true or false, not null.",
+				Subject:     validation.Condition.Range().Ptr(),
+				Expression:  validation.Condition,
+				EvalContext: hclCtx,
+			})
+			continue
+		}
+		var err error
+		result, err = convert.Convert(result, cty.Bool)
+		if err != nil {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity:    hcl.DiagError,
+				Summary:     errInvalidCondition,
+				Detail:      fmt.Sprintf("Invalid validation condition result value: %s.", tfdiags.FormatError(err)),
+				Subject:     validation.Condition.Range().Ptr(),
+				Expression:  validation.Condition,
+				EvalContext: hclCtx,
+			})
+			continue
+		}
+
+		// Validation condition may be marked if the input variable is bound to
+		// a sensitive value. This is irrelevant to the validation process, so
+		// we discard the marks now.
+		result, _ = result.Unmark()
+
+		if result.True() {
+			continue
+		}
+
+		var errorMessage string
+		if !errorDiags.HasErrors() && errorValue.IsKnown() && !errorValue.IsNull() {
+			var err error
+			errorValue, err = convert.Convert(errorValue, cty.String)
+			if err != nil {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity:    hcl.DiagError,
+					Summary:     "Invalid error message",
+					Detail:      fmt.Sprintf("Unsuitable value for error message: %s.", tfdiags.FormatError(err)),
+					Subject:     validation.ErrorMessage.Range().Ptr(),
+					Expression:  validation.ErrorMessage,
+					EvalContext: hclCtx,
+				})
+			} else {
+				if marks.Has(errorValue, marks.Sensitive) {
+					diags = diags.Append(&hcl.Diagnostic{
+						Severity: hcl.DiagError,
+
+						Summary: "Error message refers to sensitive values",
+						Detail: `The error expression used to explain this condition refers to sensitive values. Terraform will not display the resulting message.
+
+You can correct this by removing references to sensitive values, or by carefully using the nonsensitive() function if the expression will not reveal the sensitive data.`,
+
+						Subject:     validation.ErrorMessage.Range().Ptr(),
+						Expression:  validation.ErrorMessage,
+						EvalContext: hclCtx,
+					})
+					errorMessage = "The error message included a sensitive value, so it will not be displayed."
+				} else {
+					errorMessage = strings.TrimSpace(errorValue.AsString())
+				}
+			}
+		}
+		if errorMessage == "" {
+			errorMessage = "Failed to evaluate condition error message."
+		}
+
+		if expr != nil {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity:    hcl.DiagError,
+				Summary:     errInvalidValue,
+				Detail:      fmt.Sprintf("%s\n\nThis was checked by the validation rule at %s.", errorMessage, validation.DeclRange.String()),
+				Subject:     expr.Range().Ptr(),
+				Expression:  validation.Condition,
+				EvalContext: hclCtx,
+			})
+		} else {
+			// Since we don't have a source expression for a root module
+			// variable, we'll just report the error from the perspective
+			// of the variable declaration itself.
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity:    hcl.DiagError,
+				Summary:     errInvalidValue,
+				Detail:      fmt.Sprintf("%s\n\nThis was checked by the validation rule at %s.", errorMessage, validation.DeclRange.String()),
+				Subject:     config.DeclRange.Ptr(),
+				Expression:  validation.Condition,
+				EvalContext: hclCtx,
+			})
+		}
+	}
+
+	return diags
+}
diff --git a/v1.5.7/internal/terraform/eval_variable_test.go b/v1.5.7/internal/terraform/eval_variable_test.go
new file mode 100644
index 0000000..aca3b0d
--- /dev/null
+++ b/v1.5.7/internal/terraform/eval_variable_test.go
@@ -0,0 +1,1348 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestPrepareFinalInputVariableValue(t *testing.T) {
+	// This is just a concise way to define a bunch of *configs.Variable
+	// objects to use in our tests below. We're only going to decode this
+	// config, not fully evaluate it.
+	cfgSrc := `
+		variable "nullable_required" {
+		}
+		variable "nullable_optional_default_string" {
+			default = "hello"
+		}
+		variable "nullable_optional_default_null" {
+			default = null
+		}
+		variable "constrained_string_nullable_required" {
+			type = string
+		}
+		variable "constrained_string_nullable_optional_default_string" {
+			type    = string
+			default = "hello"
+		}
+		variable "constrained_string_nullable_optional_default_bool" {
+			type    = string
+			default = true
+		}
+		variable "constrained_string_nullable_optional_default_null" {
+			type    = string
+			default = null
+		}
+		variable "required" {
+			nullable = false
+		}
+		variable "optional_default_string" {
+			nullable = false
+			default  = "hello"
+		}
+		variable "constrained_string_required" {
+			nullable = false
+			type     = string
+		}
+		variable "constrained_string_optional_default_string" {
+			nullable = false
+			type     = string
+			default  = "hello"
+		}
+		variable "constrained_string_optional_default_bool" {
+			nullable = false
+			type     = string
+			default  = true
+		}
+		variable "constrained_string_sensitive_required" {
+			sensitive = true
+			nullable  = false
+			type      = string
+		}
+		variable "complex_type_with_nested_default_optional" {
+			type = set(object({
+				name      = string
+				schedules = set(object({
+					name               = string
+					cold_storage_after = optional(number, 10)
+				}))
+  			}))
+		}
+		variable "complex_type_with_nested_complex_types" {
+			type = object({
+				name                       = string
+				nested_object              = object({
+					name  = string
+					value = optional(string, "foo")
+				})
+				nested_object_with_default = optional(object({
+					name  = string
+					value = optional(string, "bar")
+				}), {
+					name = "nested_object_with_default"
+				})
+			})
+		}
+		// https://github.com/hashicorp/terraform/issues/32152
+		// This variable was originally added to test that optional attribute
+		// metadata is stripped from empty default collections. Essentially, you
+		// should be able to mix and match custom and default values for the
+		// optional_list attribute.
+        variable "complex_type_with_empty_default_and_nested_optional" {
+			type = list(object({
+				name          = string
+				optional_list = optional(list(object({
+					string          = string
+					optional_string = optional(string)
+				})), [])
+			}))
+        }
+ 		// https://github.com/hashicorp/terraform/issues/32160#issuecomment-1302783910
+		// These variables were added to test the specific use case from this
+		// GitHub comment.
+		variable "empty_object_with_optional_nested_object_with_optional_bool" {
+			type = object({
+				thing = optional(object({
+					flag = optional(bool, false)
+				}))
+			})
+			default = {}
+		}
+		variable "populated_object_with_optional_nested_object_with_optional_bool" {
+			type = object({
+				thing = optional(object({
+					flag = optional(bool, false)
+				}))
+			})
+			default = {
+				thing = {}
+			}
+		}
+		variable "empty_object_with_default_nested_object_with_optional_bool" {
+			type = object({
+				thing = optional(object({
+					flag = optional(bool, false)
+				}), {})
+			})
+			default = {}
+		}
+		// https://github.com/hashicorp/terraform/issues/32160
+		// This variable was originally added to test that optional objects do
+		// get created containing only their defaults. Instead they should be
+		// left empty. We do not expect nested_object to be created just because
+		// optional_string has a default value.
+		variable "object_with_nested_object_with_required_and_optional_attributes" {
+			type = object({
+				nested_object = optional(object({
+					string          = string
+					optional_string = optional(string, "optional")
+				}))
+			})
+		}
+		// https://github.com/hashicorp/terraform/issues/32157
+		// Similar to above, we want to see that merging combinations of the
+		// nested_object into a single collection doesn't crash because of
+		// inconsistent elements.
+		variable "list_with_nested_object_with_required_and_optional_attributes" {
+			type = list(object({
+				nested_object = optional(object({
+					string          = string
+					optional_string = optional(string, "optional")
+				}))
+			}))
+		}
+		// https://github.com/hashicorp/terraform/issues/32109
+		// This variable was originally introduced to test the behaviour of 
+		// the dynamic type constraint. You should be able to use the 'any' 
+		// constraint and introduce empty, null, and populated values into the
+		// list.
+		variable "list_with_nested_list_of_any" {
+			type = list(object({
+				a = string
+				b = optional(list(any))
+			}))
+			default = [
+				{
+					a = "a"
+				},
+				{
+					a = "b"
+					b = [1]
+				}
+			]
+		}
+		// https://github.com/hashicorp/terraform/issues/32396
+		// This variable was originally introduced to test the behaviour of the
+        // dynamic type constraint. You should be able to set primitive types in
+        // the list consistently.
+        variable "list_with_nested_collections_dynamic_with_default" {
+			type = list(
+				object({
+					name = optional(string, "default")
+					taints = optional(list(map(any)), [])
+				})
+			)
+		}
+        // https://github.com/hashicorp/terraform/issues/32752
+		// This variable was introduced to make sure the evaluation doesn't 
+        // crash even when the types are wrong.
+        variable "invalid_nested_type" {
+            type = map(
+                object({
+					rules = map(
+						object({
+							destination_addresses = optional(list(string), [])
+						})
+					)
+                })
+            )
+			default = {}
+        }
+	`
+	cfg := testModuleInline(t, map[string]string{
+		"main.tf": cfgSrc,
+	})
+	variableConfigs := cfg.Module.Variables
+
+	// Because we loaded our pseudo-module from a temporary file, the
+	// declaration source ranges will have unpredictable filenames. We'll
+	// fix that here just to make things easier below.
+	for _, vc := range variableConfigs {
+		vc.DeclRange.Filename = "main.tf"
+	}
+
+	tests := []struct {
+		varName string
+		given   cty.Value
+		want    cty.Value
+		wantErr string
+	}{
+		// nullable_required
+		{
+			"nullable_required",
+			cty.NilVal,
+			cty.UnknownVal(cty.DynamicPseudoType),
+			`Required variable not set: The variable "nullable_required" is required, but is not set.`,
+		},
+		{
+			"nullable_required",
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.NullVal(cty.DynamicPseudoType),
+			``, // "required" for a nullable variable means only that it must be set, even if it's set to null
+		},
+		{
+			"nullable_required",
+			cty.StringVal("ahoy"),
+			cty.StringVal("ahoy"),
+			``,
+		},
+		{
+			"nullable_required",
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+
+		// nullable_optional_default_string
+		{
+			"nullable_optional_default_string",
+			cty.NilVal,
+			cty.StringVal("hello"), // the declared default value
+			``,
+		},
+		{
+			"nullable_optional_default_string",
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.NullVal(cty.DynamicPseudoType), // nullable variables can be really set to null, masking the default
+			``,
+		},
+		{
+			"nullable_optional_default_string",
+			cty.StringVal("ahoy"),
+			cty.StringVal("ahoy"),
+			``,
+		},
+		{
+			"nullable_optional_default_string",
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+
+		// nullable_optional_default_null
+		{
+			"nullable_optional_default_null",
+			cty.NilVal,
+			cty.NullVal(cty.DynamicPseudoType), // the declared default value
+			``,
+		},
+		{
+			"nullable_optional_default_null",
+			cty.NullVal(cty.String),
+			cty.NullVal(cty.String), // nullable variables can be really set to null, masking the default
+			``,
+		},
+		{
+			"nullable_optional_default_null",
+			cty.StringVal("ahoy"),
+			cty.StringVal("ahoy"),
+			``,
+		},
+		{
+			"nullable_optional_default_null",
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+
+		// constrained_string_nullable_required
+		{
+			"constrained_string_nullable_required",
+			cty.NilVal,
+			cty.UnknownVal(cty.String),
+			`Required variable not set: The variable "constrained_string_nullable_required" is required, but is not set.`,
+		},
+		{
+			"constrained_string_nullable_required",
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.NullVal(cty.String), // the null value still gets converted to match the type constraint
+			``,                      // "required" for a nullable variable means only that it must be set, even if it's set to null
+		},
+		{
+			"constrained_string_nullable_required",
+			cty.StringVal("ahoy"),
+			cty.StringVal("ahoy"),
+			``,
+		},
+		{
+			"constrained_string_nullable_required",
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+
+		// constrained_string_nullable_optional_default_string
+		{
+			"constrained_string_nullable_optional_default_string",
+			cty.NilVal,
+			cty.StringVal("hello"), // the declared default value
+			``,
+		},
+		{
+			"constrained_string_nullable_optional_default_string",
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.NullVal(cty.String), // nullable variables can be really set to null, masking the default
+			``,
+		},
+		{
+			"constrained_string_nullable_optional_default_string",
+			cty.StringVal("ahoy"),
+			cty.StringVal("ahoy"),
+			``,
+		},
+		{
+			"constrained_string_nullable_optional_default_string",
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+
+		// constrained_string_nullable_optional_default_bool
+		{
+			"constrained_string_nullable_optional_default_bool",
+			cty.NilVal,
+			cty.StringVal("true"), // the declared default value, automatically converted to match type constraint
+			``,
+		},
+		{
+			"constrained_string_nullable_optional_default_bool",
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.NullVal(cty.String), // nullable variables can be really set to null, masking the default
+			``,
+		},
+		{
+			"constrained_string_nullable_optional_default_bool",
+			cty.StringVal("ahoy"),
+			cty.StringVal("ahoy"),
+			``,
+		},
+		{
+			"constrained_string_nullable_optional_default_bool",
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+
+		// constrained_string_nullable_optional_default_null
+		{
+			"constrained_string_nullable_optional_default_null",
+			cty.NilVal,
+			cty.NullVal(cty.String),
+			``,
+		},
+		{
+			"constrained_string_nullable_optional_default_null",
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.NullVal(cty.String),
+			``,
+		},
+		{
+			"constrained_string_nullable_optional_default_null",
+			cty.StringVal("ahoy"),
+			cty.StringVal("ahoy"),
+			``,
+		},
+		{
+			"constrained_string_nullable_optional_default_null",
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+
+		// required
+		{
+			"required",
+			cty.NilVal,
+			cty.UnknownVal(cty.DynamicPseudoType),
+			`Required variable not set: The variable "required" is required, but is not set.`,
+		},
+		{
+			"required",
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.UnknownVal(cty.DynamicPseudoType),
+			`Required variable not set: Unsuitable value for var.required set from outside of the configuration: required variable may not be set to null.`,
+		},
+		{
+			"required",
+			cty.StringVal("ahoy"),
+			cty.StringVal("ahoy"),
+			``,
+		},
+		{
+			"required",
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+
+		// optional_default_string
+		{
+			"optional_default_string",
+			cty.NilVal,
+			cty.StringVal("hello"), // the declared default value
+			``,
+		},
+		{
+			"optional_default_string",
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.StringVal("hello"), // the declared default value
+			``,
+		},
+		{
+			"optional_default_string",
+			cty.StringVal("ahoy"),
+			cty.StringVal("ahoy"),
+			``,
+		},
+		{
+			"optional_default_string",
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+
+		// constrained_string_required
+		{
+			"constrained_string_required",
+			cty.NilVal,
+			cty.UnknownVal(cty.String),
+			`Required variable not set: The variable "constrained_string_required" is required, but is not set.`,
+		},
+		{
+			"constrained_string_required",
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.UnknownVal(cty.String),
+			`Required variable not set: Unsuitable value for var.constrained_string_required set from outside of the configuration: required variable may not be set to null.`,
+		},
+		{
+			"constrained_string_required",
+			cty.StringVal("ahoy"),
+			cty.StringVal("ahoy"),
+			``,
+		},
+		{
+			"constrained_string_required",
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+
+		// constrained_string_optional_default_string
+		{
+			"constrained_string_optional_default_string",
+			cty.NilVal,
+			cty.StringVal("hello"), // the declared default value
+			``,
+		},
+		{
+			"constrained_string_optional_default_string",
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.StringVal("hello"), // the declared default value
+			``,
+		},
+		{
+			"constrained_string_optional_default_string",
+			cty.StringVal("ahoy"),
+			cty.StringVal("ahoy"),
+			``,
+		},
+		{
+			"constrained_string_optional_default_string",
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+
+		// constrained_string_optional_default_bool
+		{
+			"constrained_string_optional_default_bool",
+			cty.NilVal,
+			cty.StringVal("true"), // the declared default value, automatically converted to match type constraint
+			``,
+		},
+		{
+			"constrained_string_optional_default_bool",
+			cty.NullVal(cty.DynamicPseudoType),
+			cty.StringVal("true"), // the declared default value, automatically converted to match type constraint
+			``,
+		},
+		{
+			"constrained_string_optional_default_bool",
+			cty.StringVal("ahoy"),
+			cty.StringVal("ahoy"),
+			``,
+		},
+		{
+			"constrained_string_optional_default_bool",
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+		{
+			"list_with_nested_collections_dynamic_with_default",
+			cty.TupleVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("default"),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("complex"),
+					"taints": cty.ListVal([]cty.Value{
+						cty.MapVal(map[string]cty.Value{
+							"key":   cty.StringVal("my_key"),
+							"value": cty.StringVal("my_value"),
+						}),
+					}),
+				}),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"name":   cty.StringVal("default"),
+					"taints": cty.ListValEmpty(cty.Map(cty.String)),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("complex"),
+					"taints": cty.ListVal([]cty.Value{
+						cty.MapVal(map[string]cty.Value{
+							"key":   cty.StringVal("my_key"),
+							"value": cty.StringVal("my_value"),
+						}),
+					}),
+				}),
+			}),
+			``,
+		},
+
+		// complex types
+
+		{
+			"complex_type_with_nested_default_optional",
+			cty.SetVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("test1"),
+					"schedules": cty.SetVal([]cty.Value{
+						cty.MapVal(map[string]cty.Value{
+							"name": cty.StringVal("daily"),
+						}),
+					}),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("test2"),
+					"schedules": cty.SetVal([]cty.Value{
+						cty.MapVal(map[string]cty.Value{
+							"name": cty.StringVal("daily"),
+						}),
+						cty.MapVal(map[string]cty.Value{
+							"name":               cty.StringVal("weekly"),
+							"cold_storage_after": cty.StringVal("0"),
+						}),
+					}),
+				}),
+			}),
+			cty.SetVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("test1"),
+					"schedules": cty.SetVal([]cty.Value{
+						cty.ObjectVal(map[string]cty.Value{
+							"name":               cty.StringVal("daily"),
+							"cold_storage_after": cty.NumberIntVal(10),
+						}),
+					}),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("test2"),
+					"schedules": cty.SetVal([]cty.Value{
+						cty.ObjectVal(map[string]cty.Value{
+							"name":               cty.StringVal("daily"),
+							"cold_storage_after": cty.NumberIntVal(10),
+						}),
+						cty.ObjectVal(map[string]cty.Value{
+							"name":               cty.StringVal("weekly"),
+							"cold_storage_after": cty.NumberIntVal(0),
+						}),
+					}),
+				}),
+			}),
+			``,
+		},
+		{
+			"complex_type_with_nested_complex_types",
+			cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("object"),
+				"nested_object": cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("nested_object"),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"name": cty.StringVal("object"),
+				"nested_object": cty.ObjectVal(map[string]cty.Value{
+					"name":  cty.StringVal("nested_object"),
+					"value": cty.StringVal("foo"),
+				}),
+				"nested_object_with_default": cty.ObjectVal(map[string]cty.Value{
+					"name":  cty.StringVal("nested_object_with_default"),
+					"value": cty.StringVal("bar"),
+				}),
+			}),
+			``,
+		},
+		{
+			"complex_type_with_empty_default_and_nested_optional",
+			cty.ListVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("abc"),
+					"optional_list": cty.ListVal([]cty.Value{
+						cty.ObjectVal(map[string]cty.Value{
+							"string":          cty.StringVal("child"),
+							"optional_string": cty.NullVal(cty.String),
+						}),
+					}),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("def"),
+					"optional_list": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
+						"string":          cty.String,
+						"optional_string": cty.String,
+					}))),
+				}),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("abc"),
+					"optional_list": cty.ListVal([]cty.Value{
+						cty.ObjectVal(map[string]cty.Value{
+							"string":          cty.StringVal("child"),
+							"optional_string": cty.NullVal(cty.String),
+						}),
+					}),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("def"),
+					"optional_list": cty.ListValEmpty(cty.Object(map[string]cty.Type{
+						"string":          cty.String,
+						"optional_string": cty.String,
+					})),
+				}),
+			}),
+			``,
+		},
+		{
+			"object_with_nested_object_with_required_and_optional_attributes",
+			cty.EmptyObjectVal,
+			cty.ObjectVal(map[string]cty.Value{
+				"nested_object": cty.NullVal(cty.Object(map[string]cty.Type{
+					"string":          cty.String,
+					"optional_string": cty.String,
+				})),
+			}),
+			``,
+		},
+		{
+			"empty_object_with_optional_nested_object_with_optional_bool",
+			cty.NilVal,
+			cty.ObjectVal(map[string]cty.Value{
+				"thing": cty.NullVal(cty.Object(map[string]cty.Type{
+					"flag": cty.Bool,
+				})),
+			}),
+			``,
+		},
+		{
+			"populated_object_with_optional_nested_object_with_optional_bool",
+			cty.NilVal,
+			cty.ObjectVal(map[string]cty.Value{
+				"thing": cty.ObjectVal(map[string]cty.Value{
+					"flag": cty.False,
+				}),
+			}),
+			``,
+		},
+		{
+			"empty_object_with_default_nested_object_with_optional_bool",
+			cty.NilVal,
+			cty.ObjectVal(map[string]cty.Value{
+				"thing": cty.ObjectVal(map[string]cty.Value{
+					"flag": cty.False,
+				}),
+			}),
+			``,
+		},
+		{
+			"list_with_nested_object_with_required_and_optional_attributes",
+			cty.ListVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"nested_object": cty.ObjectVal(map[string]cty.Value{
+						"string":          cty.StringVal("string"),
+						"optional_string": cty.NullVal(cty.String),
+					}),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"nested_object": cty.NullVal(cty.Object(map[string]cty.Type{
+						"string":          cty.String,
+						"optional_string": cty.String,
+					})),
+				}),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"nested_object": cty.ObjectVal(map[string]cty.Value{
+						"string":          cty.StringVal("string"),
+						"optional_string": cty.StringVal("optional"),
+					}),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"nested_object": cty.NullVal(cty.Object(map[string]cty.Type{
+						"string":          cty.String,
+						"optional_string": cty.String,
+					})),
+				}),
+			}),
+			``,
+		},
+		{
+			"list_with_nested_list_of_any",
+			cty.NilVal,
+			cty.ListVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.StringVal("a"),
+					"b": cty.NullVal(cty.List(cty.Number)),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"a": cty.StringVal("b"),
+					"b": cty.ListVal([]cty.Value{
+						cty.NumberIntVal(1),
+					}),
+				}),
+			}),
+			``,
+		},
+		{
+			"list_with_nested_collections_dynamic_with_default",
+			cty.TupleVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("default"),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("complex"),
+					"taints": cty.ListVal([]cty.Value{
+						cty.MapVal(map[string]cty.Value{
+							"key":   cty.StringVal("my_key"),
+							"value": cty.StringVal("my_value"),
+						}),
+					}),
+				}),
+			}),
+			cty.ListVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"name":   cty.StringVal("default"),
+					"taints": cty.ListValEmpty(cty.Map(cty.String)),
+				}),
+				cty.ObjectVal(map[string]cty.Value{
+					"name": cty.StringVal("complex"),
+					"taints": cty.ListVal([]cty.Value{
+						cty.MapVal(map[string]cty.Value{
+							"key":   cty.StringVal("my_key"),
+							"value": cty.StringVal("my_value"),
+						}),
+					}),
+				}),
+			}),
+			``,
+		},
+		{
+			"invalid_nested_type",
+			cty.MapVal(map[string]cty.Value{
+				"mysql": cty.ObjectVal(map[string]cty.Value{
+					"rules": cty.ObjectVal(map[string]cty.Value{
+						"destination_addresses": cty.ListVal([]cty.Value{cty.StringVal("192.168.0.1")}),
+					}),
+				}),
+			}),
+			cty.UnknownVal(cty.Map(cty.Object(map[string]cty.Type{
+				"rules": cty.Map(cty.Object(map[string]cty.Type{
+					"destination_addresses": cty.List(cty.String),
+				})),
+			}))),
+			`Invalid value for input variable: Unsuitable value for var.invalid_nested_type set from outside of the configuration: incorrect map element type: attribute "rules": element "destination_addresses": object required.`,
+		},
+
+		// sensitive
+		{
+			"constrained_string_sensitive_required",
+			cty.UnknownVal(cty.String),
+			cty.UnknownVal(cty.String),
+			``,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%s %#v", test.varName, test.given), func(t *testing.T) {
+			varAddr := addrs.InputVariable{Name: test.varName}.Absolute(addrs.RootModuleInstance)
+			varCfg := variableConfigs[test.varName]
+			if varCfg == nil {
+				t.Fatalf("invalid variable name %q", test.varName)
+			}
+
+			t.Logf(
+				"test case\nvariable:    %s\nconstraint:  %#v\ndefault:     %#v\nnullable:    %#v\ngiven value: %#v",
+				varAddr,
+				varCfg.Type,
+				varCfg.Default,
+				varCfg.Nullable,
+				test.given,
+			)
+
+			rawVal := &InputValue{
+				Value:      test.given,
+				SourceType: ValueFromCaller,
+			}
+
+			got, diags := prepareFinalInputVariableValue(
+				varAddr, rawVal, varCfg,
+			)
+
+			if test.wantErr != "" {
+				if !diags.HasErrors() {
+					t.Errorf("unexpected success\nwant error: %s", test.wantErr)
+				} else if got, want := diags.Err().Error(), test.wantErr; got != want {
+					t.Errorf("wrong error\ngot:  %s\nwant: %s", got, want)
+				}
+			} else {
+				if diags.HasErrors() {
+					t.Errorf("unexpected error\ngot: %s", diags.Err().Error())
+				}
+			}
+
+			// NOTE: should still have returned some reasonable value even if there was an error
+			if !test.want.RawEquals(got) {
+				t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", got, test.want)
+			}
+		})
+	}
+
+	t.Run("SourceType error message variants", func(t *testing.T) {
+		tests := []struct {
+			SourceType  ValueSourceType
+			SourceRange tfdiags.SourceRange
+			WantTypeErr string
+			WantNullErr string
+		}{
+			{
+				ValueFromUnknown,
+				tfdiags.SourceRange{},
+				`Invalid value for input variable: Unsuitable value for var.constrained_string_required set from outside of the configuration: string required.`,
+				`Required variable not set: Unsuitable value for var.constrained_string_required set from outside of the configuration: required variable may not be set to null.`,
+			},
+			{
+				ValueFromConfig,
+				tfdiags.SourceRange{
+					Filename: "example.tf",
+					Start:    tfdiags.SourcePos(hcl.InitialPos),
+					End:      tfdiags.SourcePos(hcl.InitialPos),
+				},
+				`Invalid value for input variable: The given value is not suitable for var.constrained_string_required declared at main.tf:32,3-41: string required.`,
+				`Required variable not set: The given value is not suitable for var.constrained_string_required defined at main.tf:32,3-41: required variable may not be set to null.`,
+			},
+			{
+				ValueFromAutoFile,
+				tfdiags.SourceRange{
+					Filename: "example.auto.tfvars",
+					Start:    tfdiags.SourcePos(hcl.InitialPos),
+					End:      tfdiags.SourcePos(hcl.InitialPos),
+				},
+				`Invalid value for input variable: The given value is not suitable for var.constrained_string_required declared at main.tf:32,3-41: string required.`,
+				`Required variable not set: The given value is not suitable for var.constrained_string_required defined at main.tf:32,3-41: required variable may not be set to null.`,
+			},
+			{
+				ValueFromNamedFile,
+				tfdiags.SourceRange{
+					Filename: "example.tfvars",
+					Start:    tfdiags.SourcePos(hcl.InitialPos),
+					End:      tfdiags.SourcePos(hcl.InitialPos),
+				},
+				`Invalid value for input variable: The given value is not suitable for var.constrained_string_required declared at main.tf:32,3-41: string required.`,
+				`Required variable not set: The given value is not suitable for var.constrained_string_required defined at main.tf:32,3-41: required variable may not be set to null.`,
+			},
+			{
+				ValueFromCLIArg,
+				tfdiags.SourceRange{},
+				`Invalid value for input variable: Unsuitable value for var.constrained_string_required set using -var="constrained_string_required=...": string required.`,
+				`Required variable not set: Unsuitable value for var.constrained_string_required set using -var="constrained_string_required=...": required variable may not be set to null.`,
+			},
+			{
+				ValueFromEnvVar,
+				tfdiags.SourceRange{},
+				`Invalid value for input variable: Unsuitable value for var.constrained_string_required set using the TF_VAR_constrained_string_required environment variable: string required.`,
+				`Required variable not set: Unsuitable value for var.constrained_string_required set using the TF_VAR_constrained_string_required environment variable: required variable may not be set to null.`,
+			},
+			{
+				ValueFromInput,
+				tfdiags.SourceRange{},
+				`Invalid value for input variable: Unsuitable value for var.constrained_string_required set using an interactive prompt: string required.`,
+				`Required variable not set: Unsuitable value for var.constrained_string_required set using an interactive prompt: required variable may not be set to null.`,
+			},
+			{
+				// NOTE: This isn't actually a realistic case for this particular
+				// function, because if we have a value coming from a plan then
+				// we must be in the apply step, and we shouldn't be able to
+				// get past the plan step if we have invalid variable values,
+				// and during planning we'll always have other source types.
+				ValueFromPlan,
+				tfdiags.SourceRange{},
+				`Invalid value for input variable: Unsuitable value for var.constrained_string_required set from outside of the configuration: string required.`,
+				`Required variable not set: Unsuitable value for var.constrained_string_required set from outside of the configuration: required variable may not be set to null.`,
+			},
+			{
+				ValueFromCaller,
+				tfdiags.SourceRange{},
+				`Invalid value for input variable: Unsuitable value for var.constrained_string_required set from outside of the configuration: string required.`,
+				`Required variable not set: Unsuitable value for var.constrained_string_required set from outside of the configuration: required variable may not be set to null.`,
+			},
+		}
+
+		for _, test := range tests {
+			t.Run(fmt.Sprintf("%s %s", test.SourceType, test.SourceRange.StartString()), func(t *testing.T) {
+				varAddr := addrs.InputVariable{Name: "constrained_string_required"}.Absolute(addrs.RootModuleInstance)
+				varCfg := variableConfigs[varAddr.Variable.Name]
+				t.Run("type error", func(t *testing.T) {
+					rawVal := &InputValue{
+						Value:       cty.EmptyObjectVal,
+						SourceType:  test.SourceType,
+						SourceRange: test.SourceRange,
+					}
+
+					_, diags := prepareFinalInputVariableValue(
+						varAddr, rawVal, varCfg,
+					)
+					if !diags.HasErrors() {
+						t.Fatalf("unexpected success; want error")
+					}
+
+					if got, want := diags.Err().Error(), test.WantTypeErr; got != want {
+						t.Errorf("wrong error\ngot:  %s\nwant: %s", got, want)
+					}
+				})
+				t.Run("null error", func(t *testing.T) {
+					rawVal := &InputValue{
+						Value:       cty.NullVal(cty.DynamicPseudoType),
+						SourceType:  test.SourceType,
+						SourceRange: test.SourceRange,
+					}
+
+					_, diags := prepareFinalInputVariableValue(
+						varAddr, rawVal, varCfg,
+					)
+					if !diags.HasErrors() {
+						t.Fatalf("unexpected success; want error")
+					}
+
+					if got, want := diags.Err().Error(), test.WantNullErr; got != want {
+						t.Errorf("wrong error\ngot:  %s\nwant: %s", got, want)
+					}
+				})
+			})
+		}
+	})
+
+	t.Run("SensitiveVariable error message variants, with source variants", func(t *testing.T) {
+		tests := []struct {
+			SourceType  ValueSourceType
+			SourceRange tfdiags.SourceRange
+			WantTypeErr string
+			HideSubject bool
+		}{
+			{
+				ValueFromUnknown,
+				tfdiags.SourceRange{},
+				"Invalid value for input variable: Unsuitable value for var.constrained_string_sensitive_required set from outside of the configuration: string required.",
+				false,
+			},
+			{
+				ValueFromConfig,
+				tfdiags.SourceRange{
+					Filename: "example.tfvars",
+					Start:    tfdiags.SourcePos(hcl.InitialPos),
+					End:      tfdiags.SourcePos(hcl.InitialPos),
+				},
+				`Invalid value for input variable: The given value is not suitable for var.constrained_string_sensitive_required, which is sensitive: string required. Invalid value defined at example.tfvars:1,1-1.`,
+				true,
+			},
+		}
+
+		for _, test := range tests {
+			t.Run(fmt.Sprintf("%s %s", test.SourceType, test.SourceRange.StartString()), func(t *testing.T) {
+				varAddr := addrs.InputVariable{Name: "constrained_string_sensitive_required"}.Absolute(addrs.RootModuleInstance)
+				varCfg := variableConfigs[varAddr.Variable.Name]
+				t.Run("type error", func(t *testing.T) {
+					rawVal := &InputValue{
+						Value:       cty.EmptyObjectVal,
+						SourceType:  test.SourceType,
+						SourceRange: test.SourceRange,
+					}
+
+					_, diags := prepareFinalInputVariableValue(
+						varAddr, rawVal, varCfg,
+					)
+					if !diags.HasErrors() {
+						t.Fatalf("unexpected success; want error")
+					}
+
+					if got, want := diags.Err().Error(), test.WantTypeErr; got != want {
+						t.Errorf("wrong error\ngot:  %s\nwant: %s", got, want)
+					}
+
+					if test.HideSubject {
+						if got, want := diags[0].Source().Subject.StartString(), test.SourceRange.StartString(); got == want {
+							t.Errorf("Subject start should have been hidden, but was %s", got)
+						}
+					}
+				})
+			})
+		}
+	})
+}
+
+// These tests cover the JSON syntax configuration edge case handling,
+// the background of which is described in detail in comments in the
+// evalVariableValidations function. Future versions of Terraform may
+// be able to remove this behaviour altogether.
+func TestEvalVariableValidations_jsonErrorMessageEdgeCase(t *testing.T) {
+	cfgSrc := `{
+  "variable": {
+    "valid": {
+      "type": "string",
+      "validation": {
+        "condition": "${var.valid != \"bar\"}",
+        "error_message": "Valid template string ${var.valid}"
+      }
+    },
+    "invalid": {
+      "type": "string",
+      "validation": {
+        "condition": "${var.invalid != \"bar\"}",
+        "error_message": "Invalid template string ${"
+      }
+    }
+  }
+}
+`
+	cfg := testModuleInline(t, map[string]string{
+		"main.tf.json": cfgSrc,
+	})
+	variableConfigs := cfg.Module.Variables
+
+	// Because we loaded our pseudo-module from a temporary file, the
+	// declaration source ranges will have unpredictable filenames. We'll
+	// fix that here just to make things easier below.
+	for _, vc := range variableConfigs {
+		vc.DeclRange.Filename = "main.tf.json"
+		for _, v := range vc.Validations {
+			v.DeclRange.Filename = "main.tf.json"
+		}
+	}
+
+	tests := []struct {
+		varName  string
+		given    cty.Value
+		wantErr  []string
+		wantWarn []string
+	}{
+		// Valid variable validation declaration, assigned value which passes
+		// the condition generates no diagnostics.
+		{
+			varName: "valid",
+			given:   cty.StringVal("foo"),
+		},
+		// Assigning a value which fails the condition generates an error
+		// message with the expression successfully evaluated.
+		{
+			varName: "valid",
+			given:   cty.StringVal("bar"),
+			wantErr: []string{
+				"Invalid value for variable",
+				"Valid template string bar",
+			},
+		},
+		// Invalid variable validation declaration due to an unparseable
+		// template string. Assigning a value which passes the condition
+		// results in a warning about the error message.
+		{
+			varName: "invalid",
+			given:   cty.StringVal("foo"),
+			wantWarn: []string{
+				"Validation error message expression is invalid",
+				"Missing expression; Expected the start of an expression, but found the end of the file.",
+			},
+		},
+		// Assigning a value which fails the condition generates an error
+		// message including the configured string interpreted as a literal
+		// value, and the same warning diagnostic as above.
+		{
+			varName: "invalid",
+			given:   cty.StringVal("bar"),
+			wantErr: []string{
+				"Invalid value for variable",
+				"Invalid template string ${",
+			},
+			wantWarn: []string{
+				"Validation error message expression is invalid",
+				"Missing expression; Expected the start of an expression, but found the end of the file.",
+			},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%s %#v", test.varName, test.given), func(t *testing.T) {
+			varAddr := addrs.InputVariable{Name: test.varName}.Absolute(addrs.RootModuleInstance)
+			varCfg := variableConfigs[test.varName]
+			if varCfg == nil {
+				t.Fatalf("invalid variable name %q", test.varName)
+			}
+
+			// Build a mock context to allow the function under test to
+			// retrieve the variable value and evaluate the expressions
+			ctx := &MockEvalContext{}
+
+			// We need a minimal scope to allow basic functions to be passed to
+			// the HCL scope
+			ctx.EvaluationScopeScope = &lang.Scope{}
+			ctx.GetVariableValueFunc = func(addr addrs.AbsInputVariableInstance) cty.Value {
+				if got, want := addr.String(), varAddr.String(); got != want {
+					t.Errorf("incorrect argument to GetVariableValue: got %s, want %s", got, want)
+				}
+				return test.given
+			}
+
+			gotDiags := evalVariableValidations(
+				varAddr, varCfg, nil, ctx,
+			)
+
+			if len(test.wantErr) == 0 && len(test.wantWarn) == 0 {
+				if len(gotDiags) > 0 {
+					t.Errorf("no diags expected, got %s", gotDiags.Err().Error())
+				}
+			} else {
+			wantErrs:
+				for _, want := range test.wantErr {
+					for _, diag := range gotDiags {
+						if diag.Severity() != tfdiags.Error {
+							continue
+						}
+						desc := diag.Description()
+						if strings.Contains(desc.Summary, want) || strings.Contains(desc.Detail, want) {
+							continue wantErrs
+						}
+					}
+					t.Errorf("no error diagnostics found containing %q\ngot: %s", want, gotDiags.Err().Error())
+				}
+
+			wantWarns:
+				for _, want := range test.wantWarn {
+					for _, diag := range gotDiags {
+						if diag.Severity() != tfdiags.Warning {
+							continue
+						}
+						desc := diag.Description()
+						if strings.Contains(desc.Summary, want) || strings.Contains(desc.Detail, want) {
+							continue wantWarns
+						}
+					}
+					t.Errorf("no warning diagnostics found containing %q\ngot: %s", want, gotDiags.Err().Error())
+				}
+			}
+		})
+	}
+}
+
+func TestEvalVariableValidations_sensitiveValues(t *testing.T) {
+	cfgSrc := `
+variable "foo" {
+  type      = string
+  sensitive = true
+  default   = "boop"
+
+  validation {
+    condition     = length(var.foo) == 4
+	error_message = "Foo must be 4 characters, not ${length(var.foo)}"
+  }
+}
+
+variable "bar" {
+  type      = string
+  sensitive = true
+  default   = "boop"
+
+  validation {
+    condition     = length(var.bar) == 4
+	error_message = "Bar must be 4 characters, not ${nonsensitive(length(var.bar))}."
+  }
+}
+`
+	cfg := testModuleInline(t, map[string]string{
+		"main.tf": cfgSrc,
+	})
+	variableConfigs := cfg.Module.Variables
+
+	// Because we loaded our pseudo-module from a temporary file, the
+	// declaration source ranges will have unpredictable filenames. We'll
+	// fix that here just to make things easier below.
+	for _, vc := range variableConfigs {
+		vc.DeclRange.Filename = "main.tf"
+		for _, v := range vc.Validations {
+			v.DeclRange.Filename = "main.tf"
+		}
+	}
+
+	tests := []struct {
+		varName string
+		given   cty.Value
+		wantErr []string
+	}{
+		// Validations pass on a sensitive variable with an error message which
+		// would generate a sensitive value
+		{
+			varName: "foo",
+			given:   cty.StringVal("boop"),
+		},
+		// Assigning a value which fails the condition generates a sensitive
+		// error message, which is elided and generates another error
+		{
+			varName: "foo",
+			given:   cty.StringVal("bap"),
+			wantErr: []string{
+				"Invalid value for variable",
+				"The error message included a sensitive value, so it will not be displayed.",
+				"Error message refers to sensitive values",
+			},
+		},
+		// Validations pass on a sensitive variable with a correctly defined
+		// error message
+		{
+			varName: "bar",
+			given:   cty.StringVal("boop"),
+		},
+		// Assigning a value which fails the condition generates a nonsensitive
+		// error message, which is displayed
+		{
+			varName: "bar",
+			given:   cty.StringVal("bap"),
+			wantErr: []string{
+				"Invalid value for variable",
+				"Bar must be 4 characters, not 3.",
+			},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(fmt.Sprintf("%s %#v", test.varName, test.given), func(t *testing.T) {
+			varAddr := addrs.InputVariable{Name: test.varName}.Absolute(addrs.RootModuleInstance)
+			varCfg := variableConfigs[test.varName]
+			if varCfg == nil {
+				t.Fatalf("invalid variable name %q", test.varName)
+			}
+
+			// Build a mock context to allow the function under test to
+			// retrieve the variable value and evaluate the expressions
+			ctx := &MockEvalContext{}
+
+			// We need a minimal scope to allow basic functions to be passed to
+			// the HCL scope
+			ctx.EvaluationScopeScope = &lang.Scope{}
+			ctx.GetVariableValueFunc = func(addr addrs.AbsInputVariableInstance) cty.Value {
+				if got, want := addr.String(), varAddr.String(); got != want {
+					t.Errorf("incorrect argument to GetVariableValue: got %s, want %s", got, want)
+				}
+				if varCfg.Sensitive {
+					return test.given.Mark(marks.Sensitive)
+				} else {
+					return test.given
+				}
+			}
+
+			gotDiags := evalVariableValidations(
+				varAddr, varCfg, nil, ctx,
+			)
+
+			if len(test.wantErr) == 0 {
+				if len(gotDiags) > 0 {
+					t.Errorf("no diags expected, got %s", gotDiags.Err().Error())
+				}
+			} else {
+			wantErrs:
+				for _, want := range test.wantErr {
+					for _, diag := range gotDiags {
+						if diag.Severity() != tfdiags.Error {
+							continue
+						}
+						desc := diag.Description()
+						if strings.Contains(desc.Summary, want) || strings.Contains(desc.Detail, want) {
+							continue wantErrs
+						}
+					}
+					t.Errorf("no error diagnostics found containing %q\ngot: %s", want, gotDiags.Err().Error())
+				}
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/terraform/evaluate.go b/v1.5.7/internal/terraform/evaluate.go
new file mode 100644
index 0000000..a92b8df
--- /dev/null
+++ b/v1.5.7/internal/terraform/evaluate.go
@@ -0,0 +1,974 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"path/filepath"
+	"sync"
+	"time"
+
+	"github.com/agext/levenshtein"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// Evaluator provides the necessary contextual data for evaluating expressions
+// for a particular walk operation.
+type Evaluator struct {
+	// Operation defines what type of operation this evaluator is being used
+	// for.
+	Operation walkOperation
+
+	// Meta is contextual metadata about the current operation.
+	Meta *ContextMeta
+
+	// Config is the root node in the configuration tree.
+	Config *configs.Config
+
+	// VariableValues is a map from variable names to their associated values,
+	// within the module indicated by ModulePath. VariableValues is modified
+	// concurrently, and so it must be accessed only while holding
+	// VariableValuesLock.
+	//
+	// The first map level is string representations of addr.ModuleInstance
+	// values, while the second level is variable names.
+	VariableValues     map[string]map[string]cty.Value
+	VariableValuesLock *sync.Mutex
+
+	// Plugins is the library of available plugin components (providers and
+	// provisioners) that we have available to help us evaluate expressions
+	// that interact with plugin-provided objects.
+	//
+	// From this we only access the schemas of the plugins, and don't otherwise
+	// interact with plugin instances.
+	Plugins *contextPlugins
+
+	// State is the current state, embedded in a wrapper that ensures that
+	// it can be safely accessed and modified concurrently.
+	State *states.SyncState
+
+	// Changes is the set of proposed changes, embedded in a wrapper that
+	// ensures they can be safely accessed and modified concurrently.
+	Changes *plans.ChangesSync
+
+	PlanTimestamp time.Time
+}
+
+// Scope creates an evaluation scope for the given module path and optional
+// resource.
+//
+// If the "self" argument is nil then the "self" object is not available
+// in evaluated expressions. Otherwise, it behaves as an alias for the given
+// address.
+func (e *Evaluator) Scope(data lang.Data, self addrs.Referenceable, source addrs.Referenceable) *lang.Scope {
+	return &lang.Scope{
+		Data:          data,
+		SelfAddr:      self,
+		SourceAddr:    source,
+		PureOnly:      e.Operation != walkApply && e.Operation != walkDestroy && e.Operation != walkEval,
+		BaseDir:       ".", // Always current working directory for now.
+		PlanTimestamp: e.PlanTimestamp,
+	}
+}
+
+// evaluationStateData is an implementation of lang.Data that resolves
+// references primarily (but not exclusively) using information from a State.
+type evaluationStateData struct {
+	Evaluator *Evaluator
+
+	// ModulePath is the path through the dynamic module tree to the module
+	// that references will be resolved relative to.
+	ModulePath addrs.ModuleInstance
+
+	// InstanceKeyData describes the values, if any, that are accessible due
+	// to repetition of a containing object using "count" or "for_each"
+	// arguments. (It is _not_ used for the for_each inside "dynamic" blocks,
+	// since the user specifies in that case which variable name to locally
+	// shadow.)
+	InstanceKeyData InstanceKeyEvalData
+
+	// Operation records the type of walk the evaluationStateData is being used
+	// for.
+	Operation walkOperation
+}
+
+// InstanceKeyEvalData is the old name for instances.RepetitionData, aliased
+// here for compatibility. In new code, use instances.RepetitionData instead.
+type InstanceKeyEvalData = instances.RepetitionData
+
+// EvalDataForInstanceKey constructs a suitable InstanceKeyEvalData for
+// evaluating in a context that has the given instance key.
+//
+// The forEachMap argument can be nil when preparing for evaluation
+// in a context where each.value is prohibited, such as a destroy-time
+// provisioner. In that case, the returned EachValue will always be
+// cty.NilVal.
+func EvalDataForInstanceKey(key addrs.InstanceKey, forEachMap map[string]cty.Value) InstanceKeyEvalData {
+	var evalData InstanceKeyEvalData
+	if key == nil {
+		return evalData
+	}
+
+	keyValue := key.Value()
+	switch keyValue.Type() {
+	case cty.String:
+		evalData.EachKey = keyValue
+		evalData.EachValue = forEachMap[keyValue.AsString()]
+	case cty.Number:
+		evalData.CountIndex = keyValue
+	}
+	return evalData
+}
+
+// EvalDataForNoInstanceKey is a value of InstanceKeyData that sets no instance
+// key values at all, suitable for use in contexts where no keyed instance
+// is relevant.
+var EvalDataForNoInstanceKey = InstanceKeyEvalData{}
+
+// evaluationStateData must implement lang.Data
+var _ lang.Data = (*evaluationStateData)(nil)
+
+func (d *evaluationStateData) GetCountAttr(addr addrs.CountAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	switch addr.Name {
+
+	case "index":
+		idxVal := d.InstanceKeyData.CountIndex
+		if idxVal == cty.NilVal {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  `Reference to "count" in non-counted context`,
+				Detail:   `The "count" object can only be used in "module", "resource", and "data" blocks, and only when the "count" argument is set.`,
+				Subject:  rng.ToHCL().Ptr(),
+			})
+			return cty.UnknownVal(cty.Number), diags
+		}
+		return idxVal, diags
+
+	default:
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Invalid "count" attribute`,
+			Detail:   fmt.Sprintf(`The "count" object does not have an attribute named %q. The only supported attribute is count.index, which is the index of each instance of a resource block that has the "count" argument set.`, addr.Name),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+		return cty.DynamicVal, diags
+	}
+}
+
+func (d *evaluationStateData) GetForEachAttr(addr addrs.ForEachAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	var returnVal cty.Value
+	switch addr.Name {
+
+	case "key":
+		returnVal = d.InstanceKeyData.EachKey
+	case "value":
+		returnVal = d.InstanceKeyData.EachValue
+
+		if returnVal == cty.NilVal {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  `each.value cannot be used in this context`,
+				Detail:   `A reference to "each.value" has been used in a context in which it is unavailable, such as when the configuration no longer contains the value in its "for_each" expression. Remove this reference to each.value in your configuration to work around this error.`,
+				Subject:  rng.ToHCL().Ptr(),
+			})
+			return cty.UnknownVal(cty.DynamicPseudoType), diags
+		}
+	default:
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Invalid "each" attribute`,
+			Detail:   fmt.Sprintf(`The "each" object does not have an attribute named %q. The supported attributes are each.key and each.value, the current key and value pair of the "for_each" attribute set.`, addr.Name),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+		return cty.DynamicVal, diags
+	}
+
+	if returnVal == cty.NilVal {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Reference to "each" in context without for_each`,
+			Detail:   `The "each" object can be used only in "module" or "resource" blocks, and only when the "for_each" argument is set.`,
+			Subject:  rng.ToHCL().Ptr(),
+		})
+		return cty.UnknownVal(cty.DynamicPseudoType), diags
+	}
+	return returnVal, diags
+}
+
+func (d *evaluationStateData) GetInputVariable(addr addrs.InputVariable, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// First we'll make sure the requested value is declared in configuration,
+	// so we can produce a nice message if not.
+	moduleConfig := d.Evaluator.Config.DescendentForInstance(d.ModulePath)
+	if moduleConfig == nil {
+		// should never happen, since we can't be evaluating in a module
+		// that wasn't mentioned in configuration.
+		panic(fmt.Sprintf("input variable read from %s, which has no configuration", d.ModulePath))
+	}
+
+	config := moduleConfig.Module.Variables[addr.Name]
+	if config == nil {
+		var suggestions []string
+		for k := range moduleConfig.Module.Variables {
+			suggestions = append(suggestions, k)
+		}
+		suggestion := nameSuggestion(addr.Name, suggestions)
+		if suggestion != "" {
+			suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
+		} else {
+			suggestion = fmt.Sprintf(" This variable can be declared with a variable %q {} block.", addr.Name)
+		}
+
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Reference to undeclared input variable`,
+			Detail:   fmt.Sprintf(`An input variable with the name %q has not been declared.%s`, addr.Name, suggestion),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+		return cty.DynamicVal, diags
+	}
+	d.Evaluator.VariableValuesLock.Lock()
+	defer d.Evaluator.VariableValuesLock.Unlock()
+
+	// During the validate walk, input variables are always unknown so
+	// that we are validating the configuration for all possible input values
+	// rather than for a specific set. Checking against a specific set of
+	// input values then happens during the plan walk.
+	//
+	// This is important because otherwise the validation walk will tend to be
+	// overly strict, requiring expressions throughout the configuration to
+	// be complicated to accommodate all possible inputs, whereas returning
+	// unknown here allows for simpler patterns like using input values as
+	// guards to broadly enable/disable resources, avoid processing things
+	// that are disabled, etc. Terraform's static validation leans towards
+	// being liberal in what it accepts because the subsequent plan walk has
+	// more information available and so can be more conservative.
+	if d.Operation == walkValidate {
+		// Ensure variable sensitivity is captured in the validate walk
+		if config.Sensitive {
+			return cty.UnknownVal(config.Type).Mark(marks.Sensitive), diags
+		}
+		return cty.UnknownVal(config.Type), diags
+	}
+
+	moduleAddrStr := d.ModulePath.String()
+	vals := d.Evaluator.VariableValues[moduleAddrStr]
+	if vals == nil {
+		return cty.UnknownVal(config.Type), diags
+	}
+
+	// d.Evaluator.VariableValues should always contain valid "final values"
+	// for variables, which is to say that they have already had type
+	// conversions, validations, and default value handling applied to them.
+	// Those are the responsibility of the graph notes representing the
+	// variable declarations. Therefore here we just trust that we already
+	// have a correct value.
+
+	val, isSet := vals[addr.Name]
+	if !isSet {
+		// We should not be able to get here without having a valid value
+		// for every variable, so this always indicates a bug in either
+		// the graph builder (not including all the needed nodes) or in
+		// the graph nodes representing variables.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Reference to unresolved input variable`,
+			Detail: fmt.Sprintf(
+				`The final value for %s is missing in Terraform's evaluation context. This is a bug in Terraform; please report it!`,
+				addr.Absolute(d.ModulePath),
+			),
+			Subject: rng.ToHCL().Ptr(),
+		})
+		val = cty.UnknownVal(config.Type)
+	}
+
+	// Mark if sensitive
+	if config.Sensitive {
+		val = val.Mark(marks.Sensitive)
+	}
+
+	return val, diags
+}
+
+func (d *evaluationStateData) GetLocalValue(addr addrs.LocalValue, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// First we'll make sure the requested value is declared in configuration,
+	// so we can produce a nice message if not.
+	moduleConfig := d.Evaluator.Config.DescendentForInstance(d.ModulePath)
+	if moduleConfig == nil {
+		// should never happen, since we can't be evaluating in a module
+		// that wasn't mentioned in configuration.
+		panic(fmt.Sprintf("local value read from %s, which has no configuration", d.ModulePath))
+	}
+
+	config := moduleConfig.Module.Locals[addr.Name]
+	if config == nil {
+		var suggestions []string
+		for k := range moduleConfig.Module.Locals {
+			suggestions = append(suggestions, k)
+		}
+		suggestion := nameSuggestion(addr.Name, suggestions)
+		if suggestion != "" {
+			suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
+		}
+
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Reference to undeclared local value`,
+			Detail:   fmt.Sprintf(`A local value with the name %q has not been declared.%s`, addr.Name, suggestion),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+		return cty.DynamicVal, diags
+	}
+
+	val := d.Evaluator.State.LocalValue(addr.Absolute(d.ModulePath))
+	if val == cty.NilVal {
+		// Not evaluated yet?
+		val = cty.DynamicVal
+	}
+
+	return val, diags
+}
+
+func (d *evaluationStateData) GetModule(addr addrs.ModuleCall, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// Output results live in the module that declares them, which is one of
+	// the child module instances of our current module path.
+	moduleAddr := d.ModulePath.Module().Child(addr.Name)
+
+	parentCfg := d.Evaluator.Config.DescendentForInstance(d.ModulePath)
+	callConfig, ok := parentCfg.Module.ModuleCalls[addr.Name]
+	if !ok {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Reference to undeclared module`,
+			Detail:   fmt.Sprintf(`The configuration contains no %s.`, moduleAddr),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+		return cty.DynamicVal, diags
+	}
+
+	// We'll consult the configuration to see what output names we are
+	// expecting, so we can ensure the resulting object is of the expected
+	// type even if our data is incomplete for some reason.
+	moduleConfig := d.Evaluator.Config.Descendent(moduleAddr)
+	if moduleConfig == nil {
+		// should never happen, since we have a valid module call above, this
+		// should be caught during static validation.
+		panic(fmt.Sprintf("output value read from %s, which has no configuration", moduleAddr))
+	}
+	outputConfigs := moduleConfig.Module.Outputs
+
+	// Collect all the relevant outputs that current exist in the state.
+	// We know the instance path up to this point, and the child module name,
+	// so we only need to store these by instance key.
+	stateMap := map[addrs.InstanceKey]map[string]cty.Value{}
+	for _, output := range d.Evaluator.State.ModuleOutputs(d.ModulePath, addr) {
+		val := output.Value
+		if output.Sensitive {
+			val = val.Mark(marks.Sensitive)
+		}
+
+		_, callInstance := output.Addr.Module.CallInstance()
+		instance, ok := stateMap[callInstance.Key]
+		if !ok {
+			instance = map[string]cty.Value{}
+			stateMap[callInstance.Key] = instance
+		}
+
+		instance[output.Addr.OutputValue.Name] = val
+	}
+
+	// Get all changes that reside for this module call within our path.
+	// The change contains the full addr, so we can key these with strings.
+	changesMap := map[addrs.InstanceKey]map[string]*plans.OutputChangeSrc{}
+	for _, change := range d.Evaluator.Changes.GetOutputChanges(d.ModulePath, addr) {
+		_, callInstance := change.Addr.Module.CallInstance()
+		instance, ok := changesMap[callInstance.Key]
+		if !ok {
+			instance = map[string]*plans.OutputChangeSrc{}
+			changesMap[callInstance.Key] = instance
+		}
+
+		instance[change.Addr.OutputValue.Name] = change
+	}
+
+	// Build up all the module objects, creating a map of values for each
+	// module instance.
+	moduleInstances := map[addrs.InstanceKey]map[string]cty.Value{}
+
+	// create a dummy object type for validation below
+	unknownMap := map[string]cty.Type{}
+
+	// the structure is based on the configuration, so iterate through all the
+	// defined outputs, and add any instance state or changes we find.
+	for _, cfg := range outputConfigs {
+		// record the output names for validation
+		unknownMap[cfg.Name] = cty.DynamicPseudoType
+
+		// get all instance output for this path from the state
+		for key, states := range stateMap {
+			outputState, ok := states[cfg.Name]
+			if !ok {
+				continue
+			}
+
+			instance, ok := moduleInstances[key]
+			if !ok {
+				instance = map[string]cty.Value{}
+				moduleInstances[key] = instance
+			}
+
+			instance[cfg.Name] = outputState
+		}
+
+		// any pending changes override the state state values
+		for key, changes := range changesMap {
+			changeSrc, ok := changes[cfg.Name]
+			if !ok {
+				continue
+			}
+
+			instance, ok := moduleInstances[key]
+			if !ok {
+				instance = map[string]cty.Value{}
+				moduleInstances[key] = instance
+			}
+
+			change, err := changeSrc.Decode()
+			if err != nil {
+				// This should happen only if someone has tampered with a plan
+				// file, so we won't bother with a pretty error for it.
+				diags = diags.Append(fmt.Errorf("planned change for %s could not be decoded: %s", addr, err))
+				instance[cfg.Name] = cty.DynamicVal
+				continue
+			}
+
+			instance[cfg.Name] = change.After
+
+			if change.Sensitive {
+				instance[cfg.Name] = change.After.Mark(marks.Sensitive)
+			}
+		}
+	}
+
+	var ret cty.Value
+
+	// compile the outputs into the correct value type for the each mode
+	switch {
+	case callConfig.Count != nil:
+		// figure out what the last index we have is
+		length := -1
+		for key := range moduleInstances {
+			intKey, ok := key.(addrs.IntKey)
+			if !ok {
+				// old key from state which is being dropped
+				continue
+			}
+			if int(intKey) >= length {
+				length = int(intKey) + 1
+			}
+		}
+
+		if length > 0 {
+			vals := make([]cty.Value, length)
+			for key, instance := range moduleInstances {
+				intKey, ok := key.(addrs.IntKey)
+				if !ok {
+					// old key from state which is being dropped
+					continue
+				}
+
+				vals[int(intKey)] = cty.ObjectVal(instance)
+			}
+
+			// Insert unknown values where there are any missing instances
+			for i, v := range vals {
+				if v.IsNull() {
+					vals[i] = cty.DynamicVal
+					continue
+				}
+			}
+			ret = cty.TupleVal(vals)
+		} else {
+			ret = cty.EmptyTupleVal
+		}
+
+	case callConfig.ForEach != nil:
+		vals := make(map[string]cty.Value)
+		for key, instance := range moduleInstances {
+			strKey, ok := key.(addrs.StringKey)
+			if !ok {
+				continue
+			}
+
+			vals[string(strKey)] = cty.ObjectVal(instance)
+		}
+
+		if len(vals) > 0 {
+			ret = cty.ObjectVal(vals)
+		} else {
+			ret = cty.EmptyObjectVal
+		}
+
+	default:
+		val, ok := moduleInstances[addrs.NoKey]
+		if !ok {
+			// create the object if there wasn't one known
+			val = map[string]cty.Value{}
+			for k := range outputConfigs {
+				val[k] = cty.DynamicVal
+			}
+		}
+
+		ret = cty.ObjectVal(val)
+	}
+
+	// The module won't be expanded during validation, so we need to return an
+	// unknown value. This will ensure the types looks correct, since we built
+	// the objects based on the configuration.
+	if d.Operation == walkValidate {
+		// While we know the type here and it would be nice to validate whether
+		// indexes are valid or not, because tuples and objects have fixed
+		// numbers of elements we can't simply return an unknown value of the
+		// same type since we have not expanded any instances during
+		// validation.
+		//
+		// In order to validate the expression a little precisely, we'll create
+		// an unknown map or list here to get more type information.
+		ty := cty.Object(unknownMap)
+		switch {
+		case callConfig.Count != nil:
+			ret = cty.UnknownVal(cty.List(ty))
+		case callConfig.ForEach != nil:
+			ret = cty.UnknownVal(cty.Map(ty))
+		default:
+			ret = cty.UnknownVal(ty)
+		}
+	}
+
+	return ret, diags
+}
+
+func (d *evaluationStateData) GetPathAttr(addr addrs.PathAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	switch addr.Name {
+
+	case "cwd":
+		var err error
+		var wd string
+		if d.Evaluator.Meta != nil {
+			// Meta is always non-nil in the normal case, but some test cases
+			// are not so realistic.
+			wd = d.Evaluator.Meta.OriginalWorkingDir
+		}
+		if wd == "" {
+			wd, err = os.Getwd()
+			if err != nil {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  `Failed to get working directory`,
+					Detail:   fmt.Sprintf(`The value for path.cwd cannot be determined due to a system error: %s`, err),
+					Subject:  rng.ToHCL().Ptr(),
+				})
+				return cty.DynamicVal, diags
+			}
+		}
+		// The current working directory should always be absolute, whether we
+		// just looked it up or whether we were relying on ContextMeta's
+		// (possibly non-normalized) path.
+		wd, err = filepath.Abs(wd)
+		if err != nil {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  `Failed to get working directory`,
+				Detail:   fmt.Sprintf(`The value for path.cwd cannot be determined due to a system error: %s`, err),
+				Subject:  rng.ToHCL().Ptr(),
+			})
+			return cty.DynamicVal, diags
+		}
+
+		return cty.StringVal(filepath.ToSlash(wd)), diags
+
+	case "module":
+		moduleConfig := d.Evaluator.Config.DescendentForInstance(d.ModulePath)
+		if moduleConfig == nil {
+			// should never happen, since we can't be evaluating in a module
+			// that wasn't mentioned in configuration.
+			panic(fmt.Sprintf("module.path read from module %s, which has no configuration", d.ModulePath))
+		}
+		sourceDir := moduleConfig.Module.SourceDir
+		return cty.StringVal(filepath.ToSlash(sourceDir)), diags
+
+	case "root":
+		sourceDir := d.Evaluator.Config.Module.SourceDir
+		return cty.StringVal(filepath.ToSlash(sourceDir)), diags
+
+	default:
+		suggestion := nameSuggestion(addr.Name, []string{"cwd", "module", "root"})
+		if suggestion != "" {
+			suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
+		}
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Invalid "path" attribute`,
+			Detail:   fmt.Sprintf(`The "path" object does not have an attribute named %q.%s`, addr.Name, suggestion),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+		return cty.DynamicVal, diags
+	}
+}
+
+func (d *evaluationStateData) GetResource(addr addrs.Resource, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	// First we'll consult the configuration to see if an resource of this
+	// name is declared at all.
+	moduleAddr := d.ModulePath
+	moduleConfig := d.Evaluator.Config.DescendentForInstance(moduleAddr)
+	if moduleConfig == nil {
+		// should never happen, since we can't be evaluating in a module
+		// that wasn't mentioned in configuration.
+		panic(fmt.Sprintf("resource value read from %s, which has no configuration", moduleAddr))
+	}
+
+	config := moduleConfig.Module.ResourceByAddr(addr)
+	if config == nil {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Reference to undeclared resource`,
+			Detail:   fmt.Sprintf(`A resource %q %q has not been declared in %s`, addr.Type, addr.Name, moduleDisplayAddr(moduleAddr)),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+		return cty.DynamicVal, diags
+	}
+
+	// Build the provider address from configuration, since we may not have
+	// state available in all cases.
+	// We need to build an abs provider address, but we can use a default
+	// instance since we're only interested in the schema.
+	schema := d.getResourceSchema(addr, config.Provider)
+	if schema == nil {
+		// This shouldn't happen, since validation before we get here should've
+		// taken care of it, but we'll show a reasonable error message anyway.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Missing resource type schema`,
+			Detail:   fmt.Sprintf("No schema is available for %s in %s. This is a bug in Terraform and should be reported.", addr, config.Provider),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+		return cty.DynamicVal, diags
+	}
+	ty := schema.ImpliedType()
+
+	rs := d.Evaluator.State.Resource(addr.Absolute(d.ModulePath))
+
+	if rs == nil {
+		switch d.Operation {
+		case walkPlan, walkApply:
+			// During plan and apply as we evaluate each removed instance they
+			// are removed from the working state. Since we know there are no
+			// instances, return an empty container of the expected type.
+			switch {
+			case config.Count != nil:
+				return cty.EmptyTupleVal, diags
+			case config.ForEach != nil:
+				return cty.EmptyObjectVal, diags
+			default:
+				// While we can reference an expanded resource with 0
+				// instances, we cannot reference instances that do not exist.
+				// Due to the fact that we may have direct references to
+				// instances that may end up in a root output during destroy
+				// (since a planned destroy cannot yet remove root outputs), we
+				// need to return a dynamic value here to allow evaluation to
+				// continue.
+				log.Printf("[ERROR] unknown instance %q referenced during %s", addr.Absolute(d.ModulePath), d.Operation)
+				return cty.DynamicVal, diags
+			}
+
+		case walkImport:
+			// Import does not yet plan resource changes, so new resources from
+			// config are not going to be found here. Once walkImport fully
+			// plans resources, this case should not longer be needed.
+			// In the single instance case, we can return a typed unknown value
+			// for the instance to better satisfy other expressions using the
+			// value. This of course will not help if statically known
+			// attributes are expected to be known elsewhere, but reduces the
+			// number of problematic configs for now.
+			// Unlike in plan and apply above we can't be sure the count or
+			// for_each instances are empty, so we return a DynamicVal. We
+			// don't really have a good value to return otherwise -- empty
+			// values will fail for direct index expressions, and unknown
+			// Lists and Maps could fail in some type unifications.
+			switch {
+			case config.Count != nil:
+				return cty.DynamicVal, diags
+			case config.ForEach != nil:
+				return cty.DynamicVal, diags
+			default:
+				return cty.UnknownVal(ty), diags
+			}
+
+		default:
+			// We should only end up here during the validate walk,
+			// since later walks should have at least partial states populated
+			// for all resources in the configuration.
+			return cty.DynamicVal, diags
+		}
+	}
+
+	// Decode all instances in the current state
+	instances := map[addrs.InstanceKey]cty.Value{}
+	pendingDestroy := d.Operation == walkDestroy
+	for key, is := range rs.Instances {
+		if is == nil || is.Current == nil {
+			// Assume we're dealing with an instance that hasn't been created yet.
+			instances[key] = cty.UnknownVal(ty)
+			continue
+		}
+
+		instAddr := addr.Instance(key).Absolute(d.ModulePath)
+
+		change := d.Evaluator.Changes.GetResourceInstanceChange(instAddr, states.CurrentGen)
+		if change != nil {
+			// Don't take any resources that are yet to be deleted into account.
+			// If the referenced resource is CreateBeforeDestroy, then orphaned
+			// instances will be in the state, as they are not destroyed until
+			// after their dependants are updated.
+			if change.Action == plans.Delete {
+				if !pendingDestroy {
+					continue
+				}
+			}
+		}
+
+		// Planned resources are temporarily stored in state with empty values,
+		// and need to be replaced by the planned value here.
+		if is.Current.Status == states.ObjectPlanned {
+			if change == nil {
+				// If the object is in planned status then we should not get
+				// here, since we should have found a pending value in the plan
+				// above instead.
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Missing pending object in plan",
+					Detail:   fmt.Sprintf("Instance %s is marked as having a change pending but that change is not recorded in the plan. This is a bug in Terraform; please report it.", instAddr),
+					Subject:  &config.DeclRange,
+				})
+				continue
+			}
+			val, err := change.After.Decode(ty)
+			if err != nil {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Invalid resource instance data in plan",
+					Detail:   fmt.Sprintf("Instance %s data could not be decoded from the plan: %s.", instAddr, err),
+					Subject:  &config.DeclRange,
+				})
+				continue
+			}
+
+			// If our provider schema contains sensitive values, mark those as sensitive
+			afterMarks := change.AfterValMarks
+			if schema.ContainsSensitive() {
+				afterMarks = append(afterMarks, schema.ValueMarks(val, nil)...)
+			}
+
+			instances[key] = val.MarkWithPaths(afterMarks)
+			continue
+		}
+
+		ios, err := is.Current.Decode(ty)
+		if err != nil {
+			// This shouldn't happen, since by the time we get here we
+			// should have upgraded the state data already.
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid resource instance data in state",
+				Detail:   fmt.Sprintf("Instance %s data could not be decoded from the state: %s.", instAddr, err),
+				Subject:  &config.DeclRange,
+			})
+			continue
+		}
+
+		val := ios.Value
+
+		// If our schema contains sensitive values, mark those as sensitive.
+		// Since decoding the instance object can also apply sensitivity marks,
+		// we must remove and combine those before remarking to avoid a double-
+		// mark error.
+		if schema.ContainsSensitive() {
+			var marks []cty.PathValueMarks
+			val, marks = val.UnmarkDeepWithPaths()
+			marks = append(marks, schema.ValueMarks(val, nil)...)
+			val = val.MarkWithPaths(marks)
+		}
+		instances[key] = val
+	}
+
+	// ret should be populated with a valid value in all cases below
+	var ret cty.Value
+
+	switch {
+	case config.Count != nil:
+		// figure out what the last index we have is
+		length := -1
+		for key := range instances {
+			intKey, ok := key.(addrs.IntKey)
+			if !ok {
+				continue
+			}
+			if int(intKey) >= length {
+				length = int(intKey) + 1
+			}
+		}
+
+		if length > 0 {
+			vals := make([]cty.Value, length)
+			for key, instance := range instances {
+				intKey, ok := key.(addrs.IntKey)
+				if !ok {
+					// old key from state, which isn't valid for evaluation
+					continue
+				}
+
+				vals[int(intKey)] = instance
+			}
+
+			// Insert unknown values where there are any missing instances
+			for i, v := range vals {
+				if v == cty.NilVal {
+					vals[i] = cty.UnknownVal(ty)
+				}
+			}
+			ret = cty.TupleVal(vals)
+		} else {
+			ret = cty.EmptyTupleVal
+		}
+
+	case config.ForEach != nil:
+		vals := make(map[string]cty.Value)
+		for key, instance := range instances {
+			strKey, ok := key.(addrs.StringKey)
+			if !ok {
+				// old key that is being dropped and not used for evaluation
+				continue
+			}
+			vals[string(strKey)] = instance
+		}
+
+		if len(vals) > 0 {
+			// We use an object rather than a map here because resource schemas
+			// may include dynamically-typed attributes, which will then cause
+			// each instance to potentially have a different runtime type even
+			// though they all conform to the static schema.
+			ret = cty.ObjectVal(vals)
+		} else {
+			ret = cty.EmptyObjectVal
+		}
+
+	default:
+		val, ok := instances[addrs.NoKey]
+		if !ok {
+			// if the instance is missing, insert an unknown value
+			val = cty.UnknownVal(ty)
+		}
+
+		ret = val
+	}
+
+	return ret, diags
+}
+
+func (d *evaluationStateData) getResourceSchema(addr addrs.Resource, providerAddr addrs.Provider) *configschema.Block {
+	schema, _, err := d.Evaluator.Plugins.ResourceTypeSchema(providerAddr, addr.Mode, addr.Type)
+	if err != nil {
+		// We have plently other codepaths that will detect and report
+		// schema lookup errors before we'd reach this point, so we'll just
+		// treat a failure here the same as having no schema.
+		return nil
+	}
+	return schema
+}
+
+func (d *evaluationStateData) GetTerraformAttr(addr addrs.TerraformAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	switch addr.Name {
+
+	case "workspace":
+		workspaceName := d.Evaluator.Meta.Env
+		return cty.StringVal(workspaceName), diags
+
+	case "env":
+		// Prior to Terraform 0.12 there was an attribute "env", which was
+		// an alias name for "workspace". This was deprecated and is now
+		// removed.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Invalid "terraform" attribute`,
+			Detail:   `The terraform.env attribute was deprecated in v0.10 and removed in v0.12. The "state environment" concept was renamed to "workspace" in v0.12, and so the workspace name can now be accessed using the terraform.workspace attribute.`,
+			Subject:  rng.ToHCL().Ptr(),
+		})
+		return cty.DynamicVal, diags
+
+	default:
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Invalid "terraform" attribute`,
+			Detail:   fmt.Sprintf(`The "terraform" object does not have an attribute named %q. The only supported attribute is terraform.workspace, the name of the currently-selected workspace.`, addr.Name),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+		return cty.DynamicVal, diags
+	}
+}
+
+// nameSuggestion tries to find a name from the given slice of suggested names
+// that is close to the given name and returns it if found. If no suggestion
+// is close enough, returns the empty string.
+//
+// The suggestions are tried in order, so earlier suggestions take precedence
+// if the given string is similar to two or more suggestions.
+//
+// This function is intended to be used with a relatively-small number of
+// suggestions. It's not optimized for hundreds or thousands of them.
+func nameSuggestion(given string, suggestions []string) string {
+	for _, suggestion := range suggestions {
+		dist := levenshtein.Distance(given, suggestion, nil)
+		if dist < 3 { // threshold determined experimentally
+			return suggestion
+		}
+	}
+	return ""
+}
+
+// moduleDisplayAddr returns a string describing the given module instance
+// address that is appropriate for returning to users in situations where the
+// root module is possible. Specifically, it returns "the root module" if the
+// root module instance is given, or a string representation of the module
+// address otherwise.
+func moduleDisplayAddr(addr addrs.ModuleInstance) string {
+	switch {
+	case addr.IsRoot():
+		return "the root module"
+	default:
+		return addr.String()
+	}
+}
diff --git a/v1.5.7/internal/terraform/evaluate_test.go b/v1.5.7/internal/terraform/evaluate_test.go
new file mode 100644
index 0000000..7daf2bb
--- /dev/null
+++ b/v1.5.7/internal/terraform/evaluate_test.go
@@ -0,0 +1,569 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"sync"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func TestEvaluatorGetTerraformAttr(t *testing.T) {
+	evaluator := &Evaluator{
+		Meta: &ContextMeta{
+			Env: "foo",
+		},
+	}
+	data := &evaluationStateData{
+		Evaluator: evaluator,
+	}
+	scope := evaluator.Scope(data, nil, nil)
+
+	t.Run("workspace", func(t *testing.T) {
+		want := cty.StringVal("foo")
+		got, diags := scope.Data.GetTerraformAttr(addrs.TerraformAttr{
+			Name: "workspace",
+		}, tfdiags.SourceRange{})
+		if len(diags) != 0 {
+			t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
+		}
+		if !got.RawEquals(want) {
+			t.Errorf("wrong result %q; want %q", got, want)
+		}
+	})
+}
+
+func TestEvaluatorGetPathAttr(t *testing.T) {
+	evaluator := &Evaluator{
+		Meta: &ContextMeta{
+			Env: "foo",
+		},
+		Config: &configs.Config{
+			Module: &configs.Module{
+				SourceDir: "bar/baz",
+			},
+		},
+	}
+	data := &evaluationStateData{
+		Evaluator: evaluator,
+	}
+	scope := evaluator.Scope(data, nil, nil)
+
+	t.Run("module", func(t *testing.T) {
+		want := cty.StringVal("bar/baz")
+		got, diags := scope.Data.GetPathAttr(addrs.PathAttr{
+			Name: "module",
+		}, tfdiags.SourceRange{})
+		if len(diags) != 0 {
+			t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
+		}
+		if !got.RawEquals(want) {
+			t.Errorf("wrong result %#v; want %#v", got, want)
+		}
+	})
+
+	t.Run("root", func(t *testing.T) {
+		want := cty.StringVal("bar/baz")
+		got, diags := scope.Data.GetPathAttr(addrs.PathAttr{
+			Name: "root",
+		}, tfdiags.SourceRange{})
+		if len(diags) != 0 {
+			t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
+		}
+		if !got.RawEquals(want) {
+			t.Errorf("wrong result %#v; want %#v", got, want)
+		}
+	})
+}
+
+// This particularly tests that a sensitive attribute in config
+// results in a value that has a "sensitive" cty Mark
+func TestEvaluatorGetInputVariable(t *testing.T) {
+	evaluator := &Evaluator{
+		Meta: &ContextMeta{
+			Env: "foo",
+		},
+		Config: &configs.Config{
+			Module: &configs.Module{
+				Variables: map[string]*configs.Variable{
+					"some_var": {
+						Name:           "some_var",
+						Sensitive:      true,
+						Default:        cty.StringVal("foo"),
+						Type:           cty.String,
+						ConstraintType: cty.String,
+					},
+					// Avoid double marking a value
+					"some_other_var": {
+						Name:           "some_other_var",
+						Sensitive:      true,
+						Default:        cty.StringVal("bar"),
+						Type:           cty.String,
+						ConstraintType: cty.String,
+					},
+				},
+			},
+		},
+		VariableValues: map[string]map[string]cty.Value{
+			"": {
+				"some_var":       cty.StringVal("bar"),
+				"some_other_var": cty.StringVal("boop").Mark(marks.Sensitive),
+			},
+		},
+		VariableValuesLock: &sync.Mutex{},
+	}
+
+	data := &evaluationStateData{
+		Evaluator: evaluator,
+	}
+	scope := evaluator.Scope(data, nil, nil)
+
+	want := cty.StringVal("bar").Mark(marks.Sensitive)
+	got, diags := scope.Data.GetInputVariable(addrs.InputVariable{
+		Name: "some_var",
+	}, tfdiags.SourceRange{})
+
+	if len(diags) != 0 {
+		t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
+	}
+	if !got.RawEquals(want) {
+		t.Errorf("wrong result %#v; want %#v", got, want)
+	}
+
+	want = cty.StringVal("boop").Mark(marks.Sensitive)
+	got, diags = scope.Data.GetInputVariable(addrs.InputVariable{
+		Name: "some_other_var",
+	}, tfdiags.SourceRange{})
+
+	if len(diags) != 0 {
+		t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
+	}
+	if !got.RawEquals(want) {
+		t.Errorf("wrong result %#v; want %#v", got, want)
+	}
+}
+
+func TestEvaluatorGetResource(t *testing.T) {
+	stateSync := states.BuildState(func(ss *states.SyncState) {
+		ss.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_resource",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectReady,
+				AttrsJSON: []byte(`{"id":"foo", "nesting_list": [{"sensitive_value":"abc"}], "nesting_map": {"foo":{"foo":"x"}}, "nesting_set": [{"baz":"abc"}], "nesting_single": {"boop":"abc"}, "nesting_nesting": {"nesting_list":[{"sensitive_value":"abc"}]}, "value":"hello"}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	}).SyncWrapper()
+
+	rc := &configs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_resource",
+		Name: "foo",
+		Config: configs.SynthBody("", map[string]cty.Value{
+			"id": cty.StringVal("foo"),
+		}),
+		Provider: addrs.Provider{
+			Hostname:  addrs.DefaultProviderRegistryHost,
+			Namespace: "hashicorp",
+			Type:      "test",
+		},
+	}
+
+	evaluator := &Evaluator{
+		Meta: &ContextMeta{
+			Env: "foo",
+		},
+		Changes: plans.NewChanges().SyncWrapper(),
+		Config: &configs.Config{
+			Module: &configs.Module{
+				ManagedResources: map[string]*configs.Resource{
+					"test_resource.foo": rc,
+				},
+			},
+		},
+		State: stateSync,
+		Plugins: schemaOnlyProvidersForTesting(map[addrs.Provider]*ProviderSchema{
+			addrs.NewDefaultProvider("test"): {
+				Provider: &configschema.Block{},
+				ResourceTypes: map[string]*configschema.Block{
+					"test_resource": {
+						Attributes: map[string]*configschema.Attribute{
+							"id": {
+								Type:     cty.String,
+								Computed: true,
+							},
+							"value": {
+								Type:      cty.String,
+								Computed:  true,
+								Sensitive: true,
+							},
+						},
+						BlockTypes: map[string]*configschema.NestedBlock{
+							"nesting_list": {
+								Block: configschema.Block{
+									Attributes: map[string]*configschema.Attribute{
+										"value":           {Type: cty.String, Optional: true},
+										"sensitive_value": {Type: cty.String, Optional: true, Sensitive: true},
+									},
+								},
+								Nesting: configschema.NestingList,
+							},
+							"nesting_map": {
+								Block: configschema.Block{
+									Attributes: map[string]*configschema.Attribute{
+										"foo": {Type: cty.String, Optional: true, Sensitive: true},
+									},
+								},
+								Nesting: configschema.NestingMap,
+							},
+							"nesting_set": {
+								Block: configschema.Block{
+									Attributes: map[string]*configschema.Attribute{
+										"baz": {Type: cty.String, Optional: true, Sensitive: true},
+									},
+								},
+								Nesting: configschema.NestingSet,
+							},
+							"nesting_single": {
+								Block: configschema.Block{
+									Attributes: map[string]*configschema.Attribute{
+										"boop": {Type: cty.String, Optional: true, Sensitive: true},
+									},
+								},
+								Nesting: configschema.NestingSingle,
+							},
+							"nesting_nesting": {
+								Block: configschema.Block{
+									BlockTypes: map[string]*configschema.NestedBlock{
+										"nesting_list": {
+											Block: configschema.Block{
+												Attributes: map[string]*configschema.Attribute{
+													"value":           {Type: cty.String, Optional: true},
+													"sensitive_value": {Type: cty.String, Optional: true, Sensitive: true},
+												},
+											},
+											Nesting: configschema.NestingList,
+										},
+									},
+								},
+								Nesting: configschema.NestingSingle,
+							},
+						},
+					},
+				},
+			},
+		}),
+	}
+
+	data := &evaluationStateData{
+		Evaluator: evaluator,
+	}
+	scope := evaluator.Scope(data, nil, nil)
+
+	want := cty.ObjectVal(map[string]cty.Value{
+		"id": cty.StringVal("foo"),
+		"nesting_list": cty.ListVal([]cty.Value{
+			cty.ObjectVal(map[string]cty.Value{
+				"sensitive_value": cty.StringVal("abc").Mark(marks.Sensitive),
+				"value":           cty.NullVal(cty.String),
+			}),
+		}),
+		"nesting_map": cty.MapVal(map[string]cty.Value{
+			"foo": cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("x").Mark(marks.Sensitive)}),
+		}),
+		"nesting_nesting": cty.ObjectVal(map[string]cty.Value{
+			"nesting_list": cty.ListVal([]cty.Value{
+				cty.ObjectVal(map[string]cty.Value{
+					"sensitive_value": cty.StringVal("abc").Mark(marks.Sensitive),
+					"value":           cty.NullVal(cty.String),
+				}),
+			}),
+		}),
+		"nesting_set": cty.SetVal([]cty.Value{
+			cty.ObjectVal(map[string]cty.Value{
+				"baz": cty.StringVal("abc").Mark(marks.Sensitive),
+			}),
+		}),
+		"nesting_single": cty.ObjectVal(map[string]cty.Value{
+			"boop": cty.StringVal("abc").Mark(marks.Sensitive),
+		}),
+		"value": cty.StringVal("hello").Mark(marks.Sensitive),
+	})
+
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_resource",
+		Name: "foo",
+	}
+	got, diags := scope.Data.GetResource(addr, tfdiags.SourceRange{})
+
+	if len(diags) != 0 {
+		t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
+	}
+
+	if !got.RawEquals(want) {
+		t.Errorf("wrong result:\ngot: %#v\nwant: %#v", got, want)
+	}
+}
+
+// GetResource will return a planned object's After value
+// if there is a change for that resource instance.
+func TestEvaluatorGetResource_changes(t *testing.T) {
+	// Set up existing state
+	stateSync := states.BuildState(func(ss *states.SyncState) {
+		ss.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_resource",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectPlanned,
+				AttrsJSON: []byte(`{"id":"foo", "to_mark_val":"tacos", "sensitive_value":"abc"}`),
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	}).SyncWrapper()
+
+	// Create a change for the existing state resource,
+	// to exercise retrieving the After value of the change
+	changesSync := plans.NewChanges().SyncWrapper()
+	change := &plans.ResourceInstanceChange{
+		Addr: mustResourceInstanceAddr("test_resource.foo"),
+		ProviderAddr: addrs.AbsProviderConfig{
+			Module:   addrs.RootModule,
+			Provider: addrs.NewDefaultProvider("test"),
+		},
+		Change: plans.Change{
+			Action: plans.Update,
+			// Provide an After value that contains a marked value
+			After: cty.ObjectVal(map[string]cty.Value{
+				"id":              cty.StringVal("foo"),
+				"to_mark_val":     cty.StringVal("pizza").Mark(marks.Sensitive),
+				"sensitive_value": cty.StringVal("abc"),
+				"sensitive_collection": cty.MapVal(map[string]cty.Value{
+					"boop": cty.StringVal("beep"),
+				}),
+			}),
+		},
+	}
+
+	// Set up our schemas
+	schemas := &Schemas{
+		Providers: map[addrs.Provider]*ProviderSchema{
+			addrs.NewDefaultProvider("test"): {
+				Provider: &configschema.Block{},
+				ResourceTypes: map[string]*configschema.Block{
+					"test_resource": {
+						Attributes: map[string]*configschema.Attribute{
+							"id": {
+								Type:     cty.String,
+								Computed: true,
+							},
+							"to_mark_val": {
+								Type:     cty.String,
+								Computed: true,
+							},
+							"sensitive_value": {
+								Type:      cty.String,
+								Computed:  true,
+								Sensitive: true,
+							},
+							"sensitive_collection": {
+								Type:      cty.Map(cty.String),
+								Computed:  true,
+								Sensitive: true,
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	// The resource we'll inspect
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_resource",
+		Name: "foo",
+	}
+	schema, _ := schemas.ResourceTypeConfig(addrs.NewDefaultProvider("test"), addr.Mode, addr.Type)
+	// This encoding separates out the After's marks into its AfterValMarks
+	csrc, _ := change.Encode(schema.ImpliedType())
+	changesSync.AppendResourceInstanceChange(csrc)
+
+	evaluator := &Evaluator{
+		Meta: &ContextMeta{
+			Env: "foo",
+		},
+		Changes: changesSync,
+		Config: &configs.Config{
+			Module: &configs.Module{
+				ManagedResources: map[string]*configs.Resource{
+					"test_resource.foo": {
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_resource",
+						Name: "foo",
+						Provider: addrs.Provider{
+							Hostname:  addrs.DefaultProviderRegistryHost,
+							Namespace: "hashicorp",
+							Type:      "test",
+						},
+					},
+				},
+			},
+		},
+		State:   stateSync,
+		Plugins: schemaOnlyProvidersForTesting(schemas.Providers),
+	}
+
+	data := &evaluationStateData{
+		Evaluator: evaluator,
+	}
+	scope := evaluator.Scope(data, nil, nil)
+
+	want := cty.ObjectVal(map[string]cty.Value{
+		"id":              cty.StringVal("foo"),
+		"to_mark_val":     cty.StringVal("pizza").Mark(marks.Sensitive),
+		"sensitive_value": cty.StringVal("abc").Mark(marks.Sensitive),
+		"sensitive_collection": cty.MapVal(map[string]cty.Value{
+			"boop": cty.StringVal("beep"),
+		}).Mark(marks.Sensitive),
+	})
+
+	got, diags := scope.Data.GetResource(addr, tfdiags.SourceRange{})
+
+	if len(diags) != 0 {
+		t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
+	}
+
+	if !got.RawEquals(want) {
+		t.Errorf("wrong result:\ngot: %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestEvaluatorGetModule(t *testing.T) {
+	// Create a new evaluator with an existing state
+	stateSync := states.BuildState(func(ss *states.SyncState) {
+		ss.SetOutputValue(
+			addrs.OutputValue{Name: "out"}.Absolute(addrs.ModuleInstance{addrs.ModuleInstanceStep{Name: "mod"}}),
+			cty.StringVal("bar"),
+			true,
+		)
+	}).SyncWrapper()
+	evaluator := evaluatorForModule(stateSync, plans.NewChanges().SyncWrapper())
+	data := &evaluationStateData{
+		Evaluator: evaluator,
+	}
+	scope := evaluator.Scope(data, nil, nil)
+	want := cty.ObjectVal(map[string]cty.Value{"out": cty.StringVal("bar").Mark(marks.Sensitive)})
+	got, diags := scope.Data.GetModule(addrs.ModuleCall{
+		Name: "mod",
+	}, tfdiags.SourceRange{})
+
+	if len(diags) != 0 {
+		t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
+	}
+	if !got.RawEquals(want) {
+		t.Errorf("wrong result %#v; want %#v", got, want)
+	}
+
+	// Changes should override the state value
+	changesSync := plans.NewChanges().SyncWrapper()
+	change := &plans.OutputChange{
+		Addr:      addrs.OutputValue{Name: "out"}.Absolute(addrs.ModuleInstance{addrs.ModuleInstanceStep{Name: "mod"}}),
+		Sensitive: true,
+		Change: plans.Change{
+			After: cty.StringVal("baz"),
+		},
+	}
+	cs, _ := change.Encode()
+	changesSync.AppendOutputChange(cs)
+	evaluator = evaluatorForModule(stateSync, changesSync)
+	data = &evaluationStateData{
+		Evaluator: evaluator,
+	}
+	scope = evaluator.Scope(data, nil, nil)
+	want = cty.ObjectVal(map[string]cty.Value{"out": cty.StringVal("baz").Mark(marks.Sensitive)})
+	got, diags = scope.Data.GetModule(addrs.ModuleCall{
+		Name: "mod",
+	}, tfdiags.SourceRange{})
+
+	if len(diags) != 0 {
+		t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
+	}
+	if !got.RawEquals(want) {
+		t.Errorf("wrong result %#v; want %#v", got, want)
+	}
+
+	// Test changes with empty state
+	evaluator = evaluatorForModule(states.NewState().SyncWrapper(), changesSync)
+	data = &evaluationStateData{
+		Evaluator: evaluator,
+	}
+	scope = evaluator.Scope(data, nil, nil)
+	want = cty.ObjectVal(map[string]cty.Value{"out": cty.StringVal("baz").Mark(marks.Sensitive)})
+	got, diags = scope.Data.GetModule(addrs.ModuleCall{
+		Name: "mod",
+	}, tfdiags.SourceRange{})
+
+	if len(diags) != 0 {
+		t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
+	}
+	if !got.RawEquals(want) {
+		t.Errorf("wrong result %#v; want %#v", got, want)
+	}
+}
+
+func evaluatorForModule(stateSync *states.SyncState, changesSync *plans.ChangesSync) *Evaluator {
+	return &Evaluator{
+		Meta: &ContextMeta{
+			Env: "foo",
+		},
+		Config: &configs.Config{
+			Module: &configs.Module{
+				ModuleCalls: map[string]*configs.ModuleCall{
+					"mod": {
+						Name: "mod",
+					},
+				},
+			},
+			Children: map[string]*configs.Config{
+				"mod": {
+					Path: addrs.Module{"module.mod"},
+					Module: &configs.Module{
+						Outputs: map[string]*configs.Output{
+							"out": {
+								Name:      "out",
+								Sensitive: true,
+							},
+						},
+					},
+				},
+			},
+		},
+		State:   stateSync,
+		Changes: changesSync,
+	}
+}
diff --git a/v1.5.7/internal/terraform/evaluate_triggers.go b/v1.5.7/internal/terraform/evaluate_triggers.go
new file mode 100644
index 0000000..9d8fbb3
--- /dev/null
+++ b/v1.5.7/internal/terraform/evaluate_triggers.go
@@ -0,0 +1,146 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func evalReplaceTriggeredByExpr(expr hcl.Expression, keyData instances.RepetitionData) (*addrs.Reference, tfdiags.Diagnostics) {
+	var ref *addrs.Reference
+	var diags tfdiags.Diagnostics
+
+	traversal, diags := triggersExprToTraversal(expr, keyData)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	// We now have a static traversal, so we can just turn it into an addrs.Reference.
+	ref, ds := addrs.ParseRef(traversal)
+	diags = diags.Append(ds)
+
+	return ref, diags
+}
+
+// trggersExprToTraversal takes an hcl expression limited to the syntax allowed
+// in replace_triggered_by, and converts it to a static traversal. The
+// RepetitionData contains the data necessary to evaluate the only allowed
+// variables in the expression, count.index and each.key.
+func triggersExprToTraversal(expr hcl.Expression, keyData instances.RepetitionData) (hcl.Traversal, tfdiags.Diagnostics) {
+	var trav hcl.Traversal
+	var diags tfdiags.Diagnostics
+
+	switch e := expr.(type) {
+	case *hclsyntax.RelativeTraversalExpr:
+		t, d := triggersExprToTraversal(e.Source, keyData)
+		diags = diags.Append(d)
+		trav = append(trav, t...)
+		trav = append(trav, e.Traversal...)
+
+	case *hclsyntax.ScopeTraversalExpr:
+		// a static reference, we can just append the traversal
+		trav = append(trav, e.Traversal...)
+
+	case *hclsyntax.IndexExpr:
+		// Get the collection from the index expression
+		t, d := triggersExprToTraversal(e.Collection, keyData)
+		diags = diags.Append(d)
+		if diags.HasErrors() {
+			return nil, diags
+		}
+		trav = append(trav, t...)
+
+		// The index key is the only place where we could have variables that
+		// reference count and each, so we need to parse those independently.
+		idx, hclDiags := parseIndexKeyExpr(e.Key, keyData)
+		diags = diags.Append(hclDiags)
+
+		trav = append(trav, idx)
+
+	default:
+		// Something unexpected got through config validation. We're not sure
+		// what it is, but we'll point it out in the diagnostics for the user
+		// to fix.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid replace_triggered_by expression",
+			Detail:   "Unexpected expression found in replace_triggered_by.",
+			Subject:  e.Range().Ptr(),
+		})
+	}
+
+	return trav, diags
+}
+
+// parseIndexKeyExpr takes an hcl.Expression and parses it as an index key, while
+// evaluating any references to count.index or each.key.
+func parseIndexKeyExpr(expr hcl.Expression, keyData instances.RepetitionData) (hcl.TraverseIndex, hcl.Diagnostics) {
+	idx := hcl.TraverseIndex{
+		SrcRange: expr.Range(),
+	}
+
+	trav, diags := hcl.RelTraversalForExpr(expr)
+	if diags.HasErrors() {
+		return idx, diags
+	}
+
+	keyParts := []string{}
+
+	for _, t := range trav {
+		attr, ok := t.(hcl.TraverseAttr)
+		if !ok {
+			diags = append(diags, &hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid index expression",
+				Detail:   "Only constant values, count.index or each.key are allowed in index expressions.",
+				Subject:  expr.Range().Ptr(),
+			})
+			return idx, diags
+		}
+		keyParts = append(keyParts, attr.Name)
+	}
+
+	switch strings.Join(keyParts, ".") {
+	case "count.index":
+		if keyData.CountIndex == cty.NilVal {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  `Reference to "count" in non-counted context`,
+				Detail:   `The "count" object can only be used in "resource" blocks when the "count" argument is set.`,
+				Subject:  expr.Range().Ptr(),
+			})
+		}
+		idx.Key = keyData.CountIndex
+
+	case "each.key":
+		if keyData.EachKey == cty.NilVal {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  `Reference to "each" in context without for_each`,
+				Detail:   `The "each" object can be used only in "resource" blocks when the "for_each" argument is set.`,
+				Subject:  expr.Range().Ptr(),
+			})
+		}
+		idx.Key = keyData.EachKey
+	default:
+		// Something may have slipped through validation, probably from a json
+		// configuration.
+		diags = append(diags, &hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid index expression",
+			Detail:   "Only constant values, count.index or each.key are allowed in index expressions.",
+			Subject:  expr.Range().Ptr(),
+		})
+	}
+
+	return idx, diags
+
+}
diff --git a/v1.5.7/internal/terraform/evaluate_triggers_test.go b/v1.5.7/internal/terraform/evaluate_triggers_test.go
new file mode 100644
index 0000000..38419e6
--- /dev/null
+++ b/v1.5.7/internal/terraform/evaluate_triggers_test.go
@@ -0,0 +1,97 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestEvalReplaceTriggeredBy(t *testing.T) {
+	tests := map[string]struct {
+		// Raw config expression from within replace_triggered_by list.
+		// If this does not contains any count or each references, it should
+		// directly parse into the same *addrs.Reference.
+		expr string
+
+		// If the expression contains count or each, then we need to add
+		// repetition data, and the static string to parse into the desired
+		// *addrs.Reference
+		repData   instances.RepetitionData
+		reference string
+	}{
+		"single resource": {
+			expr: "test_resource.a",
+		},
+
+		"resource instance attr": {
+			expr: "test_resource.a.attr",
+		},
+
+		"resource instance index attr": {
+			expr: "test_resource.a[0].attr",
+		},
+
+		"resource instance count": {
+			expr: "test_resource.a[count.index]",
+			repData: instances.RepetitionData{
+				CountIndex: cty.NumberIntVal(0),
+			},
+			reference: "test_resource.a[0]",
+		},
+		"resource instance for_each": {
+			expr: "test_resource.a[each.key].attr",
+			repData: instances.RepetitionData{
+				EachKey: cty.StringVal("k"),
+			},
+			reference: `test_resource.a["k"].attr`,
+		},
+		"resource instance for_each map attr": {
+			expr: "test_resource.a[each.key].attr[each.key]",
+			repData: instances.RepetitionData{
+				EachKey: cty.StringVal("k"),
+			},
+			reference: `test_resource.a["k"].attr["k"]`,
+		},
+	}
+
+	for name, tc := range tests {
+		pos := hcl.Pos{Line: 1, Column: 1}
+		t.Run(name, func(t *testing.T) {
+			expr, hclDiags := hclsyntax.ParseExpression([]byte(tc.expr), "", pos)
+			if hclDiags.HasErrors() {
+				t.Fatal(hclDiags)
+			}
+
+			got, diags := evalReplaceTriggeredByExpr(expr, tc.repData)
+			if diags.HasErrors() {
+				t.Fatal(diags.Err())
+			}
+
+			want := tc.reference
+			if want == "" {
+				want = tc.expr
+			}
+
+			// create the desired reference
+			traversal, travDiags := hclsyntax.ParseTraversalAbs([]byte(want), "", pos)
+			if travDiags.HasErrors() {
+				t.Fatal(travDiags)
+			}
+			ref, diags := addrs.ParseRef(traversal)
+			if diags.HasErrors() {
+				t.Fatal(diags.Err())
+			}
+
+			if got.DisplayString() != ref.DisplayString() {
+				t.Fatalf("expected %q: got %q", ref.DisplayString(), got.DisplayString())
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/terraform/evaluate_valid.go b/v1.5.7/internal/terraform/evaluate_valid.go
new file mode 100644
index 0000000..7e5a610
--- /dev/null
+++ b/v1.5.7/internal/terraform/evaluate_valid.go
@@ -0,0 +1,330 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"sort"
+
+	"github.com/hashicorp/hcl/v2"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/didyoumean"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// StaticValidateReferences checks the given references against schemas and
+// other statically-checkable rules, producing error diagnostics if any
+// problems are found.
+//
+// If this method returns errors for a particular reference then evaluating
+// that reference is likely to generate a very similar error, so callers should
+// not run this method and then also evaluate the source expression(s) and
+// merge the two sets of diagnostics together, since this will result in
+// confusing redundant errors.
+//
+// This method can find more errors than can be found by evaluating an
+// expression with a partially-populated scope, since it checks the referenced
+// names directly against the schema rather than relying on evaluation errors.
+//
+// The result may include warning diagnostics if, for example, deprecated
+// features are referenced.
+func (d *evaluationStateData) StaticValidateReferences(refs []*addrs.Reference, self addrs.Referenceable, source addrs.Referenceable) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+	for _, ref := range refs {
+		moreDiags := d.staticValidateReference(ref, self, source)
+		diags = diags.Append(moreDiags)
+	}
+	return diags
+}
+
+func (d *evaluationStateData) staticValidateReference(ref *addrs.Reference, self addrs.Referenceable, source addrs.Referenceable) tfdiags.Diagnostics {
+	modCfg := d.Evaluator.Config.DescendentForInstance(d.ModulePath)
+	if modCfg == nil {
+		// This is a bug in the caller rather than a problem with the
+		// reference, but rather than crashing out here in an unhelpful way
+		// we'll just ignore it and trust a different layer to catch it.
+		return nil
+	}
+
+	if ref.Subject == addrs.Self {
+		// The "self" address is a special alias for the address given as
+		// our self parameter here, if present.
+		if self == nil {
+			var diags tfdiags.Diagnostics
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  `Invalid "self" reference`,
+				// This detail message mentions some current practice that
+				// this codepath doesn't really "know about". If the "self"
+				// object starts being supported in more contexts later then
+				// we'll need to adjust this message.
+				Detail:  `The "self" object is not available in this context. This object can be used only in resource provisioner, connection, and postcondition blocks.`,
+				Subject: ref.SourceRange.ToHCL().Ptr(),
+			})
+			return diags
+		}
+
+		synthRef := *ref // shallow copy
+		synthRef.Subject = self
+		ref = &synthRef
+	}
+
+	switch addr := ref.Subject.(type) {
+
+	// For static validation we validate both resource and resource instance references the same way.
+	// We mostly disregard the index, though we do some simple validation of
+	// its _presence_ in staticValidateSingleResourceReference and
+	// staticValidateMultiResourceReference respectively.
+	case addrs.Resource:
+		var diags tfdiags.Diagnostics
+		diags = diags.Append(d.staticValidateSingleResourceReference(modCfg, addr, ref.Remaining, ref.SourceRange))
+		diags = diags.Append(d.staticValidateResourceReference(modCfg, addr, source, ref.Remaining, ref.SourceRange))
+		return diags
+	case addrs.ResourceInstance:
+		var diags tfdiags.Diagnostics
+		diags = diags.Append(d.staticValidateMultiResourceReference(modCfg, addr, ref.Remaining, ref.SourceRange))
+		diags = diags.Append(d.staticValidateResourceReference(modCfg, addr.ContainingResource(), source, ref.Remaining, ref.SourceRange))
+		return diags
+
+	// We also handle all module call references the same way, disregarding index.
+	case addrs.ModuleCall:
+		return d.staticValidateModuleCallReference(modCfg, addr, ref.Remaining, ref.SourceRange)
+	case addrs.ModuleCallInstance:
+		return d.staticValidateModuleCallReference(modCfg, addr.Call, ref.Remaining, ref.SourceRange)
+	case addrs.ModuleCallInstanceOutput:
+		// This one is a funny one because we will take the output name referenced
+		// and use it to fake up a "remaining" that would make sense for the
+		// module call itself, rather than for the specific output, and then
+		// we can just re-use our static module call validation logic.
+		remain := make(hcl.Traversal, len(ref.Remaining)+1)
+		copy(remain[1:], ref.Remaining)
+		remain[0] = hcl.TraverseAttr{
+			Name: addr.Name,
+
+			// Using the whole reference as the source range here doesn't exactly
+			// match how HCL would normally generate an attribute traversal,
+			// but is close enough for our purposes.
+			SrcRange: ref.SourceRange.ToHCL(),
+		}
+		return d.staticValidateModuleCallReference(modCfg, addr.Call.Call, remain, ref.SourceRange)
+
+	default:
+		// Anything else we'll just permit through without any static validation
+		// and let it be caught during dynamic evaluation, in evaluate.go .
+		return nil
+	}
+}
+
+func (d *evaluationStateData) staticValidateSingleResourceReference(modCfg *configs.Config, addr addrs.Resource, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics {
+	// If we have at least one step in "remain" and this resource has
+	// "count" set then we know for sure this in invalid because we have
+	// something like:
+	//     aws_instance.foo.bar
+	// ...when we really need
+	//     aws_instance.foo[count.index].bar
+
+	// It is _not_ safe to do this check when remain is empty, because that
+	// would also match aws_instance.foo[count.index].bar due to `count.index`
+	// not being statically-resolvable as part of a reference, and match
+	// direct references to the whole aws_instance.foo tuple.
+	if len(remain) == 0 {
+		return nil
+	}
+
+	var diags tfdiags.Diagnostics
+
+	cfg := modCfg.Module.ResourceByAddr(addr)
+	if cfg == nil {
+		// We'll just bail out here and catch this in our subsequent call to
+		// staticValidateResourceReference, then.
+		return diags
+	}
+
+	if cfg.Count != nil {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Missing resource instance key`,
+			Detail:   fmt.Sprintf("Because %s has \"count\" set, its attributes must be accessed on specific instances.\n\nFor example, to correlate with indices of a referring resource, use:\n    %s[count.index]", addr, addr),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+	}
+	if cfg.ForEach != nil {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Missing resource instance key`,
+			Detail:   fmt.Sprintf("Because %s has \"for_each\" set, its attributes must be accessed on specific instances.\n\nFor example, to correlate with indices of a referring resource, use:\n    %s[each.key]", addr, addr),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+	}
+
+	return diags
+}
+
+func (d *evaluationStateData) staticValidateMultiResourceReference(modCfg *configs.Config, addr addrs.ResourceInstance, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	cfg := modCfg.Module.ResourceByAddr(addr.ContainingResource())
+	if cfg == nil {
+		// We'll just bail out here and catch this in our subsequent call to
+		// staticValidateResourceReference, then.
+		return diags
+	}
+
+	if addr.Key == addrs.NoKey {
+		// This is a different path into staticValidateSingleResourceReference
+		return d.staticValidateSingleResourceReference(modCfg, addr.ContainingResource(), remain, rng)
+	} else {
+		if cfg.Count == nil && cfg.ForEach == nil {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  `Unexpected resource instance key`,
+				Detail:   fmt.Sprintf(`Because %s does not have "count" or "for_each" set, references to it must not include an index key. Remove the bracketed index to refer to the single instance of this resource.`, addr.ContainingResource()),
+				Subject:  rng.ToHCL().Ptr(),
+			})
+		}
+	}
+
+	return diags
+}
+
+func (d *evaluationStateData) staticValidateResourceReference(modCfg *configs.Config, addr addrs.Resource, source addrs.Referenceable, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	var modeAdjective string
+	switch addr.Mode {
+	case addrs.ManagedResourceMode:
+		modeAdjective = "managed"
+	case addrs.DataResourceMode:
+		modeAdjective = "data"
+	default:
+		// should never happen
+		modeAdjective = "<invalid-mode>"
+	}
+
+	cfg := modCfg.Module.ResourceByAddr(addr)
+	if cfg == nil {
+		var suggestion string
+		// A common mistake is omitting the data. prefix when trying to refer
+		// to a data resource, so we'll add a special hint for that.
+		if addr.Mode == addrs.ManagedResourceMode {
+			candidateAddr := addr // not a pointer, so this is a copy
+			candidateAddr.Mode = addrs.DataResourceMode
+			if candidateCfg := modCfg.Module.ResourceByAddr(candidateAddr); candidateCfg != nil {
+				suggestion = fmt.Sprintf("\n\nDid you mean the data resource %s?", candidateAddr)
+			}
+		}
+
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Reference to undeclared resource`,
+			Detail:   fmt.Sprintf(`A %s resource %q %q has not been declared in %s.%s`, modeAdjective, addr.Type, addr.Name, moduleConfigDisplayAddr(modCfg.Path), suggestion),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+		return diags
+	}
+
+	if cfg.Container != nil && (source == nil || !cfg.Container.Accessible(source)) {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Reference to scoped resource`,
+			Detail:   fmt.Sprintf(`The referenced %s resource %q %q is not available from this context.`, modeAdjective, addr.Type, addr.Name),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+	}
+
+	providerFqn := modCfg.Module.ProviderForLocalConfig(cfg.ProviderConfigAddr())
+	schema, _, err := d.Evaluator.Plugins.ResourceTypeSchema(providerFqn, addr.Mode, addr.Type)
+	if err != nil {
+		// Prior validation should've taken care of a schema lookup error,
+		// so we should never get here but we'll handle it here anyway for
+		// robustness.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Failed provider schema lookup`,
+			Detail:   fmt.Sprintf(`Couldn't load schema for %s resource type %q in %s: %s.`, modeAdjective, addr.Type, providerFqn.String(), err),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+	}
+
+	if schema == nil {
+		// Prior validation should've taken care of a resource block with an
+		// unsupported type, so we should never get here but we'll handle it
+		// here anyway for robustness.
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Invalid resource type`,
+			Detail:   fmt.Sprintf(`A %s resource type %q is not supported by provider %q.`, modeAdjective, addr.Type, providerFqn.String()),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+		return diags
+	}
+
+	// As a special case we'll detect attempts to access an attribute called
+	// "count" and produce a special error for it, since versions of Terraform
+	// prior to v0.12 offered this as a weird special case that we can no
+	// longer support.
+	if len(remain) > 0 {
+		if step, ok := remain[0].(hcl.TraverseAttr); ok && step.Name == "count" {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  `Invalid resource count attribute`,
+				Detail:   fmt.Sprintf(`The special "count" attribute is no longer supported after Terraform v0.12. Instead, use length(%s) to count resource instances.`, addr),
+				Subject:  rng.ToHCL().Ptr(),
+			})
+			return diags
+		}
+	}
+
+	// If we got this far then we'll try to validate the remaining traversal
+	// steps against our schema.
+	moreDiags := schema.StaticValidateTraversal(remain)
+	diags = diags.Append(moreDiags)
+
+	return diags
+}
+
+func (d *evaluationStateData) staticValidateModuleCallReference(modCfg *configs.Config, addr addrs.ModuleCall, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	// For now, our focus here is just in testing that the referenced module
+	// call exists. All other validation is deferred until evaluation time.
+	_, exists := modCfg.Module.ModuleCalls[addr.Name]
+	if !exists {
+		var suggestions []string
+		for name := range modCfg.Module.ModuleCalls {
+			suggestions = append(suggestions, name)
+		}
+		sort.Strings(suggestions)
+		suggestion := didyoumean.NameSuggestion(addr.Name, suggestions)
+		if suggestion != "" {
+			suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
+		}
+
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  `Reference to undeclared module`,
+			Detail:   fmt.Sprintf(`No module call named %q is declared in %s.%s`, addr.Name, moduleConfigDisplayAddr(modCfg.Path), suggestion),
+			Subject:  rng.ToHCL().Ptr(),
+		})
+		return diags
+	}
+
+	return diags
+}
+
+// moduleConfigDisplayAddr returns a string describing the given module
+// address that is appropriate for returning to users in situations where the
+// root module is possible. Specifically, it returns "the root module" if the
+// root module instance is given, or a string representation of the module
+// address otherwise.
+func moduleConfigDisplayAddr(addr addrs.Module) string {
+	switch {
+	case addr.IsRoot():
+		return "the root module"
+	default:
+		return addr.String()
+	}
+}
diff --git a/v1.5.7/internal/terraform/evaluate_valid_test.go b/v1.5.7/internal/terraform/evaluate_valid_test.go
new file mode 100644
index 0000000..10048e8
--- /dev/null
+++ b/v1.5.7/internal/terraform/evaluate_valid_test.go
@@ -0,0 +1,145 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/lang"
+)
+
+func TestStaticValidateReferences(t *testing.T) {
+	tests := []struct {
+		Ref     string
+		Src     addrs.Referenceable
+		WantErr string
+	}{
+		{
+			Ref:     "aws_instance.no_count",
+			WantErr: ``,
+		},
+		{
+			Ref:     "aws_instance.count",
+			WantErr: ``,
+		},
+		{
+			Ref:     "aws_instance.count[0]",
+			WantErr: ``,
+		},
+		{
+			Ref:     "aws_instance.nonexist",
+			WantErr: `Reference to undeclared resource: A managed resource "aws_instance" "nonexist" has not been declared in the root module.`,
+		},
+		{
+			Ref: "beep.boop",
+			WantErr: `Reference to undeclared resource: A managed resource "beep" "boop" has not been declared in the root module.
+
+Did you mean the data resource data.beep.boop?`,
+		},
+		{
+			Ref:     "aws_instance.no_count[0]",
+			WantErr: `Unexpected resource instance key: Because aws_instance.no_count does not have "count" or "for_each" set, references to it must not include an index key. Remove the bracketed index to refer to the single instance of this resource.`,
+		},
+		{
+			Ref: "aws_instance.count.foo",
+			// In this case we return two errors that are somewhat redundant with
+			// one another, but we'll accept that because they both report the
+			// problem from different perspectives and so give the user more
+			// opportunity to understand what's going on here.
+			WantErr: `2 problems:
+
+- Missing resource instance key: Because aws_instance.count has "count" set, its attributes must be accessed on specific instances.
+
+For example, to correlate with indices of a referring resource, use:
+    aws_instance.count[count.index]
+- Unsupported attribute: This object has no argument, nested block, or exported attribute named "foo".`,
+		},
+		{
+			Ref:     "boop_instance.yep",
+			WantErr: ``,
+		},
+		{
+			Ref:     "boop_whatever.nope",
+			WantErr: `Invalid resource type: A managed resource type "boop_whatever" is not supported by provider "registry.terraform.io/foobar/beep".`,
+		},
+		{
+			Ref:     "data.boop_data.boop_nested",
+			WantErr: `Reference to scoped resource: The referenced data resource "boop_data" "boop_nested" is not available from this context.`,
+		},
+		{
+			Ref:     "data.boop_data.boop_nested",
+			WantErr: ``,
+			Src:     addrs.Check{Name: "foo"},
+		},
+	}
+
+	cfg := testModule(t, "static-validate-refs")
+	evaluator := &Evaluator{
+		Config: cfg,
+		Plugins: schemaOnlyProvidersForTesting(map[addrs.Provider]*ProviderSchema{
+			addrs.NewDefaultProvider("aws"): {
+				ResourceTypes: map[string]*configschema.Block{
+					"aws_instance": {},
+				},
+			},
+			addrs.MustParseProviderSourceString("foobar/beep"): {
+				ResourceTypes: map[string]*configschema.Block{
+					// intentional mismatch between resource type prefix and provider type
+					"boop_instance": {},
+				},
+				DataSources: map[string]*configschema.Block{
+					"boop_data": {
+						Attributes: map[string]*configschema.Attribute{
+							"id": {
+								Type:     cty.String,
+								Optional: true,
+							},
+						},
+					},
+				},
+			},
+		}),
+	}
+
+	for _, test := range tests {
+		t.Run(test.Ref, func(t *testing.T) {
+			traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(test.Ref), "", hcl.Pos{Line: 1, Column: 1})
+			if hclDiags.HasErrors() {
+				t.Fatal(hclDiags.Error())
+			}
+
+			refs, diags := lang.References([]hcl.Traversal{traversal})
+			if diags.HasErrors() {
+				t.Fatal(diags.Err())
+			}
+
+			data := &evaluationStateData{
+				Evaluator: evaluator,
+			}
+
+			diags = data.StaticValidateReferences(refs, nil, test.Src)
+			if diags.HasErrors() {
+				if test.WantErr == "" {
+					t.Fatalf("Unexpected diagnostics: %s", diags.Err())
+				}
+
+				gotErr := diags.Err().Error()
+				if gotErr != test.WantErr {
+					t.Fatalf("Wrong diagnostics\ngot:  %s\nwant: %s", gotErr, test.WantErr)
+				}
+				return
+			}
+
+			if test.WantErr != "" {
+				t.Fatalf("Expected diagnostics, but got none\nwant: %s", test.WantErr)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/terraform/execute.go b/v1.5.7/internal/terraform/execute.go
new file mode 100644
index 0000000..a0018ca
--- /dev/null
+++ b/v1.5.7/internal/terraform/execute.go
@@ -0,0 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import "github.com/hashicorp/terraform/internal/tfdiags"
+
+// GraphNodeExecutable is the interface that graph nodes must implement to
+// enable execution.
+type GraphNodeExecutable interface {
+	Execute(EvalContext, walkOperation) tfdiags.Diagnostics
+}
diff --git a/v1.5.7/internal/terraform/features.go b/v1.5.7/internal/terraform/features.go
new file mode 100644
index 0000000..62c43af
--- /dev/null
+++ b/v1.5.7/internal/terraform/features.go
@@ -0,0 +1,10 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import "os"
+
+// This file holds feature flags for the next release
+
+var flagWarnOutputErrors = os.Getenv("TF_WARN_OUTPUT_ERRORS") != ""
diff --git a/v1.5.7/internal/terraform/graph.go b/v1.5.7/internal/terraform/graph.go
new file mode 100644
index 0000000..6abcbe9
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph.go
@@ -0,0 +1,138 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+// Graph represents the graph that Terraform uses to represent resources
+// and their dependencies.
+type Graph struct {
+	// Graph is the actual DAG. This is embedded so you can call the DAG
+	// methods directly.
+	dag.AcyclicGraph
+
+	// Path is the path in the module tree that this Graph represents.
+	Path addrs.ModuleInstance
+}
+
+func (g *Graph) DirectedGraph() dag.Grapher {
+	return &g.AcyclicGraph
+}
+
+// Walk walks the graph with the given walker for callbacks. The graph
+// will be walked with full parallelism, so the walker should expect
+// to be called in concurrently.
+func (g *Graph) Walk(walker GraphWalker) tfdiags.Diagnostics {
+	return g.walk(walker)
+}
+
+func (g *Graph) walk(walker GraphWalker) tfdiags.Diagnostics {
+	// The callbacks for enter/exiting a graph
+	ctx := walker.EvalContext()
+
+	// Walk the graph.
+	walkFn := func(v dag.Vertex) (diags tfdiags.Diagnostics) {
+		// the walkFn is called asynchronously, and needs to be recovered
+		// separately in the case of a panic.
+		defer logging.PanicHandler()
+
+		log.Printf("[TRACE] vertex %q: starting visit (%T)", dag.VertexName(v), v)
+
+		defer func() {
+			if diags.HasErrors() {
+				for _, diag := range diags {
+					if diag.Severity() == tfdiags.Error {
+						desc := diag.Description()
+						log.Printf("[ERROR] vertex %q error: %s", dag.VertexName(v), desc.Summary)
+					}
+				}
+				log.Printf("[TRACE] vertex %q: visit complete, with errors", dag.VertexName(v))
+			} else {
+				log.Printf("[TRACE] vertex %q: visit complete", dag.VertexName(v))
+			}
+		}()
+
+		// vertexCtx is the context that we use when evaluating. This
+		// is normally the context of our graph but can be overridden
+		// with a GraphNodeModuleInstance impl.
+		vertexCtx := ctx
+		if pn, ok := v.(GraphNodeModuleInstance); ok {
+			vertexCtx = walker.EnterPath(pn.Path())
+			defer walker.ExitPath(pn.Path())
+		}
+
+		// If the node is exec-able, then execute it.
+		if ev, ok := v.(GraphNodeExecutable); ok {
+			diags = diags.Append(walker.Execute(vertexCtx, ev))
+			if diags.HasErrors() {
+				return
+			}
+		}
+
+		// If the node is dynamically expanded, then expand it
+		if ev, ok := v.(GraphNodeDynamicExpandable); ok {
+			log.Printf("[TRACE] vertex %q: expanding dynamic subgraph", dag.VertexName(v))
+
+			g, err := ev.DynamicExpand(vertexCtx)
+			diags = diags.Append(err)
+			if diags.HasErrors() {
+				log.Printf("[TRACE] vertex %q: failed expanding dynamic subgraph: %s", dag.VertexName(v), err)
+				return
+			}
+			if g != nil {
+				// The subgraph should always be valid, per our normal acyclic
+				// graph validation rules.
+				if err := g.Validate(); err != nil {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Graph node has invalid dynamic subgraph",
+						fmt.Sprintf("The internal logic for %q generated an invalid dynamic subgraph: %s.\n\nThis is a bug in Terraform. Please report it!", dag.VertexName(v), err),
+					))
+					return
+				}
+				// If we passed validation then there is exactly one root node.
+				// That root node should always be "rootNode", the singleton
+				// root node value.
+				if n, err := g.Root(); err != nil || n != dag.Vertex(rootNode) {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Graph node has invalid dynamic subgraph",
+						fmt.Sprintf("The internal logic for %q generated an invalid dynamic subgraph: the root node is %T, which is not a suitable root node type.\n\nThis is a bug in Terraform. Please report it!", dag.VertexName(v), n),
+					))
+					return
+				}
+
+				// Walk the subgraph
+				log.Printf("[TRACE] vertex %q: entering dynamic subgraph", dag.VertexName(v))
+				subDiags := g.walk(walker)
+				diags = diags.Append(subDiags)
+				if subDiags.HasErrors() {
+					var errs []string
+					for _, d := range subDiags {
+						errs = append(errs, d.Description().Summary)
+					}
+					log.Printf("[TRACE] vertex %q: dynamic subgraph encountered errors: %s", dag.VertexName(v), strings.Join(errs, ","))
+					return
+				}
+				log.Printf("[TRACE] vertex %q: dynamic subgraph completed successfully", dag.VertexName(v))
+			} else {
+				log.Printf("[TRACE] vertex %q: produced no dynamic subgraph", dag.VertexName(v))
+			}
+		}
+		return
+	}
+
+	return g.AcyclicGraph.Walk(walkFn)
+}
diff --git a/v1.5.7/internal/terraform/graph_builder.go b/v1.5.7/internal/terraform/graph_builder.go
new file mode 100644
index 0000000..ec21f5f
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph_builder.go
@@ -0,0 +1,68 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// GraphBuilder is an interface that can be implemented and used with
+// Terraform to build the graph that Terraform walks.
+type GraphBuilder interface {
+	// Build builds the graph for the given module path. It is up to
+	// the interface implementation whether this build should expand
+	// the graph or not.
+	Build(addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics)
+}
+
+// BasicGraphBuilder is a GraphBuilder that builds a graph out of a
+// series of transforms and (optionally) validates the graph is a valid
+// structure.
+type BasicGraphBuilder struct {
+	Steps []GraphTransformer
+	// Optional name to add to the graph debug log
+	Name string
+}
+
+func (b *BasicGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	g := &Graph{Path: path}
+
+	var lastStepStr string
+	for _, step := range b.Steps {
+		if step == nil {
+			continue
+		}
+		log.Printf("[TRACE] Executing graph transform %T", step)
+
+		err := step.Transform(g)
+		if thisStepStr := g.StringWithNodeTypes(); thisStepStr != lastStepStr {
+			log.Printf("[TRACE] Completed graph transform %T with new graph:\n%s  ------", step, logging.Indent(thisStepStr))
+			lastStepStr = thisStepStr
+		} else {
+			log.Printf("[TRACE] Completed graph transform %T (no changes)", step)
+		}
+
+		if err != nil {
+			if nf, isNF := err.(tfdiags.NonFatalError); isNF {
+				diags = diags.Append(nf.Diagnostics)
+			} else {
+				diags = diags.Append(err)
+				return g, diags
+			}
+		}
+	}
+
+	if err := g.Validate(); err != nil {
+		log.Printf("[ERROR] Graph validation failed. Graph:\n\n%s", g.String())
+		diags = diags.Append(err)
+		return nil, diags
+	}
+
+	return g, diags
+}
diff --git a/v1.5.7/internal/terraform/graph_builder_apply.go b/v1.5.7/internal/terraform/graph_builder_apply.go
new file mode 100644
index 0000000..d892fc9
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph_builder_apply.go
@@ -0,0 +1,189 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ApplyGraphBuilder implements GraphBuilder and is responsible for building
+// a graph for applying a Terraform diff.
+//
+// Because the graph is built from the diff (vs. the config or state),
+// this helps ensure that the apply-time graph doesn't modify any resources
+// that aren't explicitly in the diff. There are other scenarios where the
+// diff can be deviated, so this is just one layer of protection.
+type ApplyGraphBuilder struct {
+	// Config is the configuration tree that the diff was built from.
+	Config *configs.Config
+
+	// Changes describes the changes that we need apply.
+	Changes *plans.Changes
+
+	// State is the current state
+	State *states.State
+
+	// RootVariableValues are the root module input variables captured as
+	// part of the plan object, which we must reproduce in the apply step
+	// to get a consistent result.
+	RootVariableValues InputValues
+
+	// Plugins is a library of the plug-in components (providers and
+	// provisioners) available for use.
+	Plugins *contextPlugins
+
+	// Targets are resources to target. This is only required to make sure
+	// unnecessary outputs aren't included in the apply graph. The plan
+	// builder successfully handles targeting resources. In the future,
+	// outputs should go into the diff so that this is unnecessary.
+	Targets []addrs.Targetable
+
+	// ForceReplace are the resource instance addresses that the user
+	// requested to force replacement for when creating the plan, if any.
+	// The apply step refers to these as part of verifying that the planned
+	// actions remain consistent between plan and apply.
+	ForceReplace []addrs.AbsResourceInstance
+
+	// Plan Operation this graph will be used for.
+	Operation walkOperation
+}
+
+// See GraphBuilder
+func (b *ApplyGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
+	return (&BasicGraphBuilder{
+		Steps: b.Steps(),
+		Name:  "ApplyGraphBuilder",
+	}).Build(path)
+}
+
+// See GraphBuilder
+func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
+	// Custom factory for creating providers.
+	concreteProvider := func(a *NodeAbstractProvider) dag.Vertex {
+		return &NodeApplyableProvider{
+			NodeAbstractProvider: a,
+		}
+	}
+
+	concreteResource := func(a *NodeAbstractResource) dag.Vertex {
+		return &nodeExpandApplyableResource{
+			NodeAbstractResource: a,
+		}
+	}
+
+	concreteResourceInstance := func(a *NodeAbstractResourceInstance) dag.Vertex {
+		return &NodeApplyableResourceInstance{
+			NodeAbstractResourceInstance: a,
+			forceReplace:                 b.ForceReplace,
+		}
+	}
+
+	steps := []GraphTransformer{
+		// Creates all the resources represented in the config. During apply,
+		// we use this just to ensure that the whole-resource metadata is
+		// updated to reflect things such as whether the count argument is
+		// set in config, or which provider configuration manages each resource.
+		&ConfigTransformer{
+			Concrete: concreteResource,
+			Config:   b.Config,
+		},
+
+		// Add dynamic values
+		&RootVariableTransformer{Config: b.Config, RawValues: b.RootVariableValues},
+		&ModuleVariableTransformer{Config: b.Config},
+		&LocalTransformer{Config: b.Config},
+		&OutputTransformer{
+			Config:     b.Config,
+			Destroying: b.Operation == walkDestroy,
+		},
+
+		// Creates all the resource instances represented in the diff, along
+		// with dependency edges against the whole-resource nodes added by
+		// ConfigTransformer above.
+		&DiffTransformer{
+			Concrete: concreteResourceInstance,
+			State:    b.State,
+			Changes:  b.Changes,
+			Config:   b.Config,
+		},
+
+		// Add nodes and edges for check block assertions. Check block data
+		// sources were added earlier.
+		&checkTransformer{
+			Config:    b.Config,
+			Operation: b.Operation,
+		},
+
+		// Attach the state
+		&AttachStateTransformer{State: b.State},
+
+		// Create orphan output nodes
+		&OrphanOutputTransformer{Config: b.Config, State: b.State},
+
+		// Attach the configuration to any resources
+		&AttachResourceConfigTransformer{Config: b.Config},
+
+		// add providers
+		transformProviders(concreteProvider, b.Config),
+
+		// Remove modules no longer present in the config
+		&RemovedModuleTransformer{Config: b.Config, State: b.State},
+
+		// Must attach schemas before ReferenceTransformer so that we can
+		// analyze the configuration to find references.
+		&AttachSchemaTransformer{Plugins: b.Plugins, Config: b.Config},
+
+		// Create expansion nodes for all of the module calls. This must
+		// come after all other transformers that create nodes representing
+		// objects that can belong to modules.
+		&ModuleExpansionTransformer{Config: b.Config},
+
+		// Connect references so ordering is correct
+		&ReferenceTransformer{},
+		&AttachDependenciesTransformer{},
+
+		// Nested data blocks should be loaded after every other resource has
+		// done its thing.
+		&checkStartTransformer{Config: b.Config, Operation: b.Operation},
+
+		// Detect when create_before_destroy must be forced on for a particular
+		// node due to dependency edges, to avoid graph cycles during apply.
+		&ForcedCBDTransformer{},
+
+		// Destruction ordering
+		&DestroyEdgeTransformer{
+			Changes:   b.Changes,
+			Operation: b.Operation,
+		},
+		&CBDEdgeTransformer{
+			Config: b.Config,
+			State:  b.State,
+		},
+
+		// We need to remove configuration nodes that are not used at all, as
+		// they may not be able to evaluate, especially during destroy.
+		// These include variables, locals, and instance expanders.
+		&pruneUnusedNodesTransformer{},
+
+		// Target
+		&TargetsTransformer{Targets: b.Targets},
+
+		// Close opened plugin connections
+		&CloseProviderTransformer{},
+
+		// close the root module
+		&CloseRootModuleTransformer{},
+
+		// Perform the transitive reduction to make our graph a bit
+		// more understandable if possible (it usually is possible).
+		&TransitiveReductionTransformer{},
+	}
+
+	return steps
+}
diff --git a/v1.5.7/internal/terraform/graph_builder_apply_test.go b/v1.5.7/internal/terraform/graph_builder_apply_test.go
new file mode 100644
index 0000000..5041749
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph_builder_apply_test.go
@@ -0,0 +1,840 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestApplyGraphBuilder_impl(t *testing.T) {
+	var _ GraphBuilder = new(ApplyGraphBuilder)
+}
+
+func TestApplyGraphBuilder(t *testing.T) {
+	changes := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: mustResourceInstanceAddr("test_object.create"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Create,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("test_object.other"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Update,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("module.child.test_object.create"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Create,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("module.child.test_object.other"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Create,
+				},
+			},
+		},
+	}
+
+	b := &ApplyGraphBuilder{
+		Config:  testModule(t, "graph-builder-apply-basic"),
+		Changes: changes,
+		Plugins: simpleMockPluginLibrary(),
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if g.Path.String() != addrs.RootModuleInstance.String() {
+		t.Fatalf("wrong path %q", g.Path.String())
+	}
+
+	got := strings.TrimSpace(g.String())
+	want := strings.TrimSpace(testApplyGraphBuilderStr)
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Fatalf("wrong result\n%s", diff)
+	}
+}
+
+// This tests the ordering of two resources where a non-CBD depends
+// on a CBD. GH-11349.
+func TestApplyGraphBuilder_depCbd(t *testing.T) {
+	changes := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: mustResourceInstanceAddr("test_object.A"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.CreateThenDelete,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("test_object.B"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Update,
+				},
+			},
+		},
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.A").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"A"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.B").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"B","test_list":["x"]}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	b := &ApplyGraphBuilder{
+		Config:  testModule(t, "graph-builder-apply-dep-cbd"),
+		Changes: changes,
+		Plugins: simpleMockPluginLibrary(),
+		State:   state,
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if g.Path.String() != addrs.RootModuleInstance.String() {
+		t.Fatalf("wrong path %q", g.Path.String())
+	}
+
+	// We're going to go hunting for our deposed instance node here, so we
+	// can find out its key to use in the assertions below.
+	var dk states.DeposedKey
+	for _, v := range g.Vertices() {
+		tv, ok := v.(*NodeDestroyDeposedResourceInstanceObject)
+		if !ok {
+			continue
+		}
+		if dk != states.NotDeposed {
+			t.Fatalf("more than one deposed instance node in the graph; want only one")
+		}
+		dk = tv.DeposedKey
+	}
+	if dk == states.NotDeposed {
+		t.Fatalf("no deposed instance node in the graph; want one")
+	}
+
+	destroyName := fmt.Sprintf("test_object.A (destroy deposed %s)", dk)
+
+	// Create A, Modify B, Destroy A
+	testGraphHappensBefore(
+		t, g,
+		"test_object.A",
+		destroyName,
+	)
+	testGraphHappensBefore(
+		t, g,
+		"test_object.A",
+		"test_object.B",
+	)
+	testGraphHappensBefore(
+		t, g,
+		"test_object.B",
+		destroyName,
+	)
+}
+
+// This tests the ordering of two resources that are both CBD that
+// require destroy/create.
+func TestApplyGraphBuilder_doubleCBD(t *testing.T) {
+	changes := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: mustResourceInstanceAddr("test_object.A"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.CreateThenDelete,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("test_object.B"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.CreateThenDelete,
+				},
+			},
+		},
+	}
+
+	b := &ApplyGraphBuilder{
+		Config:  testModule(t, "graph-builder-apply-double-cbd"),
+		Changes: changes,
+		Plugins: simpleMockPluginLibrary(),
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if g.Path.String() != addrs.RootModuleInstance.String() {
+		t.Fatalf("wrong path %q", g.Path.String())
+	}
+
+	// We're going to go hunting for our deposed instance node here, so we
+	// can find out its key to use in the assertions below.
+	var destroyA, destroyB string
+	for _, v := range g.Vertices() {
+		tv, ok := v.(*NodeDestroyDeposedResourceInstanceObject)
+		if !ok {
+			continue
+		}
+
+		switch tv.Addr.Resource.Resource.Name {
+		case "A":
+			destroyA = fmt.Sprintf("test_object.A (destroy deposed %s)", tv.DeposedKey)
+		case "B":
+			destroyB = fmt.Sprintf("test_object.B (destroy deposed %s)", tv.DeposedKey)
+		default:
+			t.Fatalf("unknown instance: %s", tv.Addr)
+		}
+	}
+
+	// Create A, Modify B, Destroy A
+	testGraphHappensBefore(
+		t, g,
+		"test_object.A",
+		destroyA,
+	)
+	testGraphHappensBefore(
+		t, g,
+		"test_object.A",
+		"test_object.B",
+	)
+	testGraphHappensBefore(
+		t, g,
+		"test_object.B",
+		destroyB,
+	)
+}
+
+// This tests the ordering of two resources being destroyed that depend
+// on each other from only state. GH-11749
+func TestApplyGraphBuilder_destroyStateOnly(t *testing.T) {
+	changes := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: mustResourceInstanceAddr("module.child.test_object.A"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Delete,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("module.child.test_object.B"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Delete,
+				},
+			},
+		},
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.A").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.B").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"bar"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.test_object.A")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	b := &ApplyGraphBuilder{
+		Config:  testModule(t, "empty"),
+		Changes: changes,
+		State:   state,
+		Plugins: simpleMockPluginLibrary(),
+	}
+
+	g, diags := b.Build(addrs.RootModuleInstance)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	if g.Path.String() != addrs.RootModuleInstance.String() {
+		t.Fatalf("wrong path %q", g.Path.String())
+	}
+
+	testGraphHappensBefore(
+		t, g,
+		"module.child.test_object.B (destroy)",
+		"module.child.test_object.A (destroy)")
+}
+
+// This tests the ordering of destroying a single count of a resource.
+func TestApplyGraphBuilder_destroyCount(t *testing.T) {
+	changes := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: mustResourceInstanceAddr("test_object.A[1]"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Delete,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("test_object.B"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Update,
+				},
+			},
+		},
+	}
+
+	state := states.NewState()
+	root := state.RootModule()
+	addrA := mustResourceInstanceAddr("test_object.A[1]")
+	root.SetResourceInstanceCurrent(
+		addrA.Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"B"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.B").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"B"}`),
+			Dependencies: []addrs.ConfigResource{addrA.ContainingResource().Config()},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	b := &ApplyGraphBuilder{
+		Config:  testModule(t, "graph-builder-apply-count"),
+		Changes: changes,
+		Plugins: simpleMockPluginLibrary(),
+		State:   state,
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if g.Path.String() != addrs.RootModuleInstance.String() {
+		t.Fatalf("wrong module path %q", g.Path)
+	}
+
+	got := strings.TrimSpace(g.String())
+	want := strings.TrimSpace(testApplyGraphBuilderDestroyCountStr)
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Fatalf("wrong result\n%s", diff)
+	}
+}
+
+func TestApplyGraphBuilder_moduleDestroy(t *testing.T) {
+	changes := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: mustResourceInstanceAddr("module.A.test_object.foo"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Delete,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("module.B.test_object.foo"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Delete,
+				},
+			},
+		},
+	}
+
+	state := states.NewState()
+	modA := state.EnsureModule(addrs.RootModuleInstance.Child("A", addrs.NoKey))
+	modA.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	modB := state.EnsureModule(addrs.RootModuleInstance.Child("B", addrs.NoKey))
+	modB.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.foo").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"foo","value":"foo"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.A.test_object.foo")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	b := &ApplyGraphBuilder{
+		Config:  testModule(t, "graph-builder-apply-module-destroy"),
+		Changes: changes,
+		Plugins: simpleMockPluginLibrary(),
+		State:   state,
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testGraphHappensBefore(
+		t, g,
+		"module.B.test_object.foo (destroy)",
+		"module.A.test_object.foo (destroy)",
+	)
+}
+
+func TestApplyGraphBuilder_targetModule(t *testing.T) {
+	changes := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: mustResourceInstanceAddr("test_object.foo"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Update,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("module.child2.test_object.foo"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Update,
+				},
+			},
+		},
+	}
+
+	b := &ApplyGraphBuilder{
+		Config:  testModule(t, "graph-builder-apply-target-module"),
+		Changes: changes,
+		Plugins: simpleMockPluginLibrary(),
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Child("child2", addrs.NoKey),
+		},
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testGraphNotContains(t, g, "module.child1.output.instance_id")
+}
+
+// Ensure that an update resulting from the removal of a resource happens after
+// that resource is destroyed.
+func TestApplyGraphBuilder_updateFromOrphan(t *testing.T) {
+	schemas := simpleTestSchemas()
+	instanceSchema := schemas.Providers[addrs.NewDefaultProvider("test")].ResourceTypes["test_object"]
+
+	bBefore, _ := plans.NewDynamicValue(
+		cty.ObjectVal(map[string]cty.Value{
+			"id":          cty.StringVal("b_id"),
+			"test_string": cty.StringVal("a_id"),
+		}), instanceSchema.ImpliedType())
+	bAfter, _ := plans.NewDynamicValue(
+		cty.ObjectVal(map[string]cty.Value{
+			"id":          cty.StringVal("b_id"),
+			"test_string": cty.StringVal("changed"),
+		}), instanceSchema.ImpliedType())
+
+	changes := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: mustResourceInstanceAddr("test_object.a"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Delete,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("test_object.b"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Update,
+					Before: bBefore,
+					After:  bAfter,
+				},
+			},
+		},
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_object",
+			Name: "a",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"a_id"}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_object",
+			Name: "b",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"b_id","test_string":"a_id"}`),
+			Dependencies: []addrs.ConfigResource{
+				{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_object",
+						Name: "a",
+					},
+					Module: root.Addr.Module(),
+				},
+			},
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	b := &ApplyGraphBuilder{
+		Config:  testModule(t, "graph-builder-apply-orphan-update"),
+		Changes: changes,
+		Plugins: simpleMockPluginLibrary(),
+		State:   state,
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := strings.TrimSpace(`
+test_object.a (destroy)
+test_object.b
+  test_object.a (destroy)
+`)
+
+	instanceGraph := filterInstances(g)
+	got := strings.TrimSpace(instanceGraph.String())
+
+	if got != expected {
+		t.Fatalf("expected:\n%s\ngot:\n%s", expected, got)
+	}
+}
+
+// Ensure that an update resulting from the removal of a resource happens before
+// a CBD resource is destroyed.
+func TestApplyGraphBuilder_updateFromCBDOrphan(t *testing.T) {
+	schemas := simpleTestSchemas()
+	instanceSchema := schemas.Providers[addrs.NewDefaultProvider("test")].ResourceTypes["test_object"]
+
+	bBefore, _ := plans.NewDynamicValue(
+		cty.ObjectVal(map[string]cty.Value{
+			"id":          cty.StringVal("b_id"),
+			"test_string": cty.StringVal("a_id"),
+		}), instanceSchema.ImpliedType())
+	bAfter, _ := plans.NewDynamicValue(
+		cty.ObjectVal(map[string]cty.Value{
+			"id":          cty.StringVal("b_id"),
+			"test_string": cty.StringVal("changed"),
+		}), instanceSchema.ImpliedType())
+
+	changes := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: mustResourceInstanceAddr("test_object.a"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Delete,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("test_object.b"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Update,
+					Before: bBefore,
+					After:  bAfter,
+				},
+			},
+		},
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_object",
+			Name: "a",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:              states.ObjectReady,
+			AttrsJSON:           []byte(`{"id":"a_id"}`),
+			CreateBeforeDestroy: true,
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_object",
+			Name: "b",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"b_id","test_string":"a_id"}`),
+			Dependencies: []addrs.ConfigResource{
+				{
+					Resource: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "test_object",
+						Name: "a",
+					},
+					Module: root.Addr.Module(),
+				},
+			},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	b := &ApplyGraphBuilder{
+		Config:  testModule(t, "graph-builder-apply-orphan-update"),
+		Changes: changes,
+		Plugins: simpleMockPluginLibrary(),
+		State:   state,
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := strings.TrimSpace(`
+test_object.a (destroy)
+  test_object.b
+test_object.b
+`)
+
+	instanceGraph := filterInstances(g)
+	got := strings.TrimSpace(instanceGraph.String())
+
+	if got != expected {
+		t.Fatalf("expected:\n%s\ngot:\n%s", expected, got)
+	}
+}
+
+// The orphan clean up node should not be connected to a provider
+func TestApplyGraphBuilder_orphanedWithProvider(t *testing.T) {
+	changes := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: mustResourceInstanceAddr("test_object.A"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Delete,
+				},
+			},
+		},
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.A").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"A"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"].foo`),
+	)
+
+	b := &ApplyGraphBuilder{
+		Config:  testModule(t, "graph-builder-orphan-alias"),
+		Changes: changes,
+		Plugins: simpleMockPluginLibrary(),
+		State:   state,
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// The cleanup node has no state or config of its own, so would create a
+	// default provider which we don't want.
+	testGraphNotContains(t, g, "provider.test")
+}
+
+func TestApplyGraphBuilder_withChecks(t *testing.T) {
+	awsProvider := mockProviderWithResourceTypeSchema("aws_instance", simpleTestSchema())
+
+	changes := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: mustResourceInstanceAddr("aws_instance.foo"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Create,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("aws_instance.baz"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Create,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("data.aws_data_source.bar"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Read,
+				},
+				ActionReason: plans.ResourceInstanceReadBecauseCheckNested,
+			},
+		},
+	}
+
+	plugins := newContextPlugins(map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("aws"): providers.FactoryFixed(awsProvider),
+	}, nil)
+
+	b := &ApplyGraphBuilder{
+		Config:    testModule(t, "apply-with-checks"),
+		Changes:   changes,
+		Plugins:   plugins,
+		State:     states.NewState(),
+		Operation: walkApply,
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if g.Path.String() != addrs.RootModuleInstance.String() {
+		t.Fatalf("wrong path %q", g.Path.String())
+	}
+
+	got := strings.TrimSpace(g.String())
+	// We're especially looking for the edge here, where aws_instance.bat
+	// has a dependency on aws_instance.boo
+	want := strings.TrimSpace(testPlanWithCheckGraphBuilderStr)
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Fatalf("\ngot:\n%s\n\nwant:\n%s\n\ndiff:\n%s", got, want, diff)
+	}
+
+}
+
+const testPlanWithCheckGraphBuilderStr = `
+(execute checks)
+  aws_instance.baz
+aws_instance.baz
+  aws_instance.baz (expand)
+  aws_instance.foo
+aws_instance.baz (expand)
+  provider["registry.terraform.io/hashicorp/aws"]
+aws_instance.foo
+  aws_instance.foo (expand)
+aws_instance.foo (expand)
+  provider["registry.terraform.io/hashicorp/aws"]
+check.my_check (expand)
+  data.aws_data_source.bar
+data.aws_data_source.bar
+  (execute checks)
+  data.aws_data_source.bar (expand)
+data.aws_data_source.bar (expand)
+  provider["registry.terraform.io/hashicorp/aws"]
+provider["registry.terraform.io/hashicorp/aws"]
+provider["registry.terraform.io/hashicorp/aws"] (close)
+  data.aws_data_source.bar
+root
+  check.my_check (expand)
+  provider["registry.terraform.io/hashicorp/aws"] (close)
+`
+
+const testApplyGraphBuilderStr = `
+module.child (close)
+  module.child.test_object.other
+module.child (expand)
+module.child.test_object.create
+  module.child.test_object.create (expand)
+module.child.test_object.create (expand)
+  module.child (expand)
+  provider["registry.terraform.io/hashicorp/test"]
+module.child.test_object.other
+  module.child.test_object.create
+  module.child.test_object.other (expand)
+module.child.test_object.other (expand)
+  module.child (expand)
+  provider["registry.terraform.io/hashicorp/test"]
+provider["registry.terraform.io/hashicorp/test"]
+provider["registry.terraform.io/hashicorp/test"] (close)
+  module.child.test_object.other
+  test_object.other
+root
+  module.child (close)
+  provider["registry.terraform.io/hashicorp/test"] (close)
+test_object.create
+  test_object.create (expand)
+test_object.create (expand)
+  provider["registry.terraform.io/hashicorp/test"]
+test_object.other
+  test_object.create
+  test_object.other (expand)
+test_object.other (expand)
+  provider["registry.terraform.io/hashicorp/test"]
+`
+
+const testApplyGraphBuilderDestroyCountStr = `
+provider["registry.terraform.io/hashicorp/test"]
+provider["registry.terraform.io/hashicorp/test"] (close)
+  test_object.B
+root
+  provider["registry.terraform.io/hashicorp/test"] (close)
+test_object.A (expand)
+  provider["registry.terraform.io/hashicorp/test"]
+test_object.A[1] (destroy)
+  provider["registry.terraform.io/hashicorp/test"]
+test_object.B
+  test_object.A (expand)
+  test_object.A[1] (destroy)
+  test_object.B (expand)
+test_object.B (expand)
+  provider["registry.terraform.io/hashicorp/test"]
+`
diff --git a/v1.5.7/internal/terraform/graph_builder_eval.go b/v1.5.7/internal/terraform/graph_builder_eval.go
new file mode 100644
index 0000000..303538c
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph_builder_eval.go
@@ -0,0 +1,111 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// EvalGraphBuilder implements GraphBuilder and constructs a graph suitable
+// for evaluating in-memory values (input variables, local values, output
+// values) in the state without any other side-effects.
+//
+// This graph is used only in weird cases, such as the "terraform console"
+// CLI command, where we need to evaluate expressions against the state
+// without taking any other actions.
+//
+// The generated graph will include nodes for providers, resources, etc
+// just to allow indirect dependencies to be resolved, but these nodes will
+// not take any actions themselves since we assume that their parts of the
+// state, if any, are already complete.
+//
+// Although the providers are never configured, they must still be available
+// in order to obtain schema information used for type checking, etc.
+type EvalGraphBuilder struct {
+	// Config is the configuration tree.
+	Config *configs.Config
+
+	// State is the current state
+	State *states.State
+
+	// RootVariableValues are the raw input values for root input variables
+	// given by the caller, which we'll resolve into final values as part
+	// of the plan walk.
+	RootVariableValues InputValues
+
+	// Plugins is a library of plug-in components (providers and
+	// provisioners) available for use.
+	Plugins *contextPlugins
+}
+
+// See GraphBuilder
+func (b *EvalGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
+	return (&BasicGraphBuilder{
+		Steps: b.Steps(),
+		Name:  "EvalGraphBuilder",
+	}).Build(path)
+}
+
+// See GraphBuilder
+func (b *EvalGraphBuilder) Steps() []GraphTransformer {
+	concreteProvider := func(a *NodeAbstractProvider) dag.Vertex {
+		return &NodeEvalableProvider{
+			NodeAbstractProvider: a,
+		}
+	}
+
+	steps := []GraphTransformer{
+		// Creates all the data resources that aren't in the state. This will also
+		// add any orphans from scaling in as destroy nodes.
+		&ConfigTransformer{
+			Config: b.Config,
+		},
+
+		// Add dynamic values
+		&RootVariableTransformer{Config: b.Config, RawValues: b.RootVariableValues},
+		&ModuleVariableTransformer{Config: b.Config},
+		&LocalTransformer{Config: b.Config},
+		&OutputTransformer{
+			Config:   b.Config,
+			Planning: true,
+		},
+
+		// Attach the configuration to any resources
+		&AttachResourceConfigTransformer{Config: b.Config},
+
+		// Attach the state
+		&AttachStateTransformer{State: b.State},
+
+		transformProviders(concreteProvider, b.Config),
+
+		// Must attach schemas before ReferenceTransformer so that we can
+		// analyze the configuration to find references.
+		&AttachSchemaTransformer{Plugins: b.Plugins, Config: b.Config},
+
+		// Create expansion nodes for all of the module calls. This must
+		// come after all other transformers that create nodes representing
+		// objects that can belong to modules.
+		&ModuleExpansionTransformer{Config: b.Config},
+
+		// Connect so that the references are ready for targeting. We'll
+		// have to connect again later for providers and so on.
+		&ReferenceTransformer{},
+
+		// Although we don't configure providers, we do still start them up
+		// to get their schemas, and so we must shut them down again here.
+		&CloseProviderTransformer{},
+
+		// Close root module
+		&CloseRootModuleTransformer{},
+
+		// Remove redundant edges to simplify the graph.
+		&TransitiveReductionTransformer{},
+	}
+
+	return steps
+}
diff --git a/v1.5.7/internal/terraform/graph_builder_plan.go b/v1.5.7/internal/terraform/graph_builder_plan.go
new file mode 100644
index 0000000..9d37781
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph_builder_plan.go
@@ -0,0 +1,333 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// PlanGraphBuilder is a GraphBuilder implementation that builds a graph for
+// planning and for other "plan-like" operations which don't require an
+// already-calculated plan as input.
+//
+// Unlike the apply graph builder, this graph builder:
+//
+//   - Makes its decisions primarily based on the given configuration, which
+//     represents the desired state.
+//
+//   - Ignores certain lifecycle concerns like create_before_destroy, because
+//     those are only important once we already know what action we're planning
+//     to take against a particular resource instance.
+type PlanGraphBuilder struct {
+	// Config is the configuration tree to build a plan from.
+	Config *configs.Config
+
+	// State is the current state
+	State *states.State
+
+	// RootVariableValues are the raw input values for root input variables
+	// given by the caller, which we'll resolve into final values as part
+	// of the plan walk.
+	RootVariableValues InputValues
+
+	// Plugins is a library of plug-in components (providers and
+	// provisioners) available for use.
+	Plugins *contextPlugins
+
+	// Targets are resources to target
+	Targets []addrs.Targetable
+
+	// ForceReplace are resource instances where if we would normally have
+	// generated a NoOp or Update action then we'll force generating a replace
+	// action instead. Create and Delete actions are not affected.
+	ForceReplace []addrs.AbsResourceInstance
+
+	// skipRefresh indicates that we should skip refreshing managed resources
+	skipRefresh bool
+
+	// preDestroyRefresh indicates that we are executing the refresh which
+	// happens immediately before a destroy plan, which happens to use the
+	// normal planing mode so skipPlanChanges cannot be set.
+	preDestroyRefresh bool
+
+	// skipPlanChanges indicates that we should skip the step of comparing
+	// prior state with configuration and generating planned changes to
+	// resource instances. (This is for the "refresh only" planning mode,
+	// where we _only_ do the refresh step.)
+	skipPlanChanges bool
+
+	ConcreteProvider                ConcreteProviderNodeFunc
+	ConcreteResource                ConcreteResourceNodeFunc
+	ConcreteResourceInstance        ConcreteResourceInstanceNodeFunc
+	ConcreteResourceOrphan          ConcreteResourceInstanceNodeFunc
+	ConcreteResourceInstanceDeposed ConcreteResourceInstanceDeposedNodeFunc
+	ConcreteModule                  ConcreteModuleNodeFunc
+
+	// Plan Operation this graph will be used for.
+	Operation walkOperation
+
+	// ImportTargets are the list of resources to import.
+	ImportTargets []*ImportTarget
+
+	// GenerateConfig tells Terraform where to write and generated config for
+	// any import targets that do not already have configuration.
+	//
+	// If empty, then config will not be generated.
+	GenerateConfigPath string
+}
+
+// See GraphBuilder
+func (b *PlanGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
+	log.Printf("[TRACE] building graph for %s", b.Operation)
+	return (&BasicGraphBuilder{
+		Steps: b.Steps(),
+		Name:  "PlanGraphBuilder",
+	}).Build(path)
+}
+
+// See GraphBuilder
+func (b *PlanGraphBuilder) Steps() []GraphTransformer {
+	switch b.Operation {
+	case walkPlan:
+		b.initPlan()
+	case walkPlanDestroy:
+		b.initDestroy()
+	case walkValidate:
+		b.initValidate()
+	case walkImport:
+		b.initImport()
+	default:
+		panic("invalid plan operation: " + b.Operation.String())
+	}
+
+	steps := []GraphTransformer{
+		// Creates all the resources represented in the config
+		&ConfigTransformer{
+			Concrete: b.ConcreteResource,
+			Config:   b.Config,
+
+			// Resources are not added from the config on destroy.
+			skip: b.Operation == walkPlanDestroy,
+
+			importTargets: b.ImportTargets,
+
+			// We only want to generate config during a plan operation.
+			generateConfigPathForImportTargets: b.GenerateConfigPath,
+		},
+
+		// Add dynamic values
+		&RootVariableTransformer{Config: b.Config, RawValues: b.RootVariableValues},
+		&ModuleVariableTransformer{Config: b.Config},
+		&LocalTransformer{Config: b.Config},
+		&OutputTransformer{
+			Config:      b.Config,
+			RefreshOnly: b.skipPlanChanges || b.preDestroyRefresh,
+			Destroying:  b.Operation == walkPlanDestroy,
+
+			// NOTE: We currently treat anything built with the plan graph
+			// builder as "planning" for our purposes here, because we share
+			// the same graph node implementation between all of the walk
+			// types and so the pre-planning walks still think they are
+			// producing a plan even though we immediately discard it.
+			Planning: true,
+		},
+
+		// Add nodes and edges for the check block assertions. Check block data
+		// sources were added earlier.
+		&checkTransformer{
+			Config:    b.Config,
+			Operation: b.Operation,
+		},
+
+		// Add orphan resources
+		&OrphanResourceInstanceTransformer{
+			Concrete: b.ConcreteResourceOrphan,
+			State:    b.State,
+			Config:   b.Config,
+			skip:     b.Operation == walkPlanDestroy,
+		},
+
+		// We also need nodes for any deposed instance objects present in the
+		// state, so we can plan to destroy them. (During plan this will
+		// intentionally skip creating nodes for _current_ objects, since
+		// ConfigTransformer created nodes that will do that during
+		// DynamicExpand.)
+		&StateTransformer{
+			ConcreteCurrent: b.ConcreteResourceInstance,
+			ConcreteDeposed: b.ConcreteResourceInstanceDeposed,
+			State:           b.State,
+		},
+
+		// Attach the state
+		&AttachStateTransformer{State: b.State},
+
+		// Create orphan output nodes
+		&OrphanOutputTransformer{
+			Config:   b.Config,
+			State:    b.State,
+			Planning: true,
+		},
+
+		// Attach the configuration to any resources
+		&AttachResourceConfigTransformer{Config: b.Config},
+
+		// add providers
+		transformProviders(b.ConcreteProvider, b.Config),
+
+		// Remove modules no longer present in the config
+		&RemovedModuleTransformer{Config: b.Config, State: b.State},
+
+		// Must attach schemas before ReferenceTransformer so that we can
+		// analyze the configuration to find references.
+		&AttachSchemaTransformer{Plugins: b.Plugins, Config: b.Config},
+
+		// Create expansion nodes for all of the module calls. This must
+		// come after all other transformers that create nodes representing
+		// objects that can belong to modules.
+		&ModuleExpansionTransformer{Concrete: b.ConcreteModule, Config: b.Config},
+
+		&ReferenceTransformer{},
+
+		&AttachDependenciesTransformer{},
+
+		// Make sure data sources are aware of any depends_on from the
+		// configuration
+		&attachDataResourceDependsOnTransformer{},
+
+		// DestroyEdgeTransformer is only required during a plan so that the
+		// TargetsTransformer can determine which nodes to keep in the graph.
+		&DestroyEdgeTransformer{
+			Operation: b.Operation,
+		},
+
+		&pruneUnusedNodesTransformer{
+			skip: b.Operation != walkPlanDestroy,
+		},
+
+		// Target
+		&TargetsTransformer{Targets: b.Targets},
+
+		// Detect when create_before_destroy must be forced on for a particular
+		// node due to dependency edges, to avoid graph cycles during apply.
+		&ForcedCBDTransformer{},
+
+		// Close opened plugin connections
+		&CloseProviderTransformer{},
+
+		// Close the root module
+		&CloseRootModuleTransformer{},
+
+		// Perform the transitive reduction to make our graph a bit
+		// more understandable if possible (it usually is possible).
+		&TransitiveReductionTransformer{},
+	}
+
+	return steps
+}
+
+func (b *PlanGraphBuilder) initPlan() {
+	b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex {
+		return &NodeApplyableProvider{
+			NodeAbstractProvider: a,
+		}
+	}
+
+	b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex {
+		return &nodeExpandPlannableResource{
+			NodeAbstractResource: a,
+			skipRefresh:          b.skipRefresh,
+			skipPlanChanges:      b.skipPlanChanges,
+			preDestroyRefresh:    b.preDestroyRefresh,
+			forceReplace:         b.ForceReplace,
+		}
+	}
+
+	b.ConcreteResourceOrphan = func(a *NodeAbstractResourceInstance) dag.Vertex {
+		return &NodePlannableResourceInstanceOrphan{
+			NodeAbstractResourceInstance: a,
+			skipRefresh:                  b.skipRefresh,
+			skipPlanChanges:              b.skipPlanChanges,
+		}
+	}
+
+	b.ConcreteResourceInstanceDeposed = func(a *NodeAbstractResourceInstance, key states.DeposedKey) dag.Vertex {
+		return &NodePlanDeposedResourceInstanceObject{
+			NodeAbstractResourceInstance: a,
+			DeposedKey:                   key,
+
+			skipRefresh:     b.skipRefresh,
+			skipPlanChanges: b.skipPlanChanges,
+		}
+	}
+}
+
+func (b *PlanGraphBuilder) initDestroy() {
+	b.initPlan()
+
+	b.ConcreteResourceInstance = func(a *NodeAbstractResourceInstance) dag.Vertex {
+		return &NodePlanDestroyableResourceInstance{
+			NodeAbstractResourceInstance: a,
+			skipRefresh:                  b.skipRefresh,
+		}
+	}
+}
+
+func (b *PlanGraphBuilder) initValidate() {
+	// Set the provider to the normal provider. This will ask for input.
+	b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex {
+		return &NodeApplyableProvider{
+			NodeAbstractProvider: a,
+		}
+	}
+
+	b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex {
+		return &NodeValidatableResource{
+			NodeAbstractResource: a,
+		}
+	}
+
+	b.ConcreteModule = func(n *nodeExpandModule) dag.Vertex {
+		return &nodeValidateModule{
+			nodeExpandModule: *n,
+		}
+	}
+}
+
+func (b *PlanGraphBuilder) initImport() {
+	b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex {
+		return &NodeApplyableProvider{
+			NodeAbstractProvider: a,
+		}
+	}
+
+	b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex {
+		return &nodeExpandPlannableResource{
+			NodeAbstractResource: a,
+
+			// For now we always skip planning changes for import, since we are
+			// not going to combine importing with other changes. This is
+			// temporary to try and maintain existing import behaviors, but
+			// planning will need to be allowed for more complex configurations.
+			skipPlanChanges: true,
+
+			// We also skip refresh for now, since the plan output is written
+			// as the new state, and users are not expecting the import process
+			// to update any other instances in state.
+			skipRefresh: true,
+
+			// If we get here, we know that we are in legacy import mode, and
+			// that the user has run the import command rather than plan.
+			// This flag must be propagated down to the
+			// NodePlannableResourceInstance so we can ignore the new import
+			// behaviour.
+			legacyImportMode: true,
+		}
+	}
+}
diff --git a/v1.5.7/internal/terraform/graph_builder_plan_test.go b/v1.5.7/internal/terraform/graph_builder_plan_test.go
new file mode 100644
index 0000000..a89c6dc
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph_builder_plan_test.go
@@ -0,0 +1,276 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+)
+
+func TestPlanGraphBuilder_impl(t *testing.T) {
+	var _ GraphBuilder = new(PlanGraphBuilder)
+}
+
+func TestPlanGraphBuilder(t *testing.T) {
+	awsProvider := &MockProvider{
+		GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+			Provider: providers.Schema{Block: simpleTestSchema()},
+			ResourceTypes: map[string]providers.Schema{
+				"aws_security_group": {Block: simpleTestSchema()},
+				"aws_instance":       {Block: simpleTestSchema()},
+				"aws_load_balancer":  {Block: simpleTestSchema()},
+			},
+		},
+	}
+	openstackProvider := mockProviderWithResourceTypeSchema("openstack_floating_ip", simpleTestSchema())
+	plugins := newContextPlugins(map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("aws"):       providers.FactoryFixed(awsProvider),
+		addrs.NewDefaultProvider("openstack"): providers.FactoryFixed(openstackProvider),
+	}, nil)
+
+	b := &PlanGraphBuilder{
+		Config:    testModule(t, "graph-builder-plan-basic"),
+		Plugins:   plugins,
+		Operation: walkPlan,
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if g.Path.String() != addrs.RootModuleInstance.String() {
+		t.Fatalf("wrong module path %q", g.Path)
+	}
+
+	got := strings.TrimSpace(g.String())
+	want := strings.TrimSpace(testPlanGraphBuilderStr)
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Fatalf("wrong result\n%s", diff)
+	}
+}
+
+func TestPlanGraphBuilder_dynamicBlock(t *testing.T) {
+	provider := mockProviderWithResourceTypeSchema("test_thing", &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"id":   {Type: cty.String, Computed: true},
+			"list": {Type: cty.List(cty.String), Computed: true},
+		},
+		BlockTypes: map[string]*configschema.NestedBlock{
+			"nested": {
+				Nesting: configschema.NestingList,
+				Block: configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"foo": {Type: cty.String, Optional: true},
+					},
+				},
+			},
+		},
+	})
+	plugins := newContextPlugins(map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("test"): providers.FactoryFixed(provider),
+	}, nil)
+
+	b := &PlanGraphBuilder{
+		Config:    testModule(t, "graph-builder-plan-dynblock"),
+		Plugins:   plugins,
+		Operation: walkPlan,
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if g.Path.String() != addrs.RootModuleInstance.String() {
+		t.Fatalf("wrong module path %q", g.Path)
+	}
+
+	// This test is here to make sure we properly detect references inside
+	// the special "dynamic" block construct. The most important thing here
+	// is that at the end test_thing.c depends on both test_thing.a and
+	// test_thing.b. Other details might shift over time as other logic in
+	// the graph builders changes.
+	got := strings.TrimSpace(g.String())
+	want := strings.TrimSpace(`
+provider["registry.terraform.io/hashicorp/test"]
+provider["registry.terraform.io/hashicorp/test"] (close)
+  test_thing.c (expand)
+root
+  provider["registry.terraform.io/hashicorp/test"] (close)
+test_thing.a (expand)
+  provider["registry.terraform.io/hashicorp/test"]
+test_thing.b (expand)
+  provider["registry.terraform.io/hashicorp/test"]
+test_thing.c (expand)
+  test_thing.a (expand)
+  test_thing.b (expand)
+`)
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Fatalf("wrong result\n%s", diff)
+	}
+}
+
+func TestPlanGraphBuilder_attrAsBlocks(t *testing.T) {
+	provider := mockProviderWithResourceTypeSchema("test_thing", &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"id": {Type: cty.String, Computed: true},
+			"nested": {
+				Type: cty.List(cty.Object(map[string]cty.Type{
+					"foo": cty.String,
+				})),
+				Optional: true,
+			},
+		},
+	})
+	plugins := newContextPlugins(map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("test"): providers.FactoryFixed(provider),
+	}, nil)
+
+	b := &PlanGraphBuilder{
+		Config:    testModule(t, "graph-builder-plan-attr-as-blocks"),
+		Plugins:   plugins,
+		Operation: walkPlan,
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if g.Path.String() != addrs.RootModuleInstance.String() {
+		t.Fatalf("wrong module path %q", g.Path)
+	}
+
+	// This test is here to make sure we properly detect references inside
+	// the "nested" block that is actually defined in the schema as a
+	// list-of-objects attribute. This requires some special effort
+	// inside lang.ReferencesInBlock to make sure it searches blocks of
+	// type "nested" along with an attribute named "nested".
+	got := strings.TrimSpace(g.String())
+	want := strings.TrimSpace(`
+provider["registry.terraform.io/hashicorp/test"]
+provider["registry.terraform.io/hashicorp/test"] (close)
+  test_thing.b (expand)
+root
+  provider["registry.terraform.io/hashicorp/test"] (close)
+test_thing.a (expand)
+  provider["registry.terraform.io/hashicorp/test"]
+test_thing.b (expand)
+  test_thing.a (expand)
+`)
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Fatalf("wrong result\n%s", diff)
+	}
+}
+
+func TestPlanGraphBuilder_targetModule(t *testing.T) {
+	b := &PlanGraphBuilder{
+		Config:  testModule(t, "graph-builder-plan-target-module-provider"),
+		Plugins: simpleMockPluginLibrary(),
+		Targets: []addrs.Targetable{
+			addrs.RootModuleInstance.Child("child2", addrs.NoKey),
+		},
+		Operation: walkPlan,
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	t.Logf("Graph: %s", g.String())
+
+	testGraphNotContains(t, g, `module.child1.provider["registry.terraform.io/hashicorp/test"]`)
+	testGraphNotContains(t, g, "module.child1.test_object.foo")
+}
+
+func TestPlanGraphBuilder_forEach(t *testing.T) {
+	awsProvider := mockProviderWithResourceTypeSchema("aws_instance", simpleTestSchema())
+
+	plugins := newContextPlugins(map[addrs.Provider]providers.Factory{
+		addrs.NewDefaultProvider("aws"): providers.FactoryFixed(awsProvider),
+	}, nil)
+
+	b := &PlanGraphBuilder{
+		Config:    testModule(t, "plan-for-each"),
+		Plugins:   plugins,
+		Operation: walkPlan,
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if g.Path.String() != addrs.RootModuleInstance.String() {
+		t.Fatalf("wrong module path %q", g.Path)
+	}
+
+	got := strings.TrimSpace(g.String())
+	// We're especially looking for the edge here, where aws_instance.bat
+	// has a dependency on aws_instance.boo
+	want := strings.TrimSpace(testPlanGraphBuilderForEachStr)
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Fatalf("wrong result\n%s", diff)
+	}
+}
+
+const testPlanGraphBuilderStr = `
+aws_instance.web (expand)
+  aws_security_group.firewall (expand)
+  var.foo
+aws_load_balancer.weblb (expand)
+  aws_instance.web (expand)
+aws_security_group.firewall (expand)
+  provider["registry.terraform.io/hashicorp/aws"]
+local.instance_id (expand)
+  aws_instance.web (expand)
+openstack_floating_ip.random (expand)
+  provider["registry.terraform.io/hashicorp/openstack"]
+output.instance_id (expand)
+  local.instance_id (expand)
+provider["registry.terraform.io/hashicorp/aws"]
+  openstack_floating_ip.random (expand)
+provider["registry.terraform.io/hashicorp/aws"] (close)
+  aws_load_balancer.weblb (expand)
+provider["registry.terraform.io/hashicorp/openstack"]
+provider["registry.terraform.io/hashicorp/openstack"] (close)
+  openstack_floating_ip.random (expand)
+root
+  output.instance_id (expand)
+  provider["registry.terraform.io/hashicorp/aws"] (close)
+  provider["registry.terraform.io/hashicorp/openstack"] (close)
+var.foo
+`
+const testPlanGraphBuilderForEachStr = `
+aws_instance.bar (expand)
+  provider["registry.terraform.io/hashicorp/aws"]
+aws_instance.bar2 (expand)
+  provider["registry.terraform.io/hashicorp/aws"]
+aws_instance.bat (expand)
+  aws_instance.boo (expand)
+aws_instance.baz (expand)
+  provider["registry.terraform.io/hashicorp/aws"]
+aws_instance.boo (expand)
+  provider["registry.terraform.io/hashicorp/aws"]
+aws_instance.foo (expand)
+  provider["registry.terraform.io/hashicorp/aws"]
+provider["registry.terraform.io/hashicorp/aws"]
+provider["registry.terraform.io/hashicorp/aws"] (close)
+  aws_instance.bar (expand)
+  aws_instance.bar2 (expand)
+  aws_instance.bat (expand)
+  aws_instance.baz (expand)
+  aws_instance.foo (expand)
+root
+  provider["registry.terraform.io/hashicorp/aws"] (close)
+`
diff --git a/v1.5.7/internal/terraform/graph_builder_test.go b/v1.5.7/internal/terraform/graph_builder_test.go
new file mode 100644
index 0000000..733ee2d
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph_builder_test.go
@@ -0,0 +1,67 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+func TestBasicGraphBuilder_impl(t *testing.T) {
+	var _ GraphBuilder = new(BasicGraphBuilder)
+}
+
+func TestBasicGraphBuilder(t *testing.T) {
+	b := &BasicGraphBuilder{
+		Steps: []GraphTransformer{
+			&testBasicGraphBuilderTransform{1},
+		},
+	}
+
+	g, err := b.Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if g.Path.String() != addrs.RootModuleInstance.String() {
+		t.Fatalf("wrong module path %q", g.Path)
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testBasicGraphBuilderStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+func TestBasicGraphBuilder_validate(t *testing.T) {
+	b := &BasicGraphBuilder{
+		Steps: []GraphTransformer{
+			&testBasicGraphBuilderTransform{1},
+			&testBasicGraphBuilderTransform{2},
+		},
+	}
+
+	_, err := b.Build(addrs.RootModuleInstance)
+	if err == nil {
+		t.Fatal("should error")
+	}
+}
+
+type testBasicGraphBuilderTransform struct {
+	V dag.Vertex
+}
+
+func (t *testBasicGraphBuilderTransform) Transform(g *Graph) error {
+	g.Add(t.V)
+	return nil
+}
+
+const testBasicGraphBuilderStr = `
+1
+`
diff --git a/v1.5.7/internal/terraform/graph_dot.go b/v1.5.7/internal/terraform/graph_dot.go
new file mode 100644
index 0000000..de3f4a9
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph_dot.go
@@ -0,0 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import "github.com/hashicorp/terraform/internal/dag"
+
+// GraphDot returns the dot formatting of a visual representation of
+// the given Terraform graph.
+func GraphDot(g *Graph, opts *dag.DotOpts) (string, error) {
+	return string(g.Dot(opts)), nil
+}
diff --git a/v1.5.7/internal/terraform/graph_dot_test.go b/v1.5.7/internal/terraform/graph_dot_test.go
new file mode 100644
index 0000000..b4f7cd9
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph_dot_test.go
@@ -0,0 +1,316 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+func TestGraphDot(t *testing.T) {
+	cases := []struct {
+		Name   string
+		Graph  testGraphFunc
+		Opts   dag.DotOpts
+		Expect string
+		Error  string
+	}{
+		{
+			Name:  "empty",
+			Graph: func() *Graph { return &Graph{} },
+			Expect: `
+digraph {
+	compound = "true"
+	newrank = "true"
+	subgraph "root" {
+	}
+}`,
+		},
+		{
+			Name: "three-level",
+			Graph: func() *Graph {
+				var g Graph
+				root := &testDrawableOrigin{"root"}
+				g.Add(root)
+
+				levelOne := []interface{}{"foo", "bar"}
+				for i, s := range levelOne {
+					levelOne[i] = &testDrawable{
+						VertexName: s.(string),
+					}
+					v := levelOne[i]
+
+					g.Add(v)
+					g.Connect(dag.BasicEdge(v, root))
+				}
+
+				levelTwo := []string{"baz", "qux"}
+				for i, s := range levelTwo {
+					v := &testDrawable{
+						VertexName: s,
+					}
+
+					g.Add(v)
+					g.Connect(dag.BasicEdge(v, levelOne[i]))
+				}
+
+				return &g
+			},
+			Expect: `
+digraph {
+	compound = "true"
+	newrank = "true"
+	subgraph "root" {
+		"[root] bar"
+		"[root] baz"
+		"[root] foo"
+		"[root] qux"
+		"[root] root"
+		"[root] bar" -> "[root] root"
+		"[root] baz" -> "[root] foo"
+		"[root] foo" -> "[root] root"
+		"[root] qux" -> "[root] bar"
+	}
+}
+			`,
+		},
+
+		{
+			Name: "cycle",
+			Opts: dag.DotOpts{
+				DrawCycles: true,
+			},
+			Graph: func() *Graph {
+				var g Graph
+				root := &testDrawableOrigin{"root"}
+				g.Add(root)
+
+				vA := g.Add(&testDrawable{
+					VertexName: "A",
+				})
+
+				vB := g.Add(&testDrawable{
+					VertexName: "B",
+				})
+
+				vC := g.Add(&testDrawable{
+					VertexName: "C",
+				})
+
+				g.Connect(dag.BasicEdge(vA, root))
+				g.Connect(dag.BasicEdge(vA, vC))
+				g.Connect(dag.BasicEdge(vB, vA))
+				g.Connect(dag.BasicEdge(vC, vB))
+
+				return &g
+			},
+			Expect: `
+digraph {
+	compound = "true"
+	newrank = "true"
+	subgraph "root" {
+		"[root] A"
+		"[root] B"
+		"[root] C"
+		"[root] root"
+		"[root] A" -> "[root] B" [color = "red", penwidth = "2.0"]
+		"[root] A" -> "[root] C"
+		"[root] A" -> "[root] root"
+		"[root] B" -> "[root] A"
+		"[root] B" -> "[root] C" [color = "red", penwidth = "2.0"]
+		"[root] C" -> "[root] A" [color = "red", penwidth = "2.0"]
+		"[root] C" -> "[root] B"
+	}
+}
+					`,
+		},
+
+		{
+			Name: "subgraphs, no depth restriction",
+			Opts: dag.DotOpts{
+				MaxDepth: -1,
+			},
+			Graph: func() *Graph {
+				var g Graph
+				root := &testDrawableOrigin{"root"}
+				g.Add(root)
+
+				var sub Graph
+				vSubRoot := sub.Add(&testDrawableOrigin{"sub_root"})
+
+				var subsub Graph
+				subsub.Add(&testDrawableOrigin{"subsub_root"})
+				vSubV := sub.Add(&testDrawableSubgraph{
+					VertexName:   "subsub",
+					SubgraphMock: &subsub,
+				})
+
+				vSub := g.Add(&testDrawableSubgraph{
+					VertexName:   "sub",
+					SubgraphMock: &sub,
+				})
+
+				g.Connect(dag.BasicEdge(vSub, root))
+				sub.Connect(dag.BasicEdge(vSubV, vSubRoot))
+
+				return &g
+			},
+			Expect: `
+digraph {
+	compound = "true"
+	newrank = "true"
+	subgraph "root" {
+		"[root] root"
+		"[root] sub"
+		"[root] sub" -> "[root] root"
+	}
+	subgraph "cluster_sub" {
+		label = "sub"
+		"[sub] sub_root"
+		"[sub] subsub"
+		"[sub] subsub" -> "[sub] sub_root"
+	}
+	subgraph "cluster_subsub" {
+		label = "subsub"
+		"[subsub] subsub_root"
+	}
+}
+						`,
+		},
+
+		{
+			Name: "subgraphs, with depth restriction",
+			Opts: dag.DotOpts{
+				MaxDepth: 1,
+			},
+			Graph: func() *Graph {
+				var g Graph
+				root := &testDrawableOrigin{"root"}
+				g.Add(root)
+
+				var sub Graph
+				rootSub := sub.Add(&testDrawableOrigin{"sub_root"})
+
+				var subsub Graph
+				subsub.Add(&testDrawableOrigin{"subsub_root"})
+
+				subV := sub.Add(&testDrawableSubgraph{
+					VertexName:   "subsub",
+					SubgraphMock: &subsub,
+				})
+				vSub := g.Add(&testDrawableSubgraph{
+					VertexName:   "sub",
+					SubgraphMock: &sub,
+				})
+
+				g.Connect(dag.BasicEdge(vSub, root))
+				sub.Connect(dag.BasicEdge(subV, rootSub))
+				return &g
+			},
+			Expect: `
+digraph {
+	compound = "true"
+	newrank = "true"
+	subgraph "root" {
+		"[root] root"
+		"[root] sub"
+		"[root] sub" -> "[root] root"
+	}
+	subgraph "cluster_sub" {
+		label = "sub"
+		"[sub] sub_root"
+		"[sub] subsub"
+		"[sub] subsub" -> "[sub] sub_root"
+	}
+}
+						`,
+		},
+	}
+
+	for _, tc := range cases {
+		tn := tc.Name
+		t.Run(tn, func(t *testing.T) {
+			g := tc.Graph()
+			var err error
+			//actual, err := GraphDot(g, &tc.Opts)
+			actual := string(g.Dot(&tc.Opts))
+
+			if err == nil && tc.Error != "" {
+				t.Fatalf("%s: expected err: %s, got none", tn, tc.Error)
+			}
+			if err != nil && tc.Error == "" {
+				t.Fatalf("%s: unexpected err: %s", tn, err)
+			}
+			if err != nil && tc.Error != "" {
+				if !strings.Contains(err.Error(), tc.Error) {
+					t.Fatalf("%s: expected err: %s\nto contain: %s", tn, err, tc.Error)
+				}
+				return
+			}
+
+			expected := strings.TrimSpace(tc.Expect) + "\n"
+			if actual != expected {
+				t.Fatalf("%s:\n\nexpected:\n%s\n\ngot:\n%s", tn, expected, actual)
+			}
+		})
+	}
+}
+
+type testGraphFunc func() *Graph
+
+type testDrawable struct {
+	VertexName      string
+	DependentOnMock []string
+}
+
+func (node *testDrawable) Name() string {
+	return node.VertexName
+}
+func (node *testDrawable) DotNode(n string, opts *dag.DotOpts) *dag.DotNode {
+	return &dag.DotNode{Name: n, Attrs: map[string]string{}}
+}
+func (node *testDrawable) DependableName() []string {
+	return []string{node.VertexName}
+}
+func (node *testDrawable) DependentOn() []string {
+	return node.DependentOnMock
+}
+
+type testDrawableOrigin struct {
+	VertexName string
+}
+
+func (node *testDrawableOrigin) Name() string {
+	return node.VertexName
+}
+func (node *testDrawableOrigin) DotNode(n string, opts *dag.DotOpts) *dag.DotNode {
+	return &dag.DotNode{Name: n, Attrs: map[string]string{}}
+}
+func (node *testDrawableOrigin) DotOrigin() bool {
+	return true
+}
+func (node *testDrawableOrigin) DependableName() []string {
+	return []string{node.VertexName}
+}
+
+type testDrawableSubgraph struct {
+	VertexName      string
+	SubgraphMock    *Graph
+	DependentOnMock []string
+}
+
+func (node *testDrawableSubgraph) Name() string {
+	return node.VertexName
+}
+func (node *testDrawableSubgraph) Subgraph() dag.Grapher {
+	return node.SubgraphMock
+}
+func (node *testDrawableSubgraph) DotNode(n string, opts *dag.DotOpts) *dag.DotNode {
+	return &dag.DotNode{Name: n, Attrs: map[string]string{}}
+}
+func (node *testDrawableSubgraph) DependentOn() []string {
+	return node.DependentOnMock
+}
diff --git a/v1.5.7/internal/terraform/graph_interface_subgraph.go b/v1.5.7/internal/terraform/graph_interface_subgraph.go
new file mode 100644
index 0000000..0c68905
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph_interface_subgraph.go
@@ -0,0 +1,20 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// GraphNodeModuleInstance says that a node is part of a graph with a
+// different path, and the context should be adjusted accordingly.
+type GraphNodeModuleInstance interface {
+	Path() addrs.ModuleInstance
+}
+
+// GraphNodeModulePath is implemented by all referenceable nodes, to indicate
+// their configuration path in unexpanded modules.
+type GraphNodeModulePath interface {
+	ModulePath() addrs.Module
+}
diff --git a/v1.5.7/internal/terraform/graph_test.go b/v1.5.7/internal/terraform/graph_test.go
new file mode 100644
index 0000000..f929563
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph_test.go
@@ -0,0 +1,59 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+// testGraphnotContains is an assertion helper that tests that a node is
+// NOT contained in the graph.
+func testGraphNotContains(t *testing.T, g *Graph, name string) {
+	for _, v := range g.Vertices() {
+		if dag.VertexName(v) == name {
+			t.Fatalf(
+				"Expected %q to NOT be in:\n\n%s",
+				name, g.String())
+		}
+	}
+}
+
+// testGraphHappensBefore is an assertion helper that tests that node
+// A (dag.VertexName value) happens before node B.
+func testGraphHappensBefore(t *testing.T, g *Graph, A, B string) {
+	t.Helper()
+	// Find the B vertex
+	var vertexB dag.Vertex
+	for _, v := range g.Vertices() {
+		if dag.VertexName(v) == B {
+			vertexB = v
+			break
+		}
+	}
+	if vertexB == nil {
+		t.Fatalf(
+			"Expected %q before %q. Couldn't find %q in:\n\n%s",
+			A, B, B, g.String())
+	}
+
+	// Look at ancestors
+	deps, err := g.Ancestors(vertexB)
+	if err != nil {
+		t.Fatalf("Error: %s in graph:\n\n%s", err, g.String())
+	}
+
+	// Make sure B is in there
+	for _, v := range deps.List() {
+		if dag.VertexName(v) == A {
+			// Success
+			return
+		}
+	}
+
+	t.Fatalf(
+		"Expected %q before %q in:\n\n%s",
+		A, B, g.String())
+}
diff --git a/v1.5.7/internal/terraform/graph_walk.go b/v1.5.7/internal/terraform/graph_walk.go
new file mode 100644
index 0000000..b9ed16e
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph_walk.go
@@ -0,0 +1,28 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// GraphWalker is an interface that can be implemented that when used
+// with Graph.Walk will invoke the given callbacks under certain events.
+type GraphWalker interface {
+	EvalContext() EvalContext
+	EnterPath(addrs.ModuleInstance) EvalContext
+	ExitPath(addrs.ModuleInstance)
+	Execute(EvalContext, GraphNodeExecutable) tfdiags.Diagnostics
+}
+
+// NullGraphWalker is a GraphWalker implementation that does nothing.
+// This can be embedded within other GraphWalker implementations for easily
+// implementing all the required functions.
+type NullGraphWalker struct{}
+
+func (NullGraphWalker) EvalContext() EvalContext                                     { return new(MockEvalContext) }
+func (NullGraphWalker) EnterPath(addrs.ModuleInstance) EvalContext                   { return new(MockEvalContext) }
+func (NullGraphWalker) ExitPath(addrs.ModuleInstance)                                {}
+func (NullGraphWalker) Execute(EvalContext, GraphNodeExecutable) tfdiags.Diagnostics { return nil }
diff --git a/v1.5.7/internal/terraform/graph_walk_context.go b/v1.5.7/internal/terraform/graph_walk_context.go
new file mode 100644
index 0000000..3b4409d
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph_walk_context.go
@@ -0,0 +1,144 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"context"
+	"sync"
+	"time"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/refactoring"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ContextGraphWalker is the GraphWalker implementation used with the
+// Context struct to walk and evaluate the graph.
+type ContextGraphWalker struct {
+	NullGraphWalker
+
+	// Configurable values
+	Context            *Context
+	State              *states.SyncState   // Used for safe concurrent access to state
+	RefreshState       *states.SyncState   // Used for safe concurrent access to state
+	PrevRunState       *states.SyncState   // Used for safe concurrent access to state
+	Changes            *plans.ChangesSync  // Used for safe concurrent writes to changes
+	Checks             *checks.State       // Used for safe concurrent writes of checkable objects and their check results
+	InstanceExpander   *instances.Expander // Tracks our gradual expansion of module and resource instances
+	Imports            []configs.Import
+	MoveResults        refactoring.MoveResults // Read-only record of earlier processing of move statements
+	Operation          walkOperation
+	StopContext        context.Context
+	RootVariableValues InputValues
+	Config             *configs.Config
+	PlanTimestamp      time.Time
+
+	// This is an output. Do not set this, nor read it while a graph walk
+	// is in progress.
+	NonFatalDiagnostics tfdiags.Diagnostics
+
+	once               sync.Once
+	contexts           map[string]*BuiltinEvalContext
+	contextLock        sync.Mutex
+	variableValues     map[string]map[string]cty.Value
+	variableValuesLock sync.Mutex
+	providerCache      map[string]providers.Interface
+	providerSchemas    map[string]*ProviderSchema
+	providerLock       sync.Mutex
+	provisionerCache   map[string]provisioners.Interface
+	provisionerSchemas map[string]*configschema.Block
+	provisionerLock    sync.Mutex
+}
+
+func (w *ContextGraphWalker) EnterPath(path addrs.ModuleInstance) EvalContext {
+	w.contextLock.Lock()
+	defer w.contextLock.Unlock()
+
+	// If we already have a context for this path cached, use that
+	key := path.String()
+	if ctx, ok := w.contexts[key]; ok {
+		return ctx
+	}
+
+	ctx := w.EvalContext().WithPath(path)
+	w.contexts[key] = ctx.(*BuiltinEvalContext)
+	return ctx
+}
+
+func (w *ContextGraphWalker) EvalContext() EvalContext {
+	w.once.Do(w.init)
+
+	// Our evaluator shares some locks with the main context and the walker
+	// so that we can safely run multiple evaluations at once across
+	// different modules.
+	evaluator := &Evaluator{
+		Meta:               w.Context.meta,
+		Config:             w.Config,
+		Operation:          w.Operation,
+		State:              w.State,
+		Changes:            w.Changes,
+		Plugins:            w.Context.plugins,
+		VariableValues:     w.variableValues,
+		VariableValuesLock: &w.variableValuesLock,
+		PlanTimestamp:      w.PlanTimestamp,
+	}
+
+	ctx := &BuiltinEvalContext{
+		StopContext:           w.StopContext,
+		Hooks:                 w.Context.hooks,
+		InputValue:            w.Context.uiInput,
+		InstanceExpanderValue: w.InstanceExpander,
+		Plugins:               w.Context.plugins,
+		MoveResultsValue:      w.MoveResults,
+		ProviderCache:         w.providerCache,
+		ProviderInputConfig:   w.Context.providerInputConfig,
+		ProviderLock:          &w.providerLock,
+		ProvisionerCache:      w.provisionerCache,
+		ProvisionerLock:       &w.provisionerLock,
+		ChangesValue:          w.Changes,
+		ChecksValue:           w.Checks,
+		StateValue:            w.State,
+		RefreshStateValue:     w.RefreshState,
+		PrevRunStateValue:     w.PrevRunState,
+		Evaluator:             evaluator,
+		VariableValues:        w.variableValues,
+		VariableValuesLock:    &w.variableValuesLock,
+	}
+
+	return ctx
+}
+
+func (w *ContextGraphWalker) init() {
+	w.contexts = make(map[string]*BuiltinEvalContext)
+	w.providerCache = make(map[string]providers.Interface)
+	w.providerSchemas = make(map[string]*ProviderSchema)
+	w.provisionerCache = make(map[string]provisioners.Interface)
+	w.provisionerSchemas = make(map[string]*configschema.Block)
+	w.variableValues = make(map[string]map[string]cty.Value)
+
+	// Populate root module variable values. Other modules will be populated
+	// during the graph walk.
+	w.variableValues[""] = make(map[string]cty.Value)
+	for k, iv := range w.RootVariableValues {
+		w.variableValues[""][k] = iv.Value
+	}
+}
+
+func (w *ContextGraphWalker) Execute(ctx EvalContext, n GraphNodeExecutable) tfdiags.Diagnostics {
+	// Acquire a lock on the semaphore
+	w.Context.parallelSem.Acquire()
+	defer w.Context.parallelSem.Release()
+
+	return n.Execute(ctx, w.Operation)
+}
diff --git a/v1.5.7/internal/terraform/graph_walk_operation.go b/v1.5.7/internal/terraform/graph_walk_operation.go
new file mode 100644
index 0000000..0ec6786
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph_walk_operation.go
@@ -0,0 +1,20 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=walkOperation graph_walk_operation.go
+
+// walkOperation is an enum which tells the walkContext what to do.
+type walkOperation byte
+
+const (
+	walkInvalid walkOperation = iota
+	walkApply
+	walkPlan
+	walkPlanDestroy
+	walkValidate
+	walkDestroy
+	walkImport
+	walkEval // used just to prepare EvalContext for expression evaluation, with no other actions
+)
diff --git a/v1.5.7/internal/terraform/graph_walk_test.go b/v1.5.7/internal/terraform/graph_walk_test.go
new file mode 100644
index 0000000..485c73c
--- /dev/null
+++ b/v1.5.7/internal/terraform/graph_walk_test.go
@@ -0,0 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+)
+
+func TestNullGraphWalker_impl(t *testing.T) {
+	var _ GraphWalker = NullGraphWalker{}
+}
diff --git a/v1.5.7/internal/terraform/hook.go b/v1.5.7/internal/terraform/hook.go
new file mode 100644
index 0000000..f23247c
--- /dev/null
+++ b/v1.5.7/internal/terraform/hook.go
@@ -0,0 +1,195 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// HookAction is an enum of actions that can be taken as a result of a hook
+// callback. This allows you to modify the behavior of Terraform at runtime.
+type HookAction byte
+
+const (
+	// HookActionContinue continues with processing as usual.
+	HookActionContinue HookAction = iota
+
+	// HookActionHalt halts immediately: no more hooks are processed
+	// and the action that Terraform was about to take is cancelled.
+	HookActionHalt
+)
+
+// Hook is the interface that must be implemented to hook into various
+// parts of Terraform, allowing you to inspect or change behavior at runtime.
+//
+// There are MANY hook points into Terraform. If you only want to implement
+// some hook points, but not all (which is the likely case), then embed the
+// NilHook into your struct, which implements all of the interface but does
+// nothing. Then, override only the functions you want to implement.
+type Hook interface {
+	// PreApply and PostApply are called before and after an action for a
+	// single instance is applied. The error argument in PostApply is the
+	// error, if any, that was returned from the provider Apply call itself.
+	PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error)
+	PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error)
+
+	// PreDiff and PostDiff are called before and after a provider is given
+	// the opportunity to customize the proposed new state to produce the
+	// planned new state.
+	PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error)
+	PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error)
+
+	// The provisioning hooks signal both the overall start end end of
+	// provisioning for a particular instance and of each of the individual
+	// configured provisioners for each instance. The sequence of these
+	// for a given instance might look something like this:
+	//
+	//          PreProvisionInstance(aws_instance.foo[1], ...)
+	//      PreProvisionInstanceStep(aws_instance.foo[1], "file")
+	//     PostProvisionInstanceStep(aws_instance.foo[1], "file", nil)
+	//      PreProvisionInstanceStep(aws_instance.foo[1], "remote-exec")
+	//               ProvisionOutput(aws_instance.foo[1], "remote-exec", "Installing foo...")
+	//               ProvisionOutput(aws_instance.foo[1], "remote-exec", "Configuring bar...")
+	//     PostProvisionInstanceStep(aws_instance.foo[1], "remote-exec", nil)
+	//         PostProvisionInstance(aws_instance.foo[1], ...)
+	//
+	// ProvisionOutput is called with output sent back by the provisioners.
+	// This will be called multiple times as output comes in, with each call
+	// representing one line of output. It cannot control whether the
+	// provisioner continues running.
+	PreProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error)
+	PostProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error)
+	PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string) (HookAction, error)
+	PostProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string, err error) (HookAction, error)
+	ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, line string)
+
+	// PreRefresh and PostRefresh are called before and after a single
+	// resource state is refreshed, respectively.
+	PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error)
+	PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error)
+
+	// PreImportState and PostImportState are called before and after
+	// (respectively) each state import operation for a given resource address when
+	// using the legacy import command.
+	PreImportState(addr addrs.AbsResourceInstance, importID string) (HookAction, error)
+	PostImportState(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error)
+
+	// PrePlanImport and PostPlanImport are called during a plan before and after planning to import
+	// a new resource using the configuration-driven import workflow.
+	PrePlanImport(addr addrs.AbsResourceInstance, importID string) (HookAction, error)
+	PostPlanImport(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error)
+
+	// PreApplyImport and PostApplyImport are called during an apply for each imported resource when
+	// using the configuration-driven import workflow.
+	PreApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (HookAction, error)
+	PostApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (HookAction, error)
+
+	// Stopping is called if an external signal requests that Terraform
+	// gracefully abort an operation in progress.
+	//
+	// This notification might suggest that the user wants Terraform to exit
+	// ASAP and in that case it's possible that if Terraform runs for too much
+	// longer then it'll get killed un-gracefully, and so this hook could be
+	// an opportunity to persist any transient data that would be lost under
+	// a subsequent kill signal. However, implementations must take care to do
+	// so in a way that won't cause corruption if the process _is_ killed while
+	// this hook is still running.
+	//
+	// This hook cannot control whether Terraform continues, because the
+	// graceful shutdown process is typically already running by the time this
+	// function is called.
+	Stopping()
+
+	// PostStateUpdate is called each time the state is updated. It receives
+	// a deep copy of the state, which it may therefore access freely without
+	// any need for locks to protect from concurrent writes from the caller.
+	PostStateUpdate(new *states.State) (HookAction, error)
+}
+
+// NilHook is a Hook implementation that does nothing. It exists only to
+// simplify implementing hooks. You can embed this into your Hook implementation
+// and only implement the functions you are interested in.
+type NilHook struct{}
+
+var _ Hook = (*NilHook)(nil)
+
+func (*NilHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (*NilHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (*NilHook) PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (*NilHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (*NilHook) PreProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (*NilHook) PostProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (*NilHook) PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (*NilHook) PostProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string, err error) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (*NilHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, line string) {
+}
+
+func (*NilHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (*NilHook) PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (*NilHook) PreImportState(addr addrs.AbsResourceInstance, importID string) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (*NilHook) PostImportState(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (h *NilHook) PrePlanImport(addr addrs.AbsResourceInstance, importID string) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (h *NilHook) PostPlanImport(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (h *NilHook) PreApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (h *NilHook) PostApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (HookAction, error) {
+	return HookActionContinue, nil
+}
+
+func (*NilHook) Stopping() {
+	// Does nothing at all by default
+}
+
+func (*NilHook) PostStateUpdate(new *states.State) (HookAction, error) {
+	return HookActionContinue, nil
+}
diff --git a/v1.5.7/internal/terraform/hook_mock.go b/v1.5.7/internal/terraform/hook_mock.go
new file mode 100644
index 0000000..ae9aa39
--- /dev/null
+++ b/v1.5.7/internal/terraform/hook_mock.go
@@ -0,0 +1,333 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"sync"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// MockHook is an implementation of Hook that can be used for tests.
+// It records all of its function calls.
+type MockHook struct {
+	sync.Mutex
+
+	PreApplyCalled       bool
+	PreApplyAddr         addrs.AbsResourceInstance
+	PreApplyGen          states.Generation
+	PreApplyAction       plans.Action
+	PreApplyPriorState   cty.Value
+	PreApplyPlannedState cty.Value
+	PreApplyReturn       HookAction
+	PreApplyError        error
+
+	PostApplyCalled      bool
+	PostApplyAddr        addrs.AbsResourceInstance
+	PostApplyGen         states.Generation
+	PostApplyNewState    cty.Value
+	PostApplyError       error
+	PostApplyReturn      HookAction
+	PostApplyReturnError error
+	PostApplyFn          func(addrs.AbsResourceInstance, states.Generation, cty.Value, error) (HookAction, error)
+
+	PreDiffCalled        bool
+	PreDiffAddr          addrs.AbsResourceInstance
+	PreDiffGen           states.Generation
+	PreDiffPriorState    cty.Value
+	PreDiffProposedState cty.Value
+	PreDiffReturn        HookAction
+	PreDiffError         error
+
+	PostDiffCalled       bool
+	PostDiffAddr         addrs.AbsResourceInstance
+	PostDiffGen          states.Generation
+	PostDiffAction       plans.Action
+	PostDiffPriorState   cty.Value
+	PostDiffPlannedState cty.Value
+	PostDiffReturn       HookAction
+	PostDiffError        error
+
+	PreProvisionInstanceCalled bool
+	PreProvisionInstanceAddr   addrs.AbsResourceInstance
+	PreProvisionInstanceState  cty.Value
+	PreProvisionInstanceReturn HookAction
+	PreProvisionInstanceError  error
+
+	PostProvisionInstanceCalled bool
+	PostProvisionInstanceAddr   addrs.AbsResourceInstance
+	PostProvisionInstanceState  cty.Value
+	PostProvisionInstanceReturn HookAction
+	PostProvisionInstanceError  error
+
+	PreProvisionInstanceStepCalled          bool
+	PreProvisionInstanceStepAddr            addrs.AbsResourceInstance
+	PreProvisionInstanceStepProvisionerType string
+	PreProvisionInstanceStepReturn          HookAction
+	PreProvisionInstanceStepError           error
+
+	PostProvisionInstanceStepCalled          bool
+	PostProvisionInstanceStepAddr            addrs.AbsResourceInstance
+	PostProvisionInstanceStepProvisionerType string
+	PostProvisionInstanceStepErrorArg        error
+	PostProvisionInstanceStepReturn          HookAction
+	PostProvisionInstanceStepError           error
+
+	ProvisionOutputCalled          bool
+	ProvisionOutputAddr            addrs.AbsResourceInstance
+	ProvisionOutputProvisionerType string
+	ProvisionOutputMessage         string
+
+	PreRefreshCalled     bool
+	PreRefreshAddr       addrs.AbsResourceInstance
+	PreRefreshGen        states.Generation
+	PreRefreshPriorState cty.Value
+	PreRefreshReturn     HookAction
+	PreRefreshError      error
+
+	PostRefreshCalled     bool
+	PostRefreshAddr       addrs.AbsResourceInstance
+	PostRefreshGen        states.Generation
+	PostRefreshPriorState cty.Value
+	PostRefreshNewState   cty.Value
+	PostRefreshReturn     HookAction
+	PostRefreshError      error
+
+	PreImportStateCalled bool
+	PreImportStateAddr   addrs.AbsResourceInstance
+	PreImportStateID     string
+	PreImportStateReturn HookAction
+	PreImportStateError  error
+
+	PostImportStateCalled    bool
+	PostImportStateAddr      addrs.AbsResourceInstance
+	PostImportStateNewStates []providers.ImportedResource
+	PostImportStateReturn    HookAction
+	PostImportStateError     error
+
+	PrePlanImportCalled bool
+	PrePlanImportAddr   addrs.AbsResourceInstance
+	PrePlanImportReturn HookAction
+	PrePlanImportError  error
+
+	PostPlanImportAddr   addrs.AbsResourceInstance
+	PostPlanImportCalled bool
+	PostPlanImportReturn HookAction
+	PostPlanImportError  error
+
+	PreApplyImportCalled bool
+	PreApplyImportAddr   addrs.AbsResourceInstance
+	PreApplyImportReturn HookAction
+	PreApplyImportError  error
+
+	PostApplyImportCalled bool
+	PostApplyImportAddr   addrs.AbsResourceInstance
+	PostApplyImportReturn HookAction
+	PostApplyImportError  error
+
+	StoppingCalled bool
+
+	PostStateUpdateCalled bool
+	PostStateUpdateState  *states.State
+	PostStateUpdateReturn HookAction
+	PostStateUpdateError  error
+}
+
+var _ Hook = (*MockHook)(nil)
+
+func (h *MockHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.PreApplyCalled = true
+	h.PreApplyAddr = addr
+	h.PreApplyGen = gen
+	h.PreApplyAction = action
+	h.PreApplyPriorState = priorState
+	h.PreApplyPlannedState = plannedNewState
+	return h.PreApplyReturn, h.PreApplyError
+}
+
+func (h *MockHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.PostApplyCalled = true
+	h.PostApplyAddr = addr
+	h.PostApplyGen = gen
+	h.PostApplyNewState = newState
+	h.PostApplyError = err
+
+	if h.PostApplyFn != nil {
+		return h.PostApplyFn(addr, gen, newState, err)
+	}
+
+	return h.PostApplyReturn, h.PostApplyReturnError
+}
+
+func (h *MockHook) PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.PreDiffCalled = true
+	h.PreDiffAddr = addr
+	h.PreDiffGen = gen
+	h.PreDiffPriorState = priorState
+	h.PreDiffProposedState = proposedNewState
+	return h.PreDiffReturn, h.PreDiffError
+}
+
+func (h *MockHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.PostDiffCalled = true
+	h.PostDiffAddr = addr
+	h.PostDiffGen = gen
+	h.PostDiffAction = action
+	h.PostDiffPriorState = priorState
+	h.PostDiffPlannedState = plannedNewState
+	return h.PostDiffReturn, h.PostDiffError
+}
+
+func (h *MockHook) PreProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.PreProvisionInstanceCalled = true
+	h.PreProvisionInstanceAddr = addr
+	h.PreProvisionInstanceState = state
+	return h.PreProvisionInstanceReturn, h.PreProvisionInstanceError
+}
+
+func (h *MockHook) PostProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.PostProvisionInstanceCalled = true
+	h.PostProvisionInstanceAddr = addr
+	h.PostProvisionInstanceState = state
+	return h.PostProvisionInstanceReturn, h.PostProvisionInstanceError
+}
+
+func (h *MockHook) PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string) (HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.PreProvisionInstanceStepCalled = true
+	h.PreProvisionInstanceStepAddr = addr
+	h.PreProvisionInstanceStepProvisionerType = typeName
+	return h.PreProvisionInstanceStepReturn, h.PreProvisionInstanceStepError
+}
+
+func (h *MockHook) PostProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string, err error) (HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.PostProvisionInstanceStepCalled = true
+	h.PostProvisionInstanceStepAddr = addr
+	h.PostProvisionInstanceStepProvisionerType = typeName
+	h.PostProvisionInstanceStepErrorArg = err
+	return h.PostProvisionInstanceStepReturn, h.PostProvisionInstanceStepError
+}
+
+func (h *MockHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, line string) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.ProvisionOutputCalled = true
+	h.ProvisionOutputAddr = addr
+	h.ProvisionOutputProvisionerType = typeName
+	h.ProvisionOutputMessage = line
+}
+
+func (h *MockHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.PreRefreshCalled = true
+	h.PreRefreshAddr = addr
+	h.PreRefreshGen = gen
+	h.PreRefreshPriorState = priorState
+	return h.PreRefreshReturn, h.PreRefreshError
+}
+
+func (h *MockHook) PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.PostRefreshCalled = true
+	h.PostRefreshAddr = addr
+	h.PostRefreshPriorState = priorState
+	h.PostRefreshNewState = newState
+	return h.PostRefreshReturn, h.PostRefreshError
+}
+
+func (h *MockHook) PreImportState(addr addrs.AbsResourceInstance, importID string) (HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.PreImportStateCalled = true
+	h.PreImportStateAddr = addr
+	h.PreImportStateID = importID
+	return h.PreImportStateReturn, h.PreImportStateError
+}
+
+func (h *MockHook) PostImportState(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.PostImportStateCalled = true
+	h.PostImportStateAddr = addr
+	h.PostImportStateNewStates = imported
+	return h.PostImportStateReturn, h.PostImportStateError
+}
+
+func (h *MockHook) PrePlanImport(addr addrs.AbsResourceInstance, importID string) (HookAction, error) {
+	h.PrePlanImportCalled = true
+	h.PrePlanImportAddr = addr
+	return h.PrePlanImportReturn, h.PrePlanImportError
+}
+
+func (h *MockHook) PostPlanImport(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error) {
+	h.PostPlanImportCalled = true
+	h.PostPlanImportAddr = addr
+	return h.PostPlanImportReturn, h.PostPlanImportError
+}
+
+func (h *MockHook) PreApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (HookAction, error) {
+	h.PreApplyImportCalled = true
+	h.PreApplyImportAddr = addr
+	return h.PreApplyImportReturn, h.PreApplyImportError
+}
+
+func (h *MockHook) PostApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.PostApplyImportCalled = true
+	h.PostApplyImportAddr = addr
+	return h.PostApplyImportReturn, h.PostApplyImportError
+}
+
+func (h *MockHook) Stopping() {
+	h.Lock()
+	defer h.Unlock()
+
+	h.StoppingCalled = true
+}
+
+func (h *MockHook) PostStateUpdate(new *states.State) (HookAction, error) {
+	h.Lock()
+	defer h.Unlock()
+
+	h.PostStateUpdateCalled = true
+	h.PostStateUpdateState = new
+	return h.PostStateUpdateReturn, h.PostStateUpdateError
+}
diff --git a/v1.5.7/internal/terraform/hook_stop.go b/v1.5.7/internal/terraform/hook_stop.go
new file mode 100644
index 0000000..52ead5a
--- /dev/null
+++ b/v1.5.7/internal/terraform/hook_stop.go
@@ -0,0 +1,118 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"errors"
+	"sync/atomic"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// stopHook is a private Hook implementation that Terraform uses to
+// signal when to stop or cancel actions.
+type stopHook struct {
+	stop uint32
+}
+
+var _ Hook = (*stopHook)(nil)
+
+func (h *stopHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) PreProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) PostProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) PostProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string, err error) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, line string) {
+}
+
+func (h *stopHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) PreImportState(addr addrs.AbsResourceInstance, importID string) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) PostImportState(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) PrePlanImport(addr addrs.AbsResourceInstance, importID string) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) PostPlanImport(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) PreApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) PostApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) Stopping() {}
+
+func (h *stopHook) PostStateUpdate(new *states.State) (HookAction, error) {
+	return h.hook()
+}
+
+func (h *stopHook) hook() (HookAction, error) {
+	if h.Stopped() {
+		return HookActionHalt, errors.New("execution halted")
+	}
+
+	return HookActionContinue, nil
+}
+
+// reset should be called within the lock context
+func (h *stopHook) Reset() {
+	atomic.StoreUint32(&h.stop, 0)
+}
+
+func (h *stopHook) Stop() {
+	atomic.StoreUint32(&h.stop, 1)
+}
+
+func (h *stopHook) Stopped() bool {
+	return atomic.LoadUint32(&h.stop) == 1
+}
diff --git a/v1.5.7/internal/terraform/hook_stop_test.go b/v1.5.7/internal/terraform/hook_stop_test.go
new file mode 100644
index 0000000..6dd8b63
--- /dev/null
+++ b/v1.5.7/internal/terraform/hook_stop_test.go
@@ -0,0 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+)
+
+func TestStopHook_impl(t *testing.T) {
+	var _ Hook = new(stopHook)
+}
diff --git a/v1.5.7/internal/terraform/hook_test.go b/v1.5.7/internal/terraform/hook_test.go
new file mode 100644
index 0000000..e0c8455
--- /dev/null
+++ b/v1.5.7/internal/terraform/hook_test.go
@@ -0,0 +1,169 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"sync"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestNilHook_impl(t *testing.T) {
+	var _ Hook = new(NilHook)
+}
+
+// testHook is a Hook implementation that logs the calls it receives.
+// It is intended for testing that core code is emitting the correct hooks
+// for a given situation.
+type testHook struct {
+	mu    sync.Mutex
+	Calls []*testHookCall
+}
+
+var _ Hook = (*testHook)(nil)
+
+// testHookCall represents a single call in testHook.
+// This hook just logs string names to make it easy to write "want" expressions
+// in tests that can DeepEqual against the real calls.
+type testHookCall struct {
+	Action     string
+	InstanceID string
+}
+
+func (h *testHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PreApply", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PostApply", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PreDiff", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PostDiff", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) PreProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PreProvisionInstance", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) PostProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PostProvisionInstance", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PreProvisionInstanceStep", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) PostProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string, err error) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PostProvisionInstanceStep", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, line string) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"ProvisionOutput", addr.String()})
+}
+
+func (h *testHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PreRefresh", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PostRefresh", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) PreImportState(addr addrs.AbsResourceInstance, importID string) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PreImportState", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) PostImportState(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PostImportState", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) PrePlanImport(addr addrs.AbsResourceInstance, importID string) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PrePlanImport", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) PostPlanImport(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PostPlanImport", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) PreApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PreApplyImport", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) PostApplyImport(addr addrs.AbsResourceInstance, importing plans.ImportingSrc) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PostApplyImport", addr.String()})
+	return HookActionContinue, nil
+}
+
+func (h *testHook) Stopping() {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"Stopping", ""})
+}
+
+func (h *testHook) PostStateUpdate(new *states.State) (HookAction, error) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+	h.Calls = append(h.Calls, &testHookCall{"PostStateUpdate", ""})
+	return HookActionContinue, nil
+}
diff --git a/v1.5.7/internal/terraform/instance_expanders.go b/v1.5.7/internal/terraform/instance_expanders.go
new file mode 100644
index 0000000..566f09f
--- /dev/null
+++ b/v1.5.7/internal/terraform/instance_expanders.go
@@ -0,0 +1,10 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+// graphNodeExpandsInstances is implemented by nodes that causes instances to
+// be registered in the instances.Expander.
+type graphNodeExpandsInstances interface {
+	expandsInstances()
+}
diff --git a/v1.5.7/internal/terraform/marks.go b/v1.5.7/internal/terraform/marks.go
new file mode 100644
index 0000000..d753232
--- /dev/null
+++ b/v1.5.7/internal/terraform/marks.go
@@ -0,0 +1,58 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"sort"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+// filterMarks removes any PathValueMarks from marks which cannot be applied to
+// the given value. When comparing existing marks to those from a map or other
+// dynamic value, we may not have values at the same paths and need to strip
+// out irrelevant marks.
+func filterMarks(val cty.Value, marks []cty.PathValueMarks) []cty.PathValueMarks {
+	var res []cty.PathValueMarks
+	for _, mark := range marks {
+		// any error here just means the path cannot apply to this value, so we
+		// don't need this mark for comparison.
+		if _, err := mark.Path.Apply(val); err == nil {
+			res = append(res, mark)
+		}
+	}
+	return res
+}
+
+// marksEqual compares 2 unordered sets of PathValue marks for equality, with
+// the comparison using the cty.PathValueMarks.Equal method.
+func marksEqual(a, b []cty.PathValueMarks) bool {
+	if len(a) == 0 && len(b) == 0 {
+		return true
+	}
+
+	if len(a) != len(b) {
+		return false
+	}
+
+	less := func(s []cty.PathValueMarks) func(i, j int) bool {
+		return func(i, j int) bool {
+			// the sort only needs to be consistent, so use the GoString format
+			// to get a comparable value
+			return fmt.Sprintf("%#v", s[i]) < fmt.Sprintf("%#v", s[j])
+		}
+	}
+
+	sort.Slice(a, less(a))
+	sort.Slice(b, less(b))
+
+	for i := 0; i < len(a); i++ {
+		if !a[i].Equal(b[i]) {
+			return false
+		}
+	}
+
+	return true
+}
diff --git a/v1.5.7/internal/terraform/marks_test.go b/v1.5.7/internal/terraform/marks_test.go
new file mode 100644
index 0000000..c0b0eab
--- /dev/null
+++ b/v1.5.7/internal/terraform/marks_test.go
@@ -0,0 +1,108 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestMarksEqual(t *testing.T) {
+	for i, tc := range []struct {
+		a, b  []cty.PathValueMarks
+		equal bool
+	}{
+		{
+			[]cty.PathValueMarks{
+				cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+			},
+			[]cty.PathValueMarks{
+				cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+			},
+			true,
+		},
+		{
+			[]cty.PathValueMarks{
+				cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+			},
+			[]cty.PathValueMarks{
+				cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "A"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+			},
+			false,
+		},
+		{
+			[]cty.PathValueMarks{
+				cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+				cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "b"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+				cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "c"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+			},
+			[]cty.PathValueMarks{
+				cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "b"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+				cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "c"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+				cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+			},
+			true,
+		},
+		{
+			[]cty.PathValueMarks{
+				cty.PathValueMarks{
+					Path:  cty.Path{cty.GetAttrStep{Name: "a"}, cty.GetAttrStep{Name: "b"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				cty.PathValueMarks{
+					Path:  cty.Path{cty.GetAttrStep{Name: "a"}, cty.GetAttrStep{Name: "c"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			[]cty.PathValueMarks{
+				cty.PathValueMarks{
+					Path:  cty.Path{cty.GetAttrStep{Name: "a"}, cty.GetAttrStep{Name: "c"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+				cty.PathValueMarks{
+					Path:  cty.Path{cty.GetAttrStep{Name: "a"}, cty.GetAttrStep{Name: "b"}},
+					Marks: cty.NewValueMarks(marks.Sensitive),
+				},
+			},
+			true,
+		},
+		{
+			[]cty.PathValueMarks{
+				cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+			},
+			[]cty.PathValueMarks{
+				cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "b"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+			},
+			false,
+		},
+		{
+			nil,
+			nil,
+			true,
+		},
+		{
+			[]cty.PathValueMarks{
+				cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+			},
+			nil,
+			false,
+		},
+		{
+			nil,
+			[]cty.PathValueMarks{
+				cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
+			},
+			false,
+		},
+	} {
+		t.Run(fmt.Sprint(i), func(t *testing.T) {
+			if marksEqual(tc.a, tc.b) != tc.equal {
+				t.Fatalf("marksEqual(\n%#v,\n%#v,\n) != %t\n", tc.a, tc.b, tc.equal)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/terraform/node_check.go b/v1.5.7/internal/terraform/node_check.go
new file mode 100644
index 0000000..87593be
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_check.go
@@ -0,0 +1,204 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+var (
+	_ GraphNodeModulePath = (*nodeReportCheck)(nil)
+	_ GraphNodeExecutable = (*nodeReportCheck)(nil)
+)
+
+// nodeReportCheck calls the ReportCheckableObjects function for our assertions
+// within the check blocks.
+//
+// We need this to happen before the checks are actually verified and before any
+// nested data blocks, so the creator of this structure should make sure this
+// node is a parent of any nested data blocks.
+//
+// This needs to be separate to nodeExpandCheck, because the actual checks
+// should happen after referenced data blocks rather than before.
+type nodeReportCheck struct {
+	addr addrs.ConfigCheck
+}
+
+func (n *nodeReportCheck) ModulePath() addrs.Module {
+	return n.addr.Module
+}
+
+func (n *nodeReportCheck) Execute(ctx EvalContext, _ walkOperation) tfdiags.Diagnostics {
+	exp := ctx.InstanceExpander()
+	modInsts := exp.ExpandModule(n.ModulePath())
+
+	instAddrs := addrs.MakeSet[addrs.Checkable]()
+	for _, modAddr := range modInsts {
+		instAddrs.Add(n.addr.Check.Absolute(modAddr))
+	}
+	ctx.Checks().ReportCheckableObjects(n.addr, instAddrs)
+	return nil
+}
+
+func (n *nodeReportCheck) Name() string {
+	return n.addr.String() + " (report)"
+}
+
+var (
+	_ GraphNodeModulePath        = (*nodeExpandCheck)(nil)
+	_ GraphNodeDynamicExpandable = (*nodeExpandCheck)(nil)
+	_ GraphNodeReferencer        = (*nodeExpandCheck)(nil)
+)
+
+// nodeExpandCheck creates child nodes that actually execute the assertions for
+// a given check block.
+//
+// This must happen after any other nodes/resources/data sources that are
+// referenced, so we implement GraphNodeReferencer.
+//
+// This needs to be separate to nodeReportCheck as nodeReportCheck must happen
+// first, while nodeExpandCheck must execute after any referenced blocks.
+type nodeExpandCheck struct {
+	addr   addrs.ConfigCheck
+	config *configs.Check
+
+	makeInstance func(addrs.AbsCheck, *configs.Check) dag.Vertex
+}
+
+func (n *nodeExpandCheck) ModulePath() addrs.Module {
+	return n.addr.Module
+}
+
+func (n *nodeExpandCheck) DynamicExpand(ctx EvalContext) (*Graph, error) {
+	exp := ctx.InstanceExpander()
+	modInsts := exp.ExpandModule(n.ModulePath())
+
+	var g Graph
+	for _, modAddr := range modInsts {
+		testAddr := n.addr.Check.Absolute(modAddr)
+		log.Printf("[TRACE] nodeExpandCheck: Node for %s", testAddr)
+		g.Add(n.makeInstance(testAddr, n.config))
+	}
+	addRootNodeToGraph(&g)
+
+	return &g, nil
+}
+
+func (n *nodeExpandCheck) References() []*addrs.Reference {
+	var refs []*addrs.Reference
+	for _, assert := range n.config.Asserts {
+		// Check blocks reference anything referenced by conditions or messages
+		// in their check rules.
+		condition, _ := lang.ReferencesInExpr(assert.Condition)
+		message, _ := lang.ReferencesInExpr(assert.ErrorMessage)
+		refs = append(refs, condition...)
+		refs = append(refs, message...)
+	}
+	if n.config.DataResource != nil {
+		// We'll also always reference our nested data block if it exists, as
+		// there is nothing enforcing that it has to also be referenced by our
+		// conditions or messages.
+		//
+		// We don't need to make this addr absolute, because the check block and
+		// the data resource are always within the same module/instance.
+		traversal, _ := hclsyntax.ParseTraversalAbs(
+			[]byte(n.config.DataResource.Addr().String()),
+			n.config.DataResource.DeclRange.Filename,
+			n.config.DataResource.DeclRange.Start)
+		ref, _ := addrs.ParseRef(traversal)
+		refs = append(refs, ref)
+	}
+	return refs
+}
+
+func (n *nodeExpandCheck) Name() string {
+	return n.addr.String() + " (expand)"
+}
+
+var (
+	_ GraphNodeModuleInstance = (*nodeCheckAssert)(nil)
+	_ GraphNodeExecutable     = (*nodeCheckAssert)(nil)
+)
+
+type nodeCheckAssert struct {
+	addr   addrs.AbsCheck
+	config *configs.Check
+
+	// We only want to actually execute the checks during the plan and apply
+	// operations, but we still want to validate our config during
+	// other operations.
+	executeChecks bool
+}
+
+func (n *nodeCheckAssert) ModulePath() addrs.Module {
+	return n.Path().Module()
+}
+
+func (n *nodeCheckAssert) Path() addrs.ModuleInstance {
+	return n.addr.Module
+}
+
+func (n *nodeCheckAssert) Execute(ctx EvalContext, _ walkOperation) tfdiags.Diagnostics {
+
+	// We only want to actually execute the checks during specific
+	// operations, such as plan and applies.
+	if n.executeChecks {
+		if status := ctx.Checks().ObjectCheckStatus(n.addr); status == checks.StatusFail || status == checks.StatusError {
+			// This check is already failing, so we won't try and evaluate it.
+			// This typically means there was an error in a data block within
+			// the check block.
+			return nil
+		}
+
+		return evalCheckRules(
+			addrs.CheckAssertion,
+			n.config.Asserts,
+			ctx,
+			n.addr,
+			EvalDataForNoInstanceKey,
+			tfdiags.Warning)
+
+	}
+
+	// Otherwise let's still validate the config and references and return
+	// diagnostics if references do not exist etc.
+	var diags tfdiags.Diagnostics
+	for _, assert := range n.config.Asserts {
+		_, _, moreDiags := validateCheckRule(addrs.CheckAssertion, assert, ctx, n.addr, EvalDataForNoInstanceKey)
+		diags = diags.Append(moreDiags)
+	}
+	return diags
+}
+
+func (n *nodeCheckAssert) Name() string {
+	return n.addr.String() + " (assertions)"
+}
+
+var (
+	_ GraphNodeExecutable = (*nodeCheckStart)(nil)
+)
+
+// We need to ensure that any nested data sources execute after all other
+// resource changes have been applied. This node acts as a single point of
+// dependency that can enforce this ordering.
+type nodeCheckStart struct{}
+
+func (n *nodeCheckStart) Execute(context EvalContext, operation walkOperation) tfdiags.Diagnostics {
+	// This node doesn't actually do anything, except simplify the underlying
+	// graph structure.
+	return nil
+}
+
+func (n *nodeCheckStart) Name() string {
+	return "(execute checks)"
+}
diff --git a/v1.5.7/internal/terraform/node_data_destroy.go b/v1.5.7/internal/terraform/node_data_destroy.go
new file mode 100644
index 0000000..c0074e0
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_data_destroy.go
@@ -0,0 +1,27 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// NodeDestroyableDataResourceInstance represents a resource that is "destroyable":
+// it is ready to be destroyed.
+type NodeDestroyableDataResourceInstance struct {
+	*NodeAbstractResourceInstance
+}
+
+var (
+	_ GraphNodeExecutable = (*NodeDestroyableDataResourceInstance)(nil)
+)
+
+// GraphNodeExecutable
+func (n *NodeDestroyableDataResourceInstance) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
+	log.Printf("[TRACE] NodeDestroyableDataResourceInstance: removing state object for %s", n.Addr)
+	ctx.State().SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider)
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/node_data_destroy_test.go b/v1.5.7/internal/terraform/node_data_destroy_test.go
new file mode 100644
index 0000000..0781519
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_data_destroy_test.go
@@ -0,0 +1,51 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestNodeDataDestroyExecute(t *testing.T) {
+	state := states.NewState()
+	state.Module(addrs.RootModuleInstance).SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.DataResourceMode,
+			Type: "test_instance",
+			Name: "foo",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"dynamic":{"type":"string","value":"hello"}}`),
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	ctx := &MockEvalContext{
+		StateState: state.SyncWrapper(),
+	}
+
+	node := NodeDestroyableDataResourceInstance{&NodeAbstractResourceInstance{
+		Addr: addrs.Resource{
+			Mode: addrs.DataResourceMode,
+			Type: "test_instance",
+			Name: "foo",
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+	}}
+
+	diags := node.Execute(ctx, walkApply)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %v", diags.Err())
+	}
+
+	// verify resource removed from state
+	if state.HasManagedResourceInstanceObjects() {
+		t.Fatal("resources still in state after NodeDataDestroy.Execute")
+	}
+}
diff --git a/v1.5.7/internal/terraform/node_local.go b/v1.5.7/internal/terraform/node_local.go
new file mode 100644
index 0000000..4771456
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_local.go
@@ -0,0 +1,183 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// nodeExpandLocal represents a named local value in a configuration module,
+// which has not yet been expanded.
+type nodeExpandLocal struct {
+	Addr   addrs.LocalValue
+	Module addrs.Module
+	Config *configs.Local
+}
+
+var (
+	_ GraphNodeReferenceable     = (*nodeExpandLocal)(nil)
+	_ GraphNodeReferencer        = (*nodeExpandLocal)(nil)
+	_ GraphNodeDynamicExpandable = (*nodeExpandLocal)(nil)
+	_ graphNodeTemporaryValue    = (*nodeExpandLocal)(nil)
+	_ graphNodeExpandsInstances  = (*nodeExpandLocal)(nil)
+)
+
+func (n *nodeExpandLocal) expandsInstances() {}
+
+// graphNodeTemporaryValue
+func (n *nodeExpandLocal) temporaryValue() bool {
+	return true
+}
+
+func (n *nodeExpandLocal) Name() string {
+	path := n.Module.String()
+	addr := n.Addr.String() + " (expand)"
+
+	if path != "" {
+		return path + "." + addr
+	}
+	return addr
+}
+
+// GraphNodeModulePath
+func (n *nodeExpandLocal) ModulePath() addrs.Module {
+	return n.Module
+}
+
+// GraphNodeReferenceable
+func (n *nodeExpandLocal) ReferenceableAddrs() []addrs.Referenceable {
+	return []addrs.Referenceable{n.Addr}
+}
+
+// GraphNodeReferencer
+func (n *nodeExpandLocal) References() []*addrs.Reference {
+	refs, _ := lang.ReferencesInExpr(n.Config.Expr)
+	return refs
+}
+
+func (n *nodeExpandLocal) DynamicExpand(ctx EvalContext) (*Graph, error) {
+	var g Graph
+	expander := ctx.InstanceExpander()
+	for _, module := range expander.ExpandModule(n.Module) {
+		o := &NodeLocal{
+			Addr:   n.Addr.Absolute(module),
+			Config: n.Config,
+		}
+		log.Printf("[TRACE] Expanding local: adding %s as %T", o.Addr.String(), o)
+		g.Add(o)
+	}
+	addRootNodeToGraph(&g)
+	return &g, nil
+}
+
+// NodeLocal represents a named local value in a particular module.
+//
+// Local value nodes only have one operation, common to all walk types:
+// evaluate the result and place it in state.
+type NodeLocal struct {
+	Addr   addrs.AbsLocalValue
+	Config *configs.Local
+}
+
+var (
+	_ GraphNodeModuleInstance = (*NodeLocal)(nil)
+	_ GraphNodeReferenceable  = (*NodeLocal)(nil)
+	_ GraphNodeReferencer     = (*NodeLocal)(nil)
+	_ GraphNodeExecutable     = (*NodeLocal)(nil)
+	_ graphNodeTemporaryValue = (*NodeLocal)(nil)
+	_ dag.GraphNodeDotter     = (*NodeLocal)(nil)
+)
+
+// graphNodeTemporaryValue
+func (n *NodeLocal) temporaryValue() bool {
+	return true
+}
+
+func (n *NodeLocal) Name() string {
+	return n.Addr.String()
+}
+
+// GraphNodeModuleInstance
+func (n *NodeLocal) Path() addrs.ModuleInstance {
+	return n.Addr.Module
+}
+
+// GraphNodeModulePath
+func (n *NodeLocal) ModulePath() addrs.Module {
+	return n.Addr.Module.Module()
+}
+
+// GraphNodeReferenceable
+func (n *NodeLocal) ReferenceableAddrs() []addrs.Referenceable {
+	return []addrs.Referenceable{n.Addr.LocalValue}
+}
+
+// GraphNodeReferencer
+func (n *NodeLocal) References() []*addrs.Reference {
+	refs, _ := lang.ReferencesInExpr(n.Config.Expr)
+	return refs
+}
+
+// GraphNodeExecutable
+// NodeLocal.Execute is an Execute implementation that evaluates the
+// expression for a local value and writes it into a transient part of
+// the state.
+func (n *NodeLocal) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	expr := n.Config.Expr
+	addr := n.Addr.LocalValue
+
+	// We ignore diags here because any problems we might find will be found
+	// again in EvaluateExpr below.
+	refs, _ := lang.ReferencesInExpr(expr)
+	for _, ref := range refs {
+		if ref.Subject == addr {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Self-referencing local value",
+				Detail:   fmt.Sprintf("Local value %s cannot use its own result as part of its expression.", addr),
+				Subject:  ref.SourceRange.ToHCL().Ptr(),
+				Context:  expr.Range().Ptr(),
+			})
+		}
+	}
+	if diags.HasErrors() {
+		return diags
+	}
+
+	val, moreDiags := ctx.EvaluateExpr(expr, cty.DynamicPseudoType, nil)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		return diags
+	}
+
+	state := ctx.State()
+	if state == nil {
+		diags = diags.Append(fmt.Errorf("cannot write local value to nil state"))
+		return diags
+	}
+
+	state.SetLocalValue(addr.Absolute(ctx.Path()), val)
+
+	return diags
+}
+
+// dag.GraphNodeDotter impl.
+func (n *NodeLocal) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
+	return &dag.DotNode{
+		Name: name,
+		Attrs: map[string]string{
+			"label": n.Name(),
+			"shape": "note",
+		},
+	}
+}
diff --git a/v1.5.7/internal/terraform/node_local_test.go b/v1.5.7/internal/terraform/node_local_test.go
new file mode 100644
index 0000000..5a38b09
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_local_test.go
@@ -0,0 +1,88 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestNodeLocalExecute(t *testing.T) {
+	tests := []struct {
+		Value string
+		Want  interface{}
+		Err   bool
+	}{
+		{
+			"hello!",
+			"hello!",
+			false,
+		},
+		{
+			"",
+			"",
+			false,
+		},
+		{
+			"Hello, ${local.foo}",
+			nil,
+			true, // self-referencing
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Value, func(t *testing.T) {
+			expr, diags := hclsyntax.ParseTemplate([]byte(test.Value), "", hcl.Pos{Line: 1, Column: 1})
+			if diags.HasErrors() {
+				t.Fatal(diags.Error())
+			}
+
+			n := &NodeLocal{
+				Addr: addrs.LocalValue{Name: "foo"}.Absolute(addrs.RootModuleInstance),
+				Config: &configs.Local{
+					Expr: expr,
+				},
+			}
+			ctx := &MockEvalContext{
+				StateState: states.NewState().SyncWrapper(),
+
+				EvaluateExprResult: hcl2shim.HCL2ValueFromConfigValue(test.Want),
+			}
+
+			err := n.Execute(ctx, walkApply)
+			if (err != nil) != test.Err {
+				if err != nil {
+					t.Errorf("unexpected error: %s", err)
+				} else {
+					t.Errorf("successful Eval; want error")
+				}
+			}
+
+			ms := ctx.StateState.Module(addrs.RootModuleInstance)
+			gotLocals := ms.LocalValues
+			wantLocals := map[string]cty.Value{}
+			if test.Want != nil {
+				wantLocals["foo"] = hcl2shim.HCL2ValueFromConfigValue(test.Want)
+			}
+
+			if !reflect.DeepEqual(gotLocals, wantLocals) {
+				t.Errorf(
+					"wrong locals after Eval\ngot:  %swant: %s",
+					spew.Sdump(gotLocals), spew.Sdump(wantLocals),
+				)
+			}
+		})
+	}
+
+}
diff --git a/v1.5.7/internal/terraform/node_module_expand.go b/v1.5.7/internal/terraform/node_module_expand.go
new file mode 100644
index 0000000..99e2823
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_module_expand.go
@@ -0,0 +1,255 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+type ConcreteModuleNodeFunc func(n *nodeExpandModule) dag.Vertex
+
+// nodeExpandModule represents a module call in the configuration that
+// might expand into multiple module instances depending on how it is
+// configured.
+type nodeExpandModule struct {
+	Addr       addrs.Module
+	Config     *configs.Module
+	ModuleCall *configs.ModuleCall
+}
+
+var (
+	_ GraphNodeExecutable       = (*nodeExpandModule)(nil)
+	_ GraphNodeReferencer       = (*nodeExpandModule)(nil)
+	_ GraphNodeReferenceOutside = (*nodeExpandModule)(nil)
+	_ graphNodeExpandsInstances = (*nodeExpandModule)(nil)
+)
+
+func (n *nodeExpandModule) expandsInstances() {}
+
+func (n *nodeExpandModule) Name() string {
+	return n.Addr.String() + " (expand)"
+}
+
+// GraphNodeModulePath implementation
+func (n *nodeExpandModule) ModulePath() addrs.Module {
+	return n.Addr
+}
+
+// GraphNodeReferencer implementation
+func (n *nodeExpandModule) References() []*addrs.Reference {
+	var refs []*addrs.Reference
+
+	if n.ModuleCall == nil {
+		return nil
+	}
+
+	refs = append(refs, n.DependsOn()...)
+
+	// Expansion only uses the count and for_each expressions, so this
+	// particular graph node only refers to those.
+	// Individual variable values in the module call definition might also
+	// refer to other objects, but that's handled by
+	// NodeApplyableModuleVariable.
+	//
+	// Because our Path method returns the module instance that contains
+	// our call, these references will be correctly interpreted as being
+	// in the calling module's namespace, not the namespaces of any of the
+	// child module instances we might expand to during our evaluation.
+
+	if n.ModuleCall.Count != nil {
+		countRefs, _ := lang.ReferencesInExpr(n.ModuleCall.Count)
+		refs = append(refs, countRefs...)
+	}
+	if n.ModuleCall.ForEach != nil {
+		forEachRefs, _ := lang.ReferencesInExpr(n.ModuleCall.ForEach)
+		refs = append(refs, forEachRefs...)
+	}
+	return refs
+}
+
+func (n *nodeExpandModule) DependsOn() []*addrs.Reference {
+	if n.ModuleCall == nil {
+		return nil
+	}
+
+	var refs []*addrs.Reference
+	for _, traversal := range n.ModuleCall.DependsOn {
+		ref, diags := addrs.ParseRef(traversal)
+		if diags.HasErrors() {
+			// We ignore this here, because this isn't a suitable place to return
+			// errors. This situation should be caught and rejected during
+			// validation.
+			log.Printf("[ERROR] Can't parse %#v from depends_on as reference: %s", traversal, diags.Err())
+			continue
+		}
+
+		refs = append(refs, ref)
+	}
+
+	return refs
+}
+
+// GraphNodeReferenceOutside
+func (n *nodeExpandModule) ReferenceOutside() (selfPath, referencePath addrs.Module) {
+	return n.Addr, n.Addr.Parent()
+}
+
+// GraphNodeExecutable
+func (n *nodeExpandModule) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	expander := ctx.InstanceExpander()
+	_, call := n.Addr.Call()
+
+	// nodeExpandModule itself does not have visibility into how its ancestors
+	// were expanded, so we use the expander here to provide all possible paths
+	// to our module, and register module instances with each of them.
+	for _, module := range expander.ExpandModule(n.Addr.Parent()) {
+		ctx = ctx.WithPath(module)
+		switch {
+		case n.ModuleCall.Count != nil:
+			count, ctDiags := evaluateCountExpression(n.ModuleCall.Count, ctx)
+			diags = diags.Append(ctDiags)
+			if diags.HasErrors() {
+				return diags
+			}
+			expander.SetModuleCount(module, call, count)
+
+		case n.ModuleCall.ForEach != nil:
+			forEach, feDiags := evaluateForEachExpression(n.ModuleCall.ForEach, ctx)
+			diags = diags.Append(feDiags)
+			if diags.HasErrors() {
+				return diags
+			}
+			expander.SetModuleForEach(module, call, forEach)
+
+		default:
+			expander.SetModuleSingle(module, call)
+		}
+	}
+
+	return diags
+
+}
+
+// nodeCloseModule represents an expanded module during apply, and is visited
+// after all other module instance nodes. This node will depend on all module
+// instance resource and outputs, and anything depending on the module should
+// wait on this node.
+// Besides providing a root node for dependency ordering, nodeCloseModule also
+// cleans up state after all the module nodes have been evaluated, removing
+// empty resources and modules from the state.
+// The root module instance also closes any remaining provisioner plugins which
+// do not have a lifecycle controlled by individual graph nodes.
+type nodeCloseModule struct {
+	Addr addrs.Module
+}
+
+var (
+	_ GraphNodeReferenceable    = (*nodeCloseModule)(nil)
+	_ GraphNodeReferenceOutside = (*nodeCloseModule)(nil)
+	_ GraphNodeExecutable       = (*nodeCloseModule)(nil)
+)
+
+func (n *nodeCloseModule) ModulePath() addrs.Module {
+	return n.Addr
+}
+
+func (n *nodeCloseModule) ReferenceOutside() (selfPath, referencePath addrs.Module) {
+	return n.Addr.Parent(), n.Addr
+}
+
+func (n *nodeCloseModule) ReferenceableAddrs() []addrs.Referenceable {
+	_, call := n.Addr.Call()
+	return []addrs.Referenceable{
+		call,
+	}
+}
+
+func (n *nodeCloseModule) Name() string {
+	if len(n.Addr) == 0 {
+		return "root"
+	}
+	return n.Addr.String() + " (close)"
+}
+
+func (n *nodeCloseModule) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	if !n.Addr.IsRoot() {
+		return
+	}
+
+	// If this is the root module, we are cleaning up the walk, so close
+	// any running provisioners
+	diags = diags.Append(ctx.CloseProvisioners())
+
+	switch op {
+	case walkApply, walkDestroy:
+		state := ctx.State().Lock()
+		defer ctx.State().Unlock()
+
+		for modKey, mod := range state.Modules {
+			// clean out any empty resources
+			for resKey, res := range mod.Resources {
+				if len(res.Instances) == 0 {
+					delete(mod.Resources, resKey)
+				}
+			}
+
+			// empty child modules are always removed
+			if len(mod.Resources) == 0 && !mod.Addr.IsRoot() {
+				delete(state.Modules, modKey)
+			}
+		}
+		return nil
+	default:
+		return nil
+	}
+}
+
+// nodeValidateModule wraps a nodeExpand module for validation, ensuring that
+// no expansion is attempted during evaluation, when count and for_each
+// expressions may not be known.
+type nodeValidateModule struct {
+	nodeExpandModule
+}
+
+var _ GraphNodeExecutable = (*nodeValidateModule)(nil)
+
+// GraphNodeEvalable
+func (n *nodeValidateModule) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	_, call := n.Addr.Call()
+	expander := ctx.InstanceExpander()
+
+	// Modules all evaluate to single instances during validation, only to
+	// create a proper context within which to evaluate. All parent modules
+	// will be a single instance, but still get our address in the expected
+	// manner anyway to ensure they've been registered correctly.
+	for _, module := range expander.ExpandModule(n.Addr.Parent()) {
+		ctx = ctx.WithPath(module)
+
+		// Validate our for_each and count expressions at a basic level
+		// We skip validation on known, because there will be unknown values before
+		// a full expansion, presuming these errors will be caught in later steps
+		switch {
+		case n.ModuleCall.Count != nil:
+			_, countDiags := evaluateCountExpressionValue(n.ModuleCall.Count, ctx)
+			diags = diags.Append(countDiags)
+
+		case n.ModuleCall.ForEach != nil:
+			_, forEachDiags := evaluateForEachExpressionValue(n.ModuleCall.ForEach, ctx, true)
+			diags = diags.Append(forEachDiags)
+		}
+
+		diags = diags.Append(validateDependsOn(ctx, n.ModuleCall.DependsOn))
+
+		// now set our own mode to single
+		expander.SetModuleSingle(module, call)
+	}
+
+	return diags
+}
diff --git a/v1.5.7/internal/terraform/node_module_expand_test.go b/v1.5.7/internal/terraform/node_module_expand_test.go
new file mode 100644
index 0000000..1a85048
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_module_expand_test.go
@@ -0,0 +1,131 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/hashicorp/hcl/v2/hcltest"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestNodeExpandModuleExecute(t *testing.T) {
+	ctx := &MockEvalContext{
+		InstanceExpanderExpander: instances.NewExpander(),
+	}
+	ctx.installSimpleEval()
+
+	node := nodeExpandModule{
+		Addr: addrs.Module{"child"},
+		ModuleCall: &configs.ModuleCall{
+			Count: hcltest.MockExprLiteral(cty.NumberIntVal(2)),
+		},
+	}
+
+	err := node.Execute(ctx, walkApply)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	if !ctx.InstanceExpanderCalled {
+		t.Fatal("did not expand")
+	}
+}
+
+func TestNodeCloseModuleExecute(t *testing.T) {
+	t.Run("walkApply", func(t *testing.T) {
+		state := states.NewState()
+		state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+		ctx := &MockEvalContext{
+			StateState: state.SyncWrapper(),
+		}
+		node := nodeCloseModule{addrs.Module{"child"}}
+		diags := node.Execute(ctx, walkApply)
+		if diags.HasErrors() {
+			t.Fatalf("unexpected error: %s", diags.Err())
+		}
+
+		// Since module.child has no resources, it should be removed
+		if _, ok := state.Modules["module.child"]; !ok {
+			t.Fatal("module.child should not be removed from state yet")
+		}
+
+		// the root module should do all the module cleanup
+		node = nodeCloseModule{addrs.RootModule}
+		diags = node.Execute(ctx, walkApply)
+		if diags.HasErrors() {
+			t.Fatalf("unexpected error: %s", diags.Err())
+		}
+
+		// Since module.child has no resources, it should be removed
+		if _, ok := state.Modules["module.child"]; ok {
+			t.Fatal("module.child was not removed from state")
+		}
+	})
+
+	// walkImport is a no-op
+	t.Run("walkImport", func(t *testing.T) {
+		state := states.NewState()
+		state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+		ctx := &MockEvalContext{
+			StateState: state.SyncWrapper(),
+		}
+		node := nodeCloseModule{addrs.Module{"child"}}
+
+		diags := node.Execute(ctx, walkImport)
+		if diags.HasErrors() {
+			t.Fatalf("unexpected error: %s", diags.Err())
+		}
+		if _, ok := state.Modules["module.child"]; !ok {
+			t.Fatal("module.child was removed from state, expected no-op")
+		}
+	})
+}
+
+func TestNodeValidateModuleExecute(t *testing.T) {
+	t.Run("success", func(t *testing.T) {
+		ctx := &MockEvalContext{
+			InstanceExpanderExpander: instances.NewExpander(),
+		}
+		ctx.installSimpleEval()
+		node := nodeValidateModule{
+			nodeExpandModule{
+				Addr: addrs.Module{"child"},
+				ModuleCall: &configs.ModuleCall{
+					Count: hcltest.MockExprLiteral(cty.NumberIntVal(2)),
+				},
+			},
+		}
+
+		diags := node.Execute(ctx, walkApply)
+		if diags.HasErrors() {
+			t.Fatalf("unexpected error: %v", diags.Err())
+		}
+	})
+
+	t.Run("invalid count", func(t *testing.T) {
+		ctx := &MockEvalContext{
+			InstanceExpanderExpander: instances.NewExpander(),
+		}
+		ctx.installSimpleEval()
+		node := nodeValidateModule{
+			nodeExpandModule{
+				Addr: addrs.Module{"child"},
+				ModuleCall: &configs.ModuleCall{
+					Count: hcltest.MockExprLiteral(cty.StringVal("invalid")),
+				},
+			},
+		}
+
+		err := node.Execute(ctx, walkApply)
+		if err == nil {
+			t.Fatal("expected error, got success")
+		}
+	})
+
+}
diff --git a/v1.5.7/internal/terraform/node_module_variable.go b/v1.5.7/internal/terraform/node_module_variable.go
new file mode 100644
index 0000000..9042d7b
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_module_variable.go
@@ -0,0 +1,247 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// nodeExpandModuleVariable is the placeholder for an variable that has not yet had
+// its module path expanded.
+type nodeExpandModuleVariable struct {
+	Addr   addrs.InputVariable
+	Module addrs.Module
+	Config *configs.Variable
+	Expr   hcl.Expression
+}
+
+var (
+	_ GraphNodeDynamicExpandable = (*nodeExpandModuleVariable)(nil)
+	_ GraphNodeReferenceOutside  = (*nodeExpandModuleVariable)(nil)
+	_ GraphNodeReferenceable     = (*nodeExpandModuleVariable)(nil)
+	_ GraphNodeReferencer        = (*nodeExpandModuleVariable)(nil)
+	_ graphNodeTemporaryValue    = (*nodeExpandModuleVariable)(nil)
+	_ graphNodeExpandsInstances  = (*nodeExpandModuleVariable)(nil)
+)
+
+func (n *nodeExpandModuleVariable) expandsInstances() {}
+
+func (n *nodeExpandModuleVariable) temporaryValue() bool {
+	return true
+}
+
+func (n *nodeExpandModuleVariable) DynamicExpand(ctx EvalContext) (*Graph, error) {
+	var g Graph
+	expander := ctx.InstanceExpander()
+	for _, module := range expander.ExpandModule(n.Module) {
+		o := &nodeModuleVariable{
+			Addr:           n.Addr.Absolute(module),
+			Config:         n.Config,
+			Expr:           n.Expr,
+			ModuleInstance: module,
+		}
+		g.Add(o)
+	}
+	addRootNodeToGraph(&g)
+	return &g, nil
+}
+
+func (n *nodeExpandModuleVariable) Name() string {
+	return fmt.Sprintf("%s.%s (expand)", n.Module, n.Addr.String())
+}
+
+// GraphNodeModulePath
+func (n *nodeExpandModuleVariable) ModulePath() addrs.Module {
+	return n.Module
+}
+
+// GraphNodeReferencer
+func (n *nodeExpandModuleVariable) References() []*addrs.Reference {
+
+	// If we have no value expression, we cannot depend on anything.
+	if n.Expr == nil {
+		return nil
+	}
+
+	// Variables in the root don't depend on anything, because their values
+	// are gathered prior to the graph walk and recorded in the context.
+	if len(n.Module) == 0 {
+		return nil
+	}
+
+	// Otherwise, we depend on anything referenced by our value expression.
+	// We ignore diagnostics here under the assumption that we'll re-eval
+	// all these things later and catch them then; for our purposes here,
+	// we only care about valid references.
+	//
+	// Due to our GraphNodeReferenceOutside implementation, the addresses
+	// returned by this function are interpreted in the _parent_ module from
+	// where our associated variable was declared, which is correct because
+	// our value expression is assigned within a "module" block in the parent
+	// module.
+	refs, _ := lang.ReferencesInExpr(n.Expr)
+	return refs
+}
+
+// GraphNodeReferenceOutside implementation
+func (n *nodeExpandModuleVariable) ReferenceOutside() (selfPath, referencePath addrs.Module) {
+	return n.Module, n.Module.Parent()
+}
+
+// GraphNodeReferenceable
+func (n *nodeExpandModuleVariable) ReferenceableAddrs() []addrs.Referenceable {
+	return []addrs.Referenceable{n.Addr}
+}
+
+// nodeModuleVariable represents a module variable input during
+// the apply step.
+type nodeModuleVariable struct {
+	Addr   addrs.AbsInputVariableInstance
+	Config *configs.Variable // Config is the var in the config
+	Expr   hcl.Expression    // Expr is the value expression given in the call
+	// ModuleInstance in order to create the appropriate context for evaluating
+	// ModuleCallArguments, ex. so count.index and each.key can resolve
+	ModuleInstance addrs.ModuleInstance
+}
+
+// Ensure that we are implementing all of the interfaces we think we are
+// implementing.
+var (
+	_ GraphNodeModuleInstance = (*nodeModuleVariable)(nil)
+	_ GraphNodeExecutable     = (*nodeModuleVariable)(nil)
+	_ graphNodeTemporaryValue = (*nodeModuleVariable)(nil)
+	_ dag.GraphNodeDotter     = (*nodeModuleVariable)(nil)
+)
+
+func (n *nodeModuleVariable) temporaryValue() bool {
+	return true
+}
+
+func (n *nodeModuleVariable) Name() string {
+	return n.Addr.String()
+}
+
+// GraphNodeModuleInstance
+func (n *nodeModuleVariable) Path() addrs.ModuleInstance {
+	// We execute in the parent scope (above our own module) because
+	// expressions in our value are resolved in that context.
+	return n.Addr.Module.Parent()
+}
+
+// GraphNodeModulePath
+func (n *nodeModuleVariable) ModulePath() addrs.Module {
+	return n.Addr.Module.Module()
+}
+
+// GraphNodeExecutable
+func (n *nodeModuleVariable) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	log.Printf("[TRACE] nodeModuleVariable: evaluating %s", n.Addr)
+
+	var val cty.Value
+	var err error
+
+	switch op {
+	case walkValidate:
+		val, err = n.evalModuleVariable(ctx, true)
+		diags = diags.Append(err)
+	default:
+		val, err = n.evalModuleVariable(ctx, false)
+		diags = diags.Append(err)
+	}
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// Set values for arguments of a child module call, for later retrieval
+	// during expression evaluation.
+	_, call := n.Addr.Module.CallInstance()
+	ctx.SetModuleCallArgument(call, n.Addr.Variable, val)
+
+	return evalVariableValidations(n.Addr, n.Config, n.Expr, ctx)
+}
+
+// dag.GraphNodeDotter impl.
+func (n *nodeModuleVariable) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
+	return &dag.DotNode{
+		Name: name,
+		Attrs: map[string]string{
+			"label": n.Name(),
+			"shape": "note",
+		},
+	}
+}
+
+// evalModuleVariable produces the value for a particular variable as will
+// be used by a child module instance.
+//
+// The result is written into a map, with its key set to the local name of the
+// variable, disregarding the module instance address. A map is returned instead
+// of a single value as a result of trying to be convenient for use with
+// EvalContext.SetModuleCallArguments, which expects a map to merge in with any
+// existing arguments.
+//
+// validateOnly indicates that this evaluation is only for config
+// validation, and we will not have any expansion module instance
+// repetition data.
+func (n *nodeModuleVariable) evalModuleVariable(ctx EvalContext, validateOnly bool) (cty.Value, error) {
+	var diags tfdiags.Diagnostics
+	var givenVal cty.Value
+	var errSourceRange tfdiags.SourceRange
+	if expr := n.Expr; expr != nil {
+		var moduleInstanceRepetitionData instances.RepetitionData
+
+		switch {
+		case validateOnly:
+			// the instance expander does not track unknown expansion values, so we
+			// have to assume all RepetitionData is unknown.
+			moduleInstanceRepetitionData = instances.RepetitionData{
+				CountIndex: cty.UnknownVal(cty.Number),
+				EachKey:    cty.UnknownVal(cty.String),
+				EachValue:  cty.DynamicVal,
+			}
+
+		default:
+			// Get the repetition data for this module instance,
+			// so we can create the appropriate scope for evaluating our expression
+			moduleInstanceRepetitionData = ctx.InstanceExpander().GetModuleInstanceRepetitionData(n.ModuleInstance)
+		}
+
+		scope := ctx.EvaluationScope(nil, nil, moduleInstanceRepetitionData)
+		val, moreDiags := scope.EvalExpr(expr, cty.DynamicPseudoType)
+		diags = diags.Append(moreDiags)
+		if moreDiags.HasErrors() {
+			return cty.DynamicVal, diags.ErrWithWarnings()
+		}
+		givenVal = val
+		errSourceRange = tfdiags.SourceRangeFromHCL(expr.Range())
+	} else {
+		// We'll use cty.NilVal to represent the variable not being set at all.
+		givenVal = cty.NilVal
+		errSourceRange = tfdiags.SourceRangeFromHCL(n.Config.DeclRange) // we use the declaration range as a fallback for an undefined variable
+	}
+
+	// We construct a synthetic InputValue here to pretend as if this were
+	// a root module variable set from outside, just as a convenience so we
+	// can reuse the InputValue type for this.
+	rawVal := &InputValue{
+		Value:       givenVal,
+		SourceType:  ValueFromConfig,
+		SourceRange: errSourceRange,
+	}
+
+	finalVal, moreDiags := prepareFinalInputVariableValue(n.Addr, rawVal, n.Config)
+	diags = diags.Append(moreDiags)
+
+	return finalVal, diags.ErrWithWarnings()
+}
diff --git a/v1.5.7/internal/terraform/node_module_variable_test.go b/v1.5.7/internal/terraform/node_module_variable_test.go
new file mode 100644
index 0000000..59e23a0
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_module_variable_test.go
@@ -0,0 +1,124 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/go-test/deep"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+)
+
+func TestNodeModuleVariablePath(t *testing.T) {
+	n := &nodeModuleVariable{
+		Addr: addrs.RootModuleInstance.InputVariable("foo"),
+		Config: &configs.Variable{
+			Name:           "foo",
+			Type:           cty.String,
+			ConstraintType: cty.String,
+		},
+	}
+
+	want := addrs.RootModuleInstance
+	got := n.Path()
+	if got.String() != want.String() {
+		t.Fatalf("wrong module address %s; want %s", got, want)
+	}
+}
+
+func TestNodeModuleVariableReferenceableName(t *testing.T) {
+	n := &nodeExpandModuleVariable{
+		Addr: addrs.InputVariable{Name: "foo"},
+		Config: &configs.Variable{
+			Name:           "foo",
+			Type:           cty.String,
+			ConstraintType: cty.String,
+		},
+	}
+
+	{
+		expected := []addrs.Referenceable{
+			addrs.InputVariable{Name: "foo"},
+		}
+		actual := n.ReferenceableAddrs()
+		if !reflect.DeepEqual(actual, expected) {
+			t.Fatalf("%#v != %#v", actual, expected)
+		}
+	}
+
+	{
+		gotSelfPath, gotReferencePath := n.ReferenceOutside()
+		wantSelfPath := addrs.RootModuleInstance
+		wantReferencePath := addrs.RootModuleInstance
+		if got, want := gotSelfPath.String(), wantSelfPath.String(); got != want {
+			t.Errorf("wrong self path\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := gotReferencePath.String(), wantReferencePath.String(); got != want {
+			t.Errorf("wrong reference path\ngot:  %s\nwant: %s", got, want)
+		}
+	}
+
+}
+
+func TestNodeModuleVariableReference(t *testing.T) {
+	n := &nodeExpandModuleVariable{
+		Addr:   addrs.InputVariable{Name: "foo"},
+		Module: addrs.RootModule.Child("bar"),
+		Config: &configs.Variable{
+			Name:           "foo",
+			Type:           cty.String,
+			ConstraintType: cty.String,
+		},
+		Expr: &hclsyntax.ScopeTraversalExpr{
+			Traversal: hcl.Traversal{
+				hcl.TraverseRoot{Name: "var"},
+				hcl.TraverseAttr{Name: "foo"},
+			},
+		},
+	}
+
+	want := []*addrs.Reference{
+		{
+			Subject: addrs.InputVariable{Name: "foo"},
+		},
+	}
+	got := n.References()
+	for _, problem := range deep.Equal(got, want) {
+		t.Error(problem)
+	}
+}
+
+func TestNodeModuleVariableReference_grandchild(t *testing.T) {
+	n := &nodeExpandModuleVariable{
+		Addr:   addrs.InputVariable{Name: "foo"},
+		Module: addrs.RootModule.Child("bar"),
+		Config: &configs.Variable{
+			Name:           "foo",
+			Type:           cty.String,
+			ConstraintType: cty.String,
+		},
+		Expr: &hclsyntax.ScopeTraversalExpr{
+			Traversal: hcl.Traversal{
+				hcl.TraverseRoot{Name: "var"},
+				hcl.TraverseAttr{Name: "foo"},
+			},
+		},
+	}
+
+	want := []*addrs.Reference{
+		{
+			Subject: addrs.InputVariable{Name: "foo"},
+		},
+	}
+	got := n.References()
+	for _, problem := range deep.Equal(got, want) {
+		t.Error(problem)
+	}
+}
diff --git a/v1.5.7/internal/terraform/node_output.go b/v1.5.7/internal/terraform/node_output.go
new file mode 100644
index 0000000..e24c606
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_output.go
@@ -0,0 +1,608 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// nodeExpandOutput is the placeholder for a non-root module output that has
+// not yet had its module path expanded.
+type nodeExpandOutput struct {
+	Addr        addrs.OutputValue
+	Module      addrs.Module
+	Config      *configs.Output
+	Destroying  bool
+	RefreshOnly bool
+
+	// Planning is set to true when this node is in a graph that was produced
+	// by the plan graph builder, as opposed to the apply graph builder.
+	// This quirk is just because we share the same node type between both
+	// phases but in practice there are a few small differences in the actions
+	// we need to take between plan and apply. See method DynamicExpand for
+	// details.
+	Planning bool
+}
+
+var (
+	_ GraphNodeReferenceable     = (*nodeExpandOutput)(nil)
+	_ GraphNodeReferencer        = (*nodeExpandOutput)(nil)
+	_ GraphNodeReferenceOutside  = (*nodeExpandOutput)(nil)
+	_ GraphNodeDynamicExpandable = (*nodeExpandOutput)(nil)
+	_ graphNodeTemporaryValue    = (*nodeExpandOutput)(nil)
+	_ graphNodeExpandsInstances  = (*nodeExpandOutput)(nil)
+)
+
+func (n *nodeExpandOutput) expandsInstances() {}
+
+func (n *nodeExpandOutput) temporaryValue() bool {
+	// non root outputs are temporary
+	return !n.Module.IsRoot()
+}
+
+func (n *nodeExpandOutput) DynamicExpand(ctx EvalContext) (*Graph, error) {
+	expander := ctx.InstanceExpander()
+	changes := ctx.Changes()
+
+	// If this is an output value that participates in custom condition checks
+	// (i.e. it has preconditions or postconditions) then the check state
+	// wants to know the addresses of the checkable objects so that it can
+	// treat them as unknown status if we encounter an error before actually
+	// visiting the checks.
+	//
+	// We must do this only during planning, because the apply phase will start
+	// with all of the same checkable objects that were registered during the
+	// planning phase. Consumers of our JSON plan and state formats expect
+	// that the set of checkable objects will be consistent between the plan
+	// and any state snapshots created during apply, and that only the statuses
+	// of those objects will have changed.
+	var checkableAddrs addrs.Set[addrs.Checkable]
+	if n.Planning {
+		if checkState := ctx.Checks(); checkState.ConfigHasChecks(n.Addr.InModule(n.Module)) {
+			checkableAddrs = addrs.MakeSet[addrs.Checkable]()
+		}
+	}
+
+	var g Graph
+	for _, module := range expander.ExpandModule(n.Module) {
+		absAddr := n.Addr.Absolute(module)
+		if checkableAddrs != nil {
+			checkableAddrs.Add(absAddr)
+		}
+
+		// Find any recorded change for this output
+		var change *plans.OutputChangeSrc
+		var outputChanges []*plans.OutputChangeSrc
+		if module.IsRoot() {
+			outputChanges = changes.GetRootOutputChanges()
+		} else {
+			parent, call := module.Call()
+			outputChanges = changes.GetOutputChanges(parent, call)
+		}
+		for _, c := range outputChanges {
+			if c.Addr.String() == absAddr.String() {
+				change = c
+				break
+			}
+		}
+
+		var node dag.Vertex
+		switch {
+		case module.IsRoot() && n.Destroying:
+			node = &NodeDestroyableOutput{
+				Addr:     absAddr,
+				Planning: n.Planning,
+			}
+
+		default:
+			node = &NodeApplyableOutput{
+				Addr:         absAddr,
+				Config:       n.Config,
+				Change:       change,
+				RefreshOnly:  n.RefreshOnly,
+				DestroyApply: n.Destroying,
+				Planning:     n.Planning,
+			}
+		}
+
+		log.Printf("[TRACE] Expanding output: adding %s as %T", absAddr.String(), node)
+		g.Add(node)
+	}
+	addRootNodeToGraph(&g)
+
+	if checkableAddrs != nil {
+		checkState := ctx.Checks()
+		checkState.ReportCheckableObjects(n.Addr.InModule(n.Module), checkableAddrs)
+	}
+
+	return &g, nil
+}
+
+func (n *nodeExpandOutput) Name() string {
+	path := n.Module.String()
+	addr := n.Addr.String() + " (expand)"
+	if path != "" {
+		return path + "." + addr
+	}
+	return addr
+}
+
+// GraphNodeModulePath
+func (n *nodeExpandOutput) ModulePath() addrs.Module {
+	return n.Module
+}
+
+// GraphNodeReferenceable
+func (n *nodeExpandOutput) ReferenceableAddrs() []addrs.Referenceable {
+	// An output in the root module can't be referenced at all.
+	if n.Module.IsRoot() {
+		return nil
+	}
+
+	// the output is referenced through the module call, and via the
+	// module itself.
+	_, call := n.Module.Call()
+	callOutput := addrs.ModuleCallOutput{
+		Call: call,
+		Name: n.Addr.Name,
+	}
+
+	// Otherwise, we can reference the output via the
+	// module call itself
+	return []addrs.Referenceable{call, callOutput}
+}
+
+// GraphNodeReferenceOutside implementation
+func (n *nodeExpandOutput) ReferenceOutside() (selfPath, referencePath addrs.Module) {
+	// Output values have their expressions resolved in the context of the
+	// module where they are defined.
+	referencePath = n.Module
+
+	// ...but they are referenced in the context of their calling module.
+	selfPath = referencePath.Parent()
+
+	return // uses named return values
+}
+
+// GraphNodeReferencer
+func (n *nodeExpandOutput) References() []*addrs.Reference {
+	// DestroyNodes do not reference anything.
+	if n.Module.IsRoot() && n.Destroying {
+		return nil
+	}
+
+	return referencesForOutput(n.Config)
+}
+
+// NodeApplyableOutput represents an output that is "applyable":
+// it is ready to be applied.
+type NodeApplyableOutput struct {
+	Addr   addrs.AbsOutputValue
+	Config *configs.Output // Config is the output in the config
+	// If this is being evaluated during apply, we may have a change recorded already
+	Change *plans.OutputChangeSrc
+
+	// Refresh-only mode means that any failing output preconditions are
+	// reported as warnings rather than errors
+	RefreshOnly bool
+
+	// DestroyApply indicates that we are applying a destroy plan, and do not
+	// need to account for conditional blocks.
+	DestroyApply bool
+
+	Planning bool
+}
+
+var (
+	_ GraphNodeModuleInstance   = (*NodeApplyableOutput)(nil)
+	_ GraphNodeReferenceable    = (*NodeApplyableOutput)(nil)
+	_ GraphNodeReferencer       = (*NodeApplyableOutput)(nil)
+	_ GraphNodeReferenceOutside = (*NodeApplyableOutput)(nil)
+	_ GraphNodeExecutable       = (*NodeApplyableOutput)(nil)
+	_ graphNodeTemporaryValue   = (*NodeApplyableOutput)(nil)
+	_ dag.GraphNodeDotter       = (*NodeApplyableOutput)(nil)
+)
+
+func (n *NodeApplyableOutput) temporaryValue() bool {
+	// this must always be evaluated if it is a root module output
+	return !n.Addr.Module.IsRoot()
+}
+
+func (n *NodeApplyableOutput) Name() string {
+	return n.Addr.String()
+}
+
+// GraphNodeModuleInstance
+func (n *NodeApplyableOutput) Path() addrs.ModuleInstance {
+	return n.Addr.Module
+}
+
+// GraphNodeModulePath
+func (n *NodeApplyableOutput) ModulePath() addrs.Module {
+	return n.Addr.Module.Module()
+}
+
+func referenceOutsideForOutput(addr addrs.AbsOutputValue) (selfPath, referencePath addrs.Module) {
+	// Output values have their expressions resolved in the context of the
+	// module where they are defined.
+	referencePath = addr.Module.Module()
+
+	// ...but they are referenced in the context of their calling module.
+	selfPath = addr.Module.Parent().Module()
+
+	return // uses named return values
+}
+
+// GraphNodeReferenceOutside implementation
+func (n *NodeApplyableOutput) ReferenceOutside() (selfPath, referencePath addrs.Module) {
+	return referenceOutsideForOutput(n.Addr)
+}
+
+func referenceableAddrsForOutput(addr addrs.AbsOutputValue) []addrs.Referenceable {
+	// An output in the root module can't be referenced at all.
+	if addr.Module.IsRoot() {
+		return nil
+	}
+
+	// Otherwise, we can be referenced via a reference to our output name
+	// on the parent module's call, or via a reference to the entire call.
+	// e.g. module.foo.bar or just module.foo .
+	// Note that our ReferenceOutside method causes these addresses to be
+	// relative to the calling module, not the module where the output
+	// was declared.
+	_, outp := addr.ModuleCallOutput()
+	_, call := addr.Module.CallInstance()
+
+	return []addrs.Referenceable{outp, call}
+}
+
+// GraphNodeReferenceable
+func (n *NodeApplyableOutput) ReferenceableAddrs() []addrs.Referenceable {
+	return referenceableAddrsForOutput(n.Addr)
+}
+
+func referencesForOutput(c *configs.Output) []*addrs.Reference {
+	var refs []*addrs.Reference
+
+	impRefs, _ := lang.ReferencesInExpr(c.Expr)
+	expRefs, _ := lang.References(c.DependsOn)
+
+	refs = append(refs, impRefs...)
+	refs = append(refs, expRefs...)
+
+	for _, check := range c.Preconditions {
+		condRefs, _ := lang.ReferencesInExpr(check.Condition)
+		refs = append(refs, condRefs...)
+		errRefs, _ := lang.ReferencesInExpr(check.ErrorMessage)
+		refs = append(refs, errRefs...)
+	}
+
+	return refs
+}
+
+// GraphNodeReferencer
+func (n *NodeApplyableOutput) References() []*addrs.Reference {
+	return referencesForOutput(n.Config)
+}
+
+// GraphNodeExecutable
+func (n *NodeApplyableOutput) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	state := ctx.State()
+	if state == nil {
+		return
+	}
+
+	changes := ctx.Changes() // may be nil, if we're not working on a changeset
+
+	val := cty.UnknownVal(cty.DynamicPseudoType)
+	changeRecorded := n.Change != nil
+	// we we have a change recorded, we don't need to re-evaluate if the value
+	// was known
+	if changeRecorded {
+		change, err := n.Change.Decode()
+		diags = diags.Append(err)
+		if err == nil {
+			val = change.After
+		}
+	}
+
+	// Checks are not evaluated during a destroy. The checks may fail, may not
+	// be valid, or may not have been registered at all.
+	if !n.DestroyApply {
+		checkRuleSeverity := tfdiags.Error
+		if n.RefreshOnly {
+			checkRuleSeverity = tfdiags.Warning
+		}
+		checkDiags := evalCheckRules(
+			addrs.OutputPrecondition,
+			n.Config.Preconditions,
+			ctx, n.Addr, EvalDataForNoInstanceKey,
+			checkRuleSeverity,
+		)
+		diags = diags.Append(checkDiags)
+		if diags.HasErrors() {
+			return diags // failed preconditions prevent further evaluation
+		}
+	}
+
+	// If there was no change recorded, or the recorded change was not wholly
+	// known, then we need to re-evaluate the output
+	if !changeRecorded || !val.IsWhollyKnown() {
+		// This has to run before we have a state lock, since evaluation also
+		// reads the state
+		var evalDiags tfdiags.Diagnostics
+		val, evalDiags = ctx.EvaluateExpr(n.Config.Expr, cty.DynamicPseudoType, nil)
+		diags = diags.Append(evalDiags)
+
+		// We'll handle errors below, after we have loaded the module.
+		// Outputs don't have a separate mode for validation, so validate
+		// depends_on expressions here too
+		diags = diags.Append(validateDependsOn(ctx, n.Config.DependsOn))
+
+		// For root module outputs in particular, an output value must be
+		// statically declared as sensitive in order to dynamically return
+		// a sensitive result, to help avoid accidental exposure in the state
+		// of a sensitive value that the user doesn't want to include there.
+		if n.Addr.Module.IsRoot() {
+			if !n.Config.Sensitive && marks.Contains(val, marks.Sensitive) {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Output refers to sensitive values",
+					Detail: `To reduce the risk of accidentally exporting sensitive data that was intended to be only internal, Terraform requires that any root module output containing sensitive data be explicitly marked as sensitive, to confirm your intent.
+
+If you do intend to export this data, annotate the output value as sensitive by adding the following argument:
+    sensitive = true`,
+					Subject: n.Config.DeclRange.Ptr(),
+				})
+			}
+		}
+	}
+
+	// handling the interpolation error
+	if diags.HasErrors() {
+		if flagWarnOutputErrors {
+			log.Printf("[ERROR] Output interpolation %q failed: %s", n.Addr, diags.Err())
+			// if we're continuing, make sure the output is included, and
+			// marked as unknown. If the evaluator was able to find a type
+			// for the value in spite of the error then we'll use it.
+			n.setValue(state, changes, cty.UnknownVal(val.Type()))
+
+			// Keep existing warnings, while converting errors to warnings.
+			// This is not meant to be the normal path, so there no need to
+			// make the errors pretty.
+			var warnings tfdiags.Diagnostics
+			for _, d := range diags {
+				switch d.Severity() {
+				case tfdiags.Warning:
+					warnings = warnings.Append(d)
+				case tfdiags.Error:
+					desc := d.Description()
+					warnings = warnings.Append(tfdiags.SimpleWarning(fmt.Sprintf("%s:%s", desc.Summary, desc.Detail)))
+				}
+			}
+
+			return warnings
+		}
+		return diags
+	}
+	n.setValue(state, changes, val)
+
+	// If we were able to evaluate a new value, we can update that in the
+	// refreshed state as well.
+	if state = ctx.RefreshState(); state != nil && val.IsWhollyKnown() {
+		// we only need to update the state, do not pass in the changes again
+		n.setValue(state, nil, val)
+	}
+
+	return diags
+}
+
+// dag.GraphNodeDotter impl.
+func (n *NodeApplyableOutput) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
+	return &dag.DotNode{
+		Name: name,
+		Attrs: map[string]string{
+			"label": n.Name(),
+			"shape": "note",
+		},
+	}
+}
+
+// NodeDestroyableOutput represents an output that is "destroyable":
+// its application will remove the output from the state.
+type NodeDestroyableOutput struct {
+	Addr     addrs.AbsOutputValue
+	Planning bool
+}
+
+var (
+	_ GraphNodeExecutable = (*NodeDestroyableOutput)(nil)
+	_ dag.GraphNodeDotter = (*NodeDestroyableOutput)(nil)
+)
+
+func (n *NodeDestroyableOutput) Name() string {
+	return fmt.Sprintf("%s (destroy)", n.Addr.String())
+}
+
+// GraphNodeModulePath
+func (n *NodeDestroyableOutput) ModulePath() addrs.Module {
+	return n.Addr.Module.Module()
+}
+
+func (n *NodeDestroyableOutput) temporaryValue() bool {
+	// this must always be evaluated if it is a root module output
+	return !n.Addr.Module.IsRoot()
+}
+
+// GraphNodeExecutable
+func (n *NodeDestroyableOutput) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
+	state := ctx.State()
+	if state == nil {
+		return nil
+	}
+
+	// if this is a root module, try to get a before value from the state for
+	// the diff
+	sensitiveBefore := false
+	before := cty.NullVal(cty.DynamicPseudoType)
+	mod := state.Module(n.Addr.Module)
+	if n.Addr.Module.IsRoot() && mod != nil {
+		if o, ok := mod.OutputValues[n.Addr.OutputValue.Name]; ok {
+			sensitiveBefore = o.Sensitive
+			before = o.Value
+		} else {
+			// If the output was not in state, a delete change would
+			// be meaningless, so exit early.
+			return nil
+
+		}
+	}
+
+	changes := ctx.Changes()
+	if changes != nil && n.Planning {
+		change := &plans.OutputChange{
+			Addr:      n.Addr,
+			Sensitive: sensitiveBefore,
+			Change: plans.Change{
+				Action: plans.Delete,
+				Before: before,
+				After:  cty.NullVal(cty.DynamicPseudoType),
+			},
+		}
+
+		cs, err := change.Encode()
+		if err != nil {
+			// Should never happen, since we just constructed this right above
+			panic(fmt.Sprintf("planned change for %s could not be encoded: %s", n.Addr, err))
+		}
+		log.Printf("[TRACE] NodeDestroyableOutput: Saving %s change for %s in changeset", change.Action, n.Addr)
+
+		changes.RemoveOutputChange(n.Addr) // remove any existing planned change, if present
+		changes.AppendOutputChange(cs)     // add the new planned change
+	}
+
+	state.RemoveOutputValue(n.Addr)
+	return nil
+}
+
+// dag.GraphNodeDotter impl.
+func (n *NodeDestroyableOutput) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
+	return &dag.DotNode{
+		Name: name,
+		Attrs: map[string]string{
+			"label": n.Name(),
+			"shape": "note",
+		},
+	}
+}
+
+func (n *NodeApplyableOutput) setValue(state *states.SyncState, changes *plans.ChangesSync, val cty.Value) {
+	if changes != nil && n.Planning {
+		// if this is a root module, try to get a before value from the state for
+		// the diff
+		sensitiveBefore := false
+		before := cty.NullVal(cty.DynamicPseudoType)
+
+		// is this output new to our state?
+		newOutput := true
+
+		mod := state.Module(n.Addr.Module)
+		if n.Addr.Module.IsRoot() && mod != nil {
+			for name, o := range mod.OutputValues {
+				if name == n.Addr.OutputValue.Name {
+					before = o.Value
+					sensitiveBefore = o.Sensitive
+					newOutput = false
+					break
+				}
+			}
+		}
+
+		// We will not show the value if either the before or after are marked
+		// as sensitive. We can show the value again once sensitivity is
+		// removed from both the config and the state.
+		sensitiveChange := sensitiveBefore || n.Config.Sensitive
+
+		// strip any marks here just to be sure we don't panic on the True comparison
+		unmarkedVal, _ := val.UnmarkDeep()
+
+		action := plans.Update
+		switch {
+		case val.IsNull() && before.IsNull():
+			// This is separate from the NoOp case below, since we can ignore
+			// sensitivity here when there are only null values.
+			action = plans.NoOp
+
+		case newOutput:
+			// This output was just added to the configuration
+			action = plans.Create
+
+		case val.IsWhollyKnown() &&
+			unmarkedVal.Equals(before).True() &&
+			n.Config.Sensitive == sensitiveBefore:
+			// Sensitivity must also match to be a NoOp.
+			// Theoretically marks may not match here, but sensitivity is the
+			// only one we can act on, and the state will have been loaded
+			// without any marks to consider.
+			action = plans.NoOp
+		}
+
+		change := &plans.OutputChange{
+			Addr:      n.Addr,
+			Sensitive: sensitiveChange,
+			Change: plans.Change{
+				Action: action,
+				Before: before,
+				After:  val,
+			},
+		}
+
+		cs, err := change.Encode()
+		if err != nil {
+			// Should never happen, since we just constructed this right above
+			panic(fmt.Sprintf("planned change for %s could not be encoded: %s", n.Addr, err))
+		}
+		log.Printf("[TRACE] setValue: Saving %s change for %s in changeset", change.Action, n.Addr)
+		changes.AppendOutputChange(cs) // add the new planned change
+	}
+
+	if changes != nil && !n.Planning {
+		// During apply there is no longer any change to track, so we must
+		// ensure the state is updated and not overridden by a change.
+		changes.RemoveOutputChange(n.Addr)
+	}
+
+	// Null outputs must be saved for modules so that they can still be
+	// evaluated. Null root outputs are removed entirely, which is always fine
+	// because they can't be referenced by anything else in the configuration.
+	if n.Addr.Module.IsRoot() && val.IsNull() {
+		log.Printf("[TRACE] setValue: Removing %s from state (it is now null)", n.Addr)
+		state.RemoveOutputValue(n.Addr)
+		return
+	}
+
+	log.Printf("[TRACE] setValue: Saving value for %s in state", n.Addr)
+
+	// non-root outputs need to keep sensitive marks for evaluation, but are
+	// not serialized.
+	if n.Addr.Module.IsRoot() {
+		val, _ = val.UnmarkDeep()
+		val = cty.UnknownAsNull(val)
+	}
+
+	state.SetOutputValue(n.Addr, val, n.Config.Sensitive)
+}
diff --git a/v1.5.7/internal/terraform/node_output_test.go b/v1.5.7/internal/terraform/node_output_test.go
new file mode 100644
index 0000000..5a9b90f
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_output_test.go
@@ -0,0 +1,190 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestNodeApplyableOutputExecute_knownValue(t *testing.T) {
+	ctx := new(MockEvalContext)
+	ctx.StateState = states.NewState().SyncWrapper()
+	ctx.RefreshStateState = states.NewState().SyncWrapper()
+	ctx.ChecksState = checks.NewState(nil)
+
+	config := &configs.Output{Name: "map-output"}
+	addr := addrs.OutputValue{Name: config.Name}.Absolute(addrs.RootModuleInstance)
+	node := &NodeApplyableOutput{Config: config, Addr: addr}
+	val := cty.MapVal(map[string]cty.Value{
+		"a": cty.StringVal("b"),
+	})
+	ctx.EvaluateExprResult = val
+
+	err := node.Execute(ctx, walkApply)
+	if err != nil {
+		t.Fatalf("unexpected execute error: %s", err)
+	}
+
+	outputVal := ctx.StateState.OutputValue(addr)
+	if got, want := outputVal.Value, val; !got.RawEquals(want) {
+		t.Errorf("wrong output value in state\n got: %#v\nwant: %#v", got, want)
+	}
+
+	if !ctx.RefreshStateCalled {
+		t.Fatal("should have called RefreshState, but didn't")
+	}
+	refreshOutputVal := ctx.RefreshStateState.OutputValue(addr)
+	if got, want := refreshOutputVal.Value, val; !got.RawEquals(want) {
+		t.Fatalf("wrong output value in refresh state\n got: %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestNodeApplyableOutputExecute_noState(t *testing.T) {
+	ctx := new(MockEvalContext)
+
+	config := &configs.Output{Name: "map-output"}
+	addr := addrs.OutputValue{Name: config.Name}.Absolute(addrs.RootModuleInstance)
+	node := &NodeApplyableOutput{Config: config, Addr: addr}
+	val := cty.MapVal(map[string]cty.Value{
+		"a": cty.StringVal("b"),
+	})
+	ctx.EvaluateExprResult = val
+
+	err := node.Execute(ctx, walkApply)
+	if err != nil {
+		t.Fatalf("unexpected execute error: %s", err)
+	}
+}
+
+func TestNodeApplyableOutputExecute_invalidDependsOn(t *testing.T) {
+	ctx := new(MockEvalContext)
+	ctx.StateState = states.NewState().SyncWrapper()
+	ctx.ChecksState = checks.NewState(nil)
+
+	config := &configs.Output{
+		Name: "map-output",
+		DependsOn: []hcl.Traversal{
+			{
+				hcl.TraverseRoot{Name: "test_instance"},
+				hcl.TraverseAttr{Name: "foo"},
+				hcl.TraverseAttr{Name: "bar"},
+			},
+		},
+	}
+	addr := addrs.OutputValue{Name: config.Name}.Absolute(addrs.RootModuleInstance)
+	node := &NodeApplyableOutput{Config: config, Addr: addr}
+	val := cty.MapVal(map[string]cty.Value{
+		"a": cty.StringVal("b"),
+	})
+	ctx.EvaluateExprResult = val
+
+	diags := node.Execute(ctx, walkApply)
+	if !diags.HasErrors() {
+		t.Fatal("expected execute error, but there was none")
+	}
+	if got, want := diags.Err().Error(), "Invalid depends_on reference"; !strings.Contains(got, want) {
+		t.Errorf("expected error to include %q, but was: %s", want, got)
+	}
+}
+
+func TestNodeApplyableOutputExecute_sensitiveValueNotOutput(t *testing.T) {
+	ctx := new(MockEvalContext)
+	ctx.StateState = states.NewState().SyncWrapper()
+	ctx.ChecksState = checks.NewState(nil)
+
+	config := &configs.Output{Name: "map-output"}
+	addr := addrs.OutputValue{Name: config.Name}.Absolute(addrs.RootModuleInstance)
+	node := &NodeApplyableOutput{Config: config, Addr: addr}
+	val := cty.MapVal(map[string]cty.Value{
+		"a": cty.StringVal("b").Mark(marks.Sensitive),
+	})
+	ctx.EvaluateExprResult = val
+
+	diags := node.Execute(ctx, walkApply)
+	if !diags.HasErrors() {
+		t.Fatal("expected execute error, but there was none")
+	}
+	if got, want := diags.Err().Error(), "Output refers to sensitive values"; !strings.Contains(got, want) {
+		t.Errorf("expected error to include %q, but was: %s", want, got)
+	}
+}
+
+func TestNodeApplyableOutputExecute_sensitiveValueAndOutput(t *testing.T) {
+	ctx := new(MockEvalContext)
+	ctx.StateState = states.NewState().SyncWrapper()
+	ctx.ChecksState = checks.NewState(nil)
+
+	config := &configs.Output{
+		Name:      "map-output",
+		Sensitive: true,
+	}
+	addr := addrs.OutputValue{Name: config.Name}.Absolute(addrs.RootModuleInstance)
+	node := &NodeApplyableOutput{Config: config, Addr: addr}
+	val := cty.MapVal(map[string]cty.Value{
+		"a": cty.StringVal("b").Mark(marks.Sensitive),
+	})
+	ctx.EvaluateExprResult = val
+
+	err := node.Execute(ctx, walkApply)
+	if err != nil {
+		t.Fatalf("unexpected execute error: %s", err)
+	}
+
+	// Unmarked value should be stored in state
+	outputVal := ctx.StateState.OutputValue(addr)
+	want, _ := val.UnmarkDeep()
+	if got := outputVal.Value; !got.RawEquals(want) {
+		t.Errorf("wrong output value in state\n got: %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestNodeDestroyableOutputExecute(t *testing.T) {
+	outputAddr := addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance)
+
+	state := states.NewState()
+	state.Module(addrs.RootModuleInstance).SetOutputValue("foo", cty.StringVal("bar"), false)
+	state.OutputValue(outputAddr)
+
+	ctx := &MockEvalContext{
+		StateState: state.SyncWrapper(),
+	}
+	node := NodeDestroyableOutput{Addr: outputAddr}
+
+	diags := node.Execute(ctx, walkApply)
+	if diags.HasErrors() {
+		t.Fatalf("Unexpected error: %s", diags.Err())
+	}
+	if state.OutputValue(outputAddr) != nil {
+		t.Fatal("Unexpected outputs in state after removal")
+	}
+}
+
+func TestNodeDestroyableOutputExecute_notInState(t *testing.T) {
+	outputAddr := addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance)
+
+	state := states.NewState()
+
+	ctx := &MockEvalContext{
+		StateState: state.SyncWrapper(),
+	}
+	node := NodeDestroyableOutput{Addr: outputAddr}
+
+	diags := node.Execute(ctx, walkApply)
+	if diags.HasErrors() {
+		t.Fatalf("Unexpected error: %s", diags.Err())
+	}
+	if state.OutputValue(outputAddr) != nil {
+		t.Fatal("Unexpected outputs in state after removal")
+	}
+}
diff --git a/v1.5.7/internal/terraform/node_provider.go b/v1.5.7/internal/terraform/node_provider.go
new file mode 100644
index 0000000..69b4dcc
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_provider.go
@@ -0,0 +1,182 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// NodeApplyableProvider represents a provider during an apply.
+type NodeApplyableProvider struct {
+	*NodeAbstractProvider
+}
+
+var (
+	_ GraphNodeExecutable = (*NodeApplyableProvider)(nil)
+)
+
+// GraphNodeExecutable
+func (n *NodeApplyableProvider) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	_, err := ctx.InitProvider(n.Addr)
+	diags = diags.Append(err)
+	if diags.HasErrors() {
+		return diags
+	}
+	provider, _, err := getProvider(ctx, n.Addr)
+	diags = diags.Append(err)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	switch op {
+	case walkValidate:
+		log.Printf("[TRACE] NodeApplyableProvider: validating configuration for %s", n.Addr)
+		return diags.Append(n.ValidateProvider(ctx, provider))
+	case walkPlan, walkPlanDestroy, walkApply, walkDestroy:
+		log.Printf("[TRACE] NodeApplyableProvider: configuring %s", n.Addr)
+		return diags.Append(n.ConfigureProvider(ctx, provider, false))
+	case walkImport:
+		log.Printf("[TRACE] NodeApplyableProvider: configuring %s (requiring that configuration is wholly known)", n.Addr)
+		return diags.Append(n.ConfigureProvider(ctx, provider, true))
+	}
+	return diags
+}
+
+func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider providers.Interface) (diags tfdiags.Diagnostics) {
+
+	configBody := buildProviderConfig(ctx, n.Addr, n.ProviderConfig())
+
+	// if a provider config is empty (only an alias), return early and don't continue
+	// validation. validate doesn't need to fully configure the provider itself, so
+	// skipping a provider with an implied configuration won't prevent other validation from completing.
+	_, noConfigDiags := configBody.Content(&hcl.BodySchema{})
+	if !noConfigDiags.HasErrors() {
+		return nil
+	}
+
+	schemaResp := provider.GetProviderSchema()
+	diags = diags.Append(schemaResp.Diagnostics.InConfigBody(configBody, n.Addr.String()))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	configSchema := schemaResp.Provider.Block
+	if configSchema == nil {
+		// Should never happen in real code, but often comes up in tests where
+		// mock schemas are being used that tend to be incomplete.
+		log.Printf("[WARN] ValidateProvider: no config schema is available for %s, so using empty schema", n.Addr)
+		configSchema = &configschema.Block{}
+	}
+
+	configVal, _, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, EvalDataForNoInstanceKey)
+	if evalDiags.HasErrors() {
+		return diags.Append(evalDiags)
+	}
+	diags = diags.Append(evalDiags)
+
+	// If our config value contains any marked values, ensure those are
+	// stripped out before sending this to the provider
+	unmarkedConfigVal, _ := configVal.UnmarkDeep()
+
+	req := providers.ValidateProviderConfigRequest{
+		Config: unmarkedConfigVal,
+	}
+
+	validateResp := provider.ValidateProviderConfig(req)
+	diags = diags.Append(validateResp.Diagnostics.InConfigBody(configBody, n.Addr.String()))
+
+	return diags
+}
+
+// ConfigureProvider configures a provider that is already initialized and retrieved.
+// If verifyConfigIsKnown is true, ConfigureProvider will return an error if the
+// provider configVal is not wholly known and is meant only for use during import.
+func (n *NodeApplyableProvider) ConfigureProvider(ctx EvalContext, provider providers.Interface, verifyConfigIsKnown bool) (diags tfdiags.Diagnostics) {
+	config := n.ProviderConfig()
+
+	configBody := buildProviderConfig(ctx, n.Addr, config)
+
+	resp := provider.GetProviderSchema()
+	diags = diags.Append(resp.Diagnostics.InConfigBody(configBody, n.Addr.String()))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	configSchema := resp.Provider.Block
+	configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, EvalDataForNoInstanceKey)
+	diags = diags.Append(evalDiags)
+	if evalDiags.HasErrors() {
+		return diags
+	}
+
+	if verifyConfigIsKnown && !configVal.IsWhollyKnown() {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Invalid provider configuration",
+			Detail:   fmt.Sprintf("The configuration for %s depends on values that cannot be determined until apply.", n.Addr),
+			Subject:  &config.DeclRange,
+		})
+		return diags
+	}
+
+	// If our config value contains any marked values, ensure those are
+	// stripped out before sending this to the provider
+	unmarkedConfigVal, _ := configVal.UnmarkDeep()
+
+	// Allow the provider to validate and insert any defaults into the full
+	// configuration.
+	req := providers.ValidateProviderConfigRequest{
+		Config: unmarkedConfigVal,
+	}
+
+	// ValidateProviderConfig is only used for validation. We are intentionally
+	// ignoring the PreparedConfig field to maintain existing behavior.
+	validateResp := provider.ValidateProviderConfig(req)
+	diags = diags.Append(validateResp.Diagnostics.InConfigBody(configBody, n.Addr.String()))
+	if diags.HasErrors() && config == nil {
+		// If there isn't an explicit "provider" block in the configuration,
+		// this error message won't be very clear. Add some detail to the error
+		// message in this case.
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid provider configuration",
+			fmt.Sprintf(providerConfigErr, n.Addr.Provider),
+		))
+	}
+
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// If the provider returns something different, log a warning to help
+	// indicate to provider developers that the value is not used.
+	preparedCfg := validateResp.PreparedConfig
+	if preparedCfg != cty.NilVal && !preparedCfg.IsNull() && !preparedCfg.RawEquals(unmarkedConfigVal) {
+		log.Printf("[WARN] ValidateProviderConfig from %q changed the config value, but that value is unused", n.Addr)
+	}
+
+	configDiags := ctx.ConfigureProvider(n.Addr, unmarkedConfigVal)
+	diags = diags.Append(configDiags.InConfigBody(configBody, n.Addr.String()))
+	if diags.HasErrors() && config == nil {
+		// If there isn't an explicit "provider" block in the configuration,
+		// this error message won't be very clear. Add some detail to the error
+		// message in this case.
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Invalid provider configuration",
+			fmt.Sprintf(providerConfigErr, n.Addr.Provider),
+		))
+	}
+	return diags
+}
+
+const providerConfigErr = `Provider %q requires explicit configuration. Add a provider block to the root module and configure the provider's required arguments as described in the provider documentation.
+`
diff --git a/v1.5.7/internal/terraform/node_provider_abstract.go b/v1.5.7/internal/terraform/node_provider_abstract.go
new file mode 100644
index 0000000..70540c3
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_provider_abstract.go
@@ -0,0 +1,98 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+// ConcreteProviderNodeFunc is a callback type used to convert an
+// abstract provider to a concrete one of some type.
+type ConcreteProviderNodeFunc func(*NodeAbstractProvider) dag.Vertex
+
+// NodeAbstractProvider represents a provider that has no associated operations.
+// It registers all the common interfaces across operations for providers.
+type NodeAbstractProvider struct {
+	Addr addrs.AbsProviderConfig
+
+	// The fields below will be automatically set using the Attach
+	// interfaces if you're running those transforms, but also be explicitly
+	// set if you already have that information.
+
+	Config *configs.Provider
+	Schema *configschema.Block
+}
+
+var (
+	_ GraphNodeModulePath                 = (*NodeAbstractProvider)(nil)
+	_ GraphNodeReferencer                 = (*NodeAbstractProvider)(nil)
+	_ GraphNodeProvider                   = (*NodeAbstractProvider)(nil)
+	_ GraphNodeAttachProvider             = (*NodeAbstractProvider)(nil)
+	_ GraphNodeAttachProviderConfigSchema = (*NodeAbstractProvider)(nil)
+	_ dag.GraphNodeDotter                 = (*NodeAbstractProvider)(nil)
+)
+
+func (n *NodeAbstractProvider) Name() string {
+	return n.Addr.String()
+}
+
+// GraphNodeModuleInstance
+func (n *NodeAbstractProvider) Path() addrs.ModuleInstance {
+	// Providers cannot be contained inside an expanded module, so this shim
+	// converts our module path to the correct ModuleInstance.
+	return n.Addr.Module.UnkeyedInstanceShim()
+}
+
+// GraphNodeModulePath
+func (n *NodeAbstractProvider) ModulePath() addrs.Module {
+	return n.Addr.Module
+}
+
+// GraphNodeReferencer
+func (n *NodeAbstractProvider) References() []*addrs.Reference {
+	if n.Config == nil || n.Schema == nil {
+		return nil
+	}
+
+	return ReferencesFromConfig(n.Config.Config, n.Schema)
+}
+
+// GraphNodeProvider
+func (n *NodeAbstractProvider) ProviderAddr() addrs.AbsProviderConfig {
+	return n.Addr
+}
+
+// GraphNodeProvider
+func (n *NodeAbstractProvider) ProviderConfig() *configs.Provider {
+	if n.Config == nil {
+		return nil
+	}
+
+	return n.Config
+}
+
+// GraphNodeAttachProvider
+func (n *NodeAbstractProvider) AttachProvider(c *configs.Provider) {
+	n.Config = c
+}
+
+// GraphNodeAttachProviderConfigSchema impl.
+func (n *NodeAbstractProvider) AttachProviderConfigSchema(schema *configschema.Block) {
+	n.Schema = schema
+}
+
+// GraphNodeDotter impl.
+func (n *NodeAbstractProvider) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
+	return &dag.DotNode{
+		Name: name,
+		Attrs: map[string]string{
+			"label": n.Name(),
+			"shape": "diamond",
+		},
+	}
+}
diff --git a/v1.5.7/internal/terraform/node_provider_eval.go b/v1.5.7/internal/terraform/node_provider_eval.go
new file mode 100644
index 0000000..b7fb89d
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_provider_eval.go
@@ -0,0 +1,22 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import "github.com/hashicorp/terraform/internal/tfdiags"
+
+// NodeEvalableProvider represents a provider during an "eval" walk.
+// This special provider node type just initializes a provider and
+// fetches its schema, without configuring it or otherwise interacting
+// with it.
+type NodeEvalableProvider struct {
+	*NodeAbstractProvider
+}
+
+var _ GraphNodeExecutable = (*NodeEvalableProvider)(nil)
+
+// GraphNodeExecutable
+func (n *NodeEvalableProvider) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	_, err := ctx.InitProvider(n.Addr)
+	return diags.Append(err)
+}
diff --git a/v1.5.7/internal/terraform/node_provider_test.go b/v1.5.7/internal/terraform/node_provider_test.go
new file mode 100644
index 0000000..3b207ab
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_provider_test.go
@@ -0,0 +1,527 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestNodeApplyableProviderExecute(t *testing.T) {
+	config := &configs.Provider{
+		Name: "foo",
+		Config: configs.SynthBody("", map[string]cty.Value{
+			"user": cty.StringVal("hello"),
+		}),
+	}
+
+	schema := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"user": {
+				Type:     cty.String,
+				Required: true,
+			},
+			"pw": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	}
+	provider := mockProviderWithConfigSchema(schema)
+	providerAddr := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule,
+		Provider: addrs.NewDefaultProvider("foo"),
+	}
+
+	n := &NodeApplyableProvider{&NodeAbstractProvider{
+		Addr:   providerAddr,
+		Config: config,
+	}}
+
+	ctx := &MockEvalContext{ProviderProvider: provider}
+	ctx.installSimpleEval()
+	ctx.ProviderInputValues = map[string]cty.Value{
+		"pw": cty.StringVal("so secret"),
+	}
+
+	if diags := n.Execute(ctx, walkApply); diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	if !ctx.ConfigureProviderCalled {
+		t.Fatal("should be called")
+	}
+
+	gotObj := ctx.ConfigureProviderConfig
+	if !gotObj.Type().HasAttribute("user") {
+		t.Fatal("configuration object does not have \"user\" attribute")
+	}
+	if got, want := gotObj.GetAttr("user"), cty.StringVal("hello"); !got.RawEquals(want) {
+		t.Errorf("wrong configuration value\ngot:  %#v\nwant: %#v", got, want)
+	}
+
+	if !gotObj.Type().HasAttribute("pw") {
+		t.Fatal("configuration object does not have \"pw\" attribute")
+	}
+	if got, want := gotObj.GetAttr("pw"), cty.StringVal("so secret"); !got.RawEquals(want) {
+		t.Errorf("wrong configuration value\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestNodeApplyableProviderExecute_unknownImport(t *testing.T) {
+	config := &configs.Provider{
+		Name: "foo",
+		Config: configs.SynthBody("", map[string]cty.Value{
+			"test_string": cty.UnknownVal(cty.String),
+		}),
+	}
+	provider := mockProviderWithConfigSchema(simpleTestSchema())
+	providerAddr := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule,
+		Provider: addrs.NewDefaultProvider("foo"),
+	}
+	n := &NodeApplyableProvider{&NodeAbstractProvider{
+		Addr:   providerAddr,
+		Config: config,
+	}}
+
+	ctx := &MockEvalContext{ProviderProvider: provider}
+	ctx.installSimpleEval()
+
+	diags := n.Execute(ctx, walkImport)
+	if !diags.HasErrors() {
+		t.Fatal("expected error, got success")
+	}
+
+	detail := `Invalid provider configuration: The configuration for provider["registry.terraform.io/hashicorp/foo"] depends on values that cannot be determined until apply.`
+	if got, want := diags.Err().Error(), detail; got != want {
+		t.Errorf("wrong diagnostic detail\n got: %q\nwant: %q", got, want)
+	}
+
+	if ctx.ConfigureProviderCalled {
+		t.Fatal("should not be called")
+	}
+}
+
+func TestNodeApplyableProviderExecute_unknownApply(t *testing.T) {
+	config := &configs.Provider{
+		Name: "foo",
+		Config: configs.SynthBody("", map[string]cty.Value{
+			"test_string": cty.UnknownVal(cty.String),
+		}),
+	}
+	provider := mockProviderWithConfigSchema(simpleTestSchema())
+	providerAddr := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule,
+		Provider: addrs.NewDefaultProvider("foo"),
+	}
+	n := &NodeApplyableProvider{&NodeAbstractProvider{
+		Addr:   providerAddr,
+		Config: config,
+	}}
+	ctx := &MockEvalContext{ProviderProvider: provider}
+	ctx.installSimpleEval()
+
+	if err := n.Execute(ctx, walkApply); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !ctx.ConfigureProviderCalled {
+		t.Fatal("should be called")
+	}
+
+	gotObj := ctx.ConfigureProviderConfig
+	if !gotObj.Type().HasAttribute("test_string") {
+		t.Fatal("configuration object does not have \"test_string\" attribute")
+	}
+	if got, want := gotObj.GetAttr("test_string"), cty.UnknownVal(cty.String); !got.RawEquals(want) {
+		t.Errorf("wrong configuration value\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestNodeApplyableProviderExecute_sensitive(t *testing.T) {
+	config := &configs.Provider{
+		Name: "foo",
+		Config: configs.SynthBody("", map[string]cty.Value{
+			"test_string": cty.StringVal("hello").Mark(marks.Sensitive),
+		}),
+	}
+	provider := mockProviderWithConfigSchema(simpleTestSchema())
+	providerAddr := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule,
+		Provider: addrs.NewDefaultProvider("foo"),
+	}
+
+	n := &NodeApplyableProvider{&NodeAbstractProvider{
+		Addr:   providerAddr,
+		Config: config,
+	}}
+
+	ctx := &MockEvalContext{ProviderProvider: provider}
+	ctx.installSimpleEval()
+	if err := n.Execute(ctx, walkApply); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !ctx.ConfigureProviderCalled {
+		t.Fatal("should be called")
+	}
+
+	gotObj := ctx.ConfigureProviderConfig
+	if !gotObj.Type().HasAttribute("test_string") {
+		t.Fatal("configuration object does not have \"test_string\" attribute")
+	}
+	if got, want := gotObj.GetAttr("test_string"), cty.StringVal("hello"); !got.RawEquals(want) {
+		t.Errorf("wrong configuration value\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestNodeApplyableProviderExecute_sensitiveValidate(t *testing.T) {
+	config := &configs.Provider{
+		Name: "foo",
+		Config: configs.SynthBody("", map[string]cty.Value{
+			"test_string": cty.StringVal("hello").Mark(marks.Sensitive),
+		}),
+	}
+	provider := mockProviderWithConfigSchema(simpleTestSchema())
+	providerAddr := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule,
+		Provider: addrs.NewDefaultProvider("foo"),
+	}
+
+	n := &NodeApplyableProvider{&NodeAbstractProvider{
+		Addr:   providerAddr,
+		Config: config,
+	}}
+
+	ctx := &MockEvalContext{ProviderProvider: provider}
+	ctx.installSimpleEval()
+	if err := n.Execute(ctx, walkValidate); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !provider.ValidateProviderConfigCalled {
+		t.Fatal("should be called")
+	}
+
+	gotObj := provider.ValidateProviderConfigRequest.Config
+	if !gotObj.Type().HasAttribute("test_string") {
+		t.Fatal("configuration object does not have \"test_string\" attribute")
+	}
+	if got, want := gotObj.GetAttr("test_string"), cty.StringVal("hello"); !got.RawEquals(want) {
+		t.Errorf("wrong configuration value\ngot:  %#v\nwant: %#v", got, want)
+	}
+}
+
+func TestNodeApplyableProviderExecute_emptyValidate(t *testing.T) {
+	config := &configs.Provider{
+		Name:   "foo",
+		Config: configs.SynthBody("", map[string]cty.Value{}),
+	}
+	provider := mockProviderWithConfigSchema(&configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"test_string": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	})
+	providerAddr := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule,
+		Provider: addrs.NewDefaultProvider("foo"),
+	}
+
+	n := &NodeApplyableProvider{&NodeAbstractProvider{
+		Addr:   providerAddr,
+		Config: config,
+	}}
+
+	ctx := &MockEvalContext{ProviderProvider: provider}
+	ctx.installSimpleEval()
+	if err := n.Execute(ctx, walkValidate); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if ctx.ConfigureProviderCalled {
+		t.Fatal("should not be called")
+	}
+}
+
+func TestNodeApplyableProvider_Validate(t *testing.T) {
+	provider := mockProviderWithConfigSchema(&configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"region": {
+				Type:     cty.String,
+				Required: true,
+			},
+		},
+	})
+	ctx := &MockEvalContext{ProviderProvider: provider}
+	ctx.installSimpleEval()
+
+	t.Run("valid", func(t *testing.T) {
+		config := &configs.Provider{
+			Name: "test",
+			Config: configs.SynthBody("", map[string]cty.Value{
+				"region": cty.StringVal("mars"),
+			}),
+		}
+
+		node := NodeApplyableProvider{
+			NodeAbstractProvider: &NodeAbstractProvider{
+				Addr:   mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+				Config: config,
+			},
+		}
+
+		diags := node.ValidateProvider(ctx, provider)
+		if diags.HasErrors() {
+			t.Errorf("unexpected error with valid config: %s", diags.Err())
+		}
+	})
+
+	t.Run("invalid", func(t *testing.T) {
+		config := &configs.Provider{
+			Name: "test",
+			Config: configs.SynthBody("", map[string]cty.Value{
+				"region": cty.MapValEmpty(cty.String),
+			}),
+		}
+
+		node := NodeApplyableProvider{
+			NodeAbstractProvider: &NodeAbstractProvider{
+				Addr:   mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+				Config: config,
+			},
+		}
+
+		diags := node.ValidateProvider(ctx, provider)
+		if !diags.HasErrors() {
+			t.Error("missing expected error with invalid config")
+		}
+	})
+
+	t.Run("empty config", func(t *testing.T) {
+		node := NodeApplyableProvider{
+			NodeAbstractProvider: &NodeAbstractProvider{
+				Addr: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+			},
+		}
+
+		diags := node.ValidateProvider(ctx, provider)
+		if diags.HasErrors() {
+			t.Errorf("unexpected error with empty config: %s", diags.Err())
+		}
+	})
+}
+
+// This test specifically tests responses from the
+// providers.ValidateProviderConfigFn. See
+// TestNodeApplyableProvider_ConfigProvider_config_fn_err for
+// providers.ConfigureProviderRequest responses.
+func TestNodeApplyableProvider_ConfigProvider(t *testing.T) {
+	provider := mockProviderWithConfigSchema(&configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"region": {
+				Type:     cty.String,
+				Optional: true,
+			},
+		},
+	})
+	// For this test, we're returning an error for an optional argument. This
+	// can happen for example if an argument is only conditionally required.
+	provider.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
+		region := req.Config.GetAttr("region")
+		if region.IsNull() {
+			resp.Diagnostics = resp.Diagnostics.Append(
+				tfdiags.WholeContainingBody(tfdiags.Error, "value is not found", "you did not supply a required value"))
+		}
+		return
+	}
+	ctx := &MockEvalContext{ProviderProvider: provider}
+	ctx.installSimpleEval()
+
+	t.Run("valid", func(t *testing.T) {
+		config := &configs.Provider{
+			Name: "test",
+			Config: configs.SynthBody("", map[string]cty.Value{
+				"region": cty.StringVal("mars"),
+			}),
+		}
+
+		node := NodeApplyableProvider{
+			NodeAbstractProvider: &NodeAbstractProvider{
+				Addr:   mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+				Config: config,
+			},
+		}
+
+		diags := node.ConfigureProvider(ctx, provider, false)
+		if diags.HasErrors() {
+			t.Errorf("unexpected error with valid config: %s", diags.Err())
+		}
+	})
+
+	t.Run("missing required config (no config at all)", func(t *testing.T) {
+		node := NodeApplyableProvider{
+			NodeAbstractProvider: &NodeAbstractProvider{
+				Addr: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+			},
+		}
+
+		diags := node.ConfigureProvider(ctx, provider, false)
+		if !diags.HasErrors() {
+			t.Fatal("missing expected error with nil config")
+		}
+		if !strings.Contains(diags.Err().Error(), "requires explicit configuration") {
+			t.Errorf("diagnostic is missing \"requires explicit configuration\" message: %s", diags.Err())
+		}
+	})
+
+	t.Run("missing required config", func(t *testing.T) {
+		config := &configs.Provider{
+			Name:   "test",
+			Config: hcl.EmptyBody(),
+		}
+		node := NodeApplyableProvider{
+			NodeAbstractProvider: &NodeAbstractProvider{
+				Addr:   mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+				Config: config,
+			},
+		}
+
+		diags := node.ConfigureProvider(ctx, provider, false)
+		if !diags.HasErrors() {
+			t.Fatal("missing expected error with invalid config")
+		}
+		if !strings.Contains(diags.Err().Error(), "value is not found") {
+			t.Errorf("wrong diagnostic: %s", diags.Err())
+		}
+	})
+
+}
+
+// This test is similar to TestNodeApplyableProvider_ConfigProvider, but tests responses from the providers.ConfigureProviderRequest
+func TestNodeApplyableProvider_ConfigProvider_config_fn_err(t *testing.T) {
+	provider := mockProviderWithConfigSchema(&configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"region": {
+				Type:     cty.String,
+				Optional: true,
+			},
+		},
+	})
+	ctx := &MockEvalContext{ProviderProvider: provider}
+	ctx.installSimpleEval()
+	// For this test, provider.PrepareConfigFn will succeed every time but the
+	// ctx.ConfigureProviderFn will return an error if a value is not found.
+	//
+	// This is an unlikely but real situation that occurs:
+	// https://github.com/hashicorp/terraform/issues/23087
+	ctx.ConfigureProviderFn = func(addr addrs.AbsProviderConfig, cfg cty.Value) (diags tfdiags.Diagnostics) {
+		if cfg.IsNull() {
+			diags = diags.Append(fmt.Errorf("no config provided"))
+		} else {
+			region := cfg.GetAttr("region")
+			if region.IsNull() {
+				diags = diags.Append(fmt.Errorf("value is not found"))
+			}
+		}
+		return
+	}
+
+	t.Run("valid", func(t *testing.T) {
+		config := &configs.Provider{
+			Name: "test",
+			Config: configs.SynthBody("", map[string]cty.Value{
+				"region": cty.StringVal("mars"),
+			}),
+		}
+
+		node := NodeApplyableProvider{
+			NodeAbstractProvider: &NodeAbstractProvider{
+				Addr:   mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+				Config: config,
+			},
+		}
+
+		diags := node.ConfigureProvider(ctx, provider, false)
+		if diags.HasErrors() {
+			t.Errorf("unexpected error with valid config: %s", diags.Err())
+		}
+	})
+
+	t.Run("missing required config (no config at all)", func(t *testing.T) {
+		node := NodeApplyableProvider{
+			NodeAbstractProvider: &NodeAbstractProvider{
+				Addr: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+			},
+		}
+
+		diags := node.ConfigureProvider(ctx, provider, false)
+		if !diags.HasErrors() {
+			t.Fatal("missing expected error with nil config")
+		}
+		if !strings.Contains(diags.Err().Error(), "requires explicit configuration") {
+			t.Errorf("diagnostic is missing \"requires explicit configuration\" message: %s", diags.Err())
+		}
+	})
+
+	t.Run("missing required config", func(t *testing.T) {
+		config := &configs.Provider{
+			Name:   "test",
+			Config: hcl.EmptyBody(),
+		}
+		node := NodeApplyableProvider{
+			NodeAbstractProvider: &NodeAbstractProvider{
+				Addr:   mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+				Config: config,
+			},
+		}
+
+		diags := node.ConfigureProvider(ctx, provider, false)
+		if !diags.HasErrors() {
+			t.Fatal("missing expected error with invalid config")
+		}
+		if diags.Err().Error() != "value is not found" {
+			t.Errorf("wrong diagnostic: %s", diags.Err())
+		}
+	})
+}
+
+func TestGetSchemaError(t *testing.T) {
+	provider := &MockProvider{
+		GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+			Diagnostics: tfdiags.Diagnostics.Append(nil, tfdiags.WholeContainingBody(tfdiags.Error, "oops", "error")),
+		},
+	}
+
+	providerAddr := mustProviderConfig(`provider["terraform.io/some/provider"]`)
+	ctx := &MockEvalContext{ProviderProvider: provider}
+	ctx.installSimpleEval()
+	node := NodeApplyableProvider{
+		NodeAbstractProvider: &NodeAbstractProvider{
+			Addr: providerAddr,
+		},
+	}
+
+	diags := node.ConfigureProvider(ctx, provider, false)
+	for _, d := range diags {
+		desc := d.Description()
+		if desc.Address != providerAddr.String() {
+			t.Fatalf("missing provider address from diagnostics: %#v", desc)
+		}
+	}
+
+}
diff --git a/v1.5.7/internal/terraform/node_resource_abstract.go b/v1.5.7/internal/terraform/node_resource_abstract.go
new file mode 100644
index 0000000..1190f3b
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_abstract.go
@@ -0,0 +1,546 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ConcreteResourceNodeFunc is a callback type used to convert an
+// abstract resource to a concrete one of some type.
+type ConcreteResourceNodeFunc func(*NodeAbstractResource) dag.Vertex
+
+// GraphNodeConfigResource is implemented by any nodes that represent a resource.
+// The type of operation cannot be assumed, only that this node represents
+// the given resource.
+type GraphNodeConfigResource interface {
+	ResourceAddr() addrs.ConfigResource
+}
+
+// ConcreteResourceInstanceNodeFunc is a callback type used to convert an
+// abstract resource instance to a concrete one of some type.
+type ConcreteResourceInstanceNodeFunc func(*NodeAbstractResourceInstance) dag.Vertex
+
+// GraphNodeResourceInstance is implemented by any nodes that represent
+// a resource instance. A single resource may have multiple instances if,
+// for example, the "count" or "for_each" argument is used for it in
+// configuration.
+type GraphNodeResourceInstance interface {
+	ResourceInstanceAddr() addrs.AbsResourceInstance
+
+	// StateDependencies returns any inter-resource dependencies that are
+	// stored in the state.
+	StateDependencies() []addrs.ConfigResource
+}
+
+// NodeAbstractResource represents a resource that has no associated
+// operations. It registers all the interfaces for a resource that common
+// across multiple operation types.
+type NodeAbstractResource struct {
+	Addr addrs.ConfigResource
+
+	// The fields below will be automatically set using the Attach
+	// interfaces if you're running those transforms, but also be explicitly
+	// set if you already have that information.
+
+	Schema        *configschema.Block // Schema for processing the configuration body
+	SchemaVersion uint64              // Schema version of "Schema", as decided by the provider
+	Config        *configs.Resource   // Config is the resource in the config
+
+	// ProviderMetas is the provider_meta configs for the module this resource belongs to
+	ProviderMetas map[addrs.Provider]*configs.ProviderMeta
+
+	ProvisionerSchemas map[string]*configschema.Block
+
+	// Set from GraphNodeTargetable
+	Targets []addrs.Targetable
+
+	// Set from AttachDataResourceDependsOn
+	dependsOn      []addrs.ConfigResource
+	forceDependsOn bool
+
+	// The address of the provider this resource will use
+	ResolvedProvider addrs.AbsProviderConfig
+	// storedProviderConfig is the provider address retrieved from the
+	// state. This is defined here for access within the ProvidedBy method, but
+	// will be set from the embedding instance type when the state is attached.
+	storedProviderConfig addrs.AbsProviderConfig
+
+	// This resource may expand into instances which need to be imported.
+	importTargets []*ImportTarget
+
+	// generateConfigPath tells this node which file to write generated config
+	// into. If empty, then config should not be generated.
+	generateConfigPath string
+}
+
+var (
+	_ GraphNodeReferenceable               = (*NodeAbstractResource)(nil)
+	_ GraphNodeReferencer                  = (*NodeAbstractResource)(nil)
+	_ GraphNodeProviderConsumer            = (*NodeAbstractResource)(nil)
+	_ GraphNodeProvisionerConsumer         = (*NodeAbstractResource)(nil)
+	_ GraphNodeConfigResource              = (*NodeAbstractResource)(nil)
+	_ GraphNodeAttachResourceConfig        = (*NodeAbstractResource)(nil)
+	_ GraphNodeAttachResourceSchema        = (*NodeAbstractResource)(nil)
+	_ GraphNodeAttachProvisionerSchema     = (*NodeAbstractResource)(nil)
+	_ GraphNodeAttachProviderMetaConfigs   = (*NodeAbstractResource)(nil)
+	_ GraphNodeTargetable                  = (*NodeAbstractResource)(nil)
+	_ graphNodeAttachDataResourceDependsOn = (*NodeAbstractResource)(nil)
+	_ dag.GraphNodeDotter                  = (*NodeAbstractResource)(nil)
+)
+
+// NewNodeAbstractResource creates an abstract resource graph node for
+// the given absolute resource address.
+func NewNodeAbstractResource(addr addrs.ConfigResource) *NodeAbstractResource {
+	return &NodeAbstractResource{
+		Addr: addr,
+	}
+}
+
+var (
+	_ GraphNodeModuleInstance            = (*NodeAbstractResourceInstance)(nil)
+	_ GraphNodeReferenceable             = (*NodeAbstractResourceInstance)(nil)
+	_ GraphNodeReferencer                = (*NodeAbstractResourceInstance)(nil)
+	_ GraphNodeProviderConsumer          = (*NodeAbstractResourceInstance)(nil)
+	_ GraphNodeProvisionerConsumer       = (*NodeAbstractResourceInstance)(nil)
+	_ GraphNodeConfigResource            = (*NodeAbstractResourceInstance)(nil)
+	_ GraphNodeResourceInstance          = (*NodeAbstractResourceInstance)(nil)
+	_ GraphNodeAttachResourceState       = (*NodeAbstractResourceInstance)(nil)
+	_ GraphNodeAttachResourceConfig      = (*NodeAbstractResourceInstance)(nil)
+	_ GraphNodeAttachResourceSchema      = (*NodeAbstractResourceInstance)(nil)
+	_ GraphNodeAttachProvisionerSchema   = (*NodeAbstractResourceInstance)(nil)
+	_ GraphNodeAttachProviderMetaConfigs = (*NodeAbstractResourceInstance)(nil)
+	_ GraphNodeTargetable                = (*NodeAbstractResourceInstance)(nil)
+	_ dag.GraphNodeDotter                = (*NodeAbstractResourceInstance)(nil)
+)
+
+func (n *NodeAbstractResource) Name() string {
+	return n.ResourceAddr().String()
+}
+
+// GraphNodeModulePath
+func (n *NodeAbstractResource) ModulePath() addrs.Module {
+	return n.Addr.Module
+}
+
+// GraphNodeReferenceable
+func (n *NodeAbstractResource) ReferenceableAddrs() []addrs.Referenceable {
+	return []addrs.Referenceable{n.Addr.Resource}
+}
+
+// GraphNodeReferencer
+func (n *NodeAbstractResource) References() []*addrs.Reference {
+	// If we have a config then we prefer to use that.
+	if c := n.Config; c != nil {
+		var result []*addrs.Reference
+
+		result = append(result, n.DependsOn()...)
+
+		if n.Schema == nil {
+			// Should never happen, but we'll log if it does so that we can
+			// see this easily when debugging.
+			log.Printf("[WARN] no schema is attached to %s, so config references cannot be detected", n.Name())
+		}
+
+		refs, _ := lang.ReferencesInExpr(c.Count)
+		result = append(result, refs...)
+		refs, _ = lang.ReferencesInExpr(c.ForEach)
+		result = append(result, refs...)
+
+		for _, expr := range c.TriggersReplacement {
+			refs, _ = lang.ReferencesInExpr(expr)
+			result = append(result, refs...)
+		}
+
+		// ReferencesInBlock() requires a schema
+		if n.Schema != nil {
+			refs, _ = lang.ReferencesInBlock(c.Config, n.Schema)
+			result = append(result, refs...)
+		}
+
+		if c.Managed != nil {
+			if c.Managed.Connection != nil {
+				refs, _ = lang.ReferencesInBlock(c.Managed.Connection.Config, connectionBlockSupersetSchema)
+				result = append(result, refs...)
+			}
+
+			for _, p := range c.Managed.Provisioners {
+				if p.When != configs.ProvisionerWhenCreate {
+					continue
+				}
+				if p.Connection != nil {
+					refs, _ = lang.ReferencesInBlock(p.Connection.Config, connectionBlockSupersetSchema)
+					result = append(result, refs...)
+				}
+
+				schema := n.ProvisionerSchemas[p.Type]
+				if schema == nil {
+					log.Printf("[WARN] no schema for provisioner %q is attached to %s, so provisioner block references cannot be detected", p.Type, n.Name())
+				}
+				refs, _ = lang.ReferencesInBlock(p.Config, schema)
+				result = append(result, refs...)
+			}
+		}
+
+		for _, check := range c.Preconditions {
+			refs, _ := lang.ReferencesInExpr(check.Condition)
+			result = append(result, refs...)
+			refs, _ = lang.ReferencesInExpr(check.ErrorMessage)
+			result = append(result, refs...)
+		}
+		for _, check := range c.Postconditions {
+			refs, _ := lang.ReferencesInExpr(check.Condition)
+			result = append(result, refs...)
+			refs, _ = lang.ReferencesInExpr(check.ErrorMessage)
+			result = append(result, refs...)
+		}
+
+		return result
+	}
+
+	// Otherwise, we have no references.
+	return nil
+}
+
+func (n *NodeAbstractResource) DependsOn() []*addrs.Reference {
+	var result []*addrs.Reference
+	if c := n.Config; c != nil {
+
+		for _, traversal := range c.DependsOn {
+			ref, diags := addrs.ParseRef(traversal)
+			if diags.HasErrors() {
+				// We ignore this here, because this isn't a suitable place to return
+				// errors. This situation should be caught and rejected during
+				// validation.
+				log.Printf("[ERROR] Can't parse %#v from depends_on as reference: %s", traversal, diags.Err())
+				continue
+			}
+
+			result = append(result, ref)
+		}
+	}
+	return result
+}
+
+func (n *NodeAbstractResource) SetProvider(p addrs.AbsProviderConfig) {
+	n.ResolvedProvider = p
+}
+
+// GraphNodeProviderConsumer
+func (n *NodeAbstractResource) ProvidedBy() (addrs.ProviderConfig, bool) {
+	// Once the provider is fully resolved, we can return the known value.
+	if n.ResolvedProvider.Provider.Type != "" {
+		return n.ResolvedProvider, true
+	}
+
+	// If we have a config we prefer that above all else
+	if n.Config != nil {
+		relAddr := n.Config.ProviderConfigAddr()
+		return addrs.LocalProviderConfig{
+			LocalName: relAddr.LocalName,
+			Alias:     relAddr.Alias,
+		}, false
+	}
+
+	// See if we have a valid provider config from the state.
+	if n.storedProviderConfig.Provider.Type != "" {
+		// An address from the state must match exactly, since we must ensure
+		// we refresh/destroy a resource with the same provider configuration
+		// that created it.
+		return n.storedProviderConfig, true
+	}
+
+	// We might have an import target that is providing a specific provider,
+	// this is okay as we know there is nothing else potentially providing a
+	// provider configuration.
+	if len(n.importTargets) > 0 {
+		// The import targets should either all be defined via config or none
+		// of them should be. They should also all have the same provider, so it
+		// shouldn't matter which we check here, as they'll all give the same.
+		if n.importTargets[0].Config != nil && n.importTargets[0].Config.ProviderConfigRef != nil {
+			return addrs.LocalProviderConfig{
+				LocalName: n.importTargets[0].Config.ProviderConfigRef.Name,
+				Alias:     n.importTargets[0].Config.ProviderConfigRef.Alias,
+			}, false
+		}
+	}
+
+	// No provider configuration found; return a default address
+	return addrs.AbsProviderConfig{
+		Provider: n.Provider(),
+		Module:   n.ModulePath(),
+	}, false
+}
+
+// GraphNodeProviderConsumer
+func (n *NodeAbstractResource) Provider() addrs.Provider {
+	if n.Config != nil {
+		return n.Config.Provider
+	}
+	if n.storedProviderConfig.Provider.Type != "" {
+		return n.storedProviderConfig.Provider
+	}
+
+	if len(n.importTargets) > 0 {
+		// The import targets should either all be defined via config or none
+		// of them should be. They should also all have the same provider, so it
+		// shouldn't matter which we check here, as they'll all give the same.
+		if n.importTargets[0].Config != nil {
+			return n.importTargets[0].Config.Provider
+		}
+	}
+
+	return addrs.ImpliedProviderForUnqualifiedType(n.Addr.Resource.ImpliedProvider())
+}
+
+// GraphNodeProvisionerConsumer
+func (n *NodeAbstractResource) ProvisionedBy() []string {
+	// If we have no configuration, then we have no provisioners
+	if n.Config == nil || n.Config.Managed == nil {
+		return nil
+	}
+
+	// Build the list of provisioners we need based on the configuration.
+	// It is okay to have duplicates here.
+	result := make([]string, len(n.Config.Managed.Provisioners))
+	for i, p := range n.Config.Managed.Provisioners {
+		result[i] = p.Type
+	}
+
+	return result
+}
+
+// GraphNodeProvisionerConsumer
+func (n *NodeAbstractResource) AttachProvisionerSchema(name string, schema *configschema.Block) {
+	if n.ProvisionerSchemas == nil {
+		n.ProvisionerSchemas = make(map[string]*configschema.Block)
+	}
+	n.ProvisionerSchemas[name] = schema
+}
+
+// GraphNodeResource
+func (n *NodeAbstractResource) ResourceAddr() addrs.ConfigResource {
+	return n.Addr
+}
+
+// GraphNodeTargetable
+func (n *NodeAbstractResource) SetTargets(targets []addrs.Targetable) {
+	n.Targets = targets
+}
+
+// graphNodeAttachDataResourceDependsOn
+func (n *NodeAbstractResource) AttachDataResourceDependsOn(deps []addrs.ConfigResource, force bool) {
+	n.dependsOn = deps
+	n.forceDependsOn = force
+}
+
+// GraphNodeAttachResourceConfig
+func (n *NodeAbstractResource) AttachResourceConfig(c *configs.Resource) {
+	n.Config = c
+}
+
+// GraphNodeAttachResourceSchema impl
+func (n *NodeAbstractResource) AttachResourceSchema(schema *configschema.Block, version uint64) {
+	n.Schema = schema
+	n.SchemaVersion = version
+}
+
+// GraphNodeAttachProviderMetaConfigs impl
+func (n *NodeAbstractResource) AttachProviderMetaConfigs(c map[addrs.Provider]*configs.ProviderMeta) {
+	n.ProviderMetas = c
+}
+
+// GraphNodeDotter impl.
+func (n *NodeAbstractResource) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
+	return &dag.DotNode{
+		Name: name,
+		Attrs: map[string]string{
+			"label": n.Name(),
+			"shape": "box",
+		},
+	}
+}
+
+// writeResourceState ensures that a suitable resource-level state record is
+// present in the state, if that's required for the "each mode" of that
+// resource.
+//
+// This is important primarily for the situation where count = 0, since this
+// eval is the only change we get to set the resource "each mode" to list
+// in that case, allowing expression evaluation to see it as a zero-element list
+// rather than as not set at all.
+func (n *NodeAbstractResource) writeResourceState(ctx EvalContext, addr addrs.AbsResource) (diags tfdiags.Diagnostics) {
+	state := ctx.State()
+
+	// We'll record our expansion decision in the shared "expander" object
+	// so that later operations (i.e. DynamicExpand and expression evaluation)
+	// can refer to it. Since this node represents the abstract module, we need
+	// to expand the module here to create all resources.
+	expander := ctx.InstanceExpander()
+
+	switch {
+	case n.Config != nil && n.Config.Count != nil:
+		count, countDiags := evaluateCountExpression(n.Config.Count, ctx)
+		diags = diags.Append(countDiags)
+		if countDiags.HasErrors() {
+			return diags
+		}
+
+		state.SetResourceProvider(addr, n.ResolvedProvider)
+		expander.SetResourceCount(addr.Module, n.Addr.Resource, count)
+
+	case n.Config != nil && n.Config.ForEach != nil:
+		forEach, forEachDiags := evaluateForEachExpression(n.Config.ForEach, ctx)
+		diags = diags.Append(forEachDiags)
+		if forEachDiags.HasErrors() {
+			return diags
+		}
+
+		// This method takes care of all of the business logic of updating this
+		// while ensuring that any existing instances are preserved, etc.
+		state.SetResourceProvider(addr, n.ResolvedProvider)
+		expander.SetResourceForEach(addr.Module, n.Addr.Resource, forEach)
+
+	default:
+		state.SetResourceProvider(addr, n.ResolvedProvider)
+		expander.SetResourceSingle(addr.Module, n.Addr.Resource)
+	}
+
+	return diags
+}
+
+// readResourceInstanceState reads the current object for a specific instance in
+// the state.
+func (n *NodeAbstractResource) readResourceInstanceState(ctx EvalContext, addr addrs.AbsResourceInstance) (*states.ResourceInstanceObject, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	if err != nil {
+		diags = diags.Append(err)
+		return nil, diags
+	}
+
+	log.Printf("[TRACE] readResourceInstanceState: reading state for %s", addr)
+
+	src := ctx.State().ResourceInstanceObject(addr, states.CurrentGen)
+	if src == nil {
+		// Presumably we only have deposed objects, then.
+		log.Printf("[TRACE] readResourceInstanceState: no state present for %s", addr)
+		return nil, nil
+	}
+
+	schema, currentVersion := (providerSchema).SchemaForResourceAddr(addr.Resource.ContainingResource())
+	if schema == nil {
+		// Shouldn't happen since we should've failed long ago if no schema is present
+		return nil, diags.Append(fmt.Errorf("no schema available for %s while reading state; this is a bug in Terraform and should be reported", addr))
+	}
+	src, upgradeDiags := upgradeResourceState(addr, provider, src, schema, currentVersion)
+	if n.Config != nil {
+		upgradeDiags = upgradeDiags.InConfigBody(n.Config.Config, addr.String())
+	}
+	diags = diags.Append(upgradeDiags)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	obj, err := src.Decode(schema.ImpliedType())
+	if err != nil {
+		diags = diags.Append(err)
+	}
+
+	return obj, diags
+}
+
+// readResourceInstanceStateDeposed reads the deposed object for a specific
+// instance in the state.
+func (n *NodeAbstractResource) readResourceInstanceStateDeposed(ctx EvalContext, addr addrs.AbsResourceInstance, key states.DeposedKey) (*states.ResourceInstanceObject, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	if err != nil {
+		diags = diags.Append(err)
+		return nil, diags
+	}
+
+	if key == states.NotDeposed {
+		return nil, diags.Append(fmt.Errorf("readResourceInstanceStateDeposed used with no instance key; this is a bug in Terraform and should be reported"))
+	}
+
+	log.Printf("[TRACE] readResourceInstanceStateDeposed: reading state for %s deposed object %s", addr, key)
+
+	src := ctx.State().ResourceInstanceObject(addr, key)
+	if src == nil {
+		// Presumably we only have deposed objects, then.
+		log.Printf("[TRACE] readResourceInstanceStateDeposed: no state present for %s deposed object %s", addr, key)
+		return nil, diags
+	}
+
+	schema, currentVersion := (providerSchema).SchemaForResourceAddr(addr.Resource.ContainingResource())
+	if schema == nil {
+		// Shouldn't happen since we should've failed long ago if no schema is present
+		return nil, diags.Append(fmt.Errorf("no schema available for %s while reading state; this is a bug in Terraform and should be reported", addr))
+
+	}
+
+	src, upgradeDiags := upgradeResourceState(addr, provider, src, schema, currentVersion)
+	if n.Config != nil {
+		upgradeDiags = upgradeDiags.InConfigBody(n.Config.Config, addr.String())
+	}
+	diags = diags.Append(upgradeDiags)
+	if diags.HasErrors() {
+		// Note that we don't have any channel to return warnings here. We'll
+		// accept that for now since warnings during a schema upgrade would
+		// be pretty weird anyway, since this operation is supposed to seem
+		// invisible to the user.
+		return nil, diags
+	}
+
+	obj, err := src.Decode(schema.ImpliedType())
+	if err != nil {
+		diags = diags.Append(err)
+	}
+
+	return obj, diags
+}
+
+// graphNodesAreResourceInstancesInDifferentInstancesOfSameModule is an
+// annoyingly-task-specific helper function that returns true if and only if
+// the following conditions hold:
+//   - Both of the given vertices represent specific resource instances, as
+//     opposed to unexpanded resources or any other non-resource-related object.
+//   - The module instance addresses for both of the resource instances belong
+//     to the same static module.
+//   - The module instance addresses for both of the resource instances are
+//     not equal, indicating that they belong to different instances of the
+//     same module.
+//
+// This result can be used as a way to compensate for the effects of
+// conservative analysis passes in our graph builders which make their
+// decisions based only on unexpanded addresses, often so that they can behave
+// correctly for interactions between expanded and not-yet-expanded objects.
+//
+// Callers of this helper function will typically skip adding an edge between
+// the two given nodes if this function returns true.
+func graphNodesAreResourceInstancesInDifferentInstancesOfSameModule(a, b dag.Vertex) bool {
+	aRI, aOK := a.(GraphNodeResourceInstance)
+	bRI, bOK := b.(GraphNodeResourceInstance)
+	if !(aOK && bOK) {
+		return false
+	}
+	aModInst := aRI.ResourceInstanceAddr().Module
+	bModInst := bRI.ResourceInstanceAddr().Module
+	aMod := aModInst.Module()
+	bMod := bModInst.Module()
+	if !aMod.Equal(bMod) {
+		return false
+	}
+	return !aModInst.Equal(bModInst)
+}
diff --git a/v1.5.7/internal/terraform/node_resource_abstract_instance.go b/v1.5.7/internal/terraform/node_resource_abstract_instance.go
new file mode 100644
index 0000000..790efb5
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_abstract_instance.go
@@ -0,0 +1,2539 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/checks"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/objchange"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// NodeAbstractResourceInstance represents a resource instance with no
+// associated operations. It embeds NodeAbstractResource but additionally
+// contains an instance key, used to identify one of potentially many
+// instances that were created from a resource in configuration, e.g. using
+// the "count" or "for_each" arguments.
+type NodeAbstractResourceInstance struct {
+	NodeAbstractResource
+	Addr addrs.AbsResourceInstance
+
+	// These are set via the AttachState method.
+	instanceState *states.ResourceInstance
+
+	Dependencies []addrs.ConfigResource
+
+	preDestroyRefresh bool
+
+	// During import we may generate configuration for a resource, which needs
+	// to be stored in the final change.
+	generatedConfigHCL string
+}
+
+// NewNodeAbstractResourceInstance creates an abstract resource instance graph
+// node for the given absolute resource instance address.
+func NewNodeAbstractResourceInstance(addr addrs.AbsResourceInstance) *NodeAbstractResourceInstance {
+	// Due to the fact that we embed NodeAbstractResource, the given address
+	// actually ends up split between the resource address in the embedded
+	// object and the InstanceKey field in our own struct. The
+	// ResourceInstanceAddr method will stick these back together again on
+	// request.
+	r := NewNodeAbstractResource(addr.ContainingResource().Config())
+	return &NodeAbstractResourceInstance{
+		NodeAbstractResource: *r,
+		Addr:                 addr,
+	}
+}
+
+func (n *NodeAbstractResourceInstance) Name() string {
+	return n.ResourceInstanceAddr().String()
+}
+
+func (n *NodeAbstractResourceInstance) Path() addrs.ModuleInstance {
+	return n.Addr.Module
+}
+
+// GraphNodeReferenceable
+func (n *NodeAbstractResourceInstance) ReferenceableAddrs() []addrs.Referenceable {
+	addr := n.ResourceInstanceAddr()
+	return []addrs.Referenceable{
+		addr.Resource,
+
+		// A resource instance can also be referenced by the address of its
+		// containing resource, so that e.g. a reference to aws_instance.foo
+		// would match both aws_instance.foo[0] and aws_instance.foo[1].
+		addr.ContainingResource().Resource,
+	}
+}
+
+// GraphNodeReferencer
+func (n *NodeAbstractResourceInstance) References() []*addrs.Reference {
+	// If we have a configuration attached then we'll delegate to our
+	// embedded abstract resource, which knows how to extract dependencies
+	// from configuration. If there is no config, then the dependencies will
+	// be connected during destroy from those stored in the state.
+	if n.Config != nil {
+		if n.Schema == nil {
+			// We'll produce a log message about this out here so that
+			// we can include the full instance address, since the equivalent
+			// message in NodeAbstractResource.References cannot see it.
+			log.Printf("[WARN] no schema is attached to %s, so config references cannot be detected", n.Name())
+			return nil
+		}
+		return n.NodeAbstractResource.References()
+	}
+
+	// If we have neither config nor state then we have no references.
+	return nil
+}
+
+// StateDependencies returns the dependencies which will be saved in the state
+// for managed resources, or the most current dependencies for data resources.
+func (n *NodeAbstractResourceInstance) StateDependencies() []addrs.ConfigResource {
+	// Managed resources prefer the stored dependencies, to avoid possible
+	// conflicts in ordering when refactoring configuration.
+	if s := n.instanceState; s != nil {
+		if s.Current != nil {
+			return s.Current.Dependencies
+		}
+	}
+
+	// If there are no stored dependencies, this is either a newly created
+	// managed resource, or a data source, and we can use the most recently
+	// calculated dependencies.
+	return n.Dependencies
+}
+
+// GraphNodeResourceInstance
+func (n *NodeAbstractResourceInstance) ResourceInstanceAddr() addrs.AbsResourceInstance {
+	return n.Addr
+}
+
+// GraphNodeAttachResourceState
+func (n *NodeAbstractResourceInstance) AttachResourceState(s *states.Resource) {
+	if s == nil {
+		log.Printf("[WARN] attaching nil state to %s", n.Addr)
+		return
+	}
+	log.Printf("[TRACE] NodeAbstractResourceInstance.AttachResourceState for %s", n.Addr)
+	n.instanceState = s.Instance(n.Addr.Resource.Key)
+	n.storedProviderConfig = s.ProviderConfig
+}
+
+// readDiff returns the planned change for a particular resource instance
+// object.
+func (n *NodeAbstractResourceInstance) readDiff(ctx EvalContext, providerSchema *ProviderSchema) (*plans.ResourceInstanceChange, error) {
+	changes := ctx.Changes()
+	addr := n.ResourceInstanceAddr()
+
+	schema, _ := providerSchema.SchemaForResourceAddr(addr.Resource.Resource)
+	if schema == nil {
+		// Should be caught during validation, so we don't bother with a pretty error here
+		return nil, fmt.Errorf("provider does not support resource type %q", addr.Resource.Resource.Type)
+	}
+
+	gen := states.CurrentGen
+	csrc := changes.GetResourceInstanceChange(addr, gen)
+	if csrc == nil {
+		log.Printf("[TRACE] readDiff: No planned change recorded for %s", n.Addr)
+		return nil, nil
+	}
+
+	change, err := csrc.Decode(schema.ImpliedType())
+	if err != nil {
+		return nil, fmt.Errorf("failed to decode planned changes for %s: %s", n.Addr, err)
+	}
+
+	log.Printf("[TRACE] readDiff: Read %s change from plan for %s", change.Action, n.Addr)
+
+	return change, nil
+}
+
+func (n *NodeAbstractResourceInstance) checkPreventDestroy(change *plans.ResourceInstanceChange) error {
+	if change == nil || n.Config == nil || n.Config.Managed == nil {
+		return nil
+	}
+
+	preventDestroy := n.Config.Managed.PreventDestroy
+
+	if (change.Action == plans.Delete || change.Action.IsReplace()) && preventDestroy {
+		var diags tfdiags.Diagnostics
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Instance cannot be destroyed",
+			Detail: fmt.Sprintf(
+				"Resource %s has lifecycle.prevent_destroy set, but the plan calls for this resource to be destroyed. To avoid this error and continue with the plan, either disable lifecycle.prevent_destroy or reduce the scope of the plan using the -target flag.",
+				n.Addr.String(),
+			),
+			Subject: &n.Config.DeclRange,
+		})
+		return diags.Err()
+	}
+
+	return nil
+}
+
+// preApplyHook calls the pre-Apply hook
+func (n *NodeAbstractResourceInstance) preApplyHook(ctx EvalContext, change *plans.ResourceInstanceChange) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	if change == nil {
+		panic(fmt.Sprintf("preApplyHook for %s called with nil Change", n.Addr))
+	}
+
+	// Only managed resources have user-visible apply actions.
+	if n.Addr.Resource.Resource.Mode == addrs.ManagedResourceMode {
+		priorState := change.Before
+		plannedNewState := change.After
+
+		diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+			return h.PreApply(n.Addr, change.DeposedKey.Generation(), change.Action, priorState, plannedNewState)
+		}))
+		if diags.HasErrors() {
+			return diags
+		}
+	}
+
+	return nil
+}
+
+// postApplyHook calls the post-Apply hook
+func (n *NodeAbstractResourceInstance) postApplyHook(ctx EvalContext, state *states.ResourceInstanceObject, err error) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	// Only managed resources have user-visible apply actions.
+	if n.Addr.Resource.Resource.Mode == addrs.ManagedResourceMode {
+		var newState cty.Value
+		if state != nil {
+			newState = state.Value
+		} else {
+			newState = cty.NullVal(cty.DynamicPseudoType)
+		}
+		diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+			return h.PostApply(n.Addr, nil, newState, err)
+		}))
+	}
+
+	return diags
+}
+
+type phaseState int
+
+const (
+	workingState phaseState = iota
+	refreshState
+	prevRunState
+)
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type phaseState
+
+// writeResourceInstanceState saves the given object as the current object for
+// the selected resource instance.
+//
+// dependencies is a parameter, instead of those directly attacted to the
+// NodeAbstractResourceInstance, because we don't write dependencies for
+// datasources.
+//
+// targetState determines which context state we're writing to during plan. The
+// default is the global working state.
+func (n *NodeAbstractResourceInstance) writeResourceInstanceState(ctx EvalContext, obj *states.ResourceInstanceObject, targetState phaseState) error {
+	return n.writeResourceInstanceStateImpl(ctx, states.NotDeposed, obj, targetState)
+}
+
+func (n *NodeAbstractResourceInstance) writeResourceInstanceStateDeposed(ctx EvalContext, deposedKey states.DeposedKey, obj *states.ResourceInstanceObject, targetState phaseState) error {
+	if deposedKey == states.NotDeposed {
+		// Bail out to avoid silently doing something other than what the
+		// caller seems to have intended.
+		panic("trying to write current state object using writeResourceInstanceStateDeposed")
+	}
+	return n.writeResourceInstanceStateImpl(ctx, deposedKey, obj, targetState)
+}
+
+// (this is the private common body of both writeResourceInstanceState and
+// writeResourceInstanceStateDeposed. Don't call it directly; instead, use
+// one of the two wrappers to be explicit about which of the instance's
+// objects you are intending to write.
+func (n *NodeAbstractResourceInstance) writeResourceInstanceStateImpl(ctx EvalContext, deposedKey states.DeposedKey, obj *states.ResourceInstanceObject, targetState phaseState) error {
+	absAddr := n.Addr
+	_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	if err != nil {
+		return err
+	}
+	logFuncName := "NodeAbstractResouceInstance.writeResourceInstanceState"
+	if deposedKey == states.NotDeposed {
+		log.Printf("[TRACE] %s to %s for %s", logFuncName, targetState, absAddr)
+	} else {
+		logFuncName = "NodeAbstractResouceInstance.writeResourceInstanceStateDeposed"
+		log.Printf("[TRACE] %s to %s for %s (deposed key %s)", logFuncName, targetState, absAddr, deposedKey)
+	}
+
+	var state *states.SyncState
+	switch targetState {
+	case workingState:
+		state = ctx.State()
+	case refreshState:
+		state = ctx.RefreshState()
+	case prevRunState:
+		state = ctx.PrevRunState()
+	default:
+		panic(fmt.Sprintf("unsupported phaseState value %#v", targetState))
+	}
+	if state == nil {
+		// Should not happen, because we shouldn't ever try to write to
+		// a state that isn't applicable to the current operation.
+		// (We can also get in here for unit tests which are using
+		// EvalContextMock but not populating PrevRunStateState with
+		// a suitable state object.)
+		return fmt.Errorf("state of type %s is not applicable to the current operation; this is a bug in Terraform", targetState)
+	}
+
+	// In spite of the name, this function also handles the non-deposed case
+	// via the writeResourceInstanceState wrapper, by setting deposedKey to
+	// the NotDeposed value (the zero value of DeposedKey).
+	var write func(src *states.ResourceInstanceObjectSrc)
+	if deposedKey == states.NotDeposed {
+		write = func(src *states.ResourceInstanceObjectSrc) {
+			state.SetResourceInstanceCurrent(absAddr, src, n.ResolvedProvider)
+		}
+	} else {
+		write = func(src *states.ResourceInstanceObjectSrc) {
+			state.SetResourceInstanceDeposed(absAddr, deposedKey, src, n.ResolvedProvider)
+		}
+	}
+
+	if obj == nil || obj.Value.IsNull() {
+		// No need to encode anything: we'll just write it directly.
+		write(nil)
+		log.Printf("[TRACE] %s: removing state object for %s", logFuncName, absAddr)
+		return nil
+	}
+
+	if providerSchema == nil {
+		// Should never happen, unless our state object is nil
+		panic("writeResourceInstanceStateImpl used with nil ProviderSchema")
+	}
+
+	if obj != nil {
+		log.Printf("[TRACE] %s: writing state object for %s", logFuncName, absAddr)
+	} else {
+		log.Printf("[TRACE] %s: removing state object for %s", logFuncName, absAddr)
+	}
+
+	schema, currentVersion := (*providerSchema).SchemaForResourceAddr(absAddr.ContainingResource().Resource)
+	if schema == nil {
+		// It shouldn't be possible to get this far in any real scenario
+		// without a schema, but we might end up here in contrived tests that
+		// fail to set up their world properly.
+		return fmt.Errorf("failed to encode %s in state: no resource type schema available", absAddr)
+	}
+
+	src, err := obj.Encode(schema.ImpliedType(), currentVersion)
+	if err != nil {
+		return fmt.Errorf("failed to encode %s in state: %s", absAddr, err)
+	}
+
+	write(src)
+	return nil
+}
+
+// planDestroy returns a plain destroy diff.
+func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState *states.ResourceInstanceObject, deposedKey states.DeposedKey) (*plans.ResourceInstanceChange, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	var plan *plans.ResourceInstanceChange
+
+	absAddr := n.Addr
+
+	if n.ResolvedProvider.Provider.Type == "" {
+		if deposedKey == "" {
+			panic(fmt.Sprintf("planDestroy for %s does not have ProviderAddr set", absAddr))
+		} else {
+			panic(fmt.Sprintf("planDestroy for %s (deposed %s) does not have ProviderAddr set", absAddr, deposedKey))
+		}
+	}
+
+	// If there is no state or our attributes object is null then we're already
+	// destroyed.
+	if currentState == nil || currentState.Value.IsNull() {
+		// We still need to generate a NoOp change, because that allows
+		// outside consumers of the plan to distinguish between us affirming
+		// that we checked something and concluded no changes were needed
+		// vs. that something being entirely excluded e.g. due to -target.
+		noop := &plans.ResourceInstanceChange{
+			Addr:        absAddr,
+			PrevRunAddr: n.prevRunAddr(ctx),
+			DeposedKey:  deposedKey,
+			Change: plans.Change{
+				Action: plans.NoOp,
+				Before: cty.NullVal(cty.DynamicPseudoType),
+				After:  cty.NullVal(cty.DynamicPseudoType),
+			},
+			ProviderAddr: n.ResolvedProvider,
+		}
+		return noop, nil
+	}
+
+	unmarkedPriorVal, _ := currentState.Value.UnmarkDeep()
+
+	// The config and new value are null to signify that this is a destroy
+	// operation.
+	nullVal := cty.NullVal(unmarkedPriorVal.Type())
+
+	provider, _, err := getProvider(ctx, n.ResolvedProvider)
+	if err != nil {
+		return plan, diags.Append(err)
+	}
+
+	metaConfigVal, metaDiags := n.providerMetas(ctx)
+	diags = diags.Append(metaDiags)
+	if diags.HasErrors() {
+		return plan, diags
+	}
+
+	// Allow the provider to check the destroy plan, and insert any necessary
+	// private data.
+	resp := provider.PlanResourceChange(providers.PlanResourceChangeRequest{
+		TypeName:         n.Addr.Resource.Resource.Type,
+		Config:           nullVal,
+		PriorState:       unmarkedPriorVal,
+		ProposedNewState: nullVal,
+		PriorPrivate:     currentState.Private,
+		ProviderMeta:     metaConfigVal,
+	})
+
+	// We may not have a config for all destroys, but we want to reference it in
+	// the diagnostics if we do.
+	if n.Config != nil {
+		resp.Diagnostics = resp.Diagnostics.InConfigBody(n.Config.Config, n.Addr.String())
+	}
+	diags = diags.Append(resp.Diagnostics)
+	if diags.HasErrors() {
+		return plan, diags
+	}
+
+	// Check that the provider returned a null value here, since that is the
+	// only valid value for a destroy plan.
+	if !resp.PlannedState.IsNull() {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Provider produced invalid plan",
+			fmt.Sprintf(
+				"Provider %q planned a non-null destroy value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
+				n.ResolvedProvider.Provider, n.Addr),
+		),
+		)
+		return plan, diags
+	}
+
+	// Plan is always the same for a destroy.
+	plan = &plans.ResourceInstanceChange{
+		Addr:        absAddr,
+		PrevRunAddr: n.prevRunAddr(ctx),
+		DeposedKey:  deposedKey,
+		Change: plans.Change{
+			Action: plans.Delete,
+			Before: currentState.Value,
+			After:  nullVal,
+		},
+		Private:      resp.PlannedPrivate,
+		ProviderAddr: n.ResolvedProvider,
+	}
+
+	return plan, diags
+}
+
+// writeChange saves a planned change for an instance object into the set of
+// global planned changes.
+func (n *NodeAbstractResourceInstance) writeChange(ctx EvalContext, change *plans.ResourceInstanceChange, deposedKey states.DeposedKey) error {
+	changes := ctx.Changes()
+
+	if change == nil {
+		// Caller sets nil to indicate that we need to remove a change from
+		// the set of changes.
+		gen := states.CurrentGen
+		if deposedKey != states.NotDeposed {
+			gen = deposedKey
+		}
+		changes.RemoveResourceInstanceChange(n.Addr, gen)
+		return nil
+	}
+
+	_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	if err != nil {
+		return err
+	}
+
+	if change.Addr.String() != n.Addr.String() || change.DeposedKey != deposedKey {
+		// Should never happen, and indicates a bug in the caller.
+		panic("inconsistent address and/or deposed key in writeChange")
+	}
+	if change.PrevRunAddr.Resource.Resource.Type == "" {
+		// Should never happen, and indicates a bug in the caller.
+		// (The change.Encode function actually has its own fixup to just
+		// quietly make this match change.Addr in the incorrect case, but we
+		// intentionally panic here in order to catch incorrect callers where
+		// the stack trace will hopefully be actually useful. The tolerance
+		// at the next layer down is mainly to accommodate sloppy input in
+		// older tests.)
+		panic("unpopulated ResourceInstanceChange.PrevRunAddr in writeChange")
+	}
+
+	ri := n.Addr.Resource
+	schema, _ := providerSchema.SchemaForResourceAddr(ri.Resource)
+	if schema == nil {
+		// Should be caught during validation, so we don't bother with a pretty error here
+		return fmt.Errorf("provider does not support resource type %q", ri.Resource.Type)
+	}
+
+	csrc, err := change.Encode(schema.ImpliedType())
+	if err != nil {
+		return fmt.Errorf("failed to encode planned changes for %s: %s", n.Addr, err)
+	}
+
+	changes.AppendResourceInstanceChange(csrc)
+	if deposedKey == states.NotDeposed {
+		log.Printf("[TRACE] writeChange: recorded %s change for %s", change.Action, n.Addr)
+	} else {
+		log.Printf("[TRACE] writeChange: recorded %s change for %s deposed object %s", change.Action, n.Addr, deposedKey)
+	}
+
+	return nil
+}
+
+// refresh does a refresh for a resource
+func (n *NodeAbstractResourceInstance) refresh(ctx EvalContext, deposedKey states.DeposedKey, state *states.ResourceInstanceObject) (*states.ResourceInstanceObject, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	absAddr := n.Addr
+	if deposedKey == states.NotDeposed {
+		log.Printf("[TRACE] NodeAbstractResourceInstance.refresh for %s", absAddr)
+	} else {
+		log.Printf("[TRACE] NodeAbstractResourceInstance.refresh for %s (deposed object %s)", absAddr, deposedKey)
+	}
+	provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	if err != nil {
+		return state, diags.Append(err)
+	}
+	// If we have no state, we don't do any refreshing
+	if state == nil {
+		log.Printf("[DEBUG] refresh: %s: no state, so not refreshing", absAddr)
+		return state, diags
+	}
+
+	schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.Resource.ContainingResource())
+	if schema == nil {
+		// Should be caught during validation, so we don't bother with a pretty error here
+		diags = diags.Append(fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Resource.Type))
+		return state, diags
+	}
+
+	metaConfigVal, metaDiags := n.providerMetas(ctx)
+	diags = diags.Append(metaDiags)
+	if diags.HasErrors() {
+		return state, diags
+	}
+
+	hookGen := states.CurrentGen
+	if deposedKey != states.NotDeposed {
+		hookGen = deposedKey
+	}
+
+	// Call pre-refresh hook
+	diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+		return h.PreRefresh(absAddr, hookGen, state.Value)
+	}))
+	if diags.HasErrors() {
+		return state, diags
+	}
+
+	// Refresh!
+	priorVal := state.Value
+
+	// Unmarked before sending to provider
+	var priorPaths []cty.PathValueMarks
+	if priorVal.ContainsMarked() {
+		priorVal, priorPaths = priorVal.UnmarkDeepWithPaths()
+	}
+
+	providerReq := providers.ReadResourceRequest{
+		TypeName:     n.Addr.Resource.Resource.Type,
+		PriorState:   priorVal,
+		Private:      state.Private,
+		ProviderMeta: metaConfigVal,
+	}
+
+	resp := provider.ReadResource(providerReq)
+	if n.Config != nil {
+		resp.Diagnostics = resp.Diagnostics.InConfigBody(n.Config.Config, n.Addr.String())
+	}
+
+	diags = diags.Append(resp.Diagnostics)
+	if diags.HasErrors() {
+		return state, diags
+	}
+
+	if resp.NewState == cty.NilVal {
+		// This ought not to happen in real cases since it's not possible to
+		// send NilVal over the plugin RPC channel, but it can come up in
+		// tests due to sloppy mocking.
+		panic("new state is cty.NilVal")
+	}
+
+	for _, err := range resp.NewState.Type().TestConformance(schema.ImpliedType()) {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Provider produced invalid object",
+			fmt.Sprintf(
+				"Provider %q planned an invalid value for %s during refresh: %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
+				n.ResolvedProvider.Provider.String(), absAddr, tfdiags.FormatError(err),
+			),
+		))
+	}
+	if diags.HasErrors() {
+		return state, diags
+	}
+
+	newState := objchange.NormalizeObjectFromLegacySDK(resp.NewState, schema)
+	if !newState.RawEquals(resp.NewState) {
+		// We had to fix up this object in some way, and we still need to
+		// accept any changes for compatibility, so all we can do is log a
+		// warning about the change.
+		log.Printf("[WARN] Provider %q produced an invalid new value containing null blocks for %q during refresh\n", n.ResolvedProvider.Provider, n.Addr)
+	}
+
+	ret := state.DeepCopy()
+	ret.Value = newState
+	ret.Private = resp.Private
+
+	// We have no way to exempt provider using the legacy SDK from this check,
+	// so we can only log inconsistencies with the updated state values.
+	// In most cases these are not errors anyway, and represent "drift" from
+	// external changes which will be handled by the subsequent plan.
+	if errs := objchange.AssertObjectCompatible(schema, priorVal, ret.Value); len(errs) > 0 {
+		var buf strings.Builder
+		fmt.Fprintf(&buf, "[WARN] Provider %q produced an unexpected new value for %s during refresh.", n.ResolvedProvider.Provider.String(), absAddr)
+		for _, err := range errs {
+			fmt.Fprintf(&buf, "\n      - %s", tfdiags.FormatError(err))
+		}
+		log.Print(buf.String())
+	}
+
+	// Call post-refresh hook
+	diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+		return h.PostRefresh(absAddr, hookGen, priorVal, ret.Value)
+	}))
+	if diags.HasErrors() {
+		return ret, diags
+	}
+
+	// Mark the value if necessary
+	if len(priorPaths) > 0 {
+		ret.Value = ret.Value.MarkWithPaths(priorPaths)
+	}
+
+	return ret, diags
+}
+
+func (n *NodeAbstractResourceInstance) plan(
+	ctx EvalContext,
+	plannedChange *plans.ResourceInstanceChange,
+	currentState *states.ResourceInstanceObject,
+	createBeforeDestroy bool,
+	forceReplace []addrs.AbsResourceInstance,
+) (*plans.ResourceInstanceChange, *states.ResourceInstanceObject, instances.RepetitionData, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	var keyData instances.RepetitionData
+
+	resource := n.Addr.Resource.Resource
+	provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	if err != nil {
+		return nil, nil, keyData, diags.Append(err)
+	}
+
+	if providerSchema == nil {
+		diags = diags.Append(fmt.Errorf("provider schema is unavailable for %s", n.Addr))
+		return nil, nil, keyData, diags
+	}
+	schema, _ := providerSchema.SchemaForResourceAddr(resource)
+	if schema == nil {
+		// Should be caught during validation, so we don't bother with a pretty error here
+		diags = diags.Append(fmt.Errorf("provider does not support resource type %q", resource.Type))
+		return nil, nil, keyData, diags
+	}
+
+	// If we're importing and generating config, generate it now.
+	if n.Config == nil {
+		// This shouldn't happen. A node that isn't generating config should
+		// have embedded config, and the rest of Terraform should enforce this.
+		// If, however, we didn't do things correctly the next line will panic,
+		// so let's not do that and return an error message with more context.
+
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Resource has no configuration",
+			fmt.Sprintf("Terraform attempted to process a resource at %s that has no configuration. This is a bug in Terraform; please report it!", n.Addr.String())))
+		return nil, nil, keyData, diags
+	}
+
+	config := *n.Config
+
+	checkRuleSeverity := tfdiags.Error
+	if n.preDestroyRefresh {
+		checkRuleSeverity = tfdiags.Warning
+	}
+
+	if plannedChange != nil {
+		// If we already planned the action, we stick to that plan
+		createBeforeDestroy = plannedChange.Action == plans.CreateThenDelete
+	}
+
+	// Evaluate the configuration
+	forEach, _ := evaluateForEachExpression(n.Config.ForEach, ctx)
+
+	keyData = EvalDataForInstanceKey(n.ResourceInstanceAddr().Resource.Key, forEach)
+
+	checkDiags := evalCheckRules(
+		addrs.ResourcePrecondition,
+		n.Config.Preconditions,
+		ctx, n.Addr, keyData,
+		checkRuleSeverity,
+	)
+	diags = diags.Append(checkDiags)
+	if diags.HasErrors() {
+		return nil, nil, keyData, diags // failed preconditions prevent further evaluation
+	}
+
+	// If we have a previous plan and the action was a noop, then the only
+	// reason we're in this method was to evaluate the preconditions. There's
+	// no need to re-plan this resource.
+	if plannedChange != nil && plannedChange.Action == plans.NoOp {
+		return plannedChange, currentState.DeepCopy(), keyData, diags
+	}
+
+	origConfigVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, nil, keyData)
+	diags = diags.Append(configDiags)
+	if configDiags.HasErrors() {
+		return nil, nil, keyData, diags
+	}
+
+	metaConfigVal, metaDiags := n.providerMetas(ctx)
+	diags = diags.Append(metaDiags)
+	if diags.HasErrors() {
+		return nil, nil, keyData, diags
+	}
+
+	var priorVal cty.Value
+	var priorValTainted cty.Value
+	var priorPrivate []byte
+	if currentState != nil {
+		if currentState.Status != states.ObjectTainted {
+			priorVal = currentState.Value
+			priorPrivate = currentState.Private
+		} else {
+			// If the prior state is tainted then we'll proceed below like
+			// we're creating an entirely new object, but then turn it into
+			// a synthetic "Replace" change at the end, creating the same
+			// result as if the provider had marked at least one argument
+			// change as "requires replacement".
+			priorValTainted = currentState.Value
+			priorVal = cty.NullVal(schema.ImpliedType())
+		}
+	} else {
+		priorVal = cty.NullVal(schema.ImpliedType())
+	}
+
+	log.Printf("[TRACE] Re-validating config for %q", n.Addr)
+	// Allow the provider to validate the final set of values.  The config was
+	// statically validated early on, but there may have been unknown values
+	// which the provider could not validate at the time.
+	//
+	// TODO: It would be more correct to validate the config after
+	// ignore_changes has been applied, but the current implementation cannot
+	// exclude computed-only attributes when given the `all` option.
+
+	// we must unmark and use the original config, since the ignore_changes
+	// handling below needs access to the marks.
+	unmarkedConfigVal, _ := origConfigVal.UnmarkDeep()
+	validateResp := provider.ValidateResourceConfig(
+		providers.ValidateResourceConfigRequest{
+			TypeName: n.Addr.Resource.Resource.Type,
+			Config:   unmarkedConfigVal,
+		},
+	)
+	diags = diags.Append(validateResp.Diagnostics.InConfigBody(config.Config, n.Addr.String()))
+	if diags.HasErrors() {
+		return nil, nil, keyData, diags
+	}
+
+	// ignore_changes is meant to only apply to the configuration, so it must
+	// be applied before we generate a plan. This ensures the config used for
+	// the proposed value, the proposed value itself, and the config presented
+	// to the provider in the PlanResourceChange request all agree on the
+	// starting values.
+	// Here we operate on the marked values, so as to revert any changes to the
+	// marks as well as the value.
+	configValIgnored, ignoreChangeDiags := n.processIgnoreChanges(priorVal, origConfigVal, schema)
+	diags = diags.Append(ignoreChangeDiags)
+	if ignoreChangeDiags.HasErrors() {
+		return nil, nil, keyData, diags
+	}
+
+	// Create an unmarked version of our config val and our prior val.
+	// Store the paths for the config val to re-mark after we've sent things
+	// over the wire.
+	unmarkedConfigVal, unmarkedPaths := configValIgnored.UnmarkDeepWithPaths()
+	unmarkedPriorVal, priorPaths := priorVal.UnmarkDeepWithPaths()
+
+	proposedNewVal := objchange.ProposedNew(schema, unmarkedPriorVal, unmarkedConfigVal)
+
+	// Call pre-diff hook
+	diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+		return h.PreDiff(n.Addr, states.CurrentGen, priorVal, proposedNewVal)
+	}))
+	if diags.HasErrors() {
+		return nil, nil, keyData, diags
+	}
+
+	resp := provider.PlanResourceChange(providers.PlanResourceChangeRequest{
+		TypeName:         n.Addr.Resource.Resource.Type,
+		Config:           unmarkedConfigVal,
+		PriorState:       unmarkedPriorVal,
+		ProposedNewState: proposedNewVal,
+		PriorPrivate:     priorPrivate,
+		ProviderMeta:     metaConfigVal,
+	})
+	diags = diags.Append(resp.Diagnostics.InConfigBody(config.Config, n.Addr.String()))
+	if diags.HasErrors() {
+		return nil, nil, keyData, diags
+	}
+
+	plannedNewVal := resp.PlannedState
+	plannedPrivate := resp.PlannedPrivate
+
+	if plannedNewVal == cty.NilVal {
+		// Should never happen. Since real-world providers return via RPC a nil
+		// is always a bug in the client-side stub. This is more likely caused
+		// by an incompletely-configured mock provider in tests, though.
+		panic(fmt.Sprintf("PlanResourceChange of %s produced nil value", n.Addr))
+	}
+
+	// We allow the planned new value to disagree with configuration _values_
+	// here, since that allows the provider to do special logic like a
+	// DiffSuppressFunc, but we still require that the provider produces
+	// a value whose type conforms to the schema.
+	for _, err := range plannedNewVal.Type().TestConformance(schema.ImpliedType()) {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Provider produced invalid plan",
+			fmt.Sprintf(
+				"Provider %q planned an invalid value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
+				n.ResolvedProvider.Provider, tfdiags.FormatErrorPrefixed(err, n.Addr.String()),
+			),
+		))
+	}
+	if diags.HasErrors() {
+		return nil, nil, keyData, diags
+	}
+
+	if errs := objchange.AssertPlanValid(schema, unmarkedPriorVal, unmarkedConfigVal, plannedNewVal); len(errs) > 0 {
+		if resp.LegacyTypeSystem {
+			// The shimming of the old type system in the legacy SDK is not precise
+			// enough to pass this consistency check, so we'll give it a pass here,
+			// but we will generate a warning about it so that we are more likely
+			// to notice in the logs if an inconsistency beyond the type system
+			// leads to a downstream provider failure.
+			var buf strings.Builder
+			fmt.Fprintf(&buf,
+				"[WARN] Provider %q produced an invalid plan for %s, but we are tolerating it because it is using the legacy plugin SDK.\n    The following problems may be the cause of any confusing errors from downstream operations:",
+				n.ResolvedProvider.Provider, n.Addr,
+			)
+			for _, err := range errs {
+				fmt.Fprintf(&buf, "\n      - %s", tfdiags.FormatError(err))
+			}
+			log.Print(buf.String())
+		} else {
+			for _, err := range errs {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Provider produced invalid plan",
+					fmt.Sprintf(
+						"Provider %q planned an invalid value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
+						n.ResolvedProvider.Provider, tfdiags.FormatErrorPrefixed(err, n.Addr.String()),
+					),
+				))
+			}
+			return nil, nil, keyData, diags
+		}
+	}
+
+	if resp.LegacyTypeSystem {
+		// Because we allow legacy providers to depart from the contract and
+		// return changes to non-computed values, the plan response may have
+		// altered values that were already suppressed with ignore_changes.
+		// A prime example of this is where providers attempt to obfuscate
+		// config data by turning the config value into a hash and storing the
+		// hash value in the state. There are enough cases of this in existing
+		// providers that we must accommodate the behavior for now, so for
+		// ignore_changes to work at all on these values, we will revert the
+		// ignored values once more.
+		// A nil schema is passed to processIgnoreChanges to indicate that we
+		// don't want to fixup a config value according to the schema when
+		// ignoring "all", rather we are reverting provider imposed changes.
+		plannedNewVal, ignoreChangeDiags = n.processIgnoreChanges(unmarkedPriorVal, plannedNewVal, nil)
+		diags = diags.Append(ignoreChangeDiags)
+		if ignoreChangeDiags.HasErrors() {
+			return nil, nil, keyData, diags
+		}
+	}
+
+	// Add the marks back to the planned new value -- this must happen after ignore changes
+	// have been processed
+	unmarkedPlannedNewVal := plannedNewVal
+	if len(unmarkedPaths) > 0 {
+		plannedNewVal = plannedNewVal.MarkWithPaths(unmarkedPaths)
+	}
+
+	// The provider produces a list of paths to attributes whose changes mean
+	// that we must replace rather than update an existing remote object.
+	// However, we only need to do that if the identified attributes _have_
+	// actually changed -- particularly after we may have undone some of the
+	// changes in processIgnoreChanges -- so now we'll filter that list to
+	// include only where changes are detected.
+	reqRep := cty.NewPathSet()
+	if len(resp.RequiresReplace) > 0 {
+		for _, path := range resp.RequiresReplace {
+			if priorVal.IsNull() {
+				// If prior is null then we don't expect any RequiresReplace at all,
+				// because this is a Create action.
+				continue
+			}
+
+			priorChangedVal, priorPathDiags := hcl.ApplyPath(unmarkedPriorVal, path, nil)
+			plannedChangedVal, plannedPathDiags := hcl.ApplyPath(plannedNewVal, path, nil)
+			if plannedPathDiags.HasErrors() && priorPathDiags.HasErrors() {
+				// This means the path was invalid in both the prior and new
+				// values, which is an error with the provider itself.
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Provider produced invalid plan",
+					fmt.Sprintf(
+						"Provider %q has indicated \"requires replacement\" on %s for a non-existent attribute path %#v.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
+						n.ResolvedProvider.Provider, n.Addr, path,
+					),
+				))
+				continue
+			}
+
+			// Make sure we have valid Values for both values.
+			// Note: if the opposing value was of the type
+			// cty.DynamicPseudoType, the type assigned here may not exactly
+			// match the schema. This is fine here, since we're only going to
+			// check for equality, but if the NullVal is to be used, we need to
+			// check the schema for th true type.
+			switch {
+			case priorChangedVal == cty.NilVal && plannedChangedVal == cty.NilVal:
+				// this should never happen without ApplyPath errors above
+				panic("requires replace path returned 2 nil values")
+			case priorChangedVal == cty.NilVal:
+				priorChangedVal = cty.NullVal(plannedChangedVal.Type())
+			case plannedChangedVal == cty.NilVal:
+				plannedChangedVal = cty.NullVal(priorChangedVal.Type())
+			}
+
+			// Unmark for this value for the equality test. If only sensitivity has changed,
+			// this does not require an Update or Replace
+			unmarkedPlannedChangedVal, _ := plannedChangedVal.UnmarkDeep()
+			eqV := unmarkedPlannedChangedVal.Equals(priorChangedVal)
+			if !eqV.IsKnown() || eqV.False() {
+				reqRep.Add(path)
+			}
+		}
+		if diags.HasErrors() {
+			return nil, nil, keyData, diags
+		}
+	}
+
+	// The user might also ask us to force replacing a particular resource
+	// instance, regardless of whether the provider thinks it needs replacing.
+	// For example, users typically do this if they learn a particular object
+	// has become degraded in an immutable infrastructure scenario and so
+	// replacing it with a new object is a viable repair path.
+	matchedForceReplace := false
+	for _, candidateAddr := range forceReplace {
+		if candidateAddr.Equal(n.Addr) {
+			matchedForceReplace = true
+			break
+		}
+
+		// For "force replace" purposes we require an exact resource instance
+		// address to match. If a user forgets to include the instance key
+		// for a multi-instance resource then it won't match here, but we
+		// have an earlier check in NodePlannableResource.Execute that should
+		// prevent us from getting here in that case.
+	}
+
+	// Unmark for this test for value equality.
+	eqV := unmarkedPlannedNewVal.Equals(unmarkedPriorVal)
+	eq := eqV.IsKnown() && eqV.True()
+
+	var action plans.Action
+	var actionReason plans.ResourceInstanceChangeActionReason
+	switch {
+	case priorVal.IsNull():
+		action = plans.Create
+	case eq && !matchedForceReplace:
+		action = plans.NoOp
+	case matchedForceReplace || !reqRep.Empty():
+		// If the user "forced replace" of this instance of if there are any
+		// "requires replace" paths left _after our filtering above_ then this
+		// is a replace action.
+		if createBeforeDestroy {
+			action = plans.CreateThenDelete
+		} else {
+			action = plans.DeleteThenCreate
+		}
+		switch {
+		case matchedForceReplace:
+			actionReason = plans.ResourceInstanceReplaceByRequest
+		case !reqRep.Empty():
+			actionReason = plans.ResourceInstanceReplaceBecauseCannotUpdate
+		}
+	default:
+		action = plans.Update
+		// "Delete" is never chosen here, because deletion plans are always
+		// created more directly elsewhere, such as in "orphan" handling.
+	}
+
+	if action.IsReplace() {
+		// In this strange situation we want to produce a change object that
+		// shows our real prior object but has a _new_ object that is built
+		// from a null prior object, since we're going to delete the one
+		// that has all the computed values on it.
+		//
+		// Therefore we'll ask the provider to plan again here, giving it
+		// a null object for the prior, and then we'll meld that with the
+		// _actual_ prior state to produce a correctly-shaped replace change.
+		// The resulting change should show any computed attributes changing
+		// from known prior values to unknown values, unless the provider is
+		// able to predict new values for any of these computed attributes.
+		nullPriorVal := cty.NullVal(schema.ImpliedType())
+
+		// Since there is no prior state to compare after replacement, we need
+		// a new unmarked config from our original with no ignored values.
+		unmarkedConfigVal := origConfigVal
+		if origConfigVal.ContainsMarked() {
+			unmarkedConfigVal, _ = origConfigVal.UnmarkDeep()
+		}
+
+		// create a new proposed value from the null state and the config
+		proposedNewVal = objchange.ProposedNew(schema, nullPriorVal, unmarkedConfigVal)
+
+		resp = provider.PlanResourceChange(providers.PlanResourceChangeRequest{
+			TypeName:         n.Addr.Resource.Resource.Type,
+			Config:           unmarkedConfigVal,
+			PriorState:       nullPriorVal,
+			ProposedNewState: proposedNewVal,
+			PriorPrivate:     plannedPrivate,
+			ProviderMeta:     metaConfigVal,
+		})
+		// We need to tread carefully here, since if there are any warnings
+		// in here they probably also came out of our previous call to
+		// PlanResourceChange above, and so we don't want to repeat them.
+		// Consequently, we break from the usual pattern here and only
+		// append these new diagnostics if there's at least one error inside.
+		if resp.Diagnostics.HasErrors() {
+			diags = diags.Append(resp.Diagnostics.InConfigBody(config.Config, n.Addr.String()))
+			return nil, nil, keyData, diags
+		}
+		plannedNewVal = resp.PlannedState
+		plannedPrivate = resp.PlannedPrivate
+
+		if len(unmarkedPaths) > 0 {
+			plannedNewVal = plannedNewVal.MarkWithPaths(unmarkedPaths)
+		}
+
+		for _, err := range plannedNewVal.Type().TestConformance(schema.ImpliedType()) {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Provider produced invalid plan",
+				fmt.Sprintf(
+					"Provider %q planned an invalid value for %s%s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
+					n.ResolvedProvider.Provider, n.Addr, tfdiags.FormatError(err),
+				),
+			))
+		}
+		if diags.HasErrors() {
+			return nil, nil, keyData, diags
+		}
+	}
+
+	// If our prior value was tainted then we actually want this to appear
+	// as a replace change, even though so far we've been treating it as a
+	// create.
+	if action == plans.Create && !priorValTainted.IsNull() {
+		if createBeforeDestroy {
+			action = plans.CreateThenDelete
+		} else {
+			action = plans.DeleteThenCreate
+		}
+		priorVal = priorValTainted
+		actionReason = plans.ResourceInstanceReplaceBecauseTainted
+	}
+
+	// If we plan to write or delete sensitive paths from state,
+	// this is an Update action.
+	//
+	// We need to filter out any marks which may not apply to the new planned
+	// value before comparison. The one case where a provider is allowed to
+	// return a different value from the configuration is when a config change
+	// is not functionally significant and the prior state can be returned. If a
+	// new mark was also discarded from that config change, it needs to be
+	// ignored here to prevent an errant update action.
+	if action == plans.NoOp && !marksEqual(filterMarks(plannedNewVal, unmarkedPaths), priorPaths) {
+		action = plans.Update
+	}
+
+	// As a special case, if we have a previous diff (presumably from the plan
+	// phases, whereas we're now in the apply phase) and it was for a replace,
+	// we've already deleted the original object from state by the time we
+	// get here and so we would've ended up with a _create_ action this time,
+	// which we now need to paper over to get a result consistent with what
+	// we originally intended.
+	if plannedChange != nil {
+		prevChange := *plannedChange
+		if prevChange.Action.IsReplace() && action == plans.Create {
+			log.Printf("[TRACE] plan: %s treating Create change as %s change to match with earlier plan", n.Addr, prevChange.Action)
+			action = prevChange.Action
+			priorVal = prevChange.Before
+		}
+	}
+
+	// Call post-refresh hook
+	diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+		return h.PostDiff(n.Addr, states.CurrentGen, action, priorVal, plannedNewVal)
+	}))
+	if diags.HasErrors() {
+		return nil, nil, keyData, diags
+	}
+
+	// Update our return plan
+	plan := &plans.ResourceInstanceChange{
+		Addr:         n.Addr,
+		PrevRunAddr:  n.prevRunAddr(ctx),
+		Private:      plannedPrivate,
+		ProviderAddr: n.ResolvedProvider,
+		Change: plans.Change{
+			Action: action,
+			Before: priorVal,
+			// Pass the marked planned value through in our change
+			// to propogate through evaluation.
+			// Marks will be removed when encoding.
+			After:           plannedNewVal,
+			GeneratedConfig: n.generatedConfigHCL,
+		},
+		ActionReason:    actionReason,
+		RequiredReplace: reqRep,
+	}
+
+	// Update our return state
+	state := &states.ResourceInstanceObject{
+		// We use the special "planned" status here to note that this
+		// object's value is not yet complete. Objects with this status
+		// cannot be used during expression evaluation, so the caller
+		// must _also_ record the returned change in the active plan,
+		// which the expression evaluator will use in preference to this
+		// incomplete value recorded in the state.
+		Status:  states.ObjectPlanned,
+		Value:   plannedNewVal,
+		Private: plannedPrivate,
+	}
+
+	return plan, state, keyData, diags
+}
+
+func (n *NodeAbstractResource) processIgnoreChanges(prior, config cty.Value, schema *configschema.Block) (cty.Value, tfdiags.Diagnostics) {
+	// ignore_changes only applies when an object already exists, since we
+	// can't ignore changes to a thing we've not created yet.
+	if prior.IsNull() {
+		return config, nil
+	}
+
+	ignoreChanges := traversalsToPaths(n.Config.Managed.IgnoreChanges)
+	ignoreAll := n.Config.Managed.IgnoreAllChanges
+
+	if len(ignoreChanges) == 0 && !ignoreAll {
+		return config, nil
+	}
+
+	if ignoreAll {
+		// Legacy providers need up to clean up their invalid plans and ensure
+		// no changes are passed though, but that also means making an invalid
+		// config with computed values. In that case we just don't supply a
+		// schema and return the prior val directly.
+		if schema == nil {
+			return prior, nil
+		}
+
+		// If we are trying to ignore all attribute changes, we must filter
+		// computed attributes out from the prior state to avoid sending them
+		// to the provider as if they were included in the configuration.
+		ret, _ := cty.Transform(prior, func(path cty.Path, v cty.Value) (cty.Value, error) {
+			attr := schema.AttributeByPath(path)
+			if attr != nil && attr.Computed && !attr.Optional {
+				return cty.NullVal(v.Type()), nil
+			}
+
+			return v, nil
+		})
+
+		return ret, nil
+	}
+
+	if prior.IsNull() || config.IsNull() {
+		// Ignore changes doesn't apply when we're creating for the first time.
+		// Proposed should never be null here, but if it is then we'll just let it be.
+		return config, nil
+	}
+
+	ret, diags := processIgnoreChangesIndividual(prior, config, ignoreChanges)
+
+	return ret, diags
+}
+
+// Convert the hcl.Traversal values we get form the configuration to the
+// cty.Path values we need to operate on the cty.Values
+func traversalsToPaths(traversals []hcl.Traversal) []cty.Path {
+	paths := make([]cty.Path, len(traversals))
+	for i, traversal := range traversals {
+		path := traversalToPath(traversal)
+		paths[i] = path
+	}
+	return paths
+}
+
+func traversalToPath(traversal hcl.Traversal) cty.Path {
+	path := make(cty.Path, len(traversal))
+	for si, step := range traversal {
+		switch ts := step.(type) {
+		case hcl.TraverseRoot:
+			path[si] = cty.GetAttrStep{
+				Name: ts.Name,
+			}
+		case hcl.TraverseAttr:
+			path[si] = cty.GetAttrStep{
+				Name: ts.Name,
+			}
+		case hcl.TraverseIndex:
+			path[si] = cty.IndexStep{
+				Key: ts.Key,
+			}
+		default:
+			panic(fmt.Sprintf("unsupported traversal step %#v", step))
+		}
+	}
+	return path
+}
+
+func processIgnoreChangesIndividual(prior, config cty.Value, ignoreChangesPath []cty.Path) (cty.Value, tfdiags.Diagnostics) {
+	type ignoreChange struct {
+		// Path is the full path, minus any trailing map index
+		path cty.Path
+		// Value is the value we are to retain at the above path. If there is a
+		// key value, this must be a map and the desired value will be at the
+		// key index.
+		value cty.Value
+		// Key is the index key if the ignored path ends in a map index.
+		key cty.Value
+	}
+	var ignoredValues []ignoreChange
+
+	// Find the actual changes first and store them in the ignoreChange struct.
+	// If the change was to a map value, and the key doesn't exist in the
+	// config, it would never be visited in the transform walk.
+	for _, icPath := range ignoreChangesPath {
+		key := cty.NullVal(cty.String)
+		// check for a map index, since maps are the only structure where we
+		// could have invalid path steps.
+		last, ok := icPath[len(icPath)-1].(cty.IndexStep)
+		if ok {
+			if last.Key.Type() == cty.String {
+				icPath = icPath[:len(icPath)-1]
+				key = last.Key
+			}
+		}
+
+		// The structure should have been validated already, and we already
+		// trimmed the trailing map index. Any other intermediate index error
+		// means we wouldn't be able to apply the value below, so no need to
+		// record this.
+		p, err := icPath.Apply(prior)
+		if err != nil {
+			continue
+		}
+		c, err := icPath.Apply(config)
+		if err != nil {
+			continue
+		}
+
+		// If this is a map, it is checking the entire map value for equality
+		// rather than the individual key. This means that the change is stored
+		// here even if our ignored key doesn't change. That is OK since it
+		// won't cause any changes in the transformation, but allows us to skip
+		// breaking up the maps and checking for key existence here too.
+		if !p.RawEquals(c) {
+			// there a change to ignore at this path, store the prior value
+			ignoredValues = append(ignoredValues, ignoreChange{icPath, p, key})
+		}
+	}
+
+	if len(ignoredValues) == 0 {
+		return config, nil
+	}
+
+	ret, _ := cty.Transform(config, func(path cty.Path, v cty.Value) (cty.Value, error) {
+		// Easy path for when we are only matching the entire value. The only
+		// values we break up for inspection are maps.
+		if !v.Type().IsMapType() {
+			for _, ignored := range ignoredValues {
+				if path.Equals(ignored.path) {
+					return ignored.value, nil
+				}
+			}
+			return v, nil
+		}
+		// We now know this must be a map, so we need to accumulate the values
+		// key-by-key.
+
+		if !v.IsNull() && !v.IsKnown() {
+			// since v is not known, we cannot ignore individual keys
+			return v, nil
+		}
+
+		// The map values will remain as cty values, so we only need to store
+		// the marks from the outer map itself
+		v, vMarks := v.Unmark()
+
+		// The configMap is the current configuration value, which we will
+		// mutate based on the ignored paths and the prior map value.
+		var configMap map[string]cty.Value
+		switch {
+		case v.IsNull() || v.LengthInt() == 0:
+			configMap = map[string]cty.Value{}
+		default:
+			configMap = v.AsValueMap()
+		}
+
+		for _, ignored := range ignoredValues {
+			if !path.Equals(ignored.path) {
+				continue
+			}
+
+			if ignored.key.IsNull() {
+				// The map address is confirmed to match at this point,
+				// so if there is no key, we want the entire map and can
+				// stop accumulating values.
+				return ignored.value, nil
+			}
+			// Now we know we are ignoring a specific index of this map, so get
+			// the config map and modify, add, or remove the desired key.
+
+			// We also need to create a prior map, so we can check for
+			// existence while getting the value, because Value.Index will
+			// return null for a key with a null value and for a non-existent
+			// key.
+			var priorMap map[string]cty.Value
+
+			// We need to drop the marks from the ignored map for handling. We
+			// don't need to store these, as we now know the ignored value is
+			// only within the map, not the map itself.
+			ignoredVal, _ := ignored.value.Unmark()
+
+			switch {
+			case ignored.value.IsNull() || ignoredVal.LengthInt() == 0:
+				priorMap = map[string]cty.Value{}
+			default:
+				priorMap = ignoredVal.AsValueMap()
+			}
+
+			key := ignored.key.AsString()
+			priorElem, keep := priorMap[key]
+
+			switch {
+			case !keep:
+				// this didn't exist in the old map value, so we're keeping the
+				// "absence" of the key by removing it from the config
+				delete(configMap, key)
+			default:
+				configMap[key] = priorElem
+			}
+		}
+
+		var newVal cty.Value
+		switch {
+		case len(configMap) > 0:
+			newVal = cty.MapVal(configMap)
+		case v.IsNull():
+			// if the config value was null, and no values remain in the map,
+			// reset the value to null.
+			newVal = v
+		default:
+			newVal = cty.MapValEmpty(v.Type().ElementType())
+		}
+
+		if len(vMarks) > 0 {
+			newVal = newVal.WithMarks(vMarks)
+		}
+
+		return newVal, nil
+	})
+	return ret, nil
+}
+
+// readDataSource handles everything needed to call ReadDataSource on the provider.
+// A previously evaluated configVal can be passed in, or a new one is generated
+// from the resource configuration.
+func (n *NodeAbstractResourceInstance) readDataSource(ctx EvalContext, configVal cty.Value) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	var newVal cty.Value
+
+	config := *n.Config
+
+	provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	diags = diags.Append(err)
+	if diags.HasErrors() {
+		return newVal, diags
+	}
+	if providerSchema == nil {
+		diags = diags.Append(fmt.Errorf("provider schema not available for %s", n.Addr))
+		return newVal, diags
+	}
+	schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource().Resource)
+	if schema == nil {
+		// Should be caught during validation, so we don't bother with a pretty error here
+		diags = diags.Append(fmt.Errorf("provider %q does not support data source %q", n.ResolvedProvider, n.Addr.ContainingResource().Resource.Type))
+		return newVal, diags
+	}
+
+	metaConfigVal, metaDiags := n.providerMetas(ctx)
+	diags = diags.Append(metaDiags)
+	if diags.HasErrors() {
+		return newVal, diags
+	}
+
+	// Unmark before sending to provider, will re-mark before returning
+	var pvm []cty.PathValueMarks
+	configVal, pvm = configVal.UnmarkDeepWithPaths()
+
+	log.Printf("[TRACE] readDataSource: Re-validating config for %s", n.Addr)
+	validateResp := provider.ValidateDataResourceConfig(
+		providers.ValidateDataResourceConfigRequest{
+			TypeName: n.Addr.ContainingResource().Resource.Type,
+			Config:   configVal,
+		},
+	)
+	diags = diags.Append(validateResp.Diagnostics.InConfigBody(config.Config, n.Addr.String()))
+	if diags.HasErrors() {
+		return newVal, diags
+	}
+
+	// If we get down here then our configuration is complete and we're read
+	// to actually call the provider to read the data.
+	log.Printf("[TRACE] readDataSource: %s configuration is complete, so reading from provider", n.Addr)
+
+	diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+		return h.PreApply(n.Addr, states.CurrentGen, plans.Read, cty.NullVal(configVal.Type()), configVal)
+	}))
+	if diags.HasErrors() {
+		return newVal, diags
+	}
+
+	resp := provider.ReadDataSource(providers.ReadDataSourceRequest{
+		TypeName:     n.Addr.ContainingResource().Resource.Type,
+		Config:       configVal,
+		ProviderMeta: metaConfigVal,
+	})
+	diags = diags.Append(resp.Diagnostics.InConfigBody(config.Config, n.Addr.String()))
+	if diags.HasErrors() {
+		return newVal, diags
+	}
+	newVal = resp.State
+	if newVal == cty.NilVal {
+		// This can happen with incompletely-configured mocks. We'll allow it
+		// and treat it as an alias for a properly-typed null value.
+		newVal = cty.NullVal(schema.ImpliedType())
+	}
+
+	for _, err := range newVal.Type().TestConformance(schema.ImpliedType()) {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Provider produced invalid object",
+			fmt.Sprintf(
+				"Provider %q produced an invalid value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
+				n.ResolvedProvider, tfdiags.FormatErrorPrefixed(err, n.Addr.String()),
+			),
+		))
+	}
+	if diags.HasErrors() {
+		return newVal, diags
+	}
+
+	if newVal.IsNull() {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Provider produced null object",
+			fmt.Sprintf(
+				"Provider %q produced a null value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
+				n.ResolvedProvider, n.Addr,
+			),
+		))
+	}
+
+	if !newVal.IsNull() && !newVal.IsWhollyKnown() {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Provider produced invalid object",
+			fmt.Sprintf(
+				"Provider %q produced a value for %s that is not wholly known.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
+				n.ResolvedProvider, n.Addr,
+			),
+		))
+
+		// We'll still save the object, but we need to eliminate any unknown
+		// values first because we can't serialize them in the state file.
+		// Note that this may cause set elements to be coalesced if they
+		// differed only by having unknown values, but we don't worry about
+		// that here because we're saving the value only for inspection
+		// purposes; the error we added above will halt the graph walk.
+		newVal = cty.UnknownAsNull(newVal)
+	}
+
+	if len(pvm) > 0 {
+		newVal = newVal.MarkWithPaths(pvm)
+	}
+
+	diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+		return h.PostApply(n.Addr, states.CurrentGen, newVal, diags.Err())
+	}))
+
+	return newVal, diags
+}
+
+func (n *NodeAbstractResourceInstance) providerMetas(ctx EvalContext) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	metaConfigVal := cty.NullVal(cty.DynamicPseudoType)
+
+	_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	if err != nil {
+		return metaConfigVal, diags.Append(err)
+	}
+	if providerSchema == nil {
+		return metaConfigVal, diags.Append(fmt.Errorf("provider schema not available for %s", n.Addr))
+	}
+	if n.ProviderMetas != nil {
+		if m, ok := n.ProviderMetas[n.ResolvedProvider.Provider]; ok && m != nil {
+			// if the provider doesn't support this feature, throw an error
+			if providerSchema.ProviderMeta == nil {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  fmt.Sprintf("Provider %s doesn't support provider_meta", n.ResolvedProvider.Provider.String()),
+					Detail:   fmt.Sprintf("The resource %s belongs to a provider that doesn't support provider_meta blocks", n.Addr.Resource),
+					Subject:  &m.ProviderRange,
+				})
+			} else {
+				var configDiags tfdiags.Diagnostics
+				metaConfigVal, _, configDiags = ctx.EvaluateBlock(m.Config, providerSchema.ProviderMeta, nil, EvalDataForNoInstanceKey)
+				diags = diags.Append(configDiags)
+			}
+		}
+	}
+	return metaConfigVal, diags
+}
+
+// planDataSource deals with the main part of the data resource lifecycle:
+// either actually reading from the data source or generating a plan to do so.
+//
+// currentState is the current state for the data source, and the new state is
+// returned. While data sources are read-only, we need to start with the prior
+// state to determine if we have a change or not.  If we needed to read a new
+// value, but it still matches the previous state, then we can record a NoNop
+// change. If the states don't match then we record a Read change so that the
+// new value is applied to the state.
+func (n *NodeAbstractResourceInstance) planDataSource(ctx EvalContext, checkRuleSeverity tfdiags.Severity, skipPlanChanges bool) (*plans.ResourceInstanceChange, *states.ResourceInstanceObject, instances.RepetitionData, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	var keyData instances.RepetitionData
+	var configVal cty.Value
+
+	_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	if err != nil {
+		return nil, nil, keyData, diags.Append(err)
+	}
+	if providerSchema == nil {
+		return nil, nil, keyData, diags.Append(fmt.Errorf("provider schema not available for %s", n.Addr))
+	}
+
+	config := *n.Config
+	schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource().Resource)
+	if schema == nil {
+		// Should be caught during validation, so we don't bother with a pretty error here
+		diags = diags.Append(fmt.Errorf("provider %q does not support data source %q", n.ResolvedProvider, n.Addr.ContainingResource().Resource.Type))
+		return nil, nil, keyData, diags
+	}
+
+	objTy := schema.ImpliedType()
+	priorVal := cty.NullVal(objTy)
+
+	forEach, _ := evaluateForEachExpression(config.ForEach, ctx)
+	keyData = EvalDataForInstanceKey(n.ResourceInstanceAddr().Resource.Key, forEach)
+
+	checkDiags := evalCheckRules(
+		addrs.ResourcePrecondition,
+		n.Config.Preconditions,
+		ctx, n.Addr, keyData,
+		checkRuleSeverity,
+	)
+	diags = diags.Append(checkDiags)
+	if diags.HasErrors() {
+		return nil, nil, keyData, diags // failed preconditions prevent further evaluation
+	}
+
+	var configDiags tfdiags.Diagnostics
+	configVal, _, configDiags = ctx.EvaluateBlock(config.Config, schema, nil, keyData)
+	diags = diags.Append(configDiags)
+	if configDiags.HasErrors() {
+		return nil, nil, keyData, diags
+	}
+
+	check, nested := n.nestedInCheckBlock()
+	if nested {
+		// Going forward from this point, the only reason we will fail is
+		// that the data source fails to load its data. Normally, this would
+		// cancel the entire plan and this error message would bubble its way
+		// back up to the user.
+		//
+		// But, if we are in a check block then we don't want this data block to
+		// cause the plan to fail. We also need to report a status on the data
+		// block so the check processing later on knows whether to attempt to
+		// process the checks. Either we'll report the data block as failed
+		// if/when we load the data block later, or we want to report it as a
+		// success overall.
+		//
+		// Therefore, we create a deferred function here that will check if the
+		// status for the check has been updated yet, and if not we will set it
+		// to be StatusPass. The rest of this function will only update the
+		// status if it should be StatusFail.
+		defer func() {
+			status := ctx.Checks().ObjectCheckStatus(check.Addr().Absolute(n.Addr.Module))
+			if status == checks.StatusUnknown {
+				ctx.Checks().ReportCheckResult(check.Addr().Absolute(n.Addr.Module), addrs.CheckDataResource, 0, checks.StatusPass)
+			}
+		}()
+	}
+
+	configKnown := configVal.IsWhollyKnown()
+	depsPending := n.dependenciesHavePendingChanges(ctx)
+	// If our configuration contains any unknown values, or we depend on any
+	// unknown values then we must defer the read to the apply phase by
+	// producing a "Read" change for this resource, and a placeholder value for
+	// it in the state.
+	if depsPending || !configKnown {
+		// We can't plan any changes if we're only refreshing, so the only
+		// value we can set here is whatever was in state previously.
+		if skipPlanChanges {
+			plannedNewState := &states.ResourceInstanceObject{
+				Value:  priorVal,
+				Status: states.ObjectReady,
+			}
+
+			return nil, plannedNewState, keyData, diags
+		}
+
+		var reason plans.ResourceInstanceChangeActionReason
+		switch {
+		case !configKnown:
+			log.Printf("[TRACE] planDataSource: %s configuration not fully known yet, so deferring to apply phase", n.Addr)
+			reason = plans.ResourceInstanceReadBecauseConfigUnknown
+		case depsPending:
+			// NOTE: depsPending can be true at the same time as configKnown
+			// is false; configKnown takes precedence because it's more
+			// specific.
+			log.Printf("[TRACE] planDataSource: %s configuration is fully known, at least one dependency has changes pending", n.Addr)
+			reason = plans.ResourceInstanceReadBecauseDependencyPending
+		}
+
+		unmarkedConfigVal, configMarkPaths := configVal.UnmarkDeepWithPaths()
+		proposedNewVal := objchange.PlannedDataResourceObject(schema, unmarkedConfigVal)
+		proposedNewVal = proposedNewVal.MarkWithPaths(configMarkPaths)
+
+		// Apply detects that the data source will need to be read by the After
+		// value containing unknowns from PlanDataResourceObject.
+		plannedChange := &plans.ResourceInstanceChange{
+			Addr:         n.Addr,
+			PrevRunAddr:  n.prevRunAddr(ctx),
+			ProviderAddr: n.ResolvedProvider,
+			Change: plans.Change{
+				Action: plans.Read,
+				Before: priorVal,
+				After:  proposedNewVal,
+			},
+			ActionReason: reason,
+		}
+
+		plannedNewState := &states.ResourceInstanceObject{
+			Value:  proposedNewVal,
+			Status: states.ObjectPlanned,
+		}
+
+		diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+			return h.PostDiff(n.Addr, states.CurrentGen, plans.Read, priorVal, proposedNewVal)
+		}))
+
+		return plannedChange, plannedNewState, keyData, diags
+	}
+
+	// We have a complete configuration with no dependencies to wait on, so we
+	// can read the data source into the state.
+	newVal, readDiags := n.readDataSource(ctx, configVal)
+
+	// Now we've loaded the data, and diags tells us whether we were successful
+	// or not, we are going to create our plannedChange and our
+	// proposedNewState.
+	var plannedChange *plans.ResourceInstanceChange
+	var plannedNewState *states.ResourceInstanceObject
+
+	// If we are a nested block, then we want to create a plannedChange that
+	// tells Terraform to reload the data block during the apply stage even if
+	// we managed to get the data now.
+	// Another consideration is that if we failed to load the data, we need to
+	// disguise that for a nested block. Nested blocks will report the overall
+	// check as failed but won't affect the rest of the plan operation or block
+	// an apply operation.
+
+	if nested {
+		// Let's fix things up for a nested data block.
+		//
+		// A nested data block doesn't error, and creates a planned change. So,
+		// if we encountered an error we'll tidy up newVal so it makes sense
+		// and handle the error. We'll also create the plannedChange if
+		// appropriate.
+
+		if readDiags.HasErrors() {
+			// If we had errors, then we can cover that up by marking the new
+			// state as unknown.
+			unmarkedConfigVal, configMarkPaths := configVal.UnmarkDeepWithPaths()
+			newVal = objchange.PlannedDataResourceObject(schema, unmarkedConfigVal)
+			newVal = newVal.MarkWithPaths(configMarkPaths)
+
+			// We still want to report the check as failed even if we are still
+			// letting it run again during the apply stage.
+			ctx.Checks().ReportCheckFailure(check.Addr().Absolute(n.Addr.Module), addrs.CheckDataResource, 0, readDiags.Err().Error())
+		}
+
+		// Any warning or error diagnostics we'll wrap with some special checks
+		// diagnostics. This is so we can identify them later, and so they'll
+		// only report as warnings.
+		readDiags = tfdiags.AsCheckBlockDiagnostics(readDiags)
+
+		if !skipPlanChanges {
+			// refreshOnly plans cannot produce planned changes, so we only do
+			// this if skipPlanChanges is false.
+			plannedChange = &plans.ResourceInstanceChange{
+				Addr:         n.Addr,
+				PrevRunAddr:  n.prevRunAddr(ctx),
+				ProviderAddr: n.ResolvedProvider,
+				Change: plans.Change{
+					Action: plans.Read,
+					Before: priorVal,
+					After:  newVal,
+				},
+				ActionReason: plans.ResourceInstanceReadBecauseCheckNested,
+			}
+		}
+	}
+
+	diags = diags.Append(readDiags)
+	if !diags.HasErrors() {
+		// Finally, let's make our new state.
+		plannedNewState = &states.ResourceInstanceObject{
+			Value:  newVal,
+			Status: states.ObjectReady,
+		}
+	}
+
+	return plannedChange, plannedNewState, keyData, diags
+}
+
+// nestedInCheckBlock determines if this resource is nested in a Check config
+// block. If so, this resource will be loaded during both plan and apply
+// operations to make sure the check is always giving the latest information.
+func (n *NodeAbstractResourceInstance) nestedInCheckBlock() (*configs.Check, bool) {
+	if n.Config.Container != nil {
+		check, ok := n.Config.Container.(*configs.Check)
+		return check, ok
+	}
+	return nil, false
+}
+
+// dependenciesHavePendingChanges determines whether any managed resource the
+// receiver depends on has a change pending in the plan, in which case we'd
+// need to override the usual behavior of immediately reading from the data
+// source where possible, and instead defer the read until the apply step.
+func (n *NodeAbstractResourceInstance) dependenciesHavePendingChanges(ctx EvalContext) bool {
+	nModInst := n.Addr.Module
+	nMod := nModInst.Module()
+
+	// Check and see if any depends_on dependencies have
+	// changes, since they won't show up as changes in the
+	// configuration.
+	changes := ctx.Changes()
+
+	depsToUse := n.dependsOn
+
+	if n.Addr.Resource.Resource.Mode == addrs.DataResourceMode {
+		if n.Config.HasCustomConditions() {
+			// For a data resource with custom conditions we need to look at
+			// the full set of resource dependencies -- both direct and
+			// indirect -- because an upstream update might be what's needed
+			// in order to make a condition pass.
+			depsToUse = n.Dependencies
+		}
+	}
+
+	for _, d := range depsToUse {
+		if d.Resource.Mode == addrs.DataResourceMode {
+			// Data sources have no external side effects, so they pose a need
+			// to delay this read. If they do have a change planned, it must be
+			// because of a dependency on a managed resource, in which case
+			// we'll also encounter it in this list of dependencies.
+			continue
+		}
+
+		for _, change := range changes.GetChangesForConfigResource(d) {
+			changeModInst := change.Addr.Module
+			changeMod := changeModInst.Module()
+
+			if changeMod.Equal(nMod) && !changeModInst.Equal(nModInst) {
+				// Dependencies are tracked by configuration address, which
+				// means we may have changes from other instances of parent
+				// modules. The actual reference can only take effect within
+				// the same module instance, so skip any that aren't an exact
+				// match
+				continue
+			}
+
+			if change != nil && change.Action != plans.NoOp {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+// apply deals with the main part of the data resource lifecycle: either
+// actually reading from the data source or generating a plan to do so.
+func (n *NodeAbstractResourceInstance) applyDataSource(ctx EvalContext, planned *plans.ResourceInstanceChange) (*states.ResourceInstanceObject, instances.RepetitionData, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	var keyData instances.RepetitionData
+
+	_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	if err != nil {
+		return nil, keyData, diags.Append(err)
+	}
+	if providerSchema == nil {
+		return nil, keyData, diags.Append(fmt.Errorf("provider schema not available for %s", n.Addr))
+	}
+
+	if planned != nil && planned.Action != plans.Read && planned.Action != plans.NoOp {
+		// If any other action gets in here then that's always a bug; this
+		// EvalNode only deals with reading.
+		diags = diags.Append(fmt.Errorf(
+			"invalid action %s for %s: only Read is supported (this is a bug in Terraform; please report it!)",
+			planned.Action, n.Addr,
+		))
+		return nil, keyData, diags
+	}
+
+	config := *n.Config
+	schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource().Resource)
+	if schema == nil {
+		// Should be caught during validation, so we don't bother with a pretty error here
+		diags = diags.Append(fmt.Errorf("provider %q does not support data source %q", n.ResolvedProvider, n.Addr.ContainingResource().Resource.Type))
+		return nil, keyData, diags
+	}
+
+	forEach, _ := evaluateForEachExpression(config.ForEach, ctx)
+	keyData = EvalDataForInstanceKey(n.Addr.Resource.Key, forEach)
+
+	checkDiags := evalCheckRules(
+		addrs.ResourcePrecondition,
+		n.Config.Preconditions,
+		ctx, n.Addr, keyData,
+		tfdiags.Error,
+	)
+	diags = diags.Append(checkDiags)
+	if diags.HasErrors() {
+		diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+			return h.PostApply(n.Addr, states.CurrentGen, planned.Before, diags.Err())
+		}))
+		return nil, keyData, diags // failed preconditions prevent further evaluation
+	}
+
+	if planned.Action == plans.NoOp {
+		// If we didn't actually plan to read this then we have nothing more
+		// to do; we're evaluating this only for incidentals like the
+		// precondition/postcondition checks.
+		return nil, keyData, diags
+	}
+
+	configVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, nil, keyData)
+	diags = diags.Append(configDiags)
+	if configDiags.HasErrors() {
+		return nil, keyData, diags
+	}
+
+	newVal, readDiags := n.readDataSource(ctx, configVal)
+	if check, nested := n.nestedInCheckBlock(); nested {
+		// We're just going to jump in here and hide away any errors for nested
+		// data blocks.
+		if readDiags.HasErrors() {
+			ctx.Checks().ReportCheckFailure(check.Addr().Absolute(n.Addr.Module), addrs.CheckDataResource, 0, readDiags.Err().Error())
+			diags = diags.Append(tfdiags.AsCheckBlockDiagnostics(readDiags))
+			return nil, keyData, diags
+		}
+
+		// Even though we know there are no errors here, we still want to
+		// identify these diags has having been generated from a check block.
+		readDiags = tfdiags.AsCheckBlockDiagnostics(readDiags)
+
+		// If no errors, just remember to report this as a success and continue
+		// as normal.
+		ctx.Checks().ReportCheckResult(check.Addr().Absolute(n.Addr.Module), addrs.CheckDataResource, 0, checks.StatusPass)
+	}
+
+	diags = diags.Append(readDiags)
+	if readDiags.HasErrors() {
+		return nil, keyData, diags
+	}
+
+	state := &states.ResourceInstanceObject{
+		Value:  newVal,
+		Status: states.ObjectReady,
+	}
+
+	return state, keyData, diags
+}
+
+// evalApplyProvisioners determines if provisioners need to be run, and if so
+// executes the provisioners for a resource and returns an updated error if
+// provisioning fails.
+func (n *NodeAbstractResourceInstance) evalApplyProvisioners(ctx EvalContext, state *states.ResourceInstanceObject, createNew bool, when configs.ProvisionerWhen) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	if state == nil {
+		log.Printf("[TRACE] evalApplyProvisioners: %s has no state, so skipping provisioners", n.Addr)
+		return nil
+	}
+	if when == configs.ProvisionerWhenCreate && !createNew {
+		// If we're not creating a new resource, then don't run provisioners
+		log.Printf("[TRACE] evalApplyProvisioners: %s is not freshly-created, so no provisioning is required", n.Addr)
+		return nil
+	}
+	if state.Status == states.ObjectTainted {
+		// No point in provisioning an object that is already tainted, since
+		// it's going to get recreated on the next apply anyway.
+		log.Printf("[TRACE] evalApplyProvisioners: %s is tainted, so skipping provisioning", n.Addr)
+		return nil
+	}
+
+	provs := filterProvisioners(n.Config, when)
+	if len(provs) == 0 {
+		// We have no provisioners, so don't do anything
+		return nil
+	}
+
+	// Call pre hook
+	diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+		return h.PreProvisionInstance(n.Addr, state.Value)
+	}))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// If there are no errors, then we append it to our output error
+	// if we have one, otherwise we just output it.
+	diags = diags.Append(n.applyProvisioners(ctx, state, when, provs))
+	if diags.HasErrors() {
+		log.Printf("[TRACE] evalApplyProvisioners: %s provisioning failed, but we will continue anyway at the caller's request", n.Addr)
+		return diags
+	}
+
+	// Call post hook
+	return diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+		return h.PostProvisionInstance(n.Addr, state.Value)
+	}))
+}
+
+// filterProvisioners filters the provisioners on the resource to only
+// the provisioners specified by the "when" option.
+func filterProvisioners(config *configs.Resource, when configs.ProvisionerWhen) []*configs.Provisioner {
+	// Fast path the zero case
+	if config == nil || config.Managed == nil {
+		return nil
+	}
+
+	if len(config.Managed.Provisioners) == 0 {
+		return nil
+	}
+
+	result := make([]*configs.Provisioner, 0, len(config.Managed.Provisioners))
+	for _, p := range config.Managed.Provisioners {
+		if p.When == when {
+			result = append(result, p)
+		}
+	}
+
+	return result
+}
+
+// applyProvisioners executes the provisioners for a resource.
+func (n *NodeAbstractResourceInstance) applyProvisioners(ctx EvalContext, state *states.ResourceInstanceObject, when configs.ProvisionerWhen, provs []*configs.Provisioner) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	// this self is only used for destroy provisioner evaluation, and must
+	// refer to the last known value of the resource.
+	self := state.Value
+
+	var evalScope func(EvalContext, hcl.Body, cty.Value, *configschema.Block) (cty.Value, tfdiags.Diagnostics)
+	switch when {
+	case configs.ProvisionerWhenDestroy:
+		evalScope = n.evalDestroyProvisionerConfig
+	default:
+		evalScope = n.evalProvisionerConfig
+	}
+
+	// If there's a connection block defined directly inside the resource block
+	// then it'll serve as a base connection configuration for all of the
+	// provisioners.
+	var baseConn hcl.Body
+	if n.Config.Managed != nil && n.Config.Managed.Connection != nil {
+		baseConn = n.Config.Managed.Connection.Config
+	}
+
+	for _, prov := range provs {
+		log.Printf("[TRACE] applyProvisioners: provisioning %s with %q", n.Addr, prov.Type)
+
+		// Get the provisioner
+		provisioner, err := ctx.Provisioner(prov.Type)
+		if err != nil {
+			return diags.Append(err)
+		}
+
+		schema, err := ctx.ProvisionerSchema(prov.Type)
+		if err != nil {
+			// This error probably won't be a great diagnostic, but in practice
+			// we typically catch this problem long before we get here, so
+			// it should be rare to return via this codepath.
+			diags = diags.Append(err)
+			return diags
+		}
+
+		config, configDiags := evalScope(ctx, prov.Config, self, schema)
+		diags = diags.Append(configDiags)
+		if diags.HasErrors() {
+			return diags
+		}
+
+		// If the provisioner block contains a connection block of its own then
+		// it can override the base connection configuration, if any.
+		var localConn hcl.Body
+		if prov.Connection != nil {
+			localConn = prov.Connection.Config
+		}
+
+		var connBody hcl.Body
+		switch {
+		case baseConn != nil && localConn != nil:
+			// Our standard merging logic applies here, similar to what we do
+			// with _override.tf configuration files: arguments from the
+			// base connection block will be masked by any arguments of the
+			// same name in the local connection block.
+			connBody = configs.MergeBodies(baseConn, localConn)
+		case baseConn != nil:
+			connBody = baseConn
+		case localConn != nil:
+			connBody = localConn
+		}
+
+		// start with an empty connInfo
+		connInfo := cty.NullVal(connectionBlockSupersetSchema.ImpliedType())
+
+		if connBody != nil {
+			var connInfoDiags tfdiags.Diagnostics
+			connInfo, connInfoDiags = evalScope(ctx, connBody, self, connectionBlockSupersetSchema)
+			diags = diags.Append(connInfoDiags)
+			if diags.HasErrors() {
+				return diags
+			}
+		}
+
+		{
+			// Call pre hook
+			err := ctx.Hook(func(h Hook) (HookAction, error) {
+				return h.PreProvisionInstanceStep(n.Addr, prov.Type)
+			})
+			if err != nil {
+				return diags.Append(err)
+			}
+		}
+
+		// The output function
+		outputFn := func(msg string) {
+			ctx.Hook(func(h Hook) (HookAction, error) {
+				h.ProvisionOutput(n.Addr, prov.Type, msg)
+				return HookActionContinue, nil
+			})
+		}
+
+		// If our config or connection info contains any marked values, ensure
+		// those are stripped out before sending to the provisioner. Unlike
+		// resources, we have no need to capture the marked paths and reapply
+		// later.
+		unmarkedConfig, configMarks := config.UnmarkDeep()
+		unmarkedConnInfo, _ := connInfo.UnmarkDeep()
+
+		// Marks on the config might result in leaking sensitive values through
+		// provisioner logging, so we conservatively suppress all output in
+		// this case. This should not apply to connection info values, which
+		// provisioners ought not to be logging anyway.
+		if len(configMarks) > 0 {
+			outputFn = func(msg string) {
+				ctx.Hook(func(h Hook) (HookAction, error) {
+					h.ProvisionOutput(n.Addr, prov.Type, "(output suppressed due to sensitive value in config)")
+					return HookActionContinue, nil
+				})
+			}
+		}
+
+		output := CallbackUIOutput{OutputFn: outputFn}
+		resp := provisioner.ProvisionResource(provisioners.ProvisionResourceRequest{
+			Config:     unmarkedConfig,
+			Connection: unmarkedConnInfo,
+			UIOutput:   &output,
+		})
+		applyDiags := resp.Diagnostics.InConfigBody(prov.Config, n.Addr.String())
+
+		// Call post hook
+		hookErr := ctx.Hook(func(h Hook) (HookAction, error) {
+			return h.PostProvisionInstanceStep(n.Addr, prov.Type, applyDiags.Err())
+		})
+
+		switch prov.OnFailure {
+		case configs.ProvisionerOnFailureContinue:
+			if applyDiags.HasErrors() {
+				log.Printf("[WARN] Errors while provisioning %s with %q, but continuing as requested in configuration", n.Addr, prov.Type)
+			} else {
+				// Maybe there are warnings that we still want to see
+				diags = diags.Append(applyDiags)
+			}
+		default:
+			diags = diags.Append(applyDiags)
+			if applyDiags.HasErrors() {
+				log.Printf("[WARN] Errors while provisioning %s with %q, so aborting", n.Addr, prov.Type)
+				return diags
+			}
+		}
+
+		// Deal with the hook
+		if hookErr != nil {
+			return diags.Append(hookErr)
+		}
+	}
+
+	return diags
+}
+
+func (n *NodeAbstractResourceInstance) evalProvisionerConfig(ctx EvalContext, body hcl.Body, self cty.Value, schema *configschema.Block) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	forEach, forEachDiags := evaluateForEachExpression(n.Config.ForEach, ctx)
+	diags = diags.Append(forEachDiags)
+
+	keyData := EvalDataForInstanceKey(n.ResourceInstanceAddr().Resource.Key, forEach)
+
+	config, _, configDiags := ctx.EvaluateBlock(body, schema, n.ResourceInstanceAddr().Resource, keyData)
+	diags = diags.Append(configDiags)
+
+	return config, diags
+}
+
+// during destroy a provisioner can only evaluate within the scope of the parent resource
+func (n *NodeAbstractResourceInstance) evalDestroyProvisionerConfig(ctx EvalContext, body hcl.Body, self cty.Value, schema *configschema.Block) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	// For a destroy-time provisioner forEach is intentionally nil here,
+	// which EvalDataForInstanceKey responds to by not populating EachValue
+	// in its result. That's okay because each.value is prohibited for
+	// destroy-time provisioners.
+	keyData := EvalDataForInstanceKey(n.ResourceInstanceAddr().Resource.Key, nil)
+
+	evalScope := ctx.EvaluationScope(n.ResourceInstanceAddr().Resource, nil, keyData)
+	config, evalDiags := evalScope.EvalSelfBlock(body, self, schema, keyData)
+	diags = diags.Append(evalDiags)
+
+	return config, diags
+}
+
+// apply accepts an applyConfig, instead of using n.Config, so destroy plans can
+// send a nil config. The keyData information can be empty if the config is
+// nil, since it is only used to evaluate the configuration.
+func (n *NodeAbstractResourceInstance) apply(
+	ctx EvalContext,
+	state *states.ResourceInstanceObject,
+	change *plans.ResourceInstanceChange,
+	applyConfig *configs.Resource,
+	keyData instances.RepetitionData,
+	createBeforeDestroy bool) (*states.ResourceInstanceObject, tfdiags.Diagnostics) {
+
+	var diags tfdiags.Diagnostics
+	if state == nil {
+		state = &states.ResourceInstanceObject{}
+	}
+
+	if change.Action == plans.NoOp {
+		// If this is a no-op change then we don't want to actually change
+		// anything, so we'll just echo back the state we were given and
+		// let our internal checks and updates proceed.
+		log.Printf("[TRACE] NodeAbstractResourceInstance.apply: skipping %s because it has no planned action", n.Addr)
+		return state, diags
+	}
+
+	provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	if err != nil {
+		return nil, diags.Append(err)
+	}
+	schema, _ := providerSchema.SchemaForResourceType(n.Addr.Resource.Resource.Mode, n.Addr.Resource.Resource.Type)
+	if schema == nil {
+		// Should be caught during validation, so we don't bother with a pretty error here
+		diags = diags.Append(fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Resource.Type))
+		return nil, diags
+	}
+
+	log.Printf("[INFO] Starting apply for %s", n.Addr)
+
+	configVal := cty.NullVal(cty.DynamicPseudoType)
+	if applyConfig != nil {
+		var configDiags tfdiags.Diagnostics
+		configVal, _, configDiags = ctx.EvaluateBlock(applyConfig.Config, schema, nil, keyData)
+		diags = diags.Append(configDiags)
+		if configDiags.HasErrors() {
+			return nil, diags
+		}
+	}
+
+	if !configVal.IsWhollyKnown() {
+		// We don't have a pretty format function for a path, but since this is
+		// such a rare error, we can just drop the raw GoString values in here
+		// to make sure we have something to debug with.
+		var unknownPaths []string
+		cty.Transform(configVal, func(p cty.Path, v cty.Value) (cty.Value, error) {
+			if !v.IsKnown() {
+				unknownPaths = append(unknownPaths, fmt.Sprintf("%#v", p))
+			}
+			return v, nil
+		})
+
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Configuration contains unknown value",
+			fmt.Sprintf("configuration for %s still contains unknown values during apply (this is a bug in Terraform; please report it!)\n"+
+				"The following paths in the resource configuration are unknown:\n%s",
+				n.Addr,
+				strings.Join(unknownPaths, "\n"),
+			),
+		))
+		return nil, diags
+	}
+
+	metaConfigVal, metaDiags := n.providerMetas(ctx)
+	diags = diags.Append(metaDiags)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	log.Printf("[DEBUG] %s: applying the planned %s change", n.Addr, change.Action)
+
+	// If our config, Before or After value contain any marked values,
+	// ensure those are stripped out before sending
+	// this to the provider
+	unmarkedConfigVal, _ := configVal.UnmarkDeep()
+	unmarkedBefore, beforePaths := change.Before.UnmarkDeepWithPaths()
+	unmarkedAfter, afterPaths := change.After.UnmarkDeepWithPaths()
+
+	// If we have an Update action, our before and after values are equal,
+	// and only differ on their sensitivity, the newVal is the after val
+	// and we should not communicate with the provider. We do need to update
+	// the state with this new value, to ensure the sensitivity change is
+	// persisted.
+	eqV := unmarkedBefore.Equals(unmarkedAfter)
+	eq := eqV.IsKnown() && eqV.True()
+	if change.Action == plans.Update && eq && !marksEqual(beforePaths, afterPaths) {
+		// Copy the previous state, changing only the value
+		newState := &states.ResourceInstanceObject{
+			CreateBeforeDestroy: state.CreateBeforeDestroy,
+			Dependencies:        state.Dependencies,
+			Private:             state.Private,
+			Status:              state.Status,
+			Value:               change.After,
+		}
+		return newState, diags
+	}
+
+	resp := provider.ApplyResourceChange(providers.ApplyResourceChangeRequest{
+		TypeName:       n.Addr.Resource.Resource.Type,
+		PriorState:     unmarkedBefore,
+		Config:         unmarkedConfigVal,
+		PlannedState:   unmarkedAfter,
+		PlannedPrivate: change.Private,
+		ProviderMeta:   metaConfigVal,
+	})
+	applyDiags := resp.Diagnostics
+	if applyConfig != nil {
+		applyDiags = applyDiags.InConfigBody(applyConfig.Config, n.Addr.String())
+	}
+	diags = diags.Append(applyDiags)
+
+	// Even if there are errors in the returned diagnostics, the provider may
+	// have returned a _partial_ state for an object that already exists but
+	// failed to fully configure, and so the remaining code must always run
+	// to completion but must be defensive against the new value being
+	// incomplete.
+	newVal := resp.NewState
+
+	// If we have paths to mark, mark those on this new value
+	if len(afterPaths) > 0 {
+		newVal = newVal.MarkWithPaths(afterPaths)
+	}
+
+	if newVal == cty.NilVal {
+		// Providers are supposed to return a partial new value even when errors
+		// occur, but sometimes they don't and so in that case we'll patch that up
+		// by just using the prior state, so we'll at least keep track of the
+		// object for the user to retry.
+		newVal = change.Before
+
+		// As a special case, we'll set the new value to null if it looks like
+		// we were trying to execute a delete, because the provider in this case
+		// probably left the newVal unset intending it to be interpreted as "null".
+		if change.After.IsNull() {
+			newVal = cty.NullVal(schema.ImpliedType())
+		}
+
+		if !diags.HasErrors() {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Provider produced invalid object",
+				fmt.Sprintf(
+					"Provider %q produced an invalid nil value after apply for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
+					n.ResolvedProvider.String(), n.Addr.String(),
+				),
+			))
+		}
+	}
+
+	var conformDiags tfdiags.Diagnostics
+	for _, err := range newVal.Type().TestConformance(schema.ImpliedType()) {
+		conformDiags = conformDiags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Provider produced invalid object",
+			fmt.Sprintf(
+				"Provider %q produced an invalid value after apply for %s. The result cannot not be saved in the Terraform state.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
+				n.ResolvedProvider.String(), tfdiags.FormatErrorPrefixed(err, n.Addr.String()),
+			),
+		))
+	}
+	diags = diags.Append(conformDiags)
+	if conformDiags.HasErrors() {
+		// Bail early in this particular case, because an object that doesn't
+		// conform to the schema can't be saved in the state anyway -- the
+		// serializer will reject it.
+		return nil, diags
+	}
+
+	// After this point we have a type-conforming result object and so we
+	// must always run to completion to ensure it can be saved. If n.Error
+	// is set then we must not return a non-nil error, in order to allow
+	// evaluation to continue to a later point where our state object will
+	// be saved.
+
+	// By this point there must not be any unknown values remaining in our
+	// object, because we've applied the change and we can't save unknowns
+	// in our persistent state. If any are present then we will indicate an
+	// error (which is always a bug in the provider) but we will also replace
+	// them with nulls so that we can successfully save the portions of the
+	// returned value that are known.
+	if !newVal.IsWhollyKnown() {
+		// To generate better error messages, we'll go for a walk through the
+		// value and make a separate diagnostic for each unknown value we
+		// find.
+		cty.Walk(newVal, func(path cty.Path, val cty.Value) (bool, error) {
+			if !val.IsKnown() {
+				pathStr := tfdiags.FormatCtyPath(path)
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Provider returned invalid result object after apply",
+					fmt.Sprintf(
+						"After the apply operation, the provider still indicated an unknown value for %s%s. All values must be known after apply, so this is always a bug in the provider and should be reported in the provider's own repository. Terraform will still save the other known object values in the state.",
+						n.Addr, pathStr,
+					),
+				))
+			}
+			return true, nil
+		})
+
+		// NOTE: This operation can potentially be lossy if there are multiple
+		// elements in a set that differ only by unknown values: after
+		// replacing with null these will be merged together into a single set
+		// element. Since we can only get here in the presence of a provider
+		// bug, we accept this because storing a result here is always a
+		// best-effort sort of thing.
+		newVal = cty.UnknownAsNull(newVal)
+	}
+
+	if change.Action != plans.Delete && !diags.HasErrors() {
+		// Only values that were marked as unknown in the planned value are allowed
+		// to change during the apply operation. (We do this after the unknown-ness
+		// check above so that we also catch anything that became unknown after
+		// being known during plan.)
+		//
+		// If we are returning other errors anyway then we'll give this
+		// a pass since the other errors are usually the explanation for
+		// this one and so it's more helpful to let the user focus on the
+		// root cause rather than distract with this extra problem.
+		if errs := objchange.AssertObjectCompatible(schema, change.After, newVal); len(errs) > 0 {
+			if resp.LegacyTypeSystem {
+				// The shimming of the old type system in the legacy SDK is not precise
+				// enough to pass this consistency check, so we'll give it a pass here,
+				// but we will generate a warning about it so that we are more likely
+				// to notice in the logs if an inconsistency beyond the type system
+				// leads to a downstream provider failure.
+				var buf strings.Builder
+				fmt.Fprintf(&buf, "[WARN] Provider %q produced an unexpected new value for %s, but we are tolerating it because it is using the legacy plugin SDK.\n    The following problems may be the cause of any confusing errors from downstream operations:", n.ResolvedProvider.String(), n.Addr)
+				for _, err := range errs {
+					fmt.Fprintf(&buf, "\n      - %s", tfdiags.FormatError(err))
+				}
+				log.Print(buf.String())
+
+				// The sort of inconsistency we won't catch here is if a known value
+				// in the plan is changed during apply. That can cause downstream
+				// problems because a dependent resource would make its own plan based
+				// on the planned value, and thus get a different result during the
+				// apply phase. This will usually lead to a "Provider produced invalid plan"
+				// error that incorrectly blames the downstream resource for the change.
+
+			} else {
+				for _, err := range errs {
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Provider produced inconsistent result after apply",
+						fmt.Sprintf(
+							"When applying changes to %s, provider %q produced an unexpected new value: %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
+							n.Addr, n.ResolvedProvider.String(), tfdiags.FormatError(err),
+						),
+					))
+				}
+			}
+		}
+	}
+
+	// If a provider returns a null or non-null object at the wrong time then
+	// we still want to save that but it often causes some confusing behaviors
+	// where it seems like Terraform is failing to take any action at all,
+	// so we'll generate some errors to draw attention to it.
+	if !diags.HasErrors() {
+		if change.Action == plans.Delete && !newVal.IsNull() {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Provider returned invalid result object after apply",
+				fmt.Sprintf(
+					"After applying a %s plan, the provider returned a non-null object for %s. Destroying should always produce a null value, so this is always a bug in the provider and should be reported in the provider's own repository. Terraform will still save this errant object in the state for debugging and recovery.",
+					change.Action, n.Addr,
+				),
+			))
+		}
+		if change.Action != plans.Delete && newVal.IsNull() {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Provider returned invalid result object after apply",
+				fmt.Sprintf(
+					"After applying a %s plan, the provider returned a null object for %s. Only destroying should always produce a null value, so this is always a bug in the provider and should be reported in the provider's own repository.",
+					change.Action, n.Addr,
+				),
+			))
+		}
+	}
+
+	switch {
+	case diags.HasErrors() && newVal.IsNull():
+		// Sometimes providers return a null value when an operation fails for
+		// some reason, but we'd rather keep the prior state so that the error
+		// can be corrected on a subsequent run. We must only do this for null
+		// new value though, or else we may discard partial updates the
+		// provider was able to complete. Otherwise, we'll continue using the
+		// prior state as the new value, making this effectively a no-op.  If
+		// the item really _has_ been deleted then our next refresh will detect
+		// that and fix it up.
+		return state.DeepCopy(), diags
+
+	case diags.HasErrors() && !newVal.IsNull():
+		// if we have an error, make sure we restore the object status in the new state
+		newState := &states.ResourceInstanceObject{
+			Status:              state.Status,
+			Value:               newVal,
+			Private:             resp.Private,
+			CreateBeforeDestroy: createBeforeDestroy,
+		}
+
+		// if the resource was being deleted, the dependencies are not going to
+		// be recalculated and we need to restore those as well.
+		if change.Action == plans.Delete {
+			newState.Dependencies = state.Dependencies
+		}
+
+		return newState, diags
+
+	case !newVal.IsNull():
+		// Non error case with a new state
+		newState := &states.ResourceInstanceObject{
+			Status:              states.ObjectReady,
+			Value:               newVal,
+			Private:             resp.Private,
+			CreateBeforeDestroy: createBeforeDestroy,
+		}
+		return newState, diags
+
+	default:
+		// Non error case, were the object was deleted
+		return nil, diags
+	}
+}
+
+func (n *NodeAbstractResourceInstance) prevRunAddr(ctx EvalContext) addrs.AbsResourceInstance {
+	return resourceInstancePrevRunAddr(ctx, n.Addr)
+}
+
+func resourceInstancePrevRunAddr(ctx EvalContext, currentAddr addrs.AbsResourceInstance) addrs.AbsResourceInstance {
+	table := ctx.MoveResults()
+	return table.OldAddr(currentAddr)
+}
diff --git a/v1.5.7/internal/terraform/node_resource_abstract_instance_test.go b/v1.5.7/internal/terraform/node_resource_abstract_instance_test.go
new file mode 100644
index 0000000..bc8e70a
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_abstract_instance_test.go
@@ -0,0 +1,186 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestNodeAbstractResourceInstanceProvider(t *testing.T) {
+	tests := []struct {
+		Addr                 addrs.AbsResourceInstance
+		Config               *configs.Resource
+		StoredProviderConfig addrs.AbsProviderConfig
+		Want                 addrs.Provider
+	}{
+		{
+			Addr: addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "null_resource",
+				Name: "baz",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			Want: addrs.Provider{
+				Hostname:  addrs.DefaultProviderRegistryHost,
+				Namespace: "hashicorp",
+				Type:      "null",
+			},
+		},
+		{
+			Addr: addrs.Resource{
+				Mode: addrs.DataResourceMode,
+				Type: "terraform_remote_state",
+				Name: "baz",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			Want: addrs.Provider{
+				// As a special case, the type prefix "terraform_" maps to
+				// the builtin provider, not the default one.
+				Hostname:  addrs.BuiltInProviderHost,
+				Namespace: addrs.BuiltInProviderNamespace,
+				Type:      "terraform",
+			},
+		},
+		{
+			Addr: addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "null_resource",
+				Name: "baz",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			Config: &configs.Resource{
+				// Just enough configs.Resource for the Provider method. Not
+				// actually valid for general use.
+				Provider: addrs.Provider{
+					Hostname:  addrs.DefaultProviderRegistryHost,
+					Namespace: "awesomecorp",
+					Type:      "happycloud",
+				},
+			},
+			// The config overrides the default behavior.
+			Want: addrs.Provider{
+				Hostname:  addrs.DefaultProviderRegistryHost,
+				Namespace: "awesomecorp",
+				Type:      "happycloud",
+			},
+		},
+		{
+			Addr: addrs.Resource{
+				Mode: addrs.DataResourceMode,
+				Type: "terraform_remote_state",
+				Name: "baz",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			Config: &configs.Resource{
+				// Just enough configs.Resource for the Provider method. Not
+				// actually valid for general use.
+				Provider: addrs.Provider{
+					Hostname:  addrs.DefaultProviderRegistryHost,
+					Namespace: "awesomecorp",
+					Type:      "happycloud",
+				},
+			},
+			// The config overrides the default behavior.
+			Want: addrs.Provider{
+				Hostname:  addrs.DefaultProviderRegistryHost,
+				Namespace: "awesomecorp",
+				Type:      "happycloud",
+			},
+		},
+		{
+			Addr: addrs.Resource{
+				Mode: addrs.DataResourceMode,
+				Type: "null_resource",
+				Name: "baz",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			Config: nil,
+			StoredProviderConfig: addrs.AbsProviderConfig{
+				Module: addrs.RootModule,
+				Provider: addrs.Provider{
+					Hostname:  addrs.DefaultProviderRegistryHost,
+					Namespace: "awesomecorp",
+					Type:      "null",
+				},
+			},
+			// The stored provider config overrides the default behavior.
+			Want: addrs.Provider{
+				Hostname:  addrs.DefaultProviderRegistryHost,
+				Namespace: "awesomecorp",
+				Type:      "null",
+			},
+		},
+	}
+
+	for _, test := range tests {
+		var name string
+		if test.Config != nil {
+			name = fmt.Sprintf("%s with configured %s", test.Addr, test.Config.Provider)
+		} else {
+			name = fmt.Sprintf("%s with no configuration", test.Addr)
+		}
+		t.Run(name, func(t *testing.T) {
+			node := &NodeAbstractResourceInstance{
+				// Just enough NodeAbstractResourceInstance for the Provider
+				// function. (This would not be valid for some other functions.)
+				Addr: test.Addr,
+				NodeAbstractResource: NodeAbstractResource{
+					Addr:                 test.Addr.ConfigResource(),
+					Config:               test.Config,
+					storedProviderConfig: test.StoredProviderConfig,
+				},
+			}
+			got := node.Provider()
+			if got != test.Want {
+				t.Errorf("wrong result\naddr:  %s\nconfig: %#v\ngot:   %s\nwant:  %s", test.Addr, test.Config, got, test.Want)
+			}
+		})
+	}
+}
+
+func TestNodeAbstractResourceInstance_WriteResourceInstanceState(t *testing.T) {
+	state := states.NewState()
+	ctx := new(MockEvalContext)
+	ctx.StateState = state.SyncWrapper()
+	ctx.PathPath = addrs.RootModuleInstance
+
+	mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"id": {
+				Type:     cty.String,
+				Optional: true,
+			},
+		},
+	})
+
+	obj := &states.ResourceInstanceObject{
+		Value: cty.ObjectVal(map[string]cty.Value{
+			"id": cty.StringVal("i-abc123"),
+		}),
+		Status: states.ObjectReady,
+	}
+
+	node := &NodeAbstractResourceInstance{
+		Addr: mustResourceInstanceAddr("aws_instance.foo"),
+		// instanceState:        obj,
+		NodeAbstractResource: NodeAbstractResource{
+			ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+		},
+	}
+	ctx.ProviderProvider = mockProvider
+	ctx.ProviderSchemaSchema = mockProvider.ProviderSchema()
+
+	err := node.writeResourceInstanceState(ctx, obj, workingState)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err.Error())
+	}
+
+	checkStateString(t, state, `
+aws_instance.foo:
+  ID = i-abc123
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+	`)
+}
diff --git a/v1.5.7/internal/terraform/node_resource_abstract_test.go b/v1.5.7/internal/terraform/node_resource_abstract_test.go
new file mode 100644
index 0000000..85f3f20
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_abstract_test.go
@@ -0,0 +1,315 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestNodeAbstractResourceProvider(t *testing.T) {
+	tests := []struct {
+		Addr   addrs.ConfigResource
+		Config *configs.Resource
+		Want   addrs.Provider
+	}{
+		{
+			Addr: addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "null_resource",
+				Name: "baz",
+			}.InModule(addrs.RootModule),
+			Want: addrs.Provider{
+				Hostname:  addrs.DefaultProviderRegistryHost,
+				Namespace: "hashicorp",
+				Type:      "null",
+			},
+		},
+		{
+			Addr: addrs.Resource{
+				Mode: addrs.DataResourceMode,
+				Type: "terraform_remote_state",
+				Name: "baz",
+			}.InModule(addrs.RootModule),
+			Want: addrs.Provider{
+				// As a special case, the type prefix "terraform_" maps to
+				// the builtin provider, not the default one.
+				Hostname:  addrs.BuiltInProviderHost,
+				Namespace: addrs.BuiltInProviderNamespace,
+				Type:      "terraform",
+			},
+		},
+		{
+			Addr: addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "null_resource",
+				Name: "baz",
+			}.InModule(addrs.RootModule),
+			Config: &configs.Resource{
+				// Just enough configs.Resource for the Provider method. Not
+				// actually valid for general use.
+				Provider: addrs.Provider{
+					Hostname:  addrs.DefaultProviderRegistryHost,
+					Namespace: "awesomecorp",
+					Type:      "happycloud",
+				},
+			},
+			// The config overrides the default behavior.
+			Want: addrs.Provider{
+				Hostname:  addrs.DefaultProviderRegistryHost,
+				Namespace: "awesomecorp",
+				Type:      "happycloud",
+			},
+		},
+		{
+			Addr: addrs.Resource{
+				Mode: addrs.DataResourceMode,
+				Type: "terraform_remote_state",
+				Name: "baz",
+			}.InModule(addrs.RootModule),
+			Config: &configs.Resource{
+				// Just enough configs.Resource for the Provider method. Not
+				// actually valid for general use.
+				Provider: addrs.Provider{
+					Hostname:  addrs.DefaultProviderRegistryHost,
+					Namespace: "awesomecorp",
+					Type:      "happycloud",
+				},
+			},
+			// The config overrides the default behavior.
+			Want: addrs.Provider{
+				Hostname:  addrs.DefaultProviderRegistryHost,
+				Namespace: "awesomecorp",
+				Type:      "happycloud",
+			},
+		},
+	}
+
+	for _, test := range tests {
+		var name string
+		if test.Config != nil {
+			name = fmt.Sprintf("%s with configured %s", test.Addr, test.Config.Provider)
+		} else {
+			name = fmt.Sprintf("%s with no configuration", test.Addr)
+		}
+		t.Run(name, func(t *testing.T) {
+			node := &NodeAbstractResource{
+				// Just enough NodeAbstractResource for the Provider function.
+				// (This would not be valid for some other functions.)
+				Addr:   test.Addr,
+				Config: test.Config,
+			}
+			got := node.Provider()
+			if got != test.Want {
+				t.Errorf("wrong result\naddr:  %s\nconfig: %#v\ngot:   %s\nwant:  %s", test.Addr, test.Config, got, test.Want)
+			}
+		})
+	}
+}
+
+// Make sure ProvideBy returns the final resolved provider
+func TestNodeAbstractResourceSetProvider(t *testing.T) {
+	node := &NodeAbstractResource{
+
+		// Just enough NodeAbstractResource for the Provider function.
+		// (This would not be valid for some other functions.)
+		Addr: addrs.Resource{
+			Mode: addrs.DataResourceMode,
+			Type: "terraform_remote_state",
+			Name: "baz",
+		}.InModule(addrs.RootModule),
+		Config: &configs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "terraform_remote_state",
+			Name: "baz",
+			// Just enough configs.Resource for the Provider method. Not
+			// actually valid for general use.
+			Provider: addrs.Provider{
+				Hostname:  addrs.DefaultProviderRegistryHost,
+				Namespace: "awesomecorp",
+				Type:      "happycloud",
+			},
+		},
+	}
+
+	p, exact := node.ProvidedBy()
+	if exact {
+		t.Fatalf("no exact provider should be found from this confniguration, got %q\n", p)
+	}
+
+	// the implied non-exact provider should be "terraform"
+	lpc, ok := p.(addrs.LocalProviderConfig)
+	if !ok {
+		t.Fatalf("expected LocalProviderConfig, got %#v\n", p)
+	}
+
+	if lpc.LocalName != "terraform" {
+		t.Fatalf("expected non-exact provider of 'terraform', got %q", lpc.LocalName)
+	}
+
+	// now set a resolved provider for the resource
+	resolved := addrs.AbsProviderConfig{
+		Provider: addrs.Provider{
+			Hostname:  addrs.DefaultProviderRegistryHost,
+			Namespace: "awesomecorp",
+			Type:      "happycloud",
+		},
+		Module: addrs.RootModule,
+		Alias:  "test",
+	}
+
+	node.SetProvider(resolved)
+	p, exact = node.ProvidedBy()
+	if !exact {
+		t.Fatalf("exact provider should be found, got %q\n", p)
+	}
+
+	apc, ok := p.(addrs.AbsProviderConfig)
+	if !ok {
+		t.Fatalf("expected AbsProviderConfig, got %#v\n", p)
+	}
+
+	if apc.String() != resolved.String() {
+		t.Fatalf("incorrect resolved config: got %#v, wanted %#v\n", apc, resolved)
+	}
+}
+
+func TestNodeAbstractResource_ReadResourceInstanceState(t *testing.T) {
+	mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"id": {
+				Type:     cty.String,
+				Optional: true,
+			},
+		},
+	})
+	// This test does not configure the provider, but the mock provider will
+	// check that this was called and report errors.
+	mockProvider.ConfigureProviderCalled = true
+
+	tests := map[string]struct {
+		State              *states.State
+		Node               *NodeAbstractResource
+		ExpectedInstanceId string
+	}{
+		"ReadState gets primary instance state": {
+			State: states.BuildState(func(s *states.SyncState) {
+				providerAddr := addrs.AbsProviderConfig{
+					Provider: addrs.NewDefaultProvider("aws"),
+					Module:   addrs.RootModule,
+				}
+				oneAddr := addrs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "aws_instance",
+					Name: "bar",
+				}.Absolute(addrs.RootModuleInstance)
+				s.SetResourceProvider(oneAddr, providerAddr)
+				s.SetResourceInstanceCurrent(oneAddr.Instance(addrs.NoKey), &states.ResourceInstanceObjectSrc{
+					Status:    states.ObjectReady,
+					AttrsJSON: []byte(`{"id":"i-abc123"}`),
+				}, providerAddr)
+			}),
+			Node: &NodeAbstractResource{
+				Addr:             mustConfigResourceAddr("aws_instance.bar"),
+				ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+			},
+			ExpectedInstanceId: "i-abc123",
+		},
+	}
+
+	for k, test := range tests {
+		t.Run(k, func(t *testing.T) {
+			ctx := new(MockEvalContext)
+			ctx.StateState = test.State.SyncWrapper()
+			ctx.PathPath = addrs.RootModuleInstance
+			ctx.ProviderSchemaSchema = mockProvider.ProviderSchema()
+
+			ctx.ProviderProvider = providers.Interface(mockProvider)
+
+			got, readDiags := test.Node.readResourceInstanceState(ctx, test.Node.Addr.Resource.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
+			if readDiags.HasErrors() {
+				t.Fatalf("[%s] Got err: %#v", k, readDiags.Err())
+			}
+
+			expected := test.ExpectedInstanceId
+
+			if !(got != nil && got.Value.GetAttr("id") == cty.StringVal(expected)) {
+				t.Fatalf("[%s] Expected output with ID %#v, got: %#v", k, expected, got)
+			}
+		})
+	}
+}
+
+func TestNodeAbstractResource_ReadResourceInstanceStateDeposed(t *testing.T) {
+	mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"id": {
+				Type:     cty.String,
+				Optional: true,
+			},
+		},
+	})
+	// This test does not configure the provider, but the mock provider will
+	// check that this was called and report errors.
+	mockProvider.ConfigureProviderCalled = true
+
+	tests := map[string]struct {
+		State              *states.State
+		Node               *NodeAbstractResource
+		ExpectedInstanceId string
+	}{
+		"ReadStateDeposed gets deposed instance": {
+			State: states.BuildState(func(s *states.SyncState) {
+				providerAddr := addrs.AbsProviderConfig{
+					Provider: addrs.NewDefaultProvider("aws"),
+					Module:   addrs.RootModule,
+				}
+				oneAddr := addrs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "aws_instance",
+					Name: "bar",
+				}.Absolute(addrs.RootModuleInstance)
+				s.SetResourceProvider(oneAddr, providerAddr)
+				s.SetResourceInstanceDeposed(oneAddr.Instance(addrs.NoKey), states.DeposedKey("00000001"), &states.ResourceInstanceObjectSrc{
+					Status:    states.ObjectReady,
+					AttrsJSON: []byte(`{"id":"i-abc123"}`),
+				}, providerAddr)
+			}),
+			Node: &NodeAbstractResource{
+				Addr:             mustConfigResourceAddr("aws_instance.bar"),
+				ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+			},
+			ExpectedInstanceId: "i-abc123",
+		},
+	}
+	for k, test := range tests {
+		t.Run(k, func(t *testing.T) {
+			ctx := new(MockEvalContext)
+			ctx.StateState = test.State.SyncWrapper()
+			ctx.PathPath = addrs.RootModuleInstance
+			ctx.ProviderSchemaSchema = mockProvider.ProviderSchema()
+			ctx.ProviderProvider = providers.Interface(mockProvider)
+
+			key := states.DeposedKey("00000001") // shim from legacy state assigns 0th deposed index this key
+
+			got, readDiags := test.Node.readResourceInstanceStateDeposed(ctx, test.Node.Addr.Resource.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), key)
+			if readDiags.HasErrors() {
+				t.Fatalf("[%s] Got err: %#v", k, readDiags.Err())
+			}
+
+			expected := test.ExpectedInstanceId
+
+			if !(got != nil && got.Value.GetAttr("id") == cty.StringVal(expected)) {
+				t.Fatalf("[%s] Expected output with ID %#v, got: %#v", k, expected, got)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/terraform/node_resource_apply.go b/v1.5.7/internal/terraform/node_resource_apply.go
new file mode 100644
index 0000000..17abf4a
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_apply.go
@@ -0,0 +1,115 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// nodeExpandApplyableResource handles the first layer of resource
+// expansion during apply. Even though the resource instances themselves are
+// already expanded from the plan, we still need to expand the
+// NodeApplyableResource nodes into their respective modules.
+type nodeExpandApplyableResource struct {
+	*NodeAbstractResource
+}
+
+var (
+	_ GraphNodeDynamicExpandable    = (*nodeExpandApplyableResource)(nil)
+	_ GraphNodeReferenceable        = (*nodeExpandApplyableResource)(nil)
+	_ GraphNodeReferencer           = (*nodeExpandApplyableResource)(nil)
+	_ GraphNodeConfigResource       = (*nodeExpandApplyableResource)(nil)
+	_ GraphNodeAttachResourceConfig = (*nodeExpandApplyableResource)(nil)
+	_ graphNodeExpandsInstances     = (*nodeExpandApplyableResource)(nil)
+	_ GraphNodeTargetable           = (*nodeExpandApplyableResource)(nil)
+)
+
+func (n *nodeExpandApplyableResource) expandsInstances() {
+}
+
+func (n *nodeExpandApplyableResource) References() []*addrs.Reference {
+	return (&NodeApplyableResource{NodeAbstractResource: n.NodeAbstractResource}).References()
+}
+
+func (n *nodeExpandApplyableResource) Name() string {
+	return n.NodeAbstractResource.Name() + " (expand)"
+}
+
+func (n *nodeExpandApplyableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
+	var g Graph
+
+	expander := ctx.InstanceExpander()
+	moduleInstances := expander.ExpandModule(n.Addr.Module)
+	for _, module := range moduleInstances {
+		g.Add(&NodeApplyableResource{
+			NodeAbstractResource: n.NodeAbstractResource,
+			Addr:                 n.Addr.Resource.Absolute(module),
+		})
+	}
+	addRootNodeToGraph(&g)
+
+	return &g, nil
+}
+
+// NodeApplyableResource represents a resource that is "applyable":
+// it may need to have its record in the state adjusted to match configuration.
+//
+// Unlike in the plan walk, this resource node does not DynamicExpand. Instead,
+// it should be inserted into the same graph as any instances of the nodes
+// with dependency edges ensuring that the resource is evaluated before any
+// of its instances, which will turn ensure that the whole-resource record
+// in the state is suitably prepared to receive any updates to instances.
+type NodeApplyableResource struct {
+	*NodeAbstractResource
+
+	Addr addrs.AbsResource
+}
+
+var (
+	_ GraphNodeModuleInstance       = (*NodeApplyableResource)(nil)
+	_ GraphNodeConfigResource       = (*NodeApplyableResource)(nil)
+	_ GraphNodeExecutable           = (*NodeApplyableResource)(nil)
+	_ GraphNodeProviderConsumer     = (*NodeApplyableResource)(nil)
+	_ GraphNodeAttachResourceConfig = (*NodeApplyableResource)(nil)
+	_ GraphNodeReferencer           = (*NodeApplyableResource)(nil)
+)
+
+func (n *NodeApplyableResource) Path() addrs.ModuleInstance {
+	return n.Addr.Module
+}
+
+func (n *NodeApplyableResource) References() []*addrs.Reference {
+	if n.Config == nil {
+		log.Printf("[WARN] NodeApplyableResource %q: no configuration, so can't determine References", dag.VertexName(n))
+		return nil
+	}
+
+	var result []*addrs.Reference
+
+	// Since this node type only updates resource-level metadata, we only
+	// need to worry about the parts of the configuration that affect
+	// our "each mode": the count and for_each meta-arguments.
+	refs, _ := lang.ReferencesInExpr(n.Config.Count)
+	result = append(result, refs...)
+	refs, _ = lang.ReferencesInExpr(n.Config.ForEach)
+	result = append(result, refs...)
+
+	return result
+}
+
+// GraphNodeExecutable
+func (n *NodeApplyableResource) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
+	if n.Config == nil {
+		// Nothing to do, then.
+		log.Printf("[TRACE] NodeApplyableResource: no configuration present for %s", n.Name())
+		return nil
+	}
+
+	return n.writeResourceState(ctx, n.Addr)
+}
diff --git a/v1.5.7/internal/terraform/node_resource_apply_instance.go b/v1.5.7/internal/terraform/node_resource_apply_instance.go
new file mode 100644
index 0000000..98d77d8
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_apply_instance.go
@@ -0,0 +1,489 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/plans/objchange"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// NodeApplyableResourceInstance represents a resource instance that is
+// "applyable": it is ready to be applied and is represented by a diff.
+//
+// This node is for a specific instance of a resource. It will usually be
+// accompanied in the graph by a NodeApplyableResource representing its
+// containing resource, and should depend on that node to ensure that the
+// state is properly prepared to receive changes to instances.
+type NodeApplyableResourceInstance struct {
+	*NodeAbstractResourceInstance
+
+	graphNodeDeposer // implementation of GraphNodeDeposerConfig
+
+	// If this node is forced to be CreateBeforeDestroy, we need to record that
+	// in the state to.
+	ForceCreateBeforeDestroy bool
+
+	// forceReplace are resource instance addresses where the user wants to
+	// force generating a replace action. This set isn't pre-filtered, so
+	// it might contain addresses that have nothing to do with the resource
+	// that this node represents, which the node itself must therefore ignore.
+	forceReplace []addrs.AbsResourceInstance
+}
+
+var (
+	_ GraphNodeConfigResource     = (*NodeApplyableResourceInstance)(nil)
+	_ GraphNodeResourceInstance   = (*NodeApplyableResourceInstance)(nil)
+	_ GraphNodeCreator            = (*NodeApplyableResourceInstance)(nil)
+	_ GraphNodeReferencer         = (*NodeApplyableResourceInstance)(nil)
+	_ GraphNodeDeposer            = (*NodeApplyableResourceInstance)(nil)
+	_ GraphNodeExecutable         = (*NodeApplyableResourceInstance)(nil)
+	_ GraphNodeAttachDependencies = (*NodeApplyableResourceInstance)(nil)
+)
+
+// CreateBeforeDestroy returns this node's CreateBeforeDestroy status.
+func (n *NodeApplyableResourceInstance) CreateBeforeDestroy() bool {
+	if n.ForceCreateBeforeDestroy {
+		return n.ForceCreateBeforeDestroy
+	}
+
+	if n.Config != nil && n.Config.Managed != nil {
+		return n.Config.Managed.CreateBeforeDestroy
+	}
+
+	return false
+}
+
+func (n *NodeApplyableResourceInstance) ModifyCreateBeforeDestroy(v bool) error {
+	n.ForceCreateBeforeDestroy = v
+	return nil
+}
+
+// GraphNodeCreator
+func (n *NodeApplyableResourceInstance) CreateAddr() *addrs.AbsResourceInstance {
+	addr := n.ResourceInstanceAddr()
+	return &addr
+}
+
+// GraphNodeReferencer, overriding NodeAbstractResourceInstance
+func (n *NodeApplyableResourceInstance) References() []*addrs.Reference {
+	// Start with the usual resource instance implementation
+	ret := n.NodeAbstractResourceInstance.References()
+
+	// Applying a resource must also depend on the destruction of any of its
+	// dependencies, since this may for example affect the outcome of
+	// evaluating an entire list of resources with "count" set (by reducing
+	// the count).
+	//
+	// However, we can't do this in create_before_destroy mode because that
+	// would create a dependency cycle. We make a compromise here of requiring
+	// changes to be updated across two applies in this case, since the first
+	// plan will use the old values.
+	if !n.CreateBeforeDestroy() {
+		for _, ref := range ret {
+			switch tr := ref.Subject.(type) {
+			case addrs.ResourceInstance:
+				newRef := *ref // shallow copy so we can mutate
+				newRef.Subject = tr.Phase(addrs.ResourceInstancePhaseDestroy)
+				newRef.Remaining = nil // can't access attributes of something being destroyed
+				ret = append(ret, &newRef)
+			case addrs.Resource:
+				newRef := *ref // shallow copy so we can mutate
+				newRef.Subject = tr.Phase(addrs.ResourceInstancePhaseDestroy)
+				newRef.Remaining = nil // can't access attributes of something being destroyed
+				ret = append(ret, &newRef)
+			}
+		}
+	}
+
+	return ret
+}
+
+// GraphNodeAttachDependencies
+func (n *NodeApplyableResourceInstance) AttachDependencies(deps []addrs.ConfigResource) {
+	n.Dependencies = deps
+}
+
+// GraphNodeExecutable
+func (n *NodeApplyableResourceInstance) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	addr := n.ResourceInstanceAddr()
+
+	if n.Config == nil {
+		// If there is no config, and there is no change, then we have nothing
+		// to do and the change was left in the plan for informational
+		// purposes only.
+		changes := ctx.Changes()
+		csrc := changes.GetResourceInstanceChange(n.ResourceInstanceAddr(), states.CurrentGen)
+		if csrc == nil || csrc.Action == plans.NoOp {
+			log.Printf("[DEBUG] NodeApplyableResourceInstance: No config or planned change recorded for %s", n.Addr)
+			return nil
+		}
+
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Resource node has no configuration attached",
+			fmt.Sprintf(
+				"The graph node for %s has no configuration attached to it. This suggests a bug in Terraform's apply graph builder; please report it!",
+				addr,
+			),
+		))
+		return diags
+	}
+
+	// Eval info is different depending on what kind of resource this is
+	switch n.Config.Mode {
+	case addrs.ManagedResourceMode:
+		return n.managedResourceExecute(ctx)
+	case addrs.DataResourceMode:
+		return n.dataResourceExecute(ctx)
+	default:
+		panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
+	}
+}
+
+func (n *NodeApplyableResourceInstance) dataResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
+	_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	diags = diags.Append(err)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	change, err := n.readDiff(ctx, providerSchema)
+	diags = diags.Append(err)
+	if diags.HasErrors() {
+		return diags
+	}
+	// Stop early if we don't actually have a diff
+	if change == nil {
+		return diags
+	}
+	if change.Action != plans.Read && change.Action != plans.NoOp {
+		diags = diags.Append(fmt.Errorf("nonsensical planned action %#v for %s; this is a bug in Terraform", change.Action, n.Addr))
+	}
+
+	// In this particular call to applyDataSource we include our planned
+	// change, which signals that we expect this read to complete fully
+	// with no unknown values; it'll produce an error if not.
+	state, repeatData, applyDiags := n.applyDataSource(ctx, change)
+	diags = diags.Append(applyDiags)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	if state != nil {
+		// If n.applyDataSource returned a nil state object with no accompanying
+		// errors then it determined that the given change doesn't require
+		// actually reading the data (e.g. because it was already read during
+		// the plan phase) and so we're only running through here to get the
+		// extra details like precondition/postcondition checks.
+		diags = diags.Append(n.writeResourceInstanceState(ctx, state, workingState))
+		if diags.HasErrors() {
+			return diags
+		}
+	}
+
+	diags = diags.Append(n.writeChange(ctx, nil, ""))
+
+	diags = diags.Append(updateStateHook(ctx))
+
+	// Post-conditions might block further progress. We intentionally do this
+	// _after_ writing the state/diff because we want to check against
+	// the result of the operation, and to fail on future operations
+	// until the user makes the condition succeed.
+	checkDiags := evalCheckRules(
+		addrs.ResourcePostcondition,
+		n.Config.Postconditions,
+		ctx, n.ResourceInstanceAddr(),
+		repeatData,
+		tfdiags.Error,
+	)
+	diags = diags.Append(checkDiags)
+
+	return diags
+}
+
+func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
+	// Declare a bunch of variables that are used for state during
+	// evaluation. Most of this are written to by-address below.
+	var state *states.ResourceInstanceObject
+	var createBeforeDestroyEnabled bool
+	var deposedKey states.DeposedKey
+
+	addr := n.ResourceInstanceAddr().Resource
+	_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	diags = diags.Append(err)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// Get the saved diff for apply
+	diffApply, err := n.readDiff(ctx, providerSchema)
+	diags = diags.Append(err)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// We don't want to do any destroys
+	// (these are handled by NodeDestroyResourceInstance instead)
+	if diffApply == nil || diffApply.Action == plans.Delete {
+		return diags
+	}
+	if diffApply.Action == plans.Read {
+		diags = diags.Append(fmt.Errorf("nonsensical planned action %#v for %s; this is a bug in Terraform", diffApply.Action, n.Addr))
+	}
+
+	destroy := (diffApply.Action == plans.Delete || diffApply.Action.IsReplace())
+	// Get the stored action for CBD if we have a plan already
+	createBeforeDestroyEnabled = diffApply.Change.Action == plans.CreateThenDelete
+
+	if destroy && n.CreateBeforeDestroy() {
+		createBeforeDestroyEnabled = true
+	}
+
+	if createBeforeDestroyEnabled {
+		state := ctx.State()
+		if n.PreallocatedDeposedKey == states.NotDeposed {
+			deposedKey = state.DeposeResourceInstanceObject(n.Addr)
+		} else {
+			deposedKey = n.PreallocatedDeposedKey
+			state.DeposeResourceInstanceObjectForceKey(n.Addr, deposedKey)
+		}
+		log.Printf("[TRACE] managedResourceExecute: prior object for %s now deposed with key %s", n.Addr, deposedKey)
+	}
+
+	state, readDiags := n.readResourceInstanceState(ctx, n.ResourceInstanceAddr())
+	diags = diags.Append(readDiags)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// Get the saved diff
+	diff, err := n.readDiff(ctx, providerSchema)
+	diags = diags.Append(err)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// Make a new diff, in case we've learned new values in the state
+	// during apply which we can now incorporate.
+	diffApply, _, repeatData, planDiags := n.plan(ctx, diff, state, false, n.forceReplace)
+	diags = diags.Append(planDiags)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// Compare the diffs
+	diags = diags.Append(n.checkPlannedChange(ctx, diff, diffApply, providerSchema))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	diffApply = reducePlan(addr, diffApply, false)
+	// reducePlan may have simplified our planned change
+	// into a NoOp if it only requires destroying, since destroying
+	// is handled by NodeDestroyResourceInstance. If so, we'll
+	// still run through most of the logic here because we do still
+	// need to deal with other book-keeping such as marking the
+	// change as "complete", and running the author's postconditions.
+
+	diags = diags.Append(n.preApplyHook(ctx, diffApply))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// If there is no change, there was nothing to apply, and we don't need to
+	// re-write the state, but we do need to re-evaluate postconditions.
+	if diffApply.Action == plans.NoOp {
+		return diags.Append(n.managedResourcePostconditions(ctx, repeatData))
+	}
+
+	state, applyDiags := n.apply(ctx, state, diffApply, n.Config, repeatData, n.CreateBeforeDestroy())
+	diags = diags.Append(applyDiags)
+
+	// We clear the change out here so that future nodes don't see a change
+	// that is already complete.
+	err = n.writeChange(ctx, nil, "")
+	if err != nil {
+		return diags.Append(err)
+	}
+
+	state = maybeTainted(addr.Absolute(ctx.Path()), state, diffApply, diags.Err())
+
+	if state != nil {
+		// dependencies are always updated to match the configuration during apply
+		state.Dependencies = n.Dependencies
+	}
+	err = n.writeResourceInstanceState(ctx, state, workingState)
+	if err != nil {
+		return diags.Append(err)
+	}
+
+	// Run Provisioners
+	createNew := (diffApply.Action == plans.Create || diffApply.Action.IsReplace())
+	applyProvisionersDiags := n.evalApplyProvisioners(ctx, state, createNew, configs.ProvisionerWhenCreate)
+	// the provisioner errors count as port of the apply error, so we can bundle the diags
+	diags = diags.Append(applyProvisionersDiags)
+
+	state = maybeTainted(addr.Absolute(ctx.Path()), state, diffApply, diags.Err())
+
+	err = n.writeResourceInstanceState(ctx, state, workingState)
+	if err != nil {
+		return diags.Append(err)
+	}
+
+	if createBeforeDestroyEnabled && diags.HasErrors() {
+		if deposedKey == states.NotDeposed {
+			// This should never happen, and so it always indicates a bug.
+			// We should evaluate this node only if we've previously deposed
+			// an object as part of the same operation.
+			if diffApply != nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Attempt to restore non-existent deposed object",
+					fmt.Sprintf(
+						"Terraform has encountered a bug where it would need to restore a deposed object for %s without knowing a deposed object key for that object. This occurred during a %s action. This is a bug in Terraform; please report it!",
+						addr, diffApply.Action,
+					),
+				))
+			} else {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Attempt to restore non-existent deposed object",
+					fmt.Sprintf(
+						"Terraform has encountered a bug where it would need to restore a deposed object for %s without knowing a deposed object key for that object. This is a bug in Terraform; please report it!",
+						addr,
+					),
+				))
+			}
+		} else {
+			restored := ctx.State().MaybeRestoreResourceInstanceDeposed(addr.Absolute(ctx.Path()), deposedKey)
+			if restored {
+				log.Printf("[TRACE] managedResourceExecute: %s deposed object %s was restored as the current object", addr, deposedKey)
+			} else {
+				log.Printf("[TRACE] managedResourceExecute: %s deposed object %s remains deposed", addr, deposedKey)
+			}
+		}
+	}
+
+	diags = diags.Append(n.postApplyHook(ctx, state, diags.Err()))
+	diags = diags.Append(updateStateHook(ctx))
+
+	// Post-conditions might block further progress. We intentionally do this
+	// _after_ writing the state because we want to check against
+	// the result of the operation, and to fail on future operations
+	// until the user makes the condition succeed.
+	return diags.Append(n.managedResourcePostconditions(ctx, repeatData))
+}
+
+func (n *NodeApplyableResourceInstance) managedResourcePostconditions(ctx EvalContext, repeatData instances.RepetitionData) (diags tfdiags.Diagnostics) {
+
+	checkDiags := evalCheckRules(
+		addrs.ResourcePostcondition,
+		n.Config.Postconditions,
+		ctx, n.ResourceInstanceAddr(), repeatData,
+		tfdiags.Error,
+	)
+	return diags.Append(checkDiags)
+}
+
+// checkPlannedChange produces errors if the _actual_ expected value is not
+// compatible with what was recorded in the plan.
+//
+// Errors here are most often indicative of a bug in the provider, so our error
+// messages will report with that in mind. It's also possible that there's a bug
+// in Terraform's Core's own "proposed new value" code in EvalDiff.
+func (n *NodeApplyableResourceInstance) checkPlannedChange(ctx EvalContext, plannedChange, actualChange *plans.ResourceInstanceChange, providerSchema *ProviderSchema) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+	addr := n.ResourceInstanceAddr().Resource
+
+	schema, _ := providerSchema.SchemaForResourceAddr(addr.ContainingResource())
+	if schema == nil {
+		// Should be caught during validation, so we don't bother with a pretty error here
+		diags = diags.Append(fmt.Errorf("provider does not support %q", addr.Resource.Type))
+		return diags
+	}
+
+	absAddr := addr.Absolute(ctx.Path())
+
+	log.Printf("[TRACE] checkPlannedChange: Verifying that actual change (action %s) matches planned change (action %s)", actualChange.Action, plannedChange.Action)
+
+	if plannedChange.Action != actualChange.Action {
+		switch {
+		case plannedChange.Action == plans.Update && actualChange.Action == plans.NoOp:
+			// It's okay for an update to become a NoOp once we've filled in
+			// all of the unknown values, since the final values might actually
+			// match what was there before after all.
+			log.Printf("[DEBUG] After incorporating new values learned so far during apply, %s change has become NoOp", absAddr)
+
+		case (plannedChange.Action == plans.CreateThenDelete && actualChange.Action == plans.DeleteThenCreate) ||
+			(plannedChange.Action == plans.DeleteThenCreate && actualChange.Action == plans.CreateThenDelete):
+			// If the order of replacement changed, then that is a bug in terraform
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Terraform produced inconsistent final plan",
+				fmt.Sprintf(
+					"When expanding the plan for %s to include new values learned so far during apply, the planned action changed from %s to %s.\n\nThis is a bug in Terraform and should be reported.",
+					absAddr, plannedChange.Action, actualChange.Action,
+				),
+			))
+		default:
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Provider produced inconsistent final plan",
+				fmt.Sprintf(
+					"When expanding the plan for %s to include new values learned so far during apply, provider %q changed the planned action from %s to %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
+					absAddr, n.ResolvedProvider.Provider.String(),
+					plannedChange.Action, actualChange.Action,
+				),
+			))
+		}
+	}
+
+	errs := objchange.AssertObjectCompatible(schema, plannedChange.After, actualChange.After)
+	for _, err := range errs {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Provider produced inconsistent final plan",
+			fmt.Sprintf(
+				"When expanding the plan for %s to include new values learned so far during apply, provider %q produced an invalid new value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
+				absAddr, n.ResolvedProvider.Provider.String(), tfdiags.FormatError(err),
+			),
+		))
+	}
+	return diags
+}
+
+// maybeTainted takes the resource addr, new value, planned change, and possible
+// error from an apply operation and return a new instance object marked as
+// tainted if it appears that a create operation has failed.
+func maybeTainted(addr addrs.AbsResourceInstance, state *states.ResourceInstanceObject, change *plans.ResourceInstanceChange, err error) *states.ResourceInstanceObject {
+	if state == nil || change == nil || err == nil {
+		return state
+	}
+	if state.Status == states.ObjectTainted {
+		log.Printf("[TRACE] maybeTainted: %s was already tainted, so nothing to do", addr)
+		return state
+	}
+	if change.Action == plans.Create {
+		// If there are errors during a _create_ then the object is
+		// in an undefined state, and so we'll mark it as tainted so
+		// we can try again on the next run.
+		//
+		// We don't do this for other change actions because errors
+		// during updates will often not change the remote object at all.
+		// If there _were_ changes prior to the error, it's the provider's
+		// responsibility to record the effect of those changes in the
+		// object value it returned.
+		log.Printf("[TRACE] maybeTainted: %s encountered an error during creation, so it is now marked as tainted", addr)
+		return state.AsTainted()
+	}
+	return state
+}
diff --git a/v1.5.7/internal/terraform/node_resource_apply_test.go b/v1.5.7/internal/terraform/node_resource_apply_test.go
new file mode 100644
index 0000000..7dbb4f3
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_apply_test.go
@@ -0,0 +1,66 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestNodeApplyableResourceExecute(t *testing.T) {
+	state := states.NewState()
+	ctx := &MockEvalContext{
+		StateState:               state.SyncWrapper(),
+		InstanceExpanderExpander: instances.NewExpander(),
+	}
+
+	t.Run("no config", func(t *testing.T) {
+		node := NodeApplyableResource{
+			NodeAbstractResource: &NodeAbstractResource{
+				Config: nil,
+			},
+			Addr: mustAbsResourceAddr("test_instance.foo"),
+		}
+		diags := node.Execute(ctx, walkApply)
+		if diags.HasErrors() {
+			t.Fatalf("unexpected error: %s", diags.Err())
+		}
+		if !state.Empty() {
+			t.Fatalf("expected no state, got:\n %s", state.String())
+		}
+	})
+
+	t.Run("simple", func(t *testing.T) {
+
+		node := NodeApplyableResource{
+			NodeAbstractResource: &NodeAbstractResource{
+				Config: &configs.Resource{
+					Mode: addrs.ManagedResourceMode,
+					Type: "test_instance",
+					Name: "foo",
+				},
+				ResolvedProvider: addrs.AbsProviderConfig{
+					Provider: addrs.NewDefaultProvider("test"),
+					Module:   addrs.RootModule,
+				},
+			},
+			Addr: mustAbsResourceAddr("test_instance.foo"),
+		}
+		diags := node.Execute(ctx, walkApply)
+		if diags.HasErrors() {
+			t.Fatalf("unexpected error: %s", diags.Err())
+		}
+		if state.Empty() {
+			t.Fatal("expected resources in state, got empty state")
+		}
+		r := state.Resource(mustAbsResourceAddr("test_instance.foo"))
+		if r == nil {
+			t.Fatal("test_instance.foo not found in state")
+		}
+	})
+}
diff --git a/v1.5.7/internal/terraform/node_resource_destroy.go b/v1.5.7/internal/terraform/node_resource_destroy.go
new file mode 100644
index 0000000..2770d40
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_destroy.go
@@ -0,0 +1,237 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// NodeDestroyResourceInstance represents a resource instance that is to be
+// destroyed.
+type NodeDestroyResourceInstance struct {
+	*NodeAbstractResourceInstance
+
+	// If DeposedKey is set to anything other than states.NotDeposed then
+	// this node destroys a deposed object of the associated instance
+	// rather than its current object.
+	DeposedKey states.DeposedKey
+}
+
+var (
+	_ GraphNodeModuleInstance      = (*NodeDestroyResourceInstance)(nil)
+	_ GraphNodeConfigResource      = (*NodeDestroyResourceInstance)(nil)
+	_ GraphNodeResourceInstance    = (*NodeDestroyResourceInstance)(nil)
+	_ GraphNodeDestroyer           = (*NodeDestroyResourceInstance)(nil)
+	_ GraphNodeDestroyerCBD        = (*NodeDestroyResourceInstance)(nil)
+	_ GraphNodeReferenceable       = (*NodeDestroyResourceInstance)(nil)
+	_ GraphNodeReferencer          = (*NodeDestroyResourceInstance)(nil)
+	_ GraphNodeExecutable          = (*NodeDestroyResourceInstance)(nil)
+	_ GraphNodeProviderConsumer    = (*NodeDestroyResourceInstance)(nil)
+	_ GraphNodeProvisionerConsumer = (*NodeDestroyResourceInstance)(nil)
+)
+
+func (n *NodeDestroyResourceInstance) Name() string {
+	if n.DeposedKey != states.NotDeposed {
+		return fmt.Sprintf("%s (destroy deposed %s)", n.ResourceInstanceAddr(), n.DeposedKey)
+	}
+	return n.ResourceInstanceAddr().String() + " (destroy)"
+}
+
+func (n *NodeDestroyResourceInstance) ProvidedBy() (addr addrs.ProviderConfig, exact bool) {
+	if n.Addr.Resource.Resource.Mode == addrs.DataResourceMode {
+		// indicate that this node does not require a configured provider
+		return nil, true
+	}
+	return n.NodeAbstractResourceInstance.ProvidedBy()
+}
+
+// GraphNodeDestroyer
+func (n *NodeDestroyResourceInstance) DestroyAddr() *addrs.AbsResourceInstance {
+	addr := n.ResourceInstanceAddr()
+	return &addr
+}
+
+// GraphNodeDestroyerCBD
+func (n *NodeDestroyResourceInstance) CreateBeforeDestroy() bool {
+	// State takes precedence during destroy.
+	// If the resource was removed, there is no config to check.
+	// If CBD was forced from descendent, it should be saved in the state
+	// already.
+	if s := n.instanceState; s != nil {
+		if s.Current != nil {
+			return s.Current.CreateBeforeDestroy
+		}
+	}
+
+	if n.Config != nil && n.Config.Managed != nil {
+		return n.Config.Managed.CreateBeforeDestroy
+	}
+
+	return false
+}
+
+// GraphNodeDestroyerCBD
+func (n *NodeDestroyResourceInstance) ModifyCreateBeforeDestroy(v bool) error {
+	return nil
+}
+
+// GraphNodeReferenceable, overriding NodeAbstractResource
+func (n *NodeDestroyResourceInstance) ReferenceableAddrs() []addrs.Referenceable {
+	normalAddrs := n.NodeAbstractResourceInstance.ReferenceableAddrs()
+	destroyAddrs := make([]addrs.Referenceable, len(normalAddrs))
+
+	phaseType := addrs.ResourceInstancePhaseDestroy
+	if n.CreateBeforeDestroy() {
+		phaseType = addrs.ResourceInstancePhaseDestroyCBD
+	}
+
+	for i, normalAddr := range normalAddrs {
+		switch ta := normalAddr.(type) {
+		case addrs.Resource:
+			destroyAddrs[i] = ta.Phase(phaseType)
+		case addrs.ResourceInstance:
+			destroyAddrs[i] = ta.Phase(phaseType)
+		default:
+			destroyAddrs[i] = normalAddr
+		}
+	}
+
+	return destroyAddrs
+}
+
+// GraphNodeReferencer, overriding NodeAbstractResource
+func (n *NodeDestroyResourceInstance) References() []*addrs.Reference {
+	// If we have a config, then we need to include destroy-time dependencies
+	if c := n.Config; c != nil && c.Managed != nil {
+		var result []*addrs.Reference
+
+		// We include conn info and config for destroy time provisioners
+		// as dependencies that we have.
+		for _, p := range c.Managed.Provisioners {
+			schema := n.ProvisionerSchemas[p.Type]
+
+			if p.When == configs.ProvisionerWhenDestroy {
+				if p.Connection != nil {
+					result = append(result, ReferencesFromConfig(p.Connection.Config, connectionBlockSupersetSchema)...)
+				}
+				result = append(result, ReferencesFromConfig(p.Config, schema)...)
+			}
+		}
+
+		return result
+	}
+
+	return nil
+}
+
+// GraphNodeExecutable
+func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	addr := n.ResourceInstanceAddr()
+
+	// Eval info is different depending on what kind of resource this is
+	switch addr.Resource.Resource.Mode {
+	case addrs.ManagedResourceMode:
+		return n.managedResourceExecute(ctx)
+	case addrs.DataResourceMode:
+		return n.dataResourceExecute(ctx)
+	default:
+		panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
+	}
+}
+
+func (n *NodeDestroyResourceInstance) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
+	addr := n.ResourceInstanceAddr()
+
+	// Get our state
+	is := n.instanceState
+	if is == nil {
+		log.Printf("[WARN] NodeDestroyResourceInstance for %s with no state", addr)
+	}
+
+	// These vars are updated through pointers at various stages below.
+	var changeApply *plans.ResourceInstanceChange
+	var state *states.ResourceInstanceObject
+
+	_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	diags = diags.Append(err)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	changeApply, err = n.readDiff(ctx, providerSchema)
+	diags = diags.Append(err)
+	if changeApply == nil || diags.HasErrors() {
+		return diags
+	}
+
+	changeApply = reducePlan(addr.Resource, changeApply, true)
+	// reducePlan may have simplified our planned change
+	// into a NoOp if it does not require destroying.
+	if changeApply == nil || changeApply.Action == plans.NoOp {
+		return diags
+	}
+
+	state, readDiags := n.readResourceInstanceState(ctx, addr)
+	diags = diags.Append(readDiags)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// Exit early if the state object is null after reading the state
+	if state == nil || state.Value.IsNull() {
+		return diags
+	}
+
+	diags = diags.Append(n.preApplyHook(ctx, changeApply))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// Run destroy provisioners if not tainted
+	if state.Status != states.ObjectTainted {
+		applyProvisionersDiags := n.evalApplyProvisioners(ctx, state, false, configs.ProvisionerWhenDestroy)
+		diags = diags.Append(applyProvisionersDiags)
+		// keep the diags separate from the main set until we handle the cleanup
+
+		if diags.HasErrors() {
+			// If we have a provisioning error, then we just call
+			// the post-apply hook now.
+			diags = diags.Append(n.postApplyHook(ctx, state, diags.Err()))
+			return diags
+		}
+	}
+
+	// Managed resources need to be destroyed, while data sources
+	// are only removed from state.
+	// we pass a nil configuration to apply because we are destroying
+	s, d := n.apply(ctx, state, changeApply, nil, instances.RepetitionData{}, false)
+	state, diags = s, diags.Append(d)
+	// we don't return immediately here on error, so that the state can be
+	// finalized
+
+	err = n.writeResourceInstanceState(ctx, state, workingState)
+	if err != nil {
+		return diags.Append(err)
+	}
+
+	// create the err value for postApplyHook
+	diags = diags.Append(n.postApplyHook(ctx, state, diags.Err()))
+	diags = diags.Append(updateStateHook(ctx))
+	return diags
+}
+
+func (n *NodeDestroyResourceInstance) dataResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
+	log.Printf("[TRACE] NodeDestroyResourceInstance: removing state object for %s", n.Addr)
+	ctx.State().SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider)
+	return diags.Append(updateStateHook(ctx))
+}
diff --git a/v1.5.7/internal/terraform/node_resource_destroy_deposed.go b/v1.5.7/internal/terraform/node_resource_destroy_deposed.go
new file mode 100644
index 0000000..0e68ae9
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_destroy_deposed.go
@@ -0,0 +1,337 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ConcreteResourceInstanceDeposedNodeFunc is a callback type used to convert
+// an abstract resource instance to a concrete one of some type that has
+// an associated deposed object key.
+type ConcreteResourceInstanceDeposedNodeFunc func(*NodeAbstractResourceInstance, states.DeposedKey) dag.Vertex
+
+type GraphNodeDeposedResourceInstanceObject interface {
+	DeposedInstanceObjectKey() states.DeposedKey
+}
+
+// NodePlanDeposedResourceInstanceObject represents deposed resource
+// instance objects during plan. These are distinct from the primary object
+// for each resource instance since the only valid operation to do with them
+// is to destroy them.
+//
+// This node type is also used during the refresh walk to ensure that the
+// record of a deposed object is up-to-date before we plan to destroy it.
+type NodePlanDeposedResourceInstanceObject struct {
+	*NodeAbstractResourceInstance
+	DeposedKey states.DeposedKey
+
+	// skipRefresh indicates that we should skip refreshing individual instances
+	skipRefresh bool
+
+	// skipPlanChanges indicates we should skip trying to plan change actions
+	// for any instances.
+	skipPlanChanges bool
+}
+
+var (
+	_ GraphNodeDeposedResourceInstanceObject = (*NodePlanDeposedResourceInstanceObject)(nil)
+	_ GraphNodeConfigResource                = (*NodePlanDeposedResourceInstanceObject)(nil)
+	_ GraphNodeResourceInstance              = (*NodePlanDeposedResourceInstanceObject)(nil)
+	_ GraphNodeReferenceable                 = (*NodePlanDeposedResourceInstanceObject)(nil)
+	_ GraphNodeReferencer                    = (*NodePlanDeposedResourceInstanceObject)(nil)
+	_ GraphNodeExecutable                    = (*NodePlanDeposedResourceInstanceObject)(nil)
+	_ GraphNodeProviderConsumer              = (*NodePlanDeposedResourceInstanceObject)(nil)
+	_ GraphNodeProvisionerConsumer           = (*NodePlanDeposedResourceInstanceObject)(nil)
+)
+
+func (n *NodePlanDeposedResourceInstanceObject) Name() string {
+	return fmt.Sprintf("%s (deposed %s)", n.ResourceInstanceAddr().String(), n.DeposedKey)
+}
+
+func (n *NodePlanDeposedResourceInstanceObject) DeposedInstanceObjectKey() states.DeposedKey {
+	return n.DeposedKey
+}
+
+// GraphNodeReferenceable implementation, overriding the one from NodeAbstractResourceInstance
+func (n *NodePlanDeposedResourceInstanceObject) ReferenceableAddrs() []addrs.Referenceable {
+	// Deposed objects don't participate in references.
+	return nil
+}
+
+// GraphNodeReferencer implementation, overriding the one from NodeAbstractResourceInstance
+func (n *NodePlanDeposedResourceInstanceObject) References() []*addrs.Reference {
+	// We don't evaluate configuration for deposed objects, so they effectively
+	// make no references.
+	return nil
+}
+
+// GraphNodeEvalable impl.
+func (n *NodePlanDeposedResourceInstanceObject) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	log.Printf("[TRACE] NodePlanDeposedResourceInstanceObject: planning %s deposed object %s", n.Addr, n.DeposedKey)
+
+	// Read the state for the deposed resource instance
+	state, err := n.readResourceInstanceStateDeposed(ctx, n.Addr, n.DeposedKey)
+	diags = diags.Append(err)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// Note any upgrades that readResourceInstanceState might've done in the
+	// prevRunState, so that it'll conform to current schema.
+	diags = diags.Append(n.writeResourceInstanceStateDeposed(ctx, n.DeposedKey, state, prevRunState))
+	if diags.HasErrors() {
+		return diags
+	}
+	// Also the refreshState, because that should still reflect schema upgrades
+	// even if not refreshing.
+	diags = diags.Append(n.writeResourceInstanceStateDeposed(ctx, n.DeposedKey, state, refreshState))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// We don't refresh during the planDestroy walk, since that is only adding
+	// the destroy changes to the plan and the provider will not be configured
+	// at this point. The other nodes use separate types for plan and destroy,
+	// while deposed instances are always a destroy operation, so the logic
+	// here is a bit overloaded.
+	if !n.skipRefresh && op != walkPlanDestroy {
+		// Refresh this object even though it is going to be destroyed, in
+		// case it's already been deleted outside of Terraform. If this is a
+		// normal plan, providers expect a Read request to remove missing
+		// resources from the plan before apply, and may not handle a missing
+		// resource during Delete correctly. If this is a simple refresh,
+		// Terraform is expected to remove the missing resource from the state
+		// entirely
+		refreshedState, refreshDiags := n.refresh(ctx, n.DeposedKey, state)
+		diags = diags.Append(refreshDiags)
+		if diags.HasErrors() {
+			return diags
+		}
+
+		diags = diags.Append(n.writeResourceInstanceStateDeposed(ctx, n.DeposedKey, refreshedState, refreshState))
+		if diags.HasErrors() {
+			return diags
+		}
+
+		// If we refreshed then our subsequent planning should be in terms of
+		// the new object, not the original object.
+		state = refreshedState
+	}
+
+	if !n.skipPlanChanges {
+		var change *plans.ResourceInstanceChange
+		change, destroyPlanDiags := n.planDestroy(ctx, state, n.DeposedKey)
+		diags = diags.Append(destroyPlanDiags)
+		if diags.HasErrors() {
+			return diags
+		}
+
+		// NOTE: We don't check prevent_destroy for deposed objects, even
+		// though we would do so here for a "current" object, because
+		// if we've reached a point where an object is already deposed then
+		// we've already planned and partially-executed a create_before_destroy
+		// replace and we would've checked prevent_destroy at that point. We're
+		// now just need to get the deposed object destroyed, because there
+		// should be a new object already serving as its replacement.
+
+		diags = diags.Append(n.writeChange(ctx, change, n.DeposedKey))
+		if diags.HasErrors() {
+			return diags
+		}
+
+		diags = diags.Append(n.writeResourceInstanceStateDeposed(ctx, n.DeposedKey, nil, workingState))
+	} else {
+		// The working state should at least be updated with the result
+		// of upgrading and refreshing from above.
+		diags = diags.Append(n.writeResourceInstanceStateDeposed(ctx, n.DeposedKey, state, workingState))
+	}
+
+	return diags
+}
+
+// NodeDestroyDeposedResourceInstanceObject represents deposed resource
+// instance objects during apply. Nodes of this type are inserted by
+// DiffTransformer when the planned changeset contains "delete" changes for
+// deposed instance objects, and its only supported operation is to destroy
+// and then forget the associated object.
+type NodeDestroyDeposedResourceInstanceObject struct {
+	*NodeAbstractResourceInstance
+	DeposedKey states.DeposedKey
+}
+
+var (
+	_ GraphNodeDeposedResourceInstanceObject = (*NodeDestroyDeposedResourceInstanceObject)(nil)
+	_ GraphNodeConfigResource                = (*NodeDestroyDeposedResourceInstanceObject)(nil)
+	_ GraphNodeResourceInstance              = (*NodeDestroyDeposedResourceInstanceObject)(nil)
+	_ GraphNodeDestroyer                     = (*NodeDestroyDeposedResourceInstanceObject)(nil)
+	_ GraphNodeDestroyerCBD                  = (*NodeDestroyDeposedResourceInstanceObject)(nil)
+	_ GraphNodeReferenceable                 = (*NodeDestroyDeposedResourceInstanceObject)(nil)
+	_ GraphNodeReferencer                    = (*NodeDestroyDeposedResourceInstanceObject)(nil)
+	_ GraphNodeExecutable                    = (*NodeDestroyDeposedResourceInstanceObject)(nil)
+	_ GraphNodeProviderConsumer              = (*NodeDestroyDeposedResourceInstanceObject)(nil)
+	_ GraphNodeProvisionerConsumer           = (*NodeDestroyDeposedResourceInstanceObject)(nil)
+)
+
+func (n *NodeDestroyDeposedResourceInstanceObject) Name() string {
+	return fmt.Sprintf("%s (destroy deposed %s)", n.ResourceInstanceAddr(), n.DeposedKey)
+}
+
+func (n *NodeDestroyDeposedResourceInstanceObject) DeposedInstanceObjectKey() states.DeposedKey {
+	return n.DeposedKey
+}
+
+// GraphNodeReferenceable implementation, overriding the one from NodeAbstractResourceInstance
+func (n *NodeDestroyDeposedResourceInstanceObject) ReferenceableAddrs() []addrs.Referenceable {
+	// Deposed objects don't participate in references.
+	return nil
+}
+
+// GraphNodeReferencer implementation, overriding the one from NodeAbstractResourceInstance
+func (n *NodeDestroyDeposedResourceInstanceObject) References() []*addrs.Reference {
+	// We don't evaluate configuration for deposed objects, so they effectively
+	// make no references.
+	return nil
+}
+
+// GraphNodeDestroyer
+func (n *NodeDestroyDeposedResourceInstanceObject) DestroyAddr() *addrs.AbsResourceInstance {
+	addr := n.ResourceInstanceAddr()
+	return &addr
+}
+
+// GraphNodeDestroyerCBD
+func (n *NodeDestroyDeposedResourceInstanceObject) CreateBeforeDestroy() bool {
+	// A deposed instance is always CreateBeforeDestroy by definition, since
+	// we use deposed only to handle create-before-destroy.
+	return true
+}
+
+// GraphNodeDestroyerCBD
+func (n *NodeDestroyDeposedResourceInstanceObject) ModifyCreateBeforeDestroy(v bool) error {
+	if !v {
+		// Should never happen: deposed instances are _always_ create_before_destroy.
+		return fmt.Errorf("can't deactivate create_before_destroy for a deposed instance")
+	}
+	return nil
+}
+
+// GraphNodeExecutable impl.
+func (n *NodeDestroyDeposedResourceInstanceObject) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	var change *plans.ResourceInstanceChange
+
+	// Read the state for the deposed resource instance
+	state, err := n.readResourceInstanceStateDeposed(ctx, n.Addr, n.DeposedKey)
+	if err != nil {
+		return diags.Append(err)
+	}
+
+	if state == nil {
+		diags = diags.Append(fmt.Errorf("missing deposed state for %s (%s)", n.Addr, n.DeposedKey))
+		return diags
+	}
+
+	change, destroyPlanDiags := n.planDestroy(ctx, state, n.DeposedKey)
+	diags = diags.Append(destroyPlanDiags)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// Call pre-apply hook
+	diags = diags.Append(n.preApplyHook(ctx, change))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// we pass a nil configuration to apply because we are destroying
+	state, applyDiags := n.apply(ctx, state, change, nil, instances.RepetitionData{}, false)
+	diags = diags.Append(applyDiags)
+	// don't return immediately on errors, we need to handle the state
+
+	// Always write the resource back to the state deposed. If it
+	// was successfully destroyed it will be pruned. If it was not, it will
+	// be caught on the next run.
+	writeDiags := n.writeResourceInstanceState(ctx, state)
+	diags.Append(writeDiags)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	diags = diags.Append(n.postApplyHook(ctx, state, diags.Err()))
+
+	return diags.Append(updateStateHook(ctx))
+}
+
+// GraphNodeDeposer is an optional interface implemented by graph nodes that
+// might create a single new deposed object for a specific associated resource
+// instance, allowing a caller to optionally pre-allocate a DeposedKey for
+// it.
+type GraphNodeDeposer interface {
+	// SetPreallocatedDeposedKey will be called during graph construction
+	// if a particular node must use a pre-allocated deposed key if/when it
+	// "deposes" the current object of its associated resource instance.
+	SetPreallocatedDeposedKey(key states.DeposedKey)
+}
+
+// graphNodeDeposer is an embeddable implementation of GraphNodeDeposer.
+// Embed it in a node type to get automatic support for it, and then access
+// the field PreallocatedDeposedKey to access any pre-allocated key.
+type graphNodeDeposer struct {
+	PreallocatedDeposedKey states.DeposedKey
+}
+
+func (n *graphNodeDeposer) SetPreallocatedDeposedKey(key states.DeposedKey) {
+	n.PreallocatedDeposedKey = key
+}
+
+func (n *NodeDestroyDeposedResourceInstanceObject) writeResourceInstanceState(ctx EvalContext, obj *states.ResourceInstanceObject) error {
+	absAddr := n.Addr
+	key := n.DeposedKey
+	state := ctx.State()
+
+	if key == states.NotDeposed {
+		// should never happen
+		return fmt.Errorf("can't save deposed object for %s without a deposed key; this is a bug in Terraform that should be reported", absAddr)
+	}
+
+	if obj == nil {
+		// No need to encode anything: we'll just write it directly.
+		state.SetResourceInstanceDeposed(absAddr, key, nil, n.ResolvedProvider)
+		log.Printf("[TRACE] writeResourceInstanceStateDeposed: removing state object for %s deposed %s", absAddr, key)
+		return nil
+	}
+
+	_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	if err != nil {
+		return err
+	}
+	if providerSchema == nil {
+		// Should never happen, unless our state object is nil
+		panic("writeResourceInstanceStateDeposed used with no ProviderSchema object")
+	}
+
+	schema, currentVersion := providerSchema.SchemaForResourceAddr(absAddr.ContainingResource().Resource)
+	if schema == nil {
+		// It shouldn't be possible to get this far in any real scenario
+		// without a schema, but we might end up here in contrived tests that
+		// fail to set up their world properly.
+		return fmt.Errorf("failed to encode %s in state: no resource type schema available", absAddr)
+	}
+	src, err := obj.Encode(schema.ImpliedType(), currentVersion)
+	if err != nil {
+		return fmt.Errorf("failed to encode %s in state: %s", absAddr, err)
+	}
+
+	log.Printf("[TRACE] writeResourceInstanceStateDeposed: writing state object for %s deposed %s", absAddr, key)
+	state.SetResourceInstanceDeposed(absAddr, key, src, n.ResolvedProvider)
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/node_resource_destroy_deposed_test.go b/v1.5.7/internal/terraform/node_resource_destroy_deposed_test.go
new file mode 100644
index 0000000..d1be7da
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_destroy_deposed_test.go
@@ -0,0 +1,215 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestNodePlanDeposedResourceInstanceObject_Execute(t *testing.T) {
+	deposedKey := states.NewDeposedKey()
+	state := states.NewState()
+	absResource := mustResourceInstanceAddr("test_instance.foo")
+	state.Module(addrs.RootModuleInstance).SetResourceInstanceDeposed(
+		absResource.Resource,
+		deposedKey,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	p := testProvider("test")
+	p.ConfigureProvider(providers.ConfigureProviderRequest{})
+	p.UpgradeResourceStateResponse = &providers.UpgradeResourceStateResponse{
+		UpgradedState: cty.ObjectVal(map[string]cty.Value{
+			"id": cty.StringVal("bar"),
+		}),
+	}
+	ctx := &MockEvalContext{
+		StateState:        state.SyncWrapper(),
+		PrevRunStateState: state.DeepCopy().SyncWrapper(),
+		RefreshStateState: state.DeepCopy().SyncWrapper(),
+		ProviderProvider:  p,
+		ProviderSchemaSchema: &ProviderSchema{
+			ResourceTypes: map[string]*configschema.Block{
+				"test_instance": {
+					Attributes: map[string]*configschema.Attribute{
+						"id": {
+							Type:     cty.String,
+							Computed: true,
+						},
+					},
+				},
+			},
+		},
+		ChangesChanges: plans.NewChanges().SyncWrapper(),
+	}
+
+	node := NodePlanDeposedResourceInstanceObject{
+		NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
+			Addr: absResource,
+			NodeAbstractResource: NodeAbstractResource{
+				ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+			},
+		},
+		DeposedKey: deposedKey,
+	}
+	err := node.Execute(ctx, walkPlan)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	if !p.UpgradeResourceStateCalled {
+		t.Errorf("UpgradeResourceState wasn't called; should've been called to upgrade the previous run's object")
+	}
+	if !p.ReadResourceCalled {
+		t.Errorf("ReadResource wasn't called; should've been called to refresh the deposed object")
+	}
+
+	change := ctx.Changes().GetResourceInstanceChange(absResource, deposedKey)
+	if got, want := change.ChangeSrc.Action, plans.Delete; got != want {
+		t.Fatalf("wrong planned action\ngot:  %s\nwant: %s", got, want)
+	}
+}
+
+func TestNodeDestroyDeposedResourceInstanceObject_Execute(t *testing.T) {
+	deposedKey := states.NewDeposedKey()
+	state := states.NewState()
+	absResource := mustResourceInstanceAddr("test_instance.foo")
+	state.Module(addrs.RootModuleInstance).SetResourceInstanceDeposed(
+		absResource.Resource,
+		deposedKey,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(`{"id":"bar"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	schema := &ProviderSchema{
+		ResourceTypes: map[string]*configschema.Block{
+			"test_instance": {
+				Attributes: map[string]*configschema.Attribute{
+					"id": {
+						Type:     cty.String,
+						Computed: true,
+					},
+				},
+			},
+		},
+	}
+
+	p := testProvider("test")
+	p.ConfigureProvider(providers.ConfigureProviderRequest{})
+	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
+
+	p.UpgradeResourceStateResponse = &providers.UpgradeResourceStateResponse{
+		UpgradedState: cty.ObjectVal(map[string]cty.Value{
+			"id": cty.StringVal("bar"),
+		}),
+	}
+	ctx := &MockEvalContext{
+		StateState:           state.SyncWrapper(),
+		ProviderProvider:     p,
+		ProviderSchemaSchema: schema,
+		ChangesChanges:       plans.NewChanges().SyncWrapper(),
+	}
+
+	node := NodeDestroyDeposedResourceInstanceObject{
+		NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
+			Addr: absResource,
+			NodeAbstractResource: NodeAbstractResource{
+				ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+			},
+		},
+		DeposedKey: deposedKey,
+	}
+	err := node.Execute(ctx, walkApply)
+
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	if !state.Empty() {
+		t.Fatalf("resources left in state after destroy")
+	}
+}
+
+func TestNodeDestroyDeposedResourceInstanceObject_WriteResourceInstanceState(t *testing.T) {
+	state := states.NewState()
+	ctx := new(MockEvalContext)
+	ctx.StateState = state.SyncWrapper()
+	ctx.PathPath = addrs.RootModuleInstance
+	mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"id": {
+				Type:     cty.String,
+				Optional: true,
+			},
+		},
+	})
+	ctx.ProviderProvider = mockProvider
+	ctx.ProviderSchemaSchema = mockProvider.ProviderSchema()
+
+	obj := &states.ResourceInstanceObject{
+		Value: cty.ObjectVal(map[string]cty.Value{
+			"id": cty.StringVal("i-abc123"),
+		}),
+		Status: states.ObjectReady,
+	}
+	node := &NodeDestroyDeposedResourceInstanceObject{
+		NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
+			NodeAbstractResource: NodeAbstractResource{
+				ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+			},
+			Addr: mustResourceInstanceAddr("aws_instance.foo"),
+		},
+		DeposedKey: states.NewDeposedKey(),
+	}
+	err := node.writeResourceInstanceState(ctx, obj)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err.Error())
+	}
+
+	checkStateString(t, state, `
+aws_instance.foo: (1 deposed)
+  ID = <not created>
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  Deposed ID 1 = i-abc123
+	`)
+}
+
+func TestNodeDestroyDeposedResourceInstanceObject_ExecuteMissingState(t *testing.T) {
+	p := simpleMockProvider()
+	ctx := &MockEvalContext{
+		StateState:           states.NewState().SyncWrapper(),
+		ProviderProvider:     simpleMockProvider(),
+		ProviderSchemaSchema: p.ProviderSchema(),
+		ChangesChanges:       plans.NewChanges().SyncWrapper(),
+	}
+
+	node := NodeDestroyDeposedResourceInstanceObject{
+		NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
+			Addr: mustResourceInstanceAddr("test_object.foo"),
+			NodeAbstractResource: NodeAbstractResource{
+				ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+			},
+		},
+		DeposedKey: states.NewDeposedKey(),
+	}
+	err := node.Execute(ctx, walkApply)
+
+	if err == nil {
+		t.Fatal("expected error")
+	}
+}
diff --git a/v1.5.7/internal/terraform/node_resource_import.go b/v1.5.7/internal/terraform/node_resource_import.go
new file mode 100644
index 0000000..98702f1
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_import.go
@@ -0,0 +1,254 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+type graphNodeImportState struct {
+	Addr             addrs.AbsResourceInstance // Addr is the resource address to import into
+	ID               string                    // ID is the ID to import as
+	ProviderAddr     addrs.AbsProviderConfig   // Provider address given by the user, or implied by the resource type
+	ResolvedProvider addrs.AbsProviderConfig   // provider node address after resolution
+
+	states []providers.ImportedResource
+}
+
+var (
+	_ GraphNodeModulePath        = (*graphNodeImportState)(nil)
+	_ GraphNodeExecutable        = (*graphNodeImportState)(nil)
+	_ GraphNodeProviderConsumer  = (*graphNodeImportState)(nil)
+	_ GraphNodeDynamicExpandable = (*graphNodeImportState)(nil)
+)
+
+func (n *graphNodeImportState) Name() string {
+	return fmt.Sprintf("%s (import id %q)", n.Addr, n.ID)
+}
+
+// GraphNodeProviderConsumer
+func (n *graphNodeImportState) ProvidedBy() (addrs.ProviderConfig, bool) {
+	// We assume that n.ProviderAddr has been properly populated here.
+	// It's the responsibility of the code creating a graphNodeImportState
+	// to populate this, possibly by calling DefaultProviderConfig() on the
+	// resource address to infer an implied provider from the resource type
+	// name.
+	return n.ProviderAddr, false
+}
+
+// GraphNodeProviderConsumer
+func (n *graphNodeImportState) Provider() addrs.Provider {
+	// We assume that n.ProviderAddr has been properly populated here.
+	// It's the responsibility of the code creating a graphNodeImportState
+	// to populate this, possibly by calling DefaultProviderConfig() on the
+	// resource address to infer an implied provider from the resource type
+	// name.
+	return n.ProviderAddr.Provider
+}
+
+// GraphNodeProviderConsumer
+func (n *graphNodeImportState) SetProvider(addr addrs.AbsProviderConfig) {
+	n.ResolvedProvider = addr
+}
+
+// GraphNodeModuleInstance
+func (n *graphNodeImportState) Path() addrs.ModuleInstance {
+	return n.Addr.Module
+}
+
+// GraphNodeModulePath
+func (n *graphNodeImportState) ModulePath() addrs.Module {
+	return n.Addr.Module.Module()
+}
+
+// GraphNodeExecutable impl.
+func (n *graphNodeImportState) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	// Reset our states
+	n.states = nil
+
+	provider, _, err := getProvider(ctx, n.ResolvedProvider)
+	diags = diags.Append(err)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// import state
+	absAddr := n.Addr.Resource.Absolute(ctx.Path())
+
+	// Call pre-import hook
+	diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+		return h.PreImportState(absAddr, n.ID)
+	}))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	resp := provider.ImportResourceState(providers.ImportResourceStateRequest{
+		TypeName: n.Addr.Resource.Resource.Type,
+		ID:       n.ID,
+	})
+	diags = diags.Append(resp.Diagnostics)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	imported := resp.ImportedResources
+	for _, obj := range imported {
+		log.Printf("[TRACE] graphNodeImportState: import %s %q produced instance object of type %s", absAddr.String(), n.ID, obj.TypeName)
+	}
+	n.states = imported
+
+	// Call post-import hook
+	diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+		return h.PostImportState(absAddr, imported)
+	}))
+	return diags
+}
+
+// GraphNodeDynamicExpandable impl.
+//
+// We use DynamicExpand as a way to generate the subgraph of refreshes
+// and state inserts we need to do for our import state. Since they're new
+// resources they don't depend on anything else and refreshes are isolated
+// so this is nearly a perfect use case for dynamic expand.
+func (n *graphNodeImportState) DynamicExpand(ctx EvalContext) (*Graph, error) {
+	var diags tfdiags.Diagnostics
+
+	g := &Graph{Path: ctx.Path()}
+
+	// nameCounter is used to de-dup names in the state.
+	nameCounter := make(map[string]int)
+
+	// Compile the list of addresses that we'll be inserting into the state.
+	// We do this ahead of time so we can verify that we aren't importing
+	// something that already exists.
+	addrs := make([]addrs.AbsResourceInstance, len(n.states))
+	for i, state := range n.states {
+		addr := n.Addr
+		if t := state.TypeName; t != "" {
+			addr.Resource.Resource.Type = t
+		}
+
+		// Determine if we need to suffix the name to de-dup
+		key := addr.String()
+		count, ok := nameCounter[key]
+		if ok {
+			count++
+			addr.Resource.Resource.Name += fmt.Sprintf("-%d", count)
+		}
+		nameCounter[key] = count
+
+		// Add it to our list
+		addrs[i] = addr
+	}
+
+	// Verify that all the addresses are clear
+	state := ctx.State()
+	for _, addr := range addrs {
+		existing := state.ResourceInstance(addr)
+		if existing != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Resource already managed by Terraform",
+				fmt.Sprintf("Terraform is already managing a remote object for %s. To import to this address you must first remove the existing object from the state.", addr),
+			))
+			continue
+		}
+	}
+	if diags.HasErrors() {
+		// Bail out early, then.
+		return nil, diags.Err()
+	}
+
+	// For each of the states, we add a node to handle the refresh/add to state.
+	// "n.states" is populated by our own Execute with the result of
+	// ImportState. Since DynamicExpand is always called after Execute, this is
+	// safe.
+	for i, state := range n.states {
+		g.Add(&graphNodeImportStateSub{
+			TargetAddr:       addrs[i],
+			State:            state,
+			ResolvedProvider: n.ResolvedProvider,
+		})
+	}
+
+	addRootNodeToGraph(g)
+
+	// Done!
+	return g, diags.Err()
+}
+
+// graphNodeImportStateSub is the sub-node of graphNodeImportState
+// and is part of the subgraph. This node is responsible for refreshing
+// and adding a resource to the state once it is imported.
+type graphNodeImportStateSub struct {
+	TargetAddr       addrs.AbsResourceInstance
+	State            providers.ImportedResource
+	ResolvedProvider addrs.AbsProviderConfig
+}
+
+var (
+	_ GraphNodeModuleInstance = (*graphNodeImportStateSub)(nil)
+	_ GraphNodeExecutable     = (*graphNodeImportStateSub)(nil)
+)
+
+func (n *graphNodeImportStateSub) Name() string {
+	return fmt.Sprintf("import %s result", n.TargetAddr)
+}
+
+func (n *graphNodeImportStateSub) Path() addrs.ModuleInstance {
+	return n.TargetAddr.Module
+}
+
+// GraphNodeExecutable impl.
+func (n *graphNodeImportStateSub) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	// If the Ephemeral type isn't set, then it is an error
+	if n.State.TypeName == "" {
+		diags = diags.Append(fmt.Errorf("import of %s didn't set type", n.TargetAddr.String()))
+		return diags
+	}
+
+	state := n.State.AsInstanceObject()
+
+	// Refresh
+	riNode := &NodeAbstractResourceInstance{
+		Addr: n.TargetAddr,
+		NodeAbstractResource: NodeAbstractResource{
+			ResolvedProvider: n.ResolvedProvider,
+		},
+	}
+	state, refreshDiags := riNode.refresh(ctx, states.NotDeposed, state)
+	diags = diags.Append(refreshDiags)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// Verify the existance of the imported resource
+	if state.Value.IsNull() {
+		var diags tfdiags.Diagnostics
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Cannot import non-existent remote object",
+			fmt.Sprintf(
+				"While attempting to import an existing object to %q, "+
+					"the provider detected that no object exists with the given id. "+
+					"Only pre-existing objects can be imported; check that the id "+
+					"is correct and that it is associated with the provider's "+
+					"configured region or endpoint, or use \"terraform apply\" to "+
+					"create a new remote object for this resource.",
+				n.TargetAddr,
+			),
+		))
+		return diags
+	}
+
+	diags = diags.Append(riNode.writeResourceInstanceState(ctx, state, workingState))
+	return diags
+}
diff --git a/v1.5.7/internal/terraform/node_resource_plan.go b/v1.5.7/internal/terraform/node_resource_plan.go
new file mode 100644
index 0000000..a2f2354
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_plan.go
@@ -0,0 +1,422 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// nodeExpandPlannableResource represents an addrs.ConfigResource and implements
+// DynamicExpand to a subgraph containing all of the addrs.AbsResourceInstance
+// resulting from both the containing module and resource-specific expansion.
+type nodeExpandPlannableResource struct {
+	*NodeAbstractResource
+
+	// ForceCreateBeforeDestroy might be set via our GraphNodeDestroyerCBD
+	// during graph construction, if dependencies require us to force this
+	// on regardless of what the configuration says.
+	ForceCreateBeforeDestroy *bool
+
+	// skipRefresh indicates that we should skip refreshing individual instances
+	skipRefresh bool
+
+	preDestroyRefresh bool
+
+	// skipPlanChanges indicates we should skip trying to plan change actions
+	// for any instances.
+	skipPlanChanges bool
+
+	// forceReplace are resource instance addresses where the user wants to
+	// force generating a replace action. This set isn't pre-filtered, so
+	// it might contain addresses that have nothing to do with the resource
+	// that this node represents, which the node itself must therefore ignore.
+	forceReplace []addrs.AbsResourceInstance
+
+	// We attach dependencies to the Resource during refresh, since the
+	// instances are instantiated during DynamicExpand.
+	// FIXME: These would be better off converted to a generic Set data
+	// structure in the future, as we need to compare for equality and take the
+	// union of multiple groups of dependencies.
+	dependencies []addrs.ConfigResource
+
+	// legacyImportMode is set if the graph is being constructed following an
+	// invocation of the legacy "terraform import" CLI command.
+	legacyImportMode bool
+}
+
+var (
+	_ GraphNodeDestroyerCBD         = (*nodeExpandPlannableResource)(nil)
+	_ GraphNodeDynamicExpandable    = (*nodeExpandPlannableResource)(nil)
+	_ GraphNodeReferenceable        = (*nodeExpandPlannableResource)(nil)
+	_ GraphNodeReferencer           = (*nodeExpandPlannableResource)(nil)
+	_ GraphNodeConfigResource       = (*nodeExpandPlannableResource)(nil)
+	_ GraphNodeAttachResourceConfig = (*nodeExpandPlannableResource)(nil)
+	_ GraphNodeAttachDependencies   = (*nodeExpandPlannableResource)(nil)
+	_ GraphNodeTargetable           = (*nodeExpandPlannableResource)(nil)
+	_ graphNodeExpandsInstances     = (*nodeExpandPlannableResource)(nil)
+)
+
+func (n *nodeExpandPlannableResource) Name() string {
+	return n.NodeAbstractResource.Name() + " (expand)"
+}
+
+func (n *nodeExpandPlannableResource) expandsInstances() {
+}
+
+// GraphNodeAttachDependencies
+func (n *nodeExpandPlannableResource) AttachDependencies(deps []addrs.ConfigResource) {
+	n.dependencies = deps
+}
+
+// GraphNodeDestroyerCBD
+func (n *nodeExpandPlannableResource) CreateBeforeDestroy() bool {
+	if n.ForceCreateBeforeDestroy != nil {
+		return *n.ForceCreateBeforeDestroy
+	}
+
+	// If we have no config, we just assume no
+	if n.Config == nil || n.Config.Managed == nil {
+		return false
+	}
+
+	return n.Config.Managed.CreateBeforeDestroy
+}
+
+// GraphNodeDestroyerCBD
+func (n *nodeExpandPlannableResource) ModifyCreateBeforeDestroy(v bool) error {
+	n.ForceCreateBeforeDestroy = &v
+	return nil
+}
+
+func (n *nodeExpandPlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
+	var g Graph
+
+	expander := ctx.InstanceExpander()
+	moduleInstances := expander.ExpandModule(n.Addr.Module)
+
+	// Lock the state while we inspect it
+	state := ctx.State().Lock()
+
+	var orphans []*states.Resource
+	for _, res := range state.Resources(n.Addr) {
+		found := false
+		for _, m := range moduleInstances {
+			if m.Equal(res.Addr.Module) {
+				found = true
+				break
+			}
+		}
+		// The module instance of the resource in the state doesn't exist
+		// in the current config, so this whole resource is orphaned.
+		if !found {
+			orphans = append(orphans, res)
+		}
+	}
+
+	// We'll no longer use the state directly here, and the other functions
+	// we'll call below may use it so we'll release the lock.
+	state = nil
+	ctx.State().Unlock()
+
+	// The concrete resource factory we'll use for orphans
+	concreteResourceOrphan := func(a *NodeAbstractResourceInstance) *NodePlannableResourceInstanceOrphan {
+		// Add the config and state since we don't do that via transforms
+		a.Config = n.Config
+		a.ResolvedProvider = n.ResolvedProvider
+		a.Schema = n.Schema
+		a.ProvisionerSchemas = n.ProvisionerSchemas
+		a.ProviderMetas = n.ProviderMetas
+		a.Dependencies = n.dependencies
+
+		return &NodePlannableResourceInstanceOrphan{
+			NodeAbstractResourceInstance: a,
+			skipRefresh:                  n.skipRefresh,
+			skipPlanChanges:              n.skipPlanChanges,
+		}
+	}
+
+	for _, res := range orphans {
+		for key := range res.Instances {
+			addr := res.Addr.Instance(key)
+			abs := NewNodeAbstractResourceInstance(addr)
+			abs.AttachResourceState(res)
+			n := concreteResourceOrphan(abs)
+			g.Add(n)
+		}
+	}
+
+	// The above dealt with the expansion of the containing module, so now
+	// we need to deal with the expansion of the resource itself across all
+	// instances of the module.
+	//
+	// We'll gather up all of the leaf instances we learn about along the way
+	// so that we can inform the checks subsystem of which instances it should
+	// be expecting check results for, below.
+	var diags tfdiags.Diagnostics
+	instAddrs := addrs.MakeSet[addrs.Checkable]()
+	for _, module := range moduleInstances {
+		resAddr := n.Addr.Resource.Absolute(module)
+		err := n.expandResourceInstances(ctx, resAddr, &g, instAddrs)
+		diags = diags.Append(err)
+	}
+	if diags.HasErrors() {
+		return nil, diags.ErrWithWarnings()
+	}
+
+	// If this is a resource that participates in custom condition checks
+	// (i.e. it has preconditions or postconditions) then the check state
+	// wants to know the addresses of the checkable objects so that it can
+	// treat them as unknown status if we encounter an error before actually
+	// visiting the checks.
+	if checkState := ctx.Checks(); checkState.ConfigHasChecks(n.NodeAbstractResource.Addr) {
+		checkState.ReportCheckableObjects(n.NodeAbstractResource.Addr, instAddrs)
+	}
+
+	addRootNodeToGraph(&g)
+
+	return &g, diags.ErrWithWarnings()
+}
+
+// expandResourceInstances calculates the dynamic expansion for the resource
+// itself in the context of a particular module instance.
+//
+// It has several side-effects:
+//   - Adds a node to Graph g for each leaf resource instance it discovers, whether present or orphaned.
+//   - Registers the expansion of the resource in the "expander" object embedded inside EvalContext ctx.
+//   - Adds each present (non-orphaned) resource instance address to instAddrs (guaranteed to always be addrs.AbsResourceInstance, despite being declared as addrs.Checkable).
+//
+// After calling this for each of the module instances the resource appears
+// within, the caller must register the final superset instAddrs with the
+// checks subsystem so that it knows the fully expanded set of checkable
+// object instances for this resource instance.
+func (n *nodeExpandPlannableResource) expandResourceInstances(globalCtx EvalContext, resAddr addrs.AbsResource, g *Graph, instAddrs addrs.Set[addrs.Checkable]) error {
+	var diags tfdiags.Diagnostics
+
+	// The rest of our work here needs to know which module instance it's
+	// working in, so that it can evaluate expressions in the appropriate scope.
+	moduleCtx := globalCtx.WithPath(resAddr.Module)
+
+	// writeResourceState is responsible for informing the expander of what
+	// repetition mode this resource has, which allows expander.ExpandResource
+	// to work below.
+	moreDiags := n.writeResourceState(moduleCtx, resAddr)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		return diags.ErrWithWarnings()
+	}
+
+	// Before we expand our resource into potentially many resource instances,
+	// we'll verify that any mention of this resource in n.forceReplace is
+	// consistent with the repetition mode of the resource. In other words,
+	// we're aiming to catch a situation where naming a particular resource
+	// instance would require an instance key but the given address has none.
+	expander := moduleCtx.InstanceExpander()
+	instanceAddrs := expander.ExpandResource(resAddr)
+
+	// If there's a number of instances other than 1 then we definitely need
+	// an index.
+	mustHaveIndex := len(instanceAddrs) != 1
+	// If there's only one instance then we might still need an index, if the
+	// instance address has one.
+	if len(instanceAddrs) == 1 && instanceAddrs[0].Resource.Key != addrs.NoKey {
+		mustHaveIndex = true
+	}
+	if mustHaveIndex {
+		for _, candidateAddr := range n.forceReplace {
+			if candidateAddr.Resource.Key == addrs.NoKey {
+				if n.Addr.Resource.Equal(candidateAddr.Resource.Resource) {
+					switch {
+					case len(instanceAddrs) == 0:
+						// In this case there _are_ no instances to replace, so
+						// there isn't any alternative address for us to suggest.
+						diags = diags.Append(tfdiags.Sourceless(
+							tfdiags.Warning,
+							"Incompletely-matched force-replace resource instance",
+							fmt.Sprintf(
+								"Your force-replace request for %s doesn't match any resource instances because this resource doesn't have any instances.",
+								candidateAddr,
+							),
+						))
+					case len(instanceAddrs) == 1:
+						diags = diags.Append(tfdiags.Sourceless(
+							tfdiags.Warning,
+							"Incompletely-matched force-replace resource instance",
+							fmt.Sprintf(
+								"Your force-replace request for %s doesn't match any resource instances because it lacks an instance key.\n\nTo force replacement of the single declared instance, use the following option instead:\n  -replace=%q",
+								candidateAddr, instanceAddrs[0],
+							),
+						))
+					default:
+						var possibleValidOptions strings.Builder
+						for _, addr := range instanceAddrs {
+							fmt.Fprintf(&possibleValidOptions, "\n  -replace=%q", addr)
+						}
+
+						diags = diags.Append(tfdiags.Sourceless(
+							tfdiags.Warning,
+							"Incompletely-matched force-replace resource instance",
+							fmt.Sprintf(
+								"Your force-replace request for %s doesn't match any resource instances because it lacks an instance key.\n\nTo force replacement of particular instances, use one or more of the following options instead:%s",
+								candidateAddr, possibleValidOptions.String(),
+							),
+						))
+					}
+				}
+			}
+		}
+	}
+	// NOTE: The actual interpretation of n.forceReplace to produce replace
+	// actions is in the per-instance function we're about to call, because
+	// we need to evaluate it on a per-instance basis.
+
+	for _, addr := range instanceAddrs {
+		// If this resource is participating in the "checks" mechanism then our
+		// caller will need to know all of our expanded instance addresses as
+		// checkable object instances.
+		// (NOTE: instAddrs probably already has other instance addresses in it
+		// from earlier calls to this function with different resource addresses,
+		// because its purpose is to aggregate them all together into a single set.)
+		instAddrs.Add(addr)
+	}
+
+	// Our graph builder mechanism expects to always be constructing new
+	// graphs rather than adding to existing ones, so we'll first
+	// construct a subgraph just for this individual modules's instances and
+	// then we'll steal all of its nodes and edges to incorporate into our
+	// main graph which contains all of the resource instances together.
+	instG, err := n.resourceInstanceSubgraph(moduleCtx, resAddr, instanceAddrs)
+	if err != nil {
+		diags = diags.Append(err)
+		return diags.ErrWithWarnings()
+	}
+	g.Subsume(&instG.AcyclicGraph.Graph)
+
+	return diags.ErrWithWarnings()
+}
+
+func (n *nodeExpandPlannableResource) resourceInstanceSubgraph(ctx EvalContext, addr addrs.AbsResource, instanceAddrs []addrs.AbsResourceInstance) (*Graph, error) {
+	var diags tfdiags.Diagnostics
+
+	// Our graph transformers require access to the full state, so we'll
+	// temporarily lock it while we work on this.
+	state := ctx.State().Lock()
+	defer ctx.State().Unlock()
+
+	// The concrete resource factory we'll use
+	concreteResource := func(a *NodeAbstractResourceInstance) dag.Vertex {
+		var m *NodePlannableResourceInstance
+
+		// If we're in legacy import mode (the import CLI command), we only need
+		// to return the import node, not a plannable resource node.
+		if n.legacyImportMode {
+			for _, importTarget := range n.importTargets {
+				if importTarget.Addr.Equal(a.Addr) {
+					return &graphNodeImportState{
+						Addr:             importTarget.Addr,
+						ID:               importTarget.ID,
+						ResolvedProvider: n.ResolvedProvider,
+					}
+				}
+			}
+		}
+
+		// Add the config and state since we don't do that via transforms
+		a.Config = n.Config
+		a.ResolvedProvider = n.ResolvedProvider
+		a.Schema = n.Schema
+		a.ProvisionerSchemas = n.ProvisionerSchemas
+		a.ProviderMetas = n.ProviderMetas
+		a.dependsOn = n.dependsOn
+		a.Dependencies = n.dependencies
+		a.preDestroyRefresh = n.preDestroyRefresh
+		a.generateConfigPath = n.generateConfigPath
+
+		m = &NodePlannableResourceInstance{
+			NodeAbstractResourceInstance: a,
+
+			// By the time we're walking, we've figured out whether we need
+			// to force on CreateBeforeDestroy due to dependencies on other
+			// nodes that have it.
+			ForceCreateBeforeDestroy: n.CreateBeforeDestroy(),
+			skipRefresh:              n.skipRefresh,
+			skipPlanChanges:          n.skipPlanChanges,
+			forceReplace:             n.forceReplace,
+		}
+
+		for _, importTarget := range n.importTargets {
+			if importTarget.Addr.Equal(a.Addr) {
+				// If we get here, we're definitely not in legacy import mode,
+				// so go ahead and plan the resource changes including import.
+				m.importTarget = ImportTarget{
+					ID:     importTarget.ID,
+					Addr:   importTarget.Addr,
+					Config: importTarget.Config,
+				}
+			}
+		}
+
+		return m
+	}
+
+	// The concrete resource factory we'll use for orphans
+	concreteResourceOrphan := func(a *NodeAbstractResourceInstance) dag.Vertex {
+		// Add the config and state since we don't do that via transforms
+		a.Config = n.Config
+		a.ResolvedProvider = n.ResolvedProvider
+		a.Schema = n.Schema
+		a.ProvisionerSchemas = n.ProvisionerSchemas
+		a.ProviderMetas = n.ProviderMetas
+
+		return &NodePlannableResourceInstanceOrphan{
+			NodeAbstractResourceInstance: a,
+			skipRefresh:                  n.skipRefresh,
+			skipPlanChanges:              n.skipPlanChanges,
+		}
+	}
+
+	// Start creating the steps
+	steps := []GraphTransformer{
+		// Expand the count or for_each (if present)
+		&ResourceCountTransformer{
+			Concrete:      concreteResource,
+			Schema:        n.Schema,
+			Addr:          n.ResourceAddr(),
+			InstanceAddrs: instanceAddrs,
+		},
+
+		// Add the count/for_each orphans
+		&OrphanResourceInstanceCountTransformer{
+			Concrete:      concreteResourceOrphan,
+			Addr:          addr,
+			InstanceAddrs: instanceAddrs,
+			State:         state,
+		},
+
+		// Attach the state
+		&AttachStateTransformer{State: state},
+
+		// Targeting
+		&TargetsTransformer{Targets: n.Targets},
+
+		// Connect references so ordering is correct
+		&ReferenceTransformer{},
+
+		// Make sure there is a single root
+		&RootTransformer{},
+	}
+
+	// Build the graph
+	b := &BasicGraphBuilder{
+		Steps: steps,
+		Name:  "nodeExpandPlannableResource",
+	}
+	graph, diags := b.Build(addr.Module)
+	return graph, diags.ErrWithWarnings()
+}
diff --git a/v1.5.7/internal/terraform/node_resource_plan_destroy.go b/v1.5.7/internal/terraform/node_resource_plan_destroy.go
new file mode 100644
index 0000000..058d7f0
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_plan_destroy.go
@@ -0,0 +1,125 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// NodePlanDestroyableResourceInstance represents a resource that is ready
+// to be planned for destruction.
+type NodePlanDestroyableResourceInstance struct {
+	*NodeAbstractResourceInstance
+
+	// skipRefresh indicates that we should skip refreshing
+	skipRefresh bool
+}
+
+var (
+	_ GraphNodeModuleInstance       = (*NodePlanDestroyableResourceInstance)(nil)
+	_ GraphNodeReferenceable        = (*NodePlanDestroyableResourceInstance)(nil)
+	_ GraphNodeReferencer           = (*NodePlanDestroyableResourceInstance)(nil)
+	_ GraphNodeDestroyer            = (*NodePlanDestroyableResourceInstance)(nil)
+	_ GraphNodeConfigResource       = (*NodePlanDestroyableResourceInstance)(nil)
+	_ GraphNodeResourceInstance     = (*NodePlanDestroyableResourceInstance)(nil)
+	_ GraphNodeAttachResourceConfig = (*NodePlanDestroyableResourceInstance)(nil)
+	_ GraphNodeAttachResourceState  = (*NodePlanDestroyableResourceInstance)(nil)
+	_ GraphNodeExecutable           = (*NodePlanDestroyableResourceInstance)(nil)
+	_ GraphNodeProviderConsumer     = (*NodePlanDestroyableResourceInstance)(nil)
+)
+
+// GraphNodeDestroyer
+func (n *NodePlanDestroyableResourceInstance) DestroyAddr() *addrs.AbsResourceInstance {
+	addr := n.ResourceInstanceAddr()
+	return &addr
+}
+
+// GraphNodeEvalable
+func (n *NodePlanDestroyableResourceInstance) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	addr := n.ResourceInstanceAddr()
+
+	switch addr.Resource.Resource.Mode {
+	case addrs.ManagedResourceMode:
+		return n.managedResourceExecute(ctx, op)
+	case addrs.DataResourceMode:
+		return n.dataResourceExecute(ctx, op)
+	default:
+		panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
+	}
+}
+
+func (n *NodePlanDestroyableResourceInstance) managedResourceExecute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	addr := n.ResourceInstanceAddr()
+
+	// Declare a bunch of variables that are used for state during
+	// evaluation. These are written to by address in the EvalNodes we
+	// declare below.
+	var change *plans.ResourceInstanceChange
+	var state *states.ResourceInstanceObject
+
+	state, err := n.readResourceInstanceState(ctx, addr)
+	diags = diags.Append(err)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// If we are in the "skip refresh" mode then we will have skipped over our
+	// usual opportunity to update the previous run state and refresh state
+	// with the result of any provider schema upgrades, so we'll compensate
+	// by doing that here.
+	//
+	// NOTE: this is coupled with logic in Context.destroyPlan which skips
+	// running a normal plan walk when refresh is enabled. These two
+	// conditionals must agree (be exactly opposite) in order to get the
+	// correct behavior in both cases.
+	if n.skipRefresh {
+		diags = diags.Append(n.writeResourceInstanceState(ctx, state, prevRunState))
+		if diags.HasErrors() {
+			return diags
+		}
+		diags = diags.Append(n.writeResourceInstanceState(ctx, state, refreshState))
+		if diags.HasErrors() {
+			return diags
+		}
+	}
+
+	change, destroyPlanDiags := n.planDestroy(ctx, state, "")
+	diags = diags.Append(destroyPlanDiags)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	diags = diags.Append(n.checkPreventDestroy(change))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	diags = diags.Append(n.writeChange(ctx, change, ""))
+	return diags
+}
+
+func (n *NodePlanDestroyableResourceInstance) dataResourceExecute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+
+	// We may not be able to read a prior data source from the state if the
+	// schema was upgraded and we are destroying before ever refreshing that
+	// data source. Regardless, a data source  "destroy" is simply writing a
+	// null state, which we can do with a null prior state too.
+	change := &plans.ResourceInstanceChange{
+		Addr:        n.ResourceInstanceAddr(),
+		PrevRunAddr: n.prevRunAddr(ctx),
+		Change: plans.Change{
+			Action: plans.Delete,
+			Before: cty.NullVal(cty.DynamicPseudoType),
+			After:  cty.NullVal(cty.DynamicPseudoType),
+		},
+		ProviderAddr: n.ResolvedProvider,
+	}
+	return diags.Append(n.writeChange(ctx, change, ""))
+}
diff --git a/v1.5.7/internal/terraform/node_resource_plan_instance.go b/v1.5.7/internal/terraform/node_resource_plan_instance.go
new file mode 100644
index 0000000..4d211e8
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_plan_instance.go
@@ -0,0 +1,685 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+	"path/filepath"
+	"sort"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/genconfig"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// NodePlannableResourceInstance represents a _single_ resource
+// instance that is plannable. This means this represents a single
+// count index, for example.
+type NodePlannableResourceInstance struct {
+	*NodeAbstractResourceInstance
+	ForceCreateBeforeDestroy bool
+
+	// skipRefresh indicates that we should skip refreshing individual instances
+	skipRefresh bool
+
+	// skipPlanChanges indicates we should skip trying to plan change actions
+	// for any instances.
+	skipPlanChanges bool
+
+	// forceReplace are resource instance addresses where the user wants to
+	// force generating a replace action. This set isn't pre-filtered, so
+	// it might contain addresses that have nothing to do with the resource
+	// that this node represents, which the node itself must therefore ignore.
+	forceReplace []addrs.AbsResourceInstance
+
+	// replaceTriggeredBy stores references from replace_triggered_by which
+	// triggered this instance to be replaced.
+	replaceTriggeredBy []*addrs.Reference
+
+	// importTarget, if populated, contains the information necessary to plan
+	// an import of this resource.
+	importTarget ImportTarget
+}
+
+var (
+	_ GraphNodeModuleInstance       = (*NodePlannableResourceInstance)(nil)
+	_ GraphNodeReferenceable        = (*NodePlannableResourceInstance)(nil)
+	_ GraphNodeReferencer           = (*NodePlannableResourceInstance)(nil)
+	_ GraphNodeConfigResource       = (*NodePlannableResourceInstance)(nil)
+	_ GraphNodeResourceInstance     = (*NodePlannableResourceInstance)(nil)
+	_ GraphNodeAttachResourceConfig = (*NodePlannableResourceInstance)(nil)
+	_ GraphNodeAttachResourceState  = (*NodePlannableResourceInstance)(nil)
+	_ GraphNodeExecutable           = (*NodePlannableResourceInstance)(nil)
+)
+
+// GraphNodeEvalable
+func (n *NodePlannableResourceInstance) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
+	addr := n.ResourceInstanceAddr()
+
+	// Eval info is different depending on what kind of resource this is
+	switch addr.Resource.Resource.Mode {
+	case addrs.ManagedResourceMode:
+		return n.managedResourceExecute(ctx)
+	case addrs.DataResourceMode:
+		return n.dataResourceExecute(ctx)
+	default:
+		panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
+	}
+}
+
+func (n *NodePlannableResourceInstance) dataResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
+	config := n.Config
+	addr := n.ResourceInstanceAddr()
+
+	var change *plans.ResourceInstanceChange
+
+	_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	diags = diags.Append(err)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	diags = diags.Append(validateSelfRef(addr.Resource, config.Config, providerSchema))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	checkRuleSeverity := tfdiags.Error
+	if n.skipPlanChanges || n.preDestroyRefresh {
+		checkRuleSeverity = tfdiags.Warning
+	}
+
+	change, state, repeatData, planDiags := n.planDataSource(ctx, checkRuleSeverity, n.skipPlanChanges)
+	diags = diags.Append(planDiags)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// write the data source into both the refresh state and the
+	// working state
+	diags = diags.Append(n.writeResourceInstanceState(ctx, state, refreshState))
+	if diags.HasErrors() {
+		return diags
+	}
+	diags = diags.Append(n.writeResourceInstanceState(ctx, state, workingState))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	diags = diags.Append(n.writeChange(ctx, change, ""))
+
+	// Post-conditions might block further progress. We intentionally do this
+	// _after_ writing the state/diff because we want to check against
+	// the result of the operation, and to fail on future operations
+	// until the user makes the condition succeed.
+	checkDiags := evalCheckRules(
+		addrs.ResourcePostcondition,
+		n.Config.Postconditions,
+		ctx, addr, repeatData,
+		checkRuleSeverity,
+	)
+	diags = diags.Append(checkDiags)
+
+	return diags
+}
+
+func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
+	config := n.Config
+	addr := n.ResourceInstanceAddr()
+
+	var instanceRefreshState *states.ResourceInstanceObject
+
+	checkRuleSeverity := tfdiags.Error
+	if n.skipPlanChanges || n.preDestroyRefresh {
+		checkRuleSeverity = tfdiags.Warning
+	}
+
+	provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	diags = diags.Append(err)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	if config != nil {
+		diags = diags.Append(validateSelfRef(addr.Resource, config.Config, providerSchema))
+		if diags.HasErrors() {
+			return diags
+		}
+	}
+
+	importing := n.importTarget.ID != ""
+
+	if importing && n.Config == nil && len(n.generateConfigPath) == 0 {
+		// Then the user wrote an import target to a target that didn't exist.
+		if n.Addr.Module.IsRoot() {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Import block target does not exist",
+				Detail:   "The target for the given import block does not exist. If you wish to automatically generate config for this resource, use the -generate-config-out option within terraform plan. Otherwise, make sure the target resource exists within your configuration. For example:\n\n  terraform plan -generate-config-out=generated.tf",
+				Subject:  n.importTarget.Config.DeclRange.Ptr(),
+			})
+		} else {
+			// You can't generate config for a resource that is inside a
+			// module, so we will present a different error message for
+			// this case.
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Import block target does not exist",
+				Detail:   "The target for the given import block does not exist. The specified target is within a module, and must be defined as a resource within that module before anything can be imported.",
+				Subject:  n.importTarget.Config.DeclRange.Ptr(),
+			})
+		}
+		return diags
+	}
+
+	// If the resource is to be imported, we now ask the provider for an Import
+	// and a Refresh, and save the resulting state to instanceRefreshState.
+	if importing {
+		instanceRefreshState, diags = n.importState(ctx, addr, provider, providerSchema)
+	} else {
+		var readDiags tfdiags.Diagnostics
+		instanceRefreshState, readDiags = n.readResourceInstanceState(ctx, addr)
+		diags = diags.Append(readDiags)
+		if diags.HasErrors() {
+			return diags
+		}
+	}
+
+	// We'll save a snapshot of what we just read from the state into the
+	// prevRunState before we do anything else, since this will capture the
+	// result of any schema upgrading that readResourceInstanceState just did,
+	// but not include any out-of-band changes we might detect in in the
+	// refresh step below.
+	diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, prevRunState))
+	if diags.HasErrors() {
+		return diags
+	}
+	// Also the refreshState, because that should still reflect schema upgrades
+	// even if it doesn't reflect upstream changes.
+	diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, refreshState))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// In 0.13 we could be refreshing a resource with no config.
+	// We should be operating on managed resource, but check here to be certain
+	if n.Config == nil || n.Config.Managed == nil {
+		log.Printf("[WARN] managedResourceExecute: no Managed config value found in instance state for %q", n.Addr)
+	} else {
+		if instanceRefreshState != nil {
+			instanceRefreshState.CreateBeforeDestroy = n.Config.Managed.CreateBeforeDestroy || n.ForceCreateBeforeDestroy
+		}
+	}
+
+	// Refresh, maybe
+	// The import process handles its own refresh
+	if !n.skipRefresh && !importing {
+		s, refreshDiags := n.refresh(ctx, states.NotDeposed, instanceRefreshState)
+		diags = diags.Append(refreshDiags)
+		if diags.HasErrors() {
+			return diags
+		}
+
+		instanceRefreshState = s
+
+		if instanceRefreshState != nil {
+			// When refreshing we start by merging the stored dependencies and
+			// the configured dependencies. The configured dependencies will be
+			// stored to state once the changes are applied. If the plan
+			// results in no changes, we will re-write these dependencies
+			// below.
+			instanceRefreshState.Dependencies = mergeDeps(n.Dependencies, instanceRefreshState.Dependencies)
+		}
+
+		diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, refreshState))
+		if diags.HasErrors() {
+			return diags
+		}
+	}
+
+	// Plan the instance, unless we're in the refresh-only mode
+	if !n.skipPlanChanges {
+
+		// add this instance to n.forceReplace if replacement is triggered by
+		// another change
+		repData := instances.RepetitionData{}
+		switch k := addr.Resource.Key.(type) {
+		case addrs.IntKey:
+			repData.CountIndex = k.Value()
+		case addrs.StringKey:
+			repData.EachKey = k.Value()
+			repData.EachValue = cty.DynamicVal
+		}
+
+		diags = diags.Append(n.replaceTriggered(ctx, repData))
+		if diags.HasErrors() {
+			return diags
+		}
+
+		change, instancePlanState, repeatData, planDiags := n.plan(
+			ctx, nil, instanceRefreshState, n.ForceCreateBeforeDestroy, n.forceReplace,
+		)
+		diags = diags.Append(planDiags)
+		if diags.HasErrors() {
+			// If we are importing and generating a configuration, we need to
+			// ensure the change is written out so the configuration can be
+			// captured.
+			if len(n.generateConfigPath) > 0 {
+				// Update our return plan
+				change := &plans.ResourceInstanceChange{
+					Addr:         n.Addr,
+					PrevRunAddr:  n.prevRunAddr(ctx),
+					ProviderAddr: n.ResolvedProvider,
+					Change: plans.Change{
+						// we only need a placeholder, so this will be a NoOp
+						Action:          plans.NoOp,
+						Before:          instanceRefreshState.Value,
+						After:           instanceRefreshState.Value,
+						GeneratedConfig: n.generatedConfigHCL,
+					},
+				}
+				diags = diags.Append(n.writeChange(ctx, change, ""))
+			}
+
+			return diags
+		}
+
+		if importing {
+			change.Importing = &plans.Importing{ID: n.importTarget.ID}
+		}
+
+		// FIXME: here we udpate the change to reflect the reason for
+		// replacement, but we still overload forceReplace to get the correct
+		// change planned.
+		if len(n.replaceTriggeredBy) > 0 {
+			change.ActionReason = plans.ResourceInstanceReplaceByTriggers
+		}
+
+		diags = diags.Append(n.checkPreventDestroy(change))
+		if diags.HasErrors() {
+			return diags
+		}
+
+		// FIXME: it is currently important that we write resource changes to
+		// the plan (n.writeChange) before we write the corresponding state
+		// (n.writeResourceInstanceState).
+		//
+		// This is because the planned resource state will normally have the
+		// status of states.ObjectPlanned, which causes later logic to refer to
+		// the contents of the plan to retrieve the resource data. Because
+		// there is no shared lock between these two data structures, reversing
+		// the order of these writes will cause a brief window of inconsistency
+		// which can lead to a failed safety check.
+		//
+		// Future work should adjust these APIs such that it is impossible to
+		// update these two data structures incorrectly through any objects
+		// reachable via the terraform.EvalContext API.
+		diags = diags.Append(n.writeChange(ctx, change, ""))
+
+		diags = diags.Append(n.writeResourceInstanceState(ctx, instancePlanState, workingState))
+		if diags.HasErrors() {
+			return diags
+		}
+
+		// If this plan resulted in a NoOp, then apply won't have a chance to make
+		// any changes to the stored dependencies. Since this is a NoOp we know
+		// that the stored dependencies will have no effect during apply, and we can
+		// write them out now.
+		if change.Action == plans.NoOp && !depsEqual(instanceRefreshState.Dependencies, n.Dependencies) {
+			// the refresh state will be the final state for this resource, so
+			// finalize the dependencies here if they need to be updated.
+			instanceRefreshState.Dependencies = n.Dependencies
+			diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, refreshState))
+			if diags.HasErrors() {
+				return diags
+			}
+		}
+
+		// Post-conditions might block completion. We intentionally do this
+		// _after_ writing the state/diff because we want to check against
+		// the result of the operation, and to fail on future operations
+		// until the user makes the condition succeed.
+		// (Note that some preconditions will end up being skipped during
+		// planning, because their conditions depend on values not yet known.)
+		checkDiags := evalCheckRules(
+			addrs.ResourcePostcondition,
+			n.Config.Postconditions,
+			ctx, n.ResourceInstanceAddr(), repeatData,
+			checkRuleSeverity,
+		)
+		diags = diags.Append(checkDiags)
+	} else {
+		// In refresh-only mode we need to evaluate the for-each expression in
+		// order to supply the value to the pre- and post-condition check
+		// blocks. This has the unfortunate edge case of a refresh-only plan
+		// executing with a for-each map which has the same keys but different
+		// values, which could result in a post-condition check relying on that
+		// value being inaccurate. Unless we decide to store the value of the
+		// for-each expression in state, this is unavoidable.
+		forEach, _ := evaluateForEachExpression(n.Config.ForEach, ctx)
+		repeatData := EvalDataForInstanceKey(n.ResourceInstanceAddr().Resource.Key, forEach)
+
+		checkDiags := evalCheckRules(
+			addrs.ResourcePrecondition,
+			n.Config.Preconditions,
+			ctx, addr, repeatData,
+			checkRuleSeverity,
+		)
+		diags = diags.Append(checkDiags)
+
+		// Even if we don't plan changes, we do still need to at least update
+		// the working state to reflect the refresh result. If not, then e.g.
+		// any output values refering to this will not react to the drift.
+		// (Even if we didn't actually refresh above, this will still save
+		// the result of any schema upgrading we did in readResourceInstanceState.)
+		diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, workingState))
+		if diags.HasErrors() {
+			return diags
+		}
+
+		// Here we also evaluate post-conditions after updating the working
+		// state, because we want to check against the result of the refresh.
+		// Unlike in normal planning mode, these checks are still evaluated
+		// even if pre-conditions generated diagnostics, because we have no
+		// planned changes to block.
+		checkDiags = evalCheckRules(
+			addrs.ResourcePostcondition,
+			n.Config.Postconditions,
+			ctx, addr, repeatData,
+			checkRuleSeverity,
+		)
+		diags = diags.Append(checkDiags)
+	}
+
+	return diags
+}
+
+// replaceTriggered checks if this instance needs to be replace due to a change
+// in a replace_triggered_by reference. If replacement is required, the
+// instance address is added to forceReplace
+func (n *NodePlannableResourceInstance) replaceTriggered(ctx EvalContext, repData instances.RepetitionData) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+	if n.Config == nil {
+		return diags
+	}
+
+	for _, expr := range n.Config.TriggersReplacement {
+		ref, replace, evalDiags := ctx.EvaluateReplaceTriggeredBy(expr, repData)
+		diags = diags.Append(evalDiags)
+		if diags.HasErrors() {
+			continue
+		}
+
+		if replace {
+			// FIXME: forceReplace accomplishes the same goal, however we may
+			// want to communicate more information about which resource
+			// triggered the replacement in the plan.
+			// Rather than further complicating the plan method with more
+			// options, we can refactor both of these features later.
+			n.forceReplace = append(n.forceReplace, n.Addr)
+			log.Printf("[DEBUG] ReplaceTriggeredBy forcing replacement of %s due to change in %s", n.Addr, ref.DisplayString())
+
+			n.replaceTriggeredBy = append(n.replaceTriggeredBy, ref)
+			break
+		}
+	}
+
+	return diags
+}
+
+func (n *NodePlannableResourceInstance) importState(ctx EvalContext, addr addrs.AbsResourceInstance, provider providers.Interface, providerSchema *ProviderSchema) (*states.ResourceInstanceObject, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	absAddr := addr.Resource.Absolute(ctx.Path())
+
+	diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+		return h.PrePlanImport(absAddr, n.importTarget.ID)
+	}))
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	resp := provider.ImportResourceState(providers.ImportResourceStateRequest{
+		TypeName: addr.Resource.Resource.Type,
+		ID:       n.importTarget.ID,
+	})
+	diags = diags.Append(resp.Diagnostics)
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	imported := resp.ImportedResources
+
+	if len(imported) == 0 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Import returned no resources",
+			fmt.Sprintf("While attempting to import with ID %s, the provider"+
+				"returned no instance states.",
+				n.importTarget.ID,
+			),
+		))
+		return nil, diags
+	}
+	for _, obj := range imported {
+		log.Printf("[TRACE] graphNodeImportState: import %s %q produced instance object of type %s", absAddr.String(), n.importTarget.ID, obj.TypeName)
+	}
+	if len(imported) > 1 {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Multiple import states not supported",
+			fmt.Sprintf("While attempting to import with ID %s, the provider "+
+				"returned multiple resource instance states. This "+
+				"is not currently supported.",
+				n.importTarget.ID,
+			),
+		))
+		return nil, diags
+	}
+
+	// call post-import hook
+	diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
+		return h.PostPlanImport(absAddr, imported)
+	}))
+
+	if imported[0].TypeName == "" {
+		diags = diags.Append(fmt.Errorf("import of %s didn't set type", n.importTarget.Addr.String()))
+		return nil, diags
+	}
+
+	importedState := imported[0].AsInstanceObject()
+
+	if importedState.Value.IsNull() {
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Import returned null resource",
+			fmt.Sprintf("While attempting to import with ID %s, the provider"+
+				"returned an instance with no state.",
+				n.importTarget.ID,
+			),
+		))
+	}
+
+	// refresh
+	riNode := &NodeAbstractResourceInstance{
+		Addr: n.importTarget.Addr,
+		NodeAbstractResource: NodeAbstractResource{
+			ResolvedProvider: n.ResolvedProvider,
+		},
+	}
+	instanceRefreshState, refreshDiags := riNode.refresh(ctx, states.NotDeposed, importedState)
+	diags = diags.Append(refreshDiags)
+	if diags.HasErrors() {
+		return instanceRefreshState, diags
+	}
+
+	// verify the existence of the imported resource
+	if instanceRefreshState.Value.IsNull() {
+		var diags tfdiags.Diagnostics
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Cannot import non-existent remote object",
+			fmt.Sprintf(
+				"While attempting to import an existing object to %q, "+
+					"the provider detected that no object exists with the given id. "+
+					"Only pre-existing objects can be imported; check that the id "+
+					"is correct and that it is associated with the provider's "+
+					"configured region or endpoint, or use \"terraform apply\" to "+
+					"create a new remote object for this resource.",
+				n.importTarget.Addr,
+			),
+		))
+		return instanceRefreshState, diags
+	}
+
+	// If we're importing and generating config, generate it now.
+	if len(n.generateConfigPath) > 0 {
+		if n.Config != nil {
+			return instanceRefreshState, diags.Append(fmt.Errorf("tried to generate config for %s, but it already exists", n.Addr))
+		}
+
+		schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.Resource.Resource)
+		if schema == nil {
+			// Should be caught during validation, so we don't bother with a pretty error here
+			diags = diags.Append(fmt.Errorf("provider does not support resource type for %q", n.Addr))
+			return instanceRefreshState, diags
+		}
+
+		// Generate the HCL string first, then parse the HCL body from it.
+		// First we generate the contents of the resource block for use within
+		// the planning node. Then we wrap it in an enclosing resource block to
+		// pass into the plan for rendering.
+		generatedHCLAttributes, generatedDiags := n.generateHCLStringAttributes(n.Addr, instanceRefreshState, schema)
+		diags = diags.Append(generatedDiags)
+
+		n.generatedConfigHCL = genconfig.WrapResourceContents(n.Addr, generatedHCLAttributes)
+
+		// parse the "file" as HCL to get the hcl.Body
+		synthHCLFile, hclDiags := hclsyntax.ParseConfig([]byte(generatedHCLAttributes), filepath.Base(n.generateConfigPath), hcl.Pos{Byte: 0, Line: 1, Column: 1})
+		diags = diags.Append(hclDiags)
+		if hclDiags.HasErrors() {
+			return instanceRefreshState, diags
+		}
+
+		// We have to do a kind of mini parsing of the content here to correctly
+		// mark attributes like 'provider' as hidden. We only care about the
+		// resulting content, so it's remain that gets passed into the resource
+		// as the config.
+		_, remain, resourceDiags := synthHCLFile.Body.PartialContent(configs.ResourceBlockSchema)
+		diags = diags.Append(resourceDiags)
+		if resourceDiags.HasErrors() {
+			return instanceRefreshState, diags
+		}
+
+		n.Config = &configs.Resource{
+			Mode:     addrs.ManagedResourceMode,
+			Type:     n.Addr.Resource.Resource.Type,
+			Name:     n.Addr.Resource.Resource.Name,
+			Config:   remain,
+			Managed:  &configs.ManagedResource{},
+			Provider: n.ResolvedProvider.Provider,
+		}
+	}
+
+	diags = diags.Append(riNode.writeResourceInstanceState(ctx, instanceRefreshState, refreshState))
+	return instanceRefreshState, diags
+}
+
+// generateHCLStringAttributes produces a string in HCL format for the given
+// resource state and schema without the surrounding block.
+func (n *NodePlannableResourceInstance) generateHCLStringAttributes(addr addrs.AbsResourceInstance, state *states.ResourceInstanceObject, schema *configschema.Block) (string, tfdiags.Diagnostics) {
+	filteredSchema := schema.Filter(
+		configschema.FilterOr(
+			configschema.FilterReadOnlyAttribute,
+			configschema.FilterDeprecatedAttribute,
+
+			// The legacy SDK adds an Optional+Computed "id" attribute to the
+			// resource schema even if not defined in provider code.
+			// During validation, however, the presence of an extraneous "id"
+			// attribute in config will cause an error.
+			// Remove this attribute so we do not generate an "id" attribute
+			// where there is a risk that it is not in the real resource schema.
+			//
+			// TRADEOFF: Resources in which there actually is an
+			// Optional+Computed "id" attribute in the schema will have that
+			// attribute missing from generated config.
+			configschema.FilterHelperSchemaIdAttribute,
+		),
+		configschema.FilterDeprecatedBlock,
+	)
+
+	providerAddr := addrs.LocalProviderConfig{
+		LocalName: n.ResolvedProvider.Provider.Type,
+		Alias:     n.ResolvedProvider.Alias,
+	}
+
+	return genconfig.GenerateResourceContents(addr, filteredSchema, providerAddr, state.Value)
+}
+
+// mergeDeps returns the union of 2 sets of dependencies
+func mergeDeps(a, b []addrs.ConfigResource) []addrs.ConfigResource {
+	switch {
+	case len(a) == 0:
+		return b
+	case len(b) == 0:
+		return a
+	}
+
+	set := make(map[string]addrs.ConfigResource)
+
+	for _, dep := range a {
+		set[dep.String()] = dep
+	}
+
+	for _, dep := range b {
+		set[dep.String()] = dep
+	}
+
+	newDeps := make([]addrs.ConfigResource, 0, len(set))
+	for _, dep := range set {
+		newDeps = append(newDeps, dep)
+	}
+
+	return newDeps
+}
+
+func depsEqual(a, b []addrs.ConfigResource) bool {
+	if len(a) != len(b) {
+		return false
+	}
+
+	// Because we need to sort the deps to compare equality, make shallow
+	// copies to prevent concurrently modifying the array values on
+	// dependencies shared between expanded instances.
+	copyA, copyB := make([]addrs.ConfigResource, len(a)), make([]addrs.ConfigResource, len(b))
+	copy(copyA, a)
+	copy(copyB, b)
+	a, b = copyA, copyB
+
+	less := func(s []addrs.ConfigResource) func(i, j int) bool {
+		return func(i, j int) bool {
+			return s[i].String() < s[j].String()
+		}
+	}
+
+	sort.Slice(a, less(a))
+	sort.Slice(b, less(b))
+
+	for i := range a {
+		if !a[i].Equal(b[i]) {
+			return false
+		}
+	}
+	return true
+}
diff --git a/v1.5.7/internal/terraform/node_resource_plan_orphan.go b/v1.5.7/internal/terraform/node_resource_plan_orphan.go
new file mode 100644
index 0000000..4e01a49
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_plan_orphan.go
@@ -0,0 +1,288 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// NodePlannableResourceInstanceOrphan represents a resource that is "applyable":
+// it is ready to be applied and is represented by a diff.
+type NodePlannableResourceInstanceOrphan struct {
+	*NodeAbstractResourceInstance
+
+	// skipRefresh indicates that we should skip refreshing individual instances
+	skipRefresh bool
+
+	// skipPlanChanges indicates we should skip trying to plan change actions
+	// for any instances.
+	skipPlanChanges bool
+}
+
+var (
+	_ GraphNodeModuleInstance       = (*NodePlannableResourceInstanceOrphan)(nil)
+	_ GraphNodeReferenceable        = (*NodePlannableResourceInstanceOrphan)(nil)
+	_ GraphNodeReferencer           = (*NodePlannableResourceInstanceOrphan)(nil)
+	_ GraphNodeConfigResource       = (*NodePlannableResourceInstanceOrphan)(nil)
+	_ GraphNodeResourceInstance     = (*NodePlannableResourceInstanceOrphan)(nil)
+	_ GraphNodeAttachResourceConfig = (*NodePlannableResourceInstanceOrphan)(nil)
+	_ GraphNodeAttachResourceState  = (*NodePlannableResourceInstanceOrphan)(nil)
+	_ GraphNodeExecutable           = (*NodePlannableResourceInstanceOrphan)(nil)
+	_ GraphNodeProviderConsumer     = (*NodePlannableResourceInstanceOrphan)(nil)
+)
+
+func (n *NodePlannableResourceInstanceOrphan) Name() string {
+	return n.ResourceInstanceAddr().String() + " (orphan)"
+}
+
+// GraphNodeExecutable
+func (n *NodePlannableResourceInstanceOrphan) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
+	addr := n.ResourceInstanceAddr()
+
+	// Eval info is different depending on what kind of resource this is
+	switch addr.Resource.Resource.Mode {
+	case addrs.ManagedResourceMode:
+		return n.managedResourceExecute(ctx)
+	case addrs.DataResourceMode:
+		return n.dataResourceExecute(ctx)
+	default:
+		panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
+	}
+}
+
+func (n *NodePlannableResourceInstanceOrphan) ProvidedBy() (addr addrs.ProviderConfig, exact bool) {
+	if n.Addr.Resource.Resource.Mode == addrs.DataResourceMode {
+		// indicate that this node does not require a configured provider
+		return nil, true
+	}
+	return n.NodeAbstractResourceInstance.ProvidedBy()
+}
+
+func (n *NodePlannableResourceInstanceOrphan) dataResourceExecute(ctx EvalContext) tfdiags.Diagnostics {
+	// A data source that is no longer in the config is removed from the state
+	log.Printf("[TRACE] NodePlannableResourceInstanceOrphan: removing state object for %s", n.Addr)
+
+	// we need to update both the refresh state to refresh the current data
+	// source, and the working state for plan-time evaluations.
+	refreshState := ctx.RefreshState()
+	refreshState.SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider)
+
+	workingState := ctx.State()
+	workingState.SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider)
+	return nil
+}
+
+func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
+	addr := n.ResourceInstanceAddr()
+
+	oldState, readDiags := n.readResourceInstanceState(ctx, addr)
+	diags = diags.Append(readDiags)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// Note any upgrades that readResourceInstanceState might've done in the
+	// prevRunState, so that it'll conform to current schema.
+	diags = diags.Append(n.writeResourceInstanceState(ctx, oldState, prevRunState))
+	if diags.HasErrors() {
+		return diags
+	}
+	// Also the refreshState, because that should still reflect schema upgrades
+	// even if not refreshing.
+	diags = diags.Append(n.writeResourceInstanceState(ctx, oldState, refreshState))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	if !n.skipRefresh {
+		// Refresh this instance even though it is going to be destroyed, in
+		// order to catch missing resources. If this is a normal plan,
+		// providers expect a Read request to remove missing resources from the
+		// plan before apply, and may not handle a missing resource during
+		// Delete correctly.  If this is a simple refresh, Terraform is
+		// expected to remove the missing resource from the state entirely
+		refreshedState, refreshDiags := n.refresh(ctx, states.NotDeposed, oldState)
+		diags = diags.Append(refreshDiags)
+		if diags.HasErrors() {
+			return diags
+		}
+
+		diags = diags.Append(n.writeResourceInstanceState(ctx, refreshedState, refreshState))
+		if diags.HasErrors() {
+			return diags
+		}
+
+		// If we refreshed then our subsequent planning should be in terms of
+		// the new object, not the original object.
+		oldState = refreshedState
+	}
+
+	// If we're skipping planning, all we need to do is write the state. If the
+	// refresh indicates the instance no longer exists, there is also nothing
+	// to plan because there is no longer any state and it doesn't exist in the
+	// config.
+	if n.skipPlanChanges || oldState == nil || oldState.Value.IsNull() {
+		return diags.Append(n.writeResourceInstanceState(ctx, oldState, workingState))
+	}
+
+	var change *plans.ResourceInstanceChange
+	change, destroyPlanDiags := n.planDestroy(ctx, oldState, "")
+	diags = diags.Append(destroyPlanDiags)
+	if diags.HasErrors() {
+		return diags
+	}
+
+	diags = diags.Append(n.checkPreventDestroy(change))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	// We might be able to offer an approximate reason for why we are
+	// planning to delete this object. (This is best-effort; we might
+	// sometimes not have a reason.)
+	change.ActionReason = n.deleteActionReason(ctx)
+
+	diags = diags.Append(n.writeChange(ctx, change, ""))
+	if diags.HasErrors() {
+		return diags
+	}
+
+	return diags.Append(n.writeResourceInstanceState(ctx, nil, workingState))
+}
+
+func (n *NodePlannableResourceInstanceOrphan) deleteActionReason(ctx EvalContext) plans.ResourceInstanceChangeActionReason {
+	cfg := n.Config
+	if cfg == nil {
+		if !n.Addr.Equal(n.prevRunAddr(ctx)) {
+			// This means the resource was moved - see also
+			// ResourceInstanceChange.Moved() which calculates
+			// this the same way.
+			return plans.ResourceInstanceDeleteBecauseNoMoveTarget
+		}
+
+		return plans.ResourceInstanceDeleteBecauseNoResourceConfig
+	}
+
+	// If this is a resource instance inside a module instance that's no
+	// longer declared then we will have a config (because config isn't
+	// instance-specific) but the expander will know that our resource
+	// address's module path refers to an undeclared module instance.
+	if expander := ctx.InstanceExpander(); expander != nil { // (sometimes nil in MockEvalContext in tests)
+		validModuleAddr := expander.GetDeepestExistingModuleInstance(n.Addr.Module)
+		if len(validModuleAddr) != len(n.Addr.Module) {
+			// If we get here then at least one step in the resource's module
+			// path is to a module instance that doesn't exist at all, and
+			// so a missing module instance is the delete reason regardless
+			// of whether there might _also_ be a change to the resource
+			// configuration inside the module. (Conceptually the configurations
+			// inside the non-existing module instance don't exist at all,
+			// but they end up existing just as an artifact of the
+			// implementation detail that we detect module instance orphans
+			// only dynamically.)
+			return plans.ResourceInstanceDeleteBecauseNoModule
+		}
+	}
+
+	switch n.Addr.Resource.Key.(type) {
+	case nil: // no instance key at all
+		if cfg.Count != nil || cfg.ForEach != nil {
+			return plans.ResourceInstanceDeleteBecauseWrongRepetition
+		}
+	case addrs.IntKey:
+		if cfg.Count == nil {
+			// This resource isn't using "count" at all, then
+			return plans.ResourceInstanceDeleteBecauseWrongRepetition
+		}
+
+		expander := ctx.InstanceExpander()
+		if expander == nil {
+			break // only for tests that produce an incomplete MockEvalContext
+		}
+		insts := expander.ExpandResource(n.Addr.ContainingResource())
+
+		declared := false
+		for _, inst := range insts {
+			if n.Addr.Equal(inst) {
+				declared = true
+			}
+		}
+		if !declared {
+			// This instance key is outside of the configured range
+			return plans.ResourceInstanceDeleteBecauseCountIndex
+		}
+	case addrs.StringKey:
+		if cfg.ForEach == nil {
+			// This resource isn't using "for_each" at all, then
+			return plans.ResourceInstanceDeleteBecauseWrongRepetition
+		}
+
+		expander := ctx.InstanceExpander()
+		if expander == nil {
+			break // only for tests that produce an incomplete MockEvalContext
+		}
+		insts := expander.ExpandResource(n.Addr.ContainingResource())
+
+		declared := false
+		for _, inst := range insts {
+			if n.Addr.Equal(inst) {
+				declared = true
+			}
+		}
+		if !declared {
+			// This instance key is outside of the configured range
+			return plans.ResourceInstanceDeleteBecauseEachKey
+		}
+	}
+
+	// If we get here then the instance key type matches the configured
+	// repetition mode, and so we need to consider whether the key itself
+	// is within the range of the repetition construct.
+	if expander := ctx.InstanceExpander(); expander != nil { // (sometimes nil in MockEvalContext in tests)
+		// First we'll check whether our containing module instance still
+		// exists, so we can talk about that differently in the reason.
+		declared := false
+		for _, inst := range expander.ExpandModule(n.Addr.Module.Module()) {
+			if n.Addr.Module.Equal(inst) {
+				declared = true
+				break
+			}
+		}
+		if !declared {
+			return plans.ResourceInstanceDeleteBecauseNoModule
+		}
+
+		// Now we've proven that we're in a still-existing module instance,
+		// we'll see if our instance key matches something actually declared.
+		declared = false
+		for _, inst := range expander.ExpandResource(n.Addr.ContainingResource()) {
+			if n.Addr.Equal(inst) {
+				declared = true
+				break
+			}
+		}
+		if !declared {
+			// Because we already checked that the key _type_ was correct
+			// above, we can assume that any mismatch here is a range error,
+			// and thus we just need to decide which of the two range
+			// errors we're going to return.
+			switch n.Addr.Resource.Key.(type) {
+			case addrs.IntKey:
+				return plans.ResourceInstanceDeleteBecauseCountIndex
+			case addrs.StringKey:
+				return plans.ResourceInstanceDeleteBecauseEachKey
+			}
+		}
+	}
+
+	// If we didn't find any specific reason to report, we'll report "no reason"
+	// as a fallback, which means the UI should just state it'll be deleted
+	// without any explicit reasoning.
+	return plans.ResourceInstanceChangeNoReason
+}
diff --git a/v1.5.7/internal/terraform/node_resource_plan_orphan_test.go b/v1.5.7/internal/terraform/node_resource_plan_orphan_test.go
new file mode 100644
index 0000000..caf0d1d
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_plan_orphan_test.go
@@ -0,0 +1,213 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestNodeResourcePlanOrphanExecute(t *testing.T) {
+	state := states.NewState()
+	state.Module(addrs.RootModuleInstance).SetResourceInstanceCurrent(
+		addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_object",
+			Name: "foo",
+		}.Instance(addrs.NoKey),
+		&states.ResourceInstanceObjectSrc{
+			AttrsFlat: map[string]string{
+				"test_string": "foo",
+			},
+			Status: states.ObjectReady,
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+
+	p := simpleMockProvider()
+	p.ConfigureProvider(providers.ConfigureProviderRequest{})
+	ctx := &MockEvalContext{
+		StateState:               state.SyncWrapper(),
+		RefreshStateState:        state.DeepCopy().SyncWrapper(),
+		PrevRunStateState:        state.DeepCopy().SyncWrapper(),
+		InstanceExpanderExpander: instances.NewExpander(),
+		ProviderProvider:         p,
+		ProviderSchemaSchema: &ProviderSchema{
+			ResourceTypes: map[string]*configschema.Block{
+				"test_object": simpleTestSchema(),
+			},
+		},
+		ChangesChanges: plans.NewChanges().SyncWrapper(),
+	}
+
+	node := NodePlannableResourceInstanceOrphan{
+		NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
+			NodeAbstractResource: NodeAbstractResource{
+				ResolvedProvider: addrs.AbsProviderConfig{
+					Provider: addrs.NewDefaultProvider("test"),
+					Module:   addrs.RootModule,
+				},
+			},
+			Addr: mustResourceInstanceAddr("test_object.foo"),
+		},
+	}
+	diags := node.Execute(ctx, walkApply)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+	if !state.Empty() {
+		t.Fatalf("expected empty state, got %s", state.String())
+	}
+}
+
+func TestNodeResourcePlanOrphanExecute_alreadyDeleted(t *testing.T) {
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_object",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	state := states.NewState()
+	state.Module(addrs.RootModuleInstance).SetResourceInstanceCurrent(
+		addr.Resource,
+		&states.ResourceInstanceObjectSrc{
+			AttrsFlat: map[string]string{
+				"test_string": "foo",
+			},
+			Status: states.ObjectReady,
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	refreshState := state.DeepCopy()
+	prevRunState := state.DeepCopy()
+	changes := plans.NewChanges()
+
+	p := simpleMockProvider()
+	p.ConfigureProvider(providers.ConfigureProviderRequest{})
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.NullVal(p.GetProviderSchemaResponse.ResourceTypes["test_string"].Block.ImpliedType()),
+	}
+	ctx := &MockEvalContext{
+		StateState:               state.SyncWrapper(),
+		RefreshStateState:        refreshState.SyncWrapper(),
+		PrevRunStateState:        prevRunState.SyncWrapper(),
+		InstanceExpanderExpander: instances.NewExpander(),
+		ProviderProvider:         p,
+		ProviderSchemaSchema: &ProviderSchema{
+			ResourceTypes: map[string]*configschema.Block{
+				"test_object": simpleTestSchema(),
+			},
+		},
+		ChangesChanges: changes.SyncWrapper(),
+	}
+
+	node := NodePlannableResourceInstanceOrphan{
+		NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
+			NodeAbstractResource: NodeAbstractResource{
+				ResolvedProvider: addrs.AbsProviderConfig{
+					Provider: addrs.NewDefaultProvider("test"),
+					Module:   addrs.RootModule,
+				},
+			},
+			Addr: mustResourceInstanceAddr("test_object.foo"),
+		},
+	}
+	diags := node.Execute(ctx, walkPlan)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+	if !state.Empty() {
+		t.Fatalf("expected empty state, got %s", state.String())
+	}
+
+	if got := prevRunState.ResourceInstance(addr); got == nil {
+		t.Errorf("no entry for %s in the prev run state; should still be present", addr)
+	}
+	if got := refreshState.ResourceInstance(addr); got != nil {
+		t.Errorf("refresh state has entry for %s; should've been removed", addr)
+	}
+	if got := changes.ResourceInstance(addr); got != nil {
+		t.Errorf("there should be no change for the %s instance, got %s", addr, got.Action)
+	}
+}
+
+// This test describes a situation which should not be possible, as this node
+// should never work on deposed instances. However, a bug elsewhere resulted in
+// this code path being exercised and triggered a panic. As a result, the
+// assertions at the end of the test are minimal, as the behaviour (aside from
+// not panicking) is unspecified.
+func TestNodeResourcePlanOrphanExecute_deposed(t *testing.T) {
+	addr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_object",
+		Name: "foo",
+	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
+
+	state := states.NewState()
+	state.Module(addrs.RootModuleInstance).SetResourceInstanceDeposed(
+		addr.Resource,
+		states.NewDeposedKey(),
+		&states.ResourceInstanceObjectSrc{
+			AttrsFlat: map[string]string{
+				"test_string": "foo",
+			},
+			Status: states.ObjectReady,
+		},
+		addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("test"),
+			Module:   addrs.RootModule,
+		},
+	)
+	refreshState := state.DeepCopy()
+	prevRunState := state.DeepCopy()
+	changes := plans.NewChanges()
+
+	p := simpleMockProvider()
+	p.ConfigureProvider(providers.ConfigureProviderRequest{})
+	p.ReadResourceResponse = &providers.ReadResourceResponse{
+		NewState: cty.NullVal(p.GetProviderSchemaResponse.ResourceTypes["test_string"].Block.ImpliedType()),
+	}
+	ctx := &MockEvalContext{
+		StateState:               state.SyncWrapper(),
+		RefreshStateState:        refreshState.SyncWrapper(),
+		PrevRunStateState:        prevRunState.SyncWrapper(),
+		InstanceExpanderExpander: instances.NewExpander(),
+		ProviderProvider:         p,
+		ProviderSchemaSchema: &ProviderSchema{
+			ResourceTypes: map[string]*configschema.Block{
+				"test_object": simpleTestSchema(),
+			},
+		},
+		ChangesChanges: changes.SyncWrapper(),
+	}
+
+	node := NodePlannableResourceInstanceOrphan{
+		NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
+			NodeAbstractResource: NodeAbstractResource{
+				ResolvedProvider: addrs.AbsProviderConfig{
+					Provider: addrs.NewDefaultProvider("test"),
+					Module:   addrs.RootModule,
+				},
+			},
+			Addr: mustResourceInstanceAddr("test_object.foo"),
+		},
+	}
+	diags := node.Execute(ctx, walkPlan)
+	if diags.HasErrors() {
+		t.Fatalf("unexpected error: %s", diags.Err())
+	}
+}
diff --git a/v1.5.7/internal/terraform/node_resource_validate.go b/v1.5.7/internal/terraform/node_resource_validate.go
new file mode 100644
index 0000000..372eb19
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_validate.go
@@ -0,0 +1,599 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/didyoumean"
+	"github.com/hashicorp/terraform/internal/instances"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// NodeValidatableResource represents a resource that is used for validation
+// only.
+type NodeValidatableResource struct {
+	*NodeAbstractResource
+}
+
+var (
+	_ GraphNodeModuleInstance            = (*NodeValidatableResource)(nil)
+	_ GraphNodeExecutable                = (*NodeValidatableResource)(nil)
+	_ GraphNodeReferenceable             = (*NodeValidatableResource)(nil)
+	_ GraphNodeReferencer                = (*NodeValidatableResource)(nil)
+	_ GraphNodeConfigResource            = (*NodeValidatableResource)(nil)
+	_ GraphNodeAttachResourceConfig      = (*NodeValidatableResource)(nil)
+	_ GraphNodeAttachProviderMetaConfigs = (*NodeValidatableResource)(nil)
+)
+
+func (n *NodeValidatableResource) Path() addrs.ModuleInstance {
+	// There is no expansion during validation, so we evaluate everything as
+	// single module instances.
+	return n.Addr.Module.UnkeyedInstanceShim()
+}
+
+// GraphNodeEvalable
+func (n *NodeValidatableResource) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	if n.Config == nil {
+		return diags
+	}
+
+	diags = diags.Append(n.validateResource(ctx))
+
+	diags = diags.Append(n.validateCheckRules(ctx, n.Config))
+
+	if managed := n.Config.Managed; managed != nil {
+		// Validate all the provisioners
+		for _, p := range managed.Provisioners {
+			if p.Connection == nil {
+				p.Connection = n.Config.Managed.Connection
+			} else if n.Config.Managed.Connection != nil {
+				p.Connection.Config = configs.MergeBodies(n.Config.Managed.Connection.Config, p.Connection.Config)
+			}
+
+			// Validate Provisioner Config
+			diags = diags.Append(n.validateProvisioner(ctx, p))
+			if diags.HasErrors() {
+				return diags
+			}
+		}
+	}
+	return diags
+}
+
+// validateProvisioner validates the configuration of a provisioner belonging to
+// a resource. The provisioner config is expected to contain the merged
+// connection configurations.
+func (n *NodeValidatableResource) validateProvisioner(ctx EvalContext, p *configs.Provisioner) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	provisioner, err := ctx.Provisioner(p.Type)
+	if err != nil {
+		diags = diags.Append(err)
+		return diags
+	}
+
+	if provisioner == nil {
+		return diags.Append(fmt.Errorf("provisioner %s not initialized", p.Type))
+	}
+	provisionerSchema, err := ctx.ProvisionerSchema(p.Type)
+	if err != nil {
+		return diags.Append(fmt.Errorf("failed to read schema for provisioner %s: %s", p.Type, err))
+	}
+	if provisionerSchema == nil {
+		return diags.Append(fmt.Errorf("provisioner %s has no schema", p.Type))
+	}
+
+	// Validate the provisioner's own config first
+	configVal, _, configDiags := n.evaluateBlock(ctx, p.Config, provisionerSchema)
+	diags = diags.Append(configDiags)
+
+	if configVal == cty.NilVal {
+		// Should never happen for a well-behaved EvaluateBlock implementation
+		return diags.Append(fmt.Errorf("EvaluateBlock returned nil value"))
+	}
+
+	// Use unmarked value for validate request
+	unmarkedConfigVal, _ := configVal.UnmarkDeep()
+	req := provisioners.ValidateProvisionerConfigRequest{
+		Config: unmarkedConfigVal,
+	}
+
+	resp := provisioner.ValidateProvisionerConfig(req)
+	diags = diags.Append(resp.Diagnostics)
+
+	if p.Connection != nil {
+		// We can't comprehensively validate the connection config since its
+		// final structure is decided by the communicator and we can't instantiate
+		// that until we have a complete instance state. However, we *can* catch
+		// configuration keys that are not valid for *any* communicator, catching
+		// typos early rather than waiting until we actually try to run one of
+		// the resource's provisioners.
+		_, _, connDiags := n.evaluateBlock(ctx, p.Connection.Config, connectionBlockSupersetSchema)
+		diags = diags.Append(connDiags)
+	}
+	return diags
+}
+
+func (n *NodeValidatableResource) evaluateBlock(ctx EvalContext, body hcl.Body, schema *configschema.Block) (cty.Value, hcl.Body, tfdiags.Diagnostics) {
+	keyData, selfAddr := n.stubRepetitionData(n.Config.Count != nil, n.Config.ForEach != nil)
+
+	return ctx.EvaluateBlock(body, schema, selfAddr, keyData)
+}
+
+// connectionBlockSupersetSchema is a schema representing the superset of all
+// possible arguments for "connection" blocks across all supported connection
+// types.
+//
+// This currently lives here because we've not yet updated our communicator
+// subsystem to be aware of schema itself. Once that is done, we can remove
+// this and use a type-specific schema from the communicator to validate
+// exactly what is expected for a given connection type.
+var connectionBlockSupersetSchema = &configschema.Block{
+	Attributes: map[string]*configschema.Attribute{
+		// NOTE: "type" is not included here because it's treated special
+		// by the config loader and stored away in a separate field.
+
+		// Common attributes for both connection types
+		"host": {
+			Type:     cty.String,
+			Required: true,
+		},
+		"type": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"user": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"password": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"port": {
+			Type:     cty.Number,
+			Optional: true,
+		},
+		"timeout": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"script_path": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		// For type=ssh only (enforced in ssh communicator)
+		"target_platform": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"private_key": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"certificate": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"host_key": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"agent": {
+			Type:     cty.Bool,
+			Optional: true,
+		},
+		"agent_identity": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"proxy_scheme": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"proxy_host": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"proxy_port": {
+			Type:     cty.Number,
+			Optional: true,
+		},
+		"proxy_user_name": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"proxy_user_password": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"bastion_host": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"bastion_host_key": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"bastion_port": {
+			Type:     cty.Number,
+			Optional: true,
+		},
+		"bastion_user": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"bastion_password": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"bastion_private_key": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"bastion_certificate": {
+			Type:     cty.String,
+			Optional: true,
+		},
+
+		// For type=winrm only (enforced in winrm communicator)
+		"https": {
+			Type:     cty.Bool,
+			Optional: true,
+		},
+		"insecure": {
+			Type:     cty.Bool,
+			Optional: true,
+		},
+		"cacert": {
+			Type:     cty.String,
+			Optional: true,
+		},
+		"use_ntlm": {
+			Type:     cty.Bool,
+			Optional: true,
+		},
+	},
+}
+
+func (n *NodeValidatableResource) validateResource(ctx EvalContext) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
+	diags = diags.Append(err)
+	if diags.HasErrors() {
+		return diags
+	}
+	if providerSchema == nil {
+		diags = diags.Append(fmt.Errorf("validateResource has nil schema for %s", n.Addr))
+		return diags
+	}
+
+	keyData := EvalDataForNoInstanceKey
+
+	switch {
+	case n.Config.Count != nil:
+		// If the config block has count, we'll evaluate with an unknown
+		// number as count.index so we can still type check even though
+		// we won't expand count until the plan phase.
+		keyData = InstanceKeyEvalData{
+			CountIndex: cty.UnknownVal(cty.Number),
+		}
+
+		// Basic type-checking of the count argument. More complete validation
+		// of this will happen when we DynamicExpand during the plan walk.
+		countDiags := validateCount(ctx, n.Config.Count)
+		diags = diags.Append(countDiags)
+
+	case n.Config.ForEach != nil:
+		keyData = InstanceKeyEvalData{
+			EachKey:   cty.UnknownVal(cty.String),
+			EachValue: cty.UnknownVal(cty.DynamicPseudoType),
+		}
+
+		// Evaluate the for_each expression here so we can expose the diagnostics
+		forEachDiags := validateForEach(ctx, n.Config.ForEach)
+		diags = diags.Append(forEachDiags)
+	}
+
+	diags = diags.Append(validateDependsOn(ctx, n.Config.DependsOn))
+
+	// Validate the provider_meta block for the provider this resource
+	// belongs to, if there is one.
+	//
+	// Note: this will return an error for every resource a provider
+	// uses in a module, if the provider_meta for that module is
+	// incorrect. The only way to solve this that we've found is to
+	// insert a new ProviderMeta graph node in the graph, and make all
+	// that provider's resources in the module depend on the node. That's
+	// an awful heavy hammer to swing for this feature, which should be
+	// used only in limited cases with heavy coordination with the
+	// Terraform team, so we're going to defer that solution for a future
+	// enhancement to this functionality.
+	/*
+		if n.ProviderMetas != nil {
+			if m, ok := n.ProviderMetas[n.ProviderAddr.ProviderConfig.Type]; ok && m != nil {
+				// if the provider doesn't support this feature, throw an error
+				if (*n.ProviderSchema).ProviderMeta == nil {
+					diags = diags.Append(&hcl.Diagnostic{
+						Severity: hcl.DiagError,
+						Summary:  fmt.Sprintf("Provider %s doesn't support provider_meta", cfg.ProviderConfigAddr()),
+						Detail:   fmt.Sprintf("The resource %s belongs to a provider that doesn't support provider_meta blocks", n.Addr),
+						Subject:  &m.ProviderRange,
+					})
+				} else {
+					_, _, metaDiags := ctx.EvaluateBlock(m.Config, (*n.ProviderSchema).ProviderMeta, nil, EvalDataForNoInstanceKey)
+					diags = diags.Append(metaDiags)
+				}
+			}
+		}
+	*/
+	// BUG(paddy): we're not validating provider_meta blocks on EvalValidate right now
+	// because the ProviderAddr for the resource isn't available on the EvalValidate
+	// struct.
+
+	// Provider entry point varies depending on resource mode, because
+	// managed resources and data resources are two distinct concepts
+	// in the provider abstraction.
+	switch n.Config.Mode {
+	case addrs.ManagedResourceMode:
+		schema, _ := providerSchema.SchemaForResourceType(n.Config.Mode, n.Config.Type)
+		if schema == nil {
+			var suggestion string
+			if dSchema, _ := providerSchema.SchemaForResourceType(addrs.DataResourceMode, n.Config.Type); dSchema != nil {
+				suggestion = fmt.Sprintf("\n\nDid you intend to use the data source %q? If so, declare this using a \"data\" block instead of a \"resource\" block.", n.Config.Type)
+			} else if len(providerSchema.ResourceTypes) > 0 {
+				suggestions := make([]string, 0, len(providerSchema.ResourceTypes))
+				for name := range providerSchema.ResourceTypes {
+					suggestions = append(suggestions, name)
+				}
+				if suggestion = didyoumean.NameSuggestion(n.Config.Type, suggestions); suggestion != "" {
+					suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
+				}
+			}
+
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid resource type",
+				Detail:   fmt.Sprintf("The provider %s does not support resource type %q.%s", n.Provider().ForDisplay(), n.Config.Type, suggestion),
+				Subject:  &n.Config.TypeRange,
+			})
+			return diags
+		}
+
+		configVal, _, valDiags := ctx.EvaluateBlock(n.Config.Config, schema, nil, keyData)
+		diags = diags.Append(valDiags)
+		if valDiags.HasErrors() {
+			return diags
+		}
+
+		if n.Config.Managed != nil { // can be nil only in tests with poorly-configured mocks
+			for _, traversal := range n.Config.Managed.IgnoreChanges {
+				// validate the ignore_changes traversals apply.
+				moreDiags := schema.StaticValidateTraversal(traversal)
+				diags = diags.Append(moreDiags)
+
+				// ignore_changes cannot be used for Computed attributes,
+				// unless they are also Optional.
+				// If the traversal was valid, convert it to a cty.Path and
+				// use that to check whether the Attribute is Computed and
+				// non-Optional.
+				if !diags.HasErrors() {
+					path := traversalToPath(traversal)
+
+					attrSchema := schema.AttributeByPath(path)
+
+					if attrSchema != nil && !attrSchema.Optional && attrSchema.Computed {
+						// ignore_changes uses absolute traversal syntax in config despite
+						// using relative traversals, so we strip the leading "." added by
+						// FormatCtyPath for a better error message.
+						attrDisplayPath := strings.TrimPrefix(tfdiags.FormatCtyPath(path), ".")
+
+						diags = diags.Append(&hcl.Diagnostic{
+							Severity: hcl.DiagWarning,
+							Summary:  "Redundant ignore_changes element",
+							Detail:   fmt.Sprintf("Adding an attribute name to ignore_changes tells Terraform to ignore future changes to the argument in configuration after the object has been created, retaining the value originally configured.\n\nThe attribute %s is decided by the provider alone and therefore there can be no configured value to compare with. Including this attribute in ignore_changes has no effect. Remove the attribute from ignore_changes to quiet this warning.", attrDisplayPath),
+							Subject:  &n.Config.TypeRange,
+						})
+					}
+				}
+			}
+		}
+
+		// Use unmarked value for validate request
+		unmarkedConfigVal, _ := configVal.UnmarkDeep()
+		req := providers.ValidateResourceConfigRequest{
+			TypeName: n.Config.Type,
+			Config:   unmarkedConfigVal,
+		}
+
+		resp := provider.ValidateResourceConfig(req)
+		diags = diags.Append(resp.Diagnostics.InConfigBody(n.Config.Config, n.Addr.String()))
+
+	case addrs.DataResourceMode:
+		schema, _ := providerSchema.SchemaForResourceType(n.Config.Mode, n.Config.Type)
+		if schema == nil {
+			var suggestion string
+			if dSchema, _ := providerSchema.SchemaForResourceType(addrs.ManagedResourceMode, n.Config.Type); dSchema != nil {
+				suggestion = fmt.Sprintf("\n\nDid you intend to use the managed resource type %q? If so, declare this using a \"resource\" block instead of a \"data\" block.", n.Config.Type)
+			} else if len(providerSchema.DataSources) > 0 {
+				suggestions := make([]string, 0, len(providerSchema.DataSources))
+				for name := range providerSchema.DataSources {
+					suggestions = append(suggestions, name)
+				}
+				if suggestion = didyoumean.NameSuggestion(n.Config.Type, suggestions); suggestion != "" {
+					suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
+				}
+			}
+
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid data source",
+				Detail:   fmt.Sprintf("The provider %s does not support data source %q.%s", n.Provider().ForDisplay(), n.Config.Type, suggestion),
+				Subject:  &n.Config.TypeRange,
+			})
+			return diags
+		}
+
+		configVal, _, valDiags := ctx.EvaluateBlock(n.Config.Config, schema, nil, keyData)
+		diags = diags.Append(valDiags)
+		if valDiags.HasErrors() {
+			return diags
+		}
+
+		// Use unmarked value for validate request
+		unmarkedConfigVal, _ := configVal.UnmarkDeep()
+		req := providers.ValidateDataResourceConfigRequest{
+			TypeName: n.Config.Type,
+			Config:   unmarkedConfigVal,
+		}
+
+		resp := provider.ValidateDataResourceConfig(req)
+		diags = diags.Append(resp.Diagnostics.InConfigBody(n.Config.Config, n.Addr.String()))
+	}
+
+	return diags
+}
+
+func (n *NodeValidatableResource) evaluateExpr(ctx EvalContext, expr hcl.Expression, wantTy cty.Type, self addrs.Referenceable, keyData instances.RepetitionData) (cty.Value, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+
+	refs, refDiags := lang.ReferencesInExpr(expr)
+	diags = diags.Append(refDiags)
+
+	scope := ctx.EvaluationScope(self, nil, keyData)
+
+	hclCtx, moreDiags := scope.EvalContext(refs)
+	diags = diags.Append(moreDiags)
+
+	result, hclDiags := expr.Value(hclCtx)
+	diags = diags.Append(hclDiags)
+
+	return result, diags
+}
+
+func (n *NodeValidatableResource) stubRepetitionData(hasCount, hasForEach bool) (instances.RepetitionData, addrs.Referenceable) {
+	keyData := EvalDataForNoInstanceKey
+	selfAddr := n.ResourceAddr().Resource.Instance(addrs.NoKey)
+
+	if n.Config.Count != nil {
+		// For a resource that has count, we allow count.index but don't
+		// know at this stage what it will return.
+		keyData = InstanceKeyEvalData{
+			CountIndex: cty.UnknownVal(cty.Number),
+		}
+
+		// "self" can't point to an unknown key, but we'll force it to be
+		// key 0 here, which should return an unknown value of the
+		// expected type since none of these elements are known at this
+		// point anyway.
+		selfAddr = n.ResourceAddr().Resource.Instance(addrs.IntKey(0))
+	} else if n.Config.ForEach != nil {
+		// For a resource that has for_each, we allow each.value and each.key
+		// but don't know at this stage what it will return.
+		keyData = InstanceKeyEvalData{
+			EachKey:   cty.UnknownVal(cty.String),
+			EachValue: cty.DynamicVal,
+		}
+
+		// "self" can't point to an unknown key, but we'll force it to be
+		// key "" here, which should return an unknown value of the
+		// expected type since none of these elements are known at
+		// this point anyway.
+		selfAddr = n.ResourceAddr().Resource.Instance(addrs.StringKey(""))
+	}
+
+	return keyData, selfAddr
+}
+
+func (n *NodeValidatableResource) validateCheckRules(ctx EvalContext, config *configs.Resource) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	keyData, selfAddr := n.stubRepetitionData(n.Config.Count != nil, n.Config.ForEach != nil)
+
+	for _, cr := range config.Preconditions {
+		_, conditionDiags := n.evaluateExpr(ctx, cr.Condition, cty.Bool, nil, keyData)
+		diags = diags.Append(conditionDiags)
+
+		_, errorMessageDiags := n.evaluateExpr(ctx, cr.ErrorMessage, cty.Bool, nil, keyData)
+		diags = diags.Append(errorMessageDiags)
+	}
+
+	for _, cr := range config.Postconditions {
+		_, conditionDiags := n.evaluateExpr(ctx, cr.Condition, cty.Bool, selfAddr, keyData)
+		diags = diags.Append(conditionDiags)
+
+		_, errorMessageDiags := n.evaluateExpr(ctx, cr.ErrorMessage, cty.Bool, selfAddr, keyData)
+		diags = diags.Append(errorMessageDiags)
+	}
+
+	return diags
+}
+
+func validateCount(ctx EvalContext, expr hcl.Expression) (diags tfdiags.Diagnostics) {
+	val, countDiags := evaluateCountExpressionValue(expr, ctx)
+	// If the value isn't known then that's the best we can do for now, but
+	// we'll check more thoroughly during the plan walk
+	if !val.IsKnown() {
+		return diags
+	}
+
+	if countDiags.HasErrors() {
+		diags = diags.Append(countDiags)
+	}
+
+	return diags
+}
+
+func validateForEach(ctx EvalContext, expr hcl.Expression) (diags tfdiags.Diagnostics) {
+	val, forEachDiags := evaluateForEachExpressionValue(expr, ctx, true)
+	// If the value isn't known then that's the best we can do for now, but
+	// we'll check more thoroughly during the plan walk
+	if !val.IsKnown() {
+		return diags
+	}
+
+	if forEachDiags.HasErrors() {
+		diags = diags.Append(forEachDiags)
+	}
+
+	return diags
+}
+
+func validateDependsOn(ctx EvalContext, dependsOn []hcl.Traversal) (diags tfdiags.Diagnostics) {
+	for _, traversal := range dependsOn {
+		ref, refDiags := addrs.ParseRef(traversal)
+		diags = diags.Append(refDiags)
+		if !refDiags.HasErrors() && len(ref.Remaining) != 0 {
+			diags = diags.Append(&hcl.Diagnostic{
+				Severity: hcl.DiagError,
+				Summary:  "Invalid depends_on reference",
+				Detail:   "References in depends_on must be to a whole object (resource, etc), not to an attribute of an object.",
+				Subject:  ref.Remaining.SourceRange().Ptr(),
+			})
+		}
+
+		// The ref must also refer to something that exists. To test that,
+		// we'll just eval it and count on the fact that our evaluator will
+		// detect references to non-existent objects.
+		if !diags.HasErrors() {
+			scope := ctx.EvaluationScope(nil, nil, EvalDataForNoInstanceKey)
+			if scope != nil { // sometimes nil in tests, due to incomplete mocks
+				_, refDiags = scope.EvalReference(ref, cty.DynamicPseudoType)
+				diags = diags.Append(refDiags)
+			}
+		}
+	}
+	return diags
+}
diff --git a/v1.5.7/internal/terraform/node_resource_validate_test.go b/v1.5.7/internal/terraform/node_resource_validate_test.go
new file mode 100644
index 0000000..12262af
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_resource_validate_test.go
@@ -0,0 +1,638 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"errors"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcltest"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/lang/marks"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestNodeValidatableResource_ValidateProvisioner_valid(t *testing.T) {
+	ctx := &MockEvalContext{}
+	ctx.installSimpleEval()
+	mp := &MockProvisioner{}
+	ps := &configschema.Block{}
+	ctx.ProvisionerSchemaSchema = ps
+	ctx.ProvisionerProvisioner = mp
+
+	pc := &configs.Provisioner{
+		Type:   "baz",
+		Config: hcl.EmptyBody(),
+		Connection: &configs.Connection{
+			Config: configs.SynthBody("", map[string]cty.Value{
+				"host": cty.StringVal("localhost"),
+				"type": cty.StringVal("ssh"),
+				"port": cty.NumberIntVal(10022),
+			}),
+		},
+	}
+
+	rc := &configs.Resource{
+		Mode:   addrs.ManagedResourceMode,
+		Type:   "test_foo",
+		Name:   "bar",
+		Config: configs.SynthBody("", map[string]cty.Value{}),
+	}
+
+	node := NodeValidatableResource{
+		NodeAbstractResource: &NodeAbstractResource{
+			Addr:   mustConfigResourceAddr("test_foo.bar"),
+			Config: rc,
+		},
+	}
+
+	diags := node.validateProvisioner(ctx, pc)
+	if diags.HasErrors() {
+		t.Fatalf("node.Eval failed: %s", diags.Err())
+	}
+	if !mp.ValidateProvisionerConfigCalled {
+		t.Fatalf("p.ValidateProvisionerConfig not called")
+	}
+}
+
+func TestNodeValidatableResource_ValidateProvisioner__warning(t *testing.T) {
+	ctx := &MockEvalContext{}
+	ctx.installSimpleEval()
+	mp := &MockProvisioner{}
+	ps := &configschema.Block{}
+	ctx.ProvisionerSchemaSchema = ps
+	ctx.ProvisionerProvisioner = mp
+
+	pc := &configs.Provisioner{
+		Type:   "baz",
+		Config: hcl.EmptyBody(),
+	}
+
+	rc := &configs.Resource{
+		Mode:    addrs.ManagedResourceMode,
+		Type:    "test_foo",
+		Name:    "bar",
+		Config:  configs.SynthBody("", map[string]cty.Value{}),
+		Managed: &configs.ManagedResource{},
+	}
+
+	node := NodeValidatableResource{
+		NodeAbstractResource: &NodeAbstractResource{
+			Addr:   mustConfigResourceAddr("test_foo.bar"),
+			Config: rc,
+		},
+	}
+
+	{
+		var diags tfdiags.Diagnostics
+		diags = diags.Append(tfdiags.SimpleWarning("foo is deprecated"))
+		mp.ValidateProvisionerConfigResponse = provisioners.ValidateProvisionerConfigResponse{
+			Diagnostics: diags,
+		}
+	}
+
+	diags := node.validateProvisioner(ctx, pc)
+	if len(diags) != 1 {
+		t.Fatalf("wrong number of diagnostics in %s; want one warning", diags.ErrWithWarnings())
+	}
+
+	if got, want := diags[0].Description().Summary, mp.ValidateProvisionerConfigResponse.Diagnostics[0].Description().Summary; got != want {
+		t.Fatalf("wrong warning %q; want %q", got, want)
+	}
+}
+
+func TestNodeValidatableResource_ValidateProvisioner__connectionInvalid(t *testing.T) {
+	ctx := &MockEvalContext{}
+	ctx.installSimpleEval()
+	mp := &MockProvisioner{}
+	ps := &configschema.Block{}
+	ctx.ProvisionerSchemaSchema = ps
+	ctx.ProvisionerProvisioner = mp
+
+	pc := &configs.Provisioner{
+		Type:   "baz",
+		Config: hcl.EmptyBody(),
+		Connection: &configs.Connection{
+			Config: configs.SynthBody("", map[string]cty.Value{
+				"type":             cty.StringVal("ssh"),
+				"bananananananana": cty.StringVal("foo"),
+				"bazaz":            cty.StringVal("bar"),
+			}),
+		},
+	}
+
+	rc := &configs.Resource{
+		Mode:    addrs.ManagedResourceMode,
+		Type:    "test_foo",
+		Name:    "bar",
+		Config:  configs.SynthBody("", map[string]cty.Value{}),
+		Managed: &configs.ManagedResource{},
+	}
+
+	node := NodeValidatableResource{
+		NodeAbstractResource: &NodeAbstractResource{
+			Addr:   mustConfigResourceAddr("test_foo.bar"),
+			Config: rc,
+		},
+	}
+
+	diags := node.validateProvisioner(ctx, pc)
+	if !diags.HasErrors() {
+		t.Fatalf("node.Eval succeeded; want error")
+	}
+	if len(diags) != 3 {
+		t.Fatalf("wrong number of diagnostics; want two errors\n\n%s", diags.Err())
+	}
+
+	errStr := diags.Err().Error()
+	if !(strings.Contains(errStr, "bananananananana") && strings.Contains(errStr, "bazaz")) {
+		t.Fatalf("wrong errors %q; want something about each of our invalid connInfo keys", errStr)
+	}
+}
+
+func TestNodeValidatableResource_ValidateResource_managedResource(t *testing.T) {
+	mp := simpleMockProvider()
+	mp.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+		if got, want := req.TypeName, "test_object"; got != want {
+			t.Fatalf("wrong resource type\ngot:  %#v\nwant: %#v", got, want)
+		}
+		if got, want := req.Config.GetAttr("test_string"), cty.StringVal("bar"); !got.RawEquals(want) {
+			t.Fatalf("wrong value for test_string\ngot:  %#v\nwant: %#v", got, want)
+		}
+		if got, want := req.Config.GetAttr("test_number"), cty.NumberIntVal(2); !got.RawEquals(want) {
+			t.Fatalf("wrong value for test_number\ngot:  %#v\nwant: %#v", got, want)
+		}
+		return providers.ValidateResourceConfigResponse{}
+	}
+
+	p := providers.Interface(mp)
+	rc := &configs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "test_object",
+		Name: "foo",
+		Config: configs.SynthBody("", map[string]cty.Value{
+			"test_string": cty.StringVal("bar"),
+			"test_number": cty.NumberIntVal(2).Mark(marks.Sensitive),
+		}),
+	}
+	node := NodeValidatableResource{
+		NodeAbstractResource: &NodeAbstractResource{
+			Addr:             mustConfigResourceAddr("test_foo.bar"),
+			Config:           rc,
+			ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+		},
+	}
+
+	ctx := &MockEvalContext{}
+	ctx.installSimpleEval()
+	ctx.ProviderSchemaSchema = mp.ProviderSchema()
+	ctx.ProviderProvider = p
+
+	err := node.validateResource(ctx)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !mp.ValidateResourceConfigCalled {
+		t.Fatal("Expected ValidateResourceConfig to be called, but it was not!")
+	}
+}
+
+func TestNodeValidatableResource_ValidateResource_managedResourceCount(t *testing.T) {
+	// Setup
+	mp := simpleMockProvider()
+	mp.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+		if got, want := req.TypeName, "test_object"; got != want {
+			t.Fatalf("wrong resource type\ngot:  %#v\nwant: %#v", got, want)
+		}
+		if got, want := req.Config.GetAttr("test_string"), cty.StringVal("bar"); !got.RawEquals(want) {
+			t.Fatalf("wrong value for test_string\ngot:  %#v\nwant: %#v", got, want)
+		}
+		return providers.ValidateResourceConfigResponse{}
+	}
+
+	p := providers.Interface(mp)
+
+	ctx := &MockEvalContext{}
+	ctx.installSimpleEval()
+	ctx.ProviderSchemaSchema = mp.ProviderSchema()
+	ctx.ProviderProvider = p
+
+	tests := []struct {
+		name  string
+		count hcl.Expression
+	}{
+		{
+			"simple count",
+			hcltest.MockExprLiteral(cty.NumberIntVal(2)),
+		},
+		{
+			"marked count value",
+			hcltest.MockExprLiteral(cty.NumberIntVal(3).Mark("marked")),
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			rc := &configs.Resource{
+				Mode:  addrs.ManagedResourceMode,
+				Type:  "test_object",
+				Name:  "foo",
+				Count: test.count,
+				Config: configs.SynthBody("", map[string]cty.Value{
+					"test_string": cty.StringVal("bar"),
+				}),
+			}
+			node := NodeValidatableResource{
+				NodeAbstractResource: &NodeAbstractResource{
+					Addr:             mustConfigResourceAddr("test_foo.bar"),
+					Config:           rc,
+					ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+				},
+			}
+
+			diags := node.validateResource(ctx)
+			if diags.HasErrors() {
+				t.Fatalf("err: %s", diags.Err())
+			}
+
+			if !mp.ValidateResourceConfigCalled {
+				t.Fatal("Expected ValidateResourceConfig to be called, but it was not!")
+			}
+		})
+	}
+}
+
+func TestNodeValidatableResource_ValidateResource_dataSource(t *testing.T) {
+	mp := simpleMockProvider()
+	mp.ValidateDataResourceConfigFn = func(req providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse {
+		if got, want := req.TypeName, "test_object"; got != want {
+			t.Fatalf("wrong resource type\ngot:  %#v\nwant: %#v", got, want)
+		}
+		if got, want := req.Config.GetAttr("test_string"), cty.StringVal("bar"); !got.RawEquals(want) {
+			t.Fatalf("wrong value for test_string\ngot:  %#v\nwant: %#v", got, want)
+		}
+		if got, want := req.Config.GetAttr("test_number"), cty.NumberIntVal(2); !got.RawEquals(want) {
+			t.Fatalf("wrong value for test_number\ngot:  %#v\nwant: %#v", got, want)
+		}
+		return providers.ValidateDataResourceConfigResponse{}
+	}
+
+	p := providers.Interface(mp)
+	rc := &configs.Resource{
+		Mode: addrs.DataResourceMode,
+		Type: "test_object",
+		Name: "foo",
+		Config: configs.SynthBody("", map[string]cty.Value{
+			"test_string": cty.StringVal("bar"),
+			"test_number": cty.NumberIntVal(2).Mark(marks.Sensitive),
+		}),
+	}
+
+	node := NodeValidatableResource{
+		NodeAbstractResource: &NodeAbstractResource{
+			Addr:             mustConfigResourceAddr("test_foo.bar"),
+			Config:           rc,
+			ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+		},
+	}
+
+	ctx := &MockEvalContext{}
+	ctx.installSimpleEval()
+	ctx.ProviderSchemaSchema = mp.ProviderSchema()
+	ctx.ProviderProvider = p
+
+	diags := node.validateResource(ctx)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+
+	if !mp.ValidateDataResourceConfigCalled {
+		t.Fatal("Expected ValidateDataSourceConfig to be called, but it was not!")
+	}
+}
+
+func TestNodeValidatableResource_ValidateResource_valid(t *testing.T) {
+	mp := simpleMockProvider()
+	mp.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+		return providers.ValidateResourceConfigResponse{}
+	}
+
+	p := providers.Interface(mp)
+	rc := &configs.Resource{
+		Mode:   addrs.ManagedResourceMode,
+		Type:   "test_object",
+		Name:   "foo",
+		Config: configs.SynthBody("", map[string]cty.Value{}),
+	}
+	node := NodeValidatableResource{
+		NodeAbstractResource: &NodeAbstractResource{
+			Addr:             mustConfigResourceAddr("test_object.foo"),
+			Config:           rc,
+			ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+		},
+	}
+
+	ctx := &MockEvalContext{}
+	ctx.installSimpleEval()
+	ctx.ProviderSchemaSchema = mp.ProviderSchema()
+	ctx.ProviderProvider = p
+
+	diags := node.validateResource(ctx)
+	if diags.HasErrors() {
+		t.Fatalf("err: %s", diags.Err())
+	}
+}
+
+func TestNodeValidatableResource_ValidateResource_warningsAndErrorsPassedThrough(t *testing.T) {
+	mp := simpleMockProvider()
+	mp.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+		var diags tfdiags.Diagnostics
+		diags = diags.Append(tfdiags.SimpleWarning("warn"))
+		diags = diags.Append(errors.New("err"))
+		return providers.ValidateResourceConfigResponse{
+			Diagnostics: diags,
+		}
+	}
+
+	p := providers.Interface(mp)
+	rc := &configs.Resource{
+		Mode:   addrs.ManagedResourceMode,
+		Type:   "test_object",
+		Name:   "foo",
+		Config: configs.SynthBody("", map[string]cty.Value{}),
+	}
+	node := NodeValidatableResource{
+		NodeAbstractResource: &NodeAbstractResource{
+			Addr:             mustConfigResourceAddr("test_foo.bar"),
+			Config:           rc,
+			ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+		},
+	}
+
+	ctx := &MockEvalContext{}
+	ctx.installSimpleEval()
+	ctx.ProviderSchemaSchema = mp.ProviderSchema()
+	ctx.ProviderProvider = p
+
+	diags := node.validateResource(ctx)
+	if !diags.HasErrors() {
+		t.Fatal("unexpected success; want error")
+	}
+
+	bySeverity := map[tfdiags.Severity]tfdiags.Diagnostics{}
+	for _, diag := range diags {
+		bySeverity[diag.Severity()] = append(bySeverity[diag.Severity()], diag)
+	}
+	if len(bySeverity[tfdiags.Warning]) != 1 || bySeverity[tfdiags.Warning][0].Description().Summary != "warn" {
+		t.Errorf("Expected 1 warning 'warn', got: %s", bySeverity[tfdiags.Warning].ErrWithWarnings())
+	}
+	if len(bySeverity[tfdiags.Error]) != 1 || bySeverity[tfdiags.Error][0].Description().Summary != "err" {
+		t.Errorf("Expected 1 error 'err', got: %s", bySeverity[tfdiags.Error].Err())
+	}
+}
+
+func TestNodeValidatableResource_ValidateResource_invalidDependsOn(t *testing.T) {
+	mp := simpleMockProvider()
+	mp.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+		return providers.ValidateResourceConfigResponse{}
+	}
+
+	// We'll check a _valid_ config first, to make sure we're not failing
+	// for some other reason, and then make it invalid.
+	p := providers.Interface(mp)
+	rc := &configs.Resource{
+		Mode:   addrs.ManagedResourceMode,
+		Type:   "test_object",
+		Name:   "foo",
+		Config: configs.SynthBody("", map[string]cty.Value{}),
+		DependsOn: []hcl.Traversal{
+			// Depending on path.module is pointless, since it is immediately
+			// available, but we allow all of the referencable addrs here
+			// for consistency: referencing them is harmless, and avoids the
+			// need for us to document a different subset of addresses that
+			// are valid in depends_on.
+			// For the sake of this test, it's a valid address we can use that
+			// doesn't require something else to exist in the configuration.
+			{
+				hcl.TraverseRoot{
+					Name: "path",
+				},
+				hcl.TraverseAttr{
+					Name: "module",
+				},
+			},
+		},
+	}
+	node := NodeValidatableResource{
+		NodeAbstractResource: &NodeAbstractResource{
+			Addr:             mustConfigResourceAddr("test_foo.bar"),
+			Config:           rc,
+			ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+		},
+	}
+
+	ctx := &MockEvalContext{}
+	ctx.installSimpleEval()
+
+	ctx.ProviderSchemaSchema = mp.ProviderSchema()
+	ctx.ProviderProvider = p
+
+	diags := node.validateResource(ctx)
+	if diags.HasErrors() {
+		t.Fatalf("error for supposedly-valid config: %s", diags.ErrWithWarnings())
+	}
+
+	// Now we'll make it invalid by adding additional traversal steps at
+	// the end of what we're referencing. This is intended to catch the
+	// situation where the user tries to depend on e.g. a specific resource
+	// attribute, rather than the whole resource, like aws_instance.foo.id.
+	rc.DependsOn = append(rc.DependsOn, hcl.Traversal{
+		hcl.TraverseRoot{
+			Name: "path",
+		},
+		hcl.TraverseAttr{
+			Name: "module",
+		},
+		hcl.TraverseAttr{
+			Name: "extra",
+		},
+	})
+
+	diags = node.validateResource(ctx)
+	if !diags.HasErrors() {
+		t.Fatal("no error for invalid depends_on")
+	}
+	if got, want := diags.Err().Error(), "Invalid depends_on reference"; !strings.Contains(got, want) {
+		t.Fatalf("wrong error\ngot:  %s\nwant: Message containing %q", got, want)
+	}
+
+	// Test for handling an unknown root without attribute, like a
+	// typo that omits the dot inbetween "path.module".
+	rc.DependsOn = append(rc.DependsOn, hcl.Traversal{
+		hcl.TraverseRoot{
+			Name: "pathmodule",
+		},
+	})
+
+	diags = node.validateResource(ctx)
+	if !diags.HasErrors() {
+		t.Fatal("no error for invalid depends_on")
+	}
+	if got, want := diags.Err().Error(), "Invalid depends_on reference"; !strings.Contains(got, want) {
+		t.Fatalf("wrong error\ngot:  %s\nwant: Message containing %q", got, want)
+	}
+}
+
+func TestNodeValidatableResource_ValidateResource_invalidIgnoreChangesNonexistent(t *testing.T) {
+	mp := simpleMockProvider()
+	mp.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+		return providers.ValidateResourceConfigResponse{}
+	}
+
+	// We'll check a _valid_ config first, to make sure we're not failing
+	// for some other reason, and then make it invalid.
+	p := providers.Interface(mp)
+	rc := &configs.Resource{
+		Mode:   addrs.ManagedResourceMode,
+		Type:   "test_object",
+		Name:   "foo",
+		Config: configs.SynthBody("", map[string]cty.Value{}),
+		Managed: &configs.ManagedResource{
+			IgnoreChanges: []hcl.Traversal{
+				{
+					hcl.TraverseAttr{
+						Name: "test_string",
+					},
+				},
+			},
+		},
+	}
+	node := NodeValidatableResource{
+		NodeAbstractResource: &NodeAbstractResource{
+			Addr:             mustConfigResourceAddr("test_foo.bar"),
+			Config:           rc,
+			ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+		},
+	}
+
+	ctx := &MockEvalContext{}
+	ctx.installSimpleEval()
+
+	ctx.ProviderSchemaSchema = mp.ProviderSchema()
+	ctx.ProviderProvider = p
+
+	diags := node.validateResource(ctx)
+	if diags.HasErrors() {
+		t.Fatalf("error for supposedly-valid config: %s", diags.ErrWithWarnings())
+	}
+
+	// Now we'll make it invalid by attempting to ignore a nonexistent
+	// attribute.
+	rc.Managed.IgnoreChanges = append(rc.Managed.IgnoreChanges, hcl.Traversal{
+		hcl.TraverseAttr{
+			Name: "nonexistent",
+		},
+	})
+
+	diags = node.validateResource(ctx)
+	if !diags.HasErrors() {
+		t.Fatal("no error for invalid ignore_changes")
+	}
+	if got, want := diags.Err().Error(), "Unsupported attribute: This object has no argument, nested block, or exported attribute named \"nonexistent\""; !strings.Contains(got, want) {
+		t.Fatalf("wrong error\ngot:  %s\nwant: Message containing %q", got, want)
+	}
+}
+
+func TestNodeValidatableResource_ValidateResource_invalidIgnoreChangesComputed(t *testing.T) {
+	// construct a schema with a computed attribute
+	ms := &configschema.Block{
+		Attributes: map[string]*configschema.Attribute{
+			"test_string": {
+				Type:     cty.String,
+				Optional: true,
+			},
+			"computed_string": {
+				Type:     cty.String,
+				Computed: true,
+				Optional: false,
+			},
+		},
+	}
+
+	mp := &MockProvider{
+		GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+			Provider: providers.Schema{Block: ms},
+			ResourceTypes: map[string]providers.Schema{
+				"test_object": providers.Schema{Block: ms},
+			},
+		},
+	}
+
+	mp.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
+		return providers.ValidateResourceConfigResponse{}
+	}
+
+	// We'll check a _valid_ config first, to make sure we're not failing
+	// for some other reason, and then make it invalid.
+	p := providers.Interface(mp)
+	rc := &configs.Resource{
+		Mode:   addrs.ManagedResourceMode,
+		Type:   "test_object",
+		Name:   "foo",
+		Config: configs.SynthBody("", map[string]cty.Value{}),
+		Managed: &configs.ManagedResource{
+			IgnoreChanges: []hcl.Traversal{
+				{
+					hcl.TraverseAttr{
+						Name: "test_string",
+					},
+				},
+			},
+		},
+	}
+	node := NodeValidatableResource{
+		NodeAbstractResource: &NodeAbstractResource{
+			Addr:             mustConfigResourceAddr("test_foo.bar"),
+			Config:           rc,
+			ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+		},
+	}
+
+	ctx := &MockEvalContext{}
+	ctx.installSimpleEval()
+
+	ctx.ProviderSchemaSchema = mp.ProviderSchema()
+	ctx.ProviderProvider = p
+
+	diags := node.validateResource(ctx)
+	if diags.HasErrors() {
+		t.Fatalf("error for supposedly-valid config: %s", diags.ErrWithWarnings())
+	}
+
+	// Now we'll make it invalid by attempting to ignore a computed
+	// attribute.
+	rc.Managed.IgnoreChanges = append(rc.Managed.IgnoreChanges, hcl.Traversal{
+		hcl.TraverseAttr{
+			Name: "computed_string",
+		},
+	})
+
+	diags = node.validateResource(ctx)
+	if diags.HasErrors() {
+		t.Fatalf("got unexpected error: %s", diags.ErrWithWarnings())
+	}
+	if got, want := diags.ErrWithWarnings().Error(), `Redundant ignore_changes element: Adding an attribute name to ignore_changes tells Terraform to ignore future changes to the argument in configuration after the object has been created, retaining the value originally configured.
+
+The attribute computed_string is decided by the provider alone and therefore there can be no configured value to compare with. Including this attribute in ignore_changes has no effect. Remove the attribute from ignore_changes to quiet this warning.`; !strings.Contains(got, want) {
+		t.Fatalf("wrong error\ngot:  %s\nwant: Message containing %q", got, want)
+	}
+}
diff --git a/v1.5.7/internal/terraform/node_root_variable.go b/v1.5.7/internal/terraform/node_root_variable.go
new file mode 100644
index 0000000..c18d052
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_root_variable.go
@@ -0,0 +1,118 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// NodeRootVariable represents a root variable input.
+type NodeRootVariable struct {
+	Addr   addrs.InputVariable
+	Config *configs.Variable
+
+	// RawValue is the value for the variable set from outside Terraform
+	// Core, such as on the command line, or from an environment variable,
+	// or similar. This is the raw value that was provided, not yet
+	// converted or validated, and can be nil for a variable that isn't
+	// set at all.
+	RawValue *InputValue
+}
+
+var (
+	_ GraphNodeModuleInstance = (*NodeRootVariable)(nil)
+	_ GraphNodeReferenceable  = (*NodeRootVariable)(nil)
+)
+
+func (n *NodeRootVariable) Name() string {
+	return n.Addr.String()
+}
+
+// GraphNodeModuleInstance
+func (n *NodeRootVariable) Path() addrs.ModuleInstance {
+	return addrs.RootModuleInstance
+}
+
+func (n *NodeRootVariable) ModulePath() addrs.Module {
+	return addrs.RootModule
+}
+
+// GraphNodeReferenceable
+func (n *NodeRootVariable) ReferenceableAddrs() []addrs.Referenceable {
+	return []addrs.Referenceable{n.Addr}
+}
+
+// GraphNodeExecutable
+func (n *NodeRootVariable) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
+	// Root module variables are special in that they are provided directly
+	// by the caller (usually, the CLI layer) and so we don't really need to
+	// evaluate them in the usual sense, but we do need to process the raw
+	// values given by the caller to match what the module is expecting, and
+	// make sure the values are valid.
+	var diags tfdiags.Diagnostics
+
+	addr := addrs.RootModuleInstance.InputVariable(n.Addr.Name)
+	log.Printf("[TRACE] NodeRootVariable: evaluating %s", addr)
+
+	if n.Config == nil {
+		// Because we build NodeRootVariable from configuration in the normal
+		// case it's strange to get here, but we tolerate it to allow for
+		// tests that might not populate the inputs fully.
+		return nil
+	}
+
+	givenVal := n.RawValue
+	if givenVal == nil {
+		// We'll use cty.NilVal to represent the variable not being set at
+		// all, which for historical reasons is unfortunately different than
+		// explicitly setting it to null in some cases. In normal code we
+		// should never get here because all variables should have raw
+		// values, but we can get here in some historical tests that call
+		// in directly and don't necessarily obey the rules.
+		givenVal = &InputValue{
+			Value:      cty.NilVal,
+			SourceType: ValueFromUnknown,
+		}
+	}
+
+	finalVal, moreDiags := prepareFinalInputVariableValue(
+		addr,
+		givenVal,
+		n.Config,
+	)
+	diags = diags.Append(moreDiags)
+	if moreDiags.HasErrors() {
+		// No point in proceeding to validations then, because they'll
+		// probably fail trying to work with a value of the wrong type.
+		return diags
+	}
+
+	ctx.SetRootModuleArgument(addr.Variable, finalVal)
+
+	moreDiags = evalVariableValidations(
+		addrs.RootModuleInstance.InputVariable(n.Addr.Name),
+		n.Config,
+		nil, // not set for root module variables
+		ctx,
+	)
+	diags = diags.Append(moreDiags)
+	return diags
+}
+
+// dag.GraphNodeDotter impl.
+func (n *NodeRootVariable) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
+	return &dag.DotNode{
+		Name: name,
+		Attrs: map[string]string{
+			"label": n.Name(),
+			"shape": "note",
+		},
+	}
+}
diff --git a/v1.5.7/internal/terraform/node_root_variable_test.go b/v1.5.7/internal/terraform/node_root_variable_test.go
new file mode 100644
index 0000000..7e8eb6a
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_root_variable_test.go
@@ -0,0 +1,170 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcltest"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/lang"
+)
+
+func TestNodeRootVariableExecute(t *testing.T) {
+	t.Run("type conversion", func(t *testing.T) {
+		ctx := new(MockEvalContext)
+
+		n := &NodeRootVariable{
+			Addr: addrs.InputVariable{Name: "foo"},
+			Config: &configs.Variable{
+				Name:           "foo",
+				Type:           cty.String,
+				ConstraintType: cty.String,
+			},
+			RawValue: &InputValue{
+				Value:      cty.True,
+				SourceType: ValueFromUnknown,
+			},
+		}
+
+		diags := n.Execute(ctx, walkApply)
+		if diags.HasErrors() {
+			t.Fatalf("unexpected error: %s", diags.Err())
+		}
+
+		if !ctx.SetRootModuleArgumentCalled {
+			t.Fatalf("ctx.SetRootModuleArgument wasn't called")
+		}
+		if got, want := ctx.SetRootModuleArgumentAddr.String(), "var.foo"; got != want {
+			t.Errorf("wrong address for ctx.SetRootModuleArgument\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := ctx.SetRootModuleArgumentValue, cty.StringVal("true"); !want.RawEquals(got) {
+			// NOTE: The given value was cty.Bool but the type constraint was
+			// cty.String, so it was NodeRootVariable's responsibility to convert
+			// as part of preparing the "final value".
+			t.Errorf("wrong value for ctx.SetRootModuleArgument\ngot:  %#v\nwant: %#v", got, want)
+		}
+	})
+	t.Run("validation", func(t *testing.T) {
+		ctx := new(MockEvalContext)
+
+		// The variable validation function gets called with Terraform's
+		// built-in functions available, so we need a minimal scope just for
+		// it to get the functions from.
+		ctx.EvaluationScopeScope = &lang.Scope{}
+
+		// We need to reimplement a _little_ bit of EvalContextBuiltin logic
+		// here to get a similar effect with EvalContextMock just to get the
+		// value to flow through here in a realistic way that'll make this test
+		// useful.
+		var finalVal cty.Value
+		ctx.SetRootModuleArgumentFunc = func(addr addrs.InputVariable, v cty.Value) {
+			if addr.Name == "foo" {
+				t.Logf("set %s to %#v", addr.String(), v)
+				finalVal = v
+			}
+		}
+		ctx.GetVariableValueFunc = func(addr addrs.AbsInputVariableInstance) cty.Value {
+			if addr.String() != "var.foo" {
+				return cty.NilVal
+			}
+			t.Logf("reading final val for %s (%#v)", addr.String(), finalVal)
+			return finalVal
+		}
+
+		n := &NodeRootVariable{
+			Addr: addrs.InputVariable{Name: "foo"},
+			Config: &configs.Variable{
+				Name:           "foo",
+				Type:           cty.Number,
+				ConstraintType: cty.Number,
+				Validations: []*configs.CheckRule{
+					{
+						Condition: fakeHCLExpressionFunc(func(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
+							// This returns true only if the given variable value
+							// is exactly cty.Number, which allows us to verify
+							// that we were given the value _after_ type
+							// conversion.
+							// This had previously not been handled correctly,
+							// as reported in:
+							//     https://github.com/hashicorp/terraform/issues/29899
+							vars := ctx.Variables["var"]
+							if vars == cty.NilVal || !vars.Type().IsObjectType() || !vars.Type().HasAttribute("foo") {
+								t.Logf("var.foo isn't available")
+								return cty.False, nil
+							}
+							val := vars.GetAttr("foo")
+							if val == cty.NilVal || val.Type() != cty.Number {
+								t.Logf("var.foo is %#v; want a number", val)
+								return cty.False, nil
+							}
+							return cty.True, nil
+						}),
+						ErrorMessage: hcltest.MockExprLiteral(cty.StringVal("Must be a number.")),
+					},
+				},
+			},
+			RawValue: &InputValue{
+				// Note: This is a string, but the variable's type constraint
+				// is number so it should be converted before use.
+				Value:      cty.StringVal("5"),
+				SourceType: ValueFromUnknown,
+			},
+		}
+
+		diags := n.Execute(ctx, walkApply)
+		if diags.HasErrors() {
+			t.Fatalf("unexpected error: %s", diags.Err())
+		}
+
+		if !ctx.SetRootModuleArgumentCalled {
+			t.Fatalf("ctx.SetRootModuleArgument wasn't called")
+		}
+		if got, want := ctx.SetRootModuleArgumentAddr.String(), "var.foo"; got != want {
+			t.Errorf("wrong address for ctx.SetRootModuleArgument\ngot:  %s\nwant: %s", got, want)
+		}
+		if got, want := ctx.SetRootModuleArgumentValue, cty.NumberIntVal(5); !want.RawEquals(got) {
+			// NOTE: The given value was cty.Bool but the type constraint was
+			// cty.String, so it was NodeRootVariable's responsibility to convert
+			// as part of preparing the "final value".
+			t.Errorf("wrong value for ctx.SetRootModuleArgument\ngot:  %#v\nwant: %#v", got, want)
+		}
+	})
+}
+
+// fakeHCLExpressionFunc is a fake implementation of hcl.Expression that just
+// directly produces a value with direct Go code.
+//
+// An expression of this type has no references and so it cannot access any
+// variables from the EvalContext unless something else arranges for them
+// to be guaranteed available. For example, custom variable validations just
+// unconditionally have access to the variable they are validating regardless
+// of references.
+type fakeHCLExpressionFunc func(*hcl.EvalContext) (cty.Value, hcl.Diagnostics)
+
+var _ hcl.Expression = fakeHCLExpressionFunc(nil)
+
+func (f fakeHCLExpressionFunc) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
+	return f(ctx)
+}
+
+func (f fakeHCLExpressionFunc) Variables() []hcl.Traversal {
+	return nil
+}
+
+func (f fakeHCLExpressionFunc) Range() hcl.Range {
+	return hcl.Range{
+		Filename: "fake",
+		Start:    hcl.InitialPos,
+		End:      hcl.InitialPos,
+	}
+}
+
+func (f fakeHCLExpressionFunc) StartRange() hcl.Range {
+	return f.Range()
+}
diff --git a/v1.5.7/internal/terraform/node_value.go b/v1.5.7/internal/terraform/node_value.go
new file mode 100644
index 0000000..32fd7a5
--- /dev/null
+++ b/v1.5.7/internal/terraform/node_value.go
@@ -0,0 +1,13 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+// graphNodeTemporaryValue is implemented by nodes that may represent temporary
+// values, which are those not saved to the state file. This includes locals,
+// variables, and non-root outputs.
+// A boolean return value allows a node which may need to be saved to
+// conditionally do so.
+type graphNodeTemporaryValue interface {
+	temporaryValue() bool
+}
diff --git a/v1.5.7/internal/terraform/phasestate_string.go b/v1.5.7/internal/terraform/phasestate_string.go
new file mode 100644
index 0000000..3c3b4f7
--- /dev/null
+++ b/v1.5.7/internal/terraform/phasestate_string.go
@@ -0,0 +1,25 @@
+// Code generated by "stringer -type phaseState"; DO NOT EDIT.
+
+package terraform
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[workingState-0]
+	_ = x[refreshState-1]
+	_ = x[prevRunState-2]
+}
+
+const _phaseState_name = "workingStaterefreshStateprevRunState"
+
+var _phaseState_index = [...]uint8{0, 12, 24, 36}
+
+func (i phaseState) String() string {
+	if i < 0 || i >= phaseState(len(_phaseState_index)-1) {
+		return "phaseState(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _phaseState_name[_phaseState_index[i]:_phaseState_index[i+1]]
+}
diff --git a/v1.5.7/internal/terraform/provider_mock.go b/v1.5.7/internal/terraform/provider_mock.go
new file mode 100644
index 0000000..41a1464
--- /dev/null
+++ b/v1.5.7/internal/terraform/provider_mock.go
@@ -0,0 +1,542 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"sync"
+
+	"github.com/zclconf/go-cty/cty"
+	ctyjson "github.com/zclconf/go-cty/cty/json"
+	"github.com/zclconf/go-cty/cty/msgpack"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
+	"github.com/hashicorp/terraform/internal/providers"
+)
+
+var _ providers.Interface = (*MockProvider)(nil)
+
+// MockProvider implements providers.Interface but mocks out all the
+// calls for testing purposes.
+type MockProvider struct {
+	sync.Mutex
+
+	// Anything you want, in case you need to store extra data with the mock.
+	Meta interface{}
+
+	GetProviderSchemaCalled   bool
+	GetProviderSchemaResponse *providers.GetProviderSchemaResponse
+
+	ValidateProviderConfigCalled   bool
+	ValidateProviderConfigResponse *providers.ValidateProviderConfigResponse
+	ValidateProviderConfigRequest  providers.ValidateProviderConfigRequest
+	ValidateProviderConfigFn       func(providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse
+
+	ValidateResourceConfigCalled   bool
+	ValidateResourceConfigTypeName string
+	ValidateResourceConfigResponse *providers.ValidateResourceConfigResponse
+	ValidateResourceConfigRequest  providers.ValidateResourceConfigRequest
+	ValidateResourceConfigFn       func(providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse
+
+	ValidateDataResourceConfigCalled   bool
+	ValidateDataResourceConfigTypeName string
+	ValidateDataResourceConfigResponse *providers.ValidateDataResourceConfigResponse
+	ValidateDataResourceConfigRequest  providers.ValidateDataResourceConfigRequest
+	ValidateDataResourceConfigFn       func(providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse
+
+	UpgradeResourceStateCalled   bool
+	UpgradeResourceStateTypeName string
+	UpgradeResourceStateResponse *providers.UpgradeResourceStateResponse
+	UpgradeResourceStateRequest  providers.UpgradeResourceStateRequest
+	UpgradeResourceStateFn       func(providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse
+
+	ConfigureProviderCalled   bool
+	ConfigureProviderResponse *providers.ConfigureProviderResponse
+	ConfigureProviderRequest  providers.ConfigureProviderRequest
+	ConfigureProviderFn       func(providers.ConfigureProviderRequest) providers.ConfigureProviderResponse
+
+	StopCalled   bool
+	StopFn       func() error
+	StopResponse error
+
+	ReadResourceCalled   bool
+	ReadResourceResponse *providers.ReadResourceResponse
+	ReadResourceRequest  providers.ReadResourceRequest
+	ReadResourceFn       func(providers.ReadResourceRequest) providers.ReadResourceResponse
+
+	PlanResourceChangeCalled   bool
+	PlanResourceChangeResponse *providers.PlanResourceChangeResponse
+	PlanResourceChangeRequest  providers.PlanResourceChangeRequest
+	PlanResourceChangeFn       func(providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse
+
+	ApplyResourceChangeCalled   bool
+	ApplyResourceChangeResponse *providers.ApplyResourceChangeResponse
+	ApplyResourceChangeRequest  providers.ApplyResourceChangeRequest
+	ApplyResourceChangeFn       func(providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse
+
+	ImportResourceStateCalled   bool
+	ImportResourceStateResponse *providers.ImportResourceStateResponse
+	ImportResourceStateRequest  providers.ImportResourceStateRequest
+	ImportResourceStateFn       func(providers.ImportResourceStateRequest) providers.ImportResourceStateResponse
+
+	ReadDataSourceCalled   bool
+	ReadDataSourceResponse *providers.ReadDataSourceResponse
+	ReadDataSourceRequest  providers.ReadDataSourceRequest
+	ReadDataSourceFn       func(providers.ReadDataSourceRequest) providers.ReadDataSourceResponse
+
+	CloseCalled bool
+	CloseError  error
+}
+
+func (p *MockProvider) GetProviderSchema() providers.GetProviderSchemaResponse {
+	p.Lock()
+	defer p.Unlock()
+	p.GetProviderSchemaCalled = true
+	return p.getProviderSchema()
+}
+
+func (p *MockProvider) getProviderSchema() providers.GetProviderSchemaResponse {
+	// This version of getProviderSchema doesn't do any locking, so it's suitable to
+	// call from other methods of this mock as long as they are already
+	// holding the lock.
+	if p.GetProviderSchemaResponse != nil {
+		return *p.GetProviderSchemaResponse
+	}
+
+	return providers.GetProviderSchemaResponse{
+		Provider:      providers.Schema{},
+		DataSources:   map[string]providers.Schema{},
+		ResourceTypes: map[string]providers.Schema{},
+	}
+}
+
+// ProviderSchema is a helper to convert from the internal GetProviderSchemaResponse to
+// a ProviderSchema.
+func (p *MockProvider) ProviderSchema() *ProviderSchema {
+	resp := p.getProviderSchema()
+
+	schema := &ProviderSchema{
+		Provider:                   resp.Provider.Block,
+		ProviderMeta:               resp.ProviderMeta.Block,
+		ResourceTypes:              map[string]*configschema.Block{},
+		DataSources:                map[string]*configschema.Block{},
+		ResourceTypeSchemaVersions: map[string]uint64{},
+	}
+
+	for resType, s := range resp.ResourceTypes {
+		schema.ResourceTypes[resType] = s.Block
+		schema.ResourceTypeSchemaVersions[resType] = uint64(s.Version)
+	}
+
+	for dataSource, s := range resp.DataSources {
+		schema.DataSources[dataSource] = s.Block
+	}
+
+	return schema
+}
+
+func (p *MockProvider) ValidateProviderConfig(r providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ValidateProviderConfigCalled = true
+	p.ValidateProviderConfigRequest = r
+	if p.ValidateProviderConfigFn != nil {
+		return p.ValidateProviderConfigFn(r)
+	}
+
+	if p.ValidateProviderConfigResponse != nil {
+		return *p.ValidateProviderConfigResponse
+	}
+
+	resp.PreparedConfig = r.Config
+	return resp
+}
+
+func (p *MockProvider) ValidateResourceConfig(r providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ValidateResourceConfigCalled = true
+	p.ValidateResourceConfigRequest = r
+
+	// Marshall the value to replicate behavior by the GRPC protocol,
+	// and return any relevant errors
+	resourceSchema, ok := p.getProviderSchema().ResourceTypes[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName))
+		return resp
+	}
+
+	_, err := msgpack.Marshal(r.Config, resourceSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	if p.ValidateResourceConfigFn != nil {
+		return p.ValidateResourceConfigFn(r)
+	}
+
+	if p.ValidateResourceConfigResponse != nil {
+		return *p.ValidateResourceConfigResponse
+	}
+
+	return resp
+}
+
+func (p *MockProvider) ValidateDataResourceConfig(r providers.ValidateDataResourceConfigRequest) (resp providers.ValidateDataResourceConfigResponse) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ValidateDataResourceConfigCalled = true
+	p.ValidateDataResourceConfigRequest = r
+
+	// Marshall the value to replicate behavior by the GRPC protocol
+	dataSchema, ok := p.getProviderSchema().DataSources[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName))
+		return resp
+	}
+	_, err := msgpack.Marshal(r.Config, dataSchema.Block.ImpliedType())
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	if p.ValidateDataResourceConfigFn != nil {
+		return p.ValidateDataResourceConfigFn(r)
+	}
+
+	if p.ValidateDataResourceConfigResponse != nil {
+		return *p.ValidateDataResourceConfigResponse
+	}
+
+	return resp
+}
+
+func (p *MockProvider) UpgradeResourceState(r providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
+	p.Lock()
+	defer p.Unlock()
+
+	if !p.ConfigureProviderCalled {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before UpgradeResourceState %q", r.TypeName))
+		return resp
+	}
+
+	schema, ok := p.getProviderSchema().ResourceTypes[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName))
+		return resp
+	}
+
+	schemaType := schema.Block.ImpliedType()
+
+	p.UpgradeResourceStateCalled = true
+	p.UpgradeResourceStateRequest = r
+
+	if p.UpgradeResourceStateFn != nil {
+		return p.UpgradeResourceStateFn(r)
+	}
+
+	if p.UpgradeResourceStateResponse != nil {
+		return *p.UpgradeResourceStateResponse
+	}
+
+	switch {
+	case r.RawStateFlatmap != nil:
+		v, err := hcl2shim.HCL2ValueFromFlatmap(r.RawStateFlatmap, schemaType)
+		if err != nil {
+			resp.Diagnostics = resp.Diagnostics.Append(err)
+			return resp
+		}
+		resp.UpgradedState = v
+	case len(r.RawStateJSON) > 0:
+		v, err := ctyjson.Unmarshal(r.RawStateJSON, schemaType)
+
+		if err != nil {
+			resp.Diagnostics = resp.Diagnostics.Append(err)
+			return resp
+		}
+		resp.UpgradedState = v
+	}
+
+	return resp
+}
+
+func (p *MockProvider) ConfigureProvider(r providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ConfigureProviderCalled = true
+	p.ConfigureProviderRequest = r
+
+	if p.ConfigureProviderFn != nil {
+		return p.ConfigureProviderFn(r)
+	}
+
+	if p.ConfigureProviderResponse != nil {
+		return *p.ConfigureProviderResponse
+	}
+
+	return resp
+}
+
+func (p *MockProvider) Stop() error {
+	// We intentionally don't lock in this one because the whole point of this
+	// method is to be called concurrently with another operation that can
+	// be cancelled.  The provider itself is responsible for handling
+	// any concurrency concerns in this case.
+
+	p.StopCalled = true
+	if p.StopFn != nil {
+		return p.StopFn()
+	}
+
+	return p.StopResponse
+}
+
+func (p *MockProvider) ReadResource(r providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ReadResourceCalled = true
+	p.ReadResourceRequest = r
+
+	if !p.ConfigureProviderCalled {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before ReadResource %q", r.TypeName))
+		return resp
+	}
+
+	if p.ReadResourceFn != nil {
+		return p.ReadResourceFn(r)
+	}
+
+	if p.ReadResourceResponse != nil {
+		resp = *p.ReadResourceResponse
+
+		// Make sure the NewState conforms to the schema.
+		// This isn't always the case for the existing tests.
+		schema, ok := p.getProviderSchema().ResourceTypes[r.TypeName]
+		if !ok {
+			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName))
+			return resp
+		}
+
+		newState, err := schema.Block.CoerceValue(resp.NewState)
+		if err != nil {
+			resp.Diagnostics = resp.Diagnostics.Append(err)
+		}
+		resp.NewState = newState
+		return resp
+	}
+
+	// otherwise just return the same state we received
+	resp.NewState = r.PriorState
+	resp.Private = r.Private
+	return resp
+}
+
+func (p *MockProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
+	p.Lock()
+	defer p.Unlock()
+
+	if !p.ConfigureProviderCalled {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before PlanResourceChange %q", r.TypeName))
+		return resp
+	}
+
+	p.PlanResourceChangeCalled = true
+	p.PlanResourceChangeRequest = r
+
+	if p.PlanResourceChangeFn != nil {
+		return p.PlanResourceChangeFn(r)
+	}
+
+	if p.PlanResourceChangeResponse != nil {
+		return *p.PlanResourceChangeResponse
+	}
+
+	// this is a destroy plan,
+	if r.ProposedNewState.IsNull() {
+		resp.PlannedState = r.ProposedNewState
+		resp.PlannedPrivate = r.PriorPrivate
+		return resp
+	}
+
+	schema, ok := p.getProviderSchema().ResourceTypes[r.TypeName]
+	if !ok {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName))
+		return resp
+	}
+
+	// The default plan behavior is to accept the proposed value, and mark all
+	// nil computed attributes as unknown.
+	val, err := cty.Transform(r.ProposedNewState, func(path cty.Path, v cty.Value) (cty.Value, error) {
+		// We're only concerned with known null values, which can be computed
+		// by the provider.
+		if !v.IsKnown() {
+			return v, nil
+		}
+
+		attrSchema := schema.Block.AttributeByPath(path)
+		if attrSchema == nil {
+			// this is an intermediate path which does not represent an attribute
+			return v, nil
+		}
+
+		// get the current configuration value, to detect when a
+		// computed+optional attributes has become unset
+		configVal, err := path.Apply(r.Config)
+		if err != nil {
+			return v, err
+		}
+
+		switch {
+		case attrSchema.Computed && !attrSchema.Optional && v.IsNull():
+			// this is the easy path, this value is not yet set, and _must_ be computed
+			return cty.UnknownVal(v.Type()), nil
+
+		case attrSchema.Computed && attrSchema.Optional && !v.IsNull() && configVal.IsNull():
+			// If an optional+computed value has gone from set to unset, it
+			// becomes computed. (this was not possible to do with legacy
+			// providers)
+			return cty.UnknownVal(v.Type()), nil
+		}
+
+		return v, nil
+	})
+	if err != nil {
+		resp.Diagnostics = resp.Diagnostics.Append(err)
+		return resp
+	}
+
+	resp.PlannedPrivate = r.PriorPrivate
+	resp.PlannedState = val
+
+	return resp
+}
+
+func (p *MockProvider) ApplyResourceChange(r providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
+	p.Lock()
+	p.ApplyResourceChangeCalled = true
+	p.ApplyResourceChangeRequest = r
+	p.Unlock()
+
+	if !p.ConfigureProviderCalled {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before ApplyResourceChange %q", r.TypeName))
+		return resp
+	}
+
+	if p.ApplyResourceChangeFn != nil {
+		return p.ApplyResourceChangeFn(r)
+	}
+
+	if p.ApplyResourceChangeResponse != nil {
+		return *p.ApplyResourceChangeResponse
+	}
+
+	// if the value is nil, we return that directly to correspond to a delete
+	if r.PlannedState.IsNull() {
+		resp.NewState = r.PlannedState
+		return resp
+	}
+
+	// the default behavior will be to create the minimal valid apply value by
+	// setting unknowns (which correspond to computed attributes) to a zero
+	// value.
+	val, _ := cty.Transform(r.PlannedState, func(path cty.Path, v cty.Value) (cty.Value, error) {
+		if !v.IsKnown() {
+			ty := v.Type()
+			switch {
+			case ty == cty.String:
+				return cty.StringVal(""), nil
+			case ty == cty.Number:
+				return cty.NumberIntVal(0), nil
+			case ty == cty.Bool:
+				return cty.False, nil
+			case ty.IsMapType():
+				return cty.MapValEmpty(ty.ElementType()), nil
+			case ty.IsListType():
+				return cty.ListValEmpty(ty.ElementType()), nil
+			default:
+				return cty.NullVal(ty), nil
+			}
+		}
+		return v, nil
+	})
+
+	resp.NewState = val
+	resp.Private = r.PlannedPrivate
+
+	return resp
+}
+
+func (p *MockProvider) ImportResourceState(r providers.ImportResourceStateRequest) (resp providers.ImportResourceStateResponse) {
+	p.Lock()
+	defer p.Unlock()
+
+	if !p.ConfigureProviderCalled {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before ImportResourceState %q", r.TypeName))
+		return resp
+	}
+
+	p.ImportResourceStateCalled = true
+	p.ImportResourceStateRequest = r
+	if p.ImportResourceStateFn != nil {
+		return p.ImportResourceStateFn(r)
+	}
+
+	if p.ImportResourceStateResponse != nil {
+		resp = *p.ImportResourceStateResponse
+		// fixup the cty value to match the schema
+		for i, res := range resp.ImportedResources {
+			schema, ok := p.getProviderSchema().ResourceTypes[res.TypeName]
+			if !ok {
+				resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", res.TypeName))
+				return resp
+			}
+
+			var err error
+			res.State, err = schema.Block.CoerceValue(res.State)
+			if err != nil {
+				resp.Diagnostics = resp.Diagnostics.Append(err)
+				return resp
+			}
+
+			resp.ImportedResources[i] = res
+		}
+	}
+
+	return resp
+}
+
+func (p *MockProvider) ReadDataSource(r providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
+	p.Lock()
+	defer p.Unlock()
+
+	if !p.ConfigureProviderCalled {
+		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before ReadDataSource %q", r.TypeName))
+		return resp
+	}
+
+	p.ReadDataSourceCalled = true
+	p.ReadDataSourceRequest = r
+
+	if p.ReadDataSourceFn != nil {
+		return p.ReadDataSourceFn(r)
+	}
+
+	if p.ReadDataSourceResponse != nil {
+		resp = *p.ReadDataSourceResponse
+	}
+
+	return resp
+}
+
+func (p *MockProvider) Close() error {
+	p.CloseCalled = true
+	return p.CloseError
+}
diff --git a/v1.5.7/internal/terraform/provisioner_mock.go b/v1.5.7/internal/terraform/provisioner_mock.go
new file mode 100644
index 0000000..f2ffd82
--- /dev/null
+++ b/v1.5.7/internal/terraform/provisioner_mock.go
@@ -0,0 +1,107 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"sync"
+
+	"github.com/hashicorp/terraform/internal/provisioners"
+)
+
+var _ provisioners.Interface = (*MockProvisioner)(nil)
+
+// MockProvisioner implements provisioners.Interface but mocks out all the
+// calls for testing purposes.
+type MockProvisioner struct {
+	sync.Mutex
+	// Anything you want, in case you need to store extra data with the mock.
+	Meta interface{}
+
+	GetSchemaCalled   bool
+	GetSchemaResponse provisioners.GetSchemaResponse
+
+	ValidateProvisionerConfigCalled   bool
+	ValidateProvisionerConfigRequest  provisioners.ValidateProvisionerConfigRequest
+	ValidateProvisionerConfigResponse provisioners.ValidateProvisionerConfigResponse
+	ValidateProvisionerConfigFn       func(provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse
+
+	ProvisionResourceCalled   bool
+	ProvisionResourceRequest  provisioners.ProvisionResourceRequest
+	ProvisionResourceResponse provisioners.ProvisionResourceResponse
+	ProvisionResourceFn       func(provisioners.ProvisionResourceRequest) provisioners.ProvisionResourceResponse
+
+	StopCalled   bool
+	StopResponse error
+	StopFn       func() error
+
+	CloseCalled   bool
+	CloseResponse error
+	CloseFn       func() error
+}
+
+func (p *MockProvisioner) GetSchema() provisioners.GetSchemaResponse {
+	p.Lock()
+	defer p.Unlock()
+
+	p.GetSchemaCalled = true
+	return p.getSchema()
+}
+
+// getSchema is the implementation of GetSchema, which can be called from other
+// methods on MockProvisioner that may already be holding the lock.
+func (p *MockProvisioner) getSchema() provisioners.GetSchemaResponse {
+	return p.GetSchemaResponse
+}
+
+func (p *MockProvisioner) ValidateProvisionerConfig(r provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ValidateProvisionerConfigCalled = true
+	p.ValidateProvisionerConfigRequest = r
+	if p.ValidateProvisionerConfigFn != nil {
+		return p.ValidateProvisionerConfigFn(r)
+	}
+	return p.ValidateProvisionerConfigResponse
+}
+
+func (p *MockProvisioner) ProvisionResource(r provisioners.ProvisionResourceRequest) provisioners.ProvisionResourceResponse {
+	p.Lock()
+	defer p.Unlock()
+
+	p.ProvisionResourceCalled = true
+	p.ProvisionResourceRequest = r
+	if p.ProvisionResourceFn != nil {
+		fn := p.ProvisionResourceFn
+		return fn(r)
+	}
+
+	return p.ProvisionResourceResponse
+}
+
+func (p *MockProvisioner) Stop() error {
+	// We intentionally don't lock in this one because the whole point of this
+	// method is to be called concurrently with another operation that can
+	// be cancelled. The provisioner itself is responsible for handling
+	// any concurrency concerns in this case.
+
+	p.StopCalled = true
+	if p.StopFn != nil {
+		return p.StopFn()
+	}
+
+	return p.StopResponse
+}
+
+func (p *MockProvisioner) Close() error {
+	p.Lock()
+	defer p.Unlock()
+
+	p.CloseCalled = true
+	if p.CloseFn != nil {
+		return p.CloseFn()
+	}
+
+	return p.CloseResponse
+}
diff --git a/v1.5.7/internal/terraform/provisioner_mock_test.go b/v1.5.7/internal/terraform/provisioner_mock_test.go
new file mode 100644
index 0000000..805bdec
--- /dev/null
+++ b/v1.5.7/internal/terraform/provisioner_mock_test.go
@@ -0,0 +1,30 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/provisioners"
+)
+
+// simpleMockProvisioner returns a MockProvisioner that is pre-configured
+// with schema for its own config, with the same content as returned by
+// function simpleTestSchema.
+//
+// For most reasonable uses the returned provisioner must be registered in a
+// componentFactory under the name "test". Use simpleMockComponentFactory
+// to obtain a pre-configured componentFactory containing the result of
+// this function along with simpleMockProvider, both registered as "test".
+//
+// The returned provisioner has no other behaviors by default, but the caller
+// may modify it in order to stub any other required functionality, or modify
+// the default schema stored in the field GetSchemaReturn. Each new call to
+// simpleTestProvisioner produces entirely new instances of all of the nested
+// objects so that callers can mutate without affecting mock objects.
+func simpleMockProvisioner() *MockProvisioner {
+	return &MockProvisioner{
+		GetSchemaResponse: provisioners.GetSchemaResponse{
+			Provisioner: simpleTestSchema(),
+		},
+	}
+}
diff --git a/v1.5.7/internal/terraform/reduce_plan.go b/v1.5.7/internal/terraform/reduce_plan.go
new file mode 100644
index 0000000..36da4ac
--- /dev/null
+++ b/v1.5.7/internal/terraform/reduce_plan.go
@@ -0,0 +1,35 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+// reducePlan takes a planned resource instance change as might be produced by
+// Plan or PlanDestroy and "simplifies" it to a single atomic action to be
+// performed by a specific graph node.
+//
+// Callers must specify whether they are a destroy node or a regular apply node.
+// If the result is NoOp then the given change requires no action for the
+// specific graph node calling this and so evaluation of the that graph node
+// should exit early and take no action.
+//
+// The returned object may either be identical to the input change or a new
+// change object derived from the input. Because of the former case, the caller
+// must not mutate the object returned in OutChange.
+func reducePlan(addr addrs.ResourceInstance, in *plans.ResourceInstanceChange, destroy bool) *plans.ResourceInstanceChange {
+	out := in.Simplify(destroy)
+	if out.Action != in.Action {
+		if destroy {
+			log.Printf("[TRACE] reducePlan: %s change simplified from %s to %s for destroy node", addr, in.Action, out.Action)
+		} else {
+			log.Printf("[TRACE] reducePlan: %s change simplified from %s to %s for apply node", addr, in.Action, out.Action)
+		}
+	}
+	return out
+}
diff --git a/v1.5.7/internal/terraform/reduce_plan_test.go b/v1.5.7/internal/terraform/reduce_plan_test.go
new file mode 100644
index 0000000..1514ab6
--- /dev/null
+++ b/v1.5.7/internal/terraform/reduce_plan_test.go
@@ -0,0 +1,446 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestProcessIgnoreChangesIndividual(t *testing.T) {
+	tests := map[string]struct {
+		Old, New cty.Value
+		Ignore   []string
+		Want     cty.Value
+	}{
+		"string": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.StringVal("b value"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("new a value"),
+				"b": cty.StringVal("new b value"),
+			}),
+			[]string{"a"},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.StringVal("new b value"),
+			}),
+		},
+		"changed type": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.StringVal("b value"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NumberIntVal(1),
+				"b": cty.StringVal("new b value"),
+			}),
+			[]string{"a"},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("a value"),
+				"b": cty.StringVal("new b value"),
+			}),
+		},
+		"list": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.StringVal("a0 value"),
+					cty.StringVal("a1 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.StringVal("new a0 value"),
+					cty.StringVal("new a1 value"),
+				}),
+				"b": cty.StringVal("new b value"),
+			}),
+			[]string{"a"},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.StringVal("a0 value"),
+					cty.StringVal("a1 value"),
+				}),
+				"b": cty.StringVal("new b value"),
+			}),
+		},
+		"list_index": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.StringVal("a0 value"),
+					cty.StringVal("a1 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.StringVal("new a0 value"),
+					cty.StringVal("new a1 value"),
+				}),
+				"b": cty.StringVal("new b value"),
+			}),
+			[]string{"a[1]"},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ListVal([]cty.Value{
+					cty.StringVal("new a0 value"),
+					cty.StringVal("a1 value"),
+				}),
+				"b": cty.StringVal("new b value"),
+			}),
+		},
+		"map": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("a0 value"),
+					"a1": cty.StringVal("a1 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("new a0 value"),
+					"a1": cty.UnknownVal(cty.String),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			[]string{`a`},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("a0 value"),
+					"a1": cty.StringVal("a1 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+		},
+		"map_index": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("a0 value"),
+					"a1": cty.StringVal("a1 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("new a0 value"),
+					"a1": cty.StringVal("new a1 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			[]string{`a["a1"]`},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("new a0 value"),
+					"a1": cty.StringVal("a1 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+		},
+		"map_index_no_config": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("a0 value"),
+					"a1": cty.StringVal("a1 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.Map(cty.String)),
+				"b": cty.StringVal("b value"),
+			}),
+			[]string{`a["a1"]`},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a1": cty.StringVal("a1 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+		},
+		"map_index_unknown_value": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("a0 value"),
+					"a1": cty.StringVal("a1 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("a0 value"),
+					"a1": cty.UnknownVal(cty.String),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			[]string{`a["a1"]`},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("a0 value"),
+					"a1": cty.StringVal("a1 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+		},
+		"map_index_multiple_keys": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("a0 value"),
+					"a1": cty.StringVal("a1 value"),
+					"a2": cty.StringVal("a2 value"),
+					"a3": cty.StringVal("a3 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.Map(cty.String)),
+				"b": cty.StringVal("new b value"),
+			}),
+			[]string{`a["a1"]`, `a["a2"]`, `a["a3"]`, `b`},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a1": cty.StringVal("a1 value"),
+					"a2": cty.StringVal("a2 value"),
+					"a3": cty.StringVal("a3 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+		},
+		"map_index_redundant": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("a0 value"),
+					"a1": cty.StringVal("a1 value"),
+					"a2": cty.StringVal("a2 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.Map(cty.String)),
+				"b": cty.StringVal("new b value"),
+			}),
+			[]string{`a["a1"]`, `a`, `b`},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("a0 value"),
+					"a1": cty.StringVal("a1 value"),
+					"a2": cty.StringVal("a2 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+		},
+		"missing_map_index": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("a0 value"),
+					"a1": cty.StringVal("a1 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapValEmpty(cty.String),
+				"b": cty.StringVal("b value"),
+			}),
+			[]string{`a["a1"]`},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a1": cty.StringVal("a1 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+		},
+		"missing_map_index_empty": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapValEmpty(cty.String),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a": cty.StringVal("a0 value"),
+				}),
+			}),
+			[]string{`a["a"]`},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapValEmpty(cty.String),
+			}),
+		},
+		"missing_map_index_to_object": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a": cty.ObjectVal(map[string]cty.Value{
+						"a": cty.StringVal("aa0"),
+						"b": cty.StringVal("ab0"),
+					}),
+					"b": cty.ObjectVal(map[string]cty.Value{
+						"a": cty.StringVal("ba0"),
+						"b": cty.StringVal("bb0"),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapValEmpty(
+					cty.Object(map[string]cty.Type{
+						"a": cty.String,
+						"b": cty.String,
+					}),
+				),
+			}),
+			// we expect the config to be used here, as the ignore changes was
+			// `a["a"].b`, but the change was larger than that removing
+			// `a["a"]` entirely.
+			[]string{`a["a"].b`},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapValEmpty(
+					cty.Object(map[string]cty.Type{
+						"a": cty.String,
+						"b": cty.String,
+					}),
+				),
+			}),
+		},
+		"missing_prior_map_index": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("a0 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("a0 value"),
+					"a1": cty.StringVal("new a1 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			[]string{`a["a1"]`},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.MapVal(map[string]cty.Value{
+					"a0": cty.StringVal("a0 value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+		},
+		"object attribute": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("a.foo value"),
+					"bar": cty.StringVal("a.bar value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("new a.foo value"),
+					"bar": cty.StringVal("new a.bar value"),
+				}),
+				"b": cty.StringVal("new b value"),
+			}),
+			[]string{"a.bar"},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("new a.foo value"),
+					"bar": cty.StringVal("a.bar value"),
+				}),
+				"b": cty.StringVal("new b value"),
+			}),
+		},
+		"unknown_object_attribute": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("a.foo value"),
+					"bar": cty.StringVal("a.bar value"),
+				}),
+				"b": cty.StringVal("b value"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("new a.foo value"),
+					"bar": cty.UnknownVal(cty.String),
+				}),
+				"b": cty.StringVal("new b value"),
+			}),
+			[]string{"a.bar"},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.ObjectVal(map[string]cty.Value{
+					"foo": cty.StringVal("new a.foo value"),
+					"bar": cty.StringVal("a.bar value"),
+				}),
+				"b": cty.StringVal("new b value"),
+			}),
+		},
+		"null_map": {
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("ok"),
+				"list": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"s":   cty.StringVal("ok"),
+						"map": cty.NullVal(cty.Map(cty.String)),
+					}),
+				}),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.NullVal(cty.String),
+				"list": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"s":   cty.StringVal("ok"),
+						"map": cty.NullVal(cty.Map(cty.String)),
+					}),
+				}),
+			}),
+			[]string{"a"},
+			cty.ObjectVal(map[string]cty.Value{
+				"a": cty.StringVal("ok"),
+				"list": cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"s":   cty.StringVal("ok"),
+						"map": cty.NullVal(cty.Map(cty.String)),
+					}),
+				}),
+			}),
+		},
+		"marked_map": {
+			cty.ObjectVal(map[string]cty.Value{
+				"map": cty.MapVal(map[string]cty.Value{
+					"key": cty.StringVal("val"),
+				}).Mark("marked"),
+			}),
+			cty.ObjectVal(map[string]cty.Value{
+				"map": cty.MapVal(map[string]cty.Value{
+					"key": cty.StringVal("new val"),
+				}).Mark("marked"),
+			}),
+			[]string{`map["key"]`},
+			cty.ObjectVal(map[string]cty.Value{
+				"map": cty.MapVal(map[string]cty.Value{
+					"key": cty.StringVal("val"),
+				}).Mark("marked"),
+			}),
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			ignore := make([]hcl.Traversal, len(test.Ignore))
+			for i, ignoreStr := range test.Ignore {
+				trav, diags := hclsyntax.ParseTraversalAbs([]byte(ignoreStr), "", hcl.Pos{Line: 1, Column: 1})
+				if diags.HasErrors() {
+					t.Fatalf("failed to parse %q: %s", ignoreStr, diags.Error())
+				}
+				ignore[i] = trav
+			}
+
+			ret, diags := processIgnoreChangesIndividual(test.Old, test.New, traversalsToPaths(ignore))
+			if diags.HasErrors() {
+				t.Fatal(diags.Err())
+			}
+
+			if got, want := ret, test.Want; !want.RawEquals(got) {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, want)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/terraform/resource_provider_mock_test.go b/v1.5.7/internal/terraform/resource_provider_mock_test.go
new file mode 100644
index 0000000..0853c67
--- /dev/null
+++ b/v1.5.7/internal/terraform/resource_provider_mock_test.go
@@ -0,0 +1,105 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// mockProviderWithConfigSchema is a test helper to concisely create a mock
+// provider with the given schema for its own configuration.
+func mockProviderWithConfigSchema(schema *configschema.Block) *MockProvider {
+	return &MockProvider{
+		GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+			Provider: providers.Schema{Block: schema},
+		},
+	}
+}
+
+// mockProviderWithResourceTypeSchema is a test helper to concisely create a mock
+// provider with a schema containing a single resource type.
+func mockProviderWithResourceTypeSchema(name string, schema *configschema.Block) *MockProvider {
+	return &MockProvider{
+		GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+			Provider: providers.Schema{
+				Block: &configschema.Block{
+					Attributes: map[string]*configschema.Attribute{
+						"string": {
+							Type:     cty.String,
+							Optional: true,
+						},
+						"list": {
+							Type:     cty.List(cty.String),
+							Optional: true,
+						},
+						"root": {
+							Type:     cty.Map(cty.String),
+							Optional: true,
+						},
+					},
+				},
+			},
+			ResourceTypes: map[string]providers.Schema{
+				name: providers.Schema{Block: schema},
+			},
+		},
+	}
+}
+
+// getProviderSchemaResponseFromProviderSchema is a test helper to convert a
+// ProviderSchema to a GetProviderSchemaResponse for use when building a mock provider.
+func getProviderSchemaResponseFromProviderSchema(providerSchema *ProviderSchema) *providers.GetProviderSchemaResponse {
+	resp := &providers.GetProviderSchemaResponse{
+		Provider:      providers.Schema{Block: providerSchema.Provider},
+		ProviderMeta:  providers.Schema{Block: providerSchema.ProviderMeta},
+		ResourceTypes: map[string]providers.Schema{},
+		DataSources:   map[string]providers.Schema{},
+	}
+
+	for name, schema := range providerSchema.ResourceTypes {
+		resp.ResourceTypes[name] = providers.Schema{
+			Block:   schema,
+			Version: int64(providerSchema.ResourceTypeSchemaVersions[name]),
+		}
+	}
+
+	for name, schema := range providerSchema.DataSources {
+		resp.DataSources[name] = providers.Schema{Block: schema}
+	}
+
+	return resp
+}
+
+// simpleMockProvider returns a MockProvider that is pre-configured
+// with schema for its own config, for a resource type called "test_object" and
+// for a data source also called "test_object".
+//
+// All three schemas have the same content as returned by function
+// simpleTestSchema.
+//
+// For most reasonable uses the returned provider must be registered in a
+// componentFactory under the name "test". Use simpleMockComponentFactory
+// to obtain a pre-configured componentFactory containing the result of
+// this function along with simpleMockProvisioner, both registered as "test".
+//
+// The returned provider has no other behaviors by default, but the caller may
+// modify it in order to stub any other required functionality, or modify
+// the default schema stored in the field GetSchemaReturn. Each new call to
+// simpleTestProvider produces entirely new instances of all of the nested
+// objects so that callers can mutate without affecting mock objects.
+func simpleMockProvider() *MockProvider {
+	return &MockProvider{
+		GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
+			Provider: providers.Schema{Block: simpleTestSchema()},
+			ResourceTypes: map[string]providers.Schema{
+				"test_object": providers.Schema{Block: simpleTestSchema()},
+			},
+			DataSources: map[string]providers.Schema{
+				"test_object": providers.Schema{Block: simpleTestSchema()},
+			},
+		},
+	}
+}
diff --git a/v1.5.7/internal/terraform/schemas.go b/v1.5.7/internal/terraform/schemas.go
new file mode 100644
index 0000000..db3577c
--- /dev/null
+++ b/v1.5.7/internal/terraform/schemas.go
@@ -0,0 +1,190 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// ProviderSchema is an alias for providers.Schemas, which is the new location
+// for what we originally called terraform.ProviderSchema but which has
+// moved out as part of ongoing refactoring to shrink down the main "terraform"
+// package.
+type ProviderSchema = providers.Schemas
+
+// Schemas is a container for various kinds of schema that Terraform needs
+// during processing.
+type Schemas struct {
+	Providers    map[addrs.Provider]*providers.Schemas
+	Provisioners map[string]*configschema.Block
+}
+
+// ProviderSchema returns the entire ProviderSchema object that was produced
+// by the plugin for the given provider, or nil if no such schema is available.
+//
+// It's usually better to go use the more precise methods offered by type
+// Schemas to handle this detail automatically.
+func (ss *Schemas) ProviderSchema(provider addrs.Provider) *providers.Schemas {
+	if ss.Providers == nil {
+		return nil
+	}
+	return ss.Providers[provider]
+}
+
+// ProviderConfig returns the schema for the provider configuration of the
+// given provider type, or nil if no such schema is available.
+func (ss *Schemas) ProviderConfig(provider addrs.Provider) *configschema.Block {
+	ps := ss.ProviderSchema(provider)
+	if ps == nil {
+		return nil
+	}
+	return ps.Provider
+}
+
+// ResourceTypeConfig returns the schema for the configuration of a given
+// resource type belonging to a given provider type, or nil of no such
+// schema is available.
+//
+// In many cases the provider type is inferrable from the resource type name,
+// but this is not always true because users can override the provider for
+// a resource using the "provider" meta-argument. Therefore it's important to
+// always pass the correct provider name, even though it many cases it feels
+// redundant.
+func (ss *Schemas) ResourceTypeConfig(provider addrs.Provider, resourceMode addrs.ResourceMode, resourceType string) (block *configschema.Block, schemaVersion uint64) {
+	ps := ss.ProviderSchema(provider)
+	if ps == nil || ps.ResourceTypes == nil {
+		return nil, 0
+	}
+	return ps.SchemaForResourceType(resourceMode, resourceType)
+}
+
+// ProvisionerConfig returns the schema for the configuration of a given
+// provisioner, or nil of no such schema is available.
+func (ss *Schemas) ProvisionerConfig(name string) *configschema.Block {
+	return ss.Provisioners[name]
+}
+
+// loadSchemas searches the given configuration, state  and plan (any of which
+// may be nil) for constructs that have an associated schema, requests the
+// necessary schemas from the given component factory (which must _not_ be nil),
+// and returns a single object representing all of the necessary schemas.
+//
+// If an error is returned, it may be a wrapped tfdiags.Diagnostics describing
+// errors across multiple separate objects. Errors here will usually indicate
+// either misbehavior on the part of one of the providers or of the provider
+// protocol itself. When returned with errors, the returned schemas object is
+// still valid but may be incomplete.
+func loadSchemas(config *configs.Config, state *states.State, plugins *contextPlugins) (*Schemas, error) {
+	schemas := &Schemas{
+		Providers:    map[addrs.Provider]*providers.Schemas{},
+		Provisioners: map[string]*configschema.Block{},
+	}
+	var diags tfdiags.Diagnostics
+
+	newDiags := loadProviderSchemas(schemas.Providers, config, state, plugins)
+	diags = diags.Append(newDiags)
+	newDiags = loadProvisionerSchemas(schemas.Provisioners, config, plugins)
+	diags = diags.Append(newDiags)
+
+	return schemas, diags.Err()
+}
+
+func loadProviderSchemas(schemas map[addrs.Provider]*providers.Schemas, config *configs.Config, state *states.State, plugins *contextPlugins) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	ensure := func(fqn addrs.Provider) {
+		name := fqn.String()
+
+		if _, exists := schemas[fqn]; exists {
+			return
+		}
+
+		log.Printf("[TRACE] LoadSchemas: retrieving schema for provider type %q", name)
+		schema, err := plugins.ProviderSchema(fqn)
+		if err != nil {
+			// We'll put a stub in the map so we won't re-attempt this on
+			// future calls, which would then repeat the same error message
+			// multiple times.
+			schemas[fqn] = &providers.Schemas{}
+			diags = diags.Append(
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to obtain provider schema",
+					fmt.Sprintf("Could not load the schema for provider %s: %s.", fqn, err),
+				),
+			)
+			return
+		}
+
+		schemas[fqn] = schema
+	}
+
+	if config != nil {
+		for _, fqn := range config.ProviderTypes() {
+			ensure(fqn)
+		}
+	}
+
+	if state != nil {
+		needed := providers.AddressedTypesAbs(state.ProviderAddrs())
+		for _, typeAddr := range needed {
+			ensure(typeAddr)
+		}
+	}
+
+	return diags
+}
+
+func loadProvisionerSchemas(schemas map[string]*configschema.Block, config *configs.Config, plugins *contextPlugins) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	ensure := func(name string) {
+		if _, exists := schemas[name]; exists {
+			return
+		}
+
+		log.Printf("[TRACE] LoadSchemas: retrieving schema for provisioner %q", name)
+		schema, err := plugins.ProvisionerSchema(name)
+		if err != nil {
+			// We'll put a stub in the map so we won't re-attempt this on
+			// future calls, which would then repeat the same error message
+			// multiple times.
+			schemas[name] = &configschema.Block{}
+			diags = diags.Append(
+				tfdiags.Sourceless(
+					tfdiags.Error,
+					"Failed to obtain provisioner schema",
+					fmt.Sprintf("Could not load the schema for provisioner %q: %s.", name, err),
+				),
+			)
+			return
+		}
+
+		schemas[name] = schema
+	}
+
+	if config != nil {
+		for _, rc := range config.Module.ManagedResources {
+			for _, pc := range rc.Managed.Provisioners {
+				ensure(pc.Type)
+			}
+		}
+
+		// Must also visit our child modules, recursively.
+		for _, cc := range config.Children {
+			childDiags := loadProvisionerSchemas(schemas, cc, plugins)
+			diags = diags.Append(childDiags)
+		}
+	}
+
+	return diags
+}
diff --git a/v1.5.7/internal/terraform/schemas_test.go b/v1.5.7/internal/terraform/schemas_test.go
new file mode 100644
index 0000000..46792c7
--- /dev/null
+++ b/v1.5.7/internal/terraform/schemas_test.go
@@ -0,0 +1,68 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+)
+
+func simpleTestSchemas() *Schemas {
+	provider := simpleMockProvider()
+	provisioner := simpleMockProvisioner()
+
+	return &Schemas{
+		Providers: map[addrs.Provider]*ProviderSchema{
+			addrs.NewDefaultProvider("test"): provider.ProviderSchema(),
+		},
+		Provisioners: map[string]*configschema.Block{
+			"test": provisioner.GetSchemaResponse.Provisioner,
+		},
+	}
+}
+
+// schemaOnlyProvidersForTesting is a testing helper that constructs a
+// plugin library that contains a set of providers that only know how to
+// return schema, and will exhibit undefined behavior if used for any other
+// purpose.
+//
+// The intended use for this is in testing components that use schemas to
+// drive other behavior, such as reference analysis during graph construction,
+// but that don't actually need to interact with providers otherwise.
+func schemaOnlyProvidersForTesting(schemas map[addrs.Provider]*ProviderSchema) *contextPlugins {
+	factories := make(map[addrs.Provider]providers.Factory, len(schemas))
+
+	for providerAddr, schema := range schemas {
+
+		resp := &providers.GetProviderSchemaResponse{
+			Provider: providers.Schema{
+				Block: schema.Provider,
+			},
+			ResourceTypes: make(map[string]providers.Schema),
+			DataSources:   make(map[string]providers.Schema),
+		}
+		for t, tSchema := range schema.ResourceTypes {
+			resp.ResourceTypes[t] = providers.Schema{
+				Block:   tSchema,
+				Version: int64(schema.ResourceTypeSchemaVersions[t]),
+			}
+		}
+		for t, tSchema := range schema.DataSources {
+			resp.DataSources[t] = providers.Schema{
+				Block: tSchema,
+			}
+		}
+
+		provider := &MockProvider{
+			GetProviderSchemaResponse: resp,
+		}
+
+		factories[providerAddr] = func() (providers.Interface, error) {
+			return provider, nil
+		}
+	}
+
+	return newContextPlugins(factories, nil)
+}
diff --git a/v1.5.7/internal/terraform/terraform_test.go b/v1.5.7/internal/terraform/terraform_test.go
new file mode 100644
index 0000000..740d88a
--- /dev/null
+++ b/v1.5.7/internal/terraform/terraform_test.go
@@ -0,0 +1,1086 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"context"
+	"flag"
+	"io"
+	"os"
+	"path/filepath"
+	"strings"
+	"sync"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configload"
+	"github.com/hashicorp/terraform/internal/initwd"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/provisioners"
+	"github.com/hashicorp/terraform/internal/registry"
+	"github.com/hashicorp/terraform/internal/states"
+
+	_ "github.com/hashicorp/terraform/internal/logging"
+)
+
+// This is the directory where our test fixtures are.
+const fixtureDir = "./testdata"
+
+func TestMain(m *testing.M) {
+	flag.Parse()
+
+	// We have fmt.Stringer implementations on lots of objects that hide
+	// details that we very often want to see in tests, so we just disable
+	// spew's use of String methods globally on the assumption that spew
+	// usage implies an intent to see the raw values and ignore any
+	// abstractions.
+	spew.Config.DisableMethods = true
+
+	os.Exit(m.Run())
+}
+
+func testModule(t *testing.T, name string) *configs.Config {
+	t.Helper()
+	c, _ := testModuleWithSnapshot(t, name)
+	return c
+}
+
+func testModuleWithSnapshot(t *testing.T, name string) (*configs.Config, *configload.Snapshot) {
+	t.Helper()
+
+	dir := filepath.Join(fixtureDir, name)
+	// FIXME: We're not dealing with the cleanup function here because
+	// this testModule function is used all over and so we don't want to
+	// change its interface at this late stage.
+	loader, _ := configload.NewLoaderForTests(t)
+
+	// We need to be able to exercise experimental features in our integration tests.
+	loader.AllowLanguageExperiments(true)
+
+	// Test modules usually do not refer to remote sources, and for local
+	// sources only this ultimately just records all of the module paths
+	// in a JSON file so that we can load them below.
+	inst := initwd.NewModuleInstaller(loader.ModulesDir(), loader, registry.NewClient(nil, nil))
+	_, instDiags := inst.InstallModules(context.Background(), dir, true, initwd.ModuleInstallHooksImpl{})
+	if instDiags.HasErrors() {
+		t.Fatal(instDiags.Err())
+	}
+
+	// Since module installer has modified the module manifest on disk, we need
+	// to refresh the cache of it in the loader.
+	if err := loader.RefreshModules(); err != nil {
+		t.Fatalf("failed to refresh modules after installation: %s", err)
+	}
+
+	config, snap, diags := loader.LoadConfigWithSnapshot(dir)
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	return config, snap
+}
+
+// testModuleInline takes a map of path -> config strings and yields a config
+// structure with those files loaded from disk
+func testModuleInline(t *testing.T, sources map[string]string) *configs.Config {
+	t.Helper()
+
+	cfgPath := t.TempDir()
+
+	for path, configStr := range sources {
+		dir := filepath.Dir(path)
+		if dir != "." {
+			err := os.MkdirAll(filepath.Join(cfgPath, dir), os.FileMode(0777))
+			if err != nil {
+				t.Fatalf("Error creating subdir: %s", err)
+			}
+		}
+		// Write the configuration
+		cfgF, err := os.Create(filepath.Join(cfgPath, path))
+		if err != nil {
+			t.Fatalf("Error creating temporary file for config: %s", err)
+		}
+
+		_, err = io.Copy(cfgF, strings.NewReader(configStr))
+		cfgF.Close()
+		if err != nil {
+			t.Fatalf("Error creating temporary file for config: %s", err)
+		}
+	}
+
+	loader, cleanup := configload.NewLoaderForTests(t)
+	defer cleanup()
+
+	// We need to be able to exercise experimental features in our integration tests.
+	loader.AllowLanguageExperiments(true)
+
+	// Test modules usually do not refer to remote sources, and for local
+	// sources only this ultimately just records all of the module paths
+	// in a JSON file so that we can load them below.
+	inst := initwd.NewModuleInstaller(loader.ModulesDir(), loader, registry.NewClient(nil, nil))
+	_, instDiags := inst.InstallModules(context.Background(), cfgPath, true, initwd.ModuleInstallHooksImpl{})
+	if instDiags.HasErrors() {
+		t.Fatal(instDiags.Err())
+	}
+
+	// Since module installer has modified the module manifest on disk, we need
+	// to refresh the cache of it in the loader.
+	if err := loader.RefreshModules(); err != nil {
+		t.Fatalf("failed to refresh modules after installation: %s", err)
+	}
+
+	config, diags := loader.LoadConfig(cfgPath)
+	if diags.HasErrors() {
+		t.Fatal(diags.Error())
+	}
+
+	return config
+}
+
+// testSetResourceInstanceCurrent is a helper function for tests that sets a Current,
+// Ready resource instance for the given module.
+func testSetResourceInstanceCurrent(module *states.Module, resource, attrsJson, provider string) {
+	module.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr(resource).Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(attrsJson),
+		},
+		mustProviderConfig(provider),
+	)
+}
+
+// testSetResourceInstanceTainted is a helper function for tests that sets a Current,
+// Tainted resource instance for the given module.
+func testSetResourceInstanceTainted(module *states.Module, resource, attrsJson, provider string) {
+	module.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr(resource).Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectTainted,
+			AttrsJSON: []byte(attrsJson),
+		},
+		mustProviderConfig(provider),
+	)
+}
+
+func testProviderFuncFixed(rp providers.Interface) providers.Factory {
+	return func() (providers.Interface, error) {
+		if p, ok := rp.(*MockProvider); ok {
+			// make sure none of the methods were "called" on this new instance
+			p.GetProviderSchemaCalled = false
+			p.ValidateProviderConfigCalled = false
+			p.ValidateResourceConfigCalled = false
+			p.ValidateDataResourceConfigCalled = false
+			p.UpgradeResourceStateCalled = false
+			p.ConfigureProviderCalled = false
+			p.StopCalled = false
+			p.ReadResourceCalled = false
+			p.PlanResourceChangeCalled = false
+			p.ApplyResourceChangeCalled = false
+			p.ImportResourceStateCalled = false
+			p.ReadDataSourceCalled = false
+			p.CloseCalled = false
+		}
+
+		return rp, nil
+	}
+}
+
+func testProvisionerFuncFixed(rp *MockProvisioner) provisioners.Factory {
+	return func() (provisioners.Interface, error) {
+		// make sure this provisioner has has not been closed
+		rp.CloseCalled = false
+		return rp, nil
+	}
+}
+
+func mustResourceInstanceAddr(s string) addrs.AbsResourceInstance {
+	addr, diags := addrs.ParseAbsResourceInstanceStr(s)
+	if diags.HasErrors() {
+		panic(diags.Err())
+	}
+	return addr
+}
+
+func mustConfigResourceAddr(s string) addrs.ConfigResource {
+	addr, diags := addrs.ParseAbsResourceStr(s)
+	if diags.HasErrors() {
+		panic(diags.Err())
+	}
+	return addr.Config()
+}
+
+func mustAbsResourceAddr(s string) addrs.AbsResource {
+	addr, diags := addrs.ParseAbsResourceStr(s)
+	if diags.HasErrors() {
+		panic(diags.Err())
+	}
+	return addr
+}
+
+func mustProviderConfig(s string) addrs.AbsProviderConfig {
+	p, diags := addrs.ParseAbsProviderConfigStr(s)
+	if diags.HasErrors() {
+		panic(diags.Err())
+	}
+	return p
+}
+
+// HookRecordApplyOrder is a test hook that records the order of applies
+// by recording the PreApply event.
+type HookRecordApplyOrder struct {
+	NilHook
+
+	Active bool
+
+	IDs    []string
+	States []cty.Value
+	Diffs  []*plans.Change
+
+	l sync.Mutex
+}
+
+func (h *HookRecordApplyOrder) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) {
+	if plannedNewState.RawEquals(priorState) {
+		return HookActionContinue, nil
+	}
+
+	if h.Active {
+		h.l.Lock()
+		defer h.l.Unlock()
+
+		h.IDs = append(h.IDs, addr.String())
+		h.Diffs = append(h.Diffs, &plans.Change{
+			Action: action,
+			Before: priorState,
+			After:  plannedNewState,
+		})
+		h.States = append(h.States, priorState)
+	}
+
+	return HookActionContinue, nil
+}
+
+// Below are all the constant strings that are the expected output for
+// various tests.
+
+const testTerraformInputProviderOnlyStr = `
+aws_instance.foo:
+  ID = 
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = us-west-2
+  type = 
+`
+
+const testTerraformApplyStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+`
+
+const testTerraformApplyDataBasicStr = `
+data.null_data_source.testing:
+  ID = yo
+  provider = provider["registry.terraform.io/hashicorp/null"]
+`
+
+const testTerraformApplyRefCountStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = 3
+  type = aws_instance
+
+  Dependencies:
+    aws_instance.foo
+aws_instance.foo.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+aws_instance.foo.1:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+aws_instance.foo.2:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+`
+
+const testTerraformApplyProviderAliasStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"].bar
+  foo = bar
+  type = aws_instance
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+`
+
+const testTerraformApplyProviderAliasConfigStr = `
+another_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/another"].two
+  type = another_instance
+another_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/another"]
+  type = another_instance
+`
+
+const testTerraformApplyEmptyModuleStr = `
+<no state>
+Outputs:
+
+end = XXXX
+`
+
+const testTerraformApplyDependsCreateBeforeStr = `
+aws_instance.lb:
+  ID = baz
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  instance = foo
+  type = aws_instance
+
+  Dependencies:
+    aws_instance.web
+aws_instance.web:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  require_new = ami-new
+  type = aws_instance
+`
+
+const testTerraformApplyCreateBeforeStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  require_new = xyz
+  type = aws_instance
+`
+
+const testTerraformApplyCreateBeforeUpdateStr = `
+aws_instance.bar:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = baz
+  type = aws_instance
+`
+
+const testTerraformApplyCancelStr = `
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+  value = 2
+`
+
+const testTerraformApplyComputeStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = computed_value
+  type = aws_instance
+
+  Dependencies:
+    aws_instance.foo
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  compute = value
+  compute_value = 1
+  num = 2
+  type = aws_instance
+  value = computed_value
+`
+
+const testTerraformApplyCountDecStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+aws_instance.foo.0:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  type = aws_instance
+aws_instance.foo.1:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  type = aws_instance
+`
+
+const testTerraformApplyCountDecToOneStr = `
+aws_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  type = aws_instance
+`
+
+const testTerraformApplyCountDecToOneCorruptedStr = `
+aws_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  type = aws_instance
+`
+
+const testTerraformApplyCountDecToOneCorruptedPlanStr = `
+DIFF:
+
+DESTROY: aws_instance.foo[0]
+  id:   "baz" => ""
+  type: "aws_instance" => ""
+
+
+
+STATE:
+
+aws_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  type = aws_instance
+aws_instance.foo.0:
+  ID = baz
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+`
+
+const testTerraformApplyCountVariableStr = `
+aws_instance.foo.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  type = aws_instance
+aws_instance.foo.1:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  type = aws_instance
+`
+
+const testTerraformApplyCountVariableRefStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = 2
+  type = aws_instance
+
+  Dependencies:
+    aws_instance.foo
+aws_instance.foo.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+aws_instance.foo.1:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+`
+const testTerraformApplyForEachVariableStr = `
+aws_instance.foo["b15c6d616d6143248c575900dff57325eb1de498"]:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  type = aws_instance
+aws_instance.foo["c3de47d34b0a9f13918dd705c141d579dd6555fd"]:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  type = aws_instance
+aws_instance.foo["e30a7edcc42a846684f2a4eea5f3cd261d33c46d"]:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  type = aws_instance
+aws_instance.one["a"]:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+aws_instance.one["b"]:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+aws_instance.two["a"]:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+
+  Dependencies:
+    aws_instance.one
+aws_instance.two["b"]:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+
+  Dependencies:
+    aws_instance.one`
+const testTerraformApplyMinimalStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+`
+
+const testTerraformApplyModuleStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+
+module.child:
+  aws_instance.baz:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    foo = bar
+    type = aws_instance
+`
+
+const testTerraformApplyModuleBoolStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = true
+  type = aws_instance
+`
+
+const testTerraformApplyModuleDestroyOrderStr = `
+<no state>
+`
+
+const testTerraformApplyMultiProviderStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+do_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/do"]
+  num = 2
+  type = do_instance
+`
+
+const testTerraformApplyModuleOnlyProviderStr = `
+<no state>
+module.child:
+  aws_instance.foo:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    type = aws_instance
+  test_instance.foo:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/test"]
+    type = test_instance
+`
+
+const testTerraformApplyModuleProviderAliasStr = `
+<no state>
+module.child:
+  aws_instance.foo:
+    ID = foo
+    provider = module.child.provider["registry.terraform.io/hashicorp/aws"].eu
+    type = aws_instance
+`
+
+const testTerraformApplyModuleVarRefExistingStr = `
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+
+module.child:
+  aws_instance.foo:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    type = aws_instance
+    value = bar
+
+    Dependencies:
+      aws_instance.foo
+`
+
+const testTerraformApplyOutputOrphanStr = `
+<no state>
+Outputs:
+
+foo = bar
+`
+
+const testTerraformApplyOutputOrphanModuleStr = `
+<no state>
+`
+
+const testTerraformApplyProvisionerStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+
+  Dependencies:
+    aws_instance.foo
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  compute = value
+  compute_value = 1
+  num = 2
+  type = aws_instance
+  value = computed_value
+`
+
+const testTerraformApplyProvisionerModuleStr = `
+<no state>
+module.child:
+  aws_instance.bar:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    type = aws_instance
+`
+
+const testTerraformApplyProvisionerFailStr = `
+aws_instance.bar: (tainted)
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+`
+
+const testTerraformApplyProvisionerFailCreateStr = `
+aws_instance.bar: (tainted)
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+`
+
+const testTerraformApplyProvisionerFailCreateNoIdStr = `
+<no state>
+`
+
+const testTerraformApplyProvisionerFailCreateBeforeDestroyStr = `
+aws_instance.bar: (tainted) (1 deposed)
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  require_new = xyz
+  type = aws_instance
+  Deposed ID 1 = bar
+`
+
+const testTerraformApplyProvisionerResourceRefStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+`
+
+const testTerraformApplyProvisionerSelfRefStr = `
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+`
+
+const testTerraformApplyProvisionerMultiSelfRefStr = `
+aws_instance.foo.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = number 0
+  type = aws_instance
+aws_instance.foo.1:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = number 1
+  type = aws_instance
+aws_instance.foo.2:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = number 2
+  type = aws_instance
+`
+
+const testTerraformApplyProvisionerMultiSelfRefSingleStr = `
+aws_instance.foo.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = number 0
+  type = aws_instance
+aws_instance.foo.1:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = number 1
+  type = aws_instance
+aws_instance.foo.2:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = number 2
+  type = aws_instance
+`
+
+const testTerraformApplyProvisionerDiffStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+`
+
+const testTerraformApplyProvisionerSensitiveStr = `
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+`
+
+const testTerraformApplyDestroyStr = `
+<no state>
+`
+
+const testTerraformApplyErrorStr = `
+aws_instance.bar: (tainted)
+  ID = 
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = 2
+
+  Dependencies:
+    aws_instance.foo
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+  value = 2
+`
+
+const testTerraformApplyErrorCreateBeforeDestroyStr = `
+aws_instance.bar:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  require_new = abc
+  type = aws_instance
+`
+
+const testTerraformApplyErrorDestroyCreateBeforeDestroyStr = `
+aws_instance.bar: (1 deposed)
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  require_new = xyz
+  type = aws_instance
+  Deposed ID 1 = bar
+`
+
+const testTerraformApplyErrorPartialStr = `
+aws_instance.bar:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+
+  Dependencies:
+    aws_instance.foo
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  type = aws_instance
+  value = 2
+`
+
+const testTerraformApplyResourceDependsOnModuleStr = `
+aws_instance.a:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  ami = parent
+  type = aws_instance
+
+  Dependencies:
+    module.child.aws_instance.child
+
+module.child:
+  aws_instance.child:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    ami = child
+    type = aws_instance
+`
+
+const testTerraformApplyResourceDependsOnModuleDeepStr = `
+aws_instance.a:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  ami = parent
+  type = aws_instance
+
+  Dependencies:
+    module.child.module.grandchild.aws_instance.c
+
+module.child.grandchild:
+  aws_instance.c:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    ami = grandchild
+    type = aws_instance
+`
+
+const testTerraformApplyResourceDependsOnModuleInModuleStr = `
+<no state>
+module.child:
+  aws_instance.b:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    ami = child
+    type = aws_instance
+
+    Dependencies:
+      module.child.module.grandchild.aws_instance.c
+module.child.grandchild:
+  aws_instance.c:
+    ID = foo
+    provider = provider["registry.terraform.io/hashicorp/aws"]
+    ami = grandchild
+    type = aws_instance
+`
+
+const testTerraformApplyTaintStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+`
+
+const testTerraformApplyTaintDepStr = `
+aws_instance.bar:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  num = 2
+  type = aws_instance
+
+  Dependencies:
+    aws_instance.foo
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+`
+
+const testTerraformApplyTaintDepRequireNewStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo
+  require_new = yes
+  type = aws_instance
+
+  Dependencies:
+    aws_instance.foo
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+`
+
+const testTerraformApplyOutputStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+
+Outputs:
+
+foo_num = 2
+`
+
+const testTerraformApplyOutputAddStr = `
+aws_instance.test.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo0
+  type = aws_instance
+aws_instance.test.1:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = foo1
+  type = aws_instance
+
+Outputs:
+
+firstOutput = foo0
+secondOutput = foo1
+`
+
+const testTerraformApplyOutputListStr = `
+aws_instance.bar.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+aws_instance.bar.1:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+aws_instance.bar.2:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+
+Outputs:
+
+foo_num = [bar,bar,bar]
+`
+
+const testTerraformApplyOutputMultiStr = `
+aws_instance.bar.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+aws_instance.bar.1:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+aws_instance.bar.2:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+
+Outputs:
+
+foo_num = bar,bar,bar
+`
+
+const testTerraformApplyOutputMultiIndexStr = `
+aws_instance.bar.0:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+aws_instance.bar.1:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+aws_instance.bar.2:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  foo = bar
+  type = aws_instance
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+
+Outputs:
+
+foo_num = bar
+`
+
+const testTerraformApplyUnknownAttrStr = `
+aws_instance.foo: (tainted)
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  num = 2
+  type = aws_instance
+`
+
+const testTerraformApplyVarsStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  bar = override
+  baz = override
+  foo = us-east-1
+aws_instance.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  bar = baz
+  list.# = 2
+  list.0 = Hello
+  list.1 = World
+  map.Baz = Foo
+  map.Foo = Bar
+  map.Hello = World
+  num = 2
+`
+
+const testTerraformApplyVarsEnvStr = `
+aws_instance.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/aws"]
+  list.# = 2
+  list.0 = Hello
+  list.1 = World
+  map.Baz = Foo
+  map.Foo = Bar
+  map.Hello = World
+  string = baz
+  type = aws_instance
+`
+
+const testTerraformRefreshDataRefDataStr = `
+data.null_data_source.bar:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/null"]
+  bar = yes
+data.null_data_source.foo:
+  ID = foo
+  provider = provider["registry.terraform.io/hashicorp/null"]
+  foo = yes
+`
diff --git a/v1.5.7/internal/terraform/testdata/apply-blank/main.tf b/v1.5.7/internal/terraform/testdata/apply-blank/main.tf
new file mode 100644
index 0000000..0081db1
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-blank/main.tf
@@ -0,0 +1 @@
+// Nothing!
diff --git a/v1.5.7/internal/terraform/testdata/apply-cancel-block/main.tf b/v1.5.7/internal/terraform/testdata/apply-cancel-block/main.tf
new file mode 100644
index 0000000..98f5ee8
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-cancel-block/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-cancel-provisioner/main.tf b/v1.5.7/internal/terraform/testdata/apply-cancel-provisioner/main.tf
new file mode 100644
index 0000000..dadabd8
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-cancel-provisioner/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    num = "2"
+
+    provisioner "shell" {
+        foo = "bar"
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-cancel/main.tf b/v1.5.7/internal/terraform/testdata/apply-cancel/main.tf
new file mode 100644
index 0000000..7c4af5f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-cancel/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    value = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${aws_instance.foo.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-cbd-count/main.tf b/v1.5.7/internal/terraform/testdata/apply-cbd-count/main.tf
new file mode 100644
index 0000000..058d338
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-cbd-count/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "bar" {
+  count = 2
+  foo   = "bar"
+
+  lifecycle {
+    create_before_destroy = true
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-cbd-cycle/main.tf b/v1.5.7/internal/terraform/testdata/apply-cbd-cycle/main.tf
new file mode 100644
index 0000000..5ac5310
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-cbd-cycle/main.tf
@@ -0,0 +1,19 @@
+resource "test_instance" "a" {
+  foo = test_instance.b.id
+  require_new = "changed"
+
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+
+resource "test_instance" "b" {
+  foo = test_instance.c.id
+  require_new = "changed"
+}
+
+
+resource "test_instance" "c" {
+  require_new = "changed"
+}
+
diff --git a/v1.5.7/internal/terraform/testdata/apply-cbd-depends-non-cbd/main.tf b/v1.5.7/internal/terraform/testdata/apply-cbd-depends-non-cbd/main.tf
new file mode 100644
index 0000000..6ba1b98
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-cbd-depends-non-cbd/main.tf
@@ -0,0 +1,12 @@
+resource "aws_instance" "foo" {
+  require_new = "yes"
+}
+
+resource "aws_instance" "bar" {
+  require_new = "yes"
+  value       = "${aws_instance.foo.id}"
+
+  lifecycle {
+    create_before_destroy = true
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-cbd-deposed-only/main.tf b/v1.5.7/internal/terraform/testdata/apply-cbd-deposed-only/main.tf
new file mode 100644
index 0000000..0d2e2d3
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-cbd-deposed-only/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "bar" {
+  lifecycle {
+    create_before_destroy = true
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-compute/main.tf b/v1.5.7/internal/terraform/testdata/apply-compute/main.tf
new file mode 100644
index 0000000..e785294
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-compute/main.tf
@@ -0,0 +1,13 @@
+variable "value" {
+    default = ""
+}
+
+resource "aws_instance" "foo" {
+    num = "2"
+    compute = "value"
+    compute_value = "${var.value}"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${aws_instance.foo.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-count-dec-one/main.tf b/v1.5.7/internal/terraform/testdata/apply-count-dec-one/main.tf
new file mode 100644
index 0000000..3b0fd94
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-count-dec-one/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+    foo = "foo"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-count-dec/main.tf b/v1.5.7/internal/terraform/testdata/apply-count-dec/main.tf
new file mode 100644
index 0000000..f18748c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-count-dec/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+    foo = "foo"
+    count = 2
+}
+
+resource "aws_instance" "bar" {
+    foo = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-count-tainted/main.tf b/v1.5.7/internal/terraform/testdata/apply-count-tainted/main.tf
new file mode 100644
index 0000000..ba35b03
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-count-tainted/main.tf
@@ -0,0 +1,4 @@
+resource "aws_instance" "foo" {
+    count = 2
+    foo = "foo"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-count-variable-ref/main.tf b/v1.5.7/internal/terraform/testdata/apply-count-variable-ref/main.tf
new file mode 100644
index 0000000..8e9e452
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-count-variable-ref/main.tf
@@ -0,0 +1,11 @@
+variable "foo" {
+  default = "2"
+}
+
+resource "aws_instance" "foo" {
+  count = "${var.foo}"
+}
+
+resource "aws_instance" "bar" {
+  foo = length(aws_instance.foo)
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-count-variable/main.tf b/v1.5.7/internal/terraform/testdata/apply-count-variable/main.tf
new file mode 100644
index 0000000..6f322f2
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-count-variable/main.tf
@@ -0,0 +1,8 @@
+variable "foo" {
+    default = "2"
+}
+
+resource "aws_instance" "foo" {
+    foo = "foo"
+    count = "${var.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-data-basic/main.tf b/v1.5.7/internal/terraform/testdata/apply-data-basic/main.tf
new file mode 100644
index 0000000..0c3bd88
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-data-basic/main.tf
@@ -0,0 +1 @@
+data "null_data_source" "testing" {}
diff --git a/v1.5.7/internal/terraform/testdata/apply-data-sensitive/main.tf b/v1.5.7/internal/terraform/testdata/apply-data-sensitive/main.tf
new file mode 100644
index 0000000..c248a7c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-data-sensitive/main.tf
@@ -0,0 +1,8 @@
+variable "foo" {
+  sensitive = true
+  default = "foo"
+}
+
+data "null_data_source" "testing" {
+  foo = var.foo
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-depends-create-before/main.tf b/v1.5.7/internal/terraform/testdata/apply-depends-create-before/main.tf
new file mode 100644
index 0000000..63478d8
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-depends-create-before/main.tf
@@ -0,0 +1,10 @@
+resource "aws_instance" "web" {
+  require_new = "ami-new"
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+
+resource "aws_instance" "lb" {
+  instance = aws_instance.web.id
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-cbd/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-cbd/main.tf
new file mode 100644
index 0000000..3c7a46f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-cbd/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" { }
+resource "aws_instance" "bar" {
+  depends_on = ["aws_instance.foo"]
+  lifecycle {
+    create_before_destroy = true
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-computed/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-computed/child/main.tf
new file mode 100644
index 0000000..5cd1f02
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-computed/child/main.tf
@@ -0,0 +1,5 @@
+variable "value" {}
+
+resource "aws_instance" "bar" {
+    value = "${var.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-computed/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-computed/main.tf
new file mode 100644
index 0000000..768c968
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-computed/main.tf
@@ -0,0 +1,6 @@
+resource "aws_instance" "foo" {}
+
+module "child" {
+    source = "./child"
+    value = "${aws_instance.foo.output}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-cross-providers/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-cross-providers/child/main.tf
new file mode 100644
index 0000000..048b26d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-cross-providers/child/main.tf
@@ -0,0 +1,5 @@
+variable "value" {}
+
+resource "aws_vpc" "bar" {
+    value = "${var.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-cross-providers/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-cross-providers/main.tf
new file mode 100644
index 0000000..1ff123a
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-cross-providers/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "shared" {
+}
+
+module "child" {
+    source = "./child"
+    value = "${aws_instance.shared.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-data-cycle/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-data-cycle/main.tf
new file mode 100644
index 0000000..591af82
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-data-cycle/main.tf
@@ -0,0 +1,14 @@
+locals {
+    l = data.null_data_source.d.id
+}
+
+data "null_data_source" "d" {
+}
+
+resource "null_resource" "a" {
+    count = local.l == "NONE" ? 1 : 0
+}
+
+provider "test" {
+  foo = data.null_data_source.d.id
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-data-resource/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-data-resource/main.tf
new file mode 100644
index 0000000..0d941a7
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-data-resource/main.tf
@@ -0,0 +1,3 @@
+data "null_data_source" "testing" {
+  foo = "yes"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/main.tf
new file mode 100644
index 0000000..3694951
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/main.tf
@@ -0,0 +1,3 @@
+module "subchild" {
+  source = "./subchild"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/subchild/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/subchild/main.tf
new file mode 100644
index 0000000..d31b87e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/subchild/main.tf
@@ -0,0 +1,5 @@
+/*
+module "subsubchild" {
+  source = "./subsubchild"
+}
+*/
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/subchild/subsubchild/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/subchild/subsubchild/main.tf
new file mode 100644
index 0000000..6ff716a
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/subchild/subsubchild/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "bar" {}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-deeply-nested-module/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-deeply-nested-module/main.tf
new file mode 100644
index 0000000..1f95749
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-deeply-nested-module/main.tf
@@ -0,0 +1,3 @@
+module "child" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-depends-on/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-depends-on/main.tf
new file mode 100644
index 0000000..3c3ee65
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-depends-on/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "foo" {
+    depends_on = ["aws_instance.bar"]
+}
+
+resource "aws_instance" "bar" {}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/child/child2/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/child/child2/main.tf
new file mode 100644
index 0000000..6a4f91d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/child/child2/main.tf
@@ -0,0 +1,5 @@
+variable "mod_count_child2" { }
+
+resource "aws_instance" "foo" {
+  count = "${var.mod_count_child2}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/child/main.tf
new file mode 100644
index 0000000..28b5267
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/child/main.tf
@@ -0,0 +1,8 @@
+variable "mod_count_child" { }
+
+module "child2" {
+  source    = "./child2"
+  mod_count_child2 = "${var.mod_count_child}"
+}
+
+resource "aws_instance" "foo" { }
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/main.tf
new file mode 100644
index 0000000..58600cd
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/main.tf
@@ -0,0 +1,9 @@
+variable "mod_count_root" {
+  type    = string
+  default = "3"
+}
+
+module "child" {
+  source          = "./child"
+  mod_count_child = var.mod_count_root
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-and-count/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-and-count/child/main.tf
new file mode 100644
index 0000000..67dac02
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-and-count/child/main.tf
@@ -0,0 +1,5 @@
+variable "mod_count" { }
+
+resource "aws_instance" "foo" {
+  count = "${var.mod_count}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-and-count/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-and-count/main.tf
new file mode 100644
index 0000000..918b40d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-and-count/main.tf
@@ -0,0 +1,4 @@
+module "child" {
+  source    = "./child"
+  mod_count = "3"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-provider-config/child/child.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-provider-config/child/child.tf
new file mode 100644
index 0000000..6544cf6
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-provider-config/child/child.tf
@@ -0,0 +1,7 @@
+variable "input" {}
+
+provider "aws" {
+  region = "us-east-${var.input}"
+}
+
+resource "aws_instance" "foo" { }
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-provider-config/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-provider-config/main.tf
new file mode 100644
index 0000000..1e2dfb3
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-mod-var-provider-config/main.tf
@@ -0,0 +1,4 @@
+module "child" {
+  source = "./child"
+  input = "1"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-module-resource-prefix/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-module-resource-prefix/child/main.tf
new file mode 100644
index 0000000..919f140
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-module-resource-prefix/child/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-module-resource-prefix/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-module-resource-prefix/main.tf
new file mode 100644
index 0000000..0f6991c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-module-resource-prefix/main.tf
@@ -0,0 +1,3 @@
+module "child" {
+    source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-module-with-attrs/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-module-with-attrs/child/main.tf
new file mode 100644
index 0000000..55fa601
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-module-with-attrs/child/main.tf
@@ -0,0 +1,9 @@
+variable "vpc_id" {}
+
+resource "aws_instance" "child" {
+  vpc_id = var.vpc_id
+}
+
+output "modout" {
+  value = aws_instance.child.id
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-module-with-attrs/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-module-with-attrs/main.tf
new file mode 100644
index 0000000..9b2d46d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-module-with-attrs/main.tf
@@ -0,0 +1,10 @@
+resource "aws_instance" "vpc" { }
+
+module "child" {
+  source = "./child"
+  vpc_id = aws_instance.vpc.id
+}
+
+output "out" {
+  value = module.child.modout
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/middle/bottom/bottom.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/middle/bottom/bottom.tf
new file mode 100644
index 0000000..b5db44e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/middle/bottom/bottom.tf
@@ -0,0 +1,5 @@
+variable bottom_param {}
+
+resource "null_resource" "bottom" {
+  value = "${var.bottom_param}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/middle/middle.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/middle/middle.tf
new file mode 100644
index 0000000..76652ee
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/middle/middle.tf
@@ -0,0 +1,10 @@
+variable param {}
+
+module "bottom" {
+  source       = "./bottom"
+  bottom_param = "${var.param}"
+}
+
+resource "null_resource" "middle" {
+  value = "${var.param}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/top.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/top.tf
new file mode 100644
index 0000000..1b631f4
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/top.tf
@@ -0,0 +1,4 @@
+module "middle" {
+  source = "./middle"
+  param  = "foo"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module/child/main.tf
new file mode 100644
index 0000000..852bce8
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module/child/main.tf
@@ -0,0 +1,3 @@
+module "subchild" {
+    source = "./subchild"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module/child/subchild/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module/child/subchild/main.tf
new file mode 100644
index 0000000..6ff716a
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module/child/subchild/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "bar" {}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module/main.tf
new file mode 100644
index 0000000..8a5a1b2
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-nested-module/main.tf
@@ -0,0 +1,5 @@
+/*
+module "child" {
+    source = "./child"
+}
+*/
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-outputs/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-outputs/main.tf
new file mode 100644
index 0000000..8a03847
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-outputs/main.tf
@@ -0,0 +1,34 @@
+data "test_data_source" "bar" {
+  for_each = {
+    a = "b"
+  }
+  foo = "zing"
+}
+
+data "test_data_source" "foo" {
+  for_each = data.test_data_source.bar
+  foo = "ok"
+}
+
+locals {
+  l = [
+    {
+      name = data.test_data_source.foo["a"].id
+      val = "null"
+    },
+  ]
+
+  m = { for v in local.l :
+    v.name => v
+  }
+}
+
+resource "test_instance" "bar" {
+  for_each = local.m
+  foo = format("%s", each.value.name)
+  dep = each.value.val
+}
+
+output "out" {
+  value = test_instance.bar
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-provisider-refs/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-provisider-refs/main.tf
new file mode 100644
index 0000000..e7ef6f0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-provisider-refs/main.tf
@@ -0,0 +1,15 @@
+provider "null" {
+  value = ""
+}
+
+module "mod" {
+  source = "./mod"
+}
+
+provider "test" {
+  value = module.mod.output
+}
+
+resource "test_instance" "bar" {
+}
+
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-provisider-refs/mod/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-provisider-refs/mod/main.tf
new file mode 100644
index 0000000..c9ecec0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-provisider-refs/mod/main.tf
@@ -0,0 +1,9 @@
+data "null_data_source" "foo" {
+       count = 1
+}
+
+
+output "output" {
+  value = data.null_data_source.foo[0].output
+}
+
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-provisioner/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-provisioner/main.tf
new file mode 100644
index 0000000..51b29c7
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-provisioner/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+    provisioner "shell" {}
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-tainted/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-tainted/main.tf
new file mode 100644
index 0000000..48f4f13
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-tainted/main.tf
@@ -0,0 +1,17 @@
+resource "test_instance" "a" {
+  foo = "a"
+}
+
+resource "test_instance" "b" {
+  foo = "b"
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+
+resource "test_instance" "c" {
+  foo = "c"
+  lifecycle {
+    create_before_destroy = true
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-targeted-count/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-targeted-count/main.tf
new file mode 100644
index 0000000..680d30f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-targeted-count/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+  count = 3
+}
+
+resource "aws_instance" "bar" {
+  foo = ["${aws_instance.foo.*.id}"]
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy-with-locals/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy-with-locals/main.tf
new file mode 100644
index 0000000..1ab7518
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy-with-locals/main.tf
@@ -0,0 +1,8 @@
+locals {
+  name = "test-${aws_instance.foo.id}"
+}
+resource "aws_instance" "foo" {}
+
+output "name" {
+  value = "${local.name}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-destroy/main.tf b/v1.5.7/internal/terraform/testdata/apply-destroy/main.tf
new file mode 100644
index 0000000..1b6cdae
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-destroy/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${aws_instance.foo.num}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-empty-module/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-empty-module/child/main.tf
new file mode 100644
index 0000000..6db38ea
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-empty-module/child/main.tf
@@ -0,0 +1,11 @@
+output "aws_route53_zone_id" {
+    value = "XXXX"
+}
+
+output "aws_access_key" {
+    value = "YYYYY"
+}
+
+output "aws_secret_key" {
+    value = "ZZZZ"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-empty-module/main.tf b/v1.5.7/internal/terraform/testdata/apply-empty-module/main.tf
new file mode 100644
index 0000000..50ce84f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-empty-module/main.tf
@@ -0,0 +1,7 @@
+module "child" {
+    source = "./child"
+}
+
+output "end" {
+    value = "${module.child.aws_route53_zone_id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-error-create-before/main.tf b/v1.5.7/internal/terraform/testdata/apply-error-create-before/main.tf
new file mode 100644
index 0000000..c7c2776
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-error-create-before/main.tf
@@ -0,0 +1,6 @@
+resource "aws_instance" "bar" {
+    require_new = "xyz"
+    lifecycle {
+        create_before_destroy = true
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-error/main.tf b/v1.5.7/internal/terraform/testdata/apply-error/main.tf
new file mode 100644
index 0000000..7c4af5f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-error/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    value = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${aws_instance.foo.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-escape/main.tf b/v1.5.7/internal/terraform/testdata/apply-escape/main.tf
new file mode 100644
index 0000000..bca2c9b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-escape/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "bar" {
+    foo = "${"\"bar\""}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-good-create-before-update/main.tf b/v1.5.7/internal/terraform/testdata/apply-good-create-before-update/main.tf
new file mode 100644
index 0000000..d0a2fc9
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-good-create-before-update/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "bar" {
+    foo = "baz"
+
+    lifecycle {
+        create_before_destroy = true
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-good-create-before/main.tf b/v1.5.7/internal/terraform/testdata/apply-good-create-before/main.tf
new file mode 100644
index 0000000..c7c2776
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-good-create-before/main.tf
@@ -0,0 +1,6 @@
+resource "aws_instance" "bar" {
+    require_new = "xyz"
+    lifecycle {
+        create_before_destroy = true
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-good/main.tf b/v1.5.7/internal/terraform/testdata/apply-good/main.tf
new file mode 100644
index 0000000..5c22c19
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-good/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    num = 2
+}
+
+resource "aws_instance" "bar" {
+    foo = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-idattr/main.tf b/v1.5.7/internal/terraform/testdata/apply-idattr/main.tf
new file mode 100644
index 0000000..1c49f39
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-idattr/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+  num = 42
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-ignore-changes-all/main.tf b/v1.5.7/internal/terraform/testdata/apply-ignore-changes-all/main.tf
new file mode 100644
index 0000000..a89889a
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-ignore-changes-all/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+  required_field = "set"
+
+  lifecycle {
+    ignore_changes = all
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-ignore-changes-create/main.tf b/v1.5.7/internal/terraform/testdata/apply-ignore-changes-create/main.tf
new file mode 100644
index 0000000..d470660
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-ignore-changes-create/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+  required_field = "set"
+
+  lifecycle {
+    ignore_changes = ["required_field"]
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-ignore-changes-dep/main.tf b/v1.5.7/internal/terraform/testdata/apply-ignore-changes-dep/main.tf
new file mode 100644
index 0000000..097d489
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-ignore-changes-dep/main.tf
@@ -0,0 +1,12 @@
+resource "aws_instance" "foo" {
+  count         = 2
+  ami           = "ami-bcd456"
+  lifecycle {
+    ignore_changes = ["ami"]
+  }
+}
+
+resource "aws_eip" "foo" {
+  count    = 2
+  instance = "${aws_instance.foo.*.id[count.index]}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-inconsistent-with-plan/main.tf b/v1.5.7/internal/terraform/testdata/apply-inconsistent-with-plan/main.tf
new file mode 100644
index 0000000..9284072
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-inconsistent-with-plan/main.tf
@@ -0,0 +1,2 @@
+resource "test" "foo" {
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-interpolated-count/main.tf b/v1.5.7/internal/terraform/testdata/apply-interpolated-count/main.tf
new file mode 100644
index 0000000..527a0b8
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-interpolated-count/main.tf
@@ -0,0 +1,11 @@
+variable "instance_count" {
+  default = 1
+}
+
+resource "aws_instance" "test" {
+  count = "${var.instance_count}"
+}
+
+resource "aws_instance" "dependent" {
+  count = "${length(aws_instance.test)}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-invalid-index/main.tf b/v1.5.7/internal/terraform/testdata/apply-invalid-index/main.tf
new file mode 100644
index 0000000..8ea02d7
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-invalid-index/main.tf
@@ -0,0 +1,7 @@
+resource "test_instance" "a" {
+  count = 0
+}
+
+resource "test_instance" "b" {
+  value = test_instance.a[0].value
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-issue19908/issue19908.tf b/v1.5.7/internal/terraform/testdata/apply-issue19908/issue19908.tf
new file mode 100644
index 0000000..0c802fb
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-issue19908/issue19908.tf
@@ -0,0 +1,3 @@
+resource "test" "foo" {
+  baz = "updated"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-local-val/child/child.tf b/v1.5.7/internal/terraform/testdata/apply-local-val/child/child.tf
new file mode 100644
index 0000000..f7febc4
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-local-val/child/child.tf
@@ -0,0 +1,4 @@
+
+output "result" {
+  value = "hello"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-local-val/main.tf b/v1.5.7/internal/terraform/testdata/apply-local-val/main.tf
new file mode 100644
index 0000000..51ca2de
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-local-val/main.tf
@@ -0,0 +1,10 @@
+
+module "child" {
+  source = "./child"
+}
+
+locals {
+  result_1 = "${module.child.result}"
+  result_2 = "${local.result_1}"
+  result_3 = "${local.result_2} world"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-local-val/outputs.tf b/v1.5.7/internal/terraform/testdata/apply-local-val/outputs.tf
new file mode 100644
index 0000000..f0078c1
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-local-val/outputs.tf
@@ -0,0 +1,9 @@
+# These are in a separate file to make sure config merging is working properly
+
+output "result_1" {
+  value = "${local.result_1}"
+}
+
+output "result_3" {
+  value = "${local.result_3}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-map-var-through-module/amodule/main.tf b/v1.5.7/internal/terraform/testdata/apply-map-var-through-module/amodule/main.tf
new file mode 100644
index 0000000..a528496
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-map-var-through-module/amodule/main.tf
@@ -0,0 +1,9 @@
+variable "amis" {
+  type = map(string)
+}
+
+resource "null_resource" "noop" {}
+
+output "amis_out" {
+  value = var.amis
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-map-var-through-module/main.tf b/v1.5.7/internal/terraform/testdata/apply-map-var-through-module/main.tf
new file mode 100644
index 0000000..4cec4a6
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-map-var-through-module/main.tf
@@ -0,0 +1,19 @@
+variable "amis_in" {
+  type = map(string)
+  default = {
+    "us-west-1" = "ami-123456"
+    "us-west-2" = "ami-456789"
+    "eu-west-1" = "ami-789012"
+    "eu-west-2" = "ami-989484"
+  }
+}
+
+module "test" {
+  source = "./amodule"
+
+  amis = var.amis_in
+}
+
+output "amis_from_module" {
+  value = module.test.amis_out
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-minimal/main.tf b/v1.5.7/internal/terraform/testdata/apply-minimal/main.tf
new file mode 100644
index 0000000..88002d0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-minimal/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "foo" {
+}
+
+resource "aws_instance" "bar" {
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-bool/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-bool/child/main.tf
new file mode 100644
index 0000000..d2a3843
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-bool/child/main.tf
@@ -0,0 +1,7 @@
+variable "leader" {
+    default = false
+}
+
+output "leader" {
+    value = "${var.leader}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-bool/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-bool/main.tf
new file mode 100644
index 0000000..1d40cd4
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-bool/main.tf
@@ -0,0 +1,8 @@
+module "child" {
+    source = "./child"
+    leader = true
+}
+
+resource "aws_instance" "bar" {
+    foo = "${module.child.leader}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-depends-on/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-depends-on/main.tf
new file mode 100644
index 0000000..9f7102d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-depends-on/main.tf
@@ -0,0 +1,32 @@
+module "moda" {
+  source = "./moda"
+  depends_on = [test_instance.a, module.modb]
+}
+
+resource "test_instance" "a" {
+  depends_on = [module.modb]
+  num = 4
+  foo = test_instance.aa.id
+}
+
+resource "test_instance" "aa" {
+  num = 3
+  foo = module.modb.out
+}
+
+module "modb" {
+  source = "./modb"
+  depends_on = [test_instance.b]
+}
+
+resource "test_instance" "b" {
+  num = 1
+}
+
+output "moda_data" {
+  value = module.moda.out
+}
+
+output "modb_resource" {
+  value = module.modb.out
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-depends-on/moda/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-depends-on/moda/main.tf
new file mode 100644
index 0000000..e60d300
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-depends-on/moda/main.tf
@@ -0,0 +1,11 @@
+resource "test_instance" "a" {
+  num = 5
+}
+
+data "test_data_source" "a" {
+  foo = "a"
+}
+
+output "out" {
+  value = data.test_data_source.a.id
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-depends-on/modb/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-depends-on/modb/main.tf
new file mode 100644
index 0000000..961c5d5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-depends-on/modb/main.tf
@@ -0,0 +1,11 @@
+resource "test_instance" "b" {
+  num = 2
+}
+
+data "test_data_source" "b" {
+  foo = "b"
+}
+
+output "out" {
+  value = test_instance.b.id
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-destroy-order/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-destroy-order/child/main.tf
new file mode 100644
index 0000000..0b2a8bc
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-destroy-order/child/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "a" {
+  id = "a"
+}
+
+output "a_output" {
+  value = "${aws_instance.a.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-destroy-order/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-destroy-order/main.tf
new file mode 100644
index 0000000..2c47eda
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-destroy-order/main.tf
@@ -0,0 +1,8 @@
+module "child" {
+  source = "./child"
+}
+
+resource "aws_instance" "b" {
+  id   = "b"
+  blah = "${module.child.a_output}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-grandchild-provider-inherit/child/grandchild/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-grandchild-provider-inherit/child/grandchild/main.tf
new file mode 100644
index 0000000..919f140
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-grandchild-provider-inherit/child/grandchild/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-grandchild-provider-inherit/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-grandchild-provider-inherit/child/main.tf
new file mode 100644
index 0000000..b422300
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-grandchild-provider-inherit/child/main.tf
@@ -0,0 +1,3 @@
+module "grandchild" {
+  source = "./grandchild"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-grandchild-provider-inherit/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-grandchild-provider-inherit/main.tf
new file mode 100644
index 0000000..25d0993
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-grandchild-provider-inherit/main.tf
@@ -0,0 +1,7 @@
+provider "aws" {
+  value = "foo"
+}
+
+module "child" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-only-provider/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-only-provider/child/main.tf
new file mode 100644
index 0000000..e15099c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-only-provider/child/main.tf
@@ -0,0 +1,2 @@
+resource "aws_instance" "foo" {}
+resource "test_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-only-provider/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-only-provider/main.tf
new file mode 100644
index 0000000..2276b5f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-only-provider/main.tf
@@ -0,0 +1,5 @@
+provider "aws" {}
+
+module "child" {
+    source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-orphan-provider-inherit/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-orphan-provider-inherit/main.tf
new file mode 100644
index 0000000..e334ff2
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-orphan-provider-inherit/main.tf
@@ -0,0 +1,3 @@
+provider "aws" {
+    value = "foo"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-provider-alias/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-provider-alias/child/main.tf
new file mode 100644
index 0000000..ee923f2
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-provider-alias/child/main.tf
@@ -0,0 +1,7 @@
+provider "aws" {
+    alias = "eu"
+}
+
+resource "aws_instance" "foo" {
+    provider = "aws.eu"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-provider-alias/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-provider-alias/main.tf
new file mode 100644
index 0000000..0f6991c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-provider-alias/main.tf
@@ -0,0 +1,3 @@
+module "child" {
+    source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-provider-close-nested/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-provider-close-nested/child/main.tf
new file mode 100644
index 0000000..852bce8
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-provider-close-nested/child/main.tf
@@ -0,0 +1,3 @@
+module "subchild" {
+    source = "./subchild"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-provider-close-nested/child/subchild/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-provider-close-nested/child/subchild/main.tf
new file mode 100644
index 0000000..919f140
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-provider-close-nested/child/subchild/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-provider-close-nested/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-provider-close-nested/main.tf
new file mode 100644
index 0000000..0f6991c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-provider-close-nested/main.tf
@@ -0,0 +1,3 @@
+module "child" {
+    source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-provider-inherit-alias-orphan/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-provider-inherit-alias-orphan/main.tf
new file mode 100644
index 0000000..4332b9a
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-provider-inherit-alias-orphan/main.tf
@@ -0,0 +1,6 @@
+provider "aws" {
+}
+
+provider "aws" {
+  alias = "eu"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-provider-inherit-alias/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-provider-inherit-alias/child/main.tf
new file mode 100644
index 0000000..2db7c4e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-provider-inherit-alias/child/main.tf
@@ -0,0 +1,7 @@
+provider "aws" {
+  alias = "eu"
+}
+
+resource "aws_instance" "foo" {
+    provider = "aws.eu"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-provider-inherit-alias/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-provider-inherit-alias/main.tf
new file mode 100644
index 0000000..a018d14
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-provider-inherit-alias/main.tf
@@ -0,0 +1,15 @@
+provider "aws" {
+    root = 1
+}
+
+provider "aws" {
+    value = "eu"
+    alias = "eu"
+}
+
+module "child" {
+    source = "./child"
+    providers = {
+      "aws.eu" = "aws.eu"
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle-cbd/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle-cbd/main.tf
new file mode 100644
index 0000000..6393231
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle-cbd/main.tf
@@ -0,0 +1,8 @@
+module "a" {
+  source = "./mod1"
+}
+
+module "b" {
+  source = "./mod2"
+  ids = module.a.ids
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle-cbd/mod1/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle-cbd/mod1/main.tf
new file mode 100644
index 0000000..2ade442
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle-cbd/mod1/main.tf
@@ -0,0 +1,10 @@
+resource "aws_instance" "a" {
+  require_new = "new"
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+
+output "ids" {
+  value = [aws_instance.a.id]
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle-cbd/mod2/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle-cbd/mod2/main.tf
new file mode 100644
index 0000000..83fb1dc
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle-cbd/mod2/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "b" {
+  count    = length(var.ids)
+  require_new = var.ids[count.index]
+}
+
+variable "ids" {
+  type = list(string)
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle/main.tf
new file mode 100644
index 0000000..6393231
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle/main.tf
@@ -0,0 +1,8 @@
+module "a" {
+  source = "./mod1"
+}
+
+module "b" {
+  source = "./mod2"
+  ids = module.a.ids
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle/mod1/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle/mod1/main.tf
new file mode 100644
index 0000000..3dd26cb
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle/mod1/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "a" {
+  require_new = "new"
+}
+
+output "ids" {
+  value = [aws_instance.a.id]
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle/mod2/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle/mod2/main.tf
new file mode 100644
index 0000000..83fb1dc
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-replace-cycle/mod2/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "b" {
+  count    = length(var.ids)
+  require_new = var.ids[count.index]
+}
+
+variable "ids" {
+  type = list(string)
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-var-resource-count/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-var-resource-count/child/main.tf
new file mode 100644
index 0000000..1a19910
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-var-resource-count/child/main.tf
@@ -0,0 +1,6 @@
+variable "num" {
+}
+
+resource "aws_instance" "foo" {
+  count = "${var.num}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module-var-resource-count/main.tf b/v1.5.7/internal/terraform/testdata/apply-module-var-resource-count/main.tf
new file mode 100644
index 0000000..6f7d20c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module-var-resource-count/main.tf
@@ -0,0 +1,7 @@
+variable "num" {
+}
+
+module "child" {
+    source = "./child"
+    num = "${var.num}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-module/child/main.tf
new file mode 100644
index 0000000..f279d9b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module/child/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "baz" {
+    foo = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-module/main.tf b/v1.5.7/internal/terraform/testdata/apply-module/main.tf
new file mode 100644
index 0000000..f9119a1
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-module/main.tf
@@ -0,0 +1,11 @@
+module "child" {
+    source = "./child"
+}
+
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-multi-depose-create-before-destroy/main.tf b/v1.5.7/internal/terraform/testdata/apply-multi-depose-create-before-destroy/main.tf
new file mode 100644
index 0000000..e5a723b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-multi-depose-create-before-destroy/main.tf
@@ -0,0 +1,12 @@
+variable "require_new" {
+  type = string
+}
+
+resource "aws_instance" "web" {
+    // require_new is a special attribute recognized by testDiffFn that forces
+    // a new resource on every apply
+    require_new = var.require_new
+    lifecycle {
+        create_before_destroy = true
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-multi-provider-destroy-child/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-multi-provider-destroy-child/child/main.tf
new file mode 100644
index 0000000..ae1bc8e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-multi-provider-destroy-child/child/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "bar" {
+    foo = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-multi-provider-destroy-child/main.tf b/v1.5.7/internal/terraform/testdata/apply-multi-provider-destroy-child/main.tf
new file mode 100644
index 0000000..9b79997
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-multi-provider-destroy-child/main.tf
@@ -0,0 +1,9 @@
+resource "vault_instance" "foo" {}
+
+provider "aws" {
+  value = "${vault_instance.foo.id}"
+}
+
+module "child" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-multi-provider-destroy/main.tf b/v1.5.7/internal/terraform/testdata/apply-multi-provider-destroy/main.tf
new file mode 100644
index 0000000..dd3041b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-multi-provider-destroy/main.tf
@@ -0,0 +1,9 @@
+resource "vault_instance" "foo" {}
+
+provider "aws" {
+  addr = "${vault_instance.foo.id}"
+}
+
+resource "aws_instance" "bar" {
+  foo = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-multi-provider/main.tf b/v1.5.7/internal/terraform/testdata/apply-multi-provider/main.tf
new file mode 100644
index 0000000..4ee94a3
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-multi-provider/main.tf
@@ -0,0 +1,7 @@
+resource "do_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-multi-ref/main.tf b/v1.5.7/internal/terraform/testdata/apply-multi-ref/main.tf
new file mode 100644
index 0000000..2a6a671
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-multi-ref/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "create" {
+	bar = "abc"
+}
+
+resource "aws_instance" "other" {
+	var = "${aws_instance.create.id}"
+    foo = "${aws_instance.create.bar}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-multi-var-comprehensive/child/child.tf b/v1.5.7/internal/terraform/testdata/apply-multi-var-comprehensive/child/child.tf
new file mode 100644
index 0000000..8fe7df7
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-multi-var-comprehensive/child/child.tf
@@ -0,0 +1,29 @@
+variable "num" {
+}
+
+variable "source_ids" {
+  type = list(string)
+}
+
+variable "source_names" {
+  type = list(string)
+}
+
+resource "test_thing" "multi_count_var" {
+  count = var.num
+
+  key = "child.multi_count_var.${count.index}"
+
+  # Can pluck a single item out of a multi-var
+  source_id = var.source_ids[count.index]
+}
+
+resource "test_thing" "whole_splat" {
+  key = "child.whole_splat"
+
+  # Can "splat" the ids directly into an attribute of type list.
+  source_ids           = var.source_ids
+  source_names         = var.source_names
+  source_ids_wrapped   = ["${var.source_ids}"]
+  source_names_wrapped = ["${var.source_names}"]
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-multi-var-comprehensive/root.tf b/v1.5.7/internal/terraform/testdata/apply-multi-var-comprehensive/root.tf
new file mode 100644
index 0000000..64ada6b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-multi-var-comprehensive/root.tf
@@ -0,0 +1,74 @@
+variable "num" {
+}
+
+resource "test_thing" "source" {
+  count = var.num
+
+  key = "source.${count.index}"
+
+  # The diffFunc in the test exports "name" here too, which we can use
+  # to test values that are known during plan.
+}
+
+resource "test_thing" "multi_count_var" {
+  count = var.num
+
+  key = "multi_count_var.${count.index}"
+
+  # Can pluck a single item out of a multi-var
+  source_id   = test_thing.source.*.id[count.index]
+  source_name = test_thing.source.*.name[count.index]
+}
+
+resource "test_thing" "multi_count_derived" {
+  # Can use the source to get the count
+  count = length(test_thing.source)
+
+  key = "multi_count_derived.${count.index}"
+
+  source_id   = test_thing.source.*.id[count.index]
+  source_name = test_thing.source.*.name[count.index]
+}
+
+resource "test_thing" "whole_splat" {
+  key = "whole_splat"
+
+  # Can "splat" the ids directly into an attribute of type list.
+  source_ids   = test_thing.source.*.id
+  source_names = test_thing.source.*.name
+
+  # Accessing through a function should work.
+  source_ids_from_func   = split(" ", join(" ", test_thing.source.*.id))
+  source_names_from_func = split(" ", join(" ", test_thing.source.*.name))
+
+  # A common pattern of selecting with a default.
+  first_source_id   = element(concat(test_thing.source.*.id, ["default"]), 0)
+  first_source_name = element(concat(test_thing.source.*.name, ["default"]), 0)
+
+  # Prior to v0.12 we were handling lists containing list interpolations as
+  # a special case, flattening the result, for compatibility with behavior
+  # prior to v0.10. This deprecated handling is now removed, and so these
+  # each produce a list of lists. We're still using the interpolation syntax
+  # here, rather than the splat expression directly, to properly mimic how
+  # this would've looked prior to v0.12 to be explicit about what the new
+  # behavior is for this old syntax.
+  source_ids_wrapped   = ["${test_thing.source.*.id}"]
+  source_names_wrapped = ["${test_thing.source.*.name}"]
+
+}
+
+module "child" {
+  source = "./child"
+
+  num          = var.num
+  source_ids   = test_thing.source.*.id
+  source_names = test_thing.source.*.name
+}
+
+output "source_ids" {
+  value = test_thing.source.*.id
+}
+
+output "source_names" {
+  value = test_thing.source.*.name
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-multi-var-count-dec/main.tf b/v1.5.7/internal/terraform/testdata/apply-multi-var-count-dec/main.tf
new file mode 100644
index 0000000..4047651
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-multi-var-count-dec/main.tf
@@ -0,0 +1,12 @@
+variable "num" {}
+
+resource "aws_instance" "foo" {
+  count = "${var.num}"
+  value = "foo"
+}
+
+resource "aws_instance" "bar" {
+  ami = "special"
+
+  value = "${join(",", aws_instance.foo.*.id)}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-multi-var-missing-state/child/child.tf b/v1.5.7/internal/terraform/testdata/apply-multi-var-missing-state/child/child.tf
new file mode 100644
index 0000000..b5df05d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-multi-var-missing-state/child/child.tf
@@ -0,0 +1,15 @@
+
+# This resource gets visited first on the apply walk, but since it DynamicExpands
+# to an empty subgraph it ends up being a no-op, leaving the module state
+# uninitialized.
+resource "test_thing" "a" {
+  count = 0
+}
+
+# This resource is visited second. During its eval walk we try to build the
+# array for the null_resource.a.*.id interpolation, which involves iterating
+# over all of the resource in the state. This should succeed even though the
+# module state will be nil when evaluating the variable.
+resource "test_thing" "b" {
+  a_ids = "${join(" ", test_thing.a.*.id)}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-multi-var-missing-state/root.tf b/v1.5.7/internal/terraform/testdata/apply-multi-var-missing-state/root.tf
new file mode 100644
index 0000000..25a0a1f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-multi-var-missing-state/root.tf
@@ -0,0 +1,7 @@
+// We test this in a child module, since the root module state exists
+// very early on, even before any resources are created in it, but that is not
+// true for child modules.
+
+module "child" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-multi-var-order-interp/main.tf b/v1.5.7/internal/terraform/testdata/apply-multi-var-order-interp/main.tf
new file mode 100644
index 0000000..6cc2e29
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-multi-var-order-interp/main.tf
@@ -0,0 +1,17 @@
+variable "num" {
+  default = 15
+}
+
+resource "aws_instance" "bar" {
+  count = "${var.num}"
+  foo   = "index-${count.index}"
+}
+
+resource "aws_instance" "baz" {
+  count = "${var.num}"
+  foo   = "baz-${element(aws_instance.bar.*.foo, count.index)}"
+}
+
+output "should-be-11" {
+  value = "${element(aws_instance.baz.*.foo, 11)}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-multi-var-order/main.tf b/v1.5.7/internal/terraform/testdata/apply-multi-var-order/main.tf
new file mode 100644
index 0000000..7ffefb6
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-multi-var-order/main.tf
@@ -0,0 +1,12 @@
+variable "num" {
+  default = 15
+}
+
+resource "aws_instance" "bar" {
+  count = "${var.num}"
+  foo   = "index-${count.index}"
+}
+
+output "should-be-11" {
+  value = "${element(aws_instance.bar.*.foo, 11)}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-multi-var/main.tf b/v1.5.7/internal/terraform/testdata/apply-multi-var/main.tf
new file mode 100644
index 0000000..c7ed45c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-multi-var/main.tf
@@ -0,0 +1,10 @@
+variable "num" {}
+
+resource "aws_instance" "bar" {
+    count = "${var.num}"
+    foo = "bar${count.index}"
+}
+
+output "output" {
+    value = "${join(",", aws_instance.bar.*.foo)}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-nullable-variables/main.tf b/v1.5.7/internal/terraform/testdata/apply-nullable-variables/main.tf
new file mode 100644
index 0000000..ed4b6c7
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-nullable-variables/main.tf
@@ -0,0 +1,28 @@
+module "mod" {
+  source = "./mod"
+  nullable_null_default = null
+  nullable_non_null_default = null
+  nullable_no_default = null
+  non_nullable_default = null
+  non_nullable_no_default = "ok"
+}
+
+output "nullable_null_default" {
+  value = module.mod.nullable_null_default
+}
+
+output "nullable_non_null_default" {
+  value = module.mod.nullable_non_null_default
+}
+
+output "nullable_no_default" {
+  value = module.mod.nullable_no_default
+}
+
+output "non_nullable_default" {
+  value = module.mod.non_nullable_default
+}
+
+output "non_nullable_no_default" {
+  value = module.mod.non_nullable_no_default
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-nullable-variables/mod/main.tf b/v1.5.7/internal/terraform/testdata/apply-nullable-variables/mod/main.tf
new file mode 100644
index 0000000..fcac3ba
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-nullable-variables/mod/main.tf
@@ -0,0 +1,59 @@
+// optional, and this can take null as an input
+variable "nullable_null_default" {
+  // This is implied now as the default, and probably should be implied even
+  // when nullable=false is the default, so we're leaving this unset for the test.
+  // nullable = true
+
+  default = null
+}
+
+// assigning null can still override the default.
+variable "nullable_non_null_default" {
+  nullable = true
+  default = "ok"
+}
+
+// required, and assigning null is valid.
+variable "nullable_no_default" {
+  nullable = true
+}
+
+
+// this combination is invalid
+//variable "non_nullable_null_default" {
+//  nullable = false
+//  default = null
+//}
+
+
+// assigning null will take the default
+variable "non_nullable_default" {
+  nullable = false
+  default = "ok"
+}
+
+// required, but null is not a valid value
+variable "non_nullable_no_default" {
+  nullable = false
+}
+
+output "nullable_null_default" {
+  value = var.nullable_null_default
+}
+
+output "nullable_non_null_default" {
+  value = var.nullable_non_null_default
+}
+
+output "nullable_no_default" {
+  value = var.nullable_no_default
+}
+
+output "non_nullable_default" {
+  value = var.non_nullable_default
+}
+
+output "non_nullable_no_default" {
+  value = var.non_nullable_no_default
+}
+
diff --git a/v1.5.7/internal/terraform/testdata/apply-orphan-resource/main.tf b/v1.5.7/internal/terraform/testdata/apply-orphan-resource/main.tf
new file mode 100644
index 0000000..3e093ac
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-orphan-resource/main.tf
@@ -0,0 +1,7 @@
+resource "test_thing" "zero" {
+  count = 0
+}
+
+resource "test_thing" "one" {
+  count = 1
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-output-add-after/main.tf b/v1.5.7/internal/terraform/testdata/apply-output-add-after/main.tf
new file mode 100644
index 0000000..1c10eaa
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-output-add-after/main.tf
@@ -0,0 +1,6 @@
+provider "aws" {}
+
+resource "aws_instance" "test" {
+		foo = "${format("foo%d", count.index)}"
+		count = 2
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-output-add-after/outputs.tf.json b/v1.5.7/internal/terraform/testdata/apply-output-add-after/outputs.tf.json
new file mode 100644
index 0000000..32e96b0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-output-add-after/outputs.tf.json
@@ -0,0 +1,10 @@
+{
+		"output": {
+				"firstOutput": {
+						"value": "${aws_instance.test.0.foo}"
+				},
+				"secondOutput": {
+						"value": "${aws_instance.test.1.foo}"
+				}
+		}
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-output-add-before/main.tf b/v1.5.7/internal/terraform/testdata/apply-output-add-before/main.tf
new file mode 100644
index 0000000..1c10eaa
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-output-add-before/main.tf
@@ -0,0 +1,6 @@
+provider "aws" {}
+
+resource "aws_instance" "test" {
+		foo = "${format("foo%d", count.index)}"
+		count = 2
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-output-add-before/outputs.tf.json b/v1.5.7/internal/terraform/testdata/apply-output-add-before/outputs.tf.json
new file mode 100644
index 0000000..238668e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-output-add-before/outputs.tf.json
@@ -0,0 +1,7 @@
+{
+		"output": {
+				"firstOutput": {
+						"value": "${aws_instance.test.0.foo}"
+				}
+		}
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-output-list/main.tf b/v1.5.7/internal/terraform/testdata/apply-output-list/main.tf
new file mode 100644
index 0000000..11b8107
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-output-list/main.tf
@@ -0,0 +1,12 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "bar"
+    count = 3
+}
+
+output "foo_num" {
+    value = ["${join(",", aws_instance.bar.*.foo)}"]
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-output-multi-index/main.tf b/v1.5.7/internal/terraform/testdata/apply-output-multi-index/main.tf
new file mode 100644
index 0000000..c7ede94
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-output-multi-index/main.tf
@@ -0,0 +1,12 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "bar"
+    count = 3
+}
+
+output "foo_num" {
+    value = "${aws_instance.bar.0.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-output-multi/main.tf b/v1.5.7/internal/terraform/testdata/apply-output-multi/main.tf
new file mode 100644
index 0000000..a70e334
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-output-multi/main.tf
@@ -0,0 +1,12 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "bar"
+    count = 3
+}
+
+output "foo_num" {
+    value = "${join(",", aws_instance.bar.*.foo)}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-output-orphan-module/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-output-orphan-module/child/main.tf
new file mode 100644
index 0000000..ae32f8a
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-output-orphan-module/child/main.tf
@@ -0,0 +1,3 @@
+output "foo" {
+  value = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-output-orphan-module/main.tf b/v1.5.7/internal/terraform/testdata/apply-output-orphan-module/main.tf
new file mode 100644
index 0000000..0f6991c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-output-orphan-module/main.tf
@@ -0,0 +1,3 @@
+module "child" {
+    source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-output-orphan/main.tf b/v1.5.7/internal/terraform/testdata/apply-output-orphan/main.tf
new file mode 100644
index 0000000..ae32f8a
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-output-orphan/main.tf
@@ -0,0 +1,3 @@
+output "foo" {
+  value = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-output/main.tf b/v1.5.7/internal/terraform/testdata/apply-output/main.tf
new file mode 100644
index 0000000..1f91a40
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-output/main.tf
@@ -0,0 +1,11 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "bar"
+}
+
+output "foo_num" {
+    value = "${aws_instance.foo.num}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-plan-connection-refs/main.tf b/v1.5.7/internal/terraform/testdata/apply-plan-connection-refs/main.tf
new file mode 100644
index 0000000..d20191f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-plan-connection-refs/main.tf
@@ -0,0 +1,18 @@
+variable "msg" {
+  default = "ok"
+}
+
+resource "test_instance" "a" {
+  foo = "a"
+}
+
+
+resource "test_instance" "b" {
+  foo = "b"
+  provisioner "shell" {
+   command = "echo ${var.msg}"
+  }
+  connection {
+   host = test_instance.a.id
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provider-alias-configure/main.tf b/v1.5.7/internal/terraform/testdata/apply-provider-alias-configure/main.tf
new file mode 100644
index 0000000..4487e45
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provider-alias-configure/main.tf
@@ -0,0 +1,14 @@
+provider "another" {
+  foo = "bar"
+}
+
+provider "another" {
+  alias = "two"
+  foo   = "bar"
+}
+
+resource "another_instance" "foo" {}
+
+resource "another_instance" "bar" {
+  provider = "another.two"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provider-alias/main.tf b/v1.5.7/internal/terraform/testdata/apply-provider-alias/main.tf
new file mode 100644
index 0000000..19fd985
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provider-alias/main.tf
@@ -0,0 +1,12 @@
+provider "aws" {
+	alias = "bar"
+}
+
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "bar"
+    provider = "aws.bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provider-computed/main.tf b/v1.5.7/internal/terraform/testdata/apply-provider-computed/main.tf
new file mode 100644
index 0000000..81acf7c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provider-computed/main.tf
@@ -0,0 +1,9 @@
+provider "aws" {
+    value = test_instance.foo.id
+}
+
+resource "aws_instance" "bar" {}
+
+resource "test_instance" "foo" {
+    value = "yes"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provider-configure-disabled/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-provider-configure-disabled/child/main.tf
new file mode 100644
index 0000000..c421bf7
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provider-configure-disabled/child/main.tf
@@ -0,0 +1,5 @@
+provider "aws" {
+    value = "foo"
+}
+
+resource "aws_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provider-configure-disabled/main.tf b/v1.5.7/internal/terraform/testdata/apply-provider-configure-disabled/main.tf
new file mode 100644
index 0000000..dbfc527
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provider-configure-disabled/main.tf
@@ -0,0 +1,7 @@
+provider "aws" {
+    foo = "bar"
+}
+
+module "child" {
+    source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provider-warning/main.tf b/v1.5.7/internal/terraform/testdata/apply-provider-warning/main.tf
new file mode 100644
index 0000000..919f140
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provider-warning/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-compute/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-compute/main.tf
new file mode 100644
index 0000000..5982965
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-compute/main.tf
@@ -0,0 +1,13 @@
+variable "value" {}
+
+resource "aws_instance" "foo" {
+    num = "2"
+    compute = "value"
+    compute_value = "${var.value}"
+}
+
+resource "aws_instance" "bar" {
+    provisioner "shell" {
+        command = "${aws_instance.foo.value}"
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-destroy-continue/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-destroy-continue/main.tf
new file mode 100644
index 0000000..0be0d33
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-destroy-continue/main.tf
@@ -0,0 +1,15 @@
+resource "aws_instance" "foo" {
+    foo = "bar"
+
+    provisioner "shell" {
+        command  = "one"
+        when = "destroy"
+        on_failure = "continue"
+    }
+
+    provisioner "shell" {
+        command  = "two"
+        when = "destroy"
+        on_failure = "continue"
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-destroy-fail/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-destroy-fail/main.tf
new file mode 100644
index 0000000..14ad125
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-destroy-fail/main.tf
@@ -0,0 +1,14 @@
+resource "aws_instance" "foo" {
+  foo = "bar"
+
+  provisioner "shell" {
+    command    = "one"
+    when       = "destroy"
+    on_failure = "continue"
+  }
+
+  provisioner "shell" {
+    command = "two"
+    when    = "destroy"
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-destroy/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-destroy/main.tf
new file mode 100644
index 0000000..8804f64
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-destroy/main.tf
@@ -0,0 +1,18 @@
+resource "aws_instance" "foo" {
+    for_each = var.input
+    foo = "bar"
+
+    provisioner "shell" {
+        command = "create ${each.key} ${each.value}"
+    }
+
+    provisioner "shell" {
+        when = "destroy"
+        command  = "destroy ${each.key} ${self.foo}"
+    }
+}
+
+variable "input" {
+  type = map(string)
+  default = {}
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-diff/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-diff/main.tf
new file mode 100644
index 0000000..ac4f38e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-diff/main.tf
@@ -0,0 +1,4 @@
+resource "aws_instance" "bar" {
+    foo = "bar"
+    provisioner "shell" {}
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-explicit-self-ref/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-explicit-self-ref/main.tf
new file mode 100644
index 0000000..7ceca47
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-explicit-self-ref/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    foo = "bar"
+
+    provisioner "shell" {
+        command = "${aws_instance.foo.foo}"
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-fail-continue/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-fail-continue/main.tf
new file mode 100644
index 0000000..3958798
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-fail-continue/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    foo = "bar"
+
+    provisioner "shell" {
+        on_failure = "continue"
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-fail-create-before/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-fail-create-before/main.tf
new file mode 100644
index 0000000..00d32cb
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-fail-create-before/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "bar" {
+    require_new = "xyz"
+    provisioner "shell" {}
+    lifecycle {
+        create_before_destroy = true
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-fail-create/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-fail-create/main.tf
new file mode 100644
index 0000000..c1dcd22
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-fail-create/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "bar" {
+    provisioner "shell" {}
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-fail/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-fail/main.tf
new file mode 100644
index 0000000..4aacf4b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-fail/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    provisioner "shell" {}
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-for-each-self/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-for-each-self/main.tf
new file mode 100644
index 0000000..f3e1d58
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-for-each-self/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+    for_each = toset(["a", "b", "c"])
+    foo = "number ${each.value}"
+
+    provisioner "shell" {
+        command = "${self.foo}"
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-interp-count/provisioner-interp-count.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-interp-count/provisioner-interp-count.tf
new file mode 100644
index 0000000..337129e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-interp-count/provisioner-interp-count.tf
@@ -0,0 +1,17 @@
+variable "num" {
+  default = 3
+}
+
+resource "aws_instance" "a" {
+  count = var.num
+}
+
+resource "aws_instance" "b" {
+  provisioner "local-exec" {
+    # Since we're in a provisioner block here, this expression is
+    # resolved during the apply walk and so the resource count must
+    # be known during that walk, even though apply walk doesn't
+    # do DynamicExpand.
+    command = "echo ${length(aws_instance.a)}"
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-module/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-module/child/main.tf
new file mode 100644
index 0000000..85b58ff
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-module/child/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "bar" {
+    provisioner "shell" {
+        foo = "bar"
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-module/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-module/main.tf
new file mode 100644
index 0000000..1f95749
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-module/main.tf
@@ -0,0 +1,3 @@
+module "child" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-multi-self-ref-single/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-multi-self-ref-single/main.tf
new file mode 100644
index 0000000..d6c9951
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-multi-self-ref-single/main.tf
@@ -0,0 +1,9 @@
+resource "aws_instance" "foo" {
+  count = 3
+  foo   = "number ${count.index}"
+
+  provisioner "shell" {
+    command = aws_instance.foo[0].foo
+    order   = count.index
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-multi-self-ref/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-multi-self-ref/main.tf
new file mode 100644
index 0000000..72a1e79
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-multi-self-ref/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+    count = 3
+    foo = "number ${count.index}"
+
+    provisioner "shell" {
+        command = "${self.foo}"
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-resource-ref/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-resource-ref/main.tf
new file mode 100644
index 0000000..25da377
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-resource-ref/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "bar" {
+    num = "2"
+
+    provisioner "shell" {
+        command = "${aws_instance.bar.num}"
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-self-ref/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-self-ref/main.tf
new file mode 100644
index 0000000..5f401f7
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-self-ref/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    foo = "bar"
+
+    provisioner "shell" {
+        command = "${self.foo}"
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-provisioner-sensitive/main.tf b/v1.5.7/internal/terraform/testdata/apply-provisioner-sensitive/main.tf
new file mode 100644
index 0000000..99ec4a2
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-provisioner-sensitive/main.tf
@@ -0,0 +1,18 @@
+variable "password" {
+  type      = string
+  sensitive = true
+}
+
+resource "aws_instance" "foo" {
+  connection {
+    host     = "localhost"
+    type     = "telnet"
+    user     = "superuser"
+    port     = 2222
+    password = var.password
+  }
+
+  provisioner "shell" {
+    command = "echo ${var.password} > secrets"
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-ref-count/main.tf b/v1.5.7/internal/terraform/testdata/apply-ref-count/main.tf
new file mode 100644
index 0000000..1ce2ffe
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-ref-count/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+  count = 3
+}
+
+resource "aws_instance" "bar" {
+  foo = length(aws_instance.foo)
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-ref-existing/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-ref-existing/child/main.tf
new file mode 100644
index 0000000..cd1e56e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-ref-existing/child/main.tf
@@ -0,0 +1,5 @@
+variable "var" {}
+
+resource "aws_instance" "foo" {
+    value = "${var.var}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-ref-existing/main.tf b/v1.5.7/internal/terraform/testdata/apply-ref-existing/main.tf
new file mode 100644
index 0000000..a05056c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-ref-existing/main.tf
@@ -0,0 +1,9 @@
+resource "aws_instance" "foo" {
+  foo = "bar"
+}
+
+module "child" {
+  source = "./child"
+
+  var = "${aws_instance.foo.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-resource-count-one-list/main.tf b/v1.5.7/internal/terraform/testdata/apply-resource-count-one-list/main.tf
new file mode 100644
index 0000000..0aeb75b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-resource-count-one-list/main.tf
@@ -0,0 +1,7 @@
+resource "null_resource" "foo" {
+  count = 1
+}
+
+output "test" {
+  value = "${sort(null_resource.foo.*.id)}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-resource-count-zero-list/main.tf b/v1.5.7/internal/terraform/testdata/apply-resource-count-zero-list/main.tf
new file mode 100644
index 0000000..6d9b4d5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-resource-count-zero-list/main.tf
@@ -0,0 +1,7 @@
+resource "null_resource" "foo" {
+  count = 0
+}
+
+output "test" {
+  value = "${sort(null_resource.foo.*.id)}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-deep/child/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-deep/child/child/main.tf
new file mode 100644
index 0000000..7720326
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-deep/child/child/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "c" {
+  ami = "grandchild"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-deep/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-deep/child/main.tf
new file mode 100644
index 0000000..6cbe350
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-deep/child/main.tf
@@ -0,0 +1,3 @@
+module "grandchild" {
+    source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-deep/main.tf b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-deep/main.tf
new file mode 100644
index 0000000..1a7862b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-deep/main.tf
@@ -0,0 +1,9 @@
+module "child" {
+  source = "./child"
+}
+
+resource "aws_instance" "a" {
+  ami = "parent"
+
+  depends_on = ["module.child"]
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-empty/main.tf b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-empty/main.tf
new file mode 100644
index 0000000..f2316bd
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-empty/main.tf
@@ -0,0 +1 @@
+# Empty!
diff --git a/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-in-module/child/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-in-module/child/child/main.tf
new file mode 100644
index 0000000..7720326
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-in-module/child/child/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "c" {
+  ami = "grandchild"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-in-module/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-in-module/child/main.tf
new file mode 100644
index 0000000..a816cae
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-in-module/child/main.tf
@@ -0,0 +1,8 @@
+module "grandchild" {
+  source = "./child"
+}
+
+resource "aws_instance" "b" {
+  ami        = "child"
+  depends_on = ["module.grandchild"]
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-in-module/main.tf b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-in-module/main.tf
new file mode 100644
index 0000000..0f6991c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module-in-module/main.tf
@@ -0,0 +1,3 @@
+module "child" {
+    source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module/child/main.tf
new file mode 100644
index 0000000..949d8e1
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module/child/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "child" {
+  ami = "child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module/main.tf b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module/main.tf
new file mode 100644
index 0000000..1a7862b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-resource-depends-on-module/main.tf
@@ -0,0 +1,9 @@
+module "child" {
+  source = "./child"
+}
+
+resource "aws_instance" "a" {
+  ami = "parent"
+
+  depends_on = ["module.child"]
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-resource-scale-in/main.tf b/v1.5.7/internal/terraform/testdata/apply-resource-scale-in/main.tf
new file mode 100644
index 0000000..8cb3847
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-resource-scale-in/main.tf
@@ -0,0 +1,13 @@
+variable "instance_count" {}
+
+resource "aws_instance" "one" {
+  count = var.instance_count
+}
+
+locals {
+  one_id = element(concat(aws_instance.one.*.id, [""]), 0)
+}
+
+resource "aws_instance" "two" {
+  value = local.one_id
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-stop/apply-stop.tf b/v1.5.7/internal/terraform/testdata/apply-stop/apply-stop.tf
new file mode 100644
index 0000000..003ca67
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-stop/apply-stop.tf
@@ -0,0 +1,23 @@
+terraform {
+  required_providers {
+    indefinite = {
+      source = "terraform.io/test/indefinite"
+    }
+  }
+}
+
+# The TestContext2Apply_stop test arranges for "indefinite"'s
+# ApplyResourceChange to just block indefinitely until the operation
+# is cancelled using Context.Stop.
+resource "indefinite" "foo" {
+}
+
+resource "indefinite" "bar" {
+  # Should never get here during apply because we're going to interrupt the
+  # run during indefinite.foo's ApplyResourceChange.
+  depends_on = [indefinite.foo]
+}
+
+output "result" {
+  value = indefinite.foo.result
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-taint-dep-requires-new/main.tf b/v1.5.7/internal/terraform/testdata/apply-taint-dep-requires-new/main.tf
new file mode 100644
index 0000000..f964fe4
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-taint-dep-requires-new/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${aws_instance.foo.id}"
+    require_new = "yes"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-taint-dep/main.tf b/v1.5.7/internal/terraform/testdata/apply-taint-dep/main.tf
new file mode 100644
index 0000000..164db2d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-taint-dep/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    num = "2"
+    foo = "${aws_instance.foo.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-taint/main.tf b/v1.5.7/internal/terraform/testdata/apply-taint/main.tf
new file mode 100644
index 0000000..801ddba
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-taint/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "bar" {
+    num = "2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-tainted-targets/main.tf b/v1.5.7/internal/terraform/testdata/apply-tainted-targets/main.tf
new file mode 100644
index 0000000..8f6b317
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-tainted-targets/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "ifailedprovisioners" { }
+
+resource "aws_instance" "iambeingadded" { }
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted-count/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted-count/main.tf
new file mode 100644
index 0000000..cd86189
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted-count/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+  count = 3
+}
+
+resource "aws_instance" "bar" {
+  count = 3
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted-module-dep/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted-module-dep/child/main.tf
new file mode 100644
index 0000000..90a7c40
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted-module-dep/child/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "mod" { }
+
+output "output" {
+  value = "${aws_instance.mod.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted-module-dep/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted-module-dep/main.tf
new file mode 100644
index 0000000..754219c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted-module-dep/main.tf
@@ -0,0 +1,7 @@
+module "child" {
+    source = "./child"
+}
+
+resource "aws_instance" "foo" {
+    foo = "${module.child.output}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted-module-recursive/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted-module-recursive/child/main.tf
new file mode 100644
index 0000000..852bce8
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted-module-recursive/child/main.tf
@@ -0,0 +1,3 @@
+module "subchild" {
+    source = "./subchild"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted-module-recursive/child/subchild/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted-module-recursive/child/subchild/main.tf
new file mode 100644
index 0000000..98f5ee8
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted-module-recursive/child/subchild/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted-module-recursive/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted-module-recursive/main.tf
new file mode 100644
index 0000000..0f6991c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted-module-recursive/main.tf
@@ -0,0 +1,3 @@
+module "child" {
+    source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted-module-resource/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted-module-resource/child/main.tf
new file mode 100644
index 0000000..7872c90
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted-module-resource/child/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    num = "2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted-module-resource/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted-module-resource/main.tf
new file mode 100644
index 0000000..88bf07f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted-module-resource/main.tf
@@ -0,0 +1,7 @@
+module "child" {
+    source = "./child"
+}
+
+resource "aws_instance" "bar" {
+    foo = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/child1/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/child1/main.tf
new file mode 100644
index 0000000..cffe382
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/child1/main.tf
@@ -0,0 +1,17 @@
+variable "instance_id" {
+}
+
+output "instance_id" {
+  # The instance here isn't targeted, so this output shouldn't get updated.
+  # But it already has an existing value in state (specified within the
+  # test code) so we expect this to remain unchanged afterwards.
+  value = "${aws_instance.foo.id}"
+}
+
+output "given_instance_id" {
+  value = "${var.instance_id}"
+}
+
+resource "aws_instance" "foo" {
+  foo = "${var.instance_id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/child2/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/child2/main.tf
new file mode 100644
index 0000000..d8aa6cf
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/child2/main.tf
@@ -0,0 +1,9 @@
+resource "aws_instance" "foo" {
+}
+
+output "instance_id" {
+  # Even though we're targeting just the resource above, this should still
+  # be populated because outputs are implicitly targeted when their
+  # dependencies are
+  value = "${aws_instance.foo.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/main.tf
new file mode 100644
index 0000000..1170072
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/main.tf
@@ -0,0 +1,37 @@
+resource "aws_instance" "foo" {}
+
+module "child1" {
+  source = "./child1"
+  instance_id = "${aws_instance.foo.id}"
+}
+
+module "child2" {
+  source = "./child2"
+}
+
+output "child1_id" {
+  value = "${module.child1.instance_id}"
+}
+
+output "child1_given_id" {
+  value = "${module.child1.given_instance_id}"
+}
+
+output "child2_id" {
+  # This should get updated even though we're targeting specifically
+  # module.child2, because outputs are implicitly targeted when their
+  # dependencies are.
+  value = "${module.child2.instance_id}"
+}
+
+output "all_ids" {
+  # Here we are intentionally referencing values covering three different scenarios:
+  # - not targeted and not already in state
+  # - not targeted and already in state
+  # - targeted
+  # This is important because this output must appear in the graph after
+  # target filtering in case the targeted node changes its value, but we must
+  # therefore silently ignore the failure that results from trying to
+  # interpolate the un-targeted, not-in-state node.
+  value = "${aws_instance.foo.id} ${module.child1.instance_id} ${module.child2.instance_id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted-module/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted-module/child/main.tf
new file mode 100644
index 0000000..7872c90
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted-module/child/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    num = "2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted-module/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted-module/main.tf
new file mode 100644
index 0000000..938ce3a
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted-module/main.tf
@@ -0,0 +1,11 @@
+module "child" {
+    source = "./child"
+}
+
+resource "aws_instance" "foo" {
+    foo = "bar"
+}
+
+resource "aws_instance" "bar" {
+    foo = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted-resource-orphan-module/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted-resource-orphan-module/child/main.tf
new file mode 100644
index 0000000..6ff716a
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted-resource-orphan-module/child/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "bar" {}
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted-resource-orphan-module/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted-resource-orphan-module/main.tf
new file mode 100644
index 0000000..0c15c4b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted-resource-orphan-module/main.tf
@@ -0,0 +1,5 @@
+//module "child" {
+//  source = "./child"
+//}
+
+resource "aws_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/apply-targeted/main.tf b/v1.5.7/internal/terraform/testdata/apply-targeted/main.tf
new file mode 100644
index 0000000..b07fc97
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-targeted/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-terraform-workspace/main.tf b/v1.5.7/internal/terraform/testdata/apply-terraform-workspace/main.tf
new file mode 100644
index 0000000..cc50f57
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-terraform-workspace/main.tf
@@ -0,0 +1,3 @@
+output "output" {
+    value = "${terraform.workspace}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-unknown-interpolate/child/main.tf b/v1.5.7/internal/terraform/testdata/apply-unknown-interpolate/child/main.tf
new file mode 100644
index 0000000..1caedab
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-unknown-interpolate/child/main.tf
@@ -0,0 +1,5 @@
+variable "value" {}
+
+resource "aws_instance" "bar" {
+    foo = "${var.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-unknown-interpolate/main.tf b/v1.5.7/internal/terraform/testdata/apply-unknown-interpolate/main.tf
new file mode 100644
index 0000000..1ee7dd6
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-unknown-interpolate/main.tf
@@ -0,0 +1,6 @@
+resource "aws_instance" "foo" {}
+
+module "child" {
+    source = "./child"
+    value = "${aws_instance.foo.nope}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-unknown/main.tf b/v1.5.7/internal/terraform/testdata/apply-unknown/main.tf
new file mode 100644
index 0000000..98f5ee8
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-unknown/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-unstable/main.tf b/v1.5.7/internal/terraform/testdata/apply-unstable/main.tf
new file mode 100644
index 0000000..32754bb
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-unstable/main.tf
@@ -0,0 +1,3 @@
+resource "test_resource" "foo" {
+  random = "${uuid()}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-vars-env/main.tf b/v1.5.7/internal/terraform/testdata/apply-vars-env/main.tf
new file mode 100644
index 0000000..1b62ad6
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-vars-env/main.tf
@@ -0,0 +1,20 @@
+variable "string" {
+  default = "foo"
+  type    = string
+}
+
+variable "list" {
+  default = []
+  type    = list(string)
+}
+
+variable "map" {
+  default = {}
+  type    = map(string)
+}
+
+resource "aws_instance" "bar" {
+  string  = var.string
+  list    = var.list
+  map     = var.map
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-vars/main.tf b/v1.5.7/internal/terraform/testdata/apply-vars/main.tf
new file mode 100644
index 0000000..dc413c0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-vars/main.tf
@@ -0,0 +1,33 @@
+variable "amis" {
+    default = {
+        us-east-1 = "foo"
+        us-west-2 = "foo"
+    }
+}
+
+variable "test_list" {
+    type = list(string)
+}
+
+variable "test_map" {
+    type = map(string)
+}
+
+variable "bar" {
+    default = "baz"
+}
+
+variable "foo" {}
+
+resource "aws_instance" "foo" {
+    num  = "2"
+    bar  = var.bar
+    list = var.test_list
+    map  = var.test_map
+}
+
+resource "aws_instance" "bar" {
+    foo = var.foo
+    bar = var.amis[var.foo]
+    baz = var.amis["us-east-1"]
+}
diff --git a/v1.5.7/internal/terraform/testdata/apply-with-checks/main.tf b/v1.5.7/internal/terraform/testdata/apply-with-checks/main.tf
new file mode 100644
index 0000000..0064a4b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/apply-with-checks/main.tf
@@ -0,0 +1,20 @@
+
+resource "aws_instance" "foo" {
+  test_string = "Hello, world!"
+}
+
+resource "aws_instance" "baz" {
+  test_string = aws_instance.foo.test_string
+}
+
+check "my_check" {
+  data "aws_data_source" "bar" {
+    id = "UI098L"
+  }
+
+  assert {
+    condition = data.aws_data_source.bar.foo == "valid value"
+    error_message = "invalid value"
+  }
+
+}
diff --git a/v1.5.7/internal/terraform/testdata/context-required-version/main.tf b/v1.5.7/internal/terraform/testdata/context-required-version/main.tf
new file mode 100644
index 0000000..75db792
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/context-required-version/main.tf
@@ -0,0 +1 @@
+terraform {}
diff --git a/v1.5.7/internal/terraform/testdata/data-source-read-with-plan-error/main.tf b/v1.5.7/internal/terraform/testdata/data-source-read-with-plan-error/main.tf
new file mode 100644
index 0000000..2559406
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/data-source-read-with-plan-error/main.tf
@@ -0,0 +1,12 @@
+resource "aws_instance" "foo" {
+}
+
+// this will be postponed until apply
+data "aws_data_source" "foo" {
+  foo = aws_instance.foo.id
+}
+
+// this will cause an error in the final plan
+resource "test_instance" "bar" {
+  foo = "error"
+}
diff --git a/v1.5.7/internal/terraform/testdata/destroy-module-with-provider/main.tf b/v1.5.7/internal/terraform/testdata/destroy-module-with-provider/main.tf
new file mode 100644
index 0000000..3b183ec
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/destroy-module-with-provider/main.tf
@@ -0,0 +1,11 @@
+// this is the provider that should actually be used by orphaned resources
+provider "aws" {
+  alias = "bar"
+}
+
+module "mod" {
+  source = "./mod"
+  providers = {
+    aws.foo = "aws.bar"
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/destroy-module-with-provider/mod/main.tf b/v1.5.7/internal/terraform/testdata/destroy-module-with-provider/mod/main.tf
new file mode 100644
index 0000000..3e360ee
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/destroy-module-with-provider/mod/main.tf
@@ -0,0 +1,6 @@
+provider "aws" {
+  alias = "foo"
+}
+
+// removed module configuration referencing aws.foo, which was passed in by the
+// root module
diff --git a/v1.5.7/internal/terraform/testdata/destroy-targeted/child/main.tf b/v1.5.7/internal/terraform/testdata/destroy-targeted/child/main.tf
new file mode 100644
index 0000000..47ef076
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/destroy-targeted/child/main.tf
@@ -0,0 +1,10 @@
+variable "in" {
+}
+
+resource "aws_instance" "b" {
+  foo = var.in
+}
+
+output "out" {
+  value = var.in
+}
diff --git a/v1.5.7/internal/terraform/testdata/destroy-targeted/main.tf b/v1.5.7/internal/terraform/testdata/destroy-targeted/main.tf
new file mode 100644
index 0000000..70048b5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/destroy-targeted/main.tf
@@ -0,0 +1,12 @@
+resource "aws_instance" "a" {
+    foo = "bar"
+}
+
+module "child" {
+  source = "./child"
+  in = aws_instance.a.id
+}
+
+output "out" {
+  value = aws_instance.a.id
+}
diff --git a/v1.5.7/internal/terraform/testdata/empty/main.tf b/v1.5.7/internal/terraform/testdata/empty/main.tf
new file mode 100644
index 0000000..8974d9e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/empty/main.tf
@@ -0,0 +1 @@
+# Empty, use this for any test that requires a module but no config.
diff --git a/v1.5.7/internal/terraform/testdata/eval-context-basic/child/main.tf b/v1.5.7/internal/terraform/testdata/eval-context-basic/child/main.tf
new file mode 100644
index 0000000..e24069d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/eval-context-basic/child/main.tf
@@ -0,0 +1,7 @@
+variable "list" {
+}
+
+
+output "result" {
+  value = length(var.list)
+}
diff --git a/v1.5.7/internal/terraform/testdata/eval-context-basic/main.tf b/v1.5.7/internal/terraform/testdata/eval-context-basic/main.tf
new file mode 100644
index 0000000..2dc96ad
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/eval-context-basic/main.tf
@@ -0,0 +1,39 @@
+variable "number" {
+  default = 3
+}
+
+variable "string" {
+  default = "Hello, World"
+}
+
+variable "map" {
+  type = map(string)
+  default = {
+    "foo" = "bar",
+    "baz" = "bat",
+  }
+}
+
+locals {
+  result = length(var.list)
+}
+
+variable "list" {
+  type    = list(string)
+  default = ["red", "orange", "yellow", "green", "blue", "purple"]
+}
+
+resource "test_resource" "example" {
+  for_each = var.map
+  name     = each.key
+  tag      = each.value
+}
+
+module "child" {
+  source = "./child"
+  list   = var.list
+}
+
+output "result" {
+  value = module.child.result
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-basic/main.tf b/v1.5.7/internal/terraform/testdata/graph-basic/main.tf
new file mode 100644
index 0000000..a40802c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-basic/main.tf
@@ -0,0 +1,24 @@
+variable "foo" {
+    default = "bar"
+    description = "bar"
+}
+
+provider "aws" {
+    foo = "${openstack_floating_ip.random.value}"
+}
+
+resource "openstack_floating_ip" "random" {}
+
+resource "aws_security_group" "firewall" {}
+
+resource "aws_instance" "web" {
+    ami = "${var.foo}"
+    security_groups = [
+        "foo",
+        "${aws_security_group.firewall.foo}"
+    ]
+}
+
+resource "aws_load_balancer" "weblb" {
+    members = "${aws_instance.web.id_list}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-apply-basic/child/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-apply-basic/child/main.tf
new file mode 100644
index 0000000..79be97b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-apply-basic/child/main.tf
@@ -0,0 +1,7 @@
+resource "test_object" "create" {
+  provisioner "test" {}
+}
+
+resource "test_object" "other" {
+  test_string = "${test_object.create.test_string}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-apply-basic/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-apply-basic/main.tf
new file mode 100644
index 0000000..b42bd43
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-apply-basic/main.tf
@@ -0,0 +1,9 @@
+module "child" {
+  source = "./child"
+}
+
+resource "test_object" "create" {}
+
+resource "test_object" "other" {
+  test_string = "${test_object.create.test_string}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-apply-count/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-apply-count/main.tf
new file mode 100644
index 0000000..dee4eb4
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-apply-count/main.tf
@@ -0,0 +1,7 @@
+resource "test_object" "A" {
+  count = 1
+}
+
+resource "test_object" "B" {
+  test_list = test_object.A.*.test_string
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-apply-dep-cbd/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-apply-dep-cbd/main.tf
new file mode 100644
index 0000000..df6f290
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-apply-dep-cbd/main.tf
@@ -0,0 +1,9 @@
+resource "test_object" "A" {
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+
+resource "test_object" "B" {
+  test_list = test_object.A.*.test_string
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-apply-double-cbd/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-apply-double-cbd/main.tf
new file mode 100644
index 0000000..cb1f734
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-apply-double-cbd/main.tf
@@ -0,0 +1,13 @@
+resource "test_object" "A" {
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+
+resource "test_object" "B" {
+  test_list = test_object.A.*.test_string
+
+  lifecycle {
+    create_before_destroy = true
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-apply-module-destroy/A/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-apply-module-destroy/A/main.tf
new file mode 100644
index 0000000..2c427f5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-apply-module-destroy/A/main.tf
@@ -0,0 +1,9 @@
+variable "input" {}
+
+resource "test_object" "foo" {
+  test_string = var.input
+}
+
+output "output" {
+  value = test_object.foo.id
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-apply-module-destroy/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-apply-module-destroy/main.tf
new file mode 100644
index 0000000..3c56664
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-apply-module-destroy/main.tf
@@ -0,0 +1,13 @@
+variable "input" {
+  default = "value"
+}
+
+module "A" {
+  source = "./A"
+  input  = var.input
+}
+
+module "B" {
+  source = "./A"
+  input  = module.A.output
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-apply-orphan-update/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-apply-orphan-update/main.tf
new file mode 100644
index 0000000..22e7ae0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-apply-orphan-update/main.tf
@@ -0,0 +1,3 @@
+resource "test_object" "b" {
+  test_string = "changed"
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-apply-provisioner/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-apply-provisioner/main.tf
new file mode 100644
index 0000000..1ea5d21
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-apply-provisioner/main.tf
@@ -0,0 +1,3 @@
+resource "test_object" "foo" {
+  provisioner "test" {}
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-apply-target-module/child1/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-apply-target-module/child1/main.tf
new file mode 100644
index 0000000..7ac75f5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-apply-target-module/child1/main.tf
@@ -0,0 +1,11 @@
+variable "instance_id" {}
+
+output "instance_id" {
+  value = "${var.instance_id}"
+}
+
+resource "test_object" "foo" {
+  triggers = {
+    instance_id = "${var.instance_id}"
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-apply-target-module/child2/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-apply-target-module/child2/main.tf
new file mode 100644
index 0000000..0afe7ef
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-apply-target-module/child2/main.tf
@@ -0,0 +1 @@
+resource "test_object" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-apply-target-module/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-apply-target-module/main.tf
new file mode 100644
index 0000000..994d8fc
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-apply-target-module/main.tf
@@ -0,0 +1,10 @@
+resource "test_object" "foo" {}
+
+module "child1" {
+  source      = "./child1"
+  instance_id = "${test_object.foo.id}"
+}
+
+module "child2" {
+  source = "./child2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-orphan-alias/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-orphan-alias/main.tf
new file mode 100644
index 0000000..0398818
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-orphan-alias/main.tf
@@ -0,0 +1,3 @@
+provider "test" {
+  alias = "foo"
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-plan-attr-as-blocks/attr-as-blocks.tf b/v1.5.7/internal/terraform/testdata/graph-builder-plan-attr-as-blocks/attr-as-blocks.tf
new file mode 100644
index 0000000..d154cc2
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-plan-attr-as-blocks/attr-as-blocks.tf
@@ -0,0 +1,8 @@
+resource "test_thing" "a" {
+}
+
+resource "test_thing" "b" {
+  nested {
+    foo = test_thing.a.id
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-plan-basic/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-plan-basic/main.tf
new file mode 100644
index 0000000..df74468
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-plan-basic/main.tf
@@ -0,0 +1,33 @@
+variable "foo" {
+  default     = "bar"
+  description = "bar"
+}
+
+provider "aws" {
+  test_string = "${openstack_floating_ip.random.test_string}"
+}
+
+resource "openstack_floating_ip" "random" {}
+
+resource "aws_security_group" "firewall" {}
+
+resource "aws_instance" "web" {
+  test_string = var.foo
+
+  test_list = [
+    "foo",
+    aws_security_group.firewall.test_string,
+  ]
+}
+
+resource "aws_load_balancer" "weblb" {
+  test_list = aws_instance.web.test_list
+}
+
+locals {
+  instance_id = "${aws_instance.web.test_string}"
+}
+
+output "instance_id" {
+  value = "${local.instance_id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-plan-dynblock/dynblock.tf b/v1.5.7/internal/terraform/testdata/graph-builder-plan-dynblock/dynblock.tf
new file mode 100644
index 0000000..8946969
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-plan-dynblock/dynblock.tf
@@ -0,0 +1,14 @@
+resource "test_thing" "a" {
+}
+
+resource "test_thing" "b" {
+}
+
+resource "test_thing" "c" {
+  dynamic "nested" {
+    for_each = test_thing.a.list
+    content {
+      foo = test_thing.b.id
+    }
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-plan-target-module-provider/child1/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-plan-target-module-provider/child1/main.tf
new file mode 100644
index 0000000..f95800f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-plan-target-module-provider/child1/main.tf
@@ -0,0 +1,7 @@
+variable "key" {}
+
+provider "test" {
+  test_string = "${var.key}"
+}
+
+resource "test_object" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-plan-target-module-provider/child2/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-plan-target-module-provider/child2/main.tf
new file mode 100644
index 0000000..f95800f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-plan-target-module-provider/child2/main.tf
@@ -0,0 +1,7 @@
+variable "key" {}
+
+provider "test" {
+  test_string = "${var.key}"
+}
+
+resource "test_object" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/graph-builder-plan-target-module-provider/main.tf b/v1.5.7/internal/terraform/testdata/graph-builder-plan-target-module-provider/main.tf
new file mode 100644
index 0000000..d5a01db
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/graph-builder-plan-target-module-provider/main.tf
@@ -0,0 +1,9 @@
+module "child1" {
+  source = "./child1"
+  key    = "!"
+}
+
+module "child2" {
+  source = "./child2"
+  key    = "!"
+}
diff --git a/v1.5.7/internal/terraform/testdata/import-module/child/main.tf b/v1.5.7/internal/terraform/testdata/import-module/child/main.tf
new file mode 100644
index 0000000..8a8164b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/import-module/child/main.tf
@@ -0,0 +1,10 @@
+# Empty
+provider "aws" {}
+
+resource "aws_instance" "foo" {
+  id = "bar"
+}
+
+module "nested" {
+  source = "./submodule"
+}
diff --git a/v1.5.7/internal/terraform/testdata/import-module/child/submodule/main.tf b/v1.5.7/internal/terraform/testdata/import-module/child/submodule/main.tf
new file mode 100644
index 0000000..93c9015
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/import-module/child/submodule/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+  id = "baz"
+}
diff --git a/v1.5.7/internal/terraform/testdata/import-module/main.tf b/v1.5.7/internal/terraform/testdata/import-module/main.tf
new file mode 100644
index 0000000..c899a2c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/import-module/main.tf
@@ -0,0 +1,11 @@
+provider "aws" {
+  foo = "bar"
+}
+
+module "child" {
+  count = 1
+  source = "./child"
+  providers = {
+    aws = aws
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/import-provider-locals/main.tf b/v1.5.7/internal/terraform/testdata/import-provider-locals/main.tf
new file mode 100644
index 0000000..a83512c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/import-provider-locals/main.tf
@@ -0,0 +1,13 @@
+variable "foo" {}
+
+locals {
+  baz = "baz-${var.foo}"
+}
+
+provider "aws" {
+  foo = "${local.baz}"
+}
+
+resource "aws_instance" "foo" {
+  id = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/import-provider-resources/main.tf b/v1.5.7/internal/terraform/testdata/import-provider-resources/main.tf
new file mode 100644
index 0000000..a99ee5e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/import-provider-resources/main.tf
@@ -0,0 +1,11 @@
+provider "aws" {
+    value = "${test_instance.bar.id}"
+}
+
+resource "aws_instance" "foo" {
+    bar = "value"
+}
+
+resource "test_instance" "bar" {
+    value = "yes"
+}
diff --git a/v1.5.7/internal/terraform/testdata/import-provider-vars/main.tf b/v1.5.7/internal/terraform/testdata/import-provider-vars/main.tf
new file mode 100644
index 0000000..6a88bc9
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/import-provider-vars/main.tf
@@ -0,0 +1,9 @@
+variable "foo" {}
+
+provider "aws" {
+  foo = "${var.foo}"
+}
+
+resource "aws_instance" "foo" {
+  id = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/import-provider/main.tf b/v1.5.7/internal/terraform/testdata/import-provider/main.tf
new file mode 100644
index 0000000..5d41fb3
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/import-provider/main.tf
@@ -0,0 +1,6 @@
+provider "aws" {
+  foo = "bar"
+}
+
+resource "aws_instance" "foo" {
+}
diff --git a/v1.5.7/internal/terraform/testdata/input-interpolate-var/child/main.tf b/v1.5.7/internal/terraform/testdata/input-interpolate-var/child/main.tf
new file mode 100644
index 0000000..beb8c09
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-interpolate-var/child/main.tf
@@ -0,0 +1,6 @@
+variable "length" { }
+
+resource "template_file" "temp" {
+  count     = var.length
+  template  = "foo"
+}
diff --git a/v1.5.7/internal/terraform/testdata/input-interpolate-var/main.tf b/v1.5.7/internal/terraform/testdata/input-interpolate-var/main.tf
new file mode 100644
index 0000000..4e68495
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-interpolate-var/main.tf
@@ -0,0 +1,7 @@
+module "source" {
+  source = "./source"
+}
+module "child" {
+  source = "./child"
+  length = module.source.length
+}
diff --git a/v1.5.7/internal/terraform/testdata/input-interpolate-var/source/main.tf b/v1.5.7/internal/terraform/testdata/input-interpolate-var/source/main.tf
new file mode 100644
index 0000000..1405fe2
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-interpolate-var/source/main.tf
@@ -0,0 +1,3 @@
+output "length" {
+  value = 3
+}
diff --git a/v1.5.7/internal/terraform/testdata/input-module-data-vars/child/main.tf b/v1.5.7/internal/terraform/testdata/input-module-data-vars/child/main.tf
new file mode 100644
index 0000000..aa5d69b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-module-data-vars/child/main.tf
@@ -0,0 +1,5 @@
+variable "in" {}
+
+output "out" {
+	value = "${var.in}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/input-module-data-vars/main.tf b/v1.5.7/internal/terraform/testdata/input-module-data-vars/main.tf
new file mode 100644
index 0000000..0a327b1
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-module-data-vars/main.tf
@@ -0,0 +1,8 @@
+data "null_data_source" "bar" {
+  foo = ["a", "b"]
+}
+
+module "child" {
+  source = "./child"
+  in = "${data.null_data_source.bar.foo[1]}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/input-provider-multi/main.tf b/v1.5.7/internal/terraform/testdata/input-provider-multi/main.tf
new file mode 100644
index 0000000..db49fd3
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-provider-multi/main.tf
@@ -0,0 +1,9 @@
+provider "aws" {
+  alias = "east"
+}
+
+resource "aws_instance" "foo" {
+  provider = aws.east
+}
+
+resource "aws_instance" "bar" {}
diff --git a/v1.5.7/internal/terraform/testdata/input-provider-once/child/main.tf b/v1.5.7/internal/terraform/testdata/input-provider-once/child/main.tf
new file mode 100644
index 0000000..ca39ff5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-provider-once/child/main.tf
@@ -0,0 +1,2 @@
+provider "aws" {}
+resource "aws_instance" "bar" {}
diff --git a/v1.5.7/internal/terraform/testdata/input-provider-once/main.tf b/v1.5.7/internal/terraform/testdata/input-provider-once/main.tf
new file mode 100644
index 0000000..006a740
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-provider-once/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "foo" {}
+
+module "child" {
+    source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/input-provider-vars/main.tf b/v1.5.7/internal/terraform/testdata/input-provider-vars/main.tf
new file mode 100644
index 0000000..692bfb3
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-provider-vars/main.tf
@@ -0,0 +1,5 @@
+variable "foo" {}
+
+resource "aws_instance" "foo" {
+    foo = "${var.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/input-provider-with-vars-and-module/child/main.tf b/v1.5.7/internal/terraform/testdata/input-provider-with-vars-and-module/child/main.tf
new file mode 100644
index 0000000..7ec25bd
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-provider-with-vars-and-module/child/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "foo" { }
diff --git a/v1.5.7/internal/terraform/testdata/input-provider-with-vars-and-module/main.tf b/v1.5.7/internal/terraform/testdata/input-provider-with-vars-and-module/main.tf
new file mode 100644
index 0000000..c5112dc
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-provider-with-vars-and-module/main.tf
@@ -0,0 +1,7 @@
+provider "aws" {
+  access_key = "abc123"
+}
+
+module "child" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/input-provider-with-vars/main.tf b/v1.5.7/internal/terraform/testdata/input-provider-with-vars/main.tf
new file mode 100644
index 0000000..d8f9311
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-provider-with-vars/main.tf
@@ -0,0 +1,7 @@
+variable "foo" {}
+
+provider "aws" {
+    foo = "${var.foo}"
+}
+
+resource "aws_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/input-provider/main.tf b/v1.5.7/internal/terraform/testdata/input-provider/main.tf
new file mode 100644
index 0000000..919f140
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-provider/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/input-submodule-count/main.tf b/v1.5.7/internal/terraform/testdata/input-submodule-count/main.tf
new file mode 100644
index 0000000..723a15c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-submodule-count/main.tf
@@ -0,0 +1,4 @@
+module "mod" {
+  source         = "./mod"
+  instance_count = 2
+}
diff --git a/v1.5.7/internal/terraform/testdata/input-submodule-count/mod/main.tf b/v1.5.7/internal/terraform/testdata/input-submodule-count/mod/main.tf
new file mode 100644
index 0000000..dd7cf3d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-submodule-count/mod/main.tf
@@ -0,0 +1,11 @@
+variable "instance_count" {
+}
+
+resource "aws_instance" "foo" {
+  count = "${var.instance_count}"
+}
+
+module "submod" {
+  source = "./submod"
+  list   = ["${aws_instance.foo.*.id}"]
+}
diff --git a/v1.5.7/internal/terraform/testdata/input-submodule-count/mod/submod/main.tf b/v1.5.7/internal/terraform/testdata/input-submodule-count/mod/submod/main.tf
new file mode 100644
index 0000000..732ce43
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-submodule-count/mod/submod/main.tf
@@ -0,0 +1,7 @@
+variable "list" {
+  type = list(string)
+}
+
+resource "aws_instance" "bar" {
+  count = var.list[0]
+}
diff --git a/v1.5.7/internal/terraform/testdata/input-variables/main.tf b/v1.5.7/internal/terraform/testdata/input-variables/main.tf
new file mode 100644
index 0000000..9d6d49a
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/input-variables/main.tf
@@ -0,0 +1,30 @@
+# Required
+variable "foo" {
+}
+
+# Optional
+variable "bar" {
+  default = "baz"
+}
+
+# Mapping
+variable "map" {
+  default = {
+    foo = "bar"
+  }
+}
+
+# Complex Object Types
+variable "object_map" {
+  type = map(object({
+    foo = string,
+    bar = any
+  }))
+}
+
+variable "object_list" {
+  type = list(object({
+    foo = string,
+    bar = any
+  }))
+}
diff --git a/v1.5.7/internal/terraform/testdata/issue-33572/main.tf b/v1.5.7/internal/terraform/testdata/issue-33572/main.tf
new file mode 100644
index 0000000..2718b62
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/issue-33572/main.tf
@@ -0,0 +1,14 @@
+provider "aws" {}
+
+resource "aws_instance" "foo" {}
+
+check "aws_instance_exists" {
+  data "aws_data_source" "bar" {
+    id = "baz"
+  }
+
+  assert {
+    condition     = data.aws_data_source.bar.foo == "Hello, world!"
+    error_message = "incorrect value"
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/issue-5254/step-0/main.tf b/v1.5.7/internal/terraform/testdata/issue-5254/step-0/main.tf
new file mode 100644
index 0000000..dd666eb
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/issue-5254/step-0/main.tf
@@ -0,0 +1,12 @@
+variable "c" {
+  default = 1
+}
+
+resource "template_file" "parent" {
+  count    = var.c
+  template = "Hi"
+}
+
+resource "template_file" "child" {
+  template = "${join(",", template_file.parent.*.template)} ok"
+}
diff --git a/v1.5.7/internal/terraform/testdata/issue-5254/step-1/main.tf b/v1.5.7/internal/terraform/testdata/issue-5254/step-1/main.tf
new file mode 100644
index 0000000..3510fe1
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/issue-5254/step-1/main.tf
@@ -0,0 +1,13 @@
+variable "c" {
+  default = 1
+}
+
+resource "template_file" "parent" {
+  count    = var.c
+  template = "Hi"
+}
+
+resource "template_file" "child" {
+  template                = join(",", template_file.parent.*.template)
+  __template_requires_new = true
+}
diff --git a/v1.5.7/internal/terraform/testdata/issue-7824/main.tf b/v1.5.7/internal/terraform/testdata/issue-7824/main.tf
new file mode 100644
index 0000000..ec76bc3
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/issue-7824/main.tf
@@ -0,0 +1,6 @@
+variable "test" {
+  type = map(string)
+  default = {
+    "test" = "1"
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/terraform/testdata/issue-9549/main.tf b/v1.5.7/internal/terraform/testdata/issue-9549/main.tf
new file mode 100644
index 0000000..5bf28c6
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/issue-9549/main.tf
@@ -0,0 +1,11 @@
+module "mod" {
+  source = "./mod"
+}
+
+output "out" {
+  value = module.mod.base_config["base_template"]
+}
+
+resource "template_instance" "root_template" {
+  foo = module.mod.base_config["base_template"]
+}
diff --git a/v1.5.7/internal/terraform/testdata/issue-9549/mod/main.tf b/v1.5.7/internal/terraform/testdata/issue-9549/mod/main.tf
new file mode 100644
index 0000000..aedf9f0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/issue-9549/mod/main.tf
@@ -0,0 +1,10 @@
+resource "template_instance" "example" {
+  compute_value = "template text"
+  compute = "value"
+}
+
+output "base_config" {
+  value = {
+    base_template = template_instance.example.value
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/nested-resource-count-plan/main.tf b/v1.5.7/internal/terraform/testdata/nested-resource-count-plan/main.tf
new file mode 100644
index 0000000..f803fd1
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/nested-resource-count-plan/main.tf
@@ -0,0 +1,11 @@
+resource "aws_instance" "foo" {
+  count = 2
+}
+
+resource "aws_instance" "bar" {
+  count = "${length(aws_instance.foo.*.id)}"
+}
+
+resource "aws_instance" "baz" {
+  count = "${length(aws_instance.bar.*.id)}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-block-nesting-group/block-nesting-group.tf b/v1.5.7/internal/terraform/testdata/plan-block-nesting-group/block-nesting-group.tf
new file mode 100644
index 0000000..9284072
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-block-nesting-group/block-nesting-group.tf
@@ -0,0 +1,2 @@
+resource "test" "foo" {
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-cbd-depends-datasource/main.tf b/v1.5.7/internal/terraform/testdata/plan-cbd-depends-datasource/main.tf
new file mode 100644
index 0000000..b523204
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-cbd-depends-datasource/main.tf
@@ -0,0 +1,14 @@
+resource "aws_instance" "foo" {
+  count    = 2
+  num      = "2"
+  computed = data.aws_vpc.bar[count.index].id
+
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+
+data "aws_vpc" "bar" {
+  count = 2
+  foo   = count.index
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-cbd-maintain-root/main.tf b/v1.5.7/internal/terraform/testdata/plan-cbd-maintain-root/main.tf
new file mode 100644
index 0000000..99c96b9
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-cbd-maintain-root/main.tf
@@ -0,0 +1,19 @@
+resource "aws_instance" "foo" {
+  count = "2"
+
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+
+resource "aws_instance" "bar" {
+  count = "2"
+
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+
+output "out" {
+  value = "${aws_instance.foo.0.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-cbd/main.tf b/v1.5.7/internal/terraform/testdata/plan-cbd/main.tf
new file mode 100644
index 0000000..83d173a
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-cbd/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "foo" {
+  lifecycle {
+    create_before_destroy = true
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-close-module-provider/main.tf b/v1.5.7/internal/terraform/testdata/plan-close-module-provider/main.tf
new file mode 100644
index 0000000..ba84684
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-close-module-provider/main.tf
@@ -0,0 +1,3 @@
+module "mod" {
+  source = "./mod"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-close-module-provider/mod/main.tf b/v1.5.7/internal/terraform/testdata/plan-close-module-provider/mod/main.tf
new file mode 100644
index 0000000..3ce1991
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-close-module-provider/mod/main.tf
@@ -0,0 +1,7 @@
+provider "aws" {
+  alias = "mod"
+}
+
+resource "aws_instance" "bar" {
+  provider = "aws.mod"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-computed-attr-ref-type-mismatch/main.tf b/v1.5.7/internal/terraform/testdata/plan-computed-attr-ref-type-mismatch/main.tf
new file mode 100644
index 0000000..41761b2
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-computed-attr-ref-type-mismatch/main.tf
@@ -0,0 +1,10 @@
+resource "aws_ami_list" "foo" {
+  # assume this has a computed attr called "ids"
+}
+
+resource "aws_instance" "foo" {
+  # this is erroneously referencing the list of all ids. The value of this
+  # is unknown during plan, but we should still know that the unknown value
+  # is a list of strings and so catch this during plan.
+  ami = "${aws_ami_list.foo.ids}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-computed-data-count/main.tf b/v1.5.7/internal/terraform/testdata/plan-computed-data-count/main.tf
new file mode 100644
index 0000000..2d01404
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-computed-data-count/main.tf
@@ -0,0 +1,9 @@
+resource "aws_instance" "foo" {
+  num     = "2"
+  compute = "foo"
+}
+
+data "aws_vpc" "bar" {
+  count = 3
+  foo = "${aws_instance.foo.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-computed-data-resource/main.tf b/v1.5.7/internal/terraform/testdata/plan-computed-data-resource/main.tf
new file mode 100644
index 0000000..aff26eb
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-computed-data-resource/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+  num     = "2"
+  compute = "foo"
+}
+
+data "aws_vpc" "bar" {
+  foo = "${aws_instance.foo.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-computed-in-function/main.tf b/v1.5.7/internal/terraform/testdata/plan-computed-in-function/main.tf
new file mode 100644
index 0000000..554394d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-computed-in-function/main.tf
@@ -0,0 +1,7 @@
+data "aws_data_source" "foo" {
+
+}
+
+resource "aws_instance" "bar" {
+    attr = "${length(data.aws_data_source.foo.computed)}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-computed-list/main.tf b/v1.5.7/internal/terraform/testdata/plan-computed-list/main.tf
new file mode 100644
index 0000000..aeec6ba
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-computed-list/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+  num     = "2"
+  compute = "list.#"
+}
+
+resource "aws_instance" "bar" {
+  foo = aws_instance.foo.list.0
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-computed-multi-index/main.tf b/v1.5.7/internal/terraform/testdata/plan-computed-multi-index/main.tf
new file mode 100644
index 0000000..2d8a799
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-computed-multi-index/main.tf
@@ -0,0 +1,9 @@
+resource "aws_instance" "foo" {
+    count = 2
+    compute = "ip.#"
+}
+
+resource "aws_instance" "bar" {
+    count = 1
+    foo = "${aws_instance.foo.*.ip[count.index]}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-computed-value-in-map/main.tf b/v1.5.7/internal/terraform/testdata/plan-computed-value-in-map/main.tf
new file mode 100644
index 0000000..ef2cf08
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-computed-value-in-map/main.tf
@@ -0,0 +1,16 @@
+resource "aws_computed_source" "intermediates" {}
+
+module "test_mod" {
+  source = "./mod"
+
+  services = [
+    {
+      "exists" = "true"
+      "elb"    = "${aws_computed_source.intermediates.computed_read_only}"
+    },
+    {
+      "otherexists" = " true"
+      "elb"         = "${aws_computed_source.intermediates.computed_read_only}"
+    },
+  ]
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-computed-value-in-map/mod/main.tf b/v1.5.7/internal/terraform/testdata/plan-computed-value-in-map/mod/main.tf
new file mode 100644
index 0000000..f6adccf
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-computed-value-in-map/mod/main.tf
@@ -0,0 +1,8 @@
+variable "services" {
+  type = list(map(string))
+}
+
+resource "aws_instance" "inner2" {
+  looked_up = var.services[0]["elb"]
+}
+
diff --git a/v1.5.7/internal/terraform/testdata/plan-computed/main.tf b/v1.5.7/internal/terraform/testdata/plan-computed/main.tf
new file mode 100644
index 0000000..7180913
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-computed/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+    num = "2"
+    compute = "foo"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${aws_instance.foo.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count-computed-module/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-count-computed-module/child/main.tf
new file mode 100644
index 0000000..f80d699
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count-computed-module/child/main.tf
@@ -0,0 +1,5 @@
+variable "value" {}
+
+resource "aws_instance" "bar" {
+    count = "${var.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count-computed-module/main.tf b/v1.5.7/internal/terraform/testdata/plan-count-computed-module/main.tf
new file mode 100644
index 0000000..c87beb5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count-computed-module/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+    compute = "foo"
+}
+
+module "child" {
+    source = "./child"
+    value = "${aws_instance.foo.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count-computed/main.tf b/v1.5.7/internal/terraform/testdata/plan-count-computed/main.tf
new file mode 100644
index 0000000..8a02923
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count-computed/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+    num = "2"
+    compute = "foo"
+}
+
+resource "aws_instance" "bar" {
+    count = "${aws_instance.foo.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count-dec/main.tf b/v1.5.7/internal/terraform/testdata/plan-count-dec/main.tf
new file mode 100644
index 0000000..7837f58
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count-dec/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    foo = "foo"
+}
+
+resource "aws_instance" "bar" {
+    foo = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count-inc/main.tf b/v1.5.7/internal/terraform/testdata/plan-count-inc/main.tf
new file mode 100644
index 0000000..3c7fdb9
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count-inc/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+    foo = "foo"
+    count = 3
+}
+
+resource "aws_instance" "bar" {
+    foo = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count-index/main.tf b/v1.5.7/internal/terraform/testdata/plan-count-index/main.tf
new file mode 100644
index 0000000..9a0d1eb
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count-index/main.tf
@@ -0,0 +1,4 @@
+resource "aws_instance" "foo" {
+    count = 2
+    foo = "${count.index}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count-module-static-grandchild/child/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-count-module-static-grandchild/child/child/main.tf
new file mode 100644
index 0000000..5b75831
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count-module-static-grandchild/child/child/main.tf
@@ -0,0 +1,5 @@
+variable "value" {}
+
+resource "aws_instance" "foo" {
+    count = "${var.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count-module-static-grandchild/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-count-module-static-grandchild/child/main.tf
new file mode 100644
index 0000000..4dff927
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count-module-static-grandchild/child/main.tf
@@ -0,0 +1,6 @@
+variable "value" {}
+
+module "child" {
+    source = "./child"
+    value = "${var.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count-module-static-grandchild/main.tf b/v1.5.7/internal/terraform/testdata/plan-count-module-static-grandchild/main.tf
new file mode 100644
index 0000000..b2c7ca6
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count-module-static-grandchild/main.tf
@@ -0,0 +1,8 @@
+variable "foo" {
+  default = "3"
+}
+
+module "child" {
+  source = "./child"
+  value  = "${var.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count-module-static/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-count-module-static/child/main.tf
new file mode 100644
index 0000000..5b75831
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count-module-static/child/main.tf
@@ -0,0 +1,5 @@
+variable "value" {}
+
+resource "aws_instance" "foo" {
+    count = "${var.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count-module-static/main.tf b/v1.5.7/internal/terraform/testdata/plan-count-module-static/main.tf
new file mode 100644
index 0000000..b2c7ca6
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count-module-static/main.tf
@@ -0,0 +1,8 @@
+variable "foo" {
+  default = "3"
+}
+
+module "child" {
+  source = "./child"
+  value  = "${var.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count-one-index/main.tf b/v1.5.7/internal/terraform/testdata/plan-count-one-index/main.tf
new file mode 100644
index 0000000..58d4acf
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count-one-index/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+    count = 1
+    foo = "foo"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${aws_instance.foo.0.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count-splat-reference/main.tf b/v1.5.7/internal/terraform/testdata/plan-count-splat-reference/main.tf
new file mode 100644
index 0000000..76834e2
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count-splat-reference/main.tf
@@ -0,0 +1,9 @@
+resource "aws_instance" "foo" {
+    name = "foo ${count.index}"
+    count = 3
+}
+
+resource "aws_instance" "bar" {
+    foo_name = "${aws_instance.foo.*.name[count.index]}"
+    count = 3
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count-var/main.tf b/v1.5.7/internal/terraform/testdata/plan-count-var/main.tf
new file mode 100644
index 0000000..8b8a043
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count-var/main.tf
@@ -0,0 +1,10 @@
+variable "instance_count" {}
+
+resource "aws_instance" "foo" {
+  count = var.instance_count
+  foo   = "foo"
+}
+
+resource "aws_instance" "bar" {
+  foo = join(",", aws_instance.foo.*.foo)
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count-zero/main.tf b/v1.5.7/internal/terraform/testdata/plan-count-zero/main.tf
new file mode 100644
index 0000000..4845cbb
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count-zero/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+    count = 0
+    foo = "foo"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${aws_instance.foo.*.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-count/main.tf b/v1.5.7/internal/terraform/testdata/plan-count/main.tf
new file mode 100644
index 0000000..276670c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-count/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+    count = 5
+    foo = "foo"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${join(",", aws_instance.foo.*.foo)}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-data-depends-on/main.tf b/v1.5.7/internal/terraform/testdata/plan-data-depends-on/main.tf
new file mode 100644
index 0000000..c7332ad
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-data-depends-on/main.tf
@@ -0,0 +1,14 @@
+resource "test_resource" "a" {
+}
+
+data "test_data" "d" {
+  count = 1
+  depends_on = [
+    test_resource.a
+  ]
+}
+
+resource "test_resource" "b" {
+  count = 1
+  foo = data.test_data.d[count.index].compute
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-data-resource-becomes-computed/main.tf b/v1.5.7/internal/terraform/testdata/plan-data-resource-becomes-computed/main.tf
new file mode 100644
index 0000000..3f07be3
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-data-resource-becomes-computed/main.tf
@@ -0,0 +1,6 @@
+resource "aws_instance" "foo" {
+}
+
+data "aws_data_source" "foo" {
+  foo = "${aws_instance.foo.computed}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-destroy-interpolated-count/main.tf b/v1.5.7/internal/terraform/testdata/plan-destroy-interpolated-count/main.tf
new file mode 100644
index 0000000..ac0dadb
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-destroy-interpolated-count/main.tf
@@ -0,0 +1,20 @@
+variable "list" {
+  default = ["1", "2"]
+}
+
+resource "aws_instance" "a" {
+  count = length(var.list)
+}
+
+locals {
+  ids = aws_instance.a[*].id
+}
+
+module "empty" {
+  source = "./mod"
+  input = zipmap(var.list, local.ids)
+}
+
+output "out" {
+  value = aws_instance.a[*].id
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-destroy-interpolated-count/mod/main.tf b/v1.5.7/internal/terraform/testdata/plan-destroy-interpolated-count/mod/main.tf
new file mode 100644
index 0000000..682e0f0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-destroy-interpolated-count/mod/main.tf
@@ -0,0 +1,2 @@
+variable "input" {
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-destroy/main.tf b/v1.5.7/internal/terraform/testdata/plan-destroy/main.tf
new file mode 100644
index 0000000..1b6cdae
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-destroy/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${aws_instance.foo.num}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-diffvar/main.tf b/v1.5.7/internal/terraform/testdata/plan-diffvar/main.tf
new file mode 100644
index 0000000..eccc16f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-diffvar/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+  num = "3"
+}
+
+resource "aws_instance" "bar" {
+  num = aws_instance.foo.num
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-empty/main.tf b/v1.5.7/internal/terraform/testdata/plan-empty/main.tf
new file mode 100644
index 0000000..88002d0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-empty/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "foo" {
+}
+
+resource "aws_instance" "bar" {
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-escaped-var/main.tf b/v1.5.7/internal/terraform/testdata/plan-escaped-var/main.tf
new file mode 100644
index 0000000..5a01720
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-escaped-var/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+  foo = "bar-$${baz}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-for-each-unknown-value/main.tf b/v1.5.7/internal/terraform/testdata/plan-for-each-unknown-value/main.tf
new file mode 100644
index 0000000..933ed5f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-for-each-unknown-value/main.tf
@@ -0,0 +1,20 @@
+# expressions with variable reference
+variable "foo" {
+  type = string
+}
+
+resource "aws_instance" "foo" {
+  for_each = toset(
+       [for i in range(0,3) : sha1("${i}${var.foo}")]
+    )
+  foo = "foo"
+}
+
+# referencing another resource, which means it has some unknown values in it
+resource "aws_instance" "one" {
+  for_each = toset(["a", "b"])
+}
+
+resource "aws_instance" "two" {
+  for_each = aws_instance.one
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-for-each/main.tf b/v1.5.7/internal/terraform/testdata/plan-for-each/main.tf
new file mode 100644
index 0000000..94572e2
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-for-each/main.tf
@@ -0,0 +1,35 @@
+# maps
+resource "aws_instance" "foo" {
+    for_each = {
+        a = "thing"
+        b = "another thing"
+        c = "yet another thing"
+    }
+    num = "3"
+}
+
+# sets
+resource "aws_instance" "bar" {
+    for_each = toset([])
+}
+resource "aws_instance" "bar2" {
+    for_each = toset(["z", "y", "x"])
+}
+
+# an empty map should generate no resource
+resource "aws_instance" "baz" {
+    for_each = {}
+}
+
+# references
+resource "aws_instance" "boo" {
+    foo = aws_instance.foo["a"].num
+}
+
+resource "aws_instance" "bat" {
+    for_each = {
+        my_key = aws_instance.boo.foo
+    }
+    foo = each.value
+}
+
diff --git a/v1.5.7/internal/terraform/testdata/plan-good/main.tf b/v1.5.7/internal/terraform/testdata/plan-good/main.tf
new file mode 100644
index 0000000..1b6cdae
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-good/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${aws_instance.foo.num}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-ignore-changes-in-map/ignore-changes-in-map.tf b/v1.5.7/internal/terraform/testdata/plan-ignore-changes-in-map/ignore-changes-in-map.tf
new file mode 100644
index 0000000..75adcac
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-ignore-changes-in-map/ignore-changes-in-map.tf
@@ -0,0 +1,13 @@
+
+resource "test_ignore_changes_map" "foo" {
+  tags = {
+    ignored = "from config"
+    other   = "from config"
+  }
+
+  lifecycle {
+    ignore_changes = [
+      tags["ignored"],
+    ]
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-ignore-changes-sensitive/ignore-changes-sensitive.tf b/v1.5.7/internal/terraform/testdata/plan-ignore-changes-sensitive/ignore-changes-sensitive.tf
new file mode 100644
index 0000000..1f6cc98
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-ignore-changes-sensitive/ignore-changes-sensitive.tf
@@ -0,0 +1,11 @@
+variable "foo" {
+  sensitive = true
+}
+
+resource "aws_instance" "foo" {
+  ami = var.foo
+
+  lifecycle {
+    ignore_changes = [ami]
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-ignore-changes-wildcard/main.tf b/v1.5.7/internal/terraform/testdata/plan-ignore-changes-wildcard/main.tf
new file mode 100644
index 0000000..ac594a9
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-ignore-changes-wildcard/main.tf
@@ -0,0 +1,13 @@
+variable "foo" {}
+
+variable "bar" {}
+
+resource "aws_instance" "foo" {
+  ami      = "${var.foo}"
+  instance = "${var.bar}"
+  foo = "bar"
+
+  lifecycle {
+    ignore_changes = all
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-ignore-changes-with-flatmaps/main.tf b/v1.5.7/internal/terraform/testdata/plan-ignore-changes-with-flatmaps/main.tf
new file mode 100644
index 0000000..f61a3d4
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-ignore-changes-with-flatmaps/main.tf
@@ -0,0 +1,15 @@
+resource "aws_instance" "foo" {
+  user_data   = "x"
+  require_new = "yes"
+
+  set = [{
+    a = "1"
+    b = "2"
+  }]
+
+  lst = ["j", "k"]
+
+  lifecycle {
+    ignore_changes = ["require_new"]
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-ignore-changes/main.tf b/v1.5.7/internal/terraform/testdata/plan-ignore-changes/main.tf
new file mode 100644
index 0000000..ed17c63
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-ignore-changes/main.tf
@@ -0,0 +1,9 @@
+variable "foo" {}
+
+resource "aws_instance" "foo" {
+  ami = var.foo
+
+  lifecycle {
+    ignore_changes = [ami]
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-list-order/main.tf b/v1.5.7/internal/terraform/testdata/plan-list-order/main.tf
new file mode 100644
index 0000000..77db3d0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-list-order/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "a" {
+	foo = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 20]
+}
+
+resource "aws_instance" "b" {
+	foo = "${aws_instance.a.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-local-value-count/main.tf b/v1.5.7/internal/terraform/testdata/plan-local-value-count/main.tf
new file mode 100644
index 0000000..34aad96
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-local-value-count/main.tf
@@ -0,0 +1,8 @@
+
+locals {
+  count = 3
+}
+
+resource "test_resource" "foo" {
+  count = "${local.count}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-cycle/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-cycle/child/main.tf
new file mode 100644
index 0000000..e2e60c1
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-cycle/child/main.tf
@@ -0,0 +1,5 @@
+variable "in" {}
+
+output "out" {
+    value = "${var.in}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-cycle/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-cycle/main.tf
new file mode 100644
index 0000000..e9c4597
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-cycle/main.tf
@@ -0,0 +1,12 @@
+module "a" {
+    source = "./child"
+    in = "${aws_instance.b.id}"
+}
+
+resource "aws_instance" "b" {}
+
+resource "aws_instance" "c" {
+    some_input = "${module.a.out}"
+
+    depends_on = ["aws_instance.b"]
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-deadlock/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-deadlock/child/main.tf
new file mode 100644
index 0000000..2451bf0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-deadlock/child/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+  count = "${length("abc")}"
+
+  lifecycle {
+    create_before_destroy = true
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-deadlock/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-deadlock/main.tf
new file mode 100644
index 0000000..1f95749
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-deadlock/main.tf
@@ -0,0 +1,3 @@
+module "child" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-destroy-gh-1835/a/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-destroy-gh-1835/a/main.tf
new file mode 100644
index 0000000..ca44c75
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-destroy-gh-1835/a/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "a" {}
+
+output "a_output" {
+  value = "${aws_instance.a.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-destroy-gh-1835/b/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-destroy-gh-1835/b/main.tf
new file mode 100644
index 0000000..3b0cc66
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-destroy-gh-1835/b/main.tf
@@ -0,0 +1,5 @@
+variable "a_id" {}
+
+resource "aws_instance" "b" {
+  foo = "echo ${var.a_id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-destroy-gh-1835/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-destroy-gh-1835/main.tf
new file mode 100644
index 0000000..c2f72c4
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-destroy-gh-1835/main.tf
@@ -0,0 +1,8 @@
+module "a_module" {
+  source = "./a"
+}
+
+module "b_module" {
+  source = "./b"
+  a_id = "${module.a_module.a_output}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-destroy-multivar/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-destroy-multivar/child/main.tf
new file mode 100644
index 0000000..6a496f0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-destroy-multivar/child/main.tf
@@ -0,0 +1,8 @@
+variable "instance_count" {
+  default = "1"
+}
+
+resource "aws_instance" "foo" {
+  count = "${var.instance_count}"
+  bar = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-destroy-multivar/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-destroy-multivar/main.tf
new file mode 100644
index 0000000..2f965b6
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-destroy-multivar/main.tf
@@ -0,0 +1,4 @@
+module "child" {
+  source = "./child"
+  instance_count = "2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-destroy/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-destroy/child/main.tf
new file mode 100644
index 0000000..98f5ee8
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-destroy/child/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-destroy/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-destroy/main.tf
new file mode 100644
index 0000000..428f898
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-destroy/main.tf
@@ -0,0 +1,7 @@
+module "child" {
+    source = "./child"
+}
+
+resource "aws_instance" "foo" {
+    num = "2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-input-computed/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-input-computed/child/main.tf
new file mode 100644
index 0000000..c1a00c5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-input-computed/child/main.tf
@@ -0,0 +1,5 @@
+variable "input" {}
+
+resource "aws_instance" "foo" {
+    foo = "${var.input}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-input-computed/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-input-computed/main.tf
new file mode 100644
index 0000000..3a05764
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-input-computed/main.tf
@@ -0,0 +1,8 @@
+module "child" {
+    input = "${aws_instance.bar.foo}"
+    source = "./child"
+}
+
+resource "aws_instance" "bar" {
+    compute = "foo"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-input-var/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-input-var/child/main.tf
new file mode 100644
index 0000000..c1a00c5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-input-var/child/main.tf
@@ -0,0 +1,5 @@
+variable "input" {}
+
+resource "aws_instance" "foo" {
+    foo = "${var.input}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-input-var/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-input-var/main.tf
new file mode 100644
index 0000000..3fba315
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-input-var/main.tf
@@ -0,0 +1,10 @@
+variable "foo" {}
+
+module "child" {
+    input = "${var.foo}"
+    source = "./child"
+}
+
+resource "aws_instance" "bar" {
+    foo = "2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-input/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-input/child/main.tf
new file mode 100644
index 0000000..c1a00c5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-input/child/main.tf
@@ -0,0 +1,5 @@
+variable "input" {}
+
+resource "aws_instance" "foo" {
+    foo = "${var.input}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-input/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-input/main.tf
new file mode 100644
index 0000000..2ad8ec0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-input/main.tf
@@ -0,0 +1,8 @@
+module "child" {
+    input = "42"
+    source = "./child"
+}
+
+resource "aws_instance" "bar" {
+    foo = "2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-map-literal/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-map-literal/child/main.tf
new file mode 100644
index 0000000..9124319
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-map-literal/child/main.tf
@@ -0,0 +1,12 @@
+variable "amap" {
+  type = map(string)
+}
+
+variable "othermap" {
+  type = map(string)
+}
+
+resource "aws_instance" "foo" {
+  tags = "${var.amap}"
+  meta = "${var.othermap}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-map-literal/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-map-literal/main.tf
new file mode 100644
index 0000000..90235ed
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-map-literal/main.tf
@@ -0,0 +1,9 @@
+module "child" {
+  source = "./child"
+
+  amap = {
+    foo = "bar"
+  }
+
+  othermap = {}
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-multi-var/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-multi-var/child/main.tf
new file mode 100644
index 0000000..ad8dd60
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-multi-var/child/main.tf
@@ -0,0 +1,10 @@
+variable "things" {}
+
+resource "aws_instance" "bar" {
+  baz = "baz"
+  count = 2
+}
+
+resource "aws_instance" "foo" {
+  foo = "${join(",",aws_instance.bar.*.baz)}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-multi-var/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-multi-var/main.tf
new file mode 100644
index 0000000..40c7618
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-multi-var/main.tf
@@ -0,0 +1,9 @@
+resource "aws_instance" "parent" {
+  count = 2
+}
+
+module "child" {
+  source = "./child"
+  things = "${join(",", aws_instance.parent.*.id)}"
+}
+
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-provider-defaults-var/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-provider-defaults-var/child/main.tf
new file mode 100644
index 0000000..5ce4f55
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-provider-defaults-var/child/main.tf
@@ -0,0 +1,8 @@
+provider "aws" {
+    from = "child"
+    to = "child"
+}
+
+resource "aws_instance" "foo" {
+    from = "child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-provider-defaults-var/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-provider-defaults-var/main.tf
new file mode 100644
index 0000000..d3c3490
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-provider-defaults-var/main.tf
@@ -0,0 +1,11 @@
+module "child" {
+    source = "./child"
+}
+
+provider "aws" {
+    from = "${var.foo}"
+}
+
+resource "aws_instance" "foo" {}
+
+variable "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-provider-defaults/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-provider-defaults/child/main.tf
new file mode 100644
index 0000000..5ce4f55
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-provider-defaults/child/main.tf
@@ -0,0 +1,8 @@
+provider "aws" {
+    from = "child"
+    to = "child"
+}
+
+resource "aws_instance" "foo" {
+    from = "child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-provider-defaults/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-provider-defaults/main.tf
new file mode 100644
index 0000000..5b08577
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-provider-defaults/main.tf
@@ -0,0 +1,11 @@
+module "child" {
+    source = "./child"
+}
+
+provider "aws" {
+    from = "root"
+}
+
+resource "aws_instance" "foo" {
+    from = "root"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit-deep/A/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit-deep/A/main.tf
new file mode 100644
index 0000000..efe683c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit-deep/A/main.tf
@@ -0,0 +1,3 @@
+module "B" {
+  source = "../B"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit-deep/B/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit-deep/B/main.tf
new file mode 100644
index 0000000..29cba7f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit-deep/B/main.tf
@@ -0,0 +1,3 @@
+module "C" {
+  source = "../C"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit-deep/C/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit-deep/C/main.tf
new file mode 100644
index 0000000..919f140
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit-deep/C/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit-deep/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit-deep/main.tf
new file mode 100644
index 0000000..12677b6
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit-deep/main.tf
@@ -0,0 +1,7 @@
+module "A" {
+    source = "./A"
+}
+
+provider "aws" {
+    from = "root"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit/child/main.tf
new file mode 100644
index 0000000..2e890bb
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit/child/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+    from = "child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit/main.tf
new file mode 100644
index 0000000..5b08577
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-provider-inherit/main.tf
@@ -0,0 +1,11 @@
+module "child" {
+    source = "./child"
+}
+
+provider "aws" {
+    from = "root"
+}
+
+resource "aws_instance" "foo" {
+    from = "root"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-provider-var/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-provider-var/child/main.tf
new file mode 100644
index 0000000..599cb99
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-provider-var/child/main.tf
@@ -0,0 +1,9 @@
+variable "foo" {}
+
+provider "aws" {
+    value = "${var.foo}"
+}
+
+resource "aws_instance" "test" {
+    value = "hello"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-provider-var/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-provider-var/main.tf
new file mode 100644
index 0000000..43675f9
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-provider-var/main.tf
@@ -0,0 +1,8 @@
+variable "foo" {
+  default = "bar"
+}
+
+module "child" {
+  source = "./child"
+  foo    = "${var.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-var-computed/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-var-computed/child/main.tf
new file mode 100644
index 0000000..20a3013
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-var-computed/child/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    compute = "foo"
+}
+
+output "num" {
+    value = "${aws_instance.foo.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-var-computed/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-var-computed/main.tf
new file mode 100644
index 0000000..b38f538
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-var-computed/main.tf
@@ -0,0 +1,7 @@
+module "child" {
+    source = "./child"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${module.child.num}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-var-with-default-value/inner/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-var-with-default-value/inner/main.tf
new file mode 100644
index 0000000..5b5cf6c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-var-with-default-value/inner/main.tf
@@ -0,0 +1,12 @@
+variable "im_a_string" {
+  type = string
+}
+
+variable "service_region_ami" {
+  type = map(string)
+  default = {
+    us-east-1 = "ami-e4c9db8e"
+  }
+}
+
+resource "null_resource" "noop" {}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-var-with-default-value/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-var-with-default-value/main.tf
new file mode 100644
index 0000000..96b2741
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-var-with-default-value/main.tf
@@ -0,0 +1,7 @@
+resource "null_resource" "noop" {}
+
+module "test" {
+    source = "./inner"
+
+    im_a_string = "hello"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-var/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-var/child/main.tf
new file mode 100644
index 0000000..c7b1d28
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-var/child/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+  num = "2"
+}
+
+output "num" {
+  value = "${aws_instance.foo.num}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-var/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-var/main.tf
new file mode 100644
index 0000000..942bdba
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-var/main.tf
@@ -0,0 +1,7 @@
+module "child" {
+  source = "./child"
+}
+
+resource "aws_instance" "bar" {
+  foo = "${module.child.num}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-variable-from-splat/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-variable-from-splat/main.tf
new file mode 100644
index 0000000..be900a3
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-variable-from-splat/main.tf
@@ -0,0 +1,9 @@
+module "mod1" {
+  source = "./mod"
+  param  = ["this", "one", "works"]
+}
+
+module "mod2" {
+  source = "./mod"
+  param  = [module.mod1.out_from_splat[0]]
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-variable-from-splat/mod/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-variable-from-splat/mod/main.tf
new file mode 100644
index 0000000..66127d3
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-variable-from-splat/mod/main.tf
@@ -0,0 +1,12 @@
+variable "param" {
+  type = list(string)
+}
+
+resource "aws_instance" "test" {
+  count = "2"
+  thing = "doesnt"
+}
+
+output "out_from_splat" {
+  value = aws_instance.test.*.thing
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-wrong-var-type-nested/inner/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-wrong-var-type-nested/inner/main.tf
new file mode 100644
index 0000000..dabe507
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-wrong-var-type-nested/inner/main.tf
@@ -0,0 +1,13 @@
+variable "inner_in" {
+  type = map(string)
+  default = {
+    us-west-1 = "ami-12345"
+    us-west-2 = "ami-67890"
+  }
+}
+
+resource "null_resource" "inner_noop" {}
+
+output "inner_out" {
+  value = lookup(var.inner_in, "us-west-1")
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-wrong-var-type-nested/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-wrong-var-type-nested/main.tf
new file mode 100644
index 0000000..8f9fdcc
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-wrong-var-type-nested/main.tf
@@ -0,0 +1,3 @@
+module "middle" {
+  source = "./middle"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-wrong-var-type-nested/middle/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-wrong-var-type-nested/middle/main.tf
new file mode 100644
index 0000000..eb989fe
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-wrong-var-type-nested/middle/main.tf
@@ -0,0 +1,19 @@
+variable "middle_in" {
+  type = map(string)
+  default = {
+    eu-west-1 = "ami-12345"
+    eu-west-2 = "ami-67890"
+  }
+}
+
+module "inner" {
+  source = "../inner"
+
+  inner_in = "hello"
+}
+
+resource "null_resource" "middle_noop" {}
+
+output "middle_out" {
+  value = lookup(var.middle_in, "us-west-1")
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-wrong-var-type/inner/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-wrong-var-type/inner/main.tf
new file mode 100644
index 0000000..7782d1b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-wrong-var-type/inner/main.tf
@@ -0,0 +1,13 @@
+variable "map_in" {
+  type = map(string)
+
+  default = {
+    us-west-1 = "ami-12345"
+    us-west-2 = "ami-67890"
+  }
+}
+
+// We have to reference it so it isn't pruned
+output "output" {
+  value = var.map_in
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-module-wrong-var-type/main.tf b/v1.5.7/internal/terraform/testdata/plan-module-wrong-var-type/main.tf
new file mode 100644
index 0000000..5a39cd5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-module-wrong-var-type/main.tf
@@ -0,0 +1,10 @@
+variable "input" {
+  type    = string
+  default = "hello world"
+}
+
+module "test" {
+  source = "./inner"
+
+  map_in = var.input
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-modules-expand/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-modules-expand/child/main.tf
new file mode 100644
index 0000000..612478f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-modules-expand/child/main.tf
@@ -0,0 +1,12 @@
+variable "foo" {}
+variable "bar" {}
+
+resource "aws_instance" "foo" {
+  count = 2
+  num = var.foo
+  bar = "baz" #var.bar
+}
+
+output "out" {
+  value = aws_instance.foo[0].id
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-modules-expand/main.tf b/v1.5.7/internal/terraform/testdata/plan-modules-expand/main.tf
new file mode 100644
index 0000000..0237095
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-modules-expand/main.tf
@@ -0,0 +1,29 @@
+locals {
+  val = 2
+  bar = "baz"
+  m = {
+    "a" = "b"
+  }
+}
+
+variable "myvar" {
+  default = "baz"
+}
+
+module "count_child" {
+  count = local.val
+  foo = count.index
+  bar = var.myvar
+  source = "./child"
+}
+
+module "for_each_child" {
+  for_each = aws_instance.foo
+  foo = 2
+  bar = each.key
+  source = "./child"
+}
+
+resource "aws_instance" "foo" {
+  for_each = local.m
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-modules-remove-provisioners/main.tf b/v1.5.7/internal/terraform/testdata/plan-modules-remove-provisioners/main.tf
new file mode 100644
index 0000000..ce9a388
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-modules-remove-provisioners/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "top" {}
+
+# module "test" {
+#   source = "./parent"
+# }
diff --git a/v1.5.7/internal/terraform/testdata/plan-modules-remove-provisioners/parent/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-modules-remove-provisioners/parent/child/main.tf
new file mode 100644
index 0000000..b626e60
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-modules-remove-provisioners/parent/child/main.tf
@@ -0,0 +1,2 @@
+resource "aws_instance" "foo" {
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-modules-remove-provisioners/parent/main.tf b/v1.5.7/internal/terraform/testdata/plan-modules-remove-provisioners/parent/main.tf
new file mode 100644
index 0000000..fbc1aa0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-modules-remove-provisioners/parent/main.tf
@@ -0,0 +1,7 @@
+module "childone" {
+  source = "./child"
+}
+
+module "childtwo" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-modules-remove/main.tf b/v1.5.7/internal/terraform/testdata/plan-modules-remove/main.tf
new file mode 100644
index 0000000..98f5ee8
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-modules-remove/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-modules/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-modules/child/main.tf
new file mode 100644
index 0000000..98f5ee8
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-modules/child/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-modules/main.tf b/v1.5.7/internal/terraform/testdata/plan-modules/main.tf
new file mode 100644
index 0000000..dcdb236
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-modules/main.tf
@@ -0,0 +1,11 @@
+module "child" {
+    source = "./child"
+}
+
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${aws_instance.foo.num}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-orphan/main.tf b/v1.5.7/internal/terraform/testdata/plan-orphan/main.tf
new file mode 100644
index 0000000..98f5ee8
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-orphan/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-path-var/main.tf b/v1.5.7/internal/terraform/testdata/plan-path-var/main.tf
new file mode 100644
index 0000000..1301256
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-path-var/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "foo" {
+    cwd = "${path.cwd}/barpath"
+    module = "${path.module}/foopath"
+    root = "${path.root}/barpath"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-prevent-destroy-bad/main.tf b/v1.5.7/internal/terraform/testdata/plan-prevent-destroy-bad/main.tf
new file mode 100644
index 0000000..19077c1
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-prevent-destroy-bad/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+  require_new = "yes"
+
+  lifecycle {
+    prevent_destroy = true
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-prevent-destroy-count-bad/main.tf b/v1.5.7/internal/terraform/testdata/plan-prevent-destroy-count-bad/main.tf
new file mode 100644
index 0000000..818f93e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-prevent-destroy-count-bad/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+  count = "1"
+  current = "${count.index}"
+
+  lifecycle {
+    prevent_destroy = true
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-prevent-destroy-count-good/main.tf b/v1.5.7/internal/terraform/testdata/plan-prevent-destroy-count-good/main.tf
new file mode 100644
index 0000000..b6b4790
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-prevent-destroy-count-good/main.tf
@@ -0,0 +1,4 @@
+resource "aws_instance" "foo" {
+  count = "1"
+  current = "${count.index}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-prevent-destroy-good/main.tf b/v1.5.7/internal/terraform/testdata/plan-prevent-destroy-good/main.tf
new file mode 100644
index 0000000..a88b9e3
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-prevent-destroy-good/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "foo" {
+  lifecycle {
+    prevent_destroy = true
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-provider/main.tf b/v1.5.7/internal/terraform/testdata/plan-provider/main.tf
new file mode 100644
index 0000000..8010f70
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-provider/main.tf
@@ -0,0 +1,7 @@
+variable "foo" {}
+
+provider "aws" {
+    foo = "${var.foo}"
+}
+
+resource "aws_instance" "bar" {}
diff --git a/v1.5.7/internal/terraform/testdata/plan-provisioner-cycle/main.tf b/v1.5.7/internal/terraform/testdata/plan-provisioner-cycle/main.tf
new file mode 100644
index 0000000..ed65c09
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-provisioner-cycle/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    count = 3
+
+    provisioner "local-exec" {
+        command = "echo ${aws_instance.foo.0.id} ${aws_instance.foo.1.id} ${aws_instance.foo.2.id}"
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-required-output/main.tf b/v1.5.7/internal/terraform/testdata/plan-required-output/main.tf
new file mode 100644
index 0000000..227b5c1
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-required-output/main.tf
@@ -0,0 +1,7 @@
+resource "test_resource" "root" {
+  required = module.mod.object.id
+}
+
+module "mod" {
+  source = "./mod"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-required-output/mod/main.tf b/v1.5.7/internal/terraform/testdata/plan-required-output/mod/main.tf
new file mode 100644
index 0000000..772f164
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-required-output/mod/main.tf
@@ -0,0 +1,7 @@
+resource "test_resource" "for_output" {
+  required = "val"
+}
+
+output "object" {
+  value = test_resource.for_output
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-required-whole-mod/main.tf b/v1.5.7/internal/terraform/testdata/plan-required-whole-mod/main.tf
new file mode 100644
index 0000000..9deb3c5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-required-whole-mod/main.tf
@@ -0,0 +1,17 @@
+resource "test_resource" "root" {
+  required = local.object.id
+}
+
+locals {
+  # This indirection is here to force the evaluator to produce the whole
+  # module object here rather than just fetching the single "object" output.
+  # This makes this fixture different than plan-required-output, which just
+  # accesses module.mod.object.id directly and thus visits a different
+  # codepath in the evaluator.
+  mod    = module.mod
+  object = local.mod.object
+}
+
+module "mod" {
+  source = "./mod"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-required-whole-mod/mod/main.tf b/v1.5.7/internal/terraform/testdata/plan-required-whole-mod/mod/main.tf
new file mode 100644
index 0000000..772f164
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-required-whole-mod/mod/main.tf
@@ -0,0 +1,7 @@
+resource "test_resource" "for_output" {
+  required = "val"
+}
+
+output "object" {
+  value = test_resource.for_output
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-requires-replace/main.tf b/v1.5.7/internal/terraform/testdata/plan-requires-replace/main.tf
new file mode 100644
index 0000000..23cee56
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-requires-replace/main.tf
@@ -0,0 +1,3 @@
+resource "test_thing" "foo" {
+  v = "goodbye"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-self-ref-multi-all/main.tf b/v1.5.7/internal/terraform/testdata/plan-self-ref-multi-all/main.tf
new file mode 100644
index 0000000..d3a9857
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-self-ref-multi-all/main.tf
@@ -0,0 +1,4 @@
+resource "aws_instance" "web" {
+    foo = "${aws_instance.web.*.foo}"
+    count = 4
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-self-ref-multi/main.tf b/v1.5.7/internal/terraform/testdata/plan-self-ref-multi/main.tf
new file mode 100644
index 0000000..5b27cac
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-self-ref-multi/main.tf
@@ -0,0 +1,4 @@
+resource "aws_instance" "web" {
+    foo = "${aws_instance.web.0.foo}"
+    count = 4
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-self-ref/main.tf b/v1.5.7/internal/terraform/testdata/plan-self-ref/main.tf
new file mode 100644
index 0000000..f2bf91d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-self-ref/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "web" {
+    foo = "${aws_instance.web.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-shadow-uuid/main.tf b/v1.5.7/internal/terraform/testdata/plan-shadow-uuid/main.tf
new file mode 100644
index 0000000..2b6ec72
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-shadow-uuid/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "test" {
+    value = "${uuid()}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-taint-ignore-changes/main.tf b/v1.5.7/internal/terraform/testdata/plan-taint-ignore-changes/main.tf
new file mode 100644
index 0000000..ff95d65
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-taint-ignore-changes/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+  vars = "foo"
+
+  lifecycle {
+    ignore_changes = ["vars"]
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-taint-interpolated-count/main.tf b/v1.5.7/internal/terraform/testdata/plan-taint-interpolated-count/main.tf
new file mode 100644
index 0000000..91d8b65
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-taint-interpolated-count/main.tf
@@ -0,0 +1,7 @@
+variable "instance_count" {
+  default = 3
+}
+
+resource "aws_instance" "foo" {
+  count = "${var.instance_count}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-taint/main.tf b/v1.5.7/internal/terraform/testdata/plan-taint/main.tf
new file mode 100644
index 0000000..1b6cdae
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-taint/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${aws_instance.foo.num}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-targeted-cross-module/A/main.tf b/v1.5.7/internal/terraform/testdata/plan-targeted-cross-module/A/main.tf
new file mode 100644
index 0000000..4c014aa
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-targeted-cross-module/A/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+  foo = "bar"
+}
+
+output "value" {
+  value = "${aws_instance.foo.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-targeted-cross-module/B/main.tf b/v1.5.7/internal/terraform/testdata/plan-targeted-cross-module/B/main.tf
new file mode 100644
index 0000000..c3aeb7b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-targeted-cross-module/B/main.tf
@@ -0,0 +1,5 @@
+variable "input" {}
+
+resource "aws_instance" "bar" {
+    foo = "${var.input}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-targeted-cross-module/main.tf b/v1.5.7/internal/terraform/testdata/plan-targeted-cross-module/main.tf
new file mode 100644
index 0000000..e6a83b2
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-targeted-cross-module/main.tf
@@ -0,0 +1,8 @@
+module "A" {
+    source = "./A"
+}
+
+module "B" {
+    source = "./B"
+    input  = "${module.A.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-targeted-module-orphan/main.tf b/v1.5.7/internal/terraform/testdata/plan-targeted-module-orphan/main.tf
new file mode 100644
index 0000000..2b33fed
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-targeted-module-orphan/main.tf
@@ -0,0 +1,6 @@
+# Once opon a time, there was a child module here
+/*
+module "child" {
+  source = "./child"
+}
+*/
diff --git a/v1.5.7/internal/terraform/testdata/plan-targeted-module-untargeted-variable/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-targeted-module-untargeted-variable/child/main.tf
new file mode 100644
index 0000000..f7b424b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-targeted-module-untargeted-variable/child/main.tf
@@ -0,0 +1,5 @@
+variable "id" {}
+
+resource "aws_instance" "mod" {
+  value = "${var.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-targeted-module-untargeted-variable/main.tf b/v1.5.7/internal/terraform/testdata/plan-targeted-module-untargeted-variable/main.tf
new file mode 100644
index 0000000..90e44dc
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-targeted-module-untargeted-variable/main.tf
@@ -0,0 +1,12 @@
+resource "aws_instance" "blue" { }
+resource "aws_instance" "green" { }
+
+module "blue_mod" {
+  source = "./child"
+  id = "${aws_instance.blue.id}"
+}
+
+module "green_mod" {
+  source = "./child"
+  id = "${aws_instance.green.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-targeted-module-with-provider/child1/main.tf b/v1.5.7/internal/terraform/testdata/plan-targeted-module-with-provider/child1/main.tf
new file mode 100644
index 0000000..c9aaff5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-targeted-module-with-provider/child1/main.tf
@@ -0,0 +1,7 @@
+variable "key" {}
+
+provider "null" {
+  key = "${var.key}"
+}
+
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/plan-targeted-module-with-provider/child2/main.tf b/v1.5.7/internal/terraform/testdata/plan-targeted-module-with-provider/child2/main.tf
new file mode 100644
index 0000000..c9aaff5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-targeted-module-with-provider/child2/main.tf
@@ -0,0 +1,7 @@
+variable "key" {}
+
+provider "null" {
+  key = "${var.key}"
+}
+
+resource "null_resource" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/plan-targeted-module-with-provider/main.tf b/v1.5.7/internal/terraform/testdata/plan-targeted-module-with-provider/main.tf
new file mode 100644
index 0000000..0fa7bcf
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-targeted-module-with-provider/main.tf
@@ -0,0 +1,9 @@
+module "child1" {
+  source = "./child1"
+  key = "value"
+}
+
+module "child2" {
+  source = "./child2"
+  key = "value"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-targeted-orphan/main.tf b/v1.5.7/internal/terraform/testdata/plan-targeted-orphan/main.tf
new file mode 100644
index 0000000..f202085
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-targeted-orphan/main.tf
@@ -0,0 +1,6 @@
+# This resource was previously "created" and the fixture represents
+# it being destroyed subsequently
+
+/*resource "aws_instance" "orphan" {*/
+	/*foo = "bar"*/
+/*}*/
diff --git a/v1.5.7/internal/terraform/testdata/plan-targeted-over-ten/main.tf b/v1.5.7/internal/terraform/testdata/plan-targeted-over-ten/main.tf
new file mode 100644
index 0000000..1c7bc87
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-targeted-over-ten/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+  count    = 13
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-targeted/main.tf b/v1.5.7/internal/terraform/testdata/plan-targeted/main.tf
new file mode 100644
index 0000000..ab00a84
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-targeted/main.tf
@@ -0,0 +1,12 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = aws_instance.foo.num
+}
+
+module "mod" {
+  source = "./mod"
+  count = 1
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-targeted/mod/main.tf b/v1.5.7/internal/terraform/testdata/plan-targeted/mod/main.tf
new file mode 100644
index 0000000..98f5ee8
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-targeted/mod/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-untargeted-resource-output/main.tf b/v1.5.7/internal/terraform/testdata/plan-untargeted-resource-output/main.tf
new file mode 100644
index 0000000..9d4a1c8
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-untargeted-resource-output/main.tf
@@ -0,0 +1,8 @@
+module "mod" {
+  source = "./mod"
+}
+
+
+resource "aws_instance" "c" {
+  name = "${module.mod.output}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-untargeted-resource-output/mod/main.tf b/v1.5.7/internal/terraform/testdata/plan-untargeted-resource-output/mod/main.tf
new file mode 100644
index 0000000..dd6d791
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-untargeted-resource-output/mod/main.tf
@@ -0,0 +1,15 @@
+locals {
+  one = 1
+}
+
+resource "aws_instance" "a" {
+  count = "${local.one}"
+}
+
+resource "aws_instance" "b" {
+  count = "${local.one}"
+}
+
+output "output" {
+  value = "${join("", coalescelist(aws_instance.a.*.id, aws_instance.b.*.id))}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-var-list-err/main.tf b/v1.5.7/internal/terraform/testdata/plan-var-list-err/main.tf
new file mode 100644
index 0000000..6303064
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-var-list-err/main.tf
@@ -0,0 +1,16 @@
+provider "aws" {
+    access_key = "a"
+    secret_key = "b"
+    region = "us-east-1"
+}
+
+resource "aws_instance" "foo" {
+    ami = "ami-foo"
+    instance_type = "t2.micro"
+    security_groups = "${aws_security_group.foo.name}"
+}
+
+resource "aws_security_group" "foo" {
+    name = "foobar"
+    description = "foobar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-variable-sensitivity-module/child/main.tf b/v1.5.7/internal/terraform/testdata/plan-variable-sensitivity-module/child/main.tf
new file mode 100644
index 0000000..e34751a
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-variable-sensitivity-module/child/main.tf
@@ -0,0 +1,13 @@
+variable "foo" {
+  type = string
+}
+
+// "bar" is defined as sensitive by both the parent and the child
+variable "bar" {
+  sensitive = true
+}
+
+resource "aws_instance" "foo" {
+  foo   = var.foo
+  value = var.bar
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-variable-sensitivity-module/main.tf b/v1.5.7/internal/terraform/testdata/plan-variable-sensitivity-module/main.tf
new file mode 100644
index 0000000..69bdbb4
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-variable-sensitivity-module/main.tf
@@ -0,0 +1,14 @@
+variable "sensitive_var" {
+  default   = "foo"
+  sensitive = true
+}
+
+variable "another_var" {
+  sensitive = true
+}
+
+module "child" {
+  source = "./child"
+  foo    = var.sensitive_var
+  bar    = var.another_var
+}
diff --git a/v1.5.7/internal/terraform/testdata/plan-variable-sensitivity/main.tf b/v1.5.7/internal/terraform/testdata/plan-variable-sensitivity/main.tf
new file mode 100644
index 0000000..00a4b1e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/plan-variable-sensitivity/main.tf
@@ -0,0 +1,8 @@
+variable "sensitive_var" {
+    default = "foo"
+    sensitive = true
+}
+
+resource "aws_instance" "foo" {
+  foo   = var.sensitive_var
+}
\ No newline at end of file
diff --git a/v1.5.7/internal/terraform/testdata/provider-meta-data-set/main.tf b/v1.5.7/internal/terraform/testdata/provider-meta-data-set/main.tf
new file mode 100644
index 0000000..ef7acd9
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/provider-meta-data-set/main.tf
@@ -0,0 +1,13 @@
+data "test_data_source" "foo" {
+  foo = "bar"
+}
+
+terraform {
+  provider_meta "test" {
+    baz = "quux"
+  }
+}
+
+module "my_module" {
+  source = "./my-module"
+}
diff --git a/v1.5.7/internal/terraform/testdata/provider-meta-data-set/my-module/main.tf b/v1.5.7/internal/terraform/testdata/provider-meta-data-set/my-module/main.tf
new file mode 100644
index 0000000..61a9770
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/provider-meta-data-set/my-module/main.tf
@@ -0,0 +1,9 @@
+data "test_file" "foo" {
+  id = "bar"
+}
+
+terraform {
+  provider_meta "test" {
+    baz = "quux-submodule"
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/provider-meta-data-unset/main.tf b/v1.5.7/internal/terraform/testdata/provider-meta-data-unset/main.tf
new file mode 100644
index 0000000..c4091f3
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/provider-meta-data-unset/main.tf
@@ -0,0 +1,7 @@
+data "test_data_source" "foo" {
+  foo = "bar"
+}
+
+module "my_module" {
+  source = "./my-module"
+}
diff --git a/v1.5.7/internal/terraform/testdata/provider-meta-data-unset/my-module/main.tf b/v1.5.7/internal/terraform/testdata/provider-meta-data-unset/my-module/main.tf
new file mode 100644
index 0000000..7e0ea46
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/provider-meta-data-unset/my-module/main.tf
@@ -0,0 +1,3 @@
+data "test_file" "foo" {
+  id = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/provider-meta-set/main.tf b/v1.5.7/internal/terraform/testdata/provider-meta-set/main.tf
new file mode 100644
index 0000000..a3e9f80
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/provider-meta-set/main.tf
@@ -0,0 +1,13 @@
+resource "test_instance" "bar" {
+  foo = "bar"
+}
+
+terraform {
+  provider_meta "test" {
+    baz = "quux"
+  }
+}
+
+module "my_module" {
+  source = "./my-module"
+}
diff --git a/v1.5.7/internal/terraform/testdata/provider-meta-set/my-module/main.tf b/v1.5.7/internal/terraform/testdata/provider-meta-set/my-module/main.tf
new file mode 100644
index 0000000..2a89dd5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/provider-meta-set/my-module/main.tf
@@ -0,0 +1,9 @@
+resource "test_resource" "bar" {
+  value = "bar"
+}
+
+terraform {
+  provider_meta "test" {
+    baz = "quux-submodule"
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/provider-meta-unset/main.tf b/v1.5.7/internal/terraform/testdata/provider-meta-unset/main.tf
new file mode 100644
index 0000000..0ae85d3
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/provider-meta-unset/main.tf
@@ -0,0 +1,7 @@
+resource "test_instance" "bar" {
+  foo = "bar"
+}
+
+module "my_module" {
+  source = "./my-module"
+}
diff --git a/v1.5.7/internal/terraform/testdata/provider-meta-unset/my-module/main.tf b/v1.5.7/internal/terraform/testdata/provider-meta-unset/my-module/main.tf
new file mode 100644
index 0000000..ec9701f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/provider-meta-unset/my-module/main.tf
@@ -0,0 +1,3 @@
+resource "test_resource" "bar" {
+  value = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/provider-with-locals/main.tf b/v1.5.7/internal/terraform/testdata/provider-with-locals/main.tf
new file mode 100644
index 0000000..3a7db0f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/provider-with-locals/main.tf
@@ -0,0 +1,11 @@
+provider "aws" {
+	region = "${local.foo}"
+}
+
+locals {
+	foo = "bar"
+}
+
+resource "aws_instance" "foo" {
+    value = "${local.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-basic/main.tf b/v1.5.7/internal/terraform/testdata/refresh-basic/main.tf
new file mode 100644
index 0000000..64cbf62
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-basic/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "web" {}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-data-count/refresh-data-count.tf b/v1.5.7/internal/terraform/testdata/refresh-data-count/refresh-data-count.tf
new file mode 100644
index 0000000..ccabdb2
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-data-count/refresh-data-count.tf
@@ -0,0 +1,6 @@
+resource "test" "foo" {
+}
+
+data "test" "foo" {
+  count = length(test.foo.things)
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-data-module-var/child/main.tf b/v1.5.7/internal/terraform/testdata/refresh-data-module-var/child/main.tf
new file mode 100644
index 0000000..64d21be
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-data-module-var/child/main.tf
@@ -0,0 +1,6 @@
+variable "key" {}
+
+data "aws_data_source" "foo" {
+  id = "${var.key}"
+}
+
diff --git a/v1.5.7/internal/terraform/testdata/refresh-data-module-var/main.tf b/v1.5.7/internal/terraform/testdata/refresh-data-module-var/main.tf
new file mode 100644
index 0000000..a371831
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-data-module-var/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "A" {
+  foo = "bar"
+}
+
+module "child" {
+  source = "./child"
+  key    = "${aws_instance.A.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-data-ref-data/main.tf b/v1.5.7/internal/terraform/testdata/refresh-data-ref-data/main.tf
new file mode 100644
index 0000000..5512be2
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-data-ref-data/main.tf
@@ -0,0 +1,7 @@
+data "null_data_source" "foo" {
+  foo = "yes"
+}
+
+data "null_data_source" "bar" {
+  bar = "${data.null_data_source.foo.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-data-resource-basic/main.tf b/v1.5.7/internal/terraform/testdata/refresh-data-resource-basic/main.tf
new file mode 100644
index 0000000..cb16d9f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-data-resource-basic/main.tf
@@ -0,0 +1,5 @@
+data "null_data_source" "testing" {
+  inputs = {
+    test = "yes"
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-dynamic/main.tf b/v1.5.7/internal/terraform/testdata/refresh-dynamic/main.tf
new file mode 100644
index 0000000..5c857a2
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-dynamic/main.tf
@@ -0,0 +1,3 @@
+resource "test_instance" "foo" {
+  dynamic = {}
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-module-computed-var/child/main.tf b/v1.5.7/internal/terraform/testdata/refresh-module-computed-var/child/main.tf
new file mode 100644
index 0000000..38260d6
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-module-computed-var/child/main.tf
@@ -0,0 +1,5 @@
+variable "value" {}
+
+output "value" {
+    value = "${var.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-module-computed-var/main.tf b/v1.5.7/internal/terraform/testdata/refresh-module-computed-var/main.tf
new file mode 100644
index 0000000..a857332
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-module-computed-var/main.tf
@@ -0,0 +1,8 @@
+module "child" {
+    source = "./child"
+    value = "${join(" ", aws_instance.test.*.id)}"
+}
+
+resource "aws_instance" "test" {
+    value = "yes"
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-module-input-computed-output/child/main.tf b/v1.5.7/internal/terraform/testdata/refresh-module-input-computed-output/child/main.tf
new file mode 100644
index 0000000..ebc1e3f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-module-input-computed-output/child/main.tf
@@ -0,0 +1,11 @@
+variable "input" {
+    type = string
+}
+
+resource "aws_instance" "foo" {
+    foo = var.input
+}
+
+output "foo" {
+    value = aws_instance.foo.foo
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-module-input-computed-output/main.tf b/v1.5.7/internal/terraform/testdata/refresh-module-input-computed-output/main.tf
new file mode 100644
index 0000000..5827a5d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-module-input-computed-output/main.tf
@@ -0,0 +1,8 @@
+module "child" {
+    input = aws_instance.bar.foo
+    source = "./child"
+}
+
+resource "aws_instance" "bar" {
+    compute = "foo"
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-module-orphan/child/grandchild/main.tf b/v1.5.7/internal/terraform/testdata/refresh-module-orphan/child/grandchild/main.tf
new file mode 100644
index 0000000..942e93d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-module-orphan/child/grandchild/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "baz" {}
+
+output "id" { value = "${aws_instance.baz.id}" }
diff --git a/v1.5.7/internal/terraform/testdata/refresh-module-orphan/child/main.tf b/v1.5.7/internal/terraform/testdata/refresh-module-orphan/child/main.tf
new file mode 100644
index 0000000..7c3fc84
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-module-orphan/child/main.tf
@@ -0,0 +1,10 @@
+module "grandchild" {
+  source = "./grandchild"
+}
+
+resource "aws_instance" "bar" {
+  grandchildid = "${module.grandchild.id}"
+}
+
+output "id" { value = "${aws_instance.bar.id}" }
+output "grandchild_id" { value = "${module.grandchild.id}" }
diff --git a/v1.5.7/internal/terraform/testdata/refresh-module-orphan/main.tf b/v1.5.7/internal/terraform/testdata/refresh-module-orphan/main.tf
new file mode 100644
index 0000000..244374d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-module-orphan/main.tf
@@ -0,0 +1,10 @@
+/*
+module "child" {
+  source = "./child"
+}
+
+resource "aws_instance" "bar" {
+  childid      = "${module.child.id}"
+  grandchildid = "${module.child.grandchild_id}"
+}
+*/
diff --git a/v1.5.7/internal/terraform/testdata/refresh-module-var-module/bar/main.tf b/v1.5.7/internal/terraform/testdata/refresh-module-var-module/bar/main.tf
new file mode 100644
index 0000000..46ea37f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-module-var-module/bar/main.tf
@@ -0,0 +1,3 @@
+variable "value" {}
+
+resource "aws_instance" "bar" {}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-module-var-module/foo/main.tf b/v1.5.7/internal/terraform/testdata/refresh-module-var-module/foo/main.tf
new file mode 100644
index 0000000..2ee7980
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-module-var-module/foo/main.tf
@@ -0,0 +1,7 @@
+output "output" {
+    value = "${aws_instance.foo.foo}"
+}
+
+resource "aws_instance" "foo" {
+    compute = "foo"
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-module-var-module/main.tf b/v1.5.7/internal/terraform/testdata/refresh-module-var-module/main.tf
new file mode 100644
index 0000000..76775e3
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-module-var-module/main.tf
@@ -0,0 +1,8 @@
+module "foo" {
+    source = "./foo"
+}
+
+module "bar" {
+    source = "./bar"
+    value = "${module.foo.output}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-modules/child/main.tf b/v1.5.7/internal/terraform/testdata/refresh-modules/child/main.tf
new file mode 100644
index 0000000..64cbf62
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-modules/child/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "web" {}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-modules/main.tf b/v1.5.7/internal/terraform/testdata/refresh-modules/main.tf
new file mode 100644
index 0000000..6b4520e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-modules/main.tf
@@ -0,0 +1,5 @@
+module "child" {
+    source = "./child"
+}
+
+resource "aws_instance" "web" {}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-no-state/main.tf b/v1.5.7/internal/terraform/testdata/refresh-no-state/main.tf
new file mode 100644
index 0000000..76c0f87
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-no-state/main.tf
@@ -0,0 +1,3 @@
+output "foo" {
+  value = ""
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-output-partial/main.tf b/v1.5.7/internal/terraform/testdata/refresh-output-partial/main.tf
new file mode 100644
index 0000000..36ce289
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-output-partial/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {}
+
+resource "aws_instance" "web" {}
+
+output "foo" {
+    value = "${aws_instance.web.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-output/main.tf b/v1.5.7/internal/terraform/testdata/refresh-output/main.tf
new file mode 100644
index 0000000..42a01bd
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-output/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "web" {}
+
+output "foo" {
+    value = "${aws_instance.web.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-schema-upgrade/main.tf b/v1.5.7/internal/terraform/testdata/refresh-schema-upgrade/main.tf
new file mode 100644
index 0000000..ee0590e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-schema-upgrade/main.tf
@@ -0,0 +1,2 @@
+resource "test_thing" "bar" {
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-targeted-count/main.tf b/v1.5.7/internal/terraform/testdata/refresh-targeted-count/main.tf
new file mode 100644
index 0000000..f564b62
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-targeted-count/main.tf
@@ -0,0 +1,9 @@
+resource "aws_vpc" "metoo" {}
+resource "aws_instance" "notme" { }
+resource "aws_instance" "me" {
+  vpc_id = "${aws_vpc.metoo.id}"
+  count = 3
+}
+resource "aws_elb" "meneither" {
+  instances = ["${aws_instance.me.*.id}"]
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-targeted/main.tf b/v1.5.7/internal/terraform/testdata/refresh-targeted/main.tf
new file mode 100644
index 0000000..3a76184
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-targeted/main.tf
@@ -0,0 +1,8 @@
+resource "aws_vpc" "metoo" {}
+resource "aws_instance" "notme" { }
+resource "aws_instance" "me" {
+  vpc_id = "${aws_vpc.metoo.id}"
+}
+resource "aws_elb" "meneither" {
+  instances = ["${aws_instance.me.*.id}"]
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-unknown-provider/main.tf b/v1.5.7/internal/terraform/testdata/refresh-unknown-provider/main.tf
new file mode 100644
index 0000000..8a29fdd
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-unknown-provider/main.tf
@@ -0,0 +1,4 @@
+resource "unknown_instance" "foo" {
+    num = "2"
+    compute = "foo"
+}
diff --git a/v1.5.7/internal/terraform/testdata/refresh-vars/main.tf b/v1.5.7/internal/terraform/testdata/refresh-vars/main.tf
new file mode 100644
index 0000000..86cd6ac
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/refresh-vars/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "web" {}
+
+resource "aws_instance" "db" {
+  ami = "${aws_instance.web.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/static-validate-refs/static-validate-refs.tf b/v1.5.7/internal/terraform/testdata/static-validate-refs/static-validate-refs.tf
new file mode 100644
index 0000000..2f71e21
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/static-validate-refs/static-validate-refs.tf
@@ -0,0 +1,32 @@
+terraform {
+  required_providers {
+    boop = {
+      source = "foobar/beep" # intentional mismatch between local name and type
+    }
+  }
+}
+
+resource "aws_instance" "no_count" {
+}
+
+resource "aws_instance" "count" {
+  count = 1
+}
+
+resource "boop_instance" "yep" {
+}
+
+resource "boop_whatever" "nope" {
+}
+
+data "beep" "boop" {
+}
+
+check "foo" {
+  data "boop_data" "boop_nested" {}
+
+  assert {
+    condition     = data.boop_data.boop_nested.id == null
+    error_message = "check failed"
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-cbd-destroy-edge-both-count/main.tf b/v1.5.7/internal/terraform/testdata/transform-cbd-destroy-edge-both-count/main.tf
new file mode 100644
index 0000000..c19e78e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-cbd-destroy-edge-both-count/main.tf
@@ -0,0 +1,11 @@
+resource "test_object" "A" {
+  count = 2
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+
+resource "test_object" "B" {
+  count       = 2
+  test_string = test_object.A[*].test_string[count.index]
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-cbd-destroy-edge-count/main.tf b/v1.5.7/internal/terraform/testdata/transform-cbd-destroy-edge-count/main.tf
new file mode 100644
index 0000000..775900f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-cbd-destroy-edge-count/main.tf
@@ -0,0 +1,10 @@
+resource "test_object" "A" {
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+
+resource "test_object" "B" {
+  count       = 2
+  test_string = test_object.A.test_string
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-config-mode-data/main.tf b/v1.5.7/internal/terraform/testdata/transform-config-mode-data/main.tf
new file mode 100644
index 0000000..3c3e7e5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-config-mode-data/main.tf
@@ -0,0 +1,3 @@
+data "aws_ami" "foo" {}
+
+resource "aws_instance" "web" {}
diff --git a/v1.5.7/internal/terraform/testdata/transform-destroy-cbd-edge-basic/main.tf b/v1.5.7/internal/terraform/testdata/transform-destroy-cbd-edge-basic/main.tf
new file mode 100644
index 0000000..a17d8b4
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-destroy-cbd-edge-basic/main.tf
@@ -0,0 +1,9 @@
+resource "test_object" "A" {
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+
+resource "test_object" "B" {
+  test_string = "${test_object.A.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-destroy-cbd-edge-multi/main.tf b/v1.5.7/internal/terraform/testdata/transform-destroy-cbd-edge-multi/main.tf
new file mode 100644
index 0000000..964bc44
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-destroy-cbd-edge-multi/main.tf
@@ -0,0 +1,15 @@
+resource "test_object" "A" {
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+
+resource "test_object" "B" {
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+
+resource "test_object" "C" {
+  test_string = "${test_object.A.id}-${test_object.B.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-destroy-edge-basic/main.tf b/v1.5.7/internal/terraform/testdata/transform-destroy-edge-basic/main.tf
new file mode 100644
index 0000000..8afeda4
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-destroy-edge-basic/main.tf
@@ -0,0 +1,5 @@
+resource "test_object" "A" {}
+
+resource "test_object" "B" {
+  test_string = "${test_object.A.test_string}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-destroy-edge-module-only/child/main.tf b/v1.5.7/internal/terraform/testdata/transform-destroy-edge-module-only/child/main.tf
new file mode 100644
index 0000000..242bb33
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-destroy-edge-module-only/child/main.tf
@@ -0,0 +1,9 @@
+resource "test_object" "a" {}
+
+resource "test_object" "b" {
+  test_string = "${test_object.a.test_string}"
+}
+
+resource "test_object" "c" {
+  test_string = "${test_object.b.test_string}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-destroy-edge-module-only/main.tf b/v1.5.7/internal/terraform/testdata/transform-destroy-edge-module-only/main.tf
new file mode 100644
index 0000000..9193514
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-destroy-edge-module-only/main.tf
@@ -0,0 +1,4 @@
+module "child" {
+    source = "./child"
+    count  = 2
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-destroy-edge-module/child/main.tf b/v1.5.7/internal/terraform/testdata/transform-destroy-edge-module/child/main.tf
new file mode 100644
index 0000000..337bbe7
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-destroy-edge-module/child/main.tf
@@ -0,0 +1,7 @@
+resource "test_object" "b" {
+  test_string = "foo"
+}
+
+output "output" {
+  value = "${test_object.b.test_string}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-destroy-edge-module/main.tf b/v1.5.7/internal/terraform/testdata/transform-destroy-edge-module/main.tf
new file mode 100644
index 0000000..2a42635
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-destroy-edge-module/main.tf
@@ -0,0 +1,7 @@
+resource "test_object" "a" {
+  test_string = "${module.child.output}"
+}
+
+module "child" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-destroy-edge-multi/main.tf b/v1.5.7/internal/terraform/testdata/transform-destroy-edge-multi/main.tf
new file mode 100644
index 0000000..3474bf6
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-destroy-edge-multi/main.tf
@@ -0,0 +1,9 @@
+resource "test_object" "A" {}
+
+resource "test_object" "B" {
+  test_string = "${test_object.A.test_string}"
+}
+
+resource "test_object" "C" {
+  test_string = "${test_object.B.test_string}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-destroy-edge-self-ref/main.tf b/v1.5.7/internal/terraform/testdata/transform-destroy-edge-self-ref/main.tf
new file mode 100644
index 0000000..d91e024
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-destroy-edge-self-ref/main.tf
@@ -0,0 +1,5 @@
+resource "test" "A" {
+    provisioner "foo" {
+        command = "${test.A.id}"
+    }
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-module-var-basic/child/main.tf b/v1.5.7/internal/terraform/testdata/transform-module-var-basic/child/main.tf
new file mode 100644
index 0000000..53f3cd7
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-module-var-basic/child/main.tf
@@ -0,0 +1,5 @@
+variable "value" {}
+
+output "result" {
+  value = "${var.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-module-var-basic/main.tf b/v1.5.7/internal/terraform/testdata/transform-module-var-basic/main.tf
new file mode 100644
index 0000000..0adb513
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-module-var-basic/main.tf
@@ -0,0 +1,4 @@
+module "child" {
+    source = "./child"
+    value = "foo"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-module-var-nested/child/child/main.tf b/v1.5.7/internal/terraform/testdata/transform-module-var-nested/child/child/main.tf
new file mode 100644
index 0000000..53f3cd7
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-module-var-nested/child/child/main.tf
@@ -0,0 +1,5 @@
+variable "value" {}
+
+output "result" {
+  value = "${var.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-module-var-nested/child/main.tf b/v1.5.7/internal/terraform/testdata/transform-module-var-nested/child/main.tf
new file mode 100644
index 0000000..b8c7f0b
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-module-var-nested/child/main.tf
@@ -0,0 +1,6 @@
+variable "value" {}
+
+module "child" {
+    source = "./child"
+    value  = "${var.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-module-var-nested/main.tf b/v1.5.7/internal/terraform/testdata/transform-module-var-nested/main.tf
new file mode 100644
index 0000000..2c20f19
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-module-var-nested/main.tf
@@ -0,0 +1,4 @@
+module "child" {
+    source = "./child"
+    value  = "foo"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-orphan-basic/main.tf b/v1.5.7/internal/terraform/testdata/transform-orphan-basic/main.tf
new file mode 100644
index 0000000..64cbf62
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-orphan-basic/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "web" {}
diff --git a/v1.5.7/internal/terraform/testdata/transform-orphan-count-empty/main.tf b/v1.5.7/internal/terraform/testdata/transform-orphan-count-empty/main.tf
new file mode 100644
index 0000000..e8045d6
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-orphan-count-empty/main.tf
@@ -0,0 +1 @@
+# Purposefully empty
diff --git a/v1.5.7/internal/terraform/testdata/transform-orphan-count/main.tf b/v1.5.7/internal/terraform/testdata/transform-orphan-count/main.tf
new file mode 100644
index 0000000..acef373
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-orphan-count/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+  count = 3
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-orphan-modules/main.tf b/v1.5.7/internal/terraform/testdata/transform-orphan-modules/main.tf
new file mode 100644
index 0000000..919f140
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-orphan-modules/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provider-basic/main.tf b/v1.5.7/internal/terraform/testdata/transform-provider-basic/main.tf
new file mode 100644
index 0000000..8a44e1d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provider-basic/main.tf
@@ -0,0 +1,2 @@
+provider "aws" {}
+resource "aws_instance" "web" {}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provider-fqns-module/child/main.tf b/v1.5.7/internal/terraform/testdata/transform-provider-fqns-module/child/main.tf
new file mode 100644
index 0000000..5c56b76
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provider-fqns-module/child/main.tf
@@ -0,0 +1,11 @@
+terraform {
+  required_providers {
+    your-aws = {
+      source = "hashicorp/aws"
+    }
+  }
+}
+
+resource "aws_instance" "web" {
+  provider = "your-aws"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provider-fqns-module/main.tf b/v1.5.7/internal/terraform/testdata/transform-provider-fqns-module/main.tf
new file mode 100644
index 0000000..dd582c0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provider-fqns-module/main.tf
@@ -0,0 +1,11 @@
+terraform {
+  required_providers {
+    my-aws = {
+      source = "hashicorp/aws"
+    }
+  }
+}
+
+resource "aws_instance" "web" {
+  provider = "my-aws"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provider-fqns/main.tf b/v1.5.7/internal/terraform/testdata/transform-provider-fqns/main.tf
new file mode 100644
index 0000000..dd582c0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provider-fqns/main.tf
@@ -0,0 +1,11 @@
+terraform {
+  required_providers {
+    my-aws = {
+      source = "hashicorp/aws"
+    }
+  }
+}
+
+resource "aws_instance" "web" {
+  provider = "my-aws"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provider-grandchild-inherit/child/grandchild/main.tf b/v1.5.7/internal/terraform/testdata/transform-provider-grandchild-inherit/child/grandchild/main.tf
new file mode 100644
index 0000000..58363ef
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provider-grandchild-inherit/child/grandchild/main.tf
@@ -0,0 +1,7 @@
+provider "aws" {
+  alias = "baz"
+}
+
+resource "aws_instance" "baz" {
+  provider = "aws.baz"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provider-grandchild-inherit/child/main.tf b/v1.5.7/internal/terraform/testdata/transform-provider-grandchild-inherit/child/main.tf
new file mode 100644
index 0000000..7ec8034
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provider-grandchild-inherit/child/main.tf
@@ -0,0 +1,10 @@
+provider "aws" {
+  alias = "bar"
+}
+
+module "grandchild" {
+  source = "./grandchild"
+  providers = {
+    aws.baz = aws.bar
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provider-grandchild-inherit/main.tf b/v1.5.7/internal/terraform/testdata/transform-provider-grandchild-inherit/main.tf
new file mode 100644
index 0000000..cb9a2f9
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provider-grandchild-inherit/main.tf
@@ -0,0 +1,11 @@
+provider "aws" {
+  alias = "foo"
+  value = "config"
+}
+
+module "child" {
+  source = "./child"
+  providers = {
+    aws.bar = aws.foo
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provider-inherit/child/main.tf b/v1.5.7/internal/terraform/testdata/transform-provider-inherit/child/main.tf
new file mode 100644
index 0000000..b1f0706
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provider-inherit/child/main.tf
@@ -0,0 +1,7 @@
+provider "aws" {
+    alias = "bar"
+}
+
+resource "aws_instance" "thing" {
+    provider = aws.bar
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provider-inherit/main.tf b/v1.5.7/internal/terraform/testdata/transform-provider-inherit/main.tf
new file mode 100644
index 0000000..cb9a2f9
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provider-inherit/main.tf
@@ -0,0 +1,11 @@
+provider "aws" {
+  alias = "foo"
+  value = "config"
+}
+
+module "child" {
+  source = "./child"
+  providers = {
+    aws.bar = aws.foo
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provider-missing-grandchild/main.tf b/v1.5.7/internal/terraform/testdata/transform-provider-missing-grandchild/main.tf
new file mode 100644
index 0000000..385674a
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provider-missing-grandchild/main.tf
@@ -0,0 +1,3 @@
+module "sub" {
+    source = "./sub"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provider-missing-grandchild/sub/main.tf b/v1.5.7/internal/terraform/testdata/transform-provider-missing-grandchild/sub/main.tf
new file mode 100644
index 0000000..65adf2d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provider-missing-grandchild/sub/main.tf
@@ -0,0 +1,5 @@
+provider "foo" {}
+
+module "subsub" {
+    source = "./subsub"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provider-missing-grandchild/sub/subsub/main.tf b/v1.5.7/internal/terraform/testdata/transform-provider-missing-grandchild/sub/subsub/main.tf
new file mode 100644
index 0000000..fd865a5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provider-missing-grandchild/sub/subsub/main.tf
@@ -0,0 +1,2 @@
+resource "foo_instance" "one" {}
+resource "bar_instance" "two" {}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provider-missing/main.tf b/v1.5.7/internal/terraform/testdata/transform-provider-missing/main.tf
new file mode 100644
index 0000000..976f3e5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provider-missing/main.tf
@@ -0,0 +1,3 @@
+provider "aws" {}
+resource "aws_instance" "web" {}
+resource "foo_instance" "web" {}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provider-prune/main.tf b/v1.5.7/internal/terraform/testdata/transform-provider-prune/main.tf
new file mode 100644
index 0000000..986f884
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provider-prune/main.tf
@@ -0,0 +1,2 @@
+provider "aws" {}
+resource "foo_instance" "web" {}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provisioner-basic/main.tf b/v1.5.7/internal/terraform/testdata/transform-provisioner-basic/main.tf
new file mode 100644
index 0000000..3898ac4
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provisioner-basic/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "web" {
+    provisioner "shell" {}
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provisioner-module/child/main.tf b/v1.5.7/internal/terraform/testdata/transform-provisioner-module/child/main.tf
new file mode 100644
index 0000000..51b29c7
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provisioner-module/child/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+    provisioner "shell" {}
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-provisioner-module/main.tf b/v1.5.7/internal/terraform/testdata/transform-provisioner-module/main.tf
new file mode 100644
index 0000000..a825a44
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-provisioner-module/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+  provisioner "shell" {}
+}
+
+module "child" {
+  source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-root-basic/main.tf b/v1.5.7/internal/terraform/testdata/transform-root-basic/main.tf
new file mode 100644
index 0000000..e4ff4b3
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-root-basic/main.tf
@@ -0,0 +1,5 @@
+provider "aws" {}
+resource "aws_instance" "foo" {}
+
+provider "do" {}
+resource "do_droplet" "bar" {}
diff --git a/v1.5.7/internal/terraform/testdata/transform-targets-basic/main.tf b/v1.5.7/internal/terraform/testdata/transform-targets-basic/main.tf
new file mode 100644
index 0000000..47edc2a
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-targets-basic/main.tf
@@ -0,0 +1,22 @@
+resource "aws_vpc" "me" {}
+
+resource "aws_subnet" "me" {
+  depends_on = [
+    aws_vpc.me,
+  ]
+}
+
+resource "aws_instance" "me" {
+  depends_on = [
+    aws_subnet.me,
+  ]
+}
+
+resource "aws_vpc" "notme" {}
+resource "aws_subnet" "notme" {}
+resource "aws_instance" "notme" {}
+resource "aws_instance" "notmeeither" {
+  depends_on = [
+    aws_instance.me,
+  ]
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-targets-downstream/child/child.tf b/v1.5.7/internal/terraform/testdata/transform-targets-downstream/child/child.tf
new file mode 100644
index 0000000..6548b79
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-targets-downstream/child/child.tf
@@ -0,0 +1,14 @@
+resource "aws_instance" "foo" {
+}
+
+module "grandchild" {
+  source = "./grandchild"
+}
+
+output "id" {
+  value = "${aws_instance.foo.id}"
+}
+
+output "grandchild_id" {
+  value = "${module.grandchild.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-targets-downstream/child/grandchild/grandchild.tf b/v1.5.7/internal/terraform/testdata/transform-targets-downstream/child/grandchild/grandchild.tf
new file mode 100644
index 0000000..3ad8fd0
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-targets-downstream/child/grandchild/grandchild.tf
@@ -0,0 +1,6 @@
+resource "aws_instance" "foo" {
+}
+
+output "id" {
+  value = "${aws_instance.foo.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-targets-downstream/main.tf b/v1.5.7/internal/terraform/testdata/transform-targets-downstream/main.tf
new file mode 100644
index 0000000..b732fda
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-targets-downstream/main.tf
@@ -0,0 +1,18 @@
+resource "aws_instance" "foo" {
+}
+
+module "child" {
+  source = "./child"
+}
+
+output "root_id" {
+  value = "${aws_instance.foo.id}"
+}
+
+output "child_id" {
+  value = "${module.child.id}"
+}
+
+output "grandchild_id" {
+  value = "${module.child.grandchild_id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/transform-trans-reduce-basic/main.tf b/v1.5.7/internal/terraform/testdata/transform-trans-reduce-basic/main.tf
new file mode 100644
index 0000000..4fb97c7
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/transform-trans-reduce-basic/main.tf
@@ -0,0 +1,10 @@
+resource "aws_instance" "A" {}
+
+resource "aws_instance" "B" {
+    A = "${aws_instance.A.id}"
+}
+
+resource "aws_instance" "C" {
+    A = "${aws_instance.A.id}"
+    B = "${aws_instance.B.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/update-resource-provider/main.tf b/v1.5.7/internal/terraform/testdata/update-resource-provider/main.tf
new file mode 100644
index 0000000..6c082d5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/update-resource-provider/main.tf
@@ -0,0 +1,7 @@
+provider "aws" {
+  alias = "foo"
+}
+
+resource "aws_instance" "bar" {
+  provider = "aws.foo"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-bad-count/main.tf b/v1.5.7/internal/terraform/testdata/validate-bad-count/main.tf
new file mode 100644
index 0000000..a582e5e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-bad-count/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "foo" {
+  count = "${list}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-bad-module-output/child/main.tf b/v1.5.7/internal/terraform/testdata/validate-bad-module-output/child/main.tf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-bad-module-output/child/main.tf
diff --git a/v1.5.7/internal/terraform/testdata/validate-bad-module-output/main.tf b/v1.5.7/internal/terraform/testdata/validate-bad-module-output/main.tf
new file mode 100644
index 0000000..bda34f5
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-bad-module-output/main.tf
@@ -0,0 +1,7 @@
+module "child" {
+    source = "./child"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${module.child.bad}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-bad-pc/main.tf b/v1.5.7/internal/terraform/testdata/validate-bad-pc/main.tf
new file mode 100644
index 0000000..70ad701
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-bad-pc/main.tf
@@ -0,0 +1,5 @@
+provider "aws" {
+  foo = "bar"
+}
+
+resource "aws_instance" "test" {}
diff --git a/v1.5.7/internal/terraform/testdata/validate-bad-prov-conf/main.tf b/v1.5.7/internal/terraform/testdata/validate-bad-prov-conf/main.tf
new file mode 100644
index 0000000..af12124
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-bad-prov-conf/main.tf
@@ -0,0 +1,9 @@
+provider "aws" {
+  foo = "bar"
+}
+
+resource "aws_instance" "test" {
+  provisioner "shell" {
+    test_string = "foo"
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-bad-prov-connection/main.tf b/v1.5.7/internal/terraform/testdata/validate-bad-prov-connection/main.tf
new file mode 100644
index 0000000..550714f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-bad-prov-connection/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+  provisioner "shell" {
+    test_string = "test"
+    connection {
+      user = "test"
+    }
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-bad-rc/main.tf b/v1.5.7/internal/terraform/testdata/validate-bad-rc/main.tf
new file mode 100644
index 0000000..152a23e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-bad-rc/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "test" {
+    foo = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-bad-resource-connection/main.tf b/v1.5.7/internal/terraform/testdata/validate-bad-resource-connection/main.tf
new file mode 100644
index 0000000..46a1671
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-bad-resource-connection/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+  connection {
+    user = "test"
+  }
+  provisioner "shell" {
+    test_string = "test"
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-bad-resource-count/main.tf b/v1.5.7/internal/terraform/testdata/validate-bad-resource-count/main.tf
new file mode 100644
index 0000000..f852a44
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-bad-resource-count/main.tf
@@ -0,0 +1,22 @@
+// a resource named "aws_security_groups" does not exist in the schema
+variable "sg_ports" {
+  type        = list(number)
+  description = "List of ingress ports"
+  default     = [8200, 8201, 8300, 9200, 9500]
+}
+
+
+resource "aws_security_groups" "dynamicsg" {
+  name        = "dynamicsg"
+  description = "Ingress for Vault"
+
+  dynamic "ingress" {
+    for_each = var.sg_ports
+    content {
+      from_port   = ingress.value
+      to_port     = ingress.value
+      protocol    = "tcp"
+      cidr_blocks = ["0.0.0.0/0"]
+    }
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-bad-var/main.tf b/v1.5.7/internal/terraform/testdata/validate-bad-var/main.tf
new file mode 100644
index 0000000..5002845
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-bad-var/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "foo" {
+    num = "2"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${var.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-computed-in-function/main.tf b/v1.5.7/internal/terraform/testdata/validate-computed-in-function/main.tf
new file mode 100644
index 0000000..504e194
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-computed-in-function/main.tf
@@ -0,0 +1,7 @@
+data "aws_data_source" "foo" {
+    optional_attr = "value"
+}
+
+resource "aws_instance" "bar" {
+    attr = "${length(data.aws_data_source.foo.computed)}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-computed-module-var-ref/dest/main.tf b/v1.5.7/internal/terraform/testdata/validate-computed-module-var-ref/dest/main.tf
new file mode 100644
index 0000000..44095ea
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-computed-module-var-ref/dest/main.tf
@@ -0,0 +1,5 @@
+variable "destin" { }
+
+resource "aws_instance" "dest" {
+  attr = "${var.destin}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-computed-module-var-ref/main.tf b/v1.5.7/internal/terraform/testdata/validate-computed-module-var-ref/main.tf
new file mode 100644
index 0000000..d7c799c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-computed-module-var-ref/main.tf
@@ -0,0 +1,8 @@
+module "source" {
+  source = "./source"
+}
+
+module "dest" {
+  source = "./dest"
+  destin = "${module.source.sourceout}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-computed-module-var-ref/source/main.tf b/v1.5.7/internal/terraform/testdata/validate-computed-module-var-ref/source/main.tf
new file mode 100644
index 0000000..d2edc9e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-computed-module-var-ref/source/main.tf
@@ -0,0 +1,7 @@
+resource "aws_instance" "source" {
+  attr = "foo"
+}
+
+output "sourceout" {
+  value = "${aws_instance.source.attr}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-computed-var/main.tf b/v1.5.7/internal/terraform/testdata/validate-computed-var/main.tf
new file mode 100644
index 0000000..81acf7c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-computed-var/main.tf
@@ -0,0 +1,9 @@
+provider "aws" {
+    value = test_instance.foo.id
+}
+
+resource "aws_instance" "bar" {}
+
+resource "test_instance" "foo" {
+    value = "yes"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-count-computed/main.tf b/v1.5.7/internal/terraform/testdata/validate-count-computed/main.tf
new file mode 100644
index 0000000..e7de125
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-count-computed/main.tf
@@ -0,0 +1,7 @@
+data "aws_data_source" "foo" {
+    compute = "value"
+}
+
+resource "aws_instance" "bar" {
+    count = "${data.aws_data_source.foo.value}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-count-negative/main.tf b/v1.5.7/internal/terraform/testdata/validate-count-negative/main.tf
new file mode 100644
index 0000000..d5bb046
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-count-negative/main.tf
@@ -0,0 +1,3 @@
+resource "aws_instance" "test" {
+    count = "-5"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-count-variable/main.tf b/v1.5.7/internal/terraform/testdata/validate-count-variable/main.tf
new file mode 100644
index 0000000..9c892ac
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-count-variable/main.tf
@@ -0,0 +1,6 @@
+variable "foo" {}
+
+resource "aws_instance" "foo" {
+    foo = "foo"
+    count = "${var.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-good-module/child/main.tf b/v1.5.7/internal/terraform/testdata/validate-good-module/child/main.tf
new file mode 100644
index 0000000..17d8c60
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-good-module/child/main.tf
@@ -0,0 +1,3 @@
+output "good" {
+    value = "great"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-good-module/main.tf b/v1.5.7/internal/terraform/testdata/validate-good-module/main.tf
new file mode 100644
index 0000000..439d202
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-good-module/main.tf
@@ -0,0 +1,7 @@
+module "child" {
+    source = "./child"
+}
+
+resource "aws_instance" "bar" {
+    foo = "${module.child.good}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-good/main.tf b/v1.5.7/internal/terraform/testdata/validate-good/main.tf
new file mode 100644
index 0000000..fe44019
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-good/main.tf
@@ -0,0 +1,8 @@
+resource "aws_instance" "foo" {
+    num = "2"
+    foo = "bar"
+}
+
+resource "aws_instance" "bar" {
+    foo = "bar"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-module-bad-rc/child/main.tf b/v1.5.7/internal/terraform/testdata/validate-module-bad-rc/child/main.tf
new file mode 100644
index 0000000..919f140
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-module-bad-rc/child/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/validate-module-bad-rc/main.tf b/v1.5.7/internal/terraform/testdata/validate-module-bad-rc/main.tf
new file mode 100644
index 0000000..0f6991c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-module-bad-rc/main.tf
@@ -0,0 +1,3 @@
+module "child" {
+    source = "./child"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-module-deps-cycle/a/main.tf b/v1.5.7/internal/terraform/testdata/validate-module-deps-cycle/a/main.tf
new file mode 100644
index 0000000..3d3b016
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-module-deps-cycle/a/main.tf
@@ -0,0 +1,5 @@
+resource "aws_instance" "a" { }
+
+output "output" {
+  value = "${aws_instance.a.id}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-module-deps-cycle/b/main.tf b/v1.5.7/internal/terraform/testdata/validate-module-deps-cycle/b/main.tf
new file mode 100644
index 0000000..0f8fc91
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-module-deps-cycle/b/main.tf
@@ -0,0 +1,5 @@
+variable "input" {}
+
+resource "aws_instance" "b" {
+  id = "${var.input}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-module-deps-cycle/main.tf b/v1.5.7/internal/terraform/testdata/validate-module-deps-cycle/main.tf
new file mode 100644
index 0000000..11ddb64
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-module-deps-cycle/main.tf
@@ -0,0 +1,8 @@
+module "a" {
+  source = "./a"
+}
+
+module "b" {
+  source = "./b"
+  input = "${module.a.output}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-module-pc-inherit-unused/child/main.tf b/v1.5.7/internal/terraform/testdata/validate-module-pc-inherit-unused/child/main.tf
new file mode 100644
index 0000000..919f140
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-module-pc-inherit-unused/child/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/validate-module-pc-inherit-unused/main.tf b/v1.5.7/internal/terraform/testdata/validate-module-pc-inherit-unused/main.tf
new file mode 100644
index 0000000..32c8a38
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-module-pc-inherit-unused/main.tf
@@ -0,0 +1,7 @@
+module "child" {
+    source = "./child"
+}
+
+provider "aws" {
+    foo = "set"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-module-pc-inherit/child/main.tf b/v1.5.7/internal/terraform/testdata/validate-module-pc-inherit/child/main.tf
new file mode 100644
index 0000000..37189c1
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-module-pc-inherit/child/main.tf
@@ -0,0 +1,3 @@
+provider "aws" {}
+
+resource "aws_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/validate-module-pc-inherit/main.tf b/v1.5.7/internal/terraform/testdata/validate-module-pc-inherit/main.tf
new file mode 100644
index 0000000..8976f4a
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-module-pc-inherit/main.tf
@@ -0,0 +1,9 @@
+module "child" {
+    source = "./child"
+}
+
+provider "aws" {
+    set = true
+}
+
+resource "aws_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/validate-module-pc-vars/child/main.tf b/v1.5.7/internal/terraform/testdata/validate-module-pc-vars/child/main.tf
new file mode 100644
index 0000000..380cd46
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-module-pc-vars/child/main.tf
@@ -0,0 +1,7 @@
+variable "value" {}
+
+provider "aws" {
+    foo = var.value
+}
+
+resource "aws_instance" "foo" {}
diff --git a/v1.5.7/internal/terraform/testdata/validate-module-pc-vars/main.tf b/v1.5.7/internal/terraform/testdata/validate-module-pc-vars/main.tf
new file mode 100644
index 0000000..5e239b4
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-module-pc-vars/main.tf
@@ -0,0 +1,7 @@
+variable "provider_var" {}
+
+module "child" {
+    source = "./child"
+
+    value = var.provider_var
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-required-provider-config/main.tf b/v1.5.7/internal/terraform/testdata/validate-required-provider-config/main.tf
new file mode 100644
index 0000000..898a23f
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-required-provider-config/main.tf
@@ -0,0 +1,20 @@
+# This test verifies that the provider local name, local config and fqn map
+# together properly when the local name does not match the type.
+
+terraform {
+  required_providers {
+    arbitrary = {
+      source = "hashicorp/aws"
+    }
+  }
+}
+
+# hashicorp/test has required provider config attributes. This "arbitrary"
+# provider configuration block should map to hashicorp/test.
+provider "arbitrary" {
+  required_attribute = "bloop"
+}
+
+resource "aws_instance" "test" {
+  provider = "arbitrary"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-required-var/main.tf b/v1.5.7/internal/terraform/testdata/validate-required-var/main.tf
new file mode 100644
index 0000000..bd55ea1
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-required-var/main.tf
@@ -0,0 +1,5 @@
+variable "foo" {}
+
+resource "aws_instance" "web" {
+  ami = "${var.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-sensitive-provisioner-config/main.tf b/v1.5.7/internal/terraform/testdata/validate-sensitive-provisioner-config/main.tf
new file mode 100644
index 0000000..88a3727
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-sensitive-provisioner-config/main.tf
@@ -0,0 +1,11 @@
+variable "secret" {
+  type      = string
+  default   = " password123"
+  sensitive = true
+}
+
+resource "aws_instance" "foo" {
+  provisioner "test" {
+    test_string = var.secret
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-skipped-pc-empty/main.tf b/v1.5.7/internal/terraform/testdata/validate-skipped-pc-empty/main.tf
new file mode 100644
index 0000000..1ad9ade
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-skipped-pc-empty/main.tf
@@ -0,0 +1 @@
+resource "aws_instance" "test" {}
diff --git a/v1.5.7/internal/terraform/testdata/validate-targeted/main.tf b/v1.5.7/internal/terraform/testdata/validate-targeted/main.tf
new file mode 100644
index 0000000..a1e847d
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-targeted/main.tf
@@ -0,0 +1,9 @@
+resource "aws_instance" "foo" {
+  num         = "2"
+  provisioner "shell"     {}
+}
+
+resource "aws_instance" "bar" {
+  foo         = "bar"
+  provisioner "shell"     {}
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-var-no-default-explicit-type/main.tf b/v1.5.7/internal/terraform/testdata/validate-var-no-default-explicit-type/main.tf
new file mode 100644
index 0000000..5953eab
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-var-no-default-explicit-type/main.tf
@@ -0,0 +1,5 @@
+variable "maybe_a_map" {
+  type = map(string)
+
+  // No default
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-variable-custom-validations-child-sensitive/child/child.tf b/v1.5.7/internal/terraform/testdata/validate-variable-custom-validations-child-sensitive/child/child.tf
new file mode 100644
index 0000000..05027f7
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-variable-custom-validations-child-sensitive/child/child.tf
@@ -0,0 +1,8 @@
+variable "test" {
+  type = string
+
+  validation {
+    condition     = var.test != "nope"
+    error_message = "Value must not be \"nope\"."
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-variable-custom-validations-child-sensitive/validate-variable-custom-validations.tf b/v1.5.7/internal/terraform/testdata/validate-variable-custom-validations-child-sensitive/validate-variable-custom-validations.tf
new file mode 100644
index 0000000..4f436db
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-variable-custom-validations-child-sensitive/validate-variable-custom-validations.tf
@@ -0,0 +1,10 @@
+variable "test" {
+  sensitive = true
+  default = "nope"
+}
+
+module "child" {
+  source = "./child"
+
+  test = var.test
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-variable-custom-validations-child/child/child.tf b/v1.5.7/internal/terraform/testdata/validate-variable-custom-validations-child/child/child.tf
new file mode 100644
index 0000000..05027f7
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-variable-custom-validations-child/child/child.tf
@@ -0,0 +1,8 @@
+variable "test" {
+  type = string
+
+  validation {
+    condition     = var.test != "nope"
+    error_message = "Value must not be \"nope\"."
+  }
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-variable-custom-validations-child/validate-variable-custom-validations.tf b/v1.5.7/internal/terraform/testdata/validate-variable-custom-validations-child/validate-variable-custom-validations.tf
new file mode 100644
index 0000000..8b8111e
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-variable-custom-validations-child/validate-variable-custom-validations.tf
@@ -0,0 +1,5 @@
+module "child" {
+  source = "./child"
+
+  test = "nope"
+}
diff --git a/v1.5.7/internal/terraform/testdata/validate-variable-ref/main.tf b/v1.5.7/internal/terraform/testdata/validate-variable-ref/main.tf
new file mode 100644
index 0000000..3bc9860
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/validate-variable-ref/main.tf
@@ -0,0 +1,5 @@
+variable "foo" {}
+
+resource "aws_instance" "bar" {
+    foo = "${var.foo}"
+}
diff --git a/v1.5.7/internal/terraform/testdata/vars-basic-bool/main.tf b/v1.5.7/internal/terraform/testdata/vars-basic-bool/main.tf
new file mode 100644
index 0000000..52d9059
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/vars-basic-bool/main.tf
@@ -0,0 +1,10 @@
+// At the time of writing Terraform doesn't formally support a boolean
+// type, but historically this has magically worked. Lots of TF code
+// relies on this so we test it now.
+variable "a" {
+    default = true
+}
+
+variable "b" {
+    default = false
+}
diff --git a/v1.5.7/internal/terraform/testdata/vars-basic/main.tf b/v1.5.7/internal/terraform/testdata/vars-basic/main.tf
new file mode 100644
index 0000000..af3ba5c
--- /dev/null
+++ b/v1.5.7/internal/terraform/testdata/vars-basic/main.tf
@@ -0,0 +1,14 @@
+variable "a" {
+  default = "foo"
+  type    = string
+}
+
+variable "b" {
+  default = []
+  type    = list(string)
+}
+
+variable "c" {
+  default = {}
+  type    = map(string)
+}
diff --git a/v1.5.7/internal/terraform/transform.go b/v1.5.7/internal/terraform/transform.go
new file mode 100644
index 0000000..53040d5
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform.go
@@ -0,0 +1,55 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/logging"
+)
+
+// GraphTransformer is the interface that transformers implement. This
+// interface is only for transforms that need entire graph visibility.
+type GraphTransformer interface {
+	Transform(*Graph) error
+}
+
+// GraphVertexTransformer is an interface that transforms a single
+// Vertex within with graph. This is a specialization of GraphTransformer
+// that makes it easy to do vertex replacement.
+//
+// The GraphTransformer that runs through the GraphVertexTransformers is
+// VertexTransformer.
+type GraphVertexTransformer interface {
+	Transform(dag.Vertex) (dag.Vertex, error)
+}
+
+type graphTransformerMulti struct {
+	Transforms []GraphTransformer
+}
+
+func (t *graphTransformerMulti) Transform(g *Graph) error {
+	var lastStepStr string
+	for _, t := range t.Transforms {
+		log.Printf("[TRACE] (graphTransformerMulti) Executing graph transform %T", t)
+		if err := t.Transform(g); err != nil {
+			return err
+		}
+		if thisStepStr := g.StringWithNodeTypes(); thisStepStr != lastStepStr {
+			log.Printf("[TRACE] (graphTransformerMulti) Completed graph transform %T with new graph:\n%s  ------", t, logging.Indent(thisStepStr))
+			lastStepStr = thisStepStr
+		} else {
+			log.Printf("[TRACE] (graphTransformerMulti) Completed graph transform %T (no changes)", t)
+		}
+	}
+
+	return nil
+}
+
+// GraphTransformMulti combines multiple graph transformers into a single
+// GraphTransformer that runs all the individual graph transformers.
+func GraphTransformMulti(ts ...GraphTransformer) GraphTransformer {
+	return &graphTransformerMulti{Transforms: ts}
+}
diff --git a/v1.5.7/internal/terraform/transform_attach_config_provider.go b/v1.5.7/internal/terraform/transform_attach_config_provider.go
new file mode 100644
index 0000000..e42094f
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_attach_config_provider.go
@@ -0,0 +1,19 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+)
+
+// GraphNodeAttachProvider is an interface that must be implemented by nodes
+// that want provider configurations attached.
+type GraphNodeAttachProvider interface {
+	// ProviderName with no module prefix. Example: "aws".
+	ProviderAddr() addrs.AbsProviderConfig
+
+	// Sets the configuration
+	AttachProvider(*configs.Provider)
+}
diff --git a/v1.5.7/internal/terraform/transform_attach_config_provider_meta.go b/v1.5.7/internal/terraform/transform_attach_config_provider_meta.go
new file mode 100644
index 0000000..b08dcfd
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_attach_config_provider_meta.go
@@ -0,0 +1,18 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+)
+
+// GraphNodeAttachProviderMetaConfigs is an interface that must be implemented
+// by nodes that want provider meta configurations attached.
+type GraphNodeAttachProviderMetaConfigs interface {
+	GraphNodeConfigResource
+
+	// Sets the configuration
+	AttachProviderMetaConfigs(map[addrs.Provider]*configs.ProviderMeta)
+}
diff --git a/v1.5.7/internal/terraform/transform_attach_config_resource.go b/v1.5.7/internal/terraform/transform_attach_config_resource.go
new file mode 100644
index 0000000..c3c4930
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_attach_config_resource.go
@@ -0,0 +1,113 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+// GraphNodeAttachResourceConfig is an interface that must be implemented by nodes
+// that want resource configurations attached.
+type GraphNodeAttachResourceConfig interface {
+	GraphNodeConfigResource
+
+	// Sets the configuration
+	AttachResourceConfig(*configs.Resource)
+}
+
+// AttachResourceConfigTransformer goes through the graph and attaches
+// resource configuration structures to nodes that implement
+// GraphNodeAttachManagedResourceConfig or GraphNodeAttachDataResourceConfig.
+//
+// The attached configuration structures are directly from the configuration.
+// If they're going to be modified, a copy should be made.
+type AttachResourceConfigTransformer struct {
+	Config *configs.Config // Config is the root node in the config tree
+}
+
+func (t *AttachResourceConfigTransformer) Transform(g *Graph) error {
+
+	// Go through and find GraphNodeAttachResource
+	for _, v := range g.Vertices() {
+		// Only care about GraphNodeAttachResource implementations
+		arn, ok := v.(GraphNodeAttachResourceConfig)
+		if !ok {
+			continue
+		}
+
+		// Determine what we're looking for
+		addr := arn.ResourceAddr()
+
+		// Get the configuration.
+		config := t.Config.Descendent(addr.Module)
+		if config == nil {
+			log.Printf("[TRACE] AttachResourceConfigTransformer: %q (%T) has no configuration available", dag.VertexName(v), v)
+			continue
+		}
+
+		for _, r := range config.Module.ManagedResources {
+			rAddr := r.Addr()
+
+			if rAddr != addr.Resource {
+				// Not the same resource
+				continue
+			}
+
+			log.Printf("[TRACE] AttachResourceConfigTransformer: attaching to %q (%T) config from %s", dag.VertexName(v), v, r.DeclRange)
+			arn.AttachResourceConfig(r)
+
+			// attach the provider_meta info
+			if gnapmc, ok := v.(GraphNodeAttachProviderMetaConfigs); ok {
+				log.Printf("[TRACE] AttachResourceConfigTransformer: attaching provider meta configs to %s", dag.VertexName(v))
+				if config == nil {
+					log.Printf("[TRACE] AttachResourceConfigTransformer: no config set on the transformer for %s", dag.VertexName(v))
+					continue
+				}
+				if config.Module == nil {
+					log.Printf("[TRACE] AttachResourceConfigTransformer: no module in config for %s", dag.VertexName(v))
+					continue
+				}
+				if config.Module.ProviderMetas == nil {
+					log.Printf("[TRACE] AttachResourceConfigTransformer: no provider metas defined for %s", dag.VertexName(v))
+					continue
+				}
+				gnapmc.AttachProviderMetaConfigs(config.Module.ProviderMetas)
+			}
+		}
+		for _, r := range config.Module.DataResources {
+			rAddr := r.Addr()
+
+			if rAddr != addr.Resource {
+				// Not the same resource
+				continue
+			}
+
+			log.Printf("[TRACE] AttachResourceConfigTransformer: attaching to %q (%T) config from %#v", dag.VertexName(v), v, r.DeclRange)
+			arn.AttachResourceConfig(r)
+
+			// attach the provider_meta info
+			if gnapmc, ok := v.(GraphNodeAttachProviderMetaConfigs); ok {
+				log.Printf("[TRACE] AttachResourceConfigTransformer: attaching provider meta configs to %s", dag.VertexName(v))
+				if config == nil {
+					log.Printf("[TRACE] AttachResourceConfigTransformer: no config set on the transformer for %s", dag.VertexName(v))
+					continue
+				}
+				if config.Module == nil {
+					log.Printf("[TRACE] AttachResourceConfigTransformer: no module in config for %s", dag.VertexName(v))
+					continue
+				}
+				if config.Module.ProviderMetas == nil {
+					log.Printf("[TRACE] AttachResourceConfigTransformer: no provider metas defined for %s", dag.VertexName(v))
+					continue
+				}
+				gnapmc.AttachProviderMetaConfigs(config.Module.ProviderMetas)
+			}
+		}
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_attach_schema.go b/v1.5.7/internal/terraform/transform_attach_schema.go
new file mode 100644
index 0000000..e442051
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_attach_schema.go
@@ -0,0 +1,112 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+// GraphNodeAttachResourceSchema is an interface implemented by node types
+// that need a resource schema attached.
+type GraphNodeAttachResourceSchema interface {
+	GraphNodeConfigResource
+	GraphNodeProviderConsumer
+
+	AttachResourceSchema(schema *configschema.Block, version uint64)
+}
+
+// GraphNodeAttachProviderConfigSchema is an interface implemented by node types
+// that need a provider configuration schema attached.
+type GraphNodeAttachProviderConfigSchema interface {
+	GraphNodeProvider
+
+	AttachProviderConfigSchema(*configschema.Block)
+}
+
+// GraphNodeAttachProvisionerSchema is an interface implemented by node types
+// that need one or more provisioner schemas attached.
+type GraphNodeAttachProvisionerSchema interface {
+	ProvisionedBy() []string
+
+	// SetProvisionerSchema is called during transform for each provisioner
+	// type returned from ProvisionedBy, providing the configuration schema
+	// for each provisioner in turn. The implementer should save these for
+	// later use in evaluating provisioner configuration blocks.
+	AttachProvisionerSchema(name string, schema *configschema.Block)
+}
+
+// AttachSchemaTransformer finds nodes that implement
+// GraphNodeAttachResourceSchema, GraphNodeAttachProviderConfigSchema, or
+// GraphNodeAttachProvisionerSchema, looks up the needed schemas for each
+// and then passes them to a method implemented by the node.
+type AttachSchemaTransformer struct {
+	Plugins *contextPlugins
+	Config  *configs.Config
+}
+
+func (t *AttachSchemaTransformer) Transform(g *Graph) error {
+	if t.Plugins == nil {
+		// Should never happen with a reasonable caller, but we'll return a
+		// proper error here anyway so that we'll fail gracefully.
+		return fmt.Errorf("AttachSchemaTransformer used with nil Plugins")
+	}
+
+	for _, v := range g.Vertices() {
+
+		if tv, ok := v.(GraphNodeAttachResourceSchema); ok {
+			addr := tv.ResourceAddr()
+			mode := addr.Resource.Mode
+			typeName := addr.Resource.Type
+			providerFqn := tv.Provider()
+
+			schema, version, err := t.Plugins.ResourceTypeSchema(providerFqn, mode, typeName)
+			if err != nil {
+				return fmt.Errorf("failed to read schema for %s in %s: %s", addr, providerFqn, err)
+			}
+			if schema == nil {
+				log.Printf("[ERROR] AttachSchemaTransformer: No resource schema available for %s", addr)
+				continue
+			}
+			log.Printf("[TRACE] AttachSchemaTransformer: attaching resource schema to %s", dag.VertexName(v))
+			tv.AttachResourceSchema(schema, version)
+		}
+
+		if tv, ok := v.(GraphNodeAttachProviderConfigSchema); ok {
+			providerAddr := tv.ProviderAddr()
+			schema, err := t.Plugins.ProviderConfigSchema(providerAddr.Provider)
+			if err != nil {
+				return fmt.Errorf("failed to read provider configuration schema for %s: %s", providerAddr.Provider, err)
+			}
+			if schema == nil {
+				log.Printf("[ERROR] AttachSchemaTransformer: No provider config schema available for %s", providerAddr)
+				continue
+			}
+			log.Printf("[TRACE] AttachSchemaTransformer: attaching provider config schema to %s", dag.VertexName(v))
+			tv.AttachProviderConfigSchema(schema)
+		}
+
+		if tv, ok := v.(GraphNodeAttachProvisionerSchema); ok {
+			names := tv.ProvisionedBy()
+			for _, name := range names {
+				schema, err := t.Plugins.ProvisionerSchema(name)
+				if err != nil {
+					return fmt.Errorf("failed to read provisioner configuration schema for %q: %s", name, err)
+				}
+				if schema == nil {
+					log.Printf("[ERROR] AttachSchemaTransformer: No schema available for provisioner %q on %q", name, dag.VertexName(v))
+					continue
+				}
+				log.Printf("[TRACE] AttachSchemaTransformer: attaching provisioner %q config schema to %s", name, dag.VertexName(v))
+				tv.AttachProvisionerSchema(name, schema)
+			}
+		}
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_attach_state.go b/v1.5.7/internal/terraform/transform_attach_state.go
new file mode 100644
index 0000000..1ebeac2
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_attach_state.go
@@ -0,0 +1,71 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// GraphNodeAttachResourceState is an interface that can be implemented
+// to request that a ResourceState is attached to the node.
+//
+// Due to a historical naming inconsistency, the type ResourceState actually
+// represents the state for a particular _instance_, while InstanceState
+// represents the values for that instance during a particular phase
+// (e.g. primary vs. deposed). Consequently, GraphNodeAttachResourceState
+// is supported only for nodes that represent resource instances, even though
+// the name might suggest it is for containing resources.
+type GraphNodeAttachResourceState interface {
+	GraphNodeResourceInstance
+
+	// Sets the state
+	AttachResourceState(*states.Resource)
+}
+
+// AttachStateTransformer goes through the graph and attaches
+// state to nodes that implement the interfaces above.
+type AttachStateTransformer struct {
+	State *states.State // State is the root state
+}
+
+func (t *AttachStateTransformer) Transform(g *Graph) error {
+	// If no state, then nothing to do
+	if t.State == nil {
+		log.Printf("[DEBUG] Not attaching any node states: overall state is nil")
+		return nil
+	}
+
+	for _, v := range g.Vertices() {
+		// Nodes implement this interface to request state attachment.
+		an, ok := v.(GraphNodeAttachResourceState)
+		if !ok {
+			continue
+		}
+		addr := an.ResourceInstanceAddr()
+
+		rs := t.State.Resource(addr.ContainingResource())
+		if rs == nil {
+			log.Printf("[DEBUG] Resource state not found for node %q, instance %s", dag.VertexName(v), addr)
+			continue
+		}
+
+		is := rs.Instance(addr.Resource.Key)
+		if is == nil {
+			// We don't actually need this here, since we'll attach the whole
+			// resource state, but we still check because it'd be weird
+			// for the specific instance we're attaching to not to exist.
+			log.Printf("[DEBUG] Resource instance state not found for node %q, instance %s", dag.VertexName(v), addr)
+			continue
+		}
+
+		// make sure to attach a copy of the state, so instances can modify the
+		// same ResourceState.
+		an.AttachResourceState(rs.DeepCopy())
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_check.go b/v1.5.7/internal/terraform/transform_check.go
new file mode 100644
index 0000000..a3f3bec
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_check.go
@@ -0,0 +1,145 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+type checkTransformer struct {
+	// Config for the entire module.
+	Config *configs.Config
+
+	// Operation is the current operation this node will be part of.
+	Operation walkOperation
+}
+
+var _ GraphTransformer = (*checkTransformer)(nil)
+
+func (t *checkTransformer) Transform(graph *Graph) error {
+	return t.transform(graph, t.Config, graph.Vertices())
+}
+
+func (t *checkTransformer) transform(g *Graph, cfg *configs.Config, allNodes []dag.Vertex) error {
+
+	if t.Operation == walkDestroy || t.Operation == walkPlanDestroy {
+		// Don't include anything about checks during destroy operations.
+		//
+		// For other plan and normal apply operations we do everything, for
+		// destroy operations we do nothing. For any other operations we still
+		// include the check nodes, but we don't actually execute the checks
+		// instead we still validate their references and make sure their
+		// conditions make sense etc.
+		return nil
+	}
+
+	moduleAddr := cfg.Path
+
+	for _, check := range cfg.Module.Checks {
+		configAddr := check.Addr().InModule(moduleAddr)
+
+		// We want to create a node for each check block. This node will execute
+		// after anything it references, and will update the checks object
+		// embedded in the plan and/or state.
+
+		log.Printf("[TRACE] checkTransformer: Nodes and edges for %s", configAddr)
+		expand := &nodeExpandCheck{
+			addr:   configAddr,
+			config: check,
+			makeInstance: func(addr addrs.AbsCheck, cfg *configs.Check) dag.Vertex {
+				return &nodeCheckAssert{
+					addr:          addr,
+					config:        cfg,
+					executeChecks: t.ExecuteChecks(),
+				}
+			},
+		}
+		g.Add(expand)
+
+		// We also need to report the checks we are going to execute before we
+		// try and execute them.
+		if t.ReportChecks() {
+			report := &nodeReportCheck{
+				addr: configAddr,
+			}
+			g.Add(report)
+
+			// Make sure we report our checks before we start executing the
+			// actual checks.
+			g.Connect(dag.BasicEdge(expand, report))
+
+			if check.DataResource != nil {
+				// If we have a nested data source, we need to make sure we
+				// also report the check before the data source executes.
+				//
+				// We loop through all the nodes in the graph to find the one
+				// that contains our data source and connect it.
+				for _, other := range allNodes {
+					if resource, isResource := other.(GraphNodeConfigResource); isResource {
+						resourceAddr := resource.ResourceAddr()
+						if !resourceAddr.Module.Equal(moduleAddr) {
+							// This resource isn't in the same module as our check
+							// so skip it.
+							continue
+						}
+
+						resourceCfg := cfg.Module.ResourceByAddr(resourceAddr.Resource)
+						if resourceCfg != nil && resourceCfg.Container != nil && resourceCfg.Container.Accessible(check.Addr()) {
+							// Make sure we report our checks before we execute any
+							// embedded data resource.
+							g.Connect(dag.BasicEdge(other, report))
+
+							// There's at most one embedded data source, and
+							// we've found it so stop looking.
+							break
+						}
+					}
+				}
+			}
+		}
+	}
+
+	for _, child := range cfg.Children {
+		if err := t.transform(g, child, allNodes); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// ReportChecks returns true if this operation should report any check blocks
+// that it is about to execute.
+//
+// This is true for planning operations, as apply operations recreate the
+// expected checks from the plan.
+//
+// We'll also report the checks during an import operation. We still execute
+// our check blocks during an import operation so they need to be reported
+// first.
+func (t *checkTransformer) ReportChecks() bool {
+	return t.Operation == walkPlan || t.Operation == walkImport
+}
+
+// ExecuteChecks returns true if this operation should actually execute any
+// check blocks in the config.
+//
+// If this returns false we will still create and execute check nodes in the
+// graph, but they will only validate things like references and syntax.
+func (t *checkTransformer) ExecuteChecks() bool {
+	switch t.Operation {
+	case walkPlan, walkApply, walkImport:
+		// We only actually execute the checks for plan and apply operations.
+		return true
+	default:
+		// For everything else, we still want to validate the checks make sense
+		// logically and syntactically, but we won't actually resolve the check
+		// conditions.
+		return false
+	}
+}
diff --git a/v1.5.7/internal/terraform/transform_check_starter.go b/v1.5.7/internal/terraform/transform_check_starter.go
new file mode 100644
index 0000000..d836107
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_check_starter.go
@@ -0,0 +1,126 @@
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+var _ GraphTransformer = (*checkStartTransformer)(nil)
+
+// checkStartTransformer checks if the configuration has any data blocks nested
+// within check blocks, and if it does then it introduces a nodeCheckStart
+// vertex that ensures all resources have been applied before it starts loading
+// the nested data sources.
+type checkStartTransformer struct {
+	// Config for the entire module.
+	Config *configs.Config
+
+	// Operation is the current operation this node will be part of.
+	Operation walkOperation
+}
+
+func (s *checkStartTransformer) Transform(graph *Graph) error {
+	if s.Operation != walkApply && s.Operation != walkPlan {
+		// We only actually execute the checks during plan apply operations
+		// so if we are doing something else we can just skip this and
+		// leave the graph alone.
+		return nil
+	}
+
+	var resources []dag.Vertex
+	var nested []dag.Vertex
+
+	// We're going to step through all the vertices and pull out the relevant
+	// resources and data sources.
+	for _, vertex := range graph.Vertices() {
+		if node, isResource := vertex.(GraphNodeCreator); isResource {
+			addr := node.CreateAddr()
+
+			if addr.Resource.Resource.Mode == addrs.ManagedResourceMode {
+				// This is a resource, so we want to make sure it executes
+				// before any nested data sources.
+
+				// We can reduce the number of additional edges we write into
+				// the graph by only including "leaf" resources, that is
+				// resources that aren't referenced by other resources. If a
+				// resource is referenced by another resource then we know that
+				// it will execute before that resource so we only need to worry
+				// about the referencing resource.
+
+				leafResource := true
+				for _, other := range graph.UpEdges(vertex) {
+					if otherResource, isResource := other.(GraphNodeCreator); isResource {
+						otherAddr := otherResource.CreateAddr()
+						if otherAddr.Resource.Resource.Mode == addrs.ManagedResourceMode {
+							// Then this resource is being referenced so skip
+							// it.
+							leafResource = false
+							break
+						}
+					}
+				}
+
+				if leafResource {
+					resources = append(resources, vertex)
+				}
+
+				// We've handled the resource so move to the next vertex.
+				continue
+			}
+
+			// Now, we know we are processing a data block.
+
+			config := s.Config
+			if !addr.Module.IsRoot() {
+				config = s.Config.Descendent(addr.Module.Module())
+			}
+			if config == nil {
+				// might have been deleted, so it won't be subject to any checks
+				// anyway.
+				continue
+			}
+
+			resource := config.Module.ResourceByAddr(addr.Resource.Resource)
+			if resource == nil {
+				// might have been deleted, so it won't be subject to any checks
+				// anyway.
+				continue
+			}
+
+			if _, ok := resource.Container.(*configs.Check); ok {
+				// Then this is a data source within a check block, so let's
+				// make a note of it.
+				nested = append(nested, vertex)
+			}
+
+			// Otherwise, it's just a normal data source. From a check block we
+			// don't really care when Terraform is loading non-nested data
+			// sources so we'll just forget about it and move on.
+		}
+	}
+
+	if len(nested) > 0 {
+
+		// We don't need to do any of this if we don't have any nested data
+		// sources, so we check that first.
+		//
+		// Otherwise we introduce a vertex that can act as a pauser between
+		// our nested data sources and leaf resources.
+
+		check := &nodeCheckStart{}
+		graph.Add(check)
+
+		// Finally, connect everything up so it all executes in order.
+
+		for _, vertex := range nested {
+			graph.Connect(dag.BasicEdge(vertex, check))
+		}
+
+		for _, vertex := range resources {
+			graph.Connect(dag.BasicEdge(check, vertex))
+		}
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_config.go b/v1.5.7/internal/terraform/transform_config.go
new file mode 100644
index 0000000..7d9aadb
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_config.go
@@ -0,0 +1,195 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+// ConfigTransformer is a GraphTransformer that adds all the resources
+// from the configuration to the graph.
+//
+// The module used to configure this transformer must be the root module.
+//
+// Only resources are added to the graph. Variables, outputs, and
+// providers must be added via other transforms.
+//
+// Unlike ConfigTransformerOld, this transformer creates a graph with
+// all resources including module resources, rather than creating module
+// nodes that are then "flattened".
+type ConfigTransformer struct {
+	Concrete ConcreteResourceNodeFunc
+
+	// Module is the module to add resources from.
+	Config *configs.Config
+
+	// Mode will only add resources that match the given mode
+	ModeFilter bool
+	Mode       addrs.ResourceMode
+
+	// Do not apply this transformer.
+	skip bool
+
+	// importTargets specifies a slice of addresses that will have state
+	// imported for them.
+	importTargets []*ImportTarget
+
+	// generateConfigPathForImportTargets tells the graph where to write any
+	// generated config for import targets that are not contained within config.
+	//
+	// If this is empty and an import target has no config, the graph will
+	// simply import the state for the target and any follow-up operations will
+	// try to delete the imported resource unless the config is updated
+	// manually.
+	generateConfigPathForImportTargets string
+}
+
+func (t *ConfigTransformer) Transform(g *Graph) error {
+	if t.skip {
+		return nil
+	}
+
+	// If no configuration is available, we don't do anything
+	if t.Config == nil {
+		return nil
+	}
+
+	// Start the transformation process
+	return t.transform(g, t.Config, t.generateConfigPathForImportTargets)
+}
+
+func (t *ConfigTransformer) transform(g *Graph, config *configs.Config, generateConfigPath string) error {
+	// If no config, do nothing
+	if config == nil {
+		return nil
+	}
+
+	// Add our resources
+	if err := t.transformSingle(g, config, generateConfigPath); err != nil {
+		return err
+	}
+
+	// Transform all the children without generating config.
+	for _, c := range config.Children {
+		if err := t.transform(g, c, ""); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config, generateConfigPath string) error {
+	path := config.Path
+	module := config.Module
+	log.Printf("[TRACE] ConfigTransformer: Starting for path: %v", path)
+
+	allResources := make([]*configs.Resource, 0, len(module.ManagedResources)+len(module.DataResources))
+	for _, r := range module.ManagedResources {
+		allResources = append(allResources, r)
+	}
+	for _, r := range module.DataResources {
+		allResources = append(allResources, r)
+	}
+
+	// Take a copy of the import targets, so we can edit them as we go.
+	// Only include import targets that are targeting the current module.
+	var importTargets []*ImportTarget
+	for _, target := range t.importTargets {
+		if targetModule := target.Addr.Module.Module(); targetModule.Equal(config.Path) {
+			importTargets = append(importTargets, target)
+		}
+	}
+
+	for _, r := range allResources {
+		relAddr := r.Addr()
+
+		if t.ModeFilter && relAddr.Mode != t.Mode {
+			// Skip non-matching modes
+			continue
+		}
+
+		// If any of the import targets can apply to this node's instances,
+		// filter them down to the applicable addresses.
+		var imports []*ImportTarget
+		configAddr := relAddr.InModule(path)
+
+		var matchedIndices []int
+		for ix, i := range importTargets {
+			if target := i.Addr.ContainingResource().Config(); target.Equal(configAddr) {
+				// This import target has been claimed by an actual resource,
+				// let's make a note of this to remove it from the targets.
+				matchedIndices = append(matchedIndices, ix)
+				imports = append(imports, i)
+			}
+		}
+
+		for ix := len(matchedIndices) - 1; ix >= 0; ix-- {
+			tIx := matchedIndices[ix]
+
+			// We do this backwards, since it means we don't have to adjust the
+			// later indices as we change the length of import targets.
+			//
+			// We need to do this separately, as a single resource could match
+			// multiple import targets.
+			importTargets = append(importTargets[:tIx], importTargets[tIx+1:]...)
+		}
+
+		abstract := &NodeAbstractResource{
+			Addr: addrs.ConfigResource{
+				Resource: relAddr,
+				Module:   path,
+			},
+			importTargets: imports,
+		}
+
+		var node dag.Vertex = abstract
+		if f := t.Concrete; f != nil {
+			node = f(abstract)
+		}
+
+		g.Add(node)
+	}
+
+	// If any import targets were not claimed by resources, then let's add them
+	// into the graph now.
+	//
+	// We actually know that if any of the resources aren't claimed and
+	// generateConfig is false, then we have a problem. But, we can't raise a
+	// nice error message from this function.
+	//
+	// We'll add the nodes that we know will fail, and catch them again later
+	// in the processing when we are in a position to raise a much more helpful
+	// error message.
+	//
+	// TODO: We could actually catch and process these kind of problems earlier,
+	//   this is something that could be done during the Validate process.
+	for _, i := range importTargets {
+		// The case in which an unmatched import block targets an expanded
+		// resource instance can error here. Others can error later.
+		if i.Addr.Resource.Key != addrs.NoKey {
+			return fmt.Errorf("Config generation for count and for_each resources not supported.\n\nYour configuration contains an import block with a \"to\" address of %s. This resource instance does not exist in configuration.\n\nIf you intended to target a resource that exists in configuration, please double-check the address. Otherwise, please remove this import block or re-run the plan without the -generate-config-out flag to ignore the import block.", i.Addr)
+		}
+
+		abstract := &NodeAbstractResource{
+			Addr:               i.Addr.ConfigResource(),
+			importTargets:      []*ImportTarget{i},
+			generateConfigPath: generateConfigPath,
+		}
+
+		var node dag.Vertex = abstract
+		if f := t.Concrete; f != nil {
+			node = f(abstract)
+		}
+
+		g.Add(node)
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_config_test.go b/v1.5.7/internal/terraform/transform_config_test.go
new file mode 100644
index 0000000..8e247af
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_config_test.go
@@ -0,0 +1,89 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestConfigTransformer_nilModule(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	tf := &ConfigTransformer{}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if len(g.Vertices()) > 0 {
+		t.Fatalf("graph is not empty: %s", g.String())
+	}
+}
+
+func TestConfigTransformer(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	tf := &ConfigTransformer{Config: testModule(t, "graph-basic")}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testConfigTransformerGraphBasicStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+func TestConfigTransformer_mode(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	tf := &ConfigTransformer{
+		Config:     testModule(t, "transform-config-mode-data"),
+		ModeFilter: true,
+		Mode:       addrs.DataResourceMode,
+	}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(`
+data.aws_ami.foo
+`)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+func TestConfigTransformer_nonUnique(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	g.Add(NewNodeAbstractResource(
+		addrs.RootModule.Resource(
+			addrs.ManagedResourceMode, "aws_instance", "web",
+		),
+	))
+	tf := &ConfigTransformer{Config: testModule(t, "graph-basic")}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(`
+aws_instance.web
+aws_instance.web
+aws_load_balancer.weblb
+aws_security_group.firewall
+openstack_floating_ip.random
+`)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+const testConfigTransformerGraphBasicStr = `
+aws_instance.web
+aws_load_balancer.weblb
+aws_security_group.firewall
+openstack_floating_ip.random
+`
diff --git a/v1.5.7/internal/terraform/transform_destroy_cbd.go b/v1.5.7/internal/terraform/transform_destroy_cbd.go
new file mode 100644
index 0000000..d097780
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_destroy_cbd.go
@@ -0,0 +1,153 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// GraphNodeDestroyerCBD must be implemented by nodes that might be
+// create-before-destroy destroyers, or might plan a create-before-destroy
+// action.
+type GraphNodeDestroyerCBD interface {
+	// CreateBeforeDestroy returns true if this node represents a node
+	// that is doing a CBD.
+	CreateBeforeDestroy() bool
+
+	// ModifyCreateBeforeDestroy is called when the CBD state of a node
+	// is changed dynamically. This can return an error if this isn't
+	// allowed.
+	ModifyCreateBeforeDestroy(bool) error
+}
+
+// ForcedCBDTransformer detects when a particular CBD-able graph node has
+// dependencies with another that has create_before_destroy set that require
+// it to be forced on, and forces it on.
+//
+// This must be used in the plan graph builder to ensure that
+// create_before_destroy settings are properly propagated before constructing
+// the planned changes. This requires that the plannable resource nodes
+// implement GraphNodeDestroyerCBD.
+type ForcedCBDTransformer struct {
+}
+
+func (t *ForcedCBDTransformer) Transform(g *Graph) error {
+	for _, v := range g.Vertices() {
+		dn, ok := v.(GraphNodeDestroyerCBD)
+		if !ok {
+			continue
+		}
+
+		if !dn.CreateBeforeDestroy() {
+			// If there are no CBD decendent (dependent nodes), then we
+			// do nothing here.
+			if !t.hasCBDDescendent(g, v) {
+				log.Printf("[TRACE] ForcedCBDTransformer: %q (%T) has no CBD descendent, so skipping", dag.VertexName(v), v)
+				continue
+			}
+
+			// If this isn't naturally a CBD node, this means that an descendent is
+			// and we need to auto-upgrade this node to CBD. We do this because
+			// a CBD node depending on non-CBD will result in cycles. To avoid this,
+			// we always attempt to upgrade it.
+			log.Printf("[TRACE] ForcedCBDTransformer: forcing create_before_destroy on for %q (%T)", dag.VertexName(v), v)
+			if err := dn.ModifyCreateBeforeDestroy(true); err != nil {
+				return fmt.Errorf(
+					"%s: must have create before destroy enabled because "+
+						"a dependent resource has CBD enabled. However, when "+
+						"attempting to automatically do this, an error occurred: %s",
+					dag.VertexName(v), err)
+			}
+		} else {
+			log.Printf("[TRACE] ForcedCBDTransformer: %q (%T) already has create_before_destroy set", dag.VertexName(v), v)
+		}
+	}
+	return nil
+}
+
+// hasCBDDescendent returns true if any descendent (node that depends on this)
+// has CBD set.
+func (t *ForcedCBDTransformer) hasCBDDescendent(g *Graph, v dag.Vertex) bool {
+	s, _ := g.Descendents(v)
+	if s == nil {
+		return true
+	}
+
+	for _, ov := range s {
+		dn, ok := ov.(GraphNodeDestroyerCBD)
+		if !ok {
+			continue
+		}
+
+		if dn.CreateBeforeDestroy() {
+			// some descendent is CreateBeforeDestroy, so we need to follow suit
+			log.Printf("[TRACE] ForcedCBDTransformer: %q has CBD descendent %q", dag.VertexName(v), dag.VertexName(ov))
+			return true
+		}
+	}
+
+	return false
+}
+
+// CBDEdgeTransformer modifies the edges of create-before-destroy ("CBD") nodes
+// that went through the DestroyEdgeTransformer so that they will have the
+// correct dependencies. There are two parts to this:
+//
+//  1. With CBD, the destroy edge is inverted: the destroy depends on
+//     the creation.
+//
+//  2. Destroy for A must depend on resources that depend on A. This is to
+//     allow the destroy to only happen once nodes that depend on A successfully
+//     update to A. Example: adding a web server updates the load balancer
+//     before deleting the old web server.
+//
+// This transformer requires that a previous transformer has already forced
+// create_before_destroy on for nodes that are depended on by explicit CBD
+// nodes. This is the logic in ForcedCBDTransformer, though in practice we
+// will get here by recording the CBD-ness of each change in the plan during
+// the plan walk and then forcing the nodes into the appropriate setting during
+// DiffTransformer when building the apply graph.
+type CBDEdgeTransformer struct {
+	// Module and State are only needed to look up dependencies in
+	// any way possible. Either can be nil if not availabile.
+	Config *configs.Config
+	State  *states.State
+}
+
+func (t *CBDEdgeTransformer) Transform(g *Graph) error {
+	// Go through and reverse any destroy edges
+	for _, v := range g.Vertices() {
+		dn, ok := v.(GraphNodeDestroyerCBD)
+		if !ok {
+			continue
+		}
+		if _, ok = v.(GraphNodeDestroyer); !ok {
+			continue
+		}
+
+		if !dn.CreateBeforeDestroy() {
+			continue
+		}
+
+		// Find the resource edges
+		for _, e := range g.EdgesTo(v) {
+			src := e.Source()
+
+			// If source is a create node, invert the edge.
+			// This covers both the node's own creator, as well as reversing
+			// any dependants' edges.
+			if _, ok := src.(GraphNodeCreator); ok {
+				log.Printf("[TRACE] CBDEdgeTransformer: reversing edge %s -> %s", dag.VertexName(src), dag.VertexName(v))
+				g.RemoveEdge(e)
+				g.Connect(dag.BasicEdge(v, src))
+			}
+		}
+	}
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_destroy_cbd_test.go b/v1.5.7/internal/terraform/transform_destroy_cbd_test.go
new file mode 100644
index 0000000..240b29b
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_destroy_cbd_test.go
@@ -0,0 +1,363 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"regexp"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func cbdTestGraph(t *testing.T, mod string, changes *plans.Changes, state *states.State) *Graph {
+	module := testModule(t, mod)
+
+	applyBuilder := &ApplyGraphBuilder{
+		Config:  module,
+		Changes: changes,
+		Plugins: simpleMockPluginLibrary(),
+		State:   state,
+	}
+	g, err := (&BasicGraphBuilder{
+		Steps: cbdTestSteps(applyBuilder.Steps()),
+		Name:  "ApplyGraphBuilder",
+	}).Build(addrs.RootModuleInstance)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	return filterInstances(g)
+}
+
+// override the apply graph builder to halt the process after CBD
+func cbdTestSteps(steps []GraphTransformer) []GraphTransformer {
+	found := false
+	var i int
+	var t GraphTransformer
+	for i, t = range steps {
+		if _, ok := t.(*CBDEdgeTransformer); ok {
+			found = true
+			break
+		}
+	}
+
+	if !found {
+		panic("CBDEdgeTransformer not found")
+	}
+
+	// re-add the root node so we have a valid graph for a walk, then reduce
+	// the graph for less output
+	steps = append(steps[:i+1], &CloseRootModuleTransformer{})
+	steps = append(steps, &TransitiveReductionTransformer{})
+
+	return steps
+}
+
+// remove extra nodes for easier test comparisons
+func filterInstances(g *Graph) *Graph {
+	for _, v := range g.Vertices() {
+		if _, ok := v.(GraphNodeResourceInstance); !ok {
+			g.Remove(v)
+		}
+
+	}
+	return g
+}
+
+func TestCBDEdgeTransformer(t *testing.T) {
+	changes := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: mustResourceInstanceAddr("test_object.A"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.CreateThenDelete,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("test_object.B"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Update,
+				},
+			},
+		},
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.A").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"A"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.B").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"B","test_list":["x"]}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	g := cbdTestGraph(t, "transform-destroy-cbd-edge-basic", changes, state)
+	g = filterInstances(g)
+
+	actual := strings.TrimSpace(g.String())
+	expected := regexp.MustCompile(strings.TrimSpace(`
+(?m)test_object.A
+test_object.A \(destroy deposed \w+\)
+  test_object.B
+test_object.B
+  test_object.A
+`))
+
+	if !expected.MatchString(actual) {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestCBDEdgeTransformerMulti(t *testing.T) {
+	changes := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: mustResourceInstanceAddr("test_object.A"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.CreateThenDelete,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("test_object.B"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.CreateThenDelete,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("test_object.C"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Update,
+				},
+			},
+		},
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.A").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"A"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.B").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"B"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.C").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"C","test_list":["x"]}`),
+			Dependencies: []addrs.ConfigResource{
+				mustConfigResourceAddr("test_object.A"),
+				mustConfigResourceAddr("test_object.B"),
+			},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	g := cbdTestGraph(t, "transform-destroy-cbd-edge-multi", changes, state)
+	g = filterInstances(g)
+
+	actual := strings.TrimSpace(g.String())
+	expected := regexp.MustCompile(strings.TrimSpace(`
+(?m)test_object.A
+test_object.A \(destroy deposed \w+\)
+  test_object.C
+test_object.B
+test_object.B \(destroy deposed \w+\)
+  test_object.C
+test_object.C
+  test_object.A
+  test_object.B
+`))
+
+	if !expected.MatchString(actual) {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestCBDEdgeTransformer_depNonCBDCount(t *testing.T) {
+	changes := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: mustResourceInstanceAddr("test_object.A"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.CreateThenDelete,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("test_object.B[0]"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Update,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("test_object.B[1]"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Update,
+				},
+			},
+		},
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.A").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"A"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.B[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"B","test_list":["x"]}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.B[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"B","test_list":["x"]}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	g := cbdTestGraph(t, "transform-cbd-destroy-edge-count", changes, state)
+
+	actual := strings.TrimSpace(g.String())
+	expected := regexp.MustCompile(strings.TrimSpace(`
+(?m)test_object.A
+test_object.A \(destroy deposed \w+\)
+  test_object.B\[0\]
+  test_object.B\[1\]
+test_object.B\[0\]
+  test_object.A
+test_object.B\[1\]
+  test_object.A`))
+
+	if !expected.MatchString(actual) {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestCBDEdgeTransformer_depNonCBDCountBoth(t *testing.T) {
+	changes := &plans.Changes{
+		Resources: []*plans.ResourceInstanceChangeSrc{
+			{
+				Addr: mustResourceInstanceAddr("test_object.A[0]"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.CreateThenDelete,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("test_object.A[1]"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.CreateThenDelete,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("test_object.B[0]"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Update,
+				},
+			},
+			{
+				Addr: mustResourceInstanceAddr("test_object.B[1]"),
+				ChangeSrc: plans.ChangeSrc{
+					Action: plans.Update,
+				},
+			},
+		},
+	}
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.A[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"A"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.A[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"A"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.B[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"B","test_list":["x"]}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.B[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"B","test_list":["x"]}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	g := cbdTestGraph(t, "transform-cbd-destroy-edge-both-count", changes, state)
+
+	actual := strings.TrimSpace(g.String())
+	expected := regexp.MustCompile(strings.TrimSpace(`
+test_object.A\[0\]
+test_object.A\[0\] \(destroy deposed \w+\)
+  test_object.B\[0\]
+  test_object.B\[1\]
+test_object.A\[1\]
+test_object.A\[1\] \(destroy deposed \w+\)
+  test_object.B\[0\]
+  test_object.B\[1\]
+test_object.B\[0\]
+  test_object.A\[0\]
+  test_object.A\[1\]
+test_object.B\[1\]
+  test_object.A\[0\]
+  test_object.A\[1\]
+`))
+
+	if !expected.MatchString(actual) {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
diff --git a/v1.5.7/internal/terraform/transform_destroy_edge.go b/v1.5.7/internal/terraform/transform_destroy_edge.go
new file mode 100644
index 0000000..9ca05e6
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_destroy_edge.go
@@ -0,0 +1,385 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+// GraphNodeDestroyer must be implemented by nodes that destroy resources.
+type GraphNodeDestroyer interface {
+	dag.Vertex
+
+	// DestroyAddr is the address of the resource that is being
+	// destroyed by this node. If this returns nil, then this node
+	// is not destroying anything.
+	DestroyAddr() *addrs.AbsResourceInstance
+}
+
+// GraphNodeCreator must be implemented by nodes that create OR update resources.
+type GraphNodeCreator interface {
+	// CreateAddr is the address of the resource being created or updated
+	CreateAddr() *addrs.AbsResourceInstance
+}
+
+// DestroyEdgeTransformer is a GraphTransformer that creates the proper
+// references for destroy resources. Destroy resources are more complex
+// in that they must be depend on the destruction of resources that
+// in turn depend on the CREATION of the node being destroy.
+//
+// That is complicated. Visually:
+//
+//	B_d -> A_d -> A -> B
+//
+// Notice that A destroy depends on B destroy, while B create depends on
+// A create. They're inverted. This must be done for example because often
+// dependent resources will block parent resources from deleting. Concrete
+// example: VPC with subnets, the VPC can't be deleted while there are
+// still subnets.
+type DestroyEdgeTransformer struct {
+	// FIXME: GraphNodeCreators are not always applying changes, and should not
+	// participate in the destroy graph if there are no operations which could
+	// interract with destroy nodes. We need Changes for now to detect the
+	// action type, but perhaps this should be indicated somehow by the
+	// DiffTransformer which was intended to be the only transformer operating
+	// from the change set.
+	Changes *plans.Changes
+
+	// FIXME: Operation will not be needed here one we can better track
+	// inter-provider dependencies and remove the cycle checks in
+	// tryInterProviderDestroyEdge.
+	Operation walkOperation
+}
+
+// tryInterProviderDestroyEdge checks if we're inserting a destroy edge
+// across a provider boundary, and only adds the edge if it results in no cycles.
+//
+// FIXME: The cycles can arise in valid configurations when a provider depends
+// on resources from another provider. In the future we may want to inspect
+// the dependencies of the providers themselves, to avoid needing to use the
+// blunt hammer of checking for cycles.
+//
+// A reduced example of this dependency problem looks something like:
+/*
+
+createA <-               createB
+  |        \            /    |
+  |         providerB <-     |
+  v                     \    v
+destroyA ------------->  destroyB
+
+*/
+//
+// The edge from destroyA to destroyB would be skipped in this case, but there
+// are still other combinations of changes which could connect the A and B
+// groups around providerB in various ways.
+//
+// The most difficult problem here happens during a full destroy operation.
+// That creates a special case where resources on which a provider depends must
+// exist for evaluation before they are destroyed. This means that any provider
+// dependencies must wait until all that provider's resources have first been
+// destroyed. This is where these cross-provider edges are still required to
+// ensure the correct order.
+func (t *DestroyEdgeTransformer) tryInterProviderDestroyEdge(g *Graph, from, to dag.Vertex) {
+	e := dag.BasicEdge(from, to)
+	g.Connect(e)
+
+	// If this is a complete destroy operation, then there are no create/update
+	// nodes to worry about and we can accept the edge without deeper inspection.
+	if t.Operation == walkDestroy || t.Operation == walkPlanDestroy {
+		return
+	}
+
+	// getComparableProvider inspects the node to try and get the most precise
+	// description of the provider being used to help determine if 2 nodes are
+	// from the same provider instance.
+	getComparableProvider := func(pc GraphNodeProviderConsumer) string {
+		ps := pc.Provider().String()
+
+		// we don't care about `exact` here, since we're only looking for any
+		// clue that the providers may differ.
+		p, _ := pc.ProvidedBy()
+		switch p := p.(type) {
+		case addrs.AbsProviderConfig:
+			ps = p.String()
+		case addrs.LocalProviderConfig:
+			ps = p.String()
+		}
+
+		return ps
+	}
+
+	pc, ok := from.(GraphNodeProviderConsumer)
+	if !ok {
+		return
+	}
+	fromProvider := getComparableProvider(pc)
+
+	pc, ok = to.(GraphNodeProviderConsumer)
+	if !ok {
+		return
+	}
+	toProvider := getComparableProvider(pc)
+
+	// Check for cycles, and back out the edge if there are any.
+	// The cycles we are looking for only appears between providers, so don't
+	// waste time checking for cycles if both nodes use the same provider.
+	if fromProvider != toProvider && len(g.Cycles()) > 0 {
+		log.Printf("[DEBUG] DestroyEdgeTransformer: skipping inter-provider edge %s->%s which creates a cycle",
+			dag.VertexName(from), dag.VertexName(to))
+		g.RemoveEdge(e)
+	}
+}
+
+func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
+	// Build a map of what is being destroyed (by address string) to
+	// the list of destroyers.
+	destroyers := make(map[string][]GraphNodeDestroyer)
+
+	// Record the creators, which will need to depend on the destroyers if they
+	// are only being updated.
+	creators := make(map[string][]GraphNodeCreator)
+
+	// destroyersByResource records each destroyer by the ConfigResource
+	// address.  We use this because dependencies are only referenced as
+	// resources and have no index or module instance information, but we will
+	// want to connect all the individual instances for correct ordering.
+	destroyersByResource := make(map[string][]GraphNodeDestroyer)
+	for _, v := range g.Vertices() {
+		switch n := v.(type) {
+		case GraphNodeDestroyer:
+			addrP := n.DestroyAddr()
+			if addrP == nil {
+				log.Printf("[WARN] DestroyEdgeTransformer: %q (%T) has no destroy address", dag.VertexName(n), v)
+				continue
+			}
+			addr := *addrP
+
+			key := addr.String()
+			log.Printf("[TRACE] DestroyEdgeTransformer: %q (%T) destroys %s", dag.VertexName(n), v, key)
+			destroyers[key] = append(destroyers[key], n)
+
+			resAddr := addr.ContainingResource().Config().String()
+			destroyersByResource[resAddr] = append(destroyersByResource[resAddr], n)
+		case GraphNodeCreator:
+			addr := n.CreateAddr()
+			cfgAddr := addr.ContainingResource().Config().String()
+
+			if t.Changes == nil {
+				// unit tests may not have changes
+				creators[cfgAddr] = append(creators[cfgAddr], n)
+				break
+			}
+
+			// NoOp changes should not participate in the destroy dependencies.
+			rc := t.Changes.ResourceInstance(*addr)
+			if rc != nil && rc.Action != plans.NoOp {
+				creators[cfgAddr] = append(creators[cfgAddr], n)
+			}
+		}
+	}
+
+	// If we aren't destroying anything, there will be no edges to make
+	// so just exit early and avoid future work.
+	if len(destroyers) == 0 {
+		return nil
+	}
+
+	// Go through and connect creators to destroyers. Going along with
+	// our example, this makes: A_d => A
+	for _, v := range g.Vertices() {
+		cn, ok := v.(GraphNodeCreator)
+		if !ok {
+			continue
+		}
+
+		addr := cn.CreateAddr()
+		if addr == nil {
+			continue
+		}
+
+		for _, d := range destroyers[addr.String()] {
+			// For illustrating our example
+			a_d := d.(dag.Vertex)
+			a := v
+
+			log.Printf(
+				"[TRACE] DestroyEdgeTransformer: connecting creator %q with destroyer %q",
+				dag.VertexName(a), dag.VertexName(a_d))
+
+			g.Connect(dag.BasicEdge(a, a_d))
+		}
+	}
+
+	// connect creators to any destroyers on which they may depend
+	for _, cs := range creators {
+		for _, c := range cs {
+			ri, ok := c.(GraphNodeResourceInstance)
+			if !ok {
+				continue
+			}
+
+			for _, resAddr := range ri.StateDependencies() {
+				for _, desDep := range destroyersByResource[resAddr.String()] {
+					if !graphNodesAreResourceInstancesInDifferentInstancesOfSameModule(c, desDep) {
+						log.Printf("[TRACE] DestroyEdgeTransformer: %s has stored dependency of %s\n", dag.VertexName(c), dag.VertexName(desDep))
+						g.Connect(dag.BasicEdge(c, desDep))
+					} else {
+						log.Printf("[TRACE] DestroyEdgeTransformer: skipping %s => %s inter-module-instance dependency\n", dag.VertexName(c), dag.VertexName(desDep))
+					}
+				}
+			}
+		}
+	}
+
+	// Connect destroy dependencies as stored in the state
+	for _, ds := range destroyers {
+		for _, des := range ds {
+			ri, ok := des.(GraphNodeResourceInstance)
+			if !ok {
+				continue
+			}
+
+			for _, resAddr := range ri.StateDependencies() {
+				for _, desDep := range destroyersByResource[resAddr.String()] {
+					if !graphNodesAreResourceInstancesInDifferentInstancesOfSameModule(desDep, des) {
+						log.Printf("[TRACE] DestroyEdgeTransformer: %s has stored dependency of %s\n", dag.VertexName(desDep), dag.VertexName(des))
+						t.tryInterProviderDestroyEdge(g, desDep, des)
+					} else {
+						log.Printf("[TRACE] DestroyEdgeTransformer: skipping %s => %s inter-module-instance dependency\n", dag.VertexName(desDep), dag.VertexName(des))
+					}
+				}
+
+				// We can have some create or update nodes which were
+				// dependents of the destroy node. If they have no destroyer
+				// themselves, make the connection directly from the creator.
+				for _, createDep := range creators[resAddr.String()] {
+					if !graphNodesAreResourceInstancesInDifferentInstancesOfSameModule(createDep, des) {
+						log.Printf("[DEBUG] DestroyEdgeTransformer2: %s has stored dependency of %s\n", dag.VertexName(createDep), dag.VertexName(des))
+						t.tryInterProviderDestroyEdge(g, createDep, des)
+					} else {
+						log.Printf("[TRACE] DestroyEdgeTransformer2: skipping %s => %s inter-module-instance dependency\n", dag.VertexName(createDep), dag.VertexName(des))
+					}
+				}
+			}
+		}
+	}
+
+	return nil
+}
+
+// Remove any nodes that aren't needed when destroying modules.
+// Variables, outputs, locals, and expanders may not be able to evaluate
+// correctly, so we can remove these if nothing depends on them. The module
+// closers also need to disable their use of expansion if the module itself is
+// no longer present.
+type pruneUnusedNodesTransformer struct {
+	// The plan graph builder will skip this transformer except during a full
+	// destroy. Planing normally involves all nodes, but during a destroy plan
+	// we may need to prune things which are in the configuration but do not
+	// exist in state to evaluate.
+	skip bool
+}
+
+func (t *pruneUnusedNodesTransformer) Transform(g *Graph) error {
+	if t.skip {
+		return nil
+	}
+
+	// We need a reverse depth first walk of modules, processing them in order
+	// from the leaf modules to the root. This allows us to remove unneeded
+	// dependencies from child modules, freeing up nodes in the parent module
+	// to also be removed.
+
+	nodes := g.Vertices()
+
+	for removed := true; removed; {
+		removed = false
+
+		for i := 0; i < len(nodes); i++ {
+			// run this in a closure, so we can return early rather than
+			// dealing with complex looping and labels
+			func() {
+				n := nodes[i]
+				switch n := n.(type) {
+				case graphNodeTemporaryValue:
+					// root module outputs indicate they are not temporary by
+					// returning false here.
+					if !n.temporaryValue() {
+						return
+					}
+
+					// temporary values, which consist of variables, locals,
+					// and outputs, must be kept if anything refers to them.
+					for _, v := range g.UpEdges(n) {
+						// keep any value which is connected through a
+						// reference
+						if _, ok := v.(GraphNodeReferencer); ok {
+							return
+						}
+					}
+
+				case graphNodeExpandsInstances:
+					// Any nodes that expand instances are kept when their
+					// instances may need to be evaluated.
+					for _, v := range g.UpEdges(n) {
+						switch v.(type) {
+						case graphNodeExpandsInstances:
+							// Root module output values (which the following
+							// condition matches) are exempt because we know
+							// there is only ever exactly one instance of the
+							// root module, and so it's not actually important
+							// to expand it and so this lets us do a bit more
+							// pruning than we'd be able to do otherwise.
+							if tmp, ok := v.(graphNodeTemporaryValue); ok && !tmp.temporaryValue() {
+								continue
+							}
+
+							// expanders can always depend on module expansion
+							// themselves
+							return
+						case GraphNodeResourceInstance:
+							// resource instances always depend on their
+							// resource node, which is an expander
+							return
+						}
+					}
+
+				case GraphNodeProvider:
+					// Only keep providers for evaluation if they have
+					// resources to handle.
+					// The provider transformers removed most unused providers
+					// earlier, however there may be more to prune now based on
+					// targeting or a destroy with no related instances in the
+					// state.
+					des, _ := g.Descendents(n)
+					for _, v := range des {
+						switch v.(type) {
+						case GraphNodeProviderConsumer:
+							return
+						}
+					}
+
+				default:
+					return
+				}
+
+				log.Printf("[DEBUG] pruneUnusedNodes: %s is no longer needed, removing", dag.VertexName(n))
+				g.Remove(n)
+				removed = true
+
+				// remove the node from our iteration as well
+				last := len(nodes) - 1
+				nodes[i], nodes[last] = nodes[last], nodes[i]
+				nodes = nodes[:last]
+			}()
+		}
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_destroy_edge_test.go b/v1.5.7/internal/terraform/transform_destroy_edge_test.go
new file mode 100644
index 0000000..a946ded
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_destroy_edge_test.go
@@ -0,0 +1,598 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestDestroyEdgeTransformer_basic(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	g.Add(testDestroyNode("test_object.A"))
+	g.Add(testDestroyNode("test_object.B"))
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.A").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"A"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.B").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"B","test_string":"x"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil {
+		t.Fatal(err)
+	}
+
+	tf := &DestroyEdgeTransformer{}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformDestroyEdgeBasicStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestDestroyEdgeTransformer_multi(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	g.Add(testDestroyNode("test_object.A"))
+	g.Add(testDestroyNode("test_object.B"))
+	g.Add(testDestroyNode("test_object.C"))
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.A").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"A"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.B").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"B","test_string":"x"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.C").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"C","test_string":"x"}`),
+			Dependencies: []addrs.ConfigResource{
+				mustConfigResourceAddr("test_object.A"),
+				mustConfigResourceAddr("test_object.B"),
+			},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil {
+		t.Fatal(err)
+	}
+
+	tf := &DestroyEdgeTransformer{}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformDestroyEdgeMultiStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestDestroyEdgeTransformer_selfRef(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	g.Add(testDestroyNode("test_object.A"))
+	tf := &DestroyEdgeTransformer{}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformDestroyEdgeSelfRefStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestDestroyEdgeTransformer_module(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	g.Add(testDestroyNode("module.child.test_object.b"))
+	g.Add(testDestroyNode("test_object.a"))
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.a").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"a"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.test_object.b")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	child.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.b").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"b","test_string":"x"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil {
+		t.Fatal(err)
+	}
+
+	tf := &DestroyEdgeTransformer{}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformDestroyEdgeModuleStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestDestroyEdgeTransformer_moduleOnly(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+
+	state := states.NewState()
+	for moduleIdx := 0; moduleIdx < 2; moduleIdx++ {
+		g.Add(testDestroyNode(fmt.Sprintf("module.child[%d].test_object.a", moduleIdx)))
+		g.Add(testDestroyNode(fmt.Sprintf("module.child[%d].test_object.b", moduleIdx)))
+		g.Add(testDestroyNode(fmt.Sprintf("module.child[%d].test_object.c", moduleIdx)))
+
+		child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.IntKey(moduleIdx)))
+		child.SetResourceInstanceCurrent(
+			mustResourceInstanceAddr("test_object.a").Resource,
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectReady,
+				AttrsJSON: []byte(`{"id":"a"}`),
+			},
+			mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+		)
+		child.SetResourceInstanceCurrent(
+			mustResourceInstanceAddr("test_object.b").Resource,
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectReady,
+				AttrsJSON: []byte(`{"id":"b","test_string":"x"}`),
+				Dependencies: []addrs.ConfigResource{
+					mustConfigResourceAddr("module.child.test_object.a"),
+				},
+			},
+			mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+		)
+		child.SetResourceInstanceCurrent(
+			mustResourceInstanceAddr("test_object.c").Resource,
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectReady,
+				AttrsJSON: []byte(`{"id":"c","test_string":"x"}`),
+				Dependencies: []addrs.ConfigResource{
+					mustConfigResourceAddr("module.child.test_object.a"),
+					mustConfigResourceAddr("module.child.test_object.b"),
+				},
+			},
+			mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+		)
+	}
+
+	if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil {
+		t.Fatal(err)
+	}
+
+	tf := &DestroyEdgeTransformer{}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// The analyses done in the destroy edge transformer are between
+	// not-yet-expanded objects, which is conservative and so it will generate
+	// edges that aren't strictly necessary. As a special case we filter out
+	// any edges that are between resources instances that are in different
+	// instances of the same module, because those edges are never needed
+	// (one instance of a module cannot depend on another instance of the
+	// same module) and including them can, in complex cases, cause cycles due
+	// to unnecessary interactions between destroyed and created module
+	// instances in the same plan.
+	//
+	// Therefore below we expect to see the dependencies within each instance
+	// of module.child reflected, but we should not see any dependencies
+	// _between_ instances of module.child.
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(`
+module.child[0].test_object.a (destroy)
+  module.child[0].test_object.b (destroy)
+  module.child[0].test_object.c (destroy)
+module.child[0].test_object.b (destroy)
+  module.child[0].test_object.c (destroy)
+module.child[0].test_object.c (destroy)
+module.child[1].test_object.a (destroy)
+  module.child[1].test_object.b (destroy)
+  module.child[1].test_object.c (destroy)
+module.child[1].test_object.b (destroy)
+  module.child[1].test_object.c (destroy)
+module.child[1].test_object.c (destroy)
+`)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestDestroyEdgeTransformer_destroyThenUpdate(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	g.Add(testUpdateNode("test_object.A"))
+	g.Add(testDestroyNode("test_object.B"))
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.A").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"A","test_string":"old"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.B").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"B","test_string":"x"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil {
+		t.Fatal(err)
+	}
+
+	tf := &DestroyEdgeTransformer{}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := strings.TrimSpace(`
+test_object.A
+  test_object.B (destroy)
+test_object.B (destroy)
+`)
+	actual := strings.TrimSpace(g.String())
+
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestPruneUnusedNodesTransformer_rootModuleOutputValues(t *testing.T) {
+	// This is a kinda-weird test case covering the very narrow situation
+	// where a root module output value depends on a resource, where we
+	// need to make sure that the output value doesn't block pruning of
+	// the resource from the graph. This special case exists because although
+	// root module objects are "expanders", they in practice always expand
+	// to exactly one instance and so don't have the usual requirement of
+	// needing to stick around in order to support downstream expanders
+	// when there are e.g. nested expanding modules.
+
+	// In order to keep this test focused on the pruneUnusedNodesTransformer
+	// as much as possible we're using a minimal graph construction here which
+	// is just enough to get the nodes we need, but this does mean that this
+	// test might be invalidated by future changes to the apply graph builder,
+	// and so if something seems off here it might help to compare the
+	// following with the real apply graph transformer and verify whether
+	// this smaller construction is still realistic enough to be a valid test.
+	// It might be valid to change or remove this test to "make it work", as
+	// long as you verify that there is still _something_ upholding the
+	// invariant that a root module output value should not block a resource
+	// node from being pruned from the graph.
+
+	concreteResource := func(a *NodeAbstractResource) dag.Vertex {
+		return &nodeExpandApplyableResource{
+			NodeAbstractResource: a,
+		}
+	}
+
+	concreteResourceInstance := func(a *NodeAbstractResourceInstance) dag.Vertex {
+		return &NodeApplyableResourceInstance{
+			NodeAbstractResourceInstance: a,
+		}
+	}
+
+	resourceInstAddr := mustResourceInstanceAddr("test.a")
+	providerCfgAddr := addrs.AbsProviderConfig{
+		Module:   addrs.RootModule,
+		Provider: addrs.MustParseProviderSourceString("foo/test"),
+	}
+	emptyObjDynamicVal, err := plans.NewDynamicValue(cty.EmptyObjectVal, cty.EmptyObject)
+	if err != nil {
+		t.Fatal(err)
+	}
+	nullObjDynamicVal, err := plans.NewDynamicValue(cty.NullVal(cty.EmptyObject), cty.EmptyObject)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	config := testModuleInline(t, map[string]string{
+		"main.tf": `
+			resource "test" "a" {
+			}
+
+			output "test" {
+				value = test.a.foo
+			}
+		`,
+	})
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			resourceInstAddr,
+			&states.ResourceInstanceObjectSrc{
+				Status:    states.ObjectReady,
+				AttrsJSON: []byte(`{}`),
+			},
+			providerCfgAddr,
+		)
+	})
+	changes := plans.NewChanges()
+	changes.SyncWrapper().AppendResourceInstanceChange(&plans.ResourceInstanceChangeSrc{
+		Addr:         resourceInstAddr,
+		PrevRunAddr:  resourceInstAddr,
+		ProviderAddr: providerCfgAddr,
+		ChangeSrc: plans.ChangeSrc{
+			Action: plans.Delete,
+			Before: emptyObjDynamicVal,
+			After:  nullObjDynamicVal,
+		},
+	})
+
+	builder := &BasicGraphBuilder{
+		Steps: []GraphTransformer{
+			&ConfigTransformer{
+				Concrete: concreteResource,
+				Config:   config,
+			},
+			&OutputTransformer{
+				Config: config,
+			},
+			&DiffTransformer{
+				Concrete: concreteResourceInstance,
+				State:    state,
+				Changes:  changes,
+			},
+			&ReferenceTransformer{},
+			&AttachDependenciesTransformer{},
+			&pruneUnusedNodesTransformer{},
+			&CloseRootModuleTransformer{},
+		},
+	}
+	graph, diags := builder.Build(addrs.RootModuleInstance)
+	assertNoDiagnostics(t, diags)
+
+	// At this point, thanks to pruneUnusedNodesTransformer, we should still
+	// have the node for the output value, but the "test.a (expand)" node
+	// should've been pruned in recognition of the fact that we're performing
+	// a destroy and therefore we only need the "test.a (destroy)" node.
+
+	nodesByName := make(map[string]dag.Vertex)
+	nodesByResourceExpand := make(map[string]dag.Vertex)
+	for _, n := range graph.Vertices() {
+		name := dag.VertexName(n)
+		if _, exists := nodesByName[name]; exists {
+			t.Fatalf("multiple nodes have name %q", name)
+		}
+		nodesByName[name] = n
+
+		if exp, ok := n.(*nodeExpandApplyableResource); ok {
+			addr := exp.Addr
+			if _, exists := nodesByResourceExpand[addr.String()]; exists {
+				t.Fatalf("multiple nodes are expanders for %s", addr)
+			}
+			nodesByResourceExpand[addr.String()] = exp
+		}
+	}
+
+	// NOTE: The following is sensitive to the current name string formats we
+	// use for these particular node types. These names are not contractual
+	// so if this breaks in future it is fine to update these names to the new
+	// names as long as you verify first that the new names correspond to
+	// the same meaning as what we're assuming below.
+	if _, exists := nodesByName["test.a (destroy)"]; !exists {
+		t.Errorf("missing destroy node for resource instance test.a")
+	}
+	if _, exists := nodesByName["output.test (expand)"]; !exists {
+		t.Errorf("missing expand for output value 'test'")
+	}
+
+	// We _must not_ have any node that expands a resource.
+	if len(nodesByResourceExpand) != 0 {
+		t.Errorf("resource expand nodes remain the graph after transform; should've been pruned\n%s", spew.Sdump(nodesByResourceExpand))
+	}
+}
+
+// NoOp changes should not be participating in the destroy sequence
+func TestDestroyEdgeTransformer_noOp(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	g.Add(testDestroyNode("test_object.A"))
+	g.Add(testUpdateNode("test_object.B"))
+	g.Add(testDestroyNode("test_object.C"))
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.A").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"A"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.B").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:       states.ObjectReady,
+			AttrsJSON:    []byte(`{"id":"B","test_string":"x"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.C").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"C","test_string":"x"}`),
+			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A"),
+				mustConfigResourceAddr("test_object.B")},
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil {
+		t.Fatal(err)
+	}
+
+	tf := &DestroyEdgeTransformer{
+		// We only need a minimal object to indicate GraphNodeCreator change is
+		// a NoOp here.
+		Changes: &plans.Changes{
+			Resources: []*plans.ResourceInstanceChangeSrc{
+				{
+					Addr:      mustResourceInstanceAddr("test_object.B"),
+					ChangeSrc: plans.ChangeSrc{Action: plans.NoOp},
+				},
+			},
+		},
+	}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := strings.TrimSpace(`
+test_object.A (destroy)
+  test_object.C (destroy)
+test_object.B
+test_object.C (destroy)`)
+
+	actual := strings.TrimSpace(g.String())
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestDestroyEdgeTransformer_dataDependsOn(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+
+	addrA := mustResourceInstanceAddr("test_object.A")
+	instA := NewNodeAbstractResourceInstance(addrA)
+	a := &NodeDestroyResourceInstance{NodeAbstractResourceInstance: instA}
+	g.Add(a)
+
+	// B here represents a data sources, which is effectively an update during
+	// apply, but won't have dependencies stored in the state.
+	addrB := mustResourceInstanceAddr("test_object.B")
+	instB := NewNodeAbstractResourceInstance(addrB)
+	instB.Dependencies = append(instB.Dependencies, addrA.ConfigResource())
+	b := &NodeApplyableResourceInstance{NodeAbstractResourceInstance: instB}
+
+	g.Add(b)
+
+	state := states.NewState()
+	root := state.EnsureModule(addrs.RootModuleInstance)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("test_object.A").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"A"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
+	)
+
+	if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil {
+		t.Fatal(err)
+	}
+
+	tf := &DestroyEdgeTransformer{}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(`
+test_object.A (destroy)
+test_object.B
+  test_object.A (destroy)
+`)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func testDestroyNode(addrString string) GraphNodeDestroyer {
+	instAddr := mustResourceInstanceAddr(addrString)
+	inst := NewNodeAbstractResourceInstance(instAddr)
+	return &NodeDestroyResourceInstance{NodeAbstractResourceInstance: inst}
+}
+
+func testUpdateNode(addrString string) GraphNodeCreator {
+	instAddr := mustResourceInstanceAddr(addrString)
+	inst := NewNodeAbstractResourceInstance(instAddr)
+	return &NodeApplyableResourceInstance{NodeAbstractResourceInstance: inst}
+}
+
+const testTransformDestroyEdgeBasicStr = `
+test_object.A (destroy)
+  test_object.B (destroy)
+test_object.B (destroy)
+`
+
+const testTransformDestroyEdgeMultiStr = `
+test_object.A (destroy)
+  test_object.B (destroy)
+  test_object.C (destroy)
+test_object.B (destroy)
+  test_object.C (destroy)
+test_object.C (destroy)
+`
+
+const testTransformDestroyEdgeSelfRefStr = `
+test_object.A (destroy)
+`
+
+const testTransformDestroyEdgeModuleStr = `
+module.child.test_object.b (destroy)
+  test_object.a (destroy)
+test_object.a (destroy)
+`
diff --git a/v1.5.7/internal/terraform/transform_diff.go b/v1.5.7/internal/terraform/transform_diff.go
new file mode 100644
index 0000000..220734c
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_diff.go
@@ -0,0 +1,217 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/plans"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// DiffTransformer is a GraphTransformer that adds graph nodes representing
+// each of the resource changes described in the given Changes object.
+type DiffTransformer struct {
+	Concrete ConcreteResourceInstanceNodeFunc
+	State    *states.State
+	Changes  *plans.Changes
+	Config   *configs.Config
+}
+
+// return true if the given resource instance has either Preconditions or
+// Postconditions defined in the configuration.
+func (t *DiffTransformer) hasConfigConditions(addr addrs.AbsResourceInstance) bool {
+	// unit tests may have no config
+	if t.Config == nil {
+		return false
+	}
+
+	cfg := t.Config.DescendentForInstance(addr.Module)
+	if cfg == nil {
+		return false
+	}
+
+	res := cfg.Module.ResourceByAddr(addr.ConfigResource().Resource)
+	if res == nil {
+		return false
+	}
+
+	return len(res.Preconditions) > 0 || len(res.Postconditions) > 0
+}
+
+func (t *DiffTransformer) Transform(g *Graph) error {
+	if t.Changes == nil || len(t.Changes.Resources) == 0 {
+		// Nothing to do!
+		return nil
+	}
+
+	// Go through all the modules in the diff.
+	log.Printf("[TRACE] DiffTransformer starting")
+
+	var diags tfdiags.Diagnostics
+	state := t.State
+	changes := t.Changes
+
+	// DiffTransformer creates resource _instance_ nodes. If there are any
+	// whole-resource nodes already in the graph, we must ensure that they
+	// get evaluated before any of the corresponding instances by creating
+	// dependency edges, so we'll do some prep work here to ensure we'll only
+	// create connections to nodes that existed before we started here.
+	resourceNodes := map[string][]GraphNodeConfigResource{}
+	for _, node := range g.Vertices() {
+		rn, ok := node.(GraphNodeConfigResource)
+		if !ok {
+			continue
+		}
+		// We ignore any instances that _also_ implement
+		// GraphNodeResourceInstance, since in the unlikely event that they
+		// do exist we'd probably end up creating cycles by connecting them.
+		if _, ok := node.(GraphNodeResourceInstance); ok {
+			continue
+		}
+
+		addr := rn.ResourceAddr().String()
+		resourceNodes[addr] = append(resourceNodes[addr], rn)
+	}
+
+	for _, rc := range changes.Resources {
+		addr := rc.Addr
+		dk := rc.DeposedKey
+
+		log.Printf("[TRACE] DiffTransformer: found %s change for %s %s", rc.Action, addr, dk)
+
+		// Depending on the action we'll need some different combinations of
+		// nodes, because destroying uses a special node type separate from
+		// other actions.
+		var update, delete, createBeforeDestroy bool
+		switch rc.Action {
+		case plans.NoOp:
+			// For a no-op change we don't take any action but we still
+			// run any condition checks associated with the object, to
+			// make sure that they still hold when considering the
+			// results of other changes.
+			update = t.hasConfigConditions(addr)
+		case plans.Delete:
+			delete = true
+		case plans.DeleteThenCreate, plans.CreateThenDelete:
+			update = true
+			delete = true
+			createBeforeDestroy = (rc.Action == plans.CreateThenDelete)
+		default:
+			update = true
+		}
+
+		// A deposed instance may only have a change of Delete or NoOp. A NoOp
+		// can happen if the provider shows it no longer exists during the most
+		// recent ReadResource operation.
+		if dk != states.NotDeposed && !(rc.Action == plans.Delete || rc.Action == plans.NoOp) {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid planned change for deposed object",
+				fmt.Sprintf("The plan contains a non-delete change for %s deposed object %s. The only valid action for a deposed object is to destroy it, so this is a bug in Terraform.", addr, dk),
+			))
+			continue
+		}
+
+		// If we're going to do a create_before_destroy Replace operation then
+		// we need to allocate a DeposedKey to use to retain the
+		// not-yet-destroyed prior object, so that the delete node can destroy
+		// _that_ rather than the newly-created node, which will be current
+		// by the time the delete node is visited.
+		if update && delete && createBeforeDestroy {
+			// In this case, variable dk will be the _pre-assigned_ DeposedKey
+			// that must be used if the update graph node deposes the current
+			// instance, which will then align with the same key we pass
+			// into the destroy node to ensure we destroy exactly the deposed
+			// object we expect.
+			if state != nil {
+				ris := state.ResourceInstance(addr)
+				if ris == nil {
+					// Should never happen, since we don't plan to replace an
+					// instance that doesn't exist yet.
+					diags = diags.Append(tfdiags.Sourceless(
+						tfdiags.Error,
+						"Invalid planned change",
+						fmt.Sprintf("The plan contains a replace change for %s, which doesn't exist yet. This is a bug in Terraform.", addr),
+					))
+					continue
+				}
+
+				// Allocating a deposed key separately from using it can be racy
+				// in general, but we assume here that nothing except the apply
+				// node we instantiate below will actually make new deposed objects
+				// in practice, and so the set of already-used keys will not change
+				// between now and then.
+				dk = ris.FindUnusedDeposedKey()
+			} else {
+				// If we have no state at all yet then we can use _any_
+				// DeposedKey.
+				dk = states.NewDeposedKey()
+			}
+		}
+
+		if update {
+			// All actions except destroying the node type chosen by t.Concrete
+			abstract := NewNodeAbstractResourceInstance(addr)
+			var node dag.Vertex = abstract
+			if f := t.Concrete; f != nil {
+				node = f(abstract)
+			}
+
+			if createBeforeDestroy {
+				// We'll attach our pre-allocated DeposedKey to the node if
+				// it supports that. NodeApplyableResourceInstance is the
+				// specific concrete node type we are looking for here really,
+				// since that's the only node type that might depose objects.
+				if dn, ok := node.(GraphNodeDeposer); ok {
+					dn.SetPreallocatedDeposedKey(dk)
+				}
+				log.Printf("[TRACE] DiffTransformer: %s will be represented by %s, deposing prior object to %s", addr, dag.VertexName(node), dk)
+			} else {
+				log.Printf("[TRACE] DiffTransformer: %s will be represented by %s", addr, dag.VertexName(node))
+			}
+
+			g.Add(node)
+			rsrcAddr := addr.ContainingResource().String()
+			for _, rsrcNode := range resourceNodes[rsrcAddr] {
+				g.Connect(dag.BasicEdge(node, rsrcNode))
+			}
+		}
+
+		if delete {
+			// Destroying always uses a destroy-specific node type, though
+			// which one depends on whether we're destroying a current object
+			// or a deposed object.
+			var node GraphNodeResourceInstance
+			abstract := NewNodeAbstractResourceInstance(addr)
+			if dk == states.NotDeposed {
+				node = &NodeDestroyResourceInstance{
+					NodeAbstractResourceInstance: abstract,
+					DeposedKey:                   dk,
+				}
+			} else {
+				node = &NodeDestroyDeposedResourceInstanceObject{
+					NodeAbstractResourceInstance: abstract,
+					DeposedKey:                   dk,
+				}
+			}
+			if dk == states.NotDeposed {
+				log.Printf("[TRACE] DiffTransformer: %s will be represented for destruction by %s", addr, dag.VertexName(node))
+			} else {
+				log.Printf("[TRACE] DiffTransformer: %s deposed object %s will be represented for destruction by %s", addr, dk, dag.VertexName(node))
+			}
+			g.Add(node)
+		}
+
+	}
+
+	log.Printf("[TRACE] DiffTransformer complete")
+
+	return diags.Err()
+}
diff --git a/v1.5.7/internal/terraform/transform_diff_test.go b/v1.5.7/internal/terraform/transform_diff_test.go
new file mode 100644
index 0000000..68392c6
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_diff_test.go
@@ -0,0 +1,170 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/plans"
+)
+
+func TestDiffTransformer_nilDiff(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	tf := &DiffTransformer{}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if len(g.Vertices()) > 0 {
+		t.Fatal("graph should be empty")
+	}
+}
+
+func TestDiffTransformer(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+
+	beforeVal, err := plans.NewDynamicValue(cty.StringVal(""), cty.String)
+	if err != nil {
+		t.Fatal(err)
+	}
+	afterVal, err := plans.NewDynamicValue(cty.StringVal(""), cty.String)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	tf := &DiffTransformer{
+		Changes: &plans.Changes{
+			Resources: []*plans.ResourceInstanceChangeSrc{
+				{
+					Addr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "aws_instance",
+						Name: "foo",
+					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+					ProviderAddr: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("aws"),
+						Module:   addrs.RootModule,
+					},
+					ChangeSrc: plans.ChangeSrc{
+						Action: plans.Update,
+						Before: beforeVal,
+						After:  afterVal,
+					},
+				},
+			},
+		},
+	}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformDiffBasicStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+func TestDiffTransformer_noOpChange(t *testing.T) {
+	// "No-op" changes are how we record explicitly in a plan that we did
+	// indeed visit a particular resource instance during the planning phase
+	// and concluded that no changes were needed, as opposed to the resource
+	// instance not existing at all or having been excluded from planning
+	// entirely.
+	//
+	// We must include nodes for resource instances with no-op changes in the
+	// apply graph, even though they won't take any external actions, because
+	// there are some secondary effects such as precondition/postcondition
+	// checks that can refer to objects elsewhere and so might have their
+	// results changed even if the resource instance they are attached to
+	// didn't actually change directly itself.
+
+	// aws_instance.foo has a precondition, so should be included in the final
+	// graph. aws_instance.bar has no conditions, so there is nothing to
+	// execute during apply and it should not be included in the graph.
+	m := testModuleInline(t, map[string]string{
+		"main.tf": `
+resource "aws_instance" "bar" {
+}
+
+resource "aws_instance" "foo" {
+  test_string = "ok"
+
+  lifecycle {
+	precondition {
+		condition     = self.test_string != ""
+		error_message = "resource error"
+	}
+  }
+}
+`})
+
+	g := Graph{Path: addrs.RootModuleInstance}
+
+	beforeVal, err := plans.NewDynamicValue(cty.StringVal(""), cty.String)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	tf := &DiffTransformer{
+		Config: m,
+		Changes: &plans.Changes{
+			Resources: []*plans.ResourceInstanceChangeSrc{
+				{
+					Addr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "aws_instance",
+						Name: "foo",
+					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+					ProviderAddr: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("aws"),
+						Module:   addrs.RootModule,
+					},
+					ChangeSrc: plans.ChangeSrc{
+						// A "no-op" change has the no-op action and has the
+						// same object as both Before and After.
+						Action: plans.NoOp,
+						Before: beforeVal,
+						After:  beforeVal,
+					},
+				},
+				{
+					Addr: addrs.Resource{
+						Mode: addrs.ManagedResourceMode,
+						Type: "aws_instance",
+						Name: "bar",
+					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+					ProviderAddr: addrs.AbsProviderConfig{
+						Provider: addrs.NewDefaultProvider("aws"),
+						Module:   addrs.RootModule,
+					},
+					ChangeSrc: plans.ChangeSrc{
+						// A "no-op" change has the no-op action and has the
+						// same object as both Before and After.
+						Action: plans.NoOp,
+						Before: beforeVal,
+						After:  beforeVal,
+					},
+				},
+			},
+		},
+	}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformDiffBasicStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+const testTransformDiffBasicStr = `
+aws_instance.foo
+`
diff --git a/v1.5.7/internal/terraform/transform_expand.go b/v1.5.7/internal/terraform/transform_expand.go
new file mode 100644
index 0000000..76d7ef1
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_expand.go
@@ -0,0 +1,20 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+// GraphNodeDynamicExpandable is an interface that nodes can implement
+// to signal that they can be expanded at eval-time (hence dynamic).
+// These nodes are given the eval context and are expected to return
+// a new subgraph.
+type GraphNodeDynamicExpandable interface {
+	// DynamicExpand returns a new graph which will be treated as the dynamic
+	// subgraph of the receiving node.
+	//
+	// The second return value is of type error for historical reasons;
+	// it's valid (and most ideal) for DynamicExpand to return the result
+	// of calling ErrWithWarnings on a tfdiags.Diagnostics value instead,
+	// in which case the caller will unwrap it and gather the individual
+	// diagnostics.
+	DynamicExpand(EvalContext) (*Graph, error)
+}
diff --git a/v1.5.7/internal/terraform/transform_import_state_test.go b/v1.5.7/internal/terraform/transform_import_state_test.go
new file mode 100644
index 0000000..3229940
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_import_state_test.go
@@ -0,0 +1,170 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestGraphNodeImportStateExecute(t *testing.T) {
+	state := states.NewState()
+	provider := testProvider("aws")
+	provider.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
+		ImportedResources: []providers.ImportedResource{
+			{
+				TypeName: "aws_instance",
+				State: cty.ObjectVal(map[string]cty.Value{
+					"id": cty.StringVal("bar"),
+				}),
+			},
+		},
+	}
+	provider.ConfigureProvider(providers.ConfigureProviderRequest{})
+
+	ctx := &MockEvalContext{
+		StateState:       state.SyncWrapper(),
+		ProviderProvider: provider,
+	}
+
+	// Import a new aws_instance.foo, this time with ID=bar. The original
+	// aws_instance.foo object should be removed from state and replaced with
+	// the new.
+	node := graphNodeImportState{
+		Addr: addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "aws_instance",
+			Name: "foo",
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+		ID: "bar",
+		ResolvedProvider: addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("aws"),
+			Module:   addrs.RootModule,
+		},
+	}
+
+	diags := node.Execute(ctx, walkImport)
+	if diags.HasErrors() {
+		t.Fatalf("Unexpected error: %s", diags.Err())
+	}
+
+	if len(node.states) != 1 {
+		t.Fatalf("Wrong result! Expected one imported resource, got %d", len(node.states))
+	}
+	// Verify the ID for good measure
+	id := node.states[0].State.GetAttr("id")
+	if !id.RawEquals(cty.StringVal("bar")) {
+		t.Fatalf("Wrong result! Expected id \"bar\", got %q", id.AsString())
+	}
+}
+
+func TestGraphNodeImportStateSubExecute(t *testing.T) {
+	state := states.NewState()
+	provider := testProvider("aws")
+	provider.ConfigureProvider(providers.ConfigureProviderRequest{})
+	ctx := &MockEvalContext{
+		StateState:       state.SyncWrapper(),
+		ProviderProvider: provider,
+		ProviderSchemaSchema: &ProviderSchema{
+			ResourceTypes: map[string]*configschema.Block{
+				"aws_instance": {
+					Attributes: map[string]*configschema.Attribute{
+						"id": {
+							Type:     cty.String,
+							Computed: true,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	importedResource := providers.ImportedResource{
+		TypeName: "aws_instance",
+		State:    cty.ObjectVal(map[string]cty.Value{"id": cty.StringVal("bar")}),
+	}
+
+	node := graphNodeImportStateSub{
+		TargetAddr: addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "aws_instance",
+			Name: "foo",
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+		State: importedResource,
+		ResolvedProvider: addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("aws"),
+			Module:   addrs.RootModule,
+		},
+	}
+	diags := node.Execute(ctx, walkImport)
+	if diags.HasErrors() {
+		t.Fatalf("Unexpected error: %s", diags.Err())
+	}
+
+	// check for resource in state
+	actual := strings.TrimSpace(state.String())
+	expected := `aws_instance.foo:
+  ID = bar
+  provider = provider["registry.terraform.io/hashicorp/aws"]`
+	if actual != expected {
+		t.Fatalf("bad state after import: \n%s", actual)
+	}
+}
+
+func TestGraphNodeImportStateSubExecuteNull(t *testing.T) {
+	state := states.NewState()
+	provider := testProvider("aws")
+	provider.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
+		// return null indicating that the requested resource does not exist
+		resp.NewState = cty.NullVal(cty.Object(map[string]cty.Type{
+			"id": cty.String,
+		}))
+		return resp
+	}
+
+	ctx := &MockEvalContext{
+		StateState:       state.SyncWrapper(),
+		ProviderProvider: provider,
+		ProviderSchemaSchema: &ProviderSchema{
+			ResourceTypes: map[string]*configschema.Block{
+				"aws_instance": {
+					Attributes: map[string]*configschema.Attribute{
+						"id": {
+							Type:     cty.String,
+							Computed: true,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	importedResource := providers.ImportedResource{
+		TypeName: "aws_instance",
+		State:    cty.ObjectVal(map[string]cty.Value{"id": cty.StringVal("bar")}),
+	}
+
+	node := graphNodeImportStateSub{
+		TargetAddr: addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "aws_instance",
+			Name: "foo",
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+		State: importedResource,
+		ResolvedProvider: addrs.AbsProviderConfig{
+			Provider: addrs.NewDefaultProvider("aws"),
+			Module:   addrs.RootModule,
+		},
+	}
+	diags := node.Execute(ctx, walkImport)
+	if !diags.HasErrors() {
+		t.Fatal("expected error for non-existent resource")
+	}
+}
diff --git a/v1.5.7/internal/terraform/transform_local.go b/v1.5.7/internal/terraform/transform_local.go
new file mode 100644
index 0000000..b28da21
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_local.go
@@ -0,0 +1,45 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+)
+
+// LocalTransformer is a GraphTransformer that adds all the local values
+// from the configuration to the graph.
+type LocalTransformer struct {
+	Config *configs.Config
+}
+
+func (t *LocalTransformer) Transform(g *Graph) error {
+	return t.transformModule(g, t.Config)
+}
+
+func (t *LocalTransformer) transformModule(g *Graph, c *configs.Config) error {
+	if c == nil {
+		// Can't have any locals if there's no config
+		return nil
+	}
+
+	for _, local := range c.Module.Locals {
+		addr := addrs.LocalValue{Name: local.Name}
+		node := &nodeExpandLocal{
+			Addr:   addr,
+			Module: c.Path,
+			Config: local,
+		}
+		g.Add(node)
+	}
+
+	// Also populate locals for child modules
+	for _, cc := range c.Children {
+		if err := t.transformModule(g, cc); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_module_expansion.go b/v1.5.7/internal/terraform/transform_module_expansion.go
new file mode 100644
index 0000000..8e7ea94
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_module_expansion.go
@@ -0,0 +1,149 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+// ModuleExpansionTransformer is a GraphTransformer that adds graph nodes
+// representing the possible expansion of each module call in the configuration,
+// and ensures that any nodes representing objects declared within a module
+// are dependent on the expansion node so that they will be visited only
+// after the module expansion has been decided.
+//
+// This transform must be applied only after all nodes representing objects
+// that can be contained within modules have already been added.
+type ModuleExpansionTransformer struct {
+	Config *configs.Config
+
+	// Concrete allows injection of a wrapped module node by the graph builder
+	// to alter the evaluation behavior.
+	Concrete ConcreteModuleNodeFunc
+
+	closers map[string]*nodeCloseModule
+}
+
+func (t *ModuleExpansionTransformer) Transform(g *Graph) error {
+	t.closers = make(map[string]*nodeCloseModule)
+	// The root module is always a singleton and so does not need expansion
+	// processing, but any descendent modules do. We'll process them
+	// recursively using t.transform.
+	for _, cfg := range t.Config.Children {
+		err := t.transform(g, cfg, nil)
+		if err != nil {
+			return err
+		}
+	}
+
+	// Now go through and connect all nodes to their respective module closers.
+	// This is done all at once here, because orphaned modules were already
+	// handled by the RemovedModuleTransformer, and those module closers are in
+	// the graph already, and need to be connected to their parent closers.
+	for _, v := range g.Vertices() {
+		switch v.(type) {
+		case GraphNodeDestroyer:
+			// Destroy nodes can only be ordered relative to other resource
+			// instances.
+			continue
+		case *nodeCloseModule:
+			// a module closer cannot connect to itself
+			continue
+		}
+
+		// any node that executes within the scope of a module should be a
+		// GraphNodeModulePath
+		pather, ok := v.(GraphNodeModulePath)
+		if !ok {
+			continue
+		}
+		if closer, ok := t.closers[pather.ModulePath().String()]; ok {
+			// The module closer depends on each child resource instance, since
+			// during apply the module expansion will complete before the
+			// individual instances are applied.
+			g.Connect(dag.BasicEdge(closer, v))
+		}
+	}
+
+	// Modules implicitly depend on their child modules, so connect closers to
+	// other which contain their path.
+	for _, c := range t.closers {
+		for _, d := range t.closers {
+			if len(d.Addr) > len(c.Addr) && c.Addr.Equal(d.Addr[:len(c.Addr)]) {
+				g.Connect(dag.BasicEdge(c, d))
+			}
+		}
+	}
+
+	return nil
+}
+
+func (t *ModuleExpansionTransformer) transform(g *Graph, c *configs.Config, parentNode dag.Vertex) error {
+	_, call := c.Path.Call()
+	modCall := c.Parent.Module.ModuleCalls[call.Name]
+
+	n := &nodeExpandModule{
+		Addr:       c.Path,
+		Config:     c.Module,
+		ModuleCall: modCall,
+	}
+	var expander dag.Vertex = n
+	if t.Concrete != nil {
+		expander = t.Concrete(n)
+	}
+
+	g.Add(expander)
+	log.Printf("[TRACE] ModuleExpansionTransformer: Added %s as %T", c.Path, expander)
+
+	if parentNode != nil {
+		log.Printf("[TRACE] ModuleExpansionTransformer: %s must wait for expansion of %s", dag.VertexName(expander), dag.VertexName(parentNode))
+		g.Connect(dag.BasicEdge(expander, parentNode))
+	}
+
+	// Add the closer (which acts as the root module node) to provide a
+	// single exit point for the expanded module.
+	closer := &nodeCloseModule{
+		Addr: c.Path,
+	}
+	g.Add(closer)
+	g.Connect(dag.BasicEdge(closer, expander))
+	t.closers[c.Path.String()] = closer
+
+	for _, childV := range g.Vertices() {
+		// don't connect a node to itself
+		if childV == expander {
+			continue
+		}
+
+		var path addrs.Module
+		switch t := childV.(type) {
+		case GraphNodeDestroyer:
+			// skip destroyers, as they can only depend on other resources.
+			continue
+
+		case GraphNodeModulePath:
+			path = t.ModulePath()
+		default:
+			continue
+		}
+
+		if path.Equal(c.Path) {
+			log.Printf("[TRACE] ModuleExpansionTransformer: %s must wait for expansion of %s", dag.VertexName(childV), c.Path)
+			g.Connect(dag.BasicEdge(childV, expander))
+		}
+	}
+
+	// Also visit child modules, recursively.
+	for _, cc := range c.Children {
+		if err := t.transform(g, cc, expander); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_module_variable.go b/v1.5.7/internal/terraform/transform_module_variable.go
new file mode 100644
index 0000000..a4df222
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_module_variable.go
@@ -0,0 +1,115 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/configs"
+)
+
+// ModuleVariableTransformer is a GraphTransformer that adds all the variables
+// in the configuration to the graph.
+//
+// Any "variable" block present in any non-root module is included here, even
+// if a particular variable is not referenced from anywhere.
+//
+// The transform will produce errors if a call to a module does not conform
+// to the expected set of arguments, but this transformer is not in a good
+// position to return errors and so the validate walk should include specific
+// steps for validating module blocks, separate from this transform.
+type ModuleVariableTransformer struct {
+	Config *configs.Config
+}
+
+func (t *ModuleVariableTransformer) Transform(g *Graph) error {
+	return t.transform(g, nil, t.Config)
+}
+
+func (t *ModuleVariableTransformer) transform(g *Graph, parent, c *configs.Config) error {
+	// We can have no variables if we have no configuration.
+	if c == nil {
+		return nil
+	}
+
+	// Transform all the children first.
+	for _, cc := range c.Children {
+		if err := t.transform(g, c, cc); err != nil {
+			return err
+		}
+	}
+
+	// If we're processing anything other than the root module then we'll
+	// add graph nodes for variables defined inside. (Variables for the root
+	// module are dealt with in RootVariableTransformer).
+	// If we have a parent, we can determine if a module variable is being
+	// used, so we transform this.
+	if parent != nil {
+		if err := t.transformSingle(g, parent, c); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (t *ModuleVariableTransformer) transformSingle(g *Graph, parent, c *configs.Config) error {
+	_, call := c.Path.Call()
+
+	// Find the call in the parent module configuration, so we can get the
+	// expressions given for each input variable at the call site.
+	callConfig, exists := parent.Module.ModuleCalls[call.Name]
+	if !exists {
+		// This should never happen, since it indicates an improperly-constructed
+		// configuration tree.
+		panic(fmt.Errorf("no module call block found for %s", c.Path))
+	}
+
+	// We need to construct a schema for the expected call arguments based on
+	// the configured variables in our config, which we can then use to
+	// decode the content of the call block.
+	schema := &hcl.BodySchema{}
+	for _, v := range c.Module.Variables {
+		schema.Attributes = append(schema.Attributes, hcl.AttributeSchema{
+			Name:     v.Name,
+			Required: v.Default == cty.NilVal,
+		})
+	}
+
+	content, contentDiags := callConfig.Config.Content(schema)
+	if contentDiags.HasErrors() {
+		// Validation code elsewhere should deal with any errors before we
+		// get in here, but we'll report them out here just in case, to
+		// avoid crashes.
+		var diags tfdiags.Diagnostics
+		diags = diags.Append(contentDiags)
+		return diags.Err()
+	}
+
+	for _, v := range c.Module.Variables {
+		var expr hcl.Expression
+		if attr := content.Attributes[v.Name]; attr != nil {
+			expr = attr.Expr
+		}
+
+		// Add a plannable node, as the variable may expand
+		// during module expansion
+		node := &nodeExpandModuleVariable{
+			Addr: addrs.InputVariable{
+				Name: v.Name,
+			},
+			Module: c.Path,
+			Config: v,
+			Expr:   expr,
+		}
+		g.Add(node)
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_module_variable_test.go b/v1.5.7/internal/terraform/transform_module_variable_test.go
new file mode 100644
index 0000000..751a56b
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_module_variable_test.go
@@ -0,0 +1,70 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestModuleVariableTransformer(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	module := testModule(t, "transform-module-var-basic")
+
+	{
+		tf := &RootVariableTransformer{Config: module}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		tf := &ModuleVariableTransformer{Config: module}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformModuleVarBasicStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+func TestModuleVariableTransformer_nested(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	module := testModule(t, "transform-module-var-nested")
+
+	{
+		tf := &RootVariableTransformer{Config: module}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		tf := &ModuleVariableTransformer{Config: module}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformModuleVarNestedStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+const testTransformModuleVarBasicStr = `
+module.child.var.value (expand)
+`
+
+const testTransformModuleVarNestedStr = `
+module.child.module.child.var.value (expand)
+module.child.var.value (expand)
+`
diff --git a/v1.5.7/internal/terraform/transform_orphan_count.go b/v1.5.7/internal/terraform/transform_orphan_count.go
new file mode 100644
index 0000000..5f85f1d
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_orphan_count.go
@@ -0,0 +1,64 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// OrphanResourceInstanceCountTransformer is a GraphTransformer that adds orphans
+// for an expanded count to the graph. The determination of this depends
+// on the count argument given.
+//
+// Orphans are found by comparing the count to what is found in the state.
+// This transform assumes that if an element in the state is within the count
+// bounds given, that it is not an orphan.
+type OrphanResourceInstanceCountTransformer struct {
+	Concrete ConcreteResourceInstanceNodeFunc
+
+	Addr          addrs.AbsResource           // Addr of the resource to look for orphans
+	InstanceAddrs []addrs.AbsResourceInstance // Addresses that currently exist in config
+	State         *states.State               // Full global state
+}
+
+func (t *OrphanResourceInstanceCountTransformer) Transform(g *Graph) error {
+	rs := t.State.Resource(t.Addr)
+	if rs == nil {
+		return nil // Resource doesn't exist in state, so nothing to do!
+	}
+
+	// This is an O(n*m) analysis, which we accept for now because the
+	// number of instances of a single resource ought to always be small in any
+	// reasonable Terraform configuration.
+Have:
+	for key, inst := range rs.Instances {
+		// Instances which have no current objects (only one or more
+		// deposed objects) will be taken care of separately
+		if inst.Current == nil {
+			continue
+		}
+
+		thisAddr := rs.Addr.Instance(key)
+		for _, wantAddr := range t.InstanceAddrs {
+			if wantAddr.Equal(thisAddr) {
+				continue Have
+			}
+		}
+		// If thisAddr is not in t.InstanceAddrs then we've found an "orphan"
+
+		abstract := NewNodeAbstractResourceInstance(thisAddr)
+		var node dag.Vertex = abstract
+		if f := t.Concrete; f != nil {
+			node = f(abstract)
+		}
+		log.Printf("[TRACE] OrphanResourceInstanceCountTransformer: adding %s as %T", thisAddr, node)
+		g.Add(node)
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_orphan_count_test.go b/v1.5.7/internal/terraform/transform_orphan_count_test.go
new file mode 100644
index 0000000..4da96bd
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_orphan_count_test.go
@@ -0,0 +1,309 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestOrphanResourceCountTransformer(t *testing.T) {
+	state := states.NewState()
+	root := state.RootModule()
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.web").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	g := Graph{Path: addrs.RootModuleInstance}
+
+	{
+		tf := &OrphanResourceInstanceCountTransformer{
+			Concrete: testOrphanResourceConcreteFunc,
+			Addr: addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "foo",
+			),
+			InstanceAddrs: []addrs.AbsResourceInstance{mustResourceInstanceAddr("aws_instance.foo[0]")},
+			State:         state,
+		}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformOrphanResourceCountBasicStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+func TestOrphanResourceCountTransformer_zero(t *testing.T) {
+	state := states.NewState()
+	root := state.RootModule()
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.web").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	g := Graph{Path: addrs.RootModuleInstance}
+
+	{
+		tf := &OrphanResourceInstanceCountTransformer{
+			Concrete: testOrphanResourceConcreteFunc,
+			Addr: addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "foo",
+			),
+			InstanceAddrs: []addrs.AbsResourceInstance{},
+			State:         state,
+		}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformOrphanResourceCountZeroStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+func TestOrphanResourceCountTransformer_oneIndex(t *testing.T) {
+	state := states.NewState()
+	root := state.RootModule()
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.web").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	g := Graph{Path: addrs.RootModuleInstance}
+
+	{
+		tf := &OrphanResourceInstanceCountTransformer{
+			Concrete: testOrphanResourceConcreteFunc,
+			Addr: addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "foo",
+			),
+			InstanceAddrs: []addrs.AbsResourceInstance{mustResourceInstanceAddr("aws_instance.foo[0]")},
+			State:         state,
+		}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformOrphanResourceCountOneIndexStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+func TestOrphanResourceCountTransformer_deposed(t *testing.T) {
+	state := states.NewState()
+	root := state.RootModule()
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.web").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceCurrent(
+		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+	root.SetResourceInstanceDeposed(
+		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
+		states.NewDeposedKey(),
+		&states.ResourceInstanceObjectSrc{
+			Status:    states.ObjectReady,
+			AttrsJSON: []byte(`{"id":"foo"}`),
+		},
+		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+	)
+
+	g := Graph{Path: addrs.RootModuleInstance}
+
+	{
+		tf := &OrphanResourceInstanceCountTransformer{
+			Concrete: testOrphanResourceConcreteFunc,
+			Addr: addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "foo",
+			),
+			InstanceAddrs: []addrs.AbsResourceInstance{mustResourceInstanceAddr("aws_instance.foo[0]")},
+			State:         state,
+		}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformOrphanResourceCountDeposedStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+// When converting from a NoEach mode to an EachMap via a switch to for_each,
+// an edge is necessary to ensure that the map-key'd instances
+// are evaluated after the NoKey resource, because the final instance evaluated
+// sets the whole resource's EachMode.
+func TestOrphanResourceCountTransformer_ForEachEdgesAdded(t *testing.T) {
+	state := states.BuildState(func(s *states.SyncState) {
+		// "bar" key'd resource
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "foo",
+			}.Instance(addrs.StringKey("bar")).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsFlat: map[string]string{
+					"id": "foo",
+				},
+				Status: states.ObjectReady,
+			},
+			mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+		)
+
+		// NoKey'd resource
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsFlat: map[string]string{
+					"id": "foo",
+				},
+				Status: states.ObjectReady,
+			},
+			mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
+		)
+	})
+
+	g := Graph{Path: addrs.RootModuleInstance}
+
+	{
+		tf := &OrphanResourceInstanceCountTransformer{
+			Concrete: testOrphanResourceConcreteFunc,
+			Addr: addrs.RootModuleInstance.Resource(
+				addrs.ManagedResourceMode, "aws_instance", "foo",
+			),
+			InstanceAddrs: []addrs.AbsResourceInstance{},
+			State:         state,
+		}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformOrphanResourceForEachStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+const testTransformOrphanResourceCountBasicStr = `
+aws_instance.foo[2] (orphan)
+`
+
+const testTransformOrphanResourceCountZeroStr = `
+aws_instance.foo[0] (orphan)
+aws_instance.foo[2] (orphan)
+`
+
+const testTransformOrphanResourceCountOneIndexStr = `
+aws_instance.foo[1] (orphan)
+`
+
+const testTransformOrphanResourceCountDeposedStr = `
+aws_instance.foo[1] (orphan)
+`
+
+const testTransformOrphanResourceForEachStr = `
+aws_instance.foo (orphan)
+aws_instance.foo["bar"] (orphan)
+`
diff --git a/v1.5.7/internal/terraform/transform_orphan_output.go b/v1.5.7/internal/terraform/transform_orphan_output.go
new file mode 100644
index 0000000..da0b597
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_orphan_output.go
@@ -0,0 +1,65 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// OrphanOutputTransformer finds the outputs that aren't present
+// in the given config that are in the state and adds them to the graph
+// for deletion.
+type OrphanOutputTransformer struct {
+	Config   *configs.Config // Root of config tree
+	State    *states.State   // State is the root state
+	Planning bool
+}
+
+func (t *OrphanOutputTransformer) Transform(g *Graph) error {
+	if t.State == nil {
+		log.Printf("[DEBUG] No state, no orphan outputs")
+		return nil
+	}
+
+	for _, ms := range t.State.Modules {
+		if err := t.transform(g, ms); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (t *OrphanOutputTransformer) transform(g *Graph, ms *states.Module) error {
+	if ms == nil {
+		return nil
+	}
+
+	moduleAddr := ms.Addr
+
+	// Get the config for this path, which is nil if the entire module has been
+	// removed.
+	var outputs map[string]*configs.Output
+	if c := t.Config.DescendentForInstance(moduleAddr); c != nil {
+		outputs = c.Module.Outputs
+	}
+
+	// An output is "orphaned" if it's present in the state but not declared
+	// in the configuration.
+	for name := range ms.OutputValues {
+		if _, exists := outputs[name]; exists {
+			continue
+		}
+
+		g.Add(&NodeDestroyableOutput{
+			Addr:     addrs.OutputValue{Name: name}.Absolute(moduleAddr),
+			Planning: t.Planning,
+		})
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_orphan_resource.go b/v1.5.7/internal/terraform/transform_orphan_resource.go
new file mode 100644
index 0000000..f451978
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_orphan_resource.go
@@ -0,0 +1,111 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// OrphanResourceInstanceTransformer is a GraphTransformer that adds orphaned
+// resource instances to the graph. An "orphan" is an instance that is present
+// in the state but belongs to a resource that is no longer present in the
+// configuration.
+//
+// This is not the transformer that deals with "count orphans" (instances that
+// are no longer covered by a resource's "count" or "for_each" setting); that's
+// handled instead by OrphanResourceCountTransformer.
+type OrphanResourceInstanceTransformer struct {
+	Concrete ConcreteResourceInstanceNodeFunc
+
+	// State is the global state. We require the global state to
+	// properly find module orphans at our path.
+	State *states.State
+
+	// Config is the root node in the configuration tree. We'll look up
+	// the appropriate note in this tree using the path in each node.
+	Config *configs.Config
+
+	// Do not apply this transformer
+	skip bool
+}
+
+func (t *OrphanResourceInstanceTransformer) Transform(g *Graph) error {
+	if t.skip {
+		return nil
+	}
+
+	if t.State == nil {
+		// If the entire state is nil, there can't be any orphans
+		return nil
+	}
+	if t.Config == nil {
+		// Should never happen: we can't be doing any Terraform operations
+		// without at least an empty configuration.
+		panic("OrphanResourceInstanceTransformer used without setting Config")
+	}
+
+	// Go through the modules and for each module transform in order
+	// to add the orphan.
+	for _, ms := range t.State.Modules {
+		if err := t.transform(g, ms); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (t *OrphanResourceInstanceTransformer) transform(g *Graph, ms *states.Module) error {
+	if ms == nil {
+		return nil
+	}
+
+	moduleAddr := ms.Addr
+
+	// Get the configuration for this module. The configuration might be
+	// nil if the module was removed from the configuration. This is okay,
+	// this just means that every resource is an orphan.
+	var m *configs.Module
+	if c := t.Config.DescendentForInstance(moduleAddr); c != nil {
+		m = c.Module
+	}
+
+	// An "orphan" is a resource that is in the state but not the configuration,
+	// so we'll walk the state resources and try to correlate each of them
+	// with a configuration block. Each orphan gets a node in the graph whose
+	// type is decided by t.Concrete.
+	//
+	// We don't handle orphans related to changes in the "count" and "for_each"
+	// pseudo-arguments here. They are handled by OrphanResourceCountTransformer.
+	for _, rs := range ms.Resources {
+		if m != nil {
+			if r := m.ResourceByAddr(rs.Addr.Resource); r != nil {
+				continue
+			}
+		}
+
+		for key, inst := range rs.Instances {
+			// Instances which have no current objects (only one or more
+			// deposed objects) will be taken care of separately
+			if inst.Current == nil {
+				continue
+			}
+
+			addr := rs.Addr.Instance(key)
+			abstract := NewNodeAbstractResourceInstance(addr)
+			var node dag.Vertex = abstract
+			if f := t.Concrete; f != nil {
+				node = f(abstract)
+			}
+			log.Printf("[TRACE] OrphanResourceInstanceTransformer: adding single-instance orphan node for %s", addr)
+			g.Add(node)
+		}
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_orphan_resource_test.go b/v1.5.7/internal/terraform/transform_orphan_resource_test.go
new file mode 100644
index 0000000..647d211
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_orphan_resource_test.go
@@ -0,0 +1,329 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestOrphanResourceInstanceTransformer(t *testing.T) {
+	mod := testModule(t, "transform-orphan-basic")
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "web",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsFlat: map[string]string{
+					"id": "foo",
+				},
+				Status: states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+
+		// The orphan
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "db",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsFlat: map[string]string{
+					"id": "foo",
+				},
+				Status: states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+
+		// A deposed orphan should not be handled by this transformer
+		s.SetResourceInstanceDeposed(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "test_instance",
+				Name: "deposed",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			states.NewDeposedKey(),
+			&states.ResourceInstanceObjectSrc{
+				AttrsFlat: map[string]string{
+					"id": "foo",
+				},
+				Status: states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("test"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	g := Graph{Path: addrs.RootModuleInstance}
+	{
+		tf := &ConfigTransformer{Config: mod}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		tf := &OrphanResourceInstanceTransformer{
+			Concrete: testOrphanResourceConcreteFunc,
+			State:    state,
+			Config:   mod,
+		}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformOrphanResourceBasicStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+func TestOrphanResourceInstanceTransformer_countGood(t *testing.T) {
+	mod := testModule(t, "transform-orphan-count")
+
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "foo",
+			}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsFlat: map[string]string{
+					"id": "foo",
+				},
+				Status: states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "foo",
+			}.Instance(addrs.IntKey(1)).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsFlat: map[string]string{
+					"id": "foo",
+				},
+				Status: states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	g := Graph{Path: addrs.RootModuleInstance}
+	{
+		tf := &ConfigTransformer{Config: mod}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		tf := &OrphanResourceInstanceTransformer{
+			Concrete: testOrphanResourceConcreteFunc,
+			State:    state,
+			Config:   mod,
+		}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformOrphanResourceCountStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+func TestOrphanResourceInstanceTransformer_countBad(t *testing.T) {
+	mod := testModule(t, "transform-orphan-count-empty")
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "foo",
+			}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsFlat: map[string]string{
+					"id": "foo",
+				},
+				Status: states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "foo",
+			}.Instance(addrs.IntKey(1)).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsFlat: map[string]string{
+					"id": "foo",
+				},
+				Status: states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	g := Graph{Path: addrs.RootModuleInstance}
+	{
+		tf := &ConfigTransformer{Config: mod}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		tf := &OrphanResourceInstanceTransformer{
+			Concrete: testOrphanResourceConcreteFunc,
+			State:    state,
+			Config:   mod,
+		}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformOrphanResourceCountBadStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+func TestOrphanResourceInstanceTransformer_modules(t *testing.T) {
+	mod := testModule(t, "transform-orphan-modules")
+	state := states.BuildState(func(s *states.SyncState) {
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "foo",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+			&states.ResourceInstanceObjectSrc{
+				AttrsFlat: map[string]string{
+					"id": "foo",
+				},
+				Status: states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+		s.SetResourceInstanceCurrent(
+			addrs.Resource{
+				Mode: addrs.ManagedResourceMode,
+				Type: "aws_instance",
+				Name: "web",
+			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey)),
+			&states.ResourceInstanceObjectSrc{
+				AttrsFlat: map[string]string{
+					"id": "foo",
+				},
+				Status: states.ObjectReady,
+			},
+			addrs.AbsProviderConfig{
+				Provider: addrs.NewDefaultProvider("aws"),
+				Module:   addrs.RootModule,
+			},
+		)
+	})
+
+	g := Graph{Path: addrs.RootModuleInstance}
+	{
+		tf := &ConfigTransformer{Config: mod}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		tf := &OrphanResourceInstanceTransformer{
+			Concrete: testOrphanResourceConcreteFunc,
+			State:    state,
+			Config:   mod,
+		}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	got := strings.TrimSpace(g.String())
+	want := strings.TrimSpace(testTransformOrphanResourceModulesStr)
+	if got != want {
+		t.Fatalf("wrong state result\ngot:\n%s\n\nwant:\n%s", got, want)
+	}
+}
+
+const testTransformOrphanResourceBasicStr = `
+aws_instance.db (orphan)
+aws_instance.web
+`
+
+const testTransformOrphanResourceCountStr = `
+aws_instance.foo
+`
+
+const testTransformOrphanResourceCountBadStr = `
+aws_instance.foo[0] (orphan)
+aws_instance.foo[1] (orphan)
+`
+
+const testTransformOrphanResourceModulesStr = `
+aws_instance.foo
+module.child.aws_instance.web (orphan)
+`
+
+func testOrphanResourceConcreteFunc(a *NodeAbstractResourceInstance) dag.Vertex {
+	return &testOrphanResourceInstanceConcrete{a}
+}
+
+type testOrphanResourceInstanceConcrete struct {
+	*NodeAbstractResourceInstance
+}
+
+func (n *testOrphanResourceInstanceConcrete) Name() string {
+	return fmt.Sprintf("%s (orphan)", n.NodeAbstractResourceInstance.Name())
+}
diff --git a/v1.5.7/internal/terraform/transform_output.go b/v1.5.7/internal/terraform/transform_output.go
new file mode 100644
index 0000000..c0a96c0
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_output.go
@@ -0,0 +1,71 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+)
+
+// OutputTransformer is a GraphTransformer that adds all the outputs
+// in the configuration to the graph.
+//
+// This is done for the apply graph builder even if dependent nodes
+// aren't changing since there is no downside: the state will be available
+// even if the dependent items aren't changing.
+type OutputTransformer struct {
+	Config *configs.Config
+
+	// Refresh-only mode means that any failing output preconditions are
+	// reported as warnings rather than errors
+	RefreshOnly bool
+
+	// Planning must be set to true only when we're building a planning graph.
+	// It must be set to false whenever we're building an apply graph.
+	Planning bool
+
+	// If this is a planned destroy, root outputs are still in the configuration
+	// so we need to record that we wish to remove them.
+	Destroying bool
+}
+
+func (t *OutputTransformer) Transform(g *Graph) error {
+	return t.transform(g, t.Config)
+}
+
+func (t *OutputTransformer) transform(g *Graph, c *configs.Config) error {
+	// If we have no config then there can be no outputs.
+	if c == nil {
+		return nil
+	}
+
+	// Transform all the children. We must do this first because
+	// we can reference module outputs and they must show up in the
+	// reference map.
+	for _, cc := range c.Children {
+		if err := t.transform(g, cc); err != nil {
+			return err
+		}
+	}
+
+	for _, o := range c.Module.Outputs {
+		addr := addrs.OutputValue{Name: o.Name}
+
+		node := &nodeExpandOutput{
+			Addr:        addr,
+			Module:      c.Path,
+			Config:      o,
+			Destroying:  t.Destroying,
+			RefreshOnly: t.RefreshOnly,
+			Planning:    t.Planning,
+		}
+
+		log.Printf("[TRACE] OutputTransformer: adding %s as %T", o.Name, node)
+		g.Add(node)
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_provider.go b/v1.5.7/internal/terraform/transform_provider.go
new file mode 100644
index 0000000..82c951f
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_provider.go
@@ -0,0 +1,733 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+func transformProviders(concrete ConcreteProviderNodeFunc, config *configs.Config) GraphTransformer {
+	return GraphTransformMulti(
+		// Add providers from the config
+		&ProviderConfigTransformer{
+			Config:   config,
+			Concrete: concrete,
+		},
+		// Add any remaining missing providers
+		&MissingProviderTransformer{
+			Config:   config,
+			Concrete: concrete,
+		},
+		// Connect the providers
+		&ProviderTransformer{
+			Config: config,
+		},
+		// Remove unused providers and proxies
+		&PruneProviderTransformer{},
+	)
+}
+
+// GraphNodeProvider is an interface that nodes that can be a provider
+// must implement.
+//
+// ProviderAddr returns the address of the provider configuration this
+// satisfies, which is relative to the path returned by method Path().
+//
+// Name returns the full name of the provider in the config.
+type GraphNodeProvider interface {
+	GraphNodeModulePath
+	ProviderAddr() addrs.AbsProviderConfig
+	Name() string
+}
+
+// GraphNodeCloseProvider is an interface that nodes that can be a close
+// provider must implement. The CloseProviderName returned is the name of
+// the provider they satisfy.
+type GraphNodeCloseProvider interface {
+	GraphNodeModulePath
+	CloseProviderAddr() addrs.AbsProviderConfig
+}
+
+// GraphNodeProviderConsumer is an interface that nodes that require
+// a provider must implement. ProvidedBy must return the address of the provider
+// to use, which will be resolved to a configuration either in the same module
+// or in an ancestor module, with the resulting absolute address passed to
+// SetProvider.
+type GraphNodeProviderConsumer interface {
+	GraphNodeModulePath
+	// ProvidedBy returns the address of the provider configuration the node
+	// refers to, if available. The following value types may be returned:
+	//
+	//   nil + exact true: the node does not require a provider
+	// * addrs.LocalProviderConfig: the provider was set in the resource config
+	// * addrs.AbsProviderConfig + exact true: the provider configuration was
+	//   taken from the instance state.
+	// * addrs.AbsProviderConfig + exact false: no config or state; the returned
+	//   value is a default provider configuration address for the resource's
+	//   Provider
+	ProvidedBy() (addr addrs.ProviderConfig, exact bool)
+
+	// Provider() returns the Provider FQN for the node.
+	Provider() (provider addrs.Provider)
+
+	// Set the resolved provider address for this resource.
+	SetProvider(addrs.AbsProviderConfig)
+}
+
+// ProviderTransformer is a GraphTransformer that maps resources to providers
+// within the graph. This will error if there are any resources that don't map
+// to proper resources.
+type ProviderTransformer struct {
+	Config *configs.Config
+}
+
+func (t *ProviderTransformer) Transform(g *Graph) error {
+	// We need to find a provider configuration address for each resource
+	// either directly represented by a node or referenced by a node in
+	// the graph, and then create graph edges from provider to provider user
+	// so that the providers will get initialized first.
+
+	var diags tfdiags.Diagnostics
+
+	// To start, we'll collect the _requested_ provider addresses for each
+	// node, which we'll then resolve (handling provider inheritence, etc) in
+	// the next step.
+	// Our "requested" map is from graph vertices to string representations of
+	// provider config addresses (for deduping) to requests.
+	type ProviderRequest struct {
+		Addr  addrs.AbsProviderConfig
+		Exact bool // If true, inheritence from parent modules is not attempted
+	}
+	requested := map[dag.Vertex]map[string]ProviderRequest{}
+	needConfigured := map[string]addrs.AbsProviderConfig{}
+	for _, v := range g.Vertices() {
+		// Does the vertex _directly_ use a provider?
+		if pv, ok := v.(GraphNodeProviderConsumer); ok {
+			providerAddr, exact := pv.ProvidedBy()
+			if providerAddr == nil && exact {
+				// no provider is required
+				continue
+			}
+
+			requested[v] = make(map[string]ProviderRequest)
+
+			var absPc addrs.AbsProviderConfig
+
+			switch p := providerAddr.(type) {
+			case addrs.AbsProviderConfig:
+				// ProvidedBy() returns an AbsProviderConfig when the provider
+				// configuration is set in state, so we do not need to verify
+				// the FQN matches.
+				absPc = p
+
+				if exact {
+					log.Printf("[TRACE] ProviderTransformer: %s is provided by %s exactly", dag.VertexName(v), absPc)
+				}
+
+			case addrs.LocalProviderConfig:
+				// ProvidedBy() return a LocalProviderConfig when the resource
+				// contains a `provider` attribute
+				absPc.Provider = pv.Provider()
+				modPath := pv.ModulePath()
+				if t.Config == nil {
+					absPc.Module = modPath
+					absPc.Alias = p.Alias
+					break
+				}
+
+				absPc.Module = modPath
+				absPc.Alias = p.Alias
+
+			default:
+				// This should never happen; the case statements are meant to be exhaustive
+				panic(fmt.Sprintf("%s: provider for %s couldn't be determined", dag.VertexName(v), absPc))
+			}
+
+			requested[v][absPc.String()] = ProviderRequest{
+				Addr:  absPc,
+				Exact: exact,
+			}
+
+			// Direct references need the provider configured as well as initialized
+			needConfigured[absPc.String()] = absPc
+		}
+	}
+
+	// Now we'll go through all the requested addresses we just collected and
+	// figure out which _actual_ config address each belongs to, after resolving
+	// for provider inheritance and passing.
+	m := providerVertexMap(g)
+	for v, reqs := range requested {
+		for key, req := range reqs {
+			p := req.Addr
+			target := m[key]
+
+			_, ok := v.(GraphNodeModulePath)
+			if !ok && target == nil {
+				// No target and no path to traverse up from
+				diags = diags.Append(fmt.Errorf("%s: provider %s couldn't be found", dag.VertexName(v), p))
+				continue
+			}
+
+			if target != nil {
+				log.Printf("[TRACE] ProviderTransformer: exact match for %s serving %s", p, dag.VertexName(v))
+			}
+
+			// if we don't have a provider at this level, walk up the path looking for one,
+			// unless we were told to be exact.
+			if target == nil && !req.Exact {
+				for pp, ok := p.Inherited(); ok; pp, ok = pp.Inherited() {
+					key := pp.String()
+					target = m[key]
+					if target != nil {
+						log.Printf("[TRACE] ProviderTransformer: %s uses inherited configuration %s", dag.VertexName(v), pp)
+						break
+					}
+					log.Printf("[TRACE] ProviderTransformer: looking for %s to serve %s", pp, dag.VertexName(v))
+				}
+			}
+
+			// If this provider doesn't need to be configured then we can just
+			// stub it out with an init-only provider node, which will just
+			// start up the provider and fetch its schema.
+			if _, exists := needConfigured[key]; target == nil && !exists {
+				stubAddr := addrs.AbsProviderConfig{
+					Module:   addrs.RootModule,
+					Provider: p.Provider,
+				}
+				stub := &NodeEvalableProvider{
+					&NodeAbstractProvider{
+						Addr: stubAddr,
+					},
+				}
+				m[stubAddr.String()] = stub
+				log.Printf("[TRACE] ProviderTransformer: creating init-only node for %s", stubAddr)
+				target = stub
+				g.Add(target)
+			}
+
+			if target == nil {
+				diags = diags.Append(tfdiags.Sourceless(
+					tfdiags.Error,
+					"Provider configuration not present",
+					fmt.Sprintf(
+						"To work with %s its original provider configuration at %s is required, but it has been removed. This occurs when a provider configuration is removed while objects created by that provider still exist in the state. Re-add the provider configuration to destroy %s, after which you can remove the provider configuration again.",
+						dag.VertexName(v), p, dag.VertexName(v),
+					),
+				))
+				break
+			}
+
+			// see if this is a proxy provider pointing to another concrete config
+			if p, ok := target.(*graphNodeProxyProvider); ok {
+				g.Remove(p)
+				target = p.Target()
+			}
+
+			log.Printf("[DEBUG] ProviderTransformer: %q (%T) needs %s", dag.VertexName(v), v, dag.VertexName(target))
+			if pv, ok := v.(GraphNodeProviderConsumer); ok {
+				pv.SetProvider(target.ProviderAddr())
+			}
+			g.Connect(dag.BasicEdge(v, target))
+		}
+	}
+
+	return diags.Err()
+}
+
+// CloseProviderTransformer is a GraphTransformer that adds nodes to the
+// graph that will close open provider connections that aren't needed anymore.
+// A provider connection is not needed anymore once all depended resources
+// in the graph are evaluated.
+type CloseProviderTransformer struct{}
+
+func (t *CloseProviderTransformer) Transform(g *Graph) error {
+	pm := providerVertexMap(g)
+	cpm := make(map[string]*graphNodeCloseProvider)
+	var err error
+
+	for _, p := range pm {
+		key := p.ProviderAddr().String()
+
+		// get the close provider of this type if we alread created it
+		closer := cpm[key]
+
+		if closer == nil {
+			// create a closer for this provider type
+			closer = &graphNodeCloseProvider{Addr: p.ProviderAddr()}
+			g.Add(closer)
+			cpm[key] = closer
+		}
+
+		// Close node depends on the provider itself
+		// this is added unconditionally, so it will connect to all instances
+		// of the provider. Extra edges will be removed by transitive
+		// reduction.
+		g.Connect(dag.BasicEdge(closer, p))
+
+		// connect all the provider's resources to the close node
+		for _, s := range g.UpEdges(p) {
+			if _, ok := s.(GraphNodeProviderConsumer); ok {
+				g.Connect(dag.BasicEdge(closer, s))
+			}
+		}
+	}
+
+	return err
+}
+
+// MissingProviderTransformer is a GraphTransformer that adds to the graph
+// a node for each default provider configuration that is referenced by another
+// node but not already present in the graph.
+//
+// These "default" nodes are always added to the root module, regardless of
+// where they are requested. This is important because our inheritance
+// resolution behavior in ProviderTransformer will then treat these as a
+// last-ditch fallback after walking up the tree, rather than preferring them
+// as it would if they were placed in the same module as the requester.
+//
+// This transformer may create extra nodes that are not needed in practice,
+// due to overriding provider configurations in child modules.
+// PruneProviderTransformer can then remove these once ProviderTransformer
+// has resolved all of the inheritence, etc.
+type MissingProviderTransformer struct {
+	// MissingProviderTransformer needs the config to rule out _implied_ default providers
+	Config *configs.Config
+
+	// Concrete, if set, overrides how the providers are made.
+	Concrete ConcreteProviderNodeFunc
+}
+
+func (t *MissingProviderTransformer) Transform(g *Graph) error {
+	// Initialize factory
+	if t.Concrete == nil {
+		t.Concrete = func(a *NodeAbstractProvider) dag.Vertex {
+			return a
+		}
+	}
+
+	var err error
+	m := providerVertexMap(g)
+	for _, v := range g.Vertices() {
+		pv, ok := v.(GraphNodeProviderConsumer)
+		if !ok {
+			continue
+		}
+
+		// For our work here we actually care only about the provider type and
+		// we plan to place all default providers in the root module.
+		providerFqn := pv.Provider()
+
+		// We're going to create an implicit _default_ configuration for the
+		// referenced provider type in the _root_ module, ignoring all other
+		// aspects of the resource's declared provider address.
+		defaultAddr := addrs.RootModuleInstance.ProviderConfigDefault(providerFqn)
+		key := defaultAddr.String()
+		provider := m[key]
+
+		if provider != nil {
+			// There's already an explicit default configuration for this
+			// provider type in the root module, so we have nothing to do.
+			continue
+		}
+
+		log.Printf("[DEBUG] adding implicit provider configuration %s, implied first by %s", defaultAddr, dag.VertexName(v))
+
+		// create the missing top-level provider
+		provider = t.Concrete(&NodeAbstractProvider{
+			Addr: defaultAddr,
+		}).(GraphNodeProvider)
+
+		g.Add(provider)
+		m[key] = provider
+	}
+
+	return err
+}
+
+// PruneProviderTransformer removes any providers that are not actually used by
+// anything, and provider proxies. This avoids the provider being initialized
+// and configured.  This both saves resources but also avoids errors since
+// configuration may imply initialization which may require auth.
+type PruneProviderTransformer struct{}
+
+func (t *PruneProviderTransformer) Transform(g *Graph) error {
+	for _, v := range g.Vertices() {
+		// We only care about providers
+		_, ok := v.(GraphNodeProvider)
+		if !ok {
+			continue
+		}
+
+		// ProxyProviders will have up edges, but we're now done with them in the graph
+		if _, ok := v.(*graphNodeProxyProvider); ok {
+			log.Printf("[DEBUG] pruning proxy %s", dag.VertexName(v))
+			g.Remove(v)
+		}
+
+		// Remove providers with no dependencies.
+		if g.UpEdges(v).Len() == 0 {
+			log.Printf("[DEBUG] pruning unused %s", dag.VertexName(v))
+			g.Remove(v)
+		}
+	}
+
+	return nil
+}
+
+func providerVertexMap(g *Graph) map[string]GraphNodeProvider {
+	m := make(map[string]GraphNodeProvider)
+	for _, v := range g.Vertices() {
+		if pv, ok := v.(GraphNodeProvider); ok {
+			addr := pv.ProviderAddr()
+			m[addr.String()] = pv
+		}
+	}
+
+	return m
+}
+
+type graphNodeCloseProvider struct {
+	Addr addrs.AbsProviderConfig
+}
+
+var (
+	_ GraphNodeCloseProvider = (*graphNodeCloseProvider)(nil)
+	_ GraphNodeExecutable    = (*graphNodeCloseProvider)(nil)
+)
+
+func (n *graphNodeCloseProvider) Name() string {
+	return n.Addr.String() + " (close)"
+}
+
+// GraphNodeModulePath
+func (n *graphNodeCloseProvider) ModulePath() addrs.Module {
+	return n.Addr.Module
+}
+
+// GraphNodeExecutable impl.
+func (n *graphNodeCloseProvider) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
+	return diags.Append(ctx.CloseProvider(n.Addr))
+}
+
+func (n *graphNodeCloseProvider) CloseProviderAddr() addrs.AbsProviderConfig {
+	return n.Addr
+}
+
+// GraphNodeDotter impl.
+func (n *graphNodeCloseProvider) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
+	if !opts.Verbose {
+		return nil
+	}
+	return &dag.DotNode{
+		Name: name,
+		Attrs: map[string]string{
+			"label": n.Name(),
+			"shape": "diamond",
+		},
+	}
+}
+
+// graphNodeProxyProvider is a GraphNodeProvider implementation that is used to
+// store the name and value of a provider node for inheritance between modules.
+// These nodes are only used to store the data while loading the provider
+// configurations, and are removed after all the resources have been connected
+// to their providers.
+type graphNodeProxyProvider struct {
+	addr   addrs.AbsProviderConfig
+	target GraphNodeProvider
+}
+
+var (
+	_ GraphNodeModulePath = (*graphNodeProxyProvider)(nil)
+	_ GraphNodeProvider   = (*graphNodeProxyProvider)(nil)
+)
+
+func (n *graphNodeProxyProvider) ProviderAddr() addrs.AbsProviderConfig {
+	return n.addr
+}
+
+func (n *graphNodeProxyProvider) ModulePath() addrs.Module {
+	return n.addr.Module
+}
+
+func (n *graphNodeProxyProvider) Name() string {
+	return n.addr.String() + " (proxy)"
+}
+
+// find the concrete provider instance
+func (n *graphNodeProxyProvider) Target() GraphNodeProvider {
+	switch t := n.target.(type) {
+	case *graphNodeProxyProvider:
+		return t.Target()
+	default:
+		return n.target
+	}
+}
+
+// ProviderConfigTransformer adds all provider nodes from the configuration and
+// attaches the configs.
+type ProviderConfigTransformer struct {
+	Concrete ConcreteProviderNodeFunc
+
+	// each provider node is stored here so that the proxy nodes can look up
+	// their targets by name.
+	providers map[string]GraphNodeProvider
+	// record providers that can be overriden with a proxy
+	proxiable map[string]bool
+
+	// Config is the root node of the configuration tree to add providers from.
+	Config *configs.Config
+}
+
+func (t *ProviderConfigTransformer) Transform(g *Graph) error {
+	// If no configuration is given, we don't do anything
+	if t.Config == nil {
+		return nil
+	}
+
+	t.providers = make(map[string]GraphNodeProvider)
+	t.proxiable = make(map[string]bool)
+
+	// Start the transformation process
+	if err := t.transform(g, t.Config); err != nil {
+		return err
+	}
+
+	// finally attach the configs to the new nodes
+	return t.attachProviderConfigs(g)
+}
+
+func (t *ProviderConfigTransformer) transform(g *Graph, c *configs.Config) error {
+	// If no config, do nothing
+	if c == nil {
+		return nil
+	}
+
+	// Add our resources
+	if err := t.transformSingle(g, c); err != nil {
+		return err
+	}
+
+	// Transform all the children.
+	for _, cc := range c.Children {
+		if err := t.transform(g, cc); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (t *ProviderConfigTransformer) transformSingle(g *Graph, c *configs.Config) error {
+	// Get the module associated with this configuration tree node
+	mod := c.Module
+	path := c.Path
+
+	// If this is the root module, we can add nodes for required providers that
+	// have no configuration, equivalent to having an empty configuration
+	// block. This will ensure that a provider node exists for modules to
+	// access when passing around configuration and inheritance.
+	if path.IsRoot() && c.Module.ProviderRequirements != nil {
+		for name, p := range c.Module.ProviderRequirements.RequiredProviders {
+			if _, configured := mod.ProviderConfigs[name]; configured {
+				continue
+			}
+
+			addr := addrs.AbsProviderConfig{
+				Provider: p.Type,
+				Module:   path,
+			}
+
+			if _, ok := t.providers[addr.String()]; ok {
+				// The config validation warns about this too, but we can't
+				// completely prevent it in v1.
+				log.Printf("[WARN] ProviderConfigTransformer: duplicate required_providers entry for %s", addr)
+				continue
+			}
+
+			abstract := &NodeAbstractProvider{
+				Addr: addr,
+			}
+
+			var v dag.Vertex
+			if t.Concrete != nil {
+				v = t.Concrete(abstract)
+			} else {
+				v = abstract
+			}
+
+			g.Add(v)
+			t.providers[addr.String()] = v.(GraphNodeProvider)
+		}
+	}
+
+	// add all providers from the configuration
+	for _, p := range mod.ProviderConfigs {
+		fqn := mod.ProviderForLocalConfig(p.Addr())
+		addr := addrs.AbsProviderConfig{
+			Provider: fqn,
+			Alias:    p.Alias,
+			Module:   path,
+		}
+
+		if _, ok := t.providers[addr.String()]; ok {
+			// The abstract provider node may already have been added from the
+			// provider requirements.
+			log.Printf("[WARN] ProviderConfigTransformer: provider node %s already added", addr)
+			continue
+		}
+
+		abstract := &NodeAbstractProvider{
+			Addr: addr,
+		}
+		var v dag.Vertex
+		if t.Concrete != nil {
+			v = t.Concrete(abstract)
+		} else {
+			v = abstract
+		}
+
+		// Add it to the graph
+		g.Add(v)
+		key := addr.String()
+		t.providers[key] = v.(GraphNodeProvider)
+
+		// While deprecated, we still accept empty configuration blocks within
+		// modules as being a possible proxy for passed configuration.
+		if !path.IsRoot() {
+			// A provider configuration is "proxyable" if its configuration is
+			// entirely empty. This means it's standing in for a provider
+			// configuration that must be passed in from the parent module.
+			// We decide this by evaluating the config with an empty schema;
+			// if this succeeds, then we know there's nothing in the body.
+			_, diags := p.Config.Content(&hcl.BodySchema{})
+			t.proxiable[key] = !diags.HasErrors()
+		}
+	}
+
+	// Now replace the provider nodes with proxy nodes if a provider was being
+	// passed in, and create implicit proxies if there was no config. Any extra
+	// proxies will be removed in the prune step.
+	return t.addProxyProviders(g, c)
+}
+
+func (t *ProviderConfigTransformer) addProxyProviders(g *Graph, c *configs.Config) error {
+	path := c.Path
+
+	// can't add proxies at the root
+	if path.IsRoot() {
+		return nil
+	}
+
+	parentPath, callAddr := path.Call()
+	parent := c.Parent
+	if parent == nil {
+		return nil
+	}
+
+	callName := callAddr.Name
+	var parentCfg *configs.ModuleCall
+	for name, mod := range parent.Module.ModuleCalls {
+		if name == callName {
+			parentCfg = mod
+			break
+		}
+	}
+
+	if parentCfg == nil {
+		// this can't really happen during normal execution.
+		return fmt.Errorf("parent module config not found for %s", c.Path.String())
+	}
+
+	// Go through all the providers the parent is passing in, and add proxies to
+	// the parent provider nodes.
+	for _, pair := range parentCfg.Providers {
+		fqn := c.Module.ProviderForLocalConfig(pair.InChild.Addr())
+		fullAddr := addrs.AbsProviderConfig{
+			Provider: fqn,
+			Module:   path,
+			Alias:    pair.InChild.Addr().Alias,
+		}
+
+		fullParentAddr := addrs.AbsProviderConfig{
+			Provider: fqn,
+			Module:   parentPath,
+			Alias:    pair.InParent.Addr().Alias,
+		}
+
+		fullName := fullAddr.String()
+		fullParentName := fullParentAddr.String()
+
+		parentProvider := t.providers[fullParentName]
+
+		if parentProvider == nil {
+			return fmt.Errorf("missing provider %s", fullParentName)
+		}
+
+		proxy := &graphNodeProxyProvider{
+			addr:   fullAddr,
+			target: parentProvider,
+		}
+
+		concreteProvider := t.providers[fullName]
+
+		// replace the concrete node with the provider passed in only if it is
+		// proxyable
+		if concreteProvider != nil {
+			if t.proxiable[fullName] {
+				g.Replace(concreteProvider, proxy)
+				t.providers[fullName] = proxy
+			}
+			continue
+		}
+
+		// There was no concrete provider, so add this as an implicit provider.
+		// The extra proxy will be pruned later if it's unused.
+		g.Add(proxy)
+		t.providers[fullName] = proxy
+	}
+
+	return nil
+}
+
+func (t *ProviderConfigTransformer) attachProviderConfigs(g *Graph) error {
+	for _, v := range g.Vertices() {
+		// Only care about GraphNodeAttachProvider implementations
+		apn, ok := v.(GraphNodeAttachProvider)
+		if !ok {
+			continue
+		}
+
+		// Determine what we're looking for
+		addr := apn.ProviderAddr()
+
+		// Get the configuration.
+		mc := t.Config.Descendent(addr.Module)
+		if mc == nil {
+			log.Printf("[TRACE] ProviderConfigTransformer: no configuration available for %s", addr.String())
+			continue
+		}
+
+		// Find the localName for the provider fqn
+		localName := mc.Module.LocalNameForProvider(addr.Provider)
+
+		// Go through the provider configs to find the matching config
+		for _, p := range mc.Module.ProviderConfigs {
+			if p.Name == localName && p.Alias == addr.Alias {
+				log.Printf("[TRACE] ProviderConfigTransformer: attaching to %q provider configuration from %s", dag.VertexName(v), p.DeclRange)
+				apn.AttachProvider(p)
+				break
+			}
+		}
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_provider_test.go b/v1.5.7/internal/terraform/transform_provider_test.go
new file mode 100644
index 0000000..9adcb61
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_provider_test.go
@@ -0,0 +1,494 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+func testProviderTransformerGraph(t *testing.T, cfg *configs.Config) *Graph {
+	t.Helper()
+
+	g := &Graph{Path: addrs.RootModuleInstance}
+	ct := &ConfigTransformer{Config: cfg}
+	if err := ct.Transform(g); err != nil {
+		t.Fatal(err)
+	}
+	arct := &AttachResourceConfigTransformer{Config: cfg}
+	if err := arct.Transform(g); err != nil {
+		t.Fatal(err)
+	}
+
+	return g
+}
+
+func TestProviderTransformer(t *testing.T) {
+	mod := testModule(t, "transform-provider-basic")
+
+	g := testProviderTransformerGraph(t, mod)
+	{
+		transform := &MissingProviderTransformer{}
+		if err := transform.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	transform := &ProviderTransformer{}
+	if err := transform.Transform(g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformProviderBasicStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+// Test providers with FQNs that do not match the typeName
+func TestProviderTransformer_fqns(t *testing.T) {
+	for _, mod := range []string{"fqns", "fqns-module"} {
+		mod := testModule(t, fmt.Sprintf("transform-provider-%s", mod))
+
+		g := testProviderTransformerGraph(t, mod)
+		{
+			transform := &MissingProviderTransformer{Config: mod}
+			if err := transform.Transform(g); err != nil {
+				t.Fatalf("err: %s", err)
+			}
+		}
+
+		transform := &ProviderTransformer{Config: mod}
+		if err := transform.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		actual := strings.TrimSpace(g.String())
+		expected := strings.TrimSpace(testTransformProviderBasicStr)
+		if actual != expected {
+			t.Fatalf("bad:\n\n%s", actual)
+		}
+	}
+}
+
+func TestCloseProviderTransformer(t *testing.T) {
+	mod := testModule(t, "transform-provider-basic")
+	g := testProviderTransformerGraph(t, mod)
+
+	{
+		transform := &MissingProviderTransformer{}
+		if err := transform.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		transform := &ProviderTransformer{}
+		if err := transform.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		transform := &CloseProviderTransformer{}
+		if err := transform.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformCloseProviderBasicStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+func TestCloseProviderTransformer_withTargets(t *testing.T) {
+	mod := testModule(t, "transform-provider-basic")
+
+	g := testProviderTransformerGraph(t, mod)
+	transforms := []GraphTransformer{
+		&MissingProviderTransformer{},
+		&ProviderTransformer{},
+		&CloseProviderTransformer{},
+		&TargetsTransformer{
+			Targets: []addrs.Targetable{
+				addrs.RootModuleInstance.Resource(
+					addrs.ManagedResourceMode, "something", "else",
+				),
+			},
+		},
+	}
+
+	for _, tr := range transforms {
+		if err := tr.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(``)
+	if actual != expected {
+		t.Fatalf("expected:%s\n\ngot:\n\n%s", expected, actual)
+	}
+}
+
+func TestMissingProviderTransformer(t *testing.T) {
+	mod := testModule(t, "transform-provider-missing")
+
+	g := testProviderTransformerGraph(t, mod)
+	{
+		transform := &MissingProviderTransformer{}
+		if err := transform.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		transform := &ProviderTransformer{}
+		if err := transform.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		transform := &CloseProviderTransformer{}
+		if err := transform.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformMissingProviderBasicStr)
+	if actual != expected {
+		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
+	}
+}
+
+func TestMissingProviderTransformer_grandchildMissing(t *testing.T) {
+	mod := testModule(t, "transform-provider-missing-grandchild")
+
+	concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
+
+	g := testProviderTransformerGraph(t, mod)
+	{
+		transform := transformProviders(concrete, mod)
+		if err := transform.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+	{
+		transform := &TransitiveReductionTransformer{}
+		if err := transform.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformMissingGrandchildProviderStr)
+	if actual != expected {
+		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
+	}
+}
+
+func TestPruneProviderTransformer(t *testing.T) {
+	mod := testModule(t, "transform-provider-prune")
+
+	g := testProviderTransformerGraph(t, mod)
+	{
+		transform := &MissingProviderTransformer{}
+		if err := transform.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		transform := &ProviderTransformer{}
+		if err := transform.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		transform := &CloseProviderTransformer{}
+		if err := transform.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		transform := &PruneProviderTransformer{}
+		if err := transform.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformPruneProviderBasicStr)
+	if actual != expected {
+		t.Fatalf("bad:\n\n%s", actual)
+	}
+}
+
+// the child module resource is attached to the configured parent provider
+func TestProviderConfigTransformer_parentProviders(t *testing.T) {
+	mod := testModule(t, "transform-provider-inherit")
+	concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
+
+	g := testProviderTransformerGraph(t, mod)
+	{
+		tf := transformProviders(concrete, mod)
+		if err := tf.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformModuleProviderConfigStr)
+	if actual != expected {
+		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
+	}
+}
+
+// the child module resource is attached to the configured grand-parent provider
+func TestProviderConfigTransformer_grandparentProviders(t *testing.T) {
+	mod := testModule(t, "transform-provider-grandchild-inherit")
+	concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
+
+	g := testProviderTransformerGraph(t, mod)
+	{
+		tf := transformProviders(concrete, mod)
+		if err := tf.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformModuleProviderGrandparentStr)
+	if actual != expected {
+		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
+	}
+}
+
+func TestProviderConfigTransformer_inheritOldSkool(t *testing.T) {
+	mod := testModuleInline(t, map[string]string{
+		"main.tf": `
+provider "test" {
+  test_string = "config"
+}
+
+module "moda" {
+  source = "./moda"
+}
+`,
+
+		"moda/main.tf": `
+resource "test_object" "a" {
+}
+`,
+	})
+	concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
+
+	g := testProviderTransformerGraph(t, mod)
+	{
+		tf := transformProviders(concrete, mod)
+		if err := tf.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	expected := `module.moda.test_object.a
+  provider["registry.terraform.io/hashicorp/test"]
+provider["registry.terraform.io/hashicorp/test"]`
+
+	actual := strings.TrimSpace(g.String())
+	if actual != expected {
+		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
+	}
+}
+
+// Verify that configurations which are not recommended yet supported still work
+func TestProviderConfigTransformer_nestedModuleProviders(t *testing.T) {
+	mod := testModuleInline(t, map[string]string{
+		"main.tf": `
+terraform {
+  required_providers {
+    test = {
+      source = "registry.terraform.io/hashicorp/test"
+	}
+  }
+}
+
+provider "test" {
+  alias = "z"
+  test_string = "config"
+}
+
+module "moda" {
+  source = "./moda"
+  providers = {
+    test.x = test.z
+  }
+}
+`,
+
+		"moda/main.tf": `
+terraform {
+  required_providers {
+    test = {
+      source = "registry.terraform.io/hashicorp/test"
+      configuration_aliases = [ test.x ]
+	}
+  }
+}
+
+provider "test" {
+  test_string = "config"
+}
+
+// this should connect to this module's provider
+resource "test_object" "a" {
+}
+
+resource "test_object" "x" {
+  provider = test.x
+}
+
+module "modb" {
+  source = "./modb"
+}
+`,
+
+		"moda/modb/main.tf": `
+# this should end up with the provider from the parent module
+resource "test_object" "a" {
+}
+`,
+	})
+	concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
+
+	g := testProviderTransformerGraph(t, mod)
+	{
+		tf := transformProviders(concrete, mod)
+		if err := tf.Transform(g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	expected := `module.moda.module.modb.test_object.a
+  module.moda.provider["registry.terraform.io/hashicorp/test"]
+module.moda.provider["registry.terraform.io/hashicorp/test"]
+module.moda.test_object.a
+  module.moda.provider["registry.terraform.io/hashicorp/test"]
+module.moda.test_object.x
+  provider["registry.terraform.io/hashicorp/test"].z
+provider["registry.terraform.io/hashicorp/test"].z`
+
+	actual := strings.TrimSpace(g.String())
+	if actual != expected {
+		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
+	}
+}
+
+func TestProviderConfigTransformer_duplicateLocalName(t *testing.T) {
+	mod := testModuleInline(t, map[string]string{
+		"main.tf": `
+terraform {
+  required_providers {
+	# We have to allow this since it wasn't previously prevented. If the
+	# default config is equivalent to the provider config, the user may never
+	# see an error.
+    dupe = {
+      source = "registry.terraform.io/hashicorp/test"
+    }
+  }
+}
+
+provider "test" {
+}
+`})
+	concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
+
+	g := testProviderTransformerGraph(t, mod)
+	tf := ProviderConfigTransformer{
+		Config:   mod,
+		Concrete: concrete,
+	}
+	if err := tf.Transform(g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	expected := `provider["registry.terraform.io/hashicorp/test"]`
+
+	actual := strings.TrimSpace(g.String())
+	if actual != expected {
+		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
+	}
+}
+
+const testTransformProviderBasicStr = `
+aws_instance.web
+  provider["registry.terraform.io/hashicorp/aws"]
+provider["registry.terraform.io/hashicorp/aws"]
+`
+
+const testTransformCloseProviderBasicStr = `
+aws_instance.web
+  provider["registry.terraform.io/hashicorp/aws"]
+provider["registry.terraform.io/hashicorp/aws"]
+provider["registry.terraform.io/hashicorp/aws"] (close)
+  aws_instance.web
+  provider["registry.terraform.io/hashicorp/aws"]
+`
+
+const testTransformMissingProviderBasicStr = `
+aws_instance.web
+  provider["registry.terraform.io/hashicorp/aws"]
+foo_instance.web
+  provider["registry.terraform.io/hashicorp/foo"]
+provider["registry.terraform.io/hashicorp/aws"]
+provider["registry.terraform.io/hashicorp/aws"] (close)
+  aws_instance.web
+  provider["registry.terraform.io/hashicorp/aws"]
+provider["registry.terraform.io/hashicorp/foo"]
+provider["registry.terraform.io/hashicorp/foo"] (close)
+  foo_instance.web
+  provider["registry.terraform.io/hashicorp/foo"]
+`
+
+const testTransformMissingGrandchildProviderStr = `
+module.sub.module.subsub.bar_instance.two
+  provider["registry.terraform.io/hashicorp/bar"]
+module.sub.module.subsub.foo_instance.one
+  module.sub.provider["registry.terraform.io/hashicorp/foo"]
+module.sub.provider["registry.terraform.io/hashicorp/foo"]
+provider["registry.terraform.io/hashicorp/bar"]
+`
+
+const testTransformPruneProviderBasicStr = `
+foo_instance.web
+  provider["registry.terraform.io/hashicorp/foo"]
+provider["registry.terraform.io/hashicorp/foo"]
+provider["registry.terraform.io/hashicorp/foo"] (close)
+  foo_instance.web
+  provider["registry.terraform.io/hashicorp/foo"]
+`
+
+const testTransformModuleProviderConfigStr = `
+module.child.aws_instance.thing
+  provider["registry.terraform.io/hashicorp/aws"].foo
+provider["registry.terraform.io/hashicorp/aws"].foo
+`
+
+const testTransformModuleProviderGrandparentStr = `
+module.child.module.grandchild.aws_instance.baz
+  provider["registry.terraform.io/hashicorp/aws"].foo
+provider["registry.terraform.io/hashicorp/aws"].foo
+`
diff --git a/v1.5.7/internal/terraform/transform_provisioner.go b/v1.5.7/internal/terraform/transform_provisioner.go
new file mode 100644
index 0000000..8669e73
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_provisioner.go
@@ -0,0 +1,11 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+// GraphNodeProvisionerConsumer is an interface that nodes that require
+// a provisioner must implement. ProvisionedBy must return the names of the
+// provisioners to use.
+type GraphNodeProvisionerConsumer interface {
+	ProvisionedBy() []string
+}
diff --git a/v1.5.7/internal/terraform/transform_reference.go b/v1.5.7/internal/terraform/transform_reference.go
new file mode 100644
index 0000000..7a5f76a
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_reference.go
@@ -0,0 +1,560 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"log"
+	"sort"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/dag"
+	"github.com/hashicorp/terraform/internal/lang"
+)
+
+// GraphNodeReferenceable must be implemented by any node that represents
+// a Terraform thing that can be referenced (resource, module, etc.).
+//
+// Even if the thing has no name, this should return an empty list. By
+// implementing this and returning a non-nil result, you say that this CAN
+// be referenced and other methods of referencing may still be possible (such
+// as by path!)
+type GraphNodeReferenceable interface {
+	GraphNodeModulePath
+
+	// ReferenceableAddrs returns a list of addresses through which this can be
+	// referenced.
+	ReferenceableAddrs() []addrs.Referenceable
+}
+
+// GraphNodeReferencer must be implemented by nodes that reference other
+// Terraform items and therefore depend on them.
+type GraphNodeReferencer interface {
+	GraphNodeModulePath
+
+	// References returns a list of references made by this node, which
+	// include both a referenced address and source location information for
+	// the reference.
+	References() []*addrs.Reference
+}
+
+type GraphNodeAttachDependencies interface {
+	GraphNodeConfigResource
+	AttachDependencies([]addrs.ConfigResource)
+}
+
+// graphNodeDependsOn is implemented by resources that need to expose any
+// references set via DependsOn in their configuration.
+type graphNodeDependsOn interface {
+	GraphNodeReferencer
+	DependsOn() []*addrs.Reference
+}
+
+// graphNodeAttachDataResourceDependsOn records all resources that are transitively
+// referenced through depends_on in the configuration. This is used by data
+// resources to determine if they can be read during the plan, or if they need
+// to be further delayed until apply.
+// We can only use an addrs.ConfigResource address here, because modules are
+// not yet expended in the graph. While this will cause some extra data
+// resources to show in the plan when their depends_on references may be in
+// unrelated module instances, the fact that it only happens when there are any
+// resource updates pending means we can still avoid the problem of the
+// "perpetual diff"
+type graphNodeAttachDataResourceDependsOn interface {
+	GraphNodeConfigResource
+	graphNodeDependsOn
+
+	// AttachDataResourceDependsOn stores the discovered dependencies in the
+	// resource node for evaluation later.
+	//
+	// The force parameter indicates that even if there are no dependencies,
+	// force the data source to act as though there are for refresh purposes.
+	// This is needed because yet-to-be-created resources won't be in the
+	// initial refresh graph, but may still be referenced through depends_on.
+	AttachDataResourceDependsOn(deps []addrs.ConfigResource, force bool)
+}
+
+// GraphNodeReferenceOutside is an interface that can optionally be implemented.
+// A node that implements it can specify that its own referenceable addresses
+// and/or the addresses it references are in a different module than the
+// node itself.
+//
+// Any referenceable addresses returned by ReferenceableAddrs are interpreted
+// relative to the returned selfPath.
+//
+// Any references returned by References are interpreted relative to the
+// returned referencePath.
+//
+// It is valid but not required for either of these paths to match what is
+// returned by method Path, though if both match the main Path then there
+// is no reason to implement this method.
+//
+// The primary use-case for this is the nodes representing module input
+// variables, since their expressions are resolved in terms of their calling
+// module, but they are still referenced from their own module.
+type GraphNodeReferenceOutside interface {
+	// ReferenceOutside returns a path in which any references from this node
+	// are resolved.
+	ReferenceOutside() (selfPath, referencePath addrs.Module)
+}
+
+// ReferenceTransformer is a GraphTransformer that connects all the
+// nodes that reference each other in order to form the proper ordering.
+type ReferenceTransformer struct{}
+
+func (t *ReferenceTransformer) Transform(g *Graph) error {
+	// Build a reference map so we can efficiently look up the references
+	vs := g.Vertices()
+	m := NewReferenceMap(vs)
+
+	// Find the things that reference things and connect them
+	for _, v := range vs {
+		if _, ok := v.(GraphNodeDestroyer); ok {
+			// destroy nodes references are not connected, since they can only
+			// use their own state.
+			continue
+		}
+
+		parents := m.References(v)
+		parentsDbg := make([]string, len(parents))
+		for i, v := range parents {
+			parentsDbg[i] = dag.VertexName(v)
+		}
+		log.Printf(
+			"[DEBUG] ReferenceTransformer: %q references: %v",
+			dag.VertexName(v), parentsDbg)
+
+		for _, parent := range parents {
+			// A destroy plan relies solely on the state, so we only need to
+			// ensure that temporary values are connected to get the evaluation
+			// order correct. Any references to destroy nodes will cause
+			// cycles, because they are connected in reverse order.
+			if _, ok := parent.(GraphNodeDestroyer); ok {
+				continue
+			}
+
+			if !graphNodesAreResourceInstancesInDifferentInstancesOfSameModule(v, parent) {
+				g.Connect(dag.BasicEdge(v, parent))
+			} else {
+				log.Printf("[TRACE] ReferenceTransformer: skipping %s => %s inter-module-instance dependency", dag.VertexName(v), dag.VertexName(parent))
+			}
+		}
+
+		if len(parents) > 0 {
+			continue
+		}
+	}
+
+	return nil
+}
+
+type depMap map[string]addrs.ConfigResource
+
+// add stores the vertex if it represents a resource in the
+// graph.
+func (m depMap) add(v dag.Vertex) {
+	// we're only concerned with resources which may have changes that
+	// need to be applied.
+	switch v := v.(type) {
+	case GraphNodeResourceInstance:
+		instAddr := v.ResourceInstanceAddr()
+		addr := instAddr.ContainingResource().Config()
+		m[addr.String()] = addr
+	case GraphNodeConfigResource:
+		addr := v.ResourceAddr()
+		m[addr.String()] = addr
+	}
+}
+
+// attachDataResourceDependsOnTransformer records all resources transitively
+// referenced through a configuration depends_on.
+type attachDataResourceDependsOnTransformer struct {
+}
+
+func (t attachDataResourceDependsOnTransformer) Transform(g *Graph) error {
+	// First we need to make a map of referenceable addresses to their vertices.
+	// This is very similar to what's done in ReferenceTransformer, but we keep
+	// implementation separate as they may need to change independently.
+	vertices := g.Vertices()
+	refMap := NewReferenceMap(vertices)
+
+	for _, v := range vertices {
+		depender, ok := v.(graphNodeAttachDataResourceDependsOn)
+		if !ok {
+			continue
+		}
+
+		// Only data need to attach depends_on, so they can determine if they
+		// are eligible to be read during plan.
+		if depender.ResourceAddr().Resource.Mode != addrs.DataResourceMode {
+			continue
+		}
+
+		// depMap will only add resource references then dedupe
+		deps := make(depMap)
+		dependsOnDeps, fromModule := refMap.dependsOn(g, depender)
+		for _, dep := range dependsOnDeps {
+			// any the dependency
+			deps.add(dep)
+		}
+
+		res := make([]addrs.ConfigResource, 0, len(deps))
+		for _, d := range deps {
+			res = append(res, d)
+		}
+
+		log.Printf("[TRACE] attachDataDependenciesTransformer: %s depends on %s", depender.ResourceAddr(), res)
+		depender.AttachDataResourceDependsOn(res, fromModule)
+	}
+
+	return nil
+}
+
+// AttachDependenciesTransformer records all resource dependencies for each
+// instance, and attaches the addresses to the node itself. Managed resource
+// will record these in the state for proper ordering of destroy operations.
+type AttachDependenciesTransformer struct {
+}
+
+func (t AttachDependenciesTransformer) Transform(g *Graph) error {
+	for _, v := range g.Vertices() {
+		attacher, ok := v.(GraphNodeAttachDependencies)
+		if !ok {
+			continue
+		}
+		selfAddr := attacher.ResourceAddr()
+
+		ans, err := g.Ancestors(v)
+		if err != nil {
+			return err
+		}
+
+		// dedupe addrs when there's multiple instances involved, or
+		// multiple paths in the un-reduced graph
+		depMap := map[string]addrs.ConfigResource{}
+		for _, d := range ans {
+			var addr addrs.ConfigResource
+
+			switch d := d.(type) {
+			case GraphNodeResourceInstance:
+				instAddr := d.ResourceInstanceAddr()
+				addr = instAddr.ContainingResource().Config()
+			case GraphNodeConfigResource:
+				addr = d.ResourceAddr()
+			default:
+				continue
+			}
+
+			if addr.Equal(selfAddr) {
+				continue
+			}
+			depMap[addr.String()] = addr
+		}
+
+		deps := make([]addrs.ConfigResource, 0, len(depMap))
+		for _, d := range depMap {
+			deps = append(deps, d)
+		}
+		sort.Slice(deps, func(i, j int) bool {
+			return deps[i].String() < deps[j].String()
+		})
+
+		log.Printf("[TRACE] AttachDependenciesTransformer: %s depends on %s", attacher.ResourceAddr(), deps)
+		attacher.AttachDependencies(deps)
+	}
+
+	return nil
+}
+
+func isDependableResource(v dag.Vertex) bool {
+	switch v.(type) {
+	case GraphNodeResourceInstance:
+		return true
+	case GraphNodeConfigResource:
+		return true
+	}
+	return false
+}
+
+// ReferenceMap is a structure that can be used to efficiently check
+// for references on a graph, mapping internal reference keys (as produced by
+// the mapKey method) to one or more vertices that are identified by each key.
+type ReferenceMap map[string][]dag.Vertex
+
+// References returns the set of vertices that the given vertex refers to,
+// and any referenced addresses that do not have corresponding vertices.
+func (m ReferenceMap) References(v dag.Vertex) []dag.Vertex {
+	rn, ok := v.(GraphNodeReferencer)
+	if !ok {
+		return nil
+	}
+
+	var matches []dag.Vertex
+
+	for _, ref := range rn.References() {
+		subject := ref.Subject
+
+		key := m.referenceMapKey(v, subject)
+		if _, exists := m[key]; !exists {
+			// If what we were looking for was a ResourceInstance then we
+			// might be in a resource-oriented graph rather than an
+			// instance-oriented graph, and so we'll see if we have the
+			// resource itself instead.
+			switch ri := subject.(type) {
+			case addrs.ResourceInstance:
+				subject = ri.ContainingResource()
+			case addrs.ResourceInstancePhase:
+				subject = ri.ContainingResource()
+			case addrs.ModuleCallInstanceOutput:
+				subject = ri.ModuleCallOutput()
+			case addrs.ModuleCallInstance:
+				subject = ri.Call
+			default:
+				log.Printf("[INFO] ReferenceTransformer: reference not found: %q", subject)
+				continue
+			}
+			key = m.referenceMapKey(v, subject)
+		}
+		vertices := m[key]
+		for _, rv := range vertices {
+			// don't include self-references
+			if rv == v {
+				continue
+			}
+			matches = append(matches, rv)
+		}
+	}
+
+	return matches
+}
+
+// dependsOn returns the set of vertices that the given vertex refers to from
+// the configured depends_on. The bool return value indicates if depends_on was
+// found in a parent module configuration.
+func (m ReferenceMap) dependsOn(g *Graph, depender graphNodeDependsOn) ([]dag.Vertex, bool) {
+	var res []dag.Vertex
+	fromModule := false
+
+	refs := depender.DependsOn()
+
+	// get any implied dependencies for data sources
+	refs = append(refs, m.dataDependsOn(depender)...)
+
+	// This is where we record that a module has depends_on configured.
+	if _, ok := depender.(*nodeExpandModule); ok && len(refs) > 0 {
+		fromModule = true
+	}
+
+	for _, ref := range refs {
+		subject := ref.Subject
+
+		key := m.referenceMapKey(depender, subject)
+		vertices, ok := m[key]
+		if !ok {
+			// the ReferenceMap generates all possible keys, so any warning
+			// here is probably not useful for this implementation.
+			continue
+		}
+		for _, rv := range vertices {
+			// don't include self-references
+			if rv == depender {
+				continue
+			}
+			res = append(res, rv)
+
+			// Check any ancestors for transitive dependencies when we're
+			// not pointed directly at a resource. We can't be much more
+			// precise here, since in order to maintain our guarantee that data
+			// sources will wait for explicit dependencies, if those dependencies
+			// happen to be a module, output, or variable, we have to find some
+			// upstream managed resource in order to check for a planned
+			// change.
+			if _, ok := rv.(GraphNodeConfigResource); !ok {
+				ans, _ := g.Ancestors(rv)
+				for _, v := range ans {
+					if isDependableResource(v) {
+						res = append(res, v)
+					}
+				}
+			}
+		}
+	}
+
+	parentDeps, fromParentModule := m.parentModuleDependsOn(g, depender)
+	res = append(res, parentDeps...)
+
+	return res, fromModule || fromParentModule
+}
+
+// Return extra depends_on references if this is a data source.
+// For data sources we implicitly treat references to managed resources as
+// depends_on entries. If a data source references a managed resource, even if
+// that reference is resolvable, it stands to reason that the user intends for
+// the data source to require that resource in some way.
+func (m ReferenceMap) dataDependsOn(depender graphNodeDependsOn) []*addrs.Reference {
+	var refs []*addrs.Reference
+	if n, ok := depender.(GraphNodeConfigResource); ok &&
+		n.ResourceAddr().Resource.Mode == addrs.DataResourceMode {
+		for _, r := range depender.References() {
+
+			var resAddr addrs.Resource
+			switch s := r.Subject.(type) {
+			case addrs.Resource:
+				resAddr = s
+			case addrs.ResourceInstance:
+				resAddr = s.Resource
+				r.Subject = resAddr
+			}
+
+			if resAddr.Mode != addrs.ManagedResourceMode {
+				// We only want to wait on directly referenced managed resources.
+				// Data sources have no external side effects, so normal
+				// references to them in the config will suffice for proper
+				// ordering.
+				continue
+			}
+
+			refs = append(refs, r)
+		}
+	}
+	return refs
+}
+
+// parentModuleDependsOn returns the set of vertices that a data sources parent
+// module references through the module call's depends_on. The bool return
+// value indicates if depends_on was found in a parent module configuration.
+func (m ReferenceMap) parentModuleDependsOn(g *Graph, depender graphNodeDependsOn) ([]dag.Vertex, bool) {
+	var res []dag.Vertex
+	fromModule := false
+
+	// Look for containing modules with DependsOn.
+	// This should be connected directly to the module node, so we only need to
+	// look one step away.
+	for _, v := range g.DownEdges(depender) {
+		// we're only concerned with module expansion nodes here.
+		mod, ok := v.(*nodeExpandModule)
+		if !ok {
+			continue
+		}
+
+		deps, fromParentModule := m.dependsOn(g, mod)
+		for _, dep := range deps {
+			// add the dependency
+			res = append(res, dep)
+
+			// and check any transitive resource dependencies for more resources
+			ans, _ := g.Ancestors(dep)
+			for _, v := range ans {
+				if isDependableResource(v) {
+					res = append(res, v)
+				}
+			}
+		}
+		fromModule = fromModule || fromParentModule
+	}
+
+	return res, fromModule
+}
+
+func (m *ReferenceMap) mapKey(path addrs.Module, addr addrs.Referenceable) string {
+	return fmt.Sprintf("%s|%s", path.String(), addr.String())
+}
+
+// vertexReferenceablePath returns the path in which the given vertex can be
+// referenced. This is the path that its results from ReferenceableAddrs
+// are considered to be relative to.
+//
+// Only GraphNodeModulePath implementations can be referenced, so this method will
+// panic if the given vertex does not implement that interface.
+func vertexReferenceablePath(v dag.Vertex) addrs.Module {
+	sp, ok := v.(GraphNodeModulePath)
+	if !ok {
+		// Only nodes with paths can participate in a reference map.
+		panic(fmt.Errorf("vertexMapKey on vertex type %T which doesn't implement GraphNodeModulePath", sp))
+	}
+
+	if outside, ok := v.(GraphNodeReferenceOutside); ok {
+		// Vertex is referenced from a different module than where it was
+		// declared.
+		path, _ := outside.ReferenceOutside()
+		return path
+	}
+
+	// Vertex is referenced from the same module as where it was declared.
+	return sp.ModulePath()
+}
+
+// vertexReferencePath returns the path in which references _from_ the given
+// vertex must be interpreted.
+//
+// Only GraphNodeModulePath implementations can have references, so this method
+// will panic if the given vertex does not implement that interface.
+func vertexReferencePath(v dag.Vertex) addrs.Module {
+	sp, ok := v.(GraphNodeModulePath)
+	if !ok {
+		// Only nodes with paths can participate in a reference map.
+		panic(fmt.Errorf("vertexReferencePath on vertex type %T which doesn't implement GraphNodeModulePath", v))
+	}
+
+	if outside, ok := v.(GraphNodeReferenceOutside); ok {
+		// Vertex makes references to objects in a different module than where
+		// it was declared.
+		_, path := outside.ReferenceOutside()
+		return path
+	}
+
+	// Vertex makes references to objects in the same module as where it
+	// was declared.
+	return sp.ModulePath()
+}
+
+// referenceMapKey produces keys for the "edges" map. "referrer" is the vertex
+// that the reference is from, and "addr" is the address of the object being
+// referenced.
+//
+// The result is an opaque string that includes both the address of the given
+// object and the address of the module instance that object belongs to.
+//
+// Only GraphNodeModulePath implementations can be referrers, so this method will
+// panic if the given vertex does not implement that interface.
+func (m *ReferenceMap) referenceMapKey(referrer dag.Vertex, addr addrs.Referenceable) string {
+	path := vertexReferencePath(referrer)
+	return m.mapKey(path, addr)
+}
+
+// NewReferenceMap is used to create a new reference map for the
+// given set of vertices.
+func NewReferenceMap(vs []dag.Vertex) ReferenceMap {
+	// Build the lookup table
+	m := make(ReferenceMap)
+	for _, v := range vs {
+		// We're only looking for referenceable nodes
+		rn, ok := v.(GraphNodeReferenceable)
+		if !ok {
+			continue
+		}
+
+		path := vertexReferenceablePath(v)
+
+		// Go through and cache them
+		for _, addr := range rn.ReferenceableAddrs() {
+			key := m.mapKey(path, addr)
+			m[key] = append(m[key], v)
+		}
+	}
+
+	return m
+}
+
+// ReferencesFromConfig returns the references that a configuration has
+// based on the interpolated variables in a configuration.
+func ReferencesFromConfig(body hcl.Body, schema *configschema.Block) []*addrs.Reference {
+	if body == nil {
+		return nil
+	}
+	refs, _ := lang.ReferencesInBlock(body, schema)
+	return refs
+}
diff --git a/v1.5.7/internal/terraform/transform_reference_test.go b/v1.5.7/internal/terraform/transform_reference_test.go
new file mode 100644
index 0000000..6194701
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_reference_test.go
@@ -0,0 +1,322 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"reflect"
+	"sort"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+func TestReferenceTransformer_simple(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	g.Add(&graphNodeRefParentTest{
+		NameValue: "A",
+		Names:     []string{"A"},
+	})
+	g.Add(&graphNodeRefChildTest{
+		NameValue: "B",
+		Refs:      []string{"A"},
+	})
+
+	tf := &ReferenceTransformer{}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformRefBasicStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestReferenceTransformer_self(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	g.Add(&graphNodeRefParentTest{
+		NameValue: "A",
+		Names:     []string{"A"},
+	})
+	g.Add(&graphNodeRefChildTest{
+		NameValue: "B",
+		Refs:      []string{"A", "B"},
+	})
+
+	tf := &ReferenceTransformer{}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformRefBasicStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestReferenceTransformer_path(t *testing.T) {
+	g := Graph{Path: addrs.RootModuleInstance}
+	g.Add(&graphNodeRefParentTest{
+		NameValue: "A",
+		Names:     []string{"A"},
+	})
+	g.Add(&graphNodeRefChildTest{
+		NameValue: "B",
+		Refs:      []string{"A"},
+	})
+	g.Add(&graphNodeRefParentTest{
+		NameValue: "child.A",
+		PathValue: addrs.ModuleInstance{addrs.ModuleInstanceStep{Name: "child"}},
+		Names:     []string{"A"},
+	})
+	g.Add(&graphNodeRefChildTest{
+		NameValue: "child.B",
+		PathValue: addrs.ModuleInstance{addrs.ModuleInstanceStep{Name: "child"}},
+		Refs:      []string{"A"},
+	})
+
+	tf := &ReferenceTransformer{}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformRefPathStr)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestReferenceTransformer_resourceInstances(t *testing.T) {
+	// Our reference analyses are all done based on unexpanded addresses
+	// so that we can use this transformer both in the plan graph (where things
+	// are not expanded yet) and the apply graph (where resource instances are
+	// pre-expanded but nothing else is.)
+	// However, that would make the result too conservative about instances
+	// of the same resource in different instances of the same module, so we
+	// make an exception for that situation in particular, keeping references
+	// between resource instances segregated by their containing module
+	// instance.
+	g := Graph{Path: addrs.RootModuleInstance}
+	moduleInsts := []addrs.ModuleInstance{
+		{
+			{
+				Name: "foo", InstanceKey: addrs.IntKey(0),
+			},
+		},
+		{
+			{
+				Name: "foo", InstanceKey: addrs.IntKey(1),
+			},
+		},
+	}
+	resourceAs := make([]addrs.AbsResourceInstance, len(moduleInsts))
+	for i, moduleInst := range moduleInsts {
+		resourceAs[i] = addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "thing",
+			Name: "a",
+		}.Instance(addrs.NoKey).Absolute(moduleInst)
+	}
+	resourceBs := make([]addrs.AbsResourceInstance, len(moduleInsts))
+	for i, moduleInst := range moduleInsts {
+		resourceBs[i] = addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "thing",
+			Name: "b",
+		}.Instance(addrs.NoKey).Absolute(moduleInst)
+	}
+	g.Add(&graphNodeFakeResourceInstance{
+		Addr: resourceAs[0],
+	})
+	g.Add(&graphNodeFakeResourceInstance{
+		Addr: resourceBs[0],
+		Refs: []*addrs.Reference{
+			{
+				Subject: resourceAs[0].Resource,
+			},
+		},
+	})
+	g.Add(&graphNodeFakeResourceInstance{
+		Addr: resourceAs[1],
+	})
+	g.Add(&graphNodeFakeResourceInstance{
+		Addr: resourceBs[1],
+		Refs: []*addrs.Reference{
+			{
+				Subject: resourceAs[1].Resource,
+			},
+		},
+	})
+
+	tf := &ReferenceTransformer{}
+	if err := tf.Transform(&g); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	// Resource B should be connected to resource A in each module instance,
+	// but there should be no connections between the two module instances.
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(`
+module.foo[0].thing.a
+module.foo[0].thing.b
+  module.foo[0].thing.a
+module.foo[1].thing.a
+module.foo[1].thing.b
+  module.foo[1].thing.a
+`)
+	if actual != expected {
+		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+func TestReferenceMapReferences(t *testing.T) {
+	cases := map[string]struct {
+		Nodes  []dag.Vertex
+		Check  dag.Vertex
+		Result []string
+	}{
+		"simple": {
+			Nodes: []dag.Vertex{
+				&graphNodeRefParentTest{
+					NameValue: "A",
+					Names:     []string{"A"},
+				},
+			},
+			Check: &graphNodeRefChildTest{
+				NameValue: "foo",
+				Refs:      []string{"A"},
+			},
+			Result: []string{"A"},
+		},
+	}
+
+	for tn, tc := range cases {
+		t.Run(tn, func(t *testing.T) {
+			rm := NewReferenceMap(tc.Nodes)
+			result := rm.References(tc.Check)
+
+			var resultStr []string
+			for _, v := range result {
+				resultStr = append(resultStr, dag.VertexName(v))
+			}
+
+			sort.Strings(resultStr)
+			sort.Strings(tc.Result)
+			if !reflect.DeepEqual(resultStr, tc.Result) {
+				t.Fatalf("bad: %#v", resultStr)
+			}
+		})
+	}
+}
+
+type graphNodeRefParentTest struct {
+	NameValue string
+	PathValue addrs.ModuleInstance
+	Names     []string
+}
+
+var _ GraphNodeReferenceable = (*graphNodeRefParentTest)(nil)
+
+func (n *graphNodeRefParentTest) Name() string {
+	return n.NameValue
+}
+
+func (n *graphNodeRefParentTest) ReferenceableAddrs() []addrs.Referenceable {
+	ret := make([]addrs.Referenceable, len(n.Names))
+	for i, name := range n.Names {
+		ret[i] = addrs.LocalValue{Name: name}
+	}
+	return ret
+}
+
+func (n *graphNodeRefParentTest) Path() addrs.ModuleInstance {
+	return n.PathValue
+}
+
+func (n *graphNodeRefParentTest) ModulePath() addrs.Module {
+	return n.PathValue.Module()
+}
+
+type graphNodeRefChildTest struct {
+	NameValue string
+	PathValue addrs.ModuleInstance
+	Refs      []string
+}
+
+var _ GraphNodeReferencer = (*graphNodeRefChildTest)(nil)
+
+func (n *graphNodeRefChildTest) Name() string {
+	return n.NameValue
+}
+
+func (n *graphNodeRefChildTest) References() []*addrs.Reference {
+	ret := make([]*addrs.Reference, len(n.Refs))
+	for i, name := range n.Refs {
+		ret[i] = &addrs.Reference{
+			Subject: addrs.LocalValue{Name: name},
+		}
+	}
+	return ret
+}
+
+func (n *graphNodeRefChildTest) Path() addrs.ModuleInstance {
+	return n.PathValue
+}
+
+func (n *graphNodeRefChildTest) ModulePath() addrs.Module {
+	return n.PathValue.Module()
+}
+
+type graphNodeFakeResourceInstance struct {
+	Addr addrs.AbsResourceInstance
+	Refs []*addrs.Reference
+}
+
+var _ GraphNodeResourceInstance = (*graphNodeFakeResourceInstance)(nil)
+var _ GraphNodeReferenceable = (*graphNodeFakeResourceInstance)(nil)
+var _ GraphNodeReferencer = (*graphNodeFakeResourceInstance)(nil)
+
+func (n *graphNodeFakeResourceInstance) ResourceInstanceAddr() addrs.AbsResourceInstance {
+	return n.Addr
+}
+
+func (n *graphNodeFakeResourceInstance) ModulePath() addrs.Module {
+	return n.Addr.Module.Module()
+}
+
+func (n *graphNodeFakeResourceInstance) ReferenceableAddrs() []addrs.Referenceable {
+	return []addrs.Referenceable{n.Addr.Resource}
+}
+
+func (n *graphNodeFakeResourceInstance) References() []*addrs.Reference {
+	return n.Refs
+}
+
+func (n *graphNodeFakeResourceInstance) StateDependencies() []addrs.ConfigResource {
+	return nil
+}
+
+func (n *graphNodeFakeResourceInstance) String() string {
+	return n.Addr.String()
+}
+
+const testTransformRefBasicStr = `
+A
+B
+  A
+`
+
+const testTransformRefPathStr = `
+A
+B
+  A
+child.A
+child.B
+  child.A
+`
diff --git a/v1.5.7/internal/terraform/transform_removed_modules.go b/v1.5.7/internal/terraform/transform_removed_modules.go
new file mode 100644
index 0000000..c89d27f
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_removed_modules.go
@@ -0,0 +1,47 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// RemovedModuleTransformer implements GraphTransformer to add nodes indicating
+// when a module was removed from the configuration.
+type RemovedModuleTransformer struct {
+	Config *configs.Config // root node in the config tree
+	State  *states.State
+}
+
+func (t *RemovedModuleTransformer) Transform(g *Graph) error {
+	// nothing to remove if there's no state!
+	if t.State == nil {
+		return nil
+	}
+
+	removed := map[string]addrs.Module{}
+
+	for _, m := range t.State.Modules {
+		cc := t.Config.DescendentForInstance(m.Addr)
+		if cc != nil {
+			continue
+		}
+		removed[m.Addr.Module().String()] = m.Addr.Module()
+		log.Printf("[DEBUG] %s is no longer in configuration\n", m.Addr)
+	}
+
+	// add closers to collect any module instances we're removing
+	for _, modAddr := range removed {
+		closer := &nodeCloseModule{
+			Addr: modAddr,
+		}
+		g.Add(closer)
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_resource_count.go b/v1.5.7/internal/terraform/transform_resource_count.go
new file mode 100644
index 0000000..5a4061a
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_resource_count.go
@@ -0,0 +1,39 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+// ResourceCountTransformer is a GraphTransformer that expands the count
+// out for a specific resource.
+//
+// This assumes that the count is already interpolated.
+type ResourceCountTransformer struct {
+	Concrete ConcreteResourceInstanceNodeFunc
+	Schema   *configschema.Block
+
+	Addr          addrs.ConfigResource
+	InstanceAddrs []addrs.AbsResourceInstance
+}
+
+func (t *ResourceCountTransformer) Transform(g *Graph) error {
+	for _, addr := range t.InstanceAddrs {
+		abstract := NewNodeAbstractResourceInstance(addr)
+		abstract.Schema = t.Schema
+		var node dag.Vertex = abstract
+		if f := t.Concrete; f != nil {
+			node = f(abstract)
+		}
+
+		log.Printf("[TRACE] ResourceCountTransformer: adding %s as %T", addr, node)
+		g.Add(node)
+	}
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_root.go b/v1.5.7/internal/terraform/transform_root.go
new file mode 100644
index 0000000..446f250
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_root.go
@@ -0,0 +1,85 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+const rootNodeName = "root"
+
+// RootTransformer is a GraphTransformer that adds a root to the graph.
+type RootTransformer struct{}
+
+func (t *RootTransformer) Transform(g *Graph) error {
+	addRootNodeToGraph(g)
+	return nil
+}
+
+// addRootNodeToGraph modifies the given graph in-place so that it has a root
+// node if it didn't already have one and so that any other node which doesn't
+// already depend on something will depend on that root node.
+//
+// After this function returns, the graph will have only one node that doesn't
+// depend on any other nodes.
+func addRootNodeToGraph(g *Graph) {
+	// We always add the root node. This is a singleton so if it's already
+	// in the graph this will do nothing and just retain the existing root node.
+	//
+	// Note that rootNode is intentionally added by value and not by pointer
+	// so that all root nodes will be equal to one another and therefore
+	// coalesce when two valid graphs get merged together into a single graph.
+	g.Add(rootNode)
+
+	// Everything that doesn't already depend on at least one other node will
+	// depend on the root node, except the root node itself.
+	for _, v := range g.Vertices() {
+		if v == dag.Vertex(rootNode) {
+			continue
+		}
+
+		if g.UpEdges(v).Len() == 0 {
+			g.Connect(dag.BasicEdge(rootNode, v))
+		}
+	}
+}
+
+type graphNodeRoot struct{}
+
+// rootNode is the singleton value representing all root graph nodes.
+//
+// The root node for all graphs should be this value directly, and in particular
+// _not_ a pointer to this value. Using the value directly here means that
+// multiple root nodes will always coalesce together when subsuming one graph
+// into another.
+var rootNode graphNodeRoot
+
+func (n graphNodeRoot) Name() string {
+	return rootNodeName
+}
+
+// CloseRootModuleTransformer is a GraphTransformer that adds a root to the graph.
+type CloseRootModuleTransformer struct{}
+
+func (t *CloseRootModuleTransformer) Transform(g *Graph) error {
+	// close the root module
+	closeRoot := &nodeCloseModule{}
+	g.Add(closeRoot)
+
+	// since this is closing the root module, make it depend on everything in
+	// the root module.
+	for _, v := range g.Vertices() {
+		if v == closeRoot {
+			continue
+		}
+
+		// since this is closing the root module,  and must be last, we can
+		// connect to anything that doesn't have any up edges.
+		if g.UpEdges(v).Len() == 0 {
+			g.Connect(dag.BasicEdge(closeRoot, v))
+		}
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_root_test.go b/v1.5.7/internal/terraform/transform_root_test.go
new file mode 100644
index 0000000..c96bd62
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_root_test.go
@@ -0,0 +1,98 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestRootTransformer(t *testing.T) {
+	t.Run("many nodes", func(t *testing.T) {
+		mod := testModule(t, "transform-root-basic")
+
+		g := Graph{Path: addrs.RootModuleInstance}
+		{
+			tf := &ConfigTransformer{Config: mod}
+			if err := tf.Transform(&g); err != nil {
+				t.Fatalf("err: %s", err)
+			}
+		}
+
+		{
+			transform := &MissingProviderTransformer{}
+			if err := transform.Transform(&g); err != nil {
+				t.Fatalf("err: %s", err)
+			}
+		}
+
+		{
+			transform := &ProviderTransformer{}
+			if err := transform.Transform(&g); err != nil {
+				t.Fatalf("err: %s", err)
+			}
+		}
+
+		{
+			transform := &RootTransformer{}
+			if err := transform.Transform(&g); err != nil {
+				t.Fatalf("err: %s", err)
+			}
+		}
+
+		actual := strings.TrimSpace(g.String())
+		expected := strings.TrimSpace(testTransformRootBasicStr)
+		if actual != expected {
+			t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
+		}
+
+		root, err := g.Root()
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		if _, ok := root.(graphNodeRoot); !ok {
+			t.Fatalf("bad: %#v", root)
+		}
+	})
+
+	t.Run("only one initial node", func(t *testing.T) {
+		g := Graph{Path: addrs.RootModuleInstance}
+		g.Add("foo")
+		addRootNodeToGraph(&g)
+		got := strings.TrimSpace(g.String())
+		want := strings.TrimSpace(`
+foo
+root
+  foo
+`)
+		if got != want {
+			t.Errorf("wrong final graph\ngot:\n%s\nwant:\n%s", got, want)
+		}
+	})
+
+	t.Run("graph initially empty", func(t *testing.T) {
+		g := Graph{Path: addrs.RootModuleInstance}
+		addRootNodeToGraph(&g)
+		got := strings.TrimSpace(g.String())
+		want := `root`
+		if got != want {
+			t.Errorf("wrong final graph\ngot:\n%s\nwant:\n%s", got, want)
+		}
+	})
+
+}
+
+const testTransformRootBasicStr = `
+aws_instance.foo
+  provider["registry.terraform.io/hashicorp/aws"]
+do_droplet.bar
+  provider["registry.terraform.io/hashicorp/do"]
+provider["registry.terraform.io/hashicorp/aws"]
+provider["registry.terraform.io/hashicorp/do"]
+root
+  aws_instance.foo
+  do_droplet.bar
+`
diff --git a/v1.5.7/internal/terraform/transform_state.go b/v1.5.7/internal/terraform/transform_state.go
new file mode 100644
index 0000000..cd30603
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_state.go
@@ -0,0 +1,75 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+// StateTransformer is a GraphTransformer that adds the elements of
+// the state to the graph.
+//
+// This transform is used for example by the DestroyPlanGraphBuilder to ensure
+// that only resources that are in the state are represented in the graph.
+type StateTransformer struct {
+	// ConcreteCurrent and ConcreteDeposed are used to specialize the abstract
+	// resource instance nodes that this transformer will create.
+	//
+	// If either of these is nil, the objects of that type will be skipped and
+	// not added to the graph at all. It doesn't make sense to use this
+	// transformer without setting at least one of these, since that would
+	// skip everything and thus be a no-op.
+	ConcreteCurrent ConcreteResourceInstanceNodeFunc
+	ConcreteDeposed ConcreteResourceInstanceDeposedNodeFunc
+
+	State *states.State
+}
+
+func (t *StateTransformer) Transform(g *Graph) error {
+	if t.State == nil {
+		log.Printf("[TRACE] StateTransformer: state is nil, so nothing to do")
+		return nil
+	}
+
+	switch {
+	case t.ConcreteCurrent != nil && t.ConcreteDeposed != nil:
+		log.Printf("[TRACE] StateTransformer: creating nodes for both current and deposed instance objects")
+	case t.ConcreteCurrent != nil:
+		log.Printf("[TRACE] StateTransformer: creating nodes for current instance objects only")
+	case t.ConcreteDeposed != nil:
+		log.Printf("[TRACE] StateTransformer: creating nodes for deposed instance objects only")
+	default:
+		log.Printf("[TRACE] StateTransformer: pointless no-op call, creating no nodes at all")
+	}
+
+	for _, ms := range t.State.Modules {
+		for _, rs := range ms.Resources {
+			resourceAddr := rs.Addr
+
+			for key, is := range rs.Instances {
+				addr := resourceAddr.Instance(key)
+
+				if obj := is.Current; obj != nil && t.ConcreteCurrent != nil {
+					abstract := NewNodeAbstractResourceInstance(addr)
+					node := t.ConcreteCurrent(abstract)
+					g.Add(node)
+					log.Printf("[TRACE] StateTransformer: added %T for %s current object", node, addr)
+				}
+
+				if t.ConcreteDeposed != nil {
+					for dk := range is.Deposed {
+						abstract := NewNodeAbstractResourceInstance(addr)
+						node := t.ConcreteDeposed(abstract, dk)
+						g.Add(node)
+						log.Printf("[TRACE] StateTransformer: added %T for %s deposed object %s", node, addr, dk)
+					}
+				}
+			}
+		}
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_targets.go b/v1.5.7/internal/terraform/transform_targets.go
new file mode 100644
index 0000000..f561737
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_targets.go
@@ -0,0 +1,162 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+// GraphNodeTargetable is an interface for graph nodes to implement when they
+// need to be told about incoming targets. This is useful for nodes that need
+// to respect targets as they dynamically expand. Note that the list of targets
+// provided will contain every target provided, and each implementing graph
+// node must filter this list to targets considered relevant.
+type GraphNodeTargetable interface {
+	SetTargets([]addrs.Targetable)
+}
+
+// TargetsTransformer is a GraphTransformer that, when the user specifies a
+// list of resources to target, limits the graph to only those resources and
+// their dependencies.
+type TargetsTransformer struct {
+	// List of targeted resource names specified by the user
+	Targets []addrs.Targetable
+}
+
+func (t *TargetsTransformer) Transform(g *Graph) error {
+	if len(t.Targets) > 0 {
+		targetedNodes, err := t.selectTargetedNodes(g, t.Targets)
+		if err != nil {
+			return err
+		}
+
+		for _, v := range g.Vertices() {
+			if !targetedNodes.Include(v) {
+				log.Printf("[DEBUG] Removing %q, filtered by targeting.", dag.VertexName(v))
+				g.Remove(v)
+			}
+		}
+	}
+
+	return nil
+}
+
+// Returns a set of targeted nodes. A targeted node is either addressed
+// directly, address indirectly via its container, or it's a dependency of a
+// targeted node.
+func (t *TargetsTransformer) selectTargetedNodes(g *Graph, addrs []addrs.Targetable) (dag.Set, error) {
+	targetedNodes := make(dag.Set)
+
+	vertices := g.Vertices()
+
+	for _, v := range vertices {
+		if t.nodeIsTarget(v, addrs) {
+			targetedNodes.Add(v)
+
+			// We inform nodes that ask about the list of targets - helps for nodes
+			// that need to dynamically expand. Note that this only occurs for nodes
+			// that are already directly targeted.
+			if tn, ok := v.(GraphNodeTargetable); ok {
+				tn.SetTargets(addrs)
+			}
+
+			deps, _ := g.Ancestors(v)
+			for _, d := range deps {
+				targetedNodes.Add(d)
+			}
+		}
+	}
+
+	// It is expected that outputs which are only derived from targeted
+	// resources are also updated. While we don't include any other possible
+	// side effects from the targeted nodes, these are added because outputs
+	// cannot be targeted on their own.
+	// Start by finding the root module output nodes themselves
+	for _, v := range vertices {
+		// outputs are all temporary value types
+		tv, ok := v.(graphNodeTemporaryValue)
+		if !ok {
+			continue
+		}
+
+		// root module outputs indicate that while they are an output type,
+		// they not temporary and will return false here.
+		if tv.temporaryValue() {
+			continue
+		}
+
+		// If this output is descended only from targeted resources, then we
+		// will keep it
+		deps, _ := g.Ancestors(v)
+		found := 0
+		for _, d := range deps {
+			switch d.(type) {
+			case GraphNodeResourceInstance:
+			case GraphNodeConfigResource:
+			default:
+				continue
+			}
+
+			if !targetedNodes.Include(d) {
+				// this dependency isn't being targeted, so we can't process this
+				// output
+				found = 0
+				break
+			}
+
+			found++
+		}
+
+		if found > 0 {
+			// we found an output we can keep; add it, and all it's dependencies
+			targetedNodes.Add(v)
+			for _, d := range deps {
+				targetedNodes.Add(d)
+			}
+		}
+	}
+
+	return targetedNodes, nil
+}
+
+func (t *TargetsTransformer) nodeIsTarget(v dag.Vertex, targets []addrs.Targetable) bool {
+	var vertexAddr addrs.Targetable
+	switch r := v.(type) {
+	case GraphNodeResourceInstance:
+		vertexAddr = r.ResourceInstanceAddr()
+	case GraphNodeConfigResource:
+		vertexAddr = r.ResourceAddr()
+
+	default:
+		// Only resource and resource instance nodes can be targeted.
+		return false
+	}
+
+	for _, targetAddr := range targets {
+		switch vertexAddr.(type) {
+		case addrs.ConfigResource:
+			// Before expansion happens, we only have nodes that know their
+			// ConfigResource address.  We need to take the more specific
+			// target addresses and generalize them in order to compare with a
+			// ConfigResource.
+			switch target := targetAddr.(type) {
+			case addrs.AbsResourceInstance:
+				targetAddr = target.ContainingResource().Config()
+			case addrs.AbsResource:
+				targetAddr = target.Config()
+			case addrs.ModuleInstance:
+				targetAddr = target.Module()
+			}
+		}
+
+		if targetAddr.TargetContains(vertexAddr) {
+			return true
+		}
+	}
+
+	return false
+}
diff --git a/v1.5.7/internal/terraform/transform_targets_test.go b/v1.5.7/internal/terraform/transform_targets_test.go
new file mode 100644
index 0000000..ba1659c
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_targets_test.go
@@ -0,0 +1,205 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestTargetsTransformer(t *testing.T) {
+	mod := testModule(t, "transform-targets-basic")
+
+	g := Graph{Path: addrs.RootModuleInstance}
+	{
+		tf := &ConfigTransformer{Config: mod}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		transform := &AttachResourceConfigTransformer{Config: mod}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		transform := &ReferenceTransformer{}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		transform := &TargetsTransformer{
+			Targets: []addrs.Targetable{
+				addrs.RootModuleInstance.Resource(
+					addrs.ManagedResourceMode, "aws_instance", "me",
+				),
+			},
+		}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(`
+aws_instance.me
+  aws_subnet.me
+aws_subnet.me
+  aws_vpc.me
+aws_vpc.me
+	`)
+	if actual != expected {
+		t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
+	}
+}
+
+func TestTargetsTransformer_downstream(t *testing.T) {
+	mod := testModule(t, "transform-targets-downstream")
+
+	g := Graph{Path: addrs.RootModuleInstance}
+	{
+		transform := &ConfigTransformer{Config: mod}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("%T failed: %s", transform, err)
+		}
+	}
+
+	{
+		transform := &AttachResourceConfigTransformer{Config: mod}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("%T failed: %s", transform, err)
+		}
+	}
+
+	{
+		transform := &AttachResourceConfigTransformer{Config: mod}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("%T failed: %s", transform, err)
+		}
+	}
+
+	{
+		transform := &OutputTransformer{Config: mod}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("%T failed: %s", transform, err)
+		}
+	}
+
+	{
+		transform := &ReferenceTransformer{}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		transform := &TargetsTransformer{
+			Targets: []addrs.Targetable{
+				addrs.RootModuleInstance.
+					Child("child", addrs.NoKey).
+					Child("grandchild", addrs.NoKey).
+					Resource(
+						addrs.ManagedResourceMode, "aws_instance", "foo",
+					),
+			},
+		}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("%T failed: %s", transform, err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	// Even though we only asked to target the grandchild resource, all of the
+	// outputs that descend from it are also targeted.
+	expected := strings.TrimSpace(`
+module.child.module.grandchild.aws_instance.foo
+module.child.module.grandchild.output.id (expand)
+  module.child.module.grandchild.aws_instance.foo
+module.child.output.grandchild_id (expand)
+  module.child.module.grandchild.output.id (expand)
+output.grandchild_id (expand)
+  module.child.output.grandchild_id (expand)
+	`)
+	if actual != expected {
+		t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
+	}
+}
+
+// This tests the TargetsTransformer targeting a whole module,
+// rather than a resource within a module instance.
+func TestTargetsTransformer_wholeModule(t *testing.T) {
+	mod := testModule(t, "transform-targets-downstream")
+
+	g := Graph{Path: addrs.RootModuleInstance}
+	{
+		transform := &ConfigTransformer{Config: mod}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("%T failed: %s", transform, err)
+		}
+	}
+
+	{
+		transform := &AttachResourceConfigTransformer{Config: mod}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("%T failed: %s", transform, err)
+		}
+	}
+
+	{
+		transform := &AttachResourceConfigTransformer{Config: mod}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("%T failed: %s", transform, err)
+		}
+	}
+
+	{
+		transform := &OutputTransformer{Config: mod}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("%T failed: %s", transform, err)
+		}
+	}
+
+	{
+		transform := &ReferenceTransformer{}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		transform := &TargetsTransformer{
+			Targets: []addrs.Targetable{
+				addrs.RootModule.
+					Child("child").
+					Child("grandchild"),
+			},
+		}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("%T failed: %s", transform, err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	// Even though we only asked to target the grandchild module, all of the
+	// outputs that descend from it are also targeted.
+	expected := strings.TrimSpace(`
+module.child.module.grandchild.aws_instance.foo
+module.child.module.grandchild.output.id (expand)
+  module.child.module.grandchild.aws_instance.foo
+module.child.output.grandchild_id (expand)
+  module.child.module.grandchild.output.id (expand)
+output.grandchild_id (expand)
+  module.child.output.grandchild_id (expand)
+	`)
+	if actual != expected {
+		t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
+	}
+}
diff --git a/v1.5.7/internal/terraform/transform_transitive_reduction.go b/v1.5.7/internal/terraform/transform_transitive_reduction.go
new file mode 100644
index 0000000..3083ad1
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_transitive_reduction.go
@@ -0,0 +1,23 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+// TransitiveReductionTransformer is a GraphTransformer that
+// finds the transitive reduction of the graph. For a definition of
+// transitive reduction, see [Wikipedia](https://en.wikipedia.org/wiki/Transitive_reduction).
+type TransitiveReductionTransformer struct{}
+
+func (t *TransitiveReductionTransformer) Transform(g *Graph) error {
+	// If the graph isn't valid, skip the transitive reduction.
+	// We don't error here because Terraform itself handles graph
+	// validation in a better way, or we assume it does.
+	if err := g.Validate(); err != nil {
+		return nil
+	}
+
+	// Do it
+	g.TransitiveReduction()
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_transitive_reduction_test.go b/v1.5.7/internal/terraform/transform_transitive_reduction_test.go
new file mode 100644
index 0000000..894cf1f
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_transitive_reduction_test.go
@@ -0,0 +1,89 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestTransitiveReductionTransformer(t *testing.T) {
+	mod := testModule(t, "transform-trans-reduce-basic")
+
+	g := Graph{Path: addrs.RootModuleInstance}
+	{
+		tf := &ConfigTransformer{Config: mod}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		t.Logf("graph after ConfigTransformer:\n%s", g.String())
+	}
+
+	{
+		transform := &AttachResourceConfigTransformer{Config: mod}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		transform := &AttachSchemaTransformer{
+			Plugins: schemaOnlyProvidersForTesting(map[addrs.Provider]*ProviderSchema{
+				addrs.NewDefaultProvider("aws"): {
+					ResourceTypes: map[string]*configschema.Block{
+						"aws_instance": {
+							Attributes: map[string]*configschema.Attribute{
+								"A": {
+									Type:     cty.String,
+									Optional: true,
+								},
+								"B": {
+									Type:     cty.String,
+									Optional: true,
+								},
+							},
+						},
+					},
+				},
+			}),
+		}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	{
+		transform := &ReferenceTransformer{}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		t.Logf("graph after ReferenceTransformer:\n%s", g.String())
+	}
+
+	{
+		transform := &TransitiveReductionTransformer{}
+		if err := transform.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+		t.Logf("graph after TransitiveReductionTransformer:\n%s", g.String())
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testTransformTransReduceBasicStr)
+	if actual != expected {
+		t.Errorf("wrong result\ngot:\n%s\n\nwant:\n%s", actual, expected)
+	}
+}
+
+const testTransformTransReduceBasicStr = `
+aws_instance.A
+aws_instance.B
+  aws_instance.A
+aws_instance.C
+  aws_instance.B
+`
diff --git a/v1.5.7/internal/terraform/transform_variable.go b/v1.5.7/internal/terraform/transform_variable.go
new file mode 100644
index 0000000..7df3257
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_variable.go
@@ -0,0 +1,46 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs"
+)
+
+// RootVariableTransformer is a GraphTransformer that adds all the root
+// variables to the graph.
+//
+// Root variables are currently no-ops but they must be added to the
+// graph since downstream things that depend on them must be able to
+// reach them.
+type RootVariableTransformer struct {
+	Config *configs.Config
+
+	RawValues InputValues
+}
+
+func (t *RootVariableTransformer) Transform(g *Graph) error {
+	// We can have no variables if we have no config.
+	if t.Config == nil {
+		return nil
+	}
+
+	// We're only considering root module variables here, since child
+	// module variables are handled by ModuleVariableTransformer.
+	vars := t.Config.Module.Variables
+
+	// Add all variables here
+	for _, v := range vars {
+		node := &NodeRootVariable{
+			Addr: addrs.InputVariable{
+				Name: v.Name,
+			},
+			Config:   v,
+			RawValue: t.RawValues[v.Name],
+		}
+		g.Add(node)
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_vertex.go b/v1.5.7/internal/terraform/transform_vertex.go
new file mode 100644
index 0000000..8ddac61
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_vertex.go
@@ -0,0 +1,47 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+// VertexTransformer is a GraphTransformer that transforms vertices
+// using the GraphVertexTransformers. The Transforms are run in sequential
+// order. If a transform replaces a vertex then the next transform will see
+// the new vertex.
+type VertexTransformer struct {
+	Transforms []GraphVertexTransformer
+}
+
+func (t *VertexTransformer) Transform(g *Graph) error {
+	for _, v := range g.Vertices() {
+		for _, vt := range t.Transforms {
+			newV, err := vt.Transform(v)
+			if err != nil {
+				return err
+			}
+
+			// If the vertex didn't change, then don't do anything more
+			if newV == v {
+				continue
+			}
+
+			// Vertex changed, replace it within the graph
+			if ok := g.Replace(v, newV); !ok {
+				// This should never happen, big problem
+				return fmt.Errorf(
+					"failed to replace %s with %s!\n\nSource: %#v\n\nTarget: %#v",
+					dag.VertexName(v), dag.VertexName(newV), v, newV)
+			}
+
+			// Replace v so that future transforms use the proper vertex
+			v = newV
+		}
+	}
+
+	return nil
+}
diff --git a/v1.5.7/internal/terraform/transform_vertex_test.go b/v1.5.7/internal/terraform/transform_vertex_test.go
new file mode 100644
index 0000000..4bca4a4
--- /dev/null
+++ b/v1.5.7/internal/terraform/transform_vertex_test.go
@@ -0,0 +1,61 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/dag"
+)
+
+func TestVertexTransformer_impl(t *testing.T) {
+	var _ GraphTransformer = new(VertexTransformer)
+}
+
+func TestVertexTransformer(t *testing.T) {
+	var g Graph
+	g.Add(1)
+	g.Add(2)
+	g.Add(3)
+	g.Connect(dag.BasicEdge(1, 2))
+	g.Connect(dag.BasicEdge(2, 3))
+
+	{
+		tf := &VertexTransformer{
+			Transforms: []GraphVertexTransformer{
+				&testVertexTransform{Source: 2, Target: 42},
+			},
+		}
+		if err := tf.Transform(&g); err != nil {
+			t.Fatalf("err: %s", err)
+		}
+	}
+
+	actual := strings.TrimSpace(g.String())
+	expected := strings.TrimSpace(testVertexTransformerStr)
+	if actual != expected {
+		t.Fatalf("bad: %s", actual)
+	}
+}
+
+type testVertexTransform struct {
+	Source, Target dag.Vertex
+}
+
+func (t *testVertexTransform) Transform(v dag.Vertex) (dag.Vertex, error) {
+	if t.Source == v {
+		v = t.Target
+	}
+
+	return v, nil
+}
+
+const testVertexTransformerStr = `
+1
+  42
+3
+42
+  3
+`
diff --git a/v1.5.7/internal/terraform/ui_input.go b/v1.5.7/internal/terraform/ui_input.go
new file mode 100644
index 0000000..4c59177
--- /dev/null
+++ b/v1.5.7/internal/terraform/ui_input.go
@@ -0,0 +1,35 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import "context"
+
+// UIInput is the interface that must be implemented to ask for input
+// from this user. This should forward the request to wherever the user
+// inputs things to ask for values.
+type UIInput interface {
+	Input(context.Context, *InputOpts) (string, error)
+}
+
+// InputOpts are options for asking for input.
+type InputOpts struct {
+	// Id is a unique ID for the question being asked that might be
+	// used for logging or to look up a prior answered question.
+	Id string
+
+	// Query is a human-friendly question for inputting this value.
+	Query string
+
+	// Description is a description about what this option is. Be wary
+	// that this will probably be in a terminal so split lines as you see
+	// necessary.
+	Description string
+
+	// Default will be the value returned if no data is entered.
+	Default string
+
+	// Secret should be true if we are asking for sensitive input.
+	// If attached to a TTY, Terraform will disable echo.
+	Secret bool
+}
diff --git a/v1.5.7/internal/terraform/ui_input_mock.go b/v1.5.7/internal/terraform/ui_input_mock.go
new file mode 100644
index 0000000..4d8e028
--- /dev/null
+++ b/v1.5.7/internal/terraform/ui_input_mock.go
@@ -0,0 +1,28 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import "context"
+
+// MockUIInput is an implementation of UIInput that can be used for tests.
+type MockUIInput struct {
+	InputCalled       bool
+	InputOpts         *InputOpts
+	InputReturnMap    map[string]string
+	InputReturnString string
+	InputReturnError  error
+	InputFn           func(*InputOpts) (string, error)
+}
+
+func (i *MockUIInput) Input(ctx context.Context, opts *InputOpts) (string, error) {
+	i.InputCalled = true
+	i.InputOpts = opts
+	if i.InputFn != nil {
+		return i.InputFn(opts)
+	}
+	if i.InputReturnMap != nil {
+		return i.InputReturnMap[opts.Id], i.InputReturnError
+	}
+	return i.InputReturnString, i.InputReturnError
+}
diff --git a/v1.5.7/internal/terraform/ui_input_prefix.go b/v1.5.7/internal/terraform/ui_input_prefix.go
new file mode 100644
index 0000000..69a7032
--- /dev/null
+++ b/v1.5.7/internal/terraform/ui_input_prefix.go
@@ -0,0 +1,23 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"context"
+	"fmt"
+)
+
+// PrefixUIInput is an implementation of UIInput that prefixes the ID
+// with a string, allowing queries to be namespaced.
+type PrefixUIInput struct {
+	IdPrefix    string
+	QueryPrefix string
+	UIInput     UIInput
+}
+
+func (i *PrefixUIInput) Input(ctx context.Context, opts *InputOpts) (string, error) {
+	opts.Id = fmt.Sprintf("%s.%s", i.IdPrefix, opts.Id)
+	opts.Query = fmt.Sprintf("%s%s", i.QueryPrefix, opts.Query)
+	return i.UIInput.Input(ctx, opts)
+}
diff --git a/v1.5.7/internal/terraform/ui_input_prefix_test.go b/v1.5.7/internal/terraform/ui_input_prefix_test.go
new file mode 100644
index 0000000..d6a83ac
--- /dev/null
+++ b/v1.5.7/internal/terraform/ui_input_prefix_test.go
@@ -0,0 +1,30 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"context"
+	"testing"
+)
+
+func TestPrefixUIInput_impl(t *testing.T) {
+	var _ UIInput = new(PrefixUIInput)
+}
+
+func TestPrefixUIInput(t *testing.T) {
+	input := new(MockUIInput)
+	prefix := &PrefixUIInput{
+		IdPrefix: "foo",
+		UIInput:  input,
+	}
+
+	_, err := prefix.Input(context.Background(), &InputOpts{Id: "bar"})
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if input.InputOpts.Id != "foo.bar" {
+		t.Fatalf("bad: %#v", input.InputOpts)
+	}
+}
diff --git a/v1.5.7/internal/terraform/ui_output.go b/v1.5.7/internal/terraform/ui_output.go
new file mode 100644
index 0000000..a816b0d
--- /dev/null
+++ b/v1.5.7/internal/terraform/ui_output.go
@@ -0,0 +1,10 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+// UIOutput is the interface that must be implemented to output
+// data to the end user.
+type UIOutput interface {
+	Output(string)
+}
diff --git a/v1.5.7/internal/terraform/ui_output_callback.go b/v1.5.7/internal/terraform/ui_output_callback.go
new file mode 100644
index 0000000..e79f082
--- /dev/null
+++ b/v1.5.7/internal/terraform/ui_output_callback.go
@@ -0,0 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+type CallbackUIOutput struct {
+	OutputFn func(string)
+}
+
+func (o *CallbackUIOutput) Output(v string) {
+	o.OutputFn(v)
+}
diff --git a/v1.5.7/internal/terraform/ui_output_callback_test.go b/v1.5.7/internal/terraform/ui_output_callback_test.go
new file mode 100644
index 0000000..8748c0b
--- /dev/null
+++ b/v1.5.7/internal/terraform/ui_output_callback_test.go
@@ -0,0 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+)
+
+func TestCallbackUIOutput_impl(t *testing.T) {
+	var _ UIOutput = new(CallbackUIOutput)
+}
diff --git a/v1.5.7/internal/terraform/ui_output_mock.go b/v1.5.7/internal/terraform/ui_output_mock.go
new file mode 100644
index 0000000..641d076
--- /dev/null
+++ b/v1.5.7/internal/terraform/ui_output_mock.go
@@ -0,0 +1,24 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import "sync"
+
+// MockUIOutput is an implementation of UIOutput that can be used for tests.
+type MockUIOutput struct {
+	sync.Mutex
+	OutputCalled  bool
+	OutputMessage string
+	OutputFn      func(string)
+}
+
+func (o *MockUIOutput) Output(v string) {
+	o.Lock()
+	defer o.Unlock()
+	o.OutputCalled = true
+	o.OutputMessage = v
+	if o.OutputFn != nil {
+		o.OutputFn(v)
+	}
+}
diff --git a/v1.5.7/internal/terraform/ui_output_mock_test.go b/v1.5.7/internal/terraform/ui_output_mock_test.go
new file mode 100644
index 0000000..89d564a
--- /dev/null
+++ b/v1.5.7/internal/terraform/ui_output_mock_test.go
@@ -0,0 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+)
+
+func TestMockUIOutput(t *testing.T) {
+	var _ UIOutput = new(MockUIOutput)
+}
diff --git a/v1.5.7/internal/terraform/ui_output_provisioner.go b/v1.5.7/internal/terraform/ui_output_provisioner.go
new file mode 100644
index 0000000..524cfe8
--- /dev/null
+++ b/v1.5.7/internal/terraform/ui_output_provisioner.go
@@ -0,0 +1,22 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+// ProvisionerUIOutput is an implementation of UIOutput that calls a hook
+// for the output so that the hooks can handle it.
+type ProvisionerUIOutput struct {
+	InstanceAddr    addrs.AbsResourceInstance
+	ProvisionerType string
+	Hooks           []Hook
+}
+
+func (o *ProvisionerUIOutput) Output(msg string) {
+	for _, h := range o.Hooks {
+		h.ProvisionOutput(o.InstanceAddr, o.ProvisionerType, msg)
+	}
+}
diff --git a/v1.5.7/internal/terraform/ui_output_provisioner_test.go b/v1.5.7/internal/terraform/ui_output_provisioner_test.go
new file mode 100644
index 0000000..9b3118d
--- /dev/null
+++ b/v1.5.7/internal/terraform/ui_output_provisioner_test.go
@@ -0,0 +1,39 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+)
+
+func TestProvisionerUIOutput_impl(t *testing.T) {
+	var _ UIOutput = new(ProvisionerUIOutput)
+}
+
+func TestProvisionerUIOutputOutput(t *testing.T) {
+	hook := new(MockHook)
+	output := &ProvisionerUIOutput{
+		InstanceAddr: addrs.Resource{
+			Mode: addrs.ManagedResourceMode,
+			Type: "test_thing",
+			Name: "test",
+		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
+		ProvisionerType: "foo",
+		Hooks:           []Hook{hook},
+	}
+
+	output.Output("bar")
+
+	if !hook.ProvisionOutputCalled {
+		t.Fatal("hook.ProvisionOutput was not called, and should've been")
+	}
+	if got, want := hook.ProvisionOutputProvisionerType, "foo"; got != want {
+		t.Fatalf("wrong provisioner type\ngot:  %q\nwant: %q", got, want)
+	}
+	if got, want := hook.ProvisionOutputMessage, "bar"; got != want {
+		t.Fatalf("wrong output message\ngot:  %q\nwant: %q", got, want)
+	}
+}
diff --git a/v1.5.7/internal/terraform/update_state_hook.go b/v1.5.7/internal/terraform/update_state_hook.go
new file mode 100644
index 0000000..c89dd3f
--- /dev/null
+++ b/v1.5.7/internal/terraform/update_state_hook.go
@@ -0,0 +1,22 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+// updateStateHook calls the PostStateUpdate hook with the current state.
+func updateStateHook(ctx EvalContext) error {
+	// In principle we could grab the lock here just long enough to take a
+	// deep copy and then pass that to our hooks below, but we'll instead
+	// hold the hook for the duration to avoid the potential confusing
+	// situation of us racing to call PostStateUpdate concurrently with
+	// different state snapshots.
+	stateSync := ctx.State()
+	state := stateSync.Lock().DeepCopy()
+	defer stateSync.Unlock()
+
+	// Call the hook
+	err := ctx.Hook(func(h Hook) (HookAction, error) {
+		return h.PostStateUpdate(state)
+	})
+	return err
+}
diff --git a/v1.5.7/internal/terraform/update_state_hook_test.go b/v1.5.7/internal/terraform/update_state_hook_test.go
new file mode 100644
index 0000000..c500b8b
--- /dev/null
+++ b/v1.5.7/internal/terraform/update_state_hook_test.go
@@ -0,0 +1,36 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/states"
+)
+
+func TestUpdateStateHook(t *testing.T) {
+	mockHook := new(MockHook)
+
+	state := states.NewState()
+	state.Module(addrs.RootModuleInstance).SetLocalValue("foo", cty.StringVal("hello"))
+
+	ctx := new(MockEvalContext)
+	ctx.HookHook = mockHook
+	ctx.StateState = state.SyncWrapper()
+
+	if err := updateStateHook(ctx); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !mockHook.PostStateUpdateCalled {
+		t.Fatal("should call PostStateUpdate")
+	}
+	if mockHook.PostStateUpdateState.LocalValue(addrs.LocalValue{Name: "foo"}.Absolute(addrs.RootModuleInstance)) != cty.StringVal("hello") {
+		t.Fatalf("wrong state passed to hook: %s", spew.Sdump(mockHook.PostStateUpdateState))
+	}
+}
diff --git a/v1.5.7/internal/terraform/upgrade_resource_state.go b/v1.5.7/internal/terraform/upgrade_resource_state.go
new file mode 100644
index 0000000..40c03c2
--- /dev/null
+++ b/v1.5.7/internal/terraform/upgrade_resource_state.go
@@ -0,0 +1,209 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"encoding/json"
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/providers"
+	"github.com/hashicorp/terraform/internal/states"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// upgradeResourceState will, if necessary, run the provider-defined upgrade
+// logic against the given state object to make it compliant with the
+// current schema version. This is a no-op if the given state object is
+// already at the latest version.
+//
+// If any errors occur during upgrade, error diagnostics are returned. In that
+// case it is not safe to proceed with using the original state object.
+func upgradeResourceState(addr addrs.AbsResourceInstance, provider providers.Interface, src *states.ResourceInstanceObjectSrc, currentSchema *configschema.Block, currentVersion uint64) (*states.ResourceInstanceObjectSrc, tfdiags.Diagnostics) {
+	if addr.Resource.Resource.Mode != addrs.ManagedResourceMode {
+		// We only do state upgrading for managed resources.
+		// This was a part of the normal workflow in older versions and
+		// returned early, so we are only going to log the error for now.
+		log.Printf("[ERROR] data resource %s should not require state upgrade", addr)
+		return src, nil
+	}
+
+	// Remove any attributes from state that are not present in the schema.
+	// This was previously taken care of by the provider, but data sources do
+	// not go through the UpgradeResourceState process.
+	//
+	// Legacy flatmap state is already taken care of during conversion.
+	// If the schema version is be changed, then allow the provider to handle
+	// removed attributes.
+	if len(src.AttrsJSON) > 0 && src.SchemaVersion == currentVersion {
+		src.AttrsJSON = stripRemovedStateAttributes(src.AttrsJSON, currentSchema.ImpliedType())
+	}
+
+	stateIsFlatmap := len(src.AttrsJSON) == 0
+
+	// TODO: This should eventually use a proper FQN.
+	providerType := addr.Resource.Resource.ImpliedProvider()
+	if src.SchemaVersion > currentVersion {
+		log.Printf("[TRACE] upgradeResourceState: can't downgrade state for %s from version %d to %d", addr, src.SchemaVersion, currentVersion)
+		var diags tfdiags.Diagnostics
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Resource instance managed by newer provider version",
+			// This is not a very good error message, but we don't retain enough
+			// information in state to give good feedback on what provider
+			// version might be required here. :(
+			fmt.Sprintf("The current state of %s was created by a newer provider version than is currently selected. Upgrade the %s provider to work with this state.", addr, providerType),
+		))
+		return nil, diags
+	}
+
+	// If we get down here then we need to upgrade the state, with the
+	// provider's help.
+	// If this state was originally created by a version of Terraform prior to
+	// v0.12, this also includes translating from legacy flatmap to new-style
+	// representation, since only the provider has enough information to
+	// understand a flatmap built against an older schema.
+	if src.SchemaVersion != currentVersion {
+		log.Printf("[TRACE] upgradeResourceState: upgrading state for %s from version %d to %d using provider %q", addr, src.SchemaVersion, currentVersion, providerType)
+	} else {
+		log.Printf("[TRACE] upgradeResourceState: schema version of %s is still %d; calling provider %q for any other minor fixups", addr, currentVersion, providerType)
+	}
+
+	req := providers.UpgradeResourceStateRequest{
+		TypeName: addr.Resource.Resource.Type,
+
+		// TODO: The internal schema version representations are all using
+		// uint64 instead of int64, but unsigned integers aren't friendly
+		// to all protobuf target languages so in practice we use int64
+		// on the wire. In future we will change all of our internal
+		// representations to int64 too.
+		Version: int64(src.SchemaVersion),
+	}
+
+	if stateIsFlatmap {
+		req.RawStateFlatmap = src.AttrsFlat
+	} else {
+		req.RawStateJSON = src.AttrsJSON
+	}
+
+	resp := provider.UpgradeResourceState(req)
+	diags := resp.Diagnostics
+	if diags.HasErrors() {
+		return nil, diags
+	}
+
+	// After upgrading, the new value must conform to the current schema. When
+	// going over RPC this is actually already ensured by the
+	// marshaling/unmarshaling of the new value, but we'll check it here
+	// anyway for robustness, e.g. for in-process providers.
+	newValue := resp.UpgradedState
+	if errs := newValue.Type().TestConformance(currentSchema.ImpliedType()); len(errs) > 0 {
+		for _, err := range errs {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid resource state upgrade",
+				fmt.Sprintf("The %s provider upgraded the state for %s from a previous version, but produced an invalid result: %s.", providerType, addr, tfdiags.FormatError(err)),
+			))
+		}
+		return nil, diags
+	}
+
+	new, err := src.CompleteUpgrade(newValue, currentSchema.ImpliedType(), uint64(currentVersion))
+	if err != nil {
+		// We already checked for type conformance above, so getting into this
+		// codepath should be rare and is probably a bug somewhere under CompleteUpgrade.
+		diags = diags.Append(tfdiags.Sourceless(
+			tfdiags.Error,
+			"Failed to encode result of resource state upgrade",
+			fmt.Sprintf("Failed to encode state for %s after resource schema upgrade: %s.", addr, tfdiags.FormatError(err)),
+		))
+	}
+	return new, diags
+}
+
+// stripRemovedStateAttributes deletes any attributes no longer present in the
+// schema, so that the json can be correctly decoded.
+func stripRemovedStateAttributes(state []byte, ty cty.Type) []byte {
+	jsonMap := map[string]interface{}{}
+	err := json.Unmarshal(state, &jsonMap)
+	if err != nil {
+		// we just log any errors here, and let the normal decode process catch
+		// invalid JSON.
+		log.Printf("[ERROR] UpgradeResourceState: stripRemovedStateAttributes: %s", err)
+		return state
+	}
+
+	// if no changes were made, we return the original state to ensure nothing
+	// was altered in the marshaling process.
+	if !removeRemovedAttrs(jsonMap, ty) {
+		return state
+	}
+
+	js, err := json.Marshal(jsonMap)
+	if err != nil {
+		// if the json map was somehow mangled enough to not marhsal, something
+		// went horribly wrong
+		panic(err)
+	}
+
+	return js
+}
+
+// strip out the actual missing attributes, and return a bool indicating if any
+// changes were made.
+func removeRemovedAttrs(v interface{}, ty cty.Type) bool {
+	modified := false
+	// we're only concerned with finding maps that correspond to object
+	// attributes
+	switch v := v.(type) {
+	case []interface{}:
+		switch {
+		// If these aren't blocks the next call will be a noop
+		case ty.IsListType() || ty.IsSetType():
+			eTy := ty.ElementType()
+			for _, eV := range v {
+				modified = removeRemovedAttrs(eV, eTy) || modified
+			}
+		}
+		return modified
+	case map[string]interface{}:
+		switch {
+		case ty.IsMapType():
+			// map blocks aren't yet supported, but handle this just in case
+			eTy := ty.ElementType()
+			for _, eV := range v {
+				modified = removeRemovedAttrs(eV, eTy) || modified
+			}
+			return modified
+
+		case ty == cty.DynamicPseudoType:
+			log.Printf("[DEBUG] UpgradeResourceState: ignoring dynamic block: %#v\n", v)
+			return false
+
+		case ty.IsObjectType():
+			attrTypes := ty.AttributeTypes()
+			for attr, attrV := range v {
+				attrTy, ok := attrTypes[attr]
+				if !ok {
+					log.Printf("[DEBUG] UpgradeResourceState: attribute %q no longer present in schema", attr)
+					delete(v, attr)
+					modified = true
+					continue
+				}
+
+				modified = removeRemovedAttrs(attrV, attrTy) || modified
+			}
+			return modified
+		default:
+			// This shouldn't happen, and will fail to decode further on, so
+			// there's no need to handle it here.
+			log.Printf("[WARN] UpgradeResourceState: unexpected type %#v for map in json state", ty)
+			return false
+		}
+	}
+	return modified
+}
diff --git a/v1.5.7/internal/terraform/upgrade_resource_state_test.go b/v1.5.7/internal/terraform/upgrade_resource_state_test.go
new file mode 100644
index 0000000..0e277cb
--- /dev/null
+++ b/v1.5.7/internal/terraform/upgrade_resource_state_test.go
@@ -0,0 +1,151 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestStripRemovedStateAttributes(t *testing.T) {
+	cases := []struct {
+		name     string
+		state    map[string]interface{}
+		expect   map[string]interface{}
+		ty       cty.Type
+		modified bool
+	}{
+		{
+			"removed string",
+			map[string]interface{}{
+				"a": "ok",
+				"b": "gone",
+			},
+			map[string]interface{}{
+				"a": "ok",
+			},
+			cty.Object(map[string]cty.Type{
+				"a": cty.String,
+			}),
+			true,
+		},
+		{
+			"removed null",
+			map[string]interface{}{
+				"a": "ok",
+				"b": nil,
+			},
+			map[string]interface{}{
+				"a": "ok",
+			},
+			cty.Object(map[string]cty.Type{
+				"a": cty.String,
+			}),
+			true,
+		},
+		{
+			"removed nested string",
+			map[string]interface{}{
+				"a": "ok",
+				"b": map[string]interface{}{
+					"a": "ok",
+					"b": "removed",
+				},
+			},
+			map[string]interface{}{
+				"a": "ok",
+				"b": map[string]interface{}{
+					"a": "ok",
+				},
+			},
+			cty.Object(map[string]cty.Type{
+				"a": cty.String,
+				"b": cty.Object(map[string]cty.Type{
+					"a": cty.String,
+				}),
+			}),
+			true,
+		},
+		{
+			"removed nested list",
+			map[string]interface{}{
+				"a": "ok",
+				"b": map[string]interface{}{
+					"a": "ok",
+					"b": []interface{}{"removed"},
+				},
+			},
+			map[string]interface{}{
+				"a": "ok",
+				"b": map[string]interface{}{
+					"a": "ok",
+				},
+			},
+			cty.Object(map[string]cty.Type{
+				"a": cty.String,
+				"b": cty.Object(map[string]cty.Type{
+					"a": cty.String,
+				}),
+			}),
+			true,
+		},
+		{
+			"removed keys in set of objs",
+			map[string]interface{}{
+				"a": "ok",
+				"b": map[string]interface{}{
+					"a": "ok",
+					"set": []interface{}{
+						map[string]interface{}{
+							"x": "ok",
+							"y": "removed",
+						},
+						map[string]interface{}{
+							"x": "ok",
+							"y": "removed",
+						},
+					},
+				},
+			},
+			map[string]interface{}{
+				"a": "ok",
+				"b": map[string]interface{}{
+					"a": "ok",
+					"set": []interface{}{
+						map[string]interface{}{
+							"x": "ok",
+						},
+						map[string]interface{}{
+							"x": "ok",
+						},
+					},
+				},
+			},
+			cty.Object(map[string]cty.Type{
+				"a": cty.String,
+				"b": cty.Object(map[string]cty.Type{
+					"a": cty.String,
+					"set": cty.Set(cty.Object(map[string]cty.Type{
+						"x": cty.String,
+					})),
+				}),
+			}),
+			true,
+		},
+	}
+
+	for _, tc := range cases {
+		t.Run(tc.name, func(t *testing.T) {
+			modified := removeRemovedAttrs(tc.state, tc.ty)
+			if !reflect.DeepEqual(tc.state, tc.expect) {
+				t.Fatalf("expected: %#v\n      got: %#v\n", tc.expect, tc.state)
+			}
+			if modified != tc.modified {
+				t.Fatal("incorrect return value")
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/terraform/util.go b/v1.5.7/internal/terraform/util.go
new file mode 100644
index 0000000..d25e105
--- /dev/null
+++ b/v1.5.7/internal/terraform/util.go
@@ -0,0 +1,78 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"sort"
+)
+
+// Semaphore is a wrapper around a channel to provide
+// utility methods to clarify that we are treating the
+// channel as a semaphore
+type Semaphore chan struct{}
+
+// NewSemaphore creates a semaphore that allows up
+// to a given limit of simultaneous acquisitions
+func NewSemaphore(n int) Semaphore {
+	if n <= 0 {
+		panic("semaphore with limit <=0")
+	}
+	ch := make(chan struct{}, n)
+	return Semaphore(ch)
+}
+
+// Acquire is used to acquire an available slot.
+// Blocks until available.
+func (s Semaphore) Acquire() {
+	s <- struct{}{}
+}
+
+// TryAcquire is used to do a non-blocking acquire.
+// Returns a bool indicating success
+func (s Semaphore) TryAcquire() bool {
+	select {
+	case s <- struct{}{}:
+		return true
+	default:
+		return false
+	}
+}
+
+// Release is used to return a slot. Acquire must
+// be called as a pre-condition.
+func (s Semaphore) Release() {
+	select {
+	case <-s:
+	default:
+		panic("release without an acquire")
+	}
+}
+
+// strSliceContains checks if a given string is contained in a slice
+// When anybody asks why Go needs generics, here you go.
+func strSliceContains(haystack []string, needle string) bool {
+	for _, s := range haystack {
+		if s == needle {
+			return true
+		}
+	}
+	return false
+}
+
+// deduplicate a slice of strings
+func uniqueStrings(s []string) []string {
+	if len(s) < 2 {
+		return s
+	}
+
+	sort.Strings(s)
+	result := make([]string, 1, len(s))
+	result[0] = s[0]
+	for i := 1; i < len(s); i++ {
+		if s[i] != result[len(result)-1] {
+			result = append(result, s[i])
+		}
+	}
+	return result
+}
diff --git a/v1.5.7/internal/terraform/util_test.go b/v1.5.7/internal/terraform/util_test.go
new file mode 100644
index 0000000..0676c6f
--- /dev/null
+++ b/v1.5.7/internal/terraform/util_test.go
@@ -0,0 +1,94 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+	"time"
+)
+
+func TestSemaphore(t *testing.T) {
+	s := NewSemaphore(2)
+	timer := time.AfterFunc(time.Second, func() {
+		panic("deadlock")
+	})
+	defer timer.Stop()
+
+	s.Acquire()
+	if !s.TryAcquire() {
+		t.Fatalf("should acquire")
+	}
+	if s.TryAcquire() {
+		t.Fatalf("should not acquire")
+	}
+	s.Release()
+	s.Release()
+
+	// This release should panic
+	defer func() {
+		r := recover()
+		if r == nil {
+			t.Fatalf("should panic")
+		}
+	}()
+	s.Release()
+}
+
+func TestStrSliceContains(t *testing.T) {
+	if strSliceContains(nil, "foo") {
+		t.Fatalf("Bad")
+	}
+	if strSliceContains([]string{}, "foo") {
+		t.Fatalf("Bad")
+	}
+	if strSliceContains([]string{"bar"}, "foo") {
+		t.Fatalf("Bad")
+	}
+	if !strSliceContains([]string{"bar", "foo"}, "foo") {
+		t.Fatalf("Bad")
+	}
+}
+
+func TestUniqueStrings(t *testing.T) {
+	cases := []struct {
+		Input    []string
+		Expected []string
+	}{
+		{
+			[]string{},
+			[]string{},
+		},
+		{
+			[]string{"x"},
+			[]string{"x"},
+		},
+		{
+			[]string{"a", "b", "c"},
+			[]string{"a", "b", "c"},
+		},
+		{
+			[]string{"a", "a", "a"},
+			[]string{"a"},
+		},
+		{
+			[]string{"a", "b", "a", "b", "a", "a"},
+			[]string{"a", "b"},
+		},
+		{
+			[]string{"c", "b", "a", "c", "b"},
+			[]string{"a", "b", "c"},
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("unique-%d", i), func(t *testing.T) {
+			actual := uniqueStrings(tc.Input)
+			if !reflect.DeepEqual(tc.Expected, actual) {
+				t.Fatalf("Expected: %q\nGot: %q", tc.Expected, actual)
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/terraform/validate_selfref.go b/v1.5.7/internal/terraform/validate_selfref.go
new file mode 100644
index 0000000..c2100c2
--- /dev/null
+++ b/v1.5.7/internal/terraform/validate_selfref.go
@@ -0,0 +1,63 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+	"github.com/hashicorp/terraform/internal/lang"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// validateSelfRef checks to ensure that expressions within a particular
+// referencable block do not reference that same block.
+func validateSelfRef(addr addrs.Referenceable, config hcl.Body, providerSchema *ProviderSchema) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	addrStrs := make([]string, 0, 1)
+	addrStrs = append(addrStrs, addr.String())
+	switch tAddr := addr.(type) {
+	case addrs.ResourceInstance:
+		// A resource instance may not refer to its containing resource either.
+		addrStrs = append(addrStrs, tAddr.ContainingResource().String())
+	}
+
+	if providerSchema == nil {
+		diags = diags.Append(fmt.Errorf("provider schema unavailable while validating %s for self-references; this is a bug in Terraform and should be reported", addr))
+		return diags
+	}
+
+	var schema *configschema.Block
+	switch tAddr := addr.(type) {
+	case addrs.Resource:
+		schema, _ = providerSchema.SchemaForResourceAddr(tAddr)
+	case addrs.ResourceInstance:
+		schema, _ = providerSchema.SchemaForResourceAddr(tAddr.ContainingResource())
+	}
+
+	if schema == nil {
+		diags = diags.Append(fmt.Errorf("no schema available for %s to validate for self-references; this is a bug in Terraform and should be reported", addr))
+		return diags
+	}
+
+	refs, _ := lang.ReferencesInBlock(config, schema)
+	for _, ref := range refs {
+		for _, addrStr := range addrStrs {
+			if ref.Subject.String() == addrStr {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Self-referential block",
+					Detail:   fmt.Sprintf("Configuration for %s may not refer to itself.", addrStr),
+					Subject:  ref.SourceRange.ToHCL().Ptr(),
+				})
+			}
+		}
+	}
+
+	return diags
+}
diff --git a/v1.5.7/internal/terraform/validate_selfref_test.go b/v1.5.7/internal/terraform/validate_selfref_test.go
new file mode 100644
index 0000000..41de79a
--- /dev/null
+++ b/v1.5.7/internal/terraform/validate_selfref_test.go
@@ -0,0 +1,108 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/configs/configschema"
+
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hcltest"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestValidateSelfRef(t *testing.T) {
+	rAddr := addrs.Resource{
+		Mode: addrs.ManagedResourceMode,
+		Type: "aws_instance",
+		Name: "foo",
+	}
+
+	tests := []struct {
+		Name string
+		Addr addrs.Referenceable
+		Expr hcl.Expression
+		Err  bool
+	}{
+		{
+			"no references at all",
+			rAddr,
+			hcltest.MockExprLiteral(cty.StringVal("bar")),
+			false,
+		},
+
+		{
+			"non self reference",
+			rAddr,
+			hcltest.MockExprTraversalSrc("aws_instance.bar.id"),
+			false,
+		},
+
+		{
+			"self reference",
+			rAddr,
+			hcltest.MockExprTraversalSrc("aws_instance.foo.id"),
+			true,
+		},
+
+		{
+			"self reference other index",
+			rAddr,
+			hcltest.MockExprTraversalSrc("aws_instance.foo[4].id"),
+			false,
+		},
+
+		{
+			"self reference same index",
+			rAddr.Instance(addrs.IntKey(4)),
+			hcltest.MockExprTraversalSrc("aws_instance.foo[4].id"),
+			true,
+		},
+
+		{
+			"self reference whole",
+			rAddr.Instance(addrs.IntKey(4)),
+			hcltest.MockExprTraversalSrc("aws_instance.foo"),
+			true,
+		},
+	}
+
+	for i, test := range tests {
+		t.Run(fmt.Sprintf("%d-%s", i, test.Name), func(t *testing.T) {
+			body := hcltest.MockBody(&hcl.BodyContent{
+				Attributes: hcl.Attributes{
+					"foo": {
+						Name: "foo",
+						Expr: test.Expr,
+					},
+				},
+			})
+
+			ps := &ProviderSchema{
+				ResourceTypes: map[string]*configschema.Block{
+					"aws_instance": &configschema.Block{
+						Attributes: map[string]*configschema.Attribute{
+							"foo": {
+								Type:     cty.String,
+								Required: true,
+							},
+						},
+					},
+				},
+			}
+
+			diags := validateSelfRef(test.Addr, body, ps)
+			if diags.HasErrors() != test.Err {
+				if test.Err {
+					t.Errorf("unexpected success; want error")
+				} else {
+					t.Errorf("unexpected error\n\n%s", diags.Err())
+				}
+			}
+		})
+	}
+}
diff --git a/v1.5.7/internal/terraform/valuesourcetype_string.go b/v1.5.7/internal/terraform/valuesourcetype_string.go
new file mode 100644
index 0000000..627593d
--- /dev/null
+++ b/v1.5.7/internal/terraform/valuesourcetype_string.go
@@ -0,0 +1,59 @@
+// Code generated by "stringer -type ValueSourceType"; DO NOT EDIT.
+
+package terraform
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[ValueFromUnknown-0]
+	_ = x[ValueFromConfig-67]
+	_ = x[ValueFromAutoFile-70]
+	_ = x[ValueFromNamedFile-78]
+	_ = x[ValueFromCLIArg-65]
+	_ = x[ValueFromEnvVar-69]
+	_ = x[ValueFromInput-73]
+	_ = x[ValueFromPlan-80]
+	_ = x[ValueFromCaller-83]
+}
+
+const (
+	_ValueSourceType_name_0 = "ValueFromUnknown"
+	_ValueSourceType_name_1 = "ValueFromCLIArg"
+	_ValueSourceType_name_2 = "ValueFromConfig"
+	_ValueSourceType_name_3 = "ValueFromEnvVarValueFromAutoFile"
+	_ValueSourceType_name_4 = "ValueFromInput"
+	_ValueSourceType_name_5 = "ValueFromNamedFile"
+	_ValueSourceType_name_6 = "ValueFromPlan"
+	_ValueSourceType_name_7 = "ValueFromCaller"
+)
+
+var (
+	_ValueSourceType_index_3 = [...]uint8{0, 15, 32}
+)
+
+func (i ValueSourceType) String() string {
+	switch {
+	case i == 0:
+		return _ValueSourceType_name_0
+	case i == 65:
+		return _ValueSourceType_name_1
+	case i == 67:
+		return _ValueSourceType_name_2
+	case 69 <= i && i <= 70:
+		i -= 69
+		return _ValueSourceType_name_3[_ValueSourceType_index_3[i]:_ValueSourceType_index_3[i+1]]
+	case i == 73:
+		return _ValueSourceType_name_4
+	case i == 78:
+		return _ValueSourceType_name_5
+	case i == 80:
+		return _ValueSourceType_name_6
+	case i == 83:
+		return _ValueSourceType_name_7
+	default:
+		return "ValueSourceType(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/v1.5.7/internal/terraform/variables.go b/v1.5.7/internal/terraform/variables.go
new file mode 100644
index 0000000..3c4015c
--- /dev/null
+++ b/v1.5.7/internal/terraform/variables.go
@@ -0,0 +1,318 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"fmt"
+
+	"github.com/zclconf/go-cty/cty"
+
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// InputValue represents a raw value for a root module input variable as
+// provided by the external caller into a function like terraform.Context.Plan.
+//
+// InputValue should represent as directly as possible what the user set the
+// variable to, without any attempt to convert the value to the variable's
+// type constraint or substitute the configured default values for variables
+// that wasn't set. Those adjustments will be handled by Terraform Core itself
+// as part of performing the requested operation.
+//
+// A Terraform Core caller must provide an InputValue object for each of the
+// variables declared in the root module, even if the end user didn't provide
+// an explicit value for some of them. See the Value field documentation for
+// how to handle that situation.
+//
+// Terraform Core also internally uses InputValue to represent the raw value
+// provided for a variable in a child module call, following the same
+// conventions. However, that's an implementation detail not visible to
+// outside callers.
+type InputValue struct {
+	// Value is the raw value as provided by the user as part of the plan
+	// options, or a corresponding similar data structure for non-plan
+	// operations.
+	//
+	// If a particular variable declared in the root module is _not_ set by
+	// the user then the caller must still provide an InputValue for it but
+	// must set Value to cty.NilVal to represent the absense of a value.
+	// This requirement is to help detect situations where the caller isn't
+	// correctly detecting and handling all of the declared variables.
+	//
+	// For historical reasons it's important that callers distinguish the
+	// situation of the value not being set at all (cty.NilVal) from the
+	// situation of it being explicitly set to null (a cty.NullVal result):
+	// for "nullable" input variables that distinction unfortunately decides
+	// whether the final value will be the variable's default or will be
+	// explicitly null.
+	Value cty.Value
+
+	// SourceType is a high-level category for where the value of Value
+	// came from, which Terraform Core uses to tailor some of its error
+	// messages to be more helpful to the user.
+	//
+	// Some SourceType values should be accompanied by a populated SourceRange
+	// value. See that field's documentation below for more information.
+	SourceType ValueSourceType
+
+	// SourceRange provides source location information for values whose
+	// SourceType is either ValueFromConfig, ValueFromNamedFile, or
+	// ValueForNormalFile. It is not populated for other source types, and so
+	// should not be used.
+	SourceRange tfdiags.SourceRange
+}
+
+// ValueSourceType describes what broad category of source location provided
+// a particular value.
+type ValueSourceType rune
+
+const (
+	// ValueFromUnknown is the zero value of ValueSourceType and is not valid.
+	ValueFromUnknown ValueSourceType = 0
+
+	// ValueFromConfig indicates that a value came from a .tf or .tf.json file,
+	// e.g. the default value defined for a variable.
+	ValueFromConfig ValueSourceType = 'C'
+
+	// ValueFromAutoFile indicates that a value came from a "values file", like
+	// a .tfvars file, that was implicitly loaded by naming convention.
+	ValueFromAutoFile ValueSourceType = 'F'
+
+	// ValueFromNamedFile indicates that a value came from a named "values file",
+	// like a .tfvars file, that was passed explicitly on the command line (e.g.
+	// -var-file=foo.tfvars).
+	ValueFromNamedFile ValueSourceType = 'N'
+
+	// ValueFromCLIArg indicates that the value was provided directly in
+	// a CLI argument. The name of this argument is not recorded and so it must
+	// be inferred from context.
+	ValueFromCLIArg ValueSourceType = 'A'
+
+	// ValueFromEnvVar indicates that the value was provided via an environment
+	// variable. The name of the variable is not recorded and so it must be
+	// inferred from context.
+	ValueFromEnvVar ValueSourceType = 'E'
+
+	// ValueFromInput indicates that the value was provided at an interactive
+	// input prompt.
+	ValueFromInput ValueSourceType = 'I'
+
+	// ValueFromPlan indicates that the value was retrieved from a stored plan.
+	ValueFromPlan ValueSourceType = 'P'
+
+	// ValueFromCaller indicates that the value was explicitly overridden by
+	// a caller to Context.SetVariable after the context was constructed.
+	ValueFromCaller ValueSourceType = 'S'
+)
+
+func (v *InputValue) GoString() string {
+	if (v.SourceRange != tfdiags.SourceRange{}) {
+		return fmt.Sprintf("&terraform.InputValue{Value: %#v, SourceType: %#v, SourceRange: %#v}", v.Value, v.SourceType, v.SourceRange)
+	} else {
+		return fmt.Sprintf("&terraform.InputValue{Value: %#v, SourceType: %#v}", v.Value, v.SourceType)
+	}
+}
+
+// HasSourceRange returns true if the reciever has a source type for which
+// we expect the SourceRange field to be populated with a valid range.
+func (v *InputValue) HasSourceRange() bool {
+	return v.SourceType.HasSourceRange()
+}
+
+// HasSourceRange returns true if the reciever is one of the source types
+// that is used along with a valid SourceRange field when appearing inside an
+// InputValue object.
+func (v ValueSourceType) HasSourceRange() bool {
+	switch v {
+	case ValueFromConfig, ValueFromAutoFile, ValueFromNamedFile:
+		return true
+	default:
+		return false
+	}
+}
+
+func (v ValueSourceType) GoString() string {
+	return fmt.Sprintf("terraform.%s", v)
+}
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type ValueSourceType
+
+// InputValues is a map of InputValue instances.
+type InputValues map[string]*InputValue
+
+// InputValuesFromCaller turns the given map of naked values into an
+// InputValues that attributes each value to "a caller", using the source
+// type ValueFromCaller. This is primarily useful for testing purposes.
+//
+// This should not be used as a general way to convert map[string]cty.Value
+// into InputValues, since in most real cases we want to set a suitable
+// other SourceType and possibly SourceRange value.
+func InputValuesFromCaller(vals map[string]cty.Value) InputValues {
+	ret := make(InputValues, len(vals))
+	for k, v := range vals {
+		ret[k] = &InputValue{
+			Value:      v,
+			SourceType: ValueFromCaller,
+		}
+	}
+	return ret
+}
+
+// Override merges the given value maps with the receiver, overriding any
+// conflicting keys so that the latest definition wins.
+func (vv InputValues) Override(others ...InputValues) InputValues {
+	// FIXME: This should check to see if any of the values are maps and
+	// merge them if so, in order to preserve the behavior from prior to
+	// Terraform 0.12.
+	ret := make(InputValues)
+	for k, v := range vv {
+		ret[k] = v
+	}
+	for _, other := range others {
+		for k, v := range other {
+			ret[k] = v
+		}
+	}
+	return ret
+}
+
+// JustValues returns a map that just includes the values, discarding the
+// source information.
+func (vv InputValues) JustValues() map[string]cty.Value {
+	ret := make(map[string]cty.Value, len(vv))
+	for k, v := range vv {
+		ret[k] = v.Value
+	}
+	return ret
+}
+
+// SameValues returns true if the given InputValues has the same values as
+// the receiever, disregarding the source types and source ranges.
+//
+// Values are compared using the cty "RawEquals" method, which means that
+// unknown values can be considered equal to one another if they are of the
+// same type.
+func (vv InputValues) SameValues(other InputValues) bool {
+	if len(vv) != len(other) {
+		return false
+	}
+
+	for k, v := range vv {
+		ov, exists := other[k]
+		if !exists {
+			return false
+		}
+		if !v.Value.RawEquals(ov.Value) {
+			return false
+		}
+	}
+
+	return true
+}
+
+// HasValues returns true if the reciever has the same values as in the given
+// map, disregarding the source types and source ranges.
+//
+// Values are compared using the cty "RawEquals" method, which means that
+// unknown values can be considered equal to one another if they are of the
+// same type.
+func (vv InputValues) HasValues(vals map[string]cty.Value) bool {
+	if len(vv) != len(vals) {
+		return false
+	}
+
+	for k, v := range vv {
+		oVal, exists := vals[k]
+		if !exists {
+			return false
+		}
+		if !v.Value.RawEquals(oVal) {
+			return false
+		}
+	}
+
+	return true
+}
+
+// Identical returns true if the given InputValues has the same values,
+// source types, and source ranges as the receiver.
+//
+// Values are compared using the cty "RawEquals" method, which means that
+// unknown values can be considered equal to one another if they are of the
+// same type.
+//
+// This method is primarily for testing. For most practical purposes, it's
+// better to use SameValues or HasValues.
+func (vv InputValues) Identical(other InputValues) bool {
+	if len(vv) != len(other) {
+		return false
+	}
+
+	for k, v := range vv {
+		ov, exists := other[k]
+		if !exists {
+			return false
+		}
+		if !v.Value.RawEquals(ov.Value) {
+			return false
+		}
+		if v.SourceType != ov.SourceType {
+			return false
+		}
+		if v.SourceRange != ov.SourceRange {
+			return false
+		}
+	}
+
+	return true
+}
+
+// checkInputVariables ensures that the caller provided an InputValue
+// definition for each root module variable declared in the configuration.
+// The caller must provide an InputVariables with keys exactly matching
+// the declared variables, though some of them may be marked explicitly
+// unset by their values being cty.NilVal.
+//
+// This doesn't perform any type checking, default value substitution, or
+// validation checks. Those are all handled during a graph walk when we
+// visit the graph nodes representing each root variable.
+//
+// The set of values is considered valid only if the returned diagnostics
+// does not contain errors. A valid set of values may still produce warnings,
+// which should be returned to the user.
+func checkInputVariables(vcs map[string]*configs.Variable, vs InputValues) tfdiags.Diagnostics {
+	var diags tfdiags.Diagnostics
+
+	for name := range vcs {
+		_, isSet := vs[name]
+		if !isSet {
+			// Always an error, since the caller should have produced an
+			// item with Value: cty.NilVal to be explicit that it offered
+			// an opportunity to set this variable.
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Unassigned variable",
+				fmt.Sprintf("The input variable %q has not been assigned a value. This is a bug in Terraform; please report it in a GitHub issue.", name),
+			))
+			continue
+		}
+	}
+
+	// Check for any variables that are assigned without being configured.
+	// This is always an implementation error in the caller, because we
+	// expect undefined variables to be caught during context construction
+	// where there is better context to report it well.
+	for name := range vs {
+		if _, defined := vcs[name]; !defined {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Value assigned to undeclared variable",
+				fmt.Sprintf("A value was assigned to an undeclared input variable %q.", name),
+			))
+		}
+	}
+
+	return diags
+}
diff --git a/v1.5.7/internal/terraform/variables_test.go b/v1.5.7/internal/terraform/variables_test.go
new file mode 100644
index 0000000..f333f6b
--- /dev/null
+++ b/v1.5.7/internal/terraform/variables_test.go
@@ -0,0 +1,151 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform/internal/configs"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestCheckInputVariables(t *testing.T) {
+	c := testModule(t, "input-variables")
+
+	t.Run("No variables set", func(t *testing.T) {
+		// No variables set
+		diags := checkInputVariables(c.Module.Variables, nil)
+		if !diags.HasErrors() {
+			t.Fatal("check succeeded, but want errors")
+		}
+
+		// Required variables set, optional variables unset
+		// This is still an error at this layer, since it's the caller's
+		// responsibility to have already merged in any default values.
+		diags = checkInputVariables(c.Module.Variables, InputValues{
+			"foo": &InputValue{
+				Value:      cty.StringVal("bar"),
+				SourceType: ValueFromCLIArg,
+			},
+		})
+		if !diags.HasErrors() {
+			t.Fatal("check succeeded, but want errors")
+		}
+	})
+
+	t.Run("All variables set", func(t *testing.T) {
+		diags := checkInputVariables(c.Module.Variables, InputValues{
+			"foo": &InputValue{
+				Value:      cty.StringVal("bar"),
+				SourceType: ValueFromCLIArg,
+			},
+			"bar": &InputValue{
+				Value:      cty.StringVal("baz"),
+				SourceType: ValueFromCLIArg,
+			},
+			"map": &InputValue{
+				Value:      cty.StringVal("baz"), // okay because config has no type constraint
+				SourceType: ValueFromCLIArg,
+			},
+			"object_map": &InputValue{
+				Value: cty.MapVal(map[string]cty.Value{
+					"uno": cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("baz"),
+						"bar": cty.NumberIntVal(2), // type = any
+					}),
+					"dos": cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("bat"),
+						"bar": cty.NumberIntVal(99), // type = any
+					}),
+				}),
+				SourceType: ValueFromCLIArg,
+			},
+			"object_list": &InputValue{
+				Value: cty.ListVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("baz"),
+						"bar": cty.NumberIntVal(2), // type = any
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("bang"),
+						"bar": cty.NumberIntVal(42), // type = any
+					}),
+				}),
+				SourceType: ValueFromCLIArg,
+			},
+		})
+		if diags.HasErrors() {
+			t.Fatalf("unexpected errors: %s", diags.Err())
+		}
+	})
+
+	t.Run("Invalid Complex Types", func(t *testing.T) {
+		diags := checkInputVariables(c.Module.Variables, InputValues{
+			"foo": &InputValue{
+				Value:      cty.StringVal("bar"),
+				SourceType: ValueFromCLIArg,
+			},
+			"bar": &InputValue{
+				Value:      cty.StringVal("baz"),
+				SourceType: ValueFromCLIArg,
+			},
+			"map": &InputValue{
+				Value:      cty.StringVal("baz"), // okay because config has no type constraint
+				SourceType: ValueFromCLIArg,
+			},
+			"object_map": &InputValue{
+				Value: cty.MapVal(map[string]cty.Value{
+					"uno": cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("baz"),
+						"bar": cty.NumberIntVal(2), // type = any
+					}),
+					"dos": cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("bat"),
+						"bar": cty.NumberIntVal(99), // type = any
+					}),
+				}),
+				SourceType: ValueFromCLIArg,
+			},
+			"object_list": &InputValue{
+				Value: cty.TupleVal([]cty.Value{
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("baz"),
+						"bar": cty.NumberIntVal(2), // type = any
+					}),
+					cty.ObjectVal(map[string]cty.Value{
+						"foo": cty.StringVal("bang"),
+						"bar": cty.StringVal("42"), // type = any, but mismatch with the first list item
+					}),
+				}),
+				SourceType: ValueFromCLIArg,
+			},
+		})
+
+		if diags.HasErrors() {
+			t.Fatalf("unexpected errors: %s", diags.Err())
+		}
+	})
+}
+
+// testInputValuesUnset is a helper for constructing InputValues values for
+// situations where all of the root module variables are optional and a
+// test case intends to just use those default values and not override them
+// at all.
+//
+// In other words, this constructs an InputValues with one entry per given
+// input variable declaration where all of them are declared as unset.
+func testInputValuesUnset(decls map[string]*configs.Variable) InputValues {
+	if len(decls) == 0 {
+		return nil
+	}
+
+	ret := make(InputValues, len(decls))
+	for name := range decls {
+		ret[name] = &InputValue{
+			Value:      cty.NilVal,
+			SourceType: ValueFromUnknown,
+		}
+	}
+	return ret
+}
diff --git a/v1.5.7/internal/terraform/version_required.go b/v1.5.7/internal/terraform/version_required.go
new file mode 100644
index 0000000..a0bb2a0
--- /dev/null
+++ b/v1.5.7/internal/terraform/version_required.go
@@ -0,0 +1,28 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package terraform
+
+import (
+	"github.com/hashicorp/terraform/internal/tfdiags"
+
+	"github.com/hashicorp/terraform/internal/configs"
+)
+
+// CheckCoreVersionRequirements visits each of the modules in the given
+// configuration tree and verifies that any given Core version constraints
+// match with the version of Terraform Core that is being used.
+//
+// The returned diagnostics will contain errors if any constraints do not match.
+// The returned diagnostics might also return warnings, which should be
+// displayed to the user.
+func CheckCoreVersionRequirements(config *configs.Config) tfdiags.Diagnostics {
+	if config == nil {
+		return nil
+	}
+
+	var diags tfdiags.Diagnostics
+	diags = diags.Append(config.CheckCoreVersionRequirements())
+
+	return diags
+}
diff --git a/v1.5.7/internal/terraform/walkoperation_string.go b/v1.5.7/internal/terraform/walkoperation_string.go
new file mode 100644
index 0000000..799d4da
--- /dev/null
+++ b/v1.5.7/internal/terraform/walkoperation_string.go
@@ -0,0 +1,30 @@
+// Code generated by "stringer -type=walkOperation graph_walk_operation.go"; DO NOT EDIT.
+
+package terraform
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[walkInvalid-0]
+	_ = x[walkApply-1]
+	_ = x[walkPlan-2]
+	_ = x[walkPlanDestroy-3]
+	_ = x[walkValidate-4]
+	_ = x[walkDestroy-5]
+	_ = x[walkImport-6]
+	_ = x[walkEval-7]
+}
+
+const _walkOperation_name = "walkInvalidwalkApplywalkPlanwalkPlanDestroywalkValidatewalkDestroywalkImportwalkEval"
+
+var _walkOperation_index = [...]uint8{0, 11, 20, 28, 43, 55, 66, 76, 84}
+
+func (i walkOperation) String() string {
+	if i >= walkOperation(len(_walkOperation_index)-1) {
+		return "walkOperation(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _walkOperation_name[_walkOperation_index[i]:_walkOperation_index[i+1]]
+}
diff --git a/v1.5.7/internal/tfdiags/checks.go b/v1.5.7/internal/tfdiags/checks.go
new file mode 100644
index 0000000..c2159ce
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/checks.go
@@ -0,0 +1,76 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+)
+
+var _ Diagnostic = CheckBlockDiagnostic{}
+
+// CheckBlockDiagnostic is a diagnostic produced by a Terraform config Check block.
+//
+// It only ever returns warnings, and will not be consolidated as part of the
+// Diagnostics.ConsolidateWarnings function.
+type CheckBlockDiagnostic struct {
+	diag Diagnostic
+}
+
+// AsCheckBlockDiagnostics will wrap every diagnostic in diags in a
+// CheckBlockDiagnostic.
+func AsCheckBlockDiagnostics(diags Diagnostics) Diagnostics {
+	if len(diags) == 0 {
+		return nil
+	}
+
+	ret := make(Diagnostics, len(diags))
+	for i, diag := range diags {
+		ret[i] = CheckBlockDiagnostic{diag}
+	}
+	return ret
+}
+
+// AsCheckBlockDiagnostic will wrap a Diagnostic or a hcl.Diagnostic in a
+// CheckBlockDiagnostic.
+func AsCheckBlockDiagnostic(diag interface{}) Diagnostic {
+	switch d := diag.(type) {
+	case Diagnostic:
+		return CheckBlockDiagnostic{d}
+	case *hcl.Diagnostic:
+		return CheckBlockDiagnostic{hclDiagnostic{d}}
+	default:
+		panic(fmt.Errorf("can't construct diagnostic from %T", diag))
+	}
+}
+
+// IsFromCheckBlock returns true if the specified Diagnostic is a
+// CheckBlockDiagnostic.
+func IsFromCheckBlock(diag Diagnostic) bool {
+	_, ok := diag.(CheckBlockDiagnostic)
+	return ok
+}
+
+func (c CheckBlockDiagnostic) Severity() Severity {
+	// Regardless of the severity of the underlying diagnostic, check blocks
+	// only ever report Warning severity.
+	return Warning
+}
+
+func (c CheckBlockDiagnostic) Description() Description {
+	return c.diag.Description()
+}
+
+func (c CheckBlockDiagnostic) Source() Source {
+	return c.diag.Source()
+}
+
+func (c CheckBlockDiagnostic) FromExpr() *FromExpr {
+	return c.diag.FromExpr()
+}
+
+func (c CheckBlockDiagnostic) ExtraInfo() interface{} {
+	return c.diag.ExtraInfo()
+}
diff --git a/v1.5.7/internal/tfdiags/config_traversals.go b/v1.5.7/internal/tfdiags/config_traversals.go
new file mode 100644
index 0000000..c6c7cec
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/config_traversals.go
@@ -0,0 +1,71 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+import (
+	"bytes"
+	"fmt"
+	"strconv"
+
+	"github.com/zclconf/go-cty/cty"
+)
+
+// FormatCtyPath is a helper function to produce a user-friendly string
+// representation of a cty.Path. The result uses a syntax similar to the
+// HCL expression language in the hope of it being familiar to users.
+func FormatCtyPath(path cty.Path) string {
+	var buf bytes.Buffer
+	for _, step := range path {
+		switch ts := step.(type) {
+		case cty.GetAttrStep:
+			fmt.Fprintf(&buf, ".%s", ts.Name)
+		case cty.IndexStep:
+			buf.WriteByte('[')
+			key := ts.Key
+			keyTy := key.Type()
+			switch {
+			case key.IsNull():
+				buf.WriteString("null")
+			case !key.IsKnown():
+				buf.WriteString("(not yet known)")
+			case keyTy == cty.Number:
+				bf := key.AsBigFloat()
+				buf.WriteString(bf.Text('g', -1))
+			case keyTy == cty.String:
+				buf.WriteString(strconv.Quote(key.AsString()))
+			default:
+				buf.WriteString("...")
+			}
+			buf.WriteByte(']')
+		}
+	}
+	return buf.String()
+}
+
+// FormatError is a helper function to produce a user-friendly string
+// representation of certain special error types that we might want to
+// include in diagnostic messages.
+//
+// This currently has special behavior only for cty.PathError, where a
+// non-empty path is rendered in a HCL-like syntax as context.
+func FormatError(err error) string {
+	perr, ok := err.(cty.PathError)
+	if !ok || len(perr.Path) == 0 {
+		return err.Error()
+	}
+
+	return fmt.Sprintf("%s: %s", FormatCtyPath(perr.Path), perr.Error())
+}
+
+// FormatErrorPrefixed is like FormatError except that it presents any path
+// information after the given prefix string, which is assumed to contain
+// an HCL syntax representation of the value that errors are relative to.
+func FormatErrorPrefixed(err error, prefix string) string {
+	perr, ok := err.(cty.PathError)
+	if !ok || len(perr.Path) == 0 {
+		return fmt.Sprintf("%s: %s", prefix, err.Error())
+	}
+
+	return fmt.Sprintf("%s%s: %s", prefix, FormatCtyPath(perr.Path), perr.Error())
+}
diff --git a/v1.5.7/internal/tfdiags/consolidate_warnings.go b/v1.5.7/internal/tfdiags/consolidate_warnings.go
new file mode 100644
index 0000000..2c9d4d6
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/consolidate_warnings.go
@@ -0,0 +1,160 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+import "fmt"
+
+// ConsolidateWarnings checks if there is an unreasonable amount of warnings
+// with the same summary in the receiver and, if so, returns a new diagnostics
+// with some of those warnings consolidated into a single warning in order
+// to reduce the verbosity of the output.
+//
+// This mechanism is here primarily for diagnostics printed out at the CLI. In
+// other contexts it is likely better to just return the warnings directly,
+// particularly if they are going to be interpreted by software rather than
+// by a human reader.
+//
+// The returned slice always has a separate backing array from the reciever,
+// but some diagnostic values themselves might be shared.
+//
+// The definition of "unreasonable" is given as the threshold argument. At most
+// that many warnings with the same summary will be shown.
+func (diags Diagnostics) ConsolidateWarnings(threshold int) Diagnostics {
+	if len(diags) == 0 {
+		return nil
+	}
+
+	newDiags := make(Diagnostics, 0, len(diags))
+
+	// We'll track how many times we've seen each warning summary so we can
+	// decide when to start consolidating. Once we _have_ started consolidating,
+	// we'll also track the object representing the consolidated warning
+	// so we can continue appending to it.
+	warningStats := make(map[string]int)
+	warningGroups := make(map[string]*warningGroup)
+
+	for _, diag := range diags {
+		severity := diag.Severity()
+		if severity != Warning || diag.Source().Subject == nil {
+			// Only warnings can get special treatment, and we only
+			// consolidate warnings that have source locations because
+			// our primary goal here is to deal with the situation where
+			// some configuration language feature is producing a warning
+			// each time it's used across a potentially-large config.
+			newDiags = newDiags.Append(diag)
+			continue
+		}
+
+		if _, ok := diag.(CheckBlockDiagnostic); ok {
+			// Check diagnostics are never consolidated, the users have asked
+			// to be informed about each of these.
+			newDiags = newDiags.Append(diag)
+			continue
+		}
+
+		desc := diag.Description()
+		summary := desc.Summary
+		if g, ok := warningGroups[summary]; ok {
+			// We're already grouping this one, so we'll just continue it.
+			g.Append(diag)
+			continue
+		}
+
+		warningStats[summary]++
+		if warningStats[summary] == threshold {
+			// Initially creating the group doesn't really change anything
+			// visibly in the result, since a group with only one warning
+			// is just a passthrough anyway, but once we do this any additional
+			// warnings with the same summary will get appended to this group.
+			g := &warningGroup{}
+			newDiags = newDiags.Append(g)
+			warningGroups[summary] = g
+			g.Append(diag)
+			continue
+		}
+
+		// If this warning is not consolidating yet then we'll just append
+		// it directly.
+		newDiags = newDiags.Append(diag)
+	}
+
+	return newDiags
+}
+
+// A warningGroup is one or more warning diagnostics grouped together for
+// UI consolidation purposes.
+//
+// A warningGroup with only one diagnostic in it is just a passthrough for
+// that one diagnostic. If it has more than one then it will behave mostly
+// like the first one but its detail message will include an additional
+// sentence mentioning the consolidation. A warningGroup with no diagnostics
+// at all is invalid and will panic when used.
+type warningGroup struct {
+	Warnings Diagnostics
+}
+
+var _ Diagnostic = (*warningGroup)(nil)
+
+func (wg *warningGroup) Severity() Severity {
+	return wg.Warnings[0].Severity()
+}
+
+func (wg *warningGroup) Description() Description {
+	desc := wg.Warnings[0].Description()
+	if len(wg.Warnings) < 2 {
+		return desc
+	}
+	extraCount := len(wg.Warnings) - 1
+	var msg string
+	switch extraCount {
+	case 1:
+		msg = "(and one more similar warning elsewhere)"
+	default:
+		msg = fmt.Sprintf("(and %d more similar warnings elsewhere)", extraCount)
+	}
+	if desc.Detail != "" {
+		desc.Detail = desc.Detail + "\n\n" + msg
+	} else {
+		desc.Detail = msg
+	}
+	return desc
+}
+
+func (wg *warningGroup) Source() Source {
+	return wg.Warnings[0].Source()
+}
+
+func (wg *warningGroup) FromExpr() *FromExpr {
+	return wg.Warnings[0].FromExpr()
+}
+
+func (wg *warningGroup) ExtraInfo() interface{} {
+	return wg.Warnings[0].ExtraInfo()
+}
+
+func (wg *warningGroup) Append(diag Diagnostic) {
+	if diag.Severity() != Warning {
+		panic("can't append a non-warning diagnostic to a warningGroup")
+	}
+	wg.Warnings = append(wg.Warnings, diag)
+}
+
+// WarningGroupSourceRanges can be used in conjunction with
+// Diagnostics.ConsolidateWarnings to recover the full set of original source
+// locations from a consolidated warning.
+//
+// For convenience, this function accepts any diagnostic and will just return
+// the single Source value from any diagnostic that isn't a warning group.
+func WarningGroupSourceRanges(diag Diagnostic) []Source {
+	wg, ok := diag.(*warningGroup)
+	if !ok {
+		return []Source{diag.Source()}
+	}
+
+	ret := make([]Source, len(wg.Warnings))
+	for i, wrappedDiag := range wg.Warnings {
+		ret[i] = wrappedDiag.Source()
+	}
+	return ret
+}
diff --git a/v1.5.7/internal/tfdiags/consolidate_warnings_test.go b/v1.5.7/internal/tfdiags/consolidate_warnings_test.go
new file mode 100644
index 0000000..0ca7310
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/consolidate_warnings_test.go
@@ -0,0 +1,182 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/hcl/v2"
+)
+
+func TestConsolidateWarnings(t *testing.T) {
+	var diags Diagnostics
+
+	for i := 0; i < 4; i++ {
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagWarning,
+			Summary:  "Warning 1",
+			Detail:   fmt.Sprintf("This one has a subject %d", i),
+			Subject: &hcl.Range{
+				Filename: "foo.tf",
+				Start:    hcl.Pos{Line: 1, Column: 1, Byte: 0},
+				End:      hcl.Pos{Line: 1, Column: 1, Byte: 0},
+			},
+		})
+		diags = diags.Append(&hcl.Diagnostic{
+			Severity: hcl.DiagError,
+			Summary:  "Error 1",
+			Detail:   fmt.Sprintf("This one has a subject %d", i),
+			Subject: &hcl.Range{
+				Filename: "foo.tf",
+				Start:    hcl.Pos{Line: 1, Column: 1, Byte: 0},
+				End:      hcl.Pos{Line: 1, Column: 1, Byte: 0},
+			},
+		})
+		diags = diags.Append(Sourceless(
+			Warning,
+			"Warning 2",
+			fmt.Sprintf("This one is sourceless %d", i),
+		))
+		diags = diags.Append(SimpleWarning("Warning 3"))
+	}
+
+	diags = diags.Append(&hcl.Diagnostic{
+		Severity: hcl.DiagWarning,
+		Summary:  "Warning 4",
+		Detail:   "Only one of this one",
+		Subject: &hcl.Range{
+			Filename: "foo.tf",
+			Start:    hcl.Pos{Line: 1, Column: 1, Byte: 0},
+			End:      hcl.Pos{Line: 1, Column: 1, Byte: 0},
+		},
+	})
+
+	// We're using ForRPC here to force the diagnostics to be of a consistent
+	// type that we can easily assert against below.
+	got := diags.ConsolidateWarnings(2).ForRPC()
+	want := Diagnostics{
+		// First set
+		&rpcFriendlyDiag{
+			Severity_: Warning,
+			Summary_:  "Warning 1",
+			Detail_:   "This one has a subject 0",
+			Subject_: &SourceRange{
+				Filename: "foo.tf",
+				Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
+				End:      SourcePos{Line: 1, Column: 1, Byte: 0},
+			},
+		},
+		&rpcFriendlyDiag{
+			Severity_: Error,
+			Summary_:  "Error 1",
+			Detail_:   "This one has a subject 0",
+			Subject_: &SourceRange{
+				Filename: "foo.tf",
+				Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
+				End:      SourcePos{Line: 1, Column: 1, Byte: 0},
+			},
+		},
+		&rpcFriendlyDiag{
+			Severity_: Warning,
+			Summary_:  "Warning 2",
+			Detail_:   "This one is sourceless 0",
+		},
+		&rpcFriendlyDiag{
+			Severity_: Warning,
+			Summary_:  "Warning 3",
+		},
+
+		// Second set (consolidation begins; note additional paragraph in Warning 1 detail)
+		&rpcFriendlyDiag{
+			Severity_: Warning,
+			Summary_:  "Warning 1",
+			Detail_:   "This one has a subject 1\n\n(and 2 more similar warnings elsewhere)",
+			Subject_: &SourceRange{
+				Filename: "foo.tf",
+				Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
+				End:      SourcePos{Line: 1, Column: 1, Byte: 0},
+			},
+		},
+		&rpcFriendlyDiag{
+			Severity_: Error,
+			Summary_:  "Error 1",
+			Detail_:   "This one has a subject 1",
+			Subject_: &SourceRange{
+				Filename: "foo.tf",
+				Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
+				End:      SourcePos{Line: 1, Column: 1, Byte: 0},
+			},
+		},
+		&rpcFriendlyDiag{
+			Severity_: Warning,
+			Summary_:  "Warning 2",
+			Detail_:   "This one is sourceless 1",
+		},
+		&rpcFriendlyDiag{
+			Severity_: Warning,
+			Summary_:  "Warning 3",
+		},
+
+		// Third set (no more Warning 1, because it's consolidated)
+		&rpcFriendlyDiag{
+			Severity_: Error,
+			Summary_:  "Error 1",
+			Detail_:   "This one has a subject 2",
+			Subject_: &SourceRange{
+				Filename: "foo.tf",
+				Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
+				End:      SourcePos{Line: 1, Column: 1, Byte: 0},
+			},
+		},
+		&rpcFriendlyDiag{
+			Severity_: Warning,
+			Summary_:  "Warning 2",
+			Detail_:   "This one is sourceless 2",
+		},
+		&rpcFriendlyDiag{
+			Severity_: Warning,
+			Summary_:  "Warning 3",
+		},
+
+		// Fourth set (still no warning 1)
+		&rpcFriendlyDiag{
+			Severity_: Error,
+			Summary_:  "Error 1",
+			Detail_:   "This one has a subject 3",
+			Subject_: &SourceRange{
+				Filename: "foo.tf",
+				Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
+				End:      SourcePos{Line: 1, Column: 1, Byte: 0},
+			},
+		},
+		&rpcFriendlyDiag{
+			Severity_: Warning,
+			Summary_:  "Warning 2",
+			Detail_:   "This one is sourceless 3",
+		},
+		&rpcFriendlyDiag{
+			Severity_: Warning,
+			Summary_:  "Warning 3",
+		},
+
+		// Special straggler warning gets to show up unconsolidated, because
+		// there is only one of it.
+		&rpcFriendlyDiag{
+			Severity_: Warning,
+			Summary_:  "Warning 4",
+			Detail_:   "Only one of this one",
+			Subject_: &SourceRange{
+				Filename: "foo.tf",
+				Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
+				End:      SourcePos{Line: 1, Column: 1, Byte: 0},
+			},
+		},
+	}
+
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Errorf("wrong result\n%s", diff)
+	}
+}
diff --git a/v1.5.7/internal/tfdiags/contextual.go b/v1.5.7/internal/tfdiags/contextual.go
new file mode 100644
index 0000000..4ded9b9
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/contextual.go
@@ -0,0 +1,388 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+import (
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+	"github.com/zclconf/go-cty/cty/gocty"
+)
+
+// The "contextual" family of diagnostics are designed to allow separating
+// the detection of a problem from placing that problem in context. For
+// example, some code that is validating an object extracted from configuration
+// may not have access to the configuration that generated it, but can still
+// report problems within that object which the caller can then place in
+// context by calling IsConfigBody on the returned diagnostics.
+//
+// When contextual diagnostics are used, the documentation for a method must
+// be very explicit about what context is implied for any diagnostics returned,
+// to help ensure the expected result.
+
+// contextualFromConfig is an interface type implemented by diagnostic types
+// that can elaborate themselves when given information about the configuration
+// body they are embedded in, as well as the runtime address associated with
+// that configuration.
+//
+// Usually this entails extracting source location information in order to
+// populate the "Subject" range.
+type contextualFromConfigBody interface {
+	ElaborateFromConfigBody(hcl.Body, string) Diagnostic
+}
+
+// InConfigBody returns a copy of the receiver with any config-contextual
+// diagnostics elaborated in the context of the given body. An optional address
+// argument may be added to indicate which instance of the configuration the
+// error related to.
+func (diags Diagnostics) InConfigBody(body hcl.Body, addr string) Diagnostics {
+	if len(diags) == 0 {
+		return nil
+	}
+
+	ret := make(Diagnostics, len(diags))
+	for i, srcDiag := range diags {
+		if cd, isCD := srcDiag.(contextualFromConfigBody); isCD {
+			ret[i] = cd.ElaborateFromConfigBody(body, addr)
+		} else {
+			ret[i] = srcDiag
+		}
+	}
+
+	return ret
+}
+
+// AttributeValue returns a diagnostic about an attribute value in an implied current
+// configuration context. This should be returned only from functions whose
+// interface specifies a clear configuration context that this will be
+// resolved in.
+//
+// The given path is relative to the implied configuration context. To describe
+// a top-level attribute, it should be a single-element cty.Path with a
+// cty.GetAttrStep. It's assumed that the path is returning into a structure
+// that would be produced by our conventions in the configschema package; it
+// may return unexpected results for structures that can't be represented by
+// configschema.
+//
+// Since mapping attribute paths back onto configuration is an imprecise
+// operation (e.g. dynamic block generation may cause the same block to be
+// evaluated multiple times) the diagnostic detail should include the attribute
+// name and other context required to help the user understand what is being
+// referenced in case the identified source range is not unique.
+//
+// The returned attribute will not have source location information until
+// context is applied to the containing diagnostics using diags.InConfigBody.
+// After context is applied, the source location is the value assigned to the
+// named attribute, or the containing body's "missing item range" if no
+// value is present.
+func AttributeValue(severity Severity, summary, detail string, attrPath cty.Path) Diagnostic {
+	return &attributeDiagnostic{
+		diagnosticBase: diagnosticBase{
+			severity: severity,
+			summary:  summary,
+			detail:   detail,
+		},
+		attrPath: attrPath,
+	}
+}
+
+// GetAttribute extracts an attribute cty.Path from a diagnostic if it contains
+// one. Normally this is not accessed directly, and instead the config body is
+// added to the Diagnostic to create a more complete message for the user. In
+// some cases however, we may want to know just the name of the attribute that
+// generated the Diagnostic message.
+// This returns a nil cty.Path if it does not exist in the Diagnostic.
+func GetAttribute(d Diagnostic) cty.Path {
+	if d, ok := d.(*attributeDiagnostic); ok {
+		return d.attrPath
+	}
+	return nil
+}
+
+type attributeDiagnostic struct {
+	diagnosticBase
+	attrPath cty.Path
+	subject  *SourceRange // populated only after ElaborateFromConfigBody
+}
+
+// ElaborateFromConfigBody finds the most accurate possible source location
+// for a diagnostic's attribute path within the given body.
+//
+// Backing out from a path back to a source location is not always entirely
+// possible because we lose some information in the decoding process, so
+// if an exact position cannot be found then the returned diagnostic will
+// refer to a position somewhere within the containing body, which is assumed
+// to be better than no location at all.
+//
+// If possible it is generally better to report an error at a layer where
+// source location information is still available, for more accuracy. This
+// is not always possible due to system architecture, so this serves as a
+// "best effort" fallback behavior for such situations.
+func (d *attributeDiagnostic) ElaborateFromConfigBody(body hcl.Body, addr string) Diagnostic {
+	// don't change an existing address
+	if d.address == "" {
+		d.address = addr
+	}
+
+	if len(d.attrPath) < 1 {
+		// Should never happen, but we'll allow it rather than crashing.
+		return d
+	}
+
+	if d.subject != nil {
+		// Don't modify an already-elaborated diagnostic.
+		return d
+	}
+
+	ret := *d
+
+	// This function will often end up re-decoding values that were already
+	// decoded by an earlier step. This is non-ideal but is architecturally
+	// more convenient than arranging for source location information to be
+	// propagated to every place in Terraform, and this happens only in the
+	// presence of errors where performance isn't a concern.
+
+	traverse := d.attrPath[:]
+	final := d.attrPath[len(d.attrPath)-1]
+
+	// Index should never be the first step
+	// as indexing of top blocks (such as resources & data sources)
+	// is handled elsewhere
+	if _, isIdxStep := traverse[0].(cty.IndexStep); isIdxStep {
+		subject := SourceRangeFromHCL(body.MissingItemRange())
+		ret.subject = &subject
+		return &ret
+	}
+
+	// Process index separately
+	idxStep, hasIdx := final.(cty.IndexStep)
+	if hasIdx {
+		final = d.attrPath[len(d.attrPath)-2]
+		traverse = d.attrPath[:len(d.attrPath)-1]
+	}
+
+	// If we have more than one step after removing index
+	// then we'll first try to traverse to a child body
+	// corresponding to the requested path.
+	if len(traverse) > 1 {
+		body = traversePathSteps(traverse, body)
+	}
+
+	// Default is to indicate a missing item in the deepest body we reached
+	// while traversing.
+	subject := SourceRangeFromHCL(body.MissingItemRange())
+	ret.subject = &subject
+
+	// Once we get here, "final" should be a GetAttr step that maps to an
+	// attribute in our current body.
+	finalStep, isAttr := final.(cty.GetAttrStep)
+	if !isAttr {
+		return &ret
+	}
+
+	content, _, contentDiags := body.PartialContent(&hcl.BodySchema{
+		Attributes: []hcl.AttributeSchema{
+			{
+				Name:     finalStep.Name,
+				Required: true,
+			},
+		},
+	})
+	if contentDiags.HasErrors() {
+		return &ret
+	}
+
+	if attr, ok := content.Attributes[finalStep.Name]; ok {
+		hclRange := attr.Expr.Range()
+		if hasIdx {
+			// Try to be more precise by finding index range
+			hclRange = hclRangeFromIndexStepAndAttribute(idxStep, attr)
+		}
+		subject = SourceRangeFromHCL(hclRange)
+		ret.subject = &subject
+	}
+
+	return &ret
+}
+
+func traversePathSteps(traverse []cty.PathStep, body hcl.Body) hcl.Body {
+	for i := 0; i < len(traverse); i++ {
+		step := traverse[i]
+
+		switch tStep := step.(type) {
+		case cty.GetAttrStep:
+
+			var next cty.PathStep
+			if i < (len(traverse) - 1) {
+				next = traverse[i+1]
+			}
+
+			// Will be indexing into our result here?
+			var indexType cty.Type
+			var indexVal cty.Value
+			if nextIndex, ok := next.(cty.IndexStep); ok {
+				indexVal = nextIndex.Key
+				indexType = indexVal.Type()
+				i++ // skip over the index on subsequent iterations
+			}
+
+			var blockLabelNames []string
+			if indexType == cty.String {
+				// Map traversal means we expect one label for the key.
+				blockLabelNames = []string{"key"}
+			}
+
+			// For intermediate steps we expect to be referring to a child
+			// block, so we'll attempt decoding under that assumption.
+			content, _, contentDiags := body.PartialContent(&hcl.BodySchema{
+				Blocks: []hcl.BlockHeaderSchema{
+					{
+						Type:       tStep.Name,
+						LabelNames: blockLabelNames,
+					},
+				},
+			})
+			if contentDiags.HasErrors() {
+				return body
+			}
+			filtered := make([]*hcl.Block, 0, len(content.Blocks))
+			for _, block := range content.Blocks {
+				if block.Type == tStep.Name {
+					filtered = append(filtered, block)
+				}
+			}
+			if len(filtered) == 0 {
+				// Step doesn't refer to a block
+				continue
+			}
+
+			switch indexType {
+			case cty.NilType: // no index at all
+				if len(filtered) != 1 {
+					return body
+				}
+				body = filtered[0].Body
+			case cty.Number:
+				var idx int
+				err := gocty.FromCtyValue(indexVal, &idx)
+				if err != nil || idx >= len(filtered) {
+					return body
+				}
+				body = filtered[idx].Body
+			case cty.String:
+				key := indexVal.AsString()
+				var block *hcl.Block
+				for _, candidate := range filtered {
+					if candidate.Labels[0] == key {
+						block = candidate
+						break
+					}
+				}
+				if block == nil {
+					// No block with this key, so we'll just indicate a
+					// missing item in the containing block.
+					return body
+				}
+				body = block.Body
+			default:
+				// Should never happen, because only string and numeric indices
+				// are supported by cty collections.
+				return body
+			}
+
+		default:
+			// For any other kind of step, we'll just return our current body
+			// as the subject and accept that this is a little inaccurate.
+			return body
+		}
+	}
+	return body
+}
+
+func hclRangeFromIndexStepAndAttribute(idxStep cty.IndexStep, attr *hcl.Attribute) hcl.Range {
+	switch idxStep.Key.Type() {
+	case cty.Number:
+		var idx int
+		err := gocty.FromCtyValue(idxStep.Key, &idx)
+		items, diags := hcl.ExprList(attr.Expr)
+		if diags.HasErrors() {
+			return attr.Expr.Range()
+		}
+		if err != nil || idx >= len(items) {
+			return attr.NameRange
+		}
+		return items[idx].Range()
+	case cty.String:
+		pairs, diags := hcl.ExprMap(attr.Expr)
+		if diags.HasErrors() {
+			return attr.Expr.Range()
+		}
+		stepKey := idxStep.Key.AsString()
+		for _, kvPair := range pairs {
+			key, diags := kvPair.Key.Value(nil)
+			if diags.HasErrors() {
+				return attr.Expr.Range()
+			}
+			if key.AsString() == stepKey {
+				startRng := kvPair.Value.StartRange()
+				return startRng
+			}
+		}
+		return attr.NameRange
+	}
+	return attr.Expr.Range()
+}
+
+func (d *attributeDiagnostic) Source() Source {
+	return Source{
+		Subject: d.subject,
+	}
+}
+
+// WholeContainingBody returns a diagnostic about the body that is an implied
+// current configuration context. This should be returned only from
+// functions whose interface specifies a clear configuration context that this
+// will be resolved in.
+//
+// The returned attribute will not have source location information until
+// context is applied to the containing diagnostics using diags.InConfigBody.
+// After context is applied, the source location is currently the missing item
+// range of the body. In future, this may change to some other suitable
+// part of the containing body.
+func WholeContainingBody(severity Severity, summary, detail string) Diagnostic {
+	return &wholeBodyDiagnostic{
+		diagnosticBase: diagnosticBase{
+			severity: severity,
+			summary:  summary,
+			detail:   detail,
+		},
+	}
+}
+
+type wholeBodyDiagnostic struct {
+	diagnosticBase
+	subject *SourceRange // populated only after ElaborateFromConfigBody
+}
+
+func (d *wholeBodyDiagnostic) ElaborateFromConfigBody(body hcl.Body, addr string) Diagnostic {
+	// don't change an existing address
+	if d.address == "" {
+		d.address = addr
+	}
+
+	if d.subject != nil {
+		// Don't modify an already-elaborated diagnostic.
+		return d
+	}
+
+	ret := *d
+	rng := SourceRangeFromHCL(body.MissingItemRange())
+	ret.subject = &rng
+	return &ret
+}
+
+func (d *wholeBodyDiagnostic) Source() Source {
+	return Source{
+		Subject: d.subject,
+	}
+}
diff --git a/v1.5.7/internal/tfdiags/contextual_test.go b/v1.5.7/internal/tfdiags/contextual_test.go
new file mode 100644
index 0000000..1f1c6ca
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/contextual_test.go
@@ -0,0 +1,584 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+
+	"github.com/go-test/deep"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestAttributeValue(t *testing.T) {
+	testConfig := `
+foo {
+  bar = "hi"
+}
+foo {
+  bar = "bar"
+}
+bar {
+  bar = "woot"
+}
+baz "a" {
+  bar = "beep"
+}
+baz "b" {
+  bar = "boop"
+}
+parent {
+  nested_str = "hello"
+  nested_str_tuple = ["aa", "bbb", "cccc"]
+  nested_num_tuple = [1, 9863, 22]
+  nested_map = {
+    first_key  = "first_value"
+    second_key = "2nd value"
+  }
+}
+tuple_of_one = ["one"]
+tuple_of_two = ["first", "22222"]
+root_map = {
+  first  = "1st"
+  second = "2nd"
+}
+simple_attr = "val"
+`
+	// TODO: Test ConditionalExpr
+	// TODO: Test ForExpr
+	// TODO: Test FunctionCallExpr
+	// TODO: Test IndexExpr
+	// TODO: Test interpolation
+	// TODO: Test SplatExpr
+
+	f, parseDiags := hclsyntax.ParseConfig([]byte(testConfig), "test.tf", hcl.Pos{Line: 1, Column: 1})
+	if len(parseDiags) != 0 {
+		t.Fatal(parseDiags)
+	}
+	emptySrcRng := &SourceRange{
+		Filename: "test.tf",
+		Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
+		End:      SourcePos{Line: 1, Column: 1, Byte: 0},
+	}
+
+	testCases := []struct {
+		Diag          Diagnostic
+		ExpectedRange *SourceRange
+	}{
+		{
+			AttributeValue(
+				Error,
+				"foo[0].bar",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "foo"},
+					cty.IndexStep{Key: cty.NumberIntVal(0)},
+					cty.GetAttrStep{Name: "bar"},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 3, Column: 9, Byte: 15},
+				End:      SourcePos{Line: 3, Column: 13, Byte: 19},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"foo[1].bar",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "foo"},
+					cty.IndexStep{Key: cty.NumberIntVal(1)},
+					cty.GetAttrStep{Name: "bar"},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 6, Column: 9, Byte: 36},
+				End:      SourcePos{Line: 6, Column: 14, Byte: 41},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"foo[99].bar",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "foo"},
+					cty.IndexStep{Key: cty.NumberIntVal(99)},
+					cty.GetAttrStep{Name: "bar"},
+				},
+			),
+			emptySrcRng,
+		},
+		{
+			AttributeValue(
+				Error,
+				"bar.bar",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "bar"},
+					cty.GetAttrStep{Name: "bar"},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 9, Column: 9, Byte: 58},
+				End:      SourcePos{Line: 9, Column: 15, Byte: 64},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				`baz["a"].bar`,
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "baz"},
+					cty.IndexStep{Key: cty.StringVal("a")},
+					cty.GetAttrStep{Name: "bar"},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 12, Column: 9, Byte: 85},
+				End:      SourcePos{Line: 12, Column: 15, Byte: 91},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				`baz["b"].bar`,
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "baz"},
+					cty.IndexStep{Key: cty.StringVal("b")},
+					cty.GetAttrStep{Name: "bar"},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 15, Column: 9, Byte: 112},
+				End:      SourcePos{Line: 15, Column: 15, Byte: 118},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				`baz["not_exists"].bar`,
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "baz"},
+					cty.IndexStep{Key: cty.StringVal("not_exists")},
+					cty.GetAttrStep{Name: "bar"},
+				},
+			),
+			emptySrcRng,
+		},
+		{
+			// Attribute value with subject already populated should not be disturbed.
+			// (in a real case, this might've been passed through from a deeper function
+			// in the call stack, for example.)
+			&attributeDiagnostic{
+				attrPath: cty.Path{cty.GetAttrStep{Name: "foo"}},
+				diagnosticBase: diagnosticBase{
+					summary: "preexisting",
+					detail:  "detail",
+					address: "original",
+				},
+				subject: &SourceRange{
+					Filename: "somewhere_else.tf",
+				},
+			},
+			&SourceRange{
+				Filename: "somewhere_else.tf",
+			},
+		},
+		{
+			// Missing path
+			&attributeDiagnostic{
+				diagnosticBase: diagnosticBase{
+					summary: "missing path",
+				},
+			},
+			nil,
+		},
+
+		// Nested attributes
+		{
+			AttributeValue(
+				Error,
+				"parent.nested_str",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "parent"},
+					cty.GetAttrStep{Name: "nested_str"},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 18, Column: 16, Byte: 145},
+				End:      SourcePos{Line: 18, Column: 23, Byte: 152},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"parent.nested_str_tuple[99]",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "parent"},
+					cty.GetAttrStep{Name: "nested_str_tuple"},
+					cty.IndexStep{Key: cty.NumberIntVal(99)},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 19, Column: 3, Byte: 155},
+				End:      SourcePos{Line: 19, Column: 19, Byte: 171},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"parent.nested_str_tuple[0]",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "parent"},
+					cty.GetAttrStep{Name: "nested_str_tuple"},
+					cty.IndexStep{Key: cty.NumberIntVal(0)},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 19, Column: 23, Byte: 175},
+				End:      SourcePos{Line: 19, Column: 27, Byte: 179},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"parent.nested_str_tuple[2]",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "parent"},
+					cty.GetAttrStep{Name: "nested_str_tuple"},
+					cty.IndexStep{Key: cty.NumberIntVal(2)},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 19, Column: 36, Byte: 188},
+				End:      SourcePos{Line: 19, Column: 42, Byte: 194},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"parent.nested_num_tuple[0]",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "parent"},
+					cty.GetAttrStep{Name: "nested_num_tuple"},
+					cty.IndexStep{Key: cty.NumberIntVal(0)},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 20, Column: 23, Byte: 218},
+				End:      SourcePos{Line: 20, Column: 24, Byte: 219},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"parent.nested_num_tuple[1]",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "parent"},
+					cty.GetAttrStep{Name: "nested_num_tuple"},
+					cty.IndexStep{Key: cty.NumberIntVal(1)},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 20, Column: 26, Byte: 221},
+				End:      SourcePos{Line: 20, Column: 30, Byte: 225},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"parent.nested_map.first_key",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "parent"},
+					cty.GetAttrStep{Name: "nested_map"},
+					cty.IndexStep{Key: cty.StringVal("first_key")},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 22, Column: 19, Byte: 266},
+				End:      SourcePos{Line: 22, Column: 30, Byte: 277},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"parent.nested_map.second_key",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "parent"},
+					cty.GetAttrStep{Name: "nested_map"},
+					cty.IndexStep{Key: cty.StringVal("second_key")},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 23, Column: 19, Byte: 297},
+				End:      SourcePos{Line: 23, Column: 28, Byte: 306},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"parent.nested_map.undefined_key",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "parent"},
+					cty.GetAttrStep{Name: "nested_map"},
+					cty.IndexStep{Key: cty.StringVal("undefined_key")},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 21, Column: 3, Byte: 233},
+				End:      SourcePos{Line: 21, Column: 13, Byte: 243},
+			},
+		},
+
+		// Root attributes of complex types
+		{
+			AttributeValue(
+				Error,
+				"tuple_of_one[0]",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "tuple_of_one"},
+					cty.IndexStep{Key: cty.NumberIntVal(0)},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 26, Column: 17, Byte: 330},
+				End:      SourcePos{Line: 26, Column: 22, Byte: 335},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"tuple_of_two[0]",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "tuple_of_two"},
+					cty.IndexStep{Key: cty.NumberIntVal(0)},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 27, Column: 17, Byte: 353},
+				End:      SourcePos{Line: 27, Column: 24, Byte: 360},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"tuple_of_two[1]",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "tuple_of_two"},
+					cty.IndexStep{Key: cty.NumberIntVal(1)},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 27, Column: 26, Byte: 362},
+				End:      SourcePos{Line: 27, Column: 33, Byte: 369},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"tuple_of_one[null]",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "tuple_of_one"},
+					cty.IndexStep{Key: cty.NullVal(cty.Number)},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 26, Column: 1, Byte: 314},
+				End:      SourcePos{Line: 26, Column: 13, Byte: 326},
+			},
+		},
+		{
+			// index out of range
+			AttributeValue(
+				Error,
+				"tuple_of_two[99]",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "tuple_of_two"},
+					cty.IndexStep{Key: cty.NumberIntVal(99)},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 27, Column: 1, Byte: 337},
+				End:      SourcePos{Line: 27, Column: 13, Byte: 349},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"root_map.first",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "root_map"},
+					cty.IndexStep{Key: cty.StringVal("first")},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 29, Column: 13, Byte: 396},
+				End:      SourcePos{Line: 29, Column: 16, Byte: 399},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"root_map.second",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "root_map"},
+					cty.IndexStep{Key: cty.StringVal("second")},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 30, Column: 13, Byte: 413},
+				End:      SourcePos{Line: 30, Column: 16, Byte: 416},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"root_map.undefined_key",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "root_map"},
+					cty.IndexStep{Key: cty.StringVal("undefined_key")},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 28, Column: 1, Byte: 371},
+				End:      SourcePos{Line: 28, Column: 9, Byte: 379},
+			},
+		},
+		{
+			AttributeValue(
+				Error,
+				"simple_attr",
+				"detail",
+				cty.Path{
+					cty.GetAttrStep{Name: "simple_attr"},
+				},
+			),
+			&SourceRange{
+				Filename: "test.tf",
+				Start:    SourcePos{Line: 32, Column: 15, Byte: 434},
+				End:      SourcePos{Line: 32, Column: 20, Byte: 439},
+			},
+		},
+		{
+			// This should never happen as error should always point to an attribute
+			// or index of an attribute, but we should not crash if it does
+			AttributeValue(
+				Error,
+				"key",
+				"index_step",
+				cty.Path{
+					cty.IndexStep{Key: cty.StringVal("key")},
+				},
+			),
+			emptySrcRng,
+		},
+		{
+			// This should never happen as error should always point to an attribute
+			// or index of an attribute, but we should not crash if it does
+			AttributeValue(
+				Error,
+				"key.another",
+				"index_step",
+				cty.Path{
+					cty.IndexStep{Key: cty.StringVal("key")},
+					cty.IndexStep{Key: cty.StringVal("another")},
+				},
+			),
+			emptySrcRng,
+		},
+	}
+
+	for i, tc := range testCases {
+		t.Run(fmt.Sprintf("%d:%s", i, tc.Diag.Description()), func(t *testing.T) {
+			var diags Diagnostics
+
+			origAddr := tc.Diag.Description().Address
+			diags = diags.Append(tc.Diag)
+
+			gotDiags := diags.InConfigBody(f.Body, "test.addr")
+			gotRange := gotDiags[0].Source().Subject
+			gotAddr := gotDiags[0].Description().Address
+
+			switch {
+			case origAddr != "":
+				if gotAddr != origAddr {
+					t.Errorf("original diagnostic address modified from %s to %s", origAddr, gotAddr)
+				}
+			case gotAddr != "test.addr":
+				t.Error("missing detail address")
+			}
+
+			for _, problem := range deep.Equal(gotRange, tc.ExpectedRange) {
+				t.Error(problem)
+			}
+		})
+	}
+}
+
+func TestGetAttribute(t *testing.T) {
+	path := cty.Path{
+		cty.GetAttrStep{Name: "foo"},
+		cty.IndexStep{Key: cty.NumberIntVal(0)},
+		cty.GetAttrStep{Name: "bar"},
+	}
+
+	d := AttributeValue(
+		Error,
+		"foo[0].bar",
+		"detail",
+		path,
+	)
+
+	p := GetAttribute(d)
+	if !reflect.DeepEqual(path, p) {
+		t.Fatalf("paths don't match:\nexpected: %#v\ngot: %#v", path, p)
+	}
+}
diff --git a/v1.5.7/internal/tfdiags/diagnostic.go b/v1.5.7/internal/tfdiags/diagnostic.go
new file mode 100644
index 0000000..2da94df
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/diagnostic.go
@@ -0,0 +1,67 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/hcl/v2"
+)
+
+type Diagnostic interface {
+	Severity() Severity
+	Description() Description
+	Source() Source
+
+	// FromExpr returns the expression-related context for the diagnostic, if
+	// available. Returns nil if the diagnostic is not related to an
+	// expression evaluation.
+	FromExpr() *FromExpr
+
+	// ExtraInfo returns the raw extra information value. This is a low-level
+	// API which requires some work on the part of the caller to properly
+	// access associated information, so in most cases it'll be more convienient
+	// to use the package-level ExtraInfo function to try to unpack a particular
+	// specialized interface from this value.
+	ExtraInfo() interface{}
+}
+
+type Severity rune
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=Severity
+
+const (
+	Error   Severity = 'E'
+	Warning Severity = 'W'
+)
+
+// ToHCL converts a Severity to the equivalent HCL diagnostic severity.
+func (s Severity) ToHCL() hcl.DiagnosticSeverity {
+	switch s {
+	case Warning:
+		return hcl.DiagWarning
+	case Error:
+		return hcl.DiagError
+	default:
+		// The above should always be exhaustive for all of the valid
+		// Severity values in this package.
+		panic(fmt.Sprintf("unknown diagnostic severity %s", s))
+	}
+}
+
+type Description struct {
+	Address string
+	Summary string
+	Detail  string
+}
+
+type Source struct {
+	Subject *SourceRange
+	Context *SourceRange
+}
+
+type FromExpr struct {
+	Expression  hcl.Expression
+	EvalContext *hcl.EvalContext
+}
diff --git a/v1.5.7/internal/tfdiags/diagnostic_base.go b/v1.5.7/internal/tfdiags/diagnostic_base.go
new file mode 100644
index 0000000..8c1707e
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/diagnostic_base.go
@@ -0,0 +1,40 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+// diagnosticBase can be embedded in other diagnostic structs to get
+// default implementations of Severity and Description. This type also
+// has default implementations of Source and FromExpr that return no source
+// location or expression-related information, so embedders should generally
+// override those method to return more useful results where possible.
+type diagnosticBase struct {
+	severity Severity
+	summary  string
+	detail   string
+	address  string
+}
+
+func (d diagnosticBase) Severity() Severity {
+	return d.severity
+}
+
+func (d diagnosticBase) Description() Description {
+	return Description{
+		Summary: d.summary,
+		Detail:  d.detail,
+		Address: d.address,
+	}
+}
+
+func (d diagnosticBase) Source() Source {
+	return Source{}
+}
+
+func (d diagnosticBase) FromExpr() *FromExpr {
+	return nil
+}
+
+func (d diagnosticBase) ExtraInfo() interface{} {
+	return nil
+}
diff --git a/v1.5.7/internal/tfdiags/diagnostic_extra.go b/v1.5.7/internal/tfdiags/diagnostic_extra.go
new file mode 100644
index 0000000..4ca37b0
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/diagnostic_extra.go
@@ -0,0 +1,174 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+// This "Extra" idea is something we've inherited from HCL's diagnostic model,
+// and so it's primarily to expose that functionality from wrapped HCL
+// diagnostics but other diagnostic types could potentially implement this
+// protocol too, if needed.
+
+// ExtraInfo tries to retrieve extra information of interface type T from
+// the given diagnostic.
+//
+// "Extra information" is situation-specific additional contextual data which
+// might allow for some special tailored reporting of particular
+// diagnostics in the UI. Conventionally the extra information is provided
+// as a hidden type that implements one or more interfaces which a caller
+// can pass as type parameter T to retrieve a value of that type when the
+// diagnostic has such an implementation.
+//
+// If the given diagnostic's extra value has an implementation of interface T
+// then ExtraInfo returns a non-nil interface value. If there is no such
+// implementation, ExtraInfo returns a nil T.
+//
+// Although the signature of this function does not constrain T to be an
+// interface type, our convention is to only use interface types to access
+// extra info in order to allow for alternative or wrapping implementations
+// of the interface.
+func ExtraInfo[T any](diag Diagnostic) T {
+	extra := diag.ExtraInfo()
+	if ret, ok := extra.(T); ok {
+		return ret
+	}
+
+	// If "extra" doesn't implement T directly then we'll delegate to
+	// our ExtraInfoNext helper to try iteratively unwrapping it.
+	return ExtraInfoNext[T](extra)
+}
+
+// ExtraInfoNext takes a value previously returned by ExtraInfo and attempts
+// to find an implementation of interface T wrapped inside of it. The return
+// value meaning is the same as for ExtraInfo.
+//
+// This is to help with the less common situation where a particular "extra"
+// value might be wrapping another value implementing the same interface,
+// and so callers can peel away one layer at a time until there are no more
+// nested layers.
+//
+// Because this function is intended for searching for _nested_ implementations
+// of T, ExtraInfoNext does not consider whether value "previous" directly
+// implements interface T, on the assumption that the previous call to ExtraInfo
+// with the same T caused "previous" to already be that result.
+func ExtraInfoNext[T any](previous interface{}) T {
+	// As long as T is an interface type as documented, zero will always be
+	// a nil interface value for us to return in the non-matching case.
+	var zero T
+
+	unwrapper, ok := previous.(DiagnosticExtraUnwrapper)
+	// If the given value isn't unwrappable then it can't possibly have
+	// any other info nested inside of it.
+	if !ok {
+		return zero
+	}
+
+	extra := unwrapper.UnwrapDiagnosticExtra()
+
+	// We'll keep unwrapping until we either find the interface we're
+	// looking for or we run out of layers of unwrapper.
+	for {
+		if ret, ok := extra.(T); ok {
+			return ret
+		}
+
+		if unwrapper, ok := extra.(DiagnosticExtraUnwrapper); ok {
+			extra = unwrapper.UnwrapDiagnosticExtra()
+		} else {
+			return zero
+		}
+	}
+}
+
+// DiagnosticExtraUnwrapper is an interface implemented by values in the
+// Extra field of Diagnostic when they are wrapping another "Extra" value that
+// was generated downstream.
+//
+// Diagnostic recipients which want to examine "Extra" values to sniff for
+// particular types of extra data can either type-assert this interface
+// directly and repeatedly unwrap until they recieve nil, or can use the
+// helper function DiagnosticExtra.
+//
+// This interface intentionally matches hcl.DiagnosticExtraUnwrapper, so that
+// wrapping extra values implemented using HCL's API will also work with the
+// tfdiags API, but that non-HCL uses of this will not need to implement HCL
+// just to get this interface.
+type DiagnosticExtraUnwrapper interface {
+	// If the reciever is wrapping another "diagnostic extra" value, returns
+	// that value. Otherwise returns nil to indicate dynamically that nothing
+	// is wrapped.
+	//
+	// The "nothing is wrapped" condition can be signalled either by this
+	// method returning nil or by a type not implementing this interface at all.
+	//
+	// Implementers should never create unwrap "cycles" where a nested extra
+	// value returns a value that was also wrapping it.
+	UnwrapDiagnosticExtra() interface{}
+}
+
+// DiagnosticExtraBecauseUnknown is an interface implemented by values in
+// the Extra field of Diagnostic when the diagnostic is potentially caused by
+// the presence of unknown values in an expression evaluation.
+//
+// Just implementing this interface is not sufficient signal, though. Callers
+// must also call the DiagnosticCausedByUnknown method in order to confirm
+// the result, or use the package-level function DiagnosticCausedByUnknown
+// as a convenient wrapper.
+type DiagnosticExtraBecauseUnknown interface {
+	// DiagnosticCausedByUnknown returns true if the associated diagnostic
+	// was caused by the presence of unknown values during an expression
+	// evaluation, or false otherwise.
+	//
+	// Callers might use this to tailor what contextual information they show
+	// alongside an error report in the UI, to avoid potential confusion
+	// caused by talking about the presence of unknown values if that was
+	// immaterial to the error.
+	DiagnosticCausedByUnknown() bool
+}
+
+// DiagnosticCausedByUnknown returns true if the given diagnostic has an
+// indication that it was caused by the presence of unknown values during
+// an expression evaluation.
+//
+// This is a wrapper around checking if the diagnostic's extra info implements
+// interface DiagnosticExtraBecauseUnknown and then calling its method if so.
+func DiagnosticCausedByUnknown(diag Diagnostic) bool {
+	maybe := ExtraInfo[DiagnosticExtraBecauseUnknown](diag)
+	if maybe == nil {
+		return false
+	}
+	return maybe.DiagnosticCausedByUnknown()
+}
+
+// DiagnosticExtraBecauseSensitive is an interface implemented by values in
+// the Extra field of Diagnostic when the diagnostic is potentially caused by
+// the presence of sensitive values in an expression evaluation.
+//
+// Just implementing this interface is not sufficient signal, though. Callers
+// must also call the DiagnosticCausedBySensitive method in order to confirm
+// the result, or use the package-level function DiagnosticCausedBySensitive
+// as a convenient wrapper.
+type DiagnosticExtraBecauseSensitive interface {
+	// DiagnosticCausedBySensitive returns true if the associated diagnostic
+	// was caused by the presence of sensitive values during an expression
+	// evaluation, or false otherwise.
+	//
+	// Callers might use this to tailor what contextual information they show
+	// alongside an error report in the UI, to avoid potential confusion
+	// caused by talking about the presence of sensitive values if that was
+	// immaterial to the error.
+	DiagnosticCausedBySensitive() bool
+}
+
+// DiagnosticCausedBySensitive returns true if the given diagnostic has an
+// indication that it was caused by the presence of sensitive values during
+// an expression evaluation.
+//
+// This is a wrapper around checking if the diagnostic's extra info implements
+// interface DiagnosticExtraBecauseSensitive and then calling its method if so.
+func DiagnosticCausedBySensitive(diag Diagnostic) bool {
+	maybe := ExtraInfo[DiagnosticExtraBecauseSensitive](diag)
+	if maybe == nil {
+		return false
+	}
+	return maybe.DiagnosticCausedBySensitive()
+}
diff --git a/v1.5.7/internal/tfdiags/diagnostics.go b/v1.5.7/internal/tfdiags/diagnostics.go
new file mode 100644
index 0000000..a7fbc54
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/diagnostics.go
@@ -0,0 +1,333 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+import (
+	"bytes"
+	"fmt"
+	"path/filepath"
+	"sort"
+	"strings"
+
+	"github.com/hashicorp/errwrap"
+	multierror "github.com/hashicorp/go-multierror"
+	"github.com/hashicorp/hcl/v2"
+)
+
+// Diagnostics is a list of diagnostics. Diagnostics is intended to be used
+// where a Go "error" might normally be used, allowing richer information
+// to be conveyed (more context, support for warnings).
+//
+// A nil Diagnostics is a valid, empty diagnostics list, thus allowing
+// heap allocation to be avoided in the common case where there are no
+// diagnostics to report at all.
+type Diagnostics []Diagnostic
+
+// Append is the main interface for constructing Diagnostics lists, taking
+// an existing list (which may be nil) and appending the new objects to it
+// after normalizing them to be implementations of Diagnostic.
+//
+// The usual pattern for a function that natively "speaks" diagnostics is:
+//
+//	// Create a nil Diagnostics at the start of the function
+//	var diags diag.Diagnostics
+//
+//	// At later points, build on it if errors / warnings occur:
+//	foo, err := DoSomethingRisky()
+//	if err != nil {
+//	    diags = diags.Append(err)
+//	}
+//
+//	// Eventually return the result and diagnostics in place of error
+//	return result, diags
+//
+// Append accepts a variety of different diagnostic-like types, including
+// native Go errors and HCL diagnostics. It also knows how to unwrap
+// a multierror.Error into separate error diagnostics. It can be passed
+// another Diagnostics to concatenate the two lists. If given something
+// it cannot handle, this function will panic.
+func (diags Diagnostics) Append(new ...interface{}) Diagnostics {
+	for _, item := range new {
+		if item == nil {
+			continue
+		}
+
+		switch ti := item.(type) {
+		case Diagnostic:
+			diags = append(diags, ti)
+		case Diagnostics:
+			diags = append(diags, ti...) // flatten
+		case diagnosticsAsError:
+			diags = diags.Append(ti.Diagnostics) // unwrap
+		case NonFatalError:
+			diags = diags.Append(ti.Diagnostics) // unwrap
+		case hcl.Diagnostics:
+			for _, hclDiag := range ti {
+				diags = append(diags, hclDiagnostic{hclDiag})
+			}
+		case *hcl.Diagnostic:
+			diags = append(diags, hclDiagnostic{ti})
+		case *multierror.Error:
+			for _, err := range ti.Errors {
+				diags = append(diags, nativeError{err})
+			}
+		case error:
+			switch {
+			case errwrap.ContainsType(ti, Diagnostics(nil)):
+				// If we have an errwrap wrapper with a Diagnostics hiding
+				// inside then we'll unpick it here to get access to the
+				// individual diagnostics.
+				diags = diags.Append(errwrap.GetType(ti, Diagnostics(nil)))
+			case errwrap.ContainsType(ti, hcl.Diagnostics(nil)):
+				// Likewise, if we have HCL diagnostics we'll unpick that too.
+				diags = diags.Append(errwrap.GetType(ti, hcl.Diagnostics(nil)))
+			default:
+				diags = append(diags, nativeError{ti})
+			}
+		default:
+			panic(fmt.Errorf("can't construct diagnostic(s) from %T", item))
+		}
+	}
+
+	// Given the above, we should never end up with a non-nil empty slice
+	// here, but we'll make sure of that so callers can rely on empty == nil
+	if len(diags) == 0 {
+		return nil
+	}
+
+	return diags
+}
+
+// HasErrors returns true if any of the diagnostics in the list have
+// a severity of Error.
+func (diags Diagnostics) HasErrors() bool {
+	for _, diag := range diags {
+		if diag.Severity() == Error {
+			return true
+		}
+	}
+	return false
+}
+
+// ForRPC returns a version of the receiver that has been simplified so that
+// it is friendly to RPC protocols.
+//
+// Currently this means that it can be serialized with encoding/gob and
+// subsequently re-inflated. It may later grow to include other serialization
+// formats.
+//
+// Note that this loses information about the original objects used to
+// construct the diagnostics, so e.g. the errwrap API will not work as
+// expected on an error-wrapped Diagnostics that came from ForRPC.
+func (diags Diagnostics) ForRPC() Diagnostics {
+	ret := make(Diagnostics, len(diags))
+	for i := range diags {
+		ret[i] = makeRPCFriendlyDiag(diags[i])
+	}
+	return ret
+}
+
+// Err flattens a diagnostics list into a single Go error, or to nil
+// if the diagnostics list does not include any error-level diagnostics.
+//
+// This can be used to smuggle diagnostics through an API that deals in
+// native errors, but unfortunately it will lose any warnings that aren't
+// accompanied by at least one error since such APIs have no mechanism through
+// which to report those.
+//
+//	return result, diags.Error()
+func (diags Diagnostics) Err() error {
+	if !diags.HasErrors() {
+		return nil
+	}
+	return diagnosticsAsError{diags}
+}
+
+// ErrWithWarnings is similar to Err except that it will also return a non-nil
+// error if the receiver contains only warnings.
+//
+// In the warnings-only situation, the result is guaranteed to be of dynamic
+// type NonFatalError, allowing diagnostics-aware callers to type-assert
+// and unwrap it, treating it as non-fatal.
+//
+// This should be used only in contexts where the caller is able to recognize
+// and handle NonFatalError. For normal callers that expect a lack of errors
+// to be signaled by nil, use just Diagnostics.Err.
+func (diags Diagnostics) ErrWithWarnings() error {
+	if len(diags) == 0 {
+		return nil
+	}
+	if diags.HasErrors() {
+		return diags.Err()
+	}
+	return NonFatalError{diags}
+}
+
+// NonFatalErr is similar to Err except that it always returns either nil
+// (if there are no diagnostics at all) or NonFatalError.
+//
+// This allows diagnostics to be returned over an error return channel while
+// being explicit that the diagnostics should not halt processing.
+//
+// This should be used only in contexts where the caller is able to recognize
+// and handle NonFatalError. For normal callers that expect a lack of errors
+// to be signaled by nil, use just Diagnostics.Err.
+func (diags Diagnostics) NonFatalErr() error {
+	if len(diags) == 0 {
+		return nil
+	}
+	return NonFatalError{diags}
+}
+
+// Sort applies an ordering to the diagnostics in the receiver in-place.
+//
+// The ordering is: warnings before errors, sourceless before sourced,
+// short source paths before long source paths, and then ordering by
+// position within each file.
+//
+// Diagnostics that do not differ by any of these sortable characteristics
+// will remain in the same relative order after this method returns.
+func (diags Diagnostics) Sort() {
+	sort.Stable(sortDiagnostics(diags))
+}
+
+type diagnosticsAsError struct {
+	Diagnostics
+}
+
+func (dae diagnosticsAsError) Error() string {
+	diags := dae.Diagnostics
+	switch {
+	case len(diags) == 0:
+		// should never happen, since we don't create this wrapper if
+		// there are no diagnostics in the list.
+		return "no errors"
+	case len(diags) == 1:
+		desc := diags[0].Description()
+		if desc.Detail == "" {
+			return desc.Summary
+		}
+		return fmt.Sprintf("%s: %s", desc.Summary, desc.Detail)
+	default:
+		var ret bytes.Buffer
+		fmt.Fprintf(&ret, "%d problems:\n", len(diags))
+		for _, diag := range dae.Diagnostics {
+			desc := diag.Description()
+			if desc.Detail == "" {
+				fmt.Fprintf(&ret, "\n- %s", desc.Summary)
+			} else {
+				fmt.Fprintf(&ret, "\n- %s: %s", desc.Summary, desc.Detail)
+			}
+		}
+		return ret.String()
+	}
+}
+
+// WrappedErrors is an implementation of errwrap.Wrapper so that an error-wrapped
+// diagnostics object can be picked apart by errwrap-aware code.
+func (dae diagnosticsAsError) WrappedErrors() []error {
+	var errs []error
+	for _, diag := range dae.Diagnostics {
+		if wrapper, isErr := diag.(nativeError); isErr {
+			errs = append(errs, wrapper.err)
+		}
+	}
+	return errs
+}
+
+// NonFatalError is a special error type, returned by
+// Diagnostics.ErrWithWarnings and Diagnostics.NonFatalErr,
+// that indicates that the wrapped diagnostics should be treated as non-fatal.
+// Callers can conditionally type-assert an error to this type in order to
+// detect the non-fatal scenario and handle it in a different way.
+type NonFatalError struct {
+	Diagnostics
+}
+
+func (woe NonFatalError) Error() string {
+	diags := woe.Diagnostics
+	switch {
+	case len(diags) == 0:
+		// should never happen, since we don't create this wrapper if
+		// there are no diagnostics in the list.
+		return "no errors or warnings"
+	case len(diags) == 1:
+		desc := diags[0].Description()
+		if desc.Detail == "" {
+			return desc.Summary
+		}
+		return fmt.Sprintf("%s: %s", desc.Summary, desc.Detail)
+	default:
+		var ret bytes.Buffer
+		if diags.HasErrors() {
+			fmt.Fprintf(&ret, "%d problems:\n", len(diags))
+		} else {
+			fmt.Fprintf(&ret, "%d warnings:\n", len(diags))
+		}
+		for _, diag := range woe.Diagnostics {
+			desc := diag.Description()
+			if desc.Detail == "" {
+				fmt.Fprintf(&ret, "\n- %s", desc.Summary)
+			} else {
+				fmt.Fprintf(&ret, "\n- %s: %s", desc.Summary, desc.Detail)
+			}
+		}
+		return ret.String()
+	}
+}
+
+// sortDiagnostics is an implementation of sort.Interface
+type sortDiagnostics []Diagnostic
+
+var _ sort.Interface = sortDiagnostics(nil)
+
+func (sd sortDiagnostics) Len() int {
+	return len(sd)
+}
+
+func (sd sortDiagnostics) Less(i, j int) bool {
+	iD, jD := sd[i], sd[j]
+	iSev, jSev := iD.Severity(), jD.Severity()
+	iSrc, jSrc := iD.Source(), jD.Source()
+
+	switch {
+
+	case iSev != jSev:
+		return iSev == Warning
+
+	case (iSrc.Subject == nil) != (jSrc.Subject == nil):
+		return iSrc.Subject == nil
+
+	case iSrc.Subject != nil && *iSrc.Subject != *jSrc.Subject:
+		iSubj := iSrc.Subject
+		jSubj := jSrc.Subject
+		switch {
+		case iSubj.Filename != jSubj.Filename:
+			// Path with fewer segments goes first if they are different lengths
+			sep := string(filepath.Separator)
+			iCount := strings.Count(iSubj.Filename, sep)
+			jCount := strings.Count(jSubj.Filename, sep)
+			if iCount != jCount {
+				return iCount < jCount
+			}
+			return iSubj.Filename < jSubj.Filename
+		case iSubj.Start.Byte != jSubj.Start.Byte:
+			return iSubj.Start.Byte < jSubj.Start.Byte
+		case iSubj.End.Byte != jSubj.End.Byte:
+			return iSubj.End.Byte < jSubj.End.Byte
+		}
+		fallthrough
+
+	default:
+		// The remaining properties do not have a defined ordering, so
+		// we'll leave it unspecified. Since we use sort.Stable in
+		// the caller of this, the ordering of remaining items will
+		// be preserved.
+		return false
+	}
+}
+
+func (sd sortDiagnostics) Swap(i, j int) {
+	sd[i], sd[j] = sd[j], sd[i]
+}
diff --git a/v1.5.7/internal/tfdiags/diagnostics_test.go b/v1.5.7/internal/tfdiags/diagnostics_test.go
new file mode 100644
index 0000000..adadddf
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/diagnostics_test.go
@@ -0,0 +1,442 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/go-multierror"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/hashicorp/hcl/v2"
+)
+
+func TestBuild(t *testing.T) {
+	type diagFlat struct {
+		Severity Severity
+		Summary  string
+		Detail   string
+		Subject  *SourceRange
+		Context  *SourceRange
+	}
+
+	tests := map[string]struct {
+		Cons func(Diagnostics) Diagnostics
+		Want []diagFlat
+	}{
+		"nil": {
+			func(diags Diagnostics) Diagnostics {
+				return diags
+			},
+			nil,
+		},
+		"fmt.Errorf": {
+			func(diags Diagnostics) Diagnostics {
+				diags = diags.Append(fmt.Errorf("oh no bad"))
+				return diags
+			},
+			[]diagFlat{
+				{
+					Severity: Error,
+					Summary:  "oh no bad",
+				},
+			},
+		},
+		"errors.New": {
+			func(diags Diagnostics) Diagnostics {
+				diags = diags.Append(errors.New("oh no bad"))
+				return diags
+			},
+			[]diagFlat{
+				{
+					Severity: Error,
+					Summary:  "oh no bad",
+				},
+			},
+		},
+		"hcl.Diagnostic": {
+			func(diags Diagnostics) Diagnostics {
+				diags = diags.Append(&hcl.Diagnostic{
+					Severity: hcl.DiagError,
+					Summary:  "Something bad happened",
+					Detail:   "It was really, really bad.",
+					Subject: &hcl.Range{
+						Filename: "foo.tf",
+						Start:    hcl.Pos{Line: 1, Column: 10, Byte: 9},
+						End:      hcl.Pos{Line: 2, Column: 3, Byte: 25},
+					},
+					Context: &hcl.Range{
+						Filename: "foo.tf",
+						Start:    hcl.Pos{Line: 1, Column: 1, Byte: 0},
+						End:      hcl.Pos{Line: 3, Column: 1, Byte: 30},
+					},
+				})
+				return diags
+			},
+			[]diagFlat{
+				{
+					Severity: Error,
+					Summary:  "Something bad happened",
+					Detail:   "It was really, really bad.",
+					Subject: &SourceRange{
+						Filename: "foo.tf",
+						Start:    SourcePos{Line: 1, Column: 10, Byte: 9},
+						End:      SourcePos{Line: 2, Column: 3, Byte: 25},
+					},
+					Context: &SourceRange{
+						Filename: "foo.tf",
+						Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
+						End:      SourcePos{Line: 3, Column: 1, Byte: 30},
+					},
+				},
+			},
+		},
+		"hcl.Diagnostics": {
+			func(diags Diagnostics) Diagnostics {
+				diags = diags.Append(hcl.Diagnostics{
+					{
+						Severity: hcl.DiagError,
+						Summary:  "Something bad happened",
+						Detail:   "It was really, really bad.",
+					},
+					{
+						Severity: hcl.DiagWarning,
+						Summary:  "Also, somebody sneezed",
+						Detail:   "How rude!",
+					},
+				})
+				return diags
+			},
+			[]diagFlat{
+				{
+					Severity: Error,
+					Summary:  "Something bad happened",
+					Detail:   "It was really, really bad.",
+				},
+				{
+					Severity: Warning,
+					Summary:  "Also, somebody sneezed",
+					Detail:   "How rude!",
+				},
+			},
+		},
+		"multierror.Error": {
+			func(diags Diagnostics) Diagnostics {
+				err := multierror.Append(nil, errors.New("bad thing A"))
+				err = multierror.Append(err, errors.New("bad thing B"))
+				diags = diags.Append(err)
+				return diags
+			},
+			[]diagFlat{
+				{
+					Severity: Error,
+					Summary:  "bad thing A",
+				},
+				{
+					Severity: Error,
+					Summary:  "bad thing B",
+				},
+			},
+		},
+		"concat Diagnostics": {
+			func(diags Diagnostics) Diagnostics {
+				var moreDiags Diagnostics
+				moreDiags = moreDiags.Append(errors.New("bad thing A"))
+				moreDiags = moreDiags.Append(errors.New("bad thing B"))
+				return diags.Append(moreDiags)
+			},
+			[]diagFlat{
+				{
+					Severity: Error,
+					Summary:  "bad thing A",
+				},
+				{
+					Severity: Error,
+					Summary:  "bad thing B",
+				},
+			},
+		},
+		"single Diagnostic": {
+			func(diags Diagnostics) Diagnostics {
+				return diags.Append(SimpleWarning("Don't forget your toothbrush!"))
+			},
+			[]diagFlat{
+				{
+					Severity: Warning,
+					Summary:  "Don't forget your toothbrush!",
+				},
+			},
+		},
+		"multiple appends": {
+			func(diags Diagnostics) Diagnostics {
+				diags = diags.Append(SimpleWarning("Don't forget your toothbrush!"))
+				diags = diags.Append(fmt.Errorf("exploded"))
+				return diags
+			},
+			[]diagFlat{
+				{
+					Severity: Warning,
+					Summary:  "Don't forget your toothbrush!",
+				},
+				{
+					Severity: Error,
+					Summary:  "exploded",
+				},
+			},
+		},
+	}
+
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			gotDiags := test.Cons(nil)
+			var got []diagFlat
+			for _, item := range gotDiags {
+				desc := item.Description()
+				source := item.Source()
+				got = append(got, diagFlat{
+					Severity: item.Severity(),
+					Summary:  desc.Summary,
+					Detail:   desc.Detail,
+					Subject:  source.Subject,
+					Context:  source.Context,
+				})
+			}
+
+			if !reflect.DeepEqual(got, test.Want) {
+				t.Errorf("wrong result\ngot: %swant: %s", spew.Sdump(got), spew.Sdump(test.Want))
+			}
+		})
+	}
+}
+
+func TestDiagnosticsErr(t *testing.T) {
+	t.Run("empty", func(t *testing.T) {
+		var diags Diagnostics
+		err := diags.Err()
+		if err != nil {
+			t.Errorf("got non-nil error %#v; want nil", err)
+		}
+	})
+	t.Run("warning only", func(t *testing.T) {
+		var diags Diagnostics
+		diags = diags.Append(SimpleWarning("bad"))
+		err := diags.Err()
+		if err != nil {
+			t.Errorf("got non-nil error %#v; want nil", err)
+		}
+	})
+	t.Run("one error", func(t *testing.T) {
+		var diags Diagnostics
+		diags = diags.Append(errors.New("didn't work"))
+		err := diags.Err()
+		if err == nil {
+			t.Fatalf("got nil error %#v; want non-nil", err)
+		}
+		if got, want := err.Error(), "didn't work"; got != want {
+			t.Errorf("wrong error message\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run("two errors", func(t *testing.T) {
+		var diags Diagnostics
+		diags = diags.Append(errors.New("didn't work"))
+		diags = diags.Append(errors.New("didn't work either"))
+		err := diags.Err()
+		if err == nil {
+			t.Fatalf("got nil error %#v; want non-nil", err)
+		}
+		want := strings.TrimSpace(`
+2 problems:
+
+- didn't work
+- didn't work either
+`)
+		if got := err.Error(); got != want {
+			t.Errorf("wrong error message\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run("error and warning", func(t *testing.T) {
+		var diags Diagnostics
+		diags = diags.Append(errors.New("didn't work"))
+		diags = diags.Append(SimpleWarning("didn't work either"))
+		err := diags.Err()
+		if err == nil {
+			t.Fatalf("got nil error %#v; want non-nil", err)
+		}
+		// Since this "as error" mode is just a fallback for
+		// non-diagnostics-aware situations like tests, we don't actually
+		// distinguish warnings and errors here since the point is to just
+		// get the messages rendered. User-facing code should be printing
+		// each diagnostic separately, so won't enter this codepath,
+		want := strings.TrimSpace(`
+2 problems:
+
+- didn't work
+- didn't work either
+`)
+		if got := err.Error(); got != want {
+			t.Errorf("wrong error message\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+}
+
+func TestDiagnosticsErrWithWarnings(t *testing.T) {
+	t.Run("empty", func(t *testing.T) {
+		var diags Diagnostics
+		err := diags.ErrWithWarnings()
+		if err != nil {
+			t.Errorf("got non-nil error %#v; want nil", err)
+		}
+	})
+	t.Run("warning only", func(t *testing.T) {
+		var diags Diagnostics
+		diags = diags.Append(SimpleWarning("bad"))
+		err := diags.ErrWithWarnings()
+		if err == nil {
+			t.Errorf("got nil error; want NonFatalError")
+			return
+		}
+		if _, ok := err.(NonFatalError); !ok {
+			t.Errorf("got %T; want NonFatalError", err)
+		}
+	})
+	t.Run("one error", func(t *testing.T) {
+		var diags Diagnostics
+		diags = diags.Append(errors.New("didn't work"))
+		err := diags.ErrWithWarnings()
+		if err == nil {
+			t.Fatalf("got nil error %#v; want non-nil", err)
+		}
+		if got, want := err.Error(), "didn't work"; got != want {
+			t.Errorf("wrong error message\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run("two errors", func(t *testing.T) {
+		var diags Diagnostics
+		diags = diags.Append(errors.New("didn't work"))
+		diags = diags.Append(errors.New("didn't work either"))
+		err := diags.ErrWithWarnings()
+		if err == nil {
+			t.Fatalf("got nil error %#v; want non-nil", err)
+		}
+		want := strings.TrimSpace(`
+2 problems:
+
+- didn't work
+- didn't work either
+`)
+		if got := err.Error(); got != want {
+			t.Errorf("wrong error message\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+	t.Run("error and warning", func(t *testing.T) {
+		var diags Diagnostics
+		diags = diags.Append(errors.New("didn't work"))
+		diags = diags.Append(SimpleWarning("didn't work either"))
+		err := diags.ErrWithWarnings()
+		if err == nil {
+			t.Fatalf("got nil error %#v; want non-nil", err)
+		}
+		// Since this "as error" mode is just a fallback for
+		// non-diagnostics-aware situations like tests, we don't actually
+		// distinguish warnings and errors here since the point is to just
+		// get the messages rendered. User-facing code should be printing
+		// each diagnostic separately, so won't enter this codepath,
+		want := strings.TrimSpace(`
+2 problems:
+
+- didn't work
+- didn't work either
+`)
+		if got := err.Error(); got != want {
+			t.Errorf("wrong error message\ngot:  %s\nwant: %s", got, want)
+		}
+	})
+}
+
+func TestDiagnosticsNonFatalErr(t *testing.T) {
+	t.Run("empty", func(t *testing.T) {
+		var diags Diagnostics
+		err := diags.NonFatalErr()
+		if err != nil {
+			t.Errorf("got non-nil error %#v; want nil", err)
+		}
+	})
+	t.Run("warning only", func(t *testing.T) {
+		var diags Diagnostics
+		diags = diags.Append(SimpleWarning("bad"))
+		err := diags.NonFatalErr()
+		if err == nil {
+			t.Errorf("got nil error; want NonFatalError")
+			return
+		}
+		if _, ok := err.(NonFatalError); !ok {
+			t.Errorf("got %T; want NonFatalError", err)
+		}
+	})
+	t.Run("one error", func(t *testing.T) {
+		var diags Diagnostics
+		diags = diags.Append(errors.New("didn't work"))
+		err := diags.NonFatalErr()
+		if err == nil {
+			t.Fatalf("got nil error %#v; want non-nil", err)
+		}
+		if got, want := err.Error(), "didn't work"; got != want {
+			t.Errorf("wrong error message\ngot:  %s\nwant: %s", got, want)
+		}
+		if _, ok := err.(NonFatalError); !ok {
+			t.Errorf("got %T; want NonFatalError", err)
+		}
+	})
+	t.Run("two errors", func(t *testing.T) {
+		var diags Diagnostics
+		diags = diags.Append(errors.New("didn't work"))
+		diags = diags.Append(errors.New("didn't work either"))
+		err := diags.NonFatalErr()
+		if err == nil {
+			t.Fatalf("got nil error %#v; want non-nil", err)
+		}
+		want := strings.TrimSpace(`
+2 problems:
+
+- didn't work
+- didn't work either
+`)
+		if got := err.Error(); got != want {
+			t.Errorf("wrong error message\ngot:  %s\nwant: %s", got, want)
+		}
+		if _, ok := err.(NonFatalError); !ok {
+			t.Errorf("got %T; want NonFatalError", err)
+		}
+	})
+	t.Run("error and warning", func(t *testing.T) {
+		var diags Diagnostics
+		diags = diags.Append(errors.New("didn't work"))
+		diags = diags.Append(SimpleWarning("didn't work either"))
+		err := diags.NonFatalErr()
+		if err == nil {
+			t.Fatalf("got nil error %#v; want non-nil", err)
+		}
+		// Since this "as error" mode is just a fallback for
+		// non-diagnostics-aware situations like tests, we don't actually
+		// distinguish warnings and errors here since the point is to just
+		// get the messages rendered. User-facing code should be printing
+		// each diagnostic separately, so won't enter this codepath,
+		want := strings.TrimSpace(`
+2 problems:
+
+- didn't work
+- didn't work either
+`)
+		if got := err.Error(); got != want {
+			t.Errorf("wrong error message\ngot:  %s\nwant: %s", got, want)
+		}
+		if _, ok := err.(NonFatalError); !ok {
+			t.Errorf("got %T; want NonFatalError", err)
+		}
+	})
+}
diff --git a/v1.5.7/internal/tfdiags/doc.go b/v1.5.7/internal/tfdiags/doc.go
new file mode 100644
index 0000000..23be0a8
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/doc.go
@@ -0,0 +1,19 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Package tfdiags is a utility package for representing errors and
+// warnings in a manner that allows us to produce good messages for the
+// user.
+//
+// "diag" is short for "diagnostics", and is meant as a general word for
+// feedback to a user about potential or actual problems.
+//
+// A design goal for this package is for it to be able to provide rich
+// messaging where possible but to also be pragmatic about dealing with
+// generic errors produced by system components that _can't_ provide
+// such rich messaging. As a consequence, the main types in this package --
+// Diagnostics and Diagnostic -- are designed so that they can be "smuggled"
+// over an error channel and then be unpacked at the other end, so that
+// error diagnostics (at least) can transit through APIs that are not
+// aware of this package.
+package tfdiags
diff --git a/v1.5.7/internal/tfdiags/error.go b/v1.5.7/internal/tfdiags/error.go
new file mode 100644
index 0000000..f377ddb
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/error.go
@@ -0,0 +1,36 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+// nativeError is a Diagnostic implementation that wraps a normal Go error
+type nativeError struct {
+	err error
+}
+
+var _ Diagnostic = nativeError{}
+
+func (e nativeError) Severity() Severity {
+	return Error
+}
+
+func (e nativeError) Description() Description {
+	return Description{
+		Summary: FormatError(e.err),
+	}
+}
+
+func (e nativeError) Source() Source {
+	// No source information available for a native error
+	return Source{}
+}
+
+func (e nativeError) FromExpr() *FromExpr {
+	// Native errors are not expression-related
+	return nil
+}
+
+func (e nativeError) ExtraInfo() interface{} {
+	// Native errors don't carry any "extra information".
+	return nil
+}
diff --git a/v1.5.7/internal/tfdiags/hcl.go b/v1.5.7/internal/tfdiags/hcl.go
new file mode 100644
index 0000000..5822844
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/hcl.go
@@ -0,0 +1,136 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+import (
+	"github.com/hashicorp/hcl/v2"
+)
+
+// hclDiagnostic is a Diagnostic implementation that wraps a HCL Diagnostic
+type hclDiagnostic struct {
+	diag *hcl.Diagnostic
+}
+
+var _ Diagnostic = hclDiagnostic{}
+
+func (d hclDiagnostic) Severity() Severity {
+	switch d.diag.Severity {
+	case hcl.DiagWarning:
+		return Warning
+	default:
+		return Error
+	}
+}
+
+func (d hclDiagnostic) Description() Description {
+	return Description{
+		Summary: d.diag.Summary,
+		Detail:  d.diag.Detail,
+	}
+}
+
+func (d hclDiagnostic) Source() Source {
+	var ret Source
+	if d.diag.Subject != nil {
+		rng := SourceRangeFromHCL(*d.diag.Subject)
+		ret.Subject = &rng
+	}
+	if d.diag.Context != nil {
+		rng := SourceRangeFromHCL(*d.diag.Context)
+		ret.Context = &rng
+	}
+	return ret
+}
+
+func (d hclDiagnostic) FromExpr() *FromExpr {
+	if d.diag.Expression == nil || d.diag.EvalContext == nil {
+		return nil
+	}
+	return &FromExpr{
+		Expression:  d.diag.Expression,
+		EvalContext: d.diag.EvalContext,
+	}
+}
+
+func (d hclDiagnostic) ExtraInfo() interface{} {
+	return d.diag.Extra
+}
+
+// SourceRangeFromHCL constructs a SourceRange from the corresponding range
+// type within the HCL package.
+func SourceRangeFromHCL(hclRange hcl.Range) SourceRange {
+	return SourceRange{
+		Filename: hclRange.Filename,
+		Start: SourcePos{
+			Line:   hclRange.Start.Line,
+			Column: hclRange.Start.Column,
+			Byte:   hclRange.Start.Byte,
+		},
+		End: SourcePos{
+			Line:   hclRange.End.Line,
+			Column: hclRange.End.Column,
+			Byte:   hclRange.End.Byte,
+		},
+	}
+}
+
+// ToHCL constructs a HCL Range from the receiving SourceRange. This is the
+// opposite of SourceRangeFromHCL.
+func (r SourceRange) ToHCL() hcl.Range {
+	return hcl.Range{
+		Filename: r.Filename,
+		Start: hcl.Pos{
+			Line:   r.Start.Line,
+			Column: r.Start.Column,
+			Byte:   r.Start.Byte,
+		},
+		End: hcl.Pos{
+			Line:   r.End.Line,
+			Column: r.End.Column,
+			Byte:   r.End.Byte,
+		},
+	}
+}
+
+// ToHCL constructs a hcl.Diagnostics containing the same diagnostic messages
+// as the receiving tfdiags.Diagnostics.
+//
+// This conversion preserves the data that HCL diagnostics are able to
+// preserve but would be lossy in a round trip from tfdiags to HCL and then
+// back to tfdiags, because it will lose the specific type information of
+// the source diagnostics. In most cases this will not be a significant
+// problem, but could produce an awkward result in some special cases such
+// as converting the result of ConsolidateWarnings, which will force the
+// resulting warning groups to be flattened early.
+func (diags Diagnostics) ToHCL() hcl.Diagnostics {
+	if len(diags) == 0 {
+		return nil
+	}
+	ret := make(hcl.Diagnostics, len(diags))
+	for i, diag := range diags {
+		severity := diag.Severity()
+		desc := diag.Description()
+		source := diag.Source()
+		fromExpr := diag.FromExpr()
+
+		hclDiag := &hcl.Diagnostic{
+			Summary:  desc.Summary,
+			Detail:   desc.Detail,
+			Severity: severity.ToHCL(),
+		}
+		if source.Subject != nil {
+			hclDiag.Subject = source.Subject.ToHCL().Ptr()
+		}
+		if source.Context != nil {
+			hclDiag.Context = source.Context.ToHCL().Ptr()
+		}
+		if fromExpr != nil {
+			hclDiag.Expression = fromExpr.Expression
+			hclDiag.EvalContext = fromExpr.EvalContext
+		}
+
+		ret[i] = hclDiag
+	}
+	return ret
+}
diff --git a/v1.5.7/internal/tfdiags/hcl_test.go b/v1.5.7/internal/tfdiags/hcl_test.go
new file mode 100644
index 0000000..41a2d9a
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/hcl_test.go
@@ -0,0 +1,102 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"github.com/hashicorp/hcl/v2"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func TestDiagnosticsToHCL(t *testing.T) {
+	var diags Diagnostics
+	diags = diags.Append(Sourceless(
+		Error,
+		"A sourceless diagnostic",
+		"...that has a detail",
+	))
+	diags = diags.Append(fmt.Errorf("a diagnostic promoted from an error"))
+	diags = diags.Append(SimpleWarning("A diagnostic from a simple warning"))
+	diags = diags.Append(&hcl.Diagnostic{
+		Severity: hcl.DiagWarning,
+		Summary:  "A diagnostic from HCL",
+		Detail:   "...that has a detail and source information",
+		Subject: &hcl.Range{
+			Filename: "test.tf",
+			Start:    hcl.Pos{Line: 1, Column: 2, Byte: 1},
+			End:      hcl.Pos{Line: 1, Column: 3, Byte: 2},
+		},
+		Context: &hcl.Range{
+			Filename: "test.tf",
+			Start:    hcl.Pos{Line: 1, Column: 1, Byte: 0},
+			End:      hcl.Pos{Line: 1, Column: 4, Byte: 3},
+		},
+		EvalContext: &hcl.EvalContext{},
+		Expression:  &fakeHCLExpression{},
+	})
+
+	got := diags.ToHCL()
+	want := hcl.Diagnostics{
+		{
+			Severity: hcl.DiagError,
+			Summary:  "A sourceless diagnostic",
+			Detail:   "...that has a detail",
+		},
+		{
+			Severity: hcl.DiagError,
+			Summary:  "a diagnostic promoted from an error",
+		},
+		{
+			Severity: hcl.DiagWarning,
+			Summary:  "A diagnostic from a simple warning",
+		},
+		{
+			Severity: hcl.DiagWarning,
+			Summary:  "A diagnostic from HCL",
+			Detail:   "...that has a detail and source information",
+			Subject: &hcl.Range{
+				Filename: "test.tf",
+				Start:    hcl.Pos{Line: 1, Column: 2, Byte: 1},
+				End:      hcl.Pos{Line: 1, Column: 3, Byte: 2},
+			},
+			Context: &hcl.Range{
+				Filename: "test.tf",
+				Start:    hcl.Pos{Line: 1, Column: 1, Byte: 0},
+				End:      hcl.Pos{Line: 1, Column: 4, Byte: 3},
+			},
+			EvalContext: &hcl.EvalContext{},
+			Expression:  &fakeHCLExpression{},
+		},
+	}
+
+	if diff := cmp.Diff(want, got, cmpopts.IgnoreUnexported(hcl.EvalContext{})); diff != "" {
+		t.Errorf("incorrect result\n%s", diff)
+	}
+}
+
+// We have this here just to give us something easy to compare in the test
+// above, because we only care that the expression passes through, not about
+// how exactly it is shaped.
+type fakeHCLExpression struct {
+}
+
+func (e *fakeHCLExpression) Range() hcl.Range {
+	return hcl.Range{}
+}
+
+func (e *fakeHCLExpression) StartRange() hcl.Range {
+	return hcl.Range{}
+}
+
+func (e *fakeHCLExpression) Variables() []hcl.Traversal {
+	return nil
+}
+
+func (e *fakeHCLExpression) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
+	return cty.DynamicVal, nil
+}
diff --git a/v1.5.7/internal/tfdiags/rpc_friendly.go b/v1.5.7/internal/tfdiags/rpc_friendly.go
new file mode 100644
index 0000000..039781e
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/rpc_friendly.go
@@ -0,0 +1,67 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+import (
+	"encoding/gob"
+)
+
+type rpcFriendlyDiag struct {
+	Severity_ Severity
+	Summary_  string
+	Detail_   string
+	Subject_  *SourceRange
+	Context_  *SourceRange
+}
+
+// rpcFriendlyDiag transforms a given diagnostic so that is more friendly to
+// RPC.
+//
+// In particular, it currently returns an object that can be serialized and
+// later re-inflated using gob. This definition may grow to include other
+// serializations later.
+func makeRPCFriendlyDiag(diag Diagnostic) Diagnostic {
+	desc := diag.Description()
+	source := diag.Source()
+	return &rpcFriendlyDiag{
+		Severity_: diag.Severity(),
+		Summary_:  desc.Summary,
+		Detail_:   desc.Detail,
+		Subject_:  source.Subject,
+		Context_:  source.Context,
+	}
+}
+
+func (d *rpcFriendlyDiag) Severity() Severity {
+	return d.Severity_
+}
+
+func (d *rpcFriendlyDiag) Description() Description {
+	return Description{
+		Summary: d.Summary_,
+		Detail:  d.Detail_,
+	}
+}
+
+func (d *rpcFriendlyDiag) Source() Source {
+	return Source{
+		Subject: d.Subject_,
+		Context: d.Context_,
+	}
+}
+
+func (d rpcFriendlyDiag) FromExpr() *FromExpr {
+	// RPC-friendly diagnostics cannot preserve expression information because
+	// expressions themselves are not RPC-friendly.
+	return nil
+}
+
+func (d rpcFriendlyDiag) ExtraInfo() interface{} {
+	// RPC-friendly diagnostics always discard any "extra information".
+	return nil
+}
+
+func init() {
+	gob.Register((*rpcFriendlyDiag)(nil))
+}
diff --git a/v1.5.7/internal/tfdiags/rpc_friendly_test.go b/v1.5.7/internal/tfdiags/rpc_friendly_test.go
new file mode 100644
index 0000000..81e31ca
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/rpc_friendly_test.go
@@ -0,0 +1,75 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+import (
+	"bytes"
+	"encoding/gob"
+	"fmt"
+	"reflect"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+
+	"github.com/hashicorp/hcl/v2"
+)
+
+func TestDiagnosticsForRPC(t *testing.T) {
+	var diags Diagnostics
+	diags = diags.Append(fmt.Errorf("bad"))
+	diags = diags.Append(SimpleWarning("less bad"))
+	diags = diags.Append(&hcl.Diagnostic{
+		Severity: hcl.DiagError,
+		Summary:  "bad bad bad",
+		Detail:   "badily bad bad",
+		Subject: &hcl.Range{
+			Filename: "foo",
+		},
+		Context: &hcl.Range{
+			Filename: "bar",
+		},
+	})
+
+	buf := bytes.Buffer{}
+	enc := gob.NewEncoder(&buf)
+	dec := gob.NewDecoder(&buf)
+
+	rpcDiags := diags.ForRPC()
+	err := enc.Encode(rpcDiags)
+	if err != nil {
+		t.Fatalf("error on Encode: %s", err)
+	}
+
+	var got Diagnostics
+	err = dec.Decode(&got)
+	if err != nil {
+		t.Fatalf("error on Decode: %s", err)
+	}
+
+	want := Diagnostics{
+		&rpcFriendlyDiag{
+			Severity_: Error,
+			Summary_:  "bad",
+		},
+		&rpcFriendlyDiag{
+			Severity_: Warning,
+			Summary_:  "less bad",
+		},
+		&rpcFriendlyDiag{
+			Severity_: Error,
+			Summary_:  "bad bad bad",
+			Detail_:   "badily bad bad",
+			Subject_: &SourceRange{
+				Filename: "foo",
+			},
+			Context_: &SourceRange{
+				Filename: "bar",
+			},
+		},
+	}
+
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("wrong result\ngot: %swant: %s", spew.Sdump(got), spew.Sdump(want))
+	}
+}
diff --git a/v1.5.7/internal/tfdiags/severity_string.go b/v1.5.7/internal/tfdiags/severity_string.go
new file mode 100644
index 0000000..78a7210
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/severity_string.go
@@ -0,0 +1,29 @@
+// Code generated by "stringer -type=Severity"; DO NOT EDIT.
+
+package tfdiags
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[Error-69]
+	_ = x[Warning-87]
+}
+
+const (
+	_Severity_name_0 = "Error"
+	_Severity_name_1 = "Warning"
+)
+
+func (i Severity) String() string {
+	switch {
+	case i == 69:
+		return _Severity_name_0
+	case i == 87:
+		return _Severity_name_1
+	default:
+		return "Severity(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/v1.5.7/internal/tfdiags/simple_warning.go b/v1.5.7/internal/tfdiags/simple_warning.go
new file mode 100644
index 0000000..7a6fe38
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/simple_warning.go
@@ -0,0 +1,38 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+type simpleWarning string
+
+var _ Diagnostic = simpleWarning("")
+
+// SimpleWarning constructs a simple (summary-only) warning diagnostic.
+func SimpleWarning(msg string) Diagnostic {
+	return simpleWarning(msg)
+}
+
+func (e simpleWarning) Severity() Severity {
+	return Warning
+}
+
+func (e simpleWarning) Description() Description {
+	return Description{
+		Summary: string(e),
+	}
+}
+
+func (e simpleWarning) Source() Source {
+	// No source information available for a simple warning
+	return Source{}
+}
+
+func (e simpleWarning) FromExpr() *FromExpr {
+	// Simple warnings are not expression-related
+	return nil
+}
+
+func (e simpleWarning) ExtraInfo() interface{} {
+	// Simple warnings cannot carry extra information.
+	return nil
+}
diff --git a/v1.5.7/internal/tfdiags/source_range.go b/v1.5.7/internal/tfdiags/source_range.go
new file mode 100644
index 0000000..3d0fd9a
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/source_range.go
@@ -0,0 +1,38 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+)
+
+type SourceRange struct {
+	Filename   string
+	Start, End SourcePos
+}
+
+type SourcePos struct {
+	Line, Column, Byte int
+}
+
+// StartString returns a string representation of the start of the range,
+// including the filename and the line and column numbers.
+func (r SourceRange) StartString() string {
+	filename := r.Filename
+
+	// We'll try to relative-ize our filename here so it's less verbose
+	// in the common case of being in the current working directory. If not,
+	// we'll just show the full path.
+	wd, err := os.Getwd()
+	if err == nil {
+		relFn, err := filepath.Rel(wd, filename)
+		if err == nil {
+			filename = relFn
+		}
+	}
+
+	return fmt.Sprintf("%s:%d,%d", filename, r.Start.Line, r.Start.Column)
+}
diff --git a/v1.5.7/internal/tfdiags/sourceless.go b/v1.5.7/internal/tfdiags/sourceless.go
new file mode 100644
index 0000000..ad59f3f
--- /dev/null
+++ b/v1.5.7/internal/tfdiags/sourceless.go
@@ -0,0 +1,16 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package tfdiags
+
+// Sourceless creates and returns a diagnostic with no source location
+// information. This is generally used for operational-type errors that are
+// caused by or relate to the environment where Terraform is running rather
+// than to the provided configuration.
+func Sourceless(severity Severity, summary, detail string) Diagnostic {
+	return diagnosticBase{
+		severity: severity,
+		summary:  summary,
+		detail:   detail,
+	}
+}
diff --git a/v1.5.7/internal/tfplugin5/tfplugin5.pb.go b/v1.5.7/internal/tfplugin5/tfplugin5.pb.go
new file mode 100644
index 0000000..3dfc603
--- /dev/null
+++ b/v1.5.7/internal/tfplugin5/tfplugin5.pb.go
@@ -0,0 +1,5403 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Terraform Plugin RPC protocol version 5.3
+//
+// This file defines version 5.3 of the RPC protocol. To implement a plugin
+// against this protocol, copy this definition into your own codebase and
+// use protoc to generate stubs for your target language.
+//
+// This file will not be updated. Any minor versions of protocol 5 to follow
+// should copy this file and modify the copy while maintaing backwards
+// compatibility. Breaking changes, if any are required, will come
+// in a subsequent major version with its own separate proto definition.
+//
+// Note that only the proto files included in a release tag of Terraform are
+// official protocol releases. Proto files taken from other commits may include
+// incomplete changes or features that did not make it into a final release.
+// In all reasonable cases, plugin developers should take the proto file from
+// the tag of the most recent release of Terraform, and not from the main
+// branch or any other development branch.
+//
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.28.1
+// 	protoc        v3.15.6
+// source: tfplugin5.proto
+
+package tfplugin5
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type StringKind int32
+
+const (
+	StringKind_PLAIN    StringKind = 0
+	StringKind_MARKDOWN StringKind = 1
+)
+
+// Enum value maps for StringKind.
+var (
+	StringKind_name = map[int32]string{
+		0: "PLAIN",
+		1: "MARKDOWN",
+	}
+	StringKind_value = map[string]int32{
+		"PLAIN":    0,
+		"MARKDOWN": 1,
+	}
+)
+
+func (x StringKind) Enum() *StringKind {
+	p := new(StringKind)
+	*p = x
+	return p
+}
+
+func (x StringKind) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (StringKind) Descriptor() protoreflect.EnumDescriptor {
+	return file_tfplugin5_proto_enumTypes[0].Descriptor()
+}
+
+func (StringKind) Type() protoreflect.EnumType {
+	return &file_tfplugin5_proto_enumTypes[0]
+}
+
+func (x StringKind) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use StringKind.Descriptor instead.
+func (StringKind) EnumDescriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{0}
+}
+
+type Diagnostic_Severity int32
+
+const (
+	Diagnostic_INVALID Diagnostic_Severity = 0
+	Diagnostic_ERROR   Diagnostic_Severity = 1
+	Diagnostic_WARNING Diagnostic_Severity = 2
+)
+
+// Enum value maps for Diagnostic_Severity.
+var (
+	Diagnostic_Severity_name = map[int32]string{
+		0: "INVALID",
+		1: "ERROR",
+		2: "WARNING",
+	}
+	Diagnostic_Severity_value = map[string]int32{
+		"INVALID": 0,
+		"ERROR":   1,
+		"WARNING": 2,
+	}
+)
+
+func (x Diagnostic_Severity) Enum() *Diagnostic_Severity {
+	p := new(Diagnostic_Severity)
+	*p = x
+	return p
+}
+
+func (x Diagnostic_Severity) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Diagnostic_Severity) Descriptor() protoreflect.EnumDescriptor {
+	return file_tfplugin5_proto_enumTypes[1].Descriptor()
+}
+
+func (Diagnostic_Severity) Type() protoreflect.EnumType {
+	return &file_tfplugin5_proto_enumTypes[1]
+}
+
+func (x Diagnostic_Severity) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Diagnostic_Severity.Descriptor instead.
+func (Diagnostic_Severity) EnumDescriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{1, 0}
+}
+
+type Schema_NestedBlock_NestingMode int32
+
+const (
+	Schema_NestedBlock_INVALID Schema_NestedBlock_NestingMode = 0
+	Schema_NestedBlock_SINGLE  Schema_NestedBlock_NestingMode = 1
+	Schema_NestedBlock_LIST    Schema_NestedBlock_NestingMode = 2
+	Schema_NestedBlock_SET     Schema_NestedBlock_NestingMode = 3
+	Schema_NestedBlock_MAP     Schema_NestedBlock_NestingMode = 4
+	Schema_NestedBlock_GROUP   Schema_NestedBlock_NestingMode = 5
+)
+
+// Enum value maps for Schema_NestedBlock_NestingMode.
+var (
+	Schema_NestedBlock_NestingMode_name = map[int32]string{
+		0: "INVALID",
+		1: "SINGLE",
+		2: "LIST",
+		3: "SET",
+		4: "MAP",
+		5: "GROUP",
+	}
+	Schema_NestedBlock_NestingMode_value = map[string]int32{
+		"INVALID": 0,
+		"SINGLE":  1,
+		"LIST":    2,
+		"SET":     3,
+		"MAP":     4,
+		"GROUP":   5,
+	}
+)
+
+func (x Schema_NestedBlock_NestingMode) Enum() *Schema_NestedBlock_NestingMode {
+	p := new(Schema_NestedBlock_NestingMode)
+	*p = x
+	return p
+}
+
+func (x Schema_NestedBlock_NestingMode) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Schema_NestedBlock_NestingMode) Descriptor() protoreflect.EnumDescriptor {
+	return file_tfplugin5_proto_enumTypes[2].Descriptor()
+}
+
+func (Schema_NestedBlock_NestingMode) Type() protoreflect.EnumType {
+	return &file_tfplugin5_proto_enumTypes[2]
+}
+
+func (x Schema_NestedBlock_NestingMode) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Schema_NestedBlock_NestingMode.Descriptor instead.
+func (Schema_NestedBlock_NestingMode) EnumDescriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{5, 2, 0}
+}
+
+// DynamicValue is an opaque encoding of terraform data, with the field name
+// indicating the encoding scheme used.
+type DynamicValue struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Msgpack []byte `protobuf:"bytes,1,opt,name=msgpack,proto3" json:"msgpack,omitempty"`
+	Json    []byte `protobuf:"bytes,2,opt,name=json,proto3" json:"json,omitempty"`
+}
+
+func (x *DynamicValue) Reset() {
+	*x = DynamicValue{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DynamicValue) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DynamicValue) ProtoMessage() {}
+
+func (x *DynamicValue) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use DynamicValue.ProtoReflect.Descriptor instead.
+func (*DynamicValue) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *DynamicValue) GetMsgpack() []byte {
+	if x != nil {
+		return x.Msgpack
+	}
+	return nil
+}
+
+func (x *DynamicValue) GetJson() []byte {
+	if x != nil {
+		return x.Json
+	}
+	return nil
+}
+
+type Diagnostic struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Severity  Diagnostic_Severity `protobuf:"varint,1,opt,name=severity,proto3,enum=tfplugin5.Diagnostic_Severity" json:"severity,omitempty"`
+	Summary   string              `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"`
+	Detail    string              `protobuf:"bytes,3,opt,name=detail,proto3" json:"detail,omitempty"`
+	Attribute *AttributePath      `protobuf:"bytes,4,opt,name=attribute,proto3" json:"attribute,omitempty"`
+}
+
+func (x *Diagnostic) Reset() {
+	*x = Diagnostic{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Diagnostic) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Diagnostic) ProtoMessage() {}
+
+func (x *Diagnostic) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Diagnostic.ProtoReflect.Descriptor instead.
+func (*Diagnostic) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *Diagnostic) GetSeverity() Diagnostic_Severity {
+	if x != nil {
+		return x.Severity
+	}
+	return Diagnostic_INVALID
+}
+
+func (x *Diagnostic) GetSummary() string {
+	if x != nil {
+		return x.Summary
+	}
+	return ""
+}
+
+func (x *Diagnostic) GetDetail() string {
+	if x != nil {
+		return x.Detail
+	}
+	return ""
+}
+
+func (x *Diagnostic) GetAttribute() *AttributePath {
+	if x != nil {
+		return x.Attribute
+	}
+	return nil
+}
+
+type AttributePath struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Steps []*AttributePath_Step `protobuf:"bytes,1,rep,name=steps,proto3" json:"steps,omitempty"`
+}
+
+func (x *AttributePath) Reset() {
+	*x = AttributePath{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *AttributePath) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AttributePath) ProtoMessage() {}
+
+func (x *AttributePath) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AttributePath.ProtoReflect.Descriptor instead.
+func (*AttributePath) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *AttributePath) GetSteps() []*AttributePath_Step {
+	if x != nil {
+		return x.Steps
+	}
+	return nil
+}
+
+type Stop struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *Stop) Reset() {
+	*x = Stop{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Stop) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Stop) ProtoMessage() {}
+
+func (x *Stop) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Stop.ProtoReflect.Descriptor instead.
+func (*Stop) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{3}
+}
+
+// RawState holds the stored state for a resource to be upgraded by the
+// provider. It can be in one of two formats, the current json encoded format
+// in bytes, or the legacy flatmap format as a map of strings.
+type RawState struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Json    []byte            `protobuf:"bytes,1,opt,name=json,proto3" json:"json,omitempty"`
+	Flatmap map[string]string `protobuf:"bytes,2,rep,name=flatmap,proto3" json:"flatmap,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *RawState) Reset() {
+	*x = RawState{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *RawState) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RawState) ProtoMessage() {}
+
+func (x *RawState) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use RawState.ProtoReflect.Descriptor instead.
+func (*RawState) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *RawState) GetJson() []byte {
+	if x != nil {
+		return x.Json
+	}
+	return nil
+}
+
+func (x *RawState) GetFlatmap() map[string]string {
+	if x != nil {
+		return x.Flatmap
+	}
+	return nil
+}
+
+// Schema is the configuration schema for a Resource, Provider, or Provisioner.
+type Schema struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The version of the schema.
+	// Schemas are versioned, so that providers can upgrade a saved resource
+	// state when the schema is changed.
+	Version int64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
+	// Block is the top level configuration block for this schema.
+	Block *Schema_Block `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"`
+}
+
+func (x *Schema) Reset() {
+	*x = Schema{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Schema) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Schema) ProtoMessage() {}
+
+func (x *Schema) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Schema.ProtoReflect.Descriptor instead.
+func (*Schema) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *Schema) GetVersion() int64 {
+	if x != nil {
+		return x.Version
+	}
+	return 0
+}
+
+func (x *Schema) GetBlock() *Schema_Block {
+	if x != nil {
+		return x.Block
+	}
+	return nil
+}
+
+type GetProviderSchema struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *GetProviderSchema) Reset() {
+	*x = GetProviderSchema{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetProviderSchema) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetProviderSchema) ProtoMessage() {}
+
+func (x *GetProviderSchema) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[6]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetProviderSchema.ProtoReflect.Descriptor instead.
+func (*GetProviderSchema) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{6}
+}
+
+type PrepareProviderConfig struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *PrepareProviderConfig) Reset() {
+	*x = PrepareProviderConfig{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PrepareProviderConfig) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PrepareProviderConfig) ProtoMessage() {}
+
+func (x *PrepareProviderConfig) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[7]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PrepareProviderConfig.ProtoReflect.Descriptor instead.
+func (*PrepareProviderConfig) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{7}
+}
+
+type UpgradeResourceState struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *UpgradeResourceState) Reset() {
+	*x = UpgradeResourceState{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[8]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UpgradeResourceState) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpgradeResourceState) ProtoMessage() {}
+
+func (x *UpgradeResourceState) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[8]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpgradeResourceState.ProtoReflect.Descriptor instead.
+func (*UpgradeResourceState) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{8}
+}
+
+type ValidateResourceTypeConfig struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ValidateResourceTypeConfig) Reset() {
+	*x = ValidateResourceTypeConfig{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[9]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateResourceTypeConfig) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateResourceTypeConfig) ProtoMessage() {}
+
+func (x *ValidateResourceTypeConfig) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[9]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateResourceTypeConfig.ProtoReflect.Descriptor instead.
+func (*ValidateResourceTypeConfig) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{9}
+}
+
+type ValidateDataSourceConfig struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ValidateDataSourceConfig) Reset() {
+	*x = ValidateDataSourceConfig{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[10]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateDataSourceConfig) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateDataSourceConfig) ProtoMessage() {}
+
+func (x *ValidateDataSourceConfig) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[10]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateDataSourceConfig.ProtoReflect.Descriptor instead.
+func (*ValidateDataSourceConfig) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{10}
+}
+
+type Configure struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *Configure) Reset() {
+	*x = Configure{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[11]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Configure) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Configure) ProtoMessage() {}
+
+func (x *Configure) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[11]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Configure.ProtoReflect.Descriptor instead.
+func (*Configure) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{11}
+}
+
+type ReadResource struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ReadResource) Reset() {
+	*x = ReadResource{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[12]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReadResource) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReadResource) ProtoMessage() {}
+
+func (x *ReadResource) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[12]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReadResource.ProtoReflect.Descriptor instead.
+func (*ReadResource) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{12}
+}
+
+type PlanResourceChange struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *PlanResourceChange) Reset() {
+	*x = PlanResourceChange{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[13]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PlanResourceChange) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PlanResourceChange) ProtoMessage() {}
+
+func (x *PlanResourceChange) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[13]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PlanResourceChange.ProtoReflect.Descriptor instead.
+func (*PlanResourceChange) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{13}
+}
+
+type ApplyResourceChange struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ApplyResourceChange) Reset() {
+	*x = ApplyResourceChange{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[14]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ApplyResourceChange) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ApplyResourceChange) ProtoMessage() {}
+
+func (x *ApplyResourceChange) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[14]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ApplyResourceChange.ProtoReflect.Descriptor instead.
+func (*ApplyResourceChange) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{14}
+}
+
+type ImportResourceState struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ImportResourceState) Reset() {
+	*x = ImportResourceState{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[15]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ImportResourceState) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ImportResourceState) ProtoMessage() {}
+
+func (x *ImportResourceState) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[15]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ImportResourceState.ProtoReflect.Descriptor instead.
+func (*ImportResourceState) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{15}
+}
+
+type ReadDataSource struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ReadDataSource) Reset() {
+	*x = ReadDataSource{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[16]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReadDataSource) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReadDataSource) ProtoMessage() {}
+
+func (x *ReadDataSource) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[16]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReadDataSource.ProtoReflect.Descriptor instead.
+func (*ReadDataSource) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{16}
+}
+
+type GetProvisionerSchema struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *GetProvisionerSchema) Reset() {
+	*x = GetProvisionerSchema{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[17]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetProvisionerSchema) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetProvisionerSchema) ProtoMessage() {}
+
+func (x *GetProvisionerSchema) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[17]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetProvisionerSchema.ProtoReflect.Descriptor instead.
+func (*GetProvisionerSchema) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{17}
+}
+
+type ValidateProvisionerConfig struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ValidateProvisionerConfig) Reset() {
+	*x = ValidateProvisionerConfig{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[18]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateProvisionerConfig) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateProvisionerConfig) ProtoMessage() {}
+
+func (x *ValidateProvisionerConfig) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[18]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateProvisionerConfig.ProtoReflect.Descriptor instead.
+func (*ValidateProvisionerConfig) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{18}
+}
+
+type ProvisionResource struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ProvisionResource) Reset() {
+	*x = ProvisionResource{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[19]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ProvisionResource) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProvisionResource) ProtoMessage() {}
+
+func (x *ProvisionResource) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[19]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ProvisionResource.ProtoReflect.Descriptor instead.
+func (*ProvisionResource) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{19}
+}
+
+type AttributePath_Step struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Types that are assignable to Selector:
+	//
+	//	*AttributePath_Step_AttributeName
+	//	*AttributePath_Step_ElementKeyString
+	//	*AttributePath_Step_ElementKeyInt
+	Selector isAttributePath_Step_Selector `protobuf_oneof:"selector"`
+}
+
+func (x *AttributePath_Step) Reset() {
+	*x = AttributePath_Step{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[20]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *AttributePath_Step) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AttributePath_Step) ProtoMessage() {}
+
+func (x *AttributePath_Step) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[20]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AttributePath_Step.ProtoReflect.Descriptor instead.
+func (*AttributePath_Step) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{2, 0}
+}
+
+func (m *AttributePath_Step) GetSelector() isAttributePath_Step_Selector {
+	if m != nil {
+		return m.Selector
+	}
+	return nil
+}
+
+func (x *AttributePath_Step) GetAttributeName() string {
+	if x, ok := x.GetSelector().(*AttributePath_Step_AttributeName); ok {
+		return x.AttributeName
+	}
+	return ""
+}
+
+func (x *AttributePath_Step) GetElementKeyString() string {
+	if x, ok := x.GetSelector().(*AttributePath_Step_ElementKeyString); ok {
+		return x.ElementKeyString
+	}
+	return ""
+}
+
+func (x *AttributePath_Step) GetElementKeyInt() int64 {
+	if x, ok := x.GetSelector().(*AttributePath_Step_ElementKeyInt); ok {
+		return x.ElementKeyInt
+	}
+	return 0
+}
+
+type isAttributePath_Step_Selector interface {
+	isAttributePath_Step_Selector()
+}
+
+type AttributePath_Step_AttributeName struct {
+	// Set "attribute_name" to represent looking up an attribute
+	// in the current object value.
+	AttributeName string `protobuf:"bytes,1,opt,name=attribute_name,json=attributeName,proto3,oneof"`
+}
+
+type AttributePath_Step_ElementKeyString struct {
+	// Set "element_key_*" to represent looking up an element in
+	// an indexable collection type.
+	ElementKeyString string `protobuf:"bytes,2,opt,name=element_key_string,json=elementKeyString,proto3,oneof"`
+}
+
+type AttributePath_Step_ElementKeyInt struct {
+	ElementKeyInt int64 `protobuf:"varint,3,opt,name=element_key_int,json=elementKeyInt,proto3,oneof"`
+}
+
+func (*AttributePath_Step_AttributeName) isAttributePath_Step_Selector() {}
+
+func (*AttributePath_Step_ElementKeyString) isAttributePath_Step_Selector() {}
+
+func (*AttributePath_Step_ElementKeyInt) isAttributePath_Step_Selector() {}
+
+type Stop_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *Stop_Request) Reset() {
+	*x = Stop_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[21]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Stop_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Stop_Request) ProtoMessage() {}
+
+func (x *Stop_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[21]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Stop_Request.ProtoReflect.Descriptor instead.
+func (*Stop_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{3, 0}
+}
+
+type Stop_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Error string `protobuf:"bytes,1,opt,name=Error,proto3" json:"Error,omitempty"`
+}
+
+func (x *Stop_Response) Reset() {
+	*x = Stop_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[22]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Stop_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Stop_Response) ProtoMessage() {}
+
+func (x *Stop_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[22]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Stop_Response.ProtoReflect.Descriptor instead.
+func (*Stop_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{3, 1}
+}
+
+func (x *Stop_Response) GetError() string {
+	if x != nil {
+		return x.Error
+	}
+	return ""
+}
+
+type Schema_Block struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Version         int64                 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
+	Attributes      []*Schema_Attribute   `protobuf:"bytes,2,rep,name=attributes,proto3" json:"attributes,omitempty"`
+	BlockTypes      []*Schema_NestedBlock `protobuf:"bytes,3,rep,name=block_types,json=blockTypes,proto3" json:"block_types,omitempty"`
+	Description     string                `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"`
+	DescriptionKind StringKind            `protobuf:"varint,5,opt,name=description_kind,json=descriptionKind,proto3,enum=tfplugin5.StringKind" json:"description_kind,omitempty"`
+	Deprecated      bool                  `protobuf:"varint,6,opt,name=deprecated,proto3" json:"deprecated,omitempty"`
+}
+
+func (x *Schema_Block) Reset() {
+	*x = Schema_Block{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[24]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Schema_Block) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Schema_Block) ProtoMessage() {}
+
+func (x *Schema_Block) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[24]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Schema_Block.ProtoReflect.Descriptor instead.
+func (*Schema_Block) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{5, 0}
+}
+
+func (x *Schema_Block) GetVersion() int64 {
+	if x != nil {
+		return x.Version
+	}
+	return 0
+}
+
+func (x *Schema_Block) GetAttributes() []*Schema_Attribute {
+	if x != nil {
+		return x.Attributes
+	}
+	return nil
+}
+
+func (x *Schema_Block) GetBlockTypes() []*Schema_NestedBlock {
+	if x != nil {
+		return x.BlockTypes
+	}
+	return nil
+}
+
+func (x *Schema_Block) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *Schema_Block) GetDescriptionKind() StringKind {
+	if x != nil {
+		return x.DescriptionKind
+	}
+	return StringKind_PLAIN
+}
+
+func (x *Schema_Block) GetDeprecated() bool {
+	if x != nil {
+		return x.Deprecated
+	}
+	return false
+}
+
+type Schema_Attribute struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Name            string     `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	Type            []byte     `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
+	Description     string     `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
+	Required        bool       `protobuf:"varint,4,opt,name=required,proto3" json:"required,omitempty"`
+	Optional        bool       `protobuf:"varint,5,opt,name=optional,proto3" json:"optional,omitempty"`
+	Computed        bool       `protobuf:"varint,6,opt,name=computed,proto3" json:"computed,omitempty"`
+	Sensitive       bool       `protobuf:"varint,7,opt,name=sensitive,proto3" json:"sensitive,omitempty"`
+	DescriptionKind StringKind `protobuf:"varint,8,opt,name=description_kind,json=descriptionKind,proto3,enum=tfplugin5.StringKind" json:"description_kind,omitempty"`
+	Deprecated      bool       `protobuf:"varint,9,opt,name=deprecated,proto3" json:"deprecated,omitempty"`
+}
+
+func (x *Schema_Attribute) Reset() {
+	*x = Schema_Attribute{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[25]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Schema_Attribute) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Schema_Attribute) ProtoMessage() {}
+
+func (x *Schema_Attribute) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[25]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Schema_Attribute.ProtoReflect.Descriptor instead.
+func (*Schema_Attribute) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{5, 1}
+}
+
+func (x *Schema_Attribute) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *Schema_Attribute) GetType() []byte {
+	if x != nil {
+		return x.Type
+	}
+	return nil
+}
+
+func (x *Schema_Attribute) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *Schema_Attribute) GetRequired() bool {
+	if x != nil {
+		return x.Required
+	}
+	return false
+}
+
+func (x *Schema_Attribute) GetOptional() bool {
+	if x != nil {
+		return x.Optional
+	}
+	return false
+}
+
+func (x *Schema_Attribute) GetComputed() bool {
+	if x != nil {
+		return x.Computed
+	}
+	return false
+}
+
+func (x *Schema_Attribute) GetSensitive() bool {
+	if x != nil {
+		return x.Sensitive
+	}
+	return false
+}
+
+func (x *Schema_Attribute) GetDescriptionKind() StringKind {
+	if x != nil {
+		return x.DescriptionKind
+	}
+	return StringKind_PLAIN
+}
+
+func (x *Schema_Attribute) GetDeprecated() bool {
+	if x != nil {
+		return x.Deprecated
+	}
+	return false
+}
+
+type Schema_NestedBlock struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName string                         `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	Block    *Schema_Block                  `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"`
+	Nesting  Schema_NestedBlock_NestingMode `protobuf:"varint,3,opt,name=nesting,proto3,enum=tfplugin5.Schema_NestedBlock_NestingMode" json:"nesting,omitempty"`
+	MinItems int64                          `protobuf:"varint,4,opt,name=min_items,json=minItems,proto3" json:"min_items,omitempty"`
+	MaxItems int64                          `protobuf:"varint,5,opt,name=max_items,json=maxItems,proto3" json:"max_items,omitempty"`
+}
+
+func (x *Schema_NestedBlock) Reset() {
+	*x = Schema_NestedBlock{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[26]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Schema_NestedBlock) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Schema_NestedBlock) ProtoMessage() {}
+
+func (x *Schema_NestedBlock) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[26]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Schema_NestedBlock.ProtoReflect.Descriptor instead.
+func (*Schema_NestedBlock) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{5, 2}
+}
+
+func (x *Schema_NestedBlock) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *Schema_NestedBlock) GetBlock() *Schema_Block {
+	if x != nil {
+		return x.Block
+	}
+	return nil
+}
+
+func (x *Schema_NestedBlock) GetNesting() Schema_NestedBlock_NestingMode {
+	if x != nil {
+		return x.Nesting
+	}
+	return Schema_NestedBlock_INVALID
+}
+
+func (x *Schema_NestedBlock) GetMinItems() int64 {
+	if x != nil {
+		return x.MinItems
+	}
+	return 0
+}
+
+func (x *Schema_NestedBlock) GetMaxItems() int64 {
+	if x != nil {
+		return x.MaxItems
+	}
+	return 0
+}
+
+type GetProviderSchema_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *GetProviderSchema_Request) Reset() {
+	*x = GetProviderSchema_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[27]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetProviderSchema_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetProviderSchema_Request) ProtoMessage() {}
+
+func (x *GetProviderSchema_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[27]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetProviderSchema_Request.ProtoReflect.Descriptor instead.
+func (*GetProviderSchema_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{6, 0}
+}
+
+type GetProviderSchema_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Provider           *Schema                               `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
+	ResourceSchemas    map[string]*Schema                    `protobuf:"bytes,2,rep,name=resource_schemas,json=resourceSchemas,proto3" json:"resource_schemas,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	DataSourceSchemas  map[string]*Schema                    `protobuf:"bytes,3,rep,name=data_source_schemas,json=dataSourceSchemas,proto3" json:"data_source_schemas,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	Diagnostics        []*Diagnostic                         `protobuf:"bytes,4,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+	ProviderMeta       *Schema                               `protobuf:"bytes,5,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"`
+	ServerCapabilities *GetProviderSchema_ServerCapabilities `protobuf:"bytes,6,opt,name=server_capabilities,json=serverCapabilities,proto3" json:"server_capabilities,omitempty"`
+}
+
+func (x *GetProviderSchema_Response) Reset() {
+	*x = GetProviderSchema_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[28]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetProviderSchema_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetProviderSchema_Response) ProtoMessage() {}
+
+func (x *GetProviderSchema_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[28]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetProviderSchema_Response.ProtoReflect.Descriptor instead.
+func (*GetProviderSchema_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{6, 1}
+}
+
+func (x *GetProviderSchema_Response) GetProvider() *Schema {
+	if x != nil {
+		return x.Provider
+	}
+	return nil
+}
+
+func (x *GetProviderSchema_Response) GetResourceSchemas() map[string]*Schema {
+	if x != nil {
+		return x.ResourceSchemas
+	}
+	return nil
+}
+
+func (x *GetProviderSchema_Response) GetDataSourceSchemas() map[string]*Schema {
+	if x != nil {
+		return x.DataSourceSchemas
+	}
+	return nil
+}
+
+func (x *GetProviderSchema_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+func (x *GetProviderSchema_Response) GetProviderMeta() *Schema {
+	if x != nil {
+		return x.ProviderMeta
+	}
+	return nil
+}
+
+func (x *GetProviderSchema_Response) GetServerCapabilities() *GetProviderSchema_ServerCapabilities {
+	if x != nil {
+		return x.ServerCapabilities
+	}
+	return nil
+}
+
+// ServerCapabilities allows providers to communicate extra information
+// regarding supported protocol features. This is used to indicate
+// availability of certain forward-compatible changes which may be optional
+// in a major protocol version, but cannot be tested for directly.
+type GetProviderSchema_ServerCapabilities struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The plan_destroy capability signals that a provider expects a call
+	// to PlanResourceChange when a resource is going to be destroyed.
+	PlanDestroy bool `protobuf:"varint,1,opt,name=plan_destroy,json=planDestroy,proto3" json:"plan_destroy,omitempty"`
+}
+
+func (x *GetProviderSchema_ServerCapabilities) Reset() {
+	*x = GetProviderSchema_ServerCapabilities{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[29]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetProviderSchema_ServerCapabilities) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetProviderSchema_ServerCapabilities) ProtoMessage() {}
+
+func (x *GetProviderSchema_ServerCapabilities) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[29]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetProviderSchema_ServerCapabilities.ProtoReflect.Descriptor instead.
+func (*GetProviderSchema_ServerCapabilities) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{6, 2}
+}
+
+func (x *GetProviderSchema_ServerCapabilities) GetPlanDestroy() bool {
+	if x != nil {
+		return x.PlanDestroy
+	}
+	return false
+}
+
+type PrepareProviderConfig_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Config *DynamicValue `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"`
+}
+
+func (x *PrepareProviderConfig_Request) Reset() {
+	*x = PrepareProviderConfig_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[32]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PrepareProviderConfig_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PrepareProviderConfig_Request) ProtoMessage() {}
+
+func (x *PrepareProviderConfig_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[32]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PrepareProviderConfig_Request.ProtoReflect.Descriptor instead.
+func (*PrepareProviderConfig_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{7, 0}
+}
+
+func (x *PrepareProviderConfig_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+type PrepareProviderConfig_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	PreparedConfig *DynamicValue `protobuf:"bytes,1,opt,name=prepared_config,json=preparedConfig,proto3" json:"prepared_config,omitempty"`
+	Diagnostics    []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *PrepareProviderConfig_Response) Reset() {
+	*x = PrepareProviderConfig_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[33]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PrepareProviderConfig_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PrepareProviderConfig_Response) ProtoMessage() {}
+
+func (x *PrepareProviderConfig_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[33]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PrepareProviderConfig_Response.ProtoReflect.Descriptor instead.
+func (*PrepareProviderConfig_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{7, 1}
+}
+
+func (x *PrepareProviderConfig_Response) GetPreparedConfig() *DynamicValue {
+	if x != nil {
+		return x.PreparedConfig
+	}
+	return nil
+}
+
+func (x *PrepareProviderConfig_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+// Request is the message that is sent to the provider during the
+// UpgradeResourceState RPC.
+//
+// This message intentionally does not include configuration data as any
+// configuration-based or configuration-conditional changes should occur
+// during the PlanResourceChange RPC. Additionally, the configuration is
+// not guaranteed to exist (in the case of resource destruction), be wholly
+// known, nor match the given prior state, which could lead to unexpected
+// provider behaviors for practitioners.
+type UpgradeResourceState_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	// version is the schema_version number recorded in the state file
+	Version int64 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"`
+	// raw_state is the raw states as stored for the resource.  Core does
+	// not have access to the schema of prior_version, so it's the
+	// provider's responsibility to interpret this value using the
+	// appropriate older schema. The raw_state will be the json encoded
+	// state, or a legacy flat-mapped format.
+	RawState *RawState `protobuf:"bytes,3,opt,name=raw_state,json=rawState,proto3" json:"raw_state,omitempty"`
+}
+
+func (x *UpgradeResourceState_Request) Reset() {
+	*x = UpgradeResourceState_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[34]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UpgradeResourceState_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpgradeResourceState_Request) ProtoMessage() {}
+
+func (x *UpgradeResourceState_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[34]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpgradeResourceState_Request.ProtoReflect.Descriptor instead.
+func (*UpgradeResourceState_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{8, 0}
+}
+
+func (x *UpgradeResourceState_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *UpgradeResourceState_Request) GetVersion() int64 {
+	if x != nil {
+		return x.Version
+	}
+	return 0
+}
+
+func (x *UpgradeResourceState_Request) GetRawState() *RawState {
+	if x != nil {
+		return x.RawState
+	}
+	return nil
+}
+
+type UpgradeResourceState_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// new_state is a msgpack-encoded data structure that, when interpreted with
+	// the _current_ schema for this resource type, is functionally equivalent to
+	// that which was given in prior_state_raw.
+	UpgradedState *DynamicValue `protobuf:"bytes,1,opt,name=upgraded_state,json=upgradedState,proto3" json:"upgraded_state,omitempty"`
+	// diagnostics describes any errors encountered during migration that could not
+	// be safely resolved, and warnings about any possibly-risky assumptions made
+	// in the upgrade process.
+	Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *UpgradeResourceState_Response) Reset() {
+	*x = UpgradeResourceState_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[35]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UpgradeResourceState_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpgradeResourceState_Response) ProtoMessage() {}
+
+func (x *UpgradeResourceState_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[35]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpgradeResourceState_Response.ProtoReflect.Descriptor instead.
+func (*UpgradeResourceState_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{8, 1}
+}
+
+func (x *UpgradeResourceState_Response) GetUpgradedState() *DynamicValue {
+	if x != nil {
+		return x.UpgradedState
+	}
+	return nil
+}
+
+func (x *UpgradeResourceState_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+type ValidateResourceTypeConfig_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName string        `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	Config   *DynamicValue `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"`
+}
+
+func (x *ValidateResourceTypeConfig_Request) Reset() {
+	*x = ValidateResourceTypeConfig_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[36]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateResourceTypeConfig_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateResourceTypeConfig_Request) ProtoMessage() {}
+
+func (x *ValidateResourceTypeConfig_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[36]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateResourceTypeConfig_Request.ProtoReflect.Descriptor instead.
+func (*ValidateResourceTypeConfig_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{9, 0}
+}
+
+func (x *ValidateResourceTypeConfig_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *ValidateResourceTypeConfig_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+type ValidateResourceTypeConfig_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Diagnostics []*Diagnostic `protobuf:"bytes,1,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *ValidateResourceTypeConfig_Response) Reset() {
+	*x = ValidateResourceTypeConfig_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[37]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateResourceTypeConfig_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateResourceTypeConfig_Response) ProtoMessage() {}
+
+func (x *ValidateResourceTypeConfig_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[37]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateResourceTypeConfig_Response.ProtoReflect.Descriptor instead.
+func (*ValidateResourceTypeConfig_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{9, 1}
+}
+
+func (x *ValidateResourceTypeConfig_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+type ValidateDataSourceConfig_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName string        `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	Config   *DynamicValue `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"`
+}
+
+func (x *ValidateDataSourceConfig_Request) Reset() {
+	*x = ValidateDataSourceConfig_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[38]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateDataSourceConfig_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateDataSourceConfig_Request) ProtoMessage() {}
+
+func (x *ValidateDataSourceConfig_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[38]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateDataSourceConfig_Request.ProtoReflect.Descriptor instead.
+func (*ValidateDataSourceConfig_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{10, 0}
+}
+
+func (x *ValidateDataSourceConfig_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *ValidateDataSourceConfig_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+type ValidateDataSourceConfig_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Diagnostics []*Diagnostic `protobuf:"bytes,1,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *ValidateDataSourceConfig_Response) Reset() {
+	*x = ValidateDataSourceConfig_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[39]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateDataSourceConfig_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateDataSourceConfig_Response) ProtoMessage() {}
+
+func (x *ValidateDataSourceConfig_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[39]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateDataSourceConfig_Response.ProtoReflect.Descriptor instead.
+func (*ValidateDataSourceConfig_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{10, 1}
+}
+
+func (x *ValidateDataSourceConfig_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+type Configure_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TerraformVersion string        `protobuf:"bytes,1,opt,name=terraform_version,json=terraformVersion,proto3" json:"terraform_version,omitempty"`
+	Config           *DynamicValue `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"`
+}
+
+func (x *Configure_Request) Reset() {
+	*x = Configure_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[40]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Configure_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Configure_Request) ProtoMessage() {}
+
+func (x *Configure_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[40]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Configure_Request.ProtoReflect.Descriptor instead.
+func (*Configure_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{11, 0}
+}
+
+func (x *Configure_Request) GetTerraformVersion() string {
+	if x != nil {
+		return x.TerraformVersion
+	}
+	return ""
+}
+
+func (x *Configure_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+type Configure_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Diagnostics []*Diagnostic `protobuf:"bytes,1,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *Configure_Response) Reset() {
+	*x = Configure_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[41]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Configure_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Configure_Response) ProtoMessage() {}
+
+func (x *Configure_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[41]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Configure_Response.ProtoReflect.Descriptor instead.
+func (*Configure_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{11, 1}
+}
+
+func (x *Configure_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+// Request is the message that is sent to the provider during the
+// ReadResource RPC.
+//
+// This message intentionally does not include configuration data as any
+// configuration-based or configuration-conditional changes should occur
+// during the PlanResourceChange RPC. Additionally, the configuration is
+// not guaranteed to be wholly known nor match the given prior state, which
+// could lead to unexpected provider behaviors for practitioners.
+type ReadResource_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName     string        `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	CurrentState *DynamicValue `protobuf:"bytes,2,opt,name=current_state,json=currentState,proto3" json:"current_state,omitempty"`
+	Private      []byte        `protobuf:"bytes,3,opt,name=private,proto3" json:"private,omitempty"`
+	ProviderMeta *DynamicValue `protobuf:"bytes,4,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"`
+}
+
+func (x *ReadResource_Request) Reset() {
+	*x = ReadResource_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[42]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReadResource_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReadResource_Request) ProtoMessage() {}
+
+func (x *ReadResource_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[42]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReadResource_Request.ProtoReflect.Descriptor instead.
+func (*ReadResource_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{12, 0}
+}
+
+func (x *ReadResource_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *ReadResource_Request) GetCurrentState() *DynamicValue {
+	if x != nil {
+		return x.CurrentState
+	}
+	return nil
+}
+
+func (x *ReadResource_Request) GetPrivate() []byte {
+	if x != nil {
+		return x.Private
+	}
+	return nil
+}
+
+func (x *ReadResource_Request) GetProviderMeta() *DynamicValue {
+	if x != nil {
+		return x.ProviderMeta
+	}
+	return nil
+}
+
+type ReadResource_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	NewState    *DynamicValue `protobuf:"bytes,1,opt,name=new_state,json=newState,proto3" json:"new_state,omitempty"`
+	Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+	Private     []byte        `protobuf:"bytes,3,opt,name=private,proto3" json:"private,omitempty"`
+}
+
+func (x *ReadResource_Response) Reset() {
+	*x = ReadResource_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[43]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReadResource_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReadResource_Response) ProtoMessage() {}
+
+func (x *ReadResource_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[43]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReadResource_Response.ProtoReflect.Descriptor instead.
+func (*ReadResource_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{12, 1}
+}
+
+func (x *ReadResource_Response) GetNewState() *DynamicValue {
+	if x != nil {
+		return x.NewState
+	}
+	return nil
+}
+
+func (x *ReadResource_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+func (x *ReadResource_Response) GetPrivate() []byte {
+	if x != nil {
+		return x.Private
+	}
+	return nil
+}
+
+type PlanResourceChange_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName         string        `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	PriorState       *DynamicValue `protobuf:"bytes,2,opt,name=prior_state,json=priorState,proto3" json:"prior_state,omitempty"`
+	ProposedNewState *DynamicValue `protobuf:"bytes,3,opt,name=proposed_new_state,json=proposedNewState,proto3" json:"proposed_new_state,omitempty"`
+	Config           *DynamicValue `protobuf:"bytes,4,opt,name=config,proto3" json:"config,omitempty"`
+	PriorPrivate     []byte        `protobuf:"bytes,5,opt,name=prior_private,json=priorPrivate,proto3" json:"prior_private,omitempty"`
+	ProviderMeta     *DynamicValue `protobuf:"bytes,6,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"`
+}
+
+func (x *PlanResourceChange_Request) Reset() {
+	*x = PlanResourceChange_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[44]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PlanResourceChange_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PlanResourceChange_Request) ProtoMessage() {}
+
+func (x *PlanResourceChange_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[44]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PlanResourceChange_Request.ProtoReflect.Descriptor instead.
+func (*PlanResourceChange_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{13, 0}
+}
+
+func (x *PlanResourceChange_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *PlanResourceChange_Request) GetPriorState() *DynamicValue {
+	if x != nil {
+		return x.PriorState
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Request) GetProposedNewState() *DynamicValue {
+	if x != nil {
+		return x.ProposedNewState
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Request) GetPriorPrivate() []byte {
+	if x != nil {
+		return x.PriorPrivate
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Request) GetProviderMeta() *DynamicValue {
+	if x != nil {
+		return x.ProviderMeta
+	}
+	return nil
+}
+
+type PlanResourceChange_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	PlannedState    *DynamicValue    `protobuf:"bytes,1,opt,name=planned_state,json=plannedState,proto3" json:"planned_state,omitempty"`
+	RequiresReplace []*AttributePath `protobuf:"bytes,2,rep,name=requires_replace,json=requiresReplace,proto3" json:"requires_replace,omitempty"`
+	PlannedPrivate  []byte           `protobuf:"bytes,3,opt,name=planned_private,json=plannedPrivate,proto3" json:"planned_private,omitempty"`
+	Diagnostics     []*Diagnostic    `protobuf:"bytes,4,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+	// This may be set only by the helper/schema "SDK" in the main Terraform
+	// repository, to request that Terraform Core >=0.12 permit additional
+	// inconsistencies that can result from the legacy SDK type system
+	// and its imprecise mapping to the >=0.12 type system.
+	// The change in behavior implied by this flag makes sense only for the
+	// specific details of the legacy SDK type system, and are not a general
+	// mechanism to avoid proper type handling in providers.
+	//
+	//	====              DO NOT USE THIS              ====
+	//	==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+	//	====              DO NOT USE THIS              ====
+	LegacyTypeSystem bool `protobuf:"varint,5,opt,name=legacy_type_system,json=legacyTypeSystem,proto3" json:"legacy_type_system,omitempty"`
+}
+
+func (x *PlanResourceChange_Response) Reset() {
+	*x = PlanResourceChange_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[45]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PlanResourceChange_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PlanResourceChange_Response) ProtoMessage() {}
+
+func (x *PlanResourceChange_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[45]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PlanResourceChange_Response.ProtoReflect.Descriptor instead.
+func (*PlanResourceChange_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{13, 1}
+}
+
+func (x *PlanResourceChange_Response) GetPlannedState() *DynamicValue {
+	if x != nil {
+		return x.PlannedState
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Response) GetRequiresReplace() []*AttributePath {
+	if x != nil {
+		return x.RequiresReplace
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Response) GetPlannedPrivate() []byte {
+	if x != nil {
+		return x.PlannedPrivate
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Response) GetLegacyTypeSystem() bool {
+	if x != nil {
+		return x.LegacyTypeSystem
+	}
+	return false
+}
+
+type ApplyResourceChange_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName       string        `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	PriorState     *DynamicValue `protobuf:"bytes,2,opt,name=prior_state,json=priorState,proto3" json:"prior_state,omitempty"`
+	PlannedState   *DynamicValue `protobuf:"bytes,3,opt,name=planned_state,json=plannedState,proto3" json:"planned_state,omitempty"`
+	Config         *DynamicValue `protobuf:"bytes,4,opt,name=config,proto3" json:"config,omitempty"`
+	PlannedPrivate []byte        `protobuf:"bytes,5,opt,name=planned_private,json=plannedPrivate,proto3" json:"planned_private,omitempty"`
+	ProviderMeta   *DynamicValue `protobuf:"bytes,6,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"`
+}
+
+func (x *ApplyResourceChange_Request) Reset() {
+	*x = ApplyResourceChange_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[46]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ApplyResourceChange_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ApplyResourceChange_Request) ProtoMessage() {}
+
+func (x *ApplyResourceChange_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[46]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ApplyResourceChange_Request.ProtoReflect.Descriptor instead.
+func (*ApplyResourceChange_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{14, 0}
+}
+
+func (x *ApplyResourceChange_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *ApplyResourceChange_Request) GetPriorState() *DynamicValue {
+	if x != nil {
+		return x.PriorState
+	}
+	return nil
+}
+
+func (x *ApplyResourceChange_Request) GetPlannedState() *DynamicValue {
+	if x != nil {
+		return x.PlannedState
+	}
+	return nil
+}
+
+func (x *ApplyResourceChange_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+func (x *ApplyResourceChange_Request) GetPlannedPrivate() []byte {
+	if x != nil {
+		return x.PlannedPrivate
+	}
+	return nil
+}
+
+func (x *ApplyResourceChange_Request) GetProviderMeta() *DynamicValue {
+	if x != nil {
+		return x.ProviderMeta
+	}
+	return nil
+}
+
+type ApplyResourceChange_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	NewState    *DynamicValue `protobuf:"bytes,1,opt,name=new_state,json=newState,proto3" json:"new_state,omitempty"`
+	Private     []byte        `protobuf:"bytes,2,opt,name=private,proto3" json:"private,omitempty"`
+	Diagnostics []*Diagnostic `protobuf:"bytes,3,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+	// This may be set only by the helper/schema "SDK" in the main Terraform
+	// repository, to request that Terraform Core >=0.12 permit additional
+	// inconsistencies that can result from the legacy SDK type system
+	// and its imprecise mapping to the >=0.12 type system.
+	// The change in behavior implied by this flag makes sense only for the
+	// specific details of the legacy SDK type system, and are not a general
+	// mechanism to avoid proper type handling in providers.
+	//
+	//	====              DO NOT USE THIS              ====
+	//	==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+	//	====              DO NOT USE THIS              ====
+	LegacyTypeSystem bool `protobuf:"varint,4,opt,name=legacy_type_system,json=legacyTypeSystem,proto3" json:"legacy_type_system,omitempty"`
+}
+
+func (x *ApplyResourceChange_Response) Reset() {
+	*x = ApplyResourceChange_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[47]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ApplyResourceChange_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ApplyResourceChange_Response) ProtoMessage() {}
+
+func (x *ApplyResourceChange_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[47]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ApplyResourceChange_Response.ProtoReflect.Descriptor instead.
+func (*ApplyResourceChange_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{14, 1}
+}
+
+func (x *ApplyResourceChange_Response) GetNewState() *DynamicValue {
+	if x != nil {
+		return x.NewState
+	}
+	return nil
+}
+
+func (x *ApplyResourceChange_Response) GetPrivate() []byte {
+	if x != nil {
+		return x.Private
+	}
+	return nil
+}
+
+func (x *ApplyResourceChange_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+func (x *ApplyResourceChange_Response) GetLegacyTypeSystem() bool {
+	if x != nil {
+		return x.LegacyTypeSystem
+	}
+	return false
+}
+
+type ImportResourceState_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	Id       string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
+}
+
+func (x *ImportResourceState_Request) Reset() {
+	*x = ImportResourceState_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[48]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ImportResourceState_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ImportResourceState_Request) ProtoMessage() {}
+
+func (x *ImportResourceState_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[48]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ImportResourceState_Request.ProtoReflect.Descriptor instead.
+func (*ImportResourceState_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{15, 0}
+}
+
+func (x *ImportResourceState_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *ImportResourceState_Request) GetId() string {
+	if x != nil {
+		return x.Id
+	}
+	return ""
+}
+
+type ImportResourceState_ImportedResource struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName string        `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	State    *DynamicValue `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
+	Private  []byte        `protobuf:"bytes,3,opt,name=private,proto3" json:"private,omitempty"`
+}
+
+func (x *ImportResourceState_ImportedResource) Reset() {
+	*x = ImportResourceState_ImportedResource{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[49]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ImportResourceState_ImportedResource) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ImportResourceState_ImportedResource) ProtoMessage() {}
+
+func (x *ImportResourceState_ImportedResource) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[49]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ImportResourceState_ImportedResource.ProtoReflect.Descriptor instead.
+func (*ImportResourceState_ImportedResource) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{15, 1}
+}
+
+func (x *ImportResourceState_ImportedResource) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *ImportResourceState_ImportedResource) GetState() *DynamicValue {
+	if x != nil {
+		return x.State
+	}
+	return nil
+}
+
+func (x *ImportResourceState_ImportedResource) GetPrivate() []byte {
+	if x != nil {
+		return x.Private
+	}
+	return nil
+}
+
+type ImportResourceState_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	ImportedResources []*ImportResourceState_ImportedResource `protobuf:"bytes,1,rep,name=imported_resources,json=importedResources,proto3" json:"imported_resources,omitempty"`
+	Diagnostics       []*Diagnostic                           `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *ImportResourceState_Response) Reset() {
+	*x = ImportResourceState_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[50]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ImportResourceState_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ImportResourceState_Response) ProtoMessage() {}
+
+func (x *ImportResourceState_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[50]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ImportResourceState_Response.ProtoReflect.Descriptor instead.
+func (*ImportResourceState_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{15, 2}
+}
+
+func (x *ImportResourceState_Response) GetImportedResources() []*ImportResourceState_ImportedResource {
+	if x != nil {
+		return x.ImportedResources
+	}
+	return nil
+}
+
+func (x *ImportResourceState_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+type ReadDataSource_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName     string        `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	Config       *DynamicValue `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"`
+	ProviderMeta *DynamicValue `protobuf:"bytes,3,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"`
+}
+
+func (x *ReadDataSource_Request) Reset() {
+	*x = ReadDataSource_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[51]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReadDataSource_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReadDataSource_Request) ProtoMessage() {}
+
+func (x *ReadDataSource_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[51]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReadDataSource_Request.ProtoReflect.Descriptor instead.
+func (*ReadDataSource_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{16, 0}
+}
+
+func (x *ReadDataSource_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *ReadDataSource_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+func (x *ReadDataSource_Request) GetProviderMeta() *DynamicValue {
+	if x != nil {
+		return x.ProviderMeta
+	}
+	return nil
+}
+
+type ReadDataSource_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	State       *DynamicValue `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"`
+	Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *ReadDataSource_Response) Reset() {
+	*x = ReadDataSource_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[52]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReadDataSource_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReadDataSource_Response) ProtoMessage() {}
+
+func (x *ReadDataSource_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[52]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReadDataSource_Response.ProtoReflect.Descriptor instead.
+func (*ReadDataSource_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{16, 1}
+}
+
+func (x *ReadDataSource_Response) GetState() *DynamicValue {
+	if x != nil {
+		return x.State
+	}
+	return nil
+}
+
+func (x *ReadDataSource_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+type GetProvisionerSchema_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *GetProvisionerSchema_Request) Reset() {
+	*x = GetProvisionerSchema_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[53]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetProvisionerSchema_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetProvisionerSchema_Request) ProtoMessage() {}
+
+func (x *GetProvisionerSchema_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[53]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetProvisionerSchema_Request.ProtoReflect.Descriptor instead.
+func (*GetProvisionerSchema_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{17, 0}
+}
+
+type GetProvisionerSchema_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Provisioner *Schema       `protobuf:"bytes,1,opt,name=provisioner,proto3" json:"provisioner,omitempty"`
+	Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *GetProvisionerSchema_Response) Reset() {
+	*x = GetProvisionerSchema_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[54]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetProvisionerSchema_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetProvisionerSchema_Response) ProtoMessage() {}
+
+func (x *GetProvisionerSchema_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[54]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetProvisionerSchema_Response.ProtoReflect.Descriptor instead.
+func (*GetProvisionerSchema_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{17, 1}
+}
+
+func (x *GetProvisionerSchema_Response) GetProvisioner() *Schema {
+	if x != nil {
+		return x.Provisioner
+	}
+	return nil
+}
+
+func (x *GetProvisionerSchema_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+type ValidateProvisionerConfig_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Config *DynamicValue `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"`
+}
+
+func (x *ValidateProvisionerConfig_Request) Reset() {
+	*x = ValidateProvisionerConfig_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[55]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateProvisionerConfig_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateProvisionerConfig_Request) ProtoMessage() {}
+
+func (x *ValidateProvisionerConfig_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[55]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateProvisionerConfig_Request.ProtoReflect.Descriptor instead.
+func (*ValidateProvisionerConfig_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{18, 0}
+}
+
+func (x *ValidateProvisionerConfig_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+type ValidateProvisionerConfig_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Diagnostics []*Diagnostic `protobuf:"bytes,1,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *ValidateProvisionerConfig_Response) Reset() {
+	*x = ValidateProvisionerConfig_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[56]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateProvisionerConfig_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateProvisionerConfig_Response) ProtoMessage() {}
+
+func (x *ValidateProvisionerConfig_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[56]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateProvisionerConfig_Response.ProtoReflect.Descriptor instead.
+func (*ValidateProvisionerConfig_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{18, 1}
+}
+
+func (x *ValidateProvisionerConfig_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+type ProvisionResource_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Config     *DynamicValue `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"`
+	Connection *DynamicValue `protobuf:"bytes,2,opt,name=connection,proto3" json:"connection,omitempty"`
+}
+
+func (x *ProvisionResource_Request) Reset() {
+	*x = ProvisionResource_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[57]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ProvisionResource_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProvisionResource_Request) ProtoMessage() {}
+
+func (x *ProvisionResource_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[57]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ProvisionResource_Request.ProtoReflect.Descriptor instead.
+func (*ProvisionResource_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{19, 0}
+}
+
+func (x *ProvisionResource_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+func (x *ProvisionResource_Request) GetConnection() *DynamicValue {
+	if x != nil {
+		return x.Connection
+	}
+	return nil
+}
+
+type ProvisionResource_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Output      string        `protobuf:"bytes,1,opt,name=output,proto3" json:"output,omitempty"`
+	Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *ProvisionResource_Response) Reset() {
+	*x = ProvisionResource_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin5_proto_msgTypes[58]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ProvisionResource_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProvisionResource_Response) ProtoMessage() {}
+
+func (x *ProvisionResource_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin5_proto_msgTypes[58]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ProvisionResource_Response.ProtoReflect.Descriptor instead.
+func (*ProvisionResource_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin5_proto_rawDescGZIP(), []int{19, 1}
+}
+
+func (x *ProvisionResource_Response) GetOutput() string {
+	if x != nil {
+		return x.Output
+	}
+	return ""
+}
+
+func (x *ProvisionResource_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+var File_tfplugin5_proto protoreflect.FileDescriptor
+
+var file_tfplugin5_proto_rawDesc = []byte{
+	0x0a, 0x0f, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x12, 0x09, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x22, 0x3c, 0x0a, 0x0c,
+	0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07,
+	0x6d, 0x73, 0x67, 0x70, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d,
+	0x73, 0x67, 0x70, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x22, 0xe3, 0x01, 0x0a, 0x0a, 0x44,
+	0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x12, 0x3a, 0x0a, 0x08, 0x73, 0x65, 0x76,
+	0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, 0x66,
+	0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74,
+	0x69, 0x63, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x76,
+	0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12,
+	0x16, 0x0a, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x36, 0x0a, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69,
+	0x62, 0x75, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
+	0x50, 0x61, 0x74, 0x68, 0x52, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x22,
+	0x2f, 0x0a, 0x08, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0b, 0x0a, 0x07, 0x49,
+	0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f,
+	0x52, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x02,
+	0x22, 0xdc, 0x01, 0x0a, 0x0d, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x50, 0x61,
+	0x74, 0x68, 0x12, 0x33, 0x0a, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x41, 0x74,
+	0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x2e, 0x53, 0x74, 0x65, 0x70,
+	0x52, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x1a, 0x95, 0x01, 0x0a, 0x04, 0x53, 0x74, 0x65, 0x70,
+	0x12, 0x27, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x6e, 0x61,
+	0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72,
+	0x69, 0x62, 0x75, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x65, 0x6c, 0x65,
+	0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74,
+	0x4b, 0x65, 0x79, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x28, 0x0a, 0x0f, 0x65, 0x6c, 0x65,
+	0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x03, 0x48, 0x00, 0x52, 0x0d, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79,
+	0x49, 0x6e, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22,
+	0x33, 0x0a, 0x04, 0x53, 0x74, 0x6f, 0x70, 0x1a, 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x20, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14,
+	0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x45,
+	0x72, 0x72, 0x6f, 0x72, 0x22, 0x96, 0x01, 0x0a, 0x08, 0x52, 0x61, 0x77, 0x53, 0x74, 0x61, 0x74,
+	0x65, 0x12, 0x12, 0x0a, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
+	0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x07, 0x66, 0x6c, 0x61, 0x74, 0x6d, 0x61, 0x70,
+	0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69,
+	0x6e, 0x35, 0x2e, 0x52, 0x61, 0x77, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x46, 0x6c, 0x61, 0x74,
+	0x6d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x66, 0x6c, 0x61, 0x74, 0x6d, 0x61,
+	0x70, 0x1a, 0x3a, 0x0a, 0x0c, 0x46, 0x6c, 0x61, 0x74, 0x6d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72,
+	0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+	0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xcc, 0x07,
+	0x0a, 0x06, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73,
+	0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
+	0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x53, 0x63,
+	0x68, 0x65, 0x6d, 0x61, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63,
+	0x6b, 0x1a, 0xa2, 0x02, 0x0a, 0x05, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x76,
+	0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65,
+	0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
+	0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x66, 0x70, 0x6c,
+	0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x41, 0x74, 0x74,
+	0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
+	0x65, 0x73, 0x12, 0x3e, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x79, 0x70, 0x65,
+	0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67,
+	0x69, 0x6e, 0x35, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65,
+	0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x79, 0x70,
+	0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x10, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15,
+	0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e,
+	0x67, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63,
+	0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72,
+	0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x1a, 0xa9, 0x02, 0x0a, 0x09, 0x41, 0x74, 0x74, 0x72, 0x69,
+	0x62, 0x75, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b,
+	0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a,
+	0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08,
+	0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6f, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74,
+	0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74,
+	0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18,
+	0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65,
+	0x12, 0x40, 0x0a, 0x10, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
+	0x6b, 0x69, 0x6e, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4b, 0x69, 0x6e,
+	0x64, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x69,
+	0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64,
+	0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74,
+	0x65, 0x64, 0x1a, 0xa7, 0x02, 0x0a, 0x0b, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f,
+	0x63, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12,
+	0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17,
+	0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d,
+	0x61, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x43,
+	0x0a, 0x07, 0x6e, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,
+	0x29, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x61, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x4e,
+	0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x07, 0x6e, 0x65, 0x73, 0x74,
+	0x69, 0x6e, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73,
+	0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x4d, 0x0a,
+	0x0b, 0x4e, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07,
+	0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x49, 0x4e,
+	0x47, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x02, 0x12,
+	0x07, 0x0a, 0x03, 0x53, 0x45, 0x54, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x41, 0x50, 0x10,
+	0x04, 0x12, 0x09, 0x0a, 0x05, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x10, 0x05, 0x22, 0xeb, 0x05, 0x0a,
+	0x11, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x61, 0x1a, 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x91, 0x05,
+	0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x08, 0x70, 0x72,
+	0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74,
+	0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52,
+	0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x65, 0x0a, 0x10, 0x72, 0x65, 0x73,
+	0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x02, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e,
+	0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d,
+	0x61, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75,
+	0x72, 0x63, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
+	0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73,
+	0x12, 0x6c, 0x0a, 0x13, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f,
+	0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3c, 0x2e,
+	0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f,
+	0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53,
+	0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x64, 0x61, 0x74,
+	0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x12, 0x37,
+	0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x04, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e,
+	0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67,
+	0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x36, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69,
+	0x64, 0x65, 0x72, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11,
+	0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d,
+	0x61, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x12,
+	0x60, 0x0a, 0x13, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69,
+	0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74,
+	0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76,
+	0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65,
+	0x72, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x12, 0x73,
+	0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65,
+	0x73, 0x1a, 0x55, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x63, 0x68,
+	0x65, 0x6d, 0x61, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x05, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x05, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x57, 0x0a, 0x16, 0x44, 0x61, 0x74, 0x61,
+	0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x45, 0x6e, 0x74,
+	0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x03, 0x6b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e,
+	0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
+	0x01, 0x1a, 0x37, 0x0a, 0x12, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x61, 0x70, 0x61, 0x62,
+	0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x6c, 0x61, 0x6e, 0x5f,
+	0x64, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x70,
+	0x6c, 0x61, 0x6e, 0x44, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x79, 0x22, 0xdb, 0x01, 0x0a, 0x15, 0x50,
+	0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f,
+	0x6e, 0x66, 0x69, 0x67, 0x1a, 0x3a, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+	0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61,
+	0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+	0x1a, 0x85, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a,
+	0x0f, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69,
+	0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52,
+	0x0e, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
+	0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x02,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35,
+	0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61,
+	0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x22, 0x90, 0x02, 0x0a, 0x14, 0x55, 0x70, 0x67,
+	0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74,
+	0x65, 0x1a, 0x72, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09,
+	0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72,
+	0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73,
+	0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x09, 0x72, 0x61, 0x77, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69,
+	0x6e, 0x35, 0x2e, 0x52, 0x61, 0x77, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x08, 0x72, 0x61, 0x77,
+	0x53, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x83, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0e, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x5f, 0x73,
+	0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61,
+	0x6c, 0x75, 0x65, 0x52, 0x0d, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x53, 0x74, 0x61,
+	0x74, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63,
+	0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67,
+	0x69, 0x6e, 0x35, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b,
+	0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x22, 0xba, 0x01, 0x0a, 0x1a,
+	0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+	0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x57, 0x0a, 0x07, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61,
+	0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61,
+	0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44,
+	0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x1a, 0x43, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+	0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x01,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35,
+	0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61,
+	0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x22, 0xb8, 0x01, 0x0a, 0x18, 0x56, 0x61, 0x6c,
+	0x69, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43,
+	0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x57, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a,
+	0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
+	0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69,
+	0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x43,
+	0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69,
+	0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x69, 0x61, 0x67,
+	0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74,
+	0x69, 0x63, 0x73, 0x22, 0xb9, 0x01, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72,
+	0x65, 0x1a, 0x67, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x11,
+	0x74, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
+	0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x74, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f,
+	0x72, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c,
+	0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c,
+	0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x43, 0x0a, 0x08, 0x52, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f,
+	0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66,
+	0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74,
+	0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x22,
+	0xe3, 0x02, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+	0x1a, 0xbc, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09,
+	0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x0d, 0x63, 0x75, 0x72,
+	0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e,
+	0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65,
+	0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61,
+	0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74,
+	0x65, 0x12, 0x3c, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x6d, 0x65,
+	0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75,
+	0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75,
+	0x65, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x1a,
+	0x93, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x09,
+	0x6e, 0x65, 0x77, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61,
+	0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6e, 0x65, 0x77, 0x53, 0x74, 0x61,
+	0x74, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63,
+	0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67,
+	0x69, 0x6e, 0x35, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b,
+	0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70,
+	0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x72,
+	0x69, 0x76, 0x61, 0x74, 0x65, 0x22, 0xf2, 0x04, 0x0a, 0x12, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x65,
+	0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x1a, 0xbb, 0x02, 0x0a,
+	0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65,
+	0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70,
+	0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x5f, 0x73,
+	0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61,
+	0x6c, 0x75, 0x65, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12,
+	0x45, 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x5f, 0x6e, 0x65, 0x77, 0x5f,
+	0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66,
+	0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56,
+	0x61, 0x6c, 0x75, 0x65, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x4e, 0x65,
+	0x77, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69,
+	0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52,
+	0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x69, 0x6f, 0x72,
+	0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c,
+	0x70, 0x72, 0x69, 0x6f, 0x72, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x0d,
+	0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x06, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e,
+	0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x70, 0x72,
+	0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x1a, 0x9d, 0x02, 0x0a, 0x08, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x0d, 0x70, 0x6c, 0x61, 0x6e, 0x6e,
+	0x65, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17,
+	0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d,
+	0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64,
+	0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x43, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65,
+	0x73, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x18, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x41, 0x74, 0x74, 0x72,
+	0x69, 0x62, 0x75, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x52, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x69,
+	0x72, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x6c,
+	0x61, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x0c, 0x52, 0x0e, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x50, 0x72, 0x69, 0x76,
+	0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69,
+	0x63, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75,
+	0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52,
+	0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x2c, 0x0a, 0x12,
+	0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74,
+	0x65, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79,
+	0x54, 0x79, 0x70, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x22, 0x92, 0x04, 0x0a, 0x13, 0x41,
+	0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e,
+	0x67, 0x65, 0x1a, 0xb6, 0x02, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b,
+	0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x70,
+	0x72, 0x69, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e,
+	0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6f, 0x72,
+	0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x0d, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64,
+	0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74,
+	0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63,
+	0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x53, 0x74,
+	0x61, 0x74, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e,
+	0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f,
+	0x6e, 0x66, 0x69, 0x67, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x5f,
+	0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x70,
+	0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a,
+	0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35,
+	0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x70,
+	0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x1a, 0xc1, 0x01, 0x0a, 0x08,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x5f,
+	0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66,
+	0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56,
+	0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6e, 0x65, 0x77, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18,
+	0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
+	0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67,
+	0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e,
+	0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f,
+	0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63,
+	0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65,
+	0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x6c,
+	0x65, 0x67, 0x61, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x22,
+	0xed, 0x02, 0x0a, 0x13, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
+	0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x36, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12,
+	0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x1a,
+	0x78, 0x0a, 0x10, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75,
+	0x72, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65,
+	0x12, 0x2d, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61,
+	0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12,
+	0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c,
+	0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x1a, 0xa3, 0x01, 0x0a, 0x08, 0x52, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x12, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74,
+	0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x49,
+	0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61,
+	0x74, 0x65, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75,
+	0x72, 0x63, 0x65, 0x52, 0x11, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73,
+	0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f,
+	0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66,
+	0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74,
+	0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x22,
+	0x9c, 0x02, 0x0a, 0x0e, 0x52, 0x65, 0x61, 0x64, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72,
+	0x63, 0x65, 0x1a, 0x95, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b,
+	0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63,
+	0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66,
+	0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56,
+	0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x0d,
+	0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e,
+	0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x70, 0x72,
+	0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x1a, 0x72, 0x0a, 0x08, 0x52, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
+	0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05,
+	0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73,
+	0x74, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69,
+	0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x22, 0x9b,
+	0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65,
+	0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x1a, 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x78, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33,
+	0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e,
+	0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f,
+	0x6e, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69,
+	0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75,
+	0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52,
+	0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x22, 0x9c, 0x01, 0x0a,
+	0x19, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69,
+	0x6f, 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x3a, 0x0a, 0x07, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
+	0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06,
+	0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x43, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63,
+	0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67,
+	0x69, 0x6e, 0x35, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b,
+	0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x11,
+	0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+	0x65, 0x1a, 0x73, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x06,
+	0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74,
+	0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63,
+	0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x37, 0x0a,
+	0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x79,
+	0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e,
+	0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x5b, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69,
+	0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x44, 0x69, 0x61, 0x67,
+	0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74,
+	0x69, 0x63, 0x73, 0x2a, 0x25, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4b, 0x69, 0x6e,
+	0x64, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08,
+	0x4d, 0x41, 0x52, 0x4b, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x01, 0x32, 0x97, 0x09, 0x0a, 0x08, 0x50,
+	0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x58, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x63,
+	0x68, 0x65, 0x6d, 0x61, 0x12, 0x24, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35,
+	0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x61, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64,
+	0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x12, 0x6c, 0x0a, 0x15, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x76,
+	0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x28, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x50, 0x72,
+	0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35,
+	0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
+	0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+	0x7b, 0x0a, 0x1a, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75,
+	0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x2e,
+	0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61,
+	0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f,
+	0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74,
+	0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74,
+	0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, 0x18,
+	0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72,
+	0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2b, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75,
+	0x67, 0x69, 0x6e, 0x35, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74,
+	0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
+	0x35, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f,
+	0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x14, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65,
+	0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x27, 0x2e, 0x74, 0x66,
+	0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52,
+	0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35,
+	0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+	0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48,
+	0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x12, 0x1c, 0x2e, 0x74, 0x66,
+	0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72,
+	0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x74, 0x66, 0x70, 0x6c,
+	0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x2e,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64,
+	0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1f, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75,
+	0x67, 0x69, 0x6e, 0x35, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+	0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x74, 0x66, 0x70, 0x6c,
+	0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
+	0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x12, 0x50,
+	0x6c, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67,
+	0x65, 0x12, 0x25, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x50, 0x6c,
+	0x61, 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65,
+	0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75,
+	0x67, 0x69, 0x6e, 0x35, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+	0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x12, 0x66, 0x0a, 0x13, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+	0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x26, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67,
+	0x69, 0x6e, 0x35, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+	0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x27, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x41, 0x70, 0x70, 0x6c,
+	0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x13, 0x49, 0x6d, 0x70, 0x6f,
+	0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12,
+	0x26, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x49, 0x6d, 0x70, 0x6f,
+	0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67,
+	0x69, 0x6e, 0x35, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
+	0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x12, 0x57, 0x0a, 0x0e, 0x52, 0x65, 0x61, 0x64, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72,
+	0x63, 0x65, 0x12, 0x21, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x52,
+	0x65, 0x61, 0x64, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
+	0x35, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65,
+	0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x04, 0x53, 0x74, 0x6f,
+	0x70, 0x12, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x53, 0x74,
+	0x6f, 0x70, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x2e, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x32, 0x86, 0x03, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69,
+	0x6f, 0x6e, 0x65, 0x72, 0x12, 0x5e, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d,
+	0x61, 0x12, 0x27, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x47, 0x65,
+	0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x61, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73,
+	0x69, 0x6f, 0x6e, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x19, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65,
+	0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+	0x67, 0x12, 0x2c, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x56, 0x61,
+	0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65,
+	0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x2d, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x56, 0x61, 0x6c, 0x69,
+	0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x43,
+	0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62,
+	0x0a, 0x11, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75,
+	0x72, 0x63, 0x65, 0x12, 0x24, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e,
+	0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+	0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x74, 0x66, 0x70, 0x6c,
+	0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52,
+	0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x30, 0x01, 0x12, 0x39, 0x0a, 0x04, 0x53, 0x74, 0x6f, 0x70, 0x12, 0x17, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x2e, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x35, 0x2e,
+	0x53, 0x74, 0x6f, 0x70, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a,
+	0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68,
+	0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x74, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x2f,
+	0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69,
+	0x6e, 0x35, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_tfplugin5_proto_rawDescOnce sync.Once
+	file_tfplugin5_proto_rawDescData = file_tfplugin5_proto_rawDesc
+)
+
+func file_tfplugin5_proto_rawDescGZIP() []byte {
+	file_tfplugin5_proto_rawDescOnce.Do(func() {
+		file_tfplugin5_proto_rawDescData = protoimpl.X.CompressGZIP(file_tfplugin5_proto_rawDescData)
+	})
+	return file_tfplugin5_proto_rawDescData
+}
+
+var file_tfplugin5_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
+var file_tfplugin5_proto_msgTypes = make([]protoimpl.MessageInfo, 59)
+var file_tfplugin5_proto_goTypes = []interface{}{
+	(StringKind)(0),                              // 0: tfplugin5.StringKind
+	(Diagnostic_Severity)(0),                     // 1: tfplugin5.Diagnostic.Severity
+	(Schema_NestedBlock_NestingMode)(0),          // 2: tfplugin5.Schema.NestedBlock.NestingMode
+	(*DynamicValue)(nil),                         // 3: tfplugin5.DynamicValue
+	(*Diagnostic)(nil),                           // 4: tfplugin5.Diagnostic
+	(*AttributePath)(nil),                        // 5: tfplugin5.AttributePath
+	(*Stop)(nil),                                 // 6: tfplugin5.Stop
+	(*RawState)(nil),                             // 7: tfplugin5.RawState
+	(*Schema)(nil),                               // 8: tfplugin5.Schema
+	(*GetProviderSchema)(nil),                    // 9: tfplugin5.GetProviderSchema
+	(*PrepareProviderConfig)(nil),                // 10: tfplugin5.PrepareProviderConfig
+	(*UpgradeResourceState)(nil),                 // 11: tfplugin5.UpgradeResourceState
+	(*ValidateResourceTypeConfig)(nil),           // 12: tfplugin5.ValidateResourceTypeConfig
+	(*ValidateDataSourceConfig)(nil),             // 13: tfplugin5.ValidateDataSourceConfig
+	(*Configure)(nil),                            // 14: tfplugin5.Configure
+	(*ReadResource)(nil),                         // 15: tfplugin5.ReadResource
+	(*PlanResourceChange)(nil),                   // 16: tfplugin5.PlanResourceChange
+	(*ApplyResourceChange)(nil),                  // 17: tfplugin5.ApplyResourceChange
+	(*ImportResourceState)(nil),                  // 18: tfplugin5.ImportResourceState
+	(*ReadDataSource)(nil),                       // 19: tfplugin5.ReadDataSource
+	(*GetProvisionerSchema)(nil),                 // 20: tfplugin5.GetProvisionerSchema
+	(*ValidateProvisionerConfig)(nil),            // 21: tfplugin5.ValidateProvisionerConfig
+	(*ProvisionResource)(nil),                    // 22: tfplugin5.ProvisionResource
+	(*AttributePath_Step)(nil),                   // 23: tfplugin5.AttributePath.Step
+	(*Stop_Request)(nil),                         // 24: tfplugin5.Stop.Request
+	(*Stop_Response)(nil),                        // 25: tfplugin5.Stop.Response
+	nil,                                          // 26: tfplugin5.RawState.FlatmapEntry
+	(*Schema_Block)(nil),                         // 27: tfplugin5.Schema.Block
+	(*Schema_Attribute)(nil),                     // 28: tfplugin5.Schema.Attribute
+	(*Schema_NestedBlock)(nil),                   // 29: tfplugin5.Schema.NestedBlock
+	(*GetProviderSchema_Request)(nil),            // 30: tfplugin5.GetProviderSchema.Request
+	(*GetProviderSchema_Response)(nil),           // 31: tfplugin5.GetProviderSchema.Response
+	(*GetProviderSchema_ServerCapabilities)(nil), // 32: tfplugin5.GetProviderSchema.ServerCapabilities
+	nil,                                    // 33: tfplugin5.GetProviderSchema.Response.ResourceSchemasEntry
+	nil,                                    // 34: tfplugin5.GetProviderSchema.Response.DataSourceSchemasEntry
+	(*PrepareProviderConfig_Request)(nil),  // 35: tfplugin5.PrepareProviderConfig.Request
+	(*PrepareProviderConfig_Response)(nil), // 36: tfplugin5.PrepareProviderConfig.Response
+	(*UpgradeResourceState_Request)(nil),   // 37: tfplugin5.UpgradeResourceState.Request
+	(*UpgradeResourceState_Response)(nil),  // 38: tfplugin5.UpgradeResourceState.Response
+	(*ValidateResourceTypeConfig_Request)(nil),   // 39: tfplugin5.ValidateResourceTypeConfig.Request
+	(*ValidateResourceTypeConfig_Response)(nil),  // 40: tfplugin5.ValidateResourceTypeConfig.Response
+	(*ValidateDataSourceConfig_Request)(nil),     // 41: tfplugin5.ValidateDataSourceConfig.Request
+	(*ValidateDataSourceConfig_Response)(nil),    // 42: tfplugin5.ValidateDataSourceConfig.Response
+	(*Configure_Request)(nil),                    // 43: tfplugin5.Configure.Request
+	(*Configure_Response)(nil),                   // 44: tfplugin5.Configure.Response
+	(*ReadResource_Request)(nil),                 // 45: tfplugin5.ReadResource.Request
+	(*ReadResource_Response)(nil),                // 46: tfplugin5.ReadResource.Response
+	(*PlanResourceChange_Request)(nil),           // 47: tfplugin5.PlanResourceChange.Request
+	(*PlanResourceChange_Response)(nil),          // 48: tfplugin5.PlanResourceChange.Response
+	(*ApplyResourceChange_Request)(nil),          // 49: tfplugin5.ApplyResourceChange.Request
+	(*ApplyResourceChange_Response)(nil),         // 50: tfplugin5.ApplyResourceChange.Response
+	(*ImportResourceState_Request)(nil),          // 51: tfplugin5.ImportResourceState.Request
+	(*ImportResourceState_ImportedResource)(nil), // 52: tfplugin5.ImportResourceState.ImportedResource
+	(*ImportResourceState_Response)(nil),         // 53: tfplugin5.ImportResourceState.Response
+	(*ReadDataSource_Request)(nil),               // 54: tfplugin5.ReadDataSource.Request
+	(*ReadDataSource_Response)(nil),              // 55: tfplugin5.ReadDataSource.Response
+	(*GetProvisionerSchema_Request)(nil),         // 56: tfplugin5.GetProvisionerSchema.Request
+	(*GetProvisionerSchema_Response)(nil),        // 57: tfplugin5.GetProvisionerSchema.Response
+	(*ValidateProvisionerConfig_Request)(nil),    // 58: tfplugin5.ValidateProvisionerConfig.Request
+	(*ValidateProvisionerConfig_Response)(nil),   // 59: tfplugin5.ValidateProvisionerConfig.Response
+	(*ProvisionResource_Request)(nil),            // 60: tfplugin5.ProvisionResource.Request
+	(*ProvisionResource_Response)(nil),           // 61: tfplugin5.ProvisionResource.Response
+}
+var file_tfplugin5_proto_depIdxs = []int32{
+	1,  // 0: tfplugin5.Diagnostic.severity:type_name -> tfplugin5.Diagnostic.Severity
+	5,  // 1: tfplugin5.Diagnostic.attribute:type_name -> tfplugin5.AttributePath
+	23, // 2: tfplugin5.AttributePath.steps:type_name -> tfplugin5.AttributePath.Step
+	26, // 3: tfplugin5.RawState.flatmap:type_name -> tfplugin5.RawState.FlatmapEntry
+	27, // 4: tfplugin5.Schema.block:type_name -> tfplugin5.Schema.Block
+	28, // 5: tfplugin5.Schema.Block.attributes:type_name -> tfplugin5.Schema.Attribute
+	29, // 6: tfplugin5.Schema.Block.block_types:type_name -> tfplugin5.Schema.NestedBlock
+	0,  // 7: tfplugin5.Schema.Block.description_kind:type_name -> tfplugin5.StringKind
+	0,  // 8: tfplugin5.Schema.Attribute.description_kind:type_name -> tfplugin5.StringKind
+	27, // 9: tfplugin5.Schema.NestedBlock.block:type_name -> tfplugin5.Schema.Block
+	2,  // 10: tfplugin5.Schema.NestedBlock.nesting:type_name -> tfplugin5.Schema.NestedBlock.NestingMode
+	8,  // 11: tfplugin5.GetProviderSchema.Response.provider:type_name -> tfplugin5.Schema
+	33, // 12: tfplugin5.GetProviderSchema.Response.resource_schemas:type_name -> tfplugin5.GetProviderSchema.Response.ResourceSchemasEntry
+	34, // 13: tfplugin5.GetProviderSchema.Response.data_source_schemas:type_name -> tfplugin5.GetProviderSchema.Response.DataSourceSchemasEntry
+	4,  // 14: tfplugin5.GetProviderSchema.Response.diagnostics:type_name -> tfplugin5.Diagnostic
+	8,  // 15: tfplugin5.GetProviderSchema.Response.provider_meta:type_name -> tfplugin5.Schema
+	32, // 16: tfplugin5.GetProviderSchema.Response.server_capabilities:type_name -> tfplugin5.GetProviderSchema.ServerCapabilities
+	8,  // 17: tfplugin5.GetProviderSchema.Response.ResourceSchemasEntry.value:type_name -> tfplugin5.Schema
+	8,  // 18: tfplugin5.GetProviderSchema.Response.DataSourceSchemasEntry.value:type_name -> tfplugin5.Schema
+	3,  // 19: tfplugin5.PrepareProviderConfig.Request.config:type_name -> tfplugin5.DynamicValue
+	3,  // 20: tfplugin5.PrepareProviderConfig.Response.prepared_config:type_name -> tfplugin5.DynamicValue
+	4,  // 21: tfplugin5.PrepareProviderConfig.Response.diagnostics:type_name -> tfplugin5.Diagnostic
+	7,  // 22: tfplugin5.UpgradeResourceState.Request.raw_state:type_name -> tfplugin5.RawState
+	3,  // 23: tfplugin5.UpgradeResourceState.Response.upgraded_state:type_name -> tfplugin5.DynamicValue
+	4,  // 24: tfplugin5.UpgradeResourceState.Response.diagnostics:type_name -> tfplugin5.Diagnostic
+	3,  // 25: tfplugin5.ValidateResourceTypeConfig.Request.config:type_name -> tfplugin5.DynamicValue
+	4,  // 26: tfplugin5.ValidateResourceTypeConfig.Response.diagnostics:type_name -> tfplugin5.Diagnostic
+	3,  // 27: tfplugin5.ValidateDataSourceConfig.Request.config:type_name -> tfplugin5.DynamicValue
+	4,  // 28: tfplugin5.ValidateDataSourceConfig.Response.diagnostics:type_name -> tfplugin5.Diagnostic
+	3,  // 29: tfplugin5.Configure.Request.config:type_name -> tfplugin5.DynamicValue
+	4,  // 30: tfplugin5.Configure.Response.diagnostics:type_name -> tfplugin5.Diagnostic
+	3,  // 31: tfplugin5.ReadResource.Request.current_state:type_name -> tfplugin5.DynamicValue
+	3,  // 32: tfplugin5.ReadResource.Request.provider_meta:type_name -> tfplugin5.DynamicValue
+	3,  // 33: tfplugin5.ReadResource.Response.new_state:type_name -> tfplugin5.DynamicValue
+	4,  // 34: tfplugin5.ReadResource.Response.diagnostics:type_name -> tfplugin5.Diagnostic
+	3,  // 35: tfplugin5.PlanResourceChange.Request.prior_state:type_name -> tfplugin5.DynamicValue
+	3,  // 36: tfplugin5.PlanResourceChange.Request.proposed_new_state:type_name -> tfplugin5.DynamicValue
+	3,  // 37: tfplugin5.PlanResourceChange.Request.config:type_name -> tfplugin5.DynamicValue
+	3,  // 38: tfplugin5.PlanResourceChange.Request.provider_meta:type_name -> tfplugin5.DynamicValue
+	3,  // 39: tfplugin5.PlanResourceChange.Response.planned_state:type_name -> tfplugin5.DynamicValue
+	5,  // 40: tfplugin5.PlanResourceChange.Response.requires_replace:type_name -> tfplugin5.AttributePath
+	4,  // 41: tfplugin5.PlanResourceChange.Response.diagnostics:type_name -> tfplugin5.Diagnostic
+	3,  // 42: tfplugin5.ApplyResourceChange.Request.prior_state:type_name -> tfplugin5.DynamicValue
+	3,  // 43: tfplugin5.ApplyResourceChange.Request.planned_state:type_name -> tfplugin5.DynamicValue
+	3,  // 44: tfplugin5.ApplyResourceChange.Request.config:type_name -> tfplugin5.DynamicValue
+	3,  // 45: tfplugin5.ApplyResourceChange.Request.provider_meta:type_name -> tfplugin5.DynamicValue
+	3,  // 46: tfplugin5.ApplyResourceChange.Response.new_state:type_name -> tfplugin5.DynamicValue
+	4,  // 47: tfplugin5.ApplyResourceChange.Response.diagnostics:type_name -> tfplugin5.Diagnostic
+	3,  // 48: tfplugin5.ImportResourceState.ImportedResource.state:type_name -> tfplugin5.DynamicValue
+	52, // 49: tfplugin5.ImportResourceState.Response.imported_resources:type_name -> tfplugin5.ImportResourceState.ImportedResource
+	4,  // 50: tfplugin5.ImportResourceState.Response.diagnostics:type_name -> tfplugin5.Diagnostic
+	3,  // 51: tfplugin5.ReadDataSource.Request.config:type_name -> tfplugin5.DynamicValue
+	3,  // 52: tfplugin5.ReadDataSource.Request.provider_meta:type_name -> tfplugin5.DynamicValue
+	3,  // 53: tfplugin5.ReadDataSource.Response.state:type_name -> tfplugin5.DynamicValue
+	4,  // 54: tfplugin5.ReadDataSource.Response.diagnostics:type_name -> tfplugin5.Diagnostic
+	8,  // 55: tfplugin5.GetProvisionerSchema.Response.provisioner:type_name -> tfplugin5.Schema
+	4,  // 56: tfplugin5.GetProvisionerSchema.Response.diagnostics:type_name -> tfplugin5.Diagnostic
+	3,  // 57: tfplugin5.ValidateProvisionerConfig.Request.config:type_name -> tfplugin5.DynamicValue
+	4,  // 58: tfplugin5.ValidateProvisionerConfig.Response.diagnostics:type_name -> tfplugin5.Diagnostic
+	3,  // 59: tfplugin5.ProvisionResource.Request.config:type_name -> tfplugin5.DynamicValue
+	3,  // 60: tfplugin5.ProvisionResource.Request.connection:type_name -> tfplugin5.DynamicValue
+	4,  // 61: tfplugin5.ProvisionResource.Response.diagnostics:type_name -> tfplugin5.Diagnostic
+	30, // 62: tfplugin5.Provider.GetSchema:input_type -> tfplugin5.GetProviderSchema.Request
+	35, // 63: tfplugin5.Provider.PrepareProviderConfig:input_type -> tfplugin5.PrepareProviderConfig.Request
+	39, // 64: tfplugin5.Provider.ValidateResourceTypeConfig:input_type -> tfplugin5.ValidateResourceTypeConfig.Request
+	41, // 65: tfplugin5.Provider.ValidateDataSourceConfig:input_type -> tfplugin5.ValidateDataSourceConfig.Request
+	37, // 66: tfplugin5.Provider.UpgradeResourceState:input_type -> tfplugin5.UpgradeResourceState.Request
+	43, // 67: tfplugin5.Provider.Configure:input_type -> tfplugin5.Configure.Request
+	45, // 68: tfplugin5.Provider.ReadResource:input_type -> tfplugin5.ReadResource.Request
+	47, // 69: tfplugin5.Provider.PlanResourceChange:input_type -> tfplugin5.PlanResourceChange.Request
+	49, // 70: tfplugin5.Provider.ApplyResourceChange:input_type -> tfplugin5.ApplyResourceChange.Request
+	51, // 71: tfplugin5.Provider.ImportResourceState:input_type -> tfplugin5.ImportResourceState.Request
+	54, // 72: tfplugin5.Provider.ReadDataSource:input_type -> tfplugin5.ReadDataSource.Request
+	24, // 73: tfplugin5.Provider.Stop:input_type -> tfplugin5.Stop.Request
+	56, // 74: tfplugin5.Provisioner.GetSchema:input_type -> tfplugin5.GetProvisionerSchema.Request
+	58, // 75: tfplugin5.Provisioner.ValidateProvisionerConfig:input_type -> tfplugin5.ValidateProvisionerConfig.Request
+	60, // 76: tfplugin5.Provisioner.ProvisionResource:input_type -> tfplugin5.ProvisionResource.Request
+	24, // 77: tfplugin5.Provisioner.Stop:input_type -> tfplugin5.Stop.Request
+	31, // 78: tfplugin5.Provider.GetSchema:output_type -> tfplugin5.GetProviderSchema.Response
+	36, // 79: tfplugin5.Provider.PrepareProviderConfig:output_type -> tfplugin5.PrepareProviderConfig.Response
+	40, // 80: tfplugin5.Provider.ValidateResourceTypeConfig:output_type -> tfplugin5.ValidateResourceTypeConfig.Response
+	42, // 81: tfplugin5.Provider.ValidateDataSourceConfig:output_type -> tfplugin5.ValidateDataSourceConfig.Response
+	38, // 82: tfplugin5.Provider.UpgradeResourceState:output_type -> tfplugin5.UpgradeResourceState.Response
+	44, // 83: tfplugin5.Provider.Configure:output_type -> tfplugin5.Configure.Response
+	46, // 84: tfplugin5.Provider.ReadResource:output_type -> tfplugin5.ReadResource.Response
+	48, // 85: tfplugin5.Provider.PlanResourceChange:output_type -> tfplugin5.PlanResourceChange.Response
+	50, // 86: tfplugin5.Provider.ApplyResourceChange:output_type -> tfplugin5.ApplyResourceChange.Response
+	53, // 87: tfplugin5.Provider.ImportResourceState:output_type -> tfplugin5.ImportResourceState.Response
+	55, // 88: tfplugin5.Provider.ReadDataSource:output_type -> tfplugin5.ReadDataSource.Response
+	25, // 89: tfplugin5.Provider.Stop:output_type -> tfplugin5.Stop.Response
+	57, // 90: tfplugin5.Provisioner.GetSchema:output_type -> tfplugin5.GetProvisionerSchema.Response
+	59, // 91: tfplugin5.Provisioner.ValidateProvisionerConfig:output_type -> tfplugin5.ValidateProvisionerConfig.Response
+	61, // 92: tfplugin5.Provisioner.ProvisionResource:output_type -> tfplugin5.ProvisionResource.Response
+	25, // 93: tfplugin5.Provisioner.Stop:output_type -> tfplugin5.Stop.Response
+	78, // [78:94] is the sub-list for method output_type
+	62, // [62:78] is the sub-list for method input_type
+	62, // [62:62] is the sub-list for extension type_name
+	62, // [62:62] is the sub-list for extension extendee
+	0,  // [0:62] is the sub-list for field type_name
+}
+
+func init() { file_tfplugin5_proto_init() }
+func file_tfplugin5_proto_init() {
+	if File_tfplugin5_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_tfplugin5_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DynamicValue); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Diagnostic); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*AttributePath); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Stop); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*RawState); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Schema); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetProviderSchema); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*PrepareProviderConfig); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UpgradeResourceState); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateResourceTypeConfig); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateDataSourceConfig); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Configure); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReadResource); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*PlanResourceChange); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ApplyResourceChange); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ImportResourceState); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReadDataSource); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetProvisionerSchema); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateProvisionerConfig); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ProvisionResource); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*AttributePath_Step); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Stop_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Stop_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Schema_Block); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Schema_Attribute); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Schema_NestedBlock); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetProviderSchema_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetProviderSchema_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetProviderSchema_ServerCapabilities); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*PrepareProviderConfig_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*PrepareProviderConfig_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UpgradeResourceState_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UpgradeResourceState_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateResourceTypeConfig_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateResourceTypeConfig_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateDataSourceConfig_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateDataSourceConfig_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Configure_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Configure_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReadResource_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReadResource_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*PlanResourceChange_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*PlanResourceChange_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ApplyResourceChange_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ApplyResourceChange_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ImportResourceState_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ImportResourceState_ImportedResource); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ImportResourceState_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReadDataSource_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReadDataSource_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetProvisionerSchema_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetProvisionerSchema_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateProvisionerConfig_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateProvisionerConfig_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ProvisionResource_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin5_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ProvisionResource_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	file_tfplugin5_proto_msgTypes[20].OneofWrappers = []interface{}{
+		(*AttributePath_Step_AttributeName)(nil),
+		(*AttributePath_Step_ElementKeyString)(nil),
+		(*AttributePath_Step_ElementKeyInt)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_tfplugin5_proto_rawDesc,
+			NumEnums:      3,
+			NumMessages:   59,
+			NumExtensions: 0,
+			NumServices:   2,
+		},
+		GoTypes:           file_tfplugin5_proto_goTypes,
+		DependencyIndexes: file_tfplugin5_proto_depIdxs,
+		EnumInfos:         file_tfplugin5_proto_enumTypes,
+		MessageInfos:      file_tfplugin5_proto_msgTypes,
+	}.Build()
+	File_tfplugin5_proto = out.File
+	file_tfplugin5_proto_rawDesc = nil
+	file_tfplugin5_proto_goTypes = nil
+	file_tfplugin5_proto_depIdxs = nil
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConnInterface
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion6
+
+// ProviderClient is the client API for Provider service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type ProviderClient interface {
+	// ////// Information about what a provider supports/expects
+	GetSchema(ctx context.Context, in *GetProviderSchema_Request, opts ...grpc.CallOption) (*GetProviderSchema_Response, error)
+	PrepareProviderConfig(ctx context.Context, in *PrepareProviderConfig_Request, opts ...grpc.CallOption) (*PrepareProviderConfig_Response, error)
+	ValidateResourceTypeConfig(ctx context.Context, in *ValidateResourceTypeConfig_Request, opts ...grpc.CallOption) (*ValidateResourceTypeConfig_Response, error)
+	ValidateDataSourceConfig(ctx context.Context, in *ValidateDataSourceConfig_Request, opts ...grpc.CallOption) (*ValidateDataSourceConfig_Response, error)
+	UpgradeResourceState(ctx context.Context, in *UpgradeResourceState_Request, opts ...grpc.CallOption) (*UpgradeResourceState_Response, error)
+	// ////// One-time initialization, called before other functions below
+	Configure(ctx context.Context, in *Configure_Request, opts ...grpc.CallOption) (*Configure_Response, error)
+	// ////// Managed Resource Lifecycle
+	ReadResource(ctx context.Context, in *ReadResource_Request, opts ...grpc.CallOption) (*ReadResource_Response, error)
+	PlanResourceChange(ctx context.Context, in *PlanResourceChange_Request, opts ...grpc.CallOption) (*PlanResourceChange_Response, error)
+	ApplyResourceChange(ctx context.Context, in *ApplyResourceChange_Request, opts ...grpc.CallOption) (*ApplyResourceChange_Response, error)
+	ImportResourceState(ctx context.Context, in *ImportResourceState_Request, opts ...grpc.CallOption) (*ImportResourceState_Response, error)
+	ReadDataSource(ctx context.Context, in *ReadDataSource_Request, opts ...grpc.CallOption) (*ReadDataSource_Response, error)
+	// ////// Graceful Shutdown
+	Stop(ctx context.Context, in *Stop_Request, opts ...grpc.CallOption) (*Stop_Response, error)
+}
+
+type providerClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewProviderClient(cc grpc.ClientConnInterface) ProviderClient {
+	return &providerClient{cc}
+}
+
+func (c *providerClient) GetSchema(ctx context.Context, in *GetProviderSchema_Request, opts ...grpc.CallOption) (*GetProviderSchema_Response, error) {
+	out := new(GetProviderSchema_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin5.Provider/GetSchema", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) PrepareProviderConfig(ctx context.Context, in *PrepareProviderConfig_Request, opts ...grpc.CallOption) (*PrepareProviderConfig_Response, error) {
+	out := new(PrepareProviderConfig_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin5.Provider/PrepareProviderConfig", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) ValidateResourceTypeConfig(ctx context.Context, in *ValidateResourceTypeConfig_Request, opts ...grpc.CallOption) (*ValidateResourceTypeConfig_Response, error) {
+	out := new(ValidateResourceTypeConfig_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin5.Provider/ValidateResourceTypeConfig", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) ValidateDataSourceConfig(ctx context.Context, in *ValidateDataSourceConfig_Request, opts ...grpc.CallOption) (*ValidateDataSourceConfig_Response, error) {
+	out := new(ValidateDataSourceConfig_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin5.Provider/ValidateDataSourceConfig", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) UpgradeResourceState(ctx context.Context, in *UpgradeResourceState_Request, opts ...grpc.CallOption) (*UpgradeResourceState_Response, error) {
+	out := new(UpgradeResourceState_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin5.Provider/UpgradeResourceState", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) Configure(ctx context.Context, in *Configure_Request, opts ...grpc.CallOption) (*Configure_Response, error) {
+	out := new(Configure_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin5.Provider/Configure", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) ReadResource(ctx context.Context, in *ReadResource_Request, opts ...grpc.CallOption) (*ReadResource_Response, error) {
+	out := new(ReadResource_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin5.Provider/ReadResource", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) PlanResourceChange(ctx context.Context, in *PlanResourceChange_Request, opts ...grpc.CallOption) (*PlanResourceChange_Response, error) {
+	out := new(PlanResourceChange_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin5.Provider/PlanResourceChange", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) ApplyResourceChange(ctx context.Context, in *ApplyResourceChange_Request, opts ...grpc.CallOption) (*ApplyResourceChange_Response, error) {
+	out := new(ApplyResourceChange_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin5.Provider/ApplyResourceChange", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) ImportResourceState(ctx context.Context, in *ImportResourceState_Request, opts ...grpc.CallOption) (*ImportResourceState_Response, error) {
+	out := new(ImportResourceState_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin5.Provider/ImportResourceState", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) ReadDataSource(ctx context.Context, in *ReadDataSource_Request, opts ...grpc.CallOption) (*ReadDataSource_Response, error) {
+	out := new(ReadDataSource_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin5.Provider/ReadDataSource", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) Stop(ctx context.Context, in *Stop_Request, opts ...grpc.CallOption) (*Stop_Response, error) {
+	out := new(Stop_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin5.Provider/Stop", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// ProviderServer is the server API for Provider service.
+type ProviderServer interface {
+	// ////// Information about what a provider supports/expects
+	GetSchema(context.Context, *GetProviderSchema_Request) (*GetProviderSchema_Response, error)
+	PrepareProviderConfig(context.Context, *PrepareProviderConfig_Request) (*PrepareProviderConfig_Response, error)
+	ValidateResourceTypeConfig(context.Context, *ValidateResourceTypeConfig_Request) (*ValidateResourceTypeConfig_Response, error)
+	ValidateDataSourceConfig(context.Context, *ValidateDataSourceConfig_Request) (*ValidateDataSourceConfig_Response, error)
+	UpgradeResourceState(context.Context, *UpgradeResourceState_Request) (*UpgradeResourceState_Response, error)
+	// ////// One-time initialization, called before other functions below
+	Configure(context.Context, *Configure_Request) (*Configure_Response, error)
+	// ////// Managed Resource Lifecycle
+	ReadResource(context.Context, *ReadResource_Request) (*ReadResource_Response, error)
+	PlanResourceChange(context.Context, *PlanResourceChange_Request) (*PlanResourceChange_Response, error)
+	ApplyResourceChange(context.Context, *ApplyResourceChange_Request) (*ApplyResourceChange_Response, error)
+	ImportResourceState(context.Context, *ImportResourceState_Request) (*ImportResourceState_Response, error)
+	ReadDataSource(context.Context, *ReadDataSource_Request) (*ReadDataSource_Response, error)
+	// ////// Graceful Shutdown
+	Stop(context.Context, *Stop_Request) (*Stop_Response, error)
+}
+
+// UnimplementedProviderServer can be embedded to have forward compatible implementations.
+type UnimplementedProviderServer struct {
+}
+
+func (*UnimplementedProviderServer) GetSchema(context.Context, *GetProviderSchema_Request) (*GetProviderSchema_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetSchema not implemented")
+}
+func (*UnimplementedProviderServer) PrepareProviderConfig(context.Context, *PrepareProviderConfig_Request) (*PrepareProviderConfig_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method PrepareProviderConfig not implemented")
+}
+func (*UnimplementedProviderServer) ValidateResourceTypeConfig(context.Context, *ValidateResourceTypeConfig_Request) (*ValidateResourceTypeConfig_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ValidateResourceTypeConfig not implemented")
+}
+func (*UnimplementedProviderServer) ValidateDataSourceConfig(context.Context, *ValidateDataSourceConfig_Request) (*ValidateDataSourceConfig_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ValidateDataSourceConfig not implemented")
+}
+func (*UnimplementedProviderServer) UpgradeResourceState(context.Context, *UpgradeResourceState_Request) (*UpgradeResourceState_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method UpgradeResourceState not implemented")
+}
+func (*UnimplementedProviderServer) Configure(context.Context, *Configure_Request) (*Configure_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Configure not implemented")
+}
+func (*UnimplementedProviderServer) ReadResource(context.Context, *ReadResource_Request) (*ReadResource_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ReadResource not implemented")
+}
+func (*UnimplementedProviderServer) PlanResourceChange(context.Context, *PlanResourceChange_Request) (*PlanResourceChange_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method PlanResourceChange not implemented")
+}
+func (*UnimplementedProviderServer) ApplyResourceChange(context.Context, *ApplyResourceChange_Request) (*ApplyResourceChange_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ApplyResourceChange not implemented")
+}
+func (*UnimplementedProviderServer) ImportResourceState(context.Context, *ImportResourceState_Request) (*ImportResourceState_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ImportResourceState not implemented")
+}
+func (*UnimplementedProviderServer) ReadDataSource(context.Context, *ReadDataSource_Request) (*ReadDataSource_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ReadDataSource not implemented")
+}
+func (*UnimplementedProviderServer) Stop(context.Context, *Stop_Request) (*Stop_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Stop not implemented")
+}
+
+func RegisterProviderServer(s *grpc.Server, srv ProviderServer) {
+	s.RegisterService(&_Provider_serviceDesc, srv)
+}
+
+func _Provider_GetSchema_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(GetProviderSchema_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).GetSchema(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin5.Provider/GetSchema",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).GetSchema(ctx, req.(*GetProviderSchema_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_PrepareProviderConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(PrepareProviderConfig_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).PrepareProviderConfig(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin5.Provider/PrepareProviderConfig",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).PrepareProviderConfig(ctx, req.(*PrepareProviderConfig_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_ValidateResourceTypeConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ValidateResourceTypeConfig_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).ValidateResourceTypeConfig(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin5.Provider/ValidateResourceTypeConfig",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).ValidateResourceTypeConfig(ctx, req.(*ValidateResourceTypeConfig_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_ValidateDataSourceConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ValidateDataSourceConfig_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).ValidateDataSourceConfig(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin5.Provider/ValidateDataSourceConfig",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).ValidateDataSourceConfig(ctx, req.(*ValidateDataSourceConfig_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_UpgradeResourceState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(UpgradeResourceState_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).UpgradeResourceState(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin5.Provider/UpgradeResourceState",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).UpgradeResourceState(ctx, req.(*UpgradeResourceState_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_Configure_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(Configure_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).Configure(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin5.Provider/Configure",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).Configure(ctx, req.(*Configure_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_ReadResource_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ReadResource_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).ReadResource(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin5.Provider/ReadResource",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).ReadResource(ctx, req.(*ReadResource_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_PlanResourceChange_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(PlanResourceChange_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).PlanResourceChange(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin5.Provider/PlanResourceChange",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).PlanResourceChange(ctx, req.(*PlanResourceChange_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_ApplyResourceChange_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ApplyResourceChange_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).ApplyResourceChange(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin5.Provider/ApplyResourceChange",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).ApplyResourceChange(ctx, req.(*ApplyResourceChange_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_ImportResourceState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ImportResourceState_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).ImportResourceState(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin5.Provider/ImportResourceState",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).ImportResourceState(ctx, req.(*ImportResourceState_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_ReadDataSource_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ReadDataSource_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).ReadDataSource(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin5.Provider/ReadDataSource",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).ReadDataSource(ctx, req.(*ReadDataSource_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_Stop_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(Stop_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).Stop(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin5.Provider/Stop",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).Stop(ctx, req.(*Stop_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+var _Provider_serviceDesc = grpc.ServiceDesc{
+	ServiceName: "tfplugin5.Provider",
+	HandlerType: (*ProviderServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "GetSchema",
+			Handler:    _Provider_GetSchema_Handler,
+		},
+		{
+			MethodName: "PrepareProviderConfig",
+			Handler:    _Provider_PrepareProviderConfig_Handler,
+		},
+		{
+			MethodName: "ValidateResourceTypeConfig",
+			Handler:    _Provider_ValidateResourceTypeConfig_Handler,
+		},
+		{
+			MethodName: "ValidateDataSourceConfig",
+			Handler:    _Provider_ValidateDataSourceConfig_Handler,
+		},
+		{
+			MethodName: "UpgradeResourceState",
+			Handler:    _Provider_UpgradeResourceState_Handler,
+		},
+		{
+			MethodName: "Configure",
+			Handler:    _Provider_Configure_Handler,
+		},
+		{
+			MethodName: "ReadResource",
+			Handler:    _Provider_ReadResource_Handler,
+		},
+		{
+			MethodName: "PlanResourceChange",
+			Handler:    _Provider_PlanResourceChange_Handler,
+		},
+		{
+			MethodName: "ApplyResourceChange",
+			Handler:    _Provider_ApplyResourceChange_Handler,
+		},
+		{
+			MethodName: "ImportResourceState",
+			Handler:    _Provider_ImportResourceState_Handler,
+		},
+		{
+			MethodName: "ReadDataSource",
+			Handler:    _Provider_ReadDataSource_Handler,
+		},
+		{
+			MethodName: "Stop",
+			Handler:    _Provider_Stop_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "tfplugin5.proto",
+}
+
+// ProvisionerClient is the client API for Provisioner service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type ProvisionerClient interface {
+	GetSchema(ctx context.Context, in *GetProvisionerSchema_Request, opts ...grpc.CallOption) (*GetProvisionerSchema_Response, error)
+	ValidateProvisionerConfig(ctx context.Context, in *ValidateProvisionerConfig_Request, opts ...grpc.CallOption) (*ValidateProvisionerConfig_Response, error)
+	ProvisionResource(ctx context.Context, in *ProvisionResource_Request, opts ...grpc.CallOption) (Provisioner_ProvisionResourceClient, error)
+	Stop(ctx context.Context, in *Stop_Request, opts ...grpc.CallOption) (*Stop_Response, error)
+}
+
+type provisionerClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewProvisionerClient(cc grpc.ClientConnInterface) ProvisionerClient {
+	return &provisionerClient{cc}
+}
+
+func (c *provisionerClient) GetSchema(ctx context.Context, in *GetProvisionerSchema_Request, opts ...grpc.CallOption) (*GetProvisionerSchema_Response, error) {
+	out := new(GetProvisionerSchema_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin5.Provisioner/GetSchema", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *provisionerClient) ValidateProvisionerConfig(ctx context.Context, in *ValidateProvisionerConfig_Request, opts ...grpc.CallOption) (*ValidateProvisionerConfig_Response, error) {
+	out := new(ValidateProvisionerConfig_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin5.Provisioner/ValidateProvisionerConfig", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *provisionerClient) ProvisionResource(ctx context.Context, in *ProvisionResource_Request, opts ...grpc.CallOption) (Provisioner_ProvisionResourceClient, error) {
+	stream, err := c.cc.NewStream(ctx, &_Provisioner_serviceDesc.Streams[0], "/tfplugin5.Provisioner/ProvisionResource", opts...)
+	if err != nil {
+		return nil, err
+	}
+	x := &provisionerProvisionResourceClient{stream}
+	if err := x.ClientStream.SendMsg(in); err != nil {
+		return nil, err
+	}
+	if err := x.ClientStream.CloseSend(); err != nil {
+		return nil, err
+	}
+	return x, nil
+}
+
+type Provisioner_ProvisionResourceClient interface {
+	Recv() (*ProvisionResource_Response, error)
+	grpc.ClientStream
+}
+
+type provisionerProvisionResourceClient struct {
+	grpc.ClientStream
+}
+
+func (x *provisionerProvisionResourceClient) Recv() (*ProvisionResource_Response, error) {
+	m := new(ProvisionResource_Response)
+	if err := x.ClientStream.RecvMsg(m); err != nil {
+		return nil, err
+	}
+	return m, nil
+}
+
+func (c *provisionerClient) Stop(ctx context.Context, in *Stop_Request, opts ...grpc.CallOption) (*Stop_Response, error) {
+	out := new(Stop_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin5.Provisioner/Stop", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// ProvisionerServer is the server API for Provisioner service.
+type ProvisionerServer interface {
+	GetSchema(context.Context, *GetProvisionerSchema_Request) (*GetProvisionerSchema_Response, error)
+	ValidateProvisionerConfig(context.Context, *ValidateProvisionerConfig_Request) (*ValidateProvisionerConfig_Response, error)
+	ProvisionResource(*ProvisionResource_Request, Provisioner_ProvisionResourceServer) error
+	Stop(context.Context, *Stop_Request) (*Stop_Response, error)
+}
+
+// UnimplementedProvisionerServer can be embedded to have forward compatible implementations.
+type UnimplementedProvisionerServer struct {
+}
+
+func (*UnimplementedProvisionerServer) GetSchema(context.Context, *GetProvisionerSchema_Request) (*GetProvisionerSchema_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetSchema not implemented")
+}
+func (*UnimplementedProvisionerServer) ValidateProvisionerConfig(context.Context, *ValidateProvisionerConfig_Request) (*ValidateProvisionerConfig_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ValidateProvisionerConfig not implemented")
+}
+func (*UnimplementedProvisionerServer) ProvisionResource(*ProvisionResource_Request, Provisioner_ProvisionResourceServer) error {
+	return status.Errorf(codes.Unimplemented, "method ProvisionResource not implemented")
+}
+func (*UnimplementedProvisionerServer) Stop(context.Context, *Stop_Request) (*Stop_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Stop not implemented")
+}
+
+func RegisterProvisionerServer(s *grpc.Server, srv ProvisionerServer) {
+	s.RegisterService(&_Provisioner_serviceDesc, srv)
+}
+
+func _Provisioner_GetSchema_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(GetProvisionerSchema_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProvisionerServer).GetSchema(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin5.Provisioner/GetSchema",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProvisionerServer).GetSchema(ctx, req.(*GetProvisionerSchema_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provisioner_ValidateProvisionerConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ValidateProvisionerConfig_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProvisionerServer).ValidateProvisionerConfig(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin5.Provisioner/ValidateProvisionerConfig",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProvisionerServer).ValidateProvisionerConfig(ctx, req.(*ValidateProvisionerConfig_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provisioner_ProvisionResource_Handler(srv interface{}, stream grpc.ServerStream) error {
+	m := new(ProvisionResource_Request)
+	if err := stream.RecvMsg(m); err != nil {
+		return err
+	}
+	return srv.(ProvisionerServer).ProvisionResource(m, &provisionerProvisionResourceServer{stream})
+}
+
+type Provisioner_ProvisionResourceServer interface {
+	Send(*ProvisionResource_Response) error
+	grpc.ServerStream
+}
+
+type provisionerProvisionResourceServer struct {
+	grpc.ServerStream
+}
+
+func (x *provisionerProvisionResourceServer) Send(m *ProvisionResource_Response) error {
+	return x.ServerStream.SendMsg(m)
+}
+
+func _Provisioner_Stop_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(Stop_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProvisionerServer).Stop(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin5.Provisioner/Stop",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProvisionerServer).Stop(ctx, req.(*Stop_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+var _Provisioner_serviceDesc = grpc.ServiceDesc{
+	ServiceName: "tfplugin5.Provisioner",
+	HandlerType: (*ProvisionerServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "GetSchema",
+			Handler:    _Provisioner_GetSchema_Handler,
+		},
+		{
+			MethodName: "ValidateProvisionerConfig",
+			Handler:    _Provisioner_ValidateProvisionerConfig_Handler,
+		},
+		{
+			MethodName: "Stop",
+			Handler:    _Provisioner_Stop_Handler,
+		},
+	},
+	Streams: []grpc.StreamDesc{
+		{
+			StreamName:    "ProvisionResource",
+			Handler:       _Provisioner_ProvisionResource_Handler,
+			ServerStreams: true,
+		},
+	},
+	Metadata: "tfplugin5.proto",
+}
diff --git a/v1.5.7/internal/tfplugin5/tfplugin5.proto b/v1.5.7/internal/tfplugin5/tfplugin5.proto
new file mode 120000
index 0000000..0bdfe34
--- /dev/null
+++ b/v1.5.7/internal/tfplugin5/tfplugin5.proto
@@ -0,0 +1 @@
+../../docs/plugin-protocol/tfplugin5.3.proto
\ No newline at end of file
diff --git a/v1.5.7/internal/tfplugin6/tfplugin6.pb.go b/v1.5.7/internal/tfplugin6/tfplugin6.pb.go
new file mode 100644
index 0000000..96ffacc
--- /dev/null
+++ b/v1.5.7/internal/tfplugin6/tfplugin6.pb.go
@@ -0,0 +1,4763 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// Terraform Plugin RPC protocol version 6.3
+//
+// This file defines version 6.3 of the RPC protocol. To implement a plugin
+// against this protocol, copy this definition into your own codebase and
+// use protoc to generate stubs for your target language.
+//
+// This file will not be updated. Any minor versions of protocol 6 to follow
+// should copy this file and modify the copy while maintaing backwards
+// compatibility. Breaking changes, if any are required, will come
+// in a subsequent major version with its own separate proto definition.
+//
+// Note that only the proto files included in a release tag of Terraform are
+// official protocol releases. Proto files taken from other commits may include
+// incomplete changes or features that did not make it into a final release.
+// In all reasonable cases, plugin developers should take the proto file from
+// the tag of the most recent release of Terraform, and not from the main
+// branch or any other development branch.
+//
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.28.1
+// 	protoc        v3.15.6
+// source: tfplugin6.proto
+
+package tfplugin6
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type StringKind int32
+
+const (
+	StringKind_PLAIN    StringKind = 0
+	StringKind_MARKDOWN StringKind = 1
+)
+
+// Enum value maps for StringKind.
+var (
+	StringKind_name = map[int32]string{
+		0: "PLAIN",
+		1: "MARKDOWN",
+	}
+	StringKind_value = map[string]int32{
+		"PLAIN":    0,
+		"MARKDOWN": 1,
+	}
+)
+
+func (x StringKind) Enum() *StringKind {
+	p := new(StringKind)
+	*p = x
+	return p
+}
+
+func (x StringKind) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (StringKind) Descriptor() protoreflect.EnumDescriptor {
+	return file_tfplugin6_proto_enumTypes[0].Descriptor()
+}
+
+func (StringKind) Type() protoreflect.EnumType {
+	return &file_tfplugin6_proto_enumTypes[0]
+}
+
+func (x StringKind) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use StringKind.Descriptor instead.
+func (StringKind) EnumDescriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{0}
+}
+
+type Diagnostic_Severity int32
+
+const (
+	Diagnostic_INVALID Diagnostic_Severity = 0
+	Diagnostic_ERROR   Diagnostic_Severity = 1
+	Diagnostic_WARNING Diagnostic_Severity = 2
+)
+
+// Enum value maps for Diagnostic_Severity.
+var (
+	Diagnostic_Severity_name = map[int32]string{
+		0: "INVALID",
+		1: "ERROR",
+		2: "WARNING",
+	}
+	Diagnostic_Severity_value = map[string]int32{
+		"INVALID": 0,
+		"ERROR":   1,
+		"WARNING": 2,
+	}
+)
+
+func (x Diagnostic_Severity) Enum() *Diagnostic_Severity {
+	p := new(Diagnostic_Severity)
+	*p = x
+	return p
+}
+
+func (x Diagnostic_Severity) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Diagnostic_Severity) Descriptor() protoreflect.EnumDescriptor {
+	return file_tfplugin6_proto_enumTypes[1].Descriptor()
+}
+
+func (Diagnostic_Severity) Type() protoreflect.EnumType {
+	return &file_tfplugin6_proto_enumTypes[1]
+}
+
+func (x Diagnostic_Severity) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Diagnostic_Severity.Descriptor instead.
+func (Diagnostic_Severity) EnumDescriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{1, 0}
+}
+
+type Schema_NestedBlock_NestingMode int32
+
+const (
+	Schema_NestedBlock_INVALID Schema_NestedBlock_NestingMode = 0
+	Schema_NestedBlock_SINGLE  Schema_NestedBlock_NestingMode = 1
+	Schema_NestedBlock_LIST    Schema_NestedBlock_NestingMode = 2
+	Schema_NestedBlock_SET     Schema_NestedBlock_NestingMode = 3
+	Schema_NestedBlock_MAP     Schema_NestedBlock_NestingMode = 4
+	Schema_NestedBlock_GROUP   Schema_NestedBlock_NestingMode = 5
+)
+
+// Enum value maps for Schema_NestedBlock_NestingMode.
+var (
+	Schema_NestedBlock_NestingMode_name = map[int32]string{
+		0: "INVALID",
+		1: "SINGLE",
+		2: "LIST",
+		3: "SET",
+		4: "MAP",
+		5: "GROUP",
+	}
+	Schema_NestedBlock_NestingMode_value = map[string]int32{
+		"INVALID": 0,
+		"SINGLE":  1,
+		"LIST":    2,
+		"SET":     3,
+		"MAP":     4,
+		"GROUP":   5,
+	}
+)
+
+func (x Schema_NestedBlock_NestingMode) Enum() *Schema_NestedBlock_NestingMode {
+	p := new(Schema_NestedBlock_NestingMode)
+	*p = x
+	return p
+}
+
+func (x Schema_NestedBlock_NestingMode) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Schema_NestedBlock_NestingMode) Descriptor() protoreflect.EnumDescriptor {
+	return file_tfplugin6_proto_enumTypes[2].Descriptor()
+}
+
+func (Schema_NestedBlock_NestingMode) Type() protoreflect.EnumType {
+	return &file_tfplugin6_proto_enumTypes[2]
+}
+
+func (x Schema_NestedBlock_NestingMode) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Schema_NestedBlock_NestingMode.Descriptor instead.
+func (Schema_NestedBlock_NestingMode) EnumDescriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{5, 2, 0}
+}
+
+type Schema_Object_NestingMode int32
+
+const (
+	Schema_Object_INVALID Schema_Object_NestingMode = 0
+	Schema_Object_SINGLE  Schema_Object_NestingMode = 1
+	Schema_Object_LIST    Schema_Object_NestingMode = 2
+	Schema_Object_SET     Schema_Object_NestingMode = 3
+	Schema_Object_MAP     Schema_Object_NestingMode = 4
+)
+
+// Enum value maps for Schema_Object_NestingMode.
+var (
+	Schema_Object_NestingMode_name = map[int32]string{
+		0: "INVALID",
+		1: "SINGLE",
+		2: "LIST",
+		3: "SET",
+		4: "MAP",
+	}
+	Schema_Object_NestingMode_value = map[string]int32{
+		"INVALID": 0,
+		"SINGLE":  1,
+		"LIST":    2,
+		"SET":     3,
+		"MAP":     4,
+	}
+)
+
+func (x Schema_Object_NestingMode) Enum() *Schema_Object_NestingMode {
+	p := new(Schema_Object_NestingMode)
+	*p = x
+	return p
+}
+
+func (x Schema_Object_NestingMode) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Schema_Object_NestingMode) Descriptor() protoreflect.EnumDescriptor {
+	return file_tfplugin6_proto_enumTypes[3].Descriptor()
+}
+
+func (Schema_Object_NestingMode) Type() protoreflect.EnumType {
+	return &file_tfplugin6_proto_enumTypes[3]
+}
+
+func (x Schema_Object_NestingMode) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Schema_Object_NestingMode.Descriptor instead.
+func (Schema_Object_NestingMode) EnumDescriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{5, 3, 0}
+}
+
+// DynamicValue is an opaque encoding of terraform data, with the field name
+// indicating the encoding scheme used.
+type DynamicValue struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Msgpack []byte `protobuf:"bytes,1,opt,name=msgpack,proto3" json:"msgpack,omitempty"`
+	Json    []byte `protobuf:"bytes,2,opt,name=json,proto3" json:"json,omitempty"`
+}
+
+func (x *DynamicValue) Reset() {
+	*x = DynamicValue{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DynamicValue) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DynamicValue) ProtoMessage() {}
+
+func (x *DynamicValue) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use DynamicValue.ProtoReflect.Descriptor instead.
+func (*DynamicValue) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *DynamicValue) GetMsgpack() []byte {
+	if x != nil {
+		return x.Msgpack
+	}
+	return nil
+}
+
+func (x *DynamicValue) GetJson() []byte {
+	if x != nil {
+		return x.Json
+	}
+	return nil
+}
+
+type Diagnostic struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Severity  Diagnostic_Severity `protobuf:"varint,1,opt,name=severity,proto3,enum=tfplugin6.Diagnostic_Severity" json:"severity,omitempty"`
+	Summary   string              `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"`
+	Detail    string              `protobuf:"bytes,3,opt,name=detail,proto3" json:"detail,omitempty"`
+	Attribute *AttributePath      `protobuf:"bytes,4,opt,name=attribute,proto3" json:"attribute,omitempty"`
+}
+
+func (x *Diagnostic) Reset() {
+	*x = Diagnostic{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Diagnostic) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Diagnostic) ProtoMessage() {}
+
+func (x *Diagnostic) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Diagnostic.ProtoReflect.Descriptor instead.
+func (*Diagnostic) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *Diagnostic) GetSeverity() Diagnostic_Severity {
+	if x != nil {
+		return x.Severity
+	}
+	return Diagnostic_INVALID
+}
+
+func (x *Diagnostic) GetSummary() string {
+	if x != nil {
+		return x.Summary
+	}
+	return ""
+}
+
+func (x *Diagnostic) GetDetail() string {
+	if x != nil {
+		return x.Detail
+	}
+	return ""
+}
+
+func (x *Diagnostic) GetAttribute() *AttributePath {
+	if x != nil {
+		return x.Attribute
+	}
+	return nil
+}
+
+type AttributePath struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Steps []*AttributePath_Step `protobuf:"bytes,1,rep,name=steps,proto3" json:"steps,omitempty"`
+}
+
+func (x *AttributePath) Reset() {
+	*x = AttributePath{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *AttributePath) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AttributePath) ProtoMessage() {}
+
+func (x *AttributePath) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AttributePath.ProtoReflect.Descriptor instead.
+func (*AttributePath) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *AttributePath) GetSteps() []*AttributePath_Step {
+	if x != nil {
+		return x.Steps
+	}
+	return nil
+}
+
+type StopProvider struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *StopProvider) Reset() {
+	*x = StopProvider{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *StopProvider) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StopProvider) ProtoMessage() {}
+
+func (x *StopProvider) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use StopProvider.ProtoReflect.Descriptor instead.
+func (*StopProvider) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{3}
+}
+
+// RawState holds the stored state for a resource to be upgraded by the
+// provider. It can be in one of two formats, the current json encoded format
+// in bytes, or the legacy flatmap format as a map of strings.
+type RawState struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Json    []byte            `protobuf:"bytes,1,opt,name=json,proto3" json:"json,omitempty"`
+	Flatmap map[string]string `protobuf:"bytes,2,rep,name=flatmap,proto3" json:"flatmap,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *RawState) Reset() {
+	*x = RawState{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *RawState) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RawState) ProtoMessage() {}
+
+func (x *RawState) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use RawState.ProtoReflect.Descriptor instead.
+func (*RawState) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *RawState) GetJson() []byte {
+	if x != nil {
+		return x.Json
+	}
+	return nil
+}
+
+func (x *RawState) GetFlatmap() map[string]string {
+	if x != nil {
+		return x.Flatmap
+	}
+	return nil
+}
+
+// Schema is the configuration schema for a Resource or Provider.
+type Schema struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The version of the schema.
+	// Schemas are versioned, so that providers can upgrade a saved resource
+	// state when the schema is changed.
+	Version int64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
+	// Block is the top level configuration block for this schema.
+	Block *Schema_Block `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"`
+}
+
+func (x *Schema) Reset() {
+	*x = Schema{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Schema) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Schema) ProtoMessage() {}
+
+func (x *Schema) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Schema.ProtoReflect.Descriptor instead.
+func (*Schema) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *Schema) GetVersion() int64 {
+	if x != nil {
+		return x.Version
+	}
+	return 0
+}
+
+func (x *Schema) GetBlock() *Schema_Block {
+	if x != nil {
+		return x.Block
+	}
+	return nil
+}
+
+type GetProviderSchema struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *GetProviderSchema) Reset() {
+	*x = GetProviderSchema{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetProviderSchema) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetProviderSchema) ProtoMessage() {}
+
+func (x *GetProviderSchema) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[6]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetProviderSchema.ProtoReflect.Descriptor instead.
+func (*GetProviderSchema) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{6}
+}
+
+type ValidateProviderConfig struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ValidateProviderConfig) Reset() {
+	*x = ValidateProviderConfig{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateProviderConfig) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateProviderConfig) ProtoMessage() {}
+
+func (x *ValidateProviderConfig) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[7]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateProviderConfig.ProtoReflect.Descriptor instead.
+func (*ValidateProviderConfig) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{7}
+}
+
+type UpgradeResourceState struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *UpgradeResourceState) Reset() {
+	*x = UpgradeResourceState{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[8]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UpgradeResourceState) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpgradeResourceState) ProtoMessage() {}
+
+func (x *UpgradeResourceState) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[8]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpgradeResourceState.ProtoReflect.Descriptor instead.
+func (*UpgradeResourceState) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{8}
+}
+
+type ValidateResourceConfig struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ValidateResourceConfig) Reset() {
+	*x = ValidateResourceConfig{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[9]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateResourceConfig) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateResourceConfig) ProtoMessage() {}
+
+func (x *ValidateResourceConfig) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[9]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateResourceConfig.ProtoReflect.Descriptor instead.
+func (*ValidateResourceConfig) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{9}
+}
+
+type ValidateDataResourceConfig struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ValidateDataResourceConfig) Reset() {
+	*x = ValidateDataResourceConfig{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[10]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateDataResourceConfig) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateDataResourceConfig) ProtoMessage() {}
+
+func (x *ValidateDataResourceConfig) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[10]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateDataResourceConfig.ProtoReflect.Descriptor instead.
+func (*ValidateDataResourceConfig) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{10}
+}
+
+type ConfigureProvider struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ConfigureProvider) Reset() {
+	*x = ConfigureProvider{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[11]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ConfigureProvider) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ConfigureProvider) ProtoMessage() {}
+
+func (x *ConfigureProvider) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[11]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ConfigureProvider.ProtoReflect.Descriptor instead.
+func (*ConfigureProvider) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{11}
+}
+
+type ReadResource struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ReadResource) Reset() {
+	*x = ReadResource{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[12]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReadResource) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReadResource) ProtoMessage() {}
+
+func (x *ReadResource) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[12]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReadResource.ProtoReflect.Descriptor instead.
+func (*ReadResource) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{12}
+}
+
+type PlanResourceChange struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *PlanResourceChange) Reset() {
+	*x = PlanResourceChange{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[13]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PlanResourceChange) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PlanResourceChange) ProtoMessage() {}
+
+func (x *PlanResourceChange) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[13]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PlanResourceChange.ProtoReflect.Descriptor instead.
+func (*PlanResourceChange) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{13}
+}
+
+type ApplyResourceChange struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ApplyResourceChange) Reset() {
+	*x = ApplyResourceChange{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[14]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ApplyResourceChange) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ApplyResourceChange) ProtoMessage() {}
+
+func (x *ApplyResourceChange) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[14]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ApplyResourceChange.ProtoReflect.Descriptor instead.
+func (*ApplyResourceChange) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{14}
+}
+
+type ImportResourceState struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ImportResourceState) Reset() {
+	*x = ImportResourceState{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[15]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ImportResourceState) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ImportResourceState) ProtoMessage() {}
+
+func (x *ImportResourceState) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[15]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ImportResourceState.ProtoReflect.Descriptor instead.
+func (*ImportResourceState) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{15}
+}
+
+type ReadDataSource struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ReadDataSource) Reset() {
+	*x = ReadDataSource{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[16]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReadDataSource) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReadDataSource) ProtoMessage() {}
+
+func (x *ReadDataSource) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[16]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReadDataSource.ProtoReflect.Descriptor instead.
+func (*ReadDataSource) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{16}
+}
+
+type AttributePath_Step struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Types that are assignable to Selector:
+	//
+	//	*AttributePath_Step_AttributeName
+	//	*AttributePath_Step_ElementKeyString
+	//	*AttributePath_Step_ElementKeyInt
+	Selector isAttributePath_Step_Selector `protobuf_oneof:"selector"`
+}
+
+func (x *AttributePath_Step) Reset() {
+	*x = AttributePath_Step{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[17]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *AttributePath_Step) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AttributePath_Step) ProtoMessage() {}
+
+func (x *AttributePath_Step) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[17]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AttributePath_Step.ProtoReflect.Descriptor instead.
+func (*AttributePath_Step) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{2, 0}
+}
+
+func (m *AttributePath_Step) GetSelector() isAttributePath_Step_Selector {
+	if m != nil {
+		return m.Selector
+	}
+	return nil
+}
+
+func (x *AttributePath_Step) GetAttributeName() string {
+	if x, ok := x.GetSelector().(*AttributePath_Step_AttributeName); ok {
+		return x.AttributeName
+	}
+	return ""
+}
+
+func (x *AttributePath_Step) GetElementKeyString() string {
+	if x, ok := x.GetSelector().(*AttributePath_Step_ElementKeyString); ok {
+		return x.ElementKeyString
+	}
+	return ""
+}
+
+func (x *AttributePath_Step) GetElementKeyInt() int64 {
+	if x, ok := x.GetSelector().(*AttributePath_Step_ElementKeyInt); ok {
+		return x.ElementKeyInt
+	}
+	return 0
+}
+
+type isAttributePath_Step_Selector interface {
+	isAttributePath_Step_Selector()
+}
+
+type AttributePath_Step_AttributeName struct {
+	// Set "attribute_name" to represent looking up an attribute
+	// in the current object value.
+	AttributeName string `protobuf:"bytes,1,opt,name=attribute_name,json=attributeName,proto3,oneof"`
+}
+
+type AttributePath_Step_ElementKeyString struct {
+	// Set "element_key_*" to represent looking up an element in
+	// an indexable collection type.
+	ElementKeyString string `protobuf:"bytes,2,opt,name=element_key_string,json=elementKeyString,proto3,oneof"`
+}
+
+type AttributePath_Step_ElementKeyInt struct {
+	ElementKeyInt int64 `protobuf:"varint,3,opt,name=element_key_int,json=elementKeyInt,proto3,oneof"`
+}
+
+func (*AttributePath_Step_AttributeName) isAttributePath_Step_Selector() {}
+
+func (*AttributePath_Step_ElementKeyString) isAttributePath_Step_Selector() {}
+
+func (*AttributePath_Step_ElementKeyInt) isAttributePath_Step_Selector() {}
+
+type StopProvider_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *StopProvider_Request) Reset() {
+	*x = StopProvider_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[18]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *StopProvider_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StopProvider_Request) ProtoMessage() {}
+
+func (x *StopProvider_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[18]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use StopProvider_Request.ProtoReflect.Descriptor instead.
+func (*StopProvider_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{3, 0}
+}
+
+type StopProvider_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Error string `protobuf:"bytes,1,opt,name=Error,proto3" json:"Error,omitempty"`
+}
+
+func (x *StopProvider_Response) Reset() {
+	*x = StopProvider_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[19]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *StopProvider_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StopProvider_Response) ProtoMessage() {}
+
+func (x *StopProvider_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[19]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use StopProvider_Response.ProtoReflect.Descriptor instead.
+func (*StopProvider_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{3, 1}
+}
+
+func (x *StopProvider_Response) GetError() string {
+	if x != nil {
+		return x.Error
+	}
+	return ""
+}
+
+type Schema_Block struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Version         int64                 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
+	Attributes      []*Schema_Attribute   `protobuf:"bytes,2,rep,name=attributes,proto3" json:"attributes,omitempty"`
+	BlockTypes      []*Schema_NestedBlock `protobuf:"bytes,3,rep,name=block_types,json=blockTypes,proto3" json:"block_types,omitempty"`
+	Description     string                `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"`
+	DescriptionKind StringKind            `protobuf:"varint,5,opt,name=description_kind,json=descriptionKind,proto3,enum=tfplugin6.StringKind" json:"description_kind,omitempty"`
+	Deprecated      bool                  `protobuf:"varint,6,opt,name=deprecated,proto3" json:"deprecated,omitempty"`
+}
+
+func (x *Schema_Block) Reset() {
+	*x = Schema_Block{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[21]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Schema_Block) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Schema_Block) ProtoMessage() {}
+
+func (x *Schema_Block) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[21]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Schema_Block.ProtoReflect.Descriptor instead.
+func (*Schema_Block) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{5, 0}
+}
+
+func (x *Schema_Block) GetVersion() int64 {
+	if x != nil {
+		return x.Version
+	}
+	return 0
+}
+
+func (x *Schema_Block) GetAttributes() []*Schema_Attribute {
+	if x != nil {
+		return x.Attributes
+	}
+	return nil
+}
+
+func (x *Schema_Block) GetBlockTypes() []*Schema_NestedBlock {
+	if x != nil {
+		return x.BlockTypes
+	}
+	return nil
+}
+
+func (x *Schema_Block) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *Schema_Block) GetDescriptionKind() StringKind {
+	if x != nil {
+		return x.DescriptionKind
+	}
+	return StringKind_PLAIN
+}
+
+func (x *Schema_Block) GetDeprecated() bool {
+	if x != nil {
+		return x.Deprecated
+	}
+	return false
+}
+
+type Schema_Attribute struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Name            string         `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	Type            []byte         `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
+	NestedType      *Schema_Object `protobuf:"bytes,10,opt,name=nested_type,json=nestedType,proto3" json:"nested_type,omitempty"`
+	Description     string         `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
+	Required        bool           `protobuf:"varint,4,opt,name=required,proto3" json:"required,omitempty"`
+	Optional        bool           `protobuf:"varint,5,opt,name=optional,proto3" json:"optional,omitempty"`
+	Computed        bool           `protobuf:"varint,6,opt,name=computed,proto3" json:"computed,omitempty"`
+	Sensitive       bool           `protobuf:"varint,7,opt,name=sensitive,proto3" json:"sensitive,omitempty"`
+	DescriptionKind StringKind     `protobuf:"varint,8,opt,name=description_kind,json=descriptionKind,proto3,enum=tfplugin6.StringKind" json:"description_kind,omitempty"`
+	Deprecated      bool           `protobuf:"varint,9,opt,name=deprecated,proto3" json:"deprecated,omitempty"`
+}
+
+func (x *Schema_Attribute) Reset() {
+	*x = Schema_Attribute{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[22]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Schema_Attribute) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Schema_Attribute) ProtoMessage() {}
+
+func (x *Schema_Attribute) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[22]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Schema_Attribute.ProtoReflect.Descriptor instead.
+func (*Schema_Attribute) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{5, 1}
+}
+
+func (x *Schema_Attribute) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *Schema_Attribute) GetType() []byte {
+	if x != nil {
+		return x.Type
+	}
+	return nil
+}
+
+func (x *Schema_Attribute) GetNestedType() *Schema_Object {
+	if x != nil {
+		return x.NestedType
+	}
+	return nil
+}
+
+func (x *Schema_Attribute) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *Schema_Attribute) GetRequired() bool {
+	if x != nil {
+		return x.Required
+	}
+	return false
+}
+
+func (x *Schema_Attribute) GetOptional() bool {
+	if x != nil {
+		return x.Optional
+	}
+	return false
+}
+
+func (x *Schema_Attribute) GetComputed() bool {
+	if x != nil {
+		return x.Computed
+	}
+	return false
+}
+
+func (x *Schema_Attribute) GetSensitive() bool {
+	if x != nil {
+		return x.Sensitive
+	}
+	return false
+}
+
+func (x *Schema_Attribute) GetDescriptionKind() StringKind {
+	if x != nil {
+		return x.DescriptionKind
+	}
+	return StringKind_PLAIN
+}
+
+func (x *Schema_Attribute) GetDeprecated() bool {
+	if x != nil {
+		return x.Deprecated
+	}
+	return false
+}
+
+type Schema_NestedBlock struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName string                         `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	Block    *Schema_Block                  `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"`
+	Nesting  Schema_NestedBlock_NestingMode `protobuf:"varint,3,opt,name=nesting,proto3,enum=tfplugin6.Schema_NestedBlock_NestingMode" json:"nesting,omitempty"`
+	MinItems int64                          `protobuf:"varint,4,opt,name=min_items,json=minItems,proto3" json:"min_items,omitempty"`
+	MaxItems int64                          `protobuf:"varint,5,opt,name=max_items,json=maxItems,proto3" json:"max_items,omitempty"`
+}
+
+func (x *Schema_NestedBlock) Reset() {
+	*x = Schema_NestedBlock{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[23]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Schema_NestedBlock) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Schema_NestedBlock) ProtoMessage() {}
+
+func (x *Schema_NestedBlock) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[23]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Schema_NestedBlock.ProtoReflect.Descriptor instead.
+func (*Schema_NestedBlock) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{5, 2}
+}
+
+func (x *Schema_NestedBlock) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *Schema_NestedBlock) GetBlock() *Schema_Block {
+	if x != nil {
+		return x.Block
+	}
+	return nil
+}
+
+func (x *Schema_NestedBlock) GetNesting() Schema_NestedBlock_NestingMode {
+	if x != nil {
+		return x.Nesting
+	}
+	return Schema_NestedBlock_INVALID
+}
+
+func (x *Schema_NestedBlock) GetMinItems() int64 {
+	if x != nil {
+		return x.MinItems
+	}
+	return 0
+}
+
+func (x *Schema_NestedBlock) GetMaxItems() int64 {
+	if x != nil {
+		return x.MaxItems
+	}
+	return 0
+}
+
+type Schema_Object struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Attributes []*Schema_Attribute       `protobuf:"bytes,1,rep,name=attributes,proto3" json:"attributes,omitempty"`
+	Nesting    Schema_Object_NestingMode `protobuf:"varint,3,opt,name=nesting,proto3,enum=tfplugin6.Schema_Object_NestingMode" json:"nesting,omitempty"`
+	// MinItems and MaxItems were never used in the protocol, and have no
+	// effect on validation.
+	//
+	// Deprecated: Do not use.
+	MinItems int64 `protobuf:"varint,4,opt,name=min_items,json=minItems,proto3" json:"min_items,omitempty"`
+	// Deprecated: Do not use.
+	MaxItems int64 `protobuf:"varint,5,opt,name=max_items,json=maxItems,proto3" json:"max_items,omitempty"`
+}
+
+func (x *Schema_Object) Reset() {
+	*x = Schema_Object{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[24]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Schema_Object) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Schema_Object) ProtoMessage() {}
+
+func (x *Schema_Object) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[24]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Schema_Object.ProtoReflect.Descriptor instead.
+func (*Schema_Object) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{5, 3}
+}
+
+func (x *Schema_Object) GetAttributes() []*Schema_Attribute {
+	if x != nil {
+		return x.Attributes
+	}
+	return nil
+}
+
+func (x *Schema_Object) GetNesting() Schema_Object_NestingMode {
+	if x != nil {
+		return x.Nesting
+	}
+	return Schema_Object_INVALID
+}
+
+// Deprecated: Do not use.
+func (x *Schema_Object) GetMinItems() int64 {
+	if x != nil {
+		return x.MinItems
+	}
+	return 0
+}
+
+// Deprecated: Do not use.
+func (x *Schema_Object) GetMaxItems() int64 {
+	if x != nil {
+		return x.MaxItems
+	}
+	return 0
+}
+
+type GetProviderSchema_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *GetProviderSchema_Request) Reset() {
+	*x = GetProviderSchema_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[25]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetProviderSchema_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetProviderSchema_Request) ProtoMessage() {}
+
+func (x *GetProviderSchema_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[25]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetProviderSchema_Request.ProtoReflect.Descriptor instead.
+func (*GetProviderSchema_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{6, 0}
+}
+
+type GetProviderSchema_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Provider           *Schema                               `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
+	ResourceSchemas    map[string]*Schema                    `protobuf:"bytes,2,rep,name=resource_schemas,json=resourceSchemas,proto3" json:"resource_schemas,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	DataSourceSchemas  map[string]*Schema                    `protobuf:"bytes,3,rep,name=data_source_schemas,json=dataSourceSchemas,proto3" json:"data_source_schemas,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	Diagnostics        []*Diagnostic                         `protobuf:"bytes,4,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+	ProviderMeta       *Schema                               `protobuf:"bytes,5,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"`
+	ServerCapabilities *GetProviderSchema_ServerCapabilities `protobuf:"bytes,6,opt,name=server_capabilities,json=serverCapabilities,proto3" json:"server_capabilities,omitempty"`
+}
+
+func (x *GetProviderSchema_Response) Reset() {
+	*x = GetProviderSchema_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[26]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetProviderSchema_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetProviderSchema_Response) ProtoMessage() {}
+
+func (x *GetProviderSchema_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[26]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetProviderSchema_Response.ProtoReflect.Descriptor instead.
+func (*GetProviderSchema_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{6, 1}
+}
+
+func (x *GetProviderSchema_Response) GetProvider() *Schema {
+	if x != nil {
+		return x.Provider
+	}
+	return nil
+}
+
+func (x *GetProviderSchema_Response) GetResourceSchemas() map[string]*Schema {
+	if x != nil {
+		return x.ResourceSchemas
+	}
+	return nil
+}
+
+func (x *GetProviderSchema_Response) GetDataSourceSchemas() map[string]*Schema {
+	if x != nil {
+		return x.DataSourceSchemas
+	}
+	return nil
+}
+
+func (x *GetProviderSchema_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+func (x *GetProviderSchema_Response) GetProviderMeta() *Schema {
+	if x != nil {
+		return x.ProviderMeta
+	}
+	return nil
+}
+
+func (x *GetProviderSchema_Response) GetServerCapabilities() *GetProviderSchema_ServerCapabilities {
+	if x != nil {
+		return x.ServerCapabilities
+	}
+	return nil
+}
+
+// ServerCapabilities allows providers to communicate extra information
+// regarding supported protocol features. This is used to indicate
+// availability of certain forward-compatible changes which may be optional
+// in a major protocol version, but cannot be tested for directly.
+type GetProviderSchema_ServerCapabilities struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The plan_destroy capability signals that a provider expects a call
+	// to PlanResourceChange when a resource is going to be destroyed.
+	PlanDestroy bool `protobuf:"varint,1,opt,name=plan_destroy,json=planDestroy,proto3" json:"plan_destroy,omitempty"`
+}
+
+func (x *GetProviderSchema_ServerCapabilities) Reset() {
+	*x = GetProviderSchema_ServerCapabilities{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[27]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetProviderSchema_ServerCapabilities) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetProviderSchema_ServerCapabilities) ProtoMessage() {}
+
+func (x *GetProviderSchema_ServerCapabilities) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[27]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetProviderSchema_ServerCapabilities.ProtoReflect.Descriptor instead.
+func (*GetProviderSchema_ServerCapabilities) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{6, 2}
+}
+
+func (x *GetProviderSchema_ServerCapabilities) GetPlanDestroy() bool {
+	if x != nil {
+		return x.PlanDestroy
+	}
+	return false
+}
+
+type ValidateProviderConfig_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Config *DynamicValue `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"`
+}
+
+func (x *ValidateProviderConfig_Request) Reset() {
+	*x = ValidateProviderConfig_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[30]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateProviderConfig_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateProviderConfig_Request) ProtoMessage() {}
+
+func (x *ValidateProviderConfig_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[30]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateProviderConfig_Request.ProtoReflect.Descriptor instead.
+func (*ValidateProviderConfig_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{7, 0}
+}
+
+func (x *ValidateProviderConfig_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+type ValidateProviderConfig_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *ValidateProviderConfig_Response) Reset() {
+	*x = ValidateProviderConfig_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[31]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateProviderConfig_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateProviderConfig_Response) ProtoMessage() {}
+
+func (x *ValidateProviderConfig_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[31]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateProviderConfig_Response.ProtoReflect.Descriptor instead.
+func (*ValidateProviderConfig_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{7, 1}
+}
+
+func (x *ValidateProviderConfig_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+// Request is the message that is sent to the provider during the
+// UpgradeResourceState RPC.
+//
+// This message intentionally does not include configuration data as any
+// configuration-based or configuration-conditional changes should occur
+// during the PlanResourceChange RPC. Additionally, the configuration is
+// not guaranteed to exist (in the case of resource destruction), be wholly
+// known, nor match the given prior state, which could lead to unexpected
+// provider behaviors for practitioners.
+type UpgradeResourceState_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	// version is the schema_version number recorded in the state file
+	Version int64 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"`
+	// raw_state is the raw states as stored for the resource.  Core does
+	// not have access to the schema of prior_version, so it's the
+	// provider's responsibility to interpret this value using the
+	// appropriate older schema. The raw_state will be the json encoded
+	// state, or a legacy flat-mapped format.
+	RawState *RawState `protobuf:"bytes,3,opt,name=raw_state,json=rawState,proto3" json:"raw_state,omitempty"`
+}
+
+func (x *UpgradeResourceState_Request) Reset() {
+	*x = UpgradeResourceState_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[32]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UpgradeResourceState_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpgradeResourceState_Request) ProtoMessage() {}
+
+func (x *UpgradeResourceState_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[32]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpgradeResourceState_Request.ProtoReflect.Descriptor instead.
+func (*UpgradeResourceState_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{8, 0}
+}
+
+func (x *UpgradeResourceState_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *UpgradeResourceState_Request) GetVersion() int64 {
+	if x != nil {
+		return x.Version
+	}
+	return 0
+}
+
+func (x *UpgradeResourceState_Request) GetRawState() *RawState {
+	if x != nil {
+		return x.RawState
+	}
+	return nil
+}
+
+type UpgradeResourceState_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// new_state is a msgpack-encoded data structure that, when interpreted with
+	// the _current_ schema for this resource type, is functionally equivalent to
+	// that which was given in prior_state_raw.
+	UpgradedState *DynamicValue `protobuf:"bytes,1,opt,name=upgraded_state,json=upgradedState,proto3" json:"upgraded_state,omitempty"`
+	// diagnostics describes any errors encountered during migration that could not
+	// be safely resolved, and warnings about any possibly-risky assumptions made
+	// in the upgrade process.
+	Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *UpgradeResourceState_Response) Reset() {
+	*x = UpgradeResourceState_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[33]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UpgradeResourceState_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpgradeResourceState_Response) ProtoMessage() {}
+
+func (x *UpgradeResourceState_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[33]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpgradeResourceState_Response.ProtoReflect.Descriptor instead.
+func (*UpgradeResourceState_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{8, 1}
+}
+
+func (x *UpgradeResourceState_Response) GetUpgradedState() *DynamicValue {
+	if x != nil {
+		return x.UpgradedState
+	}
+	return nil
+}
+
+func (x *UpgradeResourceState_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+type ValidateResourceConfig_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName string        `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	Config   *DynamicValue `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"`
+}
+
+func (x *ValidateResourceConfig_Request) Reset() {
+	*x = ValidateResourceConfig_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[34]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateResourceConfig_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateResourceConfig_Request) ProtoMessage() {}
+
+func (x *ValidateResourceConfig_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[34]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateResourceConfig_Request.ProtoReflect.Descriptor instead.
+func (*ValidateResourceConfig_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{9, 0}
+}
+
+func (x *ValidateResourceConfig_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *ValidateResourceConfig_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+type ValidateResourceConfig_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Diagnostics []*Diagnostic `protobuf:"bytes,1,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *ValidateResourceConfig_Response) Reset() {
+	*x = ValidateResourceConfig_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[35]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateResourceConfig_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateResourceConfig_Response) ProtoMessage() {}
+
+func (x *ValidateResourceConfig_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[35]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateResourceConfig_Response.ProtoReflect.Descriptor instead.
+func (*ValidateResourceConfig_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{9, 1}
+}
+
+func (x *ValidateResourceConfig_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+type ValidateDataResourceConfig_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName string        `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	Config   *DynamicValue `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"`
+}
+
+func (x *ValidateDataResourceConfig_Request) Reset() {
+	*x = ValidateDataResourceConfig_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[36]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateDataResourceConfig_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateDataResourceConfig_Request) ProtoMessage() {}
+
+func (x *ValidateDataResourceConfig_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[36]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateDataResourceConfig_Request.ProtoReflect.Descriptor instead.
+func (*ValidateDataResourceConfig_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{10, 0}
+}
+
+func (x *ValidateDataResourceConfig_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *ValidateDataResourceConfig_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+type ValidateDataResourceConfig_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Diagnostics []*Diagnostic `protobuf:"bytes,1,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *ValidateDataResourceConfig_Response) Reset() {
+	*x = ValidateDataResourceConfig_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[37]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValidateDataResourceConfig_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidateDataResourceConfig_Response) ProtoMessage() {}
+
+func (x *ValidateDataResourceConfig_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[37]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidateDataResourceConfig_Response.ProtoReflect.Descriptor instead.
+func (*ValidateDataResourceConfig_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{10, 1}
+}
+
+func (x *ValidateDataResourceConfig_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+type ConfigureProvider_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TerraformVersion string        `protobuf:"bytes,1,opt,name=terraform_version,json=terraformVersion,proto3" json:"terraform_version,omitempty"`
+	Config           *DynamicValue `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"`
+}
+
+func (x *ConfigureProvider_Request) Reset() {
+	*x = ConfigureProvider_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[38]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ConfigureProvider_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ConfigureProvider_Request) ProtoMessage() {}
+
+func (x *ConfigureProvider_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[38]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ConfigureProvider_Request.ProtoReflect.Descriptor instead.
+func (*ConfigureProvider_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{11, 0}
+}
+
+func (x *ConfigureProvider_Request) GetTerraformVersion() string {
+	if x != nil {
+		return x.TerraformVersion
+	}
+	return ""
+}
+
+func (x *ConfigureProvider_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+type ConfigureProvider_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Diagnostics []*Diagnostic `protobuf:"bytes,1,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *ConfigureProvider_Response) Reset() {
+	*x = ConfigureProvider_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[39]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ConfigureProvider_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ConfigureProvider_Response) ProtoMessage() {}
+
+func (x *ConfigureProvider_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[39]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ConfigureProvider_Response.ProtoReflect.Descriptor instead.
+func (*ConfigureProvider_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{11, 1}
+}
+
+func (x *ConfigureProvider_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+// Request is the message that is sent to the provider during the
+// ReadResource RPC.
+//
+// This message intentionally does not include configuration data as any
+// configuration-based or configuration-conditional changes should occur
+// during the PlanResourceChange RPC. Additionally, the configuration is
+// not guaranteed to be wholly known nor match the given prior state, which
+// could lead to unexpected provider behaviors for practitioners.
+type ReadResource_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName     string        `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	CurrentState *DynamicValue `protobuf:"bytes,2,opt,name=current_state,json=currentState,proto3" json:"current_state,omitempty"`
+	Private      []byte        `protobuf:"bytes,3,opt,name=private,proto3" json:"private,omitempty"`
+	ProviderMeta *DynamicValue `protobuf:"bytes,4,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"`
+}
+
+func (x *ReadResource_Request) Reset() {
+	*x = ReadResource_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[40]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReadResource_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReadResource_Request) ProtoMessage() {}
+
+func (x *ReadResource_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[40]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReadResource_Request.ProtoReflect.Descriptor instead.
+func (*ReadResource_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{12, 0}
+}
+
+func (x *ReadResource_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *ReadResource_Request) GetCurrentState() *DynamicValue {
+	if x != nil {
+		return x.CurrentState
+	}
+	return nil
+}
+
+func (x *ReadResource_Request) GetPrivate() []byte {
+	if x != nil {
+		return x.Private
+	}
+	return nil
+}
+
+func (x *ReadResource_Request) GetProviderMeta() *DynamicValue {
+	if x != nil {
+		return x.ProviderMeta
+	}
+	return nil
+}
+
+type ReadResource_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	NewState    *DynamicValue `protobuf:"bytes,1,opt,name=new_state,json=newState,proto3" json:"new_state,omitempty"`
+	Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+	Private     []byte        `protobuf:"bytes,3,opt,name=private,proto3" json:"private,omitempty"`
+}
+
+func (x *ReadResource_Response) Reset() {
+	*x = ReadResource_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[41]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReadResource_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReadResource_Response) ProtoMessage() {}
+
+func (x *ReadResource_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[41]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReadResource_Response.ProtoReflect.Descriptor instead.
+func (*ReadResource_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{12, 1}
+}
+
+func (x *ReadResource_Response) GetNewState() *DynamicValue {
+	if x != nil {
+		return x.NewState
+	}
+	return nil
+}
+
+func (x *ReadResource_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+func (x *ReadResource_Response) GetPrivate() []byte {
+	if x != nil {
+		return x.Private
+	}
+	return nil
+}
+
+type PlanResourceChange_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName         string        `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	PriorState       *DynamicValue `protobuf:"bytes,2,opt,name=prior_state,json=priorState,proto3" json:"prior_state,omitempty"`
+	ProposedNewState *DynamicValue `protobuf:"bytes,3,opt,name=proposed_new_state,json=proposedNewState,proto3" json:"proposed_new_state,omitempty"`
+	Config           *DynamicValue `protobuf:"bytes,4,opt,name=config,proto3" json:"config,omitempty"`
+	PriorPrivate     []byte        `protobuf:"bytes,5,opt,name=prior_private,json=priorPrivate,proto3" json:"prior_private,omitempty"`
+	ProviderMeta     *DynamicValue `protobuf:"bytes,6,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"`
+}
+
+func (x *PlanResourceChange_Request) Reset() {
+	*x = PlanResourceChange_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[42]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PlanResourceChange_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PlanResourceChange_Request) ProtoMessage() {}
+
+func (x *PlanResourceChange_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[42]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PlanResourceChange_Request.ProtoReflect.Descriptor instead.
+func (*PlanResourceChange_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{13, 0}
+}
+
+func (x *PlanResourceChange_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *PlanResourceChange_Request) GetPriorState() *DynamicValue {
+	if x != nil {
+		return x.PriorState
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Request) GetProposedNewState() *DynamicValue {
+	if x != nil {
+		return x.ProposedNewState
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Request) GetPriorPrivate() []byte {
+	if x != nil {
+		return x.PriorPrivate
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Request) GetProviderMeta() *DynamicValue {
+	if x != nil {
+		return x.ProviderMeta
+	}
+	return nil
+}
+
+type PlanResourceChange_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	PlannedState    *DynamicValue    `protobuf:"bytes,1,opt,name=planned_state,json=plannedState,proto3" json:"planned_state,omitempty"`
+	RequiresReplace []*AttributePath `protobuf:"bytes,2,rep,name=requires_replace,json=requiresReplace,proto3" json:"requires_replace,omitempty"`
+	PlannedPrivate  []byte           `protobuf:"bytes,3,opt,name=planned_private,json=plannedPrivate,proto3" json:"planned_private,omitempty"`
+	Diagnostics     []*Diagnostic    `protobuf:"bytes,4,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+	// This may be set only by the helper/schema "SDK" in the main Terraform
+	// repository, to request that Terraform Core >=0.12 permit additional
+	// inconsistencies that can result from the legacy SDK type system
+	// and its imprecise mapping to the >=0.12 type system.
+	// The change in behavior implied by this flag makes sense only for the
+	// specific details of the legacy SDK type system, and are not a general
+	// mechanism to avoid proper type handling in providers.
+	//
+	//	====              DO NOT USE THIS              ====
+	//	==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+	//	====              DO NOT USE THIS              ====
+	LegacyTypeSystem bool `protobuf:"varint,5,opt,name=legacy_type_system,json=legacyTypeSystem,proto3" json:"legacy_type_system,omitempty"`
+}
+
+func (x *PlanResourceChange_Response) Reset() {
+	*x = PlanResourceChange_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[43]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PlanResourceChange_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PlanResourceChange_Response) ProtoMessage() {}
+
+func (x *PlanResourceChange_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[43]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PlanResourceChange_Response.ProtoReflect.Descriptor instead.
+func (*PlanResourceChange_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{13, 1}
+}
+
+func (x *PlanResourceChange_Response) GetPlannedState() *DynamicValue {
+	if x != nil {
+		return x.PlannedState
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Response) GetRequiresReplace() []*AttributePath {
+	if x != nil {
+		return x.RequiresReplace
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Response) GetPlannedPrivate() []byte {
+	if x != nil {
+		return x.PlannedPrivate
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+func (x *PlanResourceChange_Response) GetLegacyTypeSystem() bool {
+	if x != nil {
+		return x.LegacyTypeSystem
+	}
+	return false
+}
+
+type ApplyResourceChange_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName       string        `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	PriorState     *DynamicValue `protobuf:"bytes,2,opt,name=prior_state,json=priorState,proto3" json:"prior_state,omitempty"`
+	PlannedState   *DynamicValue `protobuf:"bytes,3,opt,name=planned_state,json=plannedState,proto3" json:"planned_state,omitempty"`
+	Config         *DynamicValue `protobuf:"bytes,4,opt,name=config,proto3" json:"config,omitempty"`
+	PlannedPrivate []byte        `protobuf:"bytes,5,opt,name=planned_private,json=plannedPrivate,proto3" json:"planned_private,omitempty"`
+	ProviderMeta   *DynamicValue `protobuf:"bytes,6,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"`
+}
+
+func (x *ApplyResourceChange_Request) Reset() {
+	*x = ApplyResourceChange_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[44]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ApplyResourceChange_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ApplyResourceChange_Request) ProtoMessage() {}
+
+func (x *ApplyResourceChange_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[44]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ApplyResourceChange_Request.ProtoReflect.Descriptor instead.
+func (*ApplyResourceChange_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{14, 0}
+}
+
+func (x *ApplyResourceChange_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *ApplyResourceChange_Request) GetPriorState() *DynamicValue {
+	if x != nil {
+		return x.PriorState
+	}
+	return nil
+}
+
+func (x *ApplyResourceChange_Request) GetPlannedState() *DynamicValue {
+	if x != nil {
+		return x.PlannedState
+	}
+	return nil
+}
+
+func (x *ApplyResourceChange_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+func (x *ApplyResourceChange_Request) GetPlannedPrivate() []byte {
+	if x != nil {
+		return x.PlannedPrivate
+	}
+	return nil
+}
+
+func (x *ApplyResourceChange_Request) GetProviderMeta() *DynamicValue {
+	if x != nil {
+		return x.ProviderMeta
+	}
+	return nil
+}
+
+type ApplyResourceChange_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	NewState    *DynamicValue `protobuf:"bytes,1,opt,name=new_state,json=newState,proto3" json:"new_state,omitempty"`
+	Private     []byte        `protobuf:"bytes,2,opt,name=private,proto3" json:"private,omitempty"`
+	Diagnostics []*Diagnostic `protobuf:"bytes,3,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+	// This may be set only by the helper/schema "SDK" in the main Terraform
+	// repository, to request that Terraform Core >=0.12 permit additional
+	// inconsistencies that can result from the legacy SDK type system
+	// and its imprecise mapping to the >=0.12 type system.
+	// The change in behavior implied by this flag makes sense only for the
+	// specific details of the legacy SDK type system, and are not a general
+	// mechanism to avoid proper type handling in providers.
+	//
+	//	====              DO NOT USE THIS              ====
+	//	==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
+	//	====              DO NOT USE THIS              ====
+	LegacyTypeSystem bool `protobuf:"varint,4,opt,name=legacy_type_system,json=legacyTypeSystem,proto3" json:"legacy_type_system,omitempty"`
+}
+
+func (x *ApplyResourceChange_Response) Reset() {
+	*x = ApplyResourceChange_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[45]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ApplyResourceChange_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ApplyResourceChange_Response) ProtoMessage() {}
+
+func (x *ApplyResourceChange_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[45]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ApplyResourceChange_Response.ProtoReflect.Descriptor instead.
+func (*ApplyResourceChange_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{14, 1}
+}
+
+func (x *ApplyResourceChange_Response) GetNewState() *DynamicValue {
+	if x != nil {
+		return x.NewState
+	}
+	return nil
+}
+
+func (x *ApplyResourceChange_Response) GetPrivate() []byte {
+	if x != nil {
+		return x.Private
+	}
+	return nil
+}
+
+func (x *ApplyResourceChange_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+func (x *ApplyResourceChange_Response) GetLegacyTypeSystem() bool {
+	if x != nil {
+		return x.LegacyTypeSystem
+	}
+	return false
+}
+
+type ImportResourceState_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	Id       string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
+}
+
+func (x *ImportResourceState_Request) Reset() {
+	*x = ImportResourceState_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[46]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ImportResourceState_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ImportResourceState_Request) ProtoMessage() {}
+
+func (x *ImportResourceState_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[46]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ImportResourceState_Request.ProtoReflect.Descriptor instead.
+func (*ImportResourceState_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{15, 0}
+}
+
+func (x *ImportResourceState_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *ImportResourceState_Request) GetId() string {
+	if x != nil {
+		return x.Id
+	}
+	return ""
+}
+
+type ImportResourceState_ImportedResource struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName string        `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	State    *DynamicValue `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
+	Private  []byte        `protobuf:"bytes,3,opt,name=private,proto3" json:"private,omitempty"`
+}
+
+func (x *ImportResourceState_ImportedResource) Reset() {
+	*x = ImportResourceState_ImportedResource{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[47]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ImportResourceState_ImportedResource) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ImportResourceState_ImportedResource) ProtoMessage() {}
+
+func (x *ImportResourceState_ImportedResource) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[47]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ImportResourceState_ImportedResource.ProtoReflect.Descriptor instead.
+func (*ImportResourceState_ImportedResource) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{15, 1}
+}
+
+func (x *ImportResourceState_ImportedResource) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *ImportResourceState_ImportedResource) GetState() *DynamicValue {
+	if x != nil {
+		return x.State
+	}
+	return nil
+}
+
+func (x *ImportResourceState_ImportedResource) GetPrivate() []byte {
+	if x != nil {
+		return x.Private
+	}
+	return nil
+}
+
+type ImportResourceState_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	ImportedResources []*ImportResourceState_ImportedResource `protobuf:"bytes,1,rep,name=imported_resources,json=importedResources,proto3" json:"imported_resources,omitempty"`
+	Diagnostics       []*Diagnostic                           `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *ImportResourceState_Response) Reset() {
+	*x = ImportResourceState_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[48]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ImportResourceState_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ImportResourceState_Response) ProtoMessage() {}
+
+func (x *ImportResourceState_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[48]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ImportResourceState_Response.ProtoReflect.Descriptor instead.
+func (*ImportResourceState_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{15, 2}
+}
+
+func (x *ImportResourceState_Response) GetImportedResources() []*ImportResourceState_ImportedResource {
+	if x != nil {
+		return x.ImportedResources
+	}
+	return nil
+}
+
+func (x *ImportResourceState_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+type ReadDataSource_Request struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TypeName     string        `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"`
+	Config       *DynamicValue `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"`
+	ProviderMeta *DynamicValue `protobuf:"bytes,3,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"`
+}
+
+func (x *ReadDataSource_Request) Reset() {
+	*x = ReadDataSource_Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[49]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReadDataSource_Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReadDataSource_Request) ProtoMessage() {}
+
+func (x *ReadDataSource_Request) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[49]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReadDataSource_Request.ProtoReflect.Descriptor instead.
+func (*ReadDataSource_Request) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{16, 0}
+}
+
+func (x *ReadDataSource_Request) GetTypeName() string {
+	if x != nil {
+		return x.TypeName
+	}
+	return ""
+}
+
+func (x *ReadDataSource_Request) GetConfig() *DynamicValue {
+	if x != nil {
+		return x.Config
+	}
+	return nil
+}
+
+func (x *ReadDataSource_Request) GetProviderMeta() *DynamicValue {
+	if x != nil {
+		return x.ProviderMeta
+	}
+	return nil
+}
+
+type ReadDataSource_Response struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	State       *DynamicValue `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"`
+	Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
+}
+
+func (x *ReadDataSource_Response) Reset() {
+	*x = ReadDataSource_Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_tfplugin6_proto_msgTypes[50]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReadDataSource_Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReadDataSource_Response) ProtoMessage() {}
+
+func (x *ReadDataSource_Response) ProtoReflect() protoreflect.Message {
+	mi := &file_tfplugin6_proto_msgTypes[50]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReadDataSource_Response.ProtoReflect.Descriptor instead.
+func (*ReadDataSource_Response) Descriptor() ([]byte, []int) {
+	return file_tfplugin6_proto_rawDescGZIP(), []int{16, 1}
+}
+
+func (x *ReadDataSource_Response) GetState() *DynamicValue {
+	if x != nil {
+		return x.State
+	}
+	return nil
+}
+
+func (x *ReadDataSource_Response) GetDiagnostics() []*Diagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
+var File_tfplugin6_proto protoreflect.FileDescriptor
+
+var file_tfplugin6_proto_rawDesc = []byte{
+	0x0a, 0x0f, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x12, 0x09, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x22, 0x3c, 0x0a, 0x0c,
+	0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07,
+	0x6d, 0x73, 0x67, 0x70, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d,
+	0x73, 0x67, 0x70, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x22, 0xe3, 0x01, 0x0a, 0x0a, 0x44,
+	0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x12, 0x3a, 0x0a, 0x08, 0x73, 0x65, 0x76,
+	0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, 0x66,
+	0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74,
+	0x69, 0x63, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x76,
+	0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12,
+	0x16, 0x0a, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x36, 0x0a, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69,
+	0x62, 0x75, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
+	0x50, 0x61, 0x74, 0x68, 0x52, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x22,
+	0x2f, 0x0a, 0x08, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0b, 0x0a, 0x07, 0x49,
+	0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f,
+	0x52, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x02,
+	0x22, 0xdc, 0x01, 0x0a, 0x0d, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x50, 0x61,
+	0x74, 0x68, 0x12, 0x33, 0x0a, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x41, 0x74,
+	0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x2e, 0x53, 0x74, 0x65, 0x70,
+	0x52, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x1a, 0x95, 0x01, 0x0a, 0x04, 0x53, 0x74, 0x65, 0x70,
+	0x12, 0x27, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x6e, 0x61,
+	0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72,
+	0x69, 0x62, 0x75, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x65, 0x6c, 0x65,
+	0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74,
+	0x4b, 0x65, 0x79, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x28, 0x0a, 0x0f, 0x65, 0x6c, 0x65,
+	0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x03, 0x48, 0x00, 0x52, 0x0d, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79,
+	0x49, 0x6e, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22,
+	0x3b, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x70, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x1a,
+	0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x0a, 0x08, 0x52, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x96, 0x01, 0x0a,
+	0x08, 0x52, 0x61, 0x77, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6a, 0x73, 0x6f,
+	0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x12, 0x3a, 0x0a,
+	0x07, 0x66, 0x6c, 0x61, 0x74, 0x6d, 0x61, 0x70, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20,
+	0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x52, 0x61, 0x77, 0x53, 0x74,
+	0x61, 0x74, 0x65, 0x2e, 0x46, 0x6c, 0x61, 0x74, 0x6d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x52, 0x07, 0x66, 0x6c, 0x61, 0x74, 0x6d, 0x61, 0x70, 0x1a, 0x3a, 0x0a, 0x0c, 0x46, 0x6c, 0x61,
+	0x74, 0x6d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
+	0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x95, 0x0a, 0x0a, 0x06, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61,
+	0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c,
+	0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c,
+	0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x42, 0x6c, 0x6f,
+	0x63, 0x6b, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x1a, 0xa2, 0x02, 0x0a, 0x05, 0x42, 0x6c,
+	0x6f, 0x63, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a,
+	0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63,
+	0x68, 0x65, 0x6d, 0x61, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x0a,
+	0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x0b, 0x62, 0x6c,
+	0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x1d, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x61, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x0a,
+	0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65,
+	0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x10,
+	0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x69, 0x6e, 0x64,
+	0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69,
+	0x6e, 0x36, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x0f, 0x64,
+	0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1e,
+	0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01,
+	0x28, 0x08, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x1a, 0xe4,
+	0x02, 0x0a, 0x09, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04,
+	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+	0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04,
+	0x74, 0x79, 0x70, 0x65, 0x12, 0x39, 0x0a, 0x0b, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x74,
+	0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x66, 0x70, 0x6c,
+	0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4f, 0x62, 0x6a,
+	0x65, 0x63, 0x74, 0x52, 0x0a, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12,
+	0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20,
+	0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x1a, 0x0a,
+	0x08, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52,
+	0x08, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6d,
+	0x70, 0x75, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x6f, 0x6d,
+	0x70, 0x75, 0x74, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69,
+	0x76, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74,
+	0x69, 0x76, 0x65, 0x12, 0x40, 0x0a, 0x10, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e,
+	0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67,
+	0x4b, 0x69, 0x6e, 0x64, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61,
+	0x74, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65,
+	0x63, 0x61, 0x74, 0x65, 0x64, 0x1a, 0xa7, 0x02, 0x0a, 0x0b, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64,
+	0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61,
+	0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61,
+	0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63,
+	0x68, 0x65, 0x6d, 0x61, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63,
+	0x6b, 0x12, 0x43, 0x0a, 0x07, 0x6e, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x0e, 0x32, 0x29, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53,
+	0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63,
+	0x6b, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x07, 0x6e,
+	0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x69, 0x74,
+	0x65, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x49, 0x74,
+	0x65, 0x6d, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73,
+	0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x49, 0x74, 0x65, 0x6d, 0x73,
+	0x22, 0x4d, 0x0a, 0x0b, 0x4e, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x12,
+	0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06,
+	0x53, 0x49, 0x4e, 0x47, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x49, 0x53, 0x54,
+	0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x53, 0x45, 0x54, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x4d,
+	0x41, 0x50, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x10, 0x05, 0x1a,
+	0x8b, 0x02, 0x0a, 0x06, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x3b, 0x0a, 0x0a, 0x61, 0x74,
+	0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b,
+	0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d,
+	0x61, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74,
+	0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x07, 0x6e, 0x65, 0x73, 0x74, 0x69,
+	0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75,
+	0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4f, 0x62, 0x6a, 0x65,
+	0x63, 0x74, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x07,
+	0x6e, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x69,
+	0x74, 0x65, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x08,
+	0x6d, 0x69, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x1f, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f,
+	0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52,
+	0x08, 0x6d, 0x61, 0x78, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x42, 0x0a, 0x0b, 0x4e, 0x65, 0x73,
+	0x74, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41,
+	0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x49, 0x4e, 0x47, 0x4c, 0x45, 0x10,
+	0x01, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x53,
+	0x45, 0x54, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x41, 0x50, 0x10, 0x04, 0x22, 0xeb, 0x05,
+	0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68,
+	0x65, 0x6d, 0x61, 0x1a, 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x91,
+	0x05, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x08, 0x70,
+	0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e,
+	0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61,
+	0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x65, 0x0a, 0x10, 0x72, 0x65,
+	0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x02,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36,
+	0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f,
+	0x75, 0x72, 0x63, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61,
+	0x73, 0x12, 0x6c, 0x0a, 0x13, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+	0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3c,
+	0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72,
+	0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65,
+	0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x64, 0x61,
+	0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x12,
+	0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x04,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36,
+	0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61,
+	0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x36, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x76,
+	0x69, 0x64, 0x65, 0x72, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x11, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x61, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61,
+	0x12, 0x60, 0x0a, 0x13, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x61, 0x70, 0x61, 0x62,
+	0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e,
+	0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f,
+	0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x76,
+	0x65, 0x72, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x12,
+	0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69,
+	0x65, 0x73, 0x1a, 0x55, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x63,
+	0x68, 0x65, 0x6d, 0x61, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
+	0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66,
+	0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x57, 0x0a, 0x16, 0x44, 0x61, 0x74,
+	0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x45, 0x6e,
+	0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36,
+	0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
+	0x38, 0x01, 0x1a, 0x37, 0x0a, 0x12, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x61, 0x70, 0x61,
+	0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x6c, 0x61, 0x6e,
+	0x5f, 0x64, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b,
+	0x70, 0x6c, 0x61, 0x6e, 0x44, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x79, 0x22, 0x99, 0x01, 0x0a, 0x16,
+	0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
+	0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x3a, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79,
+	0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66,
+	0x69, 0x67, 0x1a, 0x43, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37,
+	0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e,
+	0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67,
+	0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x22, 0x90, 0x02, 0x0a, 0x14, 0x55, 0x70, 0x67, 0x72,
+	0x61, 0x64, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65,
+	0x1a, 0x72, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74,
+	0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+	0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73,
+	0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
+	0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x09, 0x72, 0x61, 0x77, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
+	0x36, 0x2e, 0x52, 0x61, 0x77, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x08, 0x72, 0x61, 0x77, 0x53,
+	0x74, 0x61, 0x74, 0x65, 0x1a, 0x83, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x12, 0x3e, 0x0a, 0x0e, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x74,
+	0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c,
+	0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c,
+	0x75, 0x65, 0x52, 0x0d, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74,
+	0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73,
+	0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69,
+	0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64,
+	0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x22, 0xb6, 0x01, 0x0a, 0x16, 0x56,
+	0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43,
+	0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x57, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a,
+	0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
+	0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69,
+	0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x43,
+	0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69,
+	0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, 0x67,
+	0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74,
+	0x69, 0x63, 0x73, 0x22, 0xba, 0x01, 0x0a, 0x1a, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65,
+	0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66,
+	0x69, 0x67, 0x1a, 0x57, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a,
+	0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f,
+	0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61,
+	0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x43, 0x0a, 0x08, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e,
+	0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74,
+	0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73,
+	0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73,
+	0x22, 0xc1, 0x01, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x50, 0x72,
+	0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x1a, 0x67, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x2b, 0x0a, 0x11, 0x74, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x76,
+	0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x74, 0x65,
+	0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2f,
+	0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17,
+	0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d,
+	0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a,
+	0x43, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64,
+	0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61,
+	0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73,
+	0x74, 0x69, 0x63, 0x73, 0x22, 0xe3, 0x02, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73,
+	0x6f, 0x75, 0x72, 0x63, 0x65, 0x1a, 0xbc, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3c,
+	0x0a, 0x0d, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
+	0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c,
+	0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07,
+	0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70,
+	0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64,
+	0x65, 0x72, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
+	0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69,
+	0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
+	0x4d, 0x65, 0x74, 0x61, 0x1a, 0x93, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x12, 0x34, 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36,
+	0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6e,
+	0x65, 0x77, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e,
+	0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74,
+	0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73,
+	0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73,
+	0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x0c, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x22, 0xf2, 0x04, 0x0a, 0x12, 0x50,
+	0x6c, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67,
+	0x65, 0x1a, 0xbb, 0x02, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a,
+	0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x70, 0x72,
+	0x69, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61,
+	0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x53,
+	0x74, 0x61, 0x74, 0x65, 0x12, 0x45, 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x64,
+	0x5f, 0x6e, 0x65, 0x77, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e,
+	0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x70, 0x6f,
+	0x73, 0x65, 0x64, 0x4e, 0x65, 0x77, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63,
+	0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66,
+	0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56,
+	0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x0a, 0x0d,
+	0x70, 0x72, 0x69, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x0c, 0x52, 0x0c, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74,
+	0x65, 0x12, 0x3c, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x6d, 0x65,
+	0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75,
+	0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75,
+	0x65, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x1a,
+	0x9d, 0x02, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x0d,
+	0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e,
+	0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x70, 0x6c,
+	0x61, 0x6e, 0x6e, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x43, 0x0a, 0x10, 0x72, 0x65,
+	0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x18, 0x02,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36,
+	0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x52, 0x0f,
+	0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x12,
+	0x27, 0x0a, 0x0f, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61,
+	0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x65,
+	0x64, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67,
+	0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e,
+	0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f,
+	0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63,
+	0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65,
+	0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x6c,
+	0x65, 0x67, 0x61, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x22,
+	0x92, 0x04, 0x0a, 0x13, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+	0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x1a, 0xb6, 0x02, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65,
+	0x12, 0x38, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
+	0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a,
+	0x70, 0x72, 0x69, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x0d, 0x70, 0x6c,
+	0x61, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79,
+	0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x70, 0x6c, 0x61, 0x6e,
+	0x6e, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66,
+	0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75,
+	0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75,
+	0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x6c, 0x61,
+	0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01,
+	0x28, 0x0c, 0x52, 0x0e, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x50, 0x72, 0x69, 0x76, 0x61,
+	0x74, 0x65, 0x12, 0x3c, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x6d,
+	0x65, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c,
+	0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c,
+	0x75, 0x65, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61,
+	0x1a, 0xc1, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a,
+	0x09, 0x6e, 0x65, 0x77, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e,
+	0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6e, 0x65, 0x77, 0x53, 0x74,
+	0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a,
+	0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44,
+	0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e,
+	0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79,
+	0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x04, 0x20, 0x01,
+	0x28, 0x08, 0x52, 0x10, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x53, 0x79,
+	0x73, 0x74, 0x65, 0x6d, 0x22, 0xed, 0x02, 0x0a, 0x13, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52,
+	0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x36, 0x0a, 0x07,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f,
+	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65,
+	0x4e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x02, 0x69, 0x64, 0x1a, 0x78, 0x0a, 0x10, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64,
+	0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65,
+	0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70,
+	0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36,
+	0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x73,
+	0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x1a, 0xa3,
+	0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x12, 0x69,
+	0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+	0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67,
+	0x69, 0x6e, 0x36, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
+	0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64,
+	0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x11, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74,
+	0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0b, 0x64,
+	0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61,
+	0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73,
+	0x74, 0x69, 0x63, 0x73, 0x22, 0x9c, 0x02, 0x0a, 0x0e, 0x52, 0x65, 0x61, 0x64, 0x44, 0x61, 0x74,
+	0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x1a, 0x95, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65,
+	0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e,
+	0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69,
+	0x67, 0x12, 0x3c, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x6d, 0x65,
+	0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75,
+	0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75,
+	0x65, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x1a,
+	0x72, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x73,
+	0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70,
+	0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61,
+	0x6c, 0x75, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69,
+	0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, 0x67,
+	0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74,
+	0x69, 0x63, 0x73, 0x2a, 0x25, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4b, 0x69, 0x6e,
+	0x64, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08,
+	0x4d, 0x41, 0x52, 0x4b, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x01, 0x32, 0xcc, 0x09, 0x0a, 0x08, 0x50,
+	0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x60, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x72,
+	0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x24, 0x2e, 0x74,
+	0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76,
+	0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x25, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x47,
+	0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61,
+	0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x16, 0x56, 0x61, 0x6c,
+	0x69, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x12, 0x29, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e,
+	0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
+	0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a,
+	0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64,
+	0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+	0x67, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x16, 0x56, 0x61,
+	0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f,
+	0x6e, 0x66, 0x69, 0x67, 0x12, 0x29, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36,
+	0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+	0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x2a, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x56, 0x61, 0x6c, 0x69,
+	0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66,
+	0x69, 0x67, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1a, 0x56,
+	0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x6f, 0x75,
+	0x72, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x2e, 0x74, 0x66, 0x70, 0x6c,
+	0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61,
+	0x74, 0x61, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+	0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75,
+	0x67, 0x69, 0x6e, 0x36, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74,
+	0x61, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x14, 0x55, 0x70, 0x67, 0x72,
+	0x61, 0x64, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65,
+	0x12, 0x27, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x55, 0x70, 0x67,
+	0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74,
+	0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x74, 0x66, 0x70, 0x6c,
+	0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x73,
+	0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65,
+	0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x24, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75,
+	0x67, 0x69, 0x6e, 0x36, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x50, 0x72,
+	0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25,
+	0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+	0x67, 0x75, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73,
+	0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1f, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
+	0x36, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69,
+	0x6e, 0x36, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x12, 0x50, 0x6c, 0x61, 0x6e,
+	0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x25,
+	0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x52,
+	0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
+	0x36, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68,
+	0x61, 0x6e, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a,
+	0x13, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68,
+	0x61, 0x6e, 0x67, 0x65, 0x12, 0x26, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36,
+	0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68,
+	0x61, 0x6e, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74,
+	0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65,
+	0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x13, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52,
+	0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x26, 0x2e, 0x74,
+	0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52,
+	0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36,
+	0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53,
+	0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a,
+	0x0e, 0x52, 0x65, 0x61, 0x64, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12,
+	0x21, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x52, 0x65, 0x61, 0x64,
+	0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x22, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x52,
+	0x65, 0x61, 0x64, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x70, 0x50, 0x72,
+	0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69,
+	0x6e, 0x36, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67,
+	0x69, 0x6e, 0x36, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
+	0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74,
+	0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72,
+	0x70, 0x2f, 0x74, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x69, 0x6e, 0x74, 0x65,
+	0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x62, 0x06,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_tfplugin6_proto_rawDescOnce sync.Once
+	file_tfplugin6_proto_rawDescData = file_tfplugin6_proto_rawDesc
+)
+
+func file_tfplugin6_proto_rawDescGZIP() []byte {
+	file_tfplugin6_proto_rawDescOnce.Do(func() {
+		file_tfplugin6_proto_rawDescData = protoimpl.X.CompressGZIP(file_tfplugin6_proto_rawDescData)
+	})
+	return file_tfplugin6_proto_rawDescData
+}
+
+var file_tfplugin6_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
+var file_tfplugin6_proto_msgTypes = make([]protoimpl.MessageInfo, 51)
+var file_tfplugin6_proto_goTypes = []interface{}{
+	(StringKind)(0),                              // 0: tfplugin6.StringKind
+	(Diagnostic_Severity)(0),                     // 1: tfplugin6.Diagnostic.Severity
+	(Schema_NestedBlock_NestingMode)(0),          // 2: tfplugin6.Schema.NestedBlock.NestingMode
+	(Schema_Object_NestingMode)(0),               // 3: tfplugin6.Schema.Object.NestingMode
+	(*DynamicValue)(nil),                         // 4: tfplugin6.DynamicValue
+	(*Diagnostic)(nil),                           // 5: tfplugin6.Diagnostic
+	(*AttributePath)(nil),                        // 6: tfplugin6.AttributePath
+	(*StopProvider)(nil),                         // 7: tfplugin6.StopProvider
+	(*RawState)(nil),                             // 8: tfplugin6.RawState
+	(*Schema)(nil),                               // 9: tfplugin6.Schema
+	(*GetProviderSchema)(nil),                    // 10: tfplugin6.GetProviderSchema
+	(*ValidateProviderConfig)(nil),               // 11: tfplugin6.ValidateProviderConfig
+	(*UpgradeResourceState)(nil),                 // 12: tfplugin6.UpgradeResourceState
+	(*ValidateResourceConfig)(nil),               // 13: tfplugin6.ValidateResourceConfig
+	(*ValidateDataResourceConfig)(nil),           // 14: tfplugin6.ValidateDataResourceConfig
+	(*ConfigureProvider)(nil),                    // 15: tfplugin6.ConfigureProvider
+	(*ReadResource)(nil),                         // 16: tfplugin6.ReadResource
+	(*PlanResourceChange)(nil),                   // 17: tfplugin6.PlanResourceChange
+	(*ApplyResourceChange)(nil),                  // 18: tfplugin6.ApplyResourceChange
+	(*ImportResourceState)(nil),                  // 19: tfplugin6.ImportResourceState
+	(*ReadDataSource)(nil),                       // 20: tfplugin6.ReadDataSource
+	(*AttributePath_Step)(nil),                   // 21: tfplugin6.AttributePath.Step
+	(*StopProvider_Request)(nil),                 // 22: tfplugin6.StopProvider.Request
+	(*StopProvider_Response)(nil),                // 23: tfplugin6.StopProvider.Response
+	nil,                                          // 24: tfplugin6.RawState.FlatmapEntry
+	(*Schema_Block)(nil),                         // 25: tfplugin6.Schema.Block
+	(*Schema_Attribute)(nil),                     // 26: tfplugin6.Schema.Attribute
+	(*Schema_NestedBlock)(nil),                   // 27: tfplugin6.Schema.NestedBlock
+	(*Schema_Object)(nil),                        // 28: tfplugin6.Schema.Object
+	(*GetProviderSchema_Request)(nil),            // 29: tfplugin6.GetProviderSchema.Request
+	(*GetProviderSchema_Response)(nil),           // 30: tfplugin6.GetProviderSchema.Response
+	(*GetProviderSchema_ServerCapabilities)(nil), // 31: tfplugin6.GetProviderSchema.ServerCapabilities
+	nil,                                          // 32: tfplugin6.GetProviderSchema.Response.ResourceSchemasEntry
+	nil,                                          // 33: tfplugin6.GetProviderSchema.Response.DataSourceSchemasEntry
+	(*ValidateProviderConfig_Request)(nil),       // 34: tfplugin6.ValidateProviderConfig.Request
+	(*ValidateProviderConfig_Response)(nil),      // 35: tfplugin6.ValidateProviderConfig.Response
+	(*UpgradeResourceState_Request)(nil),         // 36: tfplugin6.UpgradeResourceState.Request
+	(*UpgradeResourceState_Response)(nil),        // 37: tfplugin6.UpgradeResourceState.Response
+	(*ValidateResourceConfig_Request)(nil),       // 38: tfplugin6.ValidateResourceConfig.Request
+	(*ValidateResourceConfig_Response)(nil),      // 39: tfplugin6.ValidateResourceConfig.Response
+	(*ValidateDataResourceConfig_Request)(nil),   // 40: tfplugin6.ValidateDataResourceConfig.Request
+	(*ValidateDataResourceConfig_Response)(nil),  // 41: tfplugin6.ValidateDataResourceConfig.Response
+	(*ConfigureProvider_Request)(nil),            // 42: tfplugin6.ConfigureProvider.Request
+	(*ConfigureProvider_Response)(nil),           // 43: tfplugin6.ConfigureProvider.Response
+	(*ReadResource_Request)(nil),                 // 44: tfplugin6.ReadResource.Request
+	(*ReadResource_Response)(nil),                // 45: tfplugin6.ReadResource.Response
+	(*PlanResourceChange_Request)(nil),           // 46: tfplugin6.PlanResourceChange.Request
+	(*PlanResourceChange_Response)(nil),          // 47: tfplugin6.PlanResourceChange.Response
+	(*ApplyResourceChange_Request)(nil),          // 48: tfplugin6.ApplyResourceChange.Request
+	(*ApplyResourceChange_Response)(nil),         // 49: tfplugin6.ApplyResourceChange.Response
+	(*ImportResourceState_Request)(nil),          // 50: tfplugin6.ImportResourceState.Request
+	(*ImportResourceState_ImportedResource)(nil), // 51: tfplugin6.ImportResourceState.ImportedResource
+	(*ImportResourceState_Response)(nil),         // 52: tfplugin6.ImportResourceState.Response
+	(*ReadDataSource_Request)(nil),               // 53: tfplugin6.ReadDataSource.Request
+	(*ReadDataSource_Response)(nil),              // 54: tfplugin6.ReadDataSource.Response
+}
+var file_tfplugin6_proto_depIdxs = []int32{
+	1,  // 0: tfplugin6.Diagnostic.severity:type_name -> tfplugin6.Diagnostic.Severity
+	6,  // 1: tfplugin6.Diagnostic.attribute:type_name -> tfplugin6.AttributePath
+	21, // 2: tfplugin6.AttributePath.steps:type_name -> tfplugin6.AttributePath.Step
+	24, // 3: tfplugin6.RawState.flatmap:type_name -> tfplugin6.RawState.FlatmapEntry
+	25, // 4: tfplugin6.Schema.block:type_name -> tfplugin6.Schema.Block
+	26, // 5: tfplugin6.Schema.Block.attributes:type_name -> tfplugin6.Schema.Attribute
+	27, // 6: tfplugin6.Schema.Block.block_types:type_name -> tfplugin6.Schema.NestedBlock
+	0,  // 7: tfplugin6.Schema.Block.description_kind:type_name -> tfplugin6.StringKind
+	28, // 8: tfplugin6.Schema.Attribute.nested_type:type_name -> tfplugin6.Schema.Object
+	0,  // 9: tfplugin6.Schema.Attribute.description_kind:type_name -> tfplugin6.StringKind
+	25, // 10: tfplugin6.Schema.NestedBlock.block:type_name -> tfplugin6.Schema.Block
+	2,  // 11: tfplugin6.Schema.NestedBlock.nesting:type_name -> tfplugin6.Schema.NestedBlock.NestingMode
+	26, // 12: tfplugin6.Schema.Object.attributes:type_name -> tfplugin6.Schema.Attribute
+	3,  // 13: tfplugin6.Schema.Object.nesting:type_name -> tfplugin6.Schema.Object.NestingMode
+	9,  // 14: tfplugin6.GetProviderSchema.Response.provider:type_name -> tfplugin6.Schema
+	32, // 15: tfplugin6.GetProviderSchema.Response.resource_schemas:type_name -> tfplugin6.GetProviderSchema.Response.ResourceSchemasEntry
+	33, // 16: tfplugin6.GetProviderSchema.Response.data_source_schemas:type_name -> tfplugin6.GetProviderSchema.Response.DataSourceSchemasEntry
+	5,  // 17: tfplugin6.GetProviderSchema.Response.diagnostics:type_name -> tfplugin6.Diagnostic
+	9,  // 18: tfplugin6.GetProviderSchema.Response.provider_meta:type_name -> tfplugin6.Schema
+	31, // 19: tfplugin6.GetProviderSchema.Response.server_capabilities:type_name -> tfplugin6.GetProviderSchema.ServerCapabilities
+	9,  // 20: tfplugin6.GetProviderSchema.Response.ResourceSchemasEntry.value:type_name -> tfplugin6.Schema
+	9,  // 21: tfplugin6.GetProviderSchema.Response.DataSourceSchemasEntry.value:type_name -> tfplugin6.Schema
+	4,  // 22: tfplugin6.ValidateProviderConfig.Request.config:type_name -> tfplugin6.DynamicValue
+	5,  // 23: tfplugin6.ValidateProviderConfig.Response.diagnostics:type_name -> tfplugin6.Diagnostic
+	8,  // 24: tfplugin6.UpgradeResourceState.Request.raw_state:type_name -> tfplugin6.RawState
+	4,  // 25: tfplugin6.UpgradeResourceState.Response.upgraded_state:type_name -> tfplugin6.DynamicValue
+	5,  // 26: tfplugin6.UpgradeResourceState.Response.diagnostics:type_name -> tfplugin6.Diagnostic
+	4,  // 27: tfplugin6.ValidateResourceConfig.Request.config:type_name -> tfplugin6.DynamicValue
+	5,  // 28: tfplugin6.ValidateResourceConfig.Response.diagnostics:type_name -> tfplugin6.Diagnostic
+	4,  // 29: tfplugin6.ValidateDataResourceConfig.Request.config:type_name -> tfplugin6.DynamicValue
+	5,  // 30: tfplugin6.ValidateDataResourceConfig.Response.diagnostics:type_name -> tfplugin6.Diagnostic
+	4,  // 31: tfplugin6.ConfigureProvider.Request.config:type_name -> tfplugin6.DynamicValue
+	5,  // 32: tfplugin6.ConfigureProvider.Response.diagnostics:type_name -> tfplugin6.Diagnostic
+	4,  // 33: tfplugin6.ReadResource.Request.current_state:type_name -> tfplugin6.DynamicValue
+	4,  // 34: tfplugin6.ReadResource.Request.provider_meta:type_name -> tfplugin6.DynamicValue
+	4,  // 35: tfplugin6.ReadResource.Response.new_state:type_name -> tfplugin6.DynamicValue
+	5,  // 36: tfplugin6.ReadResource.Response.diagnostics:type_name -> tfplugin6.Diagnostic
+	4,  // 37: tfplugin6.PlanResourceChange.Request.prior_state:type_name -> tfplugin6.DynamicValue
+	4,  // 38: tfplugin6.PlanResourceChange.Request.proposed_new_state:type_name -> tfplugin6.DynamicValue
+	4,  // 39: tfplugin6.PlanResourceChange.Request.config:type_name -> tfplugin6.DynamicValue
+	4,  // 40: tfplugin6.PlanResourceChange.Request.provider_meta:type_name -> tfplugin6.DynamicValue
+	4,  // 41: tfplugin6.PlanResourceChange.Response.planned_state:type_name -> tfplugin6.DynamicValue
+	6,  // 42: tfplugin6.PlanResourceChange.Response.requires_replace:type_name -> tfplugin6.AttributePath
+	5,  // 43: tfplugin6.PlanResourceChange.Response.diagnostics:type_name -> tfplugin6.Diagnostic
+	4,  // 44: tfplugin6.ApplyResourceChange.Request.prior_state:type_name -> tfplugin6.DynamicValue
+	4,  // 45: tfplugin6.ApplyResourceChange.Request.planned_state:type_name -> tfplugin6.DynamicValue
+	4,  // 46: tfplugin6.ApplyResourceChange.Request.config:type_name -> tfplugin6.DynamicValue
+	4,  // 47: tfplugin6.ApplyResourceChange.Request.provider_meta:type_name -> tfplugin6.DynamicValue
+	4,  // 48: tfplugin6.ApplyResourceChange.Response.new_state:type_name -> tfplugin6.DynamicValue
+	5,  // 49: tfplugin6.ApplyResourceChange.Response.diagnostics:type_name -> tfplugin6.Diagnostic
+	4,  // 50: tfplugin6.ImportResourceState.ImportedResource.state:type_name -> tfplugin6.DynamicValue
+	51, // 51: tfplugin6.ImportResourceState.Response.imported_resources:type_name -> tfplugin6.ImportResourceState.ImportedResource
+	5,  // 52: tfplugin6.ImportResourceState.Response.diagnostics:type_name -> tfplugin6.Diagnostic
+	4,  // 53: tfplugin6.ReadDataSource.Request.config:type_name -> tfplugin6.DynamicValue
+	4,  // 54: tfplugin6.ReadDataSource.Request.provider_meta:type_name -> tfplugin6.DynamicValue
+	4,  // 55: tfplugin6.ReadDataSource.Response.state:type_name -> tfplugin6.DynamicValue
+	5,  // 56: tfplugin6.ReadDataSource.Response.diagnostics:type_name -> tfplugin6.Diagnostic
+	29, // 57: tfplugin6.Provider.GetProviderSchema:input_type -> tfplugin6.GetProviderSchema.Request
+	34, // 58: tfplugin6.Provider.ValidateProviderConfig:input_type -> tfplugin6.ValidateProviderConfig.Request
+	38, // 59: tfplugin6.Provider.ValidateResourceConfig:input_type -> tfplugin6.ValidateResourceConfig.Request
+	40, // 60: tfplugin6.Provider.ValidateDataResourceConfig:input_type -> tfplugin6.ValidateDataResourceConfig.Request
+	36, // 61: tfplugin6.Provider.UpgradeResourceState:input_type -> tfplugin6.UpgradeResourceState.Request
+	42, // 62: tfplugin6.Provider.ConfigureProvider:input_type -> tfplugin6.ConfigureProvider.Request
+	44, // 63: tfplugin6.Provider.ReadResource:input_type -> tfplugin6.ReadResource.Request
+	46, // 64: tfplugin6.Provider.PlanResourceChange:input_type -> tfplugin6.PlanResourceChange.Request
+	48, // 65: tfplugin6.Provider.ApplyResourceChange:input_type -> tfplugin6.ApplyResourceChange.Request
+	50, // 66: tfplugin6.Provider.ImportResourceState:input_type -> tfplugin6.ImportResourceState.Request
+	53, // 67: tfplugin6.Provider.ReadDataSource:input_type -> tfplugin6.ReadDataSource.Request
+	22, // 68: tfplugin6.Provider.StopProvider:input_type -> tfplugin6.StopProvider.Request
+	30, // 69: tfplugin6.Provider.GetProviderSchema:output_type -> tfplugin6.GetProviderSchema.Response
+	35, // 70: tfplugin6.Provider.ValidateProviderConfig:output_type -> tfplugin6.ValidateProviderConfig.Response
+	39, // 71: tfplugin6.Provider.ValidateResourceConfig:output_type -> tfplugin6.ValidateResourceConfig.Response
+	41, // 72: tfplugin6.Provider.ValidateDataResourceConfig:output_type -> tfplugin6.ValidateDataResourceConfig.Response
+	37, // 73: tfplugin6.Provider.UpgradeResourceState:output_type -> tfplugin6.UpgradeResourceState.Response
+	43, // 74: tfplugin6.Provider.ConfigureProvider:output_type -> tfplugin6.ConfigureProvider.Response
+	45, // 75: tfplugin6.Provider.ReadResource:output_type -> tfplugin6.ReadResource.Response
+	47, // 76: tfplugin6.Provider.PlanResourceChange:output_type -> tfplugin6.PlanResourceChange.Response
+	49, // 77: tfplugin6.Provider.ApplyResourceChange:output_type -> tfplugin6.ApplyResourceChange.Response
+	52, // 78: tfplugin6.Provider.ImportResourceState:output_type -> tfplugin6.ImportResourceState.Response
+	54, // 79: tfplugin6.Provider.ReadDataSource:output_type -> tfplugin6.ReadDataSource.Response
+	23, // 80: tfplugin6.Provider.StopProvider:output_type -> tfplugin6.StopProvider.Response
+	69, // [69:81] is the sub-list for method output_type
+	57, // [57:69] is the sub-list for method input_type
+	57, // [57:57] is the sub-list for extension type_name
+	57, // [57:57] is the sub-list for extension extendee
+	0,  // [0:57] is the sub-list for field type_name
+}
+
+func init() { file_tfplugin6_proto_init() }
+func file_tfplugin6_proto_init() {
+	if File_tfplugin6_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_tfplugin6_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DynamicValue); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Diagnostic); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*AttributePath); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*StopProvider); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*RawState); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Schema); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetProviderSchema); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateProviderConfig); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UpgradeResourceState); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateResourceConfig); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateDataResourceConfig); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ConfigureProvider); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReadResource); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*PlanResourceChange); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ApplyResourceChange); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ImportResourceState); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReadDataSource); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*AttributePath_Step); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*StopProvider_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*StopProvider_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Schema_Block); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Schema_Attribute); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Schema_NestedBlock); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Schema_Object); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetProviderSchema_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetProviderSchema_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetProviderSchema_ServerCapabilities); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateProviderConfig_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateProviderConfig_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UpgradeResourceState_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UpgradeResourceState_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateResourceConfig_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateResourceConfig_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateDataResourceConfig_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValidateDataResourceConfig_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ConfigureProvider_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ConfigureProvider_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReadResource_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReadResource_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*PlanResourceChange_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*PlanResourceChange_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ApplyResourceChange_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ApplyResourceChange_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ImportResourceState_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ImportResourceState_ImportedResource); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ImportResourceState_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReadDataSource_Request); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_tfplugin6_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReadDataSource_Response); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	file_tfplugin6_proto_msgTypes[17].OneofWrappers = []interface{}{
+		(*AttributePath_Step_AttributeName)(nil),
+		(*AttributePath_Step_ElementKeyString)(nil),
+		(*AttributePath_Step_ElementKeyInt)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_tfplugin6_proto_rawDesc,
+			NumEnums:      4,
+			NumMessages:   51,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_tfplugin6_proto_goTypes,
+		DependencyIndexes: file_tfplugin6_proto_depIdxs,
+		EnumInfos:         file_tfplugin6_proto_enumTypes,
+		MessageInfos:      file_tfplugin6_proto_msgTypes,
+	}.Build()
+	File_tfplugin6_proto = out.File
+	file_tfplugin6_proto_rawDesc = nil
+	file_tfplugin6_proto_goTypes = nil
+	file_tfplugin6_proto_depIdxs = nil
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConnInterface
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion6
+
+// ProviderClient is the client API for Provider service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type ProviderClient interface {
+	// ////// Information about what a provider supports/expects
+	GetProviderSchema(ctx context.Context, in *GetProviderSchema_Request, opts ...grpc.CallOption) (*GetProviderSchema_Response, error)
+	ValidateProviderConfig(ctx context.Context, in *ValidateProviderConfig_Request, opts ...grpc.CallOption) (*ValidateProviderConfig_Response, error)
+	ValidateResourceConfig(ctx context.Context, in *ValidateResourceConfig_Request, opts ...grpc.CallOption) (*ValidateResourceConfig_Response, error)
+	ValidateDataResourceConfig(ctx context.Context, in *ValidateDataResourceConfig_Request, opts ...grpc.CallOption) (*ValidateDataResourceConfig_Response, error)
+	UpgradeResourceState(ctx context.Context, in *UpgradeResourceState_Request, opts ...grpc.CallOption) (*UpgradeResourceState_Response, error)
+	// ////// One-time initialization, called before other functions below
+	ConfigureProvider(ctx context.Context, in *ConfigureProvider_Request, opts ...grpc.CallOption) (*ConfigureProvider_Response, error)
+	// ////// Managed Resource Lifecycle
+	ReadResource(ctx context.Context, in *ReadResource_Request, opts ...grpc.CallOption) (*ReadResource_Response, error)
+	PlanResourceChange(ctx context.Context, in *PlanResourceChange_Request, opts ...grpc.CallOption) (*PlanResourceChange_Response, error)
+	ApplyResourceChange(ctx context.Context, in *ApplyResourceChange_Request, opts ...grpc.CallOption) (*ApplyResourceChange_Response, error)
+	ImportResourceState(ctx context.Context, in *ImportResourceState_Request, opts ...grpc.CallOption) (*ImportResourceState_Response, error)
+	ReadDataSource(ctx context.Context, in *ReadDataSource_Request, opts ...grpc.CallOption) (*ReadDataSource_Response, error)
+	// ////// Graceful Shutdown
+	StopProvider(ctx context.Context, in *StopProvider_Request, opts ...grpc.CallOption) (*StopProvider_Response, error)
+}
+
+type providerClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewProviderClient(cc grpc.ClientConnInterface) ProviderClient {
+	return &providerClient{cc}
+}
+
+func (c *providerClient) GetProviderSchema(ctx context.Context, in *GetProviderSchema_Request, opts ...grpc.CallOption) (*GetProviderSchema_Response, error) {
+	out := new(GetProviderSchema_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin6.Provider/GetProviderSchema", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) ValidateProviderConfig(ctx context.Context, in *ValidateProviderConfig_Request, opts ...grpc.CallOption) (*ValidateProviderConfig_Response, error) {
+	out := new(ValidateProviderConfig_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ValidateProviderConfig", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) ValidateResourceConfig(ctx context.Context, in *ValidateResourceConfig_Request, opts ...grpc.CallOption) (*ValidateResourceConfig_Response, error) {
+	out := new(ValidateResourceConfig_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ValidateResourceConfig", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) ValidateDataResourceConfig(ctx context.Context, in *ValidateDataResourceConfig_Request, opts ...grpc.CallOption) (*ValidateDataResourceConfig_Response, error) {
+	out := new(ValidateDataResourceConfig_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ValidateDataResourceConfig", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) UpgradeResourceState(ctx context.Context, in *UpgradeResourceState_Request, opts ...grpc.CallOption) (*UpgradeResourceState_Response, error) {
+	out := new(UpgradeResourceState_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin6.Provider/UpgradeResourceState", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) ConfigureProvider(ctx context.Context, in *ConfigureProvider_Request, opts ...grpc.CallOption) (*ConfigureProvider_Response, error) {
+	out := new(ConfigureProvider_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ConfigureProvider", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) ReadResource(ctx context.Context, in *ReadResource_Request, opts ...grpc.CallOption) (*ReadResource_Response, error) {
+	out := new(ReadResource_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ReadResource", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) PlanResourceChange(ctx context.Context, in *PlanResourceChange_Request, opts ...grpc.CallOption) (*PlanResourceChange_Response, error) {
+	out := new(PlanResourceChange_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin6.Provider/PlanResourceChange", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) ApplyResourceChange(ctx context.Context, in *ApplyResourceChange_Request, opts ...grpc.CallOption) (*ApplyResourceChange_Response, error) {
+	out := new(ApplyResourceChange_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ApplyResourceChange", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) ImportResourceState(ctx context.Context, in *ImportResourceState_Request, opts ...grpc.CallOption) (*ImportResourceState_Response, error) {
+	out := new(ImportResourceState_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ImportResourceState", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) ReadDataSource(ctx context.Context, in *ReadDataSource_Request, opts ...grpc.CallOption) (*ReadDataSource_Response, error) {
+	out := new(ReadDataSource_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ReadDataSource", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *providerClient) StopProvider(ctx context.Context, in *StopProvider_Request, opts ...grpc.CallOption) (*StopProvider_Response, error) {
+	out := new(StopProvider_Response)
+	err := c.cc.Invoke(ctx, "/tfplugin6.Provider/StopProvider", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// ProviderServer is the server API for Provider service.
+type ProviderServer interface {
+	// ////// Information about what a provider supports/expects
+	GetProviderSchema(context.Context, *GetProviderSchema_Request) (*GetProviderSchema_Response, error)
+	ValidateProviderConfig(context.Context, *ValidateProviderConfig_Request) (*ValidateProviderConfig_Response, error)
+	ValidateResourceConfig(context.Context, *ValidateResourceConfig_Request) (*ValidateResourceConfig_Response, error)
+	ValidateDataResourceConfig(context.Context, *ValidateDataResourceConfig_Request) (*ValidateDataResourceConfig_Response, error)
+	UpgradeResourceState(context.Context, *UpgradeResourceState_Request) (*UpgradeResourceState_Response, error)
+	// ////// One-time initialization, called before other functions below
+	ConfigureProvider(context.Context, *ConfigureProvider_Request) (*ConfigureProvider_Response, error)
+	// ////// Managed Resource Lifecycle
+	ReadResource(context.Context, *ReadResource_Request) (*ReadResource_Response, error)
+	PlanResourceChange(context.Context, *PlanResourceChange_Request) (*PlanResourceChange_Response, error)
+	ApplyResourceChange(context.Context, *ApplyResourceChange_Request) (*ApplyResourceChange_Response, error)
+	ImportResourceState(context.Context, *ImportResourceState_Request) (*ImportResourceState_Response, error)
+	ReadDataSource(context.Context, *ReadDataSource_Request) (*ReadDataSource_Response, error)
+	// ////// Graceful Shutdown
+	StopProvider(context.Context, *StopProvider_Request) (*StopProvider_Response, error)
+}
+
+// UnimplementedProviderServer can be embedded to have forward compatible implementations.
+type UnimplementedProviderServer struct {
+}
+
+func (*UnimplementedProviderServer) GetProviderSchema(context.Context, *GetProviderSchema_Request) (*GetProviderSchema_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetProviderSchema not implemented")
+}
+func (*UnimplementedProviderServer) ValidateProviderConfig(context.Context, *ValidateProviderConfig_Request) (*ValidateProviderConfig_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ValidateProviderConfig not implemented")
+}
+func (*UnimplementedProviderServer) ValidateResourceConfig(context.Context, *ValidateResourceConfig_Request) (*ValidateResourceConfig_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ValidateResourceConfig not implemented")
+}
+func (*UnimplementedProviderServer) ValidateDataResourceConfig(context.Context, *ValidateDataResourceConfig_Request) (*ValidateDataResourceConfig_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ValidateDataResourceConfig not implemented")
+}
+func (*UnimplementedProviderServer) UpgradeResourceState(context.Context, *UpgradeResourceState_Request) (*UpgradeResourceState_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method UpgradeResourceState not implemented")
+}
+func (*UnimplementedProviderServer) ConfigureProvider(context.Context, *ConfigureProvider_Request) (*ConfigureProvider_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ConfigureProvider not implemented")
+}
+func (*UnimplementedProviderServer) ReadResource(context.Context, *ReadResource_Request) (*ReadResource_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ReadResource not implemented")
+}
+func (*UnimplementedProviderServer) PlanResourceChange(context.Context, *PlanResourceChange_Request) (*PlanResourceChange_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method PlanResourceChange not implemented")
+}
+func (*UnimplementedProviderServer) ApplyResourceChange(context.Context, *ApplyResourceChange_Request) (*ApplyResourceChange_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ApplyResourceChange not implemented")
+}
+func (*UnimplementedProviderServer) ImportResourceState(context.Context, *ImportResourceState_Request) (*ImportResourceState_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ImportResourceState not implemented")
+}
+func (*UnimplementedProviderServer) ReadDataSource(context.Context, *ReadDataSource_Request) (*ReadDataSource_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ReadDataSource not implemented")
+}
+func (*UnimplementedProviderServer) StopProvider(context.Context, *StopProvider_Request) (*StopProvider_Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method StopProvider not implemented")
+}
+
+func RegisterProviderServer(s *grpc.Server, srv ProviderServer) {
+	s.RegisterService(&_Provider_serviceDesc, srv)
+}
+
+func _Provider_GetProviderSchema_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(GetProviderSchema_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).GetProviderSchema(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin6.Provider/GetProviderSchema",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).GetProviderSchema(ctx, req.(*GetProviderSchema_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_ValidateProviderConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ValidateProviderConfig_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).ValidateProviderConfig(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin6.Provider/ValidateProviderConfig",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).ValidateProviderConfig(ctx, req.(*ValidateProviderConfig_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_ValidateResourceConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ValidateResourceConfig_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).ValidateResourceConfig(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin6.Provider/ValidateResourceConfig",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).ValidateResourceConfig(ctx, req.(*ValidateResourceConfig_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_ValidateDataResourceConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ValidateDataResourceConfig_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).ValidateDataResourceConfig(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin6.Provider/ValidateDataResourceConfig",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).ValidateDataResourceConfig(ctx, req.(*ValidateDataResourceConfig_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_UpgradeResourceState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(UpgradeResourceState_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).UpgradeResourceState(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin6.Provider/UpgradeResourceState",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).UpgradeResourceState(ctx, req.(*UpgradeResourceState_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_ConfigureProvider_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ConfigureProvider_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).ConfigureProvider(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin6.Provider/ConfigureProvider",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).ConfigureProvider(ctx, req.(*ConfigureProvider_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_ReadResource_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ReadResource_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).ReadResource(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin6.Provider/ReadResource",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).ReadResource(ctx, req.(*ReadResource_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_PlanResourceChange_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(PlanResourceChange_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).PlanResourceChange(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin6.Provider/PlanResourceChange",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).PlanResourceChange(ctx, req.(*PlanResourceChange_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_ApplyResourceChange_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ApplyResourceChange_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).ApplyResourceChange(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin6.Provider/ApplyResourceChange",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).ApplyResourceChange(ctx, req.(*ApplyResourceChange_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_ImportResourceState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ImportResourceState_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).ImportResourceState(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin6.Provider/ImportResourceState",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).ImportResourceState(ctx, req.(*ImportResourceState_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_ReadDataSource_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ReadDataSource_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).ReadDataSource(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin6.Provider/ReadDataSource",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).ReadDataSource(ctx, req.(*ReadDataSource_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Provider_StopProvider_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(StopProvider_Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProviderServer).StopProvider(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tfplugin6.Provider/StopProvider",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProviderServer).StopProvider(ctx, req.(*StopProvider_Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+var _Provider_serviceDesc = grpc.ServiceDesc{
+	ServiceName: "tfplugin6.Provider",
+	HandlerType: (*ProviderServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "GetProviderSchema",
+			Handler:    _Provider_GetProviderSchema_Handler,
+		},
+		{
+			MethodName: "ValidateProviderConfig",
+			Handler:    _Provider_ValidateProviderConfig_Handler,
+		},
+		{
+			MethodName: "ValidateResourceConfig",
+			Handler:    _Provider_ValidateResourceConfig_Handler,
+		},
+		{
+			MethodName: "ValidateDataResourceConfig",
+			Handler:    _Provider_ValidateDataResourceConfig_Handler,
+		},
+		{
+			MethodName: "UpgradeResourceState",
+			Handler:    _Provider_UpgradeResourceState_Handler,
+		},
+		{
+			MethodName: "ConfigureProvider",
+			Handler:    _Provider_ConfigureProvider_Handler,
+		},
+		{
+			MethodName: "ReadResource",
+			Handler:    _Provider_ReadResource_Handler,
+		},
+		{
+			MethodName: "PlanResourceChange",
+			Handler:    _Provider_PlanResourceChange_Handler,
+		},
+		{
+			MethodName: "ApplyResourceChange",
+			Handler:    _Provider_ApplyResourceChange_Handler,
+		},
+		{
+			MethodName: "ImportResourceState",
+			Handler:    _Provider_ImportResourceState_Handler,
+		},
+		{
+			MethodName: "ReadDataSource",
+			Handler:    _Provider_ReadDataSource_Handler,
+		},
+		{
+			MethodName: "StopProvider",
+			Handler:    _Provider_StopProvider_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "tfplugin6.proto",
+}
diff --git a/v1.5.7/internal/tfplugin6/tfplugin6.proto b/v1.5.7/internal/tfplugin6/tfplugin6.proto
new file mode 120000
index 0000000..a7cf631
--- /dev/null
+++ b/v1.5.7/internal/tfplugin6/tfplugin6.proto
@@ -0,0 +1 @@
+../../docs/plugin-protocol/tfplugin6.3.proto
\ No newline at end of file
diff --git a/v1.5.7/main.go b/v1.5.7/main.go
new file mode 100644
index 0000000..9ce427a
--- /dev/null
+++ b/v1.5.7/main.go
@@ -0,0 +1,475 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"log"
+	"net"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+
+	"github.com/hashicorp/go-plugin"
+	"github.com/hashicorp/terraform-svchost/disco"
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/cliconfig"
+	"github.com/hashicorp/terraform/internal/command/format"
+	"github.com/hashicorp/terraform/internal/didyoumean"
+	"github.com/hashicorp/terraform/internal/httpclient"
+	"github.com/hashicorp/terraform/internal/logging"
+	"github.com/hashicorp/terraform/internal/terminal"
+	"github.com/hashicorp/terraform/version"
+	"github.com/mattn/go-shellwords"
+	"github.com/mitchellh/cli"
+	"github.com/mitchellh/colorstring"
+
+	backendInit "github.com/hashicorp/terraform/internal/backend/init"
+)
+
+const (
+	// EnvCLI is the environment variable name to set additional CLI args.
+	EnvCLI = "TF_CLI_ARGS"
+
+	// The parent process will create a file to collect crash logs
+	envTmpLogPath = "TF_TEMP_LOG_PATH"
+)
+
+// ui wraps the primary output cli.Ui, and redirects Warn calls to Output
+// calls. This ensures that warnings are sent to stdout, and are properly
+// serialized within the stdout stream.
+type ui struct {
+	cli.Ui
+}
+
+func (u *ui) Warn(msg string) {
+	u.Ui.Output(msg)
+}
+
+func init() {
+	Ui = &ui{&cli.BasicUi{
+		Writer:      os.Stdout,
+		ErrorWriter: os.Stderr,
+		Reader:      os.Stdin,
+	}}
+}
+
+func main() {
+	os.Exit(realMain())
+}
+
+func realMain() int {
+	defer logging.PanicHandler()
+
+	var err error
+
+	tmpLogPath := os.Getenv(envTmpLogPath)
+	if tmpLogPath != "" {
+		f, err := os.OpenFile(tmpLogPath, os.O_RDWR|os.O_APPEND, 0666)
+		if err == nil {
+			defer f.Close()
+
+			log.Printf("[DEBUG] Adding temp file log sink: %s", f.Name())
+			logging.RegisterSink(f)
+		} else {
+			log.Printf("[ERROR] Could not open temp log file: %v", err)
+		}
+	}
+
+	log.Printf(
+		"[INFO] Terraform version: %s %s",
+		Version, VersionPrerelease)
+	for _, depMod := range version.InterestingDependencies() {
+		log.Printf("[DEBUG] using %s %s", depMod.Path, depMod.Version)
+	}
+	log.Printf("[INFO] Go runtime version: %s", runtime.Version())
+	log.Printf("[INFO] CLI args: %#v", os.Args)
+	if ExperimentsAllowed() {
+		log.Printf("[INFO] This build of Terraform allows using experimental features")
+	}
+
+	streams, err := terminal.Init()
+	if err != nil {
+		Ui.Error(fmt.Sprintf("Failed to configure the terminal: %s", err))
+		return 1
+	}
+	if streams.Stdout.IsTerminal() {
+		log.Printf("[TRACE] Stdout is a terminal of width %d", streams.Stdout.Columns())
+	} else {
+		log.Printf("[TRACE] Stdout is not a terminal")
+	}
+	if streams.Stderr.IsTerminal() {
+		log.Printf("[TRACE] Stderr is a terminal of width %d", streams.Stderr.Columns())
+	} else {
+		log.Printf("[TRACE] Stderr is not a terminal")
+	}
+	if streams.Stdin.IsTerminal() {
+		log.Printf("[TRACE] Stdin is a terminal")
+	} else {
+		log.Printf("[TRACE] Stdin is not a terminal")
+	}
+
+	// NOTE: We're intentionally calling LoadConfig _before_ handling a possible
+	// -chdir=... option on the command line, so that a possible relative
+	// path in the TERRAFORM_CONFIG_FILE environment variable (though probably
+	// ill-advised) will be resolved relative to the true working directory,
+	// not the overridden one.
+	config, diags := cliconfig.LoadConfig()
+
+	if len(diags) > 0 {
+		// Since we haven't instantiated a command.Meta yet, we need to do
+		// some things manually here and use some "safe" defaults for things
+		// that command.Meta could otherwise figure out in smarter ways.
+		Ui.Error("There are some problems with the CLI configuration:")
+		for _, diag := range diags {
+			earlyColor := &colorstring.Colorize{
+				Colors:  colorstring.DefaultColors,
+				Disable: true, // Disable color to be conservative until we know better
+				Reset:   true,
+			}
+			// We don't currently have access to the source code cache for
+			// the parser used to load the CLI config, so we can't show
+			// source code snippets in early diagnostics.
+			Ui.Error(format.Diagnostic(diag, nil, earlyColor, 78))
+		}
+		if diags.HasErrors() {
+			Ui.Error("As a result of the above problems, Terraform may not behave as intended.\n\n")
+			// We continue to run anyway, since Terraform has reasonable defaults.
+		}
+	}
+
+	// Get any configured credentials from the config and initialize
+	// a service discovery object. The slightly awkward predeclaration of
+	// disco is required to allow us to pass untyped nil as the creds source
+	// when creating the source fails. Otherwise we pass a typed nil which
+	// breaks the nil checks in the disco object
+	var services *disco.Disco
+	credsSrc, err := credentialsSource(config)
+	if err == nil {
+		services = disco.NewWithCredentialsSource(credsSrc)
+	} else {
+		// Most commands don't actually need credentials, and most situations
+		// that would get us here would already have been reported by the config
+		// loading above, so we'll just log this one as an aid to debugging
+		// in the unlikely event that it _does_ arise.
+		log.Printf("[WARN] Cannot initialize remote host credentials manager: %s", err)
+		// passing (untyped) nil as the creds source is okay because the disco
+		// object checks that and just acts as though no credentials are present.
+		services = disco.NewWithCredentialsSource(nil)
+	}
+	services.SetUserAgent(httpclient.TerraformUserAgent(version.String()))
+
+	providerSrc, diags := providerSource(config.ProviderInstallation, services)
+	if len(diags) > 0 {
+		Ui.Error("There are some problems with the provider_installation configuration:")
+		for _, diag := range diags {
+			earlyColor := &colorstring.Colorize{
+				Colors:  colorstring.DefaultColors,
+				Disable: true, // Disable color to be conservative until we know better
+				Reset:   true,
+			}
+			Ui.Error(format.Diagnostic(diag, nil, earlyColor, 78))
+		}
+		if diags.HasErrors() {
+			Ui.Error("As a result of the above problems, Terraform's provider installer may not behave as intended.\n\n")
+			// We continue to run anyway, because most commands don't do provider installation.
+		}
+	}
+	providerDevOverrides := providerDevOverrides(config.ProviderInstallation)
+
+	// The user can declare that certain providers are being managed on
+	// Terraform's behalf using this environment variable. This is used
+	// primarily by the SDK's acceptance testing framework.
+	unmanagedProviders, err := parseReattachProviders(os.Getenv("TF_REATTACH_PROVIDERS"))
+	if err != nil {
+		Ui.Error(err.Error())
+		return 1
+	}
+
+	// Initialize the backends.
+	backendInit.Init(services)
+
+	// Get the command line args.
+	binName := filepath.Base(os.Args[0])
+	args := os.Args[1:]
+
+	originalWd, err := os.Getwd()
+	if err != nil {
+		// It would be very strange to end up here
+		Ui.Error(fmt.Sprintf("Failed to determine current working directory: %s", err))
+		return 1
+	}
+
+	// The arguments can begin with a -chdir option to ask Terraform to switch
+	// to a different working directory for the rest of its work. If that
+	// option is present then extractChdirOption returns a trimmed args with that option removed.
+	overrideWd, args, err := extractChdirOption(args)
+	if err != nil {
+		Ui.Error(fmt.Sprintf("Invalid -chdir option: %s", err))
+		return 1
+	}
+	if overrideWd != "" {
+		err := os.Chdir(overrideWd)
+		if err != nil {
+			Ui.Error(fmt.Sprintf("Error handling -chdir option: %s", err))
+			return 1
+		}
+	}
+
+	// In tests, Commands may already be set to provide mock commands
+	if Commands == nil {
+		// Commands get to hold on to the original working directory here,
+		// in case they need to refer back to it for any special reason, though
+		// they should primarily be working with the override working directory
+		// that we've now switched to above.
+		initCommands(originalWd, streams, config, services, providerSrc, providerDevOverrides, unmanagedProviders)
+	}
+
+	// Run checkpoint
+	go runCheckpoint(config)
+
+	// Make sure we clean up any managed plugins at the end of this
+	defer plugin.CleanupClients()
+
+	// Build the CLI so far, we do this so we can query the subcommand.
+	cliRunner := &cli.CLI{
+		Args:       args,
+		Commands:   Commands,
+		HelpFunc:   helpFunc,
+		HelpWriter: os.Stdout,
+	}
+
+	// Prefix the args with any args from the EnvCLI
+	args, err = mergeEnvArgs(EnvCLI, cliRunner.Subcommand(), args)
+	if err != nil {
+		Ui.Error(err.Error())
+		return 1
+	}
+
+	// Prefix the args with any args from the EnvCLI targeting this command
+	suffix := strings.Replace(strings.Replace(
+		cliRunner.Subcommand(), "-", "_", -1), " ", "_", -1)
+	args, err = mergeEnvArgs(
+		fmt.Sprintf("%s_%s", EnvCLI, suffix), cliRunner.Subcommand(), args)
+	if err != nil {
+		Ui.Error(err.Error())
+		return 1
+	}
+
+	// We shortcut "--version" and "-v" to just show the version
+	for _, arg := range args {
+		if arg == "-v" || arg == "-version" || arg == "--version" {
+			newArgs := make([]string, len(args)+1)
+			newArgs[0] = "version"
+			copy(newArgs[1:], args)
+			args = newArgs
+			break
+		}
+	}
+
+	// Rebuild the CLI with any modified args.
+	log.Printf("[INFO] CLI command args: %#v", args)
+	cliRunner = &cli.CLI{
+		Name:       binName,
+		Args:       args,
+		Commands:   Commands,
+		HelpFunc:   helpFunc,
+		HelpWriter: os.Stdout,
+
+		Autocomplete:          true,
+		AutocompleteInstall:   "install-autocomplete",
+		AutocompleteUninstall: "uninstall-autocomplete",
+	}
+
+	// Before we continue we'll check whether the requested command is
+	// actually known. If not, we might be able to suggest an alternative
+	// if it seems like the user made a typo.
+	// (This bypasses the built-in help handling in cli.CLI for the situation
+	// where a command isn't found, because it's likely more helpful to
+	// mention what specifically went wrong, rather than just printing out
+	// a big block of usage information.)
+
+	// Check if this is being run via shell auto-complete, which uses the
+	// binary name as the first argument and won't be listed as a subcommand.
+	autoComplete := os.Getenv("COMP_LINE") != ""
+
+	if cmd := cliRunner.Subcommand(); cmd != "" && !autoComplete {
+		// Due to the design of cli.CLI, this special error message only works
+		// for typos of top-level commands. For a subcommand typo, like
+		// "terraform state posh", cmd would be "state" here and thus would
+		// be considered to exist, and it would print out its own usage message.
+		if _, exists := Commands[cmd]; !exists {
+			suggestions := make([]string, 0, len(Commands))
+			for name := range Commands {
+				suggestions = append(suggestions, name)
+			}
+			suggestion := didyoumean.NameSuggestion(cmd, suggestions)
+			if suggestion != "" {
+				suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
+			}
+			fmt.Fprintf(os.Stderr, "Terraform has no command named %q.%s\n\nTo see all of Terraform's top-level commands, run:\n  terraform -help\n\n", cmd, suggestion)
+			return 1
+		}
+	}
+
+	exitCode, err := cliRunner.Run()
+	if err != nil {
+		Ui.Error(fmt.Sprintf("Error executing CLI: %s", err.Error()))
+		return 1
+	}
+
+	// if we are exiting with a non-zero code, check if it was caused by any
+	// plugins crashing
+	if exitCode != 0 {
+		for _, panicLog := range logging.PluginPanics() {
+			Ui.Error(panicLog)
+		}
+	}
+
+	return exitCode
+}
+
+func mergeEnvArgs(envName string, cmd string, args []string) ([]string, error) {
+	v := os.Getenv(envName)
+	if v == "" {
+		return args, nil
+	}
+
+	log.Printf("[INFO] %s value: %q", envName, v)
+	extra, err := shellwords.Parse(v)
+	if err != nil {
+		return nil, fmt.Errorf(
+			"Error parsing extra CLI args from %s: %s",
+			envName, err)
+	}
+
+	// Find the command to look for in the args. If there is a space,
+	// we need to find the last part.
+	search := cmd
+	if idx := strings.LastIndex(search, " "); idx >= 0 {
+		search = cmd[idx+1:]
+	}
+
+	// Find the index to place the flags. We put them exactly
+	// after the first non-flag arg.
+	idx := -1
+	for i, v := range args {
+		if v == search {
+			idx = i
+			break
+		}
+	}
+
+	// idx points to the exact arg that isn't a flag. We increment
+	// by one so that all the copying below expects idx to be the
+	// insertion point.
+	idx++
+
+	// Copy the args
+	newArgs := make([]string, len(args)+len(extra))
+	copy(newArgs, args[:idx])
+	copy(newArgs[idx:], extra)
+	copy(newArgs[len(extra)+idx:], args[idx:])
+	return newArgs, nil
+}
+
+// parse information on reattaching to unmanaged providers out of a
+// JSON-encoded environment variable.
+func parseReattachProviders(in string) (map[addrs.Provider]*plugin.ReattachConfig, error) {
+	unmanagedProviders := map[addrs.Provider]*plugin.ReattachConfig{}
+	if in != "" {
+		type reattachConfig struct {
+			Protocol        string
+			ProtocolVersion int
+			Addr            struct {
+				Network string
+				String  string
+			}
+			Pid  int
+			Test bool
+		}
+		var m map[string]reattachConfig
+		err := json.Unmarshal([]byte(in), &m)
+		if err != nil {
+			return unmanagedProviders, fmt.Errorf("Invalid format for TF_REATTACH_PROVIDERS: %w", err)
+		}
+		for p, c := range m {
+			a, diags := addrs.ParseProviderSourceString(p)
+			if diags.HasErrors() {
+				return unmanagedProviders, fmt.Errorf("Error parsing %q as a provider address: %w", a, diags.Err())
+			}
+			var addr net.Addr
+			switch c.Addr.Network {
+			case "unix":
+				addr, err = net.ResolveUnixAddr("unix", c.Addr.String)
+				if err != nil {
+					return unmanagedProviders, fmt.Errorf("Invalid unix socket path %q for %q: %w", c.Addr.String, p, err)
+				}
+			case "tcp":
+				addr, err = net.ResolveTCPAddr("tcp", c.Addr.String)
+				if err != nil {
+					return unmanagedProviders, fmt.Errorf("Invalid TCP address %q for %q: %w", c.Addr.String, p, err)
+				}
+			default:
+				return unmanagedProviders, fmt.Errorf("Unknown address type %q for %q", c.Addr.Network, p)
+			}
+			unmanagedProviders[a] = &plugin.ReattachConfig{
+				Protocol:        plugin.Protocol(c.Protocol),
+				ProtocolVersion: c.ProtocolVersion,
+				Pid:             c.Pid,
+				Test:            c.Test,
+				Addr:            addr,
+			}
+		}
+	}
+	return unmanagedProviders, nil
+}
+
+func extractChdirOption(args []string) (string, []string, error) {
+	if len(args) == 0 {
+		return "", args, nil
+	}
+
+	const argName = "-chdir"
+	const argPrefix = argName + "="
+	var argValue string
+	var argPos int
+
+	for i, arg := range args {
+		if !strings.HasPrefix(arg, "-") {
+			// Because the chdir option is a subcommand-agnostic one, we require
+			// it to appear before any subcommand argument, so if we find a
+			// non-option before we find -chdir then we are finished.
+			break
+		}
+		if arg == argName || arg == argPrefix {
+			return "", args, fmt.Errorf("must include an equals sign followed by a directory path, like -chdir=example")
+		}
+		if strings.HasPrefix(arg, argPrefix) {
+			argPos = i
+			argValue = arg[len(argPrefix):]
+		}
+	}
+
+	// When we fall out here, we'll have populated argValue with a non-empty
+	// string if the -chdir=... option was present and valid, or left it
+	// empty if it wasn't present.
+	if argValue == "" {
+		return "", args, nil
+	}
+
+	// If we did find the option then we'll need to produce a new args that
+	// doesn't include it anymore.
+	if argPos == 0 {
+		// Easy case: we can just slice off the front
+		return argValue, args[1:], nil
+	}
+	// Otherwise we need to construct a new array and copy to it.
+	newArgs := make([]string, len(args)-1)
+	copy(newArgs, args[:argPos])
+	copy(newArgs[argPos:], args[argPos+1:])
+	return argValue, newArgs, nil
+}
diff --git a/v1.5.7/main_test.go b/v1.5.7/main_test.go
new file mode 100644
index 0000000..e1eb64b
--- /dev/null
+++ b/v1.5.7/main_test.go
@@ -0,0 +1,314 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"fmt"
+	"os"
+	"reflect"
+	"testing"
+
+	"github.com/mitchellh/cli"
+)
+
+func TestMain_cliArgsFromEnv(t *testing.T) {
+	// Set up the state. This test really messes with the environment and
+	// global state so we set things up to be restored.
+
+	// Restore original CLI args
+	oldArgs := os.Args
+	defer func() { os.Args = oldArgs }()
+
+	// Set up test command and restore that
+	Commands = make(map[string]cli.CommandFactory)
+	defer func() {
+		Commands = nil
+	}()
+	testCommandName := "unit-test-cli-args"
+	testCommand := &testCommandCLI{}
+	Commands[testCommandName] = func() (cli.Command, error) {
+		return testCommand, nil
+	}
+
+	cases := []struct {
+		Name     string
+		Args     []string
+		Value    string
+		Expected []string
+		Err      bool
+	}{
+		{
+			"no env",
+			[]string{testCommandName, "foo", "bar"},
+			"",
+			[]string{"foo", "bar"},
+			false,
+		},
+
+		{
+			"both env var and CLI",
+			[]string{testCommandName, "foo", "bar"},
+			"-foo bar",
+			[]string{"-foo", "bar", "foo", "bar"},
+			false,
+		},
+
+		{
+			"only env var",
+			[]string{testCommandName},
+			"-foo bar",
+			[]string{"-foo", "bar"},
+			false,
+		},
+
+		{
+			"cli string has blank values",
+			[]string{testCommandName, "bar", "", "baz"},
+			"-foo bar",
+			[]string{"-foo", "bar", "bar", "", "baz"},
+			false,
+		},
+
+		{
+			"cli string has blank values before the command",
+			[]string{"", testCommandName, "bar"},
+			"-foo bar",
+			[]string{"-foo", "bar", "bar"},
+			false,
+		},
+
+		{
+			// this should fail gracefully, this is just testing
+			// that we don't panic with our slice arithmetic
+			"no command",
+			[]string{},
+			"-foo bar",
+			nil,
+			true,
+		},
+
+		{
+			"single quoted strings",
+			[]string{testCommandName, "foo"},
+			"-foo 'bar baz'",
+			[]string{"-foo", "bar baz", "foo"},
+			false,
+		},
+
+		{
+			"double quoted strings",
+			[]string{testCommandName, "foo"},
+			`-foo "bar baz"`,
+			[]string{"-foo", "bar baz", "foo"},
+			false,
+		},
+
+		{
+			"double quoted single quoted strings",
+			[]string{testCommandName, "foo"},
+			`-foo "'bar baz'"`,
+			[]string{"-foo", "'bar baz'", "foo"},
+			false,
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			os.Unsetenv(EnvCLI)
+			defer os.Unsetenv(EnvCLI)
+
+			// Set the env var value
+			if tc.Value != "" {
+				if err := os.Setenv(EnvCLI, tc.Value); err != nil {
+					t.Fatalf("err: %s", err)
+				}
+			}
+
+			// Set up the args
+			args := make([]string, len(tc.Args)+1)
+			args[0] = oldArgs[0] // process name
+			copy(args[1:], tc.Args)
+
+			// Run it!
+			os.Args = args
+			testCommand.Args = nil
+			exit := realMain()
+			if (exit != 0) != tc.Err {
+				t.Fatalf("bad: %d", exit)
+			}
+			if tc.Err {
+				return
+			}
+
+			// Verify
+			if !reflect.DeepEqual(testCommand.Args, tc.Expected) {
+				t.Fatalf("bad: %#v", testCommand.Args)
+			}
+		})
+	}
+}
+
+// This test just has more options than the test above. Use this for
+// more control over behavior at the expense of more complex test structures.
+func TestMain_cliArgsFromEnvAdvanced(t *testing.T) {
+	// Restore original CLI args
+	oldArgs := os.Args
+	defer func() { os.Args = oldArgs }()
+
+	// Set up test command and restore that
+	Commands = make(map[string]cli.CommandFactory)
+	defer func() {
+		Commands = nil
+	}()
+
+	cases := []struct {
+		Name     string
+		Command  string
+		EnvVar   string
+		Args     []string
+		Value    string
+		Expected []string
+		Err      bool
+	}{
+		{
+			"targeted to another command",
+			"command",
+			EnvCLI + "_foo",
+			[]string{"command", "foo", "bar"},
+			"-flag",
+			[]string{"foo", "bar"},
+			false,
+		},
+
+		{
+			"targeted to this command",
+			"command",
+			EnvCLI + "_command",
+			[]string{"command", "foo", "bar"},
+			"-flag",
+			[]string{"-flag", "foo", "bar"},
+			false,
+		},
+
+		{
+			"targeted to a command with a hyphen",
+			"command-name",
+			EnvCLI + "_command_name",
+			[]string{"command-name", "foo", "bar"},
+			"-flag",
+			[]string{"-flag", "foo", "bar"},
+			false,
+		},
+
+		{
+			"targeted to a command with a space",
+			"command name",
+			EnvCLI + "_command_name",
+			[]string{"command", "name", "foo", "bar"},
+			"-flag",
+			[]string{"-flag", "foo", "bar"},
+			false,
+		},
+	}
+
+	for i, tc := range cases {
+		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
+			// Set up test command and restore that
+			testCommandName := tc.Command
+			testCommand := &testCommandCLI{}
+			defer func() { delete(Commands, testCommandName) }()
+			Commands[testCommandName] = func() (cli.Command, error) {
+				return testCommand, nil
+			}
+
+			os.Unsetenv(tc.EnvVar)
+			defer os.Unsetenv(tc.EnvVar)
+
+			// Set the env var value
+			if tc.Value != "" {
+				if err := os.Setenv(tc.EnvVar, tc.Value); err != nil {
+					t.Fatalf("err: %s", err)
+				}
+			}
+
+			// Set up the args
+			args := make([]string, len(tc.Args)+1)
+			args[0] = oldArgs[0] // process name
+			copy(args[1:], tc.Args)
+
+			// Run it!
+			os.Args = args
+			testCommand.Args = nil
+			exit := realMain()
+			if (exit != 0) != tc.Err {
+				t.Fatalf("unexpected exit status %d; want 0", exit)
+			}
+			if tc.Err {
+				return
+			}
+
+			// Verify
+			if !reflect.DeepEqual(testCommand.Args, tc.Expected) {
+				t.Fatalf("bad: %#v", testCommand.Args)
+			}
+		})
+	}
+}
+
+// verify that we output valid autocomplete results
+func TestMain_autoComplete(t *testing.T) {
+	// Restore original CLI args
+	oldArgs := os.Args
+	defer func() { os.Args = oldArgs }()
+
+	// Set up test command and restore that
+	Commands = make(map[string]cli.CommandFactory)
+	defer func() {
+		Commands = nil
+	}()
+
+	// Set up test command and restore that
+	Commands["foo"] = func() (cli.Command, error) {
+		return &testCommandCLI{}, nil
+	}
+
+	os.Setenv("COMP_LINE", "terraform versio")
+	defer os.Unsetenv("COMP_LINE")
+
+	// Run it!
+	os.Args = []string{"terraform", "terraform", "versio"}
+	exit := realMain()
+	if exit != 0 {
+		t.Fatalf("unexpected exit status %d; want 0", exit)
+	}
+}
+
+type testCommandCLI struct {
+	Args []string
+}
+
+func (c *testCommandCLI) Run(args []string) int {
+	c.Args = args
+	return 0
+}
+
+func (c *testCommandCLI) Synopsis() string { return "" }
+func (c *testCommandCLI) Help() string     { return "" }
+
+func TestWarnOutput(t *testing.T) {
+	mock := cli.NewMockUi()
+	wrapped := &ui{mock}
+	wrapped.Warn("WARNING")
+
+	stderr := mock.ErrorWriter.String()
+	stdout := mock.OutputWriter.String()
+
+	if stderr != "" {
+		t.Fatalf("unexpected stderr: %q", stderr)
+	}
+
+	if stdout != "WARNING\n" {
+		t.Fatalf("unexpected stdout: %q\n", stdout)
+	}
+}
diff --git a/v1.5.7/plugins.go b/v1.5.7/plugins.go
new file mode 100644
index 0000000..defa9dd
--- /dev/null
+++ b/v1.5.7/plugins.go
@@ -0,0 +1,34 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"fmt"
+	"log"
+	"path/filepath"
+	"runtime"
+
+	"github.com/hashicorp/terraform/internal/command/cliconfig"
+)
+
+// globalPluginDirs returns directories that should be searched for
+// globally-installed plugins (not specific to the current configuration).
+//
+// Earlier entries in this slice get priority over later when multiple copies
+// of the same plugin version are found, but newer versions always override
+// older versions where both satisfy the provider version constraints.
+func globalPluginDirs() []string {
+	var ret []string
+	// Look in ~/.terraform.d/plugins/ , or its equivalent on non-UNIX
+	dir, err := cliconfig.ConfigDir()
+	if err != nil {
+		log.Printf("[ERROR] Error finding global config directory: %s", err)
+	} else {
+		machineDir := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH)
+		ret = append(ret, filepath.Join(dir, "plugins"))
+		ret = append(ret, filepath.Join(dir, "plugins", machineDir))
+	}
+
+	return ret
+}
diff --git a/v1.5.7/provider_source.go b/v1.5.7/provider_source.go
new file mode 100644
index 0000000..67c00ed
--- /dev/null
+++ b/v1.5.7/provider_source.go
@@ -0,0 +1,241 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"fmt"
+	"log"
+	"net/url"
+	"os"
+	"path/filepath"
+
+	"github.com/apparentlymart/go-userdirs/userdirs"
+	"github.com/hashicorp/terraform-svchost/disco"
+
+	"github.com/hashicorp/terraform/internal/addrs"
+	"github.com/hashicorp/terraform/internal/command/cliconfig"
+	"github.com/hashicorp/terraform/internal/getproviders"
+	"github.com/hashicorp/terraform/internal/tfdiags"
+)
+
+// providerSource constructs a provider source based on a combination of the
+// CLI configuration and some default search locations. This will be the
+// provider source used for provider installation in the "terraform init"
+// command, unless overridden by the special -plugin-dir option.
+func providerSource(configs []*cliconfig.ProviderInstallation, services *disco.Disco) (getproviders.Source, tfdiags.Diagnostics) {
+	if len(configs) == 0 {
+		// If there's no explicit installation configuration then we'll build
+		// up an implicit one with direct registry installation along with
+		// some automatically-selected local filesystem mirrors.
+		return implicitProviderSource(services), nil
+	}
+
+	// There should only be zero or one configurations, which is checked by
+	// the validation logic in the cliconfig package. Therefore we'll just
+	// ignore any additional configurations in here.
+	config := configs[0]
+	return explicitProviderSource(config, services)
+}
+
+func explicitProviderSource(config *cliconfig.ProviderInstallation, services *disco.Disco) (getproviders.Source, tfdiags.Diagnostics) {
+	var diags tfdiags.Diagnostics
+	var searchRules []getproviders.MultiSourceSelector
+
+	log.Printf("[DEBUG] Explicit provider installation configuration is set")
+	for _, methodConfig := range config.Methods {
+		source, moreDiags := providerSourceForCLIConfigLocation(methodConfig.Location, services)
+		diags = diags.Append(moreDiags)
+		if moreDiags.HasErrors() {
+			continue
+		}
+
+		include, err := getproviders.ParseMultiSourceMatchingPatterns(methodConfig.Include)
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid provider source inclusion patterns",
+				fmt.Sprintf("CLI config specifies invalid provider inclusion patterns: %s.", err),
+			))
+			continue
+		}
+		exclude, err := getproviders.ParseMultiSourceMatchingPatterns(methodConfig.Exclude)
+		if err != nil {
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid provider source exclusion patterns",
+				fmt.Sprintf("CLI config specifies invalid provider exclusion patterns: %s.", err),
+			))
+			continue
+		}
+
+		searchRules = append(searchRules, getproviders.MultiSourceSelector{
+			Source:  source,
+			Include: include,
+			Exclude: exclude,
+		})
+
+		log.Printf("[TRACE] Selected provider installation method %#v with includes %s and excludes %s", methodConfig.Location, include, exclude)
+	}
+
+	return getproviders.MultiSource(searchRules), diags
+}
+
+// implicitProviderSource builds a default provider source to use if there's
+// no explicit provider installation configuration in the CLI config.
+//
+// This implicit source looks in a number of local filesystem directories and
+// directly in a provider's upstream registry. Any providers that have at least
+// one version available in a local directory are implicitly excluded from
+// direct installation, as if the user had listed them explicitly in the
+// "exclude" argument in the direct provider source in the CLI config.
+func implicitProviderSource(services *disco.Disco) getproviders.Source {
+	// The local search directories we use for implicit configuration are:
+	// - The "terraform.d/plugins" directory in the current working directory,
+	//   which we've historically documented as a place to put plugins as a
+	//   way to include them in bundles uploaded to Terraform Cloud, where
+	//   there has historically otherwise been no way to use custom providers.
+	// - The "plugins" subdirectory of the CLI config search directory.
+	//   (thats ~/.terraform.d/plugins on Unix systems, equivalents elsewhere)
+	// - The "plugins" subdirectory of any platform-specific search paths,
+	//   following e.g. the XDG base directory specification on Unix systems,
+	//   Apple's guidelines on OS X, and "known folders" on Windows.
+	//
+	// Any provider we find in one of those implicit directories will be
+	// automatically excluded from direct installation from an upstream
+	// registry. Anything not available locally will query its primary
+	// upstream registry.
+	var searchRules []getproviders.MultiSourceSelector
+
+	// We'll track any providers we can find in the local search directories
+	// along the way, and then exclude them from the registry source we'll
+	// finally add at the end.
+	foundLocally := map[addrs.Provider]struct{}{}
+
+	addLocalDir := func(dir string) {
+		// We'll make sure the directory actually exists before we add it,
+		// because otherwise installation would always fail trying to look
+		// in non-existent directories. (This is done here rather than in
+		// the source itself because explicitly-selected directories via the
+		// CLI config, once we have them, _should_ produce an error if they
+		// don't exist to help users get their configurations right.)
+		if info, err := os.Stat(dir); err == nil && info.IsDir() {
+			log.Printf("[DEBUG] will search for provider plugins in %s", dir)
+			fsSource := getproviders.NewFilesystemMirrorSource(dir)
+
+			// We'll peep into the source to find out what providers it seems
+			// to be providing, so that we can exclude those from direct
+			// install. This might fail, in which case we'll just silently
+			// ignore it and assume it would fail during installation later too
+			// and therefore effectively doesn't provide _any_ packages.
+			if available, err := fsSource.AllAvailablePackages(); err == nil {
+				for found := range available {
+					foundLocally[found] = struct{}{}
+				}
+			}
+
+			searchRules = append(searchRules, getproviders.MultiSourceSelector{
+				Source: fsSource,
+			})
+
+		} else {
+			log.Printf("[DEBUG] ignoring non-existing provider search directory %s", dir)
+		}
+	}
+
+	addLocalDir("terraform.d/plugins") // our "vendor" directory
+	cliConfigDir, err := cliconfig.ConfigDir()
+	if err == nil {
+		addLocalDir(filepath.Join(cliConfigDir, "plugins"))
+	}
+
+	// This "userdirs" library implements an appropriate user-specific and
+	// app-specific directory layout for the current platform, such as XDG Base
+	// Directory on Unix, using the following name strings to construct a
+	// suitable application-specific subdirectory name following the
+	// conventions for each platform:
+	//
+	//   XDG (Unix): lowercase of the first string, "terraform"
+	//   Windows:    two-level hierarchy of first two strings, "HashiCorp\Terraform"
+	//   OS X:       reverse-DNS unique identifier, "io.terraform".
+	sysSpecificDirs := userdirs.ForApp("Terraform", "HashiCorp", "io.terraform")
+	for _, dir := range sysSpecificDirs.DataSearchPaths("plugins") {
+		addLocalDir(dir)
+	}
+
+	// Anything we found in local directories above is excluded from being
+	// looked up via the registry source we're about to construct.
+	var directExcluded getproviders.MultiSourceMatchingPatterns
+	for addr := range foundLocally {
+		directExcluded = append(directExcluded, addr)
+	}
+
+	// Last but not least, the main registry source! We'll wrap a caching
+	// layer around this one to help optimize the several network requests
+	// we'll end up making to it while treating it as one of several sources
+	// in a MultiSource (as recommended in the MultiSource docs).
+	// This one is listed last so that if a particular version is available
+	// both in one of the above directories _and_ in a remote registry, the
+	// local copy will take precedence.
+	searchRules = append(searchRules, getproviders.MultiSourceSelector{
+		Source: getproviders.NewMemoizeSource(
+			getproviders.NewRegistrySource(services),
+		),
+		Exclude: directExcluded,
+	})
+
+	return getproviders.MultiSource(searchRules)
+}
+
+func providerSourceForCLIConfigLocation(loc cliconfig.ProviderInstallationLocation, services *disco.Disco) (getproviders.Source, tfdiags.Diagnostics) {
+	if loc == cliconfig.ProviderInstallationDirect {
+		return getproviders.NewMemoizeSource(
+			getproviders.NewRegistrySource(services),
+		), nil
+	}
+
+	switch loc := loc.(type) {
+
+	case cliconfig.ProviderInstallationFilesystemMirror:
+		return getproviders.NewFilesystemMirrorSource(string(loc)), nil
+
+	case cliconfig.ProviderInstallationNetworkMirror:
+		url, err := url.Parse(string(loc))
+		if err != nil {
+			var diags tfdiags.Diagnostics
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid URL for provider installation source",
+				fmt.Sprintf("Cannot parse %q as a URL for a network provider mirror: %s.", string(loc), err),
+			))
+			return nil, diags
+		}
+		if url.Scheme != "https" || url.Host == "" {
+			var diags tfdiags.Diagnostics
+			diags = diags.Append(tfdiags.Sourceless(
+				tfdiags.Error,
+				"Invalid URL for provider installation source",
+				fmt.Sprintf("Cannot use %q as a URL for a network provider mirror: the mirror must be at an https: URL.", string(loc)),
+			))
+			return nil, diags
+		}
+		return getproviders.NewHTTPMirrorSource(url, services.CredentialsSource()), nil
+
+	default:
+		// We should not get here because the set of cases above should
+		// be comprehensive for all of the
+		// cliconfig.ProviderInstallationLocation implementations.
+		panic(fmt.Sprintf("unexpected provider source location type %T", loc))
+	}
+}
+
+func providerDevOverrides(configs []*cliconfig.ProviderInstallation) map[addrs.Provider]getproviders.PackageLocalDir {
+	if len(configs) == 0 {
+		return nil
+	}
+
+	// There should only be zero or one configurations, which is checked by
+	// the validation logic in the cliconfig package. Therefore we'll just
+	// ignore any additional configurations in here.
+	return configs[0].DevOverrides
+}
diff --git a/v1.5.7/scripts/build.sh b/v1.5.7/scripts/build.sh
new file mode 100755
index 0000000..1b59bf2
--- /dev/null
+++ b/v1.5.7/scripts/build.sh
@@ -0,0 +1,105 @@
+#!/usr/bin/env bash
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+#
+# This script builds the application from source for multiple platforms.
+
+# Get the parent directory of where this script is.
+SOURCE="${BASH_SOURCE[0]}"
+while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done
+DIR="$( cd -P "$( dirname "$SOURCE" )/.." && pwd )"
+
+# Change into that directory
+cd "$DIR"
+
+# Determine the arch/os combos we're building for
+XC_ARCH=${XC_ARCH:-"386 amd64 arm"}
+XC_OS=${XC_OS:-linux darwin windows freebsd openbsd solaris}
+XC_EXCLUDE_OSARCH="!darwin/arm !darwin/386"
+
+# Delete the old dir
+echo "==> Removing old directory..."
+rm -f bin/*
+rm -rf pkg/*
+mkdir -p bin/
+
+# If its dev mode, only build for ourself
+if [[ -n "${TF_DEV}" ]]; then
+    XC_OS=$(go env GOOS)
+    XC_ARCH=$(go env GOARCH)
+fi
+
+if ! which gox > /dev/null; then
+    echo "==> Installing gox..."
+    go install github.com/mitchellh/gox
+fi
+
+# Instruct gox to build statically linked binaries
+export CGO_ENABLED=0
+
+# Set module download mode to readonly to not implicitly update go.mod
+export GOFLAGS="-mod=readonly"
+
+# In release mode we don't want debug information in the binary
+if [[ -n "${TF_RELEASE}" ]]; then
+    LD_FLAGS="-s -w"
+fi
+
+# Ensure all remote modules are downloaded and cached before build so that
+# the concurrent builds launched by gox won't race to redundantly download them.
+go mod download
+
+# Build!
+echo "==> Building..."
+gox \
+    -os="${XC_OS}" \
+    -arch="${XC_ARCH}" \
+    -osarch="${XC_EXCLUDE_OSARCH}" \
+    -ldflags "${LD_FLAGS}" \
+    -output "pkg/{{.OS}}_{{.Arch}}/terraform" \
+    .
+
+# Move all the compiled things to the $GOPATH/bin
+GOPATH=${GOPATH:-$(go env GOPATH)}
+case $(uname) in
+    CYGWIN*)
+        GOPATH="$(cygpath $GOPATH)"
+        ;;
+esac
+OLDIFS=$IFS
+IFS=: MAIN_GOPATH=($GOPATH)
+IFS=$OLDIFS
+
+# Create GOPATH/bin if it's doesn't exists
+if [ ! -d $MAIN_GOPATH/bin ]; then
+    echo "==> Creating GOPATH/bin directory..."
+    mkdir -p $MAIN_GOPATH/bin
+fi
+
+# Copy our OS/Arch to the bin/ directory
+DEV_PLATFORM="./pkg/$(go env GOOS)_$(go env GOARCH)"
+if [[ -d "${DEV_PLATFORM}" ]]; then
+    for F in $(find ${DEV_PLATFORM} -mindepth 1 -maxdepth 1 -type f); do
+        cp ${F} bin/
+        cp ${F} ${MAIN_GOPATH}/bin/
+    done
+fi
+
+if [ "${TF_DEV}x" = "x" ]; then
+    # Zip and copy to the dist dir
+    echo "==> Packaging..."
+    for PLATFORM in $(find ./pkg -mindepth 1 -maxdepth 1 -type d); do
+        OSARCH=$(basename ${PLATFORM})
+        echo "--> ${OSARCH}"
+
+        pushd $PLATFORM >/dev/null 2>&1
+        zip ../${OSARCH}.zip ./*
+        popd >/dev/null 2>&1
+    done
+fi
+
+# Done!
+echo
+echo "==> Results:"
+ls -hl bin/
diff --git a/v1.5.7/scripts/changelog-links.sh b/v1.5.7/scripts/changelog-links.sh
new file mode 100755
index 0000000..fe1fff7
--- /dev/null
+++ b/v1.5.7/scripts/changelog-links.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+
+# This script rewrites [GH-nnnn]-style references in the CHANGELOG.md file to
+# be Markdown links to the given github issues.
+#
+# This is run during releases so that the issue references in all of the
+# released items are presented as clickable links, but we can just use the
+# easy [GH-nnnn] shorthand for quickly adding items to the "Unrelease" section
+# while merging things between releases.
+
+set -e
+
+if [[ ! -f CHANGELOG.md ]]; then
+  echo "ERROR: CHANGELOG.md not found in pwd."
+  echo "Please run this from the root of the terraform source repository"
+  exit 1
+fi
+
+if [[ `uname` == "Darwin" ]]; then
+  echo "Using BSD sed"
+  SED="sed -i.bak -E -e"
+else
+  echo "Using GNU sed"
+  SED="sed -i.bak -r -e"
+fi
+
+$SED 's/GH-([0-9]+)/\[#\1\]\(https:\/\/github.com\/hashicorp\/terraform\/issues\/\1\)/g' -e 's/\[\[#(.+)([0-9])\)]$/(\[#\1\2))/g' CHANGELOG.md
+
+rm CHANGELOG.md.bak
diff --git a/v1.5.7/scripts/debug-terraform b/v1.5.7/scripts/debug-terraform
new file mode 100755
index 0000000..f2dfae0
--- /dev/null
+++ b/v1.5.7/scripts/debug-terraform
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+# This is a helper script to launch Terraform inside the "dlv" debugger,
+# configured to await a remote debugging connection on port 2345. You can
+# then connect to it using the following command, or its equivalent in your
+# debugging frontend of choice:
+#    dlv connect 127.0.0.1:2345
+#
+# This tool does not install dlv. To install it, see its instructions:
+#    https://github.com/derekparker/delve/tree/master/Documentation/installation
+#
+# For more convenient use, you may wish to put this script in your PATH:
+#    ln -s ../src/github.com/hashicorp/terraform/scripts/debug-terraform $GOPATH/bin/debug-terraform
+#
+# Note that when running this script the Terraform binary is NOT in $GOPATH/bin,
+# so any providers installed there won't be found unless Terraform searches
+# there for some _other_ reason.
+
+set -eu
+
+echo "Launching Terraform in a headless debug session"
+echo "Connect to it using: dlv connect 127.0.0.1:2345"
+echo "(Terraform takes a long time to build and launch in this mode; some logs will appear below)"
+echo "---------------------------"
+
+exec dlv debug github.com/hashicorp/terraform --headless --listen :2345 --log -- "$@"
diff --git a/v1.5.7/scripts/exhaustive.sh b/v1.5.7/scripts/exhaustive.sh
new file mode 100755
index 0000000..eda66db
--- /dev/null
+++ b/v1.5.7/scripts/exhaustive.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+
+echo "==> Checking for switch statement exhaustiveness..."
+
+# For now we're only checking a handful of packages, rather than defaulting to
+# everything with a skip list.
+go run github.com/nishanths/exhaustive/cmd/exhaustive ./internal/command/views/json
diff --git a/v1.5.7/scripts/gofmtcheck.sh b/v1.5.7/scripts/gofmtcheck.sh
new file mode 100755
index 0000000..ccd9496
--- /dev/null
+++ b/v1.5.7/scripts/gofmtcheck.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+
+# Check go fmt
+echo "==> Checking that code complies with go fmt requirements..."
+gofmt_files=$(go fmt ./...)
+if [[ -n ${gofmt_files} ]]; then
+    echo 'gofmt needs running on the following files:'
+    echo "${gofmt_files}"
+    echo "You can use the command: \`go fmt\` to reformat code."
+    exit 1
+fi
+
+exit 0
diff --git a/v1.5.7/scripts/gogetcookie.sh b/v1.5.7/scripts/gogetcookie.sh
new file mode 100755
index 0000000..347487a
--- /dev/null
+++ b/v1.5.7/scripts/gogetcookie.sh
@@ -0,0 +1,11 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+touch ~/.gitcookies
+chmod 0600 ~/.gitcookies
+
+git config --global http.cookiefile ~/.gitcookies
+
+tr , \\t <<\__END__ >>~/.gitcookies
+go.googlesource.com,FALSE,/,TRUE,2147483647,o,git-admin.hashicorptest.com=1/5dMSZVNdQscVq3on5V38iBrG9sP2TYRlbj3TDMJHKEvoBxl_QW-zl-L7a8lk-FU-
+__END__
diff --git a/v1.5.7/scripts/goimportscheck.sh b/v1.5.7/scripts/goimportscheck.sh
new file mode 100755
index 0000000..893c662
--- /dev/null
+++ b/v1.5.7/scripts/goimportscheck.sh
@@ -0,0 +1,81 @@
+#!/usr/bin/env bash
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+
+set -euo pipefail
+
+# Check goimports
+echo "==> Checking the code complies with goimports requirements..."
+
+# We only require goimports to have been run on files that were changed
+# relative to the main branch, so that we can gradually create more consistency
+# rather than bulk-changing everything at once.
+
+declare -a target_files
+# "readarray" will return an "unbound variable" error if there isn't already
+# at least one element in the target array. "readarray" will overwrite this
+# item, though.
+target_files[0]=""
+
+base_branch="origin/main"
+
+# HACK: If we seem to be running inside a GitHub Actions pull request check
+# then we'll use the PR's target branch from this variable instead.
+if [[ -n "${GITHUB_BASE_REF:-}" ]]; then
+  base_branch="origin/$GITHUB_BASE_REF"
+fi
+
+# FIXME: "readarray' is a Bash 4 feature, which means that currently this script
+# can't work on macOS which (at the time of writing this) ships with only Bash 3.
+# We can probably replace this with something more clunky using an overridden
+# "IFS" environment variable, but the primary place we want to run this right
+# now is in our "quick checks" workflow and that _does_ have a reasonably
+# modern version of Bash.
+readarray -t target_files < <(git diff --name-only ${base_branch} --diff-filter=MA | grep "\.go" | grep -v ".pb.go" | grep -v ".go-version")
+
+# NOTE: The above intentionally excludes .pb.go files because those are
+# generated by a tool (protoc-gen-go) which itself doesn't produce
+# style-compliant imports.
+
+if [[ "${#target_files[@]}" -eq 0 ]]; then
+  echo "No files have changed relative to branch ${base_branch}, so there's nothing to check!"
+  exit 0
+fi
+
+declare -a incorrect_files
+# Array must have at least one item before we can append to it. Code below must
+# work around this extra empty-string element at the beginning of the array.
+incorrect_files[0]=""
+
+for filename in "${target_files[@]}"; do
+  if [[ -z "$filename" ]]; then
+    continue
+  fi
+
+  output=$(go run golang.org/x/tools/cmd/goimports -l "${filename}")
+  if [[ $? -ne 0 ]]; then
+    echo >&2 goimports failed for "$filename"
+    exit 1
+  fi
+
+  if [[ -n "$output" ]]; then
+    incorrect_files+=("$filename")
+  fi
+done
+
+if [[ "${#incorrect_files[@]}" -gt 1 ]]; then
+  echo >&2 'The following files have import statements that disagree with "goimports"':
+  for filename in "${incorrect_files[@]}"; do
+    if [[ -z "$filename" ]]; then
+      continue
+    fi
+
+    echo >&2 ' - ' "${filename}"
+  done
+  echo >&2 'Use `go run golang.org/x/tools/cmd/goimports -w -l` on each of these files to update these files.'
+  exit 1
+fi
+
+echo 'All of the changed files look good!'
+exit 0
diff --git a/v1.5.7/scripts/staticcheck.sh b/v1.5.7/scripts/staticcheck.sh
new file mode 100755
index 0000000..771c40a
--- /dev/null
+++ b/v1.5.7/scripts/staticcheck.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+
+echo "==> Checking that code complies with static analysis requirements..."
+# Skip legacy code which is frozen, and can be removed once we can refactor the
+# remote backends to no longer require it.
+skip="internal/legacy|backend/remote-state/"
+
+# Skip generated code for protobufs.
+skip=$skip"|internal/planproto|internal/tfplugin5|internal/tfplugin6"
+
+packages=$(go list ./... | egrep -v ${skip})
+
+# We are skipping style-related checks, since terraform intentionally breaks
+# some of these. The goal here is to find issues that reduce code clarity, or
+# may result in bugs. We also disable fucntion deprecation checks (SA1019)
+# because our policy is to update deprecated calls locally while making other
+# nearby changes, rather than to make cross-cutting changes to update them all.
+go run honnef.co/go/tools/cmd/staticcheck -checks 'all,-SA1019,-ST*' ${packages}
diff --git a/v1.5.7/signal_unix.go b/v1.5.7/signal_unix.go
new file mode 100644
index 0000000..2b076f7
--- /dev/null
+++ b/v1.5.7/signal_unix.go
@@ -0,0 +1,15 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build !windows
+// +build !windows
+
+package main
+
+import (
+	"os"
+	"syscall"
+)
+
+var ignoreSignals = []os.Signal{os.Interrupt}
+var forwardSignals = []os.Signal{syscall.SIGTERM}
diff --git a/v1.5.7/signal_windows.go b/v1.5.7/signal_windows.go
new file mode 100644
index 0000000..613ad30
--- /dev/null
+++ b/v1.5.7/signal_windows.go
@@ -0,0 +1,14 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build windows
+// +build windows
+
+package main
+
+import (
+	"os"
+)
+
+var ignoreSignals = []os.Signal{os.Interrupt}
+var forwardSignals []os.Signal
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_json_string_update/apply.json b/v1.5.7/testing/equivalence-tests/outputs/basic_json_string_update/apply.json
new file mode 100644
index 0000000..3129e26
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_json_string_update/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.json: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.json",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.json",
+        "resource_key": null,
+        "resource_name": "json",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.json: Modifying... [id=5a3fd9b3-e852-8956-8c0a-255d47eda645]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "5a3fd9b3-e852-8956-8c0a-255d47eda645",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.json",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.json",
+        "resource_key": null,
+        "resource_name": "json",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.json: Modifications complete after 0s [id=5a3fd9b3-e852-8956-8c0a-255d47eda645]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "5a3fd9b3-e852-8956-8c0a-255d47eda645",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.json",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.json",
+        "resource_key": null,
+        "resource_name": "json",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_json_string_update/plan b/v1.5.7/testing/equivalence-tests/outputs/basic_json_string_update/plan
new file mode 100644
index 0000000..654a7f1
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_json_string_update/plan
@@ -0,0 +1,38 @@
+tfcoremock_simple_resource.json: Refreshing state... [id=5a3fd9b3-e852-8956-8c0a-255d47eda645]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_simple_resource.json will be updated in-place
+  ~ resource "tfcoremock_simple_resource" "json" {
+        id     = "5a3fd9b3-e852-8956-8c0a-255d47eda645"
+      ~ string = jsonencode(
+          ~ {
+              ~ list-attribute   = [
+                    "one",
+                  - "two",
+                  + "four",
+                    "three",
+                ]
+              ~ object-attribute = {
+                  + key_four  = "value_three"
+                  ~ key_three = "value_three" -> "value_two"
+                  - key_two   = "value_two"
+                    # (1 unchanged attribute hidden)
+                }
+              ~ string-attribute = "string" -> "a new string"
+            }
+        )
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_json_string_update/plan.json b/v1.5.7/testing/equivalence-tests/outputs/basic_json_string_update/plan.json
new file mode 100644
index 0000000..46f693e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_json_string_update/plan.json
@@ -0,0 +1,112 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.json",
+          "expressions": {
+            "string": {
+              "constant_value": "{\"list-attribute\":[\"one\",\"four\",\"three\"],\"object-attribute\":{\"key_one\":\"value_one\",\"key_three\":\"value_two\", \"key_four\":\"value_three\"},\"string-attribute\":\"a new string\"}"
+            }
+          },
+          "mode": "managed",
+          "name": "json",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_simple_resource"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.json",
+          "mode": "managed",
+          "name": "json",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "5a3fd9b3-e852-8956-8c0a-255d47eda645",
+            "integer": null,
+            "number": null,
+            "string": "{\"list-attribute\":[\"one\",\"four\",\"three\"],\"object-attribute\":{\"key_one\":\"value_one\",\"key_three\":\"value_two\", \"key_four\":\"value_three\"},\"string-attribute\":\"a new string\"}"
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_simple_resource.json",
+            "mode": "managed",
+            "name": "json",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {},
+            "type": "tfcoremock_simple_resource",
+            "values": {
+              "bool": null,
+              "float": null,
+              "id": "5a3fd9b3-e852-8956-8c0a-255d47eda645",
+              "integer": null,
+              "number": null,
+              "string": "{\"list-attribute\":[\"one\",\"two\",\"three\"],\"object-attribute\":{\"key_one\":\"value_one\",\"key_two\":\"value_two\",\"key_three\":\"value_three\"},\"string-attribute\":\"string\"}"
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_simple_resource.json",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "id": "5a3fd9b3-e852-8956-8c0a-255d47eda645",
+          "integer": null,
+          "number": null,
+          "string": "{\"list-attribute\":[\"one\",\"four\",\"three\"],\"object-attribute\":{\"key_one\":\"value_one\",\"key_three\":\"value_two\", \"key_four\":\"value_three\"},\"string-attribute\":\"a new string\"}"
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "bool": null,
+          "float": null,
+          "id": "5a3fd9b3-e852-8956-8c0a-255d47eda645",
+          "integer": null,
+          "number": null,
+          "string": "{\"list-attribute\":[\"one\",\"two\",\"three\"],\"object-attribute\":{\"key_one\":\"value_one\",\"key_two\":\"value_two\",\"key_three\":\"value_three\"},\"string-attribute\":\"string\"}"
+        },
+        "before_sensitive": {}
+      },
+      "mode": "managed",
+      "name": "json",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    }
+  ],
+  "timestamp": "2023-05-25T07:34:45Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_json_string_update/state b/v1.5.7/testing/equivalence-tests/outputs/basic_json_string_update/state
new file mode 100644
index 0000000..73038c1
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_json_string_update/state
@@ -0,0 +1,19 @@
+# tfcoremock_simple_resource.json:
+resource "tfcoremock_simple_resource" "json" {
+    id     = "5a3fd9b3-e852-8956-8c0a-255d47eda645"
+    string = jsonencode(
+        {
+            list-attribute   = [
+                "one",
+                "four",
+                "three",
+            ]
+            object-attribute = {
+                key_four  = "value_three"
+                key_one   = "value_one"
+                key_three = "value_two"
+            }
+            string-attribute = "a new string"
+        }
+    )
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_json_string_update/state.json b/v1.5.7/testing/equivalence-tests/outputs/basic_json_string_update/state.json
new file mode 100644
index 0000000..6782081
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_json_string_update/state.json
@@ -0,0 +1,26 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.json",
+          "mode": "managed",
+          "name": "json",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "5a3fd9b3-e852-8956-8c0a-255d47eda645",
+            "integer": null,
+            "number": null,
+            "string": "{\"list-attribute\":[\"one\",\"four\",\"three\"],\"object-attribute\":{\"key_one\":\"value_one\",\"key_three\":\"value_two\", \"key_four\":\"value_three\"},\"string-attribute\":\"a new string\"}"
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list/apply.json b/v1.5.7/testing/equivalence-tests/outputs/basic_list/apply.json
new file mode 100644
index 0000000..932f4f5
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list/apply.json
@@ -0,0 +1,79 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Plan to create",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Creation complete after 0s [id=985820B3-ACF9-4F00-94AD-F81C5EA33663]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list/plan b/v1.5.7/testing/equivalence-tests/outputs/basic_list/plan
new file mode 100644
index 0000000..dee4008
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list/plan
@@ -0,0 +1,25 @@
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  # tfcoremock_list.list will be created
+  + resource "tfcoremock_list" "list" {
+      + id   = "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+      + list = [
+          + "9C2BE420-042D-440A-96E9-75565341C994",
+          + "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+          + "D01290F6-2D3A-45FA-B006-DAA80F6D31F6",
+        ]
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list/plan.json b/v1.5.7/testing/equivalence-tests/outputs/basic_list/plan.json
new file mode 100644
index 0000000..e3c2428
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list/plan.json
@@ -0,0 +1,98 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_list.list",
+          "expressions": {
+            "id": {
+              "constant_value": "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+            },
+            "list": {
+              "constant_value": [
+                "9C2BE420-042D-440A-96E9-75565341C994",
+                "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+                "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+              ]
+            }
+          },
+          "mode": "managed",
+          "name": "list",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_list"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_list.list",
+          "mode": "managed",
+          "name": "list",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "list": [
+              false,
+              false,
+              false
+            ]
+          },
+          "type": "tfcoremock_list",
+          "values": {
+            "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+            "list": [
+              "9C2BE420-042D-440A-96E9-75565341C994",
+              "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+              "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_list.list",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "after": {
+          "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+          "list": [
+            "9C2BE420-042D-440A-96E9-75565341C994",
+            "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+            "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+          ]
+        },
+        "after_sensitive": {
+          "list": [
+            false,
+            false,
+            false
+          ]
+        },
+        "after_unknown": {},
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "managed",
+      "name": "list",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_list"
+    }
+  ],
+  "timestamp": "2023-05-25T07:34:47Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list/state b/v1.5.7/testing/equivalence-tests/outputs/basic_list/state
new file mode 100644
index 0000000..a4d6988
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list/state
@@ -0,0 +1,9 @@
+# tfcoremock_list.list:
+resource "tfcoremock_list" "list" {
+    id   = "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+    list = [
+        "9C2BE420-042D-440A-96E9-75565341C994",
+        "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+        "D01290F6-2D3A-45FA-B006-DAA80F6D31F6",
+    ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list/state.json b/v1.5.7/testing/equivalence-tests/outputs/basic_list/state.json
new file mode 100644
index 0000000..4e3ccc9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list/state.json
@@ -0,0 +1,32 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_list.list",
+          "mode": "managed",
+          "name": "list",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "list": [
+              false,
+              false,
+              false
+            ]
+          },
+          "type": "tfcoremock_list",
+          "values": {
+            "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+            "list": [
+              "9C2BE420-042D-440A-96E9-75565341C994",
+              "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+              "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list_empty/apply.json b/v1.5.7/testing/equivalence-tests/outputs/basic_list_empty/apply.json
new file mode 100644
index 0000000..ed89b85
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list_empty/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Modifying... [id=985820B3-ACF9-4F00-94AD-F81C5EA33663]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Modifications complete after 0s [id=985820B3-ACF9-4F00-94AD-F81C5EA33663]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list_empty/plan b/v1.5.7/testing/equivalence-tests/outputs/basic_list_empty/plan
new file mode 100644
index 0000000..8f4de24
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list_empty/plan
@@ -0,0 +1,26 @@
+tfcoremock_list.list: Refreshing state... [id=985820B3-ACF9-4F00-94AD-F81C5EA33663]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_list.list will be updated in-place
+  ~ resource "tfcoremock_list" "list" {
+        id   = "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+      ~ list = [
+          - "9C2BE420-042D-440A-96E9-75565341C994",
+          - "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+          - "D01290F6-2D3A-45FA-B006-DAA80F6D31F6",
+        ]
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list_empty/plan.json b/v1.5.7/testing/equivalence-tests/outputs/basic_list_empty/plan.json
new file mode 100644
index 0000000..54c604e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list_empty/plan.json
@@ -0,0 +1,123 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_list.list",
+          "expressions": {
+            "id": {
+              "constant_value": "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+            },
+            "list": {
+              "constant_value": []
+            }
+          },
+          "mode": "managed",
+          "name": "list",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_list"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_list.list",
+          "mode": "managed",
+          "name": "list",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "list": []
+          },
+          "type": "tfcoremock_list",
+          "values": {
+            "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+            "list": []
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_list.list",
+            "mode": "managed",
+            "name": "list",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "list": [
+                false,
+                false,
+                false
+              ]
+            },
+            "type": "tfcoremock_list",
+            "values": {
+              "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+              "list": [
+                "9C2BE420-042D-440A-96E9-75565341C994",
+                "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+                "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+              ]
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_list.list",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+          "list": []
+        },
+        "after_sensitive": {
+          "list": []
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+          "list": [
+            "9C2BE420-042D-440A-96E9-75565341C994",
+            "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+            "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+          ]
+        },
+        "before_sensitive": {
+          "list": [
+            false,
+            false,
+            false
+          ]
+        }
+      },
+      "mode": "managed",
+      "name": "list",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_list"
+    }
+  ],
+  "timestamp": "2023-05-25T07:34:49Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list_empty/state b/v1.5.7/testing/equivalence-tests/outputs/basic_list_empty/state
new file mode 100644
index 0000000..71e4d83
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list_empty/state
@@ -0,0 +1,5 @@
+# tfcoremock_list.list:
+resource "tfcoremock_list" "list" {
+    id   = "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+    list = []
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list_empty/state.json b/v1.5.7/testing/equivalence-tests/outputs/basic_list_empty/state.json
new file mode 100644
index 0000000..c538681
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list_empty/state.json
@@ -0,0 +1,24 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_list.list",
+          "mode": "managed",
+          "name": "list",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "list": []
+          },
+          "type": "tfcoremock_list",
+          "values": {
+            "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+            "list": []
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list_null/apply.json b/v1.5.7/testing/equivalence-tests/outputs/basic_list_null/apply.json
new file mode 100644
index 0000000..ed89b85
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list_null/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Modifying... [id=985820B3-ACF9-4F00-94AD-F81C5EA33663]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Modifications complete after 0s [id=985820B3-ACF9-4F00-94AD-F81C5EA33663]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list_null/plan b/v1.5.7/testing/equivalence-tests/outputs/basic_list_null/plan
new file mode 100644
index 0000000..a9f8617
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list_null/plan
@@ -0,0 +1,26 @@
+tfcoremock_list.list: Refreshing state... [id=985820B3-ACF9-4F00-94AD-F81C5EA33663]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_list.list will be updated in-place
+  ~ resource "tfcoremock_list" "list" {
+        id   = "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+      - list = [
+          - "9C2BE420-042D-440A-96E9-75565341C994",
+          - "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+          - "D01290F6-2D3A-45FA-B006-DAA80F6D31F6",
+        ] -> null
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list_null/plan.json b/v1.5.7/testing/equivalence-tests/outputs/basic_list_null/plan.json
new file mode 100644
index 0000000..5cd559c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list_null/plan.json
@@ -0,0 +1,116 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_list.list",
+          "expressions": {
+            "id": {
+              "constant_value": "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+            }
+          },
+          "mode": "managed",
+          "name": "list",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_list"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_list.list",
+          "mode": "managed",
+          "name": "list",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_list",
+          "values": {
+            "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+            "list": null
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_list.list",
+            "mode": "managed",
+            "name": "list",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "list": [
+                false,
+                false,
+                false
+              ]
+            },
+            "type": "tfcoremock_list",
+            "values": {
+              "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+              "list": [
+                "9C2BE420-042D-440A-96E9-75565341C994",
+                "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+                "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+              ]
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_list.list",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+          "list": null
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+          "list": [
+            "9C2BE420-042D-440A-96E9-75565341C994",
+            "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+            "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+          ]
+        },
+        "before_sensitive": {
+          "list": [
+            false,
+            false,
+            false
+          ]
+        }
+      },
+      "mode": "managed",
+      "name": "list",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_list"
+    }
+  ],
+  "timestamp": "2023-05-25T07:34:51Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list_null/state b/v1.5.7/testing/equivalence-tests/outputs/basic_list_null/state
new file mode 100644
index 0000000..5e0291d
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list_null/state
@@ -0,0 +1,4 @@
+# tfcoremock_list.list:
+resource "tfcoremock_list" "list" {
+    id = "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list_null/state.json b/v1.5.7/testing/equivalence-tests/outputs/basic_list_null/state.json
new file mode 100644
index 0000000..79251ad
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list_null/state.json
@@ -0,0 +1,22 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_list.list",
+          "mode": "managed",
+          "name": "list",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_list",
+          "values": {
+            "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+            "list": null
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list_update/apply.json b/v1.5.7/testing/equivalence-tests/outputs/basic_list_update/apply.json
new file mode 100644
index 0000000..ed89b85
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list_update/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Modifying... [id=985820B3-ACF9-4F00-94AD-F81C5EA33663]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Modifications complete after 0s [id=985820B3-ACF9-4F00-94AD-F81C5EA33663]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list_update/plan b/v1.5.7/testing/equivalence-tests/outputs/basic_list_update/plan
new file mode 100644
index 0000000..6263c29
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list_update/plan
@@ -0,0 +1,27 @@
+tfcoremock_list.list: Refreshing state... [id=985820B3-ACF9-4F00-94AD-F81C5EA33663]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_list.list will be updated in-place
+  ~ resource "tfcoremock_list" "list" {
+        id   = "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+      ~ list = [
+            "9C2BE420-042D-440A-96E9-75565341C994",
+          - "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+            "D01290F6-2D3A-45FA-B006-DAA80F6D31F6",
+          + "9B9F3ADF-8AD4-4E8C-AFE4-7BC2413E9AC0",
+        ]
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list_update/plan.json b/v1.5.7/testing/equivalence-tests/outputs/basic_list_update/plan.json
new file mode 100644
index 0000000..fe00404
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list_update/plan.json
@@ -0,0 +1,143 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_list.list",
+          "expressions": {
+            "id": {
+              "constant_value": "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+            },
+            "list": {
+              "constant_value": [
+                "9C2BE420-042D-440A-96E9-75565341C994",
+                "D01290F6-2D3A-45FA-B006-DAA80F6D31F6",
+                "9B9F3ADF-8AD4-4E8C-AFE4-7BC2413E9AC0"
+              ]
+            }
+          },
+          "mode": "managed",
+          "name": "list",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_list"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_list.list",
+          "mode": "managed",
+          "name": "list",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "list": [
+              false,
+              false,
+              false
+            ]
+          },
+          "type": "tfcoremock_list",
+          "values": {
+            "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+            "list": [
+              "9C2BE420-042D-440A-96E9-75565341C994",
+              "D01290F6-2D3A-45FA-B006-DAA80F6D31F6",
+              "9B9F3ADF-8AD4-4E8C-AFE4-7BC2413E9AC0"
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_list.list",
+            "mode": "managed",
+            "name": "list",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "list": [
+                false,
+                false,
+                false
+              ]
+            },
+            "type": "tfcoremock_list",
+            "values": {
+              "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+              "list": [
+                "9C2BE420-042D-440A-96E9-75565341C994",
+                "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+                "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+              ]
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_list.list",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+          "list": [
+            "9C2BE420-042D-440A-96E9-75565341C994",
+            "D01290F6-2D3A-45FA-B006-DAA80F6D31F6",
+            "9B9F3ADF-8AD4-4E8C-AFE4-7BC2413E9AC0"
+          ]
+        },
+        "after_sensitive": {
+          "list": [
+            false,
+            false,
+            false
+          ]
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+          "list": [
+            "9C2BE420-042D-440A-96E9-75565341C994",
+            "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+            "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+          ]
+        },
+        "before_sensitive": {
+          "list": [
+            false,
+            false,
+            false
+          ]
+        }
+      },
+      "mode": "managed",
+      "name": "list",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_list"
+    }
+  ],
+  "timestamp": "2023-05-25T07:34:52Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list_update/state b/v1.5.7/testing/equivalence-tests/outputs/basic_list_update/state
new file mode 100644
index 0000000..4df3a39
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list_update/state
@@ -0,0 +1,9 @@
+# tfcoremock_list.list:
+resource "tfcoremock_list" "list" {
+    id   = "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+    list = [
+        "9C2BE420-042D-440A-96E9-75565341C994",
+        "D01290F6-2D3A-45FA-B006-DAA80F6D31F6",
+        "9B9F3ADF-8AD4-4E8C-AFE4-7BC2413E9AC0",
+    ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_list_update/state.json b/v1.5.7/testing/equivalence-tests/outputs/basic_list_update/state.json
new file mode 100644
index 0000000..e6c1ae4
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_list_update/state.json
@@ -0,0 +1,32 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_list.list",
+          "mode": "managed",
+          "name": "list",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "list": [
+              false,
+              false,
+              false
+            ]
+          },
+          "type": "tfcoremock_list",
+          "values": {
+            "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+            "list": [
+              "9C2BE420-042D-440A-96E9-75565341C994",
+              "D01290F6-2D3A-45FA-B006-DAA80F6D31F6",
+              "9B9F3ADF-8AD4-4E8C-AFE4-7BC2413E9AC0"
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map/apply.json b/v1.5.7/testing/equivalence-tests/outputs/basic_map/apply.json
new file mode 100644
index 0000000..6a8c7e0
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map/apply.json
@@ -0,0 +1,79 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Plan to create",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Creation complete after 0s [id=50E1A46E-E64A-4C1F-881C-BA85A5440964]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map/plan b/v1.5.7/testing/equivalence-tests/outputs/basic_map/plan
new file mode 100644
index 0000000..d4b18d5
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map/plan
@@ -0,0 +1,25 @@
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  # tfcoremock_map.map will be created
+  + resource "tfcoremock_map" "map" {
+      + id  = "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+      + map = {
+          + "one"  = "682672C7-0918-4448-8342-887BAE01062A"
+          + "two"  = "212FFBF6-40FE-4862-B708-E6AA508E84E0"
+          + "zero" = "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+        }
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map/plan.json b/v1.5.7/testing/equivalence-tests/outputs/basic_map/plan.json
new file mode 100644
index 0000000..3836c00
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map/plan.json
@@ -0,0 +1,90 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_map.map",
+          "expressions": {
+            "id": {
+              "constant_value": "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+            },
+            "map": {
+              "constant_value": {
+                "one": "682672C7-0918-4448-8342-887BAE01062A",
+                "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+                "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+              }
+            }
+          },
+          "mode": "managed",
+          "name": "map",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_map"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_map.map",
+          "mode": "managed",
+          "name": "map",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "map": {}
+          },
+          "type": "tfcoremock_map",
+          "values": {
+            "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+            "map": {
+              "one": "682672C7-0918-4448-8342-887BAE01062A",
+              "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+              "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+            }
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_map.map",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "after": {
+          "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+          "map": {
+            "one": "682672C7-0918-4448-8342-887BAE01062A",
+            "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+            "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+          }
+        },
+        "after_sensitive": {
+          "map": {}
+        },
+        "after_unknown": {},
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "managed",
+      "name": "map",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_map"
+    }
+  ],
+  "timestamp": "2023-05-25T07:34:54Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map/state b/v1.5.7/testing/equivalence-tests/outputs/basic_map/state
new file mode 100644
index 0000000..3ef5b14
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map/state
@@ -0,0 +1,9 @@
+# tfcoremock_map.map:
+resource "tfcoremock_map" "map" {
+    id  = "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+    map = {
+        "one"  = "682672C7-0918-4448-8342-887BAE01062A"
+        "two"  = "212FFBF6-40FE-4862-B708-E6AA508E84E0"
+        "zero" = "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map/state.json b/v1.5.7/testing/equivalence-tests/outputs/basic_map/state.json
new file mode 100644
index 0000000..57d858c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map/state.json
@@ -0,0 +1,28 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_map.map",
+          "mode": "managed",
+          "name": "map",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "map": {}
+          },
+          "type": "tfcoremock_map",
+          "values": {
+            "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+            "map": {
+              "one": "682672C7-0918-4448-8342-887BAE01062A",
+              "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+              "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+            }
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map_empty/apply.json b/v1.5.7/testing/equivalence-tests/outputs/basic_map_empty/apply.json
new file mode 100644
index 0000000..28e766c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map_empty/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Modifying... [id=50E1A46E-E64A-4C1F-881C-BA85A5440964]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Modifications complete after 0s [id=50E1A46E-E64A-4C1F-881C-BA85A5440964]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map_empty/plan b/v1.5.7/testing/equivalence-tests/outputs/basic_map_empty/plan
new file mode 100644
index 0000000..0eae681
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map_empty/plan
@@ -0,0 +1,26 @@
+tfcoremock_map.map: Refreshing state... [id=50E1A46E-E64A-4C1F-881C-BA85A5440964]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_map.map will be updated in-place
+  ~ resource "tfcoremock_map" "map" {
+        id  = "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+      ~ map = {
+          - "one"  = "682672C7-0918-4448-8342-887BAE01062A" -> null
+          - "two"  = "212FFBF6-40FE-4862-B708-E6AA508E84E0" -> null
+          - "zero" = "6B044AF7-172B-495B-BE11-B9546C12C3BD" -> null
+        }
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map_empty/plan.json b/v1.5.7/testing/equivalence-tests/outputs/basic_map_empty/plan.json
new file mode 100644
index 0000000..ed54de3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map_empty/plan.json
@@ -0,0 +1,115 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_map.map",
+          "expressions": {
+            "id": {
+              "constant_value": "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+            },
+            "map": {
+              "constant_value": {}
+            }
+          },
+          "mode": "managed",
+          "name": "map",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_map"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_map.map",
+          "mode": "managed",
+          "name": "map",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "map": {}
+          },
+          "type": "tfcoremock_map",
+          "values": {
+            "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+            "map": {}
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_map.map",
+            "mode": "managed",
+            "name": "map",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "map": {}
+            },
+            "type": "tfcoremock_map",
+            "values": {
+              "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+              "map": {
+                "one": "682672C7-0918-4448-8342-887BAE01062A",
+                "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+                "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+              }
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_map.map",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+          "map": {}
+        },
+        "after_sensitive": {
+          "map": {}
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+          "map": {
+            "one": "682672C7-0918-4448-8342-887BAE01062A",
+            "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+            "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+          }
+        },
+        "before_sensitive": {
+          "map": {}
+        }
+      },
+      "mode": "managed",
+      "name": "map",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_map"
+    }
+  ],
+  "timestamp": "2023-05-25T07:34:56Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map_empty/state b/v1.5.7/testing/equivalence-tests/outputs/basic_map_empty/state
new file mode 100644
index 0000000..c658bfa
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map_empty/state
@@ -0,0 +1,5 @@
+# tfcoremock_map.map:
+resource "tfcoremock_map" "map" {
+    id  = "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+    map = {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map_empty/state.json b/v1.5.7/testing/equivalence-tests/outputs/basic_map_empty/state.json
new file mode 100644
index 0000000..28d17fd
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map_empty/state.json
@@ -0,0 +1,24 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_map.map",
+          "mode": "managed",
+          "name": "map",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "map": {}
+          },
+          "type": "tfcoremock_map",
+          "values": {
+            "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+            "map": {}
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map_null/apply.json b/v1.5.7/testing/equivalence-tests/outputs/basic_map_null/apply.json
new file mode 100644
index 0000000..28e766c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map_null/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Modifying... [id=50E1A46E-E64A-4C1F-881C-BA85A5440964]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Modifications complete after 0s [id=50E1A46E-E64A-4C1F-881C-BA85A5440964]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map_null/plan b/v1.5.7/testing/equivalence-tests/outputs/basic_map_null/plan
new file mode 100644
index 0000000..4fbdf38
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map_null/plan
@@ -0,0 +1,26 @@
+tfcoremock_map.map: Refreshing state... [id=50E1A46E-E64A-4C1F-881C-BA85A5440964]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_map.map will be updated in-place
+  ~ resource "tfcoremock_map" "map" {
+        id  = "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+      - map = {
+          - "one"  = "682672C7-0918-4448-8342-887BAE01062A"
+          - "two"  = "212FFBF6-40FE-4862-B708-E6AA508E84E0"
+          - "zero" = "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+        } -> null
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map_null/plan.json b/v1.5.7/testing/equivalence-tests/outputs/basic_map_null/plan.json
new file mode 100644
index 0000000..33daeee
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map_null/plan.json
@@ -0,0 +1,108 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_map.map",
+          "expressions": {
+            "id": {
+              "constant_value": "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+            }
+          },
+          "mode": "managed",
+          "name": "map",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_map"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_map.map",
+          "mode": "managed",
+          "name": "map",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_map",
+          "values": {
+            "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+            "map": null
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_map.map",
+            "mode": "managed",
+            "name": "map",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "map": {}
+            },
+            "type": "tfcoremock_map",
+            "values": {
+              "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+              "map": {
+                "one": "682672C7-0918-4448-8342-887BAE01062A",
+                "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+                "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+              }
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_map.map",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+          "map": null
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+          "map": {
+            "one": "682672C7-0918-4448-8342-887BAE01062A",
+            "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+            "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+          }
+        },
+        "before_sensitive": {
+          "map": {}
+        }
+      },
+      "mode": "managed",
+      "name": "map",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_map"
+    }
+  ],
+  "timestamp": "2023-05-25T07:34:57Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map_null/state b/v1.5.7/testing/equivalence-tests/outputs/basic_map_null/state
new file mode 100644
index 0000000..99c5a94
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map_null/state
@@ -0,0 +1,4 @@
+# tfcoremock_map.map:
+resource "tfcoremock_map" "map" {
+    id = "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map_null/state.json b/v1.5.7/testing/equivalence-tests/outputs/basic_map_null/state.json
new file mode 100644
index 0000000..440dc72
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map_null/state.json
@@ -0,0 +1,22 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_map.map",
+          "mode": "managed",
+          "name": "map",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_map",
+          "values": {
+            "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+            "map": null
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map_update/apply.json b/v1.5.7/testing/equivalence-tests/outputs/basic_map_update/apply.json
new file mode 100644
index 0000000..28e766c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map_update/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Modifying... [id=50E1A46E-E64A-4C1F-881C-BA85A5440964]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Modifications complete after 0s [id=50E1A46E-E64A-4C1F-881C-BA85A5440964]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map_update/plan b/v1.5.7/testing/equivalence-tests/outputs/basic_map_update/plan
new file mode 100644
index 0000000..122d000
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map_update/plan
@@ -0,0 +1,26 @@
+tfcoremock_map.map: Refreshing state... [id=50E1A46E-E64A-4C1F-881C-BA85A5440964]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_map.map will be updated in-place
+  ~ resource "tfcoremock_map" "map" {
+        id  = "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+      ~ map = {
+          + "four" = "D820D482-7C2C-4EF3-8935-863168A193F9"
+          - "one"  = "682672C7-0918-4448-8342-887BAE01062A" -> null
+            # (2 unchanged elements hidden)
+        }
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map_update/plan.json b/v1.5.7/testing/equivalence-tests/outputs/basic_map_update/plan.json
new file mode 100644
index 0000000..c5f802d
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map_update/plan.json
@@ -0,0 +1,127 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_map.map",
+          "expressions": {
+            "id": {
+              "constant_value": "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+            },
+            "map": {
+              "constant_value": {
+                "four": "D820D482-7C2C-4EF3-8935-863168A193F9",
+                "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+                "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+              }
+            }
+          },
+          "mode": "managed",
+          "name": "map",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_map"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_map.map",
+          "mode": "managed",
+          "name": "map",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "map": {}
+          },
+          "type": "tfcoremock_map",
+          "values": {
+            "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+            "map": {
+              "four": "D820D482-7C2C-4EF3-8935-863168A193F9",
+              "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+              "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+            }
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_map.map",
+            "mode": "managed",
+            "name": "map",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "map": {}
+            },
+            "type": "tfcoremock_map",
+            "values": {
+              "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+              "map": {
+                "one": "682672C7-0918-4448-8342-887BAE01062A",
+                "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+                "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+              }
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_map.map",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+          "map": {
+            "four": "D820D482-7C2C-4EF3-8935-863168A193F9",
+            "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+            "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+          }
+        },
+        "after_sensitive": {
+          "map": {}
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+          "map": {
+            "one": "682672C7-0918-4448-8342-887BAE01062A",
+            "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+            "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+          }
+        },
+        "before_sensitive": {
+          "map": {}
+        }
+      },
+      "mode": "managed",
+      "name": "map",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_map"
+    }
+  ],
+  "timestamp": "2023-05-25T07:34:59Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map_update/state b/v1.5.7/testing/equivalence-tests/outputs/basic_map_update/state
new file mode 100644
index 0000000..e58fcff
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map_update/state
@@ -0,0 +1,9 @@
+# tfcoremock_map.map:
+resource "tfcoremock_map" "map" {
+    id  = "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+    map = {
+        "four" = "D820D482-7C2C-4EF3-8935-863168A193F9"
+        "two"  = "212FFBF6-40FE-4862-B708-E6AA508E84E0"
+        "zero" = "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_map_update/state.json b/v1.5.7/testing/equivalence-tests/outputs/basic_map_update/state.json
new file mode 100644
index 0000000..ee8cdb6
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_map_update/state.json
@@ -0,0 +1,28 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_map.map",
+          "mode": "managed",
+          "name": "map",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "map": {}
+          },
+          "type": "tfcoremock_map",
+          "values": {
+            "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+            "map": {
+              "four": "D820D482-7C2C-4EF3-8935-863168A193F9",
+              "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+              "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+            }
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_multiline_string_update/apply.json b/v1.5.7/testing/equivalence-tests/outputs/basic_multiline_string_update/apply.json
new file mode 100644
index 0000000..94e08ea
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_multiline_string_update/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.multiline: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.multiline",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.multiline",
+        "resource_key": null,
+        "resource_name": "multiline",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.multiline: Modifying... [id=69fe5233-e77a-804f-0dac-115c949540bc]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "69fe5233-e77a-804f-0dac-115c949540bc",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.multiline",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.multiline",
+        "resource_key": null,
+        "resource_name": "multiline",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.multiline: Modifications complete after 0s [id=69fe5233-e77a-804f-0dac-115c949540bc]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "69fe5233-e77a-804f-0dac-115c949540bc",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.multiline",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.multiline",
+        "resource_key": null,
+        "resource_name": "multiline",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_multiline_string_update/plan b/v1.5.7/testing/equivalence-tests/outputs/basic_multiline_string_update/plan
new file mode 100644
index 0000000..665d430
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_multiline_string_update/plan
@@ -0,0 +1,31 @@
+tfcoremock_simple_resource.multiline: Refreshing state... [id=69fe5233-e77a-804f-0dac-115c949540bc]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_simple_resource.multiline will be updated in-place
+  ~ resource "tfcoremock_simple_resource" "multiline" {
+        id     = "69fe5233-e77a-804f-0dac-115c949540bc"
+      ~ string = <<-EOT
+            one
+          - two
+            three
+          + two
+            four
+          - five
+          + six
+          + seven
+        EOT
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_multiline_string_update/plan.json b/v1.5.7/testing/equivalence-tests/outputs/basic_multiline_string_update/plan.json
new file mode 100644
index 0000000..d9ca2b2
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_multiline_string_update/plan.json
@@ -0,0 +1,112 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.multiline",
+          "expressions": {
+            "string": {
+              "constant_value": "one\nthree\ntwo\nfour\nsix\nseven"
+            }
+          },
+          "mode": "managed",
+          "name": "multiline",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_simple_resource"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.multiline",
+          "mode": "managed",
+          "name": "multiline",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "69fe5233-e77a-804f-0dac-115c949540bc",
+            "integer": null,
+            "number": null,
+            "string": "one\nthree\ntwo\nfour\nsix\nseven"
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_simple_resource.multiline",
+            "mode": "managed",
+            "name": "multiline",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {},
+            "type": "tfcoremock_simple_resource",
+            "values": {
+              "bool": null,
+              "float": null,
+              "id": "69fe5233-e77a-804f-0dac-115c949540bc",
+              "integer": null,
+              "number": null,
+              "string": "one\ntwo\nthree\nfour\nfive"
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_simple_resource.multiline",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "id": "69fe5233-e77a-804f-0dac-115c949540bc",
+          "integer": null,
+          "number": null,
+          "string": "one\nthree\ntwo\nfour\nsix\nseven"
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "bool": null,
+          "float": null,
+          "id": "69fe5233-e77a-804f-0dac-115c949540bc",
+          "integer": null,
+          "number": null,
+          "string": "one\ntwo\nthree\nfour\nfive"
+        },
+        "before_sensitive": {}
+      },
+      "mode": "managed",
+      "name": "multiline",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:01Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_multiline_string_update/state b/v1.5.7/testing/equivalence-tests/outputs/basic_multiline_string_update/state
new file mode 100644
index 0000000..18891b1
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_multiline_string_update/state
@@ -0,0 +1,12 @@
+# tfcoremock_simple_resource.multiline:
+resource "tfcoremock_simple_resource" "multiline" {
+    id     = "69fe5233-e77a-804f-0dac-115c949540bc"
+    string = <<-EOT
+        one
+        three
+        two
+        four
+        six
+        seven
+    EOT
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_multiline_string_update/state.json b/v1.5.7/testing/equivalence-tests/outputs/basic_multiline_string_update/state.json
new file mode 100644
index 0000000..1ee0ace
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_multiline_string_update/state.json
@@ -0,0 +1,26 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.multiline",
+          "mode": "managed",
+          "name": "multiline",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "69fe5233-e77a-804f-0dac-115c949540bc",
+            "integer": null,
+            "number": null,
+            "string": "one\nthree\ntwo\nfour\nsix\nseven"
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set/apply.json b/v1.5.7/testing/equivalence-tests/outputs/basic_set/apply.json
new file mode 100644
index 0000000..34765d5
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set/apply.json
@@ -0,0 +1,79 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Plan to create",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Creation complete after 0s [id=046952C9-B832-4106-82C0-C217F7C73E18]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "046952C9-B832-4106-82C0-C217F7C73E18",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set/plan b/v1.5.7/testing/equivalence-tests/outputs/basic_set/plan
new file mode 100644
index 0000000..f6629e4
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set/plan
@@ -0,0 +1,25 @@
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  # tfcoremock_set.set will be created
+  + resource "tfcoremock_set" "set" {
+      + id  = "046952C9-B832-4106-82C0-C217F7C73E18"
+      + set = [
+          + "41471135-E14C-4946-BFA4-2626C7E2A94A",
+          + "C04762B9-D07B-40FE-A92B-B72AD342658D",
+          + "D8F7EA80-9E25-4DD7-8D97-797D2080952B",
+        ]
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set/plan.json b/v1.5.7/testing/equivalence-tests/outputs/basic_set/plan.json
new file mode 100644
index 0000000..65b5df3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set/plan.json
@@ -0,0 +1,98 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_set.set",
+          "expressions": {
+            "id": {
+              "constant_value": "046952C9-B832-4106-82C0-C217F7C73E18"
+            },
+            "set": {
+              "constant_value": [
+                "41471135-E14C-4946-BFA4-2626C7E2A94A",
+                "C04762B9-D07B-40FE-A92B-B72AD342658D",
+                "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+              ]
+            }
+          },
+          "mode": "managed",
+          "name": "set",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_set"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_set.set",
+          "mode": "managed",
+          "name": "set",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "set": [
+              false,
+              false,
+              false
+            ]
+          },
+          "type": "tfcoremock_set",
+          "values": {
+            "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+            "set": [
+              "41471135-E14C-4946-BFA4-2626C7E2A94A",
+              "C04762B9-D07B-40FE-A92B-B72AD342658D",
+              "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_set.set",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "after": {
+          "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+          "set": [
+            "41471135-E14C-4946-BFA4-2626C7E2A94A",
+            "C04762B9-D07B-40FE-A92B-B72AD342658D",
+            "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+          ]
+        },
+        "after_sensitive": {
+          "set": [
+            false,
+            false,
+            false
+          ]
+        },
+        "after_unknown": {},
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "managed",
+      "name": "set",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_set"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:03Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set/state b/v1.5.7/testing/equivalence-tests/outputs/basic_set/state
new file mode 100644
index 0000000..7e2b277
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set/state
@@ -0,0 +1,9 @@
+# tfcoremock_set.set:
+resource "tfcoremock_set" "set" {
+    id  = "046952C9-B832-4106-82C0-C217F7C73E18"
+    set = [
+        "41471135-E14C-4946-BFA4-2626C7E2A94A",
+        "C04762B9-D07B-40FE-A92B-B72AD342658D",
+        "D8F7EA80-9E25-4DD7-8D97-797D2080952B",
+    ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set/state.json b/v1.5.7/testing/equivalence-tests/outputs/basic_set/state.json
new file mode 100644
index 0000000..b869f57
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set/state.json
@@ -0,0 +1,32 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_set.set",
+          "mode": "managed",
+          "name": "set",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "set": [
+              false,
+              false,
+              false
+            ]
+          },
+          "type": "tfcoremock_set",
+          "values": {
+            "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+            "set": [
+              "41471135-E14C-4946-BFA4-2626C7E2A94A",
+              "C04762B9-D07B-40FE-A92B-B72AD342658D",
+              "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set_empty/apply.json b/v1.5.7/testing/equivalence-tests/outputs/basic_set_empty/apply.json
new file mode 100644
index 0000000..b76d69c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set_empty/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Modifying... [id=046952C9-B832-4106-82C0-C217F7C73E18]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "046952C9-B832-4106-82C0-C217F7C73E18",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Modifications complete after 0s [id=046952C9-B832-4106-82C0-C217F7C73E18]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "046952C9-B832-4106-82C0-C217F7C73E18",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set_empty/plan b/v1.5.7/testing/equivalence-tests/outputs/basic_set_empty/plan
new file mode 100644
index 0000000..9953cff
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set_empty/plan
@@ -0,0 +1,26 @@
+tfcoremock_set.set: Refreshing state... [id=046952C9-B832-4106-82C0-C217F7C73E18]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_set.set will be updated in-place
+  ~ resource "tfcoremock_set" "set" {
+        id  = "046952C9-B832-4106-82C0-C217F7C73E18"
+      ~ set = [
+          - "41471135-E14C-4946-BFA4-2626C7E2A94A",
+          - "C04762B9-D07B-40FE-A92B-B72AD342658D",
+          - "D8F7EA80-9E25-4DD7-8D97-797D2080952B",
+        ]
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set_empty/plan.json b/v1.5.7/testing/equivalence-tests/outputs/basic_set_empty/plan.json
new file mode 100644
index 0000000..1677b69
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set_empty/plan.json
@@ -0,0 +1,123 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_set.set",
+          "expressions": {
+            "id": {
+              "constant_value": "046952C9-B832-4106-82C0-C217F7C73E18"
+            },
+            "set": {
+              "constant_value": []
+            }
+          },
+          "mode": "managed",
+          "name": "set",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_set"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_set.set",
+          "mode": "managed",
+          "name": "set",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "set": []
+          },
+          "type": "tfcoremock_set",
+          "values": {
+            "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+            "set": []
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_set.set",
+            "mode": "managed",
+            "name": "set",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "set": [
+                false,
+                false,
+                false
+              ]
+            },
+            "type": "tfcoremock_set",
+            "values": {
+              "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+              "set": [
+                "41471135-E14C-4946-BFA4-2626C7E2A94A",
+                "C04762B9-D07B-40FE-A92B-B72AD342658D",
+                "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+              ]
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_set.set",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+          "set": []
+        },
+        "after_sensitive": {
+          "set": []
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+          "set": [
+            "41471135-E14C-4946-BFA4-2626C7E2A94A",
+            "C04762B9-D07B-40FE-A92B-B72AD342658D",
+            "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+          ]
+        },
+        "before_sensitive": {
+          "set": [
+            false,
+            false,
+            false
+          ]
+        }
+      },
+      "mode": "managed",
+      "name": "set",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_set"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:04Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set_empty/state b/v1.5.7/testing/equivalence-tests/outputs/basic_set_empty/state
new file mode 100644
index 0000000..dc1835e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set_empty/state
@@ -0,0 +1,5 @@
+# tfcoremock_set.set:
+resource "tfcoremock_set" "set" {
+    id  = "046952C9-B832-4106-82C0-C217F7C73E18"
+    set = []
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set_empty/state.json b/v1.5.7/testing/equivalence-tests/outputs/basic_set_empty/state.json
new file mode 100644
index 0000000..3ad076e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set_empty/state.json
@@ -0,0 +1,24 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_set.set",
+          "mode": "managed",
+          "name": "set",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "set": []
+          },
+          "type": "tfcoremock_set",
+          "values": {
+            "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+            "set": []
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set_null/apply.json b/v1.5.7/testing/equivalence-tests/outputs/basic_set_null/apply.json
new file mode 100644
index 0000000..b76d69c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set_null/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Modifying... [id=046952C9-B832-4106-82C0-C217F7C73E18]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "046952C9-B832-4106-82C0-C217F7C73E18",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Modifications complete after 0s [id=046952C9-B832-4106-82C0-C217F7C73E18]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "046952C9-B832-4106-82C0-C217F7C73E18",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set_null/plan b/v1.5.7/testing/equivalence-tests/outputs/basic_set_null/plan
new file mode 100644
index 0000000..37c9921
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set_null/plan
@@ -0,0 +1,26 @@
+tfcoremock_set.set: Refreshing state... [id=046952C9-B832-4106-82C0-C217F7C73E18]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_set.set will be updated in-place
+  ~ resource "tfcoremock_set" "set" {
+        id  = "046952C9-B832-4106-82C0-C217F7C73E18"
+      - set = [
+          - "41471135-E14C-4946-BFA4-2626C7E2A94A",
+          - "C04762B9-D07B-40FE-A92B-B72AD342658D",
+          - "D8F7EA80-9E25-4DD7-8D97-797D2080952B",
+        ] -> null
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set_null/plan.json b/v1.5.7/testing/equivalence-tests/outputs/basic_set_null/plan.json
new file mode 100644
index 0000000..68cef7a
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set_null/plan.json
@@ -0,0 +1,116 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_set.set",
+          "expressions": {
+            "id": {
+              "constant_value": "046952C9-B832-4106-82C0-C217F7C73E18"
+            }
+          },
+          "mode": "managed",
+          "name": "set",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_set"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_set.set",
+          "mode": "managed",
+          "name": "set",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_set",
+          "values": {
+            "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+            "set": null
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_set.set",
+            "mode": "managed",
+            "name": "set",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "set": [
+                false,
+                false,
+                false
+              ]
+            },
+            "type": "tfcoremock_set",
+            "values": {
+              "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+              "set": [
+                "41471135-E14C-4946-BFA4-2626C7E2A94A",
+                "C04762B9-D07B-40FE-A92B-B72AD342658D",
+                "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+              ]
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_set.set",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+          "set": null
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+          "set": [
+            "41471135-E14C-4946-BFA4-2626C7E2A94A",
+            "C04762B9-D07B-40FE-A92B-B72AD342658D",
+            "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+          ]
+        },
+        "before_sensitive": {
+          "set": [
+            false,
+            false,
+            false
+          ]
+        }
+      },
+      "mode": "managed",
+      "name": "set",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_set"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:06Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set_null/state b/v1.5.7/testing/equivalence-tests/outputs/basic_set_null/state
new file mode 100644
index 0000000..192cb70
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set_null/state
@@ -0,0 +1,4 @@
+# tfcoremock_set.set:
+resource "tfcoremock_set" "set" {
+    id = "046952C9-B832-4106-82C0-C217F7C73E18"
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set_null/state.json b/v1.5.7/testing/equivalence-tests/outputs/basic_set_null/state.json
new file mode 100644
index 0000000..299974c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set_null/state.json
@@ -0,0 +1,22 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_set.set",
+          "mode": "managed",
+          "name": "set",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_set",
+          "values": {
+            "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+            "set": null
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set_update/apply.json b/v1.5.7/testing/equivalence-tests/outputs/basic_set_update/apply.json
new file mode 100644
index 0000000..b76d69c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set_update/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Modifying... [id=046952C9-B832-4106-82C0-C217F7C73E18]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "046952C9-B832-4106-82C0-C217F7C73E18",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Modifications complete after 0s [id=046952C9-B832-4106-82C0-C217F7C73E18]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "046952C9-B832-4106-82C0-C217F7C73E18",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set_update/plan b/v1.5.7/testing/equivalence-tests/outputs/basic_set_update/plan
new file mode 100644
index 0000000..ad8fbb7
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set_update/plan
@@ -0,0 +1,26 @@
+tfcoremock_set.set: Refreshing state... [id=046952C9-B832-4106-82C0-C217F7C73E18]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_set.set will be updated in-place
+  ~ resource "tfcoremock_set" "set" {
+        id  = "046952C9-B832-4106-82C0-C217F7C73E18"
+      ~ set = [
+          - "C04762B9-D07B-40FE-A92B-B72AD342658D",
+          + "1769B76E-12F0-4214-A864-E843EB23B64E",
+            # (2 unchanged elements hidden)
+        ]
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set_update/plan.json b/v1.5.7/testing/equivalence-tests/outputs/basic_set_update/plan.json
new file mode 100644
index 0000000..dd91262
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set_update/plan.json
@@ -0,0 +1,143 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_set.set",
+          "expressions": {
+            "id": {
+              "constant_value": "046952C9-B832-4106-82C0-C217F7C73E18"
+            },
+            "set": {
+              "constant_value": [
+                "41471135-E14C-4946-BFA4-2626C7E2A94A",
+                "D8F7EA80-9E25-4DD7-8D97-797D2080952B",
+                "1769B76E-12F0-4214-A864-E843EB23B64E"
+              ]
+            }
+          },
+          "mode": "managed",
+          "name": "set",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_set"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_set.set",
+          "mode": "managed",
+          "name": "set",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "set": [
+              false,
+              false,
+              false
+            ]
+          },
+          "type": "tfcoremock_set",
+          "values": {
+            "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+            "set": [
+              "1769B76E-12F0-4214-A864-E843EB23B64E",
+              "41471135-E14C-4946-BFA4-2626C7E2A94A",
+              "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_set.set",
+            "mode": "managed",
+            "name": "set",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "set": [
+                false,
+                false,
+                false
+              ]
+            },
+            "type": "tfcoremock_set",
+            "values": {
+              "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+              "set": [
+                "41471135-E14C-4946-BFA4-2626C7E2A94A",
+                "C04762B9-D07B-40FE-A92B-B72AD342658D",
+                "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+              ]
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_set.set",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+          "set": [
+            "1769B76E-12F0-4214-A864-E843EB23B64E",
+            "41471135-E14C-4946-BFA4-2626C7E2A94A",
+            "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+          ]
+        },
+        "after_sensitive": {
+          "set": [
+            false,
+            false,
+            false
+          ]
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+          "set": [
+            "41471135-E14C-4946-BFA4-2626C7E2A94A",
+            "C04762B9-D07B-40FE-A92B-B72AD342658D",
+            "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+          ]
+        },
+        "before_sensitive": {
+          "set": [
+            false,
+            false,
+            false
+          ]
+        }
+      },
+      "mode": "managed",
+      "name": "set",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_set"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:08Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set_update/state b/v1.5.7/testing/equivalence-tests/outputs/basic_set_update/state
new file mode 100644
index 0000000..a1afc79
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set_update/state
@@ -0,0 +1,9 @@
+# tfcoremock_set.set:
+resource "tfcoremock_set" "set" {
+    id  = "046952C9-B832-4106-82C0-C217F7C73E18"
+    set = [
+        "1769B76E-12F0-4214-A864-E843EB23B64E",
+        "41471135-E14C-4946-BFA4-2626C7E2A94A",
+        "D8F7EA80-9E25-4DD7-8D97-797D2080952B",
+    ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/basic_set_update/state.json b/v1.5.7/testing/equivalence-tests/outputs/basic_set_update/state.json
new file mode 100644
index 0000000..ba74173
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/basic_set_update/state.json
@@ -0,0 +1,32 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_set.set",
+          "mode": "managed",
+          "name": "set",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "set": [
+              false,
+              false,
+              false
+            ]
+          },
+          "type": "tfcoremock_set",
+          "values": {
+            "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+            "set": [
+              "1769B76E-12F0-4214-A864-E843EB23B64E",
+              "41471135-E14C-4946-BFA4-2626C7E2A94A",
+              "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/data_read/plan b/v1.5.7/testing/equivalence-tests/outputs/data_read/plan
new file mode 100644
index 0000000..5d01597
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/data_read/plan
@@ -0,0 +1,45 @@
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+ <= read (data resources)
+
+Terraform will perform the following actions:
+
+  # data.tfcoremock_simple_resource.read will be read during apply
+  # (config refers to values not yet known)
+ <= data "tfcoremock_simple_resource" "read" {
+      + id = (known after apply)
+    }
+
+  # tfcoremock_simple_resource.create will be created
+  + resource "tfcoremock_simple_resource" "create" {
+      + id = (known after apply)
+    }
+
+  # module.create.local_file.data_file will be created
+  + resource "local_file" "data_file" {
+      + content              = (known after apply)
+      + directory_permission = "0777"
+      + file_permission      = "0777"
+      + filename             = (known after apply)
+      + id                   = (known after apply)
+    }
+
+  # module.create.random_integer.random will be created
+  + resource "random_integer" "random" {
+      + id     = (known after apply)
+      + max    = 9999999
+      + min    = 1000000
+      + result = (known after apply)
+      + seed   = "F78CB410-BA01-44E1-82E1-37D61F7CB158"
+    }
+
+Plan: 3 to add, 0 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/data_read/plan.json b/v1.5.7/testing/equivalence-tests/outputs/data_read/plan.json
new file mode 100644
index 0000000..4286c7f
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/data_read/plan.json
@@ -0,0 +1,328 @@
+{
+  "configuration": {
+    "provider_config": {
+      "local": {
+        "full_name": "registry.terraform.io/hashicorp/local",
+        "name": "local",
+        "version_constraint": "2.2.3"
+      },
+      "random": {
+        "full_name": "registry.terraform.io/hashicorp/random",
+        "name": "random",
+        "version_constraint": "3.4.3"
+      },
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "module_calls": {
+        "create": {
+          "expressions": {
+            "contents": {
+              "constant_value": "hello, world!"
+            }
+          },
+          "module": {
+            "outputs": {
+              "id": {
+                "expression": {
+                  "references": [
+                    "random_integer.random.id",
+                    "random_integer.random"
+                  ]
+                }
+              }
+            },
+            "resources": [
+              {
+                "address": "local_file.data_file",
+                "expressions": {
+                  "content": {
+                    "references": [
+                      "local.contents"
+                    ]
+                  },
+                  "filename": {
+                    "references": [
+                      "random_integer.random.id",
+                      "random_integer.random"
+                    ]
+                  }
+                },
+                "mode": "managed",
+                "name": "data_file",
+                "provider_config_key": "local",
+                "schema_version": 0,
+                "type": "local_file"
+              },
+              {
+                "address": "random_integer.random",
+                "expressions": {
+                  "max": {
+                    "constant_value": 9999999
+                  },
+                  "min": {
+                    "constant_value": 1000000
+                  },
+                  "seed": {
+                    "constant_value": "F78CB410-BA01-44E1-82E1-37D61F7CB158"
+                  }
+                },
+                "mode": "managed",
+                "name": "random",
+                "provider_config_key": "random",
+                "schema_version": 0,
+                "type": "random_integer"
+              }
+            ],
+            "variables": {
+              "contents": {}
+            }
+          },
+          "source": "./create"
+        }
+      },
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.create",
+          "expressions": {
+            "string": {
+              "references": [
+                "data.tfcoremock_simple_resource.read.string",
+                "data.tfcoremock_simple_resource.read"
+              ]
+            }
+          },
+          "mode": "managed",
+          "name": "create",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_simple_resource"
+        },
+        {
+          "address": "data.tfcoremock_simple_resource.read",
+          "depends_on": [
+            "module.create"
+          ],
+          "expressions": {
+            "id": {
+              "references": [
+                "module.create.id",
+                "module.create"
+              ]
+            }
+          },
+          "mode": "data",
+          "name": "read",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_simple_resource"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "child_modules": [
+        {
+          "address": "module.create",
+          "resources": [
+            {
+              "address": "module.create.local_file.data_file",
+              "mode": "managed",
+              "name": "data_file",
+              "provider_name": "registry.terraform.io/hashicorp/local",
+              "schema_version": 0,
+              "sensitive_values": {},
+              "type": "local_file",
+              "values": {
+                "content_base64": null,
+                "directory_permission": "0777",
+                "file_permission": "0777",
+                "sensitive_content": null,
+                "source": null
+              }
+            },
+            {
+              "address": "module.create.random_integer.random",
+              "mode": "managed",
+              "name": "random",
+              "provider_name": "registry.terraform.io/hashicorp/random",
+              "schema_version": 0,
+              "sensitive_values": {},
+              "type": "random_integer",
+              "values": {
+                "keepers": null,
+                "max": 9999999,
+                "min": 1000000,
+                "seed": "F78CB410-BA01-44E1-82E1-37D61F7CB158"
+              }
+            }
+          ]
+        }
+      ],
+      "resources": [
+        {
+          "address": "data.tfcoremock_simple_resource.read",
+          "mode": "data",
+          "name": "read",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "integer": null,
+            "number": null,
+            "string": null
+          }
+        },
+        {
+          "address": "tfcoremock_simple_resource.create",
+          "mode": "managed",
+          "name": "create",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "integer": null,
+            "number": null,
+            "string": null
+          }
+        }
+      ]
+    }
+  },
+  "relevant_attributes": [
+    {
+      "attribute": [
+        "string"
+      ],
+      "resource": "data.tfcoremock_simple_resource.read"
+    },
+    {
+      "attribute": [
+        "id"
+      ],
+      "resource": "module.create.random_integer.random"
+    }
+  ],
+  "resource_changes": [
+    {
+      "action_reason": "read_because_config_unknown",
+      "address": "data.tfcoremock_simple_resource.read",
+      "change": {
+        "actions": [
+          "read"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "integer": null,
+          "number": null,
+          "string": null
+        },
+        "after_sensitive": {},
+        "after_unknown": {
+          "id": true
+        },
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "data",
+      "name": "read",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    },
+    {
+      "address": "tfcoremock_simple_resource.create",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "integer": null,
+          "number": null,
+          "string": null
+        },
+        "after_sensitive": {},
+        "after_unknown": {
+          "id": true
+        },
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "managed",
+      "name": "create",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    },
+    {
+      "address": "module.create.local_file.data_file",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "after": {
+          "content_base64": null,
+          "directory_permission": "0777",
+          "file_permission": "0777",
+          "sensitive_content": null,
+          "source": null
+        },
+        "after_sensitive": {
+          "sensitive_content": true
+        },
+        "after_unknown": {
+          "content": true,
+          "filename": true,
+          "id": true
+        },
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "managed",
+      "module_address": "module.create",
+      "name": "data_file",
+      "provider_name": "registry.terraform.io/hashicorp/local",
+      "type": "local_file"
+    },
+    {
+      "address": "module.create.random_integer.random",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "after": {
+          "keepers": null,
+          "max": 9999999,
+          "min": 1000000,
+          "seed": "F78CB410-BA01-44E1-82E1-37D61F7CB158"
+        },
+        "after_sensitive": {},
+        "after_unknown": {
+          "id": true,
+          "result": true
+        },
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "managed",
+      "module_address": "module.create",
+      "name": "random",
+      "provider_name": "registry.terraform.io/hashicorp/random",
+      "type": "random_integer"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:11Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/drift_refresh_only/apply.json b/v1.5.7/testing/equivalence-tests/outputs/drift_refresh_only/apply.json
new file mode 100644
index 0000000..42438bd
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/drift_refresh_only/apply.json
@@ -0,0 +1,22 @@
+[
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/drift_refresh_only/plan b/v1.5.7/testing/equivalence-tests/outputs/drift_refresh_only/plan
new file mode 100644
index 0000000..b031170
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/drift_refresh_only/plan
@@ -0,0 +1,25 @@
+tfcoremock_simple_resource.drift: Refreshing state... [id=cb79269e-dc39-1e68-0a9c-63cb392afda9]
+
+Note: Objects have changed outside of Terraform
+
+Terraform detected the following changes made outside of Terraform since the
+last "terraform apply" which may have affected this plan:
+
+  # tfcoremock_simple_resource.drift has changed
+  ~ resource "tfcoremock_simple_resource" "drift" {
+        id     = "cb79269e-dc39-1e68-0a9c-63cb392afda9"
+      ~ string = "Hello, world!" -> "Hello, drift!"
+    }
+
+
+This is a refresh-only plan, so Terraform will not take any actions to undo
+these. If you were expecting these changes then you can apply this plan to
+record the updated values in the Terraform state without changing any remote
+objects.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/drift_refresh_only/plan.json b/v1.5.7/testing/equivalence-tests/outputs/drift_refresh_only/plan.json
new file mode 100644
index 0000000..bab6159
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/drift_refresh_only/plan.json
@@ -0,0 +1,92 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.drift",
+          "expressions": {
+            "string": {
+              "constant_value": "Hello, world!"
+            }
+          },
+          "mode": "managed",
+          "name": "drift",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_simple_resource"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {}
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_simple_resource.drift",
+            "mode": "managed",
+            "name": "drift",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {},
+            "type": "tfcoremock_simple_resource",
+            "values": {
+              "bool": null,
+              "float": null,
+              "id": "cb79269e-dc39-1e68-0a9c-63cb392afda9",
+              "integer": null,
+              "number": null,
+              "string": "Hello, drift!"
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_drift": [
+    {
+      "address": "tfcoremock_simple_resource.drift",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "id": "cb79269e-dc39-1e68-0a9c-63cb392afda9",
+          "integer": null,
+          "number": null,
+          "string": "Hello, drift!"
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "bool": null,
+          "float": null,
+          "id": "cb79269e-dc39-1e68-0a9c-63cb392afda9",
+          "integer": null,
+          "number": null,
+          "string": "Hello, world!"
+        },
+        "before_sensitive": {}
+      },
+      "mode": "managed",
+      "name": "drift",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:13Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/drift_refresh_only/state.json b/v1.5.7/testing/equivalence-tests/outputs/drift_refresh_only/state.json
new file mode 100644
index 0000000..d91cc99
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/drift_refresh_only/state.json
@@ -0,0 +1,26 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.drift",
+          "mode": "managed",
+          "name": "drift",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "cb79269e-dc39-1e68-0a9c-63cb392afda9",
+            "integer": null,
+            "number": null,
+            "string": "Hello, drift!"
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/drift_relevant_attributes/apply.json b/v1.5.7/testing/equivalence-tests/outputs/drift_relevant_attributes/apply.json
new file mode 100644
index 0000000..5fafc91
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/drift_relevant_attributes/apply.json
@@ -0,0 +1,140 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.base: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.base",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.base",
+        "resource_key": null,
+        "resource_name": "base",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.dependent: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.dependent",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.dependent",
+        "resource_key": null,
+        "resource_name": "dependent",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.base: Modifying... [id=f6f74ca6-e8ef-e51f-522c-433b9ed5038f]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "f6f74ca6-e8ef-e51f-522c-433b9ed5038f",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.base",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.base",
+        "resource_key": null,
+        "resource_name": "base",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.base: Modifications complete after 0s [id=f6f74ca6-e8ef-e51f-522c-433b9ed5038f]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "f6f74ca6-e8ef-e51f-522c-433b9ed5038f",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.base",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.base",
+        "resource_key": null,
+        "resource_name": "base",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.dependent: Modifying... [id=1b17b502-96c9-fcc3-3b09-2af1c3de6ad8]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "1b17b502-96c9-fcc3-3b09-2af1c3de6ad8",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.dependent",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.dependent",
+        "resource_key": null,
+        "resource_name": "dependent",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.dependent: Modifications complete after 0s [id=1b17b502-96c9-fcc3-3b09-2af1c3de6ad8]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "1b17b502-96c9-fcc3-3b09-2af1c3de6ad8",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.dependent",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.dependent",
+        "resource_key": null,
+        "resource_name": "dependent",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 2 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 2,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/drift_relevant_attributes/plan b/v1.5.7/testing/equivalence-tests/outputs/drift_relevant_attributes/plan
new file mode 100644
index 0000000..7e4738a
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/drift_relevant_attributes/plan
@@ -0,0 +1,49 @@
+tfcoremock_simple_resource.base: Refreshing state... [id=f6f74ca6-e8ef-e51f-522c-433b9ed5038f]
+tfcoremock_simple_resource.dependent: Refreshing state... [id=1b17b502-96c9-fcc3-3b09-2af1c3de6ad8]
+
+Note: Objects have changed outside of Terraform
+
+Terraform detected the following changes made outside of Terraform since the
+last "terraform apply" which may have affected this plan:
+
+  # tfcoremock_simple_resource.base has changed
+  ~ resource "tfcoremock_simple_resource" "base" {
+        id     = "f6f74ca6-e8ef-e51f-522c-433b9ed5038f"
+      ~ string = "Hello, world!" -> "Hello, drift!"
+        # (1 unchanged attribute hidden)
+    }
+
+
+Unless you have made equivalent changes to your configuration, or ignored the
+relevant attributes using ignore_changes, the following plan may include
+actions to undo or respond to these changes.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_simple_resource.base will be updated in-place
+  ~ resource "tfcoremock_simple_resource" "base" {
+        id     = "f6f74ca6-e8ef-e51f-522c-433b9ed5038f"
+      ~ number = 1 -> 0
+      ~ string = "Hello, drift!" -> "Hello, change!"
+    }
+
+  # tfcoremock_simple_resource.dependent will be updated in-place
+  ~ resource "tfcoremock_simple_resource" "dependent" {
+        id     = "1b17b502-96c9-fcc3-3b09-2af1c3de6ad8"
+      ~ string = "Hello, world!" -> "Hello, change!"
+    }
+
+Plan: 0 to add, 2 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/drift_relevant_attributes/plan.json b/v1.5.7/testing/equivalence-tests/outputs/drift_relevant_attributes/plan.json
new file mode 100644
index 0000000..c44f5db
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/drift_relevant_attributes/plan.json
@@ -0,0 +1,240 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.base",
+          "expressions": {
+            "number": {
+              "constant_value": 0
+            },
+            "string": {
+              "constant_value": "Hello, change!"
+            }
+          },
+          "mode": "managed",
+          "name": "base",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_simple_resource"
+        },
+        {
+          "address": "tfcoremock_simple_resource.dependent",
+          "expressions": {
+            "string": {
+              "references": [
+                "tfcoremock_simple_resource.base.string",
+                "tfcoremock_simple_resource.base"
+              ]
+            }
+          },
+          "mode": "managed",
+          "name": "dependent",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_simple_resource"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.base",
+          "mode": "managed",
+          "name": "base",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "f6f74ca6-e8ef-e51f-522c-433b9ed5038f",
+            "integer": null,
+            "number": 0,
+            "string": "Hello, change!"
+          }
+        },
+        {
+          "address": "tfcoremock_simple_resource.dependent",
+          "mode": "managed",
+          "name": "dependent",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "1b17b502-96c9-fcc3-3b09-2af1c3de6ad8",
+            "integer": null,
+            "number": null,
+            "string": "Hello, change!"
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_simple_resource.base",
+            "mode": "managed",
+            "name": "base",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {},
+            "type": "tfcoremock_simple_resource",
+            "values": {
+              "bool": null,
+              "float": null,
+              "id": "f6f74ca6-e8ef-e51f-522c-433b9ed5038f",
+              "integer": null,
+              "number": 1,
+              "string": "Hello, drift!"
+            }
+          },
+          {
+            "address": "tfcoremock_simple_resource.dependent",
+            "depends_on": [
+              "tfcoremock_simple_resource.base"
+            ],
+            "mode": "managed",
+            "name": "dependent",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {},
+            "type": "tfcoremock_simple_resource",
+            "values": {
+              "bool": null,
+              "float": null,
+              "id": "1b17b502-96c9-fcc3-3b09-2af1c3de6ad8",
+              "integer": null,
+              "number": null,
+              "string": "Hello, world!"
+            }
+          }
+        ]
+      }
+    }
+  },
+  "relevant_attributes": [
+    {
+      "attribute": [
+        "string"
+      ],
+      "resource": "tfcoremock_simple_resource.base"
+    }
+  ],
+  "resource_changes": [
+    {
+      "address": "tfcoremock_simple_resource.base",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "id": "f6f74ca6-e8ef-e51f-522c-433b9ed5038f",
+          "integer": null,
+          "number": 0,
+          "string": "Hello, change!"
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "bool": null,
+          "float": null,
+          "id": "f6f74ca6-e8ef-e51f-522c-433b9ed5038f",
+          "integer": null,
+          "number": 1,
+          "string": "Hello, drift!"
+        },
+        "before_sensitive": {}
+      },
+      "mode": "managed",
+      "name": "base",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    },
+    {
+      "address": "tfcoremock_simple_resource.dependent",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "id": "1b17b502-96c9-fcc3-3b09-2af1c3de6ad8",
+          "integer": null,
+          "number": null,
+          "string": "Hello, change!"
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "bool": null,
+          "float": null,
+          "id": "1b17b502-96c9-fcc3-3b09-2af1c3de6ad8",
+          "integer": null,
+          "number": null,
+          "string": "Hello, world!"
+        },
+        "before_sensitive": {}
+      },
+      "mode": "managed",
+      "name": "dependent",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    }
+  ],
+  "resource_drift": [
+    {
+      "address": "tfcoremock_simple_resource.base",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "id": "f6f74ca6-e8ef-e51f-522c-433b9ed5038f",
+          "integer": null,
+          "number": 1,
+          "string": "Hello, drift!"
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "bool": null,
+          "float": null,
+          "id": "f6f74ca6-e8ef-e51f-522c-433b9ed5038f",
+          "integer": null,
+          "number": 0,
+          "string": "Hello, world!"
+        },
+        "before_sensitive": {}
+      },
+      "mode": "managed",
+      "name": "base",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:15Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/drift_relevant_attributes/state b/v1.5.7/testing/equivalence-tests/outputs/drift_relevant_attributes/state
new file mode 100644
index 0000000..dce6788
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/drift_relevant_attributes/state
@@ -0,0 +1,12 @@
+# tfcoremock_simple_resource.base:
+resource "tfcoremock_simple_resource" "base" {
+    id     = "f6f74ca6-e8ef-e51f-522c-433b9ed5038f"
+    number = 0
+    string = "Hello, change!"
+}
+
+# tfcoremock_simple_resource.dependent:
+resource "tfcoremock_simple_resource" "dependent" {
+    id     = "1b17b502-96c9-fcc3-3b09-2af1c3de6ad8"
+    string = "Hello, change!"
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/drift_relevant_attributes/state.json b/v1.5.7/testing/equivalence-tests/outputs/drift_relevant_attributes/state.json
new file mode 100644
index 0000000..1d9f6ad
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/drift_relevant_attributes/state.json
@@ -0,0 +1,46 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.base",
+          "mode": "managed",
+          "name": "base",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "f6f74ca6-e8ef-e51f-522c-433b9ed5038f",
+            "integer": null,
+            "number": 0,
+            "string": "Hello, change!"
+          }
+        },
+        {
+          "address": "tfcoremock_simple_resource.dependent",
+          "depends_on": [
+            "tfcoremock_simple_resource.base"
+          ],
+          "mode": "managed",
+          "name": "dependent",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "1b17b502-96c9-fcc3-3b09-2af1c3de6ad8",
+            "integer": null,
+            "number": null,
+            "string": "Hello, change!"
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/drift_simple/apply.json b/v1.5.7/testing/equivalence-tests/outputs/drift_simple/apply.json
new file mode 100644
index 0000000..6bcf899
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/drift_simple/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.drift: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.drift",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.drift",
+        "resource_key": null,
+        "resource_name": "drift",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.drift: Modifying... [id=f3c6ddc5-37d5-0170-64ff-518ad421385a]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "f3c6ddc5-37d5-0170-64ff-518ad421385a",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.drift",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.drift",
+        "resource_key": null,
+        "resource_name": "drift",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.drift: Modifications complete after 0s [id=f3c6ddc5-37d5-0170-64ff-518ad421385a]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "f3c6ddc5-37d5-0170-64ff-518ad421385a",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.drift",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.drift",
+        "resource_key": null,
+        "resource_name": "drift",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/drift_simple/plan b/v1.5.7/testing/equivalence-tests/outputs/drift_simple/plan
new file mode 100644
index 0000000..266a142
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/drift_simple/plan
@@ -0,0 +1,22 @@
+tfcoremock_simple_resource.drift: Refreshing state... [id=f3c6ddc5-37d5-0170-64ff-518ad421385a]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_simple_resource.drift will be updated in-place
+  ~ resource "tfcoremock_simple_resource" "drift" {
+        id     = "f3c6ddc5-37d5-0170-64ff-518ad421385a"
+      ~ string = "Hello, drift!" -> "Hello, world!"
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/drift_simple/plan.json b/v1.5.7/testing/equivalence-tests/outputs/drift_simple/plan.json
new file mode 100644
index 0000000..393381c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/drift_simple/plan.json
@@ -0,0 +1,145 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.drift",
+          "expressions": {
+            "string": {
+              "constant_value": "Hello, world!"
+            }
+          },
+          "mode": "managed",
+          "name": "drift",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_simple_resource"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.drift",
+          "mode": "managed",
+          "name": "drift",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "f3c6ddc5-37d5-0170-64ff-518ad421385a",
+            "integer": null,
+            "number": null,
+            "string": "Hello, world!"
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_simple_resource.drift",
+            "mode": "managed",
+            "name": "drift",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {},
+            "type": "tfcoremock_simple_resource",
+            "values": {
+              "bool": null,
+              "float": null,
+              "id": "f3c6ddc5-37d5-0170-64ff-518ad421385a",
+              "integer": null,
+              "number": null,
+              "string": "Hello, drift!"
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_simple_resource.drift",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "id": "f3c6ddc5-37d5-0170-64ff-518ad421385a",
+          "integer": null,
+          "number": null,
+          "string": "Hello, world!"
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "bool": null,
+          "float": null,
+          "id": "f3c6ddc5-37d5-0170-64ff-518ad421385a",
+          "integer": null,
+          "number": null,
+          "string": "Hello, drift!"
+        },
+        "before_sensitive": {}
+      },
+      "mode": "managed",
+      "name": "drift",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    }
+  ],
+  "resource_drift": [
+    {
+      "address": "tfcoremock_simple_resource.drift",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "id": "f3c6ddc5-37d5-0170-64ff-518ad421385a",
+          "integer": null,
+          "number": null,
+          "string": "Hello, drift!"
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "bool": null,
+          "float": null,
+          "id": "f3c6ddc5-37d5-0170-64ff-518ad421385a",
+          "integer": null,
+          "number": null,
+          "string": "Hello, world!"
+        },
+        "before_sensitive": {}
+      },
+      "mode": "managed",
+      "name": "drift",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:17Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/drift_simple/state b/v1.5.7/testing/equivalence-tests/outputs/drift_simple/state
new file mode 100644
index 0000000..8715e62
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/drift_simple/state
@@ -0,0 +1,5 @@
+# tfcoremock_simple_resource.drift:
+resource "tfcoremock_simple_resource" "drift" {
+    id     = "f3c6ddc5-37d5-0170-64ff-518ad421385a"
+    string = "Hello, world!"
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/drift_simple/state.json b/v1.5.7/testing/equivalence-tests/outputs/drift_simple/state.json
new file mode 100644
index 0000000..8029de0
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/drift_simple/state.json
@@ -0,0 +1,26 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.drift",
+          "mode": "managed",
+          "name": "drift",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "f3c6ddc5-37d5-0170-64ff-518ad421385a",
+            "integer": null,
+            "number": null,
+            "string": "Hello, world!"
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex/apply.json b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex/apply.json
new file mode 100644
index 0000000..c3fc993
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex/apply.json
@@ -0,0 +1,79 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_complex_resource.complex: Plan to create",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_complex_resource.complex",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_complex_resource.complex",
+        "resource_key": null,
+        "resource_name": "complex",
+        "resource_type": "tfcoremock_complex_resource"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_complex_resource.complex: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_complex_resource.complex",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_complex_resource.complex",
+        "resource_key": null,
+        "resource_name": "complex",
+        "resource_type": "tfcoremock_complex_resource"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_complex_resource.complex: Creation complete after 0s [id=64564E36-BFCB-458B-9405-EBBF6A3CAC7A]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+      "resource": {
+        "addr": "tfcoremock_complex_resource.complex",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_complex_resource.complex",
+        "resource_key": null,
+        "resource_name": "complex",
+        "resource_type": "tfcoremock_complex_resource"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex/plan b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex/plan
new file mode 100644
index 0000000..86fb3ae
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex/plan
@@ -0,0 +1,228 @@
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  # tfcoremock_complex_resource.complex will be created
+  + resource "tfcoremock_complex_resource" "complex" {
+      + bool    = true
+      + float   = 987654321
+      + id      = "64564E36-BFCB-458B-9405-EBBF6A3CAC7A"
+      + integer = 987654321
+      + list    = [
+          + {
+              + string = "this is my first entry in the list, and doesn't contain anything interesting"
+            },
+          + {
+              + string = <<-EOT
+                    this is my second entry in the list
+                    I am a bit more interesting
+                    and contain multiple lines
+                EOT
+            },
+          + {
+              + list   = [
+                  + {
+                      + number = 0
+                    },
+                  + {
+                      + number = 1
+                    },
+                  + {
+                      + number = 2
+                    },
+                ]
+              + string = "this is my third entry, and I actually have a nested list"
+            },
+          + {
+              + set    = [
+                  + {
+                      + number = 0
+                    },
+                  + {
+                      + number = 1
+                    },
+                ]
+              + string = "this is my fourth entry, and I actually have a nested set"
+            },
+        ]
+      + map     = {
+          + "key_four" = {
+              + set    = [
+                  + {
+                      + number = 0
+                    },
+                  + {
+                      + number = 1
+                    },
+                ]
+              + string = "this is my fourth entry, and I actually have a nested set"
+            },
+          + "key_one" = {
+              + string = "this is my first entry in the map, and doesn't contain anything interesting"
+            },
+          + "key_three" = {
+              + list   = [
+                  + {
+                      + number = 0
+                    },
+                  + {
+                      + number = 1
+                    },
+                  + {
+                      + number = 2
+                    },
+                ]
+              + string = "this is my third entry, and I actually have a nested list"
+            },
+          + "key_two" = {
+              + string = <<-EOT
+                    this is my second entry in the map
+                    I am a bit more interesting
+                    and contain multiple lines
+                EOT
+            },
+        }
+      + number  = 123456789
+      + object  = {
+          + bool   = false
+          + number = 0
+          + object = {
+              + bool   = true
+              + number = 1
+              + string = "i am a nested nested object"
+            }
+          + string = "i am a nested object"
+        }
+      + set     = [
+          + {
+              + list   = [
+                  + {
+                      + number = 0
+                    },
+                  + {
+                      + number = 1
+                    },
+                  + {
+                      + number = 2
+                    },
+                ]
+              + string = "this is my third entry, and I actually have a nested list"
+            },
+          + {
+              + set    = [
+                  + {
+                      + number = 0
+                    },
+                  + {
+                      + number = 1
+                    },
+                ]
+              + string = "this is my fourth entry, and I actually have a nested set"
+            },
+          + {
+              + string = "this is my first entry in the set, and doesn't contain anything interesting"
+            },
+          + {
+              + string = <<-EOT
+                    this is my second entry in the set
+                    I am a bit more interesting
+                    and contain multiple lines
+                EOT
+            },
+        ]
+      + string  = "a not very long or complex string"
+
+      + list_block {
+          + string = jsonencode(
+                {
+                  + index = 0
+                }
+            )
+        }
+      + list_block {
+          + list   = [
+              + {
+                  + number = 0
+                },
+              + {
+                  + number = 1
+                },
+              + {
+                  + number = 2
+                },
+            ]
+          + string = jsonencode(
+                {
+                  + index = 1
+                }
+            )
+        }
+      + list_block {
+          + set    = [
+              + {
+                  + number = 0
+                },
+              + {
+                  + number = 1
+                },
+            ]
+          + string = jsonencode(
+                {
+                  + index = 2
+                }
+            )
+        }
+
+      + set_block {
+          + list   = [
+              + {
+                  + number = 0
+                },
+              + {
+                  + number = 1
+                },
+              + {
+                  + number = 2
+                },
+            ]
+          + string = jsonencode(
+                {
+                  + index = 1
+                }
+            )
+        }
+      + set_block {
+          + set    = [
+              + {
+                  + number = 0
+                },
+              + {
+                  + number = 1
+                },
+            ]
+          + string = jsonencode(
+                {
+                  + index = 2
+                }
+            )
+        }
+      + set_block {
+          + string = jsonencode(
+                {
+                  + index = 0
+                }
+            )
+        }
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex/plan.json b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex/plan.json
new file mode 100644
index 0000000..22a2ec2
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex/plan.json
@@ -0,0 +1,1545 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_complex_resource.complex",
+          "expressions": {
+            "bool": {
+              "constant_value": true
+            },
+            "float": {
+              "constant_value": 987654321
+            },
+            "id": {
+              "constant_value": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A"
+            },
+            "integer": {
+              "constant_value": 987654321
+            },
+            "list": {
+              "constant_value": [
+                {
+                  "string": "this is my first entry in the list, and doesn't contain anything interesting"
+                },
+                {
+                  "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines"
+                },
+                {
+                  "list": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 2
+                    }
+                  ],
+                  "string": "this is my third entry, and I actually have a nested list"
+                },
+                {
+                  "set": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    }
+                  ],
+                  "string": "this is my fourth entry, and I actually have a nested set"
+                }
+              ]
+            },
+            "list_block": [
+              {
+                "string": {
+                  "constant_value": "{\"index\":0}"
+                }
+              },
+              {
+                "list": {
+                  "constant_value": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 2
+                    }
+                  ]
+                },
+                "string": {
+                  "constant_value": "{\"index\":1}"
+                }
+              },
+              {
+                "set": {
+                  "constant_value": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    }
+                  ]
+                },
+                "string": {
+                  "constant_value": "{\"index\":2}"
+                }
+              }
+            ],
+            "map": {
+              "constant_value": {
+                "key_four": {
+                  "set": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    }
+                  ],
+                  "string": "this is my fourth entry, and I actually have a nested set"
+                },
+                "key_one": {
+                  "string": "this is my first entry in the map, and doesn't contain anything interesting"
+                },
+                "key_three": {
+                  "list": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 2
+                    }
+                  ],
+                  "string": "this is my third entry, and I actually have a nested list"
+                },
+                "key_two": {
+                  "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+                }
+              }
+            },
+            "number": {
+              "constant_value": 123456789
+            },
+            "object": {
+              "constant_value": {
+                "bool": false,
+                "number": 0,
+                "object": {
+                  "bool": true,
+                  "number": 1,
+                  "string": "i am a nested nested object"
+                },
+                "string": "i am a nested object"
+              }
+            },
+            "set": {
+              "constant_value": [
+                {
+                  "string": "this is my first entry in the set, and doesn't contain anything interesting"
+                },
+                {
+                  "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+                },
+                {
+                  "list": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 2
+                    }
+                  ],
+                  "string": "this is my third entry, and I actually have a nested list"
+                },
+                {
+                  "set": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    }
+                  ],
+                  "string": "this is my fourth entry, and I actually have a nested set"
+                }
+              ]
+            },
+            "set_block": [
+              {
+                "string": {
+                  "constant_value": "{\"index\":0}"
+                }
+              },
+              {
+                "list": {
+                  "constant_value": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 2
+                    }
+                  ]
+                },
+                "string": {
+                  "constant_value": "{\"index\":1}"
+                }
+              },
+              {
+                "set": {
+                  "constant_value": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    }
+                  ]
+                },
+                "string": {
+                  "constant_value": "{\"index\":2}"
+                }
+              }
+            ],
+            "string": {
+              "constant_value": "a not very long or complex string"
+            }
+          },
+          "mode": "managed",
+          "name": "complex",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_complex_resource"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_complex_resource.complex",
+          "mode": "managed",
+          "name": "complex",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "list": [
+              {},
+              {},
+              {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ]
+              },
+              {
+                "set": [
+                  {},
+                  {}
+                ]
+              }
+            ],
+            "list_block": [
+              {
+                "list_block": [],
+                "set_block": []
+              },
+              {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ],
+                "list_block": [],
+                "set_block": []
+              },
+              {
+                "list_block": [],
+                "set": [
+                  {},
+                  {}
+                ],
+                "set_block": []
+              }
+            ],
+            "map": {
+              "key_four": {
+                "set": [
+                  {},
+                  {}
+                ]
+              },
+              "key_one": {},
+              "key_three": {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ]
+              },
+              "key_two": {}
+            },
+            "object": {
+              "object": {}
+            },
+            "set": [
+              {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ]
+              },
+              {
+                "set": [
+                  {},
+                  {}
+                ]
+              },
+              {},
+              {}
+            ],
+            "set_block": [
+              {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ],
+                "list_block": [],
+                "set_block": []
+              },
+              {
+                "list_block": [],
+                "set": [
+                  {},
+                  {}
+                ],
+                "set_block": []
+              },
+              {
+                "list_block": [],
+                "set_block": []
+              }
+            ]
+          },
+          "type": "tfcoremock_complex_resource",
+          "values": {
+            "bool": true,
+            "float": 987654321,
+            "id": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+            "integer": 987654321,
+            "list": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the list, and doesn't contain anything interesting"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              }
+            ],
+            "list_block": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":0}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":1}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "set_block": [],
+                "string": "{\"index\":2}"
+              }
+            ],
+            "map": {
+              "key_four": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              },
+              "key_one": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the map, and doesn't contain anything interesting"
+              },
+              "key_three": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              "key_two": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+              }
+            },
+            "number": 123456789,
+            "object": {
+              "bool": false,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": 0,
+              "object": {
+                "bool": true,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": 1,
+                "object": null,
+                "set": null,
+                "string": "i am a nested nested object"
+              },
+              "set": null,
+              "string": "i am a nested object"
+            },
+            "set": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the set, and doesn't contain anything interesting"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+              }
+            ],
+            "set_block": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":1}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "set_block": [],
+                "string": "{\"index\":2}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":0}"
+              }
+            ],
+            "string": "a not very long or complex string"
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_complex_resource.complex",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "after": {
+          "bool": true,
+          "float": 987654321,
+          "id": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+          "integer": 987654321,
+          "list": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my first entry in the list, and doesn't contain anything interesting"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my third entry, and I actually have a nested list"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "string": "this is my fourth entry, and I actually have a nested set"
+            }
+          ],
+          "list_block": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":0}"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":1}"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "set_block": [],
+              "string": "{\"index\":2}"
+            }
+          ],
+          "map": {
+            "key_four": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "string": "this is my fourth entry, and I actually have a nested set"
+            },
+            "key_one": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my first entry in the map, and doesn't contain anything interesting"
+            },
+            "key_three": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my third entry, and I actually have a nested list"
+            },
+            "key_two": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+            }
+          },
+          "number": 123456789,
+          "object": {
+            "bool": false,
+            "float": null,
+            "integer": null,
+            "list": null,
+            "map": null,
+            "number": 0,
+            "object": {
+              "bool": true,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": 1,
+              "object": null,
+              "set": null,
+              "string": "i am a nested nested object"
+            },
+            "set": null,
+            "string": "i am a nested object"
+          },
+          "set": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my third entry, and I actually have a nested list"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "string": "this is my fourth entry, and I actually have a nested set"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my first entry in the set, and doesn't contain anything interesting"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+            }
+          ],
+          "set_block": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":1}"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "set_block": [],
+              "string": "{\"index\":2}"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":0}"
+            }
+          ],
+          "string": "a not very long or complex string"
+        },
+        "after_sensitive": {
+          "list": [
+            {},
+            {},
+            {
+              "list": [
+                {},
+                {},
+                {}
+              ]
+            },
+            {
+              "set": [
+                {},
+                {}
+              ]
+            }
+          ],
+          "list_block": [
+            {
+              "list_block": [],
+              "set_block": []
+            },
+            {
+              "list": [
+                {},
+                {},
+                {}
+              ],
+              "list_block": [],
+              "set_block": []
+            },
+            {
+              "list_block": [],
+              "set": [
+                {},
+                {}
+              ],
+              "set_block": []
+            }
+          ],
+          "map": {
+            "key_four": {
+              "set": [
+                {},
+                {}
+              ]
+            },
+            "key_one": {},
+            "key_three": {
+              "list": [
+                {},
+                {},
+                {}
+              ]
+            },
+            "key_two": {}
+          },
+          "object": {
+            "object": {}
+          },
+          "set": [
+            {
+              "list": [
+                {},
+                {},
+                {}
+              ]
+            },
+            {
+              "set": [
+                {},
+                {}
+              ]
+            },
+            {},
+            {}
+          ],
+          "set_block": [
+            {
+              "list": [
+                {},
+                {},
+                {}
+              ],
+              "list_block": [],
+              "set_block": []
+            },
+            {
+              "list_block": [],
+              "set": [
+                {},
+                {}
+              ],
+              "set_block": []
+            },
+            {
+              "list_block": [],
+              "set_block": []
+            }
+          ]
+        },
+        "after_unknown": {},
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "managed",
+      "name": "complex",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_complex_resource"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:19Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex/state b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex/state
new file mode 100644
index 0000000..de3bff4
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex/state
@@ -0,0 +1,212 @@
+# tfcoremock_complex_resource.complex:
+resource "tfcoremock_complex_resource" "complex" {
+    bool    = true
+    float   = 987654321
+    id      = "64564E36-BFCB-458B-9405-EBBF6A3CAC7A"
+    integer = 987654321
+    list    = [
+        {
+            string = "this is my first entry in the list, and doesn't contain anything interesting"
+        },
+        {
+            string = <<-EOT
+                this is my second entry in the list
+                I am a bit more interesting
+                and contain multiple lines
+            EOT
+        },
+        {
+            list   = [
+                {
+                    number = 0
+                },
+                {
+                    number = 1
+                },
+                {
+                    number = 2
+                },
+            ]
+            string = "this is my third entry, and I actually have a nested list"
+        },
+        {
+            set    = [
+                {
+                    number = 0
+                },
+                {
+                    number = 1
+                },
+            ]
+            string = "this is my fourth entry, and I actually have a nested set"
+        },
+    ]
+    map     = {
+        "key_four" = {
+            set    = [
+                {
+                    number = 0
+                },
+                {
+                    number = 1
+                },
+            ]
+            string = "this is my fourth entry, and I actually have a nested set"
+        },
+        "key_one" = {
+            string = "this is my first entry in the map, and doesn't contain anything interesting"
+        },
+        "key_three" = {
+            list   = [
+                {
+                    number = 0
+                },
+                {
+                    number = 1
+                },
+                {
+                    number = 2
+                },
+            ]
+            string = "this is my third entry, and I actually have a nested list"
+        },
+        "key_two" = {
+            string = <<-EOT
+                this is my second entry in the map
+                I am a bit more interesting
+                and contain multiple lines
+            EOT
+        },
+    }
+    number  = 123456789
+    object  = {
+        bool   = false
+        number = 0
+        object = {
+            bool   = true
+            number = 1
+            string = "i am a nested nested object"
+        }
+        string = "i am a nested object"
+    }
+    set     = [
+        {
+            list   = [
+                {
+                    number = 0
+                },
+                {
+                    number = 1
+                },
+                {
+                    number = 2
+                },
+            ]
+            string = "this is my third entry, and I actually have a nested list"
+        },
+        {
+            set    = [
+                {
+                    number = 0
+                },
+                {
+                    number = 1
+                },
+            ]
+            string = "this is my fourth entry, and I actually have a nested set"
+        },
+        {
+            string = "this is my first entry in the set, and doesn't contain anything interesting"
+        },
+        {
+            string = <<-EOT
+                this is my second entry in the set
+                I am a bit more interesting
+                and contain multiple lines
+            EOT
+        },
+    ]
+    string  = "a not very long or complex string"
+
+    list_block {
+        string = jsonencode(
+            {
+                index = 0
+            }
+        )
+    }
+    list_block {
+        list   = [
+            {
+                number = 0
+            },
+            {
+                number = 1
+            },
+            {
+                number = 2
+            },
+        ]
+        string = jsonencode(
+            {
+                index = 1
+            }
+        )
+    }
+    list_block {
+        set    = [
+            {
+                number = 0
+            },
+            {
+                number = 1
+            },
+        ]
+        string = jsonencode(
+            {
+                index = 2
+            }
+        )
+    }
+
+    set_block {
+        list   = [
+            {
+                number = 0
+            },
+            {
+                number = 1
+            },
+            {
+                number = 2
+            },
+        ]
+        string = jsonencode(
+            {
+                index = 1
+            }
+        )
+    }
+    set_block {
+        set    = [
+            {
+                number = 0
+            },
+            {
+                number = 1
+            },
+        ]
+        string = jsonencode(
+            {
+                index = 2
+            }
+        )
+    }
+    set_block {
+        string = jsonencode(
+            {
+                index = 0
+            }
+        )
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex/state.json b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex/state.json
new file mode 100644
index 0000000..e7f3c06
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex/state.json
@@ -0,0 +1,653 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_complex_resource.complex",
+          "mode": "managed",
+          "name": "complex",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "list": [
+              {},
+              {},
+              {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ]
+              },
+              {
+                "set": [
+                  {},
+                  {}
+                ]
+              }
+            ],
+            "list_block": [
+              {
+                "list_block": [],
+                "set_block": []
+              },
+              {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ],
+                "list_block": [],
+                "set_block": []
+              },
+              {
+                "list_block": [],
+                "set": [
+                  {},
+                  {}
+                ],
+                "set_block": []
+              }
+            ],
+            "map": {
+              "key_four": {
+                "set": [
+                  {},
+                  {}
+                ]
+              },
+              "key_one": {},
+              "key_three": {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ]
+              },
+              "key_two": {}
+            },
+            "object": {
+              "object": {}
+            },
+            "set": [
+              {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ]
+              },
+              {
+                "set": [
+                  {},
+                  {}
+                ]
+              },
+              {},
+              {}
+            ],
+            "set_block": [
+              {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ],
+                "list_block": [],
+                "set_block": []
+              },
+              {
+                "list_block": [],
+                "set": [
+                  {},
+                  {}
+                ],
+                "set_block": []
+              },
+              {
+                "list_block": [],
+                "set_block": []
+              }
+            ]
+          },
+          "type": "tfcoremock_complex_resource",
+          "values": {
+            "bool": true,
+            "float": 987654321,
+            "id": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+            "integer": 987654321,
+            "list": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the list, and doesn't contain anything interesting"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              }
+            ],
+            "list_block": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":0}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":1}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "set_block": [],
+                "string": "{\"index\":2}"
+              }
+            ],
+            "map": {
+              "key_four": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              },
+              "key_one": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the map, and doesn't contain anything interesting"
+              },
+              "key_three": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              "key_two": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+              }
+            },
+            "number": 123456789,
+            "object": {
+              "bool": false,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": 0,
+              "object": {
+                "bool": true,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": 1,
+                "object": null,
+                "set": null,
+                "string": "i am a nested nested object"
+              },
+              "set": null,
+              "string": "i am a nested object"
+            },
+            "set": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the set, and doesn't contain anything interesting"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+              }
+            ],
+            "set_block": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":1}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "set_block": [],
+                "string": "{\"index\":2}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":0}"
+              }
+            ],
+            "string": "a not very long or complex string"
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_destroy/apply.json b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_destroy/apply.json
new file mode 100644
index 0000000..701f9b9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_destroy/apply.json
@@ -0,0 +1,123 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_complex_resource.complex: Refreshing state... [id=64564E36-BFCB-458B-9405-EBBF6A3CAC7A]",
+    "@module": "terraform.ui",
+    "hook": {
+      "id_key": "id",
+      "id_value": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+      "resource": {
+        "addr": "tfcoremock_complex_resource.complex",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_complex_resource.complex",
+        "resource_key": null,
+        "resource_name": "complex",
+        "resource_type": "tfcoremock_complex_resource"
+      }
+    },
+    "type": "refresh_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_complex_resource.complex: Refresh complete [id=64564E36-BFCB-458B-9405-EBBF6A3CAC7A]",
+    "@module": "terraform.ui",
+    "hook": {
+      "id_key": "id",
+      "id_value": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+      "resource": {
+        "addr": "tfcoremock_complex_resource.complex",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_complex_resource.complex",
+        "resource_key": null,
+        "resource_name": "complex",
+        "resource_type": "tfcoremock_complex_resource"
+      }
+    },
+    "type": "refresh_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_complex_resource.complex: Plan to delete",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "delete",
+      "resource": {
+        "addr": "tfcoremock_complex_resource.complex",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_complex_resource.complex",
+        "resource_key": null,
+        "resource_name": "complex",
+        "resource_type": "tfcoremock_complex_resource"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "Plan: 0 to add, 0 to change, 1 to destroy.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 0,
+      "import": 0,
+      "operation": "plan",
+      "remove": 1
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_complex_resource.complex: Destroying... [id=64564E36-BFCB-458B-9405-EBBF6A3CAC7A]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "id_key": "id",
+      "id_value": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+      "resource": {
+        "addr": "tfcoremock_complex_resource.complex",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_complex_resource.complex",
+        "resource_key": null,
+        "resource_name": "complex",
+        "resource_type": "tfcoremock_complex_resource"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_complex_resource.complex: Destruction complete after 0s",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "elapsed_seconds": 0,
+      "resource": {
+        "addr": "tfcoremock_complex_resource.complex",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_complex_resource.complex",
+        "resource_key": null,
+        "resource_name": "complex",
+        "resource_type": "tfcoremock_complex_resource"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Destroy complete! Resources: 1 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 0,
+      "import": 0,
+      "operation": "destroy",
+      "remove": 1
+    },
+    "type": "change_summary"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_destroy/plan b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_destroy/plan
new file mode 100644
index 0000000..194ca98
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_destroy/plan
@@ -0,0 +1,229 @@
+tfcoremock_complex_resource.complex: Refreshing state... [id=64564E36-BFCB-458B-9405-EBBF6A3CAC7A]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  - destroy
+
+Terraform will perform the following actions:
+
+  # tfcoremock_complex_resource.complex will be destroyed
+  - resource "tfcoremock_complex_resource" "complex" {
+      - bool    = true -> null
+      - float   = 987654321 -> null
+      - id      = "64564E36-BFCB-458B-9405-EBBF6A3CAC7A" -> null
+      - integer = 987654321 -> null
+      - list    = [
+          - {
+              - string = "this is my first entry in the list, and doesn't contain anything interesting" -> null
+            },
+          - {
+              - string = <<-EOT
+                    this is my second entry in the list
+                    I am a bit more interesting
+                    and contain multiple lines
+                EOT -> null
+            },
+          - {
+              - list   = [
+                  - {
+                      - number = 0 -> null
+                    },
+                  - {
+                      - number = 1 -> null
+                    },
+                  - {
+                      - number = 2 -> null
+                    },
+                ] -> null
+              - string = "this is my third entry, and I actually have a nested list" -> null
+            },
+          - {
+              - set    = [
+                  - {
+                      - number = 0 -> null
+                    },
+                  - {
+                      - number = 1 -> null
+                    },
+                ] -> null
+              - string = "this is my fourth entry, and I actually have a nested set" -> null
+            },
+        ] -> null
+      - map     = {
+          - "key_four" = {
+              - set    = [
+                  - {
+                      - number = 0 -> null
+                    },
+                  - {
+                      - number = 1 -> null
+                    },
+                ] -> null
+              - string = "this is my fourth entry, and I actually have a nested set" -> null
+            },
+          - "key_one" = {
+              - string = "this is my first entry in the map, and doesn't contain anything interesting" -> null
+            },
+          - "key_three" = {
+              - list   = [
+                  - {
+                      - number = 0 -> null
+                    },
+                  - {
+                      - number = 1 -> null
+                    },
+                  - {
+                      - number = 2 -> null
+                    },
+                ] -> null
+              - string = "this is my third entry, and I actually have a nested list" -> null
+            },
+          - "key_two" = {
+              - string = <<-EOT
+                    this is my second entry in the map
+                    I am a bit more interesting
+                    and contain multiple lines
+                EOT -> null
+            },
+        } -> null
+      - number  = 123456789 -> null
+      - object  = {
+          - bool   = false -> null
+          - number = 0 -> null
+          - object = {
+              - bool   = true -> null
+              - number = 1 -> null
+              - string = "i am a nested nested object" -> null
+            } -> null
+          - string = "i am a nested object" -> null
+        } -> null
+      - set     = [
+          - {
+              - list   = [
+                  - {
+                      - number = 0 -> null
+                    },
+                  - {
+                      - number = 1 -> null
+                    },
+                  - {
+                      - number = 2 -> null
+                    },
+                ] -> null
+              - string = "this is my third entry, and I actually have a nested list" -> null
+            },
+          - {
+              - set    = [
+                  - {
+                      - number = 0 -> null
+                    },
+                  - {
+                      - number = 1 -> null
+                    },
+                ] -> null
+              - string = "this is my fourth entry, and I actually have a nested set" -> null
+            },
+          - {
+              - string = "this is my first entry in the set, and doesn't contain anything interesting" -> null
+            },
+          - {
+              - string = <<-EOT
+                    this is my second entry in the set
+                    I am a bit more interesting
+                    and contain multiple lines
+                EOT -> null
+            },
+        ] -> null
+      - string  = "a not very long or complex string" -> null
+
+      - list_block {
+          - string = jsonencode(
+                {
+                  - index = 0
+                }
+            ) -> null
+        }
+      - list_block {
+          - list   = [
+              - {
+                  - number = 0 -> null
+                },
+              - {
+                  - number = 1 -> null
+                },
+              - {
+                  - number = 2 -> null
+                },
+            ] -> null
+          - string = jsonencode(
+                {
+                  - index = 1
+                }
+            ) -> null
+        }
+      - list_block {
+          - set    = [
+              - {
+                  - number = 0 -> null
+                },
+              - {
+                  - number = 1 -> null
+                },
+            ] -> null
+          - string = jsonencode(
+                {
+                  - index = 2
+                }
+            ) -> null
+        }
+
+      - set_block {
+          - list   = [
+              - {
+                  - number = 0 -> null
+                },
+              - {
+                  - number = 1 -> null
+                },
+              - {
+                  - number = 2 -> null
+                },
+            ] -> null
+          - string = jsonencode(
+                {
+                  - index = 1
+                }
+            ) -> null
+        }
+      - set_block {
+          - set    = [
+              - {
+                  - number = 0 -> null
+                },
+              - {
+                  - number = 1 -> null
+                },
+            ] -> null
+          - string = jsonencode(
+                {
+                  - index = 2
+                }
+            ) -> null
+        }
+      - set_block {
+          - string = jsonencode(
+                {
+                  - index = 0
+                }
+            ) -> null
+        }
+    }
+
+Plan: 0 to add, 0 to change, 1 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_destroy/plan.json b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_destroy/plan.json
new file mode 100644
index 0000000..f77fe27
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_destroy/plan.json
@@ -0,0 +1,1546 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_complex_resource.complex",
+          "expressions": {
+            "bool": {
+              "constant_value": true
+            },
+            "float": {
+              "constant_value": 123456789
+            },
+            "id": {
+              "constant_value": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A"
+            },
+            "integer": {
+              "constant_value": 123456789
+            },
+            "list": {
+              "constant_value": [
+                {
+                  "string": "this is my first entry in the list, and doesn't contain anything interesting"
+                },
+                {
+                  "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines\nbut I've been edited"
+                },
+                {
+                  "list": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 3
+                    },
+                    {
+                      "number": 4
+                    }
+                  ],
+                  "string": "this is my third entry, and I actually have a nested list"
+                },
+                {
+                  "set": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 2
+                    }
+                  ],
+                  "string": "this is my fourth entry, and I actually have a nested set and I edited my test"
+                }
+              ]
+            },
+            "list_block": [
+              {
+                "string": {
+                  "constant_value": "{\"index\":0}"
+                }
+              },
+              {
+                "list": {
+                  "constant_value": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 2
+                    }
+                  ]
+                },
+                "string": {
+                  "constant_value": "{\"index\":1}"
+                }
+              }
+            ],
+            "map": {
+              "constant_value": {
+                "key_four": {
+                  "set": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 3
+                    },
+                    {
+                      "number": 4
+                    }
+                  ],
+                  "string": "this is my fourth entry, and I actually have a nested set"
+                },
+                "key_one": {
+                  "string": "this is my first entry in the map, and doesn't contain anything interesting"
+                },
+                "key_three": {
+                  "list": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 3
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 2
+                    }
+                  ],
+                  "string": "this is my third entry, and I actually have a nested list"
+                },
+                "key_two": {
+                  "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+                }
+              }
+            },
+            "number": {
+              "constant_value": 987654321
+            },
+            "object": {
+              "constant_value": {
+                "number": 0,
+                "object": {
+                  "bool": true,
+                  "string": "i am a nested nested object"
+                },
+                "string": "i am a nested object"
+              }
+            },
+            "set": {
+              "constant_value": [
+                {
+                  "string": "this is my first entry in the set, and doesn't contain anything interesting"
+                },
+                {
+                  "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+                },
+                {
+                  "list": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 2
+                    }
+                  ],
+                  "string": "this is my third entry, and I actually have a nested list"
+                },
+                {
+                  "set": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    }
+                  ],
+                  "string": "this is my fourth entry, and I actually have a nested set"
+                }
+              ]
+            },
+            "set_block": [
+              {
+                "list": {
+                  "constant_value": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 2
+                    }
+                  ]
+                },
+                "string": {
+                  "constant_value": "{\"index\":1}"
+                }
+              },
+              {
+                "set": {
+                  "constant_value": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    }
+                  ]
+                },
+                "string": {
+                  "constant_value": "{\"index\":2}"
+                }
+              },
+              {
+                "string": {
+                  "constant_value": "{\"index\":3}"
+                }
+              }
+            ],
+            "string": {
+              "constant_value": "a not very long or complex string"
+            }
+          },
+          "mode": "managed",
+          "name": "complex",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_complex_resource"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {}
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_complex_resource.complex",
+            "mode": "managed",
+            "name": "complex",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "list": [
+                {},
+                {},
+                {
+                  "list": [
+                    {},
+                    {},
+                    {}
+                  ]
+                },
+                {
+                  "set": [
+                    {},
+                    {}
+                  ]
+                }
+              ],
+              "list_block": [
+                {
+                  "list_block": [],
+                  "set_block": []
+                },
+                {
+                  "list": [
+                    {},
+                    {},
+                    {}
+                  ],
+                  "list_block": [],
+                  "set_block": []
+                },
+                {
+                  "list_block": [],
+                  "set": [
+                    {},
+                    {}
+                  ],
+                  "set_block": []
+                }
+              ],
+              "map": {
+                "key_four": {
+                  "set": [
+                    {},
+                    {}
+                  ]
+                },
+                "key_one": {},
+                "key_three": {
+                  "list": [
+                    {},
+                    {},
+                    {}
+                  ]
+                },
+                "key_two": {}
+              },
+              "object": {
+                "object": {}
+              },
+              "set": [
+                {
+                  "list": [
+                    {},
+                    {},
+                    {}
+                  ]
+                },
+                {
+                  "set": [
+                    {},
+                    {}
+                  ]
+                },
+                {},
+                {}
+              ],
+              "set_block": [
+                {
+                  "list": [
+                    {},
+                    {},
+                    {}
+                  ],
+                  "list_block": [],
+                  "set_block": []
+                },
+                {
+                  "list_block": [],
+                  "set": [
+                    {},
+                    {}
+                  ],
+                  "set_block": []
+                },
+                {
+                  "list_block": [],
+                  "set_block": []
+                }
+              ]
+            },
+            "type": "tfcoremock_complex_resource",
+            "values": {
+              "bool": true,
+              "float": 987654321,
+              "id": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+              "integer": 987654321,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my first entry in the list, and doesn't contain anything interesting"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 2,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my third entry, and I actually have a nested list"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "string": "this is my fourth entry, and I actually have a nested set"
+                }
+              ],
+              "list_block": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "list_block": [],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "set_block": [],
+                  "string": "{\"index\":0}"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 2,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "list_block": [],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "set_block": [],
+                  "string": "{\"index\":1}"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "list_block": [],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "set_block": [],
+                  "string": "{\"index\":2}"
+                }
+              ],
+              "map": {
+                "key_four": {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "string": "this is my fourth entry, and I actually have a nested set"
+                },
+                "key_one": {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my first entry in the map, and doesn't contain anything interesting"
+                },
+                "key_three": {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 2,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my third entry, and I actually have a nested list"
+                },
+                "key_two": {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+                }
+              },
+              "number": 123456789,
+              "object": {
+                "bool": false,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": 0,
+                "object": {
+                  "bool": true,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": "i am a nested nested object"
+                },
+                "set": null,
+                "string": "i am a nested object"
+              },
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 2,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my third entry, and I actually have a nested list"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "string": "this is my fourth entry, and I actually have a nested set"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my first entry in the set, and doesn't contain anything interesting"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+                }
+              ],
+              "set_block": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 2,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "list_block": [],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "set_block": [],
+                  "string": "{\"index\":1}"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "list_block": [],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "set_block": [],
+                  "string": "{\"index\":2}"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "list_block": [],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "set_block": [],
+                  "string": "{\"index\":0}"
+                }
+              ],
+              "string": "a not very long or complex string"
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_complex_resource.complex",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "after": null,
+        "after_sensitive": false,
+        "after_unknown": {},
+        "before": {
+          "bool": true,
+          "float": 987654321,
+          "id": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+          "integer": 987654321,
+          "list": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my first entry in the list, and doesn't contain anything interesting"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my third entry, and I actually have a nested list"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "string": "this is my fourth entry, and I actually have a nested set"
+            }
+          ],
+          "list_block": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":0}"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":1}"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "set_block": [],
+              "string": "{\"index\":2}"
+            }
+          ],
+          "map": {
+            "key_four": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "string": "this is my fourth entry, and I actually have a nested set"
+            },
+            "key_one": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my first entry in the map, and doesn't contain anything interesting"
+            },
+            "key_three": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my third entry, and I actually have a nested list"
+            },
+            "key_two": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+            }
+          },
+          "number": 123456789,
+          "object": {
+            "bool": false,
+            "float": null,
+            "integer": null,
+            "list": null,
+            "map": null,
+            "number": 0,
+            "object": {
+              "bool": true,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": 1,
+              "object": null,
+              "set": null,
+              "string": "i am a nested nested object"
+            },
+            "set": null,
+            "string": "i am a nested object"
+          },
+          "set": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my third entry, and I actually have a nested list"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "string": "this is my fourth entry, and I actually have a nested set"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my first entry in the set, and doesn't contain anything interesting"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+            }
+          ],
+          "set_block": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":1}"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "set_block": [],
+              "string": "{\"index\":2}"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":0}"
+            }
+          ],
+          "string": "a not very long or complex string"
+        },
+        "before_sensitive": {
+          "list": [
+            {},
+            {},
+            {
+              "list": [
+                {},
+                {},
+                {}
+              ]
+            },
+            {
+              "set": [
+                {},
+                {}
+              ]
+            }
+          ],
+          "list_block": [
+            {
+              "list_block": [],
+              "set_block": []
+            },
+            {
+              "list": [
+                {},
+                {},
+                {}
+              ],
+              "list_block": [],
+              "set_block": []
+            },
+            {
+              "list_block": [],
+              "set": [
+                {},
+                {}
+              ],
+              "set_block": []
+            }
+          ],
+          "map": {
+            "key_four": {
+              "set": [
+                {},
+                {}
+              ]
+            },
+            "key_one": {},
+            "key_three": {
+              "list": [
+                {},
+                {},
+                {}
+              ]
+            },
+            "key_two": {}
+          },
+          "object": {
+            "object": {}
+          },
+          "set": [
+            {
+              "list": [
+                {},
+                {},
+                {}
+              ]
+            },
+            {
+              "set": [
+                {},
+                {}
+              ]
+            },
+            {},
+            {}
+          ],
+          "set_block": [
+            {
+              "list": [
+                {},
+                {},
+                {}
+              ],
+              "list_block": [],
+              "set_block": []
+            },
+            {
+              "list_block": [],
+              "set": [
+                {},
+                {}
+              ],
+              "set_block": []
+            },
+            {
+              "list_block": [],
+              "set_block": []
+            }
+          ]
+        }
+      },
+      "mode": "managed",
+      "name": "complex",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_complex_resource"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:24Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_destroy/state.json b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_destroy/state.json
new file mode 100644
index 0000000..00f8f1c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_destroy/state.json
@@ -0,0 +1,3 @@
+{
+  "format_version": "1.0"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_update/apply.json b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_update/apply.json
new file mode 100644
index 0000000..845c722
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_update/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_complex_resource.complex: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_complex_resource.complex",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_complex_resource.complex",
+        "resource_key": null,
+        "resource_name": "complex",
+        "resource_type": "tfcoremock_complex_resource"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_complex_resource.complex: Modifying... [id=64564E36-BFCB-458B-9405-EBBF6A3CAC7A]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+      "resource": {
+        "addr": "tfcoremock_complex_resource.complex",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_complex_resource.complex",
+        "resource_key": null,
+        "resource_name": "complex",
+        "resource_type": "tfcoremock_complex_resource"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_complex_resource.complex: Modifications complete after 0s [id=64564E36-BFCB-458B-9405-EBBF6A3CAC7A]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+      "resource": {
+        "addr": "tfcoremock_complex_resource.complex",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_complex_resource.complex",
+        "resource_key": null,
+        "resource_name": "complex",
+        "resource_type": "tfcoremock_complex_resource"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_update/plan b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_update/plan
new file mode 100644
index 0000000..3d00db8
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_update/plan
@@ -0,0 +1,131 @@
+tfcoremock_complex_resource.complex: Refreshing state... [id=64564E36-BFCB-458B-9405-EBBF6A3CAC7A]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_complex_resource.complex will be updated in-place
+  ~ resource "tfcoremock_complex_resource" "complex" {
+      ~ float   = 987654321 -> 123456789
+        id      = "64564E36-BFCB-458B-9405-EBBF6A3CAC7A"
+      ~ integer = 987654321 -> 123456789
+      ~ list    = [
+          ~ {
+              ~ string = <<-EOT
+                    this is my second entry in the list
+                    I am a bit more interesting
+                    and contain multiple lines
+                  + but I've been edited
+                EOT
+            },
+          ~ {
+              ~ list   = [
+                  ~ {
+                      ~ number = 2 -> 3
+                    },
+                  + {
+                      + number = 4
+                    },
+                    # (2 unchanged elements hidden)
+                ]
+                # (1 unchanged attribute hidden)
+            },
+          ~ {
+              ~ set    = [
+                  - {
+                      - number = 1 -> null
+                    },
+                  + {
+                      + number = 2
+                    },
+                    # (1 unchanged element hidden)
+                ]
+              ~ string = "this is my fourth entry, and I actually have a nested set" -> "this is my fourth entry, and I actually have a nested set and I edited my test"
+            },
+            # (1 unchanged element hidden)
+        ]
+      ~ map     = {
+          ~ "key_four" = {
+              ~ set    = [
+                  + {
+                      + number = 3
+                    },
+                  + {
+                      + number = 4
+                    },
+                    # (2 unchanged elements hidden)
+                ]
+                # (1 unchanged attribute hidden)
+            },
+          ~ "key_three" = {
+              ~ list   = [
+                  ~ {
+                      ~ number = 1 -> 3
+                    },
+                  ~ {
+                      ~ number = 2 -> 1
+                    },
+                  + {
+                      + number = 2
+                    },
+                    # (1 unchanged element hidden)
+                ]
+                # (1 unchanged attribute hidden)
+            },
+            # (2 unchanged elements hidden)
+        }
+      ~ number  = 123456789 -> 987654321
+      ~ object  = {
+          - bool   = false -> null
+          ~ object = {
+              - number = 1 -> null
+                # (2 unchanged attributes hidden)
+            }
+            # (2 unchanged attributes hidden)
+        }
+        # (3 unchanged attributes hidden)
+
+      - list_block {
+          - set    = [
+              - {
+                  - number = 0 -> null
+                },
+              - {
+                  - number = 1 -> null
+                },
+            ] -> null
+          - string = jsonencode(
+                {
+                  - index = 2
+                }
+            ) -> null
+        }
+
+      - set_block {
+          - string = jsonencode(
+                {
+                  - index = 0
+                }
+            ) -> null
+        }
+      + set_block {
+          + string = jsonencode(
+                {
+                  + index = 3
+                }
+            )
+        }
+
+        # (4 unchanged blocks hidden)
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_update/plan.json b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_update/plan.json
new file mode 100644
index 0000000..348e6bb
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_update/plan.json
@@ -0,0 +1,2835 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_complex_resource.complex",
+          "expressions": {
+            "bool": {
+              "constant_value": true
+            },
+            "float": {
+              "constant_value": 123456789
+            },
+            "id": {
+              "constant_value": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A"
+            },
+            "integer": {
+              "constant_value": 123456789
+            },
+            "list": {
+              "constant_value": [
+                {
+                  "string": "this is my first entry in the list, and doesn't contain anything interesting"
+                },
+                {
+                  "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines\nbut I've been edited"
+                },
+                {
+                  "list": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 3
+                    },
+                    {
+                      "number": 4
+                    }
+                  ],
+                  "string": "this is my third entry, and I actually have a nested list"
+                },
+                {
+                  "set": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 2
+                    }
+                  ],
+                  "string": "this is my fourth entry, and I actually have a nested set and I edited my test"
+                }
+              ]
+            },
+            "list_block": [
+              {
+                "string": {
+                  "constant_value": "{\"index\":0}"
+                }
+              },
+              {
+                "list": {
+                  "constant_value": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 2
+                    }
+                  ]
+                },
+                "string": {
+                  "constant_value": "{\"index\":1}"
+                }
+              }
+            ],
+            "map": {
+              "constant_value": {
+                "key_four": {
+                  "set": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 3
+                    },
+                    {
+                      "number": 4
+                    }
+                  ],
+                  "string": "this is my fourth entry, and I actually have a nested set"
+                },
+                "key_one": {
+                  "string": "this is my first entry in the map, and doesn't contain anything interesting"
+                },
+                "key_three": {
+                  "list": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 3
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 2
+                    }
+                  ],
+                  "string": "this is my third entry, and I actually have a nested list"
+                },
+                "key_two": {
+                  "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+                }
+              }
+            },
+            "number": {
+              "constant_value": 987654321
+            },
+            "object": {
+              "constant_value": {
+                "number": 0,
+                "object": {
+                  "bool": true,
+                  "string": "i am a nested nested object"
+                },
+                "string": "i am a nested object"
+              }
+            },
+            "set": {
+              "constant_value": [
+                {
+                  "string": "this is my first entry in the set, and doesn't contain anything interesting"
+                },
+                {
+                  "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+                },
+                {
+                  "list": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 2
+                    }
+                  ],
+                  "string": "this is my third entry, and I actually have a nested list"
+                },
+                {
+                  "set": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    }
+                  ],
+                  "string": "this is my fourth entry, and I actually have a nested set"
+                }
+              ]
+            },
+            "set_block": [
+              {
+                "list": {
+                  "constant_value": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    },
+                    {
+                      "number": 2
+                    }
+                  ]
+                },
+                "string": {
+                  "constant_value": "{\"index\":1}"
+                }
+              },
+              {
+                "set": {
+                  "constant_value": [
+                    {
+                      "number": 0
+                    },
+                    {
+                      "number": 1
+                    }
+                  ]
+                },
+                "string": {
+                  "constant_value": "{\"index\":2}"
+                }
+              },
+              {
+                "string": {
+                  "constant_value": "{\"index\":3}"
+                }
+              }
+            ],
+            "string": {
+              "constant_value": "a not very long or complex string"
+            }
+          },
+          "mode": "managed",
+          "name": "complex",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_complex_resource"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_complex_resource.complex",
+          "mode": "managed",
+          "name": "complex",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "list": [
+              {},
+              {},
+              {
+                "list": [
+                  {},
+                  {},
+                  {},
+                  {}
+                ]
+              },
+              {
+                "set": [
+                  {},
+                  {}
+                ]
+              }
+            ],
+            "list_block": [
+              {
+                "list_block": [],
+                "set_block": []
+              },
+              {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ],
+                "list_block": [],
+                "set_block": []
+              }
+            ],
+            "map": {
+              "key_four": {
+                "set": [
+                  {},
+                  {},
+                  {},
+                  {}
+                ]
+              },
+              "key_one": {},
+              "key_three": {
+                "list": [
+                  {},
+                  {},
+                  {},
+                  {}
+                ]
+              },
+              "key_two": {}
+            },
+            "object": {
+              "object": {}
+            },
+            "set": [
+              {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ]
+              },
+              {
+                "set": [
+                  {},
+                  {}
+                ]
+              },
+              {},
+              {}
+            ],
+            "set_block": [
+              {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ],
+                "list_block": [],
+                "set_block": []
+              },
+              {
+                "list_block": [],
+                "set": [
+                  {},
+                  {}
+                ],
+                "set_block": []
+              },
+              {
+                "list_block": [],
+                "set_block": []
+              }
+            ]
+          },
+          "type": "tfcoremock_complex_resource",
+          "values": {
+            "bool": true,
+            "float": 123456789,
+            "id": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+            "integer": 123456789,
+            "list": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the list, and doesn't contain anything interesting"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines\nbut I've been edited"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 3,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 4,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set and I edited my test"
+              }
+            ],
+            "list_block": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":0}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":1}"
+              }
+            ],
+            "map": {
+              "key_four": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 3,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 4,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              },
+              "key_one": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the map, and doesn't contain anything interesting"
+              },
+              "key_three": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 3,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              "key_two": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+              }
+            },
+            "number": 987654321,
+            "object": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": 0,
+              "object": {
+                "bool": true,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "i am a nested nested object"
+              },
+              "set": null,
+              "string": "i am a nested object"
+            },
+            "set": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the set, and doesn't contain anything interesting"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+              }
+            ],
+            "set_block": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":1}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "set_block": [],
+                "string": "{\"index\":2}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":3}"
+              }
+            ],
+            "string": "a not very long or complex string"
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_complex_resource.complex",
+            "mode": "managed",
+            "name": "complex",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "list": [
+                {},
+                {},
+                {
+                  "list": [
+                    {},
+                    {},
+                    {}
+                  ]
+                },
+                {
+                  "set": [
+                    {},
+                    {}
+                  ]
+                }
+              ],
+              "list_block": [
+                {
+                  "list_block": [],
+                  "set_block": []
+                },
+                {
+                  "list": [
+                    {},
+                    {},
+                    {}
+                  ],
+                  "list_block": [],
+                  "set_block": []
+                },
+                {
+                  "list_block": [],
+                  "set": [
+                    {},
+                    {}
+                  ],
+                  "set_block": []
+                }
+              ],
+              "map": {
+                "key_four": {
+                  "set": [
+                    {},
+                    {}
+                  ]
+                },
+                "key_one": {},
+                "key_three": {
+                  "list": [
+                    {},
+                    {},
+                    {}
+                  ]
+                },
+                "key_two": {}
+              },
+              "object": {
+                "object": {}
+              },
+              "set": [
+                {
+                  "list": [
+                    {},
+                    {},
+                    {}
+                  ]
+                },
+                {
+                  "set": [
+                    {},
+                    {}
+                  ]
+                },
+                {},
+                {}
+              ],
+              "set_block": [
+                {
+                  "list": [
+                    {},
+                    {},
+                    {}
+                  ],
+                  "list_block": [],
+                  "set_block": []
+                },
+                {
+                  "list_block": [],
+                  "set": [
+                    {},
+                    {}
+                  ],
+                  "set_block": []
+                },
+                {
+                  "list_block": [],
+                  "set_block": []
+                }
+              ]
+            },
+            "type": "tfcoremock_complex_resource",
+            "values": {
+              "bool": true,
+              "float": 987654321,
+              "id": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+              "integer": 987654321,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my first entry in the list, and doesn't contain anything interesting"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 2,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my third entry, and I actually have a nested list"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "string": "this is my fourth entry, and I actually have a nested set"
+                }
+              ],
+              "list_block": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "list_block": [],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "set_block": [],
+                  "string": "{\"index\":0}"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 2,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "list_block": [],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "set_block": [],
+                  "string": "{\"index\":1}"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "list_block": [],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "set_block": [],
+                  "string": "{\"index\":2}"
+                }
+              ],
+              "map": {
+                "key_four": {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "string": "this is my fourth entry, and I actually have a nested set"
+                },
+                "key_one": {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my first entry in the map, and doesn't contain anything interesting"
+                },
+                "key_three": {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 2,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my third entry, and I actually have a nested list"
+                },
+                "key_two": {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+                }
+              },
+              "number": 123456789,
+              "object": {
+                "bool": false,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": 0,
+                "object": {
+                  "bool": true,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": "i am a nested nested object"
+                },
+                "set": null,
+                "string": "i am a nested object"
+              },
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 2,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my third entry, and I actually have a nested list"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "string": "this is my fourth entry, and I actually have a nested set"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my first entry in the set, and doesn't contain anything interesting"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+                }
+              ],
+              "set_block": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 2,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "list_block": [],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "set_block": [],
+                  "string": "{\"index\":1}"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "list_block": [],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": [
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 0,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    },
+                    {
+                      "bool": null,
+                      "float": null,
+                      "integer": null,
+                      "list": null,
+                      "map": null,
+                      "number": 1,
+                      "object": null,
+                      "set": null,
+                      "string": null
+                    }
+                  ],
+                  "set_block": [],
+                  "string": "{\"index\":2}"
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "list_block": [],
+                  "map": null,
+                  "number": null,
+                  "object": null,
+                  "set": null,
+                  "set_block": [],
+                  "string": "{\"index\":0}"
+                }
+              ],
+              "string": "a not very long or complex string"
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_complex_resource.complex",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "bool": true,
+          "float": 123456789,
+          "id": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+          "integer": 123456789,
+          "list": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my first entry in the list, and doesn't contain anything interesting"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines\nbut I've been edited"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 3,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 4,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my third entry, and I actually have a nested list"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "string": "this is my fourth entry, and I actually have a nested set and I edited my test"
+            }
+          ],
+          "list_block": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":0}"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":1}"
+            }
+          ],
+          "map": {
+            "key_four": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 3,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 4,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "string": "this is my fourth entry, and I actually have a nested set"
+            },
+            "key_one": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my first entry in the map, and doesn't contain anything interesting"
+            },
+            "key_three": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 3,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my third entry, and I actually have a nested list"
+            },
+            "key_two": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+            }
+          },
+          "number": 987654321,
+          "object": {
+            "bool": null,
+            "float": null,
+            "integer": null,
+            "list": null,
+            "map": null,
+            "number": 0,
+            "object": {
+              "bool": true,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "i am a nested nested object"
+            },
+            "set": null,
+            "string": "i am a nested object"
+          },
+          "set": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my third entry, and I actually have a nested list"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "string": "this is my fourth entry, and I actually have a nested set"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my first entry in the set, and doesn't contain anything interesting"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+            }
+          ],
+          "set_block": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":1}"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "set_block": [],
+              "string": "{\"index\":2}"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":3}"
+            }
+          ],
+          "string": "a not very long or complex string"
+        },
+        "after_sensitive": {
+          "list": [
+            {},
+            {},
+            {
+              "list": [
+                {},
+                {},
+                {},
+                {}
+              ]
+            },
+            {
+              "set": [
+                {},
+                {}
+              ]
+            }
+          ],
+          "list_block": [
+            {
+              "list_block": [],
+              "set_block": []
+            },
+            {
+              "list": [
+                {},
+                {},
+                {}
+              ],
+              "list_block": [],
+              "set_block": []
+            }
+          ],
+          "map": {
+            "key_four": {
+              "set": [
+                {},
+                {},
+                {},
+                {}
+              ]
+            },
+            "key_one": {},
+            "key_three": {
+              "list": [
+                {},
+                {},
+                {},
+                {}
+              ]
+            },
+            "key_two": {}
+          },
+          "object": {
+            "object": {}
+          },
+          "set": [
+            {
+              "list": [
+                {},
+                {},
+                {}
+              ]
+            },
+            {
+              "set": [
+                {},
+                {}
+              ]
+            },
+            {},
+            {}
+          ],
+          "set_block": [
+            {
+              "list": [
+                {},
+                {},
+                {}
+              ],
+              "list_block": [],
+              "set_block": []
+            },
+            {
+              "list_block": [],
+              "set": [
+                {},
+                {}
+              ],
+              "set_block": []
+            },
+            {
+              "list_block": [],
+              "set_block": []
+            }
+          ]
+        },
+        "after_unknown": {},
+        "before": {
+          "bool": true,
+          "float": 987654321,
+          "id": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+          "integer": 987654321,
+          "list": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my first entry in the list, and doesn't contain anything interesting"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my third entry, and I actually have a nested list"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "string": "this is my fourth entry, and I actually have a nested set"
+            }
+          ],
+          "list_block": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":0}"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":1}"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "set_block": [],
+              "string": "{\"index\":2}"
+            }
+          ],
+          "map": {
+            "key_four": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "string": "this is my fourth entry, and I actually have a nested set"
+            },
+            "key_one": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my first entry in the map, and doesn't contain anything interesting"
+            },
+            "key_three": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my third entry, and I actually have a nested list"
+            },
+            "key_two": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+            }
+          },
+          "number": 123456789,
+          "object": {
+            "bool": false,
+            "float": null,
+            "integer": null,
+            "list": null,
+            "map": null,
+            "number": 0,
+            "object": {
+              "bool": true,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": 1,
+              "object": null,
+              "set": null,
+              "string": "i am a nested nested object"
+            },
+            "set": null,
+            "string": "i am a nested object"
+          },
+          "set": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my third entry, and I actually have a nested list"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "string": "this is my fourth entry, and I actually have a nested set"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my first entry in the set, and doesn't contain anything interesting"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+            }
+          ],
+          "set_block": [
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 2,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":1}"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": [
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 0,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                },
+                {
+                  "bool": null,
+                  "float": null,
+                  "integer": null,
+                  "list": null,
+                  "map": null,
+                  "number": 1,
+                  "object": null,
+                  "set": null,
+                  "string": null
+                }
+              ],
+              "set_block": [],
+              "string": "{\"index\":2}"
+            },
+            {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "list_block": [],
+              "map": null,
+              "number": null,
+              "object": null,
+              "set": null,
+              "set_block": [],
+              "string": "{\"index\":0}"
+            }
+          ],
+          "string": "a not very long or complex string"
+        },
+        "before_sensitive": {
+          "list": [
+            {},
+            {},
+            {
+              "list": [
+                {},
+                {},
+                {}
+              ]
+            },
+            {
+              "set": [
+                {},
+                {}
+              ]
+            }
+          ],
+          "list_block": [
+            {
+              "list_block": [],
+              "set_block": []
+            },
+            {
+              "list": [
+                {},
+                {},
+                {}
+              ],
+              "list_block": [],
+              "set_block": []
+            },
+            {
+              "list_block": [],
+              "set": [
+                {},
+                {}
+              ],
+              "set_block": []
+            }
+          ],
+          "map": {
+            "key_four": {
+              "set": [
+                {},
+                {}
+              ]
+            },
+            "key_one": {},
+            "key_three": {
+              "list": [
+                {},
+                {},
+                {}
+              ]
+            },
+            "key_two": {}
+          },
+          "object": {
+            "object": {}
+          },
+          "set": [
+            {
+              "list": [
+                {},
+                {},
+                {}
+              ]
+            },
+            {
+              "set": [
+                {},
+                {}
+              ]
+            },
+            {},
+            {}
+          ],
+          "set_block": [
+            {
+              "list": [
+                {},
+                {},
+                {}
+              ],
+              "list_block": [],
+              "set_block": []
+            },
+            {
+              "list_block": [],
+              "set": [
+                {},
+                {}
+              ],
+              "set_block": []
+            },
+            {
+              "list_block": [],
+              "set_block": []
+            }
+          ]
+        }
+      },
+      "mode": "managed",
+      "name": "complex",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_complex_resource"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:27Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_update/state b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_update/state
new file mode 100644
index 0000000..4b1061f
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_update/state
@@ -0,0 +1,208 @@
+# tfcoremock_complex_resource.complex:
+resource "tfcoremock_complex_resource" "complex" {
+    bool    = true
+    float   = 123456789
+    id      = "64564E36-BFCB-458B-9405-EBBF6A3CAC7A"
+    integer = 123456789
+    list    = [
+        {
+            string = "this is my first entry in the list, and doesn't contain anything interesting"
+        },
+        {
+            string = <<-EOT
+                this is my second entry in the list
+                I am a bit more interesting
+                and contain multiple lines
+                but I've been edited
+            EOT
+        },
+        {
+            list   = [
+                {
+                    number = 0
+                },
+                {
+                    number = 1
+                },
+                {
+                    number = 3
+                },
+                {
+                    number = 4
+                },
+            ]
+            string = "this is my third entry, and I actually have a nested list"
+        },
+        {
+            set    = [
+                {
+                    number = 0
+                },
+                {
+                    number = 2
+                },
+            ]
+            string = "this is my fourth entry, and I actually have a nested set and I edited my test"
+        },
+    ]
+    map     = {
+        "key_four" = {
+            set    = [
+                {
+                    number = 0
+                },
+                {
+                    number = 1
+                },
+                {
+                    number = 3
+                },
+                {
+                    number = 4
+                },
+            ]
+            string = "this is my fourth entry, and I actually have a nested set"
+        },
+        "key_one" = {
+            string = "this is my first entry in the map, and doesn't contain anything interesting"
+        },
+        "key_three" = {
+            list   = [
+                {
+                    number = 0
+                },
+                {
+                    number = 3
+                },
+                {
+                    number = 1
+                },
+                {
+                    number = 2
+                },
+            ]
+            string = "this is my third entry, and I actually have a nested list"
+        },
+        "key_two" = {
+            string = <<-EOT
+                this is my second entry in the map
+                I am a bit more interesting
+                and contain multiple lines
+            EOT
+        },
+    }
+    number  = 987654321
+    object  = {
+        number = 0
+        object = {
+            bool   = true
+            string = "i am a nested nested object"
+        }
+        string = "i am a nested object"
+    }
+    set     = [
+        {
+            list   = [
+                {
+                    number = 0
+                },
+                {
+                    number = 1
+                },
+                {
+                    number = 2
+                },
+            ]
+            string = "this is my third entry, and I actually have a nested list"
+        },
+        {
+            set    = [
+                {
+                    number = 0
+                },
+                {
+                    number = 1
+                },
+            ]
+            string = "this is my fourth entry, and I actually have a nested set"
+        },
+        {
+            string = "this is my first entry in the set, and doesn't contain anything interesting"
+        },
+        {
+            string = <<-EOT
+                this is my second entry in the set
+                I am a bit more interesting
+                and contain multiple lines
+            EOT
+        },
+    ]
+    string  = "a not very long or complex string"
+
+    list_block {
+        string = jsonencode(
+            {
+                index = 0
+            }
+        )
+    }
+    list_block {
+        list   = [
+            {
+                number = 0
+            },
+            {
+                number = 1
+            },
+            {
+                number = 2
+            },
+        ]
+        string = jsonencode(
+            {
+                index = 1
+            }
+        )
+    }
+
+    set_block {
+        list   = [
+            {
+                number = 0
+            },
+            {
+                number = 1
+            },
+            {
+                number = 2
+            },
+        ]
+        string = jsonencode(
+            {
+                index = 1
+            }
+        )
+    }
+    set_block {
+        set    = [
+            {
+                number = 0
+            },
+            {
+                number = 1
+            },
+        ]
+        string = jsonencode(
+            {
+                index = 2
+            }
+        )
+    }
+    set_block {
+        string = jsonencode(
+            {
+                index = 3
+            }
+        )
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_update/state.json b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_update/state.json
new file mode 100644
index 0000000..95a967d
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/fully_populated_complex_update/state.json
@@ -0,0 +1,657 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_complex_resource.complex",
+          "mode": "managed",
+          "name": "complex",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "list": [
+              {},
+              {},
+              {
+                "list": [
+                  {},
+                  {},
+                  {},
+                  {}
+                ]
+              },
+              {
+                "set": [
+                  {},
+                  {}
+                ]
+              }
+            ],
+            "list_block": [
+              {
+                "list_block": [],
+                "set_block": []
+              },
+              {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ],
+                "list_block": [],
+                "set_block": []
+              }
+            ],
+            "map": {
+              "key_four": {
+                "set": [
+                  {},
+                  {},
+                  {},
+                  {}
+                ]
+              },
+              "key_one": {},
+              "key_three": {
+                "list": [
+                  {},
+                  {},
+                  {},
+                  {}
+                ]
+              },
+              "key_two": {}
+            },
+            "object": {
+              "object": {}
+            },
+            "set": [
+              {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ]
+              },
+              {
+                "set": [
+                  {},
+                  {}
+                ]
+              },
+              {},
+              {}
+            ],
+            "set_block": [
+              {
+                "list": [
+                  {},
+                  {},
+                  {}
+                ],
+                "list_block": [],
+                "set_block": []
+              },
+              {
+                "list_block": [],
+                "set": [
+                  {},
+                  {}
+                ],
+                "set_block": []
+              },
+              {
+                "list_block": [],
+                "set_block": []
+              }
+            ]
+          },
+          "type": "tfcoremock_complex_resource",
+          "values": {
+            "bool": true,
+            "float": 123456789,
+            "id": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+            "integer": 123456789,
+            "list": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the list, and doesn't contain anything interesting"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines\nbut I've been edited"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 3,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 4,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set and I edited my test"
+              }
+            ],
+            "list_block": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":0}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":1}"
+              }
+            ],
+            "map": {
+              "key_four": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 3,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 4,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              },
+              "key_one": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the map, and doesn't contain anything interesting"
+              },
+              "key_three": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 3,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              "key_two": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+              }
+            },
+            "number": 987654321,
+            "object": {
+              "bool": null,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": 0,
+              "object": {
+                "bool": true,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "i am a nested nested object"
+              },
+              "set": null,
+              "string": "i am a nested object"
+            },
+            "set": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the set, and doesn't contain anything interesting"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+              }
+            ],
+            "set_block": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":1}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "set_block": [],
+                "string": "{\"index\":2}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":3}"
+              }
+            ],
+            "string": "a not very long or complex string"
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/apply.json b/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/apply.json
new file mode 100644
index 0000000..9e72bd8
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/apply.json
@@ -0,0 +1,79 @@
+[
+  {
+    "@level": "info",
+    "@message": "local_file.local_file: Plan to create",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "create",
+      "resource": {
+        "addr": "local_file.local_file",
+        "implied_provider": "local",
+        "module": "",
+        "resource": "local_file.local_file",
+        "resource_key": null,
+        "resource_name": "local_file",
+        "resource_type": "local_file"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "local_file.local_file: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "local_file.local_file",
+        "implied_provider": "local",
+        "module": "",
+        "resource": "local_file.local_file",
+        "resource_key": null,
+        "resource_name": "local_file",
+        "resource_type": "local_file"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "local_file.local_file: Creation complete after 0s [id=2248ee2fa0aaaad99178531f924bf00b4b0a8f4e]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "2248ee2fa0aaaad99178531f924bf00b4b0a8f4e",
+      "resource": {
+        "addr": "local_file.local_file",
+        "implied_provider": "local",
+        "module": "",
+        "resource": "local_file.local_file",
+        "resource_key": null,
+        "resource_name": "local_file",
+        "resource_type": "local_file"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/output.json b/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/output.json
new file mode 100644
index 0000000..eeedd40
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/output.json
@@ -0,0 +1,3 @@
+{
+  "hello": "world"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/plan b/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/plan
new file mode 100644
index 0000000..ab85756
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/plan
@@ -0,0 +1,28 @@
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  # local_file.local_file will be created
+  + resource "local_file" "local_file" {
+      + content              = jsonencode(
+            {
+              + hello = "world"
+            }
+        )
+      + directory_permission = "0777"
+      + file_permission      = "0777"
+      + filename             = "output.json"
+      + id                   = (known after apply)
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/plan.json b/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/plan.json
new file mode 100644
index 0000000..3cf67e8
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/plan.json
@@ -0,0 +1,90 @@
+{
+  "configuration": {
+    "provider_config": {
+      "local": {
+        "full_name": "registry.terraform.io/hashicorp/local",
+        "name": "local",
+        "version_constraint": "2.2.3"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "local_file.local_file",
+          "expressions": {
+            "content": {
+              "references": [
+                "local.contents"
+              ]
+            },
+            "filename": {
+              "constant_value": "output.json"
+            }
+          },
+          "mode": "managed",
+          "name": "local_file",
+          "provider_config_key": "local",
+          "schema_version": 0,
+          "type": "local_file"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "local_file.local_file",
+          "mode": "managed",
+          "name": "local_file",
+          "provider_name": "registry.terraform.io/hashicorp/local",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "local_file",
+          "values": {
+            "content": "{\"hello\":\"world\"}",
+            "content_base64": null,
+            "directory_permission": "0777",
+            "file_permission": "0777",
+            "filename": "output.json",
+            "sensitive_content": null,
+            "source": null
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "local_file.local_file",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "after": {
+          "content": "{\"hello\":\"world\"}",
+          "content_base64": null,
+          "directory_permission": "0777",
+          "file_permission": "0777",
+          "filename": "output.json",
+          "sensitive_content": null,
+          "source": null
+        },
+        "after_sensitive": {
+          "sensitive_content": true
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "managed",
+      "name": "local_file",
+      "provider_name": "registry.terraform.io/hashicorp/local",
+      "type": "local_file"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:31Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/state b/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/state
new file mode 100644
index 0000000..cd74916
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/state
@@ -0,0 +1,12 @@
+# local_file.local_file:
+resource "local_file" "local_file" {
+    content              = jsonencode(
+        {
+            hello = "world"
+        }
+    )
+    directory_permission = "0777"
+    file_permission      = "0777"
+    filename             = "output.json"
+    id                   = "2248ee2fa0aaaad99178531f924bf00b4b0a8f4e"
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/state.json b/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/state.json
new file mode 100644
index 0000000..7963a7a
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_basic/state.json
@@ -0,0 +1,30 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "local_file.local_file",
+          "mode": "managed",
+          "name": "local_file",
+          "provider_name": "registry.terraform.io/hashicorp/local",
+          "schema_version": 0,
+          "sensitive_values": {
+            "sensitive_content": true
+          },
+          "type": "local_file",
+          "values": {
+            "content": "{\"hello\":\"world\"}",
+            "content_base64": null,
+            "directory_permission": "0777",
+            "file_permission": "0777",
+            "filename": "output.json",
+            "id": "2248ee2fa0aaaad99178531f924bf00b4b0a8f4e",
+            "sensitive_content": null,
+            "source": null
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_delete/apply.json b/v1.5.7/testing/equivalence-tests/outputs/local_provider_delete/apply.json
new file mode 100644
index 0000000..6598d86
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_delete/apply.json
@@ -0,0 +1,80 @@
+[
+  {
+    "@level": "info",
+    "@message": "local_file.local_file: Plan to delete",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "delete",
+      "reason": "delete_because_no_resource_config",
+      "resource": {
+        "addr": "local_file.local_file",
+        "implied_provider": "local",
+        "module": "",
+        "resource": "local_file.local_file",
+        "resource_key": null,
+        "resource_name": "local_file",
+        "resource_type": "local_file"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "local_file.local_file: Destroying... [id=2248ee2fa0aaaad99178531f924bf00b4b0a8f4e]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "id_key": "id",
+      "id_value": "2248ee2fa0aaaad99178531f924bf00b4b0a8f4e",
+      "resource": {
+        "addr": "local_file.local_file",
+        "implied_provider": "local",
+        "module": "",
+        "resource": "local_file.local_file",
+        "resource_key": null,
+        "resource_name": "local_file",
+        "resource_type": "local_file"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "local_file.local_file: Destruction complete after 0s",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "elapsed_seconds": 0,
+      "resource": {
+        "addr": "local_file.local_file",
+        "implied_provider": "local",
+        "module": "",
+        "resource": "local_file.local_file",
+        "resource_key": null,
+        "resource_name": "local_file",
+        "resource_type": "local_file"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 0 changed, 1 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 1
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_delete/plan b/v1.5.7/testing/equivalence-tests/outputs/local_provider_delete/plan
new file mode 100644
index 0000000..dedcf5c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_delete/plan
@@ -0,0 +1,30 @@
+local_file.local_file: Refreshing state... [id=2248ee2fa0aaaad99178531f924bf00b4b0a8f4e]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  - destroy
+
+Terraform will perform the following actions:
+
+  # local_file.local_file will be destroyed
+  # (because local_file.local_file is not in configuration)
+  - resource "local_file" "local_file" {
+      - content              = jsonencode(
+            {
+              - hello = "world"
+            }
+        ) -> null
+      - directory_permission = "0777" -> null
+      - file_permission      = "0777" -> null
+      - filename             = "output.json" -> null
+      - id                   = "2248ee2fa0aaaad99178531f924bf00b4b0a8f4e" -> null
+    }
+
+Plan: 0 to add, 0 to change, 1 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_delete/plan.json b/v1.5.7/testing/equivalence-tests/outputs/local_provider_delete/plan.json
new file mode 100644
index 0000000..992ee2c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_delete/plan.json
@@ -0,0 +1,78 @@
+{
+  "configuration": {
+    "provider_config": {
+      "local": {
+        "full_name": "registry.terraform.io/hashicorp/local",
+        "name": "local",
+        "version_constraint": "2.2.3"
+      }
+    },
+    "root_module": {}
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {}
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "local_file.local_file",
+            "mode": "managed",
+            "name": "local_file",
+            "provider_name": "registry.terraform.io/hashicorp/local",
+            "schema_version": 0,
+            "sensitive_values": {
+              "sensitive_content": true
+            },
+            "type": "local_file",
+            "values": {
+              "content": "{\"hello\":\"world\"}",
+              "content_base64": null,
+              "directory_permission": "0777",
+              "file_permission": "0777",
+              "filename": "output.json",
+              "id": "2248ee2fa0aaaad99178531f924bf00b4b0a8f4e",
+              "sensitive_content": null,
+              "source": null
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "action_reason": "delete_because_no_resource_config",
+      "address": "local_file.local_file",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "after": null,
+        "after_sensitive": false,
+        "after_unknown": {},
+        "before": {
+          "content": "{\"hello\":\"world\"}",
+          "content_base64": null,
+          "directory_permission": "0777",
+          "file_permission": "0777",
+          "filename": "output.json",
+          "id": "2248ee2fa0aaaad99178531f924bf00b4b0a8f4e",
+          "sensitive_content": null,
+          "source": null
+        },
+        "before_sensitive": {
+          "sensitive_content": true
+        }
+      },
+      "mode": "managed",
+      "name": "local_file",
+      "provider_name": "registry.terraform.io/hashicorp/local",
+      "type": "local_file"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:33Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_delete/state b/v1.5.7/testing/equivalence-tests/outputs/local_provider_delete/state
new file mode 100644
index 0000000..222a60b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_delete/state
@@ -0,0 +1 @@
+The state file is empty. No resources are represented.
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_delete/state.json b/v1.5.7/testing/equivalence-tests/outputs/local_provider_delete/state.json
new file mode 100644
index 0000000..00f8f1c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_delete/state.json
@@ -0,0 +1,3 @@
+{
+  "format_version": "1.0"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/apply.json b/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/apply.json
new file mode 100644
index 0000000..3adabc7
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/apply.json
@@ -0,0 +1,119 @@
+[
+  {
+    "@level": "info",
+    "@message": "local_file.local_file: Plan to replace",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "replace",
+      "reason": "cannot_update",
+      "resource": {
+        "addr": "local_file.local_file",
+        "implied_provider": "local",
+        "module": "",
+        "resource": "local_file.local_file",
+        "resource_key": null,
+        "resource_name": "local_file",
+        "resource_type": "local_file"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "local_file.local_file: Destroying... [id=2248ee2fa0aaaad99178531f924bf00b4b0a8f4e]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "id_key": "id",
+      "id_value": "2248ee2fa0aaaad99178531f924bf00b4b0a8f4e",
+      "resource": {
+        "addr": "local_file.local_file",
+        "implied_provider": "local",
+        "module": "",
+        "resource": "local_file.local_file",
+        "resource_key": null,
+        "resource_name": "local_file",
+        "resource_type": "local_file"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "local_file.local_file: Destruction complete after 0s",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "elapsed_seconds": 0,
+      "resource": {
+        "addr": "local_file.local_file",
+        "implied_provider": "local",
+        "module": "",
+        "resource": "local_file.local_file",
+        "resource_key": null,
+        "resource_name": "local_file",
+        "resource_type": "local_file"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "local_file.local_file: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "local_file.local_file",
+        "implied_provider": "local",
+        "module": "",
+        "resource": "local_file.local_file",
+        "resource_key": null,
+        "resource_name": "local_file",
+        "resource_type": "local_file"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "local_file.local_file: Creation complete after 0s [id=648a5452054fca119f95b07f9ea992cc6d9681df]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "648a5452054fca119f95b07f9ea992cc6d9681df",
+      "resource": {
+        "addr": "local_file.local_file",
+        "implied_provider": "local",
+        "module": "",
+        "resource": "local_file.local_file",
+        "resource_key": null,
+        "resource_name": "local_file",
+        "resource_type": "local_file"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 1 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 1
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/output.json b/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/output.json
new file mode 100644
index 0000000..9eab206
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/output.json
@@ -0,0 +1,3 @@
+{
+  "goodbye": "world"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/plan b/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/plan
new file mode 100644
index 0000000..6cadae4
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/plan
@@ -0,0 +1,28 @@
+local_file.local_file: Refreshing state... [id=2248ee2fa0aaaad99178531f924bf00b4b0a8f4e]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+-/+ destroy and then create replacement
+
+Terraform will perform the following actions:
+
+  # local_file.local_file must be replaced
+-/+ resource "local_file" "local_file" {
+      ~ content              = jsonencode(
+          ~ {
+              + goodbye = "world"
+              - hello   = "world"
+            } # forces replacement
+        )
+      ~ id                   = "2248ee2fa0aaaad99178531f924bf00b4b0a8f4e" -> (known after apply)
+        # (3 unchanged attributes hidden)
+    }
+
+Plan: 1 to add, 0 to change, 1 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/plan.json b/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/plan.json
new file mode 100644
index 0000000..c1d6c8c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/plan.json
@@ -0,0 +1,138 @@
+{
+  "configuration": {
+    "provider_config": {
+      "local": {
+        "full_name": "registry.terraform.io/hashicorp/local",
+        "name": "local",
+        "version_constraint": "2.2.3"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "local_file.local_file",
+          "expressions": {
+            "content": {
+              "references": [
+                "local.contents"
+              ]
+            },
+            "filename": {
+              "constant_value": "output.json"
+            }
+          },
+          "mode": "managed",
+          "name": "local_file",
+          "provider_config_key": "local",
+          "schema_version": 0,
+          "type": "local_file"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "local_file.local_file",
+          "mode": "managed",
+          "name": "local_file",
+          "provider_name": "registry.terraform.io/hashicorp/local",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "local_file",
+          "values": {
+            "content": "{\"goodbye\":\"world\"}",
+            "content_base64": null,
+            "directory_permission": "0777",
+            "file_permission": "0777",
+            "filename": "output.json",
+            "sensitive_content": null,
+            "source": null
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "local_file.local_file",
+            "mode": "managed",
+            "name": "local_file",
+            "provider_name": "registry.terraform.io/hashicorp/local",
+            "schema_version": 0,
+            "sensitive_values": {
+              "sensitive_content": true
+            },
+            "type": "local_file",
+            "values": {
+              "content": "{\"hello\":\"world\"}",
+              "content_base64": null,
+              "directory_permission": "0777",
+              "file_permission": "0777",
+              "filename": "output.json",
+              "id": "2248ee2fa0aaaad99178531f924bf00b4b0a8f4e",
+              "sensitive_content": null,
+              "source": null
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "action_reason": "replace_because_cannot_update",
+      "address": "local_file.local_file",
+      "change": {
+        "actions": [
+          "delete",
+          "create"
+        ],
+        "after": {
+          "content": "{\"goodbye\":\"world\"}",
+          "content_base64": null,
+          "directory_permission": "0777",
+          "file_permission": "0777",
+          "filename": "output.json",
+          "sensitive_content": null,
+          "source": null
+        },
+        "after_sensitive": {
+          "sensitive_content": true
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before": {
+          "content": "{\"hello\":\"world\"}",
+          "content_base64": null,
+          "directory_permission": "0777",
+          "file_permission": "0777",
+          "filename": "output.json",
+          "id": "2248ee2fa0aaaad99178531f924bf00b4b0a8f4e",
+          "sensitive_content": null,
+          "source": null
+        },
+        "before_sensitive": {
+          "sensitive_content": true
+        },
+        "replace_paths": [
+          [
+            "content"
+          ]
+        ]
+      },
+      "mode": "managed",
+      "name": "local_file",
+      "provider_name": "registry.terraform.io/hashicorp/local",
+      "type": "local_file"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:35Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/state b/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/state
new file mode 100644
index 0000000..4f14ea5
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/state
@@ -0,0 +1,12 @@
+# local_file.local_file:
+resource "local_file" "local_file" {
+    content              = jsonencode(
+        {
+            goodbye = "world"
+        }
+    )
+    directory_permission = "0777"
+    file_permission      = "0777"
+    filename             = "output.json"
+    id                   = "648a5452054fca119f95b07f9ea992cc6d9681df"
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/state.json b/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/state.json
new file mode 100644
index 0000000..e8c649c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/local_provider_update/state.json
@@ -0,0 +1,30 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "local_file.local_file",
+          "mode": "managed",
+          "name": "local_file",
+          "provider_name": "registry.terraform.io/hashicorp/local",
+          "schema_version": 0,
+          "sensitive_values": {
+            "sensitive_content": true
+          },
+          "type": "local_file",
+          "values": {
+            "content": "{\"goodbye\":\"world\"}",
+            "content_base64": null,
+            "directory_permission": "0777",
+            "file_permission": "0777",
+            "filename": "output.json",
+            "id": "648a5452054fca119f95b07f9ea992cc6d9681df",
+            "sensitive_content": null,
+            "source": null
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_simple/apply.json b/v1.5.7/testing/equivalence-tests/outputs/moved_simple/apply.json
new file mode 100644
index 0000000..42438bd
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_simple/apply.json
@@ -0,0 +1,22 @@
+[
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_simple/plan b/v1.5.7/testing/equivalence-tests/outputs/moved_simple/plan
new file mode 100644
index 0000000..083308b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_simple/plan
@@ -0,0 +1,18 @@
+tfcoremock_simple_resource.second: Refreshing state... [id=70c47571-66c3-b1dc-2474-47a74b9c7886]
+
+Terraform will perform the following actions:
+
+  # tfcoremock_simple_resource.first has moved to tfcoremock_simple_resource.second
+    resource "tfcoremock_simple_resource" "second" {
+        id     = "70c47571-66c3-b1dc-2474-47a74b9c7886"
+        # (1 unchanged attribute hidden)
+    }
+
+Plan: 0 to add, 0 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_simple/plan.json b/v1.5.7/testing/equivalence-tests/outputs/moved_simple/plan.json
new file mode 100644
index 0000000..a816dc8
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_simple/plan.json
@@ -0,0 +1,113 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.second",
+          "expressions": {
+            "string": {
+              "constant_value": "Hello, world!"
+            }
+          },
+          "mode": "managed",
+          "name": "second",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_simple_resource"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.second",
+          "mode": "managed",
+          "name": "second",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "70c47571-66c3-b1dc-2474-47a74b9c7886",
+            "integer": null,
+            "number": null,
+            "string": "Hello, world!"
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_simple_resource.second",
+            "mode": "managed",
+            "name": "second",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {},
+            "type": "tfcoremock_simple_resource",
+            "values": {
+              "bool": null,
+              "float": null,
+              "id": "70c47571-66c3-b1dc-2474-47a74b9c7886",
+              "integer": null,
+              "number": null,
+              "string": "Hello, world!"
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_simple_resource.second",
+      "change": {
+        "actions": [
+          "no-op"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "id": "70c47571-66c3-b1dc-2474-47a74b9c7886",
+          "integer": null,
+          "number": null,
+          "string": "Hello, world!"
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "bool": null,
+          "float": null,
+          "id": "70c47571-66c3-b1dc-2474-47a74b9c7886",
+          "integer": null,
+          "number": null,
+          "string": "Hello, world!"
+        },
+        "before_sensitive": {}
+      },
+      "mode": "managed",
+      "name": "second",
+      "previous_address": "tfcoremock_simple_resource.first",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:37Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_simple/state b/v1.5.7/testing/equivalence-tests/outputs/moved_simple/state
new file mode 100644
index 0000000..f336bbe
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_simple/state
@@ -0,0 +1,5 @@
+# tfcoremock_simple_resource.second:
+resource "tfcoremock_simple_resource" "second" {
+    id     = "70c47571-66c3-b1dc-2474-47a74b9c7886"
+    string = "Hello, world!"
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_simple/state.json b/v1.5.7/testing/equivalence-tests/outputs/moved_simple/state.json
new file mode 100644
index 0000000..84cdbee
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_simple/state.json
@@ -0,0 +1,26 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.second",
+          "mode": "managed",
+          "name": "second",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "70c47571-66c3-b1dc-2474-47a74b9c7886",
+            "integer": null,
+            "number": null,
+            "string": "Hello, world!"
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_with_drift/apply.json b/v1.5.7/testing/equivalence-tests/outputs/moved_with_drift/apply.json
new file mode 100644
index 0000000..272591e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_with_drift/apply.json
@@ -0,0 +1,149 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.base_after: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "previous_resource": {
+        "addr": "tfcoremock_simple_resource.base_before",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.base_before",
+        "resource_key": null,
+        "resource_name": "base_before",
+        "resource_type": "tfcoremock_simple_resource"
+      },
+      "resource": {
+        "addr": "tfcoremock_simple_resource.base_after",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.base_after",
+        "resource_key": null,
+        "resource_name": "base_after",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.dependent: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.dependent",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.dependent",
+        "resource_key": null,
+        "resource_name": "dependent",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.base_after: Modifying... [id=e450ef2f-b80f-0cce-8bdb-14d88f48649c]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "e450ef2f-b80f-0cce-8bdb-14d88f48649c",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.base_after",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.base_after",
+        "resource_key": null,
+        "resource_name": "base_after",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.base_after: Modifications complete after 0s [id=e450ef2f-b80f-0cce-8bdb-14d88f48649c]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "e450ef2f-b80f-0cce-8bdb-14d88f48649c",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.base_after",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.base_after",
+        "resource_key": null,
+        "resource_name": "base_after",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.dependent: Modifying... [id=2ecc718c-8d04-5774-5c36-7d69bf77d34e]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "2ecc718c-8d04-5774-5c36-7d69bf77d34e",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.dependent",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.dependent",
+        "resource_key": null,
+        "resource_name": "dependent",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.dependent: Modifications complete after 0s [id=2ecc718c-8d04-5774-5c36-7d69bf77d34e]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "2ecc718c-8d04-5774-5c36-7d69bf77d34e",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.dependent",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.dependent",
+        "resource_key": null,
+        "resource_name": "dependent",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 2 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 2,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_with_drift/plan b/v1.5.7/testing/equivalence-tests/outputs/moved_with_drift/plan
new file mode 100644
index 0000000..0293566
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_with_drift/plan
@@ -0,0 +1,49 @@
+tfcoremock_simple_resource.base_after: Refreshing state... [id=e450ef2f-b80f-0cce-8bdb-14d88f48649c]
+tfcoremock_simple_resource.dependent: Refreshing state... [id=2ecc718c-8d04-5774-5c36-7d69bf77d34e]
+
+Note: Objects have changed outside of Terraform
+
+Terraform detected the following changes made outside of Terraform since the
+last "terraform apply" which may have affected this plan:
+
+  # tfcoremock_simple_resource.base_after has changed
+  # (moved from tfcoremock_simple_resource.base_before)
+  ~ resource "tfcoremock_simple_resource" "base_after" {
+        id     = "e450ef2f-b80f-0cce-8bdb-14d88f48649c"
+      ~ string = "Hello, world!" -> "Hello, drift!"
+    }
+
+
+Unless you have made equivalent changes to your configuration, or ignored the
+relevant attributes using ignore_changes, the following plan may include
+actions to undo or respond to these changes.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_simple_resource.base_after will be updated in-place
+  # (moved from tfcoremock_simple_resource.base_before)
+  ~ resource "tfcoremock_simple_resource" "base_after" {
+        id     = "e450ef2f-b80f-0cce-8bdb-14d88f48649c"
+      ~ string = "Hello, drift!" -> "Hello, change!"
+    }
+
+  # tfcoremock_simple_resource.dependent will be updated in-place
+  ~ resource "tfcoremock_simple_resource" "dependent" {
+        id     = "2ecc718c-8d04-5774-5c36-7d69bf77d34e"
+      ~ string = "Hello, world!" -> "Hello, change!"
+    }
+
+Plan: 0 to add, 2 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_with_drift/plan.json b/v1.5.7/testing/equivalence-tests/outputs/moved_with_drift/plan.json
new file mode 100644
index 0000000..f5a86c9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_with_drift/plan.json
@@ -0,0 +1,240 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.base_after",
+          "expressions": {
+            "string": {
+              "constant_value": "Hello, change!"
+            }
+          },
+          "mode": "managed",
+          "name": "base_after",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_simple_resource"
+        },
+        {
+          "address": "tfcoremock_simple_resource.dependent",
+          "expressions": {
+            "string": {
+              "references": [
+                "tfcoremock_simple_resource.base_after.string",
+                "tfcoremock_simple_resource.base_after"
+              ]
+            }
+          },
+          "mode": "managed",
+          "name": "dependent",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_simple_resource"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.base_after",
+          "mode": "managed",
+          "name": "base_after",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "e450ef2f-b80f-0cce-8bdb-14d88f48649c",
+            "integer": null,
+            "number": null,
+            "string": "Hello, change!"
+          }
+        },
+        {
+          "address": "tfcoremock_simple_resource.dependent",
+          "mode": "managed",
+          "name": "dependent",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "2ecc718c-8d04-5774-5c36-7d69bf77d34e",
+            "integer": null,
+            "number": null,
+            "string": "Hello, change!"
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_simple_resource.base_after",
+            "mode": "managed",
+            "name": "base_after",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {},
+            "type": "tfcoremock_simple_resource",
+            "values": {
+              "bool": null,
+              "float": null,
+              "id": "e450ef2f-b80f-0cce-8bdb-14d88f48649c",
+              "integer": null,
+              "number": null,
+              "string": "Hello, drift!"
+            }
+          },
+          {
+            "address": "tfcoremock_simple_resource.dependent",
+            "depends_on": [
+              "tfcoremock_simple_resource.base_after",
+              "tfcoremock_simple_resource.base_before"
+            ],
+            "mode": "managed",
+            "name": "dependent",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {},
+            "type": "tfcoremock_simple_resource",
+            "values": {
+              "bool": null,
+              "float": null,
+              "id": "2ecc718c-8d04-5774-5c36-7d69bf77d34e",
+              "integer": null,
+              "number": null,
+              "string": "Hello, world!"
+            }
+          }
+        ]
+      }
+    }
+  },
+  "relevant_attributes": [
+    {
+      "attribute": [
+        "string"
+      ],
+      "resource": "tfcoremock_simple_resource.base_after"
+    }
+  ],
+  "resource_changes": [
+    {
+      "address": "tfcoremock_simple_resource.base_after",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "id": "e450ef2f-b80f-0cce-8bdb-14d88f48649c",
+          "integer": null,
+          "number": null,
+          "string": "Hello, change!"
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "bool": null,
+          "float": null,
+          "id": "e450ef2f-b80f-0cce-8bdb-14d88f48649c",
+          "integer": null,
+          "number": null,
+          "string": "Hello, drift!"
+        },
+        "before_sensitive": {}
+      },
+      "mode": "managed",
+      "name": "base_after",
+      "previous_address": "tfcoremock_simple_resource.base_before",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    },
+    {
+      "address": "tfcoremock_simple_resource.dependent",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "id": "2ecc718c-8d04-5774-5c36-7d69bf77d34e",
+          "integer": null,
+          "number": null,
+          "string": "Hello, change!"
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "bool": null,
+          "float": null,
+          "id": "2ecc718c-8d04-5774-5c36-7d69bf77d34e",
+          "integer": null,
+          "number": null,
+          "string": "Hello, world!"
+        },
+        "before_sensitive": {}
+      },
+      "mode": "managed",
+      "name": "dependent",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    }
+  ],
+  "resource_drift": [
+    {
+      "address": "tfcoremock_simple_resource.base_after",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "id": "e450ef2f-b80f-0cce-8bdb-14d88f48649c",
+          "integer": null,
+          "number": null,
+          "string": "Hello, drift!"
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "bool": null,
+          "float": null,
+          "id": "e450ef2f-b80f-0cce-8bdb-14d88f48649c",
+          "integer": null,
+          "number": null,
+          "string": "Hello, world!"
+        },
+        "before_sensitive": {}
+      },
+      "mode": "managed",
+      "name": "base_after",
+      "previous_address": "tfcoremock_simple_resource.base_before",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:39Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_with_drift/state b/v1.5.7/testing/equivalence-tests/outputs/moved_with_drift/state
new file mode 100644
index 0000000..0ad1268
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_with_drift/state
@@ -0,0 +1,11 @@
+# tfcoremock_simple_resource.base_after:
+resource "tfcoremock_simple_resource" "base_after" {
+    id     = "e450ef2f-b80f-0cce-8bdb-14d88f48649c"
+    string = "Hello, change!"
+}
+
+# tfcoremock_simple_resource.dependent:
+resource "tfcoremock_simple_resource" "dependent" {
+    id     = "2ecc718c-8d04-5774-5c36-7d69bf77d34e"
+    string = "Hello, change!"
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_with_drift/state.json b/v1.5.7/testing/equivalence-tests/outputs/moved_with_drift/state.json
new file mode 100644
index 0000000..e1303be
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_with_drift/state.json
@@ -0,0 +1,46 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.base_after",
+          "mode": "managed",
+          "name": "base_after",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "e450ef2f-b80f-0cce-8bdb-14d88f48649c",
+            "integer": null,
+            "number": null,
+            "string": "Hello, change!"
+          }
+        },
+        {
+          "address": "tfcoremock_simple_resource.dependent",
+          "depends_on": [
+            "tfcoremock_simple_resource.base_after"
+          ],
+          "mode": "managed",
+          "name": "dependent",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "2ecc718c-8d04-5774-5c36-7d69bf77d34e",
+            "integer": null,
+            "number": null,
+            "string": "Hello, change!"
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_with_refresh_only/apply.json b/v1.5.7/testing/equivalence-tests/outputs/moved_with_refresh_only/apply.json
new file mode 100644
index 0000000..42438bd
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_with_refresh_only/apply.json
@@ -0,0 +1,22 @@
+[
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_with_refresh_only/plan b/v1.5.7/testing/equivalence-tests/outputs/moved_with_refresh_only/plan
new file mode 100644
index 0000000..441ec49
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_with_refresh_only/plan
@@ -0,0 +1,18 @@
+tfcoremock_simple_resource.second: Refreshing state... [id=70c47571-66c3-b1dc-2474-47a74b9c7886]
+
+Note: Objects have changed outside of Terraform
+
+Terraform detected the following changes made outside of Terraform since the
+last "terraform apply" which may have affected this plan:
+
+  # tfcoremock_simple_resource.first has moved to tfcoremock_simple_resource.second
+    resource "tfcoremock_simple_resource" "second" {
+        id     = "70c47571-66c3-b1dc-2474-47a74b9c7886"
+        # (1 unchanged attribute hidden)
+    }
+
+
+This is a refresh-only plan, so Terraform will not take any actions to undo
+these. If you were expecting these changes then you can apply this plan to
+record the updated values in the Terraform state without changing any remote
+objects.
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_with_refresh_only/plan.json b/v1.5.7/testing/equivalence-tests/outputs/moved_with_refresh_only/plan.json
new file mode 100644
index 0000000..4bfb1d0
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_with_refresh_only/plan.json
@@ -0,0 +1,93 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.second",
+          "expressions": {
+            "string": {
+              "constant_value": "Hello, world!"
+            }
+          },
+          "mode": "managed",
+          "name": "second",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_simple_resource"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {}
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_simple_resource.second",
+            "mode": "managed",
+            "name": "second",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {},
+            "type": "tfcoremock_simple_resource",
+            "values": {
+              "bool": null,
+              "float": null,
+              "id": "70c47571-66c3-b1dc-2474-47a74b9c7886",
+              "integer": null,
+              "number": null,
+              "string": "Hello, world!"
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_drift": [
+    {
+      "address": "tfcoremock_simple_resource.second",
+      "change": {
+        "actions": [
+          "no-op"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "id": "70c47571-66c3-b1dc-2474-47a74b9c7886",
+          "integer": null,
+          "number": null,
+          "string": "Hello, world!"
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "bool": null,
+          "float": null,
+          "id": "70c47571-66c3-b1dc-2474-47a74b9c7886",
+          "integer": null,
+          "number": null,
+          "string": "Hello, world!"
+        },
+        "before_sensitive": {}
+      },
+      "mode": "managed",
+      "name": "second",
+      "previous_address": "tfcoremock_simple_resource.first",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:41Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_with_refresh_only/state.json b/v1.5.7/testing/equivalence-tests/outputs/moved_with_refresh_only/state.json
new file mode 100644
index 0000000..84cdbee
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_with_refresh_only/state.json
@@ -0,0 +1,26 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.second",
+          "mode": "managed",
+          "name": "second",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "70c47571-66c3-b1dc-2474-47a74b9c7886",
+            "integer": null,
+            "number": null,
+            "string": "Hello, world!"
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_with_update/apply.json b/v1.5.7/testing/equivalence-tests/outputs/moved_with_update/apply.json
new file mode 100644
index 0000000..fd673b3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_with_update/apply.json
@@ -0,0 +1,90 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.moved: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "previous_resource": {
+        "addr": "tfcoremock_simple_resource.base",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.base",
+        "resource_key": null,
+        "resource_name": "base",
+        "resource_type": "tfcoremock_simple_resource"
+      },
+      "resource": {
+        "addr": "tfcoremock_simple_resource.moved",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.moved",
+        "resource_key": null,
+        "resource_name": "moved",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.moved: Modifying... [id=7da63aeb-f908-a112-9886-f29a0b0bd4ad]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "7da63aeb-f908-a112-9886-f29a0b0bd4ad",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.moved",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.moved",
+        "resource_key": null,
+        "resource_name": "moved",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_simple_resource.moved: Modifications complete after 0s [id=7da63aeb-f908-a112-9886-f29a0b0bd4ad]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "7da63aeb-f908-a112-9886-f29a0b0bd4ad",
+      "resource": {
+        "addr": "tfcoremock_simple_resource.moved",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_simple_resource.moved",
+        "resource_key": null,
+        "resource_name": "moved",
+        "resource_type": "tfcoremock_simple_resource"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_with_update/plan b/v1.5.7/testing/equivalence-tests/outputs/moved_with_update/plan
new file mode 100644
index 0000000..eab1737
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_with_update/plan
@@ -0,0 +1,23 @@
+tfcoremock_simple_resource.moved: Refreshing state... [id=7da63aeb-f908-a112-9886-f29a0b0bd4ad]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_simple_resource.moved will be updated in-place
+  # (moved from tfcoremock_simple_resource.base)
+  ~ resource "tfcoremock_simple_resource" "moved" {
+        id     = "7da63aeb-f908-a112-9886-f29a0b0bd4ad"
+      ~ string = "Hello, world!" -> "Hello, change!"
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_with_update/plan.json b/v1.5.7/testing/equivalence-tests/outputs/moved_with_update/plan.json
new file mode 100644
index 0000000..c1471c5
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_with_update/plan.json
@@ -0,0 +1,113 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.moved",
+          "expressions": {
+            "string": {
+              "constant_value": "Hello, change!"
+            }
+          },
+          "mode": "managed",
+          "name": "moved",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_simple_resource"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.moved",
+          "mode": "managed",
+          "name": "moved",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "7da63aeb-f908-a112-9886-f29a0b0bd4ad",
+            "integer": null,
+            "number": null,
+            "string": "Hello, change!"
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_simple_resource.moved",
+            "mode": "managed",
+            "name": "moved",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {},
+            "type": "tfcoremock_simple_resource",
+            "values": {
+              "bool": null,
+              "float": null,
+              "id": "7da63aeb-f908-a112-9886-f29a0b0bd4ad",
+              "integer": null,
+              "number": null,
+              "string": "Hello, world!"
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_simple_resource.moved",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "bool": null,
+          "float": null,
+          "id": "7da63aeb-f908-a112-9886-f29a0b0bd4ad",
+          "integer": null,
+          "number": null,
+          "string": "Hello, change!"
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "bool": null,
+          "float": null,
+          "id": "7da63aeb-f908-a112-9886-f29a0b0bd4ad",
+          "integer": null,
+          "number": null,
+          "string": "Hello, world!"
+        },
+        "before_sensitive": {}
+      },
+      "mode": "managed",
+      "name": "moved",
+      "previous_address": "tfcoremock_simple_resource.base",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_simple_resource"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:43Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_with_update/state b/v1.5.7/testing/equivalence-tests/outputs/moved_with_update/state
new file mode 100644
index 0000000..5394de2
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_with_update/state
@@ -0,0 +1,5 @@
+# tfcoremock_simple_resource.moved:
+resource "tfcoremock_simple_resource" "moved" {
+    id     = "7da63aeb-f908-a112-9886-f29a0b0bd4ad"
+    string = "Hello, change!"
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/moved_with_update/state.json b/v1.5.7/testing/equivalence-tests/outputs/moved_with_update/state.json
new file mode 100644
index 0000000..406616c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/moved_with_update/state.json
@@ -0,0 +1,26 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_simple_resource.moved",
+          "mode": "managed",
+          "name": "moved",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_simple_resource",
+          "values": {
+            "bool": null,
+            "float": null,
+            "id": "7da63aeb-f908-a112-9886-f29a0b0bd4ad",
+            "integer": null,
+            "number": null,
+            "string": "Hello, change!"
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types/apply.json b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types/apply.json
new file mode 100644
index 0000000..bfec2a1
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types/apply.json
@@ -0,0 +1,79 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_multiple_blocks.multiple_blocks: Plan to create",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_multiple_blocks.multiple_blocks",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_multiple_blocks.multiple_blocks",
+        "resource_key": null,
+        "resource_name": "multiple_blocks",
+        "resource_type": "tfcoremock_multiple_blocks"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_multiple_blocks.multiple_blocks: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_multiple_blocks.multiple_blocks",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_multiple_blocks.multiple_blocks",
+        "resource_key": null,
+        "resource_name": "multiple_blocks",
+        "resource_type": "tfcoremock_multiple_blocks"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_multiple_blocks.multiple_blocks: Creation complete after 0s [id=DA051126-BAD6-4EB2-92E5-F0250DAF0B92]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+      "resource": {
+        "addr": "tfcoremock_multiple_blocks.multiple_blocks",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_multiple_blocks.multiple_blocks",
+        "resource_key": null,
+        "resource_name": "multiple_blocks",
+        "resource_type": "tfcoremock_multiple_blocks"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types/plan b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types/plan
new file mode 100644
index 0000000..4d8be6b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types/plan
@@ -0,0 +1,37 @@
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  # tfcoremock_multiple_blocks.multiple_blocks will be created
+  + resource "tfcoremock_multiple_blocks" "multiple_blocks" {
+      + id = "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+
+      + first_block {
+          + id = "D35E88DA-BC3B-46D7-9E0B-4ED4582FA65A"
+        }
+      + first_block {
+          + id = "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+        }
+      + first_block {
+          + id = "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+        }
+
+      + second_block {
+          + id = "157660A9-D590-469E-BE28-83B8526428CA"
+        }
+      + second_block {
+          + id = "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+        }
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types/plan.json b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types/plan.json
new file mode 100644
index 0000000..8125a81
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types/plan.json
@@ -0,0 +1,156 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_multiple_blocks.multiple_blocks",
+          "expressions": {
+            "first_block": [
+              {
+                "id": {
+                  "constant_value": "D35E88DA-BC3B-46D7-9E0B-4ED4582FA65A"
+                }
+              },
+              {
+                "id": {
+                  "constant_value": "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+                }
+              },
+              {
+                "id": {
+                  "constant_value": "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+                }
+              }
+            ],
+            "id": {
+              "constant_value": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+            },
+            "second_block": [
+              {
+                "id": {
+                  "constant_value": "157660A9-D590-469E-BE28-83B8526428CA"
+                }
+              },
+              {
+                "id": {
+                  "constant_value": "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+                }
+              }
+            ]
+          },
+          "mode": "managed",
+          "name": "multiple_blocks",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_multiple_blocks"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_multiple_blocks.multiple_blocks",
+          "mode": "managed",
+          "name": "multiple_blocks",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "first_block": [
+              {},
+              {},
+              {}
+            ],
+            "second_block": [
+              {},
+              {}
+            ]
+          },
+          "type": "tfcoremock_multiple_blocks",
+          "values": {
+            "first_block": [
+              {
+                "id": "D35E88DA-BC3B-46D7-9E0B-4ED4582FA65A"
+              },
+              {
+                "id": "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+              },
+              {
+                "id": "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+              }
+            ],
+            "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+            "second_block": [
+              {
+                "id": "157660A9-D590-469E-BE28-83B8526428CA"
+              },
+              {
+                "id": "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+              }
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_multiple_blocks.multiple_blocks",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "after": {
+          "first_block": [
+            {
+              "id": "D35E88DA-BC3B-46D7-9E0B-4ED4582FA65A"
+            },
+            {
+              "id": "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+            },
+            {
+              "id": "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+            }
+          ],
+          "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+          "second_block": [
+            {
+              "id": "157660A9-D590-469E-BE28-83B8526428CA"
+            },
+            {
+              "id": "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+            }
+          ]
+        },
+        "after_sensitive": {
+          "first_block": [
+            {},
+            {},
+            {}
+          ],
+          "second_block": [
+            {},
+            {}
+          ]
+        },
+        "after_unknown": {},
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "managed",
+      "name": "multiple_blocks",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_multiple_blocks"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:44Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types/state b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types/state
new file mode 100644
index 0000000..e09b6e9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types/state
@@ -0,0 +1,21 @@
+# tfcoremock_multiple_blocks.multiple_blocks:
+resource "tfcoremock_multiple_blocks" "multiple_blocks" {
+    id = "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+
+    first_block {
+        id = "D35E88DA-BC3B-46D7-9E0B-4ED4582FA65A"
+    }
+    first_block {
+        id = "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+    }
+    first_block {
+        id = "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+    }
+
+    second_block {
+        id = "157660A9-D590-469E-BE28-83B8526428CA"
+    }
+    second_block {
+        id = "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types/state.json b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types/state.json
new file mode 100644
index 0000000..c3cc241
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types/state.json
@@ -0,0 +1,50 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_multiple_blocks.multiple_blocks",
+          "mode": "managed",
+          "name": "multiple_blocks",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "first_block": [
+              {},
+              {},
+              {}
+            ],
+            "second_block": [
+              {},
+              {}
+            ]
+          },
+          "type": "tfcoremock_multiple_blocks",
+          "values": {
+            "first_block": [
+              {
+                "id": "D35E88DA-BC3B-46D7-9E0B-4ED4582FA65A"
+              },
+              {
+                "id": "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+              },
+              {
+                "id": "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+              }
+            ],
+            "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+            "second_block": [
+              {
+                "id": "157660A9-D590-469E-BE28-83B8526428CA"
+              },
+              {
+                "id": "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+              }
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types_update/apply.json b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types_update/apply.json
new file mode 100644
index 0000000..ed9b3a9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types_update/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_multiple_blocks.multiple_blocks: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_multiple_blocks.multiple_blocks",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_multiple_blocks.multiple_blocks",
+        "resource_key": null,
+        "resource_name": "multiple_blocks",
+        "resource_type": "tfcoremock_multiple_blocks"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_multiple_blocks.multiple_blocks: Modifying... [id=DA051126-BAD6-4EB2-92E5-F0250DAF0B92]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+      "resource": {
+        "addr": "tfcoremock_multiple_blocks.multiple_blocks",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_multiple_blocks.multiple_blocks",
+        "resource_key": null,
+        "resource_name": "multiple_blocks",
+        "resource_type": "tfcoremock_multiple_blocks"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_multiple_blocks.multiple_blocks: Modifications complete after 0s [id=DA051126-BAD6-4EB2-92E5-F0250DAF0B92]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+      "resource": {
+        "addr": "tfcoremock_multiple_blocks.multiple_blocks",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_multiple_blocks.multiple_blocks",
+        "resource_key": null,
+        "resource_name": "multiple_blocks",
+        "resource_type": "tfcoremock_multiple_blocks"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types_update/plan b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types_update/plan
new file mode 100644
index 0000000..f65e01a
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types_update/plan
@@ -0,0 +1,31 @@
+tfcoremock_multiple_blocks.multiple_blocks: Refreshing state... [id=DA051126-BAD6-4EB2-92E5-F0250DAF0B92]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_multiple_blocks.multiple_blocks will be updated in-place
+  ~ resource "tfcoremock_multiple_blocks" "multiple_blocks" {
+        id = "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+
+      ~ first_block {
+          ~ id = "D35E88DA-BC3B-46D7-9E0B-4ED4582FA65A" -> "B27FB8BE-52D4-4CEB-ACE9-5E7FB3968F2B"
+        }
+
+      ~ second_block {
+          ~ id = "157660A9-D590-469E-BE28-83B8526428CA" -> "91640A80-A65F-4BEF-925B-684E4517A04D"
+        }
+
+        # (3 unchanged blocks hidden)
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types_update/plan.json b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types_update/plan.json
new file mode 100644
index 0000000..5b96e7e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types_update/plan.json
@@ -0,0 +1,237 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_multiple_blocks.multiple_blocks",
+          "expressions": {
+            "first_block": [
+              {
+                "id": {
+                  "constant_value": "B27FB8BE-52D4-4CEB-ACE9-5E7FB3968F2B"
+                }
+              },
+              {
+                "id": {
+                  "constant_value": "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+                }
+              },
+              {
+                "id": {
+                  "constant_value": "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+                }
+              }
+            ],
+            "id": {
+              "constant_value": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+            },
+            "second_block": [
+              {
+                "id": {
+                  "constant_value": "91640A80-A65F-4BEF-925B-684E4517A04D"
+                }
+              },
+              {
+                "id": {
+                  "constant_value": "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+                }
+              }
+            ]
+          },
+          "mode": "managed",
+          "name": "multiple_blocks",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_multiple_blocks"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_multiple_blocks.multiple_blocks",
+          "mode": "managed",
+          "name": "multiple_blocks",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "first_block": [
+              {},
+              {},
+              {}
+            ],
+            "second_block": [
+              {},
+              {}
+            ]
+          },
+          "type": "tfcoremock_multiple_blocks",
+          "values": {
+            "first_block": [
+              {
+                "id": "B27FB8BE-52D4-4CEB-ACE9-5E7FB3968F2B"
+              },
+              {
+                "id": "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+              },
+              {
+                "id": "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+              }
+            ],
+            "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+            "second_block": [
+              {
+                "id": "91640A80-A65F-4BEF-925B-684E4517A04D"
+              },
+              {
+                "id": "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+              }
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_multiple_blocks.multiple_blocks",
+            "mode": "managed",
+            "name": "multiple_blocks",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "first_block": [
+                {},
+                {},
+                {}
+              ],
+              "second_block": [
+                {},
+                {}
+              ]
+            },
+            "type": "tfcoremock_multiple_blocks",
+            "values": {
+              "first_block": [
+                {
+                  "id": "D35E88DA-BC3B-46D7-9E0B-4ED4582FA65A"
+                },
+                {
+                  "id": "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+                },
+                {
+                  "id": "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+                }
+              ],
+              "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+              "second_block": [
+                {
+                  "id": "157660A9-D590-469E-BE28-83B8526428CA"
+                },
+                {
+                  "id": "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+                }
+              ]
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_multiple_blocks.multiple_blocks",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "first_block": [
+            {
+              "id": "B27FB8BE-52D4-4CEB-ACE9-5E7FB3968F2B"
+            },
+            {
+              "id": "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+            },
+            {
+              "id": "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+            }
+          ],
+          "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+          "second_block": [
+            {
+              "id": "91640A80-A65F-4BEF-925B-684E4517A04D"
+            },
+            {
+              "id": "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+            }
+          ]
+        },
+        "after_sensitive": {
+          "first_block": [
+            {},
+            {},
+            {}
+          ],
+          "second_block": [
+            {},
+            {}
+          ]
+        },
+        "after_unknown": {},
+        "before": {
+          "first_block": [
+            {
+              "id": "D35E88DA-BC3B-46D7-9E0B-4ED4582FA65A"
+            },
+            {
+              "id": "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+            },
+            {
+              "id": "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+            }
+          ],
+          "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+          "second_block": [
+            {
+              "id": "157660A9-D590-469E-BE28-83B8526428CA"
+            },
+            {
+              "id": "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+            }
+          ]
+        },
+        "before_sensitive": {
+          "first_block": [
+            {},
+            {},
+            {}
+          ],
+          "second_block": [
+            {},
+            {}
+          ]
+        }
+      },
+      "mode": "managed",
+      "name": "multiple_blocks",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_multiple_blocks"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:46Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types_update/state b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types_update/state
new file mode 100644
index 0000000..eda4b81
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types_update/state
@@ -0,0 +1,21 @@
+# tfcoremock_multiple_blocks.multiple_blocks:
+resource "tfcoremock_multiple_blocks" "multiple_blocks" {
+    id = "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+
+    first_block {
+        id = "B27FB8BE-52D4-4CEB-ACE9-5E7FB3968F2B"
+    }
+    first_block {
+        id = "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+    }
+    first_block {
+        id = "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+    }
+
+    second_block {
+        id = "91640A80-A65F-4BEF-925B-684E4517A04D"
+    }
+    second_block {
+        id = "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types_update/state.json b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types_update/state.json
new file mode 100644
index 0000000..554a136
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/multiple_block_types_update/state.json
@@ -0,0 +1,50 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_multiple_blocks.multiple_blocks",
+          "mode": "managed",
+          "name": "multiple_blocks",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "first_block": [
+              {},
+              {},
+              {}
+            ],
+            "second_block": [
+              {},
+              {}
+            ]
+          },
+          "type": "tfcoremock_multiple_blocks",
+          "values": {
+            "first_block": [
+              {
+                "id": "B27FB8BE-52D4-4CEB-ACE9-5E7FB3968F2B"
+              },
+              {
+                "id": "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+              },
+              {
+                "id": "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+              }
+            ],
+            "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+            "second_block": [
+              {
+                "id": "91640A80-A65F-4BEF-925B-684E4517A04D"
+              },
+              {
+                "id": "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+              }
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_list/apply.json b/v1.5.7/testing/equivalence-tests/outputs/nested_list/apply.json
new file mode 100644
index 0000000..48d3386
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_list/apply.json
@@ -0,0 +1,79 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_list.nested_list: Plan to create",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_nested_list.nested_list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_list.nested_list",
+        "resource_key": null,
+        "resource_name": "nested_list",
+        "resource_type": "tfcoremock_nested_list"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_list.nested_list: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_nested_list.nested_list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_list.nested_list",
+        "resource_key": null,
+        "resource_name": "nested_list",
+        "resource_type": "tfcoremock_nested_list"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_list.nested_list: Creation complete after 0s [id=DA051126-BAD6-4EB2-92E5-F0250DAF0B92]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+      "resource": {
+        "addr": "tfcoremock_nested_list.nested_list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_list.nested_list",
+        "resource_key": null,
+        "resource_name": "nested_list",
+        "resource_type": "tfcoremock_nested_list"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_list/plan b/v1.5.7/testing/equivalence-tests/outputs/nested_list/plan
new file mode 100644
index 0000000..eca0a09
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_list/plan
@@ -0,0 +1,30 @@
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  # tfcoremock_nested_list.nested_list will be created
+  + resource "tfcoremock_nested_list" "nested_list" {
+      + id    = "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+      + lists = [
+          + [],
+          + [
+              + "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982",
+            ],
+          + [
+              + "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F",
+              + "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD",
+            ],
+        ]
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_list/plan.json b/v1.5.7/testing/equivalence-tests/outputs/nested_list/plan.json
new file mode 100644
index 0000000..f77e9ec
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_list/plan.json
@@ -0,0 +1,123 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_list.nested_list",
+          "expressions": {
+            "id": {
+              "constant_value": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+            },
+            "lists": {
+              "constant_value": [
+                [],
+                [
+                  "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982"
+                ],
+                [
+                  "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F",
+                  "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD"
+                ]
+              ]
+            }
+          },
+          "mode": "managed",
+          "name": "nested_list",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_nested_list"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_list.nested_list",
+          "mode": "managed",
+          "name": "nested_list",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "lists": [
+              [],
+              [
+                false
+              ],
+              [
+                false,
+                false
+              ]
+            ]
+          },
+          "type": "tfcoremock_nested_list",
+          "values": {
+            "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+            "lists": [
+              [],
+              [
+                "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982"
+              ],
+              [
+                "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F",
+                "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD"
+              ]
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_nested_list.nested_list",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "after": {
+          "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+          "lists": [
+            [],
+            [
+              "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982"
+            ],
+            [
+              "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F",
+              "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD"
+            ]
+          ]
+        },
+        "after_sensitive": {
+          "lists": [
+            [],
+            [
+              false
+            ],
+            [
+              false,
+              false
+            ]
+          ]
+        },
+        "after_unknown": {},
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "managed",
+      "name": "nested_list",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_nested_list"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:48Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_list/state b/v1.5.7/testing/equivalence-tests/outputs/nested_list/state
new file mode 100644
index 0000000..2b6cb15
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_list/state
@@ -0,0 +1,14 @@
+# tfcoremock_nested_list.nested_list:
+resource "tfcoremock_nested_list" "nested_list" {
+    id    = "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+    lists = [
+        [],
+        [
+            "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982",
+        ],
+        [
+            "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F",
+            "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD",
+        ],
+    ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_list/state.json b/v1.5.7/testing/equivalence-tests/outputs/nested_list/state.json
new file mode 100644
index 0000000..6ce6b63
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_list/state.json
@@ -0,0 +1,42 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_list.nested_list",
+          "mode": "managed",
+          "name": "nested_list",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "lists": [
+              [],
+              [
+                false
+              ],
+              [
+                false,
+                false
+              ]
+            ]
+          },
+          "type": "tfcoremock_nested_list",
+          "values": {
+            "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+            "lists": [
+              [],
+              [
+                "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982"
+              ],
+              [
+                "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F",
+                "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD"
+              ]
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_list_update/apply.json b/v1.5.7/testing/equivalence-tests/outputs/nested_list_update/apply.json
new file mode 100644
index 0000000..5ffd1a5
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_list_update/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_list.nested_list: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_nested_list.nested_list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_list.nested_list",
+        "resource_key": null,
+        "resource_name": "nested_list",
+        "resource_type": "tfcoremock_nested_list"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_list.nested_list: Modifying... [id=DA051126-BAD6-4EB2-92E5-F0250DAF0B92]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+      "resource": {
+        "addr": "tfcoremock_nested_list.nested_list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_list.nested_list",
+        "resource_key": null,
+        "resource_name": "nested_list",
+        "resource_type": "tfcoremock_nested_list"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_list.nested_list: Modifications complete after 0s [id=DA051126-BAD6-4EB2-92E5-F0250DAF0B92]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+      "resource": {
+        "addr": "tfcoremock_nested_list.nested_list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_list.nested_list",
+        "resource_key": null,
+        "resource_name": "nested_list",
+        "resource_type": "tfcoremock_nested_list"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_list_update/plan b/v1.5.7/testing/equivalence-tests/outputs/nested_list_update/plan
new file mode 100644
index 0000000..facc226
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_list_update/plan
@@ -0,0 +1,37 @@
+tfcoremock_nested_list.nested_list: Refreshing state... [id=DA051126-BAD6-4EB2-92E5-F0250DAF0B92]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_nested_list.nested_list will be updated in-place
+  ~ resource "tfcoremock_nested_list" "nested_list" {
+        id    = "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+      ~ lists = [
+          - [],
+            [
+                "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982",
+            ],
+          - [
+              - "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F",
+              - "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD",
+            ],
+          + [
+              + "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD",
+            ],
+          + [
+              + "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F",
+            ],
+        ]
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_list_update/plan.json b/v1.5.7/testing/equivalence-tests/outputs/nested_list_update/plan.json
new file mode 100644
index 0000000..fa5eee3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_list_update/plan.json
@@ -0,0 +1,193 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_list.nested_list",
+          "expressions": {
+            "id": {
+              "constant_value": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+            },
+            "lists": {
+              "constant_value": [
+                [
+                  "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982"
+                ],
+                [
+                  "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD"
+                ],
+                [
+                  "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F"
+                ]
+              ]
+            }
+          },
+          "mode": "managed",
+          "name": "nested_list",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_nested_list"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_list.nested_list",
+          "mode": "managed",
+          "name": "nested_list",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "lists": [
+              [
+                false
+              ],
+              [
+                false
+              ],
+              [
+                false
+              ]
+            ]
+          },
+          "type": "tfcoremock_nested_list",
+          "values": {
+            "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+            "lists": [
+              [
+                "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982"
+              ],
+              [
+                "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD"
+              ],
+              [
+                "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F"
+              ]
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_nested_list.nested_list",
+            "mode": "managed",
+            "name": "nested_list",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "lists": [
+                [],
+                [
+                  false
+                ],
+                [
+                  false,
+                  false
+                ]
+              ]
+            },
+            "type": "tfcoremock_nested_list",
+            "values": {
+              "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+              "lists": [
+                [],
+                [
+                  "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982"
+                ],
+                [
+                  "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F",
+                  "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD"
+                ]
+              ]
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_nested_list.nested_list",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+          "lists": [
+            [
+              "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982"
+            ],
+            [
+              "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD"
+            ],
+            [
+              "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F"
+            ]
+          ]
+        },
+        "after_sensitive": {
+          "lists": [
+            [
+              false
+            ],
+            [
+              false
+            ],
+            [
+              false
+            ]
+          ]
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+          "lists": [
+            [],
+            [
+              "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982"
+            ],
+            [
+              "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F",
+              "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD"
+            ]
+          ]
+        },
+        "before_sensitive": {
+          "lists": [
+            [],
+            [
+              false
+            ],
+            [
+              false,
+              false
+            ]
+          ]
+        }
+      },
+      "mode": "managed",
+      "name": "nested_list",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_nested_list"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:50Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_list_update/state b/v1.5.7/testing/equivalence-tests/outputs/nested_list_update/state
new file mode 100644
index 0000000..23e036a
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_list_update/state
@@ -0,0 +1,15 @@
+# tfcoremock_nested_list.nested_list:
+resource "tfcoremock_nested_list" "nested_list" {
+    id    = "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+    lists = [
+        [
+            "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982",
+        ],
+        [
+            "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD",
+        ],
+        [
+            "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F",
+        ],
+    ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_list_update/state.json b/v1.5.7/testing/equivalence-tests/outputs/nested_list_update/state.json
new file mode 100644
index 0000000..f8f1cc2
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_list_update/state.json
@@ -0,0 +1,44 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_list.nested_list",
+          "mode": "managed",
+          "name": "nested_list",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "lists": [
+              [
+                false
+              ],
+              [
+                false
+              ],
+              [
+                false
+              ]
+            ]
+          },
+          "type": "tfcoremock_nested_list",
+          "values": {
+            "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+            "lists": [
+              [
+                "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982"
+              ],
+              [
+                "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD"
+              ],
+              [
+                "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F"
+              ]
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_map/apply.json b/v1.5.7/testing/equivalence-tests/outputs/nested_map/apply.json
new file mode 100644
index 0000000..019b069
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_map/apply.json
@@ -0,0 +1,79 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_map.nested_map: Plan to create",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_nested_map.nested_map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_map.nested_map",
+        "resource_key": null,
+        "resource_name": "nested_map",
+        "resource_type": "tfcoremock_nested_map"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_map.nested_map: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_nested_map.nested_map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_map.nested_map",
+        "resource_key": null,
+        "resource_name": "nested_map",
+        "resource_type": "tfcoremock_nested_map"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_map.nested_map: Creation complete after 0s [id=502B0348-B796-4F6A-8694-A5A397237B85]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "502B0348-B796-4F6A-8694-A5A397237B85",
+      "resource": {
+        "addr": "tfcoremock_nested_map.nested_map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_map.nested_map",
+        "resource_key": null,
+        "resource_name": "nested_map",
+        "resource_type": "tfcoremock_nested_map"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_map/plan b/v1.5.7/testing/equivalence-tests/outputs/nested_map/plan
new file mode 100644
index 0000000..d0bcf5f
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_map/plan
@@ -0,0 +1,30 @@
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  # tfcoremock_nested_map.nested_map will be created
+  + resource "tfcoremock_nested_map" "nested_map" {
+      + id   = "502B0348-B796-4F6A-8694-A5A397237B85"
+      + maps = {
+          + "first_nested_map"  = {
+              + "first_key"  = "9E858021-953F-4DD3-8842-F2C782780422"
+              + "second_key" = "D55D0E1E-51D9-4BCE-9021-7D201906D3C0"
+            }
+          + "second_nested_map" = {
+              + "first_key"  = "6E80C701-A823-43FE-A520-699851EF9052"
+              + "second_key" = "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+            }
+        }
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_map/plan.json b/v1.5.7/testing/equivalence-tests/outputs/nested_map/plan.json
new file mode 100644
index 0000000..626e60b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_map/plan.json
@@ -0,0 +1,111 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_map.nested_map",
+          "expressions": {
+            "id": {
+              "constant_value": "502B0348-B796-4F6A-8694-A5A397237B85"
+            },
+            "maps": {
+              "constant_value": {
+                "first_nested_map": {
+                  "first_key": "9E858021-953F-4DD3-8842-F2C782780422",
+                  "second_key": "D55D0E1E-51D9-4BCE-9021-7D201906D3C0"
+                },
+                "second_nested_map": {
+                  "first_key": "6E80C701-A823-43FE-A520-699851EF9052",
+                  "second_key": "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+                }
+              }
+            }
+          },
+          "mode": "managed",
+          "name": "nested_map",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_nested_map"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_map.nested_map",
+          "mode": "managed",
+          "name": "nested_map",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "maps": {
+              "first_nested_map": {},
+              "second_nested_map": {}
+            }
+          },
+          "type": "tfcoremock_nested_map",
+          "values": {
+            "id": "502B0348-B796-4F6A-8694-A5A397237B85",
+            "maps": {
+              "first_nested_map": {
+                "first_key": "9E858021-953F-4DD3-8842-F2C782780422",
+                "second_key": "D55D0E1E-51D9-4BCE-9021-7D201906D3C0"
+              },
+              "second_nested_map": {
+                "first_key": "6E80C701-A823-43FE-A520-699851EF9052",
+                "second_key": "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+              }
+            }
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_nested_map.nested_map",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "after": {
+          "id": "502B0348-B796-4F6A-8694-A5A397237B85",
+          "maps": {
+            "first_nested_map": {
+              "first_key": "9E858021-953F-4DD3-8842-F2C782780422",
+              "second_key": "D55D0E1E-51D9-4BCE-9021-7D201906D3C0"
+            },
+            "second_nested_map": {
+              "first_key": "6E80C701-A823-43FE-A520-699851EF9052",
+              "second_key": "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+            }
+          }
+        },
+        "after_sensitive": {
+          "maps": {
+            "first_nested_map": {},
+            "second_nested_map": {}
+          }
+        },
+        "after_unknown": {},
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "managed",
+      "name": "nested_map",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_nested_map"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:52Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_map/state b/v1.5.7/testing/equivalence-tests/outputs/nested_map/state
new file mode 100644
index 0000000..6cd8e22
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_map/state
@@ -0,0 +1,14 @@
+# tfcoremock_nested_map.nested_map:
+resource "tfcoremock_nested_map" "nested_map" {
+    id   = "502B0348-B796-4F6A-8694-A5A397237B85"
+    maps = {
+        "first_nested_map"  = {
+            "first_key"  = "9E858021-953F-4DD3-8842-F2C782780422"
+            "second_key" = "D55D0E1E-51D9-4BCE-9021-7D201906D3C0"
+        }
+        "second_nested_map" = {
+            "first_key"  = "6E80C701-A823-43FE-A520-699851EF9052"
+            "second_key" = "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+        }
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_map/state.json b/v1.5.7/testing/equivalence-tests/outputs/nested_map/state.json
new file mode 100644
index 0000000..7c2a9c6
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_map/state.json
@@ -0,0 +1,36 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_map.nested_map",
+          "mode": "managed",
+          "name": "nested_map",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "maps": {
+              "first_nested_map": {},
+              "second_nested_map": {}
+            }
+          },
+          "type": "tfcoremock_nested_map",
+          "values": {
+            "id": "502B0348-B796-4F6A-8694-A5A397237B85",
+            "maps": {
+              "first_nested_map": {
+                "first_key": "9E858021-953F-4DD3-8842-F2C782780422",
+                "second_key": "D55D0E1E-51D9-4BCE-9021-7D201906D3C0"
+              },
+              "second_nested_map": {
+                "first_key": "6E80C701-A823-43FE-A520-699851EF9052",
+                "second_key": "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+              }
+            }
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_map_update/apply.json b/v1.5.7/testing/equivalence-tests/outputs/nested_map_update/apply.json
new file mode 100644
index 0000000..552c2d7
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_map_update/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_map.nested_map: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_nested_map.nested_map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_map.nested_map",
+        "resource_key": null,
+        "resource_name": "nested_map",
+        "resource_type": "tfcoremock_nested_map"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_map.nested_map: Modifying... [id=502B0348-B796-4F6A-8694-A5A397237B85]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "502B0348-B796-4F6A-8694-A5A397237B85",
+      "resource": {
+        "addr": "tfcoremock_nested_map.nested_map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_map.nested_map",
+        "resource_key": null,
+        "resource_name": "nested_map",
+        "resource_type": "tfcoremock_nested_map"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_map.nested_map: Modifications complete after 0s [id=502B0348-B796-4F6A-8694-A5A397237B85]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "502B0348-B796-4F6A-8694-A5A397237B85",
+      "resource": {
+        "addr": "tfcoremock_nested_map.nested_map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_map.nested_map",
+        "resource_key": null,
+        "resource_name": "nested_map",
+        "resource_type": "tfcoremock_nested_map"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_map_update/plan b/v1.5.7/testing/equivalence-tests/outputs/nested_map_update/plan
new file mode 100644
index 0000000..ef2185d
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_map_update/plan
@@ -0,0 +1,32 @@
+tfcoremock_nested_map.nested_map: Refreshing state... [id=502B0348-B796-4F6A-8694-A5A397237B85]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_nested_map.nested_map will be updated in-place
+  ~ resource "tfcoremock_nested_map" "nested_map" {
+        id   = "502B0348-B796-4F6A-8694-A5A397237B85"
+      ~ maps = {
+          ~ "first_nested_map"  = {
+              ~ "first_key"  = "9E858021-953F-4DD3-8842-F2C782780422" -> "6E80C701-A823-43FE-A520-699851EF9052"
+              + "third_key"  = "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+                # (1 unchanged element hidden)
+            }
+          ~ "second_nested_map" = {
+              ~ "first_key"  = "6E80C701-A823-43FE-A520-699851EF9052" -> "9E858021-953F-4DD3-8842-F2C782780422"
+              - "second_key" = "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC" -> null
+            }
+        }
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_map_update/plan.json b/v1.5.7/testing/equivalence-tests/outputs/nested_map_update/plan.json
new file mode 100644
index 0000000..f51d559
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_map_update/plan.json
@@ -0,0 +1,164 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_map.nested_map",
+          "expressions": {
+            "id": {
+              "constant_value": "502B0348-B796-4F6A-8694-A5A397237B85"
+            },
+            "maps": {
+              "constant_value": {
+                "first_nested_map": {
+                  "first_key": "6E80C701-A823-43FE-A520-699851EF9052",
+                  "second_key": "D55D0E1E-51D9-4BCE-9021-7D201906D3C0",
+                  "third_key": "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+                },
+                "second_nested_map": {
+                  "first_key": "9E858021-953F-4DD3-8842-F2C782780422"
+                }
+              }
+            }
+          },
+          "mode": "managed",
+          "name": "nested_map",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_nested_map"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_map.nested_map",
+          "mode": "managed",
+          "name": "nested_map",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "maps": {
+              "first_nested_map": {},
+              "second_nested_map": {}
+            }
+          },
+          "type": "tfcoremock_nested_map",
+          "values": {
+            "id": "502B0348-B796-4F6A-8694-A5A397237B85",
+            "maps": {
+              "first_nested_map": {
+                "first_key": "6E80C701-A823-43FE-A520-699851EF9052",
+                "second_key": "D55D0E1E-51D9-4BCE-9021-7D201906D3C0",
+                "third_key": "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+              },
+              "second_nested_map": {
+                "first_key": "9E858021-953F-4DD3-8842-F2C782780422"
+              }
+            }
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_nested_map.nested_map",
+            "mode": "managed",
+            "name": "nested_map",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "maps": {
+                "first_nested_map": {},
+                "second_nested_map": {}
+              }
+            },
+            "type": "tfcoremock_nested_map",
+            "values": {
+              "id": "502B0348-B796-4F6A-8694-A5A397237B85",
+              "maps": {
+                "first_nested_map": {
+                  "first_key": "9E858021-953F-4DD3-8842-F2C782780422",
+                  "second_key": "D55D0E1E-51D9-4BCE-9021-7D201906D3C0"
+                },
+                "second_nested_map": {
+                  "first_key": "6E80C701-A823-43FE-A520-699851EF9052",
+                  "second_key": "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+                }
+              }
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_nested_map.nested_map",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "502B0348-B796-4F6A-8694-A5A397237B85",
+          "maps": {
+            "first_nested_map": {
+              "first_key": "6E80C701-A823-43FE-A520-699851EF9052",
+              "second_key": "D55D0E1E-51D9-4BCE-9021-7D201906D3C0",
+              "third_key": "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+            },
+            "second_nested_map": {
+              "first_key": "9E858021-953F-4DD3-8842-F2C782780422"
+            }
+          }
+        },
+        "after_sensitive": {
+          "maps": {
+            "first_nested_map": {},
+            "second_nested_map": {}
+          }
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "502B0348-B796-4F6A-8694-A5A397237B85",
+          "maps": {
+            "first_nested_map": {
+              "first_key": "9E858021-953F-4DD3-8842-F2C782780422",
+              "second_key": "D55D0E1E-51D9-4BCE-9021-7D201906D3C0"
+            },
+            "second_nested_map": {
+              "first_key": "6E80C701-A823-43FE-A520-699851EF9052",
+              "second_key": "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+            }
+          }
+        },
+        "before_sensitive": {
+          "maps": {
+            "first_nested_map": {},
+            "second_nested_map": {}
+          }
+        }
+      },
+      "mode": "managed",
+      "name": "nested_map",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_nested_map"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:53Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_map_update/state b/v1.5.7/testing/equivalence-tests/outputs/nested_map_update/state
new file mode 100644
index 0000000..cbd0c4f
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_map_update/state
@@ -0,0 +1,14 @@
+# tfcoremock_nested_map.nested_map:
+resource "tfcoremock_nested_map" "nested_map" {
+    id   = "502B0348-B796-4F6A-8694-A5A397237B85"
+    maps = {
+        "first_nested_map"  = {
+            "first_key"  = "6E80C701-A823-43FE-A520-699851EF9052"
+            "second_key" = "D55D0E1E-51D9-4BCE-9021-7D201906D3C0"
+            "third_key"  = "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+        }
+        "second_nested_map" = {
+            "first_key" = "9E858021-953F-4DD3-8842-F2C782780422"
+        }
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_map_update/state.json b/v1.5.7/testing/equivalence-tests/outputs/nested_map_update/state.json
new file mode 100644
index 0000000..3938324
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_map_update/state.json
@@ -0,0 +1,36 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_map.nested_map",
+          "mode": "managed",
+          "name": "nested_map",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "maps": {
+              "first_nested_map": {},
+              "second_nested_map": {}
+            }
+          },
+          "type": "tfcoremock_nested_map",
+          "values": {
+            "id": "502B0348-B796-4F6A-8694-A5A397237B85",
+            "maps": {
+              "first_nested_map": {
+                "first_key": "6E80C701-A823-43FE-A520-699851EF9052",
+                "second_key": "D55D0E1E-51D9-4BCE-9021-7D201906D3C0",
+                "third_key": "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+              },
+              "second_nested_map": {
+                "first_key": "9E858021-953F-4DD3-8842-F2C782780422"
+              }
+            }
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_objects/apply.json b/v1.5.7/testing/equivalence-tests/outputs/nested_objects/apply.json
new file mode 100644
index 0000000..c920704
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_objects/apply.json
@@ -0,0 +1,79 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_object.nested_object: Plan to create",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_nested_object.nested_object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_object.nested_object",
+        "resource_key": null,
+        "resource_name": "nested_object",
+        "resource_type": "tfcoremock_nested_object"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_object.nested_object: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_nested_object.nested_object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_object.nested_object",
+        "resource_key": null,
+        "resource_name": "nested_object",
+        "resource_type": "tfcoremock_nested_object"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_object.nested_object: Creation complete after 0s [id=B2491EF0-9361-40FD-B25A-0332A1A5E052]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "B2491EF0-9361-40FD-B25A-0332A1A5E052",
+      "resource": {
+        "addr": "tfcoremock_nested_object.nested_object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_object.nested_object",
+        "resource_key": null,
+        "resource_name": "nested_object",
+        "resource_type": "tfcoremock_nested_object"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_objects/plan b/v1.5.7/testing/equivalence-tests/outputs/nested_objects/plan
new file mode 100644
index 0000000..bb70728
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_objects/plan
@@ -0,0 +1,30 @@
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  # tfcoremock_nested_object.nested_object will be created
+  + resource "tfcoremock_nested_object" "nested_object" {
+      + id            = "B2491EF0-9361-40FD-B25A-0332A1A5E052"
+      + parent_object = {
+          + first_nested_object  = {
+              + attribute_one = "09AE7244-7BFB-476B-912C-D1AB4E7E9622"
+              + attribute_two = "5425587C-49EF-4C1E-A906-1DC923A12725"
+            }
+          + second_nested_object = {
+              + attribute_one = "63712BFE-78F8-42D3-A074-A78249E5E25E"
+              + attribute_two = "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+            }
+        }
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_objects/plan.json b/v1.5.7/testing/equivalence-tests/outputs/nested_objects/plan.json
new file mode 100644
index 0000000..69bb594
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_objects/plan.json
@@ -0,0 +1,111 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_object.nested_object",
+          "expressions": {
+            "id": {
+              "constant_value": "B2491EF0-9361-40FD-B25A-0332A1A5E052"
+            },
+            "parent_object": {
+              "constant_value": {
+                "first_nested_object": {
+                  "attribute_one": "09AE7244-7BFB-476B-912C-D1AB4E7E9622",
+                  "attribute_two": "5425587C-49EF-4C1E-A906-1DC923A12725"
+                },
+                "second_nested_object": {
+                  "attribute_one": "63712BFE-78F8-42D3-A074-A78249E5E25E",
+                  "attribute_two": "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+                }
+              }
+            }
+          },
+          "mode": "managed",
+          "name": "nested_object",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_nested_object"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_object.nested_object",
+          "mode": "managed",
+          "name": "nested_object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "parent_object": {
+              "first_nested_object": {},
+              "second_nested_object": {}
+            }
+          },
+          "type": "tfcoremock_nested_object",
+          "values": {
+            "id": "B2491EF0-9361-40FD-B25A-0332A1A5E052",
+            "parent_object": {
+              "first_nested_object": {
+                "attribute_one": "09AE7244-7BFB-476B-912C-D1AB4E7E9622",
+                "attribute_two": "5425587C-49EF-4C1E-A906-1DC923A12725"
+              },
+              "second_nested_object": {
+                "attribute_one": "63712BFE-78F8-42D3-A074-A78249E5E25E",
+                "attribute_two": "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+              }
+            }
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_nested_object.nested_object",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "after": {
+          "id": "B2491EF0-9361-40FD-B25A-0332A1A5E052",
+          "parent_object": {
+            "first_nested_object": {
+              "attribute_one": "09AE7244-7BFB-476B-912C-D1AB4E7E9622",
+              "attribute_two": "5425587C-49EF-4C1E-A906-1DC923A12725"
+            },
+            "second_nested_object": {
+              "attribute_one": "63712BFE-78F8-42D3-A074-A78249E5E25E",
+              "attribute_two": "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+            }
+          }
+        },
+        "after_sensitive": {
+          "parent_object": {
+            "first_nested_object": {},
+            "second_nested_object": {}
+          }
+        },
+        "after_unknown": {},
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "managed",
+      "name": "nested_object",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_nested_object"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:55Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_objects/state b/v1.5.7/testing/equivalence-tests/outputs/nested_objects/state
new file mode 100644
index 0000000..f6da6e3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_objects/state
@@ -0,0 +1,14 @@
+# tfcoremock_nested_object.nested_object:
+resource "tfcoremock_nested_object" "nested_object" {
+    id            = "B2491EF0-9361-40FD-B25A-0332A1A5E052"
+    parent_object = {
+        first_nested_object  = {
+            attribute_one = "09AE7244-7BFB-476B-912C-D1AB4E7E9622"
+            attribute_two = "5425587C-49EF-4C1E-A906-1DC923A12725"
+        }
+        second_nested_object = {
+            attribute_one = "63712BFE-78F8-42D3-A074-A78249E5E25E"
+            attribute_two = "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+        }
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_objects/state.json b/v1.5.7/testing/equivalence-tests/outputs/nested_objects/state.json
new file mode 100644
index 0000000..f7bb2f4
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_objects/state.json
@@ -0,0 +1,36 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_object.nested_object",
+          "mode": "managed",
+          "name": "nested_object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "parent_object": {
+              "first_nested_object": {},
+              "second_nested_object": {}
+            }
+          },
+          "type": "tfcoremock_nested_object",
+          "values": {
+            "id": "B2491EF0-9361-40FD-B25A-0332A1A5E052",
+            "parent_object": {
+              "first_nested_object": {
+                "attribute_one": "09AE7244-7BFB-476B-912C-D1AB4E7E9622",
+                "attribute_two": "5425587C-49EF-4C1E-A906-1DC923A12725"
+              },
+              "second_nested_object": {
+                "attribute_one": "63712BFE-78F8-42D3-A074-A78249E5E25E",
+                "attribute_two": "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+              }
+            }
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_objects_update/apply.json b/v1.5.7/testing/equivalence-tests/outputs/nested_objects_update/apply.json
new file mode 100644
index 0000000..447dd24
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_objects_update/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_object.nested_object: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_nested_object.nested_object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_object.nested_object",
+        "resource_key": null,
+        "resource_name": "nested_object",
+        "resource_type": "tfcoremock_nested_object"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_object.nested_object: Modifying... [id=B2491EF0-9361-40FD-B25A-0332A1A5E052]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "B2491EF0-9361-40FD-B25A-0332A1A5E052",
+      "resource": {
+        "addr": "tfcoremock_nested_object.nested_object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_object.nested_object",
+        "resource_key": null,
+        "resource_name": "nested_object",
+        "resource_type": "tfcoremock_nested_object"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_object.nested_object: Modifications complete after 0s [id=B2491EF0-9361-40FD-B25A-0332A1A5E052]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "B2491EF0-9361-40FD-B25A-0332A1A5E052",
+      "resource": {
+        "addr": "tfcoremock_nested_object.nested_object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_object.nested_object",
+        "resource_key": null,
+        "resource_name": "nested_object",
+        "resource_type": "tfcoremock_nested_object"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_objects_update/plan b/v1.5.7/testing/equivalence-tests/outputs/nested_objects_update/plan
new file mode 100644
index 0000000..fe763de
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_objects_update/plan
@@ -0,0 +1,31 @@
+tfcoremock_nested_object.nested_object: Refreshing state... [id=B2491EF0-9361-40FD-B25A-0332A1A5E052]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_nested_object.nested_object will be updated in-place
+  ~ resource "tfcoremock_nested_object" "nested_object" {
+        id            = "B2491EF0-9361-40FD-B25A-0332A1A5E052"
+      ~ parent_object = {
+          ~ first_nested_object  = {
+              ~ attribute_two = "5425587C-49EF-4C1E-A906-1DC923A12725" -> "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+                # (1 unchanged attribute hidden)
+            }
+          ~ second_nested_object = {
+              ~ attribute_two = "FB350D92-4AAE-48C6-A408-BFFAFAD46B04" -> "5425587C-49EF-4C1E-A906-1DC923A12725"
+                # (1 unchanged attribute hidden)
+            }
+        }
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_objects_update/plan.json b/v1.5.7/testing/equivalence-tests/outputs/nested_objects_update/plan.json
new file mode 100644
index 0000000..b79f02e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_objects_update/plan.json
@@ -0,0 +1,164 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_object.nested_object",
+          "expressions": {
+            "id": {
+              "constant_value": "B2491EF0-9361-40FD-B25A-0332A1A5E052"
+            },
+            "parent_object": {
+              "constant_value": {
+                "first_nested_object": {
+                  "attribute_one": "09AE7244-7BFB-476B-912C-D1AB4E7E9622",
+                  "attribute_two": "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+                },
+                "second_nested_object": {
+                  "attribute_one": "63712BFE-78F8-42D3-A074-A78249E5E25E",
+                  "attribute_two": "5425587C-49EF-4C1E-A906-1DC923A12725"
+                }
+              }
+            }
+          },
+          "mode": "managed",
+          "name": "nested_object",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_nested_object"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_object.nested_object",
+          "mode": "managed",
+          "name": "nested_object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "parent_object": {
+              "first_nested_object": {},
+              "second_nested_object": {}
+            }
+          },
+          "type": "tfcoremock_nested_object",
+          "values": {
+            "id": "B2491EF0-9361-40FD-B25A-0332A1A5E052",
+            "parent_object": {
+              "first_nested_object": {
+                "attribute_one": "09AE7244-7BFB-476B-912C-D1AB4E7E9622",
+                "attribute_two": "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+              },
+              "second_nested_object": {
+                "attribute_one": "63712BFE-78F8-42D3-A074-A78249E5E25E",
+                "attribute_two": "5425587C-49EF-4C1E-A906-1DC923A12725"
+              }
+            }
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_nested_object.nested_object",
+            "mode": "managed",
+            "name": "nested_object",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "parent_object": {
+                "first_nested_object": {},
+                "second_nested_object": {}
+              }
+            },
+            "type": "tfcoremock_nested_object",
+            "values": {
+              "id": "B2491EF0-9361-40FD-B25A-0332A1A5E052",
+              "parent_object": {
+                "first_nested_object": {
+                  "attribute_one": "09AE7244-7BFB-476B-912C-D1AB4E7E9622",
+                  "attribute_two": "5425587C-49EF-4C1E-A906-1DC923A12725"
+                },
+                "second_nested_object": {
+                  "attribute_one": "63712BFE-78F8-42D3-A074-A78249E5E25E",
+                  "attribute_two": "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+                }
+              }
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_nested_object.nested_object",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "B2491EF0-9361-40FD-B25A-0332A1A5E052",
+          "parent_object": {
+            "first_nested_object": {
+              "attribute_one": "09AE7244-7BFB-476B-912C-D1AB4E7E9622",
+              "attribute_two": "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+            },
+            "second_nested_object": {
+              "attribute_one": "63712BFE-78F8-42D3-A074-A78249E5E25E",
+              "attribute_two": "5425587C-49EF-4C1E-A906-1DC923A12725"
+            }
+          }
+        },
+        "after_sensitive": {
+          "parent_object": {
+            "first_nested_object": {},
+            "second_nested_object": {}
+          }
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "B2491EF0-9361-40FD-B25A-0332A1A5E052",
+          "parent_object": {
+            "first_nested_object": {
+              "attribute_one": "09AE7244-7BFB-476B-912C-D1AB4E7E9622",
+              "attribute_two": "5425587C-49EF-4C1E-A906-1DC923A12725"
+            },
+            "second_nested_object": {
+              "attribute_one": "63712BFE-78F8-42D3-A074-A78249E5E25E",
+              "attribute_two": "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+            }
+          }
+        },
+        "before_sensitive": {
+          "parent_object": {
+            "first_nested_object": {},
+            "second_nested_object": {}
+          }
+        }
+      },
+      "mode": "managed",
+      "name": "nested_object",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_nested_object"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:57Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_objects_update/state b/v1.5.7/testing/equivalence-tests/outputs/nested_objects_update/state
new file mode 100644
index 0000000..b677f2c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_objects_update/state
@@ -0,0 +1,14 @@
+# tfcoremock_nested_object.nested_object:
+resource "tfcoremock_nested_object" "nested_object" {
+    id            = "B2491EF0-9361-40FD-B25A-0332A1A5E052"
+    parent_object = {
+        first_nested_object  = {
+            attribute_one = "09AE7244-7BFB-476B-912C-D1AB4E7E9622"
+            attribute_two = "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+        }
+        second_nested_object = {
+            attribute_one = "63712BFE-78F8-42D3-A074-A78249E5E25E"
+            attribute_two = "5425587C-49EF-4C1E-A906-1DC923A12725"
+        }
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_objects_update/state.json b/v1.5.7/testing/equivalence-tests/outputs/nested_objects_update/state.json
new file mode 100644
index 0000000..bedf6f9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_objects_update/state.json
@@ -0,0 +1,36 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_object.nested_object",
+          "mode": "managed",
+          "name": "nested_object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "parent_object": {
+              "first_nested_object": {},
+              "second_nested_object": {}
+            }
+          },
+          "type": "tfcoremock_nested_object",
+          "values": {
+            "id": "B2491EF0-9361-40FD-B25A-0332A1A5E052",
+            "parent_object": {
+              "first_nested_object": {
+                "attribute_one": "09AE7244-7BFB-476B-912C-D1AB4E7E9622",
+                "attribute_two": "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+              },
+              "second_nested_object": {
+                "attribute_one": "63712BFE-78F8-42D3-A074-A78249E5E25E",
+                "attribute_two": "5425587C-49EF-4C1E-A906-1DC923A12725"
+              }
+            }
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_set/apply.json b/v1.5.7/testing/equivalence-tests/outputs/nested_set/apply.json
new file mode 100644
index 0000000..63a6cad
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_set/apply.json
@@ -0,0 +1,79 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_set.nested_set: Plan to create",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_nested_set.nested_set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_set.nested_set",
+        "resource_key": null,
+        "resource_name": "nested_set",
+        "resource_type": "tfcoremock_nested_set"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_set.nested_set: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_nested_set.nested_set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_set.nested_set",
+        "resource_key": null,
+        "resource_name": "nested_set",
+        "resource_type": "tfcoremock_nested_set"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_set.nested_set: Creation complete after 0s [id=510598F6-83FE-4090-8986-793293E90480]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "510598F6-83FE-4090-8986-793293E90480",
+      "resource": {
+        "addr": "tfcoremock_nested_set.nested_set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_set.nested_set",
+        "resource_key": null,
+        "resource_name": "nested_set",
+        "resource_type": "tfcoremock_nested_set"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_set/plan b/v1.5.7/testing/equivalence-tests/outputs/nested_set/plan
new file mode 100644
index 0000000..819b7bf
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_set/plan
@@ -0,0 +1,30 @@
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  # tfcoremock_nested_set.nested_set will be created
+  + resource "tfcoremock_nested_set" "nested_set" {
+      + id   = "510598F6-83FE-4090-8986-793293E90480"
+      + sets = [
+          + [
+              + "29B6824A-5CB6-4C25-A359-727BAFEF25EB",
+              + "7E90963C-BE32-4411-B9DD-B02E7FE75766",
+            ],
+          + [
+              + "9373D62D-1BF0-4F17-B100-7C0FBE368ADE",
+            ],
+          + [],
+        ]
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_set/plan.json b/v1.5.7/testing/equivalence-tests/outputs/nested_set/plan.json
new file mode 100644
index 0000000..4b44499
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_set/plan.json
@@ -0,0 +1,123 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_set.nested_set",
+          "expressions": {
+            "id": {
+              "constant_value": "510598F6-83FE-4090-8986-793293E90480"
+            },
+            "sets": {
+              "constant_value": [
+                [],
+                [
+                  "9373D62D-1BF0-4F17-B100-7C0FBE368ADE"
+                ],
+                [
+                  "7E90963C-BE32-4411-B9DD-B02E7FE75766",
+                  "29B6824A-5CB6-4C25-A359-727BAFEF25EB"
+                ]
+              ]
+            }
+          },
+          "mode": "managed",
+          "name": "nested_set",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_nested_set"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_set.nested_set",
+          "mode": "managed",
+          "name": "nested_set",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "sets": [
+              [
+                false,
+                false
+              ],
+              [
+                false
+              ],
+              []
+            ]
+          },
+          "type": "tfcoremock_nested_set",
+          "values": {
+            "id": "510598F6-83FE-4090-8986-793293E90480",
+            "sets": [
+              [
+                "29B6824A-5CB6-4C25-A359-727BAFEF25EB",
+                "7E90963C-BE32-4411-B9DD-B02E7FE75766"
+              ],
+              [
+                "9373D62D-1BF0-4F17-B100-7C0FBE368ADE"
+              ],
+              []
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_nested_set.nested_set",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "after": {
+          "id": "510598F6-83FE-4090-8986-793293E90480",
+          "sets": [
+            [
+              "29B6824A-5CB6-4C25-A359-727BAFEF25EB",
+              "7E90963C-BE32-4411-B9DD-B02E7FE75766"
+            ],
+            [
+              "9373D62D-1BF0-4F17-B100-7C0FBE368ADE"
+            ],
+            []
+          ]
+        },
+        "after_sensitive": {
+          "sets": [
+            [
+              false,
+              false
+            ],
+            [
+              false
+            ],
+            []
+          ]
+        },
+        "after_unknown": {},
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "managed",
+      "name": "nested_set",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_nested_set"
+    }
+  ],
+  "timestamp": "2023-05-25T07:35:59Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_set/state b/v1.5.7/testing/equivalence-tests/outputs/nested_set/state
new file mode 100644
index 0000000..7c47e96
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_set/state
@@ -0,0 +1,14 @@
+# tfcoremock_nested_set.nested_set:
+resource "tfcoremock_nested_set" "nested_set" {
+    id   = "510598F6-83FE-4090-8986-793293E90480"
+    sets = [
+        [
+            "29B6824A-5CB6-4C25-A359-727BAFEF25EB",
+            "7E90963C-BE32-4411-B9DD-B02E7FE75766",
+        ],
+        [
+            "9373D62D-1BF0-4F17-B100-7C0FBE368ADE",
+        ],
+        [],
+    ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_set/state.json b/v1.5.7/testing/equivalence-tests/outputs/nested_set/state.json
new file mode 100644
index 0000000..1cef8af
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_set/state.json
@@ -0,0 +1,42 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_set.nested_set",
+          "mode": "managed",
+          "name": "nested_set",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "sets": [
+              [
+                false,
+                false
+              ],
+              [
+                false
+              ],
+              []
+            ]
+          },
+          "type": "tfcoremock_nested_set",
+          "values": {
+            "id": "510598F6-83FE-4090-8986-793293E90480",
+            "sets": [
+              [
+                "29B6824A-5CB6-4C25-A359-727BAFEF25EB",
+                "7E90963C-BE32-4411-B9DD-B02E7FE75766"
+              ],
+              [
+                "9373D62D-1BF0-4F17-B100-7C0FBE368ADE"
+              ],
+              []
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_set_update/apply.json b/v1.5.7/testing/equivalence-tests/outputs/nested_set_update/apply.json
new file mode 100644
index 0000000..505efe8
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_set_update/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_set.nested_set: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_nested_set.nested_set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_set.nested_set",
+        "resource_key": null,
+        "resource_name": "nested_set",
+        "resource_type": "tfcoremock_nested_set"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_set.nested_set: Modifying... [id=510598F6-83FE-4090-8986-793293E90480]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "510598F6-83FE-4090-8986-793293E90480",
+      "resource": {
+        "addr": "tfcoremock_nested_set.nested_set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_set.nested_set",
+        "resource_key": null,
+        "resource_name": "nested_set",
+        "resource_type": "tfcoremock_nested_set"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_nested_set.nested_set: Modifications complete after 0s [id=510598F6-83FE-4090-8986-793293E90480]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "510598F6-83FE-4090-8986-793293E90480",
+      "resource": {
+        "addr": "tfcoremock_nested_set.nested_set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_nested_set.nested_set",
+        "resource_key": null,
+        "resource_name": "nested_set",
+        "resource_type": "tfcoremock_nested_set"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_set_update/plan b/v1.5.7/testing/equivalence-tests/outputs/nested_set_update/plan
new file mode 100644
index 0000000..643ad10
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_set_update/plan
@@ -0,0 +1,35 @@
+tfcoremock_nested_set.nested_set: Refreshing state... [id=510598F6-83FE-4090-8986-793293E90480]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_nested_set.nested_set will be updated in-place
+  ~ resource "tfcoremock_nested_set" "nested_set" {
+        id   = "510598F6-83FE-4090-8986-793293E90480"
+      ~ sets = [
+          - [
+              - "29B6824A-5CB6-4C25-A359-727BAFEF25EB",
+              - "7E90963C-BE32-4411-B9DD-B02E7FE75766",
+            ],
+          - [],
+          + [
+              + "29B6824A-5CB6-4C25-A359-727BAFEF25EB",
+            ],
+          + [
+              + "7E90963C-BE32-4411-B9DD-B02E7FE75766",
+            ],
+            # (1 unchanged element hidden)
+        ]
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_set_update/plan.json b/v1.5.7/testing/equivalence-tests/outputs/nested_set_update/plan.json
new file mode 100644
index 0000000..807dbaf
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_set_update/plan.json
@@ -0,0 +1,193 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_set.nested_set",
+          "expressions": {
+            "id": {
+              "constant_value": "510598F6-83FE-4090-8986-793293E90480"
+            },
+            "sets": {
+              "constant_value": [
+                [
+                  "29B6824A-5CB6-4C25-A359-727BAFEF25EB"
+                ],
+                [
+                  "9373D62D-1BF0-4F17-B100-7C0FBE368ADE"
+                ],
+                [
+                  "7E90963C-BE32-4411-B9DD-B02E7FE75766"
+                ]
+              ]
+            }
+          },
+          "mode": "managed",
+          "name": "nested_set",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_nested_set"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_set.nested_set",
+          "mode": "managed",
+          "name": "nested_set",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "sets": [
+              [
+                false
+              ],
+              [
+                false
+              ],
+              [
+                false
+              ]
+            ]
+          },
+          "type": "tfcoremock_nested_set",
+          "values": {
+            "id": "510598F6-83FE-4090-8986-793293E90480",
+            "sets": [
+              [
+                "29B6824A-5CB6-4C25-A359-727BAFEF25EB"
+              ],
+              [
+                "7E90963C-BE32-4411-B9DD-B02E7FE75766"
+              ],
+              [
+                "9373D62D-1BF0-4F17-B100-7C0FBE368ADE"
+              ]
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_nested_set.nested_set",
+            "mode": "managed",
+            "name": "nested_set",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "sets": [
+                [
+                  false,
+                  false
+                ],
+                [
+                  false
+                ],
+                []
+              ]
+            },
+            "type": "tfcoremock_nested_set",
+            "values": {
+              "id": "510598F6-83FE-4090-8986-793293E90480",
+              "sets": [
+                [
+                  "29B6824A-5CB6-4C25-A359-727BAFEF25EB",
+                  "7E90963C-BE32-4411-B9DD-B02E7FE75766"
+                ],
+                [
+                  "9373D62D-1BF0-4F17-B100-7C0FBE368ADE"
+                ],
+                []
+              ]
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_nested_set.nested_set",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "510598F6-83FE-4090-8986-793293E90480",
+          "sets": [
+            [
+              "29B6824A-5CB6-4C25-A359-727BAFEF25EB"
+            ],
+            [
+              "7E90963C-BE32-4411-B9DD-B02E7FE75766"
+            ],
+            [
+              "9373D62D-1BF0-4F17-B100-7C0FBE368ADE"
+            ]
+          ]
+        },
+        "after_sensitive": {
+          "sets": [
+            [
+              false
+            ],
+            [
+              false
+            ],
+            [
+              false
+            ]
+          ]
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "510598F6-83FE-4090-8986-793293E90480",
+          "sets": [
+            [
+              "29B6824A-5CB6-4C25-A359-727BAFEF25EB",
+              "7E90963C-BE32-4411-B9DD-B02E7FE75766"
+            ],
+            [
+              "9373D62D-1BF0-4F17-B100-7C0FBE368ADE"
+            ],
+            []
+          ]
+        },
+        "before_sensitive": {
+          "sets": [
+            [
+              false,
+              false
+            ],
+            [
+              false
+            ],
+            []
+          ]
+        }
+      },
+      "mode": "managed",
+      "name": "nested_set",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_nested_set"
+    }
+  ],
+  "timestamp": "2023-05-25T07:36:01Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_set_update/state b/v1.5.7/testing/equivalence-tests/outputs/nested_set_update/state
new file mode 100644
index 0000000..8e93cbe
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_set_update/state
@@ -0,0 +1,15 @@
+# tfcoremock_nested_set.nested_set:
+resource "tfcoremock_nested_set" "nested_set" {
+    id   = "510598F6-83FE-4090-8986-793293E90480"
+    sets = [
+        [
+            "29B6824A-5CB6-4C25-A359-727BAFEF25EB",
+        ],
+        [
+            "7E90963C-BE32-4411-B9DD-B02E7FE75766",
+        ],
+        [
+            "9373D62D-1BF0-4F17-B100-7C0FBE368ADE",
+        ],
+    ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/nested_set_update/state.json b/v1.5.7/testing/equivalence-tests/outputs/nested_set_update/state.json
new file mode 100644
index 0000000..a9d25b0
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/nested_set_update/state.json
@@ -0,0 +1,44 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_nested_set.nested_set",
+          "mode": "managed",
+          "name": "nested_set",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "sets": [
+              [
+                false
+              ],
+              [
+                false
+              ],
+              [
+                false
+              ]
+            ]
+          },
+          "type": "tfcoremock_nested_set",
+          "values": {
+            "id": "510598F6-83FE-4090-8986-793293E90480",
+            "sets": [
+              [
+                "29B6824A-5CB6-4C25-A359-727BAFEF25EB"
+              ],
+              [
+                "7E90963C-BE32-4411-B9DD-B02E7FE75766"
+              ],
+              [
+                "9373D62D-1BF0-4F17-B100-7C0FBE368ADE"
+              ]
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/null_provider_basic/apply.json b/v1.5.7/testing/equivalence-tests/outputs/null_provider_basic/apply.json
new file mode 100644
index 0000000..fc6c349
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/null_provider_basic/apply.json
@@ -0,0 +1,77 @@
+[
+  {
+    "@level": "info",
+    "@message": "null_resource.null_resource: Plan to create",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "create",
+      "resource": {
+        "addr": "null_resource.null_resource",
+        "implied_provider": "null",
+        "module": "",
+        "resource": "null_resource.null_resource",
+        "resource_key": null,
+        "resource_name": "null_resource",
+        "resource_type": "null_resource"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "null_resource.null_resource: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "null_resource.null_resource",
+        "implied_provider": "null",
+        "module": "",
+        "resource": "null_resource.null_resource",
+        "resource_key": null,
+        "resource_name": "null_resource",
+        "resource_type": "null_resource"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "resource": {
+        "addr": "null_resource.null_resource",
+        "implied_provider": "null",
+        "module": "",
+        "resource": "null_resource.null_resource",
+        "resource_key": null,
+        "resource_name": "null_resource",
+        "resource_type": "null_resource"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/null_provider_basic/plan b/v1.5.7/testing/equivalence-tests/outputs/null_provider_basic/plan
new file mode 100644
index 0000000..79e0f32
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/null_provider_basic/plan
@@ -0,0 +1,20 @@
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  # null_resource.null_resource will be created
+  + resource "null_resource" "null_resource" {
+      + id = (known after apply)
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/null_provider_basic/plan.json b/v1.5.7/testing/equivalence-tests/outputs/null_provider_basic/plan.json
new file mode 100644
index 0000000..ea0c513
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/null_provider_basic/plan.json
@@ -0,0 +1,66 @@
+{
+  "configuration": {
+    "provider_config": {
+      "null": {
+        "full_name": "registry.terraform.io/hashicorp/null",
+        "name": "null",
+        "version_constraint": "3.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "null_resource.null_resource",
+          "mode": "managed",
+          "name": "null_resource",
+          "provider_config_key": "null",
+          "schema_version": 0,
+          "type": "null_resource"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "null_resource.null_resource",
+          "mode": "managed",
+          "name": "null_resource",
+          "provider_name": "registry.terraform.io/hashicorp/null",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "null_resource",
+          "values": {
+            "triggers": null
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "null_resource.null_resource",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "after": {
+          "triggers": null
+        },
+        "after_sensitive": {},
+        "after_unknown": {
+          "id": true
+        },
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "managed",
+      "name": "null_resource",
+      "provider_name": "registry.terraform.io/hashicorp/null",
+      "type": "null_resource"
+    }
+  ],
+  "timestamp": "2023-05-25T07:36:03Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/null_provider_basic/state b/v1.5.7/testing/equivalence-tests/outputs/null_provider_basic/state
new file mode 100644
index 0000000..ccb8bea
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/null_provider_basic/state
@@ -0,0 +1,4 @@
+# null_resource.null_resource:
+resource "null_resource" "null_resource" {
+    id = "1302794772536339462"
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/null_provider_basic/state.json b/v1.5.7/testing/equivalence-tests/outputs/null_provider_basic/state.json
new file mode 100644
index 0000000..cf3dc58
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/null_provider_basic/state.json
@@ -0,0 +1,21 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "null_resource.null_resource",
+          "mode": "managed",
+          "name": "null_resource",
+          "provider_name": "registry.terraform.io/hashicorp/null",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "null_resource",
+          "values": {
+            "triggers": null
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/null_provider_delete/apply.json b/v1.5.7/testing/equivalence-tests/outputs/null_provider_delete/apply.json
new file mode 100644
index 0000000..3c8364b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/null_provider_delete/apply.json
@@ -0,0 +1,80 @@
+[
+  {
+    "@level": "info",
+    "@message": "null_resource.null_resource: Plan to delete",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "delete",
+      "reason": "delete_because_no_resource_config",
+      "resource": {
+        "addr": "null_resource.null_resource",
+        "implied_provider": "null",
+        "module": "",
+        "resource": "null_resource.null_resource",
+        "resource_key": null,
+        "resource_name": "null_resource",
+        "resource_type": "null_resource"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "null_resource.null_resource: Destroying... [id=7115293105928418144]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "id_key": "id",
+      "id_value": "7115293105928418144",
+      "resource": {
+        "addr": "null_resource.null_resource",
+        "implied_provider": "null",
+        "module": "",
+        "resource": "null_resource.null_resource",
+        "resource_key": null,
+        "resource_name": "null_resource",
+        "resource_type": "null_resource"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "null_resource.null_resource: Destruction complete after 0s",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "elapsed_seconds": 0,
+      "resource": {
+        "addr": "null_resource.null_resource",
+        "implied_provider": "null",
+        "module": "",
+        "resource": "null_resource.null_resource",
+        "resource_key": null,
+        "resource_name": "null_resource",
+        "resource_type": "null_resource"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 0 changed, 1 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 1
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/null_provider_delete/plan b/v1.5.7/testing/equivalence-tests/outputs/null_provider_delete/plan
new file mode 100644
index 0000000..4c799e4
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/null_provider_delete/plan
@@ -0,0 +1,22 @@
+null_resource.null_resource: Refreshing state... [id=7115293105928418144]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  - destroy
+
+Terraform will perform the following actions:
+
+  # null_resource.null_resource will be destroyed
+  # (because null_resource.null_resource is not in configuration)
+  - resource "null_resource" "null_resource" {
+      - id = "7115293105928418144" -> null
+    }
+
+Plan: 0 to add, 0 to change, 1 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/null_provider_delete/plan.json b/v1.5.7/testing/equivalence-tests/outputs/null_provider_delete/plan.json
new file mode 100644
index 0000000..56c2a5b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/null_provider_delete/plan.json
@@ -0,0 +1,62 @@
+{
+  "configuration": {
+    "provider_config": {
+      "null": {
+        "full_name": "registry.terraform.io/hashicorp/null",
+        "name": "null",
+        "version_constraint": "3.1.1"
+      }
+    },
+    "root_module": {}
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {}
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "null_resource.null_resource",
+            "mode": "managed",
+            "name": "null_resource",
+            "provider_name": "registry.terraform.io/hashicorp/null",
+            "schema_version": 0,
+            "sensitive_values": {},
+            "type": "null_resource",
+            "values": {
+              "id": "7115293105928418144",
+              "triggers": null
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "action_reason": "delete_because_no_resource_config",
+      "address": "null_resource.null_resource",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "after": null,
+        "after_sensitive": false,
+        "after_unknown": {},
+        "before": {
+          "id": "7115293105928418144",
+          "triggers": null
+        },
+        "before_sensitive": {}
+      },
+      "mode": "managed",
+      "name": "null_resource",
+      "provider_name": "registry.terraform.io/hashicorp/null",
+      "type": "null_resource"
+    }
+  ],
+  "timestamp": "2023-05-25T07:36:05Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/null_provider_delete/state b/v1.5.7/testing/equivalence-tests/outputs/null_provider_delete/state
new file mode 100644
index 0000000..222a60b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/null_provider_delete/state
@@ -0,0 +1 @@
+The state file is empty. No resources are represented.
diff --git a/v1.5.7/testing/equivalence-tests/outputs/null_provider_delete/state.json b/v1.5.7/testing/equivalence-tests/outputs/null_provider_delete/state.json
new file mode 100644
index 0000000..00f8f1c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/null_provider_delete/state.json
@@ -0,0 +1,3 @@
+{
+  "format_version": "1.0"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_list/apply.json b/v1.5.7/testing/equivalence-tests/outputs/replace_within_list/apply.json
new file mode 100644
index 0000000..8ea8b6e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_list/apply.json
@@ -0,0 +1,119 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Plan to replace",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "replace",
+      "reason": "cannot_update",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Destroying... [id=F40F2AB4-100C-4AE8-BFD0-BF332A158415]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "id_key": "id",
+      "id_value": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Destruction complete after 0s",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "elapsed_seconds": 0,
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_list.list: Creation complete after 0s [id=F40F2AB4-100C-4AE8-BFD0-BF332A158415]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+      "resource": {
+        "addr": "tfcoremock_list.list",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_list.list",
+        "resource_key": null,
+        "resource_name": "list",
+        "resource_type": "tfcoremock_list"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 1 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 1
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_list/plan b/v1.5.7/testing/equivalence-tests/outputs/replace_within_list/plan
new file mode 100644
index 0000000..e5c73a3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_list/plan
@@ -0,0 +1,27 @@
+tfcoremock_list.list: Refreshing state... [id=F40F2AB4-100C-4AE8-BFD0-BF332A158415]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+-/+ destroy and then create replacement
+
+Terraform will perform the following actions:
+
+  # tfcoremock_list.list must be replaced
+-/+ resource "tfcoremock_list" "list" {
+        id   = "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+      ~ list = [
+          ~ {
+              ~ id = "6A8C6A29-D417-480A-BE19-12D7398B3178" -> "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9" # forces replacement
+            },
+            # (2 unchanged elements hidden)
+        ]
+    }
+
+Plan: 1 to add, 0 to change, 1 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_list/plan.json b/v1.5.7/testing/equivalence-tests/outputs/replace_within_list/plan.json
new file mode 100644
index 0000000..08bdd49
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_list/plan.json
@@ -0,0 +1,182 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_list.list",
+          "expressions": {
+            "id": {
+              "constant_value": "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+            },
+            "list": {
+              "constant_value": [
+                {
+                  "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+                },
+                {
+                  "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+                },
+                {
+                  "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+                }
+              ]
+            }
+          },
+          "mode": "managed",
+          "name": "list",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_list"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_list.list",
+          "mode": "managed",
+          "name": "list",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "list": [
+              {},
+              {},
+              {}
+            ]
+          },
+          "type": "tfcoremock_list",
+          "values": {
+            "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+            "list": [
+              {
+                "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+              },
+              {
+                "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+              },
+              {
+                "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+              }
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_list.list",
+            "mode": "managed",
+            "name": "list",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "list": [
+                {},
+                {},
+                {}
+              ]
+            },
+            "type": "tfcoremock_list",
+            "values": {
+              "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+              "list": [
+                {
+                  "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+                },
+                {
+                  "id": "6A8C6A29-D417-480A-BE19-12D7398B3178"
+                },
+                {
+                  "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+                }
+              ]
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "action_reason": "replace_because_cannot_update",
+      "address": "tfcoremock_list.list",
+      "change": {
+        "actions": [
+          "delete",
+          "create"
+        ],
+        "after": {
+          "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+          "list": [
+            {
+              "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+            },
+            {
+              "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+            },
+            {
+              "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+            }
+          ]
+        },
+        "after_sensitive": {
+          "list": [
+            {},
+            {},
+            {}
+          ]
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+          "list": [
+            {
+              "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+            },
+            {
+              "id": "6A8C6A29-D417-480A-BE19-12D7398B3178"
+            },
+            {
+              "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+            }
+          ]
+        },
+        "before_sensitive": {
+          "list": [
+            {},
+            {},
+            {}
+          ]
+        },
+        "replace_paths": [
+          [
+            "list",
+            1,
+            "id"
+          ]
+        ]
+      },
+      "mode": "managed",
+      "name": "list",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_list"
+    }
+  ],
+  "timestamp": "2023-05-25T07:36:07Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_list/state b/v1.5.7/testing/equivalence-tests/outputs/replace_within_list/state
new file mode 100644
index 0000000..6f162b1
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_list/state
@@ -0,0 +1,15 @@
+# tfcoremock_list.list:
+resource "tfcoremock_list" "list" {
+    id   = "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+    list = [
+        {
+            id = "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+        },
+        {
+            id = "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+        },
+        {
+            id = "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+        },
+    ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_list/state.json b/v1.5.7/testing/equivalence-tests/outputs/replace_within_list/state.json
new file mode 100644
index 0000000..b4a486b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_list/state.json
@@ -0,0 +1,38 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_list.list",
+          "mode": "managed",
+          "name": "list",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "list": [
+              {},
+              {},
+              {}
+            ]
+          },
+          "type": "tfcoremock_list",
+          "values": {
+            "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+            "list": [
+              {
+                "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+              },
+              {
+                "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+              },
+              {
+                "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+              }
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_map/apply.json b/v1.5.7/testing/equivalence-tests/outputs/replace_within_map/apply.json
new file mode 100644
index 0000000..0723cca
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_map/apply.json
@@ -0,0 +1,119 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Plan to replace",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "replace",
+      "reason": "cannot_update",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Destroying... [id=F40F2AB4-100C-4AE8-BFD0-BF332A158415]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "id_key": "id",
+      "id_value": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Destruction complete after 0s",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "elapsed_seconds": 0,
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_map.map: Creation complete after 0s [id=F40F2AB4-100C-4AE8-BFD0-BF332A158415]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+      "resource": {
+        "addr": "tfcoremock_map.map",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_map.map",
+        "resource_key": null,
+        "resource_name": "map",
+        "resource_type": "tfcoremock_map"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 1 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 1
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_map/plan b/v1.5.7/testing/equivalence-tests/outputs/replace_within_map/plan
new file mode 100644
index 0000000..46ab58c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_map/plan
@@ -0,0 +1,27 @@
+tfcoremock_map.map: Refreshing state... [id=F40F2AB4-100C-4AE8-BFD0-BF332A158415]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+-/+ destroy and then create replacement
+
+Terraform will perform the following actions:
+
+  # tfcoremock_map.map must be replaced
+-/+ resource "tfcoremock_map" "map" {
+        id  = "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+      ~ map = {
+          ~ "key_two" = {
+              ~ id = "56C7E07F-B9DF-4799-AF62-E703D1167A51" -> "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9" # forces replacement
+            },
+            # (2 unchanged elements hidden)
+        }
+    }
+
+Plan: 1 to add, 0 to change, 1 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_map/plan.json b/v1.5.7/testing/equivalence-tests/outputs/replace_within_map/plan.json
new file mode 100644
index 0000000..b518bc3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_map/plan.json
@@ -0,0 +1,182 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_map.map",
+          "expressions": {
+            "id": {
+              "constant_value": "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+            },
+            "map": {
+              "constant_value": {
+                "key_one": {
+                  "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+                },
+                "key_three": {
+                  "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+                },
+                "key_two": {
+                  "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+                }
+              }
+            }
+          },
+          "mode": "managed",
+          "name": "map",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_map"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_map.map",
+          "mode": "managed",
+          "name": "map",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "map": {
+              "key_one": {},
+              "key_three": {},
+              "key_two": {}
+            }
+          },
+          "type": "tfcoremock_map",
+          "values": {
+            "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+            "map": {
+              "key_one": {
+                "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+              },
+              "key_three": {
+                "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+              },
+              "key_two": {
+                "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+              }
+            }
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_map.map",
+            "mode": "managed",
+            "name": "map",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "map": {
+                "key_one": {},
+                "key_three": {},
+                "key_two": {}
+              }
+            },
+            "type": "tfcoremock_map",
+            "values": {
+              "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+              "map": {
+                "key_one": {
+                  "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+                },
+                "key_three": {
+                  "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+                },
+                "key_two": {
+                  "id": "56C7E07F-B9DF-4799-AF62-E703D1167A51"
+                }
+              }
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "action_reason": "replace_because_cannot_update",
+      "address": "tfcoremock_map.map",
+      "change": {
+        "actions": [
+          "delete",
+          "create"
+        ],
+        "after": {
+          "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+          "map": {
+            "key_one": {
+              "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+            },
+            "key_three": {
+              "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+            },
+            "key_two": {
+              "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+            }
+          }
+        },
+        "after_sensitive": {
+          "map": {
+            "key_one": {},
+            "key_three": {},
+            "key_two": {}
+          }
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+          "map": {
+            "key_one": {
+              "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+            },
+            "key_three": {
+              "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+            },
+            "key_two": {
+              "id": "56C7E07F-B9DF-4799-AF62-E703D1167A51"
+            }
+          }
+        },
+        "before_sensitive": {
+          "map": {
+            "key_one": {},
+            "key_three": {},
+            "key_two": {}
+          }
+        },
+        "replace_paths": [
+          [
+            "map",
+            "key_two",
+            "id"
+          ]
+        ]
+      },
+      "mode": "managed",
+      "name": "map",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_map"
+    }
+  ],
+  "timestamp": "2023-05-25T07:36:09Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_map/state b/v1.5.7/testing/equivalence-tests/outputs/replace_within_map/state
new file mode 100644
index 0000000..f6f1b2c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_map/state
@@ -0,0 +1,15 @@
+# tfcoremock_map.map:
+resource "tfcoremock_map" "map" {
+    id  = "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+    map = {
+        "key_one" = {
+            id = "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+        },
+        "key_three" = {
+            id = "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+        },
+        "key_two" = {
+            id = "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+        },
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_map/state.json b/v1.5.7/testing/equivalence-tests/outputs/replace_within_map/state.json
new file mode 100644
index 0000000..02fae77
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_map/state.json
@@ -0,0 +1,38 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_map.map",
+          "mode": "managed",
+          "name": "map",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "map": {
+              "key_one": {},
+              "key_three": {},
+              "key_two": {}
+            }
+          },
+          "type": "tfcoremock_map",
+          "values": {
+            "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+            "map": {
+              "key_one": {
+                "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+              },
+              "key_three": {
+                "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+              },
+              "key_two": {
+                "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+              }
+            }
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_object/apply.json b/v1.5.7/testing/equivalence-tests/outputs/replace_within_object/apply.json
new file mode 100644
index 0000000..65ddae9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_object/apply.json
@@ -0,0 +1,119 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Plan to replace",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "replace",
+      "reason": "cannot_update",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Destroying... [id=F40F2AB4-100C-4AE8-BFD0-BF332A158415]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "id_key": "id",
+      "id_value": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Destruction complete after 0s",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "elapsed_seconds": 0,
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Creation complete after 0s [id=F40F2AB4-100C-4AE8-BFD0-BF332A158415]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 1 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 1
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_object/plan b/v1.5.7/testing/equivalence-tests/outputs/replace_within_object/plan
new file mode 100644
index 0000000..2df539c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_object/plan
@@ -0,0 +1,24 @@
+tfcoremock_object.object: Refreshing state... [id=F40F2AB4-100C-4AE8-BFD0-BF332A158415]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+-/+ destroy and then create replacement
+
+Terraform will perform the following actions:
+
+  # tfcoremock_object.object must be replaced
+-/+ resource "tfcoremock_object" "object" {
+        id     = "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+      ~ object = {
+          ~ id = "56C7E07F-B9DF-4799-AF62-E703D1167A51" -> "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9" # forces replacement
+        }
+    }
+
+Plan: 1 to add, 0 to change, 1 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_object/plan.json b/v1.5.7/testing/equivalence-tests/outputs/replace_within_object/plan.json
new file mode 100644
index 0000000..22ca69a
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_object/plan.json
@@ -0,0 +1,125 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "expressions": {
+            "id": {
+              "constant_value": "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+            },
+            "object": {
+              "constant_value": {
+                "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+              }
+            }
+          },
+          "mode": "managed",
+          "name": "object",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_object"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "mode": "managed",
+          "name": "object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "object": {}
+          },
+          "type": "tfcoremock_object",
+          "values": {
+            "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+            "object": {
+              "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+            }
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_object.object",
+            "mode": "managed",
+            "name": "object",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "object": {}
+            },
+            "type": "tfcoremock_object",
+            "values": {
+              "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+              "object": {
+                "id": "56C7E07F-B9DF-4799-AF62-E703D1167A51"
+              }
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "action_reason": "replace_because_cannot_update",
+      "address": "tfcoremock_object.object",
+      "change": {
+        "actions": [
+          "delete",
+          "create"
+        ],
+        "after": {
+          "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+          "object": {
+            "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+          }
+        },
+        "after_sensitive": {
+          "object": {}
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+          "object": {
+            "id": "56C7E07F-B9DF-4799-AF62-E703D1167A51"
+          }
+        },
+        "before_sensitive": {
+          "object": {}
+        },
+        "replace_paths": [
+          [
+            "object",
+            "id"
+          ]
+        ]
+      },
+      "mode": "managed",
+      "name": "object",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_object"
+    }
+  ],
+  "timestamp": "2023-05-25T07:36:11Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_object/state b/v1.5.7/testing/equivalence-tests/outputs/replace_within_object/state
new file mode 100644
index 0000000..14a420e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_object/state
@@ -0,0 +1,7 @@
+# tfcoremock_object.object:
+resource "tfcoremock_object" "object" {
+    id     = "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+    object = {
+        id = "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_object/state.json b/v1.5.7/testing/equivalence-tests/outputs/replace_within_object/state.json
new file mode 100644
index 0000000..a2f7433
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_object/state.json
@@ -0,0 +1,26 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "mode": "managed",
+          "name": "object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "object": {}
+          },
+          "type": "tfcoremock_object",
+          "values": {
+            "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+            "object": {
+              "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+            }
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_set/apply.json b/v1.5.7/testing/equivalence-tests/outputs/replace_within_set/apply.json
new file mode 100644
index 0000000..57c5530
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_set/apply.json
@@ -0,0 +1,119 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Plan to replace",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "replace",
+      "reason": "cannot_update",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Destroying... [id=F40F2AB4-100C-4AE8-BFD0-BF332A158415]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "id_key": "id",
+      "id_value": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Destruction complete after 0s",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "elapsed_seconds": 0,
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_set.set: Creation complete after 0s [id=F40F2AB4-100C-4AE8-BFD0-BF332A158415]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+      "resource": {
+        "addr": "tfcoremock_set.set",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_set.set",
+        "resource_key": null,
+        "resource_name": "set",
+        "resource_type": "tfcoremock_set"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 1 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 1
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_set/plan b/v1.5.7/testing/equivalence-tests/outputs/replace_within_set/plan
new file mode 100644
index 0000000..252d0b4
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_set/plan
@@ -0,0 +1,30 @@
+tfcoremock_set.set: Refreshing state... [id=F40F2AB4-100C-4AE8-BFD0-BF332A158415]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+-/+ destroy and then create replacement
+
+Terraform will perform the following actions:
+
+  # tfcoremock_set.set must be replaced
+-/+ resource "tfcoremock_set" "set" {
+        id  = "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+      ~ set = [
+          - { # forces replacement
+              - id = "56C7E07F-B9DF-4799-AF62-E703D1167A51" -> null
+            },
+          + { # forces replacement
+              + id = "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+            },
+            # (2 unchanged elements hidden)
+        ]
+    }
+
+Plan: 1 to add, 0 to change, 1 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_set/plan.json b/v1.5.7/testing/equivalence-tests/outputs/replace_within_set/plan.json
new file mode 100644
index 0000000..40700b6
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_set/plan.json
@@ -0,0 +1,180 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_set.set",
+          "expressions": {
+            "id": {
+              "constant_value": "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+            },
+            "set": {
+              "constant_value": [
+                {
+                  "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+                },
+                {
+                  "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+                },
+                {
+                  "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+                }
+              ]
+            }
+          },
+          "mode": "managed",
+          "name": "set",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_set"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_set.set",
+          "mode": "managed",
+          "name": "set",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "set": [
+              {},
+              {},
+              {}
+            ]
+          },
+          "type": "tfcoremock_set",
+          "values": {
+            "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+            "set": [
+              {
+                "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+              },
+              {
+                "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+              },
+              {
+                "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+              }
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_set.set",
+            "mode": "managed",
+            "name": "set",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "set": [
+                {},
+                {},
+                {}
+              ]
+            },
+            "type": "tfcoremock_set",
+            "values": {
+              "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+              "set": [
+                {
+                  "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+                },
+                {
+                  "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+                },
+                {
+                  "id": "56C7E07F-B9DF-4799-AF62-E703D1167A51"
+                }
+              ]
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "action_reason": "replace_because_cannot_update",
+      "address": "tfcoremock_set.set",
+      "change": {
+        "actions": [
+          "delete",
+          "create"
+        ],
+        "after": {
+          "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+          "set": [
+            {
+              "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+            },
+            {
+              "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+            },
+            {
+              "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+            }
+          ]
+        },
+        "after_sensitive": {
+          "set": [
+            {},
+            {},
+            {}
+          ]
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+          "set": [
+            {
+              "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+            },
+            {
+              "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+            },
+            {
+              "id": "56C7E07F-B9DF-4799-AF62-E703D1167A51"
+            }
+          ]
+        },
+        "before_sensitive": {
+          "set": [
+            {},
+            {},
+            {}
+          ]
+        },
+        "replace_paths": [
+          [
+            "set"
+          ]
+        ]
+      },
+      "mode": "managed",
+      "name": "set",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_set"
+    }
+  ],
+  "timestamp": "2023-05-25T07:36:13Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_set/state b/v1.5.7/testing/equivalence-tests/outputs/replace_within_set/state
new file mode 100644
index 0000000..1eabcb4
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_set/state
@@ -0,0 +1,15 @@
+# tfcoremock_set.set:
+resource "tfcoremock_set" "set" {
+    id  = "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+    set = [
+        {
+            id = "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+        },
+        {
+            id = "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+        },
+        {
+            id = "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+        },
+    ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/replace_within_set/state.json b/v1.5.7/testing/equivalence-tests/outputs/replace_within_set/state.json
new file mode 100644
index 0000000..992019e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/replace_within_set/state.json
@@ -0,0 +1,38 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_set.set",
+          "mode": "managed",
+          "name": "set",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "set": [
+              {},
+              {},
+              {}
+            ]
+          },
+          "type": "tfcoremock_set",
+          "values": {
+            "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+            "set": [
+              {
+                "id": "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+              },
+              {
+                "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+              },
+              {
+                "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+              }
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object/apply.json b/v1.5.7/testing/equivalence-tests/outputs/simple_object/apply.json
new file mode 100644
index 0000000..feb1234
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object/apply.json
@@ -0,0 +1,79 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Plan to create",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Creation complete after 0s [id=AF9833AE-3434-4D0B-8B69-F4B992565D9F]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "AF9833AE-3434-4D0B-8B69-F4B992565D9F",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object/plan b/v1.5.7/testing/equivalence-tests/outputs/simple_object/plan
new file mode 100644
index 0000000..9d5ef63
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object/plan
@@ -0,0 +1,25 @@
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  + create
+
+Terraform will perform the following actions:
+
+  # tfcoremock_object.object will be created
+  + resource "tfcoremock_object" "object" {
+      + id     = "AF9833AE-3434-4D0B-8B69-F4B992565D9F"
+      + object = {
+          + boolean = true
+          + number  = 10
+          + string  = "Hello, world!"
+        }
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object/plan.json b/v1.5.7/testing/equivalence-tests/outputs/simple_object/plan.json
new file mode 100644
index 0000000..f7b94fb
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object/plan.json
@@ -0,0 +1,90 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "expressions": {
+            "id": {
+              "constant_value": "AF9833AE-3434-4D0B-8B69-F4B992565D9F"
+            },
+            "object": {
+              "constant_value": {
+                "boolean": true,
+                "number": 10,
+                "string": "Hello, world!"
+              }
+            }
+          },
+          "mode": "managed",
+          "name": "object",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_object"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "mode": "managed",
+          "name": "object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "object": {}
+          },
+          "type": "tfcoremock_object",
+          "values": {
+            "id": "AF9833AE-3434-4D0B-8B69-F4B992565D9F",
+            "object": {
+              "boolean": true,
+              "number": 10,
+              "string": "Hello, world!"
+            }
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_object.object",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "after": {
+          "id": "AF9833AE-3434-4D0B-8B69-F4B992565D9F",
+          "object": {
+            "boolean": true,
+            "number": 10,
+            "string": "Hello, world!"
+          }
+        },
+        "after_sensitive": {
+          "object": {}
+        },
+        "after_unknown": {},
+        "before": null,
+        "before_sensitive": false
+      },
+      "mode": "managed",
+      "name": "object",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_object"
+    }
+  ],
+  "timestamp": "2023-05-25T07:36:15Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object/state b/v1.5.7/testing/equivalence-tests/outputs/simple_object/state
new file mode 100644
index 0000000..d3c0e21
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object/state
@@ -0,0 +1,9 @@
+# tfcoremock_object.object:
+resource "tfcoremock_object" "object" {
+    id     = "AF9833AE-3434-4D0B-8B69-F4B992565D9F"
+    object = {
+        boolean = true
+        number  = 10
+        string  = "Hello, world!"
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object/state.json b/v1.5.7/testing/equivalence-tests/outputs/simple_object/state.json
new file mode 100644
index 0000000..5f29ead
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object/state.json
@@ -0,0 +1,28 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "mode": "managed",
+          "name": "object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "object": {}
+          },
+          "type": "tfcoremock_object",
+          "values": {
+            "id": "AF9833AE-3434-4D0B-8B69-F4B992565D9F",
+            "object": {
+              "boolean": true,
+              "number": 10,
+              "string": "Hello, world!"
+            }
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_empty/apply.json b/v1.5.7/testing/equivalence-tests/outputs/simple_object_empty/apply.json
new file mode 100644
index 0000000..6071cb9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_empty/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Modifying... [id=00e14fba-4d56-6cc5-b685-633555376e3f]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "00e14fba-4d56-6cc5-b685-633555376e3f",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Modifications complete after 0s [id=00e14fba-4d56-6cc5-b685-633555376e3f]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "00e14fba-4d56-6cc5-b685-633555376e3f",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_empty/plan b/v1.5.7/testing/equivalence-tests/outputs/simple_object_empty/plan
new file mode 100644
index 0000000..2144d18
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_empty/plan
@@ -0,0 +1,26 @@
+tfcoremock_object.object: Refreshing state... [id=00e14fba-4d56-6cc5-b685-633555376e3f]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_object.object will be updated in-place
+  ~ resource "tfcoremock_object" "object" {
+        id     = "00e14fba-4d56-6cc5-b685-633555376e3f"
+      ~ object = {
+          - boolean = true -> null
+          - number  = 10 -> null
+          - string  = "Hello, world!" -> null
+        }
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_empty/plan.json b/v1.5.7/testing/equivalence-tests/outputs/simple_object_empty/plan.json
new file mode 100644
index 0000000..fc0081f
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_empty/plan.json
@@ -0,0 +1,120 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "expressions": {
+            "object": {
+              "constant_value": {}
+            }
+          },
+          "mode": "managed",
+          "name": "object",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_object"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "mode": "managed",
+          "name": "object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "object": {}
+          },
+          "type": "tfcoremock_object",
+          "values": {
+            "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+            "object": {
+              "boolean": null,
+              "number": null,
+              "string": null
+            }
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_object.object",
+            "mode": "managed",
+            "name": "object",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "object": {}
+            },
+            "type": "tfcoremock_object",
+            "values": {
+              "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+              "object": {
+                "boolean": true,
+                "number": 10,
+                "string": "Hello, world!"
+              }
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_object.object",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+          "object": {
+            "boolean": null,
+            "number": null,
+            "string": null
+          }
+        },
+        "after_sensitive": {
+          "object": {}
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+          "object": {
+            "boolean": true,
+            "number": 10,
+            "string": "Hello, world!"
+          }
+        },
+        "before_sensitive": {
+          "object": {}
+        }
+      },
+      "mode": "managed",
+      "name": "object",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_object"
+    }
+  ],
+  "timestamp": "2023-05-25T07:36:17Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_empty/state b/v1.5.7/testing/equivalence-tests/outputs/simple_object_empty/state
new file mode 100644
index 0000000..f31cb96
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_empty/state
@@ -0,0 +1,5 @@
+# tfcoremock_object.object:
+resource "tfcoremock_object" "object" {
+    id     = "00e14fba-4d56-6cc5-b685-633555376e3f"
+    object = {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_empty/state.json b/v1.5.7/testing/equivalence-tests/outputs/simple_object_empty/state.json
new file mode 100644
index 0000000..70d8405
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_empty/state.json
@@ -0,0 +1,28 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "mode": "managed",
+          "name": "object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "object": {}
+          },
+          "type": "tfcoremock_object",
+          "values": {
+            "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+            "object": {
+              "boolean": null,
+              "number": null,
+              "string": null
+            }
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_null/apply.json b/v1.5.7/testing/equivalence-tests/outputs/simple_object_null/apply.json
new file mode 100644
index 0000000..6071cb9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_null/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Modifying... [id=00e14fba-4d56-6cc5-b685-633555376e3f]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "00e14fba-4d56-6cc5-b685-633555376e3f",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Modifications complete after 0s [id=00e14fba-4d56-6cc5-b685-633555376e3f]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "00e14fba-4d56-6cc5-b685-633555376e3f",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_null/plan b/v1.5.7/testing/equivalence-tests/outputs/simple_object_null/plan
new file mode 100644
index 0000000..35d37fc
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_null/plan
@@ -0,0 +1,26 @@
+tfcoremock_object.object: Refreshing state... [id=00e14fba-4d56-6cc5-b685-633555376e3f]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_object.object will be updated in-place
+  ~ resource "tfcoremock_object" "object" {
+        id     = "00e14fba-4d56-6cc5-b685-633555376e3f"
+      - object = {
+          - boolean = true -> null
+          - number  = 10 -> null
+          - string  = "Hello, world!" -> null
+        } -> null
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_null/plan.json b/v1.5.7/testing/equivalence-tests/outputs/simple_object_null/plan.json
new file mode 100644
index 0000000..e6e34b4
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_null/plan.json
@@ -0,0 +1,103 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "mode": "managed",
+          "name": "object",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_object"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "mode": "managed",
+          "name": "object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_object",
+          "values": {
+            "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+            "object": null
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_object.object",
+            "mode": "managed",
+            "name": "object",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "object": {}
+            },
+            "type": "tfcoremock_object",
+            "values": {
+              "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+              "object": {
+                "boolean": true,
+                "number": 10,
+                "string": "Hello, world!"
+              }
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_object.object",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+          "object": null
+        },
+        "after_sensitive": {},
+        "after_unknown": {},
+        "before": {
+          "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+          "object": {
+            "boolean": true,
+            "number": 10,
+            "string": "Hello, world!"
+          }
+        },
+        "before_sensitive": {
+          "object": {}
+        }
+      },
+      "mode": "managed",
+      "name": "object",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_object"
+    }
+  ],
+  "timestamp": "2023-05-25T07:36:19Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_null/state b/v1.5.7/testing/equivalence-tests/outputs/simple_object_null/state
new file mode 100644
index 0000000..af3a89c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_null/state
@@ -0,0 +1,4 @@
+# tfcoremock_object.object:
+resource "tfcoremock_object" "object" {
+    id = "00e14fba-4d56-6cc5-b685-633555376e3f"
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_null/state.json b/v1.5.7/testing/equivalence-tests/outputs/simple_object_null/state.json
new file mode 100644
index 0000000..6101209
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_null/state.json
@@ -0,0 +1,22 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "mode": "managed",
+          "name": "object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {},
+          "type": "tfcoremock_object",
+          "values": {
+            "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+            "object": null
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_replace/apply.json b/v1.5.7/testing/equivalence-tests/outputs/simple_object_replace/apply.json
new file mode 100644
index 0000000..1084582
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_replace/apply.json
@@ -0,0 +1,119 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Plan to replace",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "replace",
+      "reason": "cannot_update",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Destroying... [id=a0ed13ec-116b-14c4-7437-418e217d3659]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "id_key": "id",
+      "id_value": "a0ed13ec-116b-14c4-7437-418e217d3659",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Destruction complete after 0s",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "delete",
+      "elapsed_seconds": 0,
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Creating...",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Creation complete after 0s [id=63A9E8E8-71BC-4DAE-A66C-48CE393CCBD3]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "create",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "63A9E8E8-71BC-4DAE-A66C-48CE393CCBD3",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 1 added, 0 changed, 1 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 1,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 1
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_replace/plan b/v1.5.7/testing/equivalence-tests/outputs/simple_object_replace/plan
new file mode 100644
index 0000000..cbd9712
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_replace/plan
@@ -0,0 +1,22 @@
+tfcoremock_object.object: Refreshing state... [id=a0ed13ec-116b-14c4-7437-418e217d3659]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+-/+ destroy and then create replacement
+
+Terraform will perform the following actions:
+
+  # tfcoremock_object.object must be replaced
+-/+ resource "tfcoremock_object" "object" {
+      ~ id     = "a0ed13ec-116b-14c4-7437-418e217d3659" -> "63A9E8E8-71BC-4DAE-A66C-48CE393CCBD3" # forces replacement
+        # (1 unchanged attribute hidden)
+    }
+
+Plan: 1 to add, 0 to change, 1 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_replace/plan.json b/v1.5.7/testing/equivalence-tests/outputs/simple_object_replace/plan.json
new file mode 100644
index 0000000..8dae830
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_replace/plan.json
@@ -0,0 +1,134 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "expressions": {
+            "id": {
+              "constant_value": "63A9E8E8-71BC-4DAE-A66C-48CE393CCBD3"
+            },
+            "object": {
+              "constant_value": {
+                "boolean": true,
+                "number": 10,
+                "string": "Hello, world!"
+              }
+            }
+          },
+          "mode": "managed",
+          "name": "object",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_object"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "mode": "managed",
+          "name": "object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "object": {}
+          },
+          "type": "tfcoremock_object",
+          "values": {
+            "id": "63A9E8E8-71BC-4DAE-A66C-48CE393CCBD3",
+            "object": {
+              "boolean": true,
+              "number": 10,
+              "string": "Hello, world!"
+            }
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_object.object",
+            "mode": "managed",
+            "name": "object",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "object": {}
+            },
+            "type": "tfcoremock_object",
+            "values": {
+              "id": "a0ed13ec-116b-14c4-7437-418e217d3659",
+              "object": {
+                "boolean": true,
+                "number": 10,
+                "string": "Hello, world!"
+              }
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "action_reason": "replace_because_cannot_update",
+      "address": "tfcoremock_object.object",
+      "change": {
+        "actions": [
+          "delete",
+          "create"
+        ],
+        "after": {
+          "id": "63A9E8E8-71BC-4DAE-A66C-48CE393CCBD3",
+          "object": {
+            "boolean": true,
+            "number": 10,
+            "string": "Hello, world!"
+          }
+        },
+        "after_sensitive": {
+          "object": {}
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "a0ed13ec-116b-14c4-7437-418e217d3659",
+          "object": {
+            "boolean": true,
+            "number": 10,
+            "string": "Hello, world!"
+          }
+        },
+        "before_sensitive": {
+          "object": {}
+        },
+        "replace_paths": [
+          [
+            "id"
+          ]
+        ]
+      },
+      "mode": "managed",
+      "name": "object",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_object"
+    }
+  ],
+  "timestamp": "2023-05-25T07:36:20Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_replace/state b/v1.5.7/testing/equivalence-tests/outputs/simple_object_replace/state
new file mode 100644
index 0000000..4540928
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_replace/state
@@ -0,0 +1,9 @@
+# tfcoremock_object.object:
+resource "tfcoremock_object" "object" {
+    id     = "63A9E8E8-71BC-4DAE-A66C-48CE393CCBD3"
+    object = {
+        boolean = true
+        number  = 10
+        string  = "Hello, world!"
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_replace/state.json b/v1.5.7/testing/equivalence-tests/outputs/simple_object_replace/state.json
new file mode 100644
index 0000000..abdc14a
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_replace/state.json
@@ -0,0 +1,28 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "mode": "managed",
+          "name": "object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "object": {}
+          },
+          "type": "tfcoremock_object",
+          "values": {
+            "id": "63A9E8E8-71BC-4DAE-A66C-48CE393CCBD3",
+            "object": {
+              "boolean": true,
+              "number": 10,
+              "string": "Hello, world!"
+            }
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_update/apply.json b/v1.5.7/testing/equivalence-tests/outputs/simple_object_update/apply.json
new file mode 100644
index 0000000..6071cb9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_update/apply.json
@@ -0,0 +1,81 @@
+[
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Plan to update",
+    "@module": "terraform.ui",
+    "change": {
+      "action": "update",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "planned_change"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Modifying... [id=00e14fba-4d56-6cc5-b685-633555376e3f]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "id_key": "id",
+      "id_value": "00e14fba-4d56-6cc5-b685-633555376e3f",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_start"
+  },
+  {
+    "@level": "info",
+    "@message": "tfcoremock_object.object: Modifications complete after 0s [id=00e14fba-4d56-6cc5-b685-633555376e3f]",
+    "@module": "terraform.ui",
+    "hook": {
+      "action": "update",
+      "elapsed_seconds": 0,
+      "id_key": "id",
+      "id_value": "00e14fba-4d56-6cc5-b685-633555376e3f",
+      "resource": {
+        "addr": "tfcoremock_object.object",
+        "implied_provider": "tfcoremock",
+        "module": "",
+        "resource": "tfcoremock_object.object",
+        "resource_key": null,
+        "resource_name": "object",
+        "resource_type": "tfcoremock_object"
+      }
+    },
+    "type": "apply_complete"
+  },
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 1 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 1,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 0",
+    "@module": "terraform.ui",
+    "outputs": {},
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_update/plan b/v1.5.7/testing/equivalence-tests/outputs/simple_object_update/plan
new file mode 100644
index 0000000..0e1e6e1
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_update/plan
@@ -0,0 +1,26 @@
+tfcoremock_object.object: Refreshing state... [id=00e14fba-4d56-6cc5-b685-633555376e3f]
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
+  ~ update in-place
+
+Terraform will perform the following actions:
+
+  # tfcoremock_object.object will be updated in-place
+  ~ resource "tfcoremock_object" "object" {
+        id     = "00e14fba-4d56-6cc5-b685-633555376e3f"
+      ~ object = {
+          ~ boolean = true -> false
+          ~ number  = 10 -> 2
+          ~ string  = "Hello, world!" -> "Hello, a totally different world!"
+        }
+    }
+
+Plan: 0 to add, 1 to change, 0 to destroy.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_update/plan.json b/v1.5.7/testing/equivalence-tests/outputs/simple_object_update/plan.json
new file mode 100644
index 0000000..05ce21f
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_update/plan.json
@@ -0,0 +1,124 @@
+{
+  "configuration": {
+    "provider_config": {
+      "tfcoremock": {
+        "full_name": "registry.terraform.io/hashicorp/tfcoremock",
+        "name": "tfcoremock",
+        "version_constraint": "0.1.1"
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "expressions": {
+            "object": {
+              "constant_value": {
+                "boolean": false,
+                "number": 2,
+                "string": "Hello, a totally different world!"
+              }
+            }
+          },
+          "mode": "managed",
+          "name": "object",
+          "provider_config_key": "tfcoremock",
+          "schema_version": 0,
+          "type": "tfcoremock_object"
+        }
+      ]
+    }
+  },
+  "format_version": "1.2",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "mode": "managed",
+          "name": "object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "object": {}
+          },
+          "type": "tfcoremock_object",
+          "values": {
+            "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+            "object": {
+              "boolean": false,
+              "number": 2,
+              "string": "Hello, a totally different world!"
+            }
+          }
+        }
+      ]
+    }
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "tfcoremock_object.object",
+            "mode": "managed",
+            "name": "object",
+            "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+            "schema_version": 0,
+            "sensitive_values": {
+              "object": {}
+            },
+            "type": "tfcoremock_object",
+            "values": {
+              "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+              "object": {
+                "boolean": true,
+                "number": 10,
+                "string": "Hello, world!"
+              }
+            }
+          }
+        ]
+      }
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "tfcoremock_object.object",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "after": {
+          "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+          "object": {
+            "boolean": false,
+            "number": 2,
+            "string": "Hello, a totally different world!"
+          }
+        },
+        "after_sensitive": {
+          "object": {}
+        },
+        "after_unknown": {},
+        "before": {
+          "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+          "object": {
+            "boolean": true,
+            "number": 10,
+            "string": "Hello, world!"
+          }
+        },
+        "before_sensitive": {
+          "object": {}
+        }
+      },
+      "mode": "managed",
+      "name": "object",
+      "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+      "type": "tfcoremock_object"
+    }
+  ],
+  "timestamp": "2023-05-25T07:36:22Z"
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_update/state b/v1.5.7/testing/equivalence-tests/outputs/simple_object_update/state
new file mode 100644
index 0000000..efa6c14
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_update/state
@@ -0,0 +1,9 @@
+# tfcoremock_object.object:
+resource "tfcoremock_object" "object" {
+    id     = "00e14fba-4d56-6cc5-b685-633555376e3f"
+    object = {
+        boolean = false
+        number  = 2
+        string  = "Hello, a totally different world!"
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/simple_object_update/state.json b/v1.5.7/testing/equivalence-tests/outputs/simple_object_update/state.json
new file mode 100644
index 0000000..8640460
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/simple_object_update/state.json
@@ -0,0 +1,28 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "tfcoremock_object.object",
+          "mode": "managed",
+          "name": "object",
+          "provider_name": "registry.terraform.io/hashicorp/tfcoremock",
+          "schema_version": 0,
+          "sensitive_values": {
+            "object": {}
+          },
+          "type": "tfcoremock_object",
+          "values": {
+            "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+            "object": {
+              "boolean": false,
+              "number": 2,
+              "string": "Hello, a totally different world!"
+            }
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/variables_and_outputs/apply.json b/v1.5.7/testing/equivalence-tests/outputs/variables_and_outputs/apply.json
new file mode 100644
index 0000000..2f267f8
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/variables_and_outputs/apply.json
@@ -0,0 +1,124 @@
+[
+  {
+    "@level": "info",
+    "@message": "Apply complete! Resources: 0 added, 0 changed, 0 destroyed.",
+    "@module": "terraform.ui",
+    "changes": {
+      "add": 0,
+      "change": 0,
+      "import": 0,
+      "operation": "apply",
+      "remove": 0
+    },
+    "type": "change_summary"
+  },
+  {
+    "@level": "info",
+    "@message": "Outputs: 5",
+    "@module": "terraform.ui",
+    "outputs": {
+      "list_empty_default": {
+        "sensitive": false,
+        "type": [
+          "list",
+          [
+            "object",
+            {
+              "optional_attribute": "string",
+              "optional_attribute_with_default": "string",
+              "required_attribute": "string"
+            }
+          ]
+        ],
+        "value": []
+      },
+      "list_no_default": {
+        "sensitive": false,
+        "type": [
+          "list",
+          [
+            "object",
+            {
+              "optional_attribute": "string",
+              "optional_attribute_with_default": "string",
+              "required_attribute": "string"
+            }
+          ]
+        ],
+        "value": [
+          {
+            "optional_attribute": null,
+            "optional_attribute_with_default": "Hello, world!",
+            "required_attribute": "D92053D5-948A-4E5E-80BF-E53F0DB33EB5"
+          },
+          {
+            "optional_attribute": "8AC4B9EE-9E05-4AE0-AA35-6D7636AEA487",
+            "optional_attribute_with_default": "Hello, world!",
+            "required_attribute": "E6DA6176-49FB-46D6-9ECD-401B3F46A3E5"
+          },
+          {
+            "optional_attribute": "E68C1EB0-3D3D-4DB0-A41D-0F8C334E181C",
+            "optional_attribute_with_default": "92E855B2-A444-49DF-AFCA-2B5B017451B4",
+            "required_attribute": "9F9922C4-B426-4648-96AE-804A6F52F778"
+          }
+        ]
+      },
+      "nested_optional_object": {
+        "sensitive": false,
+        "type": [
+          "object",
+          {
+            "nested_object": [
+              "object",
+              {
+                "flag": "bool"
+              }
+            ]
+          }
+        ],
+        "value": {
+          "nested_object": null
+        }
+      },
+      "nested_optional_object_with_default": {
+        "sensitive": false,
+        "type": [
+          "object",
+          {
+            "nested_object": [
+              "object",
+              {
+                "flag": "bool"
+              }
+            ]
+          }
+        ],
+        "value": {
+          "nested_object": {
+            "flag": false
+          }
+        }
+      },
+      "nested_optional_object_with_embedded_default": {
+        "sensitive": false,
+        "type": [
+          "object",
+          {
+            "nested_object": [
+              "object",
+              {
+                "flag": "bool"
+              }
+            ]
+          }
+        ],
+        "value": {
+          "nested_object": {
+            "flag": false
+          }
+        }
+      }
+    },
+    "type": "outputs"
+  }
+]
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/variables_and_outputs/plan b/v1.5.7/testing/equivalence-tests/outputs/variables_and_outputs/plan
new file mode 100644
index 0000000..8b8a9f0
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/variables_and_outputs/plan
@@ -0,0 +1,43 @@
+
+Changes to Outputs:
+  + list_empty_default                           = []
+  + list_no_default                              = [
+      + {
+          + optional_attribute              = null
+          + optional_attribute_with_default = "Hello, world!"
+          + required_attribute              = "D92053D5-948A-4E5E-80BF-E53F0DB33EB5"
+        },
+      + {
+          + optional_attribute              = "8AC4B9EE-9E05-4AE0-AA35-6D7636AEA487"
+          + optional_attribute_with_default = "Hello, world!"
+          + required_attribute              = "E6DA6176-49FB-46D6-9ECD-401B3F46A3E5"
+        },
+      + {
+          + optional_attribute              = "E68C1EB0-3D3D-4DB0-A41D-0F8C334E181C"
+          + optional_attribute_with_default = "92E855B2-A444-49DF-AFCA-2B5B017451B4"
+          + required_attribute              = "9F9922C4-B426-4648-96AE-804A6F52F778"
+        },
+    ]
+  + nested_optional_object                       = {
+      + nested_object = null
+    }
+  + nested_optional_object_with_default          = {
+      + nested_object = {
+          + flag = false
+        }
+    }
+  + nested_optional_object_with_embedded_default = {
+      + nested_object = {
+          + flag = false
+        }
+    }
+
+You can apply this plan to save these new output values to the Terraform
+state, without changing any real infrastructure.
+
+─────────────────────────────────────────────────────────────────────────────
+
+Saved the plan to: equivalence_test_plan
+
+To perform exactly these actions, run the following command to apply:
+    terraform apply "equivalence_test_plan"
diff --git a/v1.5.7/testing/equivalence-tests/outputs/variables_and_outputs/plan.json b/v1.5.7/testing/equivalence-tests/outputs/variables_and_outputs/plan.json
new file mode 100644
index 0000000..8198551
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/variables_and_outputs/plan.json
@@ -0,0 +1,403 @@
+{
+  "configuration": {
+    "root_module": {
+      "outputs": {
+        "list_empty_default": {
+          "expression": {
+            "references": [
+              "var.list_empty_default"
+            ]
+          }
+        },
+        "list_no_default": {
+          "expression": {
+            "references": [
+              "var.list_no_default"
+            ]
+          }
+        },
+        "nested_optional_object": {
+          "expression": {
+            "references": [
+              "var.nested_optional_object"
+            ]
+          }
+        },
+        "nested_optional_object_with_default": {
+          "expression": {
+            "references": [
+              "var.nested_optional_object_with_default"
+            ]
+          }
+        },
+        "nested_optional_object_with_embedded_default": {
+          "expression": {
+            "references": [
+              "var.nested_optional_object_with_embedded_default"
+            ]
+          }
+        }
+      },
+      "variables": {
+        "list_empty_default": {
+          "default": []
+        },
+        "list_no_default": {},
+        "nested_optional_object": {
+          "default": {
+            "nested_object": null
+          }
+        },
+        "nested_optional_object_with_default": {
+          "default": {
+            "nested_object": {
+              "flag": false
+            }
+          }
+        },
+        "nested_optional_object_with_embedded_default": {
+          "default": {
+            "nested_object": {
+              "flag": false
+            }
+          }
+        }
+      }
+    }
+  },
+  "format_version": "1.2",
+  "output_changes": {
+    "list_empty_default": {
+      "actions": [
+        "create"
+      ],
+      "after": [],
+      "after_sensitive": false,
+      "after_unknown": false,
+      "before": null,
+      "before_sensitive": false
+    },
+    "list_no_default": {
+      "actions": [
+        "create"
+      ],
+      "after": [
+        {
+          "optional_attribute": null,
+          "optional_attribute_with_default": "Hello, world!",
+          "required_attribute": "D92053D5-948A-4E5E-80BF-E53F0DB33EB5"
+        },
+        {
+          "optional_attribute": "8AC4B9EE-9E05-4AE0-AA35-6D7636AEA487",
+          "optional_attribute_with_default": "Hello, world!",
+          "required_attribute": "E6DA6176-49FB-46D6-9ECD-401B3F46A3E5"
+        },
+        {
+          "optional_attribute": "E68C1EB0-3D3D-4DB0-A41D-0F8C334E181C",
+          "optional_attribute_with_default": "92E855B2-A444-49DF-AFCA-2B5B017451B4",
+          "required_attribute": "9F9922C4-B426-4648-96AE-804A6F52F778"
+        }
+      ],
+      "after_sensitive": false,
+      "after_unknown": false,
+      "before": null,
+      "before_sensitive": false
+    },
+    "nested_optional_object": {
+      "actions": [
+        "create"
+      ],
+      "after": {
+        "nested_object": null
+      },
+      "after_sensitive": false,
+      "after_unknown": false,
+      "before": null,
+      "before_sensitive": false
+    },
+    "nested_optional_object_with_default": {
+      "actions": [
+        "create"
+      ],
+      "after": {
+        "nested_object": {
+          "flag": false
+        }
+      },
+      "after_sensitive": false,
+      "after_unknown": false,
+      "before": null,
+      "before_sensitive": false
+    },
+    "nested_optional_object_with_embedded_default": {
+      "actions": [
+        "create"
+      ],
+      "after": {
+        "nested_object": {
+          "flag": false
+        }
+      },
+      "after_sensitive": false,
+      "after_unknown": false,
+      "before": null,
+      "before_sensitive": false
+    }
+  },
+  "planned_values": {
+    "outputs": {
+      "list_empty_default": {
+        "sensitive": false,
+        "type": [
+          "list",
+          [
+            "object",
+            {
+              "optional_attribute": "string",
+              "optional_attribute_with_default": "string",
+              "required_attribute": "string"
+            }
+          ]
+        ],
+        "value": []
+      },
+      "list_no_default": {
+        "sensitive": false,
+        "type": [
+          "list",
+          [
+            "object",
+            {
+              "optional_attribute": "string",
+              "optional_attribute_with_default": "string",
+              "required_attribute": "string"
+            }
+          ]
+        ],
+        "value": [
+          {
+            "optional_attribute": null,
+            "optional_attribute_with_default": "Hello, world!",
+            "required_attribute": "D92053D5-948A-4E5E-80BF-E53F0DB33EB5"
+          },
+          {
+            "optional_attribute": "8AC4B9EE-9E05-4AE0-AA35-6D7636AEA487",
+            "optional_attribute_with_default": "Hello, world!",
+            "required_attribute": "E6DA6176-49FB-46D6-9ECD-401B3F46A3E5"
+          },
+          {
+            "optional_attribute": "E68C1EB0-3D3D-4DB0-A41D-0F8C334E181C",
+            "optional_attribute_with_default": "92E855B2-A444-49DF-AFCA-2B5B017451B4",
+            "required_attribute": "9F9922C4-B426-4648-96AE-804A6F52F778"
+          }
+        ]
+      },
+      "nested_optional_object": {
+        "sensitive": false,
+        "type": [
+          "object",
+          {
+            "nested_object": [
+              "object",
+              {
+                "flag": "bool"
+              }
+            ]
+          }
+        ],
+        "value": {
+          "nested_object": null
+        }
+      },
+      "nested_optional_object_with_default": {
+        "sensitive": false,
+        "type": [
+          "object",
+          {
+            "nested_object": [
+              "object",
+              {
+                "flag": "bool"
+              }
+            ]
+          }
+        ],
+        "value": {
+          "nested_object": {
+            "flag": false
+          }
+        }
+      },
+      "nested_optional_object_with_embedded_default": {
+        "sensitive": false,
+        "type": [
+          "object",
+          {
+            "nested_object": [
+              "object",
+              {
+                "flag": "bool"
+              }
+            ]
+          }
+        ],
+        "value": {
+          "nested_object": {
+            "flag": false
+          }
+        }
+      }
+    },
+    "root_module": {}
+  },
+  "prior_state": {
+    "format_version": "1.0",
+    "values": {
+      "outputs": {
+        "list_empty_default": {
+          "sensitive": false,
+          "type": [
+            "list",
+            [
+              "object",
+              {
+                "optional_attribute": "string",
+                "optional_attribute_with_default": "string",
+                "required_attribute": "string"
+              }
+            ]
+          ],
+          "value": []
+        },
+        "list_no_default": {
+          "sensitive": false,
+          "type": [
+            "list",
+            [
+              "object",
+              {
+                "optional_attribute": "string",
+                "optional_attribute_with_default": "string",
+                "required_attribute": "string"
+              }
+            ]
+          ],
+          "value": [
+            {
+              "optional_attribute": null,
+              "optional_attribute_with_default": "Hello, world!",
+              "required_attribute": "D92053D5-948A-4E5E-80BF-E53F0DB33EB5"
+            },
+            {
+              "optional_attribute": "8AC4B9EE-9E05-4AE0-AA35-6D7636AEA487",
+              "optional_attribute_with_default": "Hello, world!",
+              "required_attribute": "E6DA6176-49FB-46D6-9ECD-401B3F46A3E5"
+            },
+            {
+              "optional_attribute": "E68C1EB0-3D3D-4DB0-A41D-0F8C334E181C",
+              "optional_attribute_with_default": "92E855B2-A444-49DF-AFCA-2B5B017451B4",
+              "required_attribute": "9F9922C4-B426-4648-96AE-804A6F52F778"
+            }
+          ]
+        },
+        "nested_optional_object": {
+          "sensitive": false,
+          "type": [
+            "object",
+            {
+              "nested_object": [
+                "object",
+                {
+                  "flag": "bool"
+                }
+              ]
+            }
+          ],
+          "value": {
+            "nested_object": null
+          }
+        },
+        "nested_optional_object_with_default": {
+          "sensitive": false,
+          "type": [
+            "object",
+            {
+              "nested_object": [
+                "object",
+                {
+                  "flag": "bool"
+                }
+              ]
+            }
+          ],
+          "value": {
+            "nested_object": {
+              "flag": false
+            }
+          }
+        },
+        "nested_optional_object_with_embedded_default": {
+          "sensitive": false,
+          "type": [
+            "object",
+            {
+              "nested_object": [
+                "object",
+                {
+                  "flag": "bool"
+                }
+              ]
+            }
+          ],
+          "value": {
+            "nested_object": {
+              "flag": false
+            }
+          }
+        }
+      },
+      "root_module": {}
+    }
+  },
+  "timestamp": "2023-05-25T07:36:23Z",
+  "variables": {
+    "list_empty_default": {
+      "value": []
+    },
+    "list_no_default": {
+      "value": [
+        {
+          "required_attribute": "D92053D5-948A-4E5E-80BF-E53F0DB33EB5"
+        },
+        {
+          "optional_attribute": "8AC4B9EE-9E05-4AE0-AA35-6D7636AEA487",
+          "required_attribute": "E6DA6176-49FB-46D6-9ECD-401B3F46A3E5"
+        },
+        {
+          "optional_attribute": "E68C1EB0-3D3D-4DB0-A41D-0F8C334E181C",
+          "optional_attribute_with_default": "92E855B2-A444-49DF-AFCA-2B5B017451B4",
+          "required_attribute": "9F9922C4-B426-4648-96AE-804A6F52F778"
+        }
+      ]
+    },
+    "nested_optional_object": {
+      "value": {
+        "nested_object": null
+      }
+    },
+    "nested_optional_object_with_default": {
+      "value": {
+        "nested_object": {
+          "flag": false
+        }
+      }
+    },
+    "nested_optional_object_with_embedded_default": {
+      "value": {
+        "nested_object": {
+          "flag": false
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/outputs/variables_and_outputs/state b/v1.5.7/testing/equivalence-tests/outputs/variables_and_outputs/state
new file mode 100644
index 0000000..330b898
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/variables_and_outputs/state
@@ -0,0 +1,32 @@
+
+
+Outputs:
+
+list_empty_default = []
+list_no_default = [
+    {
+        optional_attribute_with_default = "Hello, world!"
+        required_attribute              = "D92053D5-948A-4E5E-80BF-E53F0DB33EB5"
+    },
+    {
+        optional_attribute              = "8AC4B9EE-9E05-4AE0-AA35-6D7636AEA487"
+        optional_attribute_with_default = "Hello, world!"
+        required_attribute              = "E6DA6176-49FB-46D6-9ECD-401B3F46A3E5"
+    },
+    {
+        optional_attribute              = "E68C1EB0-3D3D-4DB0-A41D-0F8C334E181C"
+        optional_attribute_with_default = "92E855B2-A444-49DF-AFCA-2B5B017451B4"
+        required_attribute              = "9F9922C4-B426-4648-96AE-804A6F52F778"
+    },
+]
+nested_optional_object = {}
+nested_optional_object_with_default = {
+    nested_object = {
+        flag = false
+    }
+}
+nested_optional_object_with_embedded_default = {
+    nested_object = {
+        flag = false
+    }
+}
diff --git a/v1.5.7/testing/equivalence-tests/outputs/variables_and_outputs/state.json b/v1.5.7/testing/equivalence-tests/outputs/variables_and_outputs/state.json
new file mode 100644
index 0000000..fc76ce8
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/outputs/variables_and_outputs/state.json
@@ -0,0 +1,109 @@
+{
+  "format_version": "1.0",
+  "values": {
+    "outputs": {
+      "list_empty_default": {
+        "sensitive": false,
+        "type": [
+          "list",
+          [
+            "object",
+            {
+              "optional_attribute": "string",
+              "optional_attribute_with_default": "string",
+              "required_attribute": "string"
+            }
+          ]
+        ],
+        "value": []
+      },
+      "list_no_default": {
+        "sensitive": false,
+        "type": [
+          "list",
+          [
+            "object",
+            {
+              "optional_attribute": "string",
+              "optional_attribute_with_default": "string",
+              "required_attribute": "string"
+            }
+          ]
+        ],
+        "value": [
+          {
+            "optional_attribute": null,
+            "optional_attribute_with_default": "Hello, world!",
+            "required_attribute": "D92053D5-948A-4E5E-80BF-E53F0DB33EB5"
+          },
+          {
+            "optional_attribute": "8AC4B9EE-9E05-4AE0-AA35-6D7636AEA487",
+            "optional_attribute_with_default": "Hello, world!",
+            "required_attribute": "E6DA6176-49FB-46D6-9ECD-401B3F46A3E5"
+          },
+          {
+            "optional_attribute": "E68C1EB0-3D3D-4DB0-A41D-0F8C334E181C",
+            "optional_attribute_with_default": "92E855B2-A444-49DF-AFCA-2B5B017451B4",
+            "required_attribute": "9F9922C4-B426-4648-96AE-804A6F52F778"
+          }
+        ]
+      },
+      "nested_optional_object": {
+        "sensitive": false,
+        "type": [
+          "object",
+          {
+            "nested_object": [
+              "object",
+              {
+                "flag": "bool"
+              }
+            ]
+          }
+        ],
+        "value": {
+          "nested_object": null
+        }
+      },
+      "nested_optional_object_with_default": {
+        "sensitive": false,
+        "type": [
+          "object",
+          {
+            "nested_object": [
+              "object",
+              {
+                "flag": "bool"
+              }
+            ]
+          }
+        ],
+        "value": {
+          "nested_object": {
+            "flag": false
+          }
+        }
+      },
+      "nested_optional_object_with_embedded_default": {
+        "sensitive": false,
+        "type": [
+          "object",
+          {
+            "nested_object": [
+              "object",
+              {
+                "flag": "bool"
+              }
+            ]
+          }
+        ],
+        "value": {
+          "nested_object": {
+            "flag": false
+          }
+        }
+      }
+    },
+    "root_module": {}
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_json_string_update/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/basic_json_string_update/.terraform.lock.hcl
new file mode 100644
index 0000000..d2d6193
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_json_string_update/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/tfcoremock" {
+  version     = "0.1.1"
+  constraints = "0.1.1"
+  hashes = [
+    "h1:K5ImnTbl0eD02BQgVe6pNn5w2wW07j9t7iDUwqPvcy0=",
+    "zh:0219ffa02c6f2cf1f519ea42a89615cfbab8219803bcdb4a3614793952b1f5a8",
+    "zh:13915c1eb4f2ad384c6ce343eebe108ddfb0a103e19f1d8b199c0af8e57bc74a",
+    "zh:1c265814efa730540a475f76a8045d90a70c22010d6f2eee45f69e973ce10580",
+    "zh:34d58f6bf64afc491359ad1455007e1eb9aef60be17909096ec88a802b6f72b2",
+    "zh:7a7d709aeb7b2945f5a9a0497976a85bceb07b2cbf236c8c1bb0b7b079b839ab",
+    "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+    "zh:965fbb6042acd6fbf77a9b5c3321edbfa0aa6bf0359394afbf0a7e1392245324",
+    "zh:9e4ac8eae03d1243b9283b202132c007d5c4ee533d1c5efc690403caaaaa7aac",
+    "zh:a51833ca1c6983e32a937ea3864b6037c1ccb97a4917cafb38771a3aa583cc77",
+    "zh:ac2eba5efca9f0bf4ecca3b23c2a89c4318ef7cda45e374811e42cced0aa660b",
+    "zh:c77663f4c0e4ca799e5f1abfa94cfe15f36e9879e637a9196ea01fcaeba13286",
+    "zh:dc0ab43f1affe80e117cea108780afe53d7c97357566ded87f53221828c875de",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_json_string_update/main.tf b/v1.5.7/testing/equivalence-tests/tests/basic_json_string_update/main.tf
new file mode 100644
index 0000000..37e3cad
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_json_string_update/main.tf
@@ -0,0 +1,14 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_simple_resource" "json" {
+  string = "{\"list-attribute\":[\"one\",\"four\",\"three\"],\"object-attribute\":{\"key_one\":\"value_one\",\"key_three\":\"value_two\", \"key_four\":\"value_three\"},\"string-attribute\":\"a new string\"}"
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_json_string_update/spec.json b/v1.5.7/testing/equivalence-tests/tests/basic_json_string_update/spec.json
new file mode 100644
index 0000000..ef42c1a
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_json_string_update/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests updating a JSON compatible string",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_json_string_update/terraform.resource/5a3fd9b3-e852-8956-8c0a-255d47eda645.json b/v1.5.7/testing/equivalence-tests/tests/basic_json_string_update/terraform.resource/5a3fd9b3-e852-8956-8c0a-255d47eda645.json
new file mode 100644
index 0000000..5604f6c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_json_string_update/terraform.resource/5a3fd9b3-e852-8956-8c0a-255d47eda645.json
@@ -0,0 +1,10 @@
+{
+  "values": {
+    "id": {
+      "string": "5a3fd9b3-e852-8956-8c0a-255d47eda645"
+    },
+    "string": {
+      "string": "{\"list-attribute\":[\"one\",\"two\",\"three\"],\"object-attribute\":{\"key_one\":\"value_one\",\"key_two\":\"value_two\",\"key_three\":\"value_three\"},\"string-attribute\":\"string\"}"
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_json_string_update/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/basic_json_string_update/terraform.tfstate
new file mode 100644
index 0000000..24089bc
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_json_string_update/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.7",
+  "serial": 1,
+  "lineage": "4a3a27e3-e5b3-3db6-bc4c-6b762a030232",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_simple_resource",
+      "name": "json",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "bool": null,
+            "float": null,
+            "id": "5a3fd9b3-e852-8956-8c0a-255d47eda645",
+            "integer": null,
+            "number": null,
+            "string": "{\"list-attribute\":[\"one\",\"two\",\"three\"],\"object-attribute\":{\"key_one\":\"value_one\",\"key_two\":\"value_two\",\"key_three\":\"value_three\"},\"string-attribute\":\"string\"}"
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/basic_list/dynamic_resources.json
new file mode 100644
index 0000000..78b194e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list/dynamic_resources.json
@@ -0,0 +1,13 @@
+{
+  "tfcoremock_list": {
+    "attributes": {
+      "list": {
+        "type": "list",
+        "optional": true,
+        "list": {
+          "type": "string"
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list/main.tf b/v1.5.7/testing/equivalence-tests/tests/basic_list/main.tf
new file mode 100644
index 0000000..e2e5a6b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list/main.tf
@@ -0,0 +1,20 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_list" "list" {
+  id = "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+  list = [
+    "9C2BE420-042D-440A-96E9-75565341C994",
+    "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+    "D01290F6-2D3A-45FA-B006-DAA80F6D31F6",
+  ]
+}
+
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list/spec.json b/v1.5.7/testing/equivalence-tests/tests/basic_list/spec.json
new file mode 100644
index 0000000..1a085f6
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "basic test covering creation of a single list",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_empty/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/basic_list_empty/dynamic_resources.json
new file mode 100644
index 0000000..7311d1b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_empty/dynamic_resources.json
@@ -0,0 +1,13 @@
+{
+  "tfcoremock_list": {
+    "attributes": {
+      "list": {
+        "type": "list",
+        "optional": true,
+        "list": {
+          "type": "string"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_empty/main.tf b/v1.5.7/testing/equivalence-tests/tests/basic_list_empty/main.tf
new file mode 100644
index 0000000..520ea04
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_empty/main.tf
@@ -0,0 +1,15 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_list" "list" {
+  id = "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+  list = []
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_empty/spec.json b/v1.5.7/testing/equivalence-tests/tests/basic_list_empty/spec.json
new file mode 100644
index 0000000..99bfdb4
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_empty/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests removing all elements from a simple list",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_empty/terraform.resource/985820B3-ACF9-4F00-94AD-F81C5EA33663.json b/v1.5.7/testing/equivalence-tests/tests/basic_list_empty/terraform.resource/985820B3-ACF9-4F00-94AD-F81C5EA33663.json
new file mode 100644
index 0000000..6328bc9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_empty/terraform.resource/985820B3-ACF9-4F00-94AD-F81C5EA33663.json
@@ -0,0 +1,20 @@
+{
+  "values": {
+    "id": {
+      "string": "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+    },
+    "list": {
+      "list": [
+        {
+          "string": "9C2BE420-042D-440A-96E9-75565341C994"
+        },
+        {
+          "string": "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1"
+        },
+        {
+          "string": "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_empty/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/basic_list_empty/terraform.tfstate
new file mode 100644
index 0000000..db4167e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_empty/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.6",
+  "serial": 1,
+  "lineage": "10d37a1e-be83-d81f-dc89-30b6ec90e835",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_list",
+      "name": "list",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+            "list": [
+              "9C2BE420-042D-440A-96E9-75565341C994",
+              "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+              "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+            ]
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_null/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/basic_list_null/dynamic_resources.json
new file mode 100644
index 0000000..7311d1b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_null/dynamic_resources.json
@@ -0,0 +1,13 @@
+{
+  "tfcoremock_list": {
+    "attributes": {
+      "list": {
+        "type": "list",
+        "optional": true,
+        "list": {
+          "type": "string"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_null/main.tf b/v1.5.7/testing/equivalence-tests/tests/basic_list_null/main.tf
new file mode 100644
index 0000000..dd4ea8d
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_null/main.tf
@@ -0,0 +1,14 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_list" "list" {
+  id = "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_null/spec.json b/v1.5.7/testing/equivalence-tests/tests/basic_list_null/spec.json
new file mode 100644
index 0000000..779888c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_null/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests deleting a simple list from a resource",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_null/terraform.resource/046952C9-B832-4106-82C0-C217F7C73E18.json b/v1.5.7/testing/equivalence-tests/tests/basic_list_null/terraform.resource/046952C9-B832-4106-82C0-C217F7C73E18.json
new file mode 100644
index 0000000..1bae638
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_null/terraform.resource/046952C9-B832-4106-82C0-C217F7C73E18.json
@@ -0,0 +1,20 @@
+{
+  "values": {
+    "id": {
+      "string": "046952C9-B832-4106-82C0-C217F7C73E18"
+    },
+    "set": {
+      "set": [
+        {
+          "string": "41471135-E14C-4946-BFA4-2626C7E2A94A"
+        },
+        {
+          "string": "C04762B9-D07B-40FE-A92B-B72AD342658D"
+        },
+        {
+          "string": "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_null/terraform.resource/50E1A46E-E64A-4C1F-881C-BA85A5440964.json b/v1.5.7/testing/equivalence-tests/tests/basic_list_null/terraform.resource/50E1A46E-E64A-4C1F-881C-BA85A5440964.json
new file mode 100644
index 0000000..4ed206e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_null/terraform.resource/50E1A46E-E64A-4C1F-881C-BA85A5440964.json
@@ -0,0 +1,20 @@
+{
+  "values": {
+    "id": {
+      "string": "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+    },
+    "map": {
+      "map": {
+        "one": {
+          "string": "682672C7-0918-4448-8342-887BAE01062A"
+        },
+        "two": {
+          "string": "212FFBF6-40FE-4862-B708-E6AA508E84E0"
+        },
+        "zero": {
+          "string": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_null/terraform.resource/985820B3-ACF9-4F00-94AD-F81C5EA33663.json b/v1.5.7/testing/equivalence-tests/tests/basic_list_null/terraform.resource/985820B3-ACF9-4F00-94AD-F81C5EA33663.json
new file mode 100644
index 0000000..6328bc9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_null/terraform.resource/985820B3-ACF9-4F00-94AD-F81C5EA33663.json
@@ -0,0 +1,20 @@
+{
+  "values": {
+    "id": {
+      "string": "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+    },
+    "list": {
+      "list": [
+        {
+          "string": "9C2BE420-042D-440A-96E9-75565341C994"
+        },
+        {
+          "string": "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1"
+        },
+        {
+          "string": "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_null/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/basic_list_null/terraform.tfstate
new file mode 100644
index 0000000..db4167e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_null/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.6",
+  "serial": 1,
+  "lineage": "10d37a1e-be83-d81f-dc89-30b6ec90e835",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_list",
+      "name": "list",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+            "list": [
+              "9C2BE420-042D-440A-96E9-75565341C994",
+              "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+              "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+            ]
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_update/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/basic_list_update/dynamic_resources.json
new file mode 100644
index 0000000..78b194e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_update/dynamic_resources.json
@@ -0,0 +1,13 @@
+{
+  "tfcoremock_list": {
+    "attributes": {
+      "list": {
+        "type": "list",
+        "optional": true,
+        "list": {
+          "type": "string"
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_update/main.tf b/v1.5.7/testing/equivalence-tests/tests/basic_list_update/main.tf
new file mode 100644
index 0000000..95e5dba
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_update/main.tf
@@ -0,0 +1,19 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_list" "list" {
+  id = "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+  list = [
+    "9C2BE420-042D-440A-96E9-75565341C994",
+    "D01290F6-2D3A-45FA-B006-DAA80F6D31F6",
+    "9B9F3ADF-8AD4-4E8C-AFE4-7BC2413E9AC0",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_update/spec.json b/v1.5.7/testing/equivalence-tests/tests/basic_list_update/spec.json
new file mode 100644
index 0000000..bf5bca6
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_update/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests adding and removing elements from a simple list",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_update/terraform.resource/985820B3-ACF9-4F00-94AD-F81C5EA33663.json b/v1.5.7/testing/equivalence-tests/tests/basic_list_update/terraform.resource/985820B3-ACF9-4F00-94AD-F81C5EA33663.json
new file mode 100644
index 0000000..6328bc9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_update/terraform.resource/985820B3-ACF9-4F00-94AD-F81C5EA33663.json
@@ -0,0 +1,20 @@
+{
+  "values": {
+    "id": {
+      "string": "985820B3-ACF9-4F00-94AD-F81C5EA33663"
+    },
+    "list": {
+      "list": [
+        {
+          "string": "9C2BE420-042D-440A-96E9-75565341C994"
+        },
+        {
+          "string": "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1"
+        },
+        {
+          "string": "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_list_update/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/basic_list_update/terraform.tfstate
new file mode 100644
index 0000000..db4167e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_list_update/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.6",
+  "serial": 1,
+  "lineage": "10d37a1e-be83-d81f-dc89-30b6ec90e835",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_list",
+      "name": "list",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "985820B3-ACF9-4F00-94AD-F81C5EA33663",
+            "list": [
+              "9C2BE420-042D-440A-96E9-75565341C994",
+              "3EC6EB1F-E372-46C3-A069-00D6E82EC1E1",
+              "D01290F6-2D3A-45FA-B006-DAA80F6D31F6"
+            ]
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/basic_map/dynamic_resources.json
new file mode 100644
index 0000000..2b2d959
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map/dynamic_resources.json
@@ -0,0 +1,13 @@
+{
+  "tfcoremock_map": {
+    "attributes": {
+      "map": {
+        "type": "map",
+        "optional": true,
+        "map": {
+          "type": "string"
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map/main.tf b/v1.5.7/testing/equivalence-tests/tests/basic_map/main.tf
new file mode 100644
index 0000000..5622c5c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map/main.tf
@@ -0,0 +1,19 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_map" "map" {
+  id = "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+  map = {
+    "zero" : "6B044AF7-172B-495B-BE11-B9546C12C3BD",
+    "one" : "682672C7-0918-4448-8342-887BAE01062A",
+    "two" : "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map/spec.json b/v1.5.7/testing/equivalence-tests/tests/basic_map/spec.json
new file mode 100644
index 0000000..91eeb9e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "basic test covering creation of a simple map",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map_empty/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/basic_map_empty/dynamic_resources.json
new file mode 100644
index 0000000..2b2d959
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map_empty/dynamic_resources.json
@@ -0,0 +1,13 @@
+{
+  "tfcoremock_map": {
+    "attributes": {
+      "map": {
+        "type": "map",
+        "optional": true,
+        "map": {
+          "type": "string"
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map_empty/main.tf b/v1.5.7/testing/equivalence-tests/tests/basic_map_empty/main.tf
new file mode 100644
index 0000000..aebd593
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map_empty/main.tf
@@ -0,0 +1,15 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_map" "map" {
+  id = "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+  map = {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map_empty/spec.json b/v1.5.7/testing/equivalence-tests/tests/basic_map_empty/spec.json
new file mode 100644
index 0000000..678b5cd
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map_empty/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests removing all elements from a simple map",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map_empty/terraform.resource/50E1A46E-E64A-4C1F-881C-BA85A5440964.json b/v1.5.7/testing/equivalence-tests/tests/basic_map_empty/terraform.resource/50E1A46E-E64A-4C1F-881C-BA85A5440964.json
new file mode 100644
index 0000000..4ed206e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map_empty/terraform.resource/50E1A46E-E64A-4C1F-881C-BA85A5440964.json
@@ -0,0 +1,20 @@
+{
+  "values": {
+    "id": {
+      "string": "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+    },
+    "map": {
+      "map": {
+        "one": {
+          "string": "682672C7-0918-4448-8342-887BAE01062A"
+        },
+        "two": {
+          "string": "212FFBF6-40FE-4862-B708-E6AA508E84E0"
+        },
+        "zero": {
+          "string": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map_empty/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/basic_map_empty/terraform.tfstate
new file mode 100644
index 0000000..c985710
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map_empty/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.6",
+  "serial": 1,
+  "lineage": "6d4501ec-0c29-0728-bfb9-296c7dc09b9f",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_map",
+      "name": "map",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+            "map": {
+              "one": "682672C7-0918-4448-8342-887BAE01062A",
+              "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+              "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+            }
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map_null/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/basic_map_null/dynamic_resources.json
new file mode 100644
index 0000000..2b2d959
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map_null/dynamic_resources.json
@@ -0,0 +1,13 @@
+{
+  "tfcoremock_map": {
+    "attributes": {
+      "map": {
+        "type": "map",
+        "optional": true,
+        "map": {
+          "type": "string"
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map_null/main.tf b/v1.5.7/testing/equivalence-tests/tests/basic_map_null/main.tf
new file mode 100644
index 0000000..6bac607
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map_null/main.tf
@@ -0,0 +1,14 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_map" "map" {
+  id = "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map_null/spec.json b/v1.5.7/testing/equivalence-tests/tests/basic_map_null/spec.json
new file mode 100644
index 0000000..3eb24d9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map_null/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests deleting a simple map from a resource",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map_null/terraform.resource/50E1A46E-E64A-4C1F-881C-BA85A5440964.json b/v1.5.7/testing/equivalence-tests/tests/basic_map_null/terraform.resource/50E1A46E-E64A-4C1F-881C-BA85A5440964.json
new file mode 100644
index 0000000..4ed206e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map_null/terraform.resource/50E1A46E-E64A-4C1F-881C-BA85A5440964.json
@@ -0,0 +1,20 @@
+{
+  "values": {
+    "id": {
+      "string": "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+    },
+    "map": {
+      "map": {
+        "one": {
+          "string": "682672C7-0918-4448-8342-887BAE01062A"
+        },
+        "two": {
+          "string": "212FFBF6-40FE-4862-B708-E6AA508E84E0"
+        },
+        "zero": {
+          "string": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map_null/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/basic_map_null/terraform.tfstate
new file mode 100644
index 0000000..c985710
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map_null/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.6",
+  "serial": 1,
+  "lineage": "6d4501ec-0c29-0728-bfb9-296c7dc09b9f",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_map",
+      "name": "map",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+            "map": {
+              "one": "682672C7-0918-4448-8342-887BAE01062A",
+              "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+              "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+            }
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map_update/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/basic_map_update/dynamic_resources.json
new file mode 100644
index 0000000..2b2d959
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map_update/dynamic_resources.json
@@ -0,0 +1,13 @@
+{
+  "tfcoremock_map": {
+    "attributes": {
+      "map": {
+        "type": "map",
+        "optional": true,
+        "map": {
+          "type": "string"
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map_update/main.tf b/v1.5.7/testing/equivalence-tests/tests/basic_map_update/main.tf
new file mode 100644
index 0000000..3446f95
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map_update/main.tf
@@ -0,0 +1,19 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_map" "map" {
+  id = "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+  map = {
+    "zero" : "6B044AF7-172B-495B-BE11-B9546C12C3BD",
+    "two" : "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+    "four" : "D820D482-7C2C-4EF3-8935-863168A193F9",
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map_update/spec.json b/v1.5.7/testing/equivalence-tests/tests/basic_map_update/spec.json
new file mode 100644
index 0000000..332a515
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map_update/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "basic test coverting updating a simple map",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map_update/terraform.resource/50E1A46E-E64A-4C1F-881C-BA85A5440964.json b/v1.5.7/testing/equivalence-tests/tests/basic_map_update/terraform.resource/50E1A46E-E64A-4C1F-881C-BA85A5440964.json
new file mode 100644
index 0000000..4ed206e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map_update/terraform.resource/50E1A46E-E64A-4C1F-881C-BA85A5440964.json
@@ -0,0 +1,20 @@
+{
+  "values": {
+    "id": {
+      "string": "50E1A46E-E64A-4C1F-881C-BA85A5440964"
+    },
+    "map": {
+      "map": {
+        "one": {
+          "string": "682672C7-0918-4448-8342-887BAE01062A"
+        },
+        "two": {
+          "string": "212FFBF6-40FE-4862-B708-E6AA508E84E0"
+        },
+        "zero": {
+          "string": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_map_update/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/basic_map_update/terraform.tfstate
new file mode 100644
index 0000000..c985710
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_map_update/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.6",
+  "serial": 1,
+  "lineage": "6d4501ec-0c29-0728-bfb9-296c7dc09b9f",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_map",
+      "name": "map",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "50E1A46E-E64A-4C1F-881C-BA85A5440964",
+            "map": {
+              "one": "682672C7-0918-4448-8342-887BAE01062A",
+              "two": "212FFBF6-40FE-4862-B708-E6AA508E84E0",
+              "zero": "6B044AF7-172B-495B-BE11-B9546C12C3BD"
+            }
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_multiline_string_update/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/basic_multiline_string_update/.terraform.lock.hcl
new file mode 100644
index 0000000..d2d6193
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_multiline_string_update/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/tfcoremock" {
+  version     = "0.1.1"
+  constraints = "0.1.1"
+  hashes = [
+    "h1:K5ImnTbl0eD02BQgVe6pNn5w2wW07j9t7iDUwqPvcy0=",
+    "zh:0219ffa02c6f2cf1f519ea42a89615cfbab8219803bcdb4a3614793952b1f5a8",
+    "zh:13915c1eb4f2ad384c6ce343eebe108ddfb0a103e19f1d8b199c0af8e57bc74a",
+    "zh:1c265814efa730540a475f76a8045d90a70c22010d6f2eee45f69e973ce10580",
+    "zh:34d58f6bf64afc491359ad1455007e1eb9aef60be17909096ec88a802b6f72b2",
+    "zh:7a7d709aeb7b2945f5a9a0497976a85bceb07b2cbf236c8c1bb0b7b079b839ab",
+    "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+    "zh:965fbb6042acd6fbf77a9b5c3321edbfa0aa6bf0359394afbf0a7e1392245324",
+    "zh:9e4ac8eae03d1243b9283b202132c007d5c4ee533d1c5efc690403caaaaa7aac",
+    "zh:a51833ca1c6983e32a937ea3864b6037c1ccb97a4917cafb38771a3aa583cc77",
+    "zh:ac2eba5efca9f0bf4ecca3b23c2a89c4318ef7cda45e374811e42cced0aa660b",
+    "zh:c77663f4c0e4ca799e5f1abfa94cfe15f36e9879e637a9196ea01fcaeba13286",
+    "zh:dc0ab43f1affe80e117cea108780afe53d7c97357566ded87f53221828c875de",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_multiline_string_update/main.tf b/v1.5.7/testing/equivalence-tests/tests/basic_multiline_string_update/main.tf
new file mode 100644
index 0000000..c3bbaaa
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_multiline_string_update/main.tf
@@ -0,0 +1,14 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_simple_resource" "multiline" {
+  string = "one\nthree\ntwo\nfour\nsix\nseven"
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_multiline_string_update/spec.json b/v1.5.7/testing/equivalence-tests/tests/basic_multiline_string_update/spec.json
new file mode 100644
index 0000000..16347a0
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_multiline_string_update/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests handling of multiline strings when updating",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_multiline_string_update/terraform.resource/69fe5233-e77a-804f-0dac-115c949540bc.json b/v1.5.7/testing/equivalence-tests/tests/basic_multiline_string_update/terraform.resource/69fe5233-e77a-804f-0dac-115c949540bc.json
new file mode 100644
index 0000000..8ad35d4
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_multiline_string_update/terraform.resource/69fe5233-e77a-804f-0dac-115c949540bc.json
@@ -0,0 +1,10 @@
+{
+  "values": {
+    "id": {
+      "string": "69fe5233-e77a-804f-0dac-115c949540bc"
+    },
+    "string": {
+      "string": "one\ntwo\nthree\nfour\nfive"
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_multiline_string_update/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/basic_multiline_string_update/terraform.tfstate
new file mode 100644
index 0000000..050b259
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_multiline_string_update/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.7",
+  "serial": 1,
+  "lineage": "1e8cb645-9856-bc39-5053-f58ec18be73d",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_simple_resource",
+      "name": "multiline",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "bool": null,
+            "float": null,
+            "id": "69fe5233-e77a-804f-0dac-115c949540bc",
+            "integer": null,
+            "number": null,
+            "string": "one\ntwo\nthree\nfour\nfive"
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/basic_set/dynamic_resources.json
new file mode 100644
index 0000000..93eb390
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set/dynamic_resources.json
@@ -0,0 +1,13 @@
+{
+  "tfcoremock_set": {
+    "attributes": {
+      "set": {
+        "type": "set",
+        "optional": true,
+        "set": {
+          "type": "string"
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set/main.tf b/v1.5.7/testing/equivalence-tests/tests/basic_set/main.tf
new file mode 100644
index 0000000..a327a27
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set/main.tf
@@ -0,0 +1,19 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_set" "set" {
+  id = "046952C9-B832-4106-82C0-C217F7C73E18"
+  set = [
+    "41471135-E14C-4946-BFA4-2626C7E2A94A",
+    "C04762B9-D07B-40FE-A92B-B72AD342658D",
+    "D8F7EA80-9E25-4DD7-8D97-797D2080952B",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set/spec.json b/v1.5.7/testing/equivalence-tests/tests/basic_set/spec.json
new file mode 100644
index 0000000..5ac9530
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "basic test coverting creation of a simple set",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set_empty/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/basic_set_empty/dynamic_resources.json
new file mode 100644
index 0000000..93eb390
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set_empty/dynamic_resources.json
@@ -0,0 +1,13 @@
+{
+  "tfcoremock_set": {
+    "attributes": {
+      "set": {
+        "type": "set",
+        "optional": true,
+        "set": {
+          "type": "string"
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set_empty/main.tf b/v1.5.7/testing/equivalence-tests/tests/basic_set_empty/main.tf
new file mode 100644
index 0000000..aa7d0d2
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set_empty/main.tf
@@ -0,0 +1,15 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_set" "set" {
+  id = "046952C9-B832-4106-82C0-C217F7C73E18"
+  set = []
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set_empty/spec.json b/v1.5.7/testing/equivalence-tests/tests/basic_set_empty/spec.json
new file mode 100644
index 0000000..ed8691d
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set_empty/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests removing all elements from a simple set",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set_empty/terraform.resource/046952C9-B832-4106-82C0-C217F7C73E18.json b/v1.5.7/testing/equivalence-tests/tests/basic_set_empty/terraform.resource/046952C9-B832-4106-82C0-C217F7C73E18.json
new file mode 100644
index 0000000..1bae638
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set_empty/terraform.resource/046952C9-B832-4106-82C0-C217F7C73E18.json
@@ -0,0 +1,20 @@
+{
+  "values": {
+    "id": {
+      "string": "046952C9-B832-4106-82C0-C217F7C73E18"
+    },
+    "set": {
+      "set": [
+        {
+          "string": "41471135-E14C-4946-BFA4-2626C7E2A94A"
+        },
+        {
+          "string": "C04762B9-D07B-40FE-A92B-B72AD342658D"
+        },
+        {
+          "string": "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set_empty/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/basic_set_empty/terraform.tfstate
new file mode 100644
index 0000000..556b2ad
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set_empty/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.6",
+  "serial": 1,
+  "lineage": "b6909641-99a4-0628-bbc1-110b6361ba80",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_set",
+      "name": "set",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+            "set": [
+              "41471135-E14C-4946-BFA4-2626C7E2A94A",
+              "C04762B9-D07B-40FE-A92B-B72AD342658D",
+              "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+            ]
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set_null/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/basic_set_null/dynamic_resources.json
new file mode 100644
index 0000000..93eb390
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set_null/dynamic_resources.json
@@ -0,0 +1,13 @@
+{
+  "tfcoremock_set": {
+    "attributes": {
+      "set": {
+        "type": "set",
+        "optional": true,
+        "set": {
+          "type": "string"
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set_null/main.tf b/v1.5.7/testing/equivalence-tests/tests/basic_set_null/main.tf
new file mode 100644
index 0000000..aa7594d
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set_null/main.tf
@@ -0,0 +1,14 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_set" "set" {
+  id = "046952C9-B832-4106-82C0-C217F7C73E18"
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set_null/spec.json b/v1.5.7/testing/equivalence-tests/tests/basic_set_null/spec.json
new file mode 100644
index 0000000..07aa574
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set_null/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests deleting a simple set",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set_null/terraform.resource/046952C9-B832-4106-82C0-C217F7C73E18.json b/v1.5.7/testing/equivalence-tests/tests/basic_set_null/terraform.resource/046952C9-B832-4106-82C0-C217F7C73E18.json
new file mode 100644
index 0000000..1bae638
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set_null/terraform.resource/046952C9-B832-4106-82C0-C217F7C73E18.json
@@ -0,0 +1,20 @@
+{
+  "values": {
+    "id": {
+      "string": "046952C9-B832-4106-82C0-C217F7C73E18"
+    },
+    "set": {
+      "set": [
+        {
+          "string": "41471135-E14C-4946-BFA4-2626C7E2A94A"
+        },
+        {
+          "string": "C04762B9-D07B-40FE-A92B-B72AD342658D"
+        },
+        {
+          "string": "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set_null/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/basic_set_null/terraform.tfstate
new file mode 100644
index 0000000..556b2ad
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set_null/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.6",
+  "serial": 1,
+  "lineage": "b6909641-99a4-0628-bbc1-110b6361ba80",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_set",
+      "name": "set",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+            "set": [
+              "41471135-E14C-4946-BFA4-2626C7E2A94A",
+              "C04762B9-D07B-40FE-A92B-B72AD342658D",
+              "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+            ]
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set_update/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/basic_set_update/dynamic_resources.json
new file mode 100644
index 0000000..93eb390
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set_update/dynamic_resources.json
@@ -0,0 +1,13 @@
+{
+  "tfcoremock_set": {
+    "attributes": {
+      "set": {
+        "type": "set",
+        "optional": true,
+        "set": {
+          "type": "string"
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set_update/main.tf b/v1.5.7/testing/equivalence-tests/tests/basic_set_update/main.tf
new file mode 100644
index 0000000..dfbd4b2
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set_update/main.tf
@@ -0,0 +1,19 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_set" "set" {
+  id = "046952C9-B832-4106-82C0-C217F7C73E18"
+  set = [
+    "41471135-E14C-4946-BFA4-2626C7E2A94A",
+    "D8F7EA80-9E25-4DD7-8D97-797D2080952B",
+    "1769B76E-12F0-4214-A864-E843EB23B64E",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set_update/spec.json b/v1.5.7/testing/equivalence-tests/tests/basic_set_update/spec.json
new file mode 100644
index 0000000..7df5cf3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set_update/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests adding and removing elements from a simple set",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set_update/terraform.resource/046952C9-B832-4106-82C0-C217F7C73E18.json b/v1.5.7/testing/equivalence-tests/tests/basic_set_update/terraform.resource/046952C9-B832-4106-82C0-C217F7C73E18.json
new file mode 100644
index 0000000..1bae638
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set_update/terraform.resource/046952C9-B832-4106-82C0-C217F7C73E18.json
@@ -0,0 +1,20 @@
+{
+  "values": {
+    "id": {
+      "string": "046952C9-B832-4106-82C0-C217F7C73E18"
+    },
+    "set": {
+      "set": [
+        {
+          "string": "41471135-E14C-4946-BFA4-2626C7E2A94A"
+        },
+        {
+          "string": "C04762B9-D07B-40FE-A92B-B72AD342658D"
+        },
+        {
+          "string": "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/basic_set_update/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/basic_set_update/terraform.tfstate
new file mode 100644
index 0000000..556b2ad
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/basic_set_update/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.6",
+  "serial": 1,
+  "lineage": "b6909641-99a4-0628-bbc1-110b6361ba80",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_set",
+      "name": "set",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "046952C9-B832-4106-82C0-C217F7C73E18",
+            "set": [
+              "41471135-E14C-4946-BFA4-2626C7E2A94A",
+              "C04762B9-D07B-40FE-A92B-B72AD342658D",
+              "D8F7EA80-9E25-4DD7-8D97-797D2080952B"
+            ]
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/data_read/create/main.tf b/v1.5.7/testing/equivalence-tests/tests/data_read/create/main.tf
new file mode 100644
index 0000000..5cb4ba3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/data_read/create/main.tf
@@ -0,0 +1,32 @@
+
+variable "contents" {
+  type = string
+}
+
+resource "random_integer" "random" {
+  min = 1000000
+  max = 9999999
+  seed = "F78CB410-BA01-44E1-82E1-37D61F7CB158"
+}
+
+locals {
+  contents = jsonencode({
+    values = {
+      id = {
+        string = random_integer.random.id
+      }
+      string = {
+        string = var.contents
+      }
+    }
+  })
+}
+
+resource "local_file" "data_file" {
+  filename = "terraform.data/${random_integer.random.id}.json"
+  content = local.contents
+}
+
+output "id" {
+  value = random_integer.random.id
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/data_read/main.tf b/v1.5.7/testing/equivalence-tests/tests/data_read/main.tf
new file mode 100644
index 0000000..67c3f11
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/data_read/main.tf
@@ -0,0 +1,39 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+    local = {
+      source  = "hashicorp/local"
+      version = "2.2.3"
+    }
+    random = {
+      source = "hashicorp/random"
+      version = "3.4.3"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+provider "local" {}
+
+provider "random" {}
+
+module "create" {
+  source = "./create"
+  contents = "hello, world!"
+}
+
+data "tfcoremock_simple_resource" "read" {
+  id = module.create.id
+
+  depends_on = [
+    module.create
+  ]
+}
+
+resource "tfcoremock_simple_resource" "create" {
+  string = data.tfcoremock_simple_resource.read.string
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/data_read/spec.json b/v1.5.7/testing/equivalence-tests/tests/data_read/spec.json
new file mode 100644
index 0000000..7931b8c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/data_read/spec.json
@@ -0,0 +1,27 @@
+{
+  "description": "tests reading data from data sources using only a plan",
+  "include_files": [],
+  "ignore_fields": {},
+  "commands": [
+    {
+      "name": "init",
+      "arguments": ["init"],
+      "capture_output": false
+    },
+    {
+      "name": "plan",
+      "arguments": ["plan", "-out=equivalence_test_plan", "-no-color"],
+      "capture_output": true,
+      "output_file_name": "plan",
+      "has_json_output": false
+    },
+    {
+      "name": "show_plan",
+      "arguments": ["show", "-json", "equivalence_test_plan"],
+      "capture_output": true,
+      "output_file_name": "plan.json",
+      "has_json_output": true,
+      "streams_json_output": false
+    }
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_refresh_only/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/drift_refresh_only/.terraform.lock.hcl
new file mode 100644
index 0000000..d2d6193
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_refresh_only/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/tfcoremock" {
+  version     = "0.1.1"
+  constraints = "0.1.1"
+  hashes = [
+    "h1:K5ImnTbl0eD02BQgVe6pNn5w2wW07j9t7iDUwqPvcy0=",
+    "zh:0219ffa02c6f2cf1f519ea42a89615cfbab8219803bcdb4a3614793952b1f5a8",
+    "zh:13915c1eb4f2ad384c6ce343eebe108ddfb0a103e19f1d8b199c0af8e57bc74a",
+    "zh:1c265814efa730540a475f76a8045d90a70c22010d6f2eee45f69e973ce10580",
+    "zh:34d58f6bf64afc491359ad1455007e1eb9aef60be17909096ec88a802b6f72b2",
+    "zh:7a7d709aeb7b2945f5a9a0497976a85bceb07b2cbf236c8c1bb0b7b079b839ab",
+    "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+    "zh:965fbb6042acd6fbf77a9b5c3321edbfa0aa6bf0359394afbf0a7e1392245324",
+    "zh:9e4ac8eae03d1243b9283b202132c007d5c4ee533d1c5efc690403caaaaa7aac",
+    "zh:a51833ca1c6983e32a937ea3864b6037c1ccb97a4917cafb38771a3aa583cc77",
+    "zh:ac2eba5efca9f0bf4ecca3b23c2a89c4318ef7cda45e374811e42cced0aa660b",
+    "zh:c77663f4c0e4ca799e5f1abfa94cfe15f36e9879e637a9196ea01fcaeba13286",
+    "zh:dc0ab43f1affe80e117cea108780afe53d7c97357566ded87f53221828c875de",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_refresh_only/main.tf b/v1.5.7/testing/equivalence-tests/tests/drift_refresh_only/main.tf
new file mode 100644
index 0000000..77e8913
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_refresh_only/main.tf
@@ -0,0 +1,14 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_simple_resource" "drift" {
+  string = "Hello, world!"
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_refresh_only/spec.json b/v1.5.7/testing/equivalence-tests/tests/drift_refresh_only/spec.json
new file mode 100644
index 0000000..810211a
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_refresh_only/spec.json
@@ -0,0 +1,43 @@
+{
+  "description": "tests drift in a refresh only plan, so has a custom set of commands",
+  "include_files": [],
+  "ignore_fields": {},
+  "commands": [
+    {
+      "name": "init",
+      "arguments": ["init"],
+      "capture_output": false
+    },
+    {
+      "name": "plan",
+      "arguments": ["plan", "-out=equivalence_test_plan", "-no-color", "-refresh-only"],
+      "capture_output": true,
+      "output_file_name": "plan",
+      "has_json_output": false
+    },
+    {
+      "name": "apply",
+      "arguments": ["apply", "-json", "equivalence_test_plan"],
+      "capture_output": true,
+      "output_file_name": "apply.json",
+      "has_json_output": true,
+      "streams_json_output": true
+    },
+    {
+      "name": "show_state",
+      "arguments": ["show", "-json"],
+      "capture_output": true,
+      "output_file_name": "state.json",
+      "has_json_output": true,
+      "streams_json_output": false
+    },
+    {
+      "name": "show_plan",
+      "arguments": ["show", "-json", "equivalence_test_plan"],
+      "capture_output": true,
+      "output_file_name": "plan.json",
+      "has_json_output": true,
+      "streams_json_output": false
+    }
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_refresh_only/terraform.resource/cb79269e-dc39-1e68-0a9c-63cb392afda9.json b/v1.5.7/testing/equivalence-tests/tests/drift_refresh_only/terraform.resource/cb79269e-dc39-1e68-0a9c-63cb392afda9.json
new file mode 100644
index 0000000..4446f2c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_refresh_only/terraform.resource/cb79269e-dc39-1e68-0a9c-63cb392afda9.json
@@ -0,0 +1,10 @@
+{
+  "values": {
+    "id": {
+      "string": "cb79269e-dc39-1e68-0a9c-63cb392afda9"
+    },
+    "string": {
+      "string": "Hello, drift!"
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_refresh_only/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/drift_refresh_only/terraform.tfstate
new file mode 100644
index 0000000..b0ae387
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_refresh_only/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.7",
+  "serial": 1,
+  "lineage": "4ce8adfd-57a0-aba7-118d-834394462086",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_simple_resource",
+      "name": "drift",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "bool": null,
+            "float": null,
+            "id": "cb79269e-dc39-1e68-0a9c-63cb392afda9",
+            "integer": null,
+            "number": null,
+            "string": "Hello, world!"
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/.terraform.lock.hcl
new file mode 100644
index 0000000..d2d6193
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/tfcoremock" {
+  version     = "0.1.1"
+  constraints = "0.1.1"
+  hashes = [
+    "h1:K5ImnTbl0eD02BQgVe6pNn5w2wW07j9t7iDUwqPvcy0=",
+    "zh:0219ffa02c6f2cf1f519ea42a89615cfbab8219803bcdb4a3614793952b1f5a8",
+    "zh:13915c1eb4f2ad384c6ce343eebe108ddfb0a103e19f1d8b199c0af8e57bc74a",
+    "zh:1c265814efa730540a475f76a8045d90a70c22010d6f2eee45f69e973ce10580",
+    "zh:34d58f6bf64afc491359ad1455007e1eb9aef60be17909096ec88a802b6f72b2",
+    "zh:7a7d709aeb7b2945f5a9a0497976a85bceb07b2cbf236c8c1bb0b7b079b839ab",
+    "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+    "zh:965fbb6042acd6fbf77a9b5c3321edbfa0aa6bf0359394afbf0a7e1392245324",
+    "zh:9e4ac8eae03d1243b9283b202132c007d5c4ee533d1c5efc690403caaaaa7aac",
+    "zh:a51833ca1c6983e32a937ea3864b6037c1ccb97a4917cafb38771a3aa583cc77",
+    "zh:ac2eba5efca9f0bf4ecca3b23c2a89c4318ef7cda45e374811e42cced0aa660b",
+    "zh:c77663f4c0e4ca799e5f1abfa94cfe15f36e9879e637a9196ea01fcaeba13286",
+    "zh:dc0ab43f1affe80e117cea108780afe53d7c97357566ded87f53221828c875de",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/main.tf b/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/main.tf
new file mode 100644
index 0000000..a73a097
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/main.tf
@@ -0,0 +1,19 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_simple_resource" "base" {
+  string = "Hello, change!"
+  number = 0
+}
+
+resource "tfcoremock_simple_resource" "dependent" {
+  string = tfcoremock_simple_resource.base.string
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/spec.json b/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/spec.json
new file mode 100644
index 0000000..273ef1b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests that relevant attributes are applied when dependent resources are updated by drift",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/terraform.resource/1b17b502-96c9-fcc3-3b09-2af1c3de6ad8.json b/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/terraform.resource/1b17b502-96c9-fcc3-3b09-2af1c3de6ad8.json
new file mode 100644
index 0000000..cd2b86e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/terraform.resource/1b17b502-96c9-fcc3-3b09-2af1c3de6ad8.json
@@ -0,0 +1,10 @@
+{
+  "values": {
+    "id": {
+      "string": "1b17b502-96c9-fcc3-3b09-2af1c3de6ad8"
+    },
+    "string": {
+      "string": "Hello, world!"
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/terraform.resource/f6f74ca6-e8ef-e51f-522c-433b9ed5038f.json b/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/terraform.resource/f6f74ca6-e8ef-e51f-522c-433b9ed5038f.json
new file mode 100644
index 0000000..1e1a7ef
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/terraform.resource/f6f74ca6-e8ef-e51f-522c-433b9ed5038f.json
@@ -0,0 +1,13 @@
+{
+  "values": {
+    "id": {
+      "string": "f6f74ca6-e8ef-e51f-522c-433b9ed5038f"
+    },
+    "number": {
+      "number": "1"
+    },
+    "string": {
+      "string": "Hello, drift!"
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/terraform.tfstate
new file mode 100644
index 0000000..9ad07bf
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_relevant_attributes/terraform.tfstate
@@ -0,0 +1,53 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.7",
+  "serial": 5,
+  "lineage": "f521f089-8673-e4a9-93a7-4f01f72fbc15",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_simple_resource",
+      "name": "base",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "bool": null,
+            "float": null,
+            "id": "f6f74ca6-e8ef-e51f-522c-433b9ed5038f",
+            "integer": null,
+            "number": 0,
+            "string": "Hello, world!"
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    },
+    {
+      "mode": "managed",
+      "type": "tfcoremock_simple_resource",
+      "name": "dependent",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "bool": null,
+            "float": null,
+            "id": "1b17b502-96c9-fcc3-3b09-2af1c3de6ad8",
+            "integer": null,
+            "number": null,
+            "string": "Hello, world!"
+          },
+          "sensitive_attributes": [],
+          "dependencies": [
+            "tfcoremock_simple_resource.base"
+          ]
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_simple/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/drift_simple/.terraform.lock.hcl
new file mode 100644
index 0000000..d2d6193
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_simple/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/tfcoremock" {
+  version     = "0.1.1"
+  constraints = "0.1.1"
+  hashes = [
+    "h1:K5ImnTbl0eD02BQgVe6pNn5w2wW07j9t7iDUwqPvcy0=",
+    "zh:0219ffa02c6f2cf1f519ea42a89615cfbab8219803bcdb4a3614793952b1f5a8",
+    "zh:13915c1eb4f2ad384c6ce343eebe108ddfb0a103e19f1d8b199c0af8e57bc74a",
+    "zh:1c265814efa730540a475f76a8045d90a70c22010d6f2eee45f69e973ce10580",
+    "zh:34d58f6bf64afc491359ad1455007e1eb9aef60be17909096ec88a802b6f72b2",
+    "zh:7a7d709aeb7b2945f5a9a0497976a85bceb07b2cbf236c8c1bb0b7b079b839ab",
+    "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+    "zh:965fbb6042acd6fbf77a9b5c3321edbfa0aa6bf0359394afbf0a7e1392245324",
+    "zh:9e4ac8eae03d1243b9283b202132c007d5c4ee533d1c5efc690403caaaaa7aac",
+    "zh:a51833ca1c6983e32a937ea3864b6037c1ccb97a4917cafb38771a3aa583cc77",
+    "zh:ac2eba5efca9f0bf4ecca3b23c2a89c4318ef7cda45e374811e42cced0aa660b",
+    "zh:c77663f4c0e4ca799e5f1abfa94cfe15f36e9879e637a9196ea01fcaeba13286",
+    "zh:dc0ab43f1affe80e117cea108780afe53d7c97357566ded87f53221828c875de",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_simple/main.tf b/v1.5.7/testing/equivalence-tests/tests/drift_simple/main.tf
new file mode 100644
index 0000000..77e8913
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_simple/main.tf
@@ -0,0 +1,14 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_simple_resource" "drift" {
+  string = "Hello, world!"
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_simple/spec.json b/v1.5.7/testing/equivalence-tests/tests/drift_simple/spec.json
new file mode 100644
index 0000000..71d921b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_simple/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "a simple test that models drift in a single resource by updating an existing resource outside of Terraform",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_simple/terraform.resource/f3c6ddc5-37d5-0170-64ff-518ad421385a.json b/v1.5.7/testing/equivalence-tests/tests/drift_simple/terraform.resource/f3c6ddc5-37d5-0170-64ff-518ad421385a.json
new file mode 100644
index 0000000..14976bf
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_simple/terraform.resource/f3c6ddc5-37d5-0170-64ff-518ad421385a.json
@@ -0,0 +1,10 @@
+{
+  "values": {
+    "id": {
+      "string": "f3c6ddc5-37d5-0170-64ff-518ad421385a"
+    },
+    "string": {
+      "string": "Hello, drift!"
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/drift_simple/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/drift_simple/terraform.tfstate
new file mode 100644
index 0000000..2d652ab
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/drift_simple/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.7",
+  "serial": 1,
+  "lineage": "3ee5327f-66cc-dd24-f2f1-95ef63c0bcb8",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_simple_resource",
+      "name": "drift",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "bool": null,
+            "float": null,
+            "id": "f3c6ddc5-37d5-0170-64ff-518ad421385a",
+            "integer": null,
+            "number": null,
+            "string": "Hello, world!"
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex/main.tf b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex/main.tf
new file mode 100644
index 0000000..64335c7
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex/main.tf
@@ -0,0 +1,209 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_complex_resource" "complex" {
+  id = "64564E36-BFCB-458B-9405-EBBF6A3CAC7A"
+
+  number  = 123456789.0
+  integer = 987654321
+  float   = 987654321.0
+
+  string = "a not very long or complex string"
+
+  bool = true
+
+  list = [
+    {
+      string = "this is my first entry in the list, and doesn't contain anything interesting"
+    },
+    {
+      string = "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines"
+    },
+    {
+      string = "this is my third entry, and I actually have a nested list"
+
+      list = [
+        {
+          number = 0
+        },
+        {
+          number = 1
+        },
+        {
+          number = 2
+        }
+      ]
+    },
+    {
+      string = "this is my fourth entry, and I actually have a nested set"
+
+      set = [
+        {
+          number = 0
+        },
+        {
+          number = 1
+        },
+      ]
+    }
+  ]
+
+  object = {
+    string = "i am a nested object"
+
+    number = 0
+    bool   = false
+
+    object = {
+      string = "i am a nested nested object"
+      number = 1
+      bool   = true
+    }
+  }
+
+  map = {
+    "key_one" = {
+      string = "this is my first entry in the map, and doesn't contain anything interesting"
+    },
+    "key_two" = {
+      string = "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+    },
+    "key_three" = {
+      string = "this is my third entry, and I actually have a nested list"
+
+      list = [
+        {
+          number = 0
+        },
+        {
+          number = 1
+        },
+        {
+          number = 2
+        }
+      ]
+    },
+    "key_four" = {
+      string = "this is my fourth entry, and I actually have a nested set"
+
+      set = [
+        {
+          number = 0
+        },
+        {
+          number = 1
+        },
+      ]
+    }
+  }
+
+  set = [
+    {
+      string = "this is my first entry in the set, and doesn't contain anything interesting"
+    },
+    {
+      string = "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+    },
+    {
+      string = "this is my third entry, and I actually have a nested list"
+
+      list = [
+        {
+          number = 0
+        },
+        {
+          number = 1
+        },
+        {
+          number = 2
+        }
+      ]
+    },
+    {
+      string = "this is my fourth entry, and I actually have a nested set"
+
+      set = [
+        {
+          number = 0
+        },
+        {
+          number = 1
+        },
+      ]
+    }
+  ]
+
+  list_block {
+    string = "{\"index\":0}"
+  }
+
+  list_block {
+    string = "{\"index\":1}"
+
+    list = [
+      {
+        number = 0
+      },
+      {
+        number = 1
+      },
+      {
+        number = 2
+      }
+    ]
+  }
+
+  list_block {
+    string = "{\"index\":2}"
+
+    set = [
+      {
+        number = 0
+      },
+      {
+        number = 1
+      },
+    ]
+  }
+
+  set_block {
+    string = "{\"index\":0}"
+  }
+
+  set_block {
+    string = "{\"index\":1}"
+
+    list = [
+      {
+        number = 0
+      },
+      {
+        number = 1
+      },
+      {
+        number = 2
+      }
+    ]
+  }
+
+  set_block {
+    string = "{\"index\":2}"
+
+    set = [
+      {
+        number = 0
+      },
+      {
+        number = 1
+      },
+    ]
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex/spec.json b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex/spec.json
new file mode 100644
index 0000000..8fc0b7b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex/spec.json
@@ -0,0 +1,6 @@
+{
+  "description": "this test creates an almost fully populated tfcoremock_complex_resource, which should cover most basic Terraform use cases",
+  "include_files": [],
+  "ignore_fields": {}
+}
+
diff --git a/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_destroy/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_destroy/.terraform.lock.hcl
new file mode 100644
index 0000000..d2d6193
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_destroy/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/tfcoremock" {
+  version     = "0.1.1"
+  constraints = "0.1.1"
+  hashes = [
+    "h1:K5ImnTbl0eD02BQgVe6pNn5w2wW07j9t7iDUwqPvcy0=",
+    "zh:0219ffa02c6f2cf1f519ea42a89615cfbab8219803bcdb4a3614793952b1f5a8",
+    "zh:13915c1eb4f2ad384c6ce343eebe108ddfb0a103e19f1d8b199c0af8e57bc74a",
+    "zh:1c265814efa730540a475f76a8045d90a70c22010d6f2eee45f69e973ce10580",
+    "zh:34d58f6bf64afc491359ad1455007e1eb9aef60be17909096ec88a802b6f72b2",
+    "zh:7a7d709aeb7b2945f5a9a0497976a85bceb07b2cbf236c8c1bb0b7b079b839ab",
+    "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+    "zh:965fbb6042acd6fbf77a9b5c3321edbfa0aa6bf0359394afbf0a7e1392245324",
+    "zh:9e4ac8eae03d1243b9283b202132c007d5c4ee533d1c5efc690403caaaaa7aac",
+    "zh:a51833ca1c6983e32a937ea3864b6037c1ccb97a4917cafb38771a3aa583cc77",
+    "zh:ac2eba5efca9f0bf4ecca3b23c2a89c4318ef7cda45e374811e42cced0aa660b",
+    "zh:c77663f4c0e4ca799e5f1abfa94cfe15f36e9879e637a9196ea01fcaeba13286",
+    "zh:dc0ab43f1affe80e117cea108780afe53d7c97357566ded87f53221828c875de",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_destroy/main.tf b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_destroy/main.tf
new file mode 100644
index 0000000..f5b590f
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_destroy/main.tf
@@ -0,0 +1,206 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_complex_resource" "complex" {
+  id = "64564E36-BFCB-458B-9405-EBBF6A3CAC7A"
+
+  number  = 987654321.0
+  integer = 123456789
+  float   = 123456789.0
+
+  string = "a not very long or complex string"
+
+  bool = true
+
+  list = [
+    {
+      string = "this is my first entry in the list, and doesn't contain anything interesting"
+    },
+    {
+      string = "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines\nbut I've been edited"
+    },
+    {
+      string = "this is my third entry, and I actually have a nested list"
+
+      list = [
+        {
+          number = 0
+        },
+        {
+          number = 1
+        },
+        {
+          number = 3
+        },
+        {
+          number = 4
+        }
+      ]
+    },
+    {
+      string = "this is my fourth entry, and I actually have a nested set and I edited my test"
+
+      set = [
+        {
+          number = 0
+        },
+        {
+          number = 2
+        },
+      ]
+    }
+  ]
+
+  object = {
+    string = "i am a nested object"
+
+    number = 0
+
+    object = {
+      string = "i am a nested nested object"
+      bool   = true
+    }
+  }
+
+  map = {
+    "key_one" = {
+      string = "this is my first entry in the map, and doesn't contain anything interesting"
+    },
+    "key_two" = {
+      string = "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+    },
+    "key_three" = {
+      string = "this is my third entry, and I actually have a nested list"
+
+      list = [
+        {
+          number = 0
+        },
+        {
+          number = 3
+        },
+        {
+          number = 1
+        },
+        {
+          number = 2
+        }
+      ]
+    },
+    "key_four" = {
+      string = "this is my fourth entry, and I actually have a nested set"
+
+      set = [
+        {
+          number = 0
+        },
+        {
+          number = 1
+        },
+        {
+          number = 3
+        },
+        {
+          number = 4
+        },
+      ]
+    }
+  }
+
+  set = [
+    {
+      string = "this is my first entry in the set, and doesn't contain anything interesting"
+    },
+    {
+      string = "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+    },
+    {
+      string = "this is my third entry, and I actually have a nested list"
+
+      list = [
+        {
+          number = 0
+        },
+        {
+          number = 1
+        },
+        {
+          number = 2
+        }
+      ]
+    },
+    {
+      string = "this is my fourth entry, and I actually have a nested set"
+
+      set = [
+        {
+          number = 0
+        },
+        {
+          number = 1
+        },
+      ]
+    }
+  ]
+
+  list_block {
+    string = "{\"index\":0}"
+  }
+
+  list_block {
+    string = "{\"index\":1}"
+
+    list = [
+      {
+        number = 0
+      },
+      {
+        number = 1
+      },
+      {
+        number = 2
+      }
+    ]
+  }
+
+  set_block {
+    string = "{\"index\":1}"
+
+    list = [
+      {
+        number = 0
+      },
+      {
+        number = 1
+      },
+      {
+        number = 2
+      }
+    ]
+  }
+
+  set_block {
+    string = "{\"index\":2}"
+
+    set = [
+      {
+        number = 0
+      },
+      {
+        number = 1
+      },
+    ]
+  }
+
+  set_block {
+    string = "{\"index\":3}"
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_destroy/spec.json b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_destroy/spec.json
new file mode 100644
index 0000000..e91bd2c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_destroy/spec.json
@@ -0,0 +1,42 @@
+{
+  "include_files": [],
+  "ignore_fields": {},
+  "commands": [
+    {
+      "name": "init",
+      "arguments": ["init"],
+      "capture_output": false
+    },
+    {
+      "name": "plan",
+      "arguments": ["plan", "-out=equivalence_test_plan", "-no-color", "-destroy"],
+      "capture_output": true,
+      "output_file_name": "plan",
+      "has_json_output": false
+    },
+    {
+      "name": "apply",
+      "arguments": ["destroy", "-json", "-auto-approve"],
+      "capture_output": true,
+      "output_file_name": "apply.json",
+      "has_json_output": true,
+      "streams_json_output": true
+    },
+    {
+      "name": "show_state",
+      "arguments": ["show", "-json"],
+      "capture_output": true,
+      "output_file_name": "state.json",
+      "has_json_output": true,
+      "streams_json_output": false
+    },
+    {
+      "name": "show_plan",
+      "arguments": ["show", "-json", "equivalence_test_plan"],
+      "capture_output": true,
+      "output_file_name": "plan.json",
+      "has_json_output": true,
+      "streams_json_output": false
+    }
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_destroy/terraform.resource/64564E36-BFCB-458B-9405-EBBF6A3CAC7A.json b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_destroy/terraform.resource/64564E36-BFCB-458B-9405-EBBF6A3CAC7A.json
new file mode 100644
index 0000000..49aa8d9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_destroy/terraform.resource/64564E36-BFCB-458B-9405-EBBF6A3CAC7A.json
@@ -0,0 +1,445 @@
+{
+  "values": {
+    "bool": {
+      "boolean": true
+    },
+    "float": {
+      "number": "9.87654321e+08"
+    },
+    "id": {
+      "string": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A"
+    },
+    "integer": {
+      "number": "9.87654321e+08"
+    },
+    "list": {
+      "list": [
+        {
+          "object": {
+            "string": {
+              "string": "this is my first entry in the list, and doesn't contain anything interesting"
+            }
+          }
+        },
+        {
+          "object": {
+            "string": {
+              "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines"
+            }
+          }
+        },
+        {
+          "object": {
+            "list": {
+              "list": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "2"
+                    }
+                  }
+                }
+              ]
+            },
+            "string": {
+              "string": "this is my third entry, and I actually have a nested list"
+            }
+          }
+        },
+        {
+          "object": {
+            "set": {
+              "set": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                }
+              ]
+            },
+            "string": {
+              "string": "this is my fourth entry, and I actually have a nested set"
+            }
+          }
+        }
+      ]
+    },
+    "list_block": {
+      "list": [
+        {
+          "object": {
+            "list_block": {
+              "list": []
+            },
+            "set_block": {
+              "set": []
+            },
+            "string": {
+              "string": "{\"index\":0}"
+            }
+          }
+        },
+        {
+          "object": {
+            "list": {
+              "list": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "2"
+                    }
+                  }
+                }
+              ]
+            },
+            "list_block": {
+              "list": []
+            },
+            "set_block": {
+              "set": []
+            },
+            "string": {
+              "string": "{\"index\":1}"
+            }
+          }
+        },
+        {
+          "object": {
+            "list_block": {
+              "list": []
+            },
+            "set": {
+              "set": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                }
+              ]
+            },
+            "set_block": {
+              "set": []
+            },
+            "string": {
+              "string": "{\"index\":2}"
+            }
+          }
+        }
+      ]
+    },
+    "map": {
+      "map": {
+        "key_four": {
+          "object": {
+            "set": {
+              "set": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                }
+              ]
+            },
+            "string": {
+              "string": "this is my fourth entry, and I actually have a nested set"
+            }
+          }
+        },
+        "key_one": {
+          "object": {
+            "string": {
+              "string": "this is my first entry in the map, and doesn't contain anything interesting"
+            }
+          }
+        },
+        "key_three": {
+          "object": {
+            "list": {
+              "list": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "2"
+                    }
+                  }
+                }
+              ]
+            },
+            "string": {
+              "string": "this is my third entry, and I actually have a nested list"
+            }
+          }
+        },
+        "key_two": {
+          "object": {
+            "string": {
+              "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+            }
+          }
+        }
+      }
+    },
+    "number": {
+      "number": "1.23456789e+08"
+    },
+    "object": {
+      "object": {
+        "bool": {
+          "boolean": false
+        },
+        "number": {
+          "number": "0"
+        },
+        "object": {
+          "object": {
+            "bool": {
+              "boolean": true
+            },
+            "number": {
+              "number": "1"
+            },
+            "string": {
+              "string": "i am a nested nested object"
+            }
+          }
+        },
+        "string": {
+          "string": "i am a nested object"
+        }
+      }
+    },
+    "set": {
+      "set": [
+        {
+          "object": {
+            "list": {
+              "list": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "2"
+                    }
+                  }
+                }
+              ]
+            },
+            "string": {
+              "string": "this is my third entry, and I actually have a nested list"
+            }
+          }
+        },
+        {
+          "object": {
+            "set": {
+              "set": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                }
+              ]
+            },
+            "string": {
+              "string": "this is my fourth entry, and I actually have a nested set"
+            }
+          }
+        },
+        {
+          "object": {
+            "string": {
+              "string": "this is my first entry in the set, and doesn't contain anything interesting"
+            }
+          }
+        },
+        {
+          "object": {
+            "string": {
+              "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+            }
+          }
+        }
+      ]
+    },
+    "set_block": {
+      "set": [
+        {
+          "object": {
+            "list": {
+              "list": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "2"
+                    }
+                  }
+                }
+              ]
+            },
+            "list_block": {
+              "list": []
+            },
+            "set_block": {
+              "set": []
+            },
+            "string": {
+              "string": "{\"index\":1}"
+            }
+          }
+        },
+        {
+          "object": {
+            "list_block": {
+              "list": []
+            },
+            "set": {
+              "set": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                }
+              ]
+            },
+            "set_block": {
+              "set": []
+            },
+            "string": {
+              "string": "{\"index\":2}"
+            }
+          }
+        },
+        {
+          "object": {
+            "list_block": {
+              "list": []
+            },
+            "set_block": {
+              "set": []
+            },
+            "string": {
+              "string": "{\"index\":0}"
+            }
+          }
+        }
+      ]
+    },
+    "string": {
+      "string": "a not very long or complex string"
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_destroy/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_destroy/terraform.tfstate
new file mode 100644
index 0000000..6945ad2
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_destroy/terraform.tfstate
@@ -0,0 +1,556 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.7",
+  "serial": 1,
+  "lineage": "bc319b50-c252-a9b5-3ce3-3128618500d6",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_complex_resource",
+      "name": "complex",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "bool": true,
+            "float": 987654321,
+            "id": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+            "integer": 987654321,
+            "list": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the list, and doesn't contain anything interesting"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              }
+            ],
+            "list_block": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":0}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":1}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "set_block": [],
+                "string": "{\"index\":2}"
+              }
+            ],
+            "map": {
+              "key_four": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              },
+              "key_one": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the map, and doesn't contain anything interesting"
+              },
+              "key_three": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              "key_two": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+              }
+            },
+            "number": 123456789,
+            "object": {
+              "bool": false,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": 0,
+              "object": {
+                "bool": true,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": 1,
+                "object": null,
+                "set": null,
+                "string": "i am a nested nested object"
+              },
+              "set": null,
+              "string": "i am a nested object"
+            },
+            "set": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the set, and doesn't contain anything interesting"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+              }
+            ],
+            "set_block": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":1}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "set_block": [],
+                "string": "{\"index\":2}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":0}"
+              }
+            ],
+            "string": "a not very long or complex string"
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_update/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_update/.terraform.lock.hcl
new file mode 100644
index 0000000..d2d6193
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_update/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/tfcoremock" {
+  version     = "0.1.1"
+  constraints = "0.1.1"
+  hashes = [
+    "h1:K5ImnTbl0eD02BQgVe6pNn5w2wW07j9t7iDUwqPvcy0=",
+    "zh:0219ffa02c6f2cf1f519ea42a89615cfbab8219803bcdb4a3614793952b1f5a8",
+    "zh:13915c1eb4f2ad384c6ce343eebe108ddfb0a103e19f1d8b199c0af8e57bc74a",
+    "zh:1c265814efa730540a475f76a8045d90a70c22010d6f2eee45f69e973ce10580",
+    "zh:34d58f6bf64afc491359ad1455007e1eb9aef60be17909096ec88a802b6f72b2",
+    "zh:7a7d709aeb7b2945f5a9a0497976a85bceb07b2cbf236c8c1bb0b7b079b839ab",
+    "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+    "zh:965fbb6042acd6fbf77a9b5c3321edbfa0aa6bf0359394afbf0a7e1392245324",
+    "zh:9e4ac8eae03d1243b9283b202132c007d5c4ee533d1c5efc690403caaaaa7aac",
+    "zh:a51833ca1c6983e32a937ea3864b6037c1ccb97a4917cafb38771a3aa583cc77",
+    "zh:ac2eba5efca9f0bf4ecca3b23c2a89c4318ef7cda45e374811e42cced0aa660b",
+    "zh:c77663f4c0e4ca799e5f1abfa94cfe15f36e9879e637a9196ea01fcaeba13286",
+    "zh:dc0ab43f1affe80e117cea108780afe53d7c97357566ded87f53221828c875de",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_update/main.tf b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_update/main.tf
new file mode 100644
index 0000000..f5b590f
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_update/main.tf
@@ -0,0 +1,206 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_complex_resource" "complex" {
+  id = "64564E36-BFCB-458B-9405-EBBF6A3CAC7A"
+
+  number  = 987654321.0
+  integer = 123456789
+  float   = 123456789.0
+
+  string = "a not very long or complex string"
+
+  bool = true
+
+  list = [
+    {
+      string = "this is my first entry in the list, and doesn't contain anything interesting"
+    },
+    {
+      string = "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines\nbut I've been edited"
+    },
+    {
+      string = "this is my third entry, and I actually have a nested list"
+
+      list = [
+        {
+          number = 0
+        },
+        {
+          number = 1
+        },
+        {
+          number = 3
+        },
+        {
+          number = 4
+        }
+      ]
+    },
+    {
+      string = "this is my fourth entry, and I actually have a nested set and I edited my test"
+
+      set = [
+        {
+          number = 0
+        },
+        {
+          number = 2
+        },
+      ]
+    }
+  ]
+
+  object = {
+    string = "i am a nested object"
+
+    number = 0
+
+    object = {
+      string = "i am a nested nested object"
+      bool   = true
+    }
+  }
+
+  map = {
+    "key_one" = {
+      string = "this is my first entry in the map, and doesn't contain anything interesting"
+    },
+    "key_two" = {
+      string = "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+    },
+    "key_three" = {
+      string = "this is my third entry, and I actually have a nested list"
+
+      list = [
+        {
+          number = 0
+        },
+        {
+          number = 3
+        },
+        {
+          number = 1
+        },
+        {
+          number = 2
+        }
+      ]
+    },
+    "key_four" = {
+      string = "this is my fourth entry, and I actually have a nested set"
+
+      set = [
+        {
+          number = 0
+        },
+        {
+          number = 1
+        },
+        {
+          number = 3
+        },
+        {
+          number = 4
+        },
+      ]
+    }
+  }
+
+  set = [
+    {
+      string = "this is my first entry in the set, and doesn't contain anything interesting"
+    },
+    {
+      string = "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+    },
+    {
+      string = "this is my third entry, and I actually have a nested list"
+
+      list = [
+        {
+          number = 0
+        },
+        {
+          number = 1
+        },
+        {
+          number = 2
+        }
+      ]
+    },
+    {
+      string = "this is my fourth entry, and I actually have a nested set"
+
+      set = [
+        {
+          number = 0
+        },
+        {
+          number = 1
+        },
+      ]
+    }
+  ]
+
+  list_block {
+    string = "{\"index\":0}"
+  }
+
+  list_block {
+    string = "{\"index\":1}"
+
+    list = [
+      {
+        number = 0
+      },
+      {
+        number = 1
+      },
+      {
+        number = 2
+      }
+    ]
+  }
+
+  set_block {
+    string = "{\"index\":1}"
+
+    list = [
+      {
+        number = 0
+      },
+      {
+        number = 1
+      },
+      {
+        number = 2
+      }
+    ]
+  }
+
+  set_block {
+    string = "{\"index\":2}"
+
+    set = [
+      {
+        number = 0
+      },
+      {
+        number = 1
+      },
+    ]
+  }
+
+  set_block {
+    string = "{\"index\":3}"
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_update/spec.json b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_update/spec.json
new file mode 100644
index 0000000..cc62355
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_update/spec.json
@@ -0,0 +1,5 @@
+{
+  "include_files": [],
+  "ignore_fields": {}
+}
+
diff --git a/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_update/terraform.resource/64564E36-BFCB-458B-9405-EBBF6A3CAC7A.json b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_update/terraform.resource/64564E36-BFCB-458B-9405-EBBF6A3CAC7A.json
new file mode 100644
index 0000000..49aa8d9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_update/terraform.resource/64564E36-BFCB-458B-9405-EBBF6A3CAC7A.json
@@ -0,0 +1,445 @@
+{
+  "values": {
+    "bool": {
+      "boolean": true
+    },
+    "float": {
+      "number": "9.87654321e+08"
+    },
+    "id": {
+      "string": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A"
+    },
+    "integer": {
+      "number": "9.87654321e+08"
+    },
+    "list": {
+      "list": [
+        {
+          "object": {
+            "string": {
+              "string": "this is my first entry in the list, and doesn't contain anything interesting"
+            }
+          }
+        },
+        {
+          "object": {
+            "string": {
+              "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines"
+            }
+          }
+        },
+        {
+          "object": {
+            "list": {
+              "list": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "2"
+                    }
+                  }
+                }
+              ]
+            },
+            "string": {
+              "string": "this is my third entry, and I actually have a nested list"
+            }
+          }
+        },
+        {
+          "object": {
+            "set": {
+              "set": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                }
+              ]
+            },
+            "string": {
+              "string": "this is my fourth entry, and I actually have a nested set"
+            }
+          }
+        }
+      ]
+    },
+    "list_block": {
+      "list": [
+        {
+          "object": {
+            "list_block": {
+              "list": []
+            },
+            "set_block": {
+              "set": []
+            },
+            "string": {
+              "string": "{\"index\":0}"
+            }
+          }
+        },
+        {
+          "object": {
+            "list": {
+              "list": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "2"
+                    }
+                  }
+                }
+              ]
+            },
+            "list_block": {
+              "list": []
+            },
+            "set_block": {
+              "set": []
+            },
+            "string": {
+              "string": "{\"index\":1}"
+            }
+          }
+        },
+        {
+          "object": {
+            "list_block": {
+              "list": []
+            },
+            "set": {
+              "set": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                }
+              ]
+            },
+            "set_block": {
+              "set": []
+            },
+            "string": {
+              "string": "{\"index\":2}"
+            }
+          }
+        }
+      ]
+    },
+    "map": {
+      "map": {
+        "key_four": {
+          "object": {
+            "set": {
+              "set": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                }
+              ]
+            },
+            "string": {
+              "string": "this is my fourth entry, and I actually have a nested set"
+            }
+          }
+        },
+        "key_one": {
+          "object": {
+            "string": {
+              "string": "this is my first entry in the map, and doesn't contain anything interesting"
+            }
+          }
+        },
+        "key_three": {
+          "object": {
+            "list": {
+              "list": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "2"
+                    }
+                  }
+                }
+              ]
+            },
+            "string": {
+              "string": "this is my third entry, and I actually have a nested list"
+            }
+          }
+        },
+        "key_two": {
+          "object": {
+            "string": {
+              "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+            }
+          }
+        }
+      }
+    },
+    "number": {
+      "number": "1.23456789e+08"
+    },
+    "object": {
+      "object": {
+        "bool": {
+          "boolean": false
+        },
+        "number": {
+          "number": "0"
+        },
+        "object": {
+          "object": {
+            "bool": {
+              "boolean": true
+            },
+            "number": {
+              "number": "1"
+            },
+            "string": {
+              "string": "i am a nested nested object"
+            }
+          }
+        },
+        "string": {
+          "string": "i am a nested object"
+        }
+      }
+    },
+    "set": {
+      "set": [
+        {
+          "object": {
+            "list": {
+              "list": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "2"
+                    }
+                  }
+                }
+              ]
+            },
+            "string": {
+              "string": "this is my third entry, and I actually have a nested list"
+            }
+          }
+        },
+        {
+          "object": {
+            "set": {
+              "set": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                }
+              ]
+            },
+            "string": {
+              "string": "this is my fourth entry, and I actually have a nested set"
+            }
+          }
+        },
+        {
+          "object": {
+            "string": {
+              "string": "this is my first entry in the set, and doesn't contain anything interesting"
+            }
+          }
+        },
+        {
+          "object": {
+            "string": {
+              "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+            }
+          }
+        }
+      ]
+    },
+    "set_block": {
+      "set": [
+        {
+          "object": {
+            "list": {
+              "list": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "2"
+                    }
+                  }
+                }
+              ]
+            },
+            "list_block": {
+              "list": []
+            },
+            "set_block": {
+              "set": []
+            },
+            "string": {
+              "string": "{\"index\":1}"
+            }
+          }
+        },
+        {
+          "object": {
+            "list_block": {
+              "list": []
+            },
+            "set": {
+              "set": [
+                {
+                  "object": {
+                    "number": {
+                      "number": "0"
+                    }
+                  }
+                },
+                {
+                  "object": {
+                    "number": {
+                      "number": "1"
+                    }
+                  }
+                }
+              ]
+            },
+            "set_block": {
+              "set": []
+            },
+            "string": {
+              "string": "{\"index\":2}"
+            }
+          }
+        },
+        {
+          "object": {
+            "list_block": {
+              "list": []
+            },
+            "set_block": {
+              "set": []
+            },
+            "string": {
+              "string": "{\"index\":0}"
+            }
+          }
+        }
+      ]
+    },
+    "string": {
+      "string": "a not very long or complex string"
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_update/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_update/terraform.tfstate
new file mode 100644
index 0000000..6945ad2
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/fully_populated_complex_update/terraform.tfstate
@@ -0,0 +1,556 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.7",
+  "serial": 1,
+  "lineage": "bc319b50-c252-a9b5-3ce3-3128618500d6",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_complex_resource",
+      "name": "complex",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "bool": true,
+            "float": 987654321,
+            "id": "64564E36-BFCB-458B-9405-EBBF6A3CAC7A",
+            "integer": 987654321,
+            "list": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the list, and doesn't contain anything interesting"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the list\nI am a bit more interesting\nand contain multiple lines"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              }
+            ],
+            "list_block": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":0}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":1}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "set_block": [],
+                "string": "{\"index\":2}"
+              }
+            ],
+            "map": {
+              "key_four": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              },
+              "key_one": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the map, and doesn't contain anything interesting"
+              },
+              "key_three": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              "key_two": {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the map\nI am a bit more interesting\nand contain multiple lines"
+              }
+            },
+            "number": 123456789,
+            "object": {
+              "bool": false,
+              "float": null,
+              "integer": null,
+              "list": null,
+              "map": null,
+              "number": 0,
+              "object": {
+                "bool": true,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": 1,
+                "object": null,
+                "set": null,
+                "string": "i am a nested nested object"
+              },
+              "set": null,
+              "string": "i am a nested object"
+            },
+            "set": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my third entry, and I actually have a nested list"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "string": "this is my fourth entry, and I actually have a nested set"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my first entry in the set, and doesn't contain anything interesting"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "string": "this is my second entry in the set\nI am a bit more interesting\nand contain multiple lines"
+              }
+            ],
+            "set_block": [
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 2,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":1}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": [
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 0,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  },
+                  {
+                    "bool": null,
+                    "float": null,
+                    "integer": null,
+                    "list": null,
+                    "map": null,
+                    "number": 1,
+                    "object": null,
+                    "set": null,
+                    "string": null
+                  }
+                ],
+                "set_block": [],
+                "string": "{\"index\":2}"
+              },
+              {
+                "bool": null,
+                "float": null,
+                "integer": null,
+                "list": null,
+                "list_block": [],
+                "map": null,
+                "number": null,
+                "object": null,
+                "set": null,
+                "set_block": [],
+                "string": "{\"index\":0}"
+              }
+            ],
+            "string": "a not very long or complex string"
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/local_provider_basic/main.tf b/v1.5.7/testing/equivalence-tests/tests/local_provider_basic/main.tf
new file mode 100644
index 0000000..7640a43
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/local_provider_basic/main.tf
@@ -0,0 +1,21 @@
+terraform {
+  required_providers {
+    local = {
+      source  = "hashicorp/local"
+      version = "2.2.3"
+    }
+  }
+}
+
+locals {
+  contents = jsonencode({
+    "hello" = "world"
+  })
+}
+
+provider "local" {}
+
+resource "local_file" "local_file" {
+  filename = "output.json"
+  content  = local.contents
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/local_provider_basic/spec.json b/v1.5.7/testing/equivalence-tests/tests/local_provider_basic/spec.json
new file mode 100644
index 0000000..e47d6d2
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/local_provider_basic/spec.json
@@ -0,0 +1,7 @@
+{
+  "description": "tests creating a local file using the local provider",
+  "include_files": [
+    "output.json"
+  ],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/local_provider_delete/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/local_provider_delete/.terraform.lock.hcl
new file mode 100644
index 0000000..7379b9c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/local_provider_delete/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/local" {
+  version     = "2.2.3"
+  constraints = "2.2.3"
+  hashes = [
+    "h1:FvRIEgCmAezgZUqb2F+PZ9WnSSnR5zbEM2ZI+GLmbMk=",
+    "zh:04f0978bb3e052707b8e82e46780c371ac1c66b689b4a23bbc2f58865ab7d5c0",
+    "zh:6484f1b3e9e3771eb7cc8e8bab8b35f939a55d550b3f4fb2ab141a24269ee6aa",
+    "zh:78a56d59a013cb0f7eb1c92815d6eb5cf07f8b5f0ae20b96d049e73db915b238",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:8aa9950f4c4db37239bcb62e19910c49e47043f6c8587e5b0396619923657797",
+    "zh:996beea85f9084a725ff0e6473a4594deb5266727c5f56e9c1c7c62ded6addbb",
+    "zh:9a7ef7a21f48fabfd145b2e2a4240ca57517ad155017e86a30860d7c0c109de3",
+    "zh:a63e70ac052aa25120113bcddd50c1f3cfe61f681a93a50cea5595a4b2cc3e1c",
+    "zh:a6e8d46f94108e049ad85dbed60354236dc0b9b5ec8eabe01c4580280a43d3b8",
+    "zh:bb112ce7efbfcfa0e65ed97fa245ef348e0fd5bfa5a7e4ab2091a9bd469f0a9e",
+    "zh:d7bec0da5c094c6955efed100f3fe22fca8866859f87c025be1760feb174d6d9",
+    "zh:fb9f271b72094d07cef8154cd3d50e9aa818a0ea39130bc193132ad7b23076fd",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/local_provider_delete/main.tf b/v1.5.7/testing/equivalence-tests/tests/local_provider_delete/main.tf
new file mode 100644
index 0000000..4b08d8b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/local_provider_delete/main.tf
@@ -0,0 +1,16 @@
+terraform {
+  required_providers {
+    local = {
+      source  = "hashicorp/local"
+      version = "2.2.3"
+    }
+  }
+}
+
+locals {
+  contents = jsonencode({
+    "goodbye" = "world"
+  })
+}
+
+provider "local" {}
diff --git a/v1.5.7/testing/equivalence-tests/tests/local_provider_delete/output.json b/v1.5.7/testing/equivalence-tests/tests/local_provider_delete/output.json
new file mode 100755
index 0000000..3f3571f
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/local_provider_delete/output.json
@@ -0,0 +1 @@
+{"hello":"world"}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/local_provider_delete/spec.json b/v1.5.7/testing/equivalence-tests/tests/local_provider_delete/spec.json
new file mode 100644
index 0000000..e3a2578
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/local_provider_delete/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "test deleting a file created by the local provider",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/local_provider_delete/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/local_provider_delete/terraform.tfstate
new file mode 100644
index 0000000..abdfed0
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/local_provider_delete/terraform.tfstate
@@ -0,0 +1,33 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.0",
+  "serial": 2,
+  "lineage": "e2a94970-ee0e-0eb7-16a5-67e94860dc8e",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "local_file",
+      "name": "local_file",
+      "provider": "provider[\"registry.terraform.io/hashicorp/local\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "content": "{\"hello\":\"world\"}",
+            "content_base64": null,
+            "directory_permission": "0777",
+            "file_permission": "0777",
+            "filename": "output.json",
+            "id": "2248ee2fa0aaaad99178531f924bf00b4b0a8f4e",
+            "sensitive_content": null,
+            "source": null
+          },
+          "sensitive_attributes": [],
+          "private": "bnVsbA=="
+        }
+      ]
+    }
+  ],
+  "check_results": []
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/local_provider_update/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/local_provider_update/.terraform.lock.hcl
new file mode 100644
index 0000000..7379b9c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/local_provider_update/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/local" {
+  version     = "2.2.3"
+  constraints = "2.2.3"
+  hashes = [
+    "h1:FvRIEgCmAezgZUqb2F+PZ9WnSSnR5zbEM2ZI+GLmbMk=",
+    "zh:04f0978bb3e052707b8e82e46780c371ac1c66b689b4a23bbc2f58865ab7d5c0",
+    "zh:6484f1b3e9e3771eb7cc8e8bab8b35f939a55d550b3f4fb2ab141a24269ee6aa",
+    "zh:78a56d59a013cb0f7eb1c92815d6eb5cf07f8b5f0ae20b96d049e73db915b238",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:8aa9950f4c4db37239bcb62e19910c49e47043f6c8587e5b0396619923657797",
+    "zh:996beea85f9084a725ff0e6473a4594deb5266727c5f56e9c1c7c62ded6addbb",
+    "zh:9a7ef7a21f48fabfd145b2e2a4240ca57517ad155017e86a30860d7c0c109de3",
+    "zh:a63e70ac052aa25120113bcddd50c1f3cfe61f681a93a50cea5595a4b2cc3e1c",
+    "zh:a6e8d46f94108e049ad85dbed60354236dc0b9b5ec8eabe01c4580280a43d3b8",
+    "zh:bb112ce7efbfcfa0e65ed97fa245ef348e0fd5bfa5a7e4ab2091a9bd469f0a9e",
+    "zh:d7bec0da5c094c6955efed100f3fe22fca8866859f87c025be1760feb174d6d9",
+    "zh:fb9f271b72094d07cef8154cd3d50e9aa818a0ea39130bc193132ad7b23076fd",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/local_provider_update/main.tf b/v1.5.7/testing/equivalence-tests/tests/local_provider_update/main.tf
new file mode 100644
index 0000000..e47de3c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/local_provider_update/main.tf
@@ -0,0 +1,21 @@
+terraform {
+  required_providers {
+    local = {
+      source  = "hashicorp/local"
+      version = "2.2.3"
+    }
+  }
+}
+
+locals {
+  contents = jsonencode({
+    "goodbye" = "world"
+  })
+}
+
+provider "local" {}
+
+resource "local_file" "local_file" {
+  filename = "output.json"
+  content  = local.contents
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/local_provider_update/output.json b/v1.5.7/testing/equivalence-tests/tests/local_provider_update/output.json
new file mode 100755
index 0000000..3f3571f
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/local_provider_update/output.json
@@ -0,0 +1 @@
+{"hello":"world"}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/local_provider_update/spec.json b/v1.5.7/testing/equivalence-tests/tests/local_provider_update/spec.json
new file mode 100644
index 0000000..17b0f32
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/local_provider_update/spec.json
@@ -0,0 +1,7 @@
+{
+  "description": "tests updating a file using the local provider",
+  "include_files": [
+    "output.json"
+  ],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/local_provider_update/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/local_provider_update/terraform.tfstate
new file mode 100644
index 0000000..abdfed0
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/local_provider_update/terraform.tfstate
@@ -0,0 +1,33 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.0",
+  "serial": 2,
+  "lineage": "e2a94970-ee0e-0eb7-16a5-67e94860dc8e",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "local_file",
+      "name": "local_file",
+      "provider": "provider[\"registry.terraform.io/hashicorp/local\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "content": "{\"hello\":\"world\"}",
+            "content_base64": null,
+            "directory_permission": "0777",
+            "file_permission": "0777",
+            "filename": "output.json",
+            "id": "2248ee2fa0aaaad99178531f924bf00b4b0a8f4e",
+            "sensitive_content": null,
+            "source": null
+          },
+          "sensitive_attributes": [],
+          "private": "bnVsbA=="
+        }
+      ]
+    }
+  ],
+  "check_results": []
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_simple/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/moved_simple/.terraform.lock.hcl
new file mode 100644
index 0000000..d2d6193
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_simple/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/tfcoremock" {
+  version     = "0.1.1"
+  constraints = "0.1.1"
+  hashes = [
+    "h1:K5ImnTbl0eD02BQgVe6pNn5w2wW07j9t7iDUwqPvcy0=",
+    "zh:0219ffa02c6f2cf1f519ea42a89615cfbab8219803bcdb4a3614793952b1f5a8",
+    "zh:13915c1eb4f2ad384c6ce343eebe108ddfb0a103e19f1d8b199c0af8e57bc74a",
+    "zh:1c265814efa730540a475f76a8045d90a70c22010d6f2eee45f69e973ce10580",
+    "zh:34d58f6bf64afc491359ad1455007e1eb9aef60be17909096ec88a802b6f72b2",
+    "zh:7a7d709aeb7b2945f5a9a0497976a85bceb07b2cbf236c8c1bb0b7b079b839ab",
+    "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+    "zh:965fbb6042acd6fbf77a9b5c3321edbfa0aa6bf0359394afbf0a7e1392245324",
+    "zh:9e4ac8eae03d1243b9283b202132c007d5c4ee533d1c5efc690403caaaaa7aac",
+    "zh:a51833ca1c6983e32a937ea3864b6037c1ccb97a4917cafb38771a3aa583cc77",
+    "zh:ac2eba5efca9f0bf4ecca3b23c2a89c4318ef7cda45e374811e42cced0aa660b",
+    "zh:c77663f4c0e4ca799e5f1abfa94cfe15f36e9879e637a9196ea01fcaeba13286",
+    "zh:dc0ab43f1affe80e117cea108780afe53d7c97357566ded87f53221828c875de",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_simple/main.tf b/v1.5.7/testing/equivalence-tests/tests/moved_simple/main.tf
new file mode 100644
index 0000000..356b980
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_simple/main.tf
@@ -0,0 +1,20 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+
+resource "tfcoremock_simple_resource" "second" {
+  string = "Hello, world!"
+}
+
+moved {
+  from = tfcoremock_simple_resource.first
+  to = tfcoremock_simple_resource.second
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_simple/spec.json b/v1.5.7/testing/equivalence-tests/tests/moved_simple/spec.json
new file mode 100644
index 0000000..d9c1fbd
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_simple/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests an unchanged resource being moved",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_simple/terraform.resource/70c47571-66c3-b1dc-2474-47a74b9c7886.json b/v1.5.7/testing/equivalence-tests/tests/moved_simple/terraform.resource/70c47571-66c3-b1dc-2474-47a74b9c7886.json
new file mode 100644
index 0000000..6c63be3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_simple/terraform.resource/70c47571-66c3-b1dc-2474-47a74b9c7886.json
@@ -0,0 +1,10 @@
+{
+  "values": {
+    "id": {
+      "string": "70c47571-66c3-b1dc-2474-47a74b9c7886"
+    },
+    "string": {
+      "string": "Hello, world!"
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_simple/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/moved_simple/terraform.tfstate
new file mode 100644
index 0000000..89f82ba
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_simple/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.7",
+  "serial": 1,
+  "lineage": "4a0f03a7-03fd-9357-9fd2-b3405139fa1d",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_simple_resource",
+      "name": "first",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "bool": null,
+            "float": null,
+            "id": "70c47571-66c3-b1dc-2474-47a74b9c7886",
+            "integer": null,
+            "number": null,
+            "string": "Hello, world!"
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/.terraform.lock.hcl
new file mode 100644
index 0000000..d2d6193
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/tfcoremock" {
+  version     = "0.1.1"
+  constraints = "0.1.1"
+  hashes = [
+    "h1:K5ImnTbl0eD02BQgVe6pNn5w2wW07j9t7iDUwqPvcy0=",
+    "zh:0219ffa02c6f2cf1f519ea42a89615cfbab8219803bcdb4a3614793952b1f5a8",
+    "zh:13915c1eb4f2ad384c6ce343eebe108ddfb0a103e19f1d8b199c0af8e57bc74a",
+    "zh:1c265814efa730540a475f76a8045d90a70c22010d6f2eee45f69e973ce10580",
+    "zh:34d58f6bf64afc491359ad1455007e1eb9aef60be17909096ec88a802b6f72b2",
+    "zh:7a7d709aeb7b2945f5a9a0497976a85bceb07b2cbf236c8c1bb0b7b079b839ab",
+    "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+    "zh:965fbb6042acd6fbf77a9b5c3321edbfa0aa6bf0359394afbf0a7e1392245324",
+    "zh:9e4ac8eae03d1243b9283b202132c007d5c4ee533d1c5efc690403caaaaa7aac",
+    "zh:a51833ca1c6983e32a937ea3864b6037c1ccb97a4917cafb38771a3aa583cc77",
+    "zh:ac2eba5efca9f0bf4ecca3b23c2a89c4318ef7cda45e374811e42cced0aa660b",
+    "zh:c77663f4c0e4ca799e5f1abfa94cfe15f36e9879e637a9196ea01fcaeba13286",
+    "zh:dc0ab43f1affe80e117cea108780afe53d7c97357566ded87f53221828c875de",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/main.tf b/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/main.tf
new file mode 100644
index 0000000..e060e2b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/main.tf
@@ -0,0 +1,23 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_simple_resource" "base_after" {
+  string = "Hello, change!"
+}
+
+resource "tfcoremock_simple_resource" "dependent" {
+  string = tfcoremock_simple_resource.base_after.string
+}
+
+moved {
+  from = tfcoremock_simple_resource.base_before
+  to = tfcoremock_simple_resource.base_after
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/spec.json b/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/spec.json
new file mode 100644
index 0000000..f2ae347
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests using the moved block combined with simulated drift",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/terraform.resource/2ecc718c-8d04-5774-5c36-7d69bf77d34e.json b/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/terraform.resource/2ecc718c-8d04-5774-5c36-7d69bf77d34e.json
new file mode 100644
index 0000000..2adef56
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/terraform.resource/2ecc718c-8d04-5774-5c36-7d69bf77d34e.json
@@ -0,0 +1,10 @@
+{
+  "values": {
+    "id": {
+      "string": "2ecc718c-8d04-5774-5c36-7d69bf77d34e"
+    },
+    "string": {
+      "string": "Hello, world!"
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/terraform.resource/e450ef2f-b80f-0cce-8bdb-14d88f48649c.json b/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/terraform.resource/e450ef2f-b80f-0cce-8bdb-14d88f48649c.json
new file mode 100644
index 0000000..ea5cd38
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/terraform.resource/e450ef2f-b80f-0cce-8bdb-14d88f48649c.json
@@ -0,0 +1,10 @@
+{
+  "values": {
+    "id": {
+      "string": "e450ef2f-b80f-0cce-8bdb-14d88f48649c"
+    },
+    "string": {
+      "string": "Hello, drift!"
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/terraform.tfstate
new file mode 100644
index 0000000..97ea08c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_drift/terraform.tfstate
@@ -0,0 +1,53 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.7",
+  "serial": 3,
+  "lineage": "6cdc8ae0-8355-2447-7fb8-a9e9c2243e8f",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_simple_resource",
+      "name": "base_before",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "bool": null,
+            "float": null,
+            "id": "e450ef2f-b80f-0cce-8bdb-14d88f48649c",
+            "integer": null,
+            "number": null,
+            "string": "Hello, world!"
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    },
+    {
+      "mode": "managed",
+      "type": "tfcoremock_simple_resource",
+      "name": "dependent",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "bool": null,
+            "float": null,
+            "id": "2ecc718c-8d04-5774-5c36-7d69bf77d34e",
+            "integer": null,
+            "number": null,
+            "string": "Hello, world!"
+          },
+          "sensitive_attributes": [],
+          "dependencies": [
+            "tfcoremock_simple_resource.base_before"
+          ]
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_refresh_only/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/moved_with_refresh_only/.terraform.lock.hcl
new file mode 100644
index 0000000..d2d6193
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_refresh_only/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/tfcoremock" {
+  version     = "0.1.1"
+  constraints = "0.1.1"
+  hashes = [
+    "h1:K5ImnTbl0eD02BQgVe6pNn5w2wW07j9t7iDUwqPvcy0=",
+    "zh:0219ffa02c6f2cf1f519ea42a89615cfbab8219803bcdb4a3614793952b1f5a8",
+    "zh:13915c1eb4f2ad384c6ce343eebe108ddfb0a103e19f1d8b199c0af8e57bc74a",
+    "zh:1c265814efa730540a475f76a8045d90a70c22010d6f2eee45f69e973ce10580",
+    "zh:34d58f6bf64afc491359ad1455007e1eb9aef60be17909096ec88a802b6f72b2",
+    "zh:7a7d709aeb7b2945f5a9a0497976a85bceb07b2cbf236c8c1bb0b7b079b839ab",
+    "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+    "zh:965fbb6042acd6fbf77a9b5c3321edbfa0aa6bf0359394afbf0a7e1392245324",
+    "zh:9e4ac8eae03d1243b9283b202132c007d5c4ee533d1c5efc690403caaaaa7aac",
+    "zh:a51833ca1c6983e32a937ea3864b6037c1ccb97a4917cafb38771a3aa583cc77",
+    "zh:ac2eba5efca9f0bf4ecca3b23c2a89c4318ef7cda45e374811e42cced0aa660b",
+    "zh:c77663f4c0e4ca799e5f1abfa94cfe15f36e9879e637a9196ea01fcaeba13286",
+    "zh:dc0ab43f1affe80e117cea108780afe53d7c97357566ded87f53221828c875de",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_refresh_only/main.tf b/v1.5.7/testing/equivalence-tests/tests/moved_with_refresh_only/main.tf
new file mode 100644
index 0000000..356b980
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_refresh_only/main.tf
@@ -0,0 +1,20 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+
+resource "tfcoremock_simple_resource" "second" {
+  string = "Hello, world!"
+}
+
+moved {
+  from = tfcoremock_simple_resource.first
+  to = tfcoremock_simple_resource.second
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_refresh_only/spec.json b/v1.5.7/testing/equivalence-tests/tests/moved_with_refresh_only/spec.json
new file mode 100644
index 0000000..8cae386
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_refresh_only/spec.json
@@ -0,0 +1,43 @@
+{
+  "description": "tests displaying a moved resource within a refresh only plan",
+  "include_files": [],
+  "ignore_fields": {},
+  "commands": [
+    {
+      "name": "init",
+      "arguments": ["init"],
+      "capture_output": false
+    },
+    {
+      "name": "plan",
+      "arguments": ["plan", "-out=equivalence_test_plan", "-no-color", "-refresh-only"],
+      "capture_output": true,
+      "output_file_name": "plan",
+      "has_json_output": false
+    },
+    {
+      "name": "apply",
+      "arguments": ["apply", "-json", "equivalence_test_plan"],
+      "capture_output": true,
+      "output_file_name": "apply.json",
+      "has_json_output": true,
+      "streams_json_output": true
+    },
+    {
+      "name": "show_state",
+      "arguments": ["show", "-json"],
+      "capture_output": true,
+      "output_file_name": "state.json",
+      "has_json_output": true,
+      "streams_json_output": false
+    },
+    {
+      "name": "show_plan",
+      "arguments": ["show", "-json", "equivalence_test_plan"],
+      "capture_output": true,
+      "output_file_name": "plan.json",
+      "has_json_output": true,
+      "streams_json_output": false
+    }
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_refresh_only/terraform.resource/70c47571-66c3-b1dc-2474-47a74b9c7886.json b/v1.5.7/testing/equivalence-tests/tests/moved_with_refresh_only/terraform.resource/70c47571-66c3-b1dc-2474-47a74b9c7886.json
new file mode 100644
index 0000000..6c63be3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_refresh_only/terraform.resource/70c47571-66c3-b1dc-2474-47a74b9c7886.json
@@ -0,0 +1,10 @@
+{
+  "values": {
+    "id": {
+      "string": "70c47571-66c3-b1dc-2474-47a74b9c7886"
+    },
+    "string": {
+      "string": "Hello, world!"
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_refresh_only/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/moved_with_refresh_only/terraform.tfstate
new file mode 100644
index 0000000..89f82ba
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_refresh_only/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.7",
+  "serial": 1,
+  "lineage": "4a0f03a7-03fd-9357-9fd2-b3405139fa1d",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_simple_resource",
+      "name": "first",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "bool": null,
+            "float": null,
+            "id": "70c47571-66c3-b1dc-2474-47a74b9c7886",
+            "integer": null,
+            "number": null,
+            "string": "Hello, world!"
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_update/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/moved_with_update/.terraform.lock.hcl
new file mode 100644
index 0000000..d2d6193
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_update/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/tfcoremock" {
+  version     = "0.1.1"
+  constraints = "0.1.1"
+  hashes = [
+    "h1:K5ImnTbl0eD02BQgVe6pNn5w2wW07j9t7iDUwqPvcy0=",
+    "zh:0219ffa02c6f2cf1f519ea42a89615cfbab8219803bcdb4a3614793952b1f5a8",
+    "zh:13915c1eb4f2ad384c6ce343eebe108ddfb0a103e19f1d8b199c0af8e57bc74a",
+    "zh:1c265814efa730540a475f76a8045d90a70c22010d6f2eee45f69e973ce10580",
+    "zh:34d58f6bf64afc491359ad1455007e1eb9aef60be17909096ec88a802b6f72b2",
+    "zh:7a7d709aeb7b2945f5a9a0497976a85bceb07b2cbf236c8c1bb0b7b079b839ab",
+    "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+    "zh:965fbb6042acd6fbf77a9b5c3321edbfa0aa6bf0359394afbf0a7e1392245324",
+    "zh:9e4ac8eae03d1243b9283b202132c007d5c4ee533d1c5efc690403caaaaa7aac",
+    "zh:a51833ca1c6983e32a937ea3864b6037c1ccb97a4917cafb38771a3aa583cc77",
+    "zh:ac2eba5efca9f0bf4ecca3b23c2a89c4318ef7cda45e374811e42cced0aa660b",
+    "zh:c77663f4c0e4ca799e5f1abfa94cfe15f36e9879e637a9196ea01fcaeba13286",
+    "zh:dc0ab43f1affe80e117cea108780afe53d7c97357566ded87f53221828c875de",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_update/main.tf b/v1.5.7/testing/equivalence-tests/tests/moved_with_update/main.tf
new file mode 100644
index 0000000..a727802
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_update/main.tf
@@ -0,0 +1,19 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_simple_resource" "moved" {
+  string = "Hello, change!"
+}
+
+moved {
+  from = tfcoremock_simple_resource.base
+  to = tfcoremock_simple_resource.moved
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_update/spec.json b/v1.5.7/testing/equivalence-tests/tests/moved_with_update/spec.json
new file mode 100644
index 0000000..dceb24c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_update/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "this test updates a resource that has also been moved",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_update/terraform.resource/7da63aeb-f908-a112-9886-f29a0b0bd4ad.json b/v1.5.7/testing/equivalence-tests/tests/moved_with_update/terraform.resource/7da63aeb-f908-a112-9886-f29a0b0bd4ad.json
new file mode 100644
index 0000000..dc908dc
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_update/terraform.resource/7da63aeb-f908-a112-9886-f29a0b0bd4ad.json
@@ -0,0 +1,10 @@
+{
+  "values": {
+    "id": {
+      "string": "7da63aeb-f908-a112-9886-f29a0b0bd4ad"
+    },
+    "string": {
+      "string": "Hello, world!"
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/moved_with_update/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/moved_with_update/terraform.tfstate
new file mode 100644
index 0000000..b338b65
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/moved_with_update/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.7",
+  "serial": 1,
+  "lineage": "74f354aa-d7c6-5524-9573-cfdb625cb511",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_simple_resource",
+      "name": "base",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "bool": null,
+            "float": null,
+            "id": "7da63aeb-f908-a112-9886-f29a0b0bd4ad",
+            "integer": null,
+            "number": null,
+            "string": "Hello, world!"
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/multiple_block_types/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types/dynamic_resources.json
new file mode 100644
index 0000000..d51252e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types/dynamic_resources.json
@@ -0,0 +1,24 @@
+{
+  "tfcoremock_multiple_blocks": {
+    "blocks": {
+      "first_block": {
+        "attributes": {
+          "id": {
+            "type": "string",
+            "required": true
+          }
+        },
+        "mode": "list"
+      },
+      "second_block": {
+        "attributes": {
+          "id": {
+            "type": "string",
+            "required": true
+          }
+        },
+        "mode": "list"
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/multiple_block_types/main.tf b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types/main.tf
new file mode 100644
index 0000000..370ada5
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types/main.tf
@@ -0,0 +1,34 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_multiple_blocks" "multiple_blocks" {
+  id = "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+
+  first_block {
+    id = "D35E88DA-BC3B-46D7-9E0B-4ED4582FA65A"
+  }
+
+  first_block {
+    id = "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+  }
+
+  first_block {
+    id = "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+  }
+
+  second_block {
+    id = "157660A9-D590-469E-BE28-83B8526428CA"
+  }
+
+  second_block {
+    id = "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/multiple_block_types/spec.json b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types/spec.json
new file mode 100644
index 0000000..675c10e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "basic test case covering interaction between multiple blocks within a resource",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/multiple_block_types_update/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types_update/dynamic_resources.json
new file mode 100644
index 0000000..d51252e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types_update/dynamic_resources.json
@@ -0,0 +1,24 @@
+{
+  "tfcoremock_multiple_blocks": {
+    "blocks": {
+      "first_block": {
+        "attributes": {
+          "id": {
+            "type": "string",
+            "required": true
+          }
+        },
+        "mode": "list"
+      },
+      "second_block": {
+        "attributes": {
+          "id": {
+            "type": "string",
+            "required": true
+          }
+        },
+        "mode": "list"
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/multiple_block_types_update/main.tf b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types_update/main.tf
new file mode 100644
index 0000000..df3b5c0
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types_update/main.tf
@@ -0,0 +1,34 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_multiple_blocks" "multiple_blocks" {
+  id = "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+
+  first_block {
+    id = "B27FB8BE-52D4-4CEB-ACE9-5E7FB3968F2B"
+  }
+
+  first_block {
+    id = "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+  }
+
+  first_block {
+    id = "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+  }
+
+  second_block {
+    id = "91640A80-A65F-4BEF-925B-684E4517A04D"
+  }
+
+  second_block {
+    id = "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/multiple_block_types_update/spec.json b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types_update/spec.json
new file mode 100644
index 0000000..4fa45ba
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types_update/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "basic test covering interaction between multiple blocks within a resource, while updating",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/multiple_block_types_update/terraform.resource/DA051126-BAD6-4EB2-92E5-F0250DAF0B92.json b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types_update/terraform.resource/DA051126-BAD6-4EB2-92E5-F0250DAF0B92.json
new file mode 100644
index 0000000..23f6818
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types_update/terraform.resource/DA051126-BAD6-4EB2-92E5-F0250DAF0B92.json
@@ -0,0 +1,50 @@
+{
+  "values": {
+    "first_block": {
+      "list": [
+        {
+          "object": {
+            "id": {
+              "string": "D35E88DA-BC3B-46D7-9E0B-4ED4582FA65A"
+            }
+          }
+        },
+        {
+          "object": {
+            "id": {
+              "string": "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+            }
+          }
+        },
+        {
+          "object": {
+            "id": {
+              "string": "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+            }
+          }
+        }
+      ]
+    },
+    "id": {
+      "string": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+    },
+    "second_block": {
+      "list": [
+        {
+          "object": {
+            "id": {
+              "string": "157660A9-D590-469E-BE28-83B8526428CA"
+            }
+          }
+        },
+        {
+          "object": {
+            "id": {
+              "string": "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+            }
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/multiple_block_types_update/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types_update/terraform.tfstate
new file mode 100644
index 0000000..90829eb
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/multiple_block_types_update/terraform.tfstate
@@ -0,0 +1,44 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.0",
+  "serial": 2,
+  "lineage": "a5c97830-8a8e-bf77-515e-481367d1e17e",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_multiple_blocks",
+      "name": "multiple_blocks",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "first_block": [
+              {
+                "id": "D35E88DA-BC3B-46D7-9E0B-4ED4582FA65A"
+              },
+              {
+                "id": "E60148A2-04D1-4EF8-90A2-45CAFC02C60D"
+              },
+              {
+                "id": "717C64FB-6A93-4763-A1EF-FE4C5B341488"
+              }
+            ],
+            "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+            "second_block": [
+              {
+                "id": "157660A9-D590-469E-BE28-83B8526428CA"
+              },
+              {
+                "id": "D080F298-2BA4-4DFA-A367-2C5FB0EA7BFE"
+              }
+            ]
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": []
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_list/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/nested_list/dynamic_resources.json
new file mode 100644
index 0000000..5a9d248
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_list/dynamic_resources.json
@@ -0,0 +1,16 @@
+{
+  "tfcoremock_nested_list": {
+    "attributes": {
+      "lists": {
+        "type": "list",
+        "required": true,
+        "list": {
+          "type": "list",
+          "list": {
+            "type": "string"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_list/main.tf b/v1.5.7/testing/equivalence-tests/tests/nested_list/main.tf
new file mode 100644
index 0000000..23652ad
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_list/main.tf
@@ -0,0 +1,20 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_nested_list" "nested_list" {
+  id = "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+
+  lists = [
+    [],
+    ["44E1C623-7B70-4D78-B4D3-D9CFE8A6D982"],
+    ["13E3B154-7B85-4EAA-B3D0-E295E7D71D7F", "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD"],
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_list/spec.json b/v1.5.7/testing/equivalence-tests/tests/nested_list/spec.json
new file mode 100644
index 0000000..c60dbb1
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_list/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests creating lists within lists",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_list_update/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/nested_list_update/dynamic_resources.json
new file mode 100644
index 0000000..5a9d248
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_list_update/dynamic_resources.json
@@ -0,0 +1,16 @@
+{
+  "tfcoremock_nested_list": {
+    "attributes": {
+      "lists": {
+        "type": "list",
+        "required": true,
+        "list": {
+          "type": "list",
+          "list": {
+            "type": "string"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_list_update/main.tf b/v1.5.7/testing/equivalence-tests/tests/nested_list_update/main.tf
new file mode 100644
index 0000000..bc1808e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_list_update/main.tf
@@ -0,0 +1,20 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_nested_list" "nested_list" {
+  id = "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+
+  lists = [
+    ["44E1C623-7B70-4D78-B4D3-D9CFE8A6D982"],
+    ["8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD"],
+    ["13E3B154-7B85-4EAA-B3D0-E295E7D71D7F"],
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_list_update/spec.json b/v1.5.7/testing/equivalence-tests/tests/nested_list_update/spec.json
new file mode 100644
index 0000000..24a0a6d
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_list_update/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests updating a nested list attribute within a resource",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_list_update/terraform.resource/DA051126-BAD6-4EB2-92E5-F0250DAF0B92.json b/v1.5.7/testing/equivalence-tests/tests/nested_list_update/terraform.resource/DA051126-BAD6-4EB2-92E5-F0250DAF0B92.json
new file mode 100644
index 0000000..da4dd86
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_list_update/terraform.resource/DA051126-BAD6-4EB2-92E5-F0250DAF0B92.json
@@ -0,0 +1,31 @@
+{
+  "values": {
+    "id": {
+      "string": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92"
+    },
+    "lists": {
+      "list": [
+        {
+          "list": []
+        },
+        {
+          "list": [
+            {
+              "string": "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982"
+            }
+          ]
+        },
+        {
+          "list": [
+            {
+              "string": "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F"
+            },
+            {
+              "string": "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD"
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_list_update/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/nested_list_update/terraform.tfstate
new file mode 100644
index 0000000..7aed46c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_list_update/terraform.tfstate
@@ -0,0 +1,35 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.0",
+  "serial": 2,
+  "lineage": "a370201d-6899-c596-f68f-01dfdf622d44",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_nested_list",
+      "name": "nested_list",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "DA051126-BAD6-4EB2-92E5-F0250DAF0B92",
+            "lists": [
+              [],
+              [
+                "44E1C623-7B70-4D78-B4D3-D9CFE8A6D982"
+              ],
+              [
+                "13E3B154-7B85-4EAA-B3D0-E295E7D71D7F",
+                "8B031CD1-01F7-422C-BBE6-FF8A0E18CDFD"
+              ]
+            ]
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": []
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_map/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/nested_map/dynamic_resources.json
new file mode 100644
index 0000000..0bab718
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_map/dynamic_resources.json
@@ -0,0 +1,16 @@
+{
+  "tfcoremock_nested_map": {
+    "attributes": {
+      "maps": {
+        "type": "map",
+        "required": true,
+        "map": {
+          "type": "map",
+          "map": {
+            "type": "string"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_map/main.tf b/v1.5.7/testing/equivalence-tests/tests/nested_map/main.tf
new file mode 100644
index 0000000..1db6d16
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_map/main.tf
@@ -0,0 +1,25 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_nested_map" "nested_map" {
+  id = "502B0348-B796-4F6A-8694-A5A397237B85"
+
+  maps = {
+    "first_nested_map": {
+      "first_key": "9E858021-953F-4DD3-8842-F2C782780422",
+      "second_key": "D55D0E1E-51D9-4BCE-9021-7D201906D3C0"
+    },
+    "second_nested_map": {
+      "first_key": "6E80C701-A823-43FE-A520-699851EF9052",
+      "second_key": "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_map/spec.json b/v1.5.7/testing/equivalence-tests/tests/nested_map/spec.json
new file mode 100644
index 0000000..0590e12
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_map/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests creating maps within maps",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_map_update/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/nested_map_update/dynamic_resources.json
new file mode 100644
index 0000000..0bab718
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_map_update/dynamic_resources.json
@@ -0,0 +1,16 @@
+{
+  "tfcoremock_nested_map": {
+    "attributes": {
+      "maps": {
+        "type": "map",
+        "required": true,
+        "map": {
+          "type": "map",
+          "map": {
+            "type": "string"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_map_update/main.tf b/v1.5.7/testing/equivalence-tests/tests/nested_map_update/main.tf
new file mode 100644
index 0000000..91e57e0
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_map_update/main.tf
@@ -0,0 +1,25 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_nested_map" "nested_map" {
+  id = "502B0348-B796-4F6A-8694-A5A397237B85"
+
+  maps = {
+    "first_nested_map": {
+      "first_key": "6E80C701-A823-43FE-A520-699851EF9052",
+      "second_key": "D55D0E1E-51D9-4BCE-9021-7D201906D3C0"
+      "third_key": "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+    },
+    "second_nested_map": {
+      "first_key": "9E858021-953F-4DD3-8842-F2C782780422",
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_map_update/spec.json b/v1.5.7/testing/equivalence-tests/tests/nested_map_update/spec.json
new file mode 100644
index 0000000..b313e21
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_map_update/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests updating a map nested within another map",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_map_update/terraform.resource/502B0348-B796-4F6A-8694-A5A397237B85.json b/v1.5.7/testing/equivalence-tests/tests/nested_map_update/terraform.resource/502B0348-B796-4F6A-8694-A5A397237B85.json
new file mode 100644
index 0000000..c413447
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_map_update/terraform.resource/502B0348-B796-4F6A-8694-A5A397237B85.json
@@ -0,0 +1,31 @@
+{
+  "values": {
+    "id": {
+      "string": "502B0348-B796-4F6A-8694-A5A397237B85"
+    },
+    "maps": {
+      "map": {
+        "first_nested_map": {
+          "map": {
+            "first_key": {
+              "string": "9E858021-953F-4DD3-8842-F2C782780422"
+            },
+            "second_key": {
+              "string": "D55D0E1E-51D9-4BCE-9021-7D201906D3C0"
+            }
+          }
+        },
+        "second_nested_map": {
+          "map": {
+            "first_key": {
+              "string": "6E80C701-A823-43FE-A520-699851EF9052"
+            },
+            "second_key": {
+              "string": "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+            }
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_map_update/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/nested_map_update/terraform.tfstate
new file mode 100644
index 0000000..b64ef7d
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_map_update/terraform.tfstate
@@ -0,0 +1,35 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.0",
+  "serial": 2,
+  "lineage": "f6b2f8a8-d060-337c-a45a-25c038eb196f",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_nested_map",
+      "name": "nested_map",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "502B0348-B796-4F6A-8694-A5A397237B85",
+            "maps": {
+              "first_nested_map": {
+                "first_key": "9E858021-953F-4DD3-8842-F2C782780422",
+                "second_key": "D55D0E1E-51D9-4BCE-9021-7D201906D3C0"
+              },
+              "second_nested_map": {
+                "first_key": "6E80C701-A823-43FE-A520-699851EF9052",
+                "second_key": "79CBEBB1-1192-480A-B4A8-E816A1A9D2FC"
+              }
+            }
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": []
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_objects/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/nested_objects/dynamic_resources.json
new file mode 100644
index 0000000..30f8c82
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_objects/dynamic_resources.json
@@ -0,0 +1,40 @@
+{
+  "tfcoremock_nested_object": {
+    "attributes": {
+      "parent_object": {
+        "type": "object",
+        "required": true,
+        "object": {
+          "first_nested_object": {
+            "type": "object",
+            "required": true,
+            "object": {
+              "attribute_one": {
+                "type": "string",
+                "required": true
+              },
+              "attribute_two": {
+                "type": "string",
+                "required": true
+              }
+            }
+          },
+          "second_nested_object": {
+            "type": "object",
+            "required": true,
+            "object": {
+              "attribute_one": {
+                "type": "string",
+                "required": true
+              },
+              "attribute_two": {
+                "type": "string",
+                "required": true
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_objects/main.tf b/v1.5.7/testing/equivalence-tests/tests/nested_objects/main.tf
new file mode 100644
index 0000000..b8bd36b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_objects/main.tf
@@ -0,0 +1,25 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_nested_object" "nested_object" {
+  id = "B2491EF0-9361-40FD-B25A-0332A1A5E052"
+
+  parent_object = {
+    first_nested_object = {
+      attribute_one = "09AE7244-7BFB-476B-912C-D1AB4E7E9622",
+      attribute_two = "5425587C-49EF-4C1E-A906-1DC923A12725"
+    }
+    second_nested_object = {
+      attribute_one = "63712BFE-78F8-42D3-A074-A78249E5E25E",
+      attribute_two = "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_objects/spec.json b/v1.5.7/testing/equivalence-tests/tests/nested_objects/spec.json
new file mode 100644
index 0000000..52a765c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_objects/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests creating objects within objects",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_objects_update/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/nested_objects_update/dynamic_resources.json
new file mode 100644
index 0000000..30f8c82
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_objects_update/dynamic_resources.json
@@ -0,0 +1,40 @@
+{
+  "tfcoremock_nested_object": {
+    "attributes": {
+      "parent_object": {
+        "type": "object",
+        "required": true,
+        "object": {
+          "first_nested_object": {
+            "type": "object",
+            "required": true,
+            "object": {
+              "attribute_one": {
+                "type": "string",
+                "required": true
+              },
+              "attribute_two": {
+                "type": "string",
+                "required": true
+              }
+            }
+          },
+          "second_nested_object": {
+            "type": "object",
+            "required": true,
+            "object": {
+              "attribute_one": {
+                "type": "string",
+                "required": true
+              },
+              "attribute_two": {
+                "type": "string",
+                "required": true
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_objects_update/main.tf b/v1.5.7/testing/equivalence-tests/tests/nested_objects_update/main.tf
new file mode 100644
index 0000000..c351eb1
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_objects_update/main.tf
@@ -0,0 +1,25 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_nested_object" "nested_object" {
+  id = "B2491EF0-9361-40FD-B25A-0332A1A5E052"
+
+  parent_object = {
+    first_nested_object = {
+      attribute_one = "09AE7244-7BFB-476B-912C-D1AB4E7E9622",
+      attribute_two = "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+    }
+    second_nested_object = {
+      attribute_one = "63712BFE-78F8-42D3-A074-A78249E5E25E",
+      attribute_two = "5425587C-49EF-4C1E-A906-1DC923A12725"
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_objects_update/spec.json b/v1.5.7/testing/equivalence-tests/tests/nested_objects_update/spec.json
new file mode 100644
index 0000000..cd8465f
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_objects_update/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests updating objects that are nested within other objects",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_objects_update/terraform.resource/B2491EF0-9361-40FD-B25A-0332A1A5E052.json b/v1.5.7/testing/equivalence-tests/tests/nested_objects_update/terraform.resource/B2491EF0-9361-40FD-B25A-0332A1A5E052.json
new file mode 100644
index 0000000..58c69da
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_objects_update/terraform.resource/B2491EF0-9361-40FD-B25A-0332A1A5E052.json
@@ -0,0 +1,31 @@
+{
+  "values": {
+    "id": {
+      "string": "B2491EF0-9361-40FD-B25A-0332A1A5E052"
+    },
+    "parent_object": {
+      "object": {
+        "first_nested_object": {
+          "object": {
+            "attribute_one": {
+              "string": "09AE7244-7BFB-476B-912C-D1AB4E7E9622"
+            },
+            "attribute_two": {
+              "string": "5425587C-49EF-4C1E-A906-1DC923A12725"
+            }
+          }
+        },
+        "second_nested_object": {
+          "object": {
+            "attribute_one": {
+              "string": "63712BFE-78F8-42D3-A074-A78249E5E25E"
+            },
+            "attribute_two": {
+              "string": "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+            }
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_objects_update/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/nested_objects_update/terraform.tfstate
new file mode 100644
index 0000000..765933a
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_objects_update/terraform.tfstate
@@ -0,0 +1,35 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.0",
+  "serial": 2,
+  "lineage": "2fd492f4-7a34-53d6-de72-96debd114238",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_nested_object",
+      "name": "nested_object",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "B2491EF0-9361-40FD-B25A-0332A1A5E052",
+            "parent_object": {
+              "first_nested_object": {
+                "attribute_one": "09AE7244-7BFB-476B-912C-D1AB4E7E9622",
+                "attribute_two": "5425587C-49EF-4C1E-A906-1DC923A12725"
+              },
+              "second_nested_object": {
+                "attribute_one": "63712BFE-78F8-42D3-A074-A78249E5E25E",
+                "attribute_two": "FB350D92-4AAE-48C6-A408-BFFAFAD46B04"
+              }
+            }
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": []
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_set/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/nested_set/dynamic_resources.json
new file mode 100644
index 0000000..478a0d7
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_set/dynamic_resources.json
@@ -0,0 +1,16 @@
+{
+  "tfcoremock_nested_set": {
+    "attributes": {
+      "sets": {
+        "type": "set",
+        "required": true,
+        "set": {
+          "type": "set",
+          "set": {
+            "type": "string"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_set/main.tf b/v1.5.7/testing/equivalence-tests/tests/nested_set/main.tf
new file mode 100644
index 0000000..9c486df
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_set/main.tf
@@ -0,0 +1,20 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_nested_set" "nested_set" {
+  id = "510598F6-83FE-4090-8986-793293E90480"
+
+  sets = [
+    [],
+    ["9373D62D-1BF0-4F17-B100-7C0FBE368ADE"],
+    ["7E90963C-BE32-4411-B9DD-B02E7FE75766", "29B6824A-5CB6-4C25-A359-727BAFEF25EB"],
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_set/spec.json b/v1.5.7/testing/equivalence-tests/tests/nested_set/spec.json
new file mode 100644
index 0000000..967ec85
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_set/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests creating sets within sets",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_set_update/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/nested_set_update/dynamic_resources.json
new file mode 100644
index 0000000..478a0d7
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_set_update/dynamic_resources.json
@@ -0,0 +1,16 @@
+{
+  "tfcoremock_nested_set": {
+    "attributes": {
+      "sets": {
+        "type": "set",
+        "required": true,
+        "set": {
+          "type": "set",
+          "set": {
+            "type": "string"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_set_update/main.tf b/v1.5.7/testing/equivalence-tests/tests/nested_set_update/main.tf
new file mode 100644
index 0000000..e3f7b74
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_set_update/main.tf
@@ -0,0 +1,20 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_nested_set" "nested_set" {
+  id = "510598F6-83FE-4090-8986-793293E90480"
+
+  sets = [
+    ["29B6824A-5CB6-4C25-A359-727BAFEF25EB"],
+    ["9373D62D-1BF0-4F17-B100-7C0FBE368ADE"],
+    ["7E90963C-BE32-4411-B9DD-B02E7FE75766"],
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_set_update/spec.json b/v1.5.7/testing/equivalence-tests/tests/nested_set_update/spec.json
new file mode 100644
index 0000000..a1d1c9a
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_set_update/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests updating sets when they are nested within other sets",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_set_update/terraform.resource/510598F6-83FE-4090-8986-793293E90480.json b/v1.5.7/testing/equivalence-tests/tests/nested_set_update/terraform.resource/510598F6-83FE-4090-8986-793293E90480.json
new file mode 100644
index 0000000..6798690
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_set_update/terraform.resource/510598F6-83FE-4090-8986-793293E90480.json
@@ -0,0 +1,31 @@
+{
+  "values": {
+    "id": {
+      "string": "510598F6-83FE-4090-8986-793293E90480"
+    },
+    "sets": {
+      "set": [
+        {
+          "set": [
+            {
+              "string": "29B6824A-5CB6-4C25-A359-727BAFEF25EB"
+            },
+            {
+              "string": "7E90963C-BE32-4411-B9DD-B02E7FE75766"
+            }
+          ]
+        },
+        {
+          "set": [
+            {
+              "string": "9373D62D-1BF0-4F17-B100-7C0FBE368ADE"
+            }
+          ]
+        },
+        {
+          "set": []
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/nested_set_update/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/nested_set_update/terraform.tfstate
new file mode 100644
index 0000000..3d89c49
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/nested_set_update/terraform.tfstate
@@ -0,0 +1,35 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.0",
+  "serial": 2,
+  "lineage": "68208952-1936-3604-26c2-bcd453e7d1ad",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_nested_set",
+      "name": "nested_set",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "510598F6-83FE-4090-8986-793293E90480",
+            "sets": [
+              [
+                "29B6824A-5CB6-4C25-A359-727BAFEF25EB",
+                "7E90963C-BE32-4411-B9DD-B02E7FE75766"
+              ],
+              [
+                "9373D62D-1BF0-4F17-B100-7C0FBE368ADE"
+              ],
+              []
+            ]
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": []
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/null_provider_basic/main.tf b/v1.5.7/testing/equivalence-tests/tests/null_provider_basic/main.tf
new file mode 100644
index 0000000..31d6ee2
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/null_provider_basic/main.tf
@@ -0,0 +1,12 @@
+terraform {
+  required_providers {
+    null = {
+      source  = "hashicorp/null"
+      version = "3.1.1"
+    }
+  }
+}
+
+provider "null" {}
+
+resource "null_resource" "null_resource" {}
diff --git a/v1.5.7/testing/equivalence-tests/tests/null_provider_basic/spec.json b/v1.5.7/testing/equivalence-tests/tests/null_provider_basic/spec.json
new file mode 100644
index 0000000..d32d9a3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/null_provider_basic/spec.json
@@ -0,0 +1,13 @@
+{
+  "description": "tests creating a simple resource created by the null provider",
+  "include_files": [],
+  "ignore_fields": {
+    "apply.json": [
+      "2.@message",
+      "2.hook.id_value"
+    ],
+    "state.json": [
+      "values.root_module.resources.*.values.id"
+    ]
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/null_provider_delete/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/null_provider_delete/.terraform.lock.hcl
new file mode 100644
index 0000000..6ed19d1
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/null_provider_delete/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/null" {
+  version     = "3.1.1"
+  constraints = "3.1.1"
+  hashes = [
+    "h1:YvH6gTaQzGdNv+SKTZujU1O0bO+Pw6vJHOPhqgN8XNs=",
+    "zh:063466f41f1d9fd0dd93722840c1314f046d8760b1812fa67c34de0afcba5597",
+    "zh:08c058e367de6debdad35fc24d97131c7cf75103baec8279aba3506a08b53faf",
+    "zh:73ce6dff935150d6ddc6ac4a10071e02647d10175c173cfe5dca81f3d13d8afe",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:8fdd792a626413502e68c195f2097352bdc6a0df694f7df350ed784741eb587e",
+    "zh:976bbaf268cb497400fd5b3c774d218f3933271864345f18deebe4dcbfcd6afa",
+    "zh:b21b78ca581f98f4cdb7a366b03ae9db23a73dfa7df12c533d7c19b68e9e72e5",
+    "zh:b7fc0c1615dbdb1d6fd4abb9c7dc7da286631f7ca2299fb9cd4664258ccfbff4",
+    "zh:d1efc942b2c44345e0c29bc976594cb7278c38cfb8897b344669eafbc3cddf46",
+    "zh:e356c245b3cd9d4789bab010893566acace682d7db877e52d40fc4ca34a50924",
+    "zh:ea98802ba92fcfa8cf12cbce2e9e7ebe999afbf8ed47fa45fc847a098d89468b",
+    "zh:eff8872458806499889f6927b5d954560f3d74bf20b6043409edf94d26cd906f",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/null_provider_delete/main.tf b/v1.5.7/testing/equivalence-tests/tests/null_provider_delete/main.tf
new file mode 100644
index 0000000..f4234bf
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/null_provider_delete/main.tf
@@ -0,0 +1,10 @@
+terraform {
+  required_providers {
+    null = {
+      source  = "hashicorp/null"
+      version = "3.1.1"
+    }
+  }
+}
+
+provider "null" {}
diff --git a/v1.5.7/testing/equivalence-tests/tests/null_provider_delete/spec.json b/v1.5.7/testing/equivalence-tests/tests/null_provider_delete/spec.json
new file mode 100644
index 0000000..0ab998c
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/null_provider_delete/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests deleting a resource created by the null provider",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/null_provider_delete/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/null_provider_delete/terraform.tfstate
new file mode 100644
index 0000000..ca15ed9
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/null_provider_delete/terraform.tfstate
@@ -0,0 +1,27 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.0",
+  "serial": 2,
+  "lineage": "bc759d94-5aca-e092-1b90-cb90e6227c62",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "null_resource",
+      "name": "null_resource",
+      "provider": "provider[\"registry.terraform.io/hashicorp/null\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "7115293105928418144",
+            "triggers": null
+          },
+          "sensitive_attributes": [],
+          "private": "bnVsbA=="
+        }
+      ]
+    }
+  ],
+  "check_results": []
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_list/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/replace_within_list/.terraform.lock.hcl
new file mode 100644
index 0000000..d2d6193
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_list/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/tfcoremock" {
+  version     = "0.1.1"
+  constraints = "0.1.1"
+  hashes = [
+    "h1:K5ImnTbl0eD02BQgVe6pNn5w2wW07j9t7iDUwqPvcy0=",
+    "zh:0219ffa02c6f2cf1f519ea42a89615cfbab8219803bcdb4a3614793952b1f5a8",
+    "zh:13915c1eb4f2ad384c6ce343eebe108ddfb0a103e19f1d8b199c0af8e57bc74a",
+    "zh:1c265814efa730540a475f76a8045d90a70c22010d6f2eee45f69e973ce10580",
+    "zh:34d58f6bf64afc491359ad1455007e1eb9aef60be17909096ec88a802b6f72b2",
+    "zh:7a7d709aeb7b2945f5a9a0497976a85bceb07b2cbf236c8c1bb0b7b079b839ab",
+    "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+    "zh:965fbb6042acd6fbf77a9b5c3321edbfa0aa6bf0359394afbf0a7e1392245324",
+    "zh:9e4ac8eae03d1243b9283b202132c007d5c4ee533d1c5efc690403caaaaa7aac",
+    "zh:a51833ca1c6983e32a937ea3864b6037c1ccb97a4917cafb38771a3aa583cc77",
+    "zh:ac2eba5efca9f0bf4ecca3b23c2a89c4318ef7cda45e374811e42cced0aa660b",
+    "zh:c77663f4c0e4ca799e5f1abfa94cfe15f36e9879e637a9196ea01fcaeba13286",
+    "zh:dc0ab43f1affe80e117cea108780afe53d7c97357566ded87f53221828c875de",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_list/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/replace_within_list/dynamic_resources.json
new file mode 100644
index 0000000..5d8e42b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_list/dynamic_resources.json
@@ -0,0 +1,20 @@
+{
+  "tfcoremock_list": {
+    "attributes": {
+      "list": {
+        "type": "list",
+        "required": true,
+        "list": {
+          "type": "object",
+          "object": {
+            "id": {
+              "type": "string",
+              "replace": true,
+              "required": true
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_list/main.tf b/v1.5.7/testing/equivalence-tests/tests/replace_within_list/main.tf
new file mode 100644
index 0000000..3f4d34b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_list/main.tf
@@ -0,0 +1,26 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_list" "list" {
+  id = "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+
+  list = [
+    {
+      id = "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+    },
+    {
+      id = "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+    },
+    {
+      id = "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+    },
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_list/spec.json b/v1.5.7/testing/equivalence-tests/tests/replace_within_list/spec.json
new file mode 100644
index 0000000..002a35b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_list/spec.json
@@ -0,0 +1,6 @@
+{
+  "description": "tests the behaviour of an attribute within a list causing a resource to be replaced",
+  "include_files": [],
+  "ignore_fields": {}
+}
+
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_list/terraform.resource/F40F2AB4-100C-4AE8-BFD0-BF332A158415.json b/v1.5.7/testing/equivalence-tests/tests/replace_within_list/terraform.resource/F40F2AB4-100C-4AE8-BFD0-BF332A158415.json
new file mode 100644
index 0000000..b1c22ca
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_list/terraform.resource/F40F2AB4-100C-4AE8-BFD0-BF332A158415.json
@@ -0,0 +1,32 @@
+{
+  "values": {
+    "id": {
+      "string": "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+    },
+    "list": {
+      "list": [
+        {
+          "object": {
+            "id": {
+              "string": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+            }
+          }
+        },
+        {
+          "object": {
+            "id": {
+              "string": "6A8C6A29-D417-480A-BE19-12D7398B3178"
+            }
+          }
+        },
+        {
+          "object": {
+            "id": {
+              "string": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+            }
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_list/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/replace_within_list/terraform.tfstate
new file mode 100644
index 0000000..9526def
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_list/terraform.tfstate
@@ -0,0 +1,36 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.7",
+  "serial": 4,
+  "lineage": "a0e7bfac-ce3d-9720-1b4e-d6e6c58cf620",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_list",
+      "name": "list",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+            "list": [
+              {
+                "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+              },
+              {
+                "id": "6A8C6A29-D417-480A-BE19-12D7398B3178"
+              },
+              {
+                "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+              }
+            ]
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_map/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/replace_within_map/.terraform.lock.hcl
new file mode 100644
index 0000000..d2d6193
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_map/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/tfcoremock" {
+  version     = "0.1.1"
+  constraints = "0.1.1"
+  hashes = [
+    "h1:K5ImnTbl0eD02BQgVe6pNn5w2wW07j9t7iDUwqPvcy0=",
+    "zh:0219ffa02c6f2cf1f519ea42a89615cfbab8219803bcdb4a3614793952b1f5a8",
+    "zh:13915c1eb4f2ad384c6ce343eebe108ddfb0a103e19f1d8b199c0af8e57bc74a",
+    "zh:1c265814efa730540a475f76a8045d90a70c22010d6f2eee45f69e973ce10580",
+    "zh:34d58f6bf64afc491359ad1455007e1eb9aef60be17909096ec88a802b6f72b2",
+    "zh:7a7d709aeb7b2945f5a9a0497976a85bceb07b2cbf236c8c1bb0b7b079b839ab",
+    "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+    "zh:965fbb6042acd6fbf77a9b5c3321edbfa0aa6bf0359394afbf0a7e1392245324",
+    "zh:9e4ac8eae03d1243b9283b202132c007d5c4ee533d1c5efc690403caaaaa7aac",
+    "zh:a51833ca1c6983e32a937ea3864b6037c1ccb97a4917cafb38771a3aa583cc77",
+    "zh:ac2eba5efca9f0bf4ecca3b23c2a89c4318ef7cda45e374811e42cced0aa660b",
+    "zh:c77663f4c0e4ca799e5f1abfa94cfe15f36e9879e637a9196ea01fcaeba13286",
+    "zh:dc0ab43f1affe80e117cea108780afe53d7c97357566ded87f53221828c875de",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_map/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/replace_within_map/dynamic_resources.json
new file mode 100644
index 0000000..6034bef
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_map/dynamic_resources.json
@@ -0,0 +1,20 @@
+{
+  "tfcoremock_map": {
+    "attributes": {
+      "map": {
+        "type": "map",
+        "required": true,
+        "map": {
+          "type": "object",
+          "object": {
+            "id": {
+              "type": "string",
+              "replace": true,
+              "required": true
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_map/main.tf b/v1.5.7/testing/equivalence-tests/tests/replace_within_map/main.tf
new file mode 100644
index 0000000..aafa092
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_map/main.tf
@@ -0,0 +1,26 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_map" "map" {
+  id = "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+
+  map = {
+    "key_one" = {
+      id = "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+    },
+    "key_two" = {
+      id = "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+    },
+    "key_three" = {
+      id = "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+    },
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_map/spec.json b/v1.5.7/testing/equivalence-tests/tests/replace_within_map/spec.json
new file mode 100644
index 0000000..602fcd5
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_map/spec.json
@@ -0,0 +1,6 @@
+{
+  "description": "tests the behaviour of an attribute within a map causing a resource to be replaced",
+  "include_files": [],
+  "ignore_fields": {}
+}
+
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_map/terraform.resource/F40F2AB4-100C-4AE8-BFD0-BF332A158415.json b/v1.5.7/testing/equivalence-tests/tests/replace_within_map/terraform.resource/F40F2AB4-100C-4AE8-BFD0-BF332A158415.json
new file mode 100644
index 0000000..86c7de1
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_map/terraform.resource/F40F2AB4-100C-4AE8-BFD0-BF332A158415.json
@@ -0,0 +1,32 @@
+{
+  "values": {
+    "id": {
+      "string": "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+    },
+    "map": {
+      "map": {
+        "key_one": {
+          "object": {
+            "id": {
+              "string": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+            }
+          }
+        },
+        "key_three": {
+          "object": {
+            "id": {
+              "string": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+            }
+          }
+        },
+        "key_two": {
+          "object": {
+            "id": {
+              "string": "56C7E07F-B9DF-4799-AF62-E703D1167A51"
+            }
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_map/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/replace_within_map/terraform.tfstate
new file mode 100644
index 0000000..5ca2114
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_map/terraform.tfstate
@@ -0,0 +1,36 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.7",
+  "serial": 4,
+  "lineage": "761a9430-9f20-5cf3-d66e-c3e345115ed1",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_map",
+      "name": "map",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+            "map": {
+              "key_one": {
+                "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+              },
+              "key_three": {
+                "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+              },
+              "key_two": {
+                "id": "56C7E07F-B9DF-4799-AF62-E703D1167A51"
+              }
+            }
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_object/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/replace_within_object/.terraform.lock.hcl
new file mode 100644
index 0000000..d2d6193
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_object/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/tfcoremock" {
+  version     = "0.1.1"
+  constraints = "0.1.1"
+  hashes = [
+    "h1:K5ImnTbl0eD02BQgVe6pNn5w2wW07j9t7iDUwqPvcy0=",
+    "zh:0219ffa02c6f2cf1f519ea42a89615cfbab8219803bcdb4a3614793952b1f5a8",
+    "zh:13915c1eb4f2ad384c6ce343eebe108ddfb0a103e19f1d8b199c0af8e57bc74a",
+    "zh:1c265814efa730540a475f76a8045d90a70c22010d6f2eee45f69e973ce10580",
+    "zh:34d58f6bf64afc491359ad1455007e1eb9aef60be17909096ec88a802b6f72b2",
+    "zh:7a7d709aeb7b2945f5a9a0497976a85bceb07b2cbf236c8c1bb0b7b079b839ab",
+    "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+    "zh:965fbb6042acd6fbf77a9b5c3321edbfa0aa6bf0359394afbf0a7e1392245324",
+    "zh:9e4ac8eae03d1243b9283b202132c007d5c4ee533d1c5efc690403caaaaa7aac",
+    "zh:a51833ca1c6983e32a937ea3864b6037c1ccb97a4917cafb38771a3aa583cc77",
+    "zh:ac2eba5efca9f0bf4ecca3b23c2a89c4318ef7cda45e374811e42cced0aa660b",
+    "zh:c77663f4c0e4ca799e5f1abfa94cfe15f36e9879e637a9196ea01fcaeba13286",
+    "zh:dc0ab43f1affe80e117cea108780afe53d7c97357566ded87f53221828c875de",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_object/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/replace_within_object/dynamic_resources.json
new file mode 100644
index 0000000..641f646
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_object/dynamic_resources.json
@@ -0,0 +1,17 @@
+{
+  "tfcoremock_object": {
+    "attributes": {
+      "object": {
+        "type": "object",
+        "required": true,
+        "object": {
+          "id": {
+            "type": "string",
+            "replace": true,
+            "required": true
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_object/main.tf b/v1.5.7/testing/equivalence-tests/tests/replace_within_object/main.tf
new file mode 100644
index 0000000..9cda772
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_object/main.tf
@@ -0,0 +1,18 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_object" "object" {
+  id = "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+
+  object = {
+    id = "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_object/spec.json b/v1.5.7/testing/equivalence-tests/tests/replace_within_object/spec.json
new file mode 100644
index 0000000..e1601f2
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_object/spec.json
@@ -0,0 +1,6 @@
+{
+  "description": "tests the behaviour of an attribute within an object causing a resource to be replaced",
+  "include_files": [],
+  "ignore_fields": {}
+}
+
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_object/terraform.resource/F40F2AB4-100C-4AE8-BFD0-BF332A158415.json b/v1.5.7/testing/equivalence-tests/tests/replace_within_object/terraform.resource/F40F2AB4-100C-4AE8-BFD0-BF332A158415.json
new file mode 100644
index 0000000..49395ab
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_object/terraform.resource/F40F2AB4-100C-4AE8-BFD0-BF332A158415.json
@@ -0,0 +1,14 @@
+{
+  "values": {
+    "id": {
+      "string": "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+    },
+    "object": {
+      "object": {
+        "id": {
+          "string": "56C7E07F-B9DF-4799-AF62-E703D1167A51"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_object/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/replace_within_object/terraform.tfstate
new file mode 100644
index 0000000..1162e6a
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_object/terraform.tfstate
@@ -0,0 +1,28 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.7",
+  "serial": 4,
+  "lineage": "02b0a9ca-8da4-ad32-a144-3cc984a1d395",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_object",
+      "name": "object",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+            "object": {
+              "id": "56C7E07F-B9DF-4799-AF62-E703D1167A51"
+            }
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_set/.terraform.lock.hcl b/v1.5.7/testing/equivalence-tests/tests/replace_within_set/.terraform.lock.hcl
new file mode 100644
index 0000000..d2d6193
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_set/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/tfcoremock" {
+  version     = "0.1.1"
+  constraints = "0.1.1"
+  hashes = [
+    "h1:K5ImnTbl0eD02BQgVe6pNn5w2wW07j9t7iDUwqPvcy0=",
+    "zh:0219ffa02c6f2cf1f519ea42a89615cfbab8219803bcdb4a3614793952b1f5a8",
+    "zh:13915c1eb4f2ad384c6ce343eebe108ddfb0a103e19f1d8b199c0af8e57bc74a",
+    "zh:1c265814efa730540a475f76a8045d90a70c22010d6f2eee45f69e973ce10580",
+    "zh:34d58f6bf64afc491359ad1455007e1eb9aef60be17909096ec88a802b6f72b2",
+    "zh:7a7d709aeb7b2945f5a9a0497976a85bceb07b2cbf236c8c1bb0b7b079b839ab",
+    "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+    "zh:965fbb6042acd6fbf77a9b5c3321edbfa0aa6bf0359394afbf0a7e1392245324",
+    "zh:9e4ac8eae03d1243b9283b202132c007d5c4ee533d1c5efc690403caaaaa7aac",
+    "zh:a51833ca1c6983e32a937ea3864b6037c1ccb97a4917cafb38771a3aa583cc77",
+    "zh:ac2eba5efca9f0bf4ecca3b23c2a89c4318ef7cda45e374811e42cced0aa660b",
+    "zh:c77663f4c0e4ca799e5f1abfa94cfe15f36e9879e637a9196ea01fcaeba13286",
+    "zh:dc0ab43f1affe80e117cea108780afe53d7c97357566ded87f53221828c875de",
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_set/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/replace_within_set/dynamic_resources.json
new file mode 100644
index 0000000..25aa136
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_set/dynamic_resources.json
@@ -0,0 +1,20 @@
+{
+  "tfcoremock_set": {
+    "attributes": {
+      "set": {
+        "type": "set",
+        "required": true,
+        "set": {
+          "type": "object",
+          "object": {
+            "id": {
+              "type": "string",
+              "replace": true,
+              "required": true
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_set/main.tf b/v1.5.7/testing/equivalence-tests/tests/replace_within_set/main.tf
new file mode 100644
index 0000000..64a599b
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_set/main.tf
@@ -0,0 +1,26 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_set" "set" {
+  id = "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+
+  set = [
+    {
+      id = "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+    },
+    {
+      id = "07F887E2-FDFF-4B2E-9BFB-B6AA4A05EDB9"
+    },
+    {
+      id = "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+    },
+  ]
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_set/spec.json b/v1.5.7/testing/equivalence-tests/tests/replace_within_set/spec.json
new file mode 100644
index 0000000..3a08ac2
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_set/spec.json
@@ -0,0 +1,6 @@
+{
+  "description": "tests the behaviour of an attribute within a set causing a resource to be replaced",
+  "include_files": [],
+  "ignore_fields": {}
+}
+
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_set/terraform.resource/F40F2AB4-100C-4AE8-BFD0-BF332A158415.json b/v1.5.7/testing/equivalence-tests/tests/replace_within_set/terraform.resource/F40F2AB4-100C-4AE8-BFD0-BF332A158415.json
new file mode 100644
index 0000000..b8f76cc
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_set/terraform.resource/F40F2AB4-100C-4AE8-BFD0-BF332A158415.json
@@ -0,0 +1,32 @@
+{
+  "values": {
+    "id": {
+      "string": "F40F2AB4-100C-4AE8-BFD0-BF332A158415"
+    },
+    "set": {
+      "set": [
+        {
+          "object": {
+            "id": {
+              "string": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+            }
+          }
+        },
+        {
+          "object": {
+            "id": {
+              "string": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+            }
+          }
+        },
+        {
+          "object": {
+            "id": {
+              "string": "56C7E07F-B9DF-4799-AF62-E703D1167A51"
+            }
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/replace_within_set/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/replace_within_set/terraform.tfstate
new file mode 100644
index 0000000..8c33aca
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/replace_within_set/terraform.tfstate
@@ -0,0 +1,36 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.7",
+  "serial": 4,
+  "lineage": "a0f911d6-cc86-a0d6-4d4c-967c11b80966",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_set",
+      "name": "set",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "F40F2AB4-100C-4AE8-BFD0-BF332A158415",
+            "set": [
+              {
+                "id": "3BFC1A84-023F-44FA-A8EE-EFD88E18B8F7"
+              },
+              {
+                "id": "4B7178A8-AB9D-4FF4-8B3D-48B754DE537B"
+              },
+              {
+                "id": "56C7E07F-B9DF-4799-AF62-E703D1167A51"
+              }
+            ]
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/simple_object/dynamic_resources.json
new file mode 100644
index 0000000..dfda8f3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object/dynamic_resources.json
@@ -0,0 +1,24 @@
+{
+  "tfcoremock_object": {
+    "attributes": {
+      "object": {
+        "type": "object",
+        "optional": true,
+        "object": {
+          "string": {
+            "type": "string",
+            "optional": true
+          },
+          "boolean": {
+            "type": "boolean",
+            "optional": true
+          },
+          "number": {
+            "type": "number",
+            "optional": true
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object/main.tf b/v1.5.7/testing/equivalence-tests/tests/simple_object/main.tf
new file mode 100644
index 0000000..7881c59
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object/main.tf
@@ -0,0 +1,19 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_object" "object" {
+  id = "AF9833AE-3434-4D0B-8B69-F4B992565D9F"
+  object = {
+    string  = "Hello, world!"
+    boolean = true
+    number  = 10
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object/spec.json b/v1.5.7/testing/equivalence-tests/tests/simple_object/spec.json
new file mode 100644
index 0000000..e9b771e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests creating a simple object with primitive attributes",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_empty/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/simple_object_empty/dynamic_resources.json
new file mode 100644
index 0000000..dfda8f3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_empty/dynamic_resources.json
@@ -0,0 +1,24 @@
+{
+  "tfcoremock_object": {
+    "attributes": {
+      "object": {
+        "type": "object",
+        "optional": true,
+        "object": {
+          "string": {
+            "type": "string",
+            "optional": true
+          },
+          "boolean": {
+            "type": "boolean",
+            "optional": true
+          },
+          "number": {
+            "type": "number",
+            "optional": true
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_empty/main.tf b/v1.5.7/testing/equivalence-tests/tests/simple_object_empty/main.tf
new file mode 100644
index 0000000..c0e38ad
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_empty/main.tf
@@ -0,0 +1,14 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_object" "object" {
+  object = {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_empty/spec.json b/v1.5.7/testing/equivalence-tests/tests/simple_object_empty/spec.json
new file mode 100644
index 0000000..97195ac
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_empty/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests removing all attributes from an object",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_empty/terraform.resource/00e14fba-4d56-6cc5-b685-633555376e3f.json b/v1.5.7/testing/equivalence-tests/tests/simple_object_empty/terraform.resource/00e14fba-4d56-6cc5-b685-633555376e3f.json
new file mode 100644
index 0000000..cea8724
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_empty/terraform.resource/00e14fba-4d56-6cc5-b685-633555376e3f.json
@@ -0,0 +1,20 @@
+{
+  "values": {
+    "id": {
+      "string": "00e14fba-4d56-6cc5-b685-633555376e3f"
+    },
+    "object": {
+      "object": {
+        "boolean": {
+          "boolean": true
+        },
+        "number": {
+          "number": "10"
+        },
+        "string": {
+          "string": "Hello, world!"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_empty/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/simple_object_empty/terraform.tfstate
new file mode 100644
index 0000000..cfee84d
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_empty/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.5",
+  "serial": 1,
+  "lineage": "daaaeb37-0157-6c8c-2de9-7687bf0a6040",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_object",
+      "name": "object",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+            "object": {
+              "boolean": true,
+              "number": 10,
+              "string": "Hello, world!"
+            }
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_null/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/simple_object_null/dynamic_resources.json
new file mode 100644
index 0000000..dfda8f3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_null/dynamic_resources.json
@@ -0,0 +1,24 @@
+{
+  "tfcoremock_object": {
+    "attributes": {
+      "object": {
+        "type": "object",
+        "optional": true,
+        "object": {
+          "string": {
+            "type": "string",
+            "optional": true
+          },
+          "boolean": {
+            "type": "boolean",
+            "optional": true
+          },
+          "number": {
+            "type": "number",
+            "optional": true
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_null/main.tf b/v1.5.7/testing/equivalence-tests/tests/simple_object_null/main.tf
new file mode 100644
index 0000000..62c0f19
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_null/main.tf
@@ -0,0 +1,12 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_object" "object" {}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_null/spec.json b/v1.5.7/testing/equivalence-tests/tests/simple_object_null/spec.json
new file mode 100644
index 0000000..9f4e308
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_null/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests setting an object within a resource to null by removing it from the config",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_null/terraform.resource/00e14fba-4d56-6cc5-b685-633555376e3f.json b/v1.5.7/testing/equivalence-tests/tests/simple_object_null/terraform.resource/00e14fba-4d56-6cc5-b685-633555376e3f.json
new file mode 100644
index 0000000..cea8724
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_null/terraform.resource/00e14fba-4d56-6cc5-b685-633555376e3f.json
@@ -0,0 +1,20 @@
+{
+  "values": {
+    "id": {
+      "string": "00e14fba-4d56-6cc5-b685-633555376e3f"
+    },
+    "object": {
+      "object": {
+        "boolean": {
+          "boolean": true
+        },
+        "number": {
+          "number": "10"
+        },
+        "string": {
+          "string": "Hello, world!"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_null/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/simple_object_null/terraform.tfstate
new file mode 100644
index 0000000..cfee84d
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_null/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.5",
+  "serial": 1,
+  "lineage": "daaaeb37-0157-6c8c-2de9-7687bf0a6040",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_object",
+      "name": "object",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+            "object": {
+              "boolean": true,
+              "number": 10,
+              "string": "Hello, world!"
+            }
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_replace/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/simple_object_replace/dynamic_resources.json
new file mode 100644
index 0000000..dfda8f3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_replace/dynamic_resources.json
@@ -0,0 +1,24 @@
+{
+  "tfcoremock_object": {
+    "attributes": {
+      "object": {
+        "type": "object",
+        "optional": true,
+        "object": {
+          "string": {
+            "type": "string",
+            "optional": true
+          },
+          "boolean": {
+            "type": "boolean",
+            "optional": true
+          },
+          "number": {
+            "type": "number",
+            "optional": true
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_replace/main.tf b/v1.5.7/testing/equivalence-tests/tests/simple_object_replace/main.tf
new file mode 100644
index 0000000..0b82b8e
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_replace/main.tf
@@ -0,0 +1,20 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_object" "object" {
+  id = "63A9E8E8-71BC-4DAE-A66C-48CE393CCBD3"
+
+  object = {
+    string  = "Hello, world!"
+    boolean = true
+    number  = 10
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_replace/spec.json b/v1.5.7/testing/equivalence-tests/tests/simple_object_replace/spec.json
new file mode 100644
index 0000000..4cc29f5
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_replace/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests updating an attribute that forces the overall resource to be replaced",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_replace/terraform.resource/a0ed13ec-116b-14c4-7437-418e217d3659.json b/v1.5.7/testing/equivalence-tests/tests/simple_object_replace/terraform.resource/a0ed13ec-116b-14c4-7437-418e217d3659.json
new file mode 100644
index 0000000..ccd29f1
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_replace/terraform.resource/a0ed13ec-116b-14c4-7437-418e217d3659.json
@@ -0,0 +1,20 @@
+{
+  "values": {
+    "id": {
+      "string": "a0ed13ec-116b-14c4-7437-418e217d3659"
+    },
+    "object": {
+      "object": {
+        "boolean": {
+          "boolean": true
+        },
+        "number": {
+          "number": "10"
+        },
+        "string": {
+          "string": "Hello, world!"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_replace/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/simple_object_replace/terraform.tfstate
new file mode 100644
index 0000000..c31363d
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_replace/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.5",
+  "serial": 1,
+  "lineage": "d6a2102b-030b-3b20-a00c-6d0256541c88",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_object",
+      "name": "object",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "a0ed13ec-116b-14c4-7437-418e217d3659",
+            "object": {
+              "boolean": true,
+              "number": 10,
+              "string": "Hello, world!"
+            }
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_update/dynamic_resources.json b/v1.5.7/testing/equivalence-tests/tests/simple_object_update/dynamic_resources.json
new file mode 100644
index 0000000..dfda8f3
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_update/dynamic_resources.json
@@ -0,0 +1,24 @@
+{
+  "tfcoremock_object": {
+    "attributes": {
+      "object": {
+        "type": "object",
+        "optional": true,
+        "object": {
+          "string": {
+            "type": "string",
+            "optional": true
+          },
+          "boolean": {
+            "type": "boolean",
+            "optional": true
+          },
+          "number": {
+            "type": "number",
+            "optional": true
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_update/main.tf b/v1.5.7/testing/equivalence-tests/tests/simple_object_update/main.tf
new file mode 100644
index 0000000..8d48cc5
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_update/main.tf
@@ -0,0 +1,18 @@
+terraform {
+  required_providers {
+    tfcoremock = {
+      source  = "hashicorp/tfcoremock"
+      version = "0.1.1"
+    }
+  }
+}
+
+provider "tfcoremock" {}
+
+resource "tfcoremock_object" "object" {
+  object = {
+    string  = "Hello, a totally different world!"
+    boolean = false
+    number  = 2
+  }
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_update/spec.json b/v1.5.7/testing/equivalence-tests/tests/simple_object_update/spec.json
new file mode 100644
index 0000000..37fb69f
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_update/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests updating objects when they are nested in other objects",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_update/terraform.resource/00e14fba-4d56-6cc5-b685-633555376e3f.json b/v1.5.7/testing/equivalence-tests/tests/simple_object_update/terraform.resource/00e14fba-4d56-6cc5-b685-633555376e3f.json
new file mode 100644
index 0000000..cea8724
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_update/terraform.resource/00e14fba-4d56-6cc5-b685-633555376e3f.json
@@ -0,0 +1,20 @@
+{
+  "values": {
+    "id": {
+      "string": "00e14fba-4d56-6cc5-b685-633555376e3f"
+    },
+    "object": {
+      "object": {
+        "boolean": {
+          "boolean": true
+        },
+        "number": {
+          "number": "10"
+        },
+        "string": {
+          "string": "Hello, world!"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/v1.5.7/testing/equivalence-tests/tests/simple_object_update/terraform.tfstate b/v1.5.7/testing/equivalence-tests/tests/simple_object_update/terraform.tfstate
new file mode 100644
index 0000000..cfee84d
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/simple_object_update/terraform.tfstate
@@ -0,0 +1,30 @@
+{
+  "version": 4,
+  "terraform_version": "1.3.5",
+  "serial": 1,
+  "lineage": "daaaeb37-0157-6c8c-2de9-7687bf0a6040",
+  "outputs": {},
+  "resources": [
+    {
+      "mode": "managed",
+      "type": "tfcoremock_object",
+      "name": "object",
+      "provider": "provider[\"registry.terraform.io/hashicorp/tfcoremock\"]",
+      "instances": [
+        {
+          "schema_version": 0,
+          "attributes": {
+            "id": "00e14fba-4d56-6cc5-b685-633555376e3f",
+            "object": {
+              "boolean": true,
+              "number": 10,
+              "string": "Hello, world!"
+            }
+          },
+          "sensitive_attributes": []
+        }
+      ]
+    }
+  ],
+  "check_results": null
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/variables_and_outputs/main.auto.tfvars b/v1.5.7/testing/equivalence-tests/tests/variables_and_outputs/main.auto.tfvars
new file mode 100644
index 0000000..8a61f1a
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/variables_and_outputs/main.auto.tfvars
@@ -0,0 +1,17 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+list_no_default = [
+  {
+    required_attribute = "D92053D5-948A-4E5E-80BF-E53F0DB33EB5",
+  },
+  {
+    required_attribute = "E6DA6176-49FB-46D6-9ECD-401B3F46A3E5",
+    optional_attribute = "8AC4B9EE-9E05-4AE0-AA35-6D7636AEA487",
+  },
+  {
+    required_attribute              = "9F9922C4-B426-4648-96AE-804A6F52F778",
+    optional_attribute              = "E68C1EB0-3D3D-4DB0-A41D-0F8C334E181C",
+    optional_attribute_with_default = "92E855B2-A444-49DF-AFCA-2B5B017451B4",
+  },
+]
diff --git a/v1.5.7/testing/equivalence-tests/tests/variables_and_outputs/main.tf b/v1.5.7/testing/equivalence-tests/tests/variables_and_outputs/main.tf
new file mode 100644
index 0000000..63accd8
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/variables_and_outputs/main.tf
@@ -0,0 +1,66 @@
+variable "list_empty_default" {
+  type = list(object({
+    required_attribute              = string,
+    optional_attribute              = optional(string),
+    optional_attribute_with_default = optional(string, "Hello, world!"),
+  }))
+  default = []
+}
+
+variable "list_no_default" {
+  type = list(object({
+    required_attribute              = string,
+    optional_attribute              = optional(string),
+    optional_attribute_with_default = optional(string, "Hello, world!"),
+  }))
+}
+
+variable "nested_optional_object" {
+  type = object({
+    nested_object = optional(object({
+      flag = optional(bool, false)
+    }))
+  })
+  default = {}
+}
+
+variable "nested_optional_object_with_default" {
+  type = object({
+    nested_object = optional(object({
+      flag = optional(bool, false)
+    }))
+  })
+  default = {
+    nested_object = {}
+  }
+}
+
+variable "nested_optional_object_with_embedded_default" {
+  type = object({
+    nested_object = optional(object({
+      flag = optional(bool, false)
+    }), {})
+  })
+  default = {}
+}
+
+
+output "list_empty_default" {
+  value = var.list_empty_default
+}
+
+output "list_no_default" {
+  value = var.list_no_default
+}
+
+output "nested_optional_object" {
+  value = var.nested_optional_object
+}
+
+output "nested_optional_object_with_default" {
+  value = var.nested_optional_object_with_default
+}
+
+output "nested_optional_object_with_embedded_default" {
+  value = var.nested_optional_object_with_embedded_default
+}
diff --git a/v1.5.7/testing/equivalence-tests/tests/variables_and_outputs/spec.json b/v1.5.7/testing/equivalence-tests/tests/variables_and_outputs/spec.json
new file mode 100644
index 0000000..406d082
--- /dev/null
+++ b/v1.5.7/testing/equivalence-tests/tests/variables_and_outputs/spec.json
@@ -0,0 +1,5 @@
+{
+  "description": "tests a set of basic variables and outputs",
+  "include_files": [],
+  "ignore_fields": {}
+}
diff --git a/v1.5.7/tools.go b/v1.5.7/tools.go
new file mode 100644
index 0000000..fd65136
--- /dev/null
+++ b/v1.5.7/tools.go
@@ -0,0 +1,17 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build tools
+// +build tools
+
+package tools
+
+// This file tracks some external tools we use during development and release
+// processes. These are not used at runtime but having them here allows the
+// Go toolchain to see that we need to include them in go.mod and go.sum.
+
+import (
+	_ "github.com/nishanths/exhaustive/cmd/exhaustive"
+	_ "golang.org/x/tools/cmd/stringer"
+	_ "honnef.co/go/tools/cmd/staticcheck"
+)
diff --git a/v1.5.7/tools/loggraphdiff/loggraphdiff.go b/v1.5.7/tools/loggraphdiff/loggraphdiff.go
new file mode 100644
index 0000000..eb84c8a
--- /dev/null
+++ b/v1.5.7/tools/loggraphdiff/loggraphdiff.go
@@ -0,0 +1,156 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// loggraphdiff is a tool for interpreting changes to the Terraform graph
+// based on the simple graph printing format used in the TF_LOG=trace log
+// output from Terraform, which looks like this:
+//
+//     aws_instance.b (destroy) - *terraform.NodeDestroyResourceInstance
+//     aws_instance.b (prepare state) - *terraform.NodeApplyableResource
+//       provider.aws - *terraform.NodeApplyableProvider
+//     aws_instance.b (prepare state) - *terraform.NodeApplyableResource
+//       provider.aws - *terraform.NodeApplyableProvider
+//     module.child.aws_instance.a (destroy) - *terraform.NodeDestroyResourceInstance
+//       module.child.aws_instance.a (prepare state) - *terraform.NodeApplyableResource
+//       module.child.output.a_output - *terraform.NodeApplyableOutput
+//       provider.aws - *terraform.NodeApplyableProvider
+//     module.child.aws_instance.a (prepare state) - *terraform.NodeApplyableResource
+//       provider.aws - *terraform.NodeApplyableProvider
+//     module.child.output.a_output - *terraform.NodeApplyableOutput
+//       module.child.aws_instance.a (prepare state) - *terraform.NodeApplyableResource
+//     provider.aws - *terraform.NodeApplyableProvider
+//
+// It takes the names of two files containing this style of output and
+// produces a single graph description in graphviz format that shows the
+// differences between the two graphs: nodes and edges which are only in the
+// first graph are shown in red, while those only in the second graph are
+// shown in green. This color combination is not useful for those who are
+// red/green color blind, so the result can be adjusted by replacing the
+// keywords "red" and "green" with a combination that the user is able to
+// distinguish.
+
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"log"
+	"os"
+	"sort"
+	"strings"
+)
+
+type Graph struct {
+	nodes map[string]struct{}
+	edges map[[2]string]struct{}
+}
+
+func main() {
+	if len(os.Args) != 3 {
+		log.Fatal("usage: loggraphdiff <old-graph-file> <new-graph-file>")
+	}
+
+	old, err := readGraph(os.Args[1])
+	if err != nil {
+		log.Fatalf("failed to read %s: %s", os.Args[1], err)
+	}
+	new, err := readGraph(os.Args[2])
+	if err != nil {
+		log.Fatalf("failed to read %s: %s", os.Args[1], err)
+	}
+
+	var nodes []string
+	for n := range old.nodes {
+		nodes = append(nodes, n)
+	}
+	for n := range new.nodes {
+		if _, exists := old.nodes[n]; !exists {
+			nodes = append(nodes, n)
+		}
+	}
+	sort.Strings(nodes)
+
+	var edges [][2]string
+	for e := range old.edges {
+		edges = append(edges, e)
+	}
+	for e := range new.edges {
+		if _, exists := old.edges[e]; !exists {
+			edges = append(edges, e)
+		}
+	}
+	sort.Slice(edges, func(i, j int) bool {
+		if edges[i][0] != edges[j][0] {
+			return edges[i][0] < edges[j][0]
+		}
+		return edges[i][1] < edges[j][1]
+	})
+
+	fmt.Println("digraph G {")
+	fmt.Print("  rankdir = \"BT\";\n\n")
+	for _, n := range nodes {
+		var attrs string
+		_, inOld := old.nodes[n]
+		_, inNew := new.nodes[n]
+		switch {
+		case inOld && inNew:
+			// no attrs required
+		case inOld:
+			attrs = " [color=red]"
+		case inNew:
+			attrs = " [color=green]"
+		}
+		fmt.Printf("    %q%s;\n", n, attrs)
+	}
+	fmt.Println("")
+	for _, e := range edges {
+		var attrs string
+		_, inOld := old.edges[e]
+		_, inNew := new.edges[e]
+		switch {
+		case inOld && inNew:
+			// no attrs required
+		case inOld:
+			attrs = " [color=red]"
+		case inNew:
+			attrs = " [color=green]"
+		}
+		fmt.Printf("    %q -> %q%s;\n", e[0], e[1], attrs)
+	}
+	fmt.Println("}")
+}
+
+func readGraph(fn string) (Graph, error) {
+	ret := Graph{
+		nodes: map[string]struct{}{},
+		edges: map[[2]string]struct{}{},
+	}
+	r, err := os.Open(fn)
+	if err != nil {
+		return ret, err
+	}
+
+	sc := bufio.NewScanner(r)
+	var latestNode string
+	for sc.Scan() {
+		l := sc.Text()
+		dash := strings.Index(l, " - ")
+		if dash == -1 {
+			// invalid line, so we'll ignore it
+			continue
+		}
+		name := l[:dash]
+		if strings.HasPrefix(name, "  ") {
+			// It's an edge
+			name = name[2:]
+			edge := [2]string{latestNode, name}
+			ret.edges[edge] = struct{}{}
+		} else {
+			// It's a node
+			latestNode = name
+			ret.nodes[name] = struct{}{}
+		}
+	}
+
+	return ret, nil
+}
diff --git a/v1.5.7/tools/protobuf-compile/.workdir/.gitignore b/v1.5.7/tools/protobuf-compile/.workdir/.gitignore
new file mode 100644
index 0000000..de2eb88
--- /dev/null
+++ b/v1.5.7/tools/protobuf-compile/.workdir/.gitignore
@@ -0,0 +1,5 @@
+# This directory acts both as a cache so we can avoid constantly re-downloading
+# the same protoc, and as a staging area where we can put a protoc-gen-go
+# executable that won't interfere with the operation of other Go codebases
+# on the same system which might want a different version of protoc-gen-go.
+protoc-*
diff --git a/v1.5.7/tools/protobuf-compile/protobuf-compile.go b/v1.5.7/tools/protobuf-compile/protobuf-compile.go
new file mode 100644
index 0000000..2591cd3
--- /dev/null
+++ b/v1.5.7/tools/protobuf-compile/protobuf-compile.go
@@ -0,0 +1,236 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// protobuf-compile is a helper tool for running protoc against all of the
+// .proto files in this repository using specific versions of protoc and
+// protoc-gen-go, to ensure consistent results across all development
+// environments.
+//
+// protoc itself isn't a Go tool, so we need to use a custom strategy to
+// install and run it. The official releases are built only for a subset of
+// platforms that Go can potentially target, so this tool will fail if you
+// are using a platform other than the ones this wrapper tool has explicit
+// support for. In that case you'll need to either run this tool on a supported
+// platform or to recreate what it does manually using a protoc you've built
+// and installed yourself.
+package main
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"strings"
+
+	"github.com/hashicorp/go-getter"
+)
+
+const protocVersion = "3.15.6"
+
+// We also use protoc-gen-go and its grpc addon, but since these are Go tools
+// in Go modules our version selection for these comes from our top-level
+// go.mod, as with all other Go dependencies. If you want to switch to a newer
+// version of either tool then you can upgrade their modules in the usual way.
+const protocGenGoPackage = "github.com/golang/protobuf/protoc-gen-go"
+const protocGenGoGrpcPackage = "google.golang.org/grpc/cmd/protoc-gen-go-grpc"
+
+type protocStep struct {
+	DisplayName string
+	WorkDir     string
+	Args        []string
+}
+
+var protocSteps = []protocStep{
+	{
+		"tfplugin5 (provider wire protocol version 5)",
+		"internal/tfplugin5",
+		[]string{"--go_out=paths=source_relative,plugins=grpc:.", "./tfplugin5.proto"},
+	},
+	{
+		"tfplugin6 (provider wire protocol version 6)",
+		"internal/tfplugin6",
+		[]string{"--go_out=paths=source_relative,plugins=grpc:.", "./tfplugin6.proto"},
+	},
+	{
+		"tfplan (plan file serialization)",
+		"internal/plans/internal/planproto",
+		[]string{"--go_out=paths=source_relative:.", "planfile.proto"},
+	},
+}
+
+func main() {
+	if len(os.Args) != 2 {
+		log.Fatal("Usage: go run github.com/hashicorp/terraform/tools/protobuf-compile <basedir>")
+	}
+	baseDir := os.Args[1]
+	workDir := filepath.Join(baseDir, "tools/protobuf-compile/.workdir")
+
+	protocLocalDir := filepath.Join(workDir, "protoc-v"+protocVersion)
+	if _, err := os.Stat(protocLocalDir); os.IsNotExist(err) {
+		err := downloadProtoc(protocVersion, protocLocalDir)
+		if err != nil {
+			log.Fatal(err)
+		}
+	} else {
+		log.Printf("already have protoc v%s in %s", protocVersion, protocLocalDir)
+	}
+
+	protocExec := filepath.Join(protocLocalDir, "bin/protoc")
+
+	protocGenGoExec, err := buildProtocGenGo(workDir)
+	if err != nil {
+		log.Fatal(err)
+	}
+	_, err = buildProtocGenGoGrpc(workDir)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	protocExec, err = filepath.Abs(protocExec)
+	if err != nil {
+		log.Fatal(err)
+	}
+	protocGenGoExec, err = filepath.Abs(protocGenGoExec)
+	if err != nil {
+		log.Fatal(err)
+	}
+	protocGenGoGrpcExec, err := filepath.Abs(protocGenGoExec)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// For all of our steps we'll run our localized protoc with our localized
+	// protoc-gen-go.
+	baseCmdLine := []string{protocExec, "--plugin=" + protocGenGoExec, "--plugin=" + protocGenGoGrpcExec}
+
+	for _, step := range protocSteps {
+		log.Printf("working on %s", step.DisplayName)
+
+		cmdLine := make([]string, 0, len(baseCmdLine)+len(step.Args))
+		cmdLine = append(cmdLine, baseCmdLine...)
+		cmdLine = append(cmdLine, step.Args...)
+
+		cmd := &exec.Cmd{
+			Path:   cmdLine[0],
+			Args:   cmdLine[1:],
+			Dir:    step.WorkDir,
+			Env:    os.Environ(),
+			Stdout: os.Stdout,
+			Stderr: os.Stderr,
+		}
+		err := cmd.Run()
+		if err != nil {
+			log.Printf("failed to compile: %s", err)
+		}
+	}
+
+}
+
+// downloadProtoc downloads the given version of protoc into the given
+// directory.
+func downloadProtoc(version string, localDir string) error {
+	protocURL, err := protocDownloadURL(version)
+	if err != nil {
+		return err
+	}
+
+	log.Printf("downloading and extracting protoc v%s from %s into %s", version, protocURL, localDir)
+
+	// For convenience, we'll be using go-getter to actually download this
+	// thing, so we need to turn the real URL into the funny sort of pseudo-URL
+	// thing that go-getter wants.
+	goGetterURL := protocURL + "?archive=zip"
+
+	err = getter.Get(localDir, goGetterURL)
+	if err != nil {
+		return fmt.Errorf("failed to download or extract the package: %s", err)
+	}
+
+	return nil
+}
+
+// buildProtocGenGo uses the Go toolchain to fetch the module containing
+// protoc-gen-go and then build an executable into the working directory.
+//
+// If successful, it returns the location of the executable.
+func buildProtocGenGo(workDir string) (string, error) {
+	exeSuffixRaw, err := exec.Command("go", "env", "GOEXE").Output()
+	if err != nil {
+		return "", fmt.Errorf("failed to determine executable suffix: %s", err)
+	}
+	exeSuffix := strings.TrimSpace(string(exeSuffixRaw))
+	exePath := filepath.Join(workDir, "protoc-gen-go"+exeSuffix)
+	log.Printf("building %s as %s", protocGenGoPackage, exePath)
+
+	cmd := exec.Command("go", "build", "-o", exePath, protocGenGoPackage)
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	err = cmd.Run()
+	if err != nil {
+		return "", fmt.Errorf("failed to build %s: %s", protocGenGoPackage, err)
+	}
+
+	return exePath, nil
+}
+
+// buildProtocGenGoGrpc uses the Go toolchain to fetch the module containing
+// protoc-gen-go-grpc and then build an executable into the working directory.
+//
+// If successful, it returns the location of the executable.
+func buildProtocGenGoGrpc(workDir string) (string, error) {
+	exeSuffixRaw, err := exec.Command("go", "env", "GOEXE").Output()
+	if err != nil {
+		return "", fmt.Errorf("failed to determine executable suffix: %s", err)
+	}
+	exeSuffix := strings.TrimSpace(string(exeSuffixRaw))
+	exePath := filepath.Join(workDir, "protoc-gen-go-grpc"+exeSuffix)
+	log.Printf("building %s as %s", protocGenGoGrpcPackage, exePath)
+
+	cmd := exec.Command("go", "build", "-o", exePath, protocGenGoGrpcPackage)
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	err = cmd.Run()
+	if err != nil {
+		return "", fmt.Errorf("failed to build %s: %s", protocGenGoGrpcPackage, err)
+	}
+
+	return exePath, nil
+}
+
+// protocDownloadURL returns the URL to try to download the protoc package
+// for the current platform or an error if there's no known URL for the
+// current platform.
+func protocDownloadURL(version string) (string, error) {
+	platformKW := protocPlatform()
+	if platformKW == "" {
+		return "", fmt.Errorf("don't know where to find protoc for %s on %s", runtime.GOOS, runtime.GOARCH)
+	}
+	return fmt.Sprintf("https://github.com/protocolbuffers/protobuf/releases/download/v%s/protoc-%s-%s.zip", protocVersion, protocVersion, platformKW), nil
+}
+
+// protocPlatform returns the package name substring for the current platform
+// in the naming convention used by official protoc packages, or an empty
+// string if we don't know how protoc packaging would describe current
+// platform.
+func protocPlatform() string {
+	goPlatform := runtime.GOOS + "_" + runtime.GOARCH
+
+	switch goPlatform {
+	case "linux_amd64":
+		return "linux-x86_64"
+	case "linux_arm64":
+		return "linux-aarch_64"
+	case "darwin_amd64":
+		return "osx-x86_64"
+	case "darwin_arm64":
+		// As of 3.15.6 there isn't yet an osx-aarch_64 package available,
+		// so we'll install the x86_64 version and hope Rosetta can handle it.
+		return "osx-x86_64"
+	case "windows_amd64":
+		return "win64" // for some reason the windows packages don't have a CPU architecture part
+	default:
+		return ""
+	}
+}
diff --git a/v1.5.7/tools/terraform-bundle/README.md b/v1.5.7/tools/terraform-bundle/README.md
new file mode 100644
index 0000000..4df28c5
--- /dev/null
+++ b/v1.5.7/tools/terraform-bundle/README.md
@@ -0,0 +1,60 @@
+# terraform-bundle
+
+`terraform-bundle` was a solution intended to help with the problem
+of distributing Terraform providers to environments where direct registry
+access is impossible or undesirable, created in response to the Terraform v0.10
+change to distribute providers separately from Terraform CLI.
+
+The Terraform v0.13 series introduced our intended longer-term solutions
+to this need:
+
+* [Alternative provider installation methods](https://www.terraform.io/docs/cli/config/config-file.html#provider-installation),
+  including the possibility of running server containing a local mirror of
+  providers you intend to use which Terraform can then use instead of the
+  origin registry.
+* [The `terraform providers mirror` command](https://www.terraform.io/docs/cli/commands/providers/mirror.html),
+  built in to Terraform v0.13.0 and later, can automatically construct a
+  suitable directory structure to serve from a local mirror based on your
+  current Terraform configuration, serving a similar (though not identical)
+  purpose than `terraform-bundle` had served.
+
+For those using Terraform CLI alone, without Terraform Cloud, we recommend
+planning to transition to the above features instead of using
+`terraform-bundle`.
+
+## How to use `terraform-bundle`
+
+However, if you need to continue using `terraform-bundle`
+during a transitional period then you can use the version of the tool included
+in the Terraform v0.15 branch to build bundles compatible with
+Terraform v0.13.0 and later.
+
+If you have a working toolchain for the Go programming language, you can
+build a `terraform-bundle` executable as follows:
+
+* `git clone --single-branch --branch=v0.15 --depth=1 https://github.com/hashicorp/terraform.git`
+* `cd terraform`
+* `go build -o ../terraform-bundle ./tools/terraform-bundle`
+
+After running these commands, your original working directory will have an
+executable named `terraform-bundle`, which you can then run.
+
+
+For information
+on how to use `terraform-bundle`, see
+[the README from the v0.15 branch](https://github.com/hashicorp/terraform/blob/v0.15/tools/terraform-bundle/README.md).
+
+You can follow a similar principle to build a `terraform-bundle` release
+compatible with Terraform v0.12 by using `--branch=v0.12` instead of
+`--branch=v0.15` in the command above. Terraform CLI versions prior to
+v0.13 have different expectations for plugin packaging due to them predating
+Terraform v0.13's introduction of automatic third-party provider installation.
+
+## Terraform Enterprise Users
+
+If you use Terraform Enterprise, the self-hosted distribution of
+Terraform Cloud, you can use `terraform-bundle` as described above to build
+custom Terraform packages with bundled provider plugins.
+
+For more information, see
+[Installing a Bundle in Terraform Enterprise](https://github.com/hashicorp/terraform/blob/v0.15/tools/terraform-bundle/README.md#installing-a-bundle-in-terraform-enterprise).
diff --git a/v1.5.7/tools/tools.go b/v1.5.7/tools/tools.go
new file mode 100644
index 0000000..a849cdc
--- /dev/null
+++ b/v1.5.7/tools/tools.go
@@ -0,0 +1,17 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build tools
+// +build tools
+
+package tools
+
+import (
+	_ "github.com/golang/mock/mockgen"
+	_ "github.com/mitchellh/gox"
+	_ "github.com/nishanths/exhaustive"
+	_ "golang.org/x/tools/cmd/cover"
+	_ "golang.org/x/tools/cmd/stringer"
+	_ "google.golang.org/grpc/cmd/protoc-gen-go-grpc"
+	_ "honnef.co/go/tools/cmd/staticcheck"
+)
diff --git a/v1.5.7/version.go b/v1.5.7/version.go
new file mode 100644
index 0000000..a1e32b3
--- /dev/null
+++ b/v1.5.7/version.go
@@ -0,0 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"github.com/hashicorp/terraform/version"
+)
+
+var Version = version.Version
+
+var VersionPrerelease = version.Prerelease
diff --git a/v1.5.7/version/VERSION b/v1.5.7/version/VERSION
new file mode 100644
index 0000000..f01291b
--- /dev/null
+++ b/v1.5.7/version/VERSION
@@ -0,0 +1 @@
+1.5.7
diff --git a/v1.5.7/version/dependencies.go b/v1.5.7/version/dependencies.go
new file mode 100644
index 0000000..c05e228
--- /dev/null
+++ b/v1.5.7/version/dependencies.go
@@ -0,0 +1,46 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package version
+
+import "runtime/debug"
+
+// See the docs for InterestingDependencies to understand what "interesting" is
+// intended to mean here. We should keep this set relatively small to avoid
+// bloating the logs too much.
+var interestingDependencies = map[string]struct{}{
+	"github.com/hashicorp/hcl/v2":            {},
+	"github.com/zclconf/go-cty":              {},
+	"github.com/hashicorp/go-tfe":            {},
+	"github.com/hashicorp/terraform-svchost": {},
+}
+
+// InterestingDependencies returns the compiled-in module version info for
+// a small number of dependencies that Terraform uses broadly and which we
+// tend to upgrade relatively often as part of improvements to Terraform.
+//
+// The set of dependencies this reports might change over time if our
+// opinions change about what's "interesting". This is here only to create
+// a small number of extra annotations in a debug log to help us more easily
+// cross-reference bug reports with dependency changelogs.
+func InterestingDependencies() []*debug.Module {
+	info, ok := debug.ReadBuildInfo()
+	if !ok {
+		// Weird to not be built in module mode, but not a big deal.
+		return nil
+	}
+
+	ret := make([]*debug.Module, 0, len(interestingDependencies))
+
+	for _, mod := range info.Deps {
+		if _, ok := interestingDependencies[mod.Path]; !ok {
+			continue
+		}
+		if mod.Replace != nil {
+			mod = mod.Replace
+		}
+		ret = append(ret, mod)
+	}
+
+	return ret
+}
diff --git a/v1.5.7/version/version.go b/v1.5.7/version/version.go
new file mode 100644
index 0000000..21b7d98
--- /dev/null
+++ b/v1.5.7/version/version.go
@@ -0,0 +1,43 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+// The version package provides a location to set the release versions for all
+// packages to consume, without creating import cycles.
+//
+// This package should not import any other terraform packages.
+package version
+
+import (
+	"fmt"
+
+	version "github.com/hashicorp/go-version"
+)
+
+// The main version number that is being run at the moment.
+var Version = "1.5.7"
+
+// A pre-release marker for the version. If this is "" (empty string)
+// then it means that it is a final release. Otherwise, this is a pre-release
+// such as "dev" (in development), "beta", "rc1", etc.
+var Prerelease = ""
+
+// SemVer is an instance of version.Version. This has the secondary
+// benefit of verifying during tests and init time that our version is a
+// proper semantic version, which should always be the case.
+var SemVer *version.Version
+
+func init() {
+	SemVer = version.Must(version.NewVersion(Version))
+}
+
+// Header is the header name used to send the current terraform version
+// in http requests.
+const Header = "Terraform-Version"
+
+// String returns the complete version string, including prerelease
+func String() string {
+	if Prerelease != "" {
+		return fmt.Sprintf("%s-%s", Version, Prerelease)
+	}
+	return Version
+}
diff --git a/v1.5.7/website/Makefile b/v1.5.7/website/Makefile
new file mode 100644
index 0000000..fe76940
--- /dev/null
+++ b/v1.5.7/website/Makefile
@@ -0,0 +1,60 @@
+######################################################
+# NOTE: This file is managed by the Digital Team's   #
+# Terraform configuration @ hashicorp/mktg-terraform #
+######################################################
+
+.DEFAULT_GOAL := website
+
+# Set the preview mode for the website shell to "developer" or "io"
+PREVIEW_MODE ?= developer
+REPO ?= terraform
+
+# Enable setting alternate docker tool, e.g. 'make DOCKER_CMD=podman'
+DOCKER_CMD ?= docker
+
+CURRENT_GIT_BRANCH=$$(git rev-parse --abbrev-ref HEAD)
+LOCAL_CONTENT_DIR=../docs
+PWD=$$(pwd)
+
+DOCKER_IMAGE="hashicorp/dev-portal"
+DOCKER_IMAGE_LOCAL="dev-portal-local"
+DOCKER_RUN_FLAGS=-it \
+		--publish "3000:3000" \
+		--rm \
+		--tty \
+		--volume "$(PWD)/docs:/app/docs" \
+		--volume "$(PWD)/img:/app/public" \
+		--volume "$(PWD)/data:/app/data" \
+		--volume "$(PWD)/redirects.js:/app/redirects.js" \
+		--volume "next-dir:/app/website-preview/.next" \
+		--volume "$(PWD)/.env:/app/.env" \
+		--volume "$(PWD)/.env.development:/app/website-preview/.env.development" \
+		--volume "$(PWD)/.env.local:/app/website-preview/.env.local" \
+		-e "REPO=$(REPO)" \
+		-e "PREVIEW_FROM_REPO=$(REPO)" \
+		-e "IS_CONTENT_PREVIEW=true" \
+		-e "LOCAL_CONTENT_DIR=$(LOCAL_CONTENT_DIR)" \
+		-e "CURRENT_GIT_BRANCH=$(CURRENT_GIT_BRANCH)" \
+		-e "PREVIEW_MODE=$(PREVIEW_MODE)"
+
+# Default: run this if working on the website locally to run in watch mode.
+.PHONY: website
+website:
+	@echo "==> Downloading latest Docker image..."
+	@$(DOCKER_CMD) pull $(DOCKER_IMAGE)
+	@echo "==> Starting website..."
+	@$(DOCKER_CMD) run $(DOCKER_RUN_FLAGS) $(DOCKER_IMAGE)
+
+# Use this if you have run `website/build-local` to use the locally built image.
+.PHONY: website/local
+website/local:
+	@echo "==> Starting website from local image..."
+	@$(DOCKER_CMD) run $(DOCKER_RUN_FLAGS) $(DOCKER_IMAGE_LOCAL)
+
+# Run this to generate a new local Docker image.
+.PHONY: website/build-local
+website/build-local:
+	@echo "==> Building local Docker image"
+	@$(DOCKER_CMD) build https://github.com/hashicorp/dev-portal.git\#main \
+		-t $(DOCKER_IMAGE_LOCAL)
+
diff --git a/v1.5.7/website/README.md b/v1.5.7/website/README.md
new file mode 100644
index 0000000..2401de4
--- /dev/null
+++ b/v1.5.7/website/README.md
@@ -0,0 +1,86 @@
+# Terraform Documentation
+
+This directory contains the portions of [the Terraform website](https://www.terraform.io/) that pertain to the core functionality, excluding providers and the overall configuration.
+
+The website uses the files in this directory in conjunction with
+[the `terraform-website` repository](https://github.com/hashicorp/terraform-website). The `terraform-website` repository brings all of the documentation together and contains the scripts for testing and building the entire site.
+
+## Suggesting Changes
+
+You can [submit an issue](https://github.com/hashicorp/terraform/issues/new/choose) with documentation requests or submit a pull request with suggested changes.
+
+Click **Edit this page** at the bottom of any Terraform website page to go directly to the associated markdown file in GitHub.
+
+## Validating Content
+
+Content changes are automatically validated against a set of rules as part of the pull request process. If you want to run these checks locally to validate your content before committing your changes, you can run the following command:
+
+```
+npm run content-check
+```
+
+If the validation fails, actionable error messages will be displayed to help you address detected issues.
+
+## Modifying Sidebar Navigation
+
+You must update the the sidebar navigation when you add or delete documentation .mdx files. If you do not update the navigation, the website deploy preview fails.
+
+To update the sidebar navigation, you must edit the appropriate `nav-data.json` file. This repository contains the sidebar navigation files for the following documentation sets:
+
+- Terraform Language: [`language-nav-data.json`](https://github.com/hashicorp/terraform/blob/main/website/data/language-nav-data.json)
+- Terraform CLI: [`cli-nav-data.json`](https://github.com/hashicorp/terraform/blob/main/website/data/cli-nav-data.json)
+- Introduction to Terraform: [`intro-nav-data.json`](https://github.com/hashicorp/terraform/blob/update-readme/website/data/intro-nav-data.json)
+
+For more details about how to update the sidebar navigation, refer to [Editing Navigation Sidebars](https://github.com/hashicorp/terraform-website#editing-navigation-sidebars) in the `terraform-website` repository.
+
+## Adding Redirects
+
+You must add a redirect when you move, rename, or delete documentation pages. Refer to https://github.com/hashicorp/terraform-website#redirects for details.
+
+## Previewing Changes
+
+You should preview all of your changes locally before creating a pull request. The build includes content from this repository and the [`terraform-website`](https://github.com/hashicorp/terraform-website/) repository, allowing you to preview the entire Terraform documentation site.
+
+**Set Up Local Environment**
+
+1. [Install Docker](https://docs.docker.com/get-docker/).
+2. [Install Go](https://golang.org/doc/install) or create a `~/go` directory manually.
+3. Open terminal and set `GOPATH` as an environment variable:
+
+   Bash: `export $GOPATH=~/go`(bash)
+
+   Zsh: `echo -n 'export GOPATH=~/go' >> ~/.zshrc`
+
+4. Restart your terminal or command line session.
+
+**Launch Site Locally**
+
+1. Navigate into your local `terraform` top-level directory and run `make website`.
+1. Open `http://localhost:3000` in your web browser. While the preview is running, you can edit pages and Next.js automatically rebuilds them.
+1. Press `ctrl-C` in your terminal to stop the server and end the preview.
+
+## Deploying Changes
+
+Merging a PR to `main` queues up documentation changes for the next minor product release. Your changes are not immediately available on the website.
+
+The website generates versioned documentation by pointing to the HEAD of the release branch for that version. For example, the `v1.2.x` documentation on the website points to the HEAD of the `v1.2` release branch in the `terraform` repository. To update existing documentation versions, you must also backport your changes to that release branch. Backported changes become live on the site within one hour.
+
+### Backporting
+
+**Important:** Editing old versions (not latest) should be rare. We backport to old versions when there is an egregious error. Egregious errors include inaccuracies that could cause security vulnerabilities or extreme inconvenience for users.
+
+Backporting involves cherry-picking commits to one or more release branches within a docs repository. You can backport (cherry-pick) commits to a version branch by adding the associated backport label to your pull request. For example, if you need to add a security warning to the v1.1 documentation, you must add the `1.1-backport` label. When you merge a pull request with one or more backport labels, GitHub Actions opens a backport PR to cherry-pick your changes to the associated release branches. You must manually merge the backport PR to finish backporting the changes.
+
+To make your changes available on the latest docs version:
+
+1. Add the backport label for the latest version.
+
+   <img width="317" alt="Screen Shot 2022-08-09 at 11 06 17 AM" src="https://user-images.githubusercontent.com/83350965/183686586-f94e58f3-fd62-48cf-88bd-fa886fe4724f.png">
+
+1. Merge the pull request. GitHub Actions autogenerates a backport pull request, linked to the original.
+
+   <img width="726" alt="Screen Shot 2022-08-09 at 11 08 52 AM" src="https://user-images.githubusercontent.com/83350965/183687165-350b0e9b-a888-409e-91e2-81d82eac0a4e.png">
+
+1. Merge the auto-generated backport pull request.
+
+   You can review and merge your own backport pull request without waiting for another review if the changes in the backport pull request are effectively equivalent to the original. You can make minor adjustments to resolve merge conflicts, but you should not merge a backport PR that contains major content or functionality changes from the original, approved pull request. If you are not sure whether it is okay to merge a backport pull request, post a comment on the original pull request to discuss with the team.
diff --git a/v1.5.7/website/data/cli-nav-data.json b/v1.5.7/website/data/cli-nav-data.json
new file mode 100644
index 0000000..b8676b2
--- /dev/null
+++ b/v1.5.7/website/data/cli-nav-data.json
@@ -0,0 +1,447 @@
+[
+  { "heading": "Terraform CLI" },
+  { "title": "Overview", "path": "" },
+  { "title": "Basic CLI Features", "href": "/cli/commands" },
+  {
+    "title": "Initializing Working Directories",
+    "routes": [
+      { "title": "Overview", "path": "init" },
+      { "title": "<code>init</code>", "href": "/cli/commands/init" },
+      { "title": "<code>get</code>", "href": "/cli/commands/get" }
+    ]
+  },
+  {
+    "title": "Provisioning Infrastructure",
+    "routes": [
+      { "title": "Overview", "path": "run" },
+      { "title": "<code>plan</code>", "href": "/cli/commands/plan" },
+      { "title": "<code>apply</code>", "href": "/cli/commands/apply" },
+      { "title": "<code>destroy</code>", "href": "/cli/commands/destroy" }
+    ]
+  },
+  {
+    "title": "Authenticating",
+    "routes": [
+      { "title": "Overview", "path": "auth" },
+      { "title": "<code>login</code>", "href": "/cli/commands/login" },
+      { "title": "<code>logout</code>", "href": "/cli/commands/logout" }
+    ]
+  },
+  {
+    "title": "Writing and Modifying Code",
+    "routes": [
+      { "title": "Overview", "path": "code" },
+      { "title": "<code>console</code>", "href": "/cli/commands/console" },
+      { "title": "<code>fmt</code>", "href": "/cli/commands/fmt" },
+      { "title": "<code>validate</code>", "href": "/cli/commands/validate" },
+      {
+        "title": "<code>0.13upgrade</code>",
+        "href": "/cli/commands/0.13upgrade"
+      },
+      {
+        "title": "<code>0.12upgrade</code>",
+        "href": "/cli/commands/0.12upgrade"
+      }
+    ]
+  },
+  {
+    "title": "Inspecting Infrastructure",
+    "routes": [
+      { "title": "Overview", "path": "inspect" },
+      { "title": "<code>graph</code>", "href": "/cli/commands/graph" },
+      { "title": "<code>output</code>", "href": "/cli/commands/output" },
+      { "title": "<code>show</code>", "href": "/cli/commands/show" },
+      {
+        "title": "<code>state list</code>",
+        "href": "/cli/commands/state/list"
+      },
+      {
+        "title": "<code>state show</code>",
+        "href": "/cli/commands/state/show"
+      }
+    ]
+  },
+  {
+    "title": "Importing Infrastructure",
+    "routes": [
+      { "title": "Overview", "path": "import" },
+      {
+        "title": "<code>import</code>",
+        "href": "/cli/commands/import"
+      },
+      { "title": "Usage Tips", "path": "import/usage" },
+      {
+        "title": "Resource Importability",
+        "path": "import/importability"
+      }
+    ]
+  },
+  {
+    "title": "Manipulating State",
+    "routes": [
+      { "title": "Overview", "path": "state" },
+      {
+        "title": "Resource Addressing",
+        "path": "state/resource-addressing"
+      },
+      { "title": "<code>state</code>", "href": "/cli/commands/state" },
+      {
+        "title": "Inspecting State",
+        "routes": [
+          { "title": "Overview", "path": "state/inspect" },
+          {
+            "title": "<code>state list</code>",
+            "href": "/cli/commands/state/list"
+          },
+          {
+            "title": "<code>state show</code>",
+            "href": "/cli/commands/state/show"
+          },
+          {
+            "title": "<code>refresh</code>",
+            "href": "/cli/commands/refresh"
+          }
+        ]
+      },
+      {
+        "title": "Forcing Re-creation (Tainting)",
+        "routes": [
+          { "title": "Overview", "path": "state/taint" },
+          {
+            "title": "<code>taint</code>",
+            "href": "/cli/commands/taint"
+          },
+          {
+            "title": "<code>untaint</code>",
+            "href": "/cli/commands/untaint"
+          }
+        ]
+      },
+      {
+        "title": "Moving Resources",
+        "routes": [
+          { "title": "Overview", "path": "state/move" },
+          {
+            "title": "<code>state mv</code>",
+            "href": "/cli/commands/state/mv"
+          },
+          {
+            "title": "<code>state rm</code>",
+            "href": "/cli/commands/state/rm"
+          },
+          {
+            "title": "<code>state replace-provider</code>",
+            "href": "/cli/commands/state/replace-provider"
+          }
+        ]
+      },
+      {
+        "title": "Disaster Recovery",
+        "routes": [
+          {
+            "title": "Overview",
+            "path": "state/recover"
+          },
+          {
+            "title": "<code>state pull</code>",
+            "href": "/cli/commands/state/pull"
+          },
+          {
+            "title": "<code>state push</code>",
+            "href": "/cli/commands/state/push"
+          },
+          {
+            "title": "<code>force-unlock</code>",
+            "href": "/cli/commands/force-unlock"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "title": "Managing Workspaces",
+    "routes": [
+      { "title": "Overview", "path": "workspaces" },
+      {
+        "title": "<code>workspace</code>",
+        "routes": [
+          { "title": "Overview", "href": "/cli/commands/workspace" },
+          {
+            "title": "<code>workspace list</code>",
+            "href": "/cli/commands/workspace/list"
+          },
+          {
+            "title": "<code>workspace select</code>",
+            "href": "/cli/commands/workspace/select"
+          },
+          {
+            "title": "<code>workspace new</code>",
+            "href": "/cli/commands/workspace/new"
+          },
+          {
+            "title": "<code>workspace delete</code>",
+            "href": "/cli/commands/workspace/delete"
+          },
+          {
+            "title": "<code>workspace show</code>",
+            "href": "/cli/commands/workspace/show"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "title": "Managing Plugins",
+    "routes": [
+      { "title": "Overview", "path": "plugins" },
+      { "title": "Plugin Signing", "path": "plugins/signing" },
+      {
+        "title": "<code>providers</code>",
+        "href": "/cli/commands/providers"
+      },
+      {
+        "title": "<code>version</code>",
+        "href": "/cli/commands/version"
+      },
+      {
+        "title": "<code>providers lock</code>",
+        "href": "/cli/commands/providers/lock"
+      },
+      {
+        "title": "<code>providers mirror</code>",
+        "href": "/cli/commands/providers/mirror"
+      },
+      {
+        "title": "<code>providers schema</code>",
+        "href": "/cli/commands/providers/schema"
+      }
+    ]
+  },
+  {
+    "title": "CLI Configuration",
+    "routes": [
+      { "title": "Overview", "path": "config" },
+      { "title": "CLI Configuration", "path": "config/config-file" },
+      {
+        "title": "Environment Variables",
+        "path": "config/environment-variables"
+      }
+    ]
+  },
+  {
+    "title": "Using Terraform Cloud",
+    "routes": [
+      { "title": "Overview", "path": "cloud" },
+      { "title": "Terraform Cloud Settings", "path": "cloud/settings" },
+      {
+        "title": "Initializing and Migrating",
+        "path": "cloud/migrating"
+      },
+      {
+        "title": "Command Line Arguments",
+        "path": "cloud/command-line-arguments"
+      }
+    ]
+  },
+  {
+    "title": "Automating Terraform",
+    "routes": [
+      {
+        "title": "Running Terraform in Automation",
+        "href": "https://learn.hashicorp.com/tutorials/terraform/automate-terraform?in=terraform/automation&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS"
+      },
+      {
+        "title": "GitHub Actions",
+        "href": "https://learn.hashicorp.com/tutorials/terraform/github-actions?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS"
+      }
+    ]
+  },
+  {
+    "title": "Alphabetical List of Commands",
+    "routes": [
+      { "title": "Overview", "href": "/cli/commands" },
+      { "title": "<code>apply</code>", "href": "/cli/commands/apply" },
+      { "title": "<code>console</code>", "href": "/cli/commands/console" },
+      { "title": "<code>destroy</code>", "href": "/cli/commands/destroy" },
+      { "title": "<code>env</code>", "href": "/cli/commands/env" },
+      { "title": "<code>fmt</code>", "href": "/cli/commands/fmt" },
+      {
+        "title": "<code>force-unlock</code>",
+        "href": "/cli/commands/force-unlock"
+      },
+      { "title": "<code>get</code>", "href": "/cli/commands/get" },
+      { "title": "<code>graph</code>", "href": "/cli/commands/graph" },
+      { "title": "<code>import</code>", "href": "/cli/commands/import" },
+      { "title": "<code>init</code>", "href": "/cli/commands/init" },
+      { "title": "<code>login</code>", "href": "/cli/commands/login" },
+      { "title": "<code>logout</code>", "href": "/cli/commands/logout" },
+      { "title": "<code>output</code>", "href": "/cli/commands/output" },
+      { "title": "<code>plan</code>", "href": "/cli/commands/plan" },
+      { "title": "<code>providers</code>", "href": "/cli/commands/providers" },
+      {
+        "title": "<code>providers lock</code>",
+        "href": "/cli/commands/providers/lock"
+      },
+      {
+        "title": "<code>providers mirror</code>",
+        "href": "/cli/commands/providers/mirror"
+      },
+      {
+        "title": "<code>providers schema</code>",
+        "href": "/cli/commands/providers/schema"
+      },
+      {
+        "title": "<code>push (deprecated)</code>",
+        "href": "/cli/commands/push"
+      },
+      { "title": "<code>refresh</code>", "href": "/cli/commands/refresh" },
+      { "title": "<code>show</code>", "href": "/cli/commands/show" },
+      { "title": "<code>state</code>", "href": "/cli/commands/state" },
+      {
+        "title": "<code>state list</code>",
+        "href": "/cli/commands/state/list"
+      },
+      { "title": "<code>state mv</code>", "href": "/cli/commands/state/mv" },
+      {
+        "title": "<code>state pull</code>",
+        "href": "/cli/commands/state/pull"
+      },
+      {
+        "title": "<code>state push</code>",
+        "href": "/cli/commands/state/push"
+      },
+      {
+        "title": "<code>state replace-provider</code>",
+        "href": "/cli/commands/state/replace-provider"
+      },
+      { "title": "<code>state rm</code>", "href": "/cli/commands/state/rm" },
+      {
+        "title": "<code>state show</code>",
+        "href": "/cli/commands/state/show"
+      },
+      { "title": "<code>taint</code>", "href": "/cli/commands/taint" },
+      {
+        "title": "<code>test (deprecated)</code>",
+        "href": "/cli/commands/test"
+      },
+      { "title": "<code>untaint</code>", "href": "/cli/commands/untaint" },
+      { "title": "<code>validate</code>", "href": "/cli/commands/validate" },
+      { "title": "<code>version</code>", "href": "/cli/commands/version" },
+      { "title": "<code>workspace</code>", "href": "/cli/commands/workspace" },
+      {
+        "title": "<code>workspace list</code>",
+        "href": "/cli/commands/workspace/list"
+      },
+      {
+        "title": "<code>workspace select</code>",
+        "href": "/cli/commands/workspace/select"
+      },
+      {
+        "title": "<code>workspace new</code>",
+        "href": "/cli/commands/workspace/new"
+      },
+      {
+        "title": "<code>workspace delete</code>",
+        "href": "/cli/commands/workspace/delete"
+      },
+      {
+        "title": "<code>workspace show</code>",
+        "href": "/cli/commands/workspace/show"
+      },
+      {
+        "title": "<code>0.12upgrade</code>",
+        "href": "/cli/commands/0.12upgrade"
+      },
+      {
+        "title": "<code>0.13upgrade</code>",
+        "href": "/cli/commands/0.13upgrade"
+      }
+    ]
+  },
+  {
+    "title": "Alphabetical list of commands",
+    "hidden": true,
+    "routes": [
+      { "title": "Overview", "path": "commands" },
+      { "title": "apply", "path": "commands/apply" },
+      { "title": "console", "path": "commands/console" },
+      { "title": "destroy", "path": "commands/destroy" },
+      { "title": "env", "path": "commands/env" },
+      { "title": "fmt", "path": "commands/fmt" },
+      { "title": "force-unlock", "path": "commands/force-unlock" },
+      { "title": "get", "path": "commands/get" },
+      { "title": "graph", "path": "commands/graph" },
+      { "title": "import", "path": "commands/import" },
+      { "title": "init", "path": "commands/init" },
+      { "title": "login", "path": "commands/login" },
+      { "title": "logout", "path": "commands/logout" },
+      { "title": "output", "path": "commands/output" },
+      { "title": "plan", "path": "commands/plan" },
+      {
+        "title": "providers",
+        "routes": [
+          { "title": "providers", "path": "commands/providers" },
+          { "title": "providers lock", "path": "commands/providers/lock" },
+          { "title": "providers mirror", "path": "commands/providers/mirror" },
+          { "title": "providers schema", "path": "commands/providers/schema" }
+        ]
+      },
+      { "title": "push (deprecated)", "path": "commands/push" },
+      { "title": "refresh", "path": "commands/refresh" },
+      { "title": "show", "path": "commands/show" },
+      {
+        "title": "state",
+        "routes": [
+          { "title": "state", "path": "commands/state" },
+          { "title": "state list", "path": "commands/state/list" },
+          { "title": "state mv", "path": "commands/state/mv" },
+          { "title": "state pull", "path": "commands/state/pull" },
+          { "title": "state push", "path": "commands/state/push" },
+          {
+            "title": "state replace-provider",
+            "path": "commands/state/replace-provider"
+          },
+          { "title": "state rm", "path": "commands/state/rm" },
+          { "title": "state show", "path": "commands/state/show" }
+        ]
+      },
+      { "title": "taint", "path": "commands/taint" },
+      { "title": "test (deprecated)", "path": "commands/test", "hidden": true },
+      { "title": "untaint", "path": "commands/untaint" },
+      { "title": "validate", "path": "commands/validate" },
+      { "title": "version", "path": "commands/version" },
+      {
+        "title": "workspace",
+        "routes": [
+          {
+            "title": "workspace",
+            "path": "commands/workspace"
+          },
+          { "title": "workspace list", "path": "commands/workspace/list" },
+          { "title": "workspace select", "path": "commands/workspace/select" },
+          { "title": "workspace new", "path": "commands/workspace/new" },
+          { "title": "workspace delete", "path": "commands/workspace/delete" },
+          { "title": "workspace show", "path": "commands/workspace/show" }
+        ]
+      },
+      { "title": "0.12upgrade", "path": "commands/0.12upgrade" },
+      { "title": "0.13upgrade", "path": "commands/0.13upgrade" }
+    ]
+  },
+  {
+    "title": "Installation",
+    "hidden": true,
+    "routes": [
+      {
+        "title": "APT Packages for Debian and Ubuntu",
+        "path": "install/apt"
+      },
+      {
+        "title": "Yum Packages for Red Hat Enterprise Linux, Fedora, and Amazon Linux",
+        "path": "install/yum"
+      }
+    ]
+  },
+  { "divider": true },
+  { "title": "Terraform Internals", "href": "/internals" }
+]
diff --git a/v1.5.7/website/data/internals-nav-data.json b/v1.5.7/website/data/internals-nav-data.json
new file mode 100644
index 0000000..025ac6a
--- /dev/null
+++ b/v1.5.7/website/data/internals-nav-data.json
@@ -0,0 +1,65 @@
+[
+  { "heading": "Terraform Internals" },
+  {
+    "title": "Overview", 
+    "path": ""
+   },
+  {
+    "title": "Credentials Helpers",
+    "path": "credentials-helpers"
+  },
+  {
+    "title": "Debugging Terraform",
+    "path": "debugging"
+  },
+  {
+    "title": "Module Registry Protocol",
+    "path": "module-registry-protocol"
+  },
+  {
+    "title": "Provider Network Mirror Protocol",
+    "path": "provider-network-mirror-protocol"
+  },
+  {
+    "title": "Provider Registry Protocol",
+    "path": "provider-registry-protocol"
+  },
+  {
+    "title": "Resource Graph",
+    "path": "graph"
+  },
+  {
+    "title": "Login Protocol",
+    "path": "login-protocol"
+  },
+  {
+    "title": "JSON Output Format",
+    "path": "json-format"
+  },
+  {
+    "title": "Remote Service Discovery",
+    "path": "remote-service-discovery"
+  },
+  {
+    "title": "Provider Metadata",
+    "path": "provider-meta"
+  },
+  {
+    "title": "Functions Metadata",
+    "path": "functions-meta"
+  },
+  {
+    "title": "Machine Readable UI",
+    "path": "machine-readable-ui",
+    "hidden": true
+  },
+  {
+    "title": "Archiving",
+    "path": "archiving",
+    "hidden": true
+  },
+  { "divider": true },
+  { "title": "Terraform CLI", "href": "/cli" },
+  { "divider": true },
+  { "title": "Configuration Language", "href": "/language" }
+]
diff --git a/v1.5.7/website/data/intro-nav-data.json b/v1.5.7/website/data/intro-nav-data.json
new file mode 100644
index 0000000..120e29a
--- /dev/null
+++ b/v1.5.7/website/data/intro-nav-data.json
@@ -0,0 +1,24 @@
+[
+  { "heading": "Introduction to Terraform" },
+  { "title": "What is Terraform?", "path": "" },
+  { "title": "Use Cases", "path": "use-cases" },
+  {
+    "title": "Get Started",
+    "href": "https://learn.hashicorp.com/collections/terraform/aws-get-started?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS"
+  },
+  { "title": "Terraform Editions", "path": "terraform-editions" },
+  { "title": "The Core Terraform Workflow", "path": "core-workflow" },
+  {
+    "title": "Terraform vs. Alternatives",
+    "routes": [
+      { "title": "Overview", "path": "vs" },
+      { "title": "Chef, Puppet, etc.", "path": "vs/chef-puppet" },
+      {
+        "title": "CloudFormation, Heat, etc.",
+        "path": "vs/cloudformation"
+      },
+      { "title": "Boto, Fog, etc.", "path": "vs/boto" },
+      { "title": "Custom Solutions", "path": "vs/custom" }
+    ]
+  }
+]
diff --git a/v1.5.7/website/data/language-nav-data.json b/v1.5.7/website/data/language-nav-data.json
new file mode 100644
index 0000000..d96dad4
--- /dev/null
+++ b/v1.5.7/website/data/language-nav-data.json
@@ -0,0 +1,1072 @@
+[
+  { "heading": "Terraform Language" },
+  { "title": "Overview", "path": "" },
+  {
+    "title": "Attributes as Blocks - Configuration Language",
+    "path": "attr-as-blocks",
+    "hidden": true
+  },
+  {
+    "title": "Files and Directories",
+    "routes": [
+      { "title": "Overview", "path": "files" },
+      { "title": "Override Files", "path": "files/override" },
+      {
+        "title": "Dependency Lock File",
+        "path": "files/dependency-lock"
+      }
+    ]
+  },
+  {
+    "title": "Syntax",
+    "routes": [
+      { "title": "Overview", "path": "syntax" },
+      {
+        "title": "Configuration Syntax",
+        "path": "syntax/configuration"
+      },
+      {
+        "title": "JSON Configuration Syntax",
+        "path": "syntax/json"
+      },
+      { "title": "Style Conventions", "path": "syntax/style" }
+    ]
+  },
+  {
+    "title": "Resources",
+    "routes": [
+      { "title": "Overview", "path": "resources" },
+      { "title": "Resource Blocks", "path": "resources/syntax" },
+      {
+        "title": "Resource Behavior",
+        "path": "resources/behavior"
+      },
+      {
+        "title": "Meta-Arguments",
+        "routes": [
+          {
+            "title": "<code>depends_on</code>",
+            "href": "/language/meta-arguments/depends_on"
+          },
+          {
+            "title": "<code>count</code>",
+            "href": "/language/meta-arguments/count"
+          },
+          {
+            "title": "<code>for_each</code>",
+            "href": "/language/meta-arguments/for_each"
+          },
+          {
+            "title": "<code>provider</code>",
+            "href": "/language/meta-arguments/resource-provider"
+          },
+          {
+            "title": "<code>lifecycle</code>",
+            "href": "/language/meta-arguments/lifecycle"
+          }
+        ]
+      },
+      {
+        "title": "Provisioners",
+        "routes": [
+          {
+            "title": "Declaring Provisioners",
+            "path": "resources/provisioners/syntax"
+          },
+          {
+            "title": "Provisioner Connections",
+            "path": "resources/provisioners/connection"
+          },
+          {
+            "title": "Provisioners Without a Resource",
+            "path": "resources/provisioners/null_resource"
+          },
+          {
+            "title": "file",
+            "path": "resources/provisioners/file"
+          },
+          {
+            "title": "local-exec",
+            "path": "resources/provisioners/local-exec"
+          },
+          {
+            "title": "remote-exec",
+            "path": "resources/provisioners/remote-exec"
+          }
+        ]
+      },
+      {
+        "title": "The <code>terraform_data</code> Resource Type",
+        "path": "resources/terraform-data"
+      }
+    ]
+  },
+  { "title": "Data Sources", "path": "data-sources" },
+  {
+    "title": "Meta-Arguments",
+    "hidden": true,
+    "routes": [
+      {
+        "title": "<code>count</code>",
+        "path": "meta-arguments/count"
+      },
+      {
+        "title": "<code>depends_on</code>",
+        "path": "meta-arguments/depends_on"
+      },
+      {
+        "title": "<code>for_each</code>",
+        "path": "meta-arguments/for_each"
+      },
+      {
+        "title": "<code>lifecycle</code>",
+        "path": "meta-arguments/lifecycle"
+      },
+      {
+        "title": "<code>providers</code>",
+        "path": "meta-arguments/module-providers"
+      },
+      {
+        "title": "<code>provider</code>",
+        "path": "meta-arguments/resource-provider"
+      }
+    ]
+  },
+
+  {
+    "title": "Providers",
+    "routes": [
+      { "title": "Overview", "path": "providers" },
+      {
+        "title": "Provider Configuration",
+        "path": "providers/configuration"
+      },
+      {
+        "title": "Provider Requirements",
+        "path": "providers/requirements"
+      },
+      {
+        "title": "Dependency Lock File",
+        "href": "/language/files/dependency-lock"
+      }
+    ]
+  },
+  {
+    "title": "Variables and Outputs",
+    "routes": [
+      { "title": "Overview", "path": "values" },
+      { "title": "Input Variables", "path": "values/variables" },
+      { "title": "Output Values", "path": "values/outputs" },
+      { "title": "Local Values", "path": "values/locals" }
+    ]
+  },
+  {
+    "title": "Modules",
+    "routes": [
+      { "title": "Overview", "path": "modules" },
+
+      { "title": "Module Blocks", "path": "modules/syntax" },
+      { "title": "Module Sources", "path": "modules/sources" },
+      {
+        "title": "Meta-Arguments",
+        "routes": [
+          {
+            "title": "<code>providers</code>",
+            "href": "/language/meta-arguments/module-providers"
+          },
+          {
+            "title": "<code>depends_on</code>",
+            "href": "/language/meta-arguments/depends_on"
+          },
+          {
+            "title": "<code>count</code>",
+            "href": "/language/meta-arguments/count"
+          },
+          {
+            "title": "<code>for_each</code>",
+            "href": "/language/meta-arguments/for_each"
+          }
+        ]
+      },
+      {
+        "title": "Module Development",
+        "routes": [
+          { "title": "Overview", "path": "modules/develop" },
+          {
+            "title": "Standard Module Structure",
+            "path": "modules/develop/structure"
+          },
+          {
+            "title": "Providers Within Modules",
+            "path": "modules/develop/providers"
+          },
+          {
+            "title": "Best Practices: Module Composition",
+            "path": "modules/develop/composition"
+          },
+          {
+            "title": "Publishing Modules",
+            "path": "modules/develop/publish"
+          },
+          {
+            "title": "Refactoring Modules",
+            "path": "modules/develop/refactoring"
+          }
+        ]
+      },
+      {
+        "title": "Module Testing Experiment",
+        "path": "modules/testing-experiment",
+        "hidden": true
+      }
+    ]
+  },
+  { "title": "Checks", "path": "checks" },
+  {
+      "title": "Import",
+      "routes": [
+       { "title": "Overview", "path": "import" },
+       {
+         "title": "Generating Configuration",
+         "path": "import/generating-configuration"
+       }
+    ]
+  },
+  {
+    "title": "Expressions",
+    "routes": [
+      { "title": "Overview", "path": "expressions" },
+      { "title": "Types and Values", "path": "expressions/types" },
+      {
+        "title": "Strings and Templates",
+        "path": "expressions/strings"
+      },
+      {
+        "title": "References to Values",
+        "path": "expressions/references"
+      },
+      { "title": "Operators", "path": "expressions/operators" },
+      {
+        "title": "Function Calls",
+        "path": "expressions/function-calls"
+      },
+      {
+        "title": "Conditional Expressions",
+        "path": "expressions/conditionals"
+      },
+      { "title": "For Expressions", "path": "expressions/for" },
+      {
+        "title": "Splat Expressions",
+        "path": "expressions/splat"
+      },
+
+      {
+        "title": "Dynamic Blocks",
+        "path": "expressions/dynamic-blocks"
+      },
+      {
+        "title": "Custom Conditions",
+        "path": "expressions/custom-conditions"
+      },
+      {
+        "title": "Type Constraints",
+        "path": "expressions/type-constraints"
+      },
+      {
+        "title": "Version Constraints",
+        "path": "expressions/version-constraints"
+      }
+    ]
+  },
+  {
+    "title": "Functions",
+    "routes": [
+      { "title": "Overview", "path": "functions" },
+      {
+        "title": "Numeric Functions",
+        "routes": [
+          { "title": "<code>abs</code>", "href": "/language/functions/abs" },
+          { "title": "<code>ceil</code>", "href": "/language/functions/ceil" },
+          {
+            "title": "<code>floor</code>",
+            "href": "/language/functions/floor"
+          },
+          { "title": "<code>log</code>", "href": "/language/functions/log" },
+          { "title": "<code>max</code>", "href": "/language/functions/max" },
+          { "title": "<code>min</code>", "href": "/language/functions/min" },
+          {
+            "title": "<code>parseint</code>",
+            "href": "/language/functions/parseint"
+          },
+          { "title": "<code>pow</code>", "href": "/language/functions/pow" },
+          {
+            "title": "<code>signum</code>",
+            "href": "/language/functions/signum"
+          }
+        ]
+      },
+      {
+        "title": "String Functions",
+        "routes": [
+          {
+            "title": "<code>chomp</code>",
+            "href": "/language/functions/chomp"
+          },
+          {
+            "title": "<code>endswith</code>",
+            "href": "/language/functions/endswith"
+          },
+          {
+            "title": "<code>format</code>",
+            "href": "/language/functions/format"
+          },
+          {
+            "title": "<code>formatlist</code>",
+            "href": "/language/functions/formatlist"
+          },
+          {
+            "title": "<code>indent</code>",
+            "href": "/language/functions/indent"
+          },
+          { "title": "<code>join</code>", "href": "/language/functions/join" },
+          {
+            "title": "<code>lower</code>",
+            "href": "/language/functions/lower"
+          },
+          {
+            "title": "<code>regex</code>",
+            "href": "/language/functions/regex"
+          },
+          {
+            "title": "<code>regexall</code>",
+            "href": "/language/functions/regexall"
+          },
+          {
+            "title": "<code>replace</code>",
+            "href": "/language/functions/replace"
+          },
+          {
+            "title": "<code>split</code>",
+            "href": "/language/functions/split"
+          },
+          {
+            "title": "<code>startswith</code>",
+            "href": "/language/functions/startswith"
+          },
+          {
+            "title": "<code>strcontains</code>",
+            "href": "/language/functions/strcontains"
+          },
+          {
+            "title": "<code>strrev</code>",
+            "href": "/language/functions/strrev"
+          },
+          {
+            "title": "<code>substr</code>",
+            "href": "/language/functions/substr"
+          },
+          {
+            "title": "<code>title</code>",
+            "href": "/language/functions/title"
+          },
+          { "title": "<code>trim</code>", "href": "/language/functions/trim" },
+          {
+            "title": "<code>trimprefix</code>",
+            "href": "/language/functions/trimprefix"
+          },
+          {
+            "title": "<code>trimsuffix</code>",
+            "href": "/language/functions/trimsuffix"
+          },
+          {
+            "title": "<code>trimspace</code>",
+            "href": "/language/functions/trimspace"
+          },
+          { "title": "<code>upper</code>", "href": "/language/functions/upper" }
+        ]
+      },
+      {
+        "title": "Collection Functions",
+        "routes": [
+          {
+            "title": "<code>alltrue</code>",
+            "href": "/language/functions/alltrue"
+          },
+          {
+            "title": "<code>anytrue</code>",
+            "href": "/language/functions/anytrue"
+          },
+          {
+            "title": "<code>chunklist</code>",
+            "href": "/language/functions/chunklist"
+          },
+          {
+            "title": "<code>coalesce</code>",
+            "href": "/language/functions/coalesce"
+          },
+          {
+            "title": "<code>coalescelist</code>",
+            "href": "/language/functions/coalescelist"
+          },
+          {
+            "title": "<code>compact</code>",
+            "href": "/language/functions/compact"
+          },
+          {
+            "title": "<code>concat</code>",
+            "href": "/language/functions/concat"
+          },
+          {
+            "title": "<code>contains</code>",
+            "href": "/language/functions/contains"
+          },
+          {
+            "title": "<code>distinct</code>",
+            "href": "/language/functions/distinct"
+          },
+          {
+            "title": "<code>element</code>",
+            "href": "/language/functions/element"
+          },
+          {
+            "title": "<code>flatten</code>",
+            "href": "/language/functions/flatten"
+          },
+          {
+            "title": "<code>index</code>",
+            "href": "/language/functions/index_function"
+          },
+          { "title": "<code>keys</code>", "href": "/language/functions/keys" },
+          {
+            "title": "<code>length</code>",
+            "href": "/language/functions/length"
+          },
+          { "title": "<code>list</code>", "href": "/language/functions/list" },
+          {
+            "title": "<code>lookup</code>",
+            "href": "/language/functions/lookup"
+          },
+          { "title": "<code>map</code>", "href": "/language/functions/map" },
+          {
+            "title": "<code>matchkeys</code>",
+            "href": "/language/functions/matchkeys"
+          },
+          {
+            "title": "<code>merge</code>",
+            "href": "/language/functions/merge"
+          },
+          { "title": "<code>one</code>", "href": "/language/functions/one" },
+          {
+            "title": "<code>range</code>",
+            "href": "/language/functions/range"
+          },
+          {
+            "title": "<code>reverse</code>",
+            "href": "/language/functions/reverse"
+          },
+          {
+            "title": "<code>setintersection</code>",
+            "href": "/language/functions/setintersection"
+          },
+          {
+            "title": "<code>setproduct</code>",
+            "href": "/language/functions/setproduct"
+          },
+          {
+            "title": "<code>setsubtract</code>",
+            "href": "/language/functions/setsubtract"
+          },
+          {
+            "title": "<code>setunion</code>",
+            "href": "/language/functions/setunion"
+          },
+          {
+            "title": "<code>slice</code>",
+            "href": "/language/functions/slice"
+          },
+          { "title": "<code>sort</code>", "href": "/language/functions/sort" },
+          { "title": "<code>sum</code>", "href": "/language/functions/sum" },
+          {
+            "title": "<code>transpose</code>",
+            "href": "/language/functions/transpose"
+          },
+          {
+            "title": "<code>values</code>",
+            "href": "/language/functions/values"
+          },
+          {
+            "title": "<code>zipmap</code>",
+            "href": "/language/functions/zipmap"
+          }
+        ]
+      },
+      {
+        "title": "Encoding Functions",
+        "routes": [
+          {
+            "title": "<code>base64decode</code>",
+            "href": "/language/functions/base64decode"
+          },
+          {
+            "title": "<code>base64encode</code>",
+            "href": "/language/functions/base64encode"
+          },
+          {
+            "title": "<code>base64gzip</code>",
+            "href": "/language/functions/base64gzip"
+          },
+          {
+            "title": "<code>csvdecode</code>",
+            "href": "/language/functions/csvdecode"
+          },
+          {
+            "title": "<code>jsondecode</code>",
+            "href": "/language/functions/jsondecode"
+          },
+          {
+            "title": "<code>jsonencode</code>",
+            "href": "/language/functions/jsonencode"
+          },
+          {
+            "title": "<code>textdecodebase64</code>",
+            "href": "/language/functions/textdecodebase64"
+          },
+          {
+            "title": "<code>textencodebase64</code>",
+            "href": "/language/functions/textencodebase64"
+          },
+          {
+            "title": "<code>urlencode</code>",
+            "href": "/language/functions/urlencode"
+          },
+          {
+            "title": "<code>yamldecode</code>",
+            "href": "/language/functions/yamldecode"
+          },
+          {
+            "title": "<code>yamlencode</code>",
+            "href": "/language/functions/yamlencode"
+          }
+        ]
+      },
+      {
+        "title": "Filesystem Functions",
+        "routes": [
+          {
+            "title": "<code>abspath</code>",
+            "href": "/language/functions/abspath"
+          },
+          {
+            "title": "<code>dirname</code>",
+            "href": "/language/functions/dirname"
+          },
+          {
+            "title": "<code>pathexpand</code>",
+            "href": "/language/functions/pathexpand"
+          },
+          {
+            "title": "<code>basename</code>",
+            "href": "/language/functions/basename"
+          },
+          { "title": "<code>file</code>", "href": "/language/functions/file" },
+          {
+            "title": "<code>fileexists</code>",
+            "href": "/language/functions/fileexists"
+          },
+          {
+            "title": "<code>fileset</code>",
+            "href": "/language/functions/fileset"
+          },
+          {
+            "title": "<code>filebase64</code>",
+            "href": "/language/functions/filebase64"
+          },
+          {
+            "title": "<code>templatefile</code>",
+            "href": "/language/functions/templatefile"
+          }
+        ]
+      },
+      {
+        "title": "Date and Time Functions",
+        "routes": [
+          {
+            "title": "<code>formatdate</code>",
+            "href": "/language/functions/formatdate"
+          },
+          {
+            "title": "<code>plantimestamp</code>",
+            "href": "/language/functions/plantimestamp"
+          },
+          {
+            "title": "<code>timeadd</code>",
+            "href": "/language/functions/timeadd"
+          },
+          {
+            "title": "<code>timecmp</code>",
+            "href": "/language/functions/timecmp"
+          },
+          {
+            "title": "<code>timestamp</code>",
+            "href": "/language/functions/timestamp"
+          }
+        ]
+      },
+      {
+        "title": "Hash and Crypto Functions",
+        "routes": [
+          {
+            "title": "<code>base64sha256</code>",
+            "href": "/language/functions/base64sha256"
+          },
+          {
+            "title": "<code>base64sha512</code>",
+            "href": "/language/functions/base64sha512"
+          },
+          {
+            "title": "<code>bcrypt</code>",
+            "href": "/language/functions/bcrypt"
+          },
+          {
+            "title": "<code>filebase64sha256</code>",
+            "href": "/language/functions/filebase64sha256"
+          },
+          {
+            "title": "<code>filebase64sha512</code>",
+            "href": "/language/functions/filebase64sha512"
+          },
+          {
+            "title": "<code>filemd5</code>",
+            "href": "/language/functions/filemd5"
+          },
+          {
+            "title": "<code>filesha1</code>",
+            "href": "/language/functions/filesha1"
+          },
+          {
+            "title": "<code>filesha256</code>",
+            "href": "/language/functions/filesha256"
+          },
+          {
+            "title": "<code>filesha512</code>",
+            "href": "/language/functions/filesha512"
+          },
+          { "title": "<code>md5</code>", "href": "/language/functions/md5" },
+          {
+            "title": "<code>rsadecrypt</code>",
+            "href": "/language/functions/rsadecrypt"
+          },
+          { "title": "<code>sha1</code>", "href": "/language/functions/sha1" },
+          {
+            "title": "<code>sha256</code>",
+            "href": "/language/functions/sha256"
+          },
+          {
+            "title": "<code>sha512</code>",
+            "href": "/language/functions/sha512"
+          },
+          { "title": "<code>uuid</code>", "href": "/language/functions/uuid" },
+          {
+            "title": "<code>uuidv5</code>",
+            "href": "/language/functions/uuidv5"
+          }
+        ]
+      },
+      {
+        "title": "IP Network Functions",
+        "routes": [
+          {
+            "title": "<code>cidrhost</code>",
+            "href": "/language/functions/cidrhost"
+          },
+          {
+            "title": "<code>cidrnetmask</code>",
+            "href": "/language/functions/cidrnetmask"
+          },
+          {
+            "title": "<code>cidrsubnet</code>",
+            "href": "/language/functions/cidrsubnet"
+          },
+          {
+            "title": "<code>cidrsubnets</code>",
+            "href": "/language/functions/cidrsubnets"
+          }
+        ]
+      },
+      {
+        "title": "Type Conversion Functions",
+        "routes": [
+          { "title": "<code>can</code>", "href": "/language/functions/can" },
+          {
+            "title": "<code>nonsensitive</code>",
+            "href": "/language/functions/nonsensitive"
+          },
+          {
+            "title": "<code>sensitive</code>",
+            "href": "/language/functions/sensitive"
+          },
+          {
+            "title": "<code>tobool</code>",
+            "href": "/language/functions/tobool"
+          },
+          {
+            "title": "<code>tolist</code>",
+            "href": "/language/functions/tolist"
+          },
+          {
+            "title": "<code>tomap</code>",
+            "href": "/language/functions/tomap"
+          },
+          {
+            "title": "<code>tonumber</code>",
+            "href": "/language/functions/tonumber"
+          },
+          {
+            "title": "<code>toset</code>",
+            "href": "/language/functions/toset"
+          },
+          {
+            "title": "<code>tostring</code>",
+            "href": "/language/functions/tostring"
+          },
+          { "title": "<code>try</code>", "href": "/language/functions/try" },
+          { "title": "<code>type</code>", "href": "/language/functions/type" }
+        ]
+      },
+      { "title": "abs", "path": "functions/abs", "hidden": true },
+      { "title": "abspath", "path": "functions/abspath", "hidden": true },
+      { "title": "alltrue", "path": "functions/alltrue", "hidden": true },
+      { "title": "anytrue", "path": "functions/anytrue", "hidden": true },
+      {
+        "title": "base64decode",
+        "path": "functions/base64decode",
+        "hidden": true
+      },
+      {
+        "title": "base64encode",
+        "path": "functions/base64encode",
+        "hidden": true
+      },
+      { "title": "base64gzip", "path": "functions/base64gzip", "hidden": true },
+      {
+        "title": "base64sha256",
+        "path": "functions/base64sha256",
+        "hidden": true
+      },
+      {
+        "title": "base64sha512",
+        "path": "functions/base64sha512",
+        "hidden": true
+      },
+      { "title": "basename", "path": "functions/basename", "hidden": true },
+      { "title": "bcrypt", "path": "functions/bcrypt", "hidden": true },
+      { "title": "can", "path": "functions/can", "hidden": true },
+      { "title": "ceil", "path": "functions/ceil", "hidden": true },
+      { "title": "chomp", "path": "functions/chomp", "hidden": true },
+      { "title": "chunklist", "path": "functions/chunklist", "hidden": true },
+      { "title": "cidrhost", "path": "functions/cidrhost", "hidden": true },
+      {
+        "title": "cidrnetmask",
+        "path": "functions/cidrnetmask",
+        "hidden": true
+      },
+      { "title": "cidrsubnet", "path": "functions/cidrsubnet", "hidden": true },
+      {
+        "title": "cidrsubnets",
+        "path": "functions/cidrsubnets",
+        "hidden": true
+      },
+      { "title": "coalesce", "path": "functions/coalesce", "hidden": true },
+      {
+        "title": "coalescelist",
+        "path": "functions/coalescelist",
+        "hidden": true
+      },
+      { "title": "compact", "path": "functions/compact", "hidden": true },
+      { "title": "concat", "path": "functions/concat", "hidden": true },
+      { "title": "contains", "path": "functions/contains", "hidden": true },
+      { "title": "csvdecode", "path": "functions/csvdecode", "hidden": true },
+      { "title": "dirname", "path": "functions/dirname", "hidden": true },
+      { "title": "distinct", "path": "functions/distinct", "hidden": true },
+      { "title": "element", "path": "functions/element", "hidden": true },
+      { "title": "endswith", "path": "functions/endswith", "hidden": true },
+      { "title": "file", "path": "functions/file", "hidden": true },
+      { "title": "filebase64", "path": "functions/filebase64", "hidden": true },
+      {
+        "title": "filebase64sha256",
+        "path": "functions/filebase64sha256",
+        "hidden": true
+      },
+      {
+        "title": "filebase64sha512",
+        "path": "functions/filebase64sha512",
+        "hidden": true
+      },
+      { "title": "fileexists", "path": "functions/fileexists", "hidden": true },
+      { "title": "filemd5", "path": "functions/filemd5", "hidden": true },
+      { "title": "fileset", "path": "functions/fileset", "hidden": true },
+      { "title": "filesha1", "path": "functions/filesha1", "hidden": true },
+      { "title": "filesha256", "path": "functions/filesha256", "hidden": true },
+      { "title": "filesha512", "path": "functions/filesha512", "hidden": true },
+      { "title": "flatten", "path": "functions/flatten", "hidden": true },
+      { "title": "floor", "path": "functions/floor", "hidden": true },
+      { "title": "format", "path": "functions/format", "hidden": true },
+      { "title": "formatdate", "path": "functions/formatdate", "hidden": true },
+      { "title": "formatlist", "path": "functions/formatlist", "hidden": true },
+      { "title": "indent", "path": "functions/indent", "hidden": true },
+      { "title": "index", "path": "functions/index_function", "hidden": true },
+      { "title": "join", "path": "functions/join", "hidden": true },
+      { "title": "jsondecode", "path": "functions/jsondecode", "hidden": true },
+      { "title": "jsonencode", "path": "functions/jsonencode", "hidden": true },
+      { "title": "keys", "path": "functions/keys", "hidden": true },
+      { "title": "length", "path": "functions/length", "hidden": true },
+      { "title": "list", "path": "functions/list", "hidden": true },
+      { "title": "log", "path": "functions/log", "hidden": true },
+      { "title": "lookup", "path": "functions/lookup", "hidden": true },
+      { "title": "lower", "path": "functions/lower", "hidden": true },
+      { "title": "map", "path": "functions/map", "hidden": true },
+      { "title": "matchkeys", "path": "functions/matchkeys", "hidden": true },
+      { "title": "max", "path": "functions/max", "hidden": true },
+      { "title": "md5", "path": "functions/md5", "hidden": true },
+      { "title": "merge", "path": "functions/merge", "hidden": true },
+      { "title": "min", "path": "functions/min", "hidden": true },
+      {
+        "title": "nonsensitive",
+        "path": "functions/nonsensitive",
+        "hidden": true
+      },
+      { "title": "one", "path": "functions/one", "hidden": true },
+      { "title": "parseint", "path": "functions/parseint", "hidden": true },
+      { "title": "pathexpand", "path": "functions/pathexpand", "hidden": true },
+      { "title": "plantimestamp", "path": "functions/plantimestamp", "hidden": true },
+      { "title": "pow", "path": "functions/pow", "hidden": true },
+      { "title": "range", "path": "functions/range", "hidden": true },
+      { "title": "regex", "path": "functions/regex", "hidden": true },
+      { "title": "regexall", "path": "functions/regexall", "hidden": true },
+      { "title": "replace", "path": "functions/replace", "hidden": true },
+      { "title": "reverse", "path": "functions/reverse", "hidden": true },
+      { "title": "rsadecrypt", "path": "functions/rsadecrypt", "hidden": true },
+      { "title": "sensitive", "path": "functions/sensitive", "hidden": true },
+      {
+        "title": "setintersection",
+        "path": "functions/setintersection",
+        "hidden": true
+      },
+      { "title": "setproduct", "path": "functions/setproduct", "hidden": true },
+      {
+        "title": "setsubtract",
+        "path": "functions/setsubtract",
+        "hidden": true
+      },
+      { "title": "setunion", "path": "functions/setunion", "hidden": true },
+      { "title": "sha1", "path": "functions/sha1", "hidden": true },
+      { "title": "sha256", "path": "functions/sha256", "hidden": true },
+      { "title": "sha512", "path": "functions/sha512", "hidden": true },
+      { "title": "signum", "path": "functions/signum", "hidden": true },
+      { "title": "slice", "path": "functions/slice", "hidden": true },
+      { "title": "sort", "path": "functions/sort", "hidden": true },
+      { "title": "split", "path": "functions/split", "hidden": true },
+      { "title": "startswith", "path": "functions/startswith", "hidden": true },
+      { "title": "strcontains", "path": "functions/strcontains", "hidden": true},
+      { "title": "strrev", "path": "functions/strrev", "hidden": true },
+      { "title": "substr", "path": "functions/substr", "hidden": true },
+      { "title": "sum", "path": "functions/sum", "hidden": true },
+      {
+        "title": "templatefile",
+        "path": "functions/templatefile",
+        "hidden": true
+      },
+      {
+        "title": "textdecodebase64",
+        "path": "functions/textdecodebase64",
+        "hidden": true
+      },
+      {
+        "title": "textencodebase64",
+        "path": "functions/textencodebase64",
+        "hidden": true
+      },
+      { "title": "timeadd", "path": "functions/timeadd", "hidden": true },
+      { "title": "timecmp", "path": "functions/timecmp", "hidden": true },
+      { "title": "timestamp", "path": "functions/timestamp", "hidden": true },
+      { "title": "title", "path": "functions/title", "hidden": true },
+      { "title": "tobool", "path": "functions/tobool", "hidden": true },
+      { "title": "tolist", "path": "functions/tolist", "hidden": true },
+      { "title": "tomap", "path": "functions/tomap", "hidden": true },
+      { "title": "tonumber", "path": "functions/tonumber", "hidden": true },
+      { "title": "toset", "path": "functions/toset", "hidden": true },
+      { "title": "tostring", "path": "functions/tostring", "hidden": true },
+      { "title": "transpose", "path": "functions/transpose", "hidden": true },
+      { "title": "trim", "path": "functions/trim", "hidden": true },
+      { "title": "trimprefix", "path": "functions/trimprefix", "hidden": true },
+      { "title": "trimspace", "path": "functions/trimspace", "hidden": true },
+      { "title": "trimsuffix", "path": "functions/trimsuffix", "hidden": true },
+      { "title": "try", "path": "functions/try", "hidden": true },
+      { "title": "type", "path": "functions/type", "hidden": true },
+      { "title": "upper", "path": "functions/upper", "hidden": true },
+      { "title": "urlencode", "path": "functions/urlencode", "hidden": true },
+      { "title": "uuid", "path": "functions/uuid", "hidden": true },
+      { "title": "uuidv5", "path": "functions/uuidv5", "hidden": true },
+      { "title": "values", "path": "functions/values", "hidden": true },
+      { "title": "yamldecode", "path": "functions/yamldecode", "hidden": true },
+      { "title": "yamlencode", "path": "functions/yamlencode", "hidden": true },
+      { "title": "zipmap", "path": "functions/zipmap", "hidden": true }
+    ]
+  },
+  {
+    "title": "Terraform Settings",
+    "routes": [
+      { "title": "Overview", "path": "settings" },
+      { "title": "Terraform Cloud", "path": "settings/terraform-cloud" },
+      {
+        "title": "Backends",
+        "routes": [
+          {
+            "title": "Backend Configuration",
+            "path": "settings/backends/configuration"
+          },
+          {
+            "title": "Available Backends",
+            "routes": [
+              {
+                "title": "local",
+                "href": "/language/settings/backends/local"
+              },
+              {
+                "title": "remote",
+                "href": "/language/settings/backends/remote"
+              },
+              {
+                "title": "azurerm",
+                "href": "/language/settings/backends/azurerm"
+              },
+              {
+                "title": "consul",
+                "href": "/language/settings/backends/consul"
+              },
+              {
+                "title": "cos",
+                "href": "/language/settings/backends/cos"
+              },
+              {
+                "title": "gcs",
+                "href": "/language/settings/backends/gcs"
+              },
+              {
+                "title": "http",
+                "href": "/language/settings/backends/http"
+              },
+              {
+                "title": "Kubernetes",
+                "href": "/language/settings/backends/kubernetes"
+              },
+              {
+                "title": "oss",
+                "href": "/language/settings/backends/oss"
+              },
+              {
+                "title": "pg",
+                "href": "/language/settings/backends/pg"
+              },
+              {
+                "title": "s3",
+                "href": "/language/settings/backends/s3"
+              }
+            ]
+          },
+          {
+            "title": "local",
+            "hidden": true,
+            "path": "settings/backends/local"
+          },
+          {
+            "title": "remote",
+            "hidden": true,
+            "path": "settings/backends/remote"
+          },
+          {
+            "title": "azurerm",
+            "hidden": true,
+            "path": "settings/backends/azurerm"
+          },
+          {
+            "title": "consul",
+            "hidden": true,
+            "path": "settings/backends/consul"
+          },
+          {
+            "title": "cos",
+            "hidden": true,
+            "path": "settings/backends/cos"
+          },
+          {
+            "title": "gcs",
+            "hidden": true,
+            "path": "settings/backends/gcs"
+          },
+          {
+            "title": "http",
+            "hidden": true,
+            "path": "settings/backends/http"
+          },
+          {
+            "title": "Kubernetes",
+            "hidden": true,
+            "path": "settings/backends/kubernetes"
+          },
+          {
+            "title": "oss",
+            "hidden": true,
+            "path": "settings/backends/oss"
+          },
+          {
+            "title": "pg",
+            "hidden": true,
+            "path": "settings/backends/pg"
+          },
+          {
+            "title": "s3",
+            "hidden": true,
+            "path": "settings/backends/s3"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "title": "State",
+    "routes": [
+      { "title": "Overview", "path": "state" },
+      { "title": "Purpose", "path": "state/purpose" },
+      {
+        "title": "The <code>terraform_remote_state</code> Data Source",
+        "path": "state/remote-state-data"
+      },
+      {
+        "title": "Backends: State Storage and Locking",
+        "path": "state/backends"
+      },
+      {
+        "title": "Import Existing Resources",
+        "path": "state/import"
+      },
+      { "title": "Locking", "path": "state/locking" },
+      { "title": "Workspaces", "path": "state/workspaces" },
+      { "title": "Remote State", "path": "state/remote" },
+      {
+        "title": "Sensitive Data",
+        "path": "state/sensitive-data"
+      }
+    ]
+  },
+  {
+    "title": "Upgrading to Terraform v1.5",
+    "path": "upgrade-guides"
+  },
+  {
+    "title": "v1.x Compatibility Promises",
+    "path": "v1-compatibility-promises"
+  },
+  { "divider": true },
+  { "title": "Terraform Internals", "href": "/internals" }
+]
diff --git a/v1.5.7/website/docs/cli/auth/index.mdx b/v1.5.7/website/docs/cli/auth/index.mdx
new file mode 100644
index 0000000..f283418
--- /dev/null
+++ b/v1.5.7/website/docs/cli/auth/index.mdx
@@ -0,0 +1,31 @@
+---
+page_title: Authentication - Terraform CLI
+description: >-
+  Documentation about the login and logout commands that help automate getting
+  an API token for your Terraform Cloud account.
+---
+
+# CLI Authentication
+
+> **Hands-on:** Try the [Authenticate the CLI with Terraform Cloud](/terraform/tutorials/cloud/cloud-login?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+[Terraform Cloud](https://cloud.hashicorp.com/products/terraform) and
+[Terraform Enterprise](/terraform/enterprise) are platforms that perform
+Terraform runs to provision infrastructure, offering a collaboration-focused
+environment that makes it easier for teams to use Terraform together. (For
+expediency, the content below refers to both products as "Terraform Cloud.")
+
+Terraform CLI integrates with Terraform Cloud in several ways — it can be a
+front-end for [CLI-driven runs](/terraform/cloud-docs/run/cli) in Terraform Cloud,
+and can also use Terraform Cloud as a state backend and a private module
+registry. All of these integrations require you to authenticate Terraform CLI
+with your Terraform Cloud account.
+
+The best way to handle CLI authentication is with the `login` and `logout`
+commands, which help automate the process of getting an API token for your
+Terraform Cloud user account.
+
+For details, see:
+
+- [The `terraform login` command](/terraform/cli/commands/login)
+- [The `terraform logout` command](/terraform/cli/commands/logout)
diff --git a/v1.5.7/website/docs/cli/cloud/command-line-arguments.mdx b/v1.5.7/website/docs/cli/cloud/command-line-arguments.mdx
new file mode 100644
index 0000000..81897cf
--- /dev/null
+++ b/v1.5.7/website/docs/cli/cloud/command-line-arguments.mdx
@@ -0,0 +1,24 @@
+---
+page_title: Command Line Arguments
+description: Command Line Arguments
+---
+
+# Command Line Arguments
+
+When your configuration includes a `cloud` block, commands that
+make local modifications to Terraform state and then push them back up to the remote workspace
+accept the following option to modify that behavior:
+
+- `-ignore-remote-version` - Override checking that the local and remote
+  Terraform versions agree, making an operation proceed even when there is
+  a mismatch.
+
+  State-modification operations usually require using a local version of the
+  Terraform CLI that is compatible with the Terraform version selected
+  in the remote workspace settings. This prevents the
+  local operation from creating a new state snapshot that the workspace's
+  remote execution environment cannot decode.
+
+  We recommend against using this option unless absolutely necessary. Overriding this check can result
+  in a Terraform Cloud workspace that is no longer able to complete remote operations with the currently
+  selected version of Terraform.
diff --git a/v1.5.7/website/docs/cli/cloud/index.mdx b/v1.5.7/website/docs/cli/cloud/index.mdx
new file mode 100644
index 0000000..51136e4
--- /dev/null
+++ b/v1.5.7/website/docs/cli/cloud/index.mdx
@@ -0,0 +1,27 @@
+---
+page_title: Using Terraform Cloud - Terraform CLI
+description: >-
+  Learn how to use Terraform Cloud and Terraform Enterprise on the command line with the Terraform CLI.
+---
+
+# Using Terraform Cloud with Terraform CLI
+
+The Terraform CLI integration with Terraform Cloud lets you use Terraform Cloud and Terraform Enterprise on the command line. In the documentation Terraform Cloud instructions also apply to Terraform Enterprise, except where explicitly stated.
+
+Using Terraform Cloud through the command line is called the [CLI-driven run workflow](/terraform/cloud-docs/run/cli). When you use the CLI workflow, operations like `terraform plan` or `terraform apply` are remotely executed in Terraform Cloud's run environment by default, with log output streaming to the local terminal. This lets you use Terraform Cloud features within the familiar Terraform CLI workflow, including variables encrypted at rest in a Terraform Cloud workspace, cost estimates, and policy checking.
+
+> **Hands On:** Try the [Migrate State to Terraform Cloud](/terraform/tutorials/cloud/cloud-migrate) tutorial.
+
+Workspaces can also be configured for local execution, in which case Terraform Cloud only stores state. In this mode, Terraform Cloud behaves just like a standard state backend.
+
+-> **Note:** The CLI integration is available in Terraform 1.1.0 and later, and Terraform Enterprise 202201-1 and later. Previous versions can use the [`remote` backend](/terraform/language/settings/backends/remote). Refer to [Migrating from the remote
+backend](/terraform/cli/cloud/migrating) for details about switching to the CLI integration.
+
+## Documentation Summary
+
+- [Terraform Cloud Settings](/terraform/cli/cloud/settings) documents the `cloud` block that you must add to your configuration to enable Terraform Cloud support.
+- [Initializing and Migrating](/terraform/cli/cloud/migrating) describes
+  how to start using Terraform Cloud with a working directory that already has state data.
+- [Command Line Arguments](/terraform/cli/cloud/command-line-arguments) lists the Terraform command flags that are specific to using Terraform with Terraform Cloud.
+
+Refer to the [CLI-driven Run Workflow](/terraform/cloud-docs/run/cli) for more details about how to use Terraform Cloud from the command line.
diff --git a/v1.5.7/website/docs/cli/cloud/migrating.mdx b/v1.5.7/website/docs/cli/cloud/migrating.mdx
new file mode 100644
index 0000000..118fd60
--- /dev/null
+++ b/v1.5.7/website/docs/cli/cloud/migrating.mdx
@@ -0,0 +1,88 @@
+---
+page_title: Initializing and Migrating to Terraform Cloud - Terraform CLI
+description: >-
+  Learn how to use the Terraform CLI to migrate local or remote state to Terraform Cloud.
+---
+
+# Initializing and Migrating
+
+After [configuring Terraform Cloud settings](/terraform/cli/cloud/settings) for a working directory, you must run `terraform init` to finish setting up. If the working directory has no existing Terraform state, you can start using Terraform with Terraform Cloud right away. Refer to [CLI-driven run workflow](/terraform/cloud-docs/run/cli) for more details.
+
+When you run `terraform init` in the following scenarios, Terraform will ask you to choose whether or not to migrate state from any existing workspaces.
+
+1. [**Migrating from local state or state backends:**](#migrating-from-local-state-or-state-backends) If the working directory already has state data in one or more workspaces, Terraform will ask if you would like to migrate that state to new Terraform Cloud workspaces.
+
+1. [**Migrating from the `remote` backend:**](#migrating-from-the-remote-backend) If the working directory was already connected to Terraform Cloud with the `remote` backend, Terraform can continue using the same Terraform Cloud workspaces. You will need to switch the `remote` backend block to the `cloud` block.
+
+## Migrating from Local State or State Backends
+
+> **Hands On:** Try the [Migrate State to Terraform Cloud](/terraform/tutorials/cloud/cloud-migrate) tutorial.
+
+If the working directory already has state data available (using either local state or a [state
+backend](/terraform/language/settings/backends/configuration)), Terraform asks your approval to migrate
+that state to Terraform Cloud. You will need permission to manage workspaces in the destination Terraform Cloud organization. This process is interactive and self-documenting, and resembles
+moving between state backends.
+
+Terraform may also prompt you to rename your workspaces during the migration, to either give a name to
+the unnamed `default` workspace (Terraform Cloud requires all workspaces to have a name) or give
+your workspace names more contextual information. Unlike Terraform CLI-only workspaces, which represent
+multiple environments associated with the same configuration (e.g. production, staging, development),
+Terraform Cloud workspaces can represent totally independent configurations, and must have unique names within the Terraform Cloud organization.
+
+Because of this, Terraform will prompt you to rename the working directory's workspaces
+according to a pattern relative to their existing names. This can indicate the fact that these specific workspaces share configuration. A typical strategy is
+`<COMPONENT>-<ENVIRONMENT>-<REGION>` (e.g.,  `networking-prod-us-east`,
+`networking-staging-us-east`). Refer to [Workspace
+Naming](/terraform/cloud-docs/workspaces/naming) in the Terraform Cloud documentation for more detail.
+
+## Migrating from the `remote` Backend
+
+If the working directory was already connected to Terraform Cloud with the `remote` backend, Terraform can continue using the same Terraform Cloud workspaces. The local names shown for those workspaces will change to match their remote names.
+
+The [`remote` backend](/terraform/language/settings/backends/remote) was the primary implementation of Terraform Cloud's [CLI-driven run workflow](/terraform/cloud-docs/run/cli) for Terraform versions 0.11.13 through 1.0.x. We recommend using the native `cloud` integration for Terraform versions 1.1 or later, as it provides an improved user experience and various enhancements.
+
+### Block Replacement
+
+When switching from the `remote` backend to a `cloud` block, Terraform will continue using the same
+set of Terraform Cloud workspaces. Replace your `backend "remote"` block with an equivalent `cloud`
+block.
+
+#### Single Workspace
+
+If you were using a single workspace with the `name` argument, change the block
+label to `cloud`.
+
+```diff
+terraform {
+-  backend "remote" {
++  cloud {
+    organization = "my-org"
+
+    workspaces {
+    name = "my-app-prod"
+    }
+   }
+ }
+```
+
+#### Multiple Workspaces
+
+If you were using multiple workspaces with the `prefix` argument, replace it with a `cloud` block that uses the `tags` argument. You may specify any number of tags to distinguish the workspaces for your working directory, but a good starting point may be to use whatever the prefix was before.
+
+The tags you configure do not need to be present on the existing workspaces. When you initialize, Terraform will add the specified tags to the workspaces if necessary.
+
+```diff
+terraform {
+-  backend "remote" {
++  cloud {
+     organization = "my-org"
+
+    workspaces {
+-      prefix = "my-app-"
++      tags = ["app:mine"]
+    }
+   }
+ }
+```
+
+~> **Warning**: Because the `cloud` block does not support the `prefix` argument, once you migrate, you must refer to workspaces by their full name when using the Terraform CLI. For example, rather than `terraform workspace select prod`, you must run the command `terraform workspace select my-app-prod`.
diff --git a/v1.5.7/website/docs/cli/cloud/settings.mdx b/v1.5.7/website/docs/cli/cloud/settings.mdx
new file mode 100644
index 0000000..98b16ec
--- /dev/null
+++ b/v1.5.7/website/docs/cli/cloud/settings.mdx
@@ -0,0 +1,121 @@
+---
+page_title: Terraform Cloud Settings - Terraform CLI
+description: >-
+  Configure the Terraform Cloud CLI integration.
+---
+
+# Terraform Cloud Settings
+
+Terraform CLI can integrate with Terraform Cloud, acting as a client for Terraform Cloud's
+[CLI-driven run workflow](/terraform/cloud-docs/run/cli).
+
+> **Hands On:** Try the [Migrate State to Terraform Cloud](/terraform/tutorials/cloud/cloud-migrate) tutorial.
+
+You must configure the following settings to use Terraform Cloud for a particular working directory:
+
+- Provide credentials to access Terraform Cloud, preferably by using the
+  [`terraform login`](/terraform/cli/commands/login) command.
+- Add a `cloud` block to the directory's Terraform configuration, to specify
+  which organization and workspace(s) to use.
+- Optionally, use a `.terraformignore` file to specify files that shouldn't be
+  uploaded with the Terraform configuration when running plans and applies.
+
+After adding or changing a `cloud` block, you must run `terraform init`.
+
+## The `cloud` Block
+
+The `cloud` block is a nested block within the top-level `terraform` settings
+block. It specifies which Terraform Cloud workspaces to use for the current
+working directory.
+
+```hcl
+terraform {
+  cloud {
+    organization = "my-org"
+    hostname = "app.terraform.io" # Optional; defaults to app.terraform.io
+
+    workspaces {
+      tags = ["networking", "source:cli"]
+    }
+  }
+}
+```
+
+The `cloud` block also has some special restrictions:
+
+- A configuration can only provide one `cloud` block.
+- A `cloud` block cannot be used with [state backends](/terraform/language/settings/backends/configuration).
+  A configuration can use one or the other, but not both.
+- A `cloud` block cannot refer to named values (like input variables, locals, or
+  data source attributes).
+
+The `cloud` block only affects Terraform CLI's behavior. When Terraform Cloud uses a configuration
+that contains a cloud block - for example, when a workspace is configured to use a VCS provider
+directly - it ignores the block and behaves according to its own workspace settings.
+
+### Arguments
+
+The `cloud` block supports the following configuration arguments:
+
+- `organization` - (Required) The name of the organization containing the
+  workspace(s) the current configuration should use.
+
+- `workspaces` - (Required) A nested block that specifies which remote Terraform Cloud workspaces to
+  use for the current configuration. The `workspaces` block must contain **exactly one** of the
+  following arguments, each denoting a strategy for how workspaces should be mapped:
+
+  - `tags` - (Optional) A set of Terraform Cloud workspace tags. You will be able to use
+    this working directory with any workspaces that have all of the specified tags,
+    and can use [the `terraform workspace` commands](/terraform/cli/workspaces)
+    to switch between them or create new workspaces. New workspaces will automatically have
+    the specified tags. This option conflicts with `name`.
+
+  - `name` - (Optional) The name of a single Terraform Cloud workspace. You will
+    only be able to use the workspace specified in the configuration with this working
+    directory, and cannot manage workspaces from the CLI (e.g. `terraform workspace select` or
+    `terraform workspace new`). This option conflicts with `tags`.
+
+- `hostname` - (Optional) The hostname of a Terraform Enterprise installation, if using Terraform
+  Enterprise. Defaults to Terraform Cloud (app.terraform.io).
+
+- `token` - (Optional) The token used to authenticate with Terraform Cloud.
+  We recommend omitting the token from the configuration, and instead using
+  [`terraform login`](/terraform/cli/commands/login) or manually configuring
+  `credentials` in the
+  [CLI config file](/terraform/cli/config/config-file#credentials).
+
+### Environment Variables
+
+-> **Note:** CLI integration environment variables are supported in Terraform v1.2.0 and later.
+
+You can use environment variables to configure one or more `cloud` block attributes. This is helpful when you want to configure Terraform as part of a Continuous Integration (CI) pipeline. Terraform only reads these variables if the corresponding attribute is omitted from your configuration file. If you choose to configure the `cloud` block entirely through environment variables, you must still add an empty `cloud` block in your configuration file.
+
+~> **Warning:** Remote execution with non-interactive workflows requires auto-approved deployments. Minimize risk of unpredictable infrastructure changes and configuration drift by making sure that no one can change your infrastructure outside of your automated build pipeline.  Refer to [Non-Interactive Workflows](/terraform/cloud-docs/run/cli#non-interactive-workflows) for details.
+
+Use the following environment variables to configure the `cloud` block:
+
+- `TF_CLOUD_ORGANIZATION` - The name of the organization. Terraform reads this variable when `organization` omitted from the `cloud` block`. If both are specified, the configuration takes precedence.
+
+- `TF_CLOUD_HOSTNAME` - The hostname of a Terraform Enterprise installation. Terraform reads this when `hostname` is omitted from the `cloud` block. If both are specified, the configuration takes precedence.
+
+- `TF_WORKSPACE` - The name of a single Terraform Cloud workspace. Terraform reads this when `workspaces` is omitted from the `cloud` block. Terraform Cloud will not create a new workspace from this variable; the workspace must exist in the specified organization. You can set `TF_WORKSPACE` if the `cloud` block uses tags. However, the value of `TF_WORKSPACE` must be included in the set of tags. This variable also selects the workspace in your local environment. Refer to [TF_WORKSPACE](/terraform/cli/config/environment-variables#tf_workspace) for details.
+
+## Excluding Files from Upload with .terraformignore
+
+When executing a remote `plan` or `apply` in a [CLI-driven run](/terraform/cloud-docs/run/cli),
+a copy of your configuration directory is uploaded to Terraform Cloud. You can define
+paths to exclude from upload by adding a `.terraformignore` file at the root of your
+configuration directory. If this file is not present, the upload will exclude
+the following by default:
+
+- `.git/` directories
+- `.terraform/` directories (exclusive of `.terraform/modules`)
+
+The rules in `.terraformignore` file resemble the rules allowed in a
+[.gitignore file](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository#_ignoring):
+
+- Comments (starting with `#`) or blank lines are ignored.
+- End a pattern with a forward slash `/` to specify a directory.
+- Negate a pattern by starting it with an exclamation point `!`.
+
+-> **Note:** Unlike `.gitignore`, only the `.terraformignore` at the root of the configuration directory is considered.
diff --git a/v1.5.7/website/docs/cli/code/index.mdx b/v1.5.7/website/docs/cli/code/index.mdx
new file mode 100644
index 0000000..714f942
--- /dev/null
+++ b/v1.5.7/website/docs/cli/code/index.mdx
@@ -0,0 +1,44 @@
+---
+page_title: Writing and Modifying Code - Terraform CLI
+description: >-
+  Learn commands that help validate, format, and upgrade code written in the
+  Terraform Configuration Language.
+---
+
+# Writing and Modifying Terraform Code
+
+The [Terraform language](/terraform/language) is Terraform's primary
+user interface, and all of Terraform's workflows rely on configurations written
+in the Terraform language.
+
+Terraform CLI includes several commands to make Terraform code more convenient
+to work with. Integrating these commands into your editing workflow can
+potentially save you time and effort.
+
+- [The `terraform console` command](/terraform/cli/commands/console) starts an
+  interactive shell for evaluating Terraform
+  [expressions](/terraform/language/expressions), which can be a faster way
+  to verify that a particular resource argument results in the value you expect.
+
+- [The `terraform fmt` command](/terraform/cli/commands/fmt) rewrites Terraform
+  configuration files to a canonical format and style, so you don't have to
+  waste time making minor adjustments for readability and consistency. It works
+  well as a pre-commit hook in your version control system.
+
+- [The `terraform validate` command](/terraform/cli/commands/validate) validates the
+  syntax and arguments of the Terraform configuration files in a directory,
+  including argument and attribute names and types for resources and modules.
+  The `plan` and `apply` commands automatically validate a configuration before
+  performing any other work, so `validate` isn't a crucial part of the core
+  workflow, but it can be very useful as a pre-commit hook or as part of a
+  continuous integration pipeline.
+
+- [The `0.13upgrade` command](/terraform/cli/commands/0.13upgrade) and
+  [the `0.12upgrade` command](/terraform/cli/commands/0.12upgrade) can automatically
+  modify the configuration files in a Terraform module to help deal with major
+  syntax changes that occurred in the 0.13 and 0.12 releases of Terraform. Both
+  of these commands are only available in the Terraform version they are
+  associated with, and you are expected to upgrade older code to be compatible
+  with 0.12 before attempting to make it compatible with 0.13. For more detailed
+  information about updating code for new Terraform versions, see the [upgrade
+  guides](/terraform/language/upgrade-guides) in the Terraform language docs.
diff --git a/v1.5.7/website/docs/cli/commands/0.12upgrade.mdx b/v1.5.7/website/docs/cli/commands/0.12upgrade.mdx
new file mode 100644
index 0000000..eb4acc2
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/0.12upgrade.mdx
@@ -0,0 +1,117 @@
+---
+page_title: 'Command: 0.12upgrade'
+description: >-
+  The 0.12upgrade subcommand automatically rewrites existing configurations for
+  Terraform 0.12 compatibility.
+---
+
+# Command: 0.12upgrade
+
+The `terraform 0.12upgrade` command applies several automatic upgrade rules to
+help prepare a module that was written for Terraform v0.11 to be used
+with Terraform v0.12.
+
+-> **This command is available only in Terraform v0.12 releases.** For more information, see [the Terraform v0.12 upgrade guide](/terraform/language/v1.1.x/upgrade-guides/0-12).
+
+## Usage
+
+Usage: `terraform 0.12upgrade [options] [dir]`
+
+By default, `0.12upgrade` changes configuration files in the current working
+directory. However, you can provide an explicit path to another directory if
+desired, which may be useful for automating migrations of several modules in
+the same repository.
+
+When run with no other options, the command will first explain what it is
+going to do and prompt for confirmation:
+
+```
+$ terraform 0.12upgrade
+
+This command will rewrite the configuration files in the given directory so
+that they use the new syntax features from Terraform v0.12, and will identify
+any constructs that may need to be adjusted for correct operation with
+Terraform v0.12.
+
+We recommend using this command in a clean version control work tree, so that
+you can easily see the proposed changes as a diff against the latest commit.
+If you have uncommitted changes already present, we recommend aborting this
+command and dealing with them before running this command again.
+
+Would you like to upgrade the module in the current directory?
+  Only 'yes' will be accepted to confirm.
+
+  Enter a value: yes
+```
+
+The `0.12upgrade` subcommand requires access to providers used in the
+configuration in order to analyze their resource types, so it's important to
+run `terraform init` first to install these. In some rare cases, a configuration
+that worked in v0.11 may have syntax errors in v0.12, in which case
+`terraform init` will run in a special mode where it installs only enough to
+run the upgrade command, after which you can run `terraform init` again to
+complete initialization.
+
+Many of the rewrite rules are completely automatic, but in some cases the
+tool cannot determine enough information from the configuration alone to make
+a decision, and so it will instead add a comment to the configuration for
+user review. All such comments contain the string `TF-UPGRADE-TODO` to make
+them easier to find.
+
+After upgrading, the configuration will also be reformatted into the standard
+Terraform style and expressions rewritten to use the more-readable v0.12 syntax
+features.
+
+We recommend running this command with a clean version control work tree so
+that you can use VCS tools to review the proposed changes, including any
+`TF-UPGRADE-TODO` comments, and make any revisions required before committing
+the change.
+
+Once upgraded the configuration will no longer be compatible with Terraform
+v0.11 and earlier. When upgrading a shared module that is called from multiple
+configurations, you may need to
+[fix existing configurations to a previous version](/terraform/language/modules/syntax#version)
+to allow for a gradual upgrade. If the module is published via
+[a Terraform registry](/terraform/registry), assign a new _major_ version number
+to the upgraded module source to represent the fact that this is a breaking
+change for v0.11 callers. If a module is installed directly from a version
+control system such as Git,
+[use specific revisions](/terraform/language/modules/sources#selecting-a-revision)
+to control which version is used by which caller.
+
+The command-line options are all optional. The available options are:
+
+* `-yes` - Skip the initial introduction messages and interactive confirmation.
+  Use this when running the command in batch from a script.
+
+* `-force` - Override the heuristic that attempts to detect if a configuration
+  is already written for v0.12 or later. Some of the transformations made by
+  this command are not idempotent, so re-running against the same module may
+  change the meanings of some expressions in the module.
+
+## Batch Usage
+
+After you've experimented with the `0.12upgrade` command in some confined
+situations, if you have a repository containing multiple modules you may
+wish to batch-upgrade them all and review them together. Recursive upgrades
+are not supported by the tool itself, but if you are on a Unix-style system
+you can achieve this using the `find` command as follows:
+
+```
+find . -name '*.tf' -printf "%h\n" | uniq | xargs -n1 terraform 0.12upgrade -yes
+```
+
+On Mac OS X, the `find` included with the system does not support the `-printf` argument. You can install GNU find using Homebrew in order to use that argument:
+
+```
+brew install findutils
+```
+
+Once installed, run the above command line using `gfind` instead of `find`.
+
+Note that the above includes the `-yes` option to override the interactive
+prompt, so be sure you have a clean work tree before running it.
+
+Because upgrading requires access to the configuration's provider plugins,
+all of the directories must be initialized with `terraform init` prior to
+running the above.
diff --git a/v1.5.7/website/docs/cli/commands/0.13upgrade.mdx b/v1.5.7/website/docs/cli/commands/0.13upgrade.mdx
new file mode 100644
index 0000000..51c5f45
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/0.13upgrade.mdx
@@ -0,0 +1,89 @@
+---
+page_title: 'Command: 0.13upgrade'
+description: >-
+  The 0.13upgrade subcommand updates existing configurations to use the new
+  provider source features from Terraform 0.13.
+---
+
+# Command: 0.13upgrade
+
+The `terraform 0.13upgrade` command updates existing configuration to add an
+explicit `source` attribute for each provider used in a given module. The
+provider source settings are stored in a `required_providers` block.
+
+-> **This command is available only in Terraform v0.13 releases.** For more information, see [the Terraform v0.13 upgrade guide](/terraform/language/v1.1.x/upgrade-guides/0-13).
+
+## Usage
+
+Usage: `terraform 0.13upgrade [options] [dir]`
+
+The primary purpose of the `0.13upgrade` command is to determine which
+providers are in use for a module, detect the source address for those
+providers where possible, and record this information in a
+[`required_providers` block][required-providers].
+
+[required-providers]: /terraform/language/providers/requirements
+
+~> Note: the command ignores `.tf.json` files and override files in the module.
+
+If the module already has a `required_providers` block, the command updates it
+in-place. Otherwise, a new block is added to the `versions.tf` file.
+
+By default, `0.13upgrade` changes configuration files in the current working
+directory. However, you can provide an explicit path to another directory if
+desired, which may be useful for automating migrations of several modules in
+the same repository.
+
+When run with no other options, the command will first explain what it is
+going to do and prompt for confirmation:
+
+```
+$ terraform 0.13upgrade
+
+This command will update the configuration files in the given directory to use
+the new provider source features from Terraform v0.13. It will also highlight
+any providers for which the source cannot be detected, and advise how to
+proceed.
+
+We recommend using this command in a clean version control work tree, so that
+you can easily see the proposed changes as a diff against the latest commit.
+If you have uncommited changes already present, we recommend aborting this
+command and dealing with them before running this command again.
+
+Would you like to upgrade the module in the current directory?
+  Only 'yes' will be accepted to confirm.
+
+  Enter a value: yes
+```
+
+We recommend running this command with a clean version control work tree so
+that you can use VCS tools to review the proposed changes, including any
+`TF-UPGRADE-TODO` comments, and make any revisions required before committing
+the change.
+
+There is one command-line option:
+
+* `-yes` - Skip the initial introduction messages and interactive confirmation.
+  Use this when running the command in batch from a script.
+
+## Batch Usage
+
+After you've experimented with the `0.13upgrade` command in some confined
+situations, if you have a repository containing multiple modules you may
+wish to batch-upgrade them all and review them together. Recursive upgrades
+are not supported by the tool itself, but if you are on a Unix-style system
+you can achieve this using the `find` command as follows:
+
+```
+$ find . -name '*.tf' | xargs -n1 dirname | uniq | xargs -n1 terraform 0.13upgrade -yes
+```
+
+On a Windows system with PowerShell, you can use this command:
+
+```
+Get-Childitem -Recurse -Include *.tf | Split-Path | `
+Select-Object -Unique | ForEach-Object { terraform 0.13upgrade -yes $_.FullName }
+```
+
+Note that the above commands include the `-yes` option to override the
+interactive prompt, so be sure you have a clean work tree before running it.
diff --git a/v1.5.7/website/docs/cli/commands/apply.mdx b/v1.5.7/website/docs/cli/commands/apply.mdx
new file mode 100644
index 0000000..641b09e
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/apply.mdx
@@ -0,0 +1,120 @@
+---
+page_title: 'Command: apply'
+description: >-
+  The terraform apply command executes the actions proposed in a Terraform plan
+  to create, update, or destroy infrastructure.
+---
+
+# Command: apply
+
+The `terraform apply` command executes the actions proposed in a Terraform
+plan.
+
+> **Hands On:** Try the [Apply Terraform Configuration](/terraform/tutorials/cli/apply?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial to learn how Terraform applies a configuration, how Terraform recovers from errors during apply, and common ways to use this command.
+
+## Usage
+
+Usage: `terraform apply [options] [plan file]`
+
+
+
+### Automatic Plan Mode
+
+When you run `terraform apply` without passing a saved plan file, Terraform automatically creates a new execution plan as if you had run [`terraform plan`](/terraform/cli/commands/plan), prompts you to approve that plan, and takes the indicated actions. You can use all of the [planning modes](/terraform/cli/commands/plan#planning-modes) and
+[planning options](/terraform/cli/commands/plan#planning-options) to customize how Terraform will create the plan.
+
+You can pass the `-auto-approve` option to instruct Terraform to apply the plan without asking for confirmation.
+
+!> **Warning:** If you use `-auto-approve`, we recommend making sure that no one can change your infrastructure outside of your Terraform workflow. This minimizes the risk of unpredictable changes and configuration drift.
+
+### Saved Plan Mode
+
+When you pass a [saved plan file](/terraform/cli/commands/plan#out-filename) to `terraform apply`, Terraform takes the actions in the saved plan without prompting you for confirmation. You may want to use this two-step workflow when [running Terraform in automation](/terraform/tutorials/automation/automate-terraform?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS).
+
+Use [`terraform show`](/terraform/cli/commands/show) to inspect a saved plan file before applying it.
+
+When using a saved plan, you cannot specify any additional planning modes or options. These options only affect Terraform's decisions about which
+actions to take, and the plan file contains the final results of those
+decisions.
+
+### Plan Options
+
+Without a saved plan file, `terraform apply` supports all planning modes and planning options available for `terraform plan`.
+
+-  **[Planning Modes](/terraform/cli/commands/plan#planning-modes):** These include `-destroy`, which creates a plan to destroy all remote objects, and `-refresh-only`, which creates a plan to update Terraform state and root module output values.
+- **[Planning Options](/terraform/cli/commands/plan#planning-options):** These include specifying which resource instances Terraform should replace, setting Terraform input variables, etc.
+
+### Apply Options
+
+The following options change how the apply command executes and reports on the apply operation.
+
+- `-auto-approve` - Skips interactive approval of plan before applying. This
+  option is ignored when you pass a previously-saved plan file, because
+  Terraform considers you passing the plan file as the approval and so
+  will never prompt in that case.
+
+- `-compact-warnings` - Shows any warning messages in a compact form which
+  includes only the summary messages, unless the warnings are accompanied by
+  at least one error and thus the warning text might be useful context for
+  the errors.
+
+- `-input=false` - Disables all of Terraform's interactive prompts. Note that
+  this also prevents Terraform from prompting for interactive approval of a
+  plan, so Terraform will conservatively assume that you do not wish to
+  apply the plan, causing the operation to fail. If you wish to run Terraform
+  in a non-interactive context, see
+  [Running Terraform in Automation](/terraform/tutorials/automation/automate-terraform?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) for some
+  different approaches.
+
+- `-json` - Enables the [machine readable JSON UI][machine-readable-ui] output.
+  This implies `-input=false`, so the configuration must have no unassigned
+  variable values to continue. To enable this flag, you must also either enable
+  the `-auto-approve` flag or specify a previously-saved plan.
+
+  [machine-readable-ui]: /terraform/internals/machine-readable-ui
+
+- `-lock=false` - Don't hold a state lock during the operation. This is
+  dangerous if others might concurrently run commands against the same
+  workspace.
+
+- `-lock-timeout=DURATION` - Unless locking is disabled with `-lock=false`,
+  instructs Terraform to retry acquiring a lock for a period of time before
+  returning an error. The duration syntax is a number followed by a time
+  unit letter, such as "3s" for three seconds.
+
+- `-no-color` - Disables terminal formatting sequences in the output. Use this
+  if you are running Terraform in a context where its output will be
+  rendered by a system that cannot interpret terminal formatting.
+
+- `-parallelism=n` - Limit the number of concurrent operation as Terraform
+  [walks the graph](/terraform/internals/graph#walking-the-graph). Defaults to
+  10\.
+
+- All [planning modes](/terraform/cli/commands/plan#planning-modes) and
+[planning options](/terraform/cli/commands/plan#planning-options) for
+`terraform plan` - Customize how Terraform will create the plan. Only available when you run `terraform apply` without a saved plan file.
+
+For configurations using
+[the `local` backend](/terraform/language/settings/backends/local) only,
+`terraform apply` also accepts the legacy options
+[`-state`, `-state-out`, and `-backup`](/terraform/language/settings/backends/local#command-line-arguments).
+
+## Passing a Different Configuration Directory
+
+Terraform v0.13 and earlier also accepted a directory path in place of the
+plan file argument to `terraform apply`, in which case Terraform would use
+that directory as the root module instead of the current working directory.
+
+That usage was deprecated in Terraform v0.14 and removed in Terraform v0.15.
+If your workflow relies on overriding the root module directory, use
+[the `-chdir` global option](/terraform/cli/commands#switching-working-directory-with-chdir)
+instead, which works across all commands and makes Terraform consistently look
+in the given directory for all files it would normally read or write in the
+current working directory.
+
+If your previous use of this legacy pattern was also relying on Terraform
+writing the `.terraform` subdirectory into the current working directory even
+though the root module directory was overridden, use
+[the `TF_DATA_DIR` environment variable](/terraform/cli/config/environment-variables#tf_data_dir)
+to direct Terraform to write the `.terraform` directory to a location other
+than the current working directory.
diff --git a/v1.5.7/website/docs/cli/commands/console.mdx b/v1.5.7/website/docs/cli/commands/console.mdx
new file mode 100644
index 0000000..ca8a0ba
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/console.mdx
@@ -0,0 +1,120 @@
+---
+page_title: 'Command: console'
+description: >-
+  The terraform console command provides an interactive console for evaluating
+  expressions.
+---
+
+# Command: console
+
+The `terraform console` command provides an interactive console for
+evaluating [expressions](/terraform/language/expressions).
+
+## Usage
+
+Usage: `terraform console [options]`
+
+This command provides an interactive command-line console for evaluating and
+experimenting with [expressions](/terraform/language/expressions).
+You can use it to test interpolations before using them in configurations
+and to interact with any values currently saved in
+[state](/terraform/language/state). If the current state is empty or has not yet been created, you can use the console to experiment with the expression syntax and
+[built-in functions](/terraform/language/functions). The console holds a [lock on the state](/terraform/language/state/locking), and you will not be able to use the console while performing other actions that modify state.
+
+To close the console, enter the `exit` command or press Control-C
+or Control-D.
+
+For configurations using
+[the `local` backend](/terraform/language/settings/backends/local) only,
+`terraform console` accepts the legacy command line option
+[`-state`](/terraform/language/settings/backends/local#command-line-arguments).
+
+## Scripting
+
+The `terraform console` command can be used in non-interactive scripts
+by piping newline-separated commands to it. Only the output from the
+final command is printed unless an error occurs earlier.
+
+For example:
+
+```shell
+$ echo 'split(",", "foo,bar,baz")' | terraform console
+tolist([
+  "foo",
+  "bar",
+  "baz",
+])
+```
+
+## Remote State
+
+If [remote state](/terraform/language/state/remote) is used by the current backend,
+Terraform will read the state for the current workspace from the backend
+before evaluating any expressions.
+
+## Examples
+
+The `terraform console` command will read the Terraform configuration in the
+current working directory and the Terraform state file from the configured
+backend so that interpolations can be tested against both the values in the
+configuration and the state file.
+
+With the following `main.tf`:
+
+```hcl
+variable "apps" {
+  type = map(any)
+  default = {
+    "foo" = {
+      "region" = "us-east-1",
+    },
+    "bar" = {
+      "region" = "eu-west-1",
+    },
+    "baz" = {
+      "region" = "ap-south-1",
+    },
+  }
+}
+
+resource "random_pet" "example" {
+  for_each = var.apps
+}
+```
+
+Executing `terraform console` will drop you into an interactive shell where you
+can test interpolations to:
+
+Print a value from a map:
+
+```
+> var.apps.foo
+{
+  "region" = "us-east-1"
+}
+```
+
+Filter a map based on a specific value:
+
+```
+> { for key, value in var.apps : key => value if value.region == "us-east-1" }
+{
+  "foo" = {
+    "region" = "us-east-1"
+  }
+}
+```
+
+Check if certain values may not be known until apply:
+
+```
+> random_pet.example
+(known after apply)
+```
+
+Test various functions:
+
+```
+> cidrnetmask("172.16.0.0/12")
+"255.240.0.0"
+```
diff --git a/v1.5.7/website/docs/cli/commands/destroy.mdx b/v1.5.7/website/docs/cli/commands/destroy.mdx
new file mode 100644
index 0000000..a0d8713
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/destroy.mdx
@@ -0,0 +1,46 @@
+---
+page_title: 'Command: destroy'
+description: >-
+  The terraform destroy command destroys all objects managed by a Terraform
+  configuration.
+---
+
+# Command: destroy
+
+The `terraform destroy` command is a convenient way to destroy all remote
+objects managed by a particular Terraform configuration.
+
+While you will typically not want to destroy long-lived objects in a production
+environment, Terraform is sometimes used to manage ephemeral infrastructure
+for development purposes, in which case you can use `terraform destroy` to
+conveniently clean up all of those temporary objects once you are finished
+with your work.
+
+## Usage
+
+Usage: `terraform destroy [options]`
+
+This command is just a convenience alias for the following command:
+
+```
+terraform apply -destroy
+```
+
+For that reason, this command accepts most of the options that
+[`terraform apply`](/terraform/cli/commands/apply) accepts, although it does
+not accept a plan file argument and forces the selection of the "destroy"
+planning mode.
+
+You can also create a speculative destroy plan, to see what the effect of
+destroying would be, by running the following command:
+
+```
+terraform plan -destroy
+```
+
+This will run [`terraform plan`](/terraform/cli/commands/plan) in _destroy_ mode, showing
+you the proposed destroy changes without executing them.
+
+-> **Note:** The `-destroy` option to `terraform apply` exists only in
+Terraform v0.15.2 and later. For earlier versions, you _must_ use
+`terraform destroy` to get the effect of `terraform apply -destroy`.
diff --git a/v1.5.7/website/docs/cli/commands/env.mdx b/v1.5.7/website/docs/cli/commands/env.mdx
new file mode 100644
index 0000000..bb98c9f
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/env.mdx
@@ -0,0 +1,12 @@
+---
+page_title: 'Command: env'
+description: >-
+  The terraform env command is a deprecated form of the terraform workspace
+  command.
+---
+
+# Command: env
+
+The `terraform env` command is deprecated.
+[The `terraform workspace` command](/terraform/cli/commands/workspace)
+should be used instead.
diff --git a/v1.5.7/website/docs/cli/commands/fmt.mdx b/v1.5.7/website/docs/cli/commands/fmt.mdx
new file mode 100644
index 0000000..4b2661a
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/fmt.mdx
@@ -0,0 +1,62 @@
+---
+page_title: 'Command: fmt'
+description: >-
+  The terraform fmt command rewrites configuration files to a canonical format
+  and style.
+---
+
+# Command: fmt
+
+The `terraform fmt` command is used to rewrite Terraform configuration files
+to a canonical format and style. This command applies a subset of
+the [Terraform language style conventions](/terraform/language/syntax/style),
+along with other minor adjustments for readability.
+
+Other Terraform commands that generate Terraform configuration will produce
+configuration files that conform to the style imposed by `terraform fmt`, so
+using this style in your own files will ensure consistency.
+
+The canonical format may change in minor ways between Terraform versions, so
+after upgrading Terraform we recommend to proactively run `terraform fmt`
+on your modules along with any other changes you are making to adopt the new
+version.
+
+We don't consider new formatting rules in `terraform fmt` to be a breaking
+change in new versions of Terraform, but we do aim to minimize changes for
+configurations that are already following the style examples shown in the
+Terraform documentation. When adding new formatting rules, they will usually
+aim to apply more of the rules already shown in the configuration examples
+in the documentation, and so we recommend following the documented style even
+for decisions that `terraform fmt` doesn't yet apply automatically.
+
+Formatting decisions are always subjective and so you might disagree with the
+decisions that `terraform fmt` makes. This command is intentionally opinionated
+and has no customization options because its primary goal is to encourage
+consistency of style between different Terraform codebases, even though the
+chosen style can never be everyone's favorite.
+
+We recommend that you follow the style conventions applied by `terraform fmt`
+when writing Terraform modules, but if you find the results particularly
+objectionable then you may choose not to use this command, and possibly choose
+to use a third-party formatting tool instead. If you choose to use a
+third-party tool then you should also run it on files that are generated
+automatically by Terraform, to get consistency between your hand-written files
+and the generated files.
+
+## Usage
+
+Usage: `terraform fmt [options] [target...]`
+
+By default, `fmt` scans the current directory for configuration files. If you
+provide a directory for the `target` argument, then `fmt` will scan that
+directory instead. If you provide a file, then `fmt` will process just that
+file. If you provide a single dash (`-`), then `fmt` will read from standard
+input (STDIN).
+
+The command-line flags are all optional. The following flags are available:
+
+* `-list=false` - Don't list the files containing formatting inconsistencies.
+* `-write=false` - Don't overwrite the input files. (This is implied by `-check` or when the input is STDIN.)
+* `-diff` - Display diffs of formatting changes.
+* `-check` - Check if the input is formatted. Exit status will be 0 if all input is properly formatted. If not, exit status will be non-zero and the command will output a list of filenames whose files are not properly formatted.
+* `-recursive` - Also process files in subdirectories. By default, only the given directory (or current directory) is processed.
diff --git a/v1.5.7/website/docs/cli/commands/force-unlock.mdx b/v1.5.7/website/docs/cli/commands/force-unlock.mdx
new file mode 100644
index 0000000..705d044
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/force-unlock.mdx
@@ -0,0 +1,30 @@
+---
+page_title: 'Command: force-unlock'
+description: >-
+  The terraform force-unlock command unlocks the state for a configuration. It
+  does not modify your infrastructure.
+---
+
+# Command: force-unlock
+
+Manually unlock the state for the defined configuration.
+
+This will not modify your infrastructure. This command removes the lock on the
+state for the current configuration. The behavior of this lock is dependent
+on the backend being used. Local state files cannot be unlocked by another
+process.
+
+## Usage
+
+Usage: `terraform force-unlock [options] LOCK_ID`
+
+Manually unlock the state for the defined configuration.
+
+This will not modify your infrastructure. This command removes the lock on the
+state for the current configuration. The behavior of this lock is dependent
+on the backend being used. Local state files cannot be unlocked by another
+process.
+
+Options:
+
+* `-force` -  Don't ask for input for unlock confirmation.
diff --git a/v1.5.7/website/docs/cli/commands/get.mdx b/v1.5.7/website/docs/cli/commands/get.mdx
new file mode 100644
index 0000000..f46b877
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/get.mdx
@@ -0,0 +1,24 @@
+---
+page_title: 'Command: get'
+description: The terraform get command downloads and updates modules.
+---
+
+# Command: get
+
+The `terraform get` command is used to download and update
+[modules](/terraform/language/modules/develop) mentioned in the root module.
+
+## Usage
+
+Usage: `terraform get [options]`
+
+The modules are downloaded into a `.terraform` subdirectory of the current
+working directory. Don't commit this directory to your version control
+repository.
+
+The `get` command supports the following option:
+
+* `-update` - If specified, modules that are already downloaded will be
+  checked for updates and the updates will be downloaded if present.
+
+* `-no-color` - Disable text coloring in the output.
diff --git a/v1.5.7/website/docs/cli/commands/graph.mdx b/v1.5.7/website/docs/cli/commands/graph.mdx
new file mode 100644
index 0000000..9f59ee5
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/graph.mdx
@@ -0,0 +1,56 @@
+---
+page_title: 'Command: graph'
+description: >-
+  The terraform graph command generates a visual representation of a
+  configuration or execution plan that you can use to generate charts.
+---
+
+# Command: graph
+
+The `terraform graph` command is used to generate a visual
+representation of either a configuration or execution plan.
+The output is in the DOT format, which can be used by
+[GraphViz](http://www.graphviz.org) to generate charts.
+
+## Usage
+
+Usage: `terraform graph [options]`
+
+Outputs the visual execution graph of Terraform resources according to
+either the current configuration or an execution plan.
+
+The graph is outputted in DOT format. The typical program that can
+read this format is GraphViz, but many web services are also available
+to read this format.
+
+The `-type` flag can be used to control the type of graph shown. Terraform
+creates different graphs for different operations. See the options below
+for the list of types supported. The default type is "plan" if a
+configuration is given, and "apply" if a plan file is passed as an
+argument.
+
+Options:
+
+* `-plan=tfplan`    - Render graph using the specified plan file instead of the
+  configuration in the current directory.
+
+* `-draw-cycles`    - Highlight any cycles in the graph with colored edges.
+  This helps when diagnosing cycle errors.
+
+* `-type=plan`      - Type of graph to output. Can be: `plan`, `plan-refresh-only`, `plan-destroy`, or `apply`.
+
+* `-module-depth=n` - (deprecated) In prior versions of Terraform, specified the
+  depth of modules to show in the output.
+
+## Generating Images
+
+The output of `terraform graph` is in the DOT format, which can
+easily be converted to an image by making use of `dot` provided
+by GraphViz:
+
+```shellsession
+$ terraform graph | dot -Tsvg > graph.svg
+```
+
+Here is an example graph output:
+![Graph Example](/img/docs/graph-example.png)
diff --git a/v1.5.7/website/docs/cli/commands/import.mdx b/v1.5.7/website/docs/cli/commands/import.mdx
new file mode 100644
index 0000000..f9ffd3d
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/import.mdx
@@ -0,0 +1,160 @@
+---
+page_title: 'Command: import'
+description: The terraform import command brings existing resources into Terraform state.
+---
+
+# Command: import
+
+> **Hands-on:** Try the [Import Terraform Configuration](/terraform/tutorials/state/state-import?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+The `terraform import` command [imports existing resources](/terraform/cli/import)
+into Terraform.
+
+## Usage
+
+Usage: `terraform import [options] ADDRESS ID`
+
+Import will find the existing resource from ID and import it into your Terraform
+state at the given ADDRESS.
+
+ADDRESS must be a valid [resource address](/terraform/cli/state/resource-addressing).
+Because any resource address is valid, the import command can import resources
+into modules as well as directly into the root of your state.
+
+ID is dependent on the resource type being imported. For example, for AWS EC2
+instances it is the instance ID (`i-abcd1234`) but for AWS Route53 zones
+it is the zone ID (`Z12ABC4UGMOZ2N`). Please reference the provider documentation for details
+on the ID format. If you're unsure, feel free to just try an ID. If the ID
+is invalid, you'll just receive an error message.
+
+~> Warning: Terraform expects that each remote object it is managing will be
+bound to only one resource address, which is normally guaranteed by Terraform
+itself having created all objects. If you import existing objects into Terraform,
+be careful to import each remote object to only one Terraform resource address.
+If you import the same object multiple times, Terraform may exhibit unwanted
+behavior. For more information on this assumption, see
+[the State section](/terraform/language/state).
+
+The command-line flags are all optional. The following flags are available:
+
+- `-config=path` - Path to directory of Terraform configuration files that
+  configure the provider for import. This defaults to your working directory.
+  If this directory contains no Terraform configuration files, the provider
+  must be configured via manual input or environmental variables.
+
+- `-input=true` - Whether to ask for input for provider configuration.
+
+- `-lock=false` - Don't hold a state lock during the operation. This is
+  dangerous if others might concurrently run commands against the same
+  workspace.
+
+- `-lock-timeout=0s` - Duration to retry a state lock.
+
+- `-no-color` - If specified, output won't contain any color.
+
+- `-parallelism=n` - Limit the number of concurrent operation as Terraform
+  [walks the graph](/terraform/internals/graph#walking-the-graph). Defaults
+  to 10.
+
+- `-provider=provider` - **Deprecated** Override the provider configuration to
+  use when importing the object. By default, Terraform uses the provider specified
+  in the configuration for the target resource, and that is the best behavior in most cases.
+
+- `-var 'foo=bar'` - Set a variable in the Terraform configuration. This flag
+  can be set multiple times. Variable values are interpreted as
+  [literal expressions](/terraform/language/expressions/types) in the
+  Terraform language, so list and map values can be specified via this flag.
+
+- `-var-file=foo` - Set variables in the Terraform configuration from
+  a [variable file](/terraform/language/values/variables#variable-definitions-tfvars-files). If
+  a `terraform.tfvars` or any `.auto.tfvars` files are present in the current
+  directory, they will be automatically loaded. `terraform.tfvars` is loaded
+  first and the `.auto.tfvars` files after in alphabetical order. Any files
+  specified by `-var-file` override any values set automatically from files in
+  the working directory. This flag can be used multiple times. This is only
+  useful with the `-config` flag.
+
+For configurations using the [Terraform Cloud CLI integration](/terraform/cli/cloud) or the [`remote` backend](/terraform/language/settings/backends/remote)
+only, `terraform import`
+also accepts the option
+[`-ignore-remote-version`](/terraform/cli/cloud/command-line-arguments#ignore-remote-version).
+
+For configurations using
+[the `local` backend](/terraform/language/settings/backends/local) only,
+`terraform import` also accepts the legacy options
+[`-state`, `-state-out`, and `-backup`](/terraform/language/settings/backends/local#command-line-arguments).
+
+## Provider Configuration
+
+Terraform will attempt to load configuration files that configure the
+provider being used for import. If no configuration files are present or
+no configuration for that specific provider is present, Terraform will
+prompt you for access credentials. You may also specify environmental variables
+to configure the provider.
+
+The only limitation Terraform has when reading the configuration files
+is that the import provider configurations must not depend on non-variable
+inputs. For example, a provider configuration cannot depend on a data
+source.
+
+As a working example, if you're importing AWS resources and you have a
+configuration file with the contents below, then Terraform will configure
+the AWS provider with this file.
+
+```hcl
+variable "access_key" {}
+variable "secret_key" {}
+
+provider "aws" {
+  access_key = "${var.access_key}"
+  secret_key = "${var.secret_key}"
+}
+```
+
+## Example: Import into Resource
+
+This example will import an AWS instance into the `aws_instance` resource named `foo`:
+
+```shell
+$ terraform import aws_instance.foo i-abcd1234
+```
+
+## Example: Import into Module
+
+The example below will import an AWS instance into the `aws_instance` resource named `bar` into a module named `foo`:
+
+```shell
+$ terraform import module.foo.aws_instance.bar i-abcd1234
+```
+
+## Example: Import into Resource configured with count
+
+The example below will import an AWS instance into the first instance of the `aws_instance` resource named `baz` configured with
+[`count`](/terraform/language/meta-arguments/count):
+
+```shell
+$ terraform import 'aws_instance.baz[0]' i-abcd1234
+```
+
+## Example: Import into Resource configured with for_each
+
+The example below will import an AWS instance into the `"example"` instance of the `aws_instance` resource named `baz` configured with
+[`for_each`](/terraform/language/meta-arguments/for_each):
+
+Linux, Mac OS, and UNIX:
+
+```shell
+$ terraform import 'aws_instance.baz["example"]' i-abcd1234
+```
+
+PowerShell:
+
+```shell
+$ terraform import 'aws_instance.baz[\"example\"]' i-abcd1234
+```
+
+Windows `cmd.exe`:
+
+```shell
+$ terraform import aws_instance.baz[\"example\"] i-abcd1234
+```
diff --git a/v1.5.7/website/docs/cli/commands/index.mdx b/v1.5.7/website/docs/cli/commands/index.mdx
new file mode 100644
index 0000000..5d6126c
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/index.mdx
@@ -0,0 +1,162 @@
+---
+page_title: Basic CLI Features
+description: An introduction to the terraform command and its available subcommands.
+---
+
+# Basic CLI Features
+
+> **Hands-on:** Try the [Terraform: Get Started](/terraform/tutorials/aws-get-started?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorials.
+
+The command line interface to Terraform is the `terraform` command, which
+accepts a variety of subcommands such as `terraform init` or `terraform plan`.
+
+We refer to the `terraform` command line tool as "Terraform CLI" elsewhere
+in the documentation. This terminology is often used to distinguish it from
+other components you might use in the Terraform product family, such as
+[Terraform Cloud](/terraform/cloud-docs) or
+the various [Terraform providers](/terraform/language/providers), which
+are developed and released separately from Terraform CLI.
+
+To view a list of the commands available in your current Terraform version,
+run `terraform` with no additional arguments:
+
+```text
+Usage: terraform [global options] <subcommand> [args]
+
+The available commands for execution are listed below.
+The primary workflow commands are given first, followed by
+less common or more advanced commands.
+
+Main commands:
+  init          Prepare your working directory for other commands
+  validate      Check whether the configuration is valid
+  plan          Show changes required by the current configuration
+  apply         Create or update infrastructure
+  destroy       Destroy previously-created infrastructure
+
+All other commands:
+  console       Try Terraform expressions at an interactive command prompt
+  fmt           Reformat your configuration in the standard style
+  force-unlock  Release a stuck lock on the current workspace
+  get           Install or upgrade remote Terraform modules
+  graph         Generate a Graphviz graph of the steps in an operation
+  import        Associate existing infrastructure with a Terraform resource
+  login         Obtain and save credentials for a remote host
+  logout        Remove locally-stored credentials for a remote host
+  metadata      Metadata related commands
+  output        Show output values from your root module
+  providers     Show the providers required for this configuration
+  refresh       Update the state to match remote systems
+  show          Show the current state or a saved plan
+  state         Advanced state management
+  taint         Mark a resource instance as not fully functional
+  untaint       Remove the 'tainted' state from a resource instance
+  version       Show the current Terraform version
+  workspace     Workspace management
+
+Global options (use these before the subcommand, if any):
+  -chdir=DIR    Switch to a different working directory before executing the
+                given subcommand.
+  -help         Show this help output, or the help for a specified subcommand.
+  -version      An alias for the "version" subcommand.
+```
+
+(The output from your current Terraform version may be different than the
+above example.)
+
+To get specific help for any specific command, use the `-help` option with the
+relevant subcommand. For example, to see help about the "validate" subcommand
+you can run `terraform validate -help`.
+
+The inline help built in to Terraform CLI describes the most important
+characteristics of each command. For more detailed information, refer to each
+command's page for details.
+
+## Switching working directory with `-chdir`
+
+The usual way to run Terraform is to first switch to the directory containing
+the `.tf` files for your root module (for example, using the `cd` command), so
+that Terraform will find those files automatically without any extra arguments.
+
+In some cases though — particularly when wrapping Terraform in automation
+scripts — it can be convenient to run Terraform from a different directory than
+the root module directory. To allow that, Terraform supports a global option
+`-chdir=...` which you can include before the name of the subcommand you intend
+to run:
+
+```
+terraform -chdir=environments/production apply
+```
+
+The `chdir` option instructs Terraform to change its working directory to the
+given directory before running the given subcommand. This means that any files
+that Terraform would normally read or write in the current working directory
+will be read or written in the given directory instead.
+
+There are two exceptions where Terraform will use the original working directory
+even when you specify `-chdir=...`:
+
+* Settings in the [CLI Configuration](/terraform/cli/config/config-file) are not for a specific
+  subcommand and Terraform processes them before acting on the `-chdir`
+  option.
+
+* In case you need to use files from the original working directory as part
+  of your configuration, a reference to `path.cwd` in the configuration will
+  produce the original working directory instead of the overridden working
+  directory. Use `path.root` to get the root module directory.
+
+## Shell Tab-completion
+
+If you use either `bash` or `zsh` as your command shell, Terraform can provide
+tab-completion support for all command names and some command arguments.
+
+To add the necessary commands to your shell profile, run the following command:
+
+```bash
+terraform -install-autocomplete
+```
+
+After installation, it is necessary to restart your shell or to re-read its
+profile script before completion will be activated.
+
+To uninstall the completion hook, assuming that it has not been modified
+manually in the shell profile, run the following command:
+
+```bash
+terraform -uninstall-autocomplete
+```
+
+## Upgrade and Security Bulletin Checks
+
+The Terraform CLI commands interact with the HashiCorp service
+[Checkpoint](https://checkpoint.hashicorp.com/) to check for the availability
+of new versions and for critical security bulletins about the current version.
+
+One place where the effect of this can be seen is in `terraform version`, where
+it is used by default to indicate in the output when a newer version is
+available.
+
+Only anonymous information, which cannot be used to identify the user or host,
+is sent to Checkpoint. An anonymous ID is sent which helps de-duplicate warning
+messages. Both the anonymous id and the use of checkpoint itself are completely
+optional and can be disabled.
+
+Checkpoint itself can be entirely disabled for all HashiCorp products by
+setting the environment variable `CHECKPOINT_DISABLE` to any non-empty value.
+
+Alternatively, settings in
+[the CLI configuration file](/terraform/cli/config/config-file) can be used to
+disable checkpoint features. The following checkpoint-related settings are
+supported in this file:
+
+* `disable_checkpoint` - set to `true` to disable checkpoint calls
+  entirely. This is similar to the `CHECKPOINT_DISABLE` environment variable
+  described above.
+
+* `disable_checkpoint_signature` - set to `true` to disable the use of an
+  anonymous signature in checkpoint requests. This allows Terraform to check
+  for security bulletins but does not send the anonymous signature in these
+  requests.
+
+[The Checkpoint client code](https://github.com/hashicorp/go-checkpoint) used
+by Terraform is available for review by any interested party.
diff --git a/v1.5.7/website/docs/cli/commands/init.mdx b/v1.5.7/website/docs/cli/commands/init.mdx
new file mode 100644
index 0000000..95f75ec
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/init.mdx
@@ -0,0 +1,205 @@
+---
+page_title: 'Command: init'
+description: >-
+  The terraform init command initializes a working directory containing
+  configuration files and installs plugins for required providers.
+---
+
+# Command: init
+
+> **Hands-on:** Try the [Terraform: Get Started](/terraform/tutorials/aws-get-started?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorials. For more in-depth details on the `init` command, check out the [Initialize Terraform Configuration tutorial](/terraform/tutorials/cli/init?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS).
+
+The `terraform init` command initializes a working directory
+containing Terraform configuration files. This is the first command that should
+be run after writing a new Terraform configuration or cloning an existing one
+from version control. It is safe to run this command multiple times.
+
+## Usage
+
+Usage: `terraform init [options]`
+
+This command performs several different initialization steps in order to
+prepare the current working directory for use with Terraform. More details on
+these are in the sections below, but in most cases it is not necessary to worry
+about these individual steps.
+
+This command is always safe to run multiple times, to bring the working
+directory up to date with changes in the configuration. Though subsequent runs
+may give errors, this command will never delete your existing configuration or
+state.
+
+## General Options
+
+The following options apply to all of (or several of) the initialization steps:
+
+* `-input=true` Ask for input if necessary. If false, will error if
+  input was required.
+
+* `-lock=false` Disable locking of state files during state-related operations.
+
+* `-lock-timeout=<duration>` Override the time Terraform will wait to acquire
+  a state lock. The default is `0s` (zero seconds), which causes immediate
+  failure if the lock is already held by another process.
+
+* `-no-color` Disable color codes in the command output.
+
+* `-upgrade` Opt to upgrade modules and plugins as part of their respective
+  installation steps. See the sections below for more details.
+
+## Copy a Source Module
+
+By default, `terraform init` assumes that the working directory already
+contains a configuration and will attempt to initialize that configuration.
+
+Optionally, init can be run against an empty directory with the
+`-from-module=MODULE-SOURCE` option, in which case the given module will be
+copied into the target directory before any other initialization steps are
+run.
+
+This special mode of operation supports two use-cases:
+
+* Given a version control source, it can serve as a shorthand for checking out
+  a configuration from version control and then initializing the working directory
+  for it.
+
+* If the source refers to an _example_ configuration, it can be copied into
+  a local directory to be used as a basis for a new configuration.
+
+For routine use it is recommended to check out configuration from version
+control separately, using the version control system's own commands. This way
+it is possible to pass extra flags to the version control system when necessary,
+and to perform other preparation steps (such as configuration generation, or
+activating credentials) before running `terraform init`.
+
+## Backend Initialization
+
+During init, the root configuration directory is consulted for
+[backend configuration](/terraform/language/settings/backends/configuration) and the chosen backend
+is initialized using the given configuration settings.
+
+Re-running init with an already-initialized backend will update the working
+directory to use the new backend settings. Either `-reconfigure` or
+`-migrate-state` must be supplied to update the backend configuration.
+
+The `-migrate-state` option will attempt to copy existing state to the new
+backend, and depending on what changed, may result in interactive prompts to
+confirm migration of workspace states.  The `-force-copy` option suppresses
+these prompts and answers "yes" to the migration questions.
+Enabling `-force-copy` also automatically enables the `-migrate-state` option.
+
+The `-reconfigure` option disregards any existing configuration, preventing
+migration of any existing state.
+
+To skip backend configuration, use `-backend=false`. Note that some other init
+steps require an initialized backend, so it is recommended to use this flag only
+when the working directory was already previously initialized for a particular
+backend.
+
+The `-backend-config=...` option can be used for
+[partial backend configuration](/terraform/language/settings/backends/configuration#partial-configuration),
+in situations where the backend settings are dynamic or sensitive and so cannot
+be statically specified in the configuration file.
+
+## Child Module Installation
+
+During init, the configuration is searched for `module` blocks, and the source
+code for referenced [modules](/terraform/language/modules/develop) is retrieved from the locations
+given in their `source` arguments.
+
+Re-running init with modules already installed will install the sources for
+any modules that were added to configuration since the last init, but will not
+change any already-installed modules. Use `-upgrade` to override this behavior,
+updating all modules to the latest available source code.
+
+To skip child module installation, use `-get=false`. Note that some other init
+steps can complete only when the module tree is complete, so it's recommended
+to use this flag only when the working directory was already previously
+initialized with its child modules.
+
+## Plugin Installation
+
+Most Terraform providers are published separately from Terraform as plugins.
+During init, Terraform searches the configuration for both direct and indirect
+references to providers and attempts to install the plugins for those providers.
+
+For providers that are published in either
+[the public Terraform Registry](https://registry.terraform.io/) or in a
+third-party provider registry, `terraform init` will automatically find,
+download, and install the necessary provider plugins. If you cannot or do not
+wish to install providers from their origin registries, you can customize how
+Terraform installs providers using
+[the provider installation settings in the CLI configuration](/terraform/cli/config/config-file#provider-installation).
+
+For more information about specifying which providers are required for each
+of your modules, see [Provider Requirements](/terraform/language/providers/requirements).
+
+After successful installation, Terraform writes information about the selected
+providers to [the dependency lock file](/terraform/language/files/dependency-lock).
+You should commit this file to your version control system to ensure that
+when you run `terraform init` again in future Terraform will select exactly
+the same provider versions. Use the `-upgrade` option if you want Terraform
+to ignore the dependency lock file and consider installing newer versions.
+
+You can modify `terraform init`'s plugin behavior with the following options:
+
+* `-upgrade` Upgrade all previously-selected plugins to the newest version
+  that complies with the configuration's version constraints. This will
+  cause Terraform to ignore any selections recorded in the dependency lock
+  file, and to take the newest available version matching the configured
+  version constraints.
+* `-get-plugins=false` — Skip plugin installation.
+
+  -> Note: Since Terraform 0.13, this option has been superseded by the
+  [`provider_installation`](/terraform/cli/config/config-file#provider-installation) and
+  [`plugin_cache_dir`](/terraform/cli/config/config-file#plugin_cache_dir) settings.
+  It should not be used in Terraform versions 0.13+, and this option
+  was removed in Terraform 0.15.
+* `-plugin-dir=PATH` — Force plugin installation to read plugins _only_ from
+  the specified directory, as if it had been configured as a `filesystem_mirror`
+  in the CLI configuration. If you intend to routinely use a particular
+  filesystem mirror then we recommend
+  [configuring Terraform's installation methods globally](/terraform/cli/config/config-file#provider-installation).
+  You can use `-plugin-dir` as a one-time override for exceptional situations,
+  such as if you are testing a local build of a provider plugin you are
+  currently developing.
+* `-lockfile=MODE` Set a dependency lockfile mode.
+
+The valid values for the lockfile mode are as follows:
+
+* `readonly`: suppress the lockfile changes, but verify checksums against the
+  information already recorded. It conflicts with the `-upgrade` flag. If you
+  update the lockfile with third-party dependency management tools, it would be
+  useful to control when it changes explicitly.
+
+## Running `terraform init` in automation
+
+For teams that use Terraform as a key part of a change management and
+deployment pipeline, it can be desirable to orchestrate Terraform runs in some
+sort of automation in order to ensure consistency between runs, and provide
+other interesting features such as integration with version control hooks.
+
+There are some special concerns when running `init` in such an environment,
+including optionally making plugins available locally to avoid repeated
+re-installation. For more information, see
+the [Running Terraform in Automation](/terraform/tutorials/automation/automate-terraform?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+## Passing a Different Configuration Directory
+
+Terraform v0.13 and earlier also accepted a directory path in place of the
+plan file argument to `terraform apply`, in which case Terraform would use
+that directory as the root module instead of the current working directory.
+
+That usage is still supported in Terraform v0.14, but is now deprecated and removed in
+Terraform v0.15. If your workflow relies on overriding
+the root module directory, use
+[the `-chdir` global option](/terraform/cli/commands#switching-working-directory-with-chdir)
+instead, which works across all commands and makes Terraform consistently look
+in the given directory for all files it would normally read or write in the
+current working directory.
+
+If your previous use of this legacy pattern was also relying on Terraform
+writing the `.terraform` subdirectory into the current working directory even
+though the root module directory was overridden, use
+[the `TF_DATA_DIR` environment variable](/terraform/cli/config/environment-variables#tf_data_dir)
+to direct Terraform to write the `.terraform` directory to a location other
+than the current working directory.
diff --git a/v1.5.7/website/docs/cli/commands/login.mdx b/v1.5.7/website/docs/cli/commands/login.mdx
new file mode 100644
index 0000000..96f4e35
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/login.mdx
@@ -0,0 +1,45 @@
+---
+page_title: 'Command: login'
+description: >-
+  The terraform login command can be used to automatically obtain and save an
+  API token for Terraform Cloud, Terraform Enterprise, or any other host that
+  offers Terraform services.
+---
+
+# Command: login
+
+The `terraform login` command can be used to automatically obtain and save an
+API token for Terraform Cloud, Terraform Enterprise, or any other host that offers Terraform services.
+
+-> **Note:** This command is suitable only for use in interactive scenarios
+where it is possible to launch a web browser on the same host where Terraform
+is running. If you are running Terraform in an unattended automation scenario,
+you can
+[configure credentials manually in the CLI configuration](/terraform/cli/config/config-file#credentials).
+
+## Usage
+
+Usage: `terraform login [hostname]`
+
+If you don't provide an explicit hostname, Terraform will assume you want to
+log in to Terraform Cloud at `app.terraform.io`.
+
+## Credentials Storage
+
+By default, Terraform will obtain an API token and save it in plain text in a
+local CLI configuration file called `credentials.tfrc.json`. When you run
+`terraform login`, it will explain specifically where it intends to save
+the API token and give you a chance to cancel if the current configuration is
+not as desired.
+
+If you don't wish to store your API token in the default location, you can
+optionally configure a
+[credentials helper program](/terraform/cli/config/config-file#credentials-helpers) which knows
+how to store and later retrieve credentials in some other system, such as
+your organization's existing secrets management system.
+
+## Login Server Support
+
+The `terraform login` command works with any server supporting the
+[login protocol](/terraform/internals/login-protocol), including Terraform Cloud
+and Terraform Enterprise.
diff --git a/v1.5.7/website/docs/cli/commands/logout.mdx b/v1.5.7/website/docs/cli/commands/logout.mdx
new file mode 100644
index 0000000..cc1a888
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/logout.mdx
@@ -0,0 +1,29 @@
+---
+page_title: 'Command: logout'
+description: >-
+  The terraform logout command is used to remove credentials stored by terraform
+  login.
+---
+
+# Command: logout
+
+The `terraform logout` command is used to remove credentials stored by
+`terraform login`. These credentials are API tokens for Terraform Cloud,
+Terraform Enterprise, or any other host that offers Terraform services.
+
+## Usage
+
+Usage: `terraform logout [hostname]`
+
+If you don't provide an explicit hostname, Terraform will assume you want to
+log out of Terraform Cloud at `app.terraform.io`.
+
+-> **Note:** the API token is only removed from local storage, not destroyed on
+the remote server, so it will remain valid until manually revoked.
+
+## Credentials Storage
+
+By default, Terraform will remove the token stored in plain text in a local CLI
+configuration file called `credentials.tfrc.json`. If you have configured a
+[credentials helper program](/terraform/cli/config/config-file#credentials-helpers), Terraform
+will use the helper's `forget` command to remove it.
diff --git a/v1.5.7/website/docs/cli/commands/output.mdx b/v1.5.7/website/docs/cli/commands/output.mdx
new file mode 100644
index 0000000..8c4a5fd
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/output.mdx
@@ -0,0 +1,126 @@
+---
+page_title: 'Command: output'
+description: >-
+  The `terraform output` command is used to extract the value of an output
+  variable from the state file.
+---
+
+# Command: output
+
+The `terraform output` command is used to extract the value of
+an output variable from the state file.
+
+## Usage
+
+Usage: `terraform output [options] [NAME]`
+
+With no additional arguments, `output` will display all the outputs for
+the root module. If an output `NAME` is specified, only the value of that
+output is printed.
+
+The command-line flags are all optional. The following flags are available:
+
+* `-json` - If specified, the outputs are formatted as a JSON object, with
+  a key per output. If `NAME` is specified, only the output specified will be
+  returned. This can be piped into tools such as `jq` for further processing.
+* `-raw` - If specified, Terraform will convert the specified output value to a
+  string and print that string directly to the output, without any special
+  formatting. This can be convenient when working with shell scripts, but
+  it only supports string, number, and boolean values. Use `-json` instead
+  for processing complex data types.
+* `-no-color` - If specified, output won't contain any color.
+* `-state=path` - Path to the state file. Defaults to "terraform.tfstate".
+  Ignored when [remote state](/terraform/language/state/remote) is used.
+
+-> **Note:** When using the `-json` or `-raw` command-line flag, any sensitive
+values in Terraform state will be displayed in plain text. For more information,
+see [Sensitive Data in State](/terraform/language/state/sensitive-data).
+
+## Examples
+
+These examples assume the following Terraform output snippet.
+
+```hcl
+output "instance_ips" {
+  value = aws_instance.web.*.public_ip
+}
+
+output "lb_address" {
+  value = aws_alb.web.public_dns
+}
+
+output "password" {
+  sensitive = true
+  value = var.secret_password
+}
+```
+
+To list all outputs:
+
+```shellsession
+$ terraform output
+instance_ips = [
+  "54.43.114.12",
+  "52.122.13.4",
+  "52.4.116.53"
+]
+lb_address = "my-app-alb-1657023003.us-east-1.elb.amazonaws.com"
+password = <sensitive>
+```
+
+Note that outputs with the `sensitive` attribute will be redacted:
+
+```shellsession
+$ terraform output password
+password = <sensitive>
+```
+
+To query for the DNS address of the load balancer:
+
+```shellsession
+$ terraform output lb_address
+"my-app-alb-1657023003.us-east-1.elb.amazonaws.com"
+```
+
+To query for all instance IP addresses:
+
+```shellsession
+$ terraform output instance_ips
+instance_ips = [
+  "54.43.114.12",
+  "52.122.13.4",
+  "52.4.116.53"
+]
+```
+
+## Use in automation
+
+The `terraform output` command by default displays in a human-readable format,
+which can change over time to improve clarity.
+
+For scripting and automation, use `-json` to produce the stable JSON format.
+You can parse the output using a JSON command-line parser such as
+[jq](https://stedolan.github.io/jq/):
+
+```shellsession
+$ terraform output -json instance_ips | jq -r '.[0]'
+54.43.114.12
+```
+
+For the common case of directly using a string value in a shell script, you
+can use `-raw` instead, which will print the string directly with no extra
+escaping or whitespace.
+
+```shellsession
+$ terraform output -raw lb_address
+my-app-alb-1657023003.us-east-1.elb.amazonaws.com
+```
+
+The `-raw` option works only with values that Terraform can automatically
+convert to strings. Use `-json` instead, possibly combined with `jq`, to
+work with complex-typed values such as objects.
+
+Terraform strings are sequences of Unicode characters rather than raw bytes,
+so the `-raw` output will be UTF-8 encoded when it contains non-ASCII
+characters. If you need a different character encoding, use a separate command
+such as `iconv` to transcode Terraform's raw output.
diff --git a/v1.5.7/website/docs/cli/commands/plan.mdx b/v1.5.7/website/docs/cli/commands/plan.mdx
new file mode 100644
index 0000000..7aa7b42
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/plan.mdx
@@ -0,0 +1,365 @@
+---
+page_title: 'Command: plan'
+description: >-
+  The terraform plan command creates an execution plan with a preview of the
+  changes that Terraform will make to your infrastructure.
+---
+
+# Command: plan
+
+The `terraform plan` command creates an execution plan, which lets you preview
+the changes that Terraform plans to make to your infrastructure. By default,
+when Terraform creates a plan it:
+
+* Reads the current state of any already-existing remote objects to make sure
+  that the Terraform state is up-to-date.
+* Compares the current configuration to the prior state and noting any
+  differences.
+* Proposes a set of change actions that should, if applied, make the remote
+  objects match the configuration.
+
+> **Hands-on:** Try the [Terraform: Get Started](/terraform/tutorials/aws-get-started?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorials. For more in-depth details on the `plan` command, check out the [Create a Terraform Plan tutorial](/terraform/tutorials/cli/plan?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS).
+
+The `plan` command alone does not actually carry out the proposed changes You can use this command to check whether the proposed changes match what
+you expected before you apply the changes or share your changes with your
+team for broader review.
+
+If Terraform detects that no changes are needed to resource instances or to
+root module output values, `terraform plan` will report that no actions need
+to be taken.
+
+If you are using Terraform directly in an interactive terminal and you expect
+to apply the changes Terraform proposes, you can alternatively run
+[`terraform apply`](/terraform/cli/commands/apply) directly. By default, the "apply" command
+automatically generates a new plan and prompts for you to approve it.
+
+You can use the optional `-out=FILE` option to save the generated plan to a
+file on disk, which you can later execute by passing the file to
+[`terraform apply`](/terraform/cli/commands/apply) as an extra argument. This two-step workflow
+is primarily intended for when
+[running Terraform in automation](/terraform/tutorials/automation/automate-terraform?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS).
+
+If you run `terraform plan` without the `-out=FILE` option then it will create
+a _speculative plan_, which is a description of the effect of the plan but
+without any intent to actually apply it.
+
+In teams that use a version control and code review workflow for making changes
+to real infrastructure, developers can use speculative plans to verify the
+effect of their changes before submitting them for code review. However, it's
+important to consider that other changes made to the target system in the
+meantime might cause the final effect of a configuration change to be different
+than what an earlier speculative plan indicated, so you should always re-check
+the final non-speculative plan before applying to make sure that it still
+matches your intent.
+
+## Usage
+
+Usage: `terraform plan [options]`
+
+The `plan` subcommand looks in the current working directory for the root module
+configuration.
+
+Because the plan command is one of the main commands of Terraform, it has
+a variety of different options, described in the following sections. However,
+most of the time you should not need to set any of these options, because
+a Terraform configuration should typically be designed to work with no special
+additional options for routine work.
+
+The remaining sections on this page describe the various options:
+
+* **[Planning Modes](#planning-modes)**: There are some special alternative
+  planning modes that you can use for some special situations where your goal
+  is not just to change the remote system to match your configuration.
+* **[Planning Options](#planning-options)**: Alongside the special planning
+  modes, there are also some options you can set in order to customize the
+  planning process for unusual needs.
+  * **[Resource Targeting](#resource-targeting)** is one particular
+    special planning option that has some important caveats associated
+    with it.
+* **[Other Options](#other-options)**: These change the behavior of the planning
+  command itself, rather than customizing the content of the generated plan.
+
+## Planning Modes
+
+The previous section describes Terraform's default planning behavior, which
+changes the remote system to match the changes you make to
+your configuration. Terraform has two alternative planning modes, each of which creates a plan with a different intended outcome. These options are available for  both `terraform plan` and [`terraform apply`](/terraform/cli/commands/apply).
+
+* **Destroy mode:** creates a plan whose goal is to destroy all remote objects
+  that currently exist, leaving an empty Terraform state. It is the same as running [`terraform destroy`](/terraform/cli/commands/destroy). Destroy mode can be useful for situations like transient development environments, where the managed objects cease to be useful once the development task is complete.
+
+  Activate destroy mode using the `-destroy` command line option.
+
+* **Refresh-only mode:** creates a plan whose goal is only to update the
+  Terraform state and any root module output values to match changes made to
+  remote objects outside of Terraform. This can be useful if you've
+  intentionally changed one or more remote objects outside of the usual
+  workflow (e.g. while responding to an incident) and you now need to reconcile
+  Terraform's records with those changes.
+
+  Activate refresh-only mode using the `-refresh-only` command line option.
+
+In situations where we need to discuss the default planning mode that Terraform
+uses when none of the alternative modes are selected, we refer to it as
+"Normal mode". Because these alternative modes are for specialized situations
+only, some other Terraform documentation only discusses the normal planning
+mode.
+
+The planning modes are all mutually-exclusive, so activating any non-default
+planning mode disables the "normal" planning mode, and you can't use more than
+one alternative mode at the same time.
+
+-> **Note:** In Terraform v0.15 and earlier, the `-destroy` option is
+supported only by the `terraform plan` command, and not by the
+`terraform apply` command. To create and apply a plan in destroy mode in
+earlier versions you must run [`terraform destroy`](/terraform/cli/commands/destroy).
+
+-> **Note:** The `-refresh-only` option is available only in Terraform v0.15.4
+and later.
+
+> **Hands-on:** Try the [Use Refresh-Only Mode to Sync Terraform State](/terraform/tutorials/state/refresh) tutorial.
+
+## Planning Options
+
+In addition to alternate [planning modes](#planning-modes), there are several options that can modify planning behavior. These options are available for  both `terraform plan` and [`terraform apply`](/terraform/cli/commands/apply).
+
+- `-refresh=false` - Disables the default behavior of synchronizing the
+  Terraform state with remote objects before checking for configuration changes. This can make the planning operation faster by reducing the number of remote API requests. However, setting `refresh=false` causes Terraform to ignore external changes, which could result in an incomplete or incorrect plan. You cannot use `refresh=false` in refresh-only planning mode because it would effectively disable the entirety of the planning operation.
+
+- `-replace=ADDRESS` - Instructs Terraform to plan to replace the
+  resource instance with the given address. This is helpful when one or more remote objects have become degraded, and you can use replacement objects with the same configuration to align with immutable infrastructure patterns. Terraform will use a "replace" action if the specified resource would normally cause an "update" action or no action at all. Include this option multiple times to replace several objects at once. You cannot use `-replace` with the `-destroy` option, and it is only available from Terraform v0.15.2 onwards. For earlier versions, use [`terraform taint`](/terraform/cli/commands/taint) to achieve a similar result.
+
+- `-target=ADDRESS` - Instructs Terraform to focus its planning efforts only
+  on resource instances which match the given address and on any objects that
+  those instances depend on.
+
+  -> **Note:** Use `-target=ADDRESS` in exceptional circumstances only, such as recovering from mistakes or working around Terraform limitations. Refer to [Resource Targeting](#resource-targeting) for more details.
+
+- `-var 'NAME=VALUE'` - Sets a value for a single
+  [input variable](/terraform/language/values/variables) declared in the
+  root module of the configuration. Use this option multiple times to set
+  more than one variable. Refer to
+  [Input Variables on the Command Line](#input-variables-on-the-command-line) for more information.
+
+- `-var-file=FILENAME` - Sets values for potentially many
+  [input variables](/terraform/language/values/variables) declared in the
+  root module of the configuration, using definitions from a
+  ["tfvars" file](/terraform/language/values/variables#variable-definitions-tfvars-files).
+  Use this option multiple times to include values from more than one file.
+
+There are several other ways to set values for input variables in the root
+module, aside from the `-var` and `-var-file` options. Refer to
+[Assigning Values to Root Module Variables](/terraform/language/values/variables#assigning-values-to-root-module-variables) for more information.
+
+### Input Variables on the Command Line
+
+You can use the `-var` command line option to specify values for
+[input variables](/terraform/language/values/variables) declared in your
+root module.
+
+However, to do so will require writing a command line that is parsable both
+by your chosen command line shell _and_ Terraform, which can be complicated
+for expressions involving lots of quotes and escape sequences. In most cases
+we recommend using the `-var-file` option instead, and write your actual values
+in a separate file so that Terraform can parse them directly, rather than
+interpreting the result of your shell's parsing.
+
+~> **Warning:** Terraform will error if you include a space before or after the equals sign (e.g., `-var "length = 2"`).
+
+To use `-var` on a Unix-style shell on a system like Linux or macOS we
+recommend writing the option argument in single quotes `'` to ensure the
+shell will interpret the value literally:
+
+```
+terraform plan -var 'name=value'
+```
+
+If your intended value also includes a single quote then you'll still need to
+escape that for correct interpretation by your shell, which also requires
+temporarily ending the quoted sequence so that the backslash escape character
+will be significant:
+
+```
+terraform plan -var 'name=va'\''lue'
+```
+
+When using Terraform on Windows, we recommend using the Windows Command Prompt
+(`cmd.exe`). When you pass a variable value to Terraform from the Windows
+Command Prompt, use double quotes `"` around the argument:
+
+```
+terraform plan -var "name=value"
+```
+
+If your intended value includes literal double quotes then you'll need to
+escape those with a backslash:
+
+```
+terraform plan -var "name=va\"lue"
+```
+
+PowerShell on Windows cannot correctly pass literal quotes to external programs,
+so we do not recommend using Terraform with PowerShell when you are on Windows.
+Use Windows Command Prompt instead.
+
+The appropriate syntax for writing the variable value is different depending
+on the variable's [type constraint](/terraform/language/expressions/type-constraints).
+The primitive types `string`, `number`, and `bool` all expect a direct string
+value with no special punctuation except that required by your shell, as
+shown in the above examples. For all other type constraints, including list,
+map, and set types and the special `any` keyword, you must write a valid
+Terraform language expression representing the value, and write any necessary
+quoting or escape characters to ensure it will pass through your shell
+literally to Terraform. For example, for a `list(string)` type constraint:
+
+```
+# Unix-style shell
+terraform plan -var 'name=["a", "b", "c"]'
+
+# Windows Command Prompt (do not use PowerShell on Windows)
+terraform plan -var "name=[\"a\", \"b\", \"c\"]"
+```
+
+Similar constraints apply when setting input variables using environment
+variables. For more information on the various methods for setting root module
+input variables, see
+[Assigning Values to Root Module Variables](/terraform/language/values/variables#assigning-values-to-root-module-variables).
+
+### Resource Targeting
+
+> **Hands-on:** Try the [Target resources](/terraform/tutorials/state/resource-targeting?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+You can use the `-target` option to focus Terraform's attention on only a
+subset of resources.
+You can use [resource address syntax](/terraform/cli/state/resource-addressing)
+to specify the constraint. Terraform interprets the resource address as follows:
+
+* If the given address identifies one specific resource instance, Terraform
+  will select that instance alone. For resources with either `count` or
+  `for_each` set, a resource instance address must include the instance index
+  part, like `aws_instance.example[0]`.
+
+* If the given address identifies a resource as a whole, Terraform will select
+  all of the instances of that resource. For resources with either `count`
+  or `for_each` set, this means selecting _all_ instance indexes currently
+  associated with that resource. For single-instance resources (without
+  either `count` or `for_each`), the resource address and the resource instance
+  address are identical, so this possibility does not apply.
+
+* If the given address identifies an entire module instance, Terraform will
+  select all instances of all resources that belong to that module instance
+  and all of its child module instances.
+
+Once Terraform has selected one or more resource instances that you've directly
+targeted, it will also then extend the selection to include all other objects
+that those selections depend on either directly or indirectly.
+
+This targeting capability is provided for exceptional circumstances, such
+as recovering from mistakes or working around Terraform limitations. It
+is _not recommended_ to use `-target` for routine operations, since this can
+lead to undetected configuration drift and confusion about how the true state
+of resources relates to configuration.
+
+Instead of using `-target` as a means to operate on isolated portions of very
+large configurations, prefer instead to break large configurations into
+several smaller configurations that can each be independently applied.
+[Data sources](/terraform/language/data-sources) can be used to access
+information about resources created in other configurations, allowing
+a complex system architecture to be broken down into more manageable parts
+that can be updated independently.
+
+## Other Options
+
+The `terraform plan` command also has some other options that are related to
+the input and output of the planning command, rather than customizing what
+sort of plan Terraform will create. These commands are not necessarily also
+available on `terraform apply`, unless otherwise stated in the documentation
+for that command.
+
+The available options are:
+
+* `-compact-warnings` - Shows any warning messages in a compact form which
+  includes only the summary messages, unless the warnings are accompanied by
+  at least one error and thus the warning text might be useful context for
+  the errors.
+
+* `-detailed-exitcode` - Returns a detailed exit code when the command exits.
+  When provided, this argument changes the exit codes and their meanings to
+  provide more granular information about what the resulting plan contains:
+  * 0 = Succeeded with empty diff (no changes)
+  * 1 = Error
+  * 2 = Succeeded with non-empty diff (changes present)
+
+- `-generate-config-out=PATH` - (Experimental) If `import` blocks are present in configuration, instructs Terraform to generate HCL for any imported resources not already present. The configuration is written to a new file at PATH, which must not already exist, or Terraform will error. If the plan fails for another reason, Terraform may still attempt to write configuration.
+
+* `-input=false` - Disables Terraform's default behavior of prompting for
+  input for root module input variables that have not otherwise been assigned
+  a value. This option is particularly useful when running Terraform in
+  non-interactive automation systems.
+
+* `-json` - Enables the [machine readable JSON UI][machine-readable-ui] output.
+  This implies `-input=false`, so the configuration must have no unassigned
+  variable values to continue.
+
+  [machine-readable-ui]: /terraform/internals/machine-readable-ui
+
+* `-lock=false` - Don't hold a state lock during the operation. This is
+  dangerous if others might concurrently run commands against the same
+  workspace.
+
+* `-lock-timeout=DURATION` - Unless locking is disabled with `-lock=false`,
+  instructs Terraform to retry acquiring a lock for a period of time before
+  returning an error. The duration syntax is a number followed by a time
+  unit letter, such as "3s" for three seconds.
+
+* `-no-color` - Disables terminal formatting sequences in the output. Use this
+  if you are running Terraform in a context where its output will be
+  rendered by a system that cannot interpret terminal formatting.
+
+* `-out=FILENAME` - Writes the generated plan to the given filename in an
+  opaque file format that you can later pass to `terraform apply` to execute
+  the planned changes, and to some other Terraform commands that can work with
+  saved plan files.
+
+  Terraform will allow any filename for the plan file, but a typical
+  convention is to name it `tfplan`. **Do not** name the file with a suffix
+  that Terraform recognizes as another file format; if you use a `.tf` suffix
+  then Terraform will try to interpret the file as a configuration source
+  file, which will then cause syntax errors for subsequent commands.
+
+  The generated file is not in any standard format intended for consumption
+  by other software, but the file _does_ contain your full configuration,
+  all of the values associated with planned changes, and all of the plan
+  options including the input variables. If your plan includes any sort of
+  sensitive data, even if obscured in Terraform's terminal output, it will
+  be saved in cleartext in the plan file. You should therefore treat any
+  saved plan files as potentially-sensitive artifacts.
+
+* `-parallelism=n` - Limit the number of concurrent operations as Terraform
+  [walks the graph](/terraform/internals/graph#walking-the-graph). Defaults
+  to 10.
+
+For configurations using
+[the `local` backend](/terraform/language/settings/backends/local) only,
+`terraform plan` accepts the legacy command line option
+[`-state`](/terraform/language/settings/backends/local#command-line-arguments).
+
+### Passing a Different Configuration Directory
+
+Terraform v0.13 and earlier accepted an additional positional argument giving
+a directory path, in which case Terraform would use that directory as the root
+module instead of the current working directory.
+
+That usage was deprecated in Terraform v0.14 and removed in Terraform v0.15.
+If your workflow relies on overriding the root module directory, use
+[the `-chdir` global option](/terraform/cli/commands#switching-working-directory-with-chdir)
+instead, which works across all commands and makes Terraform consistently look
+in the given directory for all files it would normally read or write in the
+current working directory.
+
+If your previous use of this legacy pattern was also relying on Terraform
+writing the `.terraform` subdirectory into the current working directory even
+though the root module directory was overridden, use
+[the `TF_DATA_DIR` environment variable](/terraform/cli/config/environment-variables#tf_data_dir)
+to direct Terraform to write the `.terraform` directory to a location other
+than the current working directory.
diff --git a/v1.5.7/website/docs/cli/commands/providers.mdx b/v1.5.7/website/docs/cli/commands/providers.mdx
new file mode 100644
index 0000000..3222d8f
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/providers.mdx
@@ -0,0 +1,19 @@
+---
+page_title: 'Command: providers'
+description: >-
+  The terraform providers command prints information about the providers
+  required in the current configuration.
+---
+
+# Command: providers
+
+The `terraform providers` command shows information about the
+[provider requirements](/terraform/language/providers/requirements) of the
+configuration in the current working directory, as an aid to understanding
+where each requirement was detected from.
+
+This command also has several subcommands with different purposes.
+
+## Usage
+
+Usage: `terraform providers`
diff --git a/v1.5.7/website/docs/cli/commands/providers/lock.mdx b/v1.5.7/website/docs/cli/commands/providers/lock.mdx
new file mode 100644
index 0000000..c75455f
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/providers/lock.mdx
@@ -0,0 +1,168 @@
+---
+page_title: 'Command: providers lock'
+description: |-
+  The `terraform providers lock` command adds new provider selection information
+  to the dependency lock file without initializing the referenced providers.
+---
+
+# Command: terraform providers lock
+
+The `terraform providers lock` consults upstream registries (by default) in
+order to write provider dependency information into
+[the dependency lock file](/terraform/language/files/dependency-lock).
+
+The common way to update the dependency lock file is as a side-effect of normal
+provider installation during
+[`terraform init`](/terraform/cli/commands/init), but there are several situations where that
+automatic approach may not be sufficient:
+
+* If you are running Terraform in an environment that uses
+  [alternative provider installation methods](/terraform/cli/config/config-file#provider-installation),
+  such as filesystem or network mirrors, normal provider installation will not
+  access the origin registry for a provider and therefore Terraform will not
+  be able to populate all of the possible package checksums for the selected
+  provider versions.
+
+  If you use `terraform lock` to write the official release checksums for a
+  provider into the dependency lock file then future `terraform init` runs
+  will verify the packages available in your selected mirror against the
+  official checksums previously recorded, giving additional certainty that
+  the mirror is serving the provider packages it is claiming to.
+
+* If your team runs Terraform across a number of different platforms (e.g.
+  on both Windows and Linux) and the upstream registry for a provider is unable
+  to provide signed checksums using the latest hashing scheme, subsequent runs
+  of Terraform on other platforms may
+  [add additional checksums to the lock file](/terraform/language/files/dependency-lock#new-provider-package-checksums).
+  You can avoid that by pre-populating hashes for all of the platforms you
+  intend to use, using the `terraform providers lock` command.
+
+-> `terraform providers lock` is available only in Terraform v0.14 or later.
+
+## Usage
+
+Usage: `terraform providers lock [options] [providers...]`
+
+With no additional command line arguments, `terraform providers lock` will
+analyze the configuration in the current working directory to find all of
+the providers it depends on, and it will fetch the necessary data about those
+providers from their origin registries and then update
+[the dependency lock file](/terraform/language/files/dependency-lock) to
+include a selected version for each provider and all of the package checksums
+that are covered by the provider developer's cryptographic signature.
+
+~> **Warning:** The `terraform providers lock` command prints information
+about what it has fetched and whether each package was signed using a
+cryptographic signature, but it cannot automatically verify that the
+providers are trustworthy and that they comply with your local system
+policies or relevant regulations. Review the signing key information
+in the output to confirm that you trust all of the signers before committing
+the updated lock file to your version control system.
+
+If you list one or more provider source addresses on the command line then
+`terraform providers lock` will restrict its work only to those providers,
+leaving the lock entries for other providers (if any) unchanged.
+
+You can customize the default behavior using the following additional option:
+
+* `-fs-mirror=PATH` - Direct Terraform to look for provider packages in the
+  given local filesystem mirror directory, instead of in upstream registries.
+  The given directory must use the usual filesystem mirror directory layout.
+
+* `-net-mirror=URL` - Direct Terraform to look for provider packages in the
+  given network mirror service, instead of in upstream registries. The
+  given URL must implement
+  [the Terraform provider network mirror protocol](/terraform/internals/provider-network-mirror-protocol).
+
+* `-platform=OS_ARCH` - Specify a platform you intend to use to work with this
+  Terraform configuration. Terraform will ensure that the providers are all
+  available for the given platform and will save enough package checksums in
+  the lock file to support _at least_ the specified platforms.
+
+  Use this option multiple times to include checksums for multiple target
+  systems.
+
+  Target platform names consist of an operating system and a CPU
+  architecture. For example, `linux_amd64` selects the Linux operating system
+  running on an AMD64 or x86_64 CPU.
+
+  There is more detail on this option in the following section.
+
+## Specifying Target Platforms
+
+In your environment you may, for example, have both developers who work with
+your Terraform configuration on their Windows or macOS workstations _and_
+automated systems that apply the configuration while running on Linux.
+
+In that situation, you could choose to verify that all of your providers support
+all of those platforms, and to pre-populate the lock file with the necessary
+checksums, by running `terraform providers lock` and specifying those three
+platforms:
+
+```
+terraform providers lock \
+  -platform=windows_amd64 \ # 64-bit Windows
+  -platform=darwin_amd64 \  # 64-bit macOS
+  -platform=linux_amd64     # 64-bit Linux
+```
+
+(The above example uses Unix-style shell wrapping syntax for readability. If
+you are running the command on Windows then you will need to put all of the
+arguments on a single line, and remove the backslashes and comments.)
+
+## Lock Entries for In-house Providers
+
+An _in-house provider_ is one that isn't published on a real Terraform provider
+registry because it's developed and used only within a particular organization and
+distributed via either a filesystem mirror or network mirror.
+
+By default, `terraform providers lock` assumes all providers are available
+at a Terraform provider registry and tries to contact the origin registries
+in order to get access to the most detailed information about the provider
+packages.
+
+To create a lock entry for a particular provider that is available only in a
+local mirror, you can use either the `-fs-mirror` or `-net-mirror` command
+line options to override the default behavior of consulting the provider's
+origin registry:
+
+```
+terraform providers lock \
+  -fs-mirror=/usr/local/terraform/providers
+  -platform=windows_amd64 \
+  -platform=darwin_amd64 \
+  -platform=linux_amd64 \
+  tf.example.com/ourcompany/ourplatform
+```
+
+(The above example uses Unix-style shell wrapping syntax for readability. If
+you are running the command on Windows then you will need to put all of the
+arguments on a single line, and remove the backslashes.)
+
+Because the command above includes the provider source address
+`tf.example.com/ourcompany/ourplatform`, `terraform providers lock` will only
+attempt to access that particular provider and will leave the lock entries
+for any other providers unchanged. If you have a variety of different providers
+available from different sources, you can run `terraform providers lock`
+multiple times and specify a different subset of your providers each time.
+
+The `-fs-mirror` and `-net-mirror` options have the same meaning as
+`filesystem_mirror` and `network_mirror` blocks in
+[the provider installation methods configuration](/terraform/cli/config/config-file#provider-installation),
+but specify only a single method in order to be explicit about where you
+intend to derive the package checksum information from.
+
+Note that only an origin registry can provide official checksums covered by
+the original developer's cryptographic signature. Lock entries created from
+filesystem or network mirrors will therefore cover only the exact platforms
+you requested, and the recorded checksums will be those reported by the
+mirror, rather than the origin registry's official checksums. If you want
+to ensure that the recorded checksums are the ones signed by the original
+provider publisher, run this command _without_ either the `-fs-mirror` or
+`-net-mirror` options to fetch all information from origin registries.
+
+If you wish, you can publish your in-house providers via an in-house provider
+registry, which will then allow locking and installation of those providers
+without any special options or additional CLI configuration. For more
+information, see
+[the provider registry protocol](/terraform/internals/provider-registry-protocol).
diff --git a/v1.5.7/website/docs/cli/commands/providers/mirror.mdx b/v1.5.7/website/docs/cli/commands/providers/mirror.mdx
new file mode 100644
index 0000000..129c55a
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/providers/mirror.mdx
@@ -0,0 +1,63 @@
+---
+page_title: 'Command: providers mirror'
+description: |-
+  The `terraform providers mirror` command downloads the providers required
+  for the current configuration and copies them into a directory in the local
+  filesystem.
+---
+
+# Command: terraform providers mirror
+
+The `terraform providers mirror` command downloads the providers required
+for the current configuration and copies them into a directory in the local
+filesystem.
+
+In normal use, `terraform init` will automatically download needed providers
+from provider registries as part of initializing the current working directory.
+Sometimes Terraform is running in an environment where that isn't possible,
+such as on an isolated network without access to the Terraform Registry. In
+that case,
+[explicit installation method configuration](/terraform/cli/config/config-file#explicit-installation-method-configuration)
+allows you to configure Terraform, when running on a particular system, to
+consult only a local filesystem directory where you've created a local mirror
+of the necessary plugins, and to skip accessing the upstream registry at all.
+
+The `terraform providers mirror` command can automatically populate a directory
+that will be used as a local filesystem mirror in the provider installation
+configuration.
+
+-> `terraform providers mirror` is available only in Terraform v0.13 or later.
+
+## Usage
+
+Usage: `terraform providers mirror [options] <target-dir>`
+
+A single target directory is required. Terraform will create under that
+directory the path structure that is expected for filesystem-based provider
+plugin mirrors, populating it with `.zip` files containing the plugins
+themselves.
+
+Terraform will also generate various `.json` index files which contain suitable
+responses to implement
+[the network mirror protocol](/terraform/internals/provider-network-mirror-protocol),
+if you upload the resulting directory to a static website host. Terraform
+ignores those index files when using the directory as a filesystem mirror,
+because the directory entries themselves are authoritative in that case.
+
+This command supports the following additional option:
+
+* `-platform=OS_ARCH` - Choose which target platform to build a mirror for.
+  By default Terraform will obtain plugin packages suitable for the platform
+  where you run this command. Use this flag multiple times to include packages
+  for multiple target systems.
+
+  Target platform names consist of an operating system and a CPU
+  architecture. For example, `linux_amd64` selects the Linux operating system
+  running on an AMD64 or x86_64 CPU.
+
+You can run `terraform providers mirror` again on an existing mirror directory
+to update it with new packages. For example, you can add packages for a new
+target platform by re-running the command with the desired new `-platform=...`
+option, and it will place the packages for that new platform without removing
+packages you previously downloaded, merging the resulting set of packages
+together to update the JSON index files.
diff --git a/v1.5.7/website/docs/cli/commands/providers/schema.mdx b/v1.5.7/website/docs/cli/commands/providers/schema.mdx
new file mode 100644
index 0000000..3b24900
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/providers/schema.mdx
@@ -0,0 +1,151 @@
+---
+page_title: 'Command: providers schema'
+description: >-
+  The `terraform providers schema` command prints detailed schemas for the
+  providers used
+
+  in the current configuration.
+---
+
+# Command: terraform providers schema
+
+The `terraform providers schema` command is used to print detailed schemas for the providers used in the current configuration.
+
+-> `terraform providers schema` requires **Terraform v0.12 or later**.
+
+## Usage
+
+Usage: `terraform providers schema [options]`
+
+The following flags are available:
+
+- `-json` - Displays the schemas in a machine-readable, JSON format.
+
+Please note that, at this time, the `-json` flag is a _required_ option. In future releases, this command will be extended to allow for additional options.
+
+The output includes a `format_version` key, which as of Terraform 1.1.0 has
+value `"1.0"`. The semantics of this version are:
+
+- We will increment the minor version, e.g. `"1.1"`, for backward-compatible
+  changes or additions. Ignore any object properties with unrecognized names to
+  remain forward-compatible with future minor versions.
+- We will increment the major version, e.g. `"2.0"`, for changes that are not
+  backward-compatible. Reject any input which reports an unsupported major
+  version.
+
+We will introduce new major versions only within the bounds of
+[the Terraform 1.0 Compatibility Promises](/terraform/language/v1-compatibility-promises).
+
+## Format Summary
+
+The following sections describe the JSON output format by example, using a pseudo-JSON notation.
+Important elements are described with comments, which are prefixed with //.
+To avoid excessive repetition, we've split the complete format into several discrete sub-objects, described under separate headers. References wrapped in angle brackets (like `<block-representation>`) are placeholders which, in the real output, would be replaced by an instance of the specified sub-object.
+
+The JSON output format consists of the following objects and sub-objects:
+
+- [Providers Schema Representation](#providers-schema-representation) - the top-level object returned by `terraform providers schema -json`
+- [Schema Representation](#schema-representation) - a sub-object of providers, resources, and data sources that describes their schema
+- [Block Representation](#block-representation) - a sub-object of schemas that describes attributes and nested blocks
+
+## Providers Schema Representation
+
+```javascript
+{
+  "format_version": "1.0",
+
+  // "provider_schemas" describes the provider schemas for all
+  // providers throughout the configuration tree.
+  "provider_schemas": {
+    // keys in this map are the provider type, such as "random"
+    "example_provider_name": {
+      // "provider" is the schema for the provider configuration
+      "provider": <schema-representation>,
+
+      // "resource_schemas" map the resource type name to the resource's schema
+      "resource_schemas": {
+        "example_resource_name": <schema-representation>
+      },
+
+      // "data_source_schemas" map the data source type name to the
+      // data source's schema
+      "data_source_schemas": {
+        "example_datasource_name": <schema-representation>,
+      }
+    },
+    "example_provider_two": { … }
+  }
+}
+```
+
+## Schema Representation
+
+A schema representation pairs a provider or resource schema (in a "block") with that schema's version.
+
+```javascript
+{
+  // "version" is the schema version, not the provider version
+  "version": int64,
+  "block": <block-representation>
+}
+```
+
+## Block Representation
+
+A block representation contains "attributes" and "block_types" (which represent nested blocks).
+
+```javascript
+{
+  // "attributes" describes any attributes that appear directly inside the
+  // block. Keys in this map are the attribute names.
+  "attributes":  {
+    "example_attribute_name": {
+      // "type" is a representation of a type specification
+      // that the attribute's value must conform to.
+      "type": "string",
+
+      // "description" is an English-language description of
+      // the purpose and usage of the attribute.
+      "description": "string",
+
+      // "required", if set to true, specifies that an
+      // omitted or null value is not permitted.
+      "required": bool,
+
+      // "optional", if set to true, specifies that an
+      // omitted or null value is permitted.
+      "optional": bool,
+
+      // "computed", if set to true, indicates that the
+      // value comes from the provider rather than the
+      // configuration.
+      "computed": bool,
+
+      // "sensitive", if set to true, indicates that the
+      // attribute may contain sensitive information.
+      "sensitive": bool
+    },
+  },
+  // "block_types" describes any nested blocks that appear directly
+  // inside the block.
+  // Keys in this map are the names of the block_type.
+  "block_types": {
+    "example_block_name": {
+      // "nesting_mode" describes the nesting mode for the
+      // child block, and can be one of the following:
+      // 	single
+      // 	list
+      // 	set
+      // 	map
+    "nesting_mode": "list",
+    "block": <block-representation>,
+
+    // "min_items" and "max_items" set lower and upper
+    // limits on the number of child blocks allowed for
+    // the list and set modes. These are
+    // omitted for other modes.
+    "min_items": 1,
+    "max_items": 3
+  }
+}
+```
diff --git a/v1.5.7/website/docs/cli/commands/push.mdx b/v1.5.7/website/docs/cli/commands/push.mdx
new file mode 100644
index 0000000..4bbff18
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/push.mdx
@@ -0,0 +1,14 @@
+---
+page_title: 'Command: push'
+description: >-
+  DISCONTINUED. Terraform Cloud and the modern "remote" backend have replaced
+  the old `terraform push` command.
+---
+
+# Command: push
+
+!> **Important:** The `terraform push` command is no longer functional. We recommend the [Terraform Cloud CLI integration](/terraform/cli/cloud) instead, which allows you to run remote operations in Terraform Cloud directly from the command line.
+
+The `terraform push` command was an early implementation of remote Terraform runs. It allowed teams to push a configuration to a remote run environment in a discontinued version of Terraform Enterprise.
+
+The legacy Terraform Enterprise version that supported `terraform push` is no longer available, and there are no remaining instances of that version in operation. Without a service to push to, the command is now completely non-functional.
diff --git a/v1.5.7/website/docs/cli/commands/refresh.mdx b/v1.5.7/website/docs/cli/commands/refresh.mdx
new file mode 100644
index 0000000..d44f4f1
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/refresh.mdx
@@ -0,0 +1,68 @@
+---
+page_title: 'Command: refresh'
+description: |-
+  The `terraform refresh` command reads the current settings from all managed
+  remote objects and updates the Terraform state to match.
+---
+
+# Command: refresh
+
+> **Hands-on:** Try the [Use Refresh-Only Mode to Sync Terraform State](/terraform/tutorials/state/refresh) tutorial.
+
+The `terraform refresh` command reads the current settings from all managed
+remote objects and updates the Terraform state to match.
+
+~> _Warning:_ This command is deprecated, because its default behavior is
+unsafe if you have misconfigured credentials for any of your providers.
+See below for more information and recommended alternatives.
+
+This won't modify your real remote objects, but it will modify the
+[Terraform state](/terraform/language/state).
+
+You shouldn't typically need to use this command, because Terraform
+automatically performs the same refreshing actions as a part of creating
+a plan in both the
+[`terraform plan`](/terraform/cli/commands/plan)
+and
+[`terraform apply`](/terraform/cli/commands/apply)
+commands. This command is here primarily for backward compatibility, but
+we don't recommend using it because it provides no opportunity to review
+the effects of the operation before updating the state.
+
+## Usage
+
+Usage: `terraform refresh [options]`
+
+This command is effectively an alias for the following command:
+
+```
+terraform apply -refresh-only -auto-approve
+```
+
+Consequently, it supports all of the same options as
+[`terraform apply`](/terraform/cli/commands/apply) except that it does not accept a saved
+plan file, it doesn't allow selecting a planning mode other than "refresh only",
+and `-auto-approve` is always enabled.
+
+Automatically applying the effect of a refresh is risky. If you have
+misconfigured credentials for one or more providers, Terraform may
+be misled into thinking that all of the managed objects have been deleted,
+causing it to remove all of the tracked objects without any confirmation prompt.
+
+Instead, we recommend using the following command in order to get the same
+effect but with the opportunity to review the changes that Terraform has
+detected before committing them to the state:
+
+```
+terraform apply -refresh-only
+```
+
+This alternative command will present an interactive prompt for you to confirm
+the detected changes.
+
+The `-refresh-only` option for `terraform plan` and `terraform apply` was
+introduced in Terraform v0.15.4. For prior versions you must use
+`terraform refresh` directly if you need this behavior, while taking into
+account the warnings above. Wherever possible, avoid using `terraform refresh`
+explicitly and instead rely on Terraform's behavior of automatically refreshing
+existing objects as part of creating a normal plan.
diff --git a/v1.5.7/website/docs/cli/commands/show.mdx b/v1.5.7/website/docs/cli/commands/show.mdx
new file mode 100644
index 0000000..cbde69f
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/show.mdx
@@ -0,0 +1,54 @@
+---
+page_title: 'Command: show'
+description: >-
+  The `terraform show` command is used to provide human-readable output from a
+  state or plan file. This can be used to inspect a plan to ensure that the
+  planned operations are expected, or to inspect the current state as Terraform
+  sees it.
+---
+
+# Command: show
+
+The `terraform show` command is used to provide human-readable output
+from a state or plan file. This can be used to inspect a plan to ensure
+that the planned operations are expected, or to inspect the current state
+as Terraform sees it.
+
+Machine-readable output is generated by adding the `-json` command-line
+flag.
+
+-> **Note:** When using the `-json` command-line flag, any sensitive values in
+Terraform state will be displayed in plain text. For more information, see
+[Sensitive Data in State](/terraform/language/state/sensitive-data).
+
+## JSON Output
+
+For Terraform state files (including when no path is provided),
+`terraform show -json` will show a JSON representation of the state.
+
+For Terraform plan files, `terraform show -json` will show a JSON representation
+of the plan, configuration, and current state.
+
+If you've updated providers which contain new schema versions since the state
+was written, the state needs to be upgraded before it can be displayed with
+`show -json`. If you are viewing a plan, it must be created without
+`-refresh=false`. If you are viewing a state file, run `terraform refresh`
+first.
+
+The output format is covered in detail in [JSON Output Format](/terraform/internals/json-format).
+
+## Usage
+
+Usage: `terraform show [options] [file]`
+
+You may use `show` with a path to either a Terraform state file or plan
+file. If you don't specify a file path, Terraform will show the latest state
+snapshot.
+
+This command accepts the following options:
+
+* `-no-color` - Disables output with coloring
+
+* `-json` - Displays machine-readable output from a state or plan file
+
+-> JSON output via the `-json` option requires **Terraform v0.12 or later**.
diff --git a/v1.5.7/website/docs/cli/commands/state/index.mdx b/v1.5.7/website/docs/cli/commands/state/index.mdx
new file mode 100644
index 0000000..0d5a46b
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/state/index.mdx
@@ -0,0 +1,50 @@
+---
+page_title: 'Command: state'
+description: The `terraform state` command is used for advanced state management.
+---
+
+# State Command
+
+The `terraform state` command is used for advanced state management.
+As your Terraform usage becomes more advanced, there are some cases where
+you may need to modify the [Terraform state](/terraform/language/state).
+Rather than modify the state directly, the `terraform state` commands can
+be used in many cases instead.
+
+This command is a nested subcommand, meaning that it has further subcommands.
+These subcommands are listed to the left.
+
+## Usage
+
+Usage: `terraform state <subcommand> [options] [args]`
+
+Please click a subcommand to the left for more information.
+
+## Remote State
+
+The Terraform state subcommands all work with remote state just as if it
+was local state. Reads and writes may take longer than normal as each read
+and each write do a full network roundtrip. Otherwise, backups are still
+written to disk and the CLI usage is the same as if it were local state.
+
+## Backups
+
+All `terraform state` subcommands that modify the state write backup
+files. The path of these backup file can be controlled with `-backup`.
+
+Subcommands that are read-only (such as [list](/terraform/cli/commands/state/list))
+do not write any backup files since they aren't modifying the state.
+
+Note that backups for state modification _can not be disabled_. Due to
+the sensitivity of the state file, Terraform forces every state modification
+command to write a backup file. You'll have to remove these files manually
+if you don't want to keep them around.
+
+## Command-Line Friendly
+
+The output and command-line structure of the state subcommands is
+designed to be usable with Unix command-line tools such as grep, awk,
+and similar PowerShell commands.
+
+For advanced filtering and modification, we recommend piping Terraform
+state subcommands together with other command line tools.
diff --git a/v1.5.7/website/docs/cli/commands/state/list.mdx b/v1.5.7/website/docs/cli/commands/state/list.mdx
new file mode 100644
index 0000000..8471fbe
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/state/list.mdx
@@ -0,0 +1,76 @@
+---
+page_title: 'Command: state list'
+description: >-
+  The terraform state list command is used to list resources within a Terraform
+  state.
+---
+
+# Command: state list
+
+The `terraform state list` command is used to list resources within a
+[Terraform state](/terraform/language/state).
+
+## Usage
+
+Usage: `terraform state list [options] [address...]`
+
+The command will list all resources in the state file matching the given
+addresses (if any). If no addresses are given, all resources are listed.
+
+The resources listed are sorted according to module depth order followed
+by alphabetical. This means that resources that are in your immediate
+configuration are listed first, and resources that are more deeply nested
+within modules are listed last.
+
+For complex infrastructures, the state can contain thousands of resources.
+To filter these, provide one or more patterns to the command. Patterns are
+in [resource addressing format](/terraform/cli/state/resource-addressing).
+
+The command-line flags are all optional. The following flags are available:
+
+* `-state=path` - Path to the state file. Defaults to "terraform.tfstate".
+  Ignored when [remote state](/terraform/language/state/remote) is used.
+* `-id=id` - ID of resources to show. Ignored when unset.
+
+## Example: All Resources
+
+This example will list all resources, including modules:
+
+```
+$ terraform state list
+aws_instance.foo
+aws_instance.bar[0]
+aws_instance.bar[1]
+module.elb.aws_elb.main
+```
+
+## Example: Filtering by Resource
+
+This example will only list resources for the given name:
+
+```
+$ terraform state list aws_instance.bar
+aws_instance.bar[0]
+aws_instance.bar[1]
+```
+
+## Example: Filtering by Module
+
+This example will list resources in the given module and any submodules:
+
+```
+$ terraform state list module.elb
+module.elb.aws_elb.main
+module.elb.module.secgroups.aws_security_group.sg
+```
+
+## Example: Filtering by ID
+
+This example will only list the resource whose ID is specified on the
+command line. This is useful to find where in your configuration a
+specific resource is located.
+
+```
+$ terraform state list -id=sg-1234abcd
+module.elb.aws_security_group.sg
+```
diff --git a/v1.5.7/website/docs/cli/commands/state/mv.mdx b/v1.5.7/website/docs/cli/commands/state/mv.mdx
new file mode 100644
index 0000000..4c124bf
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/state/mv.mdx
@@ -0,0 +1,191 @@
+---
+page_title: 'Command: state mv'
+description: >-
+  The `terraform state mv` command changes bindings in Terraform state,
+  associating existing remote objects with new resource instances.
+---
+
+# Command: state mv
+
+The main function of [Terraform state](/terraform/language/state) is
+to track the bindings between resource instance addresses in your configuration
+and the remote objects they represent. Normally Terraform automatically
+updates the state in response to actions taken when applying a plan, such as
+removing a binding for an remote object that has now been deleted.
+
+You can use `terraform state mv` in the less common situation where you wish
+to retain an existing remote object but track it as a different resource
+instance address in Terraform, such as if you have renamed a resource block
+or you have moved it into a different module in your configuration.
+
+## Usage
+
+Usage: `terraform state mv [options] SOURCE DESTINATION`
+
+Terraform will look in the current state for a resource instance, resource,
+or module that matches the given address, and if successful it will move the
+remote objects currently associated with the source to be tracked instead
+by the destination.
+
+Both the source and destination addresses must use
+[resource address syntax](/terraform/cli/state/resource-addressing), and
+they must both refer to the same kind of object: you can only move a resource
+instance to another resource instance, a whole module instance to another
+whole module instance, etc. Furthermore, if you are moving a resource or
+a resource instance then you can only move it to a new address with the
+same resource type.
+
+The most common uses for `terraform state mv` are when you have renamed a
+resource block in your configuration or you've moved a resource block into
+a child module, in both cases with the intention of retaining the existing
+object but tracking it under a new name. By default Terraform will understand
+moving or renaming a resource configuration as a request to delete the old
+object and create a new object at the new address, and so `terraform state mv`
+allows you to override that interpretation by pre-emptively attaching the
+existing object to the new address in Terraform.
+
+~> _Warning:_ If you are using Terraform in a collaborative environment, you
+must ensure that when you are using `terraform state mv` for a code refactoring
+purpose you communicate carefully with your coworkers to ensure that nobody
+makes any other changes between your configuration change and your
+`terraform state mv` command, because otherwise they might inadvertently create
+a plan that will destroy the old object and create a new object at the new
+address.
+
+This command also accepts the following options:
+
+- `-dry-run` - Report all of the resource instances that match the given
+  address without actually "forgetting" any of them.
+
+- `-lock=false` - Don't hold a state lock during the operation. This is
+  dangerous if others might concurrently run commands against the same
+  workspace.
+
+- `-lock-timeout=DURATION` - Unless locking is disabled with `-lock=false`,
+  instructs Terraform to retry acquiring a lock for a period of time before
+  returning an error. The duration syntax is a number followed by a time
+  unit letter, such as "3s" for three seconds.
+
+For configurations using the [Terraform Cloud CLI integration](/terraform/cli/cloud) or the [`remote` backend](/terraform/language/settings/backends/remote)
+only, `terraform state mv`
+also accepts the option
+[`-ignore-remote-version`](/terraform/cli/cloud/command-line-arguments#ignore-remote-version).
+
+The legacy options [`-backup` and `-backup-out`](/terraform/language/settings/backends/local#command-line-arguments)
+operate on a local state file only. Configurations using
+[the `remote` backend](/terraform/language/settings/backends/remote)
+must specify a local state file with the [`-state`](/terraform/language/settings/backends/local#command-line-arguments)
+option in order to use the [`-backup` and `-backup-out`](/terraform/language/settings/backends/local#command-line-arguments)
+options.
+
+For configurations using
+[the `local` state mv](/terraform/language/settings/backends/local) only,
+`terraform state mv` also accepts the legacy options
+[`-state`, `-state-out`, `-backup`, and `-backup-out`](/terraform/language/settings/backends/local#command-line-arguments).
+
+## Example: Rename a Resource
+
+Renaming a resource means making a configuration change like the following:
+
+```diff
+-resource "packet_device" "worker" {
++resource "packet_device" "helper" {
+   # ...
+ }
+```
+
+To tell Terraform that it should treat the new "helper" resource as a rename
+of the old "worker" resource, you can pair the above configuration change
+with the following command:
+
+```shell
+terraform state mv packet_device.worker packet_device.helper
+```
+
+## Example: Move a Resource Into a Module
+
+If you originally wrote a resource in your root module but now wish to refactor
+it into a child module, you can move the `resource` block into the child
+module configuration, removing the original in the root module, and then
+run the following command to tell Terraform to treat it as a move:
+
+```shell
+terraform state mv packet_device.worker module.worker.packet_device.worker
+```
+
+In the above example the new resource has the same name but a different module
+address. You could also change the resource name at the same time, if the new
+module organization suggests a different naming scheme:
+
+```shell
+terraform state mv packet_device.worker module.worker.packet_device.main
+```
+
+## Example: Move a Module Into a Module
+
+You can also refactor an entire module into a child module. In the
+configuration, move the `module` block representing the module into a different
+module and then pair that change with a command like the following:
+
+```shell
+terraform state mv module.app module.parent.module.app
+```
+
+## Example: Move a Particular Instance of a Resource using `count`
+
+A resource defined with [the `count` meta-argument](/terraform/language/meta-arguments/count)
+has multiple instances that are each identified by an integer. You can
+select a particular instance by including an explicit index in your given
+address:
+
+```shell
+$ terraform state mv 'packet_device.worker[0]' 'packet_device.helper[0]'
+```
+
+A resource that doesn't use `count` or `for_each` has only a single resource
+instance whose address is the same as the resource itself, and so you can
+move from an address not containing an index to an address containing an index,
+or the opposite, as long as the address type you use matches whether and how
+each resource is configured:
+
+```shell
+$ terraform state mv 'packet_device.main' 'packet_device.all[0]'
+```
+
+Brackets (`[`, `]`) have a special meaning in some shells, so you may need to
+quote or escape the address in order to pass it literally to Terraform.
+The above examples show the typical quoting syntax for Unix-style shells.
+
+## Example: Move a Resource configured with for_each
+
+A resource defined with [the `for_each` meta-argument](/terraform/language/meta-arguments/for_each)
+has multiple instances that are each identified by an string. You can
+select a particular instance by including an explicit key in your given
+address.
+
+However, the syntax for strings includes quotes and the quote symbol often
+has special meaning in command shells, so you'll need to use the appropriate
+quoting and/or escaping syntax for the shell you are using. For example:
+
+Unix-style shells, such as on Linux or macOS:
+
+```shell
+terraform state mv 'packet_device.worker["example123"]' 'packet_device.helper["example456"]'
+```
+
+Windows Command Prompt (`cmd.exe`):
+
+```shell
+terraform state mv packet_device.worker[\"example123\"] packet_device.helper[\"example456\"]
+```
+
+PowerShell:
+
+```shell
+terraform state mv 'packet_device.worker[\"example123\"]' 'packet_device.helper[\"example456\"]'
+```
+
+Aside from the use of strings instead of integers for instance keys, the
+treatment of `for_each` resources is similar to `count` resources and so
+the same combinations of addresses with and without index components is
+valid as described in the previous section.
diff --git a/v1.5.7/website/docs/cli/commands/state/pull.mdx b/v1.5.7/website/docs/cli/commands/state/pull.mdx
new file mode 100644
index 0000000..115b5c6
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/state/pull.mdx
@@ -0,0 +1,30 @@
+---
+page_title: 'Command: state pull'
+description: >-
+  The `terraform state pull` command is used to manually download and output the
+  state from remote state.
+---
+
+# Command: state pull
+
+The `terraform state pull` command is used to manually download and output
+the state from [remote state](/terraform/language/state/remote). This command also
+works with local state.
+
+## Usage
+
+Usage: `terraform state pull`
+
+This command downloads the state from its current location, upgrades the
+local copy to the latest state file version that is compatible with
+locally-installed Terraform, and outputs the raw format to stdout.
+
+This is useful for reading values out of state (potentially pairing this
+command with something like [jq](https://stedolan.github.io/jq/)). It is
+also useful if you need to make manual modifications to state.
+
+You cannot use this command to inspect the Terraform version of
+the remote state, as it will always be converted to the current Terraform
+version before output.
+
+-> **Note:** Terraform state files must be in UTF-8 format without a byte order mark (BOM). For PowerShell on Windows, use `Set-Content` to automatically encode files in UTF-8 format. For example, run `terraform state pull | sc terraform.tfstate`.
diff --git a/v1.5.7/website/docs/cli/commands/state/push.mdx b/v1.5.7/website/docs/cli/commands/state/push.mdx
new file mode 100644
index 0000000..2372c5a
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/state/push.mdx
@@ -0,0 +1,48 @@
+---
+page_title: 'Command: state push'
+description: The `terraform state push` command pushes items to the Terraform state.
+---
+
+# Command: state push
+
+The `terraform state push` command is used to manually upload a local
+state file to [remote state](/terraform/language/state/remote). This command also
+works with local state.
+
+This command should rarely be used. It is meant only as a utility in case
+manual intervention is necessary with the remote state.
+
+## Usage
+
+Usage: `terraform state push [options] PATH`
+
+This command pushes the state specified by PATH to the currently
+configured [backend](/terraform/language/settings/backends/configuration).
+
+If PATH is "-" then the state data to push is read from stdin. This data
+is loaded completely into memory and verified prior to being written to
+the destination state.
+
+-> **Note:** Terraform state files must be in UTF-8 format without a byte order mark (BOM). For PowerShell on Windows, use `Set-Content` to automatically encode files in UTF-8 format. For example, run `terraform state push | sc terraform.tfstate`.
+
+Terraform will perform a number of safety checks to prevent you from
+making changes that appear to be unsafe:
+
+- **Differing lineage**: If the "lineage" value in the state differs,
+  Terraform will not allow you to push the state. A differing lineage
+  suggests that the states are completely different and you may lose
+  data.
+
+- **Higher remote serial**: If the "serial" value in the destination state
+  is higher than the state being pushed, Terraform will prevent the push.
+  A higher serial suggests that data is in the destination state that isn't
+  accounted for in the local state being pushed.
+
+Both of these safety checks can be disabled with the `-force` flag.
+**This is not recommended.** If you disable the safety checks and are
+pushing state, the destination state will be overwritten.
+
+For configurations using the [Terraform Cloud CLI integration](/terraform/cli/cloud) or the [`remote` backend](/terraform/language/settings/backends/remote)
+only, `terraform state push`
+also accepts the option
+[`-ignore-remote-version`](/terraform/cli/cloud/command-line-arguments#ignore-remote-version).
diff --git a/v1.5.7/website/docs/cli/commands/state/replace-provider.mdx b/v1.5.7/website/docs/cli/commands/state/replace-provider.mdx
new file mode 100644
index 0000000..1c63601
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/state/replace-provider.mdx
@@ -0,0 +1,51 @@
+---
+page_title: 'Command: state replace-provider'
+description: >-
+  The `terraform state replace-provider` command replaces the provider for
+  resources in the Terraform state.
+---
+
+# Command: state replace-provider
+
+The `terraform state replace-provider` command is used to replace the provider
+for resources in a [Terraform state](/terraform/language/state).
+
+## Usage
+
+Usage: `terraform state replace-provider [options] FROM_PROVIDER_FQN TO_PROVIDER_FQN`
+
+This command will update all resources using the "from" provider, setting the
+provider to the specified "to" provider. This allows changing the source of a
+provider which currently has resources in state.
+
+This command will output a backup copy of the state prior to saving any
+changes. The backup cannot be disabled. Due to the destructive nature
+of this command, backups are required.
+
+This command also accepts the following options:
+
+- `-auto-approve` - Skip interactive approval.
+
+- `-lock=false` - Don't hold a state lock during the operation. This is
+  dangerous if others might concurrently run commands against the same
+  workspace.
+
+- `-lock-timeout=0s` - Duration to retry a state lock.
+
+For configurations using the [Terraform Cloud CLI integration](/terraform/cli/cloud) or the [`remote` backend](/terraform/language/settings/backends/remote)
+only, `terraform state replace-provider`
+also accepts the option
+[`-ignore-remote-version`](/terraform/cli/cloud/command-line-arguments#ignore-remote-version).
+
+For configurations using
+[the `local` state](/terraform/language/settings/backends/local) only,
+`terraform state replace-provider` also accepts the legacy options
+[`-state`, `-state-out`, and `-backup`](/terraform/language/settings/backends/local#command-line-arguments).
+
+## Example
+
+The example below replaces the `hashicorp/aws` provider with a fork by `acme`, hosted at a private registry at `registry.acme.corp`:
+
+```shell
+$ terraform state replace-provider hashicorp/aws registry.acme.corp/acme/aws
+```
diff --git a/v1.5.7/website/docs/cli/commands/state/rm.mdx b/v1.5.7/website/docs/cli/commands/state/rm.mdx
new file mode 100644
index 0000000..7391f9a
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/state/rm.mdx
@@ -0,0 +1,135 @@
+---
+page_title: 'Command: state rm'
+description: >-
+  The `terraform state rm` command removes bindings from the Terraform state,
+  causing Terraform to "forget about" existing objects.
+---
+
+# Command: state rm
+
+The main function of [Terraform state](/terraform/language/state) is
+to track the bindings between resource instance addresses in your configuration
+and the remote objects they represent. Normally Terraform automatically
+updates the state in response to actions taken when applying a plan, such as
+removing a binding for a remote object that has now been deleted.
+
+You can use `terraform state rm` in the less common situation where you wish
+to remove a binding to an existing remote object without first destroying it,
+which will effectively make Terraform "forget" the object while it continues
+to exist in the remote system.
+
+## Usage
+
+Usage: `terraform state rm [options] ADDRESS...`
+
+Terraform will search the state for any instances matching the given
+[resource address](/terraform/cli/state/resource-addressing), and remove
+the record of each one so that Terraform will no longer be tracking the
+corresponding remote objects.
+
+This means that although the objects will still continue to exist in the
+remote system, a subsequent
+[`terraform plan`](/terraform/cli/commands/plan)
+will include an action to create a new object for each of the "forgotten"
+instances. Depending on the constraints imposed by the remote system, creating
+those objects might fail if their names or other identifiers conflict with
+the old objects still present.
+
+This command also accepts the following options:
+
+- `-dry-run` - Report all of the resource instances that match the given
+  address without actually "forgetting" any of them.
+
+- `-lock=false` - Don't hold a state lock during the operation. This is
+  dangerous if others might concurrently run commands against the same
+  workspace.
+
+- `-lock-timeout=DURATION` - Unless locking is disabled with `-lock=false`,
+  instructs Terraform to retry acquiring a lock for a period of time before
+  returning an error. The duration syntax is a number followed by a time
+  unit letter, such as "3s" for three seconds.
+
+For configurations using the [Terraform Cloud CLI integration](/terraform/cli/cloud) or the [`remote` backend](/terraform/language/settings/backends/remote)
+only, `terraform state rm`
+also accepts the option
+[`-ignore-remote-version`](/terraform/cli/cloud/command-line-arguments#ignore-remote-version).
+
+For configurations using
+[the `local` state rm](/terraform/language/settings/backends/local) only,
+`terraform state rm` also accepts the legacy options
+[`-state`, `-state-out`, and `-backup`](/terraform/language/settings/backends/local#command-line-arguments).
+
+## Example: Remove all Instances of a Resource
+
+The following example will cause Terraform to "forget" all of the instances
+of the `packet_device` resource named "worker".
+
+```shell
+$ terraform state rm 'packet_device.worker'
+```
+
+A resource that doesn't use `count` or `for_each` has only one instance, so
+this is also the appropriate syntax to select that single instance.
+
+## Example: Remove all Instances of a Resource in a Module
+
+To select a resource that you've defined in a child module you must specify
+the path of that module as part of the resource address:
+
+```shell
+$ terraform state rm 'module.foo.packet_device.worker'
+```
+
+## Example: Remove all Instances of all Resources in a Module
+
+The following example will cause Terraform to "forget" all of the instances
+associated with all resources defined in all instances of the module named
+`foo`:
+
+```shell
+$ terraform state rm 'module.foo'
+```
+
+## Example: Remove a Particular Instance of a Resource using `count`
+
+A resource defined with [the `count` meta-argument](/terraform/language/meta-arguments/count)
+has multiple instances that are each identified by an integer. You can
+select a particular instance by including an explicit index in your given
+address:
+
+```shell
+$ terraform state rm 'packet_device.worker[0]'
+```
+
+Brackets (`[`, `]`) have a special meaning in some shells, so you may need to
+quote or escape the address in order to pass it literally to Terraform.
+The above shows the typical quoting syntax for Unix-style shells.
+
+## Example: Remove a Particular Instance of a Resource using `for_each`
+
+A resource defined with [the `for_each` meta-argument](/terraform/language/meta-arguments/for_each)
+has multiple instances that are each identified by an string. You can
+select a particular instance by including an explicit key in your given
+address.
+
+However, the syntax for strings includes quotes and the quote symbol often
+has special meaning in command shells, so you'll need to use the appropriate
+quoting and/or escaping syntax for the shell you are using. For example:
+
+Unix-style shells, such as on Linux or macOS:
+
+```shell
+$ terraform state rm 'packet_device.worker["example"]'
+```
+
+Windows Command Prompt (`cmd.exe`):
+
+```shell
+$ terraform state rm packet_device.worker[\"example\"]
+```
+
+PowerShell:
+
+```shell
+$ terraform state rm 'packet_device.worker[\"example\"]'
+```
diff --git a/v1.5.7/website/docs/cli/commands/state/show.mdx b/v1.5.7/website/docs/cli/commands/state/show.mdx
new file mode 100644
index 0000000..b646362
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/state/show.mdx
@@ -0,0 +1,89 @@
+---
+page_title: 'Command: state show'
+description: >-
+  The `terraform state show` command is used to show the attributes of a single
+  resource in the Terraform state.
+---
+
+# Command: state show
+
+The `terraform state show` command is used to show the attributes of a
+single resource in the
+[Terraform state](/terraform/language/state).
+
+## Usage
+
+Usage: `terraform state show [options] ADDRESS`
+
+The command will show the attributes of a single resource in the
+state file that matches the given address.
+
+This command requires an address that points to a single resource in the
+state. Addresses are
+in [resource addressing format](/terraform/cli/state/resource-addressing).
+
+The command-line flags are all optional. The following flags are available:
+
+* `-state=path` - Path to the state file. Defaults to "terraform.tfstate".
+  Ignored when [remote state](/terraform/language/state/remote) is used.
+
+The output of `terraform state show` is intended for human consumption, not
+programmatic consumption. To extract state data for use in other software, use
+[`terraform show -json`](/terraform/cli/commands/show#json-output) and decode the result
+using the documented structure.
+
+## Example: Show a Resource
+
+The example below shows a `packet_device` resource named `worker`:
+
+```
+$ terraform state show 'packet_device.worker'
+# packet_device.worker:
+resource "packet_device" "worker" {
+    billing_cycle = "hourly"
+    created       = "2015-12-17T00:06:56Z"
+    facility      = "ewr1"
+    hostname      = "prod-xyz01"
+    id            = "6015bg2b-b8c4-4925-aad2-f0671d5d3b13"
+    locked        = false
+}
+```
+
+## Example: Show a Module Resource
+
+The example below shows a `packet_device` resource named `worker` inside a module named `foo`:
+
+```shell
+$ terraform state show 'module.foo.packet_device.worker'
+```
+
+## Example: Show a Resource configured with count
+
+The example below shows the first instance of a `packet_device` resource named `worker` configured with
+[`count`](/terraform/language/meta-arguments/count):
+
+```shell
+$ terraform state show 'packet_device.worker[0]'
+```
+
+## Example: Show a Resource configured with for_each
+
+The following example shows the `"example"` instance of a `packet_device` resource named `worker` configured with the [`for_each`](/terraform/language/meta-arguments/for_each) meta-argument. You must place the resource name in single quotes when it contains special characters like double quotes.
+
+Linux, Mac OS, and UNIX:
+
+```shell
+$ terraform state show 'packet_device.worker["example"]'
+```
+
+PowerShell:
+
+```shell
+$ terraform state show 'packet_device.worker[\"example\"]'
+```
+
+Windows `cmd.exe`:
+
+```shell
+$ terraform state show packet_device.worker[\"example\"]
+```
diff --git a/v1.5.7/website/docs/cli/commands/taint.mdx b/v1.5.7/website/docs/cli/commands/taint.mdx
new file mode 100644
index 0000000..c96a437
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/taint.mdx
@@ -0,0 +1,65 @@
+---
+page_title: 'Command: taint'
+description: |-
+  The `terraform taint` command informs Terraform that a particular object
+  is damaged or degraded.
+---
+
+# Command: taint
+
+The `terraform taint` command informs Terraform that a particular object has
+become degraded or damaged. Terraform represents this by marking the
+object as "tainted" in the Terraform state, and Terraform will
+propose to replace it in the next plan you create.
+
+~> **Warning:** This command is deprecated. For Terraform v0.15.2 and later, we recommend using the `-replace` option with `terraform apply` instead (details below).
+
+## Recommended Alternative
+
+For Terraform v0.15.2 and later, we recommend using the [`-replace` option](/terraform/cli/commands/plan#replace-address) with `terraform apply` to force Terraform to replace an object even though there are no configuration changes that would require it.
+
+```
+$ terraform apply -replace="aws_instance.example[0]"
+```
+
+We recommend the `-replace` option because the change will be reflected in the Terraform plan, letting you understand how it will affect your infrastructure before you take any externally-visible action. When you use `terraform taint`, other users could create a new plan against your tainted object before you can review the effects.
+
+## Usage
+
+```
+$ terraform taint [options] <address>
+```
+
+The `address` argument is the address of the resource to mark as tainted.
+The address is in
+[the resource address syntax](/terraform/cli/state/resource-addressing),
+as shown in the output from other commands, such as:
+
+- `aws_instance.foo`
+- `aws_instance.bar[1]`
+- `aws_instance.baz[\"key\"]` (quotes in resource addresses must be escaped on the command line, so that they will not be interpreted by your shell)
+- `module.foo.module.bar.aws_instance.qux`
+
+This command accepts the following options:
+
+- `-allow-missing` - If specified, the command will succeed (exit code 0)
+  even if the resource is missing. The command might still return an error
+  for other situations, such as if there is a problem reading or writing
+  the state.
+
+- `-lock=false` - Disables Terraform's default behavior of attempting to take
+  a read/write lock on the state for the duration of the operation.
+
+- `-lock-timeout=DURATION` - Unless locking is disabled with `-lock=false`,
+  instructs Terraform to retry acquiring a lock for a period of time before
+  returning an error. The duration syntax is a number followed by a time
+  unit letter, such as "3s" for three seconds.
+
+For configurations using the [Terraform Cloud CLI integration](/terraform/cli/cloud) or the [`remote` backend](/terraform/language/settings/backends/remote) only, `terraform taint`
+also accepts the option
+[`-ignore-remote-version`](/terraform/cli/cloud/command-line-arguments#ignore-remote-version).
+
+For configurations using
+[the `local` backend](/terraform/language/settings/backends/local) only,
+`terraform taint` also accepts the legacy options
+[`-state`, `-state-out`, and `-backup`](/terraform/language/settings/backends/local#command-line-arguments).
diff --git a/v1.5.7/website/docs/cli/commands/test.mdx b/v1.5.7/website/docs/cli/commands/test.mdx
new file mode 100644
index 0000000..57f9e9d
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/test.mdx
@@ -0,0 +1,13 @@
+---
+page_title: 'Command: test'
+description: Part of the ongoing design research for module integration testing.
+---
+
+# Command: test
+
+The `terraform test` command is currently serving as part of
+[the module integration testing experiment](/terraform/language/modules/testing-experiment).
+
+It's not ready for routine use, but if you'd be interested in trying the
+prototype functionality then we'd love to hear your feedback. See the
+experiment details page linked above for more information.
diff --git a/v1.5.7/website/docs/cli/commands/untaint.mdx b/v1.5.7/website/docs/cli/commands/untaint.mdx
new file mode 100644
index 0000000..98fb32a
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/untaint.mdx
@@ -0,0 +1,72 @@
+---
+page_title: 'Command: untaint'
+description: |-
+  The `terraform untaint` command tells Terraform that an object is functioning
+  correctly, even though its creation failed or it was previously manually
+  marked as degraded.
+---
+
+# Command: untaint
+
+Terraform has a marker called "tainted" which it uses to track that an object
+might be damaged and so a future Terraform plan ought to replace it.
+
+Terraform automatically marks an object as "tainted" if an error occurs during
+a multi-step "create" action, because Terraform can't be sure that the object
+was left in a fully-functional state.
+
+You can also manually mark an object as "tainted" using the deprecated command
+[`terraform taint`](/terraform/cli/commands/taint), although we no longer recommend that
+workflow.
+
+If Terraform currently considers a particular object as tainted but you've
+determined that it's actually functioning correctly and need _not_ be replaced,
+you can use `terraform untaint` to remove the taint marker from that object.
+
+This command _will not_ modify any real remote objects, but will modify the
+state in order to remove the tainted status.
+
+If you remove the taint marker from an object but then later discover that it
+was degraded after all, you can create and apply a plan to replace it without
+first re-tainting the object, by using a command like the following:
+
+```
+terraform apply -replace="aws_instance.example[0]"
+```
+
+## Usage
+
+Usage: `terraform untaint [options] address`
+
+The `address` argument is a [resource address](/terraform/cli/state/resource-addressing)
+identifying a particular resource instance which is currently tainted.
+
+This command also accepts the following options:
+
+- `-allow-missing` - If specified, the command will succeed (exit code 0)
+  even if the resource is missing. The command might still return an error
+  for other situations, such as if there is a problem reading or writing
+  the state.
+
+- `-lock=false` - Don't hold a state lock during the operation. This is
+  dangerous if others might concurrently run commands against the same
+  workspace.
+
+- `-lock-timeout=DURATION` - Unless locking is disabled with `-lock=false`,
+  instructs Terraform to retry acquiring a lock for a period of time before
+  returning an error. The duration syntax is a number followed by a time
+  unit letter, such as "3s" for three seconds.
+
+- `-no-color` - Disables terminal formatting sequences in the output. Use this
+  if you are running Terraform in a context where its output will be
+  rendered by a system that cannot interpret terminal formatting.
+
+For configurations using the [Terraform Cloud CLI integration](/terraform/cli/cloud) or the [`remote` backend](/terraform/language/settings/backends/remote)
+only, `terraform untaint`
+also accepts the option
+[`-ignore-remote-version`](/terraform/cli/cloud/command-line-arguments#ignore-remote-version).
+
+For configurations using
+[the `local` backend](/terraform/language/settings/backends/local) only,
+`terraform untaint` also accepts the legacy options
+[`-state`, `-state-out`, and `-backup`](/terraform/language/settings/backends/local#command-line-arguments).
diff --git a/v1.5.7/website/docs/cli/commands/validate.mdx b/v1.5.7/website/docs/cli/commands/validate.mdx
new file mode 100644
index 0000000..1ae22f3
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/validate.mdx
@@ -0,0 +1,213 @@
+---
+page_title: 'Command: validate'
+description: >-
+  The `terraform validate` command is used to validate the syntax of the
+  terraform files.
+---
+
+# Command: validate
+
+The `terraform validate` command validates the configuration files in a
+directory, referring only to the configuration and not accessing any remote
+services such as remote state, provider APIs, etc.
+
+Validate runs checks that verify whether a configuration is syntactically
+valid and internally consistent, regardless of any provided variables or
+existing state. It is thus primarily useful for general verification of
+reusable modules, including correctness of attribute names and value types.
+
+It is safe to run this command automatically, for example as a post-save
+check in a text editor or as a test step for a re-usable module in a CI
+system.
+
+Validation requires an initialized working directory with any referenced plugins and modules installed. To initialize a working directory for validation without accessing any configured backend, use:
+
+```
+$ terraform init -backend=false
+```
+
+To verify configuration in the context of a particular run (a particular
+target workspace, input variable values, etc), use the `terraform plan`
+command instead, which includes an implied validation check.
+
+## Usage
+
+Usage: `terraform validate [options]`
+
+This command accepts the following options:
+
+* `-json` - Produce output in a machine-readable JSON format, suitable for
+  use in text editor integrations and other automated systems. Always disables
+  color.
+
+* `-no-color` - If specified, output won't contain any color.
+
+## JSON Output Format
+
+When you use the `-json` option, Terraform will produce validation results
+in JSON format to allow using the validation result for tool integrations, such
+as highlighting errors in a text editor.
+
+As with all JSON output options, it's possible that Terraform will encounter
+an error prior to beginning the validation task that will thus not be subject
+to the JSON output setting. For that reason, external software consuming
+Terraform's output should be prepared to find data on stdout that _isn't_ valid
+JSON, which it should then treat as a generic error case.
+
+The output includes a `format_version` key, which as of Terraform 1.1.0 has
+value `"1.0"`. The semantics of this version are:
+
+* We will increment the minor version, e.g. `"1.1"`, for backward-compatible
+  changes or additions. Ignore any object properties with unrecognized names to
+  remain forward-compatible with future minor versions.
+* We will increment the major version, e.g. `"2.0"`, for changes that are not
+  backward-compatible. Reject any input which reports an unsupported major
+  version.
+
+We will introduce new major versions only within the bounds of
+[the Terraform 1.0 Compatibility Promises](/terraform/language/v1-compatibility-promises).
+
+In the normal case, Terraform will print a JSON object to the standard output
+stream. The top-level JSON object will have the following properties:
+
+- `valid` (boolean): Summarizes the overall validation result, by indicating
+  `true` if Terraform considers the current configuration to be valid or
+  `false` if it detected any errors.
+
+- `error_count` (number): A zero or positive whole number giving the count
+  of errors Terraform detected. If `valid` is `true` then `error_count` will
+  always be zero, because it is the presence of errors that indicates that
+  a configuration is invalid.
+
+- `warning_count` (number): A zero or positive whole number giving the count
+  of warnings Terraform detected. Warnings do not cause Terraform to consider
+  a configuration to be invalid, but they do indicate potential caveats that
+  a user should consider and possibly resolve.
+
+- `diagnostics` (array of objects): A JSON array of nested objects that each
+  describe an error or warning from Terraform.
+
+The nested objects in `diagnostics` have the following properties:
+
+- `severity` (string): A string keyword, either `"error"` or
+  `"warning"`, indicating the diagnostic severity.
+
+  The presence of errors causes Terraform to consider a configuration to be
+  invalid, while warnings are just advice or caveats to the user which do not
+  block working with the configuration. Later versions of Terraform may
+  introduce new severity keywords, so consumers should be prepared to accept
+  and ignore severity values they don't understand.
+
+- `summary` (string): A short description of the nature of the problem that
+  the diagnostic is reporting.
+
+  In Terraform's usual human-oriented diagnostic messages, the summary serves
+  as a sort of "heading" for the diagnostic, printed after the "Error:" or
+  "Warning:" indicator.
+
+  Summaries are typically short, single sentences, but can sometimes be longer
+  as a result of returning errors from subsystems that are not designed to
+  return full diagnostics, where the entire error message therefore becomes the
+  summary. In those cases, the summary might include newline characters which
+  a renderer should honor when presenting the message visually to a user.
+
+- `detail` (string): An optional additional message giving more detail about
+  the problem.
+
+  In Terraform's usual human-oriented diagnostic messages, the detail provides
+  the paragraphs of text that appear after the heading and the source location
+  reference.
+
+  Detail messages are often multiple paragraphs and possibly interspersed with
+  non-paragraph lines, so tools which aim to present detail messages to the
+  user should distinguish between lines without leading spaces, treating them
+  as paragraphs, and lines with leading spaces, treating them as preformatted
+  text. Renderers should then soft-wrap the paragraphs to fit the width of the
+  rendering container, but leave the preformatted lines unwrapped.
+
+  Some Terraform detail messages contain an approximation of bullet
+  lists using ASCII characters to mark the bullets. This is not a
+  contractural formatting convention, so renderers should avoid depending on
+  it and should instead treat those lines as either paragraphs or preformatted
+  text. Future versions of this format may define additional rules for other text conventions, but will maintain backward compatibility.
+
+- `range` (object): An optional object referencing a portion of the configuration
+  source code that the diagnostic message relates to. For errors, this will
+  typically indicate the bounds of the specific block header, attribute, or
+  expression which was detected as invalid.
+
+  A source range is an object with a property `filename` which gives the
+  filename as a relative path from the current working directory, and then
+  two properties `start` and `end` which are both themselves objects
+  describing source positions, as described below.
+
+  Not all diagnostic messages are connected with specific portions of the
+  configuration, so `range` will be omitted or `null` for diagnostic messages
+  where it isn't relevant.
+
+- `snippet` (object): An optional object including an excerpt of the
+  configuration source code that the diagnostic message relates to.
+
+  The snippet information includes:
+
+  - `context` (string): An optional summary of the root context of the
+    diagnostic. For example, this might be the resource block containing the
+    expression which triggered the diagnostic. For some diagnostics this
+    information is not available, and then this property will be `null`.
+
+  - `code` (string): A snippet of Terraform configuration including the
+    source of the diagnostic. This can be multiple lines and may include
+    additional configuration source code around the expression which
+    triggered the diagnostic.
+
+  - `start_line` (number): A one-based line count representing the position
+    in the source file at which the `code` excerpt begins. This is not
+    necessarily the same value as `range.start.line`, as it is possible for
+    `code` to include one or more lines of context before the source of the
+    diagnostic.
+
+  - `highlight_start_offset` (number): A zero-based character offset into the
+    `code` string, pointing at the start of the expression which triggered
+    the diagnostic.
+
+  - `highlight_end_offset` (number): A zero-based character offset into the
+    `code` string, pointing at the end of the expression which triggered the
+    diagnostic.
+
+  - `values` (array of objects): Contains zero or more expression values
+    which may be useful in understanding the source of a diagnostic in a
+    complex expression. These expression value objects are described below.
+
+### Source Position
+
+A source position object, as used in the `range` property of a diagnostic
+object, has the following properties:
+
+- `byte` (number): A zero-based byte offset into the indicated file.
+
+- `line` (number): A one-based line count for the line containing the relevant
+  position in the indicated file.
+
+- `column` (number): A one-based count of _Unicode characters_ from the start
+  of the line indicated in `line`.
+
+A `start` position is inclusive while an `end` position is exclusive. The
+exact positions used for particular error messages are intended for human
+interpretation only.
+
+### Expression Value
+
+An expression value object gives additional information about a value which is
+part of the expression which triggered the diagnostic. This is especially
+useful when using `for_each` or similar constructs, in order to identify
+exactly which values are responsible for an error. The object has two properties:
+
+- `traversal` (string): An HCL-like traversal string, such as
+  `var.instance_count`. Complex index key values may be elided, so this will
+  not always be valid, parseable HCL. The contents of this string are intended
+  to be human-readable.
+
+- `statement` (string): A short English-language fragment describing the value
+  of the expression when the diagnostic was triggered. The contents of this
+  string are intended to be human-readable and are subject to change in future
+  versions of Terraform.
diff --git a/v1.5.7/website/docs/cli/commands/version.mdx b/v1.5.7/website/docs/cli/commands/version.mdx
new file mode 100644
index 0000000..378ec3a
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/version.mdx
@@ -0,0 +1,54 @@
+---
+page_title: 'Command: version'
+description: >-
+  The terraform version command displays the Terraform version and the version
+  of all installed plugins.
+---
+
+# Command: version
+
+The `terraform version` displays the current version of Terraform and all
+installed plugins.
+
+## Usage
+
+Usage: `terraform version [options]`
+
+With no additional arguments, `version` will display the version of Terraform,
+the platform it's installed on, installed providers, and the results of upgrade
+and security checks [unless disabled](/terraform/cli/commands#upgrade-and-security-bulletin-checks).
+
+This command has one optional flag:
+
+* `-json` - If specified, the version information is formatted as a JSON object,
+  and no upgrade or security information is included.
+
+-> **Note:** Platform information was added to the `version` command in Terraform 0.15.
+
+## Example
+
+Basic usage, with upgrade and security information shown if relevant:
+
+```shellsession
+$ terraform version
+Terraform v0.15.0
+on darwin_amd64
++ provider registry.terraform.io/hashicorp/null v3.0.0
+
+Your version of Terraform is out of date! The latest version
+is X.Y.Z. You can update by downloading from https://www.terraform.io/downloads.html
+```
+
+As JSON:
+
+```shellsession
+$ terraform version -json
+{
+  "terraform_version": "0.15.0",
+  "platform": "darwin_amd64",
+  "provider_selections": {
+    "registry.terraform.io/hashicorp/null": "3.0.0"
+  },
+  "terraform_outdated": true
+}
+```
diff --git a/v1.5.7/website/docs/cli/commands/workspace/delete.mdx b/v1.5.7/website/docs/cli/commands/workspace/delete.mdx
new file mode 100644
index 0000000..8475440
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/workspace/delete.mdx
@@ -0,0 +1,43 @@
+---
+page_title: 'Command: workspace delete'
+description: The terraform workspace delete command is used to delete a workspace.
+---
+
+# Command: workspace delete
+
+The `terraform workspace delete` command is used to delete an existing workspace.
+
+## Usage
+
+Usage: `terraform workspace delete [OPTIONS] NAME [DIR]`
+
+This command will delete the specified workspace.
+
+To delete a workspace, it must already exist, it must not be tracking resources,
+and it must not be your current workspace. If the workspace is tracking resources,
+Terraform will not allow you to delete it unless the `-force` flag is specified.
+
+Additionally, different [backends](/terraform/language/settings/backends/configuration#backend-types) may implement other
+restrictions on whether a workspace is considered safe to delete without the `-force` flag, such as whether the workspace is locked.
+
+If you delete a workspace which is tracking resources (via `-force`), then resources
+may become "dangling". These are resources that physically exist but that
+Terraform can no longer manage. This is sometimes preferred: you may want
+Terraform to stop managing resources, so they can be managed some other way.
+Most of the time, however, this is not intended and so Terraform protects you
+from getting into this situation.
+
+The command-line flags are all optional. The only supported flags are:
+
+* `-force` - Delete the workspace even if it is tracking resources. After deletion, Terraform can no longer track or manage the workspace's infrastructure. Defaults to false.
+* `-lock=false` - Don't hold a state lock during the operation. This is
+  dangerous if others might concurrently run commands against the same
+  workspace.
+* `-lock-timeout=DURATION` - Duration to retry a state lock. Default 0s.
+
+## Example
+
+```
+$ terraform workspace delete example
+Deleted workspace "example".
+```
diff --git a/v1.5.7/website/docs/cli/commands/workspace/index.mdx b/v1.5.7/website/docs/cli/commands/workspace/index.mdx
new file mode 100644
index 0000000..d3a9798
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/workspace/index.mdx
@@ -0,0 +1,17 @@
+---
+page_title: 'Command: workspace'
+description: The workspace command helps you manage workspaces.
+---
+
+# Command: workspace
+
+The `terraform workspace` command is used to manage
+[workspaces](/terraform/language/state/workspaces).
+
+This command is a container for further subcommands that each have their own page in the documentation.
+
+## Usage
+
+Usage: `terraform workspace <subcommand> [options] [args]`
+
+Choose a subcommand page for more information.
diff --git a/v1.5.7/website/docs/cli/commands/workspace/list.mdx b/v1.5.7/website/docs/cli/commands/workspace/list.mdx
new file mode 100644
index 0000000..d7d2e6e
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/workspace/list.mdx
@@ -0,0 +1,24 @@
+---
+page_title: 'Command: workspace list'
+description: The terraform workspace list command is used to list all existing workspaces.
+---
+
+# Command: workspace list
+
+The `terraform workspace list` command is used to list all existing workspaces.
+
+## Usage
+
+Usage: `terraform workspace list [DIR]`
+
+The command will list all existing workspaces. The current workspace is
+indicated using an asterisk (`*`) marker.
+
+## Example
+
+```
+$ terraform workspace list
+  default
+* development
+  jsmith-test
+```
diff --git a/v1.5.7/website/docs/cli/commands/workspace/new.mdx b/v1.5.7/website/docs/cli/commands/workspace/new.mdx
new file mode 100644
index 0000000..28b4d1c
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/workspace/new.mdx
@@ -0,0 +1,50 @@
+---
+page_title: 'Command: workspace new'
+description: The terraform workspace new command is used to create a new workspace.
+---
+
+# Command: workspace new
+
+The `terraform workspace new` command is used to create a new workspace.
+
+## Usage
+
+Usage: `terraform workspace new [OPTIONS] NAME [DIR]`
+
+This command will create a new workspace with the given name. A workspace with
+this name must not already exist.
+
+If the `-state` flag is given, the state specified by the given path
+will be copied to initialize the state for this new workspace.
+
+The command-line flags are all optional. The supported flags are:
+
+* `-lock=false` - Don't hold a state lock during the operation. This is
+  dangerous if others might concurrently run commands against the same
+  workspace.
+* `-lock-timeout=DURATION` - Duration to retry a state lock. Default 0s.
+* `-state=path`   - Path to an existing state file to initialize the state of this environment.
+
+## Example: Create
+
+```
+$ terraform workspace new example
+Created and switched to workspace "example"!
+
+You're now on a new, empty workspace. Workspaces isolate their state,
+so if you run "terraform plan" Terraform will not see any existing state
+for this configuration.
+```
+
+## Example: Create from State
+
+To create a new workspace from a pre-existing local state file:
+
+```
+$ terraform workspace new -state=old.terraform.tfstate example
+Created and switched to workspace "example".
+
+You're now on a new, empty workspace. Workspaces isolate their state,
+so if you run "terraform plan" Terraform will not see any existing state
+for this configuration.
+```
diff --git a/v1.5.7/website/docs/cli/commands/workspace/select.mdx b/v1.5.7/website/docs/cli/commands/workspace/select.mdx
new file mode 100644
index 0000000..497a565
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/workspace/select.mdx
@@ -0,0 +1,32 @@
+---
+page_title: 'Command: workspace select'
+description: The terraform workspace select command is used to choose a workspace.
+---
+
+# Command: workspace select
+
+The `terraform workspace select` command is used to choose a different
+workspace to use for further operations.
+
+## Usage
+
+Usage: `terraform workspace select NAME [DIR]`
+
+This command will select another workspace. The named workspace must already
+exist.
+
+The supported flags are:
+
+* `-or-create` - If the workspace that is being selected does not exist, create it. Default is `false`.
+
+## Example
+
+```
+$ terraform workspace list
+  default
+* development
+  jsmith-test
+
+$ terraform workspace select default
+Switched to workspace "default".
+```
diff --git a/v1.5.7/website/docs/cli/commands/workspace/show.mdx b/v1.5.7/website/docs/cli/commands/workspace/show.mdx
new file mode 100644
index 0000000..c6063f2
--- /dev/null
+++ b/v1.5.7/website/docs/cli/commands/workspace/show.mdx
@@ -0,0 +1,21 @@
+---
+page_title: 'Command: workspace show'
+description: The terraform workspace show command is used to output the current workspace.
+---
+
+# Command: workspace show
+
+The `terraform workspace show` command is used to output the current workspace.
+
+## Usage
+
+Usage: `terraform workspace show`
+
+The command will display the current workspace.
+
+## Example
+
+```
+$ terraform workspace show
+development
+```
diff --git a/v1.5.7/website/docs/cli/config/config-file.mdx b/v1.5.7/website/docs/cli/config/config-file.mdx
new file mode 100644
index 0000000..c3884f6
--- /dev/null
+++ b/v1.5.7/website/docs/cli/config/config-file.mdx
@@ -0,0 +1,533 @@
+---
+page_title: CLI Configuration
+description: >-
+  Learn to use the CLI configuration file to customize your CLI settings,
+  including credentials, plugin caching, provider installation methods, etc.
+---
+
+# CLI Configuration File (`.terraformrc` or `terraform.rc`)
+
+The CLI configuration file configures per-user settings for CLI behaviors,
+which apply across all Terraform working directories. This is separate from
+[your infrastructure configuration](/terraform/language).
+
+## Locations
+
+The configuration can be placed in a single file whose location depends
+on the host operating system:
+
+* On Windows, the file must be named `terraform.rc` and placed
+  in the relevant user's `%APPDATA%` directory. The physical location
+  of this directory depends on your Windows version and system configuration;
+  use `$env:APPDATA` in PowerShell to find its location on your system.
+* On all other systems, the file must be named `.terraformrc` (note
+  the leading period) and placed directly in the home directory
+  of the relevant user.
+
+On Windows, beware of Windows Explorer's default behavior of hiding filename
+extensions. Terraform will not recognize a file named `terraform.rc.txt` as a
+CLI configuration file, even though Windows Explorer may _display_ its name
+as just `terraform.rc`. Use `dir` from PowerShell or Command Prompt to
+confirm the filename.
+
+The location of the Terraform CLI configuration file can also be specified
+using the `TF_CLI_CONFIG_FILE` [environment variable](/terraform/cli/config/environment-variables).
+Any such file should follow the naming pattern `*.tfrc`.
+
+## Configuration File Syntax
+
+The configuration file uses the same _HCL_ syntax as `.tf` files, but with
+different attributes and blocks. The following example illustrates the
+general syntax; see the following section for information on the meaning
+of each of these settings:
+
+```hcl
+plugin_cache_dir   = "$HOME/.terraform.d/plugin-cache"
+disable_checkpoint = true
+```
+
+## Available Settings
+
+The following settings can be set in the CLI configuration file:
+
+* `credentials` - configures credentials for use with Terraform Cloud or
+  Terraform Enterprise. See [Credentials](#credentials) below for more
+  information.
+
+* `credentials_helper` - configures an external helper program for the storage
+  and retrieval of credentials for Terraform Cloud or Terraform Enterprise.
+  See [Credentials Helpers](#credentials-helpers) below for more information.
+
+* `disable_checkpoint` — when set to `true`, disables
+  [upgrade and security bulletin checks](/terraform/cli/commands#upgrade-and-security-bulletin-checks)
+  that require reaching out to HashiCorp-provided network services.
+
+* `disable_checkpoint_signature` — when set to `true`, allows the upgrade and
+  security bulletin checks described above but disables the use of an anonymous
+  id used to de-duplicate warning messages.
+
+* `plugin_cache_dir` — enables
+  [plugin caching](#provider-plugin-cache)
+  and specifies, as a string, the location of the plugin cache directory.
+
+* `provider_installation` - customizes the installation methods used by
+  `terraform init` when installing provider plugins. See
+  [Provider Installation](#provider-installation) below for more information.
+
+## Credentials
+
+[Terraform Cloud](https://cloud.hashicorp.com/products/terraform) provides a number of remote network
+services for use with Terraform, and
+[Terraform Enterprise](/terraform/enterprise) allows hosting those
+services inside your own infrastructure. For example, these systems offer both
+[remote operations](/terraform/cloud-docs/run/cli) and a
+[private module registry](/terraform/cloud-docs/registry).
+
+When interacting with Terraform-specific network services, Terraform expects
+to find API tokens in CLI configuration files in `credentials` blocks:
+
+```hcl
+credentials "app.terraform.io" {
+  token = "xxxxxx.atlasv1.zzzzzzzzzzzzz"
+}
+```
+
+If you are running the Terraform CLI interactively on a computer with a web browser, you can use [the `terraform login` command](/terraform/cli/commands/login)
+to get credentials and automatically save them in the CLI configuration. If
+not, you can manually write `credentials` blocks.
+
+You can have multiple `credentials` blocks if you regularly use services from
+multiple hosts. Many users will configure only one, for either
+Terraform Cloud (at `app.terraform.io`) or for their organization's own
+Terraform Enterprise host. Each `credentials` block contains a `token` argument
+giving the API token to use for that host.
+
+~> **Important:** If you are using Terraform Cloud or Terraform Enterprise,
+the token provided must be either a
+[user token](/terraform/cloud-docs/users-teams-organizations/users#api-tokens)
+or a
+[team token](/terraform/cloud-docs/users-teams-organizations/api-tokens#team-api-tokens);
+organization tokens cannot be used for command-line Terraform actions.
+
+-> **Note:** The credentials hostname must match the hostname in your module
+sources and/or backend configuration. If your Terraform Enterprise instance
+is available at multiple hostnames, use only one of them consistently.
+Terraform Cloud responds to API calls at both its current hostname
+`app.terraform.io`, and its historical hostname `atlas.hashicorp.com`.
+
+### Environment Variable Credentials
+
+-> **Note:** Environment variable credentials are supported in Terraform v1.2.0 and later.
+
+If you would prefer not to store your API tokens directly in the CLI configuration, you may use
+a host-specific environment variable. Environment variable names should have the prefix
+`TF_TOKEN_` added to the domain name, with periods encoded as underscores. For example, the
+value of a variable named `TF_TOKEN_app_terraform_io` will be used as a bearer authorization
+token when the CLI makes service requests to the hostname `app.terraform.io`.
+
+You must convert domain names containing non-ASCII characters to their [punycode equivalent](https://www.charset.org/punycode)
+with an ACE prefix. For example, token credentials for 例えば.com must be set in a variable
+called `TF_TOKEN_xn--r8j3dr99h_com`.
+
+Hyphens are also valid within host names but usually invalid as variable names and
+may be encoded as double underscores. For example, you can set a token for the domain name
+`café.fr` as `TF_TOKEN_xn--caf-dma.fr`, `TF_TOKEN_xn--caf-dma_fr`,  or `TF_TOKEN_xn____caf__dma_fr`.
+If multiple variables evaluate to the same hostname, Terraform will choose the one defined last
+in the operating system's variable table.
+
+### Credentials Helpers
+
+You can configure a `credentials_helper` to instruct Terraform to use a different credentials storage mechanism.
+
+```hcl
+credentials_helper "example" {
+  args = []
+}
+```
+
+`credentials_helper` is a configuration block that can appear at most once
+in the CLI configuration. Its label (`"example"` above) is the name of the
+credentials helper to use. The `args` argument is optional and allows passing
+additional arguments to the helper program, for example if it needs to be
+configured with the address of a remote host to access for credentials.
+
+A configured credentials helper will be consulted only to retrieve credentials
+for hosts that are _not_ explicitly configured in a `credentials` block as
+described in the previous section.
+Conversely, this means you can override the credentials returned by the helper
+for a specific hostname by writing a `credentials` block alongside the
+`credentials_helper` block.
+
+Terraform does not include any credentials helpers in the main distribution.
+To learn how to write and install your own credentials helpers to integrate
+with existing in-house credentials management systems, see
+[the guide to Credentials Helper internals](/terraform/internals/credentials-helpers).
+
+### Credentials Source Priority Order
+
+Credentials found in an environment variable for a particular service host
+as described above will be preferred over those in CLI config as set by `terraform login`.
+If neither are set, any configured credentials helper will be consulted.
+
+~> **Note:** For users of [terraform-credentials-helper](https://github.com/apparentlymart/terraform-credentials-env), this priority has been effectively reversed following the
+release of Terraform 1.2. Previously, credentials found within CLI config or set by
+`terraform login` were preferred to `TF_TOKEN_*` variables.
+
+## Provider Installation
+
+The default way to install provider plugins is from a provider registry. The
+origin registry for a provider is encoded in the provider's source address,
+like `registry.terraform.io/hashicorp/aws`. For convenience in the common case,
+Terraform allows omitting the hostname portion for providers on
+`registry.terraform.io`, so you can write shorter public provider addresses like
+`hashicorp/aws`.
+
+Downloading a plugin directly from its origin registry is not always
+appropriate, though. For example, the system where you are running Terraform
+may not be able to access an origin registry due to firewall restrictions
+within your organization or your locality.
+
+To allow using Terraform providers in these situations, there are some
+alternative options for making provider plugins available to Terraform which
+we'll describe in the following sections.
+
+### Explicit Installation Method Configuration
+
+A `provider_installation` block in the CLI configuration allows overriding
+Terraform's default installation behaviors, so you can force Terraform to use
+a local mirror for some or all of the providers you intend to use.
+
+The general structure of a `provider_installation` block is as follows:
+
+```hcl
+provider_installation {
+  filesystem_mirror {
+    path    = "/usr/share/terraform/providers"
+    include = ["example.com/*/*"]
+  }
+  direct {
+    exclude = ["example.com/*/*"]
+  }
+}
+```
+
+Each of the nested blocks inside the `provider_installation` block specifies
+one installation method. Each installation method can take both `include`
+and `exclude` patterns that specify which providers a particular installation
+method can be used for. In the example above, we specify that any provider
+whose origin registry is at `example.com` can be installed only from the
+filesystem mirror at `/usr/share/terraform/providers`, while all other
+providers can be installed only directly from their origin registries.
+
+If you set both `include` and `exclude` for a particular installation
+method, the exclusion patterns take priority. For example, including
+`registry.terraform.io/hashicorp/*` but also excluding
+`registry.terraform.io/hashicorp/dns` will make that installation method apply
+to everything in the `hashicorp` namespace with the exception of
+`hashicorp/dns`.
+
+As with provider source addresses in the main configuration, you can omit
+the `registry.terraform.io/` prefix for providers distributed through the
+public Terraform registry, even when using wildcards. For example,
+`registry.terraform.io/hashicorp/*` and `hashicorp/*` are equivalent.
+`*/*` is a shorthand for `registry.terraform.io/*/*`, not for
+`*/*/*`.
+
+The following are the two supported installation method types:
+
+* `direct`: request information about the provider directly from its origin
+  registry and download over the network from the location that registry
+  indicates. This method expects no additional arguments.
+
+* `filesystem_mirror`: consult a directory on the local disk for copies of
+  providers. This method requires the additional argument `path` to indicate
+  which directory to look in.
+
+  Terraform expects the given directory to contain a nested directory structure
+  where the path segments together provide metadata about the available
+  providers. The following two directory structures are supported:
+
+  * Packed layout: `HOSTNAME/NAMESPACE/TYPE/terraform-provider-TYPE_VERSION_TARGET.zip`
+    is the distribution zip file obtained from the provider's origin registry.
+  * Unpacked layout: `HOSTNAME/NAMESPACE/TYPE/VERSION/TARGET` is a directory
+    containing the result of extracting the provider's distribution zip file.
+
+  In both layouts, the `VERSION` is a string like `2.0.0` and the `TARGET`
+  specifies a particular target platform using a format like `darwin_amd64`,
+  `linux_arm`, `windows_amd64`, etc.
+
+  If you use the unpacked layout, Terraform will attempt to create a symbolic
+  link to the mirror directory when installing the provider, rather than
+  creating a deep copy of the directory. The packed layout prevents this
+  because Terraform must extract the zip file during installation.
+
+  You can include multiple `filesystem_mirror` blocks in order to specify
+  several different directories to search.
+
+* `network_mirror`: consult a particular HTTPS server for copies of providers,
+  regardless of which registry host they belong to. This method requires the
+  additional argument `url` to indicate the mirror base URL, which should
+  use the `https:` scheme and end with a trailing slash.
+
+  Terraform expects the given URL to be a base URL for an implementation of
+  [the provider network mirror protocol](/terraform/internals/provider-network-mirror-protocol),
+  which is designed to be relatively easy to implement using typical static
+  website hosting mechanisms.
+
+~> **Warning:** Don't configure `network_mirror` URLs that you do not trust.
+Provider mirror servers are subject to TLS certificate checks to verify
+identity, but a network mirror with a TLS certificate can potentially serve
+modified copies of upstream providers with malicious content.
+
+Terraform will try all of the specified methods whose include and exclude
+patterns match a given provider, and select the newest version available across
+all of those methods that matches the version constraint given in each
+Terraform configuration. If you have a local mirror of a particular provider
+and intend Terraform to use that local mirror exclusively, you must either
+remove the `direct` installation method altogether or use its `exclude`
+argument to disable its use for specific providers.
+
+### Implied Local Mirror Directories
+
+If your CLI configuration does not include a `provider_installation` block at
+all, Terraform produces an _implied_ configuration. The implied configuration
+includes a selection of `filesystem_mirror` methods and then the `direct`
+method.
+
+The set of directories Terraform can select as filesystem mirrors depends on
+the operating system where you are running Terraform:
+
+* **Windows:** `%APPDATA%/terraform.d/plugins` and `%APPDATA%/HashiCorp/Terraform/plugins`
+* **Mac OS X:** `$HOME/.terraform.d/plugins`,
+  `~/Library/Application Support/io.terraform/plugins`, and
+  `/Library/Application Support/io.terraform/plugins`
+* **Linux and other Unix-like systems**:`$HOME/.terraform.d/plugins` and
+  `terraform/plugins` located within a valid
+  [XDG Base Directory](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)
+  data directory such as `$XDG_DATA_HOME/terraform/plugins`.
+  Without any XDG environment variables set, Terraform will use
+  `~/.local/share/terraform/plugins`,
+  `/usr/local/share/terraform/plugins`, and `/usr/share/terraform/plugins`.
+
+If a `terraform.d/plugins` directory exists in the current working directory
+then Terraform will also include that directory, regardless of your operating
+system. This behavior changes when you use the `-chdir` option with the `init` command. In that case, Terraform checks for the `terraform.d/plugins` directory in the launch directory and not in the directory you specified with `-chdir`.
+
+Terraform will check each of the paths above to see if it exists, and if so
+treat it as a filesystem mirror. The directory structure inside each one must
+therefore match one of the two structures described for `filesystem_mirror`
+blocks in [Explicit Installation Method Configuration](#explicit-installation-method-configuration).
+
+In addition to the zero or more implied `filesystem_mirror` blocks, Terraform
+also creates an implied `direct` block. Terraform will scan all of the
+filesystem mirror directories to see which providers are placed there and
+automatically exclude all of those providers from the implied `direct` block.
+(This automatic `exclude` behavior applies only to _implicit_ `direct` blocks;
+if you use explicit `provider_installation` you will need to write the intended
+exclusions out yourself.)
+
+### Provider Plugin Cache
+
+By default, `terraform init` downloads plugins into a subdirectory of the
+working directory so that each working directory is self-contained. As a
+consequence, if you have multiple configurations that use the same provider
+then a separate copy of its plugin will be downloaded for each configuration.
+
+Given that provider plugins can be quite large (on the order of hundreds of
+megabytes), this default behavior can be inconvenient for those with slow
+or metered Internet connections. Therefore Terraform optionally allows the
+use of a local directory as a shared plugin cache, which then allows each
+distinct plugin binary to be downloaded only once.
+
+To enable the plugin cache, use the `plugin_cache_dir` setting in
+the CLI configuration file. For example:
+
+```hcl
+plugin_cache_dir = "$HOME/.terraform.d/plugin-cache"
+```
+
+This directory must already exist before Terraform will cache plugins;
+Terraform will not create the directory itself.
+
+Please note that on Windows it is necessary to use forward slash separators
+(`/`) rather than the conventional backslash (`\`) since the configuration
+file parser considers a backslash to begin an escape sequence.
+
+Setting this in the configuration file is the recommended approach for a
+persistent setting. Alternatively, the `TF_PLUGIN_CACHE_DIR` environment
+variable can be used to enable caching or to override an existing cache
+directory within a particular shell session:
+
+```bash
+export TF_PLUGIN_CACHE_DIR="$HOME/.terraform.d/plugin-cache"
+```
+
+When a plugin cache directory is enabled, the `terraform init` command will
+still use the configured or implied installation methods to obtain metadata
+about which plugins are available, but once a suitable version has been
+selected it will first check to see if the chosen plugin is already available
+in the cache directory. If so, Terraform will use the previously-downloaded
+copy.
+
+If the selected plugin is not already in the cache, Terraform will download
+it into the cache first and then copy it from there into the correct location
+under your current working directory. When possible Terraform will use
+symbolic links to avoid storing a separate copy of a cached plugin in multiple
+directories.
+
+The plugin cache directory _must not_ also be one of the configured or implied
+filesystem mirror directories, since the cache management logic conflicts with
+the filesystem mirror logic when operating on the same directory.
+
+Terraform will never itself delete a plugin from the plugin cache once it has
+been placed there. Over time, as plugins are upgraded, the cache directory may
+grow to contain several unused versions which you must delete manually.
+
+-> **Note:** The plugin cache directory is not guaranteed to be concurrency
+safe. The provider installer's behavior in environments with multiple `terraform
+init` calls is undefined.
+
+### Allowing the Provider Plugin Cache to break the dependency lock file
+
+~> **Note:** The option described in is for unusual and exceptional situations
+only. Do not set this option unless you are sure you need it and you fully
+understand the consequences of enabling it.
+
+By default Terraform will use packages from the global cache directory only
+if they match at least one of the checksums recorded in the
+[dependency lock file](/terraform/language/files/dependency-lock)
+for that provider. This ensures that Terraform can always
+generate a complete and correct dependency lock file entry the first time you
+use a new provider in a particular configuration.
+
+However, we know that in some special situations teams have been unable to use
+the dependency lock file as intended, and so they don't include it in their
+version control as recommended and instead let Terraform re-generate it each
+time it installs providers.
+
+For those teams that don't preserve the dependency lock file in their version
+control systems between runs, Terraform allows an additional CLI Configuration
+setting which tells Terraform to always treat a package in the cache directory
+as valid even if there isn't already an entry in the dependency lock file
+to confirm it:
+
+```hcl
+plugin_cache_may_break_dependency_lock_file = true
+```
+
+Alternatively, you can set the environment variable
+`TF_PLUGIN_CACHE_MAY_BREAK_DEPENDENCY_LOCK_FILE` to any value other than the
+empty string or `0`, which is equivalent to the above setting.
+
+Setting this option gives Terraform CLI permission to create an incomplete
+dependency lock file entry for a provider if that would allow Terraform to
+use the cache to install that provider. In that situation the dependency lock
+file will be valid for use on the current system but may not be valid for use on
+another computer with a different operating system or CPU architecture, because
+it will include only a checksum of the package in the global cache.
+
+We recommend that most users leave this option unset, in which case Terraform
+will always install a provider from upstream the first time you use it with
+a particular configuration, but can then re-use the cache entry on later runs
+once the dependency lock file records valid checksums for the provider package.
+
+~> **Note:** The Terraform team intends to improve the dependency lock file
+mechanism in future versions so that it will be usable in more situations. At
+that time this option will become silently ignored. If your workflow relies on
+the use of this option, please open a GitHub issue to share details about your
+situation so that we can consider how to support it without breaking the
+dependency lock file.
+
+### Development Overrides for Provider Developers
+
+-> **Note:** Development overrides work only in Terraform v0.14 and later.
+Using a `dev_overrides` block in your CLI configuration will cause Terraform
+v0.13 to reject the configuration as invalid.
+
+Normally Terraform verifies version selections and checksums for providers
+in order to help ensure that all operations are made with the intended version
+of a provider, and that authors can gradually upgrade to newer provider versions
+in a controlled manner.
+
+These version and checksum rules are inconvenient when developing a provider
+though, because we often want to try a test configuration against a development
+build of a provider that doesn't even have an associated version number yet,
+and doesn't have an official set of checksums listed in a provider registry.
+
+As a convenience for provider development, Terraform supports a special
+additional block `dev_overrides` in `provider_installation` blocks. The contents
+of this block effectively override all of the other configured installation
+methods, so a block of this type must always appear first in the sequence:
+
+```hcl
+provider_installation {
+
+  # Use /home/developer/tmp/terraform-null as an overridden package directory
+  # for the hashicorp/null provider. This disables the version and checksum
+  # verifications for this provider and forces Terraform to look for the
+  # null provider plugin in the given directory.
+  dev_overrides {
+    "hashicorp/null" = "/home/developer/tmp/terraform-null"
+  }
+
+  # For all other providers, install them directly from their origin provider
+  # registries as normal. If you omit this, Terraform will _only_ use
+  # the dev_overrides block, and so no other providers will be available.
+  direct {}
+}
+```
+
+With development overrides in effect, the `terraform init` command will still
+attempt to select a suitable published version of your provider to install and
+record in
+[the dependency lock file](/terraform/language/files/dependency-lock)
+for future use, but other commands like
+`terraform apply` will disregard the lock file's entry for `hashicorp/null` and
+will use the given directory instead. Once your new changes are included in a
+published release of the provider, you can use `terraform init -upgrade` to
+select the new version in the dependency lock file and remove your development
+override.
+
+The override path for a particular provider should be a directory similar to
+what would be included in a `.zip` file when distributing the provider. At
+minimum that includes an executable file named with a prefix like
+`terraform-provider-null`, where `null` is the provider type. If your provider
+makes use of other files in its distribution package then you can copy those
+files into the override directory too.
+
+You may wish to enable a development override only for shell sessions where
+you are actively working on provider development. If so, you can write a
+local CLI configuration file with content like the above in your development
+directory, perhaps called `dev.tfrc` for the sake of example, and then use the
+`TF_CLI_CONFIG_FILE` environment variable to instruct Terraform to use that
+localized CLI configuration instead of the default one:
+
+```
+export TF_CLI_CONFIG_FILE=/home/developer/tmp/dev.tfrc
+```
+
+Development overrides are not intended for general use as a way to have
+Terraform look for providers on the local filesystem. If you wish to put
+copies of _released_ providers in your local filesystem, see
+[Implied Local Mirror Directories](#implied-local-mirror-directories)
+or
+[Explicit Installation Method Configuration](#explicit-installation-method-configuration)
+instead.
+
+This development overrides mechanism is intended as a pragmatic way to enable
+smoother provider development. The details of how it behaves, how to
+configure it, and how it interacts with the dependency lock file may all evolve
+in future Terraform releases, including possible breaking changes. We therefore
+recommend using development overrides only temporarily during provider
+development work.
+
+## Removed Settings
+
+The following settings are supported in Terraform 0.12 and earlier but are
+no longer recommended for use:
+
+* `providers` - a configuration block that allows specifying the locations of
+  specific plugins for each named provider. This mechanism is deprecated
+  because it is unable to specify a version number and source for each provider.
+  See [Provider Installation](#provider-installation) above for the replacement
+  of this setting in Terraform 0.13 and later.
diff --git a/v1.5.7/website/docs/cli/config/environment-variables.mdx b/v1.5.7/website/docs/cli/config/environment-variables.mdx
new file mode 100644
index 0000000..40bd825
--- /dev/null
+++ b/v1.5.7/website/docs/cli/config/environment-variables.mdx
@@ -0,0 +1,174 @@
+---
+page_title: Environment Variables
+description: >-
+  Learn to use environment variables to change Terraform's default behavior.
+  Configure log content and output, set variables, and more.
+---
+
+# Environment Variables
+
+Terraform refers to a number of environment variables to customize various
+aspects of its behavior. None of these environment variables are required
+when using Terraform, but they can be used to change some of Terraform's
+default behaviors in unusual situations, or to increase output verbosity
+for debugging.
+
+## TF_LOG
+
+Enables detailed logs to appear on stderr which is useful for debugging. For example:
+
+```shell
+export TF_LOG=trace
+```
+
+To disable, either unset it, or set it to `off`. For example:
+
+```shell
+export TF_LOG=off
+```
+
+For more on debugging Terraform, check out the section on [Debugging](/terraform/internals/debugging).
+
+## TF_LOG_PATH
+
+This specifies where the log should persist its output to. Note that even when `TF_LOG_PATH` is set, `TF_LOG` must be set in order for any logging to be enabled. For example, to always write the log to the directory you're currently running terraform from:
+
+```shell
+export TF_LOG_PATH=./terraform.log
+```
+
+For more on debugging Terraform, check out the section on [Debugging](/terraform/internals/debugging).
+
+## TF_INPUT
+
+If set to "false" or "0", causes terraform commands to behave as if the `-input=false` flag was specified. This is used when you want to disable prompts for variables that haven't had their values specified. For example:
+
+```shell
+export TF_INPUT=0
+```
+
+## TF_VAR_name
+
+Environment variables can be used to set variables. The environment variables must be in the format `TF_VAR_name` and this will be checked last for a value. For example:
+
+```shell
+export TF_VAR_region=us-west-1
+export TF_VAR_ami=ami-049d8641
+export TF_VAR_alist='[1,2,3]'
+export TF_VAR_amap='{ foo = "bar", baz = "qux" }'
+```
+
+For more on how to use `TF_VAR_name` in context, check out the section on [Variable Configuration](/terraform/language/values/variables).
+
+## TF_CLI_ARGS and TF_CLI_ARGS_name
+
+<a id="tf-cli-args"></a>
+
+The value of `TF_CLI_ARGS` will specify additional arguments to the
+command-line. This allows easier automation in CI environments as well as
+modifying default behavior of Terraform on your own system.
+
+These arguments are inserted directly _after_ the subcommand
+(such as `plan`) and _before_ any flags specified directly on the command-line.
+This behavior ensures that flags on the command-line take precedence over
+environment variables.
+
+For example, the following command: `TF_CLI_ARGS="-input=false" terraform apply -force`
+is the equivalent to manually typing: `terraform apply -input=false -force`.
+
+The flag `TF_CLI_ARGS` affects all Terraform commands. If you specify a
+named command in the form of `TF_CLI_ARGS_name` then it will only affect
+that command. As an example, to specify that only plans never refresh,
+you can set `TF_CLI_ARGS_plan="-refresh=false"`.
+
+The value of the flag is parsed as if you typed it directly to the shell.
+Double and single quotes are allowed to capture strings and arguments will
+be separated by spaces otherwise.
+
+## TF_DATA_DIR
+
+`TF_DATA_DIR` changes the location where Terraform keeps its
+per-working-directory data, such as the current backend configuration.
+
+By default this data is written into a `.terraform` subdirectory of the
+current directory, but the path given in `TF_DATA_DIR` will be used instead
+if non-empty.
+
+In most cases it should not be necessary to set this variable, but it may
+be useful to do so if e.g. the working directory is not writable.
+
+The data directory is used to retain data that must persist from one command
+to the next, so it's important to have this variable set consistently throughout
+all of the Terraform workflow commands (starting with `terraform init`) or else
+Terraform may be unable to find providers, modules, and other artifacts.
+
+## TF_WORKSPACE
+
+For multi-environment deployment, in order to select a workspace, instead of doing `terraform workspace select your_workspace`, it is possible to use this environment variable. Using TF_WORKSPACE allow and override workspace selection.
+
+For example:
+
+```shell
+export TF_WORKSPACE=your_workspace
+```
+
+Using this environment variable is recommended only for non-interactive usage, since in a local shell environment it can be easy to forget the variable is set and apply changes to the wrong state.
+
+For more information regarding workspaces, check out the section on [Using Workspaces](/terraform/language/state/workspaces).
+
+## TF_IN_AUTOMATION
+
+If `TF_IN_AUTOMATION` is set to any non-empty value, Terraform adjusts its
+output to avoid suggesting specific commands to run next. This can make the
+output more consistent and less confusing in workflows where users don't
+directly execute Terraform commands, like in CI systems or other wrapping
+applications.
+
+This is a purely cosmetic change to Terraform's human-readable output, and the
+exact output differences can change between minor Terraform versions.
+
+For more details, see [Running Terraform in Automation](/terraform/tutorials/automation/automate-terraform?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS).
+
+## TF_REGISTRY_DISCOVERY_RETRY
+
+Set `TF_REGISTRY_DISCOVERY_RETRY` to configure the max number of request retries
+the remote registry client will attempt for client connection errors or
+500-range responses that are safe to retry.
+
+## TF_REGISTRY_CLIENT_TIMEOUT
+
+The default client timeout for requests to the remote registry is 10s. `TF_REGISTRY_CLIENT_TIMEOUT` can be configured and increased during exceptional circumstances.
+
+```shell
+export TF_REGISTRY_CLIENT_TIMEOUT=15
+```
+
+## TF_CLI_CONFIG_FILE
+
+The location of the [Terraform CLI configuration file](/terraform/cli/config/config-file).
+
+```shell
+export TF_CLI_CONFIG_FILE="$HOME/.terraformrc-custom"
+```
+
+## TF_PLUGIN_CACHE_DIR
+
+The `TF_PLUGIN_CACHE_DIR` environment variable is an alternative way to set [the `plugin_cache_dir` setting in the CLI configuration](/terraform/cli/config/config-file#provider-plugin-cache).
+
+You can also use `TF_PLUGIN_CACHE_MAY_BREAK_DEPENDENCY_LOCK_FILE` to activate [the transitional compatibility setting `plugin_cache_may_break_dependency_lock_file`](/terraform/cli/config/config-file#allowing-the-provider-plugin-cache-to-break-the-dependency-lock-file).
+
+## TF_IGNORE
+
+If `TF_IGNORE` is set to "trace", Terraform will output debug messages to display ignored files and folders. This is useful when debugging large repositories with `.terraformignore` files.
+
+```shell
+export TF_IGNORE=trace
+```
+
+For more details on `.terraformignore`, please see [Excluding Files from Upload with .terraformignore](/terraform/language/settings/backends/remote#excluding-files-from-upload-with-terraformignore).
+
+## Terraform Cloud CLI Integration
+
+The CLI integration with Terraform Cloud lets you use Terraform Cloud and Terraform Enterprise on the command line. The integration requires including a `cloud` block in your Terraform configuration. You can define its arguments directly in your configuration file or supply them through environment variables, which can be useful for non-interactive workflows like Continuous Integration (CI).
+
+Refer to [Terraform Cloud Settings](/terraform/cli/cloud/settings#environment-variables) for a full list of `cloud` block environment variables.
diff --git a/v1.5.7/website/docs/cli/config/index.mdx b/v1.5.7/website/docs/cli/config/index.mdx
new file mode 100644
index 0000000..77022d1
--- /dev/null
+++ b/v1.5.7/website/docs/cli/config/index.mdx
@@ -0,0 +1,24 @@
+---
+page_title: CLI Configuration - Terraform CLI
+description: >-
+  Find documentation about the CLI config file and customizing Terraform
+  environment variables.
+---
+
+# CLI Configuration
+
+Terraform CLI can be configured with some global settings, which are separate
+from any Terraform configuration and which apply across all working directories.
+
+We've designed Terraform such that an average user running Terraform CLI
+interactively will not need to interact with any of these settings. As a result,
+most of the global settings relate to advanced or automated workflows, or
+unusual environmental conditions like running Terraform on an airgapped
+instance.
+
+- The [CLI config file](/terraform/cli/config/config-file) configures provider
+  installation and security features.
+- Several [environment variables](/terraform/cli/config/environment-variables) can
+  configure Terraform's inputs and outputs; this includes some alternate ways to
+  provide information that is usually passed on the command line or read from
+  the state of the shell.
diff --git a/v1.5.7/website/docs/cli/import/importability.mdx b/v1.5.7/website/docs/cli/import/importability.mdx
new file mode 100644
index 0000000..fdc3fe9
--- /dev/null
+++ b/v1.5.7/website/docs/cli/import/importability.mdx
@@ -0,0 +1,16 @@
+---
+page_title: 'Import: Resource Importability'
+description: |-
+  Each resource in Terraform must implement some basic logic to become
+  importable. As a result, you cannot import all Terraform resources.
+---
+
+# Resource Importability
+
+Each resource in Terraform must implement some basic logic to become
+importable. As a result, you cannot import all Terraform resources.
+
+The resources that you can import are documented at the bottom of
+each resource documentation page in the [Terraform Registry](https://registry.terraform.io/). If you have issues importing a resource, report an issue in the relevant provider repository.
+
+To make a resource importable, refer to [Extending Terraform: Resources — Import](/terraform/plugin/sdkv2/resources/import).
diff --git a/v1.5.7/website/docs/cli/import/index.mdx b/v1.5.7/website/docs/cli/import/index.mdx
new file mode 100644
index 0000000..17a9a4e
--- /dev/null
+++ b/v1.5.7/website/docs/cli/import/index.mdx
@@ -0,0 +1,26 @@
+---
+page_title: Import
+description: >-
+  Terraform can import and manage existing infrastructure. This can help you
+  transition your infrastructure to Terraform.
+---
+
+# Import
+
+> **Hands-on:** Try the [Import Terraform Configuration](/terraform/tutorials/state/state-import?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+Terraform can import existing infrastructure resources. This functionality lets you bring existing resources under Terraform management.
+
+-> **Note:** Terraform v1.5.0 and later supports `import` blocks. Unlike the `terraform import` command, you can use `import` blocks to import more than one resource at a time, and you can review imports as part of your normal plan and apply workflow. [Learn more about `import` blocks](/terraform/language/import).
+
+## State Only
+
+~> **Warning:** Terraform expects that each remote object is bound to a _single_ resource address. You should import each remote object to _one_ Terraform resource address. If you import the same object multiple times, Terraform may exhibit unwanted behavior. See [State](/terraform/language/state) for more details.
+
+The `terraform import` CLI command can only import resources into the [state](/terraform/language/state). Importing via the CLI does _not_ generate configuration. If you want to generate the accompanying configuration for imported resources, [use the `import` block instead](/terraform/language/import).
+
+Before you run `terraform import` you must manually write a `resource` configuration block for the resource. The resource block describes where Terraform should map the imported object.
+
+## Terraform Cloud
+
+When you use Terraform on the command line with Terraform Cloud, many commands like `apply` run inside your Terraform Cloud environment. However, the `import` command runs locally, so it does not have access to information from Terraform Cloud. To successfully perform an import, you may need to set local variables equivalent to any remote workspace variables in Terraform Cloud.
diff --git a/v1.5.7/website/docs/cli/import/usage.mdx b/v1.5.7/website/docs/cli/import/usage.mdx
new file mode 100644
index 0000000..f5d95be
--- /dev/null
+++ b/v1.5.7/website/docs/cli/import/usage.mdx
@@ -0,0 +1,81 @@
+---
+page_title: 'Import: Usage'
+description: The `terraform import` command is used to import existing infrastructure.
+---
+
+# Import Usage
+
+> **Hands-on:** Try the [Import Terraform Configuration](/terraform/tutorials/state/state-import?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+
+Use the `terraform import` command to import existing infrastructure to Terraform state.
+
+The `terraform import` command can only import one resource at a time. It cannot simultaneously import an entire collection of resources, like an AWS VPC.
+
+~> Warning: Terraform expects that each remote object it is managing will be
+bound to only one resource address, which is normally guaranteed by Terraform
+itself having created all objects. If you import existing objects into Terraform,
+be careful to import each remote object to only one Terraform resource address.
+If you import the same object multiple times, Terraform may exhibit unwanted
+behavior. For more information on this assumption, see
+[the State section](/terraform/language/state).
+
+To import a resource, first write a resource block for it in your
+configuration, establishing the name by which it will be known to Terraform:
+
+```
+resource "aws_instance" "example" {
+  # ...instance configuration...
+}
+```
+
+The name "example" here is local to the module where it is declared and is
+chosen by the configuration author. This is distinct from any ID issued by
+the remote system, which may change over time while the resource name
+remains constant.
+
+If desired, you can leave the body of the resource block blank for now and
+return to fill it in once the instance is imported.
+
+Now `terraform import` can be run to attach an existing instance to this
+resource configuration:
+
+```shell
+$ terraform import aws_instance.example i-abcd1234
+```
+
+This command locates the AWS EC2 instance with ID `i-abcd1234`. Then it attaches
+the existing settings of the instance, as described by the EC2 API, to the
+name `aws_instance.example` of a module. In this example the module path
+implies that the root module is used. Finally, the mapping is saved in the
+Terraform state.
+
+It is also possible to import to resources in child modules, using their paths,
+and to single instances of a resource with `count` or `for_each` set. See
+[_Resource Addressing_](/terraform/cli/state/resource-addressing) for more
+details on how to specify a target resource.
+
+The syntax of the given ID is dependent on the resource type being imported.
+For example, AWS instances use an opaque ID issued by the EC2 API, but
+AWS Route53 Zones use the domain name itself. Consult the documentation for
+each importable resource for details on what form of ID is required.
+
+As a result of the above command, the resource is recorded in the state file.
+You can now run `terraform plan` to see how the configuration compares to
+the imported resource, and make any adjustments to the configuration to
+align with the current (or desired) state of the imported object.
+
+## Complex Imports
+
+The above import is considered a "simple import": one resource is imported
+into the state file. An import may also result in a "complex import" where
+multiple resources are imported. For example, an AWS network ACL imports
+an `aws_network_acl` but also one `aws_network_acl_rule` for each rule.
+
+In this scenario, the secondary resources will not already exist in
+configuration, so it is necessary to consult the import output and create
+a `resource` block in configuration for each secondary resource. If this is
+not done, Terraform will plan to destroy the imported objects on the next run.
+
+If you want to rename or otherwise move the imported resources, the
+[state management commands](/terraform/cli/commands/state) can be used.
diff --git a/v1.5.7/website/docs/cli/index.mdx b/v1.5.7/website/docs/cli/index.mdx
new file mode 100644
index 0000000..d9e5bb8
--- /dev/null
+++ b/v1.5.7/website/docs/cli/index.mdx
@@ -0,0 +1,19 @@
+---
+page_title: Terraform CLI Documentation
+description: >-
+  Learn Terraform's CLI-based workflows. You can use the CLI alone or
+  with Terraform Cloud or Terraform Enterprise.
+---
+
+# Terraform CLI Documentation
+
+> **Hands-on:** Try the [Terraform: Get Started](/terraform/tutorials/aws-get-started?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorials.
+
+This is the documentation for Terraform CLI. It is relevant to anyone working
+with Terraform's CLI-based workflows; this includes people who use Terraform CLI
+by itself, as well as those who use Terraform CLI in conjunction with Terraform
+Cloud or Terraform Enterprise.
+
+Notably, this documentation does not cover the syntax and usage of the Terraform
+language. For that, see the
+[Terraform Language Documentation](/terraform/language).
diff --git a/v1.5.7/website/docs/cli/init/index.mdx b/v1.5.7/website/docs/cli/init/index.mdx
new file mode 100644
index 0000000..5b763eb
--- /dev/null
+++ b/v1.5.7/website/docs/cli/init/index.mdx
@@ -0,0 +1,74 @@
+---
+page_title: Initializing Working Directories - Terraform CLI
+description: >-
+  Working directories contain configurations, settings, cached plugins and
+  modules, and state data. Learn how to initialize and manage working
+  directories.
+---
+
+# Initializing Working Directories
+
+Terraform expects to be invoked from a working directory that contains
+configuration files written in
+[the Terraform language](/terraform/language). Terraform uses
+configuration content from this directory, and also uses the directory to store
+settings, cached plugins and modules, and sometimes state data.
+
+A working directory must be initialized before Terraform can perform any
+operations in it (like provisioning infrastructure or modifying state).
+
+## Working Directory Contents
+
+A Terraform working directory typically contains:
+
+- A Terraform configuration describing resources Terraform should manage. This
+  configuration is expected to change over time.
+- A hidden `.terraform` directory, which Terraform uses to manage cached
+  provider plugins and modules, record which
+  [workspace](/terraform/cli/workspaces) is currently active, and
+  record the last known backend configuration in case it needs to migrate state
+  on the next run. This directory is automatically managed by Terraform, and is
+  created during initialization.
+- State data, if the configuration uses the default `local` backend. This is
+  managed by Terraform in a `terraform.tfstate` file (if the directory only uses
+  the default workspace) or a `terraform.tfstate.d` directory (if the directory
+  uses multiple workspaces).
+
+## Initialization
+
+Run the `terraform init` command to initialize a working directory that contains
+a Terraform configuration. After initialization, you will be able to perform
+other commands, like `terraform plan` and `terraform apply`.
+
+If you try to run a command that relies on initialization without first
+initializing, the command will fail with an error and explain that you need to
+run init.
+
+Initialization performs several tasks to prepare a directory, including
+accessing state in the configured backend, downloading and installing provider
+plugins, and downloading modules. Under some conditions (usually when changing
+from one backend to another), it might ask the user for guidance or
+confirmation.
+
+For details, see [the `terraform init` command](/terraform/cli/commands/init).
+
+## Reinitialization
+
+Certain types of changes to a Terraform configuration can require
+reinitialization before normal operations can continue. This includes changes to
+provider requirements, module sources or version constraints, and backend
+configurations.
+
+You can reinitialize a directory by running `terraform init` again. In fact, you
+can reinitialize at any time; the init command is idempotent, and will have no
+effect if no changes are required.
+
+If reinitialization is required, any commands that rely on initialization will
+fail with an error and tell you so.
+
+## Reinitializing Only Modules
+
+The `terraform get` command will download modules referenced in the
+configuration, but will not perform the other required initialization tasks.
+This command is only useful for niche workflows, and most Terraform users can
+ignore it in favor of `terraform init`.
diff --git a/v1.5.7/website/docs/cli/inspect/index.mdx b/v1.5.7/website/docs/cli/inspect/index.mdx
new file mode 100644
index 0000000..113594c
--- /dev/null
+++ b/v1.5.7/website/docs/cli/inspect/index.mdx
@@ -0,0 +1,35 @@
+---
+page_title: Inspecting Infrastructure - Terraform CLI
+description: >-
+  Learn commands to inspect dependency information, outputs, etc. Use them for
+  integration or to understand your infrastructure.
+---
+
+# Inspecting Infrastructure
+
+Terraform configurations and state data include some highly structured
+information about the resources they manage; this includes dependency
+information, outputs (which are pieces of generated or discovered data that the
+configuration's author considers important enough to surface to users), and
+more.
+
+Terraform CLI includes some commands for inspecting or transforming this data.
+You can use these to integrate other tools with Terraform's infrastructure data,
+or just to gain a deeper or more holistic understanding of your infrastructure.
+
+- [The `terraform graph` command](/terraform/cli/commands/graph) creates a visual
+  representation of a configuration or a set of planned changes.
+- [The `terraform output` command](/terraform/cli/commands/output) can get the
+  values for the top-level [output values](/terraform/language/values/outputs) of
+  a configuration, which are often helpful when making use of the infrastructure
+  Terraform has provisioned.
+- [The `terraform show` command](/terraform/cli/commands/show) can generate
+  human-readable versions of a state file or plan file, or generate
+  machine-readable versions that can be integrated with other tools.
+- [The `terraform state list` command](/terraform/cli/commands/state/list) can list
+  the resources being managed by the current working directory and workspace,
+  providing a complete or filtered list.
+- [The `terraform state show` command](/terraform/cli/commands/state/show) can print
+  all of the attributes of a given resource being managed by the current working
+  directory and workspace, including generated read-only attributes like the
+  unique ID assigned by the cloud provider.
diff --git a/v1.5.7/website/docs/cli/install/apt.mdx b/v1.5.7/website/docs/cli/install/apt.mdx
new file mode 100644
index 0000000..e8ca55f
--- /dev/null
+++ b/v1.5.7/website/docs/cli/install/apt.mdx
@@ -0,0 +1,90 @@
+---
+page_title: APT Packages for Debian and Ubuntu
+description: >-
+  The HashiCorp APT repositories contain distribution-specific Terraform
+  packages for both Debian and Ubuntu systems.
+---
+
+# APT Packages for Debian and Ubuntu
+
+The primary distribution packages for Terraform are `.zip` archives containing
+single executable files that you can extract anywhere on your system. However,
+for easier integration with configuration management tools and other systematic
+system configuration strategies, we also offer package repositories for
+Debian and Ubuntu systems, which allow you to install Terraform using the
+`apt install` command or any other APT frontend.
+
+If you are instead using Red Hat Enterprise Linux, CentOS, or Fedora, you
+might prefer to [install Terraform from our Yum repositories](/terraform/cli/install/yum).
+
+-> **Note:** The APT repositories discussed on this page are generic HashiCorp
+repositories that contain packages for a variety of different HashiCorp
+products, rather than just Terraform. Adding these repositories to your
+system will, by default, therefore make several other non-Terraform
+packages available for installation. That might then mask some packages that
+are available for some HashiCorp products in the main Debian and Ubuntu
+package repositories.
+
+## Repository Configuration
+
+Please follow the instructions in the [Official Packaging Guide](https://www.hashicorp.com/official-packaging-guide).
+
+## Supported Architectures
+
+The HashiCorp APT server has packages only for the `amd64`
+architecture, which is also sometimes known as `x86_64`.
+
+There are no official packages available for other architectures, such as
+`arm64`. If you wish to use Terraform on a non-`amd64` system,
+[download a normal release `.zip` file](/terraform/downloads) instead.
+
+## Supported Debian and Ubuntu Releases
+
+The HashiCorp APT server contains release repositories for a variety of
+supported distributions, which are outlined in the [Official Packaging Guide](https://www.hashicorp.com/official-packaging-guide).
+
+## Installing a Specific Version of Terraform
+
+The HashiCorp APT repositories contain multiple versions of Terraform, but
+because the packages are all named `terraform` it is impossible to install
+more than one version at a time, and `apt install` will default to selecting
+the latest version.
+
+It's often necessary to match your Terraform version with what a particular
+configuration is currently expecting. You can use the following command to
+see which versions are currently available in the repository index:
+
+```bash
+apt policy terraform
+```
+
+If your workflow requires using multiple versions of Terraform at the same
+time, for example when working through a gradual upgrade where not all
+of your configurations are upgraded yet, we recommend that you use the
+official release `.zip` files instead of the APT packages, so you can install
+multiple versions at once and then select which to use for each command you
+run.
+
+### Terraform 1.4.3 and Later
+
+As of Terraform 1.4.3, all published packages include a revision number by
+default, starting with `-1`. This change means that in the case that we need
+to publish an updated package for any reason, installers can automatically
+retrieve the latest revision. You can learn more about this packaging change
+in [the announcement](https://discuss.hashicorp.com/t/linux-packaging-debian-revision-change/42403).
+
+You can install the latest revision for a particular version by including the
+version in the `apt install` command, as follows:
+
+```bash
+sudo apt install terraform=1.4.4-*
+```
+
+### Terraform 1.4.2 and Earlier
+
+Terraform 1.4.2 and earlier did not include a revision number for the first
+revision, so you can use the following pattern to install a specific version:
+
+```bash
+sudo apt install terraform=1.4.0
+```
diff --git a/v1.5.7/website/docs/cli/install/yum.mdx b/v1.5.7/website/docs/cli/install/yum.mdx
new file mode 100644
index 0000000..b6b4b80
--- /dev/null
+++ b/v1.5.7/website/docs/cli/install/yum.mdx
@@ -0,0 +1,121 @@
+---
+page_title: 'Yum Packages for Red Hat Enterprise Linux, Fedora, and Amazon Linux'
+description: >-
+  The HashiCorp Yum repositories contain distribution-specific Terraform
+  packages for Red Hat Enterprise Linux, Fedora, and Amazon Linux systems.
+---
+
+# Yum/DNF Packages for RHEL, CentOS, and Fedora
+
+The primary distribution packages for Terraform are `.zip` archives containing
+single executable files that you can extract anywhere on your system. However,
+for easier integration with configuration management tools and other systematic
+system configuration strategies, we also offer package repositories for
+RedHat Enterprise Linux, Fedora, and Amazon Linux systems, which allow you to
+install Terraform using the `yum install` or `dnf install` commands.
+
+If you are instead using Debian or Ubuntu, you
+might prefer to [install Terraform from our APT repositories](/terraform/cli/install/apt).
+
+-> **Note:** The Yum repositories discussed on this page are generic HashiCorp
+repositories that contain packages for a variety of different HashiCorp
+products, rather than just Terraform. Adding these repositories to your
+system will, by default, therefore make a number of other non-Terraform
+packages available for installation. That might then mask the packages that are
+available for some HashiCorp products in the main distribution repositories.
+
+## Repository Configuration
+
+Before adding a repository you must determine which distribution you are using.
+The following command lines refer to a placeholder variable `$release` which
+you must replace with the appropriate value from the following list:
+
+* Red Hat Enterprise Linux: `RHEL`
+* Fedora: `fedora`
+* Amazon Linux: `AmazonLinux`
+
+If you are using a Yum-based distribution, add the repository using
+`yum-config-manager` as follows:
+
+```bash
+sudo yum install -y yum-utils
+sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/$release/hashicorp.repo
+```
+
+If you are using a DNF-based distribution, add the repository using
+`dnf config-manager` as follows:
+
+```bash
+sudo dnf install -y dnf-plugins-core
+sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/$release/hashicorp.repo
+```
+
+In both cases, the Terraform package name is `terraform`. For example:
+
+```bash
+yum install terraform
+```
+
+## Supported Architectures
+
+The HashiCorp Yum/DNF server has packages only for the `x86_64`
+architecture, which is also sometimes known as `amd64`.
+
+There are no official packages available for other architectures, such as
+`aarch64`. If you wish to use Terraform on a non-`x86_64` system,
+[download a normal release `.zip` file](/terraform/downloads) instead.
+
+## Supported Distribution Releases
+
+The HashiCorp Yum server contains release repositories for the
+following distribution releases:
+
+* AmazonLinux 2 and "latest"
+* Fedora 33
+* Fedora 34
+* Fedora 35
+* Fedora 36
+* Fedora 37
+* RHEL 7 (and CentOS 7)
+* RHEL 8 (and CentOS 8)
+* RHEL 9 (and CentOS 9)
+
+No repositories are available for other versions of these distributions or for
+any other RPM-based Linux distributions. If you add the repository using
+the above commands on other systems then you will see a 404 Not Found error.
+
+Over time we will change the set of supported distributions, including both
+adding support for new releases and ceasing to publish new Terraform versions
+under older releases.
+
+## Choosing Terraform Versions
+
+The HashiCorp Yum repositories contain multiple versions of Terraform, but
+because the packages are all named `terraform` it is impossible to install
+more than one version at a time, and `yum install` or `dnf install` will
+default to selecting the latest version.
+
+It's often necessary to match your Terraform version with what a particular
+configuration is currently expecting. Use the following command to
+retrieve the available versions in the repository index:
+
+```bash
+yum --showduplicate list terraform
+```
+
+You can select a specific version to install by including it in the
+`yum install` command line, as follows:
+
+```bash
+yum install terraform-0.14.0-2.x86_64
+```
+
+If you are using a DNF-based distribution, similar use `dnf` instead of `yum`
+when following the above steps.
+
+If your workflow requires using multiple versions of Terraform at the same
+time, for example when working through a gradual upgrade where not all
+of your configurations are upgraded yet, we recommend that you use the
+official release `.zip` files instead of the Yum packages, so you can install
+multiple versions at once and then select which to use for each command you
+run.
diff --git a/v1.5.7/website/docs/cli/plugins/index.mdx b/v1.5.7/website/docs/cli/plugins/index.mdx
new file mode 100644
index 0000000..97f6182
--- /dev/null
+++ b/v1.5.7/website/docs/cli/plugins/index.mdx
@@ -0,0 +1,59 @@
+---
+page_title: Managing Plugins - Terraform CLI
+description: >-
+  Commands to install, configure, and show information about providers. Also
+  commands to reduce install effort in air-gapped environments.
+---
+
+# Managing Plugins
+
+Terraform relies on plugins called "providers" in order to manage various types
+of resources. (For more information about providers, see
+[Providers](/terraform/language/providers) in the Terraform
+language docs.)
+
+-> **Note:** Providers are the only plugin type most Terraform users interact with. Terraform also supports third-party provisioner plugins, but
+we discourage their use.
+
+Terraform downloads and/or installs any providers
+[required](/terraform/language/providers/requirements) by a configuration
+when [initializing](/terraform/cli/init) a working directory. By default,
+this works without any additional interaction but requires network access to
+download providers from their source registry.
+
+You can configure Terraform's provider installation behavior to limit or skip
+network access, and to enable use of providers that aren't available via a
+networked source. Terraform also includes some commands to show information
+about providers and to reduce the effort of installing providers in airgapped
+environments.
+
+## Configuring Plugin Installation
+
+Terraform's configuration file includes options for caching downloaded plugins,
+or explicitly specifying a local or HTTPS mirror to install plugins from. For
+more information, see [CLI Config File](/terraform/cli/config/config-file).
+
+## Getting Plugin Information
+
+Use the [`terraform providers`](/terraform/cli/commands/providers) command to get information
+about the providers required by the current working directory's configuration.
+
+Use the [`terraform version`](/terraform/cli/commands/version) command (or
+`terraform -version`) to show the specific provider versions installed for the
+current working directory.
+
+Use the [`terraform providers schema`](/terraform/cli/commands/providers/schema) command to
+get machine-readable information about the resources and configuration options
+offered by each provider.
+
+## Managing Plugin Installation
+
+Use the [`terraform providers mirror`](/terraform/cli/commands/providers/mirror) command to
+download local copies of every provider required by the current working
+directory's configuration. This directory will use the nested directory layout
+that Terraform expects when installing plugins from a local source, so you can
+transfer it directly to an airgapped system that runs Terraform.
+
+Use the [`terraform providers lock`](/terraform/cli/commands/providers/lock) command
+to update the lock file that Terraform uses to ensure predictable runs when
+using ambiguous provider version constraints.
diff --git a/v1.5.7/website/docs/cli/plugins/signing.mdx b/v1.5.7/website/docs/cli/plugins/signing.mdx
new file mode 100644
index 0000000..7eac2ef
--- /dev/null
+++ b/v1.5.7/website/docs/cli/plugins/signing.mdx
@@ -0,0 +1,27 @@
+---
+page_title: Plugin Signing
+description: >-
+  Learn about the types of signatures providers can have on the Terraform
+  Registry.
+---
+
+<!-- THIS PAGED IS LINKED TO IN THE CLI -->
+
+# Plugin Signing
+
+~> **Note** Terraform only authenticates provider plugins fetched from a registry.
+
+Terraform providers installed from the Registry are cryptographically signed, and the signature is verified at time of installation. There are three types of provider signatures, each with different trust implications:
+
+* **Signed by HashiCorp** - are built, signed, and supported by HashiCorp.
+* **Signed by Trusted Partners** - are built, signed, and supported by a third party. HashiCorp has
+  verified the ownership of the private key and we provide a chain of trust to the CLI to verify this
+  programatically.
+* **Self-signed** - are built, signed, and supported by a third party. HashiCorp does not provide a
+  verification or chain of trust for the signature. You may obtain and validate fingerprints manually
+  if you want to ensure you are using a binary you can trust.
+
+Terraform does **NOT** support fetching and using unsigned binaries, but you can manually install
+unsigned binaries. You should take extreme care when doing so as no programatic authentication is performed.
+
+Usage of plugins from the registry is subject to the Registry's [Terms of Use](https://registry.terraform.io/terms).
diff --git a/v1.5.7/website/docs/cli/run/index.mdx b/v1.5.7/website/docs/cli/run/index.mdx
new file mode 100644
index 0000000..3fc3538
--- /dev/null
+++ b/v1.5.7/website/docs/cli/run/index.mdx
@@ -0,0 +1,71 @@
+---
+page_title: Provisioning Infrastructure - Terraform CLI
+description: 'Learn about commands for core provisioning tasks: plan, apply, and destroy.'
+---
+
+# Provisioning Infrastructure with Terraform
+
+Terraform's primary function is to create, modify, and destroy infrastructure
+resources to match the desired state described in a
+[Terraform configuration](/terraform/language).
+
+When people refer to "running Terraform," they generally mean performing these
+provisioning actions in order to affect real infrastructure objects. The
+Terraform binary has many other subcommands for a wide variety of administrative
+actions, but these basic provisioning tasks are the core of Terraform.
+
+Terraform's provisioning workflow relies on three commands: `plan`, `apply`, and
+`destroy`. All of these commands require an
+[initialized](/terraform/cli/init) working directory, and all of them act
+only upon the currently selected [workspace](/terraform/cli/workspaces).
+
+## Planning
+
+The `terraform plan` command evaluates a Terraform configuration to determine
+the desired state of all the resources it declares, then compares that desired
+state to the real infrastructure objects being managed with the current working
+directory and workspace. It uses state data to determine which real objects
+correspond to which declared resources, and checks the current state of each
+resource using the relevant infrastructure provider's API.
+
+Once it has determined the difference between the current state and the desired
+state, `terraform plan` presents a description of the changes necessary to
+achieve the desired state. It _does not_ perform any actual changes to real
+world infrastructure objects; it only presents a plan for making changes.
+
+Plans are usually run to validate configuration changes and confirm that the
+resulting actions are as expected. However, `terraform plan` can also save its
+plan as a runnable artifact, which `terraform apply` can use to carry out those
+exact changes.
+
+For details, see [the `terraform plan` command](/terraform/cli/commands/plan).
+
+## Applying
+
+The `terraform apply` command performs a plan just like `terraform plan` does,
+but then actually carries out the planned changes to each resource using the
+relevant infrastructure provider's API. It asks for confirmation from the user
+before making any changes, unless it was explicitly told to skip approval.
+
+By default, `terraform apply` performs a fresh plan right before applying
+changes, and displays the plan to the user when asking for confirmation.
+However, it can also accept a plan file produced by `terraform plan` in lieu of
+running a new plan. You can use this to reliably perform an exact set of
+pre-approved changes, even if the configuration or the state of the real
+infrastructure has changed in the minutes since the original plan was created.
+
+For details, see [the `terraform apply` command](/terraform/cli/commands/apply).
+
+## Destroying
+
+The `terraform destroy` command destroys all of the resources being managed by
+the current working directory and workspace, using state data to determine which
+real world objects correspond to managed resources. Like `terraform apply`, it
+asks for confirmation before proceeding.
+
+A destroy behaves exactly like deleting every resource from the configuration
+and then running an apply, except that it doesn't require editing the
+configuration. This is more convenient if you intend to provision similar
+resources at a later date.
+
+For details, see [the `terraform destroy` command](/terraform/cli/commands/destroy).
diff --git a/v1.5.7/website/docs/cli/state/index.mdx b/v1.5.7/website/docs/cli/state/index.mdx
new file mode 100644
index 0000000..b5d39bd
--- /dev/null
+++ b/v1.5.7/website/docs/cli/state/index.mdx
@@ -0,0 +1,34 @@
+---
+page_title: Manipulating State - Terraform CLI
+description: >-
+  State data tracks which real-world object corresponds to each resource.
+  Inspect state, move or import resources, and more.
+---
+
+# Manipulating Terraform State
+
+> **Hands-on:** Try the [Manage Resources in Terraform State](/terraform/tutorials/state/state-cli?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+Terraform uses [state data](/terraform/language/state) to remember which
+real-world object corresponds to each resource in the configuration;
+this allows it to modify an existing object when its resource declaration
+changes.
+
+Terraform updates state automatically during plans and applies. However, it's
+sometimes necessary to make deliberate adjustments to Terraform's state data,
+usually to compensate for changes to the configuration or the real managed
+infrastructure.
+
+Terraform CLI supports several workflows for interacting with state:
+
+- [Inspecting State](/terraform/cli/state/inspect)
+- [Forcing Re-creation](/terraform/cli/state/taint)
+- [Moving Resources](/terraform/cli/state/move)
+- Importing Pre-existing Resources (documented in the
+  [Importing Infrastructure](/terraform/cli/import) section)
+- [Disaster Recovery](/terraform/cli/state/recover)
+
+~> **Important:** Modifying state data outside a normal plan or apply can cause
+Terraform to lose track of managed resources, which might waste money, annoy
+your colleagues, or even compromise the security of your operations. Make sure
+to keep backups of your state data when modifying state out-of-band.
diff --git a/v1.5.7/website/docs/cli/state/inspect.mdx b/v1.5.7/website/docs/cli/state/inspect.mdx
new file mode 100644
index 0000000..439a064
--- /dev/null
+++ b/v1.5.7/website/docs/cli/state/inspect.mdx
@@ -0,0 +1,21 @@
+---
+page_title: Inspecting State - Terraform CLI
+description: Commands that allow you to read and update state.
+---
+
+# Inspecting State
+
+Terraform includes some commands for reading and updating state without taking
+any other actions.
+
+- [The `terraform state list` command](/terraform/cli/commands/state/list)
+  shows the resource addresses for every resource Terraform knows about in a
+  configuration, optionally filtered by partial resource address.
+
+- [The `terraform state show` command](/terraform/cli/commands/state/show)
+  displays detailed state data about one resource.
+
+- [The `terraform refresh` command](/terraform/cli/commands/refresh) updates
+  state data to match the real-world condition of the managed resources. This is
+  done automatically during plans and applies, but not when interacting with
+  state directly.
diff --git a/v1.5.7/website/docs/cli/state/move.mdx b/v1.5.7/website/docs/cli/state/move.mdx
new file mode 100644
index 0000000..326cd9f
--- /dev/null
+++ b/v1.5.7/website/docs/cli/state/move.mdx
@@ -0,0 +1,47 @@
+---
+page_title: Moving Resources - Terraform CLI
+description: >-
+  Commands that allow you to manage the way that resources are tracked in state.
+  They are helpful when you move or change resources.
+---
+
+# Moving Resources
+
+Terraform's state associates each real-world object with a configured resource
+at a specific [resource address](/terraform/cli/state/resource-addressing). This
+is seamless when changing a resource's attributes, but Terraform will lose track
+of a resource if you change its name, move it to a different module, or change
+its provider.
+
+Usually that's fine: Terraform will destroy the old resource, replace it with a
+new one (using the new resource address), and update any resources that rely on
+its attributes.
+
+In cases where it's important to preserve an existing infrastructure object, you
+can explicitly tell Terraform to associate it with a different configured
+resource.
+
+For most cases we recommend using
+[the Terraform language's refactoring features](/terraform/language/modules/develop/refactoring)
+to document in your module exactly how the resource names have changed over
+time. Terraform reacts to this information automatically during planning, so users of your module do not need to take any unusual extra steps.
+
+> **Hands On:** Try the [Use Configuration to Move Resources](/terraform/tutorials/configuration-language/move-config) tutorial.
+
+There are some other situations which require explicit state modifications,
+though. For those, consider the following Terraform commands:
+
+- [The `terraform state mv` command](/terraform/cli/commands/state/mv) changes
+  which resource address in your configuration is associated with a particular
+  real-world object. Use this to preserve an object when renaming a resource, or
+  when moving a resource into or out of a child module.
+
+- [The `terraform state rm` command](/terraform/cli/commands/state/rm) tells
+  Terraform to stop managing a resource as part of the current working directory
+  and workspace, _without_ destroying the corresponding real-world object. (You
+  can later use `terraform import` to start managing that resource in a
+  different workspace or a different Terraform configuration.)
+
+- [The `terraform state replace-provider` command](/terraform/cli/commands/state/replace-provider)
+  transfers existing resources to a new provider without requiring them to be
+  re-created.
diff --git a/v1.5.7/website/docs/cli/state/recover.mdx b/v1.5.7/website/docs/cli/state/recover.mdx
new file mode 100644
index 0000000..0767549
--- /dev/null
+++ b/v1.5.7/website/docs/cli/state/recover.mdx
@@ -0,0 +1,25 @@
+---
+page_title: Recovering from State Disasters - Terraform CLI
+description: >-
+  Learn how to restore state backups and override Terraform state protections to fix state errors with the Terraform CLI.
+
+---
+
+# Recovering from State Disasters
+
+If something has gone horribly wrong (possibly due to accidents when performing
+other state manipulation actions), you might need to take drastic actions with
+your state data.
+
+- [The `terraform force-unlock` command](/terraform/cli/commands/force-unlock) can
+  override the protections Terraform uses to prevent two processes from
+  modifying state at the same time. You might need this if a Terraform process
+  (like a normal apply) is unexpectedly terminated (like by the complete
+  destruction of the VM it's running in) before it can release its lock on the
+  state backend. Do not run this until you are completely certain what happened
+  to the process that caused the lock to get stuck.
+
+- [The `terraform state pull` command](/terraform/cli/commands/state/pull) and
+  [the `terraform state push` command](/terraform/cli/commands/state/push) can
+  directly read and write entire state files from and to the configured backend.
+  You might need this for obtaining or restoring a state backup.
diff --git a/v1.5.7/website/docs/cli/state/resource-addressing.mdx b/v1.5.7/website/docs/cli/state/resource-addressing.mdx
new file mode 100644
index 0000000..072e9c2
--- /dev/null
+++ b/v1.5.7/website/docs/cli/state/resource-addressing.mdx
@@ -0,0 +1,136 @@
+---
+page_title: 'Internals: Resource Address'
+description: |-
+  A resource address is a string that identifies zero or more resource
+  instances in your overall configuration.
+---
+
+# Resource Addressing
+
+A _resource address_ is a string that identifies zero or more resource
+instances in your overall configuration.
+
+An address is made up of two parts:
+
+```
+[module path][resource spec]
+```
+
+In some contexts Terraform might allow for an incomplete resource address that
+only refers to a module as a whole, or that omits the index for a
+multi-instance resource. In those cases, the meaning depends on the context,
+so you'll need to refer to the documentation for the specific feature you
+are using which parses resource addresses.
+
+## Module path
+
+A module path addresses a module within the tree of modules. It takes the form:
+
+```
+module.module_name[module index]
+```
+
+- `module` - Module keyword indicating a child module (non-root). Multiple `module`
+  keywords in a path indicate nesting.
+- `module_name` - User-defined name of the module.
+- `[module index]` - (Optional) [Index](#index-values-for-modules-and-resources)
+  to select an instance from a module call that has multiple instances,
+  surrounded by square bracket characters (`[` and `]`).
+
+An address without a resource spec, i.e. `module.foo` applies to every resource within
+the module if a single module, or all instances of a module if a module has multiple instances.
+To address all resources of a particular module instance, include the module index in the address,
+such as `module.foo[0]`.
+
+If the module path is omitted, the address applies to the root module.
+
+An example of the `module` keyword delineating between two modules that have multiple instances:
+
+```
+module.foo[0].module.bar["a"]
+```
+
+-> Module index only applies to modules in Terraform v0.13 or later. In earlier
+versions of Terraform, a module could not have multiple instances.
+
+## Resource spec
+
+A resource spec addresses a specific resource instance in the selected module.
+It has the following syntax:
+
+```
+resource_type.resource_name[instance index]
+```
+
+- `resource_type` - Type of the resource being addressed.
+- `resource_name` - User-defined name of the resource.
+- `[instance index]` - (Optional) [Index](#index-values-for-modules-and-resources)
+  to select an instance from a resource that has multiple instances,
+  surrounded by square bracket characters (`[` and `]`).
+
+-> In Terraform v0.12 and later, a resource spec without a module path prefix
+matches only resources in the root module. In earlier versions, a resource spec
+without a module path prefix would match resources with the same type and name
+in any descendent module.
+
+## Index values for Modules and Resources
+
+The following specifications apply to index values on modules and resources with multiple instances:
+
+- `[N]` where `N` is a `0`-based numerical index into a resource with multiple
+  instances specified by the `count` meta-argument. Omitting an index when
+  addressing a resource where `count > 1` means that the address references
+  all instances.
+- `["INDEX"]` where `INDEX` is a alphanumerical key index into a resource with
+  multiple instances specified by the `for_each` meta-argument.
+
+## Examples
+
+### count Example
+
+Given a Terraform config that includes:
+
+```hcl
+resource "aws_instance" "web" {
+  # ...
+  count = 4
+}
+```
+
+An address like this:
+
+```
+aws_instance.web[3]
+```
+
+Refers to only the last instance in the config, and an address like this:
+
+```
+aws_instance.web
+```
+
+Refers to all four "web" instances.
+
+### for_each Example
+
+Given a Terraform config that includes:
+
+```hcl
+resource "aws_instance" "web" {
+  # ...
+  for_each = {
+    "terraform": "value1",
+    "resource":  "value2",
+    "indexing":  "value3",
+    "example":   "value4",
+  }
+}
+```
+
+An address like this:
+
+```
+aws_instance.web["example"]
+```
+
+Refers to only the "example" instance in the config, and resolves to "value4".
diff --git a/v1.5.7/website/docs/cli/state/taint.mdx b/v1.5.7/website/docs/cli/state/taint.mdx
new file mode 100644
index 0000000..dbf1229
--- /dev/null
+++ b/v1.5.7/website/docs/cli/state/taint.mdx
@@ -0,0 +1,63 @@
+---
+page_title: Forcing Re-creation of Resources - Terraform CLI
+description: Commands that allow you to destroy and re-create resources manually.
+---
+
+# Forcing Re-creation of Resources
+
+During planning, by default Terraform retrieves the latest state of each
+existing object and compares it with the current configuration, planning
+actions only against objects whose current state does not match the
+configuration.
+
+However, in some cases a remote object may become damaged or degraded in a
+way that Terraform cannot automatically detect. For example, if software
+running inside a virtual machine crashes but the virtual machine itself is
+still running then Terraform will typically have no way to detect and respond
+to the problem, because Terraform only directly manages the machine as a whole.
+
+If you know that an object is damaged, or if you want to force Terraform to
+replace it for any other reason, you can override Terraform's default behavior
+using [the `-replace=...` planning option](/terraform/cli/commands/plan#replace-address)
+when you run either `terraform plan` or `terraform apply`:
+
+```shellsession
+$ terraform apply -replace="aws_instance.example"
+# ...
+
+  # aws_instance.example will be replaced, as requested
+-/+ resource "aws_instance" "example" {
+      # ...
+    }
+```
+
+## The "tainted" status
+
+Sometimes Terraform is able to infer automatically that an object is in an
+incomplete or degraded state. For example, if creation of a complex object
+fails in such a way that parts of it already exist in the remote system, or
+if object creation succeeded but a provisioner step subsequently failed,
+Terraform must remember that the object exists but may not be fully-functional.
+
+Terraform represents this situation by marking an object in the state as
+"tainted". When an object is marked with this status, the next plan will force
+replacing that object in a similar way to if you had specified that object's
+address using `-replace=...` as described above.
+
+```
+  # aws_instance.example is tainted, so must be replaced
+-/+ resource "aws_instance" "example" {
+      # ...
+    }
+```
+
+If Terraform has marked an object as tainted but you consider it to be working
+correctly and do not want to replace it, you can override Terraform's
+determination using [the `terraform untaint` command](/terraform/cli/commands/untaint),
+after which Terraform will consider the object to be ready for use by any
+downstream resource declarations.
+
+You can also _force_ Terraform to mark a particular object as tainted using
+[the `terraform taint` command](/terraform/cli/commands/taint), but that approach is
+deprecated in favor of the `-replace=...` option, which avoids the need to
+create an interim state snapshot with a tainted object.
diff --git a/v1.5.7/website/docs/cli/workspaces/index.mdx b/v1.5.7/website/docs/cli/workspaces/index.mdx
new file mode 100644
index 0000000..700733d
--- /dev/null
+++ b/v1.5.7/website/docs/cli/workspaces/index.mdx
@@ -0,0 +1,86 @@
+---
+page_title: Managing Workspaces - Terraform CLI
+description: >-
+  Commands to list, select, create, and output workspaces. Workspaces help
+  manage different groups of resources with one configuration.
+---
+
+# Managing Workspaces
+
+Workspaces in the Terraform CLI refer to separate instances of [state data](/terraform/language/state) inside the same Terraform working directory. They are distinctly different from [workspaces in Terraform Cloud](/terraform/cloud-docs/workspaces), which each have their own Terraform configuration and function as separate working directories.
+
+Terraform relies on state to associate resources with real-world objects. When you run the same configuration multiple times with separate state data, Terraform can manage multiple sets of non-overlapping resources.
+
+Workspaces can be helpful for specific [use cases](#use-cases), but they are not required to use the Terraform CLI. We recommend using [alternative approaches](#alternatives-to-workspaces) for complex deployments requiring separate credentials and access controls.
+
+
+## Managing CLI Workspaces
+
+Every [initialized working directory](/terraform/cli/init) starts with one workspace named `default`.
+
+Use the [`terraform workspace list`](/terraform/cli/commands/workspace/list), [`terraform workspace new`](/terraform/cli/commands/workspace/new), and [`terraform workspace delete`](/terraform/cli/commands/workspace/delete) commands to manage the available workspaces in the current working directory.
+
+Use [the `terraform workspace select` command](/terraform/cli/commands/workspace/select) to change the currently selected workspace. For a given working directory, you can only select one workspace at a time. Most Terraform commands only interact with the currently selected workspace. This includes [provisioning](/terraform/cli/run) and [state manipulation](/terraform/cli/state).
+
+When you provision infrastructure in each workspace, you usually need to manually specify different [input variables](/terraform/language/values/variables) to differentiate each collection. For example, you might deploy test infrastructure to a different region.
+
+
+## Use Cases
+
+You can create multiple [working directories](/terraform/cli/init) to maintain multiple instances of a configuration with completely separate state data. However, Terraform installs a separate cache of plugins and modules for each working directory, so maintaining multiple directories can waste bandwidth and disk space. This approach also requires extra tasks like updating configuration from version control for each directory separately and reinitializing each directory when you change the configuration. Workspaces are convenient because they let you create different sets of infrastructure with the same working copy of your configuration and the same plugin and module caches.
+
+A common use for multiple workspaces is to create a parallel, distinct copy of
+a set of infrastructure to test a set of changes before modifying production infrastructure.
+
+Non-default workspaces are often related to feature branches in version control.
+The default workspace might correspond to the `main` or `trunk` branch, which describes the intended state of production infrastructure. When a developer creates a feature branch for a change, they might also create a corresponding workspace and deploy into it a temporary copy of the main infrastructure. They can then test changes on the copy without affecting the production infrastructure. Once the change is merged and deployed to the default workspace, they destroy the test infrastructure and delete the temporary workspace.
+
+
+### When Not to Use Multiple Workspaces
+
+Workspaces let you quickly switch between multiple instances of a **single configuration** within its **single backend**. They are not designed to solve all problems.
+
+When using Terraform to manage larger systems, you should create separate Terraform configurations that correspond to architectural boundaries within the system. This lets teams manage different components separately. Workspaces alone are not a suitable tool for system decomposition because each subsystem should have its own separate configuration and backend.
+
+In particular, organizations commonly want to create a strong separation
+between multiple deployments of the same infrastructure serving different
+development stages or different internal teams. In this case, the backend for each deployment often has different credentials and access controls. CLI workspaces within a working directory use the same backend, so they are not a suitable isolation mechanism for this scenario.
+
+## Alternatives to Workspaces
+
+Instead of creating CLI workspaces, you can use one or more [re-usable modules](/terraform/language/modules/develop) to represent the common elements and then represent each instance as a separate configuration that instantiates those common elements in the context of a different [backend](/terraform/language/settings/backends/configuration). The root module of each configuration consists only of a backend configuration and a small number of `module` blocks with arguments describing any small differences between the deployments.
+
+When multiple configurations represent distinct system components rather than multiple deployments, you can pass data from one component to another using paired resources types and data sources.
+
+- When a shared [Consul](https://www.consul.io/) cluster is available, use [`consul_key_prefix`](https://registry.terraform.io/providers/hashicorp/consul/latest/docs/resources/key_prefix) to publish to the key/value store and [`consul_keys`](https://registry.terraform.io/providers/hashicorp/consul/latest/docs/data-sources/keys) to retrieve those values in other configurations.
+
+- In systems that support user-defined labels or tags, use a tagging convention to make resources automatically discoverable. For example, use [the `aws_vpc` resource type](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) to assign suitable tags and then [the `aws_vpc` data source](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc) to query by those tags in other configurations.
+
+- For server addresses, use a provider-specific resource to create a DNS record with a predictable name. Then you can either use that name directly or use [the `dns` provider](https://registry.terraform.io/providers/hashicorp/dns/latest/docs) to retrieve the published addresses in other configurations.
+
+- If you store a Terraform state for one configuration in a remote backend that other configurations can access, then the other configurations can use [`terraform_remote_state`](/terraform/language/state/remote-state-data) to directly consume its root module outputs. This setup creates a tighter coupling between configurations, and the root configuration does not need to publish its results in a separate system.
+
+
+## Interactions with Terraform Cloud Workspaces
+
+Terraform Cloud organizes infrastructure using workspaces, but its workspaces
+act more like completely separate working directories. Each Terraform Cloud
+workspace has its own Terraform configuration, set of variable values, state
+data, run history, and settings.
+
+When you [integrate Terraform CLI with Terraform Cloud](/terraform/cli/cloud), you can associate the current CLI working directory with one or more remote Terraform Cloud workspaces. Then, use the `terraform workspace` commands to select the remote workspace you want to use for each run.
+
+Refer to [CLI-driven Runs](/terraform/cloud-docs/run/cli) in the Terraform Cloud documentation for more details.
+
+
+## Workspace Internals
+
+Workspaces are technically equivalent to renaming your state file. Terraform then includes a set of protections and support for remote state.
+
+Workspaces are also meant to be a shared resource. They are not private, unless you use purely local state and do not commit your state to version control.
+
+For local state, Terraform stores the workspace states in a directory called `terraform.tfstate.d`. This directory should be treated similarly to local-only `terraform.tfstate`. Some teams commit these files to version control, but we recommend using a remote backend instead when there are multiple collaborators.
+
+For [remote state](/terraform/language/state/remote), the workspaces are stored directly in the configured [backend](/terraform/language/settings/backends/configuration). For example, if you use [Consul](/terraform/language/settings/backends/consul), the workspaces are stored by appending the workspace name to the state path. To ensure that workspace names are stored correctly and safely in all backends, the name must be valid to use in a URL path segment without escaping.
+
+Terraform stores the current workspace name locally in the ignored `.terraform` directory. This allows multiple team members to work on different workspaces concurrently. Workspace names are also attached to associated remote workspaces in Terraform Cloud. For more details about workspace names in Terraform Cloud, refer to the [CLI Integration (recommended)](/terraform/cli/cloud/settings#arguments) and [remote backend](/terraform/language/settings/backends/remote#workspaces) and  documentation.
diff --git a/v1.5.7/website/docs/internals/archiving.mdx b/v1.5.7/website/docs/internals/archiving.mdx
new file mode 100644
index 0000000..f2caa06
--- /dev/null
+++ b/v1.5.7/website/docs/internals/archiving.mdx
@@ -0,0 +1,28 @@
+---
+page_title: Archiving Providers
+description: >-
+  Terraform is built on a plugin-based architecture, much of which is maintained
+  by our user community. Occasionally, unmaintained providers may archived to
+  reduce confusion for users and developers.
+---
+
+<!--
+This page is not in the Terraform documentation intentionally. Only link it from the README files of archived providers.
+-->
+
+# Archiving Providers
+
+As contributors' circumstances change, development on a community-maintained Terraform provider can slow. When this happens, HashiCorp may use GitHub's "archiving" feature on the provider's repository, to clearly signal the provider's status to users.
+
+What does archiving mean?
+
+1. The code repository and all commit, issue, and PR history will still be available.
+1. Existing released binaries will remain available on the releases site.
+1. Documentation for the provider will remain on the Terraform website.
+1. Issues and pull requests are not being monitored, merged, or added.
+1. No new releases will be published.
+1. Nightly acceptance tests may not be run.
+
+HashiCorp may archive a provider when we or the community are not able to support it at a level consistent with our open source guidelines and community expectations.
+
+Archiving is reversible. If anyone from the community is willing to maintain an archived provider, please reach out to the [Terraform Provider Development Program](/terraform/docs/partnerships) at _<terraform-provider-dev@hashicorp.com>_.
diff --git a/v1.5.7/website/docs/internals/credentials-helpers.mdx b/v1.5.7/website/docs/internals/credentials-helpers.mdx
new file mode 100644
index 0000000..485960b
--- /dev/null
+++ b/v1.5.7/website/docs/internals/credentials-helpers.mdx
@@ -0,0 +1,173 @@
+---
+page_title: Credentials Helpers
+description: >-
+  Credentials helpers are external programs that know how to store and retrieve
+  API tokens for remote Terraform services.
+---
+
+# Credentials Helpers
+
+For Terraform-specific features that interact with remote network services,
+such as [module registries](/terraform/registry) and
+[remote operations](/terraform/cloud-docs/run/cli), Terraform by default looks for
+API credentials to use in these calls in
+[the CLI configuration](/terraform/cli/config/config-file).
+
+Credentials helpers offer an alternative approach that allows you to customize
+how Terraform obtains credentials using an external program, which can then
+directly access an existing secrets management system in your organization.
+
+This page is about how to write and install a credentials helper. To learn
+how to configure a credentials helper that was already installed, see
+[the CLI config Credentials Helpers section](/terraform/cli/config/config-file#credentials-helpers).
+
+## How Terraform finds Credentials Helpers
+
+A credentials helper is a normal executable program that is installed in a
+particular location and whose name follows a specific naming convention.
+
+A credentials helper called "credstore", for example, would be implemented as
+an executable program named `terraform-credentials-credstore` (with an `.exe`
+extension on Windows only), and installed in one of the
+[default plugin search locations](/terraform/plugin/how-terraform-works#plugin-locations).
+
+## How Terraform runs Credentials Helpers
+
+Once Terraform has located the configured credentials helper, it will execute
+it once for each credentials request that cannot be satisfied by a `credentials`
+block in the CLI configuration.
+
+For the following examples, we'll assume a "credstore" credentials helper
+configured as follows:
+
+```
+credentials_helper "credstore" {
+  args = ["--host=credstore.example.com"]
+}
+```
+
+Terraform runs the helper program with each of the arguments given in `args`,
+followed by an _verb_ and then the hostname that the verb will apply to.
+The current set of verbs are:
+
+* `get`: retrieve the credentials for the given hostname
+* `store`: store new credentials for the given hostname
+* `forget`: delete any stored credentials for the given hostname
+
+To represent credentials, the credentials helper protocol uses a JSON object
+whose contents correspond with the contents of
+[`credentials` blocks in the CLI configuration](/terraform/cli/config/config-file#credentials).
+To represent an API token, the object contains a property called "token" whose
+value is the token string:
+
+```json
+{
+  "token": "example-token-value"
+}
+```
+
+The following sections describe the specific expected behaviors for each of the
+three verbs.
+
+## `get`: retrieve the credentials for the given hostname
+
+To retrieve credentials for `app.terraform.io`, Terraform would run the
+"credstore" helper as follows:
+
+```
+terraform-credentials-credstore --host=credstore.example.com get app.terraform.io
+```
+
+If the credentials helper is able to provide credentials for the given host
+then it must print a JSON credentials object to its stdout stream and then
+exit with status code zero to indicate success.
+
+If the credentials helper definitively has no credentials for the given host,
+then it must print an empty JSON object to stdout and exit with status zero.
+
+If the credentials helper is unable to provide the requested credentials for
+any other reason, it must print an end-user-oriented plain text error message
+to its stderr stream and then exit with a _non-zero_ status code.
+
+## `store`: store new credentials for the given hostname
+
+To store new credentials for `app.terraform.io`, Terraform would run the
+"credstore" helper as follows:
+
+```
+terraform-credentials-credstore --host=credstore.example.com store app.terraform.io
+```
+
+Terraform then writes a JSON credentials object to the helper program's stdin
+stream. If the helper is able to store the given credentials then it must do
+so and then exit with status code zero and no output on stdout or stderr to
+indicate success.
+
+If it is unable to store the given credentials for any reason, it _must_ still
+fully read its stdin until EOF and then print an end-user-oriented plain text
+error message to its stderr stream before exiting with a non-zero status
+code.
+
+The new credentials must fully replace any existing credentials stored for the
+given hostname.
+
+## `forget`: delete any stored credentials for the given hostname
+
+To forget any existing credentials for `app.terraform.io`, Terraform would run
+the "credstore" helper as follows:
+
+```
+terraform-credentials-credstore --host=credstore.example.com forget app.terraform.io
+```
+
+No JSON credentials objects are used for the `forget` verb.
+
+If the helper program is able to delete its stored credentials for the given
+hostname or if there are no such credentials stored already then it must
+exist with status code zero and produce no output on stdout or stderr.
+
+If it is unable to forget the stored credentials for any reason, particularly
+if the helper cannot be sure that the credentials are no longer available for
+retrieval, the helper program must print an end-user-oriented plain text error
+message to its stderr stream and then exit with a non-zero status code.
+
+## Handling Other Commands
+
+The credentials helper protocol may be extended with additional verbs in future,
+so for forward-compatibility a credentials helper must react to any unsupported
+verb by printing an end-user-oriented plain text error message to its stderr
+stream and then exiting with a non-zero status code.
+
+## Handling Unsupported Credentials Object Properties
+
+Terraform defines only the `token` property within JSON credentials
+objects.
+
+If a credentials helper is asked to store an object that has any properties
+other than `token` and if it is not able to faithfully retain them then it
+must behave as if the object is unstorable, returning an error. It must _not_
+store the `token` value in isolation and silently drop other properties, as
+that might change the meaning of the credentials object.
+
+If technically possible within the constraints of the target system, a
+credentials helper should prefer to store the whole JSON object as-is for
+later retrieval. For systems that are more constrained, it's acceptable to
+store only the `token` string so long as the program rejects objects containing
+other properties as described above.
+
+## Installing a Credentials Helper
+
+Terraform does not have any automatic installation mechanism for credentials
+helpers. Instead, the user must extract the helper program executable into
+one of the [default plugin search locations](/terraform/plugin/how-terraform-works#plugin-locations).
+
+If you are packaging a credentials helper for distribution, place it in an
+named with the expected naming scheme (`terraform-credentials-example`) and,
+if the containing archive format supports it and it's meaningful for the
+target operating system, mark the file as executable to increase the chances
+that it will work immediately after extraction.
+
+Terraform does _not_ honor the `-plugin-dir` argument to `terraform init` when
+searching for credentials helpers, because credentials are also used by other
+commands that can be run prior to `terraform init`. Only the default search
+locations are supported.
diff --git a/v1.5.7/website/docs/internals/debugging.mdx b/v1.5.7/website/docs/internals/debugging.mdx
new file mode 100644
index 0000000..fddcfe5
--- /dev/null
+++ b/v1.5.7/website/docs/internals/debugging.mdx
@@ -0,0 +1,27 @@
+---
+page_title: Debugging
+description: >-
+  Terraform has detailed logs which can be enabled by setting the TF_LOG
+  environment variable to any value. This will cause detailed logs to appear on
+  stderr
+---
+
+# Debugging Terraform
+
+> **Hands-on:** Try the [Create Dynamic Expressions](/terraform/tutorials/configuration-language/troubleshooting-workflow#bug-reporting-best-practices?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+Terraform has detailed logs that you can enable by setting the `TF_LOG` environment variable to any value. Enabling this setting causes detailed logs to appear on `stderr`.
+
+You can set `TF_LOG` to one of the log levels (in order of decreasing verbosity) `TRACE`, `DEBUG`, `INFO`, `WARN` or `ERROR` to change the verbosity of the logs.
+
+Setting `TF_LOG` to `JSON` outputs logs at the `TRACE` level or higher, and uses a parseable JSON encoding as the formatting.
+
+~> **Warning:** The JSON encoding of log files is not considered a stable interface. It may change at any time, without warning. It is meant to support tooling that will be forthcoming, and that tooling is the only supported way to interact with JSON formatted logs.
+
+Logging can be enabled separately for terraform itself and the provider plugins
+using the `TF_LOG_CORE` or `TF_LOG_PROVIDER` environment variables. These take
+the same level arguments as `TF_LOG`, but only activate a subset of the logs.
+
+To persist logged output you can set `TF_LOG_PATH` in order to force the log to always be appended to a specific file when logging is enabled. Note that even when `TF_LOG_PATH` is set, `TF_LOG` must be set in order for any logging to be enabled.
+
+If you find a bug with Terraform, please include the detailed log by using a service such as gist.
diff --git a/v1.5.7/website/docs/internals/functions-meta.mdx b/v1.5.7/website/docs/internals/functions-meta.mdx
new file mode 100644
index 0000000..734a341
--- /dev/null
+++ b/v1.5.7/website/docs/internals/functions-meta.mdx
@@ -0,0 +1,101 @@
+---
+page_title: Functions Metadata
+description: >-
+  The `terraform metadata functions` command prints signatures for all the
+  functions available in the current Terraform version.
+---
+
+# Functions Metadata
+
+The `terraform metadata functions` command is used to print signatures for the functions available in the current Terraform version.
+
+-> `terraform metadata functions` requires **Terraform v1.4 or later**.
+
+## Usage
+
+Usage: `terraform metadata functions [options]`
+
+The following flags are available:
+
+- `-json` - Displays the function signatures in a machine-readable, JSON format.
+
+Please note that, at this time, the `-json` flag is a _required_ option. In future releases, this command will be extended to allow for additional options.
+
+The output includes a `format_version` key, which as of Terraform 1.4.0 has
+value `"1.0"`. The semantics of this version are:
+
+- We will increment the minor version, e.g. `"1.1"`, for backward-compatible
+  changes or additions. Ignore any object properties with unrecognized names to
+  remain forward-compatible with future minor versions.
+- We will increment the major version, e.g. `"2.0"`, for changes that are not
+  backward-compatible. Reject any input which reports an unsupported major
+  version.
+
+We will introduce new major versions only within the bounds of
+[the Terraform 1.0 Compatibility Promises](/terraform/language/v1-compatibility-promises).
+
+## Format Summary
+
+The following sections describe the JSON output format by example, using a pseudo-JSON notation.
+Important elements are described with comments, which are prefixed with `//`.
+To avoid excessive repetition, we've split the complete format into several discrete sub-objects, described under separate headers. References wrapped in angle brackets (like `<block-representation>`) are placeholders which, in the real output, would be replaced by an instance of the specified sub-object.
+
+The JSON output format consists of the following objects and sub-objects:
+
+- [Function Signature Representation](#function-signature-representation) - the top-level object returned by `terraform metadata functions -json`
+- [Parameter Representation](#parameter-representation) - a sub-object of signatures that describes their parameters
+
+## Function Signature Representation
+
+```javascript
+{
+  "format_version": "1.0",
+
+  // "function_signatures" describes the signatures for all
+  // available functions.
+  "function_signatures": {
+    // keys in this map are the function names, such as "abs"
+    "example_function": {
+      // "description" is an English-language description of
+      // the purpose and usage of the function in Markdown.
+      "description": "string",
+
+      // "return_type" is a representation of a type specification
+      // that the function returns.
+      "return_type": "string",
+
+      // "parameters" is an optional list of the positional parameters
+      // that the function accepts.
+      "parameters": [
+        <parameter-representation>,
+        …
+      ],
+
+      // "variadic_parameter" is an optional representation of the
+      // additional arguments that the function accepts after those
+      // matching with the fixed parameters.
+      "variadic_parameter": <parameter-representation>
+    },
+    "example_function_two": { … }
+  }
+}
+```
+
+## Parameter Representation
+
+A parameter representation describes a parameter to a function.
+
+```javascript
+{
+  // "name" is the internal name of the parameter
+  "name": "string",
+
+  // "description" is an optional English-language description of
+  // the purpose and usage of the parameter in Markdown.
+  "description": "string",
+
+  // "type" is a representation of a type specification
+  // that the parameter's value must conform to.
+  "type": "string"
+}
+```
diff --git a/v1.5.7/website/docs/internals/graph.mdx b/v1.5.7/website/docs/internals/graph.mdx
new file mode 100644
index 0000000..77b99a7
--- /dev/null
+++ b/v1.5.7/website/docs/internals/graph.mdx
@@ -0,0 +1,123 @@
+---
+page_title: Resource Graph
+description: >-
+  Terraform builds a dependency graph from the Terraform configurations, and
+  walks this graph to generate plans, refresh state, and more. This page
+  documents the details of what are contained in this graph, what types of nodes
+  there are, and how the edges of the graph are determined.
+---
+
+# Resource Graph
+
+Terraform builds a
+[dependency graph](https://en.wikipedia.org/wiki/Dependency_graph)
+from the Terraform configurations, and walks this graph to
+generate plans, refresh state, and more. This page documents
+the details of what are contained in this graph, what types
+of nodes there are, and how the edges of the graph are determined.
+
+~> **Advanced Topic!** This page covers technical details
+of Terraform. You don't need to understand these details to
+effectively use Terraform. The details are documented here for
+those who wish to learn about them without having to go
+spelunking through the source code.
+
+For some background on graph theory, and a summary of how
+Terraform applies it, see the HashiCorp 2016 presentation
+[_Applying Graph Theory to Infrastructure as Code_](https://www.youtube.com/watch?v=Ce3RNfRbdZ0).
+This presentation also covers some similar ideas to the following
+guide.
+
+## Graph Nodes
+
+There are only a handful of node types that can exist within the
+graph. We'll cover these first before explaining how they're
+determined and built:
+
+- **Resource Node** - Represents a single resource. If you have
+  the `count` metaparameter set, then there will be one resource
+  node for each count. The configuration, diff, state, etc. of
+  the resource under change is attached to this node.
+
+- **Provider Configuration Node** - Represents the time to fully
+  configure a provider. This is when the provider configuration
+  block is given to a provider, such as AWS security credentials.
+
+- **Resource Meta-Node** - Represents a group of resources, but
+  does not represent any action on its own. This is done for
+  convenience on dependencies and making a prettier graph. This
+  node is only present for resources that have a `count`
+  parameter greater than 1.
+
+When visualizing a configuration with `terraform graph`, you can
+see all of these nodes present.
+
+## Building the Graph
+
+Building the graph is done in a series of sequential steps:
+
+1. Resources nodes are added based on the configuration. If a
+   diff (plan) or state is present, that meta-data is attached
+   to each resource node.
+
+1. Resources are mapped to provisioners if they have any
+   defined. This must be done after all resource nodes are
+   created so resources with the same provisioner type can
+   share the provisioner implementation.
+
+1. Explicit dependencies from the `depends_on` meta-parameter
+   are used to create edges between resources.
+
+1. If a state is present, any "orphan" resources are added to
+   the graph. Orphan resources are any resources that are no
+   longer present in the configuration but are present in the
+   state file. Orphans never have any configuration associated
+   with them, since the state file does not store configuration.
+
+1. Resources are mapped to providers. Provider configuration
+   nodes are created for these providers, and edges are created
+   such that the resources depend on their respective provider
+   being configured.
+
+1. Interpolations are parsed in resource and provider configurations
+   to determine dependencies. References to resource attributes
+   are turned into dependencies from the resource with the interpolation
+   to the resource being referenced.
+
+1. Create a root node. The root node points to all resources and
+   is created so there is a single root to the dependency graph. When
+   traversing the graph, the root node is ignored.
+
+1. If a diff is present, traverse all resource nodes and find resources
+   that are being destroyed. These resource nodes are split into two:
+   one node that destroys the resource and another that creates
+   the resource (if it is being recreated). The reason the nodes must
+   be split is because the destroy order is often different from the
+   create order, and so they can't be represented by a single graph
+   node.
+
+1. Validate the graph has no cycles and has a single root.
+
+## Walking the Graph
+
+<a id="walking-the-graph"></a>
+
+To walk the graph, a standard depth-first traversal is done. Graph
+walking is done in parallel: a node is walked as soon as all of its
+dependencies are walked.
+
+The amount of parallelism is limited using a semaphore to prevent too many
+concurrent operations from overwhelming the resources of the machine running
+Terraform. By default, up to 10 nodes in the graph will be processed
+concurrently. This number can be set using the `-parallelism` flag on the
+[plan](/terraform/cli/commands/plan), [apply](/terraform/cli/commands/apply), and
+[destroy](/terraform/cli/commands/destroy) commands.
+
+Setting `-parallelism` is considered an advanced operation and should not be
+necessary for normal usage of Terraform. It may be helpful in certain special
+use cases or to help debug Terraform issues.
+
+Note that some providers (AWS, for example), handle API rate limiting issues at
+a lower level by implementing graceful backoff/retry in their respective API
+clients. For this reason, Terraform does not use this `parallelism` feature to
+address API rate limits directly.
diff --git a/v1.5.7/website/docs/internals/index.mdx b/v1.5.7/website/docs/internals/index.mdx
new file mode 100644
index 0000000..eebfa5b
--- /dev/null
+++ b/v1.5.7/website/docs/internals/index.mdx
@@ -0,0 +1,17 @@
+---
+page_title: Internals
+description: >-
+  Learn how Terraform generates the resource dependency graph and executes other internal processes.
+---
+
+# Terraform Internals
+
+This section covers the internals of Terraform and explains how
+plans are generated, the lifecycle of a provider, etc. The goal
+of this section is to remove any notion of "magic" from Terraform.
+We want you to be able to trust and understand what Terraform is
+doing to function.
+
+-> **Note:** Knowledge of Terraform internals is not
+required to use Terraform. If you aren't interested in the internals
+of Terraform, you may safely skip this section.
diff --git a/v1.5.7/website/docs/internals/json-format.mdx b/v1.5.7/website/docs/internals/json-format.mdx
new file mode 100644
index 0000000..822a9b7
--- /dev/null
+++ b/v1.5.7/website/docs/internals/json-format.mdx
@@ -0,0 +1,739 @@
+---
+page_title: 'Internals: JSON Output Format'
+description: >-
+  Terraform provides a machine-readable JSON representation of state,
+  configuration and plan.
+---
+
+# JSON Output Format
+
+-> **Note:** This format is available in Terraform 0.12 and later.
+
+When Terraform plans to make changes, it prints a human-readable summary to the terminal. It can also, when run with `-out=<PATH>`, write a much more detailed binary plan file, which can later be used to apply those changes.
+
+Since the format of plan files isn't suited for use with external tools (and likely never will be), Terraform can output a machine-readable JSON representation of a plan file's changes. It can also convert state files to the same format, to simplify data loading and provide better long-term compatibility.
+
+Use `terraform show -json <FILE>` to generate a JSON representation of a plan or state file. See [the `terraform show` documentation](/terraform/cli/commands/show) for more details.
+
+The output includes a `format_version` key, which as of Terraform 1.1.0 has
+value `"1.0"`. The semantics of this version are:
+
+- We will increment the minor version, e.g. `"1.1"`, for backward-compatible
+  changes or additions. Ignore any object properties with unrecognized names to
+  remain forward-compatible with future minor versions.
+- We will increment the major version, e.g. `"2.0"`, for changes that are not
+  backward-compatible. Reject any input which reports an unsupported major
+  version.
+
+We will introduce new major versions only within the bounds of
+[the Terraform 1.0 Compatibility Promises](/terraform/language/v1-compatibility-promises).
+
+## Format Summary
+
+The following sections describe the JSON output format by example, using a pseudo-JSON notation.
+
+Important elements are described with comments, which are prefixed with `//`.
+
+To avoid excessive repetition, we've split the complete format into several discrete sub-objects, described under separate headers. References wrapped in angle brackets (like `<values-representation>`) are placeholders which, in the real output, would be replaced by an instance of the specified sub-object.
+
+The JSON output format consists of the following objects and sub-objects:
+
+- [State Representation](#state-representation) — The complete top-level object returned by `terraform show -json <STATE FILE>`.
+- [Plan Representation](#plan-representation) — The complete top-level object returned by `terraform show -json <PLAN FILE>`.
+- [Values Representation](#values-representation) — A sub-object of both plan and state output that describes current state or planned state.
+- [Configuration Representation](#configuration-representation) — A sub-object of plan output that describes a parsed Terraform configuration.
+  - [Expression Representation](#expression-representation) — A sub-object of a configuration representation that describes an unevaluated expression.
+  - [Block Expressions Representation](#block-expressions-representation) — A sub-object of a configuration representation that describes the expressions nested inside a block.
+- [Change Representation](#change-representation) — A sub-object of plan output that describes changes to an object.
+- [Checks Representation](#checks-representation) — A property of both the plan and state representations that describes the current status of any checks (e.g. preconditions and postconditions) in the configuration.
+
+## State Representation
+
+State does not have any significant metadata not included in the common [values representation](#values-representation), so the `<state-representation>` uses the following format:
+
+```javascript
+{
+  // "values" is a values representation object derived from the values in the
+  // state. Because the state is always fully known, this is always complete.
+  "values": <values-representation>
+
+  "terraform_version": "version.string"
+}
+```
+
+## Plan Representation
+
+A plan consists of a prior state, the configuration that is being applied to that state, and the set of changes Terraform plans to make to achieve that.
+
+For ease of consumption by callers, the plan representation includes a partial representation of the values in the final state (using a [value representation](#values-representation)), allowing callers to easily analyze the planned outcome using similar code as for analyzing the prior state.
+
+```javascript
+{
+  "format_version": "1.0",
+
+  // "prior_state" is a representation of the state that the configuration is
+  // being applied to, using the state representation described above.
+  "prior_state":  <state-representation>,
+
+  // "configuration" is a representation of the configuration being applied to the
+  // prior state, using the configuration representation described above.
+  "configuration": <configuration-representation>,
+
+  // "planned_values" is a description of what is known so far of the outcome in
+  // the standard value representation, with any as-yet-unknown values omitted.
+  "planned_values": <values-representation>,
+
+  // "proposed_unknown" is a representation of the attributes, including any
+  // potentially-unknown attributes. Each value is replaced with "true" or
+  // "false" depending on whether it is known in the proposed plan.
+  "proposed_unknown": <values-representation>,
+
+  // "variables" is a representation of all the variables provided for the given
+  // plan. This is structured as a map similar to the output map so we can add
+  // additional fields in later.
+  "variables": {
+    "varname": {
+      "value": "varvalue"
+    },
+  },
+
+  // "resource_changes" is a description of the individual change actions that
+  // Terraform plans to use to move from the prior state to a new state
+  // matching the configuration.
+  "resource_changes": [
+    // Each element of this array describes the action to take
+    // for one instance object. All resources in the
+    // configuration are included in this list.
+    {
+      // "address" is the full absolute address of the resource instance this
+      // change applies to, in the same format as addresses in a value
+      // representation.
+      "address": "module.child.aws_instance.foo[0]",
+
+      // "previous_address" is the full absolute address of this resource
+      // instance as it was known after the previous Terraform run.
+      // Included only if the address has changed, e.g. by handling
+      // a "moved" block in the configuration.
+      "previous_address": "module.instances.aws_instance.foo[0]",
+
+      // "module_address", if set, is the module portion of the above address.
+      // Omitted if the instance is in the root module.
+      "module_address": "module.child",
+
+      // "mode", "type", "name", and "index" have the same meaning as in a
+      // value representation.
+      "mode": "managed",
+      "type": "aws_instance",
+      "name": "foo",
+      "index": 0,
+
+      // "deposed", if set, indicates that this action applies to a "deposed"
+      // object of the given instance rather than to its "current" object.
+      // Omitted for changes to the current object. "address" and "deposed"
+      // together form a unique key across all change objects in a particular
+      // plan. The value is an opaque key representing the specific deposed
+      // object.
+      "deposed": "deadbeef",
+
+      // "change" describes the change that will be made to the indicated
+      // object. The <change-representation> is detailed in a section below.
+      "change": <change-representation>,
+
+      // "action_reason" is some optional extra context about why the
+      // actions given inside "change" were selected. This is the JSON
+      // equivalent of annotations shown in the normal plan output like
+      // "is tainted, so must be replaced" as opposed to just "must be
+      // replaced".
+      //
+      // These reason codes are display hints only and the set of possible
+      // hints may change over time. Users of this must be prepared to
+      // encounter unrecognized reasons and treat them as unspecified reasons.
+      //
+      // The current set of possible values is:
+      // - "replace_because_tainted": the object in question is marked as
+      //   "tainted" in the prior state, so Terraform planned to replace it.
+      // - "replace_because_cannot_update": the provider indicated that one
+      //   of the requested changes isn't possible without replacing the
+      //   existing object with a new object.
+      // - "replace_by_request": the user explicitly called for this object
+      //   to be replaced as an option when creating the plan, which therefore
+      //   overrode what would have been a "no-op" or "update" action otherwise.
+      // - "delete_because_no_resource_config": Terraform found no resource
+      //   configuration corresponding to this instance.
+      // - "delete_because_no_module": The resource instance belongs to a
+      //   module instance that's no longer declared, perhaps due to changing
+      //   the "count" or "for_each" argument on one of the containing modules.
+      // - "delete_because_wrong_repetition": The instance key portion of the
+      //   resource address isn't of a suitable type for the corresponding
+      //   resource's configured repetition mode (count, for_each, or neither).
+      // - "delete_because_count_index": The corresponding resource uses count,
+      //   but the instance key is out of range for the currently-configured
+      //   count value.
+      // - "delete_because_each_key": The corresponding resource uses for_each,
+      //   but the instance key doesn't match any of the keys in the
+      //   currently-configured for_each value.
+      // - "read_because_config_unknown": For a data resource, Terraform cannot
+      //   read the data during the plan phase because of values in the
+      //   configuration that won't be known until the apply phase.
+      // - "read_because_dependency_pending": For a data resource, Terraform
+      //   cannot read the data during the plan phase because the data
+      //   resource depends on at least one managed resource that also has
+      //   a pending change in the same plan.
+      //
+      // If there is no special reason to note, Terraform will omit this
+      // property altogether.
+      action_reason: "replace_because_tainted"
+    }
+  ],
+
+  // "resource_drift" is a description of the changes Terraform detected
+  // when it compared the most recent state to the prior saved state.
+  "resource_drift": [
+    {
+        // "resource_drift" uses the same object structure as
+        // "resource_changes".
+    }
+  ],
+
+  // "relevant_attributes" lists the sources of all values contributing to
+  // changes in the plan. You can use "relevant_attributes" to filter
+  // "resource_drift" and determine which external changes may have affected the
+  // plan result.
+  "relevant_attributes": [
+    {
+      "resource": "aws_instance.foo",
+      "attribute": "attr",
+    }
+  ]
+
+  // "output_changes" describes the planned changes to the output values of the
+  // root module.
+  "output_changes": {
+    // Keys are the defined output value names.
+    "foo": {
+
+      // "change" describes the change that will be made to the indicated output
+      // value, using the same representation as for resource changes except
+      // that the only valid actions values are:
+      //   ["create"]
+      //   ["update"]
+      //   ["delete"]
+      // In the Terraform CLI 0.12.0 release, Terraform is not yet fully able to
+      // track changes to output values, so the actions indicated may not be
+      // fully accurate, but the "after" value will always be correct.
+      "change": <change-representation>,
+    }
+  },
+
+  // "checks" describes the partial results for any checkable objects, such as
+  // resources with postconditions, with as much information as Terraform can
+  // recognize at plan time. Some objects will have status "unknown" to
+  // indicate that their status will only be determined after applying the plan.
+  "checks" <checks-representation>
+}
+```
+
+This overall plan structure, fully expanded, is what will be printed by the `terraform show -json <planfile>` command.
+
+## Values Representation
+
+A values representation is used in both state and plan output to describe current state (which is always complete) and planned state (which omits values not known until apply).
+
+The following example illustrates the structure of a `<values-representation>`:
+
+```javascript
+{
+  // "outputs" describes the outputs from the root module. Outputs from
+  // descendent modules are not available because they are not retained in all
+  // of the underlying structures we will build this values representation from.
+  "outputs": {
+    "private_ip": {
+      "value": "192.168.3.2",
+      "type": "string",
+      "sensitive": false
+    }
+  },
+
+  // "root_module" describes the resources and child modules in the root module.
+  "root_module": {
+    "resources": [
+      {
+        // "address" is the absolute resource address, which callers must consider
+        // opaque but may do full string comparisons with other address strings or
+        // pass this verbatim to other Terraform commands that are documented to
+        // accept absolute resource addresses. The module-local portions of this
+        // address are extracted in other properties below.
+        "address": "aws_instance.example[1]",
+
+        // "mode" can be "managed", for resources, or "data", for data resources
+        "mode": "managed",
+        "type": "aws_instance",
+        "name": "example",
+
+        // If the count or for_each meta-arguments are set for this resource, the
+        // additional key "index" is present to give the instance index key. This
+        // is omitted for the single instance of a resource that isn't using count
+        // or for_each.
+        "index": 1,
+
+        // "provider_name" is the name of the provider that is responsible for
+        // this resource. This is only the provider name, not a provider
+        // configuration address, and so no module path nor alias will be
+        // indicated here. This is included to allow the property "type" to be
+        // interpreted unambiguously in the unusual situation where a provider
+        // offers a resource type whose name does not start with its own name,
+        // such as the "googlebeta" provider offering "google_compute_instance".
+        "provider_name": "aws",
+
+        // "schema_version" indicates which version of the resource type schema
+        // the "values" property conforms to.
+        "schema_version": 2,
+
+        // "values" is the JSON representation of the attribute values of the
+        // resource, whose structure depends on the resource type schema. Any
+        // unknown values are omitted or set to null, making them
+        // indistinguishable from absent values; callers which need to distinguish
+        // unknown from unset must use the plan-specific or configuration-specific
+        // structures described in later sections.
+        "values": {
+          "id": "i-abc123",
+          "instance_type": "t2.micro",
+          // etc, etc
+        },
+
+        // "sensitive_values" is the JSON representation of the sensitivity of
+        // the resource's attribute values. Only attributes which are sensitive
+        // are included in this structure.
+        "sensitive_values": {
+          "id": true,
+        }
+      }
+    ]
+
+    "child_modules": [
+      // Each entry in "child_modules" has the same structure as the root_module
+      // object, with the additional "address" property shown below.
+      {
+        // "address" is the absolute module address, which callers must treat as
+        // opaque but may do full string comparisons with other module address
+        // strings and may pass verbatim to other Terraform commands that are
+        // documented as accepting absolute module addresses.
+        "address": "module.child",
+
+        // "resources" is the same as in "root_module" above
+        "resources": [
+            {
+              "address": "module.child.aws_instance.foo",
+              // etc, etc
+            }
+        ],
+
+        // Each module object can optionally have its own
+        // nested "child_modules", recursively describing the
+        // full module tree.
+        "child_modules": [ ... ],
+      }
+    ]
+  }
+}
+```
+
+The translation of attribute and output values is the same intuitive mapping from HCL types to JSON types used by Terraform's [`jsonencode`](/terraform/language/functions/jsonencode) function. This mapping does lose some information: lists, sets, and tuples all lower to JSON arrays while maps and objects both lower to JSON objects. Unknown values and null values are both treated as absent or null.
+
+Output values include a `"type"` field, which is a [serialization of the value's type](https://pkg.go.dev/github.com/zclconf/go-cty/cty#Type.MarshalJSON). For primitive types this is a string value, such as `"number"` or `"bool"`. Complex types are represented as a nested JSON array, such as `["map","string"]` or `["object",{"a":"number"}]`. This can be used to reconstruct the output value with the correct type.
+
+Only the "current" object for each resource instance is described. "Deposed" objects are not reflected in this structure at all; in plan representations, you can refer to the change representations for further details.
+
+The intent of this structure is to give a caller access to a similar level of detail as is available to expressions within the configuration itself. This common representation is not suitable for all use-cases because it loses information compared to the data structures it is built from. For more complex needs, use the more elaborate changes and configuration representations.
+
+## Configuration Representation
+
+Configuration is the most complicated structure in Terraform, since it includes unevaluated expression nodes and other complexities.
+
+Because the configuration models are produced at a stage prior to expression evaluation, it is not possible to produce a values representation for configuration. Instead, we describe the physical structure of the configuration, giving access to constant values where possible and allowing callers to analyze any references to other objects that are present:
+
+```javascript
+{
+  // "provider_configs" describes all of the provider configurations throughout
+  // the configuration tree, flattened into a single map for convenience since
+  // provider configurations are the one concept in Terraform that can span
+  // across module boundaries.
+  "provider_config": {
+
+    // Keys in the provider_configs map are to be considered opaque by callers,
+    // and used just for lookups using the "provider_config_key" property in each
+    // resource object.
+    "opaque_provider_ref_aws": {
+
+      // "name" is the name of the provider without any alias
+      "name": "aws",
+
+      // "full_name" is the fully-qualified provider name
+      "full_name": "registry.terraform.io/hashicorp/aws",
+
+      // "alias" is the alias set for a non-default configuration, or unset for
+      // a default configuration.
+      "alias": "foo",
+
+      // "module_address" is included only for provider configurations that are
+      // declared in a descendent module, and gives the opaque address for the
+      // module that contains the provider configuration.
+      "module_address": "module.child",
+
+      // "expressions" describes the provider-specific content of the
+      // configuration block, as a block expressions representation (see section
+      // below).
+      "expressions": <block-expressions-representation>
+    }
+  },
+
+  // "root_module" describes the root module in the configuration, and serves
+  // as the root of a tree of similar objects describing descendent modules.
+  "root_module": {
+
+    // "outputs" describes the output value configurations in the module.
+    "outputs": {
+
+      // Property names here are the output value names
+      "example": {
+        "expression": <expression-representation>,
+        "sensitive": false
+      }
+    },
+
+    // "resources" describes the "resource" and "data" blocks in the module
+    // configuration.
+    "resources": [
+      {
+        // "address" is the opaque absolute address for the resource itself.
+        "address": "aws_instance.example",
+
+        // "mode", "type", and "name" have the same meaning as for the resource
+        // portion of a value representation.
+        "mode": "managed",
+        "type": "aws_instance",
+        "name": "example",
+
+        // "provider_config_key" is the key into "provider_configs" (shown
+        // above) for the provider configuration that this resource is
+        // associated with. If the provider configuration was passed into
+        // this module from the parent module, the key will point to the
+        // original provider config block.
+        "provider_config_key": "opaque_provider_ref_aws",
+
+        // "provisioners" is an optional field which describes any provisioners.
+        // Connection info will not be included here.
+        "provisioners": [
+          {
+            "type": "local-exec",
+
+            // "expressions" describes the provisioner configuration
+            "expressions": <block-expressions-representation>
+          },
+        ],
+
+        // "expressions" describes the resource-type-specific content of the
+        // configuration block.
+        "expressions": <block-expressions-representation>,
+
+        // "schema_version" is the schema version number indicated by the
+        // provider for the type-specific arguments described in "expressions".
+        "schema_version": 2,
+
+        // "count_expression" and "for_each_expression" describe the expressions
+        // given for the corresponding meta-arguments in the resource
+        // configuration block. These are omitted if the corresponding argument
+        // isn't set.
+        "count_expression": <expression-representation>,
+        "for_each_expression": <expression-representation>
+      },
+    ],
+
+    // "module_calls" describes the "module" blocks in the module. During
+    // evaluation, a module call with count or for_each may expand to multiple
+    // module instances, but in configuration only the block itself is
+    // represented.
+    "module_calls": {
+
+      // Key is the module call name chosen in the configuration.
+      "child": {
+
+        // "resolved_source" is the resolved source address of the module, after
+        // any normalization and expansion. This could be either a
+        // go-getter-style source address or a local path starting with "./" or
+        // "../". If the user gave a registry source address then this is the
+        // final location of the module as returned by the registry, after
+        // following any redirect indirection.
+        "resolved_source": "./child"
+
+        // "expressions" describes the expressions for the arguments within the
+        // block that correspond to input variables in the child module.
+        "expressions": <block-expressions-representation>,
+
+        // "count_expression" and "for_each_expression" describe the expressions
+        // given for the corresponding meta-arguments in the module
+        // configuration block. These are omitted if the corresponding argument
+        // isn't set.
+        "count_expression": <expression-representation>,
+        "for_each_expression": <expression-representation>,
+
+        // "module" is a representation of the configuration of the child module
+        // itself, using the same structure as the "root_module" object,
+        // recursively describing the full module tree.
+        "module": <module-configuration-representation>
+      }
+    }
+  }
+}
+```
+
+### Expression Representation
+
+Each unevaluated expression in the configuration is represented with an `<expression-representation>` object with the following structure:
+
+```javascript
+{
+  // "constant_value" is set only if the expression contains no references to
+  // other objects, in which case it gives the resulting constant value. This is
+  // mapped as for the individual values in a value representation.
+  "constant_value": "hello",
+
+  // Alternatively, "references" will be set to a list of references in the
+  // expression. Multi-step references will be unwrapped and duplicated for each
+  // significant traversal step, allowing callers to more easily recognize the
+  // objects they care about without attempting to parse the expressions.
+  // Callers should only use string equality checks here, since the syntax may
+  // be extended in future releases.
+  "references": [
+    "data.template_file.foo[1].vars[\"baz\"]",
+    "data.template_file.foo[1].vars", // implied by previous
+    "data.template_file.foo[1]", // implied by previous
+    "data.template_file.foo", // implied by previous
+    "module.foo.bar",
+    "module.foo", // implied by the previous
+    "var.example[0]",
+    "var.example", // implied by the previous
+
+    // Partial references like "data" and "module" are not included, because
+    // Terraform considers "module.foo" to be an atomic reference, not an
+    // attribute access.
+  ]
+}
+```
+
+-> **Note:** Expressions in `dynamic` blocks are not included in the configuration representation.
+
+### Block Expressions Representation
+
+In some cases, it is the entire content of a block (possibly after certain special arguments have already been handled and removed) that must be represented. For that, we have an `<block-expressions-representation>` structure:
+
+```javascript
+{
+  // Attribute arguments are mapped directly with the attribute name as key and
+  // an <expression-representation> as value.
+  "ami": <expression-representation>,
+  "instance_type": <expression-representation>,
+
+  // Nested block arguments are mapped as either a single nested
+  // <block-expressions-representation> or an array object of these, depending on the
+  // block nesting mode chosen in the schema.
+  //  - "single" nesting is a direct <block-expressions-representation>
+  //  - "list" and "set" produce arrays
+  //  - "map" produces an object
+  "root_block_device": <expression-representation>,
+  "ebs_block_device": [
+    <expression-representation>
+  ]
+}
+```
+
+For now we expect callers to just hard-code assumptions about the schemas of particular resource types in order to process these expression representations. In a later release we will add new inspection commands to return machine-readable descriptions of the schemas themselves, allowing for more generic handling in programs such as visualization tools.
+
+## Change Representation
+
+A `<change-representation>` describes the change to the indicated object.
+
+```javascript
+{
+  // "actions" are the actions that will be taken on the object selected by the
+  // properties below.
+  // Valid actions values are:
+  //    ["no-op"]
+  //    ["create"]
+  //    ["read"]
+  //    ["update"]
+  //    ["delete", "create"]
+  //    ["create", "delete"]
+  //    ["delete"]
+  // The two "replace" actions are represented in this way to allow callers to
+  // e.g. just scan the list for "delete" to recognize all three situations
+  // where the object will be deleted, allowing for any new deletion
+  // combinations that might be added in future.
+  "actions": ["update"],
+
+  // "before" and "after" are representations of the object value both before
+  // and after the action. For ["create"] and ["delete"] actions, either
+  // "before" or "after" is unset (respectively). For ["no-op"], the before and
+  // after values are identical. The "after" value will be incomplete if there
+  // are values within it that won't be known until after apply.
+  "before": <value-representation>,
+  "after": <value-representation>,
+
+  // "after_unknown" is an object value with similar structure to "after", but
+  // with all unknown leaf values replaced with "true", and all known leaf
+  // values omitted. This can be combined with "after" to reconstruct a full
+  // value after the action, including values which will only be known after
+  // apply.
+  "after_unknown": {
+    "id": true
+  },
+
+  // "before_sensitive" and "after_sensitive" are object values with similar
+  // structure to "before" and "after", but with all sensitive leaf values
+  // replaced with true, and all non-sensitive leaf values omitted. These
+  // objects should be combined with "before" and "after" to prevent accidental
+  // display of sensitive values in user interfaces.
+  "before_sensitive": {},
+  "after_sensitive": {
+    "triggers": {
+      "boop": true
+    }
+  },
+
+  // "replace_paths" is an array of arrays representing a set of paths into the
+  // object value which resulted in the action being "replace". This will be
+  // omitted if the action is not replace, or if no paths caused the
+  // replacement (for example, if the resource was tainted). Each path
+  // consists of one or more steps, each of which will be a number or a
+  // string.
+  "replace_paths": [["triggers"]]
+}
+```
+
+## Checks Representation
+
+~> **Warning:** The JSON representation of checks is experimental
+and some details may change in future Terraform versions based on feedback,
+even in minor releases of Terraform CLI.
+
+A `<checks-representation>` describes the current state of a checkable object in the configuration. For example, a resource with one or more preconditions or postconditions is an example of a checkable object, and its check state represents the results of those conditions.
+
+```javascript
+[
+  {
+    // "address" describes the address of the checkable object whose status
+    // this object is describing.
+    "address": {
+      // "kind" specifies what kind of checkable object this is. Different
+      // kinds of object will have different additional properties inside the
+      // address object, but all kinds include both "kind" and "to_display".
+      // The two valid kinds are "resource" and "output_value".
+      "kind": "resource",
+
+      // "to_display" contains an opaque string representation of the address
+      // of the object that is suitable for display in a UI. For consumers that
+      // have special handling depending on the value of "kind", this property
+      // is a good fallback to use when the application doesn't recognize the
+      // "kind" value.
+      "to_display": "aws_instance.example",
+
+      // "mode" is included for kind "resource" only, and specifies the resource
+      // mode which can either be "managed" (for "resource" blocks) or "data"
+      // (for "data" blocks).
+      "mode": "managed",
+
+      // "type" is included for kind "resource" only, and specifies the resource
+      // type.
+      "type": "aws_instance",
+
+      // "name" is the local name of the object. For a resource this is the
+      // second label in the resource block header, and for an output value
+      // this is the single label in the output block header.
+      "name": "example",
+
+      // "module" is included if the object belongs to a module other than
+      // the root module, and provides an opaque string representation of the
+      // module this object belongs to. This example is of a root module
+      // resource and so "module" is not included.
+    }
+
+    // "status" is the aggregate status of all of the instances of the object
+    // being described by this object.
+    // The possible values are "pass", "fail", "error", and "unknown".
+    "status": "fail",
+
+    // "instances" describes the current status of each of the instances of
+    // the object being described. An object can have multiple instances if
+    // it is either a resource which has "count" or "for_each" set, or if
+    // it's contained within a module that has "count" or "for_each" set.
+    //
+    // If "instances" is empty or omitted, that can either mean that the object
+    // has no instances at all (e.g. count = 0) or that an error blocked
+    // evaluation of the repetition argument. You can distinguish these cases
+    // using the "status" property, which will be "pass" or "error" for a
+    // zero-instance object and "unknown" for situations where an error blocked
+    // evalation.
+    "instances": [
+      {
+        // "address" is an object similar to the property of the same name in
+        // the containing object. Merge the instance-level address into the
+        // object-level address, overwriting any conflicting property names,
+        // to create a full description of the instance's address.
+        "address": {
+          // "to_display" overrides the property of the same name in the main
+          // object's address, to include any module instance or resource
+          // instance keys that uniquely identify this instance.
+          "to_display": "aws_instance.example[0]",
+
+          // "instance_key" is included for resources only and specifies the
+          // resource-level instance key, which can either be a number or a
+          // string. Omitted for single-instance resources.
+          "instance_key": 0,
+
+          // "module" is included if the object belongs to a module other than
+          // the root module, and provides an opaque string representation of the
+          // module instance this object belongs to.
+        },
+
+        // "status" describes the result of running the configured checks
+        // against this particular instance of the object, with the same
+        // possible values as the "status" in the parent object.
+        //
+        // "fail" means that the condition evaluated successfully but returned
+        // false, while "error" means that the condition expression itself
+        // was invalid.
+        "status": "fail",
+
+        // "problems" might be included for statuses "fail" or "error", in
+        // which case it describes the individual conditions that failed for
+        // this instance, if any.
+        // When a condition expression is invalid, Terraform returns that as
+        // a normal error message rather than as a problem in this list.
+        "problems": [
+          {
+            // "message" is the string that resulted from evaluating the
+            // error_message argument of the failing condition.
+            "message": "Server does not have a public IPv6 address."
+          }
+        ]
+      },
+    ]
+  }
+]
+```
+
+The "checks" model includes both static checkable objects and instances of
+those objects to ensure that the set of checkable objects will be consistent
+even if an error prevents full evaluation of the configuration. Any object
+in the configuration which has associated checks, such as a resource with
+preconditions or postconditions, will always be included as a checkable object
+even if a runtime error prevents Terraform from evaluating its "count" or
+"for_each" argument and therefore determining which instances of that object
+exist dynamically.
+
+When summarizing checks in a UI, we recommend preferring to list only the
+individual instances and typically ignoring the top-level objects altogether.
+However, in any case where an object has _zero_ instances, the UI should show
+the top-level object instead to serve as a placeholder so that the user can
+see that Terraform recognized the existence of the checks, even if it wasn't
+able to evaluate them on the most recent run.
diff --git a/v1.5.7/website/docs/internals/login-protocol.mdx b/v1.5.7/website/docs/internals/login-protocol.mdx
new file mode 100644
index 0000000..c0406a4
--- /dev/null
+++ b/v1.5.7/website/docs/internals/login-protocol.mdx
@@ -0,0 +1,111 @@
+---
+page_title: Login Protocol
+description: >-
+  The login protocol is used for authenticating Terraform against servers
+  providing Terraform-native services.
+---
+
+# Server-side Login Protocol
+
+~> **Note:** You don't need to read these docs to _use_
+[`terraform login`](/terraform/cli/commands/login).  The information below is for
+anyone intending to implement the server side of `terraform login` in order to
+offer Terraform-native services in a third-party system.
+
+The `terraform login` command supports performing an OAuth 2.0 authorization
+request using configuration provided by the target host. You may wish to
+implement this protocol if you are producing a third-party implementation of
+any [Terraform-native services](/terraform/internals/remote-service-discovery),
+such as a Terraform module registry.
+
+First, Terraform uses
+[remote service discovery](/terraform/internals/remote-service-discovery) to
+find the OAuth configuration for the host. The host must support the service
+name `login.v1` and define for it an object containing OAuth client
+configuration values, like this:
+
+```json
+{
+  "login.v1": {
+    "client": "terraform-cli",
+    "grant_types": ["authz_code"],
+    "authz": "/oauth/authorization",
+    "token": "/oauth/token",
+    "ports": [10000, 10010],
+  }
+}
+```
+
+The properties within the discovery object are as follows:
+
+* `client` (Required): The `client_id` value to use when making requests, as
+  defined in [RFC 6749 section 2.2](https://tools.ietf.org/html/rfc6749#section-2.2).
+
+  Because Terraform is a _public client_ (it is installed on end-user systems
+  and thus cannot protect an OAuth client secret), the `client_id` is purely
+  advisory and the server must not use it as a guarantee that an authorization
+  request is truly coming from Terraform.
+
+* `grant_types` (Optional): A JSON array of strings describing a set of OAuth
+  2.0 grant types the server is able to support. A "grant type" selects a
+  specific mechanism by which an OAuth server authenticates the request and
+  issues an authorization token.
+
+  Terraform CLI supports a single grant type:
+
+  * `authz_code`: [authorization code grant](https://tools.ietf.org/html/rfc6749#section-4.1).
+    Both the `authz` and `token` properties are required when `authz_code` is
+    present.
+
+  If not specified, `grant_types` defaults to `["authz_code"]`.
+
+* `authz` (Required if needed for a given grant type): the server's
+  [authorization endpoint](https://tools.ietf.org/html/rfc6749#section-3.1).
+  If given as a relative URL, it is resolved from the location of the
+  service discovery document.
+
+* `token` (Required if needed for a given grant type): the server's
+  [token endpoint](https://tools.ietf.org/html/rfc6749#section-3.2).
+  If given as a relative URL, it is resolved from the location of the
+  service discovery document.
+
+* `ports` (Optional): A two-element JSON array giving an inclusive range of
+  TCP ports that Terraform may use for the temporary HTTP server it will start
+  to provide the [redirection endpoint](https://tools.ietf.org/html/rfc6749#section-3.1.2)
+  for the first step of an authorization code grant. Terraform opens a TCP
+  listen port on the loopback interface in order to receive the response from
+  the server's authorization endpoint.
+
+  If not specified, Terraform is free to select any TCP port greater than or
+  equal to 1024.
+
+  Terraform allows constraining this port range for interoperability with OAuth
+  server implementations that require each `client_id` to be associated with
+  a fixed set of valid redirection endpoint URLs. Configure such a server
+  to expect a range of URLs of the form `http://localhost:10000/`
+  with different consecutive port numbers, and then specify that port range
+  using `ports`.
+
+  We recommend allowing at least 10 distinct port numbers if possible, and
+  assigning them to numbers greater than or equal to 10000, to minimize the
+  risk that all of the possible ports will already be in use on a particular
+  system.
+
+When requesting an authorization code grant, Terraform CLI implements the
+[Proof Key for Code Exchange](https://tools.ietf.org/html/rfc7636) extension in
+order to protect against other applications on the system intercepting the
+incoming request to the redirection endpoint. We strongly recommend that you
+select an OAuth server implementation that also implements this extension and
+verifies the code challenge sent to the token endpoint.
+
+Terraform CLI does not support OAuth refresh tokens or token expiration. If your
+server issues time-limited tokens, Terraform CLI will simply begin receiving
+authorization errors once the token expires, after which the user can run
+`terraform login` again to obtain a new token.
+
+-> **Note:** As a special case, Terraform can use a
+[Resource Owner Password Credentials Grant](https://tools.ietf.org/html/rfc6749#section-4.3)
+only when interacting with `app.terraform.io` ([Terraform Cloud](https://cloud.hashicorp.com/products/terraform)),
+under the recommendation in the OAuth specification to use this grant type only
+when the client and server are closely related. The `password` grant type is
+not supported for any other hostname and will be ignored.
diff --git a/v1.5.7/website/docs/internals/machine-readable-ui.mdx b/v1.5.7/website/docs/internals/machine-readable-ui.mdx
new file mode 100644
index 0000000..86088c5
--- /dev/null
+++ b/v1.5.7/website/docs/internals/machine-readable-ui.mdx
@@ -0,0 +1,601 @@
+---
+page_title: 'Internals: Machine-Readable UI'
+description: >-
+  Terraform provides a machine-readable streaming JSON UI output for plan,
+  apply, and refresh operations.
+---
+
+# Machine-Readable UI
+
+-> **Note:** This format is available in Terraform 0.15.3 and later.
+
+By default, many Terraform commands display UI output as unstructured text, intended to be read by a user via a terminal emulator. This text stream is not a stable interface for integrations. Some commands support a `-json` flag, which enables a structured JSON output mode with a defined interface.
+
+For long-running commands such as `plan`, `apply`, and `refresh`, the `-json` flag outputs a stream of JSON UI messages, one per line. These can be processed one message at a time, with integrating software filtering, combining, or modifying the output as desired.
+
+The first message output has type `version`, and includes a `ui` key, which as of Terraform 1.1.0 has
+value `"1.0"`. The semantics of this version are:
+
+- We will increment the minor version, e.g. `"1.1"`, for backward-compatible
+  changes or additions. Ignore any object properties with unrecognized names to
+  remain forward-compatible with future minor versions.
+- We will increment the major version, e.g. `"2.0"`, for changes that are not
+  backward-compatible. Reject any input which reports an unsupported major
+  version.
+
+We will introduce new major versions only within the bounds of
+[the Terraform 1.0 Compatibility Promises](/terraform/language/v1-compatibility-promises).
+
+## Sample JSON Output
+
+Below is sample output from running `terraform apply -json`:
+
+```javascript
+{"@level":"info","@message":"Terraform 0.15.4","@module":"terraform.ui","@timestamp":"2021-05-25T13:32:41.275359-04:00","terraform":"0.15.4","type":"version","ui":"0.1.0"}
+{"@level":"info","@message":"random_pet.animal: Plan to create","@module":"terraform.ui","@timestamp":"2021-05-25T13:32:41.705503-04:00","change":{"resource":{"addr":"random_pet.animal","module":"","resource":"random_pet.animal","implied_provider":"random","resource_type":"random_pet","resource_name":"animal","resource_key":null},"action":"create"},"type":"planned_change"}
+{"@level":"info","@message":"Plan: 1 to add, 0 to change, 0 to destroy.","@module":"terraform.ui","@timestamp":"2021-05-25T13:32:41.705638-04:00","changes":{"add":1,"change":0,"remove":0,"operation":"plan"},"type":"change_summary"}
+{"@level":"info","@message":"random_pet.animal: Creating...","@module":"terraform.ui","@timestamp":"2021-05-25T13:32:41.825308-04:00","hook":{"resource":{"addr":"random_pet.animal","module":"","resource":"random_pet.animal","implied_provider":"random","resource_type":"random_pet","resource_name":"animal","resource_key":null},"action":"create"},"type":"apply_start"}
+{"@level":"info","@message":"random_pet.animal: Creation complete after 0s [id=smart-lizard]","@module":"terraform.ui","@timestamp":"2021-05-25T13:32:41.826179-04:00","hook":{"resource":{"addr":"random_pet.animal","module":"","resource":"random_pet.animal","implied_provider":"random","resource_type":"random_pet","resource_name":"animal","resource_key":null},"action":"create","id_key":"id","id_value":"smart-lizard","elapsed_seconds":0},"type":"apply_complete"}
+{"@level":"info","@message":"Apply complete! Resources: 1 added, 0 changed, 0 destroyed.","@module":"terraform.ui","@timestamp":"2021-05-25T13:32:41.869168-04:00","changes":{"add":1,"change":0,"remove":0,"operation":"apply"},"type":"change_summary"}
+{"@level":"info","@message":"Outputs: 1","@module":"terraform.ui","@timestamp":"2021-05-25T13:32:41.869280-04:00","outputs":{"pets":{"sensitive":false,"type":"string","value":"smart-lizard"}},"type":"outputs"}
+```
+
+Each line consists of a JSON object with several keys common to all messages. These are:
+
+- `@level`: this is normally "info", but can be "error" or "warn" when showing diagnostics
+- `@message`: a human-readable summary of the contents of this message
+- `@module`: always "terraform.ui" when rendering UI output
+- `@timestamp`: an RFC3339 timestamp of when the message was output
+- `type`: defines which kind of message this is and determines how to interpret other keys which may be present
+
+Clients presenting the logs as a user interface should handle unexpected message types by presenting at least the `@message` field to the user.
+
+Messages will be emitted as events occur to trigger them. This means that messages related to several resources may be interleaved (if Terraform is running with concurrency above 1). The [`resource` object value](#resource-object) can be used to link multiple messages about a single resource.
+
+## Message Types
+
+The following message types are supported:
+
+### Generic Messages
+
+- `version`: information about the Terraform version and the version of the schema used for the following messages
+- `log`: unstructured human-readable log lines
+- `diagnostic`: diagnostic warning or error messages; [see the `terraform validate` docs for more details on the format](/terraform/cli/commands/validate#json)
+
+### Operation Results
+
+- `resource_drift`: describes a detected change to a single resource made outside of Terraform
+- `planned_change`: describes a planned change to a single resource
+- `change_summary`: summary of all planned or applied changes
+- `outputs`: list of all root module outputs
+
+### Resource Progress
+
+- `apply_start`, `apply_progress`, `apply_complete`, `apply_errored`: sequence of messages indicating progress of a single resource through apply
+- `provision_start`, `provision_progress`, `provision_complete`, `provision_errored`: sequence of messages indicating progress of a single provisioner step
+- `refresh_start`, `refresh_complete`: sequence of messages indicating progress of a single resource through refresh
+
+## Version Message
+
+A machine-readable UI command output will always begin with a `version` message. The following message-specific keys are defined:
+
+- `terraform`: the Terraform version which emitted this message
+- `ui`: the machine-readable UI schema version defining the meaning of the following messages
+
+### Example
+
+```json
+{
+  "@level": "info",
+  "@message": "Terraform 0.15.4",
+  "@module": "terraform.ui",
+  "@timestamp": "2021-05-25T13:32:41.275359-04:00",
+  "terraform": "0.15.4",
+  "type": "version",
+  "ui": "0.1.0"
+}
+```
+
+## Resource Drift
+
+If drift is detected during planning, Terraform will emit a `resource_drift` message for each resource which has changed outside of Terraform. This message has an embedded `change` object with the following keys:
+
+- `resource`: object describing the address of the resource to be changed; see [resource object](#resource-object) below for details
+- `action`: the action planned to be taken for the resource. Values: `update`, `delete`.
+
+This message does not include details about the exact changes which caused the change to be planned. That information is available in [the JSON plan output](/terraform/internals/json-format).
+
+### Example
+
+```json
+{
+  "@level": "info",
+  "@message": "random_pet.animal: Drift detected (update)",
+  "@module": "terraform.ui",
+  "@timestamp": "2021-05-25T13:32:41.705503-04:00",
+  "change": {
+    "resource": {
+      "addr": "random_pet.animal",
+      "module": "",
+      "resource": "random_pet.animal",
+      "implied_provider": "random",
+      "resource_type": "random_pet",
+      "resource_name": "animal",
+      "resource_key": null
+    },
+    "action": "update"
+  },
+  "type": "resource_drift"
+}
+```
+
+## Planned Change
+
+At the end of a plan or before an apply, Terraform will emit a `planned_change` message for each resource which has changes to apply. This message has an embedded `change` object with the following keys:
+
+- `resource`: object describing the address of the resource to be changed; see [resource object](#resource-object) below for details
+- `previous_resource`: object describing the previous address of the resource, if this change includes a configuration-driven move
+- `action`: the action planned to be taken for the resource. Values: `noop`, `create`, `read`, `update`, `replace`, `delete`, `move`.
+- `reason`: an optional reason for the change, only used when the action is `replace` or `delete`. Values:
+  - `tainted`: resource was marked as tainted
+  - `requested`: user requested that the resource be replaced, for example via the `-replace` plan flag
+  - `cannot_update`: changes to configuration force the resource to be deleted and created rather than updated
+  - `delete_because_no_resource_config`: no matching resource in configuration
+  - `delete_because_wrong_repetition`: resource instance key has no corresponding `count` or `for_each` in configuration
+  - `delete_because_count_index`: resource instance key is outside the range of the `count` argument
+  - `delete_because_each_key`: resource instance key is not included in the `for_each` argument
+  - `delete_because_no_module`: enclosing module instance is not in configuration
+
+This message does not include details about the exact changes which caused the change to be planned. That information is available in [the JSON plan output](/terraform/internals/json-format).
+
+### Example
+
+```json
+{
+  "@level": "info",
+  "@message": "random_pet.animal: Plan to create",
+  "@module": "terraform.ui",
+  "@timestamp": "2021-05-25T13:32:41.705503-04:00",
+  "change": {
+    "resource": {
+      "addr": "random_pet.animal",
+      "module": "",
+      "resource": "random_pet.animal",
+      "implied_provider": "random",
+      "resource_type": "random_pet",
+      "resource_name": "animal",
+      "resource_key": null
+    },
+    "action": "create"
+  },
+  "type": "planned_change"
+}
+```
+
+## Change Summary
+
+Terraform outputs a change summary when a plan or apply operation completes. Both message types include a `changes` object, which has the following keys:
+
+- `add`: count of resources to be created (including as part of replacement)
+- `change`: count of resources to be changed in-place
+- `remove`: count of resources to be destroyed (including as part of replacement)
+- `operation`: one of `plan`, `apply`, or `destroy`
+
+### Example
+
+```json
+{
+  "@level": "info",
+  "@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.",
+  "@module": "terraform.ui",
+  "@timestamp": "2021-05-25T13:32:41.869168-04:00",
+  "changes": {
+    "add": 1,
+    "change": 0,
+    "remove": 0,
+    "operation": "apply"
+  },
+  "type": "change_summary"
+}
+```
+
+## Outputs
+
+After a successful plan or apply, a message with type `outputs` contains the values of all root module output values. This message contains an `outputs` object, the keys of which are the output names. The outputs values are objects with the following keys:
+
+- `action`: for planned outputs, the action which will be taken for the output. Values: `noop`, `create`, `update`, `delete`
+- `value`: for applied outputs, the value of the output, encoded in JSON
+- `type`: for applied outputs, the detected HCL type of the output value
+- `sensitive`: boolean value, `true` if the output is sensitive and should be hidden from UI by default
+
+Note that `sensitive` outputs still include the `value` field, and integrating software should respect the sensitivity value as appropriate for the given use case.
+
+### Example
+
+```json
+{
+  "@level": "info",
+  "@message": "Outputs: 1",
+  "@module": "terraform.ui",
+  "@timestamp": "2021-05-25T13:32:41.869280-04:00",
+  "outputs": {
+    "pets": {
+      "sensitive": false,
+      "type": "string",
+      "value": "smart-lizard"
+    }
+  },
+  "type": "outputs"
+}
+```
+
+## Operation Messages
+
+Performing Terraform operations to a resource will often result in several messages being emitted. The message types include:
+
+- `apply_start`: when starting to apply changes for a resource
+- `apply_progress`: periodically, showing elapsed time output
+- `apply_complete`: on successful operation completion
+- `apply_errored`: when an error is encountered during the operation
+- `provision_start`: when starting a provisioner step
+- `provision_progress`: on provisioner output
+- `provision_complete`: on successful provisioning
+- `provision_errored`: when an error is enountered during provisioning
+- `refresh_start`: when reading a resource during refresh
+- `refresh_complete`: on successful refresh
+
+Each of these messages has a `hook` object, which has different fields for each type. All hooks have a [`resource` object](#resource-object) which identifies which resource is the subject of the operation.
+
+## Apply Start
+
+The `apply_start` message `hook` object has the following keys:
+
+- `resource`: a [`resource` object](#resource-object) identifying the resource
+- `action`: the action to be taken for the resource. Values: `noop`, `create`, `read`, `update`, `replace`, `delete`
+- `id_key` and `id_value`: a key/value pair used to identify this instance of the resource, omitted when unknown
+
+### Example
+
+```json
+{
+  "@level": "info",
+  "@message": "random_pet.animal: Creating...",
+  "@module": "terraform.ui",
+  "@timestamp": "2021-05-25T13:32:41.825308-04:00",
+  "hook": {
+    "resource": {
+      "addr": "random_pet.animal",
+      "module": "",
+      "resource": "random_pet.animal",
+      "implied_provider": "random",
+      "resource_type": "random_pet",
+      "resource_name": "animal",
+      "resource_key": null
+    },
+    "action": "create"
+  },
+  "type": "apply_start"
+}
+```
+
+## Apply Progress
+
+The `apply_progress` message `hook` object has the following keys:
+
+- `resource`: a [`resource` object](#resource-object) identifying the resource
+- `action`: the action being taken for the resource. Values: `noop`, `create`, `read`, `update`, `replace`, `delete`
+- `elapsed_seconds`: time elapsed since the apply operation started, expressed as an integer number of seconds
+
+### Example
+
+```json
+{
+  "@level": "info",
+  "@message": "null_resource.none[4]: Still creating... [30s elapsed]",
+  "@module": "terraform.ui",
+  "@timestamp": "2021-03-17T09:34:26.222465-04:00",
+  "hook": {
+    "resource": {
+      "addr": "null_resource.none[4]",
+      "module": "",
+      "resource": "null_resource.none[4]",
+      "implied_provider": "null",
+      "resource_type": "null_resource",
+      "resource_name": "none",
+      "resource_key": 4
+    },
+    "action": "create",
+    "elapsed_seconds": 30
+  },
+  "type": "apply_progress"
+}
+```
+
+## Apply Complete
+
+The `apply_complete` message `hook` object has the following keys:
+
+- `resource`: a [`resource` object](#resource-object) identifying the resource
+- `action`: the action taken for the resource. Values: `noop`, `create`, `read`, `update`, `replace`, `delete`
+- `id_key` and `id_value`: a key/value pair used to identify this instance of the resource, omitted when unknown
+- `elapsed_seconds`: time elapsed since the apply operation started, expressed as an integer number of seconds
+
+### Example
+
+```json
+{
+  "@level": "info",
+  "@message": "random_pet.animal: Creation complete after 0s [id=smart-lizard]",
+  "@module": "terraform.ui",
+  "@timestamp": "2021-05-25T13:32:41.826179-04:00",
+  "hook": {
+    "resource": {
+      "addr": "random_pet.animal",
+      "module": "",
+      "resource": "random_pet.animal",
+      "implied_provider": "random",
+      "resource_type": "random_pet",
+      "resource_name": "animal",
+      "resource_key": null
+    },
+    "action": "create",
+    "id_key": "id",
+    "id_value": "smart-lizard",
+    "elapsed_seconds": 0
+  },
+  "type": "apply_complete"
+}
+```
+
+## Apply Errored
+
+The `apply_complete` message `hook` object has the following keys:
+
+- `resource`: a [`resource` object](#resource-object) identifying the resource
+- `action`: the action taken for the resource. Values: `noop`, `create`, `read`, `update`, `replace`, `delete`
+- `elapsed_seconds`: time elapsed since the apply operation started, expressed as an integer number of seconds
+
+The exact detail of the error will be rendered as a separate `diagnostic` message.
+
+### Example
+
+```json
+{
+  "@level": "info",
+  "@message": "null_resource.none[0]: Creation errored after 10s",
+  "@module": "terraform.ui",
+  "@timestamp": "2021-03-26T16:38:54.013910-04:00",
+  "hook": {
+    "resource": {
+      "addr": "null_resource.none[0]",
+      "module": "",
+      "resource": "null_resource.none[0]",
+      "implied_provider": "null",
+      "resource_type": "null_resource",
+      "resource_name": "none",
+      "resource_key": 0
+    },
+    "action": "create",
+    "elapsed_seconds": 10
+  },
+  "type": "apply_errored"
+}
+```
+
+## Provision Start
+
+The `provision_start` message `hook` object has the following keys:
+
+- `resource`: a [`resource` object](#resource-object) identifying the resource
+- `provisioner`: the type of provisioner
+
+### Example
+
+```json
+{
+  "@level": "info",
+  "@message": "null_resource.none[0]: Provisioning with 'local-exec'...",
+  "@module": "terraform.ui",
+  "@timestamp": "2021-03-26T16:38:43.997431-04:00",
+  "hook": {
+    "resource": {
+      "addr": "null_resource.none[0]",
+      "module": "",
+      "resource": "null_resource.none[0]",
+      "implied_provider": "null",
+      "resource_type": "null_resource",
+      "resource_name": "none",
+      "resource_key": 0
+    },
+    "provisioner": "local-exec"
+  },
+  "type": "provision_start"
+}
+```
+
+## Provision Progress
+
+The `provision_progress` message `hook` object has the following keys:
+
+- `resource`: a [`resource` object](#resource-object) identifying the resource
+- `provisioner`: the type of provisioner
+- `output`: the output log from the provisioner
+
+One `provision_progress` message is output for each log line received from the provisioner.
+
+### Example
+
+```json
+{
+  "@level": "info",
+  "@message": "null_resource.none[0]: (local-exec): Executing: [\"/bin/sh\" \"-c\" \"sleep 10 && exit 1\"]",
+  "@module": "terraform.ui",
+  "@timestamp": "2021-03-26T16:38:43.997869-04:00",
+  "hook": {
+    "resource": {
+      "addr": "null_resource.none[0]",
+      "module": "",
+      "resource": "null_resource.none[0]",
+      "implied_provider": "null",
+      "resource_type": "null_resource",
+      "resource_name": "none",
+      "resource_key": 0
+    },
+    "provisioner": "local-exec",
+    "output": "Executing: [\"/bin/sh\" \"-c\" \"sleep 10 && exit 1\"]"
+  },
+  "type": "provision_progress"
+}
+```
+
+## Provision Complete
+
+The `provision_complete` message `hook` object has the following keys:
+
+- `resource`: a [`resource` object](#resource-object) identifying the resource
+- `provisioner`: the type of provisioner
+
+### Example
+
+```json
+{
+  "@level": "info",
+  "@message": "null_resource.none[0]: (local-exec) Provisioning complete",
+  "@module": "terraform.ui",
+  "@timestamp": "2021-03-17T09:34:06.239043-04:00",
+  "hook": {
+    "resource": {
+      "addr": "null_resource.none[0]",
+      "module": "",
+      "resource": "null_resource.none[0]",
+      "implied_provider": "null",
+      "resource_type": "null_resource",
+      "resource_name": "none",
+      "resource_key": 0
+    },
+    "provisioner": "local-exec"
+  },
+  "type": "provision_complete"
+}
+```
+
+## Provision Errored
+
+The `provision_errored` message `hook` object has the following keys:
+
+- `resource`: a [`resource` object](#resource-object) identifying the resource
+- `provisioner`: the type of provisioner
+
+### Example
+
+```json
+{
+  "@level": "info",
+  "@message": "null_resource.none[0]: (local-exec) Provisioning errored",
+  "@module": "terraform.ui",
+  "@timestamp": "2021-03-26T16:38:54.013572-04:00",
+  "hook": {
+    "resource": {
+      "addr": "null_resource.none[0]",
+      "module": "",
+      "resource": "null_resource.none[0]",
+      "implied_provider": "null",
+      "resource_type": "null_resource",
+      "resource_name": "none",
+      "resource_key": 0
+    },
+    "provisioner": "local-exec"
+  },
+  "type": "provision_errored"
+}
+```
+
+## Refresh Start
+
+The `refresh_start` message `hook` object has the following keys:
+
+- `resource`: a [`resource` object](#resource-object) identifying the resource
+- `id_key` and `id_value`: a key/value pair used to identify this instance of the resource
+
+### Example
+
+```json
+{
+  "@level": "info",
+  "@message": "null_resource.none[0]: Refreshing state... [id=1971614370559474622]",
+  "@module": "terraform.ui",
+  "@timestamp": "2021-03-26T14:18:06.508915-04:00",
+  "hook": {
+    "resource": {
+      "addr": "null_resource.none[0]",
+      "module": "",
+      "resource": "null_resource.none[0]",
+      "implied_provider": "null",
+      "resource_type": "null_resource",
+      "resource_name": "none",
+      "resource_key": 0
+    },
+    "id_key": "id",
+    "id_value": "1971614370559474622"
+  },
+  "type": "refresh_start"
+}
+```
+
+## Refresh Complete
+
+The `refresh_complete` message `hook` object has the following keys:
+
+- `resource`: a [`resource` object](#resource-object) identifying the resource
+- `id_key` and `id_value`: a key/value pair used to identify this instance of the resource
+
+### Example
+
+```json
+{
+  "@level": "info",
+  "@message": "null_resource.none[0]: Refresh complete [id=1971614370559474622]",
+  "@module": "terraform.ui",
+  "@timestamp": "2021-03-26T14:18:06.509371-04:00",
+  "hook": {
+    "resource": {
+      "addr": "null_resource.none[0]",
+      "module": "",
+      "resource": "null_resource.none[0]",
+      "implied_provider": "null",
+      "resource_type": "null_resource",
+      "resource_name": "none",
+      "resource_key": 0
+    },
+    "id_key": "id",
+    "id_value": "1971614370559474622"
+  },
+  "type": "refresh_complete"
+}
+```
+
+## Resource Object
+
+The `resource` object is a decomposed structure representing a resource address in configuration, which is used to identify which resource a given message is associated with. The object has the following keys:
+
+- `addr`: the full unique address of the resource as a string
+- `module`: the address of the module containing the resource, in the form `module.foo.module.bar`, or an empty string for a root module resource
+- `resource`: the module-relative address, which is identical to `addr` for root module resources
+- `resource_type`: the type of resource being addressed
+- `resource_name`: the name label for the resource
+- `resource_key`: the address key (`count` or `for_each` value), or `null` if the neither are used
+- `implied_provider`: the provider type implied by the resource type; this may not reflect the resource's provider if provider aliases are used
+
+### Example
+
+```json
+{
+  "addr": "module.pets.random_pet.pet[\"friend\"]",
+  "module": "module.pets",
+  "resource": "random_pet.pet[\"friend\"]",
+  "implied_provider": "random",
+  "resource_type": "random_pet",
+  "resource_name": "pet",
+  "resource_key": "friend"
+}
+```
diff --git a/v1.5.7/website/docs/internals/module-registry-protocol.mdx b/v1.5.7/website/docs/internals/module-registry-protocol.mdx
new file mode 100644
index 0000000..8edd97b
--- /dev/null
+++ b/v1.5.7/website/docs/internals/module-registry-protocol.mdx
@@ -0,0 +1,218 @@
+---
+page_title: Module Registry Protocol
+description: |-
+  The module registry protocol is implemented by a host intending to be the
+  host of one or more Terraform modules, specifying which modules are available
+  and where to find their distribution packages.
+---
+
+# Module Registry Protocol
+
+-> Third-party module registries are supported only in Terraform CLI 0.11 and later. Prior versions do not support this protocol.
+
+The module registry protocol is what Terraform CLI uses to discover metadata
+about modules available for installation and to locate the distribution
+package for a selected module.
+
+The primary implementation of this protocol is the public
+[Terraform Registry](https://registry.terraform.io/) at `registry.terraform.io`.
+By writing and deploying your own implementation of this protocol, you can
+create a separate registry to distribute your own modules, as an alternative to
+publishing them on the public Terraform Registry.
+
+The public Terraform Registry implements a superset of the API described on
+this page, in order to capture additional information used in the registry UI.
+For information on those extensions, see
+[Terraform Registry HTTP API](/terraform/registry/api-docs). Third-party registry
+implementations may choose to implement those extensions if desired, but
+Terraform CLI itself does not use them.
+
+## Module Addresses
+
+Each Terraform module has an associated address. A module address has the
+syntax `hostname/namespace/name/system`, where:
+
+- `hostname` is the hostname of the module registry that serves this module.
+- `namespace` is the name of a namespace, unique on a particular hostname, that
+  can contain one or more modules that are somehow related. On the public
+  Terraform Registry the "namespace" represents the organization that is
+  packaging and distributing the module.
+- `name` is the module name, which generally names the abstraction that the
+  module is intending to create.
+- `system` is the name of a remote system that the module is primarily written
+  to target. For multi-cloud abstractions, there can be multiple modules with
+  addresses that differ only in "system" to reflect provider-specific
+  implementations of the abstraction, like
+  `registry.terraform.io/hashicorp/consul/aws` vs.
+  `registry.terraform.io/hashicorp/consul/azurerm`. The system name commonly
+  matches the type portion of the address of an official provider, like `aws`
+  or `azurerm` in the above examples, but that is not required and so you can
+  use whichever system keywords make sense for the organization of your
+  particular registry.
+
+The `hostname/` portion of a module address (including its slash delimiter)
+is optional, and if omitted defaults to `registry.terraform.io/`.
+
+For example:
+
+- `hashicorp/consul/aws` is a shorthand for
+  `registry.terraform.io/hashicorp/consul/aws`, which is a module on the
+  public registry for deploying Consul clusters in Amazon Web Services.
+- `example.com/awesomecorp/consul/happycloud` is a hypothetical module published
+  on a third-party registry.
+
+If you intend to share a module you've developed for use by all Terraform
+users, please consider publishing it into the public
+[Terraform Registry](https://registry.terraform.io/) to make your module more
+discoverable. You only need to implement this module registry protocol if you
+wish to publish modules whose addresses include a different hostname that is
+under your control.
+
+## Module Versions
+
+Each distinct module address has associated with it a set of versions, each
+of which has an associated version number. Terraform assumes version numbers
+follow the [Semantic Versioning 2.0](https://semver.org/) conventions, with
+the user-facing behavior of the module serving as the "public API".
+
+Each `module` block may select a distinct version of a module, even if multiple
+blocks have the same source address.
+
+## Service Discovery
+
+The module registry protocol begins with Terraform CLI using
+[Terraform's remote service discovery protocol](/terraform/internals/remote-service-discovery),
+with the hostname in the module address acting as the "User-facing Hostname".
+
+The service identifier for the module registry protocol is `modules.v1`.
+Its associated string value is the base URL for the relative URLs defined in
+the sections that follow.
+
+For example, the service discovery document for a host that _only_ implements
+the module registry protocol might contain the following:
+
+```json
+{
+  "modules.v1": "/terraform/modules/v1/"
+}
+```
+
+If the given URL is a relative URL then Terraform will interpret it as relative
+to the discovery document itself. The specific module registry protocol
+endpoints are defined as URLs relative to the given base URL, and so the
+specified base URL should generally end with a slash to ensure that those
+relative paths will be resolved as expected.
+
+The following sections describe the various operations that a module
+registry must implement to be compatible with Terraform CLI's module
+installer. The indicated URLs are all relative to the URL resulting from
+service discovery, as described above. We use the current URLs on
+Terraform Registry as working examples, assuming that the caller already
+performed service discovery on `registry.terraform.io` to learn the base URL.
+
+The URLs are shown with the convention that a path portion with a colon `:`
+prefix is a placeholder for a dynamically-selected value, while all other
+path portions are literal. For example, in `:namespace/:type/versions`,
+the first two path portions are placeholders while the third is literally
+the string "versions".
+
+## List Available Versions for a Specific Module
+
+This is the primary endpoint for resolving module sources, returning the
+available versions for a given fully-qualified module.
+
+| Method | Path                                | Produces           |
+| ------ | ----------------------------------- | ------------------ |
+| `GET`  | `:namespace/:name/:system/versions` | `application/json` |
+
+### Parameters
+
+- `namespace` `(string: <required>)` - The user or organization the module is
+  owned by. This is required and is specified as part of the URL path.
+
+- `name` `(string: <required>)` - The name of the module.
+  This is required and is specified as part of the URL path.
+
+- `system` `(string: <required>)` - The name of the target system.
+  This is required and is specified as part of the URL path.
+
+### Sample Request
+
+```text
+$ curl 'https://registry.terraform.io/v1/modules/hashicorp/consul/aws/versions'
+```
+
+### Sample Response
+
+The `modules` array in the response always includes the requested module as the
+first element.
+
+Terraform does not use the other elements of this list. However, third-party implementations should always use a single-element list for forward compatiblity.
+
+Each returned module has an array of available versions, which Terraform
+matches against any version constraints given in configuration.
+
+```json
+{
+   "modules": [
+      {
+         "versions": [
+            {"version": "1.0.0"},
+            {"version": "1.1.0"},
+            {"version": "2.0.0"}
+         ]
+      }
+   ]
+}
+```
+
+Return `404 Not Found` to indicate that no module is available with the
+requested namespace, name, and target system.
+
+## Download Source Code for a Specific Module Version
+
+This endpoint downloads the specified version of a module for a single target system.
+
+| Method | Path                                         | Produces           |
+| ------ | -------------------------------------------- | ------------------ |
+| `GET`  | `:namespace/:name/:system/:version/download` | `application/json` |
+
+### Parameters
+
+- `namespace` `(string: <required>)` - The user the module is owned by.
+  This is required and is specified as part of the URL path.
+
+- `name` `(string: <required>)` - The name of the module.
+  This is required and is specified as part of the URL path.
+
+- `system` `(string: <required>)` - The name of the target system.
+  This is required and is specified as part of the URL path.
+
+- `version` `(string: <required>)` - The version of the module.
+  This is required and is specified as part of the URL path.
+
+### Sample Request
+
+```text
+$ curl -i 'https://registry.terraform.io/v1/modules/hashicorp/consul/aws/0.0.1/download'
+```
+
+### Sample Response
+
+```text
+HTTP/1.1 204 No Content
+Content-Length: 0
+X-Terraform-Get: https://api.github.com/repos/hashicorp/terraform-aws-consul/tarball/v0.0.1//*?archive=tar.gz
+```
+
+A successful response has no body, and includes the location from which the
+module version's source can be downloaded in the `X-Terraform-Get` header.
+The value of this header accepts the same values as the `source` argument
+in a `module` block in Terraform configuration, as described in
+[Module Sources](/terraform/language/modules/sources),
+except that it may not recursively refer to another module registry address.
+
+The value of `X-Terraform-Get` may instead be a relative URL, indicated by
+beginning with `/`, `./` or `../`, in which case it is resolved relative to
+the full URL of the download endpoint to produce
+[an HTTP URL module source](/terraform/language/modules/sources#http-urls).
diff --git a/v1.5.7/website/docs/internals/provider-meta.mdx b/v1.5.7/website/docs/internals/provider-meta.mdx
new file mode 100644
index 0000000..0e25a8f
--- /dev/null
+++ b/v1.5.7/website/docs/internals/provider-meta.mdx
@@ -0,0 +1,81 @@
+---
+page_title: Provider Metadata
+description: >-
+  For advanced use cases, modules can provide some pre-defined metadata for
+  providers.
+---
+
+# Provider Metadata
+
+In some situations it's beneficial for a provider to offer an interface
+through which modules can pass it information unrelated to the resources
+in the module, but scoped on a per-module basis.
+
+Provider Metadata allows a provider to declare metadata fields it expects,
+which individual modules can then populate independently of any provider
+configuration. While provider configurations are often shared between modules,
+provider metadata is always module-specific.
+
+Provider Metadata is intended primarily for the situation where an official
+module is developed by the same vendor that produced the provider it is
+intended to work with, to allow the vendor to indirectly obtain usage
+statistics for each module via the provider. For that reason, this
+documentation is presented from the perspective of the provider developer
+rather than the module developer.
+
+~> **Advanced Topic!** This page covers technical details
+of Terraform. You don't need to understand these details to
+effectively use Terraform. The details are documented here for
+module authors and provider developers working on advanced
+functionality.
+
+~> **Experimental Feature!** This functionality is still considered
+experimental, and anyone taking advantage of it should [coordinate
+with the Terraform team](https://github.com/hashicorp/terraform/issues/new)
+to help the team understand how the feature is being used and to make
+sure their use case is taken into account as the feature develops.
+
+## Defining the Schema
+
+Before a provider can receive information from a module, the provider
+must strictly define the data it can accept. You can do this by setting
+the `ProviderMeta` property on your `schema.Provider` struct. Its value
+functions similarly to the provider config: a map of strings to the
+`schema.Schema` describing the values those strings accept.
+
+## Using the Data
+
+When Terraform calls your provider, you can use the `schema.ResourceData`
+that your `Create`, `Read`, and `Update` functions already use to get
+access to the provider metadata being passed. First define a struct
+that matches your schema, then call the `GetProviderSchema` method on
+your `schema.ResourceData`, passing a pointer to a variable of that type.
+The variable will be populated with the provider metadata, and will return
+an error if there was an issue with parsing the data into the struct.
+
+## Specifying Data in Modules
+
+To include data in your modules, create a `provider_meta` nested block under
+your module's `terraform` block, with the name of the provider it's trying
+to pass information to:
+
+```hcl
+terraform {
+  provider_meta "my-provider" {
+    hello = "world"
+  }
+}
+```
+
+The `provider_meta` block must match the schema the provider has defined.
+
+## Versioning Your Modules
+
+Any module taking advantage of this functionality must make sure that the
+provider metadata supplied matches the schema defined in the provider, and
+that the version of Terraform that is being run has support for the provider
+metadata functionality. It's therefore recommended that any module taking
+advantage of this functionality should specify a minimum Terraform version of
+0.13.0 or higher, and a minimum version of each of the providers it specifies
+metadata as the first version the schema being used was supported by the
+provider.
diff --git a/v1.5.7/website/docs/internals/provider-network-mirror-protocol.mdx b/v1.5.7/website/docs/internals/provider-network-mirror-protocol.mdx
new file mode 100644
index 0000000..89ea265
--- /dev/null
+++ b/v1.5.7/website/docs/internals/provider-network-mirror-protocol.mdx
@@ -0,0 +1,273 @@
+---
+page_title: Provider Network Mirror Protocol
+description: |-
+  The provider network mirror protocol is implemented by a server intending
+  to provide a mirror or read-through caching proxy for Terraform providers,
+  as an alternative distribution source from the provider's origin provider
+  registry.
+---
+
+# Provider Network Mirror Protocol
+
+-> Provider network mirrors are supported only in Terraform CLI v0.13.2 and later. Prior versions do not support this protocol.
+
+The provider network mirror protocol is an optional protocol which you can
+implement to provide an alternative installation source for Terraform providers,
+regardless of their origin registries.
+
+Terraform uses network mirrors only if you activate them explicitly in
+[the CLI configuration's `provider_installation` block](/terraform/cli/config/config-file#provider-installation).
+When enabled, a network mirror can serve providers belonging to any registry
+hostname, which can allow an organization to serve all of the Terraform
+providers they intend to use from an internal server, rather than from each
+provider's origin registry.
+
+This is _not_ the protocol that should be implemented by a host intending to
+serve as an origin registry for Terraform Providers. To provide an origin
+registry (whose hostname would then be included in the source addresses of the
+providers it hosts), implement
+[the provider registry protocol](/terraform/internals/provider-registry-protocol)
+instead.
+
+## Provider Addresses
+
+Each Terraform provider has an associated address which uniquely identifies it
+within Terraform. A provider address has the syntax `hostname/namespace/type`,
+which is described in more detail in
+[the Provider Requirements documentation](/terraform/language/providers/requirements).
+
+By default, the `hostname` portion of a provider address serves both as part
+of its unique identifier _and_ as the location of the registry to retrieve it
+from. However, when you configure Terraform to install providers from a network
+mirror, the `hostname` serves _only_ as an identifier and no longer as
+an installation source. A provider mirror can therefore serve providers
+belonging to a variety of different provider registry hostnames, including
+providers from the public Terraform Registry at `registry.terraform.io`, from a
+single server.
+
+In the relative URL patterns later in this document, the placeholder `:hostname`
+refers to the hostname from the address of the provider being requested, not
+the hostname where the provider network mirror is deployed.
+
+## Protocol Base URL
+
+Most Terraform-native services use
+[the remote service discovery protocol](/terraform/internals/remote-service-discovery) so
+that the physical location of the endpoints can potentially be separated from
+the hostname used in identifiers. The Provider Network Mirror protocol does
+_not_ use the service discovery indirection, because a network mirror location
+is only a physical location and is never used as part of the identifier of a
+dependency in a Terraform configuration.
+
+Instead, the provider installation section of the CLI configuration accepts
+a base URL directly. The given URL must use the scheme `https:`, and should
+end with a trailing slash so that the relative URLs of the individual operation
+endpoints will be resolved beneath it.
+
+```hcl
+provider_installation {
+  network_mirror {
+    url = "https://terraform.example.com/providers/"
+  }
+}
+```
+
+Terraform uses the base URL only as a stem to resolve the operation endpoint
+URLs against, and so it will never access the base URL directly. You can
+therefore, if desired, publish human-readable usage documentation for your
+network mirror at that URL.
+
+The following sections describe the various operations that a provider
+network mirror server must implement to be compatible with Terraform CLI's
+provider installer. The indicated URLs are all relative to the given base URL,
+as described above.
+
+The URLs are shown with the convention that a path portion with a colon `:`
+prefix is a placeholder for a dynamically-selected value, while all other
+path portions are literal. For example, in `:hostname/:namespace/:type/index.json`,
+the first three path portions are placeholders while the third is literally
+the string "index.json".
+
+The example requests in the following sections will assume the example mirror
+base URL from the above CLI configuration example.
+
+### Authentication
+
+If the CLI configuration includes
+[credentials](/terraform/cli/config/config-file#credentials) for the hostname
+given in the network mirror base URL, Terraform will include those credentials
+in its requests for operations described below.
+
+If the given URL uses a non-standard port number (other than 443) then the
+credentials must be associated with a hostname that includes the port number,
+such as `terraform.example.com:8443`.
+
+Terraform does _not_ send credentials when retrieving the archives whose
+URLs are given in the "List Available Installation Packages" response below.
+If a particular mirror considers the distribution packages themselves to be
+sensitive then it must use cryptographically-secure, user-specific, and
+time-limited URLs in the metadata response. Strategies for doing so are out
+of scope of this protocol documentation.
+
+## List Available Versions
+
+This operation determines which versions are currently available for a
+particular provider.
+
+| Method | Path                                    | Produces           |
+| ------ | --------------------------------------- | ------------------ |
+| `GET`  | `:hostname/:namespace/:type/index.json` | `application/json` |
+
+### Parameters
+
+* `hostname` (required): the hostname portion of the address of the requested
+  provider.
+* `namespace` (required): the namespace portion of the address of the requested
+  provider.
+* `type` (required): the type portion of the address of the requested provider.
+
+### Sample Request
+
+```
+curl 'https://terraform.example.com/providers/registry.terraform.io/hashicorp/random/index.json'
+```
+
+### Sample Response
+
+```json
+{
+  "versions": {
+    "2.0.0": {},
+    "2.0.1": {}
+  }
+}
+```
+
+### Response Properties
+
+A successful result is a JSON object containing a single property `versions`,
+which must be a JSON object.
+
+Each of the property names of the `versions` object represents an available
+version number. The property values must be objects, but no properties are defined for those objects. We recommend leaving those objects empty for forward compatibility.
+
+Return `404 Not Found` to signal that the mirror does not have a provider
+with the given address.
+
+## List Available Installation Packages
+
+This operation returns download URLs and associated metadata for the
+distribution packages for a particular version of a provider.
+
+Each distribution package is associated with a particular operating system
+and architecture. A network mirror may host only a subset of the available
+packages for a provider version, if the users of the mirror are known to all
+use only a subset of the target platforms that Terraform supports.
+
+Terraform CLI uses this operation after it has selected the newest available
+version matching the configured version constraints, in order to find a zip
+archive containing the plugin itself.
+
+| Method | Path                                       | Produces           |
+| ------ | ------------------------------------------ | ------------------ |
+| `GET`  | `:hostname/:namespace/:type/:version.json` | `application/json` |
+
+### Parameters
+
+* `hostname` (required): the hostname portion of the address of the requested
+  provider.
+* `namespace` (required): the namespace portion of the address of the requested
+  provider.
+* `type` (required): the type portion of the address of the requested provider.
+* `version` (required): the version selected to download. This will exactly
+  match one of the version strings returned from a previous call to
+  [List Available Versions](#list-available-versions).
+
+### Sample Request
+
+```
+curl 'https://terraform.example.com/providers/registry.terraform.io/hashicorp/random/2.0.0.json'
+```
+
+### Sample Response
+
+```json
+{
+  "archives": {
+    "darwin_amd64": {
+      "url": "terraform-provider-random_2.0.0_darwin_amd64.zip",
+      "hashes": [
+        "h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs="
+      ]
+    },
+    "linux_amd64": {
+      "url": "terraform-provider-random_2.0.0_linux_amd64.zip",
+      "hashes": [
+        "h1:lCJCxf/LIowc2IGS9TPjWDyXY4nOmdGdfcwwDQCOURQ="
+      ]
+    }
+  }
+}
+```
+
+### Response Properties
+
+A successful result is a JSON object with a property called `archives`, which
+must be a JSON object.
+
+Each of the property names of the `archives` object is a target platform
+identifier, which consists of an operating system and architecture concatenated
+with an underscore (`_`).
+
+Each property value in the `archives` object is itself a nested object with
+the following properties:
+
+* `url` (required): a string specifying the URL from which Terraform should
+  download the `.zip` archive containing the requested provider plugin version.
+
+  Terraform resolves the URL relative to the URL from which the current
+  JSON document was returned, so the examples above containing only a
+  filename would cause Terraform to construct a URL like:
+
+  ```
+  https://terraform.example.com/providers/registry.terraform.io/hashicorp/random/terraform-provider-random_2.0.0_darwin_amd64.zip
+  ```
+
+* `hashes` (optional): a JSON array of strings containing one or more hash
+  values for the indicated archive. These hashes use Terraform's provider
+  package hashing algorithm. At present, the easiest way to populate these
+  is to construct a mirror's JSON indices using the `terraform providers mirror`
+  command, as described in a later section, which will include the calculated
+  hashes of each provider.
+
+  If the response includes at least one hash, Terraform will select the hash
+  whose algorithm it considers to be strongest and verify that the downloaded
+  package matches that hash. If the response does not include a `hashes`
+  property then Terraform will install the indicated archive with no
+  verification.
+
+Terraform CLI will only attempt to download versions that it has previously
+seen in response to [List Available Versions](#list-available-versions).
+
+## Provider Mirror as a Static Website
+
+The provider mirror protocol is designed so that it can potentially be implemented
+by placing files on typical static website hosting services. When using this
+strategy, implement the JSON index responses described above as `.json` files
+in the appropriate nested subdirectories, and ensure that your system is
+configured to serve `.json` files with the `application/json` media type.
+
+As a convenience, Terraform CLI includes
+[the `terraform providers mirror` subcommand](/terraform/cli/commands/providers/mirror),
+which will analyze the current configuration for the providers it requires,
+download the packages for those providers from their origin registries, and
+place them into a local directory suitable for use as a mirror.
+
+The `terraform providers mirror` subcommand also generates `index.json` and
+version-specific `.json` files that can, when placed in a static website hosting
+system, produce responses compatible with the provider mirror protocol.
+
+If you wish to create a mirror with providers for a number of different
+Terraform configurations, run `terraform providers mirror` in each configuration
+in turn while providing the same output directory each time. Terraform will
+then merge together all of the requirements into a single set of JSON indices.
diff --git a/v1.5.7/website/docs/internals/provider-registry-protocol.mdx b/v1.5.7/website/docs/internals/provider-registry-protocol.mdx
new file mode 100644
index 0000000..e344d88
--- /dev/null
+++ b/v1.5.7/website/docs/internals/provider-registry-protocol.mdx
@@ -0,0 +1,344 @@
+---
+page_title: Provider Registry Protocol
+description: |-
+  The provider registry protocol is implemented by a host intending to be the
+  origin host for one or more Terraform providers, specifying which providers
+  are available and where to find their distribution packages.
+---
+
+# Provider Registry Protocol
+
+-> Third-party provider registries are supported only in Terraform CLI 0.13 and later. Prior versions do not support this protocol.
+
+The provider registry protocol is what Terraform CLI uses to discover metadata
+about providers available for installation and to locate the distribution
+packages for a selected provider.
+
+The primary implementation of this protocol is the public
+[Terraform Registry](https://registry.terraform.io/) at `registry.terraform.io`.
+By writing and deploying your own implementation of this protocol, you can
+create a separate _origin registry_ to distribute your own providers, as an
+alternative to publishing them on the public Terraform Registry.
+
+This page describes the provider _registry_ protocol, which is the protocol
+for finding providers available for installation. It _doesn't_ describe the
+API that provider plugins themselves implement to serve requests from Terraform
+CLI at runtime. For more information on the provider API, see the Terraform
+SDK documentation.
+
+The public Terraform Registry implements a superset of the API described on
+this page, in order to capture additional information used in the registry UI.
+Third-party implementations should not include those extensions because they
+may change in future without notice.
+
+## Provider Addresses
+
+Each Terraform provider has an associated address which uniquely identifies it
+within Terraform. A provider address has the syntax `hostname/namespace/type`,
+where:
+
+* `hostname` is the registry host that the provider is considered to have
+  originated from, and the default location Terraform will consult for
+  information about the provider
+  [unless overridden in the CLI configuration](/terraform/cli/config/config-file#provider-installation).
+* `namespace` is the name of a namespace, unique on a particular hostname, that
+  can contain one or more providers that are somehow related. On the public
+  Terraform Registry the "namespace" represents the organization that is
+  packaging and distributing the provider.
+* `type` is the provider type, like "azurerm", "aws", "google", "dns", etc.
+  A provider type is unique within a particular hostname and namespace.
+
+The `hostname/` portion of a provider address (including its slash delimiter)
+is optional, and if omitted defaults to `registry.terraform.io/`.
+
+For example:
+
+* `hashicorp/aws` is a shorthand for `registry.terraform.io/hashicorp/aws`,
+  which is the official AWS provider published by HashiCorp.
+* `example/foo` is a shorthand for `registry.terraform.io/example/foo`, which
+  is a hypothetical third-party provider published on the public
+  Terraform Registry.
+* `example.com/bar/baz` is a hypothetical third-party provider published at a
+  third-party provider registry on `example.com`.
+
+If you intend only to share a provider you've developed for use by all
+Terraform users, please consider publishing it into the public
+[Terraform Registry](https://registry.terraform.io/), which will make your
+provider discoverable. You only need to implement this provider registry
+protocol if you wish to publish providers whose addresses include a different
+hostname that is under your control.
+
+Terraform uses the full address (after normalization to always include a
+hostname) as its global identifier for providers internally, and so it's
+important to note that re-uploading the `hashicorp/azurerm` provider into
+another namespace or publishing it on a different hostname will cause Terraform
+to see it as an entirely separate provider that will _not_ be usable by modules
+that declare a dependency on `hashicorp/azurerm`. If your goal is to create
+an alternative local distribution source for an existing provider -- that is,
+a _mirror_ of the provider -- refer to
+[the provider installation method configuration](/terraform/cli/config/config-file#provider-installation)
+instead.
+
+## Provider Versions
+
+Each distinct provider address has associated with it a set of versions, each
+of which has an associated version number. Terraform assumes version numbers
+follow the [Semantic Versioning 2.0](https://semver.org/) conventions, with
+the schema and behavior of the provider as documented from the perspective of
+an end-user of Terraform serving as the "public API".
+
+All available versions for a particular provider address are considered to be
+the same provider by Terraform. Each Terraform configuration selects only one
+version of each provider for use in the entire configuration, so the version
+constraints across all modules are considered together for the purposes of
+version selection.
+
+## Service Discovery
+
+The providers protocol begins with Terraform CLI using
+[Terraform's remote service discovery protocol](/terraform/internals/remote-service-discovery),
+with the hostname in the provider address acting as the "User-facing Hostname".
+
+The service identifier for the provider registry protocol is `providers.v1`.
+Its associated string value is the base URL for the relative URLs defined in
+the sections that follow.
+
+For example, the service discovery document for a host that _only_ implements
+the provider registry protocol might contain the following:
+
+```json
+{
+  "providers.v1": "/terraform/providers/v1/"
+}
+```
+
+If the given URL is a relative URL then Terraform will interpret it as relative
+to the discovery document itself. The specific provider registry protocol
+endpoints are defined as URLs relative to the given base URL, and so the
+specified base URL should generally end with a slash to ensure that those
+relative paths will be resolved as expected.
+
+The following sections describe the various operations that a provider
+registry must implement to be compatible with Terraform CLI's provider
+installer. The indicated URLs are all relative to the URL resulting from
+service discovery, as described above. We use the current URLs on
+Terraform Registry as working examples, assuming that the caller already
+performed service discovery on `registry.terraform.io` to learn the base URL.
+
+The URLs are shown with the convention that a path portion with a colon `:`
+prefix is a placeholder for a dynamically-selected value, while all other
+path portions are literal. For example, in `:namespace/:type/versions`,
+the first two path portions are placeholders while the third is literally
+the string "versions".
+
+## List Available Versions
+
+This operation determines which versions are currently available for a
+particular provider.
+
+| Method | Path                        | Produces           |
+| ------ | --------------------------- | ------------------ |
+| `GET`  | `:namespace/:type/versions` | `application/json` |
+
+### Parameters
+
+* `namespace` (required): the namespace portion of the address of the requested
+  provider.
+* `type` (required): the type portion of the address of the requested provider.
+
+### Sample Request
+
+```
+curl 'https://registry.terraform.io/v1/providers/hashicorp/random/versions'
+```
+
+### Sample Response
+
+```json
+{
+  "versions": [
+    {
+      "version": "2.0.0",
+      "protocols": ["4.0", "5.1"],
+      "platforms": [
+        {"os": "darwin", "arch": "amd64"},
+        {"os": "linux", "arch": "amd64"},
+        {"os": "linux", "arch": "arm"},
+        {"os": "windows", "arch": "amd64"}
+      ]
+    },
+    {
+      "version": "2.0.1",
+      "protocols": ["5.2"],
+      "platforms": [
+        {"os": "darwin", "arch": "amd64"},
+        {"os": "linux", "arch": "amd64"},
+        {"os": "linux", "arch": "arm"},
+        {"os": "windows", "arch": "amd64"}
+      ]
+    }
+  ]
+}
+```
+
+### Response Properties
+
+A successful result is a JSON object containing a single property `versions`.
+`versions` is an array of objects that each describe one available version,
+with the following properties:
+
+* `version` (required): the version number this object is describing, using
+  the semantic versioning string notation. `version` must be unique across
+  all objects in the response.
+* `protocols` (recommended): an array of Terraform provider API versions that
+  this version supports, each given in `MAJOR.MINOR` format where each major
+  version appears only once and the given minor version is the highest minor
+  version supported. For example, `5.1` means that the provider supports both
+  protocol `5.0` and protocol `5.1`.
+
+  Terraform uses this information, when available, to provide hints to users
+  about upgrading or downgrading their version of a particular provider to
+  work with their current version of Terraform, if their currently-selected
+  versions are not compatible.
+
+  Which API versions are supported is, for most providers, decided by which
+  version of the Terraform SDK they are built against. Consult the Terraform
+  SDK documentation for more information.
+
+  Only Terraform 0.13 and later support third-party provider registries and
+  that Terraform version requires API version `5.0` or later, so in practice
+  it isn't useful to list major versions 4 or earlier in a third-party
+  provider registry.
+* `platforms` (recommended): an array of objects describing platforms that have
+  packages available for this version.
+
+  Terraform may use this information, when available, to provide hints to
+  users about upgrading or downgrading their version of a particular provider
+  for compatibility with their current platform.
+
+  The `platforms` objects have properties `os` and `arch`, whose values match
+  the properties of the same name in the response to
+  [Find a Provider Package](#find-a-provider-package).
+
+Return `404 Not Found` to signal that the registry does not have a provider
+with the given namespace and type.
+
+## Find a Provider Package
+
+This operation returns the download URL of and associated metadata about the
+distribution package for a particular version of a provider for a particular
+operating system and architecture.
+
+Terraform CLI uses this operation after it has selected the newest available
+version matching the configured version constraints, in order to find the zip
+archive containing the plugin itself.
+
+| Method | Path                                           | Produces           |
+| ------ | ---------------------------------------------- | ------------------ |
+| `GET`  | `:namespace/:type/:version/download/:os/:arch` | `application/json` |
+
+### Parameters
+
+* `namespace` (required): the namespace portion of the address of the requested
+  provider.
+* `type` (required): the type portion of the address of the requested provider.
+* `version` (required): the version selected to download. This will exactly
+  match one of the version strings returned from a previous call to
+  [List Available Versions](#list-available-versions).
+* `os` (required): a keyword identifying the operating system that the returned
+  package should be compatible with, like "linux" or "darwin".
+* `arch` (required): a keyword identifying the CPU architecture that the
+  returned package should be compatible with, like "amd64" or "arm".
+
+### Sample Request
+
+```
+curl 'https://registry.terraform.io/v1/providers/hashicorp/random/2.0.0/download/linux/amd64'
+```
+
+### Sample Response
+
+```json
+{
+  "protocols": ["4.0", "5.1"],
+  "os": "linux",
+  "arch": "amd64",
+  "filename": "terraform-provider-random_2.0.0_linux_amd64.zip",
+  "download_url": "https://releases.hashicorp.com/terraform-provider-random/2.0.0/terraform-provider-random_2.0.0_linux_amd64.zip",
+  "shasums_url": "https://releases.hashicorp.com/terraform-provider-random/2.0.0/terraform-provider-random_2.0.0_SHA256SUMS",
+  "shasums_signature_url": "https://releases.hashicorp.com/terraform-provider-random/2.0.0/terraform-provider-random_2.0.0_SHA256SUMS.sig",
+  "shasum": "5f9c7aa76b7c34d722fc9123208e26b22d60440cb47150dd04733b9b94f4541a",
+  "signing_keys": {
+    "gpg_public_keys": [
+      {
+        "key_id": "51852D87348FFC4C",
+        "ascii_armor": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v1\n\nmQENBFMORM0BCADBRyKO1MhCirazOSVwcfTr1xUxjPvfxD3hjUwHtjsOy/bT6p9f\nW2mRPfwnq2JB5As+paL3UGDsSRDnK9KAxQb0NNF4+eVhr/EJ18s3wwXXDMjpIifq\nfIm2WyH3G+aRLTLPIpscUNKDyxFOUbsmgXAmJ46Re1fn8uKxKRHbfa39aeuEYWFA\n3drdL1WoUngvED7f+RnKBK2G6ZEpO+LDovQk19xGjiMTtPJrjMjZJ3QXqPvx5wca\nKSZLr4lMTuoTI/ZXyZy5bD4tShiZz6KcyX27cD70q2iRcEZ0poLKHyEIDAi3TM5k\nSwbbWBFd5RNPOR0qzrb/0p9ksKK48IIfH2FvABEBAAG0K0hhc2hpQ29ycCBTZWN1\ncml0eSA8c2VjdXJpdHlAaGFzaGljb3JwLmNvbT6JATgEEwECACIFAlMORM0CGwMG\nCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEFGFLYc0j/xMyWIIAIPhcVqiQ59n\nJc07gjUX0SWBJAxEG1lKxfzS4Xp+57h2xxTpdotGQ1fZwsihaIqow337YHQI3q0i\nSqV534Ms+j/tU7X8sq11xFJIeEVG8PASRCwmryUwghFKPlHETQ8jJ+Y8+1asRydi\npsP3B/5Mjhqv/uOK+Vy3zAyIpyDOMtIpOVfjSpCplVRdtSTFWBu9Em7j5I2HMn1w\nsJZnJgXKpybpibGiiTtmnFLOwibmprSu04rsnP4ncdC2XRD4wIjoyA+4PKgX3sCO\nklEzKryWYBmLkJOMDdo52LttP3279s7XrkLEE7ia0fXa2c12EQ0f0DQ1tGUvyVEW\nWmJVccm5bq25AQ0EUw5EzQEIANaPUY04/g7AmYkOMjaCZ6iTp9hB5Rsj/4ee/ln9\nwArzRO9+3eejLWh53FoN1rO+su7tiXJA5YAzVy6tuolrqjM8DBztPxdLBbEi4V+j\n2tK0dATdBQBHEh3OJApO2UBtcjaZBT31zrG9K55D+CrcgIVEHAKY8Cb4kLBkb5wM\nskn+DrASKU0BNIV1qRsxfiUdQHZfSqtp004nrql1lbFMLFEuiY8FZrkkQ9qduixo\nmTT6f34/oiY+Jam3zCK7RDN/OjuWheIPGj/Qbx9JuNiwgX6yRj7OE1tjUx6d8g9y\n0H1fmLJbb3WZZbuuGFnK6qrE3bGeY8+AWaJAZ37wpWh1p0cAEQEAAYkBHwQYAQIA\nCQUCUw5EzQIbDAAKCRBRhS2HNI/8TJntCAClU7TOO/X053eKF1jqNW4A1qpxctVc\nz8eTcY8Om5O4f6a/rfxfNFKn9Qyja/OG1xWNobETy7MiMXYjaa8uUx5iFy6kMVaP\n0BXJ59NLZjMARGw6lVTYDTIvzqqqwLxgliSDfSnqUhubGwvykANPO+93BBx89MRG\nunNoYGXtPlhNFrAsB1VR8+EyKLv2HQtGCPSFBhrjuzH3gxGibNDDdFQLxxuJWepJ\nEK1UbTS4ms0NgZ2Uknqn1WRU1Ki7rE4sTy68iZtWpKQXZEJa0IGnuI2sSINGcXCJ\noEIgXTMyCILo34Fa/C6VCm2WBgz9zZO8/rHIiQm1J5zqz0DrDwKBUM9C\n=LYpS\n-----END PGP PUBLIC KEY BLOCK-----",
+        "trust_signature": "",
+        "source": "HashiCorp",
+        "source_url": "https://www.hashicorp.com/security.html"
+      }
+    ]
+  }
+}
+```
+
+### Response Properties
+
+A successful result is a JSON object with the following properties:
+
+* `protocols` (required): an array of Terraform provider API versions that
+  the provider supports, in the same format as for
+  [List Available Versions](#list-available-versions).
+
+  While this property is optional when listing available options, it is
+  _required_ for describing an individual provider package so that Terraform
+  CLI can avoid downloading a package that will not be compatible with it.
+
+* `os` (required): this must echo back the `os` parameter from the
+  request.
+
+* `arch` (required): this must echo back the `arch` parameter from the
+  request. 
+
+* `filename` (required): the filename for this provider's zip archive as
+  recorded in the "shasums" document, so that Terraform CLI can determine which
+  of the given checksums should be used for this specific package.
+
+* `download_url` (required): a URL from which Terraform can retrieve the
+  provider's zip archive. If this is a relative URL then it will be resolved
+  relative to the URL that returned the containing JSON object.
+
+* `shasums_url` (required): a URL from which Terraform can retrieve a text
+  document recording expected SHA256 checksums for this package and possibly
+  other packages for the same provider version on other platforms.
+
+  The indicated document must be in the format generated by the `sha256`
+  command available on many Unix systems, with one entry recording the
+  same filename given in the `filename` property (case sensitive).
+
+* `shasums_signature_url` (required): a URL from which Terraform can retrieve
+  a binary, detached GPG signature for the document at `shasums_url`, signed
+  by one of the keys indicated in the `signing_keys` property.
+  
+* `shasum` (required): the SHA256 checksum for this provider's zip archive as
+  recorded in the shasums document.
+
+* `signing_keys` (required): an object describing signing keys for this
+  provider package, one of which must have been used to produce the signature
+  at `shasums_signature_url`. The object has the following nested properties:
+
+  * `gpg_public_keys` (required): an array of objects, each describing one
+    GPG signing key that is allowed to sign the checksums for this provider
+    version. At least one element must be included, representing the key that
+    produced the signature at `shasums_signature_url`. These objects have
+    the following nested properties:
+
+    * `key_id` (required): uppercase-hexadecimal-formatted ID for this GPG key
+
+    * `ascii_armor` (required): an "ascii-armor" encoding of the **public key**
+      associated with this GPG key.
+
+Return `404 Not Found` to signal that the given provider version isn't
+available for the requested operating system and/or architecture. Terraform
+CLI will only attempt to download versions that it has previously seen in
+response to [List Available Versions](#list-available-versions).
diff --git a/v1.5.7/website/docs/internals/remote-service-discovery.mdx b/v1.5.7/website/docs/internals/remote-service-discovery.mdx
new file mode 100644
index 0000000..04c2a98
--- /dev/null
+++ b/v1.5.7/website/docs/internals/remote-service-discovery.mdx
@@ -0,0 +1,111 @@
+---
+page_title: 'Internals: Remote Service Discovery'
+description: |-
+  Remote service discovery is a protocol used to locate Terraform-native
+  services provided at a user-friendly hostname.
+---
+
+# Remote Service Discovery
+
+Terraform implements much of its functionality in terms of remote services.
+While in many cases these are generic third-party services that are useful
+to many applications, some of these services are tailored specifically to
+Terraform's needs. We call these _Terraform-native services_, and Terraform
+interacts with them via the remote service discovery protocol described below.
+
+## User-facing Hostname
+
+Terraform-native services are provided, from a user's perspective, at a
+user-facing "friendly hostname" which serves as the key for configuration and
+for any authentication credentials required.
+
+The discovery protocol's purpose is to map from a user-provided hostname to
+the base URL of a particular service. Each host can provide different
+combinations of services -- or no services at all! -- and so the discovery
+protocol has a secondary purpose of allowing Terraform to identify _which_
+services are valid for a given hostname.
+
+For example, module source strings can include a module registry hostname
+as their first segment, like `example.com/namespace/name/provider`, and
+Terraform uses service discovery to determine whether `example.com` _has_
+a module registry, and if so where its API is available.
+
+A user-facing hostname is a fully-specified
+[internationalized domain name](https://en.wikipedia.org/wiki/Internationalized_domain_name)
+expressed in its Unicode form (the corresponding "punycode" form is not allowed)
+which must be resolvable in DNS to an address that has an HTTPS server running
+on port 443.
+
+User-facing hostnames are normalized for internal comparison using the
+standard Unicode [Nameprep](https://en.wikipedia.org/wiki/Nameprep) algorithm,
+which includes converting all letters to lowercase, normalizing combining
+diacritics to precomposed form where possible, and various other normalization
+steps.
+
+## Discovery Process
+
+Given a hostname, discovery begins by forming an initial discovery URL
+using that hostname with the `https:` scheme and the fixed path
+`/.well-known/terraform.json`.
+
+For example, given the hostname `example.com` the initial discovery URL
+would be `https://example.com/.well-known/terraform.json`.
+
+Terraform then sends a `GET` request to this discovery URL and expects a
+JSON response. If the response does not have status 200, does not have a media
+type of `application/json` or, if the body cannot be parsed as a JSON object,
+then discovery fails and Terraform considers the host to not support _any_
+Terraform-native services.
+
+If the response is an HTTP redirect then Terraform repeats this step with the
+new location as its discovery URL. Terraform is guaranteed to follow at least
+one redirect, but nested redirects are not guaranteed nor recommended.
+
+If the response is a valid JSON object then its keys are Terraform native
+service identifiers, consisting of a service type name and a version string
+separated by a period. For example, the service identifier for version 1 of
+the module registry protocol is `modules.v1`.
+
+The value of each object element is the base URL for the service in question.
+This URL may be either absolute or relative, and if relative it is resolved
+against the final discovery URL (_after_ following redirects).
+
+The following is an example discovery document declaring support for
+version 1 of the module registry protocol:
+
+```json
+{
+  "modules.v1": "https://modules.example.com/v1/"
+}
+```
+
+## Supported Services
+
+At present, the following service identifiers are in use:
+
+* `login.v1`: [login protocol version 1](/terraform/cli/commands/login)
+* `modules.v1`: [module registry API version 1](/terraform/internals/module-registry-protocol)
+* `providers.v1`: [provider registry API version 1](/terraform/internals/provider-registry-protocol)
+
+## Authentication
+
+If credentials for the given hostname are available in
+[the CLI config](/terraform/cli/config/config-file#Credentials) through a `credentials_helper` or a host-specific environment variable, then they will be included in the request for the discovery document.
+
+The credentials may also be provided to endpoints declared in the discovery
+document, depending on the requirements of the service in question.
+
+## Non-standard Ports in User-facing Hostnames
+
+It is strongly recommended to provide the discovery document for a hostname
+on the standard HTTPS port 443. However, in development environments this is
+not always possible or convenient, so Terraform allows a hostname to end
+with a port specification consisting of a colon followed by one or more
+decimal digits.
+
+When a custom port number is present, the service on that port is expected to
+implement HTTPS and respond to the same fixed discovery path.
+
+For day-to-day use it is strongly recommended _not_ to rely on this mechanism
+and to instead provide the discovery document on the standard port, since this
+allows use of the most user-friendly hostname form.
diff --git a/v1.5.7/website/docs/intro/core-workflow.mdx b/v1.5.7/website/docs/intro/core-workflow.mdx
new file mode 100644
index 0000000..0e675de
--- /dev/null
+++ b/v1.5.7/website/docs/intro/core-workflow.mdx
@@ -0,0 +1,331 @@
+---
+page_title: The Core Terraform Workflow - Guides
+description: 'An overview of how individuals, teams, and organizations can use Terraform. '
+---
+
+# The Core Terraform Workflow
+
+The core Terraform workflow has three steps:
+
+1. **Write** - Author infrastructure as code.
+1. **Plan** - Preview changes before applying.
+1. **Apply** - Provision reproducible infrastructure.
+
+This guide walks through how each of these three steps plays out in the context
+of working as an individual practitioner, how they evolve when a team is
+collaborating on infrastructure, and how Terraform Cloud enables this
+workflow to run smoothly for entire organizations.
+
+## Working as an Individual Practitioner
+
+Let's first walk through how these parts fit together as an individual working
+on infrastructure as code.
+
+### Write
+
+You write Terraform configuration just like you write code: in your editor of
+choice. It's common practice to store your work in a version controlled
+repository even when you're just operating as an individual.
+
+```sh
+# Create repository
+$ git init my-infra && cd my-infra
+
+Initialized empty Git repository in /.../my-infra/.git/
+
+# Write initial config
+$ vim main.tf
+
+# Initialize Terraform
+$ terraform init
+
+Initializing provider plugins...
+# ...
+Terraform has been successfully initialized!
+```
+
+As you make progress on authoring your config, repeatedly running plans can help
+flush out syntax errors and ensure that your config is coming together as you
+expect.
+
+```sh
+# Make edits to config
+$ vim main.tf
+
+# Review plan
+$ terraform plan
+
+# Make additional edits, and repeat
+$ vim main.tf
+```
+
+This parallels working on application code as an individual, where a tight
+feedback loop between editing code and running test commands is useful.
+
+### Plan
+
+When the feedback loop of the Write step has yielded a change that looks good,
+it's time to commit your work and review the final plan.
+
+```sh
+$ git add main.tf
+$ git commit -m 'Managing infrastructure as code!'
+
+[main (root-commit) f735520] Managing infrastructure as code!
+ 1 file changed, 1 insertion(+)
+```
+
+Because `terraform apply` will display a plan for confirmation before
+proceeding to change any infrastructure, that's the command you run for final
+review.
+
+```sh
+$ terraform apply
+
+An execution plan has been generated and is shown below.
+# ...
+```
+
+### Apply
+
+After one last check, you are ready to tell Terraform to provision real
+infrastructure.
+
+```sh
+Do you want to perform these actions?
+
+  Terraform will perform the actions described above.
+  Only 'yes' will be accepted to approve.
+  Enter a value: yes
+
+# ...
+
+Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
+```
+
+At this point, it's common to push your version control repository to a remote
+location for safekeeping.
+
+```sh
+$ git remote add origin https://github.com/*user*/*repo*.git
+$ git push origin main
+```
+
+This core workflow is a loop; the next time you want to make changes, you start
+the process over from the beginning.
+
+Notice how closely this workflow parallels the process of writing application
+code or scripts as an individual? This is what we mean when we talk about
+Terraform enabling infrastructure as code.
+
+## Working as a Team
+
+Once multiple people are collaborating on Terraform configuration, new steps
+must be added to each part of the core workflow to ensure everyone is working
+together smoothly. You'll see that many of these steps parallel the workflow
+changes we make when we work on application code as teams rather than as
+individuals.
+
+### Write
+
+While each individual on a team still makes changes to Terraform configuration
+in their editor of choice, they save their changes to version control _branches_
+to avoid colliding with each other's work. Working in branches enables team
+members to resolve mutually incompatible infrastructure changes using their
+normal merge conflict workflow.
+
+```sh
+$ git checkout -b add-load-balancer
+
+Switched to a new branch 'add-load-balancer'
+```
+
+Running iterative plans is still useful as a feedback loop while authoring
+configuration, though having each team member's computer able to run them
+becomes more difficult with time. As the team and the infrastructure grows, so
+does the number of sensitive input variables (e.g. API Keys, SSL Cert Pairs)
+required to run a plan.
+
+To avoid the burden and the security risk of each team member arranging all
+sensitive inputs locally, it's common for teams to migrate to a model in which
+Terraform operations are executed in a shared Continuous Integration (CI)
+environment. The work needed to create such a CI environment is nontrivial, and
+is outside the scope of this core workflow overview, but a full deep dive on
+this topic can be found in our
+[Running Terraform in Automation](/terraform/tutorials/automation/automate-terraform?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS)
+guide.
+
+This longer iteration cycle of committing changes to version control and then
+waiting for the CI pipeline to execute is often lengthy enough to prohibit using
+speculative plans as a feedback loop while authoring individual Terraform
+configuration changes. Speculative plans are still useful before new Terraform
+changes are applied or even merged to the main development branch, however, as
+we'll see in a minute.
+
+### Plan
+
+For teams collaborating on infrastructure, Terraform's plan output creates an
+opportunity for team members to review each other's work. This allows the team
+to ask questions, evaluate risks, and catch mistakes before any potentially
+harmful changes are made.
+
+The natural place for these reviews to occur is alongside pull requests within
+version control--the point at which an individual proposes a merge from their
+working branch to the shared team branch. If team members review proposed
+config changes alongside speculative plan output, they can evaluate whether the
+intent of the change is being achieved by the plan.
+
+The problem becomes producing that speculative plan output for the team to
+review. Some teams that still run Terraform locally make a practice that pull
+requests should include an attached copy of speculative plan output generated
+by the change author. Others arrange for their CI system to post speculative
+plan output to pull requests automatically.
+
+![Screenshot of Pull Request with manually posted Terraform plan output](/img/docs/manually-pasted-plan-output.png)
+
+In addition to reviewing the plan for the proper expression of its author's
+intent, the team can also make an evaluation whether they want this change to
+happen now. For example, if a team notices that a certain change could result
+in service disruption, they may decide to delay merging its pull request until
+they can schedule a maintenance window.
+
+### Apply
+
+Once a pull request has been approved and merged, it's important for the team
+to review the final concrete plan that's run against the shared team branch and
+the latest version of the state file.
+
+This plan has the potential to be different than the one reviewed on the pull
+request due to issues like merge order or recent infrastructural changes. For
+example, if a manual change was made to your infrastructure since the plan was
+reviewed, the plan might be different when you merge.
+
+It is at this point that the team asks questions about the potential
+implications of applying the change. Do we expect any service disruption from
+this change? Is there any part of this change that is high risk? Is there
+anything in our system that we should be watching as we apply this? Is there
+anyone we need to notify that this change is happening?
+
+Depending on the change, sometimes team members will want to watch the apply
+output as it is happening. For teams that are running Terraform locally, this
+may involve a screen share with the team. For teams running Terraform in CI,
+this may involve gathering around the build log.
+
+Just like the workflow for individuals, the core workflow for teams is a loop
+that plays out for each change. For some teams this loop happens a few times a
+week, for others, many times a day.
+
+## The Core Workflow Enhanced by Terraform Cloud
+
+While the above described workflows enable the safe, predictable, and
+reproducible creating or changing of infrastructure, there are multiple
+collaboration points that can be streamlined, especially as teams and
+organizations scale.  We designed Terraform Cloud to support and enhance
+the core Terraform workflow for anyone collaborating on infrastructure, from
+small teams to large organizations. Let's look at how Terraform Cloud makes
+for a better experience at each step.
+
+### Write
+
+Terraform Cloud provides a centralized and secure location for storing
+input variables and state while also bringing back a tight feedback loop for
+speculative plans for config authors. Terraform configuration can interact with
+Terraform Cloud through the [CLI integration](/terraform/cli/cloud).
+
+```
+terraform {
+  cloud {
+    organization = "my-org"
+    hostname = "app.terraform.io" # Optional; defaults to app.terraform.io
+
+    workspaces {
+      tags = ["networking", "source:cli"]
+    }
+  }
+}
+```
+
+After you configure the integration, a Terraform Cloud API key is all your team members need to edit config and run speculative plans
+against the latest version of the state file using all the remotely stored
+input variables.
+
+```sh
+$ terraform workspace select my-app-dev
+Switched to workspace "my-app-dev".
+
+$ terraform plan
+
+Running plan remotely in Terraform Enterprise.
+
+Output will stream here. To view this plan in a browser, visit:
+
+https://app.terraform.io/my-org/my-app-dev/.../
+
+Refreshing Terraform state in-memory prior to plan...
+
+# ...
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+```
+
+With the assistance of this plan output, team members can each work on
+authoring config until it is ready to propose as a change via a pull request.
+
+### Plan
+
+Once a pull request is ready for review, Terraform Cloud makes the process
+of reviewing a speculative plan easier for team members. First, the plan is
+automatically run when the pull request is created. Status updates to the pull
+request indicate while the plan is in progress.
+
+Once the plan is complete, the status update indicates whether there were any
+changes in the speculative plan, right from the pull request view.
+
+![Screenshot of Pull Request with resource changes in the status update](/img/docs/pull-request.png)
+
+For certain types of changes, this information is all that's needed for a team
+member to be able to approve the pull request. When a teammate needs to do a
+full review of the plan, clicking the link to Terraform Cloud brings up a
+view that allows them to quickly analyze the full plan details.
+
+![Screenshot of Pull Request run in Terraform Cloud](/img/docs/pr-plan.png)
+
+This page allows the reviewer to quickly determine if the plan is matching the
+config author's intent and evaluate the risk of the change.
+
+### Apply
+
+After merge, Terraform Cloud presents the concrete plan to the team for
+review and approval.
+
+![Screenshot of concrete plan](/img/docs/concrete-plan.png)
+
+The team can discuss any outstanding questions about the plan before the change
+is made.
+
+![Screenshot of back-and-forth in Terraform Cloud comments](/img/docs/plan-comments.png)
+
+Once the Apply is confirmed, Terraform Cloud displays the progress live
+to anyone who'd like to watch.
+
+![Screenshot of in-progress Apply](/img/docs/in-progress-apply.png)
+
+<!--
+
+TODO: Add this back in w/ screenshot of notification
+
+And after the change completes, the team can be notified of its outcome.
+
+    [ Multi-screenshot of Slack alert indicating Apply completed successfully and
+    with error; except it's not gonna be Slack anymore? ]
+
+-->
+
+## Conclusion
+
+There are many different ways to use Terraform: as an individual user, a single
+team, or an entire organization at scale. Choosing the best approach for the
+density of collaboration needed will provide the most return on your investment
+in the core Terraform workflow. For organizations using Terraform at scale,
+Terraform Cloud introduces new layers that build on this core workflow to
+solve problems unique to teams and organizations.
diff --git a/v1.5.7/website/docs/intro/index.mdx b/v1.5.7/website/docs/intro/index.mdx
new file mode 100644
index 0000000..367115a
--- /dev/null
+++ b/v1.5.7/website/docs/intro/index.mdx
@@ -0,0 +1,65 @@
+---
+layout: "intro"
+page_title: "What is Terraform"
+sidebar_current: "what"
+description: |-
+ Terraform is an infrastructure as code tool that lets you build, change, and version cloud and on-prem resources safely and efficiently.
+---
+# What is Terraform?
+
+HashiCorp Terraform is an infrastructure as code tool that lets you define both cloud and on-prem resources in human-readable configuration files that you can version, reuse, and share. You can then use a consistent workflow to provision and manage all of your infrastructure throughout its lifecycle. Terraform can manage low-level components like compute, storage, and networking resources, as well as high-level components like DNS entries and SaaS features.
+
+> **Hands On:** Try the Get Started tutorials to start managing infrastructure on popular cloud providers: [Amazon Web Services](/terraform/tutorials/aws-get-started), [Azure](/terraform/tutorials/azure-get-started), [Google Cloud Platform](/terraform/tutorials/gcp-get-started), [Oracle Cloud Infrastructure](/terraform/tutorials/oci-get-started), and [Docker](/terraform/tutorials/docker-get-started).
+
+## How does Terraform work?
+Terraform creates and manages resources on cloud platforms and other services through their application programming interfaces (APIs). Providers enable Terraform to work with virtually any platform or service with an accessible API.
+
+![Terraform creates and manages cloud platforms and services through their APIs](/img/docs/intro-terraform-apis.png)
+
+HashiCorp and the Terraform community have already written **thousands of providers** to manage many different types of resources and services. You can find all publicly available providers on the [Terraform Registry](https://registry.terraform.io/), including Amazon Web Services (AWS), Azure, Google Cloud Platform (GCP), Kubernetes, Helm, GitHub, Splunk, DataDog, and many more.
+
+The core Terraform workflow consists of three stages:
+
+- **Write:** You define resources, which may be across multiple cloud providers and services. For example, you might create a configuration to deploy an application on virtual machines in a Virtual Private Cloud (VPC) network with security groups and a load balancer.
+- **Plan:** Terraform creates an execution plan describing the infrastructure it will create, update, or destroy based on the existing infrastructure and your configuration.
+- **Apply:** On approval, Terraform performs the proposed operations in the correct order, respecting any resource dependencies. For example, if you update the properties of a VPC and change the number of virtual machines in that VPC, Terraform will recreate the VPC before scaling the virtual machines.
+
+![The Terraform workflow has three steps: Write, Plan, and Apply](/img/docs/intro-terraform-workflow.png)
+
+
+## Why Terraform?
+
+HashiCorp co-founder and CTO Armon Dadgar explains how Terraform solves infrastructure challenges.
+
+<iframe src="https://www.youtube.com/embed/h970ZBgKINg" frameborder="0" allowfullscreen="true"  width="560" height="315" ></iframe>
+
+
+### Manage any infrastructure
+
+Find providers for many of the platforms and services you already use in the [Terraform Registry](https://registry.terraform.io/). You can also [write your own](/terraform/plugin). Terraform takes an [immutable approach to infrastructure](https://www.hashicorp.com/resources/what-is-mutable-vs-immutable-infrastructure), reducing the complexity of upgrading or modifying your services and infrastructure.
+
+### Track your infrastructure
+
+Terraform generates a plan and prompts you for your approval before modifying your infrastructure. It also keeps track of your real infrastructure in a [state file](/terraform/language/state), which acts as a source of truth for your environment. Terraform uses the state file to determine the changes to make to your infrastructure so that it will match your configuration.
+
+### Automate changes
+
+Terraform configuration files are declarative, meaning that they describe the end state of your infrastructure. You do not need to write step-by-step instructions to create resources because Terraform handles the underlying logic. Terraform builds a resource graph to determine resource dependencies and creates or modifies non-dependent resources in parallel. This allows Terraform to provision resources efficiently.
+
+### Standardize configurations
+
+Terraform supports reusable configuration components called [modules](/terraform/language/modules) that define configurable collections of infrastructure, saving time and encouraging best practices. You can use publicly available modules from the Terraform Registry, or write your own.
+
+### Collaborate
+
+Since your configuration is written in a file, you can commit it to a Version Control System (VCS) and use [Terraform Cloud](/terraform/intro/terraform-editions#terraform-cloud) to efficiently manage Terraform workflows across teams. Terraform Cloud runs Terraform in a consistent, reliable environment and provides secure access to shared state and secret data, role-based access controls, a private registry for sharing both modules and providers, and more.
+
+-> **Tip:** Learn more about [Terraform use cases](/terraform/intro/use-cases) and [how Terraform compares to alternatives](/terraform/intro/vs).
+
+## Community
+
+We welcome questions, suggestions, and contributions from the community.
+
+- Ask questions in [HashiCorp Discuss](https://discuss.hashicorp.com/c/terraform-core/27).
+- Read our [contributing guide](https://github.com/hashicorp/terraform/blob/main/.github/CONTRIBUTING.md).
+- [Submit an issue](https://github.com/hashicorp/terraform/issues/new/choose) for bugs and feature requests.
diff --git a/v1.5.7/website/docs/intro/terraform-editions.mdx b/v1.5.7/website/docs/intro/terraform-editions.mdx
new file mode 100644
index 0000000..1ea69e6
--- /dev/null
+++ b/v1.5.7/website/docs/intro/terraform-editions.mdx
@@ -0,0 +1,70 @@
+---
+layout: "intro"
+page_title: "Terraform Editions"
+sidebar_current: "what"
+description: |-
+ Terraform Open Source, Terraform Cloud, and Terraform Enterprise solve increasingly complex infrastructure and collaboration challenges.
+---
+
+# Terraform Editions
+
+As your organization adopts infrastructure as code (IaC), you will encounter increasingly complex technical and collaboration challenges. We offer three Terraform editions designed to help you solve them.
+
+## Terraform Open Source
+
+Terraform open source is a free, downloadable tool that you interact with on the command line. It lets you provision infrastructure on any cloud provider and manages configuration, plugins, infrastructure, and state.
+
+###  Why Terraform Open Source?
+
+Terraform open source lets you:
+
+- Adopt infrastructure as code and use a common configuration language to provision thousands of different types of resources and services.
+- Codify your infrastructure so that you can check configuration files into a version control system (VCS) to safely manage contributions. Manually pull the most up-to-date version to perform Terraform operations.
+- Use and publish public infrastructure templates called modules to implement industry and organization best practices, group your infrastructure into logically-related components, and deploy infrastructure more quickly.
+
+
+### Resources
+
+- Get Started tutorials for popular providers: [Amazon Web Services](/terraform/tutorials/aws-get-started), [Azure](/terraform/tutorials/azure-get-started), [Google Cloud Platform](/terraform/tutorials/gcp-get-started), [Oracle Cloud Infrastructure](/terraform/tutorials/oci-get-started), and [Docker](/terraform/tutorials/docker-get-started)
+- [What is Terraform?](/terraform/intro)
+- [Configuration Language Documentation](/terraform/language)
+- [CLI Documentation](/terraform/cli)
+
+## Terraform Cloud
+
+Terraform Cloud is a SaaS application that runs Terraform in a stable, remote environment and securely stores state and secrets. It includes a rich user interface that helps you better understand your Terraform operations and resources, allows you to define role-based access controls, and offers a private registry for sharing modules and providers. Terraform Cloud also integrates with the Terraform CLI and connects to common version control systems (VCS) like GitHub, GitLab, and Bitbucket. When you connect a Terraform Cloud workspace to a VCS repository, new commits and changes can automatically trigger Terraform plans. Terraform Cloud also offers an API, allowing you to integrate it into existing workflows.
+
+Many Terraform Cloud features are free for small teams; we offer paid plans for larger organizations with additional collaboration and governance features.
+
+###  Why Terraform Cloud?
+
+Terraform Cloud lets you:
+
+- Run Terraform from the local CLI or in a remote environment, trigger operations through your version control system, or use an API to integrate Terraform Cloud into your existing workflows.
+- Ensure that only approved teams can access, edit, and provision infrastructure with Terraform Cloud workspaces, single sign-on, and role-based access controls.
+- Securely store and version Terraform state remotely, with encryption at rest. Versioned state files allow you to access state file history.
+- Publish configuration modules in the Terraform Cloud private registry that define approved infrastructure patterns. For example, a module may allow users to choose the cloud provider on which to deploy their Java application. This allows consumers to implement your organization’s best practices without becoming infrastructure or cloud experts.
+- Enforce best practices and security rules with the Sentinel embedded policy as code framework. For example, policies may restrict regions for production deployments.
+
+### Resources
+
+- [Create a Terraform Cloud Account](https://app.terraform.io/public/signup/account)
+- [Terraform Cloud Documentation](/terraform/cloud-docs)
+- [Sentinel Documentation](/terraform/cloud-docs/policy-enforcement)
+- [Get Started - Terraform Cloud](/terraform/tutorials/cloud-get-started) tutorials show you how to manage infrastructure using Terraform Cloud's VCS integration
+
+## Terraform Enterprise
+
+Terraform Enterprise allows you to set up a self-hosted distribution of Terraform Cloud. It offers customizable resource limits and is ideal for organizations with strict security and compliance requirements.
+
+###  Why Terraform Enterprise?
+
+Terraform Enterprise lets you:
+
+- Set up a private instance of Terraform Cloud with dedicated support from HashiCorp.
+- Accommodate advanced security and compliance requirements. Terraform Enterprise supports several types of installations, including air gapped and active/active architecture, and allows private networking and job scaling for better performance.
+
+### Resources
+- [Terraform Pricing](https://www.hashicorp.com/products/terraform/pricing)
+- [Terraform Enterprise Documentation](/terraform/enterprise)
+- [Recommended Enterprise Patterns](/terraform/tutorials/recommended-patterns) guides
diff --git a/v1.5.7/website/docs/intro/use-cases.mdx b/v1.5.7/website/docs/intro/use-cases.mdx
new file mode 100644
index 0000000..fa53781
--- /dev/null
+++ b/v1.5.7/website/docs/intro/use-cases.mdx
@@ -0,0 +1,92 @@
+---
+layout: "intro"
+page_title: "Use Cases"
+sidebar_current: "use-cases"
+description: |-
+  Learn how  Terraform enables multi-cloud deployments, application management, policy compliance, and self-service infrastructure.
+---
+
+# Use Cases
+
+[HashiCorp Terraform](/terraform/intro) is an infrastructure as code tool that lets you define infrastructure resources in human-readable configuration files that you can version, reuse, and share. You can then use a consistent workflow to safely and efficiently provision and manage your infrastructure throughout its lifecycle.
+
+This page describes popular Terraform use cases and provides related resources that you can use to create Terraform configurations and workflows.
+
+## Multi-Cloud Deployment
+Provisioning infrastructure across multiple clouds increases fault-tolerance, allowing for more graceful recovery from cloud provider outages. However, multi-cloud deployments add complexity because each provider has its own interfaces, tools, and workflows. Terraform lets you use the same workflow to manage multiple providers and handle cross-cloud dependencies. This simplifies management and orchestration for large-scale, multi-cloud infrastructures.
+
+### Resources
+
+- Try our [Deploy Federated Multi-Cloud Kubernetes Clusters](/terraform/tutorials/networking/multicloud-kubernetes) tutorial to provision Kubernetes clusters in both Azure and AWS environments, configure Consul federation with mesh gateways across the two clusters, and deploy microservices across the two clusters to verify federation.
+- Browse the [Terraform Registry](https://registry.terraform.io/browse/providers) to find thousands of publicly available providers.
+
+
+## Application Infrastructure Deployment, Scaling, and Monitoring Tools
+
+You can use Terraform to efficiently deploy, release, scale, and monitor infrastructure for multi-tier applications. N-tier application architecture lets you scale application components independently and provides a separation of concerns. An application could consist of a pool of web servers that use a database tier, with additional tiers for API servers, caching servers, and routing meshes. Terraform allows you to manage the resources in each tier together, and automatically handles dependencies between tiers. For example, Terraform will deploy a database tier before provisioning the web servers that depend on it.
+
+### Resources
+
+- Try our [Automate Monitoring with the Terraform Datadog Provider](/terraform/tutorials/applications/datadog-provider) tutorial to deploy a demo Nginx application to a Kubernetes cluster with Helm and install the Datadog agent across the cluster. The Datadog agent reports the cluster health back to your Datadog dashboard.
+- Try our [Use Application Load Balancers for Blue-Green and Canary Deployments](/terraform/tutorials/aws/blue-green-canary-tests-deployments) tutorial. You will provision the blue and green environments, add feature toggles to your Terraform configuration to define a list of potential deployment strategies, conduct a canary test, and incrementally promote your green environment.
+
+
+## Self-Service Clusters
+
+At a large organization, your centralized operations team may get many repetitive infrastructure requests. You can use Terraform to build a "self-serve" infrastructure model that lets product teams manage their own infrastructure independently. You can create and use Terraform modules that codify the standards for deploying and managing services in your organization, allowing teams to efficiently deploy services in compliance with your organization’s practices. Terraform Cloud can also integrate with ticketing systems like ServiceNow to automatically generate new infrastructure requests.
+
+### Resources
+
+- Try the [Use Modules from the Registry](/terraform/tutorials/modules/module-use) tutorial to get started using public modules in your Terraform configuration.
+Try the [Build and Use a Local Module](/terraform/tutorials/modules/module-create) tutorial to create a module to manage AWS S3 buckets.
+- Follow these [ServiceNow Service Catalog Integration Setup Instructions](/terraform/cloud-docs/integrations/service-now) to connect ServiceNow to Terraform Cloud.
+
+
+## Policy Compliance and Management
+
+Terraform can help you enforce policies on the types of resources teams can provision and use. Ticket-based review processes are a bottleneck that can slow down development. Instead, you can use Sentinel, a policy-as-code framework, to automatically enforce compliance and governance policies before Terraform makes infrastructure changes. Sentinel policies are available in Terraform Enterprise and [Terraform Cloud](https://www.hashicorp.com/products/terraform/pricing).
+
+### Resources
+
+- Try the [Control Costs with Policies](/terraform/tutorials/cloud-get-started/cost-estimation) tutorial to estimate the cost of infrastructure changes and define policy to limit it.
+
+- The [Sentinel documentation](/terraform/cloud-docs/policy-enforcement) provides more in-depth information and a list of example policies that you can adapt for your use cases.
+
+
+## PaaS Application Setup
+Platform as a Service (PaaS) vendors like Heroku allow you to create  web applications and attach add-ons, such as databases or email providers. Heroku can elastically scale the number of dynos or workers, but most non-trivial applications need many add-ons and external services. You can use Terraform to codify the setup required for a Heroku application, configure a DNSimple to set a CNAME, and set up Cloudflare as a Content Delivery Network (CDN) for the app. Terraform can quickly and consistently do all of this without a web interface.
+
+### Resources
+
+Try the [Deploy, Manage, and Scale an Application on Heroku](/terraform/tutorials/applications/heroku-provider) tutorial to manage an application’s lifecycle with Terraform.
+
+
+## Software Defined Networking
+
+Terraform can interact with Software Defined Networks (SDNs) to automatically configure the network according to the needs of the applications running in it. This lets you move from a ticket-based workflow to an automated one, reducing deployment times.
+
+For example, when a service registers with [HashiCorp Consul](https://www.consul.io/), [Consul-Terraform-Sync](/consul/docs/nia) can automatically generate Terraform configuration to expose appropriate ports and adjust network settings for any SDN that has an associated Terraform provider. Network Infrastructure Automation (NIA) allows you to safely approve the changes that your applications require without having to manually translate tickets from developers into the changes you think their applications need.
+
+### Resources
+
+- Try the [Network Infrastructure Automation with Consul-Terraform-Sync Intro](/consul/tutorials/network-infrastructure-automation/consul-terraform-sync-intro) tutorial to install Consul-Terraform-Sync on a node. You will then configure it to communicate with a Consul datacenter, react to service changes, and execute an example task.
+- Try the [Consul-Terraform-Sync and Terraform Enterprise/Cloud Integration](/consul/tutorials/network-infrastructure-automation/consul-terraform-sync-terraform-enterprise) tutorial to configure Consul-Terraform-Sync to interact with Terraform Enterprise and Terraform Cloud.
+
+
+## Kubernetes
+
+Kubernetes is an open-source workload scheduler for containerized applications. Terraform lets you both deploy a Kubernetes cluster and manage its resources (e.g., pods, deployments, services, etc.). You can also use the [Kubernetes Operator for Terraform](https://github.com/hashicorp/terraform-k8s) to manage cloud and on-prem infrastructure through a Kubernetes Custom Resource Definition (CRD) and Terraform Cloud.
+
+### Resources
+
+- Try the [Manage Kubernetes Resources via Terraform](/terraform/tutorials/kubernetes/kubernetes-provider) tutorial. You will use Terraform to schedule and expose a NGINX deployment on a Kubernetes cluster.
+- Try the [Deploy Infrastructure with the Terraform Cloud Operator for Kubernetes](/terraform/tutorials/kubernetes/kubernetes-operator) tutorial. You will configure and deploy the Operator to a Kubernetes cluster and use it to create a Terraform Cloud workspace and provision a message queue for an example application.
+
+
+## Parallel Environments
+
+You may have staging or QA environments that you use to test new applications before releasing them in production. As the production environment grows larger and more complex, it can be increasingly difficult to maintain an up-to-date environment for each stage of the development process. Terraform lets you rapidly spin up and decommission infrastructure for development, test, QA, and production. Using Terraform to create disposable environments as needed is more cost-efficient than maintaining each one indefinitely.
+
+
+## Software Demos
+You can use Terraform to create, provision, and bootstrap a demo on various cloud providers. This lets end users easily try the software on their own infrastructure and even enables them to adjust parameters like cluster size to more rigorously test tools at any scale.
diff --git a/v1.5.7/website/docs/intro/vs/boto.mdx b/v1.5.7/website/docs/intro/vs/boto.mdx
new file mode 100644
index 0000000..de008b8
--- /dev/null
+++ b/v1.5.7/website/docs/intro/vs/boto.mdx
@@ -0,0 +1,20 @@
+---
+page_title: 'Terraform vs. Boto, Fog, etc.'
+description: 'How Terraform compares to cloud provider client libraries like Boto and Fog. '
+---
+
+# Terraform vs. Boto, Fog, etc.
+
+Libraries like Boto, Fog, etc. are used to provide native access
+to cloud providers and services by using their APIs. Some
+libraries are focused on specific clouds, while others attempt
+to bridge them all and mask the semantic differences. Using a client
+library only provides low-level access to APIs, requiring application
+developers to create their own tooling to build and manage their infrastructure.
+
+Terraform is not intended to give low-level programmatic access to
+providers, but instead provides a high level syntax for describing
+how cloud resources and services should be created, provisioned, and
+combined. Terraform is very flexible, using a plugin-based model to
+support providers and provisioners, giving it the ability to support
+almost any service that exposes APIs.
diff --git a/v1.5.7/website/docs/intro/vs/chef-puppet.mdx b/v1.5.7/website/docs/intro/vs/chef-puppet.mdx
new file mode 100644
index 0000000..c846ffa
--- /dev/null
+++ b/v1.5.7/website/docs/intro/vs/chef-puppet.mdx
@@ -0,0 +1,23 @@
+---
+page_title: 'Terraform vs. Chef, Puppet, etc.'
+description: >-
+  How Terraform compares to configuration management tools like Chef and
+  Puppet.
+---
+
+# Terraform vs. Chef, Puppet, etc.
+
+Configuration management tools install and manage software on a machine
+that already exists. Terraform is not a configuration management tool,
+and it allows existing tooling to focus on their strengths: bootstrapping
+and initializing resources.
+
+Terraform focuses on the higher-level abstraction of the datacenter and
+associated services, while allowing you to use configuration management
+tools on individual systems. It also aims to bring the same benefits of
+codification of your system configuration to infrastructure management.
+
+If you are using traditional configuration management within your compute
+instances, you can use Terraform to configure bootstrapping software like
+cloud-init to activate your configuration management software on first
+system boot.
diff --git a/v1.5.7/website/docs/intro/vs/cloudformation.mdx b/v1.5.7/website/docs/intro/vs/cloudformation.mdx
new file mode 100644
index 0000000..a677ec0
--- /dev/null
+++ b/v1.5.7/website/docs/intro/vs/cloudformation.mdx
@@ -0,0 +1,39 @@
+---
+page_title: 'Terraform vs. CloudFormation, Heat, etc.'
+description: >-
+  How Terraform compares to other infrastructure as code tools like
+  CloudFormation and Heat. Terraform can simultaneously manage multiple cloud
+  providers (AWS, OpenStack, etc.) and services (Cloudflare, DNSimple, etc.).
+---
+
+# Terraform vs. CloudFormation, Heat, etc.
+
+Tools like CloudFormation, Heat, etc. allow the details of an infrastructure
+to be codified into a configuration file. The configuration files allow
+the infrastructure to be elastically created, modified and destroyed. Terraform
+is inspired by the problems they solve.
+
+Terraform similarly uses configuration files to detail the infrastructure
+setup, but it goes further by being both cloud-agnostic and enabling
+multiple providers and services to be combined and composed. For example,
+Terraform can be used to orchestrate an AWS and OpenStack cluster simultaneously,
+while enabling 3rd-party providers like Cloudflare and DNSimple to be integrated
+to provide CDN and DNS services. This enables Terraform to represent and
+manage the entire infrastructure with its supporting services, instead of
+only the subset that exists within a single provider. It provides a single
+unified syntax, instead of requiring operators to use independent and
+non-interoperable tools for each platform and service.
+
+Terraform also separates the planning phase from the execution phase,
+by using the concept of an execution plan. By running `terraform plan`,
+the current state is refreshed and the configuration is consulted to
+generate an action plan. The plan includes all actions to be taken:
+which resources will be created, destroyed or modified. It can be
+inspected by operators to ensure it is exactly what is expected. Using
+`terraform graph`, the plan can be visualized to show dependent ordering.
+Once the plan is captured, the execution phase can be limited to only
+the actions in the plan. Other tools combine the planning and execution
+phases, meaning operators are forced to mentally reason about the effects
+of a change, which quickly becomes intractable in large infrastructures.
+Terraform lets operators apply changes with confidence, as they know exactly
+what will happen beforehand.
diff --git a/v1.5.7/website/docs/intro/vs/custom.mdx b/v1.5.7/website/docs/intro/vs/custom.mdx
new file mode 100644
index 0000000..8b381c6
--- /dev/null
+++ b/v1.5.7/website/docs/intro/vs/custom.mdx
@@ -0,0 +1,38 @@
+---
+page_title: Terraform vs. Custom Solutions
+description: >-
+  Why Terraform is easier to use and maintain than custom, internal
+  infrastructure solutions.
+---
+
+# Terraform vs. Custom Solutions
+
+Most organizations start by manually managing infrastructure through
+simple scripts or web-based interfaces. As the infrastructure grows,
+any manual approach to management becomes both error-prone and tedious,
+and many organizations begin to home-roll tooling to help
+automate the mechanical processes involved.
+
+These tools require time and resources to build and maintain.
+As tools of necessity, they represent the minimum viable
+features needed by an organization, being built to handle only
+the immediate needs. As a result, they are often hard
+to extend and difficult to maintain. Because the tooling must be
+updated in lockstep with any new features or infrastructure,
+it becomes the limiting factor for how quickly the infrastructure
+can evolve.
+
+Terraform is designed to tackle these challenges. It provides a simple,
+unified syntax, allowing almost any resource to be managed without
+learning new tooling. By capturing all the resources required, the
+dependencies between them can be resolved automatically so that operators
+do not need to remember and reason about them. Removing the burden
+of building the tool allows operators to focus on their infrastructure
+and not the tooling.
+
+Furthermore, Terraform is an open source tool. In addition to
+HashiCorp, the community around Terraform helps to extend its features,
+fix bugs and document new use cases. Terraform helps solve a problem
+that exists in every organization and provides a standard that can
+be adopted to avoid reinventing the wheel between and within organizations.
+Its open source nature ensures it will be around in the long term.
diff --git a/v1.5.7/website/docs/intro/vs/index.mdx b/v1.5.7/website/docs/intro/vs/index.mdx
new file mode 100644
index 0000000..0a809d7
--- /dev/null
+++ b/v1.5.7/website/docs/intro/vs/index.mdx
@@ -0,0 +1,22 @@
+---
+page_title: Terraform vs. Alternatives
+description: An overview of how Terraform compares to alternative software and tools.
+---
+
+# Terraform vs. Alternatives
+
+Terraform provides a flexible abstraction of resources and providers. This model
+allows for representing everything from physical hardware, virtual machines, and
+containers, to email and DNS providers. Because of this flexibility, Terraform
+can be used to solve many different problems. This means there are a number of
+existing tools that overlap with the capabilities of Terraform. We compare Terraform
+to a number of these tools, but it should be noted that Terraform is not mutually
+exclusive with other systems. It can be used to manage a single application, or the
+entire datacenter.
+
+Learn how Terraform compares to:
+
+- [Chef, Puppet, etc.](/terraform/intro/vs/chef-puppet)
+- [CloudFormation, Heat, etc.](/terraform/intro/vs/cloudformation)
+- [Boto, Fog, etc.](/terraform/intro/vs/boto)
+- [Custom Solutions](/terraform/intro/vs/custom)
diff --git a/v1.5.7/website/docs/language/attr-as-blocks.mdx b/v1.5.7/website/docs/language/attr-as-blocks.mdx
new file mode 100644
index 0000000..86b53eb
--- /dev/null
+++ b/v1.5.7/website/docs/language/attr-as-blocks.mdx
@@ -0,0 +1,176 @@
+---
+page_title: Attributes as Blocks - Configuration Language
+description: >-
+  For historical reasons, certain arguments within resource blocks can use
+  either
+
+  block or attribute syntax.
+---
+
+# Attributes as Blocks
+
+-> **Note:** This page is an appendix to the Terraform documentation. Most users do not need to know the full details of this behavior.
+
+## Summary
+
+Many resource types use repeatable nested blocks to manage collections of
+sub-objects related to the primary resource.
+
+Rarely, some resource types _also_ support an argument with the same name as a
+nested block type, and will purge any sub-objects of that type if that argument
+is set to an empty list (`<ATTR> = []`).
+
+Most users do not need to know any further details of this "nested block or
+empty list" behavior. However, read further if you need to:
+
+- Use Terraform's [JSON syntax](/terraform/language/syntax/json) with this
+  type of resource.
+- Create a reusable module that wraps this type of resource.
+
+## Details
+
+In Terraform v0.12 and later, the language makes a distinction between
+[argument syntax and nested block syntax](/terraform/language/syntax/configuration#arguments-and-blocks)
+within blocks:
+
+- Argument syntax sets a named argument for the containing object. If the
+  attribute has a default value then an explicitly-specified value entirely
+  overrides that default.
+
+- Nested block syntax represents a related child object of the container that
+  has its own set of arguments. Where multiple such objects are possible, multiple
+  blocks of the same type can be present. If the nested attributes themselves
+  have default values, they are honored for each nested block separately,
+  merging in with any explicitly-defined arguments.
+
+The distinction between these is particularly important for
+[JSON syntax](/terraform/language/syntax/json)
+because the same primitive JSON constructs (lists and objects) will be
+interpreted differently depending on whether a particular name is an argument
+or a nested block type.
+
+However, in some cases existing provider features were relying on the
+conflation of these two concepts in the language of Terraform v0.11 and earlier,
+using nested block syntax in most cases but using argument syntax to represent
+explicitly the idea of removing all existing objects of that type, since the
+absence of any blocks was interpreted as "ignore any existing objects".
+
+The information on this page only applies to certain special arguments that
+were relying on this usage pattern prior to Terraform v0.12. The documentation
+for each of those features links to this page for details of the special usage
+patterns that apply. In all other cases, use either argument or nested block
+syntax as directed by the examples in the documentation for a particular
+resource type.
+
+## Defining a Fixed Object Collection Value
+
+When working with resource type arguments that behave in this way, it is valid
+and we recommend to use the nested block syntax whenever defining a fixed
+collection of objects:
+
+```hcl
+example {
+  foo = "bar"
+}
+example {
+  foo = "baz"
+}
+```
+
+The above implicitly specifies a two-element list of objects assigned to the
+`example` argument, treating it as if it were a nested block type.
+
+If you need to explicitly call for zero `example` objects, you must use the
+argument syntax with an empty list:
+
+```hcl
+example = []
+```
+
+These two forms cannot be mixed; there cannot be both explicitly zero `example`
+objects and explicit single `example` blocks declared at the same time.
+
+For true nested blocks where this special behavior does not apply, assigning
+`[]` using argument syntax is not valid. The normal way to specify zero objects
+of a type is to write no nested blocks at all.
+
+## Arbitrary Expressions with Argument Syntax
+
+Although we recommend using block syntax for simple cases for readability, the
+names that work in this mode _are_ defined as arguments, and so it is possible
+to use argument syntax to assign arbitrary dynamic expressions to them, as
+long as the expression has the expected result type:
+
+```hcl
+example = [
+  for name in var.names: {
+    foo = name
+  }
+]
+```
+
+```hcl
+# Not recommended, but valid: a constant list-of-objects expression
+example = [
+  {
+    foo = "bar"
+  },
+  {
+    foo = "baz"
+  },
+]
+```
+
+Because of the rule that argument declarations like this fully override any
+default value, when creating a list-of-objects expression directly the usual
+handling of optional arguments does not apply, so all of the arguments must be
+assigned a value, even if it's an explicit `null`:
+
+```hcl
+example = [
+  {
+    # Cannot omit foo in this case, even though it would be optional in the
+    # nested block syntax.
+    foo = null
+  },
+]
+```
+
+If you are writing a reusable module that allows callers to pass in a list of
+objects to assign to such an argument, you may wish to use the `merge` function
+to populate any attributes the user didn't explicitly set, in order to give
+the module user the effect of optional arguments:
+
+```hcl
+example = [
+  for ex in var.examples: merge({
+    foo = null # (or any other suitable default value)
+  }, ex)
+]
+```
+
+For the arguments that use the attributes-as-blocks usage mode, the above is
+a better pattern than using
+[`dynamic` blocks](/terraform/language/expressions/dynamic-blocks)
+because the case where the
+caller provides an empty list will result in explicitly assigning an empty
+list value, rather than assigning no value at all and thus retaining and
+ignoring any existing objects. `dynamic` blocks are required for
+dynamically-generating _normal_ nested blocks, though.
+
+## In JSON syntax
+
+Arguments that use this special mode are specified in JSON syntax always using
+the [JSON expression mapping](/terraform/language/syntax/json#expression-mapping)
+to produce a list of objects.
+
+The interpretation of these values in JSON syntax is, therefore, equivalent
+to that described under _Arbitrary Expressions with Argument Syntax_ above,
+but expressed in JSON syntax instead.
+
+Due to the ambiguity of the JSON syntax, there is no way to distinguish based
+on the input alone between argument and nested block usage, so the JSON syntax
+cannot support the nested block processing mode for these arguments. This is,
+unfortunately, one necessary concession on the equivalence between native syntax
+and JSON syntax made pragmatically for compatibility with existing provider
+design patterns. Providers may phase out such patterns in future major releases.
diff --git a/v1.5.7/website/docs/language/checks/index.mdx b/v1.5.7/website/docs/language/checks/index.mdx
new file mode 100644
index 0000000..fe0c45b
--- /dev/null
+++ b/v1.5.7/website/docs/language/checks/index.mdx
@@ -0,0 +1,121 @@
+---
+page_title: Checks - Configuration Language
+description: >-
+  Check customized infrastructure requirements to provide ongoing and continuous verification.
+---
+
+# Checks
+
+-> **Note:** Check blocks are only available in Terraform v1.5.0 and later.
+
+The `check` block can validate your infrastructure outside the usual resource lifecycle. Check blocks address a gap between post-apply and functional validation of infrastructure.
+
+> **Hands-on:** Try the [Validate Infrastructure Using Checks](/terraform/tutorials/configuration-language/checks) tutorial.
+
+Check blocks allow you to define [custom conditions](/terraform/language/expressions/custom-conditions) that execute on every Terraform plan or apply operation without affecting the overall status of an operation. Check blocks execute as the last step of a plan or apply after Terraform has planned or provisioned your infrastructure.
+
+## Syntax
+
+You can declare a `check` block with a local name, zero-to-one scoped [data sources](#scoped-data-sources), and one-to-many [assertions](#assertions).
+
+The following example loads the Terraform website and validates that it returns the expected status code `200`.
+
+```hcl
+check "health_check" {
+  data "http" "terraform_io" {
+    url = "https://www.terraform.io"
+  }
+
+  assert {
+    condition = data.http.terraform_io.status_code == 200
+    error_message = "${data.http.terraform_io.url} returned an unhealthy status code"
+  }
+}
+```
+
+### Scoped data sources
+
+You can use any data source from any provider as a scoped data source within a `check` block.
+
+A `check` block can optionally contain a nested (a.k.a. scoped) data source. This `data` block behaves like an external [data source](/terraform/language/data-sources), except you can not reference it outside its enclosing `check` block. Additionally, if a scoped data source's provider raises any errors, they are masked as warnings and do not prevent Terraform from continuing operation execution.
+
+You can use a scoped data source to validate the status of a piece of infrastructure outside of the usual Terraform resource lifecycle. [In the above example](#checks-syntax), if the `terraform_io` data source fails to load, you receive a warning instead of a blocking error, which would occur if you declared this data source outside of a `check` block.
+
+#### Meta-Arguments
+
+Scoped data sources support the `depends_on` and `provider` [meta-arguments](/terraform/language/resources/syntax#meta-arguments). Scoped data sources do not support the `count` or`for_each` meta-arguments.
+
+##### `depends_on`
+
+The `depends_on` meta-argument can be particularly powerful when used within scoped data sources.
+
+The first time Terraform creates the _initial_ plan for our [previous example](#checks-syntax), the plan fails because Terraform has not applied its configuration yet. Meaning this test fails because Terraform must still create the resources to make this website exist. Therefore, the first time Terraform runs this check, it always throws a potentially distracting error message.
+
+You can fix this by adding [`depends_on`](/terraform/language/meta-arguments/depends_on) to your scoped data source, ensuring it depends on an essential piece of your site's infrastructure, such as the load balancer. The check returns  `known after apply` until that crucial piece of your website is ready. This strategy avoids producing unnecessary warnings during setup, and the check executes during subsequent plans and applies.
+
+One problem with this strategy is that if the resource your scoped data source `depends_on` changes, the check block returns `known after apply` until Terraform has updated that resource. Depending on your use case, this behavior could be acceptable or problematic.
+
+We recommend implementing the `depends_on` meta-argument if your scoped data source depends on the existence of another resource without referencing it directly.
+
+### Assertions
+
+Check blocks validate your custom assertions using `assert` blocks. Each `check` block must have at least one, but potentially many, `assert` blocks. Each `assert` block has a [`condition` attribute](/terraform/language/expressions/custom-conditions#condition-expressions) and an [`error_message` attribute](/terraform/language/expressions/custom-conditions#error-messages).
+
+Unlike other [custom conditions](/terraform/language/expressions/custom-conditions), assertions do not affect Terraform's execution of an operation. A failed assertion reports a warning without halting the ongoing operation. This contrasts with other custom conditions, such as a postcondition, where Terraform produces an error immediately, halting the operation and blocking the application or planning of future resources.
+
+Condition arguments within `assert` blocks can refer to scoped data sources within the enclosing `check` block and any variables, resources, data sources, or module outputs within the current module.
+
+[Learn more about assertions](/terraform/language/expressions/custom-conditions#checks-with-assertions).
+
+### Meta-Arguments
+
+Check blocks do not currently support [meta-arguments](/terraform/language/resources/syntax#meta-arguments). We are still collecting feedback on this feature, so if your use case would benefit from check blocks supporting meta-arguments, please [let us know](https://github.com/hashicorp/terraform/issues/new/choose).
+
+## Continuous validation in Terraform Cloud
+
+Terraform Cloud can automatically validate whether checks in a workspace’s configuration continue to pass after Terraform provisions new infrastructure. See [Continuous Validation](/terraform/cloud-docs/workspaces/health#continuous-validation) for details.
+
+## Choosing Checks or other Custom Conditions
+
+Check blocks offer the most _flexible_ validation solution within Terraform. You can reference outputs, variables, resources, and data sources within check assertions. You can also use checks to model every alternate [Custom Condition](/terraform/language/expressions/custom-conditions). However, that does not mean you should replace all your custom conditions with check blocks.
+
+There are major behavioral differences between check block assertions and other custom conditions, the main one being that check blocks do _not_ affect Terraform's execution of an operation. You can use this non-blocking behavior to decide the best type of validation for your use case.
+
+### Outputs and variables
+
+[Output postconditions](/terraform/language/expressions/custom-conditions#outputs) and [variable validations](/terraform/language/expressions/custom-conditions#input-variable-validation) both make assertions around inputs and outputs.
+
+This is one of the cases where you might want Terraform to block further execution. 
+
+For example, it is not helpful for Terraform to warn that an input variable is invalid after it applies an entire configuration with that input variable. In this case, a check block would warn of the invalid input variable _without_ interrupting the operation. A validation block for the same input variable would alert you of the invalid variable and halt the plan or apply operation.
+
+### Resource Preconditions and Postconditions
+
+The difference between [preconditions and postconditions](/terraform/language/expressions/custom-conditions#preconditions-and-postconditions) and check blocks is more nuanced.
+
+Preconditions are unique amongst the custom conditions in that they execute _before_ a resource change is applied or planned. [Choosing Between Preconditions and Postconditions](/terraform/language/expressions/custom-conditions#choosing-between-preconditions-and-postconditions) offers guidance on choosing between a precondition and a postcondition, and the same topics also apply to choosing between a precondition and a check block.
+
+You can often use postconditions interchangeably with check blocks to validate resources and data sources.
+
+For example, you can [rewrite the above `check` block example](#checks-syntax) to use a postcondition instead. The below code uses a `postcondition` block to validate that the Terraform website returns the expected status code of `200`.
+
+```hcl
+data "http" "terraform_io" {
+  url = "https://www.terraform.io"
+
+  lifecycle {
+    postcondition {
+        condition = self.status_code == 200
+        error_message = "${self.url} returned an unhealthy status code"
+    }
+  }
+}
+```
+
+Both the `check` and `postcondition` block examples validate that the Terraform website returns a `200` status code during a plan or an apply operation. The difference between the two blocks is how each handles failure.
+
+If a `postcondition` block fails, it _blocks_ Terraform from executing the current operation. If a `check` block fails, it _does not_ block Terraform from executing an operation.
+
+If the above example's postcondition fails, it is impossible to recover from. Terraform blocks any future plan or apply operations if your postcondition is unsatisfied during the planning stage. This problem occurs because the postcondition does not directly depend on Terraform configuration, but instead on the complex interactions between multiple resources.
+
+We recommend using check blocks to validate the status of infrastructure as a whole. We only recommend using postconditions when you want a guarantee on a single resource based on that resource's configuration.
diff --git a/v1.5.7/website/docs/language/data-sources/index.mdx b/v1.5.7/website/docs/language/data-sources/index.mdx
new file mode 100644
index 0000000..478b10b
--- /dev/null
+++ b/v1.5.7/website/docs/language/data-sources/index.mdx
@@ -0,0 +1,259 @@
+---
+page_title: Data Sources - Configuration Language
+description: >-
+  Data sources allow Terraform to use external data, function output, and data
+  from other configurations. Learn data resource arguments, behavior, and
+  lifecycle.
+---
+
+# Data Sources
+
+_Data sources_ allow Terraform to use information defined outside of Terraform,
+defined by another separate Terraform configuration, or modified by functions.
+
+> **Hands-on:** Try the [Query Data Sources](/terraform/tutorials/configuration-language/data-sources) tutorial.
+
+Each [provider](/terraform/language/providers) may offer data sources
+alongside its set of [resource](/terraform/language/resources)
+types.
+
+## Using Data Sources
+
+A data source is accessed via a special kind of resource known as a
+_data resource_, declared using a `data` block:
+
+```hcl
+data "aws_ami" "example" {
+  most_recent = true
+
+  owners = ["self"]
+  tags = {
+    Name   = "app-server"
+    Tested = "true"
+  }
+}
+```
+
+A `data` block requests that Terraform read from a given data source ("aws_ami")
+and export the result under the given local name ("example"). The name is used
+to refer to this resource from elsewhere in the same Terraform module, but has
+no significance outside of the scope of a module.
+
+The data source and name together serve as an identifier for a given
+resource and so must be unique within a module.
+
+Within the block body (between `{` and `}`) are query constraints defined by
+the data source. Most arguments in this section depend on the
+data source, and indeed in this example `most_recent`, `owners` and `tags` are
+all arguments defined specifically for [the `aws_ami` data source](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami).
+
+When distinguishing from data resources, the primary kind of resource (as declared
+by a `resource` block) is known as a _managed resource_. Both kinds of resources
+take arguments and export attributes for use in configuration, but while
+managed resources cause Terraform to create, update, and delete infrastructure
+objects, data resources cause Terraform only to _read_ objects. For brevity,
+managed resources are often referred to just as "resources" when the meaning
+is clear from context.
+
+## Data Source Arguments
+
+Each data resource is associated with a single data source, which determines
+the kind of object (or objects) it reads and what query constraint arguments
+are available.
+
+Each data source in turn belongs to a [provider](/terraform/language/providers),
+which is a plugin for Terraform that offers a collection of resource types and
+data sources that most often belong to a single cloud or on-premises
+infrastructure platform.
+
+Most of the items within the body of a `data` block are defined by and
+specific to the selected data source, and these arguments can make full
+use of [expressions](/terraform/language/expressions) and other dynamic
+Terraform language features.
+
+However, there are some "meta-arguments" that are defined by Terraform itself
+and apply across all data sources. These arguments often have additional
+restrictions on what language features can be used with them, and are described
+in more detail in the following sections.
+
+## Data Resource Behavior
+
+Terraform reads data resources during the planning phase when possible, but
+announces in the plan when it must defer reading resources until the apply
+phase to preserve the order of operations. Terraform defers reading data
+resources in the following situations:
+* At least one of the given arguments is a managed resource attribute or
+  other value that Terraform cannot predict until the apply step.
+* The data resource depends directly on a managed resource that itself has
+  planned changes in the current plan.
+* The data resource has
+  [custom conditions](#custom-condition-checks)
+  and it depends directly or indirectly on a managed resource that itself
+  has planned changes in the current plan.
+
+Refer to [Data Resource Dependencies](#data-resource-dependencies) for details
+on what it means for a data resource to depend on other objects. Any resulting
+attribute of such a data resource will be unknown during planning, so it cannot
+be used in situations where values must be fully known.
+
+## Local-only Data Sources
+
+While many data sources correspond to an infrastructure object type that
+is accessed via a remote network API, some specialized data sources operate
+only within Terraform itself, calculating some results and exposing them
+for use elsewhere.
+
+For example, local-only data sources exist for
+[rendering templates](https://registry.terraform.io/providers/hashicorp/template/latest/docs/data-sources/file),
+[reading local files](https://registry.terraform.io/providers/hashicorp/local/latest/docs/data-sources/file), and
+[rendering AWS IAM policies](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document).
+
+The behavior of local-only data sources is the same as all other data
+sources, but their result data exists only temporarily during a Terraform
+operation, and is re-calculated each time a new plan is created.
+
+## Data Resource Dependencies
+
+Data resources have the same dependency resolution behavior
+[as defined for managed resources](/terraform/language/resources/behavior#resource-dependencies).
+Setting the `depends_on` meta-argument within `data` blocks defers reading of
+the data source until after all changes to the dependencies have been applied.
+
+In order to ensure that data sources are accessing the most up to date
+information possible in a wide variety of use cases, arguments directly
+referencing managed resources are treated the same as if the resource was
+listed in `depends_on`. This behavior can be avoided when desired by indirectly
+referencing the managed resource values through a `local` value, unless the
+data resource itself has
+[custom conditions](#custom-condition-checks).
+
+~> **NOTE:** **In Terraform 0.12 and earlier**, due to the data resource behavior of deferring the read until the apply phase when depending on values that are not yet known, using `depends_on` with `data` resources will force the read to always be deferred to the apply phase, and therefore a configuration that uses `depends_on` with a `data` resource can never converge. Due to this behavior, we do not recommend using `depends_on` with data resources.
+
+## Custom Condition Checks
+
+You can use `precondition` and `postcondition` blocks to specify assumptions and guarantees about how the data source operates. The following examples creates a postcondition that checks whether the AMI has the correct tags.
+
+``` hcl
+data "aws_ami" "example" {
+  id = var.aws_ami_id
+
+  lifecycle {
+    # The AMI ID must refer to an existing AMI that has the tag "nomad-server".
+    postcondition {
+      condition     = self.tags["Component"] == "nomad-server"
+      error_message = "tags[\"Component\"] must be \"nomad-server\"."
+    }
+  }
+}
+```
+
+Custom conditions can help capture assumptions, helping future maintainers understand the configuration design and intent. They also return useful information about errors earlier and in context, helping consumers more easily diagnose issues in their configurations.
+
+Refer to [Custom Condition Checks](/terraform/language/expressions/custom-conditions#preconditions-and-postconditions) for more details.
+
+
+## Multiple Resource Instances
+
+Data resources support [`count`](/terraform/language/meta-arguments/count)
+and [`for_each`](/terraform/language/meta-arguments/for_each)
+meta-arguments as defined for managed resources, with the same syntax and behavior.
+
+As with managed resources, when `count` or `for_each` is present it is important to
+distinguish the resource itself from the multiple resource _instances_ it
+creates. Each instance will separately read from its data source with its
+own variant of the constraint arguments, producing an indexed result.
+
+## Selecting a Non-default Provider Configuration
+
+Data resources support [the `provider` meta-argument](/terraform/language/meta-arguments/resource-provider)
+as defined for managed resources, with the same syntax and behavior.
+
+## Lifecycle Customizations
+
+Data resources do not have any customization settings available
+for their lifecycle. However, the `lifecycle` block is reserved for future versions.
+
+## Example
+
+A data source configuration looks like the following:
+
+```hcl
+# Find the latest available AMI that is tagged with Component = web
+data "aws_ami" "web" {
+  filter {
+    name   = "state"
+    values = ["available"]
+  }
+
+  filter {
+    name   = "tag:Component"
+    values = ["web"]
+  }
+
+  most_recent = true
+}
+```
+
+## Description
+
+The `data` block creates a data instance of the given _type_ (first
+block label) and _name_ (second block label). The combination of the type
+and name must be unique.
+
+Within the block (the `{ }`) is configuration for the data instance. The
+configuration is dependent on the type; as with
+[resources](/terraform/language/resources), each provider on the
+[Terraform Registry](https://registry.terraform.io/browse/providers) has its own
+documentation for configuring and using the data types it provides.
+
+Each data instance will export one or more attributes, which can be
+used in other resources as reference expressions of the form
+`data.<TYPE>.<NAME>.<ATTRIBUTE>`. For example:
+
+```hcl
+resource "aws_instance" "web" {
+  ami           = data.aws_ami.web.id
+  instance_type = "t1.micro"
+}
+```
+
+## Meta-Arguments
+
+As data sources are essentially a read only subset of resources, they also
+support the same [meta-arguments](/terraform/language/resources/syntax#meta-arguments) of resources
+with the exception of the
+[`lifecycle` configuration block](/terraform/language/meta-arguments/lifecycle).
+
+### Non-Default Provider Configurations
+
+Similarly to [resources](/terraform/language/resources), when
+a module has multiple configurations for the same provider you can specify which
+configuration to use with the `provider` meta-argument:
+
+```hcl
+data "aws_ami" "web" {
+  provider = aws.west
+
+  # ...
+}
+```
+
+See
+[The Resource `provider` Meta-Argument](/terraform/language/meta-arguments/resource-provider)
+for more information.
+
+## Data Source Lifecycle
+
+If the arguments of a data instance contain no references to computed values,
+such as attributes of resources that have not yet been created, then the
+data instance will be read and its state updated during Terraform's "refresh"
+phase, which by default runs prior to creating a plan. This ensures that the
+retrieved data is available for use during planning and the diff will show
+the real values obtained.
+
+Data instance arguments may refer to computed values, in which case the
+attributes of the instance itself cannot be resolved until all of its
+arguments are defined. In this case, refreshing the data instance will be
+deferred until the "apply" phase, and all interpolations of the data instance
+attributes will show as "computed" in the plan since the values are not yet
+known.
diff --git a/v1.5.7/website/docs/language/expressions/conditionals.mdx b/v1.5.7/website/docs/language/expressions/conditionals.mdx
new file mode 100644
index 0000000..847216c
--- /dev/null
+++ b/v1.5.7/website/docs/language/expressions/conditionals.mdx
@@ -0,0 +1,80 @@
+---
+page_title: Conditional Expressions - Configuration Language
+description: >-
+  Conditional expressions select one of two values. You can use them to define
+  defaults to replace invalid values.
+---
+
+# Conditional Expressions
+
+A _conditional expression_ uses the value of a boolean expression to select one of
+two values.
+
+> **Hands-on:** Try the [Create Dynamic Expressions](/terraform/tutorials/configuration-language/expressions?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+## Syntax
+
+The syntax of a conditional expression is as follows:
+
+```hcl
+condition ? true_val : false_val
+```
+
+If `condition` is `true` then the result is `true_val`. If `condition` is
+`false` then the result is `false_val`.
+
+A common use of conditional expressions is to define defaults to replace
+invalid values:
+
+```
+var.a != "" ? var.a : "default-a"
+```
+
+If `var.a` is an empty string then the result is `"default-a"`, but otherwise
+it is the actual value of `var.a`.
+
+## Conditions
+
+The condition can be any expression that resolves to a boolean value. This will
+usually be an expression that uses the equality, comparison, or logical
+operators.
+
+### Custom Condition Checks
+
+You can create conditions that produce custom error messages for several types of objects in a configuration. For example, you can add a condition to an input variable that checks whether incoming image IDs are formatted properly.
+
+Custom conditions can help capture assumptions, helping future maintainers understand the configuration design and intent. They also return useful information about errors earlier and in context, helping consumers more easily diagnose issues in their configurations.
+
+Refer to [Custom Condition Checks](/terraform/language/expressions/custom-conditions#input-variable-validation) for details.
+
+## Result Types
+
+The two result values may be of any type, but they must both
+be of the _same_ type so that Terraform can determine what type the whole
+conditional expression will return without knowing the condition value.
+
+If the two result expressions don't produce the same type then Terraform will
+attempt to find a type that they can both convert to, and make those
+conversions automatically if so.
+
+For example, the following expression is valid and will always return a string,
+because in Terraform all numbers can convert automatically to a string using
+decimal digits:
+
+```hcl
+var.example ? 12 : "hello"
+```
+
+Relying on this automatic conversion behavior can be confusing for those who
+are not familiar with Terraform's conversion rules though, so we recommend
+being explicit using type conversion functions in any situation where there may
+be some uncertainty about the expected result type.
+
+The following example is contrived because it would be easier to write the
+constant `"12"` instead of the type conversion in this case, but shows how to
+use [`tostring`](/terraform/language/functions/tostring) to explicitly convert a number to
+a string.
+
+```hcl
+var.example ? tostring(12) : "hello"
+```
diff --git a/v1.5.7/website/docs/language/expressions/custom-conditions.mdx b/v1.5.7/website/docs/language/expressions/custom-conditions.mdx
new file mode 100644
index 0000000..89436c5
--- /dev/null
+++ b/v1.5.7/website/docs/language/expressions/custom-conditions.mdx
@@ -0,0 +1,414 @@
+---
+page_title: Custom Conditions - Configuration Language
+description: >-
+  Check custom requirements for variables, outputs, data sources, and resources and provide better error messages in context.
+---
+
+# Custom Conditions
+
+You can create conditions that produce custom error messages for several types of objects in a configuration. For example, you can add a condition to an input variable that checks whether incoming image IDs are formatted properly. Custom conditions can capture assumptions, helping future maintainers understand the configuration design and intent. They also return useful information about errors earlier and in context, helping consumers more easily diagnose issues in their configurations.
+
+> **Hands On:** Try the [Validate Infrastructure Using Checks](/terraform/tutorials/configuration-language/checks) tutorial to learn how to use `check` blocks. Try the [Validate Modules with Custom Conditions](/terraform/tutorials/configuration-language/custom-conditions) tutorial to learn how to use other custom conditions.
+
+This page explains the following:
+  - Creating checks with [assertions](#checks-with-assertions) to verify your infrastructure as a whole (Terraform v1.5.0 and later)
+  - Creating [validation conditions](#input-variable-validation) for input variables (Terraform v0.13.0 and later)
+  - Creating [preconditions and postconditions](#preconditions-and-postconditions) for resources, data sources, and outputs (Terraform v1.2.0 and later)
+  - Writing effective [condition expressions](#condition-expressions) and [error messages](#error-messages)
+  - When Terraform [evaluates custom conditions](#conditions-checked-only-during-apply) during the plan and apply cycle
+
+## Selecting a Custom Condition for your use case
+
+Terraform's different custom conditions are best suited to various situations. Use the following broad guidelines to select the best custom condition for your use case:
+1. [Check blocks with assertions](#checks-with-assertions) validate your infrastructure as a whole. Additionally, check blocks do not prevent or block the overall execution of Terraform operations.
+1. [Validation conditions](#input-variable-validation) or [output postconditions](#preconditions-and-postconditions) can ensure your configuration's inputs and outputs meet specific requirements.
+1. Resource [preconditions and postconditions](#preconditions-and-postconditions) can validate that Terraform produces your configuration with predictable results.
+
+For more information on when to use certain custom conditions, see [Choosing Between Preconditions and Postconditions](#choosing-between-preconditions-and-postconditions) and [Choosing Checks or Other Custom Conditions](/terraform/language/checks#choosing-checks-or-other-custom-conditions).
+
+
+## Input Variable Validation
+
+-> **Note:** Input variable validation is available in Terraform v0.13.0 and later.
+
+Add one or more `validation` blocks within the `variable` block to specify custom conditions. Each validation requires a [`condition` argument](#condition-expressions), an expression that must use the value of the variable to return `true` if the value is valid, or `false` if it is invalid. The expression can refer only to the containing variable and must not produce errors.
+
+If the condition evaluates to `false`, Terraform produces an [error message](#error-messages) that includes the result of the `error_message` expression. If you declare multiple validations, Terraform returns error messages for all failed conditions.
+
+The following example checks whether the AMI ID has valid syntax.
+
+```hcl
+variable "image_id" {
+  type        = string
+  description = "The id of the machine image (AMI) to use for the server."
+
+  validation {
+    condition     = length(var.image_id) > 4 && substr(var.image_id, 0, 4) == "ami-"
+    error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
+  }
+}
+```
+
+If the failure of an expression determines the validation decision, use the [`can` function](/terraform/language/functions/can) as demonstrated in the following example.
+
+```hcl
+variable "image_id" {
+  type        = string
+  description = "The id of the machine image (AMI) to use for the server."
+
+  validation {
+    # regex(...) fails if it cannot find a match
+    condition     = can(regex("^ami-", var.image_id))
+    error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
+  }
+}
+```
+
+
+## Preconditions and Postconditions
+
+-> **Note:** Preconditions and postconditions are available in Terraform v1.2.0 and later.
+
+Use `precondition` and `postcondition` blocks to create custom rules for resources, data sources, and outputs.
+
+Terraform checks a precondition _before_ evaluating the object it is associated with and checks a postcondition _after_ evaluating the object. Terraform evaluates custom conditions as early as possible, but must defer conditions that depend on unknown values until the apply phase. Refer to [Conditions Checked Only During Apply](#conditions-checked-only-during-apply) for more details.
+
+### Usage
+
+Each precondition and postcondition requires a [`condition` argument](#condition-expressions). This is an expression that must return `true` if the conditition is fufilled or `false` if it is invalid. The expression can refer to any other objects in the same module, as long as the references do not create cyclic dependencies. Resource postconditions can also use the [`self` object](#self-object) to refer to attributes of each instance of the resource where they are configured.
+
+If the condition evaluates to `false`, Terraform will produce an [error message](#error-messages) that includes the result of the `error_message` expression. If you declare multiple preconditions or postconditions, Terraform returns error messages for all failed conditions.
+
+The following example uses a postcondition to detect if the caller accidentally provided an AMI intended for the wrong system component.
+
+```hcl
+data "aws_ami" "example" {
+  id = var.aws_ami_id
+
+  lifecycle {
+    # The AMI ID must refer to an existing AMI that has the tag "nomad-server".
+    postcondition {
+      condition     = self.tags["Component"] == "nomad-server"
+      error_message = "tags[\"Component\"] must be \"nomad-server\"."
+    }
+  }
+}
+```
+
+#### Resources and Data Sources
+
+The `lifecycle` block inside a `resource` or `data` block can include both `precondition` and `postcondition` blocks.
+
+- Terraform evaluates `precondition` blocks after evaluating existing `count` and `for_each` arguments. This lets Terraform evaluate the precondition separately for each instance and then make `each.key`, `count.index`, etc. available to those conditions. Terraform also evaluates preconditions before evaluating the resource's configuration arguments. Preconditions can take precedence over argument evaluation errors.
+- Terraform evaluates `postcondition` blocks after planning and applying changes to a managed resource, or after reading from a data source. Postcondition failures prevent changes to other resources that depend on the failing resource.
+
+In most cases, we do not recommend including both a `data` block and a `resource` block that both represent the same object in the same configuration. Doing so can prevent Terraform from understanding that the `data` block result can be affected by changes in the `resource` block. However, when you need to check a result of a `resource` block that the resource itself does not directly export, you can use a `data` block to check that object safely as long as you place the check as a direct `postcondition` of the `data` block. This tells Terraform that the `data` block is serving as a check of an object defined elsewhere, allowing Terraform to perform actions in the correct order.
+
+#### Outputs
+
+An `output` block can include a `precondition`  block.
+
+Preconditions can serve a symmetrical purpose to input variable `validation` blocks. Whereas input variable validation checks assumptions the module makes about its inputs, preconditions check guarantees that the module makes about its outputs. You can use preconditions to prevent Terraform from saving an invalid new output value in the state. You can also use them to preserve a valid output value from the previous apply, if applicable.
+
+Terraform evaluates output value preconditions before evaluating the `value` expression to finalize the result. Preconditions can take precedence over potential errors in the `value` expression.
+
+### Continuous Validation in Terraform Cloud
+
+Terraform Cloud can automatically check whether the preconditions and postconditions in a workspace’s configuration continue to pass after Terraform provisions the infrastructure. For example, you can write a `postcondition` to check whether an API gateway certificate is valid. Continuous validation alerts you when the condition fails, so you can update the certificate and avoid errors the next time you want to update your infrastructure. Refer to [Continuous Validation](/terraform/cloud-docs/workspaces/health#continuous-validation) in the Terraform Cloud documentation for details.
+
+### Examples
+
+The following example shows use cases for preconditions and postconditions. The preconditions and postconditions declare the following assumptions and guarantees.
+
+- **The AMI ID must refer to an AMI that contains an operating system for the
+`x86_64` architecture.** The precondition would detect if the caller accidentally built an AMI for a different architecture, which may not be able to run the software this virtual machine is intended to host.
+
+- **The EC2 instance must be allocated a public DNS hostname.** In Amazon Web Services, EC2 instances are assigned public DNS hostnames only if they belong to a virtual network configured in a certain way. The postcondition would detect if the selected virtual network is not configured correctly, prompting the user to debug the network settings.
+
+- **The EC2 instance will have an encrypted root volume.** The precondition ensures that the root volume is encrypted, even though the software running in this EC2 instance would probably still operate as expected on an unencrypted volume. This lets Terraform produce an error immediately, before any other components rely on the new EC2 instance.
+
+```hcl
+
+data "aws_ami" "example" {
+  owners = ["amazon"]
+
+  filter {
+    name   = "image-id"
+    values = ["ami-abc123"]
+  }
+}
+
+resource "aws_instance" "example" {
+  instance_type = "t3.micro"
+  ami           = data.aws_ami.example.id
+
+  lifecycle {
+    # The AMI ID must refer to an AMI that contains an operating system
+    # for the `x86_64` architecture.
+    precondition {
+      condition     = data.aws_ami.example.architecture == "x86_64"
+      error_message = "The selected AMI must be for the x86_64 architecture."
+    }
+
+    # The EC2 instance must be allocated a public DNS hostname.
+    postcondition {
+      condition     = self.public_dns != ""
+      error_message = "EC2 instance must be in a VPC that has public DNS hostnames enabled."
+    }
+  }
+}
+
+data "aws_ebs_volume" "example" {
+  # Use data resources that refer to other resources to
+  # load extra data that isn't directly exported by a resource.
+  #
+  # Read the details about the root storage volume for the EC2 instance
+  # declared by aws_instance.example, using the exported ID.
+
+  filter {
+    name = "volume-id"
+    values = [aws_instance.example.root_block_device.volume_id]
+  }
+
+  # Whenever a data resource is verifying the result of a managed resource
+  # declared in the same configuration, you MUST write the checks as
+  # postconditions of the data resource. This ensures Terraform will wait
+  # to read the data resource until after any changes to the managed resource
+  # have completed.
+  lifecycle {
+    # The EC2 instance will have an encrypted root volume.
+    postcondition {
+      condition     = self.encrypted
+      error_message = "The server's root volume is not encrypted."
+    }
+  }
+}
+
+output "api_base_url" {
+  value = "https://${aws_instance.example.private_dns}:8433/"
+}
+```
+
+### Choosing Between Preconditions and Postconditions
+
+You can often implement a validation check as either a postcondition of the resource producing the data or as a precondition of a resource or output value using the data. To decide which is most appropriate, consider whether the check is representing either an assumption or a guarantee.
+
+#### Use Preconditions for Assumptions
+
+An assumption is a condition that must be true in order for the configuration of a particular resource to be usable. For example, an `aws_instance` configuration can have the assumption that the given AMI will always be configured for the `x86_64` CPU architecture.
+
+We recommend using preconditions for assumptions, so that future maintainers can find them close to the other expressions that rely on that condition. This lets them understand more about what that resource is intended to allow.
+
+#### Use Postconditions for Guarantees
+
+A guarantee is a characteristic or behavior of an object that the rest of the configuration should be able to rely on. For example, an `aws_instance` configuration can have the guarantee that an EC2 instance will be running in a network that assigns it a private DNS record.
+
+We recommend using postconditions for guarantees, so that future maintainers can find them close to the resource configuration that is responsible for implementing those guarantees. This lets them more easily determine which behaviors they should preserve when changing the configuration.
+
+#### Additional Decision Factors
+
+You should also consider the following questions when creating preconditions and postconditions.
+
+- Which resource or output value would be most helpful to report in the error message? Terraform will always report errors in the location where the condition was declared.
+- Which approach is more convenient? If a particular resource has many dependencies that all make an assumption about that resource, it can be pragmatic to declare that once as a post-condition of the resource, rather than declaring it many times as preconditions on each of the dependencies.
+- Is it helpful to declare the same or similar conditions as both preconditions and postconditions? This can be useful if the postcondition is in a different module than the precondition because it lets the modules verify one another as they evolve independently.
+
+## Checks with Assertions
+
+-> **Note:** Check blocks and their assertions are only available in Terraform v1.5.0 and later.
+
+[Check blocks](/terraform/language/checks) can validate your infrastructure outside the usual resource lifecycle. You can add custom conditions via `assert` blocks, which execute at the end of the plan and apply stages and produce warnings to notify you of problems within your infrastructure.
+
+You can add one or more `assert` blocks within a `check` block to verify custom conditions. Each assertion requires a [`condition` argument](#condition-expressions), a boolean expression that should return `true` if the intended assumption or guarantee is fulfilled or `false` if it does not. Your `condition` expression can refer to any resource, data source, or variable available to the surrounding `check` block.
+
+The following example uses a check block with an assertion to verify the Terraform website is healthy.
+
+```hcl
+check "health_check" {
+  data "http" "terraform_io" {
+    url = "https://www.terraform.io"
+  }
+
+  assert {
+    condition = data.http.terraform_io.status_code == 200
+    error_message = "${data.http.terraform_io.url} returned an unhealthy status code"
+  }
+}
+```
+
+If the condition evaluates to `false`, Terraform produces an [error message](#error-messages) that includes the result of the `error_message` expression. If you declare multiple assertions, Terraform returns error messages for all failed conditions.
+
+## Condition Expressions
+
+Check assertions, input variable validation, preconditions, and postconditions all require a `condition` argument. This is a boolean expression that should return `true` if the intended assumption or guarantee is fulfilled or `false` if it does not.
+
+You can use any of Terraform's built-in functions or language operators
+in a condition as long as the expression is valid and returns a boolean result. The following language features are particularly useful when writing condition expressions.
+
+### Logical Operators
+
+Use the logical operators `&&` (AND), `||` (OR), and `!` (NOT) to combine multiple conditions together.
+
+```hcl
+  condition = var.name != "" && lower(var.name) == var.name
+```
+
+You can also use arithmetic operators (e.g. `a + b`), equality operators (eg., `a == b`) and comparison operators (e.g., `a < b`). Refer to [Arithmetic and Logical Operators](/terraform/language/expressions/operators) for details.
+
+### `contains` Function
+
+Use the [`contains` function](/terraform/language/functions/contains) to test whether a given value is one of a set of predefined valid values.
+
+```hcl
+  condition = contains(["STAGE", "PROD"], var.environment)
+```
+
+### `length` Function
+
+Use the [`length` function](/terraform/language/functions/length) to test a collection's length and require a non-empty list or map.
+
+```hcl
+  condition = length(var.items) != 0
+```
+This is a better approach than directly comparing with another collection using `==` or `!=`. This is because the comparison operators can only return `true` if both operands have exactly the same type, which is often ambiguous for empty collections.
+
+### `for` Expressions
+
+Use [`for` expressions](/terraform/language/expressions/for) in conjunction with the functions `alltrue` and `anytrue` to test whether a condition holds for all or for any elements of a collection.
+
+```hcl
+  condition = alltrue([
+    for v in var.instances : contains(["t2.micro", "m3.medium"], v.type)
+  ])
+```
+
+### `can` Function
+
+Use the [`can` function](/terraform/language/functions/can) to concisely use the validity of an expression as a condition. It returns `true` if its given expression evaluates successfully and `false` if it returns any error, so you can use various other functions that typically return errors as a part of your condition expressions.
+
+For example, you can use `can` with `regex` to test if a string matches a particular pattern because `regex` returns an error when given a non-matching string.
+
+```hcl
+  condition = can(regex("^[a-z]+$", var.name))
+```
+
+You can also use `can` with the type conversion functions to test whether a value is convertible to a type or type constraint.
+
+```hcl
+  # This remote output value must have a value that can
+  # be used as a string, which includes strings themselves
+  # but also allows numbers and boolean values.
+  condition = can(tostring(data.terraform_remote_state.example.outputs["name"]))
+```
+
+```hcl
+  # This remote output value must be convertible to a list
+  # type of with element type.
+  condition = can(tolist(data.terraform_remote_state.example.outputs["items"]))
+```
+
+You can also use `can` with attribute access or index operators to test whether a collection or structural value has a particular element or index.
+
+```hcl
+  # var.example must have an attribute named "foo"
+  condition = can(var.example.foo)
+```
+
+```hcl
+  # var.example must be a sequence with at least one element
+  condition = can(var.example[0])
+  # (although it would typically be clearer to write this as a
+  # test like length(var.example) > 0 to better represent the
+  # intent of the condition.)
+```
+
+### `self` Object
+
+Use the `self` object in postcondition blocks to refer to attributes of the instance under evaluation.
+
+```hcl
+resource "aws_instance" "example" {
+  instance_type = "t2.micro"
+  ami           = "ami-abc123"
+
+  lifecycle {
+    postcondition {
+      condition     = self.instance_state == "running"
+      error_message = "EC2 instance must be running."
+    }
+  }
+}
+```
+
+### `each` and `count` Objects
+
+In blocks where [`for_each`](/terraform/language/meta-arguments/for_each) or [`count`](/terraform/language/meta-arguments/count)  are set, use `each` and `count` objects to refer to other resources that are expanded in a chain.
+
+```hcl
+variable "vpc_cidrs" {
+  type = set(string)
+}
+
+data "aws_vpc" "example" {
+  for_each = var.vpc_cidrs
+
+  filter {
+    name   = "cidr"
+    values = [each.key]
+  }
+}
+
+resource "aws_internet_gateway" "example" {
+  for_each = data.aws_vpc.example
+  vpc_id = each.value.id
+
+  lifecycle {
+    precondition {
+      condition     = data.aws_vpc.example[each.key].state == "available"
+      error_message = "VPC ${each.key} must be available."
+    }
+  }
+}
+```
+
+## Error Messages
+
+Input variable validations, preconditions, and postconditions all must include the `error_message` argument. This contains the text that Terraform will include as part of error messages when it detects an unmet condition.
+
+```
+Error: Resource postcondition failed
+
+  with data.aws_ami.example,
+  on ec2.tf line 19, in data "aws_ami" "example":
+  72:       condition     = self.tags["Component"] == "nomad-server"
+    |----------------
+    | self.tags["Component"] is "consul-server"
+
+The selected AMI must be tagged with the Component value "nomad-server".
+```
+
+The `error_message` argument can be any expression that evaluates to a string.
+This includes literal strings, heredocs, and template expressions. You can use the [`format` function](/terraform/language/functions/format) to convert items of `null`, `list`, or `map` types into a formatted string. Multi-line
+error messages are supported, and lines with leading whitespace will not be
+word wrapped.
+
+We recommend writing error messages as one or more full sentences in a
+style similar to Terraform's own error messages. Terraform will show the
+message alongside the name of the resource that detected the problem and any
+external values included in the condition expression.
+
+## Conditions Checked Only During Apply
+
+Terraform evaluates custom conditions as early as possible.
+
+Input variable validations can only refer to the variable value, so Terraform always evaluates them immediately. Check assertions, preconditions, and postconditions depend on Terraform evaluating whether the value(s) associated with the condition are known before or after applying the configuration.
+
+- **Known before apply:** Terraform checks the condition during the planning phase. For example, Terraform can know the value of an image ID during planning as long as it is not generated from another resource.
+- **Known after apply:** Terraform delays checking that condition until the apply phase. For example, AWS only assigns the root volume ID when it starts an EC2 instance, so Terraform cannot know this value until apply.
+
+During the apply phase, a failed _precondition_
+will prevent Terraform from implementing planned actions for the associated resource. However, a failed _postcondition_ will halt processing after Terraform has already implemented these actions. The failed postcondition prevents any further downstream actions that rely on the resource, but does not undo the actions Terraform has already taken.
+
+Terraform typically has less information during the initial creation of a
+full configuration than when applying subsequent changes. Therefore, Terraform may check conditions during apply for initial creation and then check them during planning for subsequent updates.
+
diff --git a/v1.5.7/website/docs/language/expressions/dynamic-blocks.mdx b/v1.5.7/website/docs/language/expressions/dynamic-blocks.mdx
new file mode 100644
index 0000000..dbcc3ab
--- /dev/null
+++ b/v1.5.7/website/docs/language/expressions/dynamic-blocks.mdx
@@ -0,0 +1,155 @@
+---
+page_title: Dynamic Blocks - Configuration Language
+description: >-
+  Dynamic blocks automatically construct multi-level, nested block structures.
+  Learn to configure dynamic blocks and understand their behavior.
+---
+
+# `dynamic` Blocks
+
+Within top-level block constructs like resources, expressions can usually be
+used only when assigning a value to an argument using the `name = expression`
+form. This covers many uses, but some resource types include repeatable _nested
+blocks_ in their arguments, which typically represent separate objects that
+are related to (or embedded within) the containing object:
+
+```hcl
+resource "aws_elastic_beanstalk_environment" "tfenvtest" {
+  name = "tf-test-name" # can use expressions here
+
+  setting {
+    # but the "setting" block is always a literal block
+  }
+}
+```
+
+You can dynamically construct repeatable nested blocks like `setting` using a
+special `dynamic` block type, which is supported inside `resource`, `data`,
+`provider`, and `provisioner` blocks:
+
+```hcl
+resource "aws_elastic_beanstalk_environment" "tfenvtest" {
+  name                = "tf-test-name"
+  application         = "${aws_elastic_beanstalk_application.tftest.name}"
+  solution_stack_name = "64bit Amazon Linux 2018.03 v2.11.4 running Go 1.12.6"
+
+  dynamic "setting" {
+    for_each = var.settings
+    content {
+      namespace = setting.value["namespace"]
+      name = setting.value["name"]
+      value = setting.value["value"]
+    }
+  }
+}
+```
+
+A `dynamic` block acts much like a [`for` expression](/terraform/language/expressions/for), but produces
+nested blocks instead of a complex typed value. It iterates over a given
+complex value, and generates a nested block for each element of that complex
+value.
+
+- The label of the dynamic block (`"setting"` in the example above) specifies
+  what kind of nested block to generate.
+- The `for_each` argument provides the complex value to iterate over.
+- The `iterator` argument (optional) sets the name of a temporary variable
+  that represents the current element of the complex value. If omitted, the name
+  of the variable defaults to the label of the `dynamic` block (`"setting"` in
+  the example above).
+- The `labels` argument (optional) is a list of strings that specifies the block
+  labels, in order, to use for each generated block. You can use the temporary
+  iterator variable in this value.
+- The nested `content` block defines the body of each generated block. You can
+  use the temporary iterator variable inside this block.
+
+Since the `for_each` argument accepts any collection or structural value,
+you can use a `for` expression or splat expression to transform an existing
+collection.
+
+The iterator object (`setting` in the example above) has two attributes:
+
+- `key` is the map key or list element index for the current element. If the
+  `for_each` expression produces a _set_ value then `key` is identical to
+  `value` and should not be used.
+- `value` is the value of the current element.
+
+A `dynamic` block can only generate arguments that belong to the resource type,
+data source, provider or provisioner being configured. It is _not_ possible
+to generate meta-argument blocks such as `lifecycle` and `provisioner`
+blocks, since Terraform must process these before it is safe to evaluate
+expressions.
+
+The `for_each` value must be a collection with one element per desired
+nested block. If you need to declare resource instances based on a nested
+data structure or combinations of elements from multiple data structures you
+can use Terraform expressions and functions to derive a suitable value.
+For some common examples of such situations, see the
+[`flatten`](/terraform/language/functions/flatten)
+and
+[`setproduct`](/terraform/language/functions/setproduct)
+functions.
+
+## Multi-level Nested Block Structures
+
+Some providers define resource types that include multiple levels of blocks
+nested inside one another. You can generate these nested structures dynamically
+when necessary by nesting `dynamic` blocks in the `content` portion of other
+`dynamic` blocks.
+
+For example, a module might accept a complex data structure like the following:
+
+```hcl
+variable "load_balancer_origin_groups" {
+  type = map(object({
+    origins = set(object({
+      hostname = string
+    }))
+  }))
+}
+```
+
+If you were defining a resource whose type expects a block for each origin
+group and then nested blocks for each origin within a group, you could ask
+Terraform to generate that dynamically using the following nested `dynamic`
+blocks:
+
+```hcl
+  dynamic "origin_group" {
+    for_each = var.load_balancer_origin_groups
+    content {
+      name = origin_group.key
+
+      dynamic "origin" {
+        for_each = origin_group.value.origins
+        content {
+          hostname = origin.value.hostname
+        }
+      }
+    }
+  }
+```
+
+When using nested `dynamic` blocks it's particularly important to pay attention
+to the iterator symbol for each block. In the above example,
+`origin_group.value` refers to the current element of the outer block, while
+`origin.value` refers to the current element of the inner block.
+
+If a particular resource type defines nested blocks that have the same type
+name as one of their parents, you can use the `iterator` argument in each of
+`dynamic` blocks to choose a different iterator symbol that makes the two
+easier to distinguish.
+
+## Best Practices for `dynamic` Blocks
+
+Overuse of `dynamic` blocks can make configuration hard to read and maintain, so
+we recommend using them only when you need to hide details in order to build a
+clean user interface for a re-usable module. Always write nested blocks out
+literally where possible.
+
+If you find yourself defining most or all of a `resource` block's arguments and
+nested blocks using directly-corresponding attributes from an input variable
+then that might suggest that your module is not creating a useful abstraction.
+It may be better for the calling module to define the resource itself then
+pass information about it into your module. For more information on this design
+tradeoff, see [When to Write a Module](/terraform/language/modules/develop#when-to-write-a-module)
+and [Module Composition](/terraform/language/modules/develop/composition).
diff --git a/v1.5.7/website/docs/language/expressions/for.mdx b/v1.5.7/website/docs/language/expressions/for.mdx
new file mode 100644
index 0000000..334b3a8
--- /dev/null
+++ b/v1.5.7/website/docs/language/expressions/for.mdx
@@ -0,0 +1,207 @@
+---
+page_title: For Expressions - Configuration Language
+description: >-
+  For expressions transform complex input values into complex output values.
+  Learn how to filter inputs and how to group results.
+---
+
+# `for` Expressions
+
+A _`for` expression_ creates a complex type value by transforming
+another complex type value. Each element in the input value
+can correspond to either one or zero values in the result, and an arbitrary
+expression can be used to transform each input element into an output element.
+
+For example, if `var.list` were a list of strings, then the following expression
+would produce a tuple of strings with all-uppercase letters:
+
+```hcl
+[for s in var.list : upper(s)]
+```
+
+This `for` expression iterates over each element of `var.list`, and then
+evaluates the expression `upper(s)` with `s` set to each respective element.
+It then builds a new tuple value with all of the results of executing that
+expression in the same order.
+
+## Input Types
+
+A `for` expression's input (given after the `in` keyword) can be a list,
+a set, a tuple, a map, or an object.
+
+The above example showed a `for` expression with only a single temporary
+symbol `s`, but a `for` expression can optionally declare a pair of temporary
+symbols in order to use the key or index of each item too:
+
+```hcl
+[for k, v in var.map : length(k) + length(v)]
+```
+
+For a map or object type, like above, the `k` symbol refers to the key or
+attribute name of the current element. You can also use the two-symbol form
+with lists and tuples, in which case the additional symbol is the index
+of each element starting from zero, which conventionally has the symbol name
+`i` or `idx` unless it's helpful to choose a more specific name:
+
+```hcl
+[for i, v in var.list : "${i} is ${v}"]
+```
+
+The index or key symbol is always optional. If you specify only a single
+symbol after the `for` keyword then that symbol will always represent the
+_value_ of each element of the input collection.
+
+## Result Types
+
+The type of brackets around the `for` expression decide what type of result
+it produces.
+
+The above example uses `[` and `]`, which produces a tuple. If you use `{` and
+`}` instead, the result is an object and you must provide two result
+expressions that are separated by the `=>` symbol:
+
+```hcl
+{for s in var.list : s => upper(s)}
+```
+
+This expression produces an object whose attributes are the original elements
+from `var.list` and their corresponding values are the uppercase versions.
+For example, the resulting value might be as follows:
+
+```hcl
+{
+  foo = "FOO"
+  bar = "BAR"
+  baz = "BAZ"
+}
+```
+
+A `for` expression alone can only produce either an object value or a tuple
+value, but Terraform's automatic type conversion rules mean that you can
+typically use the results in locations where lists, maps, and sets are expected.
+
+## Filtering Elements
+
+A `for` expression can also include an optional `if` clause to filter elements
+from the source collection, producing a value with fewer elements than
+the source value:
+
+```
+[for s in var.list : upper(s) if s != ""]
+```
+
+One common reason for filtering collections in `for` expressions is to split
+a single source collection into two separate collections based on some
+criteria. For example, if the input `var.users` is a map of objects where the
+objects each have an attribute `is_admin` then you may wish to produce separate
+maps with admin vs non-admin objects:
+
+```hcl
+variable "users" {
+  type = map(object({
+    is_admin = bool
+  }))
+}
+
+locals {
+  admin_users = {
+    for name, user in var.users : name => user
+    if user.is_admin
+  }
+  regular_users = {
+    for name, user in var.users : name => user
+    if !user.is_admin
+  }
+}
+```
+
+## Element Ordering
+
+Because `for` expressions can convert from unordered types (maps, objects, sets)
+to ordered types (lists, tuples), Terraform must choose an implied ordering
+for the elements of an unordered collection.
+
+For maps and objects, Terraform sorts the elements by key or attribute name,
+using lexical sorting.
+
+For sets of strings, Terraform sorts the elements by their value, using
+lexical sorting.
+
+For sets of other types, Terraform uses an arbitrary ordering that may change in future versions. We recommend converting the expression result into a set to make it clear elsewhere in the configuration that the result is unordered. You can use [the `toset` function](/terraform/language/functions/toset)
+to concisely convert a `for` expression result to be of a set type.
+
+```hcl
+toset([for e in var.set : e.example])
+```
+
+## Grouping Results
+
+If the result type is an object (using `{` and `}` delimiters) then normally
+the given key expression must be unique across all elements in the result,
+or Terraform will return an error.
+
+Sometimes the resulting keys are _not_ unique, and so to support that situation
+Terraform supports a special _grouping mode_ which changes the result to support
+multiple elements per key.
+
+To activate grouping mode, add the symbol `...` after the value expression.
+For example:
+
+```hcl
+variable "users" {
+  type = map(object({
+    role = string
+  }))
+}
+
+locals {
+  users_by_role = {
+    for name, user in var.users : user.role => name...
+  }
+}
+```
+
+The above represents a situation where a module expects a map describing
+various users who each have a single "role", where the map keys are usernames.
+The usernames are guaranteed unique because they are map keys in the input,
+but many users may all share a single role name.
+
+The `local.users_by_role` expression inverts the input map so that the keys
+are the role names and the values are usernames, but the expression is in
+grouping mode (due to the `...` after `name`) and so the result will be a
+map of lists of strings, such as the following:
+
+```hcl
+{
+  "admin": [
+    "ps",
+  ],
+  "maintainer": [
+    "am",
+    "jb",
+    "kl",
+    "ma",
+  ],
+  "viewer": [
+    "st",
+    "zq",
+  ],
+}
+```
+
+Due to [the element ordering rules](#element-ordering), Terraform will sort
+the users lexically by username as part of evaluating the `for` expression,
+and so the usernames associated with each role will be lexically sorted
+after grouping.
+
+## Repeated Configuration Blocks
+
+The `for` expressions mechanism is for constructing collection values from
+other collection values within expressions, which you can then assign to
+individual resource arguments that expect complex values.
+
+Some resource types also define _nested block types_, which typically represent
+separate objects that belong to the containing resource in some way. You can't
+dynamically generate nested blocks using `for` expressions, but you _can_
+generate nested blocks for a resource dynamically using
+[`dynamic` blocks](/terraform/language/expressions/dynamic-blocks).
diff --git a/v1.5.7/website/docs/language/expressions/function-calls.mdx b/v1.5.7/website/docs/language/expressions/function-calls.mdx
new file mode 100644
index 0000000..b12f667
--- /dev/null
+++ b/v1.5.7/website/docs/language/expressions/function-calls.mdx
@@ -0,0 +1,114 @@
+---
+page_title: Function Calls - Configuration Language
+description: >-
+  Functions transform and combine values. Learn about Terraform's built-in
+  functions.
+---
+
+# Function Calls
+
+> **Hands-on:** Try the [Perform Dynamic Operations with Functions](/terraform/tutorials/configuration-language/functions?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+The Terraform language has a number of
+[built-in functions](/terraform/language/functions) that can be used
+in expressions to transform and combine values. These
+are similar to the operators but all follow a common syntax:
+
+```hcl
+<FUNCTION NAME>(<ARGUMENT 1>, <ARGUMENT 2>)
+```
+
+The function name specifies which function to call. Each defined function
+expects a specific number of arguments with specific value types, and returns a
+specific value type as a result.
+
+Some functions take an arbitrary number of arguments. For example, the `min`
+function takes any amount of number arguments and returns the one that is
+numerically smallest:
+
+```hcl
+min(55, 3453, 2)
+```
+
+A function call expression evaluates to the function's return value.
+
+## Available Functions
+
+For a full list of available functions, see
+[the function reference](/terraform/language/functions).
+
+## Expanding Function Arguments
+
+If the arguments to pass to a function are available in a list or tuple value,
+that value can be _expanded_ into separate arguments. Provide the list value as
+an argument and follow it with the `...` symbol:
+
+```hcl
+min([55, 2453, 2]...)
+```
+
+The expansion symbol is three periods (`...`), not a Unicode ellipsis character
+(`…`). Expansion is a special syntax that is only available in function calls.
+
+## Using Sensitive Data as Function Arguments
+
+When using sensitive data, such as [an input variable](/terraform/language/values/variables#suppressing-values-in-cli-output)
+or [an output defined](/terraform/language/values/outputs#sensitive-suppressing-values-in-cli-output) as sensitive
+as function arguments, the result of the function call will be marked as sensitive.
+
+This is a conservative behavior that is true irrespective of the function being
+called. For example, passing an object containing a sensitive input variable to
+the `keys()` function will result in a list that is sensitive:
+
+```shell
+> local.baz
+{
+  "a" = (sensitive value)
+  "b" = "dog"
+}
+> keys(local.baz)
+(sensitive value)
+```
+
+## When Terraform Calls Functions
+
+Most of Terraform's built-in functions are, in programming language terms,
+[pure functions](https://en.wikipedia.org/wiki/Pure_function). This means that
+their result is based only on their arguments and so it doesn't make any
+practical difference when Terraform would call them.
+
+However, a small subset of functions interact with outside state and so for
+those it can be helpful to know when Terraform will call them in relation to
+other events that occur in a Terraform run.
+
+The small set of special functions includes
+[`file`](/terraform/language/functions/file),
+[`templatefile`](/terraform/language/functions/templatefile),
+[`timestamp`](/terraform/language/functions/timestamp),
+and [`uuid`](/terraform/language/functions/uuid).
+If you are not working with these functions then you don't need
+to read this section, although the information here may still be interesting
+background information.
+
+The `file` and `templatefile` functions are intended for reading files that
+are included as a static part of the configuration and so Terraform will
+execute these functions as part of initial configuration validation, before
+taking any other actions with the configuration. That means you cannot use
+either function to read files that your configuration might generate
+dynamically on disk as part of the plan or apply steps.
+
+The `timestamp` function returns a representation of the current system time
+at the point when Terraform calls it, and the `uuid` function returns a random
+result which differs on each call. Without any special behavior, these would
+both cause the final configuration during the apply step not to match the
+actions shown in the plan, which violates the Terraform execution model.
+
+For that reason, Terraform arranges for both of those functions to produce
+[unknown value](/terraform/language/expressions/references#values-not-yet-known) results during the
+plan step, with the real result being decided only during the apply step.
+For `timestamp` in particular, this means that the recorded time will be
+the instant when Terraform began applying the change, rather than when
+Terraform _planned_ the change.
+
+For more details on the behavior of these functions, refer to their own
+documentation pages.
diff --git a/v1.5.7/website/docs/language/expressions/index.mdx b/v1.5.7/website/docs/language/expressions/index.mdx
new file mode 100644
index 0000000..8817589
--- /dev/null
+++ b/v1.5.7/website/docs/language/expressions/index.mdx
@@ -0,0 +1,71 @@
+---
+page_title: Expressions - Configuration Language
+description: >-
+  An overview of expressions to reference or compute values in Terraform
+  configurations, including types, operators, and functions.
+---
+
+# Expressions
+
+> **Hands-on:** Try the [Create Dynamic Expressions](/terraform/tutorials/configuration-language/expressions?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+_Expressions_ refer to or compute values within a configuration.
+The simplest expressions are just literal values, like `"hello"` or `5`,
+but the Terraform language also allows more complex expressions such as
+references to data exported by resources, arithmetic, conditional evaluation,
+and a number of built-in functions.
+
+Expressions can be used in a number of places in the Terraform language,
+but some contexts limit which expression constructs are allowed,
+such as requiring a literal value of a particular type or forbidding
+[references to resource attributes](/terraform/language/expressions/references#references-to-resource-attributes).
+Each language feature's documentation describes any restrictions it places on
+expressions.
+
+You can experiment with the behavior of Terraform's expressions from
+the Terraform expression console, by running
+[the `terraform console` command](/terraform/cli/commands/console).
+
+The other pages in this section describe the features of Terraform's
+expression syntax.
+
+- [Types and Values](/terraform/language/expressions/types)
+  documents the data types that Terraform expressions can resolve to, and the
+  literal syntaxes for values of those types.
+
+- [Strings and Templates](/terraform/language/expressions/strings)
+  documents the syntaxes for string literals, including interpolation sequences
+  and template directives.
+
+- [References to Values](/terraform/language/expressions/references)
+  documents how to refer to named values like variables and resource attributes.
+
+- [Operators](/terraform/language/expressions/operators)
+  documents the arithmetic, comparison, and logical operators.
+
+- [Function Calls](/terraform/language/expressions/function-calls)
+  documents the syntax for calling Terraform's built-in functions.
+
+- [Conditional Expressions](/terraform/language/expressions/conditionals)
+  documents the `<CONDITION> ? <TRUE VAL> : <FALSE VAL>` expression, which
+  chooses between two values based on a bool condition.
+
+- [For Expressions](/terraform/language/expressions/for)
+  documents expressions like `[for s in var.list : upper(s)]`, which can
+  transform a complex type value into another complex type value.
+
+- [Splat Expressions](/terraform/language/expressions/splat)
+  documents expressions like `var.list[*].id`, which can extract simpler
+  collections from more complicated expressions.
+
+- [Dynamic Blocks](/terraform/language/expressions/dynamic-blocks)
+  documents a way to create multiple repeatable nested blocks within a resource
+  or other construct.
+
+- [Type Constraints](/terraform/language/expressions/type-constraints)
+  documents the syntax for referring to a type, rather than a value of that
+  type. Input variables expect this syntax in their `type` argument.
+
+- [Version Constraints](/terraform/language/expressions/version-constraints)
+  documents the syntax of special strings that define a set of allowed software
+  versions. Terraform uses version constraints in several places.
diff --git a/v1.5.7/website/docs/language/expressions/operators.mdx b/v1.5.7/website/docs/language/expressions/operators.mdx
new file mode 100644
index 0000000..a05a1cb
--- /dev/null
+++ b/v1.5.7/website/docs/language/expressions/operators.mdx
@@ -0,0 +1,107 @@
+---
+page_title: Operators - Configuration Language
+description: >-
+  Operators transform or combine expressions. Learn about arithmetic, logical,
+  equality, and comparison operators.
+---
+
+# Arithmetic and Logical Operators
+
+An _operator_ is a type of expression that transforms or combines one or more
+other expressions. Operators either combine two values in some way to
+produce a third result value, or transform a single given value to
+produce a single result.
+
+Operators that work on two values place an operator symbol between the two
+values, similar to mathematical notation: `1 + 2`. Operators that work on
+only one value place an operator symbol before that value, like
+`!true`.
+
+The Terraform language has a set of operators for both arithmetic and logic,
+which are similar to operators in programming languages such as JavaScript
+or Ruby.
+
+When multiple operators are used together in an expression, they are evaluated
+in the following order of operations:
+
+1. `!`, `-` (multiplication by `-1`)
+1. `*`, `/`, `%`
+1. `+`, `-` (subtraction)
+1. `>`, `>=`, `<`, `<=`
+1. `==`, `!=`
+1. `&&`
+1. `||`
+
+Use parentheses to override the default order of operations. Without
+parentheses, higher levels will be evaluated first, so Terraform will interpret
+`1 + 2 * 3` as `1 + (2 * 3)` and _not_ as `(1 + 2) * 3`.
+
+The different operators can be gathered into a few different groups with
+similar behavior, as described below. Each group of operators expects its
+given values to be of a particular type. Terraform will attempt to convert
+values to the required type automatically, or will produce an error message
+if automatic conversion is impossible.
+
+## Arithmetic Operators
+
+The arithmetic operators all expect number values and produce number values
+as results:
+
+* `a + b` returns the result of adding `a` and `b` together.
+* `a - b` returns the result of subtracting `b` from `a`.
+* `a * b` returns the result of multiplying `a` and `b`.
+* `a / b` returns the result of dividing `a` by `b`.
+* `a % b` returns the remainder of dividing `a` by `b`. This operator is
+  generally useful only when used with whole numbers.
+* `-a` returns the result of multiplying `a` by `-1`.
+
+Terraform supports some other less-common numeric operations as
+[functions](/terraform/language/expressions/function-calls). For example, you can calculate exponents
+using
+[the `pow` function](/terraform/language/functions/pow).
+
+## Equality Operators
+
+The equality operators both take two values of any type and produce boolean
+values as results.
+
+* `a == b` returns `true` if `a` and `b` both have the same type and the same
+  value, or `false` otherwise.
+* `a != b` is the opposite of `a == b`.
+
+Because the equality operators require both arguments to be of exactly the
+same type in order to decide equality, we recommend using these operators only
+with values of primitive types or using explicit type conversion functions
+to indicate which type you are intending to use for comparison.
+
+Comparisons between structural types may produce surprising results if you
+are not sure about the types of each of the arguments. For example,
+`var.list == []` may seem like it would return `true` if `var.list` were an
+empty list, but `[]` actually builds a value of type `tuple([])` and so the
+two values can never match. In this situation it's often clearer to write
+`length(var.list) == 0` instead.
+
+## Comparison Operators
+
+The comparison operators all expect number values and produce boolean values
+as results.
+
+* `a < b` returns `true` if `a` is less than `b`, or `false` otherwise.
+* `a <= b` returns `true` if `a` is less than or equal to `b`, or `false`
+  otherwise.
+* `a > b` returns `true` if `a` is greater than `b`, or `false` otherwise.
+* `a >= b` returns `true` if `a` is greater than or equal to `b`, or `false` otherwise.
+
+## Logical Operators
+
+The logical operators all expect bool values and produce bool values as results.
+
+* `a || b` returns `true` if either `a` or `b` is `true`, or `false` if both are `false`.
+* `a && b` returns `true` if both `a` and `b` are `true`, or `false` if either one is `false`.
+* `!a` returns `true` if `a` is `false`, and `false` if `a` is `true`.
+
+Terraform does not have an operator for the "exclusive OR" operation. If you
+know that both operators are boolean values then exclusive OR is equivalent
+to the `!=` ("not equal") operator.
+
+The logical operators in Terraform do not short-circuit, meaning `var.foo || var.foo.bar` will produce an error message if `var.foo` is `null` because both `var.foo` and `var.foo.bar` are evaluated.
diff --git a/v1.5.7/website/docs/language/expressions/references.mdx b/v1.5.7/website/docs/language/expressions/references.mdx
new file mode 100644
index 0000000..f6b6fc7
--- /dev/null
+++ b/v1.5.7/website/docs/language/expressions/references.mdx
@@ -0,0 +1,358 @@
+---
+page_title: References to Values - Configuration Language
+description: >-
+  Reference values in configurations, including resources, input variables,
+  local and block-local values, module outputs, data sources, and workspace
+  data.
+---
+
+# References to Named Values
+
+> **Hands-on:** Try the [Create Dynamic Expressions](/terraform/tutorials/configuration-language/expressions?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+Terraform makes several kinds of named values available. Each of these names is
+an expression that references the associated value. You can use them as
+standalone expressions, or combine them with other expressions to compute new
+values.
+
+## Types of Named Values
+
+The main kinds of named values available in Terraform are:
+
+* Resources
+* Input variables
+* Local values
+* Child module outputs
+* Data sources
+* Filesystem and workspace info
+* Block-local values
+
+The sections below explain each kind of named value in detail.
+
+Although many of these names use dot-separated paths that resemble
+[attribute notation](/terraform/language/expressions/types#indices-and-attributes) for elements of object values, they are not
+implemented as real objects. This means you must use them exactly as written:
+you cannot use square-bracket notation to replace the dot-separated paths, and
+you cannot iterate over the "parent object" of a named entity; for example, you
+cannot use `aws_instance` in a `for` expression to iterate over every AWS
+instance resource.
+
+### Resources
+
+`<RESOURCE TYPE>.<NAME>` represents a [managed resource](/terraform/language/resources) of
+the given type and name.
+
+The value of a resource reference can vary, depending on whether the resource
+uses `count` or `for_each`:
+
+* If the resource doesn't use `count` or `for_each`, the reference's value is an
+  object. The resource's attributes are elements of the object, and you can
+  access them using [dot or square bracket notation](/terraform/language/expressions/types#indices-and-attributes).
+* If the resource has the `count` argument set, the reference's value is a
+  _list_ of objects representing its instances.
+* If the resource has the `for_each` argument set, the reference's value is a
+  _map_ of objects representing its instances.
+
+Any named value that does not match another pattern listed below
+will be interpreted by Terraform as a reference to a managed resource.
+
+For more information about how to use resource references, see
+[references to resource attributes](#references-to-resource-attributes) below.
+
+### Input Variables
+
+`var.<NAME>` is the value of the [input variable](/terraform/language/values/variables) of the given name.
+
+If the variable has a type constraint (`type` argument) as part of its
+declaration, Terraform will automatically convert the caller's given value
+to conform to the type constraint.
+
+For that reason, you can safely assume that a reference using `var.` will
+always produce a value that conforms to the type constraint, even if the caller
+provided a value of a different type that was automatically converted.
+
+In particular, note that if you define a variable as being of an object type
+with particular attributes then only _those specific attributes_ will be
+available in expressions elsewhere in the module, even if the caller actually
+passed in a value with additional attributes. You must define in the type
+constraint all of the attributes you intend to use elsewhere in your module.
+
+### Local Values
+
+`local.<NAME>` is the value of the [local value](/terraform/language/values/locals) of the given name.
+
+Local values can refer to other local values, even within the same `locals`
+block, as long as you don't introduce circular dependencies.
+
+### Child Module Outputs
+
+`module.<MODULE NAME>` is an value representing the results of
+[a `module` block](/terraform/language/modules/syntax).
+
+If the corresponding `module` block does not have either `count` nor `for_each`
+set then the value will be an object with one attribute for each output value
+defined in the child module. To access one of the module's
+[output values](/terraform/language/values/outputs), use `module.<MODULE NAME>.<OUTPUT NAME>`.
+
+If the corresponding `module` uses `for_each` then the value will be a map
+of objects whose keys correspond with the keys in the `for_each` expression,
+and whose values are each objects with one attribute for each output value
+defined in the child module, each representing one module instance.
+
+If the corresponding module uses `count` then the result is similar to for
+`for_each` except that the value is a _list_ with the requested number of
+elements, each one representing one module instance.
+
+### Data Sources
+
+`data.<DATA TYPE>.<NAME>` is an object representing a
+[data resource](/terraform/language/data-sources) of the given data
+source type and name. If the resource has the `count` argument set, the value
+is a list of objects representing its instances. If the resource has the `for_each`
+argument set, the value is a map of objects representing its instances.
+
+For more information, see
+[References to Resource Attributes](#references-to-resource-attributes), which
+also applies to data resources aside from the addition of the `data.` prefix
+to mark the reference as for a data resource.
+
+### Filesystem and Workspace Info
+
+The following values are available:
+
+- `path.module` is the filesystem path of the module where the expression is placed.
+  We do not recommend using `path.module` in write operations because it can produce
+  different behavior depending on whether you use remote or local module sources.
+  Multiple invocations of local modules use the same source directory, overwriting
+  the data in `path.module` during each call. This can lead to race conditions and
+  unexpected results.
+- `path.root` is the filesystem path of the root module of the configuration.
+- `path.cwd` is the filesystem path of the original working directory from where you
+  ran Terraform before applying any `-chdir` argument. This path is an absolute path
+  that includes details about the filesystem structure. It is also useful in some
+  advanced cases where Terraform is run from a directory other than the root module
+  directory. We recommend using `path.root` or `path.module` over `path.cwd` where
+  possible.
+- `terraform.workspace` is the name of the currently selected
+  [workspace](/terraform/language/state/workspaces).
+
+Use the values in this section carefully, because they include information
+about the context in which a configuration is being applied and so may
+inadvertently hurt the portability or composability of a module.
+
+For example, if you use `path.cwd` directly to populate a path into a resource
+argument then later applying the same configuration from a different directory
+or on a different computer with a different directory structure will cause
+the provider to consider the change of path to be a change to be applied, even
+if the path still refers to the same file.
+
+Similarly, if you use any of these values as a form of namespacing in a shared
+module, such as using `terraform.workspace` as a prefix for globally-unique
+object names, it may not be possible to call your module more than once in
+the same configuration.
+
+Aside from `path.module`, we recommend using the values in this section only
+in the root module of your configuration. If you are writing a shared module
+which needs a prefix to help create unique names, define an input variable
+for your module and allow the calling module to define the prefix. The
+calling module can then use `terraform.workspace` to define it if appropriate,
+or some other value if not:
+
+```hcl
+module "example" {
+  # ...
+
+  name_prefix = "app-${terraform.workspace}"
+}
+```
+
+### Block-Local Values
+
+Within the bodies of certain blocks, or in some other specific contexts,
+there are other named values available beyond the global values listed above.
+These local names are described in the documentation for the specific contexts
+where they appear. Some of most common local names are:
+
+* `count.index`, in resources that use
+  [the `count` meta-argument](/terraform/language/meta-arguments/count).
+* `each.key` / `each.value`, in resources that use
+  [the `for_each` meta-argument](/terraform/language/meta-arguments/for_each).
+* `self`, in [provisioner](/terraform/language/resources/provisioners/syntax) and
+  [connection](/terraform/language/resources/provisioners/connection) blocks.
+
+-> **Note:** Local names are often referred to as _variables_ or
+_temporary variables_ in their documentation. These are not [input
+variables](/terraform/language/values/variables); they are just arbitrary names
+that temporarily represent a value.
+
+The names in this section relate to top-level configuration blocks only.
+If you use [`dynamic` blocks](/terraform/language/expressions/dynamic-blocks) to dynamically generate
+resource-type-specific _nested_ blocks within `resource` and `data` blocks then
+you'll refer to the key and value of each element differently. See the
+`dynamic` blocks documentation for details.
+
+## Named Values and Dependencies
+
+Constructs like resources and module calls often use references to named values
+in their block bodies, and Terraform analyzes these expressions to automatically
+infer dependencies between objects. For example, an expression in a resource
+argument that refers to another managed resource creates an implicit dependency
+between the two resources.
+
+## References to Resource Attributes
+
+The most common reference type is a reference to an attribute of a resource
+which has been declared either with a `resource` or `data` block. Because
+the contents of such blocks can be quite complicated themselves, expressions
+referring to these contents can also be complicated.
+
+Consider the following example resource block:
+
+```hcl
+resource "aws_instance" "example" {
+  ami           = "ami-abc123"
+  instance_type = "t2.micro"
+
+  ebs_block_device {
+    device_name = "sda2"
+    volume_size = 16
+  }
+  ebs_block_device {
+    device_name = "sda3"
+    volume_size = 20
+  }
+}
+```
+
+The documentation for [`aws_instance`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance)
+lists all of the arguments and nested blocks supported for this resource type,
+and also lists a number of attributes that are _exported_ by this resource
+type. All of these different resource type schema constructs are available
+for use in references, as follows:
+
+* The `ami` argument set in the configuration can be used elsewhere with
+  the reference expression `aws_instance.example.ami`.
+* The `id` attribute exported by this resource type can be read using the
+  same syntax, giving `aws_instance.example.id`.
+* The arguments of the `ebs_block_device` nested blocks can be accessed using
+  a [splat expression](/terraform/language/expressions/splat). For example, to obtain a list of
+  all of the `device_name` values, use
+  `aws_instance.example.ebs_block_device[*].device_name`.
+* The nested blocks in this particular resource type do not have any exported
+  attributes, but if `ebs_block_device` were to have a documented `id`
+  attribute then a list of them could be accessed similarly as
+  `aws_instance.example.ebs_block_device[*].id`.
+* Sometimes nested blocks are defined as taking a logical key to identify each
+  block, which serves a similar purpose as the resource's own name by providing
+  a convenient way to refer to that single block in expressions. If `aws_instance`
+  had a hypothetical nested block type `device` that accepted such a key, it
+  would look like this in configuration:
+
+  ```hcl
+    device "foo" {
+      size = 2
+    }
+    device "bar" {
+      size = 4
+    }
+  ```
+
+  Arguments inside blocks with _keys_ can be accessed using index syntax, such
+  as `aws_instance.example.device["foo"].size`.
+
+  To obtain a map of values of a particular argument for _labelled_ nested
+  block types, use a [`for` expression](/terraform/language/expressions/for):
+  `{for k, device in aws_instance.example.device : k => device.size}`.
+
+When a resource has the
+[`count`](/terraform/language/meta-arguments/count)
+argument set, the resource itself becomes a _list_ of instance objects rather than
+a single object. In that case, access the attributes of the instances using
+either [splat expressions](/terraform/language/expressions/splat) or index syntax:
+
+* `aws_instance.example[*].id` returns a list of all of the ids of each of the
+  instances.
+* `aws_instance.example[0].id` returns just the id of the first instance.
+
+When a resource has the
+[`for_each`](/terraform/language/meta-arguments/for_each)
+argument set, the resource itself becomes a _map_ of instance objects rather than
+a single object, and attributes of instances must be specified by key, or can
+be accessed using a [`for` expression](/terraform/language/expressions/for).
+
+* `aws_instance.example["a"].id` returns the id of the "a"-keyed resource.
+* `[for value in aws_instance.example: value.id]` returns a list of all of the ids
+  of each of the instances.
+
+Note that unlike `count`, splat expressions are _not_ directly applicable to resources managed with `for_each`, as splat expressions must act on a list value. However, you can use the `values()` function to extract the instances as a list and use that list value in a splat expression:
+
+* `values(aws_instance.example)[*].id`
+
+### Sensitive Resource Attributes
+
+When defining the schema for a resource type, a provider developer can mark
+certain attributes as _sensitive_, in which case Terraform will show a
+placeholder marker `(sensitive value)` instead of the actual value when rendering
+a plan involving that attribute.
+
+A provider attribute marked as sensitive behaves similarly to an
+[an input variable declared as sensitive](/terraform/language/values/variables#suppressing-values-in-cli-output),
+where Terraform will hide the value in the plan and apply messages and will
+also hide any other values you derive from it as sensitive.
+However, there are some limitations to that behavior as described in
+[Cases where Terraform may disclose a sensitive variable](/terraform/language/values/variables#cases-where-terraform-may-disclose-a-sensitive-variable).
+
+If you use a sensitive value from a resource attribute as part of an
+[output value](/terraform/language/values/outputs) then Terraform will require
+you to also mark the output value itself as sensitive, to confirm that you
+intended to export it.
+
+Terraform will still record sensitive values in the [state](/terraform/language/state),
+and so anyone who can access the state data will have access to the sensitive
+values in cleartext. For more information, see
+[_Sensitive Data in State_](/terraform/language/state/sensitive-data).
+
+-> **Note:** Treating values derived from a sensitive resource attribute as
+sensitive themselves was introduced in Terraform v0.15. Earlier versions of
+Terraform will obscure the direct value of a sensitive resource attribute,
+but will _not_ automatically obscure other values derived from sensitive
+resource attributes.
+
+### Values Not Yet Known
+
+When Terraform is planning a set of changes that will apply your configuration,
+some resource attribute values cannot be populated immediately because their
+values are decided dynamically by the remote system. For example, if a
+particular remote object type is assigned a generated unique id on creation,
+Terraform cannot predict the value of this id until the object has been created.
+
+Terraform uses special unknown value placeholders for information that it
+cannot predict during the plan phase. The Terraform language automatically
+handles unknown values in expressions. For example, adding a known value to an
+unknown value automatically produces an unknown value as a result.
+
+However, there are some situations where unknown values _do_ have a significant
+effect:
+
+* The `count` meta-argument for resources cannot be unknown, since it must
+  be evaluated during the plan phase to determine how many instances are to
+  be created.
+
+* If unknown values are used in the configuration of a data resource, that
+  data resource cannot be read during the plan phase and so it will be deferred
+  until the apply phase. In this case, the results of the data resource will
+  _also_ be unknown values.
+
+* If an unknown value is assigned to an argument inside a `module` block,
+  any references to the corresponding input variable within the child module
+  will use that unknown value.
+
+* If an unknown value is used in the `value` argument of an output value,
+  any references to that output value in the parent module will use that
+  unknown value.
+
+* Terraform will attempt to validate that unknown values are of suitable
+  types where possible, but incorrect use of such values may not be detected
+  until the apply phase, causing the apply to fail.
+
+Unknown values appear in the `terraform plan` output as `(known after apply)`.
diff --git a/v1.5.7/website/docs/language/expressions/splat.mdx b/v1.5.7/website/docs/language/expressions/splat.mdx
new file mode 100644
index 0000000..9ac126c
--- /dev/null
+++ b/v1.5.7/website/docs/language/expressions/splat.mdx
@@ -0,0 +1,128 @@
+---
+page_title: Splat Expressions - Configuration Language
+description: >-
+  Splat expressions concisely represent common operations. In Terraform, they
+  also transform single, non-null values into a single-element tuple.
+---
+
+# Splat Expressions
+
+> **Hands-on:** Try the [Create Dynamic Expressions](/terraform/tutorials/configuration-language/expressions?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+A _splat expression_ provides a more concise way to express a common
+operation that could otherwise be performed with a `for` expression.
+
+If `var.list` is a list of objects that all have an attribute `id`, then
+a list of the ids could be produced with the following `for` expression:
+
+```hcl
+[for o in var.list : o.id]
+```
+
+This is equivalent to the following _splat expression:_
+
+```hcl
+var.list[*].id
+```
+
+The special `[*]` symbol iterates over all of the elements of the list given
+to its left and accesses from each one the attribute name given on its
+right. A splat expression can also be used to access attributes and indexes
+from lists of complex types by extending the sequence of operations to the
+right of the symbol:
+
+```hcl
+var.list[*].interfaces[0].name
+```
+
+The above expression is equivalent to the following `for` expression:
+
+```hcl
+[for o in var.list : o.interfaces[0].name]
+```
+
+## Splat Expressions with Maps
+
+The splat expression patterns shown above apply only to lists, sets, and
+tuples. To get a similar result with a map or object value you must use
+[`for` expressions](/terraform/language/expressions/for).
+
+Resources that use the `for_each` argument will appear in expressions as a map
+of objects, so you can't use splat expressions with those resources.
+For more information, see
+[Referring to Resource Instances](/terraform/language/meta-arguments/for_each#referring-to-instances).
+
+## Single Values as Lists
+
+Splat expressions have a special behavior when you apply them to a value that
+isn't a list, set, or tuple.
+
+If the value is anything other than a null value then the splat expression will
+transform it into a single-element list, or more accurately a single-element
+tuple value. If the value is _null_ then the splat expression will return an
+empty tuple.
+
+This special behavior can be useful for modules that accept optional input
+variables whose default value is `null` to represent the absence of any value. This allows the module to adapt the variable value for Terraform language features designed to work with collections. For example:
+
+```
+variable "website_setting" {
+  type = object({
+    index_document = string
+    error_document = string
+  })
+  default = null
+}
+
+resource "aws_s3_bucket" "example" {
+  # ...
+
+  dynamic "website" {
+    for_each = var.website_setting[*]
+    content {
+      index_document = website.value.index_document
+      error_document = website.value.error_document
+    }
+  }
+}
+```
+
+The above example uses a [`dynamic` block](/terraform/language/expressions/dynamic-blocks), which
+generates zero or more nested blocks based on a collection value. The input
+variable `var.website_setting` is defined as a single object that might be null,
+so the `dynamic` block's `for_each` expression uses `[*]` to ensure that
+there will be one block if the module caller sets the website argument, or
+zero blocks if the caller leaves it set to null.
+
+This special behavior of splat expressions is not obvious to an unfamiliar
+reader, so we recommend using it only in `for_each` arguments and similar
+situations where the context implies working with a collection. Otherwise,
+the meaning of the expression may be unclear to future readers.
+
+## Legacy (Attribute-only) Splat Expressions
+
+Earlier versions of the Terraform language had a slightly different version
+of splat expressions, which Terraform continues to support for backward
+compatibility. This older variant is less useful than the modern form described
+above, and so we recommend against using it in new configurations.
+
+The legacy "attribute-only" splat expressions use the sequence `.*`, instead of
+`[*]`:
+
+```
+var.list.*.interfaces[0].name
+```
+
+This form has a subtly different behavior, equivalent to the following
+`for` expression:
+
+```
+[for o in var.list : o.interfaces][0].name
+```
+
+Notice that with the attribute-only splat expression the index operation
+`[0]` is applied to the result of the iteration, rather than as part of
+the iteration itself. Only the attribute lookups apply to each element of
+the input. This limitation was confusing some people using older versions of
+Terraform and so we recommend always using the new-style splat expressions,
+with `[*]`, to get the more consistent behavior.
diff --git a/v1.5.7/website/docs/language/expressions/strings.mdx b/v1.5.7/website/docs/language/expressions/strings.mdx
new file mode 100644
index 0000000..99eb677
--- /dev/null
+++ b/v1.5.7/website/docs/language/expressions/strings.mdx
@@ -0,0 +1,223 @@
+---
+page_title: Strings and Templates - Configuration Language
+description: >-
+  String literals and template sequences interpolate values and manipulate text.
+  Learn about both quoted and heredoc string syntax.
+---
+
+# Strings and Templates
+
+String literals are the most complex kind of literal expression in
+Terraform, and also the most commonly used.
+
+Terraform supports both a quoted syntax and a "heredoc" syntax for strings.
+Both of these syntaxes support template sequences for interpolating values and
+manipulating text.
+
+## Quoted Strings
+
+A quoted string is a series of characters delimited by straight double-quote
+characters (`"`).
+
+```
+"hello"
+```
+
+### Escape Sequences
+
+In quoted strings, the backslash character serves as an escape
+sequence, with the following characters selecting the escape behavior:
+
+| Sequence     | Replacement                                                                   |
+| ------------ | ----------------------------------------------------------------------------- |
+| `\n`         | Newline                                                                       |
+| `\r`         | Carriage Return                                                               |
+| `\t`         | Tab                                                                           |
+| `\"`         | Literal quote (without terminating the string)                                |
+| `\\`         | Literal backslash                                                             |
+| `\uNNNN`     | Unicode character from the basic multilingual plane (NNNN is four hex digits) |
+| `\UNNNNNNNN` | Unicode character from supplementary planes (NNNNNNNN is eight hex digits)    |
+
+There are also two special escape sequences that do not use backslashes:
+
+| Sequence | Replacement                                                    |
+| -------- | -------------------------------------------------------------- |
+| `$${`    | Literal `${`, without beginning an interpolation sequence.     |
+| `%%{`    | Literal `%{`, without beginning a template directive sequence. |
+
+## Heredoc Strings
+
+Terraform also supports a "heredoc" style of string literal inspired by Unix
+shell languages, which allows multi-line strings to be expressed more clearly.
+
+```hcl
+<<EOT
+hello
+world
+EOT
+```
+
+A heredoc string consists of:
+
+- An opening sequence consisting of:
+  - A heredoc marker (`<<` or `<<-` — two less-than signs, with an optional hyphen for indented heredocs)
+  - A delimiter word of your own choosing
+  - A line break
+- The contents of the string, which can span any number of lines
+- The delimiter word you chose, alone on its own line (with indentation allowed for indented heredocs)
+
+The `<<` marker followed by any identifier at the end of a line introduces the
+sequence. Terraform then processes the following lines until it finds one that
+consists entirely of the identifier given in the introducer.
+
+In the above example, `EOT` is the identifier selected. Any identifier is
+allowed, but conventionally this identifier is in all-uppercase and begins with
+`EO`, meaning "end of". `EOT` in this case stands for "end of text".
+
+### Generating JSON or YAML
+
+Don't use "heredoc" strings to generate JSON or YAML. Instead, use
+[the `jsonencode` function](/terraform/language/functions/jsonencode) or
+[the `yamlencode` function](/terraform/language/functions/yamlencode) so that Terraform
+can be responsible for guaranteeing valid JSON or YAML syntax.
+
+```hcl
+  example = jsonencode({
+    a = 1
+    b = "hello"
+  })
+```
+
+### Indented Heredocs
+
+The standard heredoc form (shown above) treats all space characters as literal
+spaces. If you don't want each line to begin with spaces, then each line must be
+flush with the left margin, which can be awkward for expressions in an
+indented block:
+
+```hcl
+block {
+  value = <<EOT
+hello
+world
+EOT
+}
+```
+
+To improve on this, Terraform also accepts an _indented_ heredoc string variant
+that is introduced by the `<<-` sequence:
+
+```hcl
+block {
+  value = <<-EOT
+  hello
+    world
+  EOT
+}
+```
+
+In this case, Terraform analyses the lines in the sequence to find the one
+with the smallest number of leading spaces, and then trims that many spaces
+from the beginning of all of the lines, leading to the following result:
+
+```
+hello
+  world
+```
+
+### Escape Sequences
+
+Backslash sequences are not interpreted as escapes in a heredoc string
+expression. Instead, the backslash character is interpreted literally.
+
+Heredocs support two special escape sequences that do not use backslashes:
+
+| Sequence | Replacement                                                    |
+| -------- | -------------------------------------------------------------- |
+| `$${`    | Literal `${`, without beginning an interpolation sequence.     |
+| `%%{`    | Literal `%{`, without beginning a template directive sequence. |
+
+## String Templates
+
+Within quoted and heredoc string expressions, the sequences `${` and `%{` begin
+_template sequences_. Templates let you directly embed expressions into a string
+literal, to dynamically construct strings from other values.
+
+### Interpolation
+
+A `${ ... }` sequence is an _interpolation,_ which evaluates the expression
+given between the markers, converts the result to a string if necessary, and
+then inserts it into the final string:
+
+```hcl
+"Hello, ${var.name}!"
+```
+
+In the above example, the named object `var.name` is accessed and its value
+inserted into the string, producing a result like "Hello, Juan!".
+
+### Directives
+
+A `%{ ... }` sequence is a _directive_, which allows for conditional
+results and iteration over collections, similar to conditional
+and `for` expressions.
+
+The following directives are supported:
+
+- The `%{if <BOOL>}`/`%{else}`/`%{endif}` directive chooses between two templates based
+  on the value of a bool expression:
+
+  ```hcl
+  "Hello, %{ if var.name != "" }${var.name}%{ else }unnamed%{ endif }!"
+  ```
+
+  The `else` portion may be omitted, in which case the result is an empty
+  string if the condition expression returns `false`.
+
+- The `%{for <NAME> in <COLLECTION>}` / `%{endfor}` directive iterates over the
+  elements of a given collection or structural value and evaluates a given
+  template once for each element, concatenating the results together:
+
+  ```hcl
+  <<EOT
+  %{ for ip in aws_instance.example[*].private_ip }
+  server ${ip}
+  %{ endfor }
+  EOT
+  ```
+
+  The name given immediately after the `for` keyword is used as a temporary
+  variable name which can then be referenced from the nested template.
+
+### Whitespace Stripping
+
+To allow template directives to be formatted for readability without adding
+unwanted spaces and newlines to the result, all template sequences can include
+optional _strip markers_ (`~`), immediately after the opening characters or
+immediately before the end. When a strip marker is present, the template
+sequence consumes all of the literal whitespace (spaces and newlines) either
+before the sequence (if the marker appears at the beginning) or after (if the
+marker appears at the end):
+
+```hcl
+<<EOT
+%{ for ip in aws_instance.example[*].private_ip ~}
+server ${ip}
+%{ endfor ~}
+EOT
+```
+
+In the above example, the newline after each of the directives is not included
+in the output, but the newline after the `server ${ip}` sequence is retained,
+causing only one line to be generated for each element:
+
+```
+server 10.1.16.154
+server 10.1.16.1
+server 10.1.16.34
+```
+
+When using template directives, we recommend always using the "heredoc" string
+literal form and then formatting the template over multiple lines for
+readability. Quoted string literals should usually include only interpolation
+sequences.
diff --git a/v1.5.7/website/docs/language/expressions/type-constraints.mdx b/v1.5.7/website/docs/language/expressions/type-constraints.mdx
new file mode 100644
index 0000000..d2be66d
--- /dev/null
+++ b/v1.5.7/website/docs/language/expressions/type-constraints.mdx
@@ -0,0 +1,439 @@
+---
+page_title: Type Constraints - Configuration Language
+description: >-
+  Learn how to use type constraints to validate user inputs to modules and
+  resources.
+---
+
+# Type Constraints
+
+Terraform module authors and provider developers can use detailed type
+constraints to validate user-provided values for their input variables and
+resource arguments. This requires some additional knowledge about Terraform's
+type system, but allows you to build a more resilient user interface for your
+modules and resources.
+
+## Type Keywords and Constructors
+
+Type constraints are expressed using a mixture of _type keywords_ and
+function-like constructs called _type constructors._
+
+* Type keywords are unquoted symbols that represent a static type.
+* Type constructors are unquoted symbols followed by a pair of
+  parentheses, which contain an argument that specifies more information about
+  the type. Without its argument, a type constructor does not fully
+  represent a type; instead, it represents a _kind_ of similar types.
+
+Type constraints look like other kinds of Terraform
+[expressions](/terraform/language/expressions), but are a special syntax. Within the
+Terraform language, they are only valid in the `type` argument of an
+[input variable](/terraform/language/values/variables).
+
+## Primitive Types
+
+A _primitive_ type is a simple type that isn't made from any other types. All
+primitive types in Terraform are represented by a type keyword. The available
+primitive types are:
+
+* `string`: a sequence of Unicode characters representing some text, such
+  as `"hello"`.
+* `number`: a numeric value. The `number` type can represent both whole
+  numbers like `15` and fractional values such as `6.283185`.
+* `bool`: either `true` or `false`. `bool` values can be used in conditional
+  logic.
+
+### Conversion of Primitive Types
+
+The Terraform language will automatically convert `number` and `bool` values
+to `string` values when needed, and vice-versa as long as the string contains
+a valid representation of a number or boolean value.
+
+* `true` converts to `"true"`, and vice-versa
+* `false` converts to `"false"`, and vice-versa
+* `15` converts to `"15"`, and vice-versa
+
+## Complex Types
+
+A _complex_ type is a type that groups multiple values into a single value.
+Complex types are represented by type constructors, but several of them
+also have shorthand keyword versions.
+
+There are two categories of complex types: collection types (for grouping
+similar values), and structural types (for grouping potentially dissimilar
+values).
+
+### Collection Types
+
+A _collection_ type allows multiple values of _one_ other type to be grouped
+together as a single value. The type of value _within_ a collection is called
+its _element type._ All collection types must have an element type, which is
+provided as the argument to their constructor.
+
+For example, the type `list(string)` means "list of strings", which is a
+different type than `list(number)`, a list of numbers. All elements of a
+collection must always be of the same type.
+
+The three kinds of collection type in the Terraform language are:
+
+* `list(...)`: a sequence of values identified by consecutive whole numbers
+  starting with zero.
+
+  The keyword `list` is a shorthand for `list(any)`, which accepts any
+  element type as long as every element is the same type. This is for
+  compatibility with older configurations; for new code, we recommend using
+  the full form.
+* `map(...)`: a collection of values where each is identified by a string label.
+
+  The keyword `map` is a shorthand for `map(any)`, which accepts any
+  element type as long as every element is the same type. This is for
+  compatibility with older configurations; for new code, we recommend using
+  the full form.
+
+  Maps can be made with braces ({}) and colons (:) or equals signs (=):
+  { "foo": "bar", "bar": "baz" } OR { foo = "bar", bar = "baz" }. Quotes
+  may be omitted on keys, unless the key starts with a number, in which
+  case quotes are required. Commas are required between key/value pairs
+  for single line maps. A newline between key/value pairs is sufficient
+  in multi-line maps.
+
+  -> **Note:** Although colons are valid delimiters between keys and values, `terraform fmt` ignores them. In contrast, `terraform fmt` attempts to vertically align equals signs.
+  
+* `set(...)`: a collection of unique values that do not have any secondary
+  identifiers or ordering.
+
+### Structural Types
+
+A _structural_ type allows multiple values of _several distinct types_ to be
+grouped together as a single value. Structural types require a _schema_ as an
+argument, to specify which types are allowed for which elements.
+
+The two kinds of structural type in the Terraform language are:
+
+* `object(...)`: a collection of named attributes that each have their own type.
+
+  The schema for object types is `{ <KEY> = <TYPE>, <KEY> = <TYPE>, ... }` — a
+  pair of curly braces containing a comma-separated series of `<KEY> = <TYPE>`
+  pairs. Values that match the object type must contain _all_ of the specified
+  keys, and the value for each key must match its specified type. (Values with
+  _additional_ keys can still match an object type, but the extra attributes
+  are discarded during type conversion.)
+* `tuple(...)`: a sequence of elements identified by consecutive whole
+  numbers starting with zero, where each element has its own type.
+
+  The schema for tuple types is `[<TYPE>, <TYPE>, ...]` — a pair of square
+  brackets containing a comma-separated series of types. Values that match the
+  tuple type must have _exactly_ the same number of elements (no more and no
+  fewer), and the value in each position must match the specified type for
+  that position.
+
+For example: an object type of `object({ name=string, age=number })` would match
+a value like the following:
+
+```hcl
+{
+  name = "John"
+  age  = 52
+}
+```
+
+Also, an object type of `object({ id=string, cidr_block=string })` would match
+the object produced by a reference to an `aws_vpc` resource, like
+`aws_vpc.example_vpc`; although the resource has additional attributes, they
+would be discarded during type conversion.
+
+Finally, a tuple type of `tuple([string, number, bool])` would match a value
+like the following:
+
+```hcl
+["a", 15, true]
+```
+
+### Complex Type Literals
+
+The Terraform language has literal expressions for creating tuple and object
+values, which are described in
+[Expressions: Literal Expressions](/terraform/language/expressions/types#literal-expressions) as
+"list/tuple" literals and "map/object" literals, respectively.
+
+Terraform does _not_ provide any way to directly represent lists, maps, or sets.
+However, due to the automatic conversion of complex types (described below), the
+difference between similar complex types is almost never relevant to a normal
+user, and most of the Terraform documentation conflates lists with tuples and
+maps with objects. The distinctions are only useful when restricting input
+values for a module or resource.
+
+### Conversion of Complex Types
+
+Similar kinds of complex types (list/tuple/set and map/object) can usually be
+used interchangeably within the Terraform language, and most of Terraform's
+documentation glosses over the differences between the kinds of complex type.
+This is due to two conversion behaviors:
+
+* Whenever possible, Terraform converts values between similar kinds of complex
+  types if the provided value is not the exact type requested. "Similar kinds"
+  is defined as follows:
+  * Objects and maps are similar.
+    * A map (or a larger object) can be converted to an object if it has
+      _at least_ the keys required by the object schema. Any additional
+      attributes are discarded during conversion, which means map -> object
+      -> map conversions can be lossy.
+  * Tuples and lists are similar.
+    * A list can only be converted to a tuple if it has _exactly_ the
+      required number of elements.
+  * Sets are _almost_ similar to both tuples and lists:
+    * When a list or tuple is converted to a set, duplicate values are
+      discarded and the ordering of elements is lost.
+    * When a `set` is converted to a list or tuple, the elements will be
+      in an arbitrary order. If the set's elements were strings, they will
+      be in lexicographical order; sets of other element types do not
+      guarantee any particular order of elements.
+* Whenever possible, Terraform converts _element values_ within a complex type,
+  either by converting complex-typed elements recursively or as described above
+  in [Conversion of Primitive Types](#conversion-of-primitive-types).
+
+For example: if a module argument requires a value of type `list(string)` and a
+user provides the tuple `["a", 15, true]`, Terraform will internally transform
+the value to `["a", "15", "true"]` by converting the elements to the required
+`string` element type. Later, if the module uses those elements to set different
+resource arguments that require a string, a number, and a bool (respectively),
+Terraform will automatically convert the second and third strings back to the
+required types at that time, since they contain valid representations of a
+number and a bool.
+
+On the other hand, automatic conversion will fail if the provided value
+(including any of its element values) is incompatible with the required type. If
+an argument requires a type of `map(string)` and a user provides the object
+`{name = ["Kristy", "Claudia", "Mary Anne", "Stacey"], age = 12}`, Terraform
+will raise a type mismatch error, since a tuple cannot be converted to a string.
+
+## Dynamic Types: The "any" Constraint
+
+~> **Warning:** `any` is very rarely the correct type constraint to use.
+**Do not use `any` just to avoid specifying a type constraint**. Always write an
+exact type constraint unless you are truly handling dynamic data.
+
+The keyword `any` is a special construct that serves as a placeholder for a
+type yet to be decided. `any` is not _itself_ a type: when interpreting a
+value against a type constraint containing `any`, Terraform will attempt to
+find a single actual type that could replace the `any` keyword to produce
+a valid result.
+
+The only situation where it's appropriate to use `any` is if you will pass
+the given value directly to some other system without directly accessing its
+contents. For example, it's okay to use a variable of type `any` if you use
+it only with `jsonencode` to pass the full value directly to a resource, as
+shown in the following example:
+
+```
+variable "settings" {
+  type = any
+}
+
+resource "aws_s3_object" "example" {
+  # ...
+
+  # This is a reasonable use of "any" because this module
+  # just writes any given data to S3 as JSON, without
+  # inspecting it further or applying any constraints
+  # to its type or value.
+  content = jsonencode(var.settings)
+}
+```
+
+If any part of your module accesses elements or attributes of the value, or
+expects it to be a string or number, or any other non-opaque treatment, it
+is _incorrect_ to use `any`. Write the exact type that your module is expecting
+instead.
+
+### `any` with Collection Types
+
+All of the elements of a collection must have the same type, so if you use
+`any` as the placeholder for the element type of a collection then Terraform
+will attempt to find a single exact element type to use for the resulting
+collection.
+
+For example, given the type constraint `list(any)`, Terraform will examine
+the given value and try to choose a replacement for the `any` that would
+make the result valid.
+
+If the given value were `["a", "b", "c"]` -- whose physical type is
+`tuple([string, string, string])` -- Terraform analyzes this as follows:
+
+* Tuple types and list types are _similar_ per the previous section, so the
+  tuple-to-list conversion rule applies.
+* All of the elements in the tuple are strings, so the type constraint
+  `string` would be valid for all of the list elements.
+* Therefore in this case the `any` argument is replaced with `string`,
+  and the final concrete value type is `list(string)`.
+
+If the elements of the given tuple are not all of the same type then Terraform
+will attempt to find a single type that they can all convert to. Terraform
+will consider various conversion rules as described in earlier sections.
+
+* If the given value were instead `["a", 1, "b"]` then Terraform would still
+  select `list(string)`, because of the primitive type conversion rules, and
+  the resulting value would be `["a", "1", "b"]` due to the string conversion
+  implied by that type constraint.
+* If the given value were instead `["a", [], "b"]` then the value cannot
+  conform to the type constraint: there is no single type that both a string
+  and an empty tuple can convert to. Terraform would reject this value,
+  complaining that all elements must have the same type.
+
+Although the above examples use `list(any)`, a similar principle applies to
+`map(any)` and `set(any)`.
+
+## Optional Object Type Attributes
+
+Terraform typically returns an error when it does not receive a value for specified object attributes. When you mark an attribute as optional, Terraform instead inserts a default value for the missing attribute. This allows the receiving module to describe an appropriate fallback behavior.
+
+To mark attributes as optional, use the `optional` modifier in the object type constraint. The following example creates optional attribute `b` and optional attribute with a default value `c`.
+
+```hcl
+variable "with_optional_attribute" {
+  type = object({
+    a = string                # a required attribute
+    b = optional(string)      # an optional attribute
+    c = optional(number, 127) # an optional attribute with default value
+  })
+}
+```
+
+The `optional` modifier takes one or two arguments.
+- **Type:** (Required) The first argument
+specifies the type of the attribute.
+- **Default:** (Optional) The second argument defines the default value that Terraform should use if the attribute is not present. This must be compatible with the attribute type. If not specified, Terraform uses a `null` value of the appropriate type as the default.
+
+An optional attribute with a non-`null` default value is guaranteed to never have the value `null` within the receiving module. Terraform will substitute the default value both when a caller omits the attribute altogether and when a caller explicitly sets it to `null`, thereby avoiding the need for additional checks to handle a possible null value.
+
+Terraform applies object attribute defaults top-down in nested variable types. This means that Terraform applies the default value you specify in the `optional` modifier first and then later applies any nested default values to that attribute.
+
+### Example: Nested Structures with Optional Attributes and Defaults
+
+The following example defines a variable for storage buckets that host a website. This variable type uses several optional attributes, including `website`, which is itself an optional `object` type that has optional attributes and defaults.
+
+```hcl
+variable "buckets" {
+  type = list(object({
+    name    = string
+    enabled = optional(bool, true)
+    website = optional(object({
+      index_document = optional(string, "index.html")
+      error_document = optional(string, "error.html")
+      routing_rules  = optional(string)
+    }), {})
+  }))
+}
+```
+
+The following example `terraform.tfvars` file specifies three bucket configurations for `var.buckets`.
+
+- `production` sets the routing rules to add a redirect
+- `archived` uses default configuration, but is disabled
+- `docs` overrides the index and error documents to use text files
+
+The `production` bucket does not specify the index and error documents, and the `archived` bucket omits the website configuration entirely. Terraform will use the default values specified in the `bucket` type constraint.
+
+```hcl
+buckets = [
+  {
+    name = "production"
+    website = {
+      routing_rules = <<-EOT
+      [
+        {
+          "Condition" = { "KeyPrefixEquals": "img/" },
+          "Redirect"  = { "ReplaceKeyPrefixWith": "images/" }
+        }
+      ]
+      EOT
+    }
+  },
+  {
+    name = "archived"
+    enabled = false
+  },
+  {
+    name = "docs"
+    website = {
+      index_document = "index.txt"
+      error_document = "error.txt"
+    }
+  },
+]
+```
+
+This configuration produces the following variable values.
+
+- For the `production` and `docs` buckets, Terraform sets `enabled` to `true`. Terraform also supplies default values for `website`, and then the values specified in `docs` override those defaults.
+- For the `archived` and `docs` buckets, Terraform sets `routing_rules` to a `null` value. When Terraform does not receive optional attributes and there are no specified defaults, Terraform populates those attributes with a `null` value.
+- For the `archived` bucket, Terraform populates the `website` attribute with the default values specified in the `buckets` type constraint.
+
+```hcl
+tolist([
+  {
+    "enabled" = true
+    "name" = "production"
+    "website" = {
+      "error_document" = "error.html"
+      "index_document" = "index.html"
+      "routing_rules" = <<-EOT
+      [
+        {
+          "Condition" = { "KeyPrefixEquals": "img/" },
+          "Redirect"  = { "ReplaceKeyPrefixWith": "images/" }
+        }
+      ]
+
+      EOT
+    }
+  },
+  {
+    "enabled" = false
+    "name" = "archived"
+    "website" = {
+      "error_document" = "error.html"
+      "index_document" = "index.html"
+      "routing_rules" = tostring(null)
+    }
+  },
+  {
+    "enabled" = true
+    "name" = "docs"
+    "website" = {
+      "error_document" = "error.txt"
+      "index_document" = "index.txt"
+      "routing_rules" = tostring(null)
+    }
+  },
+])
+```
+
+### Example: Conditionally setting an optional attribute
+
+Sometimes the decision about whether or not to set a value for an optional argument needs to be made dynamically based on some other data. In that case, the calling `module` block can use a conditional expression with `null` as one of its result arms to represent dynamically leaving the argument unset.
+
+With the `variable "buckets"` declaration shown in the previous section, the following example conditionally overrides the `index_document` and `error_document` settings in the `website` object based on a new variable `var.legacy_filenames`:
+
+```hcl
+variable "legacy_filenames" {
+  type     = bool
+  default  = false
+  nullable = false
+}
+
+module "buckets" {
+  source = "./modules/buckets"
+
+  buckets = [
+    {
+      name = "maybe_legacy"
+      website = {
+        error_document = var.legacy_filenames ? "ERROR.HTM" : null
+        index_document = var.legacy_filenames ? "INDEX.HTM" : null
+      }
+    },
+  ]
+}
+```
+
+When `var.legacy_filenames` is set to `true`, the call will override the document filenames. When it is `false`, the call will leave the two filenames unspecified, thereby allowing the module to use its specified default values.
diff --git a/v1.5.7/website/docs/language/expressions/types.mdx b/v1.5.7/website/docs/language/expressions/types.mdx
new file mode 100644
index 0000000..244f345
--- /dev/null
+++ b/v1.5.7/website/docs/language/expressions/types.mdx
@@ -0,0 +1,151 @@
+---
+page_title: Types and Values - Configuration Language
+description: >-
+  Learn about value types and syntax, including string, number, bool, list, and
+  map. Also learn about complex types and type conversion.
+---
+
+# Types and Values
+
+The result of an expression is a _value_. All values have a _type_, which
+dictates where that value can be used and what transformations can be
+applied to it.
+
+## Types
+
+The Terraform language uses the following types for its values:
+
+* `string`: a sequence of Unicode characters representing some text, like
+  `"hello"`.
+* `number`: a numeric value. The `number` type can represent both whole
+  numbers like `15` and fractional values like `6.283185`.
+* `bool`: a boolean value, either `true` or `false`. `bool` values can be used in conditional
+  logic.
+* `list` (or `tuple`): a sequence of values, like `["us-west-1a", "us-west-1c"]`. Identify elements in a list with consecutive whole numbers, starting with zero.
+* `set`: a collection of unique values that do not have any secondary identifiers or ordering.
+* `map` (or `object`): a group of values identified by named labels, like
+  `{name = "Mabel", age = 52}`.
+
+Strings, numbers, and bools are sometimes called _primitive types._
+Lists/tuples and maps/objects are sometimes called _complex types,_ _structural
+types,_ or _collection types._ See
+[Type Constraints](/terraform/language/expressions/type-constraints) for a more detailed
+description of complex types.
+
+Finally, there is one special value that has _no_ type:
+
+* `null`: a value that represents _absence_ or _omission._ If you set an
+  argument of a resource to `null`, Terraform behaves as though you
+  had completely omitted it — it will use the argument's default value if it has
+  one, or raise an error if the argument is mandatory. `null` is most useful in
+  conditional expressions, so you can dynamically omit an argument if a
+  condition isn't met.
+
+## Literal Expressions
+
+A _literal expression_ is an expression that directly represents a particular
+constant value. Terraform has a literal expression syntax for each of the value
+types described above.
+
+### Strings
+
+Strings are usually represented by a double-quoted sequence of Unicode
+characters, `"like this"`. There is also a "heredoc" syntax for more complex
+strings.
+
+String literals are the most complex kind of literal expression in
+Terraform, and have their own page of documentation. See [Strings](/terraform/language/expressions/strings)
+for information about escape sequences, the heredoc syntax, interpolation, and
+template directives.
+
+### Numbers
+
+Numbers are represented by unquoted sequences of digits with or without a
+decimal point, like `15` or `6.283185`.
+
+### Bools
+
+Bools are represented by the unquoted symbols `true` and `false`.
+
+### Null
+
+The null value is represented by the unquoted symbol `null`.
+
+### Lists/Tuples
+
+Lists/tuples are represented by a pair of square brackets containing a
+comma-separated sequence of values, like `["a", 15, true]`.
+
+List literals can be split into multiple lines for readability, but always
+require a comma between values. A comma after the final value is allowed,
+but not required. Values in a list can be arbitrary expressions.
+
+### Maps/Objects
+
+Maps/objects are represented by a pair of curly braces containing a series of
+`<KEY> = <VALUE>` pairs:
+
+```hcl
+{
+  name = "John"
+  age  = 52
+}
+```
+
+Key/value pairs can be separated by either a comma or a line break.
+
+The values in a map
+can be arbitrary expressions.
+
+The keys in a map must be strings; they can be left unquoted if
+they are a valid [identifier](/terraform/language/syntax/configuration#identifiers), but must be quoted
+otherwise. You can use a non-literal string expression as a key by wrapping it in
+parentheses, like `(var.business_unit_tag_name) = "SRE"`.
+
+## Indices and Attributes
+
+[inpage-index]: #indices-and-attributes
+
+Elements of list/tuple and map/object values can be accessed using
+the square-bracket index notation, like `local.list[3]`. The expression within
+the brackets must be a whole number for list and tuple values or a string
+for map and object values.
+
+Map/object attributes with names that are valid identifiers can also be accessed
+using the dot-separated attribute notation, like `local.object.attrname`.
+In cases where a map might contain arbitrary user-specified keys, we recommend
+using only the square-bracket index notation (`local.map["keyname"]`).
+
+## More About Complex Types
+
+In most situations, lists and tuples behave identically, as do maps and objects.
+Whenever the distinction isn't relevant, the Terraform documentation uses each
+pair of terms interchangeably (with a historical preference for "list" and
+"map").
+
+However, module authors and provider developers should understand the
+differences between these similar types (and the related `set` type), since they
+offer different ways to restrict the allowed values for input variables and
+resource arguments.
+
+For complete details about these types (and an explanation of why the difference
+usually doesn't matter), see [Type Constraints](/terraform/language/expressions/type-constraints).
+
+## Type Conversion
+
+Expressions are most often used to set values for the arguments of resources and
+child modules. In these cases, the argument has an expected type and the given
+expression must produce a value of that type.
+
+Where possible, Terraform automatically converts values from one type to
+another in order to produce the expected type. If this isn't possible, Terraform
+will produce a type mismatch error and you must update the configuration with a
+more suitable expression.
+
+Terraform automatically converts number and bool values to strings when needed.
+It also converts strings to numbers or bools, as long as the string contains a
+valid representation of a number or bool value.
+
+* `true` converts to `"true"`, and vice-versa
+* `false` converts to `"false"`, and vice-versa
+* `15` converts to `"15"`, and vice-versa
diff --git a/v1.5.7/website/docs/language/expressions/version-constraints.mdx b/v1.5.7/website/docs/language/expressions/version-constraints.mdx
new file mode 100644
index 0000000..52c5665
--- /dev/null
+++ b/v1.5.7/website/docs/language/expressions/version-constraints.mdx
@@ -0,0 +1,96 @@
+---
+page_title: Version Constraints - Configuration Language
+description: >-
+  Version constraint strings specify a range of acceptable versions for modules,
+  providers, and Terraform itself. Learn version constraint syntax and behavior.
+---
+
+# Version Constraints
+
+Anywhere that Terraform lets you specify a range of acceptable versions for
+something, it expects a specially formatted string known as a version
+constraint. Version constraints are used when configuring:
+
+- [Modules](/terraform/language/modules)
+- [Provider requirements](/terraform/language/providers/requirements)
+- [The `required_version` setting](/terraform/language/settings#specifying-a-required-terraform-version) in the `terraform` block.
+
+## Version Constraint Syntax
+
+Terraform's syntax for version constraints is very similar to the syntax used by
+other dependency management systems like Bundler and NPM.
+
+```hcl
+version = ">= 1.2.0, < 2.0.0"
+```
+
+A version constraint is a [string literal](/terraform/language/expressions/strings)
+containing one or more conditions, which are separated by commas.
+
+Each condition consists of an operator and a version number.
+
+Version numbers should be a series of numbers separated by periods (like
+`1.2.0`), optionally with a suffix to indicate a beta release.
+
+The following operators are valid:
+
+- `=` (or no operator): Allows only one exact version number. Cannot be combined
+  with other conditions.
+
+- `!=`: Excludes an exact version number.
+
+- `>`, `>=`, `<`, `<=`: Comparisons against a specified version, allowing
+  versions for which the comparison is true. "Greater-than" requests newer
+  versions, and "less-than" requests older versions.
+
+- `~>`: Allows only the _rightmost_ version component to increment. For example,
+  to allow new patch releases within a specific minor release, use the full
+  version number: `~> 1.0.4` will allow installation of `1.0.5` and `1.0.10`
+  but not `1.1.0`. This is usually called the pessimistic constraint operator.
+
+## Version Constraint Behavior
+
+A version number that meets every applicable constraint is considered acceptable.
+
+Terraform consults version constraints to determine whether it has acceptable
+versions of itself, any required provider plugins, and any required modules. For
+plugins and modules, it will use the newest installed version that meets the
+applicable constraints.
+
+If Terraform doesn't have an acceptable version of a required plugin or module,
+it will attempt to download the newest version that meets the applicable
+constraints.
+
+If Terraform isn't able to obtain acceptable versions of external dependencies,
+or if it doesn't have an acceptable version of itself, it won't proceed with any
+plans, applies, or state manipulation actions.
+
+Both the root module and any child module can constrain the acceptable versions
+of Terraform and any providers they use. Terraform considers these constraints
+equal, and will only proceed if all of them can be met.
+
+A prerelease version is a version number that contains a suffix introduced by
+a dash, like `1.2.0-beta`. A prerelease version can be selected only by an
+_exact_ version constraint (the `=` operator or no operator). Prerelease
+versions do not match inexact operators such as `>=`, `~>`, etc.
+
+## Best Practices
+
+### Module Versions
+
+- When depending on third-party modules, require specific versions to ensure
+  that updates only happen when convenient to you.
+
+- For modules maintained within your organization, specifying version ranges
+  may be appropriate if semantic versioning is used consistently or if there is
+  a well-defined release process that avoids unwanted updates.
+
+### Terraform Core and Provider Versions
+
+- Reusable modules should constrain only their minimum allowed versions of
+  Terraform and providers, such as `>= 0.12.0`. This helps avoid known
+  incompatibilities, while allowing the user of the module flexibility to
+  upgrade to newer versions of Terraform without altering the module.
+
+- Root modules should use a `~>` constraint to set both a lower and upper bound
+  on versions for each provider they depend on.
diff --git a/v1.5.7/website/docs/language/files/dependency-lock.mdx b/v1.5.7/website/docs/language/files/dependency-lock.mdx
new file mode 100644
index 0000000..99aeb2b
--- /dev/null
+++ b/v1.5.7/website/docs/language/files/dependency-lock.mdx
@@ -0,0 +1,419 @@
+---
+page_title: Dependency Lock File (.terraform.lock.hcl) - Configuration Language
+description: >-
+  Terraform uses the dependency lock file .teraform.lock.hcl to track and select
+  provider versions. Learn about dependency installation and lock file changes.
+---
+
+# Dependency Lock File
+
+-> **Note:** This page is about a feature of Terraform 0.14 and later. Prior
+versions of Terraform did not track dependency selections at all, so the
+information here is not relevant to those versions.
+
+> **Hands-on:** Try the [Lock and Upgrade Provider Versions](/terraform/tutorials/configuration-language/provider-versioning?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+A Terraform configuration may refer to two different kinds of external
+dependency that come from outside of its own codebase:
+
+- [Providers](/terraform/language/providers/requirements), which are plugins for Terraform
+  that extend it with support for interacting with various external systems.
+- [Modules](/terraform/language/modules), which allow
+  splitting out groups of Terraform configuration constructs (written in the
+  Terraform language) into reusable abstractions.
+
+Both of these dependency types can be published and updated independently from
+Terraform itself and from the configurations that depend on them. For that
+reason, Terraform must determine which versions of those dependencies are
+potentially compatible with the current configuration and which versions are
+currently selected for use.
+
+[Version constraints](/terraform/language/expressions/version-constraints) within the configuration
+itself determine which versions of dependencies are _potentially_ compatible,
+but after selecting a specific version of each dependency Terraform remembers
+the decisions it made in a _dependency lock file_ so that it can (by default)
+make the same decisions again in future.
+
+At present, the dependency lock file tracks only _provider_ dependencies.
+Terraform does not remember version selections for remote modules, and so
+Terraform will always select the newest available module version that meets
+the specified version constraints. You can use an _exact_ version constraint
+to ensure that Terraform will always select the same module version.
+
+## Lock File Location
+
+The dependency lock file is a file that belongs to the configuration as a
+whole, rather than to each separate module in the configuration. For that reason
+Terraform creates it and expects to find it in your current working directory
+when you run Terraform, which is also the directory containing the `.tf` files
+for the root module of your configuration.
+
+The lock file is always named `.terraform.lock.hcl`, and this name is intended
+to signify that it is a lock file for various items that Terraform caches in
+the `.terraform` subdirectory of your working directory.
+
+Terraform automatically creates or updates the dependency lock file each time
+you run [the `terraform init` command](/terraform/cli/commands/init). You should
+include this file in your version control repository so that you can discuss
+potential changes to your external dependencies via code review, just as you
+would discuss potential changes to your configuration itself.
+
+The dependency lock file uses the same low-level syntax as the main Terraform
+language, but the dependency lock file is not itself a Terraform language
+configuration file. It is named with the suffix `.hcl` instead of `.tf` in
+order to signify that difference.
+
+## Dependency Installation Behavior
+
+When `terraform init` is working on installing all of the providers needed for
+a configuration, Terraform considers both the version constraints in the
+configuration _and_ the version selections recorded in the lock file.
+
+If a particular provider has no existing recorded selection, Terraform will
+select the newest available version that matches the given version constraint,
+and then update the lock file to include that selection.
+
+If a particular provider already has a selection recorded in the lock file,
+Terraform will always re-select that version for installation, even if a
+newer version has become available. You can override that behavior by adding
+the `-upgrade` option when you run `terraform init`, in which case Terraform
+will disregard the existing selections and once again select the newest
+available version matching the version constraint.
+
+If a particular `terraform init` call makes changes to the lock file, Terraform
+will mention that as part of its output:
+
+```
+Terraform has made some changes to the provider dependency selections recorded
+in the .terraform.lock.hcl file. Review those changes and commit them to your
+version control system if they represent changes you intended to make.
+```
+
+When you see this message, you can use your version control system to
+[review the changes Terraform has proposed in the file](#understanding-lock-file-changes),
+and if they represent changes you made intentionally you can send the change
+through your team's usual code review process.
+
+### Checksum verification
+
+Terraform will also verify that each package it installs matches at least one
+of the checksums it previously recorded in the lock file, if any, returning an
+error if none of the checksums match:
+
+```
+Error: Failed to install provider
+
+Error while installing hashicorp/azurerm v2.1.0: the current package for
+registry.terraform.io/hashicorp/azurerm 2.1.0 doesn't match any of the
+checksums previously recorded in the dependency lock file.
+```
+
+This checksum verification is intended to represent a
+_[trust on first use](https://en.wikipedia.org/wiki/Trust_on_first_use)_
+approach. When you add a new provider for the first time you can verify it
+in whatever way you choose or any way you are required to by relevant
+regulations, and then trust that Terraform will raise an error if a future
+run of `terraform init` encounters a non-matching package for the same
+provider version.
+
+There are two special considerations with the "trust on first use" model:
+
+- If you install a provider from an origin registry which provides checksums
+  that are signed with a cryptographic signature, Terraform will treat all
+  of the signed checksums as valid as long as one checksum matches. The lock
+  file will therefore include checksums for both the package you installed for
+  your current platform _and_ any other packages that might be available for
+  other platforms.
+
+  In this case, the `terraform init` output will include the fingerprint of
+  the key that signed the checksums, with a message like
+  `(signed by a HashiCorp partner, key ID DC9FC6B1FCE47986)`. You may wish to
+  confirm that you trust the holder of the given key before committing the
+  lock file containing the signed checksums, or to retrieve and verify the
+  full set of available packages for the given provider version.
+
+- If you install a provider for the first time using an alternative
+  installation method, such as a filesystem or network mirror, Terraform will
+  not be able to verify the checksums for any platform other than the one
+  where you ran `terraform init`, and so it will not record the checksums
+  for other platforms and so the configuration will not be usable on any other
+  platform.
+
+  To avoid this problem you can pre-populate checksums for a variety of
+  different platforms in your lock file using
+  [the `terraform providers lock` command](/terraform/cli/commands/providers/lock),
+  which will then allow future calls to `terraform init` to verify that the
+  packages available in your chosen mirror match the official packages from
+  the provider's origin registry.
+
+## Understanding Lock File Changes
+
+Because the dependency lock file is primarily maintained automatically by
+Terraform itself, rather than being updated manually by you or your team,
+your version control system may show you that the file has changed.
+
+There are a few different types of changes that Terraform can potentially make
+to your lock file, which you may need to understand in order to review the
+proposed changes. The following sections will describe these common situations.
+
+### Dependency on a new provider
+
+If you add a new entry to the
+[provider requirements](/terraform/language/providers/requirements) for any module in your
+configuration, or if you add an external module that includes a new provider
+dependency itself, `terraform init` will respond to that by selecting the
+newest version of that provider which meets all of the version constraints
+in the configuration, and it will record its decision as a new `provider`
+block in the dependency lock file.
+
+```diff
+--- .terraform.lock.hcl	2020-10-07 16:12:07.539570634 -0700
++++ .terraform.lock.hcl	2020-10-07 16:12:15.267487237 -0700
+@@ -6,6 +6,26 @@
+   ]
+ }
+
++provider "registry.terraform.io/hashicorp/azurerm" {
++  version     = "2.30.0"
++  constraints = "~> 2.12"
++  hashes = [
++    "h1:FJwsuowaG5CIdZ0WQyFZH9r6kIJeRKts9+GcRsTz1+Y=",
++    "h1:c/ntSXrDYM1mUir2KufijYebPcwKqS9CRGd3duDSGfY=",
++    "h1:yre4Ph76g9H84MbuhZ2z5MuldjSA4FsrX6538O7PCcY=",
++    "zh:04f0a50bb2ba92f3bea6f0a9e549ace5a4c13ef0cbb6975494cac0ef7d4acb43",
++    "zh:2082e12548ebcdd6fd73580e83f626ed4ed13f8cdfd51205d8696ffe54f30734",
++    "zh:246bcc449e9a92679fb30f3c0a77f05513886565e2dcc66b16c4486f51533064",
++    "zh:24de3930625ac9014594d79bfa42d600eca65e9022b9668b54bfd0d924e21d14",
++    "zh:2a22893a576ff6f268d9bf81cf4a56406f7ba79f77826f6df51ee787f6d2840a",
++    "zh:2b27485e19c2aaa9f15f29c4cff46154a9720647610171e30fc6c18ddc42ec28",
++    "zh:435f24ce1fb2b63f7f02aa3c84ac29c5757cd29ec4d297ed0618423387fe7bd4",
++    "zh:7d99725923de5240ff8b34b5510569aa4ebdc0bdb27b7bac2aa911a8037a3893",
++    "zh:7e3b5d0af3b7411dd9dc65ec9ab6caee8c191aee0fa7f20fc4f51716e67f50c0",
++    "zh:da0af4552bef5a29b88f6a0718253f3bf71ce471c959816eb7602b0dadb469ca",
++  ]
++}
++
+ provider "registry.terraform.io/newrelic/newrelic" {
+   version     = "2.1.2"
+   constraints = "~> 2.1.1"
+```
+
+The new lock file entry records several pieces of information:
+
+- `version`: the exact version that Terraform selected based on the version
+  constraints in the configuration.
+- `constraints`: all of the version constraints that Terraform considered when
+  making this selection. (Terraform doesn't actually use this information to
+  make installation decisions, but includes it to help explain to human readers
+  how the previous decision was made.)
+- `hashes`: a number of checksums that are all considered to be valid for
+  packages implementing the selected version of this provider on different
+  platforms. The meaning of these hashes is explained more under
+  _[New provider package checksums](#new-provider-package-checksums)_ below.
+
+### New version of an existing provider
+
+If you run `terraform init -upgrade` to ask Terraform to consider newer provider
+versions that still match the configured version constraints, Terraform may
+then select a newer version for a provider and update its existing `provider`
+block to reflect that change.
+
+```diff
+--- .terraform.lock.hcl	2020-10-07 16:44:25.819579509 -0700
++++ .terraform.lock.hcl	2020-10-07 16:43:42.785665945 -0700
+@@ -7,22 +7,22 @@
+ }
+
+ provider "registry.terraform.io/hashicorp/azurerm" {
+-  version     = "2.1.0"
+-  constraints = "~> 2.1.0"
++  version     = "2.0.0"
++  constraints = "2.0.0"
+   hashes      = [
+-    "h1:EOJImaEaVThWasdqnJjfYc6/P8N/MRAq1J7avx5ZbV4=",
+-    "zh:0015b491cf9151235e57e35ea6b89381098e61bd923f56dffc86026d58748880",
+-    "zh:4c5682ba1e0fc7e2e602d3f103af1638f868c31fe80cc1a884a97f6dad6e1c11",
+-    "zh:57bac885b108c91ade4a41590062309c832c9ab6bf6a68046161636fcaef1499",
+-    "zh:5810d48f574c0e363c969b3f45276369c8f0a35b34d6202fdfceb7b85b3ac597",
+-    "zh:5c6e37a44462b8662cf9bdd29ce30523712a45c27c5d4711738705be0785db41",
+-    "zh:64548940a3387aa3a752e709ee9eb9982fa820fe60eb60e5f212cc1d2c58549e",
+-    "zh:7f46749163da17330bbb5293dc825333c86304baa0a7c6256650ac536b4567c8",
+-    "zh:8f8970f2df75ac43ffdd112055ee069d8bd1030f7eb4367cc4cf494a1fa802c3",
+-    "zh:9ad693d00dc5d7d455d06faba70e716bce727c6706f7293288e87fd7956b8fe0",
+-    "zh:b6e3cb55e6aec62b47edd0d2bd5e14bd6a2bcfdac65930a6e9e819934734c57b",
+-    "zh:d6a3f3b9b05c28ecf3919e9e7afa185805a6d7442fc4b3eedba749c2731d1f0e",
+-    "zh:d81fb624a357c57c7ea457ce543d865b39b12f26c2edd58a2f7cd43326c91010",
++    "h1:bigGXBoRbp7dv79bEEn+aaju8575qEXHQ57XHVPJeB8=",
++    "zh:09c603c8904ca4a5bc19e82335afbc2837dcc4bee81e395f9daccef2f2cba1c8",
++    "zh:194a919d4836d6c6d4ce598d0c66cce00ddc0d0b5c40d01bb32789964d818b42",
++    "zh:1f269627df4e266c4e0ef9ee2486534caa3c8bea91a201feda4bca525005aa0a",
++    "zh:2bae3071bd5f8e553355c4b3a547d6efe1774a828142b762e9a4e85f79be7f63",
++    "zh:6c98dfa5c3468e8d02e2b3af7c4a8a14a5d469ce5a642909643b413a17ca338b",
++    "zh:7af78f61666fd45fbf428161c061ea2623162d601b79dc71d6a5158756853ffa",
++    "zh:883c2df86ae9ba2a5c167cf5c2c7deca0239171a224d6d335f0fd6dd9c283830",
++    "zh:a2028379078577d8ff5ecfca6e8a8b25a25ffb1686de0ee52a7fe8011783488b",
++    "zh:abe6ef399552fd3861a454a839cd978c1d15735658fdc00f9054435aff0f4620",
++    "zh:c30b1bf14077913c3cdf34979b1434dbb1353cb5995eb3956b191c50538b64a9",
++    "zh:ca64ae2ad9793e5631e3b0b9327f7cb22cb5d8e9de57be7d85821791b1d5a375",
++    "zh:fffe56904a38109bb8d613b02808a177c3ddfac19f03b3aac799281fea38f475",
+   ]
+ }
+```
+
+The primary effect of selecting a new provider version is to change the
+value of `version` in the `provider` block. If the upgrade came along with
+a change to the configured version constraints, Terraform will also record
+that change in the `constraints` value.
+
+Because each version has its own set of distribution packages, switching to
+a new version will also tend to replace all of the values in `hashes`, to
+reflect the checksums of the packages for the new version.
+
+### New provider package checksums
+
+A more subtle change you may see in a `provider` block is the addition of
+new checksums that were not previously recorded, even though nothing else
+in the `provider` block has changed:
+
+```diff
+--- .terraform.lock.hcl	2020-10-07 17:24:23.397892140 -0700
++++ .terraform.lock.hcl	2020-10-07 17:24:57.423130253 -0700
+@@ -10,6 +10,7 @@
+   version     = "2.1.0"
+   constraints = "~> 2.1.0"
+   hashes = [
++    "h1:1xvaS5D8B8t6J6XmXxX8spo97tAzjhacjedFX1B47Fk=",
+     "h1:EOJImaEaVThWasdqnJjfYc6/P8N/MRAq1J7avx5ZbV4=",
+     "zh:0015b491cf9151235e57e35ea6b89381098e61bd923f56dffc86026d58748880",
+     "zh:4c5682ba1e0fc7e2e602d3f103af1638f868c31fe80cc1a884a97f6dad6e1c11",
+```
+
+The addition of a new checksum into the `hashes` value represents Terraform
+gradually transitioning between different _hashing schemes_. The `h1:` and
+`zh:` prefixes on these values represent different hashing schemes, each
+of which represents calculating a checksum using a different algorithm.
+We may occasionally introduce new hashing schemes if we learn of limitations
+in the existing schemes or if a new scheme offers some considerable
+additional benefit.
+
+The two hashing schemes currently supported are:
+
+- `zh:`: a mnemonic for "zip hash", this is a legacy hash format which is
+  part of the Terraform provider registry protocol and is therefore used for
+  providers that you install directly from an origin registry.
+
+  This hashing scheme captures a SHA256 hash of each of the official `.zip`
+  packages indexed in the origin registry. This is an effective scheme for
+  verifying the official release packages when installed from a registry, but
+  it's not suitable for verifying packages that come from other
+  [provider installation methods](/terraform/cli/config/config-file#provider-installation),
+  such as filesystem mirrors using the unpacked directory layout.
+
+- `h1:`: a mnemonic for "hash scheme 1", which is the current preferred hashing
+  scheme.
+
+  Hash scheme 1 is also a SHA256 hash, but is one computed from the _contents_
+  of the provider distribution package, rather than of the `.zip` archive
+  it's contained within. This scheme therefore has the advantage that it can
+  be calculated for an official `.zip` file, an unpacked directory with the
+  same contents, or a recompressed `.zip` file which contains the same files
+  but potentially different metadata or compression schemes.
+
+  Due to the limited scope of the `zh:` scheme, Terraform will
+  opportunistically add in the corresponding `h1:` checksums as it learns
+  of them, which is what caused the addition of a second `h1:` checksum
+  in the example change shown above.
+
+Terraform will add a new hash to an existing provider only if the hash is
+calculated from a package that _also_ matches one of the existing hashes. In
+the above example, Terraform installed a `hashicorp/azurerm` package for a
+different platform than that which produced the original `h1:` checksum, but was
+able to match it against one of the `zh:` checksums recorded previously.
+After confirming the `zh:` checksum match, Terraform then recorded the
+corresponding `h1:` checksum in order to gradually migrate from the old scheme
+to the new scheme.
+
+When installing a particular provider for the first time (where there is no
+existing `provider` block for it), Terraform will pre-populate the `hashes`
+value with any checksums that are covered by the provider developer's
+cryptographic signature, which usually covers all of the available packages
+for that provider version across all supported platforms. However, because
+the provider registry protocol still uses the `zh:` scheme, the initial set
+will consist primarily of hashes using that scheme, which Terraform will then
+upgrade opportunistically as you install the packages on different platforms.
+
+If you wish to avoid ongoing additions of new `h1:` hashes as you work with
+your configuration on new target platforms, or if you are installing providers
+from a mirror that therefore can't provide official signed checksums, you
+can ask Terraform to pre-populate hashes for a chosen set of platforms
+using
+[the `terraform providers lock` command](/terraform/cli/commands/providers/lock):
+
+```
+terraform providers lock \
+  -platform=linux_arm64 \
+  -platform=linux_amd64 \
+  -platform=darwin_amd64 \
+  -platform=windows_amd64
+```
+
+The above command will download and verify the official packages for all of
+the required providers across all four of the given platforms, and then record
+both `zh:` and `h1:` checksums for each of them in the lock file, thus avoiding
+the case where Terraform will learn about a `h1:` equivalent only at a later
+time. See the `terraform providers lock` documentation for more information on
+this command.
+
+### Providers that are no longer required
+
+To determine whether there still exists a dependency on a given provider,
+Terraform uses two sources of truth: the configuration itself, and the state.
+If you remove the last dependency on a particular provider from both your
+configuration and state, then `terraform init` will remove any existing lock
+file entry for that provider.
+
+```diff
+--- .terraform.lock.hcl	2020-10-07 16:12:07.539570634 -0700
++++ .terraform.lock.hcl	2020-10-07 16:12:15.267487237 -0700
+@@ -6,26 +6,6 @@
+   ]
+ }
+
+-provider "registry.terraform.io/hashicorp/azurerm" {
+-  version     = "2.30.0"
+-  constraints = "~> 2.12"
+-  hashes = [
+-    "h1:FJwsuowaG5CIdZ0WQyFZH9r6kIJeRKts9+GcRsTz1+Y=",
+-    "h1:c/ntSXrDYM1mUir2KufijYebPcwKqS9CRGd3duDSGfY=",
+-    "h1:yre4Ph76g9H84MbuhZ2z5MuldjSA4FsrX6538O7PCcY=",
+-    "zh:04f0a50bb2ba92f3bea6f0a9e549ace5a4c13ef0cbb6975494cac0ef7d4acb43",
+-    "zh:2082e12548ebcdd6fd73580e83f626ed4ed13f8cdfd51205d8696ffe54f30734",
+-    "zh:246bcc449e9a92679fb30f3c0a77f05513886565e2dcc66b16c4486f51533064",
+-    "zh:24de3930625ac9014594d79bfa42d600eca65e9022b9668b54bfd0d924e21d14",
+-    "zh:2a22893a576ff6f268d9bf81cf4a56406f7ba79f77826f6df51ee787f6d2840a",
+-    "zh:2b27485e19c2aaa9f15f29c4cff46154a9720647610171e30fc6c18ddc42ec28",
+-    "zh:435f24ce1fb2b63f7f02aa3c84ac29c5757cd29ec4d297ed0618423387fe7bd4",
+-    "zh:7d99725923de5240ff8b34b5510569aa4ebdc0bdb27b7bac2aa911a8037a3893",
+-    "zh:7e3b5d0af3b7411dd9dc65ec9ab6caee8c191aee0fa7f20fc4f51716e67f50c0",
+-    "zh:da0af4552bef5a29b88f6a0718253f3bf71ce471c959816eb7602b0dadb469ca",
+-  ]
+-}
+-
+ provider "registry.terraform.io/newrelic/newrelic" {
+   version     = "2.1.2"
+   constraints = "~> 2.1.1"
+```
+
+If you add a new requirement for the same provider at a later date and run
+`terraform init` again, Terraform will treat it as if it were
+[an entirely new provider](#dependency-on-a-new-provider)
+and so will not necessarily select the same version that was previously
+selected and will not be able to verify that the checksums remained unchanged.
+
+-> **Note:** In Terraform v1.0 and earlier, `terraform init` does not
+automatically remove now-unneeded providers from the lock file, and instead
+just ignores them. If you removed a provider dependency while using an
+earlier version of Terraform and then upgraded to Terraform v1.1 or later
+then you may see the error "missing or corrupted provider plugins", referring to
+the stale lock file entries. If so, run `terraform init` with the new Terraform
+version to tidy those unneeded entries and then retry the previous operation.
diff --git a/v1.5.7/website/docs/language/files/index.mdx b/v1.5.7/website/docs/language/files/index.mdx
new file mode 100644
index 0000000..395b54a
--- /dev/null
+++ b/v1.5.7/website/docs/language/files/index.mdx
@@ -0,0 +1,58 @@
+---
+page_title: Files and Directories - Configuration Language
+description: >-
+  Learn how to name, organize, and store Terraform configuration files. Also
+  learn how Terraform evaluates modules.
+---
+
+# Files and Directories
+
+## File Extension
+
+Code in the Terraform language is stored in plain text files with the `.tf` file
+extension. There is also
+[a JSON-based variant of the language](/terraform/language/syntax/json) that is named with
+the `.tf.json` file extension.
+
+Files containing Terraform code are often called _configuration files._
+
+## Text Encoding
+
+Configuration files must always use UTF-8 encoding, and by convention
+usually use Unix-style line endings (LF) rather than Windows-style
+line endings (CRLF), though both are accepted.
+
+## Directories and Modules
+
+A _module_ is a collection of `.tf` and/or `.tf.json` files kept together in a
+directory.
+
+A Terraform module only consists of the top-level configuration files in a
+directory; nested directories are treated as completely separate modules, and
+are not automatically included in the configuration.
+
+Terraform evaluates all of the configuration files in a module, effectively
+treating the entire module as a single document. Separating various blocks into
+different files is purely for the convenience of readers and maintainers, and
+has no effect on the module's behavior.
+
+A Terraform module can use [module calls](/terraform/language/modules) to
+explicitly include other modules into the configuration. These child modules can
+come from local directories (nested in the parent module's directory, or
+anywhere else on disk), or from external sources like the
+[Terraform Registry](https://registry.terraform.io).
+
+## The Root Module
+
+Terraform always runs in the context of a single _root module._ A complete
+_Terraform configuration_ consists of a root module and the tree of child
+modules (which includes the modules called by the root module, any modules
+called by those modules, etc.).
+
+- In Terraform CLI, the root module is the working directory where Terraform is
+  invoked. (You can use command line options to specify a root module outside
+  the working directory, but in practice this is rare.)
+- In Terraform Cloud and Terraform Enterprise, the root module for a workspace
+  defaults to the top level of the configuration directory (supplied via version
+  control repository or direct upload), but the workspace settings can specify a
+  subdirectory to use instead.
diff --git a/v1.5.7/website/docs/language/files/override.mdx b/v1.5.7/website/docs/language/files/override.mdx
new file mode 100644
index 0000000..3595cd5
--- /dev/null
+++ b/v1.5.7/website/docs/language/files/override.mdx
@@ -0,0 +1,160 @@
+---
+page_title: Override Files - Configuration Language
+description: >-
+  Override files merge additional settings into existing configuration objects.
+  Learn how to use override files and about merging behavior.
+---
+
+# Override Files
+
+Terraform normally loads all of the `.tf` and `.tf.json` files within a
+directory and expects each one to define a distinct set of configuration
+objects. If two files attempt to define the same object, Terraform returns
+an error.
+
+In some rare cases, it is convenient to be able to override specific portions
+of an existing configuration object in a separate file. For example, a
+human-edited configuration file in the Terraform language native syntax
+could be partially overridden using a programmatically-generated file
+in JSON syntax.
+
+For these rare situations, Terraform has special handling of any configuration
+file whose name ends in `_override.tf` or `_override.tf.json`. This special
+handling also applies to a file named literally `override.tf` or
+`override.tf.json`.
+
+Terraform initially skips these _override files_ when loading configuration,
+and then afterwards processes each one in turn (in lexicographical order). For
+each top-level block defined in an override file, Terraform attempts to find
+an already-defined object corresponding to that block and then merges the
+override block contents into the existing object.
+
+Use override files only in special circumstances. Over-use of override files
+hurts readability, since a reader looking only at the original files cannot
+easily see that some portions of those files have been overridden without
+consulting all of the override files that are present. When using override
+files, use comments in the original files to warn future readers about which
+override files apply changes to each block.
+
+## Example
+
+If you have a Terraform configuration `example.tf` with the following contents:
+
+```hcl
+resource "aws_instance" "web" {
+  instance_type = "t2.micro"
+  ami           = "ami-408c7f28"
+}
+```
+
+...and you created a file `override.tf` containing the following:
+
+```hcl
+resource "aws_instance" "web" {
+  ami = "foo"
+}
+```
+
+Terraform will merge the latter into the former, behaving as if the original
+configuration had been as follows:
+
+```hcl
+resource "aws_instance" "web" {
+  instance_type = "t2.micro"
+  ami           = "foo"
+}
+```
+
+## Merging Behavior
+
+The merging behavior is slightly different for each block type, and some
+special constructs within certain blocks are merged in a special way.
+
+The general rule, which applies in most cases, is:
+
+* A top-level block in an override file merges with a block in a normal
+  configuration file that has the same block header. The block _header_ is the
+  block type and any quoted labels that follow it.
+
+* Within a top-level block, an attribute argument within an override block
+  replaces any argument of the same name in the original block.
+
+* Within a top-level block, any nested blocks within an override block replace
+  _all_ blocks of the same type in the original block. Any block types that
+  do not appear in the override block remain from the original block.
+
+* The contents of nested configuration blocks are not merged.
+
+* The resulting _merged block_ must still comply with any validation rules
+  that apply to the given block type.
+
+If more than one override file defines the same top-level block, the overriding
+effect is compounded, with later blocks taking precedence over earlier blocks.
+Overrides are processed in order first by filename (in lexicographical order)
+and then by position in each file.
+
+The following sections describe the special merging behaviors that apply to
+specific arguments within certain top-level block types.
+
+### Merging `resource` and `data` blocks
+
+Within a `resource` block, the contents of any `lifecycle` nested block are
+merged on an argument-by-argument basis. For example, if an override block
+sets only the `create_before_destroy` argument then any `ignore_changes`
+argument in the original block will be preserved.
+
+If an overriding `resource` block contains one or more `provisioner` blocks
+then any `provisioner` blocks in the original block are ignored.
+
+If an overriding `resource` block contains a `connection` block then it
+completely overrides any `connection` block present in the original block.
+
+The `depends_on` meta-argument may not be used in override blocks, and will
+produce an error.
+
+### Merging `variable` blocks
+
+The arguments within a `variable` block are merged in the standard way
+described above, but some special considerations apply due to the interactions
+between the `type` and `default` arguments.
+
+If the original block defines a `default` value and an override block changes
+the variable's `type`, Terraform attempts to convert the default value to
+the overridden type, producing an error if this conversion is not possible.
+
+Conversely, if the original block defines a `type` and an override block changes
+the `default`, the overridden default value must be compatible with the
+original type specification.
+
+### Merging `output` blocks
+
+The `depends_on` meta-argument may not be used in override blocks, and will
+produce an error.
+
+### Merging `locals` blocks
+
+Each `locals` block defines a number of named values. Overrides are applied
+on a value-by-value basis, ignoring which `locals` block they are defined in.
+
+### Merging `terraform` blocks
+
+The settings within `terraform` blocks are considered individually when
+merging.
+
+If the `required_providers` argument is set, its value is merged on an
+element-by-element basis, which allows an override block to adjust the
+constraint for a single provider without affecting the constraints for
+other providers.
+
+In both the `required_version` and `required_providers` settings, each override
+constraint entirely replaces the constraints for the same component in the
+original block. If both the base block and the override block both set
+`required_version` then the constraints in the base block are entirely ignored.
+
+The presence of a block defining a backend (either `cloud` or `backend`) in an override
+file always takes precedence over a block defining a backend in the original configuration.
+That is, if a `cloud` block is set within the original configuration and a `backend` block is
+set in the override file, Terraform will use the `backend` block specified in the override file upon merging.
+Similarly, if a `backend` block is set within the original configuration and a `cloud` block
+is set in the override file, Terraform will use the `cloud` block specified in the override
+file upon merging.
diff --git a/v1.5.7/website/docs/language/functions/abs.mdx b/v1.5.7/website/docs/language/functions/abs.mdx
new file mode 100644
index 0000000..49ceef9
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/abs.mdx
@@ -0,0 +1,21 @@
+---
+page_title: abs - Functions - Configuration Language
+description: The abs function returns the absolute value of the given number.
+---
+
+# `abs` Function
+
+`abs` returns the absolute value of the given number. In other words, if the
+number is zero or positive then it is returned as-is, but if it is negative
+then it is multiplied by -1 to make it positive before returning it.
+
+## Examples
+
+```
+> abs(23)
+23
+> abs(0)
+0
+> abs(-12.4)
+12.4
+```
diff --git a/v1.5.7/website/docs/language/functions/abspath.mdx b/v1.5.7/website/docs/language/functions/abspath.mdx
new file mode 100644
index 0000000..cf6da3b
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/abspath.mdx
@@ -0,0 +1,23 @@
+---
+page_title: abspath - Functions - Configuration Language
+description: The abspath function converts the argument to an absolute filesystem path.
+---
+
+# `abspath` Function
+
+`abspath` takes a string containing a filesystem path and converts it
+to an absolute path. That is, if the path is not absolute, it will be joined
+with the current working directory.
+
+Referring directly to filesystem paths in resource arguments may cause
+spurious diffs if the same configuration is applied from multiple systems or on
+different host operating systems. We recommend using filesystem paths only
+for transient values, such as the argument to [`file`](/terraform/language/functions/file) (where
+only the contents are then stored) or in `connection` and `provisioner` blocks.
+
+## Examples
+
+```
+> abspath(path.root)
+/home/user/some/terraform/root
+```
diff --git a/v1.5.7/website/docs/language/functions/alltrue.mdx b/v1.5.7/website/docs/language/functions/alltrue.mdx
new file mode 100644
index 0000000..4236b71
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/alltrue.mdx
@@ -0,0 +1,26 @@
+---
+page_title: alltrue - Functions - Configuration Language
+description: |-
+  The alltrue function determines whether all elements of a collection
+  are true or "true". If the collection is empty, it returns true.
+---
+
+# `alltrue` Function
+
+-> **Note:** This function is available in Terraform 0.14 and later.
+
+`alltrue` returns `true` if all elements in a given collection are `true`
+or `"true"`. It also returns `true` if the collection is empty.
+
+```hcl
+alltrue(list)
+```
+
+## Examples
+
+```command
+> alltrue(["true", true])
+true
+> alltrue([true, false])
+false
+```
diff --git a/v1.5.7/website/docs/language/functions/anytrue.mdx b/v1.5.7/website/docs/language/functions/anytrue.mdx
new file mode 100644
index 0000000..4f3fb45
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/anytrue.mdx
@@ -0,0 +1,30 @@
+---
+page_title: anytrue - Functions - Configuration Language
+description: |-
+  The anytrue function determines whether any element of a collection
+  is true or "true". If the collection is empty, it returns false.
+---
+
+# `anytrue` Function
+
+-> **Note:** This function is available in Terraform 0.14 and later.
+
+`anytrue` returns `true` if any element in a given collection is `true`
+or `"true"`. It also returns `false` if the collection is empty.
+
+```hcl
+anytrue(list)
+```
+
+## Examples
+
+```command
+> anytrue(["true"])
+true
+> anytrue([true])
+true
+> anytrue([true, false])
+true
+> anytrue([])
+false
+```
diff --git a/v1.5.7/website/docs/language/functions/base64decode.mdx b/v1.5.7/website/docs/language/functions/base64decode.mdx
new file mode 100644
index 0000000..0e0ddf1
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/base64decode.mdx
@@ -0,0 +1,46 @@
+---
+page_title: base64decode - Functions - Configuration Language
+description: The base64decode function decodes a string containing a base64 sequence.
+---
+
+# `base64decode` Function
+
+`base64decode` takes a string containing a Base64 character sequence and
+returns the original string.
+
+Terraform uses the "standard" Base64 alphabet as defined in
+[RFC 4648 section 4](https://tools.ietf.org/html/rfc4648#section-4).
+
+Strings in the Terraform language are sequences of unicode characters rather
+than bytes, so this function will also interpret the resulting bytes as
+UTF-8. If the bytes after Base64 decoding are _not_ valid UTF-8, this function
+produces an error.
+
+While we do not recommend manipulating large, raw binary data in the Terraform
+language, Base64 encoding is the standard way to represent arbitrary byte
+sequences, and so resource types that accept or return binary data will use
+Base64 themselves, which avoids the need to encode or decode it directly in
+most cases. Various other functions with names containing "base64" can generate
+or manipulate Base64 data directly.
+
+`base64decode` is, in effect, a shorthand for calling
+[`textdecodebase64`](/terraform/language/functions/textdecodebase64) with the encoding name set to
+`UTF-8`.
+
+## Examples
+
+```
+> base64decode("SGVsbG8gV29ybGQ=")
+Hello World
+```
+
+## Related Functions
+
+* [`base64encode`](/terraform/language/functions/base64encode) performs the opposite operation,
+  encoding the UTF-8 bytes for a string as Base64.
+* [`textdecodebase64`](/terraform/language/functions/textdecodebase64) is a more general function that
+  supports character encodings other than UTF-8.
+* [`base64gzip`](/terraform/language/functions/base64gzip) applies gzip compression to a string
+  and returns the result with Base64 encoding.
+* [`filebase64`](/terraform/language/functions/filebase64) reads a file from the local filesystem
+  and returns its raw bytes with Base64 encoding.
diff --git a/v1.5.7/website/docs/language/functions/base64encode.mdx b/v1.5.7/website/docs/language/functions/base64encode.mdx
new file mode 100644
index 0000000..1c4d6fd
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/base64encode.mdx
@@ -0,0 +1,48 @@
+---
+page_title: base64encode - Functions - Configuration Language
+description: The base64encode function applies Base64 encoding to a string.
+---
+
+# `base64encode` Function
+
+`base64encode` applies Base64 encoding to a string.
+
+Terraform uses the "standard" Base64 alphabet as defined in
+[RFC 4648 section 4](https://tools.ietf.org/html/rfc4648#section-4).
+
+Strings in the Terraform language are sequences of unicode characters rather
+than bytes, so this function will first encode the characters from the string
+as UTF-8, and then apply Base64 encoding to the result.
+
+The Terraform language applies Unicode normalization to all strings, and so
+passing a string through `base64decode` and then `base64encode` may not yield
+the original result exactly.
+
+While we do not recommend manipulating large, raw binary data in the Terraform
+language, Base64 encoding is the standard way to represent arbitrary byte
+sequences, and so resource types that accept or return binary data will use
+Base64 themselves, and so this function exists primarily to allow string
+data to be easily provided to resource types that expect Base64 bytes.
+
+`base64encode` is, in effect, a shorthand for calling
+[`textencodebase64`](/terraform/language/functions/textencodebase64) with the encoding name set to
+`UTF-8`.
+
+## Examples
+
+```
+> base64encode("Hello World")
+SGVsbG8gV29ybGQ=
+```
+
+## Related Functions
+
+* [`base64decode`](/terraform/language/functions/base64decode) performs the opposite operation,
+  decoding Base64 data and interpreting it as a UTF-8 string.
+* [`textencodebase64`](/terraform/language/functions/textencodebase64) is a more general function that
+  supports character encodings other than UTF-8.
+* [`base64gzip`](/terraform/language/functions/base64gzip) applies gzip compression to a string
+  and returns the result with Base64 encoding all in one operation.
+* [`filebase64`](/terraform/language/functions/filebase64) reads a file from the local filesystem
+  and returns its raw bytes with Base64 encoding, without creating an
+  intermediate Unicode string.
diff --git a/v1.5.7/website/docs/language/functions/base64gzip.mdx b/v1.5.7/website/docs/language/functions/base64gzip.mdx
new file mode 100644
index 0000000..2620e20
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/base64gzip.mdx
@@ -0,0 +1,31 @@
+---
+page_title: base64gzip - Functions - Configuration Language
+description: |-
+  The base64encode function compresses the given string with gzip and then
+  encodes the result in Base64.
+---
+
+# `base64gzip` Function
+
+`base64gzip` compresses a string with gzip and then encodes the result in
+Base64 encoding.
+
+Terraform uses the "standard" Base64 alphabet as defined in
+[RFC 4648 section 4](https://tools.ietf.org/html/rfc4648#section-4).
+
+Strings in the Terraform language are sequences of unicode characters rather
+than bytes, so this function will first encode the characters from the string
+as UTF-8, then apply gzip compression, and then finally apply Base64 encoding.
+
+While we do not recommend manipulating large, raw binary data in the Terraform
+language, this function can be used to compress reasonably sized text strings
+generated within the Terraform language. For example, the result of this
+function can be used to create a compressed object in Amazon S3 as part of
+an S3 website.
+
+## Related Functions
+
+* [`base64encode`](/terraform/language/functions/base64encode) applies Base64 encoding _without_
+  gzip compression.
+* [`filebase64`](/terraform/language/functions/filebase64) reads a file from the local filesystem
+  and returns its raw bytes with Base64 encoding.
diff --git a/v1.5.7/website/docs/language/functions/base64sha256.mdx b/v1.5.7/website/docs/language/functions/base64sha256.mdx
new file mode 100644
index 0000000..7a1b340
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/base64sha256.mdx
@@ -0,0 +1,31 @@
+---
+page_title: base64sha256 - Functions - Configuration Language
+description: |-
+  The base64sha256 function computes the SHA256 hash of a given string and
+  encodes it with Base64.
+---
+
+# `base64sha256` Function
+
+`base64sha256` computes the SHA256 hash of a given string and encodes it with
+Base64. This is not equivalent to `base64encode(sha256("test"))` since `sha256()`
+returns hexadecimal representation.
+
+The given string is first encoded as UTF-8 and then the SHA256 algorithm is applied
+as defined in [RFC 4634](https://tools.ietf.org/html/rfc4634). The raw hash is
+then encoded with Base64 before returning. Terraform uses the "standard" Base64
+alphabet as defined in [RFC 4648 section 4](https://tools.ietf.org/html/rfc4648#section-4).
+
+## Examples
+
+```
+> base64sha256("hello world")
+uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=
+```
+
+## Related Functions
+
+* [`filebase64sha256`](/terraform/language/functions/filebase64sha256) calculates the same hash from
+  the contents of a file rather than from a string value.
+* [`sha256`](/terraform/language/functions/sha256) calculates the same hash but returns the result
+  in a more-verbose hexadecimal encoding.
diff --git a/v1.5.7/website/docs/language/functions/base64sha512.mdx b/v1.5.7/website/docs/language/functions/base64sha512.mdx
new file mode 100644
index 0000000..7b42628
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/base64sha512.mdx
@@ -0,0 +1,31 @@
+---
+page_title: base64sha512 - Functions - Configuration Language
+description: |-
+  The base64sha512 function computes the SHA512 hash of a given string and
+  encodes it with Base64.
+---
+
+# `base64sha512` Function
+
+`base64sha512` computes the SHA512 hash of a given string and encodes it with
+Base64. This is not equivalent to `base64encode(sha512("test"))` since `sha512()`
+returns hexadecimal representation.
+
+The given string is first encoded as UTF-8 and then the SHA512 algorithm is applied
+as defined in [RFC 4634](https://tools.ietf.org/html/rfc4634). The raw hash is
+then encoded with Base64 before returning. Terraform uses the "standard" Base64
+alphabet as defined in [RFC 4648 section 4](https://tools.ietf.org/html/rfc4648#section-4).
+
+## Examples
+
+```
+> base64sha512("hello world")
+MJ7MSJwS1utMxA9QyQLytNDtd+5RGnx6m808qG1M2G+YndNbxf9JlnDaNCVbRbDP2DDoH2Bdz33FVC6TrpzXbw==
+```
+
+## Related Functions
+
+* [`filebase64sha512`](/terraform/language/functions/filebase64sha512) calculates the same hash from
+  the contents of a file rather than from a string value.
+* [`sha512`](/terraform/language/functions/sha512) calculates the same hash but returns the result
+  in a more-verbose hexadecimal encoding.
diff --git a/v1.5.7/website/docs/language/functions/basename.mdx b/v1.5.7/website/docs/language/functions/basename.mdx
new file mode 100644
index 0000000..8f9262a
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/basename.mdx
@@ -0,0 +1,41 @@
+---
+page_title: basename - Functions - Configuration Language
+description: |-
+  The basename function removes all except the last portion from a filesystem
+  path.
+---
+
+# `basename` Function
+
+`basename` takes a string containing a filesystem path and removes all except
+the last portion from it.
+
+This function works only with the path string and does not access the
+filesystem itself. It is therefore unable to take into account filesystem
+features such as symlinks.
+
+If the path is empty then the result is `"."`, representing the current
+working directory.
+
+The behavior of this function depends on the host platform. On Windows systems,
+it uses backslash `\` as the path segment separator. On Unix systems, the slash
+`/` is used.
+
+Referring directly to filesystem paths in resource arguments may cause
+spurious diffs if the same configuration is applied from multiple systems or on
+different host operating systems. We recommend using filesystem paths only
+for transient values, such as the argument to [`file`](/terraform/language/functions/file) (where
+only the contents are then stored) or in `connection` and `provisioner` blocks.
+
+## Examples
+
+```
+> basename("foo/bar/baz.txt")
+baz.txt
+```
+
+## Related Functions
+
+* [`dirname`](/terraform/language/functions/dirname) returns all of the segments of a filesystem path
+  _except_ the last, discarding the portion that would be returned by
+  `basename`.
diff --git a/v1.5.7/website/docs/language/functions/bcrypt.mdx b/v1.5.7/website/docs/language/functions/bcrypt.mdx
new file mode 100644
index 0000000..ca6913f
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/bcrypt.mdx
@@ -0,0 +1,36 @@
+---
+page_title: bcrypt - Functions - Configuration Language
+description: |-
+  The bcrypt function computes a hash of the given string using the Blowfish
+  cipher.
+---
+
+# `bcrypt` Function
+
+`bcrypt` computes a hash of the given string using the Blowfish cipher,
+returning a string in
+[the _Modular Crypt Format_](https://passlib.readthedocs.io/en/stable/modular_crypt_format.html)
+usually expected in the shadow password file on many Unix systems.
+
+```hcl
+bcrypt(string, cost)
+```
+
+The `cost` argument is optional and will default to 10 if unspecified.
+
+Since a bcrypt hash value includes a randomly selected salt, each call to this
+function will return a different value, even if the given string and cost are
+the same. Using this function directly with resource arguments will therefore
+cause spurious diffs. We recommend using this function only in `provisioner`
+blocks, or in data resources whose results are only used in `provisioner`
+blocks.
+
+The version prefix on the generated string (e.g. `$2a$`) may change in future
+versions of Terraform.
+
+## Examples
+
+```
+> bcrypt("hello world")
+$2a$10$D5grTTzcsqyvAeIAnY/mYOIqliCoG7eAMX0/oFcuD.iErkksEbcAa
+```
diff --git a/v1.5.7/website/docs/language/functions/can.mdx b/v1.5.7/website/docs/language/functions/can.mdx
new file mode 100644
index 0000000..922b6f1
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/can.mdx
@@ -0,0 +1,74 @@
+---
+page_title: can - Functions - Configuration Language
+description: |-
+  The can function tries to evaluate an expression given as an argument and
+  indicates whether the evaluation succeeded.
+---
+
+# `can` Function
+
+`can` evaluates the given expression and returns a boolean value indicating
+whether the expression produced a result without any errors.
+
+This is a special function that is able to catch errors produced when evaluating
+its argument. For most situations where you could use `can` it's better to use
+[`try`](/terraform/language/functions/try) instead, because it allows for more concise definition of
+fallback values for failing expressions.
+
+The primary purpose of `can` is to turn an error condition into a boolean
+validation result when writing
+[custom variable validation rules](/terraform/language/values/variables#custom-validation-rules).
+For example:
+
+```
+variable "timestamp" {
+  type        = string
+
+  validation {
+    # formatdate fails if the second argument is not a valid timestamp
+    condition     = can(formatdate("", var.timestamp))
+    error_message = "The timestamp argument requires a valid RFC 3339 timestamp."
+  }
+}
+```
+
+The `can` function can only catch and handle _dynamic_ errors resulting from
+access to data that isn't known until runtime. It will not catch errors
+relating to expressions that can be proven to be invalid for any input, such
+as a malformed resource reference.
+
+~> **Warning:** The `can` function is intended only for simple tests in
+variable validation rules. Although it can technically accept any sort of
+expression and be used elsewhere in the configuration, we recommend against
+using it in other contexts. For error handling elsewhere in the configuration,
+prefer to use [`try`](/terraform/language/functions/try).
+
+## Examples
+
+```
+> local.foo
+{
+  "bar" = "baz"
+}
+> can(local.foo.bar)
+true
+> can(local.foo.boop)
+false
+```
+
+The `can` function will _not_ catch errors relating to constructs that are
+provably invalid even before dynamic expression evaluation, such as a malformed
+reference or a reference to a top-level object that has not been declared:
+
+```
+> can(local.nonexist)
+
+Error: Reference to undeclared local value
+
+A local value with the name "nonexist" has not been declared.
+```
+
+## Related Functions
+
+* [`try`](/terraform/language/functions/try), which tries evaluating a sequence of expressions and
+  returns the result of the first one that succeeds.
diff --git a/v1.5.7/website/docs/language/functions/ceil.mdx b/v1.5.7/website/docs/language/functions/ceil.mdx
new file mode 100644
index 0000000..0245a82
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/ceil.mdx
@@ -0,0 +1,25 @@
+---
+page_title: ceil - Functions - Configuration Language
+description: |-
+  The ceil function returns the closest whole number greater than or equal to
+  the given value.
+---
+
+# `ceil` Function
+
+`ceil` returns the closest whole number that is greater than or equal to the
+given value, which may be a fraction.
+
+## Examples
+
+```
+> ceil(5)
+5
+> ceil(5.1)
+6
+```
+
+## Related Functions
+
+* [`floor`](/terraform/language/functions/floor), which rounds to the nearest whole number _less than_
+  or equal.
diff --git a/v1.5.7/website/docs/language/functions/chomp.mdx b/v1.5.7/website/docs/language/functions/chomp.mdx
new file mode 100644
index 0000000..ff1b046
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/chomp.mdx
@@ -0,0 +1,27 @@
+---
+page_title: chomp - Functions - Configuration Language
+description: The chomp function removes newline characters at the end of a string.
+---
+
+# `chomp` Function
+
+`chomp` removes newline characters at the end of a string.
+
+This can be useful if, for example, the string was read from a file that has
+a newline character at the end.
+
+## Examples
+
+```
+> chomp("hello\n")
+hello
+> chomp("hello\r\n")
+hello
+> chomp("hello\n\n")
+hello
+```
+
+## Related Functions
+
+* [`trimspace`](/terraform/language/functions/trimspace), which removes all types of whitespace from
+  both the start and the end of a string.
diff --git a/v1.5.7/website/docs/language/functions/chunklist.mdx b/v1.5.7/website/docs/language/functions/chunklist.mdx
new file mode 100644
index 0000000..dcc793a
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/chunklist.mdx
@@ -0,0 +1,52 @@
+---
+page_title: chunklist - Functions - Configuration Language
+description: |-
+  The chunklist function splits a single list into fixed-size chunks, returning
+  a list of lists.
+---
+
+# `chunklist` Function
+
+`chunklist` splits a single list into fixed-size chunks, returning a list
+of lists.
+
+```hcl
+chunklist(list, chunk_size)
+```
+
+## Examples
+
+```
+> chunklist(["a", "b", "c", "d", "e"], 2)
+[
+  [
+    "a",
+    "b",
+  ],
+  [
+    "c",
+    "d",
+  ],
+  [
+    "e",
+  ],
+]
+> chunklist(["a", "b", "c", "d", "e"], 1)
+[
+  [
+    "a",
+  ],
+  [
+    "b",
+  ],
+  [
+    "c",
+  ],
+  [
+    "d",
+  ],
+  [
+    "e",
+  ],
+]
+```
diff --git a/v1.5.7/website/docs/language/functions/cidrhost.mdx b/v1.5.7/website/docs/language/functions/cidrhost.mdx
new file mode 100644
index 0000000..68cde0a
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/cidrhost.mdx
@@ -0,0 +1,54 @@
+---
+page_title: cidrhost - Functions - Configuration Language
+description: |-
+  The cidrhost function calculates a full host IP address within a given
+  IP network address prefix.
+---
+
+# `cidrhost` Function
+
+`cidrhost` calculates a full host IP address for a given host number within
+a given IP network address prefix.
+
+```hcl
+cidrhost(prefix, hostnum)
+```
+
+`prefix` must be given in CIDR notation, as defined in
+[RFC 4632 section 3.1](https://tools.ietf.org/html/rfc4632#section-3.1).
+
+`hostnum` is a whole number that can be represented as a binary integer with
+no more than the number of digits remaining in the address after the given
+prefix. For more details on how this function interprets CIDR prefixes and
+populates host numbers, see the worked example for
+[`cidrsubnet`](/terraform/language/functions/cidrsubnet).
+
+Conventionally host number zero is used to represent the address of the
+network itself and the host number that would fill all the host bits with
+binary 1 represents the network's broadcast address. These numbers should
+generally not be used to identify individual hosts except in unusual
+situations, such as point-to-point links.
+
+This function accepts both IPv6 and IPv4 prefixes, and the result always uses
+the same addressing scheme as the given prefix.
+
+-> **Note:** As a historical accident, this function interprets IPv4 address
+octets that have leading zeros as decimal numbers, which is contrary to some
+other systems which interpret them as octal. We have preserved this behavior
+for backward compatibility, but recommend against relying on this behavior.
+
+## Examples
+
+```
+> cidrhost("10.12.112.0/20", 16)
+10.12.112.16
+> cidrhost("10.12.112.0/20", 268)
+10.12.113.12
+> cidrhost("fd00:fd12:3456:7890:00a2::/72", 34)
+fd00:fd12:3456:7890::22
+```
+
+## Related Functions
+
+* [`cidrsubnet`](/terraform/language/functions/cidrsubnet) calculates a subnet address under a given
+  network address prefix.
diff --git a/v1.5.7/website/docs/language/functions/cidrnetmask.mdx b/v1.5.7/website/docs/language/functions/cidrnetmask.mdx
new file mode 100644
index 0000000..f8d5d71
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/cidrnetmask.mdx
@@ -0,0 +1,36 @@
+---
+page_title: cidrnetmask - Functions - Configuration Language
+description: |-
+  The cidrnetmask function converts an IPv4 address prefix given in CIDR
+  notation into a subnet mask address.
+---
+
+# `cidrnetmask` Function
+
+`cidrnetmask` converts an IPv4 address prefix given in CIDR notation into
+a subnet mask address.
+
+```hcl
+cidrnetmask(prefix)
+```
+
+`prefix` must be given in IPv4 CIDR notation, as defined in
+[RFC 4632 section 3.1](https://tools.ietf.org/html/rfc4632#section-3.1).
+
+The result is a subnet address formatted in the conventional dotted-decimal
+IPv4 address syntax, as expected by some software.
+
+CIDR notation is the only valid notation for IPv6 addresses, so `cidrnetmask`
+produces an error if given an IPv6 address.
+
+-> **Note:** As a historical accident, this function interprets IPv4 address
+octets that have leading zeros as decimal numbers, which is contrary to some
+other systems which interpret them as octal. We have preserved this behavior
+for backward compatibility, but recommend against relying on this behavior.
+
+## Examples
+
+```
+> cidrnetmask("172.16.0.0/12")
+255.240.0.0
+```
diff --git a/v1.5.7/website/docs/language/functions/cidrsubnet.mdx b/v1.5.7/website/docs/language/functions/cidrsubnet.mdx
new file mode 100644
index 0000000..8ee8b1c
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/cidrsubnet.mdx
@@ -0,0 +1,171 @@
+---
+page_title: cidrsubnet - Functions - Configuration Language
+description: |-
+  The cidrsubnet function calculates a subnet address within a given IP network
+  address prefix.
+---
+
+# `cidrsubnet` Function
+
+`cidrsubnet` calculates a subnet address within given IP network address prefix.
+
+```hcl
+cidrsubnet(prefix, newbits, netnum)
+```
+
+`prefix` must be given in CIDR notation, as defined in
+[RFC 4632 section 3.1](https://tools.ietf.org/html/rfc4632#section-3.1).
+
+`newbits` is the number of additional bits with which to extend the prefix.
+For example, if given a prefix ending in `/16` and a `newbits` value of
+`4`, the resulting subnet address will have length `/20`.
+
+`netnum` is a whole number that can be represented as a binary integer with
+no more than `newbits` binary digits, which will be used to populate the
+additional bits added to the prefix.
+
+This function accepts both IPv6 and IPv4 prefixes, and the result always uses
+the same addressing scheme as the given prefix.
+
+Unlike the related function [`cidrsubnets`](/terraform/language/functions/cidrsubnets), `cidrsubnet`
+allows you to give a specific network number to use. `cidrsubnets` can allocate
+multiple network addresses at once, but numbers them automatically starting
+with zero.
+
+-> **Note:** As a historical accident, this function interprets IPv4 address
+octets that have leading zeros as decimal numbers, which is contrary to some
+other systems which interpret them as octal. We have preserved this behavior
+for backward compatibility, but recommend against relying on this behavior.
+
+## Examples
+
+```
+> cidrsubnet("172.16.0.0/12", 4, 2)
+172.18.0.0/16
+> cidrsubnet("10.1.2.0/24", 4, 15)
+10.1.2.240/28
+> cidrsubnet("fd00:fd12:3456:7890::/56", 16, 162)
+fd00:fd12:3456:7800:a200::/72
+```
+
+## Netmasks and Subnets
+
+Using `cidrsubnet` requires familiarity with some network addressing concepts.
+
+The most important idea is that an IP address (whether IPv4 or IPv6) is
+fundamentally constructed from binary digits, even though we conventionally
+represent it as either four decimal octets (for IPv4) or a sequence of 16-bit
+hexadecimal numbers (for IPv6).
+
+Taking our example above of `cidrsubnet("10.1.2.0/24", 4, 15)`, the function
+will first convert the given IP address string into an equivalent binary
+representation:
+
+```
+      10 .        1 .        2 .        0
+00001010   00000001   00000010 | 00000000
+         network               |   host
+```
+
+The `/24` at the end of the prefix string specifies that the first 24
+bits -- or, the first three octets -- of the address identify the network
+while the remaining bits (32 - 24 = 8 bits in this case) identify hosts
+within the network.
+
+The CLI tool [`ipcalc`](https://gitlab.com/ipcalc/ipcalc) is useful for
+visualizing CIDR prefixes as binary numbers. We can confirm the conversion
+above by providing the same prefix string to `ipcalc`:
+
+```
+$ ipcalc 10.1.2.0/24
+Address:   10.1.2.0             00001010.00000001.00000010. 00000000
+Netmask:   255.255.255.0 = 24   11111111.11111111.11111111. 00000000
+Wildcard:  0.0.0.255            00000000.00000000.00000000. 11111111
+=>
+Network:   10.1.2.0/24          00001010.00000001.00000010. 00000000
+HostMin:   10.1.2.1             00001010.00000001.00000010. 00000001
+HostMax:   10.1.2.254           00001010.00000001.00000010. 11111110
+Broadcast: 10.1.2.255           00001010.00000001.00000010. 11111111
+Hosts/Net: 254                   Class A, Private Internet
+```
+
+This gives us some additional information but also confirms (using a slightly
+different notation) the conversion from decimal to binary and shows the range
+of possible host addresses in this network.
+
+While [`cidrhost`](/terraform/language/functions/cidrhost) allows calculating single host IP addresses,
+`cidrsubnet` on the other hand creates a new network prefix _within_ the given
+network prefix. In other words, it creates a subnet.
+
+When we call `cidrsubnet` we also pass two additional arguments: `newbits` and
+`netnum`. `newbits` decides how much longer the resulting prefix will be in
+bits; in our example here we specified `4`, which means that the resulting
+subnet will have a prefix length of 24 + 4 = 28 bits. We can imagine these
+bits breaking down as follows:
+
+```
+      10 .        1 .        2 .    ?        0
+00001010   00000001   00000010 |   XXXX | 0000
+         parent network        | netnum | host
+```
+
+Four of the eight bits that were originally the "host number" are now being
+repurposed as the subnet number. The network prefix no longer falls on an
+exact octet boundary, so in effect we are now splitting the last decimal number
+in the IP address into two parts, using half of it to represent the subnet
+number and the other half to represent the host number.
+
+The `netnum` argument then decides what number value to encode into those
+four new subnet bits. In our current example we passed `15`, which is
+represented in binary as `1111`, allowing us to fill in the `XXXX` segment
+in the above:
+
+```
+      10 .        1 .        2 .    15       0
+00001010   00000001   00000010 |   1111 | 0000
+         parent network        | netnum | host
+```
+
+To convert this back into normal decimal notation we need to recombine the
+two portions of the final octet. Converting `11110000` from binary to decimal
+gives 240, which can then be combined with our new prefix length of 28 to
+produce the result `10.1.2.240/28`. Again we can pass this prefix string to
+`ipcalc` to visualize it:
+
+```
+$ ipcalc 10.1.2.240/28
+Address:   10.1.2.240           00001010.00000001.00000010.1111 0000
+Netmask:   255.255.255.240 = 28 11111111.11111111.11111111.1111 0000
+Wildcard:  0.0.0.15             00000000.00000000.00000000.0000 1111
+=>
+Network:   10.1.2.240/28        00001010.00000001.00000010.1111 0000
+HostMin:   10.1.2.241           00001010.00000001.00000010.1111 0001
+HostMax:   10.1.2.254           00001010.00000001.00000010.1111 1110
+Broadcast: 10.1.2.255           00001010.00000001.00000010.1111 1111
+Hosts/Net: 14                    Class A, Private Internet
+```
+
+The new subnet has four bits available for host numbering, which means
+that there are 14 host addresses available for assignment once we subtract
+the network's own address and the broadcast address. You can thus use
+[`cidrhost`](/terraform/language/functions/cidrhost) function to calculate those host addresses by
+providing it a value between 1 and 14:
+
+```
+> cidrhost("10.1.2.240/28", 1)
+10.1.2.241
+> cidrhost("10.1.2.240/28", 14)
+10.1.2.254
+```
+
+For more information on CIDR notation and subnetting, see
+[Classless Inter-domain Routing](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing).
+
+## Related Functions
+
+* [`cidrhost`](/terraform/language/functions/cidrhost) calculates the IP address for a single host
+  within a given network address prefix.
+* [`cidrnetmask`](/terraform/language/functions/cidrnetmask) converts an IPv4 network prefix in CIDR
+  notation into netmask notation.
+* [`cidrsubnets`](/terraform/language/functions/cidrsubnets) can allocate multiple consecutive
+  addresses under a prefix at once, numbering them automatically.
diff --git a/v1.5.7/website/docs/language/functions/cidrsubnets.mdx b/v1.5.7/website/docs/language/functions/cidrsubnets.mdx
new file mode 100644
index 0000000..0dfd573
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/cidrsubnets.mdx
@@ -0,0 +1,104 @@
+---
+page_title: cidrsubnets - Functions - Configuration Language
+description: |-
+  The cidrsubnets function calculates a sequence of consecutive IP address
+  ranges within a particular CIDR prefix.
+---
+
+# `cidrsubnets` Function
+
+`cidrsubnets` calculates a sequence of consecutive IP address ranges within
+a particular CIDR prefix.
+
+```hcl
+cidrsubnets(prefix, newbits...)
+```
+
+`prefix` must be given in CIDR notation, as defined in
+[RFC 4632 section 3.1](https://tools.ietf.org/html/rfc4632#section-3.1).
+
+The remaining arguments, indicated as `newbits` above, each specify the number
+of additional network prefix bits for one returned address range. The return
+value is therefore a list with one element per `newbits` argument, each
+a string containing an address range in CIDR notation.
+
+For more information on IP addressing concepts, see the documentation for the
+related function [`cidrsubnet`](/terraform/language/functions/cidrsubnet). `cidrsubnet` calculates
+a single subnet address within a prefix while allowing you to specify its
+subnet number, while `cidrsubnets` can calculate many at once, potentially of
+different sizes, and assigns subnet numbers automatically.
+
+When using this function to partition an address space as part of a network
+address plan, you must not change any of the existing arguments once network
+addresses have been assigned to real infrastructure, or else later address
+assignments will be invalidated. However, you _can_ append new arguments to
+existing calls safely, as long as there is sufficient address space available.
+
+This function accepts both IPv6 and IPv4 prefixes, and the result always uses
+the same addressing scheme as the given prefix.
+
+-> **Note:** As a historical accident, this function interprets IPv4 address
+octets that have leading zeros as decimal numbers, which is contrary to some
+other systems which interpret them as octal. We have preserved this behavior
+for backward compatibility, but recommend against relying on this behavior.
+
+-> **Note:** [The Terraform module `hashicorp/subnets/cidr`](https://registry.terraform.io/modules/hashicorp/subnets/cidr)
+wraps `cidrsubnets` to provide additional functionality for assigning symbolic
+names to your networks and skipping prefixes for obsolete allocations. Its
+documentation includes usage examples for several popular cloud virtual network
+platforms.
+
+## Examples
+
+```
+> cidrsubnets("10.1.0.0/16", 4, 4, 8, 4)
+[
+  "10.1.0.0/20",
+  "10.1.16.0/20",
+  "10.1.32.0/24",
+  "10.1.48.0/20",
+]
+
+> cidrsubnets("fd00:fd12:3456:7890::/56", 16, 16, 16, 32)
+[
+  "fd00:fd12:3456:7800::/72",
+  "fd00:fd12:3456:7800:100::/72",
+  "fd00:fd12:3456:7800:200::/72",
+  "fd00:fd12:3456:7800:300::/88",
+]
+```
+
+You can use nested `cidrsubnets` calls with
+[`for` expressions](/terraform/language/expressions/for)
+to concisely allocate groups of network address blocks:
+
+```
+> [for cidr_block in cidrsubnets("10.0.0.0/8", 8, 8, 8, 8) : cidrsubnets(cidr_block, 4, 4)]
+[
+  [
+    "10.0.0.0/20",
+    "10.0.16.0/20",
+  ],
+  [
+    "10.1.0.0/20",
+    "10.1.16.0/20",
+  ],
+  [
+    "10.2.0.0/20",
+    "10.2.16.0/20",
+  ],
+  [
+    "10.3.0.0/20",
+    "10.3.16.0/20",
+  ],
+]
+```
+
+## Related Functions
+
+* [`cidrhost`](/terraform/language/functions/cidrhost) calculates the IP address for a single host
+  within a given network address prefix.
+* [`cidrnetmask`](/terraform/language/functions/cidrnetmask) converts an IPv4 network prefix in CIDR
+  notation into netmask notation.
+* [`cidrsubnet`](/terraform/language/functions/cidrsubnet) calculates a single subnet address, allowing
+  you to specify its network number.
diff --git a/v1.5.7/website/docs/language/functions/coalesce.mdx b/v1.5.7/website/docs/language/functions/coalesce.mdx
new file mode 100644
index 0000000..fcbb646
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/coalesce.mdx
@@ -0,0 +1,56 @@
+---
+page_title: coalesce - Functions - Configuration Language
+description: |-
+  The coalesce function takes any number of arguments and returns the
+  first one that isn't null nor empty.
+---
+
+# `coalesce` Function
+
+`coalesce` takes any number of arguments and returns the first one
+that isn't null or an empty string.
+
+All of the arguments must be of the same type. Terraform will try to
+convert mismatched arguments to the most general of the types that all
+arguments can convert to, or return an error if the types are incompatible.
+The result type is the same as the type of all of the arguments.
+
+## Examples
+
+```
+> coalesce("a", "b")
+a
+> coalesce("", "b")
+b
+> coalesce(1,2)
+1
+```
+
+To perform the `coalesce` operation with a list of strings, use the `...`
+symbol to expand the list as arguments:
+
+```
+> coalesce(["", "b"]...)
+b
+```
+
+Terraform attempts to select a result type that all of the arguments can
+convert to, so mixing argument types may produce surprising results due to
+Terraform's automatic type conversion rules:
+
+```
+> coalesce(1, "hello")
+"1"
+> coalesce(true, "hello")
+"true"
+> coalesce({}, "hello")
+
+Error: Error in function call
+
+Call to function "coalesce" failed: all arguments must have the same type.
+```
+
+## Related Functions
+
+* [`coalescelist`](/terraform/language/functions/coalescelist) performs a similar operation with
+  list arguments rather than individual arguments.
diff --git a/v1.5.7/website/docs/language/functions/coalescelist.mdx b/v1.5.7/website/docs/language/functions/coalescelist.mdx
new file mode 100644
index 0000000..9d53dc0
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/coalescelist.mdx
@@ -0,0 +1,42 @@
+---
+page_title: coalescelist - Functions - Configuration Language
+description: |-
+  The coalescelist function takes any number of list arguments and returns the
+  first one that isn't empty.
+---
+
+# `coalescelist` Function
+
+`coalescelist` takes any number of list arguments and returns the first one
+that isn't empty.
+
+## Examples
+
+```
+> coalescelist(["a", "b"], ["c", "d"])
+[
+  "a",
+  "b",
+]
+> coalescelist([], ["c", "d"])
+[
+  "c",
+  "d",
+]
+```
+
+To perform the `coalescelist` operation with a list of lists, use the `...`
+symbol to expand the outer list as arguments:
+
+```
+> coalescelist([[], ["c", "d"]]...)
+[
+  "c",
+  "d",
+]
+```
+
+## Related Functions
+
+* [`coalesce`](/terraform/language/functions/coalesce) performs a similar operation with string
+  arguments rather than list arguments.
diff --git a/v1.5.7/website/docs/language/functions/compact.mdx b/v1.5.7/website/docs/language/functions/compact.mdx
new file mode 100644
index 0000000..92321d6
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/compact.mdx
@@ -0,0 +1,20 @@
+---
+page_title: compact - Functions - Configuration Language
+description: The compact function removes null or empty string elements from a list.
+---
+
+# `compact` Function
+
+`compact` takes a list of strings and returns a new list with any null or empty string
+elements removed.
+
+## Examples
+
+```
+> compact(["a", "", "b", null, "c"])
+[
+  "a",
+  "b",
+  "c",
+]
+```
diff --git a/v1.5.7/website/docs/language/functions/concat.mdx b/v1.5.7/website/docs/language/functions/concat.mdx
new file mode 100644
index 0000000..89c7496
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/concat.mdx
@@ -0,0 +1,20 @@
+---
+page_title: concat - Functions - Configuration Language
+description: The concat function combines two or more lists into a single list.
+---
+
+# `concat` Function
+
+`concat` takes two or more lists and combines them into a single list.
+
+## Examples
+
+```
+> concat(["a", ""], ["b", "c"])
+[
+  "a",
+  "",
+  "b",
+  "c",
+]
+```
diff --git a/v1.5.7/website/docs/language/functions/contains.mdx b/v1.5.7/website/docs/language/functions/contains.mdx
new file mode 100644
index 0000000..2b6239c
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/contains.mdx
@@ -0,0 +1,22 @@
+---
+page_title: contains - Functions - Configuration Language
+description: The contains function determines whether a list or set contains a given value.
+---
+
+# `contains` Function
+
+`contains` determines whether a given list or set contains a given single value
+as one of its elements.
+
+```hcl
+contains(list, value)
+```
+
+## Examples
+
+```
+> contains(["a", "b", "c"], "a")
+true
+> contains(["a", "b", "c"], "d")
+false
+```
diff --git a/v1.5.7/website/docs/language/functions/csvdecode.mdx b/v1.5.7/website/docs/language/functions/csvdecode.mdx
new file mode 100644
index 0000000..2af18af
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/csvdecode.mdx
@@ -0,0 +1,95 @@
+---
+page_title: csvdecode - Functions - Configuration Language
+description: The csvdecode function decodes CSV data into a list of maps.
+---
+
+# `csvdecode` Function
+
+`csvdecode` decodes a string containing CSV-formatted data and produces a
+list of maps representing that data.
+
+CSV is _Comma-separated Values_, an encoding format for tabular data. There
+are many variants of CSV, but this function implements the format defined
+in [RFC 4180](https://tools.ietf.org/html/rfc4180).
+
+The first line of the CSV data is interpreted as a "header" row: the values
+given are used as the keys in the resulting maps. Each subsequent line becomes
+a single map in the resulting list, matching the keys from the header row
+with the given values by index. All lines in the file must contain the same
+number of fields, or this function will produce an error.
+
+## Examples
+
+```
+> csvdecode("a,b,c\n1,2,3\n4,5,6")
+[
+  {
+    "a" = "1"
+    "b" = "2"
+    "c" = "3"
+  },
+  {
+    "a" = "4"
+    "b" = "5"
+    "c" = "6"
+  }
+]
+```
+
+## Use with the `for_each` meta-argument
+
+You can use the result of `csvdecode` with
+[the `for_each` meta-argument](/terraform/language/meta-arguments/for_each)
+to describe a collection of similar objects whose differences are
+described by the rows in the given CSV file.
+
+There must be one column in the CSV file that can serve as a unique id for each
+row, which we can then use as the tracking key for the individual instances in
+the `for_each` expression. For example:
+
+```hcl
+locals {
+  # We've included this inline to create a complete example, but in practice
+  # this is more likely to be loaded from a file using the "file" function.
+  csv_data = <<-CSV
+    local_id,instance_type,ami
+    foo1,t2.micro,ami-54d2a63b
+    foo2,t2.micro,ami-54d2a63b
+    foo3,t2.micro,ami-54d2a63b
+    bar1,m3.large,ami-54d2a63b
+  CSV
+
+  instances = csvdecode(local.csv_data)
+}
+
+resource "aws_instance" "example" {
+  for_each = { for inst in local.instances : inst.local_id => inst }
+
+  instance_type = each.value.instance_type
+  ami           = each.value.ami
+}
+```
+
+The `for` expression in our `for_each` argument transforms the list produced
+by `csvdecode` into a map using the `local_id` as a key, which tells
+Terraform to use the `local_id` value to track each instance it creates.
+Terraform will create and manage the following instance addresses:
+
+- `aws_instance.example["foo1"]`
+- `aws_instance.example["foo2"]`
+- `aws_instance.example["foo3"]`
+- `aws_instance.example["bar1"]`
+
+If you modify a row in the CSV on a subsequent plan, Terraform will interpret
+that as an update to the existing object as long as the `local_id` value is
+unchanged. If you add or remove rows from the CSV then Terraform will plan to
+create or destroy associated instances as appropriate.
+
+If there is no reasonable value you can use as a unique identifier in your CSV
+then you could instead use
+[the `count` meta-argument](/terraform/language/meta-arguments/count)
+to define an object for each CSV row, with each one identified by its index into
+the list returned by `csvdecode`. However, in that case any future updates to
+the CSV may be disruptive if they change the positions of particular objects in
+the list. We recommend using `for_each` with a unique id column to make
+behavior more predictable on future changes.
diff --git a/v1.5.7/website/docs/language/functions/dirname.mdx b/v1.5.7/website/docs/language/functions/dirname.mdx
new file mode 100644
index 0000000..1b4ab32
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/dirname.mdx
@@ -0,0 +1,39 @@
+---
+page_title: dirname - Functions - Configuration Language
+description: The dirname function removes the last portion from a filesystem path.
+---
+
+# `dirname` Function
+
+`dirname` takes a string containing a filesystem path and removes the last
+portion from it.
+
+This function works only with the path string and does not access the
+filesystem itself. It is therefore unable to take into account filesystem
+features such as symlinks.
+
+If the path is empty then the result is `"."`, representing the current
+working directory.
+
+The behavior of this function depends on the host platform. On Windows systems,
+it uses backslash `\` as the path segment separator. On Unix systems, the slash
+`/` is used. The result of this function is normalized, so on a Windows system
+any slashes in the given path will be replaced by backslashes before returning.
+
+Referring directly to filesystem paths in resource arguments may cause
+spurious diffs if the same configuration is applied from multiple systems or on
+different host operating systems. We recommend using filesystem paths only
+for transient values, such as the argument to [`file`](/terraform/language/functions/file) (where
+only the contents are then stored) or in `connection` and `provisioner` blocks.
+
+## Examples
+
+```
+> dirname("foo/bar/baz.txt")
+foo/bar
+```
+
+## Related Functions
+
+* [`basename`](/terraform/language/functions/basename) returns _only_ the last portion of a filesystem
+  path, discarding the portion that would be returned by `dirname`.
diff --git a/v1.5.7/website/docs/language/functions/distinct.mdx b/v1.5.7/website/docs/language/functions/distinct.mdx
new file mode 100644
index 0000000..95025de
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/distinct.mdx
@@ -0,0 +1,24 @@
+---
+page_title: distinct - Functions - Configuration Language
+description: The distinct function removes duplicate elements from a list.
+---
+
+# `distinct` Function
+
+`distinct` takes a list and returns a new list with any duplicate elements
+removed.
+
+The first occurrence of each value is retained and the relative ordering of
+these elements is preserved.
+
+## Examples
+
+```
+> distinct(["a", "b", "a", "c", "d", "b"])
+[
+  "a",
+  "b",
+  "c",
+  "d",
+]
+```
diff --git a/v1.5.7/website/docs/language/functions/element.mdx b/v1.5.7/website/docs/language/functions/element.mdx
new file mode 100644
index 0000000..06e89f8
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/element.mdx
@@ -0,0 +1,47 @@
+---
+page_title: element - Functions - Configuration Language
+description: The element function retrieves a single element from a list.
+---
+
+# `element` Function
+
+`element` retrieves a single element from a list.
+
+```hcl
+element(list, index)
+```
+
+The index is zero-based. This function produces an error if used with an
+empty list. The index must be a non-negative integer.
+
+Use the built-in index syntax `list[index]` in most cases. Use this function
+only for the special additional "wrap-around" behavior described below.
+
+## Examples
+
+```
+> element(["a", "b", "c"], 1)
+b
+```
+
+If the given index is greater than the length of the list then the index is
+"wrapped around" by taking the index modulo the length of the list:
+
+```
+> element(["a", "b", "c"], 3)
+a
+```
+
+To get the last element from the list use [`length`](/terraform/language/functions/length) to find
+the size of the list (minus 1 as the list is zero-based) and then pick the
+last element:
+
+```
+> element(["a", "b", "c"], length(["a", "b", "c"])-1)
+c
+```
+
+## Related Functions
+
+* [`index`](/terraform/language/functions/index_function) finds the index for a particular element value.
+* [`lookup`](/terraform/language/functions/lookup) retrieves a value from a _map_ given its _key_.
diff --git a/v1.5.7/website/docs/language/functions/endswith.mdx b/v1.5.7/website/docs/language/functions/endswith.mdx
new file mode 100644
index 0000000..d6e5601
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/endswith.mdx
@@ -0,0 +1,27 @@
+---
+page_title: endswith - Functions - Configuration Language
+description: |-
+  The endswith function takes two values: a string to check and a suffix string. It returns true if the first string ends with that exact suffix.
+---
+
+# `endswith` Function
+
+`endswith` takes two values: a string to check and a suffix string. The function returns true if the first string ends with that exact suffix.
+
+```hcl
+endswith(string, suffix)
+```
+
+## Examples
+
+```
+> endswith("hello world", "world")
+true
+
+> endswith("hello world", "hello")
+false
+```
+
+## Related Functions
+
+- [`startswith`](/terraform/language/functions/startswith) takes two values: a string to check and a prefix string. The function returns true if the string begins with that exact prefix.
diff --git a/v1.5.7/website/docs/language/functions/file.mdx b/v1.5.7/website/docs/language/functions/file.mdx
new file mode 100644
index 0000000..1c9872b
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/file.mdx
@@ -0,0 +1,46 @@
+---
+page_title: file - Functions - Configuration Language
+description: |-
+  The file function reads the contents of the file at the given path and
+  returns them as a string.
+---
+
+# `file` Function
+
+`file` reads the contents of a file at the given path and returns them as
+a string.
+
+```hcl
+file(path)
+```
+
+Strings in the Terraform language are sequences of Unicode characters, so
+this function will interpret the file contents as UTF-8 encoded text and
+return the resulting Unicode characters. If the file contains invalid UTF-8
+sequences then this function will produce an error.
+
+This function can be used only with files that already exist on disk
+at the beginning of a Terraform run. Functions do not participate in the
+dependency graph, so this function cannot be used with files that are generated
+dynamically during a Terraform operation. We do not recommend using dynamic
+local files in Terraform configurations, but in rare situations where this is
+necessary you can use
+[the `local_file` data source](https://registry.terraform.io/providers/hashicorp/local/latest/docs/data-sources/file)
+to read files while respecting resource dependencies.
+
+## Examples
+
+```
+> file("${path.module}/hello.txt")
+Hello World
+```
+
+## Related Functions
+
+* [`filebase64`](/terraform/language/functions/filebase64) also reads the contents of a given file,
+  but returns the raw bytes in that file Base64-encoded, rather than
+  interpreting the contents as UTF-8 text.
+* [`fileexists`](/terraform/language/functions/fileexists) determines whether a file exists
+  at a given path.
+* [`templatefile`](/terraform/language/functions/templatefile) renders using a file from disk as a
+  template.
diff --git a/v1.5.7/website/docs/language/functions/filebase64.mdx b/v1.5.7/website/docs/language/functions/filebase64.mdx
new file mode 100644
index 0000000..15c46ac
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/filebase64.mdx
@@ -0,0 +1,46 @@
+---
+page_title: filebase64 - Functions - Configuration Language
+description: |-
+  The filebase64 function reads the contents of the file at the given path and
+  returns them as a base64-encoded string.
+---
+
+# `filebase64` Function
+
+`filebase64` reads the contents of a file at the given path and returns them as
+a base64-encoded string.
+
+```hcl
+filebase64(path)
+```
+
+The result is a Base64 representation of the raw bytes in the given file.
+Strings in the Terraform language are sequences of Unicode characters, so
+Base64 is the standard way to represent raw binary data that cannot be
+interpreted as Unicode characters. Resource types that operate on binary
+data will accept this data encoded in Base64, thus avoiding the need to
+decode the result of this function.
+
+Terraform uses the "standard" Base64 alphabet as defined in
+[RFC 4648 section 4](https://tools.ietf.org/html/rfc4648#section-4).
+
+This function can be used only with functions that already exist as static
+files on disk at the beginning of a Terraform run. Language functions do not
+participate in the dependency graph, so this function cannot be used with
+files that are generated dynamically during a Terraform operation.
+
+## Examples
+
+```
+> filebase64("${path.module}/hello.txt")
+SGVsbG8gV29ybGQ=
+```
+
+## Related Functions
+
+* [`file`](/terraform/language/functions/file) also reads the contents of a given file,
+  but interprets the data as UTF-8 text and returns the result directly
+  as a string, without any further encoding.
+* [`base64decode`](/terraform/language/functions/base64decode) can decode a Base64 string representing
+  bytes in UTF-8, but in practice `base64decode(filebase64(...))` is equivalent
+  to the shorter expression `file(...)`.
diff --git a/v1.5.7/website/docs/language/functions/filebase64sha256.mdx b/v1.5.7/website/docs/language/functions/filebase64sha256.mdx
new file mode 100644
index 0000000..2cdee34
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/filebase64sha256.mdx
@@ -0,0 +1,15 @@
+---
+page_title: filebase64sha256 - Functions - Configuration Language
+description: |-
+  The filebase64sha256 function computes the SHA256 hash of the contents of
+  a given file and encodes it with Base64.
+---
+
+# `filebase64sha256` Function
+
+`filebase64sha256` is a variant of [`base64sha256`](/terraform/language/functions/base64sha256)
+that hashes the contents of a given file rather than a literal string.
+
+This is similar to `base64sha256(file(filename))`, but
+because [`file`](/terraform/language/functions/file) accepts only UTF-8 text it cannot be used to
+create hashes for binary files.
diff --git a/v1.5.7/website/docs/language/functions/filebase64sha512.mdx b/v1.5.7/website/docs/language/functions/filebase64sha512.mdx
new file mode 100644
index 0000000..0fd09cb
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/filebase64sha512.mdx
@@ -0,0 +1,15 @@
+---
+page_title: filebase64sha512 - Functions - Configuration Language
+description: |-
+  The filebase64sha512 function computes the SHA512 hash of the contents of
+  a given file and encodes it with Base64.
+---
+
+# `filebase64sha512` Function
+
+`filebase64sha512` is a variant of [`base64sha512`](/terraform/language/functions/base64sha512)
+that hashes the contents of a given file rather than a literal string.
+
+This is similar to `base64sha512(file(filename))`, but
+because [`file`](/terraform/language/functions/file) accepts only UTF-8 text it cannot be used to
+create hashes for binary files.
diff --git a/v1.5.7/website/docs/language/functions/fileexists.mdx b/v1.5.7/website/docs/language/functions/fileexists.mdx
new file mode 100644
index 0000000..b95585f
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/fileexists.mdx
@@ -0,0 +1,34 @@
+---
+page_title: fileexists - Functions - Configuration Language
+description: The fileexists function determines whether a file exists at a given path.
+---
+
+# `fileexists` Function
+
+`fileexists` determines whether a file exists at a given path.
+
+```hcl
+fileexists(path)
+```
+
+Functions are evaluated during configuration parsing rather than at apply time,
+so this function can only be used with files that are already present on disk
+before Terraform takes any actions.
+
+This function works only with regular files. If used with a directory, FIFO,
+or other special mode, it will return an error.
+
+## Examples
+
+```
+> fileexists("${path.module}/hello.txt")
+true
+```
+
+```hcl
+fileexists("custom-section.sh") ? file("custom-section.sh") : local.default_content
+```
+
+## Related Functions
+
+* [`file`](/terraform/language/functions/file) reads the contents of a file at a given path
diff --git a/v1.5.7/website/docs/language/functions/filemd5.mdx b/v1.5.7/website/docs/language/functions/filemd5.mdx
new file mode 100644
index 0000000..3470ba9
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/filemd5.mdx
@@ -0,0 +1,15 @@
+---
+page_title: filemd5 - Functions - Configuration Language
+description: |-
+  The filemd5 function computes the MD5 hash of the contents of
+  a given file and encodes it as hex.
+---
+
+# `filemd5` Function
+
+`filemd5` is a variant of [`md5`](/terraform/language/functions/md5)
+that hashes the contents of a given file rather than a literal string.
+
+This is similar to `md5(file(filename))`, but
+because [`file`](/terraform/language/functions/file) accepts only UTF-8 text it cannot be used to
+create hashes for binary files.
diff --git a/v1.5.7/website/docs/language/functions/fileset.mdx b/v1.5.7/website/docs/language/functions/fileset.mdx
new file mode 100644
index 0000000..3a1661c
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/fileset.mdx
@@ -0,0 +1,77 @@
+---
+page_title: fileset - Functions - Configuration Language
+description: The fileset function enumerates a set of regular file names given a pattern.
+---
+
+# `fileset` Function
+
+`fileset` enumerates a set of regular file names given a path and pattern.
+The path is automatically removed from the resulting set of file names and any
+result still containing path separators always returns forward slash (`/`) as
+the path separator for cross-system compatibility.
+
+```hcl
+fileset(path, pattern)
+```
+
+Supported pattern matches:
+
+- `*` - matches any sequence of non-separator characters
+- `**` - matches any sequence of characters, including separator characters
+- `?` - matches any single non-separator character
+- `{alternative1,...}` - matches a sequence of characters if one of the comma-separated alternatives matches
+- `[CLASS]` - matches any single non-separator character inside a class of characters (see below)
+- `[^CLASS]` - matches any single non-separator character outside a class of characters (see below)
+
+Note that the doublestar (`**`) must appear as a path component by itself. A
+pattern such as /path\*\* is invalid and will be treated the same as /path\*, but
+/path\*/\*\* should achieve the desired result.
+
+Character classes support the following:
+
+- `[abc]` - matches any single character within the set
+- `[a-z]` - matches any single character within the range
+
+Functions are evaluated during configuration parsing rather than at apply time,
+so this function can only be used with files that are already present on disk
+before Terraform takes any actions.
+
+## Examples
+
+```
+> fileset(path.module, "files/*.txt")
+[
+  "files/hello.txt",
+  "files/world.txt",
+]
+
+> fileset(path.module, "files/{hello,world}.txt")
+[
+  "files/hello.txt",
+  "files/world.txt",
+]
+
+> fileset("${path.module}/files", "*")
+[
+  "hello.txt",
+  "world.txt",
+]
+
+> fileset("${path.module}/files", "**")
+[
+  "hello.txt",
+  "world.txt",
+  "subdirectory/anotherfile.txt",
+]
+```
+
+A common use of `fileset` is to create one resource instance per matched file, using
+[the `for_each` meta-argument](/terraform/language/meta-arguments/for_each):
+
+```hcl
+resource "example_thing" "example" {
+  for_each = fileset(path.module, "files/*")
+
+  # other configuration using each.value
+}
+```
diff --git a/v1.5.7/website/docs/language/functions/filesha1.mdx b/v1.5.7/website/docs/language/functions/filesha1.mdx
new file mode 100644
index 0000000..a2b56ce
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/filesha1.mdx
@@ -0,0 +1,15 @@
+---
+page_title: filesha1 - Functions - Configuration Language
+description: |-
+  The filesha1 function computes the SHA1 hash of the contents of
+  a given file and encodes it as hex.
+---
+
+# `filesha1` Function
+
+`filesha1` is a variant of [`sha1`](/terraform/language/functions/sha1)
+that hashes the contents of a given file rather than a literal string.
+
+This is similar to `sha1(file(filename))`, but
+because [`file`](/terraform/language/functions/file) accepts only UTF-8 text it cannot be used to
+create hashes for binary files.
diff --git a/v1.5.7/website/docs/language/functions/filesha256.mdx b/v1.5.7/website/docs/language/functions/filesha256.mdx
new file mode 100644
index 0000000..2592ac4
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/filesha256.mdx
@@ -0,0 +1,15 @@
+---
+page_title: filesha256 - Functions - Configuration Language
+description: |-
+  The filesha256 function computes the SHA256 hash of the contents of
+  a given file and encodes it as hex.
+---
+
+# `filesha256` Function
+
+`filesha256` is a variant of [`sha256`](/terraform/language/functions/sha256)
+that hashes the contents of a given file rather than a literal string.
+
+This is similar to `sha256(file(filename))`, but
+because [`file`](/terraform/language/functions/file) accepts only UTF-8 text it cannot be used to
+create hashes for binary files.
diff --git a/v1.5.7/website/docs/language/functions/filesha512.mdx b/v1.5.7/website/docs/language/functions/filesha512.mdx
new file mode 100644
index 0000000..a616446
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/filesha512.mdx
@@ -0,0 +1,15 @@
+---
+page_title: filesha512 - Functions - Configuration Language
+description: |-
+  The filesha512 function computes the SHA512 hash of the contents of
+  a given file and encodes it as hex.
+---
+
+# `filesha512` Function
+
+`filesha512` is a variant of [`sha512`](/terraform/language/functions/sha512)
+that hashes the contents of a given file rather than a literal string.
+
+This is similar to `sha512(file(filename))`, but
+because [`file`](/terraform/language/functions/file) accepts only UTF-8 text it cannot be used to
+create hashes for binary files.
diff --git a/v1.5.7/website/docs/language/functions/flatten.mdx b/v1.5.7/website/docs/language/functions/flatten.mdx
new file mode 100644
index 0000000..b94c7d8
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/flatten.mdx
@@ -0,0 +1,106 @@
+---
+page_title: flatten - Functions - Configuration Language
+description: The flatten function eliminates nested lists from a list.
+---
+
+# `flatten` Function
+
+`flatten` takes a list and replaces any elements that are lists with a
+flattened sequence of the list contents.
+
+## Examples
+
+```
+> flatten([["a", "b"], [], ["c"]])
+["a", "b", "c"]
+```
+
+If any of the nested lists also contain directly-nested lists, these too are
+flattened recursively:
+
+```
+> flatten([[["a", "b"], []], ["c"]])
+["a", "b", "c"]
+```
+
+Indirectly-nested lists, such as those in maps, are _not_ flattened.
+
+## Flattening nested structures for `for_each`
+
+The
+[resource `for_each`](/terraform/language/meta-arguments/for_each)
+and
+[`dynamic` block](/terraform/language/expressions/dynamic-blocks)
+language features both require a collection value that has one element for
+each repetition.
+
+Sometimes your input data structure isn't naturally in a suitable shape for
+use in a `for_each` argument, and `flatten` can be a useful helper function
+when reducing a nested data structure into a flat one.
+
+For example, consider a module that declares a variable like the following:
+
+```hcl
+variable "networks" {
+  type = map(object({
+    cidr_block = string
+    subnets    = map(object({ cidr_block = string }))
+  }))
+}
+```
+
+The above is a reasonable way to model objects that naturally form a tree,
+such as top-level networks and their subnets. The repetition for the top-level
+networks can use this variable directly, because it's already in a form
+where the resulting instances match one-to-one with map elements:
+
+```hcl
+resource "aws_vpc" "example" {
+  for_each = var.networks
+
+  cidr_block = each.value.cidr_block
+}
+```
+
+However, in order to declare all of the _subnets_ with a single `resource`
+block, we must first flatten the structure to produce a collection where each
+top-level element represents a single subnet:
+
+```hcl
+locals {
+  # flatten ensures that this local value is a flat list of objects, rather
+  # than a list of lists of objects.
+  network_subnets = flatten([
+    for network_key, network in var.networks : [
+      for subnet_key, subnet in network.subnets : {
+        network_key = network_key
+        subnet_key  = subnet_key
+        network_id  = aws_vpc.example[network_key].id
+        cidr_block  = subnet.cidr_block
+      }
+    ]
+  ])
+}
+
+resource "aws_subnet" "example" {
+  # local.network_subnets is a list, so we must now project it into a map
+  # where each key is unique. We'll combine the network and subnet keys to
+  # produce a single unique key per instance.
+  for_each = {
+    for subnet in local.network_subnets : "${subnet.network_key}.${subnet.subnet_key}" => subnet
+  }
+
+  vpc_id            = each.value.network_id
+  availability_zone = each.value.subnet_key
+  cidr_block        = each.value.cidr_block
+}
+```
+
+The above results in one subnet instance per subnet object, while retaining
+the associations between the subnets and their containing networks.
+
+## Related Functions
+
+* [`setproduct`](/terraform/language/functions/setproduct) finds all of the combinations of multiple
+  lists or sets of values, which can also be useful when preparing collections
+  for use with `for_each` constructs.
diff --git a/v1.5.7/website/docs/language/functions/floor.mdx b/v1.5.7/website/docs/language/functions/floor.mdx
new file mode 100644
index 0000000..c40b0e5
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/floor.mdx
@@ -0,0 +1,25 @@
+---
+page_title: floor - Functions - Configuration Language
+description: |-
+  The floor function returns the closest whole number less than or equal to
+  the given value.
+---
+
+# `floor` Function
+
+`floor` returns the closest whole number that is less than or equal to the
+given value, which may be a fraction.
+
+## Examples
+
+```
+> floor(5)
+5
+> floor(4.9)
+4
+```
+
+## Related Functions
+
+* [`ceil`](/terraform/language/functions/ceil), which rounds to the nearest whole number _greater than_
+  or equal.
diff --git a/v1.5.7/website/docs/language/functions/format.mdx b/v1.5.7/website/docs/language/functions/format.mdx
new file mode 100644
index 0000000..4053f17
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/format.mdx
@@ -0,0 +1,145 @@
+---
+page_title: format - Functions - Configuration Language
+description: |-
+  The format function produces a string by formatting a number of other values
+  according to a specification string.
+---
+
+# `format` Function
+
+The `format` function produces a string by formatting a number of other values according
+to a specification string. It is similar to the `printf` function in C, and
+other similar functions in other programming languages.
+
+```hcl
+format(spec, values...)
+```
+
+## Examples
+
+```
+> format("Hello, %s!", "Ander")
+Hello, Ander!
+> format("There are %d lights", 4)
+There are 4 lights
+```
+
+Simple format verbs like `%s` and `%d` behave similarly to template
+interpolation syntax, which is often more readable.
+
+```
+> format("Hello, %s!", var.name)
+Hello, Valentina!
+> "Hello, ${var.name}!"
+Hello, Valentina!
+```
+
+The formatting verb `%#v` accepts a value of any type and presents it using JSON encoding, similar to jsonencode. This can be useful for describing the values given to a module in [custom condition check](/terraform/language/expressions/custom-conditions#error-messages) error messages.
+
+```
+> format("%#v", "hello")
+"\"hello\""
+> format("%#v", true)
+"true"
+> format("%#v", 1)
+"1"
+> format("%#v", {a = 1})
+"{\"a\":1}"
+> format("%#v", [true])
+"[true]"
+> format("%#v", null)
+"null"
+```
+
+The `format` function is most useful when you use more complex format specifications.
+
+## Specification Syntax
+
+The specification is a string that includes formatting verbs that are introduced
+with the `%` character. The function call must then have one additional argument
+for each verb sequence in the specification. The verbs are matched with
+consecutive arguments and formatted as directed, as long as each given argument
+is convertible to the type required by the format verb.
+
+By default, `%` sequences consume successive arguments starting with the first.
+Introducing a `[n]` sequence immediately before the verb letter, where `n` is a
+decimal integer, explicitly chooses a particular value argument by its
+one-based index. Subsequent calls without an explicit index will then proceed
+with `n`+1, `n`+2, etc.
+
+The function produces an error if the format string requests an impossible
+conversion or access more arguments than are given. An error is produced also
+for an unsupported format verb.
+
+### Verbs
+
+The specification may contain the following verbs.
+
+| Verb  | Result                                                                                    |
+| ----- | ----------------------------------------------------------------------------------------- |
+| `%%`  | Literal percent sign, consuming no value.                                                 |
+| `%v`  | Default formatting based on the [value type](#default-format-verbs). Accepts all types, including items of `null`, `list`, and `map` types.                           |
+| `%#v` | JSON serialization of the value, as with `jsonencode`. Accepts all types, including items of `null`, `list`, and `map` types.  |
+| `%t`  | Convert to boolean and produce `true` or `false`.                                         |
+| `%b`  | Convert to integer number and produce binary representation.                              |
+| `%d`  | Convert to integer number and produce decimal representation.                             |
+| `%o`  | Convert to integer number and produce octal representation.                               |
+| `%x`  | Convert to integer number and produce hexadecimal representation with lowercase letters.  |
+| `%X`  | Like `%x`, but use uppercase letters.                                                     |
+| `%e`  | Convert to number and produce scientific notation, like `-1.234456e+78`.                  |
+| `%E`  | Like `%e`, but use an uppercase `E` to introduce the exponent.                            |
+| `%f`  | Convert to number and produce decimal fraction notation with no exponent, like `123.456`. |
+| `%g`  | Like `%e` for large exponents or like `%f` otherwise.                                     |
+| `%G`  | Like `%E` for large exponents or like `%f` otherwise.                                     |
+| `%s`  | Convert to string and insert the string's characters.                                     |
+| `%q`  | Convert to string and produce a JSON quoted string representation.                        |
+
+### Default Format Verbs
+
+When `%v` is used, Terraform chooses the appropriate format verb based on the value type.
+
+| Type      | Verb  |
+| --------- | ----- |
+| `string`  | `%s`  |
+| `number`  | `%g`  |
+| `bool`    | `%t`  |
+| any other | `%#v` |
+
+Null values produce the string `null` if formatted with `%v` or `%#v`, and cause an error for other verbs.
+
+### Width Modifier
+
+Use a width modifier with an optional decimal number immediately
+preceding the verb letter to specify how many characters will be used to represent the value. You can specify precision after the (optional) width with a period (`.`) followed by a decimal number. If width or precision are omitted, Terraform selects default values based on the given value.
+
+The following examples demonstrate example use cases for the width modifier.
+
+| Sequence | Result                       |
+| -------- | ---------------------------- |
+| `%f`     | Default width and precision. |
+| `%9f`    | Width 9, default precision.  |
+| `%.2f`   | Default width, precision 2.  |
+| `%9.2f`  | Width 9, precision 2.        |
+
+-> **Note:** Width and precision modifiers with non-numeric types such as
+strings (`%s`) are interpreted differently. Setting either width or precision to
+zero is the same as not including them at all.
+
+### Additional Format Options
+
+Use the following symbols immediately after the `%` symbol to set additional formatting requirements.
+
+| Symbol | Result                                                         |
+| ------ | -------------------------------------------------------------- |
+| space  | Leave a space where the sign would be if a number is positive. |
+| `+`    | Show the sign of a number even if it is positive.              |
+| `-`    | Pad the width with spaces on the right rather than the left.   |
+| `0`    | Pad the width with leading zeros rather than spaces.           |
+
+
+## Related Functions
+
+* [`formatdate`](/terraform/language/functions/formatdate) is a specialized formatting function for
+  human-readable timestamps.
+* [`formatlist`](/terraform/language/functions/formatlist) uses the same specification syntax to
+  produce a list of strings.
diff --git a/v1.5.7/website/docs/language/functions/formatdate.mdx b/v1.5.7/website/docs/language/functions/formatdate.mdx
new file mode 100644
index 0000000..358536d
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/formatdate.mdx
@@ -0,0 +1,105 @@
+---
+page_title: formatdate - Functions - Configuration Language
+description: The formatdate function converts a timestamp into a different time format.
+---
+
+# `formatdate` Function
+
+`formatdate` converts a timestamp into a different time format.
+
+```hcl
+formatdate(spec, timestamp)
+```
+
+In the Terraform language, timestamps are conventionally represented as
+strings using [RFC 3339](https://tools.ietf.org/html/rfc3339)
+"Date and Time format" syntax. `formatdate` requires the `timestamp` argument
+to be a string conforming to this syntax.
+
+## Examples
+
+```
+> formatdate("DD MMM YYYY hh:mm ZZZ", "2018-01-02T23:12:01Z")
+02 Jan 2018 23:12 UTC
+> formatdate("EEEE, DD-MMM-YY hh:mm:ss ZZZ", "2018-01-02T23:12:01Z")
+Tuesday, 02-Jan-18 23:12:01 UTC
+> formatdate("EEE, DD MMM YYYY hh:mm:ss ZZZ", "2018-01-02T23:12:01-08:00")
+Tue, 02 Jan 2018 23:12:01 -0800
+> formatdate("MMM DD, YYYY", "2018-01-02T23:12:01Z")
+Jan 02, 2018
+> formatdate("HH:mmaa", "2018-01-02T23:12:01Z")
+11:12pm
+```
+
+## Specification Syntax
+
+The format specification is a string that includes formatting sequences from
+the following table. This function is intended for producing common
+_machine-oriented_ timestamp formats such as those defined in RFC822, RFC850,
+and RFC1123. It is not suitable for truly human-oriented date formatting
+because it is not locale-aware. In particular, it can produce month and day
+names only in English.
+
+The specification may contain the following sequences:
+
+| Sequence | Result                                                                  |
+| -------- | ----------------------------------------------------------------------- |
+| `YYYY`   | Four (or more) digit year, like "2006".                                 |
+| `YY`     | The year modulo 100, zero padded to at least two digits, like "06".     |
+| `MMMM`   | English month name unabbreviated, like "January".                       |
+| `MMM`    | English month name abbreviated to three letters, like "Jan".            |
+| `MM`     | Month number zero-padded to two digits, like "01" for January.          |
+| `M`      | Month number with no padding, like "1" for January.                     |
+| `DD`     | Day of month number zero-padded to two digits, like "02".               |
+| `D`      | Day of month number with no padding, like "2".                          |
+| `EEEE`   | English day of week name unabbreviated, like "Monday".                  |
+| `EEE`    | English day of week name abbreviated to three letters, like "Mon".      |
+| `hh`     | 24-hour number zero-padded to two digits, like "02".                    |
+| `h`      | 24-hour number unpadded, like "2".                                      |
+| `HH`     | 12-hour number zero-padded to two digits, like "02".                    |
+| `H`      | 12-hour number unpadded, like "2".                                      |
+| `AA`     | Hour AM/PM marker in uppercase, like "AM".                              |
+| `aa`     | Hour AM/PM marker in lowercase, like "am".                              |
+| `mm`     | Minute within hour zero-padded to two digits, like "05".                |
+| `m`      | Minute within hour unpadded, like "5".                                  |
+| `ss`     | Second within minute zero-padded to two digits, like "09".              |
+| `s`      | Second within minute, like "9".                                         |
+| `ZZZZZ`  | Timezone offset with colon separating hours and minutes, like "-08:00". |
+| `ZZZZ`   | Timezone offset with just sign and digit, like "-0800".                 |
+| `ZZZ`    | Like `ZZZZ` but with a special case "UTC" for UTC.                      |
+| `Z`      | Like `ZZZZZ` but with a special case "Z" for UTC.                       |
+
+Any non-letter characters, such as punctuation, are reproduced verbatim in the
+output. To include literal letters in the format string, enclose them in single
+quotes `'`. To include a literal quote, escape it by doubling the quotes.
+
+```
+> formatdate("h'h'mm", "2018-01-02T23:12:01-08:00")
+23h12
+> formatdate("H 'o''clock'", "2018-01-02T23:12:01-08:00")
+11 o'clock
+```
+
+This format specification syntax is intended to make it easy for a reader
+to guess which format will result even if they are not experts on the syntax.
+Therefore there are no predefined shorthands for common formats, but format
+strings for various RFC-specified formats are given below to be copied into your
+configuration as needed:
+
+- [RFC 822](https://tools.ietf.org/html/rfc822#section-5) and
+  [RFC RFC 2822](https://tools.ietf.org/html/rfc2822#section-3.3):
+  `"DD MMM YYYY hh:mm ZZZ"`
+- [RFC 850](https://tools.ietf.org/html/rfc850#section-2.1.4):
+  `"EEEE, DD-MMM-YY hh:mm:ss ZZZ"`
+- [RFC 1123](https://tools.ietf.org/html/rfc1123#section-5.2.14):
+  `"EEE, DD MMM YYYY hh:mm:ss ZZZ"`
+- [RFC 3339](https://tools.ietf.org/html/rfc3339):
+  `"YYYY-MM-DD'T'hh:mm:ssZ"` (but this is also the input format, so such a
+  conversion is redundant.)
+
+## Related Functions
+
+- [`format`](/terraform/language/functions/format) is a more general formatting function for arbitrary
+  data.
+- [`timestamp`](/terraform/language/functions/timestamp) returns the current date and time in a format
+  suitable for input to `formatdate`.
diff --git a/v1.5.7/website/docs/language/functions/formatlist.mdx b/v1.5.7/website/docs/language/functions/formatlist.mdx
new file mode 100644
index 0000000..3d96865
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/formatlist.mdx
@@ -0,0 +1,49 @@
+---
+page_title: formatlist - Functions - Configuration Language
+description: |-
+  The formatlist function produces a list of strings by formatting a number of
+  other values according to a specification string.
+---
+
+# `formatlist` Function
+
+`formatlist` produces a list of strings by formatting a number of other
+values according to a specification string.
+
+```hcl
+formatlist(spec, values...)
+```
+
+The specification string uses
+[the same syntax as `format`](/terraform/language/functions/format#specification-syntax).
+
+The given values can be a mixture of list and non-list arguments. Any given
+lists must be the same length, which decides the length of the resulting list.
+
+The list arguments are iterated together in order by index, while the non-list
+arguments are used repeatedly for each iteration. The format string is evaluated
+once per element of the list arguments.
+
+## Examples
+
+```
+> formatlist("Hello, %s!", ["Valentina", "Ander", "Olivia", "Sam"])
+[
+  "Hello, Valentina!",
+  "Hello, Ander!",
+  "Hello, Olivia!",
+  "Hello, Sam!",
+]
+> formatlist("%s, %s!", "Salutations", ["Valentina", "Ander", "Olivia", "Sam"])
+[
+  "Salutations, Valentina!",
+  "Salutations, Ander!",
+  "Salutations, Olivia!",
+  "Salutations, Sam!",
+]
+```
+
+## Related Functions
+
+* [`format`](/terraform/language/functions/format) defines the specification syntax used by this
+  function and produces a single string as its result.
diff --git a/v1.5.7/website/docs/language/functions/indent.mdx b/v1.5.7/website/docs/language/functions/indent.mdx
new file mode 100644
index 0000000..0f79340
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/indent.mdx
@@ -0,0 +1,31 @@
+---
+page_title: indent - Functions - Configuration Language
+description: |-
+  The indent function adds a number of spaces to the beginnings of all but the
+  first line of a given multi-line string.
+---
+
+# `indent` Function
+
+`indent` adds a given number of spaces to the beginnings of all but the first
+line in a given multi-line string.
+
+```hcl
+indent(num_spaces, string)
+```
+
+## Examples
+
+This function is useful for inserting a multi-line string into an
+already-indented context in another string:
+
+```
+> "  items: ${indent(2, "[\n  foo,\n  bar,\n]\n")}"
+  items: [
+    foo,
+    bar,
+  ]
+```
+
+The first line of the string is not indented so that, as above, it can be
+placed after an introduction sequence that has already begun the line.
diff --git a/v1.5.7/website/docs/language/functions/index.mdx b/v1.5.7/website/docs/language/functions/index.mdx
new file mode 100644
index 0000000..a8f1519
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/index.mdx
@@ -0,0 +1,38 @@
+---
+page_title: Functions - Configuration Language
+description: >-
+  An introduction to the built-in functions that you can use to transform and
+  combine values in expressions.
+---
+
+# Built-in Functions
+
+> **Hands-on:** Try the [Perform Dynamic Operations with Functions](/terraform/tutorials/configuration-language/functions?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+The Terraform language includes a number of built-in functions that you can
+call from within expressions to transform and combine values. The general
+syntax for function calls is a function name followed by comma-separated
+arguments in parentheses:
+
+```hcl
+max(5, 12, 9)
+```
+
+For more details on syntax, see
+[_Function Calls_](/terraform/language/expressions/function-calls)
+in the Expressions section.
+
+The Terraform language does not support user-defined functions, and so only
+the functions built in to the language are available for use. The documentation includes a page for all of the available built-in functions.
+
+You can experiment with the behavior of Terraform's built-in functions from
+the Terraform expression console, by running
+[the `terraform console` command](/terraform/cli/commands/console):
+
+```
+> max(5, 12, 9)
+12
+```
+
+The examples in the documentation for each function use console output to
+illustrate the result of calling the function with different parameters.
diff --git a/v1.5.7/website/docs/language/functions/index_function.mdx b/v1.5.7/website/docs/language/functions/index_function.mdx
new file mode 100644
index 0000000..aae7015
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/index_function.mdx
@@ -0,0 +1,27 @@
+---
+page_title: index - Functions - Configuration Language
+description: The index function finds the element index for a given value in a list.
+---
+
+# `index` Function
+
+`index` finds the element index for a given value in a list.
+
+```hcl
+index(list, value)
+```
+
+The returned index is zero-based. This function produces an error if the given
+value is not present in the list.
+
+## Examples
+
+```
+> index(["a", "b", "c"], "b")
+1
+```
+
+## Related Functions
+
+* [`element`](/terraform/language/functions/element) retrieves a particular element from a list given
+  its index.
diff --git a/v1.5.7/website/docs/language/functions/join.mdx b/v1.5.7/website/docs/language/functions/join.mdx
new file mode 100644
index 0000000..a917553
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/join.mdx
@@ -0,0 +1,31 @@
+---
+page_title: join - Functions - Configuration Language
+description: |-
+  The join function produces a string by concatenating the elements of a list
+  with a given delimiter.
+---
+
+# `join` Function
+
+`join` produces a string by concatenating all of the elements of the specified
+list of strings with the specified separator.
+
+```hcl
+join(separator, list)
+```
+
+## Examples
+
+```
+> join("-", ["foo", "bar", "baz"])
+"foo-bar-baz"
+> join(", ", ["foo", "bar", "baz"])
+foo, bar, baz
+> join(", ", ["foo"])
+foo
+```
+
+## Related Functions
+
+* [`split`](/terraform/language/functions/split) performs the opposite operation: producing a list
+  by separating a single string using a given delimiter.
diff --git a/v1.5.7/website/docs/language/functions/jsondecode.mdx b/v1.5.7/website/docs/language/functions/jsondecode.mdx
new file mode 100644
index 0000000..e34322b
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/jsondecode.mdx
@@ -0,0 +1,46 @@
+---
+page_title: jsondecode - Functions - Configuration Language
+description: |-
+  The jsondecode function decodes a JSON string into a representation of its
+  value.
+---
+
+# `jsondecode` Function
+
+`jsondecode` interprets a given string as JSON, returning a representation
+of the result of decoding that string.
+
+The JSON encoding is defined in [RFC 7159](https://tools.ietf.org/html/rfc7159).
+
+This function maps JSON values to
+[Terraform language values](/terraform/language/expressions/types)
+in the following way:
+
+| JSON type | Terraform type                                               |
+| --------- | ------------------------------------------------------------ |
+| String    | `string`                                                     |
+| Number    | `number`                                                     |
+| Boolean   | `bool`                                                       |
+| Object    | `object(...)` with attribute types determined per this table |
+| Array     | `tuple(...)` with element types determined per this table    |
+| Null      | The Terraform language `null` value                          |
+
+The Terraform language automatic type conversion rules mean that you don't
+usually need to worry about exactly what type is produced for a given value,
+and can just use the result in an intuitive way.
+
+## Examples
+
+```
+> jsondecode("{\"hello\": \"world\"}")
+{
+  "hello" = "world"
+}
+> jsondecode("true")
+true
+```
+
+## Related Functions
+
+* [`jsonencode`](/terraform/language/functions/jsonencode) performs the opposite operation, _encoding_
+  a value as JSON.
diff --git a/v1.5.7/website/docs/language/functions/jsonencode.mdx b/v1.5.7/website/docs/language/functions/jsonencode.mdx
new file mode 100644
index 0000000..4afa3bc
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/jsonencode.mdx
@@ -0,0 +1,50 @@
+---
+page_title: jsonencode - Functions - Configuration Language
+description: The jsonencode function encodes a given value as a JSON string.
+---
+
+# `jsonencode` Function
+
+`jsonencode` encodes a given value to a string using JSON syntax.
+
+The JSON encoding is defined in [RFC 7159](https://tools.ietf.org/html/rfc7159).
+
+This function maps
+[Terraform language values](/terraform/language/expressions/types)
+to JSON values in the following way:
+
+| Terraform type | JSON type |
+| -------------- | --------- |
+| `string`       | String    |
+| `number`       | Number    |
+| `bool`         | Bool      |
+| `list(...)`    | Array     |
+| `set(...)`     | Array     |
+| `tuple(...)`   | Array     |
+| `map(...)`     | Object    |
+| `object(...)`  | Object    |
+| Null value     | `null`    |
+
+Since the JSON format cannot fully represent all of the Terraform language
+types, passing the `jsonencode` result to `jsondecode` will not produce an
+identical value, but the automatic type conversion rules mean that this is
+rarely a problem in practice.
+
+When encoding strings, this function escapes some characters using
+Unicode escape sequences: replacing `<`, `>`, `&`, `U+2028`, and `U+2029` with
+`\u003c`, `\u003e`, `\u0026`, `\u2028`, and `\u2029`. This is to preserve
+compatibility with Terraform 0.11 behavior.
+
+The `jsonencode` command outputs a minified representation of the input.
+
+## Examples
+
+```
+> jsonencode({"hello"="world"})
+{"hello":"world"}
+```
+
+## Related Functions
+
+* [`jsondecode`](/terraform/language/functions/jsondecode) performs the opposite operation, _decoding_
+  a JSON string to obtain its represented value.
diff --git a/v1.5.7/website/docs/language/functions/keys.mdx b/v1.5.7/website/docs/language/functions/keys.mdx
new file mode 100644
index 0000000..96a1553
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/keys.mdx
@@ -0,0 +1,26 @@
+---
+page_title: keys - Functions - Configuration Language
+description: The keys function returns a list of the keys in a given map.
+---
+
+# `keys` Function
+
+`keys` takes a map and returns a list containing the keys from that map.
+
+The keys are returned in lexicographical order, ensuring that the result will
+be identical as long as the keys in the map don't change.
+
+## Examples
+
+```
+> keys({a=1, c=2, d=3})
+[
+  "a",
+  "c",
+  "d",
+]
+```
+
+## Related Functions
+
+* [`values`](/terraform/language/functions/values) returns a list of the _values_ from a map.
diff --git a/v1.5.7/website/docs/language/functions/length.mdx b/v1.5.7/website/docs/language/functions/length.mdx
new file mode 100644
index 0000000..add12b5
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/length.mdx
@@ -0,0 +1,39 @@
+---
+page_title: length - Functions - Configuration Language
+description: The length function determines the length of a collection or string.
+---
+
+# `length` Function
+
+`length` determines the length of a given list, map, or string.
+
+If given a list or map, the result is the number of elements in that collection.
+If given a string, the result is the number of characters in the string.
+
+## Examples
+
+```
+> length([])
+0
+> length(["a", "b"])
+2
+> length({"a" = "b"})
+1
+> length("hello")
+5
+```
+
+When given a string, the result is the number of characters, rather than the
+number of bytes or Unicode sequences that form them:
+
+```
+> length("👾🕹️")
+2
+```
+
+A "character" is a _grapheme cluster_, as defined by
+[Unicode Standard Annex #29](http://unicode.org/reports/tr29/). Note that
+remote APIs may have a different definition of "character" for the purpose of
+length limits on string arguments; a Terraform provider is responsible for
+translating Terraform's string representation into that used by its respective
+remote system and applying any additional validation rules to it.
diff --git a/v1.5.7/website/docs/language/functions/list.mdx b/v1.5.7/website/docs/language/functions/list.mdx
new file mode 100644
index 0000000..2a1ffe2
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/list.mdx
@@ -0,0 +1,26 @@
+---
+page_title: list - Functions - Configuration Language
+description: The list function constructs a list from some given elements.
+---
+
+# `list` Function
+
+The `list` function is no longer available. Prior to Terraform v0.12 it was
+the only available syntax for writing a literal list inside an expression,
+but Terraform v0.12 introduced a new first-class syntax.
+
+To update an expression like `list(a, b, c)`, write the following instead:
+
+```
+tolist([a, b, c])
+```
+
+The `[ ... ]` brackets construct a tuple value, and then the `tolist` function
+then converts it to a list. For more information on the value types in the
+Terraform language, see [Type Constraints](/terraform/language/expressions/types).
+
+## Related Functions
+
+* [`concat`](/terraform/language/functions/concat) produces a new list by concatenating together the
+  elements from other lists.
+* [`tolist`](/terraform/language/functions/tolist) converts a set or tuple value to a list.
diff --git a/v1.5.7/website/docs/language/functions/log.mdx b/v1.5.7/website/docs/language/functions/log.mdx
new file mode 100644
index 0000000..7d9044e
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/log.mdx
@@ -0,0 +1,33 @@
+---
+page_title: log - Functions - Configuration Language
+description: The log function returns the logarithm of a given number in a given base.
+---
+
+# `log` Function
+
+`log` returns the logarithm of a given number in a given base.
+
+```hcl
+log(number, base)
+```
+
+## Examples
+
+```
+> log(50, 10)
+1.6989700043360185
+> log(16, 2)
+4
+```
+
+`log` and `ceil` can be used together to find the minimum number of binary
+digits required to represent a given number of distinct values:
+
+```
+> ceil(log(15, 2))
+4
+> ceil(log(16, 2))
+4
+> ceil(log(17, 2))
+5
+```
diff --git a/v1.5.7/website/docs/language/functions/lookup.mdx b/v1.5.7/website/docs/language/functions/lookup.mdx
new file mode 100644
index 0000000..98b2fdf
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/lookup.mdx
@@ -0,0 +1,30 @@
+---
+page_title: lookup - Functions - Configuration Language
+description: The lookup function retrieves an element value from a map given its key.
+---
+
+# `lookup` Function
+
+`lookup` retrieves the value of a single element from a map, given its key.
+If the given key does not exist, the given default value is returned instead.
+
+```
+lookup(map, key, default)
+```
+
+-> For historical reasons, the `default` parameter is actually optional. However,
+omitting `default` is deprecated since v0.7 because that would then be
+equivalent to the native index syntax, `map[key]`.
+
+## Examples
+
+```
+> lookup({a="ay", b="bee"}, "a", "what?")
+ay
+> lookup({a="ay", b="bee"}, "c", "what?")
+what?
+```
+
+## Related Functions
+
+* [`element`](/terraform/language/functions/element) retrieves a value from a _list_ given its _index_.
diff --git a/v1.5.7/website/docs/language/functions/lower.mdx b/v1.5.7/website/docs/language/functions/lower.mdx
new file mode 100644
index 0000000..2a4c249
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/lower.mdx
@@ -0,0 +1,26 @@
+---
+page_title: lower - Functions - Configuration Language
+description: >-
+  The lower function converts all cased letters in the given string to
+  lowercase.
+---
+
+# `lower` Function
+
+`lower` converts all cased letters in the given string to lowercase.
+
+## Examples
+
+```
+> lower("HELLO")
+hello
+> lower("АЛЛО!")
+алло!
+```
+
+This function uses Unicode's definition of letters and of upper- and lowercase.
+
+## Related Functions
+
+* [`upper`](/terraform/language/functions/upper) converts letters in a string to _uppercase_.
+* [`title`](/terraform/language/functions/title) converts the first letter of each word in a string to uppercase.
diff --git a/v1.5.7/website/docs/language/functions/map.mdx b/v1.5.7/website/docs/language/functions/map.mdx
new file mode 100644
index 0000000..42aceb6
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/map.mdx
@@ -0,0 +1,29 @@
+---
+page_title: map - Functions - Configuration Language
+description: The map function constructs a map from some given elements.
+---
+
+# `map` Function
+
+The `map` function is no longer available. Prior to Terraform v0.12 it was
+the only available syntax for writing a literal map inside an expression,
+but Terraform v0.12 introduced a new first-class syntax.
+
+To update an expression like `map("a", "b", "c", "d")`, write the following instead:
+
+```
+tomap({
+  a = "b"
+  c = "d"
+})
+```
+
+The `{ ... }` braces construct an object value, and then the `tomap` function
+then converts it to a map. For more information on the value types in the
+Terraform language, see [Type Constraints](/terraform/language/expressions/types).
+
+## Related Functions
+
+* [`tomap`](/terraform/language/functions/tomap) converts an object value to a map.
+* [`zipmap`](/terraform/language/functions/zipmap) constructs a map dynamically, by taking keys from
+  one list and values from another list.
diff --git a/v1.5.7/website/docs/language/functions/matchkeys.mdx b/v1.5.7/website/docs/language/functions/matchkeys.mdx
new file mode 100644
index 0000000..e700520
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/matchkeys.mdx
@@ -0,0 +1,70 @@
+---
+page_title: matchkeys - Functions - Configuration Language
+description: |-
+  The matchkeys function takes a subset of elements from one list by matching
+  corresponding indexes in another list.
+---
+
+# `matchkeys` Function
+
+`matchkeys` constructs a new list by taking a subset of elements from one
+list whose indexes match the corresponding indexes of values in another
+list.
+
+```hcl
+matchkeys(valueslist, keyslist, searchset)
+```
+
+`matchkeys` identifies the indexes in `keyslist` that are equal to elements of
+`searchset`, and then constructs a new list by taking those same indexes from
+`valueslist`. Both `valueslist` and `keyslist` must be the same length.
+
+The ordering of the values in `valueslist` is preserved in the result.
+
+## Examples
+
+```
+> matchkeys(["i-123", "i-abc", "i-def"], ["us-west", "us-east", "us-east"], ["us-east"])
+[
+  "i-abc",
+  "i-def",
+]
+```
+
+If the result ordering is not significant, you can achieve a similar result
+using a `for` expression with a map:
+
+```
+> [for i, z in {"i-123"="us-west","i-abc"="us-east","i-def"="us-east"}: i if z == "us-east"]
+[
+  "i-def",
+  "i-abc",
+]
+```
+
+If the keys and values of interest are attributes of objects in a list of
+objects then you can also achieve a similar result using a `for` expression
+with that list:
+
+```
+> [for x in [{id="i-123",zone="us-west"},{id="i-abc",zone="us-east"}]: x.id if x.zone == "us-east"]
+[
+  "i-abc",
+]
+```
+
+For example, the previous form can be used with the list of resource instances
+produced by a `resource` block with the `count` meta-attribute set, to filter
+the instances by matching one of the resource attributes:
+
+```
+> [for x in aws_instance.example: x.id if x.availability_zone == "us-east-1a"]
+[
+  "i-abc123",
+  "i-def456",
+]
+```
+
+Since the signature of `matchkeys` is complicated and not immediately clear to
+the reader when used in configuration, prefer to use `for` expressions where
+possible to maximize readability.
diff --git a/v1.5.7/website/docs/language/functions/max.mdx b/v1.5.7/website/docs/language/functions/max.mdx
new file mode 100644
index 0000000..05a4ee6
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/max.mdx
@@ -0,0 +1,27 @@
+---
+page_title: max - Functions - Configuration Language
+description: The max function takes one or more numbers and returns the greatest number.
+---
+
+# `max` Function
+
+`max` takes one or more numbers and returns the greatest number from the set.
+
+## Examples
+
+```
+> max(12, 54, 3)
+54
+```
+
+If the numbers are in a list or set value, use `...` to expand the collection
+to individual arguments:
+
+```
+> max([12, 54, 3]...)
+54
+```
+
+## Related Functions
+
+* [`min`](/terraform/language/functions/min), which returns the _smallest_ number from a set.
diff --git a/v1.5.7/website/docs/language/functions/md5.mdx b/v1.5.7/website/docs/language/functions/md5.mdx
new file mode 100644
index 0000000..199de34
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/md5.mdx
@@ -0,0 +1,31 @@
+---
+page_title: md5 - Functions - Configuration Language
+description: |-
+  The md5 function computes the MD5 hash of a given string and encodes it
+  with hexadecimal digits.
+---
+
+# `md5` Function
+
+`md5` computes the MD5 hash of a given string and encodes it with
+hexadecimal digits.
+
+The given string is first encoded as UTF-8 and then the MD5 algorithm is applied
+as defined in [RFC 1321](https://tools.ietf.org/html/rfc1321). The raw hash is
+then encoded to lowercase hexadecimal digits before returning.
+
+Before using this function for anything security-sensitive, refer to
+[RFC 6151](https://tools.ietf.org/html/rfc6151) for updated security
+considerations applying to the MD5 algorithm.
+
+## Examples
+
+```
+> md5("hello world")
+5eb63bbbe01eeed093cb22bb8f5acdc3
+```
+
+## Related Functions
+
+* [`filemd5`](/terraform/language/functions/filemd5) calculates the same hash from
+  the contents of a file rather than from a string value.
diff --git a/v1.5.7/website/docs/language/functions/merge.mdx b/v1.5.7/website/docs/language/functions/merge.mdx
new file mode 100644
index 0000000..6a3d230
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/merge.mdx
@@ -0,0 +1,51 @@
+---
+page_title: merge - Functions - Configuration Language
+description: |-
+  The merge function takes an arbitrary number maps or objects, and returns a
+  single map or object that contains a merged set of elements from all
+  arguments.
+---
+
+# `merge` Function
+
+`merge` takes an arbitrary number of maps or objects, and returns a single map
+or object that contains a merged set of elements from all arguments.
+
+If more than one given map or object defines the same key or attribute, then
+the one that is later in the argument sequence takes precedence. If the
+argument types do not match, the resulting type will be an object matching the
+type structure of the attributes after the merging rules have been applied.
+
+## Examples
+
+```
+> merge({a="b", c="d"}, {e="f", c="z"})
+{
+  "a" = "b"
+  "c" = "z"
+  "e" = "f"
+}
+```
+
+```
+> merge({a="b"}, {a=[1,2], c="z"}, {d=3})
+{
+  "a" = [
+    1,
+    2,
+  ]
+  "c" = "z"
+  "d" = 3
+}
+```
+
+The following example uses the expansion symbol (...) to transform the value into separate arguments. Refer to [Expanding Function Argument](/terraform/language/expressions/function-calls#expanding-function-arguments) for details.
+
+```
+> merge([{a="b", c="d"}, {}, {e="f", c="z"}]...)
+{
+  "a" = "b"
+  "c" = "z"
+  "e" = "f"
+}
+```
diff --git a/v1.5.7/website/docs/language/functions/min.mdx b/v1.5.7/website/docs/language/functions/min.mdx
new file mode 100644
index 0000000..f5388b2
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/min.mdx
@@ -0,0 +1,27 @@
+---
+page_title: min - Functions - Configuration Language
+description: The min function takes one or more numbers and returns the smallest number.
+---
+
+# `min` Function
+
+`min` takes one or more numbers and returns the smallest number from the set.
+
+## Examples
+
+```
+> min(12, 54, 3)
+3
+```
+
+If the numbers are in a list or set value, use `...` to expand the collection
+to individual arguments:
+
+```
+> min([12, 54, 3]...)
+3
+```
+
+## Related Functions
+
+* [`max`](/terraform/language/functions/max), which returns the _greatest_ number from a set.
diff --git a/v1.5.7/website/docs/language/functions/nonsensitive.mdx b/v1.5.7/website/docs/language/functions/nonsensitive.mdx
new file mode 100644
index 0000000..7518eb2
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/nonsensitive.mdx
@@ -0,0 +1,128 @@
+---
+page_title: nonsensitive - Functions - Configuration Language
+description: >-
+  The nonsensitive function removes the sensitive marking from a value that
+  Terraform considers to be sensitive.
+---
+
+# `nonsensitive` Function
+
+-> **Note:** This function is only available in Terraform v0.15 and later.
+
+`nonsensitive` takes a sensitive value and returns a copy of that value with
+the sensitive marking removed, thereby exposing the sensitive value.
+
+~> **Warning:** Using this function indiscriminately will cause values that
+Terraform would normally have considered as sensitive to be treated as normal
+values and shown clearly in Terraform's output. Use this function only when
+you've derived a new value from a sensitive value in a way that eliminates the
+sensitive portions of the value.
+
+Normally Terraform tracks when you use expressions to derive a new value from
+a value that is marked as sensitive, so that the result can also be marked
+as sensitive.
+
+However, you may wish to write expressions that derive non-sensitive results
+from sensitive values. For example, if you know based on details of your
+particular system and its threat model that a SHA256 hash of a particular
+sensitive value is safe to include clearly in Terraform output, you could use
+the `nonsensitive` function to indicate that, overriding Terraform's normal
+conservative behavior:
+
+```hcl
+output "sensitive_example_hash" {
+  value = nonsensitive(sha256(var.sensitive_example))
+}
+```
+
+Another example might be if the original value is only partially sensitive and
+you've written expressions to separate the sensitive and non-sensitive parts:
+
+```hcl
+variable "mixed_content_json" {
+  description = "A JSON string containing a mixture of sensitive and non-sensitive values."
+  type        = string
+  sensitive   = true
+}
+
+locals {
+  # mixed_content is derived from var.mixed_content_json, so it
+  # is also considered to be sensitive.
+  mixed_content = jsondecode(var.mixed_content_json)
+
+  # password_from_json is derived from mixed_content, so it's
+  # also considered to be sensitive.
+  password_from_json = local.mixed_content["password"]
+
+  # username_from_json would normally be considered to be
+  # sensitive too, but system-specific knowledge tells us
+  # that the username is a non-sensitive fragment of the
+  # original document, and so we can override Terraform's
+  # determination.
+  username_from_json = nonsensitive(local.mixed_content["username"])
+}
+```
+
+When you use this function, it's your responsibility to ensure that the
+expression passed as its argument will remove all sensitive content from
+the sensitive value it depends on. By passing a value to `nonsensitive` you are
+declaring to Terraform that you have done all that is necessary to ensure that
+the resulting value has no sensitive content, even though it was derived
+from sensitive content. If a sensitive value appears in Terraform's output
+due to an inappropriate call to `nonsensitive` in your module, that's a bug in
+your module and not a bug in Terraform itself.
+**Use this function sparingly and only with due care.**
+
+`nonsensitive` will return an error if you pass a value that isn't marked
+as sensitive, because such a call would be redundant and potentially confusing
+or misleading to a future maintainer of your module. Use `nonsensitive` only
+after careful consideration and with definite intent.
+
+Consider including a comment adjacent to your call to explain to future
+maintainers what makes the usage safe and thus what invariants they must take
+care to preserve under future modifications.
+
+## Examples
+
+The following examples are from `terraform console` when running in the
+context of the example above with `variable "mixed_content_json"` and
+the local value `mixed_content`, with a valid JSON string assigned to
+`var.mixed_content_json`.
+
+```
+> var.mixed_content_json
+(sensitive value)
+> local.mixed_content
+(sensitive value)
+> local.mixed_content["password"]
+(sensitive value)
+> nonsensitive(local.mixed_content["username"])
+"zqb"
+> nonsensitive("clear")
+
+Error: Invalid function argument
+
+Invalid value for "value" parameter: the given value is not sensitive, so this
+call is redundant.
+```
+
+Note though that it's always your responsibility to use `nonsensitive` only
+when it's safe to do so. If you use `nonsensitive` with content that
+_ought to be_ considered sensitive then that content will be disclosed:
+
+```
+> nonsensitive(var.mixed_content_json)
+<<EOT
+{
+  "username": "zqb",
+  "password": "p4ssw0rd"
+}
+EOT
+> nonsensitive(local.mixed_content)
+{
+  "password" = "p4ssw0rd"
+  "username" = "zqb"
+}
+> nonsensitive(local.mixed_content["password"])
+"p4ssw0rd"
+```
diff --git a/v1.5.7/website/docs/language/functions/one.mdx b/v1.5.7/website/docs/language/functions/one.mdx
new file mode 100644
index 0000000..ceb6a16
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/one.mdx
@@ -0,0 +1,119 @@
+---
+page_title: one - Functions - Configuration Language
+description: |-
+  The 'one' function transforms a list with either zero or one elements into
+  either a null value or the value of the first element.
+---
+
+# `one` Function
+
+-> **Note:** This function is available only in Terraform v0.15 and later.
+
+`one` takes a list, set, or tuple value with either zero or one elements.
+If the collection is empty, `one` returns `null`. Otherwise, `one` returns
+the first element. If there are two or more elements then `one` will return
+an error.
+
+This is a specialized function intended for the common situation where a
+conditional item is represented as either a zero- or one-element list, where
+a module author wishes to return a single value that might be null instead.
+
+For example:
+
+```hcl
+variable "include_ec2_instance" {
+  type    = bool
+  default = true
+}
+
+resource "aws_instance" "example" {
+  count = var.include_ec2_instance ? 1 : 0
+
+  # (other resource arguments...)
+}
+
+output "instance_ip_address" {
+  value = one(aws_instance.example[*].private_ip)
+}
+```
+
+Because the `aws_instance` resource above has the `count` argument set to a
+conditional that returns either zero or one, the value of
+`aws_instance.example` is a list of either zero or one elements. The
+`instance_ip_address` output value uses the `one` function as a concise way
+to return either the private IP address of a single instance, or `null` if
+no instances were created.
+
+## Relationship to the "Splat" Operator
+
+The Terraform language has a built-in operator `[*]`, known as
+[the _splat_ operator](/terraform/language/expressions/splat), and one of its functions
+is to translate a primitive value that might be null into a list of either
+zero or one elements:
+
+```hcl
+variable "ec2_instance_type" {
+  description = "The type of instance to create. If set to null, no instance will be created."
+
+  type    = string
+  default = null
+}
+
+resource "aws_instance" "example" {
+  count = length(var.ec2_instance_type[*])
+
+  instance_type = var.ec2_instance_type
+  # (other resource arguments...)
+}
+
+output "instance_ip_address" {
+  value = one(aws_instance.example[*].private_ip)
+}
+```
+
+In this case we can see that the `one` function is, in a sense, the opposite
+of applying `[*]` to a primitive-typed value. Splat can convert a possibly-null
+value into a zero-or-one list, and `one` can reverse that to return to a
+primitive value that might be null.
+
+## Examples
+
+```
+> one([])
+null
+> one(["hello"])
+"hello"
+> one(["hello", "goodbye"])
+
+Error: Invalid function argument
+
+Invalid value for "list" parameter: must be a list, set, or tuple value with
+either zero or one elements.
+```
+
+### Using `one` with sets
+
+The `one` function can be particularly helpful in situations where you have a
+set that you know has only zero or one elements. Set values don't support
+indexing, so it's not valid to write `var.set[0]` to extract the "first"
+element of a set, but if you know that there's only one item then `one` can
+isolate and return that single item:
+
+```
+> one(toset([]))
+null
+> one(toset(["hello"]))
+"hello"
+```
+
+Don't use `one` with sets that might have more than one element. This function
+will fail in that case:
+
+```
+> one(toset(["hello","goodbye"]))
+
+Error: Invalid function argument
+
+Invalid value for "list" parameter: must be a list, set, or tuple value with
+either zero or one elements.
+```
diff --git a/v1.5.7/website/docs/language/functions/parseint.mdx b/v1.5.7/website/docs/language/functions/parseint.mdx
new file mode 100644
index 0000000..952a147
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/parseint.mdx
@@ -0,0 +1,50 @@
+---
+page_title: parseint - Functions - Configuration Language
+description: >-
+  The parseint function parses the given string as a representation of an
+  integer.
+---
+
+# `parseint` Function
+
+`parseint` parses the given string as a representation of an integer in
+the specified base and returns the resulting number. The base must be between 2
+and 62 inclusive.
+
+All bases use the arabic numerals 0 through 9 first. Bases between 11 and 36
+inclusive use case-insensitive latin letters to represent higher unit values.
+Bases 37 and higher use lowercase latin letters and then uppercase latin
+letters.
+
+If the given string contains any non-digit characters or digit characters that
+are too large for the given base then `parseint` will produce an error.
+
+## Examples
+
+```
+> parseint("100", 10)
+100
+
+> parseint("FF", 16)
+255
+
+> parseint("-10", 16)
+-16
+
+> parseint("1011111011101111", 2)
+48879
+
+> parseint("aA", 62)
+656
+
+> parseint("12", 2)
+
+Error: Invalid function argument
+
+Invalid value for "number" parameter: cannot parse "12" as a base 2 integer.
+```
+
+## Related Functions
+
+* [`format`](/terraform/language/functions/format) can format numbers and other values into strings,
+  with optional zero padding, alignment, etc.
diff --git a/v1.5.7/website/docs/language/functions/pathexpand.mdx b/v1.5.7/website/docs/language/functions/pathexpand.mdx
new file mode 100644
index 0000000..2383f84
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/pathexpand.mdx
@@ -0,0 +1,54 @@
+---
+page_title: pathexpand - Functions - Configuration Language
+description: |-
+  The pathexpand function expands a leading ~ character to the current user's
+  home directory.
+---
+
+# `pathexpand` Function
+
+`pathexpand` takes a filesystem path that might begin with a `~` segment,
+and if so it replaces that segment with the current user's home directory
+path.
+
+This function works only with the path string and does not access the
+filesystem itself. It is therefore unable to take into account filesystem
+features such as symlinks.
+
+If the leading segment in the path is not `~` then the given path is returned
+unmodified.
+
+Using this function in resource arguments will cause spurious diffs if the
+same configuration is run by multiple users with different home directory
+paths, or used on different host operating systems. We recommend using this
+function only for transient values, such as in `connection` and `provisioner`
+blocks to locate SSH keys, etc.
+
+The rules for determining the "home directory" for the current user vary
+depending on host operating system.
+
+**For Unix systems**, the following sources are consulted, in order of preference:
+
+* The `HOME` environment variable.
+* The result of running `getent passwd` followed by the Terraform process uid.
+* The result of running `cd && pwd` in `sh`.
+
+**For Windows systems**, there is not really the concept of a home directory
+in the same sense as on Unix, but the following sources are consulted in
+order of preference:
+
+* The `HOME` environment variable.
+* The `HOMEDRIVE` and `HOMEPATH` environment variables, if both are set.
+* The `USERPROFILE` environment variable.
+
+The exact rules employed for each operating system may change in future
+releases of Terraform.
+
+## Examples
+
+```
+> pathexpand("~/.ssh/id_rsa")
+/home/steve/.ssh/id_rsa
+> pathexpand("/etc/resolv.conf")
+/etc/resolv.conf
+```
diff --git a/v1.5.7/website/docs/language/functions/plantimestamp.mdx b/v1.5.7/website/docs/language/functions/plantimestamp.mdx
new file mode 100644
index 0000000..7b3a41e
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/plantimestamp.mdx
@@ -0,0 +1,54 @@
+---
+page_title: plantimestamp - Functions - Configuration Language
+description: |-
+  The plantimestamp functions a string representation of the date and time
+  during the plan.
+---
+
+# `plantimestamp` Function
+
+-> **Note:** This function is only available in Terraform v1.5 and later.
+
+`plantimestamp` returns a UTC timestamp string in [RFC 3339](https://tools.ietf.org/html/rfc3339) format.
+
+In the Terraform language, timestamps are conventionally represented as
+strings using [RFC 3339](https://tools.ietf.org/html/rfc3339)
+"Date and Time format" syntax, and so `plantimestamp` returns a string
+in this format.
+
+The result of this function will change for every plan operation. It is intended
+for use within [Custom Conditions](/terraform/language/expressions/custom-conditions)
+as a way to validate time sensitive resources such as TLS certificates.
+
+There are circumstances, such as during a Terraform [Refresh-only](/terraform/cli/commands/plan#planning-modes) plan, where
+the value for this function will be recomputed but not propagated to resources
+defined within the configuration. As such, it is recommended that this function
+only be used to compare against timestamps exported by providers and not against
+timestamps generated in the configuration.
+
+The `plantimestamp` function is not available within the Terraform console.
+
+## Examples
+
+```
+> plantimestamp()
+2018-05-13T07:44:12Z
+```
+
+```terraform
+check "terraform_io_certificate" {
+  data "tls_certificate" "terraform_io" {
+    url = "https://www.terraform.io/"
+  }
+
+  assert {
+    condition = timecmp(plantimestamp(), data.tls_certificate.terraform_io.certificates[0].not_after) < 0
+    error_message = "terraform.io certificate has expired"
+  }
+}
+```
+
+## Related Functions
+
+* [`timestamp`](/terraform/language/functions/timestamp) returns the current timestamp when it is evaluated
+during the apply step.
\ No newline at end of file
diff --git a/v1.5.7/website/docs/language/functions/pow.mdx b/v1.5.7/website/docs/language/functions/pow.mdx
new file mode 100644
index 0000000..f542d26
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/pow.mdx
@@ -0,0 +1,17 @@
+---
+page_title: pow - Functions - Configuration Language
+description: The pow function raises a number to a power.
+---
+
+# `pow` Function
+
+`pow` calculates an exponent, by raising its first argument to the power of the second argument.
+
+## Examples
+
+```
+> pow(3, 2)
+9
+> pow(4, 0)
+1
+```
diff --git a/v1.5.7/website/docs/language/functions/range.mdx b/v1.5.7/website/docs/language/functions/range.mdx
new file mode 100644
index 0000000..ecf5c39
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/range.mdx
@@ -0,0 +1,139 @@
+---
+page_title: range - Functions - Configuration Language
+description: The range function generates sequences of numbers.
+---
+
+# `range` Function
+
+`range` generates a list of numbers using a start value, a limit value,
+and a step value.
+
+```hcl
+range(max)
+range(start, limit)
+range(start, limit, step)
+```
+
+The `start` and `step` arguments can be omitted, in which case `start` defaults
+to zero and `step` defaults to either one or negative one depending on whether
+`limit` is greater than or less than `start`.
+
+The resulting list is created by starting with the given `start` value and
+repeatedly adding `step` to it until the result is equal to or beyond `limit`.
+
+The interpretation of `limit` depends on the direction of `step`: for a positive
+step, the sequence is complete when the next number is greater than or equal
+to `limit`. For a negative step, it's complete when less than or equal.
+
+The sequence-building algorithm follows the following pseudocode:
+
+```
+let num = start
+while num < limit: (or, for negative step, num > limit)
+  append num to the sequence
+  num = num + step
+return the sequence
+```
+
+Because the sequence is created as a physical list in memory, Terraform imposes
+an artificial limit of 1024 numbers in the resulting sequence in order to avoid
+unbounded memory usage if, for example, a very large value were accidentally
+passed as the limit or a very small value as the step. If the algorithm above
+would append the 1025th number to the sequence, the function immediately exits
+with an error.
+
+We recommend iterating over existing collections where possible, rather than
+creating ranges. However, creating small numerical sequences can sometimes
+be useful when combined with other collections in collection-manipulation
+functions or `for` expressions.
+
+## Examples
+
+```
+> range(3)
+[
+  0,
+  1,
+  2,
+]
+
+> range(1, 4)
+[
+  1,
+  2,
+  3,
+]
+
+> range(1, 8, 2)
+[
+  1,
+  3,
+  5,
+  7,
+]
+
+> range(1, 4, 0.5)
+[
+  1,
+  1.5,
+  2,
+  2.5,
+  3,
+  3.5,
+]
+
+> range(4, 1)
+[
+  4,
+  3,
+  2,
+]
+
+> range(10, 5, -2)
+[
+  10,
+  8,
+  6,
+]
+```
+
+The `range` function is primarily useful when working with other collections
+to produce a certain number of instances of something. For example:
+
+```hcl
+variable "name_counts" {
+  type    = map(number)
+  default = {
+    "foo" = 2
+    "bar" = 4
+  }
+}
+
+locals {
+  expanded_names = {
+    for name, count in var.name_counts : name => [
+      for i in range(count) : format("%s%02d", name, i)
+    ]
+  }
+}
+
+output "expanded_names" {
+  value = local.expanded_names
+}
+
+# Produces the following expanded_names value when run with the default
+# "name_counts":
+#
+# {
+#   "bar" = [
+#     "bar00",
+#     "bar01",
+#     "bar02",
+#     "bar03",
+#   ]
+#   "foo" = [
+#     "foo00",
+#     "foo01",
+#   ]
+# }
+```
diff --git a/v1.5.7/website/docs/language/functions/regex.mdx b/v1.5.7/website/docs/language/functions/regex.mdx
new file mode 100644
index 0000000..9e18197
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/regex.mdx
@@ -0,0 +1,161 @@
+---
+page_title: regex - Functions - Configuration Language
+description: |-
+  The regex function applies a regular expression to a string and returns the
+  matching substrings.
+---
+
+# `regex` Function
+
+`regex` applies a
+[regular expression](https://en.wikipedia.org/wiki/Regular_expression)
+to a string and returns the matching substrings.
+
+```hcl
+regex(pattern, string)
+```
+
+The return type of `regex` depends on the capture groups, if any, in the
+pattern:
+
+- If the pattern has no capture groups at all, the result is a single string
+  covering the substring matched by the pattern as a whole.
+- If the pattern has one or more _unnamed_ capture groups, the result is a
+  list of the captured substrings in the same order as the definition of
+  the capture groups.
+- If the pattern has one or more _named_ capture groups, the result is a
+  map of the captured substrings, using the capture group names as map keys.
+
+It's not valid to mix both named and unnamed capture groups in the same pattern.
+
+If the given pattern does not match at all, the `regex` raises an error. To
+_test_ whether a given pattern matches a string, use
+[`regexall`](/terraform/language/functions/regexall) and test that the result has length greater than
+zero.
+
+The pattern is a string containing a mixture of literal characters and special
+matching operators as described in the following table. Note that when giving a
+regular expression pattern as a literal quoted string in the Terraform
+language, the quoted string itself already uses backslash `\` as an escape
+character for the string, so any backslashes intended to be recognized as part
+of the pattern must be escaped as `\\`.
+
+| Sequence               | Matches                                                                          |
+| ---------------------- | -------------------------------------------------------------------------------- |
+| `.`                    | Any character except newline                                                     |
+| `[xyz]`                | Any character listed between the brackets (`x`, `y`, and `z` in this example)    |
+| `[a-z]`                | Any character between `a` and `z`, inclusive                                     |
+| `[^xyz]`               | The opposite of `[xyz]`                                                          |
+| `\d`                   | ASCII digits (0 through 9, inclusive)                                            |
+| `\D`                   | Anything except ASCII digits                                                     |
+| `\s`                   | ASCII spaces (space, tab, newline, carriage return, form feed)                   |
+| `\S`                   | Anything except ASCII spaces                                                     |
+| `\w`                   | The same as `[0-9A-Za-z_]`                                                       |
+| `\W`                   | Anything except the characters matched by `\w`                                   |
+| `[[:alnum:]]`          | The same as `[0-9A-Za-z]`                                                        |
+| `[[:alpha:]]`          | The same as `[A-Za-z]`                                                           |
+| `[[:ascii:]]`          | Any ASCII character                                                              |
+| `[[:blank:]]`          | ASCII tab or space                                                               |
+| `[[:cntrl:]]`          | ASCII/Unicode control characters                                                 |
+| `[[:digit:]]`          | The same as `[0-9]`                                                              |
+| `[[:graph:]]`          | All "graphical" (printable) ASCII characters                                     |
+| `[[:lower:]]`          | The same as `[a-z]`                                                              |
+| `[[:print:]]`          | The same as `[[:graph:]]`                                                        |
+| `[[:punct:]]`          | The same as ``[!-/:-@[-`{-~]``                                                   |
+| `[[:space:]]`          | The same as `[\t\n\v\f\r ]`                                                      |
+| `[[:upper:]]`          | The same as `[A-Z]`                                                              |
+| `[[:word:]]`           | The same as `\w`                                                                 |
+| `[[:xdigit:]]`         | The same as `[0-9A-Fa-f]`                                                        |
+| `\pN`                  | Unicode character class by using single-letter class names ("N" in this example) |
+| `\p{Greek}`            | Unicode character class by unicode name ("Greek" in this example)                |
+| `\PN`                  | The opposite of `\pN`                                                            |
+| `\P{Greek}`            | The opposite of `\p{Greek}`                                                      |
+| `xy`                   | `x` followed immediately by `y`                                                  |
+| `x&#124;y`             | either `x` or `y`, preferring `x`                                                |
+| `x*`                   | zero or more `x`, preferring more                                                |
+| `x*?`                  | zero or more `x`, preferring fewer                                               |
+| `x+`                   | one or more `x`, preferring more                                                 |
+| `x+?`                  | one or more `x`, preferring fewer                                                |
+| `x?`                   | zero or one `x`, preferring one                                                  |
+| `x??`                  | zero or one `x`, preferring zero                                                 |
+| `x{n,m}`               | between `n` and `m` repetitions of `x`, preferring more                          |
+| `x{n,m}?`              | between `n` and `m` repetitions of `x`, preferring fewer                         |
+| `x{n,}`                | at least `n` repetitions of `x`, preferring more                                 |
+| `x{n,}?`               | at least `n` repetitions of `x`, preferring fewer                                |
+| `x{n}`                 | exactly `n` repetitions of `x`                                                   |
+| `(x)`                  | unnamed capture group for sub-pattern `x`                                        |
+| `(?P<name>x)`          | named capture group, named `name`, for sub-pattern `x`                           |
+| `(?:x)`                | non-capturing sub-pattern `x`                                                    |
+| `\*`                   | Literal `*` for any punctuation character `*`                                    |
+| `\Q...\E`              | Literal `...` for any text `...` as long as it does not include literally `\E`   |
+
+In addition to the above matching operators that consume the characters they
+match, there are some additional operators that _only_ match, but consume
+no characters. These are "zero-width" matching operators:
+
+| Sequence | Matches                                                                                          |
+| -------- | ------------------------------------------------------------------------------------------------ |
+| `^`      | At the beginning of the given string                                                             |
+| `$`      | At the end of the given string                                                                   |
+| `\A`     | At the beginning of the given string                                                             |
+| `\z`     | At the end of the given string                                                                   |
+| `\b`     | At an ASCII word boundary (transition between `\w` and either `\W`, `\A` or `\z`, or vice-versa) |
+| `\B`     | Not at an ASCII word boundary                                                                    |
+
+Terraform uses the
+[RE2](https://github.com/google/re2/wiki/Syntax) regular expression language.
+This engine does not support all of the features found in some other regular
+expression engines; in particular, it does not support backreferences.
+
+## Matching Flags
+
+Some of the matching behaviors described above can be modified by setting
+matching flags, activated using either the `(?flags)` operator (to activate
+within the current sub-pattern) or the `(?flags:x)` operator (to match `x` with
+the modified flags). Each flag is a single letter, and multiple flags can be
+set at once by listing multiple letters in the `flags` position.
+The available flags are listed in the table below:
+
+| Flag | Meaning                                                                                                                                                     |
+| ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `i`  | Case insensitive: a literal letter in the pattern matches both lowercase and uppercase versions of that letter                                              |
+| `m`  | The `^` and `$` operators also match the beginning and end of lines within the string, marked by newline characters; behavior of `\A` and `\z` is unchanged |
+| `s`  | The `.` operator also matches newline                                                                                                                       |
+| `U`  | The meaning of presence or absense `?` after a repetition operator is inverted. For example, `x*` is interpreted like `x*?` and vice-versa.                 |
+
+## Examples
+
+```
+> regex("[a-z]+", "53453453.345345aaabbbccc23454")
+aaabbbccc
+
+> regex("(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)", "2019-02-01")
+[
+  "2019",
+  "02",
+  "01",
+]
+
+> regex("^(?:(?P<scheme>[^:/?#]+):)?(?://(?P<authority>[^/?#]*))?", "https://terraform.io/docs/")
+{
+  "authority" = "terraform.io"
+  "scheme" = "https"
+}
+
+> regex("[a-z]+", "53453453.34534523454")
+
+Error: Error in function call
+
+Call to function "regex" failed: pattern did not match any part of the given
+string.
+```
+
+## Related Functions
+
+- [`regexall`](/terraform/language/functions/regexall) searches for potentially multiple matches of a given pattern in a string.
+- [`replace`](/terraform/language/functions/replace) replaces a substring of a string with another string, optionally matching using the same regular expression syntax as `regex`.
+
+If Terraform already has a more specialized function to parse the syntax you
+are trying to match, prefer to use that function instead. Regular expressions
+can be hard to read and can obscure your intent, making a configuration harder
+to read and understand.
diff --git a/v1.5.7/website/docs/language/functions/regexall.mdx b/v1.5.7/website/docs/language/functions/regexall.mdx
new file mode 100644
index 0000000..ea794af
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/regexall.mdx
@@ -0,0 +1,57 @@
+---
+page_title: regexall - Functions - Configuration Language
+description: >-
+  The regex function applies a regular expression to a string and returns a list
+  of all matches.
+---
+
+# `regexall` Function
+
+`regexall` applies a
+[regular expression](https://en.wikipedia.org/wiki/Regular_expression)
+to a string and returns a list of all matches.
+
+```hcl
+regexall(pattern, string)
+```
+
+`regexall` is a variant of [`regex`](/terraform/language/functions/regex) and uses the same pattern
+syntax. For any given input to `regex`, `regexall` returns a list of whatever
+type `regex` would've returned, with one element per match. That is:
+
+- If the pattern has no capture groups at all, the result is a list of
+  strings.
+- If the pattern has one or more _unnamed_ capture groups, the result is a
+  list of lists.
+- If the pattern has one or more _named_ capture groups, the result is a
+  list of maps.
+
+`regexall` can also be used to test whether a particular string matches a
+given pattern, by testing whether the length of the resulting list of matches
+is greater than zero.
+
+## Examples
+
+```
+> regexall("[a-z]+", "1234abcd5678efgh9")
+[
+  "abcd",
+  "efgh",
+]
+
+> length(regexall("[a-z]+", "1234abcd5678efgh9"))
+2
+
+> length(regexall("[a-z]+", "123456789")) > 0
+false
+```
+
+## Related Functions
+
+- [`regex`](/terraform/language/functions/regex) searches for a single match of a given pattern, and
+  returns an error if no match is found.
+
+If Terraform already has a more specialized function to parse the syntax you
+are trying to match, prefer to use that function instead. Regular expressions
+can be hard to read and can obscure your intent, making a configuration harder
+to read and understand.
diff --git a/v1.5.7/website/docs/language/functions/replace.mdx b/v1.5.7/website/docs/language/functions/replace.mdx
new file mode 100644
index 0000000..e4e76a1
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/replace.mdx
@@ -0,0 +1,37 @@
+---
+page_title: replace - Functions - Configuration Language
+description: |-
+  The replace function searches a given string for another given substring,
+  and replaces all occurrences with a given replacement string.
+---
+
+# `replace` Function
+
+`replace` searches a given string for another given substring, and replaces
+each occurrence with a given replacement string.
+
+```hcl
+replace(string, substring, replacement)
+```
+
+If `substring` is wrapped in forward slashes, it is treated as a regular
+expression, using the same pattern syntax as
+[`regex`](/terraform/language/functions/regex). If using a regular expression for the substring
+argument, the `replacement` string can incorporate captured strings from
+the input by using an `$n` sequence, where `n` is the index or name of a
+capture group.
+
+## Examples
+
+```
+> replace("1 + 2 + 3", "+", "-")
+1 - 2 - 3
+
+> replace("hello world", "/w.*d/", "everybody")
+hello everybody
+```
+
+## Related Functions
+
+- [`regex`](/terraform/language/functions/regex) searches a given string for a substring matching a
+  given regular expression pattern.
diff --git a/v1.5.7/website/docs/language/functions/reverse.mdx b/v1.5.7/website/docs/language/functions/reverse.mdx
new file mode 100644
index 0000000..c46350a
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/reverse.mdx
@@ -0,0 +1,24 @@
+---
+page_title: reverse - Functions - Configuration Language
+description: The reverse function reverses a sequence.
+---
+
+# `reverse` Function
+
+`reverse` takes a sequence and produces a new sequence of the same length
+with all of the same elements as the given sequence but in reverse order.
+
+## Examples
+
+```
+> reverse([1, 2, 3])
+[
+  3,
+  2,
+  1,
+]
+```
+
+## Related Functions
+
+* [`strrev`](/terraform/language/functions/strrev) reverses a string.
diff --git a/v1.5.7/website/docs/language/functions/rsadecrypt.mdx b/v1.5.7/website/docs/language/functions/rsadecrypt.mdx
new file mode 100644
index 0000000..4727311
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/rsadecrypt.mdx
@@ -0,0 +1,31 @@
+---
+page_title: rsadecrypt - Functions - Configuration Language
+description: The rsadecrypt function decrypts an RSA-encrypted message.
+---
+
+# `rsadecrypt` Function
+
+`rsadecrypt` decrypts an RSA-encrypted ciphertext, returning the corresponding
+cleartext.
+
+```hcl
+rsadecrypt(ciphertext, privatekey)
+```
+
+`ciphertext` must be a base64-encoded representation of the ciphertext, using
+the PKCS #1 v1.5 padding scheme. Terraform uses the "standard" Base64 alphabet
+as defined in [RFC 4648 section 4](https://tools.ietf.org/html/rfc4648#section-4).
+
+`privatekey` must be a PEM-encoded RSA private key that is not itself
+encrypted.
+
+Terraform has no corresponding function for _encrypting_ a message. Use this
+function to decrypt ciphertexts returned by remote services using a keypair
+negotiated out-of-band.
+
+## Examples
+
+```
+> rsadecrypt(filebase64("${path.module}/ciphertext"), file("privatekey.pem"))
+Hello, world!
+```
diff --git a/v1.5.7/website/docs/language/functions/sensitive.mdx b/v1.5.7/website/docs/language/functions/sensitive.mdx
new file mode 100644
index 0000000..4b82bbe
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/sensitive.mdx
@@ -0,0 +1,42 @@
+---
+page_title: sensitive - Functions - Configuration Language
+description: The sensitive function marks a value as being sensitive.
+---
+
+# `sensitive` Function
+
+-> **Note:** This function is only available in Terraform v0.15 and later.
+
+`sensitive` takes any value and returns a copy of it marked so that Terraform
+will treat it as sensitive, with the same meaning and behavior as for
+[sensitive input variables](/terraform/language/values/variables#suppressing-values-in-cli-output).
+
+Wherever possible we recommend marking your input variable and/or output value
+declarations as sensitive directly, instead of using this function, because in
+that case you can be sure that there is no way to refer to those values without
+Terraform automatically considering them as sensitive.
+
+The `sensitive` function might be useful in some less-common situations where a
+sensitive value arises from a definition _within_ your module, such as if you've
+loaded sensitive data from a file on disk as part of your configuration:
+
+```
+locals {
+  sensitive_content = sensitive(file("${path.module}/sensitive.txt"))
+}
+```
+
+However, we generally don't recommend writing sensitive values directly within
+your module any of the files you distribute statically as part of that module,
+because they may be exposed in other ways outside of Terraform's control.
+
+## Examples
+
+```
+> sensitive(1)
+(sensitive value)
+> sensitive("hello")
+(sensitive value)
+> sensitive([])
+(sensitive value)
+```
diff --git a/v1.5.7/website/docs/language/functions/setintersection.mdx b/v1.5.7/website/docs/language/functions/setintersection.mdx
new file mode 100644
index 0000000..95b37b7
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/setintersection.mdx
@@ -0,0 +1,39 @@
+---
+page_title: setintersection - Functions - Configuration Language
+description: |-
+  The setintersection function takes multiple sets and produces a single set
+  containing only the elements that all of the given sets have in common.
+---
+
+# `setintersection` Function
+
+The `setintersection` function takes multiple sets and produces a single set
+containing only the elements that all of the given sets have in common.
+In other words, it computes the
+[intersection](https://en.wikipedia.org/wiki/Intersection_\(set_theory\)) of the sets.
+
+```hcl
+setintersection(sets...)
+```
+
+## Examples
+
+```
+> setintersection(["a", "b"], ["b", "c"], ["b", "d"])
+[
+  "b",
+]
+```
+
+The given arguments are converted to sets, so the result is also a set and
+the ordering of the given elements is not preserved.
+
+## Related Functions
+
+* [`contains`](/terraform/language/functions/contains) tests whether a given list or set contains
+  a given element value.
+* [`setproduct`](/terraform/language/functions/setproduct) computes the _Cartesian product_ of multiple
+  sets.
+* [`setsubtract`](/terraform/language/functions/setsubtract) computes the _relative complement_ of two sets
+* [`setunion`](/terraform/language/functions/setunion) computes the _union_ of
+  multiple sets.
diff --git a/v1.5.7/website/docs/language/functions/setproduct.mdx b/v1.5.7/website/docs/language/functions/setproduct.mdx
new file mode 100644
index 0000000..077f4cb
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/setproduct.mdx
@@ -0,0 +1,281 @@
+---
+page_title: setproduct - Functions - Configuration Language
+description: |-
+  The setproduct function finds all of the possible combinations of elements
+  from all of the given sets by computing the cartesian product.
+---
+
+# `setproduct` Function
+
+The `setproduct` function finds all of the possible combinations of elements
+from all of the given sets by computing the
+[Cartesian product](https://en.wikipedia.org/wiki/Cartesian_product).
+
+```hcl
+setproduct(sets...)
+```
+
+This function is particularly useful for finding the exhaustive set of all
+combinations of members of multiple sets, such as per-application-per-environment
+resources.
+
+```
+> setproduct(["development", "staging", "production"], ["app1", "app2"])
+[
+  [
+    "development",
+    "app1",
+  ],
+  [
+    "development",
+    "app2",
+  ],
+  [
+    "staging",
+    "app1",
+  ],
+  [
+    "staging",
+    "app2",
+  ],
+  [
+    "production",
+    "app1",
+  ],
+  [
+    "production",
+    "app2",
+  ],
+]
+```
+
+You must pass at least two arguments to this function.
+
+Although defined primarily for sets, this function can also work with lists.
+If all of the given arguments are lists then the result is a list, preserving
+the ordering of the given lists. Otherwise the result is a set. In either case,
+the result's element type is a list of values corresponding to each given
+argument in turn.
+
+## Examples
+
+There is an example of the common usage of this function above. There are some
+other situations that are less common when hand-writing but may arise in
+reusable module situations.
+
+If any of the arguments is empty then the result is always empty itself,
+similar to how multiplying any number by zero gives zero:
+
+```
+> setproduct(["development", "staging", "production"], [])
+[]
+```
+
+Similarly, if all of the arguments have only one element then the result has
+only one element, which is the first element of each argument:
+
+```
+> setproduct(["a"], ["b"])
+[
+  [
+    "a",
+    "b",
+  ],
+]
+```
+
+Each argument must have a consistent type for all of its elements. If not,
+Terraform will attempt to convert to the most general type, or produce an
+error if such a conversion is impossible. For example, mixing both strings and
+numbers results in the numbers being converted to strings so that the result
+elements all have a consistent type:
+
+```
+> setproduct(["staging", "production"], ["a", 2])
+[
+  [
+    "staging",
+    "a",
+  ],
+  [
+    "staging",
+    "2",
+  ],
+  [
+    "production",
+    "a",
+  ],
+  [
+    "production",
+    "2",
+  ],
+]
+```
+
+## Finding combinations for `for_each`
+
+The
+[resource `for_each`](/terraform/language/meta-arguments/for_each)
+and
+[`dynamic` block](/terraform/language/expressions/dynamic-blocks)
+language features both require a collection value that has one element for
+each repetition.
+
+Sometimes your input data comes in separate values that cannot be directly
+used in a `for_each` argument, and `setproduct` can be a useful helper function
+for the situation where you want to find all unique combinations of elements in
+a number of different collections.
+
+For example, consider a module that declares variables like the following:
+
+```hcl
+variable "networks" {
+  type = map(object({
+    base_cidr_block = string
+  }))
+}
+
+variable "subnets" {
+  type = map(object({
+    number = number
+  }))
+}
+```
+
+If the goal is to create each of the defined subnets per each of the defined networks, creating the top-level networks can directly use `var.networks` because it is already in a form where the resulting instances match one-to-one with map elements:
+
+```hcl
+resource "aws_vpc" "example" {
+  for_each = var.networks
+
+  cidr_block = each.value.base_cidr_block
+}
+```
+
+However, to declare all of the _subnets_ with a single `resource` block, you must first produce a collection whose elements represent all of the combinations of networks and subnets, so that each element itself represents a subnet:
+
+```hcl
+locals {
+  # setproduct works with sets and lists, but the variables are both maps
+  # so convert them first.
+  networks = [
+    for key, network in var.networks : {
+      key        = key
+      cidr_block = network.cidr_block
+    }
+  ]
+  subnets = [
+    for key, subnet in var.subnets : {
+      key    = key
+      number = subnet.number
+    }
+  ]
+
+  network_subnets = [
+    # in pair, element zero is a network and element one is a subnet,
+    # in all unique combinations.
+    for pair in setproduct(local.networks, local.subnets) : {
+      network_key = pair[0].key
+      subnet_key  = pair[1].key
+      network_id  = aws_vpc.example[pair[0].key].id
+
+      # The cidr_block is derived from the corresponding network. Refer to the
+      # cidrsubnet function for more information on how this calculation works.
+      cidr_block = cidrsubnet(pair[0].cidr_block, 4, pair[1].number)
+    }
+  ]
+}
+
+resource "aws_subnet" "example" {
+  # local.network_subnets is a list, so project it into a map
+  # where each key is unique. Combine the network and subnet keys to
+  # produce a single unique key per instance.
+  for_each = {
+    for subnet in local.network_subnets : "${subnet.network_key}.${subnet.subnet_key}" => subnet
+  }
+
+  vpc_id            = each.value.network_id
+  availability_zone = each.value.subnet_key
+  cidr_block        = each.value.cidr_block
+}
+```
+
+The `network_subnets` list in the example above creates one subnet instance per combination of network and subnet elements in the input variables. So for this example input:
+
+```hcl
+networks = {
+  a = {
+    base_cidr_block = "10.1.0.0/16"
+  }
+  b = {
+    base_cidr_block = "10.2.0.0/16"
+  }
+}
+subnets = {
+  a = {
+    number = 1
+  }
+  b = {
+    number = 2
+  }
+  c = {
+    number = 3
+  }
+}
+```
+
+The `network_subnets` output would look similar to the following:
+
+```hcl
+[
+  {
+    "cidr_block" = "10.1.16.0/20"
+    "network_id" = "vpc-0bfb00ca6173ea5aa"
+    "network_key" = "a"
+    "subnet_key" = "a"
+  },
+  {
+    "cidr_block" = "10.1.32.0/20"
+    "network_id" = "vpc-0bfb00ca6173ea5aa"
+    "network_key" = "a"
+    "subnet_key" = "b"
+  },
+  {
+    "cidr_block" = "10.1.48.0/20"
+    "network_id" = "vpc-0bfb00ca6173ea5aa"
+    "network_key" = "a"
+    "subnet_key" = "c"
+  },
+  {
+    "cidr_block" = "10.2.16.0/20"
+    "network_id" = "vpc-0d193e011f6211a7d"
+    "network_key" = "b"
+    "subnet_key" = "a"
+  },
+  {
+    "cidr_block" = "10.2.32.0/20"
+    "network_id" = "vpc-0d193e011f6211a7d"
+    "network_key" = "b"
+    "subnet_key" = "b"
+  },
+  {
+    "cidr_block" = "10.2.48.0/20"
+    "network_id" = "vpc-0d193e011f6211a7d"
+    "network_key" = "b"
+    "subnet_key" = "c"
+  },
+]
+```
+
+## Related Functions
+
+- [`contains`](/terraform/language/functions/contains) tests whether a given list or set contains
+  a given element value.
+- [`flatten`](/terraform/language/functions/flatten) is useful for flattening hierarchical data
+  into a single list, for situations where the relationships between two
+  object types are defined explicitly.
+- [`setintersection`](/terraform/language/functions/setintersection) computes the _intersection_ of
+  multiple sets.
+- [`setsubtract`](/terraform/language/functions/setsubtract) computes the _relative complement_ of two sets
+- [`setunion`](/terraform/language/functions/setunion) computes the _union_ of multiple
+  sets.
diff --git a/v1.5.7/website/docs/language/functions/setsubtract.mdx b/v1.5.7/website/docs/language/functions/setsubtract.mdx
new file mode 100644
index 0000000..5397ed8
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/setsubtract.mdx
@@ -0,0 +1,42 @@
+---
+page_title: setsubtract - Functions - Configuration Language
+description: |-
+  The setsubtract function returns a new set containing the elements
+  from the first set that are not present in the second set
+---
+
+# `setsubtract` Function
+
+The `setsubtract` function returns a new set containing the elements from the first set that are not present in the second set. In other words, it computes the
+[relative complement](https://en.wikipedia.org/wiki/Complement_\(set_theory\)#Relative_complement) of the second set.
+
+```hcl
+setsubtract(a, b)
+```
+
+## Examples
+
+```
+> setsubtract(["a", "b", "c"], ["a", "c"])
+toset([
+  "b",
+])
+```
+
+### Set Difference (Symmetric Difference)
+
+```
+> setunion(setsubtract(["a", "b", "c"], ["a", "c", "d"]), setsubtract(["a", "c", "d"], ["a", "b", "c"]))
+toset([
+  "b",
+  "d",
+])
+```
+
+## Related Functions
+
+* [`setintersection`](/terraform/language/functions/setintersection) computes the _intersection_ of multiple sets
+* [`setproduct`](/terraform/language/functions/setproduct) computes the _Cartesian product_ of multiple
+  sets.
+* [`setunion`](/terraform/language/functions/setunion) computes the _union_ of
+  multiple sets.
diff --git a/v1.5.7/website/docs/language/functions/setunion.mdx b/v1.5.7/website/docs/language/functions/setunion.mdx
new file mode 100644
index 0000000..85874bd
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/setunion.mdx
@@ -0,0 +1,42 @@
+---
+page_title: setunion - Functions - Configuration Language
+description: |-
+  The setunion function takes multiple sets and produces a single set
+  containing the elements from all of the given sets.
+---
+
+# `setunion` Function
+
+The `setunion` function takes multiple sets and produces a single set
+containing the elements from all of the given sets. In other words, it
+computes the [union](https://en.wikipedia.org/wiki/Union_\(set_theory\)) of
+the sets.
+
+```hcl
+setunion(sets...)
+```
+
+## Examples
+
+```
+> setunion(["a", "b"], ["b", "c"], ["d"])
+[
+  "d",
+  "b",
+  "c",
+  "a",
+]
+```
+
+The given arguments are converted to sets, so the result is also a set and
+the ordering of the given elements is not preserved.
+
+## Related Functions
+
+* [`contains`](/terraform/language/functions/contains) tests whether a given list or set contains
+  a given element value.
+* [`setintersection`](/terraform/language/functions/setintersection) computes the _intersection_ of
+  multiple sets.
+* [`setproduct`](/terraform/language/functions/setproduct) computes the _Cartesian product_ of multiple
+  sets.
+* [`setsubtract`](/terraform/language/functions/setsubtract) computes the _relative complement_ of two sets
diff --git a/v1.5.7/website/docs/language/functions/sha1.mdx b/v1.5.7/website/docs/language/functions/sha1.mdx
new file mode 100644
index 0000000..dde0142
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/sha1.mdx
@@ -0,0 +1,31 @@
+---
+page_title: sha1 - Functions - Configuration Language
+description: |-
+  The sha1 function computes the SHA1 hash of a given string and encodes it
+  with hexadecimal digits.
+---
+
+# `sha1` Function
+
+`sha1` computes the SHA1 hash of a given string and encodes it with
+hexadecimal digits.
+
+The given string is first encoded as UTF-8 and then the SHA1 algorithm is applied
+as defined in [RFC 3174](https://tools.ietf.org/html/rfc3174). The raw hash is
+then encoded to lowercase hexadecimal digits before returning.
+
+Collision attacks have been successfully performed against this hashing
+function. Before using this function for anything security-sensitive, review
+relevant literature to understand the security implications.
+
+## Examples
+
+```
+> sha1("hello world")
+2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
+```
+
+## Related Functions
+
+* [`filesha1`](/terraform/language/functions/filesha1) calculates the same hash from
+  the contents of a file rather than from a string value.
diff --git a/v1.5.7/website/docs/language/functions/sha256.mdx b/v1.5.7/website/docs/language/functions/sha256.mdx
new file mode 100644
index 0000000..a4bba26
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/sha256.mdx
@@ -0,0 +1,31 @@
+---
+page_title: sha256 - Functions - Configuration Language
+description: |-
+  The sha256 function computes the SHA256 hash of a given string and encodes it
+  with hexadecimal digits.
+---
+
+# `sha256` Function
+
+`sha256` computes the SHA256 hash of a given string and encodes it with
+hexadecimal digits.
+
+The given string is first encoded as UTF-8 and then the SHA256 algorithm is applied
+as defined in [RFC 4634](https://tools.ietf.org/html/rfc4634). The raw hash is
+then encoded to lowercase hexadecimal digits before returning.
+
+## Examples
+
+```
+> sha256("hello world")
+b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
+```
+
+## Related Functions
+
+## Related Functions
+
+* [`filesha256`](/terraform/language/functions/filesha256) calculates the same hash from
+  the contents of a file rather than from a string value.
+* [`base64sha256`](/terraform/language/functions/base64sha256) calculates the same hash but returns
+  the result in a more-compact Base64 encoding.
diff --git a/v1.5.7/website/docs/language/functions/sha512.mdx b/v1.5.7/website/docs/language/functions/sha512.mdx
new file mode 100644
index 0000000..83f5588
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/sha512.mdx
@@ -0,0 +1,29 @@
+---
+page_title: sha512 - Functions - Configuration Language
+description: |-
+  The sha512 function computes the SHA512 hash of a given string and encodes it
+  with hexadecimal digits.
+---
+
+# `sha512` Function
+
+`sha512` computes the SHA512 hash of a given string and encodes it with
+hexadecimal digits.
+
+The given string is first encoded as UTF-8 and then the SHA512 algorithm is applied
+as defined in [RFC 4634](https://tools.ietf.org/html/rfc4634). The raw hash is
+then encoded to lowercase hexadecimal digits before returning.
+
+## Examples
+
+```
+> sha512("hello world")
+309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f
+```
+
+## Related Functions
+
+* [`filesha512`](/terraform/language/functions/filesha512) calculates the same hash from
+  the contents of a file rather than from a string value.
+* [`base64sha512`](/terraform/language/functions/base64sha512) calculates the same hash but returns
+  the result in a more-compact Base64 encoding.
diff --git a/v1.5.7/website/docs/language/functions/signum.mdx b/v1.5.7/website/docs/language/functions/signum.mdx
new file mode 100644
index 0000000..9590d7f
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/signum.mdx
@@ -0,0 +1,20 @@
+---
+page_title: signum - Functions - Configuration Language
+description: The signum function determines the sign of a number.
+---
+
+# `signum` Function
+
+`signum` determines the sign of a number, returning a number between -1 and
+1 to represent the sign.
+
+## Examples
+
+```
+> signum(-13)
+-1
+> signum(0)
+0
+> signum(344)
+1
+```
diff --git a/v1.5.7/website/docs/language/functions/slice.mdx b/v1.5.7/website/docs/language/functions/slice.mdx
new file mode 100644
index 0000000..570c282
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/slice.mdx
@@ -0,0 +1,31 @@
+---
+page_title: slice - Functions - Configuration Language
+description: The slice function extracts some consecutive elements from within a list.
+---
+
+# `slice` Function
+
+`slice` extracts some consecutive elements from within a list.
+
+```hcl
+slice(list, startindex, endindex)
+```
+
+`startindex` is inclusive, while `endindex` is exclusive. This function returns
+an error if either index is outside the bounds of valid indices for the given
+list.
+
+## Examples
+
+```
+> slice(["a", "b", "c", "d"], 1, 3)
+[
+  "b",
+  "c",
+]
+```
+
+## Related Functions
+
+* [`substr`](/terraform/language/functions/substr) performs a similar function for characters in a
+  string, although it uses a length instead of an end index.
diff --git a/v1.5.7/website/docs/language/functions/sort.mdx b/v1.5.7/website/docs/language/functions/sort.mdx
new file mode 100644
index 0000000..7f07996
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/sort.mdx
@@ -0,0 +1,26 @@
+---
+page_title: sort - Functions - Configuration Language
+description: |-
+  The sort function takes a list of strings and returns a new list with those
+  strings sorted lexicographically.
+---
+
+# `sort` Function
+
+`sort` takes a list of strings and returns a new list with those strings
+sorted lexicographically.
+
+The sort is in terms of Unicode codepoints, with higher codepoints appearing
+after lower ones in the result.
+
+## Examples
+
+```
+> sort(["e", "d", "a", "x"])
+[
+  "a",
+  "d",
+  "e",
+  "x",
+]
+```
diff --git a/v1.5.7/website/docs/language/functions/split.mdx b/v1.5.7/website/docs/language/functions/split.mdx
new file mode 100644
index 0000000..2d22e03
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/split.mdx
@@ -0,0 +1,39 @@
+---
+page_title: split - Functions - Configuration Language
+description: |-
+  The split function produces a list by dividing a given string at all
+  occurrences of a given separator.
+---
+
+# `split` Function
+
+`split` produces a list by dividing a given string at all occurrences of a
+given separator.
+
+```hcl
+split(separator, string)
+```
+
+## Examples
+
+```
+> split(",", "foo,bar,baz")
+[
+  "foo",
+  "bar",
+  "baz",
+]
+> split(",", "foo")
+[
+  "foo",
+]
+> split(",", "")
+[
+  "",
+]
+```
+
+## Related Functions
+
+* [`join`](/terraform/language/functions/join) performs the opposite operation: producing a string
+  joining together a list of strings with a given separator.
diff --git a/v1.5.7/website/docs/language/functions/startswith.mdx b/v1.5.7/website/docs/language/functions/startswith.mdx
new file mode 100644
index 0000000..d9ff41c
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/startswith.mdx
@@ -0,0 +1,27 @@
+---
+page_title: startswith - Functions - Configuration Language
+description: |-
+  The startswith function  takes two values: a string to check and a prefix string. It returns true if the string begins with that exact prefix.
+---
+
+# `startswith` Function
+
+`startswith` takes two values: a string to check and a prefix string. The function returns true if the string begins with that exact prefix.
+
+```hcl
+startswith(string, prefix)
+```
+
+## Examples
+
+```
+> startswith("hello world", "hello")
+true
+
+> startswith("hello world", "world")
+false
+```
+
+## Related Functions
+
+- [`endswith`](/terraform/language/functions/endswith) takes two values: a string to check and a suffix string. The function returns true if the first string ends with that exact suffix.
\ No newline at end of file
diff --git a/v1.5.7/website/docs/language/functions/strcontains.mdx b/v1.5.7/website/docs/language/functions/strcontains.mdx
new file mode 100644
index 0000000..6e684a6
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/strcontains.mdx
@@ -0,0 +1,25 @@
+---
+page_title: strcontains - Functions - Configuration Language
+description: |-
+  The strcontains function checks whether a given string can be found within another string.
+---
+
+# `strcontains` Function
+
+`strcontains` function checks whether a substring is within another string.
+
+```hcl
+strcontains(string, substr)
+```
+
+## Examples
+
+```
+> strcontains("hello world", "wor")
+true
+```
+
+```
+> strcontains("hello world", "wod")
+false
+```
\ No newline at end of file
diff --git a/v1.5.7/website/docs/language/functions/strrev.mdx b/v1.5.7/website/docs/language/functions/strrev.mdx
new file mode 100644
index 0000000..f5e1e36
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/strrev.mdx
@@ -0,0 +1,26 @@
+---
+page_title: strrev - Functions - Configuration Language
+description: The strrev function reverses a string.
+---
+
+# `strrev` Function
+
+`strrev` reverses the characters in a string.
+Note that the characters are treated as _Unicode characters_ (in technical terms, Unicode [grapheme cluster boundaries](https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) are respected).
+
+```hcl
+strrev(string)
+```
+
+## Examples
+
+```
+> strrev("hello")
+olleh
+> strrev("a ☃")
+☃ a
+```
+
+## Related Functions
+
+* [`reverse`](/terraform/language/functions/reverse) reverses a sequence.
diff --git a/v1.5.7/website/docs/language/functions/substr.mdx b/v1.5.7/website/docs/language/functions/substr.mdx
new file mode 100644
index 0000000..8317848
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/substr.mdx
@@ -0,0 +1,46 @@
+---
+page_title: substr - Functions - Configuration Language
+description: |-
+  The substr function extracts a substring from a given string by offset and
+  length.
+---
+
+# `substr` Function
+
+`substr` extracts a substring from a given string by offset and (maximum) length.
+
+```hcl
+substr(string, offset, length)
+```
+
+## Examples
+
+```
+> substr("hello world", 1, 4)
+ello
+```
+
+The offset and length are both counted in _unicode characters_ rather than
+bytes:
+
+```
+> substr("🤔🤷", 0, 1)
+🤔
+```
+
+The offset index may be negative, in which case it is relative to the end of
+the given string.  The length may be -1, in which case the remainder of the
+string after the given offset will be returned.
+
+```
+> substr("hello world", -5, -1)
+world
+```
+
+If the length is greater than the length of the string, the substring
+will be the length of all remaining characters.
+
+```
+> substr("hello world", 6, 10)
+world
+```
diff --git a/v1.5.7/website/docs/language/functions/sum.mdx b/v1.5.7/website/docs/language/functions/sum.mdx
new file mode 100644
index 0000000..2528240
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/sum.mdx
@@ -0,0 +1,17 @@
+---
+page_title: sum - Functions - Configuration Language
+description: |-
+  The sum function takes a list or set of numbers and returns the sum of those
+  numbers.
+---
+
+# `sum` Function
+
+`sum` takes a list or set of numbers and returns the sum of those numbers.
+
+## Examples
+
+```
+> sum([10, 13, 6, 4.5])
+33.5
+```
diff --git a/v1.5.7/website/docs/language/functions/templatefile.mdx b/v1.5.7/website/docs/language/functions/templatefile.mdx
new file mode 100644
index 0000000..ed919ee
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/templatefile.mdx
@@ -0,0 +1,150 @@
+---
+page_title: templatefile - Functions - Configuration Language
+description: |-
+  The templatefile function reads the file at the given path and renders its
+  content as a template.
+---
+
+# `templatefile` Function
+
+`templatefile` reads the file at the given path and renders its content
+as a template using a supplied set of template variables.
+
+```hcl
+templatefile(path, vars)
+```
+
+The template syntax is the same as for
+[string templates](/terraform/language/expressions/strings#string-templates)
+in the main Terraform language, including interpolation sequences delimited with
+`${` ... `}`. This function just allows longer template sequences to be factored
+out into a separate file for readability.
+
+The "vars" argument must be an object. Within the template file, each of the
+keys in the map is available as a variable for interpolation. The template may
+also use any other function available in the Terraform language, except that
+recursive calls to `templatefile` are not permitted. Variable names must
+each start with a letter, followed by zero or more letters, digits, or
+underscores.
+
+Strings in the Terraform language are sequences of Unicode characters, so
+this function will interpret the file contents as UTF-8 encoded text and
+return the resulting Unicode characters. If the file contains invalid UTF-8
+sequences then this function will produce an error.
+
+This function can be used only with files that already exist on disk at the
+beginning of a Terraform run. Functions do not participate in the dependency
+graph, so this function cannot be used with files that are generated
+dynamically during a Terraform operation.
+
+`*.tftpl` is the recommended naming pattern to use for your template files.
+Terraform will not prevent you from using other names, but following this
+convention will help your editor understand the content and likely provide
+better editing experience as a result.
+
+## Examples
+
+### Lists
+
+Given a template file `backends.tftpl` with the following content:
+
+```
+%{ for addr, port in ip_addrs ~}
+backend ${addr}:${port}
+%{ endfor ~}
+```
+
+The `templatefile` function renders the template:
+
+```
+> templatefile("${path.module}/backends.tftpl", { port = 8080, ip_addrs = ["10.0.0.1", "10.0.0.2"] })
+backend 10.0.0.1:8080
+backend 10.0.0.2:8080
+
+```
+
+### Maps
+
+Given a template file `config.tftpl` with the following content:
+
+```
+%{ for config_key, config_value in config }
+set ${config_key} = ${config_value}
+%{ endfor ~}
+```
+
+The `templatefile` function renders the template:
+
+```
+> templatefile(
+               "${path.module}/config.tftpl",
+               {
+                 config = {
+                   "x"   = "y"
+                   "foo" = "bar"
+                   "key" = "value"
+                 }
+               }
+              )
+set foo = bar
+set key = value
+set x = y
+```
+
+### Generating JSON or YAML from a template
+
+If the string you want to generate will be in JSON or YAML syntax, it's
+often tricky and tedious to write a template that will generate valid JSON or
+YAML that will be interpreted correctly when using lots of individual
+interpolation sequences and directives.
+
+Instead, you can write a template that consists only of a single interpolated
+call to either [`jsonencode`](/terraform/language/functions/jsonencode) or
+[`yamlencode`](/terraform/language/functions/yamlencode), specifying the value to encode using
+[normal Terraform expression syntax](/terraform/language/expressions)
+as in the following examples:
+
+```
+${jsonencode({
+  "backends": [for addr in ip_addrs : "${addr}:${port}"],
+})}
+```
+
+```
+${yamlencode({
+  "backends": [for addr in ip_addrs : "${addr}:${port}"],
+})}
+```
+
+Given the same input as the `backends.tftpl` example in the previous section,
+this will produce a valid JSON or YAML representation of the given data
+structure, without the need to manually handle escaping or delimiters.
+In the latest examples above, the repetition based on elements of `ip_addrs` is
+achieved by using a
+[`for` expression](/terraform/language/expressions/for)
+rather than by using
+[template directives](/terraform/language/expressions/strings#directives).
+
+```json
+{"backends":["10.0.0.1:8080","10.0.0.2:8080"]}
+```
+
+If the resulting template is small, you can choose instead to write
+`jsonencode` or `yamlencode` calls inline in your main configuration files, and
+avoid creating separate template files at all:
+
+```hcl
+locals {
+  backend_config_json = jsonencode({
+    "backends": [for addr in ip_addrs : "${addr}:${port}"],
+  })
+}
+```
+
+For more information, see the main documentation for
+[`jsonencode`](/terraform/language/functions/jsonencode) and [`yamlencode`](/terraform/language/functions/yamlencode).
+
+## Related Functions
+
+* [`file`](/terraform/language/functions/file) reads a file from disk and returns its literal contents
+  without any template interpretation.
diff --git a/v1.5.7/website/docs/language/functions/textdecodebase64.mdx b/v1.5.7/website/docs/language/functions/textdecodebase64.mdx
new file mode 100644
index 0000000..2ee2007
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/textdecodebase64.mdx
@@ -0,0 +1,42 @@
+---
+page_title: textdecodebase64 - Functions - Configuration Language
+description: >-
+  The textdecodebase64 function decodes a string that was previously
+  Base64-encoded,
+
+  and then interprets the result as characters in a specified character
+  encoding.
+---
+
+# `textdecodebase64` Function
+
+-> **Note:** This function is supported only in Terraform v0.14 and later.
+
+`textdecodebase64` function decodes a string that was previously Base64-encoded,
+and then interprets the result as characters in a specified character encoding.
+
+Terraform uses the "standard" Base64 alphabet as defined in
+[RFC 4648 section 4](https://tools.ietf.org/html/rfc4648#section-4).
+
+The `encoding_name` argument must contain one of the encoding names or aliases
+recorded in
+[the IANA character encoding registry](https://www.iana.org/assignments/character-sets/character-sets.xhtml).
+Terraform supports only a subset of the registered encodings, and the encoding
+support may vary between Terraform versions.
+
+Terraform accepts the encoding name `UTF-8`, which will produce the same result
+as [`base64decode`](/terraform/language/functions/base64decode).
+
+## Examples
+
+```
+> textdecodebase64("SABlAGwAbABvACAAVwBvAHIAbABkAA==", "UTF-16LE")
+Hello World
+```
+
+## Related Functions
+
+* [`textencodebase64`](/terraform/language/functions/textencodebase64) performs the opposite operation,
+  applying target encoding and then Base64 to a string.
+* [`base64decode`](/terraform/language/functions/base64decode) is effectively a shorthand for
+  `textdecodebase64` where the character encoding is fixed as `UTF-8`.
diff --git a/v1.5.7/website/docs/language/functions/textencodebase64.mdx b/v1.5.7/website/docs/language/functions/textencodebase64.mdx
new file mode 100644
index 0000000..b467c2c
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/textencodebase64.mdx
@@ -0,0 +1,51 @@
+---
+page_title: textencodebase64 - Functions - Configuration Language
+description: >-
+  The textencodebase64 function encodes the unicode characters in a given string
+  using a
+
+  specified character encoding, returning the result base64 encoded.
+---
+
+# `textencodebase64` Function
+
+-> **Note:** This function is supported only in Terraform v0.14 and later.
+
+`textencodebase64` encodes the unicode characters in a given string using a
+specified character encoding, returning the result base64 encoded because
+Terraform language strings are always sequences of unicode characters.
+
+```hcl
+substr(string, encoding_name)
+```
+
+Terraform uses the "standard" Base64 alphabet as defined in
+[RFC 4648 section 4](https://tools.ietf.org/html/rfc4648#section-4).
+
+The `encoding_name` argument must contain one of the encoding names or aliases
+recorded in
+[the IANA character encoding registry](https://www.iana.org/assignments/character-sets/character-sets.xhtml).
+Terraform supports only a subset of the registered encodings, and the encoding
+support may vary between Terraform versions. In particular Terraform supports
+`UTF-16LE`, which is the native character encoding for the Windows API and
+therefore sometimes expected by Windows-originated software such as PowerShell.
+
+Terraform also accepts the encoding name `UTF-8`, which will produce the same
+result as [`base64encode`](/terraform/language/functions/base64encode).
+
+## Examples
+
+```
+> textencodebase64("Hello World", "UTF-16LE")
+SABlAGwAbABvACAAVwBvAHIAbABkAA==
+```
+
+## Related Functions
+
+* [`textdecodebase64`](/terraform/language/functions/textdecodebase64) performs the opposite operation,
+  decoding Base64 data and interpreting it as a particular character encoding.
+* [`base64encode`](/terraform/language/functions/base64encode) applies Base64 encoding of the UTF-8
+  encoding of a string.
+* [`filebase64`](/terraform/language/functions/filebase64) reads a file from the local filesystem
+  and returns its raw bytes with Base64 encoding, without creating an
+  intermediate Unicode string.
diff --git a/v1.5.7/website/docs/language/functions/timeadd.mdx b/v1.5.7/website/docs/language/functions/timeadd.mdx
new file mode 100644
index 0000000..f255237
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/timeadd.mdx
@@ -0,0 +1,38 @@
+---
+page_title: timeadd - Functions - Configuration Language
+description: |-
+  The timeadd function adds a duration to a timestamp, returning a new
+  timestamp.
+---
+
+# `timeadd` Function
+
+`timeadd` adds a duration to a timestamp, returning a new timestamp.
+
+```hcl
+timeadd(timestamp, duration)
+```
+
+In the Terraform language, timestamps are conventionally represented as
+strings using [RFC 3339](https://tools.ietf.org/html/rfc3339)
+"Date and Time format" syntax. `timeadd` requires the `timestamp` argument
+to be a string conforming to this syntax.
+
+`duration` is a string representation of a time difference, consisting of
+sequences of number and unit pairs, like `"1.5h"` or `"1h30m"`. The accepted
+units are `"ns"`, `"us"` (or `"µs"`), `"ms"`, `"s"`, `"m"`, and `"h"`. The first
+number may be negative to indicate a negative duration, like `"-2h5m"`.
+
+The result is a string, also in RFC 3339 format, representing the result
+of adding the given direction to the given timestamp.
+
+## Examples
+
+```
+> timeadd("2017-11-22T00:00:00Z", "10m")
+2017-11-22T00:10:00Z
+```
+
+# Related Functions
+
+* [`timecmp`](/terraform/language/functions/timecmp) determines an ordering for two timestamps.
diff --git a/v1.5.7/website/docs/language/functions/timecmp.mdx b/v1.5.7/website/docs/language/functions/timecmp.mdx
new file mode 100644
index 0000000..2c078a9
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/timecmp.mdx
@@ -0,0 +1,66 @@
+---
+page_title: timecmp - Functions - Configuration Language
+description: |-
+  The timecmp function adds a duration to a timestamp, returning a new
+  timestamp.
+---
+
+# `timecmp` Function
+
+`timecmp` compares two timestamps and returns a number that represents the
+ordering of the instants those timestamps represent.
+
+```hcl
+timecmp(timestamp_a, timestamp_b)
+```
+
+| Condition                                          | Return Value |
+|----------------------------------------------------|--------------|
+| `timestamp_a` is before `timestamp_b`              | `-1`         |
+| `timestamp_a` is the same instant as `timestamp_b` | `0`          |
+| `timestamp_a` is after `timestamp_b`               | `1`          |
+
+When comparing the timestamps, `timecmp` takes into account the UTC offsets
+given in each timestamp. For example, `06:00:00+0200` and `04:00:00Z` are
+the same instant after taking into account the `+0200` offset on the first
+timestamp.
+
+In the Terraform language, timestamps are conventionally represented as
+strings using [RFC 3339](https://tools.ietf.org/html/rfc3339)
+"Date and Time format" syntax. `timecmp` requires the its two arguments to
+both be strings conforming to this syntax.
+
+## Examples
+
+```
+> timecmp("2017-11-22T00:00:00Z", "2017-11-22T00:00:00Z")
+0
+> timecmp("2017-11-22T00:00:00Z", "2017-11-22T01:00:00Z")
+-1
+> timecmp("2017-11-22T01:00:00Z", "2017-11-22T00:00:00Z")
+1
+> timecmp("2017-11-22T01:00:00Z", "2017-11-22T00:00:00-01:00")
+0
+```
+
+`timecmp` can be particularly useful in defining
+[custom condition checks](/terraform/language/expressions/custom-conditions) that
+involve a specified timestamp being within a particular range. For example,
+the following resource postcondition would raise an error if a TLS certificate
+(or other expiring object) expires sooner than 30 days from the time of
+the "apply" step:
+
+```hcl
+  lifecycle {
+    postcondition {
+      condition     = timecmp(timestamp(), timeadd(self.expiration_timestamp, "-720h")) < 0
+      error_message = "Certificate will expire in less than 30 days."
+    }
+  }
+```
+
+## Related Functions
+
+* [`timestamp`](/terraform/language/functions/timestamp) returns the current timestamp when it is evaluated
+  during the apply step.
+* [`timeadd`](/terraform/language/functions/timeadd) can perform arithmetic on timestamps by adding or removing a specified duration.
diff --git a/v1.5.7/website/docs/language/functions/timestamp.mdx b/v1.5.7/website/docs/language/functions/timestamp.mdx
new file mode 100644
index 0000000..ad9f8be
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/timestamp.mdx
@@ -0,0 +1,41 @@
+---
+page_title: timestamp - Functions - Configuration Language
+description: |-
+  The timestamp function returns a string representation of the current date
+  and time.
+---
+
+# `timestamp` Function
+
+`timestamp` returns a UTC timestamp string in [RFC 3339](https://tools.ietf.org/html/rfc3339) format.
+
+In the Terraform language, timestamps are conventionally represented as
+strings using [RFC 3339](https://tools.ietf.org/html/rfc3339)
+"Date and Time format" syntax, and so `timestamp` returns a string
+in this format.
+
+The result of this function will change every second, so using this function
+directly with resource attributes will cause a diff to be detected on every
+Terraform run. We do not recommend using this function in resource attributes,
+but in rare cases it can be used in conjunction with
+[the `ignore_changes` lifecycle meta-argument](/terraform/language/meta-arguments/lifecycle#ignore_changes)
+to take the timestamp only on initial creation of the resource. For more stable
+time handling, see the [Time Provider](https://registry.terraform.io/providers/hashicorp/time).
+
+Due to the constantly changing return value, the result of this function cannot
+be predicted during Terraform's planning phase, and so the timestamp will be
+taken only once the plan is being applied.
+
+## Examples
+
+```
+> timestamp()
+2018-05-13T07:44:12Z
+```
+
+## Related Functions
+
+* [`formatdate`](/terraform/language/functions/formatdate) can convert the resulting timestamp to
+  other date and time formats.
+* [`plantimestamp`](/terraform/language/functions/plantimestamp) will return a consistent timestamp
+  representing the date and time during the plan.
diff --git a/v1.5.7/website/docs/language/functions/title.mdx b/v1.5.7/website/docs/language/functions/title.mdx
new file mode 100644
index 0000000..ba7a6d9
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/title.mdx
@@ -0,0 +1,24 @@
+---
+page_title: title - Functions - Configuration Language
+description: |-
+  The title function converts the first letter of each word in a given string
+  to uppercase.
+---
+
+# `title` Function
+
+`title` converts the first letter of each word in the given string to uppercase.
+
+## Examples
+
+```
+> title("hello world")
+Hello World
+```
+
+This function uses Unicode's definition of letters and of upper- and lowercase.
+
+## Related Functions
+
+* [`upper`](/terraform/language/functions/upper) converts _all_ letters in a string to uppercase.
+* [`lower`](/terraform/language/functions/lower) converts all letters in a string to lowercase.
diff --git a/v1.5.7/website/docs/language/functions/tobool.mdx b/v1.5.7/website/docs/language/functions/tobool.mdx
new file mode 100644
index 0000000..766b6a2
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/tobool.mdx
@@ -0,0 +1,36 @@
+---
+page_title: tobool - Functions - Configuration Language
+description: The tobool function converts a value to boolean.
+---
+
+# `tobool` Function
+
+`tobool` converts its argument to a boolean value.
+
+Explicit type conversions are rarely necessary in Terraform because it will
+convert types automatically where required. Use the explicit type conversion
+functions only to normalize types returned in module outputs.
+
+Only boolean values, `null`, and the exact strings `"true"` and `"false"` can be
+converted to boolean. All other values will produce an error.
+
+## Examples
+
+```
+> tobool(true)
+true
+> tobool("true")
+true
+> tobool(null)
+null
+> tobool("no")
+Error: Invalid function argument
+
+Invalid value for "v" parameter: cannot convert "no" to bool: only the strings
+"true" or "false" are allowed.
+
+> tobool(1)
+Error: Invalid function argument
+
+Invalid value for "v" parameter: cannot convert number to bool.
+```
diff --git a/v1.5.7/website/docs/language/functions/tolist.mdx b/v1.5.7/website/docs/language/functions/tolist.mdx
new file mode 100644
index 0000000..212a430
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/tolist.mdx
@@ -0,0 +1,39 @@
+---
+page_title: tolist - Functions - Configuration Language
+description: The tolist function converts a value to a list.
+---
+
+# `tolist` Function
+
+`tolist` converts its argument to a list value.
+
+Explicit type conversions are rarely necessary in Terraform because it will
+convert types automatically where required. Use the explicit type conversion
+functions only to normalize types returned in module outputs.
+
+Pass a _set_ value to `tolist` to convert it to a list. Since set elements are
+not ordered, the resulting list will have an undefined order that will be
+consistent within a particular run of Terraform.
+
+## Examples
+
+```
+> tolist(["a", "b", "c"])
+[
+  "a",
+  "b",
+  "c",
+]
+```
+
+Since Terraform's concept of a list requires all of the elements to be of the
+same type, mixed-typed elements will be converted to the most general type:
+
+```
+> tolist(["a", "b", 3])
+[
+  "a",
+  "b",
+  "3",
+]
+```
diff --git a/v1.5.7/website/docs/language/functions/tomap.mdx b/v1.5.7/website/docs/language/functions/tomap.mdx
new file mode 100644
index 0000000..da2ebc6
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/tomap.mdx
@@ -0,0 +1,33 @@
+---
+page_title: tomap - Functions - Configuration Language
+description: The tomap function converts a value to a map.
+---
+
+# `tomap` Function
+
+`tomap` converts its argument to a map value.
+
+Explicit type conversions are rarely necessary in Terraform because it will
+convert types automatically where required. Use the explicit type conversion
+functions only to normalize types returned in module outputs.
+
+## Examples
+
+```
+> tomap({"a" = 1, "b" = 2})
+{
+  "a" = 1
+  "b" = 2
+}
+```
+
+Since Terraform's concept of a map requires all of the elements to be of the
+same type, mixed-typed elements will be converted to the most general type:
+
+```
+> tomap({"a" = "foo", "b" = true})
+{
+  "a" = "foo"
+  "b" = "true"
+}
+```
diff --git a/v1.5.7/website/docs/language/functions/tonumber.mdx b/v1.5.7/website/docs/language/functions/tonumber.mdx
new file mode 100644
index 0000000..4aa15c0
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/tonumber.mdx
@@ -0,0 +1,31 @@
+---
+page_title: tonumber - Functions - Configuration Language
+description: The tonumber function converts a value to a number.
+---
+
+# `tonumber` Function
+
+`tonumber` converts its argument to a number value.
+
+Explicit type conversions are rarely necessary in Terraform because it will
+convert types automatically where required. Use the explicit type conversion
+functions only to normalize types returned in module outputs.
+
+Only numbers, `null`, and strings containing decimal representations of numbers can be
+converted to number. All other values will produce an error.
+
+## Examples
+
+```
+> tonumber(1)
+1
+> tonumber("1")
+1
+> tonumber(null)
+null
+> tonumber("no")
+Error: Invalid function argument
+
+Invalid value for "v" parameter: cannot convert "no" to number: string must be
+a decimal representation of a number.
+```
diff --git a/v1.5.7/website/docs/language/functions/toset.mdx b/v1.5.7/website/docs/language/functions/toset.mdx
new file mode 100644
index 0000000..1b42f4d
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/toset.mdx
@@ -0,0 +1,50 @@
+---
+page_title: toset - Functions - Configuration Language
+description: The toset function converts a value to a set.
+---
+
+# `toset` Function
+
+`toset` converts its argument to a set value.
+
+Explicit type conversions are rarely necessary in Terraform because it will
+convert types automatically where required. Use the explicit type conversion
+functions only to normalize types returned in module outputs.
+
+Pass a _list_ value to `toset` to convert it to a set, which will remove any
+duplicate elements and discard the ordering of the elements.
+
+## Examples
+
+```
+> toset(["a", "b", "c"])
+[
+  "a",
+  "b",
+  "c",
+]
+```
+
+Since Terraform's concept of a set requires all of the elements to be of the
+same type, mixed-typed elements will be converted to the most general type:
+
+```
+> toset(["a", "b", 3])
+[
+  "3",
+  "a",
+  "b",
+]
+```
+
+Set collections are unordered and cannot contain duplicate values, so the
+ordering of the argument elements is lost and any duplicate values are
+coalesced:
+
+```
+> toset(["c", "b", "b"])
+[
+  "b",
+  "c",
+]
+```
diff --git a/v1.5.7/website/docs/language/functions/tostring.mdx b/v1.5.7/website/docs/language/functions/tostring.mdx
new file mode 100644
index 0000000..5df650a
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/tostring.mdx
@@ -0,0 +1,32 @@
+---
+page_title: tostring - Functions - Configuration Language
+description: The tostring function converts a value to a string.
+---
+
+# `tostring` Function
+
+`tostring` converts its argument to a string value.
+
+Explicit type conversions are rarely necessary in Terraform because it will
+convert types automatically where required. Use the explicit type conversion
+functions only to normalize types returned in module outputs.
+
+Only the primitive types (string, number, and bool) and `null` can be converted to string.
+`tostring(null)` produces a `null` value of type `string`. All other values produce an error. 
+
+## Examples
+
+```
+> tostring("hello")
+"hello"
+> tostring(1)
+"1"
+> tostring(true)
+"true"
+> tostring(null)
+tostring(null)
+> tostring([])
+Error: Invalid function argument
+
+Invalid value for "v" parameter: cannot convert tuple to string.
+```
diff --git a/v1.5.7/website/docs/language/functions/transpose.mdx b/v1.5.7/website/docs/language/functions/transpose.mdx
new file mode 100644
index 0000000..2de3bf4
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/transpose.mdx
@@ -0,0 +1,29 @@
+---
+page_title: transpose - Functions - Configuration Language
+description: |-
+  The transpose function takes a map of lists of strings and swaps the keys
+  and values.
+---
+
+# `transpose` Function
+
+`transpose` takes a map of lists of strings and swaps the keys and values
+to produce a new map of lists of strings.
+
+## Examples
+
+```
+> transpose({"a" = ["1", "2"], "b" = ["2", "3"]})
+{
+  "1" = [
+    "a",
+  ],
+  "2" = [
+    "a",
+    "b",
+  ],
+  "3" = [
+    "b",
+  ],
+}
+```
diff --git a/v1.5.7/website/docs/language/functions/trim.mdx b/v1.5.7/website/docs/language/functions/trim.mdx
new file mode 100644
index 0000000..7cdd032
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/trim.mdx
@@ -0,0 +1,40 @@
+---
+page_title: trim - Functions - Configuration Language
+description: >-
+  The trim function removes the specified set of characters from the start and
+  end of
+
+  a given string.
+---
+
+# `trim` Function
+
+`trim` removes the specified set of characters from the start and end of the given
+string.
+
+```hcl
+trim(string, str_character_set)
+```
+
+Every occurrence of a character in the second argument is removed from the start
+and end of the string specified in the first argument.
+
+## Examples
+
+```
+> trim("?!hello?!", "!?")
+"hello"
+
+> trim("foobar", "far")
+"oob"
+
+> trim("   hello! world.!  ", "! ")
+"hello! world."
+```
+
+## Related Functions
+
+* [`trimprefix`](/terraform/language/functions/trimprefix) removes a word from the start of a string.
+* [`trimsuffix`](/terraform/language/functions/trimsuffix) removes a word from the end of a string.
+* [`trimspace`](/terraform/language/functions/trimspace) removes all types of whitespace from
+  both the start and the end of a string.
diff --git a/v1.5.7/website/docs/language/functions/trimprefix.mdx b/v1.5.7/website/docs/language/functions/trimprefix.mdx
new file mode 100644
index 0000000..51b931b
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/trimprefix.mdx
@@ -0,0 +1,29 @@
+---
+page_title: trimprefix - Functions - Configuration Language
+description: |-
+  The trimprefix function removes the specified prefix from the start of a
+  given string.
+---
+
+# `trimprefix` Function
+
+`trimprefix` removes the specified prefix from the start of the given string. If the string does not start with the prefix, the string is returned unchanged.
+
+## Examples
+
+```
+> trimprefix("helloworld", "hello")
+world
+```
+
+```
+> trimprefix("helloworld", "cat")
+helloworld
+```
+
+## Related Functions
+
+* [`trim`](/terraform/language/functions/trim) removes characters at the start and end of a string.
+* [`trimsuffix`](/terraform/language/functions/trimsuffix) removes a word from the end of a string.
+* [`trimspace`](/terraform/language/functions/trimspace) removes all types of whitespace from
+  both the start and the end of a string.
diff --git a/v1.5.7/website/docs/language/functions/trimspace.mdx b/v1.5.7/website/docs/language/functions/trimspace.mdx
new file mode 100644
index 0000000..a1eafab
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/trimspace.mdx
@@ -0,0 +1,27 @@
+---
+page_title: trimspace - Functions - Configuration Language
+description: |-
+  The trimspace function removes space characters from the start and end of
+  a given string.
+---
+
+# `trimspace` Function
+
+`trimspace` removes any space characters from the start and end of the given
+string.
+
+This function follows the Unicode definition of "space", which includes
+regular spaces, tabs, newline characters, and various other space-like
+characters.
+
+## Examples
+
+```
+> trimspace("  hello\n\n")
+hello
+```
+
+## Related Functions
+
+* [`chomp`](/terraform/language/functions/chomp) removes just line ending characters from the _end_ of
+  a string.
diff --git a/v1.5.7/website/docs/language/functions/trimsuffix.mdx b/v1.5.7/website/docs/language/functions/trimsuffix.mdx
new file mode 100644
index 0000000..31f12f2
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/trimsuffix.mdx
@@ -0,0 +1,24 @@
+---
+page_title: trimsuffix - Functions - Configuration Language
+description: |-
+  The trimsuffix function removes the specified suffix from the end of a
+  given string.
+---
+
+# `trimsuffix` Function
+
+`trimsuffix` removes the specified suffix from the end of the given string.
+
+## Examples
+
+```
+> trimsuffix("helloworld", "world")
+hello
+```
+
+## Related Functions
+
+* [`trim`](/terraform/language/functions/trim) removes characters at the start and end of a string.
+* [`trimprefix`](/terraform/language/functions/trimprefix) removes a word from the start of a string.
+* [`trimspace`](/terraform/language/functions/trimspace) removes all types of whitespace from
+  both the start and the end of a string.
diff --git a/v1.5.7/website/docs/language/functions/try.mdx b/v1.5.7/website/docs/language/functions/try.mdx
new file mode 100644
index 0000000..fffc932
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/try.mdx
@@ -0,0 +1,111 @@
+---
+page_title: try - Functions - Configuration Language
+description: |-
+  The try function tries to evaluate a sequence of expressions given as
+  arguments and returns the result of the first one that does not produce
+  any errors.
+---
+
+# `try` Function
+
+`try` evaluates all of its argument expressions in turn and returns the result
+of the first one that does not produce any errors.
+
+This is a special function that is able to catch errors produced when evaluating
+its arguments, which is particularly useful when working with complex data
+structures whose shape is not well-known at implementation time.
+
+For example, if some data is retrieved from an external system in JSON or YAML
+format and then decoded, the result may have attributes that are not guaranteed
+to be set. We can use `try` to produce a normalized data structure which has
+a predictable type that can therefore be used more conveniently elsewhere in
+the configuration:
+
+```hcl
+locals {
+  raw_value = yamldecode(file("${path.module}/example.yaml"))
+  normalized_value = {
+    name   = tostring(try(local.raw_value.name, null))
+    groups = try(local.raw_value.groups, [])
+  }
+}
+```
+
+With the above local value expressions, configuration elsewhere in the module
+can refer to `local.normalized_value` attributes without the need to repeatedly
+check for and handle absent attributes that would otherwise produce errors.
+
+We can also use `try` to deal with situations where a value might be provided
+in two different forms, allowing us to normalize to the most general form:
+
+```hcl
+variable "example" {
+  type = any
+}
+
+locals {
+  example = try(
+    [tostring(var.example)],
+    tolist(var.example),
+  )
+}
+```
+
+The above permits `var.example` to be either a list or a single string. If it's
+a single string then it'll be normalized to a single-element list containing
+that string, again allowing expressions elsewhere in the configuration to just
+assume that `local.example` is always a list.
+
+This second example contains two expressions that can both potentially fail.
+For example, if `var.example` were set to `{}` then it could be converted to
+neither a string nor a list. If `try` exhausts all of the given expressions
+without any succeeding, it will return an error describing all of the problems
+it encountered.
+
+We strongly suggest using `try` only in special local values whose expressions
+perform normalization, so that the error handling is confined to a single
+location in the module and the rest of the module can just use straightforward
+references to the normalized structure and thus be more readable for future
+maintainers.
+
+The `try` function can only catch and handle _dynamic_ errors resulting from
+access to data that isn't known until runtime. It will not catch errors
+relating to expressions that can be proven to be invalid for any input, such
+as a malformed resource reference.
+
+~> **Warning:** The `try` function is intended only for concise testing of the
+presence of and types of object attributes. Although it can technically accept
+any sort of expression, we recommend using it only with simple attribute
+references and type conversion functions as shown in the examples above.
+Overuse of `try` to suppress errors will lead to a configuration that is hard
+to understand and maintain.
+
+## Examples
+
+```
+> local.foo
+{
+  "bar" = "baz"
+}
+> try(local.foo.bar, "fallback")
+baz
+> try(local.foo.boop, "fallback")
+fallback
+```
+
+The `try` function will _not_ catch errors relating to constructs that are
+provably invalid even before dynamic expression evaluation, such as a malformed
+reference or a reference to a top-level object that has not been declared:
+
+```
+> try(local.nonexist, "fallback")
+
+Error: Reference to undeclared local value
+
+A local value with the name "nonexist" has not been declared.
+```
+
+## Related Functions
+
+* [`can`](/terraform/language/functions/can), which tries evaluating an expression and returns a
+  boolean value indicating whether it succeeded.
diff --git a/v1.5.7/website/docs/language/functions/type.mdx b/v1.5.7/website/docs/language/functions/type.mdx
new file mode 100644
index 0000000..9a5eb72
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/type.mdx
@@ -0,0 +1,81 @@
+---
+page_title: type - Functions - Configuration Language
+description: 'The type function returns the type of a given value. '
+---
+
+# `type` Function
+
+-> **Note:** This function is available only in Terraform 1.0 and later.
+
+`type` returns the type of a given value.
+
+Sometimes a Terraform configuration can result in confusing errors regarding
+inconsistent types. This function displays terraform's evaluation of a given
+value's type, which is useful in understanding this error message.
+
+This is a special function which is only available in the `terraform console`
+command. It can only be used to examine the type of a given value, and should
+not be used in more complex expressions.
+
+## Examples
+
+Here we have a conditional `output` which prints either the value of `var.list` or a local named `default_list`:
+
+```hcl
+variable "list" {
+  default = []
+}
+
+locals {
+  default_list = [
+    {
+      foo = "bar"
+      map = { bleep = "bloop" }
+    },
+    {
+      beep = "boop"
+    },
+  ]
+}
+
+output "list" {
+  value = var.list != [] ? var.list : local.default_list
+}
+```
+
+Applying this configuration results in the following error:
+
+```
+Error: Inconsistent conditional result types
+
+  on main.tf line 18, in output "list":
+  18:   value = var.list != [] ? var.list : local.default_list
+    |----------------
+    | local.default_list is tuple with 2 elements
+    | var.list is empty tuple
+
+The true and false result expressions must have consistent types. The given
+expressions are tuple and tuple, respectively.
+```
+
+While this error message does include some type information, it can be helpful
+to inspect the exact type that Terraform has determined for each given input.
+Examining both `var.list` and `local.default_list` using the `type` function
+provides more context for the error message:
+
+```
+> type(var.list)
+tuple
+> type(local.default_list)
+tuple([
+    object({
+        foo: string,
+        map: object({
+            bleep: string,
+        }),
+    }),
+    object({
+        beep: string,
+    }),
+])
+```
diff --git a/v1.5.7/website/docs/language/functions/upper.mdx b/v1.5.7/website/docs/language/functions/upper.mdx
new file mode 100644
index 0000000..874e40f
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/upper.mdx
@@ -0,0 +1,26 @@
+---
+page_title: upper - Functions - Configuration Language
+description: >-
+  The upper function converts all cased letters in the given string to
+  uppercase.
+---
+
+# `upper` Function
+
+`upper` converts all cased letters in the given string to uppercase.
+
+## Examples
+
+```
+> upper("hello")
+HELLO
+> upper("алло!")
+АЛЛО!
+```
+
+This function uses Unicode's definition of letters and of upper- and lowercase.
+
+## Related Functions
+
+* [`lower`](/terraform/language/functions/lower) converts letters in a string to _lowercase_.
+* [`title`](/terraform/language/functions/title) converts the first letter of each word in a string to uppercase.
diff --git a/v1.5.7/website/docs/language/functions/urlencode.mdx b/v1.5.7/website/docs/language/functions/urlencode.mdx
new file mode 100644
index 0000000..1ce11da
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/urlencode.mdx
@@ -0,0 +1,31 @@
+---
+page_title: urlencode - Functions - Configuration Language
+description: The urlencode function applies URL encoding to a given string.
+---
+
+# `urlencode` Function
+
+`urlencode` applies URL encoding to a given string.
+
+This function identifies characters in the given string that would have a
+special meaning when included as a query string argument in a URL and
+escapes them using
+[RFC 3986 "percent encoding"](https://tools.ietf.org/html/rfc3986#section-2.1).
+
+The exact set of characters escaped may change over time, but the result
+is guaranteed to be interpolatable into a query string argument without
+inadvertently introducing additional delimiters.
+
+If the given string contains non-ASCII characters, these are first encoded as
+UTF-8 and then percent encoding is applied separately to each UTF-8 byte.
+
+## Examples
+
+```
+> urlencode("Hello World!")
+Hello+World%21
+> urlencode("☃")
+%E2%98%83
+> "http://example.com/search?q=${urlencode("terraform urlencode")}"
+http://example.com/search?q=terraform+urlencode
+```
diff --git a/v1.5.7/website/docs/language/functions/uuid.mdx b/v1.5.7/website/docs/language/functions/uuid.mdx
new file mode 100644
index 0000000..2b7967c
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/uuid.mdx
@@ -0,0 +1,37 @@
+---
+page_title: uuid - Functions - Configuration Language
+description: The uuid function generates a unique id.
+---
+
+# `uuid` Function
+
+`uuid` generates a unique identifier string.
+
+The id is a generated and formatted as required by
+[RFC 4122 section 4.4](https://tools.ietf.org/html/rfc4122#section-4.4),
+producing a Version 4 UUID. The result is a UUID generated only from
+pseudo-random numbers.
+
+This function produces a new value each time it is called, and so using it
+directly in resource arguments will result in spurious diffs. We do not
+recommend using the `uuid` function in resource configurations, but it can
+be used with care in conjunction with
+[the `ignore_changes` lifecycle meta-argument](/terraform/language/meta-arguments/lifecycle#ignore_changes).
+
+In most cases we recommend using [the `random` provider](https://registry.terraform.io/providers/hashicorp/random/latest/docs)
+instead, since it allows the one-time generation of random values that are
+then retained in the Terraform [state](/terraform/language/state) for use by
+future operations. In particular,
+[`random_id`](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) can generate results with
+equivalent randomness to the `uuid` function.
+
+## Examples
+
+```
+> uuid()
+b5ee72a3-54dd-c4b8-551c-4bdc0204cedb
+```
+
+## Related Functions
+
+* [`uuidv5`](/terraform/language/functions/uuidv5), which generates name-based UUIDs.
diff --git a/v1.5.7/website/docs/language/functions/uuidv5.mdx b/v1.5.7/website/docs/language/functions/uuidv5.mdx
new file mode 100644
index 0000000..0b45bb5
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/uuidv5.mdx
@@ -0,0 +1,80 @@
+---
+page_title: uuidv5 - Functions - Configuration Language
+description: >-
+  The uuidv5 function generates a uuid v5 string representation of the value in
+  the specified namespace.
+---
+
+# `uuidv5` Function
+
+`uuidv5` generates a _name-based_ UUID, as described in
+[RFC 4122 section 4.3](https://tools.ietf.org/html/rfc4122#section-4.3),
+also known as a "version 5" UUID.
+
+```
+uuidv5(namespace, name)
+```
+
+Unlike the pseudo-random UUIDs generated by
+[`uuid`](/terraform/language/functions/uuid), name-based UUIDs derive from namespace and an name,
+producing the same UUID value every time if the namespace and name are
+unchanged.
+
+Name-based UUID namespaces are themselves UUIDs, but for readability this
+function accepts some keywords as aliases for the namespaces that were
+assigned by RFC 4122:
+
+| Keyword  | Namespace ID                           | Name format                                                                  |
+| -------- | -------------------------------------- | ---------------------------------------------------------------------------- |
+| `"dns"`  | `6ba7b810-9dad-11d1-80b4-00c04fd430c8` | A fully-qualified DNS domain name.                                           |
+| `"url"`  | `6ba7b811-9dad-11d1-80b4-00c04fd430c8` | Any valid URL as defined in [RFC 3986](https://tools.ietf.org/html/rfc3986). |
+| `"oid"`  | `6ba7b812-9dad-11d1-80b4-00c04fd430c8` | An [ISO/IEC object identifier](https://oidref.com/)                          |
+| `"x500"` | `6ba7b814-9dad-11d1-80b4-00c04fd430c8` | [X.500 Distinguished Name](https://tools.ietf.org/html/rfc1779)              |
+
+To use any other namespace not included in the above table, pass its assigned
+namespace ID directly in the first argument in the usual UUID string format.
+
+## Examples
+
+Use the namespace keywords where possible, to make the intent more obvious to
+a future reader:
+
+```
+> uuidv5("dns", "www.terraform.io")
+a5008fae-b28c-5ba5-96cd-82b4c53552d6
+
+> uuidv5("url", "https://www.terraform.io/")
+9db6f67c-dd95-5ea0-aa5b-e70e5c5f7cf5
+
+> uuidv5("oid", "1.3.6.1.4")
+af9d40a5-7a36-5c07-b23a-851cd99fbfa5
+
+> uuidv5("x500", "CN=Example,C=GB")
+84e09961-4aa4-57f8-95b7-03edb1073253
+```
+
+The namespace keywords treated as equivalent to their corresponding namespace
+UUIDs, and in some special cases it may be more appropriate to use the
+UUID form:
+
+```
+> uuidv5("6ba7b810-9dad-11d1-80b4-00c04fd430c8", "www.terraform.io")
+a5008fae-b28c-5ba5-96cd-82b4c53552d6
+```
+
+If you wish to use a namespace defined outside of RFC 4122, using the namespace
+UUID is required because no corresponding keyword is available:
+
+```
+> uuidv5("743ac3c0-3bf7-4a5b-9e6c-59360447c757", "LIBS:diskfont.library")
+ede1a974-df7e-5f17-84b9-76208818b2c8
+```
+
+When using raw UUID namespaces, consider including a comment alongside the
+expression that indicates which namespace this represents in a
+human-significant manner, such as by reference to the standard that
+defined it.
+
+## Related Functions
+
+* [`uuid`](/terraform/language/functions/uuid), which generates pseudorandom UUIDs.
diff --git a/v1.5.7/website/docs/language/functions/values.mdx b/v1.5.7/website/docs/language/functions/values.mdx
new file mode 100644
index 0000000..b7362ab
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/values.mdx
@@ -0,0 +1,28 @@
+---
+page_title: values - Functions - Configuration Language
+description: The values function returns a list of the element values in a given map.
+---
+
+# `values` Function
+
+`values` takes a map and returns a list containing the values of the elements
+in that map.
+
+The values are returned in lexicographical order by their corresponding _keys_,
+so the values will be returned in the same order as their keys would be
+returned from [`keys`](/terraform/language/functions/keys).
+
+## Examples
+
+```
+> values({a=3, c=2, d=1})
+[
+  3,
+  2,
+  1,
+]
+```
+
+## Related Functions
+
+* [`keys`](/terraform/language/functions/keys) returns a list of the _keys_ from a map.
diff --git a/v1.5.7/website/docs/language/functions/yamldecode.mdx b/v1.5.7/website/docs/language/functions/yamldecode.mdx
new file mode 100644
index 0000000..d1fa41e
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/yamldecode.mdx
@@ -0,0 +1,99 @@
+---
+page_title: yamldecode - Functions - Configuration Language
+description: |-
+  The yamldecode function decodes a YAML string into a representation of its
+  value.
+---
+
+# `yamldecode` Function
+
+`yamldecode` parses a string as a subset of YAML, and produces a representation
+of its value.
+
+This function supports a subset of [YAML 1.2](https://yaml.org/spec/1.2/spec.html),
+as described below.
+
+This function maps YAML values to
+[Terraform language values](/terraform/language/expressions/types)
+in the following way:
+
+| YAML type     | Terraform type                                                     |
+| ------------- | ------------------------------------------------------------------ |
+| `!!str`       | `string`                                                           |
+| `!!float`     | `number`                                                           |
+| `!!int`       | `number`                                                           |
+| `!!bool`      | `bool`                                                             |
+| `!!map`       | `object(...)` with attribute types determined per this table       |
+| `!!seq`       | `tuple(...)` with element types determined per this table          |
+| `!!null`      | The Terraform language `null` value                                |
+| `!!timestamp` | `string` in [RFC 3339](https://tools.ietf.org/html/rfc3339) format |
+| `!!binary`    | `string` containing base64-encoded representation                  |
+
+The Terraform language automatic type conversion rules mean that you don't
+usually need to worry about exactly what type is produced for a given value,
+and can just use the result in an intuitive way.
+
+Note though that the mapping above is ambiguous -- several different source
+types map to the same target type -- and so round-tripping through `yamldecode`
+and then `yamlencode` cannot produce an identical result.
+
+YAML is a complex language and it supports a number of possibilities that the
+Terraform language's type system cannot represent. Therefore this YAML decoder
+supports only a subset of YAML 1.2, with restrictions including the following:
+
+- Although aliases to earlier anchors are supported, cyclic data structures
+  (where a reference to a collection appears inside that collection) are not.
+  If `yamldecode` detects such a structure then it will return an error.
+
+- Only the type tags shown in the above table (or equivalent alternative
+  representations of those same tags) are supported. Any other tags will
+  result in an error.
+
+- Only one YAML document is permitted. If multiple documents are present in
+  the given string then this function will return an error.
+
+## Examples
+
+```
+> yamldecode("hello: world")
+{
+  "hello" = "world"
+}
+
+> yamldecode("true")
+true
+
+> yamldecode("{a: &foo [1, 2, 3], b: *foo}")
+{
+  "a" = [
+    1,
+    2,
+    3,
+  ]
+  "b" = [
+    1,
+    2,
+    3,
+  ]
+}
+
+> yamldecode("{a: &foo [1, *foo, 3]}")
+
+Error: Error in function call
+
+Call to function "yamldecode" failed: cannot refer to anchor "foo" from inside
+its own definition.
+
+> yamldecode("{a: !not-supported foo}")
+
+Error: Error in function call
+
+Call to function "yamldecode" failed: unsupported tag "!not-supported".
+```
+
+## Related Functions
+
+- [`jsondecode`](/terraform/language/functions/jsondecode) is a similar operation using JSON instead
+  of YAML.
+- [`yamlencode`](/terraform/language/functions/yamlencode) performs the opposite operation, _encoding_
+  a value as YAML.
diff --git a/v1.5.7/website/docs/language/functions/yamlencode.mdx b/v1.5.7/website/docs/language/functions/yamlencode.mdx
new file mode 100644
index 0000000..c060124
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/yamlencode.mdx
@@ -0,0 +1,77 @@
+---
+page_title: yamlencode - Functions - Configuration Language
+description: The yamlencode function encodes a given value as a YAML string.
+---
+
+# `yamlencode` Function
+
+`yamlencode` encodes a given value to a string using
+[YAML 1.2](https://yaml.org/spec/1.2/spec.html) block syntax.
+
+This function maps
+[Terraform language values](/terraform/language/expressions/types)
+to YAML tags in the following way:
+
+| Terraform type | YAML type            |
+| -------------- | -------------------- |
+| `string`       | `!!str`              |
+| `number`       | `!!float` or `!!int` |
+| `bool`         | `!!bool`             |
+| `list(...)`    | `!!seq`              |
+| `set(...)`     | `!!seq`              |
+| `tuple(...)`   | `!!seq`              |
+| `map(...)`     | `!!map`              |
+| `object(...)`  | `!!map`              |
+| Null value     | `!!null`             |
+
+`yamlencode` uses the implied syntaxes for all of the above types, so it does
+not generate explicit YAML tags.
+
+Because the YAML format cannot fully represent all of the Terraform language
+types, passing the `yamlencode` result to `yamldecode` will not produce an
+identical value, but the Terraform language automatic type conversion rules
+mean that this is rarely a problem in practice.
+
+YAML is a superset of JSON, and so where possible we recommend generating
+JSON using [`jsonencode`](/terraform/language/functions/jsonencode) instead, even if
+a remote system supports YAML. JSON syntax is equivalent to flow-style YAML
+and Terraform can present detailed structural change information for JSON
+values in plans, whereas Terraform will treat block-style YAML just as a normal
+multi-line string. However, generating YAML may improve readability if the
+resulting value will be directly read or modified in the remote system by
+humans.
+
+## Examples
+
+```
+> yamlencode({"a":"b", "c":"d"})
+"a": "b"
+"c": "d"
+
+> yamlencode({"foo":[1, 2, 3], "bar": "baz"})
+"bar": "baz"
+"foo":
+- 1
+- 2
+- 3
+
+> yamlencode({"foo":[1, {"a":"b","c":"d"}, 3], "bar": "baz"})
+"bar": "baz"
+"foo":
+- 1
+- "a": "b"
+  "c": "d"
+- 3
+```
+
+`yamlencode` always uses YAML's "block style" for mappings and sequences, unless
+the mapping or sequence is empty. To generate flow-style YAML, use
+[`jsonencode`](/terraform/language/functions/jsonencode) instead: YAML flow-style is a superset
+of JSON syntax.
+
+## Related Functions
+
+- [`jsonencode`](/terraform/language/functions/jsonencode) is a similar operation using JSON instead
+  of YAML.
+- [`yamldecode`](/terraform/language/functions/yamldecode) performs the opposite operation, _decoding_
+  a YAML string to obtain its represented value.
diff --git a/v1.5.7/website/docs/language/functions/zipmap.mdx b/v1.5.7/website/docs/language/functions/zipmap.mdx
new file mode 100644
index 0000000..277543e
--- /dev/null
+++ b/v1.5.7/website/docs/language/functions/zipmap.mdx
@@ -0,0 +1,33 @@
+---
+page_title: zipmap - Functions - Configuration Language
+description: |-
+  The zipmap function constructs a map from a list of keys and a corresponding
+  list of values.
+---
+
+# `zipmap` Function
+
+`zipmap` constructs a map from a list of keys and a corresponding list of
+values.
+
+```hcl
+zipmap(keyslist, valueslist)
+```
+
+Both `keyslist` and `valueslist` must be of the same length. `keyslist` must
+be a list of strings, while `valueslist` can be a list of any type.
+
+Each pair of elements with the same index from the two lists will be used
+as the key and value of an element in the resulting map. If the same value
+appears multiple times in `keyslist` then the value with the highest index
+is used in the resulting map.
+
+## Examples
+
+```
+> zipmap(["a", "b"], [1, 2])
+{
+  "a" = 1
+  "b" = 2
+}
+```
diff --git a/v1.5.7/website/docs/language/import/generating-configuration.mdx b/v1.5.7/website/docs/language/import/generating-configuration.mdx
new file mode 100644
index 0000000..66ae392
--- /dev/null
+++ b/v1.5.7/website/docs/language/import/generating-configuration.mdx
@@ -0,0 +1,146 @@
+---
+page_title: Import - Generating Configuration
+description: >-
+  Generate configuration and manage existing resources with Terraform using configuration-driven import.
+---
+
+# Generating configuration
+
+~> **Experimental:** Configuration generation is available in Terraform v1.5 as an experimental feature. Later minor versions may contain changes to the formatting of generated configuration and behavior of the `terraform plan` command using the `-generate-config-out` flag.
+
+Terraform can generate code for the resources you define in [`import` blocks](/terraform/language/import) that do not already exist in your configuration. Terraform produces HCL to act as a template that contains Terraform's best guess at the appropriate value for each resource argument.
+
+Starting with Terraform's generated HCL, we recommend iterating to find your ideal configuration by removing some attributes, adjusting the value of others, and rearranging `resource` blocks into files and modules as appropriate.
+
+To generate configuration, run `terraform plan` with the `-generate-config-out` flag and supply a new file path. Do not supply a path to an existing file, or Terraform throws an error.
+
+```shell
+$ terraform plan -generate-config-out=generated_resources.tf
+```
+
+If any resources targeted by an `import` block do not exist in your configuration, Terraform then generates and writes configuration for those resources in `generated_resources.tf`.
+
+## Workflow
+
+The workflow for generating configuration is similar to the [`import` block workflow](/terraform/language/import#plan-and-apply-an-import), with the extra step of generating configuration during the planning stage. You can then review and modify the generated configuration before applying. 
+
+### 1. Add the `import` block
+
+Add an `import` block to your configuration. This `import` block can be in a separate file (e.g., `import.tf`) or an existing configuration file.
+
+```hcl
+import {
+  to = aws_iot_thing.bar
+  id = "foo"
+}
+```
+
+The import block's `to` argument points to the address a `resource` will have in your state file. If a resource address in your state matches an `import` block's `to` argument, Terraform attempts to import into that resource. In future planning, Terraform knows it doesn't need to generate configuration for resources that already exist in your state.
+
+The import block's `id` argument uses that resource's [import ID](/terraform/language/import#import-id).
+
+If your configuration does not contain other resources for your selected provider, you must add a `provider` block to inform Terraform which provider it should use to generate configuration. Otherwise, Terraform displays an error if it can not determine which provider to use.
+If you add a new `provider` block to your configuration, you must run `terraform init` again.
+
+### 2. Plan and generate configuration
+
+To instruct Terraform to generate configuration for the `import` blocks you defined, run `terraform plan` with the `-generate-config-out=` flag and a new file path. Terraform displays its plan for importing your resource and the file where Terraform generated configuration based on this plan. 
+
+```shell
+$ terraform plan -generate-config-out=generated.tf
+
+aws_iot_thing.bar: Preparing import... [id=foo]
+aws_iot_thing.bar: Refreshing state... [id=foo]
+
+Terraform will perform the following actions:
+
+  # aws_iot_thing.bar will be imported
+  # (config will be generated)
+    resource "aws_iot_thing" "bar" {
+        arn               = "arn:aws:iot:eu-west-1:1234567890:thing/foo"
+        attributes        = {}
+        default_client_id = "foo"
+        id                = "foo"
+        name              = "foo"
+        version           = 1
+    }
+
+Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.
+
+╷
+│ Warning: Config generation is experimental
+│ 
+│ Generating configuration during import is currently experimental, and the generated configuration format may change in future versions.
+╵
+
+──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
+
+Terraform has generated configuration and written it to generated.tf. Please review the configuration and edit it as necessary before adding it to version control.
+```
+
+### 3. Review generated configuration
+
+The example above instructs Terraform to generate configuration in a file named `generated.tf`. The below code is an example of a `generated.tf` file.
+
+```hcl
+resource aws_iot_thing "bar" {
+  name = "foo"
+}
+```
+
+Review the generated configuration and update it as needed. You may wish to move the generated configuration to another file, add or remove resource arguments, or update it to reference input variables or other resources in your configuration. 
+
+### 4. Apply
+
+Run `terraform apply` to import your infrastructure.
+
+```shell
+$ terraform apply
+
+aws_iot_thing.bar: Preparing import... [id=foo]
+aws_iot_thing.bar: Refreshing state... [id=foo]
+
+Terraform will perform the following actions:
+
+  # aws_iot_thing.bar will be imported
+    resource "aws_iot_thing" "bar" {
+        arn               = "arn:aws:iot:eu-west-1:1234567890:thing/foo"
+        attributes        = {}
+        default_client_id = "foo"
+        id                = "foo"
+        name              = "foo"
+        version           = 1
+    }
+
+Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.
+aws_iot_thing.bar: Importing... [id=foo]
+aws_iot_thing.bar: Import complete [id=foo]
+
+Apply complete! Resources: 1 imported, 0 added, 0 changed, 0 destroyed.
+
+```
+
+Commit your new resource configuration to your version control system.
+
+## Limitations
+
+### Conflicting resource arguments
+
+Terraform generates configuration for importable resources during a plan by requesting values for resource attributes from the provider. For certain resources with complex schemas, Terraform may not be able to construct a valid configuration from these values.
+
+Terraform will display an error like the one below if it does not receive values for resource attributes while generating configuration.
+
+```shell
+$ terraform plan -generate-config-out=generated.tf
+╷
+│ Error: Conflicting configuration arguments
+│ 
+│   with aws_instance.ubuntu,
+│   on g.tf line 20, in resource "aws_instance" "ubuntu":
+│   20:   ipv6_address_count                   = 0
+│ 
+│ "ipv6_address_count": conflicts with ipv6_addresses
+╵
+```
+
+In the example above, Terraform still generates configuration and writes it to `generated.tf`. This error stems from a conflict between the `ipv6_address_count` and `ipv6_addresses` arguments. The resource supports both of these arguments, but you must choose only one when configuring the resource. You could fix the error by removing one of these two arguments, then running `terraform plan` again to check that there are no further issues.
diff --git a/v1.5.7/website/docs/language/import/index.mdx b/v1.5.7/website/docs/language/import/index.mdx
new file mode 100644
index 0000000..089b281
--- /dev/null
+++ b/v1.5.7/website/docs/language/import/index.mdx
@@ -0,0 +1,136 @@
+---
+page_title: Import - Configuration Language
+description: >-
+  Import and manage existing resources with Terraform using configuration-driven import.
+---
+
+# Import
+
+-> **Note:** Import blocks are only available in Terraform v1.5.0 and later.
+
+~> **Experimental:** While we do not expect to make backwards-incompatible changes to syntax, the `-generate-config-out` flag and how Terraform processes imports during the plan stage and generates configuration may change in future releases.
+
+Use the `import` block to import existing infrastructure resources into Terraform, bringing them under Terraform's management. Unlike the `terraform import` command, configuration-driven import using `import` blocks is predictable, works with CICD pipelines, and lets you preview an import operation before modifying state.
+
+Once imported, Terraform tracks the resource in your state file. You can then manage the imported resource like any other, updating its attributes and destroying it as part of a standard resource lifecycle.
+
+The `import` block records that Terraform imported the resource and did not create it. After importing, you can optionally remove import blocks from your configuration or leave them as a record of the resource's origin.
+
+## Syntax
+
+You can add an `import` block to any Terraform configuration file. A common pattern is to create an `imports.tf` file, or to place each `import` block beside the `resource` block it imports into.
+
+```hcl
+import {
+  to = aws_instance.example
+  id = "i-abcd1234"
+}
+
+resource "aws_instance" "example" {
+  name = "hashi"
+  # (other resource arguments...)
+}
+```
+
+The above `import` block defines an import of the AWS instance with the ID "i-abcd1234" into the `aws_instance.example` resource in the root module.
+
+The `import` block has the following arguments:
+ - `to` - The instance address this resource will have in your state file.
+ - `id` - A string with the [import ID](#import-id) of the resource.
+ - `provider` (optional) - An optional custom resource provider, see [The Resource provider Meta-Argument](/terraform/language/meta-arguments/resource-provider) for details.
+
+If you do not set the `provider` argument, Terraform attempts to import from the default provider. 
+
+### Import ID
+
+The import block requires you to provide the `id` argument with a literal string of your resource's import ID. Terraform needs this import ID to locate the resource you want to import.
+
+The identifier you use for a resource's import ID is resource-specific. You can find the required ID in the [provider documentation](https://registry.terraform.io/browse/providers) for the resource you wish to import.
+
+## Plan and apply an import
+
+Terraform processes the `import` block during the plan stage. Once a plan is approved, Terraform imports the resource into its state during the subsequent apply stage.
+
+To import a resource using `import` blocks, you must:
+1. Define an `import` block for the resource(s).
+1. Add a corresponding `resource` block to your configuration , or [generate configuration](/terraform/language/import/generating-configuration) for that resource.
+1. Run `terraform plan` to review how Terraform will import the resource(s).
+1. Apply the configuration to import the resources and update your Terraform state.
+
+> **Hands-on:** Try the [State Import](/terraform/tutorials/state/state-import?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+The `import` block is [_idempotent_](https://en.wikipedia.org/wiki/Idempotence), meaning that applying an import action and running another plan will not generate another import action as long as that resource remains in your state.
+
+Terraform only needs to import a given resource once. Attempting to import a resource into the same address again is a harmless no-op. You can remove `import` blocks after completing the import or safely leave them in your configuration as a record of the resource's origin for future module maintainers. For more information on maintaining configurations over time, see [Refactoring](/terraform/language/modules/develop/refactoring).
+
+## Resource configuration
+
+Before importing, you must add configuration for every resource you want Terraform to import. Otherwise, Terraform throws an error during planning, insisting you add resource configuration before it can successfully import. You can create resource configuration manually or [generate it using Terraform](/terraform/language/import/generating-configuration). 
+
+We recommend writing a `resource` block if you know what most of the [resource's arguments](/terraform/language/resources/syntax#resource-arguments) will be. For example, your configuration may already contain a similar resource whose configuration you can copy and modify.
+
+We recommend [generating configuration](/terraform/language/import/generating-configuration) when importing multiple resources or a single complex resource that you do not already have the configuration for.
+
+### Add a `resource` block
+
+Add a `resource` block for the resource to import. The resource address must match the import block's `to` argument. 
+
+```hcl
+import {
+  to = aws_instance.example
+  id = "i-abcd1234"
+}
+
+resource "aws_instance" "example" {
+  name = "renderer"
+}
+```
+
+### Generate configuration
+
+Terraform can generate HCL for resources that do not already exist in configuration. 
+For more details, see [Generating Configuration](/terraform/language/import/generating-configuration).
+
+## Examples
+
+The following example demonstrates how to import into a module.
+
+```hcl
+import {
+  to = module.instances.aws_instance.example
+  id = "i-abcd1234"
+}
+```
+
+The below example shows how to import a resource that includes [`count`](/terraform/language/meta-arguments/count).
+
+```hcl
+import {
+  to = aws_instance.example[0]
+  id = "i-abcd1234"
+}
+```
+
+
+The below example shows how to import a resource that includes [`for_each`](/terraform/language/meta-arguments/for_each).
+```hcl
+import {
+  to = aws_instance.example["foo"]
+  id = "i-abcd1234"
+}
+```
+
+Finally, the below example demonstrates how to import from a custom resource provider.
+
+```hcl
+provider "aws" {
+  alias = "europe"
+  region = "eu-west-1"
+}
+
+import {
+  provider = aws.europe
+  to = aws_instance.example["foo"]
+  id = "i-abcd1234"
+}
+```
diff --git a/v1.5.7/website/docs/language/index.mdx b/v1.5.7/website/docs/language/index.mdx
new file mode 100644
index 0000000..c035ac7
--- /dev/null
+++ b/v1.5.7/website/docs/language/index.mdx
@@ -0,0 +1,119 @@
+---
+page_title: Overview - Configuration Language
+description: >-
+  Use the Terraform configuration language to describe the infrastructure that Terraform manages.
+---
+
+# Terraform Language Documentation
+
+This is the documentation for Terraform's configuration language. It is relevant
+to users of [Terraform CLI](/terraform/cli),
+[Terraform Cloud](https://cloud.hashicorp.com/products/terraform), and
+[Terraform Enterprise](/terraform/enterprise). Terraform's language is
+its primary user interface. Configuration files you write in Terraform
+language tell Terraform what plugins to install, what infrastructure to create,
+and what data to fetch. Terraform language also lets you define dependencies
+between resources and create multiple similar resources from a single
+configuration block.
+
+> **Hands-on:** Try the [Write Terraform Configuration](/terraform/tutorials/configuration-language) tutorials.
+
+## About the Terraform Language
+
+The main purpose of the Terraform language is declaring
+[resources](/terraform/language/resources), which represent infrastructure objects. All other
+language features exist only to make the definition of resources more flexible
+and convenient.
+
+A _Terraform configuration_ is a complete document in the Terraform language
+that tells Terraform how to manage a given collection of infrastructure. A
+configuration can consist of multiple files and directories.
+
+The syntax of the Terraform language consists of only a few basic elements:
+
+```hcl
+resource "aws_vpc" "main" {
+  cidr_block = var.base_cidr_block
+}
+
+<BLOCK TYPE> "<BLOCK LABEL>" "<BLOCK LABEL>" {
+  # Block body
+  <IDENTIFIER> = <EXPRESSION> # Argument
+}
+```
+
+- _Blocks_ are containers for other content and usually represent the
+  configuration of some kind of object, like a resource. Blocks have a
+  _block type,_ can have zero or more _labels,_ and have a _body_ that contains
+  any number of arguments and nested blocks. Most of Terraform's features are
+  controlled by top-level blocks in a configuration file.
+- _Arguments_ assign a value to a name. They appear within blocks.
+- _Expressions_ represent a value, either literally or by referencing and
+  combining other values. They appear as values for arguments, or within other
+  expressions.
+
+The Terraform language is declarative, describing an intended goal rather than
+the steps to reach that goal. The ordering of blocks and the files they are
+organized into are generally not significant; Terraform only considers implicit
+and explicit relationships between resources when determining an order of
+operations.
+
+### Example
+
+The following example describes a simple network topology for Amazon Web
+Services, just to give a sense of the overall structure and syntax of the
+Terraform language. Similar configurations can be created for other virtual
+network services, using resource types defined by other providers, and a
+practical network configuration will often contain additional elements not
+shown here.
+
+```hcl
+terraform {
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = "~> 1.0.4"
+    }
+  }
+}
+
+variable "aws_region" {}
+
+variable "base_cidr_block" {
+  description = "A /16 CIDR range definition, such as 10.1.0.0/16, that the VPC will use"
+  default = "10.1.0.0/16"
+}
+
+variable "availability_zones" {
+  description = "A list of availability zones in which to create subnets"
+  type = list(string)
+}
+
+provider "aws" {
+  region = var.aws_region
+}
+
+resource "aws_vpc" "main" {
+  # Referencing the base_cidr_block variable allows the network address
+  # to be changed without modifying the configuration.
+  cidr_block = var.base_cidr_block
+}
+
+resource "aws_subnet" "az" {
+  # Create one subnet for each given availability zone.
+  count = length(var.availability_zones)
+
+  # For each subnet, use one of the specified availability zones.
+  availability_zone = var.availability_zones[count.index]
+
+  # By referencing the aws_vpc.main object, Terraform knows that the subnet
+  # must be created only after the VPC is created.
+  vpc_id = aws_vpc.main.id
+
+  # Built-in functions and operators can be used for simple transformations of
+  # values, such as computing a subnet address. Here we create a /20 prefix for
+  # each subnet, using consecutive addresses for each availability zone,
+  # such as 10.1.16.0/20 .
+  cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 4, count.index+1)
+}
+```
diff --git a/v1.5.7/website/docs/language/meta-arguments/count.mdx b/v1.5.7/website/docs/language/meta-arguments/count.mdx
new file mode 100644
index 0000000..f08b3f7
--- /dev/null
+++ b/v1.5.7/website/docs/language/meta-arguments/count.mdx
@@ -0,0 +1,124 @@
+---
+page_title: The count Meta-Argument - Configuration Language
+description: >-
+  Count helps you efficiently manage nearly identical infrastructure resources
+  without writing a separate block for each one.
+---
+
+# The `count` Meta-Argument
+
+-> **Version note:** Module support for `count` was added in Terraform 0.13, and
+previous versions can only use it with resources.
+
+-> **Note:** A given resource or module block cannot use both `count` and `for_each`.
+
+> **Hands-on:** Try the [Manage Similar Resources With Count](/terraform/tutorials/0-13/count?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+By default, a [resource block](/terraform/language/resources/syntax) configures one real
+infrastructure object. (Similarly, a
+[module block](/terraform/language/modules/syntax) includes a
+child module's contents into the configuration one time.)
+However, sometimes you want to manage several similar objects (like a fixed
+pool of compute instances) without writing a separate block for each one.
+Terraform has two ways to do this:
+`count` and [`for_each`](/terraform/language/meta-arguments/for_each).
+
+If a resource or module block includes a `count` argument whose value is a whole number,
+Terraform will create that many instances.
+
+## Basic Syntax
+
+`count` is a meta-argument defined by the Terraform language. It can be used
+with modules and with every resource type.
+
+The `count` meta-argument accepts a whole number, and creates that many
+instances of the resource or module. Each instance has a distinct infrastructure object
+associated with it, and each is separately created,
+updated, or destroyed when the configuration is applied.
+
+```hcl
+resource "aws_instance" "server" {
+  count = 4 # create four similar EC2 instances
+
+  ami           = "ami-a1b2c3d4"
+  instance_type = "t2.micro"
+
+  tags = {
+    Name = "Server ${count.index}"
+  }
+}
+```
+
+## The `count` Object
+
+In blocks where `count` is set, an additional `count` object is
+available in expressions, so you can modify the configuration of each instance.
+This object has one attribute:
+
+- `count.index` — The distinct index number (starting with `0`) corresponding
+  to this instance.
+
+## Using Expressions in `count`
+
+The `count` meta-argument accepts numeric [expressions](/terraform/language/expressions).
+However, unlike most arguments, the `count` value must be known
+_before_ Terraform performs any remote resource actions. This means `count`
+can't refer to any resource attributes that aren't known until after a
+configuration is applied (such as a unique ID generated by the remote API when
+an object is created).
+
+## Referring to Instances
+
+When `count` is set, Terraform distinguishes between the block itself
+and the multiple _resource or module instances_ associated with it. Instances are
+identified by an index number, starting with `0`.
+
+- `<TYPE>.<NAME>` or `module.<NAME>` (for example, `aws_instance.server`) refers to the resource block.
+- `<TYPE>.<NAME>[<INDEX>]` or `module.<NAME>[<INDEX>]` (for example, `aws_instance.server[0]`,
+  `aws_instance.server[1]`, etc.) refers to individual instances.
+
+This is different from resources and modules without `count` or `for_each`, which can be
+referenced without an index or key.
+
+Similarly, resources from child modules with multiple instances are prefixed
+with `module.<NAME>[<KEY>]` when displayed in plan output and elsewhere in the UI.
+For a module without `count` or `for_each`, the address will not contain
+the module index as the module's name suffices to reference the module.
+
+-> **Note:** Within nested `provisioner` or `connection` blocks, the special
+`self` object refers to the current _resource instance,_ not the resource block
+as a whole.
+
+## When to Use `for_each` Instead of `count`
+
+If your instances are almost identical, `count` is appropriate. If some
+of their arguments need distinct values that can't be directly derived from an
+integer, it's safer to use `for_each`.
+
+Before `for_each` was available, it was common to derive `count` from the
+length of a list and use `count.index` to look up the original list value:
+
+```hcl
+variable "subnet_ids" {
+  type = list(string)
+}
+
+resource "aws_instance" "server" {
+  # Create one instance for each subnet
+  count = length(var.subnet_ids)
+
+  ami           = "ami-a1b2c3d4"
+  instance_type = "t2.micro"
+  subnet_id     = var.subnet_ids[count.index]
+
+  tags = {
+    Name = "Server ${count.index}"
+  }
+}
+```
+
+This was fragile, because the resource instances were still identified by their
+_index_ instead of the string values in the list. If an element was removed from
+the middle of the list, every instance _after_ that element would see its
+`subnet_id` value change, resulting in more remote object changes than intended.
+Using `for_each` gives the same flexibility without the extra churn.
diff --git a/v1.5.7/website/docs/language/meta-arguments/depends_on.mdx b/v1.5.7/website/docs/language/meta-arguments/depends_on.mdx
new file mode 100644
index 0000000..5f12751
--- /dev/null
+++ b/v1.5.7/website/docs/language/meta-arguments/depends_on.mdx
@@ -0,0 +1,73 @@
+---
+page_title: The depends_on Meta-Argument - Configuration Language
+description: >-
+  The depends_on meta-argument allows you to handle hidden resource or module
+  dependencies.
+---
+
+# The `depends_on` Meta-Argument
+
+Use the `depends_on` meta-argument to handle hidden resource or module dependencies that Terraform cannot automatically infer. You only need to explicitly specify a dependency when a resource or module relies on another resource's behavior but does not access any of that resource's data in its arguments.
+
+-> **Note:** Module support for `depends_on` was added in Terraform version 0.13, and prior versions can only use it with resources.
+
+
+## Processing and Planning Consequences
+
+The `depends_on` meta-argument instructs Terraform to complete all actions on the dependency object (including Read actions) before performing actions on the object declaring the dependency. When the dependency object is an entire module, `depends_on` affects the order in which Terraform processes all of the resources and data sources associated with that module. Refer to [Resource Dependencies](/terraform/language/resources/behavior#resource-dependencies) and [Data Resource Dependencies](/terraform/language/data-sources#data-resource-dependencies) for more details.
+
+You should use `depends_on` as a last resort because it can cause Terraform to create more conservative plans that replace more resources than necessary. For example, Terraform may treat more values as unknown “(known after apply)” because it is uncertain what changes will occur on the upstream object. This is especially likely when you use `depends_on` for modules.
+
+Instead of `depends_on`, we recommend using [expression references](/terraform/language/expressions/references) to imply dependencies when possible. Expression references let Terraform understand which value the reference derives from and avoid planning changes if that particular value hasn’t changed, even if other parts of the upstream object have planned changes.
+
+## Usage
+
+You can use the `depends_on` meta-argument in `module` blocks and in all `resource` blocks, regardless of resource type. It requires a list of references to other resources or child modules in the same calling module. This list cannot include arbitrary expressions because the `depends_on` value must be known before Terraform knows resource relationships and thus before it can safely evaluate expressions.
+
+We recommend always including a comment that explains why using `depends_on` is necessary. The following example uses `depends_on` to handle a "hidden" dependency on the `aws_iam_instance_profile.example`.
+
+```hcl
+resource "aws_iam_role" "example" {
+  name = "example"
+
+  # assume_role_policy is omitted for brevity in this example. Refer to the
+  # documentation for aws_iam_role for a complete example.
+  assume_role_policy = "..."
+}
+
+resource "aws_iam_instance_profile" "example" {
+  # Because this expression refers to the role, Terraform can infer
+  # automatically that the role must be created first.
+  role = aws_iam_role.example.name
+}
+
+resource "aws_iam_role_policy" "example" {
+  name   = "example"
+  role   = aws_iam_role.example.name
+  policy = jsonencode({
+    "Statement" = [{
+      # This policy allows software running on the EC2 instance to
+      # access the S3 API.
+      "Action" = "s3:*",
+      "Effect" = "Allow",
+    }],
+  })
+}
+
+resource "aws_instance" "example" {
+  ami           = "ami-a1b2c3d4"
+  instance_type = "t2.micro"
+
+  # Terraform can infer from this that the instance profile must
+  # be created before the EC2 instance.
+  iam_instance_profile = aws_iam_instance_profile.example
+
+  # However, if software running in this EC2 instance needs access
+  # to the S3 API in order to boot properly, there is also a "hidden"
+  # dependency on the aws_iam_role_policy that Terraform cannot
+  # automatically infer, so it must be declared explicitly:
+  depends_on = [
+    aws_iam_role_policy.example
+  ]
+}
+```
diff --git a/v1.5.7/website/docs/language/meta-arguments/for_each.mdx b/v1.5.7/website/docs/language/meta-arguments/for_each.mdx
new file mode 100644
index 0000000..423167c
--- /dev/null
+++ b/v1.5.7/website/docs/language/meta-arguments/for_each.mdx
@@ -0,0 +1,273 @@
+---
+page_title: The for_each Meta-Argument - Configuration Language
+description: >-
+  The for_each meta-argument allows you to manage similar infrastructure
+  resources without writing a separate block for each one.
+---
+
+# The `for_each` Meta-Argument
+
+By default, a [resource block](/terraform/language/resources/syntax) configures one real
+infrastructure object (and similarly, a
+[module block](/terraform/language/modules/syntax) includes a
+child module's contents into the configuration one time).
+However, sometimes you want to manage several similar objects (like a fixed
+pool of compute instances) without writing a separate block for each one.
+Terraform has two ways to do this:
+[`count`](/terraform/language/meta-arguments/count) and `for_each`.
+
+> **Hands-on:** Try the [Manage Similar Resources With For Each](/terraform/tutorials/configuration-language/for-each) tutorial.
+
+If a resource or module block includes a `for_each` argument whose value is a map or
+a set of strings, Terraform creates one instance for each member of
+that map or set.
+
+-> **Version note:** `for_each` was added in Terraform 0.12.6. Module support
+for `for_each` was added in Terraform 0.13; previous versions can only use
+it with resources.
+
+-> **Note:** A given resource or module block cannot use both `count` and `for_each`.
+
+## Basic Syntax
+
+`for_each` is a meta-argument defined by the Terraform language. It can be used
+with modules and with every resource type.
+
+The `for_each` meta-argument accepts a map or a set of strings, and creates an
+instance for each item in that map or set. Each instance has a distinct
+infrastructure object associated with it, and each is separately created,
+updated, or destroyed when the configuration is applied.
+
+Map:
+
+```hcl
+resource "azurerm_resource_group" "rg" {
+  for_each = {
+    a_group = "eastus"
+    another_group = "westus2"
+  }
+  name     = each.key
+  location = each.value
+}
+```
+
+Set of strings:
+
+```hcl
+resource "aws_iam_user" "the-accounts" {
+  for_each = toset( ["Todd", "James", "Alice", "Dottie"] )
+  name     = each.key
+}
+```
+
+Child module:
+
+```hcl
+# my_buckets.tf
+module "bucket" {
+  for_each = toset(["assets", "media"])
+  source   = "./publish_bucket"
+  name     = "${each.key}_bucket"
+}
+```
+
+```hcl
+# publish_bucket/bucket-and-cloudfront.tf
+variable "name" {} # this is the input parameter of the module
+
+resource "aws_s3_bucket" "example" {
+  # Because var.name includes each.key in the calling
+  # module block, its value will be different for
+  # each instance of this module.
+  bucket = var.name
+
+  # ...
+}
+
+resource "aws_iam_user" "deploy_user" {
+  # ...
+}
+```
+
+## The `each` Object
+
+In blocks where `for_each` is set, an additional `each` object is
+available in expressions, so you can modify the configuration of each instance.
+This object has two attributes:
+
+- `each.key` — The map key (or set member) corresponding to this instance.
+- `each.value` — The map value corresponding to this instance. (If a set was
+  provided, this is the same as `each.key`.)
+
+## Limitations on values used in `for_each`
+
+The keys of the map (or all the values in the case of a set of strings) must
+be _known values_, or you will get an error message that `for_each` has dependencies
+that cannot be determined before apply, and a `-target` may be needed.
+
+`for_each` keys cannot be the result (or rely on the result of) of impure functions,
+including `uuid`, `bcrypt`, or `timestamp`, as their evaluation is deferred during the
+main evaluation step.
+
+Sensitive values, such as [sensitive input variables](/terraform/language/values/variables#suppressing-values-in-cli-output),
+[sensitive outputs](/terraform/language/values/outputs#sensitive-suppressing-values-in-cli-output),
+or [sensitive resource attributes](/terraform/language/expressions/references#sensitive-resource-attributes),
+cannot be used as arguments to `for_each`. The value used in `for_each` is used
+to identify the resource instance and will always be disclosed in UI output,
+which is why sensitive values are not allowed.
+Attempts to use sensitive values as `for_each` arguments will result in an error.
+
+If you transform a value containing sensitive data into an argument to be used in `for_each`, be aware that
+[most functions in Terraform will return a sensitive result if given an argument with any sensitive content](/terraform/language/expressions/function-calls#using-sensitive-data-as-function-arguments).
+In many cases, you can achieve similar results to a function used for this purpose by
+using a `for` expression. For example, if you would like to call `keys(local.map)`, where
+`local.map` is an object with sensitive values (but non-sensitive keys), you can create a
+value to pass to  `for_each` with `toset([for k,v in local.map : k])`.
+
+## Using Expressions in `for_each`
+
+The `for_each` meta-argument accepts map or set [expressions](/terraform/language/expressions).
+However, unlike most arguments, the `for_each` value must be known
+_before_ Terraform performs any remote resource actions. This means `for_each`
+can't refer to any resource attributes that aren't known until after a
+configuration is applied (such as a unique ID generated by the remote API when
+an object is created).
+
+The `for_each` value must be a map or set with one element per desired resource
+instance. To use a sequence as the `for_each` value, you must use an expression
+that explicitly returns a set value, like the [toset](/terraform/language/functions/toset)
+function. To prevent unwanted surprises during conversion, the `for_each` argument
+does not implicitly convert lists or tuples to sets.
+If you need to declare resource instances based on a nested
+data structure or combinations of elements from multiple data structures you
+can use Terraform expressions and functions to derive a suitable value.
+For example:
+
+- Transform a multi-level nested structure into a flat list by
+  [using nested `for` expressions with the `flatten` function](/terraform/language/functions/flatten#flattening-nested-structures-for-for_each).
+- Produce an exhaustive list of combinations of elements from two or more
+  collections by
+  [using the `setproduct` function inside a `for` expression](/terraform/language/functions/setproduct#finding-combinations-for-for_each).
+
+### Chaining `for_each` Between Resources
+
+Because a resource using `for_each` appears as a map of objects when used in
+expressions elsewhere, you can directly use one resource as the `for_each`
+of another in situations where there is a one-to-one relationship between
+two sets of objects.
+
+For example, in AWS an `aws_vpc` object is commonly associated with a number
+of other objects that provide additional services to that VPC, such as an
+"internet gateway". If you are declaring multiple VPC instances using `for_each`
+then you can chain that `for_each` into another resource to declare an
+internet gateway for each VPC:
+
+```hcl
+variable "vpcs" {
+  type = map(object({
+    cidr_block = string
+  }))
+}
+
+resource "aws_vpc" "example" {
+  # One VPC for each element of var.vpcs
+  for_each = var.vpcs
+
+  # each.value here is a value from var.vpcs
+  cidr_block = each.value.cidr_block
+}
+
+resource "aws_internet_gateway" "example" {
+  # One Internet Gateway per VPC
+  for_each = aws_vpc.example
+
+  # each.value here is a full aws_vpc object
+  vpc_id = each.value.id
+}
+
+output "vpc_ids" {
+  value = {
+    for k, v in aws_vpc.example : k => v.id
+  }
+
+  # The VPCs aren't fully functional until their
+  # internet gateways are running.
+  depends_on = [aws_internet_gateway.example]
+}
+```
+
+This chaining pattern explicitly and concisely declares the relationship
+between the internet gateway instances and the VPC instances, which tells
+Terraform to expect the instance keys for both to always change together,
+and typically also makes the configuration easier to understand for human
+maintainers.
+
+## Referring to Instances
+
+When `for_each` is set, Terraform distinguishes between the block itself
+and the multiple _resource or module instances_ associated with it. Instances are
+identified by a map key (or set member) from the value provided to `for_each`.
+
+- `<TYPE>.<NAME>` or `module.<NAME>` (for example, `azurerm_resource_group.rg`) refers to the block.
+- `<TYPE>.<NAME>[<KEY>]` or `module.<NAME>[<KEY>]` (for example, `azurerm_resource_group.rg["a_group"]`,
+  `azurerm_resource_group.rg["another_group"]`, etc.) refers to individual instances.
+
+This is different from resources and modules without `count` or `for_each`, which can be
+referenced without an index or key.
+
+Similarly, resources from child modules with multiple instances are prefixed
+with `module.<NAME>[<KEY>]` when displayed in plan output and elsewhere in the UI.
+For a module without `count` or `for_each`, the address will not contain
+the module index as the module's name suffices to reference the module.
+
+-> **Note:** Within nested `provisioner` or `connection` blocks, the special
+`self` object refers to the current _resource instance,_ not the resource block
+as a whole.
+
+## Using Sets
+
+The Terraform language doesn't have a literal syntax for
+[set values](/terraform/language/expressions/type-constraints#collection-types), but you can use the `toset`
+function to explicitly convert a list of strings to a set:
+
+```hcl
+locals {
+  subnet_ids = toset([
+    "subnet-abcdef",
+    "subnet-012345",
+  ])
+}
+
+resource "aws_instance" "server" {
+  for_each = local.subnet_ids
+
+  ami           = "ami-a1b2c3d4"
+  instance_type = "t2.micro"
+  subnet_id     = each.key # note: each.key and each.value are the same for a set
+
+  tags = {
+    Name = "Server ${each.key}"
+  }
+}
+```
+
+Conversion from list to set discards the ordering of the items in the list and
+removes any duplicate elements. `toset(["b", "a", "b"])` will produce a set
+containing only `"a"` and `"b"` in no particular order; the second `"b"` is
+discarded.
+
+If you are writing a module with an [input variable](/terraform/language/values/variables) that
+will be used as a set of strings for `for_each`, you can set its type to
+`set(string)` to avoid the need for an explicit type conversion:
+
+```hcl
+variable "subnet_ids" {
+  type = set(string)
+}
+
+resource "aws_instance" "server" {
+  for_each = var.subnet_ids
+
+  # (and the other arguments as above)
+}
+```
diff --git a/v1.5.7/website/docs/language/meta-arguments/lifecycle.mdx b/v1.5.7/website/docs/language/meta-arguments/lifecycle.mdx
new file mode 100644
index 0000000..0c18043
--- /dev/null
+++ b/v1.5.7/website/docs/language/meta-arguments/lifecycle.mdx
@@ -0,0 +1,184 @@
+---
+page_title: The lifecycle Meta-Argument - Configuration Language
+description: >-
+  The meta-arguments in a lifecycle block allow you to customize resource
+  behavior.
+---
+
+# The `lifecycle` Meta-Argument
+
+> **Hands-on:** Try the [Lifecycle Management](/terraform/tutorials/state/resource-lifecycle?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+The [Resource Behavior](/terraform/language/resources/behavior) page describes the general lifecycle for resources. Some details of
+that behavior can be customized using the special nested `lifecycle` block
+within a resource block body:
+
+```hcl
+resource "azurerm_resource_group" "example" {
+  # ...
+
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+```
+
+## Syntax and Arguments
+
+`lifecycle` is a nested block that can appear within a resource block.
+The `lifecycle` block and its contents are meta-arguments, available
+for all `resource` blocks regardless of type.
+
+The arguments available within a `lifecycle` block are `create_before_destroy`,
+`prevent_destroy`, `ignore_changes`, and `replace_triggered_by`.
+
+* `create_before_destroy` (bool) - By default, when Terraform must change
+  a resource argument that cannot be updated in-place due to
+  remote API limitations, Terraform will instead destroy the existing object
+  and then create a new replacement object with the new configured arguments.
+
+  The `create_before_destroy` meta-argument changes this behavior so that
+  the new replacement object is created _first,_ and the prior object
+  is destroyed after the replacement is created.
+
+  This is an opt-in behavior because many remote object types have unique
+  name requirements or other constraints that must be accommodated for
+  both a new and an old object to exist concurrently. Some resource types
+  offer special options to append a random suffix onto each object name to
+  avoid collisions, for example. Terraform CLI cannot automatically activate
+  such features, so you must understand the constraints for each resource
+  type before using `create_before_destroy` with it.
+
+  Note that Terraform propagates and applies `create_before_destroy` meta-attribute
+  behaviour to all resource dependencies. For example, if resource A with enabled
+  `create_before_destroy` depends on resource B with disabled `create_before_destroy`
+  (by default), then Terraform enables `create_before_destroy` for resource B
+  implicitly and stores it to the state file. You cannot override `create_before_destroy`
+  to `false` on resource B, because that would imply dependency cycles in the graph.
+
+  Destroy provisioners of this resource do not run if `create_before_destroy`
+  is set to `true`. This [GitHub issue](https://github.com/hashicorp/terraform/issues/13549) contains more details.
+
+* `prevent_destroy` (bool) - This meta-argument, when set to `true`, will
+  cause Terraform to reject with an error any plan that would destroy the
+  infrastructure object associated with the resource, as long as the argument
+  remains present in the configuration.
+
+  This can be used as a measure of safety against the accidental replacement
+  of objects that may be costly to reproduce, such as database instances.
+  However, it will make certain configuration changes impossible to apply,
+  and will prevent the use of the `terraform destroy` command once such
+  objects are created, and so this option should be used sparingly.
+
+  Since this argument must be present in configuration for the protection to
+  apply, note that this setting does not prevent the remote object from
+  being destroyed if the `resource` block were removed from configuration
+  entirely: in that case, the `prevent_destroy` setting is removed along
+  with it, and so Terraform will allow the destroy operation to succeed.
+
+* `ignore_changes` (list of attribute names) - By default, Terraform detects
+  any difference in the current settings of a real infrastructure object
+  and plans to update the remote object to match configuration.
+
+  The `ignore_changes` feature is intended to be used when a resource is
+  created with references to data that may change in the future, but should
+  not affect said resource after its creation. In some rare cases, settings
+  of a remote object are modified by processes outside of Terraform, which
+  Terraform would then attempt to "fix" on the next run. In order to make
+  Terraform share management responsibilities of a single object with a
+  separate process, the `ignore_changes` meta-argument specifies resource
+  attributes that Terraform should ignore when planning updates to the
+  associated remote object.
+
+  The arguments corresponding to the given attribute names are considered
+  when planning a _create_ operation, but are ignored when planning an
+  _update_. The arguments are the relative address of the attributes in the
+  resource. Map and list elements can be referenced using index notation,
+  like `tags["Name"]` and `list[0]` respectively.
+
+  ```hcl
+  resource "aws_instance" "example" {
+    # ...
+
+    lifecycle {
+      ignore_changes = [
+        # Ignore changes to tags, e.g. because a management agent
+        # updates these based on some ruleset managed elsewhere.
+        tags,
+      ]
+    }
+  }
+  ```
+
+  Instead of a list, the special keyword `all` may be used to instruct
+  Terraform to ignore _all_ attributes, which means that Terraform can
+  create and destroy the remote object but will never propose updates to it.
+
+  Only attributes defined by the resource type can be ignored.
+  `ignore_changes` cannot be applied to itself or to any other meta-arguments.
+
+* `replace_triggered_by` (list of resource or attribute references) -
+  _Added in Terraform 1.2._ Replaces the resource when any of the referenced
+  items change. Supply a list of expressions referencing managed resources,
+  instances, or instance attributes. When used in a resource that uses `count`
+  or `for_each`, you can use `count.index` or `each.key` in the expression to
+  reference specific instances of other resources that are configured with the
+  same count or collection.
+
+  References trigger replacement in the following conditions:
+
+  - If the reference is to a resource with multiple instances, a plan to
+    update or replace any instance will trigger replacement.
+  - If the reference is to a single resource instance, a plan to update or
+    replace that instance will trigger replacement.
+  - If the reference is to a single attribute of a resource instance, any
+    change to the attribute value will trigger replacement.
+
+  You can only reference managed resources in `replace_triggered_by`
+  expressions. This lets you modify these expressions without forcing
+  replacement.
+
+  ```hcl
+  resource "aws_appautoscaling_target" "ecs_target" {
+    # ...
+    lifecycle {
+      replace_triggered_by = [
+        # Replace `aws_appautoscaling_target` each time this instance of
+        # the `aws_ecs_service` is replaced.
+        aws_ecs_service.svc.id
+      ]
+    }
+  }
+  ```
+
+  `replace_triggered_by` allows only resource addresses because the decision is based on the planned actions for all of the given resources. Plain values such as local values or input variables do not have planned actions of their own, but you can treat them with a resource-like lifecycle by using them with [the `terraform_data` resource type](/terraform/language/resources/terraform-data).
+
+## Custom Condition Checks
+
+You can add `precondition` and `postcondition` blocks with a `lifecycle` block to specify assumptions and guarantees about how resources and data sources operate. The following examples creates a precondition that checks whether the AMI is properly configured.
+
+```hcl
+resource "aws_instance" "example" {
+  instance_type = "t2.micro"
+  ami           = "ami-abc123"
+
+  lifecycle {
+    # The AMI ID must refer to an AMI that contains an operating system
+    # for the `x86_64` architecture.
+    precondition {
+      condition     = data.aws_ami.example.architecture == "x86_64"
+      error_message = "The selected AMI must be for the x86_64 architecture."
+    }
+  }
+}
+```
+
+Custom conditions can help capture assumptions, helping future maintainers understand the configuration design and intent. They also return useful information about errors earlier and in context, helping consumers more easily diagnose issues in their configurations.
+
+Refer to [Custom Conditions](/terraform/language/expressions/custom-conditions#preconditions-and-postconditions) for more details.
+
+## Literal Values Only
+
+The `lifecycle` settings all affect how Terraform constructs and traverses
+the dependency graph. As a result, only literal values can be used because
+the processing happens too early for arbitrary expression evaluation.
diff --git a/v1.5.7/website/docs/language/meta-arguments/module-providers.mdx b/v1.5.7/website/docs/language/meta-arguments/module-providers.mdx
new file mode 100644
index 0000000..3b7339c
--- /dev/null
+++ b/v1.5.7/website/docs/language/meta-arguments/module-providers.mdx
@@ -0,0 +1,126 @@
+---
+page_title: The Module providers Meta-Argument - Configuration Language
+description: >-
+  The providers meta-argument specifies which provider configurations from a
+  parent module are available in a child module.
+---
+
+# The Module `providers` Meta-Argument
+
+In a [module call](/terraform/language/modules/syntax) block, the
+optional `providers` meta-argument specifies which
+[provider configurations](/terraform/language/providers/configuration) from the parent
+module will be available inside the child module.
+
+```hcl
+# The default "aws" configuration is used for AWS resources in the root
+# module where no explicit provider instance is selected.
+provider "aws" {
+  region = "us-west-1"
+}
+
+# An alternate configuration is also defined for a different
+# region, using the alias "usw2".
+provider "aws" {
+  alias  = "usw2"
+  region = "us-west-2"
+}
+
+# An example child module is instantiated with the alternate configuration,
+# so any AWS resources it defines will use the us-west-2 region.
+module "example" {
+  source    = "./example"
+  providers = {
+    aws = aws.usw2
+  }
+}
+```
+
+## Default Behavior: Inherit Default Providers
+
+If the child module does not declare any [configuration aliases](/terraform/language/modules/develop/providers#provider-aliases-within-modules),
+the `providers` argument is optional. If you omit it, a child module inherits
+all of the _default_ provider configurations from its parent module. (Default
+provider configurations are ones that don't use the `alias` argument.)
+
+If you specify a `providers` argument, it cancels this default behavior, and the
+child module will _only_ have access to the provider configurations you specify.
+
+## Usage and Behavior
+
+The value of `providers` is a map, where:
+
+- The keys are the provider configuration names used inside the child module.
+- The values are provider configuration names from the parent module.
+
+Both keys and values should be unquoted references to provider configurations.
+For default configurations, this is the local name of the provider; for
+alternate configurations, this is a `<PROVIDER>.<ALIAS>` reference.
+
+Within a child module, resources are assigned to provider configurations as
+normal — either Terraform chooses a default based on the name of the resource
+type, or the resource specifies an alternate configuration with the `provider`
+argument. If the module receives a `providers` map when it's called, the
+provider configuration names used within the module are effectively remapped to
+refer the specified configurations from the parent module.
+
+## When to Specify Providers
+
+There are two main reasons to use the `providers` argument:
+
+- Using different default provider configurations for a child module.
+- Configuring a module that requires multiple configurations of the same provider.
+
+### Changing Default Provider Configurations
+
+Most re-usable modules only use default provider configurations, which they can
+automatically inherit from their caller when `providers` is omitted.
+
+However, in Terraform configurations that use multiple configurations of the
+same provider, you might want some child modules to use the default provider
+configuration and other ones to use an alternate. (This usually happens when
+using one configuration to manage resources in multiple different regions of the
+same cloud provider.)
+
+By using the `providers` argument (like in the code example above), you can
+accommodate this without needing to edit the child module. Although the code
+within the child module always refers to the default provider configuration, the
+actual configuration of that default can be different for each instance.
+
+### Modules With Alternate Provider Configurations
+
+In rare cases, a single re-usable module might require multiple configurations
+of the same provider. For example, a module that configures connectivity between
+networks in two AWS regions is likely to need both a source and a destination
+region. In that case, the root module may look something like this:
+
+```hcl
+provider "aws" {
+  alias  = "usw1"
+  region = "us-west-1"
+}
+
+provider "aws" {
+  alias  = "usw2"
+  region = "us-west-2"
+}
+
+module "tunnel" {
+  source    = "./tunnel"
+  providers = {
+    aws.src = aws.usw1
+    aws.dst = aws.usw2
+  }
+}
+```
+
+Non-default provider configurations are never automatically inherited, so any
+module that works like this will always need a `providers` argument. The
+documentation for the module should specify all of the provider configuration
+names it needs.
+
+## More Information for Module Developers
+
+For more details and guidance about working with providers inside a re-usable
+child module, see
+[Module Development: Providers Within Modules](/terraform/language/modules/develop/providers).
diff --git a/v1.5.7/website/docs/language/meta-arguments/resource-provider.mdx b/v1.5.7/website/docs/language/meta-arguments/resource-provider.mdx
new file mode 100644
index 0000000..a4b72a0
--- /dev/null
+++ b/v1.5.7/website/docs/language/meta-arguments/resource-provider.mdx
@@ -0,0 +1,59 @@
+---
+page_title: The Resource provider Meta-Argument - Configuration Language
+description: >-
+  The provider meta-argument specifies the provider configuration Terraform
+  should use for a resource, overriding Terraform's default behavior.
+---
+
+# The Resource `provider` Meta-Argument
+
+The `provider` meta-argument specifies which provider configuration to use for a resource,
+overriding Terraform's default behavior of selecting one based on the resource
+type name. Its value should be an unquoted `<PROVIDER>.<ALIAS>` reference.
+
+As described in [Provider Configuration](/terraform/language/providers/configuration), you can optionally
+create multiple configurations for a single provider (usually to manage
+resources in different regions of multi-region services). Each provider can have
+one default configuration, and any number of alternate configurations that
+include an extra name segment (or "alias").
+
+By default, Terraform interprets the initial word in the resource type name
+(separated by underscores) as the local name of a provider, and uses that
+provider's default configuration. For example, the resource type
+`google_compute_instance` is associated automatically with the default
+configuration for the provider named `google`.
+
+By using the `provider` meta-argument, you can select an alternate provider
+configuration for a resource:
+
+```hcl
+# default configuration
+provider "google" {
+  region = "us-central1"
+}
+
+# alternate configuration, whose alias is "europe"
+provider "google" {
+  alias  = "europe"
+  region = "europe-west1"
+}
+
+resource "google_compute_instance" "example" {
+  # This "provider" meta-argument selects the google provider
+  # configuration whose alias is "europe", rather than the
+  # default configuration.
+  provider = google.europe
+
+  # ...
+}
+```
+
+A resource always has an implicit dependency on its associated provider, to
+ensure that the provider is fully configured before any resource actions
+are taken.
+
+The `provider` meta-argument expects
+[a `<PROVIDER>.<ALIAS>` reference](/terraform/language/providers/configuration#referring-to-alternate-provider-configurations),
+which does not need to be quoted. Arbitrary expressions are not permitted for
+`provider` because it must be resolved while Terraform is constructing the
+dependency graph, before it is safe to evaluate expressions.
diff --git a/v1.5.7/website/docs/language/modules/develop/composition.mdx b/v1.5.7/website/docs/language/modules/develop/composition.mdx
new file mode 100644
index 0000000..d50679f
--- /dev/null
+++ b/v1.5.7/website/docs/language/modules/develop/composition.mdx
@@ -0,0 +1,376 @@
+---
+page_title: Module Composition
+description: |-
+  Module composition allows infrastructure to be described from modular
+  building blocks.
+---
+
+# Module Composition
+
+In a simple Terraform configuration with only one root module, we create a
+flat set of resources and use Terraform's expression syntax to describe the
+relationships between these resources:
+
+```hcl
+resource "aws_vpc" "example" {
+  cidr_block = "10.1.0.0/16"
+}
+
+resource "aws_subnet" "example" {
+  vpc_id = aws_vpc.example.id
+
+  availability_zone = "us-west-2b"
+  cidr_block        = cidrsubnet(aws_vpc.example.cidr_block, 4, 1)
+}
+```
+
+When we introduce `module` blocks, our configuration becomes hierarchical
+rather than flat: each module contains its own set of resources, and possibly
+its own child modules, which can potentially create a deep, complex tree of
+resource configurations.
+
+However, in most cases we strongly recommend keeping the module tree flat,
+with only one level of child modules, and use a technique similar to the
+above of using expressions to describe the relationships between the modules:
+
+```hcl
+module "network" {
+  source = "./modules/aws-network"
+
+  base_cidr_block = "10.0.0.0/8"
+}
+
+module "consul_cluster" {
+  source = "./modules/aws-consul-cluster"
+
+  vpc_id     = module.network.vpc_id
+  subnet_ids = module.network.subnet_ids
+}
+```
+
+We call this flat style of module usage _module composition_, because it
+takes multiple [composable](https://en.wikipedia.org/wiki/Composability)
+building-block modules and assembles them together to produce a larger system.
+Instead of a module _embedding_ its dependencies, creating and managing its
+own copy, the module _receives_ its dependencies from the root module, which
+can therefore connect the same modules in different ways to produce different
+results.
+
+The rest of this page discusses some more specific composition patterns that
+may be useful when describing larger systems with Terraform.
+
+## Dependency Inversion
+
+In the example above, we saw a `consul_cluster` module that presumably describes
+a cluster of [HashiCorp Consul](https://www.consul.io/) servers running in
+an AWS VPC network, and thus it requires as arguments the identifiers of both
+the VPC itself and of the subnets within that VPC.
+
+An alternative design would be to have the `consul_cluster` module describe
+its _own_ network resources, but if we did that then it would be hard for
+the Consul cluster to coexist with other infrastructure in the same network,
+and so where possible we prefer to keep modules relatively small and pass in
+their dependencies.
+
+This [dependency inversion](https://en.wikipedia.org/wiki/Dependency_inversion_principle)
+approach also improves flexibility for future
+refactoring, because the `consul_cluster` module doesn't know or care how
+those identifiers are obtained by the calling module. A future refactor may
+separate the network creation into its own configuration, and thus we may
+pass those values into the module from data sources instead:
+
+```hcl
+data "aws_vpc" "main" {
+  tags = {
+    Environment = "production"
+  }
+}
+
+data "aws_subnet_ids" "main" {
+  vpc_id = data.aws_vpc.main.id
+}
+
+module "consul_cluster" {
+  source = "./modules/aws-consul-cluster"
+
+  vpc_id     = data.aws_vpc.main.id
+  subnet_ids = data.aws_subnet_ids.main.ids
+}
+```
+
+### Conditional Creation of Objects
+
+In situations where the same module is used across multiple environments,
+it's common to see that some necessary object already exists in some
+environments but needs to be created in other environments.
+
+For example, this can arise in development environment scenarios: for cost
+reasons, certain infrastructure may be shared across multiple development
+environments, while in production the infrastructure is unique and managed
+directly by the production configuration.
+
+Rather than trying to write a module that itself tries to detect whether something
+exists and create it if not, we recommend applying the dependency inversion
+approach: making the module accept the object it needs as an argument, via
+an input variable.
+
+For example, consider a situation where a Terraform module deploys compute
+instances based on a disk image, and in some environments there is a
+specialized disk image available while other environments share a common
+base disk image. Rather than having the module itself handle both of these
+scenarios, we can instead declare an input variable for an object representing
+the disk image. Using AWS EC2 as an example, we might declare a common subtype
+of the `aws_ami` resource type and data source schemas:
+
+```hcl
+variable "ami" {
+  type = object({
+    # Declare an object using only the subset of attributes the module
+    # needs. Terraform will allow any object that has at least these
+    # attributes.
+    id           = string
+    architecture = string
+  })
+}
+```
+
+The caller of this module can now itself directly represent whether this is
+an AMI to be created inline or an AMI to be retrieved from elsewhere:
+
+```hcl
+# In situations where the AMI will be directly managed:
+
+resource "aws_ami_copy" "example" {
+  name              = "local-copy-of-ami"
+  source_ami_id     = "ami-abc123"
+  source_ami_region = "eu-west-1"
+}
+
+module "example" {
+  source = "./modules/example"
+
+  ami = aws_ami_copy.example
+}
+```
+
+```hcl
+# Or, in situations where the AMI already exists:
+
+data "aws_ami" "example" {
+  owner = "9999933333"
+
+  tags = {
+    application = "example-app"
+    environment = "dev"
+  }
+}
+
+module "example" {
+  source = "./modules/example"
+
+  ami = data.aws_ami.example
+}
+```
+
+This is consistent with Terraform's declarative style: rather than creating
+modules with complex conditional branches, we directly describe what
+should already exist and what we want Terraform to manage itself.
+
+By following this pattern, we can be explicit about in which situations we
+expect the AMI to already be present and which we don't. A future reader
+of the configuration can then directly understand what it is intending to do
+without first needing to inspect the state of the remote system.
+
+In the above example, the object to be created or read is simple enough to
+be given inline as a single resource, but we can also compose together multiple
+modules as described elsewhere on this page in situations where the
+dependencies themselves are complicated enough to benefit from abstractions.
+
+## Assumptions and Guarantees
+
+Every module has implicit assumptions and guarantees that define what data it expects and what data it produces for consumers.
+
+- **Assumption:** A condition that must be true in order for the configuration of a particular resource to be usable. For example, an `aws_instance` configuration can have the assumption that the given AMI will always be configured for the `x86_64` CPU architecture.
+- **Guarantee:** A characteristic or behavior of an object that the rest of the configuration should be able to rely on. For example, an `aws_instance` configuration can have the guarantee that an EC2 instance will be running in a network that assigns it a private DNS record.
+
+We recommend using [custom conditions](/terraform/language/expressions/custom-conditions) to help capture and test for assumptions and guarantees. This helps future maintainers understand the configuration design and intent. Custom conditions also return useful information about errors earlier and in context, helping consumers more easily diagnose issues in their configurations.
+
+The following examples creates a precondition that checks whether the EC2 instance has an encrypted root volume.
+
+```hcl
+output "api_base_url" {
+  value = "https://${aws_instance.example.private_dns}:8433/"
+
+  # The EC2 instance must have an encrypted root volume.
+  precondition {
+    condition     = data.aws_ebs_volume.example.encrypted
+    error_message = "The server's root volume is not encrypted."
+  }
+}
+```
+
+## Multi-cloud Abstractions
+
+Terraform itself intentionally does not attempt to abstract over similar
+services offered by different vendors, because we want to expose the full
+functionality in each offering and yet unifying multiple offerings behind a
+single interface will tend to require a "lowest common denominator" approach.
+
+However, through composition of Terraform modules it is possible to create
+your own lightweight multi-cloud abstractions by making your own tradeoffs
+about which platform features are important to you.
+
+Opportunities for such abstractions arise in any situation where multiple
+vendors implement the same concept, protocol, or open standard. For example,
+the basic capabilities of the domain name system are common across all vendors,
+and although some vendors differentiate themselves with unique features such
+as geolocation and smart load balancing, you may conclude that in your use-case
+you are willing to eschew those features in return for creating modules that
+abstract the common DNS concepts across multiple vendors:
+
+```hcl
+module "webserver" {
+  source = "./modules/webserver"
+}
+
+locals {
+  fixed_recordsets = [
+    {
+      name = "www"
+      type = "CNAME"
+      ttl  = 3600
+      records = [
+        "webserver01",
+        "webserver02",
+        "webserver03",
+      ]
+    },
+  ]
+  server_recordsets = [
+    for i, addr in module.webserver.public_ip_addrs : {
+      name    = format("webserver%02d", i)
+      type    = "A"
+      records = [addr]
+    }
+  ]
+}
+
+module "dns_records" {
+  source = "./modules/route53-dns-records"
+
+  route53_zone_id = var.route53_zone_id
+  recordsets      = concat(local.fixed_recordsets, local.server_recordsets)
+}
+```
+
+In the above example, we've created a lightweight abstraction in the form of
+a "recordset" object. This contains the attributes that describe the general
+idea of a DNS recordset that should be mappable onto any DNS provider.
+
+We then instantiate one specific _implementation_ of that abstraction as a
+module, in this case deploying our recordsets to Amazon Route53.
+
+If we later wanted to switch to a different DNS provider, we'd need only to
+replace the `dns_records` module with a new implementation targeting that
+provider, and all of the configuration that _produces_ the recordset
+definitions can remain unchanged.
+
+We can create lightweight abstractions like these by defining Terraform object
+types representing the concepts involved and then using these object types
+for module input variables. In this case, all of our "DNS records"
+implementations would have the following variable declared:
+
+```hcl
+variable "recordsets" {
+  type = list(object({
+    name    = string
+    type    = string
+    ttl     = number
+    records = list(string)
+  }))
+}
+```
+
+While DNS serves as a simple example, there are many more opportunities to
+exploit common elements across vendors. A more complex example is Kubernetes,
+where there are now many different vendors offering hosted Kubernetes clusters
+and even more ways to run Kubernetes yourself.
+
+If the common functionality across all of these implementations is sufficient
+for your needs, you may choose to implement a set of different modules that
+describe a particular Kubernetes cluster implementation and all have the common
+trait of exporting the hostname of the cluster as an output value:
+
+```hcl
+output "hostname" {
+  value = azurerm_kubernetes_cluster.main.fqdn
+}
+```
+
+You can then write _other_ modules that expect only a Kubernetes cluster
+hostname as input and use them interchangeably with any of your Kubernetes
+cluster modules:
+
+```hcl
+module "k8s_cluster" {
+  source = "modules/azurerm-k8s-cluster"
+
+  # (Azure-specific configuration arguments)
+}
+
+module "monitoring_tools" {
+  source = "modules/monitoring_tools"
+
+  cluster_hostname = module.k8s_cluster.hostname
+}
+```
+
+## Data-only Modules
+
+Most modules contain `resource` blocks and thus describe infrastructure to be
+created and managed. It may sometimes be useful to write modules that do not
+describe any new infrastructure at all, but merely retrieve information about
+existing infrastructure that was created elsewhere using
+[data sources](/terraform/language/data-sources).
+
+As with conventional modules, we suggest using this technique only when the
+module raises the level of abstraction in some way, in this case by
+encapsulating exactly how the data is retrieved.
+
+A common use of this technique is when a system has been decomposed into several
+subsystem configurations but there is certain infrastructure that is shared
+across all of the subsystems, such as a common IP network. In this situation,
+we might write a shared module called `join-network-aws` which can be called
+by any configuration that needs information about the shared network when
+deployed in AWS:
+
+```hcl
+module "network" {
+  source = "./modules/join-network-aws"
+
+  environment = "production"
+}
+
+module "k8s_cluster" {
+  source = "./modules/aws-k8s-cluster"
+
+  subnet_ids = module.network.aws_subnet_ids
+}
+```
+
+The `network` module itself could retrieve this data in a number of different
+ways: it could query the AWS API directly using
+[`aws_vpc`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc)
+and
+[`aws_subnet_ids`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet_ids)
+data sources, or it could read saved information from a Consul cluster using
+[`consul_keys`](https://registry.terraform.io/providers/hashicorp/consul/latest/docs/data-sources/keys),
+or it might read the outputs directly from the state of the configuration that
+manages the network using
+[`terraform_remote_state`](/terraform/language/state/remote-state-data).
+
+The key benefit of this approach is that the source of this information can
+change over time without updating every configuration that depends on it.
+Furthermore, if you design your data-only module with a similar set of outputs
+as a corresponding management module, you can swap between the two relatively
+easily when refactoring.
diff --git a/v1.5.7/website/docs/language/modules/develop/index.mdx b/v1.5.7/website/docs/language/modules/develop/index.mdx
new file mode 100644
index 0000000..d4a321c
--- /dev/null
+++ b/v1.5.7/website/docs/language/modules/develop/index.mdx
@@ -0,0 +1,85 @@
+---
+page_title: Creating Modules
+description: >-
+  Modules are containers for multiple resources that are used together in a
+  configuration. Learn when to create modules and about module structure.
+---
+
+# Creating Modules
+
+> **Hands-on:** Try the [Reuse Configuration with Modules](/terraform/tutorials/modules?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorials.
+
+A _module_ is a container for multiple resources that are used together.
+You can use modules to create lightweight abstractions, so that you can
+describe your infrastructure in terms of its architecture, rather than
+directly in terms of physical objects.
+
+The `.tf` files in your working directory when you run [`terraform plan`](/terraform/cli/commands/plan)
+or [`terraform apply`](/terraform/cli/commands/apply) together form the _root_
+module. That module may [call other modules](/terraform/language/modules/syntax#calling-a-child-module)
+and connect them together by passing output values from one to input values
+of another.
+
+To learn how to _use_ modules, see [the Modules configuration section](/terraform/language/modules).
+This section is about _creating_ re-usable modules that other configurations
+can include using `module` blocks.
+
+## Module structure
+
+Re-usable modules are defined using all of the same
+[configuration language](/terraform/language) concepts we use in root modules.
+Most commonly, modules use:
+
+* [Input variables](/terraform/language/values/variables) to accept values from
+  the calling module.
+* [Output values](/terraform/language/values/outputs) to return results to the
+  calling module, which it can then use to populate arguments elsewhere.
+* [Resources](/terraform/language/resources) to define one or more
+  infrastructure objects that the module will manage.
+
+To define a module, create a new directory for it and place one or more `.tf`
+files inside just as you would do for a root module. Terraform can load modules
+either from local relative paths or from remote repositories; if a module will
+be re-used by lots of configurations you may wish to place it in its own
+version control repository.
+
+Modules can also call other modules using a `module` block, but we recommend
+keeping the module tree relatively flat and using [module composition](/terraform/language/modules/develop/composition)
+as an alternative to a deeply-nested tree of modules, because this makes
+the individual modules easier to re-use in different combinations.
+
+## When to write a module
+
+In principle any combination of resources and other constructs can be factored
+out into a module, but over-using modules can make your overall Terraform
+configuration harder to understand and maintain, so we recommend moderation.
+
+A good module should raise the level of abstraction by describing a new concept
+in your architecture that is constructed from resource types offered by
+providers.
+
+For example, `aws_instance` and `aws_elb` are both resource types belonging to
+the AWS provider. You might use a module to represent the higher-level concept
+"[HashiCorp Consul](https://www.consul.io/) cluster running in AWS" which
+happens to be constructed from these and other AWS provider resources.
+
+We _do not_ recommend writing modules that are just thin wrappers around single
+other resource types. If you have trouble finding a name for your module that
+isn't the same as the main resource type inside it, that may be a sign that
+your module is not creating any new abstraction and so the module is
+adding unnecessary complexity. Just use the resource type directly in the
+calling module instead.
+
+### No-Code Provisioning in Terraform Cloud
+
+You can also create no-code ready modules to enable the no-code provisioning workflow in Terraform Cloud. No-code provisioning lets users deploy a module's resources in Terraform Cloud without writing any Terraform configuration.
+
+No-code ready modules have additional requirements and considerations. Refer to [Designing No-Code Ready Modules](/terraform/cloud-docs/no-code-provisioning/module-design) in the Terraform Cloud documentation for details.
+
+## Refactoring module resources
+
+You can include [refactoring blocks](/terraform/language/modules/develop/refactoring) to record how resource
+names and module structure have changed from previous module versions.
+Terraform uses that information during planning to reinterpret existing objects
+as if they had been created at the corresponding new addresses, eliminating a
+separate workflow step to replace or migrate existing objects.
diff --git a/v1.5.7/website/docs/language/modules/develop/providers.mdx b/v1.5.7/website/docs/language/modules/develop/providers.mdx
new file mode 100644
index 0000000..f503855
--- /dev/null
+++ b/v1.5.7/website/docs/language/modules/develop/providers.mdx
@@ -0,0 +1,366 @@
+---
+page_title: Providers Within Modules - Configuration Language
+description: >-
+  Use providers within Terraform modules. Learn about version constraints, aliases, implicit inheritance, and passing providers to Terraform modules.
+---
+
+# Providers Within Modules
+
+[inpage-providers]: #providers-within-modules
+
+In a configuration with multiple modules, there are some special considerations
+for how resources are associated with provider configurations.
+
+Each resource in the configuration must be associated with one provider
+configuration. Provider configurations, unlike most other concepts in
+Terraform, are global to an entire Terraform configuration and can be shared
+across module boundaries. Provider configurations can be defined only in a
+root Terraform module.
+
+Providers can be passed down to descendent modules in two ways: either
+_implicitly_ through inheritance, or _explicitly_ via the `providers` argument
+within a `module` block. These two options are discussed in more detail in the
+following sections.
+
+A module intended to be called by one or more other modules must not contain
+any `provider` blocks. A module containing its own provider configurations is
+not compatible with the `for_each`, `count`, and `depends_on` arguments that
+were introduced in Terraform v0.13. For more information, see
+[Legacy Shared Modules with Provider Configurations](#legacy-shared-modules-with-provider-configurations).
+
+Provider configurations are used for all operations on associated resources,
+including destroying remote objects and refreshing state. Terraform retains, as
+part of its state, a reference to the provider configuration that was most
+recently used to apply changes to each resource. When a `resource` block is
+removed from the configuration, this record in the state will be used to locate
+the appropriate configuration because the resource's `provider` argument
+(if any) will no longer be present in the configuration.
+
+As a consequence, you must ensure that all resources that belong to a
+particular provider configuration are destroyed before you can remove that
+provider configuration's block from your configuration. If Terraform finds
+a resource instance tracked in the state whose provider configuration block is
+no longer available then it will return an error during planning, prompting you
+to reintroduce the provider configuration.
+
+## Provider Version Constraints in Modules
+
+Although provider _configurations_ are shared between modules, each module must
+declare its own [provider requirements](/terraform/language/providers/requirements), so that
+Terraform can ensure that there is a single version of the provider that is
+compatible with all modules in the configuration and to specify the
+[source address](/terraform/language/providers/requirements#source-addresses) that serves as
+the global (module-agnostic) identifier for a provider.
+
+To declare that a module requires particular versions of a specific provider,
+use a `required_providers` block inside a `terraform` block:
+
+```hcl
+terraform {
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = ">= 2.7.0"
+    }
+  }
+}
+```
+
+A provider requirement says, for example, "This module requires version v2.7.0
+of the provider `hashicorp/aws` and will refer to it as `aws`." It doesn't,
+however, specify any of the configuration settings that determine what remote
+endpoints the provider will access, such as an AWS region; configuration
+settings come from provider _configurations_, and a particular overall Terraform
+configuration can potentially have
+[several different configurations for the same provider](/terraform/language/providers/configuration#alias-multiple-provider-configurations).
+
+## Provider Aliases Within Modules
+
+To declare multiple configuration names for a provider within a module, add the
+`configuration_aliases` argument:
+
+```hcl
+terraform {
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = ">= 2.7.0"
+      configuration_aliases = [ aws.alternate ]
+    }
+  }
+}
+```
+
+The above requirements are identical to the previous, with the addition of the
+alias provider configuration name `aws.alternate`, which can be referenced by
+resources using the `provider` argument.
+
+If you are writing a shared Terraform module, constrain only the minimum
+required provider version using a `>=` constraint. This should specify the
+minimum version containing the features your module relies on, and thus allow a
+user of your module to potentially select a newer provider version if other
+features are needed by other parts of their overall configuration.
+
+## Implicit Provider Inheritance
+
+For convenience in simple configurations, a child module automatically inherits
+[default provider configurations](/terraform/language/providers/configuration#default-provider-configurations) from its parent. This means that
+explicit `provider` blocks appear only in the root module, and downstream
+modules can simply declare resources for that provider and have them
+automatically associated with the root provider configurations.
+
+For example, the root module might contain only a `provider` block and a
+`module` block to instantiate a child module:
+
+```hcl
+provider "aws" {
+  region = "us-west-1"
+}
+
+module "child" {
+  source = "./child"
+}
+```
+
+The child module can then use any resource from this provider with no further
+provider configuration required:
+
+```hcl
+resource "aws_s3_bucket" "example" {
+  bucket = "provider-inherit-example"
+}
+```
+
+We recommend using this approach when a single configuration for each provider
+is sufficient for an entire configuration.
+
+~> **Note:** Only provider configurations are inherited by child modules, not provider source or version requirements. Each module must [declare its own provider requirements](/terraform/language/providers/requirements). This is especially important for non-HashiCorp providers.
+
+In more complex situations there may be
+[multiple provider configurations](/terraform/language/providers/configuration#alias-multiple-provider-configurations),
+or a child module may need to use different provider settings than
+its parent. For such situations, you must pass providers explicitly.
+
+## Passing Providers Explicitly
+
+When child modules each need a different configuration of a particular
+provider, or where the child module requires a different provider configuration
+than its parent, you can use the `providers` argument within a `module` block
+to explicitly define which provider configurations are available to the
+child module. For example:
+
+```hcl
+# The default "aws" configuration is used for AWS resources in the root
+# module where no explicit provider instance is selected.
+provider "aws" {
+  region = "us-west-1"
+}
+
+# An alternate configuration is also defined for a different
+# region, using the alias "usw2".
+provider "aws" {
+  alias  = "usw2"
+  region = "us-west-2"
+}
+
+# An example child module is instantiated with the alternate configuration,
+# so any AWS resources it defines will use the us-west-2 region.
+module "example" {
+  source    = "./example"
+  providers = {
+    aws = aws.usw2
+  }
+}
+```
+
+The `providers` argument within a `module` block is similar to
+[the `provider` argument](/terraform/language/meta-arguments/resource-provider)
+within a resource, but is a map rather than a single string because a module may
+contain resources from many different providers.
+
+The keys of the `providers` map are provider configuration names as expected by
+the child module, and the values are the names of corresponding configurations
+in the _current_ module.
+
+Once the `providers` argument is used in a `module` block, it overrides all of
+the default inheritance behavior, so it is necessary to enumerate mappings
+for _all_ of the required providers. This is to avoid confusion and surprises
+that may result when mixing both implicit and explicit provider passing.
+
+Additional provider configurations (those with the `alias` argument set) are
+_never_ inherited automatically by child modules, and so must always be passed
+explicitly using the `providers` map. For example, a module
+that configures connectivity between networks in two AWS regions is likely
+to need both a source and a destination region. In that case, the root module
+may look something like this:
+
+```hcl
+provider "aws" {
+  alias  = "usw1"
+  region = "us-west-1"
+}
+
+provider "aws" {
+  alias  = "usw2"
+  region = "us-west-2"
+}
+
+module "tunnel" {
+  source    = "./tunnel"
+  providers = {
+    aws.src = aws.usw1
+    aws.dst = aws.usw2
+  }
+}
+```
+
+The subdirectory `./tunnel` must then declare the configuration aliases for the
+provider so the calling module can pass configurations with these names in its `providers` argument:
+
+```hcl
+terraform {
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = ">= 2.7.0"
+      configuration_aliases = [ aws.src, aws.dst ]
+    }
+  }
+}
+```
+
+Each resource should then have its own `provider` attribute set to either
+`aws.src` or `aws.dst` to choose which of the two provider configurations to
+use.
+
+## Legacy Shared Modules with Provider Configurations
+
+In Terraform v0.10 and earlier there was no explicit way to use different
+configurations of a provider in different modules in the same configuration,
+and so module authors commonly worked around this by writing `provider` blocks
+directly inside their modules, making the module have its own separate
+provider configurations separate from those declared in the root module.
+
+However, that pattern had a significant drawback: because a provider
+configuration is required to destroy the remote object associated with a
+resource instance as well as to create or update it, a provider configuration
+must always stay present in the overall Terraform configuration for longer
+than all of the resources it manages. If a particular module includes
+both resources and the provider configurations for those resources then
+removing the module from its caller would violate that constraint: both the
+resources and their associated providers would, in effect, be removed
+simultaneously.
+
+Terraform v0.11 introduced the mechanisms described in earlier sections to
+allow passing provider configurations between modules in a structured way, and
+thus we explicitly recommended against writing a child module with its own
+provider configuration blocks. However, that legacy pattern continued to work
+for compatibility purposes -- though with the same drawback -- until Terraform
+v0.13.
+
+Terraform v0.13 introduced the possibility for a module itself to use the
+`for_each`, `count`, and `depends_on` arguments, but the implementation of
+those unfortunately conflicted with the support for the legacy pattern.
+
+To retain the backward compatibility as much as possible, Terraform v0.13
+continues to support the legacy pattern for module blocks that do not use these
+new features, but a module with its own provider configurations is not
+compatible with `for_each`, `count`, or `depends_on`. Terraform will produce an
+error if you attempt to combine these features. For example:
+
+```
+Error: Module does not support count
+
+  on main.tf line 15, in module "child":
+  15:   count = 2
+
+Module "child" cannot be used with count because it contains a nested provider
+configuration for "aws", at child/main.tf:2,10-15.
+
+This module can be made compatible with count by changing it to receive all of
+its provider configurations from the calling module, by using the "providers"
+argument in the calling module block.
+```
+
+To make a module compatible with the new features, you must remove all of the
+`provider` blocks from its definition.
+
+If the new version of the module declares `configuration_aliases`, or if the
+calling module needs the child module to use different provider configurations
+than its own default provider configurations, the calling module must then
+include an explicit `providers` argument to describe which provider
+configurations the child module will use:
+
+```hcl
+provider "aws" {
+  region = "us-west-1"
+}
+
+provider "aws" {
+  region = "us-east-1"
+  alias  = "east"
+}
+
+module "child" {
+  count = 2
+  providers = {
+    # By default, the child module would use the
+    # default (unaliased) AWS provider configuration
+    # using us-west-1, but this will override it
+    # to use the additional "east" configuration
+    # for its resources instead.
+    aws = aws.east
+  }
+}
+```
+
+Since the association between resources and provider configurations is
+static, module calls using `for_each` or `count` cannot pass different
+provider configurations to different instances. If you need different
+instances of your module to use different provider configurations then you
+must use a separate `module` block for each distinct set of provider
+configurations:
+
+```hcl
+provider "aws" {
+  alias  = "usw1"
+  region = "us-west-1"
+}
+
+provider "aws" {
+  alias  = "usw2"
+  region = "us-west-2"
+}
+
+provider "google" {
+  alias       = "usw1"
+  credentials = "${file("account.json")}"
+  project     = "my-project-id"
+  region      = "us-west1"
+  zone        = "us-west1-a"
+}
+
+provider "google" {
+  alias       = "usw2"
+  credentials = "${file("account.json")}"
+  project     = "my-project-id"
+  region      = "us-west2"
+  zone        = "us-west2-a"
+}
+
+module "bucket_w1" {
+  source    = "./publish_bucket"
+  providers = {
+    aws.src    = aws.usw1
+    google.src = google.usw1
+  }
+}
+
+module "bucket_w2" {
+  source    = "./publish_bucket"
+  providers = {
+    aws.src    = aws.usw2
+    google.src = google.usw2
+  }
+}
+```
diff --git a/v1.5.7/website/docs/language/modules/develop/publish.mdx b/v1.5.7/website/docs/language/modules/develop/publish.mdx
new file mode 100644
index 0000000..c904a0a
--- /dev/null
+++ b/v1.5.7/website/docs/language/modules/develop/publish.mdx
@@ -0,0 +1,41 @@
+---
+page_title: Publishing Modules
+description: A module is a container for multiple resources that are used together.
+---
+
+# Publishing Modules
+
+If you've built a module that you intend to be reused, we recommend
+[publishing the module](/terraform/registry/modules/publish) on the
+[Terraform Registry](https://registry.terraform.io). This will version
+your module, generate documentation, and more.
+
+Published modules can be easily consumed by Terraform, and users can
+[constrain module versions](/terraform/language/modules/syntax#version)
+for safe and predictable updates. The following example shows how a caller
+might use a module from the Terraform Registry:
+
+```hcl
+module "consul" {
+  source = "hashicorp/consul/aws"
+}
+```
+
+If you do not wish to publish your modules in the public registry, you can
+instead use a [private registry](/terraform/registry/private) to get
+the same benefits.
+
+We welcome contributions of Terraform modules from our community members, partners, and customers. Our ecosystem is made richer by each new module created or an existing one updated, as they reflect the wide range of experience and technical requirements of the community that uses them. Our cloud provider partners often seek to develop specific modules for popular or challenging use cases on their platform and utilize them as valuable learning experiences to empathize with their users. Similarly, our community module developers incorporate a variety of opinions and use cases from the broader Terraform community. Both types of modules have their place in the Terraform registry, accessible to practitioners who can decide which modules best fit their requirements.
+
+## Distribution via other sources
+
+Although the registry is the native mechanism for distributing re-usable
+modules, Terraform can also install modules from
+[various other sources](/terraform/language/modules/sources). The alternative sources
+do not support the first-class versioning mechanism, but some sources have
+their own mechanisms for selecting particular VCS commits, etc.
+
+We recommend that modules distributed via other protocols still use the
+[standard module structure](/terraform/language/modules/develop/structure) so that they can
+be used in a similar way as a registry module or be published on the registry
+at a later time.
diff --git a/v1.5.7/website/docs/language/modules/develop/refactoring.mdx b/v1.5.7/website/docs/language/modules/develop/refactoring.mdx
new file mode 100644
index 0000000..4be1c89
--- /dev/null
+++ b/v1.5.7/website/docs/language/modules/develop/refactoring.mdx
@@ -0,0 +1,448 @@
+---
+page_title: Refactoring
+description: How to make backward-compatible changes to modules already in use.
+---
+
+# Refactoring
+
+-> **Note:** Explicit refactoring declarations with `moved` blocks is available in Terraform v1.1 and later. For earlier Terraform versions or for refactoring actions too complex to express as `moved` blocks, you can
+use the [`terraform state mv` CLI command](/terraform/cli/commands/state/mv)
+as a separate step.
+
+In shared modules and long-lived configurations, you may eventually outgrow
+your initial module structure and resource names. For example, you might decide
+that what was previously one child module makes more sense as two separate
+modules and move a subset of the existing resources to the new one.
+
+Terraform compares previous state with new configuration, correlating by
+each module or resource's unique address. Therefore _by default_ Terraform
+understands moving or renaming an object as an intent to destroy the object
+at the old address and to create a new object at the new address.
+
+When you add `moved` blocks in your configuration to record where you've
+historically moved or renamed an object, Terraform treats an existing object at
+the old address as if it now belongs to the new address.
+
+> **Hands On:** Try the [Use Configuration to Move Resources](/terraform/tutorials/configuration-language/move-config) tutorial.
+
+## `moved` Block Syntax
+
+A `moved` block expects no labels and contains only `from` and `to` arguments:
+
+```hcl
+moved {
+  from = aws_instance.a
+  to   = aws_instance.b
+}
+```
+
+The example above records that the resource currently known as `aws_instance.b`
+was known as `aws_instance.a` in a previous version of this module.
+
+Before creating a new plan for `aws_instance.b`, Terraform first checks
+whether there is an existing object for `aws_instance.a` recorded in the state.
+If there is an existing object, Terraform renames that object to
+`aws_instance.b` and then proceeds with creating a plan. The resulting plan is
+as if the object had originally been created at `aws_instance.b`, avoiding any
+need to destroy it during apply.
+
+The `from` and `to` addresses both use a special addressing syntax that allows
+selecting modules, resources, and resources inside child modules. Below, we
+describe several refactoring use-cases and the appropriate addressing syntax
+for each situation.
+
+* [Renaming a Resource](#renaming-a-resource)
+* [Enabling `count` or `for_each` For a Resource](#enabling-count-or-for_each-for-a-resource)
+* [Renaming a Module Call](#renaming-a-module-call)
+* [Enabling `count` or `for_each` For a Module Call](#enabling-count-or-for_each-for-a-module-call)
+* [Splitting One Module into Multiple](#splitting-one-module-into-multiple)
+* [Removing `moved` blocks](#removing-moved-blocks)
+
+## Renaming a Resource
+
+Consider this example module with a resource configuration:
+
+```hcl
+resource "aws_instance" "a" {
+  count = 2
+
+  # (resource-type-specific configuration)
+}
+```
+
+Applying this configuration for the first time would cause Terraform to
+create `aws_instance.a[0]` and `aws_instance.a[1]`.
+
+If you later choose a different name for this resource, then you can change the
+name label in the `resource` block and record the old name inside a `moved` block:
+
+```hcl
+resource "aws_instance" "b" {
+  count = 2
+
+  # (resource-type-specific configuration)
+}
+
+moved {
+  from = aws_instance.a
+  to   = aws_instance.b
+}
+```
+
+When creating the next plan for each configuration using this module, Terraform
+treats any existing objects belonging to `aws_instance.a` as if they had
+been created for `aws_instance.b`: `aws_instance.a[0]` will be treated as
+`aws_instance.b[0]`, and `aws_instance.a[1]` as `aws_instance.b[1]`.
+
+New instances of the module, which _never_ had an
+`aws_instance.a`, will ignore the `moved` block and propose to create
+`aws_instance.b[0]` and `aws_instance.b[1]` as normal.
+
+Both of the addresses in this example referred to a resource as a whole, and
+so Terraform recognizes the move for all instances of the resource. That is,
+it covers both `aws_instance.a[0]` and `aws_instance.a[1]` without the need
+to identify each one separately.
+
+Each resource type has a separate schema and so objects of different types
+are not compatible. Therefore, although you can use `moved` to change the name
+of a resource, you _cannot_ use `moved` to change to a different resource type
+or to change a managed resource (a `resource` block) into a data resource
+(a `data` block).
+
+## Enabling `count` or `for_each` For a Resource
+
+Consider this example module containing a single-instance resource:
+
+```hcl
+resource "aws_instance" "a" {
+  # (resource-type-specific configuration)
+}
+```
+
+Applying this configuration would lead to Terraform creating an object
+bound to the address `aws_instance.a`.
+
+Later, you use [`for_each`](/terraform/language/meta-arguments/for_each) with this
+resource to systematically declare multiple instances. To preserve an object
+that was previously associated with `aws_instance.a` alone, you must add a
+`moved` block to specify which instance key the object will take in the new
+configuration:
+
+```hcl
+locals {
+  instances = tomap({
+    big = {
+      instance_type = "m3.large"
+    }
+    small = {
+      instance_type = "t2.medium"
+    }
+  })
+}
+
+resource "aws_instance" "a" {
+  for_each = local.instances
+
+  instance_type = each.value.instance_type
+  # (other resource-type-specific configuration)
+}
+
+moved {
+  from = aws_instance.a
+  to   = aws_instance.a["small"]
+}
+```
+
+The above will keep Terraform from planning to destroy any existing object at
+`aws_instance.a`, treating that object instead as if it were originally
+created as `aws_instance.a["small"]`.
+
+When at least one of the two addresses includes an instance key, like
+`["small"]` in the above example, Terraform understands both addresses as
+referring to specific _instances_ of a resource rather than the resource as a
+whole. That means you can use `moved` to switch between keys and to add and
+remove keys as you switch between `count`, `for_each`, or neither.
+
+The following are some other examples of valid `moved` blocks that record
+changes to resource instance keys in a similar way:
+
+```hcl
+# Both old and new configuration used "for_each", but the
+# "small" element was renamed to "tiny".
+moved {
+  from = aws_instance.b["small"]
+  to   = aws_instance.b["tiny"]
+}
+
+# The old configuration used "count" and the new configuration
+# uses "for_each", with the following mappings from
+# index to key:
+moved {
+  from = aws_instance.c[0]
+  to   = aws_instance.c["small"]
+}
+moved {
+  from = aws_instance.c[1]
+  to   = aws_instance.c["tiny"]
+}
+
+# The old configuration used "count", and the new configuration
+# uses neither "count" nor "for_each", and you want to keep
+# only the object at index 2.
+moved {
+  from = aws_instance.d[2]
+  to   = aws_instance.d
+}
+```
+
+-> **Note:** When you add `count` to an existing resource that didn't use it,
+Terraform automatically proposes to move the original object to instance zero,
+unless you write an `moved` block explicitly mentioning that resource.
+However, we recommend still writing out the corresponding `moved` block
+explicitly, to make the change clearer to future readers of the module.
+
+## Renaming a Module Call
+
+You can rename a call to a module in a similar way as renaming a resource.
+Consider the following original module version:
+
+```hcl
+module "a" {
+  source = "../modules/example"
+
+  # (module arguments)
+}
+```
+
+When applying this configuration, Terraform would prefix the addresses for
+any resources declared in this module with the module path `module.a`.
+For example, a resource `aws_instance.example` would have the full address
+`module.a.aws_instance.example`.
+
+If you later choose a better name for this module call, then you can change the
+name label in the `module` block and record the old name inside a `moved` block:
+
+```hcl
+module "b" {
+  source = "../modules/example"
+
+  # (module arguments)
+}
+
+moved {
+  from = module.a
+  to   = module.b
+}
+```
+
+When creating the next plan for each configuration using this module, Terraform
+will treat any existing object addresses beginning with `module.a` as if
+they had instead been created in `module.b`. `module.a.aws_instance.example`
+would be treated as `module.b.aws_instance.example`.
+
+Both of the addresses in this example referred to a module call as a whole, and
+so Terraform recognizes the move for all instances of the call. If this
+module call used `count` or `for_each` then it would apply to all of the
+instances, without the need to specify each one separately.
+
+## Enabling `count` or `for_each` For a Module Call
+
+Consider this example of a single-instance module:
+
+```hcl
+module "a" {
+  source = "../modules/example"
+
+  # (module arguments)
+}
+```
+
+Applying this configuration would cause Terraform to create objects whose
+addresses begin with `module.a`.
+
+In later module versions, you may need to use
+[`count`](/terraform/language/meta-arguments/count) with this resource to systematically
+declare multiple instances. To preserve an object that was previously associated
+with `aws_instance.a` alone, you can add a `moved` block to specify which
+instance key that object will take in the new configuration:
+
+```hcl
+module "a" {
+  source = "../modules/example"
+  count  = 3
+
+  # (module arguments)
+}
+
+moved {
+  from = module.a
+  to   = module.a[2]
+}
+```
+
+The configuration above directs Terraform to treat all objects in `module.a` as
+if they were originally created in `module.a[2]`. As a result, Terraform plans
+to create new objects only for `module.a[0]` and `module.a[1]`.
+
+When at least one of the two addresses includes an instance key, like
+`[2]` in the above example, Terraform will understand both addresses as
+referring to specific _instances_ of a module call rather than the module
+call as a whole. That means you can use `moved` to switch between keys and to
+add and remove keys as you switch between `count`, `for_each`, or neither.
+
+For more examples of recording moves associated with instances, refer to
+the similar section
+[Enabling `count` and `for_each` For a Resource](#enabling-count-or-for_each-for-a-resource).
+
+# Splitting One Module into Multiple
+
+As a module grows to support new requirements, it might eventually grow big
+enough to warrant splitting into two separate modules.
+
+Consider this example module:
+
+```hcl
+resource "aws_instance" "a" {
+  # (other resource-type-specific configuration)
+}
+
+resource "aws_instance" "b" {
+  # (other resource-type-specific configuration)
+}
+
+resource "aws_instance" "c" {
+  # (other resource-type-specific configuration)
+}
+```
+
+You can split this into two modules as follows:
+
+* `aws_instance.a` now belongs to module "x".
+* `aws_instance.b` also belongs to module "x".
+* `aws_instance.c` belongs module "y".
+
+To achieve this refactoring without replacing existing objects bound to the
+old resource addresses, you must:
+
+1. Write module "x", copying over the two resources it should contain.
+1. Write module "y", copying over the one resource it should contain.
+1. Edit the original module to no longer include any of these resources, and
+   instead to contain only shim configuration to migrate existing users.
+
+The new modules "x" and "y" should contain only `resource` blocks:
+
+```hcl
+# module "x"
+
+resource "aws_instance" "a" {
+  # (other resource-type-specific configuration)
+}
+
+resource "aws_instance" "b" {
+  # (other resource-type-specific configuration)
+}
+```
+
+```hcl
+# module "y"
+
+resource "aws_instance" "c" {
+  # (other resource-type-specific configuration)
+}
+```
+
+The original module, now only a shim for backward-compatibility, calls the
+two new modules and indicates that the resources moved into them:
+
+```hcl
+module "x" {
+  source = "../modules/x"
+
+  # ...
+}
+
+module "y" {
+  source = "../modules/y"
+
+  # ...
+}
+
+moved {
+  from = aws_instance.a
+  to   = module.x.aws_instance.a
+}
+
+moved {
+  from = aws_instance.b
+  to   = module.x.aws_instance.b
+}
+
+moved {
+  from = aws_instance.c
+  to   = module.y.aws_instance.c
+}
+```
+
+When an existing user of the original module upgrades to the new "shim"
+version, Terraform notices these three `moved` blocks and behaves
+as if the objects associated with the three old resource addresses were
+originally created inside the two new modules.
+
+New users of this family of modules may use either the combined shim module
+_or_ the two new modules separately. You may wish to communicate to your
+existing users that the old module is now deprecated and so they should use
+the two separate modules for any new needs.
+
+The multi-module refactoring situation is unusual in that it violates the
+typical rule that a parent module sees its child module as a "closed box",
+unaware of exactly which resources are declared inside it. This compromise
+assumes that all three of these modules are maintained by the same people
+and distributed together in a single
+[module package](/terraform/language/modules/sources#modules-in-package-sub-directories).
+
+Terraform resolves module references in `moved` blocks relative to the module
+instance they are defined in. For example, if the original module above were
+already a child module named `module.original`, the reference to
+`module.x.aws_instance.a` would resolve as
+`module.original.module.x.aws_instance.a`. A module may only make `moved`
+statements about its own objects and objects of its child modules.
+
+If you need to refer to resources within a module that was called using
+`count` or `for_each` meta-arguments, you must specify a specific instance
+key to use in order to match with the new location of the resource
+configuration:
+
+```hcl
+moved {
+  from = aws_instance.example
+  to   = module.new[2].aws_instance.example
+}
+```
+
+## Removing `moved` Blocks
+
+Over time, a long-lasting module may accumulate many `moved` blocks.
+
+Removing a `moved` block is a generally breaking change because any configurations that refer to the old address will plan to delete that existing object instead of move it. We strongly recommend that you retain all historical `moved` blocks from earlier versions of your modules to preserve the upgrade path for users of any previous version.
+
+If you do decide to remove `moved` blocks, proceed with caution. It can be safe to remove `moved` blocks when you are maintaining private modules within an organization and you are certain that all users have successfully run `terraform apply` with your new module version.
+
+If you need to rename or move the same object twice, we recommend documenting the full history
+using _chained_ `moved` blocks, where the new block refers to the existing block:
+
+```hcl
+moved {
+  from = aws_instance.a
+  to   = aws_instance.b
+}
+
+moved {
+  from = aws_instance.b
+  to   = aws_instance.c
+}
+```
+
+Recording a sequence of moves in this way allows for successful upgrades for
+both configurations with objects at `aws_instance.a` _and_ configurations with
+objects at `aws_instance.b`. In both cases, Terraform treats the existing
+object as if it had been originally created as `aws_instance.c`.
diff --git a/v1.5.7/website/docs/language/modules/develop/structure.mdx b/v1.5.7/website/docs/language/modules/develop/structure.mdx
new file mode 100644
index 0000000..20ba5c9
--- /dev/null
+++ b/v1.5.7/website/docs/language/modules/develop/structure.mdx
@@ -0,0 +1,129 @@
+---
+page_title: Standard Module Structure
+description: >-
+  Learn about the recommended file and directory structure for developing reusable modules distributed as separate repositories.
+---
+
+# Standard Module Structure
+
+The standard module structure is a file and directory layout we recommend for
+reusable modules distributed in separate repositories. Terraform tooling is
+built to understand the standard module structure and use that structure to
+generate documentation, index modules for the module registry, and more.
+
+The standard module structure expects the layout documented below. The list may
+appear long, but everything is optional except for the root module. Most modules
+don't need to do any extra work to follow the standard structure.
+
+* **Root module**. This is the **only required element** for the standard
+  module structure. Terraform files must exist in the root directory of
+  the repository. This should be the primary entrypoint for the module and is
+  expected to be opinionated. For the
+  [Consul module](https://registry.terraform.io/modules/hashicorp/consul)
+  the root module sets up a complete Consul cluster. It makes a lot of assumptions
+  however, and we expect that advanced users will use specific _nested modules_
+  to more carefully control what they want.
+
+* **README**. The root module and any nested modules should have README
+  files. This file should be named `README` or `README.md`. The latter will
+  be treated as markdown. There should be a description of the module and
+  what it should be used for. If you want to include an example for how this
+  module can be used in combination with other resources, put it in an [examples
+  directory like this](https://github.com/hashicorp/terraform-aws-consul/tree/master/examples).
+  Consider including a visual diagram depicting the infrastructure resources
+  the module may create and their relationship.
+
+  The README doesn't need to document inputs or outputs of the module because
+  tooling will automatically generate this. If you are linking to a file or
+  embedding an image contained in the repository itself, use a commit-specific
+  absolute URL so the link won't point to the wrong version of a resource in the
+  future.
+
+* **LICENSE**. The license under which this module is available. If you are
+  publishing a module publicly, many organizations will not adopt a module
+  unless a clear license is present. We recommend always having a license
+  file, even if it is not an open source license.
+
+* **`main.tf`, `variables.tf`, `outputs.tf`**. These are the recommended filenames for
+  a minimal module, even if they're empty. `main.tf` should be the primary
+  entrypoint. For a simple module, this may be where all the resources are
+  created. For a complex module, resource creation may be split into multiple
+  files but any nested module calls should be in the main file. `variables.tf`
+  and `outputs.tf` should contain the declarations for variables and outputs,
+  respectively.
+
+* **Variables and outputs should have descriptions.** All variables and
+  outputs should have one or two sentence descriptions that explain their
+  purpose. This is used for documentation. See the documentation for
+  [variable configuration](/terraform/language/values/variables) and
+  [output configuration](/terraform/language/values/outputs) for more details.
+
+* **Nested modules**. Nested modules should exist under the `modules/`
+  subdirectory. Any nested module with a `README.md` is considered usable
+  by an external user. If a README doesn't exist, it is considered for internal
+  use only. These are purely advisory; Terraform will not actively deny usage
+  of internal modules. Nested modules should be used to split complex behavior
+  into multiple small modules that advanced users can carefully pick and
+  choose. For example, the
+  [Consul module](https://registry.terraform.io/modules/hashicorp/consul)
+  has a nested module for creating the Cluster that is separate from the
+  module to setup necessary IAM policies. This allows a user to bring in their
+  own IAM policy choices.
+
+  If the root module includes calls to nested modules, they should use relative
+  paths like `./modules/consul-cluster` so that Terraform will consider them
+  to be part of the same repository or package, rather than downloading them
+  again separately.
+
+  If a repository or package contains multiple nested modules, they should
+  ideally be [composable](/terraform/language/modules/develop/composition) by the caller, rather than
+  calling directly to each other and creating a deeply-nested tree of modules.
+
+* **Examples**. Examples of using the module should exist under the
+  `examples/` subdirectory at the root of the repository. Each example may have
+  a README to explain the goal and usage of the example. Examples for
+  submodules should also be placed in the root `examples/` directory.
+
+  Because examples will often be copied into other repositories for
+  customization, any `module` blocks should have their `source` set to the
+  address an external caller would use, not to a relative path.
+
+A minimal recommended module following the standard structure is shown below.
+While the root module is the only required element, we recommend the structure
+below as the minimum:
+
+```sh
+$ tree minimal-module/
+.
+├── README.md
+├── main.tf
+├── variables.tf
+├── outputs.tf
+```
+
+A complete example of a module following the standard structure is shown below.
+This example includes all optional elements and is therefore the most
+complex a module can become:
+
+```sh
+$ tree complete-module/
+.
+├── README.md
+├── main.tf
+├── variables.tf
+├── outputs.tf
+├── ...
+├── modules/
+│   ├── nestedA/
+│   │   ├── README.md
+│   │   ├── variables.tf
+│   │   ├── main.tf
+│   │   ├── outputs.tf
+│   ├── nestedB/
+│   ├── .../
+├── examples/
+│   ├── exampleA/
+│   │   ├── main.tf
+│   ├── exampleB/
+│   ├── .../
+```
diff --git a/v1.5.7/website/docs/language/modules/index.mdx b/v1.5.7/website/docs/language/modules/index.mdx
new file mode 100644
index 0000000..b52b42b
--- /dev/null
+++ b/v1.5.7/website/docs/language/modules/index.mdx
@@ -0,0 +1,70 @@
+---
+page_title: Modules Overview - Configuration Language
+description: >-
+  Modules are containers for multiple resources that are used together in a
+  configuration. Find resources for using, developing, and publishing modules.
+---
+
+# Modules
+
+> **Hands-on:** Try the [Reuse Configuration with Modules](/terraform/tutorials/modules?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorials.
+
+_Modules_ are containers for multiple resources that are used together. A module
+consists of a collection of `.tf` and/or `.tf.json` files kept together in a
+directory.
+
+Modules are the main way to package and reuse resource configurations with
+Terraform.
+
+## The Root Module
+
+Every Terraform configuration has at least one module, known as its
+_root module_, which consists of the resources defined in the `.tf` files in
+the main working directory.
+
+## Child Modules
+
+A Terraform module (usually the root module of a configuration) can _call_ other
+modules to include their resources into the configuration. A module that has
+been called by another module is often referred to as a _child module._
+
+Child modules can be called multiple times within the same configuration, and
+multiple configurations can use the same child module.
+
+## Published Modules
+
+In addition to modules from the local filesystem, Terraform can load modules
+from a public or private registry. This makes it possible to publish modules for
+others to use, and to use modules that others have published.
+
+The [Terraform Registry](https://registry.terraform.io/browse/modules) hosts a
+broad collection of publicly available Terraform modules for configuring many
+kinds of common infrastructure. These modules are free to use, and Terraform can
+download them automatically if you specify the appropriate source and version in
+a module call block.
+
+Also, members of your organization might produce modules specifically crafted
+for your own infrastructure needs. [Terraform Cloud](https://cloud.hashicorp.com/products/terraform) and
+[Terraform Enterprise](/terraform/enterprise) both include a private
+module registry for sharing modules internally within your organization.
+
+## Using Modules
+
+- [Module Blocks](/terraform/language/modules/syntax) documents the syntax for
+  calling a child module from a parent module, including meta-arguments like
+  `for_each`.
+
+- [Module Sources](/terraform/language/modules/sources) documents what kinds of paths,
+  addresses, and URIs can be used in the `source` argument of a module block.
+
+- The Meta-Arguments section documents special arguments that can be used with
+  every module, including
+  [`providers`](/terraform/language/meta-arguments/module-providers),
+  [`depends_on`](/terraform/language/meta-arguments/depends_on),
+  [`count`](/terraform/language/meta-arguments/count),
+  and [`for_each`](/terraform/language/meta-arguments/for_each).
+
+## Developing Modules
+
+For information about developing reusable modules, see
+[Module Development](/terraform/language/modules/develop).
diff --git a/v1.5.7/website/docs/language/modules/sources.mdx b/v1.5.7/website/docs/language/modules/sources.mdx
new file mode 100644
index 0000000..5159597
--- /dev/null
+++ b/v1.5.7/website/docs/language/modules/sources.mdx
@@ -0,0 +1,478 @@
+---
+page_title: Module Sources
+description: >-
+  The source argument tells Terraform where to find child modules's
+  configurations in locations like GitHub, the Terraform Registry, Bitbucket,
+  Git, Mercurial, S3, and GCS.
+---
+
+# Module Sources
+
+The `source` argument in [a `module` block](/terraform/language/modules/syntax)
+tells Terraform where to find the source code for the desired child module.
+
+Terraform uses this during the module installation step of `terraform init`
+to download the source code to a directory on local disk so that other Terraform commands can use it. 
+
+> **Hands-on:** Try the [Use Modules From the Registry](/terraform/tutorials/modules/module-use) or [Build and Use a Local Module](/terraform/tutorials/modules/module-create) tutorials.
+
+The module installer supports installation from a number of different source
+types.
+
+- [Local paths](#local-paths)
+
+- [Terraform Registry](#terraform-registry)
+
+- [GitHub](#github)
+
+- [Bitbucket](#bitbucket)
+
+- Generic [Git](#generic-git-repository), [Mercurial](#generic-mercurial-repository) repositories
+
+- [HTTP URLs](#http-urls)
+
+- [S3 buckets](#s3-bucket)
+
+- [GCS buckets](#gcs-bucket)
+
+- [Modules in Package Sub-directories](#modules-in-package-sub-directories)
+
+Each of these is described in the following sections. Module source addresses
+use a _URL-like_ syntax, but with extensions to support unambiguous selection
+of sources and additional features.
+
+We recommend using local file paths for closely-related modules used primarily
+for the purpose of factoring out repeated code elements, and using a native
+Terraform module registry for modules intended to be shared by multiple calling
+configurations. We support other sources so that you can potentially distribute
+Terraform modules internally with existing infrastructure.
+
+Many of the source types will make use of "ambient" credentials available
+when Terraform is run, such as from environment variables or credentials files
+in your home directory. This is covered in more detail in each of the following
+sections.
+
+We recommend placing each module that is intended to be re-usable in the root
+of its own repository or archive file, but it is also possible to
+[reference modules from subdirectories](#modules-in-package-sub-directories).
+
+## Local Paths
+
+Local path references allow for factoring out portions of a configuration
+within a single source repository.
+
+```hcl
+module "consul" {
+  source = "./consul"
+}
+```
+
+A local path must begin with either `./` or `../` to indicate that a local
+path is intended, to distinguish from
+[a module registry address](#terraform-registry).
+
+Local paths are special in that they are not "installed" in the same sense
+that other sources are: the files are already present on local disk (possibly
+as a result of installing a parent module) and so can just be used directly.
+Their source code is automatically updated if the parent module is upgraded.
+
+Note that Terraform does not consider an _absolute_ filesystem path (starting
+with a slash, a drive letter, or similar) to be a local path. Instead,
+Terraform will treat that in a similar way as a remote module and copy it into
+the local module cache. An absolute path is a "package" in the sense described
+in [Modules in Package Sub-directories](#modules-in-package-sub-directories).
+We don't recommend using absolute filesystem paths to refer to Terraform
+modules, because it will tend to couple your configuration to the filesystem
+layout of a particular computer.
+
+## Terraform Registry
+
+A module registry is the native way of distributing Terraform modules for use
+across multiple configurations, using a Terraform-specific protocol that
+has full support for module versioning.
+
+[Terraform Registry](https://registry.terraform.io/) is an index of modules
+shared publicly using this protocol. This public registry is the easiest way
+to get started with Terraform and find modules created by others in the
+community.
+
+You can also use a
+[private registry](/terraform/registry/private), either
+via the built-in feature from Terraform Cloud, or by running a custom
+service that implements
+[the module registry protocol](/terraform/registry/api-docs).
+
+Modules on the public Terraform Registry can be referenced using a registry
+source address of the form `<NAMESPACE>/<NAME>/<PROVIDER>`, with each
+module's information page on the registry site including the exact address
+to use.
+
+```hcl
+module "consul" {
+  source = "hashicorp/consul/aws"
+  version = "0.1.0"
+}
+```
+
+The above example will use the
+[Consul module for AWS](https://registry.terraform.io/modules/hashicorp/consul/aws)
+from the public registry.
+
+For modules hosted in other registries, prefix the source address with an
+additional `<HOSTNAME>/` portion, giving the hostname of the private registry:
+
+```hcl
+module "consul" {
+  source = "app.terraform.io/example-corp/k8s-cluster/azurerm"
+  version = "1.1.0"
+}
+```
+
+If you are using the SaaS version of Terraform Cloud, its private
+registry hostname is `app.terraform.io`. If you use a self-hosted Terraform
+Enterprise instance, its private registry hostname is the same as the host
+where you'd access the web UI and the host you'd use when configuring
+the [Terraform Cloud CLI integration](/terraform/cli/cloud).
+
+Registry modules support versioning. You can provide a specific version as shown
+in the above examples, or use flexible
+[version constraints](/terraform/language/modules/syntax#version).
+
+You can learn more about the registry at the
+[Terraform Registry documentation](/terraform/registry/modules/use#using-modules).
+
+To access modules from a private registry, you may need to configure an access
+token [in the CLI config](/terraform/cli/config/config-file#credentials). Use the
+same hostname as used in the module source string. For a private registry
+within Terraform Cloud, use the same authentication token as you would
+use with the Enterprise API or command-line clients.
+
+## GitHub
+
+Terraform will recognize unprefixed `github.com` URLs and interpret them
+automatically as Git repository sources.
+
+```hcl
+module "consul" {
+  source = "github.com/hashicorp/example"
+}
+```
+
+The above address scheme will clone over HTTPS. To clone over SSH, use the
+following form:
+
+```hcl
+module "consul" {
+  source = "git@github.com:hashicorp/example.git"
+}
+```
+
+These GitHub schemes are treated as convenient aliases for
+[the general Git repository address scheme](#generic-git-repository), and so
+they obtain credentials in the same way and support the `ref` argument for
+selecting a specific revision. You will need to configure credentials in
+particular to access private repositories.
+
+## Bitbucket
+
+Terraform will recognize unprefixed `bitbucket.org` URLs and interpret them
+automatically as BitBucket repositories:
+
+```hcl
+module "consul" {
+  source = "bitbucket.org/hashicorp/terraform-consul-aws"
+}
+```
+
+This shorthand works only for public repositories, because Terraform must
+access the BitBucket API to learn if the given repository uses Git or Mercurial.
+
+Terraform treats the result either as [a Git source](#generic-git-repository)
+or [a Mercurial source](#generic-mercurial-repository) depending on the
+repository type. See the sections on each version control type for information
+on how to configure credentials for private repositories and how to specify
+a specific revision to install.
+
+## Generic Git Repository
+
+Arbitrary Git repositories can be used by prefixing the address with the
+special `git::` prefix. After this prefix, any valid
+[Git URL](https://git-scm.com/docs/git-clone#_git_urls)
+can be specified to select one of the protocols supported by Git.
+
+For example, to use HTTPS or SSH:
+
+```hcl
+module "vpc" {
+  source = "git::https://example.com/vpc.git"
+}
+
+module "storage" {
+  source = "git::ssh://username@example.com/storage.git"
+}
+```
+
+Terraform installs modules from Git repositories by running `git clone`, and
+so it will respect any local Git configuration set on your system, including
+credentials. To access a non-public Git repository, configure Git with
+suitable credentials for that repository.
+
+If you use the SSH protocol then any configured SSH keys will be used
+automatically. This is the most common way to access non-public Git
+repositories from automated systems because it allows access to private
+repositories without interactive prompts.
+
+If using the HTTP/HTTPS protocol, or any other protocol that uses
+username/password credentials, configure
+[Git Credentials Storage](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage)
+to select a suitable source of credentials for your environment.
+
+If your Terraform configuration will be used within [Terraform Cloud](https://www.hashicorp.com/products/terraform),
+only SSH key authentication is supported, and
+[keys can be configured on a per-workspace basis](/terraform/cloud-docs/workspaces/settings/ssh-keys).
+
+### Selecting a Revision
+
+By default, Terraform will clone and use the default branch (referenced by
+`HEAD`) in the selected repository. You can override this using the
+`ref` argument. The value of the `ref` argument can be any reference that would be accepted
+by the `git checkout` command, such as branch, SHA-1 hash (short or full), or tag names.
+For a full list of the possible values, see
+[Git Tools - Revision Selection](https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection#_single_revisions)
+in [the Git Book](https://git-scm.com/book/en/v2).
+
+```hcl
+# select a specific tag
+module "vpc" {
+  source = "git::https://example.com/vpc.git?ref=v1.2.0"
+}
+
+# directly select a commit using its SHA-1 hash
+module "storage" {
+  source = "git::https://example.com/storage.git?ref=51d462976d84fdea54b47d80dcabbf680badcdb8"
+}
+```
+
+### Shallow Clone
+
+For larger repositories you may prefer to make only a shallow clone in order
+to reduce the time taken to retrieve the remote repository.
+
+The `depth` URL argument corresponds to
+[the `--depth` argument to `git clone`](https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---depthltdepthgt),
+telling Git to create a shallow clone with the history truncated to only
+the specified number of commits.
+
+However, because shallow clone requires different Git protocol behavior,
+setting the `depth` argument makes Terraform pass your [`ref` argument](#selecting-a-revision),
+if any, to
+[the `--branch` argument to `git clone`](https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---branchltnamegt)
+instead. That means it must specify a named branch or tag known to the remote
+repository, and that raw commit IDs are not acceptable.
+
+Because Terraform only uses the most recent selected commit to find the source
+code of your specified module, it is not typically useful to set `depth`
+to any value other than `1`.
+
+### "scp-like" address syntax
+
+When using Git over SSH, we recommend using the `ssh://`-prefixed URL form
+for consistency with all of the other URL-like git address forms.
+You may opt to use the alternative "scp-like" syntax instead, in which case you
+must omit the `ssh://` scheme part and include only the `git::` part.
+For example:
+
+```hcl
+module "storage" {
+  source = "git::username@example.com:storage.git"
+}
+```
+
+If you use the `ssh://` URL scheme then Terraform will assume that the colon
+marks the beginning of a port number, rather than the beginning of the path.
+This matches how Git itself interprets these different forms, aside from
+the Terraform-specific `git::` selector prefix.
+
+## Generic Mercurial Repository
+
+You can use arbitrary Mercurial repositories by prefixing the address with the
+special `hg::` prefix. After this prefix, any valid
+[Mercurial URL](https://www.mercurial-scm.org/repo/hg/help/urls)
+can be specified to select one of the protocols supported by Mercurial.
+
+```hcl
+module "vpc" {
+  source = "hg::http://example.com/vpc.hg"
+}
+```
+
+Terraform installs modules from Mercurial repositories by running `hg clone`, and
+so it will respect any local Mercurial configuration set on your system,
+including credentials. To access a non-public repository, configure Mercurial
+with suitable credentials for that repository.
+
+If you use the SSH protocol then any configured SSH keys will be used
+automatically. This is the most common way to access non-public Mercurial
+repositories from automated systems because it allows access to private
+repositories without interactive prompts.
+
+If your Terraform configuration will be used within [Terraform Cloud](https://www.hashicorp.com/products/terraform),
+only SSH key authentication is supported, and
+[keys can be configured on a per-workspace basis](/terraform/cloud-docs/workspaces/settings/ssh-keys).
+
+### Selecting a Revision
+
+You can select a non-default branch or tag using the optional `ref` argument:
+
+```hcl
+module "vpc" {
+  source = "hg::http://example.com/vpc.hg?ref=v1.2.0"
+}
+```
+
+## HTTP URLs
+
+When you use an HTTP or HTTPS URL, Terraform will make a `GET` request to
+the given URL, which can return _another_ source address. This indirection
+allows using HTTP URLs as a sort of "vanity redirect" over a more complicated
+module source address.
+
+Terraform will append an additional query string argument `terraform-get=1` to
+the given URL before sending the `GET` request, allowing the server to
+optionally return a different result when Terraform is requesting it.
+
+If the response is successful (`200`-range status code), Terraform looks in
+the following locations in order for the next address to access:
+
+- The value of a response header field named `X-Terraform-Get`.
+
+- If the response is an HTML page, a `meta` element with the name `terraform-get`:
+
+  ```html
+  <meta name="terraform-get" content="github.com/hashicorp/example" />
+  ```
+
+In either case, the result is interpreted as another module source address
+using one of the forms documented elsewhere on this page.
+
+If an HTTP/HTTPS URL requires authentication credentials, use a `.netrc`
+file to configure the credentials. By default, Terraform searches for the `.netrc` file 
+in your HOME directory. However, you can override the default filesystem location by setting the `NETRC` environment variable. For information on the `.netrc` format,
+refer to [the documentation for using it in `curl`](https://everything.curl.dev/usingcurl/netrc).
+
+### Fetching archives over HTTP
+
+As a special case, if Terraform detects that the URL has a common file
+extension associated with an archive file format then it will bypass the
+special `terraform-get=1` redirection described above and instead just use
+the contents of the referenced archive as the module source code:
+
+```hcl
+module "vpc" {
+  source = "https://example.com/vpc-module.zip"
+}
+```
+
+The extensions that Terraform recognizes for this special behavior are:
+
+- `zip`
+- `tar.bz2` and `tbz2`
+- `tar.gz` and `tgz`
+- `tar.xz` and `txz`
+
+If your URL _doesn't_ have one of these extensions but refers to an archive
+anyway, use the `archive` argument to force this interpretation:
+
+```hcl
+module "vpc" {
+  source = "https://example.com/vpc-module?archive=zip"
+}
+```
+
+-> **Note:** If the content of the archive file is a directory, you will need to
+include that directory in the module source. Read the section on
+[Modules in Package Sub-directories](#modules-in-package-sub-directories) for more
+information.
+
+## S3 Bucket
+
+You can use archives stored in S3 as module sources using the special `s3::`
+prefix, followed by
+[an S3 bucket object URL](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html).
+
+```hcl
+module "consul" {
+  source = "s3::https://s3-eu-west-1.amazonaws.com/examplecorp-terraform-modules/vpc.zip"
+}
+```
+
+-> **Note:** Buckets in AWS's us-east-1 region must use the hostname `s3.amazonaws.com` (instead of `s3-us-east-1.amazonaws.com`).
+
+The `s3::` prefix causes Terraform to use AWS-style authentication when
+accessing the given URL. As a result, this scheme may also work for other
+services that mimic the S3 API, as long as they handle authentication in the
+same way as AWS.
+
+The resulting object must be an archive with one of the same file
+extensions as for [archives over standard HTTP](#fetching-archives-over-http).
+Terraform will extract the archive to obtain the module source tree.
+
+The module installer looks for AWS credentials in the following locations,
+preferring those earlier in the list when multiple are available:
+
+- The `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables.
+- The default profile in the `.aws/credentials` file in your home directory.
+- If running on an EC2 instance, temporary credentials associated with the
+  instance's IAM Instance Profile.
+
+## GCS Bucket
+
+You can use archives stored in Google Cloud Storage as module sources using the special `gcs::`
+prefix, followed by
+[a GCS bucket object URL](https://cloud.google.com/storage/docs/request-endpoints#typical).
+
+For example
+
+- `gcs::https://www.googleapis.com/storage/v1/BUCKET_NAME/PATH_TO_MODULE`
+- `gcs::https://www.googleapis.com/storage/v1/BUCKET_NAME/PATH/TO/module.zip`
+
+```hcl
+module "consul" {
+  source = "gcs::https://www.googleapis.com/storage/v1/modules/foomodule.zip"
+}
+```
+
+The module installer uses Google Cloud SDK to authenticate with GCS. You can
+use any of the following methods to set Google Cloud Platform credentials:
+
+* Set the `GOOGLE_OAUTH_ACCESS_TOKEN` environment variable to a raw Google Cloud Platform OAuth access token.
+* Enter the path of your service account key file in the `GOOGLE_APPLICATION_CREDENTIALS` environment variable.
+* If you're running Terraform from a GCE instance, default credentials are automatically available. See [Creating and Enabling Service Accounts](https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances) for Instances for more details.
+* On your computer, you can make your Google identity available by running `gcloud auth application-default login`.
+
+## Modules in Package Sub-directories
+
+When the source of a module is a version control repository or archive file
+(generically, a "package"), the module itself may be in a sub-directory relative
+to the root of the package.
+
+A special double-slash syntax is interpreted by Terraform to indicate that
+the remaining path after that point is a sub-directory within the package.
+For example:
+
+- `hashicorp/consul/aws//modules/consul-cluster`
+- `git::https://example.com/network.git//modules/vpc`
+- `https://example.com/network-module.zip//modules/vpc`
+- `s3::https://s3-eu-west-1.amazonaws.com/examplecorp-terraform-modules/network.zip//modules/vpc`
+
+If the source address has arguments, such as the `ref` argument supported for
+the version control sources, the sub-directory portion must be _before_ those
+arguments:
+
+- `git::https://example.com/network.git//modules/vpc?ref=v1.2.0`
+- `github.com/hashicorp/example//modules/vpc?ref=v1.2.0`
+
+Terraform will still extract the entire package to local disk, but will read
+the module from the subdirectory. As a result, it is safe for a module in
+a sub-directory of a package to use [a local path](#local-paths) to another
+module as long as it is in the _same_ package.
diff --git a/v1.5.7/website/docs/language/modules/syntax.mdx b/v1.5.7/website/docs/language/modules/syntax.mdx
new file mode 100644
index 0000000..198d523
--- /dev/null
+++ b/v1.5.7/website/docs/language/modules/syntax.mdx
@@ -0,0 +1,195 @@
+---
+page_title: Modules - Configuration Language
+description: >-
+  Modules are containers for multiple resources that are used together in
+  configurations. Learn how to call one module from another and access module
+  output.
+---
+
+# Module Blocks
+
+> **Hands-on:** Try the [Reuse Configuration with Modules](/terraform/tutorials/modules?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorials.
+
+A _module_ is a container for multiple resources that are used together.
+
+Every Terraform configuration has at least one module, known as its
+_root module_, which consists of the resources defined in the `.tf` files in
+the main working directory.
+
+A module can call other modules, which lets you include the child module's
+resources into the configuration in a concise way. Modules
+can also be called multiple times, either within the same configuration or
+in separate configurations, allowing resource configurations to be packaged
+and re-used.
+
+This page describes how to call one module from another. For more information
+about creating re-usable child modules, see [Module Development](/terraform/language/modules/develop).
+
+## Calling a Child Module
+
+To _call_ a module means to include the contents of that module into the
+configuration with specific values for its
+[input variables](/terraform/language/values/variables). Modules are called
+from within other modules using `module` blocks:
+
+```hcl
+module "servers" {
+  source = "./app-cluster"
+
+  servers = 5
+}
+```
+
+A module that includes a `module` block like this is the _calling module_ of the
+child module.
+
+The label immediately after the `module` keyword is a local name, which the
+calling module can use to refer to this instance of the module.
+
+Within the block body (between `{` and `}`) are the arguments for the module.
+Module calls use the following kinds of arguments:
+
+- The `source` argument is mandatory for all modules.
+
+- The `version` argument is recommended for modules from a registry.
+
+- Most other arguments correspond to [input variables](/terraform/language/values/variables)
+  defined by the module. (The `servers` argument in the example above is one of
+  these.)
+
+- Terraform defines a few other meta-arguments that can be used with all
+  modules, including `for_each` and `depends_on`.
+
+### Source
+
+All modules **require** a `source` argument, which is a meta-argument defined by
+Terraform. Its value is either the path to a local directory containing the
+module's configuration files, or a remote module source that Terraform should
+download and use. This value must be a literal string with no template
+sequences; arbitrary expressions are not allowed. For more information on
+possible values for this argument, see [Module Sources](/terraform/language/modules/sources).
+
+The same source address can be specified in multiple `module` blocks to create
+multiple copies of the resources defined within, possibly with different
+variable values.
+
+After adding, removing, or modifying `module` blocks, you must re-run
+`terraform init` to allow Terraform the opportunity to adjust the installed
+modules. By default this command will not upgrade an already-installed module;
+use the `-upgrade` option to instead upgrade to the newest available version.
+
+### Version
+
+When using modules installed from a module registry, we recommend explicitly
+constraining the acceptable version numbers to avoid unexpected or unwanted
+changes.
+
+Use the `version` argument in the `module` block to specify versions:
+
+```shell
+module "consul" {
+  source  = "hashicorp/consul/aws"
+  version = "0.0.5"
+
+  servers = 3
+}
+```
+
+The `version` argument accepts a [version constraint string](/terraform/language/expressions/version-constraints).
+Terraform will use the newest installed version of the module that meets the
+constraint; if no acceptable versions are installed, it will download the newest
+version that meets the constraint.
+
+Version constraints are supported only for modules installed from a module
+registry, such as the public [Terraform Registry](https://registry.terraform.io/)
+or [Terraform Cloud's private module registry](/terraform/cloud-docs/registry).
+Other module sources can provide their own versioning mechanisms within the
+source string itself, or might not support versions at all. In particular,
+modules sourced from local file paths do not support `version`; since
+they're loaded from the same source repository, they always share the same
+version as their caller.
+
+### Meta-arguments
+
+Along with `source` and `version`, Terraform defines a few more
+optional meta-arguments that have special meaning across all modules,
+described in more detail in the following pages:
+
+- `count` - Creates multiple instances of a module from a single `module` block.
+  See [the `count` page](/terraform/language/meta-arguments/count)
+  for details.
+
+- `for_each` - Creates multiple instances of a module from a single `module`
+  block. See
+  [the `for_each` page](/terraform/language/meta-arguments/for_each)
+  for details.
+
+- `providers` - Passes provider configurations to a child module. See
+  [the `providers` page](/terraform/language/meta-arguments/module-providers)
+  for details. If not specified, the child module inherits all of the default
+  (un-aliased) provider configurations from the calling module.
+
+- `depends_on` - Creates explicit dependencies between the entire
+  module and the listed targets. See
+  [the `depends_on` page](/terraform/language/meta-arguments/depends_on)
+  for details.
+
+Terraform does not use the `lifecycle` argument. However, the `lifecycle` block is reserved for future versions.
+
+## Accessing Module Output Values
+
+The resources defined in a module are encapsulated, so the calling module
+cannot access their attributes directly. However, the child module can
+declare [output values](/terraform/language/values/outputs) to selectively
+export certain values to be accessed by the calling module.
+
+For example, if the `./app-cluster` module referenced in the example above
+exported an output value named `instance_ids` then the calling module
+can reference that result using the expression `module.servers.instance_ids`:
+
+```hcl
+resource "aws_elb" "example" {
+  # ...
+
+  instances = module.servers.instance_ids
+}
+```
+
+For more information about referring to named values, see
+[Expressions](/terraform/language/expressions).
+
+## Transferring Resource State Into Modules
+
+Moving `resource` blocks from one module into several child modules causes
+Terraform to see the new location as an entirely different resource. As a
+result, Terraform plans to destroy all resource instances at the old address
+and create new instances at the new address.
+
+To preserve existing objects, you can use
+[refactoring blocks](/terraform/language/modules/develop/refactoring) to record the old and new
+addresses for each resource instance. This directs Terraform to treat existing
+objects at the old addresses as if they had originally been created at the
+corresponding new addresses.
+
+## Replacing resources within a module
+
+You may have an object that needs to be replaced with a new object for a reason
+that isn't automatically visible to Terraform, such as if a particular virtual
+machine is running on degraded underlying hardware. In this case, you can use
+[the `-replace=...` planning option](/terraform/cli/commands/plan#replace-address)
+to force Terraform to propose replacing that object.
+
+If the object belongs to a resource within a nested module, specify the full
+path to that resource including all of the nested module steps leading to it.
+For example:
+
+```shellsession
+$ terraform plan -replace=module.example.aws_instance.example
+```
+
+The above selects a `resource "aws_instance" "example"` declared inside a
+`module "example"` child module declared inside your root module.
+
+Because replacing is a very disruptive action, Terraform only allows selecting
+individual resource instances. There is no syntax to force replacing _all_
+resource instances belonging to a particular module.
diff --git a/v1.5.7/website/docs/language/modules/testing-experiment.mdx b/v1.5.7/website/docs/language/modules/testing-experiment.mdx
new file mode 100644
index 0000000..25c95c3
--- /dev/null
+++ b/v1.5.7/website/docs/language/modules/testing-experiment.mdx
@@ -0,0 +1,311 @@
+---
+page_title: Module Testing Experiment - Configuration Language
+description: Part of the ongoing design research for module integration testing.
+---
+
+# Module Testing Experiment
+
+This page is about some experimental features available in recent versions of
+Terraform CLI related to integration testing of shared modules.
+
+The Terraform team is aiming to use these features to gather feedback as part
+of ongoing research into different strategies for testing Terraform modules.
+These features are likely to change significantly in future releases based on
+feedback.
+
+## Current Research Goals
+
+Our initial area of research is into the question of whether it's helpful and
+productive to write module integration tests in the Terraform language itself,
+or whether it's better to handle that as a separate concern orchestrated by
+code written in other languages.
+
+Some existing efforts have piloted both approaches:
+
+* [Terratest](https://terratest.gruntwork.io/) and
+[kitchen-terraform](https://github.com/newcontext-oss/kitchen-terraform)
+both pioneered the idea of writing tests for Terraform modules with explicit
+orchestration written in the Go and Ruby programming languages, respectively.
+
+* The Terraform provider
+[`apparentlymart/testing`](https://registry.terraform.io/providers/apparentlymart/testing/latest)
+introduced the idea of writing Terraform module tests in the Terraform
+language itself, using a special provider that can evaluate assertions
+and fail `terraform apply` if they don't pass.
+
+Both of these approaches have both advantages and disadvantages, and so it's
+likely that both will coexist for different situations, but the community
+efforts have already explored the external-language testing model quite deeply
+while the Terraform-integrated testing model has not yet been widely trialled.
+For that reason, the current iteration of the module testing experiment is
+aimed at trying to make the Terraform-integrated approach more accessible so
+that more module authors can hopefully try it and share their experiences.
+
+## Current Experimental Features
+
+-> This page describes the incarnation of the experimental features introduced
+in **Terraform CLI v0.15.0**. If you are using an earlier version of Terraform
+then you'll need to upgrade to v0.15.0 or later to use the experimental features
+described here, though you only need to use v0.15.0 or later for running tests;
+your module itself can remain compatible with earlier Terraform versions, if
+needed.
+
+Our current area of interest is in what sorts of tests can and cannot be
+written using features integrated into the Terraform language itself. As a
+means to investigate that without invasive, cross-cutting changes to Terraform
+Core we're using a special built-in Terraform provider as a placeholder for
+potential new features.
+
+If this experiment is successful then we expect to run a second round of
+research and design about exactly what syntax is most ergonomic for writing
+tests, but for the moment we're interested less in the specific syntax and more
+in the capabilities of this approach.
+
+The temporary extensions to Terraform for this experiment consist of the
+following parts:
+
+* A temporary experimental provider `terraform.io/builtin/test`, which acts as
+a placeholder for potential new language features related to test assertions.
+
+* A `terraform test` command for more conveniently running multiple tests in
+a single action.
+
+* An experimental convention of placing test configurations in subdirectories
+of a `tests` directory within your module, which `terraform test` will then
+discover and run.
+
+We would like to invite adventurous module authors to try writing integration
+tests for their modules using these mechanisms, and ideally also share the
+tests you write (in a temporary VCS branch, if necessary) so we can see what
+you were able to test, along with anything you felt unable to test in this way.
+
+If you're interested in giving this a try, see the following sections for
+usage details. Because these features are temporary experimental extensions,
+there's some boilerplate required to activate and make use of it which would
+likely not be required in a final design.
+
+### Writing Tests for a Module
+
+For the purposes of the current experiment, module tests are arranged into
+_test suites_, each of which is a root Terraform module which includes a
+`module` block calling the module under test, and ideally also a number of
+test assertions to verify that the module outputs match expectations.
+
+In the same directory where you keep your module's `.tf` and/or `.tf.json`
+source files, create a subdirectory called `tests`. Under that directory,
+make another directory which will serve as your first test suite, with a
+directory name that concisely describes what the suite is aiming to test.
+
+Here's an example directory structure of a typical module directory layout
+with the addition of a test suite called `defaults`:
+
+```
+main.tf
+outputs.tf
+providers.tf
+variables.tf
+versions.tf
+tests/
+  defaults/
+    test_defaults.tf
+```
+
+The `tests/defaults/test_defaults.tf` file will contain a call to the
+main module with a suitable set of arguments and hopefully also one or more
+resources that will, for the sake of the experiment, serve as the temporary
+syntax for defining test assertions. For example:
+
+```hcl
+terraform {
+  required_providers {
+    # Because we're currently using a built-in provider as
+    # a substitute for dedicated Terraform language syntax
+    # for now, test suite modules must always declare a
+    # dependency on this provider. This provider is only
+    # available when running tests, so you shouldn't use it
+    # in non-test modules.
+    test = {
+      source = "terraform.io/builtin/test"
+    }
+    # This example also uses the "http" data source to
+    # verify the behavior of the hypothetical running
+    # service, so we should declare that too.
+    http = {
+      source = "hashicorp/http"
+    }
+  }
+}
+module "main" {
+  # source is always ../.. for test suite configurations,
+  # because they are placed two subdirectories deep under
+  # the main module directory.
+  source = "../.."
+  # This test suite is aiming to test the "defaults" for
+  # this module, so it doesn't set any input variables
+  # and just lets their default values be selected instead.
+}
+# As with all Terraform modules, we can use local values
+# to do any necessary post-processing of the results from
+# the module in preparation for writing test assertions.
+locals {
+  # This expression also serves as an implicit assertion
+  # that the base URL uses URL syntax; the test suite
+  # will fail if this function fails.
+  api_url_parts = regex(
+    "^(?:(?P<scheme>[^:/?#]+):)?(?://(?P<authority>[^/?#]*))?",
+    module.main.api_url,
+  )
+}
+# The special test_assertions resource type, which belongs
+# to the test provider we required above, is a temporary
+# syntax for writing out explicit test assertions.
+resource "test_assertions" "api_url" {
+  # "component" serves as a unique identifier for this
+  # particular set of assertions in the test results.
+  component = "api_url"
+  # equal and check blocks serve as the test assertions.
+  # the labels on these blocks are unique identifiers for
+  # the assertions, to allow more easily tracking changes
+  # in success between runs.
+  equal "scheme" {
+    description = "default scheme is https"
+    got         = local.api_url_parts.scheme
+    want        = "https"
+  }
+  check "port_number" {
+    description = "default port number is 8080"
+    condition   = can(regex(":8080$", local.api_url_parts.authority))
+  }
+}
+# We can also use data resources to respond to the
+# behavior of the real remote system, rather than
+# just to values within the Terraform configuration.
+data "http" "api_response" {
+  depends_on = [
+    # make sure the syntax assertions run first, so
+    # we'll be sure to see if it was URL syntax errors
+    # that let to this data resource also failing.
+    test_assertions.api_url,
+  ]
+  url = module.main.api_url
+}
+resource "test_assertions" "api_response" {
+  component = "api_response"
+  check "valid_json" {
+    description = "base URL responds with valid JSON"
+    condition   = can(jsondecode(data.http.api_response.body))
+  }
+}
+```
+
+If you like, you can create additional directories alongside
+the `default` directory to define additional test suites that
+pass different variable values into the main module, and
+then include assertions that verify that the result has changed
+in the expected way.
+
+### Running Your Tests
+
+The `terraform test` command aims to make it easier to exercise all of your
+defined test suites at once, and see only the output related to any test
+failures or errors.
+
+The current experimental incarnation of this command expects to be run from
+your main module directory. In our example directory structure above,
+that was the directory containing `main.tf` etc, and _not_ the specific test
+suite directory containing `test_defaults.tf`.
+
+Because these test suites are integration tests rather than unit tests, you'll
+need to set up any credentials files or environment variables needed by the
+providers your module uses before running `terraform test`. The test command
+will, for each suite:
+
+* Install the providers and any external modules the test configuration depends
+on.
+* Create an execution plan to create the objects declared in the module.
+* Apply that execution plan to create the objects in the real remote system.
+* Collect all of the test results from the apply step, which would also have
+"created" the `test_assertions` resources.
+* Destroy all of the objects recorded in the temporary test state, as if running
+`terraform destroy` against the test configuration.
+
+```shellsession
+$ terraform test
+─── Failed: defaults.api_url.scheme (default scheme is https) ───────────────
+wrong value
+    got:  "http"
+    want: "https"
+─────────────────────────────────────────────────────────────────────────────
+```
+
+In this case, it seems like the module returned an `http` rather than an
+`https` URL in the default case, and so the `defaults.api_url.scheme`
+assertion failed, and the `terraform test` command detected and reported it.
+
+The `test_assertions` resource captures any assertion failures but does not
+return an error, because that can then potentially allow downstream
+assertions to also run and thus capture as much context as possible.
+However, if Terraform encounters any _errors_ while processing the test
+configuration it will halt processing, which may cause some of the test
+assertions to be skipped.
+
+## Known Limitations
+
+The design above is very much a prototype aimed at gathering more experience
+with the possibilities of testing inside the Terraform language. We know it's
+currently somewhat non-ergonomic, and hope to improve on that in later phases
+of research and design, but the main focus of this iteration is on available
+functionality and so with that in mind there are some specific possibilities
+that we know the current prototype doesn't support well:
+
+* Testing of subsequent updates to an existing deployment of a module.
+Tests written in this way can only exercise the create and destroy
+behaviors.
+
+* Assertions about expected errors. For a module that includes variable
+validation rules and data resources that function as assertion checks,
+the current prototype doesn't have any way to express that a particular
+set of inputs is _expected_ to produce an error, and thus report a test
+failure if it doesn't. We'll hopefully be able to improve on this in a future
+iteration with the test assertions better integrated into the language.
+
+* Capturing context about failures. Due to this prototype using a provider as
+an approximation for new assertion syntax, the `terraform test` command is
+limited in how much context it's able to gather about failures. A design
+more integrated into the language could potentially capture the source
+expressions and input values to give better feedback about what went wrong,
+similar to what Terraform typically returns from expression evaluation errors
+in the main language.
+
+* Unit testing without creating real objects. Although we do hope to spend more
+time researching possibilities for unit testing against fake test doubles in
+the future, we've decided to focus on integration testing to start because
+it feels like the better-defined problem.
+
+## Sending Feedback
+
+The sort of feedback we'd most like to see at this stage of the experiment is
+to see the source code of any tests you've written against real modules using
+the features described above, along with notes about anything that you
+attempted to test but were blocked from doing so by limitations of the above
+features. The most ideal way to share that would be to share a link to a
+version control branch where you've added such tests, if your module is open
+source.
+
+If you've previously written or attempted to write tests in an external
+language, using a system like Terratest or kitchen-terraform, we'd also be
+interested to hear about comparative differences between the two: what worked
+well in each and what didn't work so well.
+
+Our ultimate goal is to work towards an integration testing methodology which
+strikes the best compromise between the capabilities of these different
+approaches, ideally avoiding a hard requirement on any particular external
+language and fitting well into the Terraform workflow.
+
+Since this is still early work and likely to lead to unstructured discussion,
+we'd like to gather feedback primarily via new topics in
+[the community forum](https://discuss.hashicorp.com/c/terraform-core/27). That
+way we can have some more freedom to explore different ideas and approaches
+without the structural requirements we typically impose on GitHub issues.
+
+Any feedback you'd like to share would be very welcome!
\ No newline at end of file
diff --git a/v1.5.7/website/docs/language/providers/configuration.mdx b/v1.5.7/website/docs/language/providers/configuration.mdx
new file mode 100644
index 0000000..f3cce65
--- /dev/null
+++ b/v1.5.7/website/docs/language/providers/configuration.mdx
@@ -0,0 +1,198 @@
+---
+page_title: Provider Configuration - Configuration Language
+description: >-
+  Learn how to set up providers, including how to use the alias meta-argument to
+  specify multiple configurations for a single provider.
+---
+
+# Provider Configuration
+
+Providers allow Terraform to interact with cloud providers, SaaS providers, and
+other APIs.
+
+Some providers require you to configure them with endpoint URLs, cloud regions,
+or other settings before Terraform can use them. This page documents how to
+configure settings for providers.
+
+Additionally, all Terraform configurations must declare which providers they
+require so that Terraform can install and use them. The
+[Provider Requirements](/terraform/language/providers/requirements)
+page documents how to declare providers so Terraform can install them.
+
+## Provider Configuration
+
+Provider configurations belong in the root module of a Terraform configuration.
+(Child modules receive their provider configurations from the root module; for
+more information, see
+[The Module `providers` Meta-Argument](/terraform/language/meta-arguments/module-providers)
+and [Module Development: Providers Within Modules](/terraform/language/modules/develop/providers).)
+
+A provider configuration is created using a `provider` block:
+
+```hcl
+provider "google" {
+  project = "acme-app"
+  region  = "us-central1"
+}
+```
+
+The name given in the block header (`"google"` in this example) is the
+[local name](/terraform/language/providers/requirements#local-names) of the provider to
+configure. This provider should already be included in a `required_providers`
+block.
+
+The body of the block (between `{` and `}`) contains configuration arguments for
+the provider. Most arguments in this section are defined by the provider itself;
+in this example both `project` and `region` are specific to the `google`
+provider.
+
+You can use [expressions](/terraform/language/expressions) in the values of these
+configuration arguments, but can only reference values that are known before the
+configuration is applied. This means you can safely reference input variables,
+but not attributes exported by resources (with an exception for resource
+arguments that are specified directly in the configuration).
+
+A provider's documentation should list which configuration arguments it expects.
+For providers distributed on the
+[Terraform Registry](https://registry.terraform.io), versioned documentation is
+available on each provider's page, via the "Documentation" link in the
+provider's header.
+
+Some providers can use shell environment variables (or other alternate sources,
+like VM instance profiles) as values for some of their arguments; when
+available, we recommend using this as a way to keep credentials out of your
+version-controlled Terraform code.
+
+There are also two "meta-arguments" that are defined by Terraform itself
+and available for all `provider` blocks:
+
+- [`alias`, for using the same provider with different configurations for different resources][inpage-alias]
+- [`version`, which we no longer recommend][inpage-versions] (use
+  [provider requirements](/terraform/language/providers/requirements) instead)
+
+Unlike many other objects in the Terraform language, a `provider` block may
+be omitted if its contents would otherwise be empty. Terraform assumes an
+empty default configuration for any provider that is not explicitly configured.
+
+## `alias`: Multiple Provider Configurations
+
+[inpage-alias]: #alias-multiple-provider-configurations
+
+You can optionally define multiple configurations for the same provider, and
+select which one to use on a per-resource or per-module basis. The primary
+reason for this is to support multiple regions for a cloud platform; other
+examples include targeting multiple Docker hosts, multiple Consul hosts, etc.
+
+To create multiple configurations for a given provider, include multiple
+`provider` blocks with the same provider name. For each additional non-default
+configuration, use the `alias` meta-argument to provide an extra name segment.
+For example:
+
+```hcl
+# The default provider configuration; resources that begin with `aws_` will use
+# it as the default, and it can be referenced as `aws`.
+provider "aws" {
+  region = "us-east-1"
+}
+
+# Additional provider configuration for west coast region; resources can
+# reference this as `aws.west`.
+provider "aws" {
+  alias  = "west"
+  region = "us-west-2"
+}
+```
+
+To declare a configuration alias within a module in order to receive an
+alternate provider configuration from the parent module, add the
+`configuration_aliases` argument to that provider's `required_providers`
+entry. The following example declares both the `mycloud` and
+`mycloud.alternate` provider configuration names within the containing module:
+
+```hcl
+terraform {
+  required_providers {
+    mycloud = {
+      source  = "mycorp/mycloud"
+      version = "~> 1.0"
+      configuration_aliases = [ mycloud.alternate ]
+    }
+  }
+}
+```
+
+### Default Provider Configurations
+
+A `provider` block without an `alias` argument is the _default_ configuration
+for that provider. Resources that don't set the `provider` meta-argument will
+use the default provider configuration that matches the first word of the
+resource type name. (For example, an `aws_instance` resource uses the default
+`aws` provider configuration unless otherwise stated.)
+
+If every explicit configuration of a provider has an alias, Terraform uses the
+implied empty configuration as that provider's default configuration. (If the
+provider has any required configuration arguments, Terraform will raise an error
+when resources default to the empty configuration.)
+
+### Referring to Alternate Provider Configurations
+
+When Terraform needs the name of a provider configuration, it expects a
+reference of the form `<PROVIDER NAME>.<ALIAS>`. In the example above,
+`aws.west` would refer to the provider with the `us-west-2` region.
+
+These references are special expressions. Like references to other named
+entities (for example, `var.image_id`), they aren't strings and don't need to be
+quoted. But they are only valid in specific meta-arguments of `resource`,
+`data`, and `module` blocks, and can't be used in arbitrary expressions.
+
+### Selecting Alternate Provider Configurations
+
+By default, resources use a default provider configuration (one without an
+`alias` argument) inferred from the first word of the resource type name.
+
+To use an alternate provider configuration for a resource or data source, set
+its `provider` meta-argument to a `<PROVIDER NAME>.<ALIAS>` reference:
+
+```hcl
+resource "aws_instance" "foo" {
+  provider = aws.west
+
+  # ...
+}
+```
+
+To select alternate provider configurations for a child module, use its
+`providers` meta-argument to specify which provider configurations should be
+mapped to which local provider names inside the module:
+
+```hcl
+module "aws_vpc" {
+  source = "./aws_vpc"
+  providers = {
+    aws = aws.west
+  }
+}
+```
+
+Modules have some special requirements when passing in providers; see
+[The Module `providers` Meta-Argument](/terraform/language/meta-arguments/module-providers)
+for more details. In most cases, only _root modules_ should define provider
+configurations, with all child modules obtaining their provider configurations
+from their parents.
+
+<a id="provider-versions"></a>
+
+## `version` (Deprecated)
+
+[inpage-versions]: #provider-versions
+
+The `version` meta-argument specifies a version constraint for a provider, and
+works the same way as the `version` argument in a
+[`required_providers` block](/terraform/language/providers/requirements). The version
+constraint in a provider configuration is only used if `required_providers`
+does not include one for that provider.
+
+~**Warning:** The `version` argument in provider configurations is deprecated, and we will remove it in a future Terraform version.
+
+In Terraform 0.13 and later, always declare provider version constraints in
+[the `required_providers` block](/terraform/language/providers/requirements). 
diff --git a/v1.5.7/website/docs/language/providers/index.mdx b/v1.5.7/website/docs/language/providers/index.mdx
new file mode 100644
index 0000000..e5970cf
--- /dev/null
+++ b/v1.5.7/website/docs/language/providers/index.mdx
@@ -0,0 +1,115 @@
+---
+page_title: Providers - Configuration Language
+description: >-
+  An overview of how to install and use providers, Terraform plugins that
+  interact with services, cloud providers, and other APIs.
+---
+
+# Providers
+
+> **Hands-on:** Try the [Perform CRUD Operations with Providers](/terraform/tutorials/configuration-language/provider-use?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+Terraform relies on plugins called providers to interact with cloud providers,
+SaaS providers, and other APIs.
+
+Terraform configurations must declare which providers they require so that
+Terraform can install and use them. Additionally, some providers require
+configuration (like endpoint URLs or cloud regions) before they can be used.
+
+## What Providers Do
+
+Each provider adds a set of [resource types](/terraform/language/resources)
+and/or [data sources](/terraform/language/data-sources) that Terraform can
+manage.
+
+Every resource type is implemented by a provider; without providers, Terraform
+can't manage any kind of infrastructure.
+
+Most providers configure a specific infrastructure platform (either cloud or
+self-hosted). Providers can also offer local utilities for tasks like
+generating random numbers for unique resource names.
+
+## Where Providers Come From
+
+Providers are distributed separately from Terraform itself, and each provider
+has its own release cadence and version numbers.
+
+The [Terraform Registry](https://registry.terraform.io/browse/providers)
+is the main directory of publicly available Terraform providers, and hosts
+providers for most major infrastructure platforms.
+
+## Provider Documentation
+
+Each provider has its own documentation, describing its resource
+types and their arguments.
+
+The [Terraform Registry](https://registry.terraform.io/browse/providers)
+includes documentation for a wide range of providers developed by HashiCorp, third-party vendors, and our Terraform community. Use the
+"Documentation" link in a provider's header to browse its documentation.
+
+Provider documentation in the Registry is versioned; you can use the version
+menu in the header to change which version you're viewing.
+
+For details about writing, generating, and previewing provider documentation,
+see the [provider publishing documentation](/terraform/registry/providers/docs).
+
+## How to Use Providers
+
+Providers are released separately from Terraform itself and have their own version numbers. In production we recommend constraining the acceptable provider versions in the configuration's provider requirements block, to make sure that `terraform init` does not install newer versions of the provider that are incompatible with the configuration.
+
+To use resources from a given provider, you need to include some information
+about it in your configuration. See the following pages for details:
+
+- [Provider Requirements](/terraform/language/providers/requirements)
+  documents how to declare providers so Terraform can install them.
+
+- [Provider Configuration](/terraform/language/providers/configuration)
+  documents how to configure settings for providers.
+
+- [Dependency Lock File](/terraform/language/files/dependency-lock)
+  documents an additional HCL file that can be included with a configuration,
+  which tells Terraform to always use a specific set of provider versions.
+
+## Provider Installation
+
+- Terraform Cloud and Terraform Enterprise install providers as part of every run.
+
+- Terraform CLI finds and installs providers when
+  [initializing a working directory](/terraform/cli/init). It can
+  automatically download providers from a Terraform registry, or load them from
+  a local mirror or cache. If you are using a persistent working directory, you
+  must reinitialize whenever you change a configuration's providers.
+
+  To save time and bandwidth, Terraform CLI supports an optional plugin
+  cache. You can enable the cache using the `plugin_cache_dir` setting in
+  [the CLI configuration file](/terraform/cli/config/config-file).
+
+To ensure Terraform always installs the same provider versions for a given
+configuration, you can use Terraform CLI to create a
+[dependency lock file](/terraform/language/files/dependency-lock)
+and commit it to version control along with your configuration. If a lock file
+is present, Terraform Cloud, CLI, and Enterprise will all obey it when
+installing providers.
+
+> **Hands-on:** Try the [Lock and Upgrade Provider Versions](/terraform/tutorials/configuration-language/provider-versioning?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+## How to Find Providers
+
+To find providers for the infrastructure platforms you use, browse
+[the providers section of the Terraform Registry](https://registry.terraform.io/browse/providers).
+
+Some providers on the Registry are developed and published by HashiCorp, some
+are published by platform maintainers, and some are published by users and
+volunteers. The provider listings use the following badges to indicate who
+develops and maintains a given provider.
+
+<ProviderTable />
+<p></p>
+
+## How to Develop Providers
+
+Providers are written in Go, using the Terraform Plugin SDK. For more
+information on developing providers, see:
+
+- The [Plugin Development](/terraform/plugin) documentation
+- The [Call APIs with Terraform Providers](/terraform/tutorials/providers-plugin-framework?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorials
diff --git a/v1.5.7/website/docs/language/providers/requirements.mdx b/v1.5.7/website/docs/language/providers/requirements.mdx
new file mode 100644
index 0000000..5d51e6e
--- /dev/null
+++ b/v1.5.7/website/docs/language/providers/requirements.mdx
@@ -0,0 +1,426 @@
+---
+page_title: Provider Requirements - Configuration Language
+description: >-
+  Providers are plugins that allow Terraform to interact with services, cloud
+  providers, and other APIs. Learn how to declare providers in a configuration.
+---
+
+# Provider Requirements
+
+Terraform relies on plugins called "providers" to interact with remote systems.
+Terraform configurations must declare which providers they require, so that
+Terraform can install and use them. This page documents how to declare providers
+so Terraform can install them.
+
+> **Hands-on:** Try the [Perform CRUD Operations with Providers](/terraform/tutorials/providers/provider-use) tutorial.
+
+Additionally, some providers require configuration (like endpoint URLs or cloud
+regions) before they can be used. The [Provider
+Configuration](/terraform/language/providers/configuration) page documents how
+to configure settings for providers.
+
+-> **Note:** This page is about a feature of Terraform 0.13 and later; it also
+describes how to use the more limited version of that feature that was available
+in Terraform 0.12.
+
+## Requiring Providers
+
+Each Terraform module must declare which providers it requires, so that
+Terraform can install and use them. Provider requirements are declared in a
+`required_providers` block.
+
+A provider requirement consists of a local name, a source location, and a
+version constraint:
+
+```hcl
+terraform {
+  required_providers {
+    mycloud = {
+      source  = "mycorp/mycloud"
+      version = "~> 1.0"
+    }
+  }
+}
+```
+
+The `required_providers` block must be nested inside the top-level
+[`terraform` block](/terraform/language/settings) (which can also contain other settings).
+
+Each argument in the `required_providers` block enables one provider. The key
+determines the provider's [local name](#local-names) (its unique identifier
+within this module), and the value is an object with the following elements:
+
+* `source` - the global [source address](#source-addresses) for the
+  provider you intend to use, such as `hashicorp/aws`.
+
+* `version` - a [version constraint](#version-constraints) specifying
+  which subset of available provider versions the module is compatible with.
+
+-> **Note:** The `name = { source, version }` syntax for `required_providers`
+was added in Terraform v0.13. Previous versions of Terraform used a version
+constraint string instead of an object (like `mycloud = "~> 1.0"`), and had no
+way to specify provider source addresses. If you want to write a module that
+works with both Terraform v0.12 and v0.13, see [v0.12-Compatible Provider
+Requirements](#v0-12-compatible-provider-requirements) below.
+
+## Names and Addresses
+
+Each provider has two identifiers:
+
+* A unique _source address,_ which is only used when requiring a provider.
+* A _local name,_ which is used everywhere else in a Terraform module.
+
+-> **Note:** Prior to Terraform 0.13, providers only had local names, since
+Terraform could only automatically download providers distributed by HashiCorp.
+
+### Local Names
+
+Local names are module-specific, and are assigned when requiring a provider.
+Local names must be unique per-module.
+
+Outside of the `required_providers` block, Terraform configurations always refer
+to providers by their local names. For example, the following configuration
+declares `mycloud` as the local name for `mycorp/mycloud`, then uses that local
+name when [configuring the provider](/terraform/language/providers/configuration):
+
+```hcl
+terraform {
+  required_providers {
+    mycloud = {
+      source  = "mycorp/mycloud"
+      version = "~> 1.0"
+    }
+  }
+}
+
+provider "mycloud" {
+  # ...
+}
+```
+
+Users of a provider can choose any local name for it. However, nearly every
+provider has a _preferred local name,_ which it uses as a prefix for all of its
+resource types. (For example, resources from `hashicorp/aws` all begin with
+`aws`, like `aws_instance` or `aws_security_group`.)
+
+Whenever possible, you should use a provider's preferred local name. This makes
+your configurations easier to understand, and lets you omit the `provider`
+meta-argument from most of your resources. (If a resource doesn't specify which
+provider configuration to use, Terraform interprets the first word of the
+resource type as a local provider name.)
+
+### Source Addresses
+
+A provider's source address is its global identifier. It also specifies the
+primary location where Terraform can download it.
+
+Source addresses consist of three parts delimited by slashes (`/`), as
+follows:
+
+`[<HOSTNAME>/]<NAMESPACE>/<TYPE>`
+
+* **Hostname** (optional): The hostname of the Terraform registry that
+  distributes the provider. If omitted, this defaults to
+  `registry.terraform.io`, the hostname of
+  [the public Terraform Registry](https://registry.terraform.io/).
+
+* **Namespace:** An organizational namespace within the specified registry.
+  For the public Terraform Registry and for Terraform Cloud's private registry,
+  this represents the organization that publishes the provider. This field
+  may have other meanings for other registry hosts.
+
+* **Type:** A short name for the platform or system the provider manages. Must
+  be unique within a particular namespace on a particular registry host.
+
+  The type is usually the provider's preferred local name. (There are
+  exceptions; for example,
+  [`hashicorp/google-beta`](https://registry.terraform.io/providers/hashicorp/google-beta/latest)
+  is an alternate release channel for `hashicorp/google`, so its preferred
+  local name is `google`. If in doubt, check the provider's documentation.)
+
+For example,
+[the official HTTP provider](https://registry.terraform.io/providers/hashicorp/http)
+belongs to the `hashicorp` namespace on `registry.terraform.io`, so its
+source address is `registry.terraform.io/hashicorp/http` or, more commonly, just
+`hashicorp/http`.
+
+The source address with all three components given explicitly is called the
+provider's _fully-qualified address_. You will see fully-qualified address in
+various outputs, like error messages, but in most cases a simplified display
+version is used. This display version omits the source host when it is the
+public registry, so you may see the shortened version `"hashicorp/random"` instead
+of `"registry.terraform.io/hashicorp/random"`.
+
+-> **Note:** If you omit the `source` argument when requiring a provider,
+Terraform uses an implied source address of
+`registry.terraform.io/hashicorp/<LOCAL NAME>`. This is a backward compatibility
+feature to support the transition to Terraform 0.13; in modules that require
+0.13 or later, we recommend using explicit source addresses for all providers.
+
+### Handling Local Name Conflicts
+
+Whenever possible, we recommend using a provider's preferred local name, which
+is usually the same as the "type" portion of its source address.
+
+However, it's sometimes necessary to use two providers with the same preferred
+local name in the same module, usually when the providers are named after a
+generic infrastructure type. Terraform requires unique local names for each
+provider in a module, so you'll need to use a non-preferred name for at least
+one of them.
+
+When this happens, we recommend combining each provider's namespace with
+its type name to produce compound local names with a dash:
+
+```hcl
+terraform {
+  required_providers {
+    # In the rare situation of using two providers that
+    # have the same type name -- "http" in this example --
+    # use a compound local name to distinguish them.
+    hashicorp-http = {
+      source  = "hashicorp/http"
+      version = "~> 2.0"
+    }
+    mycorp-http = {
+      source  = "mycorp/http"
+      version = "~> 1.0"
+    }
+  }
+}
+
+# References to these providers elsewhere in the
+# module will use these compound local names.
+provider "mycorp-http" {
+  # ...
+}
+
+data "http" "example" {
+  provider = hashicorp-http
+  #...
+}
+```
+
+Terraform won't be able to guess either provider's name from its resource types,
+so you'll need to specify a `provider` meta-argument for every affected
+resource. However, readers and maintainers of your module will be able to easily
+understand what's happening, and avoiding confusion is much more important than
+avoiding typing.
+
+## Version Constraints
+
+Each provider plugin has its own set of available versions, allowing the
+functionality of the provider to evolve over time. Each provider dependency you
+declare should have a [version constraint](/terraform/language/expressions/version-constraints) given in
+the `version` argument so Terraform can select a single version per provider
+that all modules are compatible with.
+
+The `version` argument is optional; if omitted, Terraform will accept any
+version of the provider as compatible. However, we strongly recommend specifying
+a version constraint for every provider your module depends on.
+
+To ensure Terraform always installs the same provider versions for a given
+configuration, you can use Terraform CLI to create a
+[dependency lock file](/terraform/language/files/dependency-lock)
+and commit it to version control along with your configuration. If a lock file
+is present, Terraform Cloud, CLI, and Enterprise will all obey it when
+installing providers.
+
+> **Hands-on:** Try the [Lock and Upgrade Provider Versions](/terraform/tutorials/configuration-language/provider-versioning) tutorial.
+
+### Best Practices for Provider Versions
+
+Each module should at least declare the minimum provider version it is known
+to work with, using the `>=` version constraint syntax:
+
+```hcl
+terraform {
+  required_providers {
+    mycloud = {
+      source  = "hashicorp/aws"
+      version = ">= 1.0"
+    }
+  }
+}
+```
+
+A module intended to be used as the root of a configuration — that is, as the
+directory where you'd run `terraform apply` — should also specify the
+_maximum_ provider version it is intended to work with, to avoid accidental
+upgrades to incompatible new versions. The `~>` operator is a convenient
+shorthand for allowing the rightmost component of a version to increment. The
+following example uses the operator to allow only patch releases within a
+specific minor release:
+
+```hcl
+terraform {
+  required_providers {
+    mycloud = {
+      source  = "hashicorp/aws"
+      version = "~> 1.0.4"
+    }
+  }
+}
+```
+
+Do not use `~>` (or other maximum-version constraints) for modules you intend to
+reuse across many configurations, even if you know the module isn't compatible
+with certain newer versions. Doing so can sometimes prevent errors, but more
+often it forces users of the module to update many modules simultaneously when
+performing routine upgrades. Specify a minimum version, document any known
+incompatibilities, and let the root module manage the maximum version.
+
+## Built-in Providers
+
+Most Terraform providers are distributed separately as plugins, but there
+is one provider that is built into Terraform itself. This provider enables the
+[the `terraform_remote_state` data source](/terraform/language/state/remote-state-data).
+
+Because this provider is built in to Terraform, you don't need to declare it
+in the `required_providers` block in order to use its features. However, for
+consistency it _does_ have a special provider source address, which is
+`terraform.io/builtin/terraform`. This address may sometimes appear in
+Terraform's error messages and other output in order to unambiguously refer
+to the built-in provider, as opposed to a hypothetical third-party provider
+with the type name "terraform".
+
+There is also an existing provider with the source address
+`hashicorp/terraform`, which is an older version of the now-built-in provider
+that was used by older versions of Terraform. `hashicorp/terraform` is not
+compatible with Terraform v0.11 or later and should never be declared in a
+`required_providers` block.
+
+## In-house Providers
+
+Anyone can develop and distribute their own Terraform providers. See
+the [Call APIs with Terraform Providers](/terraform/tutorials/providers)
+tutorials for more about provider development.
+
+Some organizations develop their own providers to configure
+proprietary systems, and wish to use these providers from Terraform without
+publishing them on the public Terraform Registry.
+
+One option for distributing such a provider is to run an in-house _private_
+registry, by implementing
+[the provider registry protocol](/terraform/internals/provider-registry-protocol).
+
+Running an additional service just to distribute a single provider internally
+may be undesirable, so Terraform also supports
+[other provider installation methods](/terraform/cli/config/config-file#provider-installation),
+including placing provider plugins directly in specific directories in the
+local filesystem, via _filesystem mirrors_.
+
+All providers must have a [source address](#source-addresses) that includes
+(or implies) the hostname of a registry, but that hostname does not need to
+provide an actual registry service. For in-house providers that you intend to
+distribute from a local filesystem directory, you can use an arbitrary hostname
+in a domain your organization controls.
+
+For example, if your corporate domain were `example.com` then you might choose
+to use `terraform.example.com` as your placeholder hostname, even if that
+hostname doesn't actually resolve in DNS. You can then choose any namespace and
+type you wish to represent your in-house provider under that hostname, giving
+a source address like `terraform.example.com/examplecorp/ourcloud`:
+
+```hcl
+terraform {
+  required_providers {
+    mycloud = {
+      source  = "terraform.example.com/examplecorp/ourcloud"
+      version = ">= 1.0"
+    }
+  }
+}
+```
+
+To make version 1.0.0 of this provider available for installation from the
+local filesystem, choose one of the
+[implied local mirror directories](/terraform/cli/config/config-file#implied-local-mirror-directories)
+and create a directory structure under it like this:
+
+```
+terraform.example.com/examplecorp/ourcloud/1.0.0
+```
+
+Under that `1.0.0` directory, create one additional directory representing the
+platform where you are running Terraform, such as `linux_amd64` for Linux on
+an AMD64/x64 processor, and then place the provider plugin executable and any
+other needed files in that directory.
+
+Thus, on a Windows system, the provider plugin executable file might be at the
+following path:
+
+```
+terraform.example.com/examplecorp/ourcloud/1.0.0/windows_amd64/terraform-provider-ourcloud.exe
+```
+
+If you later decide to switch to using a real private provider registry rather
+than distribute binaries out of band, you can deploy the registry server at
+`terraform.example.com` and retain the same namespace and type names, in which
+case your existing modules will require no changes to locate the same provider
+using your registry server.
+
+## v0.12-Compatible Provider Requirements
+
+Explicit provider source addresses were introduced with Terraform v0.13, so the
+full provider requirements syntax is not supported by Terraform v0.12.
+
+However, in order to allow writing modules that are compatible with both
+Terraform v0.12 and v0.13, versions of Terraform between v0.12.26 and v0.13
+will accept but ignore the `source` argument in a `required_providers` block.
+
+Consider the following example written for Terraform v0.13:
+
+```hcl
+terraform {
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = "~> 1.0"
+    }
+  }
+}
+```
+
+Terraform v0.12.26 will accept syntax like the above but will understand it
+in the same way as the following v0.12-style syntax:
+
+```hcl
+terraform {
+  required_providers {
+    aws = "~> 1.0"
+  }
+}
+```
+
+In other words, Terraform v0.12.26 ignores the `source` argument and considers
+only the `version` argument, using the given [local name](#local-names) as the
+un-namespaced provider type to install.
+
+When writing a module that is compatible with both Terraform v0.12.26 and
+Terraform v0.13.0 or later, you must follow the following additional rules so
+that both versions will select the same provider to install:
+
+* Use only providers that can be automatically installed by Terraform v0.12.
+  Third-party providers, such as community providers in the Terraform Registry,
+  cannot be selected by Terraform v0.12 because it does not support the
+  hierarchical source address namespace.
+
+* Ensure that your chosen local name exactly matches the "type" portion of the
+  source address given in the `source` argument, such as both being "aws" in
+  the examples above, because Terraform v0.12 will use the local name to
+  determine which provider plugin to download and install.
+
+* If the provider belongs to the `hashicorp` namespace, as with the
+  `hashicorp/aws` provider shown above, omit the `source` argument and allow
+  Terraform v0.13 to select the `hashicorp` namespace by default.
+
+* Provider type names must always be written in lowercase. Terraform v0.13
+  treats provider source addresses as case-insensitive, but Terraform v0.12
+  considers its legacy-style provider names to be case-sensitive. Using
+  lowercase will ensure that the name is selectable by both Terraform major
+  versions.
+
+This compatibility mechanism is provided as a temporary transitional aid only.
+When Terraform v0.12 detects a use of the new `source` argument it doesn't
+understand, it will emit a warning to alert the user that it is disregarding
+the source address given in that argument.
diff --git a/v1.5.7/website/docs/language/resources/behavior.mdx b/v1.5.7/website/docs/language/resources/behavior.mdx
new file mode 100644
index 0000000..c65de9d
--- /dev/null
+++ b/v1.5.7/website/docs/language/resources/behavior.mdx
@@ -0,0 +1,111 @@
+---
+page_title: Resource Behavior - Configuration Language
+description: >-
+  Learn how Terraform uses resource blocks to create infrastructure objects.
+  Also learn about resource dependencies and how to access resource attributes.
+---
+
+# Resource Behavior
+
+A `resource` block declares that you want a particular infrastructure object
+to exist with the given settings. If you are writing a new configuration for
+the first time, the resources it defines will exist _only_ in the configuration,
+and will not yet represent real infrastructure objects in the target platform.
+
+_Applying_ a Terraform configuration is the process of creating, updating,
+and destroying real infrastructure objects in order to make their settings
+match the configuration.
+
+## How Terraform Applies a Configuration
+
+When Terraform creates a new infrastructure object represented by a `resource`
+block, the identifier for that real object is saved in Terraform's
+[state](/terraform/language/state), allowing it to be updated and destroyed
+in response to future changes. For resource blocks that already have an
+associated infrastructure object in the state, Terraform compares the
+actual configuration of the object with the arguments given in the
+configuration and, if necessary, updates the object to match the configuration.
+
+In summary, applying a Terraform configuration will:
+
+- _Create_ resources that exist in the configuration but are not associated with a real infrastructure object in the state.
+- _Destroy_ resources that exist in the state but no longer exist in the configuration.
+- _Update in-place_ resources whose arguments have changed.
+- _Destroy and re-create_ resources whose arguments have changed but which cannot be updated in-place due to remote API limitations.
+
+This general behavior applies for all resources, regardless of type. The
+details of what it means to create, update, or destroy a resource are different
+for each resource type, but this standard set of verbs is common across them
+all.
+
+The meta-arguments within `resource` blocks, documented in the
+sections below, allow some details of this standard resource behavior to be
+customized on a per-resource basis.
+
+## Accessing Resource Attributes
+
+[Expressions](/terraform/language/expressions) within a Terraform module can access
+information about resources in the same module, and you can use that information
+to help configure other resources. Use the `<RESOURCE TYPE>.<NAME>.<ATTRIBUTE>`
+syntax to reference a resource attribute in an expression.
+
+In addition to arguments specified in the configuration, resources often provide
+read-only attributes with information obtained from the remote API; this often
+includes things that can't be known until the resource is created, like the
+resource's unique random ID.
+
+Many providers also include [data sources](/terraform/language/data-sources),
+which are a special type of resource used only for looking up information.
+
+For a list of the attributes a resource or data source type provides, consult
+its documentation; these are generally included in a second list below its list
+of configurable arguments.
+
+For more information about referencing resource attributes in expressions, see
+[Expressions: References to Resource Attributes](/terraform/language/expressions/references#references-to-resource-attributes).
+
+## Resource Dependencies
+
+Most resources in a configuration don't have any particular relationship, and
+Terraform can make changes to several unrelated resources in parallel.
+
+However, some resources must be processed after other specific resources;
+sometimes this is because of how the resource works, and sometimes the
+resource's configuration just requires information generated by another
+resource.
+
+Most resource dependencies are handled automatically. Terraform analyses any
+[expressions](/terraform/language/expressions) within a `resource` block to find references
+to other objects, and treats those references as implicit ordering requirements
+when creating, updating, or destroying resources. Since most resources with
+behavioral dependencies on other resources also refer to those resources' data,
+it's usually not necessary to manually specify dependencies between resources.
+
+However, some dependencies cannot be recognized implicitly in configuration. For
+example, if Terraform must manage access control policies _and_ take actions
+that require those policies to be present, there is a hidden dependency between
+the access policy and a resource whose creation depends on it. In these rare
+cases,
+[the `depends_on` meta-argument](/terraform/language/meta-arguments/depends_on)
+can explicitly specify a dependency.
+
+You can also use the [`replace_triggered_by` meta-argument](/terraform/language/meta-arguments/lifecycle#replace_triggered_by) to add dependencies between otherwise independent resources. It forces Terraform to replace the parent resource when there is a change to a referenced resource or resource attribute.
+
+## Local-only Resources
+
+While most resource types correspond to an infrastructure object type that
+is managed via a remote network API, there are certain specialized resource
+types that operate only within Terraform itself, calculating some results and
+saving those results in the state for future use.
+
+For example, local-only resource types exist for
+[generating private keys](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key),
+[issuing self-signed TLS certificates](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/self_signed_cert),
+and even [generating random ids](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id).
+While these resource types often have a more marginal purpose than those
+managing "real" infrastructure objects, they can be useful as glue to help
+connect together other resources.
+
+The behavior of local-only resources is the same as all other resources, but
+their result data exists only within the Terraform state. "Destroying" such
+a resource means only to remove it from the state, discarding its data.
diff --git a/v1.5.7/website/docs/language/resources/index.mdx b/v1.5.7/website/docs/language/resources/index.mdx
new file mode 100644
index 0000000..0c3d230
--- /dev/null
+++ b/v1.5.7/website/docs/language/resources/index.mdx
@@ -0,0 +1,36 @@
+---
+page_title: Resources Overview - Configuration Language
+description: >-
+  Resources describe infrastructure objects in Terraform configurations. Find
+  documentation for resource syntax, behavior, and meta-arguments.
+---
+
+# Resources
+
+> **Hands-on:** Try the [Terraform: Get Started](/terraform/tutorials/aws-get-started?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorials.
+
+_Resources_ are the most important element in the Terraform language.
+Each resource block describes one or more infrastructure objects, such
+as virtual networks, compute instances, or higher-level components such
+as DNS records.
+
+- [Resource Blocks](/terraform/language/resources/syntax) documents
+  the syntax for declaring resources.
+
+- [Resource Behavior](/terraform/language/resources/behavior) explains in
+  more detail how Terraform handles resource declarations when applying a
+  configuration.
+
+- The Meta-Arguments section documents special arguments that can be used with
+  every resource type, including
+  [`depends_on`](/terraform/language/meta-arguments/depends_on),
+  [`count`](/terraform/language/meta-arguments/count),
+  [`for_each`](/terraform/language/meta-arguments/for_each),
+  [`provider`](/terraform/language/meta-arguments/resource-provider),
+  and [`lifecycle`](/terraform/language/meta-arguments/lifecycle).
+
+- [Provisioners](/terraform/language/resources/provisioners/syntax)
+  documents configuring post-creation actions for a resource using the
+  `provisioner` and `connection` blocks. Since provisioners are non-declarative
+  and potentially unpredictable, we strongly recommend that you treat them as a
+  last resort.
diff --git a/v1.5.7/website/docs/language/resources/provisioners/connection.mdx b/v1.5.7/website/docs/language/resources/provisioners/connection.mdx
new file mode 100644
index 0000000..b4b51dc
--- /dev/null
+++ b/v1.5.7/website/docs/language/resources/provisioners/connection.mdx
@@ -0,0 +1,201 @@
+---
+page_title: Provisioner Connection Settings
+description: >-
+  The connection block allows you to manage provisioner connection defaults for
+  SSH and WinRM.
+---
+
+# Provisioner Connection Settings
+
+Most provisioners require access to the remote resource via SSH or WinRM and
+expect a nested `connection` block with details about how to connect.
+
+~> **Important:** Use provisioners as a last resort. There are better alternatives for most situations. Refer to
+[Declaring Provisioners](/terraform/language/resources/provisioners/syntax) for more details.
+
+## Connection Block
+
+You can create one or more `connection` blocks that describe how to access the remote resource. One use case for providing multiple connections is to have an initial provisioner connect as the `root` user to set up user accounts and then have subsequent provisioners connect as a user with more limited permissions.
+
+Connection blocks don't take a block label and can be nested within either a
+`resource` or a `provisioner`.
+
+* A `connection` block nested directly within a `resource` affects all of
+  that resource's provisioners.
+* A `connection` block nested in a `provisioner` block only affects that
+  provisioner and overrides any resource-level connection settings.
+
+Since the SSH connection type is most often used with
+newly-created remote resources, validation of SSH host keys is disabled by
+default. If this is not acceptable, you can establish a separate mechanism for key distribution and explicitly set the `host_key` argument (details below) to verify against a specific key or signing CA.
+
+-> **Note:** In Terraform 0.11 and earlier, providers could set default values
+for some connection settings, so that `connection` blocks could sometimes be
+omitted. This feature was removed in 0.12 in order to make Terraform's behavior
+more predictable.
+
+
+### Example usage
+
+```hcl
+# Copies the file as the root user using SSH
+provisioner "file" {
+  source      = "conf/myapp.conf"
+  destination = "/etc/myapp.conf"
+
+  connection {
+    type     = "ssh"
+    user     = "root"
+    password = "${var.root_password}"
+    host     = "${var.host}"
+  }
+}
+
+# Copies the file as the Administrator user using WinRM
+provisioner "file" {
+  source      = "conf/myapp.conf"
+  destination = "C:/App/myapp.conf"
+
+  connection {
+    type     = "winrm"
+    user     = "Administrator"
+    password = "${var.admin_password}"
+    host     = "${var.host}"
+  }
+}
+```
+
+### The `self` Object
+
+Expressions in `connection` blocks cannot refer to their parent resource by name. References create dependencies, and referring to a resource by name within its own block would create a dependency cycle. Instead, expressions can use the `self` object, which represents the connection's parent resource and has all of that resource's attributes. For example, use `self.public_ip` to reference an `aws_instance`'s `public_ip` attribute.
+
+
+### Argument Reference
+
+The `connection` block supports the following arguments. Some arguments are only supported by either the SSH or the WinRM connection type.
+
+
+| Argument | Connection Type | Description | Default |
+|---------------|--------------|-------------|---------|
+| `type` | Both | The connection type. Valid values are `"ssh"` and `"winrm"`. Provisioners typically assume that the remote system runs Microsoft Windows when using WinRM. Behaviors based on the SSH `target_platform` will force Windows-specific behavior for WinRM, unless otherwise specified.| `"ssh"` |
+| `user` | Both | The user to use for the connection. | `root` for type `"ssh"`<br />`Administrator` for type `"winrm"` |
+| `password` | Both | The password to use for the connection. | |
+| `host` | Both | **Required** - The address of the resource to connect to. | |
+| `port` | Both| The port to connect to. | `22` for type `"ssh"`<br />`5985` for type `"winrm"` |
+| `timeout` | Both | The timeout to wait for the connection to become available. Should be provided as a string (e.g., `"30s"` or `"5m"`.) | `"5m"` |
+| `script_path` | Both | The path used to copy scripts meant for remote execution. Refer to [How Provisioners Execute Remote Scripts](#how-provisioners-execute-remote-scripts) below for more details. | (details below) |
+| `private_key` | SSH | The contents of an SSH key to use for the connection. These can be loaded from a file on disk using [the `file` function](/terraform/language/functions/file). This takes preference over `password` if provided. | |
+| `certificate` | SSH | The contents of a signed CA Certificate. The certificate argument must be used in conjunction with a `private_key`. These can be loaded from a file on disk using the [the `file` function](/terraform/language/functions/file). | |
+| `agent` | SSH | Set to `false` to disable using `ssh-agent` to authenticate. On Windows the only supported SSH authentication agent is [Pageant](http://the.earth.li/\~sgtatham/putty/0.66/htmldoc/Chapter9.html#pageant). |   |
+| `agent_identity` | SSH | The preferred identity from the ssh agent for authentication. | |
+| `host_key` | SSH | The public key from the remote host or the signing CA, used to verify the connection. | |
+| `target_platform` | SSH | The target platform to connect to. Valid values are `"windows"` and `"unix"`. If the platform is set to `windows`, the default `script_path` is `c:\windows\temp\terraform_%RAND%.cmd`, assuming [the SSH default shell](https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_server_configuration#configuring-the-default-shell-for-openssh-in-windows) is `cmd.exe`. If the SSH default shell is PowerShell, set `script_path` to `"c:/windows/temp/terraform_%RAND%.ps1"` | `"unix"` |
+| `https` | WinRM | Set to `true` to connect using HTTPS instead of HTTP. | |
+| `insecure` | WinRM | Set to `true` to skip validating the HTTPS certificate chain. | |
+| `use_ntlm` | WinRM | Set to `true` to use NTLM authentication rather than default (basic authentication), removing the requirement for basic authentication to be enabled within the target guest. Refer to [Authentication for Remote Connections](https://docs.microsoft.com/en-us/windows/win32/winrm/authentication-for-remote-connections) in the Windows App Development documentation for more details. | |
+| `cacert` | WinRM | The CA certificate to validate against. | |
+
+
+<a id="bastion"></a>
+
+## Connecting through a Bastion Host with SSH
+
+The `ssh` connection also supports the following arguments to connect
+indirectly with a [bastion host](https://en.wikipedia.org/wiki/Bastion_host).
+
+| Argument | Description | Default |
+|---------------|-------------|---------|
+| `bastion_host` | Setting this enables the bastion Host connection. The provisioner will connect to `bastion_host` first, and then connect from there to `host`. | |
+| `bastion_host_key` | The public key from the remote host or the signing CA, used to verify the host connection. | |
+| `bastion_port` | The port to use connect to the bastion host. | The value of the `port` field.|
+| `bastion_user`| The user for the connection to the bastion host. | The value of the `user` field. |
+| `bastion_password` | The password to use for the bastion host. | The value of the `password` field. |
+| `bastion_private_key` | The contents of an SSH key file to use for the bastion host. These can be loaded from a file on disk using [the `file` function](/terraform/language/functions/file). | The value of the `private_key` field. |
+| `bastion_certificate` |  The contents of a signed CA Certificate. The certificate argument must be used in conjunction with a `bastion_private_key`. These can be loaded from a file on disk using the [the `file` function](/terraform/language/functions/file). |
+
+## Connection through a HTTP Proxy with SSH
+
+The `ssh` connection also supports the following fields to facilitate connections by SSH over HTTP proxy.
+
+| Argument | Description | Default |
+|---------------|-------------|---------|
+| `proxy_scheme` | http or https | |
+| `proxy_host` | Setting this enables the SSH over HTTP connection. This host will be connected to first, and then the `host` or `bastion_host` connection will be made from there. | |
+| `proxy_port` | The port to use connect to the proxy host. | |
+| `proxy_user_name` | The username to use connect to the private proxy host. This argument should be specified only if authentication is required for the HTTP Proxy server. | |
+| `proxy_user_password` | The password to use connect to the private proxy host. This argument should be specified only if authentication is required for the HTTP Proxy server. | |
+
+## How Provisioners Execute Remote Scripts
+
+Provisioners which execute commands on a remote system via a protocol such as
+SSH typically achieve that by uploading a script file to the remote system
+and then asking the default shell to execute it. Provisioners use this strategy
+because it then allows you to use all of the typical scripting techniques
+supported by that shell, including preserving environment variable values
+and other context between script statements.
+
+However, this approach does have some consequences which can be relevant in
+some unusual situations, even though this is just an implementation detail
+in typical use.
+
+Most importantly, there must be a suitable location in the remote filesystem
+where the provisioner can create the script file. By default, Terraform
+chooses a path containing a random number using the following patterns
+depending on how `target_platform` is set:
+
+* `"unix"`: `/tmp/terraform_%RAND%.sh`
+* `"windows"`: `C:/windows/temp/terraform_%RAND%.cmd`
+
+In both cases above, the provisioner replaces the sequence `%RAND%` with
+some randomly-chosen decimal digits.
+
+Provisioners cannot react directly to remote environment variables such as
+`TMPDIR` or use functions like `mktemp` because they run on the system where
+Terraform is running, not on the remote system. Therefore if your remote
+system doesn't use the filesystem layout expected by these default paths
+then you can override it using the `script_path` option in your `connection`
+block:
+
+```hcl
+connection {
+  # ...
+  script_path = "H:/terraform-temp/script_%RAND%.sh"
+}
+```
+
+As with the default patterns, provisioners will replace the sequence `%RAND%`
+with randomly-selected decimal digits, to reduce the likelihood of collisions
+between multiple provisioners running concurrently.
+
+If your target system is running Windows, we recommend using forward slashes
+instead of backslashes, despite the typical convention on Windows, because
+the Terraform language uses backslash as the quoted string escape character.
+
+### Executing Scripts using SSH/SCP
+
+When using the SSH protocol, provisioners upload their script files using
+the Secure Copy Protocol (SCP), which requires that the remote system have
+the `scp` service program installed to act as the server for that protocol.
+
+Provisioners will pass the chosen script path (after `%RAND%`
+expansion) directly to the remote `scp` process, which is responsible for
+interpreting it. With the default configuration of `scp` as distributed with
+OpenSSH, you can place temporary scripts in the home directory of the remote
+user by specifying a relative path:
+
+```hcl
+connection {
+  type = "ssh"
+  # ...
+  script_path = "terraform_provisioner_%RAND%.sh"
+}
+```
+
+!> **Warning:** In Terraform v1.0 and earlier, the built-in provisioners
+incorrectly passed the `script_path` value to `scp` through a remote shell and
+thus allowed it to be subject to arbitrary shell expansion, and thus created an
+unintended opportunity for remote code execution. Terraform v1.1 and later
+will now correctly quote and escape the script path to ensure that the
+remote `scp` process can always interpret it literally. For modules that will
+be used with Terraform v1.0 and earlier, avoid using untrusted external
+values as part of the `script_path` argument.
diff --git a/v1.5.7/website/docs/language/resources/provisioners/file.mdx b/v1.5.7/website/docs/language/resources/provisioners/file.mdx
new file mode 100644
index 0000000..9655e8a
--- /dev/null
+++ b/v1.5.7/website/docs/language/resources/provisioners/file.mdx
@@ -0,0 +1,129 @@
+---
+page_title: 'Provisioner: file'
+description: >-
+  The `file` provisioner is used to copy files or directories from the machine
+  executing Terraform to the newly created resource. The `file` provisioner
+  supports both `ssh` and `winrm` type connections.
+---
+
+# File Provisioner
+
+The `file` provisioner copies files or directories from the machine
+running Terraform to the newly created resource. The `file` provisioner
+supports both `ssh` and `winrm` type [connections](/terraform/language/resources/provisioners/connection).
+
+~> **Important:** Use provisioners as a last resort. There are better alternatives for most situations. Refer to
+[Declaring Provisioners](/terraform/language/resources/provisioners/syntax) for more details.
+
+## Example usage
+
+```hcl
+resource "aws_instance" "web" {
+  # ...
+
+  # Copies the myapp.conf file to /etc/myapp.conf
+  provisioner "file" {
+    source      = "conf/myapp.conf"
+    destination = "/etc/myapp.conf"
+  }
+
+  # Copies the string in content into /tmp/file.log
+  provisioner "file" {
+    content     = "ami used: ${self.ami}"
+    destination = "/tmp/file.log"
+  }
+
+  # Copies the configs.d folder to /etc/configs.d
+  provisioner "file" {
+    source      = "conf/configs.d"
+    destination = "/etc"
+  }
+
+  # Copies all files and folders in apps/app1 to D:/IIS/webapp1
+  provisioner "file" {
+    source      = "apps/app1/"
+    destination = "D:/IIS/webapp1"
+  }
+}
+```
+
+-> **Note:** When the `file` provisioner communicates with a Windows system over SSH, you must configure OpenSSH to run the commands with `cmd.exe` and not PowerShell. PowerShell causes file parsing errors because it is incompatible with both Unix shells and the Windows command interpreter.
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `source` - The source file or directory. Specify it either relative to the
+  current working directory or as an absolute path.
+  This argument cannot be combined with `content`.
+
+* `content` - The direct content to copy on the destination.
+  If destination is a file, the content will be written on that file. In case
+  of a directory, a file named `tf-file-content` is created inside that
+  directory. We recommend using a file as the destination when using `content`.
+  This argument cannot be combined with `source`.
+
+* `destination` - (Required) The destination path to write to on the remote
+  system. See [Destination Paths](#destination-paths) below for more
+  information.
+
+## Destination Paths
+
+The path you provide in the `destination` argument will be evaluated by the
+remote system, rather than by Terraform itself. Therefore the valid values
+for that argument can vary depending on the operating system and remote access
+software running on the target.
+
+When connecting over SSH, the `file` provisioner passes the given destination
+path verbatim to the `scp` program on the remote host. By default, OpenSSH's
+`scp` implementation runs in the remote user's home directory and so you can
+specify a relative path to upload into that home directory, or an absolute
+path to upload to some other location. The remote `scp` process will run with
+the access level of the user specified in the `connection` block, and so
+permissions may prevent writing directly to locations outside of the home
+directory.
+
+Because WinRM has no corresponding file transfer protocol, for WinRM
+connections the `file` provisioner uses a more complex process:
+
+1. Generate a temporary filename in the directory given in the remote system's
+   `TEMP` environment variable, using a pseudorandom UUID for uniqueness.
+2. Use sequential generated `echo` commands over WinRM to gradually append
+   base64-encoded chunks of the source file to the chosen temporary file.
+3. Use an uploaded PowerShell script to read the temporary file, base64-decode,
+   and write the raw result into the destination file.
+
+In the WinRM case, the destination path is therefore interpreted by PowerShell
+and so you must take care not to use any meta-characters that PowerShell might
+interpret. In particular, avoid including any untrusted external input in
+your `destination` argument when using WinRM, because it can serve as a vector
+for arbitrary PowerShell code execution on the remote system.
+
+Modern Windows systems support running an OpenSSH server, so we strongly
+recommend choosing SSH over WinRM whereever possible, and using WinRM only as
+a last resort when working with obsolete Windows versions.
+
+## Directory Uploads
+
+The `file` provisioner can upload a complete directory to the remote machine.
+When uploading a directory, there are some additional considerations.
+
+When using the `ssh` connection type the destination directory must already
+exist. If you need to create it, use a remote-exec provisioner just prior to
+the file provisioner in order to create the directory
+
+When using the `winrm` connection type the destination directory will be
+created for you if it doesn't already exist.
+
+The existence of a trailing slash on the source path will determine whether the
+directory name will be embedded within the destination, or whether the
+destination will be created. For example:
+
+* If the source is `/foo` (no trailing slash), and the destination is `/tmp`,
+  then the contents of `/foo` on the local machine will be uploaded to
+  `/tmp/foo` on the remote machine. The `foo` directory on the remote machine
+  will be created by Terraform.
+
+* If the source, however, is `/foo/` (a trailing slash is present), and the
+  destination is `/tmp`, then the contents of `/foo` will be uploaded directly
+  into `/tmp`.
diff --git a/v1.5.7/website/docs/language/resources/provisioners/local-exec.mdx b/v1.5.7/website/docs/language/resources/provisioners/local-exec.mdx
new file mode 100644
index 0000000..ed19ec9
--- /dev/null
+++ b/v1.5.7/website/docs/language/resources/provisioners/local-exec.mdx
@@ -0,0 +1,101 @@
+---
+page_title: 'Provisioner: local-exec'
+description: >-
+  The `local-exec` provisioner invokes a local executable after a resource is
+  created. This invokes a process on the machine running Terraform, not on the
+  resource. See the `remote-exec` provisioner to run commands on the resource.
+---
+
+# local-exec Provisioner
+
+The `local-exec` provisioner invokes a local executable after a resource is
+created. This invokes a process on the machine running Terraform, not on the
+resource. See the `remote-exec`
+[provisioner](/terraform/language/resources/provisioners/remote-exec) to run commands on the
+resource.
+
+Note that even though the resource will be fully created when the provisioner is
+run, there is no guarantee that it will be in an operable state - for example
+system services such as `sshd` may not be started yet on compute resources.
+
+~> **Important:** Use provisioners as a last resort. There are better alternatives for most situations. Refer to
+[Declaring Provisioners](/terraform/language/resources/provisioners/syntax) for more details.
+
+## Example usage
+
+```hcl
+resource "aws_instance" "web" {
+  # ...
+
+  provisioner "local-exec" {
+    command = "echo ${self.private_ip} >> private_ips.txt"
+  }
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `command` - (Required) This is the command to execute. It can be provided
+  as a relative path to the current working directory or as an absolute path.
+  It is evaluated in a shell, and can use environment variables or Terraform
+  variables.
+
+* `working_dir` - (Optional) If provided, specifies the working directory where
+  `command` will be executed. It can be provided as a relative path to the
+  current working directory or as an absolute path. The directory must exist.
+
+* `interpreter` - (Optional) If provided, this is a list of interpreter
+  arguments used to execute the command. The first argument is the
+  interpreter itself. It can be provided as a relative path to the current
+  working directory or as an absolute path.  The remaining arguments are
+  appended prior to the command.  This allows building command lines of the
+  form "/bin/bash", "-c", "echo foo". If `interpreter` is unspecified,
+  sensible defaults will be chosen based on the system OS.
+
+* `environment` - (Optional) block of key value pairs representing the
+  environment of the executed command. inherits the current process environment.
+
+* `when` - (Optional) If provided, specifies when Terraform will execute the command.
+  For example, `when = destroy` specifies that the provisioner will run when the associated resource
+  is destroyed. Refer to [Destroy-Time Provisioners](/terraform/language/resources/provisioners/syntax#destroy-time-provisioners)
+  for details.
+  
+*  `quiet` - (Optional) If set to `true`, Terraform will not print the command to be executed to stdout, and will instead print "Suppressed by quiet=true". Note that the output of the command will still be printed in any case.
+
+### Interpreter Examples
+
+```hcl
+resource "terraform_data" "example1" {
+  provisioner "local-exec" {
+    command = "open WFH, '>completed.txt' and print WFH scalar localtime"
+    interpreter = ["perl", "-e"]
+  }
+}
+```
+
+```hcl
+resource "terraform_data" "example2" {
+  provisioner "local-exec" {
+    command = "Get-Date > completed.txt"
+    interpreter = ["PowerShell", "-Command"]
+  }
+}
+```
+
+```hcl
+resource "aws_instance" "web" {
+  # ...
+
+  provisioner "local-exec" {
+    command = "echo $FOO $BAR $BAZ >> env_vars.txt"
+
+    environment = {
+      FOO = "bar"
+      BAR = 1
+      BAZ = "true"
+    }
+  }
+}
+```
diff --git a/v1.5.7/website/docs/language/resources/provisioners/null_resource.mdx b/v1.5.7/website/docs/language/resources/provisioners/null_resource.mdx
new file mode 100644
index 0000000..16c897a
--- /dev/null
+++ b/v1.5.7/website/docs/language/resources/provisioners/null_resource.mdx
@@ -0,0 +1,50 @@
+---
+page_title: Provisioners Without a Resource
+description: >-
+  A terraform_data managed resource allows you to configure provisioners that
+  are not directly associated with a single existing resource.
+---
+
+# Provisioners Without a Resource
+
+If you need to run provisioners that aren't directly associated with a specific
+resource, you can associate them with a `terraform_data`.
+
+Instances of [`terraform_data`](/terraform/language/resources/terraform-data) are treated
+like normal resources, but they don't do anything. Like with any other resource
+type, you can configure [provisioners](/terraform/language/resources/provisioners/syntax)
+and [connection details](/terraform/language/resources/provisioners/connection) on a
+`terraform_data` resource. You can also use its `input` argument, `triggers_replace` argument, and any
+meta-arguments to control exactly where in the dependency graph its
+provisioners will run.
+
+~> **Important:** Use provisioners as a last resort. There are better alternatives for most situations. Refer to
+[Declaring Provisioners](/terraform/language/resources/provisioners/syntax) for more details.
+
+## Example usage
+
+```hcl
+resource "aws_instance" "cluster" {
+  count = 3
+
+  # ...
+}
+
+resource "terraform_data" "cluster" {
+  # Replacement of any instance of the cluster requires re-provisioning
+  triggers_replace = aws_instance.cluster.[*].id
+
+  # Bootstrap script can run on any instance of the cluster
+  # So we just choose the first in this case
+  connection {
+    host = aws_instance.cluster.[0].public_ip
+  }
+
+  provisioner "remote-exec" {
+    # Bootstrap script called with private_ip of each node in the cluster
+    inline = [
+      "bootstrap-cluster.sh ${join(" ", aws_instance.cluster.*.private_ip)}",
+    ]
+  }
+}
+```
diff --git a/v1.5.7/website/docs/language/resources/provisioners/remote-exec.mdx b/v1.5.7/website/docs/language/resources/provisioners/remote-exec.mdx
new file mode 100644
index 0000000..ef548d5
--- /dev/null
+++ b/v1.5.7/website/docs/language/resources/provisioners/remote-exec.mdx
@@ -0,0 +1,89 @@
+---
+page_title: 'Provisioner: remote-exec'
+description: >-
+  The `remote-exec` provisioner invokes a script on a remote resource after it
+  is created. This can be used to run a configuration management tool, bootstrap
+  into a cluster, etc. To invoke a local process, see the `local-exec`
+  provisioner instead. The `remote-exec` provisioner supports both `ssh` and
+  `winrm` type connections.
+---
+
+# remote-exec Provisioner
+
+The `remote-exec` provisioner invokes a script on a remote resource after it
+is created. This can be used to run a configuration management tool, bootstrap
+into a cluster, etc. To invoke a local process, see the `local-exec`
+[provisioner](/terraform/language/resources/provisioners/local-exec) instead. The `remote-exec`
+provisioner requires a [connection](/terraform/language/resources/provisioners/connection)
+and supports both `ssh` and `winrm`.
+
+~> **Important:** Use provisioners as a last resort. There are better alternatives for most situations. Refer to
+[Declaring Provisioners](/terraform/language/resources/provisioners/syntax) for more details.
+
+## Example usage
+
+```hcl
+resource "aws_instance" "web" {
+  # ...
+
+  # Establishes connection to be used by all
+  # generic remote provisioners (i.e. file/remote-exec)
+  connection {
+    type     = "ssh"
+    user     = "root"
+    password = var.root_password
+    host     = self.public_ip
+  }
+
+  provisioner "remote-exec" {
+    inline = [
+      "puppet apply",
+      "consul join ${aws_instance.web.private_ip}",
+    ]
+  }
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `inline` - This is a list of command strings. The provisioner uses a default
+  shell unless you specify a shell as the first command (eg., `#!/bin/bash`). 
+  You cannot provide this with `script` or `scripts`.
+
+* `script` - This is a path (relative or absolute) to a local script that will
+  be copied to the remote resource and then executed. This cannot be provided
+  with `inline` or `scripts`.
+
+* `scripts` - This is a list of paths (relative or absolute) to local scripts
+  that will be copied to the remote resource and then executed. They are executed
+  in the order they are provided. This cannot be provided with `inline` or `script`.
+
+-> **Note:** Since `inline` is implemented by concatenating commands into a script, [`on_failure`](/terraform/language/resources/provisioners/syntax#failure-behavior) applies only to the final command in the list. In particular, with `on_failure = fail` (the default behaviour) earlier commands will be allowed to fail, and later commands will also execute. If this behaviour is not desired, consider using `"set -o errexit"` as the first command.
+
+## Script Arguments
+
+You cannot pass any arguments to scripts using the `script` or
+`scripts` arguments to this provisioner. If you want to specify arguments,
+upload the script with the
+[file provisioner](/terraform/language/resources/provisioners/file)
+and then use `inline` to call it. Example:
+
+```hcl
+resource "aws_instance" "web" {
+  # ...
+
+  provisioner "file" {
+    source      = "script.sh"
+    destination = "/tmp/script.sh"
+  }
+
+  provisioner "remote-exec" {
+    inline = [
+      "chmod +x /tmp/script.sh",
+      "/tmp/script.sh args",
+    ]
+  }
+}
+```
diff --git a/v1.5.7/website/docs/language/resources/provisioners/syntax.mdx b/v1.5.7/website/docs/language/resources/provisioners/syntax.mdx
new file mode 100644
index 0000000..bdf9e82
--- /dev/null
+++ b/v1.5.7/website/docs/language/resources/provisioners/syntax.mdx
@@ -0,0 +1,339 @@
+---
+page_title: Provisioners
+description: >-
+  Provisioners run scripts on a local or remote machine during resource creation
+  or destruction. Learn how to declare provisioners in a configuration.
+---
+
+# Provisioners
+
+You can use provisioners to model specific actions on the local machine or on
+a remote machine in order to prepare servers or other infrastructure objects
+for service.
+
+-> **Note:** We removed the Chef, Habitat, Puppet, and Salt Masterless provisioners in Terraform v0.15.0. Information about these legacy provisioners is still available in the documentation for [Terraform v1.1 (and earlier)](/terraform/language/v1.1.x/resources/provisioners/syntax).
+
+## Provisioners are a Last Resort
+
+> **Hands-on:** Try the [Provision Infrastructure Deployed with Terraform](/terraform/tutorials/provision?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorials to learn about more declarative ways to handle provisioning actions.
+
+Terraform includes the concept of provisioners as a measure of pragmatism,
+knowing that there are always certain behaviors that cannot be directly
+represented in Terraform's declarative model.
+
+However, they also add a considerable amount of complexity and uncertainty to
+Terraform usage. Firstly, Terraform cannot model the actions of provisioners
+as part of a plan because they can in principle take any action. Secondly,
+successful use of provisioners requires coordinating many more details than
+Terraform usage usually requires: direct network access to your servers,
+issuing Terraform credentials to log in, making sure that all of the necessary
+external software is installed, etc.
+
+The following sections describe some situations which can be solved with
+provisioners in principle, but where better solutions are also available. We do
+not recommend using provisioners for any of the use-cases described in the
+following sections.
+
+Even if your specific use-case is not described in the following sections, we
+still recommend attempting to solve it using other techniques first, and use
+provisioners only if there is no other option.
+
+### Passing data into virtual machines and other compute resources
+
+When deploying virtual machines or other similar compute resources, we often
+need to pass in data about other related infrastructure that the software on
+that server will need to do its job.
+
+The various provisioners that interact with remote servers over SSH or WinRM
+can potentially be used to pass such data by logging in to the server and
+providing it directly, but most cloud computing platforms provide mechanisms
+to pass data to instances at the time of their creation such that the data
+is immediately available on system boot. For example:
+
+* Alibaba Cloud: `user_data` on
+  [`alicloud_instance`](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/instance)
+  or [`alicloud_launch_template`](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/launch_template).
+* Amazon EC2: `user_data` or `user_data_base64` on
+  [`aws_instance`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance),
+  [`aws_launch_template`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/launch_template),
+  and [`aws_launch_configuration`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/launch_configuration).
+* Amazon Lightsail: `user_data` on
+  [`aws_lightsail_instance`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lightsail_instance).
+* Microsoft Azure: `custom_data` on
+  [`azurerm_virtual_machine`](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_machine)
+  or [`azurerm_virtual_machine_scale_set`](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_machine_scale_set).
+* Google Cloud Platform: `metadata` on
+  [`google_compute_instance`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance)
+  or [`google_compute_instance_group`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance_group).
+* Oracle Cloud Infrastructure: `metadata` or `extended_metadata` on
+  [`oci_core_instance`](https://registry.terraform.io/providers/hashicorp/oci/latest/docs/resources/core_instance)
+  or [`oci_core_instance_configuration`](https://registry.terraform.io/providers/hashicorp/oci/latest/docs/resources/core_instance_configuration).
+* VMware vSphere: Attach a virtual CDROM to
+  [`vsphere_virtual_machine`](https://registry.terraform.io/providers/hashicorp/vsphere/latest/docs/resources/virtual_machine)
+  using the `cdrom` block, containing a file called `user-data.txt`.
+
+Many official Linux distribution disk images include software called
+[cloud-init](https://cloudinit.readthedocs.io/en/latest/) that can automatically
+process in various ways data passed via the means described above, allowing
+you to run arbitrary scripts and do basic system configuration immediately
+during the boot process and without the need to access the machine over SSH.
+
+> **Hands-on:** Try the [Provision Infrastructure with Cloud-Init](/terraform/tutorials/provision/cloud-init?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+If you are building custom machine images, you can make use of the "user data"
+or "metadata" passed by the above means in whatever way makes sense to your
+application, by referring to your vendor's documentation on how to access the
+data at runtime.
+
+This approach is _required_ if you intend to use any mechanism in your cloud
+provider for automatically launching and destroying servers in a group,
+because in that case individual servers will launch unattended while Terraform
+is not around to provision them.
+
+Even if you're deploying individual servers directly with Terraform, passing
+data this way will allow faster boot times and simplify deployment by avoiding
+the need for direct network access from Terraform to the new server and for
+remote access credentials to be provided.
+
+### Provisioning files using cloud-config
+
+You can add the [`cloudinit_config`](https://registry.terraform.io/providers/hashicorp/cloudinit/latest/docs) data source to your Terraform configuration and specify the files you want to provision as `text/cloud-config` content. The `cloudinit_config` data source renders multi-part MIME configurations for use with [cloud-init](https://cloudinit.readthedocs.io/en/latest/). Pass the files in the `content` field as YAML-encoded configurations using the `write_files` block. 
+
+In the following example, the `my_cloud_config` data source specifies a `text/cloud-config` MIME part named `cloud.conf`. The `part.content` field is set to [`yamlencode`](/terraform/language/functions/yamlencode), which encodes the `write_files` JSON object as YAML so that the system can provision the referenced files.
+
+```hcl
+data "cloudinit_config" "my_cloud_config" {
+  gzip          = false
+  base64_encode = false
+
+  part {
+    content_type = "text/cloud-config"
+    filename     = "cloud.conf"
+    content = yamlencode(
+      {
+        "write_files" : [
+          {
+            "path" : "/etc/foo.conf",
+            "content" : "foo contents",
+          },
+          {
+            "path" : "/etc/bar.conf",
+            "content" : file("bar.conf"),
+          },
+          {
+            "path" : "/etc/baz.conf",
+            "content" : templatefile("baz.tpl.conf", { SOME_VAR = "qux" }),
+          },
+        ],
+      }
+    )
+  }
+}
+```
+
+### Running configuration management software
+
+As a convenience to users who are forced to use generic operating system
+distribution images, Terraform includes a number of specialized provisioners
+for launching specific configuration management products.
+
+We strongly recommend not using these, and instead running system configuration
+steps during a custom image build process. For example,
+[HashiCorp Packer](https://www.packer.io/) offers a similar complement of
+configuration management provisioners and can run their installation steps
+during a separate build process, before creating a system disk image that you
+can deploy many times.
+
+> **Hands-on:** Try the [Provision Infrastructure with Packer](/terraform/tutorials/provision/packer?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+If you are using configuration management software that has a centralized server
+component, you will need to delay the _registration_ step until the final
+system is booted from your custom image. To achieve that, use one of the
+mechanisms described above to pass the necessary information into each instance
+so that it can register itself with the configuration management server
+immediately on boot, without the need to accept commands from Terraform over
+SSH or WinRM.
+
+### First-class Terraform provider functionality may be available
+
+It is technically possible to use the `local-exec` provisioner to run the CLI
+for your target system in order to create, update, or otherwise interact with
+remote objects in that system.
+
+If you are trying to use a new feature of the remote system that isn't yet
+supported in its Terraform provider, that might be the only option. However,
+if there _is_ provider support for the feature you intend to use, prefer to
+use that provider functionality rather than a provisioner so that Terraform
+can be fully aware of the object and properly manage ongoing changes to it.
+
+Even if the functionality you need is not available in a provider today, we
+suggest to consider `local-exec` usage a temporary workaround and to also
+open an issue in the relevant provider's repository to discuss adding
+first-class provider support. Provider development teams often prioritize
+features based on interest, so opening an issue is a way to record your
+interest in the feature.
+
+Provisioners are used to execute scripts on a local or remote machine
+as part of resource creation or destruction. Provisioners can be used to
+bootstrap a resource, cleanup before destroy, run configuration management, etc.
+
+## How to use Provisioners
+
+-> **Note:** Provisioners should only be used as a last resort. For most
+common situations there are better alternatives. For more information, see
+the sections above.
+
+If you are certain that provisioners are the best way to solve your problem
+after considering the advice in the sections above, you can add a
+`provisioner` block inside the `resource` block of a compute instance.
+
+```hcl
+resource "aws_instance" "web" {
+  # ...
+
+  provisioner "local-exec" {
+    command = "echo The server's IP address is ${self.private_ip}"
+  }
+}
+```
+
+The `local-exec` provisioner requires no other configuration, but most other
+provisioners must connect to the remote system using SSH or WinRM.
+You must include [a `connection` block](/terraform/language/resources/provisioners/connection) so that Terraform knows how to communicate with the server.
+
+Terraform includes several built-in provisioners. You can also use third-party provisioners as plugins, by placing them
+in `%APPDATA%\terraform.d\plugins`, `~/.terraform.d/plugins`, or the same
+directory where the Terraform binary is installed. However, we do not recommend
+using any provisioners except the built-in `file`, `local-exec`, and
+`remote-exec` provisioners.
+
+All provisioners support the `when` and `on_failure` meta-arguments, which
+are described below (see [Destroy-Time Provisioners](#destroy-time-provisioners)
+and [Failure Behavior](#failure-behavior)).
+
+### The `self` Object
+
+Expressions in `provisioner` blocks cannot refer to their parent resource by
+name. Instead, they can use the special `self` object.
+
+The `self` object represents the provisioner's parent resource, and has all of
+that resource's attributes. For example, use `self.public_ip` to reference an
+`aws_instance`'s `public_ip` attribute.
+
+-> **Technical note:** Resource references are restricted here because
+references create dependencies. Referring to a resource by name within its own
+block would create a dependency cycle.
+
+## Suppressing Provisioner Logs in CLI Output
+
+The configuration for a `provisioner` block may use sensitive values, such as
+[`sensitive` variables](/terraform/language/values/variables#suppressing-values-in-cli-output) or
+[`sensitive` output values](/terraform/language/values/outputs#sensitive-suppressing-values-in-cli-output).
+In this case, all log output from the provisioner is automatically suppressed to
+prevent the sensitive values from being displayed.
+
+## Creation-Time Provisioners
+
+By default, provisioners run when the resource they are defined within is
+created. Creation-time provisioners are only run during _creation_, not
+during updating or any other lifecycle. They are meant as a means to perform
+bootstrapping of a system.
+
+If a creation-time provisioner fails, the resource is marked as **tainted**.
+A tainted resource will be planned for destruction and recreation upon the
+next `terraform apply`. Terraform does this because a failed provisioner
+can leave a resource in a semi-configured state. Because Terraform cannot
+reason about what the provisioner does, the only way to ensure proper creation
+of a resource is to recreate it. This is tainting.
+
+You can change this behavior by setting the `on_failure` attribute,
+which is covered in detail below.
+
+## Destroy-Time Provisioners
+
+If `when = destroy` is specified, the provisioner will run when the
+resource it is defined within is _destroyed_.
+
+```hcl
+resource "aws_instance" "web" {
+  # ...
+
+  provisioner "local-exec" {
+    when    = destroy
+    command = "echo 'Destroy-time provisioner'"
+  }
+}
+```
+
+Destroy provisioners are run before the resource is destroyed. If they
+fail, Terraform will error and rerun the provisioners again on the next
+`terraform apply`. Due to this behavior, care should be taken for destroy
+provisioners to be safe to run multiple times.
+
+~> **Note**: Destroy provisioners of this resource do not run if `create_before_destroy` is set to `true`. This [GitHub issue](https://github.com/hashicorp/terraform/issues/13549) contains more details.
+
+Destroy-time provisioners can only run if they remain in the configuration
+at the time a resource is destroyed. If a resource block with a destroy-time
+provisioner is removed entirely from the configuration, its provisioner
+configurations are removed along with it and thus the destroy provisioner
+won't run. To work around this, a multi-step process can be used to safely
+remove a resource with a destroy-time provisioner:
+
+* Update the resource configuration to include `count = 0`.
+* Apply the configuration to destroy any existing instances of the resource, including running the destroy provisioner.
+* Remove the resource block entirely from configuration, along with its `provisioner` blocks.
+* Apply again, at which point no further action should be taken since the resources were already destroyed.
+
+Because of this limitation, you should use destroy-time provisioners sparingly and with care.
+
+~> **NOTE:** A destroy-time provisioner within a resource that is tainted _will not_ run. This includes resources that are marked tainted from a failed creation-time provisioner or tainted manually using `terraform taint`.
+
+## Multiple Provisioners
+
+Multiple provisioners can be specified within a resource. Multiple provisioners
+are executed in the order they're defined in the configuration file.
+
+You may also mix and match creation and destruction provisioners. Only
+the provisioners that are valid for a given operation will be run. Those
+valid provisioners will be run in the order they're defined in the configuration
+file.
+
+Example of multiple provisioners:
+
+```hcl
+resource "aws_instance" "web" {
+  # ...
+
+  provisioner "local-exec" {
+    command = "echo first"
+  }
+
+  provisioner "local-exec" {
+    command = "echo second"
+  }
+}
+```
+
+## Failure Behavior
+
+By default, provisioners that fail will also cause the Terraform apply
+itself to fail. The `on_failure` setting can be used to change this. The
+allowed values are:
+
+* `continue` - Ignore the error and continue with creation or destruction.
+
+* `fail` - Raise an error and stop applying (the default behavior). If this is a creation provisioner,
+  taint the resource.
+
+Example:
+
+```hcl
+resource "aws_instance" "web" {
+  # ...
+
+  provisioner "local-exec" {
+    command    = "echo The server's IP address is ${self.private_ip}"
+    on_failure = continue
+  }
+}
+```
diff --git a/v1.5.7/website/docs/language/resources/syntax.mdx b/v1.5.7/website/docs/language/resources/syntax.mdx
new file mode 100644
index 0000000..f72489f
--- /dev/null
+++ b/v1.5.7/website/docs/language/resources/syntax.mdx
@@ -0,0 +1,186 @@
+---
+page_title: Resources - Configuration Language
+description: >-
+  Resources correspond to infrastructure objects like virtual networks or
+  compute instances. Learn about resource types, syntax, behavior, and
+  arguments.
+---
+
+# Resource Blocks
+
+> **Hands-on:** Try the [Terraform: Get Started](/terraform/tutorials/aws-get-started?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorials.
+
+_Resources_ are the most important element in the Terraform language.
+Each resource block describes one or more infrastructure objects, such
+as virtual networks, compute instances, or higher-level components such
+as DNS records.
+
+## Resource Syntax
+
+Resource declarations can include a number of advanced features, but only
+a small subset are required for initial use. More advanced syntax features,
+such as single resource declarations that produce multiple similar remote
+objects, are described later in this page.
+
+```hcl
+resource "aws_instance" "web" {
+  ami           = "ami-a1b2c3d4"
+  instance_type = "t2.micro"
+}
+```
+
+A `resource` block declares a resource of a given type ("aws_instance")
+with a given local name ("web"). The name is used to refer to this resource
+from elsewhere in the same Terraform module, but has no significance outside
+that module's scope.
+
+The resource type and name together serve as an identifier for a given
+resource and so must be unique within a module.
+
+Within the block body (between `{` and `}`) are the configuration arguments
+for the resource itself. Most arguments in this section depend on the
+resource type, and indeed in this example both `ami` and `instance_type` are
+arguments defined specifically for [the `aws_instance` resource type](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance).
+
+-> **Note:** Resource names must start with a letter or underscore, and may
+contain only letters, digits, underscores, and dashes.
+
+## Resource Types
+
+Each resource is associated with a single _resource type_, which determines
+the kind of infrastructure object it manages and what arguments and other
+attributes the resource supports.
+
+### Providers
+
+Each resource type is implemented by a [provider](/terraform/language/providers/requirements),
+which is a plugin for Terraform that offers a collection of resource types. A
+provider usually provides resources to manage a single cloud or on-premises
+infrastructure platform. Providers are distributed separately from Terraform
+itself, but Terraform can automatically install most providers when initializing
+a working directory.
+
+In order to manage resources, a Terraform module must specify which providers it
+requires. Additionally, most providers need some configuration in order to
+access their remote APIs, and the root module must provide that configuration.
+
+For more information, see:
+
+- [Provider Requirements](/terraform/language/providers/requirements), for declaring which
+  providers a module uses.
+- [Provider Configuration](/terraform/language/providers/configuration), for configuring provider settings.
+
+Terraform usually automatically determines which provider to use based on a
+resource type's name. (By convention, resource type names start with their
+provider's preferred local name.) When using multiple configurations of a
+provider (or non-preferred local provider names), you must use the `provider`
+meta-argument to manually choose an alternate provider configuration. See
+[the `provider` meta-argument](/terraform/language/meta-arguments/resource-provider) for more details.
+
+### Resource Arguments
+
+Most of the arguments within the body of a `resource` block are specific to the
+selected resource type. The resource type's documentation lists which arguments
+are available and how their values should be formatted.
+
+The values for resource arguments can make full use of
+[expressions](/terraform/language/expressions) and other dynamic Terraform
+language features.
+
+There are also some _meta-arguments_ that are defined by Terraform itself
+and apply across all resource types. (See [Meta-Arguments](#meta-arguments) below.)
+
+### Documentation for Resource Types
+
+Every Terraform provider has its own documentation, describing its resource
+types and their arguments.
+
+Most publicly available providers are distributed on the
+[Terraform Registry](https://registry.terraform.io/browse/providers), which also
+hosts their documentation. When viewing a provider's page on the Terraform
+Registry, you can click the "Documentation" link in the header to browse its
+documentation. Provider documentation on the registry is versioned, and you can
+use the dropdown version menu in the header to switch which version's
+documentation you are viewing.
+
+To browse the publicly available providers and their documentation, see
+[the providers section of the Terraform Registry](https://registry.terraform.io/browse/providers).
+
+-> **Note:** Provider documentation previously existed as part of Terraform's core documentation. Although some provider documentation
+might still be hosted here, the Terraform Registry is now the main home for all
+public provider docs.
+
+## Resource Behavior
+
+For more information about how Terraform manages resources when applying a
+configuration, see
+[Resource Behavior](/terraform/language/resources/behavior).
+
+## Meta-Arguments
+
+The Terraform language defines several meta-arguments, which can be used with
+any resource type to change the behavior of resources.
+
+The following meta-arguments are documented on separate pages:
+
+- [`depends_on`, for specifying hidden dependencies](/terraform/language/meta-arguments/depends_on)
+- [`count`, for creating multiple resource instances according to a count](/terraform/language/meta-arguments/count)
+- [`for_each`, to create multiple instances according to a map, or set of strings](/terraform/language/meta-arguments/for_each)
+- [`provider`, for selecting a non-default provider configuration](/terraform/language/meta-arguments/resource-provider)
+- [`lifecycle`, for lifecycle customizations](/terraform/language/meta-arguments/lifecycle)
+- [`provisioner`, for taking extra actions after resource creation](/terraform/language/resources/provisioners/syntax)
+
+## Custom Condition Checks
+
+You can use `precondition` and `postcondition` blocks to specify assumptions and guarantees about how the resource operates. The following example creates a precondition that checks whether the AMI is properly configured.
+
+```hcl
+resource "aws_instance" "example" {
+  instance_type = "t2.micro"
+  ami           = "ami-abc123"
+
+  lifecycle {
+    # The AMI ID must refer to an AMI that contains an operating system
+    # for the `x86_64` architecture.
+    precondition {
+      condition     = data.aws_ami.example.architecture == "x86_64"
+      error_message = "The selected AMI must be for the x86_64 architecture."
+    }
+  }
+}
+```
+
+Custom conditions can help capture assumptions, helping future maintainers understand the configuration design and intent. They also return useful information about errors earlier and in context, helping consumers more easily diagnose issues in their configurations.
+
+Refer to [Custom Condition Checks](/terraform/language/expressions/custom-conditions#preconditions-and-postconditions) for more details.
+
+## Operation Timeouts
+
+Some resource types provide a special `timeouts` nested block argument that
+allows you to customize how long certain operations are allowed to take
+before being considered to have failed.
+For example, [`aws_db_instance`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_instance)
+allows configurable timeouts for `create`, `update` and `delete` operations.
+
+Timeouts are handled entirely by the resource type implementation in the
+provider, but resource types offering these features follow the convention
+of defining a child block called `timeouts` that has a nested argument
+named after each operation that has a configurable timeout value.
+Each of these arguments takes a string representation of a duration, such
+as `"60m"` for 60 minutes, `"10s"` for ten seconds, or `"2h"` for two hours.
+
+```hcl
+resource "aws_db_instance" "example" {
+  # ...
+
+  timeouts {
+    create = "60m"
+    delete = "2h"
+  }
+}
+```
+
+The set of configurable operations is chosen by each resource type. Most
+resource types do not support the `timeouts` block at all. Consult the
+documentation for each resource type to see which operations it offers
+for configuration, if any.
diff --git a/v1.5.7/website/docs/language/resources/terraform-data.mdx b/v1.5.7/website/docs/language/resources/terraform-data.mdx
new file mode 100644
index 0000000..4e82c44
--- /dev/null
+++ b/v1.5.7/website/docs/language/resources/terraform-data.mdx
@@ -0,0 +1,82 @@
+---
+page_title: The terraform_data Managed Resource Type
+description: >-
+  Retrieves the root module output values from a Terraform state snapshot stored
+  in a remote backend.
+---
+
+# The `terraform_data` Managed Resource Type
+
+The `terraform_data` implements the standard resource lifecycle, but does not directly take any other actions. 
+You can use the `terraform_data` resource without requiring or configuring a provider. It is always available through a built-in provider with the [source address](/terraform/language/providers/requirements#source-addresses) `terraform.io/builtin/terraform`.
+
+The `terraform_data` resource is useful for storing values which need to follow a manage resource lifecycle, and for triggering provisioners when there is no other logical managed resource in which to place them.
+
+
+## Example Usage (data for `replace_triggered_by`)
+
+
+[The `replace_triggered_by` lifecycle argument](/terraform/language/meta-arguments/lifecycle#replace_triggered_by) requires all of the given addresses to be for resources, because the decision to force replacement is based on the planned actions for all of the mentioned resources.
+
+Plain data values such as [Local Values](/terraform/language/values/locals) and [Input Variables](/terraform/language/values/variables) don't have any side-effects to plan against and so they aren't valid in `replace_triggered_by`. You can use `terraform_data`'s behavior of planning an action each time `input` changes to _indirectly_ use a plain value to trigger replacement.
+
+
+```hcl
+variable "revision" {
+  default = 1
+}
+
+resource "terraform_data" "replacement" {
+  input = var.revision
+}
+
+# This resource has no convenient attribute which forces replacement,
+# but can now be replaced by any change to the revision variable value.
+resource "example_database" "test" {
+  lifecycle {
+    replace_triggered_by = [terraform_data.replacement]
+  }
+}
+```
+
+## Example Usage (`null_resource` replacement)
+
+```hcl
+resource "aws_instance" "web" {
+  # ...
+}
+
+resource "aws_instance" "database" {
+  # ...
+}
+
+# A use-case for terraform_data is as a do-nothing container
+# for arbitrary actions taken by a provisioner.
+resource "terraform_data" "bootstrap" {
+  triggers_replace = [
+    aws_instance.web.id,
+    aws_instance.database.id
+  ]
+
+  provisioner "local-exec" {
+    command = "bootstrap-hosts.sh"
+  }
+}
+```
+
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `input` - (Optional) A value which will be stored in the instance state, and reflected in the `output` attribute after apply.
+
+* `triggers_replace` - (Optional) A value which is stored in the instance state, and will force replacement when the value changes.
+
+## Attributes Reference
+
+In addition to the above, the following attributes are exported:
+
+* `id` - A string value unique to the resource instance.
+
+* `output` - The computed value derived from the `input` argument. During a plan where `output` is unknown, it will still be of the same type as `input`.
diff --git a/v1.5.7/website/docs/language/settings/backends/azurerm.mdx b/v1.5.7/website/docs/language/settings/backends/azurerm.mdx
new file mode 100644
index 0000000..a739b01
--- /dev/null
+++ b/v1.5.7/website/docs/language/settings/backends/azurerm.mdx
@@ -0,0 +1,332 @@
+---
+page_title: 'Backend Type: azurerm'
+description: Terraform can store state remotely in Azure Blob Storage.
+---
+
+# azurerm
+
+Stores the state as a Blob with the given Key within the Blob Container within [the Blob Storage Account](https://docs.microsoft.com/en-us/azure/storage/common/storage-introduction).
+
+This backend supports state locking and consistency checking with Azure Blob Storage native capabilities.
+
+~> **Terraform 1.1 and 1.2 supported a feature-flag to allow enabling/disabling the use of Microsoft Graph (and MSAL) rather than Azure Active Directory Graph (and ADAL) - however this flag has since been removed in Terraform 1.3. Microsoft Graph (and MSAL) are now enabled by default and Azure Active Directory Graph (and ADAL) can no longer be used.
+
+## Example Configuration
+
+When authenticating using the Azure CLI or a Service Principal (either with a Client Certificate or a Client Secret):
+
+```hcl
+terraform {
+  backend "azurerm" {
+    resource_group_name  = "StorageAccount-ResourceGroup"
+    storage_account_name = "abcd1234"
+    container_name       = "tfstate"
+    key                  = "prod.terraform.tfstate"
+  }
+}
+```
+
+***
+
+When authenticating using Managed Service Identity (MSI):
+
+```hcl
+terraform {
+  backend "azurerm" {
+    resource_group_name  = "StorageAccount-ResourceGroup"
+    storage_account_name = "abcd1234"
+    container_name       = "tfstate"
+    key                  = "prod.terraform.tfstate"
+    use_msi              = true
+    subscription_id      = "00000000-0000-0000-0000-000000000000"
+    tenant_id            = "00000000-0000-0000-0000-000000000000"
+  }
+}
+```
+
+***
+
+When authenticating using OpenID Connect (OIDC):
+
+```hcl
+terraform {
+  backend "azurerm" {
+    resource_group_name  = "StorageAccount-ResourceGroup"
+    storage_account_name = "abcd1234"
+    container_name       = "tfstate"
+    key                  = "prod.terraform.tfstate"
+    use_oidc             = true
+    subscription_id      = "00000000-0000-0000-0000-000000000000"
+    tenant_id            = "00000000-0000-0000-0000-000000000000"
+  }
+}
+```
+
+***
+
+When authenticating using Azure AD Authentication:
+
+```hcl
+terraform {
+  backend "azurerm" {
+    storage_account_name = "abcd1234"
+    container_name       = "tfstate"
+    key                  = "prod.terraform.tfstate"
+    use_azuread_auth     = true
+    subscription_id      = "00000000-0000-0000-0000-000000000000"
+    tenant_id            = "00000000-0000-0000-0000-000000000000"
+  }
+}
+```
+
+-> **Note:** When using AzureAD for Authentication to Storage you also need to ensure the `Storage Blob Data Owner` role is assigned.
+
+***
+
+When authenticating using the Access Key associated with the Storage Account:
+
+```hcl
+terraform {
+  backend "azurerm" {
+    storage_account_name = "abcd1234"
+    container_name       = "tfstate"
+    key                  = "prod.terraform.tfstate"
+
+    # rather than defining this inline, the Access Key can also be sourced
+    # from an Environment Variable - more information is available below.
+    access_key = "abcdefghijklmnopqrstuvwxyz0123456789..."
+  }
+}
+```
+
+***
+
+When authenticating using a SAS Token associated with the Storage Account:
+
+```hcl
+terraform {
+  backend "azurerm" {
+    storage_account_name = "abcd1234"
+    container_name       = "tfstate"
+    key                  = "prod.terraform.tfstate"
+
+    # rather than defining this inline, the SAS Token can also be sourced
+    # from an Environment Variable - more information is available below.
+    sas_token = "abcdefghijklmnopqrstuvwxyz0123456789..."
+  }
+}
+```
+
+-> **NOTE:** When using a Service Principal or an Access Key - we recommend using a [Partial Configuration](/terraform/language/settings/backends/configuration#partial-configuration) for the credentials.
+
+## Data Source Configuration
+
+When authenticating using a Service Principal (either with a Client Certificate or a Client Secret):
+
+```hcl
+data "terraform_remote_state" "foo" {
+  backend = "azurerm"
+  config = {
+    storage_account_name = "terraform123abc"
+    container_name       = "terraform-state"
+    key                  = "prod.terraform.tfstate"
+  }
+}
+```
+
+***
+
+When authenticating using Managed Service Identity (MSI):
+
+```hcl
+data "terraform_remote_state" "foo" {
+  backend = "azurerm"
+  config = {
+    resource_group_name  = "StorageAccount-ResourceGroup"
+    storage_account_name = "terraform123abc"
+    container_name       = "terraform-state"
+    key                  = "prod.terraform.tfstate"
+    use_msi              = true
+    subscription_id      = "00000000-0000-0000-0000-000000000000"
+    tenant_id            = "00000000-0000-0000-0000-000000000000"
+  }
+}
+```
+
+***
+
+When authenticating using OpenID Connect (OIDC):
+
+```hcl
+data "terraform_remote_state" "foo" {
+  backend = "azurerm"
+  config = {
+    resource_group_name  = "StorageAccount-ResourceGroup"
+    storage_account_name = "terraform123abc"
+    container_name       = "terraform-state"
+    key                  = "prod.terraform.tfstate"
+    use_oidc             = true
+    subscription_id      = "00000000-0000-0000-0000-000000000000"
+    tenant_id            = "00000000-0000-0000-0000-000000000000"
+  }
+}
+```
+
+***
+
+When authenticating using AzureAD Authentication:
+
+```hcl
+data "terraform_remote_state" "foo" {
+  backend = "azurerm"
+  config = {
+    storage_account_name = "terraform123abc"
+    container_name       = "terraform-state"
+    key                  = "prod.terraform.tfstate"
+    use_azuread_auth     = true
+    subscription_id      = "00000000-0000-0000-0000-000000000000"
+    tenant_id            = "00000000-0000-0000-0000-000000000000"
+  }
+}
+```
+
+-> **Note:** When using AzureAD for Authentication to Storage you also need to ensure the `Storage Blob Data Owner` role is assigned.
+
+***
+
+When authenticating using the Access Key associated with the Storage Account:
+
+```hcl
+data "terraform_remote_state" "foo" {
+  backend = "azurerm"
+  config = {
+    storage_account_name = "terraform123abc"
+    container_name       = "terraform-state"
+    key                  = "prod.terraform.tfstate"
+
+    # rather than defining this inline, the Access Key can also be sourced
+    # from an Environment Variable - more information is available below.
+    access_key = "abcdefghijklmnopqrstuvwxyz0123456789..."
+  }
+}
+```
+
+***
+
+When authenticating using a SAS Token associated with the Storage Account:
+
+```hcl
+data "terraform_remote_state" "foo" {
+  backend = "azurerm"
+  config = {
+    storage_account_name = "terraform123abc"
+    container_name       = "terraform-state"
+    key                  = "prod.terraform.tfstate"
+
+    # rather than defining this inline, the SAS Token can also be sourced
+    # from an Environment Variable - more information is available below.
+    sas_token = "abcdefghijklmnopqrstuvwxyz0123456789..."
+  }
+}
+```
+
+## Configuration Variables
+
+!> **Warning:**  We recommend using environment variables to supply credentials and other sensitive data. If you use `-backend-config` or hardcode these values directly in your configuration, Terraform will include these values in both the `.terraform` subdirectory and in plan files. Refer to [Credentials and Sensitive Data](/terraform/language/settings/backends/configuration#credentials-and-sensitive-data) for details.
+
+
+The following configuration options are supported:
+
+* `storage_account_name` - (Required) The Name of [the Storage Account](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account).
+
+* `container_name` - (Required) The Name of [the Storage Container](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_container) within the Storage Account.
+
+* `key` - (Required) The name of the Blob used to retrieve/store Terraform's State file inside the Storage Container.
+
+* `environment` - (Optional) The Azure Environment which should be used. This can also be sourced from the `ARM_ENVIRONMENT` environment variable. Possible values are `public`, `china`, `german`, `stack` and `usgovernment`. Defaults to `public`.
+
+* `endpoint` - (Optional) The Custom Endpoint for Azure Resource Manager. This can also be sourced from the `ARM_ENDPOINT` environment variable.
+
+~> **NOTE:** An `endpoint` should only be configured when using Azure Stack.
+
+* `metadata_host` - (Optional) The Hostname of the Azure Metadata Service (for example `management.azure.com`), used to obtain the Cloud Environment when using a Custom Azure Environment. This can also be sourced from the `ARM_METADATA_HOSTNAME` Environment Variable.
+
+* `snapshot` - (Optional) Should the Blob used to store the Terraform Statefile be snapshotted before use? Defaults to `false`. This value can also be sourced from the `ARM_SNAPSHOT` environment variable.
+
+***
+
+When authenticating using the Managed Service Identity (MSI) - the following fields are also supported:
+
+* `resource_group_name` - (Required) The Name of the Resource Group in which the Storage Account exists.
+
+* `msi_endpoint` - (Optional) The path to a custom Managed Service Identity endpoint which is automatically determined if not specified. This can also be sourced from the `ARM_MSI_ENDPOINT` environment variable.
+
+* `subscription_id` - (Optional) The Subscription ID in which the Storage Account exists. This can also be sourced from the `ARM_SUBSCRIPTION_ID` environment variable.
+
+* `tenant_id` - (Optional) The Tenant ID in which the Subscription exists. This can also be sourced from the `ARM_TENANT_ID` environment variable.
+
+* `use_msi` - (Optional) Should Managed Service Identity authentication be used? This can also be sourced from the `ARM_USE_MSI` environment variable.
+
+***
+
+When authenticating using a Service Principal with OpenID Connect (OIDC) - the following fields are also supported:
+
+* `oidc_request_url` - (Optional) The URL for the OIDC provider from which to request an ID token. This can also be sourced from the `ARM_OIDC_REQUEST_URL` or `ACTIONS_ID_TOKEN_REQUEST_URL` environment variables.
+
+* `oidc_request_token` - (Optional) The bearer token for the request to the OIDC provider. This can also be sourced from the `ARM_OIDC_REQUEST_TOKEN` or `ACTIONS_ID_TOKEN_REQUEST_TOKEN` environment variables.
+
+* `oidc_token` - (Optional) The ID token when authenticating using OpenID Connect (OIDC). This can also be sourced from the `ARM_OIDC_TOKEN` environment variable.
+
+* `oidc_token_file_path` - (Optional) The path to a file containing an ID token when authenticating using OpenID Connect (OIDC). This can also be sourced from the `ARM_OIDC_TOKEN_FILE_PATH` environment variable.
+
+* `use_oidc` - (Optional) Should OIDC authentication be used? This can also be sourced from the `ARM_USE_OIDC` environment variable.
+
+***
+
+When authenticating using a SAS Token associated with the Storage Account - the following fields are also supported:
+
+* `sas_token` - (Optional) The SAS Token used to access the Blob Storage Account. This can also be sourced from the `ARM_SAS_TOKEN` environment variable.
+
+***
+
+When authenticating using the Storage Account's Access Key - the following fields are also supported:
+
+* `access_key` - (Optional) The Access Key used to access the Blob Storage Account. This can also be sourced from the `ARM_ACCESS_KEY` environment variable.
+
+***
+
+When authenticating using AzureAD Authentication - the following fields are also supported:
+
+* `use_azuread_auth` - (Optional) Should AzureAD Authentication be used to access the Blob Storage Account. This can also be sourced from the `ARM_USE_AZUREAD` environment variable.
+
+-> **Note:** When using AzureAD for Authentication to Storage you also need to ensure the `Storage Blob Data Owner` role is assigned.
+
+***
+
+When authenticating using a Service Principal with a Client Certificate - the following fields are also supported:
+
+* `resource_group_name` - (Required) The Name of the Resource Group in which the Storage Account exists.
+
+* `client_id` - (Optional) The Client ID of the Service Principal. This can also be sourced from the `ARM_CLIENT_ID` environment variable.
+
+* `client_certificate_password` - (Optional) The password associated with the Client Certificate specified in `client_certificate_path`. This can also be sourced from the `ARM_CLIENT_CERTIFICATE_PASSWORD` environment variable.
+
+* `client_certificate_path` - (Optional) The path to the PFX file used as the Client Certificate when authenticating as a Service Principal. This can also be sourced from the `ARM_CLIENT_CERTIFICATE_PATH` environment variable.
+
+* `subscription_id` - (Optional) The Subscription ID in which the Storage Account exists. This can also be sourced from the `ARM_SUBSCRIPTION_ID` environment variable.
+
+* `tenant_id` - (Optional) The Tenant ID in which the Subscription exists. This can also be sourced from the `ARM_TENANT_ID` environment variable.
+
+***
+
+When authenticating using a Service Principal with a Client Secret - the following fields are also supported:
+
+* `resource_group_name` - (Required) The Name of the Resource Group in which the Storage Account exists.
+
+* `client_id` - (Optional) The Client ID of the Service Principal. This can also be sourced from the `ARM_CLIENT_ID` environment variable.
+
+* `client_secret` - (Optional) The Client Secret of the Service Principal. This can also be sourced from the `ARM_CLIENT_SECRET` environment variable.
+
+* `subscription_id` - (Optional) The Subscription ID in which the Storage Account exists. This can also be sourced from the `ARM_SUBSCRIPTION_ID` environment variable.
+
+* `tenant_id` - (Optional) The Tenant ID in which the Subscription exists. This can also be sourced from the `ARM_TENANT_ID` environment variable.
diff --git a/v1.5.7/website/docs/language/settings/backends/configuration.mdx b/v1.5.7/website/docs/language/settings/backends/configuration.mdx
new file mode 100644
index 0000000..3213926
--- /dev/null
+++ b/v1.5.7/website/docs/language/settings/backends/configuration.mdx
@@ -0,0 +1,204 @@
+---
+page_title: Backend Configuration - Configuration Language
+description: >-
+  Use the `backend` block to control where Terraform stores state. Learn about the available state backends, the backend block, initializing backends, partial backend configuration, changing backend configuration, and unconfiguring a backend.
+---
+
+# Backend Configuration
+
+A backend defines where Terraform stores its [state](/terraform/language/state) data files.
+
+Terraform uses persisted state data to keep track of the resources it manages. Most non-trivial Terraform configurations either [integrate with Terraform Cloud](/terraform/language/settings/terraform-cloud) or use a backend to store state remotely. This lets multiple people access the state data and work together on that collection of infrastructure resources.
+
+This page describes how to configure a backend by adding the [`backend` block](#using-a-backend-block) to your configuration.
+
+-> **Note:** In Terraform versions before 1.1.0, we classified backends as standard or enhanced. The enhanced label differentiated the [`remote` backend](/terraform/language/settings/backends/remote), which could both store state and perform Terraform operations. This classification has been removed. Refer to [Using Terraform Cloud](/terraform/cli/cloud) for details about storing state, executing remote operations, and using Terraform Cloud directly from Terraform.
+
+## Available Backends
+
+By default, Terraform uses a backend called [`local`](/terraform/language/settings/backends/local), which stores state as a local file on disk. You can also configure one of the built-in backends included in this documentation.
+
+Some of these backends act like plain remote disks for state files, while others support locking the state while operations are being performed. This helps prevent conflicts and inconsistencies. The built-in backends listed are the only backends. You cannot load additional backends as plugins.
+
+-> **Note:** We removed the `artifactory`, `etcd`, `etcdv3`, `manta`, and `swift` backends in Terraform v1.3. Information about their behavior in older versions is still available in the [Terraform v1.2 documentation](/terraform/language/v1.2.x/settings/backends/configuration). For migration paths from these removed backends, refer to [Upgrading to Terraform v1.3](/terraform/language/v1.3.x/upgrade-guides).
+
+## Using a Backend Block
+
+You do not need to configure a backend when using Terraform Cloud because
+Terraform Cloud automatically manages state in the workspaces associated with your configuration. If your configuration includes a [`cloud` block](/terraform/language/settings/terraform-cloud), it cannot include a `backend` block.
+
+To configure a backend, add a nested `backend` block within the top-level
+`terraform` block. The following example configures the `remote` backend.
+
+```hcl
+terraform {
+  backend "remote" {
+    organization = "example_corp"
+
+    workspaces {
+      name = "my-app-prod"
+    }
+  }
+}
+```
+
+There are some important limitations on backend configuration:
+
+- A configuration can only provide one backend block.
+- A backend block cannot refer to named values (like input variables, locals, or data source attributes).
+
+### Credentials and Sensitive Data
+
+Backends store state in a remote service, which allows multiple people to access it. Accessing remote state generally requires access credentials, since state data contains extremely sensitive information.
+
+!> **Warning:**  We recommend using environment variables to supply credentials and other sensitive data. If you use `-backend-config` or hardcode these values directly in your configuration, Terraform will include these values in both the `.terraform` subdirectory and in plan files. This can leak sensitive credentials.
+
+Terraform writes the backend configuration in plain text in two separate files.
+- The `.terraform/terraform.tfstate` file contains the backend configuration for the current working directory.
+- All plan files capture the information in `.terraform/terraform.tfstate` at the time the plan was created. This helps ensure Terraform is applying the plan to correct set of infrastructure.
+
+When applying a plan that you previously saved to a file, Terraform uses the backend configuration stored in that file instead of the current backend settings. If that configuration contains time-limited credentials, they may expire before you finish applying the plan. Use environment variables to pass credentials when you need to use different values between the plan and apply steps.
+
+### Backend Types
+
+The block label of the backend block (`"remote"`, in the example above) indicates which backend type to use. Terraform has a built-in selection of backends, and the configured backend must be available in the version of Terraform you are using.
+
+The arguments used in the block's body are specific to the chosen backend type; they configure where and how the backend will store the configuration's state, and in some cases configure other behavior.
+
+Some backends allow providing access credentials directly as part of the configuration for use in unusual situations, for pragmatic reasons. However, in normal use, we _do not_ recommend including access credentials as part of the backend configuration. Instead, leave those arguments completely unset and provide credentials using the credentials files or environment variables that are conventional for the target system, as described in the documentation for each backend.
+
+Refer to the page for each backend type for full details and that type's configuration arguments.
+
+### Default Backend
+
+If a configuration includes no backend block, Terraform defaults to using the `local` backend, which stores state as a plain file in the current working directory.
+
+## Initialization
+
+When you change a backend's configuration, you must run `terraform init` again
+to validate and configure the backend before you can perform any plans, applies,
+or state operations.
+
+After you initialize, Terraform creates a `.terraform/` directory locally. This directory contains the most recent backend configuration, including any authentication parameters you provided to the Terraform CLI. Do not check this directory into Git, as it may contain sensitive credentials for your remote backend.
+
+The local backend configuration is different and entirely separate from the `terraform.tfstate` file that contains [state data](/terraform/language/state) about your real-world infrastruture. Terraform stores the `terraform.tfstate` file in your remote backend.
+
+When you change backends, Terraform gives you the option to migrate
+your state to the new backend. This lets you adopt backends without losing
+any existing state.
+
+~> **Important:** Before migrating to a new backend, we strongly recommend manually backing up your state by copying your `terraform.tfstate` file
+to another location.
+
+## Partial Configuration
+
+You do not need to specify every required argument in the backend configuration.
+Omitting certain arguments may be desirable if some arguments are provided
+automatically by an automation script running Terraform. When some or all of
+the arguments are omitted, we call this a _partial configuration_.
+
+With a partial configuration, the remaining configuration arguments must be
+provided as part of [the initialization process](/terraform/cli/init).
+
+There are several ways to supply the remaining arguments:
+
+- **File**: A configuration file may be specified via the `init` command line.
+  To specify a file, use the `-backend-config=PATH` option when running
+  `terraform init`. If the file contains secrets it may be kept in
+  a secure data store, such as [Vault](https://www.vaultproject.io/),
+  in which case it must be downloaded to the local disk before running Terraform.
+
+- **Command-line key/value pairs**: Key/value pairs can be specified via the
+  `init` command line. Note that many shells retain command-line flags in a
+  history file, so this isn't recommended for secrets. To specify a single
+  key/value pair, use the `-backend-config="KEY=VALUE"` option when running
+  `terraform init`.
+
+- **Interactively**: Terraform will interactively ask you for the required
+  values, unless interactive input is disabled. Terraform will not prompt for
+  optional values.
+
+If backend settings are provided in multiple locations, the top-level
+settings are merged such that any command-line options override the settings
+in the main configuration and then the command-line options are processed
+in order, with later options overriding values set by earlier options.
+
+The final, merged configuration is stored on disk in the `.terraform`
+directory, which should be ignored from version control. This means that
+sensitive information can be omitted from version control, but it will be
+present in plain text on local disk when running Terraform.
+
+When using partial configuration, Terraform requires at a minimum that
+an empty backend configuration is specified in one of the root Terraform
+configuration files, to specify the backend type. For example:
+
+```hcl
+terraform {
+  backend "consul" {}
+}
+```
+
+### File
+
+A backend configuration file has the contents of the `backend` block as
+top-level attributes, without the need to wrap it in another `terraform`
+or `backend` block:
+
+```hcl
+address = "demo.consul.io"
+path    = "example_app/terraform_state"
+scheme  = "https"
+```
+
+`*.backendname.tfbackend` (e.g. `config.consul.tfbackend`) is the recommended
+naming pattern. Terraform will not prevent you from using other names but following
+this convention will help your editor understand the content and likely provide
+better editing experience as a result.
+
+### Command-line key/value pairs
+
+The same settings can alternatively be specified on the command line as
+follows:
+
+```
+$ terraform init \
+    -backend-config="address=demo.consul.io" \
+    -backend-config="path=example_app/terraform_state" \
+    -backend-config="scheme=https"
+```
+
+The Consul backend also requires a Consul access token. Per the recommendation
+above of omitting credentials from the configuration and using other mechanisms,
+the Consul token would be provided by setting either the `CONSUL_HTTP_TOKEN`
+or `CONSUL_HTTP_AUTH` environment variables. See the documentation of your
+chosen backend to learn how to provide credentials to it outside of its main
+configuration.
+
+## Changing Configuration
+
+You can change your backend configuration at any time. You can change
+both the configuration itself as well as the type of backend (for example
+from "consul" to "s3").
+
+Terraform will automatically detect any changes in your configuration
+and request a [reinitialization](/terraform/cli/init). As part of
+the reinitialization process, Terraform will ask if you'd like to migrate
+your existing state to the new configuration. This allows you to easily
+switch from one backend to another.
+
+If you're using multiple [workspaces](/terraform/language/state/workspaces),
+Terraform can copy all workspaces to the destination. If Terraform detects
+you have multiple workspaces, it will ask if this is what you want to do.
+
+If you're just reconfiguring the same backend, Terraform will still ask if you
+want to migrate your state. You can respond "no" in this scenario.
+
+## Unconfiguring a Backend
+
+If you no longer want to use any backend, you can simply remove the
+configuration from the file. Terraform will detect this like any other
+change and prompt you to [reinitialize](/terraform/cli/init).
+
+As part of the reinitialization, Terraform will ask if you'd like to migrate
+your state back down to normal local state. Once this is complete then
+Terraform is back to behaving as it does by default.
diff --git a/v1.5.7/website/docs/language/settings/backends/consul.mdx b/v1.5.7/website/docs/language/settings/backends/consul.mdx
new file mode 100644
index 0000000..2c4cf10
--- /dev/null
+++ b/v1.5.7/website/docs/language/settings/backends/consul.mdx
@@ -0,0 +1,58 @@
+---
+page_title: 'Backend Type: consul'
+description: Terraform can store state in Consul.
+---
+
+# consul
+
+Stores the state in the [Consul](https://www.consul.io/) KV store at a given path.
+
+This backend supports [state locking](/terraform/language/state/locking).
+
+## Example Configuration
+
+```hcl
+terraform {
+  backend "consul" {
+    address = "consul.example.com"
+    scheme  = "https"
+    path    = "full/path"
+  }
+}
+```
+
+Note that for the access credentials we recommend using a
+[partial configuration](/terraform/language/settings/backends/configuration#partial-configuration).
+
+## Data Source Configuration
+
+```hcl
+data "terraform_remote_state" "foo" {
+  backend = "consul"
+  config = {
+    path = "full/path"
+  }
+}
+```
+
+## Configuration Variables
+
+!> **Warning:**  We recommend using environment variables to supply credentials and other sensitive data. If you use `-backend-config` or hardcode these values directly in your configuration, Terraform will include these values in both the `.terraform` subdirectory and in plan files. Refer to [Credentials and Sensitive Data](/terraform/language/settings/backends/configuration#credentials-and-sensitive-data) for details.
+
+The following configuration options / environment variables are supported:
+
+- `path` - (Required) Path in the Consul KV store
+- `access_token` / `CONSUL_HTTP_TOKEN` - (Required) Access token
+- `address` / `CONSUL_HTTP_ADDR` - (Optional) DNS name and port of your Consul endpoint specified in the
+  format `dnsname:port`. Defaults to the local agent HTTP listener.
+- `scheme` - (Optional) Specifies what protocol to use when talking to the given
+  `address`, either `http` or `https`. SSL support can also be triggered
+  by setting then environment variable `CONSUL_HTTP_SSL` to `true`.
+- `datacenter` - (Optional) The datacenter to use. Defaults to that of the agent.
+- `http_auth` / `CONSUL_HTTP_AUTH` - (Optional) HTTP Basic Authentication credentials to be used when
+  communicating with Consul, in the format of either `user` or `user:pass`.
+- `gzip` - (Optional) `true` to compress the state data using gzip, or `false` (the default) to leave it uncompressed.
+- `lock` - (Optional) `false` to disable locking. This defaults to true, but will require session permissions with Consul and at least kv write permissions on `$path/.lock` to perform locking.
+- `ca_file` / `CONSUL_CACERT` - (Optional) A path to a PEM-encoded certificate authority used to verify the remote agent's certificate.
+- `cert_file` / `CONSUL_CLIENT_CERT` - (Optional) A path to a PEM-encoded certificate provided to the remote agent; requires use of `key_file`.
+- `key_file` / `CONSUL_CLIENT_KEY` - (Optional) A path to a PEM-encoded private key, required if `cert_file` is specified.
diff --git a/v1.5.7/website/docs/language/settings/backends/cos.mdx b/v1.5.7/website/docs/language/settings/backends/cos.mdx
new file mode 100644
index 0000000..67c5686
--- /dev/null
+++ b/v1.5.7/website/docs/language/settings/backends/cos.mdx
@@ -0,0 +1,106 @@
+---
+page_title: 'Backend Type: cos'
+description: >-
+  Terraform can store the state remotely, making it easier to version and work
+  with in a team.
+---
+
+# COS
+
+Stores the state as an object in a configurable prefix in a given bucket on [Tencent Cloud Object Storage](https://intl.cloud.tencent.com/product/cos) (COS).
+
+This backend supports [state locking](/terraform/language/state/locking).
+
+~> **Warning!** It is highly recommended that you enable [Object Versioning](https://intl.cloud.tencent.com/document/product/436/19883)
+on the COS bucket to allow for state recovery in the case of accidental deletions and human error.
+
+## Example Configuration
+
+```hcl
+terraform {
+  backend "cos" {
+    region = "ap-guangzhou"
+    bucket = "bucket-for-terraform-state-1258798060"
+    prefix = "terraform/state"
+  }
+}
+```
+
+This assumes we have a [COS Bucket](https://registry.terraform.io/providers/tencentcloudstack/tencentcloud/latest/docs/resources/cos_bucket) created named `bucket-for-terraform-state-1258798060`,
+Terraform state will be written into the file `terraform/state/terraform.tfstate`.
+
+## Data Source Configuration
+
+To make use of the COS remote state in another configuration, use the [`terraform_remote_state` data source](/terraform/language/state/remote-state-data).
+
+```hcl
+data "terraform_remote_state" "foo" {
+  backend = "cos"
+
+  config = {
+    region = "ap-guangzhou"
+    bucket = "bucket-for-terraform-state-1258798060"
+    prefix = "terraform/state"
+  }
+}
+```
+
+## Configuration Variables
+
+!> **Warning:**  We recommend using environment variables to supply credentials and other sensitive data. If you use `-backend-config` or hardcode these values directly in your configuration, Terraform will include these values in both the `.terraform` subdirectory and in plan files. Refer to [Credentials and Sensitive Data](/terraform/language/settings/backends/configuration#credentials-and-sensitive-data) for details.
+
+The following configuration options or environment variables are supported:
+
+- `secret_id` - (Optional) Secret id of Tencent Cloud. It supports environment variables `TENCENTCLOUD_SECRET_ID`.
+- `secret_key` - (Optional) Secret key of Tencent Cloud. It supports environment variables `TENCENTCLOUD_SECRET_KEY`.
+- `security_token` - (Optional) TencentCloud Security Token of temporary access credentials. It supports environment variables `TENCENTCLOUD_SECURITY_TOKEN`.
+- `region` - (Optional) The region of the COS bucket. It supports environment variables `TENCENTCLOUD_REGION`.
+- `bucket` - (Required) The name of the COS bucket. You shall manually create it first.
+- `prefix` - (Optional) The directory for saving the state file in bucket. Default to "env:".
+- `key` - (Optional) The path for saving the state file in bucket. Defaults to `terraform.tfstate`.
+- `encrypt` - (Optional) Whether to enable server side encryption of the state file. If it is true, COS will use 'AES256' encryption algorithm to encrypt state file.
+- `acl` - (Optional) Object ACL to be applied to the state file, allows `private` and `public-read`. Defaults to `private`.
+- `accelerate` - (Optional) Whether to enable global Acceleration. Defaults to `false`.
+
+### Assume Role
+If provided with an assume role, Terraform will attempt to assume this role using the supplied credentials.
+Assume role can be provided by adding an `assume_role` block in the cos backend block.
+
+- `assume_role` - (Optional) The `assume_role` block. If provided, terraform will attempt to assume this role using the supplied credentials.
+
+The details of `assume_role` block as following:
+- `role_arn` - (Required) The ARN of the role to assume. It can be sourced from the `TENCENTCLOUD_ASSUME_ROLE_ARN`.
+- `session_name` - (Required) The session name to use when making the AssumeRole call. It can be sourced from the `TENCENTCLOUD_ASSUME_ROLE_SESSION_NAME`.
+- `session_duration` - (Required) The duration of the session when making the AssumeRole call. Its value ranges from 0 to 43200(seconds), and default is 7200 seconds. It can be sourced from the `TENCENTCLOUD_ASSUME_ROLE_SESSION_DURATION`.
+- `policy` - (Optional) A more restrictive policy when making the AssumeRole call. Its content must not contains `principal` elements. Notice: more syntax references, please refer to: [policies syntax logic](https://intl.cloud.tencent.com/document/product/598/10603).
+
+Usage:
+
+```hcl
+terraform {
+  backend "cos" {
+    region = "ap-guangzhou"
+    bucket = "bucket-for-terraform-state-{appid}"
+    prefix = "terraform/state"
+    assume_role {
+      role_arn = "qcs::cam::uin/xxx:roleName/yyy"
+      session_name = "my-session-name"
+      session_duration = 3600
+    }
+  }
+}
+```
+
+In addition, these `assume_role` configurations can also be provided by environment variables.
+
+Usage:
+
+```shell
+$ export TENCENTCLOUD_SECRET_ID="my-secret-id"
+$ export TENCENTCLOUD_SECRET_KEY="my-secret-key"
+$ export TENCENTCLOUD_REGION="ap-guangzhou"
+$ export TENCENTCLOUD_ASSUME_ROLE_ARN="qcs::cam::uin/xxx:roleName/yyy"
+$ export TENCENTCLOUD_ASSUME_ROLE_SESSION_NAME="my-session-name"
+$ export TENCENTCLOUD_ASSUME_ROLE_SESSION_DURATION=3600
+$ terraform plan
+```
\ No newline at end of file
diff --git a/v1.5.7/website/docs/language/settings/backends/gcs.mdx b/v1.5.7/website/docs/language/settings/backends/gcs.mdx
new file mode 100644
index 0000000..9910da2
--- /dev/null
+++ b/v1.5.7/website/docs/language/settings/backends/gcs.mdx
@@ -0,0 +1,136 @@
+---
+page_title: 'Backend Type: gcs'
+description: >-
+  Terraform can store the state remotely, making it easier to version and work
+  with in a team.
+---
+
+# gcs
+
+Stores the state as an object in a configurable prefix in a pre-existing bucket on [Google Cloud Storage](https://cloud.google.com/storage/) (GCS).
+The bucket must exist prior to configuring the backend.
+
+This backend supports [state locking](/terraform/language/state/locking).
+
+~> **Warning!** It is highly recommended that you enable
+[Object Versioning](https://cloud.google.com/storage/docs/object-versioning)
+on the GCS bucket to allow for state recovery in the case of accidental deletions and human error.
+
+## Example Configuration
+
+```hcl
+terraform {
+  backend "gcs" {
+    bucket  = "tf-state-prod"
+    prefix  = "terraform/state"
+  }
+}
+```
+
+## Data Source Configuration
+
+```hcl
+data "terraform_remote_state" "foo" {
+  backend = "gcs"
+  config = {
+    bucket  = "terraform-state"
+    prefix  = "prod"
+  }
+}
+
+# Terraform >= 0.12
+resource "local_file" "foo" {
+  content  = data.terraform_remote_state.foo.outputs.greeting
+  filename = "${path.module}/outputs.txt"
+}
+
+# Terraform <= 0.11
+resource "local_file" "foo" {
+  content  = "${data.terraform_remote_state.foo.greeting}"
+  filename = "${path.module}/outputs.txt"
+}
+```
+
+## Authentication
+
+IAM Changes to buckets are [eventually consistent](https://cloud.google.com/storage/docs/consistency#eventually_consistent_operations) and may take upto a few minutes to take effect. Terraform will return 403 errors till it is eventually consistent.
+
+### Running Terraform on your workstation.
+
+If you are using terraform on your workstation, you will need to install the Google Cloud SDK and authenticate using [User Application Default
+Credentials](https://cloud.google.com/sdk/gcloud/reference/auth/application-default).
+
+User ADCs do [expire](https://developers.google.com/identity/protocols/oauth2#expiration) and you can refresh them by running `gcloud auth application-default login`.
+
+### Running Terraform on Google Cloud
+
+If you are running terraform on Google Cloud, you can configure that instance or cluster to use a [Google Service
+Account](https://cloud.google.com/compute/docs/authentication). This will allow Terraform to authenticate to Google Cloud without having to bake in a separate
+credential/authentication file. Make sure that the scope of the VM/Cluster is set to cloud-platform.
+
+### Running Terraform outside of Google Cloud
+
+If you are running terraform outside of Google Cloud, generate a service account key and set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable to
+the path of the service account key. Terraform will use that key for authentication.
+
+### Impersonating Service Accounts
+
+Terraform can impersonate a Google Service Account as described [here](https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials). A valid credential must be provided as mentioned in the earlier section and that identity must have the `roles/iam.serviceAccountTokenCreator` role on the service account you are impersonating.
+
+## Encryption
+
+!> **Warning:** Take care of your encryption keys because state data encrypted with a lost or deleted key is not recoverable. If you use customer-supplied encryption keys, you must securely manage your keys and ensure you do not lose them. You must not delete customer-managed encryption keys in Cloud KMS used to encrypt state. However, if you accidentally delete a key, there is a time window where [you can recover it](https://cloud.google.com/kms/docs/destroy-restore#restore).
+
+### Customer-supplied encryption keys
+
+To get started, follow this guide: [Use customer-supplied encryption keys](https://cloud.google.com/storage/docs/encryption/using-customer-supplied-keys)
+
+If you want to remove customer-supplied keys from your backend configuration or change to a different customer-supplied key, Terraform cannot perform a state migration automatically and manual intervention is necessary instead. This intervention is necessary because Google does not store customer-supplied encryption keys, any requests sent to the Cloud Storage API must supply them instead (see [Customer-supplied Encryption Keys](https://cloud.google.com/storage/docs/encryption/customer-supplied-keys)). At the time of state migration, the backend configuration loses the old key's details and Terraform cannot use the key during the migration process.
+
+~> **Important:** To migrate your state away from using customer-supplied encryption keys or change the key used by your backend, you need to perform a [rewrite (gsutil CLI)](https://cloud.google.com/storage/docs/gsutil/commands/rewrite) or [cp (gcloud CLI)](https://cloud.google.com/sdk/gcloud/reference/storage/cp#--decryption-keys) operation to remove use of the old customer-supplied encryption key on your state file. Once you remove the encryption, you can successfully run `terraform init -migrate-state` with your new backend configuration.
+
+### Customer-managed encryption keys (Cloud KMS)
+
+To get started, follow this guide: [Use customer-managed encryption keys](https://cloud.google.com/storage/docs/encryption/using-customer-managed-keys)
+
+If you want to remove customer-managed keys from your backend configuration or change to a different customer-managed key, Terraform _can_ manage a state migration without manual intervention. This ability is because GCP stores customer-managed encryption keys and are accessible during the state migration process. However, these changes do not fully come into effect until the first write operation occurs on the state file after state migration occurs. In the first write operation after state migration, the file decrypts with the old key and then writes with the new encryption method. This method is equivalent to the [rewrite](https://cloud.google.com/storage/docs/gsutil/commands/rewrite) operation described in the customer-supplied encryption keys section. Because of the importance of the first write to state after state migration, you should not delete old KMS keys until any state file(s) encrypted with that key update.
+
+Customer-managed keys do not need to be sent in requests to read files from GCS buckets because decryption occurs automatically within GCS. This process means that if you use the `terraform_remote_state` [data source](/terraform/language/state/remote-state-data) to access KMS-encrypted state, you do not need to specify the KMS key in the data source's `config` object. 
+
+~> **Important:** To use customer-managed encryption keys, you need to create a key and give your project's GCS service agent permission to use it with the Cloud KMS CryptoKey Encrypter/Decrypter predefined role. 
+
+## Configuration Variables
+
+!> **Warning:**  We recommend using environment variables to supply credentials and other sensitive data. If you use `-backend-config` or hardcode these values directly in your configuration, Terraform includes these values in both the `.terraform` subdirectory and in plan files. Refer to [Credentials and Sensitive Data](/terraform/language/settings/backends/configuration#credentials-and-sensitive-data) for details.
+
+The following configuration options are supported:
+
+- `bucket` - (Required) The name of the GCS bucket.  This name must be
+  globally unique.  For more information, see [Bucket Naming
+  Guidelines](https://cloud.google.com/storage/docs/bucketnaming.html#requirements).
+- `credentials` / `GOOGLE_BACKEND_CREDENTIALS` / `GOOGLE_CREDENTIALS` -
+  (Optional) Local path to Google Cloud Platform account credentials in JSON
+  format. If unset, the path uses [Google Application Default Credentials](https://developers.google.com/identity/protocols/application-default-credentials).  The provided credentials must have the Storage Object Admin role on the bucket.
+  **Warning**: if using the Google Cloud Platform provider as well, it will
+  also pick up the `GOOGLE_CREDENTIALS` environment variable.
+- `impersonate_service_account` / `GOOGLE_BACKEND_IMPERSONATE_SERVICE_ACCOUNT` / `GOOGLE_IMPERSONATE_SERVICE_ACCOUNT` - (Optional) The service account to impersonate for accessing the State Bucket.
+  You must have `roles/iam.serviceAccountTokenCreator` role on that account for the impersonation to succeed.
+  If you are using a delegation chain, you can specify that using the `impersonate_service_account_delegates` field.
+- `impersonate_service_account_delegates` - (Optional) The delegation chain for an impersonating a service account as described [here](https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials#sa-credentials-delegated).
+- `access_token` - (Optional) A temporary \[OAuth 2.0 access token] obtained
+  from the Google Authorization server, i.e. the `Authorization: Bearer` token
+  used to authenticate HTTP requests to GCP APIs. This is an alternative to
+  `credentials`. If both are specified, `access_token` will be used over the
+  `credentials` field.
+- `prefix` - (Optional) GCS prefix inside the bucket. Named states for
+  workspaces are stored in an object called `<prefix>/<name>.tfstate`.
+- `encryption_key` / `GOOGLE_ENCRYPTION_KEY` - (Optional) A 32 byte base64
+  encoded 'customer-supplied encryption key' used when reading and writing state files in the bucket. For
+  more information see [Customer-supplied Encryption
+  Keys](https://cloud.google.com/storage/docs/encryption/customer-supplied-keys).
+- `kms_encryption_key` / `GOOGLE_KMS_ENCRYPTION_KEY` - (Optional) A Cloud KMS key ('customer-managed encryption key')
+  used when reading and writing state files in the bucket.
+  Format should be `projects/{{project}}/locations/{{location}}/keyRings/{{keyRing}}/cryptoKeys/{{name}}`. 
+  For more information, including IAM requirements, see [Customer-managed Encryption 
+  Keys](https://cloud.google.com/storage/docs/encryption/customer-managed-keys).
+- `storage_custom_endpoint` / `GOOGLE_BACKEND_STORAGE_CUSTOM_ENDPOINT` / `GOOGLE_STORAGE_CUSTOM_ENDPOINT` - (Optional) A URL containing three parts: the protocol, the DNS name pointing to a Private Service Connect endpoint, and the path for the Cloud Storage API (`/storage/v1/b`, [see here](https://cloud.google.com/storage/docs/json_api/v1/buckets/get#http-request)). You can either use [a DNS name automatically made by the Service Directory](https://cloud.google.com/vpc/docs/configure-private-service-connect-apis#configure-p-dns) or a [custom DNS name](https://cloud.google.com/vpc/docs/configure-private-service-connect-apis#configure-dns-default) made by you. For example, if you create an endpoint called `xyz` and want to use the automatically-created DNS name, you should set the field value as `https://storage-xyz.p.googleapis.com/storage/v1/b`. For help creating a Private Service Connect endpoint using Terraform, [see this guide](https://cloud.google.com/vpc/docs/configure-private-service-connect-apis#terraform_1).
diff --git a/v1.5.7/website/docs/language/settings/backends/http.mdx b/v1.5.7/website/docs/language/settings/backends/http.mdx
new file mode 100644
index 0000000..041b64b
--- /dev/null
+++ b/v1.5.7/website/docs/language/settings/backends/http.mdx
@@ -0,0 +1,75 @@
+---
+page_title: 'Backend Type: http'
+description: Terraform can store state remotely at any valid HTTP endpoint.
+---
+
+# http
+
+Stores the state using a simple [REST](https://en.wikipedia.org/wiki/Representational_state_transfer) client.
+
+State will be fetched via GET, updated via POST, and purged with DELETE. The method used for updating is configurable.
+
+This backend optionally supports [state locking](/terraform/language/state/locking). When locking
+support is enabled it will use LOCK and UNLOCK requests providing the lock info in the body. The
+endpoint should return a 423: Locked or 409: Conflict with the holding lock info when it's already
+taken, 200: OK for success. Any other status will be considered an error. The ID of the holding lock
+info will be added as a query parameter to state updates requests.
+
+## Example Usage
+
+```hcl
+terraform {
+  backend "http" {
+    address = "http://myrest.api.com/foo"
+    lock_address = "http://myrest.api.com/foo"
+    unlock_address = "http://myrest.api.com/foo"
+  }
+}
+```
+
+## Data Source Configuration
+
+```hcl
+data "terraform_remote_state" "foo" {
+  backend = "http"
+  config = {
+    address = "http://my.rest.api.com"
+  }
+}
+```
+
+## Configuration Variables
+
+!> **Warning:**  We recommend using environment variables to supply credentials and other sensitive data. If you use `-backend-config` or hardcode these values directly in your configuration, Terraform will include these values in both the `.terraform` subdirectory and in plan files. Refer to [Credentials and Sensitive Data](/terraform/language/settings/backends/configuration#credentials-and-sensitive-data) for details.
+
+The following configuration options / environment variables are supported:
+
+- `address` / `TF_HTTP_ADDRESS` - (Required) The address of the REST endpoint
+- `update_method` / `TF_HTTP_UPDATE_METHOD` - (Optional) HTTP method to use
+  when updating state. Defaults to `POST`.
+- `lock_address` / `TF_HTTP_LOCK_ADDRESS` - (Optional) The address of the lock
+  REST endpoint. Defaults to disabled.
+- `lock_method` / `TF_HTTP_LOCK_METHOD` - (Optional) The HTTP method to use
+  when locking. Defaults to `LOCK`.
+- `unlock_address` / `TF_HTTP_UNLOCK_ADDRESS` - (Optional) The address of the
+  unlock REST endpoint. Defaults to disabled.
+- `unlock_method` / `TF_HTTP_UNLOCK_METHOD` - (Optional) The HTTP method to use
+  when unlocking. Defaults to `UNLOCK`.
+- `username` / `TF_HTTP_USERNAME` - (Optional) The username for HTTP basic
+  authentication
+- `password` / `TF_HTTP_PASSWORD` - (Optional) The password for HTTP basic
+  authentication
+- `skip_cert_verification` - (Optional) Whether to skip TLS verification.
+  Defaults to `false`.
+- `retry_max` / `TF_HTTP_RETRY_MAX` – (Optional) The number of HTTP request
+  retries. Defaults to `2`.
+- `retry_wait_min` / `TF_HTTP_RETRY_WAIT_MIN` – (Optional) The minimum time in
+  seconds to wait between HTTP request attempts. Defaults to `1`.
+- `retry_wait_max` / `TF_HTTP_RETRY_WAIT_MAX` – (Optional) The maximum time in
+  seconds to wait between HTTP request attempts. Defaults to `30`.
+
+For mTLS authentication, the following three options may be set:
+
+ - `client_certificate_pem` / `TF_HTTP_CLIENT_CERTIFICATE_PEM` - (Optional) A PEM-encoded certificate used by the server to verify the client during mutual TLS (mTLS) authentication.
+ - `client_private_key_pem` /`TF_HTTP_CLIENT_PRIVATE_KEY_PEM` - (Optional) A PEM-encoded private key, required if client_certificate_pem is specified.
+ - `client_ca_certificate_pem` / `TF_HTTP_CLIENT_CA_CERTIFICATE_PEM` - (Optional) A PEM-encoded CA certificate chain used by the client to verify server certificates during TLS authentication.
diff --git a/v1.5.7/website/docs/language/settings/backends/kubernetes.mdx b/v1.5.7/website/docs/language/settings/backends/kubernetes.mdx
new file mode 100644
index 0000000..262d99e
--- /dev/null
+++ b/v1.5.7/website/docs/language/settings/backends/kubernetes.mdx
@@ -0,0 +1,74 @@
+---
+page_title: 'Backend Type: Kubernetes'
+description: Terraform can store state remotely in Kubernetes and lock that state.
+---
+
+# kubernetes
+
+-> **Note:** This backend is limited by Kubernetes' maximum Secret size of 1MB. See [Secret restrictions](https://kubernetes.io/docs/concepts/configuration/secret/#restrictions) for details.
+
+Stores the state in a [Kubernetes secret](https://kubernetes.io/docs/concepts/configuration/secret/).
+
+This backend supports [state locking](/terraform/language/state/locking), with locking done using a Lease resource.
+
+## Example Configuration
+
+```hcl
+terraform {
+  backend "kubernetes" {
+    secret_suffix    = "state"
+    config_path      = "~/.kube/config"
+  }
+}
+```
+
+This assumes the user/service account running terraform has [permissions](https://kubernetes.io/docs/reference/access-authn-authz/authorization/) to read/write secrets in the [namespace](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/) used to store the secret.
+
+If the `config_path` or `config_paths` attribute is set the backend will attempt to use a [kubeconfig file](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/) to gain access to the cluster.
+
+If the `in_cluster_config` flag is set the backend will attempt to use a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) to access the cluster. This can be used if Terraform is being run from within a pod running in the Kubernetes cluster.
+
+For most use cases either `in_cluster_config`, `config_path`, or `config_paths` will need to be set. If all flags are set the configuration at `config_path` will be used.
+
+Note that for the access credentials we recommend using a [partial configuration](/terraform/language/settings/backends/configuration#partial-configuration).
+
+## Example Referencing
+
+```hcl
+data "terraform_remote_state" "foo" {
+  backend = "kubernetes"
+  config = {
+    secret_suffix    = "state"
+    load_config_file = true
+  }
+}
+```
+
+## Configuration Variables
+
+!> **Warning:**  We recommend using environment variables to supply credentials and other sensitive data. If you use `-backend-config` or hardcode these values directly in your configuration, Terraform will include these values in both the `.terraform` subdirectory and in plan files. Refer to [Credentials and Sensitive Data](/terraform/language/settings/backends/configuration#credentials-and-sensitive-data) for details.
+
+The following configuration options are supported:
+
+* `secret_suffix` - (Required) Suffix used when creating secrets. Secrets will be named in the format: `tfstate-{workspace}-{secret_suffix}`.
+* `labels` - (Optional) Map of additional labels to be applied to the secret and lease.
+* `namespace` - (Optional) Namespace to store the secret and lease in. Can be sourced from `KUBE_NAMESPACE`.
+* `in_cluster_config` - (Optional) Used to authenticate to the cluster from inside a pod. Can be sourced from `KUBE_IN_CLUSTER_CONFIG`.
+* `host` - (Optional) The hostname (in form of URI) of Kubernetes master. Can be sourced from `KUBE_HOST`. Defaults to `https://localhost`.
+* `username` - (Optional) The username to use for HTTP basic authentication when accessing the Kubernetes master endpoint. Can be sourced from `KUBE_USER`.
+* `password` - (Optional) The password to use for HTTP basic authentication when accessing the Kubernetes master endpoint. Can be sourced from `KUBE_PASSWORD`.
+* `insecure` - (Optional) Whether server should be accessed without verifying the TLS certificate. Can be sourced from `KUBE_INSECURE`. Defaults to `false`.
+* `client_certificate` - (Optional) PEM-encoded client certificate for TLS authentication. Can be sourced from `KUBE_CLIENT_CERT_DATA`.
+* `client_key` - (Optional) PEM-encoded client certificate key for TLS authentication. Can be sourced from `KUBE_CLIENT_KEY_DATA`.
+* `cluster_ca_certificate` - (Optional) PEM-encoded root certificates bundle for TLS authentication. Can be sourced from `KUBE_CLUSTER_CA_CERT_DATA`.
+* `config_path` - (Optional) Path to the kube config file. Can be sourced from `KUBE_CONFIG_PATH`.
+* `config_paths` - (Optional) List of paths to kube config files. Can be sourced from `KUBE_CONFIG_PATHS`.
+* `config_context` - (Optional) Context to choose from the config file. Can be sourced from `KUBE_CTX`.
+* `config_context_auth_info` - (Optional) Authentication info context of the kube config (name of the kubeconfig user, `--user` flag in `kubectl`). Can be sourced from `KUBE_CTX_AUTH_INFO`.
+* `config_context_cluster` - (Optional) Cluster context of the kube config (name of the kubeconfig cluster, `--cluster` flag in `kubectl`). Can be sourced from `KUBE_CTX_CLUSTER`.
+* `token` - (Optional) Token of your service account.  Can be sourced from `KUBE_TOKEN`.
+* `exec` - (Optional) Configuration block to use an [exec-based credential plugin](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins), e.g. call an external command to receive user credentials.
+  * `api_version` - (Required) API version to use when decoding the ExecCredentials resource, e.g. `client.authentication.k8s.io/v1beta1`.
+  * `command` - (Required) Command to execute.
+  * `args` - (Optional) List of arguments to pass when executing the plugin.
+  * `env` - (Optional) Map of environment variables to set when executing the plugin.
diff --git a/v1.5.7/website/docs/language/settings/backends/local.mdx b/v1.5.7/website/docs/language/settings/backends/local.mdx
new file mode 100644
index 0000000..32a9411
--- /dev/null
+++ b/v1.5.7/website/docs/language/settings/backends/local.mdx
@@ -0,0 +1,95 @@
+---
+page_title: 'Backend Type: local'
+description: >-
+  Terraform can store the state remotely, making it easier to version and work
+  with in a team.
+---
+
+# local
+
+**Kind: Enhanced**
+
+The local backend stores state on the local filesystem, locks that
+state using system APIs, and performs operations locally.
+
+## Example Configuration
+
+```hcl
+terraform {
+  backend "local" {
+    path = "relative/path/to/terraform.tfstate"
+  }
+}
+```
+
+## Data Source Configuration
+
+```hcl
+data "terraform_remote_state" "foo" {
+  backend = "local"
+
+  config = {
+    path = "${path.module}/../../terraform.tfstate"
+  }
+}
+```
+
+## Configuration variables
+
+The following configuration options are supported:
+
+* `path` - (Optional) The path to the `tfstate` file. This defaults to
+  "terraform.tfstate" relative to the root module by default.
+* `workspace_dir` - (Optional) The path to non-default workspaces.
+
+## Command Line Arguments
+
+~> This section describes legacy features that we've preserved for backward
+compatibility but that we no longer recommend. See below for more details.
+
+For configurations that include a `backend "local"` block or that default to
+the local backend by not specifying a backend at all, most commands that either
+read or write state snapshots from the backend accept the following
+additional arguments:
+
+* `-state=FILENAME` - overrides the state filename when _reading_ the prior
+  state snapshot.
+* `-state-out=FILENAME` - overrides the state filename when _writing_ new state
+  snapshots.
+
+  If you use `-state` without also using `-state-out` then Terraform will
+  use the `-state` filename for both `-state` and `-state-out`, which means
+  Terraform will overwrite the input file if it creates a new state snapshot.
+* `-backup=FILENAME` - overrides the default filename that the local backend
+  would normally choose dynamically to create backup files when it writes new
+  state.
+
+  If you use `-state` without also using `-backup` then Terraform will use
+  the `-state` filename as a filename prefix for generating a backup filename.
+  You can use `-backup=-` (that is, set the filename to just the ASCII
+  dash character) to disable the creation of backup files altogether.
+
+These three options are preserved for backward-compatibility with earlier
+workflows that predated the introduction of built-in remote state, where
+users would write wrapper scripts that fetch prior state before running
+Terraform and then save the new state after Terraform exits, in which case
+the three arguments would typically all be paths within a temporary
+directory used just for one operation.
+
+Because these old workflows predate the introduction of the possibility of
+[multiple workspaces](/terraform/language/state/workspaces), setting them
+overrides Terraform's usual behavior of selecting a different state filename
+based on the selected workspace. If you use all three of these options then
+the selected workspace has no effect on which filenames Terraform will select
+for state files, and so you'll need to select different filenames yourself if
+you wish to keep workspace state files distinct from one another.
+
+These three options have no effect for configurations that have a different
+backend type selected.
+
+We do not recommend using these options in new systems, even if you are running
+Terraform in automation. Instead,
+[select a different backend which supports remote state](/terraform/language/settings/backends/configuration) and configure it
+within your root module, which ensures that everyone working on your
+configuration will automatically retrieve and store state in the correct shared
+location without any special command line options.
diff --git a/v1.5.7/website/docs/language/settings/backends/oss.mdx b/v1.5.7/website/docs/language/settings/backends/oss.mdx
new file mode 100644
index 0000000..2498318
--- /dev/null
+++ b/v1.5.7/website/docs/language/settings/backends/oss.mdx
@@ -0,0 +1,135 @@
+---
+page_title: 'Backend Type: oss'
+description: Terraform can store state remotely in OSS and lock that state with OSS.
+---
+
+# OSS
+
+Stores the state as a given key in a given bucket on Stores
+[Alibaba Cloud OSS](https://www.alibabacloud.com/help/product/31815.htm).
+This backend also supports state locking and consistency checking via
+[Alibaba Cloud Table Store](https://www.alibabacloud.com/help/doc-detail/27280.htm), which can be enabled by setting
+the `tablestore_table` field to an existing TableStore table name.
+
+This backend supports [state locking](/terraform/language/state/locking) via TableStore.
+
+-> **Note:** The OSS backend is available from terraform version 0.12.2.
+
+## Example Configuration
+
+```hcl
+terraform {
+  backend "oss" {
+    bucket = "bucket-for-terraform-state"
+    prefix   = "path/mystate"
+    key   = "version-1.tfstate"
+    region = "cn-beijing"
+    tablestore_endpoint = "https://terraform-remote.cn-hangzhou.ots.aliyuncs.com"
+    tablestore_table = "statelock"
+  }
+}
+```
+
+This assumes we have a [OSS Bucket](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/oss_bucket) created called `bucket-for-terraform-state`,
+a [OTS Instance](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/ots_instance) called `terraform-remote` and
+a [OTS TableStore](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/ots_table) called `statelock`. The
+Terraform state will be written into the file `path/mystate/version-1.tfstate`. The `TableStore` must have a primary key named `LockID` of type `String`.
+
+## Data Source Configuration
+
+To make use of the OSS remote state in another configuration, use the
+[`terraform_remote_state` data
+source](/terraform/language/state/remote-state-data).
+
+```hcl
+terraform {
+  backend "oss" {
+    bucket = "remote-state-dns"
+    prefix = "mystate/state"
+    key    = "terraform.tfstate"
+    region = "cn-beijing"
+  }
+}
+```
+
+The `terraform_remote_state` data source will return all of the root outputs
+defined in the referenced remote state, an example output might look like:
+
+```
+data "terraform_remote_state" "network" {
+    backend   = "oss"
+    config    = {
+        bucket = "remote-state-dns"
+        key    = "terraform.tfstate"
+        prefix = "mystate/state"
+        region = "cn-beijing"
+    }
+    outputs   = {}
+    workspace = "default"
+}
+```
+
+## Configuration Variables
+
+!> **Warning:**  We recommend using environment variables to supply credentials and other sensitive data. If you use `-backend-config` or hardcode these values directly in your configuration, Terraform will include these values in both the `.terraform` subdirectory and in plan files. Refer to [Credentials and Sensitive Data](/terraform/language/settings/backends/configuration#credentials-and-sensitive-data) for details.
+
+The following configuration options or environment variables are supported:
+
+* `access_key` - (Optional) Alibaba Cloud access key. It supports environment variables `ALICLOUD_ACCESS_KEY` and  `ALICLOUD_ACCESS_KEY_ID`.
+
+* `secret_key` - (Optional) Alibaba Cloud secret access key. It supports environment variables `ALICLOUD_SECRET_KEY` and  `ALICLOUD_ACCESS_KEY_SECRET`.
+
+* `security_token` - (Optional) STS access token. It supports environment variable `ALICLOUD_SECURITY_TOKEN`.
+
+* `ecs_role_name` - (Optional, Available in 0.12.14+) The RAM Role Name attached on a ECS instance for API operations. You can retrieve this from the 'Access Control' section of the Alibaba Cloud console.
+
+* `region` - (Optional) The region of the OSS bucket. It supports environment variables `ALICLOUD_REGION` and `ALICLOUD_DEFAULT_REGION`.
+
+* `endpoint` - (Optional) A custom endpoint for the OSS API. It supports environment variables `ALICLOUD_OSS_ENDPOINT` and `OSS_ENDPOINT`.
+
+* `bucket` - (Required) The name of the OSS bucket.
+
+* `prefix` - (Opeional) The path directory of the state file will be stored. Default to "env:".
+
+* `key` - (Optional) The name of the state file. Defaults to `terraform.tfstate`.
+
+* `tablestore_endpoint` / `ALICLOUD_TABLESTORE_ENDPOINT` - (Optional) A custom endpoint for the TableStore API.
+
+* `tablestore_table` - (Optional) A TableStore table for state locking and consistency. The table must have a primary key named `LockID` of type `String`.
+
+* `sts_endpoint` - (Optional, Available in 1.0.11+) Custom endpoint for the AliCloud Security Token Service (STS) API. It supports environment variable `ALICLOUD_STS_ENDPOINT`.
+
+* `encrypt` - (Optional) Whether to enable server side
+  encryption of the state file. If it is true, OSS will use 'AES256' encryption algorithm to encrypt state file.
+
+* `acl` - (Optional) [Object
+  ACL](https://www.alibabacloud.com/help/doc-detail/52284.htm)
+  to be applied to the state file.
+
+* `shared_credentials_file` - (Optional, Available in 0.12.8+) This is the path to the shared credentials file. It can also be sourced from the `ALICLOUD_SHARED_CREDENTIALS_FILE` environment variable. If this is not set and a profile is specified, `~/.aliyun/config.json` will be used.
+
+* `profile` - (Optional, Available in 0.12.8+)  This is the Alibaba Cloud profile name as set in the shared credentials file. It can also be sourced from the `ALICLOUD_PROFILE` environment variable.
+
+* `assume_role_role_arn` - (Optional, Available in 1.1.0+) The ARN of the role to assume. If ARN is set to an empty string, it does not perform role switching. It supports the environment variable `ALICLOUD_ASSUME_ROLE_ARN`.
+  Terraform executes configuration on account with provided credentials.
+
+* `assume_role_policy` - (Optional, Available in 1.1.0+) A more restrictive policy to apply to the temporary credentials. This gives you a way to further restrict the permissions for the resulting temporary security credentials. You cannot use this policy to grant permissions that exceed those of the role that is being assumed.
+
+* `assume_role_session_name` - (Optional, Available in 1.1.0+) The session name to use when assuming the role. If omitted, 'terraform' is passed to the AssumeRole call as session name. It supports environment variable `ALICLOUD_ASSUME_ROLE_SESSION_NAME`.
+
+* `assume_role_session_expiration` - (Optional, Available in 1.1.0+) The time after which the established session for assuming role expires. Valid value range: \[900-3600] seconds. Default to 3600 (in this case Alibaba Cloud uses its own default value). It supports environment variable `ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION`.
+
+* `assume_role` - (**Deprecated as of 1.1.0+**, Available in 0.12.6+) If provided with a role ARN, will attempt to assume this role using the supplied credentials. It will be ignored when `assume_role_role_arn` is specified.
+
+  **Deprecated in favor of flattening assume_role_\* options**
+
+  * `role_arn` - (Required) The ARN of the role to assume. If ARN is set to an empty string, it does not perform role switching. It supports the environment variable `ALICLOUD_ASSUME_ROLE_ARN`.
+    Terraform executes configuration on account with provided credentials.
+
+  * `policy` - (Optional) A more restrictive policy to apply to the temporary credentials. This gives you a way to further restrict the permissions for the resulting temporary security credentials. You cannot use this policy to grant permissions that exceed those of the role that is being assumed.
+
+  * `session_name` - (Optional) The session name to use when assuming the role. If omitted, 'terraform' is passed to the AssumeRole call as session name. It supports environment variable `ALICLOUD_ASSUME_ROLE_SESSION_NAME`.
+
+  * `session_expiration` - (Optional) The time after which the established session for assuming role expires. Valid value range: \[900-3600] seconds. Default to 3600 (in this case Alibaba Cloud uses its own default value). It supports environment variable `ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION`.
+
+-> **Note:** If you want to store state in the custom OSS endpoint, you can specify an environment variable `OSS_ENDPOINT`, like "oss-cn-beijing-internal.aliyuncs.com"
diff --git a/v1.5.7/website/docs/language/settings/backends/pg.mdx b/v1.5.7/website/docs/language/settings/backends/pg.mdx
new file mode 100644
index 0000000..5dbf40b
--- /dev/null
+++ b/v1.5.7/website/docs/language/settings/backends/pg.mdx
@@ -0,0 +1,107 @@
+---
+page_title: 'Backend Type: pg'
+description: Terraform can store state remotely in a Postgres database with locking.
+---
+
+# pg
+
+Stores the state in a [Postgres database](https://www.postgresql.org) version 10 or newer.
+
+This backend supports [state locking](/terraform/language/state/locking).
+
+## Example Configuration
+
+```hcl
+terraform {
+  backend "pg" {
+    conn_str = "postgres://user:pass@db.example.com/terraform_backend"
+  }
+}
+```
+
+Before initializing the backend with `terraform init`, the database must already exist:
+
+```
+createdb terraform_backend
+```
+
+This `createdb` command is found in [Postgres client applications](https://www.postgresql.org/docs/10/reference-client.html) which are installed along with the database server.
+
+
+### Using environment variables
+
+We recommend using environment variables to configure the `pg` backend in order
+not to have sensitive credentials written to  disk and committed to source
+control.
+
+The `pg` backend supports the standard [`libpq` environment variables](https://www.postgresql.org/docs/current/libpq-envars.html).
+
+The backend can be configured either by giving the whole configuration as an
+environment variable:
+
+```hcl
+terraform {
+  backend "pg" {}
+}
+```
+
+```shellsession
+$ export PG_CONN_STR=postgres://user:pass@db.example.com/terraform_backend
+$ terraform init
+```
+
+or just the sensitive parameters:
+
+```hcl
+terraform {
+  backend "pg" {
+    conn_str = "postgres://db.example.com/terraform_backend"
+  }
+}
+```
+
+```shellsession
+$ export PGUSER=user
+$ read -s PGPASSWORD
+$ export PGPASSWORD
+$ terraform init
+```
+
+## Data Source Configuration
+
+To make use of the pg remote state in another configuration, use the [`terraform_remote_state` data source](/terraform/language/state/remote-state-data).
+
+```hcl
+data "terraform_remote_state" "network" {
+  backend = "pg"
+  config = {
+    conn_str = "postgres://localhost/terraform_backend"
+  }
+}
+```
+
+## Configuration Variables
+
+!> **Warning:**  We recommend using environment variables to supply credentials and other sensitive data. If you use `-backend-config` or hardcode these values directly in your configuration, Terraform will include these values in both the `.terraform` subdirectory and in plan files. Refer to [Credentials and Sensitive Data](/terraform/language/settings/backends/configuration#credentials-and-sensitive-data) for details.
+
+The following configuration options or environment variables are supported:
+
+- `conn_str` - Postgres connection string; a `postgres://` URL. The `PG_CONN_STR` and [standard `libpq`](https://www.postgresql.org/docs/current/libpq-envars.html) environment variables can also be used to indicate how to connect to the PostgreSQL database.
+- `schema_name` - Name of the automatically-managed Postgres schema, default to `terraform_remote_state`. Can also be set using the `PG_SCHEMA_NAME` environment variable.
+- `skip_schema_creation` - If set to `true`, the Postgres schema must already exist. Can also be set using the `PG_SKIP_SCHEMA_CREATION` environment variable. Terraform won't try to create the schema, this is useful when it has already been created by a database administrator.
+- `skip_table_creation` - If set to `true`, the Postgres table must already exist. Can also be set using the `PG_SKIP_TABLE_CREATION` environment variable. Terraform won't try to create the table, this is useful when it has already been created by a database administrator.
+- `skip_index_creation` - If set to `true`, the Postgres index must already exist. Can also be set using the `PG_SKIP_INDEX_CREATION` environment variable. Terraform won't try to create the index, this is useful when it has already been created by a database administrator.
+
+## Technical Design
+
+This backend creates one table **states** in the automatically-managed Postgres schema configured by the `schema_name` variable.
+
+The table is keyed by the [workspace](/terraform/language/state/workspaces) name. If workspaces are not in use, the name `default` is used.
+
+Locking is supported using [Postgres advisory locks](https://www.postgresql.org/docs/9.5/explicit-locking.html#ADVISORY-LOCKS). [`force-unlock`](/terraform/cli/commands/force-unlock) is not supported, because these database-native locks will automatically unlock when the session is aborted or the connection fails. To see outstanding locks in a Postgres server, use the [`pg_locks` system view](https://www.postgresql.org/docs/9.5/view-pg-locks.html).
+
+The **states** table contains:
+
+- a serial integer `id`, used as the key for advisory locks
+- the workspace `name` key as _text_ with a unique index
+- the Terraform state `data` as _text_
diff --git a/v1.5.7/website/docs/language/settings/backends/remote.mdx b/v1.5.7/website/docs/language/settings/backends/remote.mdx
new file mode 100644
index 0000000..4731590
--- /dev/null
+++ b/v1.5.7/website/docs/language/settings/backends/remote.mdx
@@ -0,0 +1,245 @@
+---
+page_title: 'Backend Type: remote'
+description: >-
+  Terraform can store the state and run operations remotely, making it easier to
+  version and work with in a team.
+---
+
+# remote
+
+-> **Note:** We introduced the remote backend in Terraform v0.11.13 and Terraform Enterprise v201809-1. As of Terraform v1.1.0 and Terraform Enterprise v202201-1, **we recommend using the Terraform Cloud's built-in [`cloud` integration](/terraform/cli/cloud/settings)** instead of this backend. The `cloud` option includes an improved user experience and more features.
+
+The remote backend is unique among all other Terraform backends because it can both store state snapshots and execute operations for Terraform Cloud's [CLI-driven run workflow](/terraform/cloud-docs/run/cli). It used to be called an "enhanced" backend.
+
+When using full remote operations, operations like `terraform plan` or `terraform apply` can be executed in Terraform
+Cloud's run environment, with log output streaming to the local terminal. Remote plans and applies use variable values from the associated Terraform Cloud workspace.
+
+You can also use Terraform Cloud with local operations, in which case only state is stored in the Terraform Cloud backend.
+
+## Command Support
+
+The remote backend supports the following Terraform commands:
+
+- `apply`
+- `console` (supported in Terraform >= v0.11.12)
+- `destroy`
+- `fmt`
+- `get`
+- `graph` (supported in Terraform >= v0.11.12)
+- `import` (supported in Terraform >= v0.11.12)
+- `init`
+- `output`
+- `plan`
+- `providers`
+- `show`
+- `state` (supports all sub-commands: list, mv, pull, push, rm, show)
+- `taint`
+- `untaint`
+- `validate`
+- `version`
+- `workspace`
+
+## Workspaces
+
+The remote backend can work with either a single remote Terraform Cloud workspace, or with multiple similarly-named remote workspaces (like `networking-dev` and `networking-prod`). The `workspaces` block of the backend configuration
+determines which mode it uses:
+
+- To use a single remote Terraform Cloud workspace, set `workspaces.name` to the
+  remote workspace's full name (like `networking-prod`).
+
+- To use multiple remote workspaces, set `workspaces.prefix` to a prefix used in
+  all of the desired remote workspace names. For example, set
+  `prefix = "networking-"` to use Terraform cloud workspaces with
+  names like `networking-dev` and `networking-prod`. This is helpful when
+  mapping multiple Terraform CLI [workspaces](/terraform/language/state/workspaces)
+  used in a single Terraform configuration to multiple Terraform Cloud
+  workspaces.
+
+
+The backend configuration requires either `name` or `prefix`. Omitting both or
+setting both results in a configuration error.
+
+If previous state is present when you run `terraform init` and the corresponding
+remote workspaces are empty or absent, Terraform will create workspaces and
+update the remote state accordingly. However, if your workspace requires variables or a specific version of Terraform for remote operations, we
+recommend that you create your remote workspaces on Terraform Cloud before
+running any remote operations against them.
+
+### Workspace Names
+
+Terraform uses shortened names without the common prefix to interact with workspaces on the command line. For example, if `prefix = "networking-"`, use `terraform workspace select prod` to switch to the Terraform CLI workspace `prod` within the current configuration. However, remote Terraform operations such as `plan` and `apply` for that Terraform CLI workspace will take place in the Terraform Cloud workspace `networking-prod`.
+
+Because of this, the [`terraform.workspace`](/terraform/language/state/workspaces#current-workspace-interpolation) interpolation expression produces different results depending on whether a remote workspace is configured to perform operations locally or remotely. For example, in a remote workspace called `networking-prod` created with `prefix = "networking-"` the expression produces the following:
+
+- For local operations, `terraform.workspace` = `prod`
+- For remote operations, `terraform.workspace`=  `networking-prod`
+
+Prior to Terraform version 1.1.0, Terraform Cloud workspaces used only the single `default` Terraform CLI workspace internally. So if a Terraform configuration used `terraform.workspace` to return `dev` or `prod`, remote runs in Terraform Cloud would always evaluate it as `default`, regardless of
+which workspace you set with the `terraform workspace select` command. Therefore, we do not recommend using `terraform.workspace` in Terraform configurations that use Terraform 1.0.x or earlier and run remote operations against Terraform Cloud workspaces.
+
+### Determining Run Environment
+
+If you need to determine whether a run is local or remote in your Terraform configuration, we recommend using [Terraform Cloud run environment variables](/terraform/cloud-docs/run/run-environment#environment-variables). The example below uses `TFC_RUN_ID`.
+
+```
+output "current_workspace_name" {
+  value = terraform.workspace
+}
+
+variable "TFC_RUN_ID" {
+  type    = string
+  default = ""
+}
+
+output "remote_execution_determine" {
+  value = "Remote run environment? %{if var.TFC_RUN_ID != ""}Yes%{else}No this is local%{endif}!"
+}
+```
+
+
+## Example Configurations
+
+->  **Note:** We recommend omitting the token from the configuration, and instead using
+[`terraform login`](/terraform/cli/commands/login) or manually configuring
+`credentials` in the [CLI config file](/terraform/cli/config/config-file#credentials).
+
+### Basic Configuration
+
+```hcl
+# Using a single workspace:
+terraform {
+  backend "remote" {
+    hostname = "app.terraform.io"
+    organization = "company"
+
+    workspaces {
+      name = "my-app-prod"
+    }
+  }
+}
+
+# Using multiple workspaces:
+terraform {
+  backend "remote" {
+    hostname = "app.terraform.io"
+    organization = "company"
+
+    workspaces {
+      prefix = "my-app-"
+    }
+  }
+}
+```
+
+### Using CLI Input
+
+```hcl
+# main.tf
+terraform {
+  required_version = "~> 0.12.0"
+
+  backend "remote" {}
+}
+```
+
+Backend configuration file:
+
+```hcl
+# config.remote.tfbackend
+workspaces { name = "workspace" }
+hostname     = "app.terraform.io"
+organization = "company"
+```
+
+Running `terraform init` with the backend file:
+
+```sh
+terraform init -backend-config=config.remote.tfbackend
+```
+
+### Data Source Configuration
+
+```hcl
+data "terraform_remote_state" "foo" {
+  backend = "remote"
+
+  config = {
+    organization = "company"
+
+    workspaces = {
+      name = "workspace"
+    }
+  }
+}
+```
+
+## Configuration Variables
+
+!> **Warning:**  We recommend using environment variables to supply credentials and other sensitive data. If you use `-backend-config` or hardcode these values directly in your configuration, Terraform will include these values in both the `.terraform` subdirectory and in plan files. Refer to [Credentials and Sensitive Data](/terraform/language/settings/backends/configuration#credentials-and-sensitive-data) for details.
+
+The following configuration options are supported:
+
+- `hostname` - (Optional) The remote backend hostname to connect to. Defaults
+  to app.terraform.io.
+- `organization` - (Required) The name of the organization containing the
+  targeted workspace(s).
+- `token` - (Optional) The token used to authenticate with the remote backend.
+  We recommend omitting the token from the configuration, and instead using
+  [`terraform login`](/terraform/cli/commands/login) or manually configuring
+  `credentials` in the
+  [CLI config file](/terraform/cli/config/config-file#credentials).
+- `workspaces` - (Required) A block specifying which remote workspace(s) to use.
+  The `workspaces` block supports the following keys:
+
+  - `name` - (Optional) The full name of one remote workspace. When configured,
+    only the default workspace can be used. This option conflicts with `prefix`.
+  - `prefix` - (Optional) A prefix used in the names of one or more remote
+    workspaces, all of which can be used with this configuration. The full
+    workspace names are used in Terraform Cloud, and the short names
+    (minus the prefix) are used on the command line for Terraform CLI workspaces.
+    If omitted, only the default workspace can be used. This option conflicts with `name`.
+
+->  **Note:** You must use the `name` key when configuring a `terraform_remote_state`
+data source that retrieves state from another Terraform Cloud workspace. The `prefix` key is only
+intended for use when configuring an instance of the remote backend.
+
+## Command Line Arguments
+
+For configurations that include a `backend "remote"` block, commands that
+make local modifications to Terraform state and then push them back up to
+the remote workspace accept the following option to modify that behavior:
+
+- `-ignore-remote-version` - Override checking that the local and remote
+  Terraform versions agree, making an operation proceed even when there is
+  a mismatch.
+
+  Normally state-modification operations require using a local version of
+  Terraform CLI which is compatible with the Terraform version selected
+  for the remote workspace as part of its settings. This is to avoid the
+  local operation creating a new state snapshot which the workspace's
+  remote execution environment would then be unable to decode.
+
+  Overriding this check can result in a Terraform Cloud workspace that is
+  no longer able to complete remote operations, so we recommend against
+  using this option.
+
+## Excluding Files from Upload with .terraformignore
+
+-> **Version note:** `.terraformignore` support was added in Terraform 0.12.11.
+
+When executing a remote `plan` or `apply` in a [CLI-driven run](/terraform/cloud-docs/run/cli),
+an archive of your configuration directory is uploaded to Terraform Cloud. You can define
+paths to ignore from upload via a `.terraformignore` file at the root of your configuration directory. If this file is not present, the archive will exclude the following by default:
+
+- `.git/` directories
+- `.terraform/` directories (exclusive of `.terraform/modules`)
+
+The `.terraformignore` file can include rules as one would include in a
+[`.gitignore` file](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository#_ignoring)
+
+- Comments (starting with `#`) or blank lines are ignored
+- End a pattern with a forward slash `/` to specify a directory
+- Negate a pattern by starting it with an exclamation point `!`
+
+Note that unlike `.gitignore`, only the `.terraformignore` at the root of the configuration
+directory is considered.
diff --git a/v1.5.7/website/docs/language/settings/backends/s3.mdx b/v1.5.7/website/docs/language/settings/backends/s3.mdx
new file mode 100644
index 0000000..1315215
--- /dev/null
+++ b/v1.5.7/website/docs/language/settings/backends/s3.mdx
@@ -0,0 +1,459 @@
+---
+page_title: 'Backend Type: s3'
+description: Terraform can store state remotely in S3 and lock that state with DynamoDB.
+---
+
+# S3
+
+Stores the state as a given key in a given bucket on
+[Amazon S3](https://aws.amazon.com/s3/).
+This backend also supports state locking and consistency checking via
+[Dynamo DB](https://aws.amazon.com/dynamodb/), which can be enabled by setting
+the `dynamodb_table` field to an existing DynamoDB table name.
+A single DynamoDB table can be used to lock multiple remote state files. Terraform generates key names that include the values of the `bucket` and `key` variables.
+
+~> **Warning!** It is highly recommended that you enable
+[Bucket Versioning](https://docs.aws.amazon.com/AmazonS3/latest/userguide/manage-versioning-examples.html)
+on the S3 bucket to allow for state recovery in the case of accidental deletions and human error.
+
+## Example Configuration
+
+```hcl
+terraform {
+  backend "s3" {
+    bucket = "mybucket"
+    key    = "path/to/my/key"
+    region = "us-east-1"
+  }
+}
+```
+
+This assumes we have a bucket created called `mybucket`. The
+Terraform state is written to the key `path/to/my/key`.
+
+Note that for the access credentials we recommend using a
+[partial configuration](/terraform/language/settings/backends/configuration#partial-configuration).
+
+### S3 Bucket Permissions
+
+Terraform will need the following AWS IAM permissions on
+the target backend bucket:
+
+* `s3:ListBucket` on `arn:aws:s3:::mybucket`
+* `s3:GetObject` on `arn:aws:s3:::mybucket/path/to/my/key`
+* `s3:PutObject` on `arn:aws:s3:::mybucket/path/to/my/key`
+* `s3:DeleteObject` on `arn:aws:s3:::mybucket/path/to/my/key`
+
+This is seen in the following AWS IAM Statement:
+
+```json
+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Effect": "Allow",
+      "Action": "s3:ListBucket",
+      "Resource": "arn:aws:s3:::mybucket"
+    },
+    {
+      "Effect": "Allow",
+      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
+      "Resource": "arn:aws:s3:::mybucket/path/to/my/key"
+    }
+  ]
+}
+```
+
+-> **Note:** AWS can control access to S3 buckets with either IAM policies
+attached to users/groups/roles (like the example above) or resource policies
+attached to bucket objects (which look similar but also require a `Principal` to
+indicate which entity has those permissions). For more details, see Amazon's
+documentation about
+[S3 access control](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html).
+
+### DynamoDB Table Permissions
+
+If you are using state locking, Terraform will need the following AWS IAM
+permissions on the DynamoDB table (`arn:aws:dynamodb:::table/mytable`):
+
+* `dynamodb:DescribeTable`
+* `dynamodb:GetItem`
+* `dynamodb:PutItem`
+* `dynamodb:DeleteItem`
+
+This is seen in the following AWS IAM Statement:
+
+```json
+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Effect": "Allow",
+      "Action": [
+        "dynamodb:DescribeTable",
+        "dynamodb:GetItem",
+        "dynamodb:PutItem",
+        "dynamodb:DeleteItem"
+      ],
+      "Resource": "arn:aws:dynamodb:*:*:table/mytable"
+    }
+  ]
+}
+```
+
+## Data Source Configuration
+
+To make use of the S3 remote state in another configuration, use the
+[`terraform_remote_state` data
+source](/terraform/language/state/remote-state-data).
+
+```hcl
+data "terraform_remote_state" "network" {
+  backend = "s3"
+  config = {
+    bucket = "terraform-state-prod"
+    key    = "network/terraform.tfstate"
+    region = "us-east-1"
+  }
+}
+```
+
+The `terraform_remote_state` data source will return all of the root module
+outputs defined in the referenced remote state (but not any outputs from
+nested modules unless they are explicitly output again in the root). An
+example output might look like:
+
+```
+data.terraform_remote_state.network:
+  id = 2016-10-29 01:57:59.780010914 +0000 UTC
+  addresses.# = 2
+  addresses.0 = 52.207.220.222
+  addresses.1 = 54.196.78.166
+  backend = s3
+  config.% = 3
+  config.bucket = terraform-state-prod
+  config.key = network/terraform.tfstate
+  config.region = us-east-1
+  elb_address = web-elb-790251200.us-east-1.elb.amazonaws.com
+  public_subnet_id = subnet-1e05dd33
+```
+
+## Configuration
+
+This backend requires the configuration of the AWS Region and S3 state storage. Other configuration, such as enabling DynamoDB state locking, is optional.
+
+### Credentials and Shared Configuration
+
+!> **Warning:**  We recommend using environment variables to supply credentials and other sensitive data. If you use `-backend-config` or hardcode these values directly in your configuration, Terraform will include these values in both the `.terraform` subdirectory and in plan files. Refer to [Credentials and Sensitive Data](/terraform/language/settings/backends/configuration#credentials-and-sensitive-data) for details.
+
+The following configuration is required:
+
+* `region` - (Required) AWS Region of the S3 Bucket and DynamoDB Table (if used). This can also be sourced from the `AWS_DEFAULT_REGION` and `AWS_REGION` environment variables.
+
+The following configuration is optional:
+
+* `access_key` - (Optional) AWS access key. If configured, must also configure `secret_key`. This can also be sourced from the `AWS_ACCESS_KEY_ID` environment variable, AWS shared credentials file (e.g. `~/.aws/credentials`), or AWS shared configuration file (e.g. `~/.aws/config`).
+* `secret_key` - (Optional) AWS access key. If configured, must also configure `access_key`. This can also be sourced from the `AWS_SECRET_ACCESS_KEY` environment variable, AWS shared credentials file (e.g. `~/.aws/credentials`), or AWS shared configuration file (e.g. `~/.aws/config`).
+* `iam_endpoint` - (Optional) Custom endpoint for the AWS Identity and Access Management (IAM) API. This can also be sourced from the `AWS_IAM_ENDPOINT` environment variable.
+* `max_retries` - (Optional) The maximum number of times an AWS API request is retried on retryable failure. Defaults to 5.
+* `profile` - (Optional) Name of AWS profile in AWS shared credentials file (e.g. `~/.aws/credentials`) or AWS shared configuration file (e.g. `~/.aws/config`) to use for credentials and/or configuration. This can also be sourced from the `AWS_PROFILE` environment variable.
+* `shared_credentials_file`  - (Optional) Path to the AWS shared credentials file. Defaults to `~/.aws/credentials`.
+* `skip_credentials_validation` - (Optional) Skip credentials validation via the STS API.
+* `skip_region_validation` - (Optional) Skip validation of provided region name.
+* `skip_metadata_api_check` - (Optional) Skip usage of EC2 Metadata API.
+* `sts_endpoint` - (Optional) Custom endpoint for the AWS Security Token Service (STS) API. This can also be sourced from the `AWS_STS_ENDPOINT` environment variable.
+* `token` - (Optional) Multi-Factor Authentication (MFA) token. This can also be sourced from the `AWS_SESSION_TOKEN` environment variable.
+
+#### Assume Role Configuration
+
+The following configuration is optional:
+
+* `assume_role_duration_seconds` - (Optional) Number of seconds to restrict the assume role session duration.
+* `assume_role_policy` - (Optional) IAM Policy JSON describing further restricting permissions for the IAM Role being assumed.
+* `assume_role_policy_arns` - (Optional) Set of Amazon Resource Names (ARNs) of IAM Policies describing further restricting permissions for the IAM Role being assumed.
+* `assume_role_tags` - (Optional) Map of assume role session tags.
+* `assume_role_transitive_tag_keys` - (Optional) Set of assume role session tag keys to pass to any subsequent sessions.
+* `external_id` - (Optional) External identifier to use when assuming the role.
+* `role_arn` - (Optional) Amazon Resource Name (ARN) of the IAM Role to assume.
+* `session_name` - (Optional) Session name to use when assuming the role.
+
+### S3 State Storage
+
+The following configuration is required:
+
+* `bucket` - (Required) Name of the S3 Bucket.
+* `key` - (Required) Path to the state file inside the S3 Bucket. When using a non-default [workspace](/terraform/language/state/workspaces), the state path will be `/workspace_key_prefix/workspace_name/key` (see also the `workspace_key_prefix` configuration).
+
+The following configuration is optional:
+
+* `acl` - (Optional) [Canned ACL](https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html#canned-acl) to be applied to the state file.
+* `encrypt` - (Optional) Enable [server side encryption](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingServerSideEncryption.html) of the state file.
+* `endpoint` - (Optional) Custom endpoint for the AWS S3 API. This can also be sourced from the `AWS_S3_ENDPOINT` environment variable.
+* `force_path_style` - (Optional) Enable path-style S3 URLs (`https://<HOST>/<BUCKET>` instead of `https://<BUCKET>.<HOST>`).
+* `kms_key_id` - (Optional) Amazon Resource Name (ARN) of a Key Management Service (KMS) Key to use for encrypting the state. Note that if this value is specified, Terraform will need `kms:Encrypt`, `kms:Decrypt` and `kms:GenerateDataKey` permissions on this KMS key.
+* `sse_customer_key` - (Optional) The key to use for encrypting state with [Server-Side Encryption with Customer-Provided Keys (SSE-C)](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerSideEncryptionCustomerKeys.html). This is the base64-encoded value of the key, which must decode to 256 bits. This can also be sourced from the `AWS_SSE_CUSTOMER_KEY` environment variable, which is recommended due to the sensitivity of the value. Setting it inside a terraform file will cause it to be persisted to disk in `terraform.tfstate`.
+* `workspace_key_prefix` - (Optional) Prefix applied to the state path inside the bucket. This is only relevant when using a non-default workspace. Defaults to `env:`.
+
+### DynamoDB State Locking
+
+The following configuration is optional:
+
+* `dynamodb_endpoint` - (Optional) Custom endpoint for the AWS DynamoDB API. This can also be sourced from the `AWS_DYNAMODB_ENDPOINT` environment variable.
+* `dynamodb_table` - (Optional) Name of DynamoDB Table to use for state locking and consistency. The table must have a partition key named `LockID` with type of `String`. If not configured, state locking will be disabled.
+
+## Multi-account AWS Architecture
+
+A common architectural pattern is for an organization to use a number of
+separate AWS accounts to isolate different teams and environments. For example,
+a "staging" system will often be deployed into a separate AWS account than
+its corresponding "production" system, to minimize the risk of the staging
+environment affecting production infrastructure, whether via rate limiting,
+misconfigured access controls, or other unintended interactions.
+
+The S3 backend can be used in a number of different ways that make different
+tradeoffs between convenience, security, and isolation in such an organization.
+This section describes one such approach that aims to find a good compromise
+between these tradeoffs, allowing use of
+[Terraform's workspaces feature](/terraform/language/state/workspaces) to switch
+conveniently between multiple isolated deployments of the same configuration.
+
+Use this section as a starting-point for your approach, but note that
+you will probably need to make adjustments for the unique standards and
+regulations that apply to your organization. You will also need to make some
+adjustments to this approach to account for _existing_ practices within your
+organization, if for example other tools have previously been used to manage
+infrastructure.
+
+Terraform is an administrative tool that manages your infrastructure, and so
+ideally the infrastructure that is used by Terraform should exist outside of
+the infrastructure that Terraform manages. This can be achieved by creating a
+separate _administrative_ AWS account which contains the user accounts used by
+human operators and any infrastructure and tools used to manage the other
+accounts. Isolating shared administrative tools from your main environments
+has a number of advantages, such as avoiding accidentally damaging the
+administrative infrastructure while changing the target infrastructure, and
+reducing the risk that an attacker might abuse production infrastructure to
+gain access to the (usually more privileged) administrative infrastructure.
+
+### Administrative Account Setup
+
+Your administrative AWS account will contain at least the following items:
+
+* One or more [IAM user](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users.html)
+  for system administrators that will log in to maintain infrastructure in
+  the other accounts.
+* Optionally, one or more [IAM groups](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_groups.html)
+  to differentiate between different groups of users that have different
+  levels of access to the other AWS accounts.
+* An [S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html)
+  that will contain the Terraform state files for each workspace.
+* A [DynamoDB table](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.TablesItemsAttributes)
+  that will be used for locking to prevent concurrent operations on a single
+  workspace.
+
+Provide the S3 bucket name and DynamoDB table name to Terraform within the
+S3 backend configuration using the `bucket` and `dynamodb_table` arguments
+respectively, and configure a suitable `workspace_key_prefix` to contain
+the states of the various workspaces that will subsequently be created for
+this configuration.
+
+### Environment Account Setup
+
+For the sake of this section, the term "environment account" refers to one
+of the accounts whose contents are managed by Terraform, separate from the
+administrative account described above.
+
+Your environment accounts will eventually contain your own product-specific
+infrastructure. Along with this it must contain one or more
+[IAM roles](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html)
+that grant sufficient access for Terraform to perform the desired management
+tasks.
+
+### Delegating Access
+
+Each Administrator will run Terraform using credentials for their IAM user
+in the administrative account.
+[IAM Role Delegation](https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html)
+is used to grant these users access to the roles created in each environment
+account.
+
+Full details on role delegation are covered in the AWS documentation linked
+above. The most important details are:
+
+* Each role's _Assume Role Policy_ must grant access to the administrative AWS
+  account, which creates a trust relationship with the administrative AWS
+  account so that its users may assume the role.
+* The users or groups within the administrative account must also have a
+  policy that creates the converse relationship, allowing these users or groups
+  to assume that role.
+
+Since the purpose of the administrative account is only to host tools for
+managing other accounts, it is useful to give the administrative accounts
+restricted access only to the specific operations needed to assume the
+environment account role and access the Terraform state. By blocking all
+other access, you remove the risk that user error will lead to staging or
+production resources being created in the administrative account by mistake.
+
+When configuring Terraform, use either environment variables or the standard
+credentials file `~/.aws/credentials` to provide the administrator user's
+IAM credentials within the administrative account to both the S3 backend _and_
+to Terraform's AWS provider.
+
+Use conditional configuration to pass a different `assume_role` value to
+the AWS provider depending on the selected workspace. For example:
+
+```hcl
+variable "workspace_iam_roles" {
+  default = {
+    staging    = "arn:aws:iam::STAGING-ACCOUNT-ID:role/Terraform"
+    production = "arn:aws:iam::PRODUCTION-ACCOUNT-ID:role/Terraform"
+  }
+}
+
+provider "aws" {
+  # No credentials explicitly set here because they come from either the
+  # environment or the global credentials file.
+
+  assume_role {
+    role_arn = "${var.workspace_iam_roles[terraform.workspace]}"
+  }
+}
+```
+
+If workspace IAM roles are centrally managed and shared across many separate
+Terraform configurations, the role ARNs could also be obtained via a data
+source such as [`terraform_remote_state`](/terraform/language/state/remote-state-data)
+to avoid repeating these values.
+
+### Creating and Selecting Workspaces
+
+With the necessary objects created and the backend configured, run
+`terraform init` to initialize the backend and establish an initial workspace
+called "default". This workspace will not be used, but is created automatically
+by Terraform as a convenience for users who are not using the workspaces
+feature.
+
+Create a workspace corresponding to each key given in the `workspace_iam_roles`
+variable value above:
+
+```
+$ terraform workspace new staging
+Created and switched to workspace "staging"!
+
+...
+
+$ terraform workspace new production
+Created and switched to workspace "production"!
+
+...
+```
+
+Due to the `assume_role` setting in the AWS provider configuration, any
+management operations for AWS resources will be performed via the configured
+role in the appropriate environment AWS account. The backend operations, such
+as reading and writing the state from S3, will be performed directly as the
+administrator's own user within the administrative account.
+
+```
+$ terraform workspace select staging
+$ terraform apply
+...
+```
+
+### Running Terraform in Amazon EC2
+
+Teams that make extensive use of Terraform for infrastructure management
+often [run Terraform in automation](/terraform/tutorials/automation/automate-terraform?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS)
+to ensure a consistent operating environment and to limit access to the
+various secrets and other sensitive information that Terraform configurations
+tend to require.
+
+When running Terraform in an automation tool running on an Amazon EC2 instance,
+consider running this instance in the administrative account and using an
+[instance profile](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html)
+in place of the various administrator IAM users suggested above. An IAM
+instance profile can also be granted cross-account delegation access via
+an IAM policy, giving this instance the access it needs to run Terraform.
+
+To isolate access to different environment accounts, use a separate EC2
+instance for each target account so that its access can be limited only to
+the single account.
+
+Similar approaches can be taken with equivalent features in other AWS compute
+services, such as ECS.
+
+### Protecting Access to Workspace State
+
+In a simple implementation of the pattern described in the prior sections,
+all users have access to read and write states for all workspaces. In many
+cases it is desirable to apply more precise access constraints to the
+Terraform state objects in S3, so that for example only trusted administrators
+are allowed to modify the production state, or to control _reading_ of a state
+that contains sensitive information.
+
+Amazon S3 supports fine-grained access control on a per-object-path basis
+using IAM policy. A full description of S3's access control mechanism is
+beyond the scope of this guide, but an example IAM policy granting access
+to only a single state object within an S3 bucket is shown below:
+
+```json
+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Effect": "Allow",
+      "Action": "s3:ListBucket",
+      "Resource": "arn:aws:s3:::myorg-terraform-states"
+    },
+    {
+      "Effect": "Allow",
+      "Action": ["s3:GetObject", "s3:PutObject"],
+      "Resource": "arn:aws:s3:::myorg-terraform-states/myapp/production/tfstate"
+    }
+  ]
+}
+```
+
+It is also possible to apply fine-grained access control to the DynamoDB
+table used for locking. When Terraform puts the state lock in place during `terraform plan`, it stores the full state file as a document and sets the s3 object key as the partition key for the document. After the state lock is released, Terraform places a digest of the updated state file in DynamoDB. The key is similar to the one for the original state file, but is suffixed with `-md5`.
+
+The example below shows a simple IAM policy that allows the backend operations role to perform these operations:
+
+```json
+{
+  "Version": "2012-10-17",
+  "Statement": [
+      {
+        "Effect" : "Allow",
+        "Action" : [
+          "dynamodb:DeleteItem",
+          "dynamodb:GetItem",
+          "dynamodb:PutItem",
+          "dynamodb:Query",
+          "dynamodb:UpdateItem"
+        ],
+        "Resource" : ["arn:aws:dynamodb:*:*:table/myorg-state-lock-table"],
+        "Condition" : {
+          "ForAllValues:StringEquals" : {
+            "dynamodb:LeadingKeys" : [
+              "myorg-terraform-states/myapp/production/tfstate", // during a state lock the full state file is stored with this key
+              "myorg-terraform-states/myapp/production/tfstate-md5" // after the lock is released a hash of the statefile's contents are stored with this key
+            ]
+          }
+        }
+      }
+  ]
+}
+```
+
+Refer to the [AWS documentation on DynamoDB fine-grained locking](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/specifying-conditions.html) for more details.
+
+### Configuring Custom User-Agent Information
+
+Note this feature is optional and only available in Terraform v0.13.1+.
+
+By default, the underlying AWS client used by the Terraform AWS Provider creates requests with User-Agent headers including information about Terraform and AWS Go SDK versions. To provide additional information in the User-Agent headers, the `TF_APPEND_USER_AGENT` environment variable can be set and its value will be directly added to HTTP requests. e.g.
+
+```sh
+$ export TF_APPEND_USER_AGENT="JenkinsAgent/i-12345678 BuildID/1234 (Optional Extra Information)"
+```
diff --git a/v1.5.7/website/docs/language/settings/index.mdx b/v1.5.7/website/docs/language/settings/index.mdx
new file mode 100644
index 0000000..441d6ea
--- /dev/null
+++ b/v1.5.7/website/docs/language/settings/index.mdx
@@ -0,0 +1,139 @@
+---
+page_title: Terraform Settings - Configuration Language
+description: >-
+  The terraform block allows you to configure Terraform behavior, including the
+  Terraform version, backend, integration with Terraform Cloud, and required
+  providers.
+---
+
+# Terraform Settings
+
+The special `terraform` configuration block type is used to configure some
+behaviors of Terraform itself, such as requiring a minimum Terraform version to
+apply your configuration.
+
+## Terraform Block Syntax
+
+Terraform settings are gathered together into `terraform` blocks:
+
+```hcl
+terraform {
+  # ...
+}
+```
+
+Each `terraform` block can contain a number of settings related to Terraform's
+behavior. Within a `terraform` block, only constant values can be used;
+arguments may not refer to named objects such as resources, input variables,
+etc, and may not use any of the Terraform language built-in functions.
+
+The various options supported within a `terraform` block are described in the
+following sections.
+
+## Configuring Terraform Cloud
+
+The nested `cloud` block configures Terraform Cloud for enabling its
+[CLI-driven run workflow](/terraform/cloud-docs/run/cli).
+
+- Refer to [Terraform Cloud Configuration](/terraform/language/settings/terraform-cloud) for a summary of the `cloud` block's syntax.
+
+- Refer to [Using Terraform Cloud](/terraform/cli/cloud) in the
+  Terraform CLI documentation for complete details about how to initialize and configure the Terraform Cloud CLI integration.
+
+## Configuring a Terraform Backend
+
+The nested `backend` block configures which state backend Terraform should use.
+
+The syntax and behavior of the `backend` block is described in [Backend
+Configuration](/terraform/language/settings/backends/configuration).
+
+## Specifying a Required Terraform Version
+
+> **Hands-on:** Try the [Manage Terraform Versions](/terraform/tutorials/configuration-language/versions)  or [Manage Terraform Versions in Terraform Cloud](/terraform/tutorials/cloud/cloud-versions) tutorials.
+
+The `required_version` setting accepts a [version constraint
+string,](/terraform/language/expressions/version-constraints) which specifies which versions of Terraform
+can be used with your configuration.
+
+If the running version of Terraform doesn't match the constraints specified,
+Terraform will produce an error and exit without taking any further actions.
+
+When you use [child modules](/terraform/language/modules), each module can specify its own
+version requirements. The requirements of all modules in the tree must be
+satisfied.
+
+Use Terraform version constraints in a collaborative environment to
+ensure that everyone is using a specific Terraform version, or using at least
+a minimum Terraform version that has behavior expected by the configuration.
+
+The `required_version` setting applies only to the version of Terraform CLI.
+Terraform's resource types are implemented by provider plugins,
+whose release cycles are independent of Terraform CLI and of each other.
+Use [the `required_providers` block](/terraform/language/providers/requirements) to manage
+the expected versions for each provider you use.
+
+## Specifying Provider Requirements
+
+[inpage-source]: #specifying-provider-requirements
+
+The `required_providers` block specifies all of the providers required by the
+current module, mapping each local provider name to a source address and a
+version constraint.
+
+```hcl
+terraform {
+  required_providers {
+    aws = {
+      version = ">= 2.7.0"
+      source = "hashicorp/aws"
+    }
+  }
+}
+```
+
+For more information, see [Provider Requirements](/terraform/language/providers/requirements).
+
+## Experimental Language Features
+
+The Terraform team will sometimes introduce new language features initially via
+an opt-in experiment, so that the community can try the new feature and give
+feedback on it prior to it becoming a backward-compatibility constraint.
+
+In releases where experimental features are available, you can enable them on
+a per-module basis by setting the `experiments` argument inside a `terraform`
+block:
+
+```hcl
+terraform {
+  experiments = [example]
+}
+```
+
+The above would opt in to an experiment named `example`, assuming such an
+experiment were available in the current Terraform version.
+
+Experiments are subject to arbitrary changes in later releases and, depending on
+the outcome of the experiment, may change drastically before final release or
+may not be released in stable form at all. Such breaking changes may appear
+even in minor and patch releases. We do not recommend using experimental
+features in Terraform modules intended for production use.
+
+In order to make that explicit and to avoid module callers inadvertently
+depending on an experimental feature, any module with experiments enabled will
+generate a warning on every `terraform plan` or `terraform apply`. If you
+want to try experimental features in a shared module, we recommend enabling the
+experiment only in alpha or beta releases of the module.
+
+The introduction and completion of experiments is reported in
+[Terraform's changelog](https://github.com/hashicorp/terraform/blob/main/CHANGELOG.md),
+so you can watch the release notes there to discover which experiment keywords,
+if any, are available in a particular Terraform release.
+
+## Passing Metadata to Providers
+
+The `terraform` block can have a nested `provider_meta` block for each
+provider a module is using, if the provider defines a schema for it. This
+allows the provider to receive module-specific information, and is primarily
+intended for modules distributed by the same vendor as the associated provider.
+
+For more information, see [Provider Metadata](/terraform/internals/provider-meta).
diff --git a/v1.5.7/website/docs/language/settings/terraform-cloud.mdx b/v1.5.7/website/docs/language/settings/terraform-cloud.mdx
new file mode 100644
index 0000000..556aea3
--- /dev/null
+++ b/v1.5.7/website/docs/language/settings/terraform-cloud.mdx
@@ -0,0 +1,36 @@
+---
+page_title: Terraform Cloud Configuration - Terraform Settings - Configuration Language
+description: >-
+  The nested `cloud` block configures Terraform's integration with Terraform
+  Cloud.
+---
+
+# Terraform Cloud Configuration
+
+The main module of a Terraform configuration can integrate with Terraform Cloud to enable its [CLI-driven run workflow](/terraform/cloud-docs/run/cli). You only need to configure these settings when you want to use Terraform CLI to interact with Terraform Cloud. Terraform Cloud ignores them when interacting with
+Terraform through version control or the API.
+
+> **Hands On:** Try the [Migrate State to Terraform Cloud](/terraform/tutorials/cloud/cloud-migrate) tutorial.
+
+## Usage Example
+
+To configure the Terraform Cloud CLI integration, add a nested `cloud` block within the `terraform` block. You cannot use the CLI integration and a [state backend](/terraform/language/settings/backends/configuration) in the same configuration.
+
+Refer to [Using Terraform Cloud](/terraform/cli/cloud) in the Terraform CLI documentation for full configuration details, migration instructions, and command line arguments.
+
+```hcl
+terraform {
+  cloud {
+    organization = "example_corp"
+    ## Required for Terraform Enterprise; Defaults to app.terraform.io for Terraform Cloud
+    hostname = "app.terraform.io"
+
+    workspaces {
+      tags = ["app"]
+    }
+  }
+}
+```
+
+
+
diff --git a/v1.5.7/website/docs/language/state/backends.mdx b/v1.5.7/website/docs/language/state/backends.mdx
new file mode 100644
index 0000000..72af00c
--- /dev/null
+++ b/v1.5.7/website/docs/language/state/backends.mdx
@@ -0,0 +1,72 @@
+---
+page_title: 'Backends: State Storage and Locking'
+description: >-
+  Backends are configured directly in Terraform files in the `terraform`
+  section.
+---
+
+# State Storage and Locking
+
+Backends are responsible for storing state and providing an API for
+[state locking](/terraform/language/state/locking). State locking is optional.
+
+Despite the state being stored remotely, all Terraform commands such
+as `terraform console`, the `terraform state` operations, `terraform taint`,
+and more will continue to work as if the state was local.
+
+## State Storage
+
+Backends determine where state is stored. For example, the local (default)
+backend stores state in a local JSON file on disk. The Consul backend stores
+the state within Consul. Both of these backends happen to provide locking:
+local via system APIs and Consul via locking APIs.
+
+When using a non-local backend, Terraform will not persist the state anywhere
+on disk except in the case of a non-recoverable error where writing the state
+to the backend failed. This behavior is a major benefit for backends: if
+sensitive values are in your state, using a remote backend allows you to use
+Terraform without that state ever being persisted to disk.
+
+In the case of an error persisting the state to the backend, Terraform will
+write the state locally. This is to prevent data loss. If this happens, the
+end user must manually push the state to the remote backend once the error
+is resolved.
+
+## Manual State Pull/Push
+
+You can still manually retrieve the state from the remote state using
+the `terraform state pull` command. This will load your remote state and
+output it to stdout. You can choose to save that to a file or perform any
+other operations.
+
+You can also manually write state with `terraform state push`. **This
+is extremely dangerous and should be avoided if possible.** This will
+overwrite the remote state. This can be used to do manual fixups if necessary.
+
+When manually pushing state, Terraform will attempt to protect you from
+some potentially dangerous situations:
+
+- **Differing lineage**: The "lineage" is a unique ID assigned to a state
+  when it is created. If a lineage is different, then it means the states
+  were created at different times and its very likely you're modifying a
+  different state. Terraform will not allow this.
+
+- **Higher serial**: Every state has a monotonically increasing "serial"
+  number. If the destination state has a higher serial, Terraform will
+  not allow you to write it since it means that changes have occurred since
+  the state you're attempting to write.
+
+Both of these protections can be bypassed with the `-force` flag if you're
+confident you're making the right decision. Even if using the `-force` flag,
+we recommend making a backup of the state with `terraform state pull`
+prior to forcing the overwrite.
+
+## State Locking
+
+Backends are responsible for supporting [state locking](/terraform/language/state/locking)
+if possible.
+
+Not all backends support locking. The [documentation for each backend](/terraform/language/settings/backends/configuration#available-backends) includes details about whether it supports locking or not.
+
+For more information on state locking, view the
+[page dedicated to state locking](/terraform/language/state/locking).
diff --git a/v1.5.7/website/docs/language/state/import.mdx b/v1.5.7/website/docs/language/state/import.mdx
new file mode 100644
index 0000000..1bf2c7d
--- /dev/null
+++ b/v1.5.7/website/docs/language/state/import.mdx
@@ -0,0 +1,13 @@
+---
+page_title: 'State: Import Existing Resources'
+description: >-
+  Terraform stores state which caches the known state of the world the last time
+  Terraform ran.
+---
+
+# Import Existing Resources
+
+Terraform is able to import existing infrastructure. This allows you to take
+resources you have created by some other means and bring them under Terraform management.
+
+To learn more, see [Import](/terraform/language/import).
diff --git a/v1.5.7/website/docs/language/state/index.mdx b/v1.5.7/website/docs/language/state/index.mdx
new file mode 100644
index 0000000..96e5a2e
--- /dev/null
+++ b/v1.5.7/website/docs/language/state/index.mdx
@@ -0,0 +1,83 @@
+---
+page_title: State
+description: >-
+  An introduction to state, information that Terraform uses to map resources to
+  a configuration, track metadata, and improve performance.
+---
+
+# State
+
+Terraform must store state about your managed infrastructure and
+configuration. This state is used by Terraform to map real world
+resources to your configuration, keep track of metadata, and to improve
+performance for large infrastructures.
+
+This state is stored by default in a local file named "terraform.tfstate",
+but we recommend [storing it in Terraform Cloud](/terraform/cloud-docs/migrate)
+to version, encrypt, and securely share it with your team.
+
+Terraform uses state to determine which changes to make to your
+infrastructure. Prior to any operation, Terraform does a
+[refresh](/terraform/cli/commands/refresh) to update the state with the
+real infrastructure.
+
+The primary purpose of Terraform state is to store bindings between objects in
+a remote system and resource instances declared in your configuration.
+When Terraform creates a remote object in response to a change of configuration,
+it will record the identity of that remote object against a particular
+resource instance, and then potentially update or delete that object in
+response to future configuration changes.
+
+For more information on why Terraform requires state and why Terraform cannot
+function without state, please see the page [state purpose](/terraform/language/state/purpose).
+
+## Inspection and Modification
+
+While the format of the state files are just JSON, direct file editing
+of the state is discouraged. Terraform provides the
+[terraform state](/terraform/cli/commands/state) command to perform
+basic modifications of the state using the CLI.
+
+The CLI usage and output of the state commands is structured to be
+friendly for Unix tools such as grep, awk, etc. Additionally, the CLI
+insulates users from any format changes within the state itself. The Terraform
+project will keep the CLI working while the state format underneath it may
+shift.
+
+Terraform expects a one-to-one mapping between configured resource instances
+and remote objects. Normally that is guaranteed by Terraform being the one
+to create each object and record its identity in the state, or to destroy
+an object and then remove the binding for it.
+
+If you add or remove bindings in the state by other means, such as by importing
+externally-created objects with `terraform import`, or by asking Terraform to
+"forget" an existing object with `terraform state rm`, you'll then need to
+ensure for yourself that this one-to-one rule is followed, such as by manually
+deleting an object that you asked Terraform to "forget", or by re-importing it
+to bind it to some other resource instance.
+
+## Format
+
+State snapshots are stored in JSON format and new Terraform versions are
+generally backward compatible with state snapshots produced by earlier versions.
+However, the state format is subject to change in new Terraform versions, so
+if you build software that parses or modifies it directly you should expect
+to perform ongoing maintenance of that software as the state format evolves
+in new versions.
+
+Alternatively, there are several integration points which produce JSON output
+that is specifically intended for consumption by external software:
+
+* [The `terraform output` command](/terraform/cli/commands/output)
+  has a `-json` option, for obtaining either the full set of root module output
+  values or a specific named output value from the latest state snapshot.
+* [The `terraform show` command](/terraform/cli/commands/show) has a `-json`
+  option for inspecting the latest state snapshot in full, and also for
+  inspecting saved plan files which include a copy of the prior state at the
+  time the plan was made.
+
+A typical way to use these in situations where Terraform is running in
+automation is to run them immediately after a successful `terraform apply`
+to obtain a representation of the latest state snapshot, and then store that
+result as an artifact associated with the automated run so that other software
+can potentially consume it without needing to run Terraform itself.
diff --git a/v1.5.7/website/docs/language/state/locking.mdx b/v1.5.7/website/docs/language/state/locking.mdx
new file mode 100644
index 0000000..a5fa145
--- /dev/null
+++ b/v1.5.7/website/docs/language/state/locking.mdx
@@ -0,0 +1,40 @@
+---
+page_title: 'State: Locking'
+description: >-
+  Terraform stores state which caches the known state of the world the last time
+  Terraform ran.
+---
+
+# State Locking
+
+If supported by your [backend](/terraform/language/settings/backends/configuration), Terraform will lock your
+state for all operations that could write state. This prevents
+others from acquiring the lock and potentially corrupting your state.
+
+State locking happens automatically on all operations that could write
+state. You won't see any message that it is happening. If state locking fails,
+Terraform will not continue. You can disable state locking for most commands
+with the `-lock` flag but it is not recommended.
+
+If acquiring the lock is taking longer than expected, Terraform will output
+a status message. If Terraform doesn't output a message, state locking is
+still occurring if your backend supports it.
+
+Not all backends support locking. The
+[documentation for each backend](/terraform/language/settings/backends/configuration)
+includes details on whether it supports locking or not.
+
+## Force Unlock
+
+Terraform has a [force-unlock command](/terraform/cli/commands/force-unlock)
+to manually unlock the state if unlocking failed.
+
+**Be very careful with this command.** If you unlock the state when someone
+else is holding the lock it could cause multiple writers. Force unlock should
+only be used to unlock your own lock in the situation where automatic
+unlocking failed.
+
+To protect you, the `force-unlock` command requires a unique lock ID. Terraform
+will output this lock ID if unlocking fails. This lock ID acts as a
+[nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce), ensuring
+that locks and unlocks target the correct lock.
diff --git a/v1.5.7/website/docs/language/state/purpose.mdx b/v1.5.7/website/docs/language/state/purpose.mdx
new file mode 100644
index 0000000..681e996
--- /dev/null
+++ b/v1.5.7/website/docs/language/state/purpose.mdx
@@ -0,0 +1,109 @@
+---
+page_title: State
+description: >-
+  Terraform must store state about your managed infrastructure and
+  configuration. This state is used by Terraform to map real world resources to
+  your configuration, keep track of metadata, and to improve performance for
+  large infrastructures.
+---
+
+# Purpose of Terraform State
+
+State is a necessary requirement for Terraform to function. It is often
+asked if it is possible for Terraform to work without state, or for Terraform
+to not use state and just inspect real world resources on every run. This page
+will help explain why Terraform state is required.
+
+As you'll see from the reasons below, state is required. And in the scenarios
+where Terraform may be able to get away without state, doing so would require
+shifting massive amounts of complexity from one place (state) to another place
+(the replacement concept).
+
+## Mapping to the Real World
+
+Terraform requires some sort of database to map Terraform config to the real
+world. For example, when you have a resource `resource "aws_instance" "foo"` in your
+configuration, Terraform uses this mapping to know that the resource `resource "aws_instance" "foo"`
+represents a real world object with the instance ID `i-abcd1234` on a remote system.
+
+For some providers like AWS, Terraform could theoretically use something like
+AWS tags. Early prototypes of Terraform actually had no state files and used
+this method. However, we quickly ran into problems. The first major issue was
+a simple one: not all resources support tags, and not all cloud providers
+support tags.
+
+Therefore, for mapping configuration to resources in the real world,
+Terraform uses its own state structure.
+
+Terraform expects that each remote object is bound to only one resource instance in the configuration.
+If a remote object is bound to multiple resource instances, the mapping from configuration to the remote
+object in the state becomes ambiguous, and Terraform may behave unexpectedly. Terraform can guarantee 
+a one-to-one mapping when it creates objects and records their identities in the state. 
+When importing objects created outside of Terraform, you must make sure that each distinct object 
+is imported to only one resource instance.
+
+## Metadata
+
+Alongside the mappings between resources and remote objects, Terraform must
+also track metadata such as resource dependencies.
+
+Terraform typically uses the configuration to determine dependency order.
+However, when you delete a resource from a Terraform configuration, Terraform
+must know how to delete that resource from the remote system. Terraform can see that a mapping exists
+in the state file for a resource not in your configuration and plan to destroy. However, since
+the configuration no longer exists, the order cannot be determined from the
+configuration alone.
+
+To ensure correct operation, Terraform retains a copy of the most recent set
+of dependencies within the state. Now Terraform can still determine the correct
+order for destruction from the state when you delete one or more items from
+the configuration.
+
+One way to avoid this would be for Terraform to know a required ordering
+between resource types. For example, Terraform could know that servers must be
+deleted before the subnets they are a part of. The complexity for this approach
+quickly explodes, however: in addition to Terraform having to understand the
+ordering semantics of every resource for every _provider_, Terraform must also
+understand the ordering _across providers_.
+
+Terraform also stores other metadata for similar reasons, such as a pointer
+to the provider configuration that was most recently used with the resource
+in situations where multiple aliased providers are present.
+
+## Performance
+
+In addition to basic mapping, Terraform stores a cache of the attribute
+values for all resources in the state. This is the most optional feature of
+Terraform state and is done only as a performance improvement.
+
+When running a `terraform plan`, Terraform must know the current state of
+resources in order to effectively determine the changes that it needs to make
+to reach your desired configuration.
+
+For small infrastructures, Terraform can query your providers and sync the
+latest attributes from all your resources. This is the default behavior
+of Terraform: for every plan and apply, Terraform will sync all resources in
+your state.
+
+For larger infrastructures, querying every resource is too slow. Many cloud
+providers do not provide APIs to query multiple resources at once, and the
+round trip time for each resource is hundreds of milliseconds. On top of this,
+cloud providers almost always have API rate limiting so Terraform can only
+request a certain number of resources in a period of time. Larger users
+of Terraform make heavy use of the `-refresh=false` flag as well as the
+`-target` flag in order to work around this. In these scenarios, the cached
+state is treated as the record of truth.
+
+## Syncing
+
+In the default configuration, Terraform stores the state in a file in the
+current working directory where Terraform was run. This is okay for getting
+started, but when using Terraform in a team it is important for everyone
+to be working with the same state so that operations will be applied to the
+same remote objects.
+
+[Remote state](/terraform/language/state/remote) is the recommended solution
+to this problem. With a fully-featured state backend, Terraform can use
+remote locking as a measure to avoid two or more different users accidentally
+running Terraform at the same time, and thus ensure that each Terraform run
+begins with the most recent updated state.
diff --git a/v1.5.7/website/docs/language/state/remote-state-data.mdx b/v1.5.7/website/docs/language/state/remote-state-data.mdx
new file mode 100644
index 0000000..1cbe298
--- /dev/null
+++ b/v1.5.7/website/docs/language/state/remote-state-data.mdx
@@ -0,0 +1,208 @@
+---
+page_title: The terraform_remote_state Data Source
+description: >-
+  Retrieves the root module output values from a Terraform state snapshot stored
+  in a remote backend.
+---
+
+# The `terraform_remote_state` Data Source
+
+[backends]: /terraform/language/settings/backends/configuration
+
+The `terraform_remote_state` data source uses the latest state snapshot from a specified state backend to retrieve the root module output values
+from some other Terraform configuration.
+
+You can use the `terraform_remote_state` data source without requiring or configuring a provider. It is always available through a built-in provider with the [source address](/terraform/language/providers/requirements#source-addresses) `terraform.io/builtin/terraform`. That provider does not include any other resources or data sources.
+
+~> **Important:** We recommend using the [`tfe_outputs` data source](https://registry.terraform.io/providers/hashicorp/tfe/latest/docs/data-sources/outputs) in the [Terraform Cloud/Enterprise Provider](https://registry.terraform.io/providers/hashicorp/tfe/latest/docs) to access remote state outputs in Terraform Cloud or Terraform Enterprise. The `tfe_outputs` data source is more secure because it does not require full access to workspace state to fetch outputs.
+
+## Alternative Ways to Share Data Between Configurations
+
+Sharing data with root module outputs is convenient, but it has drawbacks.
+Although `terraform_remote_state` only exposes output values, its user must have
+access to the entire state snapshot, which often includes some sensitive
+information.
+
+When possible, we recommend explicitly publishing data for external consumption
+to a separate location instead of accessing it via remote state. This lets you
+apply different access controls for shared information and state snapshots.
+
+To share data explicitly between configurations, you can use pairs of managed
+resource types and data sources in various providers, including (but not
+limited to) the following:
+
+| System                                                                 | Publish with...                                                                                                                                                  | Read with...                                                                                                                                                                                                                                                         |
+| ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Alibaba Cloud DNS<br /><small>(for IP addresses and hostnames)</small> | [`alicloud_alidns_record` resource type](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/alidns_record)                            | Normal DNS lookups, or [the `dns` provider](https://registry.terraform.io/providers/hashicorp/dns/latest/docs)                                                                                                                                                       |
+| Amazon Route53<br /><small>(for IP addresses and hostnames)</small>    | [`aws_route53_record` resource type](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record)                                 | Normal DNS lookups, or [the `dns` provider](https://registry.terraform.io/providers/hashicorp/dns/latest/docs)                                                                                                                                                       |
+| Amazon S3                                                              | [`aws_s3_object` resource type](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_object)                             | [`aws_s3_object` data source](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_object)                                                                                                                                |
+| Amazon SSM Parameter Store                                             | [`aws_ssm_parameter` resource type](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_parameter)                                   | [`aws_ssm_parameter` data source](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter)                                                                                                                                      |
+| Azure Automation                                                       | [`azurerm_automation_variable_string` resource type](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/automation_variable_string) | [`azurerm_automation_variable_string` data source](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/automation_variable_string)                                                                                                    |
+| Azure DNS<br /><small>(for IP addresses and hostnames)</small>         | [`azurerm_dns_a_record` resource type](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/dns_a_record), etc                        | Normal DNS lookups, or [the `dns` provider](https://registry.terraform.io/providers/hashicorp/dns/latest/docs)                                                                                                                                                       |
+| Google Cloud DNS<br /><small>(for IP addresses and hostnames)</small>  | [`google_dns_record_set` resource type](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/dns_record_set)                           | Normal DNS lookups, or [the `dns` provider](https://registry.terraform.io/providers/hashicorp/dns/latest/docs)                                                                                                                                                       |
+| Google Cloud Storage                                                   | [`google_storage_bucket_object`  resource type](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket_object)            | [`google_storage_bucket_object` data source](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/storage_bucket_object) and [`http` data source](https://registry.terraform.io/providers/hashicorp/http/latest/docs/data-sources/http) |
+| HashiCorp Consul                                                       | [`consul_key_prefix` resource type](https://registry.terraform.io/providers/hashicorp/consul/latest/docs/resources/key_prefix)                                   | [`consul_key_prefix` data source](https://registry.terraform.io/providers/hashicorp/consul/latest/docs/data-sources/key_prefix)                                                                                                                                      |
+| HashiCorp Terraform Cloud                                              | Normal `outputs` terraform block                                                                                                                                 | [`tfe_outputs` data source](https://registry.terraform.io/providers/hashicorp/tfe/latest/docs/data-sources/outputs)                                                                                                                                                  |
+| Kubernetes                                                             | [`kubernetes_config_map` resource type](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/config_map)                           | [`kubernetes_config_map` data source](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/data-sources/config_map)                                                                                                                              |
+| OCI Object Storage                                                     | [`oci_objectstorage_bucket` resource type](https://registry.terraform.io/providers/hashicorp/oci/latest/docs/resources/objectstorage_object)                     | [`oci_objectstorage_bucket` data source](https://registry.terraform.io/providers/hashicorp/oci/latest/docs/data-sources/objectstorage_object)                                                                                                                        |
+
+-> These are some common options from the Official Terraform providers, but
+there are too many configuration storage options for us to list them all
+here, including some in partner and community providers.
+Any pair of managed resource type and corresponding data source can potentially
+be used to share data between Terraform configurations. See individual provider
+documentation to find other possibilities.
+
+A key advantage of using a separate explicit configuration store instead of
+`terraform_remote_state` is that the data can potentially also be read by
+systems other than Terraform, such as configuration management or scheduler
+systems within your compute instances. For that reason, we recommend selecting
+a configuration store that your other infrastructure could potentially make
+use of. For example:
+
+* If you wish to share IP addresses and hostnames, you could publish them as
+  normal DNS `A`, `AAAA`, `CNAME`, and `SRV` records in a private DNS zone and
+  then configure your other infrastructure to refer to that zone so you can
+  find infrastructure objects via your system's built-in DNS resolver.
+* If you use HashiCorp Consul then publishing data to the Consul key/value
+  store or Consul service catalog can make that data also accessible via
+  [Consul Template](https://github.com/hashicorp/consul-template)
+  or the
+  [HashiCorp Nomad](/nomad/docs/job-specification/template)
+  `template` stanza.
+* If you use Kubernetes then you can
+  [make Config Maps available to your Pods](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/).
+
+Some of the data stores listed above are specifically designed for storing
+small configuration values, while others are generic blob storage systems. For
+those generic systems, you can use
+[the `jsonencode` function](/terraform/language/functions/jsonencode)
+and
+[the `jsondecode` function](/terraform/language/functions/jsondecode) respectively
+to store and retrieve structured data.
+
+You can encapsulate the implementation details of retrieving your published
+configuration data by writing a
+[data-only module](/terraform/language/modules/develop/composition#data-only-modules)
+containing the necessary data source configuration and any necessary
+post-processing such as JSON decoding. You can then change that module later
+if you switch to a different strategy for sharing data between multiple
+Terraform configurations.
+
+## Example Usage (`remote` Backend)
+
+```hcl
+data "terraform_remote_state" "vpc" {
+  backend = "remote"
+
+  config = {
+    organization = "hashicorp"
+    workspaces = {
+      name = "vpc-prod"
+    }
+  }
+}
+
+# Terraform >= 0.12
+resource "aws_instance" "foo" {
+  # ...
+  subnet_id = data.terraform_remote_state.vpc.outputs.subnet_id
+}
+
+# Terraform <= 0.11
+resource "aws_instance" "foo" {
+  # ...
+  subnet_id = "${data.terraform_remote_state.vpc.subnet_id}"
+}
+```
+
+## Example Usage (`local` Backend)
+
+```hcl
+data "terraform_remote_state" "vpc" {
+  backend = "local"
+
+  config = {
+    path = "..."
+  }
+}
+
+# Terraform >= 0.12
+resource "aws_instance" "foo" {
+  # ...
+  subnet_id = data.terraform_remote_state.vpc.outputs.subnet_id
+}
+
+# Terraform <= 0.11
+resource "aws_instance" "foo" {
+  # ...
+  subnet_id = "${data.terraform_remote_state.vpc.subnet_id}"
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `backend` - (Required) The remote backend to use.
+* `workspace` - (Optional) The Terraform workspace to use, if the backend
+  supports workspaces.
+* `config` - (Optional; object) The configuration of the remote backend.
+  Although this argument is listed as optional, most backends require
+  some configuration.
+
+  The `config` object can use any arguments that would be valid in the
+  equivalent `terraform { backend "<TYPE>" { ... } }` block. See
+  [the documentation of your chosen backend](/terraform/language/settings/backends/configuration)
+  for details.
+
+  -> **Note:** If the backend configuration requires a nested block, specify
+  it here as a normal attribute with an object value. (For example,
+  `workspaces = { ... }` instead of `workspaces { ... }`.)
+* `defaults` - (Optional; object) Default values for outputs, in case the state
+  file is empty or lacks a required output.
+
+## Attributes Reference
+
+In addition to the above, the following attributes are exported:
+
+* (v0.12+) `outputs` - An object containing every root-level
+  [output](/terraform/language/values/outputs) in the remote state.
+* (<= v0.11) `<OUTPUT NAME>` - Each root-level [output](/terraform/language/values/outputs)
+  in the remote state appears as a top level attribute on the data source.
+
+## Root Outputs Only
+
+Only the root-level output values from the remote state snapshot are exposed
+for use elsewhere in your module. Resource data and output values from nested
+modules are not accessible.
+
+If you wish to make a nested module output value accessible as a root module
+output value, you must explicitly configure a passthrough in the root module.
+For example:
+
+For example:
+
+```hcl
+module "app" {
+  source = "..."
+}
+
+output "app_value" {
+  # This syntax is for Terraform 0.12 or later.
+  value = module.app.example
+}
+```
+
+In this example, the output value named `example` from the "app" module is
+available as the `app_value` root module output value. If this configuration
+didn't include the `output "app_value"` block then the data would not be
+accessible via `terraform_remote_state`.
+
+~> **Warning:** Although `terraform_remote_state` doesn't expose any other
+state snapshot information for use in configuration, the state snapshot data
+is a single object and so any user or server which has enough access to read
+the root module output values will also always have access to the full state
+snapshot data by direct network requests. Don't use `terraform_remote_state`
+if any of the resources in your configuration work with data that you consider
+sensitive.
diff --git a/v1.5.7/website/docs/language/state/remote.mdx b/v1.5.7/website/docs/language/state/remote.mdx
new file mode 100644
index 0000000..1709ab9
--- /dev/null
+++ b/v1.5.7/website/docs/language/state/remote.mdx
@@ -0,0 +1,63 @@
+---
+page_title: 'State: Remote Storage'
+description: >-
+  Terraform can store the state remotely, making it easier to version and work
+  with in a team.
+---
+
+# Remote State
+
+By default, Terraform stores state locally in a file named `terraform.tfstate`.
+When working with Terraform in a team, use of a local file makes Terraform
+usage complicated because each user must make sure they always have the latest
+state data before running Terraform and make sure that nobody else runs
+Terraform at the same time.
+
+With _remote_ state, Terraform writes the state data to a remote data store,
+which can then be shared between all members of a team. Terraform supports
+storing state in [Terraform Cloud](https://www.hashicorp.com/products/terraform/),
+[HashiCorp Consul](https://www.consul.io/), Amazon S3, Azure Blob Storage, Google Cloud Storage, Alibaba Cloud OSS, and more.
+
+Remote state is implemented by a [backend](/terraform/language/settings/backends/configuration) or by
+Terraform Cloud, both of which you can configure in your configuration's root module.
+
+## Delegation and Teamwork
+
+Remote state allows you to share
+[output values](/terraform/language/values/outputs) with other configurations.
+This allows your infrastructure to be decomposed into smaller components.
+
+Put another way, remote state also allows teams to share infrastructure
+resources in a read-only way without relying on any additional configuration
+store.
+
+For example, a core infrastructure team can handle building the core
+machines, networking, etc. and can expose some information to other
+teams to run their own infrastructure. As a more specific example with AWS:
+you can expose things such as VPC IDs, subnets, NAT instance IDs, etc. through
+remote state and have other Terraform states consume that.
+
+For example usage, see
+[the `terraform_remote_state` data source](/terraform/language/state/remote-state-data).
+
+While remote state can be a convenient, built-in mechanism for sharing data
+between configurations, you may prefer to use more general stores to
+pass settings both to other configurations and to other consumers. For example,
+if your environment has [HashiCorp Consul](https://www.consul.io/) then you
+can have one Terraform configuration that writes to Consul using
+[`consul_key_prefix`](https://registry.terraform.io/providers/hashicorp/consul/latest/docs/resources/key_prefix) and then
+another that consumes those values using
+[the `consul_keys` data source](https://registry.terraform.io/providers/hashicorp/consul/latest/docs/data-sources/keys).
+
+## Locking and Teamwork
+
+For fully-featured remote backends, Terraform can also use
+[state locking](/terraform/language/state/locking) to prevent concurrent runs of
+Terraform against the same state.
+
+[Terraform Cloud by HashiCorp](https://www.hashicorp.com/products/terraform/)
+is a commercial offering that supports an even stronger locking concept that
+can also detect attempts to create a new plan when an existing plan is already
+awaiting approval, by queuing Terraform operations in a central location.
+This allows teams to more easily coordinate and communicate about changes to
+infrastructure.
diff --git a/v1.5.7/website/docs/language/state/sensitive-data.mdx b/v1.5.7/website/docs/language/state/sensitive-data.mdx
new file mode 100644
index 0000000..aa473bf
--- /dev/null
+++ b/v1.5.7/website/docs/language/state/sensitive-data.mdx
@@ -0,0 +1,37 @@
+---
+page_title: 'State: Sensitive Data'
+description: Sensitive data in Terraform state.
+---
+
+# Sensitive Data in State
+
+Terraform state can contain sensitive data, depending on the resources in use
+and your definition of "sensitive." The state contains resource IDs and all
+resource attributes. For resources such as databases, this may contain initial
+passwords.
+
+When using local state, state is stored in plain-text JSON files.
+
+When using [remote state](/terraform/language/state/remote), state is only ever held in
+memory when used by Terraform. It may be encrypted at rest, but this depends on
+the specific remote state backend.
+
+## Recommendations
+
+If you manage any sensitive data with Terraform (like database passwords, user
+passwords, or private keys), treat the state itself as sensitive data.
+
+Storing state remotely can provide better security. As of Terraform 0.9,
+Terraform does not persist state to the local disk when remote state is in use,
+and some backends can be configured to encrypt the state data at rest.
+
+For example:
+
+- [Terraform Cloud](https://cloud.hashicorp.com/products/terraform) always encrypts state at rest and
+  protects it with TLS in transit. Terraform Cloud also knows the identity of
+  the user requesting state and maintains a history of state changes. This can
+  be used to control access and track activity. [Terraform Enterprise](/terraform/enterprise)
+  also supports detailed audit logging.
+- The S3 backend supports encryption at rest when the `encrypt` option is
+  enabled. IAM policies and logging can be used to identify any invalid access.
+  Requests for the state go over a TLS connection.
diff --git a/v1.5.7/website/docs/language/state/workspaces.mdx b/v1.5.7/website/docs/language/state/workspaces.mdx
new file mode 100644
index 0000000..61501d0
--- /dev/null
+++ b/v1.5.7/website/docs/language/state/workspaces.mdx
@@ -0,0 +1,73 @@
+---
+page_title: 'State: Workspaces'
+description: >-
+  Workspaces allow the use of multiple states with a single configuration
+  directory.
+---
+
+# Workspaces
+
+Each Terraform configuration has an associated [backend](/terraform/language/settings/backends/configuration) that defines how Terraform executes operations and where Terraform stores persistent data, like [state](/terraform/language/state/purpose).
+
+The persistent data stored in the backend belongs to a workspace. The backend initially has only one workspace containing one Terraform state associated with that configuration. Some backends support multiple named workspaces, allowing multiple states to be associated with a single configuration. The configuration still has only one backend, but you can deploy multiple distinct instances of that configuration without configuring a new backend or changing authentication
+credentials.
+
+-> **Note**: The Terraform CLI workspaces are different from [workspaces in Terraform Cloud](/terraform/cloud-docs/workspaces). Refer to [Initializing and Migrating](/terraform/cli/cloud/migrating) for details about migrating a configuration with multiple workspaces to Terraform Cloud.
+
+## Backends Supporting Multiple Workspaces
+
+You can use multiple workspaces with the following backends:
+
+- [AzureRM](/terraform/language/settings/backends/azurerm)
+- [Consul](/terraform/language/settings/backends/consul)
+- [COS](/terraform/language/settings/backends/cos)
+- [GCS](/terraform/language/settings/backends/gcs)
+- [Kubernetes](/terraform/language/settings/backends/kubernetes)
+- [Local](/terraform/language/settings/backends/local)
+- [OSS](/terraform/language/settings/backends/oss)
+- [Postgres](/terraform/language/settings/backends/pg)
+- [Remote](/terraform/language/settings/backends/remote)
+- [S3](/terraform/language/settings/backends/s3)
+
+
+## Using Workspaces
+
+~> **Important:** Workspaces are not appropriate for system decomposition or deployments requiring separate credentials and access controls. Refer to [Use Cases](/terraform/cli/workspaces#use-cases) in the Terraform CLI documentation for details and recommended alternatives.
+
+Terraform starts with a single, default workspace named `default` that you cannot delete. If you have not created a new workspace, you are using the default workspace in your Terraform working directory.
+
+When you run `terraform plan` in a new workspace, Terraform does not access existing resources in other workspaces. These resources still physically exist, but you must switch workspaces to manage them.
+
+Refer to the [Terraform CLI workspaces](/terraform/cli/workspaces) documentation for full details about how to create and use workspaces.
+
+
+## Current Workspace Interpolation
+
+Within your Terraform configuration, you may include the name of the current
+workspace using the `${terraform.workspace}` interpolation sequence. This can
+be used anywhere interpolations are allowed.
+
+Referencing the current workspace is useful for changing behavior based
+on the workspace. For example, for non-default workspaces, it may be useful
+to spin up smaller cluster sizes. For example:
+
+```hcl
+resource "aws_instance" "example" {
+  count = "${terraform.workspace == "default" ? 5 : 1}"
+
+  # ... other arguments
+}
+```
+
+Another popular use case is using the workspace name as part of naming or
+tagging behavior:
+
+```hcl
+resource "aws_instance" "example" {
+  tags = {
+    Name = "web - ${terraform.workspace}"
+  }
+
+  # ... other arguments
+}
+```
diff --git a/v1.5.7/website/docs/language/syntax/configuration.mdx b/v1.5.7/website/docs/language/syntax/configuration.mdx
new file mode 100644
index 0000000..1142498
--- /dev/null
+++ b/v1.5.7/website/docs/language/syntax/configuration.mdx
@@ -0,0 +1,128 @@
+---
+page_title: Syntax - Configuration Language
+description: >-
+  Key constructs of the native Terraform language syntax, including identifiers,
+  arguments, blocks, and comments.
+---
+
+# Configuration Syntax
+
+Other pages in this section have described various configuration constructs
+that can appear in the Terraform language. This page describes the lower-level
+syntax of the language in more detail, revealing the building blocks that
+those constructs are built from.
+
+This page describes the _native syntax_ of the Terraform language, which is
+a rich language designed to be relatively easy for humans to read and write.
+The constructs in the Terraform language can also be expressed in
+[JSON syntax](/terraform/language/syntax/json), which is harder for humans
+to read and edit but easier to generate and parse programmatically.
+
+This low-level syntax of the Terraform language is defined in terms of a
+syntax called _HCL_, which is also used by configuration languages in
+other applications, and in particular other HashiCorp products.
+It is not necessary to know all of the details of HCL syntax in
+order to use Terraform, and so this page summarizes the most important
+details. If you are interested, you can find a full definition of HCL
+syntax in
+[the HCL native syntax specification](https://github.com/hashicorp/hcl/blob/main/hclsyntax/spec.md).
+
+## Arguments and Blocks
+
+The Terraform language syntax is built around two key syntax constructs:
+arguments and blocks.
+
+### Arguments
+
+An _argument_ assigns a value to a particular name:
+
+```hcl
+image_id = "abc123"
+```
+
+The identifier before the equals sign is the _argument name_, and the expression
+after the equals sign is the argument's value.
+
+The context where the argument appears determines what value types are valid
+(for example, each resource type has a schema that defines the types of its
+arguments), but many arguments accept arbitrary
+[expressions](/terraform/language/expressions), which allow the value to
+either be specified literally or generated from other values programmatically.
+
+-> **Note:** Terraform's configuration language is based on a more general
+language called HCL, and HCL's documentation usually uses the word "attribute"
+instead of "argument." These words are similar enough to be interchangeable in
+this context, and experienced Terraform users might use either term in casual
+conversation. But because Terraform also interacts with several _other_ things
+called "attributes" (in particular, Terraform resources have attributes like
+`id` that can be referenced from expressions but can't be assigned values in
+configuration), we've chosen to use "argument" in the Terraform documentation
+when referring to this syntax construct.
+
+### Blocks
+
+A _block_ is a container for other content:
+
+```hcl
+resource "aws_instance" "example" {
+  ami = "abc123"
+
+  network_interface {
+    # ...
+  }
+}
+```
+
+A block has a _type_ (`resource` in this example). Each block type defines
+how many _labels_ must follow the type keyword. The `resource` block type
+expects two labels, which are `aws_instance` and `example` in the example above.
+A particular block type may have any number of required labels, or it may
+require none as with the nested `network_interface` block type.
+
+After the block type keyword and any labels, the block _body_ is delimited
+by the `{` and `}` characters. Within the block body, further arguments
+and blocks may be nested, creating a hierarchy of blocks and their associated
+arguments.
+
+The Terraform language uses a limited number of _top-level block types,_ which
+are blocks that can appear outside of any other block in a configuration file.
+Most of Terraform's features (including resources, input variables, output
+values, data sources, etc.) are implemented as top-level blocks.
+
+## Identifiers
+
+Argument names, block type names, and the names of most Terraform-specific
+constructs like resources, input variables, etc. are all _identifiers_.
+
+Identifiers can contain letters, digits, underscores (`_`), and hyphens (`-`).
+The first character of an identifier must not be a digit, to avoid ambiguity
+with literal numbers.
+
+For complete identifier rules, Terraform implements
+[the Unicode identifier syntax](http://unicode.org/reports/tr31/), extended to
+include the ASCII hyphen character `-`.
+
+## Comments
+
+The Terraform language supports three different syntaxes for comments:
+
+* `#` begins a single-line comment, ending at the end of the line.
+* `//` also begins a single-line comment, as an alternative to `#`.
+* `/*` and `*/` are start and end delimiters for a comment that might span
+  over multiple lines.
+
+The `#` single-line comment style is the default comment style and should be
+used in most cases. Automatic configuration formatting tools may automatically
+transform `//` comments into `#` comments, since the double-slash style is
+not idiomatic.
+
+## Character Encoding and Line Endings
+
+Terraform configuration files must always be UTF-8 encoded. While the
+delimiters of the language are all ASCII characters, Terraform accepts
+non-ASCII characters in identifiers, comments, and string values.
+
+Terraform accepts configuration files with either Unix-style line endings
+(LF only) or Windows-style line endings (CR then LF), but the idiomatic style
+is to use the Unix convention, and so automatic configuration formatting tools
+may automatically transform CRLF endings to LF.
diff --git a/v1.5.7/website/docs/language/syntax/index.mdx b/v1.5.7/website/docs/language/syntax/index.mdx
new file mode 100644
index 0000000..199166b
--- /dev/null
+++ b/v1.5.7/website/docs/language/syntax/index.mdx
@@ -0,0 +1,23 @@
+---
+page_title: Syntax Overview - Configuration Language
+description: >-
+  Terraform language syntax for both the native and JSON variants. Also learn
+  formatting conventions that you can enforce with terraform fmt.
+---
+
+# Syntax
+
+The majority of the Terraform language documentation focuses on the practical
+uses of the language and the specific constructs it uses. The pages in this
+section offer a more abstract view of the Terraform language.
+
+- [Configuration Syntax](/terraform/language/syntax/configuration) describes the native
+  grammar of the Terraform language.
+- [JSON Configuration Syntax](/terraform/language/syntax/json) documents
+  how to represent Terraform language constructs in the pure JSON variant of the
+  Terraform language. Terraform's JSON syntax is unfriendly to humans, but can
+  be very useful when generating infrastructure as code with other systems that
+  don't have a readily available HCL library.
+- [Style Conventions](/terraform/language/syntax/style) documents some commonly
+  accepted formatting guidelines for Terraform code. These conventions can be
+  enforced automatically with [`terraform fmt`](/terraform/cli/commands/fmt).
diff --git a/v1.5.7/website/docs/language/syntax/json.mdx b/v1.5.7/website/docs/language/syntax/json.mdx
new file mode 100644
index 0000000..9f8ae50
--- /dev/null
+++ b/v1.5.7/website/docs/language/syntax/json.mdx
@@ -0,0 +1,469 @@
+---
+page_title: JSON Configuration Syntax - Configuration Language
+description: >-
+  Learn about the JSON-compatible language syntax, including file structure,
+  expression mapping, block mapping, and block-type-specific exceptions.
+---
+
+# JSON Configuration Syntax
+
+Most Terraform configurations are written in
+[the native Terraform language syntax](/terraform/language/syntax/configuration), which is designed to be
+relatively easy for humans to read and update.
+
+Terraform also supports an alternative syntax that is JSON-compatible. This
+syntax is useful when generating portions of a configuration programmatically,
+since existing JSON libraries can be used to prepare the generated
+configuration files.
+
+The JSON syntax is defined in terms of the native syntax. Everything that can
+be expressed in native syntax can also be expressed in JSON syntax, but some
+constructs are more complex to represent in JSON due to limitations of the
+JSON grammar.
+
+Terraform expects native syntax for files named with a `.tf` suffix, and
+JSON syntax for files named with a `.tf.json` suffix.
+
+The low-level JSON syntax, just as with the native syntax, is defined in terms
+of a specification called _HCL_. It is not necessary to know all of the details
+of HCL syntax or its JSON mapping in order to use Terraform, and so this page
+summarizes the most important differences between native and JSON syntax.
+If you are interested, you can find a full definition of HCL's JSON syntax
+in [its specification](https://github.com/hashicorp/hcl/blob/main/json/spec.md).
+
+## JSON File Structure
+
+At the root of any JSON-based Terraform configuration is a JSON object. The
+properties of this object correspond to the top-level block types of the
+Terraform language. For example:
+
+```json
+{
+  "variable": {
+    "example": {
+      "default": "hello"
+    }
+  }
+}
+```
+
+Each top-level object property must match the name of one of the expected
+top-level block types. Block types that expect labels, such as `variable`
+shown above, are represented by one nested object value for each level
+of label. `resource` blocks expect two labels, so two levels of nesting
+are required:
+
+```json
+{
+  "resource": {
+    "aws_instance": {
+      "example": {
+        "instance_type": "t2.micro",
+        "ami": "ami-abc123"
+      }
+    }
+  }
+}
+```
+
+After any nested objects representing the labels, finally one more nested
+object represents the body of the block itself. In the above examples, the
+`default` argument for `variable "example"` and the `instance_type` and
+`ami` arguments for `resource "aws_instance" "example"` are specified.
+
+Taken together, the above two configuration files are equivalent to the
+following blocks in the native syntax:
+
+```hcl
+variable "example" {
+  default = "hello"
+}
+
+resource "aws_instance" "example" {
+  instance_type = "t2.micro"
+  ami           = "ami-abc123"
+}
+```
+
+Within each top-level block type the rules for mapping to JSON are slightly
+different (see the [block-type-specific exceptions](#block-type-specific-exceptions) below), but the following general rules apply in most cases:
+
+* The JSON object representing the block body contains properties that
+  correspond either to argument names or to nested block type names.
+
+* Where a property corresponds to an argument that accepts
+  [arbitrary expressions](/terraform/language/expressions) in the native syntax, the
+  property value is mapped to an expression as described under
+  [_Expression Mapping_](#expression-mapping) below. For arguments that
+  do _not_ accept arbitrary expressions, the interpretation of the property
+  value depends on the argument, as described in the
+  [block-type-specific exceptions](#block-type-specific-exceptions)
+  given later in this page.
+
+* Where a property name corresponds to an expected nested block type name,
+  the value is interpreted as described under
+  [_Nested Block Mapping_](#nested-block-mapping) below, unless otherwise
+  stated in [the block-type-specific exceptions](#block-type-specific-exceptions)
+  given later in this page.
+
+## Expression Mapping
+
+Since JSON grammar is not able to represent all of the Terraform language
+[expression syntax](/terraform/language/expressions), JSON values interpreted as expressions
+are mapped as follows:
+
+| JSON    | Terraform Language Interpretation                                                                             |
+| ------- | ------------------------------------------------------------------------------------------------------------- |
+| Boolean | A literal `bool` value.                                                                                       |
+| Number  | A literal `number` value.                                                                                     |
+| String  | Parsed as a [string template][] and then evaluated as described below.                                        |
+| Object  | Each property value is mapped per this table, producing an `object(...)` value with suitable attribute types. |
+| Array   | Each element is mapped per this table, producing a `tuple(...)` value with suitable element types.            |
+| Null    | A literal `null`.                                                                                             |
+
+[string template]: /terraform/language/expressions/strings#string-templates
+
+When a JSON string is encountered in a location where arbitrary expressions are
+expected, its value is first parsed as a [string template][]
+and then it is evaluated to produce the final result.
+
+If the given template consists _only_ of a single interpolation sequence,
+the result of its expression is taken directly, without first converting it
+to a string. This allows non-string expressions to be used within the
+JSON syntax:
+
+```json
+{
+  "output": {
+    "example": {
+      "value": "${aws_instance.example}"
+    }
+  }
+}
+```
+
+The `output "example"` declared above has the object value representing the
+given `aws_instance` resource block as its value, rather than a string value.
+This special behavior does not apply if any literal or control sequences appear
+in the template; in these other situations, a string value is always produced.
+
+## Nested Block Mapping
+
+When a JSON object property is named after a nested block type, the value
+of this property represents one or more blocks of that type. The value of
+the property must be either a JSON object or a JSON array.
+
+The simplest situation is representing only a single block of the given type
+when that type expects no labels, as with the `lifecycle` nested block used
+within `resource` blocks:
+
+```json
+{
+  "resource": {
+    "aws_instance": {
+      "example": {
+        "lifecycle": {
+          "create_before_destroy": true
+        }
+      }
+    }
+  }
+}
+```
+
+The above is equivalent to the following native syntax configuration:
+
+```hcl
+resource "aws_instance" "example" {
+  lifecycle {
+    create_before_destroy = true
+  }
+}
+```
+
+When the nested block type requires one or more labels, or when multiple
+blocks of the same type can be given, the mapping gets a little more
+complicated. For example, the `provisioner` nested block type used
+within `resource` blocks expects a label giving the provisioner to use,
+and the ordering of provisioner blocks is significant to decide the order
+of operations.
+
+The following native syntax example shows a `resource` block with a number
+of provisioners of different types:
+
+```hcl
+resource "aws_instance" "example" {
+  # (resource configuration omitted for brevity)
+
+  provisioner "local-exec" {
+    command = "echo 'Hello World' >example.txt"
+  }
+  provisioner "file" {
+    source      = "example.txt"
+    destination = "/tmp/example.txt"
+  }
+  provisioner "remote-exec" {
+    inline = [
+      "sudo install-something -f /tmp/example.txt",
+    ]
+  }
+}
+```
+
+In order to preserve the order of these blocks, you must use a JSON array
+as the direct value of the property representing this block type, as in
+this JSON equivalent of the above:
+
+```json
+{
+  "resource": {
+    "aws_instance": {
+      "example": {
+        "provisioner": [
+          {
+            "local-exec": {
+              "command": "echo 'Hello World' >example.txt"
+            }
+          },
+          {
+            "file": {
+              "source": "example.txt",
+              "destination": "/tmp/example.txt"
+            }
+          },
+          {
+            "remote-exec": {
+              "inline": ["sudo install-something -f /tmp/example.txt"]
+            }
+          }
+        ]
+      }
+    }
+  }
+}
+```
+
+Each element of the `provisioner` array is an object with a single property
+whose name represents the label for each `provisioner` block. For block types
+that expect multiple labels, this pattern of alternating array and object
+nesting can be used for each additional level.
+
+If a nested block type requires labels but the order does _not_ matter, you
+may omit the array and provide just a single object whose property names
+correspond to unique block labels. This is allowed as a shorthand for the above
+for simple cases, but the alternating array and object approach is the most
+general. We recommend using the most general form if systematically converting
+from native syntax to JSON, to ensure that the meaning of the configuration is
+preserved exactly.
+
+### Comment Properties
+
+Although we do not recommend hand-editing of JSON syntax configuration files
+\-- this format is primarily intended for programmatic generation and consumption --
+a limited form of _comments_ are allowed inside JSON objects that represent
+block bodies using a special property name:
+
+```json
+{
+  "resource": {
+    "aws_instance": {
+      "example": {
+        "//": "This instance runs the scheduled tasks for backup",
+
+        "instance_type": "t2.micro",
+        "ami": "ami-abc123"
+      }
+    }
+  }
+}
+```
+
+In any object that represents a block body, properties named `"//"` are
+ignored by Terraform entirely. This exception does _not_ apply to objects
+that are being [interpreted as expressions](#expression-mapping), where this
+would be interpreted as an object type attribute named `"//"`.
+
+This special property name can also be used at the root of a JSON-based
+configuration file. This can be useful to note which program created the file.
+
+```json
+{
+  "//": "This file is generated by generate-outputs.py. DO NOT HAND-EDIT!",
+
+  "output": {
+    "example": {
+      "value": "${aws_instance.example}"
+    }
+  }
+}
+```
+
+## Block-type-specific Exceptions
+
+[inpage-block]: #block-type-specific-exceptions
+
+Certain arguments within specific block types are processed in a special way
+by Terraform, and so their mapping to the JSON syntax does not follow the
+general rules described above. The following sub-sections describe the special
+mapping rules that apply to each top-level block type.
+
+### `resource` and `data` blocks
+
+Some meta-arguments for the `resource` and `data` block types take direct
+references to objects, or literal keywords. When represented in JSON, the
+reference or keyword is given as a JSON string with no additional surrounding
+spaces or symbols.
+
+For example, the `provider` meta-argument takes a `<PROVIDER>.<ALIAS>` reference
+to a provider configuration, which appears unquoted in the native syntax but
+must be presented as a string in the JSON syntax:
+
+```json
+{
+  "resource": {
+    "aws_instance": {
+      "example": {
+        "provider": "aws.foo"
+      }
+    }
+  }
+}
+```
+
+This special processing applies to the following meta-arguments:
+
+* `provider`: a single string, as shown above
+* `depends_on`: an array of strings containing references to named entities,
+  like `["aws_instance.example"]`.
+* `ignore_changes` within the `lifecycle` block: if set to `all`, a single
+  string `"all"` must be given. Otherwise, an array of JSON strings containing
+  property references must be used, like `["ami"]`.
+
+Special processing also applies to the `type` argument of any `connection`
+blocks, whether directly inside the `resource` block or nested inside
+`provisioner` blocks: the given string is interpreted literally, and not
+parsed and evaluated as a string template.
+
+### `variable` blocks
+
+All arguments inside `variable` blocks have non-standard mappings to JSON:
+
+* `type`: a string containing a type expression, like `"string"` or `"list(string)"`.
+* `default`: a literal JSON value that can be converted to the given type.
+  Strings within this value are taken literally and _not_ interpreted as
+  string templates.
+* `description`: a literal JSON string, _not_ interpreted as a template.
+
+```json
+{
+  "variable": {
+    "example": {
+      "type": "string",
+      "default": "hello"
+    }
+  }
+}
+```
+
+### `output` blocks
+
+The `description` and `sensitive` arguments are interpreted as literal JSON
+values. The `description` string is not interpreted as a string template.
+
+The `value` argument is [interpreted as an expression](#expression-mapping).
+
+```json
+{
+  "output": {
+    "example": {
+      "value": "${aws_instance.example}"
+    }
+  }
+}
+```
+
+### `locals` blocks
+
+The value of the JSON object property representing the locals block type
+must be a JSON object whose property names are the local value names to
+declare:
+
+```json
+{
+  "locals": {
+    "greeting": "Hello, ${var.name}"
+  }
+}
+```
+
+The value of each of these nested properties is
+[interpreted as an expression](#expression-mapping).
+
+### `module` blocks
+
+The `source` and `version` meta-arguments must be given as literal strings. The
+values are not interpreted as string templates.
+
+The `providers` meta-argument must be given as a JSON object whose properties
+are the compact provider addresses to expose into the child module and whose
+values are the provider addresses to use from the current module, both
+given as literal strings:
+
+```json
+{
+  "module": {
+    "example": {
+      "source": "hashicorp/consul/azurerm",
+      "version": "= 1.0.0",
+      "providers": {
+        "aws": "aws.usw1"
+      }
+    }
+  }
+}
+```
+
+### `provider` blocks
+
+The `alias` and `version` meta-arguments must be given as literal strings. The
+values are not interpreted as string templates.
+
+```json
+{
+  "provider": {
+    "aws": [
+      {
+        "region": "us-east-1"
+      },
+      {
+        "alias": "usw1",
+        "region": "us-west-1"
+      }
+    ]
+  }
+}
+```
+
+### `terraform` blocks
+
+Since no settings within `terraform` blocks accept named object references or
+function calls, all setting values are taken literally. String values are not
+interpreted as string templates.
+
+Since only one `backend` block is allowed per `terraform` block, the compact
+block mapping can be used to represent it, with a nested object containing
+a single property whose name represents the backend type.
+
+```json
+{
+  "terraform": {
+    "required_version": ">= 0.12.0",
+    "backend": {
+      "s3": {
+        "region": "us-west-2",
+        "bucket": "acme-terraform-states"
+      }
+    }
+  }
+}
+```
diff --git a/v1.5.7/website/docs/language/syntax/style.mdx b/v1.5.7/website/docs/language/syntax/style.mdx
new file mode 100644
index 0000000..8cb0366
--- /dev/null
+++ b/v1.5.7/website/docs/language/syntax/style.mdx
@@ -0,0 +1,70 @@
+---
+page_title: Style Conventions - Configuration Language
+description: >-
+  Learn recommended formatting conventions for the Terraform language and a
+  command to automatically enforce them.
+---
+
+# Style Conventions
+
+The Terraform parser allows you some flexibility in how you lay out the
+elements in your configuration files, but the Terraform language also has some
+idiomatic style conventions which we recommend users always follow
+for consistency between files and modules written by different teams.
+Automatic source code formatting tools may apply these conventions
+automatically.
+
+-> **Note**: You can enforce these conventions automatically by running [`terraform fmt`](/terraform/cli/commands/fmt).
+
+* Indent two spaces for each nesting level.
+
+* When multiple arguments with single-line values appear on consecutive lines
+  at the same nesting level, align their equals signs:
+
+  ```hcl
+  ami           = "abc123"
+  instance_type = "t2.micro"
+  ```
+
+* When both arguments and blocks appear together inside a block body,
+  place all of the arguments together at the top and then place nested
+  blocks below them. Use one blank line to separate the arguments from
+  the blocks.
+
+* Use empty lines to separate logical groups of arguments within a block.
+
+* For blocks that contain both arguments and "meta-arguments" (as defined by
+  the Terraform language semantics), list meta-arguments first
+  and separate them from other arguments with one blank line. Place
+  meta-argument blocks _last_ and separate them from other blocks with
+  one blank line.
+
+  ```hcl
+  resource "aws_instance" "example" {
+    count = 2 # meta-argument first
+
+    ami           = "abc123"
+    instance_type = "t2.micro"
+
+    network_interface {
+      # ...
+    }
+
+    lifecycle { # meta-argument block last
+      create_before_destroy = true
+    }
+  }
+  ```
+
+* Top-level blocks should always be separated from one another by one
+  blank line. Nested blocks should also be separated by blank lines, except
+  when grouping together related blocks of the same type (like multiple
+  `provisioner` blocks in a resource).
+
+* Avoid grouping multiple blocks of the same type with other blocks of
+  a different type, unless the block types are defined by semantics to
+  form a family.
+  (For example: `root_block_device`, `ebs_block_device` and
+  `ephemeral_block_device` on `aws_instance` form a family of block types
+  describing AWS block devices, and can therefore be grouped together and
+  mixed.)
diff --git a/v1.5.7/website/docs/language/upgrade-guides/index.mdx b/v1.5.7/website/docs/language/upgrade-guides/index.mdx
new file mode 100644
index 0000000..9c65a19
--- /dev/null
+++ b/v1.5.7/website/docs/language/upgrade-guides/index.mdx
@@ -0,0 +1,56 @@
+---
+page_title: Upgrading to Terraform v1.5
+description: Upgrading to Terraform v1.5
+---
+
+# Upgrading to Terraform v1.5
+
+-> **Tip:** Use the version selector to view the upgrade guides for older Terraform versions.
+
+Terraform v1.5 is a minor release in the stable Terraform v1.0 series.
+
+Terraform v1.5 honors the
+[Terraform v1.0 Compatibility Promises](https://developer.hashicorp.com/terraform/language/v1-compatibility-promises),
+but there are some behavior changes outside of those promises that may affect a
+small number of users. Specifically, the following updates may require
+additional upgrade steps:
+* [End of support for older macOS releases](#end-of-support-for-older-macos-releases)
+* [Linux DNS resolver changes](#linux-dns-resolver-changes)
+
+See [the full changelog](https://github.com/hashicorp/terraform/blob/v1.5/CHANGELOG.md)
+for more details. If you encounter any problems during upgrading which are not
+covered this guide, please start a new topic in
+[the Terraform community forum](https://discuss.hashicorp.com/c/terraform-core)
+to discuss it.
+
+## End of support for older macOS releases
+
+Terraform v1.5 will be the last release supported on macOS 10.13 High Sierra
+and macOS 10.14 Mojave, both of which are no longer maintained by Apple.
+
+Terraform v1.5 itself supports these older macOS versions, but we strongly
+recommend upgrading during the v1.5 release period so that you'll be ready to
+use Terraform v1.6 once it is released.
+
+## Linux DNS resolver changes
+
+Terraform on Linux uses a built-in DNS resolver rather than using the DNS
+resolver from the platform's C library, because this allows Terraform to run
+on systems with many different C libraries.
+
+In Terraform v1.5, the DNS resolver will now notice when you have set the
+`trust-ad` option in your `/etc/resolve.conf` file, and will respond by setting
+the "authentic data" option in outgoing DNS requests to better match the
+behavior of the GNU libc DNS resolver.
+
+Terraform does not pay any attention to the corresponding option in responses,
+but some DNSSEC-aware recursive resolvers return different responses when the
+request option isn't set. This should therefore avoid some potential situations
+where a DNS request from Terraform might get a different response than a
+similar request from other software on your system.
+
+We don't expect this behavior change to be significant for most Terraform users.
+
+Note that this change affects only DNS requests made by Terraform CLI itself,
+and not requests made by providers. Provider plugins are separate programs
+which handle DNS resolution themselves and so may have different behavior.
diff --git a/v1.5.7/website/docs/language/v1-compatibility-promises.mdx b/v1.5.7/website/docs/language/v1-compatibility-promises.mdx
new file mode 100644
index 0000000..95588fc
--- /dev/null
+++ b/v1.5.7/website/docs/language/v1-compatibility-promises.mdx
@@ -0,0 +1,655 @@
+---
+page_title: Terraform v1.x Compatibility Promises
+description: |-
+  From Terraform v1.0 onwards the Terraform team promises to preserve backward
+  compatibility for most of the Terraform language and the primary CLI
+  workflow, until the next major release.
+---
+
+# Terraform v1.x Compatibility Promises
+
+The release of Terraform v1.0 represents an important milestone in the
+development of the Terraform language and workflow. Terraform v1.0 is a stable
+platform for describing and managing infrastructure.
+
+In this release we're defining a number of Terraform behaviors that we intend
+to remain compatible with throughout the 1.x releases:
+
+* A large subset of Terraform language features.
+* A more conservative subset of the Terraform CLI workflow commands.
+* The wire protocol for communication between Terraform Core and Terraform
+  providers.
+* The wire protocols for installation of Terraform providers and external
+  Terraform modules.
+
+Our intention is that Terraform modules written for Terraform v1.0 will
+continue to plan and apply successfully, without required changes, throughout
+the v1.x releases.
+
+We also intend that automation built around the workflow subset described in
+this document will work without changes in all future v1.x releases.
+
+Finally, we intend that providers built against the currently-documented
+provider wire protocol will be compatible with all future Terraform v1.x
+releases targeting the same operating system and architecture, without the
+need for source code modification or binary recompilation.
+
+In short, we aim to make upgrades between v1.x releases straightforward,
+requiring no changes to your configuration, no extra commands to run upgrade
+steps, and no changes to any automation you've set up around Terraform.
+
+The Terraform v1.x series will be actively maintained for at least 18 months
+after v1.0.
+
+The following sections include some specific guidance on what we will promise
+throughout the v1.x series, for those who would like full details. At
+a higher level though, we don't intend to make any changes that would cause
+existing modules or automation to require changes when upgrading to a new
+v1.x release. We will generally treat compatibility problems in new Terraform
+CLI releases as bugs to be fixed unless there was a very significant
+justification for the change, such as in addressing a critical security
+problem or matching with a breaking change to a remote dependency that isn't
+directly under our control.
+
+## The Terraform Language
+
+The main Terraform Language includes the language syntax, the top-level
+structures such as `resource`, `module`, and `provider` blocks, the
+"meta-arguments" in those blocks, and the documented semantics and behaviors
+for the operators and built-in functions available for use in expressions.
+
+There is not a single formal specification for the Terraform language, but the
+Configuration section of the documentation on the Terraform website serves as a
+description of the language features and their intended behaviors.
+
+The following top-level blocks and their defined "meta-arguments" (that is,
+arguments defined by Terraform Core rather than by external plugins such as
+providers) will retain their current functionality:
+
+* [`resource`](/terraform/language/resources) and
+  [`data`](/terraform/language/data-sources) blocks to
+  declare resources, including their nested block types `lifecycle`,
+  `connection`, and `provisioner`, and their meta-argument `provider`.
+* [`module`](/terraform/language/modules/syntax) blocks to call other modules,
+  and its meta-argument `providers`.
+* The [`count`](/terraform/language/meta-arguments/count),
+  [`for_each`](/terraform/language/meta-arguments/for_each), and
+  [`depends_on`](/terraform/language/meta-arguments/depends_on) meta-arguments
+  in `resource`, `data`, and `module` blocks.
+* [`provider`](/terraform/language/providers/configuration) blocks to configure
+  providers, and the `alias` meta-argument.
+* [`variable`](/terraform/language/values/variables#declaring-an-input-variable),
+  [`output`](/terraform/language/values/outputs#declaring-an-output-value), and
+  [`locals`](/terraform/language/values/locals#declaring-a-local-value) blocks
+  for declaring the various kinds of named values in a module.
+* [`terraform`](/terraform/language/settings) blocks, including the nested
+  [`required_version`](/terraform/language/settings#specifying-a-required-terraform-version)
+  and
+  [`required_providers`](/terraform/language/providers/requirements#requiring-providers)
+  arguments, and nested
+  [`backend`](/terraform/language/settings/backends/configuration#using-a-backend-block)
+  blocks for backend configuration.
+
+We also intend to keep compatibility with all
+[expression operators](/terraform/language/expressions) and
+[built-in functions](/terraform/language/functions), with the exception of
+references to
+[`terraform.workspace`](/terraform/language/expressions/references#terraform-workspace),
+whose behavior may change as part of future changes to the workspace model.
+
+We intend to retain broad compatibility with Terraform language features, with
+a few specific caveats:
+
+* We consider a configuration to be valid if Terraform can create and apply
+  a plan for it without reporting any errors.
+
+  A configuration that currently produces errors might generate different
+  errors or exhibit other non-error behaviors in a future version of
+  Terraform. A configuration that generates errors during the apply phase
+  might generate similar errors at an earlier phase in future, because
+  we generally consider it better to detect errors in as early a phase as
+  possible.
+
+  Generally-speaking, the compatibility promises described in this document
+  apply only to valid configurations. Handling of invalid configurations is
+  always subject to change in future Terraform releases.
+* If the actual behavior of a feature differs from what we explicitly
+  documented as the feature's behavior, we will usually treat that as a bug
+  and change the feature to match the documentation, although we will avoid
+  making such changes if they seem likely to cause broad compatibility problems.
+  We cannot promise to always remain "bug-compatible" with previous releases,
+  but we will consider such fixes carefully to minimize their impact.
+* Any experimental features may change or may be removed entirely from future
+  releases. Terraform always produces a warning when an experimental language
+  feature is active, to make you aware of that risk. We don't recommend using
+  experimental features in production modules.
+* We will introduce new language features, and if you start using them then
+  your configuration won't work with prior Terraform versions that didn't
+  support those features yet.
+* Terraform Providers are separate plugins which can change independently of
+  Terraform Core and are therefore not subject to these compatibility promises.
+  If you upgrade any of the providers you are using then you might need to
+  change provider or resource configurations related to those providers.
+* A small number of features remain deprecated with explicit warnings in
+  Terraform v1.0. Those deprecation cycles will end in a future v1.x release,
+  at which point we will remove the corresponding features.
+
+## Workflow
+
+There is a set of often used Terraform workflows, which we are calling
+_protected workflows_. We will not remove these commands, subcommands, and
+flags or make backward-incompatible changes to protected workflow
+functionality. If we accidentally change these, we will consider
+backwards-incompatible changes to core workflows as bugs to be fixed. For a
+list of the command and option combinations that are part of protected
+workflows, see [Protected Workflow Commands](#protected-workflow-commands).
+There is another set of commands that we are explicitly _not_ making
+compatibility promises about, because we expect their functionality to change
+in v1.x releases: see [Commands That Might Change](#commands-that-might-change).
+
+The supported ways for external software to interact with Terraform are via
+the JSON output modes offered by some commands and via exit status codes.
+We may extend certain JSON formats with new object properties but we will not
+remove or make breaking changes to the definitions of existing properties.
+
+Natural language command output or log output is not a stable interface and
+may change in any new version. If you write software that parses this output
+then it may need to be updated when you upgrade Terraform. If you need access
+to data that is not currently available via one of the machine-readable JSON
+interfaces, we suggest opening a feature request to discuss your use-case.
+
+## Upgrading and Downgrading
+
+Throughout the v1.x series of releases, we intend that you should be able to
+switch to a newer Terraform version and use it just as before, without any
+special upgrade steps.
+
+You should be able to upgrade from any v1.x release to any later v1.x release.
+You might also be able to downgrade to an earlier v1.x release, but that isn't
+guaranteed: later releases may introduce new features that earlier versions
+cannot understand, including new storage formats for Terraform state snapshots.
+
+If you make use of features introduced in a later v1.x release, your
+configuration won't be compatible with releases that predate that feature.
+For example, if a language feature is added in v1.3 and you start using it, your
+Terraform configuration will no longer be compatible with Terraform v1.2.
+
+## Providers
+
+Terraform providers are separate plugins which communicate with Terraform using
+a documented protocol. Therefore these compatibility promises can only cover
+the "client" side of this protocol as implemented by Terraform Core; the
+behaviors of individual providers, including which resource types they support
+and which arguments they expect, are decided by the provider development teams
+and can change independently of Terraform Core releases.
+
+If you upgrade to a new version of a provider then you might need to change
+the parts of your configuration which are interpreted by that provider, even
+if you are still using a Terraform v1.x release.
+
+### Provider Installation Methods
+
+Terraform normally installs providers from a provider registry implementing
+[the Provider Registry Protocol](/terraform/internals/provider-registry-protocol),
+version 1. All Terraform v1.x releases will remain compatible with that
+protocol, and so correctly-implemented provider registries will stay compatible.
+
+Terraform also supports installation of providers from
+[local filesystem directories](/terraform/cli/config/config-file#filesystem_mirror)
+(filesystem mirrors) and from
+[network mirrors](/terraform/cli/config/config-file#network_mirror)
+(implementing [the Provider Mirror Protocol](/terraform/internals/provider-network-mirror-protocol).
+All Terraform v1.x releases will remain compatible with those installation
+methods, including
+[the Implied Local Mirror Directories](/terraform/cli/config/config-file#implied-local-mirror-directories).
+
+Specific provider registries or network mirrors are run independently from
+Terraform itself and so their own behaviors are not subject to these
+compatibility promises.
+
+### Provider Protocol Versions
+
+The current major version of the provider plugin protocol as of Terraform v1.0
+is version 5, which is defined by a combination of a Protocol Buffers schema
+describing the physical wire formats and by additional prose documentation
+describing the expected provider behaviors.
+
+We will support protocol version 5 throughout the Terraform v1.x releases. If
+we make new minor revisions to protocol version 5 in later releases then we
+will design them such that existing plugins will continue to work, as long as
+they correctly implemented the protocol.
+
+We may introduce new major versions of the protocol during the v1.x series. If
+so, we will continue to support protocol version 5 alongside those new versions.
+Individual provider teams might decide to remove support for protocol version 5
+in later releases, in which case those new provider releases will not be
+compatible with all of the Terraform v1.x releases.
+
+## External Modules
+
+Terraform modules are reusable infrastructure components written in the
+Terraform language. Some modules are "external" in the sense that Terraform
+automatically installs them from a location other than the current
+configuration directory, in which case their contents could change
+independently of changes to your local modules, of the providers you use,
+and of Terraform itself.
+
+### Module Installation Methods
+
+Terraform supports installing child modules from a number of different
+[module source types](/terraform/language/modules/sources). We will continue
+to support all of the existing source types throughout the v1.x releases.
+
+One of the supported source types is a module registry implementing
+[the Module Registry Protocol](/terraform/internals/module-registry-protocol)
+version 1. All Terraform v1.x releases will remain compatible with correct
+implementations of that protocol.
+
+Some module source types work directly with services or protocols defined and
+run by third parties. Although we will not remove Terraform's own client-side
+support for those, we cannot guarantee that their owners will keep those
+services running or that they will remain compatible with Terraform's client
+implementations.
+
+### External Module Compatibility
+
+If your configuration depends on external modules, newer versions of those
+modules may include breaking changes. External modules are not part of
+Terraform and are therefore not subject to these compatibility promises.
+
+## Provisioners
+
+We will maintain compatibility for the `file`, `local-exec`, and `remote-exec`
+provisioner types through all v1.x releases.
+
+Some additional vendor-specific provisioners were available in earlier
+Terraform versions but were deprecated in Terraform v0.13 and removed in
+Terraform v0.15.
+
+Terraform supports loading additional provisioners as plugins from certain
+local filesystem directories. We'll continue to support that throughout the
+Terraform v1.x releases, but since such plugins are separate from Terraform
+Core itself their own behaviors cannot be subject to these compatibility
+promises. However, we will continue to support the plugin wire protocol as
+defined in Terraform v1.0 throughout the v1.x releases, and so
+correctly-implemented provisioner plugins should remain compatible with future
+Terraform releases.
+
+## State Storage Backends
+
+When you use _remote state_, Terraform interacts with remote services over
+the network in order to store and manage locks for Terraform state.
+
+For historical reasons, all supported state storage backends are included as
+part of Terraform CLI but not all are supported directly by the Terraform
+Team. Only the following backends maintained by the Terraform team are subject
+to compatibility promises:
+
+* `local` (the default, when you are not using remote state)
+* `http`
+
+The other state storage backends are maintained by external teams via
+contributions to the Terraform CLI codebase, and so their expected
+configuration arguments or behaviors might change even in v1.x releases,
+although we will aim to still ensure a good migration path in such cases,
+where possible.
+
+We are considering allowing external state storage backend implementations
+via plugins, similar to provider plugins. If we introduce such a mechanism
+during the v1.x releases then you may need to make configuration changes in
+order to use those plugins, and state storage backends other than those
+listed above may be removed from later versions of Terraform CLI once
+equivalent plugins are available.
+
+### The `remote` Backend and Terraform Cloud
+
+The `remote` backend is maintained by the Terraform Cloud team and so its
+behavior may change along with ongoing changes to Terraform Cloud.
+
+There will be a supported mechanism to use Terraform CLI with Terraform Cloud
+throughout the v1.x releases, but the exact details may change. Terraform Cloud
+evolves independently of Terraform CLI and is therefore not subject to these
+compatibility promises.
+
+## Community-maintained State Storage Backends
+
+The `azurerm`, `consul`, `s3`, and `kubernetes` backends are maintained by
+other teams at HashiCorp. Those teams intend to continue basic maintenence at
+the level of bug fixes through the v1.x releases, unless we implement a plugin
+protocol for backends at which point development of these backends is likely
+to continue in the external plugins only, which may require configuration
+changes to switch to the plugin equivalents.
+
+The `cos`, `oss`, `pg`, `gcs`, and `etcdv3` backends are maintained by outside
+contributors and are not subject to these compatibility promises.
+
+### Unmaintained State Storage Backends
+
+The `artifactory`, `etcdv2`, `manta`, and `swift` state storage backends do not
+currently have any maintainers and thus remain in Terraform CLI releases on
+a best-effort basis. They may be removed in later v1.x releases, and will not
+be updated in case of any breaking changes to the services they integrate with.
+
+## Supported Platforms
+
+Throughout the v1.x series we will continue to produce official releases for
+the following platforms, and make changes as necessary to support new
+releases of these operating systems:
+
+* macOS on x64 CPUs (`darwin_amd64`)
+* Windows on x64 CPUs (`windows_amd64`)
+* Linux on x64, 32-bit ARMv6, and 64-bit ARMv8 (`linux_amd64`, `linux_arm`, and `linux_arm64` respectively)
+
+Over time we may require newer versions of these operating systems. For
+example, subsequent Terraform releases in the v1.x series might end support
+for earlier versions of macOS or Windows, or earlier Linux kernel releases.
+
+We have historically produced official releases for a number of other platforms
+as a convenience to users of those platforms, and we have no current plans to
+stop publishing them but we cannot promise ongoing releases or bug fixes for
+the other platforms throughout the v1.x series. We do not routinely test
+Terraform on any platforms other than those listed above.
+
+We might add support for new platforms in later v1.x releases. If so, earlier
+Terraform releases prior to that support will not be available on those
+platforms.
+
+All Terraform plugins, including provider plugins, are separate programs that
+have their own policies for which platforms they support. We cannot guarantee
+that all providers currently support or will continue to support the platforms
+listed above, even though Terraform CLI itself will support them.
+
+## Later Revisions to These Promises
+
+We may extend or refine these promises throughout the v1.x series in order to
+describe promises related to new features or to clarify existing promises if
+we find via feedback that our earlier statements had been unclear.
+
+Promises for new features will be additive in the sense that they will add
+further promises without retracting any existing ones. For promises that only
+apply to later v1.x releases we will mention the earliest version(s) those
+promises apply to.
+
+Even if we don't add an explicit statement to this document, we intend that
+any non-experimental features added in later v1.x releases will remain
+compatible at least through the remainder of the v1.x series, unless otherwise
+stated.
+
+## Appendices
+
+### Protected Workflow Commands
+
+The following is the list of Terraform CLI subcommands and options that are
+subject to these compatibility promises. If you build automation around
+these commands then it should be compatible with all later v1.x releases.
+
+As noted above, compatibility with external software is limited to
+explicitly-machine-readable output (`-json` and `-raw` modes) and exit codes.
+Any natural-language output from these commands might change in later releases.
+
+* [`init`](/terraform/cli/commands/init)
+  * `-backend=false`
+  * `-backend-config=FILE`
+  * `-backend-config="KEY=VALUE"`
+  * `-force-copy`
+  * `-get=false`
+  * `-input=false`
+  * `-migrate-state`
+  * `-no-color`
+  * `-plugin-dir=DIR`
+  * `-reconfigure`
+  * `-upgrade`
+* [`validate`](/terraform/cli/commands/validate)
+  * `-json`
+  * `-no-color`
+* [`plan`](/terraform/cli/commands/plan)
+  * `-compact-warnings`
+  * `-destroy`
+  * `-detailed-exitcode`
+  * `-lock=false`
+  * `-lock-timeout=DURATION`
+  * `-input=false`
+  * `-json`
+  * `-no-color`
+  * `-out=FILE`
+  * `-parallelism=N`
+  * `-refresh=false`
+  * `-refresh-only`
+  * `-replace=ADDRESS`
+  * `-target=ADDRESS`
+  * `-var 'NAME=VALUE'`
+  * `-var-file=FILE`
+* [`apply`](/terraform/cli/commands/apply)
+  * `-auto-approve`
+  * `-compact-warnings`
+  * `-lock=false`
+  * `-lock-timeout=DURATION`
+  * `-input=false`
+  * `-json`
+  * `-no-color`
+  * `-parallelism=N`
+  * `-refresh=false`
+  * `-refresh-only`
+  * `-replace=ADDRESS`
+  * `-target=ADDRESS`
+  * `-var 'NAME=VALUE'`
+  * `-var-file=FILE`
+* [`show`](/terraform/cli/commands/show)
+  * `-no-color`
+  * `-json`
+  * (both with and without a plan file)
+* [`providers`](/terraform/cli/commands/providers) (with no subcommand)
+* [`providers lock`](/terraform/cli/commands/providers/lock)
+  * `-fs-mirror=PATH`
+  * `-net-mirror=URL`
+  * `-platform=OS_ARCH`
+* [`providers mirror`](/terraform/cli/commands/providers/mirror)
+  * `-platform=OS_ARCH`
+* [`providers schema`](/terraform/cli/commands/providers/schema)
+  * `-json`
+* [`fmt`](/terraform/cli/commands/fmt)
+  * `-list=false`
+  * `-write=false`
+  * `-diff`
+  * `-recursive`
+  * `-check`
+* [`version`](/terraform/cli/commands/version)
+  * `-json`
+* [`output`](/terraform/cli/commands/output)
+  * `-no-color`
+  * `-json`
+  * `-raw`
+* [`taint`](/terraform/cli/commands/taint)
+  * `-allow-missing`
+  * `-lock=false`
+  * `-lock-timeout=DURATION`
+  * `-ignore-remote-version`
+* [`untaint`](/terraform/cli/commands/untaint)
+  * `-allow-missing`
+  * `-lock=false`
+  * `-lock-timeout=DURATION`
+  * `-ignore-remote-version`
+* [`force-unlock`](/terraform/cli/commands/force-unlock)
+  * `-force`
+* [`state list`](/terraform/cli/commands/state/list)
+  * `-id=ID`
+* [`state pull`](/terraform/cli/commands/state/pull)
+* [`state push`](/terraform/cli/commands/state/push)
+  * `-force`
+  * `-lock=false`
+  * `-lock-timeout=DURATION`
+* [`state show`](/terraform/cli/commands/state/show)
+  * `-ignore-remote-version`
+* [`login`](/terraform/cli/commands/login)
+
+For commands or options not in the above list, we will still avoid breaking
+changes where possible, but can't promise full compatibility throughout the
+v1.x series. If you are building automation around Terraform, use only the
+commands above to avoid the need for changes when upgrading.
+
+Please note that although Terraform's internal logs (via the `TF_LOG`
+environment variable) are available in a JSON format, the particular syntax
+or structure of those log lines is _not_ a supported integration interface.
+The logs are available as JSON only to help with ad-hoc filtering and
+processing of logs by Terraform developers.
+
+### Commands That Might Change
+
+All of the following commands and their subcommands/options are _not_ subject
+to compatibility promises, either because we have existing plans to improve
+them during the v1.x series or because we are aware of shortcomings in their
+design that might require breaking changes for ongoing maintenence.
+
+While you can freely use these commands when running Terraform interactively
+as long as they remain supported, we don't recommend using them as part of
+any automation unless you are willing to potentially update that automation
+when upgrading to a later v1.x release.
+
+* `destroy` (consider `terraform apply -destroy` instead)
+* `console`
+* `get` (consider `terraform init` instead)
+* `graph`
+* `import`
+* `push`
+* `refresh` (consider `terraform apply -refresh-only` instead)
+* `state mv`
+* `state replace-provider`
+* `state rm`
+* all subcommands of `workspace` (and its deprecated alias `env`)
+
+While we do intend to retain support for the main use-cases associated with
+these commands in future releases, we cannot promise to retain the exact
+command names or options used to meet those use-cases.
+
+## How We Will Keep These Promises
+
+### Automated Regression Testing
+
+The Terraform codebase includes various unit and integration tests intended to
+help us to notice accidental behavior regressions before they ship in a stable
+version.
+
+However, Terraform is a relatively complex system with many different features
+that can interact in interesting ways. In the past we've seen reports of
+behavior differences that appeared only when combining two or more features in
+a way we hadn't previously anticipated or written automated tests for.
+
+In each case we have both implemented a change to resolve the compatibility
+problem _and_ added one or more integration tests representing the behavior
+of that combination of features. We intend to continue this approach, so we can
+improve Terraform's test coverage over time.
+
+### Prerelease Versions
+
+We intend that most accidental changes in behavior covered by these promises
+will be caught by existing tests. However, we also accept that our test suite
+can never have perfect coverage of all possible feature interactions or other
+edge cases, and so we aim for each significant change to be included in both
+alpha and beta releases before eventual inclusion in a final release.
+
+For minor releases we will typically also issue at least one release candidate
+prior to the final release. A release candidate represents that planned
+development is concluded and that we've fixed any regressions reported based
+on the alpha and beta releases, and thus the final release that follows should
+typically match exactly or almost exactly its most recent release candidate.
+
+### Regressions in Final Releases
+
+For more obscure combinations of features it is possible that a regression
+could be undetected during prerelease the prerelease periods and thus included
+in a final release.
+
+If someone finds and reports such a regression soon after its release then we
+will treat it as a bug and fix it to restore the previous behavior in future
+releases, unless there is a very significant justification such as a security
+advisory. In these cases, we'll typically recommend anyone affected by the
+regression remain on the previous version until the problem is fixed and then
+skip forward directly to the new release containing that fix.
+
+You can minimize the risk of being affected by missed regressions in final
+releases by proactively testing modules against alpha, beta, and release
+candidate packages. We recommend doing so only in isolated development or
+staging environments rather than against your production infrastructure. If you
+find a change in behavior in a prerelease build that seems contrary to the
+promises in this document, please open an issue in Terraform's GitHub
+repository to discuss it.
+
+### Late-reported Regressions
+
+In the most extreme case, there may be a regression with a combination of
+features that is so rare that it remains undetected for a long time.
+
+After a change has been included in more releases it becomes increasingly
+likely that other users will have depended on the newer behavior and thus we
+will need to make a tradeoff to decide whether restoring the behavior would
+have a greater negative impact than retaining the new behavior. We will always
+make this decision with due consideration to the implications of each unique
+situation.
+
+You can minimize the risk of your modules being affected by late-reported
+regressions by upgrading promptly to new minor and patch releases of Terraform
+and reporting any compatibility problems you encounter in Terraform's GitHub
+repository.
+
+### Pragmatic Exceptions
+
+We are making the promises above in good faith, with the intent that your
+investment in writing Terraform modules or automation will not be invalidated
+by future changes to Terraform. However, broad promises like the above can't
+possibly cover all nuances of practical problems that might arise as we
+continue to develop Terraform.
+
+For that reason, there are some situations where we may still need to make
+changes that may impact existing modules or automation:
+
+* Security problems: We may become aware of a design problem that has an
+  important security impact. Depending on our determination of the associated
+  risk, we may choose to break compatibility to achieve a more secure system.
+* External Dependencies: Terraform's behavior depends on interfaces provided
+  by external codebases, including your chosen operating system and including
+  some remote network services for situations such as module and provider
+  installation. These external systems can change outside of our control,
+  including potentially removing or changing features that Terraform's own
+  features depend on. In that case, if there is no suitable replacement
+  mechanism then we may need to change Terraform's design to work within the
+  new constraints.
+* Opt-in Compatibility Breaks: The design of a language new feature may require
+  changing the behavior or configuration representation of an existing feature.
+  If so, we will typically make the new feature opt-in only in order to avoid
+  breaking existing modules, but if you change your module to opt in to the
+  new feature then you may also then be required to change other parts of your
+  configuration to work with the new language design.
+* Bugs in New Features: If we introduce a new feature to Terraform and the
+  initial implementation has problems that cause it to not match the documented
+  design intent at release, we may make a follow-up release that corrects
+  the implementation to match the documented design, even if that represents
+  a minor compatibility regression compared to the initial implementation.
+  However, once a feature is well-established and in common use we will usually
+  defer to the implemented behavior and instead change the documentation to
+  reflect it.
+* Regressions in Existing Features: If we learn that a new Terraform release
+  includes a regression for an existing feature that wasn't detected during
+  the development and prerelease periods, and that learning comes promptly
+  after the new release, we will typically restore the previous behavior at
+  the expense of technically therefore breaking compatibility with the behavior
+  of the new release, under the assumption that more users will have systems
+  affected by the regression than will have systems depending on the
+  newly-introduced behavior.
+* Late-reported regressions: As described in the previous section, if we
+  learn that there was an unintentional regression of a rarely-used feature or
+  combination of features in a much earlier release then restoring the previous
+  behavior may appear as a regression to later adopters. If we believe that
+  fixing the regression would affect more users than the regression itself
+  affects then we may choose to accept the regression as the new promised
+  behavior.
+* Situations we cannot anticipate: Although we've made an effort to consider
+  various specific exceptional situations here, Terraform and its development
+  process are not isolated from broader context, and so we must consider that
+  there may be situations that we cannot possibly anticipate that would affect
+  the future of Terraform. In those situations, we will always do our best to
+  find a course of action that will minimize as much as possible the impact to
+  existing modules and automation.
+
+Our intent with these pragmatic exceptions is only to acknowledge that there
+will always be situations that general compatibility promises cannot address.
+We will use these exceptions only with due consideration and as a last resort.
diff --git a/v1.5.7/website/docs/language/values/index.mdx b/v1.5.7/website/docs/language/values/index.mdx
new file mode 100644
index 0000000..bd20755
--- /dev/null
+++ b/v1.5.7/website/docs/language/values/index.mdx
@@ -0,0 +1,20 @@
+---
+page_title: Variables and Outputs
+description: >-
+  An overview of input variables, output values, and local values in Terraform
+  language.
+---
+
+# Variables and Outputs
+
+The Terraform language includes a few kinds of blocks for requesting or
+publishing named values.
+
+- [Input Variables](/terraform/language/values/variables) serve as parameters for
+  a Terraform module, so users can customize behavior without editing the source.
+
+- [Output Values](/terraform/language/values/outputs) are like return values for a
+  Terraform module.
+
+- [Local Values](/terraform/language/values/locals) are a convenience feature for
+  assigning a short name to an expression.
diff --git a/v1.5.7/website/docs/language/values/locals.mdx b/v1.5.7/website/docs/language/values/locals.mdx
new file mode 100644
index 0000000..b6c1807
--- /dev/null
+++ b/v1.5.7/website/docs/language/values/locals.mdx
@@ -0,0 +1,87 @@
+---
+page_title: Local Values - Configuration Language
+description: >-
+  Local values assign a name to an expression that can be used multiple times
+  within a Terraform module.
+---
+
+# Local Values
+
+> **Hands-on:** Try the [Simplify Terraform Configuration with Locals](/terraform/tutorials/configuration-language/locals?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+A local value assigns a name to an [expression](/terraform/language/expressions),
+so you can use the name multiple times within a module instead of repeating
+the expression.
+
+If you're familiar with traditional programming languages, it can be useful to
+compare Terraform modules to function definitions:
+
+- [Input variables](/terraform/language/values/variables) are like function arguments.
+- [Output values](/terraform/language/values/outputs) are like function return values.
+- Local values are like a function's temporary local variables.
+
+-> **Note:** For brevity, local values are often referred to as just "locals"
+when the meaning is clear from context.
+
+## Declaring a Local Value
+
+A set of related local values can be declared together in a single `locals`
+block:
+
+```hcl
+locals {
+  service_name = "forum"
+  owner        = "Community Team"
+}
+```
+
+The expressions in local values are not limited to literal constants; they can
+also reference other values in the module in order to transform or combine them,
+including variables, resource attributes, or other local values:
+
+```hcl
+locals {
+  # Ids for multiple sets of EC2 instances, merged together
+  instance_ids = concat(aws_instance.blue.*.id, aws_instance.green.*.id)
+}
+
+locals {
+  # Common tags to be assigned to all resources
+  common_tags = {
+    Service = local.service_name
+    Owner   = local.owner
+  }
+}
+```
+
+## Using Local Values
+
+Once a local value is declared, you can reference it in
+[expressions](/terraform/language/expressions) as `local.<NAME>`.
+
+-> **Note:** Local values are _created_ by a `locals` block (plural), but you
+_reference_ them as attributes on an object named `local` (singular). Make sure
+to leave off the "s" when referencing a local value!
+
+```
+resource "aws_instance" "example" {
+  # ...
+
+  tags = local.common_tags
+}
+```
+
+A local value can only be accessed in expressions within the module where it
+was declared.
+
+## When To Use Local Values
+
+Local values can be helpful to avoid repeating the same values or expressions
+multiple times in a configuration, but if overused they can also make a
+configuration hard to read by future maintainers by hiding the actual values
+used.
+
+Use local values only in moderation, in situations where a single value or
+result is used in many places _and_ that value is likely to be changed in
+future. The ability to easily change the value in a central place is the key
+advantage of local values.
diff --git a/v1.5.7/website/docs/language/values/outputs.mdx b/v1.5.7/website/docs/language/values/outputs.mdx
new file mode 100644
index 0000000..650eedb
--- /dev/null
+++ b/v1.5.7/website/docs/language/values/outputs.mdx
@@ -0,0 +1,217 @@
+---
+page_title: Output Values - Configuration Language
+description: Output values are the return values of a Terraform module.
+---
+
+# Output Values
+
+Output values make information about your infrastructure available on the
+command line, and can expose information for other Terraform configurations to
+use. Output values are similar to return values in programming languages.
+
+> **Hands-on:** Try the [Output Data From
+> Terraform](/terraform/tutorials/configuration-language/outputs)
+> tutorial.
+
+Output values have several uses:
+
+- A child module can use outputs to expose a subset of its resource attributes
+  to a parent module.
+- A root module can use outputs to print certain values in the CLI output after
+  running `terraform apply`.
+- When using [remote state](/terraform/language/state/remote), root module outputs can be
+  accessed by other configurations via a
+  [`terraform_remote_state` data source](/terraform/language/state/remote-state-data).
+
+Resource instances managed by Terraform each export attributes whose values
+can be used elsewhere in configuration. Output values are a way to expose some
+of that information to the user of your module.
+
+-> **Note:** For brevity, output values are often referred to as just "outputs"
+when the meaning is clear from context.
+
+## Declaring an Output Value
+
+Each output value exported by a module must be declared using an `output`
+block:
+
+```hcl
+output "instance_ip_addr" {
+  value = aws_instance.server.private_ip
+}
+```
+
+The label immediately after the `output` keyword is the name, which must be a
+valid [identifier](/terraform/language/syntax/configuration#identifiers). In a root module, this name is
+displayed to the user; in a child module, it can be used to access the output's
+value.
+
+The `value` argument takes an [expression](/terraform/language/expressions)
+whose result is to be returned to the user. In this example, the expression
+refers to the `private_ip` attribute exposed by an `aws_instance` resource
+defined elsewhere in this module (not shown). Any valid expression is allowed
+as an output value.
+
+-> **Note:** Outputs are only rendered when Terraform applies your plan. Running
+`terraform plan` will not render outputs.
+
+## Accessing Child Module Outputs
+
+In a parent module, outputs of child modules are available in expressions as
+`module.<MODULE NAME>.<OUTPUT NAME>`. For example, if a child module named
+`web_server` declared an output named `instance_ip_addr`, you could access that
+value as `module.web_server.instance_ip_addr`.
+
+
+## Custom Condition Checks
+
+You can use `precondition` blocks to specify guarantees about output data. The following examples creates a precondition that checks whether the EC2 instance has an encrypted root volume.
+
+```hcl
+output "api_base_url" {
+  value = "https://${aws_instance.example.private_dns}:8433/"
+
+  # The EC2 instance must have an encrypted root volume.
+  precondition {
+    condition     = data.aws_ebs_volume.example.encrypted
+    error_message = "The server's root volume is not encrypted."
+  }
+}
+```
+
+Custom conditions can help capture assumptions, helping future maintainers understand the configuration design and intent. They also return useful information about errors earlier and in context, helping consumers more easily diagnose issues in their configurations.
+
+Refer to [Custom Condition Checks](/terraform/language/expressions/custom-conditions#preconditions-and-postconditions) for more details.
+
+## Optional Arguments
+
+`output` blocks can optionally include `description`, `sensitive`, and `depends_on` arguments, which are described in the following sections.
+
+<a id="description"></a>
+
+### `description` — Output Value Documentation
+
+Because the output values of a module are part of its user interface, you can
+briefly describe the purpose of each value using the optional `description`
+argument:
+
+```hcl
+output "instance_ip_addr" {
+  value       = aws_instance.server.private_ip
+  description = "The private IP address of the main server instance."
+}
+```
+
+The description should concisely explain the
+purpose of the output and what kind of value is expected. This description
+string might be included in documentation about the module, and so it should be
+written from the perspective of the user of the module rather than its
+maintainer. For commentary for module maintainers, use comments.
+
+<a id="sensitive"></a>
+
+### `sensitive` — Suppressing Values in CLI Output
+
+An output can be marked as containing sensitive material using the optional
+`sensitive` argument:
+
+```hcl
+output "db_password" {
+  value       = aws_db_instance.db.password
+  description = "The password for logging in to the database."
+  sensitive   = true
+}
+```
+
+Terraform will hide values marked as sensitive in the messages from
+`terraform plan` and `terraform apply`. In the following scenario, our root
+module has an output declared as sensitive and a module call with a
+sensitive output, which we then use in a resource attribute.
+
+```hcl
+# main.tf
+
+module "foo" {
+  source = "./mod"
+}
+
+resource "test_instance" "x" {
+  some_attribute = module.foo.a # resource attribute references a sensitive output
+}
+
+output "out" {
+  value     = "xyz"
+  sensitive = true
+}
+
+# mod/main.tf, our module containing a sensitive output
+
+output "a" {
+  value     = "secret"
+  sensitive = true
+}
+```
+
+When we run a plan or apply, the sensitive value is redacted from output:
+
+```
+Terraform will perform the following actions:
+
+  # test_instance.x will be created
+  + resource "test_instance" "x" {
+      + some_attribute    = (sensitive value)
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+Changes to Outputs:
+  + out = (sensitive value)
+```
+
+-> **Note:** In Terraform versions prior to Terraform 0.14, setting an output
+value in the root module as sensitive would prevent Terraform from showing its
+value in the list of outputs at the end of `terraform apply`. However, the
+value could still display in the CLI output for other reasons, like if the
+value is referenced in an expression for a resource argument.
+
+Terraform will still record sensitive values in the [state](/terraform/language/state),
+and so anyone who can access the state data will have access to the sensitive
+values in cleartext. For more information, see
+[_Sensitive Data in State_](/terraform/language/state/sensitive-data).
+
+<a id="depends_on"></a>
+
+### `depends_on` — Explicit Output Dependencies
+
+Since output values are just a means for passing data out of a module, it is
+usually not necessary to worry about their relationships with other nodes in
+the dependency graph.
+
+However, when a parent module accesses an output value exported by one of its
+child modules, the dependencies of that output value allow Terraform to
+correctly determine the dependencies between resources defined in different
+modules.
+
+Just as with
+[resource dependencies](/terraform/language/resources/behavior#resource-dependencies),
+Terraform analyzes the `value` expression for an output value and automatically
+determines a set of dependencies, but in less-common cases there are
+dependencies that cannot be recognized implicitly. In these rare cases, the
+`depends_on` argument can be used to create additional explicit dependencies:
+
+```hcl
+output "instance_ip_addr" {
+  value       = aws_instance.server.private_ip
+  description = "The private IP address of the main server instance."
+
+  depends_on = [
+    # Security group rule must be created before this IP address could
+    # actually be used, otherwise the services will be unreachable.
+    aws_security_group_rule.local_access,
+  ]
+}
+```
+
+The `depends_on` argument should be used only as a last resort. When using it,
+always include a comment explaining why it is being used, to help future
+maintainers understand the purpose of the additional dependency.
diff --git a/v1.5.7/website/docs/language/values/variables.mdx b/v1.5.7/website/docs/language/values/variables.mdx
new file mode 100644
index 0000000..3bc66db
--- /dev/null
+++ b/v1.5.7/website/docs/language/values/variables.mdx
@@ -0,0 +1,517 @@
+---
+page_title: Input Variables - Configuration Language
+description: >-
+  Input variables allow you to customize modules without altering their source
+  code. Learn how to declare, define, and reference variables in configurations.
+---
+
+# Input Variables
+
+> **Hands-on:** Try the [Customize Terraform Configuration with Variables](/terraform/tutorials/configuration-language/variables?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+Input variables let you customize aspects of Terraform modules without altering
+the module's own source code. This functionality allows you to share modules across different
+Terraform configurations, making your module composable and reusable.
+
+When you declare variables in the root module of your configuration, you can
+set their values using CLI options and environment variables.
+When you declare them in [child modules](/terraform/language/modules),
+the calling module should pass values in the `module` block.
+
+If you're familiar with traditional programming languages, it can be useful to
+compare Terraform modules to function definitions:
+
+* Input variables are like function arguments.
+* [Output values](/terraform/language/values/outputs) are like function return values.
+* [Local values](/terraform/language/values/locals) are like a function's temporary local variables.
+
+-> **Note:** For brevity, input variables are often referred to as just
+"variables" or "Terraform variables" when it is clear from context what sort of
+variable is being discussed. Other kinds of variables in Terraform include
+_environment variables_ (set by the shell where Terraform runs) and _expression
+variables_ (used to indirectly represent a value in an
+[expression](/terraform/language/expressions)).
+
+## Declaring an Input Variable
+
+Each input variable accepted by a module must be declared using a `variable`
+block:
+
+```hcl
+variable "image_id" {
+  type = string
+}
+
+variable "availability_zone_names" {
+  type    = list(string)
+  default = ["us-west-1a"]
+}
+
+variable "docker_ports" {
+  type = list(object({
+    internal = number
+    external = number
+    protocol = string
+  }))
+  default = [
+    {
+      internal = 8300
+      external = 8300
+      protocol = "tcp"
+    }
+  ]
+}
+```
+
+The label after the `variable` keyword is a name for the variable, which must
+be unique among all variables in the same module. This name is used to
+assign a value to the variable from outside and to reference the variable's
+value from within the module.
+
+The name of a variable can be any valid [identifier](/terraform/language/syntax/configuration#identifiers)
+_except_ the following: `source`, `version`, `providers`, `count`, `for_each`, `lifecycle`, `depends_on`, `locals`.
+
+These names are reserved for meta-arguments in
+[module configuration blocks](/terraform/language/modules/syntax), and cannot be
+declared as variable names.
+
+## Arguments
+
+Terraform CLI defines the following optional arguments for variable declarations:
+
+* [`default`][inpage-default] - A default value which then makes the variable optional.
+* [`type`][inpage-type] - This argument specifies what value types are accepted for the variable.
+* [`description`][inpage-description] - This specifies the input variable's documentation.
+* [`validation`][inpage-validation] - A block to define validation rules, usually in addition to type constraints.
+* [`sensitive`][inpage-sensitive] - Limits Terraform UI output when the variable is used in configuration.
+* [`nullable`][inpage-nullable] - Specify if the variable can be `null` within the module.
+
+### Default values
+
+[inpage-default]: #default-values
+
+The variable declaration can also include a `default` argument. If present,
+the variable is considered to be _optional_ and the default value will be used
+if no value is set when calling the module or running Terraform. The `default`
+argument requires a literal value and cannot reference other objects in the
+configuration.
+
+### Type Constraints
+
+[inpage-type]: #type-constraints
+
+The `type` argument in a `variable` block allows you to restrict the
+[type of value](/terraform/language/expressions/types) that will be accepted as
+the value for a variable. If no type constraint is set then a value of any type
+is accepted.
+
+While type constraints are optional, we recommend specifying them; they
+can serve as helpful reminders for users of the module, and they
+allow Terraform to return a helpful error message if the wrong type is used.
+
+Type constraints are created from a mixture of type keywords and type
+constructors. The supported type keywords are:
+
+* `string`
+* `number`
+* `bool`
+
+The type constructors allow you to specify complex types such as
+collections:
+
+* `list(<TYPE>)`
+* `set(<TYPE>)`
+* `map(<TYPE>)`
+* `object({<ATTR NAME> = <TYPE>, ... })`
+* `tuple([<TYPE>, ...])`
+
+The keyword `any` may be used to indicate that any type is acceptable. For
+more information on the meaning and behavior of these different types, as well
+as detailed information about automatic conversion of complex types, see
+[Type Constraints](/terraform/language/expressions/types).
+
+If both the `type` and `default` arguments are specified, the given default
+value must be convertible to the specified type.
+
+### Input Variable Documentation
+
+[inpage-description]: #input-variable-documentation
+
+Because the input variables of a module are part of its user interface, you can
+briefly describe the purpose of each variable using the optional
+`description` argument:
+
+```hcl
+variable "image_id" {
+  type        = string
+  description = "The id of the machine image (AMI) to use for the server."
+}
+```
+
+The description should concisely explain the purpose
+of the variable and what kind of value is expected. This description string
+might be included in documentation about the module, and so it should be written
+from the perspective of the user of the module rather than its maintainer. For
+commentary for module maintainers, use comments.
+
+### Custom Validation Rules
+
+[inpage-validation]: #custom-validation-rules
+
+-> This feature was introduced in Terraform CLI v0.13.0.
+
+You can specify custom validation rules for a particular variable by adding a `validation` block within the corresponding `variable` block. The example below checks whether the AMI ID has the correct syntax.
+
+```hcl
+variable "image_id" {
+  type        = string
+  description = "The id of the machine image (AMI) to use for the server."
+
+  validation {
+    condition     = length(var.image_id) > 4 && substr(var.image_id, 0, 4) == "ami-"
+    error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
+  }
+}
+```
+Refer to [Custom Condition Checks](/terraform/language/expressions/custom-conditions#input-variable-validation) for more details.
+
+### Suppressing Values in CLI Output
+
+[inpage-sensitive]: #suppressing-values-in-cli-output
+
+-> This feature was introduced in Terraform v0.14.0.
+
+> **Hands-on:** Try the [Protect Sensitive Input Variables](/terraform/tutorials/configuration-language/sensitive-variables?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
+
+Setting a variable as `sensitive` prevents Terraform from showing its value in
+the `plan` or `apply` output, when you use that variable elsewhere in your
+configuration.
+
+Terraform will still record sensitive values in the [state](/terraform/language/state),
+and so anyone who can access the state data will have access to the sensitive
+values in cleartext. For more information, see
+[_Sensitive Data in State_](/terraform/language/state/sensitive-data).
+
+Declare a variable as sensitive by setting the `sensitive` argument to `true`:
+
+```hcl
+variable "user_information" {
+  type = object({
+    name    = string
+    address = string
+  })
+  sensitive = true
+}
+
+resource "some_resource" "a" {
+  name    = var.user_information.name
+  address = var.user_information.address
+}
+```
+
+Any expressions whose result depends on the sensitive variable will be treated
+as sensitive themselves, and so in the above example the two arguments of
+`resource "some_resource" "a"` will also be hidden in the plan output:
+
+```
+Terraform will perform the following actions:
+
+  # some_resource.a will be created
+  + resource "some_resource" "a" {
+      + name    = (sensitive value)
+      + address = (sensitive value)
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+```
+
+In some cases where you use a sensitive variable inside a nested block, Terraform
+may treat the entire block as redacted. This happens for resource types where
+all of the blocks of a particular type are required to be unique, and so
+disclosing the content of one block might imply the content of a sibling block.
+
+```
+  # some_resource.a will be updated in-place
+  ~ resource "some_resource" "a" {
+      ~ nested_block {
+          # At least one attribute in this block is (or was) sensitive,
+          # so its contents will not be displayed.
+        }
+    }
+```
+
+A provider can also
+[declare an attribute as sensitive](/terraform/plugin/sdkv2/best-practices/sensitive-state#using-the-sensitive-flag),
+which will cause Terraform to hide it from regular output regardless of how
+you assign it a value. For more information, see
+[Sensitive Resource Attributes](/terraform/language/expressions/references#sensitive-resource-attributes).
+
+If you use a sensitive value as part of an
+[output value](/terraform/language/values/outputs) then Terraform will require
+you to also mark the output value itself as sensitive, to confirm that you
+intended to export it.
+
+#### Cases where Terraform may disclose a sensitive variable
+
+A `sensitive` variable is a configuration-centered concept, and values are sent to providers without any obfuscation. A provider error could disclose a value if that value is included in the error message. For example, a provider might return the following error even if "foo" is a sensitive value: `"Invalid value 'foo' for field"`
+
+If a resource attribute is used as, or part of, the provider-defined resource id, an `apply` will disclose the value. In the example below, the `prefix` attribute has been set to a sensitive variable, but then that value ("jae") is later disclosed as part of the resource id:
+
+```
+  # random_pet.animal will be created
+  + resource "random_pet" "animal" {
+      + id        = (known after apply)
+      + length    = 2
+      + prefix    = (sensitive value)
+      + separator = "-"
+    }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+...
+
+random_pet.animal: Creating...
+random_pet.animal: Creation complete after 0s [id=jae-known-mongoose]
+```
+
+### Disallowing Null Input Values
+
+[inpage-nullable]: #disallowing-null-input-values
+
+-> This feature is available in Terraform v1.1.0 and later.
+
+The `nullable` argument in a variable block controls whether the module caller
+may assign the value `null` to the variable.
+
+```hcl
+variable "example" {
+  type     = string
+  nullable = false
+}
+```
+
+The default value for `nullable` is `true`. When `nullable` is `true`, `null`
+is a valid value for the variable, and the module configuration must always
+account for the possibility of the variable value being `null`. Passing a
+`null` value as a module input argument will override any `default` value.
+
+Setting `nullable` to `false` ensures that the variable value will never be
+`null` within the module. If `nullable` is `false` and the variable has a
+`default` value, then Terraform uses the default when a module input argument is `null`.
+
+The `nullable` argument only controls where the direct value of the variable may be `null`.
+For variables of collection or structural types, such as lists or objects,
+the caller may still use `null` in nested elements or attributes, as long as
+the collection or structure itself is not null.
+
+## Using Input Variable Values
+
+Within the module that declared a variable, its value can be accessed from
+within [expressions](/terraform/language/expressions) as `var.<NAME>`,
+where `<NAME>` matches the label given in the declaration block:
+
+-> **Note:** Input variables are _created_ by a `variable` block, but you
+_reference_ them as attributes on an object named `var`.
+
+```hcl
+resource "aws_instance" "example" {
+  instance_type = "t2.micro"
+  ami           = var.image_id
+}
+```
+
+The value assigned to a variable can only be accessed in expressions within
+the module where it was declared.
+
+## Assigning Values to Root Module Variables
+
+When variables are declared in the root module of your configuration, they
+can be set in a number of ways:
+
+* [In a Terraform Cloud workspace](/terraform/cloud-docs/workspaces/variables).
+* Individually, with the `-var` command line option.
+* In variable definitions (`.tfvars`) files, either specified on the command line
+  or automatically loaded.
+* As environment variables.
+
+The following sections describe these options in more detail. This section does
+not apply to _child_ modules, where values for input variables are instead
+assigned in the configuration of their parent module, as described in
+[_Modules_](/terraform/language/modules).
+
+### Variables on the Command Line
+
+To specify individual variables on the command line, use the `-var` option
+when running the `terraform plan` and `terraform apply` commands:
+
+```
+terraform apply -var="image_id=ami-abc123"
+terraform apply -var='image_id_list=["ami-abc123","ami-def456"]' -var="instance_type=t2.micro"
+terraform apply -var='image_id_map={"us-east-1":"ami-abc123","us-east-2":"ami-def456"}'
+```
+
+The above examples show appropriate syntax for Unix-style shells, such as on
+Linux or macOS. For more information on shell quoting, including additional
+examples for Windows Command Prompt, see
+[Input Variables on the Command Line](/terraform/cli/commands/plan#input-variables-on-the-command-line).
+
+You can use the `-var` option multiple times in a single command to set several
+different variables.
+
+<a id="variable-files"></a>
+
+### Variable Definitions (`.tfvars`) Files
+
+To set lots of variables, it is more convenient to specify their values in
+a _variable definitions file_ (with a filename ending in either `.tfvars`
+or `.tfvars.json`) and then specify that file on the command line with
+`-var-file`:
+
+```
+terraform apply -var-file="testing.tfvars"
+```
+
+-> **Note:** This is how Terraform Cloud passes
+[workspace variables](/terraform/cloud-docs/workspaces/variables) to Terraform.
+
+A variable definitions file uses the same basic syntax as Terraform language
+files, but consists only of variable name assignments:
+
+```hcl
+image_id = "ami-abc123"
+availability_zone_names = [
+  "us-east-1a",
+  "us-west-1c",
+]
+```
+
+Terraform also automatically loads a number of variable definitions files
+if they are present:
+
+* Files named exactly `terraform.tfvars` or `terraform.tfvars.json`.
+* Any files with names ending in `.auto.tfvars` or `.auto.tfvars.json`.
+
+Files whose names end with `.json` are parsed instead as JSON objects, with
+the root object properties corresponding to variable names:
+
+```json
+{
+  "image_id": "ami-abc123",
+  "availability_zone_names": ["us-west-1a", "us-west-1c"]
+}
+```
+
+### Environment Variables
+
+As a fallback for the other ways of defining variables, Terraform searches
+the environment of its own process for environment variables named `TF_VAR_`
+followed by the name of a declared variable.
+
+This can be useful when running Terraform in automation, or when running a
+sequence of Terraform commands in succession with the same variables.
+For example, at a `bash` prompt on a Unix system:
+
+```
+$ export TF_VAR_image_id=ami-abc123
+$ terraform plan
+...
+```
+
+On operating systems where environment variable names are case-sensitive,
+Terraform matches the variable name exactly as given in configuration, and
+so the required environment variable name will usually have a mix of upper
+and lower case letters as in the above example.
+
+### Complex-typed Values
+
+When variable values are provided in a variable definitions file, you can use
+Terraform's usual syntax for
+[literal expressions](/terraform/language/expressions/types#literal-expressions)
+to assign complex-typed values, like lists and maps.
+
+Some special rules apply to the `-var` command line option and to environment
+variables. For convenience, Terraform defaults to interpreting `-var` and
+environment variable values as literal strings, which need only shell quoting,
+and no special quoting for Terraform. For example, in a Unix-style shell:
+
+```
+$ export TF_VAR_image_id='ami-abc123'
+```
+
+However, if a root module variable uses a [type constraint](#type-constraints)
+to require a complex value (list, set, map, object, or tuple), Terraform will
+instead attempt to parse its value using the same syntax used within variable
+definitions files, which requires careful attention to the string escaping rules
+in your shell:
+
+```
+$ export TF_VAR_availability_zone_names='["us-west-1b","us-west-1d"]'
+```
+
+For readability, and to avoid the need to worry about shell escaping, we
+recommend always setting complex variable values via variable definitions files.
+For more information on quoting and escaping for `-var` arguments,
+see
+[Input Variables on the Command Line](/terraform/cli/commands/plan#input-variables-on-the-command-line).
+
+### Values for Undeclared Variables
+
+If you have defined a variable value, but not its corresponding `variable {}`
+definition, you may get an error or warning depending on how you have provided
+that value.
+
+If you provide values for undeclared variables defined as [environment variables](#environment-variables)
+you will not get an error or warning. This is because environment variables may
+be declared but not used in all configurations that might be run.
+
+If you provide values for undeclared variables defined [in a file](#variable-definitions-tfvars-files)
+you will get a warning. This is to help in cases where you have provided a variable
+value _meant_ for a variable declaration, but perhaps there is a mistake in the
+value definition. For example, the following configuration:
+
+```terraform
+variable "moose" {
+  type = string
+}
+```
+
+And the following `.tfvars` file:
+
+```hcl
+mosse = "Moose"
+```
+
+Will cause Terraform to warn you that there is no variable declared `"mosse"`, which can help
+you spot this mistake.
+
+If you use `.tfvars` files across multiple configurations and expect to continue to see this warning,
+you can use the [`-compact-warnings`](/terraform/cli/commands/plan#compact-warnings)
+option to simplify your output.
+
+If you provide values for undeclared variables on the [command line](#variables-on-the-command-line),
+Terraform will error. To avoid this error, either declare a variable block for the value, or remove
+the variable value from your Terraform call.
+
+### Variable Definition Precedence
+
+The above mechanisms for setting variables can be used together in any
+combination. If the same variable is assigned multiple values, Terraform uses
+the _last_ value it finds, overriding any previous values. Note that the same
+variable cannot be assigned multiple values within a single source.
+
+Terraform loads variables in the following order, with later sources taking
+precedence over earlier ones:
+
+* Environment variables
+* The `terraform.tfvars` file, if present.
+* The `terraform.tfvars.json` file, if present.
+* Any `*.auto.tfvars` or `*.auto.tfvars.json` files, processed in lexical order
+  of their filenames.
+* Any `-var` and `-var-file` options on the command line, in the order they
+  are provided. (This includes variables set by a Terraform Cloud
+  workspace.)
+
+~> **Important:** In Terraform 0.12 and later, variables with map and object
+values behave the same way as other variables: the last value found overrides
+the previous values. This is a change from previous versions of Terraform, which
+would _merge_ map values instead of overriding them.
diff --git a/v1.5.7/website/img/docs/concrete-plan.png b/v1.5.7/website/img/docs/concrete-plan.png
new file mode 100644
index 0000000..1f6bd34
--- /dev/null
+++ b/v1.5.7/website/img/docs/concrete-plan.png
Binary files differ
diff --git a/v1.5.7/website/img/docs/graph-example.png b/v1.5.7/website/img/docs/graph-example.png
new file mode 100644
index 0000000..b83f12f
--- /dev/null
+++ b/v1.5.7/website/img/docs/graph-example.png
Binary files differ
diff --git a/v1.5.7/website/img/docs/in-progress-apply.png b/v1.5.7/website/img/docs/in-progress-apply.png
new file mode 100644
index 0000000..a9fd081
--- /dev/null
+++ b/v1.5.7/website/img/docs/in-progress-apply.png
Binary files differ
diff --git a/v1.5.7/website/img/docs/intro-terraform-apis.png b/v1.5.7/website/img/docs/intro-terraform-apis.png
new file mode 100644
index 0000000..f3e3613
--- /dev/null
+++ b/v1.5.7/website/img/docs/intro-terraform-apis.png
Binary files differ
diff --git a/v1.5.7/website/img/docs/intro-terraform-workflow.png b/v1.5.7/website/img/docs/intro-terraform-workflow.png
new file mode 100644
index 0000000..9d39ad2
--- /dev/null
+++ b/v1.5.7/website/img/docs/intro-terraform-workflow.png
Binary files differ
diff --git a/v1.5.7/website/img/docs/manually-pasted-plan-output.png b/v1.5.7/website/img/docs/manually-pasted-plan-output.png
new file mode 100644
index 0000000..b679371
--- /dev/null
+++ b/v1.5.7/website/img/docs/manually-pasted-plan-output.png
Binary files differ
diff --git a/v1.5.7/website/img/docs/plan-comments.png b/v1.5.7/website/img/docs/plan-comments.png
new file mode 100644
index 0000000..d6fa4af
--- /dev/null
+++ b/v1.5.7/website/img/docs/plan-comments.png
Binary files differ
diff --git a/v1.5.7/website/img/docs/pr-plan.png b/v1.5.7/website/img/docs/pr-plan.png
new file mode 100644
index 0000000..c9c34e4
--- /dev/null
+++ b/v1.5.7/website/img/docs/pr-plan.png
Binary files differ
diff --git a/v1.5.7/website/img/docs/pull-request.png b/v1.5.7/website/img/docs/pull-request.png
new file mode 100644
index 0000000..ff79267
--- /dev/null
+++ b/v1.5.7/website/img/docs/pull-request.png
Binary files differ
diff --git a/v1.5.7/website/layouts/docs.erb b/v1.5.7/website/layouts/docs.erb
new file mode 100644
index 0000000..381b1c1
--- /dev/null
+++ b/v1.5.7/website/layouts/docs.erb
@@ -0,0 +1,603 @@
+<% wrap_layout :inner do %>
+  <% content_for :sidebar do %>
+    <h4><a href="/docs/cli/index.html">Terraform CLI</a></h4>
+
+    <ul class="nav docs-sidenav">
+
+      <li>
+        <a href="/docs/cli/index.html">Overview</a>
+      </li>
+
+      <li>
+        <a href="/docs/cli/commands/index.html">Basic CLI Features</a>
+      </li>
+
+      <li>
+        <a href="#">Initializing Working Directories</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/cli/init/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/init.html"><code>init</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/get.html"><code>get</code></a>
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">Provisioning Infrastructure</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/cli/run/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/plan.html"><code>plan</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/apply.html"><code>apply</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/destroy.html"><code>destroy</code></a>
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">Authenticating</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/cli/auth/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/login.html"><code>login</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/logout.html"><code>logout</code></a>
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">Writing and Modifying Code</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/cli/code/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/console.html"><code>console</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/fmt.html"><code>fmt</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/validate.html"><code>validate</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/0.13upgrade.html"><code>0.13upgrade</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/0.12upgrade.html"><code>0.12upgrade</code></a>
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">Inspecting Infrastructure</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/cli/inspect/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/graph.html"><code>graph</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/output.html"><code>output</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/show.html"><code>show</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/state/list.html"><code>state list</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/state/show.html"><code>state show</code></a>
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">Importing Infrastructure</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/cli/import/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/import.html"><code>import</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/import/usage.html">Usage Tips</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/import/importability.html">Resource Importability</a>
+          </li>
+
+
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">Manipulating State</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/cli/state/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/state/resource-addressing.html">Resource Addressing</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/state/index.html"><code>state</code></a>
+          </li>
+
+          <li>
+            <a href="#">Inspecting State</a>
+            <ul class="nav nav-auto-expand">
+              <li>
+                <a href="/docs/cli/state/inspect.html">Overview</a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/state/list.html"><code>state list</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/state/show.html"><code>state show</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/refresh.html"><code>refresh</code></a>
+              </li>
+            </ul>
+          </li>
+
+          <li>
+            <a href="#">Forcing Re-creation (Tainting)</a>
+            <ul class="nav nav-auto-expand">
+              <li>
+                <a href="/docs/cli/state/taint.html">Overview</a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/taint.html"><code>taint</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/untaint.html"><code>untaint</code></a>
+              </li>
+            </ul>
+          </li>
+
+          <li>
+            <a href="#">Moving Resources</a>
+            <ul class="nav nav-auto-expand">
+              <li>
+                <a href="/docs/cli/state/move.html">Overview</a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/state/mv.html"><code>state mv</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/state/rm.html"><code>state rm</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/state/replace-provider.html"><code>state replace-provider</code></a>
+              </li>
+            </ul>
+          </li>
+
+          <li>
+            <a href="#">Disaster Recovery</a>
+            <ul class="nav nav-auto-expand">
+              <li>
+                <a href="/docs/cli/state/recover.html">Overview</a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/state/pull.html"><code>state pull</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/state/push.html"><code>state push</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/force-unlock.html"><code>force-unlock</code></a>
+              </li>
+            </ul>
+          </li>
+
+        </ul>
+      </li> <!-- state -->
+
+      <li>
+        <a href="#">Managing Workspaces</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/cli/workspaces/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="#"><code>workspace</code></a>
+            <ul class="nav nav-auto-expand">
+              <li>
+                <a href="/docs/cli/commands/workspace/index.html">Overview</a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/workspace/list.html"><code>workspace list</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/workspace/select.html"><code>workspace select</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/workspace/new.html"><code>workspace new</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/workspace/delete.html"><code>workspace delete</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/cli/commands/workspace/show.html"><code>workspace show</code></a>
+              </li>
+            </ul>
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">Managing Plugins</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/cli/plugins/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/plugins/signing.html">Plugin Signing</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/providers.html"><code>providers</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/version.html"><code>version</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/providers/lock.html"><code>providers lock</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/providers/mirror.html"><code>providers mirror</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/providers/schema.html"><code>providers schema</code></a>
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">CLI Configuration</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/cli/config/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/config/config-file.html">CLI Config File</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/config/environment-variables.html">Environment Variables</a>
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">Using Terraform Cloud</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/cli/cloud/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/cloud/settings.html">Terraform Cloud Settings</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/cloud/migrating.html">Initializing and Migrating</a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/cloud/command-line-arguments.html">Command Line Arguments</a>
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">Automating Terraform</a>
+        <ul class="nav">
+          <li>
+            <a href="https://learn.hashicorp.com/tutorials/terraform/automate-terraform?in=terraform/automation&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS">
+              Running Terraform in Automation
+              <img src="/assets/images/outbound-link.svg" width="20" height="20" aria-hidden="true" style="vertical-align: text-bottom;">
+            </a>
+          </li>
+
+          <li>
+            <a href="https://learn.hashicorp.com/tutorials/terraform/github-actions?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS">
+              GitHub Actions
+              <img src="/assets/images/outbound-link.svg" width="20" height="20" aria-hidden="true" style="vertical-align: text-bottom;">
+            </a>
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">Alphabetical List of Commands</a>
+        <ul class="nav">
+
+          <li>
+            <a href="/docs/cli/commands/apply.html"><code>apply</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/console.html"><code>console</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/destroy.html"><code>destroy</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/env.html"><code>env</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/fmt.html"><code>fmt</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/force-unlock.html"><code>force-unlock</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/get.html"><code>get</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/graph.html"><code>graph</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/import.html"><code>import</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/init.html"><code>init</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/login.html"><code>login</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/logout.html"><code>logout</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/output.html"><code>output</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/plan.html"><code>plan</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/providers.html"><code>providers</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/providers/lock.html"><code>providers lock</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/providers/mirror.html"><code>providers mirror</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/providers/schema.html"><code>providers schema</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/push.html"><code>push</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/refresh.html"><code>refresh</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/show.html"><code>show</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/state/list.html"><code>state list</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/state/mv.html"><code>state mv</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/state/pull.html"><code>state pull</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/state/push.html"><code>state push</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/state/replace-provider.html"><code>state replace-provider</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/state/rm.html"><code>state rm</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/state/show.html"><code>state show</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/taint.html"><code>taint</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/test.html"><code>test</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/untaint.html"><code>untaint</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/validate.html"><code>validate</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/version.html"><code>version</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/workspace/list.html"><code>workspace list</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/workspace/select.html"><code>workspace select</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/workspace/new.html"><code>workspace new</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/workspace/delete.html"><code>workspace delete</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/workspace/show.html"><code>workspace show</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/0.12upgrade.html"><code>0.12upgrade</code></a>
+          </li>
+
+          <li>
+            <a href="/docs/cli/commands/0.13upgrade.html"><code>0.13upgrade</code></a>
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">Internals</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/internals/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/internals/credentials-helpers.html">Credentials Helpers</a>
+          </li>
+
+          <li>
+            <a href="/docs/internals/debugging.html">Debugging Terraform</a>
+          </li>
+
+          <li>
+            <a href="/docs/internals/json-format.html">JSON Output Format</a>
+          </li>
+
+          <li>
+            <a href="/docs/internals/login-protocol.html">Login Protocol</a>
+          </li>
+
+          <li>
+            <a href="/docs/internals/machine-readable-ui.html">Machine-Readable UI</a>
+          </li>
+
+          <li>
+            <a href="/docs/internals/module-registry-protocol.html">Module Registry Protocol</a>
+          </li>
+
+          <li>
+            <a href="/docs/internals/provider-meta.html">Provider Metadata</a>
+          </li>
+
+          <li>
+            <a href="/docs/internals/provider-network-mirror-protocol.html">Provider Network Mirror Protocol</a>
+          </li>
+
+          <li>
+            <a href="/docs/internals/provider-registry-protocol.html">Provider Registry Protocol</a>
+          </li>
+
+          <li>
+            <a href="/docs/internals/remote-service-discovery.html">Remote Service Discovery</a>
+          </li>
+
+          <li>
+            <a href="/docs/internals/graph.html">Resource Graph</a>
+          </li>
+
+        </ul>
+      </li>
+
+    </ul>
+
+    <%= partial("layouts/otherdocs", :locals => { :skip => "Terraform CLI" }) %>
+  <% end %>
+
+  <%= yield %>
+<% end %>
diff --git a/v1.5.7/website/layouts/downloads.erb b/v1.5.7/website/layouts/downloads.erb
new file mode 100644
index 0000000..8fa057c
--- /dev/null
+++ b/v1.5.7/website/layouts/downloads.erb
@@ -0,0 +1,27 @@
+<% wrap_layout :inner do %>
+  <% content_for :sidebar do %>
+    <h4><a href="/downloads.html">Downloads</a></h4>
+
+    <ul class="nav docs-sidenav">
+      <li<%= sidebar_current("downloads-terraform") %>>
+        <a href="/downloads.html">Download Terraform</a>
+      </li>
+
+      <li<%= sidebar_current("docs-cli-install-apt") %>>
+        <a href="/docs/cli/install/apt.html">Debian/Ubuntu APT Packages</a>
+      </li>
+
+      <li<%= sidebar_current("docs-cli-install-yum") %>>
+        <a href="/docs/cli/install/yum.html">RHEL/Fedora Yum Packages</a>
+      </li>
+
+      <li<%= sidebar_current("upgrade-guides") %>>
+        <a href="/upgrade-guides/index.html">Upgrade Guides</a>
+      </li>
+    </ul>
+
+    <%= partial("layouts/otherdocs", :locals => { :skip => "Download Terraform" }) %>
+  <% end %>
+
+  <%= yield %>
+<% end %>
diff --git a/v1.5.7/website/layouts/intro.erb b/v1.5.7/website/layouts/intro.erb
new file mode 100644
index 0000000..fb528b5
--- /dev/null
+++ b/v1.5.7/website/layouts/intro.erb
@@ -0,0 +1,62 @@
+<% wrap_layout :inner do %>
+  <% content_for(:custom_share) do %>
+    <meta name="twitter:card" content="summary_large_image" />
+    <meta property="og:image" content="<%= image_url("og-image-large.png") %>"/>
+  <% end %>
+
+  <% content_for :sidebar do %>
+    <h4><a href="/intro/index.html">Introduction to Terraform</a></h4>
+
+    <ul class="nav docs-sidenav">
+      <li>
+        <a href="/intro/index.html">What is Terraform?</a>
+      </li>
+
+      <li>
+        <a href="/intro/use-cases.html">Use Cases</a>
+      </li>
+
+      <li>
+        <a href="https://learn.hashicorp.com/collections/terraform/aws-get-started?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS">Getting Started</a>
+      </li>
+
+      <li>
+        <a href="/guides/core-workflow.html">The Core Terraform Workflow</a>
+      </li>
+
+      <li><a href="/docs/cloud/guides/recommended-practices/index.html">Terraform Recommended Practices</a>
+        <ul class="nav">
+          <li><a href="/docs/cloud/guides/recommended-practices/part1.html">Part 1: Workflow Overview</a></li>
+          <li><a href="/docs/cloud/guides/recommended-practices/part2.html">Part 2: Evaluating Current Practices</a></li>
+          <li><a href="/docs/cloud/guides/recommended-practices/part3.html">Part 3: Evolving Your Practices</a></li>
+          <li><a href="/docs/cloud/guides/recommended-practices/part3.1.html">Part 3.1: From Manual to Semi-Automated</a></li>
+          <li><a href="/docs/cloud/guides/recommended-practices/part3.2.html">Part 3.2: From Semi-Automated to Infrastructure as Code</a></li>
+          <li><a href="/docs/cloud/guides/recommended-practices/part3.3.html">Part 3.3: From Infrastructure as Code to Collaborative IaC</a></li>
+          <li><a href="/docs/cloud/guides/recommended-practices/part3.4.html">Part 3.4: Advanced Improvements</a></li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="/intro/vs/index.html">Terraform vs. Other</a>
+        <ul class="nav">
+          <li>
+            <a href="/intro/vs/chef-puppet.html">Chef, Puppet, etc.</a>
+          </li>
+          <li>
+            <a href="/intro/vs/cloudformation.html">CloudFormation, Heat, etc.</a>
+          </li>
+          <li>
+            <a href="/intro/vs/boto.html">Boto, Fog, etc.</a>
+          </li>
+          <li>
+            <a href="/intro/vs/custom.html">Custom Solutions</a>
+          </li>
+        </ul>
+      </li>
+    </ul>
+
+    <%= partial("layouts/otherdocs", :locals => { :skip => "Introduction to Terraform" }) %>
+  <% end %>
+
+  <%= yield %>
+<% end %>
diff --git a/v1.5.7/website/layouts/language.erb b/v1.5.7/website/layouts/language.erb
new file mode 100644
index 0000000..c93f429
--- /dev/null
+++ b/v1.5.7/website/layouts/language.erb
@@ -0,0 +1,1101 @@
+<% wrap_layout :inner do %>
+  <% content_for :sidebar do %>
+    <h4><a href="/docs/language/index.html">Terraform Language</a></h4>
+
+    <ul class="nav docs-sidenav">
+
+      <li>
+        <a href="/docs/language/index.html">Overview</a>
+      </li>
+
+      <li>
+        <a href="#">Files and Directories</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/language/files/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/files/override.html">Override Files</a>
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">Syntax</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/language/syntax/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/syntax/configuration.html">Configuration Syntax</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/syntax/json.html">JSON Configuration Syntax</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/syntax/style.html">Style Conventions</a>
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">Resources</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/language/resources/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/resources/syntax.html">Resource Blocks</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/resources/behavior.html">Resource Behavior</a>
+          </li>
+
+          <li>
+            <a href="#">Meta-Arguments</a>
+            <ul class="nav nav-auto-expand">
+              <li>
+                <a href="/docs/language/meta-arguments/depends_on.html"><code>depends_on</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/language/meta-arguments/count.html"><code>count</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/language/meta-arguments/for_each.html"><code>for_each</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/language/meta-arguments/resource-provider.html"><code>provider</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/language/meta-arguments/lifecycle.html"><code>lifecycle</code></a>
+              </li>
+            </ul>
+          </li>
+
+          <li>
+            <a href="#">Provisioners</a>
+            <ul class="nav">
+              <li>
+                <a href="/docs/language/resources/provisioners/index.html">Overview</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/resources/provisioners/syntax.html">Declaring Provisioners</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/resources/provisioners/connection.html">Provisioner Connections</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/resources/provisioners/null_resource.html">Provisioners Without a Resource</a>
+              </li>
+
+              <li>
+                <a href="#">Generic Provisioners</a>
+                <ul class="nav nav-auto-expand">
+                  <li>
+                    <a href="/docs/language/resources/provisioners/file.html">file</a>
+                  </li>
+
+                  <li>
+                    <a href="/docs/language/resources/provisioners/local-exec.html">local-exec</a>
+                  </li>
+
+                  <li>
+                    <a href="/docs/language/resources/provisioners/remote-exec.html">remote-exec</a>
+                  </li>
+                </ul>
+              </li>
+
+              <li>
+                <a href="#">Vendor Provisioners</a>
+                <ul class="nav nav-auto-expand">
+                  <li>
+                    <a href="/docs/language/resources/provisioners/chef.html">chef</a>
+                  </li>
+
+                  <li>
+                    <a href="/docs/language/resources/provisioners/habitat.html">habitat</a>
+                  </li>
+
+                  <li>
+                    <a href="/docs/language/resources/provisioners/puppet.html">puppet</a>
+                  </li>
+
+                  <li>
+                    <a href="/docs/language/resources/provisioners/salt-masterless.html">salt-masterless</a>
+                  </li>
+                </ul>
+              </li>
+
+            </ul>
+          </li>
+
+          <li>
+            <a href="/docs/language/resources/terraform-data.html">Terraform Data Resource Type</a>
+          </li>
+
+        </ul>
+      </li> <!-- resources -->
+
+      <li>
+        <a href="/docs/language/data-sources/index.html">Data Sources</a>
+      </li>
+
+      <li>
+        <a href="#">Providers</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/language/providers/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/providers/requirements.html">Provider Requirements</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/providers/configuration.html">Provider Configuration</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/dependency-lock.html">Dependency Lock File</a>
+          </li>
+        </ul>
+      </li><!-- providers -->
+
+      <li>
+        <a href="#">Variables and Outputs</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/language/values/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/values/variables.html">Input Variables</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/values/outputs.html">Output Values</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/values/locals.html">Local Values</a>
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">Modules</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/language/modules/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/modules/syntax.html">Module Blocks</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/modules/sources.html">Module Sources</a>
+          </li>
+
+          <li>
+            <a href="#">Meta-Arguments</a>
+            <ul class="nav nav-auto-expand">
+              <li>
+                <a href="/docs/language/meta-arguments/module-providers.html"><code>providers</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/language/meta-arguments/depends_on.html"><code>depends_on</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/language/meta-arguments/count.html"><code>count</code></a>
+              </li>
+
+              <li>
+                <a href="/docs/language/meta-arguments/for_each.html"><code>for_each</code></a>
+              </li>
+            </ul>
+          </li>
+
+          <li>
+            <a href="#">Module Development</a>
+            <ul class="nav">
+              <li>
+                <a href="/docs/language/modules/develop/index.html">Overview</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/modules/develop/structure.html">Standard Module Structure</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/modules/develop/providers.html">Providers Within Modules</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/modules/develop/composition.html">Best Practices: Module Composition</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/modules/develop/publish.html">Publishing Modules</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/modules/develop/refactoring.html">Refactoring</a>
+              </li>
+            </ul>
+          </li>
+        </ul>
+      </li><!-- modules -->
+
+      <li>
+        <a href="#">Expressions</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/language/expressions/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/expressions/types.html">Types and Values</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/expressions/strings.html">Strings and Templates</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/expressions/references.html">References to Values</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/expressions/operators.html">Operators</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/expressions/function-calls.html">Function Calls</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/expressions/conditionals.html">Conditional Expressions</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/expressions/for.html">For Expressions</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/expressions/splat.html">Splat Expressions</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/expressions/dynamic-blocks.html">Dynamic Blocks</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/expressions/type-constraints.html">Type Constraints</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/expressions/version-constraints.html">Version Constraints</a>
+          </li>
+        </ul>
+      </li>
+
+
+      <li>
+        <a href="#">Functions</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/language/functions/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="#">Numeric Functions</a>
+            <ul class="nav">
+
+              <li>
+                <a href="/docs/language/functions/abs.html">abs</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/ceil.html">ceil</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/floor.html">floor</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/log.html">log</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/max.html">max</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/min.html">min</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/parseint.html">parseint</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/pow.html">pow</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/signum.html">signum</a>
+              </li>
+
+            </ul>
+          </li>
+
+          <li>
+            <a href="#">String Functions</a>
+            <ul class="nav">
+
+              <li>
+                <a href="/docs/language/functions/chomp.html">chomp</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/endswith.html">endswith</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/format.html">format</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/formatlist.html">formatlist</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/indent.html">indent</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/join.html">join</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/lower.html">lower</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/regex.html">regex</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/regexall.html">regexall</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/replace.html">replace</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/split.html">split</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/startswith.html">startswith</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/strcontains.html">strcontains</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/strrev.html">strrev</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/substr.html">substr</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/title.html">title</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/trim.html">trim</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/trimprefix.html">trimprefix</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/trimsuffix.html">trimsuffix</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/trimspace.html">trimspace</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/upper.html">upper</a>
+              </li>
+
+            </ul>
+          </li>
+
+          <li>
+            <a href="#">Collection Functions</a>
+            <ul class="nav">
+
+              <li>
+                <a href="/docs/language/functions/alltrue.html">alltrue</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/anytrue.html">anytrue</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/chunklist.html">chunklist</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/coalesce.html">coalesce</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/coalescelist.html">coalescelist</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/compact.html">compact</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/concat.html">concat</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/contains.html">contains</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/distinct.html">distinct</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/element.html">element</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/flatten.html">flatten</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/index_function.html">index</a>
+                <!-- odd filename out, due to web conventions -->
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/keys.html">keys</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/length.html">length</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/list.html">list</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/lookup.html">lookup</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/map.html">map</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/matchkeys.html">matchkeys</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/merge.html">merge</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/one.html">one</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/range.html">range</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/reverse.html">reverse</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/setintersection.html">setintersection</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/setproduct.html">setproduct</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/setsubtract.html">setsubtract</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/setunion.html">setunion</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/slice.html">slice</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/sort.html">sort</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/sum.html">sum</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/transpose.html">transpose</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/values.html">values</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/zipmap.html">zipmap</a>
+              </li>
+
+            </ul>
+          </li>
+
+          <li>
+            <a href="#">Encoding Functions</a>
+            <ul class="nav">
+
+              <li>
+                <a href="/docs/language/functions/base64decode.html">base64decode</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/base64encode.html">base64encode</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/base64gzip.html">base64gzip</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/csvdecode.html">csvdecode</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/jsondecode.html">jsondecode</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/jsonencode.html">jsonencode</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/textdecodebase64.html">textdecodebase64</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/textencodebase64.html">textencodebase64</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/urlencode.html">urlencode</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/yamldecode.html">yamldecode</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/yamlencode.html">yamlencode</a>
+              </li>
+
+            </ul>
+          </li>
+
+          <li>
+            <a href="#">Filesystem Functions</a>
+            <ul class="nav">
+
+              <li>
+                <a href="/docs/language/functions/abspath.html">abspath</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/dirname.html">dirname</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/pathexpand.html">pathexpand</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/basename.html">basename</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/file.html">file</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/fileexists.html">fileexists</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/fileset.html">fileset</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/filebase64.html">filebase64</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/templatefile.html">templatefile</a>
+              </li>
+
+            </ul>
+          </li>
+
+          <li>
+            <a href="#">Date and Time Functions</a>
+            <ul class="nav">
+
+              <li>
+                <a href="/docs/language/functions/formatdate.html">formatdate</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/plantimestamp.html">plantimestamp</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/timeadd.html">timeadd</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/timestamp.html">timestamp</a>
+              </li>
+
+            </ul>
+          </li>
+
+          <li>
+            <a href="#">Hash and Crypto Functions</a>
+            <ul class="nav">
+
+              <li>
+                <a href="/docs/language/functions/base64sha256.html">base64sha256</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/base64sha512.html">base64sha512</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/bcrypt.html">bcrypt</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/filebase64sha256.html">filebase64sha256</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/filebase64sha512.html">filebase64sha512</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/filemd5.html">filemd5</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/filesha1.html">filesha1</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/filesha256.html">filesha256</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/filesha512.html">filesha512</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/md5.html">md5</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/rsadecrypt.html">rsadecrypt</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/sha1.html">sha1</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/sha256.html">sha256</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/sha512.html">sha512</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/uuid.html">uuid</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/uuidv5.html">uuidv5</a>
+              </li>
+
+            </ul>
+          </li>
+
+          <li>
+            <a href="#">IP Network Functions</a>
+            <ul class="nav">
+
+              <li>
+                <a href="/docs/language/functions/cidrhost.html">cidrhost</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/cidrnetmask.html">cidrnetmask</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/cidrsubnet.html">cidrsubnet</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/cidrsubnets.html">cidrsubnets</a>
+              </li>
+
+            </ul>
+          </li>
+
+          <li>
+            <a href="#">Type Conversion Functions</a>
+            <ul class="nav">
+
+              <li>
+                <a href="/docs/language/functions/can.html">can</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/nonsensitive.html">nonsensitive</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/sensitive.html">sensitive</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/tobool.html">tobool</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/tolist.html">tolist</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/tomap.html">tomap</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/tonumber.html">tonumber</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/toset.html">toset</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/tostring.html">tostring</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/try.html">try</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/functions/type.html">type</a>
+              </li>
+
+            </ul>
+          </li>
+
+        </ul>
+
+      </li><!-- function reference -->
+
+      <li>
+        <a href="#">Terraform Settings</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/language/settings/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/settings/terraform-cloud.html">Terraform Cloud</a>
+          </li>
+
+          <li>
+            <a href="#">Backends</a>
+            <ul class="nav">
+              <li>
+                <a href="/docs/language/settings/backends/index.html">Overview</a>
+              </li>
+
+              <li>
+                <a href="/docs/language/settings/backends/configuration.html">Backend Configuration</a>
+              </li>
+
+              <li>
+                <a href="#">Available Backends</a>
+                <ul class="nav nav-auto-expand">
+                  <li>
+                    <a href="/docs/language/settings/backends/local.html">local</a>
+                  </li>
+                  <li>
+                    <a href="/docs/language/settings/backends/remote.html">remote</a>
+                  </li>
+                  <li>
+                    <a href="/docs/language/settings/backends/azurerm.html">azurerm</a>
+                  </li>
+                  <li>
+                    <a href="/docs/language/settings/backends/consul.html">consul</a>
+                  </li>
+                  <li>
+                    <a href="/docs/language/settings/backends/cos.html">cos</a>
+                  </li>
+                  <li>
+                    <a href="/docs/language/settings/backends/gcs.html">gcs</a>
+                  </li>
+                  <li>
+                    <a href="/docs/language/settings/backends/http.html">http</a>
+                  </li>
+                  <li>
+                    <a href="/docs/language/settings/backends/kubernetes.html">kubernetes</a>
+                  </li>
+                  <li>
+                    <a href="/docs/language/settings/backends/oss.html">oss</a>
+                  </li>
+                  <li>
+                    <a href="/docs/language/settings/backends/pg.html">pg</a>
+                  </li>
+                  <li>
+                    <a href="/docs/language/settings/backends/s3.html">s3</a>
+                  </li>
+                </ul>
+              </li>
+            </ul>
+          </li><!-- backends -->
+        </ul>
+      </li><!-- settings -->
+
+      <li>
+        <a href="#">State</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/language/state/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/state/purpose.html">Purpose</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/state/remote-state-data.html">The <code>terraform_remote_state</code> Data Source</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/state/backends.html">Backends: State Storage & Locking</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/state/import.html">Import Existing Resources</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/state/locking.html">Locking</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/state/workspaces.html">Workspaces</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/state/remote.html">Remote State</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/state/sensitive-data.html">Sensitive Data</a>
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#">Upgrade Guides</a>
+        <ul class="nav">
+          <li>
+            <a href="/upgrade-guides/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/upgrade-guides/1-1.html">Upgrading to v1.1</a>
+          </li>
+
+          <li>
+            <a href="/upgrade-guides/1-0.html">Upgrading to v1.0</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/v1-compatibility-promises.html">v1.0 Compatibility Promises</a>
+          </li>
+
+          <li>
+            <a href="/upgrade-guides/0-15.html">Upgrading to v0.15</a>
+          </li>
+
+          <li>
+            <a href="/upgrade-guides/0-14.html">Upgrading to v0.14</a>
+          </li>
+
+          <li>
+            <a href="/upgrade-guides/0-13.html">Upgrading to v0.13</a>
+          </li>
+
+          <li>
+            <a href="/upgrade-guides/0-12.html">Upgrading to v0.12</a>
+          </li>
+
+          <li>
+            <a href="/upgrade-guides/0-11.html">Upgrading to v0.11</a>
+          </li>
+
+          <li>
+            <a href="/upgrade-guides/0-10.html">Upgrading to v0.10</a>
+          </li>
+
+          <li>
+            <a href="/upgrade-guides/0-9.html">Upgrading to v0.9</a>
+          </li>
+
+          <li>
+            <a href="/upgrade-guides/0-8.html">Upgrading to v0.8</a>
+          </li>
+
+          <li>
+            <a href="/upgrade-guides/0-7.html">Upgrading to v0.7</a>
+          </li>
+        </ul>
+      </li>
+
+
+      <li>
+        <a href="#">Historical docs: 0.11 and Older</a>
+        <ul class="nav">
+          <li>
+            <a href="/docs/configuration-0-11/index.html">Overview</a>
+          </li>
+
+          <li>
+            <a href="/docs/configuration-0-11/load.html">Load Order and Semantics</a>
+          </li>
+
+          <li>
+            <a href="/docs/configuration-0-11/syntax.html">Configuration Syntax</a>
+          </li>
+
+          <li>
+            <a href="/docs/configuration-0-11/interpolation.html">Interpolation Syntax</a>
+          </li>
+
+          <li>
+            <a href="/docs/configuration-0-11/override.html">Overrides</a>
+          </li>
+
+          <li>
+            <a href="/docs/configuration-0-11/resources.html">Resources</a>
+          </li>
+
+          <li>
+            <a href="/docs/configuration-0-11/data-sources.html">Data Sources</a>
+          </li>
+
+          <li>
+            <a href="/docs/configuration-0-11/providers.html">Providers</a>
+          </li>
+
+          <li>
+            <a href="/docs/configuration-0-11/variables.html">Variables</a>
+          </li>
+
+          <li>
+            <a href="/docs/configuration-0-11/outputs.html">Outputs</a>
+          </li>
+
+          <li>
+            <a href="/docs/configuration-0-11/locals.html">Local Values</a>
+          </li>
+
+          <li>
+            <a href="/docs/configuration-0-11/modules.html">Modules</a>
+          </li>
+
+          <li>
+            <a href="/docs/configuration-0-11/terraform.html">Terraform</a>
+          </li>
+
+          <li>
+            <a href="/docs/language/resources/provisioners/index.html">Provisioners</a>
+          </li>
+
+          <li>
+            <a href="/docs/configuration-0-11/terraform-enterprise.html">Terraform Push (deprecated)</a>
+          </li>
+
+          <li>
+            <a href="/docs/configuration-0-11/environment-variables.html">Environment Variables</a>
+          </li>
+        </ul>
+      </li>
+
+    </ul>
+
+    <%= partial("layouts/otherdocs", :locals => { :skip => "Terraform Language" }) %>
+  <% end %>
+
+  <%= yield %>
+<% end %>
diff --git a/v1.5.7/website/package-lock.json b/v1.5.7/website/package-lock.json
new file mode 100644
index 0000000..6d55418
--- /dev/null
+++ b/v1.5.7/website/package-lock.json
@@ -0,0 +1,29501 @@
+{
+  "name": "terraform-docs-preview",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "terraform-docs-preview",
+      "devDependencies": {
+        "@hashicorp/platform-cli": "^2.6.0",
+        "@hashicorp/platform-content-conformance": "^0.0.10",
+        "next": "^12.1.0"
+      },
+      "engines": {
+        "npm": ">=7.0.0"
+      }
+    },
+    "node_modules/@ampproject/remapping": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
+      "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.1.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@ampproject/remapping/node_modules/@jridgewell/gen-mapping": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
+      "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/set-array": "^1.0.0",
+        "@jridgewell/sourcemap-codec": "^1.4.10"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
+      "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/highlight": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/compat-data": {
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz",
+      "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/core": {
+      "version": "7.12.9",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz",
+      "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.10.4",
+        "@babel/generator": "^7.12.5",
+        "@babel/helper-module-transforms": "^7.12.1",
+        "@babel/helpers": "^7.12.5",
+        "@babel/parser": "^7.12.7",
+        "@babel/template": "^7.12.7",
+        "@babel/traverse": "^7.12.9",
+        "@babel/types": "^7.12.7",
+        "convert-source-map": "^1.7.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.1",
+        "json5": "^2.1.2",
+        "lodash": "^4.17.19",
+        "resolve": "^1.3.2",
+        "semver": "^5.4.1",
+        "source-map": "^0.5.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@babel/generator": {
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz",
+      "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.21.3",
+        "@jridgewell/gen-mapping": "^0.3.2",
+        "@jridgewell/trace-mapping": "^0.3.17",
+        "jsesc": "^2.5.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
+      "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/compat-data": "^7.20.5",
+        "@babel/helper-validator-option": "^7.18.6",
+        "browserslist": "^4.21.3",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/helper-environment-visitor": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
+      "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-function-name": {
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
+      "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/template": "^7.20.7",
+        "@babel/types": "^7.21.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-hoist-variables": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
+      "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-imports": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
+      "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-transforms": {
+      "version": "7.21.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz",
+      "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-module-imports": "^7.18.6",
+        "@babel/helper-simple-access": "^7.20.2",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/helper-validator-identifier": "^7.19.1",
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.21.2",
+        "@babel/types": "^7.21.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-plugin-utils": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz",
+      "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==",
+      "dev": true
+    },
+    "node_modules/@babel/helper-simple-access": {
+      "version": "7.20.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
+      "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.20.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-split-export-declaration": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
+      "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-string-parser": {
+      "version": "7.19.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
+      "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.19.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
+      "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-option": {
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz",
+      "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helpers": {
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz",
+      "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.21.0",
+        "@babel/types": "^7.21.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/highlight": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+      "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.18.6",
+        "chalk": "^2.0.0",
+        "js-tokens": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz",
+      "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==",
+      "dev": true,
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-object-rest-spread": {
+      "version": "7.12.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz",
+      "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.0",
+        "@babel/plugin-transform-parameters": "^7.12.1"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-async-generators": {
+      "version": "7.8.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
+      "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-bigint": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
+      "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-class-properties": {
+      "version": "7.12.13",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
+      "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.12.13"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-class-properties/node_modules/@babel/helper-plugin-utils": {
+      "version": "7.20.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
+      "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-import-meta": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
+      "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-json-strings": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
+      "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-jsx": {
+      "version": "7.12.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz",
+      "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-logical-assignment-operators": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
+      "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
+      "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-numeric-separator": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
+      "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-object-rest-spread": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
+      "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-optional-catch-binding": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
+      "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-optional-chaining": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
+      "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-top-level-await": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
+      "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-top-level-await/node_modules/@babel/helper-plugin-utils": {
+      "version": "7.20.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
+      "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-parameters": {
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.21.3.tgz",
+      "integrity": "sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.20.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-parameters/node_modules/@babel/helper-plugin-utils": {
+      "version": "7.20.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
+      "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/runtime": {
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
+      "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
+      "dev": true,
+      "dependencies": {
+        "regenerator-runtime": "^0.13.11"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/template": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
+      "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.18.6",
+        "@babel/parser": "^7.20.7",
+        "@babel/types": "^7.20.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/traverse": {
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz",
+      "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.18.6",
+        "@babel/generator": "^7.21.3",
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-function-name": "^7.21.0",
+        "@babel/helper-hoist-variables": "^7.18.6",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/parser": "^7.21.3",
+        "@babel/types": "^7.21.3",
+        "debug": "^4.1.0",
+        "globals": "^11.1.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/types": {
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz",
+      "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-string-parser": "^7.19.4",
+        "@babel/helper-validator-identifier": "^7.19.1",
+        "to-fast-properties": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@bcoe/v8-coverage": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
+      "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@cnakazawa/watch": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz",
+      "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "exec-sh": "^0.3.2",
+        "minimist": "^1.2.0"
+      },
+      "bin": {
+        "watch": "cli.js"
+      },
+      "engines": {
+        "node": ">=0.1.95"
+      }
+    },
+    "node_modules/@eslint-community/eslint-utils": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz",
+      "integrity": "sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==",
+      "dev": true,
+      "dependencies": {
+        "eslint-visitor-keys": "^3.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+      }
+    },
+    "node_modules/@eslint-community/regexpp": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz",
+      "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==",
+      "dev": true,
+      "engines": {
+        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@eslint/eslintrc": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz",
+      "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==",
+      "dev": true,
+      "dependencies": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^9.5.0",
+        "globals": "^13.19.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/globals": {
+      "version": "13.20.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
+      "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+      "dev": true,
+      "dependencies": {
+        "type-fest": "^0.20.2"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/type-fest": {
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@eslint/js": {
+      "version": "8.36.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz",
+      "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==",
+      "dev": true,
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@hashicorp/platform-cli": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/@hashicorp/platform-cli/-/platform-cli-2.6.0.tgz",
+      "integrity": "sha512-nMO7Uiy/A5CT/BCE9RyQt6/Uci7bxwTesxCNWkXlciyqlIrz9WmBa9hr710IiMoDzrzQ1tL6AgFIeTbXs4RTqA==",
+      "dev": true,
+      "dependencies": {
+        "@hashicorp/platform-cms": "0.3.0",
+        "@typescript-eslint/eslint-plugin": "^5.48.0",
+        "@typescript-eslint/parser": "^5.48.0",
+        "chalk": "4.1.0",
+        "commander": "7.2.0",
+        "ejs": "3.1.5",
+        "eslint": "^8.31.0",
+        "eslint-config-next": "^13.1.1",
+        "eslint-config-prettier": "^8.6.0",
+        "eslint-plugin-jsx-a11y": "^6.6.1",
+        "eslint-plugin-prettier": "^4.2.1",
+        "fs-extra": "9.0.1",
+        "globby": "11.0.1",
+        "inquirer": "7.3.3",
+        "lint-staged": "11.1.2",
+        "open": "7.3.0",
+        "prettier": "2.5.1",
+        "readdirp": "3.5.0",
+        "signale": "1.4.0",
+        "slugify": "1.4.6",
+        "stylelint": "13.8.0",
+        "stylelint-config-css-modules": "2.2.0",
+        "stylelint-config-prettier": "8.0.2",
+        "stylelint-config-standard": "20.0.0",
+        "stylelint-media-use-custom-media": "2.0.0",
+        "stylelint-order": "4.1.0",
+        "stylelint-use-nesting": "3.0.0",
+        "stylelint-value-no-unknown-custom-properties": "3.0.0",
+        "ts-jest": "^26.4.4"
+      },
+      "bin": {
+        "next-hashicorp": "next-hashicorp"
+      }
+    },
+    "node_modules/@hashicorp/platform-cli/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/@hashicorp/platform-cli/node_modules/chalk": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+      "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/@hashicorp/platform-cli/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/@hashicorp/platform-cli/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/@hashicorp/platform-cli/node_modules/globby": {
+      "version": "11.0.1",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz",
+      "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==",
+      "dev": true,
+      "dependencies": {
+        "array-union": "^2.1.0",
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.1.1",
+        "ignore": "^5.1.4",
+        "merge2": "^1.3.0",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@hashicorp/platform-cli/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@hashicorp/platform-cli/node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@hashicorp/platform-cli/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@hashicorp/platform-cms": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/@hashicorp/platform-cms/-/platform-cms-0.3.0.tgz",
+      "integrity": "sha512-sRX9A+kDEZvfZy8PvGFbEaHjn5G1mEsHwTri1vDnrmKG8apE+ELlug83b0iEkD5wIJi9OqaewMIb0NrLxg9s5A==",
+      "dev": true,
+      "dependencies": {
+        "rivet-graphql": "0.3.1"
+      }
+    },
+    "node_modules/@hashicorp/platform-content-conformance": {
+      "version": "0.0.10",
+      "resolved": "https://registry.npmjs.org/@hashicorp/platform-content-conformance/-/platform-content-conformance-0.0.10.tgz",
+      "integrity": "sha512-vXLbd2w9phS4JfFyh17jCiyu+LXVonTfb7WEUK2eMlOL/wxe2umyJvEQaJNzD5bwyYC8LuXGA5JkbnPXnU5ZQg==",
+      "dev": true,
+      "dependencies": {
+        "find-up": "^6.3.0",
+        "flat": "^5.0.2",
+        "globby": "^13.1.2",
+        "mdast-util-to-string": "^3.1.0",
+        "remark": "12.0.1",
+        "remark-mdx": "^1.6.22",
+        "unified-lint-rule": "^2.1.1",
+        "unist-util-stringify-position": "^3.0.2",
+        "unist-util-visit": "^4.1.1",
+        "vfile": "^5.3.6",
+        "vfile-matter": "^4.0.0",
+        "vfile-reporter": "^7.0.4",
+        "vfile-reporter-json": "^3.2.0",
+        "vfile-statistics": "^2.0.0",
+        "yaml": "^2.1.3",
+        "yargs": "^17.4.1",
+        "zod": "^3.19.1"
+      },
+      "bin": {
+        "hc-content": "dist/cli.js"
+      }
+    },
+    "node_modules/@humanwhocodes/config-array": {
+      "version": "0.11.8",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
+      "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+      "dev": true,
+      "dependencies": {
+        "@humanwhocodes/object-schema": "^1.2.1",
+        "debug": "^4.1.1",
+        "minimatch": "^3.0.5"
+      },
+      "engines": {
+        "node": ">=10.10.0"
+      }
+    },
+    "node_modules/@humanwhocodes/module-importer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+      "dev": true,
+      "engines": {
+        "node": ">=12.22"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@humanwhocodes/object-schema": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+      "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+      "dev": true
+    },
+    "node_modules/@istanbuljs/load-nyc-config": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+      "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "camelcase": "^5.3.1",
+        "find-up": "^4.1.0",
+        "get-package-type": "^0.1.0",
+        "js-yaml": "^3.13.1",
+        "resolve-from": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/schema": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
+      "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/console": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz",
+      "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "jest-message-util": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/@jest/console/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/@jest/console/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/@jest/console/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/@jest/console/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@jest/console/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/console/node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/console/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/core": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz",
+      "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/console": "^26.6.2",
+        "@jest/reporters": "^26.6.2",
+        "@jest/test-result": "^26.6.2",
+        "@jest/transform": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.0.0",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.2.4",
+        "jest-changed-files": "^26.6.2",
+        "jest-config": "^26.6.3",
+        "jest-haste-map": "^26.6.2",
+        "jest-message-util": "^26.6.2",
+        "jest-regex-util": "^26.0.0",
+        "jest-resolve": "^26.6.2",
+        "jest-resolve-dependencies": "^26.6.3",
+        "jest-runner": "^26.6.3",
+        "jest-runtime": "^26.6.3",
+        "jest-snapshot": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "jest-validate": "^26.6.2",
+        "jest-watcher": "^26.6.2",
+        "micromatch": "^4.0.2",
+        "p-each-series": "^2.1.0",
+        "rimraf": "^3.0.0",
+        "slash": "^3.0.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/@jest/core/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/core/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/@jest/core/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/@jest/core/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/@jest/core/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@jest/core/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/core/node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/core/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/core/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/environment": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz",
+      "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/fake-timers": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "jest-mock": "^26.6.2"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/@jest/fake-timers": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz",
+      "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/types": "^26.6.2",
+        "@sinonjs/fake-timers": "^6.0.1",
+        "@types/node": "*",
+        "jest-message-util": "^26.6.2",
+        "jest-mock": "^26.6.2",
+        "jest-util": "^26.6.2"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/@jest/globals": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz",
+      "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/environment": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "expect": "^26.6.2"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/@jest/reporters": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz",
+      "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@bcoe/v8-coverage": "^0.2.3",
+        "@jest/console": "^26.6.2",
+        "@jest/test-result": "^26.6.2",
+        "@jest/transform": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "chalk": "^4.0.0",
+        "collect-v8-coverage": "^1.0.0",
+        "exit": "^0.1.2",
+        "glob": "^7.1.2",
+        "graceful-fs": "^4.2.4",
+        "istanbul-lib-coverage": "^3.0.0",
+        "istanbul-lib-instrument": "^4.0.3",
+        "istanbul-lib-report": "^3.0.0",
+        "istanbul-lib-source-maps": "^4.0.0",
+        "istanbul-reports": "^3.0.2",
+        "jest-haste-map": "^26.6.2",
+        "jest-resolve": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "jest-worker": "^26.6.2",
+        "slash": "^3.0.0",
+        "source-map": "^0.6.0",
+        "string-length": "^4.0.1",
+        "terminal-link": "^2.0.0",
+        "v8-to-istanbul": "^7.0.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      },
+      "optionalDependencies": {
+        "node-notifier": "^8.0.0"
+      }
+    },
+    "node_modules/@jest/reporters/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/@jest/reporters/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/@jest/reporters/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/@jest/reporters/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@jest/reporters/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/reporters/node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/reporters/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/@jest/reporters/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/source-map": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz",
+      "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "callsites": "^3.0.0",
+        "graceful-fs": "^4.2.4",
+        "source-map": "^0.6.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/@jest/source-map/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/@jest/test-result": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz",
+      "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/console": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/istanbul-lib-coverage": "^2.0.0",
+        "collect-v8-coverage": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/@jest/test-sequencer": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz",
+      "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/test-result": "^26.6.2",
+        "graceful-fs": "^4.2.4",
+        "jest-haste-map": "^26.6.2",
+        "jest-runner": "^26.6.3",
+        "jest-runtime": "^26.6.3"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/@jest/transform": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz",
+      "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/core": "^7.1.0",
+        "@jest/types": "^26.6.2",
+        "babel-plugin-istanbul": "^6.0.0",
+        "chalk": "^4.0.0",
+        "convert-source-map": "^1.4.0",
+        "fast-json-stable-stringify": "^2.0.0",
+        "graceful-fs": "^4.2.4",
+        "jest-haste-map": "^26.6.2",
+        "jest-regex-util": "^26.0.0",
+        "jest-util": "^26.6.2",
+        "micromatch": "^4.0.2",
+        "pirates": "^4.0.1",
+        "slash": "^3.0.0",
+        "source-map": "^0.6.1",
+        "write-file-atomic": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/@jest/transform/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/@jest/transform/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/@jest/transform/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/@jest/transform/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@jest/transform/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/transform/node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/transform/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/@jest/transform/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/types": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz",
+      "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/istanbul-lib-coverage": "^2.0.0",
+        "@types/istanbul-reports": "^3.0.0",
+        "@types/node": "*",
+        "@types/yargs": "^15.0.0",
+        "chalk": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/@jest/types/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/@jest/types/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/@jest/types/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/@jest/types/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/@jest/types/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/types/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
+      "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/set-array": "^1.0.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/set-array": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+      "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.4.14",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+      "dev": true
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.17",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
+      "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/resolve-uri": "3.1.0",
+        "@jridgewell/sourcemap-codec": "1.4.14"
+      }
+    },
+    "node_modules/@mdx-js/util": {
+      "version": "1.6.22",
+      "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz",
+      "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==",
+      "dev": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/@next/env": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.4.tgz",
+      "integrity": "sha512-7gQwotJDKnfMxxXd8xJ2vsX5AzyDxO3zou0+QOXX8/unypA6icw5+wf6A62yKZ6qQ4UZHHxS68pb6UV+wNneXg==",
+      "dev": true
+    },
+    "node_modules/@next/eslint-plugin-next": {
+      "version": "13.2.4",
+      "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.2.4.tgz",
+      "integrity": "sha512-ck1lI+7r1mMJpqLNa3LJ5pxCfOB1lfJncKmRJeJxcJqcngaFwylreLP7da6Rrjr6u2gVRTfmnkSkjc80IiQCwQ==",
+      "dev": true,
+      "dependencies": {
+        "glob": "7.1.7"
+      }
+    },
+    "node_modules/@next/swc-android-arm-eabi": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.4.tgz",
+      "integrity": "sha512-FJg/6a3s2YrUaqZ+/DJZzeZqfxbbWrynQMT1C5wlIEq9aDLXCFpPM/PiOyJh0ahxc0XPmi6uo38Poq+GJTuKWw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-android-arm64": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.1.4.tgz",
+      "integrity": "sha512-LXraazvQQFBgxIg3Htny6G5V5he9EK7oS4jWtMdTGIikmD/OGByOv8ZjLuVLZLtVm3UIvaAiGtlQSLecxJoJDw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-darwin-arm64": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.4.tgz",
+      "integrity": "sha512-SSST/dBymecllZxcqTCcSTCu5o1NKk9I+xcvhn/O9nH6GWjgvGgGkNqLbCarCa0jJ1ukvlBA138FagyrmZ/4rQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-darwin-x64": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.4.tgz",
+      "integrity": "sha512-p1lwdX0TVjaoDXQVuAkjtxVBbCL/urgxiMCBwuPDO7TikpXtSRivi+mIzBj5q7ypgICFmIAOW3TyupXeoPRAnA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-arm-gnueabihf": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.4.tgz",
+      "integrity": "sha512-67PZlgkCn3TDxacdVft0xqDCL7Io1/C4xbAs0+oSQ0xzp6OzN2RNpuKjHJrJgKd0DsE1XZ9sCP27Qv0591yfyg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-arm64-gnu": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.4.tgz",
+      "integrity": "sha512-OnOWixhhw7aU22TQdQLYrgpgFq0oA1wGgnjAiHJ+St7MLj82KTDyM9UcymAMbGYy6nG/TFOOHdTmRMtCRNOw0g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-arm64-musl": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.4.tgz",
+      "integrity": "sha512-UoRMzPZnsAavdWtVylYxH8DNC7Uy0i6RrvNwT4PyQVdfANBn2omsUkcH5lgS2O7oaz0nAYLk1vqyZDO7+tJotA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-x64-gnu": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.4.tgz",
+      "integrity": "sha512-nM+MA/frxlTLUKLJKorctdI20/ugfHRjVEEkcLp/58LGG7slNaP1E5d5dRA1yX6ISjPcQAkywas5VlGCg+uTvA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-x64-musl": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.4.tgz",
+      "integrity": "sha512-GoRHxkuW4u4yKw734B9SzxJwVdyEJosaZ62P7ifOwcujTxhgBt3y76V2nNUrsSuopcKI2ZTDjaa+2wd5zyeXbA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-win32-arm64-msvc": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.4.tgz",
+      "integrity": "sha512-6TQkQze0ievXwHJcVUrIULwCYVe3ccX6T0JgZ1SiMeXpHxISN7VJF/O8uSCw1JvXZYZ6ud0CJ7nfC5HXivgfPg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-win32-ia32-msvc": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.4.tgz",
+      "integrity": "sha512-CsbX/IXuZ5VSmWCpSetG2HD6VO5FTsO39WNp2IR2Ut/uom9XtLDJAZqjQEnbUTLGHuwDKFjrIO3LkhtROXLE/g==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-win32-x64-msvc": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.4.tgz",
+      "integrity": "sha512-JtYuWzKXKLDMgE/xTcFtCm1MiCIRaAc5XYZfYX3n/ZWSI1SJS/GMm+Su0SAHJgRFavJh6U/p998YwO/iGTIgqQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@pkgr/utils": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz",
+      "integrity": "sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==",
+      "dev": true,
+      "dependencies": {
+        "cross-spawn": "^7.0.3",
+        "is-glob": "^4.0.3",
+        "open": "^8.4.0",
+        "picocolors": "^1.0.0",
+        "tiny-glob": "^0.2.9",
+        "tslib": "^2.4.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/unts"
+      }
+    },
+    "node_modules/@pkgr/utils/node_modules/open": {
+      "version": "8.4.2",
+      "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
+      "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
+      "dev": true,
+      "dependencies": {
+        "define-lazy-prop": "^2.0.0",
+        "is-docker": "^2.1.1",
+        "is-wsl": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@pkgr/utils/node_modules/tslib": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+      "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
+      "dev": true
+    },
+    "node_modules/@rushstack/eslint-patch": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz",
+      "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==",
+      "dev": true
+    },
+    "node_modules/@sinonjs/commons": {
+      "version": "1.8.6",
+      "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz",
+      "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "type-detect": "4.0.8"
+      }
+    },
+    "node_modules/@sinonjs/fake-timers": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz",
+      "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@sinonjs/commons": "^1.7.0"
+      }
+    },
+    "node_modules/@stylelint/postcss-css-in-js": {
+      "version": "0.37.3",
+      "resolved": "https://registry.npmjs.org/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.3.tgz",
+      "integrity": "sha512-scLk3cSH1H9KggSniseb2KNAU5D9FWc3H7BxCSAIdtU9OWIyw0zkEZ9qEKHryRM+SExYXRKNb7tOOVNAsQ3iwg==",
+      "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
+      "dev": true,
+      "dependencies": {
+        "@babel/core": "^7.17.9"
+      },
+      "peerDependencies": {
+        "postcss": ">=7.0.0",
+        "postcss-syntax": ">=0.36.2"
+      }
+    },
+    "node_modules/@stylelint/postcss-css-in-js/node_modules/@babel/core": {
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz",
+      "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==",
+      "dev": true,
+      "dependencies": {
+        "@ampproject/remapping": "^2.2.0",
+        "@babel/code-frame": "^7.18.6",
+        "@babel/generator": "^7.21.3",
+        "@babel/helper-compilation-targets": "^7.20.7",
+        "@babel/helper-module-transforms": "^7.21.2",
+        "@babel/helpers": "^7.21.0",
+        "@babel/parser": "^7.21.3",
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.21.3",
+        "@babel/types": "^7.21.3",
+        "convert-source-map": "^1.7.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.2",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@stylelint/postcss-css-in-js/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@stylelint/postcss-markdown": {
+      "version": "0.36.2",
+      "resolved": "https://registry.npmjs.org/@stylelint/postcss-markdown/-/postcss-markdown-0.36.2.tgz",
+      "integrity": "sha512-2kGbqUVJUGE8dM+bMzXG/PYUWKkjLIkRLWNh39OaADkiabDRdw8ATFCgbMz5xdIcvwspPAluSL7uY+ZiTWdWmQ==",
+      "deprecated": "Use the original unforked package instead: postcss-markdown",
+      "dev": true,
+      "dependencies": {
+        "remark": "^13.0.0",
+        "unist-util-find-all-after": "^3.0.2"
+      },
+      "peerDependencies": {
+        "postcss": ">=7.0.0",
+        "postcss-syntax": ">=0.36.2"
+      }
+    },
+    "node_modules/@stylelint/postcss-markdown/node_modules/remark": {
+      "version": "13.0.0",
+      "resolved": "https://registry.npmjs.org/remark/-/remark-13.0.0.tgz",
+      "integrity": "sha512-HDz1+IKGtOyWN+QgBiAT0kn+2s6ovOxHyPAFGKVE81VSzJ+mq7RwHFledEvB5F1p4iJvOah/LOKdFuzvRnNLCA==",
+      "dev": true,
+      "dependencies": {
+        "remark-parse": "^9.0.0",
+        "remark-stringify": "^9.0.0",
+        "unified": "^9.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/@stylelint/postcss-markdown/node_modules/remark-parse": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz",
+      "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==",
+      "dev": true,
+      "dependencies": {
+        "mdast-util-from-markdown": "^0.8.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/@stylelint/postcss-markdown/node_modules/remark-stringify": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-9.0.1.tgz",
+      "integrity": "sha512-mWmNg3ZtESvZS8fv5PTvaPckdL4iNlCHTt8/e/8oN08nArHRHjNZMKzA/YW3+p7/lYqIw4nx1XsjCBo/AxNChg==",
+      "dev": true,
+      "dependencies": {
+        "mdast-util-to-markdown": "^0.6.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/@tootallnate/once": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
+      "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@types/babel__core": {
+      "version": "7.20.0",
+      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz",
+      "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/parser": "^7.20.7",
+        "@babel/types": "^7.20.7",
+        "@types/babel__generator": "*",
+        "@types/babel__template": "*",
+        "@types/babel__traverse": "*"
+      }
+    },
+    "node_modules/@types/babel__generator": {
+      "version": "7.6.4",
+      "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz",
+      "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__template": {
+      "version": "7.4.1",
+      "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz",
+      "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/parser": "^7.1.0",
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__traverse": {
+      "version": "7.18.3",
+      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz",
+      "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/types": "^7.3.0"
+      }
+    },
+    "node_modules/@types/graceful-fs": {
+      "version": "4.1.6",
+      "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz",
+      "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/istanbul-lib-coverage": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
+      "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==",
+      "dev": true
+    },
+    "node_modules/@types/istanbul-lib-report": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+      "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==",
+      "dev": true,
+      "dependencies": {
+        "@types/istanbul-lib-coverage": "*"
+      }
+    },
+    "node_modules/@types/istanbul-reports": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz",
+      "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==",
+      "dev": true,
+      "dependencies": {
+        "@types/istanbul-lib-report": "*"
+      }
+    },
+    "node_modules/@types/json-schema": {
+      "version": "7.0.11",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
+      "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
+      "dev": true
+    },
+    "node_modules/@types/json5": {
+      "version": "0.0.29",
+      "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+      "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
+      "dev": true
+    },
+    "node_modules/@types/mdast": {
+      "version": "3.0.10",
+      "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz",
+      "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "*"
+      }
+    },
+    "node_modules/@types/minimist": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz",
+      "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==",
+      "dev": true
+    },
+    "node_modules/@types/node": {
+      "version": "18.15.3",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.3.tgz",
+      "integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==",
+      "dev": true
+    },
+    "node_modules/@types/normalize-package-data": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz",
+      "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==",
+      "dev": true
+    },
+    "node_modules/@types/parse-json": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+      "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+      "dev": true
+    },
+    "node_modules/@types/prettier": {
+      "version": "2.7.2",
+      "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz",
+      "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@types/semver": {
+      "version": "7.3.13",
+      "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
+      "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
+      "dev": true
+    },
+    "node_modules/@types/stack-utils": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
+      "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@types/supports-color": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/@types/supports-color/-/supports-color-8.1.1.tgz",
+      "integrity": "sha512-dPWnWsf+kzIG140B8z2w3fr5D03TLWbOAFQl45xUpI3vcizeXriNR5VYkWZ+WTMsUHqZ9Xlt3hrxGNANFyNQfw==",
+      "dev": true
+    },
+    "node_modules/@types/unist": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
+      "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==",
+      "dev": true
+    },
+    "node_modules/@types/yargs": {
+      "version": "15.0.15",
+      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz",
+      "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==",
+      "dev": true,
+      "dependencies": {
+        "@types/yargs-parser": "*"
+      }
+    },
+    "node_modules/@types/yargs-parser": {
+      "version": "21.0.0",
+      "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz",
+      "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
+      "dev": true
+    },
+    "node_modules/@typescript-eslint/eslint-plugin": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz",
+      "integrity": "sha512-IZGc50rtbjk+xp5YQoJvmMPmJEYoC53SiKPXyqWfv15XoD2Y5Kju6zN0DwlmaGJp1Iw33JsWJcQ7nw0lGCGjVg==",
+      "dev": true,
+      "dependencies": {
+        "@eslint-community/regexpp": "^4.4.0",
+        "@typescript-eslint/scope-manager": "5.55.0",
+        "@typescript-eslint/type-utils": "5.55.0",
+        "@typescript-eslint/utils": "5.55.0",
+        "debug": "^4.3.4",
+        "grapheme-splitter": "^1.0.4",
+        "ignore": "^5.2.0",
+        "natural-compare-lite": "^1.4.0",
+        "semver": "^7.3.7",
+        "tsutils": "^3.21.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "@typescript-eslint/parser": "^5.0.0",
+        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": {
+      "version": "7.3.8",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true
+    },
+    "node_modules/@typescript-eslint/parser": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.55.0.tgz",
+      "integrity": "sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/scope-manager": "5.55.0",
+        "@typescript-eslint/types": "5.55.0",
+        "@typescript-eslint/typescript-estree": "5.55.0",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/scope-manager": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz",
+      "integrity": "sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/types": "5.55.0",
+        "@typescript-eslint/visitor-keys": "5.55.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/type-utils": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.55.0.tgz",
+      "integrity": "sha512-ObqxBgHIXj8rBNm0yh8oORFrICcJuZPZTqtAFh0oZQyr5DnAHZWfyw54RwpEEH+fD8suZaI0YxvWu5tYE/WswA==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/typescript-estree": "5.55.0",
+        "@typescript-eslint/utils": "5.55.0",
+        "debug": "^4.3.4",
+        "tsutils": "^3.21.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "*"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/types": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz",
+      "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==",
+      "dev": true,
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz",
+      "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/types": "5.55.0",
+        "@typescript-eslint/visitor-keys": "5.55.0",
+        "debug": "^4.3.4",
+        "globby": "^11.1.0",
+        "is-glob": "^4.0.3",
+        "semver": "^7.3.7",
+        "tsutils": "^3.21.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+      "dev": true,
+      "dependencies": {
+        "array-union": "^2.1.0",
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.2.9",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+      "version": "7.3.8",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true
+    },
+    "node_modules/@typescript-eslint/utils": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.55.0.tgz",
+      "integrity": "sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw==",
+      "dev": true,
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.2.0",
+        "@types/json-schema": "^7.0.9",
+        "@types/semver": "^7.3.12",
+        "@typescript-eslint/scope-manager": "5.55.0",
+        "@typescript-eslint/types": "5.55.0",
+        "@typescript-eslint/typescript-estree": "5.55.0",
+        "eslint-scope": "^5.1.1",
+        "semver": "^7.3.7"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/utils/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@typescript-eslint/utils/node_modules/semver": {
+      "version": "7.3.8",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@typescript-eslint/utils/node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true
+    },
+    "node_modules/@typescript-eslint/visitor-keys": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz",
+      "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/types": "5.55.0",
+        "eslint-visitor-keys": "^3.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/abab": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
+      "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/acorn": {
+      "version": "8.8.2",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
+      "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
+      "dev": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-globals": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz",
+      "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "acorn": "^7.1.1",
+        "acorn-walk": "^7.1.1"
+      }
+    },
+    "node_modules/acorn-globals/node_modules/acorn": {
+      "version": "7.4.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+      "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+      "dev": true,
+      "peer": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true,
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/acorn-walk": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
+      "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/agent-base": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6.0.0"
+      }
+    },
+    "node_modules/aggregate-error": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+      "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+      "dev": true,
+      "dependencies": {
+        "clean-stack": "^2.0.0",
+        "indent-string": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/ansi-colors": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+      "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/ansi-escapes": {
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+      "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+      "dev": true,
+      "dependencies": {
+        "type-fest": "^0.21.3"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+      "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true
+    },
+    "node_modules/aria-query": {
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz",
+      "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==",
+      "dev": true,
+      "dependencies": {
+        "deep-equal": "^2.0.5"
+      }
+    },
+    "node_modules/arr-diff": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+      "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/arr-flatten": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/arr-union": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+      "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/array-buffer-byte-length": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz",
+      "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "is-array-buffer": "^3.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array-includes": {
+      "version": "3.1.6",
+      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz",
+      "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4",
+        "get-intrinsic": "^1.1.3",
+        "is-string": "^1.0.7"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array-union": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/array-unique": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+      "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/array.prototype.flat": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz",
+      "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4",
+        "es-shim-unscopables": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array.prototype.flatmap": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz",
+      "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4",
+        "es-shim-unscopables": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array.prototype.tosorted": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz",
+      "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4",
+        "es-shim-unscopables": "^1.0.0",
+        "get-intrinsic": "^1.1.3"
+      }
+    },
+    "node_modules/arrify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+      "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/assign-symbols": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+      "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/ast-types-flow": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
+      "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==",
+      "dev": true
+    },
+    "node_modules/astral-regex": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+      "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/async": {
+      "version": "3.2.4",
+      "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
+      "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
+      "dev": true
+    },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+      "dev": true
+    },
+    "node_modules/at-least-node": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+      "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4.0.0"
+      }
+    },
+    "node_modules/atob": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+      "dev": true,
+      "peer": true,
+      "bin": {
+        "atob": "bin/atob.js"
+      },
+      "engines": {
+        "node": ">= 4.5.0"
+      }
+    },
+    "node_modules/autoprefixer": {
+      "version": "9.8.8",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.8.tgz",
+      "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==",
+      "dev": true,
+      "dependencies": {
+        "browserslist": "^4.12.0",
+        "caniuse-lite": "^1.0.30001109",
+        "normalize-range": "^0.1.2",
+        "num2fraction": "^1.2.2",
+        "picocolors": "^0.2.1",
+        "postcss": "^7.0.32",
+        "postcss-value-parser": "^4.1.0"
+      },
+      "bin": {
+        "autoprefixer": "bin/autoprefixer"
+      },
+      "funding": {
+        "type": "tidelift",
+        "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+      }
+    },
+    "node_modules/autoprefixer/node_modules/picocolors": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+      "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+      "dev": true
+    },
+    "node_modules/autoprefixer/node_modules/postcss": {
+      "version": "7.0.39",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+      "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+      "dev": true,
+      "dependencies": {
+        "picocolors": "^0.2.1",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/autoprefixer/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/available-typed-arrays": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
+      "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/axe-core": {
+      "version": "4.6.3",
+      "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.3.tgz",
+      "integrity": "sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/axobject-query": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz",
+      "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==",
+      "dev": true,
+      "dependencies": {
+        "deep-equal": "^2.0.5"
+      }
+    },
+    "node_modules/babel-jest": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz",
+      "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/transform": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/babel__core": "^7.1.7",
+        "babel-plugin-istanbul": "^6.0.0",
+        "babel-preset-jest": "^26.6.2",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.4",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/babel-jest/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/babel-jest/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/babel-jest/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/babel-jest/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/babel-jest/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/babel-jest/node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/babel-jest/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/babel-plugin-istanbul": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
+      "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.0.0",
+        "@istanbuljs/load-nyc-config": "^1.0.0",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-instrument": "^5.0.4",
+        "test-exclude": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
+      "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/core": "^7.12.3",
+        "@babel/parser": "^7.14.7",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-coverage": "^3.2.0",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/babel-plugin-istanbul/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "peer": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/babel-plugin-jest-hoist": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz",
+      "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/template": "^7.3.3",
+        "@babel/types": "^7.3.3",
+        "@types/babel__core": "^7.0.0",
+        "@types/babel__traverse": "^7.0.6"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/babel-preset-current-node-syntax": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz",
+      "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/plugin-syntax-async-generators": "^7.8.4",
+        "@babel/plugin-syntax-bigint": "^7.8.3",
+        "@babel/plugin-syntax-class-properties": "^7.8.3",
+        "@babel/plugin-syntax-import-meta": "^7.8.3",
+        "@babel/plugin-syntax-json-strings": "^7.8.3",
+        "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3",
+        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
+        "@babel/plugin-syntax-numeric-separator": "^7.8.3",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+        "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
+        "@babel/plugin-syntax-optional-chaining": "^7.8.3",
+        "@babel/plugin-syntax-top-level-await": "^7.8.3"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/babel-preset-jest": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz",
+      "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "babel-plugin-jest-hoist": "^26.6.2",
+        "babel-preset-current-node-syntax": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/bail": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
+      "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "dev": true
+    },
+    "node_modules/base": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+      "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "cache-base": "^1.0.1",
+        "class-utils": "^0.3.5",
+        "component-emitter": "^1.2.1",
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.1",
+        "mixin-deep": "^1.2.0",
+        "pascalcase": "^0.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/base/node_modules/define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+      "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dev": true,
+      "dependencies": {
+        "fill-range": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/browser-process-hrtime": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz",
+      "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/browserslist": {
+      "version": "4.21.5",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
+      "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        }
+      ],
+      "dependencies": {
+        "caniuse-lite": "^1.0.30001449",
+        "electron-to-chromium": "^1.4.284",
+        "node-releases": "^2.0.8",
+        "update-browserslist-db": "^1.0.10"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/bs-logger": {
+      "version": "0.2.6",
+      "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz",
+      "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==",
+      "dev": true,
+      "dependencies": {
+        "fast-json-stable-stringify": "2.x"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/bser": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
+      "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "node-int64": "^0.4.0"
+      }
+    },
+    "node_modules/buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "dev": true
+    },
+    "node_modules/cache-base": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+      "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "collection-visit": "^1.0.0",
+        "component-emitter": "^1.2.1",
+        "get-value": "^2.0.6",
+        "has-value": "^1.0.0",
+        "isobject": "^3.0.1",
+        "set-value": "^2.0.0",
+        "to-object-path": "^0.3.0",
+        "union-value": "^1.0.0",
+        "unset-value": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/call-bind": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+      "dev": true,
+      "dependencies": {
+        "function-bind": "^1.1.1",
+        "get-intrinsic": "^1.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/camelcase-keys": {
+      "version": "6.2.2",
+      "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz",
+      "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==",
+      "dev": true,
+      "dependencies": {
+        "camelcase": "^5.3.1",
+        "map-obj": "^4.0.0",
+        "quick-lru": "^4.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001466",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001466.tgz",
+      "integrity": "sha512-ewtFBSfWjEmxUgNBSZItFSmVtvk9zkwkl1OfRZlKA8slltRN+/C/tuGVrF9styXkN36Yu3+SeJ1qkXxDEyNZ5w==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        }
+      ]
+    },
+    "node_modules/capture-exit": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz",
+      "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "rsvp": "^4.8.4"
+      },
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/ccount": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz",
+      "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/char-regex": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
+      "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/character-entities": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
+      "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/character-entities-html4": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz",
+      "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/character-entities-legacy": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
+      "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/character-reference-invalid": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
+      "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/chardet": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+      "dev": true
+    },
+    "node_modules/ci-info": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+      "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+      "dev": true
+    },
+    "node_modules/cjs-module-lexer": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz",
+      "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/class-utils": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+      "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "arr-union": "^3.1.0",
+        "define-property": "^0.2.5",
+        "isobject": "^3.0.0",
+        "static-extend": "^0.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/class-utils/node_modules/define-property": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+      "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/class-utils/node_modules/is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/class-utils/node_modules/is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/class-utils/node_modules/is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/class-utils/node_modules/is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/class-utils/node_modules/kind-of": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+      "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/clean-stack": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+      "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/cli-cursor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+      "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+      "dev": true,
+      "dependencies": {
+        "restore-cursor": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cli-truncate": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
+      "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
+      "dev": true,
+      "dependencies": {
+        "slice-ansi": "^3.0.0",
+        "string-width": "^4.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/cli-truncate/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cli-truncate/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true
+    },
+    "node_modules/cli-truncate/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cli-truncate/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cli-width": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
+      "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/cliui": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.1",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/cliui/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cliui/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true
+    },
+    "node_modules/cliui/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cliui/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/clone-regexp": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz",
+      "integrity": "sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==",
+      "dev": true,
+      "dependencies": {
+        "is-regexp": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/clone-regexp/node_modules/is-regexp": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz",
+      "integrity": "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/co": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+      "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "iojs": ">= 1.0.0",
+        "node": ">= 0.12.0"
+      }
+    },
+    "node_modules/collapse-white-space": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz",
+      "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/collect-v8-coverage": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
+      "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/collection-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+      "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "map-visit": "^1.0.0",
+        "object-visit": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+      "dev": true
+    },
+    "node_modules/colorette": {
+      "version": "2.0.19",
+      "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
+      "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
+      "dev": true
+    },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "dev": true,
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/commander": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+      "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/component-emitter": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "dev": true
+    },
+    "node_modules/convert-source-map": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+      "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+      "dev": true
+    },
+    "node_modules/copy-descriptor": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+      "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/cosmiconfig": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
+      "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
+      "dev": true,
+      "dependencies": {
+        "@types/parse-json": "^4.0.0",
+        "import-fresh": "^3.2.1",
+        "parse-json": "^5.0.0",
+        "path-type": "^4.0.0",
+        "yaml": "^1.10.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/cosmiconfig/node_modules/yaml": {
+      "version": "1.10.2",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+      "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/cross-fetch": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
+      "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
+      "dev": true,
+      "dependencies": {
+        "node-fetch": "2.6.7"
+      }
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+      "dev": true,
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/cssesc": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+      "dev": true,
+      "bin": {
+        "cssesc": "bin/cssesc"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/cssom": {
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz",
+      "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/cssstyle": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz",
+      "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "cssom": "~0.3.6"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cssstyle/node_modules/cssom": {
+      "version": "0.3.8",
+      "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
+      "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/damerau-levenshtein": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
+      "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
+      "dev": true
+    },
+    "node_modules/data-urls": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
+      "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "abab": "^2.0.3",
+        "whatwg-mimetype": "^2.3.0",
+        "whatwg-url": "^8.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/debug": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.1.2"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/decamelize-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz",
+      "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==",
+      "dev": true,
+      "dependencies": {
+        "decamelize": "^1.1.0",
+        "map-obj": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/decamelize-keys/node_modules/map-obj": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+      "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/decimal.js": {
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
+      "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/decode-uri-component": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
+      "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/deep-equal": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz",
+      "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "es-get-iterator": "^1.1.2",
+        "get-intrinsic": "^1.1.3",
+        "is-arguments": "^1.1.1",
+        "is-array-buffer": "^3.0.1",
+        "is-date-object": "^1.0.5",
+        "is-regex": "^1.1.4",
+        "is-shared-array-buffer": "^1.0.2",
+        "isarray": "^2.0.5",
+        "object-is": "^1.1.5",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.4",
+        "regexp.prototype.flags": "^1.4.3",
+        "side-channel": "^1.0.4",
+        "which-boxed-primitive": "^1.0.2",
+        "which-collection": "^1.0.1",
+        "which-typed-array": "^1.1.9"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/deep-is": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+      "dev": true
+    },
+    "node_modules/deepmerge": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz",
+      "integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/define-lazy-prop": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
+      "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/define-properties": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz",
+      "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==",
+      "dev": true,
+      "dependencies": {
+        "has-property-descriptors": "^1.0.0",
+        "object-keys": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/detect-newline": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
+      "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/diff-sequences": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
+      "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/dir-glob": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+      "dev": true,
+      "dependencies": {
+        "path-type": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/doctrine": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+      "dev": true,
+      "dependencies": {
+        "esutils": "^2.0.2"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/dom-serializer": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
+      "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
+      "dev": true,
+      "dependencies": {
+        "domelementtype": "^2.0.1",
+        "entities": "^2.0.0"
+      }
+    },
+    "node_modules/dom-serializer/node_modules/domelementtype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ]
+    },
+    "node_modules/dom-serializer/node_modules/entities": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+      "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/domelementtype": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+      "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
+      "dev": true
+    },
+    "node_modules/domexception": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
+      "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "webidl-conversions": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/domexception/node_modules/webidl-conversions": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
+      "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/domhandler": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
+      "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
+      "dev": true,
+      "dependencies": {
+        "domelementtype": "1"
+      }
+    },
+    "node_modules/domutils": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
+      "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
+      "dev": true,
+      "dependencies": {
+        "dom-serializer": "0",
+        "domelementtype": "1"
+      }
+    },
+    "node_modules/eastasianwidth": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+      "dev": true
+    },
+    "node_modules/ejs": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.5.tgz",
+      "integrity": "sha512-dldq3ZfFtgVTJMLjOe+/3sROTzALlL9E34V4/sDtUd/KlBSS0s6U1/+WPE1B4sj9CXHJpL1M6rhNJnc9Wbal9w==",
+      "dev": true,
+      "dependencies": {
+        "jake": "^10.6.1"
+      },
+      "bin": {
+        "ejs": "bin/cli.js"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.4.332",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.332.tgz",
+      "integrity": "sha512-c1Vbv5tuUlBFp0mb3mCIjw+REEsgthRgNE8BlbEDKmvzb8rxjcVki6OkQP83vLN34s0XCxpSkq7AZNep1a6xhw==",
+      "dev": true
+    },
+    "node_modules/emittery": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz",
+      "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/emittery?sponsor=1"
+      }
+    },
+    "node_modules/emoji-regex": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+      "dev": true
+    },
+    "node_modules/end-of-stream": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "once": "^1.4.0"
+      }
+    },
+    "node_modules/enhanced-resolve": {
+      "version": "5.12.0",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz",
+      "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.2.4",
+        "tapable": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/enquirer": {
+      "version": "2.3.6",
+      "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
+      "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
+      "dev": true,
+      "dependencies": {
+        "ansi-colors": "^4.1.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/entities": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+      "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
+      "dev": true
+    },
+    "node_modules/error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dev": true,
+      "dependencies": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "node_modules/es-abstract": {
+      "version": "1.21.2",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz",
+      "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==",
+      "dev": true,
+      "dependencies": {
+        "array-buffer-byte-length": "^1.0.0",
+        "available-typed-arrays": "^1.0.5",
+        "call-bind": "^1.0.2",
+        "es-set-tostringtag": "^2.0.1",
+        "es-to-primitive": "^1.2.1",
+        "function.prototype.name": "^1.1.5",
+        "get-intrinsic": "^1.2.0",
+        "get-symbol-description": "^1.0.0",
+        "globalthis": "^1.0.3",
+        "gopd": "^1.0.1",
+        "has": "^1.0.3",
+        "has-property-descriptors": "^1.0.0",
+        "has-proto": "^1.0.1",
+        "has-symbols": "^1.0.3",
+        "internal-slot": "^1.0.5",
+        "is-array-buffer": "^3.0.2",
+        "is-callable": "^1.2.7",
+        "is-negative-zero": "^2.0.2",
+        "is-regex": "^1.1.4",
+        "is-shared-array-buffer": "^1.0.2",
+        "is-string": "^1.0.7",
+        "is-typed-array": "^1.1.10",
+        "is-weakref": "^1.0.2",
+        "object-inspect": "^1.12.3",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.4",
+        "regexp.prototype.flags": "^1.4.3",
+        "safe-regex-test": "^1.0.0",
+        "string.prototype.trim": "^1.2.7",
+        "string.prototype.trimend": "^1.0.6",
+        "string.prototype.trimstart": "^1.0.6",
+        "typed-array-length": "^1.0.4",
+        "unbox-primitive": "^1.0.2",
+        "which-typed-array": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/es-get-iterator": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
+      "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.3",
+        "has-symbols": "^1.0.3",
+        "is-arguments": "^1.1.1",
+        "is-map": "^2.0.2",
+        "is-set": "^2.0.2",
+        "is-string": "^1.0.7",
+        "isarray": "^2.0.5",
+        "stop-iteration-iterator": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/es-set-tostringtag": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
+      "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.1.3",
+        "has": "^1.0.3",
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-shim-unscopables": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
+      "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
+      "dev": true,
+      "dependencies": {
+        "has": "^1.0.3"
+      }
+    },
+    "node_modules/es-to-primitive": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+      "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+      "dev": true,
+      "dependencies": {
+        "is-callable": "^1.1.4",
+        "is-date-object": "^1.0.1",
+        "is-symbol": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/escodegen": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz",
+      "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "esprima": "^4.0.1",
+        "estraverse": "^5.2.0",
+        "esutils": "^2.0.2",
+        "optionator": "^0.8.1"
+      },
+      "bin": {
+        "escodegen": "bin/escodegen.js",
+        "esgenerate": "bin/esgenerate.js"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "optionalDependencies": {
+        "source-map": "~0.6.1"
+      }
+    },
+    "node_modules/escodegen/node_modules/levn": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+      "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/escodegen/node_modules/optionator": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+      "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "deep-is": "~0.1.3",
+        "fast-levenshtein": "~2.0.6",
+        "levn": "~0.3.0",
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2",
+        "word-wrap": "~1.2.3"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/escodegen/node_modules/prelude-ls": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+      "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/escodegen/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "optional": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/escodegen/node_modules/type-check": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+      "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "prelude-ls": "~1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/eslint": {
+      "version": "8.36.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz",
+      "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==",
+      "dev": true,
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.2.0",
+        "@eslint-community/regexpp": "^4.4.0",
+        "@eslint/eslintrc": "^2.0.1",
+        "@eslint/js": "8.36.0",
+        "@humanwhocodes/config-array": "^0.11.8",
+        "@humanwhocodes/module-importer": "^1.0.1",
+        "@nodelib/fs.walk": "^1.2.8",
+        "ajv": "^6.10.0",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.2",
+        "debug": "^4.3.2",
+        "doctrine": "^3.0.0",
+        "escape-string-regexp": "^4.0.0",
+        "eslint-scope": "^7.1.1",
+        "eslint-visitor-keys": "^3.3.0",
+        "espree": "^9.5.0",
+        "esquery": "^1.4.2",
+        "esutils": "^2.0.2",
+        "fast-deep-equal": "^3.1.3",
+        "file-entry-cache": "^6.0.1",
+        "find-up": "^5.0.0",
+        "glob-parent": "^6.0.2",
+        "globals": "^13.19.0",
+        "grapheme-splitter": "^1.0.4",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.0.0",
+        "imurmurhash": "^0.1.4",
+        "is-glob": "^4.0.0",
+        "is-path-inside": "^3.0.3",
+        "js-sdsl": "^4.1.4",
+        "js-yaml": "^4.1.0",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "levn": "^0.4.1",
+        "lodash.merge": "^4.6.2",
+        "minimatch": "^3.1.2",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.1",
+        "strip-ansi": "^6.0.1",
+        "strip-json-comments": "^3.1.0",
+        "text-table": "^0.2.0"
+      },
+      "bin": {
+        "eslint": "bin/eslint.js"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint-config-next": {
+      "version": "13.2.4",
+      "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.2.4.tgz",
+      "integrity": "sha512-lunIBhsoeqw6/Lfkd6zPt25w1bn0znLA/JCL+au1HoEpSb4/PpsOYsYtgV/q+YPsoKIOzFyU5xnb04iZnXjUvg==",
+      "dev": true,
+      "dependencies": {
+        "@next/eslint-plugin-next": "13.2.4",
+        "@rushstack/eslint-patch": "^1.1.3",
+        "@typescript-eslint/parser": "^5.42.0",
+        "eslint-import-resolver-node": "^0.3.6",
+        "eslint-import-resolver-typescript": "^3.5.2",
+        "eslint-plugin-import": "^2.26.0",
+        "eslint-plugin-jsx-a11y": "^6.5.1",
+        "eslint-plugin-react": "^7.31.7",
+        "eslint-plugin-react-hooks": "^4.5.0"
+      },
+      "peerDependencies": {
+        "eslint": "^7.23.0 || ^8.0.0",
+        "typescript": ">=3.3.1"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/eslint-config-prettier": {
+      "version": "8.7.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.7.0.tgz",
+      "integrity": "sha512-HHVXLSlVUhMSmyW4ZzEuvjpwqamgmlfkutD53cYXLikh4pt/modINRcCIApJ84czDxM4GZInwUrromsDdTImTA==",
+      "dev": true,
+      "bin": {
+        "eslint-config-prettier": "bin/cli.js"
+      },
+      "peerDependencies": {
+        "eslint": ">=7.0.0"
+      }
+    },
+    "node_modules/eslint-import-resolver-node": {
+      "version": "0.3.7",
+      "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz",
+      "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^3.2.7",
+        "is-core-module": "^2.11.0",
+        "resolve": "^1.22.1"
+      }
+    },
+    "node_modules/eslint-import-resolver-node/node_modules/debug": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/eslint-import-resolver-typescript": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.3.tgz",
+      "integrity": "sha512-njRcKYBc3isE42LaTcJNVANR3R99H9bAxBDMNDr2W7yq5gYPxbU3MkdhsQukxZ/Xg9C2vcyLlDsbKfRDg0QvCQ==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^4.3.4",
+        "enhanced-resolve": "^5.10.0",
+        "get-tsconfig": "^4.2.0",
+        "globby": "^13.1.2",
+        "is-core-module": "^2.10.0",
+        "is-glob": "^4.0.3",
+        "synckit": "^0.8.4"
+      },
+      "engines": {
+        "node": "^14.18.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts"
+      },
+      "peerDependencies": {
+        "eslint": "*",
+        "eslint-plugin-import": "*"
+      }
+    },
+    "node_modules/eslint-module-utils": {
+      "version": "2.7.4",
+      "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz",
+      "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^3.2.7"
+      },
+      "engines": {
+        "node": ">=4"
+      },
+      "peerDependenciesMeta": {
+        "eslint": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/eslint-module-utils/node_modules/debug": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/eslint-plugin-import": {
+      "version": "2.27.5",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz",
+      "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==",
+      "dev": true,
+      "dependencies": {
+        "array-includes": "^3.1.6",
+        "array.prototype.flat": "^1.3.1",
+        "array.prototype.flatmap": "^1.3.1",
+        "debug": "^3.2.7",
+        "doctrine": "^2.1.0",
+        "eslint-import-resolver-node": "^0.3.7",
+        "eslint-module-utils": "^2.7.4",
+        "has": "^1.0.3",
+        "is-core-module": "^2.11.0",
+        "is-glob": "^4.0.3",
+        "minimatch": "^3.1.2",
+        "object.values": "^1.1.6",
+        "resolve": "^1.22.1",
+        "semver": "^6.3.0",
+        "tsconfig-paths": "^3.14.1"
+      },
+      "engines": {
+        "node": ">=4"
+      },
+      "peerDependencies": {
+        "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
+      }
+    },
+    "node_modules/eslint-plugin-import/node_modules/debug": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/eslint-plugin-import/node_modules/doctrine": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+      "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+      "dev": true,
+      "dependencies": {
+        "esutils": "^2.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/eslint-plugin-import/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/eslint-plugin-jsx-a11y": {
+      "version": "6.7.1",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz",
+      "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/runtime": "^7.20.7",
+        "aria-query": "^5.1.3",
+        "array-includes": "^3.1.6",
+        "array.prototype.flatmap": "^1.3.1",
+        "ast-types-flow": "^0.0.7",
+        "axe-core": "^4.6.2",
+        "axobject-query": "^3.1.1",
+        "damerau-levenshtein": "^1.0.8",
+        "emoji-regex": "^9.2.2",
+        "has": "^1.0.3",
+        "jsx-ast-utils": "^3.3.3",
+        "language-tags": "=1.0.5",
+        "minimatch": "^3.1.2",
+        "object.entries": "^1.1.6",
+        "object.fromentries": "^2.0.6",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependencies": {
+        "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
+      }
+    },
+    "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/eslint-plugin-prettier": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
+      "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
+      "dev": true,
+      "dependencies": {
+        "prettier-linter-helpers": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "peerDependencies": {
+        "eslint": ">=7.28.0",
+        "prettier": ">=2.0.0"
+      },
+      "peerDependenciesMeta": {
+        "eslint-config-prettier": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/eslint-plugin-react": {
+      "version": "7.32.2",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz",
+      "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==",
+      "dev": true,
+      "dependencies": {
+        "array-includes": "^3.1.6",
+        "array.prototype.flatmap": "^1.3.1",
+        "array.prototype.tosorted": "^1.1.1",
+        "doctrine": "^2.1.0",
+        "estraverse": "^5.3.0",
+        "jsx-ast-utils": "^2.4.1 || ^3.0.0",
+        "minimatch": "^3.1.2",
+        "object.entries": "^1.1.6",
+        "object.fromentries": "^2.0.6",
+        "object.hasown": "^1.1.2",
+        "object.values": "^1.1.6",
+        "prop-types": "^15.8.1",
+        "resolve": "^2.0.0-next.4",
+        "semver": "^6.3.0",
+        "string.prototype.matchall": "^4.0.8"
+      },
+      "engines": {
+        "node": ">=4"
+      },
+      "peerDependencies": {
+        "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
+      }
+    },
+    "node_modules/eslint-plugin-react-hooks": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
+      "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
+      }
+    },
+    "node_modules/eslint-plugin-react/node_modules/doctrine": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+      "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+      "dev": true,
+      "dependencies": {
+        "esutils": "^2.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/eslint-plugin-react/node_modules/resolve": {
+      "version": "2.0.0-next.4",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz",
+      "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==",
+      "dev": true,
+      "dependencies": {
+        "is-core-module": "^2.9.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/eslint-plugin-react/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/eslint-scope": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+      "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+      "dev": true,
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^4.1.1"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/eslint-scope/node_modules/estraverse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/eslint-visitor-keys": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+      "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+      "dev": true,
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/eslint/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/eslint/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/eslint/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/eslint/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/eslint/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/eslint/node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/eslint-scope": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+      "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+      "dev": true,
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/eslint/node_modules/find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+      "dev": true,
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/eslint/node_modules/globals": {
+      "version": "13.20.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
+      "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+      "dev": true,
+      "dependencies": {
+        "type-fest": "^0.20.2"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/eslint/node_modules/locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "dev": true,
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/eslint/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/eslint/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/eslint/node_modules/type-fest": {
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/espree": {
+      "version": "9.5.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz",
+      "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==",
+      "dev": true,
+      "dependencies": {
+        "acorn": "^8.8.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^3.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true,
+      "peer": true,
+      "bin": {
+        "esparse": "bin/esparse.js",
+        "esvalidate": "bin/esvalidate.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/esquery": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
+      "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
+      "dev": true,
+      "dependencies": {
+        "estraverse": "^5.1.0"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/esrecurse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+      "dev": true,
+      "dependencies": {
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/exec-sh": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz",
+      "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/execa": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
+      "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "cross-spawn": "^7.0.0",
+        "get-stream": "^5.0.0",
+        "human-signals": "^1.1.1",
+        "is-stream": "^2.0.0",
+        "merge-stream": "^2.0.0",
+        "npm-run-path": "^4.0.0",
+        "onetime": "^5.1.0",
+        "signal-exit": "^3.0.2",
+        "strip-final-newline": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/execa?sponsor=1"
+      }
+    },
+    "node_modules/execall": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz",
+      "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==",
+      "dev": true,
+      "dependencies": {
+        "clone-regexp": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/exit": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+      "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/expand-brackets": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+      "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "debug": "^2.3.3",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "posix-character-classes": "^0.1.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/expand-brackets/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/expand-brackets/node_modules/define-property": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+      "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/expand-brackets/node_modules/extend-shallow": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+      "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extendable": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/expand-brackets/node_modules/is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/expand-brackets/node_modules/is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/expand-brackets/node_modules/is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/expand-brackets/node_modules/is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/expand-brackets/node_modules/is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/expand-brackets/node_modules/kind-of": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+      "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/expand-brackets/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/expect": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz",
+      "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/types": "^26.6.2",
+        "ansi-styles": "^4.0.0",
+        "jest-get-type": "^26.3.0",
+        "jest-matcher-utils": "^26.6.2",
+        "jest-message-util": "^26.6.2",
+        "jest-regex-util": "^26.0.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/expect/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/expect/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/expect/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+      "dev": true
+    },
+    "node_modules/extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/external-editor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+      "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+      "dev": true,
+      "dependencies": {
+        "chardet": "^0.7.0",
+        "iconv-lite": "^0.4.24",
+        "tmp": "^0.0.33"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/extglob": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "array-unique": "^0.3.2",
+        "define-property": "^1.0.0",
+        "expand-brackets": "^2.1.4",
+        "extend-shallow": "^2.0.1",
+        "fragment-cache": "^0.2.1",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/extglob/node_modules/define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+      "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/extglob/node_modules/extend-shallow": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+      "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extendable": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/extglob/node_modules/is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/extract-files": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-9.0.0.tgz",
+      "integrity": "sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ==",
+      "dev": true,
+      "engines": {
+        "node": "^10.17.0 || ^12.0.0 || >= 13.7.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jaydenseric"
+      }
+    },
+    "node_modules/fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "dev": true
+    },
+    "node_modules/fast-diff": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
+      "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
+      "dev": true
+    },
+    "node_modules/fast-glob": {
+      "version": "3.2.12",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
+      "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.4"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+      "dev": true
+    },
+    "node_modules/fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+      "dev": true
+    },
+    "node_modules/fastest-levenshtein": {
+      "version": "1.0.16",
+      "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
+      "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4.9.1"
+      }
+    },
+    "node_modules/fastq": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+      "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+      "dev": true,
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "node_modules/fb-watchman": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
+      "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "bser": "2.1.1"
+      }
+    },
+    "node_modules/figures": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+      "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+      "dev": true,
+      "dependencies": {
+        "escape-string-regexp": "^1.0.5"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/file-entry-cache": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+      "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+      "dev": true,
+      "dependencies": {
+        "flat-cache": "^3.0.4"
+      },
+      "engines": {
+        "node": "^10.12.0 || >=12.0.0"
+      }
+    },
+    "node_modules/filelist": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
+      "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
+      "dev": true,
+      "dependencies": {
+        "minimatch": "^5.0.1"
+      }
+    },
+    "node_modules/filelist/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/filelist/node_modules/minimatch": {
+      "version": "5.1.6",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+      "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "dev": true,
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/find-up": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz",
+      "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^7.1.0",
+        "path-exists": "^5.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/flat": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+      "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+      "dev": true,
+      "bin": {
+        "flat": "cli.js"
+      }
+    },
+    "node_modules/flat-cache": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+      "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+      "dev": true,
+      "dependencies": {
+        "flatted": "^3.1.0",
+        "rimraf": "^3.0.2"
+      },
+      "engines": {
+        "node": "^10.12.0 || >=12.0.0"
+      }
+    },
+    "node_modules/flatted": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+      "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+      "dev": true
+    },
+    "node_modules/for-each": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+      "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+      "dev": true,
+      "dependencies": {
+        "is-callable": "^1.1.3"
+      }
+    },
+    "node_modules/for-in": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+      "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/form-data": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
+      "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
+      "dev": true,
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/fragment-cache": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+      "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "map-cache": "^0.2.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/fs-extra": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
+      "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
+      "dev": true,
+      "dependencies": {
+        "at-least-node": "^1.0.0",
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^6.0.1",
+        "universalify": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+      "dev": true
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "dev": true
+    },
+    "node_modules/function.prototype.name": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
+      "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.19.0",
+        "functions-have-names": "^1.2.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/functions-have-names": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/gensync": {
+      "version": "1.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true,
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/get-intrinsic": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
+      "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
+      "dev": true,
+      "dependencies": {
+        "function-bind": "^1.1.1",
+        "has": "^1.0.3",
+        "has-symbols": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-own-enumerable-property-symbols": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz",
+      "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==",
+      "dev": true
+    },
+    "node_modules/get-package-type": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+      "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/get-stdin": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz",
+      "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/get-stream": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+      "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "pump": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/get-symbol-description": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
+      "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-tsconfig": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.4.0.tgz",
+      "integrity": "sha512-0Gdjo/9+FzsYhXCEFueo2aY1z1tpXrxWZzP7k8ul9qt1U5o8rYJwTJYmaeHdrVosYIVYkOy2iwCJ9FdpocJhPQ==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+      }
+    },
+    "node_modules/get-value": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+      "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/glob": {
+      "version": "7.1.7",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
+      "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/global-modules": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
+      "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==",
+      "dev": true,
+      "dependencies": {
+        "global-prefix": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/global-prefix": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz",
+      "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==",
+      "dev": true,
+      "dependencies": {
+        "ini": "^1.3.5",
+        "kind-of": "^6.0.2",
+        "which": "^1.3.1"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/global-prefix/node_modules/which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "which": "bin/which"
+      }
+    },
+    "node_modules/globals": {
+      "version": "11.12.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/globalthis": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
+      "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
+      "dev": true,
+      "dependencies": {
+        "define-properties": "^1.1.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/globalyzer": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
+      "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==",
+      "dev": true
+    },
+    "node_modules/globby": {
+      "version": "13.1.3",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz",
+      "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==",
+      "dev": true,
+      "dependencies": {
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.2.11",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^4.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/globjoin": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz",
+      "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==",
+      "dev": true
+    },
+    "node_modules/globrex": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
+      "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
+      "dev": true
+    },
+    "node_modules/gonzales-pe": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz",
+      "integrity": "sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==",
+      "dev": true,
+      "dependencies": {
+        "minimist": "^1.2.5"
+      },
+      "bin": {
+        "gonzales": "bin/gonzales.js"
+      },
+      "engines": {
+        "node": ">=0.6.0"
+      }
+    },
+    "node_modules/gopd": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+      "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.1.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.10",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
+      "dev": true
+    },
+    "node_modules/grapheme-splitter": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+      "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+      "dev": true
+    },
+    "node_modules/graphql": {
+      "version": "15.8.0",
+      "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.8.0.tgz",
+      "integrity": "sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 10.x"
+      }
+    },
+    "node_modules/graphql-request": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-3.7.0.tgz",
+      "integrity": "sha512-dw5PxHCgBneN2DDNqpWu8QkbbJ07oOziy8z+bK/TAXufsOLaETuVO4GkXrbs0WjhdKhBMN3BkpN/RIvUHkmNUQ==",
+      "dev": true,
+      "dependencies": {
+        "cross-fetch": "^3.0.6",
+        "extract-files": "^9.0.0",
+        "form-data": "^3.0.0"
+      },
+      "peerDependencies": {
+        "graphql": "14 - 16"
+      }
+    },
+    "node_modules/growly": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
+      "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==",
+      "dev": true,
+      "optional": true,
+      "peer": true
+    },
+    "node_modules/hard-rejection": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz",
+      "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dev": true,
+      "dependencies": {
+        "function-bind": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/has-bigints": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
+      "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/has-property-descriptors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
+      "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.1.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
+      "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-tostringtag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
+      "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
+      "dev": true,
+      "dependencies": {
+        "has-symbols": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+      "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "get-value": "^2.0.6",
+        "has-values": "^1.0.0",
+        "isobject": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/has-values": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+      "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-number": "^3.0.0",
+        "kind-of": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/has-values/node_modules/is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/has-values/node_modules/is-number": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+      "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/has-values/node_modules/is-number/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/has-values/node_modules/kind-of": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+      "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/hosted-git-info": {
+      "version": "2.8.9",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+      "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+      "dev": true
+    },
+    "node_modules/html-encoding-sniffer": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
+      "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "whatwg-encoding": "^1.0.5"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/html-escaper": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+      "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/html-tags": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz",
+      "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/htmlparser2": {
+      "version": "3.10.1",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
+      "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
+      "dev": true,
+      "dependencies": {
+        "domelementtype": "^1.3.1",
+        "domhandler": "^2.3.0",
+        "domutils": "^1.5.1",
+        "entities": "^1.1.1",
+        "inherits": "^2.0.1",
+        "readable-stream": "^3.1.1"
+      }
+    },
+    "node_modules/http-proxy-agent": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
+      "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@tootallnate/once": "1",
+        "agent-base": "6",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/https-proxy-agent": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "agent-base": "6",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/human-signals": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
+      "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8.12.0"
+      }
+    },
+    "node_modules/iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "dev": true,
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/ignore": {
+      "version": "5.2.4",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+      "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+      "dev": true,
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/import-lazy": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz",
+      "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/import-local": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
+      "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "pkg-dir": "^4.2.0",
+        "resolve-cwd": "^3.0.0"
+      },
+      "bin": {
+        "import-local-fixture": "fixtures/cli.js"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.19"
+      }
+    },
+    "node_modules/indent-string": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+      "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "dev": true,
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "dev": true
+    },
+    "node_modules/ini": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+      "dev": true
+    },
+    "node_modules/inquirer": {
+      "version": "7.3.3",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz",
+      "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.1.0",
+        "cli-cursor": "^3.1.0",
+        "cli-width": "^3.0.0",
+        "external-editor": "^3.0.3",
+        "figures": "^3.0.0",
+        "lodash": "^4.17.19",
+        "mute-stream": "0.0.8",
+        "run-async": "^2.4.0",
+        "rxjs": "^6.6.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0",
+        "through": "^2.3.6"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/inquirer/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/inquirer/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/inquirer/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/inquirer/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/inquirer/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/inquirer/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true
+    },
+    "node_modules/inquirer/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/inquirer/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/inquirer/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/inquirer/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/internal-slot": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz",
+      "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.2.0",
+        "has": "^1.0.3",
+        "side-channel": "^1.0.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/ip-regex": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz",
+      "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-accessor-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+      "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-alphabetical": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
+      "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/is-alphanumeric": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz",
+      "integrity": "sha512-ZmRL7++ZkcMOfDuWZuMJyIVLr2keE1o/DeNWh1EmgqGhUcV+9BIVsx0BcSBOHTZqzjs4+dISzr2KAeBEWGgXeA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-alphanumerical": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
+      "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
+      "dev": true,
+      "dependencies": {
+        "is-alphabetical": "^1.0.0",
+        "is-decimal": "^1.0.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/is-arguments": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
+      "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-array-buffer": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
+      "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.2.0",
+        "is-typed-array": "^1.1.10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+      "dev": true
+    },
+    "node_modules/is-bigint": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
+      "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
+      "dev": true,
+      "dependencies": {
+        "has-bigints": "^1.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-boolean-object": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
+      "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-buffer": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
+      "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/is-callable": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+      "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-ci": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+      "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+      "dev": true,
+      "dependencies": {
+        "ci-info": "^2.0.0"
+      },
+      "bin": {
+        "is-ci": "bin.js"
+      }
+    },
+    "node_modules/is-core-module": {
+      "version": "2.11.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
+      "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
+      "dev": true,
+      "dependencies": {
+        "has": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-data-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+      "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-date-object": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
+      "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
+      "dev": true,
+      "dependencies": {
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-decimal": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
+      "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/is-descriptor": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+      "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^1.0.0",
+        "is-data-descriptor": "^1.0.0",
+        "kind-of": "^6.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-docker": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+      "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+      "dev": true,
+      "bin": {
+        "is-docker": "cli.js"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-extendable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+      "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.4"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-generator-fn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
+      "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dev": true,
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-hexadecimal": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
+      "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/is-map": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
+      "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-negative-zero": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
+      "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-number-object": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
+      "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
+      "dev": true,
+      "dependencies": {
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-obj": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
+      "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-path-inside": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+      "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-plain-obj": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+      "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-potential-custom-element-name": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
+      "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/is-regex": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
+      "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-regexp": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
+      "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-set": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
+      "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-shared-array-buffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
+      "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-stream": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-string": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
+      "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
+      "dev": true,
+      "dependencies": {
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-symbol": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
+      "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
+      "dev": true,
+      "dependencies": {
+        "has-symbols": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-typed-array": {
+      "version": "1.1.10",
+      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz",
+      "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==",
+      "dev": true,
+      "dependencies": {
+        "available-typed-arrays": "^1.0.5",
+        "call-bind": "^1.0.2",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
+      "dev": true
+    },
+    "node_modules/is-unicode-supported": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-url-superb": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-url-superb/-/is-url-superb-3.0.0.tgz",
+      "integrity": "sha512-3faQP+wHCGDQT1qReM5zCPx2mxoal6DzbzquFlCYJLWyy4WPTved33ea2xFbX37z4NoriEwZGIYhFtx8RUB5wQ==",
+      "dev": true,
+      "dependencies": {
+        "url-regex": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-weakmap": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
+      "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-weakref": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
+      "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-weakset": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz",
+      "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-whitespace-character": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz",
+      "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/is-windows": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-word-character": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz",
+      "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/is-wsl": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+      "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+      "dev": true,
+      "dependencies": {
+        "is-docker": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/isarray": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+      "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+      "dev": true
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true
+    },
+    "node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/istanbul-lib-coverage": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
+      "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-instrument": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
+      "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/core": "^7.7.5",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-coverage": "^3.0.0",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-instrument/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "peer": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/istanbul-lib-report": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+      "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "istanbul-lib-coverage": "^3.0.0",
+        "make-dir": "^3.0.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-report/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-report/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-source-maps": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
+      "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "debug": "^4.1.1",
+        "istanbul-lib-coverage": "^3.0.0",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/istanbul-lib-source-maps/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/istanbul-reports": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
+      "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "html-escaper": "^2.0.0",
+        "istanbul-lib-report": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jake": {
+      "version": "10.8.5",
+      "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz",
+      "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==",
+      "dev": true,
+      "dependencies": {
+        "async": "^3.2.3",
+        "chalk": "^4.0.2",
+        "filelist": "^1.0.1",
+        "minimatch": "^3.0.4"
+      },
+      "bin": {
+        "jake": "bin/cli.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/jake/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/jake/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jake/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jake/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/jake/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jake/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz",
+      "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/core": "^26.6.3",
+        "import-local": "^3.0.2",
+        "jest-cli": "^26.6.3"
+      },
+      "bin": {
+        "jest": "bin/jest.js"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-changed-files": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz",
+      "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/types": "^26.6.2",
+        "execa": "^4.0.0",
+        "throat": "^5.0.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-cli": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz",
+      "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/core": "^26.6.3",
+        "@jest/test-result": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "chalk": "^4.0.0",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.2.4",
+        "import-local": "^3.0.2",
+        "is-ci": "^2.0.0",
+        "jest-config": "^26.6.3",
+        "jest-util": "^26.6.2",
+        "jest-validate": "^26.6.2",
+        "prompts": "^2.0.1",
+        "yargs": "^15.4.1"
+      },
+      "bin": {
+        "jest": "bin/jest.js"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-cli/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-cli/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/jest-cli/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jest-cli/node_modules/cliui": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+      "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^6.2.0"
+      }
+    },
+    "node_modules/jest-cli/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jest-cli/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-cli/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-cli/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-cli/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-cli/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-cli/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/jest-cli/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-cli/node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-cli/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-cli/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-cli/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-cli/node_modules/wrap-ansi": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-cli/node_modules/y18n": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+      "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-cli/node_modules/yargs": {
+      "version": "15.4.1",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+      "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "cliui": "^6.0.0",
+        "decamelize": "^1.2.0",
+        "find-up": "^4.1.0",
+        "get-caller-file": "^2.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^2.0.0",
+        "set-blocking": "^2.0.0",
+        "string-width": "^4.2.0",
+        "which-module": "^2.0.0",
+        "y18n": "^4.0.0",
+        "yargs-parser": "^18.1.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-cli/node_modules/yargs-parser": {
+      "version": "18.1.3",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+      "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "camelcase": "^5.0.0",
+        "decamelize": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/jest-config": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz",
+      "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/core": "^7.1.0",
+        "@jest/test-sequencer": "^26.6.3",
+        "@jest/types": "^26.6.2",
+        "babel-jest": "^26.6.3",
+        "chalk": "^4.0.0",
+        "deepmerge": "^4.2.2",
+        "glob": "^7.1.1",
+        "graceful-fs": "^4.2.4",
+        "jest-environment-jsdom": "^26.6.2",
+        "jest-environment-node": "^26.6.2",
+        "jest-get-type": "^26.3.0",
+        "jest-jasmine2": "^26.6.3",
+        "jest-regex-util": "^26.0.0",
+        "jest-resolve": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "jest-validate": "^26.6.2",
+        "micromatch": "^4.0.2",
+        "pretty-format": "^26.6.2"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      },
+      "peerDependencies": {
+        "ts-node": ">=9.0.0"
+      },
+      "peerDependenciesMeta": {
+        "ts-node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/jest-config/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/jest-config/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jest-config/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jest-config/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-config/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-config/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-diff": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz",
+      "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "chalk": "^4.0.0",
+        "diff-sequences": "^26.6.2",
+        "jest-get-type": "^26.3.0",
+        "pretty-format": "^26.6.2"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-diff/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/jest-diff/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jest-diff/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jest-diff/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-diff/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-diff/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-docblock": {
+      "version": "26.0.0",
+      "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz",
+      "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "detect-newline": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-each": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz",
+      "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/types": "^26.6.2",
+        "chalk": "^4.0.0",
+        "jest-get-type": "^26.3.0",
+        "jest-util": "^26.6.2",
+        "pretty-format": "^26.6.2"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-each/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/jest-each/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jest-each/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jest-each/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-each/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-each/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-environment-jsdom": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz",
+      "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/environment": "^26.6.2",
+        "@jest/fake-timers": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "jest-mock": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "jsdom": "^16.4.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-environment-node": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz",
+      "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/environment": "^26.6.2",
+        "@jest/fake-timers": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "jest-mock": "^26.6.2",
+        "jest-util": "^26.6.2"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-get-type": {
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz",
+      "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-haste-map": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz",
+      "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/types": "^26.6.2",
+        "@types/graceful-fs": "^4.1.2",
+        "@types/node": "*",
+        "anymatch": "^3.0.3",
+        "fb-watchman": "^2.0.0",
+        "graceful-fs": "^4.2.4",
+        "jest-regex-util": "^26.0.0",
+        "jest-serializer": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "jest-worker": "^26.6.2",
+        "micromatch": "^4.0.2",
+        "sane": "^4.0.3",
+        "walker": "^1.0.7"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      },
+      "optionalDependencies": {
+        "fsevents": "^2.1.2"
+      }
+    },
+    "node_modules/jest-jasmine2": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz",
+      "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/traverse": "^7.1.0",
+        "@jest/environment": "^26.6.2",
+        "@jest/source-map": "^26.6.2",
+        "@jest/test-result": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "co": "^4.6.0",
+        "expect": "^26.6.2",
+        "is-generator-fn": "^2.0.0",
+        "jest-each": "^26.6.2",
+        "jest-matcher-utils": "^26.6.2",
+        "jest-message-util": "^26.6.2",
+        "jest-runtime": "^26.6.3",
+        "jest-snapshot": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "pretty-format": "^26.6.2",
+        "throat": "^5.0.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-jasmine2/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/jest-jasmine2/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jest-jasmine2/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jest-jasmine2/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-jasmine2/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-jasmine2/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-leak-detector": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz",
+      "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "jest-get-type": "^26.3.0",
+        "pretty-format": "^26.6.2"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-matcher-utils": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz",
+      "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "chalk": "^4.0.0",
+        "jest-diff": "^26.6.2",
+        "jest-get-type": "^26.3.0",
+        "pretty-format": "^26.6.2"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-matcher-utils/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/jest-matcher-utils/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jest-matcher-utils/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jest-matcher-utils/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-matcher-utils/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-matcher-utils/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-message-util": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz",
+      "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.0.0",
+        "@jest/types": "^26.6.2",
+        "@types/stack-utils": "^2.0.0",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.4",
+        "micromatch": "^4.0.2",
+        "pretty-format": "^26.6.2",
+        "slash": "^3.0.0",
+        "stack-utils": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-message-util/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/jest-message-util/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jest-message-util/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jest-message-util/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-message-util/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-message-util/node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-message-util/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-mock": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz",
+      "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/types": "^26.6.2",
+        "@types/node": "*"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-pnp-resolver": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
+      "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=6"
+      },
+      "peerDependencies": {
+        "jest-resolve": "*"
+      },
+      "peerDependenciesMeta": {
+        "jest-resolve": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/jest-regex-util": {
+      "version": "26.0.0",
+      "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz",
+      "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-resolve": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz",
+      "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/types": "^26.6.2",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.4",
+        "jest-pnp-resolver": "^1.2.2",
+        "jest-util": "^26.6.2",
+        "read-pkg-up": "^7.0.1",
+        "resolve": "^1.18.1",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-resolve-dependencies": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz",
+      "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/types": "^26.6.2",
+        "jest-regex-util": "^26.0.0",
+        "jest-snapshot": "^26.6.2"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-resolve/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/jest-resolve/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jest-resolve/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jest-resolve/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-resolve/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-resolve/node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-resolve/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-runner": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz",
+      "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/console": "^26.6.2",
+        "@jest/environment": "^26.6.2",
+        "@jest/test-result": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "emittery": "^0.7.1",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.2.4",
+        "jest-config": "^26.6.3",
+        "jest-docblock": "^26.0.0",
+        "jest-haste-map": "^26.6.2",
+        "jest-leak-detector": "^26.6.2",
+        "jest-message-util": "^26.6.2",
+        "jest-resolve": "^26.6.2",
+        "jest-runtime": "^26.6.3",
+        "jest-util": "^26.6.2",
+        "jest-worker": "^26.6.2",
+        "source-map-support": "^0.5.6",
+        "throat": "^5.0.0"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-runner/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/jest-runner/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jest-runner/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jest-runner/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-runner/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-runner/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-runtime": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz",
+      "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/console": "^26.6.2",
+        "@jest/environment": "^26.6.2",
+        "@jest/fake-timers": "^26.6.2",
+        "@jest/globals": "^26.6.2",
+        "@jest/source-map": "^26.6.2",
+        "@jest/test-result": "^26.6.2",
+        "@jest/transform": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/yargs": "^15.0.0",
+        "chalk": "^4.0.0",
+        "cjs-module-lexer": "^0.6.0",
+        "collect-v8-coverage": "^1.0.0",
+        "exit": "^0.1.2",
+        "glob": "^7.1.3",
+        "graceful-fs": "^4.2.4",
+        "jest-config": "^26.6.3",
+        "jest-haste-map": "^26.6.2",
+        "jest-message-util": "^26.6.2",
+        "jest-mock": "^26.6.2",
+        "jest-regex-util": "^26.0.0",
+        "jest-resolve": "^26.6.2",
+        "jest-snapshot": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "jest-validate": "^26.6.2",
+        "slash": "^3.0.0",
+        "strip-bom": "^4.0.0",
+        "yargs": "^15.4.1"
+      },
+      "bin": {
+        "jest-runtime": "bin/jest-runtime.js"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/cliui": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+      "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^6.2.0"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-runtime/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-runtime/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/wrap-ansi": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/y18n": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+      "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-runtime/node_modules/yargs": {
+      "version": "15.4.1",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+      "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "cliui": "^6.0.0",
+        "decamelize": "^1.2.0",
+        "find-up": "^4.1.0",
+        "get-caller-file": "^2.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^2.0.0",
+        "set-blocking": "^2.0.0",
+        "string-width": "^4.2.0",
+        "which-module": "^2.0.0",
+        "y18n": "^4.0.0",
+        "yargs-parser": "^18.1.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-runtime/node_modules/yargs-parser": {
+      "version": "18.1.3",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+      "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "camelcase": "^5.0.0",
+        "decamelize": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/jest-serializer": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz",
+      "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@types/node": "*",
+        "graceful-fs": "^4.2.4"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-snapshot": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz",
+      "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/types": "^7.0.0",
+        "@jest/types": "^26.6.2",
+        "@types/babel__traverse": "^7.0.4",
+        "@types/prettier": "^2.0.0",
+        "chalk": "^4.0.0",
+        "expect": "^26.6.2",
+        "graceful-fs": "^4.2.4",
+        "jest-diff": "^26.6.2",
+        "jest-get-type": "^26.3.0",
+        "jest-haste-map": "^26.6.2",
+        "jest-matcher-utils": "^26.6.2",
+        "jest-message-util": "^26.6.2",
+        "jest-resolve": "^26.6.2",
+        "natural-compare": "^1.4.0",
+        "pretty-format": "^26.6.2",
+        "semver": "^7.3.2"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-snapshot/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/jest-snapshot/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jest-snapshot/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jest-snapshot/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-snapshot/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-snapshot/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/jest-snapshot/node_modules/semver": {
+      "version": "7.3.8",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/jest-snapshot/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-snapshot/node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-util": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz",
+      "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==",
+      "dev": true,
+      "dependencies": {
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.4",
+        "is-ci": "^2.0.0",
+        "micromatch": "^4.0.2"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-util/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/jest-util/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jest-util/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jest-util/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/jest-util/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-util/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-validate": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz",
+      "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/types": "^26.6.2",
+        "camelcase": "^6.0.0",
+        "chalk": "^4.0.0",
+        "jest-get-type": "^26.3.0",
+        "leven": "^3.1.0",
+        "pretty-format": "^26.6.2"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-validate/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/jest-validate/node_modules/camelcase": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+      "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/jest-validate/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jest-validate/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jest-validate/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-validate/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-validate/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-watcher": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz",
+      "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/test-result": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.0.0",
+        "jest-util": "^26.6.2",
+        "string-length": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 10.14.2"
+      }
+    },
+    "node_modules/jest-watcher/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/jest-watcher/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jest-watcher/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jest-watcher/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/jest-watcher/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-watcher/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-worker": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
+      "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@types/node": "*",
+        "merge-stream": "^2.0.0",
+        "supports-color": "^7.0.0"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      }
+    },
+    "node_modules/jest-worker/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-worker/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/js-sdsl": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
+      "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
+      "dev": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/js-sdsl"
+      }
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true
+    },
+    "node_modules/js-yaml": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/jsdom": {
+      "version": "16.7.0",
+      "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz",
+      "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "abab": "^2.0.5",
+        "acorn": "^8.2.4",
+        "acorn-globals": "^6.0.0",
+        "cssom": "^0.4.4",
+        "cssstyle": "^2.3.0",
+        "data-urls": "^2.0.0",
+        "decimal.js": "^10.2.1",
+        "domexception": "^2.0.1",
+        "escodegen": "^2.0.0",
+        "form-data": "^3.0.0",
+        "html-encoding-sniffer": "^2.0.1",
+        "http-proxy-agent": "^4.0.1",
+        "https-proxy-agent": "^5.0.0",
+        "is-potential-custom-element-name": "^1.0.1",
+        "nwsapi": "^2.2.0",
+        "parse5": "6.0.1",
+        "saxes": "^5.0.1",
+        "symbol-tree": "^3.2.4",
+        "tough-cookie": "^4.0.0",
+        "w3c-hr-time": "^1.0.2",
+        "w3c-xmlserializer": "^2.0.0",
+        "webidl-conversions": "^6.1.0",
+        "whatwg-encoding": "^1.0.5",
+        "whatwg-mimetype": "^2.3.0",
+        "whatwg-url": "^8.5.0",
+        "ws": "^7.4.6",
+        "xml-name-validator": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "canvas": "^2.5.0"
+      },
+      "peerDependenciesMeta": {
+        "canvas": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/jsesc": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+      "dev": true,
+      "bin": {
+        "jsesc": "bin/jsesc"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/json-parse-better-errors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+      "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+      "dev": true
+    },
+    "node_modules/json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+      "dev": true
+    },
+    "node_modules/json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true
+    },
+    "node_modules/json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+      "dev": true
+    },
+    "node_modules/json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "dev": true,
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/jsonfile": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+      "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+      "dev": true,
+      "dependencies": {
+        "universalify": "^2.0.0"
+      },
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/jsonfile/node_modules/universalify": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+      "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      }
+    },
+    "node_modules/jsx-ast-utils": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz",
+      "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==",
+      "dev": true,
+      "dependencies": {
+        "array-includes": "^3.1.5",
+        "object.assign": "^4.1.3"
+      },
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/kleur": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
+      "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/known-css-properties": {
+      "version": "0.20.0",
+      "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.20.0.tgz",
+      "integrity": "sha512-URvsjaA9ypfreqJ2/ylDr5MUERhJZ+DhguoWRr2xgS5C7aGCalXo+ewL+GixgKBfhT2vuL02nbIgNGqVWgTOYw==",
+      "dev": true
+    },
+    "node_modules/language-subtag-registry": {
+      "version": "0.3.22",
+      "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
+      "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==",
+      "dev": true
+    },
+    "node_modules/language-tags": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz",
+      "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==",
+      "dev": true,
+      "dependencies": {
+        "language-subtag-registry": "~0.3.2"
+      }
+    },
+    "node_modules/leven": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+      "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/levn": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+      "dev": true,
+      "dependencies": {
+        "prelude-ls": "^1.2.1",
+        "type-check": "~0.4.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+      "dev": true
+    },
+    "node_modules/lint-staged": {
+      "version": "11.1.2",
+      "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-11.1.2.tgz",
+      "integrity": "sha512-6lYpNoA9wGqkL6Hew/4n1H6lRqF3qCsujVT0Oq5Z4hiSAM7S6NksPJ3gnr7A7R52xCtiZMcEUNNQ6d6X5Bvh9w==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^4.1.1",
+        "cli-truncate": "^2.1.0",
+        "commander": "^7.2.0",
+        "cosmiconfig": "^7.0.0",
+        "debug": "^4.3.1",
+        "enquirer": "^2.3.6",
+        "execa": "^5.0.0",
+        "listr2": "^3.8.2",
+        "log-symbols": "^4.1.0",
+        "micromatch": "^4.0.4",
+        "normalize-path": "^3.0.0",
+        "please-upgrade-node": "^3.2.0",
+        "string-argv": "0.3.1",
+        "stringify-object": "^3.3.0"
+      },
+      "bin": {
+        "lint-staged": "bin/lint-staged.js"
+      },
+      "funding": {
+        "url": "https://opencollective.com/lint-staged"
+      }
+    },
+    "node_modules/lint-staged/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/lint-staged/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/lint-staged/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/lint-staged/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/lint-staged/node_modules/execa": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+      "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+      "dev": true,
+      "dependencies": {
+        "cross-spawn": "^7.0.3",
+        "get-stream": "^6.0.0",
+        "human-signals": "^2.1.0",
+        "is-stream": "^2.0.0",
+        "merge-stream": "^2.0.0",
+        "npm-run-path": "^4.0.1",
+        "onetime": "^5.1.2",
+        "signal-exit": "^3.0.3",
+        "strip-final-newline": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/execa?sponsor=1"
+      }
+    },
+    "node_modules/lint-staged/node_modules/get-stream": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+      "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/lint-staged/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/lint-staged/node_modules/human-signals": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+      "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10.17.0"
+      }
+    },
+    "node_modules/lint-staged/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/listr2": {
+      "version": "3.14.0",
+      "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz",
+      "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==",
+      "dev": true,
+      "dependencies": {
+        "cli-truncate": "^2.1.0",
+        "colorette": "^2.0.16",
+        "log-update": "^4.0.0",
+        "p-map": "^4.0.0",
+        "rfdc": "^1.3.0",
+        "rxjs": "^7.5.1",
+        "through": "^2.3.8",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "enquirer": ">= 2.3.0 < 3"
+      },
+      "peerDependenciesMeta": {
+        "enquirer": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/listr2/node_modules/rxjs": {
+      "version": "7.8.0",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz",
+      "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==",
+      "dev": true,
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/listr2/node_modules/tslib": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+      "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
+      "dev": true
+    },
+    "node_modules/load-json-file": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+      "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.2",
+        "parse-json": "^4.0.0",
+        "pify": "^3.0.0",
+        "strip-bom": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/load-json-file/node_modules/parse-json": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+      "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
+      "dev": true,
+      "dependencies": {
+        "error-ex": "^1.3.1",
+        "json-parse-better-errors": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/load-json-file/node_modules/strip-bom": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+      "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/locate-path": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz",
+      "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^6.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+      "dev": true
+    },
+    "node_modules/lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+      "dev": true
+    },
+    "node_modules/lodash.truncate": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
+      "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==",
+      "dev": true
+    },
+    "node_modules/log-symbols": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^4.1.0",
+        "is-unicode-supported": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/log-symbols/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/log-symbols/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/log-symbols/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/log-symbols/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/log-symbols/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/log-symbols/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/log-update": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
+      "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
+      "dev": true,
+      "dependencies": {
+        "ansi-escapes": "^4.3.0",
+        "cli-cursor": "^3.1.0",
+        "slice-ansi": "^4.0.0",
+        "wrap-ansi": "^6.2.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/log-update/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/log-update/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/log-update/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/log-update/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/log-update/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true
+    },
+    "node_modules/log-update/node_modules/slice-ansi": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+      "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "astral-regex": "^2.0.0",
+        "is-fullwidth-code-point": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+      }
+    },
+    "node_modules/log-update/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/log-update/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/log-update/node_modules/wrap-ansi": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/longest-streak": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz",
+      "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/loose-envify": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+      "dev": true,
+      "dependencies": {
+        "js-tokens": "^3.0.0 || ^4.0.0"
+      },
+      "bin": {
+        "loose-envify": "cli.js"
+      }
+    },
+    "node_modules/lru-cache": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "node_modules/make-dir": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+      "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "semver": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/make-dir/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "peer": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+      "dev": true
+    },
+    "node_modules/makeerror": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
+      "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "tmpl": "1.0.5"
+      }
+    },
+    "node_modules/map-cache": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+      "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/map-obj": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
+      "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/map-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+      "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "object-visit": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/markdown-escapes": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz",
+      "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/markdown-table": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz",
+      "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==",
+      "dev": true,
+      "dependencies": {
+        "repeat-string": "^1.0.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/mathml-tag-names": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
+      "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/mdast-util-compact": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-2.0.1.tgz",
+      "integrity": "sha512-7GlnT24gEwDrdAwEHrU4Vv5lLWrEer4KOkAiKT9nYstsTad7Oc1TwqT2zIMKRdZF7cTuaf+GA1E4Kv7jJh8mPA==",
+      "dev": true,
+      "dependencies": {
+        "unist-util-visit": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-compact/node_modules/unist-util-is": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz",
+      "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==",
+      "dev": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-compact/node_modules/unist-util-visit": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz",
+      "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "unist-util-is": "^4.0.0",
+        "unist-util-visit-parents": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-compact/node_modules/unist-util-visit-parents": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz",
+      "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "unist-util-is": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-from-markdown": {
+      "version": "0.8.5",
+      "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz",
+      "integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/mdast": "^3.0.0",
+        "mdast-util-to-string": "^2.0.0",
+        "micromark": "~2.11.0",
+        "parse-entities": "^2.0.0",
+        "unist-util-stringify-position": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-from-markdown/node_modules/mdast-util-to-string": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz",
+      "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==",
+      "dev": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-from-markdown/node_modules/unist-util-stringify-position": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
+      "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.2"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-to-markdown": {
+      "version": "0.6.5",
+      "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz",
+      "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "longest-streak": "^2.0.0",
+        "mdast-util-to-string": "^2.0.0",
+        "parse-entities": "^2.0.0",
+        "repeat-string": "^1.0.0",
+        "zwitch": "^1.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-to-markdown/node_modules/mdast-util-to-string": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz",
+      "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==",
+      "dev": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-to-string": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.1.tgz",
+      "integrity": "sha512-tGvhT94e+cVnQt8JWE9/b3cUQZWS732TJxXHktvP+BYo62PpYD53Ls/6cC60rW21dW+txxiM4zMdc6abASvZKA==",
+      "dev": true,
+      "dependencies": {
+        "@types/mdast": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/meow": {
+      "version": "8.1.2",
+      "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz",
+      "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==",
+      "dev": true,
+      "dependencies": {
+        "@types/minimist": "^1.2.0",
+        "camelcase-keys": "^6.2.2",
+        "decamelize-keys": "^1.1.0",
+        "hard-rejection": "^2.1.0",
+        "minimist-options": "4.1.0",
+        "normalize-package-data": "^3.0.0",
+        "read-pkg-up": "^7.0.1",
+        "redent": "^3.0.0",
+        "trim-newlines": "^3.0.0",
+        "type-fest": "^0.18.0",
+        "yargs-parser": "^20.2.3"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/meow/node_modules/hosted-git-info": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+      "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/meow/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/meow/node_modules/normalize-package-data": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
+      "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
+      "dev": true,
+      "dependencies": {
+        "hosted-git-info": "^4.0.1",
+        "is-core-module": "^2.5.0",
+        "semver": "^7.3.4",
+        "validate-npm-package-license": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/meow/node_modules/semver": {
+      "version": "7.3.8",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/meow/node_modules/type-fest": {
+      "version": "0.18.1",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz",
+      "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/meow/node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true
+    },
+    "node_modules/meow/node_modules/yargs-parser": {
+      "version": "20.2.9",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+      "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/merge-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+      "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+      "dev": true
+    },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/micromark": {
+      "version": "2.11.4",
+      "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz",
+      "integrity": "sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "dependencies": {
+        "debug": "^4.0.0",
+        "parse-entities": "^2.0.0"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+      "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+      "dev": true,
+      "dependencies": {
+        "braces": "^3.0.2",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "dev": true,
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mimic-fn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+      "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/min-indent": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+      "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/minimist-options": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
+      "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==",
+      "dev": true,
+      "dependencies": {
+        "arrify": "^1.0.1",
+        "is-plain-obj": "^1.1.0",
+        "kind-of": "^6.0.3"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/minimist-options/node_modules/is-plain-obj": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+      "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/mixin-deep": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+      "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "for-in": "^1.0.2",
+        "is-extendable": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+      "dev": true,
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+      "dev": true
+    },
+    "node_modules/mute-stream": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+      "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+      "dev": true
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.2.tgz",
+      "integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==",
+      "dev": true,
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/nanomatch": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "fragment-cache": "^0.2.1",
+        "is-windows": "^1.0.2",
+        "kind-of": "^6.0.2",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+      "dev": true
+    },
+    "node_modules/natural-compare-lite": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
+      "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
+      "dev": true
+    },
+    "node_modules/next": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/next/-/next-12.1.4.tgz",
+      "integrity": "sha512-DA4g97BM4Z0nKtDvCTm58RxdvoQyYzeg0AeVbh0N4Y/D8ELrNu47lQeEgRGF8hV4eQ+Sal90zxrJQQG/mPQ8CQ==",
+      "dev": true,
+      "dependencies": {
+        "@next/env": "12.1.4",
+        "caniuse-lite": "^1.0.30001283",
+        "postcss": "8.4.5",
+        "styled-jsx": "5.0.1"
+      },
+      "bin": {
+        "next": "dist/bin/next"
+      },
+      "engines": {
+        "node": ">=12.22.0"
+      },
+      "optionalDependencies": {
+        "@next/swc-android-arm-eabi": "12.1.4",
+        "@next/swc-android-arm64": "12.1.4",
+        "@next/swc-darwin-arm64": "12.1.4",
+        "@next/swc-darwin-x64": "12.1.4",
+        "@next/swc-linux-arm-gnueabihf": "12.1.4",
+        "@next/swc-linux-arm64-gnu": "12.1.4",
+        "@next/swc-linux-arm64-musl": "12.1.4",
+        "@next/swc-linux-x64-gnu": "12.1.4",
+        "@next/swc-linux-x64-musl": "12.1.4",
+        "@next/swc-win32-arm64-msvc": "12.1.4",
+        "@next/swc-win32-ia32-msvc": "12.1.4",
+        "@next/swc-win32-x64-msvc": "12.1.4"
+      },
+      "peerDependencies": {
+        "fibers": ">= 3.1.0",
+        "node-sass": "^6.0.0 || ^7.0.0",
+        "react": "^17.0.2 || ^18.0.0-0",
+        "react-dom": "^17.0.2 || ^18.0.0-0",
+        "sass": "^1.3.0"
+      },
+      "peerDependenciesMeta": {
+        "fibers": {
+          "optional": true
+        },
+        "node-sass": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/nice-try": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/node-fetch": {
+      "version": "2.6.7",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+      "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+      "dev": true,
+      "dependencies": {
+        "whatwg-url": "^5.0.0"
+      },
+      "engines": {
+        "node": "4.x || >=6.0.0"
+      },
+      "peerDependencies": {
+        "encoding": "^0.1.0"
+      },
+      "peerDependenciesMeta": {
+        "encoding": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/node-fetch/node_modules/tr46": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+      "dev": true
+    },
+    "node_modules/node-fetch/node_modules/webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+      "dev": true
+    },
+    "node_modules/node-fetch/node_modules/whatwg-url": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+      "dev": true,
+      "dependencies": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
+    "node_modules/node-int64": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
+      "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/node-notifier": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz",
+      "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==",
+      "dev": true,
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "growly": "^1.3.0",
+        "is-wsl": "^2.2.0",
+        "semver": "^7.3.2",
+        "shellwords": "^0.1.1",
+        "uuid": "^8.3.0",
+        "which": "^2.0.2"
+      }
+    },
+    "node_modules/node-notifier/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/node-notifier/node_modules/semver": {
+      "version": "7.3.8",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "dev": true,
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/node-notifier/node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true,
+      "optional": true,
+      "peer": true
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.10",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
+      "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==",
+      "dev": true
+    },
+    "node_modules/normalize-package-data": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+      "dev": true,
+      "dependencies": {
+        "hosted-git-info": "^2.1.4",
+        "resolve": "^1.10.0",
+        "semver": "2 || 3 || 4 || 5",
+        "validate-npm-package-license": "^3.0.1"
+      }
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/normalize-range": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+      "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/normalize-selector": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz",
+      "integrity": "sha512-dxvWdI8gw6eAvk9BlPffgEoGfM7AdijoCwOEJge3e3ulT2XLgmU7KvvxprOaCu05Q1uGRHmOhHe1r6emZoKyFw==",
+      "dev": true
+    },
+    "node_modules/npm-run-path": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+      "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+      "dev": true,
+      "dependencies": {
+        "path-key": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/num2fraction": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
+      "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==",
+      "dev": true
+    },
+    "node_modules/nwsapi": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz",
+      "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-copy": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+      "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "copy-descriptor": "^0.1.0",
+        "define-property": "^0.2.5",
+        "kind-of": "^3.0.3"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-copy/node_modules/define-property": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+      "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-copy/node_modules/is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-copy/node_modules/is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/object-copy/node_modules/is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-copy/node_modules/is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+      "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-copy/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-inspect": {
+      "version": "1.12.3",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
+      "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object-is": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
+      "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/object-visit": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+      "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "isobject": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object.assign": {
+      "version": "4.1.4",
+      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
+      "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "has-symbols": "^1.0.3",
+        "object-keys": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object.entries": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz",
+      "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/object.fromentries": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz",
+      "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object.hasown": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz",
+      "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==",
+      "dev": true,
+      "dependencies": {
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object.pick": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+      "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object.values": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz",
+      "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dev": true,
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/onetime": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+      "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+      "dev": true,
+      "dependencies": {
+        "mimic-fn": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/open": {
+      "version": "7.3.0",
+      "resolved": "https://registry.npmjs.org/open/-/open-7.3.0.tgz",
+      "integrity": "sha512-mgLwQIx2F/ye9SmbrUkurZCnkoXyXyu9EbHtJZrICjVAJfyMArdHp3KkixGdZx1ZHFPNIwl0DDM1dFFqXbTLZw==",
+      "dev": true,
+      "dependencies": {
+        "is-docker": "^2.0.0",
+        "is-wsl": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/optionator": {
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+      "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+      "dev": true,
+      "dependencies": {
+        "deep-is": "^0.1.3",
+        "fast-levenshtein": "^2.0.6",
+        "levn": "^0.4.1",
+        "prelude-ls": "^1.2.1",
+        "type-check": "^0.4.0",
+        "word-wrap": "^1.2.3"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/p-each-series": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz",
+      "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-finally": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+      "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/p-limit": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
+      "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
+      "dev": true,
+      "dependencies": {
+        "yocto-queue": "^1.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz",
+      "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^4.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-map": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+      "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+      "dev": true,
+      "dependencies": {
+        "aggregate-error": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/parse-entities": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
+      "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
+      "dev": true,
+      "dependencies": {
+        "character-entities": "^1.0.0",
+        "character-entities-legacy": "^1.0.0",
+        "character-reference-invalid": "^1.0.0",
+        "is-alphanumerical": "^1.0.0",
+        "is-decimal": "^1.0.0",
+        "is-hexadecimal": "^1.0.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/parse-json": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/parse5": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
+      "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/pascalcase": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+      "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-exists": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
+      "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==",
+      "dev": true,
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+      "dev": true
+    },
+    "node_modules/path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+      "dev": true
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pify": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+      "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/pirates": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
+      "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/pkg-conf": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz",
+      "integrity": "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==",
+      "dev": true,
+      "dependencies": {
+        "find-up": "^2.0.0",
+        "load-json-file": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/pkg-conf/node_modules/find-up": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+      "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/pkg-conf/node_modules/locate-path": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+      "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^2.0.0",
+        "path-exists": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/pkg-conf/node_modules/p-limit": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+      "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+      "dev": true,
+      "dependencies": {
+        "p-try": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/pkg-conf/node_modules/p-locate": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+      "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/pkg-conf/node_modules/p-try": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+      "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/pkg-conf/node_modules/path-exists": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+      "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/pkg-dir": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "find-up": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/please-upgrade-node": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
+      "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
+      "dev": true,
+      "dependencies": {
+        "semver-compare": "^1.0.0"
+      }
+    },
+    "node_modules/posix-character-classes": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+      "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/postcss": {
+      "version": "8.4.5",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz",
+      "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==",
+      "dev": true,
+      "dependencies": {
+        "nanoid": "^3.1.30",
+        "picocolors": "^1.0.0",
+        "source-map-js": "^1.0.1"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/postcss-html": {
+      "version": "0.36.0",
+      "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-0.36.0.tgz",
+      "integrity": "sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw==",
+      "dev": true,
+      "dependencies": {
+        "htmlparser2": "^3.10.0"
+      },
+      "peerDependencies": {
+        "postcss": ">=5.0.0",
+        "postcss-syntax": ">=0.36.0"
+      }
+    },
+    "node_modules/postcss-less": {
+      "version": "3.1.4",
+      "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-3.1.4.tgz",
+      "integrity": "sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA==",
+      "dev": true,
+      "dependencies": {
+        "postcss": "^7.0.14"
+      },
+      "engines": {
+        "node": ">=6.14.4"
+      }
+    },
+    "node_modules/postcss-less/node_modules/picocolors": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+      "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+      "dev": true
+    },
+    "node_modules/postcss-less/node_modules/postcss": {
+      "version": "7.0.39",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+      "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+      "dev": true,
+      "dependencies": {
+        "picocolors": "^0.2.1",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/postcss-less/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/postcss-media-query-parser": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz",
+      "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==",
+      "dev": true
+    },
+    "node_modules/postcss-resolve-nested-selector": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz",
+      "integrity": "sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==",
+      "dev": true
+    },
+    "node_modules/postcss-safe-parser": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz",
+      "integrity": "sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g==",
+      "dev": true,
+      "dependencies": {
+        "postcss": "^7.0.26"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/postcss-safe-parser/node_modules/picocolors": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+      "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+      "dev": true
+    },
+    "node_modules/postcss-safe-parser/node_modules/postcss": {
+      "version": "7.0.39",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+      "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+      "dev": true,
+      "dependencies": {
+        "picocolors": "^0.2.1",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/postcss-safe-parser/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/postcss-sass": {
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/postcss-sass/-/postcss-sass-0.4.4.tgz",
+      "integrity": "sha512-BYxnVYx4mQooOhr+zer0qWbSPYnarAy8ZT7hAQtbxtgVf8gy+LSLT/hHGe35h14/pZDTw1DsxdbrwxBN++H+fg==",
+      "dev": true,
+      "dependencies": {
+        "gonzales-pe": "^4.3.0",
+        "postcss": "^7.0.21"
+      }
+    },
+    "node_modules/postcss-sass/node_modules/picocolors": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+      "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+      "dev": true
+    },
+    "node_modules/postcss-sass/node_modules/postcss": {
+      "version": "7.0.39",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+      "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+      "dev": true,
+      "dependencies": {
+        "picocolors": "^0.2.1",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/postcss-sass/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/postcss-scss": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.1.1.tgz",
+      "integrity": "sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA==",
+      "dev": true,
+      "dependencies": {
+        "postcss": "^7.0.6"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/postcss-scss/node_modules/picocolors": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+      "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+      "dev": true
+    },
+    "node_modules/postcss-scss/node_modules/postcss": {
+      "version": "7.0.39",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+      "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+      "dev": true,
+      "dependencies": {
+        "picocolors": "^0.2.1",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/postcss-scss/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/postcss-selector-parser": {
+      "version": "6.0.11",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz",
+      "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==",
+      "dev": true,
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-sorting": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-5.0.1.tgz",
+      "integrity": "sha512-Y9fUFkIhfrm6i0Ta3n+89j56EFqaNRdUKqXyRp6kvTcSXnmgEjaVowCXH+JBe9+YKWqd4nc28r2sgwnzJalccA==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.14",
+        "postcss": "^7.0.17"
+      },
+      "engines": {
+        "node": ">=8.7.0"
+      }
+    },
+    "node_modules/postcss-sorting/node_modules/picocolors": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+      "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+      "dev": true
+    },
+    "node_modules/postcss-sorting/node_modules/postcss": {
+      "version": "7.0.39",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+      "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+      "dev": true,
+      "dependencies": {
+        "picocolors": "^0.2.1",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/postcss-sorting/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/postcss-syntax": {
+      "version": "0.36.2",
+      "resolved": "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz",
+      "integrity": "sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==",
+      "dev": true,
+      "peerDependencies": {
+        "postcss": ">=5.0.0"
+      }
+    },
+    "node_modules/postcss-value-parser": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+      "dev": true
+    },
+    "node_modules/postcss-values-parser": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-3.2.1.tgz",
+      "integrity": "sha512-SQ7/88VE9LhJh9gc27/hqnSU/aZaREVJcRVccXBmajgP2RkjdJzNyH/a9GCVMI5nsRhT0jC5HpUMwfkz81DVVg==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "^1.1.4",
+        "is-url-superb": "^3.0.0",
+        "postcss": "^7.0.5",
+        "url-regex": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=6.14.4"
+      }
+    },
+    "node_modules/postcss-values-parser/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/postcss-values-parser/node_modules/picocolors": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+      "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+      "dev": true
+    },
+    "node_modules/postcss-values-parser/node_modules/postcss": {
+      "version": "7.0.39",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+      "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+      "dev": true,
+      "dependencies": {
+        "picocolors": "^0.2.1",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/postcss-values-parser/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/prelude-ls": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/prettier": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
+      "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
+      "dev": true,
+      "bin": {
+        "prettier": "bin-prettier.js"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/prettier-linter-helpers": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+      "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+      "dev": true,
+      "dependencies": {
+        "fast-diff": "^1.1.2"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/pretty-format": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz",
+      "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jest/types": "^26.6.2",
+        "ansi-regex": "^5.0.0",
+        "ansi-styles": "^4.0.0",
+        "react-is": "^17.0.1"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/pretty-format/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pretty-format/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/pretty-format/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/pretty-format/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/prompts": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
+      "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kleur": "^3.0.3",
+        "sisteransi": "^1.0.5"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/prop-types": {
+      "version": "15.8.1",
+      "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+      "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+      "dev": true,
+      "dependencies": {
+        "loose-envify": "^1.4.0",
+        "object-assign": "^4.1.1",
+        "react-is": "^16.13.1"
+      }
+    },
+    "node_modules/prop-types/node_modules/react-is": {
+      "version": "16.13.1",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+      "dev": true
+    },
+    "node_modules/psl": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
+      "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/pump": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+      "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "node_modules/punycode": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
+      "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/querystringify": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+      "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/quick-lru": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
+      "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/react": {
+      "version": "18.0.0",
+      "resolved": "https://registry.npmjs.org/react/-/react-18.0.0.tgz",
+      "integrity": "sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "loose-envify": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/react-dom": {
+      "version": "18.0.0",
+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.0.0.tgz",
+      "integrity": "sha512-XqX7uzmFo0pUceWFCt7Gff6IyIMzFUn7QMZrbrQfGxtaxXZIcGQzoNpRLE3fQLnS4XzLLPMZX2T9TRcSrasicw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "loose-envify": "^1.1.0",
+        "scheduler": "^0.21.0"
+      },
+      "peerDependencies": {
+        "react": "^18.0.0"
+      }
+    },
+    "node_modules/react-is": {
+      "version": "17.0.2",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+      "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/read-pkg": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+      "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+      "dev": true,
+      "dependencies": {
+        "@types/normalize-package-data": "^2.4.0",
+        "normalize-package-data": "^2.5.0",
+        "parse-json": "^5.0.0",
+        "type-fest": "^0.6.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/read-pkg-up": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+      "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
+      "dev": true,
+      "dependencies": {
+        "find-up": "^4.1.0",
+        "read-pkg": "^5.2.0",
+        "type-fest": "^0.8.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/read-pkg-up/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/read-pkg-up/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/read-pkg-up/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/read-pkg-up/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/read-pkg-up/node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/read-pkg-up/node_modules/type-fest": {
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+      "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/read-pkg/node_modules/type-fest": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+      "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/readable-stream": {
+      "version": "3.6.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
+      "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
+      "dev": true,
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/redent": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
+      "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
+      "dev": true,
+      "dependencies": {
+        "indent-string": "^4.0.0",
+        "strip-indent": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/regenerator-runtime": {
+      "version": "0.13.11",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+      "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
+      "dev": true
+    },
+    "node_modules/regex-not": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+      "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "extend-shallow": "^3.0.2",
+        "safe-regex": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/regexp.prototype.flags": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
+      "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3",
+        "functions-have-names": "^1.2.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/remark": {
+      "version": "12.0.1",
+      "resolved": "https://registry.npmjs.org/remark/-/remark-12.0.1.tgz",
+      "integrity": "sha512-gS7HDonkdIaHmmP/+shCPejCEEW+liMp/t/QwmF0Xt47Rpuhl32lLtDV1uKWvGoq+kxr5jSgg5oAIpGuyULjUw==",
+      "dev": true,
+      "dependencies": {
+        "remark-parse": "^8.0.0",
+        "remark-stringify": "^8.0.0",
+        "unified": "^9.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/remark-mdx": {
+      "version": "1.6.22",
+      "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-1.6.22.tgz",
+      "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/core": "7.12.9",
+        "@babel/helper-plugin-utils": "7.10.4",
+        "@babel/plugin-proposal-object-rest-spread": "7.12.1",
+        "@babel/plugin-syntax-jsx": "7.12.1",
+        "@mdx-js/util": "1.6.22",
+        "is-alphabetical": "1.0.4",
+        "remark-parse": "8.0.3",
+        "unified": "9.2.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/remark-mdx/node_modules/unified": {
+      "version": "9.2.0",
+      "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz",
+      "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==",
+      "dev": true,
+      "dependencies": {
+        "bail": "^1.0.0",
+        "extend": "^3.0.0",
+        "is-buffer": "^2.0.0",
+        "is-plain-obj": "^2.0.0",
+        "trough": "^1.0.0",
+        "vfile": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/remark-mdx/node_modules/unist-util-stringify-position": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
+      "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.2"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/remark-mdx/node_modules/vfile": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz",
+      "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "is-buffer": "^2.0.0",
+        "unist-util-stringify-position": "^2.0.0",
+        "vfile-message": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/remark-mdx/node_modules/vfile-message": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
+      "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "unist-util-stringify-position": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/remark-parse": {
+      "version": "8.0.3",
+      "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz",
+      "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==",
+      "dev": true,
+      "dependencies": {
+        "ccount": "^1.0.0",
+        "collapse-white-space": "^1.0.2",
+        "is-alphabetical": "^1.0.0",
+        "is-decimal": "^1.0.0",
+        "is-whitespace-character": "^1.0.0",
+        "is-word-character": "^1.0.0",
+        "markdown-escapes": "^1.0.0",
+        "parse-entities": "^2.0.0",
+        "repeat-string": "^1.5.4",
+        "state-toggle": "^1.0.0",
+        "trim": "0.0.1",
+        "trim-trailing-lines": "^1.0.0",
+        "unherit": "^1.0.4",
+        "unist-util-remove-position": "^2.0.0",
+        "vfile-location": "^3.0.0",
+        "xtend": "^4.0.1"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/remark-stringify": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-8.1.1.tgz",
+      "integrity": "sha512-q4EyPZT3PcA3Eq7vPpT6bIdokXzFGp9i85igjmhRyXWmPs0Y6/d2FYwUNotKAWyLch7g0ASZJn/KHHcHZQ163A==",
+      "dev": true,
+      "dependencies": {
+        "ccount": "^1.0.0",
+        "is-alphanumeric": "^1.0.0",
+        "is-decimal": "^1.0.0",
+        "is-whitespace-character": "^1.0.0",
+        "longest-streak": "^2.0.1",
+        "markdown-escapes": "^1.0.0",
+        "markdown-table": "^2.0.0",
+        "mdast-util-compact": "^2.0.0",
+        "parse-entities": "^2.0.0",
+        "repeat-string": "^1.5.4",
+        "state-toggle": "^1.0.0",
+        "stringify-entities": "^3.0.0",
+        "unherit": "^1.0.4",
+        "xtend": "^4.0.1"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/remove-trailing-separator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+      "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/repeat-element": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
+      "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/require-from-string": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+      "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/require-main-filename": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/requires-port": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+      "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/resolve": {
+      "version": "1.22.1",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+      "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+      "dev": true,
+      "dependencies": {
+        "is-core-module": "^2.9.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/resolve-cwd": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
+      "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "resolve-from": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/resolve-cwd/node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/resolve-url": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+      "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==",
+      "deprecated": "https://github.com/lydell/resolve-url#deprecated",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/restore-cursor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+      "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+      "dev": true,
+      "dependencies": {
+        "onetime": "^5.1.0",
+        "signal-exit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ret": {
+      "version": "0.1.15",
+      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.12"
+      }
+    },
+    "node_modules/reusify": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+      "dev": true,
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rfdc": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
+      "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==",
+      "dev": true
+    },
+    "node_modules/rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "dev": true,
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/rivet-graphql": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/rivet-graphql/-/rivet-graphql-0.3.1.tgz",
+      "integrity": "sha512-HEov02XhZ6H1jOME+mO8CZwliu/UtgZSHixYUwvQ7HSx3gk8EOVaQY5c3zscOYjZECvP8cR4+1Ob3KHWJRWEMw==",
+      "dev": true,
+      "dependencies": {
+        "graphql": "^15.3.0",
+        "graphql-request": "^3.0.0"
+      }
+    },
+    "node_modules/rsvp": {
+      "version": "4.8.5",
+      "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
+      "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": "6.* || >= 7.*"
+      }
+    },
+    "node_modules/run-async": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
+      "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/rxjs": {
+      "version": "6.6.7",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+      "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+      "dev": true,
+      "dependencies": {
+        "tslib": "^1.9.0"
+      },
+      "engines": {
+        "npm": ">=2.0.0"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/safe-regex": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+      "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ret": "~0.1.10"
+      }
+    },
+    "node_modules/safe-regex-test": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
+      "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.3",
+        "is-regex": "^1.1.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true
+    },
+    "node_modules/sane": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz",
+      "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==",
+      "deprecated": "some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@cnakazawa/watch": "^1.0.3",
+        "anymatch": "^2.0.0",
+        "capture-exit": "^2.0.0",
+        "exec-sh": "^0.3.2",
+        "execa": "^1.0.0",
+        "fb-watchman": "^2.0.0",
+        "micromatch": "^3.1.4",
+        "minimist": "^1.1.1",
+        "walker": "~1.0.5"
+      },
+      "bin": {
+        "sane": "src/cli.js"
+      },
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/sane/node_modules/anymatch": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+      "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "micromatch": "^3.1.4",
+        "normalize-path": "^2.1.1"
+      }
+    },
+    "node_modules/sane/node_modules/braces": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+      "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "arr-flatten": "^1.1.0",
+        "array-unique": "^0.3.2",
+        "extend-shallow": "^2.0.1",
+        "fill-range": "^4.0.0",
+        "isobject": "^3.0.1",
+        "repeat-element": "^1.1.2",
+        "snapdragon": "^0.8.1",
+        "snapdragon-node": "^2.0.1",
+        "split-string": "^3.0.2",
+        "to-regex": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sane/node_modules/braces/node_modules/extend-shallow": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+      "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extendable": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sane/node_modules/cross-spawn": {
+      "version": "6.0.5",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+      "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "nice-try": "^1.0.4",
+        "path-key": "^2.0.1",
+        "semver": "^5.5.0",
+        "shebang-command": "^1.2.0",
+        "which": "^1.2.9"
+      },
+      "engines": {
+        "node": ">=4.8"
+      }
+    },
+    "node_modules/sane/node_modules/execa": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+      "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "cross-spawn": "^6.0.0",
+        "get-stream": "^4.0.0",
+        "is-stream": "^1.1.0",
+        "npm-run-path": "^2.0.0",
+        "p-finally": "^1.0.0",
+        "signal-exit": "^3.0.0",
+        "strip-eof": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/sane/node_modules/fill-range": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+      "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "extend-shallow": "^2.0.1",
+        "is-number": "^3.0.0",
+        "repeat-string": "^1.6.1",
+        "to-regex-range": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sane/node_modules/fill-range/node_modules/extend-shallow": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+      "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extendable": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sane/node_modules/get-stream": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+      "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "pump": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/sane/node_modules/is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/sane/node_modules/is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sane/node_modules/is-number": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+      "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sane/node_modules/is-number/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sane/node_modules/is-stream": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+      "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sane/node_modules/micromatch": {
+      "version": "3.1.10",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+      "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "braces": "^2.3.1",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "extglob": "^2.0.4",
+        "fragment-cache": "^0.2.1",
+        "kind-of": "^6.0.2",
+        "nanomatch": "^1.2.9",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sane/node_modules/normalize-path": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+      "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "remove-trailing-separator": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sane/node_modules/npm-run-path": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+      "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "path-key": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/sane/node_modules/path-key": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+      "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/sane/node_modules/shebang-command": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+      "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "shebang-regex": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sane/node_modules/shebang-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+      "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sane/node_modules/to-regex-range": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+      "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-number": "^3.0.0",
+        "repeat-string": "^1.6.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sane/node_modules/which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "which": "bin/which"
+      }
+    },
+    "node_modules/saxes": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz",
+      "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "xmlchars": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/scheduler": {
+      "version": "0.21.0",
+      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz",
+      "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "loose-envify": "^1.1.0"
+      }
+    },
+    "node_modules/semver": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver"
+      }
+    },
+    "node_modules/semver-compare": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
+      "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
+      "dev": true
+    },
+    "node_modules/set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/set-value": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "extend-shallow": "^2.0.1",
+        "is-extendable": "^0.1.1",
+        "is-plain-object": "^2.0.3",
+        "split-string": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/set-value/node_modules/extend-shallow": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+      "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extendable": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/set-value/node_modules/is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shellwords": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
+      "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
+      "dev": true,
+      "optional": true,
+      "peer": true
+    },
+    "node_modules/side-channel": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.0",
+        "get-intrinsic": "^1.0.2",
+        "object-inspect": "^1.9.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/signal-exit": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+      "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+      "dev": true
+    },
+    "node_modules/signale": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz",
+      "integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^2.3.2",
+        "figures": "^2.0.0",
+        "pkg-conf": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/signale/node_modules/figures": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+      "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==",
+      "dev": true,
+      "dependencies": {
+        "escape-string-regexp": "^1.0.5"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/sisteransi": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
+      "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/slash": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
+      "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/slice-ansi": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
+      "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "astral-regex": "^2.0.0",
+        "is-fullwidth-code-point": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/slice-ansi/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/slice-ansi/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/slice-ansi/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/slugify": {
+      "version": "1.4.6",
+      "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.6.tgz",
+      "integrity": "sha512-ZdJIgv9gdrYwhXqxsH9pv7nXxjUEyQ6nqhngRxoAAOlmMGA28FDq5O4/5US4G2/Nod7d1ovNcgURQJ7kHq50KQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/snapdragon": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+      "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "base": "^0.11.1",
+        "debug": "^2.2.0",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "map-cache": "^0.2.2",
+        "source-map": "^0.5.6",
+        "source-map-resolve": "^0.5.0",
+        "use": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-node": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+      "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.0",
+        "snapdragon-util": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-node/node_modules/define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+      "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-util": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+      "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.2.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-util/node_modules/is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/snapdragon-util/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/define-property": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+      "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/extend-shallow": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+      "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extendable": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/snapdragon/node_modules/is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/kind-of": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+      "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/source-map": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+      "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-js": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+      "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-resolve": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+      "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+      "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "atob": "^2.1.2",
+        "decode-uri-component": "^0.2.0",
+        "resolve-url": "^0.2.1",
+        "source-map-url": "^0.4.0",
+        "urix": "^0.1.0"
+      }
+    },
+    "node_modules/source-map-support": {
+      "version": "0.5.21",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "node_modules/source-map-support/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-url": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
+      "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
+      "deprecated": "See https://github.com/lydell/source-map-url#deprecated",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/spdx-correct": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
+      "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
+      "dev": true,
+      "dependencies": {
+        "spdx-expression-parse": "^3.0.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "node_modules/spdx-exceptions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+      "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
+      "dev": true
+    },
+    "node_modules/spdx-expression-parse": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+      "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+      "dev": true,
+      "dependencies": {
+        "spdx-exceptions": "^2.1.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "node_modules/spdx-license-ids": {
+      "version": "3.0.13",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz",
+      "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==",
+      "dev": true
+    },
+    "node_modules/specificity": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/specificity/-/specificity-0.4.1.tgz",
+      "integrity": "sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==",
+      "dev": true,
+      "bin": {
+        "specificity": "bin/specificity"
+      }
+    },
+    "node_modules/split-string": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+      "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "extend-shallow": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/stack-utils": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
+      "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "escape-string-regexp": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/stack-utils/node_modules/escape-string-regexp": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+      "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/state-toggle": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz",
+      "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/static-extend": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+      "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "define-property": "^0.2.5",
+        "object-copy": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/static-extend/node_modules/define-property": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+      "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/static-extend/node_modules/is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/static-extend/node_modules/is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/static-extend/node_modules/is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/static-extend/node_modules/is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/static-extend/node_modules/kind-of": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+      "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/stop-iteration-iterator": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
+      "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==",
+      "dev": true,
+      "dependencies": {
+        "internal-slot": "^1.0.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/string_decoder": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "~5.2.0"
+      }
+    },
+    "node_modules/string-argv": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
+      "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.6.19"
+      }
+    },
+    "node_modules/string-length": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
+      "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "char-regex": "^1.0.2",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/string-length/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string-length/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string-width": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+      "dev": true,
+      "dependencies": {
+        "eastasianwidth": "^0.2.0",
+        "emoji-regex": "^9.2.2",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/string.prototype.matchall": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz",
+      "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4",
+        "get-intrinsic": "^1.1.3",
+        "has-symbols": "^1.0.3",
+        "internal-slot": "^1.0.3",
+        "regexp.prototype.flags": "^1.4.3",
+        "side-channel": "^1.0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/string.prototype.trim": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz",
+      "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/string.prototype.trimend": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz",
+      "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/string.prototype.trimstart": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz",
+      "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/stringify-entities": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-3.1.0.tgz",
+      "integrity": "sha512-3FP+jGMmMV/ffZs86MoghGqAoqXAdxLrJP4GUdrDN1aIScYih5tuIO3eF4To5AJZ79KDZ8Fpdy7QJnK8SsL1Vg==",
+      "dev": true,
+      "dependencies": {
+        "character-entities-html4": "^1.0.0",
+        "character-entities-legacy": "^1.0.0",
+        "xtend": "^4.0.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/stringify-object": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
+      "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==",
+      "dev": true,
+      "dependencies": {
+        "get-own-enumerable-property-symbols": "^3.0.0",
+        "is-obj": "^1.0.1",
+        "is-regexp": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
+      "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+      }
+    },
+    "node_modules/strip-bom": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+      "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-eof": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+      "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/strip-final-newline": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+      "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/strip-indent": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+      "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+      "dev": true,
+      "dependencies": {
+        "min-indent": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/style-search": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz",
+      "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==",
+      "dev": true
+    },
+    "node_modules/styled-jsx": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.1.tgz",
+      "integrity": "sha512-+PIZ/6Uk40mphiQJJI1202b+/dYeTVd9ZnMPR80pgiWbjIwvN2zIp4r9et0BgqBuShh48I0gttPlAXA7WVvBxw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "peerDependencies": {
+        "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
+      },
+      "peerDependenciesMeta": {
+        "@babel/core": {
+          "optional": true
+        },
+        "babel-plugin-macros": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/stylelint": {
+      "version": "13.8.0",
+      "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.8.0.tgz",
+      "integrity": "sha512-iHH3dv3UI23SLDrH4zMQDjLT9/dDIz/IpoFeuNxZmEx86KtfpjDOscxLTFioQyv+2vQjPlRZnK0UoJtfxLICXQ==",
+      "dev": true,
+      "dependencies": {
+        "@stylelint/postcss-css-in-js": "^0.37.2",
+        "@stylelint/postcss-markdown": "^0.36.2",
+        "autoprefixer": "^9.8.6",
+        "balanced-match": "^1.0.0",
+        "chalk": "^4.1.0",
+        "cosmiconfig": "^7.0.0",
+        "debug": "^4.2.0",
+        "execall": "^2.0.0",
+        "fast-glob": "^3.2.4",
+        "fastest-levenshtein": "^1.0.12",
+        "file-entry-cache": "^6.0.0",
+        "get-stdin": "^8.0.0",
+        "global-modules": "^2.0.0",
+        "globby": "^11.0.1",
+        "globjoin": "^0.1.4",
+        "html-tags": "^3.1.0",
+        "ignore": "^5.1.8",
+        "import-lazy": "^4.0.0",
+        "imurmurhash": "^0.1.4",
+        "known-css-properties": "^0.20.0",
+        "lodash": "^4.17.20",
+        "log-symbols": "^4.0.0",
+        "mathml-tag-names": "^2.1.3",
+        "meow": "^8.0.0",
+        "micromatch": "^4.0.2",
+        "normalize-selector": "^0.2.0",
+        "postcss": "^7.0.35",
+        "postcss-html": "^0.36.0",
+        "postcss-less": "^3.1.4",
+        "postcss-media-query-parser": "^0.2.3",
+        "postcss-resolve-nested-selector": "^0.1.1",
+        "postcss-safe-parser": "^4.0.2",
+        "postcss-sass": "^0.4.4",
+        "postcss-scss": "^2.1.1",
+        "postcss-selector-parser": "^6.0.4",
+        "postcss-syntax": "^0.36.2",
+        "postcss-value-parser": "^4.1.0",
+        "resolve-from": "^5.0.0",
+        "slash": "^3.0.0",
+        "specificity": "^0.4.1",
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "style-search": "^0.1.0",
+        "sugarss": "^2.0.0",
+        "svg-tags": "^1.0.0",
+        "table": "^6.0.3",
+        "v8-compile-cache": "^2.2.0",
+        "write-file-atomic": "^3.0.3"
+      },
+      "bin": {
+        "stylelint": "bin/stylelint.js"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/stylelint"
+      }
+    },
+    "node_modules/stylelint-config-css-modules": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/stylelint-config-css-modules/-/stylelint-config-css-modules-2.2.0.tgz",
+      "integrity": "sha512-+zjcDbot+zbuxy1UA31k4G2lUG+nHUwnLyii3uT2F09B8kT2YrT9LZYNfMtAWlDidrxr7sFd5HX9EqPHGU3WKA==",
+      "dev": true,
+      "peerDependencies": {
+        "stylelint": "11.x - 13.x"
+      }
+    },
+    "node_modules/stylelint-config-prettier": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/stylelint-config-prettier/-/stylelint-config-prettier-8.0.2.tgz",
+      "integrity": "sha512-TN1l93iVTXpF9NJstlvP7nOu9zY2k+mN0NSFQ/VEGz15ZIP9ohdDZTtCWHs5LjctAhSAzaILULGbgiM0ItId3A==",
+      "dev": true,
+      "bin": {
+        "stylelint-config-prettier": "bin/check.js",
+        "stylelint-config-prettier-check": "bin/check.js"
+      },
+      "engines": {
+        "node": ">= 10",
+        "npm": ">= 5"
+      },
+      "peerDependencies": {
+        "stylelint": ">=11.0.0"
+      }
+    },
+    "node_modules/stylelint-config-recommended": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-3.0.0.tgz",
+      "integrity": "sha512-F6yTRuc06xr1h5Qw/ykb2LuFynJ2IxkKfCMf+1xqPffkxh0S09Zc902XCffcsw/XMFq/OzQ1w54fLIDtmRNHnQ==",
+      "dev": true,
+      "peerDependencies": {
+        "stylelint": ">=10.1.0"
+      }
+    },
+    "node_modules/stylelint-config-standard": {
+      "version": "20.0.0",
+      "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-20.0.0.tgz",
+      "integrity": "sha512-IB2iFdzOTA/zS4jSVav6z+wGtin08qfj+YyExHB3LF9lnouQht//YyB0KZq9gGz5HNPkddHOzcY8HsUey6ZUlA==",
+      "dev": true,
+      "dependencies": {
+        "stylelint-config-recommended": "^3.0.0"
+      },
+      "peerDependencies": {
+        "stylelint": ">=10.1.0"
+      }
+    },
+    "node_modules/stylelint-media-use-custom-media": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/stylelint-media-use-custom-media/-/stylelint-media-use-custom-media-2.0.0.tgz",
+      "integrity": "sha512-G7Hwma8HIMFJOChqrX9ie8hAGbtEMUbEjuiaR3olHIXjloDWqYlFHIJKsCyyckigkm+4LtCwtZDQASrVY4pRBg==",
+      "dev": true,
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "stylelint": "10 - 13"
+      }
+    },
+    "node_modules/stylelint-order": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-4.1.0.tgz",
+      "integrity": "sha512-sVTikaDvMqg2aJjh4r48jsdfmqLT+nqB1MOsaBnvM3OwLx4S+WXcsxsgk5w18h/OZoxZCxuyXMh61iBHcj9Qiw==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.15",
+        "postcss": "^7.0.31",
+        "postcss-sorting": "^5.0.1"
+      },
+      "peerDependencies": {
+        "stylelint": "^10.0.1 || ^11.0.0 || ^12.0.0 || ^13.0.0"
+      }
+    },
+    "node_modules/stylelint-order/node_modules/picocolors": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+      "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+      "dev": true
+    },
+    "node_modules/stylelint-order/node_modules/postcss": {
+      "version": "7.0.39",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+      "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+      "dev": true,
+      "dependencies": {
+        "picocolors": "^0.2.1",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/stylelint-order/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/stylelint-use-nesting": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/stylelint-use-nesting/-/stylelint-use-nesting-3.0.0.tgz",
+      "integrity": "sha512-BMzhXWbK5DdAYtZMQULn7VmWZXpy8Rwlx2PgeNYqKInQrKTJWM/TFKPScc+xvsGUc/6JPiUDeQQij9gFnOo8Kg==",
+      "dev": true,
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "stylelint": "10 - 13"
+      }
+    },
+    "node_modules/stylelint-value-no-unknown-custom-properties": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/stylelint-value-no-unknown-custom-properties/-/stylelint-value-no-unknown-custom-properties-3.0.0.tgz",
+      "integrity": "sha512-8WoOnZ4ELTxA1cDbhwolIVOutxHwbjpXmd0lL0Li3Iye078jSnEb1KO6pJ/ig5oDVGRApFeA25Fyy4qqmqwGgg==",
+      "dev": true,
+      "dependencies": {
+        "postcss-values-parser": "^3.2.1"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "stylelint": "10 - 13"
+      }
+    },
+    "node_modules/stylelint/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/stylelint/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/stylelint/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/stylelint/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/stylelint/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/stylelint/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true
+    },
+    "node_modules/stylelint/node_modules/globby": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+      "dev": true,
+      "dependencies": {
+        "array-union": "^2.1.0",
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.2.9",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/stylelint/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/stylelint/node_modules/picocolors": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+      "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+      "dev": true
+    },
+    "node_modules/stylelint/node_modules/postcss": {
+      "version": "7.0.39",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+      "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+      "dev": true,
+      "dependencies": {
+        "picocolors": "^0.2.1",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/stylelint/node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/stylelint/node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/stylelint/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/stylelint/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/stylelint/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/stylelint/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/sugarss": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz",
+      "integrity": "sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==",
+      "dev": true,
+      "dependencies": {
+        "postcss": "^7.0.2"
+      }
+    },
+    "node_modules/sugarss/node_modules/picocolors": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+      "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+      "dev": true
+    },
+    "node_modules/sugarss/node_modules/postcss": {
+      "version": "7.0.39",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+      "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+      "dev": true,
+      "dependencies": {
+        "picocolors": "^0.2.1",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/sugarss/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/supports-hyperlinks": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz",
+      "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0",
+        "supports-color": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/supports-hyperlinks/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/supports-hyperlinks/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/svg-tags": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
+      "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==",
+      "dev": true
+    },
+    "node_modules/symbol-tree": {
+      "version": "3.2.4",
+      "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+      "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/synckit": {
+      "version": "0.8.5",
+      "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz",
+      "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==",
+      "dev": true,
+      "dependencies": {
+        "@pkgr/utils": "^2.3.1",
+        "tslib": "^2.5.0"
+      },
+      "engines": {
+        "node": "^14.18.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/unts"
+      }
+    },
+    "node_modules/synckit/node_modules/tslib": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+      "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
+      "dev": true
+    },
+    "node_modules/table": {
+      "version": "6.8.1",
+      "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz",
+      "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==",
+      "dev": true,
+      "dependencies": {
+        "ajv": "^8.0.1",
+        "lodash.truncate": "^4.4.2",
+        "slice-ansi": "^4.0.0",
+        "string-width": "^4.2.3",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/table/node_modules/ajv": {
+      "version": "8.12.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+      "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.1",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/table/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/table/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/table/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/table/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/table/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true
+    },
+    "node_modules/table/node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true
+    },
+    "node_modules/table/node_modules/slice-ansi": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+      "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "astral-regex": "^2.0.0",
+        "is-fullwidth-code-point": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+      }
+    },
+    "node_modules/table/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/table/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/tapable": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
+      "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/terminal-link": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz",
+      "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ansi-escapes": "^4.2.1",
+        "supports-hyperlinks": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/test-exclude": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+      "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@istanbuljs/schema": "^0.1.2",
+        "glob": "^7.1.4",
+        "minimatch": "^3.0.4"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+      "dev": true
+    },
+    "node_modules/throat": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
+      "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+      "dev": true
+    },
+    "node_modules/tiny-glob": {
+      "version": "0.2.9",
+      "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
+      "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
+      "dev": true,
+      "dependencies": {
+        "globalyzer": "0.1.0",
+        "globrex": "^0.1.2"
+      }
+    },
+    "node_modules/tlds": {
+      "version": "1.237.0",
+      "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.237.0.tgz",
+      "integrity": "sha512-4IA6zR7jQop4pEdziQaptOgkIwnnZ537fXM3MKAzOXjXLjiHm77SA3/E0nXWJGSVRnKcn/JxDJmwTqyPgQ+ozg==",
+      "dev": true,
+      "bin": {
+        "tlds": "bin.js"
+      }
+    },
+    "node_modules/tmp": {
+      "version": "0.0.33",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+      "dev": true,
+      "dependencies": {
+        "os-tmpdir": "~1.0.2"
+      },
+      "engines": {
+        "node": ">=0.6.0"
+      }
+    },
+    "node_modules/tmpl": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
+      "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/to-fast-properties": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+      "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/to-object-path": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+      "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-object-path/node_modules/is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/to-object-path/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-regex": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+      "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "regex-not": "^1.0.2",
+        "safe-regex": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/tough-cookie": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
+      "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "psl": "^1.1.33",
+        "punycode": "^2.1.1",
+        "universalify": "^0.2.0",
+        "url-parse": "^1.5.3"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/tough-cookie/node_modules/universalify": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
+      "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">= 4.0.0"
+      }
+    },
+    "node_modules/tr46": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz",
+      "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "punycode": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/trim": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
+      "integrity": "sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==",
+      "deprecated": "Use String.prototype.trim() instead",
+      "dev": true
+    },
+    "node_modules/trim-newlines": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
+      "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/trim-trailing-lines": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz",
+      "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/trough": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
+      "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/ts-jest": {
+      "version": "26.5.6",
+      "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz",
+      "integrity": "sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA==",
+      "dev": true,
+      "dependencies": {
+        "bs-logger": "0.x",
+        "buffer-from": "1.x",
+        "fast-json-stable-stringify": "2.x",
+        "jest-util": "^26.1.0",
+        "json5": "2.x",
+        "lodash": "4.x",
+        "make-error": "1.x",
+        "mkdirp": "1.x",
+        "semver": "7.x",
+        "yargs-parser": "20.x"
+      },
+      "bin": {
+        "ts-jest": "cli.js"
+      },
+      "engines": {
+        "node": ">= 10"
+      },
+      "peerDependencies": {
+        "jest": ">=26 <27",
+        "typescript": ">=3.8 <5.0"
+      }
+    },
+    "node_modules/ts-jest/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/ts-jest/node_modules/semver": {
+      "version": "7.3.8",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/ts-jest/node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true
+    },
+    "node_modules/ts-jest/node_modules/yargs-parser": {
+      "version": "20.2.9",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+      "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/tsconfig-paths": {
+      "version": "3.14.2",
+      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
+      "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==",
+      "dev": true,
+      "dependencies": {
+        "@types/json5": "^0.0.29",
+        "json5": "^1.0.2",
+        "minimist": "^1.2.6",
+        "strip-bom": "^3.0.0"
+      }
+    },
+    "node_modules/tsconfig-paths/node_modules/json5": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+      "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+      "dev": true,
+      "dependencies": {
+        "minimist": "^1.2.0"
+      },
+      "bin": {
+        "json5": "lib/cli.js"
+      }
+    },
+    "node_modules/tsconfig-paths/node_modules/strip-bom": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+      "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "dev": true
+    },
+    "node_modules/tsutils": {
+      "version": "3.21.0",
+      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+      "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+      "dev": true,
+      "dependencies": {
+        "tslib": "^1.8.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      },
+      "peerDependencies": {
+        "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+      }
+    },
+    "node_modules/type-check": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+      "dev": true,
+      "dependencies": {
+        "prelude-ls": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/type-detect": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+      "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/type-fest": {
+      "version": "0.21.3",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+      "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/typed-array-length": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz",
+      "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "for-each": "^0.3.3",
+        "is-typed-array": "^1.1.9"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/typedarray-to-buffer": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+      "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+      "dev": true,
+      "dependencies": {
+        "is-typedarray": "^1.0.0"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+      "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
+      "dev": true,
+      "peer": true,
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=4.2.0"
+      }
+    },
+    "node_modules/unbox-primitive": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
+      "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "has-bigints": "^1.0.2",
+        "has-symbols": "^1.0.3",
+        "which-boxed-primitive": "^1.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/unherit": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz",
+      "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.0",
+        "xtend": "^4.0.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/unified": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz",
+      "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==",
+      "dev": true,
+      "dependencies": {
+        "bail": "^1.0.0",
+        "extend": "^3.0.0",
+        "is-buffer": "^2.0.0",
+        "is-plain-obj": "^2.0.0",
+        "trough": "^1.0.0",
+        "vfile": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unified-lint-rule": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/unified-lint-rule/-/unified-lint-rule-2.1.1.tgz",
+      "integrity": "sha512-vsLHyLZFstqtGse2gvrGwasOmH8M2y+r2kQMoDSWzSqUkQx2MjHjvZuGSv5FUaiv4RQO1bHRajy7lSGp7XWq5A==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "trough": "^2.0.0",
+        "unified": "^10.0.0",
+        "vfile": "^5.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unified-lint-rule/node_modules/bail": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
+      "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/unified-lint-rule/node_modules/is-plain-obj": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
+      "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/unified-lint-rule/node_modules/trough": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz",
+      "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/unified-lint-rule/node_modules/unified": {
+      "version": "10.1.2",
+      "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz",
+      "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "bail": "^2.0.0",
+        "extend": "^3.0.0",
+        "is-buffer": "^2.0.0",
+        "is-plain-obj": "^4.0.0",
+        "trough": "^2.0.0",
+        "vfile": "^5.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unified/node_modules/unist-util-stringify-position": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
+      "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.2"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unified/node_modules/vfile": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz",
+      "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "is-buffer": "^2.0.0",
+        "unist-util-stringify-position": "^2.0.0",
+        "vfile-message": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unified/node_modules/vfile-message": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
+      "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "unist-util-stringify-position": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/union-value": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "arr-union": "^3.1.0",
+        "get-value": "^2.0.6",
+        "is-extendable": "^0.1.1",
+        "set-value": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/union-value/node_modules/is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/unist-util-find-all-after": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/unist-util-find-all-after/-/unist-util-find-all-after-3.0.2.tgz",
+      "integrity": "sha512-xaTC/AGZ0rIM2gM28YVRAFPIZpzbpDtU3dRmp7EXlNVA8ziQc4hY3H7BHXM1J49nEmiqc3svnqMReW+PGqbZKQ==",
+      "dev": true,
+      "dependencies": {
+        "unist-util-is": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-find-all-after/node_modules/unist-util-is": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz",
+      "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==",
+      "dev": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-is": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz",
+      "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-remove-position": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz",
+      "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==",
+      "dev": true,
+      "dependencies": {
+        "unist-util-visit": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-remove-position/node_modules/unist-util-is": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz",
+      "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==",
+      "dev": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-remove-position/node_modules/unist-util-visit": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz",
+      "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "unist-util-is": "^4.0.0",
+        "unist-util-visit-parents": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-remove-position/node_modules/unist-util-visit-parents": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz",
+      "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "unist-util-is": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-stringify-position": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz",
+      "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-visit": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz",
+      "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "unist-util-is": "^5.0.0",
+        "unist-util-visit-parents": "^5.1.1"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-visit-parents": {
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz",
+      "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "unist-util-is": "^5.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/universalify": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
+      "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
+      "dev": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      }
+    },
+    "node_modules/unset-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+      "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-value": "^0.3.1",
+        "isobject": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/unset-value/node_modules/has-value": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+      "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "get-value": "^2.0.3",
+        "has-values": "^0.1.4",
+        "isobject": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/unset-value/node_modules/has-value/node_modules/isobject": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+      "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "isarray": "1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/unset-value/node_modules/has-values": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+      "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/unset-value/node_modules/isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
+      "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        }
+      ],
+      "dependencies": {
+        "escalade": "^3.1.1",
+        "picocolors": "^1.0.0"
+      },
+      "bin": {
+        "browserslist-lint": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/uri-js": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+      "dev": true,
+      "dependencies": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "node_modules/urix": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+      "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==",
+      "deprecated": "Please see https://github.com/lydell/urix#deprecated",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/url-parse": {
+      "version": "1.5.10",
+      "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
+      "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "querystringify": "^2.1.1",
+        "requires-port": "^1.0.0"
+      }
+    },
+    "node_modules/url-regex": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/url-regex/-/url-regex-5.0.0.tgz",
+      "integrity": "sha512-O08GjTiAFNsSlrUWfqF1jH0H1W3m35ZyadHrGv5krdnmPPoxP27oDTqux/579PtaroiSGm5yma6KT1mHFH6Y/g==",
+      "dev": true,
+      "dependencies": {
+        "ip-regex": "^4.1.0",
+        "tlds": "^1.203.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/use": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+      "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+      "dev": true
+    },
+    "node_modules/uuid": {
+      "version": "8.3.2",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+      "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+      "dev": true,
+      "optional": true,
+      "peer": true,
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
+    "node_modules/v8-compile-cache": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
+      "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
+      "dev": true
+    },
+    "node_modules/v8-to-istanbul": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz",
+      "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@types/istanbul-lib-coverage": "^2.0.1",
+        "convert-source-map": "^1.6.0",
+        "source-map": "^0.7.3"
+      },
+      "engines": {
+        "node": ">=10.10.0"
+      }
+    },
+    "node_modules/v8-to-istanbul/node_modules/source-map": {
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+      "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/validate-npm-package-license": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+      "dev": true,
+      "dependencies": {
+        "spdx-correct": "^3.0.0",
+        "spdx-expression-parse": "^3.0.0"
+      }
+    },
+    "node_modules/vfile": {
+      "version": "5.3.7",
+      "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz",
+      "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "is-buffer": "^2.0.0",
+        "unist-util-stringify-position": "^3.0.0",
+        "vfile-message": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/vfile-location": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz",
+      "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==",
+      "dev": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/vfile-matter": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/vfile-matter/-/vfile-matter-4.0.1.tgz",
+      "integrity": "sha512-ZeACdaxCOxhePpoLO4A5y/VgI9EuWBXu+sUk65aQ7lXBZDFg7X0tuOzigLJUtsQzazFt6K2m9SdlDxZdfL5vVg==",
+      "dev": true,
+      "dependencies": {
+        "is-buffer": "^2.0.0",
+        "vfile": "^5.0.0",
+        "yaml": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/vfile-message": {
+      "version": "3.1.4",
+      "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz",
+      "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==",
+      "dev": true,
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "unist-util-stringify-position": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/vfile-reporter": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/vfile-reporter/-/vfile-reporter-7.0.5.tgz",
+      "integrity": "sha512-NdWWXkv6gcd7AZMvDomlQbK3MqFWL1RlGzMn++/O2TI+68+nqxCPTvLugdOtfSzXmjh+xUyhp07HhlrbJjT+mw==",
+      "dev": true,
+      "dependencies": {
+        "@types/supports-color": "^8.0.0",
+        "string-width": "^5.0.0",
+        "supports-color": "^9.0.0",
+        "unist-util-stringify-position": "^3.0.0",
+        "vfile": "^5.0.0",
+        "vfile-message": "^3.0.0",
+        "vfile-sort": "^3.0.0",
+        "vfile-statistics": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/vfile-reporter-json": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/vfile-reporter-json/-/vfile-reporter-json-3.3.0.tgz",
+      "integrity": "sha512-/zgRtjxQ2UGJn+HViiZ7+nIXtUzkkXFQum3BmaS/bSyr10P0X41ETRqqwMJ95RtbKUah3m7pKb6oS1eZeXXHzQ==",
+      "dev": true,
+      "dependencies": {
+        "vfile": "^5.0.0",
+        "vfile-message": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/vfile-reporter/node_modules/supports-color": {
+      "version": "9.3.1",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.3.1.tgz",
+      "integrity": "sha512-knBY82pjmnIzK3NifMo3RxEIRD9E0kIzV4BKcyTZ9+9kWgLMxd4PrsTSMoFQUabgRBbF8KOLRDCyKgNV+iK44Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/supports-color?sponsor=1"
+      }
+    },
+    "node_modules/vfile-sort": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/vfile-sort/-/vfile-sort-3.0.1.tgz",
+      "integrity": "sha512-1os1733XY6y0D5x0ugqSeaVJm9lYgj0j5qdcZQFyxlZOSy1jYarL77lLyb5gK4Wqr1d5OxmuyflSO3zKyFnTFw==",
+      "dev": true,
+      "dependencies": {
+        "vfile": "^5.0.0",
+        "vfile-message": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/vfile-statistics": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/vfile-statistics/-/vfile-statistics-2.0.1.tgz",
+      "integrity": "sha512-W6dkECZmP32EG/l+dp2jCLdYzmnDBIw6jwiLZSER81oR5AHRcVqL+k3Z+pfH1R73le6ayDkJRMk0sutj1bMVeg==",
+      "dev": true,
+      "dependencies": {
+        "vfile": "^5.0.0",
+        "vfile-message": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/w3c-hr-time": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
+      "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==",
+      "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "browser-process-hrtime": "^1.0.0"
+      }
+    },
+    "node_modules/w3c-xmlserializer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz",
+      "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "xml-name-validator": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/walker": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
+      "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "makeerror": "1.0.12"
+      }
+    },
+    "node_modules/webidl-conversions": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
+      "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=10.4"
+      }
+    },
+    "node_modules/whatwg-encoding": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
+      "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "iconv-lite": "0.4.24"
+      }
+    },
+    "node_modules/whatwg-mimetype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
+      "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/whatwg-url": {
+      "version": "8.7.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz",
+      "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "lodash": "^4.7.0",
+        "tr46": "^2.1.0",
+        "webidl-conversions": "^6.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/which-boxed-primitive": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
+      "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
+      "dev": true,
+      "dependencies": {
+        "is-bigint": "^1.0.1",
+        "is-boolean-object": "^1.1.0",
+        "is-number-object": "^1.0.4",
+        "is-string": "^1.0.5",
+        "is-symbol": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/which-collection": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz",
+      "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==",
+      "dev": true,
+      "dependencies": {
+        "is-map": "^2.0.1",
+        "is-set": "^2.0.1",
+        "is-weakmap": "^2.0.1",
+        "is-weakset": "^2.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/which-module": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+      "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/which-typed-array": {
+      "version": "1.1.9",
+      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz",
+      "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==",
+      "dev": true,
+      "dependencies": {
+        "available-typed-arrays": "^1.0.5",
+        "call-bind": "^1.0.2",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "has-tostringtag": "^1.0.0",
+        "is-typed-array": "^1.1.10"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/word-wrap": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/wrap-ansi/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true
+    },
+    "node_modules/wrap-ansi/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+      "dev": true
+    },
+    "node_modules/write-file-atomic": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
+      "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
+      "dev": true,
+      "dependencies": {
+        "imurmurhash": "^0.1.4",
+        "is-typedarray": "^1.0.0",
+        "signal-exit": "^3.0.2",
+        "typedarray-to-buffer": "^3.1.5"
+      }
+    },
+    "node_modules/ws": {
+      "version": "7.5.9",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
+      "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=8.3.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": "^5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/xml-name-validator": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
+      "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/xmlchars": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
+      "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/xtend": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4"
+      }
+    },
+    "node_modules/y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+      "dev": true
+    },
+    "node_modules/yaml": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
+      "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/yargs": {
+      "version": "17.7.1",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz",
+      "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==",
+      "dev": true,
+      "dependencies": {
+        "cliui": "^8.0.1",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.3",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^21.1.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "21.1.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yargs/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/yargs/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true
+    },
+    "node_modules/yargs/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/yargs/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/yocto-queue": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
+      "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
+      "dev": true,
+      "engines": {
+        "node": ">=12.20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/zod": {
+      "version": "3.21.4",
+      "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
+      "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/colinhacks"
+      }
+    },
+    "node_modules/zwitch": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz",
+      "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    }
+  },
+  "dependencies": {
+    "@ampproject/remapping": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
+      "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/gen-mapping": "^0.1.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      },
+      "dependencies": {
+        "@jridgewell/gen-mapping": {
+          "version": "0.1.1",
+          "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
+          "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
+          "dev": true,
+          "requires": {
+            "@jridgewell/set-array": "^1.0.0",
+            "@jridgewell/sourcemap-codec": "^1.4.10"
+          }
+        }
+      }
+    },
+    "@babel/code-frame": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
+      "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+      "dev": true,
+      "requires": {
+        "@babel/highlight": "^7.18.6"
+      }
+    },
+    "@babel/compat-data": {
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz",
+      "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==",
+      "dev": true
+    },
+    "@babel/core": {
+      "version": "7.12.9",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz",
+      "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.10.4",
+        "@babel/generator": "^7.12.5",
+        "@babel/helper-module-transforms": "^7.12.1",
+        "@babel/helpers": "^7.12.5",
+        "@babel/parser": "^7.12.7",
+        "@babel/template": "^7.12.7",
+        "@babel/traverse": "^7.12.9",
+        "@babel/types": "^7.12.7",
+        "convert-source-map": "^1.7.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.1",
+        "json5": "^2.1.2",
+        "lodash": "^4.17.19",
+        "resolve": "^1.3.2",
+        "semver": "^5.4.1",
+        "source-map": "^0.5.0"
+      }
+    },
+    "@babel/generator": {
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz",
+      "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "^7.21.3",
+        "@jridgewell/gen-mapping": "^0.3.2",
+        "@jridgewell/trace-mapping": "^0.3.17",
+        "jsesc": "^2.5.1"
+      }
+    },
+    "@babel/helper-compilation-targets": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
+      "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
+      "dev": true,
+      "requires": {
+        "@babel/compat-data": "^7.20.5",
+        "@babel/helper-validator-option": "^7.18.6",
+        "browserslist": "^4.21.3",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
+        }
+      }
+    },
+    "@babel/helper-environment-visitor": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
+      "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
+      "dev": true
+    },
+    "@babel/helper-function-name": {
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
+      "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
+      "dev": true,
+      "requires": {
+        "@babel/template": "^7.20.7",
+        "@babel/types": "^7.21.0"
+      }
+    },
+    "@babel/helper-hoist-variables": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
+      "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "^7.18.6"
+      }
+    },
+    "@babel/helper-module-imports": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
+      "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "^7.18.6"
+      }
+    },
+    "@babel/helper-module-transforms": {
+      "version": "7.21.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz",
+      "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-module-imports": "^7.18.6",
+        "@babel/helper-simple-access": "^7.20.2",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/helper-validator-identifier": "^7.19.1",
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.21.2",
+        "@babel/types": "^7.21.2"
+      }
+    },
+    "@babel/helper-plugin-utils": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz",
+      "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==",
+      "dev": true
+    },
+    "@babel/helper-simple-access": {
+      "version": "7.20.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
+      "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "^7.20.2"
+      }
+    },
+    "@babel/helper-split-export-declaration": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
+      "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "^7.18.6"
+      }
+    },
+    "@babel/helper-string-parser": {
+      "version": "7.19.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
+      "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
+      "dev": true
+    },
+    "@babel/helper-validator-identifier": {
+      "version": "7.19.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
+      "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+      "dev": true
+    },
+    "@babel/helper-validator-option": {
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz",
+      "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==",
+      "dev": true
+    },
+    "@babel/helpers": {
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz",
+      "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==",
+      "dev": true,
+      "requires": {
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.21.0",
+        "@babel/types": "^7.21.0"
+      }
+    },
+    "@babel/highlight": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+      "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-validator-identifier": "^7.18.6",
+        "chalk": "^2.0.0",
+        "js-tokens": "^4.0.0"
+      }
+    },
+    "@babel/parser": {
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz",
+      "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==",
+      "dev": true
+    },
+    "@babel/plugin-proposal-object-rest-spread": {
+      "version": "7.12.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz",
+      "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.0",
+        "@babel/plugin-transform-parameters": "^7.12.1"
+      }
+    },
+    "@babel/plugin-syntax-async-generators": {
+      "version": "7.8.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
+      "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-bigint": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
+      "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-class-properties": {
+      "version": "7.12.13",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
+      "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.12.13"
+      },
+      "dependencies": {
+        "@babel/helper-plugin-utils": {
+          "version": "7.20.2",
+          "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
+          "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "@babel/plugin-syntax-import-meta": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
+      "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      }
+    },
+    "@babel/plugin-syntax-json-strings": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
+      "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-jsx": {
+      "version": "7.12.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz",
+      "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      }
+    },
+    "@babel/plugin-syntax-logical-assignment-operators": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
+      "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      }
+    },
+    "@babel/plugin-syntax-nullish-coalescing-operator": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
+      "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-numeric-separator": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
+      "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      }
+    },
+    "@babel/plugin-syntax-object-rest-spread": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
+      "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-optional-catch-binding": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
+      "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-optional-chaining": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
+      "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-top-level-await": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
+      "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.14.5"
+      },
+      "dependencies": {
+        "@babel/helper-plugin-utils": {
+          "version": "7.20.2",
+          "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
+          "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "@babel/plugin-transform-parameters": {
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.21.3.tgz",
+      "integrity": "sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.20.2"
+      },
+      "dependencies": {
+        "@babel/helper-plugin-utils": {
+          "version": "7.20.2",
+          "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
+          "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==",
+          "dev": true
+        }
+      }
+    },
+    "@babel/runtime": {
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
+      "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
+      "dev": true,
+      "requires": {
+        "regenerator-runtime": "^0.13.11"
+      }
+    },
+    "@babel/template": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
+      "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.18.6",
+        "@babel/parser": "^7.20.7",
+        "@babel/types": "^7.20.7"
+      }
+    },
+    "@babel/traverse": {
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz",
+      "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.18.6",
+        "@babel/generator": "^7.21.3",
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-function-name": "^7.21.0",
+        "@babel/helper-hoist-variables": "^7.18.6",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/parser": "^7.21.3",
+        "@babel/types": "^7.21.3",
+        "debug": "^4.1.0",
+        "globals": "^11.1.0"
+      }
+    },
+    "@babel/types": {
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz",
+      "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-string-parser": "^7.19.4",
+        "@babel/helper-validator-identifier": "^7.19.1",
+        "to-fast-properties": "^2.0.0"
+      }
+    },
+    "@bcoe/v8-coverage": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
+      "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
+      "dev": true,
+      "peer": true
+    },
+    "@cnakazawa/watch": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz",
+      "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "exec-sh": "^0.3.2",
+        "minimist": "^1.2.0"
+      }
+    },
+    "@eslint-community/eslint-utils": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz",
+      "integrity": "sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==",
+      "dev": true,
+      "requires": {
+        "eslint-visitor-keys": "^3.3.0"
+      }
+    },
+    "@eslint-community/regexpp": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz",
+      "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==",
+      "dev": true
+    },
+    "@eslint/eslintrc": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz",
+      "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==",
+      "dev": true,
+      "requires": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^9.5.0",
+        "globals": "^13.19.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      },
+      "dependencies": {
+        "globals": {
+          "version": "13.20.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
+          "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+          "dev": true,
+          "requires": {
+            "type-fest": "^0.20.2"
+          }
+        },
+        "type-fest": {
+          "version": "0.20.2",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+          "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+          "dev": true
+        }
+      }
+    },
+    "@eslint/js": {
+      "version": "8.36.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz",
+      "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==",
+      "dev": true
+    },
+    "@hashicorp/platform-cli": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/@hashicorp/platform-cli/-/platform-cli-2.6.0.tgz",
+      "integrity": "sha512-nMO7Uiy/A5CT/BCE9RyQt6/Uci7bxwTesxCNWkXlciyqlIrz9WmBa9hr710IiMoDzrzQ1tL6AgFIeTbXs4RTqA==",
+      "dev": true,
+      "requires": {
+        "@hashicorp/platform-cms": "0.3.0",
+        "@typescript-eslint/eslint-plugin": "^5.48.0",
+        "@typescript-eslint/parser": "^5.48.0",
+        "chalk": "4.1.0",
+        "commander": "7.2.0",
+        "ejs": "3.1.5",
+        "eslint": "^8.31.0",
+        "eslint-config-next": "^13.1.1",
+        "eslint-config-prettier": "^8.6.0",
+        "eslint-plugin-jsx-a11y": "^6.6.1",
+        "eslint-plugin-prettier": "^4.2.1",
+        "fs-extra": "9.0.1",
+        "globby": "11.0.1",
+        "inquirer": "7.3.3",
+        "lint-staged": "11.1.2",
+        "open": "7.3.0",
+        "prettier": "2.5.1",
+        "readdirp": "3.5.0",
+        "signale": "1.4.0",
+        "slugify": "1.4.6",
+        "stylelint": "13.8.0",
+        "stylelint-config-css-modules": "2.2.0",
+        "stylelint-config-prettier": "8.0.2",
+        "stylelint-config-standard": "20.0.0",
+        "stylelint-media-use-custom-media": "2.0.0",
+        "stylelint-order": "4.1.0",
+        "stylelint-use-nesting": "3.0.0",
+        "stylelint-value-no-unknown-custom-properties": "3.0.0",
+        "ts-jest": "^26.4.4"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "globby": {
+          "version": "11.0.1",
+          "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz",
+          "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==",
+          "dev": true,
+          "requires": {
+            "array-union": "^2.1.0",
+            "dir-glob": "^3.0.1",
+            "fast-glob": "^3.1.1",
+            "ignore": "^5.1.4",
+            "merge2": "^1.3.0",
+            "slash": "^3.0.0"
+          }
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "slash": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+          "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "@hashicorp/platform-cms": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/@hashicorp/platform-cms/-/platform-cms-0.3.0.tgz",
+      "integrity": "sha512-sRX9A+kDEZvfZy8PvGFbEaHjn5G1mEsHwTri1vDnrmKG8apE+ELlug83b0iEkD5wIJi9OqaewMIb0NrLxg9s5A==",
+      "dev": true,
+      "requires": {
+        "rivet-graphql": "0.3.1"
+      }
+    },
+    "@hashicorp/platform-content-conformance": {
+      "version": "0.0.10",
+      "resolved": "https://registry.npmjs.org/@hashicorp/platform-content-conformance/-/platform-content-conformance-0.0.10.tgz",
+      "integrity": "sha512-vXLbd2w9phS4JfFyh17jCiyu+LXVonTfb7WEUK2eMlOL/wxe2umyJvEQaJNzD5bwyYC8LuXGA5JkbnPXnU5ZQg==",
+      "dev": true,
+      "requires": {
+        "find-up": "^6.3.0",
+        "flat": "^5.0.2",
+        "globby": "^13.1.2",
+        "mdast-util-to-string": "^3.1.0",
+        "remark": "12.0.1",
+        "remark-mdx": "^1.6.22",
+        "unified-lint-rule": "^2.1.1",
+        "unist-util-stringify-position": "^3.0.2",
+        "unist-util-visit": "^4.1.1",
+        "vfile": "^5.3.6",
+        "vfile-matter": "^4.0.0",
+        "vfile-reporter": "^7.0.4",
+        "vfile-reporter-json": "^3.2.0",
+        "vfile-statistics": "^2.0.0",
+        "yaml": "^2.1.3",
+        "yargs": "^17.4.1",
+        "zod": "^3.19.1"
+      }
+    },
+    "@humanwhocodes/config-array": {
+      "version": "0.11.8",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
+      "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+      "dev": true,
+      "requires": {
+        "@humanwhocodes/object-schema": "^1.2.1",
+        "debug": "^4.1.1",
+        "minimatch": "^3.0.5"
+      }
+    },
+    "@humanwhocodes/module-importer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+      "dev": true
+    },
+    "@humanwhocodes/object-schema": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+      "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+      "dev": true
+    },
+    "@istanbuljs/load-nyc-config": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+      "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "camelcase": "^5.3.1",
+        "find-up": "^4.1.0",
+        "get-package-type": "^0.1.0",
+        "js-yaml": "^3.13.1",
+        "resolve-from": "^5.0.0"
+      },
+      "dependencies": {
+        "argparse": {
+          "version": "1.0.10",
+          "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+          "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "sprintf-js": "~1.0.2"
+          }
+        },
+        "find-up": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "locate-path": "^5.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "js-yaml": {
+          "version": "3.14.1",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+          "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "argparse": "^1.0.7",
+            "esprima": "^4.0.0"
+          }
+        },
+        "locate-path": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "p-locate": "^4.1.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "p-try": "^2.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "p-limit": "^2.2.0"
+          }
+        },
+        "path-exists": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+          "dev": true,
+          "peer": true
+        },
+        "resolve-from": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+          "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "@istanbuljs/schema": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
+      "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
+      "dev": true,
+      "peer": true
+    },
+    "@jest/console": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz",
+      "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "jest-message-util": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "slash": "^3.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "slash": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+          "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "@jest/core": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz",
+      "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/console": "^26.6.2",
+        "@jest/reporters": "^26.6.2",
+        "@jest/test-result": "^26.6.2",
+        "@jest/transform": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.0.0",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.2.4",
+        "jest-changed-files": "^26.6.2",
+        "jest-config": "^26.6.3",
+        "jest-haste-map": "^26.6.2",
+        "jest-message-util": "^26.6.2",
+        "jest-regex-util": "^26.0.0",
+        "jest-resolve": "^26.6.2",
+        "jest-resolve-dependencies": "^26.6.3",
+        "jest-runner": "^26.6.3",
+        "jest-runtime": "^26.6.3",
+        "jest-snapshot": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "jest-validate": "^26.6.2",
+        "jest-watcher": "^26.6.2",
+        "micromatch": "^4.0.2",
+        "p-each-series": "^2.1.0",
+        "rimraf": "^3.0.0",
+        "slash": "^3.0.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true,
+          "peer": true
+        },
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "slash": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+          "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+          "dev": true,
+          "peer": true
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "@jest/environment": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz",
+      "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/fake-timers": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "jest-mock": "^26.6.2"
+      }
+    },
+    "@jest/fake-timers": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz",
+      "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/types": "^26.6.2",
+        "@sinonjs/fake-timers": "^6.0.1",
+        "@types/node": "*",
+        "jest-message-util": "^26.6.2",
+        "jest-mock": "^26.6.2",
+        "jest-util": "^26.6.2"
+      }
+    },
+    "@jest/globals": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz",
+      "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/environment": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "expect": "^26.6.2"
+      }
+    },
+    "@jest/reporters": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz",
+      "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@bcoe/v8-coverage": "^0.2.3",
+        "@jest/console": "^26.6.2",
+        "@jest/test-result": "^26.6.2",
+        "@jest/transform": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "chalk": "^4.0.0",
+        "collect-v8-coverage": "^1.0.0",
+        "exit": "^0.1.2",
+        "glob": "^7.1.2",
+        "graceful-fs": "^4.2.4",
+        "istanbul-lib-coverage": "^3.0.0",
+        "istanbul-lib-instrument": "^4.0.3",
+        "istanbul-lib-report": "^3.0.0",
+        "istanbul-lib-source-maps": "^4.0.0",
+        "istanbul-reports": "^3.0.2",
+        "jest-haste-map": "^26.6.2",
+        "jest-resolve": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "jest-worker": "^26.6.2",
+        "node-notifier": "^8.0.0",
+        "slash": "^3.0.0",
+        "source-map": "^0.6.0",
+        "string-length": "^4.0.1",
+        "terminal-link": "^2.0.0",
+        "v8-to-istanbul": "^7.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "slash": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+          "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+          "dev": true,
+          "peer": true
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "@jest/source-map": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz",
+      "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "callsites": "^3.0.0",
+        "graceful-fs": "^4.2.4",
+        "source-map": "^0.6.0"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "@jest/test-result": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz",
+      "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/console": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/istanbul-lib-coverage": "^2.0.0",
+        "collect-v8-coverage": "^1.0.0"
+      }
+    },
+    "@jest/test-sequencer": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz",
+      "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/test-result": "^26.6.2",
+        "graceful-fs": "^4.2.4",
+        "jest-haste-map": "^26.6.2",
+        "jest-runner": "^26.6.3",
+        "jest-runtime": "^26.6.3"
+      }
+    },
+    "@jest/transform": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz",
+      "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/core": "^7.1.0",
+        "@jest/types": "^26.6.2",
+        "babel-plugin-istanbul": "^6.0.0",
+        "chalk": "^4.0.0",
+        "convert-source-map": "^1.4.0",
+        "fast-json-stable-stringify": "^2.0.0",
+        "graceful-fs": "^4.2.4",
+        "jest-haste-map": "^26.6.2",
+        "jest-regex-util": "^26.0.0",
+        "jest-util": "^26.6.2",
+        "micromatch": "^4.0.2",
+        "pirates": "^4.0.1",
+        "slash": "^3.0.0",
+        "source-map": "^0.6.1",
+        "write-file-atomic": "^3.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "slash": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+          "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+          "dev": true,
+          "peer": true
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "@jest/types": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz",
+      "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==",
+      "dev": true,
+      "requires": {
+        "@types/istanbul-lib-coverage": "^2.0.0",
+        "@types/istanbul-reports": "^3.0.0",
+        "@types/node": "*",
+        "@types/yargs": "^15.0.0",
+        "chalk": "^4.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "@jridgewell/gen-mapping": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
+      "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/set-array": "^1.0.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      }
+    },
+    "@jridgewell/resolve-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+      "dev": true
+    },
+    "@jridgewell/set-array": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+      "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+      "dev": true
+    },
+    "@jridgewell/sourcemap-codec": {
+      "version": "1.4.14",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+      "dev": true
+    },
+    "@jridgewell/trace-mapping": {
+      "version": "0.3.17",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
+      "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/resolve-uri": "3.1.0",
+        "@jridgewell/sourcemap-codec": "1.4.14"
+      }
+    },
+    "@mdx-js/util": {
+      "version": "1.6.22",
+      "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz",
+      "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==",
+      "dev": true
+    },
+    "@next/env": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.4.tgz",
+      "integrity": "sha512-7gQwotJDKnfMxxXd8xJ2vsX5AzyDxO3zou0+QOXX8/unypA6icw5+wf6A62yKZ6qQ4UZHHxS68pb6UV+wNneXg==",
+      "dev": true
+    },
+    "@next/eslint-plugin-next": {
+      "version": "13.2.4",
+      "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.2.4.tgz",
+      "integrity": "sha512-ck1lI+7r1mMJpqLNa3LJ5pxCfOB1lfJncKmRJeJxcJqcngaFwylreLP7da6Rrjr6u2gVRTfmnkSkjc80IiQCwQ==",
+      "dev": true,
+      "requires": {
+        "glob": "7.1.7"
+      }
+    },
+    "@next/swc-android-arm-eabi": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.4.tgz",
+      "integrity": "sha512-FJg/6a3s2YrUaqZ+/DJZzeZqfxbbWrynQMT1C5wlIEq9aDLXCFpPM/PiOyJh0ahxc0XPmi6uo38Poq+GJTuKWw==",
+      "dev": true,
+      "optional": true
+    },
+    "@next/swc-android-arm64": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.1.4.tgz",
+      "integrity": "sha512-LXraazvQQFBgxIg3Htny6G5V5he9EK7oS4jWtMdTGIikmD/OGByOv8ZjLuVLZLtVm3UIvaAiGtlQSLecxJoJDw==",
+      "dev": true,
+      "optional": true
+    },
+    "@next/swc-darwin-arm64": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.4.tgz",
+      "integrity": "sha512-SSST/dBymecllZxcqTCcSTCu5o1NKk9I+xcvhn/O9nH6GWjgvGgGkNqLbCarCa0jJ1ukvlBA138FagyrmZ/4rQ==",
+      "dev": true,
+      "optional": true
+    },
+    "@next/swc-darwin-x64": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.4.tgz",
+      "integrity": "sha512-p1lwdX0TVjaoDXQVuAkjtxVBbCL/urgxiMCBwuPDO7TikpXtSRivi+mIzBj5q7ypgICFmIAOW3TyupXeoPRAnA==",
+      "dev": true,
+      "optional": true
+    },
+    "@next/swc-linux-arm-gnueabihf": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.4.tgz",
+      "integrity": "sha512-67PZlgkCn3TDxacdVft0xqDCL7Io1/C4xbAs0+oSQ0xzp6OzN2RNpuKjHJrJgKd0DsE1XZ9sCP27Qv0591yfyg==",
+      "dev": true,
+      "optional": true
+    },
+    "@next/swc-linux-arm64-gnu": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.4.tgz",
+      "integrity": "sha512-OnOWixhhw7aU22TQdQLYrgpgFq0oA1wGgnjAiHJ+St7MLj82KTDyM9UcymAMbGYy6nG/TFOOHdTmRMtCRNOw0g==",
+      "dev": true,
+      "optional": true
+    },
+    "@next/swc-linux-arm64-musl": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.4.tgz",
+      "integrity": "sha512-UoRMzPZnsAavdWtVylYxH8DNC7Uy0i6RrvNwT4PyQVdfANBn2omsUkcH5lgS2O7oaz0nAYLk1vqyZDO7+tJotA==",
+      "dev": true,
+      "optional": true
+    },
+    "@next/swc-linux-x64-gnu": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.4.tgz",
+      "integrity": "sha512-nM+MA/frxlTLUKLJKorctdI20/ugfHRjVEEkcLp/58LGG7slNaP1E5d5dRA1yX6ISjPcQAkywas5VlGCg+uTvA==",
+      "dev": true,
+      "optional": true
+    },
+    "@next/swc-linux-x64-musl": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.4.tgz",
+      "integrity": "sha512-GoRHxkuW4u4yKw734B9SzxJwVdyEJosaZ62P7ifOwcujTxhgBt3y76V2nNUrsSuopcKI2ZTDjaa+2wd5zyeXbA==",
+      "dev": true,
+      "optional": true
+    },
+    "@next/swc-win32-arm64-msvc": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.4.tgz",
+      "integrity": "sha512-6TQkQze0ievXwHJcVUrIULwCYVe3ccX6T0JgZ1SiMeXpHxISN7VJF/O8uSCw1JvXZYZ6ud0CJ7nfC5HXivgfPg==",
+      "dev": true,
+      "optional": true
+    },
+    "@next/swc-win32-ia32-msvc": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.4.tgz",
+      "integrity": "sha512-CsbX/IXuZ5VSmWCpSetG2HD6VO5FTsO39WNp2IR2Ut/uom9XtLDJAZqjQEnbUTLGHuwDKFjrIO3LkhtROXLE/g==",
+      "dev": true,
+      "optional": true
+    },
+    "@next/swc-win32-x64-msvc": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.4.tgz",
+      "integrity": "sha512-JtYuWzKXKLDMgE/xTcFtCm1MiCIRaAc5XYZfYX3n/ZWSI1SJS/GMm+Su0SAHJgRFavJh6U/p998YwO/iGTIgqQ==",
+      "dev": true,
+      "optional": true
+    },
+    "@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "requires": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      }
+    },
+    "@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true
+    },
+    "@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "requires": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      }
+    },
+    "@pkgr/utils": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz",
+      "integrity": "sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==",
+      "dev": true,
+      "requires": {
+        "cross-spawn": "^7.0.3",
+        "is-glob": "^4.0.3",
+        "open": "^8.4.0",
+        "picocolors": "^1.0.0",
+        "tiny-glob": "^0.2.9",
+        "tslib": "^2.4.0"
+      },
+      "dependencies": {
+        "open": {
+          "version": "8.4.2",
+          "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
+          "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
+          "dev": true,
+          "requires": {
+            "define-lazy-prop": "^2.0.0",
+            "is-docker": "^2.1.1",
+            "is-wsl": "^2.2.0"
+          }
+        },
+        "tslib": {
+          "version": "2.5.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+          "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
+          "dev": true
+        }
+      }
+    },
+    "@rushstack/eslint-patch": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz",
+      "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==",
+      "dev": true
+    },
+    "@sinonjs/commons": {
+      "version": "1.8.6",
+      "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz",
+      "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "type-detect": "4.0.8"
+      }
+    },
+    "@sinonjs/fake-timers": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz",
+      "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@sinonjs/commons": "^1.7.0"
+      }
+    },
+    "@stylelint/postcss-css-in-js": {
+      "version": "0.37.3",
+      "resolved": "https://registry.npmjs.org/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.3.tgz",
+      "integrity": "sha512-scLk3cSH1H9KggSniseb2KNAU5D9FWc3H7BxCSAIdtU9OWIyw0zkEZ9qEKHryRM+SExYXRKNb7tOOVNAsQ3iwg==",
+      "dev": true,
+      "requires": {
+        "@babel/core": "^7.17.9"
+      },
+      "dependencies": {
+        "@babel/core": {
+          "version": "7.21.3",
+          "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz",
+          "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==",
+          "dev": true,
+          "requires": {
+            "@ampproject/remapping": "^2.2.0",
+            "@babel/code-frame": "^7.18.6",
+            "@babel/generator": "^7.21.3",
+            "@babel/helper-compilation-targets": "^7.20.7",
+            "@babel/helper-module-transforms": "^7.21.2",
+            "@babel/helpers": "^7.21.0",
+            "@babel/parser": "^7.21.3",
+            "@babel/template": "^7.20.7",
+            "@babel/traverse": "^7.21.3",
+            "@babel/types": "^7.21.3",
+            "convert-source-map": "^1.7.0",
+            "debug": "^4.1.0",
+            "gensync": "^1.0.0-beta.2",
+            "json5": "^2.2.2",
+            "semver": "^6.3.0"
+          }
+        },
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
+        }
+      }
+    },
+    "@stylelint/postcss-markdown": {
+      "version": "0.36.2",
+      "resolved": "https://registry.npmjs.org/@stylelint/postcss-markdown/-/postcss-markdown-0.36.2.tgz",
+      "integrity": "sha512-2kGbqUVJUGE8dM+bMzXG/PYUWKkjLIkRLWNh39OaADkiabDRdw8ATFCgbMz5xdIcvwspPAluSL7uY+ZiTWdWmQ==",
+      "dev": true,
+      "requires": {
+        "remark": "^13.0.0",
+        "unist-util-find-all-after": "^3.0.2"
+      },
+      "dependencies": {
+        "remark": {
+          "version": "13.0.0",
+          "resolved": "https://registry.npmjs.org/remark/-/remark-13.0.0.tgz",
+          "integrity": "sha512-HDz1+IKGtOyWN+QgBiAT0kn+2s6ovOxHyPAFGKVE81VSzJ+mq7RwHFledEvB5F1p4iJvOah/LOKdFuzvRnNLCA==",
+          "dev": true,
+          "requires": {
+            "remark-parse": "^9.0.0",
+            "remark-stringify": "^9.0.0",
+            "unified": "^9.1.0"
+          }
+        },
+        "remark-parse": {
+          "version": "9.0.0",
+          "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz",
+          "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==",
+          "dev": true,
+          "requires": {
+            "mdast-util-from-markdown": "^0.8.0"
+          }
+        },
+        "remark-stringify": {
+          "version": "9.0.1",
+          "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-9.0.1.tgz",
+          "integrity": "sha512-mWmNg3ZtESvZS8fv5PTvaPckdL4iNlCHTt8/e/8oN08nArHRHjNZMKzA/YW3+p7/lYqIw4nx1XsjCBo/AxNChg==",
+          "dev": true,
+          "requires": {
+            "mdast-util-to-markdown": "^0.6.0"
+          }
+        }
+      }
+    },
+    "@tootallnate/once": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
+      "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+      "dev": true,
+      "peer": true
+    },
+    "@types/babel__core": {
+      "version": "7.20.0",
+      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz",
+      "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/parser": "^7.20.7",
+        "@babel/types": "^7.20.7",
+        "@types/babel__generator": "*",
+        "@types/babel__template": "*",
+        "@types/babel__traverse": "*"
+      }
+    },
+    "@types/babel__generator": {
+      "version": "7.6.4",
+      "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz",
+      "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "@types/babel__template": {
+      "version": "7.4.1",
+      "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz",
+      "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/parser": "^7.1.0",
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "@types/babel__traverse": {
+      "version": "7.18.3",
+      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz",
+      "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/types": "^7.3.0"
+      }
+    },
+    "@types/graceful-fs": {
+      "version": "4.1.6",
+      "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz",
+      "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
+    "@types/istanbul-lib-coverage": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
+      "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==",
+      "dev": true
+    },
+    "@types/istanbul-lib-report": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+      "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==",
+      "dev": true,
+      "requires": {
+        "@types/istanbul-lib-coverage": "*"
+      }
+    },
+    "@types/istanbul-reports": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz",
+      "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==",
+      "dev": true,
+      "requires": {
+        "@types/istanbul-lib-report": "*"
+      }
+    },
+    "@types/json-schema": {
+      "version": "7.0.11",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
+      "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
+      "dev": true
+    },
+    "@types/json5": {
+      "version": "0.0.29",
+      "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+      "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
+      "dev": true
+    },
+    "@types/mdast": {
+      "version": "3.0.10",
+      "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz",
+      "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==",
+      "dev": true,
+      "requires": {
+        "@types/unist": "*"
+      }
+    },
+    "@types/minimist": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz",
+      "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==",
+      "dev": true
+    },
+    "@types/node": {
+      "version": "18.15.3",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.3.tgz",
+      "integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==",
+      "dev": true
+    },
+    "@types/normalize-package-data": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz",
+      "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==",
+      "dev": true
+    },
+    "@types/parse-json": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+      "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+      "dev": true
+    },
+    "@types/prettier": {
+      "version": "2.7.2",
+      "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz",
+      "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==",
+      "dev": true,
+      "peer": true
+    },
+    "@types/semver": {
+      "version": "7.3.13",
+      "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
+      "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
+      "dev": true
+    },
+    "@types/stack-utils": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
+      "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
+      "dev": true,
+      "peer": true
+    },
+    "@types/supports-color": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/@types/supports-color/-/supports-color-8.1.1.tgz",
+      "integrity": "sha512-dPWnWsf+kzIG140B8z2w3fr5D03TLWbOAFQl45xUpI3vcizeXriNR5VYkWZ+WTMsUHqZ9Xlt3hrxGNANFyNQfw==",
+      "dev": true
+    },
+    "@types/unist": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
+      "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==",
+      "dev": true
+    },
+    "@types/yargs": {
+      "version": "15.0.15",
+      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz",
+      "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==",
+      "dev": true,
+      "requires": {
+        "@types/yargs-parser": "*"
+      }
+    },
+    "@types/yargs-parser": {
+      "version": "21.0.0",
+      "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz",
+      "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
+      "dev": true
+    },
+    "@typescript-eslint/eslint-plugin": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz",
+      "integrity": "sha512-IZGc50rtbjk+xp5YQoJvmMPmJEYoC53SiKPXyqWfv15XoD2Y5Kju6zN0DwlmaGJp1Iw33JsWJcQ7nw0lGCGjVg==",
+      "dev": true,
+      "requires": {
+        "@eslint-community/regexpp": "^4.4.0",
+        "@typescript-eslint/scope-manager": "5.55.0",
+        "@typescript-eslint/type-utils": "5.55.0",
+        "@typescript-eslint/utils": "5.55.0",
+        "debug": "^4.3.4",
+        "grapheme-splitter": "^1.0.4",
+        "ignore": "^5.2.0",
+        "natural-compare-lite": "^1.4.0",
+        "semver": "^7.3.7",
+        "tsutils": "^3.21.0"
+      },
+      "dependencies": {
+        "lru-cache": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+          "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+          "dev": true,
+          "requires": {
+            "yallist": "^4.0.0"
+          }
+        },
+        "semver": {
+          "version": "7.3.8",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+          "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "yallist": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+          "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+          "dev": true
+        }
+      }
+    },
+    "@typescript-eslint/parser": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.55.0.tgz",
+      "integrity": "sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/scope-manager": "5.55.0",
+        "@typescript-eslint/types": "5.55.0",
+        "@typescript-eslint/typescript-estree": "5.55.0",
+        "debug": "^4.3.4"
+      }
+    },
+    "@typescript-eslint/scope-manager": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz",
+      "integrity": "sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/types": "5.55.0",
+        "@typescript-eslint/visitor-keys": "5.55.0"
+      }
+    },
+    "@typescript-eslint/type-utils": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.55.0.tgz",
+      "integrity": "sha512-ObqxBgHIXj8rBNm0yh8oORFrICcJuZPZTqtAFh0oZQyr5DnAHZWfyw54RwpEEH+fD8suZaI0YxvWu5tYE/WswA==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/typescript-estree": "5.55.0",
+        "@typescript-eslint/utils": "5.55.0",
+        "debug": "^4.3.4",
+        "tsutils": "^3.21.0"
+      }
+    },
+    "@typescript-eslint/types": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz",
+      "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==",
+      "dev": true
+    },
+    "@typescript-eslint/typescript-estree": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz",
+      "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/types": "5.55.0",
+        "@typescript-eslint/visitor-keys": "5.55.0",
+        "debug": "^4.3.4",
+        "globby": "^11.1.0",
+        "is-glob": "^4.0.3",
+        "semver": "^7.3.7",
+        "tsutils": "^3.21.0"
+      },
+      "dependencies": {
+        "globby": {
+          "version": "11.1.0",
+          "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+          "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+          "dev": true,
+          "requires": {
+            "array-union": "^2.1.0",
+            "dir-glob": "^3.0.1",
+            "fast-glob": "^3.2.9",
+            "ignore": "^5.2.0",
+            "merge2": "^1.4.1",
+            "slash": "^3.0.0"
+          }
+        },
+        "lru-cache": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+          "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+          "dev": true,
+          "requires": {
+            "yallist": "^4.0.0"
+          }
+        },
+        "semver": {
+          "version": "7.3.8",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+          "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "slash": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+          "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+          "dev": true
+        },
+        "yallist": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+          "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+          "dev": true
+        }
+      }
+    },
+    "@typescript-eslint/utils": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.55.0.tgz",
+      "integrity": "sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw==",
+      "dev": true,
+      "requires": {
+        "@eslint-community/eslint-utils": "^4.2.0",
+        "@types/json-schema": "^7.0.9",
+        "@types/semver": "^7.3.12",
+        "@typescript-eslint/scope-manager": "5.55.0",
+        "@typescript-eslint/types": "5.55.0",
+        "@typescript-eslint/typescript-estree": "5.55.0",
+        "eslint-scope": "^5.1.1",
+        "semver": "^7.3.7"
+      },
+      "dependencies": {
+        "lru-cache": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+          "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+          "dev": true,
+          "requires": {
+            "yallist": "^4.0.0"
+          }
+        },
+        "semver": {
+          "version": "7.3.8",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+          "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "yallist": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+          "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+          "dev": true
+        }
+      }
+    },
+    "@typescript-eslint/visitor-keys": {
+      "version": "5.55.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz",
+      "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/types": "5.55.0",
+        "eslint-visitor-keys": "^3.3.0"
+      }
+    },
+    "abab": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
+      "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
+      "dev": true,
+      "peer": true
+    },
+    "acorn": {
+      "version": "8.8.2",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
+      "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
+      "dev": true
+    },
+    "acorn-globals": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz",
+      "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "acorn": "^7.1.1",
+        "acorn-walk": "^7.1.1"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "7.4.1",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+          "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true,
+      "requires": {}
+    },
+    "acorn-walk": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
+      "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
+      "dev": true,
+      "peer": true
+    },
+    "agent-base": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "debug": "4"
+      }
+    },
+    "aggregate-error": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+      "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+      "dev": true,
+      "requires": {
+        "clean-stack": "^2.0.0",
+        "indent-string": "^4.0.0"
+      }
+    },
+    "ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "dev": true,
+      "requires": {
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      }
+    },
+    "ansi-colors": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+      "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
+      "dev": true
+    },
+    "ansi-escapes": {
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+      "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+      "dev": true,
+      "requires": {
+        "type-fest": "^0.21.3"
+      }
+    },
+    "ansi-regex": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+      "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+      "dev": true
+    },
+    "ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "requires": {
+        "color-convert": "^1.9.0"
+      }
+    },
+    "anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      }
+    },
+    "argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true
+    },
+    "aria-query": {
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz",
+      "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==",
+      "dev": true,
+      "requires": {
+        "deep-equal": "^2.0.5"
+      }
+    },
+    "arr-diff": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+      "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==",
+      "dev": true,
+      "peer": true
+    },
+    "arr-flatten": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+      "dev": true,
+      "peer": true
+    },
+    "arr-union": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+      "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
+      "dev": true,
+      "peer": true
+    },
+    "array-buffer-byte-length": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz",
+      "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "is-array-buffer": "^3.0.1"
+      }
+    },
+    "array-includes": {
+      "version": "3.1.6",
+      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz",
+      "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4",
+        "get-intrinsic": "^1.1.3",
+        "is-string": "^1.0.7"
+      }
+    },
+    "array-union": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+      "dev": true
+    },
+    "array-unique": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+      "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==",
+      "dev": true,
+      "peer": true
+    },
+    "array.prototype.flat": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz",
+      "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4",
+        "es-shim-unscopables": "^1.0.0"
+      }
+    },
+    "array.prototype.flatmap": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz",
+      "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4",
+        "es-shim-unscopables": "^1.0.0"
+      }
+    },
+    "array.prototype.tosorted": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz",
+      "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4",
+        "es-shim-unscopables": "^1.0.0",
+        "get-intrinsic": "^1.1.3"
+      }
+    },
+    "arrify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+      "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
+      "dev": true
+    },
+    "assign-symbols": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+      "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==",
+      "dev": true,
+      "peer": true
+    },
+    "ast-types-flow": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
+      "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==",
+      "dev": true
+    },
+    "astral-regex": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+      "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+      "dev": true
+    },
+    "async": {
+      "version": "3.2.4",
+      "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
+      "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
+      "dev": true
+    },
+    "asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+      "dev": true
+    },
+    "at-least-node": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+      "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+      "dev": true
+    },
+    "atob": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+      "dev": true,
+      "peer": true
+    },
+    "autoprefixer": {
+      "version": "9.8.8",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.8.tgz",
+      "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==",
+      "dev": true,
+      "requires": {
+        "browserslist": "^4.12.0",
+        "caniuse-lite": "^1.0.30001109",
+        "normalize-range": "^0.1.2",
+        "num2fraction": "^1.2.2",
+        "picocolors": "^0.2.1",
+        "postcss": "^7.0.32",
+        "postcss-value-parser": "^4.1.0"
+      },
+      "dependencies": {
+        "picocolors": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+          "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+          "dev": true
+        },
+        "postcss": {
+          "version": "7.0.39",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+          "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+          "dev": true,
+          "requires": {
+            "picocolors": "^0.2.1",
+            "source-map": "^0.6.1"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "available-typed-arrays": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
+      "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
+      "dev": true
+    },
+    "axe-core": {
+      "version": "4.6.3",
+      "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.3.tgz",
+      "integrity": "sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg==",
+      "dev": true
+    },
+    "axobject-query": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz",
+      "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==",
+      "dev": true,
+      "requires": {
+        "deep-equal": "^2.0.5"
+      }
+    },
+    "babel-jest": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz",
+      "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/transform": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/babel__core": "^7.1.7",
+        "babel-plugin-istanbul": "^6.0.0",
+        "babel-preset-jest": "^26.6.2",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.4",
+        "slash": "^3.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "slash": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+          "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "babel-plugin-istanbul": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
+      "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.0.0",
+        "@istanbuljs/load-nyc-config": "^1.0.0",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-instrument": "^5.0.4",
+        "test-exclude": "^6.0.0"
+      },
+      "dependencies": {
+        "istanbul-lib-instrument": {
+          "version": "5.2.1",
+          "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
+          "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "@babel/core": "^7.12.3",
+            "@babel/parser": "^7.14.7",
+            "@istanbuljs/schema": "^0.1.2",
+            "istanbul-lib-coverage": "^3.2.0",
+            "semver": "^6.3.0"
+          }
+        },
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "babel-plugin-jest-hoist": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz",
+      "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/template": "^7.3.3",
+        "@babel/types": "^7.3.3",
+        "@types/babel__core": "^7.0.0",
+        "@types/babel__traverse": "^7.0.6"
+      }
+    },
+    "babel-preset-current-node-syntax": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz",
+      "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/plugin-syntax-async-generators": "^7.8.4",
+        "@babel/plugin-syntax-bigint": "^7.8.3",
+        "@babel/plugin-syntax-class-properties": "^7.8.3",
+        "@babel/plugin-syntax-import-meta": "^7.8.3",
+        "@babel/plugin-syntax-json-strings": "^7.8.3",
+        "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3",
+        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
+        "@babel/plugin-syntax-numeric-separator": "^7.8.3",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+        "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
+        "@babel/plugin-syntax-optional-chaining": "^7.8.3",
+        "@babel/plugin-syntax-top-level-await": "^7.8.3"
+      }
+    },
+    "babel-preset-jest": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz",
+      "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "babel-plugin-jest-hoist": "^26.6.2",
+        "babel-preset-current-node-syntax": "^1.0.0"
+      }
+    },
+    "bail": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
+      "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==",
+      "dev": true
+    },
+    "balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "dev": true
+    },
+    "base": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+      "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "cache-base": "^1.0.1",
+        "class-utils": "^0.3.5",
+        "component-emitter": "^1.2.1",
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.1",
+        "mixin-deep": "^1.2.0",
+        "pascalcase": "^0.1.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        }
+      }
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "requires": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dev": true,
+      "requires": {
+        "fill-range": "^7.0.1"
+      }
+    },
+    "browser-process-hrtime": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz",
+      "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==",
+      "dev": true,
+      "peer": true
+    },
+    "browserslist": {
+      "version": "4.21.5",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
+      "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
+      "dev": true,
+      "requires": {
+        "caniuse-lite": "^1.0.30001449",
+        "electron-to-chromium": "^1.4.284",
+        "node-releases": "^2.0.8",
+        "update-browserslist-db": "^1.0.10"
+      }
+    },
+    "bs-logger": {
+      "version": "0.2.6",
+      "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz",
+      "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==",
+      "dev": true,
+      "requires": {
+        "fast-json-stable-stringify": "2.x"
+      }
+    },
+    "bser": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
+      "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "node-int64": "^0.4.0"
+      }
+    },
+    "buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "dev": true
+    },
+    "cache-base": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+      "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "collection-visit": "^1.0.0",
+        "component-emitter": "^1.2.1",
+        "get-value": "^2.0.6",
+        "has-value": "^1.0.0",
+        "isobject": "^3.0.1",
+        "set-value": "^2.0.0",
+        "to-object-path": "^0.3.0",
+        "union-value": "^1.0.0",
+        "unset-value": "^1.0.0"
+      }
+    },
+    "call-bind": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.1",
+        "get-intrinsic": "^1.0.2"
+      }
+    },
+    "callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true
+    },
+    "camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "dev": true
+    },
+    "camelcase-keys": {
+      "version": "6.2.2",
+      "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz",
+      "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==",
+      "dev": true,
+      "requires": {
+        "camelcase": "^5.3.1",
+        "map-obj": "^4.0.0",
+        "quick-lru": "^4.0.1"
+      }
+    },
+    "caniuse-lite": {
+      "version": "1.0.30001466",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001466.tgz",
+      "integrity": "sha512-ewtFBSfWjEmxUgNBSZItFSmVtvk9zkwkl1OfRZlKA8slltRN+/C/tuGVrF9styXkN36Yu3+SeJ1qkXxDEyNZ5w==",
+      "dev": true
+    },
+    "capture-exit": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz",
+      "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "rsvp": "^4.8.4"
+      }
+    },
+    "ccount": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz",
+      "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==",
+      "dev": true
+    },
+    "chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      }
+    },
+    "char-regex": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
+      "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
+      "dev": true,
+      "peer": true
+    },
+    "character-entities": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
+      "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
+      "dev": true
+    },
+    "character-entities-html4": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz",
+      "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==",
+      "dev": true
+    },
+    "character-entities-legacy": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
+      "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
+      "dev": true
+    },
+    "character-reference-invalid": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
+      "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
+      "dev": true
+    },
+    "chardet": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+      "dev": true
+    },
+    "ci-info": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+      "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+      "dev": true
+    },
+    "cjs-module-lexer": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz",
+      "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==",
+      "dev": true,
+      "peer": true
+    },
+    "class-utils": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+      "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "define-property": "^0.2.5",
+        "isobject": "^3.0.0",
+        "static-extend": "^0.1.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+          "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "is-buffer": {
+          "version": "1.1.6",
+          "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+          "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+          "dev": true,
+          "peer": true
+        },
+        "is-data-descriptor": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+          "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "is-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+          "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-accessor-descriptor": "^0.1.6",
+            "is-data-descriptor": "^0.1.4",
+            "kind-of": "^5.0.0"
+          }
+        },
+        "kind-of": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "clean-stack": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+      "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+      "dev": true
+    },
+    "cli-cursor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+      "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+      "dev": true,
+      "requires": {
+        "restore-cursor": "^3.1.0"
+      }
+    },
+    "cli-truncate": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
+      "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
+      "dev": true,
+      "requires": {
+        "slice-ansi": "^3.0.0",
+        "string-width": "^4.2.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "4.2.3",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.1"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        }
+      }
+    },
+    "cli-width": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
+      "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
+      "dev": true
+    },
+    "cliui": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+      "dev": true,
+      "requires": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.1",
+        "wrap-ansi": "^7.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "4.2.3",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.1"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        }
+      }
+    },
+    "clone-regexp": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz",
+      "integrity": "sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==",
+      "dev": true,
+      "requires": {
+        "is-regexp": "^2.0.0"
+      },
+      "dependencies": {
+        "is-regexp": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz",
+          "integrity": "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==",
+          "dev": true
+        }
+      }
+    },
+    "co": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+      "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
+      "dev": true,
+      "peer": true
+    },
+    "collapse-white-space": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz",
+      "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==",
+      "dev": true
+    },
+    "collect-v8-coverage": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
+      "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==",
+      "dev": true,
+      "peer": true
+    },
+    "collection-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+      "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "map-visit": "^1.0.0",
+        "object-visit": "^1.0.0"
+      }
+    },
+    "color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "requires": {
+        "color-name": "1.1.3"
+      }
+    },
+    "color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+      "dev": true
+    },
+    "colorette": {
+      "version": "2.0.19",
+      "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
+      "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
+      "dev": true
+    },
+    "combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "dev": true,
+      "requires": {
+        "delayed-stream": "~1.0.0"
+      }
+    },
+    "commander": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+      "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+      "dev": true
+    },
+    "component-emitter": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+      "dev": true,
+      "peer": true
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "dev": true
+    },
+    "convert-source-map": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+      "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+      "dev": true
+    },
+    "copy-descriptor": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+      "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==",
+      "dev": true,
+      "peer": true
+    },
+    "cosmiconfig": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
+      "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
+      "dev": true,
+      "requires": {
+        "@types/parse-json": "^4.0.0",
+        "import-fresh": "^3.2.1",
+        "parse-json": "^5.0.0",
+        "path-type": "^4.0.0",
+        "yaml": "^1.10.0"
+      },
+      "dependencies": {
+        "yaml": {
+          "version": "1.10.2",
+          "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+          "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+          "dev": true
+        }
+      }
+    },
+    "cross-fetch": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
+      "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
+      "dev": true,
+      "requires": {
+        "node-fetch": "2.6.7"
+      }
+    },
+    "cross-spawn": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+      "dev": true,
+      "requires": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      }
+    },
+    "cssesc": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+      "dev": true
+    },
+    "cssom": {
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz",
+      "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==",
+      "dev": true,
+      "peer": true
+    },
+    "cssstyle": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz",
+      "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "cssom": "~0.3.6"
+      },
+      "dependencies": {
+        "cssom": {
+          "version": "0.3.8",
+          "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
+          "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "damerau-levenshtein": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
+      "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
+      "dev": true
+    },
+    "data-urls": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
+      "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "abab": "^2.0.3",
+        "whatwg-mimetype": "^2.3.0",
+        "whatwg-url": "^8.0.0"
+      }
+    },
+    "debug": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+      "dev": true,
+      "requires": {
+        "ms": "2.1.2"
+      }
+    },
+    "decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+      "dev": true
+    },
+    "decamelize-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz",
+      "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==",
+      "dev": true,
+      "requires": {
+        "decamelize": "^1.1.0",
+        "map-obj": "^1.0.0"
+      },
+      "dependencies": {
+        "map-obj": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+          "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==",
+          "dev": true
+        }
+      }
+    },
+    "decimal.js": {
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
+      "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
+      "dev": true,
+      "peer": true
+    },
+    "decode-uri-component": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
+      "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
+      "dev": true,
+      "peer": true
+    },
+    "deep-equal": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz",
+      "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "es-get-iterator": "^1.1.2",
+        "get-intrinsic": "^1.1.3",
+        "is-arguments": "^1.1.1",
+        "is-array-buffer": "^3.0.1",
+        "is-date-object": "^1.0.5",
+        "is-regex": "^1.1.4",
+        "is-shared-array-buffer": "^1.0.2",
+        "isarray": "^2.0.5",
+        "object-is": "^1.1.5",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.4",
+        "regexp.prototype.flags": "^1.4.3",
+        "side-channel": "^1.0.4",
+        "which-boxed-primitive": "^1.0.2",
+        "which-collection": "^1.0.1",
+        "which-typed-array": "^1.1.9"
+      }
+    },
+    "deep-is": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+      "dev": true
+    },
+    "deepmerge": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz",
+      "integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==",
+      "dev": true,
+      "peer": true
+    },
+    "define-lazy-prop": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
+      "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
+      "dev": true
+    },
+    "define-properties": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz",
+      "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==",
+      "dev": true,
+      "requires": {
+        "has-property-descriptors": "^1.0.0",
+        "object-keys": "^1.1.1"
+      }
+    },
+    "define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
+      }
+    },
+    "delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+      "dev": true
+    },
+    "detect-newline": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
+      "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
+      "dev": true,
+      "peer": true
+    },
+    "diff-sequences": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
+      "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==",
+      "dev": true,
+      "peer": true
+    },
+    "dir-glob": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+      "dev": true,
+      "requires": {
+        "path-type": "^4.0.0"
+      }
+    },
+    "doctrine": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+      "dev": true,
+      "requires": {
+        "esutils": "^2.0.2"
+      }
+    },
+    "dom-serializer": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
+      "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "^2.0.1",
+        "entities": "^2.0.0"
+      },
+      "dependencies": {
+        "domelementtype": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+          "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+          "dev": true
+        },
+        "entities": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+          "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+          "dev": true
+        }
+      }
+    },
+    "domelementtype": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+      "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
+      "dev": true
+    },
+    "domexception": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
+      "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "webidl-conversions": "^5.0.0"
+      },
+      "dependencies": {
+        "webidl-conversions": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
+          "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "domhandler": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
+      "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "1"
+      }
+    },
+    "domutils": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
+      "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
+      "dev": true,
+      "requires": {
+        "dom-serializer": "0",
+        "domelementtype": "1"
+      }
+    },
+    "eastasianwidth": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+      "dev": true
+    },
+    "ejs": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.5.tgz",
+      "integrity": "sha512-dldq3ZfFtgVTJMLjOe+/3sROTzALlL9E34V4/sDtUd/KlBSS0s6U1/+WPE1B4sj9CXHJpL1M6rhNJnc9Wbal9w==",
+      "dev": true,
+      "requires": {
+        "jake": "^10.6.1"
+      }
+    },
+    "electron-to-chromium": {
+      "version": "1.4.332",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.332.tgz",
+      "integrity": "sha512-c1Vbv5tuUlBFp0mb3mCIjw+REEsgthRgNE8BlbEDKmvzb8rxjcVki6OkQP83vLN34s0XCxpSkq7AZNep1a6xhw==",
+      "dev": true
+    },
+    "emittery": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz",
+      "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==",
+      "dev": true,
+      "peer": true
+    },
+    "emoji-regex": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+      "dev": true
+    },
+    "end-of-stream": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "once": "^1.4.0"
+      }
+    },
+    "enhanced-resolve": {
+      "version": "5.12.0",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz",
+      "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.2.4",
+        "tapable": "^2.2.0"
+      }
+    },
+    "enquirer": {
+      "version": "2.3.6",
+      "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
+      "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
+      "dev": true,
+      "requires": {
+        "ansi-colors": "^4.1.1"
+      }
+    },
+    "entities": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+      "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
+      "dev": true
+    },
+    "error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dev": true,
+      "requires": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "es-abstract": {
+      "version": "1.21.2",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz",
+      "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==",
+      "dev": true,
+      "requires": {
+        "array-buffer-byte-length": "^1.0.0",
+        "available-typed-arrays": "^1.0.5",
+        "call-bind": "^1.0.2",
+        "es-set-tostringtag": "^2.0.1",
+        "es-to-primitive": "^1.2.1",
+        "function.prototype.name": "^1.1.5",
+        "get-intrinsic": "^1.2.0",
+        "get-symbol-description": "^1.0.0",
+        "globalthis": "^1.0.3",
+        "gopd": "^1.0.1",
+        "has": "^1.0.3",
+        "has-property-descriptors": "^1.0.0",
+        "has-proto": "^1.0.1",
+        "has-symbols": "^1.0.3",
+        "internal-slot": "^1.0.5",
+        "is-array-buffer": "^3.0.2",
+        "is-callable": "^1.2.7",
+        "is-negative-zero": "^2.0.2",
+        "is-regex": "^1.1.4",
+        "is-shared-array-buffer": "^1.0.2",
+        "is-string": "^1.0.7",
+        "is-typed-array": "^1.1.10",
+        "is-weakref": "^1.0.2",
+        "object-inspect": "^1.12.3",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.4",
+        "regexp.prototype.flags": "^1.4.3",
+        "safe-regex-test": "^1.0.0",
+        "string.prototype.trim": "^1.2.7",
+        "string.prototype.trimend": "^1.0.6",
+        "string.prototype.trimstart": "^1.0.6",
+        "typed-array-length": "^1.0.4",
+        "unbox-primitive": "^1.0.2",
+        "which-typed-array": "^1.1.9"
+      }
+    },
+    "es-get-iterator": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
+      "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.3",
+        "has-symbols": "^1.0.3",
+        "is-arguments": "^1.1.1",
+        "is-map": "^2.0.2",
+        "is-set": "^2.0.2",
+        "is-string": "^1.0.7",
+        "isarray": "^2.0.5",
+        "stop-iteration-iterator": "^1.0.0"
+      }
+    },
+    "es-set-tostringtag": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
+      "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==",
+      "dev": true,
+      "requires": {
+        "get-intrinsic": "^1.1.3",
+        "has": "^1.0.3",
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "es-shim-unscopables": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
+      "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
+      "dev": true,
+      "requires": {
+        "has": "^1.0.3"
+      }
+    },
+    "es-to-primitive": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+      "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+      "dev": true,
+      "requires": {
+        "is-callable": "^1.1.4",
+        "is-date-object": "^1.0.1",
+        "is-symbol": "^1.0.2"
+      }
+    },
+    "escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "dev": true
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "dev": true
+    },
+    "escodegen": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz",
+      "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "esprima": "^4.0.1",
+        "estraverse": "^5.2.0",
+        "esutils": "^2.0.2",
+        "optionator": "^0.8.1",
+        "source-map": "~0.6.1"
+      },
+      "dependencies": {
+        "levn": {
+          "version": "0.3.0",
+          "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+          "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "prelude-ls": "~1.1.2",
+            "type-check": "~0.3.2"
+          }
+        },
+        "optionator": {
+          "version": "0.8.3",
+          "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+          "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "deep-is": "~0.1.3",
+            "fast-levenshtein": "~2.0.6",
+            "levn": "~0.3.0",
+            "prelude-ls": "~1.1.2",
+            "type-check": "~0.3.2",
+            "word-wrap": "~1.2.3"
+          }
+        },
+        "prelude-ls": {
+          "version": "1.1.2",
+          "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+          "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
+          "dev": true,
+          "peer": true
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true,
+          "optional": true,
+          "peer": true
+        },
+        "type-check": {
+          "version": "0.3.2",
+          "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+          "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "prelude-ls": "~1.1.2"
+          }
+        }
+      }
+    },
+    "eslint": {
+      "version": "8.36.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz",
+      "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==",
+      "dev": true,
+      "requires": {
+        "@eslint-community/eslint-utils": "^4.2.0",
+        "@eslint-community/regexpp": "^4.4.0",
+        "@eslint/eslintrc": "^2.0.1",
+        "@eslint/js": "8.36.0",
+        "@humanwhocodes/config-array": "^0.11.8",
+        "@humanwhocodes/module-importer": "^1.0.1",
+        "@nodelib/fs.walk": "^1.2.8",
+        "ajv": "^6.10.0",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.2",
+        "debug": "^4.3.2",
+        "doctrine": "^3.0.0",
+        "escape-string-regexp": "^4.0.0",
+        "eslint-scope": "^7.1.1",
+        "eslint-visitor-keys": "^3.3.0",
+        "espree": "^9.5.0",
+        "esquery": "^1.4.2",
+        "esutils": "^2.0.2",
+        "fast-deep-equal": "^3.1.3",
+        "file-entry-cache": "^6.0.1",
+        "find-up": "^5.0.0",
+        "glob-parent": "^6.0.2",
+        "globals": "^13.19.0",
+        "grapheme-splitter": "^1.0.4",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.0.0",
+        "imurmurhash": "^0.1.4",
+        "is-glob": "^4.0.0",
+        "is-path-inside": "^3.0.3",
+        "js-sdsl": "^4.1.4",
+        "js-yaml": "^4.1.0",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "levn": "^0.4.1",
+        "lodash.merge": "^4.6.2",
+        "minimatch": "^3.1.2",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.1",
+        "strip-ansi": "^6.0.1",
+        "strip-json-comments": "^3.1.0",
+        "text-table": "^0.2.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "escape-string-regexp": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+          "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+          "dev": true
+        },
+        "eslint-scope": {
+          "version": "7.1.1",
+          "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+          "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+          "dev": true,
+          "requires": {
+            "esrecurse": "^4.3.0",
+            "estraverse": "^5.2.0"
+          }
+        },
+        "find-up": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+          "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^6.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "glob-parent": {
+          "version": "6.0.2",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+          "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+          "dev": true,
+          "requires": {
+            "is-glob": "^4.0.3"
+          }
+        },
+        "globals": {
+          "version": "13.20.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
+          "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+          "dev": true,
+          "requires": {
+            "type-fest": "^0.20.2"
+          }
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "locate-path": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+          "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^5.0.0"
+          }
+        },
+        "p-limit": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+          "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+          "dev": true,
+          "requires": {
+            "yocto-queue": "^0.1.0"
+          }
+        },
+        "p-locate": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+          "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^3.0.2"
+          }
+        },
+        "path-exists": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+          "dev": true
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        },
+        "type-fest": {
+          "version": "0.20.2",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+          "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+          "dev": true
+        },
+        "yocto-queue": {
+          "version": "0.1.0",
+          "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+          "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+          "dev": true
+        }
+      }
+    },
+    "eslint-config-next": {
+      "version": "13.2.4",
+      "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.2.4.tgz",
+      "integrity": "sha512-lunIBhsoeqw6/Lfkd6zPt25w1bn0znLA/JCL+au1HoEpSb4/PpsOYsYtgV/q+YPsoKIOzFyU5xnb04iZnXjUvg==",
+      "dev": true,
+      "requires": {
+        "@next/eslint-plugin-next": "13.2.4",
+        "@rushstack/eslint-patch": "^1.1.3",
+        "@typescript-eslint/parser": "^5.42.0",
+        "eslint-import-resolver-node": "^0.3.6",
+        "eslint-import-resolver-typescript": "^3.5.2",
+        "eslint-plugin-import": "^2.26.0",
+        "eslint-plugin-jsx-a11y": "^6.5.1",
+        "eslint-plugin-react": "^7.31.7",
+        "eslint-plugin-react-hooks": "^4.5.0"
+      }
+    },
+    "eslint-config-prettier": {
+      "version": "8.7.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.7.0.tgz",
+      "integrity": "sha512-HHVXLSlVUhMSmyW4ZzEuvjpwqamgmlfkutD53cYXLikh4pt/modINRcCIApJ84czDxM4GZInwUrromsDdTImTA==",
+      "dev": true,
+      "requires": {}
+    },
+    "eslint-import-resolver-node": {
+      "version": "0.3.7",
+      "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz",
+      "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==",
+      "dev": true,
+      "requires": {
+        "debug": "^3.2.7",
+        "is-core-module": "^2.11.0",
+        "resolve": "^1.22.1"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.2.7",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        }
+      }
+    },
+    "eslint-import-resolver-typescript": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.3.tgz",
+      "integrity": "sha512-njRcKYBc3isE42LaTcJNVANR3R99H9bAxBDMNDr2W7yq5gYPxbU3MkdhsQukxZ/Xg9C2vcyLlDsbKfRDg0QvCQ==",
+      "dev": true,
+      "requires": {
+        "debug": "^4.3.4",
+        "enhanced-resolve": "^5.10.0",
+        "get-tsconfig": "^4.2.0",
+        "globby": "^13.1.2",
+        "is-core-module": "^2.10.0",
+        "is-glob": "^4.0.3",
+        "synckit": "^0.8.4"
+      }
+    },
+    "eslint-module-utils": {
+      "version": "2.7.4",
+      "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz",
+      "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==",
+      "dev": true,
+      "requires": {
+        "debug": "^3.2.7"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.2.7",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        }
+      }
+    },
+    "eslint-plugin-import": {
+      "version": "2.27.5",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz",
+      "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==",
+      "dev": true,
+      "requires": {
+        "array-includes": "^3.1.6",
+        "array.prototype.flat": "^1.3.1",
+        "array.prototype.flatmap": "^1.3.1",
+        "debug": "^3.2.7",
+        "doctrine": "^2.1.0",
+        "eslint-import-resolver-node": "^0.3.7",
+        "eslint-module-utils": "^2.7.4",
+        "has": "^1.0.3",
+        "is-core-module": "^2.11.0",
+        "is-glob": "^4.0.3",
+        "minimatch": "^3.1.2",
+        "object.values": "^1.1.6",
+        "resolve": "^1.22.1",
+        "semver": "^6.3.0",
+        "tsconfig-paths": "^3.14.1"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.2.7",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "doctrine": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+          "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+          "dev": true,
+          "requires": {
+            "esutils": "^2.0.2"
+          }
+        },
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
+        }
+      }
+    },
+    "eslint-plugin-jsx-a11y": {
+      "version": "6.7.1",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz",
+      "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==",
+      "dev": true,
+      "requires": {
+        "@babel/runtime": "^7.20.7",
+        "aria-query": "^5.1.3",
+        "array-includes": "^3.1.6",
+        "array.prototype.flatmap": "^1.3.1",
+        "ast-types-flow": "^0.0.7",
+        "axe-core": "^4.6.2",
+        "axobject-query": "^3.1.1",
+        "damerau-levenshtein": "^1.0.8",
+        "emoji-regex": "^9.2.2",
+        "has": "^1.0.3",
+        "jsx-ast-utils": "^3.3.3",
+        "language-tags": "=1.0.5",
+        "minimatch": "^3.1.2",
+        "object.entries": "^1.1.6",
+        "object.fromentries": "^2.0.6",
+        "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
+        }
+      }
+    },
+    "eslint-plugin-prettier": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
+      "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
+      "dev": true,
+      "requires": {
+        "prettier-linter-helpers": "^1.0.0"
+      }
+    },
+    "eslint-plugin-react": {
+      "version": "7.32.2",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz",
+      "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==",
+      "dev": true,
+      "requires": {
+        "array-includes": "^3.1.6",
+        "array.prototype.flatmap": "^1.3.1",
+        "array.prototype.tosorted": "^1.1.1",
+        "doctrine": "^2.1.0",
+        "estraverse": "^5.3.0",
+        "jsx-ast-utils": "^2.4.1 || ^3.0.0",
+        "minimatch": "^3.1.2",
+        "object.entries": "^1.1.6",
+        "object.fromentries": "^2.0.6",
+        "object.hasown": "^1.1.2",
+        "object.values": "^1.1.6",
+        "prop-types": "^15.8.1",
+        "resolve": "^2.0.0-next.4",
+        "semver": "^6.3.0",
+        "string.prototype.matchall": "^4.0.8"
+      },
+      "dependencies": {
+        "doctrine": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+          "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+          "dev": true,
+          "requires": {
+            "esutils": "^2.0.2"
+          }
+        },
+        "resolve": {
+          "version": "2.0.0-next.4",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz",
+          "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==",
+          "dev": true,
+          "requires": {
+            "is-core-module": "^2.9.0",
+            "path-parse": "^1.0.7",
+            "supports-preserve-symlinks-flag": "^1.0.0"
+          }
+        },
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
+        }
+      }
+    },
+    "eslint-plugin-react-hooks": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
+      "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
+      "dev": true,
+      "requires": {}
+    },
+    "eslint-scope": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+      "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+      "dev": true,
+      "requires": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^4.1.1"
+      },
+      "dependencies": {
+        "estraverse": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+          "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+          "dev": true
+        }
+      }
+    },
+    "eslint-visitor-keys": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+      "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+      "dev": true
+    },
+    "espree": {
+      "version": "9.5.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz",
+      "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==",
+      "dev": true,
+      "requires": {
+        "acorn": "^8.8.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^3.3.0"
+      }
+    },
+    "esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true,
+      "peer": true
+    },
+    "esquery": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
+      "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
+      "dev": true,
+      "requires": {
+        "estraverse": "^5.1.0"
+      }
+    },
+    "esrecurse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+      "dev": true,
+      "requires": {
+        "estraverse": "^5.2.0"
+      }
+    },
+    "estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true
+    },
+    "esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "dev": true
+    },
+    "exec-sh": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz",
+      "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==",
+      "dev": true,
+      "peer": true
+    },
+    "execa": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
+      "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "cross-spawn": "^7.0.0",
+        "get-stream": "^5.0.0",
+        "human-signals": "^1.1.1",
+        "is-stream": "^2.0.0",
+        "merge-stream": "^2.0.0",
+        "npm-run-path": "^4.0.0",
+        "onetime": "^5.1.0",
+        "signal-exit": "^3.0.2",
+        "strip-final-newline": "^2.0.0"
+      }
+    },
+    "execall": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz",
+      "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==",
+      "dev": true,
+      "requires": {
+        "clone-regexp": "^2.1.0"
+      }
+    },
+    "exit": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+      "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
+      "dev": true,
+      "peer": true
+    },
+    "expand-brackets": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+      "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "debug": "^2.3.3",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "posix-character-classes": "^0.1.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+          "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "is-buffer": {
+          "version": "1.1.6",
+          "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+          "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+          "dev": true,
+          "peer": true
+        },
+        "is-data-descriptor": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+          "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "is-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+          "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-accessor-descriptor": "^0.1.6",
+            "is-data-descriptor": "^0.1.4",
+            "kind-of": "^5.0.0"
+          }
+        },
+        "is-extendable": {
+          "version": "0.1.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+          "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+          "dev": true,
+          "peer": true
+        },
+        "kind-of": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+          "dev": true,
+          "peer": true
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "expect": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz",
+      "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/types": "^26.6.2",
+        "ansi-styles": "^4.0.0",
+        "jest-get-type": "^26.3.0",
+        "jest-matcher-utils": "^26.6.2",
+        "jest-message-util": "^26.6.2",
+        "jest-regex-util": "^26.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+      "dev": true
+    },
+    "extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      }
+    },
+    "external-editor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+      "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+      "dev": true,
+      "requires": {
+        "chardet": "^0.7.0",
+        "iconv-lite": "^0.4.24",
+        "tmp": "^0.0.33"
+      }
+    },
+    "extglob": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "array-unique": "^0.3.2",
+        "define-property": "^1.0.0",
+        "expand-brackets": "^2.1.4",
+        "extend-shallow": "^2.0.1",
+        "fragment-cache": "^0.2.1",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "is-extendable": {
+          "version": "0.1.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+          "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "extract-files": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-9.0.0.tgz",
+      "integrity": "sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ==",
+      "dev": true
+    },
+    "fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "dev": true
+    },
+    "fast-diff": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
+      "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
+      "dev": true
+    },
+    "fast-glob": {
+      "version": "3.2.12",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
+      "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+      "dev": true,
+      "requires": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.4"
+      }
+    },
+    "fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+      "dev": true
+    },
+    "fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+      "dev": true
+    },
+    "fastest-levenshtein": {
+      "version": "1.0.16",
+      "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
+      "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
+      "dev": true
+    },
+    "fastq": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+      "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+      "dev": true,
+      "requires": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "fb-watchman": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
+      "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "bser": "2.1.1"
+      }
+    },
+    "figures": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+      "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+      "dev": true,
+      "requires": {
+        "escape-string-regexp": "^1.0.5"
+      }
+    },
+    "file-entry-cache": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+      "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+      "dev": true,
+      "requires": {
+        "flat-cache": "^3.0.4"
+      }
+    },
+    "filelist": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
+      "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
+      "dev": true,
+      "requires": {
+        "minimatch": "^5.0.1"
+      },
+      "dependencies": {
+        "brace-expansion": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+          "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+          "dev": true,
+          "requires": {
+            "balanced-match": "^1.0.0"
+          }
+        },
+        "minimatch": {
+          "version": "5.1.6",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+          "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^2.0.1"
+          }
+        }
+      }
+    },
+    "fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "dev": true,
+      "requires": {
+        "to-regex-range": "^5.0.1"
+      }
+    },
+    "find-up": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz",
+      "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==",
+      "dev": true,
+      "requires": {
+        "locate-path": "^7.1.0",
+        "path-exists": "^5.0.0"
+      }
+    },
+    "flat": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+      "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+      "dev": true
+    },
+    "flat-cache": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+      "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+      "dev": true,
+      "requires": {
+        "flatted": "^3.1.0",
+        "rimraf": "^3.0.2"
+      }
+    },
+    "flatted": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+      "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+      "dev": true
+    },
+    "for-each": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+      "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+      "dev": true,
+      "requires": {
+        "is-callable": "^1.1.3"
+      }
+    },
+    "for-in": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+      "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==",
+      "dev": true,
+      "peer": true
+    },
+    "form-data": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
+      "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
+      "dev": true,
+      "requires": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      }
+    },
+    "fragment-cache": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+      "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "map-cache": "^0.2.2"
+      }
+    },
+    "fs-extra": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
+      "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
+      "dev": true,
+      "requires": {
+        "at-least-node": "^1.0.0",
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^6.0.1",
+        "universalify": "^1.0.0"
+      }
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+      "dev": true
+    },
+    "fsevents": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "dev": true,
+      "optional": true,
+      "peer": true
+    },
+    "function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "dev": true
+    },
+    "function.prototype.name": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
+      "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.19.0",
+        "functions-have-names": "^1.2.2"
+      }
+    },
+    "functions-have-names": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+      "dev": true
+    },
+    "gensync": {
+      "version": "1.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+      "dev": true
+    },
+    "get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true
+    },
+    "get-intrinsic": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
+      "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.1",
+        "has": "^1.0.3",
+        "has-symbols": "^1.0.3"
+      }
+    },
+    "get-own-enumerable-property-symbols": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz",
+      "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==",
+      "dev": true
+    },
+    "get-package-type": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+      "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+      "dev": true,
+      "peer": true
+    },
+    "get-stdin": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz",
+      "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==",
+      "dev": true
+    },
+    "get-stream": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+      "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "pump": "^3.0.0"
+      }
+    },
+    "get-symbol-description": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
+      "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.1"
+      }
+    },
+    "get-tsconfig": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.4.0.tgz",
+      "integrity": "sha512-0Gdjo/9+FzsYhXCEFueo2aY1z1tpXrxWZzP7k8ul9qt1U5o8rYJwTJYmaeHdrVosYIVYkOy2iwCJ9FdpocJhPQ==",
+      "dev": true
+    },
+    "get-value": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+      "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==",
+      "dev": true,
+      "peer": true
+    },
+    "glob": {
+      "version": "7.1.7",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
+      "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
+      "dev": true,
+      "requires": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      }
+    },
+    "glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "requires": {
+        "is-glob": "^4.0.1"
+      }
+    },
+    "global-modules": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
+      "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==",
+      "dev": true,
+      "requires": {
+        "global-prefix": "^3.0.0"
+      }
+    },
+    "global-prefix": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz",
+      "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==",
+      "dev": true,
+      "requires": {
+        "ini": "^1.3.5",
+        "kind-of": "^6.0.2",
+        "which": "^1.3.1"
+      },
+      "dependencies": {
+        "which": {
+          "version": "1.3.1",
+          "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+          "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+          "dev": true,
+          "requires": {
+            "isexe": "^2.0.0"
+          }
+        }
+      }
+    },
+    "globals": {
+      "version": "11.12.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+      "dev": true
+    },
+    "globalthis": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
+      "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
+      "dev": true,
+      "requires": {
+        "define-properties": "^1.1.3"
+      }
+    },
+    "globalyzer": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
+      "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==",
+      "dev": true
+    },
+    "globby": {
+      "version": "13.1.3",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz",
+      "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==",
+      "dev": true,
+      "requires": {
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.2.11",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^4.0.0"
+      }
+    },
+    "globjoin": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz",
+      "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==",
+      "dev": true
+    },
+    "globrex": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
+      "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
+      "dev": true
+    },
+    "gonzales-pe": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz",
+      "integrity": "sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==",
+      "dev": true,
+      "requires": {
+        "minimist": "^1.2.5"
+      }
+    },
+    "gopd": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+      "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+      "dev": true,
+      "requires": {
+        "get-intrinsic": "^1.1.3"
+      }
+    },
+    "graceful-fs": {
+      "version": "4.2.10",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
+      "dev": true
+    },
+    "grapheme-splitter": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+      "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+      "dev": true
+    },
+    "graphql": {
+      "version": "15.8.0",
+      "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.8.0.tgz",
+      "integrity": "sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==",
+      "dev": true
+    },
+    "graphql-request": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-3.7.0.tgz",
+      "integrity": "sha512-dw5PxHCgBneN2DDNqpWu8QkbbJ07oOziy8z+bK/TAXufsOLaETuVO4GkXrbs0WjhdKhBMN3BkpN/RIvUHkmNUQ==",
+      "dev": true,
+      "requires": {
+        "cross-fetch": "^3.0.6",
+        "extract-files": "^9.0.0",
+        "form-data": "^3.0.0"
+      }
+    },
+    "growly": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
+      "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==",
+      "dev": true,
+      "optional": true,
+      "peer": true
+    },
+    "hard-rejection": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz",
+      "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==",
+      "dev": true
+    },
+    "has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.1"
+      }
+    },
+    "has-bigints": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
+      "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
+      "dev": true
+    },
+    "has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "dev": true
+    },
+    "has-property-descriptors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
+      "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
+      "dev": true,
+      "requires": {
+        "get-intrinsic": "^1.1.1"
+      }
+    },
+    "has-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
+      "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
+      "dev": true
+    },
+    "has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+      "dev": true
+    },
+    "has-tostringtag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
+      "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
+      "dev": true,
+      "requires": {
+        "has-symbols": "^1.0.2"
+      }
+    },
+    "has-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+      "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "get-value": "^2.0.6",
+        "has-values": "^1.0.0",
+        "isobject": "^3.0.0"
+      }
+    },
+    "has-values": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+      "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "is-number": "^3.0.0",
+        "kind-of": "^4.0.0"
+      },
+      "dependencies": {
+        "is-buffer": {
+          "version": "1.1.6",
+          "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+          "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+          "dev": true,
+          "peer": true
+        },
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "kind-of": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+          "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "hosted-git-info": {
+      "version": "2.8.9",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+      "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+      "dev": true
+    },
+    "html-encoding-sniffer": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
+      "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "whatwg-encoding": "^1.0.5"
+      }
+    },
+    "html-escaper": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+      "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+      "dev": true,
+      "peer": true
+    },
+    "html-tags": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz",
+      "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==",
+      "dev": true
+    },
+    "htmlparser2": {
+      "version": "3.10.1",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
+      "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "^1.3.1",
+        "domhandler": "^2.3.0",
+        "domutils": "^1.5.1",
+        "entities": "^1.1.1",
+        "inherits": "^2.0.1",
+        "readable-stream": "^3.1.1"
+      }
+    },
+    "http-proxy-agent": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
+      "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@tootallnate/once": "1",
+        "agent-base": "6",
+        "debug": "4"
+      }
+    },
+    "https-proxy-agent": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "agent-base": "6",
+        "debug": "4"
+      }
+    },
+    "human-signals": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
+      "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
+      "dev": true,
+      "peer": true
+    },
+    "iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "dev": true,
+      "requires": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      }
+    },
+    "ignore": {
+      "version": "5.2.4",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+      "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+      "dev": true
+    },
+    "import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+      "dev": true,
+      "requires": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      }
+    },
+    "import-lazy": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz",
+      "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==",
+      "dev": true
+    },
+    "import-local": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
+      "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "pkg-dir": "^4.2.0",
+        "resolve-cwd": "^3.0.0"
+      }
+    },
+    "imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+      "dev": true
+    },
+    "indent-string": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+      "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+      "dev": true
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "dev": true,
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "dev": true
+    },
+    "ini": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+      "dev": true
+    },
+    "inquirer": {
+      "version": "7.3.3",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz",
+      "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==",
+      "dev": true,
+      "requires": {
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.1.0",
+        "cli-cursor": "^3.1.0",
+        "cli-width": "^3.0.0",
+        "external-editor": "^3.0.3",
+        "figures": "^3.0.0",
+        "lodash": "^4.17.19",
+        "mute-stream": "0.0.8",
+        "run-async": "^2.4.0",
+        "rxjs": "^6.6.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0",
+        "through": "^2.3.6"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "4.2.3",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.1"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "internal-slot": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz",
+      "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==",
+      "dev": true,
+      "requires": {
+        "get-intrinsic": "^1.2.0",
+        "has": "^1.0.3",
+        "side-channel": "^1.0.4"
+      }
+    },
+    "ip-regex": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz",
+      "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==",
+      "dev": true
+    },
+    "is-accessor-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+      "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "kind-of": "^6.0.0"
+      }
+    },
+    "is-alphabetical": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
+      "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
+      "dev": true
+    },
+    "is-alphanumeric": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz",
+      "integrity": "sha512-ZmRL7++ZkcMOfDuWZuMJyIVLr2keE1o/DeNWh1EmgqGhUcV+9BIVsx0BcSBOHTZqzjs4+dISzr2KAeBEWGgXeA==",
+      "dev": true
+    },
+    "is-alphanumerical": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
+      "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
+      "dev": true,
+      "requires": {
+        "is-alphabetical": "^1.0.0",
+        "is-decimal": "^1.0.0"
+      }
+    },
+    "is-arguments": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
+      "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "is-array-buffer": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
+      "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.2.0",
+        "is-typed-array": "^1.1.10"
+      }
+    },
+    "is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+      "dev": true
+    },
+    "is-bigint": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
+      "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
+      "dev": true,
+      "requires": {
+        "has-bigints": "^1.0.1"
+      }
+    },
+    "is-boolean-object": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
+      "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "is-buffer": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
+      "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
+      "dev": true
+    },
+    "is-callable": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+      "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+      "dev": true
+    },
+    "is-ci": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+      "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+      "dev": true,
+      "requires": {
+        "ci-info": "^2.0.0"
+      }
+    },
+    "is-core-module": {
+      "version": "2.11.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
+      "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
+      "dev": true,
+      "requires": {
+        "has": "^1.0.3"
+      }
+    },
+    "is-data-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+      "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "kind-of": "^6.0.0"
+      }
+    },
+    "is-date-object": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
+      "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
+      "dev": true,
+      "requires": {
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "is-decimal": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
+      "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
+      "dev": true
+    },
+    "is-descriptor": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+      "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "is-accessor-descriptor": "^1.0.0",
+        "is-data-descriptor": "^1.0.0",
+        "kind-of": "^6.0.2"
+      }
+    },
+    "is-docker": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+      "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+      "dev": true
+    },
+    "is-extendable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+      "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "is-plain-object": "^2.0.4"
+      }
+    },
+    "is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "dev": true
+    },
+    "is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "dev": true
+    },
+    "is-generator-fn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
+      "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==",
+      "dev": true,
+      "peer": true
+    },
+    "is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dev": true,
+      "requires": {
+        "is-extglob": "^2.1.1"
+      }
+    },
+    "is-hexadecimal": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
+      "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
+      "dev": true
+    },
+    "is-map": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
+      "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
+      "dev": true
+    },
+    "is-negative-zero": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
+      "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
+      "dev": true
+    },
+    "is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true
+    },
+    "is-number-object": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
+      "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
+      "dev": true,
+      "requires": {
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "is-obj": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
+      "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==",
+      "dev": true
+    },
+    "is-path-inside": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+      "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+      "dev": true
+    },
+    "is-plain-obj": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+      "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+      "dev": true
+    },
+    "is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      }
+    },
+    "is-potential-custom-element-name": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
+      "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
+      "dev": true,
+      "peer": true
+    },
+    "is-regex": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
+      "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "is-regexp": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
+      "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==",
+      "dev": true
+    },
+    "is-set": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
+      "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
+      "dev": true
+    },
+    "is-shared-array-buffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
+      "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2"
+      }
+    },
+    "is-stream": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+      "dev": true
+    },
+    "is-string": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
+      "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
+      "dev": true,
+      "requires": {
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "is-symbol": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
+      "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
+      "dev": true,
+      "requires": {
+        "has-symbols": "^1.0.2"
+      }
+    },
+    "is-typed-array": {
+      "version": "1.1.10",
+      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz",
+      "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==",
+      "dev": true,
+      "requires": {
+        "available-typed-arrays": "^1.0.5",
+        "call-bind": "^1.0.2",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "has-tostringtag": "^1.0.0"
+      }
+    },
+    "is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
+      "dev": true
+    },
+    "is-unicode-supported": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+      "dev": true
+    },
+    "is-url-superb": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-url-superb/-/is-url-superb-3.0.0.tgz",
+      "integrity": "sha512-3faQP+wHCGDQT1qReM5zCPx2mxoal6DzbzquFlCYJLWyy4WPTved33ea2xFbX37z4NoriEwZGIYhFtx8RUB5wQ==",
+      "dev": true,
+      "requires": {
+        "url-regex": "^5.0.0"
+      }
+    },
+    "is-weakmap": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
+      "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==",
+      "dev": true
+    },
+    "is-weakref": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
+      "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2"
+      }
+    },
+    "is-weakset": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz",
+      "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.1"
+      }
+    },
+    "is-whitespace-character": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz",
+      "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==",
+      "dev": true
+    },
+    "is-windows": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+      "dev": true,
+      "peer": true
+    },
+    "is-word-character": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz",
+      "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==",
+      "dev": true
+    },
+    "is-wsl": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+      "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+      "dev": true,
+      "requires": {
+        "is-docker": "^2.0.0"
+      }
+    },
+    "isarray": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+      "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+      "dev": true
+    },
+    "isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true
+    },
+    "isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
+      "dev": true,
+      "peer": true
+    },
+    "istanbul-lib-coverage": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
+      "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
+      "dev": true,
+      "peer": true
+    },
+    "istanbul-lib-instrument": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
+      "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/core": "^7.7.5",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-coverage": "^3.0.0",
+        "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "istanbul-lib-report": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+      "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "istanbul-lib-coverage": "^3.0.0",
+        "make-dir": "^3.0.0",
+        "supports-color": "^7.1.0"
+      },
+      "dependencies": {
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "istanbul-lib-source-maps": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
+      "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "debug": "^4.1.1",
+        "istanbul-lib-coverage": "^3.0.0",
+        "source-map": "^0.6.1"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "istanbul-reports": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
+      "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "html-escaper": "^2.0.0",
+        "istanbul-lib-report": "^3.0.0"
+      }
+    },
+    "jake": {
+      "version": "10.8.5",
+      "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz",
+      "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==",
+      "dev": true,
+      "requires": {
+        "async": "^3.2.3",
+        "chalk": "^4.0.2",
+        "filelist": "^1.0.1",
+        "minimatch": "^3.0.4"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "jest": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz",
+      "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/core": "^26.6.3",
+        "import-local": "^3.0.2",
+        "jest-cli": "^26.6.3"
+      }
+    },
+    "jest-changed-files": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz",
+      "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/types": "^26.6.2",
+        "execa": "^4.0.0",
+        "throat": "^5.0.0"
+      }
+    },
+    "jest-cli": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz",
+      "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/core": "^26.6.3",
+        "@jest/test-result": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "chalk": "^4.0.0",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.2.4",
+        "import-local": "^3.0.2",
+        "is-ci": "^2.0.0",
+        "jest-config": "^26.6.3",
+        "jest-util": "^26.6.2",
+        "jest-validate": "^26.6.2",
+        "prompts": "^2.0.1",
+        "yargs": "^15.4.1"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true,
+          "peer": true
+        },
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "cliui": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+          "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "string-width": "^4.2.0",
+            "strip-ansi": "^6.0.0",
+            "wrap-ansi": "^6.2.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true,
+          "peer": true
+        },
+        "find-up": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "locate-path": "^5.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "locate-path": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "p-locate": "^4.1.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "p-try": "^2.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "p-limit": "^2.2.0"
+          }
+        },
+        "path-exists": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+          "dev": true,
+          "peer": true
+        },
+        "string-width": {
+          "version": "4.2.3",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.1"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        },
+        "wrap-ansi": {
+          "version": "6.2.0",
+          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+          "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.0.0",
+            "string-width": "^4.1.0",
+            "strip-ansi": "^6.0.0"
+          }
+        },
+        "y18n": {
+          "version": "4.0.3",
+          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+          "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+          "dev": true,
+          "peer": true
+        },
+        "yargs": {
+          "version": "15.4.1",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+          "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "cliui": "^6.0.0",
+            "decamelize": "^1.2.0",
+            "find-up": "^4.1.0",
+            "get-caller-file": "^2.0.1",
+            "require-directory": "^2.1.1",
+            "require-main-filename": "^2.0.0",
+            "set-blocking": "^2.0.0",
+            "string-width": "^4.2.0",
+            "which-module": "^2.0.0",
+            "y18n": "^4.0.0",
+            "yargs-parser": "^18.1.2"
+          }
+        },
+        "yargs-parser": {
+          "version": "18.1.3",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+          "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "camelcase": "^5.0.0",
+            "decamelize": "^1.2.0"
+          }
+        }
+      }
+    },
+    "jest-config": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz",
+      "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/core": "^7.1.0",
+        "@jest/test-sequencer": "^26.6.3",
+        "@jest/types": "^26.6.2",
+        "babel-jest": "^26.6.3",
+        "chalk": "^4.0.0",
+        "deepmerge": "^4.2.2",
+        "glob": "^7.1.1",
+        "graceful-fs": "^4.2.4",
+        "jest-environment-jsdom": "^26.6.2",
+        "jest-environment-node": "^26.6.2",
+        "jest-get-type": "^26.3.0",
+        "jest-jasmine2": "^26.6.3",
+        "jest-regex-util": "^26.0.0",
+        "jest-resolve": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "jest-validate": "^26.6.2",
+        "micromatch": "^4.0.2",
+        "pretty-format": "^26.6.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "jest-diff": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz",
+      "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "chalk": "^4.0.0",
+        "diff-sequences": "^26.6.2",
+        "jest-get-type": "^26.3.0",
+        "pretty-format": "^26.6.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "jest-docblock": {
+      "version": "26.0.0",
+      "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz",
+      "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "detect-newline": "^3.0.0"
+      }
+    },
+    "jest-each": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz",
+      "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/types": "^26.6.2",
+        "chalk": "^4.0.0",
+        "jest-get-type": "^26.3.0",
+        "jest-util": "^26.6.2",
+        "pretty-format": "^26.6.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "jest-environment-jsdom": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz",
+      "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/environment": "^26.6.2",
+        "@jest/fake-timers": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "jest-mock": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "jsdom": "^16.4.0"
+      }
+    },
+    "jest-environment-node": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz",
+      "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/environment": "^26.6.2",
+        "@jest/fake-timers": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "jest-mock": "^26.6.2",
+        "jest-util": "^26.6.2"
+      }
+    },
+    "jest-get-type": {
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz",
+      "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==",
+      "dev": true,
+      "peer": true
+    },
+    "jest-haste-map": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz",
+      "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/types": "^26.6.2",
+        "@types/graceful-fs": "^4.1.2",
+        "@types/node": "*",
+        "anymatch": "^3.0.3",
+        "fb-watchman": "^2.0.0",
+        "fsevents": "^2.1.2",
+        "graceful-fs": "^4.2.4",
+        "jest-regex-util": "^26.0.0",
+        "jest-serializer": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "jest-worker": "^26.6.2",
+        "micromatch": "^4.0.2",
+        "sane": "^4.0.3",
+        "walker": "^1.0.7"
+      }
+    },
+    "jest-jasmine2": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz",
+      "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/traverse": "^7.1.0",
+        "@jest/environment": "^26.6.2",
+        "@jest/source-map": "^26.6.2",
+        "@jest/test-result": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "co": "^4.6.0",
+        "expect": "^26.6.2",
+        "is-generator-fn": "^2.0.0",
+        "jest-each": "^26.6.2",
+        "jest-matcher-utils": "^26.6.2",
+        "jest-message-util": "^26.6.2",
+        "jest-runtime": "^26.6.3",
+        "jest-snapshot": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "pretty-format": "^26.6.2",
+        "throat": "^5.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "jest-leak-detector": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz",
+      "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "jest-get-type": "^26.3.0",
+        "pretty-format": "^26.6.2"
+      }
+    },
+    "jest-matcher-utils": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz",
+      "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "chalk": "^4.0.0",
+        "jest-diff": "^26.6.2",
+        "jest-get-type": "^26.3.0",
+        "pretty-format": "^26.6.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "jest-message-util": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz",
+      "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/code-frame": "^7.0.0",
+        "@jest/types": "^26.6.2",
+        "@types/stack-utils": "^2.0.0",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.4",
+        "micromatch": "^4.0.2",
+        "pretty-format": "^26.6.2",
+        "slash": "^3.0.0",
+        "stack-utils": "^2.0.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "slash": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+          "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "jest-mock": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz",
+      "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/types": "^26.6.2",
+        "@types/node": "*"
+      }
+    },
+    "jest-pnp-resolver": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
+      "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
+      "dev": true,
+      "peer": true,
+      "requires": {}
+    },
+    "jest-regex-util": {
+      "version": "26.0.0",
+      "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz",
+      "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==",
+      "dev": true,
+      "peer": true
+    },
+    "jest-resolve": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz",
+      "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/types": "^26.6.2",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.4",
+        "jest-pnp-resolver": "^1.2.2",
+        "jest-util": "^26.6.2",
+        "read-pkg-up": "^7.0.1",
+        "resolve": "^1.18.1",
+        "slash": "^3.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "slash": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+          "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "jest-resolve-dependencies": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz",
+      "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/types": "^26.6.2",
+        "jest-regex-util": "^26.0.0",
+        "jest-snapshot": "^26.6.2"
+      }
+    },
+    "jest-runner": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz",
+      "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/console": "^26.6.2",
+        "@jest/environment": "^26.6.2",
+        "@jest/test-result": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "emittery": "^0.7.1",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.2.4",
+        "jest-config": "^26.6.3",
+        "jest-docblock": "^26.0.0",
+        "jest-haste-map": "^26.6.2",
+        "jest-leak-detector": "^26.6.2",
+        "jest-message-util": "^26.6.2",
+        "jest-resolve": "^26.6.2",
+        "jest-runtime": "^26.6.3",
+        "jest-util": "^26.6.2",
+        "jest-worker": "^26.6.2",
+        "source-map-support": "^0.5.6",
+        "throat": "^5.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "jest-runtime": {
+      "version": "26.6.3",
+      "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz",
+      "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/console": "^26.6.2",
+        "@jest/environment": "^26.6.2",
+        "@jest/fake-timers": "^26.6.2",
+        "@jest/globals": "^26.6.2",
+        "@jest/source-map": "^26.6.2",
+        "@jest/test-result": "^26.6.2",
+        "@jest/transform": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/yargs": "^15.0.0",
+        "chalk": "^4.0.0",
+        "cjs-module-lexer": "^0.6.0",
+        "collect-v8-coverage": "^1.0.0",
+        "exit": "^0.1.2",
+        "glob": "^7.1.3",
+        "graceful-fs": "^4.2.4",
+        "jest-config": "^26.6.3",
+        "jest-haste-map": "^26.6.2",
+        "jest-message-util": "^26.6.2",
+        "jest-mock": "^26.6.2",
+        "jest-regex-util": "^26.0.0",
+        "jest-resolve": "^26.6.2",
+        "jest-snapshot": "^26.6.2",
+        "jest-util": "^26.6.2",
+        "jest-validate": "^26.6.2",
+        "slash": "^3.0.0",
+        "strip-bom": "^4.0.0",
+        "yargs": "^15.4.1"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true,
+          "peer": true
+        },
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "cliui": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+          "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "string-width": "^4.2.0",
+            "strip-ansi": "^6.0.0",
+            "wrap-ansi": "^6.2.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true,
+          "peer": true
+        },
+        "find-up": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "locate-path": "^5.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "locate-path": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "p-locate": "^4.1.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "p-try": "^2.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "p-limit": "^2.2.0"
+          }
+        },
+        "path-exists": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+          "dev": true,
+          "peer": true
+        },
+        "slash": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+          "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+          "dev": true,
+          "peer": true
+        },
+        "string-width": {
+          "version": "4.2.3",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.1"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        },
+        "wrap-ansi": {
+          "version": "6.2.0",
+          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+          "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.0.0",
+            "string-width": "^4.1.0",
+            "strip-ansi": "^6.0.0"
+          }
+        },
+        "y18n": {
+          "version": "4.0.3",
+          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+          "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+          "dev": true,
+          "peer": true
+        },
+        "yargs": {
+          "version": "15.4.1",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+          "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "cliui": "^6.0.0",
+            "decamelize": "^1.2.0",
+            "find-up": "^4.1.0",
+            "get-caller-file": "^2.0.1",
+            "require-directory": "^2.1.1",
+            "require-main-filename": "^2.0.0",
+            "set-blocking": "^2.0.0",
+            "string-width": "^4.2.0",
+            "which-module": "^2.0.0",
+            "y18n": "^4.0.0",
+            "yargs-parser": "^18.1.2"
+          }
+        },
+        "yargs-parser": {
+          "version": "18.1.3",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+          "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "camelcase": "^5.0.0",
+            "decamelize": "^1.2.0"
+          }
+        }
+      }
+    },
+    "jest-serializer": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz",
+      "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@types/node": "*",
+        "graceful-fs": "^4.2.4"
+      }
+    },
+    "jest-snapshot": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz",
+      "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@babel/types": "^7.0.0",
+        "@jest/types": "^26.6.2",
+        "@types/babel__traverse": "^7.0.4",
+        "@types/prettier": "^2.0.0",
+        "chalk": "^4.0.0",
+        "expect": "^26.6.2",
+        "graceful-fs": "^4.2.4",
+        "jest-diff": "^26.6.2",
+        "jest-get-type": "^26.3.0",
+        "jest-haste-map": "^26.6.2",
+        "jest-matcher-utils": "^26.6.2",
+        "jest-message-util": "^26.6.2",
+        "jest-resolve": "^26.6.2",
+        "natural-compare": "^1.4.0",
+        "pretty-format": "^26.6.2",
+        "semver": "^7.3.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "lru-cache": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+          "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "yallist": "^4.0.0"
+          }
+        },
+        "semver": {
+          "version": "7.3.8",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+          "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        },
+        "yallist": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+          "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "jest-util": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz",
+      "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==",
+      "dev": true,
+      "requires": {
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.4",
+        "is-ci": "^2.0.0",
+        "micromatch": "^4.0.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "jest-validate": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz",
+      "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/types": "^26.6.2",
+        "camelcase": "^6.0.0",
+        "chalk": "^4.0.0",
+        "jest-get-type": "^26.3.0",
+        "leven": "^3.1.0",
+        "pretty-format": "^26.6.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "camelcase": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+          "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+          "dev": true,
+          "peer": true
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "jest-watcher": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz",
+      "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/test-result": "^26.6.2",
+        "@jest/types": "^26.6.2",
+        "@types/node": "*",
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.0.0",
+        "jest-util": "^26.6.2",
+        "string-length": "^4.0.1"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "jest-worker": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
+      "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@types/node": "*",
+        "merge-stream": "^2.0.0",
+        "supports-color": "^7.0.0"
+      },
+      "dependencies": {
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "js-sdsl": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
+      "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
+      "dev": true
+    },
+    "js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true
+    },
+    "js-yaml": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+      "dev": true,
+      "requires": {
+        "argparse": "^2.0.1"
+      }
+    },
+    "jsdom": {
+      "version": "16.7.0",
+      "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz",
+      "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "abab": "^2.0.5",
+        "acorn": "^8.2.4",
+        "acorn-globals": "^6.0.0",
+        "cssom": "^0.4.4",
+        "cssstyle": "^2.3.0",
+        "data-urls": "^2.0.0",
+        "decimal.js": "^10.2.1",
+        "domexception": "^2.0.1",
+        "escodegen": "^2.0.0",
+        "form-data": "^3.0.0",
+        "html-encoding-sniffer": "^2.0.1",
+        "http-proxy-agent": "^4.0.1",
+        "https-proxy-agent": "^5.0.0",
+        "is-potential-custom-element-name": "^1.0.1",
+        "nwsapi": "^2.2.0",
+        "parse5": "6.0.1",
+        "saxes": "^5.0.1",
+        "symbol-tree": "^3.2.4",
+        "tough-cookie": "^4.0.0",
+        "w3c-hr-time": "^1.0.2",
+        "w3c-xmlserializer": "^2.0.0",
+        "webidl-conversions": "^6.1.0",
+        "whatwg-encoding": "^1.0.5",
+        "whatwg-mimetype": "^2.3.0",
+        "whatwg-url": "^8.5.0",
+        "ws": "^7.4.6",
+        "xml-name-validator": "^3.0.0"
+      }
+    },
+    "jsesc": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+      "dev": true
+    },
+    "json-parse-better-errors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+      "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+      "dev": true
+    },
+    "json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+      "dev": true
+    },
+    "json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true
+    },
+    "json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+      "dev": true
+    },
+    "json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "dev": true
+    },
+    "jsonfile": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+      "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.6",
+        "universalify": "^2.0.0"
+      },
+      "dependencies": {
+        "universalify": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+          "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+          "dev": true
+        }
+      }
+    },
+    "jsx-ast-utils": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz",
+      "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==",
+      "dev": true,
+      "requires": {
+        "array-includes": "^3.1.5",
+        "object.assign": "^4.1.3"
+      }
+    },
+    "kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true
+    },
+    "kleur": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
+      "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
+      "dev": true,
+      "peer": true
+    },
+    "known-css-properties": {
+      "version": "0.20.0",
+      "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.20.0.tgz",
+      "integrity": "sha512-URvsjaA9ypfreqJ2/ylDr5MUERhJZ+DhguoWRr2xgS5C7aGCalXo+ewL+GixgKBfhT2vuL02nbIgNGqVWgTOYw==",
+      "dev": true
+    },
+    "language-subtag-registry": {
+      "version": "0.3.22",
+      "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
+      "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==",
+      "dev": true
+    },
+    "language-tags": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz",
+      "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==",
+      "dev": true,
+      "requires": {
+        "language-subtag-registry": "~0.3.2"
+      }
+    },
+    "leven": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+      "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+      "dev": true,
+      "peer": true
+    },
+    "levn": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "^1.2.1",
+        "type-check": "~0.4.0"
+      }
+    },
+    "lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+      "dev": true
+    },
+    "lint-staged": {
+      "version": "11.1.2",
+      "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-11.1.2.tgz",
+      "integrity": "sha512-6lYpNoA9wGqkL6Hew/4n1H6lRqF3qCsujVT0Oq5Z4hiSAM7S6NksPJ3gnr7A7R52xCtiZMcEUNNQ6d6X5Bvh9w==",
+      "dev": true,
+      "requires": {
+        "chalk": "^4.1.1",
+        "cli-truncate": "^2.1.0",
+        "commander": "^7.2.0",
+        "cosmiconfig": "^7.0.0",
+        "debug": "^4.3.1",
+        "enquirer": "^2.3.6",
+        "execa": "^5.0.0",
+        "listr2": "^3.8.2",
+        "log-symbols": "^4.1.0",
+        "micromatch": "^4.0.4",
+        "normalize-path": "^3.0.0",
+        "please-upgrade-node": "^3.2.0",
+        "string-argv": "0.3.1",
+        "stringify-object": "^3.3.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "execa": {
+          "version": "5.1.1",
+          "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+          "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+          "dev": true,
+          "requires": {
+            "cross-spawn": "^7.0.3",
+            "get-stream": "^6.0.0",
+            "human-signals": "^2.1.0",
+            "is-stream": "^2.0.0",
+            "merge-stream": "^2.0.0",
+            "npm-run-path": "^4.0.1",
+            "onetime": "^5.1.2",
+            "signal-exit": "^3.0.3",
+            "strip-final-newline": "^2.0.0"
+          }
+        },
+        "get-stream": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+          "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "human-signals": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+          "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "listr2": {
+      "version": "3.14.0",
+      "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz",
+      "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==",
+      "dev": true,
+      "requires": {
+        "cli-truncate": "^2.1.0",
+        "colorette": "^2.0.16",
+        "log-update": "^4.0.0",
+        "p-map": "^4.0.0",
+        "rfdc": "^1.3.0",
+        "rxjs": "^7.5.1",
+        "through": "^2.3.8",
+        "wrap-ansi": "^7.0.0"
+      },
+      "dependencies": {
+        "rxjs": {
+          "version": "7.8.0",
+          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz",
+          "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==",
+          "dev": true,
+          "requires": {
+            "tslib": "^2.1.0"
+          }
+        },
+        "tslib": {
+          "version": "2.5.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+          "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
+          "dev": true
+        }
+      }
+    },
+    "load-json-file": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+      "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "parse-json": "^4.0.0",
+        "pify": "^3.0.0",
+        "strip-bom": "^3.0.0"
+      },
+      "dependencies": {
+        "parse-json": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+          "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
+          "dev": true,
+          "requires": {
+            "error-ex": "^1.3.1",
+            "json-parse-better-errors": "^1.0.1"
+          }
+        },
+        "strip-bom": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+          "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+          "dev": true
+        }
+      }
+    },
+    "locate-path": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz",
+      "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==",
+      "dev": true,
+      "requires": {
+        "p-locate": "^6.0.0"
+      }
+    },
+    "lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+      "dev": true
+    },
+    "lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+      "dev": true
+    },
+    "lodash.truncate": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
+      "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==",
+      "dev": true
+    },
+    "log-symbols": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+      "dev": true,
+      "requires": {
+        "chalk": "^4.1.0",
+        "is-unicode-supported": "^0.1.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "log-update": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
+      "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
+      "dev": true,
+      "requires": {
+        "ansi-escapes": "^4.3.0",
+        "cli-cursor": "^3.1.0",
+        "slice-ansi": "^4.0.0",
+        "wrap-ansi": "^6.2.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "slice-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+          "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.0.0",
+            "astral-regex": "^2.0.0",
+            "is-fullwidth-code-point": "^3.0.0"
+          }
+        },
+        "string-width": {
+          "version": "4.2.3",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.1"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        },
+        "wrap-ansi": {
+          "version": "6.2.0",
+          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+          "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.0.0",
+            "string-width": "^4.1.0",
+            "strip-ansi": "^6.0.0"
+          }
+        }
+      }
+    },
+    "longest-streak": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz",
+      "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==",
+      "dev": true
+    },
+    "loose-envify": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+      "dev": true,
+      "requires": {
+        "js-tokens": "^3.0.0 || ^4.0.0"
+      }
+    },
+    "lru-cache": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+      "dev": true,
+      "requires": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "make-dir": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+      "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "semver": "^6.0.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+      "dev": true
+    },
+    "makeerror": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
+      "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "tmpl": "1.0.5"
+      }
+    },
+    "map-cache": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+      "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==",
+      "dev": true,
+      "peer": true
+    },
+    "map-obj": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
+      "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
+      "dev": true
+    },
+    "map-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+      "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "object-visit": "^1.0.0"
+      }
+    },
+    "markdown-escapes": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz",
+      "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==",
+      "dev": true
+    },
+    "markdown-table": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz",
+      "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==",
+      "dev": true,
+      "requires": {
+        "repeat-string": "^1.0.0"
+      }
+    },
+    "mathml-tag-names": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
+      "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==",
+      "dev": true
+    },
+    "mdast-util-compact": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-2.0.1.tgz",
+      "integrity": "sha512-7GlnT24gEwDrdAwEHrU4Vv5lLWrEer4KOkAiKT9nYstsTad7Oc1TwqT2zIMKRdZF7cTuaf+GA1E4Kv7jJh8mPA==",
+      "dev": true,
+      "requires": {
+        "unist-util-visit": "^2.0.0"
+      },
+      "dependencies": {
+        "unist-util-is": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz",
+          "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==",
+          "dev": true
+        },
+        "unist-util-visit": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz",
+          "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==",
+          "dev": true,
+          "requires": {
+            "@types/unist": "^2.0.0",
+            "unist-util-is": "^4.0.0",
+            "unist-util-visit-parents": "^3.0.0"
+          }
+        },
+        "unist-util-visit-parents": {
+          "version": "3.1.1",
+          "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz",
+          "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==",
+          "dev": true,
+          "requires": {
+            "@types/unist": "^2.0.0",
+            "unist-util-is": "^4.0.0"
+          }
+        }
+      }
+    },
+    "mdast-util-from-markdown": {
+      "version": "0.8.5",
+      "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz",
+      "integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==",
+      "dev": true,
+      "requires": {
+        "@types/mdast": "^3.0.0",
+        "mdast-util-to-string": "^2.0.0",
+        "micromark": "~2.11.0",
+        "parse-entities": "^2.0.0",
+        "unist-util-stringify-position": "^2.0.0"
+      },
+      "dependencies": {
+        "mdast-util-to-string": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz",
+          "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==",
+          "dev": true
+        },
+        "unist-util-stringify-position": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
+          "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
+          "dev": true,
+          "requires": {
+            "@types/unist": "^2.0.2"
+          }
+        }
+      }
+    },
+    "mdast-util-to-markdown": {
+      "version": "0.6.5",
+      "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz",
+      "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==",
+      "dev": true,
+      "requires": {
+        "@types/unist": "^2.0.0",
+        "longest-streak": "^2.0.0",
+        "mdast-util-to-string": "^2.0.0",
+        "parse-entities": "^2.0.0",
+        "repeat-string": "^1.0.0",
+        "zwitch": "^1.0.0"
+      },
+      "dependencies": {
+        "mdast-util-to-string": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz",
+          "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==",
+          "dev": true
+        }
+      }
+    },
+    "mdast-util-to-string": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.1.tgz",
+      "integrity": "sha512-tGvhT94e+cVnQt8JWE9/b3cUQZWS732TJxXHktvP+BYo62PpYD53Ls/6cC60rW21dW+txxiM4zMdc6abASvZKA==",
+      "dev": true,
+      "requires": {
+        "@types/mdast": "^3.0.0"
+      }
+    },
+    "meow": {
+      "version": "8.1.2",
+      "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz",
+      "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==",
+      "dev": true,
+      "requires": {
+        "@types/minimist": "^1.2.0",
+        "camelcase-keys": "^6.2.2",
+        "decamelize-keys": "^1.1.0",
+        "hard-rejection": "^2.1.0",
+        "minimist-options": "4.1.0",
+        "normalize-package-data": "^3.0.0",
+        "read-pkg-up": "^7.0.1",
+        "redent": "^3.0.0",
+        "trim-newlines": "^3.0.0",
+        "type-fest": "^0.18.0",
+        "yargs-parser": "^20.2.3"
+      },
+      "dependencies": {
+        "hosted-git-info": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+          "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "lru-cache": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+          "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+          "dev": true,
+          "requires": {
+            "yallist": "^4.0.0"
+          }
+        },
+        "normalize-package-data": {
+          "version": "3.0.3",
+          "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
+          "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
+          "dev": true,
+          "requires": {
+            "hosted-git-info": "^4.0.1",
+            "is-core-module": "^2.5.0",
+            "semver": "^7.3.4",
+            "validate-npm-package-license": "^3.0.1"
+          }
+        },
+        "semver": {
+          "version": "7.3.8",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+          "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "type-fest": {
+          "version": "0.18.1",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz",
+          "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==",
+          "dev": true
+        },
+        "yallist": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+          "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+          "dev": true
+        },
+        "yargs-parser": {
+          "version": "20.2.9",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+          "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+          "dev": true
+        }
+      }
+    },
+    "merge-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+      "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+      "dev": true
+    },
+    "merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true
+    },
+    "micromark": {
+      "version": "2.11.4",
+      "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz",
+      "integrity": "sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==",
+      "dev": true,
+      "requires": {
+        "debug": "^4.0.0",
+        "parse-entities": "^2.0.0"
+      }
+    },
+    "micromatch": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+      "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+      "dev": true,
+      "requires": {
+        "braces": "^3.0.2",
+        "picomatch": "^2.3.1"
+      }
+    },
+    "mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "dev": true
+    },
+    "mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "dev": true,
+      "requires": {
+        "mime-db": "1.52.0"
+      }
+    },
+    "mimic-fn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+      "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+      "dev": true
+    },
+    "min-indent": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+      "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+      "dev": true
+    },
+    "minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "requires": {
+        "brace-expansion": "^1.1.7"
+      }
+    },
+    "minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "dev": true
+    },
+    "minimist-options": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
+      "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==",
+      "dev": true,
+      "requires": {
+        "arrify": "^1.0.1",
+        "is-plain-obj": "^1.1.0",
+        "kind-of": "^6.0.3"
+      },
+      "dependencies": {
+        "is-plain-obj": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+          "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
+          "dev": true
+        }
+      }
+    },
+    "mixin-deep": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+      "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "for-in": "^1.0.2",
+        "is-extendable": "^1.0.1"
+      }
+    },
+    "mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+      "dev": true
+    },
+    "ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+      "dev": true
+    },
+    "mute-stream": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+      "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+      "dev": true
+    },
+    "nanoid": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.2.tgz",
+      "integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==",
+      "dev": true
+    },
+    "nanomatch": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "fragment-cache": "^0.2.1",
+        "is-windows": "^1.0.2",
+        "kind-of": "^6.0.2",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      }
+    },
+    "natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+      "dev": true
+    },
+    "natural-compare-lite": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
+      "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
+      "dev": true
+    },
+    "next": {
+      "version": "12.1.4",
+      "resolved": "https://registry.npmjs.org/next/-/next-12.1.4.tgz",
+      "integrity": "sha512-DA4g97BM4Z0nKtDvCTm58RxdvoQyYzeg0AeVbh0N4Y/D8ELrNu47lQeEgRGF8hV4eQ+Sal90zxrJQQG/mPQ8CQ==",
+      "dev": true,
+      "requires": {
+        "@next/env": "12.1.4",
+        "@next/swc-android-arm-eabi": "12.1.4",
+        "@next/swc-android-arm64": "12.1.4",
+        "@next/swc-darwin-arm64": "12.1.4",
+        "@next/swc-darwin-x64": "12.1.4",
+        "@next/swc-linux-arm-gnueabihf": "12.1.4",
+        "@next/swc-linux-arm64-gnu": "12.1.4",
+        "@next/swc-linux-arm64-musl": "12.1.4",
+        "@next/swc-linux-x64-gnu": "12.1.4",
+        "@next/swc-linux-x64-musl": "12.1.4",
+        "@next/swc-win32-arm64-msvc": "12.1.4",
+        "@next/swc-win32-ia32-msvc": "12.1.4",
+        "@next/swc-win32-x64-msvc": "12.1.4",
+        "caniuse-lite": "^1.0.30001283",
+        "postcss": "8.4.5",
+        "styled-jsx": "5.0.1"
+      }
+    },
+    "nice-try": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+      "dev": true,
+      "peer": true
+    },
+    "node-fetch": {
+      "version": "2.6.7",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+      "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+      "dev": true,
+      "requires": {
+        "whatwg-url": "^5.0.0"
+      },
+      "dependencies": {
+        "tr46": {
+          "version": "0.0.3",
+          "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+          "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+          "dev": true
+        },
+        "webidl-conversions": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+          "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+          "dev": true
+        },
+        "whatwg-url": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+          "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+          "dev": true,
+          "requires": {
+            "tr46": "~0.0.3",
+            "webidl-conversions": "^3.0.0"
+          }
+        }
+      }
+    },
+    "node-int64": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
+      "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
+      "dev": true,
+      "peer": true
+    },
+    "node-notifier": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz",
+      "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==",
+      "dev": true,
+      "optional": true,
+      "peer": true,
+      "requires": {
+        "growly": "^1.3.0",
+        "is-wsl": "^2.2.0",
+        "semver": "^7.3.2",
+        "shellwords": "^0.1.1",
+        "uuid": "^8.3.0",
+        "which": "^2.0.2"
+      },
+      "dependencies": {
+        "lru-cache": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+          "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+          "dev": true,
+          "optional": true,
+          "peer": true,
+          "requires": {
+            "yallist": "^4.0.0"
+          }
+        },
+        "semver": {
+          "version": "7.3.8",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+          "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+          "dev": true,
+          "optional": true,
+          "peer": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "yallist": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+          "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+          "dev": true,
+          "optional": true,
+          "peer": true
+        }
+      }
+    },
+    "node-releases": {
+      "version": "2.0.10",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
+      "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==",
+      "dev": true
+    },
+    "normalize-package-data": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+      "dev": true,
+      "requires": {
+        "hosted-git-info": "^2.1.4",
+        "resolve": "^1.10.0",
+        "semver": "2 || 3 || 4 || 5",
+        "validate-npm-package-license": "^3.0.1"
+      }
+    },
+    "normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "dev": true
+    },
+    "normalize-range": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+      "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+      "dev": true
+    },
+    "normalize-selector": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz",
+      "integrity": "sha512-dxvWdI8gw6eAvk9BlPffgEoGfM7AdijoCwOEJge3e3ulT2XLgmU7KvvxprOaCu05Q1uGRHmOhHe1r6emZoKyFw==",
+      "dev": true
+    },
+    "npm-run-path": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+      "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+      "dev": true,
+      "requires": {
+        "path-key": "^3.0.0"
+      }
+    },
+    "num2fraction": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
+      "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==",
+      "dev": true
+    },
+    "nwsapi": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz",
+      "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==",
+      "dev": true,
+      "peer": true
+    },
+    "object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "dev": true
+    },
+    "object-copy": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+      "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "copy-descriptor": "^0.1.0",
+        "define-property": "^0.2.5",
+        "kind-of": "^3.0.3"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+          "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          }
+        },
+        "is-buffer": {
+          "version": "1.1.6",
+          "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+          "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+          "dev": true,
+          "peer": true
+        },
+        "is-data-descriptor": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+          "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          }
+        },
+        "is-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+          "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-accessor-descriptor": "^0.1.6",
+            "is-data-descriptor": "^0.1.4",
+            "kind-of": "^5.0.0"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "5.1.0",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+              "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+              "dev": true,
+              "peer": true
+            }
+          }
+        },
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "object-inspect": {
+      "version": "1.12.3",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
+      "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
+      "dev": true
+    },
+    "object-is": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
+      "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3"
+      }
+    },
+    "object-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+      "dev": true
+    },
+    "object-visit": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+      "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "isobject": "^3.0.0"
+      }
+    },
+    "object.assign": {
+      "version": "4.1.4",
+      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
+      "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "has-symbols": "^1.0.3",
+        "object-keys": "^1.1.1"
+      }
+    },
+    "object.entries": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz",
+      "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4"
+      }
+    },
+    "object.fromentries": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz",
+      "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4"
+      }
+    },
+    "object.hasown": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz",
+      "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==",
+      "dev": true,
+      "requires": {
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4"
+      }
+    },
+    "object.pick": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+      "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      }
+    },
+    "object.values": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz",
+      "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4"
+      }
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dev": true,
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "onetime": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+      "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+      "dev": true,
+      "requires": {
+        "mimic-fn": "^2.1.0"
+      }
+    },
+    "open": {
+      "version": "7.3.0",
+      "resolved": "https://registry.npmjs.org/open/-/open-7.3.0.tgz",
+      "integrity": "sha512-mgLwQIx2F/ye9SmbrUkurZCnkoXyXyu9EbHtJZrICjVAJfyMArdHp3KkixGdZx1ZHFPNIwl0DDM1dFFqXbTLZw==",
+      "dev": true,
+      "requires": {
+        "is-docker": "^2.0.0",
+        "is-wsl": "^2.1.1"
+      }
+    },
+    "optionator": {
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+      "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+      "dev": true,
+      "requires": {
+        "deep-is": "^0.1.3",
+        "fast-levenshtein": "^2.0.6",
+        "levn": "^0.4.1",
+        "prelude-ls": "^1.2.1",
+        "type-check": "^0.4.0",
+        "word-wrap": "^1.2.3"
+      }
+    },
+    "os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
+      "dev": true
+    },
+    "p-each-series": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz",
+      "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==",
+      "dev": true,
+      "peer": true
+    },
+    "p-finally": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+      "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
+      "dev": true,
+      "peer": true
+    },
+    "p-limit": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
+      "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
+      "dev": true,
+      "requires": {
+        "yocto-queue": "^1.0.0"
+      }
+    },
+    "p-locate": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz",
+      "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==",
+      "dev": true,
+      "requires": {
+        "p-limit": "^4.0.0"
+      }
+    },
+    "p-map": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+      "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+      "dev": true,
+      "requires": {
+        "aggregate-error": "^3.0.0"
+      }
+    },
+    "p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "dev": true
+    },
+    "parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "requires": {
+        "callsites": "^3.0.0"
+      }
+    },
+    "parse-entities": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
+      "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
+      "dev": true,
+      "requires": {
+        "character-entities": "^1.0.0",
+        "character-entities-legacy": "^1.0.0",
+        "character-reference-invalid": "^1.0.0",
+        "is-alphanumerical": "^1.0.0",
+        "is-decimal": "^1.0.0",
+        "is-hexadecimal": "^1.0.0"
+      }
+    },
+    "parse-json": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
+      }
+    },
+    "parse5": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
+      "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
+      "dev": true,
+      "peer": true
+    },
+    "pascalcase": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+      "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==",
+      "dev": true,
+      "peer": true
+    },
+    "path-exists": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
+      "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==",
+      "dev": true
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "dev": true
+    },
+    "path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true
+    },
+    "path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+      "dev": true
+    },
+    "path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "dev": true
+    },
+    "picocolors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+      "dev": true
+    },
+    "picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true
+    },
+    "pify": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+      "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
+      "dev": true
+    },
+    "pirates": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
+      "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
+      "dev": true,
+      "peer": true
+    },
+    "pkg-conf": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz",
+      "integrity": "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==",
+      "dev": true,
+      "requires": {
+        "find-up": "^2.0.0",
+        "load-json-file": "^4.0.0"
+      },
+      "dependencies": {
+        "find-up": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+          "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^2.0.0"
+          }
+        },
+        "locate-path": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+          "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^2.0.0",
+            "path-exists": "^3.0.0"
+          }
+        },
+        "p-limit": {
+          "version": "1.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+          "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+          "dev": true,
+          "requires": {
+            "p-try": "^1.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+          "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^1.1.0"
+          }
+        },
+        "p-try": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+          "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==",
+          "dev": true
+        },
+        "path-exists": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+          "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
+          "dev": true
+        }
+      }
+    },
+    "pkg-dir": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "find-up": "^4.0.0"
+      },
+      "dependencies": {
+        "find-up": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "locate-path": "^5.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "locate-path": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "p-locate": "^4.1.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "p-try": "^2.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "p-limit": "^2.2.0"
+          }
+        },
+        "path-exists": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "please-upgrade-node": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
+      "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
+      "dev": true,
+      "requires": {
+        "semver-compare": "^1.0.0"
+      }
+    },
+    "posix-character-classes": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+      "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==",
+      "dev": true,
+      "peer": true
+    },
+    "postcss": {
+      "version": "8.4.5",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz",
+      "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==",
+      "dev": true,
+      "requires": {
+        "nanoid": "^3.1.30",
+        "picocolors": "^1.0.0",
+        "source-map-js": "^1.0.1"
+      }
+    },
+    "postcss-html": {
+      "version": "0.36.0",
+      "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-0.36.0.tgz",
+      "integrity": "sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw==",
+      "dev": true,
+      "requires": {
+        "htmlparser2": "^3.10.0"
+      }
+    },
+    "postcss-less": {
+      "version": "3.1.4",
+      "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-3.1.4.tgz",
+      "integrity": "sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA==",
+      "dev": true,
+      "requires": {
+        "postcss": "^7.0.14"
+      },
+      "dependencies": {
+        "picocolors": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+          "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+          "dev": true
+        },
+        "postcss": {
+          "version": "7.0.39",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+          "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+          "dev": true,
+          "requires": {
+            "picocolors": "^0.2.1",
+            "source-map": "^0.6.1"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "postcss-media-query-parser": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz",
+      "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==",
+      "dev": true
+    },
+    "postcss-resolve-nested-selector": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz",
+      "integrity": "sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==",
+      "dev": true
+    },
+    "postcss-safe-parser": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz",
+      "integrity": "sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g==",
+      "dev": true,
+      "requires": {
+        "postcss": "^7.0.26"
+      },
+      "dependencies": {
+        "picocolors": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+          "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+          "dev": true
+        },
+        "postcss": {
+          "version": "7.0.39",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+          "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+          "dev": true,
+          "requires": {
+            "picocolors": "^0.2.1",
+            "source-map": "^0.6.1"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "postcss-sass": {
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/postcss-sass/-/postcss-sass-0.4.4.tgz",
+      "integrity": "sha512-BYxnVYx4mQooOhr+zer0qWbSPYnarAy8ZT7hAQtbxtgVf8gy+LSLT/hHGe35h14/pZDTw1DsxdbrwxBN++H+fg==",
+      "dev": true,
+      "requires": {
+        "gonzales-pe": "^4.3.0",
+        "postcss": "^7.0.21"
+      },
+      "dependencies": {
+        "picocolors": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+          "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+          "dev": true
+        },
+        "postcss": {
+          "version": "7.0.39",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+          "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+          "dev": true,
+          "requires": {
+            "picocolors": "^0.2.1",
+            "source-map": "^0.6.1"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "postcss-scss": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.1.1.tgz",
+      "integrity": "sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA==",
+      "dev": true,
+      "requires": {
+        "postcss": "^7.0.6"
+      },
+      "dependencies": {
+        "picocolors": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+          "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+          "dev": true
+        },
+        "postcss": {
+          "version": "7.0.39",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+          "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+          "dev": true,
+          "requires": {
+            "picocolors": "^0.2.1",
+            "source-map": "^0.6.1"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "postcss-selector-parser": {
+      "version": "6.0.11",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz",
+      "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==",
+      "dev": true,
+      "requires": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      }
+    },
+    "postcss-sorting": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-5.0.1.tgz",
+      "integrity": "sha512-Y9fUFkIhfrm6i0Ta3n+89j56EFqaNRdUKqXyRp6kvTcSXnmgEjaVowCXH+JBe9+YKWqd4nc28r2sgwnzJalccA==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.14",
+        "postcss": "^7.0.17"
+      },
+      "dependencies": {
+        "picocolors": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+          "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+          "dev": true
+        },
+        "postcss": {
+          "version": "7.0.39",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+          "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+          "dev": true,
+          "requires": {
+            "picocolors": "^0.2.1",
+            "source-map": "^0.6.1"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "postcss-syntax": {
+      "version": "0.36.2",
+      "resolved": "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz",
+      "integrity": "sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==",
+      "dev": true,
+      "requires": {}
+    },
+    "postcss-value-parser": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+      "dev": true
+    },
+    "postcss-values-parser": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-3.2.1.tgz",
+      "integrity": "sha512-SQ7/88VE9LhJh9gc27/hqnSU/aZaREVJcRVccXBmajgP2RkjdJzNyH/a9GCVMI5nsRhT0jC5HpUMwfkz81DVVg==",
+      "dev": true,
+      "requires": {
+        "color-name": "^1.1.4",
+        "is-url-superb": "^3.0.0",
+        "postcss": "^7.0.5",
+        "url-regex": "^5.0.0"
+      },
+      "dependencies": {
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "picocolors": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+          "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+          "dev": true
+        },
+        "postcss": {
+          "version": "7.0.39",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+          "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+          "dev": true,
+          "requires": {
+            "picocolors": "^0.2.1",
+            "source-map": "^0.6.1"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "prelude-ls": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+      "dev": true
+    },
+    "prettier": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
+      "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
+      "dev": true
+    },
+    "prettier-linter-helpers": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+      "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+      "dev": true,
+      "requires": {
+        "fast-diff": "^1.1.2"
+      }
+    },
+    "pretty-format": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz",
+      "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@jest/types": "^26.6.2",
+        "ansi-regex": "^5.0.0",
+        "ansi-styles": "^4.0.0",
+        "react-is": "^17.0.1"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true,
+          "peer": true
+        },
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "prompts": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
+      "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "kleur": "^3.0.3",
+        "sisteransi": "^1.0.5"
+      }
+    },
+    "prop-types": {
+      "version": "15.8.1",
+      "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+      "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+      "dev": true,
+      "requires": {
+        "loose-envify": "^1.4.0",
+        "object-assign": "^4.1.1",
+        "react-is": "^16.13.1"
+      },
+      "dependencies": {
+        "react-is": {
+          "version": "16.13.1",
+          "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+          "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+          "dev": true
+        }
+      }
+    },
+    "psl": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
+      "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
+      "dev": true,
+      "peer": true
+    },
+    "pump": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+      "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "punycode": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
+      "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
+      "dev": true
+    },
+    "querystringify": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+      "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
+      "dev": true,
+      "peer": true
+    },
+    "queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "dev": true
+    },
+    "quick-lru": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
+      "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
+      "dev": true
+    },
+    "react": {
+      "version": "18.0.0",
+      "resolved": "https://registry.npmjs.org/react/-/react-18.0.0.tgz",
+      "integrity": "sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "loose-envify": "^1.1.0"
+      }
+    },
+    "react-dom": {
+      "version": "18.0.0",
+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.0.0.tgz",
+      "integrity": "sha512-XqX7uzmFo0pUceWFCt7Gff6IyIMzFUn7QMZrbrQfGxtaxXZIcGQzoNpRLE3fQLnS4XzLLPMZX2T9TRcSrasicw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "loose-envify": "^1.1.0",
+        "scheduler": "^0.21.0"
+      }
+    },
+    "react-is": {
+      "version": "17.0.2",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+      "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
+      "dev": true,
+      "peer": true
+    },
+    "read-pkg": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+      "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+      "dev": true,
+      "requires": {
+        "@types/normalize-package-data": "^2.4.0",
+        "normalize-package-data": "^2.5.0",
+        "parse-json": "^5.0.0",
+        "type-fest": "^0.6.0"
+      },
+      "dependencies": {
+        "type-fest": {
+          "version": "0.6.0",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+          "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
+          "dev": true
+        }
+      }
+    },
+    "read-pkg-up": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+      "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
+      "dev": true,
+      "requires": {
+        "find-up": "^4.1.0",
+        "read-pkg": "^5.2.0",
+        "type-fest": "^0.8.1"
+      },
+      "dependencies": {
+        "find-up": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^5.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "locate-path": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^4.1.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+          "dev": true,
+          "requires": {
+            "p-try": "^2.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^2.2.0"
+          }
+        },
+        "path-exists": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+          "dev": true
+        },
+        "type-fest": {
+          "version": "0.8.1",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+          "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+          "dev": true
+        }
+      }
+    },
+    "readable-stream": {
+      "version": "3.6.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      }
+    },
+    "readdirp": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
+      "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
+      "dev": true,
+      "requires": {
+        "picomatch": "^2.2.1"
+      }
+    },
+    "redent": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
+      "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
+      "dev": true,
+      "requires": {
+        "indent-string": "^4.0.0",
+        "strip-indent": "^3.0.0"
+      }
+    },
+    "regenerator-runtime": {
+      "version": "0.13.11",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+      "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
+      "dev": true
+    },
+    "regex-not": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+      "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "extend-shallow": "^3.0.2",
+        "safe-regex": "^1.1.0"
+      }
+    },
+    "regexp.prototype.flags": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
+      "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3",
+        "functions-have-names": "^1.2.2"
+      }
+    },
+    "remark": {
+      "version": "12.0.1",
+      "resolved": "https://registry.npmjs.org/remark/-/remark-12.0.1.tgz",
+      "integrity": "sha512-gS7HDonkdIaHmmP/+shCPejCEEW+liMp/t/QwmF0Xt47Rpuhl32lLtDV1uKWvGoq+kxr5jSgg5oAIpGuyULjUw==",
+      "dev": true,
+      "requires": {
+        "remark-parse": "^8.0.0",
+        "remark-stringify": "^8.0.0",
+        "unified": "^9.0.0"
+      }
+    },
+    "remark-mdx": {
+      "version": "1.6.22",
+      "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-1.6.22.tgz",
+      "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==",
+      "dev": true,
+      "requires": {
+        "@babel/core": "7.12.9",
+        "@babel/helper-plugin-utils": "7.10.4",
+        "@babel/plugin-proposal-object-rest-spread": "7.12.1",
+        "@babel/plugin-syntax-jsx": "7.12.1",
+        "@mdx-js/util": "1.6.22",
+        "is-alphabetical": "1.0.4",
+        "remark-parse": "8.0.3",
+        "unified": "9.2.0"
+      },
+      "dependencies": {
+        "unified": {
+          "version": "9.2.0",
+          "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz",
+          "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==",
+          "dev": true,
+          "requires": {
+            "bail": "^1.0.0",
+            "extend": "^3.0.0",
+            "is-buffer": "^2.0.0",
+            "is-plain-obj": "^2.0.0",
+            "trough": "^1.0.0",
+            "vfile": "^4.0.0"
+          }
+        },
+        "unist-util-stringify-position": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
+          "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
+          "dev": true,
+          "requires": {
+            "@types/unist": "^2.0.2"
+          }
+        },
+        "vfile": {
+          "version": "4.2.1",
+          "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz",
+          "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==",
+          "dev": true,
+          "requires": {
+            "@types/unist": "^2.0.0",
+            "is-buffer": "^2.0.0",
+            "unist-util-stringify-position": "^2.0.0",
+            "vfile-message": "^2.0.0"
+          }
+        },
+        "vfile-message": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
+          "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==",
+          "dev": true,
+          "requires": {
+            "@types/unist": "^2.0.0",
+            "unist-util-stringify-position": "^2.0.0"
+          }
+        }
+      }
+    },
+    "remark-parse": {
+      "version": "8.0.3",
+      "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz",
+      "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==",
+      "dev": true,
+      "requires": {
+        "ccount": "^1.0.0",
+        "collapse-white-space": "^1.0.2",
+        "is-alphabetical": "^1.0.0",
+        "is-decimal": "^1.0.0",
+        "is-whitespace-character": "^1.0.0",
+        "is-word-character": "^1.0.0",
+        "markdown-escapes": "^1.0.0",
+        "parse-entities": "^2.0.0",
+        "repeat-string": "^1.5.4",
+        "state-toggle": "^1.0.0",
+        "trim": "0.0.1",
+        "trim-trailing-lines": "^1.0.0",
+        "unherit": "^1.0.4",
+        "unist-util-remove-position": "^2.0.0",
+        "vfile-location": "^3.0.0",
+        "xtend": "^4.0.1"
+      }
+    },
+    "remark-stringify": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-8.1.1.tgz",
+      "integrity": "sha512-q4EyPZT3PcA3Eq7vPpT6bIdokXzFGp9i85igjmhRyXWmPs0Y6/d2FYwUNotKAWyLch7g0ASZJn/KHHcHZQ163A==",
+      "dev": true,
+      "requires": {
+        "ccount": "^1.0.0",
+        "is-alphanumeric": "^1.0.0",
+        "is-decimal": "^1.0.0",
+        "is-whitespace-character": "^1.0.0",
+        "longest-streak": "^2.0.1",
+        "markdown-escapes": "^1.0.0",
+        "markdown-table": "^2.0.0",
+        "mdast-util-compact": "^2.0.0",
+        "parse-entities": "^2.0.0",
+        "repeat-string": "^1.5.4",
+        "state-toggle": "^1.0.0",
+        "stringify-entities": "^3.0.0",
+        "unherit": "^1.0.4",
+        "xtend": "^4.0.1"
+      }
+    },
+    "remove-trailing-separator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+      "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==",
+      "dev": true,
+      "peer": true
+    },
+    "repeat-element": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
+      "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==",
+      "dev": true,
+      "peer": true
+    },
+    "repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==",
+      "dev": true
+    },
+    "require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "dev": true
+    },
+    "require-from-string": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+      "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+      "dev": true
+    },
+    "require-main-filename": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+      "dev": true,
+      "peer": true
+    },
+    "requires-port": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+      "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+      "dev": true,
+      "peer": true
+    },
+    "resolve": {
+      "version": "1.22.1",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+      "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+      "dev": true,
+      "requires": {
+        "is-core-module": "^2.9.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      }
+    },
+    "resolve-cwd": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
+      "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "resolve-from": "^5.0.0"
+      },
+      "dependencies": {
+        "resolve-from": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+          "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true
+    },
+    "resolve-url": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+      "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==",
+      "dev": true,
+      "peer": true
+    },
+    "restore-cursor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+      "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+      "dev": true,
+      "requires": {
+        "onetime": "^5.1.0",
+        "signal-exit": "^3.0.2"
+      }
+    },
+    "ret": {
+      "version": "0.1.15",
+      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+      "dev": true,
+      "peer": true
+    },
+    "reusify": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+      "dev": true
+    },
+    "rfdc": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
+      "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==",
+      "dev": true
+    },
+    "rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "dev": true,
+      "requires": {
+        "glob": "^7.1.3"
+      }
+    },
+    "rivet-graphql": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/rivet-graphql/-/rivet-graphql-0.3.1.tgz",
+      "integrity": "sha512-HEov02XhZ6H1jOME+mO8CZwliu/UtgZSHixYUwvQ7HSx3gk8EOVaQY5c3zscOYjZECvP8cR4+1Ob3KHWJRWEMw==",
+      "dev": true,
+      "requires": {
+        "graphql": "^15.3.0",
+        "graphql-request": "^3.0.0"
+      }
+    },
+    "rsvp": {
+      "version": "4.8.5",
+      "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
+      "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==",
+      "dev": true,
+      "peer": true
+    },
+    "run-async": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
+      "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+      "dev": true
+    },
+    "run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "requires": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "rxjs": {
+      "version": "6.6.7",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+      "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+      "dev": true,
+      "requires": {
+        "tslib": "^1.9.0"
+      }
+    },
+    "safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "dev": true
+    },
+    "safe-regex": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+      "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "ret": "~0.1.10"
+      }
+    },
+    "safe-regex-test": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
+      "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.1.3",
+        "is-regex": "^1.1.4"
+      }
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true
+    },
+    "sane": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz",
+      "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@cnakazawa/watch": "^1.0.3",
+        "anymatch": "^2.0.0",
+        "capture-exit": "^2.0.0",
+        "exec-sh": "^0.3.2",
+        "execa": "^1.0.0",
+        "fb-watchman": "^2.0.0",
+        "micromatch": "^3.1.4",
+        "minimist": "^1.1.1",
+        "walker": "~1.0.5"
+      },
+      "dependencies": {
+        "anymatch": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+          "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "micromatch": "^3.1.4",
+            "normalize-path": "^2.1.1"
+          }
+        },
+        "braces": {
+          "version": "2.3.2",
+          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "arr-flatten": "^1.1.0",
+            "array-unique": "^0.3.2",
+            "extend-shallow": "^2.0.1",
+            "fill-range": "^4.0.0",
+            "isobject": "^3.0.1",
+            "repeat-element": "^1.1.2",
+            "snapdragon": "^0.8.1",
+            "snapdragon-node": "^2.0.1",
+            "split-string": "^3.0.2",
+            "to-regex": "^3.0.1"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "cross-spawn": {
+          "version": "6.0.5",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+          "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "nice-try": "^1.0.4",
+            "path-key": "^2.0.1",
+            "semver": "^5.5.0",
+            "shebang-command": "^1.2.0",
+            "which": "^1.2.9"
+          }
+        },
+        "execa": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+          "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "cross-spawn": "^6.0.0",
+            "get-stream": "^4.0.0",
+            "is-stream": "^1.1.0",
+            "npm-run-path": "^2.0.0",
+            "p-finally": "^1.0.0",
+            "signal-exit": "^3.0.0",
+            "strip-eof": "^1.0.0"
+          }
+        },
+        "fill-range": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+          "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "extend-shallow": "^2.0.1",
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1",
+            "to-regex-range": "^2.1.0"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "get-stream": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+          "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "pump": "^3.0.0"
+          }
+        },
+        "is-buffer": {
+          "version": "1.1.6",
+          "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+          "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+          "dev": true,
+          "peer": true
+        },
+        "is-extendable": {
+          "version": "0.1.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+          "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+          "dev": true,
+          "peer": true
+        },
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "is-stream": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+          "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
+          "dev": true,
+          "peer": true
+        },
+        "micromatch": {
+          "version": "3.1.10",
+          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "arr-diff": "^4.0.0",
+            "array-unique": "^0.3.2",
+            "braces": "^2.3.1",
+            "define-property": "^2.0.2",
+            "extend-shallow": "^3.0.2",
+            "extglob": "^2.0.4",
+            "fragment-cache": "^0.2.1",
+            "kind-of": "^6.0.2",
+            "nanomatch": "^1.2.9",
+            "object.pick": "^1.3.0",
+            "regex-not": "^1.0.0",
+            "snapdragon": "^0.8.1",
+            "to-regex": "^3.0.2"
+          }
+        },
+        "normalize-path": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+          "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "remove-trailing-separator": "^1.0.1"
+          }
+        },
+        "npm-run-path": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+          "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "path-key": "^2.0.0"
+          }
+        },
+        "path-key": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+          "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
+          "dev": true,
+          "peer": true
+        },
+        "shebang-command": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+          "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "shebang-regex": "^1.0.0"
+          }
+        },
+        "shebang-regex": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+          "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
+          "dev": true,
+          "peer": true
+        },
+        "to-regex-range": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+          "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1"
+          }
+        },
+        "which": {
+          "version": "1.3.1",
+          "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+          "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "isexe": "^2.0.0"
+          }
+        }
+      }
+    },
+    "saxes": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz",
+      "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "xmlchars": "^2.2.0"
+      }
+    },
+    "scheduler": {
+      "version": "0.21.0",
+      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz",
+      "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "loose-envify": "^1.1.0"
+      }
+    },
+    "semver": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+      "dev": true
+    },
+    "semver-compare": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
+      "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
+      "dev": true
+    },
+    "set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+      "dev": true,
+      "peer": true
+    },
+    "set-value": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "extend-shallow": "^2.0.1",
+        "is-extendable": "^0.1.1",
+        "is-plain-object": "^2.0.3",
+        "split-string": "^3.0.1"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "is-extendable": {
+          "version": "0.1.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+          "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "requires": {
+        "shebang-regex": "^3.0.0"
+      }
+    },
+    "shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true
+    },
+    "shellwords": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
+      "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
+      "dev": true,
+      "optional": true,
+      "peer": true
+    },
+    "side-channel": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.0",
+        "get-intrinsic": "^1.0.2",
+        "object-inspect": "^1.9.0"
+      }
+    },
+    "signal-exit": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+      "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+      "dev": true
+    },
+    "signale": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz",
+      "integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==",
+      "dev": true,
+      "requires": {
+        "chalk": "^2.3.2",
+        "figures": "^2.0.0",
+        "pkg-conf": "^2.1.0"
+      },
+      "dependencies": {
+        "figures": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+          "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==",
+          "dev": true,
+          "requires": {
+            "escape-string-regexp": "^1.0.5"
+          }
+        }
+      }
+    },
+    "sisteransi": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
+      "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+      "dev": true,
+      "peer": true
+    },
+    "slash": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
+      "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
+      "dev": true
+    },
+    "slice-ansi": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
+      "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^4.0.0",
+        "astral-regex": "^2.0.0",
+        "is-fullwidth-code-point": "^3.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        }
+      }
+    },
+    "slugify": {
+      "version": "1.4.6",
+      "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.6.tgz",
+      "integrity": "sha512-ZdJIgv9gdrYwhXqxsH9pv7nXxjUEyQ6nqhngRxoAAOlmMGA28FDq5O4/5US4G2/Nod7d1ovNcgURQJ7kHq50KQ==",
+      "dev": true
+    },
+    "snapdragon": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+      "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "base": "^0.11.1",
+        "debug": "^2.2.0",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "map-cache": "^0.2.2",
+        "source-map": "^0.5.6",
+        "source-map-resolve": "^0.5.0",
+        "use": "^3.1.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+          "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "is-buffer": {
+          "version": "1.1.6",
+          "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+          "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+          "dev": true,
+          "peer": true
+        },
+        "is-data-descriptor": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+          "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "is-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+          "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-accessor-descriptor": "^0.1.6",
+            "is-data-descriptor": "^0.1.4",
+            "kind-of": "^5.0.0"
+          }
+        },
+        "is-extendable": {
+          "version": "0.1.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+          "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+          "dev": true,
+          "peer": true
+        },
+        "kind-of": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+          "dev": true,
+          "peer": true
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "snapdragon-node": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+      "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.0",
+        "snapdragon-util": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        }
+      }
+    },
+    "snapdragon-util": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+      "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "kind-of": "^3.2.0"
+      },
+      "dependencies": {
+        "is-buffer": {
+          "version": "1.1.6",
+          "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+          "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+          "dev": true,
+          "peer": true
+        },
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "source-map": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+      "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+      "dev": true
+    },
+    "source-map-js": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+      "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+      "dev": true
+    },
+    "source-map-resolve": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+      "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "atob": "^2.1.2",
+        "decode-uri-component": "^0.2.0",
+        "resolve-url": "^0.2.1",
+        "source-map-url": "^0.4.0",
+        "urix": "^0.1.0"
+      }
+    },
+    "source-map-support": {
+      "version": "0.5.21",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "source-map-url": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
+      "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
+      "dev": true,
+      "peer": true
+    },
+    "spdx-correct": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
+      "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
+      "dev": true,
+      "requires": {
+        "spdx-expression-parse": "^3.0.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-exceptions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+      "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
+      "dev": true
+    },
+    "spdx-expression-parse": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+      "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+      "dev": true,
+      "requires": {
+        "spdx-exceptions": "^2.1.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-license-ids": {
+      "version": "3.0.13",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz",
+      "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==",
+      "dev": true
+    },
+    "specificity": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/specificity/-/specificity-0.4.1.tgz",
+      "integrity": "sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==",
+      "dev": true
+    },
+    "split-string": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+      "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "extend-shallow": "^3.0.0"
+      }
+    },
+    "sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+      "dev": true,
+      "peer": true
+    },
+    "stack-utils": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
+      "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "escape-string-regexp": "^2.0.0"
+      },
+      "dependencies": {
+        "escape-string-regexp": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+          "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "state-toggle": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz",
+      "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==",
+      "dev": true
+    },
+    "static-extend": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+      "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "define-property": "^0.2.5",
+        "object-copy": "^0.1.0"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+          "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "is-buffer": {
+          "version": "1.1.6",
+          "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+          "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+          "dev": true,
+          "peer": true
+        },
+        "is-data-descriptor": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+          "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "is-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+          "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-accessor-descriptor": "^0.1.6",
+            "is-data-descriptor": "^0.1.4",
+            "kind-of": "^5.0.0"
+          }
+        },
+        "kind-of": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "stop-iteration-iterator": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
+      "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==",
+      "dev": true,
+      "requires": {
+        "internal-slot": "^1.0.4"
+      }
+    },
+    "string_decoder": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "~5.2.0"
+      }
+    },
+    "string-argv": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
+      "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==",
+      "dev": true
+    },
+    "string-length": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
+      "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "char-regex": "^1.0.2",
+        "strip-ansi": "^6.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true,
+          "peer": true
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        }
+      }
+    },
+    "string-width": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+      "dev": true,
+      "requires": {
+        "eastasianwidth": "^0.2.0",
+        "emoji-regex": "^9.2.2",
+        "strip-ansi": "^7.0.1"
+      }
+    },
+    "string.prototype.matchall": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz",
+      "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4",
+        "get-intrinsic": "^1.1.3",
+        "has-symbols": "^1.0.3",
+        "internal-slot": "^1.0.3",
+        "regexp.prototype.flags": "^1.4.3",
+        "side-channel": "^1.0.4"
+      }
+    },
+    "string.prototype.trim": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz",
+      "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4"
+      }
+    },
+    "string.prototype.trimend": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz",
+      "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4"
+      }
+    },
+    "string.prototype.trimstart": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz",
+      "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4"
+      }
+    },
+    "stringify-entities": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-3.1.0.tgz",
+      "integrity": "sha512-3FP+jGMmMV/ffZs86MoghGqAoqXAdxLrJP4GUdrDN1aIScYih5tuIO3eF4To5AJZ79KDZ8Fpdy7QJnK8SsL1Vg==",
+      "dev": true,
+      "requires": {
+        "character-entities-html4": "^1.0.0",
+        "character-entities-legacy": "^1.0.0",
+        "xtend": "^4.0.0"
+      }
+    },
+    "stringify-object": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
+      "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==",
+      "dev": true,
+      "requires": {
+        "get-own-enumerable-property-symbols": "^3.0.0",
+        "is-obj": "^1.0.1",
+        "is-regexp": "^1.0.0"
+      }
+    },
+    "strip-ansi": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
+      "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "^6.0.1"
+      }
+    },
+    "strip-bom": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+      "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+      "dev": true,
+      "peer": true
+    },
+    "strip-eof": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+      "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==",
+      "dev": true,
+      "peer": true
+    },
+    "strip-final-newline": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+      "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+      "dev": true
+    },
+    "strip-indent": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+      "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+      "dev": true,
+      "requires": {
+        "min-indent": "^1.0.0"
+      }
+    },
+    "strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true
+    },
+    "style-search": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz",
+      "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==",
+      "dev": true
+    },
+    "styled-jsx": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.1.tgz",
+      "integrity": "sha512-+PIZ/6Uk40mphiQJJI1202b+/dYeTVd9ZnMPR80pgiWbjIwvN2zIp4r9et0BgqBuShh48I0gttPlAXA7WVvBxw==",
+      "dev": true,
+      "requires": {}
+    },
+    "stylelint": {
+      "version": "13.8.0",
+      "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.8.0.tgz",
+      "integrity": "sha512-iHH3dv3UI23SLDrH4zMQDjLT9/dDIz/IpoFeuNxZmEx86KtfpjDOscxLTFioQyv+2vQjPlRZnK0UoJtfxLICXQ==",
+      "dev": true,
+      "requires": {
+        "@stylelint/postcss-css-in-js": "^0.37.2",
+        "@stylelint/postcss-markdown": "^0.36.2",
+        "autoprefixer": "^9.8.6",
+        "balanced-match": "^1.0.0",
+        "chalk": "^4.1.0",
+        "cosmiconfig": "^7.0.0",
+        "debug": "^4.2.0",
+        "execall": "^2.0.0",
+        "fast-glob": "^3.2.4",
+        "fastest-levenshtein": "^1.0.12",
+        "file-entry-cache": "^6.0.0",
+        "get-stdin": "^8.0.0",
+        "global-modules": "^2.0.0",
+        "globby": "^11.0.1",
+        "globjoin": "^0.1.4",
+        "html-tags": "^3.1.0",
+        "ignore": "^5.1.8",
+        "import-lazy": "^4.0.0",
+        "imurmurhash": "^0.1.4",
+        "known-css-properties": "^0.20.0",
+        "lodash": "^4.17.20",
+        "log-symbols": "^4.0.0",
+        "mathml-tag-names": "^2.1.3",
+        "meow": "^8.0.0",
+        "micromatch": "^4.0.2",
+        "normalize-selector": "^0.2.0",
+        "postcss": "^7.0.35",
+        "postcss-html": "^0.36.0",
+        "postcss-less": "^3.1.4",
+        "postcss-media-query-parser": "^0.2.3",
+        "postcss-resolve-nested-selector": "^0.1.1",
+        "postcss-safe-parser": "^4.0.2",
+        "postcss-sass": "^0.4.4",
+        "postcss-scss": "^2.1.1",
+        "postcss-selector-parser": "^6.0.4",
+        "postcss-syntax": "^0.36.2",
+        "postcss-value-parser": "^4.1.0",
+        "resolve-from": "^5.0.0",
+        "slash": "^3.0.0",
+        "specificity": "^0.4.1",
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "style-search": "^0.1.0",
+        "sugarss": "^2.0.0",
+        "svg-tags": "^1.0.0",
+        "table": "^6.0.3",
+        "v8-compile-cache": "^2.2.0",
+        "write-file-atomic": "^3.0.3"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "globby": {
+          "version": "11.1.0",
+          "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+          "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+          "dev": true,
+          "requires": {
+            "array-union": "^2.1.0",
+            "dir-glob": "^3.0.1",
+            "fast-glob": "^3.2.9",
+            "ignore": "^5.2.0",
+            "merge2": "^1.4.1",
+            "slash": "^3.0.0"
+          }
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "picocolors": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+          "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+          "dev": true
+        },
+        "postcss": {
+          "version": "7.0.39",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+          "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+          "dev": true,
+          "requires": {
+            "picocolors": "^0.2.1",
+            "source-map": "^0.6.1"
+          }
+        },
+        "resolve-from": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+          "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+          "dev": true
+        },
+        "slash": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+          "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+          "dev": true
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "4.2.3",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.1"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "stylelint-config-css-modules": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/stylelint-config-css-modules/-/stylelint-config-css-modules-2.2.0.tgz",
+      "integrity": "sha512-+zjcDbot+zbuxy1UA31k4G2lUG+nHUwnLyii3uT2F09B8kT2YrT9LZYNfMtAWlDidrxr7sFd5HX9EqPHGU3WKA==",
+      "dev": true,
+      "requires": {}
+    },
+    "stylelint-config-prettier": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/stylelint-config-prettier/-/stylelint-config-prettier-8.0.2.tgz",
+      "integrity": "sha512-TN1l93iVTXpF9NJstlvP7nOu9zY2k+mN0NSFQ/VEGz15ZIP9ohdDZTtCWHs5LjctAhSAzaILULGbgiM0ItId3A==",
+      "dev": true,
+      "requires": {}
+    },
+    "stylelint-config-recommended": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-3.0.0.tgz",
+      "integrity": "sha512-F6yTRuc06xr1h5Qw/ykb2LuFynJ2IxkKfCMf+1xqPffkxh0S09Zc902XCffcsw/XMFq/OzQ1w54fLIDtmRNHnQ==",
+      "dev": true,
+      "requires": {}
+    },
+    "stylelint-config-standard": {
+      "version": "20.0.0",
+      "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-20.0.0.tgz",
+      "integrity": "sha512-IB2iFdzOTA/zS4jSVav6z+wGtin08qfj+YyExHB3LF9lnouQht//YyB0KZq9gGz5HNPkddHOzcY8HsUey6ZUlA==",
+      "dev": true,
+      "requires": {
+        "stylelint-config-recommended": "^3.0.0"
+      }
+    },
+    "stylelint-media-use-custom-media": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/stylelint-media-use-custom-media/-/stylelint-media-use-custom-media-2.0.0.tgz",
+      "integrity": "sha512-G7Hwma8HIMFJOChqrX9ie8hAGbtEMUbEjuiaR3olHIXjloDWqYlFHIJKsCyyckigkm+4LtCwtZDQASrVY4pRBg==",
+      "dev": true,
+      "requires": {}
+    },
+    "stylelint-order": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-4.1.0.tgz",
+      "integrity": "sha512-sVTikaDvMqg2aJjh4r48jsdfmqLT+nqB1MOsaBnvM3OwLx4S+WXcsxsgk5w18h/OZoxZCxuyXMh61iBHcj9Qiw==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.15",
+        "postcss": "^7.0.31",
+        "postcss-sorting": "^5.0.1"
+      },
+      "dependencies": {
+        "picocolors": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+          "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+          "dev": true
+        },
+        "postcss": {
+          "version": "7.0.39",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+          "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+          "dev": true,
+          "requires": {
+            "picocolors": "^0.2.1",
+            "source-map": "^0.6.1"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "stylelint-use-nesting": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/stylelint-use-nesting/-/stylelint-use-nesting-3.0.0.tgz",
+      "integrity": "sha512-BMzhXWbK5DdAYtZMQULn7VmWZXpy8Rwlx2PgeNYqKInQrKTJWM/TFKPScc+xvsGUc/6JPiUDeQQij9gFnOo8Kg==",
+      "dev": true,
+      "requires": {}
+    },
+    "stylelint-value-no-unknown-custom-properties": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/stylelint-value-no-unknown-custom-properties/-/stylelint-value-no-unknown-custom-properties-3.0.0.tgz",
+      "integrity": "sha512-8WoOnZ4ELTxA1cDbhwolIVOutxHwbjpXmd0lL0Li3Iye078jSnEb1KO6pJ/ig5oDVGRApFeA25Fyy4qqmqwGgg==",
+      "dev": true,
+      "requires": {
+        "postcss-values-parser": "^3.2.1"
+      }
+    },
+    "sugarss": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz",
+      "integrity": "sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==",
+      "dev": true,
+      "requires": {
+        "postcss": "^7.0.2"
+      },
+      "dependencies": {
+        "picocolors": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+          "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
+          "dev": true
+        },
+        "postcss": {
+          "version": "7.0.39",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+          "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+          "dev": true,
+          "requires": {
+            "picocolors": "^0.2.1",
+            "source-map": "^0.6.1"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "requires": {
+        "has-flag": "^3.0.0"
+      }
+    },
+    "supports-hyperlinks": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz",
+      "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "has-flag": "^4.0.0",
+        "supports-color": "^7.0.0"
+      },
+      "dependencies": {
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "peer": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "dev": true
+    },
+    "svg-tags": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
+      "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==",
+      "dev": true
+    },
+    "symbol-tree": {
+      "version": "3.2.4",
+      "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+      "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
+      "dev": true,
+      "peer": true
+    },
+    "synckit": {
+      "version": "0.8.5",
+      "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz",
+      "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==",
+      "dev": true,
+      "requires": {
+        "@pkgr/utils": "^2.3.1",
+        "tslib": "^2.5.0"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.5.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+          "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
+          "dev": true
+        }
+      }
+    },
+    "table": {
+      "version": "6.8.1",
+      "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz",
+      "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==",
+      "dev": true,
+      "requires": {
+        "ajv": "^8.0.1",
+        "lodash.truncate": "^4.4.2",
+        "slice-ansi": "^4.0.0",
+        "string-width": "^4.2.3",
+        "strip-ansi": "^6.0.1"
+      },
+      "dependencies": {
+        "ajv": {
+          "version": "8.12.0",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+          "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "json-schema-traverse": "^1.0.0",
+            "require-from-string": "^2.0.2",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "json-schema-traverse": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+          "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+          "dev": true
+        },
+        "slice-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+          "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.0.0",
+            "astral-regex": "^2.0.0",
+            "is-fullwidth-code-point": "^3.0.0"
+          }
+        },
+        "string-width": {
+          "version": "4.2.3",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.1"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        }
+      }
+    },
+    "tapable": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
+      "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
+      "dev": true
+    },
+    "terminal-link": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz",
+      "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "ansi-escapes": "^4.2.1",
+        "supports-hyperlinks": "^2.0.0"
+      }
+    },
+    "test-exclude": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+      "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@istanbuljs/schema": "^0.1.2",
+        "glob": "^7.1.4",
+        "minimatch": "^3.0.4"
+      }
+    },
+    "text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+      "dev": true
+    },
+    "throat": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
+      "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==",
+      "dev": true,
+      "peer": true
+    },
+    "through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+      "dev": true
+    },
+    "tiny-glob": {
+      "version": "0.2.9",
+      "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
+      "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
+      "dev": true,
+      "requires": {
+        "globalyzer": "0.1.0",
+        "globrex": "^0.1.2"
+      }
+    },
+    "tlds": {
+      "version": "1.237.0",
+      "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.237.0.tgz",
+      "integrity": "sha512-4IA6zR7jQop4pEdziQaptOgkIwnnZ537fXM3MKAzOXjXLjiHm77SA3/E0nXWJGSVRnKcn/JxDJmwTqyPgQ+ozg==",
+      "dev": true
+    },
+    "tmp": {
+      "version": "0.0.33",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+      "dev": true,
+      "requires": {
+        "os-tmpdir": "~1.0.2"
+      }
+    },
+    "tmpl": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
+      "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
+      "dev": true,
+      "peer": true
+    },
+    "to-fast-properties": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+      "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
+      "dev": true
+    },
+    "to-object-path": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+      "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "is-buffer": {
+          "version": "1.1.6",
+          "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+          "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+          "dev": true,
+          "peer": true
+        },
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "to-regex": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+      "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "regex-not": "^1.0.2",
+        "safe-regex": "^1.1.0"
+      }
+    },
+    "to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "requires": {
+        "is-number": "^7.0.0"
+      }
+    },
+    "tough-cookie": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
+      "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "psl": "^1.1.33",
+        "punycode": "^2.1.1",
+        "universalify": "^0.2.0",
+        "url-parse": "^1.5.3"
+      },
+      "dependencies": {
+        "universalify": {
+          "version": "0.2.0",
+          "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
+          "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "tr46": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz",
+      "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "punycode": "^2.1.1"
+      }
+    },
+    "trim": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
+      "integrity": "sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==",
+      "dev": true
+    },
+    "trim-newlines": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
+      "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
+      "dev": true
+    },
+    "trim-trailing-lines": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz",
+      "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==",
+      "dev": true
+    },
+    "trough": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
+      "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==",
+      "dev": true
+    },
+    "ts-jest": {
+      "version": "26.5.6",
+      "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz",
+      "integrity": "sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA==",
+      "dev": true,
+      "requires": {
+        "bs-logger": "0.x",
+        "buffer-from": "1.x",
+        "fast-json-stable-stringify": "2.x",
+        "jest-util": "^26.1.0",
+        "json5": "2.x",
+        "lodash": "4.x",
+        "make-error": "1.x",
+        "mkdirp": "1.x",
+        "semver": "7.x",
+        "yargs-parser": "20.x"
+      },
+      "dependencies": {
+        "lru-cache": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+          "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+          "dev": true,
+          "requires": {
+            "yallist": "^4.0.0"
+          }
+        },
+        "semver": {
+          "version": "7.3.8",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+          "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "yallist": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+          "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+          "dev": true
+        },
+        "yargs-parser": {
+          "version": "20.2.9",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+          "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+          "dev": true
+        }
+      }
+    },
+    "tsconfig-paths": {
+      "version": "3.14.2",
+      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
+      "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==",
+      "dev": true,
+      "requires": {
+        "@types/json5": "^0.0.29",
+        "json5": "^1.0.2",
+        "minimist": "^1.2.6",
+        "strip-bom": "^3.0.0"
+      },
+      "dependencies": {
+        "json5": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+          "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+          "dev": true,
+          "requires": {
+            "minimist": "^1.2.0"
+          }
+        },
+        "strip-bom": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+          "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+          "dev": true
+        }
+      }
+    },
+    "tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "dev": true
+    },
+    "tsutils": {
+      "version": "3.21.0",
+      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+      "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+      "dev": true,
+      "requires": {
+        "tslib": "^1.8.1"
+      }
+    },
+    "type-check": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "^1.2.1"
+      }
+    },
+    "type-detect": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+      "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+      "dev": true,
+      "peer": true
+    },
+    "type-fest": {
+      "version": "0.21.3",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+      "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+      "dev": true
+    },
+    "typed-array-length": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz",
+      "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "for-each": "^0.3.3",
+        "is-typed-array": "^1.1.9"
+      }
+    },
+    "typedarray-to-buffer": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+      "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+      "dev": true,
+      "requires": {
+        "is-typedarray": "^1.0.0"
+      }
+    },
+    "typescript": {
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+      "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
+      "dev": true,
+      "peer": true
+    },
+    "unbox-primitive": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
+      "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "has-bigints": "^1.0.2",
+        "has-symbols": "^1.0.3",
+        "which-boxed-primitive": "^1.0.2"
+      }
+    },
+    "unherit": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz",
+      "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.0",
+        "xtend": "^4.0.0"
+      }
+    },
+    "unified": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz",
+      "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==",
+      "dev": true,
+      "requires": {
+        "bail": "^1.0.0",
+        "extend": "^3.0.0",
+        "is-buffer": "^2.0.0",
+        "is-plain-obj": "^2.0.0",
+        "trough": "^1.0.0",
+        "vfile": "^4.0.0"
+      },
+      "dependencies": {
+        "unist-util-stringify-position": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
+          "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
+          "dev": true,
+          "requires": {
+            "@types/unist": "^2.0.2"
+          }
+        },
+        "vfile": {
+          "version": "4.2.1",
+          "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz",
+          "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==",
+          "dev": true,
+          "requires": {
+            "@types/unist": "^2.0.0",
+            "is-buffer": "^2.0.0",
+            "unist-util-stringify-position": "^2.0.0",
+            "vfile-message": "^2.0.0"
+          }
+        },
+        "vfile-message": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
+          "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==",
+          "dev": true,
+          "requires": {
+            "@types/unist": "^2.0.0",
+            "unist-util-stringify-position": "^2.0.0"
+          }
+        }
+      }
+    },
+    "unified-lint-rule": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/unified-lint-rule/-/unified-lint-rule-2.1.1.tgz",
+      "integrity": "sha512-vsLHyLZFstqtGse2gvrGwasOmH8M2y+r2kQMoDSWzSqUkQx2MjHjvZuGSv5FUaiv4RQO1bHRajy7lSGp7XWq5A==",
+      "dev": true,
+      "requires": {
+        "@types/unist": "^2.0.0",
+        "trough": "^2.0.0",
+        "unified": "^10.0.0",
+        "vfile": "^5.0.0"
+      },
+      "dependencies": {
+        "bail": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
+          "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==",
+          "dev": true
+        },
+        "is-plain-obj": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
+          "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
+          "dev": true
+        },
+        "trough": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz",
+          "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==",
+          "dev": true
+        },
+        "unified": {
+          "version": "10.1.2",
+          "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz",
+          "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==",
+          "dev": true,
+          "requires": {
+            "@types/unist": "^2.0.0",
+            "bail": "^2.0.0",
+            "extend": "^3.0.0",
+            "is-buffer": "^2.0.0",
+            "is-plain-obj": "^4.0.0",
+            "trough": "^2.0.0",
+            "vfile": "^5.0.0"
+          }
+        }
+      }
+    },
+    "union-value": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "get-value": "^2.0.6",
+        "is-extendable": "^0.1.1",
+        "set-value": "^2.0.1"
+      },
+      "dependencies": {
+        "is-extendable": {
+          "version": "0.1.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+          "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "unist-util-find-all-after": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/unist-util-find-all-after/-/unist-util-find-all-after-3.0.2.tgz",
+      "integrity": "sha512-xaTC/AGZ0rIM2gM28YVRAFPIZpzbpDtU3dRmp7EXlNVA8ziQc4hY3H7BHXM1J49nEmiqc3svnqMReW+PGqbZKQ==",
+      "dev": true,
+      "requires": {
+        "unist-util-is": "^4.0.0"
+      },
+      "dependencies": {
+        "unist-util-is": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz",
+          "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==",
+          "dev": true
+        }
+      }
+    },
+    "unist-util-is": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz",
+      "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==",
+      "dev": true,
+      "requires": {
+        "@types/unist": "^2.0.0"
+      }
+    },
+    "unist-util-remove-position": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz",
+      "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==",
+      "dev": true,
+      "requires": {
+        "unist-util-visit": "^2.0.0"
+      },
+      "dependencies": {
+        "unist-util-is": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz",
+          "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==",
+          "dev": true
+        },
+        "unist-util-visit": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz",
+          "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==",
+          "dev": true,
+          "requires": {
+            "@types/unist": "^2.0.0",
+            "unist-util-is": "^4.0.0",
+            "unist-util-visit-parents": "^3.0.0"
+          }
+        },
+        "unist-util-visit-parents": {
+          "version": "3.1.1",
+          "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz",
+          "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==",
+          "dev": true,
+          "requires": {
+            "@types/unist": "^2.0.0",
+            "unist-util-is": "^4.0.0"
+          }
+        }
+      }
+    },
+    "unist-util-stringify-position": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz",
+      "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==",
+      "dev": true,
+      "requires": {
+        "@types/unist": "^2.0.0"
+      }
+    },
+    "unist-util-visit": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz",
+      "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==",
+      "dev": true,
+      "requires": {
+        "@types/unist": "^2.0.0",
+        "unist-util-is": "^5.0.0",
+        "unist-util-visit-parents": "^5.1.1"
+      }
+    },
+    "unist-util-visit-parents": {
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz",
+      "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==",
+      "dev": true,
+      "requires": {
+        "@types/unist": "^2.0.0",
+        "unist-util-is": "^5.0.0"
+      }
+    },
+    "universalify": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
+      "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
+      "dev": true
+    },
+    "unset-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+      "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "has-value": "^0.3.1",
+        "isobject": "^3.0.0"
+      },
+      "dependencies": {
+        "has-value": {
+          "version": "0.3.1",
+          "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+          "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "get-value": "^2.0.3",
+            "has-values": "^0.1.4",
+            "isobject": "^2.0.0"
+          },
+          "dependencies": {
+            "isobject": {
+              "version": "2.1.0",
+              "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+              "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "isarray": "1.0.0"
+              }
+            }
+          }
+        },
+        "has-values": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+          "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==",
+          "dev": true,
+          "peer": true
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "update-browserslist-db": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
+      "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
+      "dev": true,
+      "requires": {
+        "escalade": "^3.1.1",
+        "picocolors": "^1.0.0"
+      }
+    },
+    "uri-js": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+      "dev": true,
+      "requires": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "urix": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+      "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==",
+      "dev": true,
+      "peer": true
+    },
+    "url-parse": {
+      "version": "1.5.10",
+      "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
+      "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "querystringify": "^2.1.1",
+        "requires-port": "^1.0.0"
+      }
+    },
+    "url-regex": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/url-regex/-/url-regex-5.0.0.tgz",
+      "integrity": "sha512-O08GjTiAFNsSlrUWfqF1jH0H1W3m35ZyadHrGv5krdnmPPoxP27oDTqux/579PtaroiSGm5yma6KT1mHFH6Y/g==",
+      "dev": true,
+      "requires": {
+        "ip-regex": "^4.1.0",
+        "tlds": "^1.203.0"
+      }
+    },
+    "use": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+      "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+      "dev": true,
+      "peer": true
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+      "dev": true
+    },
+    "uuid": {
+      "version": "8.3.2",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+      "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+      "dev": true,
+      "optional": true,
+      "peer": true
+    },
+    "v8-compile-cache": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
+      "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
+      "dev": true
+    },
+    "v8-to-istanbul": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz",
+      "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "@types/istanbul-lib-coverage": "^2.0.1",
+        "convert-source-map": "^1.6.0",
+        "source-map": "^0.7.3"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.7.4",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+          "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "validate-npm-package-license": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+      "dev": true,
+      "requires": {
+        "spdx-correct": "^3.0.0",
+        "spdx-expression-parse": "^3.0.0"
+      }
+    },
+    "vfile": {
+      "version": "5.3.7",
+      "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz",
+      "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==",
+      "dev": true,
+      "requires": {
+        "@types/unist": "^2.0.0",
+        "is-buffer": "^2.0.0",
+        "unist-util-stringify-position": "^3.0.0",
+        "vfile-message": "^3.0.0"
+      }
+    },
+    "vfile-location": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz",
+      "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==",
+      "dev": true
+    },
+    "vfile-matter": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/vfile-matter/-/vfile-matter-4.0.1.tgz",
+      "integrity": "sha512-ZeACdaxCOxhePpoLO4A5y/VgI9EuWBXu+sUk65aQ7lXBZDFg7X0tuOzigLJUtsQzazFt6K2m9SdlDxZdfL5vVg==",
+      "dev": true,
+      "requires": {
+        "is-buffer": "^2.0.0",
+        "vfile": "^5.0.0",
+        "yaml": "^2.0.0"
+      }
+    },
+    "vfile-message": {
+      "version": "3.1.4",
+      "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz",
+      "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==",
+      "dev": true,
+      "requires": {
+        "@types/unist": "^2.0.0",
+        "unist-util-stringify-position": "^3.0.0"
+      }
+    },
+    "vfile-reporter": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/vfile-reporter/-/vfile-reporter-7.0.5.tgz",
+      "integrity": "sha512-NdWWXkv6gcd7AZMvDomlQbK3MqFWL1RlGzMn++/O2TI+68+nqxCPTvLugdOtfSzXmjh+xUyhp07HhlrbJjT+mw==",
+      "dev": true,
+      "requires": {
+        "@types/supports-color": "^8.0.0",
+        "string-width": "^5.0.0",
+        "supports-color": "^9.0.0",
+        "unist-util-stringify-position": "^3.0.0",
+        "vfile": "^5.0.0",
+        "vfile-message": "^3.0.0",
+        "vfile-sort": "^3.0.0",
+        "vfile-statistics": "^2.0.0"
+      },
+      "dependencies": {
+        "supports-color": {
+          "version": "9.3.1",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.3.1.tgz",
+          "integrity": "sha512-knBY82pjmnIzK3NifMo3RxEIRD9E0kIzV4BKcyTZ9+9kWgLMxd4PrsTSMoFQUabgRBbF8KOLRDCyKgNV+iK44Q==",
+          "dev": true
+        }
+      }
+    },
+    "vfile-reporter-json": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/vfile-reporter-json/-/vfile-reporter-json-3.3.0.tgz",
+      "integrity": "sha512-/zgRtjxQ2UGJn+HViiZ7+nIXtUzkkXFQum3BmaS/bSyr10P0X41ETRqqwMJ95RtbKUah3m7pKb6oS1eZeXXHzQ==",
+      "dev": true,
+      "requires": {
+        "vfile": "^5.0.0",
+        "vfile-message": "^3.0.0"
+      }
+    },
+    "vfile-sort": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/vfile-sort/-/vfile-sort-3.0.1.tgz",
+      "integrity": "sha512-1os1733XY6y0D5x0ugqSeaVJm9lYgj0j5qdcZQFyxlZOSy1jYarL77lLyb5gK4Wqr1d5OxmuyflSO3zKyFnTFw==",
+      "dev": true,
+      "requires": {
+        "vfile": "^5.0.0",
+        "vfile-message": "^3.0.0"
+      }
+    },
+    "vfile-statistics": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/vfile-statistics/-/vfile-statistics-2.0.1.tgz",
+      "integrity": "sha512-W6dkECZmP32EG/l+dp2jCLdYzmnDBIw6jwiLZSER81oR5AHRcVqL+k3Z+pfH1R73le6ayDkJRMk0sutj1bMVeg==",
+      "dev": true,
+      "requires": {
+        "vfile": "^5.0.0",
+        "vfile-message": "^3.0.0"
+      }
+    },
+    "w3c-hr-time": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
+      "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "browser-process-hrtime": "^1.0.0"
+      }
+    },
+    "w3c-xmlserializer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz",
+      "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "xml-name-validator": "^3.0.0"
+      }
+    },
+    "walker": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
+      "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "makeerror": "1.0.12"
+      }
+    },
+    "webidl-conversions": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
+      "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==",
+      "dev": true,
+      "peer": true
+    },
+    "whatwg-encoding": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
+      "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "iconv-lite": "0.4.24"
+      }
+    },
+    "whatwg-mimetype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
+      "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==",
+      "dev": true,
+      "peer": true
+    },
+    "whatwg-url": {
+      "version": "8.7.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz",
+      "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "lodash": "^4.7.0",
+        "tr46": "^2.1.0",
+        "webidl-conversions": "^6.1.0"
+      }
+    },
+    "which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "requires": {
+        "isexe": "^2.0.0"
+      }
+    },
+    "which-boxed-primitive": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
+      "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
+      "dev": true,
+      "requires": {
+        "is-bigint": "^1.0.1",
+        "is-boolean-object": "^1.1.0",
+        "is-number-object": "^1.0.4",
+        "is-string": "^1.0.5",
+        "is-symbol": "^1.0.3"
+      }
+    },
+    "which-collection": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz",
+      "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==",
+      "dev": true,
+      "requires": {
+        "is-map": "^2.0.1",
+        "is-set": "^2.0.1",
+        "is-weakmap": "^2.0.1",
+        "is-weakset": "^2.0.1"
+      }
+    },
+    "which-module": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+      "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
+      "dev": true,
+      "peer": true
+    },
+    "which-typed-array": {
+      "version": "1.1.9",
+      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz",
+      "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==",
+      "dev": true,
+      "requires": {
+        "available-typed-arrays": "^1.0.5",
+        "call-bind": "^1.0.2",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "has-tostringtag": "^1.0.0",
+        "is-typed-array": "^1.1.10"
+      }
+    },
+    "word-wrap": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+      "dev": true
+    },
+    "wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "4.2.3",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.1"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        }
+      }
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+      "dev": true
+    },
+    "write-file-atomic": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
+      "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
+      "dev": true,
+      "requires": {
+        "imurmurhash": "^0.1.4",
+        "is-typedarray": "^1.0.0",
+        "signal-exit": "^3.0.2",
+        "typedarray-to-buffer": "^3.1.5"
+      }
+    },
+    "ws": {
+      "version": "7.5.9",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
+      "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+      "dev": true,
+      "peer": true,
+      "requires": {}
+    },
+    "xml-name-validator": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
+      "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
+      "dev": true,
+      "peer": true
+    },
+    "xmlchars": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
+      "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
+      "dev": true,
+      "peer": true
+    },
+    "xtend": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+      "dev": true
+    },
+    "y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "dev": true
+    },
+    "yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+      "dev": true
+    },
+    "yaml": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
+      "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
+      "dev": true
+    },
+    "yargs": {
+      "version": "17.7.1",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz",
+      "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==",
+      "dev": true,
+      "requires": {
+        "cliui": "^8.0.1",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.3",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^21.1.1"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "4.2.3",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.1"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        }
+      }
+    },
+    "yargs-parser": {
+      "version": "21.1.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+      "dev": true
+    },
+    "yocto-queue": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
+      "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
+      "dev": true
+    },
+    "zod": {
+      "version": "3.21.4",
+      "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
+      "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==",
+      "dev": true
+    },
+    "zwitch": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz",
+      "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==",
+      "dev": true
+    }
+  }
+}
diff --git a/v1.5.7/website/package.json b/v1.5.7/website/package.json
new file mode 100644
index 0000000..eb63c57
--- /dev/null
+++ b/v1.5.7/website/package.json
@@ -0,0 +1,16 @@
+{
+  "name": "terraform-docs-preview",
+  "private": "true",
+  "scripts": {
+    "build": "./scripts/website-build.sh",
+    "content-check": "hc-content --config base-docs"
+  },
+  "devDependencies": {
+    "@hashicorp/platform-cli": "^2.6.0",
+    "@hashicorp/platform-content-conformance": "^0.0.10",
+    "next": "^12.1.0"
+  },
+  "engines": {
+    "npm": ">=7.0.0"
+  }
+}
diff --git a/v1.5.7/website/scripts/should-build.sh b/v1.5.7/website/scripts/should-build.sh
new file mode 100644
index 0000000..b653682
--- /dev/null
+++ b/v1.5.7/website/scripts/should-build.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+
+######################################################
+# NOTE: This file is managed by the Digital Team's   #
+# Terraform configuration @ hashicorp/mktg-terraform #
+######################################################
+
+# This is run during the website build step to determine if we should skip the build or not.
+# More information: https://vercel.com/docs/platform/projects#ignored-build-step
+
+if [[ "$VERCEL_GIT_COMMIT_REF" == "stable-website"  ]] ; then
+  # Proceed with the build if the branch is stable-website
+  echo "✅ - Build can proceed"
+  exit 1;
+else
+  # Check for differences in the website directory
+  git diff --quiet HEAD^ HEAD ./
+fi
\ No newline at end of file
diff --git a/v1.5.7/website/scripts/website-build.sh b/v1.5.7/website/scripts/website-build.sh
new file mode 100755
index 0000000..32d27dd
--- /dev/null
+++ b/v1.5.7/website/scripts/website-build.sh
@@ -0,0 +1,55 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+######################################################
+# NOTE: This file is managed by the Digital Team's   #
+# Terraform configuration @ hashicorp/mktg-terraform #
+######################################################
+
+# Repo which we are cloning and executing npm run build:deploy-preview within
+REPO_TO_CLONE=dev-portal
+# Set the subdirectory name for the base project
+PREVIEW_DIR=website-preview
+# The directory we want to clone the project into
+CLONE_DIR=website-preview
+# The product for which we are building the deploy preview
+PRODUCT=terraform
+# Preview mode, controls the UI rendered (either the product site or developer). Can be `io` or `developer`
+PREVIEW_MODE=developer
+
+# Get the git branch of the commit that triggered the deploy preview
+# This will power remote image assets in local and deploy previews
+CURRENT_GIT_BRANCH=$VERCEL_GIT_COMMIT_REF
+
+# This is where content files live, relative to the website-preview dir. If omitted, "../content" will be used
+LOCAL_CONTENT_DIR=../docs
+
+from_cache=false
+
+if [ -d "$PREVIEW_DIR" ]; then
+  echo "$PREVIEW_DIR found"
+  CLONE_DIR="$PREVIEW_DIR-tmp"
+  from_cache=true
+fi
+
+# Clone the base project, if needed
+echo "⏳ Cloning the $REPO_TO_CLONE repo, this might take a while..."
+git clone --depth=1 "https://github.com/hashicorp/$REPO_TO_CLONE.git" "$CLONE_DIR"
+
+if [ "$from_cache" = true ]; then
+  echo "Setting up $PREVIEW_DIR"
+  cp -R "./$CLONE_DIR/." "./$PREVIEW_DIR"
+fi
+
+# cd into the preview directory project
+cd "$PREVIEW_DIR"
+
+# Run the build:deploy-preview start script
+PREVIEW_FROM_REPO=$PRODUCT \
+IS_CONTENT_PREVIEW=true \
+PREVIEW_MODE=$PREVIEW_MODE \
+REPO=$PRODUCT \
+HASHI_ENV=project-preview \
+LOCAL_CONTENT_DIR=$LOCAL_CONTENT_DIR \
+CURRENT_GIT_BRANCH=$CURRENT_GIT_BRANCH \
+npm run build:deploy-preview
\ No newline at end of file
diff --git a/v1.5.7/website/scripts/website-start.sh b/v1.5.7/website/scripts/website-start.sh
new file mode 100644
index 0000000..cc0e36a
--- /dev/null
+++ b/v1.5.7/website/scripts/website-start.sh
@@ -0,0 +1,47 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+######################################################
+# NOTE: This file is managed by the Digital Team's   #
+# Terraform configuration @ hashicorp/mktg-terraform #
+######################################################
+
+# Repo which we are cloning and executing npm run build:deploy-preview within
+REPO_TO_CLONE=dev-portal
+# Set the subdirectory name for the dev-portal app
+PREVIEW_DIR=website-preview
+# The product for which we are building the deploy preview
+PRODUCT=terraform
+# Preview mode, controls the UI rendered (either the product site or developer). Can be `io` or `developer`
+PREVIEW_MODE=developer
+
+# Get the git branch of the commit that triggered the deploy preview
+# This will power remote image assets in local and deploy previews
+CURRENT_GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
+
+# This is where content files live, relative to the website-preview dir. If omitted, "../content" will be used
+LOCAL_CONTENT_DIR=../docs
+
+should_pull=true
+
+# Clone the dev-portal project, if needed
+if [ ! -d "$PREVIEW_DIR" ]; then
+    echo "⏳ Cloning the $REPO_TO_CLONE repo, this might take a while..."
+    git clone --depth=1 https://github.com/hashicorp/$REPO_TO_CLONE.git "$PREVIEW_DIR"
+    should_pull=false
+fi
+
+cd "$PREVIEW_DIR"
+
+# If the directory already existed, pull to ensure the clone is fresh
+if [ "$should_pull" = true ]; then
+    git pull origin main
+fi
+
+# Run the dev-portal content-repo start script
+REPO=$PRODUCT \
+PREVIEW_FROM_REPO=$PRODUCT \
+LOCAL_CONTENT_DIR=$LOCAL_CONTENT_DIR \
+CURRENT_GIT_BRANCH=$CURRENT_GIT_BRANCH \
+PREVIEW_MODE=$PREVIEW_MODE \
+npm run start:local-preview
\ No newline at end of file
diff --git a/v1.5.7/website/vercel.json b/v1.5.7/website/vercel.json
new file mode 100644
index 0000000..7ae9a3d
--- /dev/null
+++ b/v1.5.7/website/vercel.json
@@ -0,0 +1,5 @@
+{
+  "github": {
+    "silent": true
+  }
+}
diff --git a/v1.5.7/working_dir.go b/v1.5.7/working_dir.go
new file mode 100644
index 0000000..3c108a6
--- /dev/null
+++ b/v1.5.7/working_dir.go
@@ -0,0 +1,15 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import "github.com/hashicorp/terraform/internal/command/workdir"
+
+func WorkingDir(originalDir string, overrideDataDir string) *workdir.Dir {
+	ret := workdir.NewDir(".") // caller should already have used os.Chdir in "-chdir=..." mode
+	ret.OverrideOriginalWorkingDir(originalDir)
+	if overrideDataDir != "" {
+		ret.OverrideDataDir(overrideDataDir)
+	}
+	return ret
+}